From 4ecf5ed1d331717b3c4eeed2da0e00915f5931c0 Mon Sep 17 00:00:00 2001 From: Stan Smith Date: Thu, 9 Sep 2010 16:29:07 +0000 Subject: [PATCH] git-svn-id: svn://openib.tc.cornell.edu/gen1@2903 ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86 --- branches/WOF2-3/OFED/Bld1.bat | 539 + branches/WOF2-3/OFED/BuildRelease.bat | 615 + branches/WOF2-3/OFED/WIX/CustomActions.vbs | 1901 +++ branches/WOF2-3/OFED/WIX/HPC/HPC.inc | 25 + .../WOF2-3/OFED/WIX/HPC/OFA-cert-install.bat | 34 + .../WOF2-3/OFED/WIX/HPC/WinOF-install.bat | 28 + branches/WOF2-3/OFED/WIX/HPC/cert-add.bat | 142 + branches/WOF2-3/OFED/WIX/HPC/readme-HPC.txt | 40 + branches/WOF2-3/OFED/WIX/HPC/rem-cert-ADD.bat | 40 + branches/WOF2-3/OFED/WIX/License.rtf | Bin 0 -> 1644 bytes branches/WOF2-3/OFED/WIX/README.txt | 176 + branches/WOF2-3/OFED/WIX/README_checked.txt | 18 + branches/WOF2-3/OFED/WIX/README_release.txt | 82 + branches/WOF2-3/OFED/WIX/Release_notes.htm | 1506 ++ .../OFED/WIX/SDK_Samples/WDK/README.txt | 102 + .../WOF2-3/OFED/WIX/SDK_Samples/WDK/SOURCES | 21 + .../WOF2-3/OFED/WIX/SDK_Samples/WDK/cmtest.rc | 48 + .../WOF2-3/OFED/WIX/SDK_Samples/WDK/makefile | 7 + .../OFED/WIX/SDK_Samples/cmtest/Makefile.x64 | 97 + .../OFED/WIX/SDK_Samples/cmtest/Makefile.x86 | 100 + .../OFED/WIX/SDK_Samples/cmtest/README.txt | 113 + .../OFED/WIX/SDK_Samples/cmtest/cmtest.rc | 55 + .../OFED/WIX/SDK_Samples/rdma_bw/Makefile.x64 | 103 + .../OFED/WIX/SDK_Samples/rdma_bw/Makefile.x86 | 103 + .../OFED/WIX/SDK_Samples/rdma_bw/README.txt | 58 + .../OFED/WIX/SDK_Samples/rdma_bw/rdma_bw.rc | 48 + branches/WOF2-3/OFED/WIX/WIX_tools/README.txt | 23 + branches/WOF2-3/OFED/WIX/banner.bmp | Bin 0 -> 85894 bytes branches/WOF2-3/OFED/WIX/build-OFA-dist.bat | 251 + branches/WOF2-3/OFED/WIX/build-all-MSI.bat | 179 + branches/WOF2-3/OFED/WIX/common/Config.inc | 15 + .../WOF2-3/OFED/WIX/common/DAT_config.inc | 87 + branches/WOF2-3/OFED/WIX/common/Docs.inc | 25 + branches/WOF2-3/OFED/WIX/common/Drivers.inc | 15 + branches/WOF2-3/OFED/WIX/common/IBcore.inc | 21 + .../OFED/WIX/common/InstallExecuteSeq.inc | 79 + branches/WOF2-3/OFED/WIX/common/Makefile.inc | 58 + .../WOF2-3/OFED/WIX/common/OpenSM_service.inc | 72 + branches/WOF2-3/OFED/WIX/common/Package.inc | 14 + .../OFED/WIX/common/PgmMenuShortcuts.inc | 48 + .../WOF2-3/OFED/WIX/common/UserInterface.inc | 20 + branches/WOF2-3/OFED/WIX/common/arp.inc | 16 + branches/WOF2-3/OFED/WIX/common/checked.inc | 240 + branches/WOF2-3/OFED/WIX/common/dapl_rt.inc | 47 + .../OFED/WIX/common/directory_structure.inc | 21 + .../WOF2-3/OFED/WIX/common/hca_filters.inc | 80 + branches/WOF2-3/OFED/WIX/common/ib_sdk.inc | 565 + branches/WOF2-3/OFED/WIX/common/iou.inc | 31 + branches/WOF2-3/OFED/WIX/common/ipoib.inc | 104 + .../WOF2-3/OFED/WIX/common/mlnx_drivers.inc | 191 + branches/WOF2-3/OFED/WIX/common/qlgc_vnic.inc | 32 + .../WOF2-3/OFED/WIX/common/requirements.inc | 60 + branches/WOF2-3/OFED/WIX/common/srp.inc | 36 + .../WOF2-3/OFED/WIX/common/std_features.inc | 181 + .../WOF2-3/OFED/WIX/common/system_files.inc | 150 + branches/WOF2-3/OFED/WIX/common/tools.inc | 49 + .../WOF2-3/OFED/WIX/common/winverbs_OFED.inc | 245 + .../OFED/WIX/common/winverbs_drivers.inc | 56 + branches/WOF2-3/OFED/WIX/dat.conf | 39 + branches/WOF2-3/OFED/WIX/dialog.bmp | Bin 0 -> 464774 bytes branches/WOF2-3/OFED/WIX/dpinst.xml | 5 + .../WOF2-3/OFED/WIX/ia64/Command Window.lnk | Bin 0 -> 1368 bytes branches/WOF2-3/OFED/WIX/ia64/devman.exe | Bin 0 -> 129536 bytes branches/WOF2-3/OFED/WIX/openfabrics.gif | Bin 0 -> 3660 bytes branches/WOF2-3/OFED/WIX/openfabrics.ico | Bin 0 -> 12618 bytes branches/WOF2-3/OFED/WIX/sign-all-drivers.bat | 149 + branches/WOF2-3/OFED/WIX/win7/build-MSI.bat | 63 + branches/WOF2-3/OFED/WIX/win7/ia64/Makefile | 9 + branches/WOF2-3/OFED/WIX/win7/ia64/ofed.wxs | 97 + branches/WOF2-3/OFED/WIX/win7/signDrivers.bat | 172 + branches/WOF2-3/OFED/WIX/win7/x64/Makefile | 11 + branches/WOF2-3/OFED/WIX/win7/x64/ofed.wxs | 99 + branches/WOF2-3/OFED/WIX/win7/x86/Makefile | 8 + branches/WOF2-3/OFED/WIX/win7/x86/ofed.wxs | 93 + branches/WOF2-3/OFED/WIX/wlh/build-MSI.bat | 63 + branches/WOF2-3/OFED/WIX/wlh/ia64/Makefile | 8 + branches/WOF2-3/OFED/WIX/wlh/ia64/ofed.wxs | 97 + branches/WOF2-3/OFED/WIX/wlh/signDrivers.bat | 172 + branches/WOF2-3/OFED/WIX/wlh/x64/Makefile | 11 + branches/WOF2-3/OFED/WIX/wlh/x64/ofed.wxs | 99 + branches/WOF2-3/OFED/WIX/wlh/x86/Makefile | 8 + branches/WOF2-3/OFED/WIX/wlh/x86/ofed.wxs | 93 + branches/WOF2-3/OFED/WIX/wnet/build-MSI.bat | 63 + branches/WOF2-3/OFED/WIX/wnet/ia64/Makefile | 8 + branches/WOF2-3/OFED/WIX/wnet/ia64/ofed.wxs | 97 + branches/WOF2-3/OFED/WIX/wnet/signDrivers.bat | 171 + branches/WOF2-3/OFED/WIX/wnet/x64/Makefile | 10 + branches/WOF2-3/OFED/WIX/wnet/x64/ofed.wxs | 97 + branches/WOF2-3/OFED/WIX/wnet/x86/Makefile | 8 + branches/WOF2-3/OFED/WIX/wnet/x86/ofed.wxs | 93 + branches/WOF2-3/OFED/WIX/wxp/build-MSI.bat | 67 + branches/WOF2-3/OFED/WIX/wxp/signDrivers.bat | 172 + branches/WOF2-3/OFED/WIX/wxp/x86/Makefile | 8 + branches/WOF2-3/OFED/WIX/wxp/x86/ofed.wxs | 93 + .../WOF2-3/OFED/WIX/x64/Command Window.lnk | Bin 0 -> 1368 bytes branches/WOF2-3/OFED/WIX/x64/devman.exe | Bin 0 -> 80896 bytes .../WOF2-3/OFED/WIX/x86/Command Window.lnk | Bin 0 -> 1340 bytes branches/WOF2-3/OFED/WIX/x86/devman.exe | Bin 0 -> 77312 bytes branches/WOF2-3/OFED/WIX/zip-OFA-dist.bat | 113 + branches/WOF2-3/core/al/al.c | 433 + branches/WOF2-3/core/al/al.h | 294 + branches/WOF2-3/core/al/al_av.c | 345 + branches/WOF2-3/core/al/al_av.h | 91 + branches/WOF2-3/core/al/al_ca.c | 425 + branches/WOF2-3/core/al/al_ca.h | 85 + branches/WOF2-3/core/al/al_ci_ca.h | 228 + branches/WOF2-3/core/al/al_ci_ca_shared.c | 616 + branches/WOF2-3/core/al/al_cm_cep.h | 516 + branches/WOF2-3/core/al/al_cm_conn.h | 1308 ++ branches/WOF2-3/core/al/al_cm_qp.c | 1959 +++ branches/WOF2-3/core/al/al_cm_sidr.h | 173 + branches/WOF2-3/core/al/al_common.c | 693 + branches/WOF2-3/core/al/al_common.h | 338 + branches/WOF2-3/core/al/al_cq.c | 508 + branches/WOF2-3/core/al/al_cq.h | 159 + branches/WOF2-3/core/al/al_debug.h | 262 + branches/WOF2-3/core/al/al_dev.h | 563 + branches/WOF2-3/core/al/al_dm.c | 1800 +++ branches/WOF2-3/core/al/al_dm.h | 125 + branches/WOF2-3/core/al/al_init.c | 173 + branches/WOF2-3/core/al/al_init.h | 92 + branches/WOF2-3/core/al/al_ioc_pnp.h | 53 + branches/WOF2-3/core/al/al_mad.c | 3274 ++++ branches/WOF2-3/core/al/al_mad.h | 237 + branches/WOF2-3/core/al/al_mad_pool.h | 278 + branches/WOF2-3/core/al/al_mcast.c | 691 + branches/WOF2-3/core/al/al_mcast.h | 115 + branches/WOF2-3/core/al/al_mgr.h | 126 + branches/WOF2-3/core/al/al_mgr_shared.c | 676 + branches/WOF2-3/core/al/al_mr.h | 182 + branches/WOF2-3/core/al/al_mr_shared.c | 635 + branches/WOF2-3/core/al/al_mw.c | 260 + branches/WOF2-3/core/al/al_mw.h | 75 + branches/WOF2-3/core/al/al_pd.c | 485 + branches/WOF2-3/core/al/al_pd.h | 81 + branches/WOF2-3/core/al/al_pnp.h | 242 + branches/WOF2-3/core/al/al_proxy_ioctl.h | 160 + branches/WOF2-3/core/al/al_proxy_ndi.h | 70 + branches/WOF2-3/core/al/al_qp.c | 2128 +++ branches/WOF2-3/core/al/al_qp.h | 295 + branches/WOF2-3/core/al/al_query.c | 377 + branches/WOF2-3/core/al/al_query.h | 153 + branches/WOF2-3/core/al/al_reg_svc.c | 359 + branches/WOF2-3/core/al/al_reg_svc.h | 65 + branches/WOF2-3/core/al/al_res_mgr.c | 300 + branches/WOF2-3/core/al/al_res_mgr.h | 98 + branches/WOF2-3/core/al/al_srq.c | 439 + branches/WOF2-3/core/al/al_srq.h | 109 + branches/WOF2-3/core/al/al_sub.c | 92 + branches/WOF2-3/core/al/al_verbs.h | 645 + branches/WOF2-3/core/al/dirs | 3 + branches/WOF2-3/core/al/ib_common.c | 134 + branches/WOF2-3/core/al/ib_common.h | 50 + branches/WOF2-3/core/al/ib_statustext.c | 271 + branches/WOF2-3/core/al/kernel/SOURCES | 78 + branches/WOF2-3/core/al/kernel/al_ci_ca.c | 532 + branches/WOF2-3/core/al/kernel/al_cm.c | 393 + branches/WOF2-3/core/al/kernel/al_cm_cep.c | 6670 ++++++++ branches/WOF2-3/core/al/kernel/al_dev.c | 499 + branches/WOF2-3/core/al/kernel/al_exports.def | 7 + branches/WOF2-3/core/al/kernel/al_fmr_pool.c | 750 + branches/WOF2-3/core/al/kernel/al_fmr_pool.h | 117 + branches/WOF2-3/core/al/kernel/al_ioc_pnp.c | 3329 ++++ branches/WOF2-3/core/al/kernel/al_mad_pool.c | 961 ++ branches/WOF2-3/core/al/kernel/al_mgr.c | 626 + branches/WOF2-3/core/al/kernel/al_mr.c | 615 + branches/WOF2-3/core/al/kernel/al_ndi_cm.c | 2014 +++ branches/WOF2-3/core/al/kernel/al_ndi_cm.h | 166 + branches/WOF2-3/core/al/kernel/al_ndi_cq.c | 294 + branches/WOF2-3/core/al/kernel/al_ndi_cq.h | 63 + branches/WOF2-3/core/al/kernel/al_pnp.c | 1824 +++ branches/WOF2-3/core/al/kernel/al_proxy.c | 1276 ++ branches/WOF2-3/core/al/kernel/al_proxy.h | 405 + branches/WOF2-3/core/al/kernel/al_proxy_cep.c | 1005 ++ branches/WOF2-3/core/al/kernel/al_proxy_ioc.c | 70 + branches/WOF2-3/core/al/kernel/al_proxy_ndi.c | 814 + .../WOF2-3/core/al/kernel/al_proxy_subnet.c | 1162 ++ .../WOF2-3/core/al/kernel/al_proxy_verbs.c | 3909 +++++ branches/WOF2-3/core/al/kernel/al_sa_req.c | 812 + branches/WOF2-3/core/al/kernel/al_smi.c | 3770 +++++ branches/WOF2-3/core/al/kernel/al_smi.h | 250 + branches/WOF2-3/core/al/kernel/ibal.rc | 47 + branches/WOF2-3/core/al/kernel/makefile | 7 + branches/WOF2-3/core/al/user/SOURCES | 100 + branches/WOF2-3/core/al/user/al_dll.c | 205 + branches/WOF2-3/core/al/user/al_exports.src | 191 + branches/WOF2-3/core/al/user/al_mad_pool.c | 1508 ++ branches/WOF2-3/core/al/user/ibal.rc | 48 + branches/WOF2-3/core/al/user/makefile | 7 + branches/WOF2-3/core/al/user/ual_av.c | 404 + branches/WOF2-3/core/al/user/ual_ca.c | 535 + branches/WOF2-3/core/al/user/ual_ca.h | 59 + branches/WOF2-3/core/al/user/ual_ci_ca.c | 339 + branches/WOF2-3/core/al/user/ual_ci_ca.h | 287 + branches/WOF2-3/core/al/user/ual_cm_cep.c | 1475 ++ branches/WOF2-3/core/al/user/ual_cq.c | 550 + branches/WOF2-3/core/al/user/ual_mad.c | 531 + branches/WOF2-3/core/al/user/ual_mad.h | 97 + branches/WOF2-3/core/al/user/ual_mad_pool.c | 140 + branches/WOF2-3/core/al/user/ual_mcast.c | 174 + branches/WOF2-3/core/al/user/ual_mcast.h | 45 + branches/WOF2-3/core/al/user/ual_mgr.c | 1061 ++ branches/WOF2-3/core/al/user/ual_mgr.h | 143 + branches/WOF2-3/core/al/user/ual_mr.c | 354 + branches/WOF2-3/core/al/user/ual_mw.c | 303 + branches/WOF2-3/core/al/user/ual_pd.c | 170 + branches/WOF2-3/core/al/user/ual_pnp.c | 568 + branches/WOF2-3/core/al/user/ual_qp.c | 673 + branches/WOF2-3/core/al/user/ual_qp.h | 47 + branches/WOF2-3/core/al/user/ual_res_mgr.h | 71 + branches/WOF2-3/core/al/user/ual_sa_req.c | 309 + branches/WOF2-3/core/al/user/ual_srq.c | 439 + branches/WOF2-3/core/al/user/ual_support.h | 123 + branches/WOF2-3/core/bus/dirs | 2 + branches/WOF2-3/core/bus/kernel/SOURCES | 42 + branches/WOF2-3/core/bus/kernel/bus_driver.c | 1086 ++ branches/WOF2-3/core/bus/kernel/bus_driver.h | 317 + branches/WOF2-3/core/bus/kernel/bus_ev_log.mc | 56 + branches/WOF2-3/core/bus/kernel/bus_iou_mgr.c | 1698 +++ branches/WOF2-3/core/bus/kernel/bus_iou_mgr.h | 67 + branches/WOF2-3/core/bus/kernel/bus_pnp.c | 1868 +++ branches/WOF2-3/core/bus/kernel/bus_pnp.h | 84 + .../WOF2-3/core/bus/kernel/bus_port_mgr.c | 2155 +++ .../WOF2-3/core/bus/kernel/bus_port_mgr.h | 68 + branches/WOF2-3/core/bus/kernel/bus_stat.c | 53 + branches/WOF2-3/core/bus/kernel/bus_stat.h | 94 + branches/WOF2-3/core/bus/kernel/ibbus.rc | 49 + branches/WOF2-3/core/bus/kernel/makefile | 7 + branches/WOF2-3/core/complib/cl_async_proc.c | 160 + branches/WOF2-3/core/complib/cl_list.c | 652 + branches/WOF2-3/core/complib/cl_map.c | 2278 +++ branches/WOF2-3/core/complib/cl_memory.c | 353 + branches/WOF2-3/core/complib/cl_memtrack.h | 86 + branches/WOF2-3/core/complib/cl_obj.c | 782 + branches/WOF2-3/core/complib/cl_perf.c | 269 + branches/WOF2-3/core/complib/cl_pool.c | 708 + branches/WOF2-3/core/complib/cl_ptr_vector.c | 358 + branches/WOF2-3/core/complib/cl_reqmgr.c | 288 + branches/WOF2-3/core/complib/cl_statustext.c | 71 + branches/WOF2-3/core/complib/cl_threadpool.c | 241 + branches/WOF2-3/core/complib/cl_vector.c | 617 + branches/WOF2-3/core/complib/dirs | 3 + branches/WOF2-3/core/complib/kernel/SOURCES | 32 + .../WOF2-3/core/complib/kernel/cl_bus_ifc.c | 86 + .../WOF2-3/core/complib/kernel/cl_driver.c | 80 + .../WOF2-3/core/complib/kernel/cl_event.c | 74 + .../WOF2-3/core/complib/kernel/cl_exports.def | 7 + branches/WOF2-3/core/complib/kernel/cl_log.c | 216 + .../core/complib/kernel/cl_memory_osd.c | 60 + .../WOF2-3/core/complib/kernel/cl_pnp_po.c | 1404 ++ .../core/complib/kernel/cl_syscallback.c | 88 + .../WOF2-3/core/complib/kernel/cl_thread.c | 136 + .../WOF2-3/core/complib/kernel/cl_timer.c | 181 + branches/WOF2-3/core/complib/kernel/makefile | 7 + branches/WOF2-3/core/complib/user/SOURCES | 50 + branches/WOF2-3/core/complib/user/cl_debug.c | 61 + branches/WOF2-3/core/complib/user/cl_dll.c | 89 + branches/WOF2-3/core/complib/user/cl_event.c | 64 + branches/WOF2-3/core/complib/user/cl_log.c | 78 + .../WOF2-3/core/complib/user/cl_memory_osd.c | 54 + .../WOF2-3/core/complib/user/cl_nodenamemap.c | 186 + .../WOF2-3/core/complib/user/cl_syscallback.c | 122 + branches/WOF2-3/core/complib/user/cl_thread.c | 127 + branches/WOF2-3/core/complib/user/cl_timer.c | 202 + branches/WOF2-3/core/complib/user/complib.rc | 48 + branches/WOF2-3/core/complib/user/complib.src | 298 + branches/WOF2-3/core/complib/user/makefile | 7 + branches/WOF2-3/core/dirs | 8 + branches/WOF2-3/core/ibat/dirs | 2 + branches/WOF2-3/core/ibat/user/SOURCES | 9 + branches/WOF2-3/core/ibat/user/ibat.cpp | 412 + branches/WOF2-3/core/ibat/user/makefile | 7 + branches/WOF2-3/core/iou/dirs | 2 + branches/WOF2-3/core/iou/kernel/SOURCES | 52 + branches/WOF2-3/core/iou/kernel/ib_iou.cdf | 8 + branches/WOF2-3/core/iou/kernel/ib_iou.inx | 128 + branches/WOF2-3/core/iou/kernel/ibiou.rc | 47 + branches/WOF2-3/core/iou/kernel/iou_driver.c | 903 ++ branches/WOF2-3/core/iou/kernel/iou_driver.h | 263 + branches/WOF2-3/core/iou/kernel/iou_ioc_mgr.c | 1716 +++ branches/WOF2-3/core/iou/kernel/iou_ioc_mgr.h | 126 + branches/WOF2-3/core/iou/kernel/iou_pnp.c | 637 + branches/WOF2-3/core/iou/kernel/iou_pnp.h | 80 + branches/WOF2-3/core/iou/kernel/makefile | 7 + branches/WOF2-3/core/iou/kernel/makefile.inc | 17 + branches/WOF2-3/core/winmad/dirs | 3 + branches/WOF2-3/core/winmad/kernel/SOURCES | 22 + branches/WOF2-3/core/winmad/kernel/makefile | 7 + .../WOF2-3/core/winmad/kernel/makefile.inc | 13 + branches/WOF2-3/core/winmad/kernel/winmad.inx | 108 + branches/WOF2-3/core/winmad/kernel/winmad.rc | 44 + .../WOF2-3/core/winmad/kernel/wm_driver.c | 415 + .../WOF2-3/core/winmad/kernel/wm_driver.h | 81 + .../WOF2-3/core/winmad/kernel/wm_provider.c | 434 + .../WOF2-3/core/winmad/kernel/wm_provider.h | 82 + branches/WOF2-3/core/winmad/kernel/wm_reg.c | 311 + branches/WOF2-3/core/winmad/kernel/wm_reg.h | 69 + branches/WOF2-3/core/winmad/user/SOURCES | 27 + branches/WOF2-3/core/winmad/user/makefile | 7 + branches/WOF2-3/core/winmad/user/winmad.rc | 46 + .../WOF2-3/core/winmad/user/wm_exports.src | 9 + branches/WOF2-3/core/winmad/user/wm_main.cpp | 56 + branches/WOF2-3/core/winmad/user/wm_memory.h | 47 + .../WOF2-3/core/winmad/user/wm_provider.cpp | 224 + .../WOF2-3/core/winmad/user/wm_provider.h | 110 + branches/WOF2-3/core/winmad/wm_ioctl.h | 121 + branches/WOF2-3/core/winverbs/dirs | 3 + branches/WOF2-3/core/winverbs/kernel/SOURCES | 28 + branches/WOF2-3/core/winverbs/kernel/makefile | 7 + .../WOF2-3/core/winverbs/kernel/makefile.inc | 13 + .../WOF2-3/core/winverbs/kernel/winverbs.cdf | 11 + .../WOF2-3/core/winverbs/kernel/winverbs.inx | 108 + .../WOF2-3/core/winverbs/kernel/winverbs.rc | 44 + branches/WOF2-3/core/winverbs/kernel/wv_cq.c | 335 + branches/WOF2-3/core/winverbs/kernel/wv_cq.h | 72 + .../WOF2-3/core/winverbs/kernel/wv_device.c | 819 + .../WOF2-3/core/winverbs/kernel/wv_device.h | 87 + .../WOF2-3/core/winverbs/kernel/wv_driver.c | 593 + .../WOF2-3/core/winverbs/kernel/wv_driver.h | 84 + branches/WOF2-3/core/winverbs/kernel/wv_ep.c | 1375 ++ branches/WOF2-3/core/winverbs/kernel/wv_ep.h | 102 + branches/WOF2-3/core/winverbs/kernel/wv_pd.c | 634 + branches/WOF2-3/core/winverbs/kernel/wv_pd.h | 110 + .../WOF2-3/core/winverbs/kernel/wv_provider.c | 242 + .../WOF2-3/core/winverbs/kernel/wv_provider.h | 97 + branches/WOF2-3/core/winverbs/kernel/wv_qp.c | 762 + branches/WOF2-3/core/winverbs/kernel/wv_qp.h | 78 + branches/WOF2-3/core/winverbs/kernel/wv_srq.c | 379 + branches/WOF2-3/core/winverbs/kernel/wv_srq.h | 71 + branches/WOF2-3/core/winverbs/user/SOURCES | 39 + branches/WOF2-3/core/winverbs/user/makefile | 7 + .../WOF2-3/core/winverbs/user/winverbs.rc | 46 + .../WOF2-3/core/winverbs/user/wv_base.cpp | 107 + branches/WOF2-3/core/winverbs/user/wv_base.h | 86 + branches/WOF2-3/core/winverbs/user/wv_cq.cpp | 275 + branches/WOF2-3/core/winverbs/user/wv_cq.h | 103 + .../WOF2-3/core/winverbs/user/wv_device.cpp | 495 + .../WOF2-3/core/winverbs/user/wv_device.h | 129 + branches/WOF2-3/core/winverbs/user/wv_ep.cpp | 588 + branches/WOF2-3/core/winverbs/user/wv_ep.h | 184 + .../WOF2-3/core/winverbs/user/wv_exports.src | 9 + .../WOF2-3/core/winverbs/user/wv_main.cpp | 152 + .../WOF2-3/core/winverbs/user/wv_memory.h | 75 + branches/WOF2-3/core/winverbs/user/wv_pd.cpp | 471 + branches/WOF2-3/core/winverbs/user/wv_pd.h | 219 + .../WOF2-3/core/winverbs/user/wv_provider.cpp | 193 + .../WOF2-3/core/winverbs/user/wv_provider.h | 105 + branches/WOF2-3/core/winverbs/user/wv_qp.cpp | 796 + branches/WOF2-3/core/winverbs/user/wv_qp.h | 219 + branches/WOF2-3/core/winverbs/user/wv_srq.cpp | 306 + branches/WOF2-3/core/winverbs/user/wv_srq.h | 102 + .../WOF2-3/core/winverbs/user/wv_uverbs.cpp | 512 + branches/WOF2-3/core/winverbs/wv_ioctl.h | 752 + branches/WOF2-3/core/winverbs/wv_public.h | 32 + branches/WOF2-3/dirs | 6 + branches/WOF2-3/docs/Manual.htm | 8644 +++++++++++ branches/WOF2-3/docs/build.txt | 32 + .../WOF2-3/docs/complib/cl_async_proc_h.html | 309 + branches/WOF2-3/docs/complib/cl_atomic_h.html | 272 + .../WOF2-3/docs/complib/cl_byteswap_h.html | 500 + .../WOF2-3/docs/complib/cl_comppool_h.html | 604 + branches/WOF2-3/docs/complib/cl_debug_h.html | 534 + branches/WOF2-3/docs/complib/cl_event_h.html | 274 + .../WOF2-3/docs/complib/cl_fleximap_h.html | 948 ++ branches/WOF2-3/docs/complib/cl_ioctl_h.html | 609 + .../WOF2-3/docs/complib/cl_irqlock_h.html | 221 + branches/WOF2-3/docs/complib/cl_list_h.html | 1412 ++ branches/WOF2-3/docs/complib/cl_log_h.html | 117 + branches/WOF2-3/docs/complib/cl_map_h.html | 898 ++ branches/WOF2-3/docs/complib/cl_math_h.html | 103 + branches/WOF2-3/docs/complib/cl_memory_h.html | 629 + branches/WOF2-3/docs/complib/cl_mutex_h.html | 207 + branches/WOF2-3/docs/complib/cl_obj_h.html | 997 ++ .../WOF2-3/docs/complib/cl_passivelock_h.html | 417 + branches/WOF2-3/docs/complib/cl_perf_h.html | 583 + branches/WOF2-3/docs/complib/cl_pool_h.html | 581 + .../WOF2-3/docs/complib/cl_ptr_vector_h.html | 890 ++ .../WOF2-3/docs/complib/cl_qcomppool_h.html | 740 + branches/WOF2-3/docs/complib/cl_qlist_h.html | 1728 +++ .../WOF2-3/docs/complib/cl_qlockpool_h.html | 340 + branches/WOF2-3/docs/complib/cl_qmap_h.html | 998 ++ branches/WOF2-3/docs/complib/cl_qpool_h.html | 628 + branches/WOF2-3/docs/complib/cl_rbmap_h.html | 563 + branches/WOF2-3/docs/complib/cl_reqmgr_h.html | 463 + .../WOF2-3/docs/complib/cl_spinlock_h.html | 210 + .../WOF2-3/docs/complib/cl_syscallback_h.html | 243 + branches/WOF2-3/docs/complib/cl_thread_h.html | 164 + .../WOF2-3/docs/complib/cl_threadpool_h.html | 273 + branches/WOF2-3/docs/complib/cl_timer_h.html | 432 + branches/WOF2-3/docs/complib/cl_types_h.html | 410 + branches/WOF2-3/docs/complib/cl_vector_h.html | 984 ++ .../WOF2-3/docs/complib/cl_waitobj_h.html | 356 + branches/WOF2-3/docs/complib/comp_lib_h.html | 50 + branches/WOF2-3/docs/dontdiff.txt | 27 + branches/WOF2-3/docs/generate-patch.txt | 18 + branches/WOF2-3/docs/iba/ib_al_h.html | 10482 +++++++++++++ branches/WOF2-3/docs/iba/ib_types_h.html | 10744 +++++++++++++ branches/WOF2-3/docs/install.txt | 111 + branches/WOF2-3/docs/interfaces.txt | 40 + branches/WOF2-3/docs/maintainers.txt | 61 + branches/WOF2-3/docs/masterindex.html | 2741 ++++ branches/WOF2-3/docs/openfabrics.gif | Bin 0 -> 3660 bytes branches/WOF2-3/docs/robo_definitions.html | 655 + branches/WOF2-3/docs/robo_functions.html | 1535 ++ branches/WOF2-3/docs/robo_modules.html | 116 + branches/WOF2-3/docs/robo_sourcefiles.html | 149 + branches/WOF2-3/docs/robo_strutures.html | 381 + branches/WOF2-3/docs/robodoc.css | 36 + branches/WOF2-3/etc/addcert.bat | 3 + branches/WOF2-3/etc/bldwo.bat | 104 + branches/WOF2-3/etc/bldwoall.bat | 19 + branches/WOF2-3/etc/clean-build.bat | 117 + branches/WOF2-3/etc/cpinst.bat | 84 + branches/WOF2-3/etc/depwo.bat | 115 + branches/WOF2-3/etc/kernel/index_list.c | 110 + branches/WOF2-3/etc/kernel/work_queue.c | 146 + branches/WOF2-3/etc/makebin.bat | 917 ++ branches/WOF2-3/etc/nomerge.txt | 1 + branches/WOF2-3/etc/pkgwo.bat | 206 + branches/WOF2-3/etc/pkgwoall.bat | 19 + branches/WOF2-3/etc/signall.bat | 11 + branches/WOF2-3/etc/signwo.bat | 6 + branches/WOF2-3/etc/user/comp_channel.cpp | 325 + branches/WOF2-3/etc/user/getopt.c | 188 + branches/WOF2-3/etc/user/gtod.c | 138 + branches/WOF2-3/etc/user/inet.c | 220 + branches/WOF2-3/etc/user/search.c | 115 + branches/WOF2-3/etc/wpp/ALTraceRt.cmd | 14 + branches/WOF2-3/etc/wpp/CreateTrace.cmd | 14 + branches/WOF2-3/etc/wpp/IPoIBTraceRt.cmd | 13 + branches/WOF2-3/etc/wpp/MTHCATraceRt.cmd | 14 + branches/WOF2-3/etc/wpp/SDPTraceRt.cmd | 10 + branches/WOF2-3/etc/wpp/StartSdpTrace.cmd | 7 + branches/WOF2-3/etc/wpp/StartTrace.cmd | 22 + branches/WOF2-3/etc/wpp/StopSdpTrace.cmd | 10 + branches/WOF2-3/etc/wpp/StopTrace.cmd | 8 + branches/WOF2-3/hw/dirs | 3 + branches/WOF2-3/hw/mlx4/dirs | 3 + branches/WOF2-3/hw/mlx4/inc/mx_abi.h | 180 + branches/WOF2-3/hw/mlx4/inc/public.h | 139 + branches/WOF2-3/hw/mlx4/inc/user.h | 94 + .../WOF2-3/hw/mlx4/kernel/bus/core/SOURCES | 51 + .../WOF2-3/hw/mlx4/kernel/bus/core/cache.c | 449 + .../WOF2-3/hw/mlx4/kernel/bus/core/core.def | 64 + .../WOF2-3/hw/mlx4/kernel/bus/core/core.h | 12 + .../WOF2-3/hw/mlx4/kernel/bus/core/core.rc | 48 + .../WOF2-3/hw/mlx4/kernel/bus/core/device.c | 762 + .../WOF2-3/hw/mlx4/kernel/bus/core/ev_log.mc | 163 + .../WOF2-3/hw/mlx4/kernel/bus/core/iobuf.c | 552 + branches/WOF2-3/hw/mlx4/kernel/bus/core/l2w.c | 504 + .../hw/mlx4/kernel/bus/core/l2w_debug.c | 406 + .../hw/mlx4/kernel/bus/core/l2w_memory.c | 119 + .../hw/mlx4/kernel/bus/core/l2w_radix.c | 74 + .../WOF2-3/hw/mlx4/kernel/bus/core/l2w_umem.c | 186 + .../WOF2-3/hw/mlx4/kernel/bus/core/makefile | 7 + .../WOF2-3/hw/mlx4/kernel/bus/core/pa_cash.c | 366 + .../WOF2-3/hw/mlx4/kernel/bus/core/pa_cash.h | 51 + .../WOF2-3/hw/mlx4/kernel/bus/core/packer.c | 203 + .../hw/mlx4/kernel/bus/core/ud_header.c | 380 + .../WOF2-3/hw/mlx4/kernel/bus/core/verbs.c | 363 + branches/WOF2-3/hw/mlx4/kernel/bus/dirs | 5 + .../WOF2-3/hw/mlx4/kernel/bus/drv/bus.mof | 27 + branches/WOF2-3/hw/mlx4/kernel/bus/drv/bus.rc | 16 + branches/WOF2-3/hw/mlx4/kernel/bus/drv/drv.c | 1474 ++ branches/WOF2-3/hw/mlx4/kernel/bus/drv/drv.h | 242 + .../WOF2-3/hw/mlx4/kernel/bus/drv/makefile | 8 + .../hw/mlx4/kernel/bus/drv/makefile.inc | 24 + .../hw/mlx4/kernel/bus/drv/mlx4_bus.cdf | 9 + .../hw/mlx4/kernel/bus/drv/mlx4_bus.inx | 303 + .../hw/mlx4/kernel/bus/drv/mlx4_bus32.cdf | 9 + branches/WOF2-3/hw/mlx4/kernel/bus/drv/pci.c | 942 ++ branches/WOF2-3/hw/mlx4/kernel/bus/drv/pdo.c | 332 + .../WOF2-3/hw/mlx4/kernel/bus/drv/precomp.h | 16 + .../WOF2-3/hw/mlx4/kernel/bus/drv/sources | 61 + branches/WOF2-3/hw/mlx4/kernel/bus/drv/stat.c | 199 + branches/WOF2-3/hw/mlx4/kernel/bus/drv/stat.h | 86 + branches/WOF2-3/hw/mlx4/kernel/bus/drv/wmi.c | 237 + .../WOF2-3/hw/mlx4/kernel/bus/drv/wpptrace.h | 116 + branches/WOF2-3/hw/mlx4/kernel/bus/ib/Kconfig | 8 + .../WOF2-3/hw/mlx4/kernel/bus/ib/Makefile.lnx | 3 + branches/WOF2-3/hw/mlx4/kernel/bus/ib/SOURCES | 45 + branches/WOF2-3/hw/mlx4/kernel/bus/ib/ah.c | 270 + branches/WOF2-3/hw/mlx4/kernel/bus/ib/cq.c | 651 + .../WOF2-3/hw/mlx4/kernel/bus/ib/doorbell.c | 217 + branches/WOF2-3/hw/mlx4/kernel/bus/ib/ib.def | 11 + branches/WOF2-3/hw/mlx4/kernel/bus/ib/ib.rc | 47 + branches/WOF2-3/hw/mlx4/kernel/bus/ib/mad.c | 267 + branches/WOF2-3/hw/mlx4/kernel/bus/ib/main.c | 738 + .../WOF2-3/hw/mlx4/kernel/bus/ib/makefile | 7 + .../WOF2-3/hw/mlx4/kernel/bus/ib/mlx4_ib.h | 357 + branches/WOF2-3/hw/mlx4/kernel/bus/ib/mr.c | 288 + branches/WOF2-3/hw/mlx4/kernel/bus/ib/qp.c | 1978 +++ branches/WOF2-3/hw/mlx4/kernel/bus/ib/srq.c | 373 + .../WOF2-3/hw/mlx4/kernel/bus/inc/bus_intf.h | 200 + branches/WOF2-3/hw/mlx4/kernel/bus/inc/cmd.h | 190 + branches/WOF2-3/hw/mlx4/kernel/bus/inc/cq.h | 164 + .../WOF2-3/hw/mlx4/kernel/bus/inc/device.h | 554 + .../WOF2-3/hw/mlx4/kernel/bus/inc/doorbell.h | 83 + .../WOF2-3/hw/mlx4/kernel/bus/inc/driver.h | 59 + branches/WOF2-3/hw/mlx4/kernel/bus/inc/eq.h | 132 + .../WOF2-3/hw/mlx4/kernel/bus/inc/ib_cache.h | 116 + .../WOF2-3/hw/mlx4/kernel/bus/inc/ib_mad.h | 657 + .../WOF2-3/hw/mlx4/kernel/bus/inc/ib_pack.h | 276 + .../WOF2-3/hw/mlx4/kernel/bus/inc/ib_smi.h | 131 + .../WOF2-3/hw/mlx4/kernel/bus/inc/ib_verbs.h | 1913 +++ .../hw/mlx4/kernel/bus/inc/ib_verbs_ex.h | 94 + branches/WOF2-3/hw/mlx4/kernel/bus/inc/qp.h | 312 + branches/WOF2-3/hw/mlx4/kernel/bus/inc/srq.h | 42 + .../hw/mlx4/kernel/bus/net/Makefile.lnx | 4 + .../WOF2-3/hw/mlx4/kernel/bus/net/SOURCES | 54 + .../WOF2-3/hw/mlx4/kernel/bus/net/alloc.c | 448 + .../WOF2-3/hw/mlx4/kernel/bus/net/catas.c | 405 + branches/WOF2-3/hw/mlx4/kernel/bus/net/cmd.c | 618 + branches/WOF2-3/hw/mlx4/kernel/bus/net/cq.c | 289 + branches/WOF2-3/hw/mlx4/kernel/bus/net/eq.c | 935 ++ branches/WOF2-3/hw/mlx4/kernel/bus/net/fw.c | 947 ++ branches/WOF2-3/hw/mlx4/kernel/bus/net/fw.h | 173 + branches/WOF2-3/hw/mlx4/kernel/bus/net/icm.c | 460 + branches/WOF2-3/hw/mlx4/kernel/bus/net/icm.h | 132 + branches/WOF2-3/hw/mlx4/kernel/bus/net/intf.c | 186 + branches/WOF2-3/hw/mlx4/kernel/bus/net/main.c | 1162 ++ .../WOF2-3/hw/mlx4/kernel/bus/net/makefile | 7 + branches/WOF2-3/hw/mlx4/kernel/bus/net/mcg.c | 380 + branches/WOF2-3/hw/mlx4/kernel/bus/net/mlx4.h | 455 + branches/WOF2-3/hw/mlx4/kernel/bus/net/mr.c | 659 + .../WOF2-3/hw/mlx4/kernel/bus/net/net.def | 24 + branches/WOF2-3/hw/mlx4/kernel/bus/net/net.rc | 47 + branches/WOF2-3/hw/mlx4/kernel/bus/net/pd.c | 104 + branches/WOF2-3/hw/mlx4/kernel/bus/net/port.c | 365 + .../WOF2-3/hw/mlx4/kernel/bus/net/profile.c | 239 + branches/WOF2-3/hw/mlx4/kernel/bus/net/qp.c | 429 + .../WOF2-3/hw/mlx4/kernel/bus/net/reset.c | 0 branches/WOF2-3/hw/mlx4/kernel/bus/net/srq.c | 277 + branches/WOF2-3/hw/mlx4/kernel/dirs | 3 + branches/WOF2-3/hw/mlx4/kernel/hca/Makefile | 6 + branches/WOF2-3/hw/mlx4/kernel/hca/SOURCES | 63 + branches/WOF2-3/hw/mlx4/kernel/hca/av.c | 234 + branches/WOF2-3/hw/mlx4/kernel/hca/ca.c | 458 + branches/WOF2-3/hw/mlx4/kernel/hca/cq.c | 211 + branches/WOF2-3/hw/mlx4/kernel/hca/data.c | 1019 ++ branches/WOF2-3/hw/mlx4/kernel/hca/data.h | 338 + branches/WOF2-3/hw/mlx4/kernel/hca/debug.h | 132 + branches/WOF2-3/hw/mlx4/kernel/hca/direct.c | 285 + branches/WOF2-3/hw/mlx4/kernel/hca/drv.c | 2015 +++ branches/WOF2-3/hw/mlx4/kernel/hca/drv.h | 372 + branches/WOF2-3/hw/mlx4/kernel/hca/fw.c | 494 + branches/WOF2-3/hw/mlx4/kernel/hca/hca.mof | 59 + branches/WOF2-3/hw/mlx4/kernel/hca/hca.rc | 44 + branches/WOF2-3/hw/mlx4/kernel/hca/hverbs.c | 673 + branches/WOF2-3/hw/mlx4/kernel/hca/hverbs.h | 72 + .../WOF2-3/hw/mlx4/kernel/hca/makefile.inc | 24 + branches/WOF2-3/hw/mlx4/kernel/hca/mcast.c | 197 + .../WOF2-3/hw/mlx4/kernel/hca/mlx4_hca.cdf | 28 + .../WOF2-3/hw/mlx4/kernel/hca/mlx4_hca.inx | 470 + .../WOF2-3/hw/mlx4/kernel/hca/mlx4_hca32.cdf | 22 + branches/WOF2-3/hw/mlx4/kernel/hca/mr.c | 588 + branches/WOF2-3/hw/mlx4/kernel/hca/pd.c | 174 + branches/WOF2-3/hw/mlx4/kernel/hca/precomp.h | 48 + branches/WOF2-3/hw/mlx4/kernel/hca/qp.c | 398 + branches/WOF2-3/hw/mlx4/kernel/hca/srq.c | 183 + branches/WOF2-3/hw/mlx4/kernel/hca/vp.c | 326 + branches/WOF2-3/hw/mlx4/kernel/hca/wmi.c | 254 + branches/WOF2-3/hw/mlx4/kernel/inc/iobuf.h | 53 + branches/WOF2-3/hw/mlx4/kernel/inc/l2w.h | 364 + .../WOF2-3/hw/mlx4/kernel/inc/l2w_atomic.h | 47 + branches/WOF2-3/hw/mlx4/kernel/inc/l2w_bit.h | 192 + .../WOF2-3/hw/mlx4/kernel/inc/l2w_bitmap.h | 79 + .../WOF2-3/hw/mlx4/kernel/inc/l2w_debug.h | 55 + branches/WOF2-3/hw/mlx4/kernel/inc/l2w_list.h | 99 + .../WOF2-3/hw/mlx4/kernel/inc/l2w_memory.h | 334 + branches/WOF2-3/hw/mlx4/kernel/inc/l2w_pci.h | 117 + .../WOF2-3/hw/mlx4/kernel/inc/l2w_pcipool.h | 102 + .../WOF2-3/hw/mlx4/kernel/inc/l2w_radix.h | 25 + .../WOF2-3/hw/mlx4/kernel/inc/l2w_spinlock.h | 148 + branches/WOF2-3/hw/mlx4/kernel/inc/l2w_sync.h | 165 + branches/WOF2-3/hw/mlx4/kernel/inc/l2w_time.h | 17 + branches/WOF2-3/hw/mlx4/kernel/inc/l2w_umem.h | 34 + .../WOF2-3/hw/mlx4/kernel/inc/mlx4_debug.h | 200 + branches/WOF2-3/hw/mlx4/kernel/inc/vc.h | 94 + branches/WOF2-3/hw/mlx4/kernel/inc/vip_dev.h | 75 + .../mlx4/kernel_patches/core_0020_csum.patch | 51 + .../core_0025_qp_create_flags.patch | 53 + .../mlx4/kernel_patches/core_0030_lso.patch | 66 + .../kernel_patches/mlx4_0010_add_wc.patch | 312 + .../mlx4_0030_checksum_offload.patch | 125 + .../kernel_patches/mlx4_0045_qp_flags.patch | 76 + .../mlx4/kernel_patches/mlx4_0050_lso.patch | 249 + .../mlx4_0170_shrinking_wqe.patch | 509 + branches/WOF2-3/hw/mlx4/todo.txt | 116 + branches/WOF2-3/hw/mlx4/user/dirs | 2 + branches/WOF2-3/hw/mlx4/user/hca/Makefile | 7 + branches/WOF2-3/hw/mlx4/user/hca/SOURCES | 70 + branches/WOF2-3/hw/mlx4/user/hca/buf.c | 47 + branches/WOF2-3/hw/mlx4/user/hca/cq.c | 529 + branches/WOF2-3/hw/mlx4/user/hca/dbrec.c | 147 + branches/WOF2-3/hw/mlx4/user/hca/doorbell.h | 55 + branches/WOF2-3/hw/mlx4/user/hca/l2w.h | 183 + branches/WOF2-3/hw/mlx4/user/hca/mlx4.c | 329 + branches/WOF2-3/hw/mlx4/user/hca/mlx4.def | 11 + branches/WOF2-3/hw/mlx4/user/hca/mlx4.h | 350 + branches/WOF2-3/hw/mlx4/user/hca/mlx4_debug.c | 88 + branches/WOF2-3/hw/mlx4/user/hca/mlx4_debug.h | 144 + branches/WOF2-3/hw/mlx4/user/hca/mlx4u.rc | 48 + branches/WOF2-3/hw/mlx4/user/hca/qp.c | 780 + branches/WOF2-3/hw/mlx4/user/hca/srq.c | 212 + branches/WOF2-3/hw/mlx4/user/hca/verbs.c | 1470 ++ branches/WOF2-3/hw/mlx4/user/hca/verbs.h | 436 + branches/WOF2-3/hw/mlx4/user/hca/wqe.h | 120 + branches/WOF2-3/hw/mthca/dirs | 3 + branches/WOF2-3/hw/mthca/hca_utils.c | 79 + branches/WOF2-3/hw/mthca/hca_utils.h | 49 + branches/WOF2-3/hw/mthca/kernel/Makefile | 6 + branches/WOF2-3/hw/mthca/kernel/SOURCES | 94 + branches/WOF2-3/hw/mthca/kernel/hca.rc | 45 + branches/WOF2-3/hw/mthca/kernel/hca_data.c | 973 ++ branches/WOF2-3/hw/mthca/kernel/hca_data.h | 390 + branches/WOF2-3/hw/mthca/kernel/hca_debug.h | 194 + branches/WOF2-3/hw/mthca/kernel/hca_direct.c | 308 + branches/WOF2-3/hw/mthca/kernel/hca_driver.c | 1049 ++ branches/WOF2-3/hw/mthca/kernel/hca_driver.h | 238 + branches/WOF2-3/hw/mthca/kernel/hca_mcast.c | 202 + branches/WOF2-3/hw/mthca/kernel/hca_memory.c | 572 + branches/WOF2-3/hw/mthca/kernel/hca_pci.c | 762 + branches/WOF2-3/hw/mthca/kernel/hca_pci.h | 24 + branches/WOF2-3/hw/mthca/kernel/hca_pnp.c | 1365 ++ branches/WOF2-3/hw/mthca/kernel/hca_pnp.h | 46 + branches/WOF2-3/hw/mthca/kernel/hca_verbs.c | 1698 +++ branches/WOF2-3/hw/mthca/kernel/ib_cache.h | 109 + branches/WOF2-3/hw/mthca/kernel/ib_mad.h | 579 + branches/WOF2-3/hw/mthca/kernel/ib_pack.h | 245 + branches/WOF2-3/hw/mthca/kernel/ib_smi.h | 95 + branches/WOF2-3/hw/mthca/kernel/ib_verbs.h | 1335 ++ branches/WOF2-3/hw/mthca/kernel/makefile.inc | 17 + branches/WOF2-3/hw/mthca/kernel/mt_atomic.h | 81 + branches/WOF2-3/hw/mthca/kernel/mt_bitmap.h | 74 + branches/WOF2-3/hw/mthca/kernel/mt_cache.c | 407 + branches/WOF2-3/hw/mthca/kernel/mt_device.c | 569 + branches/WOF2-3/hw/mthca/kernel/mt_l2w.c | 133 + branches/WOF2-3/hw/mthca/kernel/mt_l2w.h | 92 + branches/WOF2-3/hw/mthca/kernel/mt_list.h | 63 + branches/WOF2-3/hw/mthca/kernel/mt_memory.c | 762 + branches/WOF2-3/hw/mthca/kernel/mt_memory.h | 309 + branches/WOF2-3/hw/mthca/kernel/mt_pa_cash.c | 364 + branches/WOF2-3/hw/mthca/kernel/mt_pa_cash.h | 51 + branches/WOF2-3/hw/mthca/kernel/mt_packer.c | 205 + branches/WOF2-3/hw/mthca/kernel/mt_pci.h | 131 + branches/WOF2-3/hw/mthca/kernel/mt_pcipool.h | 103 + .../WOF2-3/hw/mthca/kernel/mt_reset_tavor.c | 485 + branches/WOF2-3/hw/mthca/kernel/mt_spinlock.h | 143 + branches/WOF2-3/hw/mthca/kernel/mt_sync.h | 109 + branches/WOF2-3/hw/mthca/kernel/mt_types.h | 60 + .../WOF2-3/hw/mthca/kernel/mt_ud_header.c | 280 + branches/WOF2-3/hw/mthca/kernel/mt_uverbs.c | 101 + branches/WOF2-3/hw/mthca/kernel/mt_verbs.c | 929 ++ branches/WOF2-3/hw/mthca/kernel/mthca.cdf | 29 + branches/WOF2-3/hw/mthca/kernel/mthca.h | 9 + branches/WOF2-3/hw/mthca/kernel/mthca.inx | 463 + branches/WOF2-3/hw/mthca/kernel/mthca32.cdf | 22 + .../WOF2-3/hw/mthca/kernel/mthca_allocator.c | 294 + branches/WOF2-3/hw/mthca/kernel/mthca_av.c | 293 + branches/WOF2-3/hw/mthca/kernel/mthca_catas.c | 166 + branches/WOF2-3/hw/mthca/kernel/mthca_cmd.c | 1844 +++ branches/WOF2-3/hw/mthca/kernel/mthca_cmd.h | 327 + .../WOF2-3/hw/mthca/kernel/mthca_config_reg.h | 50 + branches/WOF2-3/hw/mthca/kernel/mthca_cq.c | 989 ++ branches/WOF2-3/hw/mthca/kernel/mthca_dev.h | 608 + .../WOF2-3/hw/mthca/kernel/mthca_doorbell.h | 106 + branches/WOF2-3/hw/mthca/kernel/mthca_eq.c | 1249 ++ branches/WOF2-3/hw/mthca/kernel/mthca_log.c | 242 + branches/WOF2-3/hw/mthca/kernel/mthca_log.mc | 56 + branches/WOF2-3/hw/mthca/kernel/mthca_mad.c | 286 + branches/WOF2-3/hw/mthca/kernel/mthca_main.c | 1095 ++ branches/WOF2-3/hw/mthca/kernel/mthca_mcg.c | 403 + .../WOF2-3/hw/mthca/kernel/mthca_memfree.c | 729 + .../WOF2-3/hw/mthca/kernel/mthca_memfree.h | 177 + branches/WOF2-3/hw/mthca/kernel/mthca_mr.c | 976 ++ branches/WOF2-3/hw/mthca/kernel/mthca_pd.c | 83 + .../WOF2-3/hw/mthca/kernel/mthca_profile.c | 290 + .../WOF2-3/hw/mthca/kernel/mthca_profile.h | 61 + .../WOF2-3/hw/mthca/kernel/mthca_provider.c | 1315 ++ .../WOF2-3/hw/mthca/kernel/mthca_provider.h | 401 + branches/WOF2-3/hw/mthca/kernel/mthca_qp.c | 2542 ++++ branches/WOF2-3/hw/mthca/kernel/mthca_srq.c | 743 + branches/WOF2-3/hw/mthca/kernel/mthca_uar.c | 78 + branches/WOF2-3/hw/mthca/mt_utils.c | 50 + branches/WOF2-3/hw/mthca/mt_utils.h | 225 + branches/WOF2-3/hw/mthca/mthca_wqe.h | 139 + branches/WOF2-3/hw/mthca/mx_abi.h | 178 + branches/WOF2-3/hw/mthca/user/Makefile | 7 + branches/WOF2-3/hw/mthca/user/SOURCES | 87 + branches/WOF2-3/hw/mthca/user/arch.h | 53 + branches/WOF2-3/hw/mthca/user/mlnx_ual_av.c | 362 + branches/WOF2-3/hw/mthca/user/mlnx_ual_ca.c | 203 + branches/WOF2-3/hw/mthca/user/mlnx_ual_cq.c | 220 + branches/WOF2-3/hw/mthca/user/mlnx_ual_data.h | 52 + branches/WOF2-3/hw/mthca/user/mlnx_ual_main.c | 164 + branches/WOF2-3/hw/mthca/user/mlnx_ual_main.h | 134 + .../WOF2-3/hw/mthca/user/mlnx_ual_mcast.c | 122 + branches/WOF2-3/hw/mthca/user/mlnx_ual_mrw.c | 232 + .../WOF2-3/hw/mthca/user/mlnx_ual_osbypass.c | 254 + branches/WOF2-3/hw/mthca/user/mlnx_ual_pd.c | 182 + branches/WOF2-3/hw/mthca/user/mlnx_ual_qp.c | 386 + branches/WOF2-3/hw/mthca/user/mlnx_ual_srq.c | 262 + branches/WOF2-3/hw/mthca/user/mlnx_uvp.c | 212 + branches/WOF2-3/hw/mthca/user/mlnx_uvp.def | 10 + branches/WOF2-3/hw/mthca/user/mlnx_uvp.h | 338 + branches/WOF2-3/hw/mthca/user/mlnx_uvp.rc | 48 + branches/WOF2-3/hw/mthca/user/mlnx_uvp_ah.c | 190 + branches/WOF2-3/hw/mthca/user/mlnx_uvp_cq.c | 628 + .../WOF2-3/hw/mthca/user/mlnx_uvp_debug.c | 85 + .../WOF2-3/hw/mthca/user/mlnx_uvp_debug.h | 145 + .../WOF2-3/hw/mthca/user/mlnx_uvp_doorbell.h | 80 + .../WOF2-3/hw/mthca/user/mlnx_uvp_memfree.c | 207 + branches/WOF2-3/hw/mthca/user/mlnx_uvp_qp.c | 1088 ++ branches/WOF2-3/hw/mthca/user/mlnx_uvp_srq.c | 326 + .../WOF2-3/hw/mthca/user/mlnx_uvp_verbs.c | 512 + .../WOF2-3/hw/mthca/user/mlnx_uvp_verbs.h | 491 + branches/WOF2-3/hw/mthca/user/mt_l2w.h | 104 + branches/WOF2-3/hw/mthca/user/opcode.h | 149 + branches/WOF2-3/inc/complib/cl_async_proc.h | 342 + branches/WOF2-3/inc/complib/cl_atomic.h | 297 + branches/WOF2-3/inc/complib/cl_byteswap.h | 539 + branches/WOF2-3/inc/complib/cl_comppool.h | 619 + branches/WOF2-3/inc/complib/cl_debug.h | 599 + branches/WOF2-3/inc/complib/cl_event.h | 304 + branches/WOF2-3/inc/complib/cl_fleximap.h | 992 ++ branches/WOF2-3/inc/complib/cl_ioctl.h | 626 + branches/WOF2-3/inc/complib/cl_irqlock.h | 248 + branches/WOF2-3/inc/complib/cl_list.h | 1364 ++ branches/WOF2-3/inc/complib/cl_log.h | 245 + branches/WOF2-3/inc/complib/cl_map.h | 875 ++ branches/WOF2-3/inc/complib/cl_math.h | 138 + branches/WOF2-3/inc/complib/cl_memory.h | 963 ++ branches/WOF2-3/inc/complib/cl_mutex.h | 235 + branches/WOF2-3/inc/complib/cl_nodenamemap.h | 73 + branches/WOF2-3/inc/complib/cl_obj.h | 998 ++ branches/WOF2-3/inc/complib/cl_passivelock.h | 433 + branches/WOF2-3/inc/complib/cl_perf.h | 807 + branches/WOF2-3/inc/complib/cl_pool.h | 594 + branches/WOF2-3/inc/complib/cl_ptr_vector.h | 878 ++ branches/WOF2-3/inc/complib/cl_qcomppool.h | 785 + branches/WOF2-3/inc/complib/cl_qlist.h | 1756 +++ branches/WOF2-3/inc/complib/cl_qlockpool.h | 369 + branches/WOF2-3/inc/complib/cl_qmap.h | 973 ++ branches/WOF2-3/inc/complib/cl_qpool.h | 639 + branches/WOF2-3/inc/complib/cl_rbmap.h | 593 + branches/WOF2-3/inc/complib/cl_reqmgr.h | 481 + branches/WOF2-3/inc/complib/cl_spinlock.h | 238 + branches/WOF2-3/inc/complib/cl_syscallback.h | 368 + branches/WOF2-3/inc/complib/cl_thread.h | 396 + branches/WOF2-3/inc/complib/cl_threadpool.h | 306 + branches/WOF2-3/inc/complib/cl_timer.h | 446 + branches/WOF2-3/inc/complib/cl_types.h | 509 + branches/WOF2-3/inc/complib/cl_vector.h | 1004 ++ branches/WOF2-3/inc/complib/cl_waitobj.h | 377 + branches/WOF2-3/inc/complib/comp_lib.h | 115 + branches/WOF2-3/inc/iba/ib_al.h | 10095 +++++++++++++ branches/WOF2-3/inc/iba/ib_al_ioctl.h | 3636 +++++ branches/WOF2-3/inc/iba/ib_at_ioctl.h | 171 + branches/WOF2-3/inc/iba/ib_ci.h | 3023 ++++ branches/WOF2-3/inc/iba/ib_types.h | 12533 ++++++++++++++++ .../WOF2-3/inc/kernel/complib/cl_atomic_osd.h | 107 + .../WOF2-3/inc/kernel/complib/cl_bus_ifc.h | 75 + .../inc/kernel/complib/cl_byteswap_osd.h | 67 + .../WOF2-3/inc/kernel/complib/cl_debug_osd.h | 122 + .../WOF2-3/inc/kernel/complib/cl_event_osd.h | 119 + branches/WOF2-3/inc/kernel/complib/cl_init.h | 59 + .../WOF2-3/inc/kernel/complib/cl_ioctl_osd.h | 203 + .../inc/kernel/complib/cl_irqlock_osd.h | 128 + .../WOF2-3/inc/kernel/complib/cl_memory_osd.h | 216 + .../WOF2-3/inc/kernel/complib/cl_mutex_osd.h | 106 + .../WOF2-3/inc/kernel/complib/cl_packoff.h | 36 + .../WOF2-3/inc/kernel/complib/cl_packon.h | 51 + .../WOF2-3/inc/kernel/complib/cl_pnp_po.h | 994 ++ .../inc/kernel/complib/cl_spinlock_osd.h | 120 + .../inc/kernel/complib/cl_syscallback_osd.h | 45 + .../WOF2-3/inc/kernel/complib/cl_thread_osd.h | 89 + .../WOF2-3/inc/kernel/complib/cl_timer_osd.h | 104 + .../WOF2-3/inc/kernel/complib/cl_types_osd.h | 154 + .../inc/kernel/complib/cl_waitobj_osd.h | 107 + branches/WOF2-3/inc/kernel/iba/ib_al_ifc.h | 775 + branches/WOF2-3/inc/kernel/iba/ib_ci_ifc.h | 136 + branches/WOF2-3/inc/kernel/iba/ib_cm_ifc.h | 318 + branches/WOF2-3/inc/kernel/iba/ib_rdma_cm.h | 65 + branches/WOF2-3/inc/kernel/iba/ioc_ifc.h | 96 + branches/WOF2-3/inc/kernel/iba/iou_ifc.h | 103 + branches/WOF2-3/inc/kernel/iba/ipoib_ifc.h | 112 + branches/WOF2-3/inc/kernel/index_list.h | 88 + branches/WOF2-3/inc/kernel/ip_packet.h | 561 + branches/WOF2-3/inc/kernel/rdma/verbs.h | 63 + branches/WOF2-3/inc/kernel/shutter.h | 119 + branches/WOF2-3/inc/kernel/work_queue.h | 71 + branches/WOF2-3/inc/mod_ver.def | 20 + branches/WOF2-3/inc/mthca/mthca_vc.h | 101 + branches/WOF2-3/inc/oib_ver.h | 70 + branches/WOF2-3/inc/openib.def | 31 + branches/WOF2-3/inc/user/comp_channel.h | 106 + .../WOF2-3/inc/user/complib/cl_atomic_osd.h | 107 + .../WOF2-3/inc/user/complib/cl_byteswap_osd.h | 68 + .../WOF2-3/inc/user/complib/cl_debug_osd.h | 87 + .../WOF2-3/inc/user/complib/cl_event_osd.h | 120 + .../WOF2-3/inc/user/complib/cl_ioctl_osd.h | 118 + .../WOF2-3/inc/user/complib/cl_memory_osd.h | 101 + .../WOF2-3/inc/user/complib/cl_mutex_osd.h | 106 + branches/WOF2-3/inc/user/complib/cl_packoff.h | 36 + branches/WOF2-3/inc/user/complib/cl_packon.h | 51 + .../WOF2-3/inc/user/complib/cl_spinlock_osd.h | 127 + .../inc/user/complib/cl_syscallback_osd.h | 51 + .../WOF2-3/inc/user/complib/cl_thread_osd.h | 91 + .../WOF2-3/inc/user/complib/cl_timer_osd.h | 53 + .../WOF2-3/inc/user/complib/cl_types_osd.h | 157 + .../WOF2-3/inc/user/complib/cl_waitobj_osd.h | 120 + branches/WOF2-3/inc/user/dlist.h | 81 + branches/WOF2-3/inc/user/getopt.h | 67 + branches/WOF2-3/inc/user/iba/ib_uvp.h | 3492 +++++ branches/WOF2-3/inc/user/iba/ibat.h | 83 + branches/WOF2-3/inc/user/iba/winmad.h | 162 + branches/WOF2-3/inc/user/linux/_errno.h | 91 + branches/WOF2-3/inc/user/linux/_string.h | 47 + branches/WOF2-3/inc/user/linux/arpa/inet.h | 52 + branches/WOF2-3/inc/user/linux/inttypes.h | 37 + branches/WOF2-3/inc/user/linux/netdb.h | 37 + branches/WOF2-3/inc/user/linux/netinet/in.h | 42 + branches/WOF2-3/inc/user/linux/search.h | 59 + branches/WOF2-3/inc/user/linux/sys/socket.h | 33 + branches/WOF2-3/inc/user/linux/sys/time.h | 41 + branches/WOF2-3/inc/user/linux/unistd.h | 55 + branches/WOF2-3/inc/user/rdma/winverbs.h | 1551 ++ branches/WOF2-3/inc/user/rdma/wvstatus.h | 134 + branches/WOF2-3/inc/user/wsd/ibsp_regpath.h | 66 + branches/WOF2-3/tests/alts/allocdeallocpd.c | 116 + branches/WOF2-3/tests/alts/alts_common.h | 299 + branches/WOF2-3/tests/alts/alts_debug.h | 79 + branches/WOF2-3/tests/alts/alts_misc.c | 255 + branches/WOF2-3/tests/alts/alts_readme.txt | 119 + branches/WOF2-3/tests/alts/cmtests.c | 4258 ++++++ .../WOF2-3/tests/alts/createanddestroycq.c | 333 + .../WOF2-3/tests/alts/createanddestroyqp.c | 285 + branches/WOF2-3/tests/alts/createdestroyav.c | 334 + branches/WOF2-3/tests/alts/creatememwindow.c | 241 + branches/WOF2-3/tests/alts/dirs | 3 + branches/WOF2-3/tests/alts/ibquery.c | 583 + branches/WOF2-3/tests/alts/kernel/SOURCES | 38 + branches/WOF2-3/tests/alts/kernel/alts.inf | 169 + branches/WOF2-3/tests/alts/kernel/alts.rc | 47 + .../WOF2-3/tests/alts/kernel/alts_driver.c | 346 + .../WOF2-3/tests/alts/kernel/alts_driver.h | 23 + branches/WOF2-3/tests/alts/kernel/makefile | 7 + branches/WOF2-3/tests/alts/madtests.c | 3035 ++++ branches/WOF2-3/tests/alts/multisendrecv.c | 2369 +++ branches/WOF2-3/tests/alts/openclose.c | 81 + branches/WOF2-3/tests/alts/querycaattr.c | 271 + .../WOF2-3/tests/alts/registermemregion.c | 724 + branches/WOF2-3/tests/alts/registerpnp.c | 208 + branches/WOF2-3/tests/alts/smatests.c | 439 + branches/WOF2-3/tests/alts/user/SOURCES | 35 + branches/WOF2-3/tests/alts/user/alts_main.c | 504 + branches/WOF2-3/tests/alts/user/makefile | 7 + branches/WOF2-3/tests/cmtest/dirs | 2 + branches/WOF2-3/tests/cmtest/user/SOURCES | 20 + branches/WOF2-3/tests/cmtest/user/cmtest.rc | 48 + .../WOF2-3/tests/cmtest/user/cmtest_main.c | 2036 +++ branches/WOF2-3/tests/cmtest/user/makefile | 7 + branches/WOF2-3/tests/dirs | 8 + branches/WOF2-3/tests/ibat/dirs | 2 + branches/WOF2-3/tests/ibat/user/PrintIp.c | 254 + branches/WOF2-3/tests/ibat/user/SOURCES | 18 + branches/WOF2-3/tests/ibat/user/makefile | 7 + branches/WOF2-3/tests/limits/dirs | 2 + branches/WOF2-3/tests/limits/user/SOURCES | 20 + .../WOF2-3/tests/limits/user/limits_main.c | 530 + branches/WOF2-3/tests/limits/user/makefile | 7 + branches/WOF2-3/tests/perftest/dirs | 9 + branches/WOF2-3/tests/perftest/perftest.c | 173 + branches/WOF2-3/tests/perftest/perftest.h | 49 + .../WOF2-3/tests/perftest/rdma_bw/SOURCES | 33 + .../WOF2-3/tests/perftest/rdma_bw/makefile | 7 + .../WOF2-3/tests/perftest/rdma_bw/rdma_bw.c | 1126 ++ .../WOF2-3/tests/perftest/rdma_bw/rdma_bw.rc | 47 + .../WOF2-3/tests/perftest/rdma_lat/SOURCES | 33 + .../WOF2-3/tests/perftest/rdma_lat/makefile | 7 + .../WOF2-3/tests/perftest/rdma_lat/rdma_lat.c | 1147 ++ .../tests/perftest/rdma_lat/rdma_lat.rc | 47 + .../WOF2-3/tests/perftest/read_bw/SOURCES | 30 + .../WOF2-3/tests/perftest/read_bw/makefile | 7 + .../WOF2-3/tests/perftest/read_bw/read_bw.c | 754 + .../WOF2-3/tests/perftest/read_bw/read_bw.rc | 47 + .../WOF2-3/tests/perftest/read_lat/SOURCES | 30 + .../WOF2-3/tests/perftest/read_lat/makefile | 7 + .../WOF2-3/tests/perftest/read_lat/read_lat.c | 808 + .../tests/perftest/read_lat/read_lat.rc | 47 + .../WOF2-3/tests/perftest/send_bw/SOURCES | 30 + .../WOF2-3/tests/perftest/send_bw/makefile | 7 + .../WOF2-3/tests/perftest/send_bw/send_bw.c | 1177 ++ .../WOF2-3/tests/perftest/send_bw/send_bw.rc | 47 + .../WOF2-3/tests/perftest/send_lat/SOURCES | 30 + .../WOF2-3/tests/perftest/send_lat/makefile | 7 + .../WOF2-3/tests/perftest/send_lat/send_lat.c | 1059 ++ .../tests/perftest/send_lat/send_lat.rc | 47 + .../WOF2-3/tests/perftest/write_bw/SOURCES | 29 + .../WOF2-3/tests/perftest/write_bw/makefile | 7 + .../WOF2-3/tests/perftest/write_bw/write_bw.c | 887 ++ .../tests/perftest/write_bw/write_bw.rc | 47 + .../tests/perftest/write_bw_postlist/SOURCES | 30 + .../tests/perftest/write_bw_postlist/makefile | 7 + .../write_bw_postlist/write_bw_postlist.c | 987 ++ .../write_bw_postlist/write_bw_postlist.rc | 47 + .../WOF2-3/tests/perftest/write_lat/SOURCES | 30 + .../WOF2-3/tests/perftest/write_lat/makefile | 7 + .../tests/perftest/write_lat/write_lat.c | 798 + .../tests/perftest/write_lat/write_lat.rc | 47 + branches/WOF2-3/tests/wherebu/dirs | 2 + branches/WOF2-3/tests/wherebu/user/SOURCES | 20 + branches/WOF2-3/tests/wherebu/user/makefile | 7 + .../WOF2-3/tests/wherebu/user/wherebu.cpp | 121 + branches/WOF2-3/tests/wsd/dirs | 2 + .../WOF2-3/tests/wsd/user/contest/contest.c | 200 + .../WOF2-3/tests/wsd/user/contest/contest.h | 4 + branches/WOF2-3/tests/wsd/user/dirs | 2 + branches/WOF2-3/tests/wsd/user/test1/test1.c | 233 + branches/WOF2-3/tests/wsd/user/test2/ibwrap.c | 599 + branches/WOF2-3/tests/wsd/user/test2/ibwrap.h | 41 + branches/WOF2-3/tests/wsd/user/test2/test2.c | 64 + branches/WOF2-3/tests/wsd/user/test3/ibwrap.c | 610 + branches/WOF2-3/tests/wsd/user/test3/ibwrap.h | 44 + branches/WOF2-3/tests/wsd/user/test3/test3.c | 126 + branches/WOF2-3/tests/wsd/user/ttcp/SOURCES | 13 + branches/WOF2-3/tests/wsd/user/ttcp/makefile | 7 + branches/WOF2-3/tests/wsd/user/ttcp/ttcp.c | 860 ++ branches/WOF2-3/tools/dirs | 9 + branches/WOF2-3/tools/infiniband-diags/dirs | 1 + .../tools/infiniband-diags/include/grouping.h | 113 + .../infiniband-diags/include/ibdiag_common.h | 78 + .../infiniband-diags/include/ibnetdiscover.h | 107 + .../infiniband-diags/include/windows/config.h | 40 + .../include/windows/ibdiag_version.h | 41 + .../patches/ibping-cdecl.diff | 19 + .../WOF2-3/tools/infiniband-diags/src/dirs | 19 + .../tools/infiniband-diags/src/grouping.c | 785 + .../tools/infiniband-diags/src/ibaddr.c | 165 + .../tools/infiniband-diags/src/ibaddr/SOURCES | 34 + .../infiniband-diags/src/ibaddr/ibaddr.rc | 47 + .../infiniband-diags/src/ibaddr/makefile | 7 + .../infiniband-diags/src/ibdiag_common.c | 330 + .../infiniband-diags/src/ibdiag_windows.c | 40 + .../tools/infiniband-diags/src/iblinkinfo.c | 419 + .../infiniband-diags/src/iblinkinfo/SOURCES | 36 + .../src/iblinkinfo/iblinkinfo.rc | 47 + .../infiniband-diags/src/iblinkinfo/makefile | 7 + .../infiniband-diags/src/ibnetdiscover.c | 1008 ++ .../src/ibnetdiscover/SOURCES | 36 + .../src/ibnetdiscover/ibnetdiscover.rc | 47 + .../src/ibnetdiscover/makefile | 7 + .../tools/infiniband-diags/src/ibping.c | 265 + .../tools/infiniband-diags/src/ibping/SOURCES | 33 + .../infiniband-diags/src/ibping/ibping.rc | 47 + .../infiniband-diags/src/ibping/makefile | 7 + .../tools/infiniband-diags/src/ibportstate.c | 485 + .../infiniband-diags/src/ibportstate/SOURCES | 30 + .../src/ibportstate/ibportstate.rc | 47 + .../infiniband-diags/src/ibportstate/makefile | 7 + .../infiniband-diags/src/ibqueryerrors.c | 688 + .../src/ibqueryerrors/SOURCES | 36 + .../src/ibqueryerrors/ibqueryerrors.rc | 47 + .../src/ibqueryerrors/makefile | 7 + .../tools/infiniband-diags/src/ibroute.c | 452 + .../infiniband-diags/src/ibroute/SOURCES | 33 + .../infiniband-diags/src/ibroute/ibroute.rc | 47 + .../infiniband-diags/src/ibroute/makefile | 7 + .../tools/infiniband-diags/src/ibsendtrap.c | 214 + .../infiniband-diags/src/ibsendtrap/SOURCES | 30 + .../src/ibsendtrap/ibsendtrap.rc | 47 + .../infiniband-diags/src/ibsendtrap/makefile | 7 + .../tools/infiniband-diags/src/ibstat.c | 275 + .../tools/infiniband-diags/src/ibstat/SOURCES | 31 + .../infiniband-diags/src/ibstat/ibstat.rc | 47 + .../infiniband-diags/src/ibstat/makefile | 7 + .../tools/infiniband-diags/src/ibsysstat.c | 370 + .../infiniband-diags/src/ibsysstat/SOURCES | 31 + .../src/ibsysstat/ibsysstat.rc | 47 + .../infiniband-diags/src/ibsysstat/makefile | 7 + .../tools/infiniband-diags/src/ibtracert.c | 824 + .../infiniband-diags/src/ibtracert/SOURCES | 33 + .../src/ibtracert/ibtracert.rc | 47 + .../infiniband-diags/src/ibtracert/makefile | 7 + .../infiniband-diags/src/mcm_rereg_test.c | 500 + .../src/mcm_rereg_test/SOURCES | 30 + .../src/mcm_rereg_test/makefile | 7 + .../src/mcm_rereg_test/mcm_rereg_test.rc | 47 + .../tools/infiniband-diags/src/perfquery.c | 620 + .../infiniband-diags/src/perfquery/SOURCES | 31 + .../infiniband-diags/src/perfquery/makefile | 7 + .../src/perfquery/perfquery.rc | 47 + .../tools/infiniband-diags/src/saquery.c | 1827 +++ .../infiniband-diags/src/saquery/SOURCES | 35 + .../infiniband-diags/src/saquery/makefile | 7 + .../infiniband-diags/src/saquery/saquery.rc | 47 + .../tools/infiniband-diags/src/sminfo.c | 159 + .../tools/infiniband-diags/src/sminfo/SOURCES | 30 + .../infiniband-diags/src/sminfo/makefile | 7 + .../infiniband-diags/src/sminfo/sminfo.rc | 47 + .../tools/infiniband-diags/src/smpdump.c | 304 + .../infiniband-diags/src/smpdump/SOURCES | 31 + .../infiniband-diags/src/smpdump/makefile | 7 + .../infiniband-diags/src/smpdump/smpdump.rc | 47 + .../tools/infiniband-diags/src/smpquery.c | 475 + .../infiniband-diags/src/smpquery/SOURCES | 33 + .../infiniband-diags/src/smpquery/makefile | 7 + .../infiniband-diags/src/smpquery/smpquery.rc | 47 + .../tools/infiniband-diags/src/vendstat.c | 442 + .../infiniband-diags/src/vendstat/SOURCES | 31 + .../infiniband-diags/src/vendstat/makefile | 7 + .../infiniband-diags/src/vendstat/vendstat.rc | 47 + branches/WOF2-3/tools/ndinstall/dirs | 2 + branches/WOF2-3/tools/ndinstall/user/SOURCES | 23 + .../WOF2-3/tools/ndinstall/user/installsp.c | 354 + .../WOF2-3/tools/ndinstall/user/installsp.rc | 48 + branches/WOF2-3/tools/ndinstall/user/makefile | 15 + branches/WOF2-3/tools/nsc/SOURCES | 26 + branches/WOF2-3/tools/nsc/makefile | 8 + branches/WOF2-3/tools/nsc/nsc.c | 67 + branches/WOF2-3/tools/nsc/nsc.rc | 47 + branches/WOF2-3/tools/part_man/dirs | 2 + branches/WOF2-3/tools/part_man/user/SOURCES | 23 + branches/WOF2-3/tools/part_man/user/makefile | 7 + .../WOF2-3/tools/part_man/user/part_man.c | 587 + .../WOF2-3/tools/part_man/user/part_man.rc | 15 + branches/WOF2-3/tools/perftests/dirs | 2 + branches/WOF2-3/tools/perftests/user/README | 101 + branches/WOF2-3/tools/perftests/user/TODO | 1 + .../WOF2-3/tools/perftests/user/clock_test.c | 24 + branches/WOF2-3/tools/perftests/user/dirs | 9 + .../WOF2-3/tools/perftests/user/get_clock.c | 185 + .../WOF2-3/tools/perftests/user/get_clock.h | 79 + branches/WOF2-3/tools/perftests/user/getopt.c | 250 + branches/WOF2-3/tools/perftests/user/getopt.h | 117 + .../WOF2-3/tools/perftests/user/perf_defs.h | 157 + .../WOF2-3/tools/perftests/user/perf_utils.c | 246 + .../tools/perftests/user/read_bw/SOURCES | 28 + .../tools/perftests/user/read_bw/makefile | 7 + .../tools/perftests/user/read_bw/read_bw.c | 788 + .../tools/perftests/user/read_bw/read_bw.rc | 47 + .../tools/perftests/user/read_lat/SOURCES | 28 + .../tools/perftests/user/read_lat/makefile | 7 + .../tools/perftests/user/read_lat/read_lat.c | 810 + .../tools/perftests/user/read_lat/read_lat.rc | 47 + .../tools/perftests/user/send_bw/SOURCES | 28 + .../tools/perftests/user/send_bw/makefile | 7 + .../tools/perftests/user/send_bw/send_bw.c | 1208 ++ .../tools/perftests/user/send_bw/send_bw.rc | 47 + .../tools/perftests/user/send_lat/SOURCES | 28 + .../tools/perftests/user/send_lat/makefile | 7 + .../tools/perftests/user/send_lat/send_lat.c | 1025 ++ .../tools/perftests/user/send_lat/send_lat.rc | 47 + .../tools/perftests/user/write_bw/SOURCES | 28 + .../tools/perftests/user/write_bw/makefile | 7 + .../tools/perftests/user/write_bw/write_bw.c | 881 ++ .../tools/perftests/user/write_bw/write_bw.rc | 47 + .../tools/perftests/user/write_lat/SOURCES | 28 + .../tools/perftests/user/write_lat/makefile | 7 + .../perftests/user/write_lat/write_lat.c | 849 ++ .../perftests/user/write_lat/write_lat.rc | 47 + branches/WOF2-3/tools/qlgcvnic_config/SOURCES | 20 + .../WOF2-3/tools/qlgcvnic_config/makefile | 7 + .../tools/qlgcvnic_config/qlgcvnic_config.rc | 47 + .../tools/qlgcvnic_config/vnic_child_config.c | 560 + branches/WOF2-3/tools/vstat/dirs | 2 + branches/WOF2-3/tools/vstat/user/SOURCES | 23 + branches/WOF2-3/tools/vstat/user/makefile | 7 + branches/WOF2-3/tools/vstat/user/vstat.rc | 47 + branches/WOF2-3/tools/vstat/user/vstat_main.c | 781 + branches/WOF2-3/tools/wsdinstall/dirs | 2 + .../tools/wsdinstall/user/InstallSP.sln | 21 + branches/WOF2-3/tools/wsdinstall/user/SOURCES | 23 + .../WOF2-3/tools/wsdinstall/user/installsp.c | 759 + .../wsdinstall/user/installsp.exe.manifest | 10 + .../WOF2-3/tools/wsdinstall/user/installsp.rc | 47 + .../WOF2-3/tools/wsdinstall/user/makefile | 8 + .../ulp/dapl/dapl/common/dapl_adapter_util.h | 300 + .../ulp/dapl/dapl/common/dapl_cno_create.c | 104 + .../ulp/dapl/dapl/common/dapl_cno_free.c | 89 + .../dapl/dapl/common/dapl_cno_modify_agent.c | 82 + .../ulp/dapl/dapl/common/dapl_cno_query.c | 97 + .../ulp/dapl/dapl/common/dapl_cno_util.c | 195 + .../ulp/dapl/dapl/common/dapl_cno_util.h | 56 + .../ulp/dapl/dapl/common/dapl_cno_wait.c | 133 + .../WOF2-3/ulp/dapl/dapl/common/dapl_cookie.c | 400 + .../WOF2-3/ulp/dapl/dapl/common/dapl_cookie.h | 71 + .../ulp/dapl/dapl/common/dapl_cr_accept.c | 322 + .../ulp/dapl/dapl/common/dapl_cr_callback.c | 615 + .../ulp/dapl/dapl/common/dapl_cr_handoff.c | 78 + .../ulp/dapl/dapl/common/dapl_cr_query.c | 104 + .../ulp/dapl/dapl/common/dapl_cr_reject.c | 141 + .../ulp/dapl/dapl/common/dapl_cr_util.c | 115 + .../ulp/dapl/dapl/common/dapl_cr_util.h | 58 + .../WOF2-3/ulp/dapl/dapl/common/dapl_debug.c | 105 + .../ulp/dapl/dapl/common/dapl_ep_connect.c | 373 + .../ulp/dapl/dapl/common/dapl_ep_create.c | 344 + .../ulp/dapl/dapl/common/dapl_ep_disconnect.c | 152 + .../dapl/dapl/common/dapl_ep_dup_connect.c | 129 + .../ulp/dapl/dapl/common/dapl_ep_free.c | 202 + .../ulp/dapl/dapl/common/dapl_ep_get_status.c | 119 + .../ulp/dapl/dapl/common/dapl_ep_modify.c | 756 + .../dapl/dapl/common/dapl_ep_post_rdma_read.c | 105 + .../dapl/common/dapl_ep_post_rdma_write.c | 104 + .../ulp/dapl/dapl/common/dapl_ep_post_recv.c | 135 + .../ulp/dapl/dapl/common/dapl_ep_post_send.c | 100 + .../ulp/dapl/dapl/common/dapl_ep_query.c | 124 + .../ulp/dapl/dapl/common/dapl_ep_reset.c | 106 + .../ulp/dapl/dapl/common/dapl_ep_util.c | 559 + .../ulp/dapl/dapl/common/dapl_ep_util.h | 79 + .../dapl/common/dapl_evd_clear_unwaitable.c | 81 + .../dapl/common/dapl_evd_connection_callb.c | 263 + .../common/dapl_evd_cq_async_error_callb.c | 92 + .../ulp/dapl/dapl/common/dapl_evd_create.c | 193 + .../ulp/dapl/dapl/common/dapl_evd_dequeue.c | 153 + .../ulp/dapl/dapl/common/dapl_evd_disable.c | 79 + .../ulp/dapl/dapl/common/dapl_evd_dto_callb.c | 168 + .../ulp/dapl/dapl/common/dapl_evd_enable.c | 93 + .../ulp/dapl/dapl/common/dapl_evd_free.c | 126 + .../dapl/dapl/common/dapl_evd_modify_cno.c | 116 + .../ulp/dapl/dapl/common/dapl_evd_post_se.c | 103 + .../common/dapl_evd_qp_async_error_callb.c | 127 + .../ulp/dapl/dapl/common/dapl_evd_query.c | 117 + .../ulp/dapl/dapl/common/dapl_evd_resize.c | 193 + .../dapl/common/dapl_evd_set_unwaitable.c | 104 + .../common/dapl_evd_un_async_error_callb.c | 96 + .../ulp/dapl/dapl/common/dapl_evd_util.c | 1457 ++ .../ulp/dapl/dapl/common/dapl_evd_util.h | 150 + .../ulp/dapl/dapl/common/dapl_evd_wait.c | 283 + .../dapl/common/dapl_get_consumer_context.c | 101 + .../dapl/dapl/common/dapl_get_handle_type.c | 88 + .../WOF2-3/ulp/dapl/dapl/common/dapl_hash.c | 537 + .../WOF2-3/ulp/dapl/dapl/common/dapl_hash.h | 103 + .../ulp/dapl/dapl/common/dapl_hca_util.c | 175 + .../ulp/dapl/dapl/common/dapl_hca_util.h | 59 + .../ulp/dapl/dapl/common/dapl_ia_close.c | 100 + .../ulp/dapl/dapl/common/dapl_ia_open.c | 529 + .../ulp/dapl/dapl/common/dapl_ia_query.c | 224 + .../ulp/dapl/dapl/common/dapl_ia_util.c | 1244 ++ .../ulp/dapl/dapl/common/dapl_ia_util.h | 147 + .../WOF2-3/ulp/dapl/dapl/common/dapl_init.h | 56 + .../WOF2-3/ulp/dapl/dapl/common/dapl_llist.c | 380 + .../ulp/dapl/dapl/common/dapl_lmr_create.c | 537 + .../ulp/dapl/dapl/common/dapl_lmr_free.c | 134 + .../ulp/dapl/dapl/common/dapl_lmr_query.c | 93 + .../ulp/dapl/dapl/common/dapl_lmr_util.c | 109 + .../ulp/dapl/dapl/common/dapl_lmr_util.h | 101 + .../ulp/dapl/dapl/common/dapl_mr_util.c | 80 + .../ulp/dapl/dapl/common/dapl_mr_util.h | 92 + .../ulp/dapl/dapl/common/dapl_provider.c | 401 + .../ulp/dapl/dapl/common/dapl_provider.h | 108 + .../ulp/dapl/dapl/common/dapl_psp_create.c | 213 + .../dapl/dapl/common/dapl_psp_create_any.c | 213 + .../ulp/dapl/dapl/common/dapl_psp_free.c | 149 + .../ulp/dapl/dapl/common/dapl_psp_query.c | 104 + .../ulp/dapl/dapl/common/dapl_pz_create.c | 107 + .../ulp/dapl/dapl/common/dapl_pz_free.c | 94 + .../ulp/dapl/dapl/common/dapl_pz_query.c | 95 + .../ulp/dapl/dapl/common/dapl_pz_util.c | 115 + .../ulp/dapl/dapl/common/dapl_pz_util.h | 50 + .../dapl/dapl/common/dapl_ring_buffer_util.c | 348 + .../dapl/dapl/common/dapl_ring_buffer_util.h | 77 + .../ulp/dapl/dapl/common/dapl_rmr_bind.c | 348 + .../ulp/dapl/dapl/common/dapl_rmr_create.c | 110 + .../ulp/dapl/dapl/common/dapl_rmr_free.c | 99 + .../ulp/dapl/dapl/common/dapl_rmr_query.c | 95 + .../ulp/dapl/dapl/common/dapl_rmr_util.c | 96 + .../ulp/dapl/dapl/common/dapl_rmr_util.h | 108 + .../ulp/dapl/dapl/common/dapl_rsp_create.c | 218 + .../ulp/dapl/dapl/common/dapl_rsp_free.c | 161 + .../ulp/dapl/dapl/common/dapl_rsp_query.c | 103 + .../dapl/common/dapl_set_consumer_context.c | 89 + .../ulp/dapl/dapl/common/dapl_sp_util.c | 316 + .../ulp/dapl/dapl/common/dapl_sp_util.h | 62 + branches/WOF2-3/ulp/dapl/dapl/dirs | 1 + .../WOF2-3/ulp/dapl/dapl/ibal/dapl_ibal_cm.c | 2004 +++ .../WOF2-3/ulp/dapl/dapl/ibal/dapl_ibal_dto.h | 354 + .../ulp/dapl/dapl/ibal/dapl_ibal_kmod.h | 107 + .../ulp/dapl/dapl/ibal/dapl_ibal_mrdb.c | 408 + .../ulp/dapl/dapl/ibal/dapl_ibal_mrdb.h | 68 + .../WOF2-3/ulp/dapl/dapl/ibal/dapl_ibal_qp.c | 698 + .../ulp/dapl/dapl/ibal/dapl_ibal_util.c | 2515 ++++ .../ulp/dapl/dapl/ibal/dapl_ibal_util.h | 433 + branches/WOF2-3/ulp/dapl/dapl/include/dapl.h | 1042 ++ .../WOF2-3/ulp/dapl/dapl/include/dapl_debug.h | 135 + .../ulp/dapl/dapl/include/dapl_ipoib_names.h | 261 + .../ulp/dapl/dapl/include/dapl_vendor.h | 125 + .../ulp/dapl/dapl/udapl/Makefile.cygwin | 396 + .../WOF2-3/ulp/dapl/dapl/udapl/Makefile.org | 200 + .../WOF2-3/ulp/dapl/dapl/udapl/Makefile.orig | 305 + branches/WOF2-3/ulp/dapl/dapl/udapl/SOURCES | 45 + .../WOF2-3/ulp/dapl/dapl/udapl/dapl_init.c | 318 + .../ulp/dapl/dapl/udapl/dapl_name_service.c | 333 + .../ulp/dapl/dapl/udapl/dapl_name_service.h | 70 + .../ulp/dapl/dapl/udapl/dapl_timer_util.c | 336 + .../ulp/dapl/dapl/udapl/dapl_timer_util.h | 46 + .../ulp/dapl/dapl/udapl/linux/dapl_osd.c | 642 + .../ulp/dapl/dapl/udapl/linux/dapl_osd.h | 553 + branches/WOF2-3/ulp/dapl/dapl/udapl/makefile | 7 + .../WOF2-3/ulp/dapl/dapl/udapl/makefile.wnd | 283 + branches/WOF2-3/ulp/dapl/dapl/udapl/udapl.rc | 48 + .../ulp/dapl/dapl/udapl/udapl_exports.src | 11 + .../ulp/dapl/dapl/udapl/udapl_sources.c | 112 + .../ulp/dapl/dapl/udapl/windows/dapl_osd.c | 253 + .../ulp/dapl/dapl/udapl/windows/dapl_osd.h | 538 + .../ulp/dapl/dapl/udapl/windows/dapl_win.def | 61 + .../ulp/dapl/dapl/udapl/windows/dapllib.rc | 50 + .../ulp/dapl/dat/common/dat_dictionary.c | 467 + .../ulp/dapl/dat/common/dat_dictionary.h | 115 + branches/WOF2-3/ulp/dapl/dat/common/dat_dr.c | 381 + branches/WOF2-3/ulp/dapl/dat/common/dat_dr.h | 105 + .../WOF2-3/ulp/dapl/dat/common/dat_init.c | 161 + .../WOF2-3/ulp/dapl/dat/common/dat_init.h | 77 + branches/WOF2-3/ulp/dapl/dat/common/dat_sr.c | 412 + branches/WOF2-3/ulp/dapl/dat/common/dat_sr.h | 106 + .../WOF2-3/ulp/dapl/dat/common/dat_strerror.c | 600 + branches/WOF2-3/ulp/dapl/dat/dirs | 1 + .../WOF2-3/ulp/dapl/dat/include/dat/dat.h | 958 ++ .../ulp/dapl/dat/include/dat/dat_error.h | 333 + .../dat/include/dat/dat_platform_specific.h | 191 + .../dapl/dat/include/dat/dat_redirection.h | 333 + .../ulp/dapl/dat/include/dat/dat_registry.h | 103 + .../dat/include/dat/dat_vendor_specific.h | 150 + .../WOF2-3/ulp/dapl/dat/include/dat/kdat.h | 240 + .../ulp/dapl/dat/include/dat/kdat_config.h | 78 + .../dapl/dat/include/dat/kdat_redirection.h | 163 + .../dat/include/dat/kdat_vendor_specific.h | 112 + .../WOF2-3/ulp/dapl/dat/include/dat/udat.h | 332 + .../ulp/dapl/dat/include/dat/udat_config.h | 76 + .../dapl/dat/include/dat/udat_redirection.h | 225 + .../dat/include/dat/udat_vendor_specific.h | 143 + branches/WOF2-3/ulp/dapl/dat/kdat/Makefile | 113 + branches/WOF2-3/ulp/dapl/dat/kdat/dat_kdapl.c | 101 + .../WOF2-3/ulp/dapl/dat/kdat/dat_module.c | 104 + .../WOF2-3/ulp/dapl/dat/kdat/linux/dat_osd.c | 262 + .../WOF2-3/ulp/dapl/dat/kdat/linux/dat_osd.h | 258 + .../WOF2-3/ulp/dapl/dat/udat/Makefile.cygwin | 271 + .../WOF2-3/ulp/dapl/dat/udat/Makefile.org | 86 + .../WOF2-3/ulp/dapl/dat/udat/Makefile.orig | 114 + branches/WOF2-3/ulp/dapl/dat/udat/SOURCES | 31 + branches/WOF2-3/ulp/dapl/dat/udat/dat.conf | 7 + branches/WOF2-3/ulp/dapl/dat/udat/ibhosts | 7 + .../ulp/dapl/dat/udat/linux/dat-1.1.spec | 80 + .../WOF2-3/ulp/dapl/dat/udat/linux/dat_osd.c | 179 + .../WOF2-3/ulp/dapl/dat/udat/linux/dat_osd.h | 394 + branches/WOF2-3/ulp/dapl/dat/udat/makefile | 7 + .../WOF2-3/ulp/dapl/dat/udat/makefile.wnd | 144 + branches/WOF2-3/ulp/dapl/dat/udat/udat.c | 420 + branches/WOF2-3/ulp/dapl/dat/udat/udat.rc | 48 + .../WOF2-3/ulp/dapl/dat/udat/udat_exports.src | 15 + .../WOF2-3/ulp/dapl/dat/udat/udat_sources.c | 33 + .../WOF2-3/ulp/dapl/dat/udat/udat_sr_parser.c | 1551 ++ .../WOF2-3/ulp/dapl/dat/udat/udat_sr_parser.h | 59 + .../ulp/dapl/dat/udat/windows/dat_osd.c | 149 + .../ulp/dapl/dat/udat/windows/dat_osd.h | 409 + .../ulp/dapl/dat/udat/windows/dat_osd_sr.h | 59 + .../ulp/dapl/dat/udat/windows/dat_win.def | 9 + branches/WOF2-3/ulp/dapl/dirs | 4 + .../WOF2-3/ulp/dapl/doc/dapl_coding_style.txt | 264 + .../ulp/dapl/doc/dapl_end_point_design.txt | 908 ++ branches/WOF2-3/ulp/dapl/doc/dapl_environ.txt | 42 + .../WOF2-3/ulp/dapl/doc/dapl_event_design.txt | 875 ++ .../doc/dapl_memory_management_design.txt | 173 + .../ulp/dapl/doc/dapl_registry_design.txt | 631 + .../dapl/doc/dapl_shared_memory_design.txt | 867 ++ .../dapl/doc/dapl_vendor_specific_changes.txt | 394 + branches/WOF2-3/ulp/dapl/doc/dat.conf | 11 + branches/WOF2-3/ulp/dapl/doc/dat_environ.txt | 45 + branches/WOF2-3/ulp/dapl/doc/ibhosts | 3 + .../WOF2-3/ulp/dapl/doc/mv_dapl_readme.txt | 226 + .../WOF2-3/ulp/dapl/doc/mv_dapl_relnotes.txt | 167 + branches/WOF2-3/ulp/dapl/test/dirs | 1 + .../ulp/dapl/test/udapl/dapltest/.DT_defaults | 12 + .../ulp/dapl/test/udapl/dapltest/.DT_onetest | 35 + .../ulp/dapl/test/udapl/dapltest/.DT_perf.csh | 42 + .../test/udapl/dapltest/DaplTest_how_2.txt | 292 + .../dapl/test/udapl/dapltest/Makefile.cygwin | 250 + .../ulp/dapl/test/udapl/dapltest/Makefile.org | 54 + .../dapl/test/udapl/dapltest/Makefile.orig | 134 + .../ulp/dapl/test/udapl/dapltest/SOURCES | 69 + .../WOF2-3/ulp/dapl/test/udapl/dapltest/bw.sh | 22 + .../WOF2-3/ulp/dapl/test/udapl/dapltest/cl.sh | 30 + .../ulp/dapl/test/udapl/dapltest/dapl_bpool.c | 348 + .../ulp/dapl/test/udapl/dapltest/dapl_bpool.h | 61 + .../dapl/test/udapl/dapltest/dapl_client.c | 603 + .../test/udapl/dapltest/dapl_client_info.c | 51 + .../test/udapl/dapltest/dapl_client_info.h | 44 + .../ulp/dapl/test/udapl/dapltest/dapl_cnxn.c | 68 + .../ulp/dapl/test/udapl/dapltest/dapl_cnxn.h | 35 + .../dapl/test/udapl/dapltest/dapl_common.h | 47 + .../dapl/test/udapl/dapltest/dapl_endian.c | 96 + .../dapl/test/udapl/dapltest/dapl_fft_cmd.c | 356 + .../dapl/test/udapl/dapltest/dapl_fft_cmd.h | 73 + .../test/udapl/dapltest/dapl_fft_connmgt.c | 120 + .../test/udapl/dapltest/dapl_fft_dataxfer.c | 153 + .../udapl/dapltest/dapl_fft_dataxfer_client.c | 133 + .../test/udapl/dapltest/dapl_fft_endpoint.c | 281 + .../test/udapl/dapltest/dapl_fft_hwconn.c | 225 + .../dapl/test/udapl/dapltest/dapl_fft_mem.c | 237 + .../dapl/test/udapl/dapltest/dapl_fft_pz.c | 254 + .../test/udapl/dapltest/dapl_fft_queryinfo.c | 621 + .../dapl/test/udapl/dapltest/dapl_fft_test.c | 94 + .../dapl/test/udapl/dapltest/dapl_fft_util.c | 357 + .../dapl/test/udapl/dapltest/dapl_fft_util.h | 85 + .../ulp/dapl/test/udapl/dapltest/dapl_funcs.h | 58 + .../dapl/test/udapl/dapltest/dapl_getopt.c | 179 + .../dapl/test/udapl/dapltest/dapl_getopt.h | 48 + .../ulp/dapl/test/udapl/dapltest/dapl_limit.c | 1529 ++ .../dapl/test/udapl/dapltest/dapl_limit_cmd.c | 230 + .../dapl/test/udapl/dapltest/dapl_limit_cmd.h | 60 + .../ulp/dapl/test/udapl/dapltest/dapl_main.c | 196 + .../ulp/dapl/test/udapl/dapltest/dapl_mdep.c | 943 ++ .../ulp/dapl/test/udapl/dapltest/dapl_mdep.h | 333 + .../dapl/test/udapl/dapltest/dapl_memlist.c | 133 + .../dapl/test/udapl/dapltest/dapl_memlist.h | 54 + .../dapl/test/udapl/dapltest/dapl_netaddr.c | 149 + .../dapl/test/udapl/dapltest/dapl_params.c | 296 + .../dapl/test/udapl/dapltest/dapl_params.h | 66 + .../udapl/dapltest/dapl_performance_client.c | 545 + .../udapl/dapltest/dapl_performance_cmd.c | 355 + .../udapl/dapltest/dapl_performance_cmd.h | 63 + .../udapl/dapltest/dapl_performance_server.c | 411 + .../udapl/dapltest/dapl_performance_stats.c | 389 + .../udapl/dapltest/dapl_performance_stats.h | 61 + .../udapl/dapltest/dapl_performance_test.h | 85 + .../udapl/dapltest/dapl_performance_util.c | 652 + .../ulp/dapl/test/udapl/dapltest/dapl_proto.h | 610 + .../dapl/test/udapl/dapltest/dapl_quit_cmd.c | 148 + .../dapl/test/udapl/dapltest/dapl_quit_cmd.h | 39 + .../dapl/test/udapl/dapltest/dapl_server.c | 842 ++ .../test/udapl/dapltest/dapl_server_cmd.c | 124 + .../test/udapl/dapltest/dapl_server_cmd.h | 39 + .../test/udapl/dapltest/dapl_server_info.c | 50 + .../test/udapl/dapltest/dapl_server_info.h | 55 + .../dapl/test/udapl/dapltest/dapl_test_data.c | 59 + .../dapl/test/udapl/dapltest/dapl_test_data.h | 106 + .../dapl/test/udapl/dapltest/dapl_test_util.c | 743 + .../dapl/test/udapl/dapltest/dapl_thread.c | 132 + .../udapl/dapltest/dapl_transaction_cmd.c | 543 + .../udapl/dapltest/dapl_transaction_cmd.h | 64 + .../udapl/dapltest/dapl_transaction_stats.c | 170 + .../udapl/dapltest/dapl_transaction_stats.h | 47 + .../udapl/dapltest/dapl_transaction_test.c | 1922 +++ .../udapl/dapltest/dapl_transaction_test.h | 99 + .../udapl/dapltest/dapl_transaction_util.c | 730 + .../ulp/dapl/test/udapl/dapltest/dapl_util.c | 297 + .../dapl/test/udapl/dapltest/dapl_version.h | 37 + .../ulp/dapl/test/udapl/dapltest/dapltest.rc | 49 + .../ulp/dapl/test/udapl/dapltest/lat_block.sh | 22 + .../ulp/dapl/test/udapl/dapltest/lat_poll.sh | 22 + .../ulp/dapl/test/udapl/dapltest/lim.sh | 17 + .../ulp/dapl/test/udapl/dapltest/makefile | 7 + .../ulp/dapl/test/udapl/dapltest/makefile.wnd | 179 + .../ulp/dapl/test/udapl/dapltest/quit.sh | 19 + .../ulp/dapl/test/udapl/dapltest/regress.sh | 66 + .../ulp/dapl/test/udapl/dapltest/srv.sh | 15 + branches/WOF2-3/ulp/dapl/test/udapl/dirs | 1 + branches/WOF2-3/ulp/dapl2/AUTHORS | 17 + branches/WOF2-3/ulp/dapl2/COPYING | 28 + branches/WOF2-3/ulp/dapl2/ChangeLog | 5079 +++++++ branches/WOF2-3/ulp/dapl2/LICENSE.txt | 235 + branches/WOF2-3/ulp/dapl2/LICENSE2.txt | 30 + branches/WOF2-3/ulp/dapl2/LICENSE3.txt | 340 + branches/WOF2-3/ulp/dapl2/Makefile.am | 581 + branches/WOF2-3/ulp/dapl2/README | 434 + branches/WOF2-3/ulp/dapl2/README.windows | 190 + branches/WOF2-3/ulp/dapl2/autogen.sh | 10 + branches/WOF2-3/ulp/dapl2/configure.in | 104 + branches/WOF2-3/ulp/dapl2/dapl.spec.in | 238 + .../ulp/dapl2/dapl/common/dapl_adapter_util.h | 289 + .../ulp/dapl2/dapl/common/dapl_cno_util.c | 313 + .../ulp/dapl2/dapl/common/dapl_cno_util.h | 66 + .../ulp/dapl2/dapl/common/dapl_cookie.c | 360 + .../ulp/dapl2/dapl/common/dapl_cookie.h | 76 + .../ulp/dapl2/dapl/common/dapl_cr_accept.c | 246 + .../ulp/dapl2/dapl/common/dapl_cr_callback.c | 542 + .../ulp/dapl2/dapl/common/dapl_cr_handoff.c | 65 + .../ulp/dapl2/dapl/common/dapl_cr_query.c | 98 + .../ulp/dapl2/dapl/common/dapl_cr_reject.c | 137 + .../ulp/dapl2/dapl/common/dapl_cr_util.c | 103 + .../ulp/dapl2/dapl/common/dapl_cr_util.h | 59 + .../WOF2-3/ulp/dapl2/dapl/common/dapl_csp.c | 102 + .../WOF2-3/ulp/dapl2/dapl/common/dapl_debug.c | 243 + .../ulp/dapl2/dapl/common/dapl_ep_connect.c | 408 + .../ulp/dapl2/dapl/common/dapl_ep_create.c | 335 + .../dapl/common/dapl_ep_create_with_srq.c | 355 + .../dapl2/dapl/common/dapl_ep_disconnect.c | 183 + .../dapl2/dapl/common/dapl_ep_dup_connect.c | 127 + .../ulp/dapl2/dapl/common/dapl_ep_free.c | 219 + .../dapl2/dapl/common/dapl_ep_get_status.c | 113 + .../ulp/dapl2/dapl/common/dapl_ep_modify.c | 642 + .../dapl/common/dapl_ep_post_rdma_read.c | 100 + .../common/dapl_ep_post_rdma_read_to_rmr.c | 90 + .../dapl/common/dapl_ep_post_rdma_write.c | 99 + .../ulp/dapl2/dapl/common/dapl_ep_post_recv.c | 120 + .../ulp/dapl2/dapl/common/dapl_ep_post_send.c | 97 + .../common/dapl_ep_post_send_invalidate.c | 92 + .../ulp/dapl2/dapl/common/dapl_ep_query.c | 122 + .../dapl2/dapl/common/dapl_ep_recv_query.c | 98 + .../ulp/dapl2/dapl/common/dapl_ep_reset.c | 105 + .../dapl2/dapl/common/dapl_ep_set_watermark.c | 99 + .../ulp/dapl2/dapl/common/dapl_ep_util.c | 615 + .../ulp/dapl2/dapl/common/dapl_ep_util.h | 105 + .../dapl/common/dapl_evd_connection_callb.c | 225 + .../common/dapl_evd_cq_async_error_callb.c | 90 + .../ulp/dapl2/dapl/common/dapl_evd_dequeue.c | 134 + .../dapl2/dapl/common/dapl_evd_dto_callb.c | 158 + .../ulp/dapl2/dapl/common/dapl_evd_free.c | 136 + .../ulp/dapl2/dapl/common/dapl_evd_post_se.c | 97 + .../common/dapl_evd_qp_async_error_callb.c | 155 + .../ulp/dapl2/dapl/common/dapl_evd_resize.c | 136 + .../common/dapl_evd_un_async_error_callb.c | 92 + .../ulp/dapl2/dapl/common/dapl_evd_util.c | 1522 ++ .../ulp/dapl2/dapl/common/dapl_evd_util.h | 175 + .../dapl/common/dapl_get_consumer_context.c | 98 + .../dapl2/dapl/common/dapl_get_handle_type.c | 87 + .../WOF2-3/ulp/dapl2/dapl/common/dapl_hash.c | 478 + .../WOF2-3/ulp/dapl2/dapl/common/dapl_hash.h | 109 + .../ulp/dapl2/dapl/common/dapl_hca_util.c | 162 + .../ulp/dapl2/dapl/common/dapl_hca_util.h | 60 + .../ulp/dapl2/dapl/common/dapl_ia_close.c | 87 + .../WOF2-3/ulp/dapl2/dapl/common/dapl_ia_ha.c | 77 + .../ulp/dapl2/dapl/common/dapl_ia_open.c | 462 + .../ulp/dapl2/dapl/common/dapl_ia_query.c | 232 + .../ulp/dapl2/dapl/common/dapl_ia_util.c | 1140 ++ .../ulp/dapl2/dapl/common/dapl_ia_util.h | 158 + .../WOF2-3/ulp/dapl2/dapl/common/dapl_init.h | 57 + .../WOF2-3/ulp/dapl2/dapl/common/dapl_llist.c | 343 + .../ulp/dapl2/dapl/common/dapl_lmr_free.c | 118 + .../ulp/dapl2/dapl/common/dapl_lmr_query.c | 86 + .../dapl/common/dapl_lmr_sync_rdma_read.c | 83 + .../dapl/common/dapl_lmr_sync_rdma_write.c | 83 + .../ulp/dapl2/dapl/common/dapl_lmr_util.c | 93 + .../ulp/dapl2/dapl/common/dapl_lmr_util.h | 63 + .../ulp/dapl2/dapl/common/dapl_mr_util.c | 113 + .../ulp/dapl2/dapl/common/dapl_mr_util.h | 96 + .../ulp/dapl2/dapl/common/dapl_name_service.c | 264 + .../ulp/dapl2/dapl/common/dapl_name_service.h | 61 + .../ulp/dapl2/dapl/common/dapl_provider.c | 453 + .../ulp/dapl2/dapl/common/dapl_provider.h | 108 + .../ulp/dapl2/dapl/common/dapl_psp_create.c | 205 + .../dapl2/dapl/common/dapl_psp_create_any.c | 215 + .../ulp/dapl2/dapl/common/dapl_psp_free.c | 152 + .../ulp/dapl2/dapl/common/dapl_psp_query.c | 102 + .../ulp/dapl2/dapl/common/dapl_pz_create.c | 100 + .../ulp/dapl2/dapl/common/dapl_pz_free.c | 88 + .../ulp/dapl2/dapl/common/dapl_pz_query.c | 86 + .../ulp/dapl2/dapl/common/dapl_pz_util.c | 111 + .../ulp/dapl2/dapl/common/dapl_pz_util.h | 51 + .../dapl2/dapl/common/dapl_ring_buffer_util.c | 317 + .../dapl2/dapl/common/dapl_ring_buffer_util.h | 78 + .../ulp/dapl2/dapl/common/dapl_rmr_bind.c | 314 + .../ulp/dapl2/dapl/common/dapl_rmr_create.c | 140 + .../ulp/dapl2/dapl/common/dapl_rmr_free.c | 95 + .../ulp/dapl2/dapl/common/dapl_rmr_query.c | 93 + .../ulp/dapl2/dapl/common/dapl_rmr_util.c | 84 + .../ulp/dapl2/dapl/common/dapl_rmr_util.h | 86 + .../ulp/dapl2/dapl/common/dapl_rsp_create.c | 213 + .../ulp/dapl2/dapl/common/dapl_rsp_free.c | 154 + .../ulp/dapl2/dapl/common/dapl_rsp_query.c | 100 + .../dapl/common/dapl_set_consumer_context.c | 86 + .../ulp/dapl2/dapl/common/dapl_sp_util.c | 282 + .../ulp/dapl2/dapl/common/dapl_sp_util.h | 63 + .../ulp/dapl2/dapl/common/dapl_srq_create.c | 151 + .../ulp/dapl2/dapl/common/dapl_srq_free.c | 133 + .../dapl2/dapl/common/dapl_srq_post_recv.c | 123 + .../ulp/dapl2/dapl/common/dapl_srq_query.c | 97 + .../ulp/dapl2/dapl/common/dapl_srq_resize.c | 109 + .../ulp/dapl2/dapl/common/dapl_srq_set_lw.c | 99 + .../ulp/dapl2/dapl/common/dapl_srq_util.c | 138 + .../ulp/dapl2/dapl/common/dapl_srq_util.h | 54 + .../ulp/dapl2/dapl/common/dapl_timer_util.c | 365 + .../ulp/dapl2/dapl/common/dapl_timer_util.h | 48 + .../WOF2-3/ulp/dapl2/dapl/dapl_common_src.c | 112 + .../WOF2-3/ulp/dapl2/dapl/dapl_udapl_src.c | 45 + branches/WOF2-3/ulp/dapl2/dapl/dirs | 1 + branches/WOF2-3/ulp/dapl2/dapl/ibal/SOURCES | 56 + .../WOF2-3/ulp/dapl2/dapl/ibal/dapl_ibal_cm.c | 1842 +++ .../WOF2-3/ulp/dapl2/dapl/ibal/dapl_ibal_cq.c | 435 + .../ulp/dapl2/dapl/ibal/dapl_ibal_dto.h | 767 + .../dapl2/dapl/ibal/dapl_ibal_extensions.c | 326 + .../ulp/dapl2/dapl/ibal/dapl_ibal_kmod.h | 91 + .../ulp/dapl2/dapl/ibal/dapl_ibal_mrdb.c | 392 + .../ulp/dapl2/dapl/ibal/dapl_ibal_mrdb.h | 52 + .../dapl2/dapl/ibal/dapl_ibal_name_service.c | 564 + .../dapl2/dapl/ibal/dapl_ibal_name_service.h | 99 + .../WOF2-3/ulp/dapl2/dapl/ibal/dapl_ibal_qp.c | 707 + .../ulp/dapl2/dapl/ibal/dapl_ibal_util.c | 2318 +++ .../ulp/dapl2/dapl/ibal/dapl_ibal_util.h | 602 + branches/WOF2-3/ulp/dapl2/dapl/ibal/makefile | 7 + branches/WOF2-3/ulp/dapl2/dapl/ibal/udapl.rc | 48 + .../ulp/dapl2/dapl/ibal/udapl_exports.src | 14 + branches/WOF2-3/ulp/dapl2/dapl/include/dapl.h | 1269 ++ .../ulp/dapl2/dapl/include/dapl_debug.h | 116 + .../ulp/dapl2/dapl/include/dapl_ipoib_names.h | 262 + .../ulp/dapl2/dapl/include/dapl_vendor.h | 116 + .../WOF2-3/ulp/dapl2/dapl/openib_cma/README | 40 + .../WOF2-3/ulp/dapl2/dapl/openib_cma/SOURCES | 55 + .../WOF2-3/ulp/dapl2/dapl/openib_cma/cm.c | 1219 ++ .../ulp/dapl2/dapl/openib_cma/dapl_ib_util.h | 148 + .../WOF2-3/ulp/dapl2/dapl/openib_cma/device.c | 718 + .../dapl2/dapl/openib_cma/linux/openib_osd.h | 16 + .../WOF2-3/ulp/dapl2/dapl/openib_cma/makefile | 7 + .../WOF2-3/ulp/dapl2/dapl/openib_cma/udapl.rc | 48 + .../dapl/openib_cma/udapl_ofa_cma_exports.src | 14 + .../dapl/openib_cma/windows/openib_osd.h | 6 + .../WOF2-3/ulp/dapl2/dapl/openib_common.c | 6 + .../WOF2-3/ulp/dapl2/dapl/openib_common/cq.c | 478 + .../dapl2/dapl/openib_common/dapl_ib_common.h | 403 + .../dapl2/dapl/openib_common/dapl_ib_dto.h | 504 + .../dapl2/dapl/openib_common/ib_extensions.c | 360 + .../WOF2-3/ulp/dapl2/dapl/openib_common/mem.c | 365 + .../WOF2-3/ulp/dapl2/dapl/openib_common/qp.c | 614 + .../ulp/dapl2/dapl/openib_common/util.c | 724 + .../WOF2-3/ulp/dapl2/dapl/openib_scm/SOURCES | 52 + .../WOF2-3/ulp/dapl2/dapl/openib_scm/cm.c | 1927 +++ .../ulp/dapl2/dapl/openib_scm/dapl_ib_util.h | 129 + .../WOF2-3/ulp/dapl2/dapl/openib_scm/device.c | 773 + .../dapl2/dapl/openib_scm/linux/openib_osd.h | 21 + .../WOF2-3/ulp/dapl2/dapl/openib_scm/makefile | 7 + .../WOF2-3/ulp/dapl2/dapl/openib_scm/udapl.rc | 48 + .../dapl/openib_scm/udapl_ofa_scm_exports.src | 14 + .../dapl/openib_scm/windows/openib_osd.h | 39 + .../WOF2-3/ulp/dapl2/dapl/openib_ucm/README | 40 + .../WOF2-3/ulp/dapl2/dapl/openib_ucm/SOURCES | 48 + .../WOF2-3/ulp/dapl2/dapl/openib_ucm/cm.c | 2166 +++ .../ulp/dapl2/dapl/openib_ucm/dapl_ib_util.h | 136 + .../WOF2-3/ulp/dapl2/dapl/openib_ucm/device.c | 672 + .../dapl2/dapl/openib_ucm/linux/openib_osd.h | 37 + .../WOF2-3/ulp/dapl2/dapl/openib_ucm/makefile | 7 + .../WOF2-3/ulp/dapl2/dapl/openib_ucm/udapl.rc | 48 + .../dapl/openib_ucm/udapl_ofa_ucm_exports.src | 14 + .../dapl/openib_ucm/windows/openib_osd.h | 46 + .../ulp/dapl2/dapl/udapl/dapl_cno_create.c | 101 + .../ulp/dapl2/dapl/udapl/dapl_cno_free.c | 87 + .../dapl2/dapl/udapl/dapl_cno_modify_agent.c | 80 + .../ulp/dapl2/dapl/udapl/dapl_cno_query.c | 92 + .../ulp/dapl2/dapl/udapl/dapl_cno_wait.c | 132 + .../dapl/udapl/dapl_evd_clear_unwaitable.c | 79 + .../ulp/dapl2/dapl/udapl/dapl_evd_create.c | 184 + .../ulp/dapl2/dapl/udapl/dapl_evd_disable.c | 78 + .../ulp/dapl2/dapl/udapl/dapl_evd_enable.c | 91 + .../dapl2/dapl/udapl/dapl_evd_modify_cno.c | 110 + .../ulp/dapl2/dapl/udapl/dapl_evd_query.c | 112 + .../dapl/udapl/dapl_evd_set_unwaitable.c | 98 + .../ulp/dapl2/dapl/udapl/dapl_evd_wait.c | 271 + .../WOF2-3/ulp/dapl2/dapl/udapl/dapl_init.c | 307 + .../ulp/dapl2/dapl/udapl/dapl_lmr_create.c | 419 + .../ulp/dapl2/dapl/udapl/linux/dapl_osd.c | 599 + .../ulp/dapl2/dapl/udapl/linux/dapl_osd.h | 586 + .../ulp/dapl2/dapl/udapl/windows/dapl_osd.c | 273 + .../ulp/dapl2/dapl/udapl/windows/dapl_osd.h | 533 + .../WOF2-3/ulp/dapl2/dat/common/dat_api.c | 1077 ++ .../ulp/dapl2/dat/common/dat_dictionary.c | 420 + .../ulp/dapl2/dat/common/dat_dictionary.h | 112 + branches/WOF2-3/ulp/dapl2/dat/common/dat_dr.c | 327 + branches/WOF2-3/ulp/dapl2/dat/common/dat_dr.h | 103 + .../WOF2-3/ulp/dapl2/dat/common/dat_init.c | 152 + .../WOF2-3/ulp/dapl2/dat/common/dat_init.h | 106 + branches/WOF2-3/ulp/dapl2/dat/common/dat_sr.c | 447 + branches/WOF2-3/ulp/dapl2/dat/common/dat_sr.h | 104 + .../ulp/dapl2/dat/common/dat_strerror.c | 611 + branches/WOF2-3/ulp/dapl2/dat/dirs | 1 + .../WOF2-3/ulp/dapl2/dat/include/dat2/dat.h | 1379 ++ .../ulp/dapl2/dat/include/dat2/dat_error.h | 380 + .../dat/include/dat2/dat_ib_extensions.h | 510 + .../dat/include/dat2/dat_iw_extensions.h | 167 + .../dat/include/dat2/dat_platform_specific.h | 274 + .../dapl2/dat/include/dat2/dat_redirection.h | 858 ++ .../ulp/dapl2/dat/include/dat2/dat_registry.h | 132 + .../dat/include/dat2/dat_vendor_specific.h | 81 + .../WOF2-3/ulp/dapl2/dat/include/dat2/kdat.h | 487 + .../ulp/dapl2/dat/include/dat2/kdat_config.h | 83 + .../dapl2/dat/include/dat2/kdat_redirection.h | 330 + .../dat/include/dat2/kdat_vendor_specific.h | 83 + .../WOF2-3/ulp/dapl2/dat/include/dat2/udat.h | 503 + .../ulp/dapl2/dat/include/dat2/udat_config.h | 89 + .../dapl2/dat/include/dat2/udat_redirection.h | 356 + .../dat/include/dat2/udat_vendor_specific.h | 83 + branches/WOF2-3/ulp/dapl2/dat/udat/SOURCES | 36 + .../dat/udat/linux/dat-registry-1.1.spec | 106 + .../WOF2-3/ulp/dapl2/dat/udat/linux/dat_osd.c | 183 + .../WOF2-3/ulp/dapl2/dat/udat/linux/dat_osd.h | 415 + branches/WOF2-3/ulp/dapl2/dat/udat/makefile | 7 + branches/WOF2-3/ulp/dapl2/dat/udat/udat.c | 409 + branches/WOF2-3/ulp/dapl2/dat/udat/udat.rc | 48 + branches/WOF2-3/ulp/dapl2/dat/udat/udat_api.c | 260 + .../ulp/dapl2/dat/udat/udat_exports.src | 59 + .../WOF2-3/ulp/dapl2/dat/udat/udat_sources.c | 11 + .../ulp/dapl2/dat/udat/udat_sr_parser.c | 1216 ++ .../ulp/dapl2/dat/udat/udat_sr_parser.h | 63 + .../ulp/dapl2/dat/udat/windows/dat_osd.c | 208 + .../ulp/dapl2/dat/udat/windows/dat_osd.h | 430 + .../ulp/dapl2/dat/udat/windows/dat_osd_sr.h | 43 + branches/WOF2-3/ulp/dapl2/dirs | 4 + .../ulp/dapl2/doc/dapl_coding_style.txt | 264 + .../ulp/dapl2/doc/dapl_end_point_design.txt | 1129 ++ .../WOF2-3/ulp/dapl2/doc/dapl_environ.txt | 42 + .../ulp/dapl2/doc/dapl_event_design.txt | 875 ++ .../ulp/dapl2/doc/dapl_ibm_api_variations.txt | 34 + .../doc/dapl_memory_management_design.txt | 173 + branches/WOF2-3/ulp/dapl2/doc/dapl_patch.txt | 83 + .../ulp/dapl2/doc/dapl_registry_design.txt | 631 + .../dapl2/doc/dapl_shared_memory_design.txt | 876 ++ .../doc/dapl_vendor_specific_changes.txt | 394 + branches/WOF2-3/ulp/dapl2/doc/dat_environ.txt | 45 + .../ulp/dapl2/doc/uDAPL_release_notes.txt | 926 ++ branches/WOF2-3/ulp/dapl2/man/dapltest.1 | 390 + branches/WOF2-3/ulp/dapl2/man/dat.conf.5 | 108 + branches/WOF2-3/ulp/dapl2/man/dtest.1 | 78 + .../ulp/dapl2/test/dapltest/Makefile.am | 67 + .../WOF2-3/ulp/dapl2/test/dapltest/README | 293 + .../dapl2/test/dapltest/cmd/dapl_fft_cmd.c | 325 + .../ulp/dapl2/test/dapltest/cmd/dapl_getopt.c | 153 + .../dapl2/test/dapltest/cmd/dapl_limit_cmd.c | 222 + .../ulp/dapl2/test/dapltest/cmd/dapl_main.c | 143 + .../dapl2/test/dapltest/cmd/dapl_netaddr.c | 137 + .../ulp/dapl2/test/dapltest/cmd/dapl_params.c | 281 + .../test/dapltest/cmd/dapl_performance_cmd.c | 297 + .../dapl2/test/dapltest/cmd/dapl_qos_util.c | 59 + .../dapl2/test/dapltest/cmd/dapl_quit_cmd.c | 132 + .../dapl2/test/dapltest/cmd/dapl_server_cmd.c | 114 + .../dapl2/test/dapltest/cmd/dapl_test_data.c | 55 + .../test/dapltest/cmd/dapl_transaction_cmd.c | 453 + .../dapl2/test/dapltest/common/dapl_endian.c | 98 + .../dapl2/test/dapltest/common/dapl_global.c | 34 + .../common/dapl_performance_cmd_util.c | 57 + .../test/dapltest/common/dapl_quit_cmd_util.c | 37 + .../common/dapl_transaction_cmd_util.c | 62 + .../ulp/dapl2/test/dapltest/configure.in | 26 + branches/WOF2-3/ulp/dapl2/test/dapltest/dirs | 1 + .../WOF2-3/ulp/dapl2/test/dapltest/dt_cmd.c | 12 + .../ulp/dapl2/test/dapltest/dt_common.c | 5 + .../WOF2-3/ulp/dapl2/test/dapltest/dt_mdep.c | 2 + .../WOF2-3/ulp/dapl2/test/dapltest/dt_test.c | 32 + .../WOF2-3/ulp/dapl2/test/dapltest/dt_udapl.c | 2 + .../dapl2/test/dapltest/include/dapl_bpool.h | 62 + .../test/dapltest/include/dapl_client_info.h | 47 + .../dapl2/test/dapltest/include/dapl_common.h | 53 + .../test/dapltest/include/dapl_execute.h | 40 + .../test/dapltest/include/dapl_fft_cmd.h | 72 + .../test/dapltest/include/dapl_fft_util.h | 97 + .../dapl2/test/dapltest/include/dapl_getopt.h | 52 + .../dapl2/test/dapltest/include/dapl_global.h | 39 + .../test/dapltest/include/dapl_limit_cmd.h | 69 + .../dapl2/test/dapltest/include/dapl_mdep.h | 40 + .../test/dapltest/include/dapl_memlist.h | 57 + .../dapl2/test/dapltest/include/dapl_params.h | 75 + .../dapltest/include/dapl_performance_cmd.h | 69 + .../dapltest/include/dapl_performance_stats.h | 65 + .../dapltest/include/dapl_performance_test.h | 91 + .../dapl2/test/dapltest/include/dapl_proto.h | 667 + .../test/dapltest/include/dapl_quit_cmd.h | 44 + .../test/dapltest/include/dapl_server_cmd.h | 44 + .../test/dapltest/include/dapl_server_info.h | 58 + .../dapl2/test/dapltest/include/dapl_tdep.h | 81 + .../test/dapltest/include/dapl_tdep_print.h | 68 + .../test/dapltest/include/dapl_test_data.h | 106 + .../dapltest/include/dapl_transaction_cmd.h | 69 + .../dapltest/include/dapl_transaction_stats.h | 50 + .../dapltest/include/dapl_transaction_test.h | 101 + .../test/dapltest/include/dapl_version.h | 41 + .../dapltest/mdep/linux/dapl_mdep_kernel.c | 347 + .../dapltest/mdep/linux/dapl_mdep_kernel.h | 180 + .../test/dapltest/mdep/linux/dapl_mdep_user.c | 546 + .../test/dapltest/mdep/linux/dapl_mdep_user.h | 208 + .../dapltest/mdep/solaris/dapl_mdep_user.c | 466 + .../dapltest/mdep/solaris/dapl_mdep_user.h | 155 + .../dapltest/mdep/windows/dapl_mdep_user.c | 436 + .../dapltest/mdep/windows/dapl_mdep_user.h | 190 + .../ulp/dapl2/test/dapltest/scripts/cl.sh | 58 + .../dapl2/test/dapltest/scripts/dt-cli.bat | 367 + .../dapl2/test/dapltest/scripts/dt-svr.bat | 62 + .../dapl2/test/dapltest/scripts/kregress.sh | 112 + .../ulp/dapl2/test/dapltest/scripts/ksrv.sh | 43 + .../ulp/dapl2/test/dapltest/scripts/lim.sh | 44 + .../dapl2/test/dapltest/scripts/regress.sh | 112 + .../ulp/dapl2/test/dapltest/scripts/srv.sh | 43 + .../ulp/dapl2/test/dapltest/test/dapl_bpool.c | 359 + .../dapl2/test/dapltest/test/dapl_client.c | 559 + .../test/dapltest/test/dapl_client_info.c | 56 + .../ulp/dapl2/test/dapltest/test/dapl_cnxn.c | 68 + .../dapl2/test/dapltest/test/dapl_execute.c | 98 + .../test/dapltest/test/dapl_fft_connmgt.c | 118 + .../test/dapltest/test/dapl_fft_dataxfer.c | 158 + .../dapltest/test/dapl_fft_dataxfer_client.c | 129 + .../test/dapltest/test/dapl_fft_endpoint.c | 264 + .../test/dapltest/test/dapl_fft_hwconn.c | 217 + .../dapl2/test/dapltest/test/dapl_fft_mem.c | 216 + .../dapl2/test/dapltest/test/dapl_fft_pz.c | 247 + .../test/dapltest/test/dapl_fft_queryinfo.c | 596 + .../dapl2/test/dapltest/test/dapl_fft_test.c | 92 + .../dapl2/test/dapltest/test/dapl_fft_util.c | 360 + .../ulp/dapl2/test/dapltest/test/dapl_limit.c | 1536 ++ .../dapl2/test/dapltest/test/dapl_memlist.c | 123 + .../dapltest/test/dapl_performance_client.c | 490 + .../dapltest/test/dapl_performance_server.c | 391 + .../dapltest/test/dapl_performance_stats.c | 374 + .../dapltest/test/dapl_performance_util.c | 618 + .../dapl2/test/dapltest/test/dapl_quit_util.c | 43 + .../dapl2/test/dapltest/test/dapl_server.c | 855 ++ .../test/dapltest/test/dapl_server_info.c | 53 + .../dapl2/test/dapltest/test/dapl_test_data.c | 56 + .../dapl2/test/dapltest/test/dapl_test_util.c | 680 + .../dapl2/test/dapltest/test/dapl_thread.c | 127 + .../dapltest/test/dapl_transaction_stats.c | 176 + .../dapltest/test/dapl_transaction_test.c | 2265 +++ .../dapltest/test/dapl_transaction_util.c | 747 + .../ulp/dapl2/test/dapltest/test/dapl_util.c | 219 + .../dapl2/test/dapltest/udapl/udapl_tdep.c | 112 + .../ulp/dapl2/test/dapltest/windows/SOURCES | 33 + .../dapl2/test/dapltest/windows/dapltest.rc | 50 + .../ulp/dapl2/test/dapltest/windows/makefile | 7 + branches/WOF2-3/ulp/dapl2/test/dirs | 1 + .../WOF2-3/ulp/dapl2/test/dtest/Makefile.am | 18 + branches/WOF2-3/ulp/dapl2/test/dtest/README | 19 + .../WOF2-3/ulp/dapl2/test/dtest/configure.in | 21 + branches/WOF2-3/ulp/dapl2/test/dtest/dirs | 1 + branches/WOF2-3/ulp/dapl2/test/dtest/dtc.bat | 42 + branches/WOF2-3/ulp/dapl2/test/dtest/dtest.c | 2107 +++ .../WOF2-3/ulp/dapl2/test/dtest/dtestcm.c | 1168 ++ branches/WOF2-3/ulp/dapl2/test/dtest/dtestx.c | 1360 ++ branches/WOF2-3/ulp/dapl2/test/dtest/dts.bat | 47 + .../WOF2-3/ulp/dapl2/test/dtest/windows/dirs | 1 + .../dapl2/test/dtest/windows/dtest/SOURCES | 34 + .../dapl2/test/dtest/windows/dtest/dtest.c | 4 + .../dapl2/test/dtest/windows/dtest/dtest.rc | 48 + .../dapl2/test/dtest/windows/dtest/makefile | 7 + .../dapl2/test/dtest/windows/dtestcm/SOURCES | 34 + .../test/dtest/windows/dtestcm/dtestcm.c | 4 + .../test/dtest/windows/dtestcm/dtestcm.rc | 48 + .../dapl2/test/dtest/windows/dtestcm/makefile | 7 + .../dapl2/test/dtest/windows/dtestx/SOURCES | 32 + .../dapl2/test/dtest/windows/dtestx/dtestx.c | 2 + .../dapl2/test/dtest/windows/dtestx/dtestx.rc | 48 + .../dapl2/test/dtest/windows/dtestx/makefile | 7 + branches/WOF2-3/ulp/dirs | 15 + branches/WOF2-3/ulp/ipoib/dirs | 2 + branches/WOF2-3/ulp/ipoib/ip_stats.h | 150 + branches/WOF2-3/ulp/ipoib/kernel/SOURCES | 59 + branches/WOF2-3/ulp/ipoib/kernel/ipoib.cdf | 13 + branches/WOF2-3/ulp/ipoib/kernel/ipoib.rc | 48 + .../WOF2-3/ulp/ipoib/kernel/ipoib32-xp.cdf | 10 + branches/WOF2-3/ulp/ipoib/kernel/ipoib32.cdf | 11 + .../WOF2-3/ulp/ipoib/kernel/ipoib_adapter.c | 1478 ++ .../WOF2-3/ulp/ipoib/kernel/ipoib_adapter.h | 439 + .../WOF2-3/ulp/ipoib/kernel/ipoib_debug.h | 300 + .../WOF2-3/ulp/ipoib/kernel/ipoib_driver.c | 2597 ++++ .../WOF2-3/ulp/ipoib/kernel/ipoib_driver.h | 146 + .../WOF2-3/ulp/ipoib/kernel/ipoib_endpoint.c | 358 + .../WOF2-3/ulp/ipoib/kernel/ipoib_endpoint.h | 158 + branches/WOF2-3/ulp/ipoib/kernel/ipoib_ibat.c | 670 + branches/WOF2-3/ulp/ipoib/kernel/ipoib_ibat.h | 45 + branches/WOF2-3/ulp/ipoib/kernel/ipoib_log.mc | 318 + branches/WOF2-3/ulp/ipoib/kernel/ipoib_port.c | 6526 ++++++++ branches/WOF2-3/ulp/ipoib/kernel/ipoib_port.h | 651 + branches/WOF2-3/ulp/ipoib/kernel/ipoib_stat.c | 37 + branches/WOF2-3/ulp/ipoib/kernel/ipoib_stat.h | 80 + .../WOF2-3/ulp/ipoib/kernel/ipoib_xfr_mgr.c | 52 + .../WOF2-3/ulp/ipoib/kernel/ipoib_xfr_mgr.h | 504 + branches/WOF2-3/ulp/ipoib/kernel/makefile | 13 + branches/WOF2-3/ulp/ipoib/kernel/makefile.inc | 17 + .../WOF2-3/ulp/ipoib/kernel/netipoib-xp32.inf | 284 + branches/WOF2-3/ulp/ipoib/kernel/netipoib.inx | 286 + branches/WOF2-3/ulp/ipoib/kernel/offload.h | 47 + branches/WOF2-3/ulp/ipoib_NDIS6_CM/dirs | 2 + branches/WOF2-3/ulp/ipoib_NDIS6_CM/ip_stats.h | 150 + .../WOF2-3/ulp/ipoib_NDIS6_CM/kernel/SOURCES | 64 + .../ulp/ipoib_NDIS6_CM/kernel/ipoib.cdf | 13 + .../WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib.rc | 48 + .../ulp/ipoib_NDIS6_CM/kernel/ipoib32.cdf | 11 + .../ipoib_NDIS6_CM/kernel/ipoib_adapter.cpp | 1698 +++ .../ulp/ipoib_NDIS6_CM/kernel/ipoib_adapter.h | 510 + .../ulp/ipoib_NDIS6_CM/kernel/ipoib_debug.h | 303 + .../ipoib_NDIS6_CM/kernel/ipoib_driver.cpp | 4104 +++++ .../ulp/ipoib_NDIS6_CM/kernel/ipoib_driver.h | 166 + .../ipoib_NDIS6_CM/kernel/ipoib_endpoint.cpp | 1183 ++ .../ipoib_NDIS6_CM/kernel/ipoib_endpoint.h | 266 + .../ulp/ipoib_NDIS6_CM/kernel/ipoib_ibat.cpp | 691 + .../ulp/ipoib_NDIS6_CM/kernel/ipoib_ibat.h | 45 + .../ulp/ipoib_NDIS6_CM/kernel/ipoib_log.mc | 374 + .../ulp/ipoib_NDIS6_CM/kernel/ipoib_port.cpp | 8698 +++++++++++ .../ulp/ipoib_NDIS6_CM/kernel/ipoib_port.h | 940 ++ .../ulp/ipoib_NDIS6_CM/kernel/ipoib_stat.cpp | 36 + .../ulp/ipoib_NDIS6_CM/kernel/ipoib_stat.h | 79 + .../ipoib_NDIS6_CM/kernel/ipoib_xfr_mgr.cpp | 76 + .../ulp/ipoib_NDIS6_CM/kernel/ipoib_xfr_mgr.h | 513 + .../WOF2-3/ulp/ipoib_NDIS6_CM/kernel/makefile | 13 + .../ulp/ipoib_NDIS6_CM/kernel/makefile.inc | 17 + .../ulp/ipoib_NDIS6_CM/kernel/netipoib.inx | 309 + .../ulp/ipoib_NDIS6_CM/kernel/offload.h | 47 + .../ulp/ipoib_NDIS6_CM/kernel/precompile.h | 26 + branches/WOF2-3/ulp/libibmad/README.txt | 19 + branches/WOF2-3/ulp/libibmad/dirs | 2 + .../ulp/libibmad/include/infiniband/mad.h | 1086 ++ .../ulp/libibmad/include/infiniband/mad_osd.h | 74 + .../ulp/libibmad/include/windows/config.h | 39 + branches/WOF2-3/ulp/libibmad/src/Sources | 55 + branches/WOF2-3/ulp/libibmad/src/bm.c | 107 + branches/WOF2-3/ulp/libibmad/src/dump.c | 787 + branches/WOF2-3/ulp/libibmad/src/fields.c | 761 + branches/WOF2-3/ulp/libibmad/src/gs.c | 119 + branches/WOF2-3/ulp/libibmad/src/ibmad.rc | 46 + .../WOF2-3/ulp/libibmad/src/ibmad_export.def | 34 + .../WOF2-3/ulp/libibmad/src/ibmad_exports.src | 47 + .../WOF2-3/ulp/libibmad/src/ibmad_main.cpp | 43 + branches/WOF2-3/ulp/libibmad/src/libibmad.map | 114 + branches/WOF2-3/ulp/libibmad/src/mad.c | 192 + .../WOF2-3/ulp/libibmad/src/mad_internal.h | 49 + branches/WOF2-3/ulp/libibmad/src/makefile | 7 + branches/WOF2-3/ulp/libibmad/src/portid.c | 118 + branches/WOF2-3/ulp/libibmad/src/register.c | 178 + branches/WOF2-3/ulp/libibmad/src/resolve.c | 228 + branches/WOF2-3/ulp/libibmad/src/rpc.c | 418 + branches/WOF2-3/ulp/libibmad/src/sa.c | 147 + branches/WOF2-3/ulp/libibmad/src/serv.c | 197 + branches/WOF2-3/ulp/libibmad/src/smp.c | 112 + branches/WOF2-3/ulp/libibmad/src/vendor.c | 104 + branches/WOF2-3/ulp/libibnetdisc/README.txt | 19 + branches/WOF2-3/ulp/libibnetdisc/dirs | 2 + .../include/infiniband/ibnetdisc.h | 217 + .../ulp/libibnetdisc/include/windows/config.h | 53 + branches/WOF2-3/ulp/libibnetdisc/src/Sources | 45 + .../WOF2-3/ulp/libibnetdisc/src/chassis.c | 1115 ++ .../WOF2-3/ulp/libibnetdisc/src/chassis.h | 91 + .../WOF2-3/ulp/libibnetdisc/src/ibnetdisc.c | 626 + .../ulp/libibnetdisc/src/ibnetdisc_cache.c | 941 ++ .../ulp/libibnetdisc/src/ibnetdisc_export.def | 34 + .../libibnetdisc/src/ibnetdisc_exports.src | 21 + .../ulp/libibnetdisc/src/ibnetdisc_main.cpp | 39 + .../WOF2-3/ulp/libibnetdisc/src/internal.h | 107 + branches/WOF2-3/ulp/libibnetdisc/src/makefile | 7 + .../WOF2-3/ulp/libibnetdisc/src/query_smp.c | 277 + branches/WOF2-3/ulp/libibumad/AUTHORS | 4 + branches/WOF2-3/ulp/libibumad/COPYING | 27 + branches/WOF2-3/ulp/libibumad/dirs | 2 + .../ulp/libibumad/include/infiniband/umad.h | 220 + branches/WOF2-3/ulp/libibumad/src/Sources | 39 + .../WOF2-3/ulp/libibumad/src/ibum_export.def | 34 + .../WOF2-3/ulp/libibumad/src/ibum_exports.src | 39 + .../WOF2-3/ulp/libibumad/src/ibum_main.cpp | 39 + branches/WOF2-3/ulp/libibumad/src/ibumad.h | 44 + branches/WOF2-3/ulp/libibumad/src/ibumad.rc | 46 + branches/WOF2-3/ulp/libibumad/src/makefile | 7 + branches/WOF2-3/ulp/libibumad/src/umad.cpp | 768 + branches/WOF2-3/ulp/libibverbs/AUTHORS | 4 + branches/WOF2-3/ulp/libibverbs/COPYING | 29 + branches/WOF2-3/ulp/libibverbs/dirs | 3 + .../libibverbs/examples/asyncwatch/SOURCES | 31 + .../examples/asyncwatch/asyncwatch.c | 109 + .../examples/asyncwatch/asyncwatch.rc | 47 + .../libibverbs/examples/asyncwatch/makefile | 7 + .../ulp/libibverbs/examples/device_list.c | 68 + .../ulp/libibverbs/examples/devinfo/SOURCES | 31 + .../ulp/libibverbs/examples/devinfo/devinfo.c | 393 + .../libibverbs/examples/devinfo/devinfo.rc | 47 + .../ulp/libibverbs/examples/devinfo/makefile | 7 + branches/WOF2-3/ulp/libibverbs/examples/dirs | 6 + .../WOF2-3/ulp/libibverbs/examples/pingpong.c | 52 + .../WOF2-3/ulp/libibverbs/examples/pingpong.h | 38 + .../libibverbs/examples/rc_pingpong/SOURCES | 31 + .../libibverbs/examples/rc_pingpong/makefile | 7 + .../examples/rc_pingpong/rc_pingpong.c | 752 + .../examples/rc_pingpong/rc_pingpong.rc | 47 + .../libibverbs/examples/srq_pingpong/SOURCES | 29 + .../libibverbs/examples/srq_pingpong/makefile | 7 + .../examples/srq_pingpong/srq_pingpong.c | 886 ++ .../examples/srq_pingpong/srq_pingpong.rc | 47 + .../libibverbs/examples/uc_pingpong/SOURCES | 31 + .../libibverbs/examples/uc_pingpong/makefile | 7 + .../examples/uc_pingpong/uc_pingpong.c | 739 + .../examples/uc_pingpong/uc_pingpong.rc | 47 + .../libibverbs/examples/ud_pingpong/SOURCES | 31 + .../libibverbs/examples/ud_pingpong/makefile | 7 + .../examples/ud_pingpong/ud_pingpong.c | 738 + .../examples/ud_pingpong/ud_pingpong.rc | 47 + .../ulp/libibverbs/include/infiniband/sa.h | 98 + .../ulp/libibverbs/include/infiniband/verbs.h | 1133 ++ branches/WOF2-3/ulp/libibverbs/src/Sources | 38 + branches/WOF2-3/ulp/libibverbs/src/device.cpp | 372 + .../WOF2-3/ulp/libibverbs/src/enum_strs.cpp | 130 + .../WOF2-3/ulp/libibverbs/src/ibv_export.def | 34 + .../WOF2-3/ulp/libibverbs/src/ibv_exports.src | 57 + .../WOF2-3/ulp/libibverbs/src/ibv_main.cpp | 59 + branches/WOF2-3/ulp/libibverbs/src/ibverbs.h | 48 + branches/WOF2-3/ulp/libibverbs/src/ibverbs.rc | 46 + branches/WOF2-3/ulp/libibverbs/src/makefile | 7 + branches/WOF2-3/ulp/libibverbs/src/verbs.cpp | 930 ++ branches/WOF2-3/ulp/librdmacm/AUTHORS | 1 + branches/WOF2-3/ulp/librdmacm/COPYING | 26 + branches/WOF2-3/ulp/librdmacm/dirs | 3 + .../ulp/librdmacm/examples/cmatose/SOURCES | 31 + .../ulp/librdmacm/examples/cmatose/cmatose.c | 815 + .../ulp/librdmacm/examples/cmatose/makefile | 7 + branches/WOF2-3/ulp/librdmacm/examples/dirs | 4 + .../ulp/librdmacm/examples/mckey/mckey.c | 579 + .../librdmacm/examples/rdma_client/SOURCES | 28 + .../librdmacm/examples/rdma_client/makefile | 7 + .../examples/rdma_client/rdma_client.c | 134 + .../librdmacm/examples/rdma_server/SOURCES | 28 + .../librdmacm/examples/rdma_server/makefile | 7 + .../examples/rdma_server/rdma_server.c | 148 + .../ulp/librdmacm/examples/rping/rping.c | 1122 ++ .../ulp/librdmacm/examples/udaddy/udaddy.c | 701 + .../ulp/librdmacm/include/rdma/rdma_cma.h | 722 + .../ulp/librdmacm/include/rdma/rdma_verbs.h | 297 + branches/WOF2-3/ulp/librdmacm/src/Sources | 42 + .../WOF2-3/ulp/librdmacm/src/addrinfo.cpp | 243 + branches/WOF2-3/ulp/librdmacm/src/cma.cpp | 1469 ++ branches/WOF2-3/ulp/librdmacm/src/cma.h | 49 + branches/WOF2-3/ulp/librdmacm/src/cma.rc | 46 + .../WOF2-3/ulp/librdmacm/src/cma_export.def | 34 + .../WOF2-3/ulp/librdmacm/src/cma_exports.src | 37 + .../WOF2-3/ulp/librdmacm/src/cma_main.cpp | 58 + branches/WOF2-3/ulp/librdmacm/src/makefile | 7 + branches/WOF2-3/ulp/nd/dirs | 2 + branches/WOF2-3/ulp/nd/user/NdAdapter.cpp | 953 ++ branches/WOF2-3/ulp/nd/user/NdAdapter.h | 210 + branches/WOF2-3/ulp/nd/user/NdConnector.cpp | 935 ++ branches/WOF2-3/ulp/nd/user/NdConnector.h | 172 + branches/WOF2-3/ulp/nd/user/NdCq.cpp | 487 + branches/WOF2-3/ulp/nd/user/NdCq.h | 113 + branches/WOF2-3/ulp/nd/user/NdEndpoint.cpp | 1035 ++ branches/WOF2-3/ulp/nd/user/NdEndpoint.h | 208 + branches/WOF2-3/ulp/nd/user/NdListen.cpp | 385 + branches/WOF2-3/ulp/nd/user/NdListen.h | 115 + branches/WOF2-3/ulp/nd/user/NdMr.cpp | 48 + branches/WOF2-3/ulp/nd/user/NdMr.h | 55 + branches/WOF2-3/ulp/nd/user/NdMw.cpp | 110 + branches/WOF2-3/ulp/nd/user/NdMw.h | 75 + branches/WOF2-3/ulp/nd/user/NdProv.cpp | 576 + branches/WOF2-3/ulp/nd/user/NdProv.def | 6 + branches/WOF2-3/ulp/nd/user/NdProv.h | 110 + branches/WOF2-3/ulp/nd/user/NdProv.rc | 49 + branches/WOF2-3/ulp/nd/user/README.txt | 18 + branches/WOF2-3/ulp/nd/user/SOURCES | 64 + .../nd/user/fre_svr-03_ia64/ia64/ibndprov.dll | Bin 0 -> 37376 bytes .../user/fre_svr-03_ia64/ia64/ndinstall.exe | Bin 0 -> 11264 bytes .../nd/user/fre_svr-08_ia64/ia64/ibndprov.dll | Bin 0 -> 37376 bytes .../user/fre_svr-08_ia64/ia64/ndinstall.exe | Bin 0 -> 9216 bytes branches/WOF2-3/ulp/nd/user/makefile | 17 + branches/WOF2-3/ulp/nd/user/makefile.inc | 27 + branches/WOF2-3/ulp/nd/user/nddebug.h | 160 + branches/WOF2-3/ulp/netdirect/dirs | 1 + branches/WOF2-3/ulp/netdirect/user/SOURCES | 43 + branches/WOF2-3/ulp/netdirect/user/makefile | 14 + .../WOF2-3/ulp/netdirect/user/nd_adapter.cpp | 302 + .../WOF2-3/ulp/netdirect/user/nd_adapter.h | 127 + .../WOF2-3/ulp/netdirect/user/nd_base.cpp | 64 + branches/WOF2-3/ulp/netdirect/user/nd_base.h | 66 + .../WOF2-3/ulp/netdirect/user/nd_connect.cpp | 324 + .../WOF2-3/ulp/netdirect/user/nd_connect.h | 120 + branches/WOF2-3/ulp/netdirect/user/nd_cq.cpp | 169 + branches/WOF2-3/ulp/netdirect/user/nd_cq.h | 96 + branches/WOF2-3/ulp/netdirect/user/nd_ep.cpp | 318 + branches/WOF2-3/ulp/netdirect/user/nd_ep.h | 132 + .../WOF2-3/ulp/netdirect/user/nd_export.def | 39 + .../WOF2-3/ulp/netdirect/user/nd_exports.src | 12 + .../WOF2-3/ulp/netdirect/user/nd_listen.cpp | 154 + .../WOF2-3/ulp/netdirect/user/nd_listen.h | 98 + .../WOF2-3/ulp/netdirect/user/nd_main.cpp | 88 + branches/WOF2-3/ulp/netdirect/user/nd_main.h | 37 + branches/WOF2-3/ulp/netdirect/user/nd_mw.cpp | 81 + branches/WOF2-3/ulp/netdirect/user/nd_mw.h | 85 + .../WOF2-3/ulp/netdirect/user/nd_provider.cpp | 180 + .../WOF2-3/ulp/netdirect/user/nd_provider.h | 76 + .../WOF2-3/ulp/netdirect/user/netdirect.rc | 46 + branches/WOF2-3/ulp/netdirect2/dirs | 1 + branches/WOF2-3/ulp/netdirect2/user/SOURCES | 45 + branches/WOF2-3/ulp/netdirect2/user/makefile | 14 + .../WOF2-3/ulp/netdirect2/user/nd_adapter.cpp | 281 + .../WOF2-3/ulp/netdirect2/user/nd_adapter.h | 114 + .../WOF2-3/ulp/netdirect2/user/nd_base.cpp | 64 + branches/WOF2-3/ulp/netdirect2/user/nd_base.h | 69 + .../WOF2-3/ulp/netdirect2/user/nd_connect.cpp | 332 + .../WOF2-3/ulp/netdirect2/user/nd_connect.h | 124 + branches/WOF2-3/ulp/netdirect2/user/nd_cq.cpp | 175 + branches/WOF2-3/ulp/netdirect2/user/nd_cq.h | 97 + branches/WOF2-3/ulp/netdirect2/user/nd_ep.cpp | 92 + branches/WOF2-3/ulp/netdirect2/user/nd_ep.h | 81 + .../WOF2-3/ulp/netdirect2/user/nd_export.def | 39 + .../WOF2-3/ulp/netdirect2/user/nd_exports.src | 12 + .../WOF2-3/ulp/netdirect2/user/nd_listen.cpp | 154 + .../WOF2-3/ulp/netdirect2/user/nd_listen.h | 87 + .../WOF2-3/ulp/netdirect2/user/nd_main.cpp | 95 + branches/WOF2-3/ulp/netdirect2/user/nd_main.h | 37 + branches/WOF2-3/ulp/netdirect2/user/nd_mw.cpp | 193 + branches/WOF2-3/ulp/netdirect2/user/nd_mw.h | 133 + .../ulp/netdirect2/user/nd_provider.cpp | 179 + .../WOF2-3/ulp/netdirect2/user/nd_provider.h | 94 + branches/WOF2-3/ulp/netdirect2/user/nd_qp.cpp | 244 + branches/WOF2-3/ulp/netdirect2/user/nd_qp.h | 118 + .../WOF2-3/ulp/netdirect2/user/nd_srq.cpp | 179 + branches/WOF2-3/ulp/netdirect2/user/nd_srq.h | 100 + .../WOF2-3/ulp/netdirect2/user/netdirect.rc | 46 + branches/WOF2-3/ulp/opensm/dirs | 2 + branches/WOF2-3/ulp/opensm/user/AUTHORS | 9 + branches/WOF2-3/ulp/opensm/user/README | 25 + .../WOF2-3/ulp/opensm/user/README.windows | 111 + .../WOF2-3/ulp/opensm/user/complib/README.txt | 6 + .../ulp/opensm/user/complib/cl_dispatcher.c | 361 + .../ulp/opensm/user/complib/cl_event_wheel.c | 566 + branches/WOF2-3/ulp/opensm/user/config.h | 51 + branches/WOF2-3/ulp/opensm/user/dirs | 6 + .../ulp/opensm/user/doc/OpenSM_PKey_Mgr.txt | 78 + .../WOF2-3/ulp/opensm/user/doc/OpenSM_RN.pdf | Bin 0 -> 117072 bytes .../WOF2-3/ulp/opensm/user/doc/OpenSM_UM.pdf | Bin 0 -> 307923 bytes .../user/doc/QoS_management_in_OpenSM.txt | 492 + .../ulp/opensm/user/doc/current-routing.txt | 390 + .../user/doc/opensm_release_notes-3.3.txt | 735 + .../ulp/opensm/user/doc/partition-config.txt | 131 + .../ulp/opensm/user/doc/perf-manager-arch.txt | 181 + .../user/doc/performance-manager-HOWTO.txt | 154 + .../WOF2-3/ulp/opensm/user/doc/qos-config.txt | 44 + .../WOF2-3/ulp/opensm/user/ibtrapgen/Makefile | 7 + .../WOF2-3/ulp/opensm/user/ibtrapgen/SOURCES | 70 + .../ulp/opensm/user/ibtrapgen/ibtrapgen.c | 440 + .../ulp/opensm/user/ibtrapgen/ibtrapgen.h | 313 + .../WOF2-3/ulp/opensm/user/ibtrapgen/main.c | 465 + .../ulp/opensm/user/ibtrapgen/osm_files.c | 9 + .../ulp/opensm/user/ibtrapgen/vendor-ibal.inc | 2 + .../ulp/opensm/user/ibtrapgen/vendor-umad.inc | 2 + .../WOF2-3/ulp/opensm/user/include/README.txt | 15 + .../user/include/complib/cl_dispatcher.h | 631 + .../user/include/complib/cl_event_wheel.h | 457 + .../ulp/opensm/user/include/iba/ib_cm_types.h | 203 + .../user/include/opensm/osm_attrib_req.h | 108 + .../ulp/opensm/user/include/opensm/osm_base.h | 910 ++ .../opensm/user/include/opensm/osm_config.h | 69 + .../user/include/opensm/osm_config.h.in | 64 + .../opensm/user/include/opensm/osm_console.h | 50 + .../user/include/opensm/osm_console_io.h | 93 + .../ulp/opensm/user/include/opensm/osm_db.h | 424 + .../opensm/user/include/opensm/osm_db_pack.h | 239 + .../opensm/user/include/opensm/osm_errors.h | 176 + .../user/include/opensm/osm_event_plugin.h | 180 + .../opensm/user/include/opensm/osm_helper.h | 549 + .../opensm/user/include/opensm/osm_inform.h | 235 + .../opensm/user/include/opensm/osm_lid_mgr.h | 279 + .../ulp/opensm/user/include/opensm/osm_log.h | 478 + .../opensm/user/include/opensm/osm_mad_pool.h | 370 + .../ulp/opensm/user/include/opensm/osm_madw.h | 1120 ++ .../user/include/opensm/osm_mcast_tbl.h | 486 + .../opensm/user/include/opensm/osm_mcm_port.h | 173 + .../ulp/opensm/user/include/opensm/osm_mesh.h | 77 + .../opensm/user/include/opensm/osm_msgdef.h | 167 + .../opensm/user/include/opensm/osm_mtree.h | 274 + .../user/include/opensm/osm_multicast.h | 389 + .../ulp/opensm/user/include/opensm/osm_node.h | 668 + .../opensm/user/include/opensm/osm_opensm.h | 523 + .../user/include/opensm/osm_partition.h | 274 + .../ulp/opensm/user/include/opensm/osm_path.h | 254 + .../opensm/user/include/opensm/osm_perfmgr.h | 251 + .../user/include/opensm/osm_perfmgr_db.h | 204 + .../ulp/opensm/user/include/opensm/osm_pkey.h | 634 + .../ulp/opensm/user/include/opensm/osm_port.h | 1460 ++ .../user/include/opensm/osm_port_profile.h | 206 + .../user/include/opensm/osm_prefix_route.h | 63 + .../user/include/opensm/osm_qos_policy.h | 204 + .../user/include/opensm/osm_remote_sm.h | 196 + .../opensm/user/include/opensm/osm_router.h | 215 + .../ulp/opensm/user/include/opensm/osm_sa.h | 495 + .../user/include/opensm/osm_sa_mad_ctrl.h | 337 + .../opensm/user/include/opensm/osm_service.h | 191 + .../ulp/opensm/user/include/opensm/osm_sm.h | 739 + .../user/include/opensm/osm_sm_mad_ctrl.h | 321 + .../opensm/user/include/opensm/osm_stats.h | 184 + .../opensm/user/include/opensm/osm_subnet.h | 1185 ++ .../opensm/user/include/opensm/osm_switch.h | 1143 ++ .../user/include/opensm/osm_ucast_cache.h | 241 + .../user/include/opensm/osm_ucast_lash.h | 100 + .../user/include/opensm/osm_ucast_mgr.h | 300 + .../opensm/user/include/opensm/osm_version.h | 55 + .../user/include/opensm/osm_version.h.in | 51 + .../opensm/user/include/opensm/osm_vl15intf.h | 361 + .../ulp/opensm/user/include/opensm/st.h | 103 + .../opensm/user/include/vendor/osm_mtl_bind.h | 136 + .../user/include/vendor/osm_pkt_randomizer.h | 224 + .../user/include/vendor/osm_ts_useraccess.h | 52 + .../opensm/user/include/vendor/osm_umadt.h | 137 + .../opensm/user/include/vendor/osm_vendor.h | 71 + .../user/include/vendor/osm_vendor_al.h | 350 + .../user/include/vendor/osm_vendor_api.h | 487 + .../user/include/vendor/osm_vendor_ibumad.h | 182 + .../user/include/vendor/osm_vendor_mlx.h | 99 + .../user/include/vendor/osm_vendor_mlx_defs.h | 101 + .../vendor/osm_vendor_mlx_dispatcher.h | 70 + .../user/include/vendor/osm_vendor_mlx_hca.h | 64 + .../include/vendor/osm_vendor_mlx_inout.h | 76 + .../include/vendor/osm_vendor_mlx_rmpp_ctx.h | 289 + .../user/include/vendor/osm_vendor_mlx_sar.h | 116 + .../include/vendor/osm_vendor_mlx_sender.h | 128 + .../user/include/vendor/osm_vendor_mlx_svc.h | 195 + .../include/vendor/osm_vendor_mlx_transport.h | 95 + .../vendor/osm_vendor_mlx_transport_anafa.h | 69 + .../user/include/vendor/osm_vendor_mlx_txn.h | 380 + .../user/include/vendor/osm_vendor_mtl.h | 348 + .../include/vendor/osm_vendor_mtl_hca_guid.h | 195 + .../vendor/osm_vendor_mtl_transaction_mgr.h | 299 + .../user/include/vendor/osm_vendor_sa_api.h | 866 ++ .../user/include/vendor/osm_vendor_test.h | 123 + .../user/include/vendor/osm_vendor_ts.h | 410 + .../user/include/vendor/osm_vendor_umadt.h | 130 + .../user/include/vendor/winosm_common.h | 211 + .../ulp/opensm/user/libvendor/ChangeLog | 64 + .../WOF2-3/ulp/opensm/user/libvendor/Makefile | 7 + .../WOF2-3/ulp/opensm/user/libvendor/SOURCES | 66 + .../ulp/opensm/user/libvendor/complib_files.c | 3 + .../opensm/user/libvendor/libosmvendor.ver | 9 + .../user/libvendor/osm_pkt_randomizer.c | 323 + .../ulp/opensm/user/libvendor/osm_vendor_al.c | 1527 ++ .../opensm/user/libvendor/osm_vendor_ibumad.c | 1198 ++ .../user/libvendor/osm_vendor_ibumad_sa.c | 733 + .../opensm/user/libvendor/osm_vendor_mlx.c | 768 + .../libvendor/osm_vendor_mlx_dispatcher.c | 710 + .../user/libvendor/osm_vendor_mlx_hca.c | 522 + .../user/libvendor/osm_vendor_mlx_hca_sim.c | 862 ++ .../user/libvendor/osm_vendor_mlx_ibmgt.c | 783 + .../user/libvendor/osm_vendor_mlx_rmpp_ctx.c | 361 + .../opensm/user/libvendor/osm_vendor_mlx_sa.c | 874 ++ .../user/libvendor/osm_vendor_mlx_sar.c | 154 + .../user/libvendor/osm_vendor_mlx_sender.c | 390 + .../user/libvendor/osm_vendor_mlx_sim.c | 439 + .../opensm/user/libvendor/osm_vendor_mlx_ts.c | 505 + .../user/libvendor/osm_vendor_mlx_txn.c | 680 + .../opensm/user/libvendor/osmv_ibal.exports | 34 + .../opensm/user/libvendor/osmv_openib.exports | 33 + .../ulp/opensm/user/libvendor/vendor-ibal.inc | 6 + .../ulp/opensm/user/libvendor/vendor-umad.inc | 5 + .../ulp/opensm/user/libvendor/winosm_common.c | 215 + .../WOF2-3/ulp/opensm/user/mad-vendor.inc | 6 + branches/WOF2-3/ulp/opensm/user/man/opensm.8 | 1105 ++ branches/WOF2-3/ulp/opensm/user/man/osmtest.8 | 191 + .../WOF2-3/ulp/opensm/user/opensm/ChangeLog | 115 + .../WOF2-3/ulp/opensm/user/opensm/Makefile | 7 + .../WOF2-3/ulp/opensm/user/opensm/SOURCES | 75 + .../WOF2-3/ulp/opensm/user/opensm/dlfcn.h | 14 + .../ulp/opensm/user/opensm/libopensm.map | 60 + .../ulp/opensm/user/opensm/libopensm.ver | 9 + branches/WOF2-3/ulp/opensm/user/opensm/main.c | 1534 ++ .../WOF2-3/ulp/opensm/user/opensm/opensm.rc | 46 + branches/WOF2-3/ulp/opensm/user/opensm/osm.mc | 29 + .../ulp/opensm/user/opensm/osm_console.c | 1607 ++ .../ulp/opensm/user/opensm/osm_console_io.c | 238 + .../ulp/opensm/user/opensm/osm_db_files.c | 691 + .../ulp/opensm/user/opensm/osm_db_pack.c | 151 + .../ulp/opensm/user/opensm/osm_drop_mgr.c | 491 + .../WOF2-3/ulp/opensm/user/opensm/osm_dump.c | 639 + .../ulp/opensm/user/opensm/osm_event_plugin.c | 150 + .../WOF2-3/ulp/opensm/user/opensm/osm_files.c | 86 + .../ulp/opensm/user/opensm/osm_helper.c | 2247 +++ .../ulp/opensm/user/opensm/osm_inform.c | 617 + .../ulp/opensm/user/opensm/osm_lid_mgr.c | 1206 ++ .../ulp/opensm/user/opensm/osm_lin_fwd_rcv.c | 101 + .../ulp/opensm/user/opensm/osm_link_mgr.c | 474 + .../WOF2-3/ulp/opensm/user/opensm/osm_log.c | 359 + .../ulp/opensm/user/opensm/osm_mad_pool.c | 173 + .../opensm/user/opensm/osm_mcast_fwd_rcv.c | 120 + .../ulp/opensm/user/opensm/osm_mcast_mgr.c | 1171 ++ .../ulp/opensm/user/opensm/osm_mcast_tbl.c | 262 + .../ulp/opensm/user/opensm/osm_mcm_port.c | 74 + .../WOF2-3/ulp/opensm/user/opensm/osm_mesh.c | 1735 +++ .../WOF2-3/ulp/opensm/user/opensm/osm_mtree.c | 105 + .../ulp/opensm/user/opensm/osm_multicast.c | 325 + .../WOF2-3/ulp/opensm/user/opensm/osm_node.c | 264 + .../opensm/user/opensm/osm_node_desc_rcv.c | 118 + .../opensm/user/opensm/osm_node_info_rcv.c | 804 + .../ulp/opensm/user/opensm/osm_opensm.c | 483 + .../ulp/opensm/user/opensm/osm_perfmgr.c | 1284 ++ .../ulp/opensm/user/opensm/osm_perfmgr_db.c | 818 + .../WOF2-3/ulp/opensm/user/opensm/osm_pkey.c | 427 + .../ulp/opensm/user/opensm/osm_pkey_mgr.c | 520 + .../ulp/opensm/user/opensm/osm_pkey_rcv.c | 141 + .../WOF2-3/ulp/opensm/user/opensm/osm_port.c | 634 + .../opensm/user/opensm/osm_port_info_rcv.c | 618 + .../WOF2-3/ulp/opensm/user/opensm/osm_prtn.c | 388 + .../ulp/opensm/user/opensm/osm_prtn_config.c | 469 + .../WOF2-3/ulp/opensm/user/opensm/osm_qos.c | 393 + .../ulp/opensm/user/opensm/osm_qos_parser_l.c | 2679 ++++ .../ulp/opensm/user/opensm/osm_qos_parser_l.l | 394 + .../ulp/opensm/user/opensm/osm_qos_parser_y.c | 5181 +++++++ .../ulp/opensm/user/opensm/osm_qos_parser_y.h | 208 + .../ulp/opensm/user/opensm/osm_qos_parser_y.y | 3066 ++++ .../ulp/opensm/user/opensm/osm_qos_policy.c | 1057 ++ .../ulp/opensm/user/opensm/osm_remote_sm.c | 71 + .../WOF2-3/ulp/opensm/user/opensm/osm_req.c | 274 + .../WOF2-3/ulp/opensm/user/opensm/osm_resp.c | 150 + .../ulp/opensm/user/opensm/osm_router.c | 71 + .../WOF2-3/ulp/opensm/user/opensm/osm_sa.c | 1133 ++ .../user/opensm/osm_sa_class_port_info.c | 207 + .../user/opensm/osm_sa_guidinfo_record.c | 346 + .../opensm/user/opensm/osm_sa_informinfo.c | 595 + .../opensm/user/opensm/osm_sa_lft_record.c | 236 + .../opensm/user/opensm/osm_sa_link_record.c | 477 + .../ulp/opensm/user/opensm/osm_sa_mad_ctrl.c | 565 + .../user/opensm/osm_sa_mcmember_record.c | 1513 ++ .../opensm/user/opensm/osm_sa_mft_record.c | 269 + .../user/opensm/osm_sa_multipath_record.c | 1482 ++ .../opensm/user/opensm/osm_sa_node_record.c | 337 + .../opensm/user/opensm/osm_sa_path_record.c | 1610 ++ .../opensm/user/opensm/osm_sa_pkey_record.c | 309 + .../user/opensm/osm_sa_portinfo_record.c | 539 + .../user/opensm/osm_sa_service_record.c | 800 + .../opensm/user/opensm/osm_sa_slvl_record.c | 294 + .../opensm/user/opensm/osm_sa_sminfo_record.c | 314 + .../user/opensm/osm_sa_sw_info_record.c | 258 + .../opensm/user/opensm/osm_sa_vlarb_record.c | 306 + .../ulp/opensm/user/opensm/osm_service.c | 145 + .../ulp/opensm/user/opensm/osm_slvl_map_rcv.c | 161 + .../WOF2-3/ulp/opensm/user/opensm/osm_sm.c | 447 + .../ulp/opensm/user/opensm/osm_sm_mad_ctrl.c | 905 ++ .../ulp/opensm/user/opensm/osm_sm_state_mgr.c | 540 + .../ulp/opensm/user/opensm/osm_sminfo_rcv.c | 590 + .../ulp/opensm/user/opensm/osm_state_mgr.c | 1438 ++ .../ulp/opensm/user/opensm/osm_subnet.c | 1663 ++ .../ulp/opensm/user/opensm/osm_sw_info_rcv.c | 382 + .../ulp/opensm/user/opensm/osm_switch.c | 638 + .../ulp/opensm/user/opensm/osm_trap_rcv.c | 622 + .../ulp/opensm/user/opensm/osm_ucast_cache.c | 1028 ++ .../ulp/opensm/user/opensm/osm_ucast_file.c | 389 + .../ulp/opensm/user/opensm/osm_ucast_ftree.c | 4112 +++++ .../ulp/opensm/user/opensm/osm_ucast_lash.c | 1317 ++ .../ulp/opensm/user/opensm/osm_ucast_mgr.c | 1156 ++ .../ulp/opensm/user/opensm/osm_ucast_updn.c | 668 + .../ulp/opensm/user/opensm/osm_vl15intf.c | 366 + .../ulp/opensm/user/opensm/osm_vl_arb_rcv.c | 151 + branches/WOF2-3/ulp/opensm/user/opensm/st.c | 584 + .../ulp/opensm/user/opensm/vendor-ibal.inc | 5 + .../ulp/opensm/user/opensm/vendor-umad.inc | 15 + .../user/osmeventplugin/libosmeventplugin.map | 5 + .../user/osmeventplugin/libosmeventplugin.ver | 9 + .../user/osmeventplugin/src/osmeventplugin.c | 200 + .../WOF2-3/ulp/opensm/user/osmtest/Makefile | 7 + .../WOF2-3/ulp/opensm/user/osmtest/SOURCES | 71 + .../opensm/user/osmtest/include/osmt_inform.h | 78 + .../osmtest/include/osmt_mtl_regular_qp.h | 162 + .../ulp/opensm/user/osmtest/include/osmtest.h | 510 + .../user/osmtest/include/osmtest_base.h | 64 + .../user/osmtest/include/osmtest_subnet.h | 326 + .../WOF2-3/ulp/opensm/user/osmtest/main.c | 622 + .../ulp/opensm/user/osmtest/osmt_files.c | 11 + .../ulp/opensm/user/osmtest/osmt_inform.c | 767 + .../opensm/user/osmtest/osmt_mtl_regular_qp.c | 470 + .../ulp/opensm/user/osmtest/osmt_multicast.c | 2575 ++++ .../ulp/opensm/user/osmtest/osmt_service.c | 1587 ++ .../opensm/user/osmtest/osmt_slvl_vl_arb.c | 526 + .../WOF2-3/ulp/opensm/user/osmtest/osmtest.c | 7410 +++++++++ .../WOF2-3/ulp/opensm/user/osmtest/osmtest.rc | 45 + .../ulp/opensm/user/osmtest/vendor-ibal.inc | 2 + .../ulp/opensm/user/osmtest/vendor-umad.inc | 2 + .../ulp/opensm/user/scripts/osm-regress.bat | 45 + branches/WOF2-3/ulp/qlgcvnic/dirs | 2 + branches/WOF2-3/ulp/qlgcvnic/kernel/SOURCES | 90 + branches/WOF2-3/ulp/qlgcvnic/kernel/inic.rc | 47 + branches/WOF2-3/ulp/qlgcvnic/kernel/makefile | 7 + .../WOF2-3/ulp/qlgcvnic/kernel/makefile.inc | 17 + .../WOF2-3/ulp/qlgcvnic/kernel/netvnic.cdf | 8 + .../WOF2-3/ulp/qlgcvnic/kernel/netvnic.inx | 198 + .../WOF2-3/ulp/qlgcvnic/kernel/vnic_adapter.c | 1845 +++ .../WOF2-3/ulp/qlgcvnic/kernel/vnic_adapter.h | 242 + .../WOF2-3/ulp/qlgcvnic/kernel/vnic_config.h | 302 + .../WOF2-3/ulp/qlgcvnic/kernel/vnic_control.c | 2091 +++ .../WOF2-3/ulp/qlgcvnic/kernel/vnic_control.h | 123 + .../ulp/qlgcvnic/kernel/vnic_controlpkt.h | 287 + .../WOF2-3/ulp/qlgcvnic/kernel/vnic_data.c | 1459 ++ .../WOF2-3/ulp/qlgcvnic/kernel/vnic_data.h | 206 + .../WOF2-3/ulp/qlgcvnic/kernel/vnic_debug.h | 132 + .../WOF2-3/ulp/qlgcvnic/kernel/vnic_driver.c | 2152 +++ .../WOF2-3/ulp/qlgcvnic/kernel/vnic_driver.h | 192 + branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_ib.c | 921 ++ branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_ib.h | 239 + .../WOF2-3/ulp/qlgcvnic/kernel/vnic_netpath.c | 345 + .../WOF2-3/ulp/qlgcvnic/kernel/vnic_trailer.h | 107 + .../WOF2-3/ulp/qlgcvnic/kernel/vnic_util.h | 60 + .../WOF2-3/ulp/qlgcvnic/kernel/vnic_viport.c | 1232 ++ .../WOF2-3/ulp/qlgcvnic/kernel/vnic_viport.h | 396 + branches/WOF2-3/ulp/srp/dirs | 2 + branches/WOF2-3/ulp/srp/kernel/SOURCES | 64 + branches/WOF2-3/ulp/srp/kernel/ib_srp.cdf | 10 + branches/WOF2-3/ulp/srp/kernel/ib_srp.inx | 136 + branches/WOF2-3/ulp/srp/kernel/ibsrp.rc | 47 + branches/WOF2-3/ulp/srp/kernel/makefile | 7 + branches/WOF2-3/ulp/srp/kernel/makefile.inc | 17 + branches/WOF2-3/ulp/srp/kernel/srp.h | 370 + branches/WOF2-3/ulp/srp/kernel/srp_aer_req.h | 295 + branches/WOF2-3/ulp/srp/kernel/srp_aer_rsp.h | 163 + branches/WOF2-3/ulp/srp/kernel/srp_cmd.h | 648 + .../WOF2-3/ulp/srp/kernel/srp_connection.c | 874 ++ .../WOF2-3/ulp/srp/kernel/srp_connection.h | 127 + branches/WOF2-3/ulp/srp/kernel/srp_cred_req.h | 201 + branches/WOF2-3/ulp/srp/kernel/srp_cred_rsp.h | 163 + branches/WOF2-3/ulp/srp/kernel/srp_data.h | 80 + .../WOF2-3/ulp/srp/kernel/srp_data_path.c | 1627 ++ .../WOF2-3/ulp/srp/kernel/srp_data_path.h | 86 + branches/WOF2-3/ulp/srp/kernel/srp_debug.h | 149 + .../WOF2-3/ulp/srp/kernel/srp_descriptors.c | 687 + .../WOF2-3/ulp/srp/kernel/srp_descriptors.h | 144 + branches/WOF2-3/ulp/srp/kernel/srp_driver.c | 941 ++ branches/WOF2-3/ulp/srp/kernel/srp_event.c | 83 + branches/WOF2-3/ulp/srp/kernel/srp_event.h | 42 + branches/WOF2-3/ulp/srp/kernel/srp_hba.c | 1032 ++ branches/WOF2-3/ulp/srp/kernel/srp_hba.h | 100 + branches/WOF2-3/ulp/srp/kernel/srp_hca.c | 263 + branches/WOF2-3/ulp/srp/kernel/srp_hca.h | 76 + branches/WOF2-3/ulp/srp/kernel/srp_i_logout.h | 163 + .../ulp/srp/kernel/srp_information_unit.h | 106 + .../WOF2-3/ulp/srp/kernel/srp_iu_buffer.h | 142 + .../WOF2-3/ulp/srp/kernel/srp_login_rej.h | 262 + .../WOF2-3/ulp/srp/kernel/srp_login_req.h | 364 + .../WOF2-3/ulp/srp/kernel/srp_login_rsp.h | 382 + branches/WOF2-3/ulp/srp/kernel/srp_rsp.h | 726 + branches/WOF2-3/ulp/srp/kernel/srp_session.c | 597 + branches/WOF2-3/ulp/srp/kernel/srp_session.h | 132 + branches/WOF2-3/ulp/srp/kernel/srp_t_logout.h | 200 + branches/WOF2-3/ulp/srp/kernel/srp_tsk_mgmt.h | 276 + branches/WOF2-3/ulp/wsd/dirs | 2 + branches/WOF2-3/ulp/wsd/user/README | 38 + branches/WOF2-3/ulp/wsd/user/SOURCES | 63 + branches/WOF2-3/ulp/wsd/user/extensions.c | 651 + branches/WOF2-3/ulp/wsd/user/ib_cm.c | 991 ++ branches/WOF2-3/ulp/wsd/user/ibsp_duplicate.c | 343 + branches/WOF2-3/ulp/wsd/user/ibsp_iblow.c | 1328 ++ branches/WOF2-3/ulp/wsd/user/ibsp_ip.c | 556 + branches/WOF2-3/ulp/wsd/user/ibsp_mem.c | 400 + branches/WOF2-3/ulp/wsd/user/ibsp_mem.h | 30 + branches/WOF2-3/ulp/wsd/user/ibsp_perfmon.c | 562 + branches/WOF2-3/ulp/wsd/user/ibsp_perfmon.h | 116 + branches/WOF2-3/ulp/wsd/user/ibsp_pnp.c | 443 + branches/WOF2-3/ulp/wsd/user/ibspdebug.c | 291 + branches/WOF2-3/ulp/wsd/user/ibspdebug.h | 268 + branches/WOF2-3/ulp/wsd/user/ibspdefines.h | 90 + branches/WOF2-3/ulp/wsd/user/ibspdll.c | 2594 ++++ branches/WOF2-3/ulp/wsd/user/ibspdll.def | 6 + branches/WOF2-3/ulp/wsd/user/ibspdll.h | 74 + branches/WOF2-3/ulp/wsd/user/ibspdll.rc | 47 + branches/WOF2-3/ulp/wsd/user/ibspproto.h | 311 + branches/WOF2-3/ulp/wsd/user/ibspstruct.h | 491 + branches/WOF2-3/ulp/wsd/user/makefile | 8 + branches/WOF2-3/ulp/wsd/user/misc.c | 134 + branches/WOF2-3/ulp/wsd/user/sockinfo.c | 176 + 2341 files changed, 771991 insertions(+) create mode 100644 branches/WOF2-3/OFED/Bld1.bat create mode 100644 branches/WOF2-3/OFED/BuildRelease.bat create mode 100644 branches/WOF2-3/OFED/WIX/CustomActions.vbs create mode 100644 branches/WOF2-3/OFED/WIX/HPC/HPC.inc create mode 100644 branches/WOF2-3/OFED/WIX/HPC/OFA-cert-install.bat create mode 100644 branches/WOF2-3/OFED/WIX/HPC/WinOF-install.bat create mode 100644 branches/WOF2-3/OFED/WIX/HPC/cert-add.bat create mode 100644 branches/WOF2-3/OFED/WIX/HPC/readme-HPC.txt create mode 100644 branches/WOF2-3/OFED/WIX/HPC/rem-cert-ADD.bat create mode 100644 branches/WOF2-3/OFED/WIX/License.rtf create mode 100644 branches/WOF2-3/OFED/WIX/README.txt create mode 100644 branches/WOF2-3/OFED/WIX/README_checked.txt create mode 100644 branches/WOF2-3/OFED/WIX/README_release.txt create mode 100644 branches/WOF2-3/OFED/WIX/Release_notes.htm create mode 100644 branches/WOF2-3/OFED/WIX/SDK_Samples/WDK/README.txt create mode 100644 branches/WOF2-3/OFED/WIX/SDK_Samples/WDK/SOURCES create mode 100644 branches/WOF2-3/OFED/WIX/SDK_Samples/WDK/cmtest.rc create mode 100644 branches/WOF2-3/OFED/WIX/SDK_Samples/WDK/makefile create mode 100644 branches/WOF2-3/OFED/WIX/SDK_Samples/cmtest/Makefile.x64 create mode 100644 branches/WOF2-3/OFED/WIX/SDK_Samples/cmtest/Makefile.x86 create mode 100644 branches/WOF2-3/OFED/WIX/SDK_Samples/cmtest/README.txt create mode 100644 branches/WOF2-3/OFED/WIX/SDK_Samples/cmtest/cmtest.rc create mode 100644 branches/WOF2-3/OFED/WIX/SDK_Samples/rdma_bw/Makefile.x64 create mode 100644 branches/WOF2-3/OFED/WIX/SDK_Samples/rdma_bw/Makefile.x86 create mode 100644 branches/WOF2-3/OFED/WIX/SDK_Samples/rdma_bw/README.txt create mode 100644 branches/WOF2-3/OFED/WIX/SDK_Samples/rdma_bw/rdma_bw.rc create mode 100644 branches/WOF2-3/OFED/WIX/WIX_tools/README.txt create mode 100644 branches/WOF2-3/OFED/WIX/banner.bmp create mode 100644 branches/WOF2-3/OFED/WIX/build-OFA-dist.bat create mode 100644 branches/WOF2-3/OFED/WIX/build-all-MSI.bat create mode 100644 branches/WOF2-3/OFED/WIX/common/Config.inc create mode 100644 branches/WOF2-3/OFED/WIX/common/DAT_config.inc create mode 100644 branches/WOF2-3/OFED/WIX/common/Docs.inc create mode 100644 branches/WOF2-3/OFED/WIX/common/Drivers.inc create mode 100644 branches/WOF2-3/OFED/WIX/common/IBcore.inc create mode 100644 branches/WOF2-3/OFED/WIX/common/InstallExecuteSeq.inc create mode 100644 branches/WOF2-3/OFED/WIX/common/Makefile.inc create mode 100644 branches/WOF2-3/OFED/WIX/common/OpenSM_service.inc create mode 100644 branches/WOF2-3/OFED/WIX/common/Package.inc create mode 100644 branches/WOF2-3/OFED/WIX/common/PgmMenuShortcuts.inc create mode 100644 branches/WOF2-3/OFED/WIX/common/UserInterface.inc create mode 100644 branches/WOF2-3/OFED/WIX/common/arp.inc create mode 100644 branches/WOF2-3/OFED/WIX/common/checked.inc create mode 100644 branches/WOF2-3/OFED/WIX/common/dapl_rt.inc create mode 100644 branches/WOF2-3/OFED/WIX/common/directory_structure.inc create mode 100644 branches/WOF2-3/OFED/WIX/common/hca_filters.inc create mode 100644 branches/WOF2-3/OFED/WIX/common/ib_sdk.inc create mode 100644 branches/WOF2-3/OFED/WIX/common/iou.inc create mode 100644 branches/WOF2-3/OFED/WIX/common/ipoib.inc create mode 100644 branches/WOF2-3/OFED/WIX/common/mlnx_drivers.inc create mode 100644 branches/WOF2-3/OFED/WIX/common/qlgc_vnic.inc create mode 100644 branches/WOF2-3/OFED/WIX/common/requirements.inc create mode 100644 branches/WOF2-3/OFED/WIX/common/srp.inc create mode 100644 branches/WOF2-3/OFED/WIX/common/std_features.inc create mode 100644 branches/WOF2-3/OFED/WIX/common/system_files.inc create mode 100644 branches/WOF2-3/OFED/WIX/common/tools.inc create mode 100644 branches/WOF2-3/OFED/WIX/common/winverbs_OFED.inc create mode 100644 branches/WOF2-3/OFED/WIX/common/winverbs_drivers.inc create mode 100644 branches/WOF2-3/OFED/WIX/dat.conf create mode 100644 branches/WOF2-3/OFED/WIX/dialog.bmp create mode 100644 branches/WOF2-3/OFED/WIX/dpinst.xml create mode 100644 branches/WOF2-3/OFED/WIX/ia64/Command Window.lnk create mode 100644 branches/WOF2-3/OFED/WIX/ia64/devman.exe create mode 100644 branches/WOF2-3/OFED/WIX/openfabrics.gif create mode 100644 branches/WOF2-3/OFED/WIX/openfabrics.ico create mode 100644 branches/WOF2-3/OFED/WIX/sign-all-drivers.bat create mode 100644 branches/WOF2-3/OFED/WIX/win7/build-MSI.bat create mode 100644 branches/WOF2-3/OFED/WIX/win7/ia64/Makefile create mode 100644 branches/WOF2-3/OFED/WIX/win7/ia64/ofed.wxs create mode 100644 branches/WOF2-3/OFED/WIX/win7/signDrivers.bat create mode 100644 branches/WOF2-3/OFED/WIX/win7/x64/Makefile create mode 100644 branches/WOF2-3/OFED/WIX/win7/x64/ofed.wxs create mode 100644 branches/WOF2-3/OFED/WIX/win7/x86/Makefile create mode 100644 branches/WOF2-3/OFED/WIX/win7/x86/ofed.wxs create mode 100644 branches/WOF2-3/OFED/WIX/wlh/build-MSI.bat create mode 100644 branches/WOF2-3/OFED/WIX/wlh/ia64/Makefile create mode 100644 branches/WOF2-3/OFED/WIX/wlh/ia64/ofed.wxs create mode 100644 branches/WOF2-3/OFED/WIX/wlh/signDrivers.bat create mode 100644 branches/WOF2-3/OFED/WIX/wlh/x64/Makefile create mode 100644 branches/WOF2-3/OFED/WIX/wlh/x64/ofed.wxs create mode 100644 branches/WOF2-3/OFED/WIX/wlh/x86/Makefile create mode 100644 branches/WOF2-3/OFED/WIX/wlh/x86/ofed.wxs create mode 100644 branches/WOF2-3/OFED/WIX/wnet/build-MSI.bat create mode 100644 branches/WOF2-3/OFED/WIX/wnet/ia64/Makefile create mode 100644 branches/WOF2-3/OFED/WIX/wnet/ia64/ofed.wxs create mode 100644 branches/WOF2-3/OFED/WIX/wnet/signDrivers.bat create mode 100644 branches/WOF2-3/OFED/WIX/wnet/x64/Makefile create mode 100644 branches/WOF2-3/OFED/WIX/wnet/x64/ofed.wxs create mode 100644 branches/WOF2-3/OFED/WIX/wnet/x86/Makefile create mode 100644 branches/WOF2-3/OFED/WIX/wnet/x86/ofed.wxs create mode 100644 branches/WOF2-3/OFED/WIX/wxp/build-MSI.bat create mode 100644 branches/WOF2-3/OFED/WIX/wxp/signDrivers.bat create mode 100644 branches/WOF2-3/OFED/WIX/wxp/x86/Makefile create mode 100644 branches/WOF2-3/OFED/WIX/wxp/x86/ofed.wxs create mode 100644 branches/WOF2-3/OFED/WIX/x64/Command Window.lnk create mode 100644 branches/WOF2-3/OFED/WIX/x64/devman.exe create mode 100644 branches/WOF2-3/OFED/WIX/x86/Command Window.lnk create mode 100644 branches/WOF2-3/OFED/WIX/x86/devman.exe create mode 100644 branches/WOF2-3/OFED/WIX/zip-OFA-dist.bat create mode 100644 branches/WOF2-3/core/al/al.c create mode 100644 branches/WOF2-3/core/al/al.h create mode 100644 branches/WOF2-3/core/al/al_av.c create mode 100644 branches/WOF2-3/core/al/al_av.h create mode 100644 branches/WOF2-3/core/al/al_ca.c create mode 100644 branches/WOF2-3/core/al/al_ca.h create mode 100644 branches/WOF2-3/core/al/al_ci_ca.h create mode 100644 branches/WOF2-3/core/al/al_ci_ca_shared.c create mode 100644 branches/WOF2-3/core/al/al_cm_cep.h create mode 100644 branches/WOF2-3/core/al/al_cm_conn.h create mode 100644 branches/WOF2-3/core/al/al_cm_qp.c create mode 100644 branches/WOF2-3/core/al/al_cm_sidr.h create mode 100644 branches/WOF2-3/core/al/al_common.c create mode 100644 branches/WOF2-3/core/al/al_common.h create mode 100644 branches/WOF2-3/core/al/al_cq.c create mode 100644 branches/WOF2-3/core/al/al_cq.h create mode 100644 branches/WOF2-3/core/al/al_debug.h create mode 100644 branches/WOF2-3/core/al/al_dev.h create mode 100644 branches/WOF2-3/core/al/al_dm.c create mode 100644 branches/WOF2-3/core/al/al_dm.h create mode 100644 branches/WOF2-3/core/al/al_init.c create mode 100644 branches/WOF2-3/core/al/al_init.h create mode 100644 branches/WOF2-3/core/al/al_ioc_pnp.h create mode 100644 branches/WOF2-3/core/al/al_mad.c create mode 100644 branches/WOF2-3/core/al/al_mad.h create mode 100644 branches/WOF2-3/core/al/al_mad_pool.h create mode 100644 branches/WOF2-3/core/al/al_mcast.c create mode 100644 branches/WOF2-3/core/al/al_mcast.h create mode 100644 branches/WOF2-3/core/al/al_mgr.h create mode 100644 branches/WOF2-3/core/al/al_mgr_shared.c create mode 100644 branches/WOF2-3/core/al/al_mr.h create mode 100644 branches/WOF2-3/core/al/al_mr_shared.c create mode 100644 branches/WOF2-3/core/al/al_mw.c create mode 100644 branches/WOF2-3/core/al/al_mw.h create mode 100644 branches/WOF2-3/core/al/al_pd.c create mode 100644 branches/WOF2-3/core/al/al_pd.h create mode 100644 branches/WOF2-3/core/al/al_pnp.h create mode 100644 branches/WOF2-3/core/al/al_proxy_ioctl.h create mode 100644 branches/WOF2-3/core/al/al_proxy_ndi.h create mode 100644 branches/WOF2-3/core/al/al_qp.c create mode 100644 branches/WOF2-3/core/al/al_qp.h create mode 100644 branches/WOF2-3/core/al/al_query.c create mode 100644 branches/WOF2-3/core/al/al_query.h create mode 100644 branches/WOF2-3/core/al/al_reg_svc.c create mode 100644 branches/WOF2-3/core/al/al_reg_svc.h create mode 100644 branches/WOF2-3/core/al/al_res_mgr.c create mode 100644 branches/WOF2-3/core/al/al_res_mgr.h create mode 100644 branches/WOF2-3/core/al/al_srq.c create mode 100644 branches/WOF2-3/core/al/al_srq.h create mode 100644 branches/WOF2-3/core/al/al_sub.c create mode 100644 branches/WOF2-3/core/al/al_verbs.h create mode 100644 branches/WOF2-3/core/al/dirs create mode 100644 branches/WOF2-3/core/al/ib_common.c create mode 100644 branches/WOF2-3/core/al/ib_common.h create mode 100644 branches/WOF2-3/core/al/ib_statustext.c create mode 100644 branches/WOF2-3/core/al/kernel/SOURCES create mode 100644 branches/WOF2-3/core/al/kernel/al_ci_ca.c create mode 100644 branches/WOF2-3/core/al/kernel/al_cm.c create mode 100644 branches/WOF2-3/core/al/kernel/al_cm_cep.c create mode 100644 branches/WOF2-3/core/al/kernel/al_dev.c create mode 100644 branches/WOF2-3/core/al/kernel/al_exports.def create mode 100644 branches/WOF2-3/core/al/kernel/al_fmr_pool.c create mode 100644 branches/WOF2-3/core/al/kernel/al_fmr_pool.h create mode 100644 branches/WOF2-3/core/al/kernel/al_ioc_pnp.c create mode 100644 branches/WOF2-3/core/al/kernel/al_mad_pool.c create mode 100644 branches/WOF2-3/core/al/kernel/al_mgr.c create mode 100644 branches/WOF2-3/core/al/kernel/al_mr.c create mode 100644 branches/WOF2-3/core/al/kernel/al_ndi_cm.c create mode 100644 branches/WOF2-3/core/al/kernel/al_ndi_cm.h create mode 100644 branches/WOF2-3/core/al/kernel/al_ndi_cq.c create mode 100644 branches/WOF2-3/core/al/kernel/al_ndi_cq.h create mode 100644 branches/WOF2-3/core/al/kernel/al_pnp.c create mode 100644 branches/WOF2-3/core/al/kernel/al_proxy.c create mode 100644 branches/WOF2-3/core/al/kernel/al_proxy.h create mode 100644 branches/WOF2-3/core/al/kernel/al_proxy_cep.c create mode 100644 branches/WOF2-3/core/al/kernel/al_proxy_ioc.c create mode 100644 branches/WOF2-3/core/al/kernel/al_proxy_ndi.c create mode 100644 branches/WOF2-3/core/al/kernel/al_proxy_subnet.c create mode 100644 branches/WOF2-3/core/al/kernel/al_proxy_verbs.c create mode 100644 branches/WOF2-3/core/al/kernel/al_sa_req.c create mode 100644 branches/WOF2-3/core/al/kernel/al_smi.c create mode 100644 branches/WOF2-3/core/al/kernel/al_smi.h create mode 100644 branches/WOF2-3/core/al/kernel/ibal.rc create mode 100644 branches/WOF2-3/core/al/kernel/makefile create mode 100644 branches/WOF2-3/core/al/user/SOURCES create mode 100644 branches/WOF2-3/core/al/user/al_dll.c create mode 100644 branches/WOF2-3/core/al/user/al_exports.src create mode 100644 branches/WOF2-3/core/al/user/al_mad_pool.c create mode 100644 branches/WOF2-3/core/al/user/ibal.rc create mode 100644 branches/WOF2-3/core/al/user/makefile create mode 100644 branches/WOF2-3/core/al/user/ual_av.c create mode 100644 branches/WOF2-3/core/al/user/ual_ca.c create mode 100644 branches/WOF2-3/core/al/user/ual_ca.h create mode 100644 branches/WOF2-3/core/al/user/ual_ci_ca.c create mode 100644 branches/WOF2-3/core/al/user/ual_ci_ca.h create mode 100644 branches/WOF2-3/core/al/user/ual_cm_cep.c create mode 100644 branches/WOF2-3/core/al/user/ual_cq.c create mode 100644 branches/WOF2-3/core/al/user/ual_mad.c create mode 100644 branches/WOF2-3/core/al/user/ual_mad.h create mode 100644 branches/WOF2-3/core/al/user/ual_mad_pool.c create mode 100644 branches/WOF2-3/core/al/user/ual_mcast.c create mode 100644 branches/WOF2-3/core/al/user/ual_mcast.h create mode 100644 branches/WOF2-3/core/al/user/ual_mgr.c create mode 100644 branches/WOF2-3/core/al/user/ual_mgr.h create mode 100644 branches/WOF2-3/core/al/user/ual_mr.c create mode 100644 branches/WOF2-3/core/al/user/ual_mw.c create mode 100644 branches/WOF2-3/core/al/user/ual_pd.c create mode 100644 branches/WOF2-3/core/al/user/ual_pnp.c create mode 100644 branches/WOF2-3/core/al/user/ual_qp.c create mode 100644 branches/WOF2-3/core/al/user/ual_qp.h create mode 100644 branches/WOF2-3/core/al/user/ual_res_mgr.h create mode 100644 branches/WOF2-3/core/al/user/ual_sa_req.c create mode 100644 branches/WOF2-3/core/al/user/ual_srq.c create mode 100644 branches/WOF2-3/core/al/user/ual_support.h create mode 100644 branches/WOF2-3/core/bus/dirs create mode 100644 branches/WOF2-3/core/bus/kernel/SOURCES create mode 100644 branches/WOF2-3/core/bus/kernel/bus_driver.c create mode 100644 branches/WOF2-3/core/bus/kernel/bus_driver.h create mode 100644 branches/WOF2-3/core/bus/kernel/bus_ev_log.mc create mode 100644 branches/WOF2-3/core/bus/kernel/bus_iou_mgr.c create mode 100644 branches/WOF2-3/core/bus/kernel/bus_iou_mgr.h create mode 100644 branches/WOF2-3/core/bus/kernel/bus_pnp.c create mode 100644 branches/WOF2-3/core/bus/kernel/bus_pnp.h create mode 100644 branches/WOF2-3/core/bus/kernel/bus_port_mgr.c create mode 100644 branches/WOF2-3/core/bus/kernel/bus_port_mgr.h create mode 100644 branches/WOF2-3/core/bus/kernel/bus_stat.c create mode 100644 branches/WOF2-3/core/bus/kernel/bus_stat.h create mode 100644 branches/WOF2-3/core/bus/kernel/ibbus.rc create mode 100644 branches/WOF2-3/core/bus/kernel/makefile create mode 100644 branches/WOF2-3/core/complib/cl_async_proc.c create mode 100644 branches/WOF2-3/core/complib/cl_list.c create mode 100644 branches/WOF2-3/core/complib/cl_map.c create mode 100644 branches/WOF2-3/core/complib/cl_memory.c create mode 100644 branches/WOF2-3/core/complib/cl_memtrack.h create mode 100644 branches/WOF2-3/core/complib/cl_obj.c create mode 100644 branches/WOF2-3/core/complib/cl_perf.c create mode 100644 branches/WOF2-3/core/complib/cl_pool.c create mode 100644 branches/WOF2-3/core/complib/cl_ptr_vector.c create mode 100644 branches/WOF2-3/core/complib/cl_reqmgr.c create mode 100644 branches/WOF2-3/core/complib/cl_statustext.c create mode 100644 branches/WOF2-3/core/complib/cl_threadpool.c create mode 100644 branches/WOF2-3/core/complib/cl_vector.c create mode 100644 branches/WOF2-3/core/complib/dirs create mode 100644 branches/WOF2-3/core/complib/kernel/SOURCES create mode 100644 branches/WOF2-3/core/complib/kernel/cl_bus_ifc.c create mode 100644 branches/WOF2-3/core/complib/kernel/cl_driver.c create mode 100644 branches/WOF2-3/core/complib/kernel/cl_event.c create mode 100644 branches/WOF2-3/core/complib/kernel/cl_exports.def create mode 100644 branches/WOF2-3/core/complib/kernel/cl_log.c create mode 100644 branches/WOF2-3/core/complib/kernel/cl_memory_osd.c create mode 100644 branches/WOF2-3/core/complib/kernel/cl_pnp_po.c create mode 100644 branches/WOF2-3/core/complib/kernel/cl_syscallback.c create mode 100644 branches/WOF2-3/core/complib/kernel/cl_thread.c create mode 100644 branches/WOF2-3/core/complib/kernel/cl_timer.c create mode 100644 branches/WOF2-3/core/complib/kernel/makefile create mode 100644 branches/WOF2-3/core/complib/user/SOURCES create mode 100644 branches/WOF2-3/core/complib/user/cl_debug.c create mode 100644 branches/WOF2-3/core/complib/user/cl_dll.c create mode 100644 branches/WOF2-3/core/complib/user/cl_event.c create mode 100644 branches/WOF2-3/core/complib/user/cl_log.c create mode 100644 branches/WOF2-3/core/complib/user/cl_memory_osd.c create mode 100644 branches/WOF2-3/core/complib/user/cl_nodenamemap.c create mode 100644 branches/WOF2-3/core/complib/user/cl_syscallback.c create mode 100644 branches/WOF2-3/core/complib/user/cl_thread.c create mode 100644 branches/WOF2-3/core/complib/user/cl_timer.c create mode 100644 branches/WOF2-3/core/complib/user/complib.rc create mode 100644 branches/WOF2-3/core/complib/user/complib.src create mode 100644 branches/WOF2-3/core/complib/user/makefile create mode 100644 branches/WOF2-3/core/dirs create mode 100644 branches/WOF2-3/core/ibat/dirs create mode 100644 branches/WOF2-3/core/ibat/user/SOURCES create mode 100644 branches/WOF2-3/core/ibat/user/ibat.cpp create mode 100644 branches/WOF2-3/core/ibat/user/makefile create mode 100644 branches/WOF2-3/core/iou/dirs create mode 100644 branches/WOF2-3/core/iou/kernel/SOURCES create mode 100644 branches/WOF2-3/core/iou/kernel/ib_iou.cdf create mode 100644 branches/WOF2-3/core/iou/kernel/ib_iou.inx create mode 100644 branches/WOF2-3/core/iou/kernel/ibiou.rc create mode 100644 branches/WOF2-3/core/iou/kernel/iou_driver.c create mode 100644 branches/WOF2-3/core/iou/kernel/iou_driver.h create mode 100644 branches/WOF2-3/core/iou/kernel/iou_ioc_mgr.c create mode 100644 branches/WOF2-3/core/iou/kernel/iou_ioc_mgr.h create mode 100644 branches/WOF2-3/core/iou/kernel/iou_pnp.c create mode 100644 branches/WOF2-3/core/iou/kernel/iou_pnp.h create mode 100644 branches/WOF2-3/core/iou/kernel/makefile create mode 100644 branches/WOF2-3/core/iou/kernel/makefile.inc create mode 100644 branches/WOF2-3/core/winmad/dirs create mode 100644 branches/WOF2-3/core/winmad/kernel/SOURCES create mode 100644 branches/WOF2-3/core/winmad/kernel/makefile create mode 100644 branches/WOF2-3/core/winmad/kernel/makefile.inc create mode 100644 branches/WOF2-3/core/winmad/kernel/winmad.inx create mode 100644 branches/WOF2-3/core/winmad/kernel/winmad.rc create mode 100644 branches/WOF2-3/core/winmad/kernel/wm_driver.c create mode 100644 branches/WOF2-3/core/winmad/kernel/wm_driver.h create mode 100644 branches/WOF2-3/core/winmad/kernel/wm_provider.c create mode 100644 branches/WOF2-3/core/winmad/kernel/wm_provider.h create mode 100644 branches/WOF2-3/core/winmad/kernel/wm_reg.c create mode 100644 branches/WOF2-3/core/winmad/kernel/wm_reg.h create mode 100644 branches/WOF2-3/core/winmad/user/SOURCES create mode 100644 branches/WOF2-3/core/winmad/user/makefile create mode 100644 branches/WOF2-3/core/winmad/user/winmad.rc create mode 100644 branches/WOF2-3/core/winmad/user/wm_exports.src create mode 100644 branches/WOF2-3/core/winmad/user/wm_main.cpp create mode 100644 branches/WOF2-3/core/winmad/user/wm_memory.h create mode 100644 branches/WOF2-3/core/winmad/user/wm_provider.cpp create mode 100644 branches/WOF2-3/core/winmad/user/wm_provider.h create mode 100644 branches/WOF2-3/core/winmad/wm_ioctl.h create mode 100644 branches/WOF2-3/core/winverbs/dirs create mode 100644 branches/WOF2-3/core/winverbs/kernel/SOURCES create mode 100644 branches/WOF2-3/core/winverbs/kernel/makefile create mode 100644 branches/WOF2-3/core/winverbs/kernel/makefile.inc create mode 100644 branches/WOF2-3/core/winverbs/kernel/winverbs.cdf create mode 100644 branches/WOF2-3/core/winverbs/kernel/winverbs.inx create mode 100644 branches/WOF2-3/core/winverbs/kernel/winverbs.rc create mode 100644 branches/WOF2-3/core/winverbs/kernel/wv_cq.c create mode 100644 branches/WOF2-3/core/winverbs/kernel/wv_cq.h create mode 100644 branches/WOF2-3/core/winverbs/kernel/wv_device.c create mode 100644 branches/WOF2-3/core/winverbs/kernel/wv_device.h create mode 100644 branches/WOF2-3/core/winverbs/kernel/wv_driver.c create mode 100644 branches/WOF2-3/core/winverbs/kernel/wv_driver.h create mode 100644 branches/WOF2-3/core/winverbs/kernel/wv_ep.c create mode 100644 branches/WOF2-3/core/winverbs/kernel/wv_ep.h create mode 100644 branches/WOF2-3/core/winverbs/kernel/wv_pd.c create mode 100644 branches/WOF2-3/core/winverbs/kernel/wv_pd.h create mode 100644 branches/WOF2-3/core/winverbs/kernel/wv_provider.c create mode 100644 branches/WOF2-3/core/winverbs/kernel/wv_provider.h create mode 100644 branches/WOF2-3/core/winverbs/kernel/wv_qp.c create mode 100644 branches/WOF2-3/core/winverbs/kernel/wv_qp.h create mode 100644 branches/WOF2-3/core/winverbs/kernel/wv_srq.c create mode 100644 branches/WOF2-3/core/winverbs/kernel/wv_srq.h create mode 100644 branches/WOF2-3/core/winverbs/user/SOURCES create mode 100644 branches/WOF2-3/core/winverbs/user/makefile create mode 100644 branches/WOF2-3/core/winverbs/user/winverbs.rc create mode 100644 branches/WOF2-3/core/winverbs/user/wv_base.cpp create mode 100644 branches/WOF2-3/core/winverbs/user/wv_base.h create mode 100644 branches/WOF2-3/core/winverbs/user/wv_cq.cpp create mode 100644 branches/WOF2-3/core/winverbs/user/wv_cq.h create mode 100644 branches/WOF2-3/core/winverbs/user/wv_device.cpp create mode 100644 branches/WOF2-3/core/winverbs/user/wv_device.h create mode 100644 branches/WOF2-3/core/winverbs/user/wv_ep.cpp create mode 100644 branches/WOF2-3/core/winverbs/user/wv_ep.h create mode 100644 branches/WOF2-3/core/winverbs/user/wv_exports.src create mode 100644 branches/WOF2-3/core/winverbs/user/wv_main.cpp create mode 100644 branches/WOF2-3/core/winverbs/user/wv_memory.h create mode 100644 branches/WOF2-3/core/winverbs/user/wv_pd.cpp create mode 100644 branches/WOF2-3/core/winverbs/user/wv_pd.h create mode 100644 branches/WOF2-3/core/winverbs/user/wv_provider.cpp create mode 100644 branches/WOF2-3/core/winverbs/user/wv_provider.h create mode 100644 branches/WOF2-3/core/winverbs/user/wv_qp.cpp create mode 100644 branches/WOF2-3/core/winverbs/user/wv_qp.h create mode 100644 branches/WOF2-3/core/winverbs/user/wv_srq.cpp create mode 100644 branches/WOF2-3/core/winverbs/user/wv_srq.h create mode 100644 branches/WOF2-3/core/winverbs/user/wv_uverbs.cpp create mode 100644 branches/WOF2-3/core/winverbs/wv_ioctl.h create mode 100644 branches/WOF2-3/core/winverbs/wv_public.h create mode 100644 branches/WOF2-3/dirs create mode 100644 branches/WOF2-3/docs/Manual.htm create mode 100644 branches/WOF2-3/docs/build.txt create mode 100644 branches/WOF2-3/docs/complib/cl_async_proc_h.html create mode 100644 branches/WOF2-3/docs/complib/cl_atomic_h.html create mode 100644 branches/WOF2-3/docs/complib/cl_byteswap_h.html create mode 100644 branches/WOF2-3/docs/complib/cl_comppool_h.html create mode 100644 branches/WOF2-3/docs/complib/cl_debug_h.html create mode 100644 branches/WOF2-3/docs/complib/cl_event_h.html create mode 100644 branches/WOF2-3/docs/complib/cl_fleximap_h.html create mode 100644 branches/WOF2-3/docs/complib/cl_ioctl_h.html create mode 100644 branches/WOF2-3/docs/complib/cl_irqlock_h.html create mode 100644 branches/WOF2-3/docs/complib/cl_list_h.html create mode 100644 branches/WOF2-3/docs/complib/cl_log_h.html create mode 100644 branches/WOF2-3/docs/complib/cl_map_h.html create mode 100644 branches/WOF2-3/docs/complib/cl_math_h.html create mode 100644 branches/WOF2-3/docs/complib/cl_memory_h.html create mode 100644 branches/WOF2-3/docs/complib/cl_mutex_h.html create mode 100644 branches/WOF2-3/docs/complib/cl_obj_h.html create mode 100644 branches/WOF2-3/docs/complib/cl_passivelock_h.html create mode 100644 branches/WOF2-3/docs/complib/cl_perf_h.html create mode 100644 branches/WOF2-3/docs/complib/cl_pool_h.html create mode 100644 branches/WOF2-3/docs/complib/cl_ptr_vector_h.html create mode 100644 branches/WOF2-3/docs/complib/cl_qcomppool_h.html create mode 100644 branches/WOF2-3/docs/complib/cl_qlist_h.html create mode 100644 branches/WOF2-3/docs/complib/cl_qlockpool_h.html create mode 100644 branches/WOF2-3/docs/complib/cl_qmap_h.html create mode 100644 branches/WOF2-3/docs/complib/cl_qpool_h.html create mode 100644 branches/WOF2-3/docs/complib/cl_rbmap_h.html create mode 100644 branches/WOF2-3/docs/complib/cl_reqmgr_h.html create mode 100644 branches/WOF2-3/docs/complib/cl_spinlock_h.html create mode 100644 branches/WOF2-3/docs/complib/cl_syscallback_h.html create mode 100644 branches/WOF2-3/docs/complib/cl_thread_h.html create mode 100644 branches/WOF2-3/docs/complib/cl_threadpool_h.html create mode 100644 branches/WOF2-3/docs/complib/cl_timer_h.html create mode 100644 branches/WOF2-3/docs/complib/cl_types_h.html create mode 100644 branches/WOF2-3/docs/complib/cl_vector_h.html create mode 100644 branches/WOF2-3/docs/complib/cl_waitobj_h.html create mode 100644 branches/WOF2-3/docs/complib/comp_lib_h.html create mode 100644 branches/WOF2-3/docs/dontdiff.txt create mode 100644 branches/WOF2-3/docs/generate-patch.txt create mode 100644 branches/WOF2-3/docs/iba/ib_al_h.html create mode 100644 branches/WOF2-3/docs/iba/ib_types_h.html create mode 100644 branches/WOF2-3/docs/install.txt create mode 100755 branches/WOF2-3/docs/interfaces.txt create mode 100644 branches/WOF2-3/docs/maintainers.txt create mode 100644 branches/WOF2-3/docs/masterindex.html create mode 100644 branches/WOF2-3/docs/openfabrics.gif create mode 100644 branches/WOF2-3/docs/robo_definitions.html create mode 100644 branches/WOF2-3/docs/robo_functions.html create mode 100644 branches/WOF2-3/docs/robo_modules.html create mode 100644 branches/WOF2-3/docs/robo_sourcefiles.html create mode 100644 branches/WOF2-3/docs/robo_strutures.html create mode 100644 branches/WOF2-3/docs/robodoc.css create mode 100644 branches/WOF2-3/etc/addcert.bat create mode 100644 branches/WOF2-3/etc/bldwo.bat create mode 100644 branches/WOF2-3/etc/bldwoall.bat create mode 100644 branches/WOF2-3/etc/clean-build.bat create mode 100644 branches/WOF2-3/etc/cpinst.bat create mode 100644 branches/WOF2-3/etc/depwo.bat create mode 100644 branches/WOF2-3/etc/kernel/index_list.c create mode 100644 branches/WOF2-3/etc/kernel/work_queue.c create mode 100644 branches/WOF2-3/etc/makebin.bat create mode 100644 branches/WOF2-3/etc/nomerge.txt create mode 100644 branches/WOF2-3/etc/pkgwo.bat create mode 100644 branches/WOF2-3/etc/pkgwoall.bat create mode 100644 branches/WOF2-3/etc/signall.bat create mode 100644 branches/WOF2-3/etc/signwo.bat create mode 100644 branches/WOF2-3/etc/user/comp_channel.cpp create mode 100644 branches/WOF2-3/etc/user/getopt.c create mode 100644 branches/WOF2-3/etc/user/gtod.c create mode 100644 branches/WOF2-3/etc/user/inet.c create mode 100644 branches/WOF2-3/etc/user/search.c create mode 100644 branches/WOF2-3/etc/wpp/ALTraceRt.cmd create mode 100644 branches/WOF2-3/etc/wpp/CreateTrace.cmd create mode 100644 branches/WOF2-3/etc/wpp/IPoIBTraceRt.cmd create mode 100644 branches/WOF2-3/etc/wpp/MTHCATraceRt.cmd create mode 100644 branches/WOF2-3/etc/wpp/SDPTraceRt.cmd create mode 100644 branches/WOF2-3/etc/wpp/StartSdpTrace.cmd create mode 100644 branches/WOF2-3/etc/wpp/StartTrace.cmd create mode 100644 branches/WOF2-3/etc/wpp/StopSdpTrace.cmd create mode 100644 branches/WOF2-3/etc/wpp/StopTrace.cmd create mode 100644 branches/WOF2-3/hw/dirs create mode 100644 branches/WOF2-3/hw/mlx4/dirs create mode 100644 branches/WOF2-3/hw/mlx4/inc/mx_abi.h create mode 100644 branches/WOF2-3/hw/mlx4/inc/public.h create mode 100644 branches/WOF2-3/hw/mlx4/inc/user.h create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/core/SOURCES create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/core/cache.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/core/core.def create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/core/core.h create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/core/core.rc create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/core/device.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/core/ev_log.mc create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/core/iobuf.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/core/l2w.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/core/l2w_debug.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/core/l2w_memory.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/core/l2w_radix.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/core/l2w_umem.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/core/makefile create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/core/pa_cash.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/core/pa_cash.h create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/core/packer.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/core/ud_header.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/core/verbs.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/dirs create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/drv/bus.mof create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/drv/bus.rc create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/drv/drv.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/drv/drv.h create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/drv/makefile create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/drv/makefile.inc create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/drv/mlx4_bus.cdf create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/drv/mlx4_bus.inx create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/drv/mlx4_bus32.cdf create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/drv/pci.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/drv/pdo.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/drv/precomp.h create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/drv/sources create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/drv/stat.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/drv/stat.h create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/drv/wmi.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/drv/wpptrace.h create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/ib/Kconfig create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/ib/Makefile.lnx create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/ib/SOURCES create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/ib/ah.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/ib/cq.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/ib/doorbell.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/ib/ib.def create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/ib/ib.rc create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/ib/mad.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/ib/main.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/ib/makefile create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/ib/mlx4_ib.h create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/ib/mr.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/ib/qp.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/ib/srq.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/inc/bus_intf.h create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/inc/cmd.h create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/inc/cq.h create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/inc/device.h create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/inc/doorbell.h create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/inc/driver.h create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/inc/eq.h create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/inc/ib_cache.h create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/inc/ib_mad.h create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/inc/ib_pack.h create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/inc/ib_smi.h create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/inc/ib_verbs.h create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/inc/ib_verbs_ex.h create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/inc/qp.h create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/inc/srq.h create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/net/Makefile.lnx create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/net/SOURCES create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/net/alloc.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/net/catas.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/net/cmd.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/net/cq.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/net/eq.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/net/fw.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/net/fw.h create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/net/icm.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/net/icm.h create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/net/intf.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/net/main.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/net/makefile create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/net/mcg.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/net/mlx4.h create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/net/mr.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/net/net.def create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/net/net.rc create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/net/pd.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/net/port.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/net/profile.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/net/qp.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/net/reset.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/bus/net/srq.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/dirs create mode 100644 branches/WOF2-3/hw/mlx4/kernel/hca/Makefile create mode 100644 branches/WOF2-3/hw/mlx4/kernel/hca/SOURCES create mode 100644 branches/WOF2-3/hw/mlx4/kernel/hca/av.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/hca/ca.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/hca/cq.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/hca/data.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/hca/data.h create mode 100644 branches/WOF2-3/hw/mlx4/kernel/hca/debug.h create mode 100644 branches/WOF2-3/hw/mlx4/kernel/hca/direct.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/hca/drv.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/hca/drv.h create mode 100644 branches/WOF2-3/hw/mlx4/kernel/hca/fw.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/hca/hca.mof create mode 100644 branches/WOF2-3/hw/mlx4/kernel/hca/hca.rc create mode 100644 branches/WOF2-3/hw/mlx4/kernel/hca/hverbs.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/hca/hverbs.h create mode 100644 branches/WOF2-3/hw/mlx4/kernel/hca/makefile.inc create mode 100644 branches/WOF2-3/hw/mlx4/kernel/hca/mcast.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/hca/mlx4_hca.cdf create mode 100644 branches/WOF2-3/hw/mlx4/kernel/hca/mlx4_hca.inx create mode 100644 branches/WOF2-3/hw/mlx4/kernel/hca/mlx4_hca32.cdf create mode 100644 branches/WOF2-3/hw/mlx4/kernel/hca/mr.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/hca/pd.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/hca/precomp.h create mode 100644 branches/WOF2-3/hw/mlx4/kernel/hca/qp.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/hca/srq.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/hca/vp.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/hca/wmi.c create mode 100644 branches/WOF2-3/hw/mlx4/kernel/inc/iobuf.h create mode 100644 branches/WOF2-3/hw/mlx4/kernel/inc/l2w.h create mode 100644 branches/WOF2-3/hw/mlx4/kernel/inc/l2w_atomic.h create mode 100644 branches/WOF2-3/hw/mlx4/kernel/inc/l2w_bit.h create mode 100644 branches/WOF2-3/hw/mlx4/kernel/inc/l2w_bitmap.h create mode 100644 branches/WOF2-3/hw/mlx4/kernel/inc/l2w_debug.h create mode 100644 branches/WOF2-3/hw/mlx4/kernel/inc/l2w_list.h create mode 100644 branches/WOF2-3/hw/mlx4/kernel/inc/l2w_memory.h create mode 100644 branches/WOF2-3/hw/mlx4/kernel/inc/l2w_pci.h create mode 100644 branches/WOF2-3/hw/mlx4/kernel/inc/l2w_pcipool.h create mode 100644 branches/WOF2-3/hw/mlx4/kernel/inc/l2w_radix.h create mode 100644 branches/WOF2-3/hw/mlx4/kernel/inc/l2w_spinlock.h create mode 100644 branches/WOF2-3/hw/mlx4/kernel/inc/l2w_sync.h create mode 100644 branches/WOF2-3/hw/mlx4/kernel/inc/l2w_time.h create mode 100644 branches/WOF2-3/hw/mlx4/kernel/inc/l2w_umem.h create mode 100644 branches/WOF2-3/hw/mlx4/kernel/inc/mlx4_debug.h create mode 100644 branches/WOF2-3/hw/mlx4/kernel/inc/vc.h create mode 100644 branches/WOF2-3/hw/mlx4/kernel/inc/vip_dev.h create mode 100644 branches/WOF2-3/hw/mlx4/kernel_patches/core_0020_csum.patch create mode 100644 branches/WOF2-3/hw/mlx4/kernel_patches/core_0025_qp_create_flags.patch create mode 100644 branches/WOF2-3/hw/mlx4/kernel_patches/core_0030_lso.patch create mode 100644 branches/WOF2-3/hw/mlx4/kernel_patches/mlx4_0010_add_wc.patch create mode 100644 branches/WOF2-3/hw/mlx4/kernel_patches/mlx4_0030_checksum_offload.patch create mode 100644 branches/WOF2-3/hw/mlx4/kernel_patches/mlx4_0045_qp_flags.patch create mode 100644 branches/WOF2-3/hw/mlx4/kernel_patches/mlx4_0050_lso.patch create mode 100644 branches/WOF2-3/hw/mlx4/kernel_patches/mlx4_0170_shrinking_wqe.patch create mode 100644 branches/WOF2-3/hw/mlx4/todo.txt create mode 100644 branches/WOF2-3/hw/mlx4/user/dirs create mode 100644 branches/WOF2-3/hw/mlx4/user/hca/Makefile create mode 100644 branches/WOF2-3/hw/mlx4/user/hca/SOURCES create mode 100644 branches/WOF2-3/hw/mlx4/user/hca/buf.c create mode 100644 branches/WOF2-3/hw/mlx4/user/hca/cq.c create mode 100644 branches/WOF2-3/hw/mlx4/user/hca/dbrec.c create mode 100644 branches/WOF2-3/hw/mlx4/user/hca/doorbell.h create mode 100644 branches/WOF2-3/hw/mlx4/user/hca/l2w.h create mode 100644 branches/WOF2-3/hw/mlx4/user/hca/mlx4.c create mode 100644 branches/WOF2-3/hw/mlx4/user/hca/mlx4.def create mode 100644 branches/WOF2-3/hw/mlx4/user/hca/mlx4.h create mode 100644 branches/WOF2-3/hw/mlx4/user/hca/mlx4_debug.c create mode 100644 branches/WOF2-3/hw/mlx4/user/hca/mlx4_debug.h create mode 100644 branches/WOF2-3/hw/mlx4/user/hca/mlx4u.rc create mode 100644 branches/WOF2-3/hw/mlx4/user/hca/qp.c create mode 100644 branches/WOF2-3/hw/mlx4/user/hca/srq.c create mode 100644 branches/WOF2-3/hw/mlx4/user/hca/verbs.c create mode 100644 branches/WOF2-3/hw/mlx4/user/hca/verbs.h create mode 100644 branches/WOF2-3/hw/mlx4/user/hca/wqe.h create mode 100644 branches/WOF2-3/hw/mthca/dirs create mode 100644 branches/WOF2-3/hw/mthca/hca_utils.c create mode 100644 branches/WOF2-3/hw/mthca/hca_utils.h create mode 100644 branches/WOF2-3/hw/mthca/kernel/Makefile create mode 100644 branches/WOF2-3/hw/mthca/kernel/SOURCES create mode 100644 branches/WOF2-3/hw/mthca/kernel/hca.rc create mode 100644 branches/WOF2-3/hw/mthca/kernel/hca_data.c create mode 100644 branches/WOF2-3/hw/mthca/kernel/hca_data.h create mode 100644 branches/WOF2-3/hw/mthca/kernel/hca_debug.h create mode 100644 branches/WOF2-3/hw/mthca/kernel/hca_direct.c create mode 100644 branches/WOF2-3/hw/mthca/kernel/hca_driver.c create mode 100644 branches/WOF2-3/hw/mthca/kernel/hca_driver.h create mode 100644 branches/WOF2-3/hw/mthca/kernel/hca_mcast.c create mode 100644 branches/WOF2-3/hw/mthca/kernel/hca_memory.c create mode 100644 branches/WOF2-3/hw/mthca/kernel/hca_pci.c create mode 100644 branches/WOF2-3/hw/mthca/kernel/hca_pci.h create mode 100644 branches/WOF2-3/hw/mthca/kernel/hca_pnp.c create mode 100644 branches/WOF2-3/hw/mthca/kernel/hca_pnp.h create mode 100644 branches/WOF2-3/hw/mthca/kernel/hca_verbs.c create mode 100644 branches/WOF2-3/hw/mthca/kernel/ib_cache.h create mode 100644 branches/WOF2-3/hw/mthca/kernel/ib_mad.h create mode 100644 branches/WOF2-3/hw/mthca/kernel/ib_pack.h create mode 100644 branches/WOF2-3/hw/mthca/kernel/ib_smi.h create mode 100644 branches/WOF2-3/hw/mthca/kernel/ib_verbs.h create mode 100644 branches/WOF2-3/hw/mthca/kernel/makefile.inc create mode 100644 branches/WOF2-3/hw/mthca/kernel/mt_atomic.h create mode 100644 branches/WOF2-3/hw/mthca/kernel/mt_bitmap.h create mode 100644 branches/WOF2-3/hw/mthca/kernel/mt_cache.c create mode 100644 branches/WOF2-3/hw/mthca/kernel/mt_device.c create mode 100644 branches/WOF2-3/hw/mthca/kernel/mt_l2w.c create mode 100644 branches/WOF2-3/hw/mthca/kernel/mt_l2w.h create mode 100644 branches/WOF2-3/hw/mthca/kernel/mt_list.h create mode 100644 branches/WOF2-3/hw/mthca/kernel/mt_memory.c create mode 100644 branches/WOF2-3/hw/mthca/kernel/mt_memory.h create mode 100644 branches/WOF2-3/hw/mthca/kernel/mt_pa_cash.c create mode 100644 branches/WOF2-3/hw/mthca/kernel/mt_pa_cash.h create mode 100644 branches/WOF2-3/hw/mthca/kernel/mt_packer.c create mode 100644 branches/WOF2-3/hw/mthca/kernel/mt_pci.h create mode 100644 branches/WOF2-3/hw/mthca/kernel/mt_pcipool.h create mode 100644 branches/WOF2-3/hw/mthca/kernel/mt_reset_tavor.c create mode 100644 branches/WOF2-3/hw/mthca/kernel/mt_spinlock.h create mode 100644 branches/WOF2-3/hw/mthca/kernel/mt_sync.h create mode 100644 branches/WOF2-3/hw/mthca/kernel/mt_types.h create mode 100644 branches/WOF2-3/hw/mthca/kernel/mt_ud_header.c create mode 100644 branches/WOF2-3/hw/mthca/kernel/mt_uverbs.c create mode 100644 branches/WOF2-3/hw/mthca/kernel/mt_verbs.c create mode 100644 branches/WOF2-3/hw/mthca/kernel/mthca.cdf create mode 100644 branches/WOF2-3/hw/mthca/kernel/mthca.h create mode 100644 branches/WOF2-3/hw/mthca/kernel/mthca.inx create mode 100644 branches/WOF2-3/hw/mthca/kernel/mthca32.cdf create mode 100644 branches/WOF2-3/hw/mthca/kernel/mthca_allocator.c create mode 100644 branches/WOF2-3/hw/mthca/kernel/mthca_av.c create mode 100644 branches/WOF2-3/hw/mthca/kernel/mthca_catas.c create mode 100644 branches/WOF2-3/hw/mthca/kernel/mthca_cmd.c create mode 100644 branches/WOF2-3/hw/mthca/kernel/mthca_cmd.h create mode 100644 branches/WOF2-3/hw/mthca/kernel/mthca_config_reg.h create mode 100644 branches/WOF2-3/hw/mthca/kernel/mthca_cq.c create mode 100644 branches/WOF2-3/hw/mthca/kernel/mthca_dev.h create mode 100644 branches/WOF2-3/hw/mthca/kernel/mthca_doorbell.h create mode 100644 branches/WOF2-3/hw/mthca/kernel/mthca_eq.c create mode 100644 branches/WOF2-3/hw/mthca/kernel/mthca_log.c create mode 100644 branches/WOF2-3/hw/mthca/kernel/mthca_log.mc create mode 100644 branches/WOF2-3/hw/mthca/kernel/mthca_mad.c create mode 100644 branches/WOF2-3/hw/mthca/kernel/mthca_main.c create mode 100644 branches/WOF2-3/hw/mthca/kernel/mthca_mcg.c create mode 100644 branches/WOF2-3/hw/mthca/kernel/mthca_memfree.c create mode 100644 branches/WOF2-3/hw/mthca/kernel/mthca_memfree.h create mode 100644 branches/WOF2-3/hw/mthca/kernel/mthca_mr.c create mode 100644 branches/WOF2-3/hw/mthca/kernel/mthca_pd.c create mode 100644 branches/WOF2-3/hw/mthca/kernel/mthca_profile.c create mode 100644 branches/WOF2-3/hw/mthca/kernel/mthca_profile.h create mode 100644 branches/WOF2-3/hw/mthca/kernel/mthca_provider.c create mode 100644 branches/WOF2-3/hw/mthca/kernel/mthca_provider.h create mode 100644 branches/WOF2-3/hw/mthca/kernel/mthca_qp.c create mode 100644 branches/WOF2-3/hw/mthca/kernel/mthca_srq.c create mode 100644 branches/WOF2-3/hw/mthca/kernel/mthca_uar.c create mode 100644 branches/WOF2-3/hw/mthca/mt_utils.c create mode 100644 branches/WOF2-3/hw/mthca/mt_utils.h create mode 100644 branches/WOF2-3/hw/mthca/mthca_wqe.h create mode 100644 branches/WOF2-3/hw/mthca/mx_abi.h create mode 100644 branches/WOF2-3/hw/mthca/user/Makefile create mode 100644 branches/WOF2-3/hw/mthca/user/SOURCES create mode 100644 branches/WOF2-3/hw/mthca/user/arch.h create mode 100644 branches/WOF2-3/hw/mthca/user/mlnx_ual_av.c create mode 100644 branches/WOF2-3/hw/mthca/user/mlnx_ual_ca.c create mode 100644 branches/WOF2-3/hw/mthca/user/mlnx_ual_cq.c create mode 100644 branches/WOF2-3/hw/mthca/user/mlnx_ual_data.h create mode 100644 branches/WOF2-3/hw/mthca/user/mlnx_ual_main.c create mode 100644 branches/WOF2-3/hw/mthca/user/mlnx_ual_main.h create mode 100644 branches/WOF2-3/hw/mthca/user/mlnx_ual_mcast.c create mode 100644 branches/WOF2-3/hw/mthca/user/mlnx_ual_mrw.c create mode 100644 branches/WOF2-3/hw/mthca/user/mlnx_ual_osbypass.c create mode 100644 branches/WOF2-3/hw/mthca/user/mlnx_ual_pd.c create mode 100644 branches/WOF2-3/hw/mthca/user/mlnx_ual_qp.c create mode 100644 branches/WOF2-3/hw/mthca/user/mlnx_ual_srq.c create mode 100644 branches/WOF2-3/hw/mthca/user/mlnx_uvp.c create mode 100644 branches/WOF2-3/hw/mthca/user/mlnx_uvp.def create mode 100644 branches/WOF2-3/hw/mthca/user/mlnx_uvp.h create mode 100644 branches/WOF2-3/hw/mthca/user/mlnx_uvp.rc create mode 100644 branches/WOF2-3/hw/mthca/user/mlnx_uvp_ah.c create mode 100644 branches/WOF2-3/hw/mthca/user/mlnx_uvp_cq.c create mode 100644 branches/WOF2-3/hw/mthca/user/mlnx_uvp_debug.c create mode 100644 branches/WOF2-3/hw/mthca/user/mlnx_uvp_debug.h create mode 100644 branches/WOF2-3/hw/mthca/user/mlnx_uvp_doorbell.h create mode 100644 branches/WOF2-3/hw/mthca/user/mlnx_uvp_memfree.c create mode 100644 branches/WOF2-3/hw/mthca/user/mlnx_uvp_qp.c create mode 100644 branches/WOF2-3/hw/mthca/user/mlnx_uvp_srq.c create mode 100644 branches/WOF2-3/hw/mthca/user/mlnx_uvp_verbs.c create mode 100644 branches/WOF2-3/hw/mthca/user/mlnx_uvp_verbs.h create mode 100644 branches/WOF2-3/hw/mthca/user/mt_l2w.h create mode 100644 branches/WOF2-3/hw/mthca/user/opcode.h create mode 100644 branches/WOF2-3/inc/complib/cl_async_proc.h create mode 100644 branches/WOF2-3/inc/complib/cl_atomic.h create mode 100644 branches/WOF2-3/inc/complib/cl_byteswap.h create mode 100644 branches/WOF2-3/inc/complib/cl_comppool.h create mode 100644 branches/WOF2-3/inc/complib/cl_debug.h create mode 100644 branches/WOF2-3/inc/complib/cl_event.h create mode 100644 branches/WOF2-3/inc/complib/cl_fleximap.h create mode 100644 branches/WOF2-3/inc/complib/cl_ioctl.h create mode 100644 branches/WOF2-3/inc/complib/cl_irqlock.h create mode 100644 branches/WOF2-3/inc/complib/cl_list.h create mode 100644 branches/WOF2-3/inc/complib/cl_log.h create mode 100644 branches/WOF2-3/inc/complib/cl_map.h create mode 100644 branches/WOF2-3/inc/complib/cl_math.h create mode 100644 branches/WOF2-3/inc/complib/cl_memory.h create mode 100644 branches/WOF2-3/inc/complib/cl_mutex.h create mode 100644 branches/WOF2-3/inc/complib/cl_nodenamemap.h create mode 100644 branches/WOF2-3/inc/complib/cl_obj.h create mode 100644 branches/WOF2-3/inc/complib/cl_passivelock.h create mode 100644 branches/WOF2-3/inc/complib/cl_perf.h create mode 100644 branches/WOF2-3/inc/complib/cl_pool.h create mode 100644 branches/WOF2-3/inc/complib/cl_ptr_vector.h create mode 100644 branches/WOF2-3/inc/complib/cl_qcomppool.h create mode 100644 branches/WOF2-3/inc/complib/cl_qlist.h create mode 100644 branches/WOF2-3/inc/complib/cl_qlockpool.h create mode 100644 branches/WOF2-3/inc/complib/cl_qmap.h create mode 100644 branches/WOF2-3/inc/complib/cl_qpool.h create mode 100644 branches/WOF2-3/inc/complib/cl_rbmap.h create mode 100644 branches/WOF2-3/inc/complib/cl_reqmgr.h create mode 100644 branches/WOF2-3/inc/complib/cl_spinlock.h create mode 100644 branches/WOF2-3/inc/complib/cl_syscallback.h create mode 100644 branches/WOF2-3/inc/complib/cl_thread.h create mode 100644 branches/WOF2-3/inc/complib/cl_threadpool.h create mode 100644 branches/WOF2-3/inc/complib/cl_timer.h create mode 100644 branches/WOF2-3/inc/complib/cl_types.h create mode 100644 branches/WOF2-3/inc/complib/cl_vector.h create mode 100644 branches/WOF2-3/inc/complib/cl_waitobj.h create mode 100644 branches/WOF2-3/inc/complib/comp_lib.h create mode 100644 branches/WOF2-3/inc/iba/ib_al.h create mode 100644 branches/WOF2-3/inc/iba/ib_al_ioctl.h create mode 100644 branches/WOF2-3/inc/iba/ib_at_ioctl.h create mode 100644 branches/WOF2-3/inc/iba/ib_ci.h create mode 100644 branches/WOF2-3/inc/iba/ib_types.h create mode 100644 branches/WOF2-3/inc/kernel/complib/cl_atomic_osd.h create mode 100644 branches/WOF2-3/inc/kernel/complib/cl_bus_ifc.h create mode 100644 branches/WOF2-3/inc/kernel/complib/cl_byteswap_osd.h create mode 100644 branches/WOF2-3/inc/kernel/complib/cl_debug_osd.h create mode 100644 branches/WOF2-3/inc/kernel/complib/cl_event_osd.h create mode 100644 branches/WOF2-3/inc/kernel/complib/cl_init.h create mode 100644 branches/WOF2-3/inc/kernel/complib/cl_ioctl_osd.h create mode 100644 branches/WOF2-3/inc/kernel/complib/cl_irqlock_osd.h create mode 100644 branches/WOF2-3/inc/kernel/complib/cl_memory_osd.h create mode 100644 branches/WOF2-3/inc/kernel/complib/cl_mutex_osd.h create mode 100644 branches/WOF2-3/inc/kernel/complib/cl_packoff.h create mode 100644 branches/WOF2-3/inc/kernel/complib/cl_packon.h create mode 100644 branches/WOF2-3/inc/kernel/complib/cl_pnp_po.h create mode 100644 branches/WOF2-3/inc/kernel/complib/cl_spinlock_osd.h create mode 100644 branches/WOF2-3/inc/kernel/complib/cl_syscallback_osd.h create mode 100644 branches/WOF2-3/inc/kernel/complib/cl_thread_osd.h create mode 100644 branches/WOF2-3/inc/kernel/complib/cl_timer_osd.h create mode 100644 branches/WOF2-3/inc/kernel/complib/cl_types_osd.h create mode 100644 branches/WOF2-3/inc/kernel/complib/cl_waitobj_osd.h create mode 100644 branches/WOF2-3/inc/kernel/iba/ib_al_ifc.h create mode 100644 branches/WOF2-3/inc/kernel/iba/ib_ci_ifc.h create mode 100644 branches/WOF2-3/inc/kernel/iba/ib_cm_ifc.h create mode 100644 branches/WOF2-3/inc/kernel/iba/ib_rdma_cm.h create mode 100644 branches/WOF2-3/inc/kernel/iba/ioc_ifc.h create mode 100644 branches/WOF2-3/inc/kernel/iba/iou_ifc.h create mode 100644 branches/WOF2-3/inc/kernel/iba/ipoib_ifc.h create mode 100644 branches/WOF2-3/inc/kernel/index_list.h create mode 100644 branches/WOF2-3/inc/kernel/ip_packet.h create mode 100644 branches/WOF2-3/inc/kernel/rdma/verbs.h create mode 100644 branches/WOF2-3/inc/kernel/shutter.h create mode 100644 branches/WOF2-3/inc/kernel/work_queue.h create mode 100644 branches/WOF2-3/inc/mod_ver.def create mode 100644 branches/WOF2-3/inc/mthca/mthca_vc.h create mode 100644 branches/WOF2-3/inc/oib_ver.h create mode 100644 branches/WOF2-3/inc/openib.def create mode 100644 branches/WOF2-3/inc/user/comp_channel.h create mode 100644 branches/WOF2-3/inc/user/complib/cl_atomic_osd.h create mode 100644 branches/WOF2-3/inc/user/complib/cl_byteswap_osd.h create mode 100644 branches/WOF2-3/inc/user/complib/cl_debug_osd.h create mode 100644 branches/WOF2-3/inc/user/complib/cl_event_osd.h create mode 100644 branches/WOF2-3/inc/user/complib/cl_ioctl_osd.h create mode 100644 branches/WOF2-3/inc/user/complib/cl_memory_osd.h create mode 100644 branches/WOF2-3/inc/user/complib/cl_mutex_osd.h create mode 100644 branches/WOF2-3/inc/user/complib/cl_packoff.h create mode 100644 branches/WOF2-3/inc/user/complib/cl_packon.h create mode 100644 branches/WOF2-3/inc/user/complib/cl_spinlock_osd.h create mode 100644 branches/WOF2-3/inc/user/complib/cl_syscallback_osd.h create mode 100644 branches/WOF2-3/inc/user/complib/cl_thread_osd.h create mode 100644 branches/WOF2-3/inc/user/complib/cl_timer_osd.h create mode 100644 branches/WOF2-3/inc/user/complib/cl_types_osd.h create mode 100644 branches/WOF2-3/inc/user/complib/cl_waitobj_osd.h create mode 100644 branches/WOF2-3/inc/user/dlist.h create mode 100644 branches/WOF2-3/inc/user/getopt.h create mode 100644 branches/WOF2-3/inc/user/iba/ib_uvp.h create mode 100644 branches/WOF2-3/inc/user/iba/ibat.h create mode 100644 branches/WOF2-3/inc/user/iba/winmad.h create mode 100644 branches/WOF2-3/inc/user/linux/_errno.h create mode 100644 branches/WOF2-3/inc/user/linux/_string.h create mode 100644 branches/WOF2-3/inc/user/linux/arpa/inet.h create mode 100644 branches/WOF2-3/inc/user/linux/inttypes.h create mode 100644 branches/WOF2-3/inc/user/linux/netdb.h create mode 100644 branches/WOF2-3/inc/user/linux/netinet/in.h create mode 100644 branches/WOF2-3/inc/user/linux/search.h create mode 100644 branches/WOF2-3/inc/user/linux/sys/socket.h create mode 100644 branches/WOF2-3/inc/user/linux/sys/time.h create mode 100644 branches/WOF2-3/inc/user/linux/unistd.h create mode 100644 branches/WOF2-3/inc/user/rdma/winverbs.h create mode 100644 branches/WOF2-3/inc/user/rdma/wvstatus.h create mode 100644 branches/WOF2-3/inc/user/wsd/ibsp_regpath.h create mode 100644 branches/WOF2-3/tests/alts/allocdeallocpd.c create mode 100644 branches/WOF2-3/tests/alts/alts_common.h create mode 100644 branches/WOF2-3/tests/alts/alts_debug.h create mode 100644 branches/WOF2-3/tests/alts/alts_misc.c create mode 100644 branches/WOF2-3/tests/alts/alts_readme.txt create mode 100644 branches/WOF2-3/tests/alts/cmtests.c create mode 100644 branches/WOF2-3/tests/alts/createanddestroycq.c create mode 100644 branches/WOF2-3/tests/alts/createanddestroyqp.c create mode 100644 branches/WOF2-3/tests/alts/createdestroyav.c create mode 100644 branches/WOF2-3/tests/alts/creatememwindow.c create mode 100644 branches/WOF2-3/tests/alts/dirs create mode 100644 branches/WOF2-3/tests/alts/ibquery.c create mode 100644 branches/WOF2-3/tests/alts/kernel/SOURCES create mode 100644 branches/WOF2-3/tests/alts/kernel/alts.inf create mode 100644 branches/WOF2-3/tests/alts/kernel/alts.rc create mode 100644 branches/WOF2-3/tests/alts/kernel/alts_driver.c create mode 100644 branches/WOF2-3/tests/alts/kernel/alts_driver.h create mode 100644 branches/WOF2-3/tests/alts/kernel/makefile create mode 100644 branches/WOF2-3/tests/alts/madtests.c create mode 100644 branches/WOF2-3/tests/alts/multisendrecv.c create mode 100644 branches/WOF2-3/tests/alts/openclose.c create mode 100644 branches/WOF2-3/tests/alts/querycaattr.c create mode 100644 branches/WOF2-3/tests/alts/registermemregion.c create mode 100644 branches/WOF2-3/tests/alts/registerpnp.c create mode 100644 branches/WOF2-3/tests/alts/smatests.c create mode 100644 branches/WOF2-3/tests/alts/user/SOURCES create mode 100644 branches/WOF2-3/tests/alts/user/alts_main.c create mode 100644 branches/WOF2-3/tests/alts/user/makefile create mode 100644 branches/WOF2-3/tests/cmtest/dirs create mode 100644 branches/WOF2-3/tests/cmtest/user/SOURCES create mode 100644 branches/WOF2-3/tests/cmtest/user/cmtest.rc create mode 100644 branches/WOF2-3/tests/cmtest/user/cmtest_main.c create mode 100644 branches/WOF2-3/tests/cmtest/user/makefile create mode 100644 branches/WOF2-3/tests/dirs create mode 100644 branches/WOF2-3/tests/ibat/dirs create mode 100644 branches/WOF2-3/tests/ibat/user/PrintIp.c create mode 100644 branches/WOF2-3/tests/ibat/user/SOURCES create mode 100644 branches/WOF2-3/tests/ibat/user/makefile create mode 100644 branches/WOF2-3/tests/limits/dirs create mode 100644 branches/WOF2-3/tests/limits/user/SOURCES create mode 100644 branches/WOF2-3/tests/limits/user/limits_main.c create mode 100644 branches/WOF2-3/tests/limits/user/makefile create mode 100644 branches/WOF2-3/tests/perftest/dirs create mode 100644 branches/WOF2-3/tests/perftest/perftest.c create mode 100644 branches/WOF2-3/tests/perftest/perftest.h create mode 100644 branches/WOF2-3/tests/perftest/rdma_bw/SOURCES create mode 100644 branches/WOF2-3/tests/perftest/rdma_bw/makefile create mode 100644 branches/WOF2-3/tests/perftest/rdma_bw/rdma_bw.c create mode 100644 branches/WOF2-3/tests/perftest/rdma_bw/rdma_bw.rc create mode 100644 branches/WOF2-3/tests/perftest/rdma_lat/SOURCES create mode 100644 branches/WOF2-3/tests/perftest/rdma_lat/makefile create mode 100644 branches/WOF2-3/tests/perftest/rdma_lat/rdma_lat.c create mode 100644 branches/WOF2-3/tests/perftest/rdma_lat/rdma_lat.rc create mode 100644 branches/WOF2-3/tests/perftest/read_bw/SOURCES create mode 100644 branches/WOF2-3/tests/perftest/read_bw/makefile create mode 100644 branches/WOF2-3/tests/perftest/read_bw/read_bw.c create mode 100644 branches/WOF2-3/tests/perftest/read_bw/read_bw.rc create mode 100644 branches/WOF2-3/tests/perftest/read_lat/SOURCES create mode 100644 branches/WOF2-3/tests/perftest/read_lat/makefile create mode 100644 branches/WOF2-3/tests/perftest/read_lat/read_lat.c create mode 100644 branches/WOF2-3/tests/perftest/read_lat/read_lat.rc create mode 100644 branches/WOF2-3/tests/perftest/send_bw/SOURCES create mode 100644 branches/WOF2-3/tests/perftest/send_bw/makefile create mode 100644 branches/WOF2-3/tests/perftest/send_bw/send_bw.c create mode 100644 branches/WOF2-3/tests/perftest/send_bw/send_bw.rc create mode 100644 branches/WOF2-3/tests/perftest/send_lat/SOURCES create mode 100644 branches/WOF2-3/tests/perftest/send_lat/makefile create mode 100644 branches/WOF2-3/tests/perftest/send_lat/send_lat.c create mode 100644 branches/WOF2-3/tests/perftest/send_lat/send_lat.rc create mode 100644 branches/WOF2-3/tests/perftest/write_bw/SOURCES create mode 100644 branches/WOF2-3/tests/perftest/write_bw/makefile create mode 100644 branches/WOF2-3/tests/perftest/write_bw/write_bw.c create mode 100644 branches/WOF2-3/tests/perftest/write_bw/write_bw.rc create mode 100644 branches/WOF2-3/tests/perftest/write_bw_postlist/SOURCES create mode 100644 branches/WOF2-3/tests/perftest/write_bw_postlist/makefile create mode 100644 branches/WOF2-3/tests/perftest/write_bw_postlist/write_bw_postlist.c create mode 100644 branches/WOF2-3/tests/perftest/write_bw_postlist/write_bw_postlist.rc create mode 100644 branches/WOF2-3/tests/perftest/write_lat/SOURCES create mode 100644 branches/WOF2-3/tests/perftest/write_lat/makefile create mode 100644 branches/WOF2-3/tests/perftest/write_lat/write_lat.c create mode 100644 branches/WOF2-3/tests/perftest/write_lat/write_lat.rc create mode 100644 branches/WOF2-3/tests/wherebu/dirs create mode 100644 branches/WOF2-3/tests/wherebu/user/SOURCES create mode 100644 branches/WOF2-3/tests/wherebu/user/makefile create mode 100644 branches/WOF2-3/tests/wherebu/user/wherebu.cpp create mode 100644 branches/WOF2-3/tests/wsd/dirs create mode 100644 branches/WOF2-3/tests/wsd/user/contest/contest.c create mode 100644 branches/WOF2-3/tests/wsd/user/contest/contest.h create mode 100644 branches/WOF2-3/tests/wsd/user/dirs create mode 100644 branches/WOF2-3/tests/wsd/user/test1/test1.c create mode 100644 branches/WOF2-3/tests/wsd/user/test2/ibwrap.c create mode 100644 branches/WOF2-3/tests/wsd/user/test2/ibwrap.h create mode 100644 branches/WOF2-3/tests/wsd/user/test2/test2.c create mode 100644 branches/WOF2-3/tests/wsd/user/test3/ibwrap.c create mode 100644 branches/WOF2-3/tests/wsd/user/test3/ibwrap.h create mode 100644 branches/WOF2-3/tests/wsd/user/test3/test3.c create mode 100644 branches/WOF2-3/tests/wsd/user/ttcp/SOURCES create mode 100644 branches/WOF2-3/tests/wsd/user/ttcp/makefile create mode 100644 branches/WOF2-3/tests/wsd/user/ttcp/ttcp.c create mode 100644 branches/WOF2-3/tools/dirs create mode 100644 branches/WOF2-3/tools/infiniband-diags/dirs create mode 100644 branches/WOF2-3/tools/infiniband-diags/include/grouping.h create mode 100644 branches/WOF2-3/tools/infiniband-diags/include/ibdiag_common.h create mode 100644 branches/WOF2-3/tools/infiniband-diags/include/ibnetdiscover.h create mode 100644 branches/WOF2-3/tools/infiniband-diags/include/windows/config.h create mode 100644 branches/WOF2-3/tools/infiniband-diags/include/windows/ibdiag_version.h create mode 100644 branches/WOF2-3/tools/infiniband-diags/patches/ibping-cdecl.diff create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/dirs create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/grouping.c create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/ibaddr.c create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/ibaddr/SOURCES create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/ibaddr/ibaddr.rc create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/ibaddr/makefile create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/ibdiag_common.c create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/ibdiag_windows.c create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/iblinkinfo.c create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/iblinkinfo/SOURCES create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/iblinkinfo/iblinkinfo.rc create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/iblinkinfo/makefile create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/ibnetdiscover.c create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/ibnetdiscover/SOURCES create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/ibnetdiscover/ibnetdiscover.rc create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/ibnetdiscover/makefile create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/ibping.c create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/ibping/SOURCES create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/ibping/ibping.rc create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/ibping/makefile create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/ibportstate.c create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/ibportstate/SOURCES create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/ibportstate/ibportstate.rc create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/ibportstate/makefile create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/ibqueryerrors.c create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/ibqueryerrors/SOURCES create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/ibqueryerrors/ibqueryerrors.rc create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/ibqueryerrors/makefile create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/ibroute.c create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/ibroute/SOURCES create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/ibroute/ibroute.rc create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/ibroute/makefile create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/ibsendtrap.c create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/ibsendtrap/SOURCES create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/ibsendtrap/ibsendtrap.rc create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/ibsendtrap/makefile create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/ibstat.c create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/ibstat/SOURCES create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/ibstat/ibstat.rc create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/ibstat/makefile create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/ibsysstat.c create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/ibsysstat/SOURCES create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/ibsysstat/ibsysstat.rc create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/ibsysstat/makefile create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/ibtracert.c create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/ibtracert/SOURCES create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/ibtracert/ibtracert.rc create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/ibtracert/makefile create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/mcm_rereg_test.c create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/mcm_rereg_test/SOURCES create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/mcm_rereg_test/makefile create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/mcm_rereg_test/mcm_rereg_test.rc create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/perfquery.c create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/perfquery/SOURCES create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/perfquery/makefile create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/perfquery/perfquery.rc create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/saquery.c create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/saquery/SOURCES create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/saquery/makefile create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/saquery/saquery.rc create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/sminfo.c create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/sminfo/SOURCES create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/sminfo/makefile create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/sminfo/sminfo.rc create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/smpdump.c create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/smpdump/SOURCES create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/smpdump/makefile create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/smpdump/smpdump.rc create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/smpquery.c create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/smpquery/SOURCES create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/smpquery/makefile create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/smpquery/smpquery.rc create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/vendstat.c create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/vendstat/SOURCES create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/vendstat/makefile create mode 100644 branches/WOF2-3/tools/infiniband-diags/src/vendstat/vendstat.rc create mode 100644 branches/WOF2-3/tools/ndinstall/dirs create mode 100644 branches/WOF2-3/tools/ndinstall/user/SOURCES create mode 100644 branches/WOF2-3/tools/ndinstall/user/installsp.c create mode 100644 branches/WOF2-3/tools/ndinstall/user/installsp.rc create mode 100644 branches/WOF2-3/tools/ndinstall/user/makefile create mode 100644 branches/WOF2-3/tools/nsc/SOURCES create mode 100644 branches/WOF2-3/tools/nsc/makefile create mode 100644 branches/WOF2-3/tools/nsc/nsc.c create mode 100644 branches/WOF2-3/tools/nsc/nsc.rc create mode 100644 branches/WOF2-3/tools/part_man/dirs create mode 100644 branches/WOF2-3/tools/part_man/user/SOURCES create mode 100644 branches/WOF2-3/tools/part_man/user/makefile create mode 100644 branches/WOF2-3/tools/part_man/user/part_man.c create mode 100644 branches/WOF2-3/tools/part_man/user/part_man.rc create mode 100644 branches/WOF2-3/tools/perftests/dirs create mode 100644 branches/WOF2-3/tools/perftests/user/README create mode 100644 branches/WOF2-3/tools/perftests/user/TODO create mode 100644 branches/WOF2-3/tools/perftests/user/clock_test.c create mode 100644 branches/WOF2-3/tools/perftests/user/dirs create mode 100644 branches/WOF2-3/tools/perftests/user/get_clock.c create mode 100644 branches/WOF2-3/tools/perftests/user/get_clock.h create mode 100644 branches/WOF2-3/tools/perftests/user/getopt.c create mode 100644 branches/WOF2-3/tools/perftests/user/getopt.h create mode 100644 branches/WOF2-3/tools/perftests/user/perf_defs.h create mode 100644 branches/WOF2-3/tools/perftests/user/perf_utils.c create mode 100644 branches/WOF2-3/tools/perftests/user/read_bw/SOURCES create mode 100644 branches/WOF2-3/tools/perftests/user/read_bw/makefile create mode 100644 branches/WOF2-3/tools/perftests/user/read_bw/read_bw.c create mode 100644 branches/WOF2-3/tools/perftests/user/read_bw/read_bw.rc create mode 100644 branches/WOF2-3/tools/perftests/user/read_lat/SOURCES create mode 100644 branches/WOF2-3/tools/perftests/user/read_lat/makefile create mode 100644 branches/WOF2-3/tools/perftests/user/read_lat/read_lat.c create mode 100644 branches/WOF2-3/tools/perftests/user/read_lat/read_lat.rc create mode 100644 branches/WOF2-3/tools/perftests/user/send_bw/SOURCES create mode 100644 branches/WOF2-3/tools/perftests/user/send_bw/makefile create mode 100644 branches/WOF2-3/tools/perftests/user/send_bw/send_bw.c create mode 100644 branches/WOF2-3/tools/perftests/user/send_bw/send_bw.rc create mode 100644 branches/WOF2-3/tools/perftests/user/send_lat/SOURCES create mode 100644 branches/WOF2-3/tools/perftests/user/send_lat/makefile create mode 100644 branches/WOF2-3/tools/perftests/user/send_lat/send_lat.c create mode 100644 branches/WOF2-3/tools/perftests/user/send_lat/send_lat.rc create mode 100644 branches/WOF2-3/tools/perftests/user/write_bw/SOURCES create mode 100644 branches/WOF2-3/tools/perftests/user/write_bw/makefile create mode 100644 branches/WOF2-3/tools/perftests/user/write_bw/write_bw.c create mode 100644 branches/WOF2-3/tools/perftests/user/write_bw/write_bw.rc create mode 100644 branches/WOF2-3/tools/perftests/user/write_lat/SOURCES create mode 100644 branches/WOF2-3/tools/perftests/user/write_lat/makefile create mode 100644 branches/WOF2-3/tools/perftests/user/write_lat/write_lat.c create mode 100644 branches/WOF2-3/tools/perftests/user/write_lat/write_lat.rc create mode 100644 branches/WOF2-3/tools/qlgcvnic_config/SOURCES create mode 100644 branches/WOF2-3/tools/qlgcvnic_config/makefile create mode 100644 branches/WOF2-3/tools/qlgcvnic_config/qlgcvnic_config.rc create mode 100644 branches/WOF2-3/tools/qlgcvnic_config/vnic_child_config.c create mode 100644 branches/WOF2-3/tools/vstat/dirs create mode 100644 branches/WOF2-3/tools/vstat/user/SOURCES create mode 100644 branches/WOF2-3/tools/vstat/user/makefile create mode 100644 branches/WOF2-3/tools/vstat/user/vstat.rc create mode 100644 branches/WOF2-3/tools/vstat/user/vstat_main.c create mode 100644 branches/WOF2-3/tools/wsdinstall/dirs create mode 100644 branches/WOF2-3/tools/wsdinstall/user/InstallSP.sln create mode 100644 branches/WOF2-3/tools/wsdinstall/user/SOURCES create mode 100644 branches/WOF2-3/tools/wsdinstall/user/installsp.c create mode 100644 branches/WOF2-3/tools/wsdinstall/user/installsp.exe.manifest create mode 100644 branches/WOF2-3/tools/wsdinstall/user/installsp.rc create mode 100644 branches/WOF2-3/tools/wsdinstall/user/makefile create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_adapter_util.h create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_cno_create.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_cno_free.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_cno_modify_agent.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_cno_query.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_cno_util.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_cno_util.h create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_cno_wait.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_cookie.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_cookie.h create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_cr_accept.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_cr_callback.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_cr_handoff.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_cr_query.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_cr_reject.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_cr_util.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_cr_util.h create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_debug.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_connect.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_create.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_disconnect.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_dup_connect.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_free.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_get_status.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_modify.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_post_rdma_read.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_post_rdma_write.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_post_recv.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_post_send.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_query.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_reset.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_util.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_util.h create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_clear_unwaitable.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_connection_callb.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_cq_async_error_callb.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_create.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_dequeue.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_disable.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_dto_callb.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_enable.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_free.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_modify_cno.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_post_se.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_qp_async_error_callb.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_query.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_resize.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_set_unwaitable.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_un_async_error_callb.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_util.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_util.h create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_wait.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_get_consumer_context.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_get_handle_type.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_hash.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_hash.h create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_hca_util.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_hca_util.h create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_ia_close.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_ia_open.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_ia_query.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_ia_util.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_ia_util.h create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_init.h create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_llist.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_lmr_create.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_lmr_free.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_lmr_query.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_lmr_util.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_lmr_util.h create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_mr_util.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_mr_util.h create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_provider.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_provider.h create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_psp_create.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_psp_create_any.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_psp_free.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_psp_query.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_pz_create.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_pz_free.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_pz_query.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_pz_util.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_pz_util.h create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_ring_buffer_util.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_ring_buffer_util.h create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_rmr_bind.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_rmr_create.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_rmr_free.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_rmr_query.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_rmr_util.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_rmr_util.h create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_rsp_create.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_rsp_free.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_rsp_query.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_set_consumer_context.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_sp_util.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/common/dapl_sp_util.h create mode 100644 branches/WOF2-3/ulp/dapl/dapl/dirs create mode 100644 branches/WOF2-3/ulp/dapl/dapl/ibal/dapl_ibal_cm.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/ibal/dapl_ibal_dto.h create mode 100644 branches/WOF2-3/ulp/dapl/dapl/ibal/dapl_ibal_kmod.h create mode 100644 branches/WOF2-3/ulp/dapl/dapl/ibal/dapl_ibal_mrdb.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/ibal/dapl_ibal_mrdb.h create mode 100644 branches/WOF2-3/ulp/dapl/dapl/ibal/dapl_ibal_qp.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/ibal/dapl_ibal_util.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/ibal/dapl_ibal_util.h create mode 100644 branches/WOF2-3/ulp/dapl/dapl/include/dapl.h create mode 100644 branches/WOF2-3/ulp/dapl/dapl/include/dapl_debug.h create mode 100644 branches/WOF2-3/ulp/dapl/dapl/include/dapl_ipoib_names.h create mode 100644 branches/WOF2-3/ulp/dapl/dapl/include/dapl_vendor.h create mode 100644 branches/WOF2-3/ulp/dapl/dapl/udapl/Makefile.cygwin create mode 100644 branches/WOF2-3/ulp/dapl/dapl/udapl/Makefile.org create mode 100644 branches/WOF2-3/ulp/dapl/dapl/udapl/Makefile.orig create mode 100644 branches/WOF2-3/ulp/dapl/dapl/udapl/SOURCES create mode 100644 branches/WOF2-3/ulp/dapl/dapl/udapl/dapl_init.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/udapl/dapl_name_service.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/udapl/dapl_name_service.h create mode 100644 branches/WOF2-3/ulp/dapl/dapl/udapl/dapl_timer_util.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/udapl/dapl_timer_util.h create mode 100644 branches/WOF2-3/ulp/dapl/dapl/udapl/linux/dapl_osd.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/udapl/linux/dapl_osd.h create mode 100644 branches/WOF2-3/ulp/dapl/dapl/udapl/makefile create mode 100644 branches/WOF2-3/ulp/dapl/dapl/udapl/makefile.wnd create mode 100644 branches/WOF2-3/ulp/dapl/dapl/udapl/udapl.rc create mode 100644 branches/WOF2-3/ulp/dapl/dapl/udapl/udapl_exports.src create mode 100644 branches/WOF2-3/ulp/dapl/dapl/udapl/udapl_sources.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/udapl/windows/dapl_osd.c create mode 100644 branches/WOF2-3/ulp/dapl/dapl/udapl/windows/dapl_osd.h create mode 100644 branches/WOF2-3/ulp/dapl/dapl/udapl/windows/dapl_win.def create mode 100644 branches/WOF2-3/ulp/dapl/dapl/udapl/windows/dapllib.rc create mode 100644 branches/WOF2-3/ulp/dapl/dat/common/dat_dictionary.c create mode 100644 branches/WOF2-3/ulp/dapl/dat/common/dat_dictionary.h create mode 100644 branches/WOF2-3/ulp/dapl/dat/common/dat_dr.c create mode 100644 branches/WOF2-3/ulp/dapl/dat/common/dat_dr.h create mode 100644 branches/WOF2-3/ulp/dapl/dat/common/dat_init.c create mode 100644 branches/WOF2-3/ulp/dapl/dat/common/dat_init.h create mode 100644 branches/WOF2-3/ulp/dapl/dat/common/dat_sr.c create mode 100644 branches/WOF2-3/ulp/dapl/dat/common/dat_sr.h create mode 100644 branches/WOF2-3/ulp/dapl/dat/common/dat_strerror.c create mode 100644 branches/WOF2-3/ulp/dapl/dat/dirs create mode 100644 branches/WOF2-3/ulp/dapl/dat/include/dat/dat.h create mode 100644 branches/WOF2-3/ulp/dapl/dat/include/dat/dat_error.h create mode 100644 branches/WOF2-3/ulp/dapl/dat/include/dat/dat_platform_specific.h create mode 100644 branches/WOF2-3/ulp/dapl/dat/include/dat/dat_redirection.h create mode 100644 branches/WOF2-3/ulp/dapl/dat/include/dat/dat_registry.h create mode 100644 branches/WOF2-3/ulp/dapl/dat/include/dat/dat_vendor_specific.h create mode 100644 branches/WOF2-3/ulp/dapl/dat/include/dat/kdat.h create mode 100644 branches/WOF2-3/ulp/dapl/dat/include/dat/kdat_config.h create mode 100644 branches/WOF2-3/ulp/dapl/dat/include/dat/kdat_redirection.h create mode 100644 branches/WOF2-3/ulp/dapl/dat/include/dat/kdat_vendor_specific.h create mode 100644 branches/WOF2-3/ulp/dapl/dat/include/dat/udat.h create mode 100644 branches/WOF2-3/ulp/dapl/dat/include/dat/udat_config.h create mode 100644 branches/WOF2-3/ulp/dapl/dat/include/dat/udat_redirection.h create mode 100644 branches/WOF2-3/ulp/dapl/dat/include/dat/udat_vendor_specific.h create mode 100644 branches/WOF2-3/ulp/dapl/dat/kdat/Makefile create mode 100644 branches/WOF2-3/ulp/dapl/dat/kdat/dat_kdapl.c create mode 100644 branches/WOF2-3/ulp/dapl/dat/kdat/dat_module.c create mode 100644 branches/WOF2-3/ulp/dapl/dat/kdat/linux/dat_osd.c create mode 100644 branches/WOF2-3/ulp/dapl/dat/kdat/linux/dat_osd.h create mode 100644 branches/WOF2-3/ulp/dapl/dat/udat/Makefile.cygwin create mode 100644 branches/WOF2-3/ulp/dapl/dat/udat/Makefile.org create mode 100644 branches/WOF2-3/ulp/dapl/dat/udat/Makefile.orig create mode 100644 branches/WOF2-3/ulp/dapl/dat/udat/SOURCES create mode 100644 branches/WOF2-3/ulp/dapl/dat/udat/dat.conf create mode 100644 branches/WOF2-3/ulp/dapl/dat/udat/ibhosts create mode 100644 branches/WOF2-3/ulp/dapl/dat/udat/linux/dat-1.1.spec create mode 100644 branches/WOF2-3/ulp/dapl/dat/udat/linux/dat_osd.c create mode 100644 branches/WOF2-3/ulp/dapl/dat/udat/linux/dat_osd.h create mode 100644 branches/WOF2-3/ulp/dapl/dat/udat/makefile create mode 100644 branches/WOF2-3/ulp/dapl/dat/udat/makefile.wnd create mode 100644 branches/WOF2-3/ulp/dapl/dat/udat/udat.c create mode 100644 branches/WOF2-3/ulp/dapl/dat/udat/udat.rc create mode 100644 branches/WOF2-3/ulp/dapl/dat/udat/udat_exports.src create mode 100644 branches/WOF2-3/ulp/dapl/dat/udat/udat_sources.c create mode 100644 branches/WOF2-3/ulp/dapl/dat/udat/udat_sr_parser.c create mode 100644 branches/WOF2-3/ulp/dapl/dat/udat/udat_sr_parser.h create mode 100644 branches/WOF2-3/ulp/dapl/dat/udat/windows/dat_osd.c create mode 100644 branches/WOF2-3/ulp/dapl/dat/udat/windows/dat_osd.h create mode 100644 branches/WOF2-3/ulp/dapl/dat/udat/windows/dat_osd_sr.h create mode 100644 branches/WOF2-3/ulp/dapl/dat/udat/windows/dat_win.def create mode 100644 branches/WOF2-3/ulp/dapl/dirs create mode 100644 branches/WOF2-3/ulp/dapl/doc/dapl_coding_style.txt create mode 100644 branches/WOF2-3/ulp/dapl/doc/dapl_end_point_design.txt create mode 100644 branches/WOF2-3/ulp/dapl/doc/dapl_environ.txt create mode 100644 branches/WOF2-3/ulp/dapl/doc/dapl_event_design.txt create mode 100644 branches/WOF2-3/ulp/dapl/doc/dapl_memory_management_design.txt create mode 100644 branches/WOF2-3/ulp/dapl/doc/dapl_registry_design.txt create mode 100644 branches/WOF2-3/ulp/dapl/doc/dapl_shared_memory_design.txt create mode 100644 branches/WOF2-3/ulp/dapl/doc/dapl_vendor_specific_changes.txt create mode 100644 branches/WOF2-3/ulp/dapl/doc/dat.conf create mode 100644 branches/WOF2-3/ulp/dapl/doc/dat_environ.txt create mode 100644 branches/WOF2-3/ulp/dapl/doc/ibhosts create mode 100644 branches/WOF2-3/ulp/dapl/doc/mv_dapl_readme.txt create mode 100644 branches/WOF2-3/ulp/dapl/doc/mv_dapl_relnotes.txt create mode 100644 branches/WOF2-3/ulp/dapl/test/dirs create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/.DT_defaults create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/.DT_onetest create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/.DT_perf.csh create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/DaplTest_how_2.txt create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/Makefile.cygwin create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/Makefile.org create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/Makefile.orig create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/SOURCES create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/bw.sh create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/cl.sh create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_bpool.c create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_bpool.h create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_client.c create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_client_info.c create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_client_info.h create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_cnxn.c create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_cnxn.h create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_common.h create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_endian.c create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_fft_cmd.c create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_fft_cmd.h create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_fft_connmgt.c create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_fft_dataxfer.c create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_fft_dataxfer_client.c create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_fft_endpoint.c create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_fft_hwconn.c create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_fft_mem.c create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_fft_pz.c create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_fft_queryinfo.c create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_fft_test.c create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_fft_util.c create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_fft_util.h create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_funcs.h create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_getopt.c create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_getopt.h create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_limit.c create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_limit_cmd.c create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_limit_cmd.h create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_main.c create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_mdep.c create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_mdep.h create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_memlist.c create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_memlist.h create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_netaddr.c create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_params.c create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_params.h create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_performance_client.c create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_performance_cmd.c create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_performance_cmd.h create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_performance_server.c create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_performance_stats.c create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_performance_stats.h create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_performance_test.h create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_performance_util.c create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_proto.h create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_quit_cmd.c create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_quit_cmd.h create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_server.c create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_server_cmd.c create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_server_cmd.h create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_server_info.c create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_server_info.h create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_test_data.c create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_test_data.h create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_test_util.c create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_thread.c create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_transaction_cmd.c create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_transaction_cmd.h create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_transaction_stats.c create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_transaction_stats.h create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_transaction_test.c create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_transaction_test.h create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_transaction_util.c create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_util.c create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_version.h create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapltest.rc create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/lat_block.sh create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/lat_poll.sh create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/lim.sh create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/makefile create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/makefile.wnd create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/quit.sh create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/regress.sh create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dapltest/srv.sh create mode 100644 branches/WOF2-3/ulp/dapl/test/udapl/dirs create mode 100644 branches/WOF2-3/ulp/dapl2/AUTHORS create mode 100644 branches/WOF2-3/ulp/dapl2/COPYING create mode 100644 branches/WOF2-3/ulp/dapl2/ChangeLog create mode 100644 branches/WOF2-3/ulp/dapl2/LICENSE.txt create mode 100644 branches/WOF2-3/ulp/dapl2/LICENSE2.txt create mode 100644 branches/WOF2-3/ulp/dapl2/LICENSE3.txt create mode 100644 branches/WOF2-3/ulp/dapl2/Makefile.am create mode 100644 branches/WOF2-3/ulp/dapl2/README create mode 100644 branches/WOF2-3/ulp/dapl2/README.windows create mode 100644 branches/WOF2-3/ulp/dapl2/autogen.sh create mode 100644 branches/WOF2-3/ulp/dapl2/configure.in create mode 100644 branches/WOF2-3/ulp/dapl2/dapl.spec.in create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_adapter_util.h create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_cno_util.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_cno_util.h create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_cookie.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_cookie.h create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_cr_accept.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_cr_callback.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_cr_handoff.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_cr_query.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_cr_reject.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_cr_util.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_cr_util.h create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_csp.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_debug.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_connect.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_create.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_create_with_srq.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_disconnect.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_dup_connect.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_free.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_get_status.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_modify.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_post_rdma_read.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_post_rdma_read_to_rmr.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_post_rdma_write.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_post_recv.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_post_send.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_post_send_invalidate.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_query.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_recv_query.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_reset.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_set_watermark.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_util.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_util.h create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_evd_connection_callb.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_evd_cq_async_error_callb.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_evd_dequeue.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_evd_dto_callb.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_evd_free.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_evd_post_se.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_evd_qp_async_error_callb.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_evd_resize.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_evd_un_async_error_callb.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_evd_util.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_evd_util.h create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_get_consumer_context.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_get_handle_type.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_hash.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_hash.h create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_hca_util.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_hca_util.h create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ia_close.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ia_ha.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ia_open.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ia_query.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ia_util.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ia_util.h create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_init.h create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_llist.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_lmr_free.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_lmr_query.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_lmr_sync_rdma_read.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_lmr_sync_rdma_write.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_lmr_util.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_lmr_util.h create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_mr_util.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_mr_util.h create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_name_service.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_name_service.h create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_provider.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_provider.h create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_psp_create.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_psp_create_any.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_psp_free.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_psp_query.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_pz_create.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_pz_free.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_pz_query.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_pz_util.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_pz_util.h create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ring_buffer_util.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ring_buffer_util.h create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_rmr_bind.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_rmr_create.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_rmr_free.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_rmr_query.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_rmr_util.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_rmr_util.h create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_rsp_create.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_rsp_free.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_rsp_query.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_set_consumer_context.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_sp_util.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_sp_util.h create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_srq_create.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_srq_free.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_srq_post_recv.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_srq_query.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_srq_resize.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_srq_set_lw.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_srq_util.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_srq_util.h create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_timer_util.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/common/dapl_timer_util.h create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/dapl_common_src.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/dapl_udapl_src.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/dirs create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/ibal/SOURCES create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/ibal/dapl_ibal_cm.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/ibal/dapl_ibal_cq.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/ibal/dapl_ibal_dto.h create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/ibal/dapl_ibal_extensions.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/ibal/dapl_ibal_kmod.h create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/ibal/dapl_ibal_mrdb.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/ibal/dapl_ibal_mrdb.h create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/ibal/dapl_ibal_name_service.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/ibal/dapl_ibal_name_service.h create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/ibal/dapl_ibal_qp.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/ibal/dapl_ibal_util.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/ibal/dapl_ibal_util.h create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/ibal/makefile create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/ibal/udapl.rc create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/ibal/udapl_exports.src create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/include/dapl.h create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/include/dapl_debug.h create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/include/dapl_ipoib_names.h create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/include/dapl_vendor.h create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/openib_cma/README create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/openib_cma/SOURCES create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/openib_cma/cm.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/openib_cma/dapl_ib_util.h create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/openib_cma/device.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/openib_cma/linux/openib_osd.h create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/openib_cma/makefile create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/openib_cma/udapl.rc create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/openib_cma/udapl_ofa_cma_exports.src create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/openib_cma/windows/openib_osd.h create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/openib_common.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/openib_common/cq.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/openib_common/dapl_ib_common.h create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/openib_common/dapl_ib_dto.h create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/openib_common/ib_extensions.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/openib_common/mem.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/openib_common/qp.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/openib_common/util.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/openib_scm/SOURCES create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/openib_scm/cm.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/openib_scm/dapl_ib_util.h create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/openib_scm/device.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/openib_scm/linux/openib_osd.h create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/openib_scm/makefile create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/openib_scm/udapl.rc create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/openib_scm/udapl_ofa_scm_exports.src create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/openib_scm/windows/openib_osd.h create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/openib_ucm/README create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/openib_ucm/SOURCES create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/openib_ucm/cm.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/openib_ucm/dapl_ib_util.h create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/openib_ucm/device.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/openib_ucm/linux/openib_osd.h create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/openib_ucm/makefile create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/openib_ucm/udapl.rc create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/openib_ucm/udapl_ofa_ucm_exports.src create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/openib_ucm/windows/openib_osd.h create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_cno_create.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_cno_free.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_cno_modify_agent.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_cno_query.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_cno_wait.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_evd_clear_unwaitable.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_evd_create.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_evd_disable.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_evd_enable.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_evd_modify_cno.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_evd_query.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_evd_set_unwaitable.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_evd_wait.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_init.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_lmr_create.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/udapl/linux/dapl_osd.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/udapl/linux/dapl_osd.h create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/udapl/windows/dapl_osd.c create mode 100644 branches/WOF2-3/ulp/dapl2/dapl/udapl/windows/dapl_osd.h create mode 100644 branches/WOF2-3/ulp/dapl2/dat/common/dat_api.c create mode 100644 branches/WOF2-3/ulp/dapl2/dat/common/dat_dictionary.c create mode 100644 branches/WOF2-3/ulp/dapl2/dat/common/dat_dictionary.h create mode 100644 branches/WOF2-3/ulp/dapl2/dat/common/dat_dr.c create mode 100644 branches/WOF2-3/ulp/dapl2/dat/common/dat_dr.h create mode 100644 branches/WOF2-3/ulp/dapl2/dat/common/dat_init.c create mode 100644 branches/WOF2-3/ulp/dapl2/dat/common/dat_init.h create mode 100644 branches/WOF2-3/ulp/dapl2/dat/common/dat_sr.c create mode 100644 branches/WOF2-3/ulp/dapl2/dat/common/dat_sr.h create mode 100644 branches/WOF2-3/ulp/dapl2/dat/common/dat_strerror.c create mode 100644 branches/WOF2-3/ulp/dapl2/dat/dirs create mode 100644 branches/WOF2-3/ulp/dapl2/dat/include/dat2/dat.h create mode 100644 branches/WOF2-3/ulp/dapl2/dat/include/dat2/dat_error.h create mode 100644 branches/WOF2-3/ulp/dapl2/dat/include/dat2/dat_ib_extensions.h create mode 100644 branches/WOF2-3/ulp/dapl2/dat/include/dat2/dat_iw_extensions.h create mode 100644 branches/WOF2-3/ulp/dapl2/dat/include/dat2/dat_platform_specific.h create mode 100644 branches/WOF2-3/ulp/dapl2/dat/include/dat2/dat_redirection.h create mode 100644 branches/WOF2-3/ulp/dapl2/dat/include/dat2/dat_registry.h create mode 100644 branches/WOF2-3/ulp/dapl2/dat/include/dat2/dat_vendor_specific.h create mode 100644 branches/WOF2-3/ulp/dapl2/dat/include/dat2/kdat.h create mode 100644 branches/WOF2-3/ulp/dapl2/dat/include/dat2/kdat_config.h create mode 100644 branches/WOF2-3/ulp/dapl2/dat/include/dat2/kdat_redirection.h create mode 100644 branches/WOF2-3/ulp/dapl2/dat/include/dat2/kdat_vendor_specific.h create mode 100644 branches/WOF2-3/ulp/dapl2/dat/include/dat2/udat.h create mode 100644 branches/WOF2-3/ulp/dapl2/dat/include/dat2/udat_config.h create mode 100644 branches/WOF2-3/ulp/dapl2/dat/include/dat2/udat_redirection.h create mode 100644 branches/WOF2-3/ulp/dapl2/dat/include/dat2/udat_vendor_specific.h create mode 100644 branches/WOF2-3/ulp/dapl2/dat/udat/SOURCES create mode 100644 branches/WOF2-3/ulp/dapl2/dat/udat/linux/dat-registry-1.1.spec create mode 100644 branches/WOF2-3/ulp/dapl2/dat/udat/linux/dat_osd.c create mode 100644 branches/WOF2-3/ulp/dapl2/dat/udat/linux/dat_osd.h create mode 100644 branches/WOF2-3/ulp/dapl2/dat/udat/makefile create mode 100644 branches/WOF2-3/ulp/dapl2/dat/udat/udat.c create mode 100644 branches/WOF2-3/ulp/dapl2/dat/udat/udat.rc create mode 100644 branches/WOF2-3/ulp/dapl2/dat/udat/udat_api.c create mode 100644 branches/WOF2-3/ulp/dapl2/dat/udat/udat_exports.src create mode 100644 branches/WOF2-3/ulp/dapl2/dat/udat/udat_sources.c create mode 100644 branches/WOF2-3/ulp/dapl2/dat/udat/udat_sr_parser.c create mode 100644 branches/WOF2-3/ulp/dapl2/dat/udat/udat_sr_parser.h create mode 100644 branches/WOF2-3/ulp/dapl2/dat/udat/windows/dat_osd.c create mode 100644 branches/WOF2-3/ulp/dapl2/dat/udat/windows/dat_osd.h create mode 100644 branches/WOF2-3/ulp/dapl2/dat/udat/windows/dat_osd_sr.h create mode 100644 branches/WOF2-3/ulp/dapl2/dirs create mode 100644 branches/WOF2-3/ulp/dapl2/doc/dapl_coding_style.txt create mode 100644 branches/WOF2-3/ulp/dapl2/doc/dapl_end_point_design.txt create mode 100644 branches/WOF2-3/ulp/dapl2/doc/dapl_environ.txt create mode 100644 branches/WOF2-3/ulp/dapl2/doc/dapl_event_design.txt create mode 100644 branches/WOF2-3/ulp/dapl2/doc/dapl_ibm_api_variations.txt create mode 100644 branches/WOF2-3/ulp/dapl2/doc/dapl_memory_management_design.txt create mode 100644 branches/WOF2-3/ulp/dapl2/doc/dapl_patch.txt create mode 100644 branches/WOF2-3/ulp/dapl2/doc/dapl_registry_design.txt create mode 100644 branches/WOF2-3/ulp/dapl2/doc/dapl_shared_memory_design.txt create mode 100644 branches/WOF2-3/ulp/dapl2/doc/dapl_vendor_specific_changes.txt create mode 100644 branches/WOF2-3/ulp/dapl2/doc/dat_environ.txt create mode 100644 branches/WOF2-3/ulp/dapl2/doc/uDAPL_release_notes.txt create mode 100644 branches/WOF2-3/ulp/dapl2/man/dapltest.1 create mode 100644 branches/WOF2-3/ulp/dapl2/man/dat.conf.5 create mode 100644 branches/WOF2-3/ulp/dapl2/man/dtest.1 create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/Makefile.am create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/README create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/cmd/dapl_fft_cmd.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/cmd/dapl_getopt.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/cmd/dapl_limit_cmd.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/cmd/dapl_main.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/cmd/dapl_netaddr.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/cmd/dapl_params.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/cmd/dapl_performance_cmd.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/cmd/dapl_qos_util.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/cmd/dapl_quit_cmd.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/cmd/dapl_server_cmd.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/cmd/dapl_test_data.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/cmd/dapl_transaction_cmd.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/common/dapl_endian.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/common/dapl_global.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/common/dapl_performance_cmd_util.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/common/dapl_quit_cmd_util.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/common/dapl_transaction_cmd_util.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/configure.in create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/dirs create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/dt_cmd.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/dt_common.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/dt_mdep.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/dt_test.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/dt_udapl.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_bpool.h create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_client_info.h create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_common.h create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_execute.h create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_fft_cmd.h create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_fft_util.h create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_getopt.h create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_global.h create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_limit_cmd.h create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_mdep.h create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_memlist.h create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_params.h create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_performance_cmd.h create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_performance_stats.h create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_performance_test.h create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_proto.h create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_quit_cmd.h create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_server_cmd.h create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_server_info.h create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_tdep.h create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_tdep_print.h create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_test_data.h create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_transaction_cmd.h create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_transaction_stats.h create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_transaction_test.h create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_version.h create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/mdep/linux/dapl_mdep_kernel.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/mdep/linux/dapl_mdep_kernel.h create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/mdep/linux/dapl_mdep_user.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/mdep/linux/dapl_mdep_user.h create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/mdep/solaris/dapl_mdep_user.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/mdep/solaris/dapl_mdep_user.h create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/mdep/windows/dapl_mdep_user.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/mdep/windows/dapl_mdep_user.h create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/scripts/cl.sh create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/scripts/dt-cli.bat create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/scripts/dt-svr.bat create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/scripts/kregress.sh create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/scripts/ksrv.sh create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/scripts/lim.sh create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/scripts/regress.sh create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/scripts/srv.sh create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_bpool.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_client.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_client_info.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_cnxn.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_execute.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_fft_connmgt.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_fft_dataxfer.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_fft_dataxfer_client.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_fft_endpoint.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_fft_hwconn.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_fft_mem.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_fft_pz.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_fft_queryinfo.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_fft_test.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_fft_util.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_limit.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_memlist.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_performance_client.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_performance_server.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_performance_stats.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_performance_util.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_quit_util.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_server.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_server_info.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_test_data.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_test_util.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_thread.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_transaction_stats.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_transaction_test.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_transaction_util.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_util.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/udapl/udapl_tdep.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/windows/SOURCES create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/windows/dapltest.rc create mode 100644 branches/WOF2-3/ulp/dapl2/test/dapltest/windows/makefile create mode 100644 branches/WOF2-3/ulp/dapl2/test/dirs create mode 100644 branches/WOF2-3/ulp/dapl2/test/dtest/Makefile.am create mode 100644 branches/WOF2-3/ulp/dapl2/test/dtest/README create mode 100644 branches/WOF2-3/ulp/dapl2/test/dtest/configure.in create mode 100644 branches/WOF2-3/ulp/dapl2/test/dtest/dirs create mode 100644 branches/WOF2-3/ulp/dapl2/test/dtest/dtc.bat create mode 100644 branches/WOF2-3/ulp/dapl2/test/dtest/dtest.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dtest/dtestcm.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dtest/dtestx.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dtest/dts.bat create mode 100644 branches/WOF2-3/ulp/dapl2/test/dtest/windows/dirs create mode 100644 branches/WOF2-3/ulp/dapl2/test/dtest/windows/dtest/SOURCES create mode 100644 branches/WOF2-3/ulp/dapl2/test/dtest/windows/dtest/dtest.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dtest/windows/dtest/dtest.rc create mode 100644 branches/WOF2-3/ulp/dapl2/test/dtest/windows/dtest/makefile create mode 100644 branches/WOF2-3/ulp/dapl2/test/dtest/windows/dtestcm/SOURCES create mode 100644 branches/WOF2-3/ulp/dapl2/test/dtest/windows/dtestcm/dtestcm.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dtest/windows/dtestcm/dtestcm.rc create mode 100644 branches/WOF2-3/ulp/dapl2/test/dtest/windows/dtestcm/makefile create mode 100644 branches/WOF2-3/ulp/dapl2/test/dtest/windows/dtestx/SOURCES create mode 100644 branches/WOF2-3/ulp/dapl2/test/dtest/windows/dtestx/dtestx.c create mode 100644 branches/WOF2-3/ulp/dapl2/test/dtest/windows/dtestx/dtestx.rc create mode 100644 branches/WOF2-3/ulp/dapl2/test/dtest/windows/dtestx/makefile create mode 100644 branches/WOF2-3/ulp/dirs create mode 100644 branches/WOF2-3/ulp/ipoib/dirs create mode 100644 branches/WOF2-3/ulp/ipoib/ip_stats.h create mode 100644 branches/WOF2-3/ulp/ipoib/kernel/SOURCES create mode 100644 branches/WOF2-3/ulp/ipoib/kernel/ipoib.cdf create mode 100644 branches/WOF2-3/ulp/ipoib/kernel/ipoib.rc create mode 100644 branches/WOF2-3/ulp/ipoib/kernel/ipoib32-xp.cdf create mode 100644 branches/WOF2-3/ulp/ipoib/kernel/ipoib32.cdf create mode 100644 branches/WOF2-3/ulp/ipoib/kernel/ipoib_adapter.c create mode 100644 branches/WOF2-3/ulp/ipoib/kernel/ipoib_adapter.h create mode 100644 branches/WOF2-3/ulp/ipoib/kernel/ipoib_debug.h create mode 100644 branches/WOF2-3/ulp/ipoib/kernel/ipoib_driver.c create mode 100644 branches/WOF2-3/ulp/ipoib/kernel/ipoib_driver.h create mode 100644 branches/WOF2-3/ulp/ipoib/kernel/ipoib_endpoint.c create mode 100644 branches/WOF2-3/ulp/ipoib/kernel/ipoib_endpoint.h create mode 100644 branches/WOF2-3/ulp/ipoib/kernel/ipoib_ibat.c create mode 100644 branches/WOF2-3/ulp/ipoib/kernel/ipoib_ibat.h create mode 100644 branches/WOF2-3/ulp/ipoib/kernel/ipoib_log.mc create mode 100644 branches/WOF2-3/ulp/ipoib/kernel/ipoib_port.c create mode 100644 branches/WOF2-3/ulp/ipoib/kernel/ipoib_port.h create mode 100644 branches/WOF2-3/ulp/ipoib/kernel/ipoib_stat.c create mode 100644 branches/WOF2-3/ulp/ipoib/kernel/ipoib_stat.h create mode 100644 branches/WOF2-3/ulp/ipoib/kernel/ipoib_xfr_mgr.c create mode 100644 branches/WOF2-3/ulp/ipoib/kernel/ipoib_xfr_mgr.h create mode 100644 branches/WOF2-3/ulp/ipoib/kernel/makefile create mode 100644 branches/WOF2-3/ulp/ipoib/kernel/makefile.inc create mode 100644 branches/WOF2-3/ulp/ipoib/kernel/netipoib-xp32.inf create mode 100644 branches/WOF2-3/ulp/ipoib/kernel/netipoib.inx create mode 100644 branches/WOF2-3/ulp/ipoib/kernel/offload.h create mode 100644 branches/WOF2-3/ulp/ipoib_NDIS6_CM/dirs create mode 100644 branches/WOF2-3/ulp/ipoib_NDIS6_CM/ip_stats.h create mode 100644 branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/SOURCES create mode 100644 branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib.cdf create mode 100644 branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib.rc create mode 100644 branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib32.cdf create mode 100644 branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_adapter.cpp create mode 100644 branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_adapter.h create mode 100644 branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_debug.h create mode 100644 branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_driver.cpp create mode 100644 branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_driver.h create mode 100644 branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_endpoint.cpp create mode 100644 branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_endpoint.h create mode 100644 branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_ibat.cpp create mode 100644 branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_ibat.h create mode 100644 branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_log.mc create mode 100644 branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_port.cpp create mode 100644 branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_port.h create mode 100644 branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_stat.cpp create mode 100644 branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_stat.h create mode 100644 branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_xfr_mgr.cpp create mode 100644 branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_xfr_mgr.h create mode 100644 branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/makefile create mode 100644 branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/makefile.inc create mode 100644 branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/netipoib.inx create mode 100644 branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/offload.h create mode 100644 branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/precompile.h create mode 100644 branches/WOF2-3/ulp/libibmad/README.txt create mode 100644 branches/WOF2-3/ulp/libibmad/dirs create mode 100644 branches/WOF2-3/ulp/libibmad/include/infiniband/mad.h create mode 100644 branches/WOF2-3/ulp/libibmad/include/infiniband/mad_osd.h create mode 100644 branches/WOF2-3/ulp/libibmad/include/windows/config.h create mode 100644 branches/WOF2-3/ulp/libibmad/src/Sources create mode 100644 branches/WOF2-3/ulp/libibmad/src/bm.c create mode 100644 branches/WOF2-3/ulp/libibmad/src/dump.c create mode 100644 branches/WOF2-3/ulp/libibmad/src/fields.c create mode 100644 branches/WOF2-3/ulp/libibmad/src/gs.c create mode 100644 branches/WOF2-3/ulp/libibmad/src/ibmad.rc create mode 100644 branches/WOF2-3/ulp/libibmad/src/ibmad_export.def create mode 100644 branches/WOF2-3/ulp/libibmad/src/ibmad_exports.src create mode 100644 branches/WOF2-3/ulp/libibmad/src/ibmad_main.cpp create mode 100644 branches/WOF2-3/ulp/libibmad/src/libibmad.map create mode 100644 branches/WOF2-3/ulp/libibmad/src/mad.c create mode 100644 branches/WOF2-3/ulp/libibmad/src/mad_internal.h create mode 100644 branches/WOF2-3/ulp/libibmad/src/makefile create mode 100644 branches/WOF2-3/ulp/libibmad/src/portid.c create mode 100644 branches/WOF2-3/ulp/libibmad/src/register.c create mode 100644 branches/WOF2-3/ulp/libibmad/src/resolve.c create mode 100644 branches/WOF2-3/ulp/libibmad/src/rpc.c create mode 100644 branches/WOF2-3/ulp/libibmad/src/sa.c create mode 100644 branches/WOF2-3/ulp/libibmad/src/serv.c create mode 100644 branches/WOF2-3/ulp/libibmad/src/smp.c create mode 100644 branches/WOF2-3/ulp/libibmad/src/vendor.c create mode 100644 branches/WOF2-3/ulp/libibnetdisc/README.txt create mode 100644 branches/WOF2-3/ulp/libibnetdisc/dirs create mode 100644 branches/WOF2-3/ulp/libibnetdisc/include/infiniband/ibnetdisc.h create mode 100644 branches/WOF2-3/ulp/libibnetdisc/include/windows/config.h create mode 100644 branches/WOF2-3/ulp/libibnetdisc/src/Sources create mode 100644 branches/WOF2-3/ulp/libibnetdisc/src/chassis.c create mode 100644 branches/WOF2-3/ulp/libibnetdisc/src/chassis.h create mode 100644 branches/WOF2-3/ulp/libibnetdisc/src/ibnetdisc.c create mode 100644 branches/WOF2-3/ulp/libibnetdisc/src/ibnetdisc_cache.c create mode 100644 branches/WOF2-3/ulp/libibnetdisc/src/ibnetdisc_export.def create mode 100644 branches/WOF2-3/ulp/libibnetdisc/src/ibnetdisc_exports.src create mode 100644 branches/WOF2-3/ulp/libibnetdisc/src/ibnetdisc_main.cpp create mode 100644 branches/WOF2-3/ulp/libibnetdisc/src/internal.h create mode 100644 branches/WOF2-3/ulp/libibnetdisc/src/makefile create mode 100644 branches/WOF2-3/ulp/libibnetdisc/src/query_smp.c create mode 100644 branches/WOF2-3/ulp/libibumad/AUTHORS create mode 100644 branches/WOF2-3/ulp/libibumad/COPYING create mode 100644 branches/WOF2-3/ulp/libibumad/dirs create mode 100644 branches/WOF2-3/ulp/libibumad/include/infiniband/umad.h create mode 100644 branches/WOF2-3/ulp/libibumad/src/Sources create mode 100644 branches/WOF2-3/ulp/libibumad/src/ibum_export.def create mode 100644 branches/WOF2-3/ulp/libibumad/src/ibum_exports.src create mode 100644 branches/WOF2-3/ulp/libibumad/src/ibum_main.cpp create mode 100644 branches/WOF2-3/ulp/libibumad/src/ibumad.h create mode 100644 branches/WOF2-3/ulp/libibumad/src/ibumad.rc create mode 100644 branches/WOF2-3/ulp/libibumad/src/makefile create mode 100644 branches/WOF2-3/ulp/libibumad/src/umad.cpp create mode 100644 branches/WOF2-3/ulp/libibverbs/AUTHORS create mode 100644 branches/WOF2-3/ulp/libibverbs/COPYING create mode 100644 branches/WOF2-3/ulp/libibverbs/dirs create mode 100644 branches/WOF2-3/ulp/libibverbs/examples/asyncwatch/SOURCES create mode 100644 branches/WOF2-3/ulp/libibverbs/examples/asyncwatch/asyncwatch.c create mode 100644 branches/WOF2-3/ulp/libibverbs/examples/asyncwatch/asyncwatch.rc create mode 100644 branches/WOF2-3/ulp/libibverbs/examples/asyncwatch/makefile create mode 100644 branches/WOF2-3/ulp/libibverbs/examples/device_list.c create mode 100644 branches/WOF2-3/ulp/libibverbs/examples/devinfo/SOURCES create mode 100644 branches/WOF2-3/ulp/libibverbs/examples/devinfo/devinfo.c create mode 100644 branches/WOF2-3/ulp/libibverbs/examples/devinfo/devinfo.rc create mode 100644 branches/WOF2-3/ulp/libibverbs/examples/devinfo/makefile create mode 100644 branches/WOF2-3/ulp/libibverbs/examples/dirs create mode 100644 branches/WOF2-3/ulp/libibverbs/examples/pingpong.c create mode 100644 branches/WOF2-3/ulp/libibverbs/examples/pingpong.h create mode 100644 branches/WOF2-3/ulp/libibverbs/examples/rc_pingpong/SOURCES create mode 100644 branches/WOF2-3/ulp/libibverbs/examples/rc_pingpong/makefile create mode 100644 branches/WOF2-3/ulp/libibverbs/examples/rc_pingpong/rc_pingpong.c create mode 100644 branches/WOF2-3/ulp/libibverbs/examples/rc_pingpong/rc_pingpong.rc create mode 100644 branches/WOF2-3/ulp/libibverbs/examples/srq_pingpong/SOURCES create mode 100644 branches/WOF2-3/ulp/libibverbs/examples/srq_pingpong/makefile create mode 100644 branches/WOF2-3/ulp/libibverbs/examples/srq_pingpong/srq_pingpong.c create mode 100644 branches/WOF2-3/ulp/libibverbs/examples/srq_pingpong/srq_pingpong.rc create mode 100644 branches/WOF2-3/ulp/libibverbs/examples/uc_pingpong/SOURCES create mode 100644 branches/WOF2-3/ulp/libibverbs/examples/uc_pingpong/makefile create mode 100644 branches/WOF2-3/ulp/libibverbs/examples/uc_pingpong/uc_pingpong.c create mode 100644 branches/WOF2-3/ulp/libibverbs/examples/uc_pingpong/uc_pingpong.rc create mode 100644 branches/WOF2-3/ulp/libibverbs/examples/ud_pingpong/SOURCES create mode 100644 branches/WOF2-3/ulp/libibverbs/examples/ud_pingpong/makefile create mode 100644 branches/WOF2-3/ulp/libibverbs/examples/ud_pingpong/ud_pingpong.c create mode 100644 branches/WOF2-3/ulp/libibverbs/examples/ud_pingpong/ud_pingpong.rc create mode 100644 branches/WOF2-3/ulp/libibverbs/include/infiniband/sa.h create mode 100644 branches/WOF2-3/ulp/libibverbs/include/infiniband/verbs.h create mode 100644 branches/WOF2-3/ulp/libibverbs/src/Sources create mode 100644 branches/WOF2-3/ulp/libibverbs/src/device.cpp create mode 100644 branches/WOF2-3/ulp/libibverbs/src/enum_strs.cpp create mode 100644 branches/WOF2-3/ulp/libibverbs/src/ibv_export.def create mode 100644 branches/WOF2-3/ulp/libibverbs/src/ibv_exports.src create mode 100644 branches/WOF2-3/ulp/libibverbs/src/ibv_main.cpp create mode 100644 branches/WOF2-3/ulp/libibverbs/src/ibverbs.h create mode 100644 branches/WOF2-3/ulp/libibverbs/src/ibverbs.rc create mode 100644 branches/WOF2-3/ulp/libibverbs/src/makefile create mode 100644 branches/WOF2-3/ulp/libibverbs/src/verbs.cpp create mode 100644 branches/WOF2-3/ulp/librdmacm/AUTHORS create mode 100644 branches/WOF2-3/ulp/librdmacm/COPYING create mode 100644 branches/WOF2-3/ulp/librdmacm/dirs create mode 100644 branches/WOF2-3/ulp/librdmacm/examples/cmatose/SOURCES create mode 100644 branches/WOF2-3/ulp/librdmacm/examples/cmatose/cmatose.c create mode 100644 branches/WOF2-3/ulp/librdmacm/examples/cmatose/makefile create mode 100644 branches/WOF2-3/ulp/librdmacm/examples/dirs create mode 100644 branches/WOF2-3/ulp/librdmacm/examples/mckey/mckey.c create mode 100644 branches/WOF2-3/ulp/librdmacm/examples/rdma_client/SOURCES create mode 100644 branches/WOF2-3/ulp/librdmacm/examples/rdma_client/makefile create mode 100644 branches/WOF2-3/ulp/librdmacm/examples/rdma_client/rdma_client.c create mode 100644 branches/WOF2-3/ulp/librdmacm/examples/rdma_server/SOURCES create mode 100644 branches/WOF2-3/ulp/librdmacm/examples/rdma_server/makefile create mode 100644 branches/WOF2-3/ulp/librdmacm/examples/rdma_server/rdma_server.c create mode 100644 branches/WOF2-3/ulp/librdmacm/examples/rping/rping.c create mode 100644 branches/WOF2-3/ulp/librdmacm/examples/udaddy/udaddy.c create mode 100644 branches/WOF2-3/ulp/librdmacm/include/rdma/rdma_cma.h create mode 100644 branches/WOF2-3/ulp/librdmacm/include/rdma/rdma_verbs.h create mode 100644 branches/WOF2-3/ulp/librdmacm/src/Sources create mode 100644 branches/WOF2-3/ulp/librdmacm/src/addrinfo.cpp create mode 100644 branches/WOF2-3/ulp/librdmacm/src/cma.cpp create mode 100644 branches/WOF2-3/ulp/librdmacm/src/cma.h create mode 100644 branches/WOF2-3/ulp/librdmacm/src/cma.rc create mode 100644 branches/WOF2-3/ulp/librdmacm/src/cma_export.def create mode 100644 branches/WOF2-3/ulp/librdmacm/src/cma_exports.src create mode 100644 branches/WOF2-3/ulp/librdmacm/src/cma_main.cpp create mode 100644 branches/WOF2-3/ulp/librdmacm/src/makefile create mode 100644 branches/WOF2-3/ulp/nd/dirs create mode 100644 branches/WOF2-3/ulp/nd/user/NdAdapter.cpp create mode 100644 branches/WOF2-3/ulp/nd/user/NdAdapter.h create mode 100644 branches/WOF2-3/ulp/nd/user/NdConnector.cpp create mode 100644 branches/WOF2-3/ulp/nd/user/NdConnector.h create mode 100644 branches/WOF2-3/ulp/nd/user/NdCq.cpp create mode 100644 branches/WOF2-3/ulp/nd/user/NdCq.h create mode 100644 branches/WOF2-3/ulp/nd/user/NdEndpoint.cpp create mode 100644 branches/WOF2-3/ulp/nd/user/NdEndpoint.h create mode 100644 branches/WOF2-3/ulp/nd/user/NdListen.cpp create mode 100644 branches/WOF2-3/ulp/nd/user/NdListen.h create mode 100644 branches/WOF2-3/ulp/nd/user/NdMr.cpp create mode 100644 branches/WOF2-3/ulp/nd/user/NdMr.h create mode 100644 branches/WOF2-3/ulp/nd/user/NdMw.cpp create mode 100644 branches/WOF2-3/ulp/nd/user/NdMw.h create mode 100644 branches/WOF2-3/ulp/nd/user/NdProv.cpp create mode 100644 branches/WOF2-3/ulp/nd/user/NdProv.def create mode 100644 branches/WOF2-3/ulp/nd/user/NdProv.h create mode 100644 branches/WOF2-3/ulp/nd/user/NdProv.rc create mode 100644 branches/WOF2-3/ulp/nd/user/README.txt create mode 100644 branches/WOF2-3/ulp/nd/user/SOURCES create mode 100644 branches/WOF2-3/ulp/nd/user/fre_svr-03_ia64/ia64/ibndprov.dll create mode 100644 branches/WOF2-3/ulp/nd/user/fre_svr-03_ia64/ia64/ndinstall.exe create mode 100644 branches/WOF2-3/ulp/nd/user/fre_svr-08_ia64/ia64/ibndprov.dll create mode 100644 branches/WOF2-3/ulp/nd/user/fre_svr-08_ia64/ia64/ndinstall.exe create mode 100644 branches/WOF2-3/ulp/nd/user/makefile create mode 100644 branches/WOF2-3/ulp/nd/user/makefile.inc create mode 100644 branches/WOF2-3/ulp/nd/user/nddebug.h create mode 100644 branches/WOF2-3/ulp/netdirect/dirs create mode 100644 branches/WOF2-3/ulp/netdirect/user/SOURCES create mode 100644 branches/WOF2-3/ulp/netdirect/user/makefile create mode 100644 branches/WOF2-3/ulp/netdirect/user/nd_adapter.cpp create mode 100644 branches/WOF2-3/ulp/netdirect/user/nd_adapter.h create mode 100644 branches/WOF2-3/ulp/netdirect/user/nd_base.cpp create mode 100644 branches/WOF2-3/ulp/netdirect/user/nd_base.h create mode 100644 branches/WOF2-3/ulp/netdirect/user/nd_connect.cpp create mode 100644 branches/WOF2-3/ulp/netdirect/user/nd_connect.h create mode 100644 branches/WOF2-3/ulp/netdirect/user/nd_cq.cpp create mode 100644 branches/WOF2-3/ulp/netdirect/user/nd_cq.h create mode 100644 branches/WOF2-3/ulp/netdirect/user/nd_ep.cpp create mode 100644 branches/WOF2-3/ulp/netdirect/user/nd_ep.h create mode 100644 branches/WOF2-3/ulp/netdirect/user/nd_export.def create mode 100644 branches/WOF2-3/ulp/netdirect/user/nd_exports.src create mode 100644 branches/WOF2-3/ulp/netdirect/user/nd_listen.cpp create mode 100644 branches/WOF2-3/ulp/netdirect/user/nd_listen.h create mode 100644 branches/WOF2-3/ulp/netdirect/user/nd_main.cpp create mode 100644 branches/WOF2-3/ulp/netdirect/user/nd_main.h create mode 100644 branches/WOF2-3/ulp/netdirect/user/nd_mw.cpp create mode 100644 branches/WOF2-3/ulp/netdirect/user/nd_mw.h create mode 100644 branches/WOF2-3/ulp/netdirect/user/nd_provider.cpp create mode 100644 branches/WOF2-3/ulp/netdirect/user/nd_provider.h create mode 100644 branches/WOF2-3/ulp/netdirect/user/netdirect.rc create mode 100644 branches/WOF2-3/ulp/netdirect2/dirs create mode 100644 branches/WOF2-3/ulp/netdirect2/user/SOURCES create mode 100644 branches/WOF2-3/ulp/netdirect2/user/makefile create mode 100644 branches/WOF2-3/ulp/netdirect2/user/nd_adapter.cpp create mode 100644 branches/WOF2-3/ulp/netdirect2/user/nd_adapter.h create mode 100644 branches/WOF2-3/ulp/netdirect2/user/nd_base.cpp create mode 100644 branches/WOF2-3/ulp/netdirect2/user/nd_base.h create mode 100644 branches/WOF2-3/ulp/netdirect2/user/nd_connect.cpp create mode 100644 branches/WOF2-3/ulp/netdirect2/user/nd_connect.h create mode 100644 branches/WOF2-3/ulp/netdirect2/user/nd_cq.cpp create mode 100644 branches/WOF2-3/ulp/netdirect2/user/nd_cq.h create mode 100644 branches/WOF2-3/ulp/netdirect2/user/nd_ep.cpp create mode 100644 branches/WOF2-3/ulp/netdirect2/user/nd_ep.h create mode 100644 branches/WOF2-3/ulp/netdirect2/user/nd_export.def create mode 100644 branches/WOF2-3/ulp/netdirect2/user/nd_exports.src create mode 100644 branches/WOF2-3/ulp/netdirect2/user/nd_listen.cpp create mode 100644 branches/WOF2-3/ulp/netdirect2/user/nd_listen.h create mode 100644 branches/WOF2-3/ulp/netdirect2/user/nd_main.cpp create mode 100644 branches/WOF2-3/ulp/netdirect2/user/nd_main.h create mode 100644 branches/WOF2-3/ulp/netdirect2/user/nd_mw.cpp create mode 100644 branches/WOF2-3/ulp/netdirect2/user/nd_mw.h create mode 100644 branches/WOF2-3/ulp/netdirect2/user/nd_provider.cpp create mode 100644 branches/WOF2-3/ulp/netdirect2/user/nd_provider.h create mode 100644 branches/WOF2-3/ulp/netdirect2/user/nd_qp.cpp create mode 100644 branches/WOF2-3/ulp/netdirect2/user/nd_qp.h create mode 100644 branches/WOF2-3/ulp/netdirect2/user/nd_srq.cpp create mode 100644 branches/WOF2-3/ulp/netdirect2/user/nd_srq.h create mode 100644 branches/WOF2-3/ulp/netdirect2/user/netdirect.rc create mode 100644 branches/WOF2-3/ulp/opensm/dirs create mode 100644 branches/WOF2-3/ulp/opensm/user/AUTHORS create mode 100644 branches/WOF2-3/ulp/opensm/user/README create mode 100644 branches/WOF2-3/ulp/opensm/user/README.windows create mode 100644 branches/WOF2-3/ulp/opensm/user/complib/README.txt create mode 100644 branches/WOF2-3/ulp/opensm/user/complib/cl_dispatcher.c create mode 100644 branches/WOF2-3/ulp/opensm/user/complib/cl_event_wheel.c create mode 100644 branches/WOF2-3/ulp/opensm/user/config.h create mode 100644 branches/WOF2-3/ulp/opensm/user/dirs create mode 100644 branches/WOF2-3/ulp/opensm/user/doc/OpenSM_PKey_Mgr.txt create mode 100644 branches/WOF2-3/ulp/opensm/user/doc/OpenSM_RN.pdf create mode 100644 branches/WOF2-3/ulp/opensm/user/doc/OpenSM_UM.pdf create mode 100644 branches/WOF2-3/ulp/opensm/user/doc/QoS_management_in_OpenSM.txt create mode 100644 branches/WOF2-3/ulp/opensm/user/doc/current-routing.txt create mode 100644 branches/WOF2-3/ulp/opensm/user/doc/opensm_release_notes-3.3.txt create mode 100644 branches/WOF2-3/ulp/opensm/user/doc/partition-config.txt create mode 100644 branches/WOF2-3/ulp/opensm/user/doc/perf-manager-arch.txt create mode 100644 branches/WOF2-3/ulp/opensm/user/doc/performance-manager-HOWTO.txt create mode 100644 branches/WOF2-3/ulp/opensm/user/doc/qos-config.txt create mode 100644 branches/WOF2-3/ulp/opensm/user/ibtrapgen/Makefile create mode 100644 branches/WOF2-3/ulp/opensm/user/ibtrapgen/SOURCES create mode 100644 branches/WOF2-3/ulp/opensm/user/ibtrapgen/ibtrapgen.c create mode 100644 branches/WOF2-3/ulp/opensm/user/ibtrapgen/ibtrapgen.h create mode 100644 branches/WOF2-3/ulp/opensm/user/ibtrapgen/main.c create mode 100644 branches/WOF2-3/ulp/opensm/user/ibtrapgen/osm_files.c create mode 100644 branches/WOF2-3/ulp/opensm/user/ibtrapgen/vendor-ibal.inc create mode 100644 branches/WOF2-3/ulp/opensm/user/ibtrapgen/vendor-umad.inc create mode 100644 branches/WOF2-3/ulp/opensm/user/include/README.txt create mode 100644 branches/WOF2-3/ulp/opensm/user/include/complib/cl_dispatcher.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/complib/cl_event_wheel.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/iba/ib_cm_types.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/opensm/osm_attrib_req.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/opensm/osm_base.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/opensm/osm_config.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/opensm/osm_config.h.in create mode 100644 branches/WOF2-3/ulp/opensm/user/include/opensm/osm_console.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/opensm/osm_console_io.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/opensm/osm_db.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/opensm/osm_db_pack.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/opensm/osm_errors.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/opensm/osm_event_plugin.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/opensm/osm_helper.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/opensm/osm_inform.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/opensm/osm_lid_mgr.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/opensm/osm_log.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/opensm/osm_mad_pool.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/opensm/osm_madw.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/opensm/osm_mcast_tbl.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/opensm/osm_mcm_port.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/opensm/osm_mesh.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/opensm/osm_msgdef.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/opensm/osm_mtree.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/opensm/osm_multicast.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/opensm/osm_node.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/opensm/osm_opensm.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/opensm/osm_partition.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/opensm/osm_path.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/opensm/osm_perfmgr.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/opensm/osm_perfmgr_db.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/opensm/osm_pkey.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/opensm/osm_port.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/opensm/osm_port_profile.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/opensm/osm_prefix_route.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/opensm/osm_qos_policy.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/opensm/osm_remote_sm.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/opensm/osm_router.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/opensm/osm_sa.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/opensm/osm_sa_mad_ctrl.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/opensm/osm_service.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/opensm/osm_sm.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/opensm/osm_sm_mad_ctrl.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/opensm/osm_stats.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/opensm/osm_subnet.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/opensm/osm_switch.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/opensm/osm_ucast_cache.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/opensm/osm_ucast_lash.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/opensm/osm_ucast_mgr.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/opensm/osm_version.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/opensm/osm_version.h.in create mode 100644 branches/WOF2-3/ulp/opensm/user/include/opensm/osm_vl15intf.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/opensm/st.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/vendor/osm_mtl_bind.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/vendor/osm_pkt_randomizer.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/vendor/osm_ts_useraccess.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/vendor/osm_umadt.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_al.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_api.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_ibumad.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mlx.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mlx_defs.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mlx_dispatcher.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mlx_hca.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mlx_inout.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mlx_rmpp_ctx.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mlx_sar.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mlx_sender.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mlx_svc.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mlx_transport.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mlx_transport_anafa.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mlx_txn.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mtl.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mtl_hca_guid.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mtl_transaction_mgr.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_sa_api.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_test.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_ts.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_umadt.h create mode 100644 branches/WOF2-3/ulp/opensm/user/include/vendor/winosm_common.h create mode 100644 branches/WOF2-3/ulp/opensm/user/libvendor/ChangeLog create mode 100644 branches/WOF2-3/ulp/opensm/user/libvendor/Makefile create mode 100644 branches/WOF2-3/ulp/opensm/user/libvendor/SOURCES create mode 100644 branches/WOF2-3/ulp/opensm/user/libvendor/complib_files.c create mode 100644 branches/WOF2-3/ulp/opensm/user/libvendor/libosmvendor.ver create mode 100644 branches/WOF2-3/ulp/opensm/user/libvendor/osm_pkt_randomizer.c create mode 100644 branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_al.c create mode 100644 branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_ibumad.c create mode 100644 branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_ibumad_sa.c create mode 100644 branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_mlx.c create mode 100644 branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_mlx_dispatcher.c create mode 100644 branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_mlx_hca.c create mode 100644 branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_mlx_hca_sim.c create mode 100644 branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_mlx_ibmgt.c create mode 100644 branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_mlx_rmpp_ctx.c create mode 100644 branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_mlx_sa.c create mode 100644 branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_mlx_sar.c create mode 100644 branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_mlx_sender.c create mode 100644 branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_mlx_sim.c create mode 100644 branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_mlx_ts.c create mode 100644 branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_mlx_txn.c create mode 100644 branches/WOF2-3/ulp/opensm/user/libvendor/osmv_ibal.exports create mode 100644 branches/WOF2-3/ulp/opensm/user/libvendor/osmv_openib.exports create mode 100644 branches/WOF2-3/ulp/opensm/user/libvendor/vendor-ibal.inc create mode 100644 branches/WOF2-3/ulp/opensm/user/libvendor/vendor-umad.inc create mode 100644 branches/WOF2-3/ulp/opensm/user/libvendor/winosm_common.c create mode 100644 branches/WOF2-3/ulp/opensm/user/mad-vendor.inc create mode 100644 branches/WOF2-3/ulp/opensm/user/man/opensm.8 create mode 100644 branches/WOF2-3/ulp/opensm/user/man/osmtest.8 create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/ChangeLog create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/Makefile create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/SOURCES create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/dlfcn.h create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/libopensm.map create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/libopensm.ver create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/main.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/opensm.rc create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm.mc create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_console.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_console_io.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_db_files.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_db_pack.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_drop_mgr.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_dump.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_event_plugin.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_files.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_helper.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_inform.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_lid_mgr.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_lin_fwd_rcv.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_link_mgr.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_log.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_mad_pool.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_mcast_fwd_rcv.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_mcast_mgr.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_mcast_tbl.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_mcm_port.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_mesh.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_mtree.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_multicast.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_node.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_node_desc_rcv.c create mode 100755 branches/WOF2-3/ulp/opensm/user/opensm/osm_node_info_rcv.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_opensm.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_perfmgr.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_perfmgr_db.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_pkey.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_pkey_mgr.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_pkey_rcv.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_port.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_port_info_rcv.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_prtn.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_prtn_config.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_qos.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_qos_parser_l.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_qos_parser_l.l create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_qos_parser_y.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_qos_parser_y.h create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_qos_parser_y.y create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_qos_policy.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_remote_sm.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_req.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_resp.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_router.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_sa.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_class_port_info.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_guidinfo_record.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_informinfo.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_lft_record.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_link_record.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_mad_ctrl.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_mcmember_record.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_mft_record.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_multipath_record.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_node_record.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_path_record.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_pkey_record.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_portinfo_record.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_service_record.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_slvl_record.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_sminfo_record.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_sw_info_record.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_vlarb_record.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_service.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_slvl_map_rcv.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_sm.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_sm_mad_ctrl.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_sm_state_mgr.c create mode 100755 branches/WOF2-3/ulp/opensm/user/opensm/osm_sminfo_rcv.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_state_mgr.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_subnet.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_sw_info_rcv.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_switch.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_trap_rcv.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_ucast_cache.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_ucast_file.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_ucast_ftree.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_ucast_lash.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_ucast_mgr.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_ucast_updn.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_vl15intf.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/osm_vl_arb_rcv.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/st.c create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/vendor-ibal.inc create mode 100644 branches/WOF2-3/ulp/opensm/user/opensm/vendor-umad.inc create mode 100644 branches/WOF2-3/ulp/opensm/user/osmeventplugin/libosmeventplugin.map create mode 100644 branches/WOF2-3/ulp/opensm/user/osmeventplugin/libosmeventplugin.ver create mode 100644 branches/WOF2-3/ulp/opensm/user/osmeventplugin/src/osmeventplugin.c create mode 100644 branches/WOF2-3/ulp/opensm/user/osmtest/Makefile create mode 100644 branches/WOF2-3/ulp/opensm/user/osmtest/SOURCES create mode 100644 branches/WOF2-3/ulp/opensm/user/osmtest/include/osmt_inform.h create mode 100644 branches/WOF2-3/ulp/opensm/user/osmtest/include/osmt_mtl_regular_qp.h create mode 100644 branches/WOF2-3/ulp/opensm/user/osmtest/include/osmtest.h create mode 100644 branches/WOF2-3/ulp/opensm/user/osmtest/include/osmtest_base.h create mode 100644 branches/WOF2-3/ulp/opensm/user/osmtest/include/osmtest_subnet.h create mode 100644 branches/WOF2-3/ulp/opensm/user/osmtest/main.c create mode 100644 branches/WOF2-3/ulp/opensm/user/osmtest/osmt_files.c create mode 100644 branches/WOF2-3/ulp/opensm/user/osmtest/osmt_inform.c create mode 100644 branches/WOF2-3/ulp/opensm/user/osmtest/osmt_mtl_regular_qp.c create mode 100644 branches/WOF2-3/ulp/opensm/user/osmtest/osmt_multicast.c create mode 100644 branches/WOF2-3/ulp/opensm/user/osmtest/osmt_service.c create mode 100644 branches/WOF2-3/ulp/opensm/user/osmtest/osmt_slvl_vl_arb.c create mode 100644 branches/WOF2-3/ulp/opensm/user/osmtest/osmtest.c create mode 100644 branches/WOF2-3/ulp/opensm/user/osmtest/osmtest.rc create mode 100644 branches/WOF2-3/ulp/opensm/user/osmtest/vendor-ibal.inc create mode 100644 branches/WOF2-3/ulp/opensm/user/osmtest/vendor-umad.inc create mode 100644 branches/WOF2-3/ulp/opensm/user/scripts/osm-regress.bat create mode 100644 branches/WOF2-3/ulp/qlgcvnic/dirs create mode 100644 branches/WOF2-3/ulp/qlgcvnic/kernel/SOURCES create mode 100644 branches/WOF2-3/ulp/qlgcvnic/kernel/inic.rc create mode 100644 branches/WOF2-3/ulp/qlgcvnic/kernel/makefile create mode 100644 branches/WOF2-3/ulp/qlgcvnic/kernel/makefile.inc create mode 100644 branches/WOF2-3/ulp/qlgcvnic/kernel/netvnic.cdf create mode 100644 branches/WOF2-3/ulp/qlgcvnic/kernel/netvnic.inx create mode 100644 branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_adapter.c create mode 100644 branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_adapter.h create mode 100644 branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_config.h create mode 100644 branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_control.c create mode 100644 branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_control.h create mode 100644 branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_controlpkt.h create mode 100644 branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_data.c create mode 100644 branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_data.h create mode 100644 branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_debug.h create mode 100644 branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_driver.c create mode 100644 branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_driver.h create mode 100644 branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_ib.c create mode 100644 branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_ib.h create mode 100644 branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_netpath.c create mode 100644 branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_trailer.h create mode 100644 branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_util.h create mode 100644 branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_viport.c create mode 100644 branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_viport.h create mode 100644 branches/WOF2-3/ulp/srp/dirs create mode 100644 branches/WOF2-3/ulp/srp/kernel/SOURCES create mode 100644 branches/WOF2-3/ulp/srp/kernel/ib_srp.cdf create mode 100644 branches/WOF2-3/ulp/srp/kernel/ib_srp.inx create mode 100644 branches/WOF2-3/ulp/srp/kernel/ibsrp.rc create mode 100644 branches/WOF2-3/ulp/srp/kernel/makefile create mode 100644 branches/WOF2-3/ulp/srp/kernel/makefile.inc create mode 100644 branches/WOF2-3/ulp/srp/kernel/srp.h create mode 100644 branches/WOF2-3/ulp/srp/kernel/srp_aer_req.h create mode 100644 branches/WOF2-3/ulp/srp/kernel/srp_aer_rsp.h create mode 100644 branches/WOF2-3/ulp/srp/kernel/srp_cmd.h create mode 100644 branches/WOF2-3/ulp/srp/kernel/srp_connection.c create mode 100644 branches/WOF2-3/ulp/srp/kernel/srp_connection.h create mode 100644 branches/WOF2-3/ulp/srp/kernel/srp_cred_req.h create mode 100644 branches/WOF2-3/ulp/srp/kernel/srp_cred_rsp.h create mode 100644 branches/WOF2-3/ulp/srp/kernel/srp_data.h create mode 100644 branches/WOF2-3/ulp/srp/kernel/srp_data_path.c create mode 100644 branches/WOF2-3/ulp/srp/kernel/srp_data_path.h create mode 100644 branches/WOF2-3/ulp/srp/kernel/srp_debug.h create mode 100644 branches/WOF2-3/ulp/srp/kernel/srp_descriptors.c create mode 100644 branches/WOF2-3/ulp/srp/kernel/srp_descriptors.h create mode 100644 branches/WOF2-3/ulp/srp/kernel/srp_driver.c create mode 100644 branches/WOF2-3/ulp/srp/kernel/srp_event.c create mode 100644 branches/WOF2-3/ulp/srp/kernel/srp_event.h create mode 100644 branches/WOF2-3/ulp/srp/kernel/srp_hba.c create mode 100644 branches/WOF2-3/ulp/srp/kernel/srp_hba.h create mode 100644 branches/WOF2-3/ulp/srp/kernel/srp_hca.c create mode 100644 branches/WOF2-3/ulp/srp/kernel/srp_hca.h create mode 100644 branches/WOF2-3/ulp/srp/kernel/srp_i_logout.h create mode 100644 branches/WOF2-3/ulp/srp/kernel/srp_information_unit.h create mode 100644 branches/WOF2-3/ulp/srp/kernel/srp_iu_buffer.h create mode 100644 branches/WOF2-3/ulp/srp/kernel/srp_login_rej.h create mode 100644 branches/WOF2-3/ulp/srp/kernel/srp_login_req.h create mode 100644 branches/WOF2-3/ulp/srp/kernel/srp_login_rsp.h create mode 100644 branches/WOF2-3/ulp/srp/kernel/srp_rsp.h create mode 100644 branches/WOF2-3/ulp/srp/kernel/srp_session.c create mode 100644 branches/WOF2-3/ulp/srp/kernel/srp_session.h create mode 100644 branches/WOF2-3/ulp/srp/kernel/srp_t_logout.h create mode 100644 branches/WOF2-3/ulp/srp/kernel/srp_tsk_mgmt.h create mode 100644 branches/WOF2-3/ulp/wsd/dirs create mode 100644 branches/WOF2-3/ulp/wsd/user/README create mode 100644 branches/WOF2-3/ulp/wsd/user/SOURCES create mode 100644 branches/WOF2-3/ulp/wsd/user/extensions.c create mode 100644 branches/WOF2-3/ulp/wsd/user/ib_cm.c create mode 100644 branches/WOF2-3/ulp/wsd/user/ibsp_duplicate.c create mode 100644 branches/WOF2-3/ulp/wsd/user/ibsp_iblow.c create mode 100644 branches/WOF2-3/ulp/wsd/user/ibsp_ip.c create mode 100644 branches/WOF2-3/ulp/wsd/user/ibsp_mem.c create mode 100644 branches/WOF2-3/ulp/wsd/user/ibsp_mem.h create mode 100644 branches/WOF2-3/ulp/wsd/user/ibsp_perfmon.c create mode 100644 branches/WOF2-3/ulp/wsd/user/ibsp_perfmon.h create mode 100644 branches/WOF2-3/ulp/wsd/user/ibsp_pnp.c create mode 100644 branches/WOF2-3/ulp/wsd/user/ibspdebug.c create mode 100644 branches/WOF2-3/ulp/wsd/user/ibspdebug.h create mode 100644 branches/WOF2-3/ulp/wsd/user/ibspdefines.h create mode 100644 branches/WOF2-3/ulp/wsd/user/ibspdll.c create mode 100644 branches/WOF2-3/ulp/wsd/user/ibspdll.def create mode 100644 branches/WOF2-3/ulp/wsd/user/ibspdll.h create mode 100644 branches/WOF2-3/ulp/wsd/user/ibspdll.rc create mode 100644 branches/WOF2-3/ulp/wsd/user/ibspproto.h create mode 100644 branches/WOF2-3/ulp/wsd/user/ibspstruct.h create mode 100644 branches/WOF2-3/ulp/wsd/user/makefile create mode 100644 branches/WOF2-3/ulp/wsd/user/misc.c create mode 100644 branches/WOF2-3/ulp/wsd/user/sockinfo.c diff --git a/branches/WOF2-3/OFED/Bld1.bat b/branches/WOF2-3/OFED/Bld1.bat new file mode 100644 index 00000000..afdedcca --- /dev/null +++ b/branches/WOF2-3/OFED/Bld1.bat @@ -0,0 +1,539 @@ +@echo off +setlocal +rem tabstop=4 +rem +rem version 1.1 +rem +rem Build a single OFED installer (.msi) file for a specific Windows OS version. +rem Binary release tree is constructed in OFED\Wix\OS\bin on an arch basis. +rem Processor architecture specific WIX installers are constructed in %IDIR% +rem +rem BldOS options +rem option: [win7,wlh,wnet,wxp] arch:x86,x64,ia64 [all | allnf | compile | compilenoforce | +rem compf path | compnf path | makebin | msi |sign | wix | clean] + +rem This script is an 'example' of a one-command IB stack build to single-file +rem installer for a single OS type (wxp produces 1 .msi file, +rem all others produce 3 msi files) +rem +rem Script is designed to be invoked from the \gen1\trunk folder with +rem \gen1\trunk\WinOF\Wix\* present. +rem +rem Verify the following env vars are suitible for your system configuration. +rem _DDK, _PSDK, SVN, IDIR + +rem WIX Installer files (.msi) destination folder - set for local environment. +set IDIR=%SystemRoot%\temp + +if "%1" == "" goto usage +if "%2" == "" goto usage + +if "%1" == "/?" goto usage +if "%1" == "-h" goto usage + +rem Wix 3.0 tools + +set WIX=%CD%\OFED\WIX +set WIX_BIN=wix3.0.5419.0-binaries + +rem validate OS arg + +if "%1" == "win7" ( + set __OS=%1 + set __BOS=%1 + goto OK_OS +) +if "%1" == "wlh" ( + set __OS=%1 + set __BOS=2008 + goto OK_OS +) +if "%1" == "wnet" ( + set __OS=%1 + set __BOS=2003 + goto OK_OS +) +if "%1" == "wxp" ( + set __OS=%1 + set __BOS=xp + goto OK_OS +) + +echo BuildOne: bad OS type '%1' use one of win7, wlh, wnet, wxp +exit /B 1 + +:OK_OS + +set RBIN=%WIX%\%__OS%\bin + +if /I "%2"=="x86" ( + set __ARCH=%2 + set __ARCH_MS=i386 + set RBIN_KF=%WIX%\%__OS%\bin\bin\kernel\objfre_%__OS%_%2 + goto OK_ARCH +) + +if /I "%2"=="ia64" ( + set X86_REBUILD=true + set __ARCH=%2 + set __ARCH_MS=%2 + set RBIN_KF=%WIX%\%__OS%\bin\bin\kernel\objfre_%__OS%_%2 + goto OK_ARCH +) + +if /I "%2"=="x64" ( + set X86_REBUILD=true + set __ARCH=%2 + set __ARCH_MS=amd64 + set RBIN_KF=%WIX%\%__OS%\bin\bin\kernel\objfre_%__OS%_%__ARCH_MS% + goto OK_ARCH +) + +rem archK implies existing x86 binaries for SYSWOW64 are good to use. +rem skip x86 rebuild. Case of being called from BldOS.bat or buildrelease.bat + +if "%2"=="x64K" ( + set __ARCH=x64 + set __ARCH_MS=amd64 + set RBIN_KF=%WIX%\%__OS%\bin\bin\kernel\objfre_%__OS%_amd64 + goto OK_ARCH +) + +if "%2"=="ia64K" ( + set __ARCH=ia64 + set __ARCH_MS=ia64 + set RBIN_KF=%WIX%\%__OS%\bin\bin\kernel\objfre_%__OS%_ia64 + goto OK_ARCH +) + +echo %0: Invalid Arch type '%2' use one of x86, x64, ia64 +exit /B 1 + +:OK_ARCH + +rem validate OS & arch combination +if not "%__OS%" == "wxp" goto OK_os_arch +if "%__ARCH%" == "x86" goto OK_os_arch +echo %0 - %__OS% only supports x86 architecture. +exit /B 1 + +:OK_os_arch + +rem process build option +if "%3" == "" goto usage +if "%3" == "all" goto OK +if "%3" == "allnoforce" goto OK +if "%3" == "allnf" goto allf +if "%3" == "allf" ( +:allf + if "%4" == "" goto usage + if exist "%4" goto OK + echo %0 Err - path .\%4 does not exist? + exit /B 1 +) +if "%3" == "compile" goto OK +if "%3" == "compilenoforce" goto OK +if "%3" == "compf" goto allf +if "%3" == "compnf" goto allf +if "%3" == "makebin" goto OK +if "%3" == "msi" goto OK +if "%3" == "sign" goto OK +if "%3" == "wix" goto OK +if "%3" == "clean" goto OK + +echo Unknown option '%3' ? + +:usage + +echo usage: Build1 OS Arch cmd {build-this-path} +echo OS - [win7,wlh,wnet,wxp] +echo Arch - [x86,x64,ia64] +echo 'option' may be: +echo all - force recompile, install binaries to WIX tree(makebin), +echo sign drivers and build one installer. +echo allnoforce - recompile only if needed, makebin, sign drivers and +echo build one installer. +echo allf path - force recompile the specified folder, makebin, +echo sign drivers and build installers. +echo allnf path - No-force recompile (all arch*) specified folder +echo compile - force a recompile/link of everything then exit. +echo compilenoforce - recompile/link only if needed then exit. +echo compf path - force recompile (all arch*) specified folder +echo compnf path - No-force recompile (all arch*) specified folder +echo makebin - assumes binaries are built, installs binaries to WIX tree +echo then exit. +echo msi - assumes binaries are installed in WIX tree, signs drivers and +echo create installers (.msi files) in IDIR. +echo sign - assumes binaries are built and installed, sign drivers, exit. +echo wix - build .msi installers, assumes (drivers signed) .cat files exist +echo clean - remove build artifacts for a clean build: .obj, .sys, ... +echo. +echo example: Bld wlh x64 all +exit /B 1 + +:OK + +if not "%WDM_INC_PATH%" == "" ( + echo %0: Error - unable to run from WDK window, + echo use %comspec% + exit /B 1 +) + +rem assumes %CD% == '<...>\gen1\trunk' + +set BSE=%CD% + +set MKBIN=%BSE%\etc\makebin.bat +if not EXIST "%MKBIN%" ( + echo %0: Error - missing file %MKBIN% + exit /B 1 +) + +rem remove build artifacts +if "%3" == "clean" ( + echo Removing build artifacts for %__OS% %__ARCH% + + if "%X86_REBUILD%" == "true" ( + call %CD%\etc\clean-build.bat %__OS% x86 + ) + + if not "%__ARCH%" == "x86" ( + call %CD%\etc\clean-build.bat %__OS% %__ARCH% + ) + + if exist %IDIR%\OFED_%__OS%_%__ARCH%.msi ( + echo Removing %IDIR%\OFED_%__OS%_%__ARCH%.msi + del /F %IDIR%\OFED_%__OS%_%__ARCH%.msi + ) + exit /B 0 +) + +rem Driver Signing Certificate filename, assumes Microsoft cross-cert file +rem %WIX%\%CERTFILE% is valid. +rem set CERTFILE=noCert +set CERTFILE=MSCV-VSClass3.cer + +set SW_PUBLISHER="OpenFabrics Alliance" + +rem A Digital driver signing certificate store name may be required. + +if "%3" == "all" goto chk_cert +if "%3" == "allf" goto chk_cert +if "%3" == "msi" goto chk_cert +if "%3" == "sign" goto chk_cert + +goto cert_OK + +:chk_cert + +if "%CERTFILE%" == "noCert" set /P CERTFILE=[Enter Cross Certificate FileName] + +if "%CERTFILE%" == "" ( + echo %0 + echo %0: Err - MS cross certificate %CERTFILE% required. + echo %0: see certmgr.exe + exit /B 1 +) + +if Not EXIST "%WIX%\%CERTFILE%" ( + echo %0 + echo %0: Err - MS cross certificate %WIX%\%CERTFILE% required. + exit /B 1 +) + +rem Required WIX files +if Not EXIST "%WIX%\banner.bmp" ( + echo %0 + echo %0: Err - %WIX%\banner.bmp required. + exit /B 1 +) + +if Not EXIST "%WIX%\dialog.bmp" ( + echo %0 + echo %0: Err - %WIX%\dialog.bmp required. + exit /B 1 +) + +:cert_OK + +rem Use this WDK + +rem Windows 7 WDK +set _DDK_VER=7600.16385.1 +set _COIN_VER=01009 + +rem Full DDK root path +set _DDK=%SystemDrive%\WinDDK\%_DDK_VER% + +if NOT EXIST %_DDK% ( + echo Missing WDK @ %_DDK% + exit /B 1 +) + +rem Platform SDK path - watchout for missing LoadPerf.h (installsp.c) + +if DEFINED PLATFORM_SDK_PATH ( + set _PSDK=%PLATFORM_SDK_PATH% +) else ( + set _PSDK=C:\PROGRA~1\MICROS~3\Windows\v6.1 +) +if NOT EXIST %_PSDK% ( + echo Missing PLATFORM SDK @ %_PSDK% + exit /B 1 +) + +if not DEFINED ND_SDK_PATH ( + set ND_SDK_PATH=C:\PROGRA~1\MICROS~4\NetworkDirect +) +if NOT EXIST %ND_SDK_PATH% ( + echo Missing Network Direct SDK @ %ND_SDK_PATH% + exit /B 1 +) + +rem set this to be the current svn commit number; overrides svn in path +rem processing. Additionally if set to 'latest' code expects ..\..\..\latest.txt +rem to contain the SVN number to use. +rem set USE_SVN=1748 +set USE_SVN=latest + +if "%3" == "allf" ( +:fp + set FPATH=%4 + goto svn +) +if "%3" == "compf" goto fp +if "%3" == "compnf" goto fp + +:svn + +rem Determine SVN value from current path. +rem WARNING - SVN value depends on the path '\openIB-windows-svn\XXX\gen1', +rem where SVN is set to XXX +rem substring[23rd...26th] chars (offset counting) == xxxx +rem Note - OPENIB_REV is assigned SVN in a child script. + +if "%USE_SVN%" == "" ( + set SVN=%CD:~22,4% +) else ( + if "%USE_SVN%" == "latest" ( +rem set /P SVN=\WinOF\WIX\WIX_tools\ +rem +if NOT EXIST %WIX%\WIX_tools\%WIX_BIN% ( + echo %0 - Missing WIX tools @ %WIX%\WIX_tools\%WIX_BIN% + exit /B 1 +) + +set STIME=%TIME% + +rem skip build - assumes binaries already built and installed. + +if "%3" == "wix" ( + set MSI_CMD=msi + goto mk_msi +) + +if "%3" == "makebin" goto InstallBin + +if "%3" == "sign" ( + set MSI_CMD=%3 + goto do_msi_chk +) else ( + set MSI_CMD=all +) +if "%3" == "msi" goto do_msi_chk +goto compile + +:do_msi_chk + +rem make sure building a msi has files to work with. +if not EXIST "%RBIN_KF%" goto InstallBin +goto mk_msi + +:compile + +set OPS=-wgcPM 3 +if "%3" == "allnoforce" ( + rem Compile everything only if needed. + set OPS=-wgPM 3 +) +if "%3" == "compilenoforce" ( + rem Compile everything only if needed. + set OPS=-wgPM 3 +) +if "%3" == "allf" ( + rem Force Compile everything + set OPS=-wgcfPM 3 +) +if "%3" == "compf" ( + rem Force Compile everything + set OPS=-wgcfPM 3 +) +if "%3" == "compnf" ( + rem Force Compile everything + set OPS=-wgPM 3 +) + +if "%3" == "all" ( + echo Removing build artifacts and folders for %__OS% %__ARCH% + if not "%__ARCH%" == "x86" ( + call %CD%\etc\clean-build.bat %__OS% %__ARCH% + echo Removing build artifacts and folders for %__OS% x86 + ) + if "%X86_REBUILD%" == "true" ( + call %CD%\etc\clean-build.bat %__OS% x86 + ) + if exist %IDIR%\OFED_%__OS%_%__ARCH%.msi ( + echo Removing %IDIR%\OFED_%__OS%_%__ARCH%.msi + del /F %IDIR%\OFED_%__OS%_%__ARCH%.msi + ) +) + +rem ************ Setup Env for Building + +set WDK_PATH=%_DDK% +set WINOF_PATH=%CD% +set OPENIB_REV=%SVN% +if not DEFINED PLATFORM_SDK_PATH set PLATFORM_SDK_PATH=%_PSDK% + +rem Compile in a specific folder? compf | compnf | allf +if EXIST "%FPATH%" pushd %FPATH% + +rem **** Compile for specific OS & architecture + +rem always build x86 as sysWOW64 x86 binaries are needed. +rem Unless arch specified as x64K or ia64K which imply x86 does not need regen. + +if Not "%__ARCH%" == "x86" ( + if "%X86_REBUILD%" == "true" ( + echo Build x86 binaries for sysWOW64 + %COMSPEC% /C "%BSE%\etc\bldwo.bat chk x86 %__BOS% %OPS%" + if ERRORLEVEL 1 exit /B 1 + ) +) +echo %0 - Checked build %__OS% %__BOS% %__ARCH% +%COMSPEC% /C "%BSE%\etc\bldwo.bat chk %__ARCH% %__BOS% %OPS%" +if ERRORLEVEL 1 exit /B 1 + +rem Free build + +if Not "%__ARCH%" == "x86" ( + if "%X86_REBUILD%" == "true" ( + echo free build x86 binaries for sysWOW64 + %COMSPEC% /C "%BSE%\etc\bldwo.bat fre x86 %__BOS% %__ARCH% %OPS%" + if ERRORLEVEL 1 exit /B 1 + ) +) +echo %0 - Free build %__OS% %__ARCH% +%COMSPEC% /C "%BSE%\etc\bldwo.bat fre %__ARCH% %__BOS% %OPS%" +if ERRORLEVEL 1 exit /B 1 + +rem compnf | compf | allf +if EXIST "%FPATH%" popd + +if "%3" == "compf" goto finito +if "%3" == "compnf" goto finito +if "%3" == "compile" goto finito +if "%3" == "compilenoforce" goto finito + +rem Install binaries into WIX environment, build msi installers. + +:InstallBin + +echo Create binary release tree - suitible for OFED-WIX installer build. + +if not EXIST %RBIN% ( + mkdir %RBIN% +) else ( + rem clean out OS & arch files. + + pushd %RBIN% + + call %BSE%\etc\clean-build.bat %__OS% x86 + + if not "%__ARCH%" == "x86" ( + call %BSE%\etc\clean-build.bat %__OS% %__ARCH% + ) + for /F %%i in ('dir /S/B x86') DO ( + if exist "%%i" rmdir /S/Q %%i + ) + if not "%__ARCH%" == "x86" ( + for /F %%i in ('dir /S/B %__ARCH%') DO ( + if exist "%%i" rmdir /S/Q %%i + ) + for /F %%i in ('dir /S/B %__ARCH_MS%') DO ( + if exist "%%i" rmdir /S/Q %%i + ) + ) + popd +) + +if not "%__ARCH%" == "x86" ( + rem populate for SysWow64 binaries + call %MKBIN% %BSE% %RBIN% %__OS% x86 %_DDK% %_COIN_VER% + if ERRORLEVEL 1 ( + echo %0: Err: %MKBIN% %BSE% %RBIN% %__OS% x86 %_DDK% %_COIN_VER% + exit /B 1 + ) +) + +call %MKBIN% %BSE% %RBIN% %__OS% %__ARCH% %_DDK% %_COIN_VER% +if ERRORLEVEL 1 ( + echo %0: Err: %MKBIN% %BSE% %RBIN% %__OS% %__ARCH% %_DDK% %_COIN_VER% + exit /B 1 +) + +if "%3" == "makebin" goto finito + +:mk_msi + +echo %0 - Drivers Signed with %CERTFILE% +echo Binary release tree created in +echo %RBIN% + +rem sign drivers & build WIX installers --> see WinOF\WIX + +%COMSPEC% /V:on /E:on /C "%_DDK%\bin\setenv.bat %_DDK% fre X64 WNET no_oacr & cd /D %WIX% & build-all-MSI %MSI_CMD% %CERTFILE% %SW_PUBLISHER% %IDIR% %__OS% %__ARCH%" + +:finito + +echo. +echo %0: Finished %0 %* +echo %0: Started %STIME% +echo %0: Finished %TIME% + +:xit + +endlocal diff --git a/branches/WOF2-3/OFED/BuildRelease.bat b/branches/WOF2-3/OFED/BuildRelease.bat new file mode 100644 index 00000000..ee1d2ff4 --- /dev/null +++ b/branches/WOF2-3/OFED/BuildRelease.bat @@ -0,0 +1,615 @@ +@echo off +setlocal +rem tabstop=4 + +rem version: 2.1.1 + +rem EXAMPLE - Build entire openIB-windows release & WIX installers (.msi) files. +rem Binary release is constructed in OFED\Wix\OS\bin. +rem Processor architecture specific WIX installers are constructed +rem in %IDIR% +rem +rem BuildRelease option +rem option: all | allnoforce | allf | allnf | compile | compilenoforce | +rem compf path | compnf path | makebin | msi |sign | wix | clean | +rem msi-label | msi-del | msi-dir {OPENIB_REV} + +rem This script is an 'example' of a one-command entire IB stack build to +rem single-file installer; used to build a OFED releases. +rem Script is designed to be invoked from the \gen1\trunk folder with +rem \gen1\trunk\OFED\Wix\* present. +rem +rem Verify the following env vars are suitible for your system configuration. +rem _DDK, _PSDK, SVN, IDIR, CERTFILE, SW_PUBLISHER + +rem 'nf path' command variants are required due to a bug in the WDK build env. +rem ipoib\ & ipoib_ndis6_cm\ both build ipoib.sys just for different OS +rem versions. The problem arises when a compile is forced on one folder or the +rem other, all instances of ipoib.sys are deleted + +rem WIX Installer files (.msi) destination folder - set for local environment. +set IDIR=%SystemRoot%\temp + +if "%1" == "" goto usage +if "%1" == "/?" goto usage +if "%1" == "-h" goto usage +if "%1" == "all" goto OK +if "%1" == "allnoforce" goto OK +if "%1" == "allf" ( +:allf + if "%2" == "" goto usage + set FPATH=%2 + if exist "%2" goto OK + echo %0 Err - path .\%2 does not exist? + exit /B 1 +) +if "%1" == "allnf" goto allf +if "%1" == "compile" goto OK +if "%1" == "compilenoforce" goto OK +if "%1" == "compf" ( +:cpf + if "%2" == "" goto usage + set FPATH=%2 + if exist "%2" goto OK + echo %0 Err - path .\%2 does not exist? + exit /B 1 +) +if "%1" == "compnf" goto cpf +if "%1" == "makebin" goto OK +if "%1" == "msi" goto OK +if "%1" == "sign" goto OK +if "%1" == "wix" goto OK +if "%1" == "clean" goto OK +if "%1" == "msi-label" goto OK +if "%1" == "msi-del" goto OK +if "%1" == "msi-dir" goto OK + +echo Unknown arg '%1' ? + +:usage + +echo "usage: BuildRelease command {OPENIB_REV value}" +echo where 'command' may be: +echo all - force recompile, install binaries to WIX tree(makebin), +echo sign drivers and build installers. +echo allnoforce - recompile only if needed, makebin, sign drivers and +echo build installers. +echo allf path - force recompile the specified folder, makebin, +echo sign drivers and build installers. +echo allnf path - recompile specified folder ONLY if required, makebin, +echo sign drivers and build installers. +echo compile - force a recompile/link of everything then exit. +echo compilenoforce - recompile/link only if needed then exit. +echo compf path - force recompile (all arch*) specified folder +echo compnf path - No-force recompile (all arch*) specified folder +echo makebin - assumes binaries are built, installs binaries to WIX tree +echo then exit. +echo msi - assumes binaries are installed in WIX tree, signs drivers and +echo create installers (.msi files) in IDIR. +echo sign - assumes binaries are built and installed, sign drivers, exit. +echo wix - build .msi installers, assumes (drivers signed) .cat files exist +echo clean - remove build artifacts for a clean build: .obj, .sys, ... +echo msi-label {OPENIB_REV} +echo rename WOF_os*_arch*.msi to WOF_os*_arch*_svn#.msi +echo Uniquely identify installers just created. +echo If OPENIB_REV arg used, then rename WOF_os*_arch*argVal.msi +echo otherwise, use SVN# from path. +echo msi-del - del %windir%\temp\WOF_os*_arch*.msi +echo msi-dir - del %windir%\temp\WOF_os*_arch*.msi +echo : +echo {OPENIB_REV} +echo optional, if set then OPENIB_REV is assigned this value. +echo example: BuildRelease all 1414 + +exit /B 1 + +:OK + +if not "%WDM_INC_PATH%" == "" ( + echo %0: Error - %0 unable to run from WDK window, + echo use %comspec% + exit /B 1 +) + +rem assumes %CD% == '<...>\gen1\trunk' +set BSE=%CD% +set WIX=%CD%\OFED\WIX + +rem Setup Wix 3.0 items + +set WIX_BIN=wix3.0.5419.0-binaries + + +set RBIN_W7=%WIX%\win7\bin% +set RBIN_WLH=%WIX%\wlh\bin% +set RBIN_WNET=%WIX%\wnet\bin% +set RBIN_WXP=%WIX%\wxp\bin% + +rem remove build artifacts +if "%1" == "clean" ( + echo Removing build artifacts and folders... + call %CD%\etc\clean-build.bat + if exist %WIX%\win7\bin ( + echo Removing %WIX%\win7\bin + rmdir /Q /S %WIX%\win7\bin + ) + if exist %WIX%\wlh\bin ( + echo Removing %WIX%\wlh\bin + rmdir /Q /S %WIX%\wlh\bin + ) + if exist %WIX%\wnet\bin ( + echo Removing %WIX%\wnet\bin + rmdir /Q /S %WIX%\wnet\bin + ) + if exist %WIX%\wxp\bin ( + echo Removing %WIX%\wxp\bin + rmdir /Q /S %WIX%\wxp\bin + ) + exit /B 0 +) + +rem Driver Signing Certificate filename, assumes %WIX%\%CERTFILE% is valid. +rem set CERTFILE=noCert +set CERTFILE=MSCV-VSClass3.cer +set SW_PUBLISHER="OpenFabrics Alliance" + +rem A Digital driver signing certificate store name may be required. + +if "%1" == "all" goto chk_cert +if "%1" == "allf" goto chk_cert +if "%1" == "allnf" goto chk_cert +if "%1" == "msi" goto chk_cert +if "%1" == "sign" goto chk_cert + +goto cert_OK + +:chk_cert + +if "%CERTFILE%" == "noCert" set /P CERTFILE=[Enter Cross Certificate FileName] + +if "%CERTFILE%" == "" ( + echo %0 + echo %0: Err - MS cross certificate %CERTFILE% required. + echo %0: see certmgr.exe + exit /B 1 + ) +) + +rem Required WIX files +if Not EXIST "%WIX%\banner.bmp" ( + echo %0 + echo %0: Err - %WIX%\banner.bmp required. + exit /B 1 +) + +if Not EXIST "%WIX%\dialog.bmp" ( + echo %0 + echo %0: Err - %WIX%\dialog.bmp required. + exit /B 1 +) + +:cert_OK + +rem WDK setup + +rem Windows 7 WDK 7600_1, 7600_0 was the last. +set _DDK_VER=7600.16385.1 +set _COIN_VER=01009 + +rem Full DDK root path +set _DDK=%SystemDrive%\WinDDK\%_DDK_VER% + +if NOT EXIST %_DDK% ( + echo Missing WDK @ %_DDK% + exit /B 1 +) + +rem Platform SDK path - watchout for missing LoadPerf.h (installsp.c) + +if DEFINED PLATFORM_SDK_PATH ( + set _PSDK=%PLATFORM_SDK_PATH% +) else ( + set _PSDK=C:\PROGRA~1\MICROS~3\Windows\v6.1 +) +if NOT EXIST %_PSDK% ( + echo Missing PLATFORM SDK @ %_PSDK% + exit /B 1 +) + +if not DEFINED ND_SDK_PATH ( + set ND_SDK_PATH=C:\PROGRA~1\MICROS~4\NetworkDirect +) +if NOT EXIST %ND_SDK_PATH% ( + echo Missing Network Direct SDK @ %ND_SDK_PATH% + exit /B 1 +) + +rem set this to be the current svn commit number; overrides svn in path +rem processing. Additionally if set to 'latest' code expects ..\..\..\latest.txt +rem to contain the SVN number to use. +rem set USE_SVN=1748 +set USE_SVN=latest + +rem %2 can be either a file spec or IPENIB_REV value. +rem Based on %1 command, FPATH will/will-not be set to a file spec. + +if Not "%FPATH%" == "" goto svn + +rem setup value for OPENIB_REV assignment +if not "%2" == "" ( + rem set SVN commit number. + set SVN=%2 + set LBL=%2 + goto svn_set +) + +:svn + +rem Determine SVN value from current path. +rem WARNING - SVN value depends on the path '\openIB-windows-svn\XXX\gen1', +rem where SVN is set to XXX +rem substring[23rd...26th] chars (offset counting) == xxxx +rem Note - OPENIB_REV is assigned SVN in a child script. + +if "%USE_SVN%" == "" ( + set SVN=%CD:~22,4% +) else ( + if "%USE_SVN%" == "latest" ( +rem set /P SVN=\OFED\WIX\WIX_tools\ +rem +if NOT EXIST %WIX%\WIX_tools\%WIX_BIN% ( + echo %0 - Missing WIX tools @ %WIX%\WIX_tools\%WIX_BIN% + exit /B 1 +) + +set MKBIN=%BSE%\etc\makebin.bat + +if NOT EXIST "%MKBIN%" ( + echo %0 - Missing %MKBIN%, script must run from trunk\ equivalent. + exit /B 1 +) + +set STIME=%TIME% + +rem skip build - assumes binaries already built and installed. + +if "%1" == "wix" ( + set MSI_CMD=msi + goto mk_msi +) + +if "%1" == "makebin" goto InstallBin + +rem poor man's OR +if "%1" == "sign" ( + set MSI_CMD=%1 + goto do_msi_chk +) else ( + set MSI_CMD=all +) +if "%1" == "msi" goto do_msi_chk +goto compile + +:do_msi_chk + +rem make sure building a msi has files to work with. +if not EXIST "%RBIN_W7%" goto InstallBin +if not EXIST "%RBIN_WLH%" goto InstallBin +if not EXIST "%RBIN_WNET%" goto InstallBin +if not EXIST "%RBIN_WXP%" goto InstallBin +goto mk_msi + +:compile + +set OPS=-wgcPM 3 +if "%1" == "allnoforce" ( + rem Compile everything only if needed. + set OPS=-wgPM 3 +) +if "%1" == "compilenoforce" ( + rem Compile everything only if needed. + set OPS=-wgPM 3 +) +if "%1" == "allf" ( + rem Force Compile everything + set OPS=-wgcfPM 3 +) +if "%1" == "allnf" ( + rem Compile only if necessary + set OPS=-wgPM 3 +) +if "%1" == "compf" ( + rem Force Compile everything + set OPS=-wgcfPM 3 +) +if "%1" == "compnf" ( + rem Compile only if necessary + set OPS=-wgPM 3 +) + +if "%1" == "all" ( + echo Removing build artifacts and folders... + call %CD%\etc\clean-build.bat + if exist %WIX%\wlh\bin ( + echo Removing %WIX%\wlh\bin + rmdir /Q /S %WIX%\wlh\bin + ) + if exist %WIX%\wnet\bin ( + echo Removing %WIX%\wnet\bin + rmdir /Q /S %WIX%\wnet\bin + ) + if exist %WIX%\wxp\bin ( + echo Removing %WIX%\wxp\bin + rmdir /Q /S %WIX%\wxp\bin + ) +) + +rem ************ Setup Env for Building + +set WDK_PATH=%_DDK% +set WINOF_PATH=%CD% +set OPENIB_REV=%SVN% +if not DEFINED PLATFORM_SDK_PATH set PLATFORM_SDK_PATH=%_PSDK% + +rem Compile in a specific folder? compf | compnf | allf | allnf +if EXIST "%FPATH%" pushd %FPATH% + +rem ********* Compile for win7 - Windows 7 + +rem win7 x64 +echo %0 - Build win7 x64 Checked +%COMSPEC% /C "%BSE%\etc\bldwo.bat chk x64 win7 %OPS%" +if ERRORLEVEL 1 exit /B 1 +echo %0 - Build win7 x64 Free +%COMSPEC% /C "%BSE%\etc\bldwo.bat fre x64 win7 %OPS%" +if ERRORLEVEL 1 exit /B 1 + +rem win7 x86 +echo %0 - Build win7 x86 Checked +%COMSPEC% /C "%BSE%\etc\bldwo.bat chk x86 win7 %OPS%" +if ERRORLEVEL 1 exit /B 1 +echo %0 - Build win7 x86 Free +%COMSPEC% /C "%BSE%\etc\bldwo.bat fre x86 win7 %OPS%" +if ERRORLEVEL 1 exit /B 1 + +rem win7 ia64 +echo %0 - Build win7 ia64 Checked +%COMSPEC% /C "%BSE%\etc\bldwo.bat chk ia64 win7 %OPS%" +if ERRORLEVEL 1 exit /B 1 +echo %0 - Build win7 ia64 Free +%COMSPEC% /C "%BSE%\etc\bldwo.bat fre ia64 win7 %OPS%" +if ERRORLEVEL 1 exit /B 1 + +rem ********* Compile for WLH - Windows Server 2008 & Vista + +rem WLH x64 +echo %0 - Build WLH x64 Checked +%COMSPEC% /C "%BSE%\etc\bldwo.bat chk x64 2008 %OPS%" +if ERRORLEVEL 1 exit /B 1 +echo %0 - Build WLH x64 Free +%COMSPEC% /C "%BSE%\etc\bldwo.bat fre x64 2008 %OPS%" +if ERRORLEVEL 1 exit /B 1 + +rem WLH x86 +echo %0 - Build WLH x86 Checked +%COMSPEC% /C "%BSE%\etc\bldwo.bat chk x86 2008 %OPS%" +if ERRORLEVEL 1 exit /B 1 +echo %0 - Build WLH x86 Free +%COMSPEC% /C "%BSE%\etc\bldwo.bat fre x86 2008 %OPS%" +if ERRORLEVEL 1 exit /B 1 + +rem WLH ia64 +echo %0 - Build WLH ia64 Checked +%COMSPEC% /C "%BSE%\etc\bldwo.bat chk ia64 2008 %OPS%" +if ERRORLEVEL 1 exit /B 1 +echo %0 - Build WLH ia64 Free +%COMSPEC% /C "%BSE%\etc\bldwo.bat fre ia64 2008 %OPS%" +if ERRORLEVEL 1 exit /B 1 + +rem ********* WXP - Windows XP - x86 only + +echo %0 - Build XP x86 Checked +%COMSPEC% /C "%BSE%\etc\bldwo.bat chk x86 xp %OPS%" +if ERRORLEVEL 1 exit /B 1 +echo %0 - Build XP x86 Free +%COMSPEC% /C "%BSE%\etc\bldwo.bat fre x86 xp %OPS%" +if ERRORLEVEL 1 exit /B 1 + +rem ********* WNET - Windows Server 2003 + +echo %0 - Build WNET x64 Checked +%COMSPEC% /C "%BSE%\etc\bldwo.bat chk x64 2003 %OPS%" +if ERRORLEVEL 1 exit /B 1 +echo %0 - Build WNET x64 Free +%COMSPEC% /C "%BSE%\etc\bldwo.bat fre x64 2003 %OPS%" +if ERRORLEVEL 1 exit /B 1 + +echo %0 - Build WNET x86 Checked +%COMSPEC% /C "%BSE%\etc\bldwo.bat chk x86 2003 %OPS%" +if ERRORLEVEL 1 exit /B 1 +echo %0 - Build WNET x86 Free +%COMSPEC% /C "%BSE%\etc\bldwo.bat fre x86 2003 %OPS%" +if ERRORLEVEL 1 exit /B 1 + +echo %0 - Build WNET ia64 Checked +%COMSPEC% /C "%BSE%\etc\bldwo.bat chk ia64 2003 %OPS%" +if ERRORLEVEL 1 exit /B 1 +echo %0 - Build WNET ia64 Free +%COMSPEC% /C "%BSE%\etc\bldwo.bat fre ia64 2003 %OPS%" +if ERRORLEVEL 1 exit /B 1 + +rem compnf | compf | allf | allnf +if EXIST "%FPATH%" popd + +if "%1" == "compf" goto finito +if "%1" == "compnf" goto finito +if "%1" == "compile" goto finito +if "%1" == "compilenoforce" goto finito + +rem Install binaries into WIX environment, build msi installers. + +:InstallBin + +echo Create binary release tree - suitible for OFED-WIX installer build. + +if EXIST "%RBIN_W7%" (rmdir /S /Q %RBIN_W7% & echo %0 - removed %RBIN_W7%) +if EXIST "%RBIN_WLH%" (rmdir /S /Q %RBIN_WLH% & echo %0 - removed %RBIN_WLH%) +if EXIST "%RBIN_WNET%" (rmdir /S /Q %RBIN_WNET% & echo %0 - removed %RBIN_WNET%) +if EXIST "%RBIN_WXP%" (rmdir /S /Q %RBIN_WXP% & echo %0 - removed %RBIN_WXP%) + +mkdir %RBIN_W7% +mkdir %RBIN_WLH% +mkdir %RBIN_WNET% +mkdir %RBIN_WXP% + + +for %%i in ( x64 x86 ia64 ) do ( + call %MKBIN% %BSE% %RBIN_W7% win7 %%i %_DDK% %_COIN_VER% + if ERRORLEVEL 1 ( + echo %0: Err in %MKBIN% %BSE% %RBIN_W7% wlh %%i %_DDK% %_COIN_VER% + exit /B 1 + ) +) + +for %%i in ( x64 x86 ia64 ) do ( + call %MKBIN% %BSE% %RBIN_WLH% wlh %%i %_DDK% %_COIN_VER% + if ERRORLEVEL 1 ( + echo %0: Err in %MKBIN% %BSE% %RBIN_WLH% wlh %%i %_DDK% %_COIN_VER% + exit /B 1 + ) +) + +for %%i in ( x64 x86 ia64 ) do ( + call %MKBIN% %BSE% %RBIN_WNET% wnet %%i %_DDK% %_COIN_VER% + if ERRORLEVEL 1 ( + echo %0: Err in %MKBIN% %BSE% %RBIN_WNET% wnet %%i %_DDK% %_COIN_VER% + exit /B 1 + ) +) + +call %MKBIN% %BSE% %RBIN_WXP% wxp x86 %_DDK% %_COIN_VER% +if ERRORLEVEL 1 ( + echo %0: Err in %MKBIN% %BSE% %RBIN_WXP% wxp x86 %_DDK% %_COIN_VER% + exit /B 1 +) + +if "%1" == "makebin" goto finito + +:mk_msi + +echo %0 - Drivers Signed with %CERTFILE% +echo Binary release trees in +echo %RBIN_W7% +echo %RBIN_WLH% +echo %RBIN_WNET% +echo %RBIN_WXP% + +rem build WIX installers --> see OFED\WIX + +%COMSPEC% /V:on /E:on /C "%_DDK%\bin\setenv.bat %_DDK% fre X64 WNET no_oacr & cd /D %WIX% & build-all-MSI %MSI_CMD% %CERTFILE% %SW_PUBLISHER% %IDIR%" + +:finito + +echo . +echo %0: Finished %0 %* +echo %0: Started %STIME% +echo %0: Finished %TIME% + +endlocal diff --git a/branches/WOF2-3/OFED/WIX/CustomActions.vbs b/branches/WOF2-3/OFED/WIX/CustomActions.vbs new file mode 100644 index 00000000..dc70266e --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/CustomActions.vbs @@ -0,0 +1,1901 @@ +'/* +' * Copyright (c) 2010 Intel Corporation. All rights reserved. +' * +' * This software is available to you under the OpenIB.org BSD license +' * below: +' * +' * Redistribution and use in source and binary forms, with or +' * without modification, are permitted provided that the following +' * conditions are met: +' * +' * - Redistributions of source code must retain the above +' * copyright notice, this list of conditions and the following +' * disclaimer. +' * +' * - Redistributions in binary form must reproduce the above +' * copyright notice, this list of conditions and the following +' * disclaimer in the documentation and/or other materials +' * provided with the distribution. +' * +' * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +' * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +' * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +' * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +' * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +' * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +' * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +' * SOFTWARE. +' */ + +' WIX CustomActions used in the OFED for Windows Release. +' File is based on the installer src contributed by Mellanox Technologies. +' +' TabStops == 4 +' +' $Id$ + +' //msdn.microsoft.com/en-us/library/d5fk67ky(VS.85).aspx +Const WindowStyle = 7 + +' VersionNT values +Const WindowsXP ="501" +Const WindowsSvr2003 ="502" +Const WindowsVista ="600" +Const WindowsSvr2008 ="600" +Const Windows7 ="601" + +Const UseDPinst = "501" ' use DPinst.exe to install drivers for + ' Windows VersionNT >= this value. + +' Global debug flag: Session.Property from msiexec.exe cmd line DBG=1 +Dim sDBG + + +' Write string to MSI log file + +Function MsiLogInfo(msg) + Dim rec + Set rec = Session.Installer.CreateRecord(1) + rec.StringData(0) = msg + MsiLogInfo = Session.Message(&H04000000, rec) +End Function + + +Sub ShowError() + If Err.Number = 0 Then + Exit Sub + End if + strMsg = vbCrLf & "Error # " & Err.Number & vbCrLf & _ + Err.Description & vbCrLf & vbCrLf + msgbox strMsg + MsiLogInfo strMsg + +End Sub + + +Sub ErrMsg(msg) + If Err.Number <> 0 Then + msgbox msg & vbCrLf & "Err # " & Err.Number & vbCrLf & Err.Description + Err.clear + End if +End Sub + +Function ShowErr2(msg) + If Err.Number <> 0 Then + strMsg = vbCrLf & "Err # " & Err.Number & vbCrLf & _ + Err.Description & vbCrLf + msgbox msg & strMsg + End if + ShowErr2=Err.Number +End Function + + +Function Architecture() + Dim Arch,item + For Each item In GetObject("winmgmts:root/cimv2").ExecQuery("SELECT Architecture FROM Win32_Processor") + Arch=item.Architecture + Exit For + Next + + If (Arch=0) Then + Arch="x86" + Elseif (Arch=1) Then + Arch="MIPS" + Elseif (Arch=2) Then + Arch="Alpha" + Elseif (Arch=3) Then + Arch="PowerPC" + Elseif (Arch=6) Then + Arch="ia64" + Elseif (Arch=9) Then + 'Arch="x64" + Arch="amd64" + Else + WScript.echo "Arch ID=" & Arch + Arch="CustomAction.vbs: Unable to determine Architecture" + End If + Architecture=Arch + +End Function + + +' A CustomAction (CA) that runs after SetupInitialize which sets up +' CustomAction Data for the defered action PostDriverInstall. +' A CA can only see Installer properties through pre-loaded 'CustomActionData' + +Sub WinOF_setup + dim VersionNT,Installed,AddLocal + + VersionNT = Session.Property("VersionNT") + Installed = Session.Property("Installed") + AddLocal = Session.Property("ADDLOCAL") + + ' The WIX UI (UserInterface) sets up ADDLOCAL. When cmd-line msiexec.exe is + ' run with a minimal UI (/passive), then ADDLOCAL is not setup correctly; + ' default it's value here. + + If AddLocal = "" AND Installed = "" Then + ' Enable default features. + AddLocal = "IBcore,fIPoIB,fDAPL,fDatBASIC1,fDatBASIC2,fND" + If VersionNT <> WindowsXP Then + AddLocal = AddLocal & ",fWSD" + End If + End If + + If Session.Property("OSM") = "1" OR Session.Property("OSMS") = "1" Then + AddLocal = AddLocal & ",fOSMS" + End If + + If Session.Property("SRP") = "1" Then + AddLocal = AddLocal & ",fSRP" + End If + + If Session.Property("VNIC") = "1" Then + AddLocal = AddLocal & ",fVNIC" + End If + + ' Driver Install Properties: + ' 0-INSTALLDIR; 1-SystemFolder; 2-System64Folder; 3-WindowsFolder ; + ' 4-VersionNT; 5-ADDLOCAL; 6-REMOVE; 7-NODRV; 8-DBG + + Session.Property("PostDriverInstall") = _ + Session.Property("INSTALLDIR") & ";" & _ + Session.Property("SystemFolder") & ";" & _ + Session.Property("System64Folder") & ";" & _ + Session.Property("WindowsFolder") & ";" & _ + VersionNT & ";" & _ + AddLocal & ";" & _ + Session.Property("REMOVE") & ";" & _ + Session.Property("NODRV") & ";" & _ + Session.Property("DBG") +End Sub + + +Sub FileDelete(filename) + Dim fso + Set fso = CreateObject("Scripting.FileSystemObject") + Err.clear + If fso.FileExists(filename) Then + On Error Resume Next + fso.DeleteFile(filename),True + If (Err And Err.Number <> 70) Then ' tolerate protection errors + ErrMsg ("Could not delete: " & filename) + End If + End If +End Sub + + +Sub FileDeleteQ(fso,filename) + Err.clear + If fso.FileExists(filename) Then + On Error Resume Next + fso.DeleteFile(filename),True + If (Err And Err.Number <> 70) Then ' tolerate protection errors + ErrMsg ("Could not delete: " & filename) + End If + End If +End Sub + + +' Move and then Delete a file. File is moved into %TEMP%\basename(filename) +' then deleted; pesky files in 'system32\drivers'. + +Function FileMove(filename,destination) + Dim fso + Set fso = CreateObject("Scripting.FileSystemObject") + On Error Resume Next + If fso.FileExists(filename) Then + fso.MoveFile filename,destination + If (Err And Err.Number <> 70) then ' tolerate protection errors. + ErrMsg ("Could not move: " & filename & " to " & destination) + End if + End If + If Err Then ShowError +End Function + + +Sub DriverFileDelete(fso,WshShell,filename) + Err.clear + If fso.FileExists(filename) Then + ' allow continuation after 'permission denied' error + On Error Resume Next + ' unlock the driver file by deleting PnPLocked reg entry. + base = "reg delete HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Setup\PnpLockdownFiles /v " + Return = WshShell.Run (base & filename & " /f", WindowStyle, true) + fso.DeleteFile(filename),True + If (Err And Err.Number <> 70) Then ' tolerate protection errors + ErrMsg ("Could not delete: " & filename) + End If + End If +End Sub + + + +' Remove the specified folder and all sub-folders & files. +' What rmdir does from the cmd line but will not do from vbs? + +Sub RemoveFolder(objStartFolder) + + Set objFSO = CreateObject("Scripting.FileSystemObject") + + If Not objFSO.FolderExists(objStartFolder) Then + Exit Sub + End if + + Set objFolder = objFSO.GetFolder(objStartFolder) + 'Wscript.Echo objFolder.Path + Set colFiles = objFolder.Files + + ' del files in top-level folder + For Each objFile in colFiles + objFSO.DeleteFile(objFolder.Path & "\" & objFile.Name) + If Err Then + ErrMsg("Del err on " & objFolder.Path & "\" & objFile.Name) + End if + Next + + ShowSubfolders objFSO.GetFolder(objStartFolder), objFSO + + On Error Resume Next + objFSO.DeleteFolder(objStartFolder) + If Err Then + ErrMsg("DelFolder err on " & objStartFolder) + End if + +End Sub + + +Sub ShowSubFolders(Folder,FSO) + On Error Resume Next + For Each Subfolder in Folder.SubFolders + ' Wscript.Echo Subfolder.Path + Set objFolder = FSO.GetFolder(Subfolder.Path) + Set colFiles = objFolder.Files + For Each objFile in colFiles + ' Wscript.Echo Subfolder.Path & "\" & objFile.Name + FSO.DeleteFile(Subfolder.Path & "\" & objFile.Name) + If Err Then + ErrMsg("DelFile err on " & Subfolder.Path & "\" & objFile.Name) + End if + Next + ' Wscript.Echo + ShowSubFolders Subfolder, FSO + FSO.DeleteFolder(Subfolder.Path) + If Err Then + ErrMsg("DelFolder err on " & Subfolder.Path) + End if + Next +End Sub + + + + +''''''''''' Remove Driver Files '''''''''''' + +' Attempt to clean out driver installed files which fail to be uninstalled +' when the driver is uninstalled. + +Sub RemoveDriverFiles(fso,WshShell) + + Dim Win, sDRIVERS, sSYS32, sSYSWOW64 + Dim CheckMode, PropArray, sTemp + + ' Function can be called from the Driver{Install/Uninstall} rtns. + + Win = fso.GetSpecialFolder(0) & "\" + + ' this is screw-ball: on 64-bit systems: SystemFolder == %windir%\SysWOW64 + ' on 32-bit systems: SystemFolder == %windir%\system32 + + sSYS32 = Win & "system32\" + sSYSWOW64 = Win & "SysWOW64\" + sDRIVERS = sSYS32 & "drivers\" + + DriverFileDelete fso,WshShell,sDRIVERS & "ibbus.sys" + DriverFileDelete fso,WshShell,sDRIVERS & "mthca.sys" + FileDeleteQ fso,sDRIVERS & "mthca.sy1" + DriverFileDelete fso,WshShell,sDRIVERS & "mlx4_bus.sys" + DriverFileDelete fso,WshShell,sDRIVERS & "mlx4_hca.sys" + DriverFileDelete fso,WshShell,sDRIVERS & "winverbs.sys" + DriverFileDelete fso,WshShell,sDRIVERS & "winverbsd.sys" + DriverFileDelete fso,WshShell,sDRIVERS & "winmad.sys" + DriverFileDelete fso,WshShell,sDRIVERS & "winmadd.sys" + DriverFileDelete fso,WshShell,sDRIVERS & "ipoib.sys" + DriverFileDelete fso,WshShell,sDRIVERS & "ibiou.sys" + DriverFileDelete fso,WshShell,sDRIVERS & "ibsrp.sys" + DriverFileDelete fso,WshShell,sDRIVERS & "vnic.sys" + DriverFileDelete fso,WshShell,sDRIVERS & "qlgcvnic.sys" + + DriverFileDelete fso,WshShell,sSYS32 & "libibverbs.dll" + DriverFileDelete fso,WshShell,sSYS32 & "libibverbsd.dll" + DriverFileDelete fso,WshShell,sSYS32 & "winmad.dll" + DriverFileDelete fso,WshShell,sSYS32 & "winmadd.dll" + DriverFileDelete fso,WshShell,sSYS32 & "winverbs.dll" + DriverFileDelete fso,WshShell,sSYS32 & "winverbsd.dll" + DriverFileDelete fso,WshShell,sSYS32 & "ibal.dll" + DriverFileDelete fso,WshShell,sSYS32 & "ibald.dll" + DriverFileDelete fso,WshShell,sSYS32 & "ibal32.dll" + DriverFileDelete fso,WshShell,sSYS32 & "ibal32d.dll" + DriverFileDelete fso,WshShell,sSYS32 & "complib.dll" + DriverFileDelete fso,WshShell,sSYS32 & "complibd.dll" + DriverFileDelete fso,WshShell,sSYS32 & "cl32.dll" + DriverFileDelete fso,WshShell,sSYS32 & "cl32d.dll" + DriverFileDelete fso,WshShell,sSYS32 & "mthcau.dll" + DriverFileDelete fso,WshShell,sSYS32 & "mthcaud.dll" + DriverFileDelete fso,WshShell,sSYS32 & "mthca32.dll" + DriverFileDelete fso,WshShell,sSYS32 & "mthca32d.dll" + DriverFileDelete fso,WshShell,sSYS32 & "mlx4u.dll" + DriverFileDelete fso,WshShell,sSYS32 & "mlx4ud.dll" + DriverFileDelete fso,WshShell,sSYS32 & "mlx4u32.dll" + DriverFileDelete fso,WshShell,sSYS32 & "mlx4u32d.dll" + DriverFileDelete fso,WshShell,sSYS32 & "ibsrp.dll" + DriverFileDelete fso,WshShell,sSYS32 & "ibsrpd.dll" + DriverFileDelete fso,WshShell,sSYS32 & "IbInstaller.dll" + DriverFileDelete fso,WshShell,sSYS32 & "ibwsd.dll" + DriverFileDelete fso,WshShell,sSYS32 & "ibndprov.dll" + DriverFileDelete fso,WshShell,sSYS32 & "ndinstall.exe" + DriverFileDelete fso,WshShell,sSYS32 & "wvndpov.dll" + + If fso.FolderExists(sSYSWOW64) Then + DriverFileDelete fso,WshShell,sSYSWOW64 & "ibal.dll" + DriverFileDelete fso,WshShell,sSYSWOW64 & "ibald.dll" + DriverFileDelete fso,WshShell,sSYSWOW64 & "complib.dll" + DriverFileDelete fso,WshShell,sSYSWOW64 & "complibd.dll" + DriverFileDelete fso,WshShell,sSYSWOW64 & "mthcau.dll" + DriverFileDelete fso,WshShell,sSYSWOW64 & "mthcaud.dll" + DriverFileDelete fso,WshShell,sSYSWOW64 & "mlx4u.dll" + DriverFileDelete fso,WshShell,sSYSWOW64 & "mlx4ud.dll" + DriverFileDelete fso,WshShell,sSYSWOW64 & "ibsrp.dll" + DriverFileDelete fso,WshShell,sSYSWOW64 & "ibsrpd.dll" + DriverFileDelete fso,WshShell,sSYSWOW64 & "IbInstaller.dll" + DriverFileDelete fso,WshShell,sSYSWOW64 & "ibwsd.dll" + DriverFileDelete fso,WshShell,sSYSWOW64 & "ibndprov.dll" + DriverFileDelete fso,WshShell,sSYSWOW64 & "wvndprov.dll" + End If + + If fso.FolderExists(Win & "lastgood" ) Then + FileDeleteQ fso,Win & "lastgood\system32\ibal.dll" + FileDeleteQ fso,Win & "lastgood\system32\ibald.dll" + FileDeleteQ fso,Win & "lastgood\system32\complib.dll" + FileDeleteQ fso,Win & "lastgood\system32\complibd.dll" + FileDeleteQ fso,Win & "lastgood\system32\winverbs.dll" + FileDeleteQ fso,Win & "lastgood\system32\winverbsd.dll" + FileDeleteQ fso,Win & "lastgood\system32\winmad.dll" + FileDeleteQ fso,Win & "lastgood\system32\winmadd.dll" + + FileDeleteQ fso,Win & "lastgood\system32\ibndprov.dll" + FileDeleteQ fso,Win & "lastgood\system32\wvndprov.dll" + FileDeleteQ fso,Win & "lastgood\system32\ndinstall.exe" + FileDeleteQ fso,Win & "lastgood\system32\ibwsd.dll" + + FileDeleteQ fso,Win & "lastgood\SysWOW64\ibndprov.dll" + FileDeleteQ fso,Win & "lastgood\SysWOW64\wvndprov.dll" + FileDeleteQ fso,Win & "lastgood\SysWOW64\ibwsd.dll" + FileDeleteQ fso,Win & "lastgood\SysWOW64\mthcau.dll" + FileDeleteQ fso,Win & "lastgood\SysWOW64\mthcaud.dll" + FileDeleteQ fso,Win & "lastgood\SysWOW64\mlx4u.sys" + FileDeleteQ fso,Win & "lastgood\SysWOW64\mlx4ud.sys" + + FileDeleteQ fso,Win & "lastgood\system32\mthcau.dll" + FileDeleteQ fso,Win & "lastgood\system32\mthcaud.dll" + + FileDeleteQ fso,Win & "lastgood\system32\drivers\ipoib.sys" + FileDeleteQ fso,Win & "lastgood\system32\drivers\ibbus.sys" + FileDeleteQ fso,Win & "lastgood\system32\drivers\mthcau.dll" + FileDeleteQ fso,Win & "lastgood\system32\drivers\mthcaud.dll" + FileDeleteQ fso,Win & "lastgood\system32\drivers\mthca.sys" + FileDeleteQ fso,Win & "lastgood\system32\drivers\mlx4u.sys" + FileDeleteQ fso,Win & "lastgood\system32\drivers\mlx4ud.sys" + FileDeleteQ fso,Win & "lastgood\system32\drivers\mlx4_bus.sys" + FileDeleteQ fso,Win & "lastgood\system32\drivers\mlx4_hca.sys" + FileDeleteQ fso,Win & "lastgood\system32\drivers\winverbs.sys" + FileDeleteQ fso,Win & "lastgood\system32\drivers\winverbsd.sys" + FileDeleteQ fso,Win & "lastgood\system32\drivers\winmad.sys" + FileDeleteQ fso,Win & "lastgood\system32\drivers\winmadd.sys" + End If + + FileDeleteQ fso,Win & "winverbs.lib" + FileDeleteQ fso,Win & "libibverbs.lib" + + ' delete opensm files + sTemp = fso.GetSpecialFolder(0) & "\temp\" + ' remove files from %SystemRoot%\temp + FileDeleteQ fso,sTemp & "guid2lid" + FileDeleteQ fso,sTemp & "opensm-sa.dump" + FileDeleteQ fso,sTemp & "osm.log" + FileDeleteQ fso,sTemp & "osm-subnet.lst" + +End Sub + + +''''''''''' Delete registry key '''''''''''' + +Function DeleteRegKey(KeyPath) + Const HKEY_LOCAL_MACHINE = &H80000002 + dim strComputer + strComputer = "." + Set objReg=GetObject("winmgmts:" & _ + "{impersonationLevel=impersonate}!\\" & _ + strComputer & "\root\default:StdRegProv") + + ' Display error number and description if applicable + ' If Err Then ShowError + Return = objReg.DeleteKey(HKEY_LOCAL_MACHINE, KeyPath) + +End Function + + +''''''''''' Delete registry value '''''''''''' + +Function DeleteRegValue(strKeyPath, strValueName) + Const HKEY_LOCAL_MACHINE = &H80000002 + + dim strComputer + strComputer = "." + + Set objReg=GetObject("winmgmts:" & _ + "{impersonationLevel=impersonate}!\\" & _ + strComputer & "\root\default:StdRegProv") + + + Return = objReg.DeleteValue(HKEY_LOCAL_MACHINE, strKeyPath, strValueName) + ' Display error number and description if applicable + If Err Then ShowError +' If (Return = 0) And (Err.Number = 0) Then +' WScript.Echo value & "Registry value HKEY_LOCAL_MACHINE," & _ +' strKeyPath & "," & strValueName & "," & dwValue & " deleted" +' Else +' WScript.Echo "Registry value not deleted" & VBNewLine & _ +' "Error = " & Err.Number +' End If + +End Function + + + +Function ReadSysPath + + Const HKEY_LOCAL_MACHINE = &H80000002 + Dim strComputer, strKeyPath, strValueName, strValue + + ReadSysPath = Null ' assume the worst. + strComputer = "." + Set oReg = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & _ + strComputer & "\root\default:StdRegProv") + + strKeyPath="SYSTEM\CurrentControlSet\Control\Session Manager\Environment" + strValueName = "Path" + oReg.GetExpandedStringValue HKEY_LOCAL_MACHINE,_ + strKeyPath, strValueName, strValue + + If (Err.Number = 0) And (Not IsNull(strValue)) Then + ReadSysPath = strValue + End if +End Function + + +Function WriteSysPath(NewPath) + + Const HKEY_LOCAL_MACHINE = &H80000002 + Dim strComputer, strKeyPath, strValueName + + strComputer = "." + Set oReg = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & _ + strComputer & "\root\default:StdRegProv") + + strKeyPath="SYSTEM\CurrentControlSet\Control\Session Manager\Environment" + strValueName = "Path" + oReg.SetExpandedStringValue _ + HKEY_LOCAL_MACHINE, strKeyPath, strValueName, NewPath + + WriteSysPath = Err.Number +End Function + +' not used +''''''''''' Check installation status '''''''''''' + +Function install_verify() + Dim Status + Dim sInstalldir + sInstalldir = Session.Property("INSTALLDIR") + Set WshShell = CreateObject("WScript.Shell") + Set vstat = WshShell.Exec(sInstalldir & "vstat.exe") + install_verify = vstat.ExitCode +End Function + +'------------------------------------------------------------- + +' add registry key +Function CreateRegKey(KeyPath) + Const HKEY_LOCAL_MACHINE = &H80000002 + dim strComputer + strComputer = "." + Set objReg=GetObject("winmgmts:" & _ + "{impersonationLevel=impersonate}!\\" & _ + strComputer & "\root\default:StdRegProv") + + ' Display error number and description if applicable + If Err Then ShowError + Return = objReg.CreateKey(HKEY_LOCAL_MACHINE, KeyPath) + +End Function + + + +'-------------------------------------------------------- + + +' Function to add registry DWORD val. +Function AddRegDWORDValue(strKeyPath, strValueName, dwValue) + Const HKEY_LOCAL_MACHINE = &H80000002 + strComputer = "." + + Set oReg=GetObject("winmgmts:{impersonationLevel=impersonate}!\\" &_ + strComputer & "\root\default:StdRegProv") + If Err Then ShowError + + oReg.SetDWORDValue HKEY_LOCAL_MACHINE,strKeyPath,strValueName,dwValue + + If Err Then ShowError + +End Function + +'------------------------------------------------- + +' Function to add registry Expanded string val. + +Function AddRegExpandValue(strKeyPath, strValueName, dwValue) + Const HKEY_LOCAL_MACHINE = &H80000002 + strComputer = "." + + Set oReg=GetObject("winmgmts:{impersonationLevel=impersonate}!\\" &_ + strComputer & "\root\default:StdRegProv") + + If Err Then ShowError + oReg.SetExpandedStringValue HKEY_LOCAL_MACHINE,strKeyPath,strValueName,_ + dwValue + If Err Then ShowError + +End Function + +'------------------------------------------------------------------------ + + +' Function to add registry string val. + +Function AddRegStringValue(strKeyPath, strValueName, dwValue) +Const HKEY_LOCAL_MACHINE = &H80000002 +strComputer = "." + +Set oReg=GetObject("winmgmts:{impersonationLevel=impersonate}!\\" &_ +strComputer & "\root\default:StdRegProv") + +If Err Then ShowError +oReg.SetStringValue HKEY_LOCAL_MACHINE,strKeyPath,strValueName,dwValue +If Err Then ShowError + +End Function + +'------------------------------------------------------------------------ + +' Return a list of PCI devices using 'devcon find | findall' +' sFindHow - stringArg: devcon cmd arg {find | findall} + +Function Find_Dev_by_Tag(WshShell,exe,sFindHow,tag) + Dim cmd + + cmd = exe & " " & sFindHow & " * | find """ & tag & """" + Set connExec = WshShell.Exec(cmd) + If Err Then + msgbox "Shell.Exec err: " & cmd + Find_Dev_by_Tag = Null + Exit Function + End if + + devs = split(connExec.StdOut.ReadAll, vbCrLF) + + On Error Resume Next + + ' verify we have some useful data. + dim arrSize + arrSize = 0 + for each dev in devs + If Instr(dev,Tag) <> 0 Then + arrSize = arrSize + 1 + End if + next + + If arrSize = 0 Then + Find_Dev_by_Tag = Null + Exit Function + End If + + 'Create new array of selected devices + dim ibaDev() + Redim ibaDev(arrSize - 1) + index = 0 + For each dev in devs + if (Instr(dev,Tag) <> 0) Then + ibaDev(index) = dev + index = index + 1 + End if + Next + + Find_Dev_by_Tag = ibaDev + +End Function + + + +Function dpinst_Install_VNIC(WshShell,sInstalldir) + Dim dpinstVNIC,cmd,rc + + dpinst_Install_VNIC = 0 + + dpinstVNIC = "cmd.exe /c cd /d " & sInstalldir & _ + "qlgcvnic & ..\dpinst.exe " + + cmd = dpinstVNIC & "/S /F /SA /PATH """ & sInstalldir & _ + "Drivers\qlgcvnic"" /SE /SW" + rc = WshShell.Run (cmd,WindowStyle,true) + If (rc AND DPINST_INSTALLED) = 0 Then + dpinst_status "qlgcvnic Install failed",cmd,rc,"dpinst_Install_VNIC" + dpinst_Install_VNIC = rc + ElseIf sDBG >= "1" Then + dpinst_status "qlgcvnic Install OK.",cmd,rc,"dpinst_Install_VNIC" + End If + +End Function + + + +Function dpinst_Install_SRP(WshShell,sInstalldir) + Dim dpinstSRP,cmd,rc + + dpinst_Install_SRP = 0 + dpinstSRP = "cmd.exe /c cd /d " & sInstalldir _ + & "SRP & ..\dpinst.exe " + cmd = dpinstSRP & "/S /F /SA /PATH """ & sInstalldir & "Drivers\SRP""" & " /SE /SW" + rc = WshShell.Run (cmd,WindowStyle,true) + If (rc AND DPINST_INSTALLED) = 0 Then + dpinst_status "SRP Install failed",cmd,rc,"dpinst_Install_SRP" + dpinst_Install_SRP = rc + ElseIf sDBG >= "1" Then + dpinst_status "SRP Install OK.",cmd,rc,"dpinst_Install_SRP" + End if + +End Function + + + +' For installer error codes see +' http://msdn2.microsoft.com/en-us/library/aa368542(VS.85).aspx + +Const ERROR_INSTALL_SOURCE_ABSENT = 1612 ' missing files to install, + ' invalid feature selection. +Const ERROR_INSTALL_FAILURE = 1603 ' fatal error during installation +Const ERROR_FUNCTION_FAILED = 1627 ' function failed during execution +Const ERROR_SUCCESS_REBOOT_REQUIRED = 3010 ' restart required + +' For the dpinst.exe error discussion see +' http://msdn.microsoft.com/en-us/library/ms791066.aspx +' +' The dpinst.exe return code is a DWORD (0xWWXXYYZZ), where the meaning of +' the four single-byte fields 0xWW, 0xXX, 0xYY, and 0xZZ are defined as follows + +' 0xWW If a driver package could not be installed, the 0x80 bit is set. If a +' computer restart is necessary, the 0x40 bit is set. Otherwise, no bits +' are set. +' 0xXX The number of driver packages that could not be installed. +' 0xYY The number of driver packages that were copied to the driver store but +' were not installed on a device. +' 0xZZ The number of driver packages that were installed on a device. + +Const DPINST_INSTALLED = &H000000FF + +Sub dpinst_status(umsg,cmd,err,title) + + Dim I,S(4) + + msg = umsg & " (status 0x" & Hex(err) & ") " & vbCrLf & vbCrLf & _ + cmd & vbCrLf & _ + " Details in %windir%\dpinst.log" & vbCrLf & _ + " or %windir%\inf\setupapi.dev.log" & vbCrLf & vbCrLf + For I = 0 To 3 + S(I) = (err AND 255) + err = err / 256 + Next + msg = msg & "Status Decode:" & vbCrLf + msg = msg & S(0) & " driver packages installed on a device" & vbcrlf & _ + S(1) & " driver packages copied to the driver store and not installed on a device" & vbcrlf & _ + S(2) & " driver packages not installed on a device" & vbcrlf + if S(3) = &H80 then + msg = msg & "[0x" & Hex(S(3)) & "] A driver package could not be installed." & vbcrlf + end if + if S(3) = &H40 then + msg = msg & "[0x" & Hex(S(3)) & "] 0x40 reboot required." & vbcrlf + end if + + msgbox msg,,title + +End Sub + + + +''''''''''' Post Device Driver Install '''''''''''' + +Function PostDriverInstall() + Dim CheckMode, PropArray + Dim VersionNT, InstallThis, localSM + Dim rc, cmd, sInstalldir, fso + + On Error Resume Next + + ' Get the value of INSTALLDIR - see WinOF_Setup + CheckMode = Session.Property("CustomActionData") + + If CheckMode <> "" Then + 'in defered action this is the way to pass arguments. + PropArray = Split(Session.Property("CustomActionData"), ";") + Else + Redim PropArray(9) + PropArray(0) = Session.Property("INSTALLDIR") + PropArray(1) = Session.Property("SystemFolder") + PropArray(2) = Session.Property("System64Folder") + PropArray(3) = Session.Property("WindowsFolder") + PropArray(4) = Session.Property("VersionNT") + PropArray(5) = Session.Property("ADDLOCAL") + PropArray(6) = Session.Property("REMOVE") + PropArray(7) = Session.Property("NODRV") + PropArray(8) = Session.Property("DBG") + End If + + ' If cmd-line specified NODRV=1, then do not install drivers. + ' Should not get here with NODRV=1 as WIX src files check. + ' Be safe. + + If PropArray(7) <> "" Then + Exit Function + End If + + sInstalldir = PropArray(0) + VersionNT = PropArray(4) + InstallThis = PropArray(5) + sDBG = PropArray(8) ' set global debug flag. + localSM = instr(InstallThis,"fOSMS") + + Set WshShell = CreateObject("WScript.Shell") + Set fso = CreateObject("Scripting.FileSystemObject") + + err.clear + + ' DIFxApp (Driver Install Frameworks for Applications) + ' http://www.microsoft.com/whdc/driver/install/DIFxFAQ.mspx#E4AAC + ' DIFxApp.wixlib has already installed driver to Driver Store; PNP will + ' handle the actual device driver install/rollback on failure. + + ' OpenSM Subnet Manager service was already created in the disabled state. + ' Should the Local OpenSM Subnet Manager service be started/enabled? + + If localSM Then + OpenSM_StartMeUp WshShell,sInstalldir + If sDBG >= "1" Then + msgbox "Local Subnet Management Service [OpenSM] started.",,_ + "PostDriverInstall" + MsiLogInfo "[PostDriverInstall] Local Subnet Management Service [OpenSM] started." + End If + End If + + PostDriverInstall = 0 + +End Function + + + +''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +' called from WIX src to Disable/Remove IB devices so actual driver removal +' can proceed correctly. +' Actual driver file cleanup is handled after DIFxApp processing. +' shutdown NetworkDirect & Winsock Direct providers in +' order to remove their references to the rest of the IB stack such that the +' IB stack/drivers can be removed. + +Sub Remove_IB_Devices() + Dim WshShell, fso, sInstalldir, winDir, sVersionNT, rc + + Set WshShell = CreateObject("WScript.Shell") + Set fso = CreateObject("Scripting.FileSystemObject") + + ' Check if install was done with NODRV=1, if so then nothing to do, exit + If Session.Property("NODRV") = "1" Then + Exit Sub + End If + + sInstalldir = Session.Property("INSTALLDIR") + sVersionNT = Session.Property("VersionNT") + winDir = Session.Property("WindowsFolder") + + If fso.FileExists(winDir & "system32\ndinstall.exe") Then + cmd = "ndinstall -q -r winverbs & ndinstall -q -r ibal" + rc = WshShell.Run ("cmd.exe /c " & cmd, WindowStyle, true) + End If + + ' WSD is not supported on XP and should NOT have been installed. + ' otherwise, remove the WinSock Direct service. + + If sVersionNT <> WindowsXP Then + If fso.FileExists(sInstalldir & "installsp.exe") Then + rc = WshShell.Run ("cmd.exe /c cd /d " & sInstalldir & _ + " & installsp.exe -r", WindowStyle, true) + End If + End If + + Uninstall_IB_Devices fso,WshShell,sInstalldir + +End Sub + + +' Find all IBA devices [IBA,PCI\VEN_15B3,MLX4] using devman.exe +' In devman.exe output, Device tags all start in col #1. + +Function Find_IBA_Devices(WshShell,sInstalldir) + Dim dev + + Set ibaDevicesExec = WshShell.Exec ("cmd.exe /c cd /D " & sInstalldir & "Drivers & devman.exe findall * ") + + ibaDevices = split(ibaDevicesExec.StdOut.ReadAll, vbCrLF) + + ' Determine the actual array Size - dump nonessential lines from cmd output. + dim arrSize + arrSize = 0 + For each dev in ibaDevices + If (Instr(dev,"IBA\") = 1) Then + arrSize = arrSize + 1 + ElseIf (Instr(dev,"PCI\VEN_15B3") = 1) Then + arrSize = arrSize + 1 + ElseIf (Instr(dev,"MLX4") = 1) Then + arrSize = arrSize + 1 + End if + Next + + If arrSize = 0 Then + Find_IBA_Devices = Null + Exit Function + End If + + 'Creating array of IBA\ devices + dim ibaDev() + Redim ibaDev(arrSize - 1) + index = 0 + For each dev in ibaDevices + If (Instr(dev,"IBA\") = 1) Then + ibaDev(index) = dev + index = index + 1 + ElseIf (Instr(dev,"PCI\VEN_15B3") = 1) Then + ibaDev(index) = dev + index = index + 1 + ElseIf (Instr(dev,"MLX4") = 1) Then + ibaDev(index) = dev + index = index + 1 + End if + Next + + Find_IBA_Devices=ibaDev + +End Function + + +' returns an array of all Local Area Connections which +' were created for IPoIB. + +Function Find_IPOIB_LAC() + Dim WinOS,cmd,base,dev + + Set WshShell = CreateObject("WScript.Shell") + base = "cmd.exe /c reg query HKLM\SYSTEM\CurrentControlSet\Control\Network" + WinOS = Session.Property("VersionNT") + + If (WinOS <> WindowsXP) Then + ' Win2K3 style + cmd = base & " /f ""IBA\IPOIB"" /s /d | FIND ""Connection"" " + Else + ' XP style + cmd = base & " /s | FIND ""}\Connection"" " + End if + + Set ibaDevicesExec = WshShell.Exec ("cmd.exe /C " & cmd) + + ibaDevices = split(ibaDevicesExec.StdOut.ReadAll, vbCrLF) + + ' determine the array Size + dim arrSize + arrSize = 0 + for each dev in ibaDevices + arrSize = arrSize + 1 + next + 'Creating array of Local Area Connections based on IPoIB + dim ibaDev() + Redim ibaDev(arrSize - 1) + index = 0 + + For each dev in ibaDevices + If dev = "" Then + ElseIf WinOS <> WindowsXP then + ' ibaDev(index) = dev + delstr = Left(dev,Len(dev)-Len("\Connection")) + ibaDev(index) = delstr + index = index + 1 + Else + ' XP reg.exe format sucks, unable to filter IBA\IPOIB, so we do + ' it here....sigh. + Set rex = WshShell.Exec ("cmd.exe /C reg.exe query " & dev & _ + " /v PnpInstanceID | FIND ""IBA\IPOIB"" ") + resp = split(rex.StdOut.ReadAll, vbCrLF) + For each re in resp +' msgbox "XP dev " & dev +' msgbox "XP re " & re + if Instr(re,"IPOIB") Then + delstr = Left(dev,Len(dev)-Len("\Connection")) + ibaDev(index) = delstr + index = index + 1 + Exit For + End If + next + End if + next + Find_IPOIB_LAC=ibaDev + +End Function + + +' Remove 3rd party (OEM) driver package; files are identified by containing +' the string LookFor. + +Sub find_remove_INF_file(WshShell,exe,LookFor) + + Dim cmd,cmdDM,use_dpinst,pfile,found + + ' using dpinst.exe[WLH] or devman.exe[wnet/xp]? + use_dpinst = Instr(exe,"dpinst") + + cmd = "cmd.exe /c for /f %i in ('findstr /m /c:""" & LookFor _ + & """ %WINDIR%\inf\oem*.inf') do @echo %i" + + Set infFilesExec = WshShell.Exec ( cmd ) + + InfFiles = infFilesExec.StdOut.ReadAll + IFILES = Split(InfFiles,vbCrLf) + found = 0 + On Error Resume Next + For Each file in IFILES + If (file <> "") Then + ' most common is devman.exe + cmd = exe & " -f dp_delete " & file + if use_dpinst then + cmdDM = replace(cmd,"dpinst","devman") + cmd = exe & " /U """ & file & """ /S /D" + end if + If sDBG >= "1" Then + msgbox "Found '" & LookFor & _ + "' in file" & vbCrLf & " " & file & vbCrLf & _ + " " & cmd,,"find_remove_INF_file" + found = 1 + End If + Return = WshShell.Run (cmd, WindowStyle, true) + if use_dpinst then + ' use devman.exe to delete all .inf referenced files + Return = WshShell.Run (cmdDM, WindowStyle, true) + end if + ' make sure the .inf & .pnf files are removed. + pfile = replace(file,".inf",".pnf") + FileDelete file + FileDelete pfile + End IF + Next + + If sDBG > "1" AND found = 0 Then + msgbox "Did not find " & LookFor,,"find_remove_INF_file" + End If + +End Sub + + +Sub remove_INF_file(WshShell,exe,file) + + Dim cmd,cmdDM,use_dpinst,pfile + + ' using dpinst.exe[WLH] or devman.exe[wnet/xp]? + use_dpinst = Instr(exe,"dpinst") + + On Error Resume Next + + ' most common is devman.exe + cmd = exe & " -f dp_delete " & file + If use_dpinst Then + cmdDM = replace(cmd,"dpinst","devman") + cmd = exe & " /U """ & file & """ /S /D" + end if + + If sDBG >= "1" Then + msgbox "Removing driver package " & file & vbCrLf & " " & cmd,,_ + "remove_INF_file" + end if + + Return = WshShell.Run (cmd, WindowStyle, true) + if use_dpinst then + ' use devman.exe to delete all .inf referenced files + Return = WshShell.Run (cmdDM, WindowStyle, true) + end if + + ' make sure the .inf & .pnf files are removed. + pfile = replace(file,".inf",".pnf") + FileDelete file + FileDelete pfile + +End Sub + + +Sub cleanup_driver_files(fso,WshShell,sInstalldir,tool,devInfo) + + Dim i,Flist,udfCnt + + If IsNull(devInfo) Then + msgbox "cleanup_driver_files devInfo?" + Exit Sub + End If + + If sDBG >= "1" Then + DisplayDevInfo devInfo,"OFED Remove Driver Package" + udfCnt = 0 + Flist = "" + End If + + ' Device Install Info + '(0) Device-ID + '(1) Device name + '(2) Fully qualified INF filename + '(3) count of files installed from .inf file. + '(4) thru (3) [fileCount] Fully qualified Installed driver filenames. + + remove_INF_file WshShell,tool,devInfo(2) + + For i=4 To DevInfo(3) + 3 + ' skip the KMDF wdmcoinstaller*.dll file as we do not ref count here + ' and could break other installed KMDF drivers if removed. + If Instr(devinfo(i),"WdfCoInstaller") = 0 Then + DriverFileDelete fso,WshShell,devInfo(i) + If sDBG >= "1" Then + If fso.FileExists(devInfo(i)) Then + Flist = Flist & " " & devInfo(i) & vbCrLf + udfCnt = udfCnt + 1 + End If + End If + End If + Next + + If sDBG >= "1" Then + msgbox devInfo(1) & vbCrLf & devInfo(2) & vbCrLf & _ + "Remaining Driver Package Files " & udfCnt & vbCrLf & Flist,,_ + "cleanup_driver_files" + End If + +End Sub + + +' Not used - run the specified command during next startup. + +Function RunAtReboot(name,run_once_cmd) + dim key_name + key_name = "Software\Microsoft\Windows\CurrentVersion\RunOnce" + AddRegStringValue key_name,name,run_once_cmd + msgbox "RunAtReboot( " & name & " , " & run_once_cmd & " )" + RunAtReboot = 0 +End Function + +' DEBUG +Sub DisplayDevInfo(DevInfo,suffix) + + Dim i,devs + + If IsNull(DevInfo) Then + Exit Sub + End If + devs = "" + For i=4 To DevInfo(3) + 3 + devs = devs & " " & DevInfo(i) & vbCRLF + Next + + msgbox "[DeviceID] " & DevInfo(0) & vbCRLF &_ + "[DeviceName] " & DevInfo(1) & vbCRLF &_ + "[INF filename] " & DevInfo(2) & vbCRLF &_ + "[INF installed files] " & DevInfo(3) & vbCRLF &_ + devs,,suffix +End Sub + + +Function GetDeviceInstallInfo(WshShell,sInstalldir,Dev) + + Dim devman,tmp,s,StrStart,StrEnd,FileCnt,INF + + devman = "cmd.exe /c cd /d " & sInstalldir & _ + "Drivers & devman.exe driverfiles ""@" + + Set connExec = WshShell.Exec(devman & Dev & """") + cmdout = split(connExec.StdOut.ReadAll, vbCrLF) + If IsNull(cmdout) Then + GetDeviceInstallInfo = Null + Exit Function + End If + + StrStart = InStr(1,cmdout(2),"installed from ") + 15 + If StrStart <= 15 Then + GetDeviceInstallInfo = Null + Exit Function + End If + + StrEnd = InStr(StrStart,cmdout(2),"[") - 1 + INF = mid(cmdout(2),StrStart,StrEnd-StrStart) + + StrStart = InStr(StrEnd,cmdout(2),"]. ") + 3 + StrEnd = InStr(StrStart,cmdout(2)," file") + FileCnt = CInt(mid(cmdout(2),StrStart,StrEnd-StrStart)) + + '(0) Device-ID + '(1) Device name + '(2) Fully qualified INF filename + '(3) count of files installed from .inf file. + '(4) thru (3) [fileCount] Fully qualified Installed driver filenames. + + dim ibaDev() + Redim ibaDev(3+FileCnt) + ibaDev(0) = cmdout(0) + tmp = ltrim(cmdout(1)) + s = Len(tmp) - (Instr(tmp,"Name: ") + 5) + ibaDev(1) = Right(tmp,s) + ibaDev(2) = INF + ibaDev(3) = FileCnt + + ' (ibaDev(3) - 1) + 4 == ibaDev(3) + 3 + For i=4 To FileCnt + 3 + ibaDev(i) = ltrim(cmdout(i-1)) + Next + +' DisplayDevInfo ibaDev,"OFED Device Info" + + GetDeviceInstallInfo = ibaDev + +End Function + + + +' remove IB I/O Unit driver + +Sub Uninstall_IOU(fso,WshShell,devList,sInstalldir) + + RemoveDevice fso,WshShell,sInstalldir,devList,"InfiniBand I/O Unit" + +End Sub + + + +' Remove QLogic VNIC instances + +Sub Uninstall_VNIC(fso,WshShell,devices,sInstalldir) + + Dim devman,Return,device,dt,sDRIVERS,tool,devInfo + + devman = "cmd.exe /c cd /d " & sInstalldir & "Drivers & devman.exe " + + If IsNull(devices) Then + ' create a list of IBA\* devices via "devcon find" + devices = Find_IBA_Devices(WshShell,sInstalldir) + If IsNull(devices) Then + Exit Sub + End If + End If + + devInfo = Null + For each devTarget in devices + If (Instr(devTarget,"IBA\V00066AP00000030")) Then + device = split(devTarget, ":") + dt = rtrim(device(0)) + If IsNull(devInfo) Then + devInfo = GetDeviceInstallInfo(WshShell,sInstalldir,dt) + End If + ' disable instance - double quote complex device name for success. + Return = WshShell.Run (devman & "disable ""@" & dt & """", _ + WindowStyle, true) + ' Removing the Qlogic Vnic I/O Unit + Return = WshShell.Run (devman & "remove ""@" & dt & """", _ + WindowStyle, true) + End if + Next + +End Sub + + +' QLogic Virtual FC I/O controller or +' InfiniBand SRP Miniport: IBA\C0100C609EP0108 or IBA\CFF00C609EP0108 +' OFED SRP target: IBA\V000002P00005A44 +' one driver handles all three. + +SRP_IDS = Array(_ + "IBA\V000002P00005A44",_ + "IBA\C0100C609EP0108",_ + "IBA\CFF00C609EP0108",_ + "IBA\V00066AP00000038",_ + "IBA\V000006P00006282") + + +Sub Uninstall_SRP(fso,WshShell,devices,sInstalldir) + + Dim devman,devmanRMAT,devmanDAAT,Return,device,sDRIVERS,tool,devInfo + + ' QLogic Virtual FC I/O controller or + ' InfiniBand SRP Miniport: IBA\C0100C609EP0108 or IBA\CFF00C609EP0108 + ' one driver handles all three. + ' See previous SRP_IDS definition @ Install_SRP. + + devman = "cmd.exe /c cd /d " & sInstalldir & "Drivers & devman.exe " + devmanRMAT = devman & "remove @" + devmanDAAT = devman & "disable @" + devInfo = Null + + If IsNull(devices) Then + ' create a list of IBA\* devices via "devcon find" + devices = Find_IBA_Devices(WshShell,sInstalldir) + If IsNull(devices) Then + Exit Sub + End If + End If + + ' Remove SRP devices + ' QLogic Virtual FC I/O controller instance? + ' Either: IBA\C0100C609EP0108 or IBA\CFF00C609EP0108 + ' Linux SRP target: IBA\V000002P00005A44 + For each ID in SRP_IDS + For each deviceCan in devices + If Instr(deviceCan,ID) <> 0 Then + device = split(deviceCan, ":") + dt = rtrim(device(0)) + If IsNull(devInfo) Then + devInfo = GetDeviceInstallInfo(WshShell,sInstalldir,dt) + End If + ' disable the instance + Return = WshShell.Run (devmanDAAT & dt, WindowStyle, true) + ' Removing SRP device + Return = WshShell.Run (devmanRMAT & dt, WindowStyle, true) + ' msgbox "Uninstall_SRP() " & devmanRMAT & dt & " rc " & Return + End if + Next + Next + +End Sub + + +Sub RemoveDevice(fso,WshShell,sInstalldir,devList,DeviceTag) + + dim device,devman,devmanRMAT,devTarget,dt,Return,devInfo + + devman = "cmd.exe /c cd /d " & sInstalldir & "Drivers & devman.exe " + devmanRMAT = devman & "remove ""@" + devmanDAAT = devman & "disable ""@" + devInfo = Null + + If IsNull(devList) Then + devList = Find_Dev_by_Tag(WshShell,devman,"findall",DeviceTag) + If IsNull(devList) Then + If sDBG > "1" Then + msgbox "No device by tag '" & DeviceTag & "' ?",,"RemoveDevice" + End If + Exit Sub + End If + End If + + For each devTarget in devList + If Instr(devTarget,DeviceTag) Then + device = split(devTarget, ":") + dt = rtrim(device(0)) + If IsNull(devInfo) Then + devInfo = GetDeviceInstallInfo(WshShell,sInstalldir,dt) + End If + Return = WshShell.Run (devmanDAAT & dt & """", WindowStyle, true) + Return = WshShell.Run (devmanRMAT & dt & """", WindowStyle, true) + End if + Next + +End Sub + + +Sub Uninstall_IB_Devices(fso,WshShell,sInstalldir) + + Dim devList + + If (fso.FileExists(sInstalldir & "Drivers\dpinst.exe") = False) Then + msgbox "Uninstall_IB_Devices() Error " & sInstalldir & _ + "Drivers\dpinst.exe Not Found?" + Exit Sub ' no reason to continue without the tool. + End if + + If (fso.FileExists(sInstalldir & "Drivers\devman.exe") = False) Then + Exit Sub ' no reason to continue without the tool. + End if + + ' create a list of IBA\* devices via "devcon find" + + devList = Find_IBA_Devices(WshShell,sInstalldir) + If Not IsNull(devList) Then + Uninstall_SRP fso,WshShell,devList,sInstalldir + + Uninstall_VNIC fso,WshShell,devList,sInstalldir + + ' remove I/O Unit driver + Uninstall_IOU fso,WshShell,devList,sInstalldir + + ' remove IPoIB devices + RemoveDevice fso,WshShell,sInstalldir,devList,"IBA\IPOIB" + End If + + ' stop the openSM service in case it was started. + Return = WshShell.Run ("cmd.exe /c sc.exe stop opensm", WindowStyle, true) + + ' delete opensm service from registry + Return = WshShell.Run ("cmd.exe /c sc.exe delete opensm", WindowStyle, true) + + ' remove HCA devices + + If Not IsNull(devList) Then + RemoveDevice fso,WshShell,sInstalldir,devList,"MLX4\CONNECTX_HCA" + ' VEN_15B3 covers devices: mthca & mlx4_bus + RemoveDevice fso,WshShell,sInstalldir,devList,"PCI\VEN_15B3" + End If + +End Sub + + + +''''''''''' Driver Cleanup '''''''''''' +' called from WIX src to cleanup after IB driver uninstall. +' Assumption is NetworkDirect and Winsock Direct have been shutdown to remove +' their IB stack references. + +Sub IB_DriverCleanup() + Dim sInstalldir, WshShell, fso, sRemove,devman, tool + + sInstalldir = Session.Property("INSTALLDIR") + + Set WshShell = CreateObject("WScript.Shell") + Set fso = CreateObject("Scripting.FileSystemObject") + + ' Check if install was done with NODRV=1, if so then nothing to do, exit + If Session.Property("NODRV") = "1" Then + Exit Sub + End If + + sDBG = Session.Property("DBG") + + sRemove = Session.Property("REMOVE") + If sRemove = "" Then + sRemove = "ALL" + End If + + ' Remove Service entries from the registry + + DeleteRegKey "System\CurrentControlSet\Services\ibbus" + DeleteRegKey "System\CurrentControlSet\Services\mthca" + DeleteRegKey "System\CurrentControlSet\Services\mlx4_bus" + DeleteRegKey "System\CurrentControlSet\Services\mlx4_hca" + DeleteRegKey "System\CurrentControlSet\Services\ipoib" + DeleteRegKey "System\CurrentControlSet\Services\ibiou" + DeleteRegKey "System\CurrentControlSet\Services\ibsrp" + DeleteRegKey "System\CurrentControlSet\Services\qlgcvnic" + DeleteRegKey "System\CurrentControlSet\Services\winverbs" + + ' Mthca + DeleteRegValue "SYSTEM\CurrentControlSet\Control\CoDeviceInstallers" ,_ + "{58517E00-D3CF-40c9-A679-CEE5752F4491}" + + DeleteRegKey "SYSTEM\CurrentControlSet\Control\Class\{58517E00-D3CF-40C9-A679-CEE5752F4491}" + + ' Connectx (mlx4) + DeleteRegValue "SYSTEM\CurrentControlSet\Control\CoDeviceInstallers" ,_ + "{31B0B28A-26FF-4dca-A6FA-E767C7DFBA20}" + + DeleteRegKey "SYSTEM\CurrentControlSet\Control\Class\{31B0B28A-26FF-4dca-A6FA-E767C7DFBA20}" + + DeleteRegKey "SYSTEM\CurrentControlSet\Control\Class\{714995B2-CD65-4a47-BCFE-95AC73A0D780}" + + ' In livefish mode, the above does not always work - just in case. + ' remove reg entries for ConnectX, mthca, ibbus, mlx4 & ipoib + + nukem = Array(_ + "Control\Class\{58517E00-D3CF-40C9-A679-CEE5752F4491}",_ + "Control\Class\{31B0B28A-26FF-4dca-A6FA-E767C7DFBA20}",_ + "Control\Class\{714995B2-CD65-4a47-BCFE-95AC73A0D780}",_ + "Services\ibbus",_ + "Services\mthca",_ + "Services\mlx4_bus",_ + "Services\mlx4_hca",_ + "Services\ipoib",_ + "Services\EventLog\System\ipoib",_ + "Services\ibiou",_ + "Services\qlgcvnic",_ + "Services\ibsrp",_ + "Services\winmad",_ + "Services\winverbs",_ + "Services\eventlog\System\mthca",_ + "Services\eventlog\System\mlx4_bus",_ + "Services\eventlog\System\mlx4_hca",_ + "Services\eventlog\System\ibbus" ) + + base = "reg.exe delete HKLM\SYSTEM\CurrentControlSet\" + + ' in livefish mode the delete didn't suceed, delete it in another way + For each ID in nukem + If ID <> "" Then + Return = WshShell.Run (base & ID & " /f", WindowStyle, true) + End if + Next + + ' Cleanup KMDF CoInstaller Driver entries. + Return = WshShell.Run (base & "Control\Wdf\Kmdf\kmdflibrary\versions\1\driverservices /v mlx4_bus /f", WindowStyle, true) + Return = WshShell.Run (base & "Control\Wdf\Kmdf\kmdflibrary\versions\1\driverservices /v winverbs /f", WindowStyle, true) + Return = WshShell.Run (base & "Control\Wdf\Kmdf\kmdflibrary\versions\1\driverservices /v winmad /f", WindowStyle, true) + +' Not yet +' Return = WshShell.Run ("reg.exe delete HKLM\Software\Microsoft\Windows\currentVersion\DIFx\DriverStore\WinVerbs_* /f", WindowStyle, true) +' Return = WshShell.Run ("reg.exe delete HKLM\Software\Microsoft\Windows\currentVersion\DIFx\DriverStore\ipoib_* /f", WindowStyle, true) +' + + ' Remove all Local Area Connection Registry entries which were constructed + ' for IPoIB. Next OFED install gets same IPoIB local area connection + ' assignment. + + Dim IPOIB_LAC + IPOIB_LAC = Find_IPOIB_LAC + + For each LAC in IPOIB_LAC + If LAC <> "" Then + Return = WshShell.Run ("reg.exe delete " & LAC & " /f", _ + WindowStyle, true) + If Err Then ShowErr + End if + Next + + Session.Property("REBOOT") = "FORCE" + err.clear + + ' cleanup INF files + + If (fso.FileExists(sInstalldir & "Drivers\dpinst.exe") = False) Then + Exit Sub ' no reason to continue without the tool. + End if + + devman = "cmd.exe /c cd /d " & sInstalldir & "Drivers & devman.exe " + + ' use dpinst.exe instead of devman.exe for Windows LongHorn++ + tool = "cmd.exe /c cd /d " & sInstalldir & "Drivers & dpinst.exe " + + find_remove_INF_file WshShell,tool,"mthca" + find_remove_INF_file WshShell,tool,"mlx4_hca" + find_remove_INF_file WshShell,tool,"mlx4_bus" + + ' catch-all cleanup. + find_remove_INF_file WshShell,devman,"Mellanox" + find_remove_INF_file WshShell,devman,"InfiniBand" + + ' remove driver installed files + RemoveDriverFiles fso,WshShell + + err.clear + +End Sub + + +' HCA load failure? +' Check for [SystemFolder]\complib.dll. If not preset then ConnectX HCA +' driver failed to install; see mlx4_hca.inf. Complib.dll absence occurs +' when ConnectX bus driver detects invalid Firmware hence does not create +' the PDO for the ConnectX HCA device so PNP never loads the HCA driver and +' complib.dll never gets installed. +' If features[IPoIB+(WinSockDirect OR NetworkDirect)] are installed, then +' wait for IPoIB device to appear in order to ensure WSD and/or ND provider +' install success. + +Sub CheckDriversOK() + Dim winDir, WshShell, fso, AddLocal, too_long + + Set WshShell = CreateObject("WScript.Shell") + Set fso = CreateObject("Scripting.FileSystemObject") + + winDir = Session.Property("WindowsFolder") + sInstalldir = Session.Property("INSTALLDIR") + devman = "cmd.exe /c cd /d " & sInstalldir & "Drivers & devman.exe " + AddLocal = Session.Property("ADDLOCAL") + + ' Check if HCA driver installed OK. + If Not fso.FileExists(winDir & "system32\complib.dll") Then + ' SW only install, such that there are no hardware HCAs avaiable? + devList = Find_Dev_by_Tag(WshShell,devman,"find","PCI\VEN_15B3") + If IsNull(devList) Then + Exit Sub + End If + + ' 10 sec timeout warning box. + WshShell.Popup "WARNING: Possible HCA Driver Startup Failure." _ + & vbCrLf & " Consult the Windows System Event log! (mlx4_bus)",_ + 10,"OFED-Install CheckDriversOK",vbInformation+vbSystemModal + + MsiLogInfo "[CheckDriversOK] ** Possible HCA Driver Startup Failure" & _ + vbCrLf & "[CheckDriversOK] ** Consult System Event Log." + Exit Sub + End If + + ' empty string implies default install Features which include IPoIB+WSD+ND. + If AddLocal <> "" Then + ' No wait if !IPoIB OR (!WinSockDirect AND !NetworkDirect) + If Instr(AddLocal,"fIPoIB") = 0 Then + Exit Sub + End If + If Instr(AddLocal,"fWSD") = 0 AND Instr(AddLocal,"fND") = 0 Then + Exit Sub + End If + End If + + ' wait for IPoIB driver to start so ND and/or WSD can install + ' Define start as the appearance of IBA\IPOIB instance in device database. + + devList = Find_Dev_by_Tag(WshShell,devman,"find","IBA\IPOIB") + + too_long = 15 + If Session.Property("VersionNT") = WindowsXP Then + ' XP does not support timeout cmd; let timeout cmd fail to consume time. + too_long = 50 + End If + + Do While IsNull(devList) + ' Wait for device IPoIB to appear as it's required for WSD/ND install. + WshShell.Run "cmd.exe /c timeout /T 2", WindowStyle, true + too_long = too_long - 1 + if too_long <= 0 then + ' timeout info box. + WshShell.Popup "WARNING: Possible NetworkDirect startup Failure." _ + & vbCrLf & " Waited too long for IBA\IPOIB device?" & vbCrLf & _ + "use 'ndinstall -l' to verify NetworkDirect provider " & _ + "installed correctly.",15,"OFED-Install CheckDriversOK", _ + vbInformation+vbSystemModal + + MsiLogInfo "[OFED] ** Possible NetworkDirect startup Failure" & _ + vbCrLf & "[OFED] ** Waited too long for IBA\IPOIB device?" & _ + vbCrLf & "[OFED] ** Check ND provider status." + exit Do + End If + err.clear + devList = Find_Dev_by_Tag(WshShell,devman,"find","IBA\IPOIB") + Loop + +End Sub + + +' Enable WSD if installsp.exe was installed (feature Winsock direct selected). +' For Windows XP, this CustomAction should not be called as WSD is not +' supported on XP. + +Sub WSDEnable() + Dim sInstalldir, WshShell, fso + + sInstalldir = Session.Property("INSTALLDIR") + + Set WshShell = CreateObject("WScript.Shell") + Set fso = CreateObject("Scripting.FileSystemObject") + + ' Check if install was done with NODRV=1, if so then nothing to do, exit + If Session.Property("NODRV") = "1" Then + Exit Sub + End If + + If fso.FileExists(sInstalldir & "installsp.exe") Then + ' install the WinSockdirect service + Return = WshShell.Run ("cmd.exe /c cd /d " & sInstalldir _ + & " & installsp.exe -i", WindowStyle, true) + End If + +End Sub + + +' This sub will only be called if the feature ND start was selected. +' See WIX src file - ND_start + +Sub ND_StartMeUp() + Dim Ret, sInstalldir, NDprovider, winDir, WshShell, fso + + sInstalldir = Session.Property("INSTALLDIR") + + Set WshShell = CreateObject("WScript.Shell") + Set fso = CreateObject("Scripting.FileSystemObject") + winDir = Session.Property("WindowsFolder") + + ' Start the Network Direct Service if installed + If fso.FileExists(winDir & "system32\ndinstall.exe") Then + ' ia64 only supports the ND/winverbs provider, otherwise use + ' ND/ibal provider. + NDprovider = "ibal" + If Architecture() = "ia64" Then + NDprovider = "winverbs" + End If + Ret = WshShell.Run ("cmd.exe /c ndinstall -q -i " & NDprovider, _ + WindowStyle, true) + If Ret Then ShowErr2("ND service provider install failed") + End If + +End Sub + + + +' Convert the disabled OpenSM Windows service to an 'auto' startup on next boot. +' OpenSM service was created by WIX installer directives - see WOF.wxs file. +' Performs local service conversion and then starts the local OpenSM service. +' Routine called from PostDriverInstall phase 'IF' a local OpenSM service was +' requested. The point is to get a local OpenSM up and running prior to loading +' the IOU and SRP/VNIC drivers. Server 2003 IOU driver load fails if OpenSM +' has not yet registered the IOC? + +Sub OpenSM_StartMeUp(WshShell,sInstalldir) + + Return = WshShell.Run ("cmd.exe /c sc.exe config opensm start= auto", _ + WindowStyle,true) + Return = WshShell.Run ("cmd.exe /c sc.exe start opensm", WindowStyle, true) + Err.clear + +End Sub + + +Sub ScheduleLocalReboot + + Set objWMILocator = CreateObject ("WbemScripting.SWbemLocator") + objWMILocator.Security_.Privileges.AddAsString "SeShutdownPrivilege",True + Set objWMIServices = objWMILocator.ConnectServer(strComputerName, _ + cWMINameSpace, strUserID, strPassword) + Set objSystemSet = GetObject(_ + "winmgmts:{impersonationLevel=impersonate,(Shutdown)}")._ + InstancesOf("Win32_OperatingSystem") + + ' Forced restart + For Each objSystem In objSystemSet + objSystem.Win32Shutdown 2+4 + objSystem.Win32Shutdown 2+4 + objSystem.Win32Shutdown 2+4 + Next + + 'msgbox "Please wait while computer restarts ...",0,"OFED" + +End Sub + + +' Now that WIX+[Windows Installer] handle previous installs, this routine +' only deletes lingering driver files which were not removed from the last +' uninstall. +' Called in immediate mode, condition: INSTALL=1 + +Function ChkPreviousInstall() + + Set fso = CreateObject("Scripting.FileSystemObject") + Set WshShell = CreateObject("WScript.Shell") + + ' Check if install was done with NODRV=1, if so then nothing to do, exit + If Session.Property("NODRV") = "1" Then + Exit Function + End If + + ' remove any lingering driver installed files + RemoveDriverFiles fso,WshShell + + ChkPreviousInstall = 0 + +End Function + + + +' Not Used - idea was to run %SystemRoot%\temp\OFEDcleanup.bat on the next +' reboot to remove driver files which did not get uninstalled (win2K3 only); +' script ran, files persisted on Win2K3? + +Sub RunOnceCleanup(fso,sInstalldir) + + Dim sTemp, cmd, script + + On Error Resume Next + + If Session.Property("REMOVE") <> "ALL" Then + ' XXX + msgbox "RunOnceCleanup - not remove ALL?" + Exit Sub + End if + + script = "RunOnceOFEDcleanup.bat" + src = sInstalldir & "Drivers\" & script + + If Not fso.FileExists(src) Then + msgbox "Missing " & src + Exit Sub + End if + + ' copy OFEDclean.bat to %SystemRoot%\temp for runOnce cmd + sTemp = fso.GetSpecialFolder(0) & "\temp\" & script + If fso.FileExists(sTemp) Then + Err.clear + fso.DeleteFile(sTemp),True + End If + + Err.clear + fso.CopyFile src, sTemp + If Err.Number = 0 Then + cmd = "cmd.exe /C " & sTemp + RunAtReboot "OFED", cmd + ' 2nd cmd to remove previous script. +' XXX cmd = "cmd.exe /C del /F/Q " & sTemp +' RunAtReboot "OFED2", cmd + End if + +End Sub + + + +' WIX has appended [INSTALLDIR] to the system search path via . +' Unfortunately WIX does not _Broadcast_ to all top-level windows the registry +' Settings for '%PATH%' have changed. Run nsc to do the broadcast. + +Sub BcastRegChanged + Dim sInstalldir + Set WshShell=CreateObject("WScript.Shell") + + sInstalldir = Session.Property("INSTALLDIR") + + On Error Resume Next + WshShell.Run "%COMSPEC% /c cd /d " & sInstalldir & " & nsc.exe", _ + WindowStyle, true + Err.clear + BcastRegChanged = 0 + +End Sub + + +' This routine should never be...InstallShield-12 for some reason has +' decided not to completely remove [INSTALLDIR]? Until such a time +' that 'why' is understood, this routine removes [INSTALLDIR]! Sigh... +' nuke some driver files which remain due to devcon device install. +' Immediate execution; called after MsiCleanupOnSuccess (REMOVE="ALL") + +Sub HammerTime + Dim fso, sInstalldir, rc, cmd + + Set fso=CreateObject("Scripting.FileSystemObject") + Set WshShell=CreateObject("WScript.Shell") + + sInstalldir = Session.Property("INSTALLDIR") + If fso.FolderExists(sInstalldir) Then + cmd = "cmd.exe /c rmdir /S /Q """ & sInstalldir & """" + rc = wshShell.Run(cmd,WindowStyle,true) + End if + + If fso.FolderExists("C:\IBSDK") Then + RemoveFolder "C:\IBSDK" + End if + +End Sub + + + +' NOT USED - deferred action to increment ticks while action is taking place +' +Function AddProgressInfo( ) + Const INSTALLMESSAGE_ACTIONSTART = &H08000000 + Const INSTALLMESSAGE_ACTIONDATA = &H09000000 + Const INSTALLMESSAGE_PROGRESS = &H0A000000 + + Set rec = Installer.CreateRecord(3) + + rec.StringData(1) = "callAddProgressInfo" + rec.StringData(2) = "Incrementing the progress bar..." + rec.StringData(3) = "Incrementing tick [1] of [2]" + + 'Message INSTALLMESSAGE_ACTIONSTART, rec + + rec.IntegerData(1) = 1 + rec.IntegerData(2) = 1 + rec.IntegerData(3) = 0 + + Message INSTALLMESSAGE_PROGRESS, rec + + Set progrec = Installer.CreateRecord(3) + + progrec.IntegerData(1) = 2 + progrec.IntegerData(2) = 5000 + progrec.IntegerData(3) = 0 + + rec.IntegerData(2) = 1500000 + + For i = 0 To 5000000 Step 5000 + rec.IntegerData(1) = i + ' action data appears only if a text control subscribes to it + ' Message INSTALLMESSAGE_ACTIONDATA, rec + Message INSTALLMESSAGE_PROGRESS, progrec + Next ' i + + ' return success to MSI + AddProgressInfo = 0 +End Function + + +' Called when .msi 'CHANGE' (ADD/REMOVE) installation was selected. +' Currently only handles SRP & VNIC + +Function InstallChanged + + Dim rc, sInstalldir, sRemove, sDRIVERS, NeedReboot + Err.clear + + sRemove = Session.Property("REMOVE") + If sRemove = "ALL" Then + Exit Function + End If + + sDBG = Session.Property("DBG") + + Set WshShell=CreateObject("WScript.Shell") + Set fso = CreateObject("Scripting.FileSystemObject") + + NeedReboot = 0 + + sInstalldir = Session.Property("INSTALLDIR") + + On Error Resume Next + + ' Nothing to do for ADD as DIFxAPP has loaded drivers into Driver Store. + + ' For REMOVE - cleanup + + If (Not IsNull(sRemove)) AND (sRemove <> "") Then + + If Instr(sRemove,"fSRP") Then + Uninstall_SRP fso,WshShell,Null,sInstalldir + NeedReboot = NeedReboot + 1 + End If + + If Instr(sRemove,"fVNIC") Then + Uninstall_VNIC fso,WshShell,Null,sInstalldir + NeedReboot = NeedReboot + 1 + End If + End If + + If NeedReboot Then + Session.Property("REBOOT") = "FORCE" + InstallChanged = ERROR_SUCCESS_REBOOT_REQUIRED + ' until forced reboot relly works.... + msgbox "A system reboot is required to complete this operation." _ + & vbCrLf & "Please do so at your earliest convinence." + End If + +End Function + diff --git a/branches/WOF2-3/OFED/WIX/HPC/HPC.inc b/branches/WOF2-3/OFED/WIX/HPC/HPC.inc new file mode 100644 index 00000000..65d1be01 --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/HPC/HPC.inc @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + diff --git a/branches/WOF2-3/OFED/WIX/HPC/OFA-cert-install.bat b/branches/WOF2-3/OFED/WIX/HPC/OFA-cert-install.bat new file mode 100644 index 00000000..93b8c7d1 --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/HPC/OFA-cert-install.bat @@ -0,0 +1,34 @@ +@echo off +rem Install OpenFabrics Alliance (OFA) Trusted SW Publisher certificate +rem in the node local TRUSTEDPUBLISHER certificate store. +rem This file is a no-args wrapper for rem-cert-ADD.bat; both in same folder. + +setlocal +set OfACertID=71175fca6b85d5c2e0864df16349ad84 + +rem This is where the provisioning step copied the WOF folder. +set TARGET=c:\WOF + +cd /d %TARGET% +if ERRORLEVEL 1 ( + echo %0 - unable to CD to folder %TARGET% ? + exit /B %ERRORLEVEL% +) + +if not exist rem-cert-add.bat ( + echo %0 Missing file rem-cert-add.bat, ABORT. + exit /B 1 +) +rem Trusted Publisher cert file extracted from head-node +if not exist OFA_TP.cer ( + echo %0 Missing file OFA_TP.cert, ABORT. + exit /B 1 +) +echo on +call rem-cert-add.bat %OfACertID% %CD%\OFA_TP.cer + +@if %ERRORLEVEL% NEQ 0 echo %0 exit with error %ERRORLEVEL% + +@endlocal +@exit /B %ERRORLEVEL% + diff --git a/branches/WOF2-3/OFED/WIX/HPC/WinOF-install.bat b/branches/WOF2-3/OFED/WIX/HPC/WinOF-install.bat new file mode 100644 index 00000000..babfdfa0 --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/HPC/WinOF-install.bat @@ -0,0 +1,28 @@ +@echo off +setlocal + +rem Example Local WinOF install +rem all files in the current folder; setup by provisioning template. +rem excute under Administrator login. + +set MSI=WinOF_2-1_wlh_x64.msi + +set TARGET=c:\WOF + +cd /d %TARGET% +if ERRORLEVEL 1 ( + echo %0 - unable to CD to folder %TARGET% ? + exit /B %ERRORLEVEL% +) + +if not exist %MSI% ( + echo %0 Missing WinOF installer %MSI%, ABORT. + exit /B 1 +) + +echo on +start/wait msiexec /I %MSI% /quiet /qn /Lv msi.log + +@endlocal +@exit /B %ERRORLEVEL% + diff --git a/branches/WOF2-3/OFED/WIX/HPC/cert-add.bat b/branches/WOF2-3/OFED/WIX/HPC/cert-add.bat new file mode 100644 index 00000000..49e3349e --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/HPC/cert-add.bat @@ -0,0 +1,142 @@ +@echo off +setlocal + +rem clusrun execute the 'rem-cert-ADD.bat' script on specified nodes to install the OFA +rem public cert in the remote node's TrustedPublisher Certificate Store. +rem Sets the 'OpenFabric Alliance' as a Trusted 3rd party Software Publisher which then +rem allows unattened WinOF installs to complete. +rem Assumes the OFA cert is in the local Trusted Publisher certificate Store. + +if "%1" == "" ( +:usage + echo usage: %0 remote-node-visiable-share-path [remote-node-hostnames] + echo Valid ONLY for Server 2008 HPC. + echo. + echo Will use OFA Cert file named 'OFA_TP.cer' if present. + echo Otherwise extract the OFA cert from the local Trusted Publisher store + echo for injection into remote node certificate store. + echo. + echo example: install OFA certificate on remote nodes. + echo %0 \\head-node\remShar cn1 cn2 cn3 cn4 + echo example: extract OFA certificate to \\head-node\remShar\OFA_TP.cer + echo %0 \\head-node\remShar + exit /B 1 +) + +if "%2" == "" echo cert extraction only. + +where clusrun > Nul +if ERRORLEVEL 1 ( + echo %0 Must be run on server 2008 HPC [clusrun.exe] only? + exit /B 1 +) +where certutil > Nul +if ERRORLEVEL 1 ( + echo %0 missing file Windows utility certutil.exe ? + exit /B 1 +) + +rem worker script file can be local or in the WinOF install folder. +set CISF=rem-cert-ADD.bat +if exist "%CISF%" ( + set CIS="%CD%\%CISF%" +) else ( + set CIS="%ProgramFiles%\WinOF\%CISF%" +) + +if not exist %CIS% ( + echo missing WinOF script %CIS% ? + exit /B 1 +) + +rem Certificate ID's (Serial Number) for the OFA WinOF driver signing cert + +rem [expired 8/20/09] set OFA_CERT_ID=71175fca6b85d5c2e0864df16349ad84 +rem [expires 8/20/2011] +set OFA_CERT_ID=765c1a5b6e0fcad96ae0c35cd2f9523e + +rem Openfabrics Alliance Trusted SW Publisher +set CERTNAME=OFA_TP.cer + +if exist "%CERTNAME%" ( + echo Using OFA cert file %CERTNAME% + goto have_cert +) + +rem extract OFA cert from local Trusted Publisher Cert Store. +rem test for OFA cert in local TrustedPublisher cert store + +certutil -store TRUSTEDPUBLISHER %OFA_CERT_ID% 1> Nul +IF %ERRORLEVEL% NEQ 0 ( + echo 'OpenFabrics Alliance' Trusted SW Publisher certificate not in local Cert Store. + echo Install WinOF on head-node or Install OFA Cert from WinOF installer .msi file. + echo Install OFA Cert from .msi file: + echo Right-click .msi file, select Properties -\> Digital Signatures tab' + echo Highlight 'OpenFabrics Alliance', select 'Details' -\> View Certificate + echo select 'Install Certificate' -\> Next -\> Place Certificate in Trusted Publishers store -\> Browse + echo Next -\> Finish. rerun this script. + exit /B 1 +) + +rem Extract OFA cert to %CERTNAME% file. +if EXIST "%CERTNAME%" del /F/Q %CERTNAME% +certutil -store TRUSTEDPUBLISHER %OFA_CERT_ID% %CERTNAME% 1> Nul +IF %ERRORLEVEL% NEQ 0 ( + echo Unable to extract OFA cert from local Trusted Publisher Store err %ERRORLEVEL% + exit /B 1 +) +echo Extracted OFA cert to %CERTNAME% +set EXTRACTED=1 + +:have_cert + +if not EXIST "%1\%CERTNAME%" ( + echo Copying %CERTNAME% to compute node visible shar %1 + copy /B/Y %CERTNAME% %1\%CERTNAME% + if ERRORLEVEL 1 ( + echo copy %CERTNAME% ERR %ERRORLEVEL% ? + del /F/Q %CERTNAME% + exit /B 1 + ) + set CPY_CERT=1 +) + +if not EXIST "%1\%CISF%" ( + echo Copying %CISF% to compute node visible shar %1 + copy /B/Y %CIS% %1\%CISF% + if ERRORLEVEL 1 ( + echo copy %CIS% ERR %ERRORLEVEL% ? + del /F/Q %CERTNAME% + exit /B 1 + ) + set CPY_CISF=1 +) + +rem install OFA Trusted 3rd Party SW Publisher cert in remote nodes cert store +rem using clusrun. + +rem Cert extract only? +if "%2" == "" ( + echo Extract Cert ONLY! + goto xit +) + +:again + +rem echo call clusrun /node:%1 %1\%CISF% %OFA_CERT_ID% %1\%CERTNAME% + clusrun /nodes:%2 %1\%CISF% %OFA_CERT_ID% %1\%CERTNAME% + shift /2 + if "%2" == "" goto cpy_cleanup + timeout /T 5 + goto again + + +:cpy_cleanup + +if %CPY_CERT% EQU 1 del /F %1\%CERTNAME% +if %CPY_CISF% EQU 1 del /F %1\%CISF% +if %EXTRACTED% EQU 1 del /F %CERTNAME% + +:xit + +endlocal diff --git a/branches/WOF2-3/OFED/WIX/HPC/readme-HPC.txt b/branches/WOF2-3/OFED/WIX/HPC/readme-HPC.txt new file mode 100644 index 00000000..8df14aa5 --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/HPC/readme-HPC.txt @@ -0,0 +1,40 @@ +[7-28-09] stan. + +Files in this folder are Windows Server 2008 HPC specific. +For full HPC install details, +see Start-->All Programs-->Windows OpenFabrics-->WinOF Release Notes-->HPC Install + +cert_add.bat + Extract OFA Trusted Publisher certificate from the head-node local certificate + store to a local file OFA_TP.cer, then insert OFA_TP.cer into remote node's + Trusted Publisher certificate store by calling '.\rem-cert-add.bat'. + + For the example, assume \\HN\WOF is the compute node visible share name; + head-node local name is \Program Files\Microsoft HPC Pack\Data\InstallShare\WOF + + First extract OFA TP certificate into a remote node visible share file OFA_TP.cer, + creates \\HN\WOF\OFA_TP.cer & \\HN\WOF\rem-cert-ADD.bat + + cert-add \\HN\WOF + + Instert OFA TP certificate into a remote node's Trusted Publisher Store + cert-add \\HN\WOF cn01 cn02 cn03 [...] + +rem-cert-add.bat + Add Trusted Publisher certificate to local node's TP store. Can be run via + clusrun.exe or locally as a WDM provisioning template step. + +Provisioning Template installation examples: (local config mods required) + +Batch files are part of an entire directory copied via the template to the +node under provisioning. Template then executes + 1) OFA-cert-install.bat + 2) WinOF-install.bat + +OFA-cert-install.bat + No args wrapper for rem-cert-add.bat suitible to be run as a compute node + provisioning template step. + +WinOF-install.bat + No args wrapper to quietly with logging, install default WinOF on local node. + diff --git a/branches/WOF2-3/OFED/WIX/HPC/rem-cert-ADD.bat b/branches/WOF2-3/OFED/WIX/HPC/rem-cert-ADD.bat new file mode 100644 index 00000000..38a971d6 --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/HPC/rem-cert-ADD.bat @@ -0,0 +1,40 @@ +@echo off +setlocal + +rem Remote Certificate add + +rem Install specified Digital Certificate in the local TrustedPublishers store. +rem Intended to be called from clusrun in cert-add.bat script. + +rem usage: %0 CertID TrustedPublisherCertFilename + +where certutil > Nul +if ERRORLEVEL 1 ( + echo %0 Must be run on server 2008 HPC [clusrun.exe] ? + exit /B 1 +) + +if "%1" == "" ( +:usage + echo usage: %0 CertID TrustedPublisherCertFilename + echo designed to be called from cert-add.bat + exit /B 1 +) + +rem test for cert already in the TrustedPublisher cert store +certutil -verifystore TRUSTEDPUBLISHER %1 1> Nul +if %ERRORLEVEL% EQU 0 ( + echo. + echo %computername% OFA TrustedPublisher Cert already installed. + exit /B 0 +) +echo Installing %2 Cert on %computername% +echo. +certutil -f -addstore TRUSTEDPUBLISHER "%2" 1> Nul +if %ERRORLEVEL% EQU 0 ( + echo %computername% SUCCESS: OFA TrustedPublisher cert installed +) else ( + echo %computername% FAILURE: OFA TrustedPublisher cert install err %ERRORLEVEL% + echo. +) +endlocal diff --git a/branches/WOF2-3/OFED/WIX/License.rtf b/branches/WOF2-3/OFED/WIX/License.rtf new file mode 100644 index 0000000000000000000000000000000000000000..6de463f6acd1df99690b0c945f5f44d8b525db14 GIT binary patch literal 1644 zcmcJQ!H?oL6vlgAY5#|(J+&33f!(=uPllMmYDkb1b~;inCUL-Ou&M0~LZkWL_c;>~ zGu=ZkMJN#C?|Z-ZJx4s3);E(eg6DhHb#5DZShM~ zHtwXHE1RSJXIeJZURWo61jH)QetmiQ_~E(ywcJT9t?_cgArn8moSGGzEdxpl?gB!sKgTtV1UBZ&-JRD4|8dZtlHG+VAl=h%JP92Wc zV95Bz?}hJyuNmE1RR*UK^f*P-AEf^gHvIOE+<|E>$d##4*g22m@B&*A`g~gg+pf&< zY}Ib>K^u=5jSvXWO^aCsqg#k!`agt4CycLZg*r%kISOw|{hJecZt}cvVmft)afd;Q zt$C7fT>c;6Fy&CMHdPm%o_=g$;J@QzVDJ|U2jOLSnB6;^>oEJn(3{*GqjyOZOA2|m zC>{u>z;amg>>G<|44+7j_n$`az=~zIDFAnHk`|AUErx<5eS|+*8jpbfwdOR>A>+VS z>x5BUW9dBE#4Nps8LHE)fP}4BLE}MPWDtrEwv3{B0V~SqORPd>EMdjt2o|hJgYyEd z$)H>lUat!}%jpORXF1|uit-F=h3HWil1+m;rLSILEPW@}>1BKnhFCWk X$`voBBtc&sX!=I-_AKCE!cX4;pKA#O literal 0 HcmV?d00001 diff --git a/branches/WOF2-3/OFED/WIX/README.txt b/branches/WOF2-3/OFED/WIX/README.txt new file mode 100644 index 00000000..c0dd742e --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/README.txt @@ -0,0 +1,176 @@ +[01-28-10] + +How to generate a Windows OpenFabrics Enterprise Distribution Release (OFED) +using the WIX 3.0 open source installer tool set +(http://sourceforge.net/projects/wix/ ). + +WIX References: + WIX collection http://www.dalun.com/wix/default.htm + WIX Tutorial http://www.tramontana.co.hu/wix/ + WIX sourceforge project http://sourceforge.net/projects/wix/ + WIX Introduction http://wix.sourceforge.net/manual-wix3/wix_index.htm + + +WinOF Revisions: (based on) + 1.0 svn.614 + 1.0.1 svn.864 + 1.1 svn.1177 + 2.0 svn.1763 + 2.0.2 svn.1975 + 2.1 svn.2476 + 2.2 svn.2655 +WinOF renamed to OFED + 2.3 svn.xxxx + + +Creating a binary release tree +------------------------------ + +As of WinOF 2.0 release [Aug'2008] the build environment has been switched over +to Microsoft's WDK (Windows Driver Kit) version 6001.180001. + +See gen1\trunk\OFED\BuildRelease.bat file to generate a Wix installer (.msi +file) containing signed driver files. +The OS flavor WLH\ - Vista/Server 2008[LongHorn], WNET\ - Server 2003+XP64 +and XP\ (x86 only) bin\ folders will be populated with the correct folder +structure such that a WIX installer (.msi) files can be generated; either +cd into OS\arch dir and run buildmsi.bat or use WinOF\BuildRelease.bat. + +Warning - buildrelease.bat is not generic, some modifications are required +as the folder structure is assumed; see SVN to set build SVN (aka OPENIB_REV). + +BuildRelease.bat will by default deposit 7 .msi files in +'%SystemRoot%\temp\WinOF_OS_arch.msi'. + + +The other approach to creating a binary release tree is to generate the +contents of WIX\bin\ yourself from a WDK/SDK build window which can run +'nmake'. + + 1) Generate binaries for each supported architecture: x86, x64 and ia64. + cd to trunk; build /wg from a WDK OS and arch specific command window; all + are required by etc\makebin.bat. + + 2) from trunk: execute 'etc\makebin %CD% dest-dir OS-flavor' for each OS + flavor: wnet, wlh and wxp. + Say your svn repository is at C:\open-ib\, then to populate the WIX bin + folder for Server 2008 binaries from a command window: + makebin C:\open-ib\gen1\trunk C:\open-ib\gen1\WinOF\Wix\WLH\bin WLH + +With the arrival of Windows Server 2008 & Vista (WLH - Windows LongHorn) driver +signing is a requirement. The WIX\sign-all-drivers.bat script will create a .cat +file for each driver .inf located. The generation of the .cat file is driven +from the corresponding driver.inf file via inf2cat.exe creating the .cat file +and signtool.exe signing the .cat and .sys files. + +A SW publisher's digital-ID certificate is required in order for WinOF +installers to be created. A test certificate can be generated for local use, +requires overhead during installation ('bcdedit -set testsigning on', reboot & +local certificate store updates). +The MS prescribed procedure is to obtain a SW publisher's certificate from +VeriSign or other CA agency; if your company is producing SW drivers for +SVR2008/Vista, then you will likely have access to a cert file. +The OFA will be purchasing a certificate for WinOF publication. +Scripts for signing drivers assume the MS cross-certification .cer file will be +resident in 'trunk\WinOF\Wix\*.cer'; your company Cert must be placed in the +local cert store under the default personal 'My' store. +see trunk\winof\buildrelease.bat for an example of how to invoke driver +signing or 'WIX\sign-all-drivers.bat'. +Also see the Microsoft 'Kernel Mode Code Signing' document +'KMCS_Walkthrough.doc'; goggle for current URL. + + +Creating a WIX tool set +------------------------- + +Download the WIX v3 (stable) tool set (http://sourceforge.net/projects/wix/) +to ‘OFED\WIX\WIX_tools\’. +Unzip the archive to a folder within 'WIX_tools\' as this folder represents the +version of the tool set. +Something like unzip wix-3.0.5419.0-binaries.zip into wix-3.0.5419.0-binaries\. +You would now have the following structure: + OFED\WIX\WIX_tools\wix-3.0.5419.0-binaries\{candle.exe, light.exe,...} +Point being Trunk\OFED\buildRelease.bat needs the path to the WIX tool set. + +*** Temp workaround *** + +Also download a weekly Wix 3.5 build and extract the file 3.5\bin\difxapp_ia64.wixlib +and copy to 'OFED\WIX\WIX_tools\wix-3.0.5419.0-binaries\'. +The file difxapp_ia64.wixlib was missing from the WIX 3.0 stable release and +added back into the 3.5 weekly builds. + + + +Updating Release Files +--------------------- + +Update Release_notes.htm file. + + The file 'Release_notes.htm' represents the next to be released + WinOF version, as reflected by is Release ID. + + Release ID number (e.g., 1.0, point releases are 1.0.x) + + New features + + Know issues + +Update the trunk\docs\Manual.htm file for new features. + + +BUILDING a .msi installer image file +------------------------------------ + +Easy way: + place MS cross certificate file (.cer) in WIX\ folder; 'My' cert store needs + to contain your company cert file; OFED\BuildRelease.bat needs the name of + your company cert file; OFA case 'OpenFabrics Alliance'. + . + cd trunk\ + From a standard DOS cmd window, not a WDK cmd window, say + + buildrelease all # .msi files created in %windir%\temp\*.msi + + buildrelease makebin - assumes trunk\bin\* built, + populates WIX\{wlh,wnet,wxp}\bin folders. + buildrelease sign - sign driver files & exit, assumes makebin has been run. + buildrelease msi - signs & creates installers assuming makebin has been run. + buildrelease wix - creates .msi installers - assumes all bin\ folders + populated and drivers signed. + +CPU specific builds + +CD to the WIX OS-flavor and architecture specific directory. 'nmake.exe' needs +to be in your command window search path. Build three arch specific installers +(.msi files) for WLH and WNET; WXP is x86 only. + +WARNING: + assupmtion: .\bin is populated correctly from makebin.bat or + 'BuildRelease makebin'. + +cd gen1\trunk\OFED\WIX\wlh\x86 & nmake + Results in a .\WOF_wlh_x86.msi installer image. + +cd gen1\trunk\OFED\WIX\wlh\x64 & nmake + Results in a WOF_wlh_x64.msi installer image. + +cd gen1\trunk\OFED\WIX\wlh\ia64 & nmake + Results in a WOF_wlh_ia64.msi installer image. + + +DEBUG Installation +------------------ +Create a log file for a given .msi installation: + + msiexec /I "OFED_x86.msi" /Lv \temp\msi.log + + Also see %windir%\inf\setupapi.dev.log on Svr08 & Vista for driver load + logging. + +Command line way to set an interface's IP address, netmask, no gateway: + + netsh interface ip set \ + address "Local Area Connection 3" static 10.10.4.200 255.255.255.0 + netsh interface ip show address "Local Area Connection 3" + + diff --git a/branches/WOF2-3/OFED/WIX/README_checked.txt b/branches/WOF2-3/OFED/WIX/README_checked.txt new file mode 100644 index 00000000..0a2424bb --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/README_checked.txt @@ -0,0 +1,18 @@ + +Installing Checked drivers which are signed. + +For Server 2003 or XP, replace the installed .sys file (%windir%\system32\drivers) +with the checked version. + + +For Server 2008 or Vista, install with the signed .inf & .cat checked files. + +1) Make a copy of the free driver .sys and it's .cat file from the correct install + folder in Winof\ {IBcore, net or storage}. + +2) Copy checked driver .sys and .cat file from the OFED\Checked\kernel folder to + correct install folder; where free versions were located. + +3) Uninstall currently installed free driver; right-click uninstall. + +4) Install signed debug from it's inf file using the found new hardware wizard. diff --git a/branches/WOF2-3/OFED/WIX/README_release.txt b/branches/WOF2-3/OFED/WIX/README_release.txt new file mode 100644 index 00000000..46ce52db --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/README_release.txt @@ -0,0 +1,82 @@ + +[01-15-10] OFED 2.2 RC2 Release available + +Release available @ http://www.openfabrics.org/downloads/OFED/v2.3_RC0 + +Please address comments and concerns to https://bugs.openfabrics.org and/or the +Windows OpenFabrics email list ofw@lists.openfabrics.org + + +OFED Release Summary +----------------- + +1) The OFED 2.2 release is based on openib-windows source svn revision + (branches\OFED2-2 svn.2667). + + Last OFED release (2.1) based on svn.2476. + +2) Features + + Installers available for Windows 7 & Server 2008 R2 + + NDIS 6 IPoIB for Server 2008, Svr 2008 R2, Windows 7 and Vista. + + NDIS 5.1 IPoIB for Server 2003 & XP. + + uDAPL 2.0.25 code base: + No longer supporting uDAT/uDAPL version 1.0, uDAT/uDAPL version 2.0 only. + + OpenSM upgraded to version 3.3.3 (see %windir%\temp\osm.log for SM details). + + OFED installer upgraded to WIX 3.0 + + ND/winverbs provider available as a technology preview (see ndinstall -h). + + +2) Bug fixes in + + IB Core + IPoIB + WSD + DAT/DAPL + WinVerbs + WinMAD + OFED (Open Fabrics Enterprise Distribution [Linux]) verbs API + IPoIB + SRP + OFED Installer + manual + +**** Known Issues **** + +HCA drivers are reclassified as BOOT_START drivers to support booting from +an SRP IOC. An unfortunate side-effect is when OFED 2.2 is installed +on a system for the first time, after installation a mandatory reboot is +Required by Windows. + +After the OFED.msi file has started installation, an errant +"Welcome to the Found New Hardware Wizard" window 'may' popup; XP & Svr 2003. + +Just ignore or 'cancel' the errant FNHW popup window in order to proceed with +the installation. XP requires a cancel, for WLH & WNET, the notifier will +disappear on their own. + +You do need to answer 'Yes' or 'Continue' to popup windows which refer to +Non-Logo'ed (aka, Non-WHQL'ed) drivers being installed. + +If the install appears to hang, look around for popup windows requesting input +which are covered by other windows. +Such is the case on Server 2008 initial install - Answer 'yes' to always trust +the OpenFabrics Alliance as a SW publisher. + + +Please: + Read the Release_notes.htm file! + + make 'sure' your HCA firmware is recent: + vstat.exe displays HCA firmware version & PSID. + flint.exe (found in the Mellanox firmware tools package) displays PSID. + +Thank you, + +OFED for Windows Developers. diff --git a/branches/WOF2-3/OFED/WIX/Release_notes.htm b/branches/WOF2-3/OFED/WIX/Release_notes.htm new file mode 100644 index 00000000..7ad59495 --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/Release_notes.htm @@ -0,0 +1,1506 @@ + + + + + + + + + +WinOF Release Notes + + + + + +
+ +

+ +

Windows OpenFabrics

+ +

2.2 Release Notes

+ +

+01/13/2010

+ + + +

+Unattended Install

+

HCA Device Driver +Installation

+

+Server 2008 HPC Install Notes

+

+Setting the IPoIB Interface IP Address

+

+Uninstall

+

+Verifying +the Installation

+

+Trouble Shooting

+

+InfiniBand Subnet Management as a Windows Service

+

+Local Network Adapter Ordering

+

+Which WinOF release is installed?

+

+QLogic VNIC Configuration

+

+DAT & uDAPL Configuration

+

+SRP (SCSI RDMA Protocol) Driver Installation

+

WinVerbs

+

+Known Issues

+
+

 

+ +
+

Overview

+ +

The +Windows OpenFabrics (WinOF) release package is composed of software modules +intended for use on Microsoft Windows based computer systems connected via an +InfiniBand fabric.

+ +

 Binary +files generated from the OpenIB-windows developers subversion (svn) source tree +'svn://openib.tc.cornell.edu' +(branches\WOF2-2 svn revision 2667) +are packaged into a WIX +(Windows Installer Xml) single file install package referred to as the +Windows OpenFabrics (WinOF) release 2.2.

+

+This WinOF 2.2 is a full release as it contains:

+ +
+
    +
  • +

    Windows 7, Windows Server + 2008 R2 and HPC SP2 are now supported.

  • +
  • +

    NDIS 6 IPoIB for Server + 2008, Serverr 2008 R2, Windows 7 and Vista.

  • +
  • +

    NDIS 5.1 IPoIB for + Server 2003 & XP.

  • +
  • +

    NetworkDirect + is supported for Server 2008/HPC and Server 2008 R2/HPC (SP2).

  • +
  • +

    Mellanox ConnectX(mlx4) drivers + enhanced for increased performance and stability.

  • +
  • +

    WInVerbs and WinMad HCA + filter drivers are automatically loaded in support of OFED verbs and + diagnostics.

  • +
  • +

    OFED verbs library + enables easy porting of Linux OFED applications into the WinOF environment.

    +
  • +
  • +

    uDAT/DAPL is now a + common code base with OFED uDAT/DAPL verson 2.0.25; uDAT/DAPL v1.* is + deprecated, v2.0 only.

  • +
  • +

    Bug fixes for stability in IBcore, + ConnectX, WSD, NetworkDirect, VNIC, SRP, IPoIB, DAT/DAPL

  • +
  • +

    OpenSM ws upgraded to + version 3.3.3.

  • +
  • +

    + WIX 3.0 based + installer

  • +
+
+ +

The Windows OpenFabrics (WinOF) release package contains the following:
+
+OpenFabrics InfiniBand core drivers and Upper Level Protocols (ULPs):

+
    +
  • +

    HCA + Drivers - +  Mellanox + : + + + + ConnectX & + + + InfiniHost low level drivers.

  • +
  • +

    + + Infiniband Core components: IBAL, + Winverbs, Winmad, OFED verbs and rdma_cm.

  • +
  • +

    Upper Layer Protocols: + IPoIB, WSD, ND, VNIC, SRP Initiator and DAT/DAPL

  • +
+ +

OpenFabrics utilities:

+ +
    +
  • +

    OpenSM: InfiniBand fabric Subnet Manager

    +
  • +
  • +

    Performance + tests

  • +
  • +

    + OFED Diagnostics

    +
  • +
+ +

Documentation

+ +
    +
  • +

    User's manual

    +
  • +
  • +

    Release Notes

    +
  • +
+ +

+<Return-to-Top>

+

 

+
+

Supported Platforms, Operating Systems and Infiniband Hardware

+ +

CPU architectures

+ +
    +
  • +

    x64 (x86_64, amd64)

    +
  • +
  • +

    x86

    +
  • +
  • +

    IA64

    +
  • +
+ +

Operating Systems

+ +
    +
  • +

    Windows + Server 2008 R2

    +
  • +
  • +

    Windows + Server 2008 R2 + HPC SP2

    +
  • +
  • +

    Windows 7

    +
  • +
  • +

    Windows + Server 2008

  • +
  • +

    + Windows Server 2008 HPC

  • +
  • +

    + Vista

  • +
  • +

    + Windows Server 2003 + / XP64

  • +
  • +

    + Windows XP32 (SP2)

  • +
+ +

Supported HCAs (Host Channel Adapters)

+ +

Mellanox - all InfiniBand HCA products are supported.

+ +Mellanox Firmware (FW) versions and update tools
+
+Current HCA firmware version can be viewed from the 'vstat' command or the +Mellanox firmware tool flint.

+ +

Supported Switches

+ +
    +
  • +

    QLogic

    +
  • +
  • +

    SilverStorm - + update your firmware for correct embedded Subnet Manager operation.

    +
  • +
  • +

    Voltaire

    +
  • +
  • +

    Flextronics

    +
  • +
  • +

    Due to lack of hardware + accessibility, + other vendor switches have not been tested.

    +
  • +
+ +

<Return-to-Top>

+

 

+
+

Installation +Notes

+ +

User mode tools and diagnostics are installed in '%SystemDrive%\Program +Files\WinOF'.  Although device driver modules initially reside in +'%SystemDrive%\Program Files\WinOF\Drivers', when installed the Windows device +installer copies driver files to %SystemRoot%\system32 & %SystemRoot%\SysWOW64'. +DAT & DAPL runtime libraries are installed into %SystemRoot% in order to be +accessible by user mode applications.
+WinOF user mode executables are designed to be run from +a Command Prompt window; see  'Start->Program Files-> Windows OpenFabrics-> Command Prompt'.

+

'%SystemDrive%\Program Files\WinOF' is appended to the system wide search +path environment variable 'PATH'; any command windows created after the installation will have the updated +%PATH% environment variable, hence will be able to access WinOF executables.

+ +

The ‘default’ installation installs ‘released/free’ (not +checked/debug) versions of drivers and executables. Debug/Checked versions are +available as an install feature.

+ +

A single instance of a subnet manager, opensm.exe, must be +running on a fabric connected node in order for the Infiniband fabric to be +configured and useful; either Windows or Linux OFED opensm work well.

+

It is recommended that OpenSM be run as a Windows service.  A typical +WinOF install will install OpenSM as a Windows service which +is disabled; after an installation, choose your openSM node and start the openSM +service.  +See the WinOF Manual for details on opensm as a service.
+By selecting the 'OpenSM_Service_Started' install feature, a local OpenSM subnet +management service will be automatically started.

+ +

Note, the opensm.exe process must continue to run in order +to maintain Infiniband fabric configuration. Should the opensm.exe process die, +restart the service if not automatic or re-run opensm.exe in order to continue +correct fabric operation.

+ +

For more subnet management information, consult the Windows +OpenFabrics manual.

+ +

+<Return-to-Top>

+

 

+ +
+

How to Install

+ +

Summary

+
    +
  • Double-click the .msi installer file, Except for + Vista.
  • +
  • For Vista installs, from an privileged administrator command window, execute 'msiexec /I + WinOF_2-2_wlh_xxx.msi'.
  • +
+

Requirements

+ +

Install HCA hardware prior to installing the Windows OpenFabrics Release +package. Upon reboot, cancel any attempts to install new device hardware from +the "Found New Hardware Wizard".

+ +

If you have previously installed openib-windows, WinOF (Windows OpenFabrics) +packages or vendor supplied Infiniband packages, uninstall and reboot prior to +installing this version of Windows OpenFabrics (WinOF).

+ +

For an existing Windows OpenFabrics (WinOF) uninstall
+    Start-> Programs-> Windows OpenFabrics-> Uninstall WinOF
+      -or-
+    Control Panel -> Add or Remove Programs-> Windows +OpenFabrics->Remove.

+

openib-windows (IB stack before WinOF 1.0 release) uninstall: (not the normal +uninstall case)

+ +
    +
  1. Disable any Local Area Connections which are bound to the + IPoIB network adapter.
  2. +
  3. Uninstall the IPoIB driver - My + computer->Manage->Devices->Network Adapters->IPoIB*
  4. +
  5. Stop the openSM subnet manager if it is running on the + local node.
  6. +
  7. Uninstall the Infiniband HCA device; don't forget the + System Device-> InfiniBand Fabric
  8. +
+ +

 

+ +

REBOOT

+ +

Upon system restart, cancel the 'Found New Hardware Wizard' attempts to install +drivers for newly discovered PCI device (HCA).

+

'My Computer->Manage->Device Manager' should display +'Other Devices->?PCI device' which is your Infiniband HCA device.

+ +

Install

+ +
+ +

Vista installation only; open a privileged Administrator command +window and type

+

    start/wait msiexec /I WinOF_2-1_wlh_xxx.msi

+

For all other Windows variants, double-clicking the installer file (.msi) +works correctly to start a WinOF installation.
+From a login session with administrator privileges, File Explorer view, double-click the WinOF_M-m{-p}_OSE_arch.msi file to begin the Windows OpenFabrics +installation.

+

Where 'M-n{-p}' indicates Major release number, Minor release number, and +optional point-release number.

+

 OSE - Operating System Environment:

+
    +
  • wlh - (Windows LongHorn) Windows Server 2008, HPC or Vista
  • +
  • wnet - Windows Server 2003 or Windows XP 64-bit version
  • +
  • wxp - Windows XP x86/32-bit version
  • +
+

'_arch_' will be one of

+
    +
  • _x64_ for  Intel EMT64 systems or amd64; see + x86-64
  • +
  • _x86_ for x86 +compatible systems
  • +
  • _ia64_ for Intel IA64 systems.
  • +
+ +

Follow the on-screen instructions.
+
+Answer 'yes' or 'Continue' to any notifier windows which reference non-WHQL'ed +driver installation.
+These non-WHQL'ed driver install questions can not be disabled +via 'My Computer->Properties->Hardware->Driver Signing->Ignore'.

+

Bottom-line - The digitally signed WinOF drivers in this package are not WHQL'ed +per se, although they are +built from driver source which has been or is in process of being WHQL'ed by +hardware vendors who participate in the open source WinOF development process.

+

 

+

 **** WARNING ****

+
+

Should any 'Welcome to the Found New Hardware Wizard' windows popup after the + WinOF install has started, just ignore (window will disappear in a few + seconds) or 'Cancel' the errant popup window.  + For Windows Server 2003 (SP1) you can safely ignore the errant FNHW popup + window; for Windows XP (SP2) the errant FNHW popups need to be 'cancelled' + in order for the WinOF install to proceed. The report back from Microsoft on these 'Found New Hardware Wizard' windows + popping up, is they are due to the fact the WinOF drivers are not WHQL'ed + and hence are not trusted by Windows; MS claims this is a 'feature'.

+

An artifact of cancelling an errant 'Found New Hardware' popup window may + induce an errant taskbar Information notifier/bubble indicating there may + have been problems installing your hardware drivers; + IGNORE/cancel this information bubble, likely the device installation + proceeded without error. Check the Device Manager views for the + Infiniband HCA and IPoIB Network Adapters for initial verification of + correct installation.

+

You do need to answer 'Yes' or 'Continue' to those notifier windows which + reference non-WHQL driver installation. If you have previously + set My Computer->Properties->Hardware->Driver Signing->Ignore, the FNHW + windows likely will occur anyway.

+

Should the install appear to hang, look around for occluded notifier windows + waiting for a response which + are covered by existing windows.

+
+ +

Install type: Custom only

+ +
    +
  • InfiniBand Core:
      +
    • HCA driver - Mellanox: InfiniHost or ConnectX
      + Windows PNP will select the correct HCA driver.
    • +
    • IB core stack and libraries - includes winverbs, + winmad and OFED verbs library.
    • +
    • Release Notes, Manual
    • +
    • Subnet Management service [OpenSM] (installed & disabled), Performance & + OFED Diagnostic tools
    • +
    +
  • +
  • Optional:
        IPoIB - Internet Protocols over + InfiniBand
        Winsock Direct (Win2008/3 only)
    +    Network Direct (MS supported only for Server 2008 HPC).
        VNIC - Virtual Ethernet device over Infiniband
        SRP - SCSI over RDMA Protocol
        + DAT/DAPL + - RDMA device independent, user-mode Direct Access Transport & Direct Access + Provider
           - DAT v1.1  runtime libraries.
           - DAT v1.1 application build environment + (header files & link files).
           - DAT/DAPL v2.0 runtime libraries
           - DAT v2.0 application build environment
        OpenSM_service_started - InfiniBand Subnet Management + enabled and started as a Windows Service.
                                                    + By default OpenSM is installed as a disabled Windows Service.
    +    Checked versions of driver files.
  • +
  • The 'default' installation includes IB core, IPoIB, WSD (Win2K3 only), + DAT 1.1 runtime libraries, OpenSM service (disabled).
  • +
+ +
+ +

<Return-to-Top>

+

 

+
+

HCA Driver Installation

+

WinOF driver installation uses the Device Installation +Frameworks for Applications (DIFxApp) and the Windows Driver Store.
+The  Microsoft Plug-n-Play (PNP) subsystem +controls which Infiniband HCA (Host Channel Adapter) device driver is loaded +from the Windows Driver Store.  HCA driver selection is based on PNP device +ID probing, thus InfiniHost, ConnectX or both drivers can be loaded +by the PNP subsystem.
+Using DIFxApp and PNP device probing results in the WinOF installation not +requiring a specific HCA model [ConnectX or InfiniHost] feature selection; HCA +vendor is the feature selection criteria.

+


+
+

Unattended Install

+ +
+ +
+ An unattended WinOF install will install the following 'default' options
    +
  • Infiniband Core modules - Mellanox HCA driver + (see HCA driver selection note), IB core stack, libraries, utilities and + documentation.
  • +
  • IPoIB - Internet Protocols over InfiniBand
  • +
  • WSD - (Win2K8/3 only, not installed on XP) Win Sock Direct
  • +
  • ND - NetworkDirect [started automatically (via ndinstall.exe) only for Server + 2008/HPC and Vista].
  • +
  • DAT & DAPL (v1.1 & v2.0) runtime libraries + dapltest.exe + (dt-svr & dt-cli).
  • +
+
+

HCA selection for all Windows variants + (Server 2008, HPC & Vista)

+
+

Default HCA driver selection is driven by the + Windows PNP subsystem; no user selection required or supported.

+
+

Should WSD not be a desirable unattended install option (Win2008/3 only), +currently you would install unattended then execute the
+command 'installsp -r' +on each node to remove WSD.

+

To perform a silent unattended installation for Server + 2003/XP, invoke the following command + from a command window.

+
+

start/wait msiexec.exe /i WinOF_2-1_wnet_x64.msi  /qn  /quiet  /log + %TEMP%\WOF-install.log

+

'/log dev:path\logFilename.log' is optional.

+

msiexec.exe /? for all options.

+
+
+

Examples:

+

Windows XP - Mellanox HCA Hardware - same as above with .msi +name change (wnet --> wxp).

+
    +
  • ConnectX HCA
    + start/wait msiexec.exe /i WinOF_2-1_wxp_x86.msi /qb /quiet HCA=cx
  • +
+

Server 2008 / Vista - any Mellanox HCA Hardware

+
    +
  • No need to specify HCA type as PNP (Plug-n-Play)  + figures out the correct HCA to install.
    + start/wait msiexec.exe /i WinOF_2-1_wlh_x64.msi /qb /quiet
  • +
  • If you desire an unattended WinOF install with a + progress bar, from a console window
    + start/wait msiexec.exe /i WinOF_2-1_wlh_x64.msi /passive
  • +
+

 

+

Non-HCA Install Features added to above msiexec command +line examples:

+
    +
  • Start a Subnet Manager running on the local system: + add 'OSMS=1'
  • +
+

Default install +  OpenSM Started on the local +system

+
    +
  • Server 2003, Mellanox HCA - start/wait msiexec.exe /i WinOF_2-1_wnet_x64.msi + /passive  OSMS=1
  • +
+

<Return-to-Top>

+

 

+
+

Server 2008 HPC Install Notes

+

Device drivers in WinOF 2.0 and later releases are Digitally +signed by the 3rd party Software Publisher 'OpenFabrics Alliance', although they are not WHQL'ed (Windows Quality Hardware Labs) certified. +The WinOF source code is used  by hardware vendors to achieve WHQL +certification.

+

The lack of WHQL driver certification places WinOF drivers +in the 'unknown 3rd party SW publishers' category.
+When installing 'Unknown 3rd party SW publishers' drivers, Windows prompts on +the install console for instructions as what to do (Install, Trust or not)?
+This prompting results in a failed remote node install when performing a +first-time unattended WinOF install.
+By preloading the remote node's Trusted 3rd party Software Publisher Certificate +Store, the unattended install will proceed without prompting, thus allowing the WinOF install to complete +successfully.

+

Be aware: if a node is reimaged (same or different template applied) the +established trust of the OpenFabric Alliance is destroyed, thus the OFA certificate +needs to be reinstalled.

+

How to install WinOF drivers and components in the HPC +Server 2008 environment.

+
    +
  • Add the OpenFabrics Alliance Trusted SW Publisher certificate to the head-node's Trusted Publisher Certificate store by
      +
    • Installing WinOF on the head node - start Open Subnet + Manager if needed, otherwise depend on another OpenSM on the IB fabric.
    • +
    • Our recommendation is to install WinOF on the + head-node; Set head-node IPoIB interface IPv4 address after WinOF install.
    • +
    • Or - Installing the OFA certificate from the + installer .msi file by
        +
      • right-clicking the .msi file, select Properties
      • +
      • Select the Digital Signatures tab
      • +
      • Highlight the OpenFabrics Alliance
      • +
      • Details
      • +
      • View Certificate
      • +
      • Install certificate
      • +
      • Trusted Publisher certificate store
      • +
      +
    • +
    +
  • +
  • Once the OFA certificate is installed, it will remain + until the node is wiped clean by reprovisioning.
  • +
  • If remote nodes are operational (booted & + network accessible), then run the digital certificate install script 'cert-add.bat' + to 'add' the 'Open Fabrics Alliance' as a Trusted 3rd party Software Publisher + to the remote node 's certificate stores.
      +
    • CD your administrator command window to the WinOF + folder which contains the 'cert-add.bat' script file.
    • +
    • If WinOF was installed on the head-node, then 'cd /d + %ProgramFiles%\WinOF
    • +
    • Otherwise unpack, not install, the WinOF files to + gain access to cert-add.bat file by executing the following commands:
        +
      • Folder %TARGETDIR% folder must not exist, msiexec + /A will create it.
      • +
      • msiexec /A WinOF_2-1_wlh.msi TARGETDIR=%TEMP%\WOF    + # WOF folder does not exist.
      • +
      • cd /d %TEMP%\WOF\PFiles\WinOF
      • +
    • +
    +
      +
    • Select a filesystem share folder which is + accessible from the head-node and 'all' remote nodes specified in the + cert-add command; cert-add will write a batch script to this folder + which the remote node will execute to add the OFA SW Publishing + certificate to the local store.
    • +
    • Cert add command format:  cert-add    + share-folder   list-of-remote-nodes
    • +
    • For the examples, assume + \\HN\WOF is the compute node visible share name;
      + head-node local name is \Program Files\Microsoft HPC Pack\Data\InstallShare\WOF
      + Head-node uses remote share name \\HN\WOF.
    • +
    • First extract OFA TP certificate to remote + node visible share, creates + \\HN\WOF\OFA_TP.cer & + \\HN\WOF\rem-cert-ADD.bat
      +    cert-add + \\HN\WOF
    • +
    • example:  add OFA Trusted Publisher + certificate to remote node's local certificate store
          cert-add + \\HN\WOF cn01 cn02 cn03 cn04 + cn05
    • +
    • +
    • For all compute nodes:  clusrun /nodes:X  msiexec /I + \\HN\WOF\WinOF_xxx_yyy.msi + /quiet /qn /Lv msi.log
       
    • +
  • +
  • Node Template Provisioning: if remote nodes are not + operational (not yet provisioned) then do the following:
      +
    • See %ProgramFiles%\WinOF\HPC\* for provisioning + example scripts; customization is required.
    • +
    • From the head node, extract the OFA certificate to a + file in the remote node visible share file OFA_TP.cer;
       (example + Remote node visible share: \Program Files\Microsoft HPC Pack\Data\InstallShare\WOF  + == \\HN\WOF)
      +    Start -->All Programs -->Windows OpenFabric --> WinOF Command + Window
      +    cd HPC
      +    cert-add \\HN\WOF        + # \\HN\WOF is the remote node visible + share; create \\HN\WOF\OFA_TP.cer
       
    • +
    • copy the following files to (example: \Program + Files\Microsoft HPC Pack\Data\InstallShare\WOF)
        +
      • WinOF installer .msi file
      • +
      • %ProgramFiles%\WinOF\HPC\OFA-cert-install.bat
      • +
      • %ProgramFiles%\WinOF\HPC\WinOF-install.bat
      • +
    • +
    • Verify you have the required WinOF provisioning files + in the remote node visible share:
        +
      • WinOF installer .msi file, referenced in + WinOF-install.bat
      • +
      • OFA-cert-install.bat
      • +
      • WinOF-install.bat
      • +
      • rem-cert-ADD.bat
      • +
      • OFA_TP.cer
      • +
    • +
    • Run the cluster manager tool to create a compute node + template; include the following steps as part of the node provisioning + template steps after the HPC pack has been installed:
        +
      •  copy entire contents of (example: \Program + Files\Microsoft HPC Pack\Data\InstallShare\WOF) to remote node as
        + %INSTALLDRIVE%\WOF
      • +
      • execute the DOS command: %INSTALLDRIVE%\WOF\OFA-cert-install.bat
      • +
      • execute the DOS command: %INSTALLDRIVE%\WOF\WinOF-install.bat
      • +
    • +
    • Use 'cluster manager' to provision all compute nodes + using newly created compute node template.
    • +
  • +
  • Set the IPoIB interface static IPv4 address on all compute + nodes; 1st IPoIB instance will be the next 'Local Area Connection X' after + the Ethernet port(s) on the compute node.
      +
    • clusrun /nodes:X netsh interface ip set address + "Local Area Connection 3" static 10.10.4.1 255.255.255.0
    • +
    • clusrun /nodes:X netsh interface ip show address + "Local Area Connection 3"
    • +
  • +
  • IPoIB supports DHCP IP address assignment for those + who choose to use it. Static IP address binding allows a direct mapping from + IP address to physical node number.
  • +
  • IPoIB static IPv4 address assignment points of + Interest
    + When installing WinOF one must consider how the Interface name 'Local Area + Connection {x}' is assigned to the IPoIB ports in order to correctly target + IP address assignment.
    + Assume the target compute node has two Ethernet port and your HCA has two IB + ports.  After the 1st  WinOF installation, or node reprovisioing + you will see the following assignments:
      +
    • Ethernet port 0 is 'Local Area Connection'
    • +
    • Ethernet port 1 is 'Local Area Connection 2'
    • +
    • IB port 1 is 'Local Area Connection 3'
    • +
    • IB port 2 is 'Local Area Connection 4'
    • +
    +

    A few minutes after the WinOF install completes, the + HPC manager will rename the active IPoIB 'Local Area Connection 3' network + interface to the 'Application' network interface along with the active + Ethernet interface being renamed to the 'Private' network; 'Local Area + Connection' is no longer in use.
    + If WinOF is uninstalled and then reinstalled without node reprovisioning, + the active IPoIB network interface is installed as 'Local Area Connection'.  + Within a few minutes, the active IPoIB network interface will again be + renamed the 'Application' network interface.
    + Summary:
    +    1st WinOF install, an IB cable is attached to HCA port 1, + IPoIB is named 'Local Area Connection 3'.
    +    2nd WinOF install, IPoIB is named 'Local Area Connection' as + the Ethernet interface is renamed the 'Private' network.

  • +
  • At this juncture, the WinOF drivers are installed.
  • +
+

Windows Deployment Manager usage for HPC compute node provisioning

+

Microsoft has chosen WDM to provision HPC +cluster compute nodes; see  +Microsoft HPC +installs for details.

+

In support of the new Microsoft WDM HPC cluster +provisioning process, WinOF now supports an administrative install mode which is +a method to extract WinOF files to the local filesystem without actually installing them; +thus making WinOF files accessible to WDM provisioning.

+

Disclaimer - WDM 'driver' provisioning ONLY works for +WHQL'ed drivers; WinOF drivers are not WHQL'ed.  For WinOF installs, see +previous node template provisioning discussion.

+

msiexec /A WinOF_2-1_wlh_x64.msi TARGETDIR=dev:\path-to-extracted-files    +# last folder in path-to-extracted-files must NOT exist.

+

example:  msiexec /A WinOF_2-1_wlh_x64.msi TARGETDIR=%TEMP%\WOF   +(note: TARGETDIR is case sensitive, WOF must not exist)

+

The above command creates the folder structure: +%TEMP%\WOF\PFiles\WinOF\

+

WinOF device driver-less installs:

+

Normally WinOF device driver files are installed by processing the driver '.inf' +files. To install the WinOF package by selecting install features without +installing any device drivers [HCA, IPoIB, ND, WSD, SRP or VNIC] (assumed +reliance on WDM to install device drivers) can be accomplished with the following +interactive install command:

+

start/wait msiexec /I WinOF_2-1_wlh_x64.msi  NODRV=1

+

To skip driver installation for an unattended install

+

    start/wait msiexec /I WinOF_2-1_wlh_x64.msi /qn /quiet NODRV=1

+

Note: when uninstalling WinOF from an installation +which was done with NODRV=1, you MUST include NODRV=1 on the uninstall +command line; otherwise WinOF drivers will be uninstalled also.

+

    start/wait msiexec /X WinOF_2-1_wlh_x64.msi /qn /quiet NODRV=1

+

See Unattended +Installations for further references.

+

<Return-to-Top>

+

 

+
+

Setting the IPoIB Interface IP Address

+

The Windows command 'netsh' will assist in assigning an IP address to an +IPoIB interface.
+By default, an IPoIB interface is configured to use DHCP. The following +discussion deals with setting a static IP address on an IPoIB interface.
+If your system has two Ethernet ports, then IPoIB interfaces (HCA port 1, 2...) +will be assigned to 'Local Area Connection 3' and 'Local Area Connection 4'.  +If you system has a single Ethernet port, then IPoIB interface is 'Local Area +Connection 2'.

+

For Server 2008/HPC systems, the WinOF installation follows the above +discussion. In defining HPC network interfaces, the IPoIB network will +eventually be +identified as the 'Application' network '.  A few minutes after a +compute node is installed, the HPC  network manager will rename the installed IPoIB 'Local Area Connection X' network interface to the 'Application' network.

+

Display all network interface configuration information
+        netsh interface ip show config
+        netsh interface ip show address +"Local Area Connection 3"

+

Config a static IP address for an IPoIB interface: [Local Area Connection 3 +== 1st IPoIB interface], 10.10.4.23 is the assigned IP address
+with a netmask of 255.255.255.0, the gateway is 10.10.4.1 metric is 2.

+

        netsh interface ip set address +"Local Area Connection 3" static 10.10.4.23 255.255.255.0 10.10.4.1 2

+

See netsh for further +reference.

+

<Return-to-Top>

+

 

+
+

Uninstall

+ +

To uninstall a WinOF package from a single node

+
    +
  1. Start--> All Programs-> Windows OpenFabrics-> Uninstall WinOF
  2. +
  3. Control Panel-> Add Remove Programs-> Windows OpenFabrics-> Remove
  4. +
+

Unattended +Uninstall

+

From a Command Window invoke the following command; a system reboot will +occur after the uninstall.

+
+

start/wait msiexec.exe  /x {3A6A276E-A636-48E8-8624-9A0DE3F2A15E} + /quiet + /forcerestart
+  - or -
+ start/wait msiexec.exe  /x WinOF_wlh_2-1_x64.msi /quiet /forcerestart        + # WinOF_xxxx.msi is the file used to install WinOF.

+

msiexec.exe /help for details.

+

'/log dev:path\logfilename.log'  if you wish to later view the install + results.

+

If for some reason the Product Code {GUID} changes, the latest code can + be located via
Programs-> Windows OpenFabrics-> Uninstall WinOF<right-click>Properties

+
+

Infrequently, the 'System Device->Infiniband Fabric' may not correctly uninstall. Make sure the Infiniband Fabric device is + completely uninstalled; use device manager for checking. The effect of a + partially uninstalled Infiniband Fabric device is IPoIB load failure + upon the next WinOF install.

+

Uninstall Notes

+
    +
  1. If the SRP (SCSI RDMA Protocol) driver has been previously installed, + then in order to achieve a 'clean' uninstall, the SRP target drive(s) must + be released.
      +
    • Use the following diskpart.exe commands from an administrator + privileged command window:
    • +
    • c:\windows\temp> diskpart.exe
      +    SELECT VOLUME=<Drive Letter of the SRP target to be released>        + # example: SELECT VOLUME=L
      +    OFFLINE DISK
      +    EXIT
    • +
    • For additional SRP drives, repeat SELECT & OFFLINE DISK with new + Drive Letter.
    • +
    +

    The consequences of not releasing the SRP target drive(s) is that after the + uninstall reboot there are lingering InfiniBand driver files. These driver + files remain because while the SRP target is active they have references, + thus when the uninstall attempts to delete the files the operation fails.

    +
  2. +
+

<Return-to-Top>

+

 

+

Verifying the +WinOF install

+
    +
  • From a command windows type 'devmgmt.msc'. Look for + InfiniBand HCA device(s) along with Network IPoIB devices .
  • +
  • From a command-window, type 'ibv_devinfo' which + should print "hca_id: ibv_device0" on the first line.
  • +
  • Make sure that a Subnet Manager is running on the + fabric by invoking the sminfo utility.
    +
    + If an SM is not running, sminfo prints:  sminfo: iberror: query failed
    +
    + If an SM is running, sminfo prints the LID and other SM node information.
    +
    + Example:  sminfo: sm lid 0x1 sm guid 0x2c9010b7c2ae1, activity count 20 + priority 1
  • +
  • To check if OpenSM is running on the 'management' + node, enter:  'services.msc'.
    + Look for the Infiniband Subnet Manager entry; it should be automatic & + started.
    + View %windir%\temp\osm.syslog or %windir%\temp\osm.log files to see how + OpenSM started.
  • +
  • Verify the status of ports by using ibv_devinfo: all + connected ports should report a "PORT_ACTIVE" state.
  • +
  • Check the network connectivity status: run + ibnetdiscover to see if the subnet is "clean" and ready for ULP/application + use.
    + Note: ibndetdiscover scans the entire fabric.
  • +
  • After you have assigned an IP address to the IPoIB + Local Area Connection(s).  From a command-window, type 'ping IPoIB_addr'; + where IPoIB_addr is an address of an IPoIB instance on another fabric + connected system.
  • +
+

<Return-to-Top>

+

 

+

Trouble Shooting

+

From a command window type the following quick-start +commands:

+
    +
  • To start the Device Manager:  'devmgmt.msc'
    + Look for InfiniBand HCA devices along with IPoIB network devices.
  • +
  • To start the Services Manager:  services.msc
    + If the Subnet Manager was installed as 'started' on this system, find the + InfiniBand Subnet Manager entry; entry should be automatic & started.
  • +
+

A Vista WinOF installation can fail due to protection failures when +installing the HCA driver. Vista HCA driver installation failure can be caused +by  double-clicking the .msi installer +file to start the installation.
+WinOF installs for (Vista only) require the installation be started  from a +privileged Administrator command window.
Start a privileged Administrator command window (Start->Command +Prompt->Right-click->Run as Administrator) and execute:
+    msiexec /I +WinOF_xxx_yyy.msi

+

To create a LOG file of your WinOF installation, execute this command: +msiexec /I WinOF_xxx_yyy.msi  /Lv %TEMP%\WOF-install.log
+View %TEMP%\WOF-install.log

+

msiexec /? for details.

+

Server 2008 or Vista can also fail to install due to driver install files +left over from previously failed install attempts; see %windir%\system32\DriverStore\{Temp|FileRepository}. +Look for folders with the following in the folder name: mthca, mlx4_, netipoib, +srp, vnic. Once you have located one of these folders you need to remove it as +win2k8/Vista will use these files instead of what your attempting to install.; +removing the folders is a pain.
+Right-click the folder and select Properties->Security->Advanced, select owner +tab, select Edit button, select Administrator and check the 'Replace owner on +subcontainers and objects', now click 'OK', OK again, select Edit button from +the securities tab, check allow 'Full Control' box and click OK, OK again. At +this point you should be back to the file explorer. Now you can delete the +folder!

+

Setupapi.log has moved in Server 2008/Vista, see '%windir%\inf\setupapi-dev.log'. +Setupapi-*.log can at times contain useful install debug info.

+

Server 2008/Vista/HPC all use dpinst.exe to preinstall drivers into the +driver store. Windows PNP (Plug-n-Play) later will deamand drivers when the +hardware is recognized. dpinst.exe writes it's error information to '%windir%\dpinst.log'.

+

Down rev firmware will result in IPoIB not installing or other anonmolus +behavior. Consult the event +viewer, system error records, look for 'mthca' or 'mlx4*' entries generated when the HCA +driver loads. One of the mthca or mlx4 entries will display the current firmware +revision.

+

Firmware version information and updates + are available at + + www.mellanox.com/support/firmware_download.php

+ +
+
+ + •
+
+
+ + –
+
+
+ + •If + HCA FW is older than minimal FW +
+
+
+ + Error + reported to system event log
+
+ + + + –HCA loads as memory controller to allow FW upgrade +
+
+
+ + + •If HCA  + FW is equal or newer than optimal version
+
+
+ + + + –HCA starts OK. + +
+
+
+ + + •Else
+
+
+ + + HCA loads OK.
+
+ + + + –Warning will be issued to system event log + +
+
+
+ + + + – +
+
+ My computer-> Manage-> Event Viewer-> System Events; search for + mthca, mlx4 or ipoib entries.

<Return-to-Top>

+

 

+

Incomplete Previous Uninstall

+

Should the previous uninstall silently fail, the next installation + can fail in the Driver Install phase with the following error:
+    DriverInstall - HCA Ret 2 Error 0
+
+ At this juncture, check the Device Manager and uninstall the PCI + device from 'InfiniBand Host Channel Adapters', and make sure you uninstall the system device + 'InfiniBand Fabric' if it is present.
+
+ REBOOT and retry the WinOF installation again.

+ See + ibscan.bat and ibcleanup.bat @ + + http://www.openfabrics.org/downloads/WinOF/etc/.
+ ibscan will display WinOF files on your system.
+ ibcleanup will attempt to remove all WinOF files from your syste. + WARNING - ibcleanup is not valid as a WinOF uninstall tool!

<Return-to-Top>

 

+
+

Correct Installation Validation

+

From the Device Manager you should find the following devices:

+
    +
  • From a command window type 'devmgmt.msc'
  • +
  • InfiniBand Host Channel Adapters -> InfiniHost or Mellanox ConnectX
  • +
  • The System Devices -> InfiniBand Fabric device is no longer present in + WinOF 2.0 and following releases.
  • +
  • Network Adapters -> OpenIB IPoIB Adapter (an Instance per HCA port).
  • +
+
+

Validation Test

+

Open a WinOF command window

+
    +
  1. Start->Program Files->Windows OpenFabrics -> Command +Window
  2. +
  3. run vstat.exe to view HCA configuration.
  4. +
  5. If IPoIB is installed (Device Manager->Network Adapters), ping another node on the InfiniBand fabric 'ping a.b.c.d'
  6. +
+
+

<Return-to-Top>

+

 

+
+

Subnet Management as a Windows Service

+

Limit the number of Subnet Managers on your fabric; one SM per fabric is +sufficient, although redundant Subnet Managers are supported.

+
    +
  1. After a 'typical' WinOF install, OpenSM is installed as a disabled + Windows service named "InfiniBand Subnet Management".
    + To start the OpenSM service, from a command window type 'services.msc' to + start the Services manager.  From the Services manager, find and select + 'InfiniBand Subnet Manager' view; Click the start button and set the service properties to 'auto' in order to restart on the next + system reboot.
  2. +
  3. Install OpenSM as an automatic/running Windows service:
    + a) Select the 'OpenSM_service_Started' install feature. Once + the install has completed, check that the Infiniband Subnet Manager service + is running: From a command windows type 'services.msc' to start the Services + manager. Find and open the InfiniBand Subnet + Manager view.
  4. +
  5. Consult the OpenSM log file @ %SystemRoot%\temp\osm.log to see what + OpenSM thinks is happening.
  6. +
+

<Return-to-Top>

+

 

+
+

Local Network Adapter Ordering

+

Local Network Adapter ordering, which results in the IP address advertised +for the system, can be managed from
    'My Network Places-> Advanced Tab-> Advanced settings'
From the Advanced settings display, the ordering +of Local Network Adapters can be +reordered after the IPoIB Local Network Adapters have been installed. Please +check for your desired adapter ordering.

+ +<Return-to-Top>

+

 

+
+

Which WinOF release is installed?

+
    +
  1. Control Pannel -->Add/Remove Programs or  + -->Programs/Features entry identifies the installed WinOF release version.
  2. +
  3. Start->Programs->Windows OpenFabrics (check + Uninstall entry).
  4. +
  5. Driver confirmation from the Device Manager:
        Query My Computer-> Manage-> Device Manager-> Network +Adapters-> OpenFabrics IPoIB Adapter-> Properties-> Driver-> Details
        The subversion (svn) revision number will be listed under +'Driver Version'. The svn revision number will match what's listed in the +release notes.
  6. +
  7. Hold the mouse point over \Program Files\WinOF\ib_read_bw.exe to display +the file version; [WinOF-Major.Minor.not-used.svn revision number].
  8. +
+
    +
  • WinOF 1.0 is based on openib-windows svn revision 614 @ + http://openib.tc.cornell.edu/downloads/binaries/ .
  • +
  • WinOF 1.0.1 is based on openib-windows svn revision 864.
  • +
  • WinOF 1.1 is based on openib-windows + (svn revision 1177 branches\WOF1-1).
  • +
  • WinOF 2.0 is based on (svn.1763 branches\WOF2-0)
  • +
  • WinOF 2.1 is based on (svn.2476 branches\WOF2-1)
  • +
  • WinOF 2.2 is based on (svn.2667 branches\WOF2-2)
  • +
+

<Return-to-Top>

+

 

+
+

QLogic VNIC Configuration

+

+The QLogic VNIC +(Virtual Network Interface Card) driver in conjunction with the QLogic Ethernet +Virtual I/O Controller (EVIC) provides virtual Ethernet interfaces and transport +for Ethernet packets over Infiniband.
+
+Users can modify NIC parameters through User Interface icon in Network +Connections:
+( Properties->"Configure..." button -> "Advanced" Tab).

+

+Parameters +available:
+
+Vlan Id (802.1Q) 

+

+  values from 0 to +4094 ( default 0, disabled )
+  This specifies if VLAN ID-marked packet transmission is enabled and, if so, +specifies the ID.
+
+Priority (802.1P)

+

+  values from 0 to 7 +( default 0, feature disabled)
+  This specifies if priority-marked packet transmission is enabled.
+
+Payload MTU size 

+

+  values from 1500 +to 9500 (default 1500)
+  This specifies the maximum transfer unit size in 100 bytes increments.
+
+Recv ChkSum offload 

+

+  (default enabled)
+  This specifies if IP protocols checksum calculations for receive is offloaded.
+
+Send ChkSum offload

+

+  (default enabled)
+  This specifies if IP protocols checksum calculations for send is offloaded.

+

+Secondary Path 

+

+   (default +disabled)
+   Enabled - If more than one IB path to IOC exist then secondary IB instance of +virtual port will be created and configured with the same parameters as primary +one. Failover from Primary to Secondary IB path is transparent for user +application sending data through associated NIC.
+
+   Disabled – only one path at a time is allowed. If more than one path to IOC +exists then failed path will be destroyed and next available path will be used +for new connection. With this scenario there is a possibility new interface +instance will be assigned different MAC address when other hosts compete for +EVIC resources.

+

+LBFO Bundle Id
+   (default disabled) Enabling support for OS provided Load Balancing and Fail +Over functionality on adapter level.
+   If enabled group ID can be selected from predefined names.

+

+ 

+

+Heartbeat interval

+

+   configures +interval for VNIC protocol heartbeat messages in milliseconds.
+   0 – heartbeats disabled.
+
+Note:
+   To take advantage of the features supported by these options, ensure that the +Ethernet gateway is also configured appropriately.  For example, if the Payload +MTU for a VNIC interface is set to 4000, +the MTU at the EVIC module must also be set at least 4000 +for the setting to take effect.

+
+

<Return-to-Top>

+

 

+
+

DAT & uDAPL Configuration

+

In order for DAT/DAPL programs to execute correctly, the 'dat.dll' +file must be present in the current directory, +%SystemRoot% or in the library search path.

+

WinOF installation places the dat2.dll and dapl2.dll +files in the '%SystemRoot%' +folder (a.k.a. \Windows).

+

The DAT/DAPL configuration file by convention is defined as +'%SystemDrive%\DAT\dat.conf'. If the file '%SystemDrive%\DAT\dat.conf' does not exist, +a template configuration file will be installed as '%SystemDrive%\DAT\dat.conf'.
+In order to preserve existing installations, the dat.conf file is not +automatically installed if '%SystemDrive%\DAT\dat.conf' exists.
+A sample dat.conf file is always installed as '\Program Files\WinOF\dat.conf +'.

+

The default DAT configuration file specification can be overridden by use +of the environment variable DAT_OVERRIDE. Such that 'DAT_OVERRIDE=D:\MyDAT\test.conf' +would be a valid override specification.

+

Within the dat.conf file, the DAPL library specification can be +located as the 5th whitespace separated line argument. By default the DAPL +library file is installed as %WINDIR%\dapl2.dll'.

+

Should you choose to relocate the DAPL library file to a folder +where whitespace appears in the full library path specification, then the full +library file specification must be contained within double-quotes. A side effect +of the double-quotes is the library specification is treated as a Windows string +which implies the '\' (backslash character) is treated as an 'escape' character.  +Hence all backslashes in the library path must be duplicated when enclosed in +double-quotes (e.g., "C:\\Programs Files\\WinOF\\dapl.dll").

+

uDAT/uDAPL version 2.0 runtime +libraries are identified as dat2.dll and dapl2.dll, both in %SystemRoot%; see +manual for further details.
+uDAT/uDAPL version 1.1 runtime libraries identified as dat.dll and dapl.dll, are +no longer available as support for v1.1 is deprecated.

+

+<Return-to-Top>

+

 

+
+

SRP (SCSI RDMA Protocol) Driver Installation

+

The WinOF installer does not install the SRP driver as part of a default +installation.  +If the SRP feature is selected in the custom installation window, an InfiniBand +SRP Miniport driver will be installed; see the device manager view under SCSI +and RAID controllers.

+

The system device 'InfiniBand I/O Unit' (IOU) +device is required for correct SRP operation.  The WinOF installer will +install/load the IOU driver if the SRP feature is selected.  See the device +manager view System Devices --> InfiniBand I/O Unit for conformation of correct +IOU driver loading.

+

In order for the SRP miniport driver installation to complete, an SRP target must be +detected by a Subnet Manager running somewhere on the InfiniBand fabric; either +a local or remote Subnet Manager works.
+When the subnet manager communicates the existence of an SRP target, Windows PNP +(Plug-n-Play) will match the IOC device ID with DriverStore installed drives and +then will load the IBiou.sys driver along with the ib_srp.sys driver.

+

An invocation of 'diskmgmt.msc' will display +available SRP target disks.

+

Consult the WinOF manual for further SRP +topics including configuring a Linux OFED SRP target.

+

SRP Driver Uninstall

+

If the SRP (SCSI RDMA Protocol) driver has been previously +installed, then in order to achieve a 'clean' uninstall, the SRP target drive(s) +must be released.   Unfortunately the 'offline disk' command is only +valid for diskpart (ver 6.0.6001) which is not distributed with Windows Server +2003 or XP.

+
    +
  • Use the following diskpart.exe commands from an administrator privileged + command window:
  • +
  • + + + c:\windows\temp> diskpart.exe
    +    SELECT VOLUME=<Drive Letter of the SRP target to be released>        + # example: SELECT VOLUME=L
    +    OFFLINE DISK
    +    EXIT
  • +
  • For additional SRP drives, repeat SELECT & OFFLINE DISK with new Drive + Letter.
  • +
+

The consequences of not releasing the SRP target drive(s) are that after the +WinOF uninstall reboot there are lingering InfiniBand driver files. These driver +files remain because while the SRP target is active they have references, thus +when the WinOF uninstall attempts to delete the files the operation fails.

+

+
+<Return-to-Top>

+

 

+
+ +
+

WinVerbs

+

WinVerbs is a userspace verbs and communication management interface +optimized +for the Windows operating system. Its lower interface is designed to support +any RDMA based device, including Infiniband and iWarp. Its upper interface is +capable of providing a low latency verbs interface, plus supports Microsoft's +NetworkDirect Interface, DAPL, and OFED libibverbs interfaces. It consists of
+a userspace library and a kernel filter driver.
+
+The WinVerbs and WinMAD drivers load as upper filter drivers for the Infiniband HCA +device.
+(Open source iWarp drivers for Windows are not yet available.)  A corresponding
+WinVerbs.dll and libibmad.dll +userspace libraries install as part of the Winverbs driver installation package.
+Additionally, a Windows port of the OFED libibverbs library, several test +programs and OFED InfiniBand diagnostic utilities are also included.

+

As of WinOF 2.1, Winverbs components are now integral +components of a default WinOF installation.
+Although WinVerbs, WinMAD drivers, OFED libraries and utilities are install +selectable features, they are automatically included as part of the default +WinOF install.

+ +
+ +

+ +<Return-to-Top>

+
+

Known Issues
 

+ +
    +
  • +

    HCA drivers are now + classified as 'BOOT START' drivers; the implication being for a first time + install, the system will reboot after installation.

  • +
  • +

    IPoIB partition + multicast + support requires IGMP (Internet Gateway Management Protocol) v2 Windows default is v3.
     

    +
    Partition + multicast on ipoib will only work if the machine is configured to use + IGMP V2 (and not V3 which is the default).
    +
    To + configure your machine to use IGMP v2 please do the following:
    +
     
    +
    Server + 2003 or XP:
    +
    +

    netsh routing ip igmp install

    +
    +

    netsh routing ip igmp install add + interface "interface name of IPoIB adapter"  igmpprototype=igmprtrv2

    +
    + +

    If IGMP V3 is still used, please follow the instructions on + (http://support.microsoft.com/default.aspx/kb/815752)

    +

     

    +

    Server 2008, + HPC or Vista:

    +
    If the netsh command is not + available, then you will need to install via the command 'servermanagercmd.exe + -install NPAS-RRAS-Services'.
    +
    +
    +

    + netsh + routing ip igmp + install

    +
    +

    + netsh + routing ip igmp install + add interface "interface name of IPoIB + adapter"  igmpprototype=igmprtrv2

    +

     

    + +

    Future WinOF releases + will support IGMP V3.

    +

     

  • +
  • +

    Sometimes an + errant "Welcome to the Found New Hardware Wizard" window pops up during + InfiniBand device installation on XP or Server 2003.
    Just 'cancel' the FNHW popup window and proceed with installation.
    An artifact of the 'Cancel' operation may cause a taskbar Information bubble + to appear which incorrectly claims problems with the Infiniband device + installation; Check IB device status via the Device Manager.

  • +
+ +
+
+ +
    +
  • +

    + The Microsoft hotfix + + + + http://support.microsoft.com/kb/915858 + + is necessary for users of SRP in any + of the Windows Server 2003 platforms.  The hotfix is described in Article ID + 915858 and fixes problems in the eventlog where specific event ids (56, 118, + 129) are not found in the latest IoLogMsg.dll file.  Without the correct + information, there is no supplied way to decipher the event log data.
    + The SRP hotfix need not be installed by non-SRP users; however, if the + hotfix is installed in a system without SRP, it will not have any negative + effects.

  • +
  • +

    + x64 Windows platforms do not exhibit + the following SRP behavior.
    + SRP when run on a Windows 32-bit platform (x86) will exhibit SRP read + transfer hangs when the size of the SRP read  is greater-than  4096 + bytes.

    +
    + + Setting the registry entry + HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\ibsrp\Parameters\ModeFlags
    +

    +  to 1 will + enable > 4KB transfers to proceed without hanging.
     
     

  • +
+

+<Return-to-Top>

+ +
+ + + + diff --git a/branches/WOF2-3/OFED/WIX/SDK_Samples/WDK/README.txt b/branches/WOF2-3/OFED/WIX/SDK_Samples/WDK/README.txt new file mode 100644 index 00000000..9c5257d2 --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/SDK_Samples/WDK/README.txt @@ -0,0 +1,102 @@ + +WDK (Windows Driver Kit) Build Environment Example [4-08-10] +----------------------------------------------------------------- + +Install the Windows WDK see + http://www.microsoft.com/whdc/Devtools/wdk/default.mspx + +Why use the WDK? WDK (600.16385.0) is what's used to build the OFED for Windows +distribution. +Installing the WDK first requires burning a CD of the downloaded WDK - sigh... + +Due to the problematic nature of spaces in path names, the Windows Driver Kit +does not allow spaces in pathnames; Due to the spaces in %ProgramFiles%\OFED +path, the OFED_SDK is not installed under %ProgramFiles%\OFED. +See %SystemDrive%\OFED_SDK\ + + +Building CM test example +------------------------ + +Start a 'Free/Release' type WDK command window for you respective architecture +[x86,amd64,ia64]; assumed OS is Windows Server 2008 R2 (aka win7). + +cd to %SystemDrive%\OFED_SDK\Samples\DDK + +Set the 'OPENIB_REV' env variable to the svn version number; any # will work. +Hold the mouse-point over the file 'C:\Program Files\OFED\opensm.exe'. +The last field of the 'File Version' field is the svn revision number. + +example: set OPENIB_REV=917 + +If building an 32-bit cmtest version on an x64 platform, edit Sources file by +adding '32' to ibal.lib and complib.lib, resulting in 'ibal32.lib' and +'complib32.lib'. +Note - executable will be appear as 'objfre_win7_x86\i386\cmtest.exe'. + +build /wg + +The executable will be created in a processor specific directory: + + x64 (Release/Free) example: + %SystemDrive%\OFED_SDK\Samples\DDK\objfre_win7_amd64\amd64\cmtest.exe + + x64 (Checked/Debug)) example: + %SystemDrive%\OFED_SDK\Samples\DDK\objchk_win7_amd64\amd64\cmtest.exe + + x86 (Release/Free) example: + %SystemDrive%\OFED_SDK\Samples\DDK\objfre_win7_x86\i386\cmtest.exe + +Executing cmtest.exe +-------------------- + +cmtest.exe passes messages between the server and client over a reliable IB +queue-pair connection (RC). +Connection end-points (hosts) are identified by IB port LID (hex integer, as +displayed by the vstat command). + +Note: are not allowed between command line switch and it's argument. + +Server side: cmtest -s -l0xlll -r0xrrr -m1024 -n100 + +Client side: cmtest.exe -l0xlll -r0xrrr -m1024 -n100 + +where: + lll == local port lid as displayed by vstat command. + rrr == Remote port lid as displayed by vstat command; + lll == rrr for local loopback operation. + -m == bytes per message + -n == number of messages to send. + -c == number of connections (default is -c1) + cmtest -h reveals all... + + +Example cmtest invocation +------------------------- + +cmdWin> vstat + + hca_idx=0 + uplink={BUS=UNRECOGNIZED (33)} + vendor_id=0x02c9 + vendor_part_id=0x6278 + hw_ver=0xa0 + fw_ver=4.08.0200 + PSID=_00A0000001 + node_guid=0002:c902:0020:1d74 + num_phys_ports=2 + port=1 + port_state=PORT_ACTIVE (4) <==== Must be active! + link_speed=2.5Gbps (1) + link_width=4x (2) + rate=10 + sm_lid=0x0001 + port_lid=0x0020 <==== -l0x20 + port_lmc=0x0 + max_mtu=2048 (4) + + +Separate processes for server & client (different cmd windows). + +server: cmtest -s -l0x20 -r0x20 -m8192 -n400 +client: cmtest -l0x20 -r0x20 -m8192 -n400 diff --git a/branches/WOF2-3/OFED/WIX/SDK_Samples/WDK/SOURCES b/branches/WOF2-3/OFED/WIX/SDK_Samples/WDK/SOURCES new file mode 100644 index 00000000..160f23fd --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/SDK_Samples/WDK/SOURCES @@ -0,0 +1,21 @@ +TARGETNAME=cmtest +TARGETPATH=obj$(BUILD_ALT_DIR) +TARGETTYPE=PROGRAM +UMTYPE=console +USE_MSVCRT=1 +_LIBS=C:\OFED_SDK\Lib + +SOURCES=cmtest.c cmtest.rc + +INCLUDES=C:\OFED_SDK\Inc; + +TARGETLIBS= \ +!if $(FREEBUILD) + $(_LIBS)\complib.lib \ + $(_LIBS)\ibal.lib +!else + $(_LIBS)\complibd.lib \ + $(_LIBS)\ibald.lib +!endif + +MSC_WARNING_LEVEL= /W3 diff --git a/branches/WOF2-3/OFED/WIX/SDK_Samples/WDK/cmtest.rc b/branches/WOF2-3/OFED/WIX/SDK_Samples/WDK/cmtest.rc new file mode 100644 index 00000000..3c02ca9b --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/SDK_Samples/WDK/cmtest.rc @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2007 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#if DBG +#define VER_FILEDESCRIPTION_STR "Connection Manager Test (Debug)" +#define VER_INTERNALNAME_STR "cmtest.exe" +#define VER_ORIGINALFILENAME_STR "cmtest.exe" +#else +#define VER_FILEDESCRIPTION_STR "Connection Manager Test (Release)" +#define VER_INTERNALNAME_STR "cmtest.exe" +#define VER_ORIGINALFILENAME_STR "cmtest.exe" +#endif + +#include diff --git a/branches/WOF2-3/OFED/WIX/SDK_Samples/WDK/makefile b/branches/WOF2-3/OFED/WIX/SDK_Samples/WDK/makefile new file mode 100644 index 00000000..46abe2e5 --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/SDK_Samples/WDK/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE C:\OFED_SDK\Inc\openib.def diff --git a/branches/WOF2-3/OFED/WIX/SDK_Samples/cmtest/Makefile.x64 b/branches/WOF2-3/OFED/WIX/SDK_Samples/cmtest/Makefile.x64 new file mode 100644 index 00000000..a09bb5e1 --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/SDK_Samples/cmtest/Makefile.x64 @@ -0,0 +1,97 @@ +# +#********************************************************************* +# +# NMAKE Options (passed as macro) +# +# Select a Visual Studio command window from the start menu +# vcvarsall X64 - sets X64 processor compilation env, X86 | IA64 +# +#*********************************************************************/ + + +#********************************************************************* +# +# Dot Directives +# +#*********************************************************************/ + +.SUFFIXES : # clear the .SUFFIXES list +.SUFFIXES : .c # initialize .SUFFIXES list + + +#********************************************************************* +# +# Macros +# +#*********************************************************************/ + +SRC=cmtest + +LIB_PATH=C:\OFED_SDK\Lib +INC_PATH=C:\OFED_SDK\Inc + +IB_LIBS=ibal.lib complib.lib + +DEFS= /D_WIN64 /D_X64_ /D_AMD64_ + +ARCH=x64 + +OBJS = $(SRC).obj +EXEC = $(SRC).exe + +# +# Compiler +# + +CC = cl + +INC_FLAGS = /I $(INC_PATH) + +UNUSED_CL=/Zp1 /Od +UNUSED_LINKER= /DEBUG /incremental:no + +CC_FLAGS= /nologo /Gy /W3 /Gm- \ + /GR- /GF /O2 /Oi /Oy- /D_CRT_SECURE_NO_WARNINGS \ + $(DEFS) $(INC_FLAGS) + +# +# Linker +# + +LINK = link + +LIBS = ws2_32.lib advapi32.lib User32.lib + +LINK_FLAGS = /nologo /subsystem:console /machine:$(ARCH) $(LIBS) \ + /libpath:$(LIB_PATH) $(IB_LIBS) + +# +# System Utilities +# + +RM = del /Q + + +#********************************************************************* +# Inference Rules +# +#*********************************************************************/ + +.c.obj: + $(CC) $(CC_FLAGS) /Fo$@ /c $< + + +#********************************************************************* +# +# Description Blocks +# +#*********************************************************************/ + +all : $(EXEC) + + +$(EXEC) : $(OBJS) $0 + $(LINK) $(LINK_FLAGS) /out:$(EXEC) $(OBJS) + +clean: + -$(RM) *.exe *.pdb *.obj diff --git a/branches/WOF2-3/OFED/WIX/SDK_Samples/cmtest/Makefile.x86 b/branches/WOF2-3/OFED/WIX/SDK_Samples/cmtest/Makefile.x86 new file mode 100644 index 00000000..3631e063 --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/SDK_Samples/cmtest/Makefile.x86 @@ -0,0 +1,100 @@ +# +#********************************************************************* +# +# NMAKE Options (passed as macro) +# +# Select a Visual Studio command window from the start menu +# vcvarsall X86 - sets X86 processor compilation env, X64 | IA64 +# +#*********************************************************************/ + + +#********************************************************************* +# +# Dot Directives +# +#*********************************************************************/ + +.SUFFIXES : # clear the .SUFFIXES list +.SUFFIXES : .c # initialize .SUFFIXES list + + +#********************************************************************* +# +# Macros +# +#*********************************************************************/ + +SRC=cmtest + +LIB_PATH=C:\OFED_SDK\Lib +INC_PATH=C:\OFED_SDK\Inc + +# For x86 on x64 system: IB_LIBS=ibal32.lib complib32.lib +# For x86 on x86 system: IB_LIBS=ibal.lib complib.lib + +IB_LIBS=ibal32.lib complib32.lib + +DEFS= /D_WIN32 + +ARCH=x86 + +OBJS = $(SRC).obj +EXEC = $(SRC).exe + +# +# Compiler +# + +CC = cl + +INC_FLAGS = /I $(INC_PATH) + +UNUSED_CL=/Zp1 /Od +UNUSED_LINKER= /DEBUG /incremental:no + +CC_FLAGS= /nologo /Gy /W3 /Gm- \ + /GR- /GF /O2 /Oi /Oy- /D_CRT_SECURE_NO_WARNINGS \ + $(DEFS) $(INC_FLAGS) + +# +# Linker +# + +LINK = link + +LIBS = ws2_32.lib advapi32.lib User32.lib + +LINK_FLAGS = /nologo /subsystem:console /machine:$(ARCH) $(LIBS) \ + /libpath:$(LIB_PATH) $(IB_LIBS) + +# +# System Utilities +# + +RM = del /Q + + +#********************************************************************* +# Inference Rules +# +#*********************************************************************/ + +.c.obj: + $(CC) $(CC_FLAGS) /Fo$@ /c $< + + +#********************************************************************* +# +# Description Blocks +# +#*********************************************************************/ + +all : $(EXEC) + + +$(EXEC) : $(OBJS) $0 + $(LINK) $(LINK_FLAGS) /out:$(EXEC) $(OBJS) + +clean: + -$(RM) *.exe *.pdb *.obj diff --git a/branches/WOF2-3/OFED/WIX/SDK_Samples/cmtest/README.txt b/branches/WOF2-3/OFED/WIX/SDK_Samples/cmtest/README.txt new file mode 100644 index 00000000..67e901bc --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/SDK_Samples/cmtest/README.txt @@ -0,0 +1,113 @@ + +Visual Studio (C++) Build Environment [4-07-10] +----------------------------------------------------------------- + +Install Microsoft Visual Studio 10 (C++ env) + + +**** WARNING - win32 application building **** + +Disregard if building x64 application. + +The Visual Studio default x86 calling convention is '__cdecl' (/Gd). +The 32-bit versions of ibal32.lib & complib32.lib are built using '__stdcall' +as the default calling convention (AL_API & CL_API). +Make _sure_ 'all' user-defined ibal and complib callback routines match the +callback function declaration [AL_API or CL_API calling conventions]. +The VS compiler will note a C-style cast is required if the calling conventions +do not match. +The other option is to force __stdcall (/Gz) as the 'default' calling +convention for your 'win32' InfiniBand application. + + +Building CM test example from a cmd.exe window +---------------------------------------------- + + +cd to %SystemDrive%\OFED_SDK\Samples\VS + + +Makefile Solution +----------------- + +Assuming Visual Studio is installed, select a Visual Studio 2005 command +window from the start menu. + +vcvarsall X64 - sets X64 processor compilation env, X86 | IA64 + +nmake -f Makefile.x64 + +If building a win32 application on a 64-bit platform then link with +lbal32[d].lib & complib32[d].lib. + + + +Visual Studio Solution +---------------------- + +Double-click cmtest.c + +Create a New Solution 'Project from Existing Code', using cmtest.c & cmtest.rc +Select a C++ console application project. + +Salient Solution points: + compile as a C program + set additional Include path as C:\OFED_SDK\Inc + set additional Resource Include path as C:\OFED_SDK\Inc + Set additional Library path as C:\OFED_SDK\Lib . + Link with additional libraries ibal.lib & complib.lib . + If building a win32 application on a 64-bit platform then link with + lbal32[d].lib & complib32[d].lib + + +Executing cmtest.exe +-------------------- + +cmtest.exe passes messages between the server and client over a reliable +IB queue-pair connection (RC). +Connection end-points (hosts) are identified by IB port LID (hex integer, +as displayed by the vstat command). + +Note: are not allowed between command line switch and it's argument. + +Server side: cmtest -s -l0xlll -r0xrrr -m1024 -n100 + +Client side: cmtest.exe -l0xlll -r0xrrr -m1024 -n100 + +where: + lll == local port lid as displayed by vstat command. + rrr == Remote port lid as displayed by vstat; lll == rrr for local loopback + operation. + -m == bytes per message + -n == number of messages to send. + -c == number of connections (default is -c1) + cmtest -h reveals all... + +Example cmtest invocation: local loopback test + +cmdWin> vstat + + hca_idx=0 + uplink={BUS=UNRECOGNIZED (33)} + vendor_id=0x02c9 + vendor_part_id=0x6278 + hw_ver=0xa0 + fw_ver=4.08.0200 + PSID=_00A0000001 + node_guid=0002:c902:0020:1d74 + num_phys_ports=2 + port=1 + port_state=PORT_ACTIVE (4) <==== Must be active! + link_speed=2.5Gbps (1) + link_width=4x (2) + rate=10 + sm_lid=0x0001 + port_lid=0x0020 <=== -l0x20 + port_lmc=0x0 + max_mtu=2048 (4) + + +Separate processes for server & client (different cmd windows). + +server: cmtest -s -l0x20 -r0x20 -m8192 -n400 +client: cmtest -l0x20 -r0x20 -m8192 -n400 diff --git a/branches/WOF2-3/OFED/WIX/SDK_Samples/cmtest/cmtest.rc b/branches/WOF2-3/OFED/WIX/SDK_Samples/cmtest/cmtest.rc new file mode 100644 index 00000000..b0a596b0 --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/SDK_Samples/cmtest/cmtest.rc @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2007 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#define IB_COMPANYNAME "OpenFabricsAlliance\x20Windows" +#define IB_PRODUCTNAME "WinOF" +#define VER_FILEMAJORVERSION 1 +#define VER_FILEMINORVERSION 0 +#define VER_FILEBUILD 1 +#define VER_FILEREV 906 + +#include + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT2_UNKNOWN + + +#if DBG +#define VER_FILEDESCRIPTION_STR "Connection Manager Test (Debug)" +#define VER_INTERNALNAME_STR "cmtest.exe" +#define VER_ORIGINALFILENAME_STR "cmtest.exe" +#else +#define VER_FILEDESCRIPTION_STR "Connection Manager Test (Release)" +#define VER_INTERNALNAME_STR "cmtest.exe" +#define VER_ORIGINALFILENAME_STR "cmtest.exe" +#endif + +#include diff --git a/branches/WOF2-3/OFED/WIX/SDK_Samples/rdma_bw/Makefile.x64 b/branches/WOF2-3/OFED/WIX/SDK_Samples/rdma_bw/Makefile.x64 new file mode 100644 index 00000000..c6665197 --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/SDK_Samples/rdma_bw/Makefile.x64 @@ -0,0 +1,103 @@ +# +#********************************************************************* +# +# NMAKE Options (passed as macro) +# +# Select a Visual Studio command window from the start menu +# vcvarsall X64 - sets X64 processor compilation env, X86 | IA64 +# +#*********************************************************************/ + + +#********************************************************************* +# +# Dot Directives +# +#*********************************************************************/ + +.SUFFIXES : # clear the .SUFFIXES list +.SUFFIXES : .c .rc # initialize .SUFFIXES list + + +#********************************************************************* +# +# Macros +# +#*********************************************************************/ + +PGM=ibv_rdma_bw + +SDK=%SystemDrive%\OFED_SDK + +INC_PATH=$(SDK)\Inc +LIB_PATH=$(SDK)\Lib + +IB_LIBS=libibverbs.lib librdmacm.lib + +DEFS= /D_WIN64 /D_X64_ /D_AMD64_ + +ARCH=x64 + +OBJS = rdma_bw.obj perftest.obj rdma_bw.res +EXEC = $(PGM).exe + +# +# Compiler +# + +CC = cl + +INC_FLAGS = /I $(INC_PATH) /I $(INC_PATH)\linux /I $(INC_PATH)\etc +RFLAGS=/r /i $(INC_PATH) + +UNUSED_CL=/Zp1 /Od +UNUSED_LINKER= /DEBUG /incremental:no + +CC_FLAGS= /nologo /Gy /W3 /Gm- \ + /GR- /GF /O2 /Oi /Oy- /D_CRT_SECURE_NO_WARNINGS \ + $(DEFS) $(INC_FLAGS) + +# +# Linker +# + +LINK = link + +LIBS = ws2_32.lib advapi32.lib User32.lib + +LINK_FLAGS = /nologo /subsystem:console /machine:$(ARCH) $(LIBS) \ + /libpath:$(LIB_PATH) $(IB_LIBS) + +# +# System Utilities +# + +RM = del /Q + + +#********************************************************************* +# Inference Rules +# +#*********************************************************************/ + +.c.obj: + $(CC) $(CC_FLAGS) /Fo$@ /c $< + +.rc.res: + $(RC) $(RFLAGS) $< + + +#********************************************************************* +# +# Description Blocks +# +#*********************************************************************/ + +all : $(EXEC) + + +$(EXEC) : $(OBJS) $0 + $(LINK) $(LINK_FLAGS) /out:$(EXEC) $(OBJS) + +clean: + -$(RM) *.exe *.pdb *.obj *.res diff --git a/branches/WOF2-3/OFED/WIX/SDK_Samples/rdma_bw/Makefile.x86 b/branches/WOF2-3/OFED/WIX/SDK_Samples/rdma_bw/Makefile.x86 new file mode 100644 index 00000000..a69198ec --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/SDK_Samples/rdma_bw/Makefile.x86 @@ -0,0 +1,103 @@ +# +#********************************************************************* +# +# NMAKE Options (passed as macro) +# +# Select a Visual Studio command window from the start menu +# vcvarsall X64 - sets X64 processor compilation env, X86 | IA64 +# +#*********************************************************************/ + + +#********************************************************************* +# +# Dot Directives +# +#*********************************************************************/ + +.SUFFIXES : # clear the .SUFFIXES list +.SUFFIXES : .c .rc # initialize .SUFFIXES list + + +#********************************************************************* +# +# Macros +# +#*********************************************************************/ + +PGM=ibv_rdma_bw + +SDK=%SystemDrive%\OFED_SDK + +INC_PATH=$(SDK)\Inc +LIB_PATH=$(SDK)\Lib + +IB_LIBS=libibverbs.lib librdmacm.lib + +DEFS= /D_WIN32 + +ARCH=x86 + +OBJS = rdma_bw.obj perftest.obj rdma_bw.res +EXEC = $(PGM).exe + +# +# Compiler +# + +CC = cl + +INC_FLAGS = /I $(INC_PATH) /I $(INC_PATH)\linux /I $(INC_PATH)\etc +RFLAGS=/r /i $(INC_PATH) + +UNUSED_CL=/Zp1 /Od +UNUSED_LINKER= /DEBUG /incremental:no + +CC_FLAGS= /nologo /Gy /W3 /Gm- \ + /GR- /GF /O2 /Oi /Oy- /D_CRT_SECURE_NO_WARNINGS \ + $(DEFS) $(INC_FLAGS) + +# +# Linker +# + +LINK = link + +LIBS = ws2_32.lib advapi32.lib User32.lib + +LINK_FLAGS = /nologo /subsystem:console /machine:$(ARCH) $(LIBS) \ + /libpath:$(LIB_PATH) $(IB_LIBS) + +# +# System Utilities +# + +RM = del /Q + + +#********************************************************************* +# Inference Rules +# +#*********************************************************************/ + +.c.obj: + $(CC) $(CC_FLAGS) /Fo$@ /c $< + +.rc.res: + $(RC) $(RFLAGS) $< + + +#********************************************************************* +# +# Description Blocks +# +#*********************************************************************/ + +all : $(EXEC) + + +$(EXEC) : $(OBJS) $0 + $(LINK) $(LINK_FLAGS) /out:$(EXEC) $(OBJS) + +clean: + -$(RM) *.exe *.pdb *.obj *.res diff --git a/branches/WOF2-3/OFED/WIX/SDK_Samples/rdma_bw/README.txt b/branches/WOF2-3/OFED/WIX/SDK_Samples/rdma_bw/README.txt new file mode 100644 index 00000000..9ba2a4f5 --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/SDK_Samples/rdma_bw/README.txt @@ -0,0 +1,58 @@ + +Visual Studio (C++) Build Environment [4-07-10] +----------------------------------------------------------------- + +Install Microsoft Visual Studio 10 (C++ env) + + +**** WARNING - win32 application building **** + +Disregard if building x64 application. + +The Visual Studio default x86 calling convention is '__cdecl' (/Gd). +The 32-bit versions of ibal32.lib & complib32.lib are built using '__stdcall' +as the default calling convention (AL_API & CL_API). +Make _sure_ 'all' user-defined ibal and complib callback routines match the +callback function declaration [AL_API or CL_API calling conventions]. +The VS compiler will note a C-style cast is required if the calling conventions +do not match. +The other option is to force __stdcall (/Gz) as the 'default' calling +convention for your 'win32' InfiniBand application. + + +Building rdma_bw test example from a cmd.exe window +---------------------------------------------- + + +cd to %SystemDrive%\OFED_SDK\Samples\rdma_bw + + +Makefile Solution +----------------- + +Assuming Visual Studio is installed, select a Visual Studio x64 command +window from the start menu. + +nmake -f Makefile + +If building a win32 application on a 64-bit platform then link with +lbal32[d].lib & complib32[d].lib. + + +Executing ibv_rdma_bw.exe +-------------------- + + 'ibv_rdma_bw -h' tells the story... + +Example ibv_rdma_bw invocation: local loopback test + +Separate processes for server & client (different cmd windows). + +server: ibv_rdma_bw +client: ibv_rdma_bw -h + +Example using rdma_cm over IPoIB interface + +server: ibv_rdma_bw -c +client: ibv_rdma_bw -c -h IPoIB-IF-IPv4-address + diff --git a/branches/WOF2-3/OFED/WIX/SDK_Samples/rdma_bw/rdma_bw.rc b/branches/WOF2-3/OFED/WIX/SDK_Samples/rdma_bw/rdma_bw.rc new file mode 100644 index 00000000..9badd598 --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/SDK_Samples/rdma_bw/rdma_bw.rc @@ -0,0 +1,48 @@ +/* + * This software is available to you under the OpenFabrics Alliance BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION 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 VER_FILEMAJORVERSION 2 +#define VER_FILEMINORVERSION 2 +#define VER_FILEBUILD 1 +#define VER_FILEREV 1 +#define IB_COMPANYNAME "OpenFabrics Alliance" +#define IB_PRODUCTNAME "OpenFabrics\x20Windows" + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef DBG +#define VER_FILEDESCRIPTION_STR "winverbs - RDMA Bandwidth Test (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "winverbs - RDMA Bandwidth Test " +#endif + +#define VER_INTERNALNAME_STR "ibv_rdma_bw.exe" +#define VER_ORIGINALFILENAME_STR "ibv_rdma_bw.exe" + diff --git a/branches/WOF2-3/OFED/WIX/WIX_tools/README.txt b/branches/WOF2-3/OFED/WIX/WIX_tools/README.txt new file mode 100644 index 00000000..78593136 --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/WIX_tools/README.txt @@ -0,0 +1,23 @@ + +[11-16-09] + +Creating the WIX tool set +------------------------- + +Download the WIX 3.0 (stable) tool to ‘WinOF\WIX\WIX_tools\Â’. + +http://sourceforge.net/projects/wix/files/ + +Download WIX binaries wix-3.0.5419.0-RTM wix-3.0.5419.0-binaries.zip into 'trunk\WinOF\WIX\WIX_tools\'. + +Unzip the archive to a folder within 'WIX_tools\'; the new folder represents the version of the +tool set. + +Something like unzip wix-3.0.5419.0-binaries.zip into wix-3.0.5419.0-binaries\. + +You should now have the following structure: + trunk\WinOF\WIX\WIX_tools\wix-3.0.5419.0-binaries\{candle.exe,light.exe,...} + +The path to the WIX binaries is referenced in files: + trunk\WinOF\buildrelease.bat + trunk\WinOF\WIX\{wlh,wnet,wxp}\{ia64,x86,x64}\Makefile diff --git a/branches/WOF2-3/OFED/WIX/banner.bmp b/branches/WOF2-3/OFED/WIX/banner.bmp new file mode 100644 index 0000000000000000000000000000000000000000..f21a6250c8f6d82c3671b8655c3aac5a2b75bff3 GIT binary patch literal 85894 zcmeI52~?BUw#PpxqOIc4tG2bP_qyuqyREi&Xua*zUM-`(I^f*CI*%X-Xa%kJ;ZSE$ z8APcUMFt@Z2>}_ylmN;M0s;wxAP@)v0wF*KASApU!iymc60W|tlzkR_?z7K6=garY zT7Qn`JA?7sOY3w9Mfw_kKZV~`$S#F{b%^)jN)YRzJZ(DB|J(0?OCKgAfCP{L5_p{n zppL)J-yVK;B!C27F#)+;uGJmX|h#|&?e@L^ELhsT9pB!C3oYy#m_%7sf8 zmCyL=g>%Wtbk*|;g`J;%_Qxelmzb_xp>l$8^svps&lfHEc1e95Tjeh+FLOM7Qk4b6 zY=v1_MY+>6NM;zP+QveB*k^%H%SY z6O5gEc4cK|XgFCc*3o13>R}~M@;?5z1tw;u%a;A!+UAgYQ3#m~I$l&p4Aua8p zx<_euO2qHYoo#pYNLEg^RIO{T9*O;NbsA_R0VFVi2*B`&!_PJrR+bviJd%#@J+LqD z@nenPVRhWu#f40z?BBanBRG^wJ$?4fxeMo+Oy-5b<0@A#pTFVmt`QH}_BNjR2E~64 zMoFmSqrkx;B!C3oa01`2US)C6LgOLZ+uKc7nrS#8yXB`JGBYzY{KX|D*0zHNPapus z#3#Q!C4ES6Sa=xB5)=wM3JVKQojs$`)b?FF&DXA8z2JzQY3%`kict70Q=*w=@*9|8wntRmq37# zlI(fQH8~}@x3?FX>+b1J&logvl98Di75N}4;z3ek0`#);3k!HHJjIRWvbgwoc5OA7 zyd;m_PKC3J!)nW+f}u=Z+zNg+xmP4;ia5s&JJb5mOWxB3MWRx=s5})6S+}S))=4Jq z7UV@pJDQcXL{*Qulz(vjZ916@2xtyJ#r8hd{<6paK@~d4})m$@zum z-8Jk16?B|sH&6Ubq2rLsPkvtS{|hJhI497Nxqni3D_dB{th)4Fe_S!8Y~Y zR$$b7?P!X=2}aE|Q_yi)cUQ??JyBJjGFbh}i*e$3YrcC8h(|WE7%*zwex6rPGA+Bc?Z6%*;{gxJdK2Iv^ zRW8RrbMgcuH3b%SLJa6QH7vAG*2_Bb2T^54pKM@dKg;%AX-5MnmAS`hcIosQ0zvcUoa8HOqRIQjt4ri>odxUT=0cRh6Gm zjI=b6?HjyzgCWT9ulQvi7*$tRNZ9$%*=AW1s-br9cRtOiKKC~;Mo*~Yqw~R1B!C3o zSOO%{eQT=&Q4hin+1XG+$?%+wjrAKhuDj>sy?fV=yI!8)v9R2K!`;R6?wyFp2*_SI ze`d=Mo5T_^*a1N#G9?(qnq@P)_U7h>fCKytfAGsC9Z!BF>H`Mmy-3(a%!9MJad%*VQ&QHG*z;`mcO~>YB3J>gU7p|4LJ;x~StS6lfp;B!C1)B*5qMw{G7C zyN5&ibm79HLdEnFt&&*OnM$XUNzUQHx031Mot@98Giue&&|uW@p-j+&1dsp{7(~GF z)JZt(7!+K$U&rC1qf4wYU)$07eCw4#6*Mw3X^E{D8(Cun@qY+i}J0mE@M|S6JkjI{+<-l_2>wns!FD8`1SU~HaUzFb$l2o z=t2TW013c8;|o7u1bRKGzZ1T5&o1>-e(rhS)zcw#b)aWXyfba;qqIjuiM0s$F_HH} zgWMu0p46ZltfE}?n4+RgYOt%Xzh7vO3oX*WyMJqP^? zAuGMfddg0>shLUc<6-uaZQ?Z_JMN&2fvcIBiE2HONG!?Cj;98>QvzK=gKp&KC3kkV z4P__lY|qJv3k&vuFzB%7W+ikpL_yHVy zKl;O0JgfZb%fBe%p>IwQ_Q&j5%%Z>m59okXgKs9%0{E@4=5w^v($Wwg>qiN42_|_2 zki6^b29}bJR%dV->iA$Dm_q_cU}6(kX1H9T#{}W*<{}gc#{vVkOH86CPMBVt8EM1`e#8Tk0|OLZ7ZUVYfB8{kpL2SlL;tw{GOk; zwh!6f-VQoGW9AH!@74Q$w|GtU+P1*0uc8FHqK<3J4damj59{W$c$hZ5>W>}NHHc7*BCtWJ*#SV zEC%TKeSfcLs^a_#trCupYlRDgkpL2S!wG0RuF_VVmSeS;_AQZQG9}iKIP}FFs>7Pt zRnwAg~Aih=k=tuGL@LnG9i%4CbrMQp{IzqLAEp ztrf$ht)AP?tp08Of%TVwMva6 zi9*20*bs(C7Jt1sD?4l0XHMDhA#}#;!d%o#Ih?xP2lhh6cV|pjjH?8?&>7K!wn00q z2udEtD_)0!j`P&(D($v59wYGqtmcoTV1Ill9`qmqB!C3QOkmgE-LN68^1z5yYgS9d znj_k&Ylzt81c&CMY!WtCaXfueu}PMWVu#xWpDc)``aB@t21WMs_sYwRSM7Ey;Z{U1 zA>g%V_YfV=%}pf-xGCCY9FI2WCmMo|`+_qdkTn0}`Tc>!lqve2cRag$y1`#t%?zjB3l4CDT?`|`Jgcji z;1qG5(v}cOW>b3v&8h|~%ko1*?}rAuLKmJE>BHsJsEWpJppK876-FWfBrt&pTz7Sz zJ^Ob`jh_4ddkIO2eSL~!dl=?(5)6sd-%kBmxm_(m=FxjzW`Eu4I_pkSDjD2BE`SS;v70!RP} z^tHCM*c`S6DSxY9&j0e&pPM_xsT=fHyr=V)u2SLQ%;nFDOG-w9)zu|RVT8enZXtp0 zWRiR2HOr*`)PoiLX%A_zL3s$tEiB|-c6#h6C&P`@vbrC2T%88mNB{{S0Zjr$CB>$u zCLr62gCcZ^=~MLjE#mhdedysiroFZVGSgJ1STGV1V-XyJzY@n{tI!$a*wtQDvKWl`znr@2qfJO3%SXzF4eY$ zk>XLuMr-3#SKmthM z1q5LJIKzl&h}Zg{2@$&-bbQ$P<1e`7i;7XlUqlGYkpL1v0%`SYne16pN@o~diNB{{;NCI-jQlPr1JE`UdNyd|7 zmJ(TeK50rFaV33cSz5NOaojT4SBqen5zhk7%X@?`9USWTOGkSn8Ik{saaU8V`eS#ua*8i+iCaoAOmvdX-paRMBJ1u_4|s_->iA29iA^B^ zBrvfE2_phLw;25 %DST%\jnk.txt +if ERRORLEVEL 1 ( + echo %0 missing nmake.exe in PATH? + exit /B 1 +) +del /Q /F %DST%\jnk.txt + +if "%1" == "msi" goto mk_msi + +rem Sign drivers for specified OSes & arches. Convert CertFilename to full path. + +call sign-all-drivers %CD%\%2 %3 %OSarg% %ARCHarg% + +if ERRORLEVEL 1 ( + echo %0: Error signing drivers? + exit /B 1 +) + +if "%1" == "sign" ( + echo %0: Drivers Signed. + exit /B 0 +) + +:mk_msi + +rem build x86, x64 & ia64 Installers for each of +rem Windows 7/Server 2008 R2 +rem Vista/Server 2008 +rem Server 2003/XP64 +rem Windows XP (32-bit) version: x86 only + +echo %0 - Building .msi files + +for %%o in ( %TOS% ) do ( + if Not exist %%o\bin\HCA ( + echo Missing %%o files? + exit /B 1 + ) + pushd %%o + call build-MSI %DST% %ARCHarg% + if ERRORLEVEL 1 exit /B 1 + popd +) + +rem Digitally Sign the installer .msi files + +echo %0 - Signing Installer .msi files +for %%o in ( %TOS% ) do ( + for %%a in ( %TARCH% ) do ( + if exist %DST%\OFED_%%o_%%a.msi ( + echo Signing installer %DST%\OFED_%%o_%%a.msi + signtool sign /ac %CD%\%2 /n %3 %TS% %DST%\OFED_%%o_%%a.msi + if ERRORLEVEL 1 ( + echo %0 signtool sign %DST%\OFED_%%o_%%a.msi failed? + exit /B 1 + ) + signtool verify /pa %DST%\OFED_%%o_%%a.msi + if ERRORLEVEL 1 ( + echo %0 signtool verify %DST%\OFED_%%o_%%a.msi failed? + exit /B 1 + ) + ) + ) +) + +dir %DST%\*.msi + +echo. +echo Done - OFED installers in %DST% + +@endlocal diff --git a/branches/WOF2-3/OFED/WIX/common/Config.inc b/branches/WOF2-3/OFED/WIX/common/Config.inc new file mode 100644 index 00000000..1b7db20f --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/common/Config.inc @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/branches/WOF2-3/OFED/WIX/common/DAT_config.inc b/branches/WOF2-3/OFED/WIX/common/DAT_config.inc new file mode 100644 index 00000000..becd6392 --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/common/DAT_config.inc @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/branches/WOF2-3/OFED/WIX/common/Docs.inc b/branches/WOF2-3/OFED/WIX/common/Docs.inc new file mode 100644 index 00000000..c5fadb44 --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/common/Docs.inc @@ -0,0 +1,25 @@ + + + + + + + + + diff --git a/branches/WOF2-3/OFED/WIX/common/Drivers.inc b/branches/WOF2-3/OFED/WIX/common/Drivers.inc new file mode 100644 index 00000000..734499e2 --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/common/Drivers.inc @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/branches/WOF2-3/OFED/WIX/common/IBcore.inc b/branches/WOF2-3/OFED/WIX/common/IBcore.inc new file mode 100644 index 00000000..3e1b2c47 --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/common/IBcore.inc @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + diff --git a/branches/WOF2-3/OFED/WIX/common/InstallExecuteSeq.inc b/branches/WOF2-3/OFED/WIX/common/InstallExecuteSeq.inc new file mode 100644 index 00000000..4b043aea --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/common/InstallExecuteSeq.inc @@ -0,0 +1,79 @@ + + + File where Custom Actions are defined --> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Install ONLY + + NOT Installed AND Not NODRV + + + Not Installed AND Not NODRV + + + Not Installed AND Not NODRV + + + Not Installed AND Not NODRV + + + ($cNetworkDirect = 3) AND Not Installed AND Not NODRV + + + Not Installed + + CHANGE ONLY + + Installed + + REMOVE ONLY + + REMOVE="ALL" AND Not NODRV + + + REMOVE="ALL" AND Not NODRV + + + REMOVE="ALL" + + + + diff --git a/branches/WOF2-3/OFED/WIX/common/Makefile.inc b/branches/WOF2-3/OFED/WIX/common/Makefile.inc new file mode 100644 index 00000000..ad38413d --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/common/Makefile.inc @@ -0,0 +1,58 @@ + +# Common Makefile include for WIX Installer (.msi) build + +# Inputs args: +# +# S == WIX src & obj filename: .wxs & .wixobj +# A == arch {x86,ia64,x64} +# P == Installer (.msi) 'complete' filename +# optional: DFXP == Path to DifxApp files setup in makebin.bat + +!ifndef DFXP +DFXP=..\bin\Misc\$(A) +!endif + +# WIX 3.0 +L=..\..\WIX_tools\wix3.0.5419.0-binaries + +DFX=difxapp_$(A).wixlib + +# Since makebin.bat knows correct WDK version, makebin copies the DIFX APP files +# to the bin\Misc\arch tree; this eliminates Makefiles having to know about +# WDK versions. see DFXP=..\bin\Misc\arch + +full: clean $(P).msi + +clean: + @del /q $(S).wixobj 2>nul + @del /q $(P).wixpdb 2>nul + @del /q $(P).msi 2>nul + @del /q/f DIFxA*.* 2>nul + +MySetup: $(P).msi + +# .dlls need to be in the current folder +$(DFX) : $(L)\$(DFX) $(DFXP)\DIFxApp.dll $(DFXP)\DIFxAppA.dll + @copy /B/Y $(DFXP)\DIFxApp.dll . + @copy /B/Y $(DFXP)\DIFxAppA.dll . + @copy /B/Y $(L)\$(DFX) . + +$(S).wixobj: $(S).wxs + +$(P).msi: $(S).wixobj $(DFX) + @echo -- + @echo Building $(P).msi + $(L)\light.exe -nologo -ext WixUiExtension -ext WixDifxAppExtension -out $(P).msi $(S).wixobj $(DFX) + @del /q $(S).wixobj 2>nul + @del /q/f DIFxA*.* 2>nul + @del /q $(P).wixpdb 2>nul + + +################### +# makefile inference rules +# +.SUFFIXES: .wxs .wixobj + +.wxs.wixobj:: + @$(L)\candle.exe -nologo -arch $(A) -ext WixDifxAppExtension -trace -v $< + diff --git a/branches/WOF2-3/OFED/WIX/common/OpenSM_service.inc b/branches/WOF2-3/OFED/WIX/common/OpenSM_service.inc new file mode 100644 index 00000000..21c6b626 --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/common/OpenSM_service.inc @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/branches/WOF2-3/OFED/WIX/common/Package.inc b/branches/WOF2-3/OFED/WIX/common/Package.inc new file mode 100644 index 00000000..d6ce88fe --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/common/Package.inc @@ -0,0 +1,14 @@ + + + + + + + diff --git a/branches/WOF2-3/OFED/WIX/common/PgmMenuShortcuts.inc b/branches/WOF2-3/OFED/WIX/common/PgmMenuShortcuts.inc new file mode 100644 index 00000000..16c9ec20 --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/common/PgmMenuShortcuts.inc @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/branches/WOF2-3/OFED/WIX/common/UserInterface.inc b/branches/WOF2-3/OFED/WIX/common/UserInterface.inc new file mode 100644 index 00000000..0593e672 --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/common/UserInterface.inc @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + Installing Drivers + Verify Driver Install + Installing Network Providers + Uninstalling Drivers + + + diff --git a/branches/WOF2-3/OFED/WIX/common/arp.inc b/branches/WOF2-3/OFED/WIX/common/arp.inc new file mode 100644 index 00000000..e2284ce0 --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/common/arp.inc @@ -0,0 +1,16 @@ + + + + + + $(var.PRODUCT) + Openfabrics Alliance www.OpenFabrics.org + https://wiki.openfabrics.org/tiki-index.php?page=OpenIB%20Windows + https://wiki.openfabrics.org/tiki-index.php?page=Windows+FAQ + http://www.openfabrics.org/downloads/WinOF/ + openfabrics.ico + + diff --git a/branches/WOF2-3/OFED/WIX/common/checked.inc b/branches/WOF2-3/OFED/WIX/common/checked.inc new file mode 100644 index 00000000..6ab523e3 --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/common/checked.inc @@ -0,0 +1,240 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/branches/WOF2-3/OFED/WIX/common/dapl_rt.inc b/branches/WOF2-3/OFED/WIX/common/dapl_rt.inc new file mode 100644 index 00000000..1a56cd4b --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/common/dapl_rt.inc @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/branches/WOF2-3/OFED/WIX/common/directory_structure.inc b/branches/WOF2-3/OFED/WIX/common/directory_structure.inc new file mode 100644 index 00000000..33cec742 --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/common/directory_structure.inc @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/branches/WOF2-3/OFED/WIX/common/hca_filters.inc b/branches/WOF2-3/OFED/WIX/common/hca_filters.inc new file mode 100644 index 00000000..7239aa00 --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/common/hca_filters.inc @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/branches/WOF2-3/OFED/WIX/common/ib_sdk.inc b/branches/WOF2-3/OFED/WIX/common/ib_sdk.inc new file mode 100644 index 00000000..c24e1097 --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/common/ib_sdk.inc @@ -0,0 +1,565 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/branches/WOF2-3/OFED/WIX/common/iou.inc b/branches/WOF2-3/OFED/WIX/common/iou.inc new file mode 100644 index 00000000..0eb0636c --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/common/iou.inc @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + diff --git a/branches/WOF2-3/OFED/WIX/common/ipoib.inc b/branches/WOF2-3/OFED/WIX/common/ipoib.inc new file mode 100644 index 00000000..74335598 --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/common/ipoib.inc @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/branches/WOF2-3/OFED/WIX/common/mlnx_drivers.inc b/branches/WOF2-3/OFED/WIX/common/mlnx_drivers.inc new file mode 100644 index 00000000..1d729ca5 --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/common/mlnx_drivers.inc @@ -0,0 +1,191 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/branches/WOF2-3/OFED/WIX/common/qlgc_vnic.inc b/branches/WOF2-3/OFED/WIX/common/qlgc_vnic.inc new file mode 100644 index 00000000..67b12844 --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/common/qlgc_vnic.inc @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + diff --git a/branches/WOF2-3/OFED/WIX/common/requirements.inc b/branches/WOF2-3/OFED/WIX/common/requirements.inc new file mode 100644 index 00000000..f7ec2522 --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/common/requirements.inc @@ -0,0 +1,60 @@ + + + + Value="1" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + REG_EXISTS + + + + SC_EXISTS + + + + + + + + + diff --git a/branches/WOF2-3/OFED/WIX/common/srp.inc b/branches/WOF2-3/OFED/WIX/common/srp.inc new file mode 100644 index 00000000..041131fd --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/common/srp.inc @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/branches/WOF2-3/OFED/WIX/common/std_features.inc b/branches/WOF2-3/OFED/WIX/common/std_features.inc new file mode 100644 index 00000000..0c494edb --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/common/std_features.inc @@ -0,0 +1,181 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + IPOIB_EXISTS + + + + + + + + IPOIB_EXISTS + + + + + + + + IPOIB_EXISTS + + + DAT_CONF_EXISTS AND Not Installed + + + + + + + + + + + + + DAT2_INSTALLED + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/branches/WOF2-3/OFED/WIX/common/system_files.inc b/branches/WOF2-3/OFED/WIX/common/system_files.inc new file mode 100644 index 00000000..c63d0712 --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/common/system_files.inc @@ -0,0 +1,150 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/branches/WOF2-3/OFED/WIX/common/tools.inc b/branches/WOF2-3/OFED/WIX/common/tools.inc new file mode 100644 index 00000000..b4a432e8 --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/common/tools.inc @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/branches/WOF2-3/OFED/WIX/common/winverbs_OFED.inc b/branches/WOF2-3/OFED/WIX/common/winverbs_OFED.inc new file mode 100644 index 00000000..b03198ed --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/common/winverbs_OFED.inc @@ -0,0 +1,245 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/branches/WOF2-3/OFED/WIX/common/winverbs_drivers.inc b/branches/WOF2-3/OFED/WIX/common/winverbs_drivers.inc new file mode 100644 index 00000000..cb565b4e --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/common/winverbs_drivers.inc @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/branches/WOF2-3/OFED/WIX/dat.conf b/branches/WOF2-3/OFED/WIX/dat.conf new file mode 100644 index 00000000..b661e2c4 --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/dat.conf @@ -0,0 +1,39 @@ +# +# DAT (DAPL Provider) configuration file +# +# Entries scanned sequentially - first entry to open is used unless explicit +# DAPL interface name specified. +# +# Each entry requires the following fields: +# +# \ +# +# +# DAT 2.0 +ibnic0v2 u2.0 nonthreadsafe default C:\Windows\system32\dapl2.dll ri.2.0 "IbalHca0 1" "" +ibnic1v2 u2.0 nonthreadsafe default C:\Windows\system32\dapl2.dll ri.2.0 "IbalHca1 1" "" +IbalHca0v2 u2.0 nonthreadsafe default C:\Windows\system32\dapl2.dll ri.2.0 "IbalHca0 1" "" +ibal1 u2.0 nonthreadsafe default C:\Windows\system32\dapl2.dll ri.2.0 "IbalHca1 1" "" +# +# DAT 2.0 (debug) +ibnic0v2d u2.0 nonthreadsafe default C:\Windows\system32\dapl2d.dll ri.2.0 "IbalHca0 1" "" +# +# DAT 2.0 [socket-cm] InfiniBand QPs setup by passing QP info over a socket +# connection; supports DAT Windows <==> Linux over IB connections. +ibnic0v2-scm u2.0 nonthreadsafe default C:\Windows\system32\dapl2-ofa-scm.dll ri.2.0 "ibv_device0 1" "" +# +# Socket-CM (debug) +ibnic0v2-scmd u2.0 nonthreadsafe default C:\Windows\system32\dapl2-ofa-scmd.dll ri.2.0 "ibv_device0 1" "" +# +# DAT 2.0 RDMA-CM +# connection; supports DAT Windows <==> Linux over IB connections. +ibnic0v2-cma u2.0 nonthreadsafe default C:\Windows\system32\dapl2-ofa-cma.dll ri.2.0 "rdma_dev0 1" "" +# +# DAT 2.0 RDMA-CM (debug) +ibnic0v2-cmad u2.0 nonthreadsafe default C:\Windows\system32\dapl2-ofa-cmad.dll ri.2.0 "rdma_dev0 1" "" +# +# DAT 2.0 UCM - Unreliable Datagram Connection Manager +ibnic0v2-ucm u2.0 nonthreadsafe default C:\Windows\system32\dapl2-ofa-ucm.dll ri.2.0 "ibv_device0 1" "" +# +# DAT 2.0 UCM (debug) +ibnic0v2-ucmd u2.0 nonthreadsafe default C:\Windows\system32\dapl2-ofa-ucmd.dll ri.2.0 "ibv_device0 1" "" diff --git a/branches/WOF2-3/OFED/WIX/dialog.bmp b/branches/WOF2-3/OFED/WIX/dialog.bmp new file mode 100644 index 0000000000000000000000000000000000000000..b76dd51da439439dc2d768ec451da29a8595c6bf GIT binary patch literal 464774 zcmeFaS8!WdcK+Mb5{V3)2#_EFMkHp14&zki`(nGw*M4!8%XQ24gCAUFmtFqbnk?1@Z6v zKRfF~cI}EOq}_3~uTkIAWI*WPa7SF()u8VvOY!gyCvA_J`PvyXd+Ut8I%7}0*&hp| zMZY(y@2XMX(R|yCz|M$*L%M)Y?XESUUYqvRn$W)5u+)Ltu+&gAQl`wIs5xxYNYsQ5 z)flAFTJuP)c{Ca(9gjt%PQ*-TJZ4Bu#P!Jr<5YtNO*iV$shH4o+&JA}o^3GCHHI%X znb4&cq07zMr6%=qqjISsbTJ;h6boLe^Uu@=uEnytTJOJB@4H&(z18T4?lcGQwuBzE zh8`vq=utv>zcoa9oKXHh{)Z#L5m>7c=x;U&)4=zRy5P22KLl#yFo*9u8`N?+zB3+n z)Q*^$uU++m;{(Im8@atG6wGFOI;1 z2mstoM#^2u}RXkXw3i zbnN}r&T-&diu^cnocuT-P8htY?&$2E-XY&1yXR70dM9_fvRNg(wuxNMtf1TATgWw$|U z81T0g4+NAGyJZW$+Z67NhWl*lkA@+cR6$23RnQqMTgG6mF=W%hS_48lMGAQpsiSqK z)Ui4pI#H)Vlv;7jt58zqOk)^H6@l`&23>9qUu-rmHY(?lP64%>HTdzlWaMJhcey?= z+ZejuqTOmW?j*x^Qs(WXajP{X)EtCvHv8wAe7Bl>cN%^6)XEDlY+o}!TK*y&0gk|e z2sm;aC?{7g&te4m@f|Vs-FgKOe>)lk&B63HB0h+~EmP+JINU!b6UTw_^9?$5 zHm)GAGJ}jtDguIo;}>FqGqoP1$Y+pOX;N;q>bDXgc$VXLk}7mJq25U-cM_r7t--sk z!TYVjdyT$_O@8RT<^cQg1;2Yf;0Uax2uM=f{W!8H@Zgf>G~3zRZ0v3{0BbNB?%NLZ z@0y<1!(Lz=e8)IhbzBT;gU+Nr%v;W@KOWf)j)y}#YgCaF2f?E{`jibvE(IMJ@V)T} zvf)5>KEc;2$0@HO%y_ebNlsXD%y0tY=j;9F>U>D8KywKLx|uX@rLr8qpE00&X&t(s z)<_T28s$|UwFDvd<7?@*xa+Tl)nG2v*lkl^ zjRCEeyh^?w2gl*Zkykn2sGX_vO+{SO5f>m%sg)avFlIY%B!!6Mw^E?Fc_*zy#PNG+ z4SJB#-^=J9wV5AhjE~a#2T7Iv_=4X(A8-WLQUn}1E^7_#KqrpNKcqPD;BgXrATx!;Jnor2*m)XwH6oE#0>KT{r>@BH+kz48n;c zwPMe%Ag_Xy_YNVeiX5%g2g={AQ??bP$_2zh z@D?2e2ggBk6s`!hXplg8Qb7DpTO`YI%az~H=+J{U<6)cegyU`CIM=Hz_~r8fM_}zl zV0WVi?EZoUH^mOf=98dyW(eC=7gKG83tA6s5q71Ki;Fjv8%yMBNrv-Z6r2 z>wz~_-|HdIYeDxPc{h^2-C`b4aN7S>VI1czH0*g8c^O_V_+#zf33N< zMrdEekh0gV9H=p&0ZW6R_CgI?hXXY_G-%UsjSh`OvchVh!J_VyoN5q70b;9ml`MJEoJ$!u)5x)?5YhZ@TDzOk1j;k|qm1^rO?{lvK4?c?h3i$; z&TY%zgd?yZ0=oe5JYmU?gW_6W-0X`%C@)#iqW+|}-q;N{U8kcEWmi-atyOJ82@uL_ zqeWH({`!re3svDT)Id2oZgfOyMfJa-2j4Okw0|7({-NLXzkJmYI*$5Z-l{+JRsT`I zjf-Dbd~a!iceLO(J+wQlL3_e_|2)L^*O(ASAi_G05XXmV!crhObkG_pkK<8rT(dZ? zqP26JXg(HI$LqAodI9lMadWyMe6FQ-y1_gdRgQ=KC&K>mn&4!8Xu3f=*Q7&$ICKHC zoi>gOKc3L9C5`I|LnO*m1~ivcA>#P$w0b8aQY-h;%6l30y*9MUBf)X@;|qTIe83S{ zI}yl-I7S>GE*!en7ZcNx`GS>(gzvTlf|F>95>8xZw2>+y4-Rls%9}=jbtF%|<9B^0 z=y^@?5ybz%TLl&2I0!BvZs|3jOX^+44{g_iI}N4J)If7k8)h6GN%p;A9olbcFk(s# zM@*6!Da(&bj>D2K2_~#>nZ$@OW+LsNsbsqKe3pw^&*hj%VgM z-bNf}KfZQuTmB{-fdvtmPp8Pdis)EL6-uo!!12AHxdrilQ`>8(drfU1VhDwW1}zOyf0;NwRlhIenEonsFoF5qfakj*FZ5c_18@FEzG^TU zhr*{ji3m>Z>j4k+h9z)Zpxp0%!{>V2=YGrUB5e=(3G2JG&>j%n%CQKm9x))|IJLy_ zMdnrV{5T+vC7qLT6ZvtNaf{%AW2PS&6_F)x3?sXO8pO#u^-Pm-AyKn39A`hic5Yk# zCLDnU5y&Ap9WKOoww4@zya>l-E`=a23Qnv7K~NjWhVKT!(LzXwgXx&wB#6J}+bB8y zMo^@=A#fZJe=5hn3(5oimWbeXjsxZJ=5KgiuY0OV-}O|z?yUyjVb#I(UDBu9ax9c- zIbiD0a&a6G7nU4zo;9Hpk>FTO2q=d!2f?!tkLiFo)^@^=uNcSKk1zP;^8rU-?L?p# zOYrmL%<))3j!TH6W9K-MDsom6G^gwevMA)iUq>CGB>FC0SC2T^HxK2Xm7!8Vb3j*Pk+s`GA2y_*hY=Q%k)zIN_c{w5p&rwH_6pYakE z)Aqzotf80loHDgS9G8=vBBNrJ7{YhMh6Ck*I9i(F1hwJ8L38Lko);l>=$h>&QZeeg zdgyI60Hy=e-}SrY?4`X=gRdhM4w_pnQQPjyWuNjbBJnbxZy~IsMb-s+$LoUL^|`kP zyt_mGJz5A%2hI0~)dLY^&$Bv!LnE|b4-T6uL?|bYqqTGVXuWpK5@t9-@Dbg6$nb&V z@Z)lx6DYT85Je>-@+zVR5#{7fV7fsZN2Ll0^(w_Velw*(vR7#hy~Xhyh)Z^(LnSLnr=UU{OLeepXP(XrAP(ydc7x_ft)Pz%E~A1LTAV4?^@O!- zi%wX3Tk*f8_yyUKLh-r&*o$|l`i^@ek|b|=j}74hRBcvf}l;o8us=?BCQ zhXY3EW~GIOoUL!2QZ!fg|7)fjx1xRK=du9p+4LN}2=WSm{HH?6LMT zrzi!~Mn(l@{ExjGVAaW?BV&#nIx;Yjz_+!QN36`Wc1@Ab`oSRvcbF>5!{60{Ap1Lt zpWL*V$s~^ZT%f$jiCZWqYTM^R9XM{~Teby#?*_c@_&t~oecM7g+4FZj8@G9@b_Lvo za&X)+uR=?K$d4b6DxoV~uPOHwO&ro;k z3W~(HTR48pO1~f*{@Q$LIcm&l#ZV!RQ@R`k$F!%No3#bZ8et zYH4R$dY&?t^I(xZ%D~Z~HTQjCu~in*FWU{}9X<4xitTVk^@}KX@gl1u^5Z0`UCFjS z7s^+N;IQN{<~xGEohVEUdL+t0b7(J^j&!-|KcEIkLs}3T)rCNrtUJK$9qq;WbVMnAPBh@+*o^*JqozCRkl*0or@iGHu4?$ASU z>qx(3Cq*%<3F{4Ti^RH+V7HXtvn}AoBqy{Z=-CnS>{Psc7R39l*-lJ&?l%==R}SD% z4eSf~_6EKE0ngrm3x0gq@FFvQB&ra{kJN?^*956{<#@d|X60DuF>h$`q&F%(M4Nr) za)XBbRdVW8P_;t!D%d1T?2~0}c1XL|UQg;mDHWosm78hxmZdvs^FJ)YixiAQ*3@nkhXmIU%bpgBlQrG&_C6No88fEgu=uiT>#7+*u=F<*q`zV0zQ%-UgccJ@5LfN!tPddGjK2x0LN*b zb2#iDGQ0y;js+%NjFV5V*N(^Z6LE{qVj{ZEy(b?`3+F=P5ETH)w%zr9AaGY}GLuP0=5*&>9f$syR!1rF&wKr7N7u<-p zU#Z@&x(*m#oIQwo#HfP3v`*Bk_jNmN1w%qto z5`0jFtzA6Y1haacf6(Trj zzSHm8?RWJC+#;hA^dh^mPx0>4z5Tj-ujcMktM@2XyOpZG(8k@NjlIDQX!~%eR^#km z!voL{8r~5TrRBb35&wzW;CP*KGN!?dBd>A>4|Ri@RR}0QkG4tdVN1sRN~<=L&`H;l z*uyrPSGkeWAdy#LKfX%tKK_^-f#r#SBgbLJ?S7mbG!RVShKUB9(b_#YIdQV#s4s*i z2i$QDm8O8>1a8XGNSZIvj|0Ju8i+<9(40^%IZhor#0lkeCC1^?0d&wDi5CE!I8G=R zW*lXRma?wgSG~(u-RrIH^SPki{_0-E1$OTWZ6u-JYtdY`y=t}89<};_QZ=MjAJpAP zK=YcwSe-InADWCQry4_Xb?x_%5YtXK3S& z;06-<7}>2>L%o`7fmCE#ss_~RLCrO+xegkhL#B5$;yDuW9If%3i2BCry%TZ&RAcaT zlLBLYwnaPFs-K4v+NFdJU4|=9>9Z;QT1tfgamjHc$3=cT$@%e$yW{u+aRin>0>p7l zbwV`H*;@zfVu7WOEIC>UaY8dvE0k1`5QhgR0pHZYDO@J4H{JoVa~vqo=QsvSoZgg| zR5w$<8pjc&(7C`AC)^?IBM_vU2!AanF zpXvs$0dC20bbxZnaq46b)#`m(^?;CzG_1RajcRDbs5)d;AFioB9(9A}C*%If#^6*_ z=uC?y)T*AdbfHzflu)lE)T>DaLdgno{I&&g@l>D%9A`hi{I?IkBS)YjBG4BLp;849 z-`l8*!WAsOuZMRQwT7Vij&L@ALJ1JGGM6H$P3)$GI0h-5LIxb{c9i5e+&x5TmSyC) zozbQA?R;O*w>S=zL-svvQFkb+5A~p^B@cSRak%nbzN(#ptP=;jNnko8Z8#B}29b5? z*96M<>#hMygSvars2(z^2lb7^`o@v)#zT>+!?mtsQTOpW&j}0YCmRA2je%2*f$3&o zT{+(py40#%NrZ^wKsh$ax|LF(+eu|1$9X+xMci@xAvgldAAy~H5}uw=vS9vtA7P8=N&9A`m!aG4Bv5tOfXjt@u8p;`kETo&7{7z$Q( zqGV;C=HDHv2A%DqYpZ~vXifEzI@gJqXR^UR-4s0661v!`%p?`$RmhKLA)W}`Y7H*rIQ#MCzkT=} zIRX_CfgLs8owfd5(Ew;J6b(V!43vQjZ8rlTIM7VF6ijB44F|+AnF)~%2geEG1byN@ zUgc=UF}T_}E;g{W_RIpx57ii>wdUby_;8&$T&oP!qVzDZFN`e`-GbdAG3|*dO#mG& zM*3C3^u6c^Rqp}Hbr-Y`C^y{u&1&d?v2nnx8Vqk3nn(F4XdZP98!rx<8%An2j@DKk zt8P8^JeA1Cy$RgUBN%Mc(A;ZYJm zxlpZs2wRO~zr(143h|Me;7}xhYH?JQqn3O>HqX*M`*imK&Am?(El}R4Rrl%Ddkhx@ zSH911?=!2R{pQ94;Vj32^5L2)81sX*)#zCLjU%|_*4v23Hd$yTg2oQ%Ex02&xbq}Re z&;r>+Z34HfV8JQbC;v{F^tHl7Pk=!($ER zSll=s({NTiUjj_8!8VG*kHd+R;KUCYRR_$CgT}@|^Tk1P15zu zW6|odXw}KusxvXyg$57I_|@jXTx$RXhZ(;+uX`!Y+Fyn9D$9TS@H=t@Dk1{CwIHcy zo9^CWdUu9>5IXOu)o&|RZ-q9#5qR-+|F_V-8QA!CsJhn(LVaOn4+xGntf1d(hIWI+ zD7DrDyMS`VyDj8-C*XP;>te7?RYYH~Lt!-B9}Qy=Eyi~m3WN>~=Ik(D{1B|C0>pmo zhgECZTRc|Bl8)8Gn5$zk4H}Q@(8&e^Iv!V##g$|A!6Q-sXpMIy;yx61jhNLV z`i4Wsi=*a-(a45lk&VY{kUv2}9Qdxrv?m}AGmfMR#$m=MYBpYJ30!IRUv2VVYx3W0 z_TO#|-c5wS@!Mc}GJt1w-sk-eE8=eB55W;wnFxT|(5{FdK;K;x0Mh|+;y6$ap)VuXUsj@J$;_p(7SR zYW{V|ae_G7tP_uG$DlkvP8=VLE63vsT5x>40j)A&X|f>zO~idCW8RbX9`Jgs4r_v{ z4pZGBrZ+`KMR0to&IOK7*KRly-FUIy1(aWJ^n&AeS^~FP0z~jTsUTcAbG!oXHvR}4 zft85>7>!&C95;No#5YimTndCiSoJ-13Lq|6ulZrUr6k8eZLk}gNzs;4I26~Iq4mab zg81Q>3JHA2wc`ysREXop>w`z@gC}Be;sW9)8`a51b*f35ZdNRXu-NCcrRnCtsph~~ z%!k!LC^sAf*`qFKqPA+Pwn}mwe*8w0Z?0KnSD?8TFX>jo&m3Qw8;IYPBTxYm=&cFt zL_%Dtdc*%Mq{7kJuDjn3RlO;4;xE37jX`Pxd!h<1+hus|9G4Kc=Tbm(>_!5JBkN-2 z(AQU9g$R!Jhz;UJI8J^XW*n)Ni6(8bS)Xn(pwlg?B?U|H&teIFLOYjKA;5jASvl1d zoN5eA#eGvT@2Pq>bf&KAT+DSDd6gzVidAk}W*juX(d+@oZ?^iF;}vkL@kihYtXKqg zXm04;P}N)h7vBzSK)*Na->G}HDb*On;hvh{UT{3@$B3Y_8A3({qz11kk&@jGFz5!* z0e4(LIrRP-ZN2$%;y54CxuhYmp3p8N zwDYYh7IR`6okZ_eTPKVL#4Fg3BpQup1KDaK%eboO0;< zYP7wzdVj=_4{5VcMN)xEPQ3~aix;TmpS8cIyW~ zAq0Y7Na`0YU9t8%oVE5>!D7zqNp&uz2qi-gbp3% zlbS~QP^9Rj(s^Cz%HkX!tTiBPr6Ls7p@X7wT&&xqy2DXxu@6@I5VZ?&e5}EMsMe5L z;yCa5=8wb|WkQ_2lXp!uy- z5SE<8`SBIIhxm;-0?#`FyA8#{9^5g8siRR15@r%~;fB^9;mWboC zDHS3=el3N)4~2m8J62{K5Qimaj<47~#BaFdQK$`scgD?h&1^!FP+ zX(F#9~M|5V? zyJ_tX=f|J-jmCdIM_>gbFceh>YZYjqCIlUb1fl)mfOzzKsCuvALmzFw?gh>F8lfCz zvn$v(3lPV)g{T>?)uH|-8M(Try;vv$}Mpf!~gDM4B6R(NgXeS$}Ohp@S7R!GusZ*`m zbgMd@kQ`Ufise6{d07jBP z6}*f1tvLeEHv*+|eBb)xxDDcl1#t}!mmIesu8hQ%iQ_F6#}hV=C!fagWKoW1z;W$X zTDLf^F~^_pjmCdEM_>gbz#NAqFXYDyahzxljvtDtaN?s43Q3xAbfg(arzAhl9ACko zIlnbWU`3fC097mv1BfuPA1ji4>G)wAeTm#1m;>__% z{f+bI;s~tu2r$PN&2a(oxF#Xa9AE4A3V%P2K&3_i9M6|yy$a?z`}H76R;^IkxY(k$ zoO%^{t{bXWs9ps%E&J+g&@N+XisM@qs#h7PGohhqt|&i#sLm9s*GFT*o6P^Eg6sTKppDxzK`p`L10u+5>^=`bNg#VY4h z%K4Po=1^?0BI{M2HqVLe55*3MN%eLL^PDeK>Ti%g7e|02u(Sx|LmVT_abo&v=lC49 zKTN9g9OvgOFYQ+0S91g^HUi9XGPb8+A;eiC;EBwoRii( z=eU^XRIw<3szqPiJm=-Sb@|uiy8MhtjzfUB#c|G$Fa37mci;$AWCXBJ)=*R-4Mszx z{dka@=IT|ev0>JMngH5qO|*^|7a80WH5}DftCQqeu{~Cuu}?^o?SVQ?tmLfI25L1t1ql!zuG5F>%=uOu zuGbFQ6&DMCpd$^sP1=zL?U<$GjT-c%OhxuBj*sCHZjBmr5|t`Yvp(LUj<+b2KzXY| zLb1w|dX-i@mQ$g9vd$;5rwZy-P^=>ARn8@KY_TGg(k>>oOKBCll9e)>7Q$9pVv^HJ zj$3&Zu2-qZJCHvVM_}m@7_L``>J*aXIM}^McLU}7!oGppAlkjAS8SMN2C3o@1c&yA zReGc{9>oa}yX|dXo#7}6?j7L}Bo7@gE;5*3M@S>`Gsp|}*5T1{#{POpBjGWm0}vpN z7CVL2sl#=kwoV$U2hi1nF>N@8c3$%wKiZ&69c$1bdY&>7oL1pGw&P7Ybh6nHYSB-& zswY8kpxl|`;`y9{+6k4YEgrHggr_Y(;W+r7!|^Ng97j?G$#KY<=VU*=^xK8sfg@0n z5m-kY7Z88Kae;3s>uGkx@sXGTA&UZt3y#OtgEo;Lmk>vX2u`gdyX}L{9G{0cXui;o zOOA^T4k2fbr%L2F`|*mr1NlR71eP8F<~V2$Gd?8pCptkKEtdSO0gm6W_B%xBA&fci zcewPMh2McAP@xfEj^}XvP~3#T@sYT&b~Y%kdk4ct*c2IL`U;io65)LvaL_9s!X8wooo<4gqS2Xrq|wEGw@<9M6F`Q2x9)el4RzWXai&SLFT2 zABrQe91)=Ex*S)&&N+^fl|^$r2jY|pf4&?insa`9Ic^tz4~{@ZMgSboM|n|>(^O}+ zwdOe$+HK03-dwN?l{Iy#JGT8XF?G2!60+twjm6D#?x{2Kh4uH&suxatFs=_;t!2jb z;kYr3I&qkBWWz<}xB-ZdHkd~nBZr&9hZ^*!`f-}@w5B>Wi`SyX-YKx*6D>5QNq$_j zaxAv-#msYx75TaA@*V3{Qp#*fA%f3yob%%qc?a@`;s`7~0>p7ibIOv_{wkQ~M5PMS z-D{{1?`@CeNRlwZ~N-B{y6xq?TGkygaf!{ zUqiS*W;hn56dLS{8GUhmcZ1d!f1*8c4eGaPUtA*{h-<@*g3BWoov8(>ML9}=cC<-9 z(xm0UW^J6dOli@?#wjJVC{`(6uOjzRxsWoTbJ!{iPj|C~9kQe@rF7`Z z6REQ)eKw_DO>0u@$CrMy@H=n>Dl`I%;W*LUY5{SJ<6`qE0r7E*Zwe`($u2)(5?ZWTC5va%rR368H@?7OZ93$ZP9*g6BNUc~lT%vq$T!Vko1fu%>lk>jXN={G!h1`ujgP_iN_ zRU&@qKy4^T`)WfFJz*zjk`srHlbjgD4Ch|B>6o^&CIHbqr*$#vTO8CMH=LyRH$Kt6 z23_hvgANVaWEB@K*eS(vVl!v3a^^X+&yiTtJSXSJmwvnOJ8%RlG6Ieq2f=}I0q&ZB z6b=WXN{;qN6(Q?kX{B?Vz>NZxU9~|79n`B}5S_BLugQ=)&}c{vHX6{dO(+kCMw^_K zgKv5Gyf`k4#AV&#a&VmectzfU{Gm7kOOL=)ISxNgmRxxA0vx9uOZEZB3snfp1vx&S z;I=18iu4KM65r?)A~qoM~+J~P7s$UuQ-l38vATEJeT7Q#;|3> z3F1Zkcp;zeSSMa+a2e~z*^gJ~-NGM>BT$(Ucq+$fGutfC3;1!`d1`-yks~C*9kpD3 zJl~1i{kX(8IjPP-ls z)#156{sZCxKmp(z`>PB^LxUF62SD?M+8+%;1^swj-|M73F%|g`?1HkZHUOc6LkwE` zqM*%F0kZFJ)JX%4y3|mkE>TWECy3MR-f=~9TnOjP%w9AarnuLHjlKe*QaW-@i%UXK8;?52zEo`rM1~jvYa?h`>5o%65NDu*`7)1IU=m*Y^x%-Sh4gunldcMy>a|PTD_FfNbJX#e6R2ua0Dtf0%dU=x$?nplY z?tvx~?Vh?2BoFQEw)YEhJfGlpj@t=N6)9z{>w!rx!;HhZSDGKkrsQdLCasY;KVGS~ zAb&27z>*{I961g;6UWgZtlQab@0Y>xMt!hRCqKTn{V*pDyyUg0<32vlkW z%Hp_qTF^ob#8hYzetfVw3_ADMD-b$3ge$kR+ukqEaq{5Q;)y>{KEcV47s`Vd8ei3Z z9300Zfv%@D68rH=y#@JmaRineful_(P>!M$RIO0G3QAK3BEJ2m2W?KhO1XIzpxIFb z?i`Ne(D7mn7UFo8-C|-hEAiO2g&aTJXh;>}b)oTcIX;olCK77C@+(znBxib49?FT$ zoKDX4raa7<-lRitTo4>jcS|Y|`|%~;EBpo=fl7_QvF0%08ypAI(dKX*Bg4@kN)Lx) zO1T^_#9xf(`|%=m{XUMoz=8KoStgG z-Z+lOaw4@dlT^^MA7A2~!Y}6tRBi;y;&{3F@gf#`S^PM8aC?O~WyUFyLN@#;YJG_)qgfbfY@g?3V{Bn*!A#}J|JJg7kKE8ok&;E#O zAnL{VXrnS*?;oo39gI7194LnxP3SO2mJv0Z2Spj8 zhRbq9`xn~R*^>uHi*$;`ZvAjmu8uV6(9wlD)}$S80j$*%&AIJZi+;RS&1uK5=~aty zvQ;m=b)3vBGMF>HDG%kuW=v^g{!_hAsAxBR$19DAa{m<|m!hM|F`9GQ~8G$AQl zQRUqPj;s6Xf&(#Sq$PZ)1@EAV`jdId*AlYj9w`el;LZ9GYwN*66POFfHIN!~9&b@g zX|Z|XM8dMzrMF3~2(|N1NpRcN-?hodc_;RYWDM;ZZiH7B(~c@?Cpq5RT7>75-rLk-&g zx*%u{h>x~L0Cx#-bnGv&=f3S3@P(MBv`OI>`^vWHpmXW6@+6ckDY30Aj$4*Ii*nA7 zFXcAj*K!0ZIs(s&<0H)`IDVi$1dapZ%yGLVmj*nilVii>VIe=hkmH;mujo6GKO9G3 z@ez2A9ESl1$3b&I{BWWM2Ausk(L4v=@=$_1r&EaI7c&Mu0ggaLM*tAV^d=;M4r+trnCcXB zn@s`I!AAdZ+&|K!LI)caso^FS8fwvoTlK+KeJEi-=s*K4T0X%g#{q6wa{6lk9pd9H3QX=5UaZ0KH+*Ch~5^_TMNV5VRYzj#YH!ILki#pt@4JNdqqz<72 z4Ya5-F_Pcmyb6{D+2=OxeS1#a-Y?|43ym+#tFRwm%8kOWIWZktG=<`Lwv4>WR8l)tz>?cNxV?WarRA%T8OJ#L@ul1v{92B{ zs)@jn*3jXWAcPKds0no`o}rj~f6a!G2JexU(80LpP@@l>!MIy&!y;Dj+teI9*c?2B zjajg!KSwRfNUP?kLkazG(maIv7Nlre)Wa$Ba4L+>NUIKw7SQ2V-7akJHI^{O657dD z$5yw-pR^~-g!m#jK9$f)*QtcyxTB_1dI4$EDecTc<&b>=*0BgErJYTxXt`cx)!dW( zK{*2DM&Ky$4T!e{(Sb&r`~dgxJjXGDLku2EV6#IvvgD4U%Eg>^6h^*P8A&*3G^HI* z>xYu+a7z#u9LX5aLHvz^BFK`3|C1Omr-*P7TrSs-pGxTEsZ5Sfr8Q{UCStlB<%K!U z`SEgZ4!)ivuu38TKoi8#ksJrR57cgi4acD5I696H#~_fJFCsEvoiAsOBZuSkKKbuV zBgdHI>8v*|jpLjjUnTb>e@u=*xe*|IgW%{uhnoXPr`S1;L-OMS=vJaUzb%AXf%2rI zv?D2fG@*)|OsjGDjZ^9lackz*+xE*m)+yxZ}#0pYI%SnM){ zoy0jmZq0d?mRI5YIN$Odfi)Td02($thvP`04Ar~9adPN@J36rE`2?qtr&2rT0uWqs zT;MyULs^cus>kwlJfY_61fJK!94~|8?8n#WJ7?PPLPacv@+XDHmzGyyKhC#1M_`Rc zU`088Jf%BIAlo{17&R&_A?hD(Rq_c=BaRR+l2mboI0jb~;&^jMh-0uaIL>~2jo!oj zwKxJR%JCB^{Y271M_UvcKhhk6s4oVc%s2*_$b*=xkaC;!h`4v@g8C^(vKqGxF!-2rM!JmBVq6y)201;uVHC{*qXJj)UM* zlF=o0^4VQ{WFg17US*N@2)~RYQ0WmUm*cSH`GWO!l%pA^LGt6U ze|90q*^gKH&B&jRBe2K_tSHCF(t06*+F-X74sj)Od?h)~etePl2)~RYQ0WmUkK@?n z)=9^(xZg>IAWq{Fnygi9lH#muZlk4nXXv@r+SO zptk)bIK-9g$BU!9IJNW7F621-@nyMV_)Rzhl@|fjr~u_9)~k#qRY#4dG-nmycn-wL zk2A-ML!AA1<=s8}i8un45dkVUM0>K`K#Tgq!!7ap$;o*YnOa$yybAmAHFx*&7vcy|1j^+&p**Jr$Kl6wT5x<~ZEzgB zreI-b32pAW{Dph1EQ23Ul~;Pm`EkC@IRfh<0w>$FiHwSNs$EArmJA+g@r^d%p>96( zPo$KwBp#a?M1L$58c(TXDfMJtJDGv?*7Mtm3{dVY{7ry&gT!A6_&XqD2o;*=OzD$O zDw^7M-g?FHeH;hnn@=ajTb0tvmrw^UvFl7yhtAq`I;lG=p`Feb>c=6VykyNAe2w>4 zSr<1mf5~+lfvI+Fs!c^Z-JzpBnF=0n^&M$+p+$cpqfDfM?;!f)=vbR-QOUWzMXgJ| zCfkjvjP9uEb`#?hDQu{sqI0UvfJ7&4I4Xya^03gpfR5wzs)B!2+wFPQ`l;% z)D{=pHIGs84vv!BW|h{#j#uT${)fKs0@tgo+q;~<_*##^DU0K1!EvA3YWcK8or-H|^FTU0zu%aAC{shQ&)U)^F z#Bs{5l-S}WcI+;D|Jib!{rFnHnfd#z+X$4-agiv;3VtU|v>W+Ce!S8+ek!Gxu9b#3 z{#JOl9A`hiZtrsb;%hwu<#HS-&lixLuPG!|3YhWdl~)0p%hIwN@SHb%wj5_azSeJM z{(kE=0yMpemOA6f!0{F@gbwOhi1L{2r2b@Da}*VvVD%J161( zOgYYeyvTjPr#J$uIRfOw(Vp%!;J%Aa>}RnSDgFLl;iBji`)l% ziX*U^BXFk61i{fl06L0N#uEOu%JFkay)3OQjm`Wu&T4f7Jm=PeFb=3ev!L? zPjLiRcLb)pwdpPc?dfjwRF`@(6FQ#s9BcKCrG1m_>QtwKcA`Cq_Ed*9l~JbCYQE02 z8;&~LVL0kcyAGXh)21^jgidxOW1P+yXHkW+usxI3r_*{)i^GB{l9;wOtD-Hdp57LD zpXE4Z-<{mvKb6p(mDDDa+Nnjg%<E& zJ(lrJc7&$76toi^LA2AI%BeQ>G_aeea~(!mI@_*8XWBG+D|Be&EbyH%&gHe@;bioP zGFwZVvX<4Zc%Gz8xZBxn?>j?0p#$QJ7IVDFUBIU}0;@X$g5#D>Z?ZVvZgD(malF&w zc&Ekj&S$}K5ZqB^!Me!B%<Gu;~LY>$4rOPy>Bj3qrM67G{}-zj1@ zXx<*AzQ|=esjQ?5E-sW;VUAOFh4U(_`=;Vg&k=aW5h#n}ju6Knb9`}5-<}h<_nG6* z_%7f-jw7(TBjCXCgxk@NpYBwi%5gHapJz6-S$3ne0ASc{OLIY&o}~SyEW)s zkA8j=O2|`R3e!kNrcH23Q!9ucMY=23i zyh@?*@-yb5s4-uQbJI(Im7U%8K6CsT-v#`~aRgR(1kM5C-P-vc{lX^WY?pefEijJc zc+!K;nN9_#Fo+I>P9cs{;UMTNp^Od&nd8M-Z)dl?&m3RfHx+++j=(dHzr$uN0w)vhiKGXevz-b~VGtb%okAQ3wE=NZ`$AV3LWh{n9A}O{+x3P@5~WcbObJRY0$-P{ZbDMH5_+fqSZZ_@St<9 zL%}Hwq61lHg(c6=kHdol%@~)49fxGh9Z}94XO1uW7t1f?2yg^)BXAKA@6s-H>z8|s z3!UnjOklFrJ(cjFbG}2tDGZ_mp>sNek`?7l8&EEEwjJx~h0b?je-(8q6*$@IgV4bt z1}`Af;-vFP!eA*svN7|@j#%qC&zIbuv(^Wd(Wb;C=efKV`)2{H`EBv6$kNZAP8zV` z)E4pMlh$@CXcxUGA1~x}`ME!RKIRClnFw6o1ShUR=v?dungi2m?^M!#rpjUQ9%qhQKqsaH>i|6oZ-PP4AHp~euWUAe@++Ojl@7CXf#BuI zf;c#yBM^M)!ruf?A!Iv_m&)7 zhjS;s!_?DzA`inHFHUymINyLA0gk{jM4%AI0cD^WPzI?bvL(KAI!MdlViIL(&_CB6 zVvaM%m*F?cZ^04Z2o#TiBgc^<2gd<%0yLR!pqV<7?C0jwESHg9x037xacZw{Ugc@q zk+UB!{^R7c9086%NfDSqF1tsA(76ov-5xjth-Z8kkml}IF^=|PX9&8~r9jk2iwkfu zi3Tx3gJ^LjbG*12$64lhNxxCPh$FxeC?0{?P5KNV-lL;)rCYrKi=FnKNqH`IgsyaJ zm%(ljyc4Z*u_HLI5YD219b-PAA>d3D@bQ#~KXGbeS`qVaPt!dAYsd z{AaBft@;hzMNWWX$&HXrY;I?P7cI9EhCs zT<%mbj`k9O-lak~MZyS#{`rjmY|48&;YN#>pfla-g3!U?*_3a#J3QMJf$TId!tu-P zVMmqA@tpD%c~})rfph6=^@vTSH%6sAA%#W5)rt* z$+*^|qlK=*fVT%PqfU>y!!WKlXoSsUK1 zf#ab0OvjUTK!k6~m7}$LaC@IQ&KzGGw-tX2j=(dGz_m^K)gBEkG~2CRLMb8YPm-Q1 zoyyf7EUZ^9cLZnV^W%WEOp#NE*!{$V!-iwlv|AI2^>(}#@1TR!GhN0^r#aJ&P8gG) zg56>qhF!FmJN3(Gp?1j3SE2m)g|tz+F5==c*XxUV6>3zk2 z7)Rh)M&RmZR2*t(sdKR-a4v&7LhqGs1tVxLbp~g8R9u684#dfZ1MUE~qh`8wAwb-z z6%g;z&|dCTFL!7{g5za~_SGt*O&OO;7C|2+RO&@4Jp7aAS)>n%in#-;5kc=wh4iLdHAWt>6&tmCoSR z9`)KLO^kGFkVN?`yg8~2+k-To-=g%eh-N!A5@tlRYBy#|7W{ajym_H<_T%g5m(5?5 zBd~rVFt^3LvDrXtb>N^wm)iUn(%#uF#F=`KxjS)=vb8;M4-#S35(OGd`dk;0E6vINqULZwp?7 z2T%KFQ@$Be(t9Q0xzy^0E+;%QNiWU<^hF>pta=BmJq*5nquW47puA*=)0LOg0_A0> z*q$}Z^{u^!3f;m8kQ)R9G__qppS7lagd$-_zn2+ z_7ETrMuXIsfoy=g#RUQ45aAma;If;Y>a8yAX14)GJ4$jKXXkoM914`T8D$8W^t1t# zmm~9Xx(pSnSILJsMwsI(_%r3V<_K^EibUY<*6^JzCh68D{d#9;CgZ!>9zY+1bKNRN z(BACPz;S8AL2ZIK(OeQ7_`cn(-{~=+yPM3LT?SC@s5zuuI*_FitiRP`;t>7oZAR$= z@xk%3R2IZ>F>}1gFNaTY1ULef5`lYL!*{osq}!VS)6i_jcdb2uJ_c_hGu|0Od#gvA z1ILjq!EUrEAGJ8Vo(bG&3(mENZgr}6y7haT%zK-|Xz%tI0Q&7N<5mIP?9^|xt8*P1 zF1X!o;t>5CZAR$=@ymj^W!}p$}@!~&zKFbkUBM~Tz<1pPfI~2HY2sWIYI7TdFYdA~7A^fg`SH&2EuAxeZu%D7QL7H`{}A$f&dhAdK7u+}i>-GX5Kx08ZWR zB)IFhx}0^h3*H}p9BjT$ec{L3Edk=_Jhg4puV(a_jBzz%Rf_5gY&!mhi z=~5+%VN&`zr9Jh*&V#IS%q%(gzj{ycRCf)t@hwefIIEGp7K(AE$M;i z5U1uq^KSiSQO$MXPt>R^{YHl>GA&SBNi8l$^`YbX&&wIjQDx=RL40t$bX`b`l9fWp zb{uDpukD+Qza2;58Aag1%O-e@79x&cZSy#DygPKiN59vtf#ZNU*bQpWwz_6os?lCe zxFJA%F5}19yC8nIRvyQZv>}d{)`H`h>U1nQpUG&>Dl?y6I>d1$bNm_oWciQb2yg^) zA|MF~ z01y|rXO5?yV$a!+=lmM^kR!kmSWE=odpZ2@B@-=le+zQi!Ru|_xeoum&Dw*lC<9k8 za(9yof#WifLJ*f(6i^$2TbIJ&?JiMEUV2_-j{SH_r{@82eta=MWqu7uVBJQ52u>}) zU7X|a+Q^x}cT*Ca3^+{sgH6W6&88F%CC6`d>qT@EYd(=8??iQ@iZw)w$g5myGx9Z? z)*Mw2y>ox+90P&a1 z_g@Y}54Y%d!10XdR)_z=X6-%HBlakFF}=A-h0q~73qV^{E9g)vT;e;YBbIkMiK@%d z(gLFSMMK&xEbnwuA)j7o(a`m@mM@TfwQ!uWD^n>QnoQeNbk$FORU)qgTDSK#fARGd zf%mtX(BqfF(0iNpyPd(gwC8q*|KVos(N^O@k9w~wg!aKEOkE0&XN~qe$7v)7-}3N& zkLjp;-AKF$-R;szcREo9;|y_-eYrS}wL*?4cQoS|d|rN>IljJbLjJZKfh9)ZF(AIx z{NSZ9^k}nwuQPZv?YY|#Kp*1|d(`_~A++yp(jIgxG>s`;IXW~V!JXUbF&{YTez!ro z*QJy0c50BL8DB1rUlYj|=J*nSFZ^S2G*$LlhaR`oMCX+~Q$G05J zg*ejXP7uf7a&i1-o8hP%X)RyKv@pjj?+3`Ah$FxeSaJjkas2%)hH&Vcw1?daApZVl zUAXcs;T&q?5Q7c`r#VmNc+nE_LiOXES6TA!n%{sUu%06D;a20rt>#BBLE*=!8Sf0< zPP@^5utlelM?EUWKiFct*P|kn4r;$=l^9a{XiNCf*2qJP+WGCu`tdf+(Trm--;85~ z{5W>hqFoZHrF6Mte!Q&YI4-`hg#A^{%rEFCf}^ELPM+snPxm5!SB}79Bk<8H#)p9T zE5=7JhaYcMA7J%nyZdgt_x&xQk6tz(Z&4m?Qa^Y}`(Uf_{$>@#f4nvP7)-YuI$HD} zZ808iHXdy@-ruCZw@F9)5P29Fd8E{PkXmuj{cfFfuS+A{?NpH;zul?d?l7TS9fnZ5 zPP!?OoiDvyj$ca|BtRS;Vmewo$8+!vI$uZ{rL_k9_1SVH@J+I8y931M>s3xt)yn+l zS+s@LQ(LZAS?q1Wuj2@;stA1is`1e)I$G$1m(+(n{<|IS2i-pOKl!%#;maC2bOAb# z0d7mM=U}=N4k3B={Y@I_JzGV&J@;Z?_DK~lqJ+_!=e*elIt$HZH0VZJh2𝔰Pl# zFzG1+x^5FP=1?Jyi{}9W;w8(TCn=@x2ytn~Cjs%Lar|VfD)qt(+gH^OlRqp+fFn?H z1ROd3-lhP?Kl{lD!5tij!0~(SexzKGX#urAemMdm_X3(1;W$v9uZKOzwhKMzMj4FI z{fgx{P+qc1VR!yD_N@@flFOt@US1`;ne9`ZI9(tijt+CYfI8aN=7P!2M>@btmHm%3-(3jFSyt7LMN+rHA^R4&!!*ep_Tzv|DXL*v9r&LFu>J z95k0!9h7qLL@2S zKywS|+MN!e+wE#WwduE=bQ7tVe5KU6d6e6;D+1+7-HvjkS>{oWEmleuh!2jJB|F@u zE0-vDaOGv@$C=}cx+nNW9D&sqflppRhD1jTeYjP9uiJmG-HrC6mo$t&-W+<^<%1q{ zdhcYakx_wU`dgyB5Xax|F&y=%TPMBOrI8+Xs`oq9dmUNbZC9W>Z6OjJ=C*Ch-8SuR zo1U-RX*FMh>?w_O13;gzF-INCwUjz*)0LEZC2eWmq}vndh5E4YWkFnCynyCb;fkE_ zl(}+Zx-{A)c9`RCc3 z^@MIFgC*)lA|!P!8G53WaxJCI+H@tY2&J@gq+cx4k2|A0rJqh})0Suh+o_~RDh1yY z2~~3)cf5!2_xt{f*A+CJCq0QA?QAy@M%%|YO`y$sd}cd z3cAv;5kdze7{Auy2G#+0BKx&w4|KK3O`2_Vk!akh^<8WBU2XQw&TFRGcLn{{z)T{m zD~Z76dCjDh%TBtK3^_@;ln^K{OL)#_4$YA+Ka`3zS5B@Ji4{B~F{ z-6~L_8WmZlVz=k$m;5L5h0YN;o6yd*s;67k>4eZJOH&CIDo${4oFL8|caAKNas<|D z1OV}`z8!|XKx$=+@?lTl{Z8*kn}Rs}`X?fQ`)4m{bPYKE@k?PqJYTYq9G$fqsAu-Q z&a^1txIlSANYY%Oe7=Y!ry~<7IUUZcJhT65{0DIao@WH?9RGBy3XVVS@)hFvNAqic zB+99ZoC?Xwm_N@ivnKxR>89Z67Deh*t3sM=RgfijwB&Yt+b>wi@fX%ac=$_j1ULeD z5r7ki?}h+$a2y0L!g0#0*el0r!t*_Bg@|p+JA+s#l=mm_KzR|Eh|-IY^?kxGlSaM0r-6A207e17FP%SVa-|`ql6^-;O|Ey<&d8Rr|On z_+gh1?Uyeb82sWT9fLT9%aAMo^4qmvyjt_w%i)i)yVhpyad+rZXW&7H|5maZx|yiD znW$bx-@P(F>O{TgL~S+cxYa=m9gS8Wi+LOc#6x3^eh92T*&Ljga8ScDNsBT<>RGA9i>@?DUGZgZ=nY|C3DAxhCt~q?1+$EorRY<*4zP+fgU* zS3p21y8-YK4HT-{nJMyQmM*ifL@b_OfzuBsP1$J*%zJja{ zApTjG|C0{yNA2#<+FhS@RDIe}^;u{2r=4y~-cK+u+V1|S!wvdF75hzB%LlV_Tmqds zz<#_g>b&c}e?fi}K~>5cGLZfB^kL zruzNVM(A;B!zY=lPuezo+P+cHywm-8xA*fd-{;+aT=QX@>w`97&rAOV|MXA)^k4t= zU-J6@_>ceimw)*ec}N{x@DKC<{M*0%Th7`4{LlZKKlu-MdCpmkzxkWL!JFi~0}k;*`grK%pDi@9j2xE`KUP!4 ze!Nh?d7LA#>Lc){;P}h>_qM8E1K&M?FS`9e^JksjPukrdrmG$&H#}nS|L*Vp?)3DujNqd0)s#J!4En*I!>KBm2&|OfApgt{q}GFc4uejrcIlE`Imn=|AL?Y`Jcxr zeD+`b#b3-nTWBQ5gWC@anenl@YDbY1hZ(mx&iU~|A?I<9z$%Zx_g~V!*@7%e@XH=Q zApS+S4=p$jI)B{e`UpllQ-v1&PdZ#*c2+&}n(Klshx{7u;EoXc>{2OoTZ!C(LNUsqLi zbaXW50v!IvZ~O-E{nvl}*XYBN=U=d8%NG1igOB&)AOAT2Y@rc5xO4i2IDR5pRX{GF zoWy>-P{4VdBe3ctfb<9eO`=rE7d<`*Ig`)2JXQugd%>seE&=iOjU?juCqR6r`ja-7 z1${SAUV22p<(FT6`Imm_mjF|kVz^i2NpfBej^k9$pgaV}@p5^X({bcDu9=#gtgo;C z{ont6{11WG>;3f8Pjg;~!=L)8p904}`tZY7UwH+f&*wPMtn2z;{Ka47zgCWbHZ{Bast9LJHZ&SWz1(f97%`7634T10-_F{y$bQQ9|t+3kjKNcz098bVSf3-Qc`FWNSK0f@t)x49v3+%o26bNugr{9_;$ zrnN1T`L}=l*ZhF41jq5Gy!pl(0|NuU_G`c9nE1v8;P~sWzmESE_}72^*WdY_-^u4V z@-vZ03+?=*RIU_?w`kz5U|Fi(h~J_1xTC{^#GkdGq1JhmrmN_~VcB z&lVb4MvlwmI69mkFBEVd=LoF&2z=86WV@iRx~ipeM!xKmh(VRH`dAb?`#|6q4 z#qqTe#AW>s`S_M2g?L?f+`bNI`?7vaelv~$N1$RNAgB!|-dP2q^SvJT_cwXI>2^Ul zB+*&4-*i-eW1(EoJX8H;y6W@P6OMnLc7K*CJFikPk*JgpvWR+>LLA3VTPI^)Bvsgt zSIU1~{u~^Em56}Fao1O!KzX%=Z#Pg*9RFq^$G-vSJF20t$dzZRze-nqX>nZ8Tyz%0 zag>Yv-QWG)-~P?t*i+R=S^W4%Ka#6;=!;|3B?f==!ylp%|NQWW$a~-#bmWz|250`^ zfB$d1+yPgyfe1OXO8XJ z@vh~yC+&XbH`gxb!|J-yYH*dKk>fumd6FLXs&`5D{k^)1ck-4E=<&h&#_ zEK%v9tm8Z%zh&(C1v~=xW&~KVO1c)sD#~mpW;h$25@>cxO%4$>+Jz>&fU({V#TV+3 zl>>{=Xb~DrLcK|-OVdEm_nSmW`LM!p?(EssD_2&Om91F1blH+6ZEbC2NuN7+uB^DY zPgNg;zPz+_NpW#SX(_-liFk2AfpX=^lP60H3pcG_kB{-u`JUV-rQsUw-yM)^EPGc(OkKsldFa0yfY8_s>6J1%-zXEXkfMo;}-& z<128(Uwg1>=D%FKcC}{Cua^C3;x&0S|J5s3_OE=q^x5eA$%cZbg7SVJ@WIKJj@qTU zzt!Q}+}~=Kz3Te-%wT2aeIiyEt0D4ZHDIw9l&WJQba9j>H&P970C1*1NYass!y+ds z=k?=#;>^G05%}grV2C>2tmrr@SY#cCh%-!#`rFcRlq1^M6Qyq}+6D>8Q;~lN#m%qAnynAE8evW-pTrns&?fYmp(p+-{SnKwl6P!^xmP?GY4z&&&&r$I}4u- z-# zE3bo^o26mp<5)_A+?hNO1P>~_Zp|9VI*y^^rA0+>NW6oJ^`A?ZEID!PnDMwbdgDzfVA4$>iixFs^S>fB$JJ#X!Ea*%IFOvk@9$PeW& z@d)q;+`|!ojyI-jl`8TEhX~-P5HM9*@U2}KT*n*DVm(9JZyrY9+I@TWtXZ|nJ9Z6q zbx>*uI?Kn4i{F3$eZ{KAW$;yCryM(a)cY+^@WQ-2jCj}fty_2R+_`u6?oDz&{=xa4 zY_EJA@9No}o%@8U>do)1pYoHcw|Y=tnC$eyVkS)^Em~?7nGv_?I8Qx8zTzRdfD__h%mbc*Jy^=i`G1 zp1;Z?aL-1d0Xpu|HaJnE!e~S?4()bIM6*L|wTmq_0g#k8z+gc#Zqqbb1V$Rm$D7Tf zEalRH;pjMIxBAAq?Dn>{rDbLCOrYZ>g@sW0^_7*ocI?3PCIU=4exSDY$l=4_?3pt- ziAl~9*&oNUNm%Fj7XLhuukxYnkMCRdOmA%o`0!-U$7hchJ~i&$_RZ{#?;cwGTm6ZK zl{h9H-@EMhy?YCG<^Ce?cm5|j+5atouaY%MU9;$k4Kp4sm~42jXAe%|OVRPRee<#( zAA9L0ZE26UZY_JowD`B;v37R1A%2aRj`Mtch);lD#v^dAMF7colS@lR3PzgPY;{Tm zlJPdX*lH61q?~3un;_ygO|wN{K*!UB7PHiBks8g~y5Z>fwwjtP8#j6fth1v7vzMgf z@W;Emx(*#YxS_IgS$R3kbn;bJFJE4@b}eYEug7~K-0;WYq(i=OL!7~Zx35z1T*C5~ z?aN+vbZslftCjP9vbW?395nBmU-VS))h}7!aMJPRFPm4qb${+30%}X2yLyFnGe5k) zENjx(<@3M0de%SZJsaIv^%k;zoL6+bUDokyU-j)M0B3wx`Eyy1tCqfIJ$Z1jwfneR zpRWAXVr7!6E&b?)2&qiLmdU^fqAMD8e z1$|o5@vhc#-1cNwZO-q+!~0m%t|N8js8>06wiWW-v$rH?lIBb=OUV@-KiawuzRJhP zn(02uc(i>@)+E)wl0SU)xx4C7dFhr1gXlOd2%^#ys#Kw>mHx#lID>kX8|OKBK7PyC z^9y(c?#&1csN=2Bal2P0?$PmPITMGVGiA4kZ5FZJECJ{^Xdb4H_xAK)p7Ue5)|-O2 zv8rmDXPy(g*&P?=#Oy`8Zmb!+{~CR&*S`O3sb`IDX2fAHA3N)VSmO zRun!Nbh6Ry&U^dgxTfL-+xD_&aB!ryB5$&IL9SOh|6Xs_Z?y-vv8DWqj(>LHY~E9$ zwG}9CxuJu3-HIuNlcPR6e-0N9_iMy-oaf`ieH8q99)Wu#0&N-k)^r_cb7=wDDeVpk zc1pWUn@s@ivXmn?hf9u8J|lHlr4EZ0kd#Bm8%)E<$I(h~c}2y}?b~6bAmQ!p?naFY z)g7X)oSEGpeuxD@EzQl4`!i?GkUx$VS5$OJd##Z_4vYM_r;Y_WzEQ3pr@F(Q1Ixbn z^do?}6g(6BpsIO~7QbjI{$unPpT18|Nzrjka-M8o56ioGJ=-{<*Hf>8jJ|R0l$=Sb zcjYNfMaOYXbLF(G->K`XrhR#lt@rul-R>_hUTCi=ge`u&Wfgwh=byg!#f8564bjgX za2zom=lS@6@#ZIa1n&I^K*!r4;vOAugMvFG=r}{x@eaG#VG{roba>@*o{pC~ZCcP} z)d5AvVXX`+B&ScET2WB}`+ME$)kwOr9}t8OcVP3J1qC<{a2|dO&Qm^)k`=5N0x(aI zfRm0_u34jOp{eBKq~nVx`xiVF0(KTZPM@u7?-G=a*W~_O`KYAhSOiq`YpIUcY<#G@ZwYdKH|%{MA=D_O3KX;R*`LajQ$0E*@=Jf3jiS(Z$V*9aDbX)ytQTH>^6^xb9GE^#>;#u6Y*Xe|F)_!R9S^`=D-LcgeeYl$?uPSMFMW2hXIIyrlH;AbE)QpE{)p)~ z&&QR=#SeG{zF83%M8`?WyF5~k9K6LM&v0Ur)1q#}B&S*EFp2HJ4V?K zhdR#skIU=wG4lT7K6p0#7CZu@GXjdQLMeH>Q_GNj6(r-(Zulzg9$%#el`2*>M$l#v zK!-(WHzP5ZS}k(P%5dscMrT02_D@w9BNRkyK)#2?@ zV0O8DzQZcCS*2Enw!t!NUuC3zv3vHug)w45G^G4G`SLMJ3G-v5#W7M|tQO!P7kel} z%8_(OYWjm7hYO=L^F8o<{GR+iV?f4 zLMNo$Dzzgex7=+VKYjZ2(@#Gg7#J8D8j9`hsZ8b09|%?+HPqL$Ugsqxb^G_DAHbd8 zbLe*%F&*dm_|P8$zmiAbo{GRAI^N|a<)~W0v?mnYTgRc`&~YZ^7Pcm+?Jnv#s>QJt zeQa#3%IhmJF|nYa0858%`w1YsM*{$CYJuu?v~9tNrnp$FgvKva`*_=T9{L+cOviaX zKJi6)A^~1GkRbG#xgLEZ>?g3n8JFoGr~a4{tx9+Xxlb z{!~_0W~8T+fUDJNjYgx0Ilg`1fd^`8YHmYzQJlV^s*2>B6da=hRw|)T{Wfkp+}{yy zcz%?oKk~jmBIY(R!%35z!<^^j`S@@j1;3t0;2w!U$9R7LHSf$cpk#%Bj)QKD9x3m3 zYC*e001$CS$Ga^W&}G3=AX&$Uxv$%>f&>jkW7|g`eN>Vp=ryz(qs!%5v0_D8S(({v zR@7Xl)BVSP{6|ku&k$u7Jzmhb932)F)n2o5B^m%=t$*d(wdkOWtQ@a8xKC@30G? z)20F4a8xXs9$CkGELhdaRs*5;;RwYGeGQ*~{`uhGV3Kc)@WiK0o2IncLQ}2RUw<85 zxuWLb;o&d6^b(eX4)T%U&tN|}Y+j)#IQnz7HaBBIDZL99w6(UvD_1UnX%6=sJzfU6 z?VY>?;Vz1m`h(3m^9B-e$okE6d{MNpzyq%zzmtc;-^(K~sv|I0hxHOEalMgF0-q+D%U6nXzhY+hA3gDi{YWeNv95r z%4I$|$ct1fIk@-1Ao(~|k@p#~nDa&*=l-})o)5nXkHF}Qz@6wgM4UKik-E*S*NSiR zaj0ZG|+a7-SVdY(dAbj_`-`%}?x8jGKJ$n{= z2Ei~P5r=0|wQk*e@4cs7(EmZX<5jQgw9mlp3z6!(9 zqep-F%U^1>TE!LPCP_c7wq%Y0@OP-e`!3M!3xKmeX)F zTtp{ysQ=(Mq*rknT6(Qoz8sr^l4;Je`0d+28z_q($_@KpQyix)iP!a~C|*bFIft&} zJRk2LUVes0;2RhL=y)flIz988ov2jtOmfmZXOBxqlbpSn>a+>n@KvlZRXo0mtmE)i zC?EHsjz9V2lZpff1qHqG$}5T$KJ>=`R~>cb0RaKZt^VyNKT#5DSmAKGhxiYJ_YZ|j z)6&$0hPres{CiM;;DGl9cXAB>1m<|5Y>|79@W%_}75TI--+NS)Jr|4hy~vK!W_jTL z_?iTYws<3E zP!*fShdN%G8d#nhgt06+pg7sTB+*cqs7EpmN)qv{e{q7LC|;i*r-PJ}YA;5+6`7nk ztpXH$ev~*bnlU#@;QdwZjTl_G=Of09{B3FRdhT%JNwS>Ic3TeO39()#&=r~GNe6Hir>!Ku4TKMZPq1hNjN#c3dGh4S?N zW0ze=jM{vB>eQ*^t33LX|5=cihgnKgh2Qz3z)~Zh>p1qgUmPnc;9HOrtpOz8?q0RB zf-@19`_n?i(PZ2$-%*-*glwwteEiNIG`|Cnz^IPEkq5&MKM;24{&9yr1`D$CZkIpk z!RT>IV6cDzlX2xF6d(BNxAkp44jnh>R6od6P5(dooELwZm%YFzIzAG<3Q2bVF*{04 z3Ai$5$ra)#O7X5snHMcEVil9N|XhB%4!;mn``QA~4O=BwY)hdO@k+SS6D&%XTAZ()07BKyg>J!=;ZQiMLl z-(nH2^WRz6z`M13V@Gv{Mxx=dsn~l-xUS-K3MbS z_s$%x9c1m#Eq|Ah@KwAsaWYjDUj;4-z;11T3~|Lvxvt<*nmIt$@!3%VF)I@Lx^aK} zmd}%4z$0*PM&RH>5r@AWap=KtaPWaJcq{;3IUuJ6)1D|pqw$V;XYe_J&(Y>6M^1`B6`0a4h}vT-uplpQgT3(pGT0JD_OZ*l88z~ zD7d$XlYEn=kA`_pSl-^}cM$ zU(F}$)(y)vA5mYWPd*MEM-C1nMe$NllyWl>pBb$IB;p<&=lS@(^JmFFDUZOgBGCO{ zSkHrD-4BcdUH6Cf+{Zxq3MM~k{*x^clIK5rlog&{rV4o}-j#^M`sssQJp6q8+S${M zmDBz;dy#ZZ13K z1196}Qb^4)LePB`jA7~c=O3QiTlRF`QwAl!E_x=sWy9RBKL40L&wx5kFX5V|s<&~y z^4{Dh{r4?-2KT(>@A9?lIGfVEQO7+B-e1RgK7PyR$uHm$xHltk`uoYJ{wWEZ#`wKN zH{Xpv_1*Y)zY}-*ALCB_L+r^%Vop60ee&U`Qx8SG`%u*BZ%3YbFyhn$;ivBl1E(gA zJ24@Yfbrt1FbrMCzxwpkl4qi?tMC)zuEIZDxbUv`CmBS?=`viuwcvNTPl(EWa8K_$ z40t>uzDksuraIa5re_5ZiVm}))ZY0xCONO0DmRsK?vD@n-1tczfp1m>jyw``_~B^c z&_hv2zRfr$bK=`k;P``)NAC|ma$nftiQ`baas;!T6WlBHPh9wq?#6U=EjQ9aoFNO7ICKIgkq6H&Eb;I zj}hm^i1XtlupnMLFJ3!8K?fEj7{L5^{k%9GuU8pj{P|@(0{317IwpjG_VK|)M@A6n zlIh6^0^R9>olgG_hoRlBZ?|ayt?leZ7cGl)&?NSz382Ts=uFf2Dg;VCo|2r54SfdL zNA1#QACQjc{3-O>m9P4IfG@uIA~z=|F)>lmar9TgV*2G36+PYE{o9UTxpFDz3Dqri z9B)JyMl>SFt$f?J7Rk6f6PNSxEJ!(42Dx!J!|KxyYhj$0k)Q*M67^tVk^w-$NyKFx z=l*z~|1|iwJOba82q+@nmKg*f;_c~y-I>9lR|Znv6x^r* z-D!*tquN)2dEtc@NO>`$zt#7@|NZ?p$$7v0!F7p!rSphcYEwt zzoL2-8aGr`z5DJB4h-&aOC5jz+&OF~gga1k6^zYIO?`g!ZGQ_LUlgeV$iZ2yA(C-O zd8`PiqhX)EhAbJE*W%B`LVORiV}v=eBI!6rWaT^`zwIZ&-^e2{+9S|)-#E}YF%&@4 zyT&s*k%OlPQZh~=j%2*ert{9n52B^5Rf~L_QgS5Y&~YE;<4C~s^74|Bk`y(^-awB% z_SlINC;G(ns>fF;^V0Ey2M_-I=RX%kQBiPgCsbZuj@uqTb_{v+brmiw+_iJ(g$oyy z+YX}R?u|N&iz%t6ydL{}4y#&G`9T97FbgHZ56qA7TM(&Q$ZT=-{AdQ5D$4R7w?!VU zfsT7CxKgz;J5H;>*K-aSZGMtR;F}NuMZqaC@5~HlqzA%UAszSjRgjDW+CgHZ^Kl9; zcE5b?x#xm|gDES=7#SHkZQ3+%*}e4HdCJF2WF0?${`{-2z8V%5ru+kdT2(QO9s6E?VZexlR!?K#Eg_!aZ#MOFjiO)qXD!>!~#rddcgGN zyjXF8JgbR`P0Vo4iIZl>NwZ=_Ff&d&BUYLoBTkFv`vKkF)8Oyo5x5s3pqMJ&z6z3Y zmXf;y6yU40TG=EgpnP1J=Y)uNr>eV*3?KUA{e!n@)293GyHCloaqz<*{;;mD?yHL* zLdXB>$750=ulwM5^^r#&*}i>y|NHbgbLPw$Yia*FnHn>Uh&q?ynPBZ|T&!ll~oCF}>3Nzy+00k!z ze~0JeK72y_Ry+cuEdm4TI3_t29fz+1P_F_V@389t>Qx}+q~nLo61Y1$j?lrLo;Pn^ zLPCO~=7E8Mk3IIQ2h-q$v*}Qr#|T#)-uloTkIR=Y!{bIWPKh~GyC^qj@zh@(sI7&0 z!cGYZJ*l}O z-#7>e2!Nm7zXWBFyD2Y0_Z#c$A>2sGv0)Ij8wyS$j+4;zix)2{7mwUQPP`UI3YZ^@ zy&yDTZnS!i3??&a2|jCQC|lt(WGj3IJn<;?v}pA^Uc4QxemhDtHBvn#LIt=#K5~zY z-NwC1fS z^_!6@!1M8;1fO5SBXCbf;5Kx;yPrS)b?G=o{QWa0=03*OOb5vq93h%^d6yA;%r^X0S zbHMZQ!Nbm9G6B~5~bfap;8Nk-%+t?&0z}7#? zJSU1(z}KteS3i62X6rd`@4*aMKYn|+x{Y_ui&V{HOM94z%R0{5($0?2%tDgx)^SL= zI6GPZs1OH=h~q#Jadr?V0jN3P`S@)-3;q@!fqNqYJrl=)?g^o687D+s?yN#JDr|&~ zL(LujZqTAu-jlN%RV&nA#Vj5)izrz+XpvCC0)4;xzxJ1(y6eY%oR1HoPu58MvhyO< zSl~lTG)cHonnIO@^JBGOt{1di6LsPWGf*?`VS0j2f#>5R@v!(kc?3p91iB`&MftRt zQ|YflYL2nn6)3|}a)!&l%Vp?t=&{2xst>935DPmGSy&n3*QMi^K5?(-%>J$ZNNeS_ ztG8blc;(9FqxDsk-7D*W?(%bD%kJf6J`i#57KT{kgLYR6bK-Q2c*g7my~3;nJ(!uu zm=>>9;Q9DnevbUd@d(_#2((WOX`2w-IzFg1Bd{es0JOUNTU{6f+MWJw1WXmwkF!w+ z+U)XzAgk127TZk%XiHVK$TS&MckiQne$v&C-M$Je@~q#e)-U>(4^JNSyf}>i{oq8~ z+6DiLJIMFBzMgX!xA4WK?!H%^j#sDViR@ZtW?|! z*y4a@I6d>6yx*ZO9uL0HhUDL%q{b=g>C* zyRP1@Yq06+ty(uWvCb;iTZ9I)rpc^nOj9=+RRDtCB-4=gHRR(I%}>rB-&Q(l@$Yns zniu~up`|+O(xt%`@8H$W>YUO)CMfU19k!NC`t*aoT@~-zGlQLi`a&o;Kv4?odquD% zKN^Ot5OJ5G z&Z%c=?lLqw4N!B+&7tX_&Mtuls|cDc0;HVeo75a4UibCsI0f!(PhI6Z|1JA*wxJK> z@i8mjyzf-|j=x>I);F@(uAOMzhF5WoaxvbEJM_Ks?tTv)XBLX5zL56YoF1)acrtNs z5m(Z1l!_B?M5&3_B2@&ka-NUh-N(p(8jrwTi~!~1ka9}N8{w{G1jt#roRZ5~IZMoK zT5!N70+x@Hh{IYjF-XT7(^U0ew~ixn*b?Y;WBHQj)07k&miNX*Kl$k0>s=2&Jl%~m ziWQD4mppGj)U@I*FZmhpIiqU|D-W0ZrFcXf8MnM#)8nE*#}y-GDi+^Iu?q1wJ@O6J zhJ3$@F-lFm&g;hqj5R;WBk;|LK;wj9;C9K!2Q_B~f=1aTXGXcx(Bv`7;gvVqwV=ta zZMI3R0PV=JLy$#mm-~{Vt1V8BlCXSv@ss+sQ}dr5r>J?}AM~{=U;OO7t^+Gy&ij3^ za=!5Cu;w+dUHbgfQS!-I=R!}@t7*|11}eejg_@LxD+-PSth^^H9R7(r2ai%i!HHL* zR5I#UqtPepTchL`yS&xQAOTC`?|@y0=cWm(TH4bUEApj=*bN1&IkZK=>fei|3gmygAM~Ygj#YL ztPdJ3znItOIN4FV_N_-0`KE(4Qy)IrTkCbzXgP$A&xr9fp7pHHbazehvQw10l(#&S znTm^oWSr#trAR*l-|~EXv^-$`Id}wo9s#dK`PbLwL%0bn%4h5H+0uM}(CIROE~f#h zH*)Ypz@`I-tvYPi39vZG=bz9gH@x!IrSAPjC4V$!{bo$*e;K>?7vqdi?(FlMK*z5) z5Fbd#6+;|Su88;>(Hhe6SEJOgcy#=)k$wc!oaf^{e^UI0JOZO70<^I*Ey`Ec<@aU= zGctmE(}O^dE6|P8(BsngI1RnBjzhQ)6IOOGnsuDQeeuEvhxabIc;WnLiT*&JL&?XH zl`H*Hyz_A-6Zh6}%w&>|!$MK)loun${w31yFOe#YJRct@*!&!iz&9cS)L8{Ojy-@B zu){J?6dWy9dVtHn$D!?UN^G=C44c$z69Lk2&?WPYh|1UbOR$>pXw7taoQ7V80G(-N zXoi#WajH>)l)KGwMaLsmEFX_xj>-!We$Pkv{W(JYXI6K}{qe8!vGSkIBQSyyfR2-t zV--QIz-TIbJJxN&;b#2*z{loKkMJet*Id`jkJst z`$f37jPUZuNz*AeCngOWVe~Qomo{#^1{O7}e%fHJADEYXzj#Ixw z=(y7FkaYZ@-7Vt1c7b%9iMUnhv}r-RRR{hqqv*?D`Zjc2sZ{Zna=0shhJr_GFan;B z`|=_2d+`X2stAxj4riQ_@f-TqdNr->wzIiS(s775={Siv*KyxIP+I%rUI9egM97=| z$ou|WU;g8rk5dyB5^+V!q2n(^Xr8~W~E>F{~u?1E-L)JNh zSJ?xXn*Ga6dQfihUuq9p;R;>h3}d86f@SH^3Ki+mpv)c#N^KD(*6l`6{I2-U~RP=9ut&F;aNJ z1JB1t&EFjVAUp!TjsP-of<(MCJrIzN)7}vfanf-(;A~dYF7((mfTiKGh~J)$L(1!{ z1}5d!0O)v~EpWdb1nhIT*=r93yB#w2;NA9Mi1-d!#F=(O#63C=5eJHhZ!$3v2c+N_ z*D(=itTp;GDNhTmGzF24S6YLrY{BITnq|q-O0)l3dvKL&-1_t|u+|y6+8Mgk76=_L zF>04s{FggJR;5RPo9TGDJ#vXHqRbjzY6*jmlZZpdvyu!8;jOOJi@vl)L)Esbs+}D3P{C+$Fqb33! z89@Xoc!w(hK*u{#FfMNcL^|GO(?iF5tZotat&T&=4_E_gZ2>pa@m;nc01@x6<0RsW zjzh!;(ec%(y49(MwQ2tAOaYZ9sCnQTlRqenQ$fd9L(`pM>s{gN(;1cN;p;NOmpg)? z<3%ZANt&+07Kmhgbp}hum3(}uD+-ho_Q-Nu#1dJ@i#^GBUTV;yL_KtTj@-qN^%IYi z&;|>OHr-uQsCSCjs0cbPpkuZ!pGozL3jjw9RU*Y zb~z0v5g)paEB^R!eHEB0imw6@AFhs*uL5hO+8nUOnVT;o={LIJY!Wim@`A3aY}%SLwEBx~*zLF~@Pxj+TcOvDGXow3xLm7O4ra&4buM zgBxvwMGJGB{Bc<1bryfH-{QZ|3JiN}ZgyM!!A=`vha~`PvjhUSkzx+2F$Wxm@|)@S>roPT zB~k=DANTd24!<9dz^IA9fWAtH!vG-Sw6q6R;hn&y?J}#oEGnYItX60<3!ud$Dm0s< zX0zA`ECL(NV!a!w-Ygw3>A-%oj7h)Wq~B-K?=kClo3uO4Zg!Y-V4In-HBAqy(+mKq zH^b=9kdHSR^ zhh7V}r{k|hih$?iqvmgpe-Iu4Uq_(L6+mEDWwx=h!@#iV7;+sUrP%Fe2}<3O=GS2w zOSGl=DYT@iL6cFV&}bAI(=_$Kq-JB9=71aFK$@^GRRnvDGO5zuRB3mrw9_cG6sY?zZ8FgwM6=J0)$H=kKUpJ$=!9$%<-G}`~wTx!JQL{Hi0DDre zvnxg12@y|LZ%gsRSd+r2CXzK`YOD?$|(7p;~#@Zz}FFIbohe?yP=V==^KGn*JRN(nY9d)#7GmH(u5`x zwpUhRWIHUULABXNZVV*dCiMZcdcO&%YSVyUtxcX& z6xGgD)s7Uu?MbTb$zyjJ)w|MEY?RqyRD*3s4U_d`4X9>_n?0;g6ets?WSosjZdN4; zU}d6aS%Mls$4Sbe=5&lqoLCYM5f@RiQiAk6NxR$>xY`!7+8(;f7P7>sD@)auB#T9f zn!*J2;&{LOI6sVq@K_SX{uIP%K%UIvcp)cV$c_^i#*1^K)w5#MnCEnF?!#s{*@nn( zM60e7rFsKNy39LqBA70NsZJcAa0Mgk4oSNe1*gs`7@^?kjrG@vu`h;?!N}UxvP~r1 z_2XFB$^CI(|LO4i@d%8X2sAnjpuw(hlxeW(fV}V$A})bOlL%xHmp4|%-pXc8qe%^D zV`c2EykBOYNd@+%`GGygu>clI9WV;}(}Y^1hUA;1e0QoEK*Ygz=(x-dqYCVTvdahC zQq^u!gsrK<))cYYi_Iz8HF2udAYRRYsp84Rm%&1TUSpKyn<+R;y;aMw-X}q`REF6p z@oH3#m&W>4K*tlAjxR|P%2TyV)ASWa-I5du3SOKfkcdOa0gk=DrIX5-AFly*wB z4VNY{$|2ct%o9h=I4TY+rJPpukikMDd~>(oBB$geoTNYt zIHBXT`wvFS$8Xee?vMNWkB8rnM_`mhK+*9gyPn~tE`1NRc+DNE?%cjY%R{4-zG! zGD%WqHOUai2qOhxVw3C?=BPlyJvxpYoD>`)4&bFAA1{g>TO8+CnxHO~6`YB9l29z? z-K8lK<>OFoMapq7pop_;WCe$a_t$YqIqA4NC6`xby4#CWlkq5bEjg=1jM0E8v6{DH zG;hYJUyo707OevCPZVE8aa3?XI*tXL$|e#oAvebk5)m3g_Eoq)K1%-P_{ZQ8@O1>5 zoO;mc&^6l`O*SoPwxYQeCOJjWY!(=48Zd~C!&*^H6(uX*nam6mO1hbUBC|DBwIylH zmSo0ej45Ncr1}BOYHm(aZbWeM0|3)<)i*_1wRb4J*f%<$^*5u4J(H_L2vg;m;u(H^TjS%iXD zq-vL&{a4w7);K~|IYL(2gICytS2{wLngc3K{!5Jdk`$>(Hdx44DL|gy56p!^zH?=A z5?DS?$vE>>qSb)b0eSji2{WPvoS75F@P3I^mt$5lR(LB`Lkj+K6gGtz`*P%1G*NlO z1NBsKk8)3y*J1^Lwkl9_((#v~CG=OJ7AxQS7SG3h{l~-a$0IOGBGBa0w>b69&~cd- zyB4(CB+z0N87K^gj+->#W;%WVlbj}Xt(l>?@agRj;`)s;eyS~<8*yk|p zb?Emx4SSr1-56c|d(#6LuAn`x;N8y9UCz**E{x-L$ZU6pZMBEi*h9D4!m90I)wb|0 zws4F%#>pB-$W~`4sBw+knjW?-BYbN{_-1G5CTHjdX9!sD2(EGjSK5QXYLow3OCS^+ ztg!?xPt!xki{n*rQDBQNw*)M+1fa(urZ-E|bZDzmYBZFj>Wh-Kg-NVZ1tWpu0fC4! z1y9gq11}w)7b^g)$S2StYj&(OCq{yTqXQyP)SOlc!DE51f+Lk3fq{*XGi-0;d+V*(J~}(`FajY+}1rXag2at3?A@ zZ?*^oX}Y^o#Y@MpOSwr^@AN<5^sjRTG-L!dW(GHn4{4kb+B9)o)BRzfp%3>(G(H$p z|3F;*gNy?Y#Do3!$JgE;zjtCR*fk+;=lIy2nQ_}QVz+_Jm~H71(C)3San;Vy&Gz7p zz!row9BX`5q%xMJh|7|NrO84C%yGa<#WhP{izf*%#F2?J6FknZI6(~~g=RGilY|1S z`XLg8yaW`Fij1wJGyvkI`p+~Ri0sbmE@ z-ltxL@^R*|nB-a%*-JtBAUyG1CIRXBPP4efBy2Y`wt8cdHl}FSr-&O;B~X>3B`Q;N zRjGQgF4cc+iUF)n_GhFR*5Rbw28%kV(8MN$n?!ths-&RezgzLagQJ{RB zb*xp0k>aIiWfY?aJPSNKZwr*%bx<<2Ou%n?bHnL|rWAth99X77O}y#G-f|VC}RLbaNAQGv$JD)Qr0q0VQgu z$;?bLC`?Z>D9lI=1k;SydB+$Crlo{{cannv&&NmN&xhZWM_^P$pgmpN?vimz?Z6>| z4m+b0qYZm+3LREWr&ZGqY%pFJih<7BU|Gd_ivSK-`?B98*2?Tb^hlcuhulO=d*R_=uVbkzjLXIM^h!F*6)&7|&Rr!Kg|Pt4t4D=Nh-xH4YsO z(VTXb+|&?#4Ociruvr9aiN(5Ng_c=@NwT5ZB;3$$P?!<`NWt?G^-RR$(P%|n5U*Jf zul9grH}hi!hG&hwd?3w_k>a>z%T|bG>0zm zFwY#SFxN5;%(h-NjUX6m~#bf7a`3%W46q~3HL z(c{t{bZL8?66gjl|4x^I=y2*mt3wAGZ4#)r_ruJ(V%3=?Cg@5nITi$@yav!EEk zE_pf>eoKu}wZ*8aPSaGIG&N?S+M;DxbsJKJjYessQM(?b>CjtzgGs;MWMG}JXrmuA zFEks#S_@_}{a2avV1*aU%zA*L6k?glP+>BZW1dq6vzh>#{uCRvSbWdc-=|9XDcbyG z9dc~|u_nESWGm1~8d*x7tjkK07A1>raGWIJ3_F>iWyndlXVfo>*TY4bD|;z8@CKdA zXUWXK))Q<}lraknf?@}*AD^0_18*f>=gmYNcq3M?!1M8u`19fSttYXDJdk^9qH#x1doLssscm?Ig7qe2uL zgD6QaG6m+Q>T`@bH#kn!;|$17l1VgRqt09+!9P3Ee?g*t4)X5A>);GfG#xt!q311u iRQ+Z;elvgkRk?5N8_`<8^YKyf_r^a2kHAPo;Qs^XBr-7o literal 0 HcmV?d00001 diff --git a/branches/WOF2-3/OFED/WIX/dpinst.xml b/branches/WOF2-3/OFED/WIX/dpinst.xml new file mode 100644 index 00000000..653066c3 --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/dpinst.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/branches/WOF2-3/OFED/WIX/ia64/Command Window.lnk b/branches/WOF2-3/OFED/WIX/ia64/Command Window.lnk new file mode 100644 index 0000000000000000000000000000000000000000..662fc9c70181440afd3891ef2dc96974c9a508d9 GIT binary patch literal 1368 zcmeZaU|?VrVFHp23z$zKRB!YO( zAi^LY@WB6q!Yivxfkihs7_u7qqL*5c3bz|1dep2ItUDQ~ zD}_N1sJjA)L3T4RgaWY)5Q72$L|Xtc2!sGJh|dhf(|@j;BLJi!Zc|9fEY4;Ch6B`_ zF)$~`!0ZNwohm~BLlHwhLpqR51X}CHkjan(w6qu~69e>mCPN-D2;3M%faU|OUZ5Hb z_IFTzeu*j;1A&$gf1nCX5Qyjv0)}2bFseb}g&yrO4Cqlg{6lBt_%H$JRbaMQ5CQda za&f8wvhPb+zT4%`SmQK}abvdsW=Y1VL+4J`9l9;p+w|hnligj*3CV-9GAk(00qK=M e49e!*Kz_O3L8<3Vv3}cK^fs;woUt7w2Lb>d1D+uO literal 0 HcmV?d00001 diff --git a/branches/WOF2-3/OFED/WIX/ia64/devman.exe b/branches/WOF2-3/OFED/WIX/ia64/devman.exe new file mode 100644 index 0000000000000000000000000000000000000000..e55b0f72ffdb14314ced5141ef3055e3fe2766d4 GIT binary patch literal 129536 zcmd?S51d?OeJ}hwe`e;)Zoo51urprD`%JP)7s}NML_0|%oSj|52+@u)(uH#I1cENy zKqnA!>5cRxyM)ynVNfg^itPzdyHd1+^4hhf?Ma|^1%2O9?CsJ^drtsiZSB2-*t%F~ z?)UdQ^Pf$kE&ATi=UpYq*>leG{GQ+cf6sH?eOZMJA~Nycv13HD_?v$m`SZkoEa3L3 z|JNU%N{=MJk)74Hd?UMU?3x=@`G#Nr&<)$KQ&(-j{`z0vt**RU-SFY-)iu|vkzaYA zy6)F^T>aKlPU#zH481j%{?BiI?@jsUf9vl45BW=Qz3%RGKHm8KX>xr^J|ov3$$wU^ z&3yEGEB|wH-Pid0RQY@BHCK)Cn9UWGF2KL^1pPmiJ1=bhu1>3{U$=+`G@`$Ye(Ndx z&HoYMm-tcmPbZ4wFa9sa7yJ|8Zy@cS|EvRljz?t6uiJ=gT&w8U{Ac4g@{8)Z8u|RM zP^0lb#NVz)4=@p$KfX?n0|G}8o!)hj{(aucSnPreF1Yp9 zTfx7%oLBNZaOU7I(@hTUMXzwWB+00^+G)F;rT-NTw?qKS{?t)){Yu~{I(!zY2nlPJq22i-?4BJDOR%@ zdB^Z$?D`IkWyV*Lm%}f0?>37jjm)AoGPshjDN!OC?jwDpmA~(`J)UJ+iv!R0efQO0 zKL4s!i=O=l13!4vYX{DH18X@Q<5ci4A6dnBr@dIB_Y253Qquvme)1s5Yfnl6GD77yXItxbID_pFgd>7x%pw6)O<1O=+7_xE}^d zN+i7lxS!jXqk<1yOj=&$9rLHrnb+Vxt}DqYP-B25aNmLHn9R`hJLXfAzoyEXiBys% zcT}*51G&}Ce$1DlJsYQS&G;QBZ@J}ao71*U4}l)0Lz8`F-S+a;q4>wQgh^Lx;-?Bb zoKPAK_t)qhX}dl&mK($%CU8jW)3&owvz?&M@D9e_Ls@q#Q8E0%`L7+wjNLhEt7yJ4 zp0A?WmL2E^s!GwQHklmLY5#_r?ooj*(UoV-E8~K-_G9LOEkUjF_80qdgFC*l!Pj=? z)bL7Mo6L-Bz$cIA#WCz~W>KwAuf%v|@WruX#Z)HDsgyjg;#UoM8KNtv8u;M*SkDz{hOfLT4Erd7`y>L^z!#6#z?Y2IU&-o2Yi(mL zr*LgjpO?Kdz0#(~b1IE- z+tY-1f%(y<@tg{4pkMEL;Vu?I&wW|&r(vZJ_77@0t*vV1=KD4E4t^i>3H+Y-8|%gU z3=jF0W5+Hs@K3DI!g?v!_aHUkvzzO+iWj^Yf?y=PEhO^gdYSWA`@G%|VqUSvH8*YN zD7Q)ZCd-f7o(6o&fimZDmM@{dU4T5%2(J6mdvV{UM*&|iJ%t}F+D6%`u2{Y>Ucb8+ z@>JJM%+K`fuhV&HyEZi5;P;fsXL-Q{{31W{e%(~G%fFT7YZR*+;PrZm9ONbC4e8F> zV4q1m9;tqTKNxznJs$YY4S76)XP$~_yQ<%nQ;JHE57O=1^EI8<6X*5UT#N_!_H9wd zGkdls$9cXG+{F3=^DnSG3Vjn$lZ8IfHxYeVpLEitXn`XnaTH3G{F9 zS4*C(Ql!7ny=Ai!{u%{8XM^Qr7lY>$iyz2{{`T&JKBeGmRI-$2GykxDOga>18~_UV zJUWsHKwqmeWE9rc^htvLhkiTH9x-0PUdVT2 zOZZL3uZnz4yonC>g|rd!F;s5wTYJ4;3<3Q`MvdNM+a6V@pjOuwxAs?e6m6hx)MoxR zNp~HFe*{tN`>;75M3Ql1+V#i7thSx_wjpk?i+rz>()yINC^) zzVL-XU*><-Z)HV!Z8F7=Wka(9`&wiB>v)Cf)3Dx>O85|3tNhVTj#)GJ&@NB>5u53a zcVMqQ<_E_c!Sj0~{f_mi7~omb9tFMjNcf?5y>y+!>jl0sN%wkv<_8CYob~j|*%VCl zy~_i>H#Pkqyr4iv0!0RyAKWGQ0k^w;tl|dPr>gD&9jrgJQiHy)zD)^z^GshC!xm)y zsX@N3n;zALzNz{bfS=HOh{_2U_|V4=gWjdSyQtu7)8FOwyV_;!Usc=sbQJQv*t9p$ zk0ZD)+^ai^?E~n0$(tJV1wUS7G@Oh!N!Aq zj$`I7?UdhyhxJ?ed)_mZ3x4#ww`}%fxZekRMMn=`3;3Ql0AK&5e63N{Uj6vXXAXHQ zG}W59*q)l*Ah; z`uo%!8v?xo{#I=7=#2Aj|B5lidB)0N*gLT|&hi7B&UDtY{-t|%#2>sa>?cexTqiUW*+0xf4kk2c#67QVF z{9b}RbYJP_cdW30^|j>J3r=kRfDomh#Gc}ruAj)i4?Or^qCbVJ>D88%f zQy9O7_%1o7!GDH6hdga&|J`N%7;?NV{(a=Hvi*B0QD^HpkqnCs|j`Ypw zzD(_j^kK49Rfm6tC&7>MJpKTFY&?(k!M|pHDGPqu{sqM=7{A}ka{QnNIfZv%FUL4u z#y=r{^?yB9G!|(K;AQxN)r;Vt1rz>Y@Y0lW+^15)KY8Y#o!}q!!zK6!_KC6>5AZmD zCj8Uo?|1r7ct|z)$N91KXYN13zpChyxyZjtmX0D{P#;Qse2Y8D`IiN@7oj$Tc-BP1 zMz>?2uP5}i7B+<$iHE9)e|^pu75duoYuFpVvj1$5Ztn-b!M_?dIlgizS|9LLF_3|m zc+d@DpPi@Pb($B^&wtCbWB&9 zvX%POcS+Odr_PC~x`zCVf6n~k)|AijXK0Snu7r)}GuHdz@8EUJj~``~_G10vPznCR z%ojJkkScyo);q=a8|%Y-gYXyXP5&Wfvp*;6;qrjfzew9K{?H!0&-{SrF`p~Xv%h7* z9~?xyhxJGPL8wMz3Xifs3H_g3@bwGVhR%nPtymwz-=1gx+#lN69uN7Va;-VPRn$hT zXuJUNREPgdk-xF%VmwcOK=`{UUw)xG{&q{uFAQH2@HNJBO=pDq=K|ov)pq0y#Izk&{~V0FT56SYH!AmEQcsTnpdgzqjcJed|!R!tzZT_&F7ZjqwoAvVK_Lc(OjU zyG=jP(_Q58csPb=u76;2%dS)Uml==%XVBFv0o=^u!#D2*jgSIs^aG z;rIlYdYm%jxQi|K@ka&zyu?Y{zl(df+7q0cOmV)o>5pKKoMkQksU*pPXpZd7kvVlXR)h6m4AQ&@@zdwbY<>UL zI`!?1udf?=)|vRBQS>_Pt&i~#KW)xKe?X0d?2lw}?4OY7QNgg2(C@Z>-e9G2tn69Y z!A0C(P&(`t)&u97^G9?28-U;MB~Q6A_&M-rYT+pI6Tyl-ct6CVkU!dod^zWTl!f~k zf0LJ2BglUk0q#@8zjhq>=locQy^rkAJY8l-@WKA1JN2#M;{AT{XFB5VS}Q-bq&>7` zJo@(P({EH%nLkNGbVB%rTIf5(2|H!>9XE0be-;2}`RPe9)3KHxhT`ous$tUvk} zG{~Pae*pV8xWN9AzHiW`ZNP`&06x8F06%4uw3m$29BuNIA}G|5e~j;BI<7GbaCG0u z{+zp-^M!x81Ng3gtQ1pf=W#r3g?WT8medC8VFIPd~(ej{L{9msf zFvhYj`+osYYcG3{teG!@|La=SR*rS*%7e*J8|8cj+vnfck&hLAB@_8`KhF9zE$cOJ zS$3o0GW?5KFTJwV4|sw)*8?o_(%?qM2g@_`#ct4BSIBqrc>N*U=k|P=X#7aNd42Wl zzVynP=-crhrC&h44e;jf2fQ+0YC(g(wuc#h{HQ*A)o-xA`T_KnTGpNamHZ&-myN=` z{2Jtm>6xP12P>$L03N1~1Ninq9(nvA1pFzPFB)IqkKXsc(R%;es5j;0eV#wPs9m13 zDg75YkObFBy7IF0Y2+Tpb&}SGmYcmIzjD>9yF6<^ThyM_%iAvpzdRPuk&zyL_Pu|F z{vmza?Gb+^Jn)aTuovR55*_9co=UoxxnLvn7;^7 z1V7XX{1tG01-z(D_8~~7fg0y4{bW7&Eb5b+Zij+J{p5uj^!vVt@&2L59$QC8Euds)K=K6ESjE6Wuv({0B! zlZamzU)y{B>hQ4x?jY6s!Ovr_fS+A+5&n$m6UIlD;V&4VcLD1uKprQ}k7Iq%xBbF@ z^&xZJAf^}p5d6^P4}gCocp1J_ef#FzO8W@xiSM(2v$!4fp~-W=KMBLGMDkOcz_n|# zzFwqTAP;pdyIQgQBr948_${0Ze1DbeH|=~u81~ph;a`y-*F=0ABp^Q-lv@Fh`M?>w z48{I6Eqav{d{)@s3E=Cy@8$IdMiuZeKO|*+;bX8b{y%MiK3HV=f&pBoB6-E4@J35s zQ)RA?ioO^B*UIVJynJQfBY<~m`GzB6A3SXylO%FF<_|R&>eod5Nm&)-t885#Sxe^Q z%XS%6)<>`js4p40zCv)DX;zZu*o3X>%uj*ou0;KS^Cip;oG$`@ihthr=Pmont@cVX z)v{f_f$<~!3Vi-;kcT;R6m0Js4?*9T1fH+m8QVdJ0t5V&eKY8H zX$99E{MR|Y|Gi_QD?-hY`SIB(&O>%`yd~=zUKJJI*+dmAM}n3 zz1bhC@%+(zw5rLUAuXZLVLzMmCCcnCci3Ns7p@cIf38^%PK6r#gWmbs9>BhJ=>y>Z6391xY^r^p{Vx(GL}`fE1MRM|#Oqv%j5>K6LIx&h-Wqim~SID|f& zO6DOynDIuRuTlTrGzfe4cnRkElW%`9MUSFCg3c||k+>3l@=?4W?EFo-(LM86`h`Ba z=lqXv2*z&lZgjJ+rC-cY`urz02>kI1=!^RC#z8yGmZ@<6-=b6LO4 zPcHC>eh_!icK^$Dpzh3ndFKlmd7ke_@rqUB`Gg(;Y(uC2%K44P{7MfR@{t+8&+%}B z-=BlOVC9DN;@avE_mjjN=*OA|f3U*-QwXF^T0U)oJ>&k8Fj=FoW@cs!%T@F~hAH$_ zvaS4q>fskh1N?*9S%{Z8-=Oxhf4JaaKB1Sx{wmgYk%fHJ8OLV|_R~zNgDLbIAs?~VtVHp4M*52!ZCdyb@-6wT zx>-WK$pe1izabv4>xdsDo&-OG9_2pdbDHry#*gCp8lF#9KJy;L+Y!yeaZHo`(ZYB^uwUvq}dM>!ZdXCABen__aX$X>&DE* z1O}d5A?xL-;FSIi@{1ku8qeR*52K8qV2OCsLjI_T{3haeCk}dRo`(8}ug#$T7sL3; z`MDifpYb`=k3O4xmzSE`dERp6{>^k_eduR62l}I@pTV7J<_D~_27XaY4@G0#kHr2! zxJ=Q@i4gd+7rDQtcDkY)0d7NnJY$r+Lva`P(fAJob}65{D7|Ez|4@?$cd_~$a7ydSQKm+nq^8tj?W=c(8;UKROY)SKWx zGw8PAJ<~m31^2Do+mU}o|66&p&-sO
P1{V@DR$+sf@9&PlWxH0$x$>L!$2Xgz) zIkiABYWBxP{WK%+Pm?sWc{)YK&m(@|=Ocb~3g~x<`jM=*{~`S1Xig6OSry0|*P|o+ zSHTu@3C1t%HTy1aAM17dW9wO%lIMZui?Mc74ntbZ&sH1QY8)a@%F{(>j{VHJ*q+eg2F?Pcb*^g zhCM91O?r3OH^TEyN}l%$iAKLrpPRje{n3Y5ewWBEBL9Ybca+a9f0jzfslwliu1k16 zgB++|vb=<*4f&Sw<-VZ+FYG_pSJR9S4da85 z_?r~l|Eu&R?0@M3?!TmSZff-J)Lo7*CK9)AabtiV^hbYKsB=Htt;~PvY{ry+oq}&5 z{y_ib<>{3{C7F~D;2d`^ks7Jz3|6sM-U&7iTDuox~P)! z0A{2=t+H0g*<^UkkLYKN_z`N#o)h~AdkuWm56AXz@xJpd(vq%>w-4hf$wx{)x!Rk* zoo9U`{4Vv#5cuEaKkd*98Mh@53D(ysa2h(E{n4D%6{b&e0RBT`QS{awrl zejfq9Q;XlnhUl3!(epN*N4@4Ej+ZM+ITPqF)W_oFZ2+euURnM3Ij=9Lp`Wd+PXiup zj-E@|*)7O_JW_6~7xTR*z0F875cU5i^RYd*c|P$+$3Cz9_r`oa?6r;h*JjA;4#dCs zY4|rrj^D51eFVktX~Nr+e~9Q&){2}@1Ae^NFyfi9L(%wH@8VOKU)F>ABk;}RLw>-I zvYzm}-=&h^Gl=GMFrO~?@_4-gv3v`@@Fwsn`n!W3pN{YBqQ?~GL%$#J7d@Mp{Wrhi5k{s!S6 zQkln-_1H88eI@I`Ows(&dNN}Vx5mRQ#rhEO2KSfJ?6{_gJ#aX`9L6Em$j@Bc%r8s-=pe^iF2|Ej zg6)&^=MmitdnEY*$oq84n}EFf+&>-JryT1`@n=v^1M5h=TKEI&83TNhKd;7+|6Fhl z#QQDyGmBgwtDk-={4)pgo0(zzUKW3l*N6AvAGjP3Mf@9$*LolR2l_Al;l%zeKG&=D zS}zY>4`55e zjPyTNc>F}pgngai`RiJ2Y75=!K)<>}&=;-&{Z5Q8;1}@IFZ-j8+JE80Q+oO5N6%K3 zBVQUF31i5g_tiS;Wj+41@cRPS%LP6k^FO;{Mk~^G0}KlJ{$21x2R?iQ`eQu4(c2KN z+>Q8X!vekVL+!UHs32U1zg1y>U^WZ;Oar^qH~Jt$CFQJx|5LfPg8oFufWKYRu7^Ly z@<&zhU$U0mN-HZXd>ZuQmNlIWv=X5nHj^9l?tk)c->ubYD@FZS?!)qV16%rE+`13xb2NB;@dTOP)I>Q?LY zgM9)|uyN0*6MT5~VJ}$^&p&%raQJ_Wj?n%;e|X9g`b7PemYYG!O}{*muU@GQIR1C^ zqBn>6)3u}A|84xyx3rtJ@uTOT{p?HET<2|iEPnZ?y@grr*VZUs|H4Ji{h#_$_U3*E z*Z!e@2u}}Izxb8x&Hpg}{CTG;|EcTx94rt1SP(<}UpGT4%XNbvYfNwTP2g*m`xD&Z zAU8qw{sE@ay^$XdWpCc_@OL+L=36`Ir!?TNmff0O=?y>5^Ow&IlVe|@ z<%-PU&1EOH=hI&CCEAMovGL`LobNmZd?ZJYzW3}^9@AU+4fzM)BVhht!|UJv73^QA z-1p>1PY=HH@)7N31E6TZC;#Mgl}BTD1HS&+cgr#5q6}Mz@G-9Mq(!61_^@k&k5R@4 z`;%6A9pl42C0{bk20lLa62bqj7(VjLPqpxI|H}_l9{uXeEqu6)j~5spfA9+Xqk@mk zKYVZY=C5?%qnDrXloEMlea!a#-fns1`_P}zx24B&tPj}#nq&RsxAYV2BlJTV%P#UD z3iVF(pG&`a81(q#4gUxFl;hJ~KI^x>^6dr6*AB<0wm7$)Vjpbq%jj#^zvHmKJ*Pqc zdBe{GKg?e#p}(y6b@IXUYf(JK@e=Y+P5+msoAw0Hbp2SxA@qMD{<�N&ZRv&-y<2 zpH9R71V7f;|Agm-_@;aa_9b@&@k7)9ysY7WlGq=L{Lfjn+BcE!hJCq=>4AQH!3VSl z{7vTw@af%(`>^N5=~VeX*q_KB8PndAgT9=B{en|7nM6E_`iG9k+!&8H&i$g|e?IoD zCrHbv;)9-aTAC^b{nEQ)t)|Uxi=YC%vzosQ%4~pMh zUrLR!zN-S>Bhnv{l6rgHz1kBrs=o0o`qw4?3hO=b4AVR1M)`HDC+=}ROU4hle?2r# zwGSpo*3rz{fkJILR^Wf#pqy#B>Zl#gfp#U1b)^b7NI9sar#Fn+O2jh6}v^scAM z_I@-L*#r28&evgY8vZZlmv}&z__Vx!_p-s~I6g)GCy$)mwSY&id&jp%BYz$E@|fR5 z9(aDp=h)ZaAC7W-7{P--BY&4~Az!hkOY7b))sNe!5%M*NRX0efW=nha8dj zt6TnKdwv4ng zVZMX@L#DsS`RWyEj{o@<`iq}ndaKRpmE{7*_q<;O>jAv&{SMGa46g!w3Q>F0za4Dq zBWry7D%L;e=$ix4KeL>FA@*+_@oyIi{*1)8Zd}h{f8gPCGVAPHw+H$G`d|g^f&Rc8 zO#jcp-<#SCc~Y#8-TkIrLH^Cf{BmFMeYwuqDdBh9lrTjse z-+fY1QS52Phjb0FJ$NbMB%mMAUptI^Bj9nl9)uh*;)R-yjhc{$VShLPJjmU@fc>7xx0fc??JflD|6B7u z;PZz}Z;KP}hrc?e+h5JsmhC=pqrhv;@qSI0`oPSN~lG5xn8{_Lf{ z*#G&~{BGC$I~()Yc>YSX{x@O$qrCp=vYpNKFLFM&cl`nKi$`K52#r3QMSay@g?wYQ ze$nS7`kVb9^n-zZw&BBnjv?OZm-W^(*mpbx|Mg`4OB;R%y8DIX%;EG~v*P~*aY8<- z#`~ju^8s&{lbNR%lfvJ*UxPe~e5K}iKcDcoz>EE3&Hl3`_m3g|+J^oXt*VqF5BaDf z+tZwZ^_n)vZ=sKPRK^RQ{U`c>Ch}4p`iS>7kOTZw6aK8ufInkb%|id|9Id1(`Z;eY zV7>6yW?K92mh7jD@i0^?fKYrD~N%u>kHAU+8kSDa#0Uy=mRtxdgj6LWXS1q8QgEFaX zco_bS%xBZzT>mEYbIqS#mi0IM%_{uyL{0h|td0DB*&Y;nC8t^6mL{}x5%h(BLAS{J zdrmKVad&ERMR9L>)ls9;dcV%{LAh@t|H$`~rNilSvem-6ZLsH8%}+u;Tm7ZI^1=KG z`@#CfRBw@fROq7+{ff2r{@#=DC+~+iutD^T#LJmBK4iVeS$~e8e7|aPvo3Te|A1!iJou8JH7Pm9p8Cedz+LP7{osIa1c6+<%FL0e196~>hz!MJJ7FEli?5#Jmyr9Mfd;=#$Uff)^J>#%FC_M-G%pAjC zC)i_`^B2x$$WM~}J@~umzma@XTKpNw5AzrbiV6FT%ER6L@@2{2GJPWY+N{5*^k;~t zqWwVJj}Tg6`q{ok=(EaE-hXlbO5o$~Psab#yq`_g;x9+&k)ayAQnR5EZK>}UVh;{0?Q{tkJN^;*8_ z(x3gJKXY2C$*&c)micuH{CU+QZ*6^5fAtRf=cvD2;3-d-$RFURp?^!mJ^FVB@zCq^ zFF$YjT<;)r>Wp2A{r|Q-5q&U>dM)!Cevngs6!nSOY=PmMJYKvZ`cC~e;$Ox7Q)fJ# z{^M?aM;{Y?Hv;=B{vyMJ_!9g@Wx(rcS1mTH5W*?9txH}rGb#P&AD z_5k}$;LoIE-h}K2$L|Q-!Sz;&SJ7WUjrGViuDX7#sjJs|v4GZX+DuYk2{`^#9DjPu zPpBW18}X;l@nmv3n?XESIJbcKbNfo*^BJzU;s-o@5A@MA>r03E&*yj*@#hYiANPH} zFV}8CM?5#l`K`gdY|l8}^P>23x`;&$a{S5qD>=jSDIKODFcH5&pTT~6jrxk@136z4 zH2KMz=6pff!2Ud`hxGA$N6*FhM}B|e&$JJ`@{(_iyf6&?7VW3%)S96 zdS$ABe}K!DbBP?{?PQ((Gls7K{egOu=tHkZ|G9!+mUpZd^bC2tgdYb#OMgte-U0su z^ytNpoM#c`H|6~j9A?Z1eV6i&qJHS~;hLttjC^=-l&1D5n#O3 zAnPmfXUUm`|AqW&+CIMj8u5Q_g3sUiE%v`=hBBvRnUtup{@oY{B-3DD?EO{@RyCSsqfqTv~)Zw^Ev+= z`qYnK3HcX#^3cH1BY?jHA2}Ys&hY!a{SdX5KPvA>`1q>8zZdaVG~PIm*MW}^`~m*N zc*p0@PW=A2#(1YR#v8* z^aqsUhd5u$`IjowkM%(ZzWw-F@7${UuR)$&o?_5@D&&}##aFP{>1z|6Zu~}9_ynO zz83Yf0KUbC!GB|I`F45y1+M1=J^Lx!@ubzL$G69ewZ@ylc*!c)<2~*tapBfg>@l{l z;REx;{MV3Araz2k9rWrO%%Z-8en0p(-2c^~eL+ob&p;pWKZ9aZndc8UUk`r+_QhK&UWxR6x5KL||p*CcuWWH#KZ zS*Rz%-Xs2Ic`P5yt@b3JPve)NKDiJ1Q~0y!N0EG!*!QTOEAa#%06&R+#QA0x&KH=5 z{gD0>uE!iTz(MH0`e?U5r8s}E=tCcnxpUbr_X5O!N%v}-2I?5C=yQLT&iy8pbv%C% zJi8^&4}$(d{m0Q2`014k>3gV;A>YsNd5J31&mGc@wUIq_{}lX~=YE$QKOZ38 z4Ws&3q0R2{o{pYE{RIK0I_;#7To$Ip!59-H&7yYg5zxL?2Mn0rfZ~SzRej5dR=nvhD z{SGXj?i!4b^LI9*p8)+DUl;kc=%Z&jW=UuLiCRt6ALSW}`Lpr`=;LvzM;1`O^O)a& zAMl4e&h%yca6OX!`5Dj;7bViWGR|24 z>zfnOuU#=}zXACX{;t3JDa6-=d@{uJaL`I_k3A74`6x9ivK{>OIxTCGEV0s5OZOMW4V`Y8J0 zxj#kvyAhwp`Fz@kP>-YMkNr+E$NHqq`jl865HGQPP3OoV*5^q%4^jH{75ASYzk&Ex z;t3ZI+}UTJk|t<^kL6Ya=IKoyhz^``bUp)zLw#^FQuNg zjpcg=^4HrBB>E@E{U%X9L;6whRx}1Apb9 zKM?N&zG%J9Qu|3p4+DSYeF?}JFnT#(tF;?Xp_IdZ-6&6IiB|Le!uj8FBv~9 z>94^4;e9#JHC%7*z8mNLAzuQ}!GHPRhkW3?i;=Yzz=wYQH!YjS{z1gkxD5y~pA*ej z!^Zpf_U&H=P zXmb9@VfZ`Zxs&)e5q|{CA90WQ1N{q|mp-p|>GK^r=(VkfKhnPkdf|MX6Y@um=Uei; zl)ya+f9&YtkC_LW^PP}C5MO$F>?h|B>Xk_Y>4FPXO;2#_Plf(+Bnn_1$Wr+g`bC`_f@wgT*Dzw=E4}|5a5-zF$fF zDEn*cCeFuFBj&cdEeF^{e1iDSHQ_&CKN7C%IR6O#wFdnr@nwB4_OJSUKb7bEp;<+} z1NcP!jrV8O^gTJ{m^i;wAB=%NWxs0FA0_*aoZ#^85M$^uO}{xfOyBERFTw??4`oFJDo90Z#%h(SIzzx~!+h{id$L=heGM zb!%yP3VQniBz|)+R#x_R@u;d__^*B@_zRafKRW$U@RRc+8gS@>jhfe2=l)Hc|AX&I z@cmBz7UwBm1hvBO71@9Dm+&ufyX(hthE{qp=`RnZ|5Wlb6_z*XTc;AqkK|`)68)>m zH0KLSte*pxrxi5oH0x`0oz%~^f}fyo%bw{#9wndS11$7|@cAfuMvY$MJdvo|CN)`9zFg!}z;AIe&GY`(xVY+jY=8j{f6|l5?!TiN7!6Jfe@@ zjrq<=*H&-U9%6ZgeH_nX|AtMF&!zJhIA6WFUfy4b_#N=pB;J_*ZS)Ud|305*l$hLt z{T~~?h5i4Wk7N8MJmB9N=YBDD4$il7W&f+Y7x<_F`^A9enU2aT=|6JORc!%$M-0xh#{!fF};u`Yl+ynhoUWL7b@_qvJZ}_kN@;ldJ ze$-!+u10#t{84-<{1vRsb>-`pw#QBWI%Ai|>j6G6o_~b>d4UI0V+HsDP7ij&;{jgY zkAm~%^tio6@X_yXhyV2B?*~Vvph*wxKd=sF#_w70t!IDSPxyQuRT{Gkegp`$qQv=@ z2p;De$;YsKwD=$Qoo0L=jLCj&$rpjY2~mmc*EX}{95;VEbq&|wy&UqlQh%T0{H<#q zI34{ls5e=GhW$>WADlQE(39>_^yd)wuRA94Ar^(B(|4{jLgWwmyz-}R2K)Jfzf$RA=f9D1-?-o~|I?b|^_IC_F7PL3Se_k&_0M{IiwXV# z=ym-5ap)hcPxQ}8&VTkq|5!Ed|3yDE`ioX-m*1_Afxg+YIk^nqJF4OQS?-6f?Ak|P zcrxKaKAxUK|MR!+?Ad?XwOhYzlGh|il!&GG#*^i`yvPgbvw__4(L zJj&%(~vZhR2^ z4l;gSdp@VUcpmyI;QsOGJaez7-X;D7Mg6B-9}2i%81YPJ#dChm|^1CnP`M%vdU;8|~h##Z=gm@A21?*3i4De4N z^l^lrcz&Au6yp0jmB9ZzpU6i__^Z<9|8_jQq)K8=H#@IjDF7}w=Z_Srk3_$M)-V)%&c!)PW z1Mw#w0z7lsGRrsmT>^n0zr+mkKFfD6{Fo2%9zTG0T*==%o%11o&hvY~r>A|Wwg0SD zueBt;_Ew?(rzF0X?-PZ^JH=uqT@haO#hrM{KM;l{apwB!T#ovM2YQJ>7xUVDf4kXtR(W{87?C^ z_$|C|v%O>ci=H~@^Hl5mK1bp?DDh7Ds^EFv-${9;Ltn=|;2Y-+!@dL(Kj$D1@Q;g( z@5*ugvJ{GkMU6mK8)u(*AslYxqiWq&}T&%ld=86x4h2+l_pB^SliIJ3aNy@jJThF&5!q z4canse!=)?7f-@L#h zA8QMRzZ~@Qcv({5XY}*nyc_gBfgeiD53+wo;344$p-1gL=^x?z32p%&__1m16HE_= zrzZKN%2TpF=*wEvAE4lmyO7$3zu-miz`oZ1b;Ki<_Xr*@f~Nxh>VPNgg{RFQwFj4i zXZ}DNo(klF7#=yVhRnMV-?2Ql`O{0dfCv5TS2Xph&GVPr_yCo<>gOH!_~KIYk7E8# z{oqZ@bt_&gr5ULSZkat=x|N(}2HrAIE2053q_%Zx81o6^Y~h zr-?4B+^LbL?w9yH%Kzl3s1^*n|=*_0sR4c%K13O`Ax*XQ9Tj-Irs5yedR(Q zAzpzzh<`USl7N4=9sO+EjufK$zxa2k|GRF}AHjKZIFqO`KJ**%0~kL#|7;B78x9bW z?f5=`8#MA6QNKIL)AeKhyYUa&{FwMBTu-pTm=b^85{!EX}#aZZX~8~OW4zx-_QJ2vsg;x~=)eq#KJ z{}O!sXQ4kh|Npbp-`2iv{6ZeyQ2%9S@5%AalH2+7I{uFE->2(8efyb%|NOJW|CIOB z#s472KN-Jw;-3F)P5r0t`b?GUGm7&$;lwG{LG1UyenhFyxH05^uzy#Ff2@Ck^MCNy zkq_j0-VFBBxV*m(^>^sI8pos9-v|F*&O5B|{wQw({!Xe4)jr^ef8#i1!}l{hRIlg5<~A`!V!!KF_Sg^#;Ko@L`O6cHO7&{siME zs(*6-qo08N7(UtlsVHCC9>0IlMLxdWUuVrJ)K7i3e*%A!s#uS#Pw-_4{4{ZY7$g!(P&Gw82V zI>j6H_a*ncboG}apI90Oy@h{pJ`wU&A;#O4r~@CUx1qn3ik}ns(9cjO@L#oOe_h9Z zRQY~r$(Sxj-wTiMN=Wg7c* zV}9gUFB!EXdgq`oSJ;1jhGXIy{&yA6WB(DJ&lwL@75@_ZRn48?&&2}`{I=)A%lJR! zN%GfTWBr}^50}U5n2*Ope)f_y^Bd-KE|&T$QaMr|AOe4;+<@z)t$Zv$+4*CYFI8R) z=gZ!-*_Zt649j<&;}Npb?|c^Df4{aN-!!=$=Rr{5On>uz6LIuEVZFnh@C6rfes~$^ zj~O^oU|>C@7v6;W=eN-hv){P9l9?XTXh8Azfg0z{s4>W!0sd0AqQ0U#+cR3WeB@j+ zI*%6lv@yXy#%u7~6~G_&XE^(>HYbxZp8cfu)*^BJEmL=l3qHI0KFD*z;rPaD)TbF9 z#uxs8hlL+}UsT{_eS%BeFX@0+@&mr?{}KIQ9b)~!`of=t{OdEEFMwwVc_>BsfA$~c z{YE~M;p6p$(!W(Xn$fel2_5xe@7S@6Q~nUXcVIuo@Zv`yzm4_v)=S&_{Y-&hAok*> zy&d?#_>nv~7|)`r_`7$h)scLAcy_?XGI8D#{A;X^zaQ(|nuGpTsPAF_J^bGy^f9LA z@2%dut=V7W+zES!{i>)}@b_KCUrx#Qa5%sAb*@LVzl?r$GWRt7<(Zbh9N`0_3bepy z2R_{m-_7?M{E(U2uFbE( zFPVP){xrXDGkx$&$lFZzgZ%#2Ip4_i>Uf{w%S`>J*8BWCzHh<%1qEIj@6JCij3d9+ z^ZTfWF#X36FXQ~pRz0MA-2R6*Q2rc&=lJsX<)5DXJ@;>szshFD z-@i%zahy4A+PeJ|^%24PB5dVYa|0kBe0Qv2orTnFDdL!iTC3^bbC4c|edjDkd zH}>If`74e5pCy06@QLl;3qL*i`J^k z^0$}%=HDfMA8oyVGWlEB)h&ND=M9j*+?l8kRk(ibOMOW4S5dvkvfdeHl+=Ip2Xg*x zC>QDIpDM9E$9dpOpU>eOmU=q+Q`8#jKHqJS;m0DyKY{%&@8<7Sa6Hzor#zu>H|tRa z{%?1`#&PN^`3=jxSU~Wf1A%{x{b%g&LVTCBv=H@Is|87qbUB#eaq z5uE3Eu~q!STO6~xpQ^et0YB=i~mZG@pl2)385S#YVZ_v>ovItH^Bl zPv{4?I6wN9T^O{hej=5{9{)G{;Gv)ZV;D}KSe)Edw&PMzup|r$Nu;K z+4k?ec%9?V(or4b=?Od9F9ClW>pi}|jd-_&ep<8DUtZL}PqMyvg~uDq0zO|imp8^c z34HL^Fl}OMD{vaMW*bURL`&30wmnAMosod7xk8{35*H!1u}EDMs=I`Z;Ti zp8b#4@qQnUALM)kq1V%PtQBA37mCkAVR}UJCGk7*F}>?=?^lfQhc^KszYl(k`i&dc zo$~B#5`7f)&ou7CAIEwrC;m9(k3(gR@TINh_f<;o=I<|g=k9ELf2qRqTW!m)e1B2o z7yBy*Ci@0iAJLSY7cqr=h=+cy+RKnX>EG^(hpWHbEw6Q!*D?M+AT2v^##PRK$ZIOk z@){O$eG(5}Y*~jPueoa>uU-t}LtZcQ@->#nNM0@O9|-yTj9$z`|K>PWGf>wiZH1Mw zeCp?Yg7?p(zJcEiXI$;drhJwmpZXN{(|bDd`+*(BugLH4^No1T)v!M%+AlJdf9JQb z{{`cRNCwO$Y@8p7euK1@#q%8hyt~;C6X-b|^%wMONBb?xI`TJEzZU$7eBkifa0L59 zg&#BHdwD$UUo9l6kawKlw}a~=INwU*cj%83e_t=!55xS6`4I27&;O6R=(p^z?B)5| z->+=<8y@fc4D{>RxA!{mS5H%*XoRrC6Euf#5UToA4U?Aj&`VoUh~7n*HI>Pk6tQVtBb9 zB00wJh8*vPG1r_-RYT^ppBLUL&7^@kAd4obPD#yFG#N zVm0s&e-D(;R|dafJnWBd(`QNhn<_@<6Fr3UnJfIh^j|EwpK!_jPSO6c+E$&<KfC#`m0{FBD>K*js^AoVY1vCYJV*d;JL$Lo0`p6;FPdm<6VSIJM zU;1IU{|SC{aGpQxTd*&_9N(WCgnn7Fzr3AaO^!ke23+Lh%8JiV`Q|A1o8tVPeOsg- zFxroF!t>Agd=uSk@v{c~&G19Mkgw{5*Z=2kcmqOzexB)FA5y~K(obW<-YvG|CCB$= ze1Q-BbZkGFAAG@w;EO3@lY{ZGKLh8n;5;8HxQtKOOFr+Wg>OU7BdKzKpg)l`51tG^ zDTgp03LxN5{3vDd|0n%ba=w(apYK!c66E{pd!Wzwdx6j=$d{FL zK3_0kf33*%5MTTY$=~5Tk9a*OZkfyxx(MP9|-x^=)81i z0`nz8`!3QGJGFV>iaJ01wPk{V7>9Z0H5uX&-ILC zO`+cJ6u@uJB(6bk?5F9{x0t^Mecg3l?=NEgKri&$4C}|bhWs|x1O3?EPjI~bsThyX zuP=C<3sRO&h6*b-u!RI?m{UM~e^mEn>&U3zNoiUa3uR8zNNPCj1&HB}IoL>|D z73`W}es#dN$giS4;STZlzwo0X`%)Ti*%$m$qq02D_pPZR?5~sWAvpV?4?Fl>><{!U z)3>E>asD>WAHg-pXXmu*83E)6Ru1(HFTE^_%xu$tbKi^aXG{IUjpT#FnUzD{E zHsi0Teu4d@-#mB8`UPRW&iX}NZ`LoA!SZ#QiTcIV5b77yS-;qkUKv8HizM}nJl8MW z&iV!Xn`nIvdyDTALtmf1i==)b_N1;BiqW+eS{0-K3 z{CLU~_#yK|PCRCD{es75c}hg}i+e}7{xGRfpMZQrKVv<0j*p4!7m!!fSMh0=+-k-3 zi%e9%$o(Gb7Zv2=pJ?%SPEfCyZr3YLuzrrW!Zq4>SG{7v?Y2LVR|oP7 z{fYRvS+AJRf*(+S1Hbf+&-BlXznA`QO+>E}zdyzAm!VG^{^NAE>HjWCpUn8XTkkVH zEsyulhSHD9-*4`;mwCX8{R9#JK%Ugw#9u-GUNk?y4}XREaTN01S+8(g@|9aB{k!=7 zq#yO~9)dsI=vM^UBKs0*GthrrA4^KUrfyDB8RsM8e&hR-9_YpXYNogy_JQa3n7d;}i0s5T#+i6c7`^n+RCnF9ew17kT4;FZq6NHupv2(Tg!C^wCND74RRg zU(Um|F`kb7v^f8j_Y+>VJ28Iu({}6aj-<5FT&!yx%76*3=JPFqip)ad^-a0NN zKLUTTYd>fUzFV=rPX0&(KHXt_<9j>%w?N*}Ki@k4B%)8p`6ofOryq{tYv8k`zdPt9 z@ae9@^d4mU;V$9tSQYucDS^M>ui*RJHP+vb!TLL$e&<)QpKo_Vf4gz(2}(MLc)Wca ze?jeG|L^mq=@iaWE-Q+IA7Nk6AL{}?h^PD6KY8tyW4}>nbYZ;sIaO`OjQ_MN)&U?2KzlK6gtSH^zhIh+R)*>8~_bkXqle$Imb z^7;ShQS`kbOTOQ{G-4$85+WQkRS~(~u z{uB0Z>vG+J5hWn_>bUi*iYa)7+@*y103x34^ojHv7!TlF4Ks@Sq>(}|qu>WI* z`N5U_*4+Qz9-k<%#DCcGCiMG&-&D+`4~YB)24=`oWe46z{*&^q&hS?)&Ib%Z-_^cv zEWQmuz+TsQ|6Sc&pt8HB27QQMihhCqtYAM|UrF1I{OtEWclwRE)0v;8L=KBe;ygE; zPr7OW>y!N`<17y~bB3_L9N(*geBpl0e2{JoX1A_;L8m{X|C&SnAMyg)JiB6Sa$E3< z;pzPSS)8x&)c9AfAZ1|aLorYA$MG>dB`P?{8uUjCK8m@l-xn3~!?M2-cVs<`Uvr^x zzDNTfbv~~KgE}et^0qrRczZNDnt;I>&hUQzEZ)Qn{JvE?it`ku-zbQKpKyLP_IK8` z1<}{=zj^;R>@Vaw+MkJ+FhWZnAkW~Ry4lL_%KNT?d_}^>dGM(~!+9UVPy8157h(VB z@$-|>cp;DHaDE8iKL)?ZeA2(wUpowVe|-3$Pg$R|)|*>{|uP5J2 z>Yqzq-h?+XcPaJJm&=JCy!SC}0Hb02PJ840g5(Rk@gL%`Yz-tjBK(Z}ScyE%uDtb09vo$DKOyNb(|f8&Sy z9Gc(t&LeuT3+LTL`24J)yc9ij!!*8k@_dvp88#MQz3%+g!Na@Ap?Xrr$9`F__P56w zKe=cE9?@UK`mL|N2lJsb$Tk;Y0-y~%`nJ+wT9Q-8nRrq}jihPU2yJS9pdO6BZm-YAW z-w?7s2;&SN&I1SizH)HD`AgP6di|L#%YCgM`Y@cRqhC|_xsIl|h#wp454ax0@TP>m z<^E?H{!WS(Hch8O9#7`)}?f;$@UNj(tf zt2%3InLGO&9}QoVNwKeGwqNuS(64cxYHBy?s|moTOa8{sl=qw|`5WjX&aXa2%8~dU z*R0RP->$;nPRV&frB=MtU*+@kOFiFraA#WiyU6~&yp;VNeP6fz_4vFTtP09R_?zbg;Q>AW`1`BUT{;r}AOsBK4lQRnmFy~(Rj@64Z40{oMt z@A3C$7Z=oObsNXG;-AX*t0RAP@G#z&`hHYj2{e3e|vfECxyL(zlZZ= z(4Sk^@VzK!-}^{|zSFdUs>mC!FUp^vpugFo>qWj0FJB0FGQkk$m-iDn)PAjy&wKX` zd~e#H=wEga{w4C!rTbd?L*iw>_j`G@raT}XK|dtEuLFLR{Zj%jAVYnzmcaOkr!HLU zO_(cje%D;C<9iAeuY!sD=Mhia!SMIm`spUfmTd2lR&~0&V#bxUt|B3 z;junLJhEam3;gh_=->V|#1Emi8ToJa&$0eZ;fes<^}K;#J4?0E=6%eUeEn2*pHxHlDBg&uJJ7YJBj)SlBAE{kyD_5f!N>6Ot<~F0RC`l z>VGYF%wYH*$>Bj&e~$UrH>PccOV;QAy!(y~_$T{&7{o&UY&zvG=XwVG<&O9P!iE3$ z<-V}{wpaG<{O1R5BoO;wg27T`vAsORr%xh%}m-!%AZMFFvW^5{YNMPrlq(6O8fGs zCB*_`TOcafnKmhjr0FzCX<@5O+M+>G0#rA!>P|{qsHC z5!s5mI~8|Lwb<|HbML$J-kX^uE!2O%&9pD~y?5_D_uO;OIrrRi|GXV*V+YqI!YO~Y zT8N>4y?pTDhmAENw*B7>*aw5trF{kYkoJB?_5Z$gINvJ{`)VTiv%WMlK!4^Vv@hlS zuG9y8zy0R>mx>9ncOZ{QiW_ry0pSjBt(m&E?gnto!^zYA!L%(F6iI$i^73b$AS-%MLXXSZ9e-C?i z($H%g7gH2~ZwmG^>VxxzWPLJny^gCsvOaR- zAL&0($+D zwr9VHi-~A|+g|IXJ(svy$zuro`FPw+2Ef0tv9LZ{%6EGE**Nbm{+%s}a2oQ}I5B-3 z=Nn>tLHS8V&FDnR$C1o+i)Ri7wu&swAI$Gq^v|aGeNONX=o|IbD0@sOdn|JR_JzU^ zNSl+;mB1fYf5g#u&}Y#ht?&GYlsyLhmGNV|G^yr&*8{ZiiJbiU7JBS4sh_e3a6V#U zbKN-!oWEqTzuf_Oo(Oz=a=lKfJPUcaY-o4|{7t#}v?TpinHCr?zzprp_6+I%;{1(x zY43+fb36}y2775*$gy|RcrKUo3F#MRCzzb_np@vh++QjCH}cEV>iotO`-jK@_BRtt ztNKf2{}BQ;!luP%=rhb8o3+csRp#WR>|f_VKlH9LXJ*VI^Me>4 zLf=UK%%Ck@_H<%m8vGy3@Oy&^e+m01arM)Vd?hAYKmz>}^=D50V6U=&8r1Ctdxib0 zq#x@~`=0hA=f6H!R@LtdmVm!RSpxRmRLG<1uSf2`d>QhaEl-(+9(=KW?%HyN?{?zL z@=g^$ktY2_iux*8Rhe=1KY{2f^pEWSLaILTV<#Hj&n(ZCUS!Xe{S{dwSAW=Bq(@TP zTdsQdea(-H_FEKejEUf`F zj2G@ZKW54C51`=<%1_AgV6cz#BZGCl_+I2alSF^1^^xlXChaM;KL_o%2LA6pwjcQ& z&rM4IADtM1Jgf1ZDgB)s@1g(F^K)waI-J1xeeeL_$@BC}GbkJT8Nn(^&R+z@)+?!> zus<$6oA^5GPcnYkpMh5D2Z^yc!3f1lLj$x2w*#JNK>V~;u{2#XD3Xbz6VezDVSY>Q z-$}rp1Th|-B6csrd>4MOKW>FSllvtzM#7|h5q=TpOTqq;-@};@NB*Gl2N^rUW)x$y z7hU{ag8r?ptgmtb{b8->ugqfOlPx@NMEJQsP@c~!>6HOx-Y$lhfL|;O{3?MCC}2V# z1Vs|_?U_>O?`WU~`gIso9{n;jg^=a3`9{p(_`eW4}w8I`z z@G`$U(TMiMe#?+Q4u3@H5fA2!EBS z{iSL8gB<=*_6+)4v>)xKjiT4Q;)N;Efr`Lk9A66iDFk^6V!dUc6lDUo{><4VWJKm-MNU`WO5{Q3Ah)N7TR86+C~N>(evN z`gH2oji%JUa{aR8Ke;}=RIV40^fDFyrLaCdnd3jy|JwfNU#%_KX7B%u7)`(jzmQ0W zy!;o!`Kdy!Czks8vsYsNElU1QN&aJhUn19MW(XktJ%1<)`Q&`?5k3Bd{+0bZ?ByiN zemOXl@zu`3eC2)1t&&Nz`pa8Ii25|1$WF*|{pTUdceb`Uj3F8<48Vhb$+aF#p1+(1 zKgXjS4@`?tpCYMGOt3J1QR}-?z6rYjmGsHfde@&j>%oE%j(0)=_(idvCxi8z@K3}8 zy=UwzNdlk2*2+-D&f1*6>nD7knn8iWI*9thC)qV^Mg0W)F~0$Mn7Xkf z1${qhI0Jjr+28H@K3viBH0}HgDkmQe#32NeE^5y~{!xCC z`ZfB`dF#E07JKCZ_~E>h!@$o4zsWftJb(V!mUq@~Y9;0qC4O=~zG(eMTECma?YJw5a{6XV9{dR4 zW4?dEXzOjn$LF7?yAj-^7b-;(=hh~Gv_>Zc~| z|B(90+_4V*W3&hBQ^Q;zln7uw;}r3DUH|jw|4@h}%Xj*}2$rm2eGvM;l<%@&U4s2j zspx^fEzb5yv;V_-0F0MRJ}3DMd4c|M>5C(Pf%#YTfABuKdFU9Ya+0$hyQ<}Q2zM|Y%gDH>7uHsBG5fKyW_jir!x%S zyFRq#g=3rFzx0_`e|`MEYsl%2(|*o}Of*r+lBQ!fFP_Qr?@sLb zPtgkh&`rJN*=9q;k|mR{AEAl#Nkd;hJuwS?gMlUKpX2AT`fuQ`Am z$q!1tPq9B&@KV%2iITkU*EC(_l|PH}Ju>{_>r2)53Cr-kBH6wk`|nEZXOa3c%l%QP zglB!{NcIxfGfRAD6W`XO=#rPsw)5xY6W`~9y~C{dQ(DyC zV0o65U&xGps-+um#`CvG9!kEN72meMvF>lN*nq5VH)Em$2Viex|g{aF;ic{xc(3kN95BdEhrxv(XHkz2IT>y&Th*viWtIc-)!`Lkp$y zX9gqp)=k5F@x*P*qdU%8@UU+fk+b^h{Ac03iU`hgmHwX0s(aBtMA<*c^D&VV{zQxI zrRF=L#Gm|#`oMoD%SR&5dIHgh{YKNw63={%FKR4Jh5CL2d__g{YW;nb3hHlhwus>S zg@9+y0R0Q#CDH$du>UO;((!`Og@J$gnfE}6;fppm-LJ;qR*7HW;~1Kr3EAJ3i>*sj zs7vP5Ml%cNPiY7ZOR>TZG5+ixW=*o@~E>c(&s4 zx_5@cPfvVgxp@!TyA0*S-VLM#qzUww@aWG2{$cco82=$&!b`(GeG%UWMtdZQFY)32 zO+2UT)cQfWe**J0(J0%O{0e=6_5f(RzNOhD_;s)c{GZqk{zv|WT;HhI13;hDXnhif zKUVQaU!8z|-G9b{hf9YN$lqs7yl*+yw^ck`(NFtaSgmq?2J*a5ye$;6)OmgT7QP7n zn*;wl%1^NWBLBf37?=2w|8TxgHSz}{di`xQxBe%cE^fbg>f^MJ8ZRpTOZ!kiv*hfG zhf9Y;&<9B$_%V79@P$5T3PB&h|8L$S%tV~;%LK_Q#78TLb;RVJQXASoFrY^I- zK>G*&qhKg=cq8neCqxM6SH1sjw*Oh~x5ju1?Tg$#k@g*G5@pGz8exWwh-sR2k3k>y zMXMnHl@VWEre`nqpNTu>e6(ipz)D}8%s(w5X2E_k8lom~Fhi~HH4`;ZN);RBv*cIH zUj=^s0Q8*?J}k69#`{q-1AH+ax^m%%FGo^e;vUBP2RqBGfC$9T*!W}Q?Sp?x?>|=h zGAqsxhvKhIO$3v6{zdnz{1P93`YxG&%UMSswew$T^S8`Tq};z?=p1as4EqA`ud{!c zCiHxqOl3;^OWKYR`%gy>TDL)zbGa?4$Kd}wZ!G4YhOrzN}(>^>;6N$O>54}UKKN4m|uXtM% zj-OwyI-Xz_BV<$__1VpieCaHfmr!46wsWEF~Q!iJZ+0u1b-Xn z%UNr)T+RoGz(UAhIM+W!GkX07^oPfP;j@sdQUs}A%p(0UVm&`2cqaO1aNims`(HP` zQq~tL`O=(stzn_p?M|5Vx8QljYb&dx2Yty|qBTwX z)IvvJnLP?`e^L4b&9~tD&ROFg^mmjmBOJr{F>3Tyi=?!-5?rqqGWxOK*^m8d&{t+S zloate*3&02Uo=SlWIf*?EEFFQ*xyuD6^hnHpwH@)&`*cNm7$PX+HX}Q>mz{`_}<_A zL=7gHnhs9Pf+)eEM(BgAczaVrbY5R70s9pCORQ=gdV?+mddFc^l z2A`|~K9L_le`OvWnwppdAh7q2HI(rtAfVHPAuvC7$Ay{72dqR{)50r-nZ0F8k?)Hn zSih!KfES;->WtgdJD+b%Oll0y7l)6|TOzD)?Hp`Od~3LWhR7U^Z3Taml zLVP0W4`F^XlewyTM(S|FrZ3K~hkp(6sOI2t=sQa^z+Ww}ACfOkAO4V^D1XJiKg~q$ zU$Ew4_{WpThVuo{{@Bj}eo6Rt*zhF1WCqAL>@}YS3u>0!&oAO9p+ABl>W@JK`!7tw z#~eSbt_&fjFZ=StYXigJ5A=HYSu@wnjg|~WuM`8Q0qWv6{cD1-N5UcTtF7m6O#5EJ z`l8J7%NNhg8YTBVC;Jo3Usi`hna_v7-HrQdUY^!}{0e)1UB(+ye`FpDC4{IMSny&{ z#H;?HM$Hc<2NwKznrOx|O7kUT|7ZIjj^y+wq9isxQCxn4Qh(K!>`>#Ek`TuSGDkGv z3&e`gM>_r|NH1AYpuJ2H!hF0cFR1;=lR_E)(l?;LV1L4Yk^t1Y^mhY;50(yD#)oDl z-zl)Z>RW!6ch{o(YX*<@h^Ljk0C^3DqDDMqA`jXCe+&_Mw&{1X6TW?zPwJ0Y!ZeNL zrfF__nD#-(EXXVQRpy6(YzFdwZ>!jdmjUqu#V?F6PQT${3+s;$_W(aI;SMQg7*B4M zz(1QjKZNr+tD`0gL4UgC0}I81zUQ}ywCqoPnfC^* zz~Hm6pVQM`5w7vAknyFdKsD?y>td9@Z5!q*w!CXr;#dA5_a#?R-2caR+=1~I{9A*=+Y|pgAp`pl^C6J;)O&rc%fvH~Z=>;;1^%4p zOI&LCOR64(KQ>YY`*C-~6i=?W+C5(_{ewnRHw?YOEKH%qcaI)_dobQ95@GRD`+04q zKhp$z75tZguEKs43+0tr%@!Kc+G?-2p9KB^KYZ`;Gd3b+Ks+zRqW%YZa9@YZ%YWnt zd~XE!Cm3(a{f6*|(tZ};PyEcW_`!EXtbn}d@OAT7gy$ilzPA35^>N3C5wFG<=udVi z`?I`)`rAV3jk0`<4`Bbu{b+cW^I2Gruk`2MNC_yWnL9pTq46Y|jU* zi>D@@x%gr1&PdPt@st)Lnx3|Jruj?%k1mY{&YsTm0pOpI`X)pDQz~lF9(_I-*a_|@ z1)`XL#QLXg%dLBmzI@9g@P`i``^)znl=fM<=*Ib_X|PD0)OY3bJeK4(JWKps=dl!> zkM&n^{zA^*S^gmQXUhGL(Y*P?cuLPlV*JMW44(=6avRfQ{Sxr6jfAUEo@}2gv`@e8 zzg7AW)2IEVNI%T^g~9y&nnyHzoKFn+soEXqTh=|Ozb_N@)y?VqLE?PN+-YF_-k?06 zptjX1597b6#E(BWHtgj@#Hhp1#RLSRBMQ=Q-`WUMH6uk=PAD#9p9Zs@7gy*hL?MU@0k@S=JrMJ&) zx7#z@b9WQ@4UQhM75jY@{(i(O{ycHw*onK-um1YP2JC+#{ztb~STengSNxS`dRKn= zjP?e8XiuAdlZL~KszErkcjnat(Us8GkWavyJ|?_O4j*Kn0R83{B3c|DCw|(NyK?On zL3;&|*S4n|co;bA`YHL4^-FKRjrK0-A@LPq@N-EvgZeo1QRy9iDH+bi>-u~6$;~g> z<0l&3?cuMiD3CA2V$9ei(ABH3zc}~|O zev*o(KPK(R_qKEOi7R<7$NGnB=41|N{w$17LSI^tUcw)VUmf{V`X$@L@lzf?iNFMm zpNh(_!|&L?!2Z`z=XXJ$7ESMz7aC5Zy+T6ozfk;|Ca%eypqDNGJz8FD`RhUd$23x3 zjV6BzALwHrT<$zC1)0!VAw8ZW5YKPlbgSCzD>bUF628es0{qZWIxis-;^`eQ?~I@j zbI-m)Y`J&pnzRVMG~cFkhLK2IE*mKQKhi6IUhtnb3})A*K(#(nf zziq5vR-k@8fcMXSS3K#X;s?iwPmK}ZH%5HCSo}U~3Fs^Fixi6&s}_R3GCo`^K6C*2 zK|0v06|}F1f(_N!|BzsR8k!cF*0iue%u9-1(RmN}+uthd?_>QFN6U?arM<(IDF1Lh z_J2e}vm?EXKS$C>w#T!5$7e5o)Hud?F*N<9Dg*Hk7>6t|6O)sbk)QSrBfk9DHH-)U zPBWTk^`X5QLNlekl;1wV;0`NsPNZ}d){m5j49HiyVbVPFHy?igw?9byritlu%jQMJ zjPk3@G%JenCq}d%pLKH5pNc?{!v8ud7bhVmo$X zJIbg0*F_=piSNxfe;M2l{V=^@;ykk^(UkUQxc(&~>S3?KwyZNTl6t8$v7-V0NO3Q~ zO8FJR2@|$-ZtV@Nfm2t!^nGzqqz8>EAu0n2=I>otS8aw%cVNUG4NX5-8VUs9-)lsA zAJB2W?Hy+Iy+wE^$&tJ&_`2aZxLeE(^ty+=C?26&x!ufV16qw z^|kwg`&eGKX9w)}frLnxCL-1S=ZK@whnW=0SNLQQzt5kJOplZ%Rx$n<;w5}{e$v;K zU&YJ%Fh594{&VsN5;zYyAHPxHDSRDx*3l`D4+q{@_?Sj{<-w`})OXd35}$bJEeBor zlwf_p+k;`zAZmPf^_E$)0_EoH+wFauE`YJ)ENNcj}EkpC$EvixI&|GgiR zUObPW5&YUPVV)p7lkk+kfc)HpK{572B~7$%)Pnq5?0-~$mPmrW8_MP-Fs%mu1bvTW5I^;Wa>UPChV;`yK`ZgG%8FIuBI+04 z5v;vVoHOGHp3@P;PYE4evUsg;=){TH3C5%T0dYlN`h&1{v!IW}H*LTIob9(z|I#e* znQCH~-)Q{`_y&Vp08eaze3(6F@9&)=rUxd>^X+4L)?f6Qp`Mbg5bMCA*w2bZ(2(zt z5o{6W_Rud@lpdjchHG{-0Xm8f?mK?j;+e@id+}_B=8Dpx=IY62`q^2tEE5TQ!C)o$ zHBuJ`KSgjJLNFYhAg+j;XNXP_gS>xVn3Tr^=0^ev_GjTU7+=MBoFs_&D#rIQK8g5z z{wwtnegoj|Yn?i|@}{b~`>OkI+)=YWe9@tXxs^9L_J+u?eicBa0BATR&GsQLQ}@*l{{e_+)7k%Ih(^YR}a zHGhcth4D5~Y5H2xf1OC&J;?}eYA7)=w!abGZTV-!WJ@d%SJXlNz={}Ou<6{tg8nC! zXb@Q5&He}ea-+17{F)5*R797KQTVPe|jkPfohTc{q;}Noc?J-#D}@VKjZ!>jVbUq(my2%^2hS@b8J-oY!&41 z$;;m}YJO3We;_aaz^M7tXg_cL59H-PFlzopLH@&e`45kp-y;7+Xb+`epwyYZ5YG32 zYBa0K(&5u?;S$hWhT8PANFy3f9K4tOD=&^U(5v{Ii9t$zdrFd(%u)oew<$*?f2l|Lhxg_W)|#m z+V7=}nJLvXq6gmH)L=du`ss?`z9h;EJ$=Fa>U13T^|Xw%-_t1HZ(%%(g_+v^SNuK1 zcxnGj{#N{snu5Pm(w+~He=BIO<0Nm`>-qehZ|{5gJLo$+W!lGg{Abhr&-czOtGvnf zH`4ydkiSt7O3L1y{$`1^2d6cflSO6piY8IV$wSMVzxE{Z&&uV`fM31&V<(ZnDwjW5 zkiX|7@>l2bM+@=~oJ4-?UDEY0$baA@@-N8c&wyXO^*?+P`D=3dlgyvZOqq7B816l5 z4V)1;kKUTTK+Hp<`4WD}Q(Z9e!Rm+KBz|2r|5A~iJp16Z-~pu1^xQoE@jw{kX;-`z zI2YsTTzqwM5bbZrXRE?98@7KR=l7L@U(Vfj_B#Pj+GDBdSijO&GYkA6pYa#|M~)}3 zA0;<_kn$$wGf8=iP~PnE`S29uJOeeXmrMUE_7er=d4?cy9S+~g`RA)f^3MmWF7%XNVgXcT8h?a| zAy%|hmLK(DzC7JO`RW(TE20%*pa*UcDSBo;KGQTl@Q;F?bw0I!-5hDX3+BTxKhFI+ zb!n{4&M1G1zwu@G8>7#iXvF%D8C(wxP$K!liN;A-FNNu6uFnRFSbsGf;Cemk0}*9B z)@L(*%ULS^*byf_fp{O*Z({w{cUosznW}vi|KjQ|MdbU)AASwzvtT_Z{0f90>=(1E zXE^IO-RZ4=!TJlV7sdSUJKD=Encf|rVtj=2=@LJ+KJ>_j-`zbyrSD_B+>an;ttvcU zRhUDF$NE3i=M$0hRDIm=8ISq;b3-An=ThaD9cdOpGjql!(OQ5{_+LR!yoG)8%9)@S zekRTbZw!UP^*&#t82l9W)AVz{C}K#@B+3tQ{|8*7A=84rfsfNLzl!fW7wHedKWe8> z;JF<8%dsBiJe=1j!fyh-<@!7e(CU(y%XY2DLE&c>;)DI7x${G;rwii&AMr^a`8)Z| z!gzes1@UGS2ATXGnH%5uLr5Rxd9-~#tVb15JeSpQe_AH+3448l&3_epz<=pwhzI^S zzpISt$q#OLk*f;J$9ej7XfH{>$i>KSa{Wgp(C39ed>`RY)A1tEH$5)l+vN}5clT^8 z#zXstj$ytbTizQ|{5Z|7*&;l(&#X!2H_9#D0AS>G;9FA|bot@N<* zdr6tnWkj)L+IA zi#4cE``w}o*(+S@lb}IoA^#R*A^7)uUq8PKIlb+jRPkJ|8F)&bZi;$iMzMld3l3vZ4UQxss)OX9_)zC))oS!Yzmqjbz1OL8} z3Ne2ke&?b5VdIui=s|JZUZ3i&f9B1AUomhE=C7a>8x_24Y-wm}6w8zqzV7tqTL=&9 zr}{!ui}8QF0`eX5VZB#o65$O^InP5+#!nKyZNX3+TOAbqV^&FSe^i|OFVEx81RnRw zN6kH;msuvuhy3uoESG#({(X#3BR-#AIPYymMW1sXn!7&PCy<`;gNMtW1V5*~fcC)o ziJBj?pOf)R(cj4Pu`?-@kMr|*zThu}RY317;-|^;vk(RTi+rgNpK^KrdHhNCe}lUK zPoD3T3A|+2$Bkd~Gl(}0oUfX6&SwQ^Ex(M%d6+rei95AoPfs_^NX?cKke>5=+4 zg8fgv1pC`z&;Ak-U61l{-VN#fR1y4=al{XE{Z}T}9&Y?Y8w>F%>nFZ_{^ugtKih9) z-08zDu-^_D>$rbw25-hJkc@Vt;S+ zq)Sw~v?)Z*1?VXG_;Vqw{}v+p7L4@~@~83eBmWF!9*EU>5OK#>zGS45)t>0W{6*qf zw*QE4|EFr4yc(|9KP&aiNd3|A6M)w&;Pq(iW+!tV-WMQ#Z;^6If7B{9 zFsH`@o3Ax|r{1%Q!e{%*_PN9poy#9WysLd|sO?mCd5RGr>smJE_q>b2;fi!iS{xJ=&iG-6ef|7MU`|p3{ ztHu+3c3uNv^hb)N{eY(0>(Y!^llt78o|&?OeI{H~GCflWF&X7unlaX(ywAmUfX`(n z%#G#JDY=6*r1lVq0)w3Dr}3fO%>j@-n0)PtU95;a{MvB#}%vMiN9S=E>7no zeHHwbo{Ws=MY_#Z{P5}6YP9EtUKDh?Aktk3Jojb%zSw(v(tPj!@tGu`oXmK|_r#+w zl|Y8Qyv+0(UUUWlW{eWT{Q1Nu=EhcffI96^l@T*ik7@28efeWNVNowtWel>=W3lJa z4mM)$bgDh)WJEoiLS~okln)1bt6nxmYYvPnokOpje!Ja~9|cw6rOLa2c<;T?#XtGw zU7+yZ8+)u6-in^N_Pg5Ce6sE=hkP*?NPjx^3B#R2)8|cymwGF6=8iy&nmab=8&G_j zkI%e}@lhXOrD6yDngVWqHkd)_N#4nyZg=7-%em67uq$5Wo1NONiH|sUzS$^q_eDLI z0MnlD{Hhfn5a#H`e(brBBUichE?!RJKr)3Gmm>8<2i(Hp%a z`_EDJwCqP~3hPPKC{JK(>eqd-HO2Tt)ypGy9mUdVJ#=A4EKTjZut!xozh2~jl($rt zm&Zr$da-?^{6ffGkA$C#eXv9`h&!E6=48axBkK|J8T7-|fU_sokn0u-^oZDBo%-xd@R{?E)zAG{H7W5KJ$pLhS(7npVGjKr z`qrGs7ZzDy3|zd5+Pe8F^6 zf!F1VeqVeg_{5iE`;{unZ!fWben$9G`=9s%ky5Z&Ony4@$9!eC?gzXt#GVOA7RgUn zMmlEsFOT6xn{NA9>j4V591# z_+Hn$c)O9#xqAP?E3aA)v0l>N$ru#ZJ+Xz3d>~5x-1UbXsdQJ3oR0M$EuDrNSzzc} zaW2n^Nn#$x^=`$L2K;)42>*qXZueD&$n3&u#v13{goTE9@=-%nx!%pdyCJ;myWB~) zs1~;KfFVLIc%68c2E1aw8XMknJB-@l7CY>-!^iFLYj!wjhcDXUFYPd(&cewRHOqdk zvBPWa@FqK4XNTQ(n6SeK?J#MFPuk&gcK9PZ{4YBUfR6l~Ylk!JaK0U0Ylmi?N;km{ zv!D%s|7wTdvBQ)de!>plZ-)!)d@>XMyu3)|Z$Mk{_Z~Yu-%c;=@Fh#d58C15cKC5S ze7_yO#}4c4aF!jOWrzQ}*v8impR&V8>~NbMuCv4I?J#VI=i1?M8}Dix-{&|hfQ`^V}})X_&Xb)f49T0+2Jlb z+-8T8*!a_A(|5TYHfy@u38Hqpzt;}$u)}S3_)$CjxE=1c!|&K(3bM%GgLc?!hg{b$PN$Mp^gvb z(dnphL%gLU(z#)6OIO#b4Y#*+;Jjboik92nv8ko=&YNQGn_8A^xmkz@jO80P+`cIu z>1?~Bt-a;878!N3IA7E@zjsqtx6GQ0>=K)eWgTtZZL#i_m3MY^x2#{;x~aQ)!{!bG zn@jlh?HjsU-rjPjSSjS~%9hSM+Sax-#yXnYTZDL3;!f-ww6v{@IUH}N`~h; zLTPAeZ|T;!Y~h=gE!_^*wGB7bMwVSR|B~kRb|F4%T+`BBzp1mcrK8)fvAEV)x}kG@ ztou4t9|ZyKGlBN5?#}j>4&47Ib1aW_bua1c+<=Mu28FAQYcCBp% z4Lbd+aoe_bJsiE?3v_ST+`eIR3*K*)?>l5fIIu3hsk=*biPfvyHmq5_Zd1ovA&wD7 zCxP4?XzSV>Ymc|auq<9IUVNGL&f2EPlG-NgU1Gk>yBXO3Gof#a#|eE3Qq4yyCR+V= zBon12o8z5r9o_3hA4=JLTTA!)SX)P|^ETvMAyzl7jkBWN$oxC8x@AjSxA>x1y;k0c zX#o|!*I3;KHbtWKVnD2pt?#-`B?VWmUR}SsE8eoUZC%^i)vb~(fyZ{d?`rAZ)P*c) zv6fD}I|#TN*00~tjP^X&SiMf&^{AAqWAXUv?mOd%Titr2^sZ7K^oS zdY4$|ThZNKAB%Ty>TIds(9w;i5`PoGyPMiNyEnz!Z|vBN<`UxTe!NrSxD5COW#o=(2z_ME&xW%Nmw;Zdkt(EYfkC*wEf$H|EWv{<_s@{M8LD6uH&Q8dggg zUui&iHpLs-5Le$G>*_*$myGFj#i&e>v^I#zonSY#Pd6CnYMrK`1rZzWROyy=tlO|0 zDFwDO+0d7CY+CO`f-mj&^_?vsh7-eVvh)_60(g0&8(O+!ZS6OUhja=mGbahS`2rmy zD|F4Kw&pIP{xLRWRW;v1m*S~^)HUG6tjY))L4w{<{VKdbYg zVj7vQ?igjf6D$U-Hs}_RLcV(WhTB%7!PlV~gt(G%R2{2Vv~;0~x>jqQ81zX>v5r7O zsfIOLPPrtm#Dssk9VzAm=5Rq|z6ms3pA#APGJqTZ&ClNj1;qy$?^(FH88p{;AJw@7if z&WE}$yMC$6c(X|9w;-63k3wxyuF}+Rh~Ig`lIuVXVDV*^vZAF0`lF@OTV-*PhAGRS zcvH+N??iBqjzx(!_MRqKxn$Li5m*XJH_sRKt+CEXXUiQoi%aD_8S!Rt1$$w|5jTq) zS1wthd&ijp0KTz9^%5v?ZHrVO;8FHJzhQ5E-G=5(?Y4P?x~%j|11r+fxsLWn$69Fo zO;Gur;=SybSGBFZUA_?F^UQ5qEvs6gBb%3@4|v@5*0yEvdL{EZ=0$B6r9>JUR|Qt- z?nawFVtHUhl(o4y9{!n7z?y}9HFGehc@f6+2$L7Ur-plm0?V0?%*A*GVWe7!H14Aa z!;wt317-7-e!u~4Nra(CkRI<%gnfUl?vn^Zp9EaKN7(l%b)Q5ik|-DN8Ab=xJ;T9W zDoqAqWVgDHGTaAPD9b{a`Yhm+CJ4iySN9ge)D!l5gz+x`F7Qtvw7vowvR(*Ne~0#E zyC59=I_Qb}3_@{0h+)iuGK?NXz0kf4)87WY$R`NR?*d)CXV~}ezz_FHgvtK^{-guK z(2K~6^d`de%fN?u8NPyxyn)dA8Oogld=O@E9l||BYylP_%(F+20=HiRKJGIJ!>^(~ zxVI4Y@xs0NE7XM-?$Zqa7xm&j!qBhLMwkya5oU2U;$94+UbtFuZ~X@Fev3S~j~)k} zuOS`o876-R{6GhW34wUrGYn5KL@(~GGWgy?xNx6F$aMgRaL;fM*AdnQVf1{YCwznn zTzz;yh%owAqz9f1lensoW)LB|O)&&G3@uzHWes5zS1;}vCio0`GECyyhkJ$@Toq_v zhCJ6Ji+hG9t}5_6Lkm|g`5$2d*C6hb3~@!#E(}96fE(@^TDWS!^9&QX_EC-yCUIqP z&oDj{X&|Qzqq6`X_Y9M`j^LhQcs6hVpD;|~+CrW|IEX8Ydxl}qW*_*6A?b7k_v63c z9|cVO+|XBw7K~wAp$@x6GsYX6@wv7L*7moFJ8-ol_BLD`ZCow0Ep}(d{cLeD?CLN^ z@K*{GPhB_^m_L12B^HYd@%)$Kee(TvVhL2cX{Qd08nF!d7lb{kwwct%P{7D$EfigVjUiVsyoVP` zK5sz&PEek4-k*wJi!xNZ@p-*$aa9vOufg*M2~D7uZ4&<4938#z+5ktD-;NaMb8O6X zxvhYwzFn{KtpmIcNfDJ^KWnI@QVbZ7y8Jbx9+XXTL z>6~YkTk)gF$r0s!ei3<>$l*^1%G)flxt4T#o*?;qXmN~n-Q5)$(MrK4w`M2)Kkx1 z{Urpt{ zN&oTrIz@-^`8q|1|G&-GX(cm%*MG>vIsf5S^M!TaJ8@zY#;g387=Ns}xx3Zd3Hh+UZ{d?BlpH_WP*){w;t#9oL}!K4QNgK$|3SrS11A`@I30ab0@KelKkL z90TlOTuJ+VpN-GoqOOnQO4#o+_WS*Km%yRe&PgNb7B%M3)cxh{@A|+!XD^`3WQw$Wa7FT zSHUmovvThal{ojm3FhvtPn?mvk9_Ow-2JRyP1g5`kN2Oe@6D&aF-_eEzWMB%Ke~YT z1HX9gAK(1+cdxh1?5DmIzi8jzKJ&>oYw*_BX8+{8kKQotXWOlfAOHTx>dz|q$c3N( zly&Tz$%bF_OuoNo+gGh`F8t@c|8!#6Tem#@U2DU)Gxz;8@$5BUduU(nQ}^6{;{{iI z8H-p?hc{rJ(PXSTfQj7>cs*mTFUjn_5Rz4X{aS6p@Z zlTZ9&<#mt!Du#GZfc!|(d=(Cl09J@#+6edc4s zuU_!YU59S{VWMOCvw!_p=7)SMq6cTgBPql`JogXJso!rGZ@jwf`;W%?XL#|uny>ng z8$R+^9h0~J&*E==x4LE8i%oC(%JWAT51u`9$2D)h=J979`>(~;-Y>Vcf4=1FfAN8z zExzpPr|Rzd$v^M>=D+;s;-_DG?H^-1$~Qmv*_Reyy8PXTuRHjSogaJo*~JeYTzS=| zhJTp)jYmGe_(!*WZRZtB{`UO+|Fm=QteM|_@u{y}H81wzyB5c8eCL7p?_arf^53mq z{QdvB^dl3#@!&n@{I+57ti^kNdc~d#Ub%bU+{N#EeBh<0nzt?;{Nas@*8b&$=Vq?j zy#2%jJy$>Qn=7Z?wRU#>y!7J>EAM^2X4^G?^`v<1`&a#YZ&UEi`;Ywi1AF~feS61} zx`|(Yc++3}+a*_CwsHCkGyiS=e=X~K*A;s|_>J_<|GH<}-d$gs|6=PC<&UlSn}&CO zB~(3o*-IC{ZNUvIKlhKf&%Xbif!*mJJ^jAl9{Kk9pZd?NLCMTo%l^NFYM zv<2_KjENr&1$#*?Uh8mJxqFJ2gc*Dc5J9q_CzwMXd6i?jjhUXW?R@Q8)Q6}T2)Ut<{W zmy2_ew;rR{^>QrSA@20}qOJp^wSc<;KjC<}Sdamy4d5IPPoV8CwRtx-r6aVC8$81blm!0RKy*k1&jhqDyeq z;0^zo;5?4UNr_g8We2ECzs-7?i|OXc^cTy&qzQeASBf)HCTXU;6ZDX@yQr}e?Y0Wu zt%!}~CGc`B$3OlOfNbENeof{gjpCpsYfmibGx{_zJ9&CuBB?# zG^1p!Mw7VTV5cN~iG^+pJ}K|wXmxlmJf+xy2pIJLY?7YG>vK6db(YTyp941D*5sQT zP;+9Zc!RCLHog;WO}efpxq$E41!d*8@@Q>L7!9}#NK*`D>6$tm&*L5-^k^|+Lhl(p zln%FI1y>*yC`XDY1bhvyLEIli_-$MZAuk-4Ttr*9MA_^Q;XWNy;|AKtsk7ABq6zoM zuTtZcr*K~Z#As`qxE6ptXxDGU)wdEl2w^$w*h8z-_~2UHFNiAJ`8nKIG%I_5Ds21Z zSW!hAe+#ak!&u_@hU1)7+tgTUaaM>=d{Ei%dvKrl8?FU2(2Daw@f%U&7--*O`^5R~ z-SDz?id*fw^@zCz{}!T6VrcDFDVHtykRekn#2ab_#!*@q$y^KZ)Cs7Iz;*n0EBLMq z)Tb^mk(OZ#?#O}b z2U5|0+KgxVb6Gxh73U4++xboph6n<4*;7B)F=r z$knWym%G_#kaL_8HQ$?(x2U^J)R^tbe(OS;ukz(V*Ns|`K5I=cM>3TBaF&BU_-$-2wQ^m_u{FfKy$N}9JW~-^0(S~x;&I!TL5KrIV>jon&%sY(l3=ce|;sO zH=uNuNexT9y_D8iY6-3ej2lt++i|Ix!Q!=~E?AJ0G2L#?Oq1f6dcbhB6!Baxu~C$z zW?&E63~D=a>UjTIvYxpjJaQL%6s=DbudvNImqSQO8!8DHnM(=DEAyjkTWTuB)%m(u zbJR#&O-URX4~2z8Gt=fe+9is9Lg%%eGYIyDdx2U063#lt(pJu*6g43D%NxwzTlnJRSQt+BNKJ zE1{bx1tW8n(ys3Qh`dc%dVTPmx>opgAEf0&Lv&O7)MbRan00ix!mCqgcaB!$Kc*Zh z{iUT^+bs?~ytd2f@1K+$yUWuu%y1+*J{b+A+FfZ^ZF8tz;P5^*u+v9G|Jthu0F)apb`KdOH@Qrfo3|PwSu) zc{j_@v1bbE_ejctpWSeM2TMt(0+2=&je|5yT#EB!&V z*Od*ZwDUr666vQ#t0p{f<|zLzMqF(XOR7uSgdCZ#M0^DPvj}_)Dh!LurSHu|8*p@- z&s*dn_Bx|EZkha^iQ`Y!nthrYe^YZiu&mbw%gMhgR|hq28yzG1g=miz!^*L78s8vH zja_EM{#}n+3&(Pr`hTcip5CKk66S43N;!F0`L*2k5dBl_y%w zYy9ziF&qz#TN8SWS$y20cy`>H7`GR4D9hVR zy2lCH;yWGVaMtRNHIFggce+Os<9(;%@$r#(p=V%xBwlPJ&bhH$iuMy)=W_OyBg9kD zw0eXE;03zgy*rV<80{A;9BVlkP{%9%&e=pYALiag#}T6gNzJL|_it}Z`%}j|Sg5%i z#bd?%uxgB@#?!i|aeLD_e@LI8v(AF>mCux(?~~Q)D(%U8PrW`?6XmFXZ+xC?d}J~{ zG8rG4RL$0oY=6`1QdmA`UKyi2EqcaeyifS^=@U5S$X|Eyhwl-_b^W-mrygnlKcnl% zS~ESCuJ!6zt=)0XLBV{s@~iWtrLpXO?WJhJiW2S^;+m3Teir40Q4mk3kDaiCJF&Wk994^V&FH1v9%8P-q1T0_v>=VM|7H!| zt2IoFyG^c~(Nu9$oU1X_%sJPyjL({L4WRlrk{5|1$gy@!jQ2z1Yw+A&)$uiWTB=Sa zq{cecHF#tDrcR|V7=7e{y|M*kk0roapJ7+5cXG#5o4a)|pPenij#`Fl5=-iE!8I?IqdhdZ%iGk^Y_y%YDD>NS(jifXm1_*CWzoPDsT zHe>LoyU%reCWC9eoz>B9Epc)ylSf)9O_*A3iau*U;z&h)R3Dp^EaF6-P zK;(SwCX7(IN?OBY-h7;$`W``jSJ|umsk!yORX47BwXFmb^>Qo(rxi}0ec)IJ%Uo8Twhqj3`#|o5%|8cY+&&n$ z57ap^oTnHcO}g#FvF=~rXmTX`z^kc8vJg(jKH&Z`=iKw(pM`Kb?Sp)rb-(%Z(`X+Q zmZ2>KZ;aDBxqIo+Yy?umo0ju^g=Z3tZX-B$2$B# zaB#Tq4dYN;dQ|I-#yJ{aeX687Z%X%z`BYK!o@%~Coy|?n$5V2-mc;R3s&tN?X?Dqk z=A~Jvb0hM2&wx_vEH!1SkVcJosBgKBMQIYX7l~i+Q~HDZ4iwJ$I`>j|y!8p>h56mS za&^zq9(ha4xg*OOZ?0!5Mjuj{^`vC6{`#B|H!VhnT1+=-h$cRf;_#TRGikF7GR)pb zx1!c(Os)I9YF9e$7B=mJyC~Fb zhCb=DFei0#{x<>Lr+6xwIW=N^@^K_@&_|q~_LhRQYQ+>asM@dQZ?-w@E(Ib0w<+Mw>b9}-4UOGBBD6A>xomfq$G~f)JtX_*8Gi(TKZ(Y7h z&tCC1T%3EM9l)6#Qu;PvKo|;do}s7n@$5IsOB+%+c9AMi=}UJnvJ_|X)0!t&F^95b zxNgHa-1_h3GG+tFlYjPivW7BXQxmB%~sx*O3&~hxKBO+^ZVcf4XZ(?A)!Y z=u)U5wJuozyl%8@0BRn`kFRA~wVb2r1lC%3^C;ObOh?$%oos#b1Y1N?jTB;kuTEjn z8U<&>BTp4_FjtH1M`k~)VClUyT)j#gPf7Mj6&&qS$ zDU-S_iAw|0YwWd*5o_{+YJHv?8b|M}a!p5`>j9NAqHRzOk9<5DJavv5p^}msBF@T3 zz9pa{X{&vN>N^<@`8`1-UYFA$o3( zJ$Tk2ao|ZyI?hDA^RM{oO+|5j4O7b>v2fO25t`E)&iGAfuwvGcyZ0w7H~m$syK#2# z<6UtaN7|i2j1?zp&0kp7pXv%H>X?WqHum*$w;E@=>s5@0m1HZO??{~*?R+TX3|DRsK9_VS2=&$B|czOnrIGR_{L*~X@rguCNeQhv$0 z-B0(fBz4+kl}D=hbpo}fE-FC4rP)+La^87%g#XT5V<1GI3;^V*&@0lY!;r-HN_n zLC;^m>gEJDy~({!X{vW|tWRnRtr@(O~|LM;WwJl#Q@i_CFl;=yKhjROWTQ1f=Ti?%`-#D_K;l!Kk4f&oI})@jan%9Ito9 zFc-h_Lha6Ptgxoqo93pQw#3~%yeda|XgFS?HSg8l&M3-FL4|uQYR&q)W3=@}9Np_m zy_Sj7S8Q@=evS2wsEKz>;l+t%IMmnQF``yxoAT>S%RDK#s*arEwPPJBvG46J+V@^3 zTidY?l}+vRR56s}u08omjU5ynN9HS**@!Y5AV+!^6YJ%zDRHDd&+mol)#DtQsj;P& zoRp#EMy>XCTAj64yP^oYDi69kdzE#dzTt|hX7Hc(>yxjl>@TA8j8?ZkP~Ly;3R7Rf zQkcA6Sy6Vr)_G$|j8i*Oi}hj+G*uL4gr)ge!&P5&&)2YS`jc7_Ky&J)D5H4U;W)KQ zvsg0v0&xKpqlc?G`?Wc6J zS}jKD)%8=Yo!^V(^SYY=^N4fNX~G+mZrQo`Icosu{DYaCfg zpzf+SpeAw8Ru?N_w0>E)RB>8Uo{N10vd}M1?A^WM1=3Ex0JTvXz-vqO0)I!c-*_Fy z;+c`^@!TI35Arc(z`ft(_4N|eW&i#sT^G&G>;+U`QcR zxwVa3X10PpN)D-Uobd%Q8yTa~WQV%a(X*r3bDzkSO-?La0Yd33Mvt*dAK9N)h?(}& z=@TaPj7A8!k#QzC$RD>@9G;x#aFPft;fGK#dQE~`551qr1k#E zgw!#5E;QeY!TqUt`m+fe7cL~n^9>;gAwXSbBK-~=?Py;D->7e1E6O;~ zw0E6;iOtB7-%Azihm@bt-S0T77REZQh}7YV$I-uTNS$~3zgVc|8p+p43i$Htk94X5N^7+i|!KJlNSs*_Z za-7?H;I+No`7|B8GWGkim)IgBTTG6GyZKgAN89>}nuOi%Z%GHlo#6E z7XGSPGOlSG|7s?wa(e!~UR$O~=)T#l^R*_U9plU&I_rDbp2bdUboB0)bMy76Gg^1A zXDp^isk1Z&%Gyv~Ky^>Osr9ywRWs(aUD)R`1;_AeHkG?SxO!0c`qXsAR#tlJ%G_F0 z$8hh~*2GV(f#mG6drc|rf_iB!(66fciDs0iD90HbTI^i!%adN#;h(Zkh$+`Ta*e;E zlVh$F%IELKf*883Jhf_$JEoYHIC|HrdHvwpPfVI=JI?X4GPhgbJL@I#cj5jeFjqTl zNaL-z9QwWwPw$4s!aX=_1A0G*(;~cc^ML;9^VsS17ol&J^~=Y_ktFx3hc=Y0Xyt81 zy^gi84O#nQSS$F&VRxXeZv6G?_bSkXBM8+hYNkU`NUs1Xq=l|W@siy9Mjj>4sF8}7 zgOx10TSvoH;WEk7it7kPQ;9Wk=NhX7r@g)KId@2YEiA#!BV*Tqt)a#ynv#x$ICx&_ z;=9pc=F2t5e`+l>=UrKr{@O9Ubedym5s@xVYA;ptIdOEUU@59rYF?)SRJsGOM=wKJ zWt3v2?bNCo)`#mi*2w(M2uNv0uB7Km9(v&ve0ny?jaq-J(G#(8bFb1IRrroNsba~$ z7t6mF$-kBItGXH!>PIg<@_P-nE?jZs>8v?Rrq7XDPpzV1J-K^Y0| zm7L#Ey%0;%sfZbCNZ4*H)ymNu0iXRN*Y_8jja3xUupE4~2Sj~eoW5J7!_+swb$V}Y zIhW5JCU?rRG?g70V;uWqr{!kIT3=dT8??tj;zjX0<4)Y@CJw-#el)=ej`o}@O? zGEto3Y!x?d>VBkF@Iu#GUcs>P;6zYMN~EUsNVRq5iAWK8CDe`_wwY={?FIDmQ?dD6 zHzk~QQNC7pE!7OM>ajErlJA$vGTEQId3&sqyl|X)y0OtCc(>Ln#&^ZrgKfysg_okr zrXki`!B`BMwuCrFXN`(M(3s_GI%-GN23~p;$54BdymeNqzcglJbF$`Ew#CiRVeDa@ znicB{l4{{?Ci!y!L{d|0n^Ywd%=mAo+gl3Em44JaLA^bOGt%(Z*|Bv-8c&+o&&&RE143uSUJEr#hHQDCf66nyvJVx{O^QIrfy0Bsc2YR>#5 zu~8c3RLZ~Ft|7x(S<_Q*!O4OtLi_l&S`Hz^ew&WVFUQ=>( z0phui$XWfsH+*+;6j$wfvCQL?zoQ@uWH#->YtImIc%RNc~FtL)qha6W^Vf)2-X4zpbp^JgoolGeIgL-JYs zFeu6Fix^M8f#d1P*Y~PrSk^(5<#@I8(-8*ejg=>uV_;LB6y=P#wXLSGa<83Iy&`ea zzF8-&dybuN>0PE*NO_gDo^zM&^);*AK)M!Ok1$#t=$CfG(qnnnfA>U1>#=99)%gP4 zqosC^E5ES1*FIenJs-UQ3v-shdbCEDz0X|rRAbGM>vB$J&T;he=zrj88|+iO7E=CN z0FEumgH8{p+d$jQY6L{ia@v^OunPR4MppU0J!dZoNB$%2{i7d?W7dlSS?!0=UiRW8 z($+bdG7EPZ#(*ukkscn7%8Ks;$hV_(kMFd)ny*l6M~i=JLg{ViFE#5(`vBEmIF8wg zo2DUYL0UK4r)w<3{C_Q0fAIY3TkJ55b57K(tS*V=jJ(opuAOgmoJWS?wg*((HUnSf z8zbLT$uDnEio2z>DUPG=xD#*4CDbBnb(aM#as&RYLT%>COV`025|?Gj<@FA!{pOBs zQXCfxc~5PYHsAlPxSCv3e4dOxEPbAiI-iCo*wI>KO|{2B?*P{F8h$xDhuuLk8wA&zrK{zpnvgL0h}dyeAz!R=+#eU73H zEeGXEqbAoSs@hzXdmg!bWqoMBiBk{dJsk-f)o;*yL@$k&RIRbdk*ep_GfNI{YLDi{ zzh~T(92dh(=_gXpy#rX|Re92QtpEhJ_~?{!c86%{sJ789HCoH4wjqtx91LmAUPb$R zIdUq-F^cDu6uIq6B^hpuQp<*tSN1QQ+i>>s-zSRMLr(9;b%Dk8p1ViWHCN@oo_>e+ z0@sD9wU5QQQkBRSae7|2y|EAZSHjNWIce%lNAEgFdT=|?8*2Q#c9mKgNt-Xf1jn{2 zju&~b1Npd~Y2@#&Xp2e!d!Ezgt%XxYacVndjP`98rwp#ub7-OZ2TCpJt9r!IYy&MT zY?Z>_M0iA~pVdi#&7wT-S>sAgsqNDg4#dd?Z;HV@D=(E7YH6M| zP2N0PzN3$co&eQLxUp1qJu5G#7w$wEOCF(KVC~&{Lg`9!gB$Ldo-|%~h4lTCdt(am zIFJe^&16+FnruzRlUtIBWN)%B*`G`%_a#%wCzI*qq2yq4D49tfNk#^m2BHJ41Mz_^ z1Brp&fxdzMf#krxfz-g01L=W71A_xY1DSy%1KEM$0kJE%E3~U(m$|EIS9n*=E^Alg zuE?&YUC~{wyW+dH>`LtF-PO0Ne^+wXzFnzZPwq@lc315V@3wX~ z?rz#0-5uY(Wq0rHzTL^)`*uIMJH2~w_t5SmyR*B+p5UH}J?5V9o|-+4dm?+Hds_Ew z*^}7Qx2J#4zCEcu={<+`4DHG6$?h566WklxYwoSuTeH{N8`;~mw{>rPFNzxfjZ}d{{vklN6Y{K literal 0 HcmV?d00001 diff --git a/branches/WOF2-3/OFED/WIX/openfabrics.gif b/branches/WOF2-3/OFED/WIX/openfabrics.gif new file mode 100644 index 0000000000000000000000000000000000000000..148d87752e676f4fe97573730f58cc5e0182878c GIT binary patch literal 3660 zcmWNSdobj zLv27|5LiVtprosaR{)i9%0z;S8WFp}d;>{sqdG}LQ(cR^iJ(g*>u5s^V)Q7w`kN_$ zS**5^&1NG5z%*6Y*dAwm+<1$Tskw=&70cYx+{)V0cAJge_HEnk?T9;b0a~lW4tv14 zLv_c^9shGgJ2fdd-v!(|RNV^*F886Hopfg!&Bc}E`q0JIS<&l(hFcrM-4){3OZ0AY z_3(1{bR+q6Dh1rz?d9pk+zlLjuD$OL5HiN}*#m@*d+%kc1@!>o<9mI56v9XT@$&_u zUl;}5F$(DR^WR5i^%EmT1A_cXkz=U1@t^~NAp50lXfG@Dpjp%)<;WQ6*uSCSArVoB zw2!~odUTK)GY}OWX>n{^|HQwJ@y`rTP8^LpVwU=^!>N}pDZ>eg$KsPt_?&Lpnm(1B zay&4#(f5qhlQ-g+HMuL}^~uvIL22UCsi%T@{i)nD0sIlKyf$ST)NPy(zzPDeKyOcI|?&`ljgW<%&vC!Hs(UHTl)5ij(zo#W%%y)ssba?boWS z1a-31#&>wKJ@nWh@X7!c=GiA;Jbmx{g0mxc1wpl zhCWH8OTE(f&xVKkM#tJmze-+we?B(S^WyW9SN{%lZI3rXEkO z4o!Y}Gc_?RUwJK?o|M0NKJ)#R{M*afuamQL)3dVixu3GxW%=8M*Yn?I-_Fb~yq{eB z@pfTue(~*p3qR)GeUyLrwfKHv=F{5Zr!VtMKi)0>USD6=`2mMufpx$H1pq+!Unc@e>}@BN<4tdx*DUUq$X8xnL1$BDc454ek<#ACGdh)1CQA zc>)GbUN^kFYJ91Qu&2a)p6=N@Q#aI7>~Lmy`xlqeXyT2oKR-hQ=JV{5rx`7c^Zz}( zwMBj7kKQYNz837amj&JWmx@MHu-aM#)9h`V>x>Qz{jTsMN_QMRc9@rv$geb8<2;>Y zYwR~@edv(B%ZbW?s^_1)c|I*)-{<mzSI|t8IZ2+_U`7A+QML3;KyaX+{Z_=K}xh_!$!>#mcV2vqxh<^O#^)IfQ^Ybe#^2C!I>0heR(nPo zZ3e884Q*-PSBH5FvlfoJQ$V2ZvRj%Y+GfqE;-!>WHwPwsdyZ)^mAYpyEbo#jDczQB z35KmEI(?N9N`g!&R#Mq_7gMQKU3_F0@hR2DlP5HHoS(!UndxP?%7K5LL#oPU+g;e3 zeUv;d4zU-L@%G!D8*Mt(vHKZJ>%Q!l-s%x&CaeoAO2eV;u3KRJDb9rwNx7HX^$)w0 zwlAb3169h8HVk$JE)Qw!>%7cUpc!r*A>NBkxVQ2?=2=15)ax>@!jXay-%lx<2DAWv zWP$HXz=VAmqd6fbtmp{!uoIVEEU4V_6%KyhSf;;PZ9h;>fkLQM%mlNoXumiWkg{AZ zAc5D1y5ck~$(XcA`dLr1=i1?m%D9zGd(xm#xA}JYTjOLZ>E3`ISR;LO^mt*Q3Ofo2 z;1q0)&&IY@Cux5f-ZjToV8n)IYFWY`PV9wj-c3=rTAj{F5MxX`J#_USpVw#6ifDEc zZ>Xq~xM>7uVUzp!Zk-$`iA~^e7Y*bR`=}5MGa<*|gN%N`i~_(oG%cmiVcqaJSPa;s zUcM?6XvXLJE$4)tEykVP(si29knFBvt~c44R3#m5?Gb>dmahht8b2{K7FvE! z7pWnK`M9Kw9K?Kx&X;~4UQ!Qsqp{w(Q@R;l^hy+>#*N`5sXGn2pA_B2MwAeVr?oGv&AR#TxjW4xj7(Fq@JRY(y)r8{o^lIJ_QdBbYW z4aXcQL@?&O@#bnNvt)4ey8X%xW?rpt^*wEt#WZ2Su-~ZFI44fgStC#>#sS`hjlxkh z8$iL%fQszaS{{2nif`O%B|OvCqWX%AHk(k-6`?5_^@a?`h(>{nER;MW>(Ozx#HEco zDcLjA)K6Jtas^H(Ul~+cNUcj{L2vt^>y6Cc!4k2vDhzSo&L=u>BVTz-2WgE#;z%&O zQW)AFbW-Dh0&Wxp8(ISeYb9+AbmulGp;x((%s12Ins#!a$EwAsv>FJ;?w6}&Lfqrj zQ72U0DrzS=#@&+~BKSb%;Tlc^P<{_+x-m0oO>DT8fJ>eM=&WA^G`aYrcCavwdZr-V z5nZM1Mm@TPBShV6(2Mw|pKcGg3gL;mQ37(mb^=+L#PK7`sq|X2inJ6J_$EeML)JPs zV61Qk%{66Eo^TY%OeT32>@tBv^C>-T3b7>g##%Bs^Ygm42Rfei6OvA+z*X$q^sG+- zmh4q>`+A#6y_tNHw|^tacit>|-3F(vQKfKh-gWI1p>C=Js?)k&L)S#=@_(&`5&Hi0 znQ%CHX_}pi7y?{*p9z>SFRCo*Z8Aw<)q50=YYEl*59P?QlxDw{Lvzmm+xj7*wZC(y zPLemuLwy!><E2*^n{zwNeWG=ScWi{#%_ z`X+Q&h9TqUAoA|_9VlLC%(*}JJ{|c=t?>Zknt!xfUPq~1Qe^3W3d5WMx5f985p7x& zWoq1xoJ0;fA>9dYZxMY}Z_lBq)iXE$sG&cO;ieM5la}B&=)zB0S!|nbMb~+2j`yFl zJE$Srd!BvWDPDtQ7&SvRUo(5tze;o2&AJ%QR&;dMZiK&Lm6p)F|3OYY?10}H^3)Rd zwry&pVQC;aQwU#<3#0=_f|m}iixBSL@a;?sDi~lGy$r>;(I59Ujc|OEA)7{zrvEzD(E|Y4H;v|r<6PksDchoftmyh!4oB!ct8nl$;Z$T5dttu07|5gb)h0C6;#Fr7bb%? z%xv^94xqwz%98b6p(~=8ATT>k0A|#H)ybd{AOF`_?C*dzleOZQ)H}CW0RJh%uP!N}guz+!9_w+sD-qy;0A3IkfUv{^ z5=E?A7GL0F6$eHG5LG5bPgF>h+7xO=fGidoMT17@gF)0B*yoUS3oIzxh5W3R!vg>QROR&P=T>YV_U6mwYn-( z+e$0?NGnO_jExe_XDcFAREmE9;n68zY2}Ybxn|^3qEsglH~f4!-+Ru@&Ao{Uf@9mW z@AL57ocEmb-uHKZ@B5x}&q)9nfPZsS0n7am`xL+W-N@=JOjBulf&L|sQ>Iw;qY?+JD!b#xcFz`vtQf~ zrO!PGho1+?dp-)v#t(*yN#B5R&;1;9(w;@Z!uQIF|M}ocgsKW~L-V!<-?|IR8GF^->Bnza9zI z8KYr#Mj9N?dJ-C59S&y}4uSN{4ER;nuc2wtFgX6&)9|OcT9{+Zg2siT;LPGD;N*fh zIQu&#ygL6iIFtP(G{5yzs9!Q37XJ1(u=tGyP_lFyaBn{iivl7m)djX2p8sVLscj0ty z2CRBN2TrXqg7c#!SiLqE)~s6#j{GdR@W&L$TmJ#HZpwo7=6pE!$2VZ7%;Bu<>IHlx=+v+@HJ-JM8OV(-tdO3pPXH_B?QI zeHS*{w!no#e8wH?p~b!i4t)9{*z8;3{HHl^xi}l_pZpi>Dcl6Eow=~@vkmY`;is@~ z*Jg0;`VibD@57FwLMYu`0PXv7VP|m>l$C6SgZu1oaqk8w-t!r_OV`8U((SN&?;fZ< zV1tUXPvPrBAHl%`yWm1u0qpyHKU^)}0M&fo%j|0E4bEF1!qpzz_rHX(9qlnXHTDk z&a=m$$#ELEvrX`~mJ`s?QU_rx9`a9@Orm)fAq{oioq@&)*xubtp-zXaV^TcP9X zCFuG~8{E2n83-Zt`e&8@BUqk5e~G+|i|Cj+)~jKRjEWjA$nvNtjaN>~@d_~|R7f#; zn;JVI1(Eo{7fvsake}h@PBax&CXH8#oV(@mD6+lEv-Dhx(<>*XwY0Q(W&IMbVAS8d z>EXg_yiG*`A<;6cx8;%RTZk8mcw{v#EjS?ZB8tf9Xn913S9?~HSHLP!czBe3SX@L@ zbo8JYK?||6V-;p^b5XR=k2M#;yHkRd6VvI@rwBSytR&`Me#D1G^hS?IE)XFKt0%H1 zM!WeLzZKvdJ?P~a?TT3FX%|Ig7PBe(WE9)P$!B4qn?OZ5>Fsj?9USYv53)_ z>vIW_Vg=_#6eW7mq+(G-i-=`Z_#T4#u#>eUya*Q+?Q@AgmS|Fp7a_SZzUUI7h(IMD zFHdA*C*iz!Tm1@Aqf9EERGYNA#~l%hWJlHuFYw7UbJ$x(vd5UE37Hy zW!GyoiFB3gjQ6f<)_4t;T+*g5$8IiO?;&n&A&RRLc=M|a*WFs3R-0Ojoyo7@#{q2x z$q6u8Pd~J)04H=5N|gcOh!)hs?Z`~%BxnpQ2@evi`F5<%F(k4 z;fyaJotmAzo>k9d(Rg|EJMEMgkLA!U&(F^{%%R-&6LQV48nIp{i0$SKMpDFD!ee>#xtNEG3bHjX<6D}hp{9d$A}_rav1lIB z;vjkHgzVR1GP90k8k-9vq|P)W5n8zT^2C)C%Om6lvdHgdp=+fR&VjRv#fxMh{%Yj4TZ^-R6&-yJ zT12e2_#E1ijhh&jhfY0WdGoMMZ=|eQypRSfd6~?G#HB;GxhO2nd6JpT`>=Z=ZDHxw z;&fm|#3DvLCVjOApT84x{+1Dw->PqCS{-@~-O@<%5UJ=gsS63^)xBI>i&!-04U5r- z28>mqb}@SKY8OeKi7upGlwfrlHAZ9nLhR%;i79%dMXZ{{q@<)q?1-nEBFf9Ho0goM zj2C2% zZ2u$6J*>aqyZ^s^=+sA--N}b_MQ87z(kman943>=^juG-IE%?-E9F+3QOvx8t-H7oYgjXazFmaUQHr*0rXtSUQD>o^v;_}aXsr5J zW;znzXF@4au&(bE2pyG3#AdNbV&pkUnVGh6f{LULh1HS50u`3VHgdijRt{olV;X5s zBlDQ0(l^S4_9E(4-l_g0A+WqQV|~YG;jWG}1}01EXy1mpX9;Gr2~)+o&KmFxp>iXK z8H}Y|^0M^g!+zs6 zSa$ytuk{?Se&aRd+bX5<*|&P+W$r^B_7Jb_PpgzFm0CIfiX?^sV*l`Jo}pACmJ&bX zJ_tY%oBa{5tMh)MQmd3Bo*buADb=c}pNr=Gq$8$2_>l9vRcL%Lijf*RFxK?iXr&q( zS(0AZV#gkc_W;{&ivgQ3Z)EG3SdYO1K7Qrg}GM72=KCk3>37w}>jx8p_ zy5Y(~Vrup1t+(kSuRi!NkeBC86^+oy_s}lGve9+p#8jFis;PL?^Dlk!A?JVZ)~C^^ zQaO*Fycia4W7z!K6o-$XRPh7iJx9!aSbP0>y@YX5t7n|#jR`(vt*&Jw)fl#s4I&Uq zm3O}$PQbXt`NBf61YT(O+%MIb{wD&lO8q)Qy_e~`a)qDfWVLdJFWpMQ5er|uH9nQC z=te&*5AK9}|NfFGq{oG+YUMnyWlm3b2$=J@0Tqr5Coy7DtU3#BMtX-;5<$&Lj|*cl z`V6Zx4N1vlVa6SFyJRimj|&c*Xd>3x0vy7fu#Yw`1mABEXCgHy3x8EmAFJlER`8p) zm~ujJ14Avc?NWophu(uk(QR*m5Lo#ALkvTc!8JqJ7JsPU3NGB5fTf3R*)VSCaYBQxG@Y#mgc*^eVc8q*<{|voy7Iz5begj zAtK%8K6XbBSmdUW*$zwO2*I2m#&*K87{3ix6LqA?w0<1R4X(&c_wxsXpZR*i!Y^v# z8Cv*KGGXXICdzNypH?Cm+Mhf61UpEWY};-N6k`=?et8G6D&r#*^$-ubNF4D=o>EH9 z{Qk#yj==bZ+@Idz{6+1pAkTa!V ztZFSX!<8aU(>+ePDkk}C^G`;XUbT*y`GbpJgC57_4zVr z(c3&EYv`jZ)oQ&2%_t< jk-NnTFw?8%KNTzF|J2?axaWa;9=PX$dmi|=^1%NB`Qusp literal 0 HcmV?d00001 diff --git a/branches/WOF2-3/OFED/WIX/sign-all-drivers.bat b/branches/WOF2-3/OFED/WIX/sign-all-drivers.bat new file mode 100644 index 00000000..c6b1039e --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/sign-all-drivers.bat @@ -0,0 +1,149 @@ +@echo off +setlocal +rem +rem Digitally sign all drivers present in specified OS & arch folders +rem +rem usage: sign-all-drivers CertFilename CertSubjName {OS arch} +rem CertFilename - full path to MSCV-VSClass3.cer file +rem example ...\trunk\OFED\wix\MSCV-VSClass3.cer +rem CertSubjName - "OpenFabricsAlliance" Your Company CertName in CertStore. +rem OS - one of all,wxp,wlh,wnet,win7 +rem arch - all,x64,x86,ia64 +rem +rem XXX defeat TimeStamping until net access resolved. +rem set TS=noTimeStamp + +if "%1" == "" ( + echo %0 - Missing CertStore Filename? + exit /B 1 +) + +if not EXIST %1 ( + echo %0 - Missing Certificate file? + echo %0 - %1 + exit /B 1 +) + +rem already quoted +if %2 == "" ( + echo %0 - Missing Cert Subject name? + exit /B 1 +) + +if "%3" == "" ( +:all_os + set OS_names=win7 wlh wnet wxp + goto OK_os +) +if "%3" == "all" goto all_os +set OS_names=%3 + +:OK_os + +if "%4" == "" ( +:arch_all + set ArchNames=amd64 x86 ia64 + set ArchArg=all + goto OK_arch +) +if "%4" == "all" goto arch_all +if "%4" == "x64" (set ArchNames=amd64) else (set ArchNames=%4) +set ArchArg=%ArchNames% + +:OK_arch + +echo. + +for %%p in ( %OS_names% ) do ( + echo %0 - Signing %%p drivers arch %ArchArg% + pushd %%p + if ERRORLEVEL 1 ( + echo %0 - Error in pushd %%p folder ? + exit /B 1 + ) + rem Sign free HCA drivers + call signDrivers %1 %2 bin\HCA %ArchArg% %TS% + if ERRORLEVEL 1 ( + echo %0 - Error signing %%p\bin\HCA\%ArchArg% drivers? + exit /B 1 + ) + rem Sign checked HCA drivers + call signDrivers %1 %2 bin\Chk\HCA %ArchArg% %TS% + if ERRORLEVEL 1 ( + echo %0 - Error signing %%p\bin\Chk\HCA\%ArchArg% drivers? + exit /B 1 + ) + + rem Sign free: IPoIB & VNIC drivers + call signDrivers %1 %2 bin\net %ArchArg% %TS% + if ERRORLEVEL 1 ( + echo %0 - Error signing %%p\bin\net\%ArchArg% drivers? + exit /B 1 + ) + rem Sign checked: IPoIB & VNIC drivers + call signDrivers %1 %2 bin\Chk\net %ArchArg% %TS% + if ERRORLEVEL 1 ( + echo %0 - Error signing %%p\bin\Chk\net\%ArchArg% drivers? + exit /B 1 + ) + + rem Sign free SRP drivers + call signDrivers %1 %2 bin\storage %ArchArg% %TS% + if ERRORLEVEL 1 ( + echo %0 - Error signing %%p\bin\storage\%ArchArg% drivers? + exit /B 1 + ) + rem Sign checked SRP drivers + call signDrivers %1 %2 bin\Chk\storage %ArchArg% %TS% + if ERRORLEVEL 1 ( + echo %0 - Error signing %%p\bin\Chk\storage\%ArchArg% drivers? + exit /B 1 + ) + popd +) + +rem sign executables used in installation so Win7 doesn't complain + +set TISTMP=/t http://timestamp.verisign.com/scripts/timstamp.dll +set DU=/du http://www.openfabrics.org + +for %%p in ( %OS_names% ) do ( + pushd %%p + echo. + echo Sign %%p Executables for arch %ArchNames% + for %%a in ( %ArchNames% ) do ( + for %%f in ( bin\net\%%a\ndinstall.exe bin\net\%%a\installsp.exe ) do ( + if exist %%f ( + signtool sign /ac %1 /n %2 %TISTMP% %DU% %%f + if ERRORLEVEL 1 ( + echo %0 signtool sign %%a\%%f failed? + popd + exit /B 1 + ) + signtool verify /pa %%f + if ERRORLEVEL 1 ( + echo %0 signtool verify %%a\%%f failed? + popd + exit /B 1 + ) + ) + ) + ) + popd +) + +rem Sign devman.exe for win7 device cleanup operation. + +for %%a in ( x64 x86 ia64 ) do ( + signtool verify /q /pa %%a\devman.exe + if ERRORLEVEL 1 ( + signtool sign /ac %1 /n %2 %TISTMP% %DU% %%a\devman.exe + if ERRORLEVEL 1 ( + echo %0 signtool sign %%a\devman.exe failed? + exit /B 1 + ) + ) +) + +endlocal +echo Done %0 %1 diff --git a/branches/WOF2-3/OFED/WIX/win7/build-MSI.bat b/branches/WOF2-3/OFED/WIX/win7/build-MSI.bat new file mode 100644 index 00000000..d339002f --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/win7/build-MSI.bat @@ -0,0 +1,63 @@ +@echo off +setlocal +rem Build WIX installer (.msi) for specified architecture(s) +rem +rem usage: %0 {dest-path-for-msi-files Arch} + +rem *** REQUIRES nmake, common invocation from Visual C or DDK command window + +set OS=win7 + +if "%1" == "" ( + set DST=%SystemRoot%\temp +) else ( + set DST=%1 +) +if "%2" == "" ( +:all_arch + set ARCH=ia64 x64 x86 + goto OK_arch +) +if "%2" == "all" goto all_arch +set ARCH=%2 + +:OK_arch + +if NOT EXIST %DST% ( + echo %0: Installer output path %DST% not found? + exit /B 1 +) +nmake /NOLOGO /? > %DST%\jnk.txt +if ERRORLEVEL 1 ( + echo %0 missing nmake.exe in PATH? + exit /B 1 +) +del /Q /F %DST%\jnk.txt + +for %%a in ( %ARCH% ) do ( + if "%%a" == "x64" (set HWN=amd64) else (set HWN=%%a) + if NOT EXIST %CD%\bin\HCA\!HWN! ( + echo %0 - %CD%\bin\HCA\!HWN! not populated correctly?, abort. + exit /B 1 + ) + if EXIST %%a\OFED_%OS%_%%a.msi del /Q /F %%a\OFED_%OS%_%%a.msi + pushd %%a + nmake /NOLOGO full + if ERRORLEVEL 1 ( + echo %0 - Error building OFED_%OS%_%%a.msi ? + exit /B 1 + ) + echo move /Y OFED_%OS%_%%a.msi %DST% + move /Y OFED_%OS%_%%a.msi %DST% + popd +) + +rem if run from top-level %1 will not be null, otherwise assume run from +rem cmd line. +if "%1" == "" dir %DST%\*.msi + +echo ---- +echo Done - %OS% WIX installers in %DST% +echo ---- + +endlocal diff --git a/branches/WOF2-3/OFED/WIX/win7/ia64/Makefile b/branches/WOF2-3/OFED/WIX/win7/ia64/Makefile new file mode 100644 index 00000000..22e32575 --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/win7/ia64/Makefile @@ -0,0 +1,9 @@ +################### +# IA64/IPF Itanium makefile targets +# +S=OFED +A=ia64 +P=$(S)_win7_$(A) + +!include ..\..\common\Makefile.inc + diff --git a/branches/WOF2-3/OFED/WIX/win7/ia64/ofed.wxs b/branches/WOF2-3/OFED/WIX/win7/ia64/ofed.wxs new file mode 100644 index 00000000..6f7c174f --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/win7/ia64/ofed.wxs @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + Privileged + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/branches/WOF2-3/OFED/WIX/win7/signDrivers.bat b/branches/WOF2-3/OFED/WIX/win7/signDrivers.bat new file mode 100644 index 00000000..f5788f9b --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/win7/signDrivers.bat @@ -0,0 +1,172 @@ +@echo off +setlocal +rem Sign device drivers for architectures specified + +rem usage: +rem signDrivers CrossCertFname CertStoreName path-2-drivers arch {noTimeStamp} +rem CrossCertFname - fully qualified path\filename of cross cert. +rem CertStoreName - name of certificate in 'MY' Cert store (certmgr) +rem path-2-drivers +rem arch - all,x86,x64,ia64 +rem noTimeStamp - blank implies no TimeStamp. + +rem example: signDrivers %CD%\Cross-Cert SWPublisher bin\hca all + +rem cmd.exe /V:on (delayed environment variable expansion) is required! +set F=on +set F=off +if not "!F!" == "off" ( + echo Err: cmd.exe /V:on [delayed environment variable expansion] Required! + exit /B 1 +) + +set OE=Win7 +set DU=/du http://www.openfabrics.org + +set Usage='usage: signDrivers CrossCertFilename CertStoreName path-2-drivers {noTimeStamp}' + +if "%1" == "" ( + echo %0 - missing CertFileName? + echo %0 - %Usage% + exit /B 1 +) + +if not EXIST %1 ( + echo %0 - Cert file missing? + echo %0 - %Usage% + exit /B 1 +) + +rem %2 is already quoted. +if %2 == "" ( + echo %0 - missing Cert Subject Name? + echo %0 - %Usage% + exit /B 1 +) + +if "%3" == "" ( + echo %0 - missing path-2-driver files? + echo %0 - %Usage% + exit /B 1 +) + +if "%4" == "" ( +:all + set ArchNames=amd64 x86 ia64 + goto OK_arch +) +if "%4" == "all" goto all +if "%4" == "x64" (set ArchNames=amd64) else (set ArchNames=%4) + +:OK_arch + +rem Timestamp the signed file unless instructed not to. +if "%5" == "" ( + set TS=/t http://timestamp.verisign.com/scripts/timstamp.dll +) else ( + set TS= +) + +rem make sure signtool is accessible in our path +path > jnk.txt +findstr /c:"SelfSign" jnk.txt > jnk1.txt +if %ERRORLEVEL% EQU 1 ( + path "%PATH%;C:\WinDDK\xxx\bin\SelfSign" +) +if exist jnk1.txt del /Q /F jnk1.txt +if exist jnk.txt del /Q /F jnk.txt + +rem move to drivers folder +cd %3 +if ERRORLEVEL 1 ( + echo %0 - missing relative path %3 + exit /B 1 +) +echo cwd !CD! + +rem sign drivers for all architectures found + +for %%d in ( %ArchNames% ) do ( + + if not exist %%d ( + echo %0 - skipping arch folder %%d + ) else ( + pushd %%d + echo %0 - Delete existing %%d .cat files + for %%f in ( *.cat ) do ( + if exist %%f del /F /Q %%f + ) + + rem set OS type for inf2cat + if "%%d" == "x86" set OEA=7_X86 + if "%%d" == "amd64" set OEA=7_X64,Server2008R2_X64 + if "%%d" == "ia64" set OEA=Server2008R2_IA64 + + echo %0 [%OE%] Generating %%d .cat files for !OEA! + inf2cat /driver:!CD! /os:!OEA! + if !ERRORLEVEL! NEQ 0 ( + echo %CD% inf2cat failed + exit /B 1 + ) + echo %0 [%OE%] Signing %%d .cat files + for %%f in ( *.cat ) do ( + echo %0 [%OE%] Signing %%d\%%f + signtool sign /ac %1 /s "My" /n %2 %TS% %DU% %%f + if ERRORLEVEL 1 ( + echo %0 signtool sign %%f failed? + echo %0 file %CD%\%%f + exit /B 1 + ) + signtool verify /kp %%f + if ERRORLEVEL 1 ( + echo %0 signtool verify %%f failed? + echo %0 file %CD%\%%f + exit /B 1 + ) + echo + + ) + + echo %0 [%OE%] Signing %%d .sys files + for %%f in ( *.sys ) do ( + echo %0 [%OE%] Signing %%d\%%f + signtool sign /ac %1 /s "My" /n %2 %TS% %DU% %%f + if ERRORLEVEL 1 ( + echo %0 signtool sign %%f failed? + echo %0 file %CD%\%%f + exit /B 1 + ) + signtool verify /kp %%f + if ERRORLEVEL 1 ( + echo %0 signtool verify %%f failed? + echo %0 file %CD%\%%f + exit /B 1 + ) + echo + + ) + + echo %0 [%OE%] Verify %%d .cat + .sys files + for %%f in ( *.sys ) do ( + set D=%%f + set C=!D:sys=cat! + if exist !C! ( + echo %0 [%OE%] Verify %%d\!C! %%d\%%f + signtool verify /q /kp /c !C! %%f + if ERRORLEVEL 1 ( + echo %0 signtool verify /kp /c !C! %%f failed? + exit /B 1 + ) + signtool verify /pa /c !C! %%f + if ERRORLEVEL 1 ( + echo %0 signtool verify /pa /c !C! %%f failed? + exit /B 1 + ) + echo + + ) + ) + popd + ) +) + +echo %0 [%OE%] Finished: %0 %1 %2 +echo + +endlocal diff --git a/branches/WOF2-3/OFED/WIX/win7/x64/Makefile b/branches/WOF2-3/OFED/WIX/win7/x64/Makefile new file mode 100644 index 00000000..0d3dab9a --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/win7/x64/Makefile @@ -0,0 +1,11 @@ +################### +# makefile targets +# +S=OFED +A=x64 +P=$(S)_win7_$(A) + +DFXP=..\bin\Misc\amd64 + +!include ..\..\common\Makefile.inc + diff --git a/branches/WOF2-3/OFED/WIX/win7/x64/ofed.wxs b/branches/WOF2-3/OFED/WIX/win7/x64/ofed.wxs new file mode 100644 index 00000000..726937d4 --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/win7/x64/ofed.wxs @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + Privileged + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/branches/WOF2-3/OFED/WIX/win7/x86/Makefile b/branches/WOF2-3/OFED/WIX/win7/x86/Makefile new file mode 100644 index 00000000..305d23ae --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/win7/x86/Makefile @@ -0,0 +1,8 @@ +################### +# makefile targets +# +S=OFED +A=x86 +P=$(S)_win7_$(A) + +!include ..\..\common\Makefile.inc diff --git a/branches/WOF2-3/OFED/WIX/win7/x86/ofed.wxs b/branches/WOF2-3/OFED/WIX/win7/x86/ofed.wxs new file mode 100644 index 00000000..e0c6799d --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/win7/x86/ofed.wxs @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + + + + Privileged + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/branches/WOF2-3/OFED/WIX/wlh/build-MSI.bat b/branches/WOF2-3/OFED/WIX/wlh/build-MSI.bat new file mode 100644 index 00000000..5074593c --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/wlh/build-MSI.bat @@ -0,0 +1,63 @@ +@echo off +setlocal +rem Build WIX installer (.msi) for specified architecture(s) +rem +rem usage: %0 {dest-path-for-msi-files Proc-Arch} + +rem *** REQUIRES nmake, common invocation from Visual C or DDK command window + +set OS=WLH + +if "%1" == "" ( + set DST=%SystemRoot%\temp +) else ( + set DST=%1 +) +if "%2" == "" ( +:all_arch + set ARCH=ia64 x64 x86 + goto OK_arch +) +if "%2" == "all" goto all_arch +set ARCH=%2 + +:OK_arch + +if NOT EXIST %DST% ( + echo %0: Installer output path %DST% not found? + exit /B 1 +) +nmake /NOLOGO /? > %DST%\jnk.txt +if ERRORLEVEL 1 ( + echo %0 missing nmake.exe in PATH? + exit /B 1 +) +del /Q /F %DST%\jnk.txt + +for %%a in ( %ARCH% ) do ( + if "%%a" == "x64" (set HWN=amd64) else (set HWN=%%a) + if NOT EXIST %CD%\bin\HCA\!HWN! ( + echo %0 - %CD%\bin\HCA\!HWN! not populated correctly?, abort. + exit /B 1 + ) + if EXIST %%a\OFED_%OS%_%%a.msi del /Q /F %%a\OFED_%OS%_%%a.msi + pushd %%a + nmake /NOLOGO full + if ERRORLEVEL 1 ( + echo %0 - Error building OFED_%OS%_%%a.msi ? + exit /B 1 + ) + echo move /Y OFED_%OS%_%%a.msi %DST% + move /Y OFED_%OS%_%%a.msi %DST% + popd +) + +rem if run from top-level %1 will not be null, otherwise assume run from +rem cmd line. +if "%1" == "" dir %DST%\*.msi + +echo ---- +echo Done - %OS% WIX installers in %DST% +echo ---- + +endlocal diff --git a/branches/WOF2-3/OFED/WIX/wlh/ia64/Makefile b/branches/WOF2-3/OFED/WIX/wlh/ia64/Makefile new file mode 100644 index 00000000..e3e7f49e --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/wlh/ia64/Makefile @@ -0,0 +1,8 @@ +################### +# IA64/IPF Itanium makefile targets +# +S=OFED +A=ia64 +P=$(S)_wlh_$(A) + +!include ..\..\common\Makefile.inc diff --git a/branches/WOF2-3/OFED/WIX/wlh/ia64/ofed.wxs b/branches/WOF2-3/OFED/WIX/wlh/ia64/ofed.wxs new file mode 100644 index 00000000..b2fbf39d --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/wlh/ia64/ofed.wxs @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + Privileged + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/branches/WOF2-3/OFED/WIX/wlh/signDrivers.bat b/branches/WOF2-3/OFED/WIX/wlh/signDrivers.bat new file mode 100644 index 00000000..af6823d1 --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/wlh/signDrivers.bat @@ -0,0 +1,172 @@ +@echo off +setlocal +rem Sign device drivers for architectures specified + +rem usage: +rem signDrivers CrossCertFname CertStoreName path-2-drivers arch {noTimeStamp} +rem CrossCertFname - fully qualified path\filename of cross cert. +rem CertStoreName - name of certificate in 'MY' Cert store (certmgr) +rem path-2-drivers +rem arch - all,x86,x64,ia64 +rem noTimeStamp - blank implies no TimeStamp. + +rem example: signDrivers %CD%\Cross-Cert SWPublisher bin\hca all + +rem cmd.exe /V:on (delayed environment variable expansion) is required! +set F=on +set F=off +if not "!F!" == "off" ( + echo Err: cmd.exe /V:on [delayed environment variable expansion] Required! + exit /B 1 +) + +set OE=Server2008 +set DU=/du http://www.openfabrics.org + +set Usage='usage: signDrivers CrossCertFilename CertStoreName path-2-drivers {noTimeStamp}' + +if "%1" == "" ( + echo %0 - missing CertFileName? + echo %0 - %Usage% + exit /B 1 +) + +if not EXIST %1 ( + echo %0 - Cert file missing? + echo %0 - %Usage% + exit /B 1 +) + +rem %2 is already quoted. +if %2 == "" ( + echo %0 - missing Cert Subject Name? + echo %0 - %Usage% + exit /B 1 +) + +if "%3" == "" ( + echo %0 - missing path-2-driver files? + echo %0 - %Usage% + exit /B 1 +) + +if "%4" == "" ( +:all + set ArchNames=amd64 x86 ia64 + goto OK_arch +) +if "%4" == "all" goto all +if "%4" == "x64" (set ArchNames=amd64) else (set ArchNames=%4) + +:OK_arch + +rem Timestamp the signed file unless instructed not to. +if "%5" == "" ( + set TS=/t http://timestamp.verisign.com/scripts/timstamp.dll +) else ( + set TS= +) + +rem make sure signtool is accessible in our path +path > jnk.txt +findstr /c:"SelfSign" jnk.txt > jnk1.txt +if %ERRORLEVEL% EQU 1 ( + path "%PATH%;C:\WinDDK\xxx\bin\SelfSign" +) +if exist jnk1.txt del /Q /F jnk1.txt +if exist jnk.txt del /Q /F jnk.txt + +rem move to drivers folder +cd %3 +if ERRORLEVEL 1 ( + echo %0 - missing relative path %3 + exit /B 1 +) +echo cwd !CD! + +rem sign drivers for all architectures found + +for %%d in ( %ArchNames% ) do ( + + if not exist %%d ( + echo %0 - skipping arch folder %%d + ) else ( + pushd %%d + echo %0 - Delete existing %%d .cat files + for %%f in ( *.cat ) do ( + if exist %%f del /F /Q %%f + ) + + rem set OS type for inf2cat + if "%%d" == "amd64" set OEA=%OE%_X64,Vista_X64 + if "%%d" == "x86" set OEA=%OE%_X86,Vista_X86 + if "%%d" == "ia64" set OEA=%OE%_IA64 + + echo %0 [%OE%] Generating %%d .cat files for !OEA! + inf2cat /driver:!CD! /os:!OEA! + if !ERRORLEVEL! NEQ 0 ( + echo %CD% inf2cat failed + exit /B 1 + ) + echo %0 [%OE%] Signing %%d .cat files + for %%f in ( *.cat ) do ( + echo %0 [%OE%] Signing %%d\%%f + signtool sign /ac %1 /s "My" /n %2 %TS% %DU% %%f + if ERRORLEVEL 1 ( + echo %0 signtool sign %%f failed? + echo %0 file %CD%\%%f + exit /B 1 + ) + signtool verify /kp %%f + if ERRORLEVEL 1 ( + echo %0 signtool verify %%f failed? + echo %0 file %CD%\%%f + exit /B 1 + ) + echo + + ) + + echo %0 [%OE%] Signing %%d .sys files + for %%f in ( *.sys ) do ( + echo %0 [%OE%] Signing %%d\%%f + signtool sign /ac %1 /s "My" /n %2 %TS% %DU% %%f + if ERRORLEVEL 1 ( + echo %0 signtool sign %%f failed? + echo %0 file %CD%\%%f + exit /B 1 + ) + signtool verify /kp %%f + if ERRORLEVEL 1 ( + echo %0 signtool verify %%f failed? + echo %0 file %CD%\%%f + exit /B 1 + ) + echo + + ) + + echo %0 [%OE%] Verify %%d .cat + .sys files + for %%f in ( *.sys ) do ( + set D=%%f + set C=!D:sys=cat! + if exist !C! ( + echo %0 [%OE%] Verify %%d\!C! %%d\%%f + signtool verify /q /kp /c !C! %%f + if ERRORLEVEL 1 ( + echo %0 signtool verify /kp /c !C! %%f failed? + exit /B 1 + ) + signtool verify /pa /c !C! %%f + if ERRORLEVEL 1 ( + echo %0 signtool verify /pa /c !C! %%f failed? + exit /B 1 + ) + echo + + ) + ) + popd + ) +) + +echo %0 [%OE%] Finished: %0 %1 %2 +echo + +endlocal diff --git a/branches/WOF2-3/OFED/WIX/wlh/x64/Makefile b/branches/WOF2-3/OFED/WIX/wlh/x64/Makefile new file mode 100644 index 00000000..b5cd0119 --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/wlh/x64/Makefile @@ -0,0 +1,11 @@ +################### +# makefile targets +# +S=OFED +A=x64 +P=$(S)_wlh_$(A) + +DFXP=..\bin\Misc\amd64 + +!include ..\..\common\Makefile.inc + diff --git a/branches/WOF2-3/OFED/WIX/wlh/x64/ofed.wxs b/branches/WOF2-3/OFED/WIX/wlh/x64/ofed.wxs new file mode 100644 index 00000000..35103e03 --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/wlh/x64/ofed.wxs @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + Privileged + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/branches/WOF2-3/OFED/WIX/wlh/x86/Makefile b/branches/WOF2-3/OFED/WIX/wlh/x86/Makefile new file mode 100644 index 00000000..cf361195 --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/wlh/x86/Makefile @@ -0,0 +1,8 @@ +################### +# makefile targets +# +S=OFED +A=x86 +P=$(S)_wlh_$(A) + +!include ..\..\common\Makefile.inc diff --git a/branches/WOF2-3/OFED/WIX/wlh/x86/ofed.wxs b/branches/WOF2-3/OFED/WIX/wlh/x86/ofed.wxs new file mode 100644 index 00000000..06cb57ef --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/wlh/x86/ofed.wxs @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + + + + Privileged + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/branches/WOF2-3/OFED/WIX/wnet/build-MSI.bat b/branches/WOF2-3/OFED/WIX/wnet/build-MSI.bat new file mode 100644 index 00000000..b675662c --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/wnet/build-MSI.bat @@ -0,0 +1,63 @@ +@echo off +setlocal +rem Build WIX installer (.msi) for specified architecture(s) +rem +rem usage: %0 {dest-path-for-msi-files Proc-Arch} + +rem *** REQUIRES nmake, common invocation from Visual C or DDK command window + +set OS=wnet + +if "%1" == "" ( + set DST=%SystemRoot%\temp +) else ( + set DST=%1 +) +if "%2" == "" ( +:all_arch + set ARCH=ia64 x64 x86 + goto OK_arch +) +if "%2" == "all" goto all_arch +set ARCH=%2 + +:OK_arch + +if NOT EXIST %DST% ( + echo %0: Installer output path %DST% not found? + exit /B 1 +) +nmake /NOLOGO /? > %DST%\jnk.txt +if ERRORLEVEL 1 ( + echo %0 missing nmake.exe in PATH? + exit /B 1 +) +del /Q /F %DST%\jnk.txt + +for %%a in ( %ARCH% ) do ( + if "%%a" == "x64" (set HWN=amd64) else (set HWN=%%a) + if NOT EXIST %CD%\bin\HCA\!HWN! ( + echo %0 - %CD%\bin\HCA\!HWN! not populated correctly?, abort. + exit /B 1 + ) + if EXIST %%a\OFED_%OS%_%%a.msi del /Q /F %%a\OFED_%OS%_%%a.msi + pushd %%a + nmake /NOLOGO full + if ERRORLEVEL 1 ( + echo %0 - Error building OFED_%OS%_%%a.msi ? + exit /B 1 + ) + echo move /Y OFED_%OS%_%%a.msi %DST% + move /Y OFED_%OS%_%%a.msi %DST% + popd +) + +rem if run from top-level %1 will not be null, otherwise assume run from +rem cmd line. +if "%1" == "" dir %DST%\*.msi + +echo ---- +echo Done - %OS% WIX installers in %DST% +echo ---- + +endlocal diff --git a/branches/WOF2-3/OFED/WIX/wnet/ia64/Makefile b/branches/WOF2-3/OFED/WIX/wnet/ia64/Makefile new file mode 100644 index 00000000..c364c793 --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/wnet/ia64/Makefile @@ -0,0 +1,8 @@ +################### +# IA64/IPF Itanium makefile targets +# +S=OFED +A=ia64 +P=$(S)_wnet_$(A) + +!include ..\..\common\Makefile.inc diff --git a/branches/WOF2-3/OFED/WIX/wnet/ia64/ofed.wxs b/branches/WOF2-3/OFED/WIX/wnet/ia64/ofed.wxs new file mode 100644 index 00000000..7741df67 --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/wnet/ia64/ofed.wxs @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + Privileged + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/branches/WOF2-3/OFED/WIX/wnet/signDrivers.bat b/branches/WOF2-3/OFED/WIX/wnet/signDrivers.bat new file mode 100644 index 00000000..8aea7576 --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/wnet/signDrivers.bat @@ -0,0 +1,171 @@ +@echo off +setlocal +rem Sign device drivers for architectures specified + +rem usage: +rem signDrivers CrossCertFname CertStoreName path-2-drivers arch {noTimeStamp} +rem CrossCertFname - fully qualified path\filename of cross cert. +rem CertStoreName - name of certificate in 'MY' Cert store (certmgr) +rem path-2-drivers +rem arch - all,x86,x64,ia64 +rem noTimeStamp - blank implies no TimeStamp. + +rem example: signDrivers %CD%\Cross-Cert SWPublisher bin\hca all + +rem cmd.exe /V:on (delayed environment variable expansion) is required! +set F=on +set F=off +if not "!F!" == "off" ( + echo Err: cmd.exe /V:on [delayed environment variable expansion] Required! + exit /B 1 +) + +set OE=Server2003 +set DU=/du http://www.openfabrics.org + +set Usage='usage: signDrivers CrossCertFilename CertStoreName path-2-drivers {noTimeStamp}' + +if "%1" == "" ( + echo %0 - missing CertFileName? + echo %0 - %Usage% + exit /B 1 +) + +if not EXIST %1 ( + echo %0 - Cert file missing? + echo %0 - %Usage% + exit /B 1 +) + +rem %2 is already quoted. +if %2 == "" ( + echo %0 - missing Cert Subject Name? + echo %0 - %Usage% + exit /B 1 +) + +if "%3" == "" ( + echo %0 - missing path-2-driver files? + echo %0 - %Usage% + exit /B 1 +) + +if "%4" == "" ( +:all + set ArchNames=amd64 x86 ia64 + goto OK_arch +) +if "%4" == "all" goto all +if "%4" == "x64" (set ArchNames=amd64) else (set ArchNames=%4) + +:OK_arch + +rem Timestamp the signed file unless instructed not to. +if "%5" == "" ( + set TS=/t http://timestamp.verisign.com/scripts/timstamp.dll +) else ( + set TS= +) + +rem make sure signtool is accessible in our path +path > jnk.txt +findstr /c:"SelfSign" jnk.txt > jnk1.txt +if %ERRORLEVEL% EQU 1 ( + path "%PATH%;C:\WinDDK\xxx\bin\SelfSign" +) +if exist jnk1.txt del /Q /F jnk1.txt +if exist jnk.txt del /Q /F jnk.txt + +rem move to drivers folder +cd %3 +if ERRORLEVEL 1 ( + echo %0 - missing relative path %3 + exit /B 1 +) +echo cwd !CD! + +rem sign drivers for all architectures found + +for %%d in ( %ArchNames% ) do ( + + if not exist %%d ( + echo %0 - skipping arch folder %%d + ) else ( + pushd %%d + echo %0 - Delete existing %%d .cat files + for %%f in ( *.cat ) do ( + if exist %%f del /F /Q %%f + ) + + if "%%d" == "amd64" set OEA=%OE%_X64,XP_X64 + if "%%d" == "x86" set OEA=%OE%_X86 + if "%%d" == "ia64" set OEA=%OE%_IA64 + + echo %0 [%OE%] Generating %%d .cat files for !OEA! + inf2cat /driver:!CD! /os:!OEA! + if !ERRORLEVEL! NEQ 0 ( + echo %CD% inf2cat failed + exit /B 1 + ) + echo %0 [%OE%] Signing %%d .cat files + for %%f in ( *.cat ) do ( + echo %0 [%OE%] Signing %%d\%%f + signtool sign /ac %1 /s "My" /n %2 %TS% %DU% %%f + if ERRORLEVEL 1 ( + echo %0 signtool sign %%f failed? + echo %0 file %CD%\%%f + exit /B 1 + ) + signtool verify /kp %%f + if ERRORLEVEL 1 ( + echo %0 signtool verify %%f failed? + echo %0 file %CD%\%%f + exit /B 1 + ) + echo + + ) + + echo %0 [%OE%] Signing %%d .sys files + for %%f in ( *.sys ) do ( + echo %0 [%OE%] Signing %%d\%%f + signtool sign /ac %1 /s "My" /n %2 %TS% %DU% %%f + if ERRORLEVEL 1 ( + echo %0 signtool sign %%f failed? + echo %0 file %CD%\%%f + exit /B 1 + ) + signtool verify /kp %%f + if ERRORLEVEL 1 ( + echo %0 signtool verify %%f failed? + echo %0 file %CD%\%%f + exit /B 1 + ) + echo + + ) + + echo %0 [%OE%] Verify %%d .cat + .sys files + for %%f in ( *.sys ) do ( + set D=%%f + set C=!D:sys=cat! + if exist !C! ( + echo %0 [%OE%] Verify %%d\!C! %%d\%%f + signtool verify /q /kp /c !C! %%f + if ERRORLEVEL 1 ( + echo %0 signtool verify /kp /c !C! %%f failed? + exit /B 1 + ) + signtool verify /pa /c !C! %%f + if ERRORLEVEL 1 ( + echo %0 signtool verify /pa /c !C! %%f failed? + exit /B 1 + ) + echo + + ) + ) + popd + ) +) + +echo %0 [%OE%] Finished: %0 %1 %2 +echo + +endlocal diff --git a/branches/WOF2-3/OFED/WIX/wnet/x64/Makefile b/branches/WOF2-3/OFED/WIX/wnet/x64/Makefile new file mode 100644 index 00000000..a7c28192 --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/wnet/x64/Makefile @@ -0,0 +1,10 @@ +################### +# makefile targets +# +S=OFED +A=x64 +P=$(S)_wnet_$(A) + +DFXP=..\bin\Misc\amd64 + +!include ..\..\common\Makefile.inc diff --git a/branches/WOF2-3/OFED/WIX/wnet/x64/ofed.wxs b/branches/WOF2-3/OFED/WIX/wnet/x64/ofed.wxs new file mode 100644 index 00000000..39c36d26 --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/wnet/x64/ofed.wxs @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + Privileged + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/branches/WOF2-3/OFED/WIX/wnet/x86/Makefile b/branches/WOF2-3/OFED/WIX/wnet/x86/Makefile new file mode 100644 index 00000000..aa206da7 --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/wnet/x86/Makefile @@ -0,0 +1,8 @@ +################### +# makefile targets +# +S=OFED +A=x86 +P=$(S)_wnet_$(A) + +!include ..\..\common\Makefile.inc diff --git a/branches/WOF2-3/OFED/WIX/wnet/x86/ofed.wxs b/branches/WOF2-3/OFED/WIX/wnet/x86/ofed.wxs new file mode 100644 index 00000000..0265239d --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/wnet/x86/ofed.wxs @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + + + + Privileged + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/branches/WOF2-3/OFED/WIX/wxp/build-MSI.bat b/branches/WOF2-3/OFED/WIX/wxp/build-MSI.bat new file mode 100644 index 00000000..81f026a9 --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/wxp/build-MSI.bat @@ -0,0 +1,67 @@ +@echo off +setlocal +rem Build WIX installer (.msi) for specified architecture(s) +rem +rem usage: %0 {dest-path-for-msi-files Proc-Arch} + +rem *** REQUIRES nmake, common invocation from Visual C or DDK command window + +set OS=wxp + +if "%1" == "" ( + set DST=%SystemRoot%\temp +) else ( + set DST=%1 +) +if "%2" == "" ( + set ARCH=x86 + goto OK_arch +) +if "%2" == "all" ( + set ARCH=x86 +) else ( + if not "%2" == "x86" ( + echo %0 - x86 only! + exit /B 1 + ) + set ARCH=%2 +) +:OK_arch + +if NOT EXIST %DST% ( + echo %0: Installer output path %DST% not found? + exit /B 1 +) +nmake /NOLOGO /? > %DST%\jnk.txt +if ERRORLEVEL 1 ( + echo %0 missing nmake.exe in PATH? + exit /B 1 +) +del /Q /F %DST%\jnk.txt + +for %%a in ( %ARCH% ) do ( + if NOT EXIST %CD%\bin\HCA\%%a ( + echo %0 - %CD%\bin\HCA\%%a not populated correctly?, abort. + exit /B 1 + ) + if EXIST %%a\OFED_%OS%_%%a.msi del /Q /F %%a\OFED_%OS%_%%a.msi + pushd %%a + nmake /NOLOGO full + if ERRORLEVEL 1 ( + echo %0 - Error building OFED_%OS%_%%a.msi ? + exit /B 1 + ) + echo move /Y OFED_%OS%_%%a.msi %DST% + move /Y OFED_%OS%_%%a.msi %DST% + popd +) + +rem if run from top-level %1 will not be null, otherwise assume run from +rem cmd line. +if "%1" == "" dir %DST%\*.msi + +echo ---- +echo Done - %OS% WIX installers in %DST% +echo ---- + +endlocal diff --git a/branches/WOF2-3/OFED/WIX/wxp/signDrivers.bat b/branches/WOF2-3/OFED/WIX/wxp/signDrivers.bat new file mode 100644 index 00000000..feef2a5b --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/wxp/signDrivers.bat @@ -0,0 +1,172 @@ +@echo off +setlocal +rem Sign device drivers for architectures specified + +rem usage: +rem signDrivers CrossCertFname CertStoreName path-2-drivers arch {noTimeStamp} +rem CrossCertFname - fully qualified path\filename of cross cert. +rem CertStoreName - name of certificate in 'MY' Cert store (certmgr) +rem path-2-drivers +rem arch - all,x86,x64,ia64 +rem noTimeStamp - blank implies no TimeStamp. + +rem example: signDrivers %CD%\Cross-Cert SWPublisher bin\hca all + +rem cmd.exe /V:on (delayed environment variable expansion) is required! +set F=on +set F=off +if not "!F!" == "off" ( + echo Err: cmd.exe /V:on [delayed environment variable expansion] Required! + exit /B 1 +) + +set OE=XP +set DU=/du http://www.openfabrics.org + +set Usage='usage: signDrivers CrossCertFilename CertStoreName path-2-drivers {noTimeStamp}' + +if "%1" == "" ( + echo %0 - missing CertFileName? + echo %0 - %Usage% + exit /B 1 +) + +if not EXIST %1 ( + echo %0 - Cert file missing? + echo %0 - %Usage% + exit /B 1 +) + +rem %2 is already quoted. +if %2 == "" ( + echo %0 - missing Cert Subject Name? + echo %0 - %Usage% + exit /B 1 +) + +if "%3" == "" ( + echo %0 - missing path-2-driver files? + echo %0 - %Usage% + exit /B 1 +) + +if "%4" == "" ( +:all_arch + set ArchNames=x86 + goto OK_arch +) +if "%4" == "all" goto all_arch +if not "%4" == "x86" exit /B 0 +set ArchNames=%4 + +:OK_arch + +rem Timestamp the signed file unless instructed not to. +if "%5" == "" ( + set TS=/t http://timestamp.verisign.com/scripts/timstamp.dll +) else ( + set TS= +) + +rem make sure signtool is accessible in our path +path > jnk.txt +findstr /c:"SelfSign" jnk.txt > jnk1.txt +if %ERRORLEVEL% EQU 1 ( + path "%PATH%;C:\WinDDK\xxx\bin\SelfSign" +) +if exist jnk1.txt del /Q /F jnk1.txt +if exist jnk.txt del /Q /F jnk.txt + +rem move to drivers folder +cd %3 +if ERRORLEVEL 1 ( + echo %0 - missing relative path %3 + exit /B 1 +) +echo cwd !CD! + +rem Sign drivers only for x86 architecture + +for %%d in ( %ArchNames% ) do ( + + if not exist %%d ( + echo %0 - skipping arch folder %%d + ) else ( + pushd %%d + echo %0 - Delete existing %%d .cat files + for %%f in ( *.cat ) do ( + if exist %%f del /F /Q %%f + ) + + if "%%d" == "x86" set OEA=%OE%_X86 +rem if "%%d" == "amd64" set OEA=%OE%_X64 +rem if "%%d" == "ia64" set OEA=%OE%_IA64 + + echo %0 [%OE%] Generating %%d .cat files for !OEA! + inf2cat /driver:!CD! /os:!OEA! + if !ERRORLEVEL! NEQ 0 ( + echo %CD% inf2cat failed + exit /B 1 + ) + echo %0 [%OE%] Signing %%d .cat files + for %%f in ( *.cat ) do ( + echo %0 [%OE%] Signing %%d\%%f + signtool sign /ac %1 /s "My" /n %2 %TS% %DU% %%f + if ERRORLEVEL 1 ( + echo %0 signtool sign %%f failed? + echo %0 file %CD%\%%f + exit /B 1 + ) + signtool verify /kp %%f + if ERRORLEVEL 1 ( + echo %0 signtool verify %%f failed? + echo %0 file %CD%\%%f + exit /B 1 + ) + echo + + ) + + echo %0 [%OE%] Signing %%d .sys files + for %%f in ( *.sys ) do ( + echo %0 [%OE%] Signing %%d\%%f + signtool sign /ac %1 /s "My" /n %2 %TS% %DU% %%f + if ERRORLEVEL 1 ( + echo %0 signtool sign %%f failed? + echo %0 file %CD%\%%f + exit /B 1 + ) + signtool verify /kp %%f + if ERRORLEVEL 1 ( + echo %0 signtool verify %%f failed? + echo %0 file %CD%\%%f + exit /B 1 + ) + echo + + ) + + echo %0 [%OE%] Verify %%d .cat + .sys files + for %%f in ( *.sys ) do ( + set D=%%f + set C=!D:sys=cat! + if exist !C! ( + echo %0 [%OE%] Verify %%d\!C! %%d\%%f + signtool verify /q /kp /c !C! %%f + if ERRORLEVEL 1 ( + echo %0 signtool verify /kp /c !C! %%f failed? + exit /B 1 + ) + signtool verify /pa /c !C! %%f + if ERRORLEVEL 1 ( + echo %0 signtool verify /pa /c !C! %%f failed? + exit /B 1 + ) + echo + + ) + ) + popd + ) +) + +echo %0 [%OE%] Finished: %0 %1 %2 +echo + +endlocal diff --git a/branches/WOF2-3/OFED/WIX/wxp/x86/Makefile b/branches/WOF2-3/OFED/WIX/wxp/x86/Makefile new file mode 100644 index 00000000..b23e7cde --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/wxp/x86/Makefile @@ -0,0 +1,8 @@ +################### +# makefile targets +# +S=OFED +A=x86 +P=$(S)_wxp_$(A) + +!include ..\..\common\Makefile.inc diff --git a/branches/WOF2-3/OFED/WIX/wxp/x86/ofed.wxs b/branches/WOF2-3/OFED/WIX/wxp/x86/ofed.wxs new file mode 100644 index 00000000..c8f57a10 --- /dev/null +++ b/branches/WOF2-3/OFED/WIX/wxp/x86/ofed.wxs @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + + + + Privileged + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/branches/WOF2-3/OFED/WIX/x64/Command Window.lnk b/branches/WOF2-3/OFED/WIX/x64/Command Window.lnk new file mode 100644 index 0000000000000000000000000000000000000000..662fc9c70181440afd3891ef2dc96974c9a508d9 GIT binary patch literal 1368 zcmeZaU|?VrVFHp23z$zKRB!YO( zAi^LY@WB6q!Yivxfkihs7_u7qqL*5c3bz|1dep2ItUDQ~ zD}_N1sJjA)L3T4RgaWY)5Q72$L|Xtc2!sGJh|dhf(|@j;BLJi!Zc|9fEY4;Ch6B`_ zF)$~`!0ZNwohm~BLlHwhLpqR51X}CHkjan(w6qu~69e>mCPN-D2;3M%faU|OUZ5Hb z_IFTzeu*j;1A&$gf1nCX5Qyjv0)}2bFseb}g&yrO4Cqlg{6lBt_%H$JRbaMQ5CQda za&f8wvhPb+zT4%`SmQK}abvdsW=Y1VL+4J`9l9;p+w|hnligj*3CV-9GAk(00qK=M e49e!*Kz_O3L8<3Vv3}cK^fs;woUt7w2Lb>d1D+uO literal 0 HcmV?d00001 diff --git a/branches/WOF2-3/OFED/WIX/x64/devman.exe b/branches/WOF2-3/OFED/WIX/x64/devman.exe new file mode 100644 index 0000000000000000000000000000000000000000..805c64adb0c87b81dd106f44b061803523276d48 GIT binary patch literal 80896 zcmeEv34B!5+5Vj@5Y`FE2#C}{f}$WsleWYV$&d-$!3jhXgj$ruERY(KG?`(ssKH4r z^fDH=YFlclRco!*rM5!c!VYD}4aF*o+KEBM4RC?^KhHV$%$>=CSnbz-|Bvt+&b?=O z&wJkUZs$Gc-kW#%GA&-yv;_RZVNF|!lz-Xc|KtA`LUHdintE%GciT2(rOmr-Na5^? zI%iF7^{m?BInI*es;X+A^Qtmut-s1yQRQ?`E^yANE-f3?t5^3F6ZD~^_=?9W=3JzH zw?CYG(IdFO{o(kF?iT5(7dw<*8MBebP2Bjd{ zuU@x-e%bY!1~~k4ivRJS3B*j88+EA_q0be}d_>dcKa3PNg`5cWS7g%~aGlyu(@s}; zCz7I*gVAu>v>D|qo9{zj-v#)O2yyHfNA#al(~3rw7W;~kIlm|VTZSKpcO8CFf7zPW zJgP=k6u7TIAz|H!U({bV*lAR4U2O^S#8@$Aj$8W~eo=qfqFz~LH7b(48fYNMeGzZ0 zzidq#XWgB=`X&@OXwGTE^%BYeGfg#9-Aqf(wAM@)o9VC2^Z_${%1jkbubTG<%`~oF zmh?8$@0jUGGaYTF6U}tGnbw$TgPH!qOz$((r_6M_nZ9DC@0w}cB2E0gxmc!~%=9rc zU2djJ&9v4`uQbzaGd*Oc5{jnX-zcxT1Z3(o(|tdc_iN1bJ~O?=OsmXvx|wF1snbjo z%=8^omUf!yN;6$2NbmHq(zxJolLCGiLh!4HD0r%=`IfdYPGyF;l0R z_B7K&R8IJN#Y~&b^gc6PYNj=2I>}5&o9St0`ngH3SIo58Oz$$&g=Si6rfxHpy=&TO z=6v)v)3e&l&j54Y&ot9fW_ppCjyKauW;(-6Z!ptZlRmS}bfTGNn`ye4I?c4NnRYSL zVjxY^II%=AVxRpqH6{50(% zElboNE1PM)4Gcibv0ZYtDS?KpJ>;L{5&mJ%R^0BJ5?L4dC)#x zn-4g{0LQwQa6H;%)VAuUx2bR4%ld9WcSY*^O>8u@nxb9WVSbfXj*%8)+_Qlp$6PJO zT#E75YLiehM~qyc4>+t(YL%cx1?pCb0=G#kwsE7h4(0rts@32hbH@uh`owjeDC2)# zLF>-T+v1}dUS`5k8027%iqUJGHUWKlfP?&t#!I%5`K7>WCSX)y#=**%bKY~zoNHnk zU9T7=r6R+RdZmI|Y+GU0(g4NEXJ#E>kfwfIS@$K{)#8rj>}59itU^Gp#l37(i+m0A z;(ayR*MgF~mVYw81h6IDc|S+Yn8cX(SK+=|K+!Oo3IVqyLLUjI0_|mgl_=37n5cec z15PEzr2fhQr%H@m)>rqcoYW{r&!iszN`W_JhcjCRY)Dzcj?O0x)|dIj(}G~(E6c5W z*-G+}7U6Ho;e{Q@VHM!d6TQ#XMj@5hgD>fKmbq&y=9bltuddCn^v`ltmF8C#FL0O5 zttct0n9iWAT4Y>rw9988g|@vBpkLskreo>moG8!S$BUgQ8lnO z9N1`UeWfw%J54v-DcQ!B@{I|4cTL;`FR_&eQgqx9s_|mjaTlP7yRajk-38X=&%E-7 zYq!e3#?9BAQvmdx#>-(x39ANsC4bH&KQ-)_$c#X%&A%VboT?G3>tV-DpN7NUpgSeM z$qCx%#-^}i5VA0YE15lA4?3RvEF4bT9Cn<7e4>z#!c3w$T^A(b|4xmyQw3%8CGM2; zjkx0sARR-i7k0e*iP=2t$N(f%%}r}g+nu%u4&CJ_oJR3Y)Dzm6sV@Me=fpWuL?WvK+l0A*Vr4EqcpHECEI3iycw5n;~v?- z*b-V@sA+k|tFpsgt)9SIo9FO;)!V};mA(0HiRs3@1pMO-VnW@#4$NH<>AjnB$6F7OS~jU8df-5+DH8*G7Qn|`Mr95bOjFjn)w9ULF0 zmuy-|cL7AyH?Af{b$j+|(sEaUIl3dhagB%cB?Ek;(hikpr1{R)gR_%>i@xLvOrS0y z>w)!2CiK&D$^)62{~vnE2Jp+qBuv2s)Sr=(svDIlqjkdvMhAD!Jl>p7HOJAo8RPH` z(G6SL-d2ZT+7~|}%dE8peO+w2k?=aE!2b>gXW}m=%Uklk=kVKVC|%T0_ShS?W3XxO z>5XA~!!L1}oA#ETalXAFNE#R$y+*RJVZ?fGNwZ$EUJv%nu{Yd~63-&YRrq@QPsvHH zCy(J8OsyNc@<#0Oj@WfcFd-gT`1-r-PbBm$$5pTLC2@LSO`InXvibMr0mJTk;N3Xa zs%x~a_2q#xwcN(d^DhoNx??P!z&cy7GSN0MnD9?MFj})W&P8XL?_b*;I0*J=?OHxA zPD6^>B)CxOfO3oM#K+l;RTN&qy*yk6Lg8$ z2^dR77rRTB<@^16^$b_yKI_^+zW1RF{!0A z)_NgdLS3z=h*bf!Ak`6j!|yS2sHY;hv0Cf+u;a)F;c(Ww$n;+i+RX0ipN~l{f-r|h zqLtU!+ny)_=4la_z5*SJx`=vcHuNtQ;Bcjk7E&1vLlk} zH|)3(laaZ$Wh@MVcSIbrJiCsB9rYsDNA-O!N_68o^u19Z(M8{NL=XCMHTx4?%QM&7 z8xl}jo^>v2?C|#pJCe~(H;%OKD{nd%YH0{>*;~lo@BpZ2f5NVh_(0!vH0*d$_HYTZ zV1ICf3%C7=ePPF!2YJ)GJaY@~(QrQItK5~j)pr{H-{$M58{5NgJZ(K~oxY?YWtqrnNJ&nF!YkS132X|BY*0^!y&8aQI8xcn zqZ))v7$3TgklWY?&dN8A;QvBbFngfKXz>^abA$8abzv*Pd4h8{g|5q^!fp0sHtWVt z@}q8Vcm}fX(rXwb=>QsW;8Io~Kt2sZ4P4U|O@>YR;2f3L8kQ02ASCHIz?8S`}vyoSPS z*z_e64(f&rzR`puNZ}rJ^=3>s;!ou0ySSbvc$!5$uyKH%`I>!c8JH+7Zz+<^-hg#iq`Z$DCQh2zr+Nz&BXtV3^E?3}< z1a}X3Hiusp01gqkp_|fnn={e}bD#%~P(thtYlXj73Cd+2z4jtHl)50Aaa0eUzS=V) z?9Ql5_Ca(`kuD-w-vrZ_JRev)Ko5Li^S{iQ-$|5>?Vu&EQUN*a_ynD~GB?;8F2`+d z<~v>tZ3RkQ#%sCu-1kvEZMUc7DB3XBi61x-6Z2HcowyD=)~WUmwD)8lvp3uWDgs$I z)LWq!3^3be9J2?TkxTKC*as`ug80yXF0^R8PLwsIga8pP0Wj6#sh{64mZm(8JdDh> zauY5%>0sIWTd8A~idt#AGuM>cbN`+(RV!a2vwY`zgyWHo6~z`kC^JL9hl8KCIdiqW zVKpEH7uZ@>5h6NUfz-7UIFLA@9I+lyxfm34y~e@NxhP26>@i;RW`5{3_W9C18NGey zdrG#U8;_V6JvefgZuEe;41L$^&97q$lJtxo{&$4F_h!D~F<$kJ@nrN&@qJI>3C7aV zc$3-qh*&~ouJ-qcG;U24QYUQ&$>;&9vk$}bF}8+^kP?B}@E|eWt8K2pdhj~UOD61+ zz63?CXD|}YzSMxaqn0xPg8shYtqIKWg4$F{iX?98!|mbQQkEeTEaJZalA+iGCB}2) zgs@}HyMlwrgOVwTWKqk(qv5a{#-vBCaSSTpSxHH-Z|Gqiodk}BeccG(@iVrkkH1u^ z&$O+fS*)>W9rdegCOmjLVpm?FTq|KClcQBJJcYDFUgKSF$!8uT58AEVR^BuN?DBX@ zJ&<=Bhm2z`<5h@bP1tb_`qMF-E*@i!*4h*L1AY|qj8I*jh4?+esu=lQze z|MUID_9t9%o`opP;PR{~ny-I(R=I|HS>rW-MtR1M6Z~ne9$&T& z6_>+vjZaz!lm`|hT;x9;Gt-63iBohiD)I8fKktfv)tmYG^*2FIYCwb$Yh9V^7MAEG zYdyw7D%G(9g|X-RfhX1=RV~Ex2wLeG-+lB)9NIg+bUm1OFRpb1Y7~`zj7sp(Ch2tO zgS~!+A{YE)J(w^Tzt!}Q{m+FRKSDJa*QTO(Ip=y&Xdo==N(i2i)A_>W#StKqm!Z=dHu-o zMO1%jo5}Q2$>jV~P;nxb^r_?y=tb6{J`w4Noq90vJ*;Bjefk_&v~=g9rDypPSdZ0l z`iR&4SXJ%yC+LBexbnadEe$J9-u;8x0m7z^ZK zS}w=5JY_UTyJ#H;4S8tmGx}1J8I*ClR&q~OH$F#DCUg)~l}ibKA7KRPN`+owuCd2U z5f>SM6f2^=#u4eT_Y@t9<)$xXG>|#&T9ch(iMdLu&{smsVR~IFy9y+p151XkMt3f` zMn;?mEMkO0(*$Dg!N~as0YU$%VaJ|#F!R0NCz18k(9dAMTJ!bB_w-=aiy#R&>?J1l z+@lvMrS31~hOHZnlTM#~Y}+RB9->h?Z(U zYINkS0pzTDPPUOarWA?ftQzDXc$3Qi(oyybc`Q3E4DQO7-1UdI$ustb0iXn#Yr5OW z0e2OqKt#PF-eWS?U2h5I`flJzFJHI7kzw}6w?VBZNkB-#42&S`_&b0#B`azygq=0k zw!Fp~;AUgfqBqC}J||W->8JV!s@}+oGONGJ89-6!6BpW*d&&EzKB3N)%R6B;qK)LydX84NvUnc(>8aRTOSv|^vx-C=!3P26ifUAvyo?*vi z(5JO{6^5;aCdjfeC~JLFH*%8o5jjaZ;zhn(S>Y^Mp%v6_JtL+geNf>FL4;dMa(kn`2L%czqe6aL`e2ySR~umb)|d__6=@R zmu52TxL(#xmppwhw6~k;#Z|vQ$#rP&puJ&7B2W+B`o0pMzd?ZsmD75uY(rb!w#_a; z4c>ZCwYdRpyx<%ttU`=razB`<&{4)%FfxqhmVKD;2Vw>1ENnk^A~-Oi*)opR2xoQ= zqU<(X>uHih_6s%Jt4PQIT!bCK1c0F)BfeME8hGWtWbkEc4!Rn#52~`y%*eFvLJ|-YXHqmIprjxTG9gu1kgjYC>2*qq!f9vkP9W`i zRpNAp1*u@x8g4}+dlQy+$^3tMkEm%3JLbJ6r?3i@Fl%!9!j6?@+iA?kMusXeUiV^= z0v);0tl&TePw=nF7%dkX0x@HQcfwpp77>|2J_-Vx50dc9dRII)5l7i zJq}?)Tyj5VS|2haW%x?cnv?Pf=Pm{;qCw1*f;tkz23&+2&%|)Wrqc|-D9>0f*u>s2 zN!_7|y&)TSvCzT}4`z|xSqjR+j$h+WMp;7khCaxmhRWtxsjfn=UQ7V+?93tZ3i+Tv zx+fHRVgWCdNmMPaxo3wRHD*UolHXttjh9wAa2a--Zx-B*I}AP*Ke%A@!>AM}!njHG z276tO@PR9sp8(}(DymOjR<6^!7zNf7dm&i+KTMeihzUJ9oFOMNw|zECW5^;I7UCgxb?tMv1;EIcBGRGd;OFcg^bmeJ&w(qY^}{99cE%}ijn;z=;D?|q5gOqp+3V7v#?b>(wcpU6F zZNz+GBh1QSN5LM}@V)jV;K57h&Jq^gVaKg#8T^S5t#<_`Qq#g-pjg(+#hgfO@C(t6 zz2QOBbQ_1mj^6-kuCcM{h@zYKb+Sk)Y#7C1pQ&6p2nh>1i5aeQ}jS6JH-$I z&}+6>O}Kg$h)f*)Dt2 z{_b@{rR;r-+_0k<)tll_i`7G?MAz(5_Z?Ytv#9xf){Iv*TcC@SL*R}NM=>;_U{)aM zT|rfQ!yvg98dRfuHNkk^dFTJGRW8($=HWQ+_!BCvrO9(zaP+7O2d_9w92VeW|p z^AgIrje(q8V}0JB&C+x<(I@wE^CJrlbAx`wzPN93#OH+vJ_O=`=xS&fwYOL(`@YNI zqwj1Nl-)d`$=^o1rml*jcTlez&v7OXz$8)MQUAGCVx$4?o(i!Yv~vWsI|waF zL8HAlq1|Od`<{Ttg`NqGzBaHyEG+a6s$(AsAOzcV1DH@3f`CSM@;HX?G$Qsavx2?G zfE557>qRtZJ)I@@3IL}Nhwci8^|YF58~kq9-%x4+N}@ z&jD5s1#1CeN$PAr!pkk8a;O7gouA%GGWE3vwvZ+5$P_2Q)(~t@1(yDl33i?d){e$5 z+7>g`3Eq1?l{8zP@(5XH(K_-JUCSs7F71xk))~NaN6u+0Yn-6r-@l6%!tNZ*$Cb%} zC`sE(`Pb8Sb7^jT5q3Ct0~5LN#Vx%Ij0yXW$Al|~u!=XB*qc-jI?fQp2ix^Vi>LXR z3ATmDP`MS+f~C5RZB1wey(Uf!P2YuO$y(o_uwyRji)u}4)$oVH+_v@$JAR0wrgbW} z7jlUmJ6#RAM5hlh;fBR8B{*NF{e^%y`or0QLTh0Z0m{Q za1+n`2%g(N&5>lleEXmfd_ z&&>*YSF_Kt?DOv`_d{V7qG=6gP_#a8bEMZ8(jHy_6q%f(aY-j8s3*Rh4YSd4g<@F=mI$@a^b_<54_cbgd?LzY&8T72 zbr7${;*&ZCF5|u6Auo_&Hq$ePCR$^A>AY#JNIKzQwu1MF*BqB^Zf)^Efr)7(_jC%niSHgEOyl z2WR#62In1Z1(%g>HCJyB(eHrP{M|@+5pW?qm@MmD;2p>n>IES($x!t^7`Uk1OTSv5_DX8Lw!MO->k+wGjUDw_qZN7 z`%dK%wq$cRC{B-m30pum|7$of=I^49cq!M|Zk}GVFTS6GBZkJEp?cf_q-&)H^u&oP zF~STnLjPry;cPk_X1yj>qp!z%fx->Pjzyu66xoo9-+_~J0)^c~VTV9rh&VuZ4&5&T z5CZ|rJO@PuK1843mP}IXhCRp3<&fM)`QTj4nAor7JX0E?k|2j9{Qo2aF)i6MVvn= zIPT+?*{o=+(GS0=&MZy=T8fEul;)_4;?&*YYr^F)L}`Ydk(*&x_$|jRM&J2*#*w)M7TH` z5gl`b;HoWxfp0f3yWlaXFbINR`~_5K9L65?OukrFI{nCpbQ5O(|xgMoXd^ITHq5#KO)e$$;mKW%qwR~{O0 z8848_rVF2<$q5kIrVtULVqeTXy4=S1 zFhTwc%qbd%Zn?k|piM~%-g>K2JKO>at%ka2EjAl`!WmEvI5{FdLlE_VPF)qe_2*~~ zH#@W#4b%2wZm?U-WgWc5KJcX>m&S9}G>wz=e^n1`!K8lSlP3kz#Y}(U!WjT}Cga*S zyoB|K7ivCV2dC-eV7CWT?g?y6@@9slL@fRAOLU2&z2=T-!r3IfWEQzU_Ua}$Wx_M0 zfKvFI&XU4U5r*(X@UPB>@Z*Ha{>bX20~-QIk!RDzhBeMdpec@9bIaP_Jv0J7af_gK zT63s3e0DPW9?<7dP6E!esSR$ib8Uy4AtWv2KUD<5Meb)*(R6=9zH{VGOIPHC9e$wi zmDab(4re2jLc0j-a2iGd=-ECT-w_b{0|#WpMKa!$83~b$VF<;bMp7i>9-I?EMtvls z?jwbF8JA+KJP?oQ5frTqz~vjMZKPp;^!)Z7*g#NJo(Q7gEH$bGCCo^{7Iz4ngJgm&M*nQ8VN%Wry?$Qsx zO#6B1M*1KhD;_pBhQbi))?qwDDizcDs3Ag*!COC#RNE2SgKAJ~L2Lzr5t6|K&RBo! z#Kut{H4dDuL;RA1SPS-TH;5m>+39!?OElMut&!9#JJTVK^j>8k* zbS(LZ8nu(v)f~%5FghKNrC+ceX;?c~p4oijZqb1iG`dFOeca!d zelmS-scDSQT!tqh@R?1R(vP56oQTje$eY5zkgp3hY3o#a4o=sqe#ny3GaUXEYmH=z z=bWD9*nEA=ohvql-E0PSISHa81($zJmH9F6AUQUtK2}rXrkugPbidg@suL?bk@LJ zEQ=I9sfw~t)WKXFJMHVtMJhJ_{^hxNM$E<2PaSVAo;8Vmhp5$VE}G5a`Lg(1nv1(( zv7+We_+ouUya%>5A{S%OrzIEfL(50a#Th7+bKz9mH(OZ)bCD1!IztsbilPqYqITeM z=OS=mIMj{L^l8ovJ05rv7~P|E{YK7w>SJ;1|?3}FhOtzPXfSGOdVT-02RU~}xk#`H6ypSPY04YrRP zxJKgV-;dCDCv!;J$5Wi}lU+tjuCWi{=NKB_M=dUC+*{H3I?#A5XiP)V3``i+Ai2X1 zH!#lPr9E&p{%2_65zv(9SdvgN)Q{R0t<20PX{A&peZ&z@FrZ?FJi~6cLWWyBdwbZZIf z@X8L_yRhRu)By{OV^;`(ytE3!1|;v2zz{^A0Um3bs5qmyux8tGjdghXiDz)IofTU3 zC75H6;FA~8PM&TNQwlzL+#&gdlWvAU5y_K}pvOE%+{vB6W`cJ>4^+4 zq6{@c9$K4)fVjeNlW^h#z(i~y0?{}U+Jd!_vBTIS>Hxr&$K{Z5R+E7WM5FLHA5Ti- zsUtkYDjw1?)s5+^7V&ff_&*(qwBY$72WNfpP?3-)gnT|UPmiS{BkU*>^JH(>LEeA{ zx*xeX^2!#?pe$G;=1H)-Fe)%v;|f$Cf_EplgL*Qj7_k%valkdHrVE_Tbt&#ggLTo* z(-;l-VG2&VKufG*A?&7r=F5`&s34f$W0Q}N$3I@1n9cg4aqUPD182^WR{$J()452)B;ES$?!Nj>YF)Zc(e2SrR zfXWwLV;a?=a`0{apS5Ojf-L@)Z0;*ZBQ`g5A6%1Izh@^%-PHF3jENrR4X|@jw)QV5 zl(x2?s!_xmu(fwaicV2QxhU$u)^@?F<|}dqG1HL0Yc4=S4ub0N8V{!I zLpC-(JtZHC@pu9|0RP?0!y*E#V@qW^-@Sn_?yI>!`^3KVk3ym0nPPXw5PQR~aVPc^ zSkWnVo=J`(932Lm-vQk402@zfE_{R*9bMVZZ4%qJ+1GmTL##;ZdW- zhX>UVPHIl#lbsn!{!dy@am62K?HxFFp1tvTRL7I;-WKx7beeulaXrpm|5;cLJgjPO z_$%tje4Kw1CgN^ciqrFa^aY1079m6IcFxBIIVAHFdqX|iVW-K9mzE@(D7f%2p%+-4l@ z#xCUtc_r(-OGcvNrfUa+xwhlkt%NOntW_5;1W7`{!UK57nFZTJ@sMz&7-Z-&beNa< zj=f=%;QTG237A6gvD|@gxdFK#nz!Wbi5Wfj`%)$vJ@^q2Ll6rCkDps z*Zgnj2If{T*#=5@Gg7wr7GRG2T`-laTXRIlX+UlZaNt`?5T2Jfvc%sC?GXAAMAwtK zj`Y2l_e}!P*92JC-)wlgL9i3Kh;Mz#Tq8K@+AOh0)AA5BgPM`iO3P3hBjrst`kgC4U)h%=gTs zk4M2-{t%JM)<=BmS|y&^3v7skB0~rIu4D0s;QS0XH`}j6QwXfRu>$fLcAWh%bk)TN zDV$K$FGD;bU2?l+nph`LtV{z42VpJOn zSOtGUH2kfIe!7e=TlO6@>D2NfuFS_*;nFbD;Ot3p$MIAU1GcsvNn}SV>hVeIyqxuF zhiqybBk|&qNTl^m6*-?%;t^bdubPKrv#<&}To^h}(}fcc52HqUGQWO^gLu!Cx!&Gj z5CM2Ii;A_fF1ecqkOVe_5?T(piOkET*C%oHSF z?1`NXt?kLg?%xsrDR>BJF?<{IHo;ii`T!X^H)CXq8@ubNP<8g3UI$+a{~3B3S`oWg zMmpZrb#azI$-Crym+@Zf>9`x=`xO75hu1I|q1GO_9O6%U8nYSJ<39#}j`Q+J8hSHE`S99^DpLvI5q7Brp1(g<35w-r1VOsdR$zOfDer z)5hR=qCZj-toO|#OAWxWq6i00gwb^w|G+sMj2)BaF+Rm3>c$5c$8~(j`686#JQ50Z zV=7tpJdsht4DrPJ$iv=@Ihr3&_4YbV6zM4PWFECQ+ySLXDpZ3=EkDD}lhlx{`{nTx zdDh?bfv}v)_u@5VD^MW~t9%4;;ql;{`*rX!dcF!5WC|u4>*oi=1PxP%x-wr|_`0b@ zaL^Ww;bi5TFCbVOoM0PqIPku$kuQ_M*{`iojUYBS%C`ku<{Pmjb~Av2SJ8<@2uc`v zUH%2nap0KyMiGz|0wJTY*a1rJBJ>)nv7nZ8^ zdx*#C8jmynK~#eUX}U*Ac_C}ynBY+PbHnkS&Ix_!jhav2A{$WJ?8ADC)Fao0@ep_G{azj z%bKfH{-wy5i*qp=sJQ-IcftT*6ly!pjM<21<|D!8$!DRSBt$mVDX?{7pg5a>JHbOP zyiowx8t5>=*7A`>2l&En1l(m%=HYue27AMwS&r>>rwV@c+6I*jd{Hg}U2rTPWSyWR z9U5DBVYkXMc$@+_78Zeb@GN9Abkk1I#fA4Wp+;6#oVJfdx(DQHdYVL(S4d=oC4O2&@z!|;ruc@L>wR5cn`e| z5=4*(lzkc`<;gFG%gjB0gvX-KU~=9VFW@A4TUwp&4PW(JGqEa2Ook zg?J+va1}Bz6o9uwMDYk+9Jlr6Bj0Nz zK1#J}I37b{^jePpLpf0NOGJJk>n3DCjd0;L8XO+T`i;oIQ~wuG$`TFSww|{nF@Q9X zRU`_#vG!>w-WtfNQq|)`^%=MokAyKKr_%}HI}Gt|IZRr%c!L~Yih@^Q8M}<6ka*TB zu+ACv4iW4xlrPG{Wo5H{oH;k!$rVeXaqo3f|#nS784U*C7p2z+JvmTt;?MUP*q! z;XU5?UGNyZLw9*f)=o6~!H3OBHuNMt{*t6au6Vnzr~PlP_`tq{`kmhRP2RM>dkj2b zgQxCWuCOdN_C_(DJi|2_>t>I!E3^n@;@QXOL9-5~dC};Sx;gv&BLnjXB>2xVvYlDZ z#9IgY99ct{^v*hyN!Khb`xpd5;G2I2nbT41Du={`>arWDq*F28{j*`xU{D?b9ZfbytXZVjW=^=ZL*7@fWYeExtUvP-$-l5&dqA2 znbdrEjn!a``XHqFY7BtKS6DPDj9il@5pbNt0XWo_`FGz~J@8rB zmm$e@ZpNi!77kmq0K45eFfq3#RUT}{uPK+dK%=C@q$xJMP zGY3{g;Q?uKiDykGGgBomu_Q^Ck??* zE$aHq<*0(%qgCO@$l%7rXfGadVAv0T5dNWi^p$C5cizm`y>|B=D1<*_H_LPQIb1!+ zeJwKx8uc1ntO2~RO^XgJ#wfu8N6(~g`2KH+S7K-=@?aV81Y|QUYmr#Xgcv+wHWcQ< zlzh$S(z#E7_5c9innkI?mE{%v`TGHs*G|TLvC0q!rU4F1;zvnboTZd&ebC3pKH={Q ze6VaqmW^51cNN$qZW+Qm?6tDLC5c-Bdt>6=$n2J&HE&E@jw|5D29FM64L3GipexPm z8qRm~uSwHhZ`=jaIiAE#*zxwS;B63s@F{1p!lHG=L2+Vu*v~L4N`lWqQ+3@paxHWC zf0Vuq9DvpDm%?qNq&z;tRhTlsJ7Q;^ecW?pUgPv($>=06^SQcH%Uz4!)DGqaf2|$F zf^b7TbNvUs2HIlY5bIl)3}kHZm=mtT7!ecga$#J4H%F4@Sl3;1__}G1Qe02zv-8Ct zOB%Gy(X_GEn%00HQ_*%D(ysAZ*KzUrad1DnNjRyh&4OBd3JAYuGwsIyKx0)tqz>Oj z!jCi-soCDvJwfZ9o}_iZuuF}tXPnm4)<+vSI8p0i+o~nh#22wIFYw}i&cJiKX#;Gh z$Mx9PZD-f!#F~U6i3`j5N(Ni^IKoM_4d|{7C{5M|6xy``>Akf9xAfcBw>h~+jN=B> z>lUYVyD%};c4~rl>Meb1`V=Ln4ovB)^)1cQ`lfrezP5>4j~dx89q@sJ;Bw%!SES?7gq&&hE`g zHC>Ck#p^k(tBsmnjS?1 z&q&mIrQfFYvfZL}F>$4fD{<`woPaah3`U#5QwHu6xSrQT8&rC?HmLA-+Mx6m+92C< zt=~>kR^qY~?FWiFKR})7sB;2KNWw%2UYWqiYd#Jdo9=ST47!b7(Csb;s~LnKl3;j7(j{km)Y((PKmDX|nBcoy<) zw`;u)#&Q(-X&GrD_z1j&IU9gE8*rfGe5ak$CNe960pFTkA|50oW z!Unla9xsgH@nz%{dl$`K%JCz;ut$w8IY~=SPu7xev1VSm|QdPf?nDgr6t-Kg;!~3q!(#t*e=%w96WVj^t?5*E#>jCxK!DHGWzeW z*&jpyl;gfY_$T<8f7`FeMY5(9Mdfv0gnQ)eyH?f0w-Ii@J=!*3XXR}|UNiP&_eJHs z#d^rgUTD?RphUC5+s#q%(vjCpTsrtW`TZ+Nl#}1Tl5{xv{VPd_|6jj<^`UKYO<7fb zZ8bg-Q&(7hby*d@of9{uY}Tdzvf2fg6<7Mpa_8gyD>vJ`)zw$~Yx41hnTpD?S!JSV zn)V&dRr(`;oli846xM0;Y@VtLUj@ENQ?Q`US2m|$w%=D;J+F$u&L#Yu%IdnZOUf4D z+e_lIpsbePsnLt8N-N7W?PGygK~7$ARq?E{T43<0%#qb_KaNn`WtC+A-~%%j z)-LyDu6$40g`-Ldy;wh3jv9Di+XS(VQmu{P0$ujR}s_T^#t=m>B(B~;e=YAegC zaQ#oV@D|tka%*d=;gPu|t|pRS#(AqtiYv$0mX&Fbv8EftmEh2Jl8pu4imPgiYZt&5 z8V|A+R?I0Ytd#kUClpkcmDOmMs7S-AYoofUCC_FU_ty$Tvn9Kf%$zo!B;)6vU*+_ z@&h8jN)&uAp}fZLSoER+6{nQhi@d+p$IcpRtu=>(7t*OzvQaHubx>huj*yZ znZ-3VGkptcP&TJ-Zb_|A@?t~6oU%Cpgjf1#W7!W-_myRn4%08!?o62CtGukD*5@y- zoLV&xlY~?F@yL@xI3DEmRa95yR{6kMT4@|ga*Atw{@SvfYJ9Z`Uo@@qf#pS4J+&Nf zfyX_*wt7whn5Al#R$Wl7mBn>+D6bPG zwNWLq5oE3c0&hnez$g|bu~cNq$*%`Z^lLr>LS)Pz5x%5$syb0iQJfqryIoPeFD%B?Zi zmDE<$2tq?^`J&3@ceaR{>h~F08WCJ?MHK}1PpS77EuZh*VnXCATX8_V9{G9kPyb<|Z5tkjg z-jrxvf1VV%&R*U#a-F}{9=T5Wq_4WJ|HYlBs%z&{&kU5;3D0gGbW=L7fA`+j?Ss}l zH!0hB@UFksjJW@y^}nge-g(8*VQ-&y)8v7zf$Sgu;-%YjdM5_YdHAmE&z@c3es59V zpD(&$Rra%EUbt^Z*mK7GHP2;NZ`ilArGE2-rd#iKJ=J*i)Uz{!himpN9QV{eZhGyr z-+a+}-2<2A{O+B(`?r2{&iM_C&TmQ!~_;BkR6R){_M{e2H zjW_qc@6Rg+?*IMxUS<7z`WM~kpSxMln?CNXKiry;`Q4R|y;qR;hqtfDT7N~Ran~)E zhp)Kr;P0Hxh4(J~e(|oO#^uJIVOK2qZ11cGZa?zz+0Wj+>56~US9v%8`VQyM;-(a> z8|KG&wQXCsnPKlQ#{M{~`%AyC;eSWQUS68{`sCmpReb}Wj$QlQ$g+WNPVfK3t`EoV zv=42VFlfSq>;Lfn*zEiMR#EwI;?v*1v2|=()>GrIdHaRio_+D3W7ix#y1lre&%CXF zdTZ?Y-XFe^x9*wSZhvR<*jv^WWcuCP`aScjhsVA)tLe6k+=ssN=#JaQrVQQi=2K0X z7Ze-Uj4ht}gVonPTClM1lQYM@^#1w5F3;T3==j1tHf8L+EgAQo{qFVmpF8&22Y>h0 zQ>6>X@BGKqi%WjeW$Vzwd4cfFi?VM1{Gx%^lnl$cp!vZuLze6seZz!1R%%CI%6xV4 z^rS(LhW6ihUwr0};0o=6@!%=6ZH-%Fod@aOGU5BvEK67Fe!ZOye`gf@KVu757ReA>-p zp3M)OIbhNyWmg>y{QTiAw_V%kt@B>{?e^W968>@D9-P6$S{MvXzMnl)rdbE!d*CDJTE?k5gb19<&SMDdY5c_=Y>uHTaFh z^(Lg1gETD#*FL1nv7g%$*Y_YT!k%)%HP8`ASAPd`iZ%Hrq#xmzfI3Hz4s*)-Basdt z0v?_Zoq%-1nX*3jQS*kQU$iYmI_X^0;Wg43BS02hmm=MY-zHo?kMx0&vfoFLP8kIq z0GQK}etACl8rKP_IJI(t%)brkX8azRi|7$j0|xvpT;GOt$Y{Vt{ozRG;rAtQu19)x zhJ^1!dUY0b3CE6f|5(Tf>K{PrgI-yQeDd*H=)&c=rcUevJ+T;ddLr#Q5%LH6BqPnb zM8c&0N`Nft$fwTQY+h47Z-)+GK6OFyBzZj>Y5ZjP8?2A?59T%Xmmjju`jmNoK9tuw z(z~EL9|5hXL(hgjK7ecL<-b6e@R~Yh>@;~z{dGNlGe8sSf`3d0ym_Dz(r(ZJr5Fo! z!Tb2>xc&s`*;in!s81dDrz<5K>b0w2D{9b|Hsjau(3cShq-D@mmAIzPx*7Uo53Z?4 zZut@VMg2RG9=RH0#5MKBb#nk4eKjE6hMyCCJ&*K;YUJaZ`^qcu8;n)72h@7y!1z>j0BLHd|^y%On8m5+GVO8jb2hkMZb@hio3GNNi%;kOLevyncC zA9?9&&~?r)5` zU->wq+kdn&oR5MZ~JYo9EtKArHvF=^qt zX!+xR+#ec2q)-{+FF{Mt;>>H6972W-@O=21e1%q}&BFKKD zm}xqG86q8r|FK`Jor?S%)R}{Q;bPQZ0Gx_(hd>to@&Ks>aH|oMt_Cb0Rw%4pi`x9Z z7&#TVsuHmJ0+#CA4G49jZ3XIDwKQ#-z_Jvr=AniYnB$ox&5v46&86i7Yse(NWN*Q` z3^i&|SM{VJVl@i*k3yP?e;45D0&TRoP6d?V7(H>CrOg&tR)Na+k{?FJR;+h{sDGaL zpENlKeO{#XLZ76WPxM!X(N#uKqX6?(s7(ci63bE8*YM&W|LOtRhU+r)$yTIM4QR<3 zAr=sE?T^6h#OXOoP@@vCoKa9nuUhm{Cor6g|4Y#`c69{qlg*ms0%D=&f_HL8k2i)N zX~Qsve88v%R6pj<7d85hc;U~$CU!QNGZ`c2d`aHmEO3q&0B6z_idf)lZ`W7bSw7wz z6NVc<8>FcieW{UJ91ouZvI0*)U{ZzND@}|fxANrGBME&_gI`AEhX{A#ny=*DfFDlR zi**U#EW096`s}yjx;aU%8|WWD(i_l`@+CQ6WkjHu7dTOuX&J7_fz&*;qP>#-ktp$j z6UZMHRnfJO`XvXNUi$0E?@DQ#EK${o%t* z6T7-7nIy%kfb|08&lBZUxGKg^Y8#)JcWQq*)67*cIonDv{TMS)A=;=JYtLN@%L2g% zC8%GHA9b45BRPrM!fA404d66ewpi|_&7e-TdQ^Px6ud>< z<-~}|skB??n0(b%9@N;V1*-(Kwvr*`#}BzELk(+2s4b-gl?sY*CP@ESJf##UZdQ`R zIjcbX*=C!%7|NEkgK~U1bap^n#q(}W>X#wV9~Z)I)@efk-HqPaCp9ebj-|B1Qc3Vg zz?h1$UyUDW*?u-uP3XpmjH!9c5xsDaTyjhfU|3p;czOjklCsncw4kM^ZOJLyDvzTi z1|GSK7Dee3$t#@m5|PU}p*ECq(K(manfxJj@mFhGYAVUqZFRBYsLr^WlGr&Ol9Cq9 zoTyE%qhBKFHyb0OA7SZ*XuVBdP~OAELT8T=w3MFR#R6xkFNjBMZKW5KzOg9njKH+$ z84LG#Z8?|iJxhycrgzAriYwUT*X0Sx{rP~apwPb2ui^X-fo`G{bk0>$yGGk1+BwS7 zzXs15>wtJ=gOq$Ih|$#k`Z7XY%rRPA5vx<^cOGxV|4BKL`ir`VT0;3P7CmBpmv7%b zNjZ-0PsuRT&gA$+G?biosa=)N@%81I^GbV0O-8@v#N@htDTvMq_Ki?HHz0 zJ5zY7XQJ2PxJrX}VQGx?i03=|-`uAf8}(eF@ByVxm);$1wZ!xS;M*B}EWDNHjri8L z08epFv?Y$UlnQ$doE?ilJuY&k9KqM08983g%!M&ClNOm7#PU4x@bnI9(RQ9lNk!?;wwG`Z?Ad=>>vIjL^u4@}UZs8=U(Bgx z2`{*<6=@Ikf1mxxMZ}fyAo}al2b8PjG2kT9Pp(#-h`>3I^Y1*AxjOKq>V!|om3aZm z^ASPHM~p$HsoHl%?9GYQ16Rjwd5b(m>&d=li;i*VymjCO_)y`v;a9W1~LnBF7e22GmdjH77Hih;X%u2Yswrq@-6x543BKosu8-0>)-h% zCLK$b!sqM=Wh`1+vvgu~DMqi1=W-RmD5Z=B4A;)?5T8omCRg6{o1-ZwXR$3M%LI2Z zb||9>^up*x%BWANHqxZ5h4r_8MHu=qvIOk2yu^(RNo6^2}YQ*&Fevi~JmR{O%p z805O`_!u!RM1QO!tSlc#|AsIXcKbTD?`qZhpSSXi9(5#PvGYj%NgkGQt!N*Najp`~ zaIMgNj7BI;;ls6zM9Y1R|6DAFYsiz{gj!>Eyl#;^d(xYTwuvXbiId(0HQ)bjZ=&OZxQang21uOv>|PRZjZSK{p>11DGF9j(N< zH#Va~JE3$gcVD?e{5qOet*`*RovwESUWM2NtrcexR9victslL|!QDi;A66O#hbu;T zc7+x~?y0t2AAd9LPaRK7Bdv_w%aJ_RQ5;sTvE+JMS(@l*dI>BlV}jN>3&NK%Q%1f| zRIAInCmuch_wAFNT$!9)nVgJsQnN+JIeA3BqZpp0TP>aPuWL4?ZJ%nVYo~}fHzRzt zhyuy=a_4%My0iTr6!-IZ$}SqlN$*;n#{A#1&t;wCi{52(V#ejaZ+=qZ#4Nyx)jGK! z#(lZ$llx)Nr~eoB!!+!_9N$iym|pJK^Hug?aXb5S1 zF3OKTv2&;=&pw>g^(S>b^~nE~vk!QN>1*rySX~>dW0iKt^S15wvt?Yp1Sc;}G^$>P z6D53Nh-XSVinGZ0hlKcTt^yeU_^Q)x`G~*dV zyF)yM!>9|_U1fk}J%4i*^5q#OxuZagRO}|2;yjHhcg}g9<>an8&j22O4Z#)US3Nbs zCyf5HE0dFU=%gL`zh#HMDmL|XY{BtY9(Y!^-P$7;8n_rw`N^j@+pj*N%Q-L6I+*v? znNOvqzm2`z_WIn4iuYwK%cacK@B$iO-p; zGm}=NNj_Elb@mCYXOX|&j=_KLbFL??1cR=a= z&LQ$CB%Xk^&Jz==wbtM><|hJ?`?Y>pDxQ*7Fxj>(&enKC7;m9@+Mk+RJ+~T-t2*th z&g+s2#pr`ib^C<%=(rE3X^AJwNKj8CaTrJ5pc)uq_*=7rocOq5m>%ut|Q+dw#G@{AbLmge=c@#GNOC(sp{x+ zvL|iuiP~S*`*v+`tVZn227dyZ^i^wg>U~T5a)?;^VKr74CdC`>SFLvHi*?eMwpV-D9@5-n2L+YUNM6sn-6-Tg~!)4y?;J+DeP8 zP6RQJdwP6!K<*{CKgC2om;A)@uktOXJU6e#$oJ#OF-AYb7LDhLVX5FTUJ>28t$%yG zkt!HGtEFN)(cY0fJsV9o#+^7WzIjje#J5mXn?5Yx3aZ{~mWp%#^pE81Sns%@v|2mc zaz{bF4_NKc^9@R|P&?WkiN;io1ZM^?mgpxksChVo*k?Z4){lPXO4jepeK&oKd?MNd=I)47%CFSc%Y)Le7A_CQtYW^YYcopLM%??OOBclRa?d! zPV^aQ1+AtXtj@<5ji-{VjyOchY;KG8kI3qyLG%&LbFoq? zWw~7N@f^@g?kW8cX&T;9%QF$tT1h>bqoRQ_ddo=aRU*K=iEUb>+yGwn@x8(9HiCU{#&m^f?>PQ+>FlHTXV&4HJ&;BUN z3`ZTgS4w@$b1Z5HHMSo2b|ubjb?*6C+p9N_w{IUEE04um$+;!VN(OkIsU!MOnmA5U z+={@TDAbO0lY;2fhDPyNG;KVPVZM!6&7#t0HNJ^Eei?OWpeFKC;GS*ik`@$Jg&hfh(+-3;}n&-N{;ljWPisWsUjcRxC>&+)Xy zk-Whev79w)^fTJkrH-@S_a5Cs?pcfy@@-wGnR^+`PdBe6W!uxrnlHYgoNu9R4_~&G zb|PB3thVJsl4c1$QhOy*!|?s`(<3&M{*ani?&|QZzvKkkTk0t#d#oc*mD4ZrMfig4 zW9ew&AnC|`(OQf`YQQt`CU_TGoM}Sfe5?MIwD67e+{2RRqq(y~TQv(95QZE(-=U}4 z@!fBfmkQLd{36+()R)mZYdqe`Pyc{i#TN42OFXwh?Zz`#n@F7)-A2lO`+9^;-6`M6D?KwsHR=J{d-)a?rBU#Xc(fUg7Hm~!#*x{lgr!cb z@$@QvJSnN2^-ny#Cs2>_UjSI@t;sop|M`AZCh=QtkgM55Ec;pmnb?)c+A`tPee6-6&8Rd<0$6D&`$HYzXr`%B|XDW>4 zc}>ah@(m7(AHIxJxX@}<0jdZ8TawXH{4cf!Iax`5M<;}$@sKAUsIQg0c67q?U)k>? zZBP765Vedv5yY{mSUe?Jp2+#?GeNY1JefHLd(d2a@Lhw%fp1z;Wloe^|2lpGOj3Lj zzB-`fk62h|uL#YW4Qu@-H5jda>{kg0MRJFllW6+OS&zoq!jD%SR3ybI^tm|*;406*R<>#{TZGV#p4wyG zXzd^E$y4f-t&Zgp37_u@Rr)47zO9T?o0po{bR^-?DowsyLOorlYDLSr>aR0B5iKKM zM@#TKRnni55=iN#U)h(VP%XZ*s5I z8?{qsSjSS5=XEDV`4`f6lq)v*t`hYPl0w+iXidl!fqZ+WJWpAPKIx}OA7P%bbzJo* zjT9YUWLxV?KyuvC7LLBPltp zbG~AqI{I`&j?~+6IIh@{5=Z*;{9c$kJAoN$b&uGT+*oJCrLO0wOBrjVWCr@d1G*i|{q_lM;@%Tn& zhrISbH&5ifniySMF1||E5%;(uJIePX5B+cB7FrTHI&1!YRO18-|bDz<$9j6CK5nzhdT1VZT@5ojI+pj=qTExyDFe~ZoBV55g1YS0|LU; zajf+PG3y+oKULh0*>9{;bsvxkwRO5*q+fouYdK?o79 zBd=IiI3zfuHETMdP&LhOWx0&a8Xu z0h^azbd`@dbYCewZRpYuUe}5T`nQ2g;*BbYkhw7Z^D~73i)>h6m|Bfu9 zIbMI^JMl1*Deai@U*kNLviY(4$vvN}!KbsLaNj*qj#+BiWt5+@cCy-Yt#T*z@f}!s z%KM_7$ME|2NmKLzWc@hqiFVt#$|p9)YoT=%x&FSSY!7Q|7_kWXYh@9~_7cy7o#fpu zZ;nB}wrdrGlpS$-B=3rI-_BUX&}7@D*G*W&YeOWHVTa|;5MqB%Fx7RI_ zVGj;GAo~GM&)cyq1OC+K<>&bmp*aM`@ryY}}bG;`b zg2QokNtN}q0w|i5>N*#VN`JGl7sF6g78N{o)i59WH{Kquj}?$CBc1eg@{ono`1HLX zjYum!J>oamWa*XV*tF-ULzSK3eS3J{8s5(g9UE>@v5zG^vK+=v6G`O#oH>xmIb!wH zMZ-L)D6>}&jnK-@SJRRlI?MiQ_W8ykzr}@+E>UKBMs&)l!i^m-;e{2JeTLG$I;L8~ z?v4EHE5Y(JpiSVhIn;OLg@EK|ff+Mo?2M&4NB?N!;~%k#t!k_&;$sEAo&nMG#mU{u zhUuB#ettPyYWeIixjn#gDu<5o8~!*r|8nIE{E74D4cGj7(Rf5nH)dTzE@!cvvYAe$ zox~csPP8cwS2Aw;{}dO>(cQ{xjGbznJ)0#O>9n4jZPbaN2w4g3$bo0#pl1O~dHQIe z_B#dvY!yRfN(5h&Yt6G%g;*ZTWe~Z)GQh;&WZ7N@sT?QfnX&N|e70IGxoh)76|`D< z71Mw<)~+?0M?%E5%&0YjV^&)_tfP2P(xZ)`XOqe~tNY6_TQ12it?=ScX2bBXF|(F0 zknQLBaAn*qm~C83ZJVa8Q^xVv9O)k1Hr=OtXR*|68SeSzQb+8osOHDWT#OPFDyc8c z`fW*E882k{!}2cT>M9b5Jkj}8T9W%Mb*10@C1fy5ogzPBai);RjnrwP2sul-tnddG z14v(3O&!$|uddBg)Y2~OmX4RyhPT4_=HL}VYR1;DmIL(JAs{7Lo6yuYZdZp0l{NE+ z_CKu&_RtfWmdIduIOl=K%vu4JJVqL>4PIH2lDil3?laaWQ+xl&W3gu4HVm~N0@+oM zAwI8$2pv~}Io@S>-9|$i$?&i$YwrW7<0$v|!FAOu6yda=H6gnl?^xEUeSq2v$C@47 zJUe{lcmHx56~*?mq_m32tKxoot<0w`<6Ea5Cvd;0LY#W+uo zk>dgF6FM+_1r7dh4o}`di$5N;O%jLgxNS#>-LN9+?%FXc^0K|I*=(L3{(KJk6I`y? zRb_Ta`^_UZY2&hE*REHkt@Gc?7a%q5I$7j|vB1)tw{52E79hIU%EEU5yFP_Y7JZ!K zvf;95aBFNqu*GPSXTL*NISQv`aglFiNfLVAC=Z3eX8HxCv7q!>;W^s&A!ixg=ZH2$ z4$7oq$sM9*vvu$LG<-!Lo;QhkD0@1Ejr<1LBeFEEscx~5NO@kbEQM@(Msxco#!Y(M z!c6uF>g654j@Ox$@p{EZfa8lP6}v;6I^vCUY7u9|8)&Q=47A3pc)pjFQ%hnbbJC(5 zS4uN-MCrOAeIzKcBVYq3~|>1-9*8_GmtH!9R-MAzq*_>?OmmHRJH1a3nl$ zjyKq|b=Be=?vti_I+lHqWN_a%Z|L}y9#EZ;#C$b`h^?lyg>e6hz`dj^{{hj`c v{>%QW{+s^0{`>yF{oVeD{^b1hd}F>je{Q}r-<$8xZ_IDbe|0qZ9U=681p)T& literal 0 HcmV?d00001 diff --git a/branches/WOF2-3/OFED/WIX/x86/Command Window.lnk b/branches/WOF2-3/OFED/WIX/x86/Command Window.lnk new file mode 100644 index 0000000000000000000000000000000000000000..bc46aee337826f0a126cab47c14d90c8ce366ce2 GIT binary patch literal 1340 zcmdT@Ur3Wt6#va{#)N`}Ba|%nvM2(b8EXu)Q6dSli7UR4Js57pbZgcYYJ7?4O9X); zl=P2P4_g?4^pFr#NGQEjM4%9aP^3vz5EhbAzw>S1w0!6-=)muubMEMYGHz8Rb{89Lf6x~EBBSC%>0P~J4_e{Ns!M65SvEZFIE zUM)rC0Z(wnD=*ccN|!IYPWM}(Hu&oNY5?1yz>H51_PUk>Y1hqbHu|V&fDd)>QwmVu z1aCgJxX+42Pa+wPRqq0}{}w%+lIR3_h$O;@p&E2T32KD%825Ig)sD7Us3P1Q&exXR zv`f1#(QS+hp@PxfgwzHO6J>-9K)9O_Iz))B5Eqy3T(Od8d$Wfki4JfMxnl;6mV-uZ z&dz}*oJ1VQxE^KMdPERq(F83)9zBBN96>#7%+Jy(M?gP!b3C4OtWCK3$iX$oU}yh5 zW!|ZZgAZcmdYd`DIImjf_2;#(ok4U?Rbquhn#Xwh#RcYnI+R>JsUKo5(eH!W31W3W zUhYdzp)aaZ@-b_ZjU@N`hx;_$NPU)i`FLMGcKmZT&di6B`H+<*kI>m4OUh&VpPGEx z<&KOzTvj&oO90*Lff??5#VJP~c+ki`#b(In1yymM`P$_r%HFF=&Ah5S+ghv3)8rB= zH8vPYPy{D^M)wS9Q-oz*5ys7k#GQWy;`hWq2M|5*!Y2o6kDvA2 zh>a<8pBu5jUDul3+|sn7rD|pN@~XzhCQtUYHQ6oR#_YPr?82)`vsX4%*IaS-+5JaG zL4SDglA4zKv1pn4H)g4@16pdzfE25y)gxqw4E@QqxM$#6FWytcbE>BG#VfBq zA{ale6hW+I&!vEF1slXmHY1Ul`Q?**!0)E(H0?gV-KlA7e$I!4zk(F)9uPl!u%-=9 zh%&!spPSGoDC;;->Fw_dPt6(+B5!o#hj_8BD98Mlt!dX>QC;P!Lf{mTL)4v>ZNz2z zE6}u#D_UAxmLp8m0d>(H!^Hwje+5ACik6y&CM3)_3lXTB)*ttg@rWYbl?Xla_isRf zMQCdeuG?@uh-)LRJ-GgWs|(jBxH6m2gt+)uh`S5dwYZvbwc)x8*L}EtiR)Qh`*6L3 z>qA@_&B%)@2Uh{E`MBn-(Xsj;kKm0$h2xvT<2)g}j>fGOjJS9>#SGt`=NnxF+Blf-4o* z1%SI3Wju-NZd~heEyGoS>x;OoxI(R<4X$6}x*OMxxURufgzGX~{c(i==XqR@w*2T({%85m!B~CAeI;X5*TQYdo&e zxX!^f5Z8yue;C(6T>EhC!PSB5aa=#f^*vnt>q1)orABe$^WDuUe^AgUhXXp%ALICT%qoh)ZkH>aoiab+VuTN|b2Xj8N~+9Yj)wnn==;hoAvL+n*ZX{4W!kluKg=?ejU zMl8KosH8dCe61uQY?Rh2;tHd<*Wg|V%v&{TK9<|4)r#6KM@{QcQwRtCSl1>|*J`A0 z(dKDY+DcJlmB)n;4=9AbNYIC=iUe&uA_o`;e+#u{{3nky<5VWnXxdEBwhGv_YO|1c z4sZp3Md2yz5^-ZWqd?b5pmS@K;L-&XfLUx01>IB3Vyvy`02#36i_a@|RK}#@Bg)Ik6 z*#=CrQnUgwl=0W%y-7gOfPI~SxjaTQ4Iz!uavBf{o{nNb_-?>!K)v`^D^jwCGM##7 z9BW*qU5gl5ZZ&Wu-?J4PQ93C{c;;~CXL=bS`mv?+7-CV8bD@iJlx^*aj`-&U3XC>dpD3g{7YR-^lv?>#2p`UA^Lm zf3kdiLkhyHYgR39YP_Pk`dV4UE~uKnuSh6Pk1W)?N=nMggU*bAv)djCI=fwXIqoWt zc+&&xj+eVN*jtgT2^m_7W8HE6u%|5dm}gF@eZTHJ9!zg8aYeEk25Bj_Cp2I8*`7YW z?*3lOyqV!QbN{&5lc^UU4_YSGc3Q0cH9Xe_)>=~|UTegAJd(8*xhg8eV-A251vmne^KDr2qJYNi&u{ZH)sdl2*kheKuKAU)S(560JTvl9h+bfGFv> z*^l}=JhOw&BQAF#urG^bSrLk`F}m|eS-=_6o!w=)cLkjXU1cCer}H42uG4v#EgQ+Q zAi1E>6g;?7wUqVsDP{PJWWn-IiK7@A(Z0Jr_3DjeierDW-MQ`9?+5HE3FXewH2tvu zXobgHTCV3?K|f;ZrpX>Ih-4K2kgxlz-X*?u-6`HOed+PC&`01+eftX`0xY=N1ngZ# z5Lkt0GNF{B*4?g%Hv`PVc6}9fdlZcELa5d^vPjc+RxVz)`{{Jef7H{jEc769SJ*qk z?-h zUJdls`y%oZZ$B4b!UO9sLvtJu+!iRZRO&myI_7pRCD?L%q}DM_f5S7lG?G;ango~3 zOr2Hh%hkN^f((|cgR@dig!nUteEL5B{tC~SfZey<;*WTS3kaU9vcQC=q98m)1TjtX zhJ7QS0!1sAEsp0#$>yGOeeYWIzMx${SLh}{t|$ww;Vps3V@;fz5!b|vhzwiB*7i-1 zAikNi(abZ9X0Aaq_w!bYX3k_jG;=|ZcJ8YnR(PiO*3Lf>?Hsfe)%vp08rP(1WuZqQ z9B9R}WqUtfB-%U514g6!y3(V(noyBDkik?DG;ao4qSJXC=9Ct`Qr03L@~C-NhZG;9!XZ0sS0R?C!ci@EL*P`9P9m2lA8SKV{=X3amt#2na!M2uCGhiXIW6= zb0d?<|58Y+n`ZSOer7AjJvueRtr z$Mk!lJD4}~&?bb`=3l0H2SUWj+WO%`k04AxpZr^YSy|*Ie@6w{`DX|mv-5@SfHU3p zL|^dt%ZT@P;JL!(nG?y{hgaJZ`()f};-w?twA!BNS1SQ*U`e^#J?GZuI<1~T<Rh?DVJO8H!sA z+}n-!z`YrayZ5+ww&2-otxsEY=qG8K24PJ%>*T9vYFh60ih%zJ65HBtMiR%;Oxx}2 z0ZnMaeD7ReM{2EOh^Mf$JQyU*5_@D89t%K6cHnab^LTABHDU9g2Qa#yX>+&R+WO)x zu$g#-&yt}4pnsbIj)j>wj?mM;Q|ohF<{eq4CG1Djc`+=ZEeZ(H%O z?mAr{ecg-c!6m8Ia9>>zL-#W>GU1k>|235F3Vr-RBoh2uw|@AchaU2M?YQRcL$%z$ z(@#Ge7^1Jxz5bBk4KB%?+^s_j&cZ+de1M7w3F_~_6_Th1Sq|D8%W>+3Bs4_ zyN>;S*zRZ&-z5vO6-I0KwEp2P-qNul%9QwM<++*v;Tz51* zt(^@rMo`VM3^G<)S{j)YX&1bawTJ+AreEbf81xT8K9`K>6fa){Cq%NAh*q(+-2vbd zdrx1<9znkgE$8YKH~RJh_mY1~4}DoAC0T53N7?=Yr(ADlpq(_8Y-I~(AXyAU3EJl0 zhxC#5u}Bv5HvoL8dly20S2bSj$V;+CvaS(WdHU4`?qw?0%vL6IxI%A#2o9N5pAtn- z)+sa{?WcFwr^bg~iqNw1fS+JPgYW}2no%ZOCzK-IJ!oTc4A9leL(g`je9?HJt$Z{$ z`c5{w?Y0~QhfSHHWV<-hPSKO)N7_lND7_=!rikWl_tr#&2*yxk8r4>hL2ps3{Sft) zl#YnD4ZVbMt#7kv&jD}~-pXb6=N5;yA>r<)hid^59PTg_m9HyP>MHxu z`Xv!N=&-*qx z4@{m9zT_>lJuy2KPb)nW@LTM;0>3Su^YJ?$n%?(8tw>koy`t99Z1IjhYvGab`Qq{X zz{0NZ;9B1r%T(_mUq|0sM~>&Lfb;My$2#jxck52;n9kg%*OurLP+;HM{L3`}%Kwt) zJuB8v`D(hgS-yO2Jw{NT(HnV>Y#bXZR6=)_QTey~DrTW8DDOi`=xT&&G1C-+F(?+9H&P5siO$ znf{*VGJRo2`BpUbO=CV7vp1MN894^oo=8uvW!Bn&wV+_0H{?HB>Fqar_ETR41R6lg z^zE?i(oMsM5_FgBfcB&J9IE%T9}U~kg6so}f=kj;bjuT9_`lAi?RB-j-DFz^;LEDe zciE5TJ|8HydRF9q;+gK496&{<=$(-qefyZ5!Sw50C80|w1RZPhfql@@90eXh7gTHw zditiostH>DgJga-_x*MKV3A+1g~2D)6`yD&p_G3Ji5o!UdjLzcv)kJpH>kppL>S{G zBqa=|f$`AG0KFnypg$k(^Xs+f$C0MbMh_lJT<){ula4`B zARrA;JMf|L(yu%;nvbYrB4!)9ra;-6yKgJ{>U4CDFT(<~qk9Z&-ixQe<~`zf7k)ea zj58}~&)7(N2w_1#Q9E zz6;u?grmzq@sWVH8|)v+nj&Ozz_f_5=Ns7(?8@$AFA4jij%3X-uTT#4L8rV$uGW&PU*>8)>ek?Bg zSQc*1S!vEWKQ1RsKvTh)=A5PIpRzJhN&EiX_ig?WW+0h((c4K@sieET@U^Z$(^DY+%chUk+H!K~FYYI6t0Ah-abgb;S7J>L_;PXVEH<3)WT zRssK`z%(d+VQ3SvNIRJ>BB&L~8Z9d49S|FEdRs6sMFR%?JCN)&%Jn*sQP}o-U_zWm zMo&=`F+ZsqY3FZ!N*tObum3@4(1h@;u|Qw~8^ zhOS!&#>;NHFL*1=frzvhw+sgb;V=mJZ$n_vee}~WyzYo1-(sJnt6E?;HU~IIOp!}m!fJ{K)vx&Bp*)>pxthJ7N zcYsT5ZF8b8$ZKoM!;8c?iWLB8Q9jN_930ws6XRyq*w!`xfl^aRbE(u7`tx|DmMBT8 za#W}QrgRf6B;8LKK4GU>1Ab|KF`ZGilBx%hTtX_Z&x&L{0&%9~1PNtgI#3Gw*8>)G zz*^q6W{=UJ@9Hg)b`}x1m!W}snI!TG2z&Kk1fxoFkqj5Amo%N0B1e5ljRvL01WTyMT$u9Q?0z6^gBVm_@z9^#!)BRyAdYy{yC!#m9 zEcZvT=w&K8gomJiBPGs#JQh7&Meml;ltlN(vFL0W9rQ1dHQ7j_!r3XL-&5$e2yJzQ z8lxT*6sbzZych;;GSP*lp_Kx*Nag+{27AY!1kLo#9cf>2fnD5IGL#1DZ(;^s*-d*9@SHALN$cmLf%Nb8yVdi$Aqtt zz_}6;6i$>P?G21hiA4{W(HPt@LbG^=KxV#&KzC{^P4}CWK9$5OlB{Nuv{;hgi6jv} znJ2~)e1VxB#~M-2^M3Mxsrk6y47hG2L|w z=KSMFiyOKofUnKguazz|Ibz3nU5rnY4Nf}H;I+EH3%J!D+XtV777X%bSO;9d^(n&G z4bHTHN4i0IbW>5~C58>2eD`fI3|%1yw2IyhufkYNk$6U+9$yCD?tX$;q8>jwK!TQo z(s#liS{@n%=B^(EuQGe5&^Wxs=kL$_RwMt4Sbmqt{{q;m-lFmk1l8){2@Ac1WbU(! zY&m%MqhQZ4PTqL3Q2t{GDmN*0G0ONa=Id|d>;7XjAKWAGz+RwW6pKukOd`Vm&T0joL&t60E#9+ei} z8}J1ks?C=ra>d4+Y-sV-2#@28vS4s8V3pLT!mr>8v>(JvB0ggol!cj3O3OJ6-xv2enF90|cbK|gc2I78>TNODdz z&b{5JnEr-P9N{4{g?on))r_c$iYOTOCRH%TmVm2D_gq)6B`7Xj)-1h z?Nob*%Y`)^63=L&NY-Id8P9Nq<1+>#e|cTvIM}_@2z(KN26m71g5BEQu#1(m+W>h} ztej_!z7M_|y>&?jI(=(75wMV1t}&`U!hjC=4>AYMkon8r)0c=?5Vv51!+heeE4yjWon zBH4QJl8q0;$u&xVk93b?{AA!)m+&==L zb-g3hDvC=F_l{7BM2Hhjl|3*rXmkT<)Pp{q&Mqi1c)1ms3W(K7$@KcGCnM8SB1J}0 zGMxfaSW9U_>L=7pCq-)ZNs;>E36LtoiV$zK?HU~3bnnqPMhbY@cp%qVz%0sAnF6ic zPrMF?7cDr{O>QzV(-W^qDxC*ra+8ltasMUalGEo@Q5j*N5sARR=D#F{#pKH$$l0tpZ+F~l>oU=@#e*6{0c z|Mp6bd5DqyC{#faT`GZg3)5}3ieIJ+MbLu?wZ7D`nE~D*iE81#7ilqv^Bp1^R<1DB zIqpSWaSGzANEJTET^=7=jZpm!n0fm4Wuz^~JZsM-|?wQWLNFv#`@1O+rLdp z-E6vQ49m6ysU&qTjF0#cB6?7F%Xx{^rQ6mc?7ETeo8uwW2n0g+?Uf7ldtJ!6@lPkXt2O$`gS}*tE8ZD9L1Sy-`B0R4u_|!R9|GNb>vEw^A_mL zalG*HZJ}4NtOP?d=;7R*HXmCdx6{`4Ytb4a4VLC168<4u+XD!79}pJ!B4+4>69J`S z873n(Ap(Ab1<@EzQFyLVt^on6)crGKgxd7H=yotfM?&FIkZH;z-)2^*zKh+zG?Et} zIffFVniUvMU9SkZ`5brBLygC1Na2D{Hyh9(Y8Y>0AqCKiiCvRDIQe)X$d zdgwb4%`$g4YJg6OHQdqmH zmtl+-ueiEl`58R|`vP{L9D4-C2-<~-{!F;e z>NA3VEAG%No#H`u$ms~8;fckCctU#{J>?us&-765Z61tZ|->1)4O@b`>Z! z&J!TT>1dpDzpT1SsbqvIrLaos-DkB_*X|z?NR0x|l=%K|$;S;Mg~7FE|;Kr7N(A5G!ZO;grdGSq2qBkH7@s zC?1m4XB7%o!}Q(H5@}?CKLzWB_Q?#H?lnYCj^rN}N$mTVVVv(di>nv2UPH1<4Bg^8 za9>xUAp}^S2wCwJ@58d#`qX96W#}1;v21@=zsRZ7~;;vp+a{mCS9P2jO+P=e_6S*D};dswy@ykKW zt#D`9+L%YzY)=fqigw>e`2pu%?|FO!#Qjl-wzeN5Q9%LX?7M3nR$JRzmibYEt?gn& z_&yq8YdcRojPVZ7eQ(`B=un&I>;gyne|SF(_tBjP(sl-%uZ6$h`{;6;zW{l2-wPDK zwl*!`ea#Jw*NbXn77Q)QEkFQ^G$JPA-HU0Ck&NJK$$nhMffvr);pRVTYwJeA_Wh0v z150;!`p@*`{Xp}6fM>bGXr_6Gk?#wrDWG7p$987wa5!JPak%b$O@CE?e#|QY=K+0q z|G-eJP>&QJ@V>7v-I2RpFWwtSzh&K^;M`j*dggxw1{EMWcl+A+ebu*Eusx?5BOh$Q z2n_>l>|L_8)d6yO=z7SJ?tLvvzpy*adjP9bbGKnZm3J>>f-EDJ@LG%Hs?|`?@`PxP zO9dSZ$UUMp!{f0=^DNzEnGwhcTJE3+>hI;DzhXEgDfI#9he-wsbj<+`44tBX6mh<+ zJ6{&dw`o3x`(YCtI7eH*4(#4`51u%iv0Se_&fQr0`<_7{E0@s*vAs&{uKL@U_lt^N z_$2LUS!sPgw$7f27rRV`ljc~#!Ra&iw8L?l$I?k5wjV7oDhq|-F@l7JD^*cB7sfl6Il3u`blRNG5PaS^-?_PQajvWysa6P??jCihvYvf$HNH2@_%mSf!%E z{ZKqnzVi$Wl3D3ocoOaX7KeU@`4jeik=54Hve59|WDzWRe#1McEVKzdNA6De*HRaS zpT~l;U>*vOU=6g`o?yFU1DWC>)({GfMMh?!rEuT(@PyXT6hh@UaK_zmXyz-!Qkd)>2TGXH*0-_nq47gMmjLwP_%zn8vwZ2Z!L z+%BP8ZVmXS-~oGJYxDCpZ@TYdpeG6pkE+cdqj}!rl6mi0(TapKYV${E-a(zBQ1E=j zC-SH2;uh6f>!j2V2>3?>wkI75%IE!1zRBvqxOE5+H}(yPJJkpjqj`5wo(-Z-({KV2 zY#WQh-~ekUa)EYMoZ%a~hFi>f2?mTb zw%})89N5ggZGp`P@hgW~I#9-pECWh{L5^-ppYzjUt0$$B;gB&$_)?!(Fx$n)C66|3@VUfMizL)D03qXU&EBX1U+5r$^GYK&R?|Jfl3*X1N zH}Q6v%;?@4PlVJC(cW^D+>=IcZDp(H{?XG9sK}utN2M`m$=~`Xl1yJHcU*1(k~i@{ z0c+?VnCHiI-#M7>V=Q;m%))-ldMz{uPx7Pb3=y`rdI&~&X)yRW-b!G^cYsvkir7+9n|~q_MB14+ zGzgh>KU1=ts{{Uxcr@+B`54mx03Cxp&%I+<_fylZoUpk zU?DYdacm~hxE@gu?_~_9<-9W^<-GH&2un0wZjEbJU+^AQ3l_`}u~NN0L#Vz*SX_tj zPX8MGvUR0c^@siyO=D^lH_E`axPbp|B(=4@iPRh_wXf&v?GNBJaPO^n#tKpXBCW0M zdW2$Ao2?C}C}2DFTo?`D(coQ30Lfy>SeuMrSNK{Jrz}Nc86NseKeiRqM>&OgOh~MxgAiR%0jq@(QdVAuDJ$%u~$cq=LE^z#nK zr{)R|jrf@Zi}>&h?i1PDMPmV9@0)}kWlX}4G3F36V}1*!5>(x79BLuMQ{?E<7>CMy zQ4SqSE>v-$tD_k)A&y$IY$*Iq#DvN8PVWVRINwSjPVQ4APA24Aa;N8}omp4-_X=2Ef{=H_0GpwJCvuFxbPLcP(>>@w8NHg|;ru*b*=`_Z6L z#tHiGK`OY#SOP#lE=X)^+sGu*$Vk>kR=3+n(f$Da(pNG`bPGGrP9GEX7g{t z+8jwufRYVE(pI8n#7^H=p|27fW=UMba8?ukol4mn&#>y!28!7?%~7(jdvMXtOUP0-~*(j}IwL6HqJQ62HsI7d_?TpnF>wvDmUQ+50aRuB_{1m%9(htX3g(E_|Nai>9@B~-xOlPnC2WIO zW#|LBQYZ2P)|uye(_6ZhEtLuHKhlO3cL(tknRpn#5Af0bGJp2*XD@!x;#6uoG9NgA zH<_r zGu#|oN3!llRQL}Fyni%OBSHWA3qxD58>1qeD}sRb*uX?ax-+p6&uzs|=wgU@MFsTv zxmX88ncs+AKH8zZ_z6tx0(uJCFt>%7jsx@15<;!$>_b=}7!GVW=(Te8_a5NjIDZ0y zJwx5Rg*vDb0KPw#$HNq3SY#r}5t&GOL?)6Tp~s}P`#=aUj`Lr`uXi%!;87H&JG*qN zepaCP0JaSO9;{eVv0bmh(L)DBYM8V#J-1Ijj`WW6iM6*c1QBo1O5IPup;VwPsa?AP zTZXli;;TJ8#H0BBJiG+gGibvUmlK`$A?!pSvf%@6@bC=79kqli-PndC16S>_?{?hU zjmPjn-x|-rRh#%8!n^I;+w^VqDG#s$p{r3EaJmy%_|6{Adi&1K<_+H0th-pVvyUTP z0LQM}E#A7t+x_?OMSEZ*srM7Ar~F+woCCvh_XIa`XWfVRiqH*+v3JPYgswnQhn|Fp zi2++=R2!0r$32lz2i0@#**xUKoBICtL$@Nmj5mHuf^$b&#_Sr_acu9!yYwBSG;D*- z-PO`x-&S##t_3V3w_mPhV8p704@FD4O+hw*;E87Mf{__|;mAyV?#Lkv=etTu+&H`| zr8+VZB#I77b_5DXTB`%27=olZ`XVb*kF^igo6~)teB#Lkj0wIEKk-;{|Gw&q;DlAd zCI6kF4+zXo_k9g(zxKE}C8p1`hQ17W`8A%!%M!eVAFI9tw4qubf@O5u0oHPCh6Od& zHZq;Zj`FPfY^!}&=nxowq3#|MX-Krd8dM{Yx)H*qZC?m5R{he* z^}{3A4~bkqI+PVnh_#jr%gRgjcd+1Zzx_ol(ThZ0Sd6j3cKsdwJ#s_nM<`pw?nZnh z@-~hv1Cg-VL31}%V-t8Nj09Zqhf*3wTIZKUJR>thj{`SilCaYlOAokQJhM!1wc2ya z^}fFDPj)&ZaB+(Pb?|E$o&i|Lk@j1A`jp7RbbVgBUS{RnRK7Vgjuu#IZT`WaM6fs% z_{wp8ak}rLPsCYXLvWIp=bCWeAZMVoVCG_d?sqc%yMu+_!P#nu!2`~29EtX7C>>Sz zcc9RewRtyT_i{H-(D!+tU%xJ*d9npYC&b|h>Z<>F>2{#Zg2K-MtqoI_x2`g`Q`dc`mWFu zGE^__2Dh9Xo5NrQ{nbPBkn2fY5l3k{TrzmTV$70q{WqZ%2tD*g1PC@4$GdSrs6|m8 z<6D!F<{hOMWael0`PNWRR{jXy2IgPHTfcm*;JZQ_t%0;~Gi-EiuKQe^CkpMr{wFHN zkx`GCBuW-kY^~kkkZKAXH6t%=TU0^)4Q{p#YlaL+vE2oo6YYG=f*3<|c3#>p+Y>V~ zOL4l!^?mIx`j3_e3#~&|osY>%eRg{82Q6no`qF-%`%z1}?`a%XH#+x~mbb-m3Q@52 zR`+`LP3zEFzMA9OlenkM4_ytKP_^>_hcQpP=7$0dV8|G~VC1&Yg~#^#4k!&A&ZZ*A zcH82tf-WnSRzXm6f;i-yI;5# zJs!1Y=tj8BpirU&apR~(PMM^j+r1Uop-U2^S1nne?!J!%n+t-_XUtW-GkhOJJb5FW z$3=sB$LJ+_{ukGd-0&d~$!HxOwDb=+56Z^%3=CseRRO7E$NbsBXe~ll0-WL>fh;Bq zvTg$hf#f4yp<57*Crl_6EUATOML3|BZm-Qx!z18>=a-!JvSP|JdFK9!KrN(R1>$)}Soid)&^6!?onx!&tc+y|;-weT1M1(>agW zormq5K<%^TD!>g)Bqfi%5|~Js%PP(1C2r^%4K@3Kb_@E$vybES%0N~(f6qU{--(C$ zo8N`s+S{^*AW`jYXQzwX`5_V5=b*TaIv{SBzlPgAcl60X65XjiU=erA16JJO*Lfh5 z@BRa5(#}3SDl-KQc|Ri`NXJ`eA0DB3mPPC6>|+tJ(M~Ji--j&s6Z?SwH9V616kzv8 z;flDAkIWZ4MA3tgXf^kgfnhTTba+RjCt>fHZh!IEdsr!s&ItFzaKBU|d>6b#xTn1k zo`vTn2w5;PooQY;^uqoZ-g#l)fZg6B$KKZuBUL6+KnRY#o%TY@z+9wTZEdmTBJHZP z=8ZwbumvMC?fda$#Z&sRKOEcV`-7%G3nlq`ma|OF+@sGfd1^0e6&?_M0E+2>uUG>! zErILO7nZmdRV=Mo49<(}m3&TSCsM4+fL%L;$MTy9FNJlSo}>ekbJn7G%$tyo799m z442zXVfD>80~KK}uT-h91@d~FJB^8}*^Ne6H^P9c<}!t4;(%9dP0=i-yg92i?GeD+ zVG658m>cPm{hc{m{QvIR;;U2UG}d|Qa6WPA4XvJITSLYTDeU1}DLY4k*Er2U0qbE{fC&X$%Y$X$n}q1DsUP}7Lq zzhGP;$SA=gWKc>G=(V73WzB*nNn1YS6!jD$Ft_g7ma3K;w2M-aj|I%Au5JM?n)X5J z+@`APXguKjmXHZ*hR4%VcdgeW&Wk=ELcI+Qt}2gvUe!w0;5?MrSS=`}jT6uF@No%d zE!Reg_oBL%)@Xos3rj9XhNji6g>@}8%RNmkHvr04ob%^7=PH^#XsK=XdR7CkABv|| zEmNC5-Cj^JW07mdqJpb6Z7|-);~lSa_+HXy_43x`ZqO&UkEdyML(}RSJm>M*+uY3O z-Ilu6)m076?kdzatrE!_>z1!<*8V1*#iMo&p|lW8bD!1CEp?5aTJ2rS%9@p}H8^T~ ze@bOt)3uuRrdCX?}Jdz71YtvaO5cbp*kdBM4)-D0oO^u$G zriNPd1-fOvr(t2^YP5~k=mG1Bj8<*t+|oIPMJ-J$OTh?@E3~GDnrJh%q(EG}&4qPn zQhBC0B&ZI|c>`DrH20uk^HrL{8bmZj&mPC|-c56n5^H=^ytC1}QUYP5R<6w~t_0jl z8CE%`uu@2IjY=OYQ^6{%@l@3{lxyEoDX10(7c5!))Dj#n`=TWWY{ zx;P+R0TwAPiKSr1S>C$pR?>trAmX7bV))KO>r|F{s?eH18p8z@H@~J8^}&U&s)!hW z(wNe^uhuYnDq|_Ol`5msK{u&<6t!3^%bFC+Gq-6)<;OBEbjijNP)0?W0F6ttN*d|oid z9C;8uB)6~3!SZ7{G_76b0Ju_gBFjBB(b|=3t5lqcR`IyqsZtQCC{NaljMPuY3A{mn zmI>W$$XS$cTbH-gHGArsM2{Jg@hDG-M zm4JfG1W*le33;cmt`+K{5tXehu3GK}Fzr_ipI=i0*~Lc!JT;V7!Tn&W?=p^EUtDmx z_63H6G0lL=wZ}{tNM7ivO9sg_Gn<-khFq+&t!IrEAH=yI*pxnQ9SeZSPXpP=V#{s>T&H+89e|LrqPyw$&UvvuR~>RST3) zG?8|p1&z0`5m{iSFmsJy5O5HCpkwU0@c{>KL)4I&fuVnzFp*p}Ew!{t8kg71Z1VDR z4_Lp6)C=mCUnc@I?Pts#wM!Pbp(Cs3RBPH#OrcS01;M4vYnUE0TFJx02$^hIpt>Ms z+-S2cy`r3K&~PT~f0P3EVe7z!#ac@KVc1f*?!^1pMOwLt3bd4u5ceTxaPfZL3@zpNSXaFdR{`Gp6ly68k#+&D33#6|O-p$XX%FKXiT9WA zehkk?aSg$HAWutqhBM0eOUL^|fEPjBC%BGd%YFS)EoBZSy=LPI;XUnYI5-e@8?JqL zA3hrs8h-_@xOU+^=PO#uAmEaLYa`y<=3+ts&mLS4;{C(vTFS?Sjq5JFZzrsl>bxU_9(7GygxKYOZf$! zAHy{P?*{Qi*z{Mj5NDo1bBtLXr{bK0WLKOwK zfcR4x=$ut?;*O~#9@ET8i2=9@aB;QVdfYc4=MdbnP(#bcbrY`G-+ieCvFBZVjOP!n zvFCz&(qqrA?Y7wS$RmT*^ZM`HeU5t0-n3I7D~>ucvtP7UA*YZgFpI~BX{D)U;eeU_(y+Un*YqwT>bmsygIV< z;luZ5cPx15w#ij5e5_xs?;Eu=@WK8SKmK<2`7!B16AfA!rj1^aIKra$YW!s#QYKXl0P&?WEO^vGq?*FAdw z!A;d`i}t?0aN6>(_1$yvg4MprH#X#d+GdyR*%CWxrp2*E@Ot6;tik4}bCE{o~)AbLZ8LhyP!69(U5sxsk!!J-yJ{id)K-_2QPo)2hYE_%kuie`>;st%-?6DK$^x0#L-X>)D^RF z&%pf}sV?xO{!+C~c*L+`{bt=B@LH_CuXLlXwfc3#2&``EwOay7w&?thW}svWq$+T^n+eZ{JT4C0)oo$)wfFgI`P%G zQhbN%Dtw!&GWtELt3;N~mcM<%nG$|2)Kzr-x#~VW3eciiG_D~q{~bj@3gCIfH^Un7 zmAsJ{!4RPO{D+Z+H zfZK#`ay8)#W*%sGriR}`{PJ6D>Kk!$;cH2Wm0c*lOvb!*NNc3RIwOQM;u~W80$3~H z@wOwI>#EU}*mj^*eQXULmN#@2q8;ppahjJ9hkb8ov)$jgt8x zRN{VBG$rXvEEFH`O@2x6M0KdgSJYBaJGOQ;+G9Deo)^o>?<*$q!q0$Bd}}h~D%70V zN#0;9u#Im(Ta&IUNiN`P>rqx>E1#&138N5K3Z$tDWvQAP91j~2vI6T-V8So-@hgXB zK0M3vn1xdg{E`?y5w;i4JfdeOE-bAUb}Lu*-q%Okh+K`>VU_kL?YPGVO52os{Ez2K zyOw*>hX66!fZRbn0qjA0l3SkdEQJojohQNXS|IIEE3v^TjcaxVNA zv^BZcunR^N?PA);3vQM+Ha8>P^B>Z_dQf_R zBQ5VWcp?YZiZ|w0R3D2N4>*DRVPK`ckw{4V%Z}Bd7J2124$0*z{?=$bA+WtyAr-&N zSdDjn7n0>uS7n0|aL9}Fc#g~yT96!0Lwh)B6$sg!zhS`+Z$`)vI3>yOkd{iE&j z&uRmG@4cey7qXk(@+rksam2X26wNnR=1bOvaxQa&K^D zTal|-w|MSmpFz$sN>qHGEqIH%D;qUtd$QlUG|E?r@}TNQEy!2(V zph@KSHb($@AxdYN)Ud=mp3(|SCBb6>Vrl%mfTW zOA*hx0vkzLY6kY8)u6T^r)+6uaTs4lB|LH$dlaQlB(Jc|`HfgYlG;#8K<`{iNbxd% zVr@%JCAm6L7b}kHjjJh%z2hOVFld$?I;Q~UH~gu0k@G`J#O zr_k;^QH}qVawPSa`lhwATMT-{+b*Af|0LzuT%M9)-g}edQ_)be-KBO_Hizs*PDh^E zuI$gK$!NEnnq2qHrDU`UwekX1oyOjuS|Bkk`JeWf(gg8!RT}lg8X!Io-%g|hu7PYx z*);c4N;Z<~0E6dQqvX=8B+qja*)?Npz)cP_Te}Fjj>j*pkWrc))`g)lCPaG@_>BL_ zWvaSS&n*x(pw#Kox?^80F&!r`?X51d$22T&4R*n2ho?Bl+!M$5lnQ$dTozv*EiQ7U ztikEGjI1wPW_(=B*kdgt+r~_@&$mpYZtMFd>U)lSIX;u4k9bQ+#gPLO>up$!inhr# zJgtKk_vJ){omJr zIN@=nKZy3av;n1d&I2cresZ*$4G&!Q3H~of+>9iaRI9KFIWjLrybB&A7kmuzo}*0^ zzPD_&0Y}G)yhR>j@5!=dj^sG>p4&VUB8NAiMzq|?!;}JQSi+QE3Hm%F1=t7OAo?eA z_6o?k#G@dg9+#mm22R9d4$_-@Q-%~G+>o!{@F+m4W}%xn{#_HrB)McMd@hMm#-OFq zN~cDbDwIlpF8#&yQc7>YXzh}u_%r}FIr5g{AA@qT6^(aE$r{03^c_lXLY1Jq^7>S3 zW22Ncu>Sm?NJH9RUbMPwPs8>gKC(XS*RF%klC&)Z{f!agzuu}+TKV70vYMhLv#V4; zli14`{T8Oqp$TX~82qAICb4JY_>;9}pQfw{didoijC0SQ29}Y3L97mP+;(D&=og|r zmJBQ9UE~~>qRXd)sjxfHYyYlBtv$zbiu(Uky*#}~$s{bk9obssVd>X0+e7qoEk_Ht z2;D~?n9>v;JWEfsoY(l*`C>SRJY!9$F=ldGU-Il3Yr?G4&R7#?tO;tq|J&9?@1B{v zWBsJrFQa;}MEjw)o`(GjEm)36KWiT&t%^JQB#x^~MPI~O0`{vtdtK#AVyv>&T7=y~ zPnh%$%W;8%AxBy9y`*`ZprCvn<8apMUp0?$rtdV5B+m4mlE=@C#Cv)M&Wyy9jl?-O zwj^mkp>!^1UpYcN9Zjo7SODHb*B1g_otOn}5o-~YU#xenZ=U1eY@(bGt2V*mh*7Rx zVGkkaR1^ER&!+vUf?mhkI&6AxOnVcD!obhu~vzh&z8nl)2RheyYL$?|_<rhKacX)wx#g?+hg*B}53|M0shq9t-Tr2;(X)KcyfQ}i1!~6R zjK@XU@n_aPoYD1X#sp`^1U<(DCtEXpGF=<5W0iKt*%&?Mv!!2sIaXers#m=RD@wRy zh-*rc`B|j@LqhyKM*;MIoNTq53;q`uY9eG1(COU^rZ;#=0Ms z(Cfl+R}Ekp`){sAxLm^|XB3E$^4*vz&ef`N=A7$U&di!~4d98#5FA0CY}W*L82xKU zCTGSRXT}_~XaBFP!8^Hc>U8>o6OTNwSGLF4!wC&sgD0R%xDDV|8YY74;tf zc*GU8Q2c&mvz|`W(#F{2F!IVZ$vyQr&#$1i<2rEFBXI3HL*!0trjR?rY5S{l2bA9L z9U^xjaRscgo|sULu?F{;p9)0I*Lu-Yah0@!$-Id;8}$vLz6+wO{Uy!hT4gh?YPGXk zuS+Uap$zWo_K4mic^TQ!zQs&0V_lTFgjPXCIfG-ID$pC;uv#ajlnOAsDUj`Pm1Cbub6Kr*>K> z>md7#eIRziCZ2AINiJI8SkAM;GnFQ~js^OX(Tu3p4auZ#%krw-4eqb#E5J zsn`eHU&hgr95ep&EQHU~K1jq_^_yLvqkYh`3}qq2#~7`6sx|^C5uaA=Nj@DL!LS>9 zw-MqoHLQc29=5@JSSQj0E6+&k={bl`amF?<&q)5y`3}x_bkFRnHm{RC(+8hw|I2ir zZyy}55qs-{kDyOF*%+OA-_X9CA^c~J(?8E%xF^=CAKvsi_QT0aQ9W^d+{t?46OX#Pom$BAhj^}!Jf)6% z2jpCG&zWuVx#TCVe>G08RCVO}I6Zw%W;{;~O9hYq3Uls6`}RaNRWP_#OZj%p){$H# zWu_bbPOKMC-cu#<6pE&(4a>7p)VXFkSocr+NVX2oA2P}?X13*wf;EnSJ?Z2Fo{_=z2ZjYG z&w@(^LwVxp4^-5ZXNyQG#jjd6>cI06;^C1mS!+U6d5trFRfu^Fw1U>$16J?#Gvlcw zD;bAKnKhRtPl=(-lJ}D1esYK>u8~njn<&G~bMaCtWw}=H@k+tJ+_AD4a%#sJwOkWn z)=Fw;j`DU&?=3y4*9uRkdEJJA!)>1#hvd>DTjxZaqwrOyO3L%5RKJ)=6*=!I=S$?- z+|+zLC6{YS)L7NnlcZXy+9VT-mqwz_vymtM3@EwIQc-3!(#R1H^)1)2s2SAwbli6! zaZc2^U&7d4oj~3*zu8wFkF}C>LzWfZT+ft@KBO}1Ny#!i@TUqjnQl@Lv$cy&JZ7fN z9LO+xAJvLVpOGU~zc&{6s&w2j%C%0a?PM*D)Ev9U>ql9m#Ix3umBaH}iqT4q(Ca*1 zndNX7g`CY$Cw=zJNu4ZD2B+3!d7S;|Jw5A_h$DG}KH|jsEa{P!=aIGu4J!Am89C%x zn^%C+^A|6@rh{T#3{$ zIXH)Y5pa+&Xb-7&<*W`*{Us-`XQZA|vd1)XRXObvPmC{^Kc0>T4w5RA^A^-XYQT$d zvic0Deo;z{R;2+5w!|VPCZZ7!ZcUn`h{$d_4P&@=}KshFv7flls!! zixlBZep>V7D(2uRsjS%={Bjmo%AfgsMOh-go6w`K(k@XPM;xvdxbR#OQjvQ=4M|~r zSTEMdysClyr@4m2&fKb!EyszgB8qC%13cqjp2DIu3eJc}p3%s`Ts2WYGRu^()QUB(8lsISCAGKmiRau? zNJsfE1uS)H@=QP{SFp~qZ#67-g-apQE9{kw5o_{++!fDrLz^MNk^_dLjCp`c8BtIb zZ;+2q1W%r$MyRBuf{3&7koq06%M%fJ#X*BqQ0}V0;R4vXcB{D}>B=$dwP&*GgWKt?>Lb^L?c4sjms5mXRxhSQq7s zKb<*0_JUlQnTI)Ojy-tRAaUSHODZlK@y37h9bl5;^YGOHC4a=iSbIfiMr#=3H>tsr zSw}L=XcII2WviQUHt^$9avXcxokENyC#v@ES=PVn3Mb07OG`HPjpuGT&NkO884pXz zmO9^%Iyv59Ug}v&tF#(8_Ub8TQgbWYk*oHoVa?j#tm!Frs;`dc5%y*Bq)?@A3epl~ zoZ7rPicK;JH^;N2#FACJf8M*2Xk&A2pP57XbppAjHk^n_VPPDe}dJ5|!2k`hSirCr&ZjL{OOrd3up zM+>U=mTSfgOil%sk#{ZnehEEs{i>N0%=9Mr8l_P?^@epkB`MSMO!kGe9p#8ko>ij0 zL9zh-saX?pL?BPklqF3{Hk`vFc-h_Lha6Ptgxoan`Wk)vc%0jyevn0XxKy3nvd7sC+fFnpw_H^ zB5ldN#L>L2G~O~X`UcAW5O z@QhZoWJ&KocZJEXU`b3qt*l5ppEyv0PbM+Rc$)GisUk5WEXB_X?i_Fjty;N@O@*52 zPinbPBcooDGLn}Kj+3i2leLsl6De)UBp%kwc@K}$+)KwZK7;H z^3eY_ZedR%YiG2d)Xj3W7^PR$PqubqFOtaXa{iNEv__#-r0%6}gwm^I*!WtS^x`CH z3Mnx?d0FwL;r&zl?TLq1cz;<6Wre!I;A-l1mD`XZ@^m5>W+UYSA@LGh{;HhxWb1&eSD|4@34QwirmOCz4hUyh%IBCPLa48L?0e-Tv%|DO3$m5&h^dhlT=kSv#zwm1V5V!_w%Nq`Z({4ZBfsTq1W8f~Gx^lwbbc+E4nx*oth2WZotvpK|tw zy^_=s%2y}ljs6-#R@S5LvNvEKBYnKRmvEwfS+!JhTC+8heFL(mU!2&Rd&NtHoz8C> zNDaWYHSoU`_#2Y_+3RpJp6RU~d;X<(kdG+?=KUt0u9u)Ld+p!4E{dC}y<}gKOryqg zk-;xL=Yrx>X5;G_92b(`%-Y7xb8A5#DTmZJ#`uDm^^VbrWQV%a(6cA9=kAG>O-}5& z0)*0+j2g1oEPAn$BEK%hRFEN zq%47R+A2@ac?_9`^Bu|4B!j476k?<=L+cu|m+=^z@$H!|Iczh&h0takvBg7;r+bsX3m!OvzF6FMOvxOwN?j(Odu3 z(@%A>Q#*S1in8@pPh?oAv@#M;N9D+KfskBEv*80V&pfLA)SrFsgQo7a*u1~lber(a?E!Z^F^nhU)ijr zrNMi&gL=YJ7J>528B%uGlE`Of4=$~J$^!YRC&!t+2l2MIIiI3KyiEPG>?O8HBB!4I zdJ}_34Il2wts0s3j4gAf+i*{rRJpIigU*=6?WYCR?Gf|h>^Q^AnyBxM^%9A@aK8r3Iaf=2Z`MC|lAhz7^Fv)}C$1+9$(W!cPvHen~U_YW@Fc(1Rlg*(!3T zLsCes0O?5!RgdH)nfZ-8N}iD;m3R)8vS@A{1y|nZ2%eT)M<|L)tcf|-$x1NVJ03pg z4#}@QOEB}u$!oyYkYf`?Nkc*mJilb(yA#1olxstFIq%A{)Yp#brBfV3dy#Z8QpZyz zkrPiW6)Z*8O3u0zf=a6Z`^05Pn^lc))ch~&!}S~2iu}eGGgY_#GiuY$%ON{TNS=#9l+L3zr=EdDfgI)8|O7 zCs)z1o}5wUUOj3gIkJl%(Q;*(7y8*9ZEx8M26xGxt@j#nrJS7MmLocId4?92I!Ee! zSpsKkxO>C=?W_3JBBYIh$7nIXBYPp1q(<4qj5Q=|GnR7Y=t96}|H$?I$!23EMHDOp zU*!Rj-xsIvR_ZYM&2N=Hp1PdN=MIw_L|KZ;hKwWlOFz}5U;j5gw& zu2JjwlH+S}a>|*@DUo7|&11W{l00Fxo}>TFteTGsLpTQanh$pCig-e{SaOla&+?$Ec?n z8#RJAYprB_m%KgLh8$hQQ&ieC#F{G@lR;CK5Xb1OQ8EY$vqVit?I_zIo*v0DRNkcc zI?L5x3bT`Qvf@^@MLBdBdsw4p$@&7R`}uvic)MAanH<-6Y3rS~iZTj+Sx0&pE{E)M z^^UY$&2=_&-5B6*{#RT_+gDmOpM~cPCl)+05xu3pc^$kn+OO)ThHBHum$f|7^nD z7_rZQ9epLPnbCV;^zOt=K5>#W0@8yjbH|U$3c#1y+6cfRI_C>fLh+9+sP~f0ed+0xW3J1msnMyok-09XQc`@4oTp8>MQDjJS_OW|3q2{f z2oTAE%93Hbv3(4#yac&>reVI*;}&9a`AIRMZK*8z-f>Ax_35xVIb9OVNlqE2@(6#e zv~w@P`3&(CG&r7fm%(Gv(fX>3y>GH z1XhA-tkA5tUSuY1EYq1OmZCg zf?BU8s;v_3DAnT|tuE&)q=l3GTN6@m8^6@7z3l^(d*L`{CvJ*{qy=eR9X(xR4(9)7 zVD$&juU-X~-{E4)UWGG6lmfh~SwN*TLD6m?|VsFpfW%gDANjj1bXZO|iT_oC-GscoZRu+{8?0HUGd@YPJl2h9#gX>CrTPJCh!L@n@EyyD)fT28fK=z0yvJI51 zuvL2g^@B%*`dOWeKPcf{;Yv-Z?9;R3($Ho$c79pWi;|ZOh=Y5CB!f9HAyquovl6Un z@}^CM(Z@tjfb1pASjxH%Ovo7zx1We5k5DgEYl9NrlVN&xT$*@zJ?Z;z7m}f&2g2X@ z^zj+vAD^^w(xypECSNo8`N{80&Ym)6%B(4_DP>dEOnG3+^HaK~M5YXMWH|~Q#g1i; z?>K(ssGWNI)TgF?GId?E9HUH1~gQpFfmNV^+ zX?IV1ciK;;w@*h|*_w72Za>R;J?DaPGse9-?%DAljGt*=U_WF(YX8LEZ^G~it_jyn zIA>z(#Df#BoK!yPnn^1s{dCgXldO|RPo6jVrpcvKYNmLne0|CjQ{J3%bjm2l0>?Vw z^WToYI=(P<#MFnU{%&e&Zf@?3+-q|;=Dw8sc5Z53LEcSyzs~zjUTXg3`P1{4<`19t z#cBJe9i4W;^xLNIoW6HDOhWB(;M6ZCD`!EDFXwwXkK{a+6Umu2u5{eWaqZ)t8fP8< z`1lcar@hp^*#0&9AM6M1cTd{!Y?wRt_ zDLbe9X3C3G{s6j-a7+i?T#gNnA2?oj{K@gI93QH1)8=Iw_!Q1 zoR*xQ=e(Koan96n4dZSdw{zS_JB?e>r~t_{qS!&HhdM&+UUI%$TroLidCV zCQg`GKk<7LhfG>9>8q2zHR;(&A5OY{@-HXvoBZBnJ7~Lg%4<{JnR0kanxnttJjZ&+ zqmExXo^kAP{N7=idhyh`Q?H-;v#Fc@fBR+k5>*h!;VsrmB()Hv=t63#CAxUu**#~@ zJ9FlorM%F<5VOK^MM6W!izQaG4{8mIK0)*QB2bJ9im=d&OiIcNN!S7-3U5RsFG>_j zD7xwOkLYgSe_(#|{GMTE)EAYbw`f;4>IJ=>30Jv8oPW|?baPGEG?~k$*9@5F=7o80 zR?VFE$J^j<_TTyZpbiXk?l`nU7mPs~mS8tlVkeH^CtSu=TrV2LS + +#include "al.h" +#include "al_ca.h" +#include "al_cm_cep.h" +#include "al_common.h" +#include "al_debug.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "al.tmh" +#endif + +#include "al_mad_pool.h" +#include "al_mgr.h" +#include "al_verbs.h" +#include "ib_common.h" + + +void +destroying_al( + IN al_obj_t *p_obj ); + + +void +free_al( + IN al_obj_t *p_obj ); + + + +/* + * Destroy an instance of the access layer. + */ +#ifdef CL_KERNEL +ib_api_status_t +ib_close_al( + IN const ib_al_handle_t h_al ) +#else +ib_api_status_t +do_close_al( + IN const ib_al_handle_t h_al ) +#endif +{ + AL_ENTER( AL_DBG_MGR ); + + if( AL_OBJ_INVALID_HANDLE( h_al, AL_OBJ_TYPE_H_AL ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_AL_HANDLE\n") ); + return IB_INVALID_AL_HANDLE; + } + + ref_al_obj( &h_al->obj ); + h_al->obj.pfn_destroy( &h_al->obj, NULL ); + + AL_EXIT( AL_DBG_MGR ); + return IB_SUCCESS; +} + + + +void +destroying_al( + IN al_obj_t *p_obj ) +{ + ib_al_handle_t h_al; + cl_list_item_t *p_list_item; + al_sa_req_t *p_sa_req; + + CL_ASSERT( p_obj ); + h_al = PARENT_STRUCT( p_obj, ib_al_t, obj ); + + cl_spinlock_acquire( &p_obj->lock ); + + /* Cancel all outstanding queries. */ + for( p_list_item = cl_qlist_head( &h_al->query_list ); + p_list_item != cl_qlist_end( &h_al->query_list ); + p_list_item = cl_qlist_next( p_list_item ) ) + { + p_sa_req = PARENT_STRUCT( p_list_item, al_sa_req_t, list_item ); + al_cancel_sa_req( p_sa_req ); + } + + cl_spinlock_release( &p_obj->lock ); + + /* Cleanup any left-over connections. */ + al_cep_cleanup_al( h_al ); +} + + + +static void +__free_mads( + IN const ib_al_handle_t h_al ) +{ + cl_list_item_t *p_list_item; + al_mad_element_t *p_mad_element; + ib_api_status_t status; + + /* Return all outstanding MADs to their MAD pools. */ + for( p_list_item = cl_qlist_head( &h_al->mad_list ); + p_list_item != cl_qlist_end( &h_al->mad_list ); + p_list_item = cl_qlist_head( &h_al->mad_list ) ) + { + p_mad_element = PARENT_STRUCT( p_list_item, al_mad_element_t, al_item ); + p_mad_element->element.p_next = NULL; + + status = ib_put_mad( &p_mad_element->element ); + if( status != IB_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("ib_put_mad failed with status %s, continuing.\n", + ib_get_err_str(status)) ); + } + } +} + + +void +free_al( + IN al_obj_t *p_obj ) +{ + ib_al_handle_t h_al; + + CL_ASSERT( p_obj ); + h_al = PARENT_STRUCT( p_obj, ib_al_t, obj ); + + /* Free any MADs not returned by the user. */ + __free_mads( h_al ); + +#ifdef CL_KERNEL + cl_vector_destroy( &h_al->hdl_vector ); +#endif + + cl_spinlock_destroy( &h_al->mad_lock ); + destroy_al_obj( &h_al->obj ); + cl_free( h_al ); +} + + +ib_api_status_t +ib_query_ca_by_guid( + IN const ib_al_handle_t h_al, + IN const ib_net64_t ca_guid, + OUT ib_ca_attr_t* const p_ca_attr OPTIONAL, + IN OUT uint32_t* const p_size ) +{ + ib_ca_handle_t h_ca; + ib_api_status_t status; + + AL_ENTER( AL_DBG_CA ); + + if( AL_OBJ_INVALID_HANDLE( h_al, AL_OBJ_TYPE_H_AL ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_AL_HANDLE\n") ); + return IB_INVALID_AL_HANDLE; + } + if( !p_size ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + h_ca = acquire_ca( ca_guid ); + if( !h_ca ) + { + return IB_INVALID_GUID; + } + status = ib_query_ca( h_ca, p_ca_attr, p_size ); + deref_al_obj( &h_ca->obj ); + + AL_EXIT( AL_DBG_CA ); + return status; +} + + + +void +al_insert_mad( + IN const ib_al_handle_t h_al, + IN al_mad_element_t* const p_mad ) +{ + /* Assert that the MAD does not already have an owner. */ + CL_ASSERT( !p_mad->h_al ); + + ref_al_obj( &h_al->obj ); + cl_spinlock_acquire( &h_al->mad_lock ); + + /* + * Initialize the h_al field. This field is used to locate the AL + * instance that owns a given MAD. + */ + p_mad->h_al = h_al; + cl_qlist_insert_tail( &h_al->mad_list, &p_mad->al_item ); + + cl_spinlock_release( &h_al->mad_lock ); +} + + + +void +al_remove_mad( + IN al_mad_element_t* const p_mad ) +{ + /* Return if the MAD is not in the AL instance MAD list. */ + if( !p_mad->h_al ) return; + + cl_spinlock_acquire( &p_mad->h_al->mad_lock ); + cl_qlist_remove_item( &p_mad->h_al->mad_list, &p_mad->al_item ); + cl_spinlock_release( &p_mad->h_al->mad_lock ); + + deref_al_obj( &p_mad->h_al->obj ); + p_mad->h_al = NULL; +} + + + +void +al_handoff_mad( + IN const ib_al_handle_t h_al, + IN ib_mad_element_t* const p_mad_element ) +{ + al_mad_element_t *p_mad; + + p_mad = PARENT_STRUCT( p_mad_element, al_mad_element_t, element ); + + /* + * See if we're handing off to the same AL instance. This can happen if + * we hand off to an internal service that uses the global AL instance. + */ + if( p_mad->h_al == h_al ) + return; + + al_remove_mad( p_mad ); + al_insert_mad( h_al, p_mad ); +} + + + +void +al_insert_key( + IN const ib_al_handle_t h_al, + IN al_pool_key_t* const p_pool_key ) +{ + ref_al_obj( &h_al->obj ); + p_pool_key->h_al = h_al; + + cl_spinlock_acquire( &h_al->obj.lock ); + p_pool_key->in_al_list = TRUE; + cl_qlist_insert_tail( &h_al->key_list, &p_pool_key->al_item ); + cl_spinlock_release( &h_al->obj.lock ); +} + + + +/* + * Remove the pool_key from AL's list. This is called from the pool_key's + * cleanup routine. + */ +void +al_remove_key( + IN al_pool_key_t* const p_pool_key ) +{ + /* Return if the pool key is not in the AL instance key list. */ + if( !p_pool_key->h_al ) return; + + cl_spinlock_acquire( &p_pool_key->h_al->obj.lock ); + if( p_pool_key->in_al_list ) + { + cl_qlist_remove_item( &p_pool_key->h_al->key_list, + &p_pool_key->al_item ); + } + cl_spinlock_release( &p_pool_key->h_al->obj.lock ); + + deref_al_obj( &p_pool_key->h_al->obj ); + p_pool_key->h_al = NULL; +} + + + +void +al_dereg_pool( + IN const ib_al_handle_t h_al, + IN ib_pool_handle_t const h_pool ) +{ + cl_qlist_t destroy_list; + cl_list_item_t *p_list_item, *p_next_item; + al_pool_key_t *p_pool_key; + + /* + * Deregister matching pool keys. This may deregister memory, so we + * cannot do this while holding a lock. So we need to move the pool + * keys to a destroy_list. + */ + cl_qlist_init( &destroy_list ); + + /* Search for keys associated with the given PD or MAD pool. */ + cl_spinlock_acquire( &h_al->obj.lock ); + for( p_list_item = cl_qlist_head( &h_al->key_list ); + p_list_item != cl_qlist_end( &h_al->key_list ); + p_list_item = p_next_item ) + { + /* Cache the next item in case we remove this one. */ + p_next_item = cl_qlist_next( p_list_item ); + p_pool_key = PARENT_STRUCT( p_list_item, al_pool_key_t, al_item ); + + if( p_pool_key->h_pool == h_pool ) + { + /* + * Destroy this pool key. This only deregisters memory in + * user-mode since we use phys reg in kernel mode, so we + * can do this while holding a lock. + */ + ref_al_obj( &p_pool_key->obj ); + p_pool_key->in_al_list = FALSE; + cl_qlist_remove_item( &h_al->key_list, &p_pool_key->al_item ); + cl_qlist_insert_tail( &destroy_list, &p_pool_key->al_item ); + } + } + cl_spinlock_release( &h_al->obj.lock ); + + /* Destroy all pool_keys associated with the MAD pool. */ + for( p_list_item = cl_qlist_remove_head( &destroy_list ); + p_list_item != cl_qlist_end( &destroy_list ); + p_list_item = cl_qlist_remove_head( &destroy_list ) ) + { + /* Mark that we've remove the item from the list. */ + p_pool_key = PARENT_STRUCT( p_list_item, al_pool_key_t, al_item ); + p_pool_key->obj.pfn_destroy( &p_pool_key->obj, NULL ); + } +} + + +void +al_insert_query( + IN const ib_al_handle_t h_al, + IN al_query_t* const p_query ) +{ + p_query->h_al = h_al; + ref_al_obj( &h_al->obj ); + cl_spinlock_acquire( &h_al->obj.lock ); + cl_qlist_insert_tail( &h_al->query_list, &p_query->sa_req.list_item ); + cl_spinlock_release( &h_al->obj.lock ); +} + + +void +al_remove_query( + IN al_query_t* const p_query ) +{ + cl_spinlock_acquire( &p_query->h_al->obj.lock ); + cl_qlist_remove_item( &p_query->h_al->query_list, + &p_query->sa_req.list_item ); + cl_spinlock_release( &p_query->h_al->obj.lock ); + deref_al_obj( &p_query->h_al->obj ); +} + + + +static cl_status_t +__match_query( + IN const cl_list_item_t* const p_item, + IN void* context ) +{ + al_sa_req_t *p_sa_req; + + p_sa_req = PARENT_STRUCT( p_item, al_sa_req_t, list_item ); + if( context == PARENT_STRUCT( p_item, al_query_t, sa_req ) ) + return IB_SUCCESS; + + return IB_NOT_FOUND; +} + + +void +ib_cancel_query( + IN const ib_al_handle_t h_al, + IN const ib_query_handle_t h_query ) +{ + cl_list_item_t *p_item; + + AL_ENTER( AL_DBG_QUERY ); + + if( AL_OBJ_INVALID_HANDLE( h_al, AL_OBJ_TYPE_H_AL ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_AL_HANDLE\n") ); + return; + } + + cl_spinlock_acquire( &h_al->obj.lock ); + p_item = + cl_qlist_find_from_head( &h_al->query_list, __match_query, h_query ); + if( p_item != cl_qlist_end( &h_al->query_list ) ) + al_cancel_sa_req( &h_query->sa_req ); + + cl_spinlock_release( &h_al->obj.lock ); + + AL_EXIT( AL_DBG_QUERY ); +} diff --git a/branches/WOF2-3/core/al/al.h b/branches/WOF2-3/core/al/al.h new file mode 100644 index 00000000..07e402d9 --- /dev/null +++ b/branches/WOF2-3/core/al/al.h @@ -0,0 +1,294 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#if !defined(__AL_H__) +#define __AL_H__ + +#include +#include +#include +#include + +#include "al_common.h" +#include "al_mad_pool.h" +#include "al_query.h" +#include "al_reg_svc.h" +#ifdef CL_KERNEL +#include "al_proxy.h" +#endif + + + +typedef struct _al_handle +{ + uint32_t type; + al_obj_t *p_obj; + +} al_handle_t; + + +#define AL_INVALID_HANDLE 0 + + +/* + * AL instance structure. + */ +typedef struct _ib_al +{ + al_obj_t obj; + + /* Asynchronous processing item used to deregister services with the SA. */ + cl_async_proc_item_t dereg_svc_async; + + cl_qlist_t mad_list; + /* + * The MAD list must have a dedicated lock protecting it to prevent + * deadlocks. The MAD service gets/puts MADs from/to pools, which + * needs to track the MAD in the associated AL instance's mad_list. + * When cancelling SA requests, the AL instance's object lock is held + * and MAD cancellation takes the MAD service's lock. + */ + cl_spinlock_t mad_lock; + + cl_qlist_t key_list; + cl_qlist_t query_list; + cl_qlist_t cep_list; + +#ifdef CL_KERNEL + /* Handle manager is only needed in the kernel. */ + cl_vector_t hdl_vector; + uint64_t free_hdl; + + /* Proxy context. */ + al_dev_open_context_t *p_context; +#endif + +} ib_al_t; + + + +ib_api_status_t +init_al( + IN al_obj_t *p_parent_obj, + IN const ib_al_handle_t h_al ); + + +void +destroying_al( + IN al_obj_t *p_obj ); + + +void +free_al( + IN al_obj_t *p_obj ); + + + +/* + * Insert a pnp registration in the PnP vector. + */ +ib_api_status_t +al_insert_pnp( + IN const ib_al_handle_t h_al, + IN const ib_pnp_handle_t h_pnp ); + +/* + * Remove a pnp registration from the PnP vector. + */ +void +al_remove_pnp( + IN const ib_al_handle_t h_al, + IN const ib_pnp_handle_t h_pnp ); + + +void +al_insert_mad( + IN const ib_al_handle_t h_al, + IN al_mad_element_t* const p_mad ); + + +void +al_remove_mad( + IN al_mad_element_t* const p_mad ); + + +void +al_handoff_mad( + IN const ib_al_handle_t h_al, + IN ib_mad_element_t* const p_mad_element ); + + +void +al_insert_key( + IN const ib_al_handle_t h_al, + IN al_pool_key_t* const p_pool_key ); + + +void +al_remove_key( + IN al_pool_key_t* const p_pool_key ); + + +void +al_dereg_pool( + IN const ib_al_handle_t h_al, + IN ib_pool_handle_t const h_pool ); + + +void +al_insert_query( + IN const ib_al_handle_t h_al, + IN al_query_t* const p_query ); + + +void +al_remove_query( + IN al_query_t* const p_query ); + +void +al_insert_conn( + IN const ib_al_handle_t h_al, + IN const ib_cm_handle_t h_conn ); + +void +al_remove_conn( + IN const ib_cm_handle_t h_conn ); + +#ifdef CL_KERNEL +// TODO: Once all things in the handle vector are al_obj_t, +// TODO: we can remove the type parameter. +uint64_t +al_hdl_insert( + IN const ib_al_handle_t h_al, + IN void* const p_obj, + IN const uint32_t type ); + + +static inline uint64_t +al_hdl_lock_insert( + IN const ib_al_handle_t h_al, + IN void* const p_obj, + IN const uint32_t type ) +{ + uint64_t hdl; + cl_spinlock_acquire( &h_al->obj.lock ); + hdl = al_hdl_insert( h_al, p_obj, type ); + cl_spinlock_release( &h_al->obj.lock ); + return hdl; +} + + +void +al_hdl_free( + IN const ib_al_handle_t h_al, + IN const uint64_t hdl ); + + +static inline uint64_t +al_hdl_insert_obj( + IN al_obj_t* const p_obj ) +{ + uint64_t hdl; + + CL_ASSERT( p_obj->h_al ); + + cl_spinlock_acquire( &p_obj->h_al->obj.lock ); + hdl = al_hdl_insert( p_obj->h_al, p_obj, AL_BASE_TYPE( p_obj->type ) ); + cl_spinlock_release( &p_obj->h_al->obj.lock ); + + return hdl; +} + + +static inline void +al_hdl_free_obj( + IN al_obj_t* const p_obj ) +{ + CL_ASSERT( p_obj->h_al ); + CL_ASSERT( p_obj->hdl != AL_INVALID_HANDLE ); + cl_spinlock_acquire( &p_obj->h_al->obj.lock ); + + al_hdl_free( p_obj->h_al, p_obj->hdl ); + p_obj->hdl = AL_INVALID_HANDLE; + p_obj->hdl_valid = FALSE; + + cl_spinlock_release( &p_obj->h_al->obj.lock ); +} + + +al_obj_t* +al_hdl_ref( + IN const ib_al_handle_t h_al, + IN const uint64_t hdl, + IN const uint32_t type ); + +/* Validate an object. */ +void* +al_hdl_chk( + IN const ib_al_handle_t h_al, + IN const uint64_t hdl, + IN const uint32_t type ); + +/* Validate and remove an object. */ +void* +al_hdl_get( + IN const ib_al_handle_t h_al, + IN const uint64_t hdl, + IN const uint32_t type ); + +/* Validate and removes a MAD element. */ +static inline ib_mad_element_t* +al_hdl_get_mad( + IN const ib_al_handle_t h_al, + IN const uint64_t hdl ) +{ + return (ib_mad_element_t*)al_hdl_get( h_al, hdl, AL_OBJ_TYPE_H_MAD ); +} + +/* Validate and reference a connection. Used for MRA */ +struct _al_conn* +al_hdl_ref_conn( + IN const ib_al_handle_t h_al, + IN const uint64_t hdl, + IN const uint32_t sub_type ); + +/* Validate, reference, and remove a connection. */ +struct _al_conn* +al_hdl_get_conn( + IN const ib_al_handle_t h_al, + IN const uint64_t hdl, + IN const uint32_t sub_type ); + +#endif /* CL_KERNEL */ + +#endif /* __AL_H__ */ diff --git a/branches/WOF2-3/core/al/al_av.c b/branches/WOF2-3/core/al/al_av.c new file mode 100644 index 00000000..b94162e4 --- /dev/null +++ b/branches/WOF2-3/core/al/al_av.c @@ -0,0 +1,345 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include +#include "al.h" +#include "al_av.h" +#include "al_debug.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "al_av.tmh" +#endif + +#include "al_pd.h" +#include "al_res_mgr.h" +#include "al_verbs.h" + + + +static void +__cleanup_av( + IN struct _al_obj *p_obj ); + + +static void +__return_av( + IN al_obj_t *p_obj ); + + + +cl_status_t +av_ctor( + IN void* const p_object, + IN void* context, + OUT cl_pool_item_t** const pp_pool_item ) +{ + ib_api_status_t status; + ib_av_handle_t h_av; + + UNUSED_PARAM( context ); + + h_av = (ib_av_handle_t)p_object; + cl_memclr( h_av, sizeof( ib_av_t ) ); + + construct_al_obj( &h_av->obj, AL_OBJ_TYPE_H_AV ); + status = init_al_obj( &h_av->obj, NULL, FALSE, NULL, + __cleanup_av, __return_av ); + if( status != IB_SUCCESS ) + { + return CL_ERROR; + } + + *pp_pool_item = &((ib_av_handle_t)p_object)->obj.pool_item; + + /* Release the reference taken in init_al_obj. */ + deref_al_obj( &h_av->obj ); + + return CL_SUCCESS; +} + + +void +av_dtor( + IN const cl_pool_item_t* const p_pool_item, + IN void* context ) +{ + al_obj_t *p_obj; + + UNUSED_PARAM( context ); + + p_obj = PARENT_STRUCT( p_pool_item, al_obj_t, pool_item ); + + /* + * The AV is being totally destroyed. Modify the free_cb to destroy the + * AL object. + */ + p_obj->pfn_free = (al_pfn_free_t)destroy_al_obj; + ref_al_obj( p_obj ); + p_obj->pfn_destroy( p_obj, NULL ); +} + + +static ib_api_status_t +__check_av_port( + IN const al_ci_ca_t* const p_ci_ca, + IN const ib_av_attr_t* const p_av_attr ) +{ + ib_api_status_t status = IB_SUCCESS; + + if (p_av_attr->port_num == 0 || p_av_attr->port_num > p_ci_ca->num_ports) + { + AL_PRINT(TRACE_LEVEL_WARNING ,AL_DBG_AV, + ("invalid port number specified (%d)\n", p_av_attr->port_num) ); + status = IB_INVALID_PORT; + } + return status; +} + + +ib_api_status_t +create_av( + IN const ib_pd_handle_t h_pd, + IN const ib_av_attr_t* const p_av_attr, + OUT ib_av_handle_t* const ph_av, + IN OUT ci_umv_buf_t* const p_umv_buf ) +{ + ib_api_status_t status; + ib_av_handle_t h_av; + + CL_ASSERT( h_pd ); + + if( !p_av_attr || !ph_av ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + if( AL_OBJ_INVALID_HANDLE( h_pd, AL_OBJ_TYPE_H_PD ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PD_HANDLE\n") ); + return IB_INVALID_PD_HANDLE; + } + + status = __check_av_port(h_pd->obj.p_ci_ca, p_av_attr); + if( status != IB_SUCCESS ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PORT\n") ); + return status; + } + + /* Get an AV tracking structure. */ + h_av = alloc_av(); + if( !h_av ) + return IB_INSUFFICIENT_MEMORY; + + status = attach_al_obj( &h_pd->obj, &h_av->obj ); + if( status != IB_SUCCESS ) + { + h_av->obj.pfn_destroy( &h_av->obj, NULL ); + return status; + } + + /* Create the address vector. */ + status = verbs_create_av( h_pd, p_av_attr, h_av ); + if( status != IB_SUCCESS ) + { + h_av->obj.pfn_destroy( &h_av->obj, NULL ); + return status; + } + + /* keep a copy of the av for special qp access */ + h_av->av_attr = *p_av_attr; + *ph_av = h_av; + + return IB_SUCCESS; +} + + + +ib_api_status_t +ib_destroy_av( + IN const ib_av_handle_t h_av ) +{ + AL_ENTER( AL_DBG_AV ); + + if( AL_OBJ_INVALID_HANDLE( h_av, AL_OBJ_TYPE_H_AV ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_AV_HANDLE\n") ); + return IB_INVALID_AV_HANDLE; + } + + ref_al_obj( &h_av->obj ); + h_av->obj.pfn_destroy( &h_av->obj, NULL ); + + AL_EXIT( AL_DBG_AV ); + return IB_SUCCESS; +} + + + +static void +__cleanup_av( + IN struct _al_obj *p_obj ) +{ + ib_api_status_t status; + ib_av_handle_t h_av; + + CL_ASSERT( p_obj ); + h_av = PARENT_STRUCT( p_obj, ib_av_t, obj ); + + /* Destroy the AV. */ + if( verbs_check_av( h_av ) ) + { + status = verbs_destroy_av(h_av); + CL_ASSERT( status == IB_SUCCESS ); +#ifndef CL_KERNEL + h_av->obj.hdl = AL_INVALID_HANDLE; +#endif + h_av->h_ci_av = NULL; + } +} + + + +static void +__return_av( + IN al_obj_t *p_obj ) +{ + ib_av_handle_t h_av; + + h_av = PARENT_STRUCT( p_obj, ib_av_t, obj ); + reset_al_obj( p_obj ); + put_av( h_av ); +} + + + +ib_api_status_t +ib_query_av( + IN const ib_av_handle_t h_av, + OUT ib_av_attr_t* const p_av_attr, + OUT ib_pd_handle_t* const ph_pd ) +{ + return query_av( h_av, p_av_attr, ph_pd, NULL ); +} + + + +ib_api_status_t +query_av( + IN const ib_av_handle_t h_av, + OUT ib_av_attr_t* const p_av_attr, + OUT ib_pd_handle_t* const ph_pd, + IN OUT ci_umv_buf_t* const p_umv_buf ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_AV ); + + if( AL_OBJ_INVALID_HANDLE( h_av, AL_OBJ_TYPE_H_AV ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_AV_HANDLE\n") ); + return IB_INVALID_AV_HANDLE; + } + if( !p_av_attr || !ph_pd ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + status = verbs_query_av(h_av, p_av_attr, ph_pd); + + /* Record AL's PD handle. */ + if( status == IB_SUCCESS ) + { + *ph_pd = PARENT_STRUCT( h_av->obj.p_parent_obj, ib_pd_t, obj ); + h_av->av_attr = *p_av_attr; + } + + AL_EXIT( AL_DBG_AV ); + return status; +} + + + +ib_api_status_t +ib_modify_av( + IN const ib_av_handle_t h_av, + IN const ib_av_attr_t* const p_av_mod ) +{ + return modify_av( h_av, p_av_mod, NULL ); +} + + +ib_api_status_t +modify_av( + IN const ib_av_handle_t h_av, + IN const ib_av_attr_t* const p_av_mod, + IN OUT ci_umv_buf_t* const p_umv_buf ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_AV ); + + if( AL_OBJ_INVALID_HANDLE( h_av, AL_OBJ_TYPE_H_AV ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_AV_HANDLE\n") ); + return IB_INVALID_AV_HANDLE; + } + if( !p_av_mod ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + status = __check_av_port(h_av->obj.p_ci_ca, p_av_mod); + if( status != IB_SUCCESS ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PORT\n") ); + return status; + } + + status = verbs_modify_av(h_av, p_av_mod); + + /* Record av for special qp access */ + if( status == IB_SUCCESS ) + { + h_av->av_attr = *p_av_mod; + } + + AL_EXIT( AL_DBG_AV ); + return status; +} diff --git a/branches/WOF2-3/core/al/al_av.h b/branches/WOF2-3/core/al/al_av.h new file mode 100644 index 00000000..ffbff2f1 --- /dev/null +++ b/branches/WOF2-3/core/al/al_av.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#if !defined(__AL_AV_H__) +#define __AL_AV_H__ + + +#include "al_ca.h" +#include +#include + + +typedef struct _ib_av +{ + al_obj_t obj; + ib_av_handle_t h_ci_av; /* Actual HW CI AV. */ + + ib_av_attr_t av_attr; + + cl_list_item_t list_item; /* item to manage AL AV's */ + +} ib_av_t; + + + +cl_status_t +av_ctor( + IN void* const p_object, + IN void* context, + OUT cl_pool_item_t** const pp_pool_item ); + +void +av_dtor( + IN const cl_pool_item_t* const p_pool_item, + IN void* context ); + + +ib_api_status_t +create_av( + IN const ib_pd_handle_t h_pd, + IN const ib_av_attr_t* const p_av_attr, + OUT ib_av_handle_t* const ph_av, + IN OUT ci_umv_buf_t* const p_umv_buf ); + + +ib_api_status_t +query_av( + IN const ib_av_handle_t h_av, + OUT ib_av_attr_t* const p_av_attr, + OUT ib_pd_handle_t* const ph_pd, + IN OUT ci_umv_buf_t* const p_umv_buf ); + + +ib_api_status_t +modify_av( + IN const ib_av_handle_t h_av, + IN const ib_av_attr_t* const p_av_mod, + IN OUT ci_umv_buf_t* const p_umv_buf ); + + +#endif /* __AL_AV_H__ */ diff --git a/branches/WOF2-3/core/al/al_ca.c b/branches/WOF2-3/core/al/al_ca.c new file mode 100644 index 00000000..e056cf30 --- /dev/null +++ b/branches/WOF2-3/core/al/al_ca.c @@ -0,0 +1,425 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include +#include + +#include "al.h" +#include "al_av.h" +#include "al_ca.h" +#include "al_cq.h" +#include "al_debug.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "al_ca.tmh" +#endif + +#include "al_mgr.h" +#include "al_mr.h" +#include "al_mw.h" +#include "al_pd.h" +#include "al_qp.h" +#include "al_verbs.h" +#include "ib_common.h" + + +static void +__destroying_ca( + IN struct _al_obj *p_obj ); + +static void +__cleanup_ca( + IN struct _al_obj *p_obj ); + +static void +__free_ca( + IN struct _al_obj *p_obj ); + + + +ib_api_status_t +ib_open_ca( + IN const ib_al_handle_t h_al, + IN const ib_net64_t ca_guid, + IN const ib_pfn_event_cb_t pfn_ca_event_cb OPTIONAL, + IN const void* const ca_context, + OUT ib_ca_handle_t* const ph_ca ) +{ + ib_api_status_t status; + + if( AL_OBJ_INVALID_HANDLE( h_al, AL_OBJ_TYPE_H_AL ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_AL_HANDLE\n") ); + return IB_INVALID_AL_HANDLE; + } + + status = open_ca( h_al, ca_guid, pfn_ca_event_cb, ca_context, ph_ca, NULL ); + + /* Release the reference taken in init_al_obj. */ + if( status == IB_SUCCESS ) + deref_al_obj( &(*ph_ca)->obj ); + + return status; +} + + +ib_api_status_t +open_ca( + IN const ib_al_handle_t h_al, + IN const ib_net64_t ca_guid, + IN const ib_pfn_event_cb_t pfn_ca_event_cb OPTIONAL, + IN const void* const ca_context, + OUT ib_ca_handle_t* const ph_ca, + IN OUT ci_umv_buf_t* const p_umv_buf OPTIONAL ) +{ + ib_ca_handle_t h_ca; + ib_api_status_t status; + al_obj_type_t obj_type = AL_OBJ_TYPE_H_CA; + + AL_ENTER( AL_DBG_CA ); + if( !ph_ca ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + /* Allocate a CA instance. */ + h_ca = (ib_ca_handle_t)cl_zalloc( sizeof( ib_ca_t ) ); + if( !h_ca ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("IB_INSUFFICIENT_MEMORY\n") ); + return IB_INSUFFICIENT_MEMORY; + } + + /* Construct the CA. */ + if( p_umv_buf ) + obj_type |= AL_OBJ_SUBTYPE_UM_EXPORT; + construct_al_obj( &h_ca->obj, obj_type ); + h_ca->pfn_event_cb = pfn_ca_event_cb; + + status = init_al_obj( &h_ca->obj, ca_context, TRUE, + NULL, __cleanup_ca, __free_ca ); + if( status != IB_SUCCESS ) + { + __free_ca( &h_ca->obj ); + AL_EXIT( AL_DBG_CA ); + return status; + } + + status = attach_al_obj( &h_al->obj, &h_ca->obj ); + if( status != IB_SUCCESS ) + { + h_ca->obj.pfn_destroy( &h_ca->obj, NULL ); + AL_EXIT( AL_DBG_CA ); + return status; + } + + /* Obtain a reference to the correct CI CA. */ + h_ca->obj.p_ci_ca = acquire_ci_ca( ca_guid, h_ca ); + if( !h_ca->obj.p_ci_ca ) + { + h_ca->obj.pfn_destroy( &h_ca->obj, NULL ); + AL_EXIT( AL_DBG_CA ); + return IB_INVALID_GUID; + } + +#if defined(CL_KERNEL) + /* If a UM open, pass to the VPD to establish the UM CA context. */ + if( p_umv_buf ) + { + status = h_ca->obj.p_ci_ca->verbs.um_open_ca( + h_ca->obj.p_ci_ca->h_ci_ca, p_umv_buf, &h_ca->h_um_ca ); + if( status != IB_SUCCESS ) + { + h_ca->obj.pfn_destroy( &h_ca->obj, NULL ); + AL_EXIT( AL_DBG_CA ); + return status; + } + } +#endif /* defined(CL_KERNEL) */ + + *ph_ca = h_ca; + + AL_EXIT( AL_DBG_CA ); + return IB_SUCCESS; +} + + +/* + * Destroy an instance of an AL channel adapter. + */ +ib_api_status_t +ib_close_ca( + IN const ib_ca_handle_t h_ca, + IN const ib_pfn_destroy_cb_t pfn_destroy_cb OPTIONAL ) +{ + AL_ENTER( AL_DBG_CA ); + + if( AL_OBJ_INVALID_HANDLE( h_ca, AL_OBJ_TYPE_H_CA ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_CA_HANDLE\n") ); + return IB_INVALID_CA_HANDLE; + } + + ref_al_obj( &h_ca->obj ); + h_ca->obj.pfn_destroy( &h_ca->obj, pfn_destroy_cb ); + + AL_EXIT( AL_DBG_CA ); + return IB_SUCCESS; +} + + +/* + * Release all resources associated with the CA. + */ +static void +__cleanup_ca( + IN struct _al_obj *p_obj ) +{ +#if defined(CL_KERNEL) + ib_ca_handle_t h_ca; + + CL_ASSERT( p_obj ); + h_ca = PARENT_STRUCT( p_obj, ib_ca_t, obj ); + if( h_ca->h_um_ca ) + { + h_ca->obj.p_ci_ca->verbs.um_close_ca( + h_ca->obj.p_ci_ca->h_ci_ca, h_ca->h_um_ca ); + } +#endif + + /* It is now safe to release the CI CA. */ + if( p_obj->p_ci_ca ) + release_ci_ca( PARENT_STRUCT( p_obj, ib_ca_t, obj ) ); +} + + + +static void +__free_ca( + IN struct _al_obj *p_obj ) +{ + ib_ca_handle_t h_ca; + + CL_ASSERT( p_obj ); + h_ca = PARENT_STRUCT( p_obj, ib_ca_t, obj ); + + destroy_al_obj( p_obj ); + cl_free( h_ca ); +} + + + +ib_api_status_t +ib_query_ca( + IN const ib_ca_handle_t h_ca, + OUT ib_ca_attr_t* const p_ca_attr OPTIONAL, + IN OUT uint32_t* const p_size ) +{ + return query_ca( h_ca, p_ca_attr, p_size, NULL ); +} + + + +ib_api_status_t +query_ca( + IN const ib_ca_handle_t h_ca, + OUT ib_ca_attr_t* const p_ca_attr OPTIONAL, + IN OUT uint32_t* const p_size, + IN OUT ci_umv_buf_t* const p_umv_buf ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_CA ); + + if( AL_OBJ_INVALID_HANDLE( h_ca, AL_OBJ_TYPE_H_CA ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_CA_HANDLE\n") ); + return IB_INVALID_CA_HANDLE; + } + if( !p_size ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + status = verbs_query_ca( h_ca, p_ca_attr, p_size ); + + AL_EXIT( AL_DBG_CA ); + return status; +} + + + +ib_api_status_t +ib_modify_ca( + IN const ib_ca_handle_t h_ca, + IN const uint8_t port_num, + IN const ib_ca_mod_t ca_mod, + IN const ib_port_attr_mod_t* const p_port_attr_mod ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_CA ); + + if( AL_OBJ_INVALID_HANDLE( h_ca, AL_OBJ_TYPE_H_CA ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_CA_HANDLE\n") ); + return IB_INVALID_CA_HANDLE; + } + if( !p_port_attr_mod || (ca_mod & IB_CA_MOD_RESERVED_MASK) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + status = verbs_modify_ca(h_ca, port_num, ca_mod, p_port_attr_mod); + + AL_EXIT( AL_DBG_CA ); + return status; +} + + + +/* + * Allocate a new protection domain. + */ +ib_api_status_t +ib_alloc_pd( + IN const ib_ca_handle_t h_ca, + IN const ib_pd_type_t pd_type, + IN const void * const pd_context, + OUT ib_pd_handle_t* const ph_pd ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_PD ); + + if( AL_OBJ_INVALID_HANDLE( h_ca, AL_OBJ_TYPE_H_CA ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_CA_HANDLE\n") ); + return IB_INVALID_CA_HANDLE; + } + + status = alloc_pd( h_ca, pd_type, pd_context, ph_pd, NULL ); + + /* Release the reference taken in init_al_obj. */ + if( status == IB_SUCCESS ) + deref_al_obj( &(*ph_pd)->obj ); + + AL_EXIT( AL_DBG_PD ); + return status; +} + + + +ib_api_status_t +ib_create_cq( + IN const ib_ca_handle_t h_ca, + IN OUT ib_cq_create_t* const p_cq_create, + IN const void* const cq_context, + IN const ib_pfn_event_cb_t pfn_cq_event_cb OPTIONAL, + OUT ib_cq_handle_t* const ph_cq ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_CQ ); + + if( AL_OBJ_INVALID_HANDLE( h_ca, AL_OBJ_TYPE_H_CA ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_CA_HANDLE\n") ); + return IB_INVALID_CA_HANDLE; + } + + status = create_cq( h_ca, p_cq_create, cq_context, pfn_cq_event_cb, + ph_cq, NULL ); + + /* Release the reference taken in init_al_obj. */ + if( status == IB_SUCCESS ) + deref_al_obj( &(*ph_cq)->obj ); + + AL_EXIT( AL_DBG_CQ ); + return status; +} + + +ib_api_status_t +al_convert_to_ci_handles( + IN void** const dst_handle_array, + IN const void** const src_handle_array, + IN uint32_t num_handles ) +{ + uint32_t i; + al_obj_t *p_al_obj; + + for( i = 0; i < num_handles; i++ ) + { + p_al_obj = (al_obj_t*)(const void*)src_handle_array[i]; + switch( p_al_obj->type ) + { + case AL_OBJ_TYPE_H_PD: + dst_handle_array[i] = ((ib_pd_t*)p_al_obj)->h_ci_pd; + break; + case AL_OBJ_TYPE_H_CQ: + dst_handle_array[i] = ((ib_cq_t*)p_al_obj)->h_ci_cq; + break; + case AL_OBJ_TYPE_H_AV: + dst_handle_array[i] = ((ib_av_t*)p_al_obj)->h_ci_av; + break; + case AL_OBJ_TYPE_H_QP: + dst_handle_array[i] = ((ib_qp_t*)p_al_obj)->h_ci_qp; + break; + case AL_OBJ_TYPE_H_MR: + dst_handle_array[i] = ((ib_mr_t*)p_al_obj)->h_ci_mr; + break; + case AL_OBJ_TYPE_H_MW: + dst_handle_array[i] = ((ib_mw_t*)p_al_obj)->h_ci_mw; + break; + default: + /* Bad handle type. */ + CL_ASSERT( p_al_obj->type == AL_OBJ_TYPE_H_PD || + p_al_obj->type == AL_OBJ_TYPE_H_CQ || + p_al_obj->type == AL_OBJ_TYPE_H_AV || + p_al_obj->type == AL_OBJ_TYPE_H_QP || + p_al_obj->type == AL_OBJ_TYPE_H_MR || + p_al_obj->type == AL_OBJ_TYPE_H_MW ); + return IB_INVALID_HANDLE; + } + } + + return IB_SUCCESS; +} diff --git a/branches/WOF2-3/core/al/al_ca.h b/branches/WOF2-3/core/al/al_ca.h new file mode 100644 index 00000000..403a0a08 --- /dev/null +++ b/branches/WOF2-3/core/al/al_ca.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#if !defined(__AL_CA_H__) +#define __AL_CA_H__ + +#include +#include + +#include "al_common.h" +#include "al_ci_ca.h" + + + +typedef struct _ib_ca +{ + al_obj_t obj; + + ib_pfn_event_cb_t pfn_event_cb; + cl_list_item_t list_item; +#if defined(CL_KERNEL) + ib_ca_handle_t h_um_ca; + PDEVICE_OBJECT p_hca_dev; + PDEVICE_OBJECT p_fdo; +#endif + +} ib_ca_t; + + +ib_api_status_t +open_ca( + IN const ib_al_handle_t h_al, + IN const ib_net64_t ca_guid, + IN const ib_pfn_event_cb_t pfn_ca_event_cb OPTIONAL, + IN const void* const ca_context, + OUT ib_ca_handle_t* const ph_ca, + IN OUT ci_umv_buf_t* const p_umv_buf OPTIONAL ); + + +ib_api_status_t +query_ca( + IN const ib_ca_handle_t h_ca, + OUT ib_ca_attr_t* const p_ca_attr OPTIONAL, + IN OUT uint32_t* const p_size, + IN OUT ci_umv_buf_t* const p_umv_buf ); + + +ib_api_status_t +al_convert_to_ci_handles( + IN void** const dst_handle_array, + IN const void** const src_handle_array, + IN uint32_t num_handles ); + + +#endif /* __AL_CA_H__ */ diff --git a/branches/WOF2-3/core/al/al_ci_ca.h b/branches/WOF2-3/core/al/al_ci_ca.h new file mode 100644 index 00000000..8d654143 --- /dev/null +++ b/branches/WOF2-3/core/al/al_ci_ca.h @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#if !defined(__AL_CI_CA_H__) +#define __AL_CI_CA_H__ + +#include +#ifdef CL_KERNEL +#include +#include +#else +#include "ual_ci_ca.h" +#endif /* CL_KERNEL */ + + +#include +#include +#include + +#include "al_common.h" + + +#ifdef CL_KERNEL +typedef ci_interface_t verbs_interface_t; + +ib_api_status_t +create_ci_ca( + IN al_obj_t *p_parent_obj, + IN const ci_interface_t* p_ci, + IN const PDEVICE_OBJECT p_hca_dev, + IN const PDEVICE_OBJECT p_fdo + ); + +DEVICE_OBJECT* +get_ca_dev( + IN const ib_ca_handle_t h_ca ); +#endif + +#define MAX_AE 32 +typedef struct _al_ae_info { + ib_pnp_event_t pnp_event; + uint8_t port_index; +} al_ae_info_t; + + +typedef struct _al_ci_ca +{ + al_obj_t obj; + cl_list_item_t list_item; + + cl_async_proc_item_t dereg_async_item; + + verbs_interface_t verbs; + + ib_ca_handle_t h_ci_ca; /* CI handle */ + ib_ca_handle_t h_ca; /* AL handle */ + ib_pd_handle_t h_pd; /* AL handle */ + ib_pd_handle_t h_pd_alias; /* AL handle */ + ib_pool_key_t pool_key; /* AL handle */ + + /* Opened instances of this CA. */ + cl_qlist_t ca_list; + + /* + * Last known attributes as reported by the PnP manager. + * Updated by the PnP manager through the asynchronous processing thread. + */ + ib_ca_attr_t *p_pnp_attr; + ib_ca_attr_t *p_user_attr; + cl_spinlock_t attr_lock; + + cl_qpool_t event_pool; + + uint8_t num_ports; + + /* Shared memory registrations across processes. */ + cl_qlist_t shmid_list; + + /* Array of port GUIDs on this CI CA. */ + ib_net64_t *port_array; + + /* "end of PnP handling" event */ + cl_event_t event; + + /* Array of pending AEs (Asynchronic events) */ + al_ae_info_t ae[MAX_AE]; /* pending Asynchronic Events */ + int ci; /* Consumer Index - first event to handle */ + int pi; /* Producer index - next not handled event */ + int cnt; /* number of not handled events */ + +} al_ci_ca_t; + + +ib_api_status_t +get_port_info( + IN al_ci_ca_t *p_ci_ca ); + + +/* + * Asynchronous event reporting. + */ +typedef struct _event_item +{ + cl_async_proc_item_t async_item; + ib_async_event_rec_t event_rec; + +} event_item_t; + + +void +add_ca( + IN al_ci_ca_t* const p_ci_ca, + IN const ib_ca_handle_t h_ca ); + +void +remove_ca( + IN const ib_ca_handle_t h_ca ); + + +void +ca_event_cb( + IN ib_async_event_rec_t *p_event_rec ); + +void +free_ci_ca( + IN al_obj_t* p_obj ); + + +void +ci_ca_async_event( + IN const ib_async_event_rec_t* const p_event_rec ); + + +struct _al_shmid; + +void +add_shmid( + IN al_ci_ca_t* const p_ci_ca, + IN struct _al_shmid *p_shmid ); + +ib_api_status_t +acquire_shmid( + IN al_ci_ca_t* const p_ci_ca, + IN int shmid, + OUT struct _al_shmid **pp_shmid ); + +void +release_shmid( + IN struct _al_shmid *p_shmid ); + + + +ib_api_status_t +get_port_num( + IN al_ci_ca_t* const p_ci_ca, + IN const ib_net64_t port_guid, + OUT uint8_t *p_port_num OPTIONAL ); + +ib_port_attr_t* +get_port_attr( + IN ib_ca_attr_t * const p_ca_attr, + IN ib_gid_t * const p_gid ); + + +#define BAD_PKEY_INDEX 0xFFFF + +uint16_t +get_pkey_index( + IN ib_port_attr_t * const p_port_attr, + IN const ib_net16_t pkey ); + +ib_api_status_t +ci_ca_update_attr( + IN al_ci_ca_t* p_ci_ca, + OUT ib_ca_attr_t** pp_old_pnp_attr ); + +void +ci_ca_lock_attr( + IN al_ci_ca_t* const p_ci_ca ); + +void +ci_ca_excl_lock_attr( + IN al_ci_ca_t* const p_ci_ca ); + +void +ci_ca_unlock_attr( + IN al_ci_ca_t* const p_ci_ca ); + +ib_api_status_t +ci_call( + IN ib_ca_handle_t h_ca, + IN const void** const handle_array OPTIONAL, + IN uint32_t num_handles, + IN ib_ci_op_t* const p_ci_op, + IN ci_umv_buf_t* const p_umv_buf OPTIONAL ); + + +#endif /* __AL_CI_CA_H__ */ diff --git a/branches/WOF2-3/core/al/al_ci_ca_shared.c b/branches/WOF2-3/core/al/al_ci_ca_shared.c new file mode 100644 index 00000000..da867599 --- /dev/null +++ b/branches/WOF2-3/core/al/al_ci_ca_shared.c @@ -0,0 +1,616 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include "al_ci_ca.h" +#include "al_common.h" +#include "al_cq.h" +#include "al_debug.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "al_ci_ca_shared.tmh" +#endif + +#include "al_mgr.h" +#include "al_pnp.h" +#include "al_qp.h" +#include "al_srq.h" +#include "ib_common.h" + + +void +ci_ca_process_event_cb( + IN cl_async_proc_item_t* p_async_item ); + +void +ca_process_async_event_cb( + IN const ib_async_event_rec_t* const p_event_rec ); + +void +ca_async_event_cb( + IN ib_async_event_rec_t* const p_event_rec ); + + +void +free_ci_ca( + IN al_obj_t* p_obj ) +{ + al_ci_ca_t *p_ci_ca; + + CL_ASSERT( p_obj ); + p_ci_ca = PARENT_STRUCT( p_obj, al_ci_ca_t, obj ); + + cl_spinlock_destroy( &p_ci_ca->attr_lock ); + cl_qpool_destroy( &p_ci_ca->event_pool ); + cl_event_destroy( &p_ci_ca->event ); + + if( p_ci_ca->port_array ) + cl_free( p_ci_ca->port_array ); + + /* Free the PnP attributes buffer. */ + if( p_ci_ca->p_pnp_attr ) + cl_free( p_ci_ca->p_pnp_attr ); + + destroy_al_obj( p_obj ); + cl_free( p_ci_ca ); +} + +void +add_ca( + IN al_ci_ca_t* const p_ci_ca, + IN const ib_ca_handle_t h_ca ) +{ + cl_spinlock_acquire( &p_ci_ca->obj.lock ); + cl_qlist_insert_tail( &p_ci_ca->ca_list, &h_ca->list_item ); + ref_al_obj( &p_ci_ca->obj ); + cl_spinlock_release( &p_ci_ca->obj.lock ); +} + + + +void +remove_ca( + IN const ib_ca_handle_t h_ca ) +{ + al_ci_ca_t *p_ci_ca; + + p_ci_ca = h_ca->obj.p_ci_ca; + + cl_spinlock_acquire( &p_ci_ca->obj.lock ); + cl_qlist_remove_item( &p_ci_ca->ca_list, &h_ca->list_item ); + cl_spinlock_release( &p_ci_ca->obj.lock ); + deref_al_obj( &p_ci_ca->obj ); +} + + + +ib_api_status_t +get_port_info( + IN al_ci_ca_t *p_ci_ca ) +{ + ib_api_status_t status; + ib_ca_attr_t *p_ca_attr; + uint32_t attr_size; + uint8_t i; + + AL_ENTER( AL_DBG_CA ); + + /* Get the size of the CA attribute structure. */ + status = ib_query_ca( p_ci_ca->h_ca, NULL, &attr_size ); + if( status != IB_INSUFFICIENT_MEMORY ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("ib_query_ca failed with status %s.\n", ib_get_err_str(status)) ); + return status; + } + + /* Allocate enough space to store the attribute structure. */ + p_ca_attr = cl_malloc( attr_size ); + if( !p_ca_attr ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("cl_malloc failed to allocate p_ca_attr!\n") ); + return IB_INSUFFICIENT_RESOURCES; + } + + /* Query the CA attributes. */ + status = ib_query_ca( p_ci_ca->h_ca, p_ca_attr, &attr_size ); + if( status != IB_SUCCESS ) + { + cl_free( p_ca_attr ); + + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("ib_query_ca failed with status %s.\n", ib_get_err_str(status)) ); + return status; + } + + /* Allocate the port GUID array. */ + p_ci_ca->port_array = cl_malloc( sizeof( ib_net64_t ) * + p_ca_attr->num_ports ); + if( !p_ci_ca->port_array ) + { + cl_free( p_ca_attr ); + + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("cl_malloc failed to allocate port_array!\n") ); + return IB_INSUFFICIENT_RESOURCES; + } + p_ci_ca->num_ports = p_ca_attr->num_ports; + + /* Copy the necessary port information. */ + for( i = 0; i < p_ca_attr->num_ports; i++ ) + { + p_ci_ca->port_array[i] = p_ca_attr->p_port_attr[i].port_guid; + +#ifdef CL_KERNEL + /* Set the port's client reregister bit. */ + { + ib_port_attr_mod_t attr; + + attr.cap.client_reregister = TRUE; + ib_modify_ca( p_ci_ca->h_ca, i + 1, + IB_CA_MOD_IS_CLIENT_REREGISTER_SUPPORTED, &attr ); + } +#endif + } + + cl_free( p_ca_attr ); + + AL_EXIT( AL_DBG_CA ); + return IB_SUCCESS; +} + + + +void +ci_ca_async_event( + IN const ib_async_event_rec_t* const p_event_rec ) +{ + al_obj_t* p_obj; + cl_pool_item_t* p_item; + event_item_t* p_event_item; + + AL_ENTER( AL_DBG_CA ); + + CL_ASSERT( p_event_rec ); + + p_obj = (al_obj_t*)p_event_rec->context; + + /* Block the destruction of the object until a reference is taken. */ + cl_spinlock_acquire( &p_obj->lock ); + if( p_obj->state == CL_DESTROYING ) + { + /* Ignore events if the object is being destroyed. */ + cl_spinlock_release( &p_obj->lock ); + AL_EXIT( AL_DBG_CA ); + return; + } + + /* + * Get an event item from the pool. If an object is a child of + * a CA (e.g., CQ or QP) it will have valid p_ci_ca pointer. + * For CA's, the object is the actual p_ci_ca pointer itself. + */ + if( p_obj->p_ci_ca ) + { + cl_spinlock_acquire( &p_obj->p_ci_ca->obj.lock ); + p_item = cl_qpool_get( &p_obj->p_ci_ca->event_pool ); + cl_spinlock_release( &p_obj->p_ci_ca->obj.lock ); + } + else + { + p_item = cl_qpool_get( &((al_ci_ca_t*)p_obj)->event_pool ); + } + if( !p_item ) + { + /* Could not get an item. This event will not be reported. */ + cl_spinlock_release( &p_obj->lock ); + AL_EXIT( AL_DBG_CA ); + return; + } + + /* Hold a reference to prevent destruction until the async_item runs. */ + ref_al_obj( p_obj ); + + cl_spinlock_release( &p_obj->lock ); + + /* Initialize the item with the asynchronous event information. */ + p_event_item = PARENT_STRUCT( p_item, event_item_t, async_item.pool_item ); + p_event_item->event_rec.code = p_event_rec->code; + p_event_item->event_rec.context = p_event_rec->context; + p_event_item->event_rec.port_number = p_event_rec->port_number; + + /* Queue the item on the asynchronous callback thread for processing. */ + p_event_item->async_item.pfn_callback = ci_ca_process_event_cb; + cl_async_proc_queue( gp_async_proc_mgr, &p_event_item->async_item ); + + AL_EXIT( AL_DBG_CA ); +} + + + +void +ci_ca_process_event_cb( + IN cl_async_proc_item_t* p_async_item ) +{ + event_item_t* p_event_item; + al_obj_t* p_obj; + + AL_ENTER( AL_DBG_CA ); + + CL_ASSERT( p_async_item ); + + p_event_item = PARENT_STRUCT( p_async_item, event_item_t, + async_item.pool_item ); + + p_obj = (al_obj_t*)p_event_item->event_rec.context; + + switch( p_event_item->event_rec.code ) + { + case IB_AE_QP_COMM: + case IB_AE_QP_APM: + case IB_AE_QP_APM_ERROR: + case IB_AE_QP_FATAL: + case IB_AE_RQ_ERROR: + case IB_AE_SQ_ERROR: + case IB_AE_SQ_DRAINED: + case IB_AE_WQ_REQ_ERROR: + case IB_AE_WQ_ACCESS_ERROR: + case IB_AE_SRQ_QP_LAST_WQE_REACHED: + qp_async_event_cb( &p_event_item->event_rec ); + break; + + case IB_AE_SRQ_LIMIT_REACHED: + case IB_AE_SRQ_CATAS_ERROR: + srq_async_event_cb( &p_event_item->event_rec ); + break; + + case IB_AE_CQ_ERROR: + cq_async_event_cb( &p_event_item->event_rec ); + break; + +#ifdef CL_KERNEL + + case IB_AE_LID_CHANGE: + case IB_AE_CLIENT_REREGISTER: + // These AE events will be generated even in the case when + // SM was restaretd but LID will not actually change. + // It's important to propagate these event (via PnP mechanism) + // up to subscribers. Otherwise, there will be no ping after + // subnet manager restart + //if (AL_OBJ_IS_TYPE(p_obj, AL_OBJ_TYPE_CI_CA) + if (AL_BASE_TYPE( p_obj->type) == AL_OBJ_TYPE_CI_CA) { + pnp_force_event( (struct _al_ci_ca *) p_obj, IB_PNP_LID_CHANGE, + p_event_item->event_rec.port_number ); + force_smi_poll(); + } + break; +#endif //CL_KERNEL + + case IB_AE_PORT_TRAP: + case IB_AE_PORT_DOWN: + case IB_AE_PORT_ACTIVE: + +#ifdef CL_KERNEL + /* The SMI polling routine may report a PnP event. */ + force_smi_poll(); +#endif + /* Fall through next case. */ + + case IB_AE_LOCAL_FATAL: + ca_process_async_event_cb( &p_event_item->event_rec ); + break; + + /* Unhandled events - optional per IBA spec. */ + case IB_AE_QKEY_TRAP: + case IB_AE_PKEY_TRAP: + case IB_AE_MKEY_TRAP: + case IB_AE_BKEY_TRAP: + case IB_AE_BUF_OVERRUN: + case IB_AE_LINK_INTEGRITY: + case IB_AE_FLOW_CTRL_ERROR: + case IB_AE_SYSIMG_GUID_TRAP: + default: + break; + } + + /* + * Return the event item to the pool. If an object is a child of + * a CA (e.g., CQ or QP) it will have valid p_ci_ca pointer. + * For CA's, the object is the actual p_ci_ca pointer itself. + */ + if( p_obj->p_ci_ca ) + { + cl_spinlock_acquire( &p_obj->p_ci_ca->obj.lock ); + cl_qpool_put( &p_obj->p_ci_ca->event_pool, + &p_event_item->async_item.pool_item ); + cl_spinlock_release( &p_obj->p_ci_ca->obj.lock ); + } + else + { + cl_spinlock_acquire( &p_obj->lock ); + cl_qpool_put( &((al_ci_ca_t*)p_obj)->event_pool, + &p_event_item->async_item.pool_item ); + cl_spinlock_release( &p_obj->lock ); + } + + /* Dereference the object. */ + deref_al_obj( p_obj ); + + AL_EXIT( AL_DBG_CA ); +} + + + +/* + * Process an asynchronous event on a CA. Notify all clients of the event. + */ +void +ca_process_async_event_cb( + IN const ib_async_event_rec_t* const p_event_rec ) +{ + al_ci_ca_t* p_ci_ca; + cl_list_item_t* p_list_item; + ib_ca_handle_t h_ca; + ib_async_event_rec_t event_rec; + + CL_ASSERT( p_event_rec ); + p_ci_ca = (al_ci_ca_t*)p_event_rec->context; + + /* Report the CA event to all clients. */ + cl_spinlock_acquire( &p_ci_ca->obj.lock ); + for( p_list_item = cl_qlist_head( &p_ci_ca->ca_list ); + p_list_item != cl_qlist_end( &p_ci_ca->ca_list ); + p_list_item = cl_qlist_next( p_list_item ) ) + { + cl_spinlock_release( &p_ci_ca->obj.lock ); + + h_ca = PARENT_STRUCT( p_list_item, ib_ca_t, list_item ); + + event_rec.handle.h_ca = h_ca; + event_rec.code = p_event_rec->code; + ca_async_event_cb( &event_rec ); + + cl_spinlock_acquire( &p_ci_ca->obj.lock ); + } + cl_spinlock_release( &p_ci_ca->obj.lock ); +} + + + +/* + * Process an asynchronous event on a CA. Notify the user of the event. + */ +void +ca_async_event_cb( + IN ib_async_event_rec_t* const p_event_rec ) +{ + ib_ca_handle_t h_ca; + + CL_ASSERT( p_event_rec ); + h_ca = p_event_rec->handle.h_ca; + + p_event_rec->context = (void*)h_ca->obj.context; + p_event_rec->handle.h_ca = h_ca; + + if( h_ca->pfn_event_cb ) + h_ca->pfn_event_cb( p_event_rec ); +} + + + +void +ca_event_cb( + IN ib_async_event_rec_t *p_event_rec ) +{ + UNUSED_PARAM( p_event_rec ); +} + + + +/* + * Returns a port's index on its CA for the given port GUID. + */ +ib_api_status_t +get_port_num( + IN al_ci_ca_t* const p_ci_ca, + IN const ib_net64_t port_guid, + OUT uint8_t *p_port_num OPTIONAL ) +{ + uint8_t i; + + /* Find a matching port GUID on this CI CA. */ + for( i = 0; i < p_ci_ca->num_ports; i++ ) + { + if( p_ci_ca->port_array[i] == port_guid ) + { + /* The port number is the index plus one. */ + if( p_port_num ) + *p_port_num = (uint8_t)(i + 1); + return IB_SUCCESS; + } + } + + /* The port GUID was not found. */ + return IB_INVALID_GUID; +} + + + +ib_port_attr_t* +get_port_attr( + IN ib_ca_attr_t * const p_ca_attr, + IN ib_gid_t * const p_gid ) +{ + uintn_t port_index, gid_index; + ib_port_attr_t *p_port_attr; + + AL_ENTER( AL_DBG_CA ); + + if( !p_ca_attr || !p_gid ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("No p_ca_attr or p_gid.\n") ); + return NULL; + } + + /* Check all ports on this HCA for matching GID. */ + for( port_index = 0; port_index < p_ca_attr->num_ports; port_index++ ) + { + p_port_attr = &p_ca_attr->p_port_attr[port_index]; + + for( gid_index = 0; gid_index < p_port_attr->num_gids; gid_index++ ) + { + if( !cl_memcmp( &p_port_attr->p_gid_table[gid_index], + p_gid, sizeof(ib_gid_t) ) ) + { + AL_EXIT( AL_DBG_CA ); + return p_port_attr; + } + } + } + + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("No match found.\n") ); + return NULL; +} + + + +uint16_t +get_pkey_index( + IN ib_port_attr_t * const p_port_attr, + IN const ib_net16_t pkey ) +{ + uint16_t pkey_index; + + if( !p_port_attr ) + return BAD_PKEY_INDEX; + + for( pkey_index = 0; pkey_index < p_port_attr->num_pkeys; pkey_index++ ) + { + if( p_port_attr->p_pkey_table[pkey_index] == pkey ) + return pkey_index; + } + return BAD_PKEY_INDEX; +} + + +/* + * Reads the CA attributes from verbs. + */ +ib_api_status_t +ci_ca_update_attr( + IN al_ci_ca_t* p_ci_ca, + OUT ib_ca_attr_t** pp_old_pnp_attr ) +{ + ib_ca_attr_t *p_pnp_attr; + uint32_t attr_size; + ib_api_status_t status; + + AL_ENTER( AL_DBG_CA ); + + /* Query to get the CA attributes size. */ + attr_size = 0; + status = ib_query_ca( p_ci_ca->h_ca, NULL, &attr_size ); + CL_ASSERT( status == IB_INSUFFICIENT_MEMORY ); + + /* + * Allocate the new CA attributes buffer. + * Double the buffer size for PnP and user reporting halves. + */ + p_pnp_attr = (ib_ca_attr_t*)cl_zalloc( attr_size * 2 ); + if( !p_pnp_attr ) + { + AL_PRINT_EXIT( TRACE_LEVEL_WARNING, AL_DBG_CA, + ("Unable to allocate buffer for PnP attributes\n") ); + return IB_INSUFFICIENT_MEMORY; + } + + /* Read the attributes. */ + status = ib_query_ca( p_ci_ca->h_ca, p_pnp_attr, &attr_size ); + if( status != IB_SUCCESS ) + { + AL_PRINT_EXIT( TRACE_LEVEL_WARNING, AL_DBG_CA, + ("Unable to query attributes\n") ); + cl_free( p_pnp_attr ); + return status; + } + + ci_ca_excl_lock_attr( p_ci_ca ); + if( pp_old_pnp_attr ) + *pp_old_pnp_attr = p_ci_ca->p_pnp_attr; + p_ci_ca->p_pnp_attr = p_pnp_attr; + + /* + * Initialize pointer to the user reporting half. + * This buffer is used to report this CAs attributes to users. + */ + p_ci_ca->p_user_attr = (ib_ca_attr_t*)(((uint8_t*)p_pnp_attr) + attr_size); + ci_ca_unlock_attr( p_ci_ca ); + + AL_EXIT( AL_DBG_CA ); + return IB_SUCCESS; +} + + + +void +ci_ca_lock_attr( + IN al_ci_ca_t* const p_ci_ca ) +{ + CL_ASSERT( p_ci_ca ); + + cl_spinlock_acquire( &p_ci_ca->attr_lock ); +} + + +void +ci_ca_excl_lock_attr( + IN al_ci_ca_t* const p_ci_ca ) +{ + CL_ASSERT( p_ci_ca ); + + cl_spinlock_acquire( &p_ci_ca->attr_lock ); +} + + +void +ci_ca_unlock_attr( + IN al_ci_ca_t* const p_ci_ca ) +{ + CL_ASSERT( p_ci_ca ); + + cl_spinlock_release( &p_ci_ca->attr_lock ); +} diff --git a/branches/WOF2-3/core/al/al_cm_cep.h b/branches/WOF2-3/core/al/al_cm_cep.h new file mode 100644 index 00000000..07a838b1 --- /dev/null +++ b/branches/WOF2-3/core/al/al_cm_cep.h @@ -0,0 +1,516 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#pragma once + +#ifndef _AL_CM_CEP_H_ +#define _AL_CM_CEP_H_ + +#include +#include "al_common.h" + +#ifdef CL_KERNEL +#include +#endif + +#define CEP_EVENT_TIMEOUT 0x80000000 +#define CEP_EVENT_RECV 0x40000000 +#define CEP_EVENT_REQ 0x00000001 +#define CEP_EVENT_REP 0x00000002 +#define CEP_EVENT_RTU 0x00000004 +#define CEP_EVENT_DREQ 0x00000008 +#define CEP_EVENT_DREP 0x00000010 +#define CEP_EVENT_MRA 0x00000020 +#define CEP_EVENT_REJ 0x00000040 +#define CEP_EVENT_LAP 0x00000080 +#define CEP_EVENT_APR 0x00000100 +#define CEP_EVENT_SIDR 0x00800000 + + +#define AL_INVALID_CID 0xFFFFFFFF +#define AL_RESERVED_CID 0 + + +typedef void +(*al_pfn_cep_cb_t)( + IN const ib_al_handle_t h_al, + IN const net32_t cid ); +/* PARAMETERS +* h_al +* [in] Handle to the AL instance to pass into the al_cep_poll call. +* +* cid +* [in] CID of the CEP on which the event occurred. The CID should +* be passed into the al_cep_poll call. +* +* RETURN VALUES: +* This function does not return a value. +* +* NOTES +* The callback is invoked at DISPATCH_LEVEL. +* +* Recipients of the callback are expected to call al_cep_poll to retrieve +* event specific details until al_cep_poll returns IB_NOT_DONE. This may +* be done in a different thread context. +*********/ + + +ib_api_status_t +create_cep_mgr( + IN al_obj_t* const p_parent_obj ); + + +void +al_cep_cleanup_al( + IN const ib_al_handle_t h_al ); + + +ib_api_status_t +al_create_cep( + IN ib_al_handle_t h_al, + IN al_pfn_cep_cb_t pfn_cb, + IN void* context, + IN ib_pfn_destroy_cb_t pfn_destroy_cb OPTIONAL, + IN OUT net32_t* const p_cid ); +/* +* NOTES +* This function may be invoked at DISPATCH_LEVEL +* +* The pfn_cb parameter may be NULL in the kernel if using IRPs for +* event notification. +*********/ + +#ifdef CL_KERNEL +ib_api_status_t +kal_cep_alloc( + IN ib_al_handle_t h_al, + IN OUT net32_t* const p_cid ); + +ib_api_status_t +kal_cep_config( + IN ib_al_handle_t h_al, + IN net32_t cid, + IN al_pfn_cep_cb_t pfn_cb, + IN void* context, + IN ib_pfn_destroy_cb_t pfn_destroy_cb ); +#endif + +/* Destruction is asynchronous. */ +void +al_destroy_cep( + IN ib_al_handle_t h_al, + IN OUT net32_t* const p_cid, + IN boolean_t reusable ); +/* +*********/ + +ib_api_status_t +al_cep_listen( + IN ib_al_handle_t h_al, + IN net32_t cid, + IN ib_cep_listen_t* const p_listen_info ); + + +#ifdef CL_KERNEL +ib_api_status_t +kal_cep_pre_req( + IN ib_al_handle_t h_al, + IN net32_t cid, + IN const iba_cm_req* const p_cm_req, + IN uint8_t rnr_nak_timeout, + IN OUT ib_qp_mod_t* const p_init OPTIONAL ); +#endif + +ib_api_status_t +al_cep_pre_req( + IN ib_al_handle_t h_al, + IN net32_t cid, + IN const ib_cm_req_t* const p_cm_req, + OUT ib_qp_mod_t* const p_init ); + + +ib_api_status_t +al_cep_send_req( + IN ib_al_handle_t h_al, + IN net32_t cid ); + + +ib_api_status_t +al_cep_pre_rep( + IN ib_al_handle_t h_al, + IN net32_t cid, + IN void* context, + IN ib_pfn_destroy_cb_t pfn_destroy_cb OPTIONAL, + IN const ib_cm_rep_t* const p_cm_rep, + IN OUT net32_t* const p_cid, + OUT ib_qp_mod_t* const p_init ); + +#ifdef CL_KERNEL +ib_api_status_t +kal_cep_pre_rep( + IN ib_al_handle_t h_al, + IN net32_t cid, + IN const iba_cm_rep* const p_cm_rep, + IN uint8_t rnr_nak_timeout, + IN OUT ib_qp_mod_t* const p_init OPTIONAL ); + +void +kal_cep_destroy( + IN ib_al_handle_t h_al, + IN net32_t cid, + IN NTSTATUS status ); +#endif + +ib_api_status_t +al_cep_send_rep( + IN ib_al_handle_t h_al, + IN net32_t cid ); + +#ifdef CL_KERNEL +void +kal_cep_format_event( + IN ib_al_handle_t h_al, + IN net32_t cid, + IN ib_mad_element_t *p_mad, + IN OUT iba_cm_event *p_event); + +ib_api_status_t +al_cep_get_init_attr( + IN ib_al_handle_t h_al, + IN net32_t cid, + OUT ib_qp_mod_t* const p_init ); +#endif + +ib_api_status_t +al_cep_get_rtr_attr( + IN ib_al_handle_t h_al, + IN net32_t cid, + OUT ib_qp_mod_t* const p_rtr ); + + +ib_api_status_t +al_cep_get_rts_attr( + IN ib_al_handle_t h_al, + IN net32_t cid, + OUT ib_qp_mod_t* const p_rts ); + + +ib_api_status_t +al_cep_rtu( + IN ib_al_handle_t h_al, + IN net32_t cid, + IN const uint8_t* p_pdata OPTIONAL, + IN uint8_t pdata_len ); + + +ib_api_status_t +al_cep_rej( + IN ib_al_handle_t h_al, + IN net32_t cid, + IN ib_rej_status_t rej_status, + IN const uint8_t* const p_ari, + IN uint8_t ari_len, + IN const uint8_t* const p_pdata, + IN uint8_t pdata_len ); + + +ib_api_status_t +al_cep_mra( + IN ib_al_handle_t h_al, + IN net32_t cid, + IN const ib_cm_mra_t* const p_cm_mra ); + + +ib_api_status_t +al_cep_lap( + IN ib_al_handle_t h_al, + IN net32_t cid, + IN const ib_cm_lap_t* const p_cm_lap ); + + +ib_api_status_t +al_cep_pre_apr( + IN ib_al_handle_t h_al, + IN net32_t cid, + IN const ib_cm_apr_t* const p_cm_apr, + OUT ib_qp_mod_t* const p_apr ); + + +ib_api_status_t +al_cep_send_apr( + IN ib_al_handle_t h_al, + IN net32_t cid ); + + +ib_api_status_t +al_cep_dreq( + IN ib_al_handle_t h_al, + IN net32_t cid, + IN const uint8_t* const p_pdata OPTIONAL, + IN const uint8_t pdata_len ); + + +ib_api_status_t +al_cep_drep( + IN ib_al_handle_t h_al, + IN net32_t cid, + IN const uint8_t* const p_pdata OPTIONAL, + IN const uint8_t pdata_len ); + + +ib_api_status_t +al_cep_get_timewait( + IN ib_al_handle_t h_al, + IN net32_t cid, + OUT uint64_t* const p_timewait_us ); + + +ib_api_status_t +al_cep_migrate( + IN ib_al_handle_t h_al, + IN net32_t cid ); + + +ib_api_status_t +al_cep_established( + IN ib_al_handle_t h_al, + IN net32_t cid ); + + +ib_api_status_t +al_cep_poll( + IN ib_al_handle_t h_al, + IN net32_t cid, + OUT void** p_context, + OUT net32_t* const p_new_cid, + OUT ib_mad_element_t** const pp_mad ); + + +#ifdef CL_KERNEL +void cm_get_interface(iba_cm_interface *p_ifc); + +NTSTATUS +al_cep_queue_irp( + IN ib_al_handle_t h_al, + IN net32_t cid, + IN IRP* const p_irp ); + +NTSTATUS +al_cep_get_pdata( + IN ib_al_handle_t h_al, + IN net32_t cid, + OUT uint8_t *p_init_depth, + OUT uint8_t *p_resp_res, + IN OUT uint8_t *p_psize, + OUT uint8_t* pdata ); + +void* +kal_cep_get_context( + IN ib_al_handle_t h_al, + IN net32_t cid, + IN al_pfn_cep_cb_t pfn_cb, + IN ib_pfn_destroy_cb_t pfn_addref ); +#endif /* CL_KERNEL */ + + +/****s* Access Layer/al_cep_sreq_t +* NAME +* al_cep_sreq_t +* +* DESCRIPTION +* Connection request information used to establish a new connection. +* +* SYNOPSIS +*/ +typedef struct _al_cep_sreq +{ + ib_net64_t svc_id; + + ib_path_rec_t* p_path; + + const uint8_t* p_pdata; + uint8_t pdata_len; + + uint8_t max_cm_retries; + ib_net16_t pkey; + uint32_t timeout_ms; + +} al_cep_sreq_t; +/* +* FIELDS +* svc_id +* The ID of the remote service to which the SIDR request is +* being made. +* +* p_path +* Path information over which to send the request. +* +* p_pdata +* Optional user-defined private data sent as part of the SIDR request. +* +* pdata_len +* Defines the size of the user-defined private data. +* +* max_cm_retries +* The maximum number of times that either CM should +* resend a SIDR message. +* +* timeout_ms +* Timeout value in milli-seconds for the SIDR REQ to expire. The CM will +* add twice packet lifetime to this value to determine the actual timeout +* value used. +* +* pkey +* pkey to be used as part of the request. +* +* SEE ALSO +* al_cep_sreq +*****/ + +ib_api_status_t +al_cep_sreq( + IN ib_al_handle_t h_al, + IN net32_t cid, + IN const al_cep_sreq_t* const p_sreq ); + + +/****s* Access Layer/al_cep_srep_t +* NAME +* al_cep_srep_t +* +* DESCRIPTION +* SIDR reply information. +* +* SYNOPSIS +*/ +typedef struct _al_cep_srep +{ + net32_t qp_num; + net32_t qkey; + + const uint8_t* p_pdata; + const void* p_info; + + uint8_t pdata_len; + uint8_t info_len; + + ib_sidr_status_t status; + +} al_cep_srep_t; +/* +* FIELDS +* qp_num +* The number of the queue pair on which the requested service +* is supported. +* +* qp_key +* The QKEY of the returned queue pair. +* +* p_pdata +* Optional user-defined private data sent as part of the SIDR reply. +* +* p_info +* Optional "additonal information" sent as part of the SIDR reply. +* +* pdata_len +* Size of the user-defined private data. +* +* info_len +* Size of the "additional information". +* +* status +* sidr status value returned back to a previously received REQ. +* +* SEE ALSO +* al_cep_srep +*****/ + +ib_api_status_t +al_cep_srep( + IN ib_al_handle_t h_al, + IN net32_t cid, + IN const al_cep_srep_t* const p_sreq ); + + + + +/* + * Return the local ACK timeout value based on the given packet lifetime + * and target ACK delay. Both input values are assumed to be in the form + * 4.096 x 2 ^ input. + */ +#define MAX_LOCAL_ACK_TIMEOUT 0x1F /* limited to 5 bits */ + +inline uint8_t +calc_lcl_ack_timeout( + IN const uint8_t round_trip_time, + IN const uint8_t target_ack_delay ) +{ + uint64_t timeout; + uint8_t local_ack_timeout; + + if( !target_ack_delay ) + { + if( round_trip_time > MAX_LOCAL_ACK_TIMEOUT ) + return MAX_LOCAL_ACK_TIMEOUT; + else + return round_trip_time; + } + + /* + * Since both input and the output values are in the same form, we + * can ignore the 4.096 portion by dividing it out. + */ + + /* The input parameter is the round trip time. */ + timeout = (uint64_t)1 << round_trip_time; + + /* Add in the target ack delay. */ + if( target_ack_delay ) + timeout += (uint64_t)1 << target_ack_delay; + + /* Calculate the local ACK timeout. */ + local_ack_timeout = 1; + while( (1ui64 << local_ack_timeout) <= timeout ) + { + local_ack_timeout++; + + /* Only 5-bits are valid. */ + if( local_ack_timeout > MAX_LOCAL_ACK_TIMEOUT ) + return MAX_LOCAL_ACK_TIMEOUT; + } + + return local_ack_timeout; +} + +#endif /* _AL_CM_CEP_H_ */ diff --git a/branches/WOF2-3/core/al/al_cm_conn.h b/branches/WOF2-3/core/al/al_cm_conn.h new file mode 100644 index 00000000..d11ab34f --- /dev/null +++ b/branches/WOF2-3/core/al/al_cm_conn.h @@ -0,0 +1,1308 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#if !defined(__IB_AL_CM_CONN_H__) +#define __IB_AL_CM_CONN_H__ + + +#include +#include +#include "al_common.h" + + +/* + * Helper functions + */ +static inline void +__set_low24( + OUT ib_field32_t* const p_field, + IN const net32_t val ) +{ + const uint8_t* p8 = (const uint8_t*)&val; + + p_field->bytes[0] = p8[1]; + p_field->bytes[1] = p8[2]; + p_field->bytes[2] = p8[3]; +} + +/* + * Returns a network byte ordered 32-bit quantity equal to the 24-bit value + * stored in the lower 3-bytes of the supplied field + */ +static inline net32_t +__get_low24( + IN const ib_field32_t field ) +{ + return cl_hton32( cl_ntoh32( field.val ) >> 8 ); +} + +static inline net32_t +__get_low20( + IN const ib_field32_t field ) +{ + return cl_hton32( cl_ntoh32( field.val ) >> 12 ); +} + +/* + * CM MAD definitions. + */ +#include + +typedef struct _req_path_info +{ + ib_net16_t local_lid; + ib_net16_t remote_lid; + ib_gid_t local_gid; + ib_gid_t remote_gid; + + /* Version 2: Flow Label:20, rsvd:6, Packet Rate:6 */ + ib_field32_t offset36; + + uint8_t traffic_class; + uint8_t hop_limit; + /* SL:4, Subnet Local:1, rsvd:3 */ + uint8_t offset42; + /* Local ACK Timeout:5, rsvd:3 */ + uint8_t offset43; + +} PACK_SUFFIX req_path_info_t; + + +#define CM_REQ_ATTR_ID CL_HTON16(0x0010) +typedef struct _mad_cm_req +{ + ib_mad_t hdr; + + ib_net32_t local_comm_id; + ib_net32_t rsvd1; + ib_net64_t sid; + ib_net64_t local_ca_guid; + ib_net32_t rsvd2; + ib_net32_t local_qkey; + + /* Local QPN:24, Responder resources:8 */ + ib_field32_t offset32; + /* Local EECN:24, Initiator depth:8 */ + ib_field32_t offset36; + /* + * Remote EECN:24, Remote CM Response Timeout:5, + * Transport Service Type:2, End-to-End Flow Control:1 + */ + ib_field32_t offset40; + /* Starting PSN:24, Local CM Response Timeout:5, Retry Count:3. */ + ib_field32_t offset44; + + ib_net16_t pkey; + + /* Path MTU:4, RDC Exists:1, RNR Retry Count:3. */ + uint8_t offset50; + /* Max CM Retries:4, rsvd:4 */ + uint8_t offset51; + + req_path_info_t primary_path; + req_path_info_t alternate_path; + + uint8_t pdata[IB_REQ_PDATA_SIZE]; + +} PACK_SUFFIX mad_cm_req_t; +C_ASSERT( sizeof(mad_cm_req_t) == MAD_BLOCK_SIZE ); + +#include + +/* REQ functions */ + +/* REQ offset32 accessors. */ +static inline ib_net32_t +conn_req_get_lcl_qpn( + IN const mad_cm_req_t* const p_req ) +{ + CL_ASSERT( p_req->hdr.class_ver == IB_MCLASS_CM_VER_2 ); + return __get_low24( p_req->offset32 ); +} + +static inline void +conn_req_set_lcl_qpn( + IN const ib_net32_t qpn, + IN OUT mad_cm_req_t* const p_req ) +{ + CL_ASSERT( p_req->hdr.class_ver == IB_MCLASS_CM_VER_2 ); + __set_low24( &p_req->offset32, qpn ); +} + +static inline uint8_t +conn_req_get_resp_res( + IN const mad_cm_req_t* const p_req ) +{ + CL_ASSERT( p_req->hdr.class_ver == IB_MCLASS_CM_VER_2 ); + return p_req->offset32.bytes[3]; +} + +static inline void +conn_req_set_resp_res( + IN const uint8_t resp_res, + IN OUT mad_cm_req_t* const p_req ) +{ + CL_ASSERT( p_req->hdr.class_ver == IB_MCLASS_CM_VER_2 ); + p_req->offset32.bytes[3] = resp_res; +} + +/* REQ offset36 accessors. */ +static inline uint8_t +conn_req_get_init_depth( + IN const mad_cm_req_t* const p_req ) +{ + CL_ASSERT( p_req->hdr.class_ver == IB_MCLASS_CM_VER_2 ); + return p_req->offset36.bytes[3]; +} + +static inline void +conn_req_set_init_depth( + IN const uint8_t init_depth, + IN OUT mad_cm_req_t* const p_req ) +{ + CL_ASSERT( p_req->hdr.class_ver == IB_MCLASS_CM_VER_2 ); + p_req->offset36.bytes[3] = init_depth; +} + +static inline uint8_t +conn_req_get_resp_timeout( + IN const mad_cm_req_t* const p_req ) +{ + CL_ASSERT( p_req->hdr.class_ver == IB_MCLASS_CM_VER_2 ); + return (p_req->offset40.bytes[3] >> 3); +} + +static inline void +conn_req_set_remote_resp_timeout( + IN const uint8_t resp_timeout, + IN OUT mad_cm_req_t* const p_req ) +{ + CL_ASSERT( !(resp_timeout & 0xE0) ); + CL_ASSERT( p_req->hdr.class_ver == IB_MCLASS_CM_VER_2 ); + p_req->offset40.bytes[3] &= 0x07; + p_req->offset40.bytes[3] |= (resp_timeout << 3); +} + +static inline ib_qp_type_t +conn_req_get_qp_type( + IN const mad_cm_req_t* const p_req ) +{ + CL_ASSERT( p_req->hdr.class_ver == IB_MCLASS_CM_VER_2 ); + return ( ib_qp_type_t )( (p_req->offset40.bytes[3] >> 1) & 0x3 ); +} + +static inline void +conn_req_set_qp_type( + IN const ib_qp_type_t qp_type, + IN OUT mad_cm_req_t* const p_req ) +{ + CL_ASSERT( !(qp_type & 0xFC) ); + CL_ASSERT( p_req->hdr.class_ver == IB_MCLASS_CM_VER_2 ); + p_req->offset40.bytes[3] &= 0xF9; + p_req->offset40.bytes[3] |= ( ((uint8_t)qp_type & 0x03) << 1 ); +} + +static inline boolean_t +conn_req_get_flow_ctrl( + IN const mad_cm_req_t* const p_req ) +{ + CL_ASSERT(p_req->hdr.class_ver == IB_MCLASS_CM_VER_2 ); + return ( (p_req->offset40.bytes[3] & 0x01) != 0 ); +} + +static inline void +conn_req_set_flow_ctrl( + IN const boolean_t flow_ctrl, + IN OUT mad_cm_req_t* const p_req ) +{ + CL_ASSERT( p_req->hdr.class_ver == IB_MCLASS_CM_VER_2 ); + if( flow_ctrl ) + p_req->offset40.bytes[3] |= 0x01; + else + p_req->offset40.bytes[3] &= 0xFE; +} + +/* REQ offset44 accessors. */ +static inline ib_net32_t +conn_req_get_starting_psn( + IN const mad_cm_req_t* const p_req ) +{ + CL_ASSERT( p_req->hdr.class_ver == IB_MCLASS_CM_VER_2 ); + return __get_low24( p_req->offset44 ); +} + +static inline void +conn_req_set_starting_psn( + IN const ib_net32_t starting_psn, + IN mad_cm_req_t* const p_req ) +{ + CL_ASSERT( p_req->hdr.class_ver == IB_MCLASS_CM_VER_2 ); + __set_low24( &p_req->offset44, starting_psn ); +} + +static inline uint8_t +conn_req_get_retry_cnt( + IN const mad_cm_req_t* const p_req ) +{ + CL_ASSERT( p_req->hdr.class_ver == IB_MCLASS_CM_VER_2 ); + return p_req->offset44.bytes[3] & 0x7; +} + +static inline void +conn_req_set_retry_cnt( + IN const uint8_t retry_cnt, + IN OUT mad_cm_req_t* const p_req ) +{ + CL_ASSERT( p_req->hdr.class_ver == IB_MCLASS_CM_VER_2 ); + p_req->offset44.bytes[3] &= 0xF8; + p_req->offset44.bytes[3] |= (retry_cnt & 0x7); +} + +static inline uint8_t +conn_req_get_lcl_resp_timeout( + IN const mad_cm_req_t* const p_req ) +{ + CL_ASSERT( p_req->hdr.class_ver == IB_MCLASS_CM_VER_2 ); + return (p_req->offset44.bytes[3] >> 3); +} + +static inline void +conn_req_set_lcl_resp_timeout( + IN const uint8_t resp_timeout, + IN OUT mad_cm_req_t* const p_req ) +{ + CL_ASSERT( !(resp_timeout & 0xE0) ); + CL_ASSERT( p_req->hdr.class_ver == IB_MCLASS_CM_VER_2 ); + p_req->offset44.bytes[3] &= 0x07; + p_req->offset44.bytes[3] |= (resp_timeout << 3); +} + +/* REQ offset50 accessors. */ +static inline uint8_t +conn_req_get_mtu( + IN const mad_cm_req_t* const p_req ) +{ + CL_ASSERT( p_req->hdr.class_ver == IB_MCLASS_CM_VER_2 ); + return ( p_req->offset50 >> 4); +} + +static inline void +conn_req_set_mtu( + IN const uint8_t path_mtu, + IN OUT mad_cm_req_t* const p_req ) +{ + CL_ASSERT( !(path_mtu & 0xF0) ); + CL_ASSERT( p_req->hdr.class_ver == IB_MCLASS_CM_VER_2 ); + p_req->offset50 &= 0x0F; + p_req->offset50 |= (path_mtu << 4); +} + +static inline uint8_t +conn_req_get_rnr_retry_cnt( + IN const mad_cm_req_t* const p_req ) +{ + CL_ASSERT( p_req->hdr.class_ver == IB_MCLASS_CM_VER_2 ); + return ( p_req->offset50 & 0x07 ); +} + +static inline void +conn_req_set_rnr_retry_cnt( + IN const uint8_t rnr_retry_cnt, + IN OUT mad_cm_req_t* const p_req ) +{ + CL_ASSERT( !(rnr_retry_cnt & 0xF8) ); + CL_ASSERT( p_req->hdr.class_ver == IB_MCLASS_CM_VER_2 ); + p_req->offset50 &= 0xF8; + p_req->offset50 |= (rnr_retry_cnt & 0x07); +} + +static inline uint8_t +conn_req_get_max_cm_retries( + IN const mad_cm_req_t* const p_req ) +{ + CL_ASSERT( p_req->hdr.class_ver == IB_MCLASS_CM_VER_2 ); + return (uint8_t)( p_req->offset51 >> 4 ); +} + +static inline void +conn_req_set_max_cm_retries( + IN const uint8_t retries, + IN OUT mad_cm_req_t* const p_req ) +{ + CL_ASSERT( !(retries & 0xF0) ); + CL_ASSERT( p_req->hdr.class_ver == IB_MCLASS_CM_VER_2 ); + p_req->offset51 = (retries << 4); +} + +static inline ib_api_status_t +conn_req_set_pdata( + IN const uint8_t* const p_data OPTIONAL, + IN const uint8_t data_len, + IN OUT mad_cm_req_t* const p_req ) +{ + CL_ASSERT( p_req->hdr.class_ver == IB_MCLASS_CM_VER_2 ); + + if( p_data ) + { + if( data_len > IB_REQ_PDATA_SIZE ) + return IB_INVALID_SETTING; + + cl_memcpy( p_req->pdata, p_data, data_len ); + cl_memclr( p_req->pdata + data_len, IB_REQ_PDATA_SIZE - data_len ); + } + else + { + cl_memclr( p_req->pdata, IB_REQ_PDATA_SIZE ); + } + return IB_SUCCESS; +} + +static inline void +conn_req_clr_rsvd_fields( + IN OUT mad_cm_req_t* const p_req ) +{ + CL_ASSERT( p_req->hdr.class_ver == IB_MCLASS_CM_VER_2 ); + p_req->rsvd1 = 0; + p_req->rsvd2 = 0; + p_req->offset36.val &= CL_HTON32( 0x000000FF ); + p_req->offset40.val &= CL_HTON32( 0x000000FF ); + p_req->offset50 &= 0xF7; + p_req->offset51 &= 0xF0; +} + +/* REQ Path accessors. */ +static inline net32_t +conn_req_path_get_flow_lbl( + IN const req_path_info_t* const p_path ) +{ + return __get_low20( p_path->offset36 ); +} + +static inline void +conn_req_path_set_flow_lbl( + IN const net32_t flow_lbl, + IN OUT req_path_info_t* const p_path ) +{ + CL_ASSERT( !(cl_ntoh32( flow_lbl ) & 0xFFF00000) ); + __set_low24( &p_path->offset36, (flow_lbl & CL_HTON32( 0x000FFFFF )) ); +} + +static inline uint8_t +conn_req_path_get_pkt_rate( + IN const req_path_info_t* const p_path ) +{ + return p_path->offset36.bytes[3] & 0x3F; +} + +static inline void +conn_req_path_set_pkt_rate( + IN const uint8_t rate, + OUT req_path_info_t* const p_path ) +{ + CL_ASSERT( !(rate & 0xC0) ); + p_path->offset36.bytes[3] = (rate & 0x3F); +} + +static inline uint8_t +conn_req_path_get_svc_lvl( + IN const req_path_info_t* const p_path ) +{ + return ( p_path->offset42 >> 4 ); +} + +static inline void +conn_req_path_set_svc_lvl( + IN const uint8_t svc_lvl, + IN OUT req_path_info_t* const p_path ) +{ + CL_ASSERT( !(svc_lvl & 0xF0) ); + p_path->offset42 = ( ( p_path->offset42 & 0x08 ) | (svc_lvl << 4) ); +} + +static inline boolean_t +conn_req_path_get_subn_lcl( + IN const req_path_info_t* const p_path ) +{ + return (p_path->offset42 & 0x08) != 0; +} + +static inline void +conn_req_path_set_subn_lcl( + IN const boolean_t subn_lcl, + IN OUT req_path_info_t* const p_path ) +{ + if( subn_lcl ) + p_path->offset42 = ((p_path->offset42 & 0xF0) | 0x08); + else + p_path->offset42 = (p_path->offset42 & 0xF0); +} + +static inline uint8_t +conn_req_path_get_lcl_ack_timeout( + IN const req_path_info_t* const p_path ) +{ + return( p_path->offset43 >> 3 ); +} + +static inline void +conn_req_path_set_lcl_ack_timeout( + IN const uint8_t lcl_ack_timeout, + IN OUT req_path_info_t* const p_path ) +{ + CL_ASSERT( !(lcl_ack_timeout & 0xE0) ); + p_path->offset43 = (lcl_ack_timeout << 3); +} + +static inline void +conn_req_path_clr_rsvd_fields( + IN OUT req_path_info_t* const p_path ) +{ + p_path->offset36.val &= CL_HTON32( 0xFFFFF03F ); + p_path->offset42 &= 0xF8; + p_path->offset43 &= 0xF8; +} + + + +/* MRA */ +#include + +#define CM_MRA_ATTR_ID CL_HTON16(0x0011) +/* MRA is the same in ver1 and ver2. */ +typedef struct _mad_cm_mra +{ + ib_mad_t hdr; + + ib_net32_t local_comm_id; + ib_net32_t remote_comm_id; + /* Message MRAed:2, rsvd:6 */ + uint8_t offset8; + /* Service Timeout:5, rsvd:3 */ + uint8_t offset9; + + uint8_t pdata[IB_MRA_PDATA_SIZE]; + +} PACK_SUFFIX mad_cm_mra_t; +C_ASSERT( sizeof(mad_cm_mra_t) == MAD_BLOCK_SIZE ); + +#include + +static inline uint8_t +conn_mra_get_msg_mraed( + IN const mad_cm_mra_t* const p_mra ) +{ + return (p_mra->offset8 >> 6); +} + +static inline void +conn_mra_set_msg_mraed( + IN const uint8_t msg, + OUT mad_cm_mra_t* const p_mra ) +{ + p_mra->offset8 = (msg << 6); +} + +static inline uint8_t +conn_mra_get_svc_timeout( + IN const mad_cm_mra_t* const p_mra ) +{ + return (p_mra->offset9 >> 3); +} + +static inline void +conn_mra_set_svc_timeout( + IN const uint8_t svc_timeout, + OUT mad_cm_mra_t* const p_mra ) +{ + p_mra->offset9 = (svc_timeout << 3); +} + +static inline ib_api_status_t +conn_mra_set_pdata( + IN const uint8_t* const p_data OPTIONAL, + IN const uint8_t data_len, + IN OUT mad_cm_mra_t* const p_mra ) +{ + if( p_data ) + { + if( data_len > IB_MRA_PDATA_SIZE ) + return IB_INVALID_SETTING; + + cl_memcpy( p_mra->pdata, p_data, data_len ); + cl_memclr( p_mra->pdata + data_len, IB_MRA_PDATA_SIZE - data_len ); + } + else + { + cl_memclr( p_mra->pdata, IB_MRA_PDATA_SIZE ); + } + return IB_SUCCESS; +} + +static inline void +conn_mra_clr_rsvd_fields( + IN OUT mad_cm_mra_t* const p_mra ) +{ + p_mra->offset8 &= 0xC0; + p_mra->offset9 &= 0xF8; +} + + + +/* REJ */ + +#include + +#define CM_REJ_ATTR_ID CL_HTON16(0x0012) +/* REJ is the same in ver1 and ver2. */ +typedef struct _mad_cm_rej +{ + ib_mad_t hdr; + + ib_net32_t local_comm_id; + ib_net32_t remote_comm_id; + + /* Message REJected:2, rsvd:6 */ + uint8_t offset8; + + /* Reject Info Length:7, rsvd:1. */ + uint8_t offset9; + + ib_net16_t reason; + uint8_t ari[IB_ARI_SIZE]; + uint8_t pdata[IB_REJ_PDATA_SIZE]; + +} PACK_SUFFIX mad_cm_rej_t; +C_ASSERT( sizeof(mad_cm_rej_t) == MAD_BLOCK_SIZE ); + +#include + +static inline uint8_t +conn_rej_get_msg_rejected( + IN const mad_cm_rej_t* const p_rej ) +{ + return (p_rej->offset8 >> 6); +} + +static inline void +conn_rej_set_msg_rejected( + IN const uint8_t msg, + IN OUT mad_cm_rej_t* const p_rej ) +{ + p_rej->offset8 = (msg << 6); +} + +static inline uint8_t +conn_rej_get_ari_len( + IN const mad_cm_rej_t* const p_rej ) +{ + return (p_rej->offset9 >> 1); +} + +static inline ib_api_status_t +conn_rej_set_ari( + IN const uint8_t* const p_ari_info OPTIONAL, + IN const uint8_t info_len, + IN OUT mad_cm_rej_t* const p_rej ) +{ + if( p_ari_info && info_len > IB_ARI_SIZE ) + return IB_INVALID_PARAMETER; + + if( p_ari_info ) + { + cl_memcpy( p_rej->ari, p_ari_info, info_len ); + cl_memclr( p_rej->ari + info_len, IB_ARI_SIZE - info_len ); + } + else + { + cl_memclr( p_rej->ari, IB_ARI_SIZE ); + } + p_rej->offset9 = (info_len << 1); + return IB_SUCCESS; +} + + +static inline ib_api_status_t +conn_rej_set_pdata( + IN const uint8_t* const p_data OPTIONAL, + IN const uint8_t data_len, + IN OUT mad_cm_rej_t* const p_rej ) +{ + if( p_data ) + { + if( data_len > IB_REJ_PDATA_SIZE ) + return IB_INVALID_SETTING; + + cl_memcpy( p_rej->pdata, p_data, data_len ); + cl_memclr( p_rej->pdata + data_len, IB_REJ_PDATA_SIZE - data_len ); + } + else + { + cl_memclr( p_rej->pdata, IB_REJ_PDATA_SIZE ); + } + return IB_SUCCESS; +} + +static inline void +conn_rej_clr_rsvd_fields( + IN OUT mad_cm_rej_t* const p_rej ) +{ + p_rej->offset8 &= 0xC0; + p_rej->offset9 &= 0xFE; +} + + + +/* REP */ + +#include + +#define CM_REP_ATTR_ID CL_HTON16(0x0013) +typedef struct _mad_cm_rep +{ + ib_mad_t hdr; + + ib_net32_t local_comm_id; + ib_net32_t remote_comm_id; + + ib_net32_t local_qkey; + /* Local QPN:24, rsvd:8 */ + ib_field32_t offset12; + /* Local EECN:24, rsvd:8 */ + ib_field32_t offset16; + /* Starting PSN:24 rsvd:8 */ + ib_field32_t offset20; + + uint8_t resp_resources; + uint8_t initiator_depth; + /* Target ACK Delay:5, Failover Accepted:2, End-to-End Flow Control:1 */ + uint8_t offset26; + /* RNR Retry Count:3, rsvd:5 */ + uint8_t offset27; + + ib_net64_t local_ca_guid; + uint8_t pdata[IB_REP_PDATA_SIZE]; + +} PACK_SUFFIX mad_cm_rep_t; +C_ASSERT( sizeof(mad_cm_rep_t) == MAD_BLOCK_SIZE ); + +#include + +static inline ib_net32_t +conn_rep_get_lcl_qpn( + IN const mad_cm_rep_t* const p_rep ) +{ + CL_ASSERT( p_rep->hdr.class_ver == IB_MCLASS_CM_VER_2 ); + return __get_low24( p_rep->offset12 ); +} + +static inline void +conn_rep_set_lcl_qpn( + IN const ib_net32_t qpn, + IN OUT mad_cm_rep_t* const p_rep ) +{ + CL_ASSERT( p_rep->hdr.class_ver == IB_MCLASS_CM_VER_2 ); + __set_low24( &p_rep->offset12, qpn ); +} + +static inline ib_net32_t +conn_rep_get_starting_psn( + IN const mad_cm_rep_t* const p_rep ) +{ + CL_ASSERT( p_rep->hdr.class_ver == IB_MCLASS_CM_VER_2 ); + return __get_low24( p_rep->offset20 ); +} + +static inline void +conn_rep_set_starting_psn( + IN const ib_net32_t starting_psn, + IN OUT mad_cm_rep_t* const p_rep ) +{ + CL_ASSERT( p_rep->hdr.class_ver == IB_MCLASS_CM_VER_2 ); + __set_low24( &p_rep->offset20, starting_psn ); +} + +static inline uint8_t +conn_rep_get_target_ack_delay( + IN const mad_cm_rep_t* const p_rep ) +{ + CL_ASSERT( p_rep->hdr.class_ver == IB_MCLASS_CM_VER_2 ); + return (p_rep->offset26 >> 3); +} + +static inline void +conn_rep_set_target_ack_delay( + IN const uint8_t target_ack_delay, + IN OUT mad_cm_rep_t* const p_rep ) +{ + CL_ASSERT( !(target_ack_delay & 0xE0) ); + CL_ASSERT( p_rep->hdr.class_ver == IB_MCLASS_CM_VER_2 ); + p_rep->offset26 = + ((p_rep->offset26 & 0xE0) | (target_ack_delay << 3)); +} + +static inline uint8_t +conn_rep_get_failover( + IN const mad_cm_rep_t* const p_rep ) +{ + CL_ASSERT( p_rep->hdr.class_ver == IB_MCLASS_CM_VER_2 ); + return ( ( p_rep->offset26 >> 1 ) & 0x3 ); +} + +static inline void +conn_rep_set_failover( + IN const uint8_t failover, + IN OUT mad_cm_rep_t* const p_rep ) +{ + CL_ASSERT( p_rep->hdr.class_ver == IB_MCLASS_CM_VER_2 ); + p_rep->offset26 = + ( (p_rep->offset26 & 0xF9) | (( failover & 0x03) << 1) ); +} + +static inline boolean_t +conn_rep_get_e2e_flow_ctl( + IN const mad_cm_rep_t* const p_rep ) +{ + CL_ASSERT( p_rep->hdr.class_ver == IB_MCLASS_CM_VER_2 ); + return ( p_rep->offset26 & 0x01 ); +} + +static inline void +conn_rep_set_e2e_flow_ctl( + IN const boolean_t e2e_flow_ctl, + IN OUT mad_cm_rep_t* const p_rep ) +{ + CL_ASSERT( p_rep->hdr.class_ver == IB_MCLASS_CM_VER_2 ); + if( e2e_flow_ctl ) + p_rep->offset26 |= 0x01; + else + p_rep->offset26 &= 0xFE; +} + +static inline uint8_t +conn_rep_get_rnr_retry_cnt( + IN const mad_cm_rep_t* const p_rep ) +{ + CL_ASSERT( p_rep->hdr.class_ver == IB_MCLASS_CM_VER_2 ); + return (p_rep->offset27 >> 5); +} + +static inline void +conn_rep_set_rnr_retry_cnt( + IN const uint8_t rnr_retry_cnt, + IN OUT mad_cm_rep_t* const p_rep ) +{ + CL_ASSERT( p_rep->hdr.class_ver == IB_MCLASS_CM_VER_2 ); + p_rep->offset27 = (rnr_retry_cnt << 5); +} + +static inline ib_api_status_t +conn_rep_set_pdata( + IN const uint8_t* const p_data OPTIONAL, + IN const uint8_t data_len, + IN OUT mad_cm_rep_t* const p_rep ) +{ + CL_ASSERT( p_rep->hdr.class_ver == IB_MCLASS_CM_VER_2 ); + + if( p_data ) + { + if( data_len > IB_REP_PDATA_SIZE ) + return IB_INVALID_SETTING; + + cl_memcpy( p_rep->pdata, p_data, data_len ); + cl_memclr( p_rep->pdata + data_len, IB_REP_PDATA_SIZE - data_len ); + } + else + { + cl_memclr( p_rep->pdata, IB_REP_PDATA_SIZE ); + } + return IB_SUCCESS; +} + +static inline void +conn_rep_clr_rsvd_fields( + IN OUT mad_cm_rep_t* const p_rep ) +{ + p_rep->offset12.bytes[3] = 0; + p_rep->offset16.val = 0; + p_rep->offset20.bytes[3] = 0; + p_rep->offset27 &= 0xE0; +} + + +/* RTU */ + +#include + +#define CM_RTU_ATTR_ID CL_HTON16(0x0014) +/* RTU is the same for ver1 and ver2. */ +typedef struct _mad_cm_rtu +{ + ib_mad_t hdr; + + ib_net32_t local_comm_id; + ib_net32_t remote_comm_id; + uint8_t pdata[IB_RTU_PDATA_SIZE]; + +} PACK_SUFFIX mad_cm_rtu_t; +C_ASSERT( sizeof(mad_cm_rtu_t) == MAD_BLOCK_SIZE ); + +#include + +static inline ib_api_status_t +conn_rtu_set_pdata( + IN const uint8_t* const p_data OPTIONAL, + IN const uint8_t data_len, + IN OUT mad_cm_rtu_t* const p_rtu ) +{ + if( p_data ) + { + if( data_len > IB_RTU_PDATA_SIZE ) + return IB_INVALID_SETTING; + + cl_memcpy( p_rtu->pdata, p_data, data_len ); + cl_memclr( p_rtu->pdata + data_len, IB_RTU_PDATA_SIZE - data_len ); + } + else + { + cl_memclr( p_rtu->pdata, IB_RTU_PDATA_SIZE ); + } + return IB_SUCCESS; +} + +/* DREQ */ + +#include + +#define CM_DREQ_ATTR_ID CL_HTON16(0x0015) +/* DREQ is the same for ver1 and ver2. */ +typedef struct _mad_cm_dreq +{ + ib_mad_t hdr; + + ib_net32_t local_comm_id; + ib_net32_t remote_comm_id; + /* Remote QPN/EECN:24, rsvd:8 */ + ib_field32_t offset8; + uint8_t pdata[IB_DREQ_PDATA_SIZE]; + +} PACK_SUFFIX mad_cm_dreq_t; +C_ASSERT( sizeof(mad_cm_dreq_t) == MAD_BLOCK_SIZE ); + +#include + +static inline ib_net32_t +conn_dreq_get_remote_qpn( + IN const mad_cm_dreq_t* const p_dreq ) +{ + return __get_low24( p_dreq->offset8 ); +} + +static inline void +conn_dreq_set_remote_qpn( + IN const ib_net32_t qpn, + IN OUT mad_cm_dreq_t* const p_dreq ) +{ + __set_low24( &p_dreq->offset8, qpn ); +} + +static inline ib_api_status_t +conn_dreq_set_pdata( + IN const uint8_t* const p_data OPTIONAL, + IN const uint8_t data_len, + IN OUT mad_cm_dreq_t* const p_dreq ) +{ + if( p_data ) + { + if( data_len > IB_DREQ_PDATA_SIZE ) + return IB_INVALID_SETTING; + + cl_memcpy( p_dreq->pdata, p_data, data_len ); + cl_memclr( p_dreq->pdata + data_len, IB_DREQ_PDATA_SIZE - data_len ); + } + else + { + cl_memclr( p_dreq->pdata, IB_DREQ_PDATA_SIZE ); + } + return IB_SUCCESS; +} + +static inline void +conn_dreq_clr_rsvd_fields( + IN OUT mad_cm_dreq_t* const p_dreq ) +{ + p_dreq->offset8.bytes[3] = 0; +} + + + +/* DREP */ + +#include + +#define CM_DREP_ATTR_ID CL_HTON16(0x0016) +/* DREP is the same for ver1 and ver2. */ +typedef struct _mad_cm_drep +{ + ib_mad_t hdr; + + ib_net32_t local_comm_id; + ib_net32_t remote_comm_id; + uint8_t pdata[IB_DREP_PDATA_SIZE]; + +} PACK_SUFFIX mad_cm_drep_t; +C_ASSERT( sizeof(mad_cm_drep_t) == MAD_BLOCK_SIZE ); + +#include + +static inline ib_api_status_t +conn_drep_set_pdata( + IN const uint8_t* const p_data OPTIONAL, + IN const uint8_t data_len, + IN OUT mad_cm_drep_t* const p_drep ) +{ + if( p_data ) + { + if( data_len > IB_DREP_PDATA_SIZE ) + return IB_INVALID_SETTING; + + cl_memcpy( p_drep->pdata, p_data, data_len ); + cl_memclr( p_drep->pdata + data_len, IB_DREP_PDATA_SIZE - data_len ); + } + else + { + cl_memclr( p_drep->pdata, IB_DREP_PDATA_SIZE ); + } + return IB_SUCCESS; +} + + +/* LAP */ + +#include + +typedef struct _lap_path_info +{ + ib_net16_t local_lid; + ib_net16_t remote_lid; + ib_gid_t local_gid; + ib_gid_t remote_gid; + /* Flow Label:20, rsvd:4, Traffic Class:8 */ + ib_field32_t offset36; + uint8_t hop_limit; + + /* rsvd:2, Packet Rate:6 */ + uint8_t offset41; + /* SL:4, Subnet Local:1, rsvd:3 */ + uint8_t offset42; + /* Local ACK Timeout:5, rsvd:3 */ + uint8_t offset43; + +} PACK_SUFFIX lap_path_info_t; + +#define CM_LAP_ATTR_ID CL_HTON16(0x0019) +typedef struct _mad_cm_lap +{ + ib_mad_t hdr; + + ib_net32_t local_comm_id; + ib_net32_t remote_comm_id; + + ib_net32_t rsvd1; + /* Remote QPN/EECN:24, Remote CM Response Timeout:5, rsvd:3 */ + ib_field32_t offset12; + ib_net32_t rsvd2; + lap_path_info_t alternate_path; + uint8_t pdata[IB_LAP_PDATA_SIZE]; + +} PACK_SUFFIX mad_cm_lap_t; +C_ASSERT( sizeof(mad_cm_lap_t) == MAD_BLOCK_SIZE ); + +#include + +static inline ib_net32_t +conn_lap_get_remote_qpn( + IN const mad_cm_lap_t* const p_lap ) +{ + CL_ASSERT( p_lap->hdr.class_ver == IB_MCLASS_CM_VER_2 ); + return __get_low24( p_lap->offset12 ); +} + +static inline void +conn_lap_set_remote_qpn( + IN const ib_net32_t qpn, + IN OUT mad_cm_lap_t* const p_lap ) +{ + CL_ASSERT( p_lap->hdr.class_ver == IB_MCLASS_CM_VER_2 ); + __set_low24( &p_lap->offset12, qpn ); +} + +static inline uint8_t +conn_lap_get_resp_timeout( + IN const mad_cm_lap_t* const p_lap ) +{ + CL_ASSERT( p_lap->hdr.class_ver == IB_MCLASS_CM_VER_2 ); + return (p_lap->offset12.bytes[3] >> 3); +} + +static inline void +conn_lap_set_resp_timeout( + IN const uint8_t resp_timeout, + IN OUT mad_cm_lap_t* const p_lap ) +{ + CL_ASSERT( !(resp_timeout & 0xE0) ); + CL_ASSERT( p_lap->hdr.class_ver == IB_MCLASS_CM_VER_2 ); + p_lap->offset12.bytes[3] = (resp_timeout << 3); +} + +static inline ib_api_status_t +conn_lap_set_pdata( + IN const uint8_t* const p_data OPTIONAL, + IN const uint8_t data_len, + IN OUT mad_cm_lap_t* const p_lap ) +{ + CL_ASSERT( p_lap->hdr.class_ver == IB_MCLASS_CM_VER_2 ); + + cl_memclr( p_lap->pdata, IB_LAP_PDATA_SIZE ); + if( p_data ) + { + if( data_len > IB_LAP_PDATA_SIZE ) + return IB_INVALID_PARAMETER; + + cl_memcpy( p_lap->pdata, p_data, data_len ); + cl_memclr( p_lap->pdata + data_len, + IB_LAP_PDATA_SIZE - data_len ); + } + else + { + cl_memclr( p_lap->pdata, IB_LAP_PDATA_SIZE ); + } + return IB_SUCCESS; +} + +static inline void +conn_lap_clr_rsvd_fields( + IN OUT mad_cm_lap_t* const p_lap ) +{ + p_lap->rsvd1 = 0; + p_lap->offset12.val &= CL_HTON32( 0xFFFFFFF8 ); + p_lap->rsvd2 = 0; +} + +static inline net32_t +conn_lap_path_get_flow_lbl( + IN const lap_path_info_t* const p_lap_path ) +{ + return __get_low20( p_lap_path->offset36 ); +} + +static inline void +conn_lap_path_set_flow_lbl( + IN const ib_net32_t flow_lbl, + IN OUT lap_path_info_t* const p_lap_path ) +{ + __set_low24( &p_lap_path->offset36, (flow_lbl & CL_HTON32( 0x000FFFFF )) ); +} + +static inline uint8_t +conn_lap_path_get_tclass( + IN const lap_path_info_t* const p_lap_path ) +{ + return p_lap_path->offset36.bytes[3]; +} + +static inline void +conn_lap_path_set_tclass( + IN const uint8_t tclass, + IN OUT lap_path_info_t* const p_lap_path ) +{ + p_lap_path->offset36.bytes[3] = tclass; +} + +static inline uint8_t +conn_lap_path_get_pkt_rate( + IN const lap_path_info_t* const p_lap_path ) +{ + return ( p_lap_path->offset41 & 0x7F ); +} + +static inline void +conn_lap_path_set_pkt_rate( + IN const uint8_t pkt_rate, + IN OUT lap_path_info_t* const p_lap_path ) +{ + CL_ASSERT( !( pkt_rate & 0xC0 ) ); + + p_lap_path->offset41 = ( pkt_rate & 0x7F ); +} + +static inline const uint8_t +conn_lap_path_get_svc_lvl( + IN const lap_path_info_t* const p_lap_path ) +{ + return ( p_lap_path->offset42 >> 4 ); +} + +static inline void +conn_lap_path_set_svc_lvl( + IN const uint8_t sl, + IN OUT lap_path_info_t* const p_lap_path ) +{ + CL_ASSERT( !( sl & 0xF0 ) ); + + p_lap_path->offset42 = ( (p_lap_path->offset42 & 0x08) | (sl & 0xF0) ); +} + +static inline boolean_t +conn_lap_path_get_subn_lcl( + IN const lap_path_info_t* const p_lap_path ) +{ + return (p_lap_path->offset42 & 0x08) != 0; +} + +static inline void +conn_lap_path_set_subn_lcl( + IN const boolean_t subn_lcl, + IN OUT lap_path_info_t* const p_lap_path ) +{ + if( subn_lcl ) + p_lap_path->offset42 |= 0x08; + else + p_lap_path->offset42 &= 0xF0; +} + +static inline const uint8_t +conn_lap_path_get_lcl_ack_timeout( + IN const lap_path_info_t* const p_lap_path ) +{ + return ( p_lap_path->offset43 >> 3 ); +} + +static inline void +conn_lap_path_set_lcl_ack_timeout( + IN const uint8_t timeout, + IN OUT lap_path_info_t* const p_lap_path ) +{ + CL_ASSERT( !( timeout & 0xE0 ) ); + p_lap_path->offset43 = (timeout << 3); +} + +static inline void +conn_lap_path_clr_rsvd_fields( + IN OUT lap_path_info_t* const p_lap_path ) +{ + p_lap_path->offset36.val &= CL_HTON32( 0xFFFFF0FF ); + p_lap_path->offset41 &= 0x3F; + p_lap_path->offset42 &= 0xF8; + p_lap_path->offset43 &= 0xF8; +} + + + +/* APR */ +#include + +#define CM_APR_ATTR_ID CL_HTON16(0x001A) +typedef struct _mad_cm_apr +{ + ib_mad_t hdr; + + ib_net32_t local_comm_id; + ib_net32_t remote_comm_id; + + uint8_t info_len; + uint8_t status; + ib_net16_t rsvd; + + uint8_t info[IB_APR_INFO_SIZE]; + uint8_t pdata[IB_APR_PDATA_SIZE]; + +} PACK_SUFFIX mad_cm_apr_t; +C_ASSERT( sizeof(mad_cm_apr_t) == MAD_BLOCK_SIZE ); + +#include + +static inline ib_api_status_t +conn_apr_set_apr_info( + IN const uint8_t* const p_info OPTIONAL, + IN const uint8_t info_len, + IN OUT mad_cm_apr_t* const p_apr ) +{ + CL_ASSERT( p_apr->hdr.class_ver == IB_MCLASS_CM_VER_2 ); + if( p_info && ( info_len > IB_APR_INFO_SIZE ) ) + return IB_INVALID_PARAMETER; + + if( p_info ) + { + cl_memcpy( p_apr->info, p_info, info_len ); + cl_memclr( p_apr->info + info_len, + IB_APR_INFO_SIZE - info_len ); + p_apr->info_len = info_len; + } + else + { + cl_memclr( p_apr->info, IB_APR_INFO_SIZE ); + p_apr->info_len = 0; + } + return IB_SUCCESS; +} + +static inline ib_api_status_t +conn_apr_set_pdata( + IN const uint8_t* const p_data OPTIONAL, + IN const uint8_t data_len, + IN OUT mad_cm_apr_t* const p_apr ) +{ + CL_ASSERT( p_apr->hdr.class_ver == IB_MCLASS_CM_VER_2 ); + if( p_data ) + { + if( data_len > IB_APR_PDATA_SIZE ) + return IB_INVALID_PARAMETER; + + cl_memcpy( p_apr->pdata, p_data, data_len ); + cl_memclr( p_apr->pdata + data_len, + IB_APR_PDATA_SIZE - data_len ); + } + else + { + cl_memclr( p_apr->pdata, IB_APR_PDATA_SIZE ); + } + return IB_SUCCESS; +} + +static inline void +conn_apr_clr_rsvd_fields( + IN OUT mad_cm_apr_t* const p_apr ) +{ + p_apr->rsvd = 0; +} + +#endif /* __IB_AL_CM_CONN_H__ */ diff --git a/branches/WOF2-3/core/al/al_cm_qp.c b/branches/WOF2-3/core/al/al_cm_qp.c new file mode 100644 index 00000000..b2f362fe --- /dev/null +++ b/branches/WOF2-3/core/al/al_cm_qp.c @@ -0,0 +1,1959 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include +#include "al.h" +#include "al_qp.h" +#include "al_cm_cep.h" +#include "al_cm_conn.h" +#include "al_cm_sidr.h" +#include "al_mgr.h" +#include "al_debug.h" + + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "al_cm_qp.tmh" +#endif + +typedef struct _al_listen +{ + al_obj_t obj; + net32_t cid; + + ib_pfn_cm_req_cb_t pfn_cm_req_cb; + + /* valid for ud qp_type only */ + const void* sidr_context; + +} al_listen_t; + + +#ifdef CL_KERNEL + +/* + * Structure for queuing received MADs to the asynchronous processing + * manager. + */ +typedef struct _cep_async_mad +{ + cl_async_proc_item_t item; + ib_al_handle_t h_al; + net32_t cid; + +} cep_async_mad_t; + +#endif /* CL_KERNEL */ + + +/* + * Transition the QP to the error state to flush all oustanding work + * requests and sets the timewait time. This function may be called + * when destroying the QP in order to flush all work requests, so we + * cannot call through the main API, or the call will fail since the + * QP is no longer in the initialize state. + */ +static void +__cep_timewait_qp( + IN const ib_qp_handle_t h_qp ) +{ + uint64_t timewait = 0; + ib_qp_mod_t qp_mod; + ib_api_status_t status; + + AL_ENTER( AL_DBG_CM ); + + CL_ASSERT( h_qp ); + + /* + * The CM should have set the proper timewait time-out value. Reset + * the QP and let it enter the timewait state. + */ + if( al_cep_get_timewait( h_qp->obj.h_al, + ((al_conn_qp_t*)h_qp)->cid, &timewait ) == IB_SUCCESS ) + { + /* Special checks on the QP state for error handling - see above. */ + if( !h_qp || !AL_OBJ_IS_TYPE( h_qp, AL_OBJ_TYPE_H_QP ) || + ( (h_qp->obj.state != CL_INITIALIZED) && + (h_qp->obj.state != CL_DESTROYING) ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_QP_HANDLE\n") ); + return; + } + + cl_memclr( &qp_mod, sizeof(ib_qp_mod_t) ); + qp_mod.req_state = IB_QPS_ERROR; + + /* Modify to error state using function pointers - see above. */ + status = h_qp->pfn_modify_qp( h_qp, &qp_mod, NULL ); + if( status != IB_SUCCESS ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("pfn_modify_qp to IB_QPS_ERROR returned %s\n", + ib_get_err_str( status )) ); + return; + } + +#ifdef CL_KERNEL + /* Store the timestamp after which the QP exits timewait. */ + h_qp->timewait = cl_get_time_stamp() + timewait; +#endif /* CL_KERNEL */ + } + + AL_EXIT( AL_DBG_CM ); +} + + +static void +__format_req_path_rec( + IN const mad_cm_req_t* const p_req, + IN const req_path_info_t* const p_path, + OUT ib_path_rec_t* const p_path_rec ) +{ + AL_ENTER( AL_DBG_CM ); + + CL_ASSERT( p_req ); + CL_ASSERT( p_path ); + CL_ASSERT( p_path_rec ); + + /* + * Format a local path record. The local ack timeout specified in the + * REQ is twice the packet life plus the sender's CA ACK delay. When + * reporting the packet life, we divide the local ack timeout by 2 to + * approach the path's packet lifetime. Since local ack timeout is + * expressed as 4.096 * 2^x, subtracting 1 is equivalent to dividing the + * time in half. + */ + ib_path_rec_init_local( p_path_rec, + &p_path->local_gid, + &p_path->remote_gid, + p_path->local_lid, + p_path->remote_lid, + 1, p_req->pkey, + conn_req_path_get_svc_lvl( p_path ), 0, + IB_PATH_SELECTOR_EXACTLY, conn_req_get_mtu( p_req ), + IB_PATH_SELECTOR_EXACTLY, + conn_req_path_get_pkt_rate( p_path ), + IB_PATH_SELECTOR_EXACTLY, + (uint8_t)( conn_req_path_get_lcl_ack_timeout( p_path ) - 1 ), + 0 ); + + /* Add global routing info as necessary. */ + if( !conn_req_path_get_subn_lcl( p_path ) ) + { + ib_path_rec_set_hop_flow_raw( p_path_rec, p_path->hop_limit, + conn_req_path_get_flow_lbl( p_path ), FALSE ); + p_path_rec->tclass = p_path->traffic_class; + } + + AL_EXIT( AL_DBG_CM ); +} + + +static void +__format_req_rec( + IN const mad_cm_req_t* const p_req, + OUT ib_cm_req_rec_t *p_req_rec ) +{ + AL_ENTER( AL_DBG_CM ); + + CL_ASSERT( p_req ); + CL_ASSERT( p_req_rec ); + + cl_memclr( p_req_rec, sizeof(ib_cm_req_rec_t) ); + + /* format version specific data */ + p_req_rec->p_req_pdata = p_req->pdata; + + p_req_rec->qp_type = conn_req_get_qp_type( p_req ); + + p_req_rec->resp_res = conn_req_get_resp_res( p_req ); + p_req_rec->flow_ctrl = conn_req_get_flow_ctrl( p_req ); + p_req_rec->rnr_retry_cnt = conn_req_get_rnr_retry_cnt( p_req ); + + __format_req_path_rec( p_req, &p_req->primary_path, + &p_req_rec->primary_path ); + __format_req_path_rec( p_req, &p_req->alternate_path, + &p_req_rec->alt_path ); + + /* These values are filled in later based on listen or peer connections + p_req_rec->context = ; + p_req_rec->h_cm_req = ; + p_req_rec->h_cm_listen = ; + */ + + AL_EXIT( AL_DBG_CM ); +} + + +/****************************************************************************** +* Functions that handle incoming REQs that matched to an outstanding listen. +* +*/ + + +static void +__listen_req( + IN al_listen_t* const p_listen, + IN const net32_t new_cid, + IN const mad_cm_req_t* const p_req ) +{ + ib_cm_req_rec_t req_rec; + + AL_ENTER( AL_DBG_CM ); + + CL_ASSERT( p_listen ); + CL_ASSERT( new_cid != AL_INVALID_CID ); + CL_ASSERT( p_req ); + + /* Format the callback record. */ + __format_req_rec( p_req, &req_rec ); + + /* update listen based rec */ + req_rec.context = p_listen->obj.context; + + req_rec.h_cm_req.cid = new_cid; + req_rec.h_cm_req.h_al = p_listen->obj.h_al; + req_rec.h_cm_req.h_qp = NULL; + + req_rec.h_cm_listen = p_listen; + + /* Invoke the user's callback. */ + p_listen->pfn_cm_req_cb( &req_rec ); + + AL_EXIT( AL_DBG_CM ); +} + + +static void +__proc_listen( + IN al_listen_t* const p_listen, + IN net32_t new_cid, + IN const ib_mad_t* const p_mad ) +{ + AL_ENTER( AL_DBG_CM ); + + /* Context is a listen - MAD must be a REQ or SIDR REQ */ + switch( p_mad->attr_id ) + { + case CM_REQ_ATTR_ID: + __listen_req( + p_listen, new_cid, (mad_cm_req_t*)p_mad ); + break; + + case CM_SIDR_REQ_ATTR_ID: + /* TODO - implement SIDR. */ + default: + CL_ASSERT( p_mad->attr_id == CM_REQ_ATTR_ID || + p_mad->attr_id == CM_SIDR_REQ_ATTR_ID ); + /* Destroy the new CEP as it won't ever be reported to the user. */ + al_destroy_cep( p_listen->obj.h_al, &new_cid, FALSE ); + } + + AL_EXIT( AL_DBG_CM ); +} + + +/****************************************************************************** +* Functions that handle send timeouts: +* +*/ + +/* + * callback to process a connection establishment timeout due to reply not + * being received. The connection object has a reference + * taken when the timer is set or when the send is sent. + */ +static void +__proc_conn_timeout( + IN const ib_qp_handle_t h_qp ) +{ + ib_cm_rej_rec_t rej_rec; + + AL_ENTER( AL_DBG_CM ); + + CL_ASSERT( h_qp ); + + /* + * Format the reject record before aborting the connection since + * we need the QP context. + */ + cl_memclr( &rej_rec, sizeof(ib_cm_rej_rec_t) ); + rej_rec.h_qp = h_qp; + rej_rec.qp_context = h_qp->obj.context; + rej_rec.rej_status = IB_REJ_TIMEOUT; + + /* Unbind the QP from the CEP. */ + __cep_timewait_qp( h_qp ); + + al_destroy_cep( h_qp->obj.h_al, &((al_conn_qp_t*)h_qp)->cid, TRUE ); + + /* Invoke the callback. */ + ((al_conn_qp_t*)h_qp)->pfn_cm_rej_cb( &rej_rec ); + + AL_EXIT( AL_DBG_CM ); +} + + +/* + * callback to process a LAP timeout due to APR not being received. + */ +static void +__proc_lap_timeout( + IN const ib_qp_handle_t h_qp ) +{ + ib_cm_apr_rec_t apr_rec; + + AL_ENTER( AL_DBG_CM ); + + CL_ASSERT( h_qp ); + + /* Report the timeout. */ + cl_memclr( &apr_rec, sizeof(ib_cm_apr_rec_t) ); + apr_rec.h_qp = h_qp; + apr_rec.qp_context = h_qp->obj.context; + apr_rec.cm_status = IB_TIMEOUT; + apr_rec.apr_status = IB_AP_REJECT; + + /* Notify the user that the LAP failed. */ + ((al_conn_qp_t*)h_qp)->pfn_cm_apr_cb( &apr_rec ); + + AL_EXIT( AL_DBG_CM ); +} + + +/* + * Callback to process a disconnection timeout due to not receiving the DREP + * within allowable time. + */ +static void +__proc_dconn_timeout( + IN const ib_qp_handle_t h_qp ) +{ + ib_cm_drep_rec_t drep_rec; + + AL_ENTER( AL_DBG_CM ); + + /* No response. We're done. Deliver a DREP callback. */ + cl_memclr( &drep_rec, sizeof(ib_cm_drep_rec_t) ); + drep_rec.h_qp = h_qp; + drep_rec.qp_context = h_qp->obj.context; + drep_rec.cm_status = IB_TIMEOUT; + + __cep_timewait_qp( h_qp ); + + al_destroy_cep( h_qp->obj.h_al, &((al_conn_qp_t*)h_qp)->cid, TRUE ); + + /* Call the user back. */ + ((al_conn_qp_t*)h_qp)->pfn_cm_drep_cb( &drep_rec ); + + AL_EXIT( AL_DBG_CM ); +} + + +static void +__proc_failed_send( + IN ib_qp_handle_t h_qp, + IN const ib_mad_t* const p_mad ) +{ + AL_ENTER( AL_DBG_CM ); + + /* Failure indicates a send. */ + switch( p_mad->attr_id ) + { + case CM_REQ_ATTR_ID: + case CM_REP_ATTR_ID: + __proc_conn_timeout( h_qp ); + break; + case CM_LAP_ATTR_ID: + __proc_lap_timeout( h_qp ); + break; + case CM_DREQ_ATTR_ID: + __proc_dconn_timeout( h_qp ); + break; + default: + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("Invalid CM send MAD attribute ID %d.\n", p_mad->attr_id) ); + break; + } + + AL_EXIT( AL_DBG_CM ); +} + + +/****************************************************************************** +* Functions that handle received MADs on a connection (not listen) +* +*/ + + +void +__proc_peer_req( + IN const ib_cm_handle_t* const p_cm, + IN const mad_cm_req_t* const p_req ) +{ + ib_cm_req_rec_t req_rec; + + AL_ENTER( AL_DBG_CM ); + + CL_ASSERT( p_cm ); + CL_ASSERT( p_cm->h_qp ); + /* Must be peer-to-peer. */ + CL_ASSERT( ((al_conn_qp_t*)p_cm->h_qp)->pfn_cm_req_cb ); + CL_ASSERT( p_req ); + + /* Format the callback record. */ + __format_req_rec( p_req, &req_rec ); + + /* update peer based rec handles and context values */ + req_rec.context = p_cm->h_qp->obj.context; + req_rec.h_cm_req = *p_cm; + req_rec.h_cm_listen = NULL; + + /* Invoke the user's callback. User must call ib_cm_rep or ib_cm_rej. */ + ((al_conn_qp_t*)p_cm->h_qp)->pfn_cm_req_cb( &req_rec ); + + AL_EXIT( AL_DBG_CM ); +} + + +void +__proc_mra( + IN const ib_cm_handle_t* const p_cm, + IN const mad_cm_mra_t* const p_mra ) +{ + ib_cm_mra_rec_t mra_rec; + + AL_ENTER( AL_DBG_CM ); + + CL_ASSERT( p_cm->h_qp ); + CL_ASSERT( ((al_conn_qp_t*)p_cm->h_qp)->pfn_cm_mra_cb ); + + /* Format the MRA callback record. */ + cl_memclr( &mra_rec, sizeof(ib_cm_mra_rec_t) ); + + mra_rec.h_qp = p_cm->h_qp; + mra_rec.qp_context = p_cm->h_qp->obj.context; + mra_rec.p_mra_pdata = p_mra->pdata; + + /* + * Call the user back. Note that users will get a callback only + * for the first MRA received in response to a REQ, REP, or LAP. + */ + ((al_conn_qp_t*)p_cm->h_qp)->pfn_cm_mra_cb( &mra_rec ); + + AL_EXIT( AL_DBG_CM ); +} + + +void +__proc_rej( + IN const ib_cm_handle_t* const p_cm, + IN const mad_cm_rej_t* const p_rej ) +{ + ib_cm_rej_rec_t rej_rec; + + AL_ENTER( AL_DBG_CM ); + + if( p_cm->h_qp ) + { + /* Format the REJ callback record. */ + cl_memclr( &rej_rec, sizeof(ib_cm_rej_rec_t) ); + + rej_rec.h_qp = p_cm->h_qp; + rej_rec.qp_context = p_cm->h_qp->obj.context; + + rej_rec.p_rej_pdata = p_rej->pdata; + rej_rec.p_ari = p_rej->ari; + rej_rec.ari_length = conn_rej_get_ari_len( p_rej ); + rej_rec.rej_status = p_rej->reason; + + /* + * Unbind the QP from the connection object. This allows the QP to + * be immediately reused in another connection request. + */ + __cep_timewait_qp( p_cm->h_qp ); + + al_destroy_cep( p_cm->h_al, &((al_conn_qp_t*)p_cm->h_qp)->cid, TRUE ); + + /* Call the user back. */ + ((al_conn_qp_t*)p_cm->h_qp)->pfn_cm_rej_cb( &rej_rec ); + } + + AL_EXIT( AL_DBG_CM ); +} + + +static void +__proc_rep( + IN ib_cm_handle_t* const p_cm, + IN mad_cm_rep_t* const p_rep ) +{ + ib_cm_rep_rec_t rep_rec; + + AL_ENTER( AL_DBG_CM ); + + cl_memclr( &rep_rec, sizeof(ib_cm_rep_rec_t) ); + + /* fill the rec callback data */ + rep_rec.p_rep_pdata = p_rep->pdata; + rep_rec.qp_type = p_cm->h_qp->type; + + rep_rec.h_cm_rep = *p_cm; + rep_rec.qp_context = p_cm->h_qp->obj.context; + rep_rec.resp_res = p_rep->resp_resources; + rep_rec.flow_ctrl = conn_rep_get_e2e_flow_ctl( p_rep ); + rep_rec.apr_status = conn_rep_get_failover( p_rep ); + + /* Notify the user of the reply. */ + ((al_conn_qp_t*)p_cm->h_qp)->pfn_cm_rep_cb( &rep_rec ); + + AL_EXIT( AL_DBG_CM ); +} + + +static void +__proc_rtu( + IN ib_cm_handle_t* const p_cm, + IN mad_cm_rtu_t* const p_rtu ) +{ + ib_cm_rtu_rec_t rtu_rec; + + AL_ENTER( AL_DBG_CM ); + + rtu_rec.p_rtu_pdata = p_rtu->pdata; + rtu_rec.h_qp = p_cm->h_qp; + rtu_rec.qp_context = p_cm->h_qp->obj.context; + + ((al_conn_qp_t*)p_cm->h_qp)->pfn_cm_rtu_cb( &rtu_rec ); + + AL_EXIT( AL_DBG_CM ); +} + + +static void +__proc_dreq( + IN ib_cm_handle_t* const p_cm, + IN mad_cm_dreq_t* const p_dreq ) +{ + ib_cm_dreq_rec_t dreq_rec; + + AL_ENTER( AL_DBG_CM ); + + cl_memclr( &dreq_rec, sizeof(ib_cm_dreq_rec_t) ); + + dreq_rec.h_cm_dreq = *p_cm; + dreq_rec.p_dreq_pdata = p_dreq->pdata; + + dreq_rec.qp_context = p_cm->h_qp->obj.context; + + ((al_conn_qp_t*)p_cm->h_qp)->pfn_cm_dreq_cb( &dreq_rec ); + + AL_EXIT( AL_DBG_CM ); +} + + +void +__proc_drep( + IN ib_cm_handle_t* const p_cm, + IN mad_cm_drep_t* const p_drep ) +{ + ib_cm_drep_rec_t drep_rec; + + AL_ENTER( AL_DBG_CM ); + + cl_memclr( &drep_rec, sizeof(ib_cm_drep_rec_t) ); + + /* Copy qp context before the connection is released */ + drep_rec.cm_status = IB_SUCCESS; + drep_rec.p_drep_pdata = p_drep->pdata; + drep_rec.h_qp = p_cm->h_qp; + drep_rec.qp_context = p_cm->h_qp->obj.context; + + __cep_timewait_qp( p_cm->h_qp ); + + al_destroy_cep( p_cm->h_al, &((al_conn_qp_t*)p_cm->h_qp)->cid, TRUE ); + + ((al_conn_qp_t*)p_cm->h_qp)->pfn_cm_drep_cb( &drep_rec ); + + AL_EXIT( AL_DBG_CM ); +} + + +void +__proc_lap( + IN ib_cm_handle_t* const p_cm, + IN const mad_cm_lap_t* const p_lap ) +{ + ib_cm_lap_rec_t lap_rec; + const lap_path_info_t* const p_path = &p_lap->alternate_path; + + AL_ENTER( AL_DBG_CM ); + + CL_ASSERT( p_cm ); + CL_ASSERT( p_cm->h_qp ); + CL_ASSERT( p_lap ); + + cl_memclr( &lap_rec, sizeof(ib_cm_lap_rec_t) ); + lap_rec.qp_context = p_cm->h_qp->obj.context; + lap_rec.h_cm_lap = *p_cm; + + /* + * Format the path record. The local ack timeout specified in the + * LAP is twice the packet life plus the sender's CA ACK delay. When + * reporting the packet life, we divide the local ack timeout by 2 to + * approach the path's packet lifetime. Since local ack timeout is + * expressed as 4.096 * 2^x, subtracting 1 is equivalent to dividing the + * time in half. + */ + ib_path_rec_init_local( &lap_rec.alt_path, + &p_lap->alternate_path.local_gid, + &p_lap->alternate_path.remote_gid, + p_lap->alternate_path.local_lid, + p_lap->alternate_path.remote_lid, + 1, IB_DEFAULT_PKEY, + conn_lap_path_get_svc_lvl( &p_lap->alternate_path ), 0, + IB_PATH_SELECTOR_EXACTLY, + IB_MTU_LEN_2048, + IB_PATH_SELECTOR_EXACTLY, + conn_lap_path_get_pkt_rate( p_path ), + IB_PATH_SELECTOR_EXACTLY, + (uint8_t)( conn_lap_path_get_lcl_ack_timeout( p_path ) - 1 ), + 0 ); + + /* Add global routing info as necessary. */ + if( !conn_lap_path_get_subn_lcl( &p_lap->alternate_path ) ) + { + ib_path_rec_set_hop_flow_raw( &lap_rec.alt_path, + p_lap->alternate_path.hop_limit, + conn_lap_path_get_flow_lbl( &p_lap->alternate_path ), + FALSE ); + lap_rec.alt_path.tclass = + conn_lap_path_get_tclass( &p_lap->alternate_path ); + } + + ((al_conn_qp_t*)p_cm->h_qp)->pfn_cm_lap_cb( &lap_rec ); + + AL_EXIT( AL_DBG_CM ); +} + + +static ib_api_status_t +__cep_lap_qp( + IN ib_cm_handle_t* const p_cm ) +{ + ib_api_status_t status; + ib_qp_mod_t qp_mod; + + AL_ENTER( AL_DBG_CM ); + + status = al_cep_get_rts_attr( p_cm->h_al, p_cm->cid, &qp_mod ); + if( status != IB_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("al_cep_get_rts_attr returned %s.\n", ib_get_err_str(status)) ); + goto done; + } + + status = ib_modify_qp( p_cm->h_qp, &qp_mod ); + if( status != IB_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("ib_modify_qp for LAP returned %s.\n", ib_get_err_str(status)) ); + } + +done: + AL_EXIT( AL_DBG_CM ); + return status; +} + + +static void +__proc_apr( + IN ib_cm_handle_t* const p_cm, + IN mad_cm_apr_t* const p_apr ) +{ + ib_cm_apr_rec_t apr_rec; + + AL_ENTER( AL_DBG_CM ); + + apr_rec.h_qp = p_cm->h_qp; + apr_rec.qp_context = p_cm->h_qp->obj.context; + apr_rec.p_info = (const uint8_t*)&p_apr->info; + apr_rec.info_length = p_apr->info_len; + apr_rec.p_apr_pdata = p_apr->pdata; + apr_rec.apr_status = p_apr->status; + + if( apr_rec.apr_status == IB_AP_SUCCESS ) + { + apr_rec.cm_status = __cep_lap_qp( p_cm ); + } + else + { + apr_rec.cm_status = IB_ERROR; + } + + ((al_conn_qp_t*)p_cm->h_qp)->pfn_cm_apr_cb( &apr_rec ); + + AL_EXIT( AL_DBG_CM ); +} + + +static void +__proc_conn( + IN ib_cm_handle_t* const p_cm, + IN ib_mad_t* const p_mad ) +{ + AL_ENTER( AL_DBG_CM ); + + /* Success indicates a receive. */ + switch( p_mad->attr_id ) + { + case CM_REQ_ATTR_ID: + CL_ASSERT( ((al_conn_qp_t*)p_cm->h_qp)->cid == (int32_t)p_cm->cid || + ((al_conn_qp_t*)p_cm->h_qp)->cid == AL_RESERVED_CID || + ((al_conn_qp_t*)p_cm->h_qp)->cid == AL_INVALID_CID ); + __proc_peer_req( p_cm, (mad_cm_req_t*)p_mad ); + break; + + case CM_MRA_ATTR_ID: + CL_ASSERT( ((al_conn_qp_t*)p_cm->h_qp)->cid == (int32_t)p_cm->cid || + ((al_conn_qp_t*)p_cm->h_qp)->cid == AL_RESERVED_CID || + ((al_conn_qp_t*)p_cm->h_qp)->cid == AL_INVALID_CID ); + __proc_mra( p_cm, (mad_cm_mra_t*)p_mad ); + break; + + case CM_REJ_ATTR_ID: + __proc_rej( p_cm, (mad_cm_rej_t*)p_mad ); + break; + + case CM_REP_ATTR_ID: + CL_ASSERT( ((al_conn_qp_t*)p_cm->h_qp)->cid == (int32_t)p_cm->cid || + ((al_conn_qp_t*)p_cm->h_qp)->cid == AL_RESERVED_CID || + ((al_conn_qp_t*)p_cm->h_qp)->cid == AL_INVALID_CID ); + __proc_rep( p_cm, (mad_cm_rep_t*)p_mad ); + break; + + case CM_RTU_ATTR_ID: + CL_ASSERT( ((al_conn_qp_t*)p_cm->h_qp)->cid == (int32_t)p_cm->cid || + ((al_conn_qp_t*)p_cm->h_qp)->cid == AL_RESERVED_CID || + ((al_conn_qp_t*)p_cm->h_qp)->cid == AL_INVALID_CID ); + __proc_rtu( p_cm, (mad_cm_rtu_t*)p_mad ); + break; + + case CM_DREQ_ATTR_ID: + CL_ASSERT( ((al_conn_qp_t*)p_cm->h_qp)->cid == (int32_t)p_cm->cid || + ((al_conn_qp_t*)p_cm->h_qp)->cid == AL_INVALID_CID ); + __proc_dreq( p_cm, (mad_cm_dreq_t*)p_mad ); + break; + + case CM_DREP_ATTR_ID: + CL_ASSERT( ((al_conn_qp_t*)p_cm->h_qp)->cid == (int32_t)p_cm->cid || + ((al_conn_qp_t*)p_cm->h_qp)->cid == AL_RESERVED_CID || + ((al_conn_qp_t*)p_cm->h_qp)->cid == AL_INVALID_CID ); + __proc_drep( p_cm, (mad_cm_drep_t*)p_mad ); + break; + + case CM_LAP_ATTR_ID: + CL_ASSERT( ((al_conn_qp_t*)p_cm->h_qp)->cid == (int32_t)p_cm->cid || + ((al_conn_qp_t*)p_cm->h_qp)->cid == AL_RESERVED_CID || + ((al_conn_qp_t*)p_cm->h_qp)->cid == AL_INVALID_CID ); + __proc_lap( p_cm, (mad_cm_lap_t*)p_mad ); + break; + + case CM_APR_ATTR_ID: + CL_ASSERT( ((al_conn_qp_t*)p_cm->h_qp)->cid == (int32_t)p_cm->cid || + ((al_conn_qp_t*)p_cm->h_qp)->cid == AL_INVALID_CID ); + __proc_apr( p_cm, (mad_cm_apr_t*)p_mad ); + break; + + //case CM_SIDR_REQ_ATTR_ID: + // p_async_mad->item.pfn_callback = __process_cm_sidr_req; + // break; + + //case CM_SIDR_REP_ATTR_ID: + // p_async_mad->item.pfn_callback = __process_cm_sidr_rep; + // break; + + default: + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("Invalid CM recv MAD attribute ID %d.\n", p_mad->attr_id) ); + } + + AL_EXIT( AL_DBG_CM ); +} + +/****************************************************************************** +* CEP callback handler. +* +*/ + +#ifdef CL_KERNEL +static void +__process_cep_cb( +#else +static void +__cm_handler( +#endif + IN const ib_al_handle_t h_al, + IN const net32_t cid ) +{ + ib_api_status_t status; + void* context; + net32_t new_cid; + ib_mad_element_t *p_mad; + ib_cm_handle_t h_cm; + + AL_ENTER( AL_DBG_CM ); + + for( status = al_cep_poll( h_al, cid, &context, &new_cid, &p_mad ); + status == IB_SUCCESS; + status = al_cep_poll( h_al, cid, &context, &new_cid, &p_mad ) ) + { + /* Something to do - WOOT!!! */ + if( new_cid != AL_INVALID_CID ) + { + __proc_listen( (al_listen_t*)context, + new_cid, ib_get_mad_buf( p_mad ) ); + } + else if( p_mad->status != IB_SUCCESS ) + { + /* Context is a QP handle, and a sent MAD timed out. */ + __proc_failed_send( + (ib_qp_handle_t)context, ib_get_mad_buf( p_mad ) ); + } + else + { + h_cm.h_al = h_al; + h_cm.cid = cid; + h_cm.h_qp = (ib_qp_handle_t)context; + __proc_conn( &h_cm, ib_get_mad_buf( p_mad ) ); + } + ib_put_mad( p_mad ); + } +} + + +#ifdef CL_KERNEL + +static void +__process_cep_async( + IN cl_async_proc_item_t *p_item ) +{ + cep_async_mad_t *p_async_mad; + + AL_ENTER( AL_DBG_CM ); + + p_async_mad = PARENT_STRUCT( p_item, cep_async_mad_t, item ); + + __process_cep_cb( p_async_mad->h_al, p_async_mad->cid ); + + cl_free( p_async_mad ); + + AL_EXIT( AL_DBG_CM ); +} + + +/* + * The handler is invoked at DISPATCH_LEVEL in kernel mode. We need to switch + * to a passive level thread context to perform QP modify and invoke user + * callbacks. + */ +static void +__cm_handler( + IN const ib_al_handle_t h_al, + IN const net32_t cid ) +{ + cep_async_mad_t *p_async_mad; + + AL_ENTER( AL_DBG_CM ); + + p_async_mad = (cep_async_mad_t*)cl_zalloc( sizeof(cep_async_mad_t) ); + if( !p_async_mad ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("failed to cl_zalloc cm_async_mad_t (%d bytes)\n", + sizeof(cep_async_mad_t)) ); + return; + } + + p_async_mad->h_al = h_al; + p_async_mad->cid = cid; + p_async_mad->item.pfn_callback = __process_cep_async; + + /* Queue the MAD for asynchronous processing. */ + cl_async_proc_queue( gp_async_proc_mgr, &p_async_mad->item ); + + AL_EXIT( AL_DBG_CM ); +} +#endif /* CL_KERNEL */ + + +/* + * Transition the QP to the INIT state, if it is not already in the + * INIT state. + */ +ib_api_status_t +__cep_init_qp( + IN const ib_qp_handle_t h_qp, + IN ib_qp_mod_t* const p_init ) +{ + ib_qp_mod_t qp_mod; + ib_api_status_t status; + + /* + * Move to the init state to allow posting of receive buffers. + * Chech the current state of the QP. The user may have already + * transitioned it and posted some receives to the QP, so we + * should not reset the QP if it is already in the INIT state. + */ + if( h_qp->state != IB_QPS_INIT ) + { + /* Reset the QP. */ + cl_memclr( &qp_mod, sizeof(ib_qp_mod_t) ); + qp_mod.req_state = IB_QPS_RESET; + + status = ib_modify_qp( h_qp, &qp_mod ); + if( status != IB_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("ib_modify_qp to IB_QPS_RESET returned %s\n", + ib_get_err_str(status) ) ); + } + + /* Initialize the QP. */ + status = ib_modify_qp( h_qp, p_init ); + if( status != IB_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("ib_modify_qp returned %s.\n", ib_get_err_str(status) ) ); + return status; + } + } + + return IB_SUCCESS; +} + +static ib_api_status_t +__cep_pre_req( + IN const ib_cm_req_t* const p_cm_req ) +{ + ib_api_status_t status; + ib_qp_mod_t qp_mod; + + AL_ENTER( AL_DBG_CM ); + + status = al_cep_pre_req( qp_get_al( p_cm_req->h_qp ), + ((al_conn_qp_t*)p_cm_req->h_qp)->cid, p_cm_req, &qp_mod ); + if( status != IB_SUCCESS ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("al_cep_pre_req returned %s.\n", ib_get_err_str( status )) ); + return status; + } + + /* Transition QP through state machine */ + /* + * Warning! Using all access rights. We need to modify + * the ib_cm_req_t to include this. + */ + qp_mod.state.init.access_ctrl |= + IB_AC_RDMA_READ | IB_AC_RDMA_WRITE | IB_AC_ATOMIC; + status = __cep_init_qp( p_cm_req->h_qp, &qp_mod ); + if( status != IB_SUCCESS ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("__cep_init_qp returned %s\n", ib_get_err_str(status)) ); + return status; + } + + AL_EXIT( AL_DBG_CM ); + return IB_SUCCESS; +} + + +static ib_api_status_t +__cep_conn_req( + IN const ib_al_handle_t h_al, + IN const ib_cm_req_t* const p_cm_req ) +{ + ib_api_status_t status; + //cl_status_t cl_status; + //cl_event_t sync_event; + //cl_event_t *p_sync_event = NULL; + al_conn_qp_t *p_qp; + + AL_ENTER( AL_DBG_CM ); + + /* event based mechanism */ + if( p_cm_req->flags & IB_FLAGS_SYNC ) + { + AL_EXIT( AL_DBG_CM ); + return IB_UNSUPPORTED; + //cl_event_construct( &sync_event ); + //cl_status = cl_event_init( &sync_event, FALSE ); + //if( cl_status != CL_SUCCESS ) + //{ + // __deref_conn( p_conn ); + // return ib_convert_cl_status( cl_status ); + //} + //p_conn->p_sync_event = p_sync_event = &sync_event; + } + + p_qp = (al_conn_qp_t*)p_cm_req->h_qp; + + /* Get a CEP and bind it to the QP. */ + status = al_create_cep( h_al, __cm_handler, p_qp, deref_al_obj, &p_qp->cid ); + if( status != IB_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("al_create_cep returned %s.\n", ib_get_err_str( status )) ); + goto done; + } + + /* Take a reference on behalf of the CEP. */ + ref_al_obj( &p_qp->qp.obj ); + + status = __cep_pre_req( p_cm_req ); + if( status != IB_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("__cep_pre_req returned %s.\n", ib_get_err_str( status )) ); + goto err; + } + + /* Store callback pointers. */ + p_qp->pfn_cm_req_cb = p_cm_req->pfn_cm_req_cb; + p_qp->pfn_cm_rep_cb = p_cm_req->pfn_cm_rep_cb; + p_qp->pfn_cm_mra_cb = p_cm_req->pfn_cm_mra_cb; + p_qp->pfn_cm_rej_cb = p_cm_req->pfn_cm_rej_cb; + + /* Send the REQ. */ + status = al_cep_send_req( h_al, p_qp->cid ); + if( status != IB_SUCCESS ) + { + //if( p_sync_event ) + // cl_event_destroy( p_sync_event ); + + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("al_cep_send_req returned %s.\n", ib_get_err_str(status)) ); +err: + al_destroy_cep( h_al, &p_qp->cid, TRUE ); + } + + /* wait on event if synchronous operation */ + //if( p_sync_event ) + //{ + // AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_CM, + // ("event blocked on REQ...\n") ); + // cl_event_wait_on( p_sync_event, EVENT_NO_TIMEOUT, FALSE ); + + // cl_event_destroy( p_sync_event ); + //} + +done: + AL_EXIT( AL_DBG_CM ); + return status; +} + + +ib_api_status_t +ib_cm_req( + IN const ib_cm_req_t* const p_cm_req ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_CM ); + + if( !p_cm_req ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + /* Only supported qp types allowed */ + switch( p_cm_req->qp_type ) + { + default: + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("Invalid qp_type.\n") ); + return IB_INVALID_SETTING; + + case IB_QPT_RELIABLE_CONN: + case IB_QPT_UNRELIABLE_CONN: + if( AL_OBJ_INVALID_HANDLE( p_cm_req->h_qp, AL_OBJ_TYPE_H_QP ) || + (p_cm_req->h_qp->type != p_cm_req->qp_type) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_QP_HANDLE\n") ); + return IB_INVALID_QP_HANDLE; + } + + status = __cep_conn_req( qp_get_al( p_cm_req->h_qp ), p_cm_req ); + break; + + case IB_QPT_UNRELIABLE_DGRM: + if( AL_OBJ_INVALID_HANDLE( p_cm_req->h_al, AL_OBJ_TYPE_H_AL ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_AL_HANDLE\n") ); + return IB_INVALID_AL_HANDLE; + } + status = IB_UNSUPPORTED; +// status = cm_sidr_req( p_cm_req->h_al, p_cm_req ); + break; + } + + AL_EXIT( AL_DBG_CM ); + return status; +} + + +/* + * Note: we pass in the QP handle separately because it comes form different + * sources. It comes from the ib_cm_rep_t structure in the ib_cm_rep path, and + * from the ib_cm_handle_t structure in the ib_cm_rtu path. + */ +static ib_api_status_t +__cep_rts_qp( + IN const ib_cm_handle_t h_cm, + IN const ib_qp_handle_t h_qp, + IN const ib_access_t access_ctrl, + IN const uint32_t sq_depth, + IN const uint32_t rq_depth ) +{ + ib_api_status_t status; + ib_qp_mod_t qp_mod; + + AL_ENTER( AL_DBG_CM ); + + /* Set the QP to RTR. */ + status = al_cep_get_rtr_attr( h_cm.h_al, h_cm.cid, &qp_mod ); + if( status != IB_SUCCESS ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("al_cep_get_rtr_attr returned %s\n", ib_get_err_str( status )) ); + return status; + } + + if( access_ctrl ) + { + qp_mod.state.rtr.access_ctrl = access_ctrl; + qp_mod.state.rtr.opts |= IB_MOD_QP_ACCESS_CTRL; + } + + if( sq_depth ) + { + qp_mod.state.rtr.sq_depth = sq_depth; + qp_mod.state.rtr.opts |= IB_MOD_QP_SQ_DEPTH; + } + + if( rq_depth ) + { + qp_mod.state.rtr.rq_depth = rq_depth; + qp_mod.state.rtr.opts |= IB_MOD_QP_RQ_DEPTH; + } + + status = ib_modify_qp( h_qp, &qp_mod ); + if( status != IB_SUCCESS ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("ib_modify_qp to RTR returned %s.\n", ib_get_err_str(status) ) ); + return status; + } + + /* Set the QP to RTS. */ + status = al_cep_get_rts_attr( h_cm.h_al, h_cm.cid, &qp_mod ); + if( status != IB_SUCCESS ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("al_cep_get_rts_attr returned %s\n", ib_get_err_str( status )) ); + return status; + } + + status = ib_modify_qp( h_qp, &qp_mod ); + if( status != IB_SUCCESS ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("ib_modify_qp to RTS returned %s.\n", ib_get_err_str(status) ) ); + return status; + } + + AL_EXIT( AL_DBG_CM ); + return IB_SUCCESS; +} + + +static ib_api_status_t +__cep_pre_rep( + IN const ib_cm_handle_t h_cm, + IN ib_qp_mod_t* const p_qp_mod, + IN const ib_cm_rep_t* const p_cm_rep ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_CM ); + + /* Transition the QP to the INIT state. */ + p_qp_mod->state.init.access_ctrl = p_cm_rep->access_ctrl; + status = __cep_init_qp( p_cm_rep->h_qp, p_qp_mod ); + if( status != IB_SUCCESS ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("cm_init_qp returned %s.\n", ib_get_err_str(status)) ); + return status; + } + + /* Prepost receives. */ + if( p_cm_rep->p_recv_wr ) + { + status = ib_post_recv( p_cm_rep->h_qp, p_cm_rep->p_recv_wr, + (ib_recv_wr_t**)p_cm_rep->pp_recv_failure ); + if( status != IB_SUCCESS ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("ib_post_recv returned %s.\n", ib_get_err_str(status)) ); + return status; + } + } + + /* Transition the QP to the RTR and RTS states. */ + status = __cep_rts_qp( h_cm, p_cm_rep->h_qp, + p_cm_rep->access_ctrl, p_cm_rep->sq_depth, p_cm_rep->rq_depth ); + if( status != IB_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("__cep_rts_qp returned %s.\n", ib_get_err_str(status)) ); + } + + AL_EXIT( AL_DBG_CM ); + return status; +} + + +static ib_api_status_t +__cep_conn_rep( + IN ib_cm_handle_t h_cm, + IN const ib_cm_rep_t* const p_cm_rep ) +{ + ib_api_status_t status; + ib_qp_mod_t qp_mod; + + AL_ENTER( AL_DBG_CM ); + + status = al_cep_pre_rep( + h_cm.h_al, h_cm.cid, p_cm_rep->h_qp, deref_al_obj, p_cm_rep, + &((al_conn_qp_t*)p_cm_rep->h_qp)->cid, &qp_mod ); + switch( status ) + { + case IB_SUCCESS: + break; + + case IB_RESOURCE_BUSY: + /* We don't destroy the CEP to allow the user to retry accepting. */ + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("QP already connected.\n") ); + return IB_INVALID_QP_HANDLE; + + default: + al_cep_rej( h_cm.h_al, h_cm.cid, IB_REJ_INSUF_RESOURCES, NULL, 0, NULL, 0 ); + al_destroy_cep( h_cm.h_al, &h_cm.cid, FALSE ); + + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("al_cep_pre_rep returned %s.\n", ib_get_err_str( status )) ); + return status; + } + + /* Take a reference on behalf of the CEP. */ + ref_al_obj( &p_cm_rep->h_qp->obj ); + + /* Store the CM callbacks. */ + ((al_conn_qp_t*)p_cm_rep->h_qp)->pfn_cm_rej_cb = p_cm_rep->pfn_cm_rej_cb; + ((al_conn_qp_t*)p_cm_rep->h_qp)->pfn_cm_mra_cb = p_cm_rep->pfn_cm_mra_cb; + ((al_conn_qp_t*)p_cm_rep->h_qp)->pfn_cm_rtu_cb = p_cm_rep->pfn_cm_rtu_cb; + ((al_conn_qp_t*)p_cm_rep->h_qp)->pfn_cm_lap_cb = p_cm_rep->pfn_cm_lap_cb; + ((al_conn_qp_t*)p_cm_rep->h_qp)->pfn_cm_dreq_cb = p_cm_rep->pfn_cm_dreq_cb; + + /* Transition QP through state machine */ + status = __cep_pre_rep( h_cm, &qp_mod, p_cm_rep ); + if( status != IB_SUCCESS ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("__cep_pre_rep returned %s\n", ib_get_err_str(status)) ); + goto err; + } + + status = al_cep_send_rep( h_cm.h_al, h_cm.cid ); + if( status != IB_SUCCESS ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("al_cep_send_rep returned %s\n", ib_get_err_str(status)) ); +err: + + /* Reject and abort the connection. */ + al_cep_rej( h_cm.h_al, h_cm.cid, IB_REJ_INSUF_QP, NULL, 0, NULL, 0 ); + al_destroy_cep( + h_cm.h_al, &((al_conn_qp_t*)p_cm_rep->h_qp)->cid, TRUE ); + } + + AL_EXIT( AL_DBG_CM ); + return status; +} + + +ib_api_status_t +ib_cm_rep( + IN const ib_cm_handle_t h_cm_req, + IN const ib_cm_rep_t* const p_cm_rep ) +{ + ib_api_status_t status; + net32_t cid; + + AL_ENTER( AL_DBG_CM ); + + if( !p_cm_rep ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + /* Only supported qp types allowed */ + status = IB_SUCCESS; + switch( p_cm_rep->qp_type ) + { + default: + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("Invalid qp_type.\n") ); + status = IB_INVALID_SETTING; + break; + + case IB_QPT_RELIABLE_CONN: + case IB_QPT_UNRELIABLE_CONN: + if( AL_OBJ_INVALID_HANDLE( p_cm_rep->h_qp, AL_OBJ_TYPE_H_QP ) || + (p_cm_rep->h_qp->type != p_cm_rep->qp_type) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_QP_HANDLE\n") ); + status = IB_INVALID_QP_HANDLE; + } + else if( p_cm_rep->h_qp->obj.h_al != h_cm_req.h_al ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_QP_HANDLE\n") ); + status = IB_INVALID_QP_HANDLE; + } + break; + + case IB_QPT_UNRELIABLE_DGRM: + if( ( p_cm_rep->status == IB_SIDR_SUCCESS ) && + (AL_OBJ_INVALID_HANDLE( p_cm_rep->h_qp, AL_OBJ_TYPE_H_QP ) || + (p_cm_rep->h_qp->type != p_cm_rep->qp_type) ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_QP_HANDLE\n") ); + status = IB_INVALID_QP_HANDLE; + } + break; + } + + if( status != IB_SUCCESS ) + { + cid = h_cm_req.cid; + al_cep_rej( + h_cm_req.h_al, h_cm_req.cid, IB_REJ_INSUF_QP, NULL, 0, NULL, 0 ); + al_destroy_cep( h_cm_req.h_al, &cid, FALSE ); + + AL_EXIT( AL_DBG_CM ); + return status; + } + + if( p_cm_rep->qp_type == IB_QPT_UNRELIABLE_DGRM ) + status = IB_UNSUPPORTED;//status = cm_sidr_rep( p_conn, p_cm_rep ); + else + status = __cep_conn_rep( h_cm_req, p_cm_rep ); + + AL_EXIT( AL_DBG_CM ); + return status; +} + + +ib_api_status_t +ib_cm_rtu( + IN const ib_cm_handle_t h_cm_rep, + IN const ib_cm_rtu_t* const p_cm_rtu ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_CM ); + + if( !p_cm_rtu ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + ///* + // * Call invalid if event is still processed. + // * User may have called rtu in rep callback. + // */ + //if( p_conn->p_sync_event ) + //{ + // AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + // ("Connection in invalid state. Sync call in progress.\n" ) ); + + // cm_res_release( p_conn ); + // __deref_conn( p_conn ); + // return IB_INVALID_STATE; + //} + ((al_conn_qp_t*)h_cm_rep.h_qp)->pfn_cm_apr_cb = p_cm_rtu->pfn_cm_apr_cb; + ((al_conn_qp_t*)h_cm_rep.h_qp)->pfn_cm_dreq_cb = p_cm_rtu->pfn_cm_dreq_cb; + + /* Transition QP through state machine */ + status = __cep_rts_qp( h_cm_rep, h_cm_rep.h_qp, + p_cm_rtu->access_ctrl, p_cm_rtu->sq_depth, p_cm_rtu->rq_depth ); + if( status != IB_SUCCESS ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("__cep_rts_qp returned %s.\n", ib_get_err_str( status )) ); + goto err; + } + + status = al_cep_rtu( h_cm_rep.h_al, h_cm_rep.cid, + p_cm_rtu->p_rtu_pdata, p_cm_rtu->rtu_length ); + if( status != IB_SUCCESS && status != IB_INVALID_STATE ) + { +err: + /* Reject and abort the connection. */ + al_cep_rej( + h_cm_rep.h_al, h_cm_rep.cid, IB_REJ_INSUF_QP, NULL, 0, NULL, 0 ); + + __cep_timewait_qp( h_cm_rep.h_qp ); + + al_destroy_cep( + h_cm_rep.h_al, &((al_conn_qp_t*)h_cm_rep.h_qp)->cid, TRUE ); + + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("al_cep_rtu returned %s.\n", ib_get_err_str( status )) ); + return status; + } + + AL_EXIT( AL_DBG_CM ); + return status; +} + + +ib_api_status_t +ib_cm_mra( + IN const ib_cm_handle_t h_cm, + IN const ib_cm_mra_t* const p_cm_mra ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_CM ); + + if( !p_cm_mra ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + status = al_cep_mra( h_cm.h_al, h_cm.cid, p_cm_mra ); + if( status != IB_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("al_cep_mra returned %s\n", ib_get_err_str( status )) ); + } + + AL_EXIT( AL_DBG_CM ); + return status; +} + + +ib_api_status_t +ib_cm_rej( + IN const ib_cm_handle_t h_cm, + IN const ib_cm_rej_t* const p_cm_rej ) +{ + ib_api_status_t status; + net32_t cid; + + AL_ENTER( AL_DBG_CM ); + + if( !p_cm_rej ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + status = al_cep_rej( h_cm.h_al, h_cm.cid, p_cm_rej->rej_status, + p_cm_rej->p_ari->data, p_cm_rej->ari_length, + p_cm_rej->p_rej_pdata, p_cm_rej->rej_length ); + + if( h_cm.h_qp ) + { + __cep_timewait_qp( h_cm.h_qp ); + + al_destroy_cep( + h_cm.h_al, &((al_conn_qp_t*)h_cm.h_qp)->cid, TRUE ); + } + else + { + cid = h_cm.cid; + al_destroy_cep( h_cm.h_al, &cid, FALSE ); + } + + AL_EXIT( AL_DBG_CM ); + return status; +} + + +ib_api_status_t +ib_cm_dreq( + IN const ib_cm_dreq_t* const p_cm_dreq ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_CM ); + + if( !p_cm_dreq ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + /* Only supported qp types allowed */ + switch( p_cm_dreq->qp_type ) + { + default: + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("Invalid qp_type.\n") ); + return IB_INVALID_SETTING; + + case IB_QPT_RELIABLE_CONN: + case IB_QPT_UNRELIABLE_CONN: + if( AL_OBJ_INVALID_HANDLE( p_cm_dreq->h_qp, AL_OBJ_TYPE_H_QP ) || + (p_cm_dreq->h_qp->type != p_cm_dreq->qp_type) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_QP_HANDLE\n") ); + return IB_INVALID_QP_HANDLE; + } + break; + } + + /* Store the callback pointers. */ + ((al_conn_qp_t*)p_cm_dreq->h_qp)->pfn_cm_drep_cb = + p_cm_dreq->pfn_cm_drep_cb; + + status = al_cep_dreq( p_cm_dreq->h_qp->obj.h_al, + ((al_conn_qp_t*)p_cm_dreq->h_qp)->cid, + p_cm_dreq->p_dreq_pdata, p_cm_dreq->dreq_length ); + switch( status ) + { + case IB_INVALID_STATE: + case IB_INVALID_HANDLE: + case IB_INVALID_PARAMETER: + case IB_INVALID_SETTING: + /* Bad call - don't touch the QP. */ + break; + + case IB_SUCCESS: + /* Wait for the DREP or timeout. */ + break; + + default: + /* + * If we failed to send the DREQ, just release the connection. It's + * unreliable anyway. The local port may be down. Note that we could + * not send the DREQ, but we still could have received one. The DREQ + * will have a reference on the connection until the user calls + * ib_cm_drep. + */ + __cep_timewait_qp( p_cm_dreq->h_qp ); + + al_destroy_cep( p_cm_dreq->h_qp->obj.h_al, + &((al_conn_qp_t*)p_cm_dreq->h_qp)->cid, TRUE ); + status = IB_SUCCESS; + } + + AL_EXIT( AL_DBG_CM ); + return status; +} + + + +ib_api_status_t +ib_cm_drep( + IN const ib_cm_handle_t h_cm_dreq, + IN const ib_cm_drep_t* const p_cm_drep ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_CM ); + + if( !p_cm_drep ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + status = al_cep_drep( h_cm_dreq.h_al, h_cm_dreq.cid, + p_cm_drep->p_drep_pdata, p_cm_drep->drep_length ); + switch( status ) + { + case IB_INVALID_SETTING: + case IB_INVALID_HANDLE: + case IB_INVALID_PARAMETER: + case IB_INVALID_STATE: + /* Bad call - don't touch the QP. */ + break; + + default: + /* + * Some other out-of-resource error - continue as if we succeeded in + * sending the DREP. + */ + status = IB_SUCCESS; + /* Fall through */ + case IB_SUCCESS: + __cep_timewait_qp( h_cm_dreq.h_qp ); + + al_destroy_cep( h_cm_dreq.h_al, + &((al_conn_qp_t*)h_cm_dreq.h_qp)->cid, TRUE ); + } + + AL_EXIT( AL_DBG_CM ); + return status; +} + + +ib_api_status_t +ib_cm_lap( + IN const ib_cm_lap_t* const p_cm_lap ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_CM ); + + if( !p_cm_lap ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + /* Only supported qp types allowed */ + switch( p_cm_lap->qp_type ) + { + default: + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("Invalid qp_type.\n") ); + return IB_INVALID_SETTING; + + case IB_QPT_RELIABLE_CONN: + case IB_QPT_UNRELIABLE_CONN: + if( AL_OBJ_INVALID_HANDLE( p_cm_lap->h_qp, AL_OBJ_TYPE_H_QP ) || + (p_cm_lap->h_qp->type != p_cm_lap->qp_type) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_QP_HANDLE\n") ); + return IB_INVALID_QP_HANDLE; + } + break; + } + + status = al_cep_lap( p_cm_lap->h_qp->obj.h_al, + ((al_conn_qp_t*)p_cm_lap->h_qp)->cid, p_cm_lap ); + if( status != IB_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("al_cep_lap returned %s.\n", ib_get_err_str( status )) ); + } + + AL_EXIT( AL_DBG_CM ); + return status; +} + + +ib_api_status_t +ib_cm_apr( + IN const ib_cm_handle_t h_cm_lap, + IN const ib_cm_apr_t* const p_cm_apr ) +{ + ib_api_status_t status; + ib_qp_mod_t qp_mod; + + AL_ENTER( AL_DBG_CM ); + + if( !p_cm_apr ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + /* Only supported qp types allowed */ + switch( p_cm_apr->qp_type ) + { + default: + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("Invalid qp_type.\n") ); + return IB_INVALID_SETTING; + + case IB_QPT_RELIABLE_CONN: + case IB_QPT_UNRELIABLE_CONN: + if( AL_OBJ_INVALID_HANDLE( p_cm_apr->h_qp, AL_OBJ_TYPE_H_QP ) || + (p_cm_apr->h_qp->type != p_cm_apr->qp_type) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_QP_HANDLE\n") ); + return IB_INVALID_QP_HANDLE; + } + break; + } + + status = al_cep_pre_apr( h_cm_lap.h_al, h_cm_lap.cid, p_cm_apr, &qp_mod ); + if( status != IB_SUCCESS ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("al_cep_pre_apr returned %s.\n", ib_get_err_str( status )) ); + return status; + } + + /* Load alt path into QP */ + status = ib_modify_qp( h_cm_lap.h_qp, &qp_mod ); + if( status != IB_SUCCESS ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("ib_modify_qp for LAP returned %s.\n", + ib_get_err_str( status )) ); + return status; + } + + status = al_cep_send_apr( h_cm_lap.h_al, h_cm_lap.cid ); + if( status != IB_SUCCESS ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("al_cep_send_apr returned %s.\n", + ib_get_err_str( status )) ); + } + + AL_EXIT( AL_DBG_CM ); + return status; +} + + +ib_api_status_t +ib_force_apm( + IN const ib_qp_handle_t h_qp ) +{ + ib_api_status_t status; + al_conn_qp_t *p_conn_qp; + ib_qp_mod_t qp_mod; + + AL_ENTER( AL_DBG_CM ); + + if( AL_OBJ_INVALID_HANDLE( h_qp, AL_OBJ_TYPE_H_QP ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_QP_HANDLE\n") ); + return IB_INVALID_QP_HANDLE; + } + + p_conn_qp = PARENT_STRUCT( h_qp, al_conn_qp_t, qp ); + cl_memclr( &qp_mod, sizeof(ib_qp_mod_t) ); + qp_mod.req_state = IB_QPS_RTS; + qp_mod.state.rts.apm_state = IB_APM_MIGRATED; + qp_mod.state.rts.opts = IB_MOD_QP_APM_STATE; + + /* Set the QP to RTS. */ + status = ib_modify_qp( h_qp, &qp_mod ); + + AL_EXIT( AL_DBG_CM ); + return status; +} + + +static void +__destroying_listen( + IN al_obj_t* p_obj ) +{ + al_listen_t *p_listen; + + p_listen = PARENT_STRUCT( p_obj, al_listen_t, obj ); + + /* Destroy the listen's CEP. */ + al_destroy_cep( p_obj->h_al, &p_listen->cid, TRUE ); +} + + + +static void +__free_listen( + IN al_obj_t* p_obj ) +{ + destroy_al_obj( p_obj ); + cl_free( PARENT_STRUCT( p_obj, al_listen_t, obj ) ); +} + + +static ib_api_status_t +__cep_listen( + IN const ib_al_handle_t h_al, + IN const ib_cm_listen_t* const p_cm_listen, + IN const void* const listen_context, + OUT ib_listen_handle_t* const ph_cm_listen ) +{ + ib_api_status_t status; + al_listen_t *p_listen; + ib_cep_listen_t cep_listen; + + AL_ENTER( AL_DBG_CM ); + + /* Allocate the listen object. */ + p_listen = (al_listen_t*)cl_zalloc( sizeof(al_listen_t) ); + if( !p_listen ) + { + AL_EXIT( AL_DBG_CM ); + return IB_INSUFFICIENT_MEMORY; + } + + /* Copy the listen request information for matching incoming requests. */ + p_listen->pfn_cm_req_cb = p_cm_listen->pfn_cm_req_cb; + + /* valid for ud qp_type only */ + p_listen->sidr_context = p_cm_listen->sidr_context; + + construct_al_obj( &p_listen->obj, AL_OBJ_TYPE_H_LISTEN ); + status = init_al_obj( &p_listen->obj, listen_context, TRUE, + __destroying_listen, NULL, __free_listen ); + if( status != IB_SUCCESS ) + { + __free_listen( &p_listen->obj ); + AL_EXIT( AL_DBG_CM ); + return status; + } + + /* Add the listen to the AL instance's object list. */ + status = attach_al_obj( &h_al->obj, &p_listen->obj ); + if( status != IB_SUCCESS ) + { + p_listen->obj.pfn_destroy( &p_listen->obj, NULL ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("attach_al_obj returned %s.\n", ib_get_err_str(status)) ); + return status; + } + + /* Create a CEP to listen on. */ + p_listen->cid = AL_INVALID_CID; + status = al_create_cep( h_al, __cm_handler, p_listen, deref_al_obj, &p_listen->cid ); + if( status != IB_SUCCESS ) + { + p_listen->obj.pfn_destroy( &p_listen->obj, NULL ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("al_create_cep returned %s.\n", ib_get_err_str(status)) ); + return status; + } + + /* Take a reference on behalf of the CEP. */ + ref_al_obj( &p_listen->obj ); + + cep_listen.cmp_len = p_cm_listen->compare_length; + cep_listen.cmp_offset = p_cm_listen->compare_offset; + cep_listen.p_cmp_buf = p_cm_listen->p_compare_buffer; + cep_listen.port_guid = p_cm_listen->port_guid; + cep_listen.svc_id = p_cm_listen->svc_id; + + status = al_cep_listen( h_al, p_listen->cid, &cep_listen ); + if( status != IB_SUCCESS ) + { + p_listen->obj.pfn_destroy( &p_listen->obj, NULL ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("al_cep_listen returned %s.\n", ib_get_err_str(status)) ); + return status; + } + + *ph_cm_listen = p_listen; + + /* Release the reference taken in init_al_obj. */ + deref_al_obj( &p_listen->obj ); + + AL_EXIT( AL_DBG_CM ); + return IB_SUCCESS; +} + + +ib_api_status_t +ib_cm_listen( + IN const ib_al_handle_t h_al, + IN const ib_cm_listen_t* const p_cm_listen, + IN const void* const listen_context, + OUT ib_listen_handle_t* const ph_cm_listen ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_CM ); + + if( AL_OBJ_INVALID_HANDLE( h_al, AL_OBJ_TYPE_H_AL ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_AL_HANDLE\n") ); + return IB_INVALID_AL_HANDLE; + } + if( !p_cm_listen || !ph_cm_listen ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + status = __cep_listen(h_al, p_cm_listen, listen_context, ph_cm_listen ); + + AL_EXIT( AL_DBG_CM ); + return status; +} + + +ib_api_status_t +ib_cm_cancel( + IN const ib_listen_handle_t h_cm_listen, + IN const ib_pfn_destroy_cb_t pfn_destroy_cb OPTIONAL ) +{ + AL_ENTER( AL_DBG_CM ); + + if( AL_OBJ_INVALID_HANDLE( h_cm_listen, AL_OBJ_TYPE_H_LISTEN ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_HANDLE\n") ); + return IB_INVALID_HANDLE; + } + + ref_al_obj( &h_cm_listen->obj ); + h_cm_listen->obj.pfn_destroy( &h_cm_listen->obj, pfn_destroy_cb ); + + AL_EXIT( AL_DBG_CM ); + return IB_SUCCESS; +} + + +ib_api_status_t +ib_cm_handoff( + IN const ib_cm_handle_t h_cm_req, + IN const ib_net64_t svc_id ) +{ + UNUSED_PARAM( h_cm_req ); + UNUSED_PARAM( svc_id ); + return IB_UNSUPPORTED; +} diff --git a/branches/WOF2-3/core/al/al_cm_sidr.h b/branches/WOF2-3/core/al/al_cm_sidr.h new file mode 100644 index 00000000..2d37bbbc --- /dev/null +++ b/branches/WOF2-3/core/al/al_cm_sidr.h @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#if !defined(__IB_AL_CM_SIDR_H__) +#define __IB_AL_CM_SIDR_H__ + + +#include +#include +#include "al_common.h" + +/* + * CM SIDR MAD definitions. + * Helper functions to handle version specific SIDR MADs + */ + + +/* SIDR REQ */ +#include + +#define CM_SIDR_REQ_ATTR_ID CL_HTON16(0x0017) +typedef struct _mad_cm_sidr_req +{ + ib_mad_t hdr; + + ib_net32_t req_id; + + ib_net16_t pkey; + ib_net16_t rsvd; + + ib_net64_t sid; + + uint8_t pdata[IB_SIDR_REQ_PDATA_SIZE]; + +} PACK_SUFFIX mad_cm_sidr_req_t; + +#include + +static inline ib_api_status_t +sidr_req_set_pdata( + IN const uint8_t* p_data OPTIONAL, + IN const uint8_t rep_length, + IN OUT mad_cm_sidr_req_t* const p_sidr_req ) +{ + if( p_data && rep_length > IB_SIDR_REQ_PDATA_SIZE ) + return IB_INVALID_SETTING; + + if( p_data ) + { + cl_memcpy( p_sidr_req->pdata, p_data, rep_length ); + cl_memclr( p_sidr_req->pdata + rep_length, + IB_SIDR_REQ_PDATA_SIZE - rep_length ); + } + else + { + cl_memclr( p_sidr_req->pdata, IB_SIDR_REQ_PDATA_SIZE ); + } + return IB_SUCCESS; +} + +static inline void +sidr_req_clr_rsvd_fields( + IN OUT mad_cm_sidr_req_t* const p_sidr_req ) +{ + p_sidr_req->rsvd = 0; +} + + + +/* SIDR REP */ +#include + +#define CM_SIDR_REP_ATTR_ID CL_HTON16(0x0018) +typedef struct _mad_cm_sidr_rep +{ + ib_mad_t hdr; + + ib_net32_t req_id; + + uint8_t status; + uint8_t info_len; + ib_net16_t rsvd; + + /* QPN 24; rsvd 8 */ + ib_field32_t offset8; + + ib_net64_t sid; + ib_net32_t qkey; + + ib_class_port_info_t class_info; + + uint8_t pdata[IB_SIDR_REP_PDATA_SIZE]; + +} PACK_SUFFIX mad_cm_sidr_rep_t; + +#include + +static inline ib_net32_t +sidr_rep_get_qpn( + IN const mad_cm_sidr_rep_t* const p_sidr_rep ) +{ + return __get_low24( p_sidr_rep->offset8 ); +} + +static inline void +sidr_rep_set_qpn( + IN const ib_net32_t qpn, + IN OUT mad_cm_sidr_rep_t* const p_sidr_rep ) +{ + CL_ASSERT( !( cl_ntoh32( qpn ) & 0xFF000000 ) ); + __set_low24( &p_sidr_rep->offset8, qpn ); +} + +static inline ib_api_status_t +sidr_rep_set_pdata( + IN const uint8_t* p_data OPTIONAL, + IN const uint8_t rep_length, + IN OUT mad_cm_sidr_rep_t* const p_sidr_rep ) +{ + if( p_data && rep_length > IB_SIDR_REP_PDATA_SIZE ) + return IB_INVALID_SETTING; + + if( p_data ) + { + cl_memcpy( p_sidr_rep->pdata, p_data, rep_length ); + cl_memclr( p_sidr_rep->pdata + rep_length, + IB_SIDR_REP_PDATA_SIZE - rep_length ); + } + else + { + cl_memclr( p_sidr_rep->pdata, IB_SIDR_REP_PDATA_SIZE ); + } + return IB_SUCCESS; +} + +static inline void +sidr_rep_clr_rsvd_fields( + IN OUT mad_cm_sidr_rep_t* const p_sidr_rep ) +{ + p_sidr_rep->rsvd = 0; + p_sidr_rep->offset8.bytes[3] = 0; +} + +#endif /* __IB_AL_CM_SIDR_H__ */ diff --git a/branches/WOF2-3/core/al/al_common.c b/branches/WOF2-3/core/al/al_common.c new file mode 100644 index 00000000..d9dbd50c --- /dev/null +++ b/branches/WOF2-3/core/al/al_common.c @@ -0,0 +1,693 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include "al.h" +#include "al_ci_ca.h" +#include "al_common.h" +#include "al_debug.h" +#include "al_ca.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "al_common.tmh" +#endif + +#include "al_mgr.h" +#include +#include "ib_common.h" +#include "bus_ev_log.h" + + + +#if AL_OBJ_PRIVATE_ASYNC_PROC +cl_async_proc_t *gp_async_obj_mgr = NULL; +#endif + + +boolean_t +destroy_obj( + IN struct _al_obj *p_obj, + IN const ib_pfn_destroy_cb_t pfn_destroy_cb ); + + +void +async_destroy_cb( + IN cl_async_proc_item_t *p_item ); + + +void +async_destroy_obj( + IN struct _al_obj *p_obj, + IN const ib_pfn_destroy_cb_t pfn_destroy_cb ); + + +void +sync_destroy_obj( + IN struct _al_obj *p_obj, + IN const ib_pfn_destroy_cb_t pfn_destroy_cb ); + + + +const char* ib_obj_type_str[] = +{ + "AL_OBJ_TYPE_UNKNOWN", + "AL_OBJ_TYPE_H_AL", + "AL_OBJ_TYPE_H_QP", + "AL_OBJ_TYPE_H_AV", + "AL_OBJ_TYPE_H_MR", + "AL_OBJ_TYPE_H_MW", + "AL_OBJ_TYPE_H_PD", + "AL_OBJ_TYPE_H_CA", + "AL_OBJ_TYPE_H_CQ", + "AL_OBJ_TYPE_H_CONN", + "AL_OBJ_TYPE_H_LISTEN", + "AL_OBJ_TYPE_H_IOC", + "AL_OBJ_TYPE_H_SVC_ENTRY", + "AL_OBJ_TYPE_H_PNP", + "AL_OBJ_TYPE_H_SA_REQ", + "AL_OBJ_TYPE_H_MCAST", + "AL_OBJ_TYPE_H_ATTACH", + "AL_OBJ_TYPE_H_MAD", + "AL_OBJ_TYPE_H_MAD_POOL", + "AL_OBJ_TYPE_H_POOL_KEY", + "AL_OBJ_TYPE_H_MAD_SVC", + "AL_OBJ_TYPE_CI_CA", + "AL_OBJ_TYPE_CM", + "AL_OBJ_TYPE_SMI", + "AL_OBJ_TYPE_DM", + "AL_OBJ_TYPE_IOU", + "AL_OBJ_TYPE_LOADER", + "AL_OBJ_TYPE_MAD_POOL", + "AL_OBJ_TYPE_MAD_DISP", + "AL_OBJ_TYPE_AL_MGR", + "AL_OBJ_TYPE_PNP_MGR", + "AL_OBJ_TYPE_IOC_PNP_MGR", + "AL_OBJ_TYPE_IOC_PNP_SVC", + "AL_OBJ_TYPE_QUERY_SVC", + "AL_OBJ_TYPE_MCAST_SVC", + "AL_OBJ_TYPE_SA_REQ_SVC", + "AL_OBJ_TYPE_RES_MGR", + "AL_OBJ_TYPE_H_CA_ATTR", + "AL_OBJ_TYPE_H_PNP_EVENT", + "AL_OBJ_TYPE_H_SA_REG", + "AL_OBJ_TYPE_H_FMR", + "AL_OBJ_TYPE_H_SRQ", + "AL_OBJ_TYPE_H_FMR_POOL", + "AL_OBJ_TYPE_NDI" +}; + + +/* + * Used to force synchronous destruction of AL objects. + */ +void +__sync_destroy_cb( + IN void *context ) +{ + UNUSED_PARAM( context ); +} + + +void +construct_al_obj( + IN al_obj_t * const p_obj, + IN const al_obj_type_t obj_type ) +{ + CL_ASSERT( p_obj ); + cl_memclr( p_obj, sizeof( al_obj_t ) ); + + cl_spinlock_construct( &p_obj->lock ); + p_obj->state = CL_UNINITIALIZED; + p_obj->type = obj_type; + p_obj->timeout_ms = AL_DEFAULT_TIMEOUT_MS; + p_obj->ref_cnt = 1; + cl_event_construct( &p_obj->event ); + + /* Insert the object into the global tracking list. */ + if( p_obj != &gp_al_mgr->obj ) + { + cl_spinlock_acquire( &gp_al_mgr->lock ); + cl_qlist_insert_tail( &gp_al_mgr->al_obj_list, &p_obj->list_item ); + cl_spinlock_release( &gp_al_mgr->lock ); + ref_al_obj( &gp_al_mgr->obj ); + } +} + + + +ib_api_status_t +init_al_obj( + IN al_obj_t * const p_obj, + IN const void* const context, + IN boolean_t async_destroy, + IN const al_pfn_destroying_t pfn_destroying, + IN const al_pfn_cleanup_t pfn_cleanup, + IN const al_pfn_free_t pfn_free ) +{ + cl_status_t cl_status; + + AL_ENTER( AL_DBG_AL_OBJ ); + CL_ASSERT( p_obj && pfn_free ); + CL_ASSERT( p_obj->state == CL_UNINITIALIZED ); + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_AL_OBJ, + ("%p\n", p_obj ) ); + + /* Initialize the object. */ + p_obj->async_item.pfn_callback = async_destroy_cb; + p_obj->pfn_free = pfn_free; + + p_obj->context = context; + + if( async_destroy ) + p_obj->pfn_destroy = async_destroy_obj; + else + p_obj->pfn_destroy = sync_destroy_obj; + + p_obj->pfn_destroying = pfn_destroying; + + p_obj->pfn_cleanup = pfn_cleanup; + p_obj->user_destroy_cb = NULL; + + cl_qlist_init( &p_obj->obj_list ); + cl_status = cl_spinlock_init( &p_obj->lock ); + if( cl_status != CL_SUCCESS ) + { + return ib_convert_cl_status( cl_status ); + } + + cl_status = cl_event_init( &p_obj->event, FALSE ); + if( cl_status != CL_SUCCESS ) + { + return ib_convert_cl_status( cl_status ); + } + + p_obj->state = CL_INITIALIZED; + + /* + * Hold an extra reference on the object until creation is complete. + * This prevents a client's destruction of the object during asynchronous + * event callback processing from deallocating the object before the + * creation is complete. + */ + ref_al_obj( p_obj ); + + AL_EXIT( AL_DBG_AL_OBJ ); + return IB_SUCCESS; +} + + +void +reset_al_obj( + IN al_obj_t * const p_obj ) +{ + CL_ASSERT( p_obj && (p_obj->ref_cnt == 0) ); + CL_ASSERT( p_obj->state == CL_DESTROYING ); + + p_obj->ref_cnt = 1; + p_obj->desc_cnt = 0; + p_obj->state = CL_INITIALIZED; + p_obj->h_al = NULL; + p_obj->hdl = AL_INVALID_HANDLE; +} + + + +void +set_al_obj_timeout( + IN al_obj_t * const p_obj, + IN const uint32_t timeout_ms ) +{ + CL_ASSERT( p_obj ); + + /* Only increase timeout values. */ + p_obj->timeout_ms = MAX( p_obj->timeout_ms, timeout_ms ); +} + + + +void +inc_al_obj_desc( + IN al_obj_t * const p_obj, + IN const uint32_t desc_cnt ) +{ + CL_ASSERT( p_obj ); + + /* Increment the number of descendants. */ + p_obj->desc_cnt += desc_cnt; +} + + + +ib_api_status_t +attach_al_obj( + IN al_obj_t * const p_parent_obj, + IN al_obj_t * const p_child_obj ) +{ + AL_ENTER( AL_DBG_AL_OBJ ); + + CL_ASSERT( p_child_obj->state == CL_INITIALIZED ); + + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_AL_OBJ, + ("%p(%s) to %p(%s)\n", + p_child_obj, ib_get_obj_type( p_child_obj ), + p_parent_obj, ib_get_obj_type( p_parent_obj ) ) ); + + /* Insert the object into the parent's object tracking list. */ + p_child_obj->p_ci_ca = p_parent_obj->p_ci_ca; + cl_spinlock_acquire( &p_parent_obj->lock ); + if( p_parent_obj->state != CL_INITIALIZED ) + { + cl_spinlock_release( &p_parent_obj->lock ); + return IB_INVALID_STATE; + } + cl_qlist_insert_tail( &p_parent_obj->obj_list, + (cl_list_item_t*)&p_child_obj->pool_item ); + p_child_obj->p_parent_obj = p_parent_obj; + cl_spinlock_release( &p_parent_obj->lock ); + + if( p_parent_obj->h_al ) + { + if( !p_child_obj->h_al ) + { + p_child_obj->h_al = p_parent_obj->h_al; +#ifdef CL_KERNEL + p_child_obj->hdl = al_hdl_insert_obj( p_child_obj ); + if( p_child_obj->hdl == AL_INVALID_HANDLE ) + { + cl_spinlock_acquire( &p_parent_obj->lock ); + cl_qlist_remove_item( &p_parent_obj->obj_list, + (cl_list_item_t*)&p_child_obj->pool_item ); + p_child_obj->p_parent_obj = NULL; + cl_spinlock_release( &p_parent_obj->lock ); + return IB_INSUFFICIENT_MEMORY; + } +#endif + } + else + { + CL_ASSERT( p_child_obj->h_al == p_parent_obj->h_al ); + } + } + + /* Reference the parent. */ + ref_al_obj( p_parent_obj ); + AL_EXIT( AL_DBG_AL_OBJ ); + return IB_SUCCESS; +} + + + +/* + * Called to release a child object from its parent. + */ +void +detach_al_obj( + IN al_obj_t * const p_obj ) +{ + al_obj_t *p_parent_obj; + + AL_ENTER( AL_DBG_AL_OBJ ); + + p_parent_obj = p_obj->p_parent_obj; + CL_ASSERT( p_obj ); + CL_ASSERT( p_obj->state == CL_INITIALIZED || + p_obj->state == CL_DESTROYING ); + CL_ASSERT( p_parent_obj ); + CL_ASSERT( p_parent_obj->state == CL_INITIALIZED || + p_parent_obj->state == CL_DESTROYING ); + + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_AL_OBJ, + ("%p(%s) from %p(%s)\n", + p_obj, ib_get_obj_type( p_obj ), + p_parent_obj, ib_get_obj_type( p_parent_obj ) ) ); + + /* Remove the object from the parent's list. */ + cl_spinlock_acquire( &p_parent_obj->lock ); + cl_qlist_remove_item( &p_parent_obj->obj_list, + (cl_list_item_t*)&p_obj->pool_item ); + cl_spinlock_release( &p_parent_obj->lock ); + AL_EXIT( AL_DBG_AL_OBJ ); +} + + + +/* + * Increment a reference count on an object. This object should not be + * an object's parent. + */ +int32_t +ref_al_obj( + IN al_obj_t * const p_obj ) +{ + uint32_t ref_cnt; + + AL_ENTER( AL_DBG_AL_OBJ ); + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_AL_OBJ, + ("%p(%s)\n", p_obj, ib_get_obj_type( p_obj ) ) ); + ref_cnt = cl_atomic_inc( &p_obj->ref_cnt ); + CL_ASSERT( ref_cnt != 1 || p_obj->type == AL_OBJ_TYPE_H_CQ ); + + AL_EXIT( AL_DBG_AL_OBJ ); + return ref_cnt; +} + + + +/* + * Decrement the reference count on an AL object. Destroy the object if + * it is no longer referenced. This object should not be an object's parent. + */ +int32_t +deref_al_obj( + IN al_obj_t * const p_obj ) +{ + int32_t ref_cnt; + + AL_ENTER( AL_DBG_AL_OBJ ); + + CL_ASSERT( p_obj ); + CL_ASSERT( p_obj->state == CL_INITIALIZED || + p_obj->state == CL_DESTROYING ); + CL_ASSERT( p_obj->ref_cnt ); + + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_AL_OBJ, + ("%p(%s)\n", p_obj, ib_get_obj_type( p_obj ) ) ); + + ref_cnt = cl_atomic_dec( &p_obj->ref_cnt ); + + /* If the reference count went to 0, the object should be destroyed. */ + if( ref_cnt == 0 ) + { + if( p_obj->pfn_destroy == async_destroy_obj && + p_obj->user_destroy_cb != __sync_destroy_cb ) + { + /* Queue the object for asynchronous destruction. */ +#if AL_OBJ_PRIVATE_ASYNC_PROC + cl_async_proc_queue( gp_async_obj_mgr, &p_obj->async_item ); +#else + cl_async_proc_queue( gp_async_proc_mgr, &p_obj->async_item ); +#endif + } + else + { + /* Signal an event for synchronous destruction. */ + cl_event_signal( &p_obj->event ); + } + } + + AL_EXIT( AL_DBG_AL_OBJ ); + return ref_cnt; +} + + + +/* + * Called to cleanup all resources allocated by an object. + */ +void +destroy_al_obj( + IN al_obj_t * const p_obj ) +{ + AL_ENTER( AL_DBG_AL_OBJ ); + + CL_ASSERT( p_obj ); + CL_ASSERT( p_obj->state == CL_DESTROYING || + p_obj->state == CL_UNINITIALIZED ); + CL_ASSERT( cl_is_qlist_empty( &p_obj->obj_list ) ); + + /* Remove the object from the global tracking list. */ + if( p_obj != &gp_al_mgr->obj ) + { + cl_spinlock_acquire( &gp_al_mgr->lock ); + cl_qlist_remove_item( &gp_al_mgr->al_obj_list, &p_obj->list_item ); + cl_spinlock_release( &gp_al_mgr->lock ); + deref_al_obj( &gp_al_mgr->obj ); + } + + cl_event_destroy( &p_obj->event ); + cl_spinlock_destroy( &p_obj->lock ); + p_obj->state = CL_DESTROYED; + + AL_EXIT( AL_DBG_AL_OBJ ); +} + + + +void +async_destroy_obj( + IN struct _al_obj *p_obj, + IN const ib_pfn_destroy_cb_t pfn_destroy_cb ) +{ + AL_ENTER( AL_DBG_AL_OBJ ); + + if( pfn_destroy_cb == ib_sync_destroy ) + sync_destroy_obj( p_obj, pfn_destroy_cb ); + else if( destroy_obj( p_obj, pfn_destroy_cb ) ) + deref_al_obj( p_obj ); /* Only destroy the object once. */ + + AL_EXIT( AL_DBG_AL_OBJ ); +} + + + +void +sync_destroy_obj( + IN struct _al_obj *p_obj, + IN const ib_pfn_destroy_cb_t pfn_destroy_cb ) +{ + cl_status_t cl_status; + + AL_ENTER( AL_DBG_AL_OBJ ); + + if( !destroy_obj( p_obj, pfn_destroy_cb ) ) + { + /* Object is already being destroyed... */ + AL_EXIT( AL_DBG_AL_OBJ ); + return; + } + + if( deref_al_obj( p_obj ) ) + { + uint32_t wait_us; + /* + * Wait for all other references to go away. We wait as long as the + * longest child will take, plus an additional amount based on the + * number of descendants. + */ + wait_us = (p_obj->timeout_ms * 1000) + + (AL_TIMEOUT_PER_DESC_US * p_obj->desc_cnt); + wait_us = MIN( wait_us, AL_MAX_TIMEOUT_US ); + do + { + cl_status = cl_event_wait_on( + &p_obj->event, wait_us, AL_WAIT_ALERTABLE ); + } while( cl_status == CL_NOT_DONE ); + + if( cl_status != CL_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("Error waiting for references to be released - delaying.\n") ); + print_al_obj( p_obj ); + /* + * Wait some more to handle really long timeouts by referencing + * objects that are not descendants. + */ + do + { + cl_status = cl_event_wait_on( + &p_obj->event, AL_MAX_TIMEOUT_US, AL_WAIT_ALERTABLE ); + } while( cl_status == CL_NOT_DONE ); + + if ( p_obj->p_ci_ca && p_obj->p_ci_ca->h_ca ) + CL_PRINT_TO_EVENT_LOG( p_obj->p_ci_ca->h_ca->p_fdo, EVENT_IBBUS_ANY_ERROR, + ("IBAL stuck: AL object %s, ref_cnt: %d. Forcing object destruction.\n", + ib_get_obj_type( p_obj ), p_obj->ref_cnt)); + } + + CL_ASSERT( cl_status == CL_SUCCESS ); + if( cl_status != CL_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("Forcing object destruction.\n") ); + print_al_obj( p_obj ); + //print_tail_al_objs(); + print_al_objs( p_obj->h_al ); + p_obj->ref_cnt = 0; + } + } + async_destroy_cb( &p_obj->async_item ); + + AL_EXIT( AL_DBG_AL_OBJ ); +} + + + +boolean_t +destroy_obj( + IN struct _al_obj *p_obj, + IN const ib_pfn_destroy_cb_t pfn_destroy_cb ) +{ + cl_list_item_t *p_list_item; + al_obj_t *p_child_obj; + + AL_ENTER( AL_DBG_AL_OBJ ); + + CL_ASSERT( p_obj ); + CL_ASSERT( p_obj->state == CL_INITIALIZED || + p_obj->state == CL_DESTROYING ); + + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_AL_OBJ, + ("%p(%s)\n", p_obj, ib_get_obj_type( p_obj ) ) ); + + /* + * Lock to synchronize with asynchronous event processing. + * See ci_ca_async_event_cb for more information. + */ + cl_spinlock_acquire( &p_obj->lock ); + if( p_obj->state == CL_DESTROYING ) + { + cl_spinlock_release( &p_obj->lock ); + deref_al_obj( p_obj ); + AL_EXIT( AL_DBG_AL_OBJ ); + return FALSE; + } + p_obj->state = CL_DESTROYING; + cl_spinlock_release( &p_obj->lock ); + deref_al_obj( p_obj ); + +#ifdef CL_KERNEL + /* + * Release this object's handle. We must do this before calling the + * destroy callback so that any IOCTLs referencing this object will fail + */ + if( p_obj->hdl != AL_INVALID_HANDLE ) + { + CL_ASSERT( p_obj->h_al ); + al_hdl_free_obj( p_obj ); + } +#endif + + /* Notify the object that it is being destroyed. */ + if( p_obj->pfn_destroying ) + p_obj->pfn_destroying( p_obj ); + + if( p_obj->p_parent_obj ) + detach_al_obj( p_obj ); + + /* Destroy all child resources. No need to lock during destruction. */ + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_AL_OBJ, ("destroying children\n") ); + p_list_item = cl_qlist_tail( &p_obj->obj_list ); + while( p_list_item != cl_qlist_end( &p_obj->obj_list ) ) + { + p_child_obj = PARENT_STRUCT( p_list_item, al_obj_t, pool_item ); + CL_ASSERT( p_child_obj->pfn_destroy ); + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_AL_OBJ, + ("bye bye: %p(%s)\n", p_child_obj, + ib_get_obj_type( p_child_obj ) ) ); + ref_al_obj( p_child_obj ); + p_child_obj->pfn_destroy( p_child_obj, NULL ); + + p_list_item = cl_qlist_tail( &p_obj->obj_list ); + } + + /* + * Update our parent's timeout value. Ours could have been increased + * when destroying one of our children's. + */ + if( p_obj->p_parent_obj ) + { + set_al_obj_timeout( p_obj->p_parent_obj, p_obj->timeout_ms ); + inc_al_obj_desc( p_obj->p_parent_obj, p_obj->desc_cnt + 1 ); + } + + if( pfn_destroy_cb == ib_sync_destroy ) + p_obj->user_destroy_cb = __sync_destroy_cb; + else + p_obj->user_destroy_cb = pfn_destroy_cb; + + AL_EXIT( AL_DBG_AL_OBJ ); + return TRUE; +} + + + +void +async_destroy_cb( + IN cl_async_proc_item_t *p_item ) +{ + al_obj_t *p_obj; + al_obj_t *p_parent_obj = NULL; + + AL_ENTER( AL_DBG_AL_OBJ ); + + CL_ASSERT( p_item ); + p_obj = PARENT_STRUCT( p_item, al_obj_t, async_item ); + CL_ASSERT( p_obj ); + CL_ASSERT( p_obj->state == CL_DESTROYING ); + CL_ASSERT( !p_obj->ref_cnt ); + + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_AL_OBJ, + ("%p\n", p_obj ) ); + + /* Cleanup any hardware related resources. */ + if( p_obj->pfn_cleanup ) + { + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_AL_OBJ, ("cleaning up\n" ) ); + p_obj->pfn_cleanup( p_obj ); + } + + /* We can now safely dereference the parent. */ + if( p_obj->p_parent_obj ) + { + p_parent_obj = p_obj->p_parent_obj; + p_obj->p_parent_obj = NULL; + } + + /* Notify the user that we're done. */ + if( p_obj->user_destroy_cb ) + { + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_AL_OBJ, ("notifying user\n" ) ); + p_obj->user_destroy_cb( (void*)p_obj->context ); + } + + /* Free the resources associated with the object. */ + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_AL_OBJ, ("freeing object\n" ) ); + p_obj->pfn_free( p_obj ); + + /* Dereference the parent after freeing the child. */ + if( p_parent_obj ) + deref_al_obj( p_parent_obj ); + AL_EXIT( AL_DBG_AL_OBJ ); +} diff --git a/branches/WOF2-3/core/al/al_common.h b/branches/WOF2-3/core/al/al_common.h new file mode 100644 index 00000000..14288694 --- /dev/null +++ b/branches/WOF2-3/core/al/al_common.h @@ -0,0 +1,338 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#if !defined(__AL_COMMON_H__) +#define __AL_COMMON_H__ + +#include + +#include +#include +#include +#include +#include +#include + + +/* Driver parameters */ +extern uint32_t g_smi_poll_interval; +extern uint32_t g_ioc_query_timeout; +extern uint32_t g_ioc_query_retries; +extern uint32_t g_ioc_poll_interval; + + +/* Wait operations performed in user-mode must be alertable. */ +#ifdef CL_KERNEL +#define AL_WAIT_ALERTABLE FALSE +#else /* CL_KERNEL */ +#define AL_WAIT_ALERTABLE TRUE +#endif /* CL_KERNEL */ + +/* + * Controls whether the al_objects use their own private + * thread pool for destruction. + */ +#define AL_OBJ_PRIVATE_ASYNC_PROC 1 + +#if AL_OBJ_PRIVATE_ASYNC_PROC +extern cl_async_proc_t *gp_async_obj_mgr; +#endif + + +/* + * Macro to verify a AL object handle. We ignore the upper byte of the type + * when making the type comparison. The upper byte specifies a subtype. + */ +#define AL_BASE_TYPE( t ) ( (t) & 0x00FFFFFF ) +#define AL_SUBTYPE( t ) ( (t) & 0xFF000000 ) + +#define AL_OBJ_BASE_TYPE( h ) ( AL_BASE_TYPE( (h)->obj.type ) ) +#define AL_OBJ_SUBTYPE( h ) ( AL_SUBTYPE( (h)->obj.type ) ) + +#define AL_OBJ_IS_TYPE( h, t ) \ + ( AL_OBJ_BASE_TYPE( h ) == AL_BASE_TYPE( t ) ) + +#define AL_OBJ_IS_SUBTYPE( h, t ) \ + ( AL_OBJ_SUBTYPE( h ) == AL_SUBTYPE( t ) ) + +#define AL_OBJ_INVALID_HANDLE( h, t ) \ + ( !(h) || !AL_OBJ_IS_TYPE( h, t ) || ((h)->obj.state != CL_INITIALIZED) ) + + +typedef struct _al_obj __p_al_obj_t; + + +/* Function used to release AL items created by the object. */ +typedef void +(*al_pfn_destroying_t)( + IN struct _al_obj *p_obj ); + + +/* Function used to cleanup any HW resources used by the object. */ +typedef void +(*al_pfn_cleanup_t)( + IN struct _al_obj *p_obj ); + + +/* Function to all resources used by the object. */ +typedef void +(*al_pfn_free_t)( + IN struct _al_obj *p_obj ); + + +/* Function invoked to release HW resources. */ +typedef void +(*al_pfn_destroy_t)( + IN struct _al_obj *p_obj, + IN const ib_pfn_destroy_cb_t pfn_destroy_cb ); + + + +/* + * Different types of AL object's. Note that the upper byte signifies + * a subtype. + */ +#define AL_OBJ_TYPE_UNKNOWN 0 +#define AL_OBJ_TYPE_H_AL 1 +#define AL_OBJ_TYPE_H_QP 2 +#define AL_OBJ_TYPE_H_AV 3 +#define AL_OBJ_TYPE_H_MR 4 +#define AL_OBJ_TYPE_H_MW 5 +#define AL_OBJ_TYPE_H_PD 6 +#define AL_OBJ_TYPE_H_CA 7 +#define AL_OBJ_TYPE_H_CQ 8 +#define AL_OBJ_TYPE_H_CONN 9 +#define AL_OBJ_TYPE_H_LISTEN 10 +#define AL_OBJ_TYPE_H_IOC 11 +#define AL_OBJ_TYPE_H_SVC_ENTRY 12 +#define AL_OBJ_TYPE_H_PNP 13 +#define AL_OBJ_TYPE_H_SA_REQ 14 +#define AL_OBJ_TYPE_H_MCAST 15 +#define AL_OBJ_TYPE_H_ATTACH 16 +#define AL_OBJ_TYPE_H_MAD 17 +#define AL_OBJ_TYPE_H_MAD_POOL 18 +#define AL_OBJ_TYPE_H_POOL_KEY 19 +#define AL_OBJ_TYPE_H_MAD_SVC 20 +#define AL_OBJ_TYPE_CI_CA 21 +#define AL_OBJ_TYPE_CM 22 +#define AL_OBJ_TYPE_SMI 23 +#define AL_OBJ_TYPE_DM 24 +#define AL_OBJ_TYPE_IOU 25 +#define AL_OBJ_TYPE_LOADER 26 +#define AL_OBJ_TYPE_MAD_POOL 27 +#define AL_OBJ_TYPE_MAD_DISP 28 +#define AL_OBJ_TYPE_AL_MGR 29 +#define AL_OBJ_TYPE_PNP_MGR 30 +#define AL_OBJ_TYPE_IOC_PNP_MGR 31 +#define AL_OBJ_TYPE_IOC_PNP_SVC 32 +#define AL_OBJ_TYPE_QUERY_SVC 33 +#define AL_OBJ_TYPE_MCAST_SVC 34 +#define AL_OBJ_TYPE_SA_REQ_SVC 35 +#define AL_OBJ_TYPE_RES_MGR 36 +#define AL_OBJ_TYPE_H_CA_ATTR 37 +#define AL_OBJ_TYPE_H_PNP_EVENT 38 +#define AL_OBJ_TYPE_H_SA_REG 39 +#define AL_OBJ_TYPE_H_FMR 40 +#define AL_OBJ_TYPE_H_SRQ 41 +#define AL_OBJ_TYPE_H_FMR_POOL 42 +#define AL_OBJ_TYPE_NDI 43 +#define AL_OBJ_TYPE_INVALID 44 /* Must be last type. */ + +/* Kernel object for a user-mode app. */ +#define AL_OBJ_SUBTYPE_UM_EXPORT 0x80000000 + +/* CM related subtypes, used by the CM proxy. */ +#define AL_OBJ_SUBTYPE_REQ 0x01000000 +#define AL_OBJ_SUBTYPE_REP 0x02000000 +#define AL_OBJ_SUBTYPE_DREQ 0x04000000 +#define AL_OBJ_SUBTYPE_LAP 0x08000000 + +typedef uint32_t al_obj_type_t; + + +#define AL_DEFAULT_TIMEOUT_MS 10000 /* 10 seconds */ +#define AL_DEFAULT_TIMEOUT_US (AL_DEFAULT_TIMEOUT_MS * 1000) +#define AL_TIMEOUT_PER_DESC_US 10000 +#define AL_MAX_TIMEOUT_MS (AL_DEFAULT_TIMEOUT_MS * 10) +#define AL_MAX_TIMEOUT_US (AL_MAX_TIMEOUT_MS * 1000) + + +#if defined( _DEBUG_ ) +const char* ib_obj_type_str[]; +#endif + + +/* + * Base object for AL resources. This must be the first element of + * AL resources. + */ +typedef struct _al_obj +{ + cl_pool_item_t pool_item; + + struct _al_obj *p_parent_obj; + struct _al_ci_ca *p_ci_ca; + + const void *context; + + /* Asynchronous item used when destroying the object asynchronously. */ + cl_async_proc_item_t async_item; + + /* Event used when destroying the object synchronously. */ + cl_event_t event; + uint32_t timeout_ms; + uint32_t desc_cnt; + + al_pfn_destroy_t pfn_destroy; + al_pfn_destroying_t pfn_destroying; + al_pfn_cleanup_t pfn_cleanup; + al_pfn_free_t pfn_free; + ib_pfn_destroy_cb_t user_destroy_cb; + + cl_spinlock_t lock; + cl_qlist_t obj_list; + atomic32_t ref_cnt; + + cl_list_item_t list_item; + al_obj_type_t type; + cl_state_t state; + + uint64_t hdl; /* User Handle. */ + ib_al_handle_t h_al; /* Owning AL instance. */ + +#ifdef CL_KERNEL + /* + * Flag to indicate that UM calls may proceed on the given object. + * Set by the proxy when creation completes successfully. + */ + boolean_t hdl_valid; +#endif +} al_obj_t; + + +void +construct_al_obj( + IN al_obj_t * const p_obj, + IN const al_obj_type_t obj_type ); + + +ib_api_status_t +init_al_obj( + IN al_obj_t * const p_obj, + IN const void* const context, + IN boolean_t async_destroy, + IN const al_pfn_destroying_t pfn_destroying, + IN const al_pfn_cleanup_t pfn_cleanup, + IN const al_pfn_free_t pfn_free ); + +/* + * Reset an object's state. This is called after pfn_destroy() has + * been called on a object, but before destroy_al_obj() has been invoked. + * It allows an object to be initialized once, then returned to a pool + * on destruction, and later reused after being removed from the pool. + */ +void +reset_al_obj( + IN al_obj_t * const p_obj ); + +void +set_al_obj_timeout( + IN al_obj_t * const p_obj, + IN const uint32_t timeout_ms ); + +void +inc_al_obj_desc( + IN al_obj_t * const p_obj, + IN const uint32_t desc_cnt ); + + +/* + * Attach to our parent object. The parent will destroy the child when + * it is destroyed. Attaching a child to the parent automatically + * increments the parent's reference count. + */ +ib_api_status_t +attach_al_obj( + IN al_obj_t * const p_parent_obj, + IN al_obj_t * const p_child_obj ); + + +/* + * Increment the reference count on an AL object. + */ +int32_t +ref_al_obj( + IN al_obj_t * const p_obj ); + + +/* + * Called to release a child object from its parent. The child's + * reference to its parent is still held. + */ +void +detach_al_obj( + IN al_obj_t * const p_obj ); + +/* + * Decrement the reference count on an AL object. + */ +AL_EXPORT int32_t AL_API +deref_al_obj( + IN al_obj_t * const p_obj ); + +/* + * Called to cleanup all resources allocated by an object. + */ +void +destroy_al_obj( + IN al_obj_t * const p_obj ); + + + + +extern const char* ib_obj_type_str[]; + +static inline const char* +ib_get_obj_type( + IN al_obj_t * const p_obj ) +{ + if( AL_BASE_TYPE( p_obj->type ) >= AL_OBJ_TYPE_INVALID ) + return( ib_obj_type_str[AL_OBJ_TYPE_UNKNOWN] ); + + return( ib_obj_type_str[ AL_BASE_TYPE( p_obj->type ) ] ); +} + + + + +#endif /* __AL_COMMON_H__ */ diff --git a/branches/WOF2-3/core/al/al_cq.c b/branches/WOF2-3/core/al/al_cq.c new file mode 100644 index 00000000..ef5f8002 --- /dev/null +++ b/branches/WOF2-3/core/al/al_cq.c @@ -0,0 +1,508 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include "al_cq.h" +#include "al_debug.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "al_cq.tmh" +#endif + +#include "al_ca.h" +#include "al_pd.h" +#include "al_qp.h" +#include "al_verbs.h" +#ifdef CL_KERNEL +#include "al_proxy_ndi.h" +#endif + +/* + * Function prototypes. + */ +void +destroying_cq( + IN struct _al_obj *p_obj ); + +void +cleanup_cq( + IN al_obj_t *p_obj ); + +void +free_cq( + IN al_obj_t *p_obj ); + + + + +/* + * Initializes the CQ information structure. + */ +ib_api_status_t +create_cq( + IN const ib_ca_handle_t h_ca, + IN OUT ib_cq_create_t* const p_cq_create, + IN const void* const cq_context, + IN const ib_pfn_event_cb_t pfn_cq_event_cb, + OUT ib_cq_handle_t* const ph_cq, + IN OUT ci_umv_buf_t* const p_umv_buf ) +{ + ib_cq_handle_t h_cq; + ib_api_status_t status; + al_obj_type_t obj_type = AL_OBJ_TYPE_H_CQ; + + if( !p_cq_create || !ph_cq ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + if( (p_cq_create->pfn_comp_cb && p_cq_create->h_wait_obj) || + (!p_cq_create->pfn_comp_cb && !p_cq_create->h_wait_obj) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_SETTING\n") ); + return IB_INVALID_SETTING; + } + + h_cq = cl_zalloc( sizeof( ib_cq_t ) ); + if( !h_cq ) + { + return IB_INSUFFICIENT_MEMORY; + } + +#ifdef CL_KERNEL + if( !NT_SUCCESS( ndi_cq_init( h_cq ) ) ) + { + free_cq( &h_cq->obj ); + return IB_ERROR; + } +#endif + + if( p_umv_buf ) + obj_type |= AL_OBJ_SUBTYPE_UM_EXPORT; + + /* Construct the CQ. */ + construct_al_obj( &h_cq->obj, obj_type ); + + cl_qlist_init( &h_cq->qp_list ); + + /* Initialize the CQ. */ + status = init_al_obj( &h_cq->obj, cq_context, TRUE, + destroying_cq, cleanup_cq, free_cq ); + if( status != IB_SUCCESS ) + { + free_cq( &h_cq->obj ); + return status; + } + status = attach_al_obj( &h_ca->obj, &h_cq->obj ); + if( status != IB_SUCCESS ) + { + h_cq->obj.pfn_destroy( &h_cq->obj, NULL ); + return status; + } + + /* + * Record which completion routine will be used to notify the CQ of + * a completion. + */ + h_cq->pfn_event_cb = pfn_cq_event_cb; + if( p_cq_create->pfn_comp_cb ) + { + CL_ASSERT( !p_cq_create->h_wait_obj ); + h_cq->pfn_user_comp_cb = p_cq_create->pfn_comp_cb; + } + else + { + CL_ASSERT( p_cq_create->h_wait_obj ); + h_cq->h_wait_obj = p_cq_create->h_wait_obj; + } + + /* + * Note: + * Because an extra reference is not held on the object during creation, + * the h_cq handle may be destroryed by the client's asynchronous event + * callback routine before call to verbs returns. + */ + status = verbs_create_cq( h_ca, p_cq_create, h_cq, p_umv_buf ); + if( status != IB_SUCCESS ) + { + h_cq->obj.pfn_destroy( &h_cq->obj, NULL ); + return status; + } + + *ph_cq = h_cq; + + return IB_SUCCESS; +} + + + +ib_api_status_t +ib_destroy_cq( + IN const ib_cq_handle_t h_cq, + IN const ib_pfn_destroy_cb_t pfn_destroy_cb OPTIONAL ) +{ + AL_ENTER( AL_DBG_CQ ); + + if( AL_OBJ_INVALID_HANDLE( h_cq, AL_OBJ_TYPE_H_CQ ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_CQ_HANDLE\n") ); + return IB_INVALID_CQ_HANDLE; + } + + ref_al_obj( &h_cq->obj ); + h_cq->obj.pfn_destroy( &h_cq->obj, pfn_destroy_cb ); + + AL_EXIT( AL_DBG_CQ ); + return IB_SUCCESS; +} + + + +void +destroying_cq( + IN struct _al_obj *p_obj ) +{ + ib_cq_handle_t h_cq; + cl_list_item_t *p_item; + cl_obj_rel_t *p_rel; + ib_qp_handle_t h_qp; + + CL_ASSERT( p_obj ); + h_cq = PARENT_STRUCT( p_obj, ib_cq_t, obj ); + + /* Initiate destruction of all bound QPs. */ + cl_spinlock_acquire( &h_cq->obj.lock ); + for( p_item = cl_qlist_remove_tail( &h_cq->qp_list ); + p_item != cl_qlist_end( &h_cq->qp_list ); + p_item = cl_qlist_remove_tail( &h_cq->qp_list ) ) + { + p_rel = PARENT_STRUCT( p_item, cl_obj_rel_t, pool_item.list_item ); + p_rel->p_parent_obj = NULL; + h_qp = (ib_qp_handle_t)p_rel->p_child_obj; + if( h_qp ) + { + /* Take a reference to prevent the QP from being destroyed. */ + ref_al_obj( &h_qp->obj ); + cl_spinlock_release( &h_cq->obj.lock ); + h_qp->obj.pfn_destroy( &h_qp->obj, NULL ); + cl_spinlock_acquire( &h_cq->obj.lock ); + } + } + + cl_spinlock_release( &h_cq->obj.lock ); + +#ifdef CL_KERNEL + /* cancel pending IRPS for NDI type CQ */ + ndi_cq_flush_ques( h_cq ); +#endif + +} + + +void +cleanup_cq( + IN struct _al_obj *p_obj ) +{ + ib_cq_handle_t h_cq; + ib_api_status_t status; + + CL_ASSERT( p_obj ); + h_cq = PARENT_STRUCT( p_obj, ib_cq_t, obj ); + + /* Deallocate the CI cq. */ + if( verbs_check_cq( h_cq ) ) + { + status = verbs_destroy_cq( h_cq ); + CL_ASSERT( status == IB_SUCCESS ); + } +} + + + +/* + * Release all resources associated with the completion queue. + */ +void +free_cq( + IN al_obj_t *p_obj ) +{ + ib_cq_handle_t h_cq; + + CL_ASSERT( p_obj ); + h_cq = PARENT_STRUCT( p_obj, ib_cq_t, obj ); + + destroy_al_obj( &h_cq->obj ); + cl_free( h_cq ); +} + + +void +cq_attach_qp( + IN const ib_cq_handle_t h_cq, + IN cl_obj_rel_t* const p_qp_rel ) +{ + p_qp_rel->p_parent_obj = (cl_obj_t*)h_cq; + ref_al_obj( &h_cq->obj ); + cl_spinlock_acquire( &h_cq->obj.lock ); + cl_qlist_insert_tail( &h_cq->qp_list, &p_qp_rel->pool_item.list_item ); + cl_spinlock_release( &h_cq->obj.lock ); +} + + +void +cq_detach_qp( + IN const ib_cq_handle_t h_cq, + IN cl_obj_rel_t* const p_qp_rel ) +{ + if( p_qp_rel->p_parent_obj ) + { + CL_ASSERT( p_qp_rel->p_parent_obj == (cl_obj_t*)h_cq ); + p_qp_rel->p_parent_obj = NULL; + cl_spinlock_acquire( &h_cq->obj.lock ); + cl_qlist_remove_item( &h_cq->qp_list, &p_qp_rel->pool_item.list_item ); + cl_spinlock_release( &h_cq->obj.lock ); + } +} + + +ib_api_status_t +ib_modify_cq( + IN const ib_cq_handle_t h_cq, + IN OUT uint32_t* const p_size ) +{ + return modify_cq( h_cq, p_size, NULL ); +} + + +ib_api_status_t +modify_cq( + IN const ib_cq_handle_t h_cq, + IN OUT uint32_t* const p_size, + IN OUT ci_umv_buf_t* const p_umv_buf ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_CQ ); + + if( AL_OBJ_INVALID_HANDLE( h_cq, AL_OBJ_TYPE_H_CQ ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_CQ_HANDLE\n") ); + return IB_INVALID_CQ_HANDLE; + } + if( !p_size ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + status = verbs_modify_cq( h_cq, p_size ); + + AL_EXIT( AL_DBG_CQ ); + return status; +} + + + +ib_api_status_t +ib_query_cq( + IN const ib_cq_handle_t h_cq, + OUT uint32_t* const p_size ) +{ + return query_cq( h_cq, p_size, NULL ); +} + + + +ib_api_status_t +query_cq( + IN const ib_cq_handle_t h_cq, + OUT uint32_t* const p_size, + IN OUT ci_umv_buf_t* const p_umv_buf ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_CQ ); + + if( AL_OBJ_INVALID_HANDLE( h_cq, AL_OBJ_TYPE_H_CQ ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_CQ_HANDLE\n") ); + return IB_INVALID_CQ_HANDLE; + } + if( !p_size ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + status = verbs_query_cq( h_cq, p_size ); + + AL_EXIT( AL_DBG_CQ ); + return status; +} + + + +ib_api_status_t +ib_peek_cq( + IN const ib_cq_handle_t h_cq, + OUT uint32_t* const p_n_cqes ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_CQ ); + + if( AL_OBJ_INVALID_HANDLE( h_cq, AL_OBJ_TYPE_H_CQ ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_CQ_HANDLE\n") ); + return IB_INVALID_CQ_HANDLE; + } + if( !p_n_cqes ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + status = verbs_peek_cq( h_cq, p_n_cqes ); + + AL_EXIT( AL_DBG_CQ ); + return status; +} + + + +ib_api_status_t +ib_poll_cq( + IN const ib_cq_handle_t h_cq, + IN OUT ib_wc_t** const pp_free_wclist, + OUT ib_wc_t** const pp_done_wclist ) +{ + ib_api_status_t status; + PERF_DECLARE( IbPollCq ); + PERF_DECLARE( VerbsPollCq ); + + cl_perf_start( IbPollCq ); + AL_ENTER( AL_DBG_CQ ); + + if( AL_OBJ_INVALID_HANDLE( h_cq, AL_OBJ_TYPE_H_CQ ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_CQ_HANDLE\n") ); + return IB_INVALID_CQ_HANDLE; + } + if( !pp_free_wclist || !pp_done_wclist ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + cl_perf_start( VerbsPollCq ); + status = verbs_poll_cq( h_cq, pp_free_wclist, pp_done_wclist ); + cl_perf_stop( &g_perf, VerbsPollCq ); + + AL_EXIT( AL_DBG_CQ ); + cl_perf_stop( &g_perf, IbPollCq ); + return status; +} + + + +ib_api_status_t +ib_rearm_cq( + IN const ib_cq_handle_t h_cq, + IN const boolean_t solicited ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_CQ ); + + if( AL_OBJ_INVALID_HANDLE( h_cq, AL_OBJ_TYPE_H_CQ ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_CQ_HANDLE\n") ); + return IB_INVALID_CQ_HANDLE; + } + + status = verbs_rearm_cq( h_cq, solicited ); + + AL_EXIT( AL_DBG_CQ ); + return status; +} + + + +ib_api_status_t +ib_rearm_n_cq( + IN const ib_cq_handle_t h_cq, + IN const uint32_t n_cqes ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_CQ ); + + if( AL_OBJ_INVALID_HANDLE( h_cq, AL_OBJ_TYPE_H_CQ ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_CQ_HANDLE\n") ); + return IB_INVALID_CQ_HANDLE; + } + if( !n_cqes ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + status = verbs_rearm_n_cq( h_cq, n_cqes ); + + AL_EXIT( AL_DBG_CQ ); + return status; +} + + + +/* + * Process an asynchronous event on the CQ. Notify the user of the event. + */ +void +cq_async_event_cb( + IN ib_async_event_rec_t* const p_event_rec ) +{ + ib_cq_handle_t h_cq; + + CL_ASSERT( p_event_rec ); + h_cq = (ib_cq_handle_t)p_event_rec->context; + + p_event_rec->context = (void*)h_cq->obj.context; + p_event_rec->handle.h_cq = h_cq; + + if( h_cq->pfn_event_cb ) + h_cq->pfn_event_cb( p_event_rec ); +} diff --git a/branches/WOF2-3/core/al/al_cq.h b/branches/WOF2-3/core/al/al_cq.h new file mode 100644 index 00000000..39a4b24c --- /dev/null +++ b/branches/WOF2-3/core/al/al_cq.h @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#if !defined(__AL_CQ_H__) +#define __AL_CQ_H__ + +#include "al_ca.h" + +typedef void +(*pfn_proc_comp_t)( + IN const ib_cq_handle_t h_cq ); + +typedef ib_api_status_t +(*pfn_peek_cq_t)( + IN const ib_cq_handle_t h_cq, + OUT uint32_t* const p_n_cqes ); + +typedef ib_api_status_t +(*pfn_poll_cq_t)( + IN const ib_cq_handle_t h_cq, + IN OUT ib_wc_t** const pp_free_wclist, + OUT ib_wc_t** const pp_done_wclist ); + +typedef ib_api_status_t +(*pfn_rearm_cq_t)( + IN const ib_cq_handle_t h_cq, + IN const boolean_t solicited ); + +typedef ib_api_status_t +(*pfn_rearm_n_cq_t)( + IN const ib_cq_handle_t h_cq, + IN const uint32_t n_cqes ); + +#ifdef CL_KERNEL + +typedef struct _ib_cq ib_cq_t; + +typedef struct _ndi_cq_csq +{ + IO_CSQ csq; + ib_cq_t* h_cq; + LIST_ENTRY queue; +} ndi_cq_csq_t; + +#endif + +/* + * Completion queue information required by the access layer. This structure + * is referenced by a user's CQ handle. + */ +typedef struct _ib_cq +{ + al_obj_t obj; /* Must be first. */ + + cl_qlist_t qp_list; /* List of QPs bound to this CQ. */ + + ib_pfn_comp_cb_t pfn_user_comp_cb; + cl_waitobj_handle_t h_wait_obj; + + ib_cq_handle_t h_ci_cq; + + /* Function pointers for the various speed path operations. */ +#ifndef CL_KERNEL + pfn_peek_cq_t pfn_peek; + ib_cq_handle_t h_peek_cq; + + pfn_poll_cq_t pfn_poll; + ib_cq_handle_t h_poll_cq; + + pfn_rearm_cq_t pfn_rearm; + ib_cq_handle_t h_rearm_cq; + + pfn_rearm_n_cq_t pfn_rearm_n; + ib_cq_handle_t h_rearm_n_cq; +#endif + + ib_pfn_event_cb_t pfn_event_cb; + + /* NDI CQ fields */ +#ifdef CL_KERNEL + ndi_cq_csq_t compl; + ndi_cq_csq_t error; +#endif + +} ib_cq_t; + + + +ib_api_status_t +create_cq( + IN const ib_ca_handle_t h_ca, + IN OUT ib_cq_create_t* const p_cq_create, + IN const void* const cq_context, + IN const ib_pfn_event_cb_t pfn_cq_event_cb, + OUT ib_cq_handle_t* const ph_cq, + IN OUT ci_umv_buf_t* const p_umv_buf ); + + +ib_api_status_t +modify_cq( + IN const ib_cq_handle_t h_cq, + IN OUT uint32_t* const p_size, + IN OUT ci_umv_buf_t* const p_umv_buf ); + + +ib_api_status_t +query_cq( + IN const ib_cq_handle_t h_cq, + OUT uint32_t* const p_size, + IN OUT ci_umv_buf_t* const p_umv_buf ); + + +void +cq_async_event_cb( + IN ib_async_event_rec_t* const p_event_rec ); + + +void +cq_attach_qp( + IN const ib_cq_handle_t h_cq, + IN cl_obj_rel_t* const p_qp_rel ); + + +void +cq_detach_qp( + IN const ib_cq_handle_t h_cq, + IN cl_obj_rel_t* const p_qp_rel ); + +#endif /* __AL_CQ_H__ */ diff --git a/branches/WOF2-3/core/al/al_debug.h b/branches/WOF2-3/core/al/al_debug.h new file mode 100644 index 00000000..b7f9c30c --- /dev/null +++ b/branches/WOF2-3/core/al/al_debug.h @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#if !defined(__AL_DEBUG_H__) +#define __AL_DEBUG_H__ + +#ifdef __MODULE__ +#undef __MODULE__ +#endif +#define __MODULE__ "[AL]" + + +#include +#include + +extern uint32_t g_al_dbg_level; +extern uint32_t g_al_dbg_flags; + +#if defined(EVENT_TRACING) +// +// Software Tracing Definitions +// + +#ifndef CL_KERNEL + +#define WPP_CONTROL_GUIDS \ + WPP_DEFINE_CONTROL_GUID(ALCtlGuid1,(B199CE55,F8BF,4147,B119,DACD1E5987A6), \ + WPP_DEFINE_BIT( AL_DBG_ERROR) \ + WPP_DEFINE_BIT( AL_DBG_PNP) \ + WPP_DEFINE_BIT( AL_DBG_HDL) \ + WPP_DEFINE_BIT( AL_DBG_AL_OBJ) \ + WPP_DEFINE_BIT( AL_DBG_SMI) \ + WPP_DEFINE_BIT( AL_DBG_SMI_CB) \ + WPP_DEFINE_BIT( AL_DBG_RES1) \ + WPP_DEFINE_BIT( AL_DBG_MAD_POOL) \ + WPP_DEFINE_BIT( AL_DBG_MAD_SVC) \ + WPP_DEFINE_BIT( AL_DBG_RES2) \ + WPP_DEFINE_BIT( AL_DBG_CM) \ + WPP_DEFINE_BIT( AL_DBG_CA) \ + WPP_DEFINE_BIT( AL_DBG_MR) \ + WPP_DEFINE_BIT( AL_DBG_MGR)\ + WPP_DEFINE_BIT( AL_DBG_DEV)\ + WPP_DEFINE_BIT( AL_DBG_MCAST)\ + WPP_DEFINE_BIT( AL_DBG_PD)\ + WPP_DEFINE_BIT( AL_DBG_AV)\ + WPP_DEFINE_BIT( AL_DBG_CQ)\ + WPP_DEFINE_BIT( AL_DBG_QP)\ + WPP_DEFINE_BIT( AL_DBG_SRQ)\ + WPP_DEFINE_BIT( AL_DBG_MW)\ + WPP_DEFINE_BIT( AL_DBG_NDI) \ + WPP_DEFINE_BIT( AL_DBG_PROXY_CB)\ + WPP_DEFINE_BIT( AL_DBG_UAL)\ + WPP_DEFINE_BIT( AL_DBG_QUERY)\ + WPP_DEFINE_BIT( AL_DBG_SA_REQ)\ + WPP_DEFINE_BIT( AL_DBG_IOC)\ + WPP_DEFINE_BIT( AL_DBG_SUB)\ + WPP_DEFINE_BIT( AL_DBG_MAD)) + +#else + +#define WPP_CONTROL_GUIDS \ + WPP_DEFINE_CONTROL_GUID(ALCtlGuid2,(99DC84E3,B106,431e,88A6,4DD20C9BBDE3), \ + WPP_DEFINE_BIT( AL_DBG_ERROR) \ + WPP_DEFINE_BIT( AL_DBG_PNP) \ + WPP_DEFINE_BIT( AL_DBG_HDL) \ + WPP_DEFINE_BIT( AL_DBG_AL_OBJ) \ + WPP_DEFINE_BIT( AL_DBG_SMI) \ + WPP_DEFINE_BIT( AL_DBG_SMI_CB) \ + WPP_DEFINE_BIT( AL_DBG_FMR_POOL) \ + WPP_DEFINE_BIT( AL_DBG_MAD_POOL) \ + WPP_DEFINE_BIT( AL_DBG_MAD_SVC) \ + WPP_DEFINE_BIT( AL_DBG_RES2) \ + WPP_DEFINE_BIT( AL_DBG_CM) \ + WPP_DEFINE_BIT( AL_DBG_CA) \ + WPP_DEFINE_BIT( AL_DBG_MR) \ + WPP_DEFINE_BIT( AL_DBG_MGR)\ + WPP_DEFINE_BIT( AL_DBG_DEV)\ + WPP_DEFINE_BIT( AL_DBG_MCAST)\ + WPP_DEFINE_BIT( AL_DBG_PD)\ + WPP_DEFINE_BIT( AL_DBG_AV)\ + WPP_DEFINE_BIT( AL_DBG_CQ)\ + WPP_DEFINE_BIT( AL_DBG_QP)\ + WPP_DEFINE_BIT( AL_DBG_SRQ)\ + WPP_DEFINE_BIT( AL_DBG_MW)\ + WPP_DEFINE_BIT( AL_DBG_NDI) \ + WPP_DEFINE_BIT( AL_DBG_PROXY_CB)\ + WPP_DEFINE_BIT( AL_DBG_UAL)\ + WPP_DEFINE_BIT( AL_DBG_QUERY)\ + WPP_DEFINE_BIT( AL_DBG_SA_REQ)\ + WPP_DEFINE_BIT( AL_DBG_IOC)\ + WPP_DEFINE_BIT( AL_DBG_SUB)\ + WPP_DEFINE_BIT( AL_DBG_MAD)) + +#endif + + +#define WPP_LEVEL_FLAGS_ENABLED(lvl, flags) (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= lvl) +#define WPP_LEVEL_FLAGS_LOGGER(lvl,flags) WPP_LEVEL_LOGGER(flags) +#define WPP_FLAG_ENABLED(flags)(WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= TRACE_LEVEL_VERBOSE) +#define WPP_FLAG_LOGGER(flags) WPP_LEVEL_LOGGER(flags) + + +// begin_wpp config +// AL_ENTER( FLAG ); +// AL_EXIT( FLAG ); +// USEPREFIX(AL_PRINT, "%!STDPREFIX! [AL] :%!FUNC!():"); +// USESUFFIX(AL_ENTER, " [AL] :%!FUNC!():["); +// USESUFFIX(AL_EXIT, " [AL] :%!FUNC!():]"); +// end_wpp + + + +#else + +#include +#include + +/* + * Debug macros + */ + + +/* Debug message source */ +#define AL_DBG_ERR (1 << 0) +#define AL_DBG_PNP (1 << 1) +#define AL_DBG_HDL (1 << 2) +#define AL_DBG_AL_OBJ (1 << 3) +#define AL_DBG_SMI (1 << 4) +#define AL_DBG_SMI_CB (1 << 5) +#define AL_DBG_FMR_POOL (1 << 6) +#define AL_DBG_MAD_POOL (1 << 7) +#define AL_DBG_MAD_SVC (1 << 8) +#define AL_DBG_CM (1 << 10) +#define AL_DBG_CA (1 << 11) +#define AL_DBG_MR (1 << 12) +#define AL_DBG_MGR (1 << 13) +#define AL_DBG_DEV (1 << 14) +#define AL_DBG_MCAST (1 << 15) +#define AL_DBG_PD (1 << 16) +#define AL_DBG_AV (1 << 17) +#define AL_DBG_CQ (1 << 18) +#define AL_DBG_QP (1 << 19) +#define AL_DBG_SRQ (1 << 20) +#define AL_DBG_MW (1 << 21) +#define AL_DBG_NDI (1 << 22) +#define AL_DBG_PROXY_CB (1 << 23) +#define AL_DBG_UAL (1 << 24) +#define AL_DBG_QUERY (1 << 25) +#define AL_DBG_SA_REQ (1 << 26) +#define AL_DBG_IOC (1 << 27) +#define AL_DBG_SUB (1 << 28) +#define AL_DBG_MAD (1 << 29) //TODO + +#define AL_DBG_ERROR (CL_DBG_ERROR | AL_DBG_ERR) + +#if DBG + +// assignment of _level_ is need to to overcome warning C4127 + +// +// Code in DBG, has no impact on fre performance +// Hence the 6326 warning suppression +// + +#define AL_PRINT( _level_,_flag_,_msg_) \ + { \ + __pragma(warning(suppress:6326)) \ + if( g_al_dbg_level >= (_level_) ) \ + CL_TRACE( _flag_, g_al_dbg_flags, _msg_ ); \ + } + + +#define AL_PRINT_EXIT( _level_,_flag_,_msg_) \ + { \ + __pragma(warning(suppress:6326)) \ + if( g_al_dbg_level >= (_level_) ) \ + CL_TRACE( _flag_, g_al_dbg_flags, _msg_ );\ + AL_EXIT( _flag_ );\ + } + +#define AL_ENTER( _flag_) \ + { \ + __pragma(warning(suppress:6326)) \ + if( g_al_dbg_level >= TRACE_LEVEL_VERBOSE ) \ + CL_ENTER( _flag_, g_al_dbg_flags ); \ + } + +#define AL_EXIT( _flag_)\ + { \ + __pragma(warning(suppress:6326)) \ + if( g_al_dbg_level >= TRACE_LEVEL_VERBOSE ) \ + CL_EXIT( _flag_, g_al_dbg_flags ); \ + } + + +#else + +#define AL_PRINT( lvl, flags, msg) + +#define AL_PRINT_EXIT( _level_,_flag_,_msg_) + +#define AL_ENTER( _flag_) + +#define AL_EXIT( _flag_) + + +#endif + +#endif //EVENT_TRACING + + + +enum al_perf_counters +{ + IbPostSend, + PostSend, + VpPostSend, + UalDoPostSend, + + IbPollCq, + VerbsPollCq, + VpPollCq, + UalDoPollCq, + + + AlMaxPerf + +}; + +extern cl_perf_t g_perf; + + +#endif /* __AL_DEBUG_H__ */ diff --git a/branches/WOF2-3/core/al/al_dev.h b/branches/WOF2-3/core/al/al_dev.h new file mode 100644 index 00000000..179fb13d --- /dev/null +++ b/branches/WOF2-3/core/al/al_dev.h @@ -0,0 +1,563 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + +/* + * Abstract: + * This header file defines data structures for the user-mode proxy + * and UAL support + * + * Environment: + * Kernel and User Mode. + */ + + +#ifndef _ALDEV_H_ +#define _ALDEV_H_ + +#include +#include +#include +#include +#include + +#define AL_DEVICE_NAME L"\\Device\\ibal" +#define ALDEV_KEY (0x3B) /* Matches FILE_DEVICE_INFINIBAND from wdm.h */ + +#define AL_IOCTL_VERSION (12) + +/* max number of devices with non-default pkey */ +#define MAX_NUM_PKEY 16 + +typedef struct _pkey_array +{ + ib_net64_t port_guid; + ib_net16_t pkey_num; + ib_net16_t pkey_array[MAX_NUM_PKEY]; +}pkey_array_t; +#ifdef CL_KERNEL + +/* Function prototypes for al device framework */ + +AL_EXPORT cl_status_t AL_API +al_dev_open( + IN cl_ioctl_handle_t h_ioctl ); + +AL_EXPORT cl_status_t AL_API +al_dev_close( + IN cl_ioctl_handle_t h_ioctl ); + +AL_EXPORT cl_status_t AL_API +al_dev_ioctl( + IN cl_ioctl_handle_t h_ioctl ); + +cl_status_t +bus_add_pkey( + IN cl_ioctl_handle_t h_ioctl ); +cl_status_t +bus_rem_pkey( + IN cl_ioctl_handle_t h_ioctl ); + +/* Define data structures for user-mode proxy */ +#else /* CL_KERNEL */ + + +/* Prototype for the ioctl support function */ +cl_status_t +do_al_dev_ioctl( + IN uint32_t command, + IN void *p_buf, + IN uintn_t buf_size, + IN void *p_out_buf, + IN uintn_t out_buf_size, + OUT uintn_t *p_bytes_ret ); + + +#endif /* CL_KERNEL */ + +/* + * Shared between user and kernel mode. + */ + + +/****d* AL device Helper/al_proxy_ops_t +* NAME +* al_proxy_ops_t +* +* DESCRIPTION +* +* Define the enumeration for UAL/proxy excluding AL specific +* These are intended to be the support ioctls such as the +* notification from the proxy to the UAL in user-mode +* +* SYNOPSIS +*/ +typedef enum al_proxy_ops +{ + al_proxy_ops_start = 0, + + ual_get_comp_cb_info = al_proxy_ops_start+1, + ual_get_misc_cb_info, + ual_bind, + ual_bind_sa, + ual_bind_pnp, + ual_bind_misc, + ual_bind_cm, + ual_bind_cq, + ual_bind_destroy, + ual_bind_nd, + al_proxy_maxops + +} al_proxy_ops_t; +/**********/ +/* + * Various Opration Allowable on the System Helper + */ + +/* IOCTL to specify what notification wait objects are used by UAL + * for asynchronous event notifications from proxy + */ + +#define UAL_GET_COMP_CB_INFO IOCTL_CODE(ALDEV_KEY, ual_get_comp_cb_info) +#define UAL_GET_MISC_CB_INFO IOCTL_CODE(ALDEV_KEY, ual_get_misc_cb_info) +#define UAL_BIND IOCTL_CODE(ALDEV_KEY, ual_bind) +#define UAL_BIND_SA IOCTL_CODE(ALDEV_KEY, ual_bind_sa) +#define UAL_BIND_PNP IOCTL_CODE(ALDEV_KEY, ual_bind_pnp) +#define UAL_BIND_MISC IOCTL_CODE(ALDEV_KEY, ual_bind_misc) +#define UAL_BIND_CM IOCTL_CODE(ALDEV_KEY, ual_bind_cm) +#define UAL_BIND_CQ IOCTL_CODE(ALDEV_KEY, ual_bind_cq) +#define UAL_BIND_DESTROY IOCTL_CODE(ALDEV_KEY, ual_bind_destroy) +#define UAL_BIND_ND IOCTL_CODE(ALDEV_KEY, ual_bind_nd) + +#define AL_PROXY_OPS_START IOCTL_CODE(ALDEV_KEY, al_proxy_ops_start) +#define AL_PROXY_MAXOPS IOCTL_CODE(ALDEV_KEY, al_proxy_maxops) + +#define IS_AL_PROXY_IOCTL(cmd) \ + ((cmd) > AL_PROXY_OPS_START && (cmd) < AL_PROXY_MAXOPS) + + + +/****d* AL device Helper/al_dev_ops_t +* NAME +* al_dev_ops_t +* +* DESCRIPTION +* AL device supports the following ioctls +* 1. those meant strictly for the consumption of the proxy +* 2. those meant to denote an AL api and hence the call +* is further dispatched AL api and/or KAL internal interface +* +* SYNOPSIS +*/ +/* All verbs related ioctls */ +typedef enum _al_verbs_ops +{ + al_verbs_ops_start = al_proxy_maxops, + + ual_get_uvp_name_cmd = al_verbs_ops_start + 1, + ual_open_ca_ioctl_cmd, + ual_query_ca_ioctl_cmd, + ual_modify_ca_ioctl_cmd, + ual_close_ca_ioctl_cmd, + ual_ci_call_ioctl_cmd, + ual_alloc_pd_ioctl_cmd, + ual_dealloc_pd_ioctl_cmd, + ual_create_av_ioctl_cmd, + ual_query_av_ioctl_cmd, + ual_modify_av_ioctl_cmd, + ual_destroy_av_ioctl_cmd, + ual_create_srq_ioctl_cmd, + ual_query_srq_ioctl_cmd, + ual_modify_srq_ioctl_cmd, + ual_destroy_srq_ioctl_cmd, + ual_create_qp_ioctl_cmd, + ual_query_qp_ioctl_cmd, + ual_modify_qp_ioctl_cmd, + ual_destroy_qp_ioctl_cmd, + ual_create_cq_ioctl_cmd, + ual_query_cq_ioctl_cmd, + ual_modify_cq_ioctl_cmd, + ual_destroy_cq_ioctl_cmd, + ual_reg_mr_ioctl_cmd, + ual_query_mr_ioctl_cmd, + ual_rereg_mem_ioctl_cmd, + ual_reg_shared_ioctl_cmd, + ual_dereg_mr_ioctl_cmd, + ual_create_mw_ioctl_cmd, + ual_query_mw_ioctl_cmd, + ual_bind_mw_ioctl_cmd, + ual_destroy_mw_ioctl_cmd, + ual_post_send_ioctl_cmd, + ual_post_recv_ioctl_cmd, + ual_post_srq_recv_ioctl_cmd, + ual_peek_cq_ioctl_cmd, + ual_poll_cq_ioctl_cmd, + ual_rearm_cq_ioctl_cmd, + ual_rearm_n_cq_ioctl_cmd, + ual_attach_mcast_ioctl_cmd, + ual_detach_mcast_ioctl_cmd, + ual_get_spl_qp_cmd, + + al_verbs_maxops + +} al_verbs_ops_t; + +#define AL_VERBS_OPS_START IOCTL_CODE(ALDEV_KEY, al_verbs_ops_start) +#define AL_VERBS_MAXOPS IOCTL_CODE(ALDEV_KEY, al_verbs_maxops) +#define IS_VERBS_IOCTL(cmd) \ + ((cmd) > AL_VERBS_OPS_START && (cmd) < AL_VERBS_MAXOPS) + +/* All subnet management related ioctls */ + +typedef enum _al_subnet_ops +{ + al_subnet_ops_start = al_verbs_maxops, + + ual_reg_svc_cmd = al_subnet_ops_start + 1, + ual_dereg_svc_cmd, + ual_send_sa_req_cmd, + ual_cancel_sa_req_cmd, + ual_mad_send_cmd, + ual_mad_recv_cmd, + ual_init_dgram_svc_cmd, + ual_reg_mad_svc_cmd, + ual_dereg_mad_svc_cmd, + ual_reg_mad_pool_cmd, + ual_dereg_mad_pool_cmd, + ual_cancel_mad_cmd, + ual_mad_recv_comp_cmd, + ual_local_mad_cmd, + + al_subnet_maxops + +} al_subnet_ops_t; + +#define AL_SUBNET_OPS_START IOCTL_CODE(ALDEV_KEY, al_subnet_ops_start) +#define AL_SUBNET_MAXOPS IOCTL_CODE(ALDEV_KEY, al_subnet_maxops) +#define IS_SUBNET_IOCTL(cmd) \ + ((cmd) > AL_SUBNET_OPS_START && (cmd) < AL_SUBNET_MAXOPS) + +/* All ioc related ioctls */ + +typedef enum _al_ioc_ops +{ + al_ioc_ops_start = al_subnet_maxops, + + ual_create_ioc_cmd = al_ioc_ops_start + 1, + ual_destroy_ioc_cmd, + ual_reg_ioc_cmd, + ual_reject_ioc_cmd, + ual_add_svc_entry_cmd, + ual_remove_svc_entry_cmd, + ual_req_create_pdo, + ual_req_remove_pdo, + al_ioc_maxops, + +} al_ioc_ops_t; + +#define AL_IOC_OPS_START IOCTL_CODE(ALDEV_KEY, al_ioc_ops_start) +#define AL_IOC_MAXOPS IOCTL_CODE(ALDEV_KEY, al_ioc_maxops) +#define IS_IOC_IOCTL(cmd) \ + ((cmd) > AL_IOC_OPS_START && (cmd) < AL_IOC_MAXOPS) + +typedef enum _al_cm_sidr_ops +{ + al_cm_ops_start = al_ioc_maxops, + ual_cm_req_cmd = al_cm_ops_start + 1, + ual_cm_rep_cmd, + ual_cm_dreq_cmd, + ual_cm_drep_cmd, + ual_cm_listen_cmd, + ual_cm_cancel_cmd, + ual_cm_rtu_cmd, + ual_cm_rej_cmd, + ual_cm_handoff_cmd, + ual_cm_mra_cmd, + ual_cm_lap_cmd, + ual_cm_apr_cmd, + ual_force_apm_cmd, + ual_reg_sidr_cmd, + ual_sidr_req_cmd, + ual_sidr_rep_cmd, + + al_cm_maxops + +} al_cm_sidr_ops_t; + +#define AL_CM_OPS_START IOCTL_CODE(ALDEV_KEY, al_cm_ops_start) +#define AL_CM_MAXOPS IOCTL_CODE(ALDEV_KEY, al_cm_maxops) +#define IS_CM_IOCTL(cmd) \ + ((cmd) > AL_CM_OPS_START && (cmd) < AL_CM_MAXOPS) + + +typedef enum _ual_cep_ops +{ + al_cep_ops_start = al_ioc_maxops, + ual_create_cep, + ual_destroy_cep, + ual_cep_listen, + ual_cep_pre_req, + ual_cep_send_req, + ual_cep_pre_rep, + ual_cep_send_rep, + ual_cep_get_rtr, + ual_cep_get_rts, + ual_cep_rtu, + ual_cep_rej, + ual_cep_mra, + ual_cep_lap, + ual_cep_pre_apr, + ual_cep_send_apr, + ual_cep_dreq, + ual_cep_drep, + ual_cep_get_timewait, + ual_cep_get_event, + ual_cep_poll, + ual_cep_get_pdata, + + al_cep_maxops + +} ual_cep_ops_t; + +#define UAL_CEP_OPS_START IOCTL_CODE(ALDEV_KEY, al_cep_ops_start) +#define UAL_CEP_MAXOPS IOCTL_CODE(ALDEV_KEY, al_cep_maxops) +#define IS_CEP_IOCTL(cmd) \ + ((cmd) > UAL_CEP_OPS_START && (cmd) < UAL_CEP_MAXOPS) + + +/* AL ioctls */ + +typedef enum _al_dev_ops +{ + al_ops_start = al_cep_maxops, + + ual_reg_shmid_cmd, + ual_get_ca_attr, + ual_reg_pnp_cmd, + ual_poll_pnp_cmd, + ual_rearm_pnp_cmd, + ual_dereg_pnp_cmd, + + ual_access_flash, + + al_maxops + +} al_dev_ops_t; + +#define AL_OPS_START IOCTL_CODE(ALDEV_KEY, al_ops_start) +#define AL_MAXOPS IOCTL_CODE(ALDEV_KEY, al_maxops) + +#define IS_AL_IOCTL(cmd) \ + ((cmd) > AL_OPS_START && (cmd) < AL_MAXOPS) + +/* NDI ioctls */ + +typedef enum _al_ndi_ops +{ + al_ndi_ops_start = al_maxops, + + ual_ndi_create_cq_ioctl_cmd, + ual_ndi_notify_cq_ioctl_cmd, + ual_ndi_cancel_cq_ioctl_cmd, + ual_ndi_modify_qp_ioctl_cmd, + ual_ndi_req_cm_ioctl_cmd, + ual_ndi_rep_cm_ioctl_cmd, + ual_ndi_rtu_cm_ioctl_cmd, + ual_ndi_rej_cm_ioctl_cmd, + ual_ndi_dreq_cm_ioctl_cmd, + ual_ndi_noop, + ual_ndi_notify_dreq_cmd, + ual_ndi_cancel_cm_irps, + ual_ndi_listen_cm_cmd, + ual_ndi_get_req_cm_cmd, + + al_ndi_maxops + +} al_ndi_ops_t; + +typedef enum _al_ioc_device_config +{ + al_ioc_device_config_start = al_ndi_maxops, + ual_ioc_device_create, + ual_ioc_list, + al_ioc_device_config_maxops + +} al_ioc_device_config_t; + +#define AL_NDI_OPS_START IOCTL_CODE(ALDEV_KEY, al_ndi_ops_start) +#define AL_NDI_MAXOPS IOCTL_CODE(ALDEV_KEY, al_ndi_maxops) + +#define IS_NDI_IOCTL(cmd) \ + ((cmd) > AL_NDI_OPS_START && (cmd) < AL_NDI_MAXOPS) + +/* NDI Related ioctl commands */ +#define UAL_NDI_CREATE_CQ IOCTL_CODE(ALDEV_KEY, ual_ndi_create_cq_ioctl_cmd) +#define UAL_NDI_NOTIFY_CQ IOCTL_CODE(ALDEV_KEY, ual_ndi_notify_cq_ioctl_cmd) +#define UAL_NDI_CANCEL_CQ IOCTL_CODE(ALDEV_KEY, ual_ndi_cancel_cq_ioctl_cmd) +#define UAL_NDI_MODIFY_QP IOCTL_CODE(ALDEV_KEY, ual_ndi_modify_qp_ioctl_cmd) +#define UAL_NDI_REQ_CM IOCTL_CODE(ALDEV_KEY, ual_ndi_req_cm_ioctl_cmd) +#define UAL_NDI_REP_CM IOCTL_CODE(ALDEV_KEY, ual_ndi_rep_cm_ioctl_cmd) +#define UAL_NDI_RTU_CM IOCTL_CODE(ALDEV_KEY, ual_ndi_rtu_cm_ioctl_cmd) +#define UAL_NDI_REJ_CM IOCTL_CODE(ALDEV_KEY, ual_ndi_rej_cm_ioctl_cmd) +#define UAL_NDI_DREQ_CM IOCTL_CODE(ALDEV_KEY, ual_ndi_dreq_cm_ioctl_cmd) +#define UAL_NDI_NOOP IOCTL_CODE(ALDEV_KEY, ual_ndi_noop) +#define UAL_NDI_NOTIFY_DREQ IOCTL_CODE(ALDEV_KEY, ual_ndi_notify_dreq_cmd) +#define UAL_NDI_CANCEL_CM_IRPS IOCTL_CODE(ALDEV_KEY, ual_ndi_cancel_cm_irps) +#define UAL_NDI_LISTEN_CM IOCTL_CODE(ALDEV_KEY, ual_ndi_listen_cm_cmd) +#define UAL_NDI_GET_REQ_CM IOCTL_CODE(ALDEV_KEY, ual_ndi_get_req_cm_cmd) + +/* + * Various Operation Allowable on the System Helper + */ + +#define UAL_REG_SHMID IOCTL_CODE(ALDEV_KEY, ual_reg_shmid_cmd) +#define UAL_GET_VENDOR_LIBCFG IOCTL_CODE(ALDEV_KEY, ual_get_uvp_name_cmd) +#define UAL_OPEN_CA IOCTL_CODE(ALDEV_KEY, ual_open_ca_ioctl_cmd) +#define UAL_QUERY_CA IOCTL_CODE(ALDEV_KEY, ual_query_ca_ioctl_cmd) +#define UAL_MODIFY_CA IOCTL_CODE(ALDEV_KEY, ual_modify_ca_ioctl_cmd) +#define UAL_CLOSE_CA IOCTL_CODE(ALDEV_KEY, ual_close_ca_ioctl_cmd) +#define UAL_CI_CALL IOCTL_CODE(ALDEV_KEY, ual_ci_call_ioctl_cmd) +#define UAL_ALLOC_PD IOCTL_CODE(ALDEV_KEY, ual_alloc_pd_ioctl_cmd) +#define UAL_DEALLOC_PD IOCTL_CODE(ALDEV_KEY, ual_dealloc_pd_ioctl_cmd) +#define UAL_CREATE_AV IOCTL_CODE(ALDEV_KEY, ual_create_av_ioctl_cmd) +#define UAL_QUERY_AV IOCTL_CODE(ALDEV_KEY, ual_query_av_ioctl_cmd) +#define UAL_MODIFY_AV IOCTL_CODE(ALDEV_KEY, ual_modify_av_ioctl_cmd) +#define UAL_DESTROY_AV IOCTL_CODE(ALDEV_KEY, ual_destroy_av_ioctl_cmd) +#define UAL_CREATE_SRQ IOCTL_CODE(ALDEV_KEY, ual_create_srq_ioctl_cmd) +#define UAL_QUERY_SRQ IOCTL_CODE(ALDEV_KEY, ual_query_srq_ioctl_cmd) +#define UAL_MODIFY_SRQ IOCTL_CODE(ALDEV_KEY, ual_modify_srq_ioctl_cmd) +#define UAL_DESTROY_SRQ IOCTL_CODE(ALDEV_KEY, ual_destroy_srq_ioctl_cmd) +#define UAL_CREATE_QP IOCTL_CODE(ALDEV_KEY, ual_create_qp_ioctl_cmd) +#define UAL_QUERY_QP IOCTL_CODE(ALDEV_KEY, ual_query_qp_ioctl_cmd) +#define UAL_MODIFY_QP IOCTL_CODE(ALDEV_KEY, ual_modify_qp_ioctl_cmd) +#define UAL_DESTROY_QP IOCTL_CODE(ALDEV_KEY, ual_destroy_qp_ioctl_cmd) +#define UAL_CREATE_CQ IOCTL_CODE(ALDEV_KEY, ual_create_cq_ioctl_cmd) +#define UAL_QUERY_CQ IOCTL_CODE(ALDEV_KEY, ual_query_cq_ioctl_cmd) +#define UAL_MODIFY_CQ IOCTL_CODE(ALDEV_KEY, ual_modify_cq_ioctl_cmd) +#define UAL_DESTROY_CQ IOCTL_CODE(ALDEV_KEY, ual_destroy_cq_ioctl_cmd) +#define UAL_REG_MR IOCTL_CODE(ALDEV_KEY, ual_reg_mr_ioctl_cmd) +#define UAL_QUERY_MR IOCTL_CODE(ALDEV_KEY, ual_query_mr_ioctl_cmd) +#define UAL_MODIFY_MR IOCTL_CODE(ALDEV_KEY, ual_rereg_mem_ioctl_cmd) +#define UAL_REG_SHARED IOCTL_CODE(ALDEV_KEY, ual_reg_shared_ioctl_cmd) +#define UAL_DEREG_MR IOCTL_CODE(ALDEV_KEY, ual_dereg_mr_ioctl_cmd) +#define UAL_CREATE_MW IOCTL_CODE(ALDEV_KEY, ual_create_mw_ioctl_cmd) +#define UAL_QUERY_MW IOCTL_CODE(ALDEV_KEY, ual_query_mw_ioctl_cmd) +#define UAL_BIND_MW IOCTL_CODE(ALDEV_KEY, ual_bind_mw_ioctl_cmd) +#define UAL_DESTROY_MW IOCTL_CODE(ALDEV_KEY, ual_destroy_mw_ioctl_cmd) +#define UAL_POST_SEND IOCTL_CODE(ALDEV_KEY, ual_post_send_ioctl_cmd) +#define UAL_POST_RECV IOCTL_CODE(ALDEV_KEY, ual_post_recv_ioctl_cmd) +#define UAL_POST_SRQ_RECV IOCTL_CODE(ALDEV_KEY, ual_post_srq_recv_ioctl_cmd) +#define UAL_PEEK_CQ IOCTL_CODE(ALDEV_KEY, ual_peek_cq_ioctl_cmd) +#define UAL_POLL_CQ IOCTL_CODE(ALDEV_KEY, ual_poll_cq_ioctl_cmd) +#define UAL_REARM_CQ IOCTL_CODE(ALDEV_KEY, ual_rearm_cq_ioctl_cmd) +#define UAL_REARM_N_CQ IOCTL_CODE(ALDEV_KEY, ual_rearm_n_cq_ioctl_cmd) +#define UAL_ATTACH_MCAST IOCTL_CODE(ALDEV_KEY, ual_attach_mcast_ioctl_cmd) +#define UAL_DETACH_MCAST IOCTL_CODE(ALDEV_KEY, ual_detach_mcast_ioctl_cmd) + +/* Subnet management related ioctl commands */ +#define UAL_REG_SVC IOCTL_CODE(ALDEV_KEY, ual_reg_svc_cmd) +#define UAL_DEREG_SVC IOCTL_CODE(ALDEV_KEY, ual_dereg_svc_cmd) +#define UAL_SEND_SA_REQ IOCTL_CODE(ALDEV_KEY, ual_send_sa_req_cmd) +#define UAL_CANCEL_SA_REQ IOCTL_CODE(ALDEV_KEY, ual_cancel_sa_req_cmd) +#define UAL_MAD_SEND IOCTL_CODE(ALDEV_KEY, ual_mad_send_cmd) +#define UAL_INIT_DGRM_SVC IOCTL_CODE(ALDEV_KEY, ual_init_dgram_svc_cmd) +#define UAL_REG_MAD_SVC IOCTL_CODE(ALDEV_KEY, ual_reg_mad_svc_cmd) +#define UAL_DEREG_MAD_SVC IOCTL_CODE(ALDEV_KEY, ual_dereg_mad_svc_cmd) +#define UAL_REG_MAD_POOL IOCTL_CODE(ALDEV_KEY, ual_reg_mad_pool_cmd) +#define UAL_DEREG_MAD_POOL IOCTL_CODE(ALDEV_KEY, ual_dereg_mad_pool_cmd) +#define UAL_CANCEL_MAD IOCTL_CODE(ALDEV_KEY, ual_cancel_mad_cmd) +#define UAL_GET_SPL_QP_ALIAS IOCTL_CODE(ALDEV_KEY, ual_get_spl_qp_cmd) +#define UAL_MAD_RECV_COMP IOCTL_CODE(ALDEV_KEY, ual_mad_recv_comp_cmd) +#define UAL_LOCAL_MAD IOCTL_CODE(ALDEV_KEY, ual_local_mad_cmd) + +/* CM Related ioctl commands */ +#define UAL_CM_LISTEN IOCTL_CODE(ALDEV_KEY, ual_cm_listen_cmd) +#define UAL_CM_CANCEL IOCTL_CODE(ALDEV_KEY, ual_cm_cancel_cmd) +#define UAL_CM_REQ IOCTL_CODE(ALDEV_KEY, ual_cm_req_cmd) +#define UAL_CM_REP IOCTL_CODE(ALDEV_KEY, ual_cm_rep_cmd) +#define UAL_CM_RTU IOCTL_CODE(ALDEV_KEY, ual_cm_rtu_cmd) +#define UAL_CM_REJ IOCTL_CODE(ALDEV_KEY, ual_cm_rej_cmd) +#define UAL_CM_HANDOFF IOCTL_CODE(ALDEV_KEY, ual_cm_handoff_cmd) +#define UAL_CM_DREQ IOCTL_CODE(ALDEV_KEY, ual_cm_dreq_cmd) +#define UAL_CM_DREP IOCTL_CODE(ALDEV_KEY, ual_cm_drep_cmd) +#define UAL_CM_MRA IOCTL_CODE(ALDEV_KEY, ual_cm_mra_cmd) +#define UAL_CM_LAP IOCTL_CODE(ALDEV_KEY, ual_cm_lap_cmd) +#define UAL_CM_APR IOCTL_CODE(ALDEV_KEY, ual_cm_apr_cmd) +#define UAL_CM_FORCE_APM IOCTL_CODE(ALDEV_KEY, ual_force_apm_cmd) + +/* CEP Related IOCTL commands */ +#define UAL_CREATE_CEP IOCTL_CODE(ALDEV_KEY, ual_create_cep) +#define UAL_DESTROY_CEP IOCTL_CODE(ALDEV_KEY, ual_destroy_cep) +#define UAL_CEP_LISTEN IOCTL_CODE(ALDEV_KEY, ual_cep_listen) +#define UAL_CEP_PRE_REQ IOCTL_CODE(ALDEV_KEY, ual_cep_pre_req) +#define UAL_CEP_SEND_REQ IOCTL_CODE(ALDEV_KEY, ual_cep_send_req) +#define UAL_CEP_PRE_REP IOCTL_CODE(ALDEV_KEY, ual_cep_pre_rep) +#define UAL_CEP_SEND_REP IOCTL_CODE(ALDEV_KEY, ual_cep_send_rep) +#define UAL_CEP_GET_RTR IOCTL_CODE(ALDEV_KEY, ual_cep_get_rtr) +#define UAL_CEP_GET_RTS IOCTL_CODE(ALDEV_KEY, ual_cep_get_rts) +#define UAL_CEP_RTU IOCTL_CODE(ALDEV_KEY, ual_cep_rtu) +#define UAL_CEP_REJ IOCTL_CODE(ALDEV_KEY, ual_cep_rej) +#define UAL_CEP_MRA IOCTL_CODE(ALDEV_KEY, ual_cep_mra) +#define UAL_CEP_LAP IOCTL_CODE(ALDEV_KEY, ual_cep_lap) +#define UAL_CEP_PRE_APR IOCTL_CODE(ALDEV_KEY, ual_cep_pre_apr) +#define UAL_CEP_SEND_APR IOCTL_CODE(ALDEV_KEY, ual_cep_send_apr) +#define UAL_CEP_DREQ IOCTL_CODE(ALDEV_KEY, ual_cep_dreq) +#define UAL_CEP_DREP IOCTL_CODE(ALDEV_KEY, ual_cep_drep) +#define UAL_CEP_GET_TIMEWAIT IOCTL_CODE(ALDEV_KEY, ual_cep_get_timewait) +#define UAL_CEP_GET_EVENT IOCTL_CODE(ALDEV_KEY, ual_cep_get_event) +#define UAL_CEP_POLL IOCTL_CODE(ALDEV_KEY, ual_cep_poll) +#define UAL_CEP_GET_PDATA IOCTL_CODE(ALDEV_KEY, ual_cep_get_pdata) + + +#define UAL_GET_CA_ATTR_INFO IOCTL_CODE(ALDEV_KEY, ual_get_ca_attr) +#define UAL_REQ_CREATE_PDO IOCTL_CODE(ALDEV_KEY, ual_req_create_pdo) +#define UAL_REQ_REMOVE_PDO IOCTL_CODE(ALDEV_KEY, ual_req_remove_pdo) + +/* PnP related ioctl commands. */ +#define UAL_REG_PNP IOCTL_CODE(ALDEV_KEY, ual_reg_pnp_cmd) +#define UAL_POLL_PNP IOCTL_CODE(ALDEV_KEY, ual_poll_pnp_cmd) +#define UAL_REARM_PNP IOCTL_CODE(ALDEV_KEY, ual_rearm_pnp_cmd) +#define UAL_DEREG_PNP IOCTL_CODE(ALDEV_KEY, ual_dereg_pnp_cmd) +#define UAL_ACCESS_FLASH IOCTL_CODE(ALDEV_KEY, ual_access_flash) + +#define AL_IOC_DEVICE_CONFIG_START IOCTL_CODE(ALDEV_KEY, al_ioc_device_config_start) +#define AL_IOC_DEVICE_CONFIG_MAXOPS IOCTL_CODE(ALDEV_KEY, al_ioc_device_config_maxops) + +#define IS_IOC_DEVICE_CONFIG_IOCTL(cmd) \ + ((cmd) > AL_IOC_DEVICE_CONFIG_START && (cmd) < AL_IOC_DEVICE_CONFIG_MAXOPS) + +#define UAL_IOC_DEVICE_CREATE IOCTL_CODE(ALDEV_KEY, ual_ioc_device_create) +#define UAL_IOC_LIST IOCTL_CODE(ALDEV_KEY, ual_ioc_list) + +#endif /* _AL_DEV_H_ */ diff --git a/branches/WOF2-3/core/al/al_dm.c b/branches/WOF2-3/core/al/al_dm.c new file mode 100644 index 00000000..29815a5d --- /dev/null +++ b/branches/WOF2-3/core/al/al_dm.c @@ -0,0 +1,1800 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include "al_ca.h" +#include "al_debug.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "al_dm.tmh" +#endif + +#include "al_dm.h" +#include "al_mgr.h" +#include "ib_common.h" + + +/* + * This code implements a minimal device management agent. + */ + + +static dm_agent_t* gp_dm_agent = NULL; + + +#define SVC_REG_TIMEOUT 2000 // Milliseconds +#define SVC_REG_RETRY_CNT 3 +#define DM_CLASS_RESP_TIME_VALUE 20 + + +#define SET_NIBBLE( nibble_array, nibble_num, value ) \ +{ \ + ((uint8_t*)(nibble_array))[(nibble_num) >> 1] = (uint8_t) \ + ((((nibble_num) & 1) == 0) ? \ + ((uint8_t*)(nibble_array))[(nibble_num) >> 1] & 0x0f : \ + ((uint8_t*)(nibble_array))[(nibble_num) >> 1] & 0xf0); \ + ((uint8_t*)(nibble_array))[(nibble_num) >> 1] |= \ + ( ((nibble_num) & 1) == 0) ? ((value) << 4) : ((value) & 0x0f); \ +} + + +void +free_ioc( + IN al_obj_t* p_obj ); + +void +free_svc_entry( + IN al_obj_t* p_obj ); + +al_iou_t* +acquire_iou( + IN const ib_net64_t ca_guid ); + +al_iou_t* +get_iou( + IN const ib_ioc_handle_t h_ioc ); + +ib_ioc_handle_t +get_ioc( + IN const ib_ca_handle_t h_ca ); + +ib_api_status_t +add_ioc( + IN al_iou_t* p_iou, + IN ib_ioc_handle_t h_ioc ); + +void +ioc_change( + IN ib_ioc_handle_t h_ioc ); + +void +iou_change( + IN al_iou_t* p_iou ); + +ib_api_status_t +set_port_dm_attr( + IN al_iou_port_t* p_iou_port ); + +void +iou_port_svc_reg_cb( + IN ib_reg_svc_rec_t* p_reg_svc_rec ); + +void +destroying_dm_agent( + IN al_obj_t* p_obj ); + +void +free_dm_agent( + IN al_obj_t* p_obj ); + +ib_api_status_t +dm_agent_reg_pnp( + IN ib_pnp_class_t pnp_class, + IN ib_pnp_handle_t * ph_pnp ); + +ib_api_status_t +dm_agent_pnp_cb( + IN ib_pnp_rec_t* p_pnp_rec ); + +ib_api_status_t +create_iou( + IN ib_pnp_rec_t* p_pnp_rec ); + +void +cleanup_iou( + IN al_obj_t* p_obj ); + +void +free_iou( + IN al_obj_t* p_obj ); + +ib_api_status_t +create_iou_port( + IN ib_pnp_port_rec_t* p_pnp_rec ); + +void +destroying_iou_port( + IN al_obj_t* p_obj ); + +void +free_iou_port( + IN al_obj_t* p_obj ); + +void +iou_port_event_cb( + IN ib_async_event_rec_t *p_event_rec ); + +void +dm_agent_send_cb( + IN ib_mad_svc_handle_t h_mad_svc, + IN void* mad_svc_context, + IN ib_mad_element_t* p_mad_response ); + +void +dm_agent_recv_cb( + IN ib_mad_svc_handle_t h_mad_svc, + IN void* mad_svc_context, + IN ib_mad_element_t* p_mad_request ); + +void +dm_agent_get( + IN al_iou_port_t* p_iou_port, + IN ib_mad_t* p_mad_req, + IN ib_mad_t* p_mad_rsp ); + +void +dm_agent_set( + IN al_iou_port_t* p_iou_port, + IN ib_mad_t* p_mad_req, + IN ib_mad_t* p_mad_rsp ); + +void +get_class_port_info( + IN al_iou_t* p_iou, + IN ib_dm_mad_t* p_dm_mad ); + +void +get_io_unit_info( + IN al_iou_t* p_iou, + IN ib_dm_mad_t* p_dm_mad ); + +void +get_ioc_profile( + IN al_iou_t* p_iou, + IN uint8_t slot, + IN ib_dm_mad_t* p_dm_mad ); + +void +get_svc_entries( + IN al_iou_t* p_iou, + IN uint8_t slot, + IN uint8_t svc_num_lo, + IN uint8_t svc_num_hi, + IN ib_dm_mad_t* p_dm_mad ); + + + + +ib_api_status_t +ib_create_ioc( + IN const ib_ca_handle_t h_ca, + IN const ib_ioc_profile_t* const p_ioc_profile, + OUT ib_ioc_handle_t* const ph_ioc ) +{ + ib_ioc_handle_t h_ioc; + + AL_ENTER( AL_DBG_IOC ); + + if( AL_OBJ_INVALID_HANDLE( h_ca, AL_OBJ_TYPE_H_CA ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_CA_HANDLE\n") ); + return IB_INVALID_CA_HANDLE; + } + if( !p_ioc_profile || !ph_ioc ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + /* Get an IOC. */ + h_ioc = get_ioc( h_ca ); + if( !h_ioc ) + return IB_INSUFFICIENT_MEMORY; + + /* Save the IOC profile. */ + cl_memcpy( &h_ioc->ioc_profile, p_ioc_profile, sizeof(ib_ioc_profile_t) ); + + /* Clear the service entry count. */ + h_ioc->ioc_profile.num_svc_entries = 0; + + /* Return the IOC handle to the user. */ + *ph_ioc = h_ioc; + + AL_EXIT( AL_DBG_IOC ); + return IB_SUCCESS; +} + + + +ib_api_status_t +ib_destroy_ioc( + IN const ib_ioc_handle_t h_ioc ) +{ + AL_ENTER( AL_DBG_IOC ); + + if( AL_OBJ_INVALID_HANDLE( h_ioc, AL_OBJ_TYPE_H_IOC ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_HANDLE\n") ); + return IB_INVALID_HANDLE; + } + + ref_al_obj( &h_ioc->obj ); + h_ioc->obj.pfn_destroy( &h_ioc->obj, NULL ); + + AL_EXIT( AL_DBG_IOC ); + return IB_SUCCESS; +} + + + +/* + * Free an IOC. + */ +void +free_ioc( + IN al_obj_t* p_obj ) +{ + ib_ioc_handle_t h_ioc; + + CL_ASSERT( p_obj ); + + h_ioc = PARENT_STRUCT( p_obj, al_ioc_t, obj ); + + /* + * To maintain slot ordering, IOCs attached to an IO unit are freed when + * the IO unit is destroyed. Otherwise, unattached IOCs may be freed now. + */ + if( h_ioc->p_iou ) + { + /* Mark the IOC slot as empty. */ + h_ioc->state = EMPTY_SLOT; + reset_al_obj( p_obj ); + deref_al_obj( &h_ioc->p_iou->obj ); + + /* Report that a change occurred on the IOC. */ + ioc_change( h_ioc ); + } + else + { + /* Unattached IOCs can be destroyed. */ + destroy_al_obj( p_obj ); + cl_free( h_ioc ); + } +} + + + +ib_api_status_t +ib_reg_ioc( + IN const ib_ioc_handle_t h_ioc ) +{ + al_iou_t* p_iou; + ib_api_status_t status; + + AL_ENTER( AL_DBG_IOC ); + + if( AL_OBJ_INVALID_HANDLE( h_ioc, AL_OBJ_TYPE_H_IOC ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_HANDLE\n") ); + return IB_INVALID_HANDLE; + } + + /* Get an IO unit for this IOC. */ + p_iou = get_iou( h_ioc ); + if( !p_iou ) + return IB_INSUFFICIENT_MEMORY; + + /* Register the IOC with the IO unit. */ + status = add_ioc( p_iou, h_ioc ); + + AL_EXIT( AL_DBG_IOC ); + return status; +} + + + +ib_api_status_t +ib_add_svc_entry( + IN const ib_ioc_handle_t h_ioc, + IN const ib_svc_entry_t* const p_svc_entry, + OUT ib_svc_handle_t* const ph_svc ) +{ + ib_svc_handle_t h_svc; + ib_api_status_t status; + + AL_ENTER( AL_DBG_IOC ); + + if( AL_OBJ_INVALID_HANDLE( h_ioc, AL_OBJ_TYPE_H_IOC ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_HANDLE\n") ); + return IB_INVALID_HANDLE; + } + if( !p_svc_entry || !ph_svc ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + /* + * Synchronize the addition of a service entry with the removal. + * Cannot hold a lock on the IOC when attaching a service entry + * object. Wait here until the IOC is no longer in use. + */ + cl_spinlock_acquire( &h_ioc->obj.lock ); + while( h_ioc->in_use_cnt ) + { + cl_spinlock_release( &h_ioc->obj.lock ); + cl_thread_suspend( 0 ); + cl_spinlock_acquire( &h_ioc->obj.lock ); + } + /* Flag the IOC as in use by this thread. */ + cl_atomic_inc( &h_ioc->in_use_cnt ); + cl_spinlock_release( &h_ioc->obj.lock ); + + /* Check the current service entry count. */ + if( h_ioc->ioc_profile.num_svc_entries == MAX_NUM_SVC_ENTRIES ) + { + cl_spinlock_release( &h_ioc->obj.lock ); + AL_EXIT( AL_DBG_IOC ); + return IB_INSUFFICIENT_RESOURCES; + } + h_svc = cl_zalloc( sizeof( ib_svc_handle_t ) ); + if( !h_svc ) + { + AL_EXIT( AL_DBG_IOC ); + return IB_INSUFFICIENT_MEMORY; + } + + /* Construct the service entry. */ + construct_al_obj( &h_svc->obj, AL_OBJ_TYPE_H_SVC_ENTRY ); + + /* Save the service entry. */ + cl_memcpy( &h_svc->svc_entry, p_svc_entry, sizeof( ib_svc_entry_t ) ); + + /* Initialize the service entry object. */ + status = init_al_obj( &h_svc->obj, h_svc, FALSE, NULL, NULL, + free_svc_entry ); + if( status != IB_SUCCESS ) + { + free_svc_entry( &h_svc->obj ); + AL_EXIT( AL_DBG_IOC ); + return status; + } + + /* Attach the service entry to the IOC. */ + status = attach_al_obj( &h_ioc->obj, &h_svc->obj ); + if( status != IB_SUCCESS ) + { + h_svc->obj.pfn_destroy( &h_svc->obj, NULL ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("attach_al_obj returned %s.\n", ib_get_err_str(status)) ); + return status; + } + + h_ioc->ioc_profile.num_svc_entries++; + + /* Indicate that a change occured on the IOC. */ + ioc_change( h_ioc ); + + /* No longer in use by this thread. */ + cl_atomic_dec( &h_ioc->in_use_cnt ); + + /* Return the service entry handle to the user. */ + *ph_svc = h_svc; + + /* Release the reference taken in init_al_obj. */ + deref_al_obj( &h_svc->obj ); + + AL_EXIT( AL_DBG_IOC ); + return IB_SUCCESS; +} + + + +ib_api_status_t +ib_remove_svc_entry( + IN const ib_svc_handle_t h_svc ) +{ + ib_ioc_handle_t h_ioc; + + AL_ENTER( AL_DBG_IOC ); + + if( AL_OBJ_INVALID_HANDLE( h_svc, AL_OBJ_TYPE_H_SVC_ENTRY ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_HANDLE\n") ); + return IB_INVALID_HANDLE; + } + + h_ioc = PARENT_STRUCT( h_svc->obj.p_parent_obj, al_ioc_t, obj ); + + /* + * Synchronize the removal of a service entry with the addition. + * Cannot hold a lock on the IOC when detaching a service entry + * object. Wait here until the IOC is no longer in use. + */ + cl_spinlock_acquire( &h_ioc->obj.lock ); + while( h_ioc->in_use_cnt ) + { + cl_spinlock_release( &h_ioc->obj.lock ); + cl_thread_suspend( 0 ); + cl_spinlock_acquire( &h_ioc->obj.lock ); + } + /* Flag the IOC as in use by this thread. */ + cl_atomic_inc( &h_ioc->in_use_cnt ); + cl_spinlock_release( &h_ioc->obj.lock ); + + /* + * Synchronously destroy the service entry. + * The service handle is invalid when this call returns. + */ + ref_al_obj( &h_svc->obj ); + h_svc->obj.pfn_destroy( &h_svc->obj, NULL ); + + /* Decrement the service entry count. */ + h_ioc->ioc_profile.num_svc_entries--; + + /* Indicate that a change occured on the IOC. */ + ioc_change( h_ioc ); + + /* No longer in use by this thread. */ + cl_atomic_dec( &h_ioc->in_use_cnt ); + + AL_EXIT( AL_DBG_IOC ); + return IB_SUCCESS; +} + + + +/* + * Free a service entry. + */ +void +free_svc_entry( + IN al_obj_t* p_obj ) +{ + ib_svc_handle_t h_svc; + + CL_ASSERT( p_obj ); + h_svc = PARENT_STRUCT( p_obj, al_svc_entry_t, obj ); + + destroy_al_obj( &h_svc->obj ); + cl_free( h_svc ); +} + + + +/* + * Acquire the IO unit matching the given CA GUID. + */ +al_iou_t* +acquire_iou( + IN const ib_net64_t ca_guid ) +{ + cl_list_item_t* p_iou_item; + al_obj_t* p_obj; + al_iou_t* p_iou; + + /* Search for an existing IO unit matching the CA GUID. */ + cl_spinlock_acquire( &gp_dm_agent->obj.lock ); + for( p_iou_item = cl_qlist_head( &gp_dm_agent->obj.obj_list ); + p_iou_item != cl_qlist_end( &gp_dm_agent->obj.obj_list ); + p_iou_item = cl_qlist_next( p_iou_item ) ) + { + p_obj = PARENT_STRUCT( p_iou_item, al_obj_t, pool_item ); + p_iou = PARENT_STRUCT( p_obj, al_iou_t, obj ); + + /* Check for a GUID match. */ + if( p_iou->obj.p_ci_ca->verbs.guid == ca_guid ) + { + /* Reference the IO unit on behalf of the client. */ + ref_al_obj( &p_iou->obj ); + + cl_spinlock_release( &gp_dm_agent->obj.lock ); + return p_iou; + } + } + cl_spinlock_release( &gp_dm_agent->obj.lock ); + + return NULL; +} + + + +/* + * Get the IO unit for the given IOC. + */ +al_iou_t* +get_iou( + IN const ib_ioc_handle_t h_ioc ) +{ + CL_ASSERT( h_ioc ); + + /* Check if the IOC is already attached to an IO unit. */ + if( h_ioc->p_iou ) + return h_ioc->p_iou; + + /* The IOC is a new slot. Acquire the IO unit. */ + return acquire_iou( h_ioc->obj.p_ci_ca->verbs.guid ); +} + + + +ib_ioc_handle_t +get_ioc( + IN const ib_ca_handle_t h_ca ) +{ + cl_list_item_t* p_ioc_item; + al_iou_t* p_iou; + ib_ioc_handle_t h_ioc; + boolean_t found; + ib_api_status_t status; + + found = FALSE; + h_ioc = NULL; + + /* Acquire the IO unit. */ + p_iou = acquire_iou( h_ca->obj.p_ci_ca->verbs.guid ); + + if( p_iou ) + { + /* Search for an empty IOC slot in the IO unit. */ + cl_spinlock_acquire( &p_iou->obj.lock ); + for( p_ioc_item = cl_qlist_head( &p_iou->ioc_list ); + (p_ioc_item != cl_qlist_end( &p_iou->ioc_list )) && !found; + p_ioc_item = cl_qlist_next( p_ioc_item ) ) + { + h_ioc = PARENT_STRUCT( p_ioc_item, al_ioc_t, iou_item ); + + if( h_ioc->state == EMPTY_SLOT ) + { + /* + * An empty slot was found. + * Change the state to indicate that the slot is in use. + */ + h_ioc->state = SLOT_IN_USE; + found = TRUE; + } + } + cl_spinlock_release( &p_iou->obj.lock ); + } + + /* Allocate a new IOC if one was not found. */ + if( !found ) + { + h_ioc = cl_zalloc( sizeof( al_ioc_t ) ); + if( !h_ioc ) + return NULL; + + /* Construct the IOC. */ + construct_al_obj( &h_ioc->obj, AL_OBJ_TYPE_H_IOC ); + + /* Initialize the IOC object. */ + status = + init_al_obj( &h_ioc->obj, h_ioc, FALSE, NULL, NULL, free_ioc ); + if( status != IB_SUCCESS ) + { + free_ioc( &h_ioc->obj ); + return NULL; + } + } + + /* Attach the IOC to the CA. */ + status = attach_al_obj( &h_ca->obj, &h_ioc->obj ); + if( status != IB_SUCCESS ) + { + h_ioc->obj.pfn_destroy( &h_ioc->obj, NULL ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("attach_al_obj returned %s.\n", ib_get_err_str(status)) ); + return NULL; + } + + /* Release the reference taken in init_al_obj. */ + deref_al_obj( &h_ioc->obj ); + + return h_ioc; +} + + + +ib_api_status_t +add_ioc( + IN al_iou_t* p_iou, + IN ib_ioc_handle_t h_ioc ) +{ + cl_list_item_t* p_list_item; + al_obj_t* p_obj; + al_iou_port_t* p_iou_port; + ib_api_status_t status; + + CL_ASSERT( p_iou ); + CL_ASSERT( h_ioc ); + + /* Attach the IOC to the IO unit. */ + if( !h_ioc->p_iou ) + { + cl_spinlock_acquire( &p_iou->obj.lock ); + + /* Make sure the IO unit can support the new IOC slot. */ + if( cl_qlist_count( &p_iou->ioc_list ) >= + ( sizeof( ((ib_iou_info_t*)0)->controller_list ) - 1) ) + { + cl_spinlock_release( &p_iou->obj.lock ); + deref_al_obj( &p_iou->obj ); + return IB_INSUFFICIENT_RESOURCES; + } + + /* Add a new IOC slot to the IO unit. */ + cl_qlist_insert_tail( &p_iou->ioc_list, &h_ioc->iou_item ); + h_ioc->p_iou = p_iou; + + cl_spinlock_release( &p_iou->obj.lock ); + } + else + { + /* The IOC is being added to an empty IO unit slot. */ + CL_ASSERT( h_ioc->p_iou == p_iou ); + CL_ASSERT( h_ioc->state == SLOT_IN_USE ); + } + + /* Enable the IOC. */ + h_ioc->state = IOC_ACTIVE; + + /* Indicate that a change occured on the IO unit. */ + iou_change( p_iou ); + + /* Flag each port on the IO unit CA as supporting device management. */ + status = IB_SUCCESS; + cl_spinlock_acquire( &p_iou->obj.lock ); + for( p_list_item = cl_qlist_head( &p_iou->obj.obj_list ); + p_list_item != cl_qlist_end( &p_iou->obj.obj_list ); + p_list_item = cl_qlist_next( p_list_item ) ) + { + p_obj = PARENT_STRUCT( p_list_item, al_obj_t, pool_item ); + p_iou_port = PARENT_STRUCT( p_obj, al_iou_port_t, obj ); + + status = set_port_dm_attr( p_iou_port ); + if( status != IB_SUCCESS ) break; + } + cl_spinlock_release( &p_iou->obj.lock ); + + if( status != IB_SUCCESS ) + h_ioc->state = SLOT_IN_USE; + + return status; +} + + + +void +ioc_change( + IN ib_ioc_handle_t h_ioc ) +{ + CL_ASSERT( h_ioc ); + + /* Report a change to the IO unit which the IOC is attached. */ + if( h_ioc->p_iou ) iou_change( h_ioc->p_iou ); +} + + + +void +iou_change( + IN al_iou_t* p_iou ) +{ + CL_ASSERT( p_iou ); + + /* Increment the IO unit change counter. */ + cl_spinlock_acquire( &p_iou->obj.lock ); + p_iou->change_id++; + cl_spinlock_release( &p_iou->obj.lock ); +} + + + +ib_api_status_t +set_port_dm_attr( + IN al_iou_port_t* p_iou_port ) +{ + ib_port_attr_mod_t port_attr_mod; + ib_reg_svc_req_t reg_svc_req; + ib_api_status_t status; + + CL_ASSERT( p_iou_port ); + + /* Initialize a port attribute modification structure. */ + cl_memclr( &port_attr_mod, sizeof( ib_port_attr_mod_t ) ); + port_attr_mod.cap.dev_mgmt = TRUE; + + /* Flag each port on the IO unit CA as supporting device management. */ + status = ib_modify_ca( p_iou_port->obj.p_ci_ca->h_ca, p_iou_port->port_num, + IB_CA_MOD_IS_DEV_MGMT_SUPPORTED, &port_attr_mod ); + + if( status != IB_SUCCESS ) + return status; + + /* The register a service with the SA if one is needed. */ + if( !p_iou_port->svc_handle ) + { + /* Build the service registration request. */ + cl_memclr( ®_svc_req, sizeof( ib_reg_svc_req_t ) ); + + reg_svc_req.svc_rec.service_lease = 0xffffffff; + strncpy( (char*)reg_svc_req.svc_rec.service_name, DM_SVC_NAME, + sizeof( reg_svc_req.svc_rec.service_name ) ); + reg_svc_req.svc_rec.service_gid = p_iou_port->port_gid; + reg_svc_req.port_guid = p_iou_port->port_guid; + + reg_svc_req.timeout_ms = SVC_REG_TIMEOUT; + reg_svc_req.retry_cnt = SVC_REG_RETRY_CNT; + reg_svc_req.svc_context = p_iou_port; + reg_svc_req.pfn_reg_svc_cb = iou_port_svc_reg_cb; + reg_svc_req.svc_data_mask = IB_SR_COMPMASK_SGID | + IB_SR_COMPMASK_SPKEY | + IB_SR_COMPMASK_SLEASE | + IB_SR_COMPMASK_SNAME; + + /* Reference the IO unit port on behalf of the ib_reg_svc call. */ + ref_al_obj( &p_iou_port->obj ); + + status = ib_reg_svc( gh_al, ®_svc_req, &p_iou_port->svc_handle ); + + if( status != IB_SUCCESS ) + { + deref_al_obj( &p_iou_port->obj ); + + /* Ignore this error - the SM will sweep port attribute changes. */ + status = IB_SUCCESS; + } + } + + return status; +} + + + +void +iou_port_svc_reg_cb( + IN ib_reg_svc_rec_t* p_reg_svc_rec ) +{ + al_iou_port_t* p_iou_port; + + CL_ASSERT( p_reg_svc_rec ); + + p_iou_port = (al_iou_port_t*)p_reg_svc_rec->svc_context; + + if( p_reg_svc_rec->req_status != IB_SUCCESS ) + deref_al_obj( &p_iou_port->obj ); +} + + +/* + * Device Management Agent + */ + + +/* + * Create the device management agent. + */ +ib_api_status_t +create_dm_agent( + IN al_obj_t* const p_parent_obj ) +{ + cl_status_t cl_status; + ib_api_status_t status; + + CL_ASSERT( p_parent_obj ); + CL_ASSERT( !gp_dm_agent ); + + gp_dm_agent = cl_zalloc( sizeof( dm_agent_t ) ); + if( !gp_dm_agent ) + return IB_INSUFFICIENT_MEMORY; + + /* Construct the device management agent. */ + construct_al_obj( &gp_dm_agent->obj, AL_OBJ_TYPE_DM ); + cl_spinlock_construct( &gp_dm_agent->lock ); + + cl_status = cl_spinlock_init( &gp_dm_agent->lock ); + if( cl_status != CL_SUCCESS ) + { + free_dm_agent( &gp_dm_agent->obj ); + return ib_convert_cl_status( cl_status ); + } + + /* Initialize the device management agent object. */ + status = init_al_obj( &gp_dm_agent->obj, gp_dm_agent, TRUE, + destroying_dm_agent, NULL, free_dm_agent ); + if( status != IB_SUCCESS ) + { + free_dm_agent( &gp_dm_agent->obj ); + return status; + } + + /* Attach the device management agent to the parent object. */ + status = attach_al_obj( p_parent_obj, &gp_dm_agent->obj ); + if( status != IB_SUCCESS ) + { + gp_dm_agent->obj.pfn_destroy( &gp_dm_agent->obj, NULL ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("attach_al_obj returned %s.\n", ib_get_err_str(status)) ); + return status; + } + + /* Register for CA PnP events. */ + status = dm_agent_reg_pnp( IB_PNP_CA, &gp_dm_agent->h_ca_pnp ); + if (status != IB_SUCCESS) + { + gp_dm_agent->obj.pfn_destroy( &gp_dm_agent->obj, NULL ); + return status; + } + + /* Register for port PnP events. */ + status = dm_agent_reg_pnp( IB_PNP_PORT, &gp_dm_agent->h_port_pnp ); + if (status != IB_SUCCESS) + { + gp_dm_agent->obj.pfn_destroy( &gp_dm_agent->obj, NULL ); + return status; + } + + /* Release the reference taken in init_al_obj. */ + deref_al_obj( &gp_dm_agent->obj ); + + return IB_SUCCESS; +} + + + +/* + * Pre-destroy the device management agent. + */ +void +destroying_dm_agent( + IN al_obj_t* p_obj ) +{ + ib_api_status_t status; + + CL_ASSERT( p_obj ); + CL_ASSERT( gp_dm_agent == PARENT_STRUCT( p_obj, dm_agent_t, obj ) ); + UNUSED_PARAM( p_obj ); + + /* Mark that we're destroying the agent. */ + cl_spinlock_acquire( &gp_dm_agent->lock ); + gp_dm_agent->destroying = TRUE; + cl_spinlock_release( &gp_dm_agent->lock ); + + /* Deregister for port PnP events. */ + if( gp_dm_agent->h_port_pnp ) + { + status = ib_dereg_pnp( gp_dm_agent->h_port_pnp, + (ib_pfn_destroy_cb_t)deref_al_obj ); + CL_ASSERT( status == IB_SUCCESS ); + } + + /* Deregister for CA PnP events. */ + if( gp_dm_agent->h_ca_pnp ) + { + status = ib_dereg_pnp( gp_dm_agent->h_ca_pnp, + (ib_pfn_destroy_cb_t)deref_al_obj ); + CL_ASSERT( status == IB_SUCCESS ); + } +} + + + +/* + * Free the device management agent. + */ +void +free_dm_agent( + IN al_obj_t* p_obj ) +{ + CL_ASSERT( p_obj ); + CL_ASSERT( gp_dm_agent == PARENT_STRUCT( p_obj, dm_agent_t, obj ) ); + UNUSED_PARAM( p_obj ); + + destroy_al_obj( &gp_dm_agent->obj ); + cl_free( gp_dm_agent ); + gp_dm_agent = NULL; +} + + + +/* + * Register the device management agent for the given PnP class events. + */ +ib_api_status_t +dm_agent_reg_pnp( + IN ib_pnp_class_t pnp_class, + IN ib_pnp_handle_t * ph_pnp ) +{ + ib_api_status_t status; + ib_pnp_req_t pnp_req; + + CL_ASSERT( ph_pnp ); + + cl_memclr( &pnp_req, sizeof( ib_pnp_req_t ) ); + pnp_req.pnp_class = pnp_class; + pnp_req.pnp_context = gp_dm_agent; + pnp_req.pfn_pnp_cb = dm_agent_pnp_cb; + + status = ib_reg_pnp( gh_al, &pnp_req, ph_pnp ); + + /* Reference the DM agent on behalf of the ib_reg_pnp call. */ + if( status == IB_SUCCESS ) + ref_al_obj( &gp_dm_agent->obj ); + + return status; +} + + + +/* + * Device managment agent PnP event callback. + */ +ib_api_status_t +dm_agent_pnp_cb( + IN ib_pnp_rec_t* p_pnp_rec ) +{ + ib_api_status_t status; + al_iou_t* p_iou; + al_iou_port_t* p_iou_port; + + CL_ASSERT( p_pnp_rec ); + CL_ASSERT( p_pnp_rec->pnp_context == gp_dm_agent ); + + /* Dispatch based on the PnP event type. */ + switch( p_pnp_rec->pnp_event ) + { + case IB_PNP_CA_ADD: + status = create_iou( p_pnp_rec ); + break; + + case IB_PNP_CA_REMOVE: + CL_ASSERT( p_pnp_rec->context ); + p_iou = p_pnp_rec->context; + ref_al_obj( &p_iou->obj ); + p_iou->obj.pfn_destroy( &p_iou->obj, NULL ); + status = IB_SUCCESS; + break; + + case IB_PNP_PORT_ADD: + CL_ASSERT( !p_pnp_rec->context ); + status = create_iou_port( (ib_pnp_port_rec_t*)p_pnp_rec ); + break; + + case IB_PNP_PORT_REMOVE: + CL_ASSERT( p_pnp_rec->context ); + p_iou_port = p_pnp_rec->context; + ref_al_obj( &p_iou_port->obj ); + p_iou_port->obj.pfn_destroy( &p_iou_port->obj, NULL ); + + default: + /* All other events are ignored. */ + status = IB_SUCCESS; + break; + } + + return status; +} + + + +/* + * Create an IO unit. + */ +ib_api_status_t +create_iou( + IN ib_pnp_rec_t* p_pnp_rec ) +{ + al_iou_t* p_iou; + ib_ca_handle_t h_ca; + ib_api_status_t status; + + CL_ASSERT( p_pnp_rec ); + + p_iou = cl_zalloc( sizeof( al_iou_t ) ); + if( !p_iou ) + return IB_INSUFFICIENT_MEMORY; + + /* Construct the IO unit object. */ + construct_al_obj( &p_iou->obj, AL_OBJ_TYPE_IOU ); + + /* Initialize the IO unit object. */ + status = + init_al_obj( &p_iou->obj, p_iou, TRUE, NULL, cleanup_iou, free_iou ); + if( status != IB_SUCCESS ) + { + free_iou( &p_iou->obj ); + return status; + } + + /* + * Attach the IO unit to the device management agent. Lock and + * check to synchronize the destruction of the user-mode device + * management agent with the creation of the IO unit through a + * PnP callback. + */ + cl_spinlock_acquire( &gp_dm_agent->lock ); + if( gp_dm_agent->destroying ) + { + p_iou->obj.pfn_destroy( &p_iou->obj, NULL ); + cl_spinlock_release( &gp_dm_agent->lock ); + return IB_INVALID_STATE; + } + status = attach_al_obj( &gp_dm_agent->obj, &p_iou->obj ); + if( status != IB_SUCCESS ) + { + p_iou->obj.pfn_destroy( &p_iou->obj, NULL ); + cl_spinlock_release( &gp_dm_agent->lock ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("attach_al_obj returned %s.\n", ib_get_err_str(status)) ); + return status; + } + cl_spinlock_release( &gp_dm_agent->lock ); + + /* It is now safe to acquire the CA and initialize the p_ci_ca pointer. */ + h_ca = acquire_ca( p_pnp_rec->guid ); + if( !h_ca ) + { + p_iou->obj.pfn_destroy( &p_iou->obj, NULL ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("acquire_ca for GUID %016I64x failed.\n", p_pnp_rec->guid) ); + return IB_INVALID_CA_HANDLE; + } + + p_iou->obj.p_ci_ca = h_ca->obj.p_ci_ca; + + /* Initialize the IO unit IOC list. */ + cl_qlist_init( &p_iou->ioc_list ); + + /* Set the context of the PnP event to this child object. */ + p_pnp_rec->context = p_iou; + + /* Release the reference taken in init_al_obj. */ + deref_al_obj( &p_iou->obj ); + + return IB_SUCCESS; +} + + + +/* + * Cleanup an IO unit. + */ +void +cleanup_iou( + IN al_obj_t* p_obj ) +{ + al_iou_t* p_iou; + cl_list_item_t* p_ioc_item; + ib_ioc_handle_t h_ioc; + + CL_ASSERT( p_obj ); + p_iou = PARENT_STRUCT( p_obj, al_iou_t, obj ); + + /* No need to lock during cleanup. */ + for( p_ioc_item = cl_qlist_remove_head( &p_iou->ioc_list ); + p_ioc_item != cl_qlist_end( &p_iou->ioc_list ); + p_ioc_item = cl_qlist_remove_head( &p_iou->ioc_list ) ) + { + h_ioc = PARENT_STRUCT( p_ioc_item, al_ioc_t, obj ); + + CL_ASSERT( h_ioc->state == EMPTY_SLOT ); + + /* Detach the IOC from the IO unit. */ + CL_ASSERT( h_ioc->p_iou == p_iou ); + h_ioc->p_iou = NULL; + + /* Destroy the IOC. */ + ref_al_obj( &h_ioc->obj ); + h_ioc->obj.pfn_destroy( &h_ioc->obj, NULL ); + } +} + + + +/* + * Free an IO unit. + */ +void +free_iou( + IN al_obj_t* p_obj ) +{ + al_iou_t* p_iou; + + CL_ASSERT( p_obj ); + + p_iou = PARENT_STRUCT( p_obj, al_iou_t, obj ); + + /* Dereference the CA. */ + if( p_iou->obj.p_ci_ca ) + deref_al_obj( &p_iou->obj.p_ci_ca->h_ca->obj ); + + destroy_al_obj( &p_iou->obj ); + cl_free( p_iou ); +} + + + +/* + * Create an IO unit port. + */ +ib_api_status_t +create_iou_port( + IN ib_pnp_port_rec_t* p_pnp_rec ) +{ + al_iou_port_t* p_iou_port; + al_iou_t* p_iou; + ib_qp_create_t qp_create; + ib_mad_svc_t mad_svc; + ib_api_status_t status; + + CL_ASSERT( p_pnp_rec ); + + CL_ASSERT( p_pnp_rec->p_ca_attr ); + CL_ASSERT( p_pnp_rec->p_port_attr ); + + p_iou_port = cl_zalloc( sizeof( al_iou_port_t ) ); + if( !p_iou_port ) + return IB_INSUFFICIENT_MEMORY; + + /* Construct the IO unit port object. */ + construct_al_obj( &p_iou_port->obj, AL_OBJ_TYPE_IOU ); + + /* Initialize the IO unit port object. */ + status = init_al_obj( &p_iou_port->obj, p_iou_port, TRUE, + destroying_iou_port, NULL, free_iou_port ); + if( status != IB_SUCCESS ) + { + free_iou_port( &p_iou_port->obj ); + return status; + } + + /* Acquire the IO unit. */ + p_iou = acquire_iou( p_pnp_rec->p_ca_attr->ca_guid ); + if( !p_iou ) + { + p_iou_port->obj.pfn_destroy( &p_iou_port->obj, NULL ); + return IB_INVALID_GUID; + } + + /* Attach the IO unit port to the IO unit. */ + status = attach_al_obj( &p_iou->obj, &p_iou_port->obj ); + if( status != IB_SUCCESS ) + { + p_iou_port->obj.pfn_destroy( &p_iou_port->obj, NULL ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("attach_al_obj returned %s.\n", ib_get_err_str(status)) ); + return status; + } + deref_al_obj( &p_iou->obj ); + + /* Save the port number. */ + p_iou_port->port_num = p_pnp_rec->p_port_attr->port_num; + + /* Save the port GUID - used in svc reg. */ + p_iou_port->port_guid = p_pnp_rec->pnp_rec.guid; + + /* Save the default port gid and pkey */ + p_iou_port->port_gid = p_pnp_rec->p_port_attr->p_gid_table[0]; + p_iou_port->port_pkey = p_pnp_rec->p_port_attr->p_pkey_table[0]; + + /* Create a QP alias. */ + cl_memclr( &qp_create, sizeof( ib_qp_create_t ) ); + qp_create.qp_type = IB_QPT_QP1_ALIAS; + qp_create.sq_depth = 1; + qp_create.sq_sge = 1; + qp_create.sq_signaled = TRUE; + + status = ib_get_spl_qp( p_iou_port->obj.p_ci_ca->h_pd_alias, + p_pnp_rec->p_port_attr->port_guid, &qp_create, + p_iou_port, iou_port_event_cb, &p_iou_port->pool_key, + &p_iou_port->h_qp_alias ); + + if (status != IB_SUCCESS) + { + p_iou_port->obj.pfn_destroy( &p_iou_port->obj, NULL ); + return status; + } + + /* Reference the IO unit port on behalf of ib_get_spl_qp. */ + ref_al_obj( &p_iou_port->obj ); + + /* Register a service the MAD service for device management. */ + cl_memclr( &mad_svc, sizeof( ib_mad_svc_t ) ); + mad_svc.mad_svc_context = p_iou_port; + mad_svc.pfn_mad_send_cb = dm_agent_send_cb; + mad_svc.pfn_mad_recv_cb = dm_agent_recv_cb; + mad_svc.support_unsol = TRUE; + mad_svc.mgmt_class = IB_MCLASS_DEV_MGMT; + mad_svc.mgmt_version = 1; + mad_svc.method_array[ IB_MAD_METHOD_GET ] = TRUE; + mad_svc.method_array[ IB_MAD_METHOD_SET ] = TRUE; + + status = ib_reg_mad_svc( p_iou_port->h_qp_alias, &mad_svc, + &p_iou_port->h_mad_svc ); + if( status != IB_SUCCESS ) + { + p_iou_port->obj.pfn_destroy( &p_iou_port->obj, NULL ); + return status; + } + + /* Determine if any IOCs are attached to this IO unit. */ + cl_spinlock_acquire( &p_iou->obj.lock ); + if( !cl_is_qlist_empty( &p_iou->ioc_list ) ) + { + /* Set the device management port attribute. */ + status = set_port_dm_attr( p_iou_port ); + CL_ASSERT( status == IB_SUCCESS ); + } + cl_spinlock_release( &p_iou->obj.lock ); + + /* Set the context of the PnP event to this child object. */ + p_pnp_rec->pnp_rec.context = p_iou_port; + + /* Release the reference taken in init_al_obj. */ + deref_al_obj( &p_iou_port->obj ); + + return IB_SUCCESS; +} + + + +/* + * Pre-destroy an IO unit port. + */ +void +destroying_iou_port( + IN al_obj_t* p_obj ) +{ + al_iou_port_t* p_iou_port; + ib_api_status_t status; + + CL_ASSERT( p_obj ); + p_iou_port = PARENT_STRUCT( p_obj, al_iou_port_t, obj ); + + /* Deregister the device management service. */ + if( p_iou_port->svc_handle ) + { + status = ib_dereg_svc( p_iou_port->svc_handle, + (ib_pfn_destroy_cb_t)deref_al_obj ); + CL_ASSERT( status == IB_SUCCESS ); + } + + /* Destroy the QP alias. */ + if( p_iou_port->h_qp_alias ) + { + status = ib_destroy_qp( p_iou_port->h_qp_alias, + (ib_pfn_destroy_cb_t)deref_al_obj ); + CL_ASSERT( status == IB_SUCCESS ); + } +} + + + +/* + * Free an IO unit port. + */ +void +free_iou_port( + IN al_obj_t* p_obj ) +{ + al_iou_port_t* p_iou_port; + + CL_ASSERT( p_obj ); + + p_iou_port = PARENT_STRUCT( p_obj, al_iou_port_t, obj ); + + destroy_al_obj( &p_iou_port->obj ); + cl_free( p_iou_port ); +} + + + +/* + * IO unit port asynchronous event callback. + */ +void +iou_port_event_cb( + IN ib_async_event_rec_t *p_event_rec ) +{ + UNUSED_PARAM( p_event_rec ); + + /* The QP is an alias, so if we've received an error, it is unusable. */ +} + + + +/* + * Device management agent send completion callback. + */ +void +dm_agent_send_cb( + IN ib_mad_svc_handle_t h_mad_svc, + IN void* mad_svc_context, + IN ib_mad_element_t* p_mad_response ) +{ + ib_api_status_t status; + + CL_ASSERT( mad_svc_context ); + CL_ASSERT( p_mad_response ); + UNUSED_PARAM( h_mad_svc ); + UNUSED_PARAM( mad_svc_context ); + + /* Return the MAD. */ + status = ib_destroy_av( p_mad_response->h_av ); + CL_ASSERT( status == IB_SUCCESS ); + status = ib_put_mad( p_mad_response ); + CL_ASSERT( status == IB_SUCCESS ); +} + + + +/* + * Device management agent receive completion callback. + */ +void +dm_agent_recv_cb( + IN ib_mad_svc_handle_t h_mad_svc, + IN void* mad_svc_context, + IN ib_mad_element_t* p_mad_request ) +{ + al_iou_port_t* p_iou_port; + ib_mad_element_t* p_mad_response; + ib_mad_t* p_mad_req; + ib_mad_t* p_mad_rsp; + ib_av_attr_t av_attr; + ib_api_status_t status; + + CL_ASSERT( mad_svc_context ); + CL_ASSERT( p_mad_request ); + + p_iou_port = mad_svc_context; + p_mad_req = ib_get_mad_buf( p_mad_request ); + + /* Get a MAD element for the response. */ + status = ib_get_mad( p_iou_port->pool_key, MAD_BLOCK_SIZE, + &p_mad_response ); + + if( status != IB_SUCCESS ) + { + status = ib_put_mad( p_mad_request ); + CL_ASSERT( status == IB_SUCCESS ); + return; + } + + /* Initialize the response MAD element. */ + p_mad_response->remote_qp = p_mad_request->remote_qp; + p_mad_response->remote_qkey = IB_QP1_WELL_KNOWN_Q_KEY; + p_mad_rsp = ib_get_mad_buf( p_mad_response ); + + /* Create an address vector for the response. */ + cl_memclr( &av_attr, sizeof( ib_av_attr_t ) ); + av_attr.port_num = p_iou_port->port_num; + av_attr.sl = p_mad_request->remote_sl; + av_attr.dlid = p_mad_request->remote_lid; + av_attr.path_bits = p_mad_request->path_bits; + av_attr.static_rate = IB_PATH_RECORD_RATE_10_GBS; + if( p_mad_request->grh_valid ) + { + av_attr.grh_valid = TRUE; + av_attr.grh = *p_mad_request->p_grh; + } + + status = ib_create_av( p_iou_port->obj.p_ci_ca->h_pd_alias, &av_attr, + &p_mad_response->h_av ); + + if( status != IB_SUCCESS ) + { + status = ib_put_mad( p_mad_request ); + CL_ASSERT( status == IB_SUCCESS ); + status = ib_put_mad( p_mad_response ); + CL_ASSERT( status == IB_SUCCESS ); + return; + } + + /* Initialize the response header. */ + ib_mad_init_response( p_mad_req, p_mad_rsp, 0 ); + + /* Process the MAD request. */ + switch( p_mad_req->method ) + { + case IB_MAD_METHOD_GET: + dm_agent_get( p_iou_port, p_mad_req, p_mad_rsp ); + break; + + case IB_MAD_METHOD_SET: + dm_agent_set( p_iou_port, p_mad_req, p_mad_rsp ); + break; + + default: + p_mad_rsp->status = IB_MAD_STATUS_UNSUP_METHOD; + break; + } + + /* Return the request to the pool. */ + status = ib_put_mad( p_mad_request ); + CL_ASSERT( status == IB_SUCCESS ); + + /* Send the response. */ + status = ib_send_mad( h_mad_svc, p_mad_response, NULL ); + + if( status != IB_SUCCESS ) + { + status = ib_destroy_av( p_mad_response->h_av ); + CL_ASSERT( status == IB_SUCCESS ); + status = ib_put_mad( p_mad_response ); + CL_ASSERT( status == IB_SUCCESS ); + } +} + + + +/* + * Device management agent get method MAD. + */ +void +dm_agent_get( + IN al_iou_port_t* p_iou_port, + IN ib_mad_t* p_mad_req, + IN ib_mad_t* p_mad_rsp ) +{ + al_iou_t* p_iou; + ib_dm_mad_t* p_dm_mad; + + CL_ASSERT( p_iou_port ); + CL_ASSERT( p_mad_req ); + CL_ASSERT( p_mad_rsp ); + + p_iou = PARENT_STRUCT( p_iou_port->obj.p_parent_obj, al_iou_t, obj ); + + p_dm_mad = (ib_dm_mad_t*)p_mad_rsp; + + switch( p_mad_req->attr_id ) + { + case IB_MAD_ATTR_CLASS_PORT_INFO: + get_class_port_info( p_iou, p_dm_mad ); + break; + + case IB_MAD_ATTR_IO_UNIT_INFO: + get_io_unit_info( p_iou, p_dm_mad ); + break; + + case IB_MAD_ATTR_IO_CONTROLLER_PROFILE: + { + uint8_t slot; + + slot = (uint8_t)CL_NTOH32( p_dm_mad->hdr.attr_mod ); + + get_ioc_profile( p_iou, slot, p_dm_mad ); + break; + } + + case IB_MAD_ATTR_SERVICE_ENTRIES: + { + uint8_t slot; + uint8_t svc_num_hi; + uint8_t svc_num_lo; + + ib_dm_get_slot_lo_hi( p_dm_mad->hdr.attr_mod, &slot, + &svc_num_hi, &svc_num_lo ); + + get_svc_entries( p_iou, slot, svc_num_lo, svc_num_hi, p_dm_mad ); + break; + } + + case IB_MAD_ATTR_DIAGNOSTIC_TIMEOUT: + case IB_MAD_ATTR_PREPARE_TO_TEST: + case IB_MAD_ATTR_DIAG_CODE: + default: + p_mad_rsp->status = IB_MAD_STATUS_UNSUP_METHOD_ATTR; + break; + } +} + + + +/* + * Device management agent set method MAD. + */ +void +dm_agent_set( + IN al_iou_port_t* p_iou_port, + IN ib_mad_t* p_mad_req, + IN ib_mad_t* p_mad_rsp ) +{ + ib_dm_mad_t* p_dm_mad; + + CL_ASSERT( p_iou_port ); + CL_ASSERT( p_mad_req ); + CL_ASSERT( p_mad_rsp ); + UNUSED_PARAM( p_iou_port ); + + p_dm_mad = (ib_dm_mad_t*)p_mad_rsp; + + switch( p_mad_req->attr_id ) + { + case IB_MAD_ATTR_CLASS_PORT_INFO: + break; + + case IB_MAD_ATTR_PREPARE_TO_TEST: + case IB_MAD_ATTR_TEST_DEVICE_ONCE: + case IB_MAD_ATTR_TEST_DEVICE_LOOP: + default: + p_mad_rsp->status = IB_MAD_STATUS_UNSUP_METHOD_ATTR; + break; + } +} + + +void +get_class_port_info( + IN al_iou_t* p_iou, + IN ib_dm_mad_t* p_dm_mad ) +{ + ib_class_port_info_t* p_class_port_info; + + CL_ASSERT( p_iou ); + CL_ASSERT( p_dm_mad ); + UNUSED_PARAM( p_iou ); + + p_class_port_info = (ib_class_port_info_t*)&p_dm_mad->data; + + p_class_port_info->base_ver = 1; + p_class_port_info->class_ver = 1; + p_class_port_info->cap_mask2_resp_time = CL_HTON32( DM_CLASS_RESP_TIME_VALUE ); +} + + + +void +get_io_unit_info( + IN al_iou_t* p_iou, + IN ib_dm_mad_t* p_dm_mad ) +{ + ib_iou_info_t* p_iou_info; + cl_list_item_t* p_ioc_item; + ib_ioc_handle_t h_ioc; + uint8_t slot; + + CL_ASSERT( p_iou ); + CL_ASSERT( p_dm_mad ); + + p_iou_info = (ib_iou_info_t*)&p_dm_mad->data; + + cl_spinlock_acquire( &p_iou->obj.lock ); + + p_iou_info->change_id = p_iou->change_id; + + /* Mark all slots as non-existant. */ + SET_NIBBLE( &slot, 0, SLOT_DOES_NOT_EXIST ); + SET_NIBBLE( &slot, 1, SLOT_DOES_NOT_EXIST ); + cl_memset( p_iou_info->controller_list, slot, sizeof( p_iou->ioc_list ) ); + + /* Now mark the existing slots. */ + slot = 1; + for( p_ioc_item = cl_qlist_head( &p_iou->ioc_list ); + p_ioc_item != cl_qlist_end( &p_iou->ioc_list ); + p_ioc_item = cl_qlist_next( p_ioc_item ) ) + { + h_ioc = PARENT_STRUCT( p_ioc_item, al_ioc_t, iou_item ); + + switch( h_ioc->state ) + { + case EMPTY_SLOT: + case SLOT_IN_USE: + SET_NIBBLE( p_iou_info->controller_list, slot, IOC_NOT_INSTALLED ); + break; + + case IOC_ACTIVE: + SET_NIBBLE( p_iou_info->controller_list, slot, IOC_INSTALLED ); + break; + + default: + break; + } + slot++; + } + + p_iou_info->max_controllers = slot; + + cl_spinlock_release( &p_iou->obj.lock ); +} + + + +void +get_ioc_profile( + IN al_iou_t* p_iou, + IN uint8_t slot, + IN ib_dm_mad_t* p_dm_mad ) +{ + ib_ioc_profile_t* p_ioc_profile; + cl_list_item_t* p_ioc_item; + ib_ioc_handle_t h_ioc; + + CL_ASSERT( p_iou ); + CL_ASSERT( p_dm_mad ); + + p_ioc_profile = (ib_ioc_profile_t*)&p_dm_mad->data; + + cl_spinlock_acquire( &p_iou->obj.lock ); + + /* Verify that the slot number is within range. */ + if( ( slot == 0 ) || + ( slot > cl_qlist_count( &p_iou->ioc_list ) ) ) + { + cl_spinlock_release( &p_iou->obj.lock ); + p_dm_mad->hdr.status = IB_MAD_STATUS_INVALID_FIELD; + return; + } + + /* The remaining code assumes the slot number starts at zero. */ + for( p_ioc_item = cl_qlist_head( &p_iou->ioc_list ); + p_ioc_item != cl_qlist_end( &p_iou->ioc_list ) && slot; + p_ioc_item = cl_qlist_next( p_ioc_item ) ) + { + slot--; + } + + h_ioc = PARENT_STRUCT( p_ioc_item, al_ioc_t, iou_item ); + + cl_spinlock_acquire( &h_ioc->obj.lock ); + + /* Verify the IOC state. */ + if( h_ioc->state != IOC_ACTIVE ) + { + cl_spinlock_release( &h_ioc->obj.lock ); + cl_spinlock_release( &p_iou->obj.lock ); + p_dm_mad->hdr.status = IB_DM_MAD_STATUS_NO_IOC_RESP; + return; + } + + /* Copy the IOC profile. */ + *p_ioc_profile = h_ioc->ioc_profile; + + cl_spinlock_release( &h_ioc->obj.lock ); + cl_spinlock_release( &p_iou->obj.lock ); +} + + + +void +get_svc_entries( + IN al_iou_t* p_iou, + IN uint8_t slot, + IN uint8_t svc_num_lo, + IN uint8_t svc_num_hi, + IN ib_dm_mad_t* p_dm_mad ) +{ + ib_svc_entries_t* p_svc_entries; + cl_list_item_t* p_ioc_item; + cl_list_item_t* p_list_item; + ib_ioc_handle_t h_ioc; + al_obj_t* p_obj; + al_svc_entry_t* p_svc_entry; + uint8_t i, j, k; + + CL_ASSERT( p_iou ); + CL_ASSERT( p_dm_mad ); + + p_svc_entries = (ib_svc_entries_t*)&p_dm_mad->data; + + cl_spinlock_acquire( &p_iou->obj.lock ); + + /* + * Verify that the slot number is within range and + * a maximum of SVC_ENTRY_COUNT entries is requested. + */ + if( ( slot == 0 ) || + ( slot > cl_qlist_count( &p_iou->ioc_list ) ) || + ( ( svc_num_hi - svc_num_lo + 1) > SVC_ENTRY_COUNT ) ) + { + cl_spinlock_release( &p_iou->obj.lock ); + p_dm_mad->hdr.status = IB_MAD_STATUS_INVALID_FIELD; + return; + } + + /* The remaining code assumes the slot number starts at zero. */ + for( p_ioc_item = cl_qlist_head( &p_iou->ioc_list ); + p_ioc_item != cl_qlist_end( &p_iou->ioc_list ) && slot; + p_ioc_item = cl_qlist_next( p_ioc_item ) ) + { + slot--; + } + + h_ioc = PARENT_STRUCT( p_ioc_item, al_ioc_t, iou_item ); + + cl_spinlock_acquire( &h_ioc->obj.lock ); + + /* Verify the IOC state. */ + if( h_ioc->state != IOC_ACTIVE ) + { + cl_spinlock_release( &h_ioc->obj.lock ); + cl_spinlock_release( &p_iou->obj.lock ); + p_dm_mad->hdr.status = IB_DM_MAD_STATUS_NO_IOC_RESP; + return; + } + + /* Verify the service entry range. */ + if( ( svc_num_lo > h_ioc->ioc_profile.num_svc_entries ) || + ( svc_num_hi >= h_ioc->ioc_profile.num_svc_entries ) ) + { + cl_spinlock_release( &h_ioc->obj.lock ); + cl_spinlock_release( &p_iou->obj.lock ); + p_dm_mad->hdr.status = IB_MAD_STATUS_INVALID_FIELD; + return; + } + + for( i = svc_num_lo, j = 0; j < ( svc_num_hi - svc_num_lo + 1 ); i++, j++ ) + { + k = i; + + /* Locate the service entry. Traverse until k=0. */ + for( p_list_item = cl_qlist_head( &h_ioc->obj.obj_list ); + k && ( p_list_item != cl_qlist_end( &h_ioc->obj.obj_list ) ); + p_list_item = cl_qlist_next( p_list_item ) ) + { + k--; + } + + if( p_list_item == cl_qlist_end( &h_ioc->obj.obj_list ) ) + { + /* The service entry list was empty or the end was reached. */ + cl_spinlock_release( &h_ioc->obj.lock ); + cl_spinlock_release( &p_iou->obj.lock ); + p_dm_mad->hdr.status = IB_DM_MAD_STATUS_NO_SVC_ENTRIES; + return; + } + + p_obj = PARENT_STRUCT( p_list_item, al_obj_t, obj_list ); + p_svc_entry = PARENT_STRUCT( p_obj, al_svc_entry_t, obj ); + + /* Copy the service entry. */ + p_svc_entries->service_entry[ j ] = p_svc_entry->svc_entry; + } + + cl_spinlock_release( &h_ioc->obj.lock ); + cl_spinlock_release( &p_iou->obj.lock ); +} diff --git a/branches/WOF2-3/core/al/al_dm.h b/branches/WOF2-3/core/al/al_dm.h new file mode 100644 index 00000000..ebd30bdc --- /dev/null +++ b/branches/WOF2-3/core/al/al_dm.h @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#if !defined(__AL_DM_H__) +#define __AL_DM_H__ + +#include +#include "al_common.h" + + +typedef struct _dm_agent /* Global device management agent struct */ +{ + al_obj_t obj; /* Child of al_mgr_t */ + ib_pnp_handle_t h_ca_pnp; /* Handle for CA PnP events */ + ib_pnp_handle_t h_port_pnp; /* Handle for Port PnP events */ + + /* + * Lock and state to synchronize user-mode device management + * agent destruction with PnP callbacks to create IO units. + */ + cl_spinlock_t lock; + boolean_t destroying; + +} dm_agent_t; + + +typedef struct _al_iou /* IO unit struct - max of one per CA */ +{ + al_obj_t obj; /* Child of dm_agent_t */ + + uint16_t change_id; + cl_qlist_t ioc_list; /* List of IOCs */ + +} al_iou_t; + + +typedef struct _al_iou_port /* Per-port object of an IO unit */ +{ + al_obj_t obj; /* Child of al_iou_t */ + + uint8_t port_num; + net64_t port_guid; + ib_gid_t port_gid; + ib_net16_t port_pkey; + ib_qp_handle_t h_qp_alias; + ib_mad_svc_handle_t h_mad_svc; + + ib_pool_key_t pool_key; + + ib_reg_svc_handle_t svc_handle; /* Service registration handle */ + +} al_iou_port_t; + + +typedef enum _ioc_state /* An IOC represents a slot in an IO unit */ +{ + IOC_INIT = 0, + EMPTY_SLOT, + SLOT_IN_USE, + IOC_ACTIVE + +} ioc_state_t; + + +#pragma warning(disable:4324) +typedef struct _al_ioc +{ + al_obj_t obj; /* Child of ib_ca_t */ + + cl_list_item_t iou_item; /* Item on IO Unit list */ + al_iou_t* p_iou; + + ioc_state_t state; + ib_ioc_profile_t ioc_profile; + + atomic32_t in_use_cnt; + +} al_ioc_t; +#pragma warning(default:4324) + + +typedef struct _al_svc_entry +{ + al_obj_t obj; /* Child of al_ioc_t */ + ib_svc_entry_t svc_entry; + +} al_svc_entry_t; + + +ib_api_status_t +create_dm_agent( + IN al_obj_t* const p_parent_obj ); + + +#endif /* __AL_DM_H__ */ diff --git a/branches/WOF2-3/core/al/al_init.c b/branches/WOF2-3/core/al/al_init.c new file mode 100644 index 00000000..b57fc9d0 --- /dev/null +++ b/branches/WOF2-3/core/al/al_init.c @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include "al_debug.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "al_init.tmh" +#endif + +#include "al_dev.h" +#include "al_init.h" +#include "al_mgr.h" + +#include "ib_common.h" + + + +uint32_t g_al_dbg_level = TRACE_LEVEL_ERROR; +uint32_t g_al_dbg_flags = 0xf0; +/* + * Device driver initialization routine. + */ +ib_api_status_t +al_initialize( void ) +{ + cl_status_t cl_status; + ib_api_status_t status = IB_ERROR; + + AL_ENTER( AL_DBG_DEV ); + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_DEV, ("Hello World! =)\n") ); + + /* + * Initialize access layer services. + */ +#if AL_OBJ_PRIVATE_ASYNC_PROC + gp_async_proc_mgr = cl_malloc( sizeof(cl_async_proc_t) * 3 ); +#else + gp_async_proc_mgr = cl_malloc( sizeof(cl_async_proc_t) * 2 ); +#endif + if( !gp_async_proc_mgr ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("alloc_async_proc failed.\n") ); + return IB_INSUFFICIENT_MEMORY; + } + gp_async_pnp_mgr = gp_async_proc_mgr + 1; + cl_async_proc_construct( gp_async_proc_mgr ); + cl_async_proc_construct( gp_async_pnp_mgr ); +#if AL_OBJ_PRIVATE_ASYNC_PROC + gp_async_obj_mgr = gp_async_proc_mgr + 2; + cl_async_proc_construct( gp_async_obj_mgr ); + cl_status = cl_async_proc_init( gp_async_obj_mgr, 1, "AL_OBJ" ); + if( cl_status != CL_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("Failed to init async_obj_mgr: status = 0x%x.\n", cl_status) ); + return ib_convert_cl_status( cl_status ); + } +#endif + cl_status = cl_async_proc_init( gp_async_proc_mgr, 1, "AL_MISC" ); + if( cl_status != CL_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("Failed to init async_proc_mgr: status = 0x%x.\n", cl_status) ); + return ib_convert_cl_status( cl_status ); + } + + cl_status = cl_async_proc_init( gp_async_pnp_mgr, 1, "AL_PNP" ); + if( cl_status != CL_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("Failed to init async_pnp_mgr: status = 0x%x.\n", cl_status) ); + return ib_convert_cl_status( cl_status ); + } + + status = create_al_mgr(); + if( status != IB_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("init_al_mgr: status = 0x%x.\n", status) ); + return status; + } + + AL_EXIT( AL_DBG_DEV ); + return status; +} + + + +/* + * Device driver cleanup routine. + */ +void +al_cleanup( void ) +{ + AL_ENTER( AL_DBG_DEV ); + + /* + * Destroy access layer device interface. + */ + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_DEV, ("Destroying %s device.\n", + (const char *)AL_DEVICE_NAME) ); + + /* + * Destroy access layer services. + */ + if( gp_al_mgr ) + { + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_DEV, ("Destroying AL Mgr.\n") ); + ref_al_obj( &gp_al_mgr->obj ); + gp_al_mgr->obj.pfn_destroy( &gp_al_mgr->obj, NULL ); + } + +#if AL_OBJ_PRIVATE_ASYNC_PROC + if( gp_async_obj_mgr ) + { + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_DEV, + ("Destroying async obj mgr.\n") ); + cl_async_proc_destroy( gp_async_obj_mgr ); + gp_async_obj_mgr = NULL; + } +#endif + + if( gp_async_pnp_mgr ) + { + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_DEV, + ("Destroying async pnp mgr.\n") ); + cl_async_proc_destroy( gp_async_pnp_mgr ); + gp_async_pnp_mgr = NULL; + } + + if( gp_async_proc_mgr ) + { + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_DEV, + ("Destroying async proc mgr.\n") ); + cl_async_proc_destroy( gp_async_proc_mgr ); + cl_free( gp_async_proc_mgr ); + gp_async_proc_mgr = NULL; + } + + AL_PRINT_EXIT( TRACE_LEVEL_WARNING, AL_DBG_DEV, ("Goodbye Cruel World =(\n") ); +} diff --git a/branches/WOF2-3/core/al/al_init.h b/branches/WOF2-3/core/al/al_init.h new file mode 100644 index 00000000..4f100474 --- /dev/null +++ b/branches/WOF2-3/core/al/al_init.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#if !defined(_IB_AL_INIT_H_) +#define _IB_AL_INIT_H_ + +#include + + +/****i* AL/al_initialize +* NAME +* This function initializes the Access Layer. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +al_initialize( void ); +/* +* DESCRIPTION +* This function performs a global initialization of the +* Access Layer (AL) +* +* PARAMETERS +* None +* +* RETURN VALUE +* Status - +* TBD +* +* PORTABILITY +* Kernel mode only. +* +* SEE ALSO +* al_cleanup +*********/ + + +/****i* AL/al_cleanup +* NAME +* This function cleans up resources allocated during al_initialize. +* +* SYNOPSIS +*/ +AL_EXPORT void AL_API +al_cleanup( void ); +/* +* DESCRIPTION +* This function frees up resources used by the access layer. +* +* PARAMETERS +* None +* +* RETURN VALUE +* +* PORTABILITY +* Kernel mode only. +* +* SEE ALSO +* al_initialize +*********/ + +#endif /* _IB_AL_INIT_H_ */ diff --git a/branches/WOF2-3/core/al/al_ioc_pnp.h b/branches/WOF2-3/core/al/al_ioc_pnp.h new file mode 100644 index 00000000..5758ff46 --- /dev/null +++ b/branches/WOF2-3/core/al/al_ioc_pnp.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + +#if !defined(__IB_AL_IOC_PNP_H__) +#define __IB_AL_IOC_PNP_H__ + + +#include "al_common.h" + + +ib_api_status_t +create_ioc_pnp( + IN al_obj_t* const p_parent_obj ); + +void +ioc_pnp_process_reg( + IN cl_async_proc_item_t *p_item ); + +void +ioc_pnp_process_dereg( + IN cl_async_proc_item_t *p_item ); + +#endif /* __IB_AL_IOC_PNP_H__ */ diff --git a/branches/WOF2-3/core/al/al_mad.c b/branches/WOF2-3/core/al/al_mad.c new file mode 100644 index 00000000..6dd0cac7 --- /dev/null +++ b/branches/WOF2-3/core/al/al_mad.c @@ -0,0 +1,3274 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include +#include +#include + +#include "al.h" +#include "al_debug.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "al_mad.tmh" +#endif + +#include "al_cq.h" +#include "al_mad.h" +#include "al_qp.h" +#include "al_res_mgr.h" +#include "al_verbs.h" + +#include "ib_common.h" + + +#define MAX_TIME CL_CONST64(0xFFFFFFFFFFFFFFFF) +#define MAD_VECTOR_SIZE 8 +#define MAX_METHOD 127 +#define DEFAULT_RMPP_VERSION 1 + +#define AL_RMPP_WINDOW 16 /* Max size of RMPP window */ +#define AL_REASSEMBLY_TIMEOUT 5000 /* 5 seconds */ +#define AL_RMPP_RETRIES 5 + +static void +__cleanup_mad_disp( + IN al_obj_t *p_obj ); + +static void +__free_mad_disp( + IN al_obj_t *p_obj ); + +static cl_status_t +__init_mad_reg( + IN void* const p_element, + IN void* context ); + +static cl_status_t +__init_version_entry( + IN void* const p_element, + IN void* context ); + +static void +__destroy_version_entry( + IN void* const p_element, + IN void* context ); + +static cl_status_t +__init_class_entry( + IN void* const p_element, + IN void* context ); + +static void +__destroy_class_entry( + IN void* const p_element, + IN void* context ); + +static __inline uint8_t +__mgmt_class_index( + IN const uint8_t mgmt_class ); + +static __inline uint8_t +__mgmt_version_index( + IN const uint8_t mgmt_version ); + +static boolean_t +__mad_disp_reg_unsol( + IN const al_mad_disp_handle_t h_mad_disp, + IN const al_mad_reg_handle_t h_mad_reg, + IN const ib_mad_svc_t *p_mad_svc ); + +static boolean_t +__use_tid_routing( + IN const ib_mad_t* const p_mad_hdr, + IN const boolean_t are_we_sender ); + +/* + * Issue a send request to the MAD dispatcher. + */ +static void +__mad_disp_queue_send( + IN const al_mad_reg_handle_t h_mad_reg, + IN al_mad_wr_t* const p_mad_wr ); + +static inline void +__mad_disp_resume_send( + IN const al_mad_reg_handle_t h_mad_reg ); + +static void +__destroying_mad_svc( + IN struct _al_obj *p_obj ); + +static void +__cleanup_mad_svc( + IN struct _al_obj *p_obj ); + +static void +__send_timer_cb( + IN void *context ); + +static void +__check_send_queue( + IN ib_mad_svc_handle_t h_mad_svc ); + +static void +__recv_timer_cb( + IN void *context ); + +static ib_api_status_t +__init_send_mad( + IN ib_mad_svc_handle_t h_mad_svc, + IN const ib_mad_send_handle_t h_send, + IN ib_mad_element_t* const p_mad_element ); + +static boolean_t +__does_send_req_rmpp( + IN const ib_mad_svc_type_t mad_svc_type, + IN const ib_mad_element_t* const p_mad_element, + OUT uint8_t *p_rmpp_version ); + +static void +__queue_mad_wr( + IN const al_mad_reg_handle_t h_mad_reg, + IN const ib_mad_send_handle_t h_send ); + +static void +__queue_rmpp_seg( + IN const al_mad_reg_handle_t h_mad_reg, + IN ib_mad_send_handle_t h_send ); + +static ib_api_status_t +__create_send_av( + IN ib_mad_svc_handle_t h_mad_svc, + IN ib_mad_send_handle_t h_send ); + +static void +__cleanup_mad_send( + IN ib_mad_svc_handle_t h_mad_svc, + IN ib_mad_send_handle_t h_send ); + +static __inline void +__set_retry_time( + IN ib_mad_send_handle_t h_send ); + +static void +__mad_svc_send_done( + IN ib_mad_svc_handle_t h_mad_svc, + IN al_mad_wr_t *p_mad_wr, + IN ib_wc_t *p_wc ); + +static boolean_t +__is_send_mad_done( + IN ib_mad_send_handle_t h_send, + IN ib_wc_status_t status ); + +static void +__notify_send_comp( + IN ib_mad_svc_handle_t h_mad_svc, + IN ib_mad_send_handle_t h_send, + IN ib_wc_status_t wc_status ); + +static void +__mad_svc_recv_done( + IN ib_mad_svc_handle_t h_mad_svc, + IN ib_mad_element_t *p_mad_element ); + +static void +__process_recv_resp( + IN ib_mad_svc_handle_t h_mad_svc, + IN ib_mad_element_t *p_mad_element ); + +static cl_status_t +__do_rmpp_recv( + IN ib_mad_svc_handle_t h_mad_svc, + IN OUT ib_mad_element_t **pp_mad_element ); + +static __inline boolean_t +__recv_requires_rmpp( + IN const ib_mad_svc_type_t mad_svc_type, + IN const ib_mad_element_t* const p_mad_element ); + +static __inline boolean_t +__is_internal_send( + IN const ib_mad_svc_type_t mad_svc_type, + IN const ib_mad_element_t* const p_mad_element ); + +static cl_status_t +__process_rmpp_data( + IN ib_mad_svc_handle_t h_mad_svc, + IN OUT ib_mad_element_t **pp_mad_element ); + +static void +__process_rmpp_ack( + IN ib_mad_svc_handle_t h_mad_svc, + IN ib_mad_element_t *p_mad_element ); + +static void +__process_rmpp_nack( + IN ib_mad_svc_handle_t h_mad_svc, + IN ib_mad_element_t *p_mad_element ); + +static cl_status_t +__process_segment( + IN ib_mad_svc_handle_t h_mad_svc, + IN al_mad_rmpp_t *p_rmpp, + IN OUT ib_mad_element_t **pp_mad_element, + OUT ib_mad_element_t **pp_rmpp_resp_mad ); + +static al_mad_rmpp_t* +__find_rmpp( + IN ib_mad_svc_handle_t h_mad_svc, + IN OUT ib_mad_element_t *p_mad_element ); + +static al_mad_rmpp_t* +__get_mad_rmpp( + IN ib_mad_svc_handle_t h_mad_svc, + IN ib_mad_element_t *p_mad_element ); + +static void +__put_mad_rmpp( + IN ib_mad_svc_handle_t h_mad_svc, + IN al_mad_rmpp_t *p_rmpp ); + +static void +__init_reply_element( + IN ib_mad_element_t *p_dst_element, + IN ib_mad_element_t *p_src_element ); + +static ib_mad_element_t* +__get_rmpp_ack( + IN al_mad_rmpp_t *p_rmpp ); + +ib_net64_t +__get_send_tid( + IN ib_mad_send_handle_t h_send ) +{ + return ((ib_mad_t*)ib_get_mad_buf( h_send->p_send_mad ))->trans_id; +} + + +ib_mad_t* +get_mad_hdr_from_wr( + IN al_mad_wr_t* const p_mad_wr ) +{ + ib_mad_send_handle_t h_send; + + CL_ASSERT( p_mad_wr ); + + h_send = PARENT_STRUCT( p_mad_wr, al_mad_send_t, mad_wr ); + return h_send->p_send_mad->p_mad_buf; +} + + + +/* + * Construct a MAD element from a receive work completion. + */ +void +build_mad_recv( + IN ib_mad_element_t* p_mad_element, + IN ib_wc_t* p_wc ) +{ + AL_ENTER( AL_DBG_SMI ); + + CL_ASSERT( p_mad_element ); + CL_ASSERT( p_wc ); + + /* Build the MAD element from the work completion. */ + p_mad_element->status = p_wc->status; + p_mad_element->remote_qp = p_wc->recv.ud.remote_qp; + + /* + * We assume all communicating managers using MAD services use + * the same QKEY. + */ + + /* + * Mellanox workaround: + * The Q_KEY from the QP context must be used if the high bit is + * set in the Q_KEY part of the work request. See section 10.2.5 + * on Q_KEYS Compliance Statement C10-15. + * This must be enabled to permit future non special QP's to have + * MAD level service capability. To use SAR in a generic way. + */ + + /* + * p_mad_element->remote_qkey = IB_QP_PRIVILEGED_Q_KEY; + */ + + p_mad_element->remote_qkey = IB_QP1_WELL_KNOWN_Q_KEY; + p_mad_element->remote_lid = p_wc->recv.ud.remote_lid; + p_mad_element->remote_sl = p_wc->recv.ud.remote_sl; + p_mad_element->pkey_index = p_wc->recv.ud.pkey_index; + p_mad_element->path_bits = p_wc->recv.ud.path_bits; + p_mad_element->recv_opt = p_wc->recv.ud.recv_opt; + + p_mad_element->grh_valid = p_wc->recv.ud.recv_opt & IB_RECV_OPT_GRH_VALID; + + if( p_wc->recv.ud.recv_opt & IB_RECV_OPT_IMMEDIATE ) + p_mad_element->immediate_data = p_wc->recv.ud.immediate_data; + + AL_EXIT( AL_DBG_SMI ); +} + + + +/* + * + * MAD Dispatcher. + * + */ + + +ib_api_status_t +create_mad_disp( + IN al_obj_t* const p_parent_obj, + IN const ib_qp_handle_t h_qp, + IN al_mad_disp_handle_t* const ph_mad_disp ) +{ + al_mad_disp_handle_t h_mad_disp; + ib_api_status_t status; + cl_status_t cl_status; + + AL_ENTER( AL_DBG_MAD_SVC ); + h_mad_disp = cl_zalloc( sizeof( al_mad_disp_t ) ); + if( !h_mad_disp ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("insufficient memory\n") ); + return IB_INSUFFICIENT_MEMORY; + } + + /* Initialize the MAD dispatcher. */ + cl_vector_construct( &h_mad_disp->client_vector ); + cl_vector_construct( &h_mad_disp->version_vector ); + construct_al_obj( &h_mad_disp->obj, AL_OBJ_TYPE_MAD_DISP ); + status = init_al_obj( &h_mad_disp->obj, h_mad_disp, TRUE, + NULL, __cleanup_mad_disp, __free_mad_disp ); + if( status != IB_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("init obj: %s\n", + ib_get_err_str(status)) ); + __free_mad_disp( &h_mad_disp->obj ); + return status; + } + status = attach_al_obj( p_parent_obj, &h_mad_disp->obj ); + if( status != IB_SUCCESS ) + { + h_mad_disp->obj.pfn_destroy( &h_mad_disp->obj, NULL ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("attach_al_obj returned %s.\n", ib_get_err_str(status)) ); + return status; + } + + /* Obtain a reference to the QP to post sends to. */ + h_mad_disp->h_qp = h_qp; + ref_al_obj( &h_qp->obj ); + + /* Create the client vector. */ + cl_status = cl_vector_init( &h_mad_disp->client_vector, 1, MAD_VECTOR_SIZE, + sizeof( al_mad_disp_reg_t ), __init_mad_reg, NULL, h_mad_disp ); + if( cl_status != CL_SUCCESS ) + { + h_mad_disp->obj.pfn_destroy( &h_mad_disp->obj, NULL ); + return ib_convert_cl_status( cl_status ); + } + + /* Create the version vector. */ + cl_status = cl_vector_init( &h_mad_disp->version_vector, + 1, 1, sizeof( cl_vector_t ), __init_version_entry, + __destroy_version_entry, &h_mad_disp->version_vector ); + if( cl_status != CL_SUCCESS ) + { + h_mad_disp->obj.pfn_destroy( &h_mad_disp->obj, NULL ); + return ib_convert_cl_status( cl_status ); + } + + *ph_mad_disp = h_mad_disp; + + /* Release the reference taken in init_al_obj. */ + deref_al_obj( &h_mad_disp->obj ); + + AL_EXIT( AL_DBG_MAD_SVC ); + return IB_SUCCESS; +} + + + +static void +__cleanup_mad_disp( + IN al_obj_t *p_obj ) +{ + al_mad_disp_handle_t h_mad_disp; + + AL_ENTER( AL_DBG_MAD_SVC ); + CL_ASSERT( p_obj ); + h_mad_disp = PARENT_STRUCT( p_obj, al_mad_disp_t, obj ); + + /* Detach from the QP that we were using. */ + if( h_mad_disp->h_qp ) + deref_al_obj( &h_mad_disp->h_qp->obj ); + + AL_EXIT( AL_DBG_MAD_SVC ); +} + + + +static void +__free_mad_disp( + IN al_obj_t *p_obj ) +{ + al_mad_disp_handle_t h_mad_disp; + + AL_ENTER( AL_DBG_MAD_SVC ); + CL_ASSERT( p_obj ); + h_mad_disp = PARENT_STRUCT( p_obj, al_mad_disp_t, obj ); + + cl_vector_destroy( &h_mad_disp->client_vector ); + cl_vector_destroy( &h_mad_disp->version_vector ); + destroy_al_obj( p_obj ); + cl_free( h_mad_disp ); + AL_EXIT( AL_DBG_MAD_SVC ); +} + + + +static al_mad_reg_handle_t +__mad_disp_reg( + IN const al_mad_disp_handle_t h_mad_disp, + IN const ib_mad_svc_handle_t h_mad_svc, + IN const ib_mad_svc_t *p_mad_svc, + IN const pfn_mad_svc_send_done_t pfn_send_done, + IN const pfn_mad_svc_recv_done_t pfn_recv_done ) +{ + al_mad_reg_handle_t h_mad_reg; + size_t i; + cl_status_t cl_status; + + AL_ENTER( AL_DBG_MAD_SVC ); + cl_spinlock_acquire( &h_mad_disp->obj.lock ); + + /* Find an empty slot in the client vector for the registration. */ + for( i = 0; i < cl_vector_get_size( &h_mad_disp->client_vector ); i++ ) + { + h_mad_reg = cl_vector_get_ptr( &h_mad_disp->client_vector, i ); + if( !h_mad_reg->ref_cnt ) + break; + } + /* Trap for ClientID overflow. */ + if( i >= 0xFFFFFFFF ) + { + cl_spinlock_release( &h_mad_disp->obj.lock ); + return NULL; + } + cl_status = cl_vector_set_min_size( &h_mad_disp->client_vector, i+1 ); + if( cl_status != CL_SUCCESS ) + { + cl_spinlock_release( &h_mad_disp->obj.lock ); + return NULL; + } + h_mad_reg = cl_vector_get_ptr( &h_mad_disp->client_vector, i ); + + /* Record the registration. */ + h_mad_reg->client_id = (uint32_t)i; + h_mad_reg->support_unsol = p_mad_svc->support_unsol; + h_mad_reg->mgmt_class = p_mad_svc->mgmt_class; + h_mad_reg->mgmt_version = p_mad_svc->mgmt_version; + h_mad_reg->pfn_recv_done = pfn_recv_done; + h_mad_reg->pfn_send_done = pfn_send_done; + + /* If the client requires support for unsolicited MADs, add tracking. */ + if( p_mad_svc->support_unsol ) + { + if( !__mad_disp_reg_unsol( h_mad_disp, h_mad_reg, p_mad_svc ) ) + { + cl_spinlock_release( &h_mad_disp->obj.lock ); + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("reg unsol failed\n") ); + return NULL; + } + } + + /* Record that the registration was successful. */ + h_mad_reg->h_mad_svc = h_mad_svc; + h_mad_reg->ref_cnt = 1; + cl_spinlock_release( &h_mad_disp->obj.lock ); + + /* The MAD service needs to take a reference on the dispatcher. */ + ref_al_obj( &h_mad_disp->obj ); + + AL_EXIT( AL_DBG_MAD_SVC ); + return h_mad_reg; +} + + +static cl_status_t +__init_mad_reg( + IN void* const p_element, + IN void* context ) +{ + al_mad_reg_handle_t h_mad_reg; + + /* Record the MAD dispatcher for the registration structure. */ + h_mad_reg = p_element; + h_mad_reg->h_mad_disp = context; + h_mad_reg->ref_cnt = 0; + + return CL_SUCCESS; +} + + +/* + * Initialize an entry in the version vector. Each entry is a vector of + * classes. + */ +static cl_status_t +__init_version_entry( + IN void* const p_element, + IN void* context ) +{ + cl_vector_t *p_vector; + + p_vector = p_element; + UNUSED_PARAM( context ); + + cl_vector_construct( p_vector ); + return cl_vector_init( p_vector, MAD_VECTOR_SIZE, MAD_VECTOR_SIZE, + sizeof( cl_ptr_vector_t ), __init_class_entry, __destroy_class_entry, + p_vector ); +} + + +static void +__destroy_version_entry( + IN void* const p_element, + IN void* context ) +{ + cl_vector_t *p_vector; + + p_vector = p_element; + UNUSED_PARAM( context ); + + cl_vector_destroy( p_vector ); +} + + +/* + * Initialize an entry in the class vector. Each entry is a pointer vector + * of methods. + */ +static cl_status_t +__init_class_entry( + IN void* const p_element, + IN void* context ) +{ + cl_ptr_vector_t *p_ptr_vector; + + p_ptr_vector = p_element; + UNUSED_PARAM( context ); + + cl_ptr_vector_construct( p_ptr_vector ); + return cl_ptr_vector_init( p_ptr_vector, + MAD_VECTOR_SIZE, MAD_VECTOR_SIZE ); +} + + +static void +__destroy_class_entry( + IN void* const p_element, + IN void* context ) +{ + cl_ptr_vector_t *p_ptr_vector; + + p_ptr_vector = p_element; + UNUSED_PARAM( context ); + + cl_ptr_vector_destroy( p_ptr_vector ); +} + + +/* + * Add support for unsolicited MADs for the given MAD service. + */ +static boolean_t +__mad_disp_reg_unsol( + IN const al_mad_disp_handle_t h_mad_disp, + IN const al_mad_reg_handle_t h_mad_reg, + IN const ib_mad_svc_t *p_mad_svc ) +{ + cl_status_t cl_status; + cl_vector_t *p_class_vector; + cl_ptr_vector_t *p_method_ptr_vector; + uint8_t i; + + /* Ensure that we are ready to handle this version number. */ + AL_ENTER( AL_DBG_MAD_SVC ); + cl_status = cl_vector_set_min_size( &h_mad_disp->version_vector, + __mgmt_version_index( p_mad_svc->mgmt_version ) + 1 ); + if( cl_status != CL_SUCCESS ) + return FALSE; + + /* Get the list of classes in use for this version. */ + p_class_vector = cl_vector_get_ptr( &h_mad_disp->version_vector, + __mgmt_version_index( p_mad_svc->mgmt_version ) ); + + /* Ensure that we are ready to handle the specified class. */ + cl_status = cl_vector_set_min_size( p_class_vector, + __mgmt_class_index( p_mad_svc->mgmt_class ) + 1 ); + if( cl_status != CL_SUCCESS ) + return FALSE; + + /* Get the list of methods in use for this class. */ + p_method_ptr_vector = cl_vector_get_ptr( p_class_vector, + __mgmt_class_index( p_mad_svc->mgmt_class ) ); + + /* Ensure that we can handle all requested methods. */ + for( i = MAX_METHOD - 1; i > 0; i-- ) + { + if( p_mad_svc->method_array[i] ) + { + cl_status = cl_ptr_vector_set_min_size( p_method_ptr_vector, i+1 ); + if( cl_status != CL_SUCCESS ) + return FALSE; + + /* No one else can be registered for this method. */ + if( cl_ptr_vector_get( p_method_ptr_vector, i ) ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("Other client already registered for Un-Solicited Method " + "%u for version %u of class %u.\n", i, p_mad_svc->mgmt_version, + p_mad_svc->mgmt_class ) ); + return FALSE; + } + } + } + + /* We can support the request. Record the methods. */ + for( i = 0; i < MAX_METHOD; i++ ) + { + if( p_mad_svc->method_array[i] ) + { + cl_ptr_vector_set( p_method_ptr_vector, i, h_mad_reg ); + + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC, + ("Register version:%u (%u) class:0x%02X(%u) method:0x%02X Hdl:%p\n", + p_mad_svc->mgmt_version, + __mgmt_version_index( p_mad_svc->mgmt_version ), + p_mad_svc->mgmt_class, + __mgmt_class_index( p_mad_svc->mgmt_class ), + i, + h_mad_reg) ); + } + } + + AL_EXIT( AL_DBG_MAD_SVC ); + return TRUE; +} + + +static __inline uint8_t +__mgmt_version_index( + IN const uint8_t mgmt_version ) +{ + return (uint8_t)(mgmt_version - 1); +} + + +static __inline uint8_t +__mgmt_class_index( + IN const uint8_t mgmt_class ) +{ + /* Map class 0x81 to 0 to remove empty class values. */ + if( mgmt_class == IB_MCLASS_SUBN_DIR ) + return IB_MCLASS_SUBN_LID; + else + return mgmt_class; +} + + + +/* + * Deregister a MAD service from the dispatcher. + */ +static void +__mad_disp_dereg( + IN const al_mad_reg_handle_t h_mad_reg ) +{ + al_mad_disp_handle_t h_mad_disp; + cl_vector_t *p_class_vector; + cl_ptr_vector_t *p_method_ptr_vector; + size_t i; + + AL_ENTER( AL_DBG_MAD_SVC ); + h_mad_disp = h_mad_reg->h_mad_disp; + + cl_spinlock_acquire( &h_mad_disp->obj.lock ); + + if( h_mad_reg->support_unsol ) + { + /* Deregister the service from receiving unsolicited MADs. */ + p_class_vector = cl_vector_get_ptr( &h_mad_disp->version_vector, + __mgmt_version_index( h_mad_reg->mgmt_version ) ); + + p_method_ptr_vector = cl_vector_get_ptr( p_class_vector, + __mgmt_class_index( h_mad_reg->mgmt_class ) ); + + /* Deregister all methods registered to the client. */ + for( i = 0; i < cl_ptr_vector_get_size( p_method_ptr_vector ); i++ ) + { + if( cl_ptr_vector_get( p_method_ptr_vector, i ) == h_mad_reg ) + { + cl_ptr_vector_set( p_method_ptr_vector, i, NULL ); + } + } + } + + cl_spinlock_release( &h_mad_disp->obj.lock ); + + /* Decrement the reference count in the registration table. */ + cl_atomic_dec( &h_mad_reg->ref_cnt ); + + /* The MAD service no longer requires access to the MAD dispatcher. */ + deref_al_obj( &h_mad_disp->obj ); + AL_EXIT( AL_DBG_MAD_SVC ); +} + + + +static void +__mad_disp_queue_send( + IN const al_mad_reg_handle_t h_mad_reg, + IN al_mad_wr_t* const p_mad_wr ) +{ + ib_mad_t *p_mad_hdr; + + /* + * Increment the reference count on the registration to ensure that + * the MAD service does not go away until the send completes. + */ + AL_ENTER( AL_DBG_MAD_SVC ); + cl_atomic_inc( &h_mad_reg->ref_cnt ); + ref_al_obj( &h_mad_reg->h_mad_svc->obj ); + + /* Get the MAD header. */ + p_mad_hdr = get_mad_hdr_from_wr( p_mad_wr ); + CL_ASSERT( !p_mad_wr->send_wr.wr_id ); + p_mad_wr->send_wr.wr_id = (uintn_t)p_mad_wr; + + /* + * If we are the originator of the transaction, we need to modify the + * TID to ensure that duplicate TIDs are not used by multiple clients. + */ + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC, ("dispatching TID: 0x%I64x\n", + p_mad_hdr->trans_id) ); + p_mad_wr->client_tid = p_mad_hdr->trans_id; + if( __use_tid_routing( p_mad_hdr, TRUE ) ) + { + /* Clear the AL portion of the TID before setting. */ + ((al_tid_t*)&p_mad_hdr->trans_id)->tid32.al_tid = 0; + +#pragma warning( push, 3 ) + al_set_al_tid( &p_mad_hdr->trans_id, h_mad_reg->client_id ); +#pragma warning( pop ) + + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC, + ("modified TID to: 0x%0I64x\n", p_mad_hdr->trans_id) ); + } + + /* Post the work request to the QP. */ + p_mad_wr->client_id = h_mad_reg->client_id; + h_mad_reg->h_mad_disp->h_qp->pfn_queue_mad( + h_mad_reg->h_mad_disp->h_qp, p_mad_wr ); + + AL_EXIT( AL_DBG_MAD_SVC ); +} + + +static inline void +__mad_disp_resume_send( + IN const al_mad_reg_handle_t h_mad_reg ) +{ + AL_ENTER( AL_DBG_MAD_SVC ); + + h_mad_reg->h_mad_disp->h_qp->pfn_resume_mad( + h_mad_reg->h_mad_disp->h_qp ); + + AL_EXIT( AL_DBG_MAD_SVC ); +} + + +/* + * Complete a sent MAD. Route the completion to the correct MAD service. + */ +void +mad_disp_send_done( + IN al_mad_disp_handle_t h_mad_disp, + IN al_mad_wr_t *p_mad_wr, + IN ib_wc_t *p_wc ) +{ + al_mad_reg_handle_t h_mad_reg; + ib_mad_t *p_mad_hdr; + + AL_ENTER( AL_DBG_MAD_SVC ); + + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC, + ("p_mad_wr 0x%p\n", p_mad_wr ) ); + + /* Get the MAD header. */ + p_mad_hdr = get_mad_hdr_from_wr( p_mad_wr ); + + /* Get the MAD service that issued the send. */ + cl_spinlock_acquire( &h_mad_disp->obj.lock ); + h_mad_reg = cl_vector_get_ptr( &h_mad_disp->client_vector, + p_mad_wr->client_id ); + cl_spinlock_release( &h_mad_disp->obj.lock ); + CL_ASSERT( h_mad_reg && (h_mad_reg->client_id == p_mad_wr->client_id) ); + + /* Reset the TID and WR ID. */ + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC, ("send done TID: 0x%I64x\n", + p_mad_hdr->trans_id) ); + p_mad_hdr->trans_id = p_mad_wr->client_tid; + p_mad_wr->send_wr.wr_id = 0; + + /* Return the completed request to the MAD service. */ + CL_ASSERT( h_mad_reg->h_mad_svc ); + h_mad_reg->pfn_send_done( h_mad_reg->h_mad_svc, p_mad_wr, p_wc ); + + /* The MAD service is no longer referenced once the send completes. */ + deref_al_obj( &h_mad_reg->h_mad_svc->obj ); + cl_atomic_dec( &h_mad_reg->ref_cnt ); + + AL_EXIT( AL_DBG_MAD_SVC ); +} + + + +/* + * Process a received MAD. Route the completion to the correct MAD service. + */ +ib_api_status_t +mad_disp_recv_done( + IN al_mad_disp_handle_t h_mad_disp, + IN ib_mad_element_t *p_mad_element ) +{ + ib_mad_t *p_mad_hdr; + al_mad_reg_handle_t h_mad_reg; + ib_al_handle_t h_al; + ib_mad_svc_handle_t h_mad_svc; + + cl_vector_t *p_class_vector; + cl_ptr_vector_t *p_method_ptr_vector; + uint8_t method; + + AL_ENTER( AL_DBG_MAD_SVC ); + p_mad_hdr = ib_get_mad_buf( p_mad_element ); + + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC, + ("TID = 0x%I64x\n" + "class = 0x%x.\n" + "version = 0x%x.\n" + "method = 0x%x.\n", + p_mad_hdr->trans_id, + p_mad_hdr->mgmt_class, + p_mad_hdr->class_ver, + p_mad_hdr->method) ); + + /* Get the client to route the receive to. */ + cl_spinlock_acquire( &h_mad_disp->obj.lock ); + if( __use_tid_routing( p_mad_hdr, FALSE ) ) + { + /* The MAD was received in response to a send. */ + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC, ("routing based on TID\n")); + + /* Verify that we have a registration entry. */ + if( al_get_al_tid( p_mad_hdr->trans_id ) >= + cl_vector_get_size( &h_mad_disp->client_vector ) ) + { + /* No clients for this version-class-method. */ + cl_spinlock_release( &h_mad_disp->obj.lock ); + AL_PRINT_EXIT( TRACE_LEVEL_WARNING, AL_DBG_MAD_SVC, + ("invalid client ID\n") ); + return IB_NOT_FOUND; + } + + h_mad_reg = cl_vector_get_ptr( &h_mad_disp->client_vector, + al_get_al_tid( p_mad_hdr->trans_id ) ); + +/* + * Disable warning about passing unaligned 64-bit value. + * The value is always aligned given how buffers are allocated + * and given the layout of a MAD. + */ +#pragma warning( push, 3 ) + al_set_al_tid( &p_mad_hdr->trans_id, 0 ); +#pragma warning( pop ) + } + else + { + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC, + ("routing based on version, class, method\n")); + + /* The receive is unsolicited. Find the client. */ + if( __mgmt_version_index( p_mad_hdr->class_ver ) >= + cl_vector_get_size( &h_mad_disp->version_vector ) ) + { + /* No clients for this version of MADs. */ + cl_spinlock_release( &h_mad_disp->obj.lock ); + AL_PRINT_EXIT( TRACE_LEVEL_WARNING, AL_DBG_MAD_SVC, + ("no clients registered for this class version\n") ); + return IB_NOT_FOUND; + } + + /* See if we have a client for this class of MADs. */ + p_class_vector = cl_vector_get_ptr( &h_mad_disp->version_vector, + __mgmt_version_index( p_mad_hdr->class_ver ) ); + + if( __mgmt_class_index( p_mad_hdr->mgmt_class ) >= + cl_vector_get_size( p_class_vector ) ) + { + /* No clients for this version-class. */ + cl_spinlock_release( &h_mad_disp->obj.lock ); + AL_PRINT_EXIT( TRACE_LEVEL_WARNING, AL_DBG_MAD_SVC, + ("no clients registered for this class\n") ); + return IB_NOT_FOUND; + } + + /* See if we have a client for this method. */ + p_method_ptr_vector = cl_vector_get_ptr( p_class_vector, + __mgmt_class_index( p_mad_hdr->mgmt_class ) ); + method = (uint8_t)(p_mad_hdr->method & (~IB_MAD_METHOD_RESP_MASK)); + + if( method >= cl_ptr_vector_get_size( p_method_ptr_vector ) ) + { + /* No clients for this version-class-method. */ + cl_spinlock_release( &h_mad_disp->obj.lock ); + AL_PRINT_EXIT( TRACE_LEVEL_WARNING, AL_DBG_MAD_SVC, + ("no clients registered for this method-out of range\n") ); + return IB_NOT_FOUND; + } + + h_mad_reg = cl_ptr_vector_get( p_method_ptr_vector, method ); + if( !h_mad_reg ) + { + /* No clients for this version-class-method. */ + cl_spinlock_release( &h_mad_disp->obj.lock ); + AL_PRINT_EXIT( TRACE_LEVEL_WARNING, AL_DBG_MAD_SVC, + ("no clients registered for method %u of class %u(%u) version %u(%u)\n", + method, + p_mad_hdr->mgmt_class, + __mgmt_class_index( p_mad_hdr->mgmt_class ), + p_mad_hdr->class_ver, + __mgmt_version_index( p_mad_hdr->class_ver ) + ) ); + return IB_NOT_FOUND; + } + } + + /* Verify that the registration is still valid. */ + if( !h_mad_reg->ref_cnt ) + { + cl_spinlock_release( &h_mad_disp->obj.lock ); + AL_PRINT_EXIT( TRACE_LEVEL_WARNING, AL_DBG_MAD_SVC, + ("no client registered\n") ); + return IB_NOT_FOUND; + } + + /* Take a reference on the MAD service in case it deregisters. */ + h_mad_svc = h_mad_reg->h_mad_svc; + ref_al_obj( &h_mad_svc->obj ); + cl_spinlock_release( &h_mad_disp->obj.lock ); + + /* Handoff the MAD to the correct AL instance. */ + h_al = qp_get_al( (ib_qp_handle_t)(h_mad_svc->obj.p_parent_obj) ); + al_handoff_mad( h_al, p_mad_element ); + + h_mad_reg->pfn_recv_done( h_mad_svc, p_mad_element ); + deref_al_obj( &h_mad_svc->obj ); + AL_EXIT( AL_DBG_MAD_SVC ); + return IB_SUCCESS; +} + + + +/* + * Return TRUE if we should route the MAD to the recipient based on the TID. + */ +static boolean_t +__use_tid_routing( + IN const ib_mad_t* const p_mad_hdr, + IN const boolean_t are_we_sender ) +{ + boolean_t is_orig; + + AL_ENTER( AL_DBG_MAD_SVC ); + + /* CM MADs are never TID routed. */ + if( p_mad_hdr->mgmt_class == IB_MCLASS_COMM_MGMT ) + { + AL_EXIT( AL_DBG_MAD_SVC ); + return FALSE; + } + + if (are_we_sender) + is_orig = !ib_mad_is_response(p_mad_hdr); + else + is_orig = ib_mad_is_response(p_mad_hdr); + + AL_EXIT( AL_DBG_MAD_SVC ); + return is_orig; +} + + + +/* + * + * MAD Service. + * + */ + + + +/* + * Create and initialize a MAD service for use. + */ +ib_api_status_t +reg_mad_svc( + IN const ib_qp_handle_t h_qp, + IN const ib_mad_svc_t* const p_mad_svc, + OUT ib_mad_svc_handle_t* const ph_mad_svc ) +{ + ib_api_status_t status; + cl_status_t cl_status; + ib_mad_svc_handle_t h_mad_svc; + al_qp_alias_t *p_qp_alias; + ib_qp_attr_t qp_attr; + + AL_ENTER( AL_DBG_MAD_SVC ); + CL_ASSERT( h_qp ); + + switch( h_qp->type ) + { + case IB_QPT_QP0: + case IB_QPT_QP1: + case IB_QPT_QP0_ALIAS: + case IB_QPT_QP1_ALIAS: + case IB_QPT_MAD: + break; + + default: + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + if( !p_mad_svc || !ph_mad_svc ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + h_mad_svc = cl_zalloc( sizeof( al_mad_svc_t) ); + if( !h_mad_svc ) + { + return IB_INSUFFICIENT_MEMORY; + } + + /* Construct the MAD service. */ + construct_al_obj( &h_mad_svc->obj, AL_OBJ_TYPE_H_MAD_SVC ); + cl_timer_construct( &h_mad_svc->send_timer ); + cl_timer_construct( &h_mad_svc->recv_timer ); + cl_qlist_init( &h_mad_svc->send_list ); + cl_qlist_init( &h_mad_svc->recv_list ); + + p_qp_alias = PARENT_STRUCT( h_qp, al_qp_alias_t, qp ); + h_mad_svc->svc_type = p_mad_svc->svc_type; + h_mad_svc->obj.context = p_mad_svc->mad_svc_context; + h_mad_svc->pfn_user_recv_cb = p_mad_svc->pfn_mad_recv_cb; + h_mad_svc->pfn_user_send_cb = p_mad_svc->pfn_mad_send_cb; + + /* Initialize the MAD service. */ + status = init_al_obj( &h_mad_svc->obj, p_mad_svc->mad_svc_context, + TRUE, __destroying_mad_svc, __cleanup_mad_svc, free_mad_svc ); + if( status != IB_SUCCESS ) + { + free_mad_svc( &h_mad_svc->obj ); + return status; + } + status = attach_al_obj( &h_qp->obj, &h_mad_svc->obj ); + if( status != IB_SUCCESS ) + { + h_mad_svc->obj.pfn_destroy( &h_mad_svc->obj, NULL ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("attach_al_obj returned %s.\n", ib_get_err_str(status)) ); + return status; + } + + h_mad_svc->h_mad_reg = __mad_disp_reg( p_qp_alias->h_mad_disp, + h_mad_svc, p_mad_svc, __mad_svc_send_done, __mad_svc_recv_done ); + if( !h_mad_svc->h_mad_reg ) + { + h_mad_svc->obj.pfn_destroy( &h_mad_svc->obj, NULL ); + return IB_INSUFFICIENT_MEMORY; + } + + /* Record which port this MAD service uses, to use when creating AVs. */ + status = ib_query_qp( h_qp, &qp_attr ); + if( status != IB_SUCCESS ) + { + h_mad_svc->obj.pfn_destroy( &h_mad_svc->obj, NULL ); + return status; + } + h_mad_svc->h_pd = qp_attr.h_pd; + h_mad_svc->port_num = qp_attr.primary_port; + + cl_status = cl_timer_init( &h_mad_svc->send_timer, + __send_timer_cb, h_mad_svc ); + if( cl_status != CL_SUCCESS ) + { + h_mad_svc->obj.pfn_destroy( &h_mad_svc->obj, NULL ); + return ib_convert_cl_status( cl_status ); + } + + cl_status = cl_timer_init( &h_mad_svc->recv_timer, + __recv_timer_cb, h_mad_svc ); + if( cl_status != CL_SUCCESS ) + { + h_mad_svc->obj.pfn_destroy( &h_mad_svc->obj, NULL ); + return ib_convert_cl_status( cl_status ); + } + + *ph_mad_svc = h_mad_svc; + + AL_EXIT( AL_DBG_MAD_SVC ); + return IB_SUCCESS; +} + + + +static void +__destroying_mad_svc( + IN struct _al_obj *p_obj ) +{ + ib_qp_handle_t h_qp; + ib_mad_svc_handle_t h_mad_svc; + ib_mad_send_handle_t h_send; + cl_list_item_t *p_list_item; + int32_t timeout_ms; +#ifdef CL_KERNEL + KIRQL old_irql; +#endif + + AL_ENTER( AL_DBG_MAD_SVC ); + CL_ASSERT( p_obj ); + h_mad_svc = PARENT_STRUCT( p_obj, al_mad_svc_t, obj ); + + /* Deregister the MAD service. */ + h_qp = (ib_qp_handle_t)p_obj->p_parent_obj; + if( h_qp->pfn_dereg_mad_svc ) + h_qp->pfn_dereg_mad_svc( h_mad_svc ); + + /* Wait here until the MAD service is no longer in use. */ + timeout_ms = (int32_t)h_mad_svc->obj.timeout_ms; + while( h_mad_svc->ref_cnt && timeout_ms > 0 ) + { + /* Use a timeout to avoid waiting forever - just in case. */ + cl_thread_suspend( 10 ); + timeout_ms -= 10; + } + + /* + * Deregister from the MAD dispatcher. The MAD dispatcher holds + * a reference on the MAD service when invoking callbacks. Since we + * issue sends, we know how many callbacks are expected for send + * completions. With receive completions, we need to wait until all + * receive callbacks have completed before cleaning up receives. + */ + if( h_mad_svc->h_mad_reg ) + __mad_disp_dereg( h_mad_svc->h_mad_reg ); + + /* Cancel all outstanding send requests. */ + cl_spinlock_acquire( &h_mad_svc->obj.lock ); + for( p_list_item = cl_qlist_head( &h_mad_svc->send_list ); + p_list_item != cl_qlist_end( &h_mad_svc->send_list ); + p_list_item = cl_qlist_next( p_list_item ) ) + { + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC, ("canceling MAD\n") ); + h_send = PARENT_STRUCT( p_list_item, al_mad_send_t, pool_item ); + h_send->canceled = TRUE; + } + cl_spinlock_release( &h_mad_svc->obj.lock ); + + /* + * Invoke the timer callback to return the canceled MADs to the user. + * Since the MAD service is being destroyed, the user cannot be issuing + * sends. + */ + if( h_mad_svc->h_mad_reg ) + { +#ifdef CL_KERNEL + old_irql = KeRaiseIrqlToDpcLevel(); +#endif + __check_send_queue( h_mad_svc ); +#ifdef CL_KERNEL + KeLowerIrql( old_irql ); +#endif + } + + cl_timer_destroy( &h_mad_svc->send_timer ); + +#ifdef CL_KERNEL + /* + * Reclaim any pending receives sent to the proxy for UAL. + */ + if( h_mad_svc->obj.h_al->p_context ) + { + cl_qlist_t *p_cblist; + al_proxy_cb_info_t *p_cb_info; + + cl_spinlock_acquire( &h_mad_svc->obj.h_al->p_context->cb_lock ); + p_cblist = &h_mad_svc->obj.h_al->p_context->misc_cb_list; + p_list_item = cl_qlist_head( p_cblist ); + while( p_list_item != cl_qlist_end( p_cblist ) ) + { + p_cb_info = (al_proxy_cb_info_t*)p_list_item; + p_list_item = cl_qlist_next( p_list_item ); + + if( p_cb_info->p_al_obj && p_cb_info->p_al_obj == &h_mad_svc->obj ) + { + cl_qlist_remove_item( p_cblist, &p_cb_info->pool_item.list_item ); + deref_al_obj( p_cb_info->p_al_obj ); + proxy_cb_put( p_cb_info ); + } + } + cl_spinlock_release( &h_mad_svc->obj.h_al->p_context->cb_lock ); + } +#endif + + AL_EXIT( AL_DBG_MAD_SVC ); +} + + + +static void +__cleanup_mad_svc( + IN struct _al_obj *p_obj ) +{ + ib_mad_svc_handle_t h_mad_svc; + al_mad_rmpp_t *p_rmpp; + cl_list_item_t *p_list_item; + + CL_ASSERT( p_obj ); + h_mad_svc = PARENT_STRUCT( p_obj, al_mad_svc_t, obj ); + + /* + * There are no more callbacks from the MAD dispatcher that are active. + * Cleanup any receives that may still be lying around. Stop the receive + * timer to avoid synchronizing with it. + */ + cl_timer_destroy( &h_mad_svc->recv_timer ); + for( p_list_item = cl_qlist_head( &h_mad_svc->recv_list ); + p_list_item != cl_qlist_end( &h_mad_svc->recv_list ); + p_list_item = cl_qlist_next( p_list_item ) ) + { + p_rmpp = PARENT_STRUCT( p_list_item, al_mad_rmpp_t, pool_item ); + p_rmpp->inactive = TRUE; + } + __recv_timer_cb( h_mad_svc ); + + CL_ASSERT( cl_is_qlist_empty( &h_mad_svc->send_list ) ); + CL_ASSERT( cl_is_qlist_empty( &h_mad_svc->recv_list ) ); +} + + + +void +free_mad_svc( + IN al_obj_t *p_obj ) +{ + ib_mad_svc_handle_t h_mad_svc; + + CL_ASSERT( p_obj ); + h_mad_svc = PARENT_STRUCT( p_obj, al_mad_svc_t, obj ); + + destroy_al_obj( p_obj ); + cl_free( h_mad_svc ); +} + + + +ib_api_status_t +ib_send_mad( + IN const ib_mad_svc_handle_t h_mad_svc, + IN ib_mad_element_t* const p_mad_element_list, + OUT ib_mad_element_t **pp_mad_failure OPTIONAL ) +{ + ib_api_status_t status = IB_SUCCESS; +#ifdef CL_KERNEL + ib_mad_send_handle_t h_send; + ib_mad_element_t *p_cur_mad, *p_next_mad; +#endif + + AL_ENTER( AL_DBG_MAD_SVC ); + + if( AL_OBJ_INVALID_HANDLE( h_mad_svc, AL_OBJ_TYPE_H_MAD_SVC ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_HANDLE\n") ); + return IB_INVALID_HANDLE; + } + if( !p_mad_element_list || + ( p_mad_element_list->p_next && !pp_mad_failure ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + +#ifndef CL_KERNEL + /* This is a send from user mode using special QP alias */ + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC, + ("ib_send_mad: ual_context non-zero, TID = 0x%I64x.\n", + ((ib_mad_t*)(ib_get_mad_buf( p_mad_element_list )))->trans_id )); + status = spl_qp_mad_send( h_mad_svc, p_mad_element_list, + pp_mad_failure ); + AL_EXIT( AL_DBG_MAD_SVC ); + return status; +#else + /* Post each send on the list. */ + p_cur_mad = p_mad_element_list; + while( p_cur_mad ) + { + p_next_mad = p_cur_mad->p_next; + + /* Get an element to track the send. */ + h_send = get_mad_send( PARENT_STRUCT( p_cur_mad, + al_mad_element_t, element ) ); + if( !h_send ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("unable to get mad_send\n") ); + if( pp_mad_failure ) + *pp_mad_failure = p_cur_mad; + return IB_INSUFFICIENT_RESOURCES; + } + + /* Initialize the MAD for sending. */ + status = __init_send_mad( h_mad_svc, h_send, p_cur_mad ); + if( status != IB_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("init_send_mad failed: %s\n", + ib_get_err_str(status)) ); + put_mad_send( h_send ); + if( pp_mad_failure ) + *pp_mad_failure = p_cur_mad; + return status; + } + + /* Add the MADs to our list. */ + cl_spinlock_acquire( &h_mad_svc->obj.lock ); + cl_qlist_insert_tail( &h_mad_svc->send_list, + (cl_list_item_t*)&h_send->pool_item ); + + /* Post the MAD to the dispatcher, and check for failures. */ + ref_al_obj( &h_mad_svc->obj ); + p_cur_mad->p_next = NULL; + if( h_send->uses_rmpp ) + __queue_rmpp_seg( h_mad_svc->h_mad_reg, h_send ); + else + __queue_mad_wr( h_mad_svc->h_mad_reg, h_send ); + cl_spinlock_release( &h_mad_svc->obj.lock ); + + p_cur_mad = p_next_mad; + } + + /* + * Resume any sends that can now be sent without holding + * the mad service lock. + */ + __mad_disp_resume_send( h_mad_svc->h_mad_reg ); + + AL_EXIT( AL_DBG_MAD_SVC ); + return status; +#endif +} + + + +static ib_api_status_t +__init_send_mad( + IN ib_mad_svc_handle_t h_mad_svc, + IN const ib_mad_send_handle_t h_send, + IN ib_mad_element_t* const p_mad_element ) +{ + ib_rmpp_mad_t *p_rmpp_hdr; + uint8_t rmpp_version; + ib_api_status_t status; + + AL_ENTER( AL_DBG_MAD_SVC ); + + /* Initialize tracking the send. */ + h_send->p_send_mad = p_mad_element; + h_send->retry_time = MAX_TIME; + h_send->retry_cnt = p_mad_element->retry_cnt; + + /* See if the send uses RMPP. */ + h_send->uses_rmpp = __does_send_req_rmpp( h_mad_svc->svc_type, + p_mad_element, &rmpp_version ); + if( h_send->uses_rmpp ) + { + /* The RMPP header is present. */ + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC, ("RMPP is activated\n") ); + p_rmpp_hdr = (ib_rmpp_mad_t*)p_mad_element->p_mad_buf; + + /* We only support version 1. */ + if( rmpp_version != DEFAULT_RMPP_VERSION ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("unsupported version\n") ); + return IB_INVALID_SETTING; + } + + if( !p_mad_element->timeout_ms ) + p_mad_element->timeout_ms = AL_REASSEMBLY_TIMEOUT; + + if( !h_send->retry_cnt ) + h_send->retry_cnt = AL_RMPP_RETRIES; + + p_rmpp_hdr->rmpp_version = rmpp_version; + p_rmpp_hdr->rmpp_type = IB_RMPP_TYPE_DATA; + ib_rmpp_set_resp_time( p_rmpp_hdr, IB_RMPP_NO_RESP_TIME ); + p_rmpp_hdr->rmpp_status = IB_RMPP_STATUS_SUCCESS; + /* + * The segment number, flags, and payload size are set when + * sending, so that they are set correctly when issuing retries. + */ + + h_send->ack_seg = 0; + h_send->seg_limit = 1; + h_send->cur_seg = 1; + /* For SA RMPP MADS we need different data size and header size */ + if( p_mad_element->p_mad_buf->mgmt_class == IB_MCLASS_SUBN_ADM ) + { + h_send->total_seg = ( (p_mad_element->size - IB_SA_MAD_HDR_SIZE) + + (IB_SA_DATA_SIZE - 1) ) / IB_SA_DATA_SIZE; + } + else + { + h_send->total_seg = ( (p_mad_element->size - MAD_RMPP_HDR_SIZE) + + (MAD_RMPP_DATA_SIZE - 1) ) / MAD_RMPP_DATA_SIZE; + } + /*for cases that there is no data we still need 1 seg */ + h_send->total_seg = h_send->total_seg?h_send->total_seg:1; + } + + /* See if we need to create the address vector for the user. + We also create AV for local send to pass the slid and grh in case of trap generation*/ + if( !p_mad_element->h_av){ + + status = __create_send_av( h_mad_svc, h_send ); + if( status != IB_SUCCESS ) + { + return status; + } + } + + AL_EXIT( AL_DBG_MAD_SVC ); + return IB_SUCCESS; +} + + + +static ib_api_status_t +__create_send_av( + IN ib_mad_svc_handle_t h_mad_svc, + IN ib_mad_send_handle_t h_send ) +{ + ib_av_attr_t av_attr; + ib_mad_element_t *p_mad_element; + + p_mad_element = h_send->p_send_mad; + + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC, + ("class %d attr %d AV attr: port num %d, sl %d, dlid %d, path bits %d", + p_mad_element->p_mad_buf->mgmt_class, + p_mad_element->p_mad_buf->attr_id, + h_mad_svc->port_num, + p_mad_element->remote_sl, + p_mad_element->remote_lid, + p_mad_element->path_bits) + ); + + av_attr.port_num = h_mad_svc->port_num; + + av_attr.sl = p_mad_element->remote_sl; + av_attr.dlid = p_mad_element->remote_lid; + + av_attr.grh_valid = p_mad_element->grh_valid; + if( av_attr.grh_valid ) + { + av_attr.grh = *p_mad_element->p_grh; + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC, + ("ver_class_flow %08x, hop lmt %d, src gid %16I64x%16I64x, dest gid %16I64x%16I64x", + av_attr.grh.ver_class_flow, + av_attr.grh.hop_limit, + cl_ntoh64( av_attr.grh.src_gid.unicast.prefix ), + cl_ntoh64( av_attr.grh.src_gid.unicast.interface_id ), + cl_ntoh64( av_attr.grh.dest_gid.unicast.prefix ), + cl_ntoh64( av_attr.grh.dest_gid.unicast.interface_id )) + ); + } + + av_attr.static_rate = IB_PATH_RECORD_RATE_10_GBS; + av_attr.path_bits = p_mad_element->path_bits; + + return ib_create_av( h_mad_svc->h_pd, &av_attr, &h_send->h_av ); +} + + + +static boolean_t +__does_send_req_rmpp( + IN const ib_mad_svc_type_t mad_svc_type, + IN const ib_mad_element_t* const p_mad_element, + OUT uint8_t *p_rmpp_version ) +{ + switch( mad_svc_type ) + { + case IB_MAD_SVC_DEFAULT: + case IB_MAD_SVC_RMPP: + /* Internally generated MADs do not use RMPP. */ + if( __is_internal_send( mad_svc_type, p_mad_element ) ) + return FALSE; + + /* If the MAD has the version number set, just return it. */ + if( p_mad_element->rmpp_version ) + { + *p_rmpp_version = p_mad_element->rmpp_version; + return TRUE; + } + + /* If the class is well known and uses RMPP, use the default version. */ + if( p_mad_element->p_mad_buf->mgmt_class == IB_MCLASS_SUBN_ADM ) + { + switch( p_mad_element->p_mad_buf->method ) + { + case IB_MAD_METHOD_GETTABLE_RESP: + case IB_MAD_METHOD_GETMULTI: + case IB_MAD_METHOD_GETMULTI_RESP: + *p_rmpp_version = DEFAULT_RMPP_VERSION; + return TRUE; + + default: + return FALSE; + } + } + if (ib_class_is_vendor_specific_high(p_mad_element->p_mad_buf->mgmt_class) && + ib_rmpp_is_flag_set((ib_rmpp_mad_t *) p_mad_element->p_mad_buf, + IB_RMPP_FLAG_ACTIVE)) + { + *p_rmpp_version = DEFAULT_RMPP_VERSION; + return TRUE; + } + + /* The RMPP is not active. */ + return FALSE; + + default: + return FALSE; + } +} + + + +/* + * Sends the next RMPP segment of an RMPP transfer. + */ +static void +__queue_rmpp_seg( + IN const al_mad_reg_handle_t h_mad_reg, + IN ib_mad_send_handle_t h_send ) +{ + ib_rmpp_mad_t *p_rmpp_hdr; + + AL_ENTER( AL_DBG_MAD_SVC ); + + CL_ASSERT( h_mad_reg && h_send ); + CL_ASSERT( h_send->cur_seg <= h_send->seg_limit ); + + /* Reset information to track the send. */ + h_send->retry_time = MAX_TIME; + + /* Set the RMPP header information. */ + p_rmpp_hdr = (ib_rmpp_mad_t*)h_send->p_send_mad->p_mad_buf; + p_rmpp_hdr->seg_num = cl_hton32( h_send->cur_seg ); + p_rmpp_hdr->rmpp_flags = IB_RMPP_FLAG_ACTIVE; + p_rmpp_hdr->paylen_newwin = 0; + + /* See if this is the first segment that needs to be sent. */ + if( h_send->cur_seg == 1 ) + { + p_rmpp_hdr->rmpp_flags |= IB_RMPP_FLAG_FIRST; + + /* + * Since the RMPP layer is the one to support SA MADs by duplicating + * the SA header. The actual Payload Length should include the + * original mad size + NumSegs * SA-extra-header. + */ + if( h_send->p_send_mad->p_mad_buf->mgmt_class == IB_MCLASS_SUBN_ADM ) + { + /* Add sa_ext_hdr to each segment over the first one. */ + p_rmpp_hdr->paylen_newwin = cl_hton32( + h_send->p_send_mad->size - MAD_RMPP_HDR_SIZE + + (h_send->total_seg - 1) * + (IB_SA_MAD_HDR_SIZE - MAD_RMPP_HDR_SIZE) ); + } + else + { + /* For other RMPP packets we simply use the given MAD */ + p_rmpp_hdr->paylen_newwin = cl_hton32( h_send->p_send_mad->size - + MAD_RMPP_HDR_SIZE ); + } + } + + /* See if this is the last segment that needs to be sent. */ + if( h_send->cur_seg == h_send->total_seg ) + { + p_rmpp_hdr->rmpp_flags |= IB_RMPP_FLAG_LAST; + + /* But for SA MADs we need extra header size */ + if( h_send->p_send_mad->p_mad_buf->mgmt_class == IB_MCLASS_SUBN_ADM ) + { + p_rmpp_hdr->paylen_newwin = cl_hton32( h_send->p_send_mad->size - + (h_send->cur_seg -1)*IB_SA_DATA_SIZE - MAD_RMPP_HDR_SIZE ); + } + else + { + p_rmpp_hdr->paylen_newwin = cl_hton32( h_send->p_send_mad->size - + (h_send->cur_seg -1)*MAD_RMPP_DATA_SIZE ); + } + } + + /* Set the current segment to the next one. */ + h_send->cur_seg++; + + /* Send the MAD. */ + __queue_mad_wr( h_mad_reg, h_send ); + + AL_EXIT( AL_DBG_MAD_SVC ); +} + + + +/* + * Posts a send work request to the dispatcher for a MAD send. + */ +static void +__queue_mad_wr( + IN const al_mad_reg_handle_t h_mad_reg, + IN const ib_mad_send_handle_t h_send ) +{ + ib_send_wr_t *p_send_wr; + al_mad_element_t *p_al_element; + ib_rmpp_mad_t *p_rmpp_hdr; + uint8_t *p_rmpp_src, *p_rmpp_dst; + uintn_t hdr_len, offset, max_len; + + AL_ENTER( AL_DBG_MAD_SVC ); + p_send_wr = &h_send->mad_wr.send_wr; + + cl_memclr( p_send_wr, sizeof( ib_send_wr_t ) ); + + p_send_wr->wr_type = WR_SEND; + p_send_wr->send_opt = h_send->p_send_mad->send_opt; + + p_al_element = PARENT_STRUCT( h_send->p_send_mad, + al_mad_element_t, element ); + + /* See if the MAD requires RMPP support. */ + if( h_send->uses_rmpp && p_al_element->p_al_mad_buf ) + { +#if defined( CL_KERNEL ) + p_rmpp_dst = p_al_element->mad_buf + sizeof(ib_grh_t); +#else + p_rmpp_dst = (uint8_t*)(uintn_t)p_al_element->mad_ds.vaddr; +#endif + p_rmpp_src = (uint8_t*)h_send->p_send_mad->p_mad_buf; + p_rmpp_hdr = (ib_rmpp_mad_t*)p_rmpp_src; + + if( h_send->p_send_mad->p_mad_buf->mgmt_class == IB_MCLASS_SUBN_ADM ) + hdr_len = IB_SA_MAD_HDR_SIZE; + else + hdr_len = MAD_RMPP_HDR_SIZE; + + max_len = MAD_BLOCK_SIZE - hdr_len; + + offset = hdr_len + (max_len * (cl_ntoh32( p_rmpp_hdr->seg_num ) - 1)); + + /* Copy the header into the registered send buffer. */ + cl_memcpy( p_rmpp_dst, p_rmpp_src, hdr_len ); + + /* Copy this segment's payload into the registered send buffer. */ + CL_ASSERT( h_send->p_send_mad->size != offset ); + if( (h_send->p_send_mad->size - offset) < max_len ) + { + max_len = h_send->p_send_mad->size - offset; + /* Clear unused payload. */ + cl_memclr( p_rmpp_dst + hdr_len + max_len, + MAD_BLOCK_SIZE - hdr_len - max_len ); + } + + cl_memcpy( + p_rmpp_dst + hdr_len, p_rmpp_src + offset, max_len ); + } + + p_send_wr->num_ds = 1; + p_send_wr->ds_array = &p_al_element->mad_ds; + + p_send_wr->dgrm.ud.remote_qp = h_send->p_send_mad->remote_qp; + p_send_wr->dgrm.ud.remote_qkey = h_send->p_send_mad->remote_qkey; + p_send_wr->dgrm.ud.pkey_index = h_send->p_send_mad->pkey_index; + + /* See if we created the address vector on behalf of the user. */ + if( h_send->p_send_mad->h_av ) + p_send_wr->dgrm.ud.h_av = h_send->p_send_mad->h_av; + else + p_send_wr->dgrm.ud.h_av = h_send->h_av; + + __mad_disp_queue_send( h_mad_reg, &h_send->mad_wr ); + + AL_EXIT( AL_DBG_MAD_SVC ); +} + + + +static cl_status_t +__mad_svc_find_send( + IN const cl_list_item_t* const p_list_item, + IN void* context ) +{ + ib_mad_send_handle_t h_send; + + h_send = PARENT_STRUCT( p_list_item, al_mad_send_t, pool_item ); + + if( h_send->p_send_mad == context ) + return CL_SUCCESS; + else + return CL_NOT_FOUND; +} + + + +ib_api_status_t +ib_cancel_mad( + IN const ib_mad_svc_handle_t h_mad_svc, + IN ib_mad_element_t* const p_mad_element ) +{ +#ifdef CL_KERNEL + cl_list_item_t *p_list_item; + ib_mad_send_handle_t h_send; +#else + ib_api_status_t status; +#endif + + AL_ENTER( AL_DBG_MAD_SVC ); + + if( AL_OBJ_INVALID_HANDLE( h_mad_svc, AL_OBJ_TYPE_H_MAD_SVC ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_HANDLE\n") ); + return IB_INVALID_HANDLE; + } + if( !p_mad_element ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + +#ifndef CL_KERNEL + /* This is a send from user mode using special QP alias */ + status = spl_qp_cancel_mad( h_mad_svc, p_mad_element ); + AL_EXIT( AL_DBG_MAD_SVC ); + return status; +#else + /* Search for the MAD in our MAD list. It may have already completed. */ + cl_spinlock_acquire( &h_mad_svc->obj.lock ); + p_list_item = cl_qlist_find_from_head( &h_mad_svc->send_list, + __mad_svc_find_send, p_mad_element ); + + if( p_list_item == cl_qlist_end( &h_mad_svc->send_list ) ) + { + cl_spinlock_release( &h_mad_svc->obj.lock ); + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC, ("mad not found\n") ); + return IB_NOT_FOUND; + } + + /* Mark the MAD as having been canceled. */ + h_send = PARENT_STRUCT( p_list_item, al_mad_send_t, pool_item ); + h_send->canceled = TRUE; + + /* If the MAD is active, process it in the send callback. */ + if( h_send->retry_time != MAX_TIME ) + { + /* Process the canceled MAD using the timer thread. */ + cl_timer_trim( &h_mad_svc->send_timer, 0 ); + } + + cl_spinlock_release( &h_mad_svc->obj.lock ); + AL_EXIT( AL_DBG_MAD_SVC ); + return IB_SUCCESS; +#endif +} + + +ib_api_status_t +ib_delay_mad( + IN const ib_mad_svc_handle_t h_mad_svc, + IN ib_mad_element_t* const p_mad_element, + IN const uint32_t delay_ms ) +{ +#ifdef CL_KERNEL + cl_list_item_t *p_list_item; + ib_mad_send_handle_t h_send; +#endif + + AL_ENTER( AL_DBG_MAD_SVC ); + + if( AL_OBJ_INVALID_HANDLE( h_mad_svc, AL_OBJ_TYPE_H_MAD_SVC ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_HANDLE\n") ); + return IB_INVALID_HANDLE; + } + if( !p_mad_element ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + +#ifndef CL_KERNEL + UNUSED_PARAM( p_mad_element ); + UNUSED_PARAM( delay_ms ); + /* TODO: support for user-mode MAD QP's. */ + AL_EXIT( AL_DBG_MAD_SVC ); + return IB_UNSUPPORTED; +#else + /* Search for the MAD in our MAD list. It may have already completed. */ + cl_spinlock_acquire( &h_mad_svc->obj.lock ); + p_list_item = cl_qlist_find_from_head( &h_mad_svc->send_list, + __mad_svc_find_send, p_mad_element ); + + if( p_list_item == cl_qlist_end( &h_mad_svc->send_list ) ) + { + cl_spinlock_release( &h_mad_svc->obj.lock ); + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC, ("MAD not found\n") ); + return IB_NOT_FOUND; + } + + /* Mark the MAD as having been canceled. */ + h_send = PARENT_STRUCT( p_list_item, al_mad_send_t, pool_item ); + + if( h_send->retry_time == MAX_TIME ) + h_send->delay = delay_ms; + else + h_send->retry_time += ((uint64_t)delay_ms * 1000Ui64); + + cl_spinlock_release( &h_mad_svc->obj.lock ); + AL_EXIT( AL_DBG_MAD_SVC ); + return IB_SUCCESS; +#endif +} + + +/* + * Process a send completion. + */ +static void +__mad_svc_send_done( + IN ib_mad_svc_handle_t h_mad_svc, + IN al_mad_wr_t *p_mad_wr, + IN ib_wc_t *p_wc ) +{ + ib_mad_send_handle_t h_send; + + AL_ENTER( AL_DBG_MAD_SVC ); + CL_ASSERT( h_mad_svc && p_mad_wr && !p_wc->p_next ); + + h_send = PARENT_STRUCT( p_mad_wr, al_mad_send_t, mad_wr ); + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC, ("send callback TID:0x%I64x\n", + __get_send_tid( h_send )) ); + + /* We need to synchronize access to the list as well as the MAD request. */ + cl_spinlock_acquire( &h_mad_svc->obj.lock ); + + /* Complete internally sent MADs. */ + if( __is_internal_send( h_mad_svc->svc_type, h_send->p_send_mad ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_WARNING, AL_DBG_MAD_SVC, ("internal send\n") ); + cl_qlist_remove_item( &h_mad_svc->send_list, + (cl_list_item_t*)&h_send->pool_item ); + cl_spinlock_release( &h_mad_svc->obj.lock ); + ib_put_mad( h_send->p_send_mad ); + __cleanup_mad_send( h_mad_svc, h_send ); + return; + } + + /* See if the send request has completed. */ + if( __is_send_mad_done( h_send, p_wc->status ) ) + { + /* The send has completed. */ + cl_qlist_remove_item( &h_mad_svc->send_list, + (cl_list_item_t*)&h_send->pool_item ); + cl_spinlock_release( &h_mad_svc->obj.lock ); + + /* Report the send as canceled only if we don't have the response. */ + if( h_send->canceled && !h_send->p_resp_mad ) + __notify_send_comp( h_mad_svc, h_send, IB_WCS_CANCELED ); + else + __notify_send_comp( h_mad_svc, h_send, p_wc->status ); + } + else + { + /* See if this is an RMPP MAD, and we should send more segments. */ + if( h_send->uses_rmpp && (h_send->cur_seg <= h_send->seg_limit) ) + { + /* Send the next segment. */ + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC, + ("sending next RMPP segment for TID:0x%I64x\n", + __get_send_tid( h_send )) ); + + __queue_rmpp_seg( h_mad_svc->h_mad_reg, h_send ); + } + else + { + /* Continue waiting for a response or ACK. */ + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC, + ("waiting for response for TID:0x%I64x\n", + __get_send_tid( h_send )) ); + + __set_retry_time( h_send ); + cl_timer_trim( &h_mad_svc->send_timer, + h_send->p_send_mad->timeout_ms ); + } + cl_spinlock_release( &h_mad_svc->obj.lock ); + } + + /* + * Resume any sends that can now be sent without holding + * the mad service lock. + */ + __mad_disp_resume_send( h_mad_svc->h_mad_reg ); + + AL_EXIT( AL_DBG_MAD_SVC ); +} + + + +/* + * Notify the user of a completed send operation. + */ +static void +__notify_send_comp( + IN ib_mad_svc_handle_t h_mad_svc, + IN ib_mad_send_handle_t h_send, + IN ib_wc_status_t wc_status ) +{ + AL_ENTER( AL_DBG_MAD_SVC ); + + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC, ("completing TID:0x%I64x\n", + __get_send_tid( h_send )) ); + + h_send->p_send_mad->status = wc_status; + + /* Notify the user of a received response, if one exists. */ + if( h_send->p_resp_mad ) + { + h_mad_svc->pfn_user_recv_cb( h_mad_svc, (void*)h_mad_svc->obj.context, + h_send->p_resp_mad ); + } + + /* The transaction has completed, return the send MADs. */ + h_mad_svc->pfn_user_send_cb( h_mad_svc, (void*)h_mad_svc->obj.context, + h_send->p_send_mad ); + + __cleanup_mad_send( h_mad_svc, h_send ); + + AL_EXIT( AL_DBG_MAD_SVC ); +} + + + +/* + * Return a send MAD tracking structure to its pool and cleanup any resources + * it may have allocated. + */ +static void +__cleanup_mad_send( + IN ib_mad_svc_handle_t h_mad_svc, + IN ib_mad_send_handle_t h_send ) +{ + /* Release any address vectors that we may have created. */ + if( h_send->h_av ) + { + ib_destroy_av( h_send->h_av ); + } + + /* Return the send MAD tracking structure to its pool. */ + put_mad_send( h_send ); + + /* We no longer need to reference the MAD service. */ + deref_al_obj( &h_mad_svc->obj ); +} + + + +static boolean_t +__is_send_mad_done( + IN ib_mad_send_handle_t h_send, + IN ib_wc_status_t status ) +{ + AL_ENTER( AL_DBG_MAD_SVC ); + + /* Complete the send if the request failed. */ + if( status != IB_WCS_SUCCESS ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("y-send failed\n" ) ); + return TRUE; + } + + /* Complete the send if it has been canceled. */ + if( h_send->canceled ) + { + AL_PRINT_EXIT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC, + ("y-send was canceled\n") ); + return TRUE; + } + + /* Complete the send if we have its response. */ + if( h_send->p_resp_mad ) + { + AL_PRINT_EXIT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC, + ("y-response received\n") ); + return TRUE; + } + + /* RMPP sends cannot complete until all segments have been acked. */ + if( h_send->uses_rmpp && (h_send->ack_seg < h_send->total_seg) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC, + ("more RMPP segments to send\n") ); + return FALSE; + } + + /* + * All segments of this send have been sent. + * The send has completed if we are not waiting for a response. + */ + if( h_send->p_send_mad->resp_expected ) + { + AL_PRINT_EXIT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC, + ("no-waiting on response\n") ); + return FALSE; + } + else + { + AL_PRINT_EXIT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC, + ("send completed\n") ); + return TRUE; + } +} + + + +/* + * Try to find a send that matches the received response. This call must + * be synchronized with access to the MAD service send_list. + */ +static ib_mad_send_handle_t +__mad_svc_match_recv( + IN const ib_mad_svc_handle_t h_mad_svc, + IN ib_mad_element_t* const p_recv_mad ) +{ + ib_mad_t *p_recv_hdr; + cl_list_item_t *p_list_item; + ib_mad_send_handle_t h_send; + + AL_ENTER( AL_DBG_MAD_SVC ); + + p_recv_hdr = p_recv_mad->p_mad_buf; + + /* Search the send list for a matching request. */ + for( p_list_item = cl_qlist_head( &h_mad_svc->send_list ); + p_list_item != cl_qlist_end( &h_mad_svc->send_list ); + p_list_item = cl_qlist_next( p_list_item ) ) + { + h_send = PARENT_STRUCT( p_list_item, al_mad_send_t, pool_item ); + + /* Match on the transaction ID, ignoring internally generated sends. */ + AL_EXIT( AL_DBG_MAD_SVC ); + if( al_get_user_tid(p_recv_hdr->trans_id) == + al_get_user_tid(h_send->mad_wr.client_tid) && + !__is_internal_send( h_mad_svc->svc_type, h_send->p_send_mad ) ) + { + return h_send; + } + } + + return NULL; +} + + + +static void +__mad_svc_recv_done( + IN ib_mad_svc_handle_t h_mad_svc, + IN ib_mad_element_t *p_mad_element ) +{ + ib_mad_t *p_mad_hdr; + ib_api_status_t cl_status; + + AL_ENTER( AL_DBG_MAD_SVC ); + + p_mad_hdr = ib_get_mad_buf( p_mad_element ); + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC, ("recv done TID:0x%I64x\n", + p_mad_hdr->trans_id) ); + + /* Raw MAD services get all receives. */ + if( h_mad_svc->svc_type == IB_MAD_SVC_RAW ) + { + /* Report the receive. */ + AL_PRINT_EXIT( TRACE_LEVEL_WARNING, AL_DBG_MAD_SVC, + ("recv TID:0x%I64x\n", p_mad_hdr->trans_id) ); + h_mad_svc->pfn_user_recv_cb( h_mad_svc, (void*)h_mad_svc->obj.context, + p_mad_element ); + return; + } + + /* Fully reassemble received MADs before completing them. */ + if( __recv_requires_rmpp( h_mad_svc->svc_type, p_mad_element ) ) + { + /* Reassembling the receive. */ + cl_status = __do_rmpp_recv( h_mad_svc, &p_mad_element ); + if( cl_status != CL_SUCCESS ) + { + /* The reassembly is not done. */ + AL_PRINT_EXIT( TRACE_LEVEL_WARNING, AL_DBG_MAD_SVC, + ("no RMPP receive to report\n") ); + return; + } + + /* + * Get the header to the MAD element to report to the user. This + * will be a MAD element received earlier. + */ + p_mad_hdr = ib_get_mad_buf( p_mad_element ); + } + + /* + * If the response indicates that the responder was busy, continue + * retrying the request. + */ + if( p_mad_hdr->status & IB_MAD_STATUS_BUSY ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("responder busy TID:0x%I64x\n", p_mad_hdr->trans_id) ); + ib_put_mad( p_mad_element ); + return; + } + + /* + * See if the MAD was sent in response to a previously sent MAD. + */ + if( ib_mad_is_response( p_mad_hdr ) ) + { + /* Process the received response. */ + __process_recv_resp( h_mad_svc, p_mad_element ); + } + else + { + /* Report the receive. */ + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC, ("unsol recv TID:0x%I64x\n", + p_mad_hdr->trans_id) ); + h_mad_svc->pfn_user_recv_cb( h_mad_svc, (void*)h_mad_svc->obj.context, + p_mad_element ); + } + AL_EXIT( AL_DBG_MAD_SVC ); +} + + + +/* + * A MAD was received in response to a send. Find the corresponding send + * and process the receive completion. + */ +static void +__process_recv_resp( + IN ib_mad_svc_handle_t h_mad_svc, + IN ib_mad_element_t *p_mad_element ) +{ + ib_mad_t *p_mad_hdr; + ib_mad_send_handle_t h_send; + + /* + * Try to find the send. The send may have already timed out or + * have been canceled, so we need to search for it. + */ + AL_ENTER( AL_DBG_MAD_SVC ); + p_mad_hdr = ib_get_mad_buf( p_mad_element ); + cl_spinlock_acquire( &h_mad_svc->obj.lock ); + + h_send = __mad_svc_match_recv( h_mad_svc, p_mad_element ); + if( !h_send ) + { + /* A matching send was not found. */ + AL_PRINT_EXIT( TRACE_LEVEL_WARNING, AL_DBG_MAD_SVC, + ("unmatched resp TID:0x%I64x\n", p_mad_hdr->trans_id) ); + cl_spinlock_release( &h_mad_svc->obj.lock ); + ib_put_mad( p_mad_element ); + return; + } + + /* We've found the matching send. */ + h_send->p_send_mad->status = IB_WCS_SUCCESS; + + /* Record the send contexts with the receive. */ + p_mad_element->send_context1 = (void*)h_send->p_send_mad->context1; + p_mad_element->send_context2 = (void*)h_send->p_send_mad->context2; + + if( h_send->retry_time == MAX_TIME ) + { + /* The send is currently active. Do not report it. */ + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC, + ("resp send active TID:0x%I64x\n", p_mad_hdr->trans_id) ); + /* Handle a duplicate receive happening before the send completion is processed. */ + if( h_send->p_resp_mad ) + ib_put_mad( h_send->p_resp_mad ); + h_send->p_resp_mad = p_mad_element; + cl_spinlock_release( &h_mad_svc->obj.lock ); + } + else + { + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC, + ("resp received TID:0x%I64x\n", p_mad_hdr->trans_id) ); + + /* Report the send completion below. */ + cl_qlist_remove_item( &h_mad_svc->send_list, + (cl_list_item_t*)&h_send->pool_item ); + cl_spinlock_release( &h_mad_svc->obj.lock ); + + /* Report the receive. */ + h_mad_svc->pfn_user_recv_cb( h_mad_svc, (void*)h_mad_svc->obj.context, + p_mad_element ); + + /* Report the send completion. */ + h_mad_svc->pfn_user_send_cb( h_mad_svc, (void*)h_mad_svc->obj.context, + h_send->p_send_mad ); + __cleanup_mad_send( h_mad_svc, h_send ); + } + AL_EXIT( AL_DBG_MAD_SVC ); +} + + + +/* + * Return TRUE if a received MAD requires RMPP processing. + */ +static __inline boolean_t +__recv_requires_rmpp( + IN const ib_mad_svc_type_t mad_svc_type, + IN const ib_mad_element_t* const p_mad_element ) +{ + ib_rmpp_mad_t *p_rmpp_mad; + + AL_ENTER( AL_DBG_MAD_SVC ); + + p_rmpp_mad = (ib_rmpp_mad_t*)ib_get_mad_buf( p_mad_element ); + + AL_EXIT( AL_DBG_MAD_SVC ); + + switch( mad_svc_type ) + { + case IB_MAD_SVC_DEFAULT: + return (p_rmpp_mad->common_hdr.mgmt_class == IB_MCLASS_SUBN_ADM || + ib_class_is_vendor_specific_high(p_rmpp_mad->common_hdr.mgmt_class)) && + ib_rmpp_is_flag_set(p_rmpp_mad, IB_RMPP_FLAG_ACTIVE); + + case IB_MAD_SVC_RMPP: + return( ib_rmpp_is_flag_set( p_rmpp_mad, IB_RMPP_FLAG_ACTIVE ) ); + + default: + return FALSE; + } +} + + + +/* + * Return TRUE if the MAD was issued by AL itself. + */ +static __inline boolean_t +__is_internal_send( + IN const ib_mad_svc_type_t mad_svc_type, + IN const ib_mad_element_t* const p_mad_element ) +{ + ib_rmpp_mad_t *p_rmpp_mad; + + p_rmpp_mad = (ib_rmpp_mad_t*)ib_get_mad_buf( p_mad_element ); + + /* See if the MAD service issues internal MADs. */ + switch( mad_svc_type ) + { + case IB_MAD_SVC_DEFAULT: + /* Internal sends are non-RMPP data MADs. */ + return ((p_rmpp_mad->common_hdr.mgmt_class == IB_MCLASS_SUBN_ADM || + ib_class_is_vendor_specific_high(p_rmpp_mad->common_hdr.mgmt_class)) && + (p_rmpp_mad->rmpp_type && p_rmpp_mad->rmpp_type != IB_RMPP_TYPE_DATA)); + + case IB_MAD_SVC_RMPP: + /* The RMPP header is present. Check its type. */ + return( (p_rmpp_mad->rmpp_type) && + (p_rmpp_mad->rmpp_type != IB_RMPP_TYPE_DATA) ); + + default: + return FALSE; + } +} + + + +/* + * Fully reassemble a received MAD. Return TRUE once all segments of the + * MAD have been received. Return the fully reassembled MAD. + */ +static cl_status_t +__do_rmpp_recv( + IN ib_mad_svc_handle_t h_mad_svc, + IN OUT ib_mad_element_t **pp_mad_element ) +{ + ib_rmpp_mad_t *p_rmpp_mad; + cl_status_t cl_status; + + AL_ENTER( AL_DBG_MAD_SVC ); + + p_rmpp_mad = ib_get_mad_buf( *pp_mad_element ); + CL_ASSERT( ib_rmpp_is_flag_set( p_rmpp_mad, IB_RMPP_FLAG_ACTIVE ) ); + + /* Perform the correct operation base on the RMPP MAD type. */ + switch( p_rmpp_mad->rmpp_type ) + { + case IB_RMPP_TYPE_DATA: + cl_status = __process_rmpp_data( h_mad_svc, pp_mad_element ); + /* Return the received element back to its MAD pool if not needed. */ + if( (cl_status != CL_SUCCESS) && (cl_status != CL_NOT_DONE) ) + { + ib_put_mad( *pp_mad_element ); + } + break; + + case IB_RMPP_TYPE_ACK: + /* Process the ACK. */ + __process_rmpp_ack( h_mad_svc, *pp_mad_element ); + ib_put_mad( *pp_mad_element ); + cl_status = CL_COMPLETED; + break; + + case IB_RMPP_TYPE_STOP: + case IB_RMPP_TYPE_ABORT: + default: + /* Process the ABORT or STOP. */ + __process_rmpp_nack( h_mad_svc, *pp_mad_element ); + ib_put_mad( *pp_mad_element ); + cl_status = CL_REJECT; + break; + } + + AL_EXIT( AL_DBG_MAD_SVC ); + return cl_status; +} + + + +/* + * Process an RMPP DATA message. Reassemble the received data. If the + * received MAD is fully reassembled, this call returns CL_SUCCESS. + */ +static cl_status_t +__process_rmpp_data( + IN ib_mad_svc_handle_t h_mad_svc, + IN OUT ib_mad_element_t **pp_mad_element ) +{ + ib_mad_element_t *p_rmpp_resp_mad = NULL; + al_mad_rmpp_t *p_rmpp; + ib_rmpp_mad_t *p_rmpp_hdr; + uint32_t cur_seg; + cl_status_t cl_status; + ib_api_status_t status; + + p_rmpp_hdr = ib_get_mad_buf( *pp_mad_element ); + CL_ASSERT( p_rmpp_hdr->rmpp_type == IB_RMPP_TYPE_DATA ); + + /* Try to find a receive already being reassembled. */ + cl_spinlock_acquire( &h_mad_svc->obj.lock ); + p_rmpp = __find_rmpp( h_mad_svc, *pp_mad_element ); + if( !p_rmpp ) + { + /* This receive is not being reassembled. It should be the first seg. */ + if( cl_ntoh32( p_rmpp_hdr->seg_num ) != 1 ) + { + cl_spinlock_release( &h_mad_svc->obj.lock ); + return CL_NOT_FOUND; + } + + /* Start tracking the new reassembly. */ + p_rmpp = __get_mad_rmpp( h_mad_svc, *pp_mad_element ); + if( !p_rmpp ) + { + cl_spinlock_release( &h_mad_svc->obj.lock ); + return CL_INSUFFICIENT_MEMORY; + } + } + + /* Verify that we just received the expected segment. */ + cur_seg = cl_ntoh32( p_rmpp_hdr->seg_num ); + if( cur_seg == p_rmpp->expected_seg ) + { + /* Copy the new segment's data into our reassembly buffer. */ + cl_status = __process_segment( h_mad_svc, p_rmpp, + pp_mad_element, &p_rmpp_resp_mad ); + + /* See if the RMPP is done. */ + if( cl_status == CL_SUCCESS ) + { + /* Stop tracking the reassembly. */ + __put_mad_rmpp( h_mad_svc, p_rmpp ); + } + else if( cl_status == CL_NOT_DONE ) + { + /* Start the reassembly timer. */ + cl_timer_trim( &h_mad_svc->recv_timer, AL_REASSEMBLY_TIMEOUT ); + } + } + else if( cur_seg < p_rmpp->expected_seg ) + { + /* We received an old segment. Resend the last ACK. */ + p_rmpp_resp_mad = __get_rmpp_ack( p_rmpp ); + cl_status = CL_DUPLICATE; + } + else + { + /* The sender is confused, ignore this MAD. We could ABORT here. */ + cl_status = CL_OVERRUN; + } + + cl_spinlock_release( &h_mad_svc->obj.lock ); + + /* + * Send any response MAD (ACK, ABORT, etc.) to the sender. Note that + * we are currently in the callback from the MAD dispatcher. The + * dispatcher holds a reference on the MAD service while in the callback, + * preventing the MAD service from being destroyed. This allows the + * call to ib_send_mad() to proceed even if the user tries to destroy + * the MAD service. + */ + if( p_rmpp_resp_mad ) + { + status = ib_send_mad( h_mad_svc, p_rmpp_resp_mad, NULL ); + if( status != IB_SUCCESS ) + { + /* Return the MAD. The MAD is considered dropped. */ + ib_put_mad( p_rmpp_resp_mad ); + } + } + + return cl_status; +} + + + +/* + * Locate an existing RMPP MAD being reassembled. Return NULL if one is not + * found. This call assumes access to the recv_list is synchronized. + */ +static al_mad_rmpp_t* +__find_rmpp( + IN ib_mad_svc_handle_t h_mad_svc, + IN OUT ib_mad_element_t *p_mad_element ) +{ + al_mad_rmpp_t *p_rmpp; + cl_list_item_t *p_list_item; + ib_mad_t *p_mad_hdr, *p_mad_hdr2; + ib_mad_element_t *p_mad_element2; + + + p_mad_hdr = ib_get_mad_buf( p_mad_element ); + + /* Search all MADs being reassembled. */ + for( p_list_item = cl_qlist_head( &h_mad_svc->recv_list ); + p_list_item != cl_qlist_end( &h_mad_svc->recv_list ); + p_list_item = cl_qlist_next( p_list_item ) ) + { + p_rmpp = PARENT_STRUCT( p_list_item, al_mad_rmpp_t, pool_item ); + + p_mad_element2 = p_rmpp->p_mad_element; + p_mad_hdr2 = ib_get_mad_buf( p_mad_element2 ); + + /* See if the incoming MAD matches - what a check. */ + if( (p_mad_hdr->trans_id == p_mad_hdr2->trans_id) && + (p_mad_hdr->class_ver == p_mad_hdr2->class_ver) && + (p_mad_hdr->mgmt_class == p_mad_hdr2->mgmt_class) && + (p_mad_hdr->method == p_mad_hdr2->method) && + (p_mad_element->remote_lid == p_mad_element2->remote_lid) && + (p_mad_element->remote_qp == p_mad_element2->remote_qp) ) + { + return p_rmpp; + } + } + + return NULL; +} + + + +/* + * Acquire a new RMPP tracking structure. This call assumes access to + * the recv_list is synchronized. + */ +static al_mad_rmpp_t* +__get_mad_rmpp( + IN ib_mad_svc_handle_t h_mad_svc, + IN ib_mad_element_t *p_mad_element ) +{ + al_mad_rmpp_t *p_rmpp; + al_mad_element_t *p_al_element; + + p_al_element = PARENT_STRUCT( p_mad_element, al_mad_element_t, element ); + + /* Get an RMPP tracking structure. */ + p_rmpp = get_mad_rmpp( p_al_element ); + if( !p_rmpp ) + return NULL; + + /* Initialize the tracking information. */ + p_rmpp->expected_seg = 1; + p_rmpp->seg_limit = 1; + p_rmpp->inactive = FALSE; + p_rmpp->p_mad_element = p_mad_element; + + /* Insert the tracking structure into the reassembly list. */ + cl_qlist_insert_tail( &h_mad_svc->recv_list, + (cl_list_item_t*)&p_rmpp->pool_item ); + + return p_rmpp; +} + + + +/* + * Return the RMPP tracking structure. This call assumes access to + * the recv_list is synchronized. + */ +static void +__put_mad_rmpp( + IN ib_mad_svc_handle_t h_mad_svc, + IN al_mad_rmpp_t *p_rmpp ) +{ + /* Remove the tracking structure from the reassembly list. */ + cl_qlist_remove_item( &h_mad_svc->recv_list, + (cl_list_item_t*)&p_rmpp->pool_item ); + + /* Return the RMPP tracking structure. */ + put_mad_rmpp( p_rmpp ); +} + + + +/* + * Process a received RMPP segment. Copy the data into our receive buffer, + * update the expected segment, and send an ACK if needed. + */ +static cl_status_t +__process_segment( + IN ib_mad_svc_handle_t h_mad_svc, + IN al_mad_rmpp_t *p_rmpp, + IN OUT ib_mad_element_t **pp_mad_element, + OUT ib_mad_element_t **pp_rmpp_resp_mad ) +{ + ib_rmpp_mad_t *p_rmpp_hdr; + uint32_t cur_seg; + ib_api_status_t status; + cl_status_t cl_status; + uint8_t *p_dst_seg, *p_src_seg; + uint32_t paylen; + + CL_ASSERT( h_mad_svc && p_rmpp && pp_mad_element && *pp_mad_element ); + + p_rmpp_hdr = (ib_rmpp_mad_t*)(*pp_mad_element)->p_mad_buf; + cur_seg = cl_ntoh32( p_rmpp_hdr->seg_num ); + CL_ASSERT( cur_seg == p_rmpp->expected_seg ); + CL_ASSERT( cur_seg <= p_rmpp->seg_limit ); + + /* See if the receive has been fully reassembled. */ + if( ib_rmpp_is_flag_set( p_rmpp_hdr, IB_RMPP_FLAG_LAST ) ) + cl_status = CL_SUCCESS; + else + cl_status = CL_NOT_DONE; + + /* Save the payload length for later use. */ + paylen = cl_ntoh32(p_rmpp_hdr->paylen_newwin); + + /* The element of the first segment starts the reasembly. */ + if( *pp_mad_element != p_rmpp->p_mad_element ) + { + /* SA MADs require extra header size ... */ + if( (*pp_mad_element)->p_mad_buf->mgmt_class == IB_MCLASS_SUBN_ADM ) + { + /* Copy the received data into our reassembly buffer. */ + p_src_seg = ((uint8_t*)(*pp_mad_element)->p_mad_buf) + + IB_SA_MAD_HDR_SIZE; + p_dst_seg = ((uint8_t*)p_rmpp->p_mad_element->p_mad_buf) + + IB_SA_MAD_HDR_SIZE + IB_SA_DATA_SIZE * (cur_seg - 1); + cl_memcpy( p_dst_seg, p_src_seg, IB_SA_DATA_SIZE ); + } + else + { + /* Copy the received data into our reassembly buffer. */ + p_src_seg = ((uint8_t*)(*pp_mad_element)->p_mad_buf) + + MAD_RMPP_HDR_SIZE; + p_dst_seg = ((uint8_t*)p_rmpp->p_mad_element->p_mad_buf) + + MAD_RMPP_HDR_SIZE + MAD_RMPP_DATA_SIZE * (cur_seg - 1); + cl_memcpy( p_dst_seg, p_src_seg, MAD_RMPP_DATA_SIZE ); + } + /* This MAD is no longer needed. */ + ib_put_mad( *pp_mad_element ); + } + + /* Update the size of the mad if the last segment */ + if ( cl_status == CL_SUCCESS ) + { + if (p_rmpp->p_mad_element->p_mad_buf->mgmt_class == IB_MCLASS_SUBN_ADM ) + { + /* + * Note we will get one extra SA Hdr size in the paylen, + * so we only take the rmpp header size of the first segment. + */ + p_rmpp->p_mad_element->size = + MAD_RMPP_HDR_SIZE + IB_SA_DATA_SIZE *(cur_seg - 1) + paylen; + } + else + { + p_rmpp->p_mad_element->size = + MAD_RMPP_HDR_SIZE + MAD_RMPP_DATA_SIZE * (cur_seg - 1) + paylen; + } + } + + /* + * We are ready to accept the next segment. We increment expected segment + * even if we're done, so that ACKs correctly report the last segment. + */ + p_rmpp->expected_seg++; + + /* Mark the RMPP as active if we're not destroying the MAD service. */ + p_rmpp->inactive = (h_mad_svc->obj.state == CL_DESTROYING); + + /* See if the receive has been fully reassembled. */ + if( cl_status == CL_NOT_DONE && cur_seg == p_rmpp->seg_limit ) + { + /* Allocate more segments for the incoming receive. */ + status = al_resize_mad( p_rmpp->p_mad_element, + p_rmpp->p_mad_element->size + AL_RMPP_WINDOW * MAD_RMPP_DATA_SIZE ); + + /* If we couldn't allocate a new buffer, just drop the MAD. */ + if( status == IB_SUCCESS ) + { + /* Send an ACK indicating that more space is available. */ + p_rmpp->seg_limit += AL_RMPP_WINDOW; + *pp_rmpp_resp_mad = __get_rmpp_ack( p_rmpp ); + } + } + else if( cl_status == CL_SUCCESS ) + { + /* Return the element referencing the reassembled MAD. */ + *pp_mad_element = p_rmpp->p_mad_element; + *pp_rmpp_resp_mad = __get_rmpp_ack( p_rmpp ); + } + + return cl_status; +} + + + +/* + * Get an ACK message to return to the sender of an RMPP MAD. + */ +static ib_mad_element_t* +__get_rmpp_ack( + IN al_mad_rmpp_t *p_rmpp ) +{ + ib_mad_element_t *p_mad_element; + al_mad_element_t *p_al_element; + ib_api_status_t status; + ib_rmpp_mad_t *p_ack_rmpp_hdr, *p_data_rmpp_hdr; + + /* Get a MAD to carry the ACK. */ + p_al_element = PARENT_STRUCT( p_rmpp->p_mad_element, + al_mad_element_t, element ); + status = ib_get_mad( p_al_element->pool_key, MAD_BLOCK_SIZE, + &p_mad_element ); + if( status != IB_SUCCESS ) + { + /* Just return. The ACK will be treated as being dropped. */ + return NULL; + } + + /* Format the ACK. */ + p_ack_rmpp_hdr = ib_get_mad_buf( p_mad_element ); + p_data_rmpp_hdr = ib_get_mad_buf( p_rmpp->p_mad_element ); + + __init_reply_element( p_mad_element, p_rmpp->p_mad_element ); + + /* Copy the MAD common header. */ + cl_memcpy( &p_ack_rmpp_hdr->common_hdr, &p_data_rmpp_hdr->common_hdr, + sizeof( ib_mad_t ) ); + + /* Reset the status (in case the BUSY bit is set). */ + p_ack_rmpp_hdr->common_hdr.status = 0; + + /* Flip the response bit in the method */ + p_ack_rmpp_hdr->common_hdr.method ^= IB_MAD_METHOD_RESP_MASK; + + p_ack_rmpp_hdr->rmpp_version = p_data_rmpp_hdr->rmpp_version; + p_ack_rmpp_hdr->rmpp_type = IB_RMPP_TYPE_ACK; + ib_rmpp_set_resp_time( p_ack_rmpp_hdr, IB_RMPP_NO_RESP_TIME ); + p_ack_rmpp_hdr->rmpp_flags |= IB_RMPP_FLAG_ACTIVE; + p_ack_rmpp_hdr->rmpp_status = IB_RMPP_STATUS_SUCCESS; + + p_ack_rmpp_hdr->seg_num = cl_hton32( p_rmpp->expected_seg - 1 ); + + if (p_rmpp->seg_limit == p_rmpp->expected_seg - 1 && + !ib_rmpp_is_flag_set( p_data_rmpp_hdr, IB_RMPP_FLAG_LAST ) ) + { + p_ack_rmpp_hdr->paylen_newwin = cl_hton32( 1 + p_rmpp->seg_limit); + } + else + { + p_ack_rmpp_hdr->paylen_newwin = cl_hton32( p_rmpp->seg_limit ); + } + + return p_mad_element; +} + + + +/* + * Copy necessary data between MAD elements to allow the destination + * element to be sent to the sender of the source element. + */ +static void +__init_reply_element( + IN ib_mad_element_t *p_dst_element, + IN ib_mad_element_t *p_src_element ) +{ + p_dst_element->remote_qp = p_src_element->remote_qp; + p_dst_element->remote_qkey = p_src_element->remote_qkey; + + if( p_src_element->grh_valid ) + { + p_dst_element->grh_valid = p_src_element->grh_valid; + cl_memcpy( p_dst_element->p_grh, p_src_element->p_grh, + sizeof( ib_grh_t ) ); + } + + p_dst_element->remote_lid = p_src_element->remote_lid; + p_dst_element->remote_sl = p_src_element->remote_sl; + p_dst_element->pkey_index = p_src_element->pkey_index; + p_dst_element->path_bits = p_src_element->path_bits; +} + + + +/* + * Process an RMPP ACK message. Continue sending addition segments. + */ +static void +__process_rmpp_ack( + IN ib_mad_svc_handle_t h_mad_svc, + IN ib_mad_element_t *p_mad_element ) +{ + ib_mad_send_handle_t h_send; + ib_rmpp_mad_t *p_rmpp_mad; + boolean_t send_done = FALSE; + ib_wc_status_t wc_status = IB_WCS_SUCCESS; + + AL_ENTER( AL_DBG_MAD_SVC ); + p_rmpp_mad = (ib_rmpp_mad_t*)ib_get_mad_buf( p_mad_element ); + + /* + * Search for the send. The send may have timed out, been canceled, + * or received a response. + */ + cl_spinlock_acquire( &h_mad_svc->obj.lock ); + h_send = __mad_svc_match_recv( h_mad_svc, p_mad_element ); + if( !h_send ) + { + cl_spinlock_release( &h_mad_svc->obj.lock ); + AL_PRINT_EXIT( TRACE_LEVEL_WARNING, AL_DBG_MAD_SVC, + ("ACK cannot find a matching send\n") ); + return; + } + + /* Drop old ACKs. */ + if( cl_ntoh32( p_rmpp_mad->seg_num ) < h_send->ack_seg ) + { + cl_spinlock_release( &h_mad_svc->obj.lock ); + AL_PRINT_EXIT( TRACE_LEVEL_WARNING, AL_DBG_MAD_SVC, + ("old ACK - being dropped\n") ); + return; + } + + /* Update the acknowledged segment and segment limit. */ + h_send->ack_seg = cl_ntoh32( p_rmpp_mad->seg_num ); + + /* Keep seg_limit <= total_seg to simplify checks. */ + if( cl_ntoh32( p_rmpp_mad->paylen_newwin ) > h_send->total_seg ) + h_send->seg_limit = h_send->total_seg; + else + h_send->seg_limit = cl_ntoh32( p_rmpp_mad->paylen_newwin ); + + /* Reset the current segment to start resending from the ACK. */ + h_send->cur_seg = h_send->ack_seg + 1; + + /* If the send is active, we will finish processing it once it completes. */ + if( h_send->retry_time == MAX_TIME ) + { + cl_spinlock_release( &h_mad_svc->obj.lock ); + AL_PRINT_EXIT( TRACE_LEVEL_WARNING, AL_DBG_MAD_SVC, + ("ACK processed, waiting for send to complete\n") ); + return; + } + + /* + * Complete the send if all segments have been ack'ed and no + * response is expected. (If the response for a send had already been + * received, we would have reported the completion regardless of the + * send having been ack'ed.) + */ + CL_ASSERT( !h_send->p_send_mad->resp_expected || !h_send->p_resp_mad ); + if( (h_send->ack_seg == h_send->total_seg) && + !h_send->p_send_mad->resp_expected ) + { + /* The send is done. All segments have been ack'ed. */ + send_done = TRUE; + } + else if( h_send->ack_seg < h_send->seg_limit ) + { + /* Send the next segment. */ + __queue_rmpp_seg( h_mad_svc->h_mad_reg, h_send ); + } + + if( send_done ) + { + /* Notify the user of a send completion or error. */ + cl_qlist_remove_item( &h_mad_svc->send_list, + (cl_list_item_t*)&h_send->pool_item ); + cl_spinlock_release( &h_mad_svc->obj.lock ); + __notify_send_comp( h_mad_svc, h_send, wc_status ); + } + else + { + /* Continue waiting for a response or a larger send window. */ + cl_spinlock_release( &h_mad_svc->obj.lock ); + } + + /* + * Resume any sends that can now be sent without holding + * the mad service lock. + */ + __mad_disp_resume_send( h_mad_svc->h_mad_reg ); + + AL_EXIT( AL_DBG_MAD_SVC ); +} + + + +/* + * Process an RMPP STOP or ABORT message. + */ +static void +__process_rmpp_nack( + IN ib_mad_svc_handle_t h_mad_svc, + IN ib_mad_element_t *p_mad_element ) +{ + ib_mad_send_handle_t h_send; + ib_rmpp_mad_t *p_rmpp_mad; + + AL_ENTER( AL_DBG_MAD_SVC ); + p_rmpp_mad = (ib_rmpp_mad_t*)ib_get_mad_buf( p_mad_element ); + + /* Search for the send. The send may have timed out or been canceled. */ + cl_spinlock_acquire( &h_mad_svc->obj.lock ); + h_send = __mad_svc_match_recv( h_mad_svc, p_mad_element ); + if( !h_send ) + { + cl_spinlock_release( &h_mad_svc->obj.lock ); + return; + } + + /* If the send is active, we will finish processing it once it completes. */ + if( h_send->retry_time == MAX_TIME ) + { + h_send->canceled = TRUE; + cl_spinlock_release( &h_mad_svc->obj.lock ); + AL_EXIT( AL_DBG_MAD_SVC ); + return; + } + + /* Fail the send operation. */ + cl_qlist_remove_item( &h_mad_svc->send_list, + (cl_list_item_t*)&h_send->pool_item ); + cl_spinlock_release( &h_mad_svc->obj.lock ); + __notify_send_comp( h_mad_svc, h_send, IB_WCS_CANCELED ); + + AL_EXIT( AL_DBG_MAD_SVC ); +} + + + +static __inline void +__set_retry_time( + IN ib_mad_send_handle_t h_send ) +{ + h_send->retry_time = + (uint64_t)(h_send->p_send_mad->timeout_ms + h_send->delay) * 1000Ui64 + + cl_get_time_stamp(); + h_send->delay = 0; +} + + + +static void +__send_timer_cb( + IN void *context ) +{ + AL_ENTER( AL_DBG_MAD_SVC ); + + __check_send_queue( (ib_mad_svc_handle_t)context ); + + AL_EXIT( AL_DBG_MAD_SVC ); +} + + + +/* + * Check the send queue for any sends that have timed out or were canceled + * by the user. + */ +static void +__check_send_queue( + IN ib_mad_svc_handle_t h_mad_svc ) +{ + ib_mad_send_handle_t h_send; + cl_list_item_t *p_list_item, *p_next_item; + uint64_t cur_time; + cl_qlist_t timeout_list; + + AL_ENTER( AL_DBG_MAD_SVC ); + + /* + * The timeout out list is used to call the user back without + * holding the lock on the MAD service. + */ + cl_qlist_init( &timeout_list ); + cur_time = cl_get_time_stamp(); + + cl_spinlock_acquire( &h_mad_svc->obj.lock ); + + /* Check all outstanding sends. */ + for( p_list_item = cl_qlist_head( &h_mad_svc->send_list ); + p_list_item != cl_qlist_end( &h_mad_svc->send_list ); + p_list_item = p_next_item ) + { + p_next_item = cl_qlist_next( p_list_item ); + h_send = PARENT_STRUCT( p_list_item, al_mad_send_t, pool_item ); + + /* See if the request is active. */ + if( h_send->retry_time == MAX_TIME ) + { + /* The request is still active. */ + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC, ("active TID:0x%I64x\n", + __get_send_tid( h_send )) ); + continue; + } + + /* The request is not active. */ + /* See if the request has been canceled. */ + if( h_send->canceled ) + { + /* The request has been canceled. */ + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC, ("canceling TID:0x%I64x\n", + __get_send_tid( h_send )) ); + + h_send->p_send_mad->status = IB_WCS_CANCELED; + cl_qlist_remove_item( &h_mad_svc->send_list, p_list_item ); + cl_qlist_insert_tail( &timeout_list, p_list_item ); + continue; + } + + /* Skip requests that have not timed out. */ + if( cur_time < h_send->retry_time ) + { + /* The request has not timed out. */ + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC, ("waiting on TID:0x%I64x\n", + __get_send_tid( h_send )) ); + + /* Set the retry timer to the minimum needed time, in ms. */ + cl_timer_trim( &h_mad_svc->send_timer, + ((uint32_t)(h_send->retry_time - cur_time) / 1000) ); + continue; + } + + /* See if we need to retry the send operation. */ + if( h_send->retry_cnt ) + { + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC, ("retrying TID:0x%I64x\n", + __get_send_tid( h_send )) ); + + /* Retry the send. */ + h_send->retry_time = MAX_TIME; + h_send->retry_cnt--; + + if( h_send->uses_rmpp ) + { + if( h_send->ack_seg < h_send->seg_limit ) + { + /* Resend all unacknowledged segments. */ + h_send->cur_seg = h_send->ack_seg + 1; + __queue_rmpp_seg( h_mad_svc->h_mad_reg, h_send ); + } + else + { + /* The send was delivered. Continue waiting. */ + __set_retry_time( h_send ); + cl_timer_trim( &h_mad_svc->send_timer, + ((uint32_t)(h_send->retry_time - cur_time) / 1000) ); + } + } + else + { + /* The work request should already be formatted properly. */ + __mad_disp_queue_send( h_mad_svc->h_mad_reg, + &h_send->mad_wr ); + } + continue; + } + /* The request has timed out or failed to be retried. */ + AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_MAD_SVC, + ("timing out TID:0x%I64x\n", __get_send_tid( h_send )) ); + + h_send->p_send_mad->status = IB_WCS_TIMEOUT_RETRY_ERR; + cl_qlist_remove_item( &h_mad_svc->send_list, p_list_item ); + cl_qlist_insert_tail( &timeout_list, p_list_item ); + } + + cl_spinlock_release( &h_mad_svc->obj.lock ); + + /* + * Resume any sends that can now be sent without holding + * the mad service lock. + */ + __mad_disp_resume_send( h_mad_svc->h_mad_reg ); + + /* Report all timed out sends to the user. */ + p_list_item = cl_qlist_remove_head( &timeout_list ); + while( p_list_item != cl_qlist_end( &timeout_list ) ) + { + h_send = PARENT_STRUCT( p_list_item, al_mad_send_t, pool_item ); + + h_mad_svc->pfn_user_send_cb( h_mad_svc, (void*)h_mad_svc->obj.context, + h_send->p_send_mad ); + __cleanup_mad_send( h_mad_svc, h_send ); + p_list_item = cl_qlist_remove_head( &timeout_list ); + } + AL_EXIT( AL_DBG_MAD_SVC ); +} + + + +static void +__recv_timer_cb( + IN void *context ) +{ + ib_mad_svc_handle_t h_mad_svc; + al_mad_rmpp_t *p_rmpp; + cl_list_item_t *p_list_item, *p_next_item; + boolean_t restart_timer; + + AL_ENTER( AL_DBG_MAD_SVC ); + + h_mad_svc = (ib_mad_svc_handle_t)context; + + cl_spinlock_acquire( &h_mad_svc->obj.lock ); + + /* Check all outstanding receives. */ + for( p_list_item = cl_qlist_head( &h_mad_svc->recv_list ); + p_list_item != cl_qlist_end( &h_mad_svc->recv_list ); + p_list_item = p_next_item ) + { + p_next_item = cl_qlist_next( p_list_item ); + p_rmpp = PARENT_STRUCT( p_list_item, al_mad_rmpp_t, pool_item ); + + /* Fail all RMPP MADs that have remained inactive. */ + if( p_rmpp->inactive ) + { + ib_put_mad( p_rmpp->p_mad_element ); + __put_mad_rmpp( h_mad_svc, p_rmpp ); + } + else + { + /* Mark the RMPP as inactive. */ + p_rmpp->inactive = TRUE; + } + } + + restart_timer = !cl_is_qlist_empty( &h_mad_svc->recv_list ); + cl_spinlock_release( &h_mad_svc->obj.lock ); + + if( restart_timer ) + cl_timer_start( &h_mad_svc->recv_timer, AL_REASSEMBLY_TIMEOUT ); + AL_EXIT( AL_DBG_MAD_SVC ); +} + + + +ib_api_status_t +ib_local_mad( + IN const ib_ca_handle_t h_ca, + IN const uint8_t port_num, + IN const void* const p_mad_in, + IN void* p_mad_out ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_MAD_SVC ); + + if( AL_OBJ_INVALID_HANDLE( h_ca, AL_OBJ_TYPE_H_CA ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_CA_HANDLE\n") ); + return IB_INVALID_CA_HANDLE; + } + if( !p_mad_in || !p_mad_out ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + status = al_local_mad(h_ca, port_num, NULL,p_mad_in, p_mad_out); + + AL_EXIT( AL_DBG_MAD_SVC ); + return status; +} + +ib_api_status_t +al_local_mad( + IN const ib_ca_handle_t h_ca, + IN const uint8_t port_num, + IN const ib_av_attr_t* p_src_av_attr, + IN const void* const p_mad_in, + IN void* p_mad_out ) +{ + ib_api_status_t status; + void* p_mad_out_local = NULL; + AL_ENTER( AL_DBG_MAD_SVC ); + + if( AL_OBJ_INVALID_HANDLE( h_ca, AL_OBJ_TYPE_H_CA ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_CA_HANDLE\n") ); + return IB_INVALID_CA_HANDLE; + } + if( !p_mad_in ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + if( !p_mad_out ) + { + p_mad_out_local = cl_zalloc(256); + if(!p_mad_out_local) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INSUFFICIENT_MEMORY\n") ); + return IB_INSUFFICIENT_MEMORY; + } + }else + { + p_mad_out_local = p_mad_out; + } + + status = verbs_local_mad( h_ca, port_num, p_src_av_attr, p_mad_in, p_mad_out_local ); + + if( !p_mad_out ) + { + cl_free(p_mad_out_local); + } + + AL_EXIT( AL_DBG_MAD_SVC ); + return status; + +} + +ib_net32_t +al_get_user_tid( + IN const ib_net64_t tid64 ) +{ + al_tid_t al_tid; + + al_tid.tid64 = tid64; + return( al_tid.tid32.user_tid ); +} + +uint32_t +al_get_al_tid( + IN const ib_net64_t tid64 ) +{ + al_tid_t al_tid; + + al_tid.tid64 = tid64; + return( cl_ntoh32( al_tid.tid32.al_tid ) ); +} + +void +al_set_al_tid( + IN ib_net64_t* const p_tid64, + IN const uint32_t tid32 ) +{ + al_tid_t *p_al_tid; + + p_al_tid = (al_tid_t*)p_tid64; + + if( tid32 ) + { + CL_ASSERT( !p_al_tid->tid32.al_tid ); + } + + p_al_tid->tid32.al_tid = cl_hton32( tid32 ); +} diff --git a/branches/WOF2-3/core/al/al_mad.h b/branches/WOF2-3/core/al/al_mad.h new file mode 100644 index 00000000..ff6cb9cc --- /dev/null +++ b/branches/WOF2-3/core/al/al_mad.h @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#if !defined(__IB_AL_MAD_H__) +#define __IB_AL_MAD_H__ + + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "al_common.h" +#include "al_mad_pool.h" + + + +/* + * The MAD dispatcher routes completed MAD work requests to the correct + * MAD service. + */ +typedef struct _al_mad_disp +{ + al_obj_t obj; + ib_qp_handle_t h_qp; + + /* Client information. */ + cl_vector_t client_vector; + + /* + * Indicates the version of supported MADs. 1 based-index. This is + * a vector of class vectors. + */ + cl_vector_t version_vector; + +} al_mad_disp_t; + + +typedef al_mad_disp_t *al_mad_disp_handle_t; + + +typedef void +(*pfn_mad_svc_send_done_t)( + IN ib_mad_svc_handle_t h_mad_svc, + IN al_mad_wr_t *p_mad_wr, + IN ib_wc_t *p_wc ); + +typedef void +(*pfn_mad_svc_recv_done_t)( + IN ib_mad_svc_handle_t h_mad_svc, + IN ib_mad_element_t *p_mad_element ); + + +typedef struct _al_mad_disp_reg +{ + ib_mad_svc_handle_t h_mad_svc; + al_mad_disp_handle_t h_mad_disp; + uint32_t client_id; + atomic32_t ref_cnt; + + /* Clients must specify completion routines for user-mode support. */ + pfn_mad_svc_send_done_t pfn_send_done; + pfn_mad_svc_recv_done_t pfn_recv_done; + + /* Mgmt class supported by the client. Class 0x81 is mapped to 0x00. */ + uint8_t mgmt_class; + uint8_t mgmt_version; + boolean_t support_unsol; + +} al_mad_disp_reg_t; + + + +/* The registration handle is an index into the client_vector. */ +typedef al_mad_disp_reg_t* al_mad_reg_handle_t; + + + +ib_api_status_t +create_mad_disp( + IN al_obj_t* const p_parent_obj, + IN const ib_qp_handle_t h_qp, + IN al_mad_disp_handle_t* const ph_mad_disp ); + +void +mad_disp_send_done( + IN al_mad_disp_handle_t h_mad_disp, + IN al_mad_wr_t *p_mad_wr, + IN ib_wc_t *p_wc ); + +ib_api_status_t +mad_disp_recv_done( + IN al_mad_disp_handle_t h_mad_disp, + IN ib_mad_element_t *p_mad_element ); + + + + +/* + * MAD service used to send and receive MADs. MAD services are responsible + * for retransmissions and SAR. + */ +typedef struct _al_mad_svc +{ + al_obj_t obj; + + ib_mad_svc_type_t svc_type; + + atomic32_t ref_cnt; + + al_mad_reg_handle_t h_mad_reg; + ib_pfn_mad_comp_cb_t pfn_user_send_cb; + ib_pfn_mad_comp_cb_t pfn_user_recv_cb; + + cl_qlist_t send_list; + cl_timer_t send_timer; + + cl_qlist_t recv_list; + cl_timer_t recv_timer; + + /* The PD and port number are used to create address vectors on sends. */ + ib_pd_handle_t h_pd; + uint8_t port_num; + +} al_mad_svc_t; + + +void +free_mad_svc( + IN struct _al_obj *p_obj ); + + +/* + * Register a MAD service with a QP. + */ +ib_api_status_t +reg_mad_svc( + IN const ib_qp_handle_t h_qp, + IN const ib_mad_svc_t* const p_mad_svc, + OUT ib_mad_svc_handle_t* const ph_mad_svc ); + + +ib_api_status_t +al_local_mad( + IN const ib_ca_handle_t h_ca, + IN const uint8_t port_num, + IN const ib_av_attr_t* p_av_attr, + IN const void* const p_mad_in, + IN void* p_mad_out ); + +/* + * TID management + */ +typedef union _al_tid +{ + ib_net64_t tid64; + struct _tid + { + ib_net32_t al_tid; + ib_net32_t user_tid; + } tid32; + +} al_tid_t; + + +ib_net32_t +al_get_user_tid( + IN const ib_net64_t tid64 ); + + +uint32_t +al_get_al_tid( + IN const ib_net64_t tid64 ); + + +void +al_set_al_tid( + IN ib_net64_t* const p_tid64, + IN const uint32_t tid32 ); + + + +void +build_mad_recv( + IN ib_mad_element_t* p_mad_element, + IN ib_wc_t* p_wc ); + + +ib_mad_t* +get_mad_hdr_from_wr( + IN al_mad_wr_t* const p_mad_wr ); + + +ib_api_status_t +ib_delay_mad( + IN const ib_mad_svc_handle_t h_mad_svc, + IN ib_mad_element_t* const p_mad_element, + IN const uint32_t delay_ms ); + + +#endif /* __IB_AL_MAD_H__ */ diff --git a/branches/WOF2-3/core/al/al_mad_pool.h b/branches/WOF2-3/core/al/al_mad_pool.h new file mode 100644 index 00000000..cc08888f --- /dev/null +++ b/branches/WOF2-3/core/al/al_mad_pool.h @@ -0,0 +1,278 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#if !defined( __AL_MAD_POOL_H__ ) +#define __AL_MAD_POOL_H__ + +#include +#include +#include "al_common.h" + + +typedef struct _al_pool +{ + al_obj_t obj; /* Child of ib_al_handle_t */ +#if defined( CL_KERNEL ) + NPAGED_LOOKASIDE_LIST mad_stack; +#else + cl_qlist_t mad_stack; +#endif + cl_qlist_t key_list; + size_t max; + size_t actual; + size_t grow_size; +#if defined( CL_KERNEL ) + NPAGED_LOOKASIDE_LIST mad_send_pool; + NPAGED_LOOKASIDE_LIST mad_rmpp_pool; +#else + cl_qpool_t mad_send_pool; + cl_qpool_t mad_rmpp_pool; +#endif + +} al_pool_t; + + + +/* + * Pool key type used to distinguish between pool_keys allocated by the user + * and those that reference AL's internal MAD pool_key. + */ +typedef enum _al_key_type +{ + AL_KEY_NORMAL, + AL_KEY_ALIAS + +} al_key_type_t; + + + +typedef struct _al_pool_key +{ + al_obj_t obj; /* Not a child object. */ + /* Parent of mad_reg_t */ + al_key_type_t type; + + /* + * Pool keys can be destroyed either by deregistering them, destroying + * the associated pool, or destroying the associated PD. We track the + * pool key with the AL instance in order to synchronize destruction. + */ + boolean_t in_al_list; + ib_al_handle_t h_al; + cl_list_item_t al_item; /* Chain in ib_al_t for dereg */ + cl_list_item_t pool_item; /* Chain in al_pool_t for grow */ + + ib_pool_handle_t h_pool; +#ifndef CL_KERNEL + ib_pd_handle_t h_pd; +#else + ib_mr_handle_t h_mr; + net32_t lkey; +#endif + + /* Number of MADs currently removed from pool using this key. */ + atomic32_t mad_cnt; + + /* For alias keys, maintain a reference to the actual pool key. */ + ib_pool_key_t pool_key; + +} al_pool_key_t; + + +ib_api_status_t +reg_mad_pool( + IN const ib_pool_handle_t h_pool, + IN const ib_pd_handle_t h_pd, + OUT ib_pool_key_t* const pp_pool_key ); + +/* Deregister a MAD pool key if it is of the expected type. */ +ib_api_status_t +dereg_mad_pool( + IN const ib_pool_key_t pool_key, + IN const al_key_type_t expected_type ); + +typedef struct _al_mad_element +{ + /* + * List item used to track free MADs by the MAD pool. Also used by + * the SMI and MAD QPs to track received MADs. + */ + cl_list_item_t list_item; + ib_al_handle_t h_al; /* Track out-of-pool MAD owner */ + cl_list_item_t al_item; /* Out-of-pool MAD owner chain */ + ib_mad_element_t element; + ib_pool_key_t pool_key; /* For getting mads for RMPP ACK */ + ib_local_ds_t grh_ds; /* GRH + 256 byte buffer. */ + ib_local_ds_t mad_ds; /* Registered 256-byte buffer. */ + ib_mad_t *p_al_mad_buf; /* Allocated send/recv buffer. */ +#if defined( CL_KERNEL ) + uint8_t mad_buf[MAD_BLOCK_GRH_SIZE]; +#endif + + uint64_t h_proxy_element; /* For user-mode support */ + +} al_mad_element_t; + + + +ib_api_status_t +al_resize_mad( + OUT ib_mad_element_t *p_mad_element, + IN const size_t buf_size ); + + + +/* We don't have MAD array structures in the Windows kernel. */ +#if !defined( CL_KERNEL ) +typedef struct _mad_array +{ + al_obj_t obj; /* Child of al_pool_t */ + ib_pool_handle_t h_pool; + size_t sizeof_array; + void* p_data; + +} mad_array_t; +#endif + + +typedef struct _mad_item +{ + al_mad_element_t al_mad_element; +#if defined( CL_KERNEL ) + ib_pool_key_t pool_key; +#else + mad_array_t* p_mad_array; +#endif + +} mad_item_t; + + + +/* + * Work request structure to use when posting sends. + */ +typedef struct _al_mad_wr +{ + cl_list_item_t list_item; + + uint32_t client_id; + ib_net64_t client_tid; + + /* + * Work request used when sending MADs. This permits formatting the + * work request once and re-using it when issuing retries. + */ + ib_send_wr_t send_wr; + +} al_mad_wr_t; + + + +/* + * Structure used to track an outstanding send request. + */ +typedef struct _al_mad_send +{ + cl_pool_item_t pool_item; + ib_mad_element_t *p_send_mad; + ib_av_handle_t h_av; + + al_mad_wr_t mad_wr; + + /* + * Received MAD in response to a send. This is not set until + * the entire response has been received. + */ + ib_mad_element_t *p_resp_mad; + + /* Absolute time that the request should be retried. */ + uint64_t retry_time; + + /* Delay, in milliseconds, to add before the next retry. */ + uint32_t delay; + + /* Number of times that the request can be retried. */ + uint32_t retry_cnt; + boolean_t canceled; /* indicates if send was canceled */ + + /* + * SAR tracking information. + */ + boolean_t uses_rmpp; + uint32_t ack_seg; /* last segment number ack'ed*/ + uint32_t cur_seg; /* current segment to send */ + uint32_t seg_limit; /* max. segment to send */ + uint32_t total_seg; /* total segments to send */ + +} al_mad_send_t; + + + +/* + * Structure used to track receiving an RMPP MAD. + */ +typedef struct _al_mad_rmpp +{ + cl_pool_item_t pool_item; + + boolean_t inactive; /* used to time out reassembly */ + + uint32_t expected_seg;/* next segment to receive */ + uint32_t seg_limit; /* upper bound of recv window */ + ib_mad_element_t *p_mad_element;/* reassembled recv */ + +} al_mad_rmpp_t; + + + +ib_mad_send_handle_t +get_mad_send( + IN const al_mad_element_t *p_mad_element ); + + +void +put_mad_send( + IN ib_mad_send_handle_t h_mad_send ); + + +al_mad_rmpp_t* +get_mad_rmpp( + IN const al_mad_element_t *p_mad_element ); + + +void +put_mad_rmpp( + IN al_mad_rmpp_t *p_rmpp ); + + +#endif // __AL_MAD_POOL_H__ diff --git a/branches/WOF2-3/core/al/al_mcast.c b/branches/WOF2-3/core/al/al_mcast.c new file mode 100644 index 00000000..fe6fde5d --- /dev/null +++ b/branches/WOF2-3/core/al/al_mcast.c @@ -0,0 +1,691 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include + +#include "al.h" +#include "al_ca.h" +#include "al_debug.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "al_mcast.tmh" +#endif + +#include "al_mgr.h" +#include "al_qp.h" +#include "al_verbs.h" + +#include "ib_common.h" + + +/* + * Function prototypes. + */ +static ib_api_status_t +send_join( + IN ib_mcast_t *p_mcast, + IN const ib_mcast_req_t* const p_mcast_req ); + +static void +join_req_cb( + IN al_sa_req_t *p_sa_req, + IN ib_mad_element_t *p_mad_response ); + +static void +join_async_cb( + IN cl_async_proc_item_t *p_item ); + +static void +leave_req_cb( + IN al_sa_req_t *p_sa_req, + IN ib_mad_element_t *p_mad_response ); + +static void +leave_async_cb( + IN cl_async_proc_item_t *p_item ); + +static void +__destroying_mcast( + IN al_obj_t *p_obj ); + +static void +__cleanup_mcast( + IN al_obj_t *p_obj ); + +static void +__free_mcast( + IN al_obj_t *p_obj ); + +#ifdef CL_KERNEL +static void +__cleanup_attach( + IN al_obj_t *p_obj ); + +static void +__free_attach( + IN al_obj_t *p_obj ); +#endif + + + +ib_api_status_t +al_join_mcast( + IN const ib_qp_handle_t h_qp, + IN const ib_mcast_req_t* const p_mcast_req ) +{ + ib_mcast_handle_t h_mcast; + ib_api_status_t status; + cl_status_t cl_status; + boolean_t sync; + + AL_ENTER( AL_DBG_MCAST ); + + /* + * Validate the port GUID. There is no need to validate the pkey index as + * the user could change it later to make it invalid. There is also no + * need to perform any QP transitions as ib_init_dgrm_svc resets the QP and + * starts from scratch. + */ + status = get_port_num( h_qp->obj.p_ci_ca, p_mcast_req->port_guid, NULL ); + if( status != IB_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("get_port_num failed, status: %s\n", ib_get_err_str(status)) ); + return status; + } + + /* Allocate a new multicast request. */ + h_mcast = cl_zalloc( sizeof( ib_mcast_t ) ); + if( !h_mcast ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("zalloc of h_mcast failed\n") ); + return IB_INSUFFICIENT_MEMORY; + } + + /* Construct the AL object so we can call destroy_al_obj in case of failure. */ + construct_al_obj( &h_mcast->obj, AL_OBJ_TYPE_H_MCAST ); + + /* Check for synchronous operation. */ + h_mcast->flags = p_mcast_req->flags; + cl_event_construct( &h_mcast->event ); + sync = ( (h_mcast->flags & IB_FLAGS_SYNC) == IB_FLAGS_SYNC ); + if( sync ) + { + if( !cl_is_blockable() ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("Thread context not blockable\n") ); + __free_mcast( &h_mcast->obj ); + return IB_INVALID_SETTING; + } + + cl_status = cl_event_init( &h_mcast->event, TRUE ); + if( cl_status != CL_SUCCESS ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("unable to initialize event for sync operation\n") ); + __free_mcast( &h_mcast->obj ); + return ib_convert_cl_status( cl_status ); + } + } + + /* Initialize the AL object now. */ + status = init_al_obj( &h_mcast->obj, p_mcast_req->mcast_context, TRUE, + __destroying_mcast, __cleanup_mcast, __free_mcast ); + if( status != IB_SUCCESS ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("init_al_obj returned %s\n", ib_get_err_str( status )) ); + __free_mcast( &h_mcast->obj ); + return status; + } + + /* Copy the multicast context information. */ + h_mcast->pfn_mcast_cb = p_mcast_req->pfn_mcast_cb; + /* + * Copy the mcast member record so that we can leave without requiring the + * user to provide the settings. + */ + h_mcast->member_rec = p_mcast_req->member_rec; + h_mcast->port_guid = p_mcast_req->port_guid; + + /* Track the multicast with the QP instance. */ + status = attach_al_obj( &h_qp->obj, &h_mcast->obj ); + if( status != IB_SUCCESS ) + { + h_mcast->obj.pfn_destroy( &h_mcast->obj, NULL ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("attach_al_obj returned %s.\n", ib_get_err_str(status)) ); + return status; + } + + /* Issue the MAD to the SA. */ + status = send_join( h_mcast, p_mcast_req ); + if( status == IB_SUCCESS ) + { + /* If synchronous, wait for the completion. */ + if( sync ) + { + do + { + cl_status = cl_event_wait_on( + &h_mcast->event, EVENT_NO_TIMEOUT, AL_WAIT_ALERTABLE ); + } while( cl_status == CL_NOT_DONE ); + CL_ASSERT( cl_status == CL_SUCCESS ); + } + } + else + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("unable to send join request: %s\n", ib_get_err_str(status)) ); + h_mcast->obj.pfn_destroy( &h_mcast->obj, NULL ); + } + + /* + * Note: Don't release the reference taken in init_al_obj while we + * have the SA req outstanding. + */ + + AL_EXIT( AL_DBG_MCAST ); + return status; +} + + +static void +__destroying_mcast( + IN al_obj_t *p_obj ) +{ + ib_mcast_handle_t h_mcast; + ib_user_query_t sa_mad_data; + ib_api_status_t status; + + AL_ENTER( AL_DBG_MCAST ); + + h_mcast = PARENT_STRUCT( p_obj, ib_mcast_t, obj ); + + if( h_mcast->state != SA_REG_STARTING && h_mcast->state != SA_REG_ACTIVE ) + { + AL_EXIT( AL_DBG_MCAST ); + return; + } + + if( h_mcast->state == SA_REG_STARTING ) + { + cl_spinlock_acquire( &h_mcast->obj.lock ); + /* Cancel all outstanding join requests. */ + h_mcast->state = SA_REG_CANCELING; +#if defined( CL_KERNEL ) + if( h_mcast->sa_reg_req.p_sa_req_svc ) + al_cancel_sa_req( &h_mcast->sa_reg_req ); +#else /* defined( CL_KERNEL ) */ + if( h_mcast->sa_reg_req.hdl ) + al_cancel_sa_req( &h_mcast->sa_reg_req ); +#endif /* defined( CL_KERNEL ) */ + cl_spinlock_release( &h_mcast->obj.lock ); + } + + /* Set the request information. */ + h_mcast->sa_dereg_req.pfn_sa_req_cb = leave_req_cb; + + /* Set the MAD attributes and component mask correctly. */ + sa_mad_data.method = IB_MAD_METHOD_DELETE; + sa_mad_data.attr_id = IB_MAD_ATTR_MCMEMBER_RECORD; + sa_mad_data.attr_size = sizeof( ib_member_rec_t ); + + /* Set the component mask. */ + sa_mad_data.comp_mask = IB_MCR_COMPMASK_MGID | + IB_MCR_COMPMASK_PORT_GID | IB_MCR_COMPMASK_JOIN_STATE; + + sa_mad_data.p_attr = &h_mcast->member_rec; + + ref_al_obj( &h_mcast->obj ); + status = al_send_sa_req( + &h_mcast->sa_dereg_req, h_mcast->port_guid, 500, 0, &sa_mad_data, 0 ); + if( status != IB_SUCCESS ) + deref_al_obj( &h_mcast->obj ); + + AL_EXIT( AL_DBG_MCAST ); +} + + +static void +__cleanup_mcast( + IN al_obj_t *p_obj ) +{ + ib_mcast_handle_t h_mcast; + ib_api_status_t status; + + AL_ENTER( AL_DBG_MCAST ); + + h_mcast = PARENT_STRUCT( p_obj, ib_mcast_t, obj ); + + /* + * Detach from the multicast group to ensure that multicast messages + * are not received on this QP again. Note that we need to check for + * a valid verbs handle in case the attach failed earlier, and we are + * just calling ib_leave_mcast to notify the SA. + */ + if( h_mcast->h_ci_mcast ) + { + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MCAST, + ("detaching from multicast group\n") ); + status = verbs_detach_mcast( h_mcast ); + if( status != IB_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("detach failed: %s\n", ib_get_err_str(status)) ); + } + } + + AL_EXIT( AL_DBG_MCAST ); +} + + +static void +__free_mcast( + IN al_obj_t *p_obj ) +{ + ib_mcast_handle_t h_mcast; + + h_mcast = PARENT_STRUCT( p_obj, ib_mcast_t, obj ); + + cl_event_destroy( &h_mcast->event ); + destroy_al_obj( &h_mcast->obj ); + cl_free( h_mcast ); +} + + + +/* + * Format an SA request based on the user's request. + */ +static ib_api_status_t +send_join( + IN ib_mcast_t *p_mcast, + IN const ib_mcast_req_t* const p_mcast_req ) +{ + ib_user_query_t sa_mad_data; + ib_api_status_t status; + + AL_ENTER( AL_DBG_MCAST ); + + /* Set the request information. */ + p_mcast->sa_reg_req.pfn_sa_req_cb = join_req_cb; + + ib_gid_set_default( &p_mcast->member_rec.port_gid, p_mcast_req->port_guid ); + + /* Set the MAD attributes and component mask correctly. */ + sa_mad_data.method = IB_MAD_METHOD_SET; + sa_mad_data.attr_id = IB_MAD_ATTR_MCMEMBER_RECORD; + sa_mad_data.attr_size = sizeof( ib_member_rec_t ); + + /* Initialize the component mask. */ + sa_mad_data.comp_mask = IB_MCR_COMPMASK_MGID | + IB_MCR_COMPMASK_PORT_GID | IB_MCR_COMPMASK_JOIN_STATE; + + if( p_mcast_req->create ) + { + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MCAST, + ("requesting creation of mcast group\n") ); + + /* Set the necessary creation components. */ + sa_mad_data.comp_mask |= IB_MCR_COMPMASK_QKEY | + IB_MCR_COMPMASK_TCLASS | IB_MCR_COMPMASK_PKEY | + IB_MCR_COMPMASK_FLOW | IB_MCR_COMPMASK_SL; + + /* Set the MTU mask if so requested. */ + if( p_mcast_req->member_rec.mtu ) + { + sa_mad_data.comp_mask |= IB_MCR_COMPMASK_MTU_SEL; + if( (p_mcast_req->member_rec.mtu >> 6) != + IB_PATH_SELECTOR_LARGEST ) + { + sa_mad_data.comp_mask |= IB_MCR_COMPMASK_MTU; + } + } + + /* Set the rate mask if so requested. */ + if( p_mcast_req->member_rec.rate ) + { + sa_mad_data.comp_mask |= IB_MCR_COMPMASK_RATE_SEL; + if( (p_mcast_req->member_rec.rate >> 6) != + IB_PATH_SELECTOR_LARGEST ) + { + sa_mad_data.comp_mask |= IB_MCR_COMPMASK_RATE; + } + } + + /* Set the packet lifetime mask if so requested. */ + if( p_mcast_req->member_rec.pkt_life ) + { + sa_mad_data.comp_mask |= IB_MCR_COMPMASK_LIFE_SEL; + if( (p_mcast_req->member_rec.pkt_life >> 6) != + IB_PATH_SELECTOR_LARGEST ) + { + sa_mad_data.comp_mask |= IB_MCR_COMPMASK_LIFE; + } + } + } + + sa_mad_data.p_attr = &p_mcast->member_rec; + + p_mcast->state = SA_REG_STARTING; + status = al_send_sa_req( &p_mcast->sa_reg_req, p_mcast->port_guid, + p_mcast_req->timeout_ms, p_mcast_req->retry_cnt, &sa_mad_data, 0 ); + + AL_EXIT( AL_DBG_MCAST ); + return status; +} + + +/* + * Multicast join completion callback. + */ +static void +join_req_cb( + IN al_sa_req_t *p_sa_req, + IN ib_mad_element_t *p_mad_response ) +{ + ib_mcast_handle_t h_mcast; + ib_sa_mad_t *p_sa_mad; + + AL_ENTER( AL_DBG_MCAST ); + h_mcast = PARENT_STRUCT( p_sa_req, ib_mcast_t, sa_reg_req ); + + /* Record the status of the join request. */ + h_mcast->req_status = p_sa_req->status; + + if( p_mad_response ) + { + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MCAST, ("processing response\n") ); + p_sa_mad = (ib_sa_mad_t*)ib_get_mad_buf( p_mad_response ); + h_mcast->resp_status = p_sa_mad->status; + + /* Record the join membership information. */ + if( h_mcast->req_status == IB_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MCAST, ("join successful\n") ); + h_mcast->member_rec = *((ib_member_rec_t*)p_sa_mad->data); + } + + /* We no longer need the response MAD. */ + ib_put_mad( p_mad_response ); + } + + /* + * Finish processing the join in the async callback context since + * we can't attach the QP to the mcast group at dispatch. + */ + h_mcast->async.pfn_callback = join_async_cb; + cl_async_proc_queue( gp_async_proc_mgr, &h_mcast->async ); + AL_EXIT( AL_DBG_MCAST ); +} + + +/* + * Process the results of a join request. This call is invoked from + * the asynchronous processing manager to allow invoking the + * VPD's attach_mcast entrypoint at passive level. + */ +static void +join_async_cb( + IN cl_async_proc_item_t *p_item ) +{ + ib_api_status_t status; + ib_mcast_handle_t h_mcast; + ib_mcast_rec_t mcast_rec; + boolean_t sync; + + AL_ENTER( AL_DBG_MCAST ); + + h_mcast = PARENT_STRUCT( p_item, ib_mcast_t, async ); + + cl_spinlock_acquire( &h_mcast->obj.lock ); +#if defined( CL_KERNEL ) + CL_ASSERT( h_mcast->sa_reg_req.p_sa_req_svc ); + h_mcast->sa_reg_req.p_sa_req_svc = NULL; +#else /* defined( CL_KERNEL ) */ + h_mcast->sa_reg_req.hdl = AL_INVALID_HANDLE; +#endif /* defined( CL_KERNEL ) */ + cl_spinlock_release( &h_mcast->obj.lock ); + + /* Initialize the user's response. */ + cl_memclr( &mcast_rec, sizeof( ib_mcast_rec_t ) ); + mcast_rec.mcast_context = h_mcast->obj.context; + status = h_mcast->req_status; + mcast_rec.error_status = h_mcast->resp_status; + mcast_rec.p_member_rec = &h_mcast->member_rec; + + /* If a synchronous join fails, the blocking thread needs to do cleanup. */ + sync = ((h_mcast->flags & IB_FLAGS_SYNC) == IB_FLAGS_SYNC); + + /* See if the join operation was successful. */ + if( status == IB_SUCCESS ) + { + /* Ensure that the user wants the join operation to proceed. */ + if( h_mcast->state == SA_REG_STARTING ) + { + /* + * Change the state here so that we avoid trying to cancel + * the request if the verb operation fails. + */ + h_mcast->state = SA_REG_ACTIVE; + /* Attach the QP to the multicast group. */ + if(ib_member_get_state(mcast_rec.p_member_rec->scope_state) == IB_MC_REC_STATE_FULL_MEMBER) + { + status = verbs_attach_mcast(h_mcast); + if( status != IB_SUCCESS ) + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_MCAST, ("attach_mcast failed\n") ); + } + mcast_rec.h_mcast = h_mcast; + + } + else + { + /* + * The operation was canceled as a result of destroying the QP. + * Invoke the user's callback notifying them that the join was + * canceled. The join succeeded with the SA, but we don't + * attach the QP to the multicast group, so the user will not + * be aware that the join succeeded. + */ + CL_ASSERT( h_mcast->state == SA_REG_CANCELING ); + status = IB_CANCELED; + } + } + + mcast_rec.status = status; + CL_ASSERT( h_mcast->pfn_mcast_cb ); + h_mcast->pfn_mcast_cb( &mcast_rec ); + + /* If synchronous, signal that the join is done. */ + if( sync ) + cl_event_signal( &h_mcast->event ); + + /* Dereference the mcast object now that the SA operation is complete. */ + if( status != IB_SUCCESS ) + h_mcast->obj.pfn_destroy( &h_mcast->obj, NULL ); + else + deref_al_obj( &h_mcast->obj ); + + AL_EXIT( AL_DBG_MCAST ); +} + + + +ib_api_status_t +ib_leave_mcast( + IN const ib_mcast_handle_t h_mcast, + IN const ib_pfn_destroy_cb_t pfn_destroy_cb OPTIONAL ) +{ + + AL_ENTER( AL_DBG_MCAST ); + + if( !h_mcast ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("IB_INVALID_MCAST_HANDLE\n") ); + return IB_INVALID_MCAST_HANDLE; + } + + /* Record that we're already leaving the multicast group. */ + ref_al_obj( &h_mcast->obj ); + h_mcast->obj.pfn_destroy( &h_mcast->obj, pfn_destroy_cb ); + AL_EXIT( AL_DBG_MCAST ); + return IB_SUCCESS; +} + + +/* + * Multicast leave completion callback. + */ +static void +leave_req_cb( + IN al_sa_req_t *p_sa_req, + IN ib_mad_element_t *p_mad_response ) +{ + ib_mcast_handle_t h_mcast; + + AL_ENTER( AL_DBG_MCAST ); + h_mcast = PARENT_STRUCT( p_sa_req, ib_mcast_t, sa_dereg_req ); + + if( p_mad_response ) + ib_put_mad( p_mad_response ); + + /* + * Release the reference on the mcast object now that + * the SA operation is complete. + */ + deref_al_obj( &h_mcast->obj ); + AL_EXIT( AL_DBG_MCAST ); +} + + + +#if defined( CL_KERNEL ) + +/* + * Called by proxy to attach a QP to a multicast group. + */ +ib_api_status_t +al_attach_mcast( + IN const ib_qp_handle_t h_qp, + IN const ib_gid_t *p_mcast_gid, + IN const ib_net16_t mcast_lid, + OUT al_attach_handle_t *ph_attach, + IN OUT ci_umv_buf_t *p_umv_buf OPTIONAL ) +{ + al_attach_handle_t h_attach; + ib_api_status_t status; + + CL_ASSERT( h_qp ); + CL_ASSERT( ph_attach ); + + /* Allocate a attachment object. */ + h_attach = (al_attach_handle_t)cl_zalloc( sizeof( al_attach_t ) ); + if( !h_attach ) + { + return IB_INSUFFICIENT_MEMORY; + } + + /* Construct the attachment object. */ + construct_al_obj( &h_attach->obj, AL_OBJ_TYPE_H_ATTACH ); + + status = init_al_obj( &h_attach->obj, NULL, FALSE, + NULL, __cleanup_attach, __free_attach ); + if( status != IB_SUCCESS ) + { + __free_attach( &h_attach->obj ); + return status; + } + status = attach_al_obj( &h_qp->obj, &h_attach->obj ); + if( status != IB_SUCCESS ) + { + h_attach->obj.pfn_destroy( &h_attach->obj, NULL ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("attach_al_obj returned %s.\n", ib_get_err_str(status)) ); + return status; + } + + /* Attach the QP. */ + status = h_qp->obj.p_ci_ca->verbs.attach_mcast( h_qp->h_ci_qp, + p_mcast_gid, mcast_lid, &h_attach->h_ci_mcast, p_umv_buf ); + if( status != IB_SUCCESS ) + { + h_attach->obj.pfn_destroy( &h_attach->obj, NULL ); + return status; + } + + /* The proxy will release the reference taken in init_al_obj. */ + *ph_attach = h_attach; + return status; +} + + + +static void +__cleanup_attach( + IN al_obj_t *p_obj ) +{ + ib_api_status_t status; + al_attach_handle_t h_attach; + + CL_ASSERT( p_obj ); + h_attach = PARENT_STRUCT( p_obj, al_attach_t, obj ); + + if( h_attach->h_ci_mcast ) + { + status = h_attach->obj.p_ci_ca->verbs.detach_mcast( + h_attach->h_ci_mcast ); + CL_ASSERT( status == IB_SUCCESS ); + } +} + + +static void +__free_attach( + IN al_obj_t *p_obj ) +{ + al_attach_handle_t h_attach; + + CL_ASSERT( p_obj ); + h_attach = PARENT_STRUCT( p_obj, al_attach_t, obj ); + + destroy_al_obj( p_obj ); + cl_free( h_attach ); +} + +#endif /* CL_KERNEL */ diff --git a/branches/WOF2-3/core/al/al_mcast.h b/branches/WOF2-3/core/al/al_mcast.h new file mode 100644 index 00000000..4c3c0a25 --- /dev/null +++ b/branches/WOF2-3/core/al/al_mcast.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#if !defined(__AL_MCAST_H__) +#define __AL_MCAST_H__ + +#include + +#include "al_common.h" +#include "al_query.h" +#include + + +/* + * Tracks attaching to a multicast group in the kernel for QPs allocated to + * user-mode clients. + */ +typedef struct _al_attach +{ + al_obj_t obj; + ib_mcast_handle_t h_ci_mcast; /* CI CA handle from attach */ + +} al_attach_t, *al_attach_handle_t; + + +typedef struct _ib_mcast +{ + al_obj_t obj; + + al_sa_req_t sa_reg_req; + al_sa_req_t sa_dereg_req; + + ib_mcast_handle_t h_ci_mcast; + + cl_async_proc_item_t async; + + /* Used to perform synchronous requests. */ + ib_al_flags_t flags; + cl_event_t event; + + /* Status of the join/leave request. */ + ib_api_status_t req_status; + + /* Additional status information returned in the join/leave response. */ + ib_net16_t resp_status; + + al_sa_reg_state_t state; + ib_pfn_mcast_cb_t pfn_mcast_cb; + + /* Store member record to report to SA later. */ + ib_member_rec_t member_rec; + ib_net64_t port_guid; + +} ib_mcast_t; + + + + +void +al_cancel_mcast( + IN const ib_mcast_handle_t h_mcast ); + + +ib_api_status_t +al_join_mcast( + IN const ib_qp_handle_t h_qp, + IN const ib_mcast_req_t* const p_mcast_req ); + + +#if defined( CL_KERNEL ) +/* + * Called by proxy to attach a QP to a multicast group. + */ +ib_api_status_t +al_attach_mcast( + IN const ib_qp_handle_t h_qp, + IN const ib_gid_t *p_mcast_gid, + IN const ib_net16_t mcast_lid, + OUT al_attach_handle_t *ph_attach, + IN OUT ci_umv_buf_t *p_umv_buf OPTIONAL ); + +#endif /* CL_KERNEL */ + + +#endif /* __AL_MCAST_H__ */ diff --git a/branches/WOF2-3/core/al/al_mgr.h b/branches/WOF2-3/core/al/al_mgr.h new file mode 100644 index 00000000..684c6cb2 --- /dev/null +++ b/branches/WOF2-3/core/al/al_mgr.h @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#if !defined(__AL_MGR_H__) +#define __AL_MGR_H__ + + +#include +#include "al_ci_ca.h" +#include "al_common.h" +#include "al_proxy_ioctl.h" + +#ifndef CL_KERNEL +#include "ual_mgr.h" +#endif + + +typedef struct _al_mgr +{ + al_obj_t obj; + + /* List of all AL object's in the system. */ + cl_qlist_t al_obj_list; + cl_spinlock_t lock; + + /* Table of Channel Adapters. */ + cl_qlist_t ci_ca_list; + +#ifndef CL_KERNEL + ual_mgr_t ual_mgr; +#endif + +} al_mgr_t; + + +/* + * Globals used throughout AL + * + * Note that the exported symbols are only exported for the bus driver + * (loader) and are not intended for use by any normal AL clients. + */ +cl_async_proc_t *gp_async_proc_mgr; +cl_async_proc_t *gp_async_pnp_mgr; +al_mgr_t *gp_al_mgr; +ib_al_handle_t gh_al; +ib_pool_handle_t gh_mad_pool; +void *gp_tmp; +cl_obj_mgr_t *gp_obj_mgr; + + + +ib_api_status_t +create_al_mgr( void ); + + +void +print_al_objs( + IN const ib_al_handle_t h_al ); + +void +print_al_obj( + IN al_obj_t * const p_obj ); + +void +print_tail_al_objs( void ); + + +al_ci_ca_t* +acquire_ci_ca( + IN const ib_net64_t ci_ca_guid, + IN const ib_ca_handle_t h_ca ); + +void +release_ci_ca( + IN const ib_ca_handle_t h_ca ); + + +ib_ca_handle_t +acquire_ca( + IN const ib_net64_t ci_ca_guid ); + + +void +add_ci_ca( + IN al_ci_ca_t* const p_ci_ca ); + +void +remove_ci_ca( + IN al_ci_ca_t* const p_ci_ca ); + +al_ci_ca_t* +find_ci_ca( + IN const ib_net64_t ci_ca_guid ); + + +#endif /* __AL_MGR_H__ */ diff --git a/branches/WOF2-3/core/al/al_mgr_shared.c b/branches/WOF2-3/core/al/al_mgr_shared.c new file mode 100644 index 00000000..02bd4727 --- /dev/null +++ b/branches/WOF2-3/core/al/al_mgr_shared.c @@ -0,0 +1,676 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include "al.h" +#include "al_common.h" +#include "al_debug.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "al_mgr_shared.tmh" +#endif +#include "al_ci_ca.h" +#include "ib_common.h" +#include "al_mgr.h" +#include "al_pnp.h" + +ib_al_handle_t gh_al = NULL; +ib_pool_handle_t gh_mad_pool = NULL; +al_mgr_t *gp_al_mgr = NULL; +cl_async_proc_t *gp_async_proc_mgr = NULL; +cl_async_proc_t *gp_async_pnp_mgr = NULL; + + + +void +print_al_obj( + IN al_obj_t * const p_obj ) +{ + CL_ASSERT( p_obj ); + + UNUSED_PARAM( p_obj ); + + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("AL object %016Ix(%s), parent: %016Ix ref_cnt: %d\n", + (LONG_PTR)p_obj, ib_get_obj_type( p_obj ), + (LONG_PTR)p_obj->p_parent_obj, p_obj->ref_cnt) ); +} + + +void +print_al_objs( + IN const ib_al_handle_t h_al ) +{ + al_obj_t *p_obj; + cl_list_item_t *p_list_item; + + if( !gp_al_mgr ) + return; + + /* Display all access layer objects. */ + for( p_list_item = cl_qlist_head( &gp_al_mgr->al_obj_list ); + p_list_item != cl_qlist_end( &gp_al_mgr->al_obj_list ); + p_list_item = cl_qlist_next( p_list_item ) ) + { + p_obj = PARENT_STRUCT( p_list_item, al_obj_t, list_item ); + if( !h_al || p_obj->h_al == h_al ) + print_al_obj( p_obj ); + } +} + + + +void +print_tail_al_objs() +{ + al_obj_t *p_obj; + cl_list_item_t *p_list_item; + int count = 3; + + if( !gp_al_mgr ) + return; + + /* Display all access layer objects. */ + for( p_list_item = cl_qlist_tail( &gp_al_mgr->al_obj_list ); + p_list_item != cl_qlist_end( &gp_al_mgr->al_obj_list ) && count; + p_list_item = cl_qlist_prev( p_list_item ) ) + { + p_obj = PARENT_STRUCT( p_list_item, al_obj_t, list_item ); + print_al_obj( p_obj ); + count--; + } +} + + + +/* + * Search all available CI CAs in the system to see if one exists with the + * given GUID. + */ +al_ci_ca_t* +find_ci_ca( + IN const ib_net64_t ci_ca_guid ) +{ + cl_list_item_t *p_list_item; + al_ci_ca_t *p_ci_ca; + + AL_ENTER( AL_DBG_MGR ); + + for( p_list_item = cl_qlist_head( &gp_al_mgr->ci_ca_list ); + p_list_item != cl_qlist_end( &gp_al_mgr->ci_ca_list ); + p_list_item = cl_qlist_next( p_list_item ) ) + { + p_ci_ca = PARENT_STRUCT( p_list_item, al_ci_ca_t, list_item ); + if( p_ci_ca->verbs.guid == ci_ca_guid && + p_ci_ca->obj.state == CL_INITIALIZED ) + { + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MGR, + ("find_ci_ca:CA guid %I64x.\n", ci_ca_guid) ); + AL_EXIT( AL_DBG_MGR ); + return p_ci_ca; + } + } + + AL_EXIT( AL_DBG_MGR ); + return NULL; +} + + + +al_ci_ca_t* +acquire_ci_ca( + IN const ib_net64_t ci_ca_guid, + IN const ib_ca_handle_t h_ca ) +{ + al_ci_ca_t *p_ci_ca; + + cl_spinlock_acquire( &gp_al_mgr->obj.lock ); + p_ci_ca = find_ci_ca( ci_ca_guid ); + if( !p_ci_ca ) + { + cl_spinlock_release( &gp_al_mgr->obj.lock ); + return NULL; + } + + add_ca( p_ci_ca, h_ca ); + cl_spinlock_release( &gp_al_mgr->obj.lock ); + return p_ci_ca; +} + + + +void +release_ci_ca( + IN const ib_ca_handle_t h_ca ) +{ + AL_ENTER( AL_DBG_MGR ); + remove_ca( h_ca ); + AL_EXIT( AL_DBG_MGR ); +} + + + +void +add_ci_ca( + IN al_ci_ca_t* const p_ci_ca ) +{ + AL_ENTER( AL_DBG_MGR ); + cl_spinlock_acquire( &gp_al_mgr->obj.lock ); + cl_qlist_insert_tail( &gp_al_mgr->ci_ca_list, &p_ci_ca->list_item ); + ref_al_obj( &gp_al_mgr->obj ); + cl_spinlock_release( &gp_al_mgr->obj.lock ); + AL_EXIT( AL_DBG_MGR ); +} + + +void +remove_ci_ca( + IN al_ci_ca_t* const p_ci_ca ) +{ + AL_ENTER( AL_DBG_MGR ); + cl_spinlock_acquire( &gp_al_mgr->obj.lock ); + cl_qlist_remove_item( &gp_al_mgr->ci_ca_list, &p_ci_ca->list_item ); + cl_spinlock_release( &gp_al_mgr->obj.lock ); + deref_al_obj( &gp_al_mgr->obj ); + AL_EXIT( AL_DBG_MGR ); +} + + + +ib_ca_handle_t +acquire_ca( + IN const ib_net64_t ci_ca_guid ) +{ + al_ci_ca_t *p_ci_ca; + + cl_spinlock_acquire( &gp_al_mgr->obj.lock ); + p_ci_ca = find_ci_ca( ci_ca_guid ); + if( !p_ci_ca ) + { + cl_spinlock_release( &gp_al_mgr->obj.lock ); + return NULL; + } + + ref_al_obj( &p_ci_ca->h_ca->obj ); + cl_spinlock_release( &gp_al_mgr->obj.lock ); + return p_ci_ca->h_ca; +} + + + +#define SEARCH_CA_GUID (1) +#define SEARCH_PORT_GUID (2) + +/* + * Return the GUID of CA with the given port GID. + */ + +static ib_api_status_t +__get_guid_by_gid ( + IN ib_al_handle_t h_al, + IN const ib_gid_t* const p_gid, + IN const uintn_t type, + OUT ib_net64_t* const p_guid ) +{ + ib_net64_t *p_guid_array = NULL; + uint32_t size; + uintn_t ca_ind, port_ind, gid_ind, ca_cnt; + ib_api_status_t status = IB_SUCCESS; + ib_ca_attr_t *p_ca_attr = NULL; + ib_port_attr_t *p_port_attr = NULL; + + AL_ENTER( AL_DBG_MGR ); + + CL_ASSERT( h_al && p_gid && p_guid ); + + /* Get the number of CA GUIDs. */ + ca_cnt = 0; + p_guid_array = NULL; + status = ib_get_ca_guids( h_al, p_guid_array, &ca_cnt ); + if( status != IB_INSUFFICIENT_MEMORY ) + { + if( status == IB_SUCCESS ) + { + status = IB_NOT_FOUND; /* No CAs in the system */ + } + goto end; + } + + /* Allocate an array to store the CA GUIDs. */ + p_guid_array = cl_malloc( sizeof( ib_net64_t ) * ca_cnt ); + if( !p_guid_array ) + { + status = IB_INSUFFICIENT_MEMORY; + goto end; + } + + /* Get the list of CA GUIDs in the system. */ + status = ib_get_ca_guids( h_al, p_guid_array, &ca_cnt ); + if( status != IB_SUCCESS ) + goto end; + + /* Query each CA. */ + size = 0; + p_ca_attr = NULL; + for( ca_ind = 0; ca_ind < ca_cnt; ca_ind++ ) + { + /* Query the CA and port information. */ + status = ib_query_ca_by_guid( h_al, p_guid_array[ca_ind], + p_ca_attr, &size ); + + if( status == IB_INSUFFICIENT_MEMORY ) + { + /* Allocate a larger buffer and requery. */ + if( p_ca_attr ) + cl_free( p_ca_attr ); + + p_ca_attr = cl_malloc( size ); + if( !p_ca_attr ) + { + status = IB_INSUFFICIENT_MEMORY; + goto end; + } + + status = ib_query_ca_by_guid( h_al, p_guid_array[ca_ind], + p_ca_attr, &size ); + } + + if( status != IB_SUCCESS ) + goto end; + + /* Try to match the GID with one of the port's GIDs. */ + status = IB_NOT_FOUND; + for( port_ind = 0; port_ind < p_ca_attr->num_ports; port_ind++ ) + { + p_port_attr = &p_ca_attr->p_port_attr[port_ind]; + + for( gid_ind = 0; gid_ind < p_port_attr->num_gids; gid_ind++ ) + { + if( !cl_memcmp( &p_port_attr->p_gid_table[gid_ind], p_gid, + sizeof( ib_gid_t ) ) ) + { + if ( type == SEARCH_CA_GUID ) + *p_guid = p_guid_array[ca_ind]; + else + *p_guid = p_port_attr->port_guid; + status = IB_SUCCESS; + goto end; + } + } + } + } + +end: + if ( p_ca_attr ) + cl_free ( p_ca_attr ); + if ( p_guid_array ) + cl_free( p_guid_array ); + + AL_EXIT( AL_DBG_MGR ); + return status; +} + + + +ib_api_status_t +ib_get_ca_by_gid( + IN ib_al_handle_t h_al, + IN const ib_gid_t* const p_gid, + OUT ib_net64_t* const p_ca_guid ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_MGR ); + + if( AL_OBJ_INVALID_HANDLE( h_al, AL_OBJ_TYPE_H_AL ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_AL_HANDLE\n") ); + return IB_INVALID_AL_HANDLE; + } + if( !p_gid || !p_ca_guid ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + status = __get_guid_by_gid( h_al, p_gid, SEARCH_CA_GUID, p_ca_guid ); + + AL_EXIT( AL_DBG_MGR ); + return status; +} + + + +ib_api_status_t +ib_get_port_by_gid( + IN ib_al_handle_t h_al, + IN const ib_gid_t* const p_gid, + OUT ib_net64_t* const p_port_guid ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_MGR ); + + if( AL_OBJ_INVALID_HANDLE( h_al, AL_OBJ_TYPE_H_AL ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_AL_HANDLE\n") ); + return IB_INVALID_AL_HANDLE; + } + if( !p_gid || !p_port_guid ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + status = __get_guid_by_gid( h_al, p_gid, SEARCH_PORT_GUID, p_port_guid ); + + AL_EXIT( AL_DBG_MGR ); + return status; +} + + + +/* + * Return the GUIDs of all CAs the system. + */ +ib_api_status_t +ib_get_ca_guids( + IN ib_al_handle_t h_al, + OUT ib_net64_t* const p_guid_array OPTIONAL, + IN OUT size_t* const p_guid_cnt ) +{ + cl_list_item_t *p_list_item; + al_ci_ca_t *p_ci_ca; + uintn_t guid_cnt; + + AL_ENTER( AL_DBG_MGR ); + + if( AL_OBJ_INVALID_HANDLE( h_al, AL_OBJ_TYPE_H_AL ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_AL_HANDLE\n") ); + return IB_INVALID_AL_HANDLE; + } + if( !p_guid_cnt ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + /* Prevent CA additions or removals. */ + cl_spinlock_acquire( &gp_al_mgr->obj.lock ); + + /* + * Count the number of GUIDs available. Allow CA + * additions or removals and maintain the count. + */ + guid_cnt = cl_qlist_count( &gp_al_mgr->ci_ca_list ); + + /* Check if a GUID array of sufficient size was provided. */ + if( !p_guid_array || (*p_guid_cnt < guid_cnt) ) + { + /* Array too small. */ + cl_spinlock_release( &gp_al_mgr->obj.lock ); + + /* Return the actual count. */ + *p_guid_cnt = guid_cnt; + + AL_EXIT( AL_DBG_MGR ); + return IB_INSUFFICIENT_MEMORY; + } + + /* Return the actual count. */ + *p_guid_cnt = guid_cnt; + + /* Copy the GUIDs into the array. */ + guid_cnt = 0; + for( p_list_item = cl_qlist_head( &gp_al_mgr->ci_ca_list ); + p_list_item != cl_qlist_end( &gp_al_mgr->ci_ca_list ); + p_list_item = cl_qlist_next( p_list_item ) ) + { + p_ci_ca = PARENT_STRUCT( p_list_item, al_ci_ca_t, list_item ); + p_guid_array[guid_cnt++] = p_ci_ca->verbs.guid; + } + + /* Allow CA additions or removals. */ + cl_spinlock_release( &gp_al_mgr->obj.lock ); + + AL_EXIT( AL_DBG_MGR ); + return IB_SUCCESS; +} + + + +static boolean_t +__match_ca_attr( + IN al_ci_ca_t * const p_ci_ca, + IN const uint64_t attr_mask ) +{ + boolean_t match; + + ci_ca_lock_attr( p_ci_ca ); + + /* We don't match any attributes for CA's currently. */ + UNUSED_PARAM( attr_mask ); + match = TRUE; + + ci_ca_unlock_attr( p_ci_ca ); + + return match; +} + + + +static ib_api_status_t +__get_ca_guid( + IN const uint32_t index, + IN const uint64_t attr_mask, + OUT ib_net64_t* const p_guid ) +{ + uint32_t ca_index; + cl_list_item_t *p_list_item; + al_ci_ca_t *p_ci_ca; + ib_api_status_t status; + + AL_ENTER( AL_DBG_MGR ); + + /* Prevent CA additions or removals. */ + cl_spinlock_acquire( &gp_al_mgr->obj.lock ); + + /* Check for a valid index. */ + if( index != IB_ANY_INDEX && + index >= cl_qlist_count( &gp_al_mgr->ci_ca_list ) ) + { + cl_spinlock_release( &gp_al_mgr->obj.lock ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_INDEX\n") ); + return IB_INVALID_INDEX; + } + + /* + * Find the CA at the correct index and check its attributes. Optimize + * for the "any index" case. + */ + status = IB_NO_MATCH; + ca_index = 0; + for( p_list_item = cl_qlist_head( &gp_al_mgr->ci_ca_list ); + p_list_item != cl_qlist_end( &gp_al_mgr->ci_ca_list ); + p_list_item = cl_qlist_next( p_list_item ) ) + { + p_ci_ca = PARENT_STRUCT( p_list_item, al_ci_ca_t, list_item ); + + if( (ca_index == index || index == IB_ANY_INDEX) && + __match_ca_attr( p_ci_ca, attr_mask ) ) + { + *p_guid = p_ci_ca->verbs.guid; + status = IB_SUCCESS; + break; + } + ca_index++; + } + + cl_spinlock_release( &gp_al_mgr->obj.lock ); + + AL_EXIT( AL_DBG_MGR ); + return status; +} + + + +static boolean_t +__match_port_attr( + IN const ib_port_attr_t * const p_port_attr, + IN const uint64_t attr_mask ) +{ + if( attr_mask & IB_DEV_PORT_ACTIVE ) + return( p_port_attr->link_state == IB_LINK_ACTIVE ); + + return TRUE; +} + + + +static ib_api_status_t +__get_port_guid( + IN const uint32_t index, + IN const uint64_t attr_mask, + OUT ib_net64_t* const p_guid ) +{ + uint32_t port_index, i; + cl_list_item_t *p_list_item; + al_ci_ca_t *p_ci_ca; + ib_api_status_t status; + + AL_ENTER( AL_DBG_MGR ); + + /* Prevent CA additions or removals. */ + cl_spinlock_acquire( &gp_al_mgr->obj.lock ); + + /* + * Find the port at the correct index and check its attributes. Optimize + * for the "any index" case. + */ + status = IB_NO_MATCH; + port_index = 0; + for( p_list_item = cl_qlist_head( &gp_al_mgr->ci_ca_list ); + p_list_item != cl_qlist_end( &gp_al_mgr->ci_ca_list ) && + status != IB_SUCCESS; + p_list_item = cl_qlist_next( p_list_item ) ) + { + p_ci_ca = PARENT_STRUCT( p_list_item, al_ci_ca_t, list_item ); + + /* Check all ports on this CA. */ + ci_ca_lock_attr( p_ci_ca ); + for( i = 0; i < p_ci_ca->p_pnp_attr->num_ports; i++ ) + { + /* Check the attributes. */ + if( (port_index == index || index == IB_ANY_INDEX) && + __match_port_attr( &p_ci_ca->p_pnp_attr->p_port_attr[i], + attr_mask ) ) + { + *p_guid = p_ci_ca->verbs.guid; + status = IB_SUCCESS; + break; + } + port_index++; + } + ci_ca_unlock_attr( p_ci_ca ); + } + cl_spinlock_release( &gp_al_mgr->obj.lock ); + + /* + * See if the index was valid. We need to perform this check at the + * end of the routine, since we don't know how many ports we have. + */ + if( p_list_item == cl_qlist_end( &gp_al_mgr->ci_ca_list ) && + index != IB_ANY_INDEX ) + { + status = IB_INVALID_INDEX; + } + + AL_EXIT( AL_DBG_MGR ); + return status; +} + + + +ib_api_status_t +ib_get_guid( + IN ib_al_handle_t h_al, + IN const uint32_t index, + IN const ib_pnp_class_t device_type, + IN const uint64_t attr_mask, + OUT ib_net64_t* const p_guid ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_MGR ); + + if( AL_OBJ_INVALID_HANDLE( h_al, AL_OBJ_TYPE_H_AL ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_AL_HANDLE\n") ); + return IB_INVALID_AL_HANDLE; + } + if( !p_guid ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + switch( device_type ) + { + case IB_PNP_CA: + status = __get_ca_guid( index, attr_mask, p_guid ); + break; + + case IB_PNP_PORT: + status = __get_port_guid( index, attr_mask, p_guid ); + break; + + case IB_PNP_IOC: + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("IOC GUIDs not supported at this time\n") ); + return IB_UNSUPPORTED; + + default: + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_SETTING\n") ); + return IB_INVALID_SETTING; + } + + AL_EXIT( AL_DBG_MGR ); + return status; +} + + + + + diff --git a/branches/WOF2-3/core/al/al_mr.h b/branches/WOF2-3/core/al/al_mr.h new file mode 100644 index 00000000..07b5880e --- /dev/null +++ b/branches/WOF2-3/core/al/al_mr.h @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#if !defined(__AL_MR_H__) +#define __AL_MR_H__ + + +#include + +#include "al_ca.h" + + +typedef struct _al_shmid +{ + al_obj_t obj; + cl_list_item_t list_item; + + /* List of sharing registered memory regions. */ + cl_list_t mr_list; + int id; + +} al_shmid_t; + + + +/* + * The MR and MR alias structures must be the same in order to seemlessly + * handle posting of work requests. + */ +typedef struct _ib_mr +{ + al_obj_t obj; + ib_mr_handle_t h_ci_mr; /* Actual HW handle. */ + + /* Reference to any memory registrations shared between processes. */ + al_shmid_t *p_shmid; + +} ib_mr_t; + + +cl_status_t +mr_ctor( + IN void* const p_object, + IN void* context, + OUT cl_pool_item_t** const pp_pool_item ); + + +void +mr_dtor( + IN const cl_pool_item_t* const p_pool_item, + IN void* context ); + + +ib_api_status_t +reg_mem( + IN const ib_pd_handle_t h_pd, + IN const ib_mr_create_t* const p_mr_create, + OUT net32_t* const p_lkey, + OUT net32_t* const p_rkey, + OUT ib_mr_handle_t* const ph_mr, + IN boolean_t um_call ); + + +ib_api_status_t +reg_phys( + IN const ib_pd_handle_t h_pd, + IN const ib_phys_create_t* const p_phys_create, + IN OUT uint64_t* const p_vaddr, + OUT net32_t* const p_lkey, + OUT net32_t* const p_rkey, + OUT ib_mr_handle_t* const ph_mr, + IN boolean_t um_call ); + + +ib_api_status_t +reg_shared( + IN const ib_mr_handle_t h_mr, + IN const ib_pd_handle_t h_pd, + IN const ib_access_t access_ctrl, + IN OUT uint64_t* const p_vaddr, + OUT net32_t* const p_lkey, + OUT net32_t* const p_rkey, + OUT ib_mr_handle_t* const ph_mr, + IN boolean_t um_call ); + + +ib_api_status_t +rereg_mem( + IN const ib_mr_handle_t h_mr, + IN const ib_mr_mod_t mr_mod_mask, + IN const ib_mr_create_t* const p_mr_create OPTIONAL, + OUT net32_t* const p_lkey, + OUT net32_t* const p_rkey, + IN const ib_pd_handle_t h_pd OPTIONAL, + IN boolean_t um_call ); + + +ib_api_status_t +rereg_phys( + IN const ib_mr_handle_t h_mr, + IN const ib_mr_mod_t mr_mod_mask, + IN const ib_phys_create_t* const p_phys_create OPTIONAL, + IN OUT uint64_t* const p_vaddr, + OUT net32_t* const p_lkey, + OUT net32_t* const p_rkey, + IN const ib_pd_handle_t h_pd OPTIONAL, + IN boolean_t um_call ); + + +ib_api_status_t +dereg_mr( + IN const ib_mr_handle_t h_mr ); + +ib_api_status_t +reg_shmid( + IN const ib_pd_handle_t h_pd, + IN const ib_shmid_t shmid, + IN const ib_mr_create_t* const p_mr_create, + IN OUT uint64_t* const p_vaddr, + OUT net32_t* const p_lkey, + OUT net32_t* const p_rkey, + OUT ib_mr_handle_t* const ph_mr ); + + +#ifdef CL_KERNEL +typedef struct _mlnx_fmr +{ + al_obj_t obj; + mlnx_fmr_handle_t h_ci_fmr; /* Actual HW handle. */ + struct _mlnx_fmr* p_next; +} mlnx_fmr_t; + + + +cl_status_t +mlnx_fmr_ctor( + IN void* const p_object, + IN void* context, + OUT cl_pool_item_t** const pp_pool_item ); + + +void +mlnx_fmr_dtor( + IN const cl_pool_item_t* const p_pool_item, + IN void* context ); + + + +#endif + + +#endif /* __AL_MR_H__ */ diff --git a/branches/WOF2-3/core/al/al_mr_shared.c b/branches/WOF2-3/core/al/al_mr_shared.c new file mode 100644 index 00000000..ef5192d8 --- /dev/null +++ b/branches/WOF2-3/core/al/al_mr_shared.c @@ -0,0 +1,635 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include +#include "al.h" +#include "al_debug.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "al_mr_shared.tmh" +#endif +#include "al_mr.h" +#include "al_pd.h" +#include "al_res_mgr.h" +#include "al_verbs.h" + +#include "ib_common.h" + + +static void +__cleanup_mr( + IN struct _al_obj *p_obj ); + +static void +__return_mr( + IN al_obj_t *p_obj ); + + +cl_status_t +mr_ctor( + IN void* const p_object, + IN void* context, + OUT cl_pool_item_t** const pp_pool_item ) +{ + ib_api_status_t status; + ib_mr_handle_t h_mr; + + UNUSED_PARAM( context ); + + h_mr = (ib_mr_handle_t)p_object; + cl_memclr( h_mr, sizeof( ib_mr_t ) ); + + construct_al_obj( &h_mr->obj, AL_OBJ_TYPE_H_MR ); + status = init_al_obj( &h_mr->obj, NULL, FALSE, NULL, + __cleanup_mr, __return_mr ); + if( status != IB_SUCCESS ) + { + return CL_ERROR; + } + + *pp_pool_item = &((ib_mr_handle_t)p_object)->obj.pool_item; + + /* Release the reference taken in init_al_obj. */ + deref_al_obj( &h_mr->obj ); + + return CL_SUCCESS; +} + + + +void +mr_dtor( + IN const cl_pool_item_t* const p_pool_item, + IN void* context ) +{ + al_obj_t *p_obj; + + UNUSED_PARAM( context ); + + p_obj = PARENT_STRUCT( p_pool_item, al_obj_t, pool_item ); + + /* + * The MR is being totally destroyed. Modify the free_cb to destroy the + * AL object. + */ + p_obj->pfn_free = (al_pfn_free_t)destroy_al_obj; + ref_al_obj( p_obj ); + p_obj->pfn_destroy( p_obj, NULL ); +} + + + +static void +__cleanup_mr( + IN struct _al_obj *p_obj ) +{ + ib_api_status_t status; + ib_mr_handle_t h_mr; + + CL_ASSERT( p_obj ); + h_mr = PARENT_STRUCT( p_obj, ib_mr_t, obj ); + + /* Dereference any shared memory registrations. */ + verbs_release_shmid(h_mr); + + /* Deregister the memory. */ + if( verbs_check_mr(h_mr) ) + { + status = verbs_deregister_mr(h_mr); + + /* + * This was our last chance to deregister the MR. All MW's should + * be destroyed by now. + */ + CL_ASSERT( status == IB_SUCCESS ); + h_mr->h_ci_mr = NULL; +#ifndef CL_KERNEL + h_mr->obj.hdl = AL_INVALID_HANDLE; +#endif + } +} + + + +static void +__return_mr( + IN al_obj_t *p_obj ) +{ + ib_mr_handle_t h_mr; + + h_mr = PARENT_STRUCT( p_obj, ib_mr_t, obj ); + reset_al_obj( p_obj ); + put_mr( h_mr ); +} + + + +ib_api_status_t +ib_reg_mem( + IN const ib_pd_handle_t h_pd, + IN const ib_mr_create_t* const p_mr_create, + OUT net32_t* const p_lkey, + OUT net32_t* const p_rkey, + OUT ib_mr_handle_t* const ph_mr ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_MR ); + + if( AL_OBJ_INVALID_HANDLE( h_pd, AL_OBJ_TYPE_H_PD ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PD_HANDLE\n") ); + return IB_INVALID_PD_HANDLE; + } + + status = reg_mem( h_pd, p_mr_create, p_lkey, p_rkey, ph_mr, FALSE ); + + /* Release the reference taken in alloc_mr for initialization. */ + if( status == IB_SUCCESS ) + deref_al_obj( &(*ph_mr)->obj ); + + AL_EXIT( AL_DBG_MR ); + return status; +} + + + +ib_api_status_t +reg_mem( + IN const ib_pd_handle_t h_pd, + IN const ib_mr_create_t* const p_mr_create, + OUT net32_t* const p_lkey, + OUT net32_t* const p_rkey, + OUT ib_mr_handle_t* const ph_mr, + IN boolean_t um_call ) +{ + ib_mr_handle_t h_mr; + ib_api_status_t status; + + AL_ENTER( AL_DBG_MR ); + + if( !p_mr_create || !p_lkey || !p_rkey || !ph_mr ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + /* Get a MR tracking structure. */ + h_mr = alloc_mr(); + if( !h_mr ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("unable to allocate memory handle\n") ); + return IB_INSUFFICIENT_MEMORY; + } + + status = attach_al_obj( &h_pd->obj, &h_mr->obj ); + if( status != IB_SUCCESS ) + { + h_mr->obj.pfn_destroy( &h_mr->obj, NULL ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("attach_al_obj returned %s.\n", ib_get_err_str(status)) ); + return status; + } + + /* Register the memory region. */ + status = verbs_register_mr( h_pd, p_mr_create, p_lkey, p_rkey, h_mr ); + if( status != IB_SUCCESS ) + { + h_mr->obj.pfn_destroy( &h_mr->obj, NULL ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("unable to register memory: %s\n", ib_get_err_str(status)) ); + return status; + } + + *ph_mr = h_mr; + + AL_EXIT( AL_DBG_MR ); + return IB_SUCCESS; +} + + + +ib_api_status_t +ib_reg_phys( + IN const ib_pd_handle_t h_pd, + IN const ib_phys_create_t* const p_phys_create, + IN OUT uint64_t* const p_vaddr, + OUT net32_t* const p_lkey, + OUT net32_t* const p_rkey, + OUT ib_mr_handle_t* const ph_mr ) +{ + ib_mr_handle_t h_mr; + ib_api_status_t status; + + AL_ENTER( AL_DBG_MR ); + + if( AL_OBJ_INVALID_HANDLE( h_pd, AL_OBJ_TYPE_H_PD ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PD_HANDLE\n") ); + return IB_INVALID_PD_HANDLE; + } + if( !p_vaddr || !p_lkey || !p_rkey || !ph_mr ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + /* Get a MR tracking structure. */ + h_mr = alloc_mr(); + if( !h_mr ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("unable to allocate memory handle\n") ); + return IB_INSUFFICIENT_MEMORY; + } + + status = attach_al_obj( &h_pd->obj, &h_mr->obj ); + if( status != IB_SUCCESS ) + { + h_mr->obj.pfn_destroy( &h_mr->obj, NULL ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("attach_al_obj returned %s.\n", ib_get_err_str(status)) ); + return status; + } + + /* Register the memory region. */ + status = verbs_register_pmr( h_pd, p_phys_create, p_vaddr, + p_lkey, p_rkey, h_mr ); + if( status != IB_SUCCESS ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("unable to register memory: %s\n", ib_get_err_str(status)) ); + h_mr->obj.pfn_destroy( &h_mr->obj, NULL ); + return status; + } + + *ph_mr = h_mr; + + /* Release the reference taken in alloc_mr for initialization. */ + deref_al_obj( &h_mr->obj ); + + AL_EXIT( AL_DBG_MR ); + return IB_SUCCESS; +} + + + +ib_api_status_t +ib_rereg_mem( + IN const ib_mr_handle_t h_mr, + IN const ib_mr_mod_t mr_mod_mask, + IN const ib_mr_create_t* const p_mr_create OPTIONAL, + OUT net32_t* const p_lkey, + OUT net32_t* const p_rkey, + IN const ib_pd_handle_t h_pd OPTIONAL ) +{ + if( AL_OBJ_INVALID_HANDLE( h_mr, AL_OBJ_TYPE_H_MR ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_MR_HANDLE\n") ); + return IB_INVALID_MR_HANDLE; + } + + return rereg_mem( + h_mr, mr_mod_mask, p_mr_create, p_lkey, p_rkey, h_pd, FALSE ); +} + + +ib_api_status_t +rereg_mem( + IN const ib_mr_handle_t h_mr, + IN const ib_mr_mod_t mr_mod_mask, + IN const ib_mr_create_t* const p_mr_create OPTIONAL, + OUT net32_t* const p_lkey, + OUT net32_t* const p_rkey, + IN const ib_pd_handle_t h_pd OPTIONAL, + IN boolean_t um_call ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_MR ); + + if( ( mr_mod_mask & IB_MR_MOD_PD ) ) + { + if( AL_OBJ_INVALID_HANDLE( h_pd, AL_OBJ_TYPE_H_PD ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PD_HANDLE\n") ); + return IB_INVALID_PD_HANDLE; + } + if( h_pd->obj.h_al != h_mr->obj.h_al ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PD_HANDLE\n") ); + return IB_INVALID_PD_HANDLE; + } + } + if( !p_lkey || !p_rkey ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + /* Modify the registered memory region. */ + status = verbs_modify_mr( h_mr, mr_mod_mask, p_mr_create, + p_lkey, p_rkey, h_pd ); + + /* If we're changing the PD, we need to update the object hierarchy. */ + if( h_pd && (status == IB_SUCCESS) ) + { + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MR, ("associating MR with new PD\n") ); + detach_al_obj( &h_mr->obj ); + deref_al_obj( h_mr->obj.p_parent_obj ); + status = attach_al_obj( &h_pd->obj, &h_mr->obj ); + CL_ASSERT( status ); + } + + AL_EXIT( AL_DBG_MR ); + return status; +} + + + +ib_api_status_t +ib_rereg_phys( + IN const ib_mr_handle_t h_mr, + IN const ib_mr_mod_t mr_mod_mask, + IN const ib_phys_create_t* const p_phys_create OPTIONAL, + IN OUT uint64_t* const p_vaddr, + OUT net32_t* const p_lkey, + OUT net32_t* const p_rkey, + IN const ib_pd_handle_t h_pd OPTIONAL ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_MR ); + + if( AL_OBJ_INVALID_HANDLE( h_mr, AL_OBJ_TYPE_H_MR ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_MR_HANDLE\n") ); + return IB_INVALID_MR_HANDLE; + } + if( ( mr_mod_mask & IB_MR_MOD_PD ) ) + { + if( AL_OBJ_INVALID_HANDLE( h_pd, AL_OBJ_TYPE_H_PD ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PD_HANDLE\n") ); + return IB_INVALID_PD_HANDLE; + } + if( h_pd->obj.p_parent_obj != h_mr->obj.p_parent_obj->p_parent_obj ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PD_HANDLE\n") ); + return IB_INVALID_PD_HANDLE; + } + } + if( !p_vaddr || !p_lkey || !p_rkey ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + /* Modify the registered memory region. */ + status = verbs_modify_pmr( h_mr, mr_mod_mask, p_phys_create, p_vaddr, + p_lkey, p_rkey, h_pd ); + + /* If we're changing the PD, we need to update the object hierarchy. */ + if( h_pd && (status == IB_SUCCESS) ) + { + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MR, ("associating MR with new PD\n") ); + detach_al_obj( &h_mr->obj ); + deref_al_obj( h_mr->obj.p_parent_obj ); + status = attach_al_obj( &h_pd->obj, &h_mr->obj ); + CL_ASSERT( status ); + } + + AL_EXIT( AL_DBG_MR ); + return status; +} + + + +ib_api_status_t +ib_reg_shared( + IN const ib_mr_handle_t h_mr, + IN const ib_pd_handle_t h_pd, + IN const ib_access_t access_ctrl, + IN OUT uint64_t* const p_vaddr, + OUT net32_t* const p_lkey, + OUT net32_t* const p_rkey, + OUT ib_mr_handle_t* const ph_mr ) +{ + ib_api_status_t status; + + if( AL_OBJ_INVALID_HANDLE( h_mr, AL_OBJ_TYPE_H_MR ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_MR_HANDLE\n") ); + return IB_INVALID_MR_HANDLE; + } + if( AL_OBJ_INVALID_HANDLE( h_pd, AL_OBJ_TYPE_H_PD ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PD_HANDLE\n") ); + return IB_INVALID_PD_HANDLE; + } + + status = reg_shared( h_mr, h_pd, access_ctrl, p_vaddr, p_lkey, p_rkey, + ph_mr, FALSE ); + + /* Release the reference taken in alloc_mr for initialization. */ + if( status == IB_SUCCESS ) + deref_al_obj( &(*ph_mr)->obj ); + + return status; +} + + + +ib_api_status_t +reg_shared( + IN const ib_mr_handle_t h_mr, + IN const ib_pd_handle_t h_pd, + IN const ib_access_t access_ctrl, + IN OUT uint64_t* const p_vaddr, + OUT net32_t* const p_lkey, + OUT net32_t* const p_rkey, + OUT ib_mr_handle_t* const ph_mr, + IN boolean_t um_call ) +{ + ib_mr_handle_t h_new_mr; + ib_api_status_t status; + + AL_ENTER( AL_DBG_MR ); + + if( !p_vaddr || !p_lkey || !p_rkey || !ph_mr ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + /* Get a MR tracking structure. */ + h_new_mr = alloc_mr(); + if( !h_new_mr ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("unable to allocate memory handle\n") ); + return IB_INSUFFICIENT_MEMORY; + } + + status = attach_al_obj( &h_pd->obj, &h_new_mr->obj ); + if( status != IB_SUCCESS ) + { + h_new_mr->obj.pfn_destroy( &h_new_mr->obj, NULL ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("attach_al_obj returned %s.\n", ib_get_err_str(status)) ); + return status; + } + + /* Register the memory region. */ + status = verbs_register_smr( h_mr, h_pd, access_ctrl, p_vaddr, + p_lkey, p_rkey, h_new_mr ); + if( status != IB_SUCCESS ) + { + h_new_mr->obj.pfn_destroy( &h_new_mr->obj, NULL ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("unable to register memory: %s\n", ib_get_err_str(status)) ); + return status; + } + + *ph_mr = h_new_mr; + + AL_EXIT( AL_DBG_MR ); + return IB_SUCCESS; +} + + + +ib_api_status_t +ib_dereg_mr( + IN const ib_mr_handle_t h_mr ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_MR ); + + if( AL_OBJ_INVALID_HANDLE( h_mr, AL_OBJ_TYPE_H_MR ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_MR_HANDLE\n") ); + return IB_INVALID_MR_HANDLE; + } + + ref_al_obj( &h_mr->obj ); + + status = dereg_mr( h_mr ); + if( status != IB_SUCCESS ) + deref_al_obj( &h_mr->obj ); + + AL_EXIT( AL_DBG_MR ); + return status; +} + + + +ib_api_status_t +dereg_mr( + IN const ib_mr_handle_t h_mr ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_MR ); + + if( !verbs_check_mr(h_mr) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_MR_HANDLE\n") ); + return IB_INVALID_MR_HANDLE; + } + + /* + * MR's are destroyed synchronously. Go ahead and try to destroy it now. + * If we fail, then report the failure to the user. Failures could be + * a result of having a memory window bound to the region, which we cannot + * track in the kernel for user-mode clients. + */ + status = verbs_deregister_mr(h_mr); + + if( status == IB_SUCCESS ) + { + h_mr->h_ci_mr = NULL; +#ifndef CL_KERNEL + h_mr->obj.hdl = AL_INVALID_HANDLE; +#endif + + /* We're good to destroy the object. */ + h_mr->obj.pfn_destroy( &h_mr->obj, NULL ); + } + + AL_EXIT( AL_DBG_MR ); + return status; +} + + + +ib_api_status_t +ib_query_mr( + IN const ib_mr_handle_t h_mr, + OUT ib_mr_attr_t* const p_mr_attr ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_MR ); + + if( AL_OBJ_INVALID_HANDLE( h_mr, AL_OBJ_TYPE_H_MR ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_MR_HANDLE\n") ); + return IB_INVALID_MR_HANDLE; + } + if( !p_mr_attr ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + status = verbs_query_mr(h_mr, p_mr_attr); + + /* Set AL's handles. */ + if( status == IB_SUCCESS ) + { + p_mr_attr->h_pd = PARENT_STRUCT( h_mr->obj.p_parent_obj, ib_pd_t, obj ); + } + else + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("unable to query memory region: %s\n", ib_get_err_str(status)) ); + } + + AL_EXIT( AL_DBG_MR ); + return status; +} diff --git a/branches/WOF2-3/core/al/al_mw.c b/branches/WOF2-3/core/al/al_mw.c new file mode 100644 index 00000000..10b92cef --- /dev/null +++ b/branches/WOF2-3/core/al/al_mw.c @@ -0,0 +1,260 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include + +#include "al_debug.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "al_mw.tmh" +#endif +#include "al_mw.h" +#include "al_pd.h" +#include "al_verbs.h" + + + +void +destroying_mw( + IN struct _al_obj *p_obj ); + +void +cleanup_mw( + IN struct _al_obj *p_obj ); + +void +free_mw( + IN al_obj_t *p_obj ); + + + +ib_api_status_t +create_mw( + IN const ib_pd_handle_t h_pd, + OUT net32_t* const p_rkey, + OUT ib_mw_handle_t* const ph_mw, + IN OUT ci_umv_buf_t* const p_umv_buf ) +{ + ib_mw_handle_t h_mw; + ib_api_status_t status; + al_obj_type_t obj_type = AL_OBJ_TYPE_H_MW; + + if( !p_rkey || !ph_mw ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + /* Allocate a MW tracking structure. */ + h_mw = cl_zalloc( sizeof( ib_mw_t) ); + if( !h_mw ) + { + return IB_INSUFFICIENT_MEMORY; + } + + if( p_umv_buf ) + obj_type |= AL_OBJ_SUBTYPE_UM_EXPORT; + + /* Construct the mw. */ + construct_al_obj( &h_mw->obj, obj_type ); + + status = init_al_obj( &h_mw->obj, NULL, FALSE, + destroying_mw, NULL, free_mw ); + if( status != IB_SUCCESS ) + { + free_mw( &h_mw->obj ); + return status; + } + status = attach_al_obj( &h_pd->obj, &h_mw->obj ); + if( status != IB_SUCCESS ) + { + h_mw->obj.pfn_destroy( &h_mw->obj, NULL ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("attach_al_obj returned %s.\n", ib_get_err_str(status)) ); + return status; + } + + /* Insert the MW into the PD's MW list used to order destruction. */ + pd_insert_mw( h_mw ); + + /* Allocate the protection domain. */ + status = verbs_create_mw( h_pd, p_rkey, h_mw ); + if( status != IB_SUCCESS ) + { + h_mw->obj.pfn_destroy( &h_mw->obj, NULL ); + return status; + } + + *ph_mw = h_mw; + + return IB_SUCCESS; +} + + + +ib_api_status_t +ib_destroy_mw( + IN const ib_mw_handle_t h_mw ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_MW ); + + if( AL_OBJ_INVALID_HANDLE( h_mw, AL_OBJ_TYPE_H_MW ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_MW_HANDLE\n") ); + return IB_INVALID_MW_HANDLE; + } + + ref_al_obj( &h_mw->obj ); + + status = destroy_mw( h_mw ); + + if( status != IB_SUCCESS ) + deref_al_obj( &h_mw->obj ); + + AL_EXIT( AL_DBG_MW ); + return status; +} + + + +ib_api_status_t +destroy_mw( + IN const ib_mw_handle_t h_mw ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_MW ); + + if( !verbs_check_mw( h_mw ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_MW_HANDLE\n") ); + return IB_INVALID_MW_HANDLE; + } + + /* + * MW's are destroyed synchronously. Go ahead and try to destroy it now. + * If we fail, then report the failure to the user. + */ + status = verbs_destroy_mw( h_mw ); + + if( status == IB_SUCCESS ) + h_mw->obj.pfn_destroy( &h_mw->obj, NULL ); + + AL_EXIT( AL_DBG_MW ); + return status; +} + + + +void +destroying_mw( + IN struct _al_obj *p_obj ) +{ + ib_mw_handle_t h_mw; + + CL_ASSERT( p_obj ); + h_mw = PARENT_STRUCT( p_obj, ib_mw_t, obj ); + + /* Remove the MW from the PD's MW list. */ + pd_remove_mw( h_mw ); +} + + + +/* + * Release all resources associated with the protection domain. + */ +void +free_mw( + IN al_obj_t *p_obj ) +{ + ib_mw_handle_t h_mw; + + CL_ASSERT( p_obj ); + h_mw = PARENT_STRUCT( p_obj, ib_mw_t, obj ); + + destroy_al_obj( p_obj ); + cl_free( h_mw ); +} + + + +ib_api_status_t +ib_query_mw( + IN const ib_mw_handle_t h_mw, + OUT ib_pd_handle_t* const ph_pd, + OUT net32_t* const p_rkey ) +{ + return query_mw( h_mw, ph_pd, p_rkey, NULL ); +} + + +ib_api_status_t +query_mw( + IN const ib_mw_handle_t h_mw, + OUT ib_pd_handle_t* const ph_pd, + OUT net32_t* const p_rkey, + IN OUT ci_umv_buf_t* const p_umv_buf ) +{ + ib_pd_handle_t h_ci_pd; + ib_api_status_t status; + + AL_ENTER( AL_DBG_MW ); + + if( AL_OBJ_INVALID_HANDLE( h_mw, AL_OBJ_TYPE_H_MW ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_MW_HANDLE\n") ); + return IB_INVALID_MW_HANDLE; + } + if( !ph_pd || !p_rkey ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + status = verbs_query_mw(h_mw, &h_ci_pd, p_rkey); + + /* Get the PD for AL associated with this memory window. */ + if( status == IB_SUCCESS ) + { + *ph_pd = PARENT_STRUCT( h_mw->obj.p_parent_obj, ib_pd_t, obj ); + CL_ASSERT( (*ph_pd)->h_ci_pd == h_ci_pd ); + } + + AL_EXIT( AL_DBG_MW ); + return status; +} diff --git a/branches/WOF2-3/core/al/al_mw.h b/branches/WOF2-3/core/al/al_mw.h new file mode 100644 index 00000000..cdaa97b0 --- /dev/null +++ b/branches/WOF2-3/core/al/al_mw.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#if !defined(__AL_MW_H__) +#define __AL_MW_H__ + + +#include + +#include "al_ca.h" + + + +typedef struct _ib_mw +{ + al_obj_t obj; + + /* List item used to store MW in PD list for proper destruction order. */ + cl_list_item_t pd_list_item; + ib_mw_handle_t h_ci_mw; /* Actual HW handle. */ + +} ib_mw_t; + + + +ib_api_status_t +create_mw( + IN const ib_pd_handle_t h_pd, + OUT uint32_t* const p_rkey, + OUT ib_mw_handle_t* const ph_mw, + IN OUT ci_umv_buf_t* const p_umv_buf ); + + +ib_api_status_t +query_mw( + IN const ib_mw_handle_t h_mw, + OUT ib_pd_handle_t* const ph_pd, + OUT uint32_t* const p_rkey, + IN OUT ci_umv_buf_t* const p_umv_buf ); + +ib_api_status_t +destroy_mw( + IN const ib_mw_handle_t h_mw ); + +#endif /* __AL_MW_H__ */ diff --git a/branches/WOF2-3/core/al/al_pd.c b/branches/WOF2-3/core/al/al_pd.c new file mode 100644 index 00000000..0d5622a1 --- /dev/null +++ b/branches/WOF2-3/core/al/al_pd.c @@ -0,0 +1,485 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include + +#include "al.h" +#include "al_av.h" +#include "al_ca.h" +#include "al_cq.h" +#include "al_debug.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "al_pd.tmh" +#endif +#include "al_mgr.h" +#include "al_mr.h" +#include "al_mw.h" +#include "al_pd.h" +#include "al_qp.h" +#include "al_srq.h" +#include "al_verbs.h" + +#include "ib_common.h" + + +void +destroying_pd( + IN struct _al_obj *p_obj ); + + +void +cleanup_pd( + IN struct _al_obj *p_obj ); + + +void +free_pd( + IN al_obj_t *p_obj ); + + + +ib_api_status_t +alloc_pd( + IN const ib_ca_handle_t h_ca, + IN const ib_pd_type_t pd_type, + IN const void * const pd_context, + OUT ib_pd_handle_t* const ph_pd, + IN OUT ci_umv_buf_t* const p_umv_buf ) +{ + ib_pd_handle_t h_pd; + ib_api_status_t status; + al_obj_type_t obj_type = AL_OBJ_TYPE_H_PD; + + CL_ASSERT( h_ca ); + + if( !ph_pd ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + /* Allocate a protection domain. */ + h_pd = (ib_pd_handle_t)cl_zalloc( sizeof( ib_pd_t ) ); + if( !h_pd ) + { + return IB_INSUFFICIENT_MEMORY; + } + + if( p_umv_buf ) + obj_type |= AL_OBJ_SUBTYPE_UM_EXPORT; + + /* Construct the PD. */ + construct_al_obj( &h_pd->obj, obj_type ); + cl_qlist_init( &h_pd->mw_list ); + + status = init_al_obj( &h_pd->obj, pd_context, TRUE, + destroying_pd, cleanup_pd, free_pd ); + if( status != IB_SUCCESS ) + { + free_pd( &h_pd->obj ); + return status; + } + + status = attach_al_obj( &h_ca->obj, &h_pd->obj ); + if( status != IB_SUCCESS ) + { + h_pd->obj.pfn_destroy( &h_pd->obj, NULL ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("attach_al_obj returned %s.\n", ib_get_err_str(status)) ); + return status; + } + + h_pd->type = pd_type; + switch( h_pd->type ) + { + case IB_PDT_ALIAS: + status = allocate_pd_alias( h_ca, h_pd ); + break; + + case IB_PDT_NORMAL: + case IB_PDT_SQP: + case IB_PDT_UD: + /* Allocate the protection domain. */ + status = verbs_allocate_pd( h_ca, h_pd, p_umv_buf ); + break; + + default: + status = IB_INVALID_PARAMETER; + } + + if( status != IB_SUCCESS ) + { + h_pd->obj.pfn_destroy( &h_pd->obj, NULL ); + return status; + } + + *ph_pd = h_pd; + + return status; +} + + + +ib_api_status_t +ib_dealloc_pd( + IN const ib_pd_handle_t h_pd, + IN const ib_pfn_destroy_cb_t pfn_destroy_cb OPTIONAL ) +{ + AL_ENTER( AL_DBG_PD ); + + if( AL_OBJ_INVALID_HANDLE( h_pd, AL_OBJ_TYPE_H_PD ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PD_HANDLE\n") ); + return IB_INVALID_PD_HANDLE; + } + + ref_al_obj( &h_pd->obj ); + h_pd->obj.pfn_destroy( &h_pd->obj, pfn_destroy_cb ); + + AL_EXIT( AL_DBG_PD ); + return IB_SUCCESS; +} + + + +/* + * Pre-destroy the protection domain. + */ +void +destroying_pd( + IN al_obj_t *p_obj ) +{ + ib_al_handle_t h_al; + ib_ca_handle_t h_ca; + ib_pd_handle_t h_pd; + ib_mw_handle_t h_mw; + cl_list_item_t *p_list_item; + ib_api_status_t status; + + CL_ASSERT( p_obj ); + h_pd = PARENT_STRUCT( p_obj, ib_pd_t, obj ); + + /* Get the AL instance of this protection domain. */ + p_obj = h_pd->obj.p_parent_obj; + h_ca = PARENT_STRUCT( p_obj, ib_ca_t, obj ); + p_obj = h_ca->obj.p_parent_obj; + h_al = PARENT_STRUCT( p_obj, ib_al_t, obj ); + + /* + * Deallocate all MW's before proceeding with destruction. This ensures + * that all MW's have been destroyed before any MR's are. + */ + p_list_item = cl_qlist_head( &h_pd->mw_list ); + while( p_list_item != cl_qlist_end( &h_pd->mw_list ) ) + { + h_mw = PARENT_STRUCT( p_list_item, ib_mw_t, pd_list_item ); + status = ib_destroy_mw( h_mw ); + CL_ASSERT( status == IB_SUCCESS ); + + CL_ASSERT( p_list_item != cl_qlist_head( &h_pd->mw_list ) ); + p_list_item = cl_qlist_head( &h_pd->mw_list ); + } +} + + + +void +cleanup_pd( + IN struct _al_obj *p_obj ) +{ + ib_pd_handle_t h_pd; + ib_api_status_t status; + + CL_ASSERT( p_obj ); + h_pd = PARENT_STRUCT( p_obj, ib_pd_t, obj ); + + /* Release the HW resources. */ + if( verbs_check_pd(h_pd)) + { + if( h_pd->type != IB_PDT_ALIAS ) + { + /* Deallocate the CI PD. */ + status = verbs_deallocate_pd(h_pd); + CL_ASSERT( status == IB_SUCCESS ); + } + else + { + deallocate_pd_alias( h_pd ); + } + } +} + + + +/* + * Release all resources associated with the protection domain. + */ +void +free_pd( + IN al_obj_t *p_obj ) +{ + ib_pd_handle_t h_pd; + + CL_ASSERT( p_obj ); + h_pd = PARENT_STRUCT( p_obj, ib_pd_t, obj ); + + destroy_al_obj( p_obj ); + cl_free( h_pd ); +} + +ib_api_status_t +ib_create_srq( + IN const ib_pd_handle_t h_pd, + IN const ib_srq_attr_t* const p_srq_attr, + IN const void* const srq_context, + IN const ib_pfn_event_cb_t pfn_srq_event_cb OPTIONAL, + OUT ib_srq_handle_t* const ph_srq ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_SRQ ); + + if( AL_OBJ_INVALID_HANDLE( h_pd, AL_OBJ_TYPE_H_PD ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PD_HANDLE\n") ); + return IB_INVALID_PD_HANDLE; + } + + if( !p_srq_attr || !ph_srq) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + if( !p_srq_attr->max_wr) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_MAX_WRS\n") ); + return IB_INVALID_MAX_WRS; + } + + if (h_pd->obj.p_ci_ca && h_pd->obj.p_ci_ca->p_pnp_attr) + { + if (p_srq_attr->max_wr > h_pd->obj.p_ci_ca->p_pnp_attr->max_srq_wrs) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_MAX_WRS\n") ); + return IB_INVALID_MAX_WRS; + } + if (p_srq_attr->max_sge > h_pd->obj.p_ci_ca->p_pnp_attr->max_srq_sges) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_MAX_SGE\n") ); + return IB_INVALID_MAX_SGE; + } + } + + status = create_srq( + h_pd, p_srq_attr, srq_context, pfn_srq_event_cb, ph_srq, NULL ); + + /* Release the reference taken in init_al_obj (init_base_srq). */ + if( status == IB_SUCCESS ) + deref_al_obj( &(*ph_srq)->obj ); + + AL_EXIT( AL_DBG_SRQ ); + return status; +} + + +ib_api_status_t +ib_create_qp( + IN const ib_pd_handle_t h_pd, + IN const ib_qp_create_t* const p_qp_create, + IN const void* const qp_context, + IN const ib_pfn_event_cb_t pfn_qp_event_cb OPTIONAL, + OUT ib_qp_handle_t* const ph_qp ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_QP ); + + if( AL_OBJ_INVALID_HANDLE( h_pd, AL_OBJ_TYPE_H_PD ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PD_HANDLE\n") ); + return IB_INVALID_PD_HANDLE; + } + if( !p_qp_create || !ph_qp ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + if (h_pd->obj.p_ci_ca && h_pd->obj.p_ci_ca->p_pnp_attr) + { + if ((p_qp_create->rq_depth > h_pd->obj.p_ci_ca->p_pnp_attr->max_wrs) || + (p_qp_create->sq_depth > h_pd->obj.p_ci_ca->p_pnp_attr->max_wrs)) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_MAX_WRS\n") ); + return IB_INVALID_MAX_WRS; + } + if ((p_qp_create->rq_sge > h_pd->obj.p_ci_ca->p_pnp_attr->max_sges) || + (p_qp_create->sq_sge > h_pd->obj.p_ci_ca->p_pnp_attr->max_sges)) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_MAX_SGE\n") ); + return IB_INVALID_MAX_SGE; + } + } + status = create_qp( + h_pd, p_qp_create, qp_context, pfn_qp_event_cb, ph_qp, NULL ); + + /* Release the reference taken in init_al_obj (init_base_qp). */ + if( status == IB_SUCCESS ) + deref_al_obj( &(*ph_qp)->obj ); + + AL_EXIT( AL_DBG_QP ); + return status; +} + + + +ib_api_status_t +ib_get_spl_qp( + IN const ib_pd_handle_t h_pd, + IN const ib_net64_t port_guid, + IN const ib_qp_create_t* const p_qp_create, + IN const void* const qp_context, + IN const ib_pfn_event_cb_t pfn_qp_event_cb OPTIONAL, + OUT ib_pool_key_t* const p_pool_key OPTIONAL, + OUT ib_qp_handle_t* const ph_qp ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_QP ); + + if( AL_OBJ_INVALID_HANDLE( h_pd, AL_OBJ_TYPE_H_PD ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PD_HANDLE\n") ); + return IB_INVALID_PD_HANDLE; + } + + status = get_spl_qp( h_pd, port_guid, p_qp_create, qp_context, + pfn_qp_event_cb, p_pool_key, ph_qp, NULL ); + + /* Release the reference taken in init_al_obj. */ + if( status == IB_SUCCESS ) + deref_al_obj( &(*ph_qp)->obj ); + + AL_EXIT( AL_DBG_QP ); + return status; +} + + + +ib_api_status_t +ib_create_av( + IN const ib_pd_handle_t h_pd, + IN const ib_av_attr_t* const p_av_attr, + OUT ib_av_handle_t* const ph_av ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_AV ); + + if( AL_OBJ_INVALID_HANDLE( h_pd, AL_OBJ_TYPE_H_PD ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PD_HANDLE\n") ); + return IB_INVALID_PD_HANDLE; + } + + status = create_av( h_pd, p_av_attr, ph_av, NULL ); + + /* Release the reference taken in alloc_av. */ + if( status == IB_SUCCESS ) + deref_al_obj( &(*ph_av)->obj ); + + AL_EXIT( AL_DBG_AV ); + return status; +} + + + +ib_api_status_t +ib_create_mw( + IN const ib_pd_handle_t h_pd, + OUT net32_t* const p_rkey, + OUT ib_mw_handle_t* const ph_mw ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_MW ); + + if( AL_OBJ_INVALID_HANDLE( h_pd, AL_OBJ_TYPE_H_PD ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PD_HANDLE\n") ); + return IB_INVALID_PD_HANDLE; + } + + status = create_mw( h_pd, p_rkey, ph_mw, NULL ); + + if( status == IB_SUCCESS ) + deref_al_obj( &(*ph_mw)->obj ); + + AL_EXIT( AL_DBG_MW ); + return status; +} + + + +void +pd_insert_mw( + IN const ib_mw_handle_t h_mw ) +{ + ib_pd_handle_t h_pd; + + CL_ASSERT( h_mw ); + h_pd = PARENT_STRUCT( h_mw->obj.p_parent_obj, ib_pd_t, obj ); + + cl_spinlock_acquire( &h_pd->obj.lock ); + cl_qlist_insert_tail( &h_pd->mw_list, &h_mw->pd_list_item ); + cl_spinlock_release( &h_pd->obj.lock ); +} + + + +void +pd_remove_mw( + IN const ib_mw_handle_t h_mw ) +{ + ib_pd_handle_t h_pd; + + CL_ASSERT( h_mw ); + h_pd = PARENT_STRUCT( h_mw->obj.p_parent_obj, ib_pd_t, obj ); + + cl_spinlock_acquire( &h_pd->obj.lock ); + cl_qlist_remove_item( &h_pd->mw_list, &h_mw->pd_list_item ); + cl_spinlock_release( &h_pd->obj.lock ); +} diff --git a/branches/WOF2-3/core/al/al_pd.h b/branches/WOF2-3/core/al/al_pd.h new file mode 100644 index 00000000..4d55867b --- /dev/null +++ b/branches/WOF2-3/core/al/al_pd.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#if !defined(__AL_PD_H__) +#define __AL_PD_H__ + +#include +#include +#include + +#include "al_common.h" + + + +typedef struct _ib_pd +{ + al_obj_t obj; + + /* + * MW list used to order destruction between MW's and MR's. MR and MW + * can be created in any order, so we can't rely on their order in the + * al_obj list for proper destruction. + */ + cl_qlist_t mw_list; + + ib_pd_type_t type; + ib_pd_handle_t h_ci_pd; /* Actual CI PD handle. */ + +} ib_pd_t; + + + +ib_api_status_t +alloc_pd( + IN const ib_ca_handle_t h_ca, + IN const ib_pd_type_t pd_type, + IN const void * const pd_context, + OUT ib_pd_handle_t* const ph_pd, + IN OUT ci_umv_buf_t* const p_umv_buf ); + + +void +pd_insert_mw( + IN const ib_mw_handle_t h_mw ); + +void +pd_remove_mw( + IN const ib_mw_handle_t h_mw ); + + +#endif /* __AL_PD_H__ */ diff --git a/branches/WOF2-3/core/al/al_pnp.h b/branches/WOF2-3/core/al/al_pnp.h new file mode 100644 index 00000000..fdd6c85e --- /dev/null +++ b/branches/WOF2-3/core/al/al_pnp.h @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#if !defined(__AL_PNP_H__) +#define __AL_PNP_H__ + + +#include "al_common.h" +#include "al_ca.h" +#include +#include +#include + + +extern char* ib_pnp_event_str[]; + + +typedef struct _al_pnp +{ + al_obj_t obj; + + cl_async_proc_item_t async_item; +#if defined( CL_KERNEL ) + KEVENT *p_sync_event; + cl_list_item_t list_item; + cl_async_proc_item_t dereg_item; + ib_pnp_class_t pnp_class; + cl_fmap_t context_map; + IRP *p_rearm_irp; + IRP *p_dereg_irp; +#else /* defined( CL_KERNEL ) */ + ual_rearm_pnp_ioctl_out_t rearm; + OVERLAPPED ov; + OVERLAPPED destroy_ov; +#endif /* defined( CL_KERNEL ) */ + ib_pfn_pnp_cb_t pfn_pnp_cb; + +} al_pnp_t; +/* +* FIELDS +* obj +* AL object, used to manage relationships and destruction +* synchronization. +* +* list_item +* Used to store the registration in the proper list for the class. +* +* async_item +* Asynchronous processing item used to handle registration and events. +* +* dereg_item +* Asynchronous processing item used to handle deregistration. This item +* is separate from the registration item to allow a user to immediately +* call ib_dereg_pnp after ib_reg_pnp. +* +* pnp_class +* Class of PnP events for this registration. +* +* pfn_pnp_cb +* Client's PnP notification callback. +* +* context_map +* map of client contexts. +*********/ + + +/* + * Context information stored in a registration structure. + */ +typedef struct _al_pnp_context +{ + /* List item must be first. */ + cl_fmap_item_t map_item; + ib_net64_t guid; + ib_net64_t ca_guid; + const void *context; + +} al_pnp_context_t; + +/****f* Access Layer/create_pnp +* DESCRIPTION +* Initialized the plug and play manager. +* +* SYNOPSIS +*/ +ib_api_status_t +create_pnp( + IN al_obj_t* const p_parent_obj ); +/******/ + + +#ifdef CL_KERNEL + +/****f* Access Layer/al_pnp_ca_event +* NAME +* pnp_ca_event +* +* DESCRIPTION +* Reports a CA event to the plug and play manager. +* +* SYNOPSIS +*/ +ib_api_status_t +pnp_ca_event( + IN al_ci_ca_t* const p_ci_ca, + IN const ib_pnp_event_t event ); +/* +* PARAMETERS +* p_ci_ca +* Pointer to the al_ci_ca_t structure for the ca for which the event +* is being reported. +* +* event +* One of IB_PNP_CA_ADD, IB_PNP_CA_REMOVE to indicate the type of CA +* event being reported. +*****/ + + +/****f* Access Layer/pnp_ca_change +* NAME +* pnp_ca_change +* +* DESCRIPTION +* Called by user mode AL to report a CA attribute change. +* +* SYNOPSIS +*/ +ib_api_status_t +pnp_ca_change( + IN al_ci_ca_t* const p_ci_ca, + IN const ib_ca_attr_t* p_ca_attr ); +/* +* PARAMETERS +* p_ci_ca +* Pointer to the al_ci_ca_t structure for the ca for which the change +* is being reported. +* +* p_ca_attr +* Pointer to the updated CA attributes. +*****/ + + +/****f* Access Layer/pnp_check_events +* NAME +* pnp_poll +* +* DESCRIPTION +* Check for PnP new events and report changes to registered clients. +* +* SYNOPSIS +*/ +void +pnp_poll( + void ); +/******/ + + +/****f* Access Layer/pnp_create_context +* NAME +* pnp_create_context +* +* DESCRIPTION +* Creates a context structure for a reported PnP event. +* +* SYNOPSIS +*/ +al_pnp_context_t* +pnp_create_context( + IN al_pnp_t* const p_reg, + IN const void* const p_key ); +/******/ + +al_pnp_context_t* +pnp_get_context( + IN const al_pnp_t* const p_reg, + IN const void* const p_key ); + +void +pnp_reg_complete( + IN al_pnp_t* const p_reg ); + +ib_api_status_t +al_reg_pnp( + IN const ib_al_handle_t h_al, + IN const ib_pnp_req_t* const p_pnp_req, + IN KEVENT *p_sync_event, + OUT ib_pnp_handle_t* const ph_pnp ); + +void +pnp_force_event( + IN struct _al_ci_ca * p_ci_ca, + IN ib_pnp_event_t pnp_event, + IN uint8_t port_num); + + +#endif /* CL_KERNEL */ + +static inline ib_pnp_class_t +pnp_get_class( + IN const ib_pnp_class_t pnp_class ) +{ + return pnp_class & IB_PNP_CLASS_MASK; +} + +static inline ib_pnp_class_t +pnp_get_flag( + IN const ib_pnp_class_t pnp_class ) +{ + return pnp_class & IB_PNP_FLAG_MASK; +} + +#endif /* __AL_PNP_H__ */ diff --git a/branches/WOF2-3/core/al/al_proxy_ioctl.h b/branches/WOF2-3/core/al/al_proxy_ioctl.h new file mode 100644 index 00000000..07b27b47 --- /dev/null +++ b/branches/WOF2-3/core/al/al_proxy_ioctl.h @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#if !defined(__AL_PROXY_IOCTL_H__) +#define __AL_PROXY_IOCTL_H__ + + + +/* + * IOCTL structures for passing the callback contexts to user mode. + */ + +typedef enum _cm_cb_rec_type +{ + CM_REQ_REC, + CM_REP_REC, + CM_RTU_REC, + CM_REJ_REC, + CM_MRA_REC, + CM_LAP_REC, + CM_APR_REC, + CM_DREQ_REC, + CM_DREP_REC + +} cm_cb_rec_type; + + + +typedef enum _misc_cb_rec_type +{ + CA_ERROR_REC, + QP_ERROR_REC, + SRQ_ERROR_REC, + CQ_ERROR_REC, + MCAST_REC, + MAD_SEND_REC, + MAD_RECV_REC, + SVC_REG_REC, + QUERY_REC, + PNP_REC + +} misc_cb_rec_type; + + + +/* + * Information for most callbacks. This does not include callbacks for + * the CM or completions. + */ +typedef union _misc_cb_ioctl_rec +{ + uint64_t context; + + /* Asynchronous event records */ + ib_async_event_rec_t event_rec; + + /* Multicast record */ + struct _mcast_cb_ioctl_rec + { + uint64_t mcast_context; + ib_api_status_t status; + ib_net16_t error_status; + uint64_t h_mcast; + ib_member_rec_t member_rec; + + } mcast_cb_ioctl_rec; + + + /* Mad send */ + struct _mad_send_cb_ioctl_rec + { + uint64_t p_um_mad; + ib_wc_status_t wc_status; + uint64_t mad_svc_context; + + } mad_send_cb_ioctl_rec; + + + /* Mad receive */ + struct _mad_recv_cb_ioctl_rec + { + uint64_t h_mad; + uint32_t elem_size; + uint64_t mad_svc_context; + uint64_t p_send_mad; + + } mad_recv_cb_ioctl_rec; + + + /* PNP Record as defined here is for UAL's consumption alone */ + struct _pnp_cb_ioctl_rec + { + ib_pnp_event_t pnp_event; + + union _pnp_info + { + /* pnp_ca is valid only for CA events + * UAL can query based on the ca_guid for more info + */ + struct _pnp_ca + { + ib_net64_t ca_guid; + + } ca; + + } pnp_info; + + } pnp_cb_ioctl_rec; + +} misc_cb_ioctl_rec_t; + + + +typedef struct _comp_cb_ioctl_info +{ + uint64_t cq_context; + +} comp_cb_ioctl_info_t; + + + +typedef struct _misc_cb_ioctl_info +{ + misc_cb_rec_type rec_type; + misc_cb_ioctl_rec_t ioctl_rec; + +} misc_cb_ioctl_info_t; + + +#endif /* __AL_PROXY_IOCTL_H__ */ diff --git a/branches/WOF2-3/core/al/al_proxy_ndi.h b/branches/WOF2-3/core/al/al_proxy_ndi.h new file mode 100644 index 00000000..ff589629 --- /dev/null +++ b/branches/WOF2-3/core/al/al_proxy_ndi.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: al_proxy.h 33 2005-07-11 19:51:17Z ftillier $ + */ + +/* + * Abstract: + * This header file defines data structures for the kernel-mode NDI support + * + * Environment: + * Kernel . + */ + + +#ifndef _ALPROXY_NDI_H_ +#define _ALPROXY_NDI_H_ + +#include "complib/cl_ioctl_osd.h" +#include "al_cq.h" +#include "al_ndi_cq.h" +#include "al_qp.h" +#include "al_ndi_cm.h" + +/* functions from al_proxy_verbs.c */ +ib_api_status_t +cpyin_umvbuf( + IN ci_umv_buf_t *p_src, + OUT ci_umv_buf_t **pp_dst ); + +ib_api_status_t +cpyout_umvbuf( + IN ci_umv_buf_t *p_dest, + IN ci_umv_buf_t *p_src); + +void +free_umvbuf( + IN ci_umv_buf_t *p_umv_buf ); + + +#endif + + + diff --git a/branches/WOF2-3/core/al/al_qp.c b/branches/WOF2-3/core/al/al_qp.c new file mode 100644 index 00000000..e785a6fa --- /dev/null +++ b/branches/WOF2-3/core/al/al_qp.c @@ -0,0 +1,2128 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include +#include +#include + +#include "al.h" +#include "al_av.h" +#include "al_ca.h" +#include "al_cm_cep.h" +#include "al_cq.h" +#include "al_debug.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "al_qp.tmh" +#endif +#include "al_mad.h" +#include "al_mad_pool.h" +#include "al_mcast.h" +#include "al_mgr.h" +#include "al_mr.h" +#include "al_mw.h" +#include "al_pd.h" +#include "al_qp.h" +#include "al_query.h" +#ifdef CL_KERNEL +#include "al_smi.h" +#include "al_proxy_ndi.h" +#endif /* CL_KERNEL */ +#include "al_verbs.h" + +#include "ib_common.h" + + +#define UNBOUND_PORT_GUID 0 + + +extern ib_pool_handle_t gh_mad_pool; + + +/* + * Function prototypes. + */ +void +destroying_qp( + IN al_obj_t *p_obj ); + +void +cleanup_qp( + IN al_obj_t *p_obj ); + +void +free_qp( + IN al_obj_t *p_obj ); + + + +ib_api_status_t +init_base_qp( + IN ib_qp_t* const p_qp, + IN const void* const qp_context, + IN const ib_pfn_event_cb_t pfn_qp_event_cb, + IN OUT ci_umv_buf_t* const p_umv_buf ); + +ib_api_status_t +init_raw_qp( + IN const ib_qp_handle_t h_qp, + IN const ib_pd_handle_t h_pd, + IN const ib_net64_t port_guid OPTIONAL, + IN const ib_qp_create_t* const p_qp_create, + IN OUT ci_umv_buf_t* const p_umv_buf ); + +ib_api_status_t +init_conn_qp( + IN al_conn_qp_t* const p_conn_qp, + IN const ib_pd_handle_t h_pd, + IN const ib_qp_create_t* const p_qp_create, + IN OUT ci_umv_buf_t* const p_umv_buf ); + +ib_api_status_t +init_dgrm_qp( + IN al_dgrm_qp_t* const p_dgrm_qp, + IN const ib_pd_handle_t h_pd, + IN const ib_qp_create_t* const p_qp_create, + IN OUT ci_umv_buf_t* const p_umv_buf ); + +ib_api_status_t +init_special_qp( + IN al_special_qp_t* const p_special_qp, + IN const ib_pd_handle_t h_pd, + IN const ib_net64_t port_guid, + IN const ib_qp_create_t* const p_qp_create ); + +ib_api_status_t +init_qp_alias( + IN al_qp_alias_t* const p_qp_alias, + IN const ib_pd_handle_t h_pd, + IN const ib_net64_t port_guid, + IN const ib_qp_create_t* const p_qp_create ); + +ib_api_status_t +init_mad_qp( + IN al_mad_qp_t* const p_mad_qp, + IN const ib_pd_handle_t h_pd, + IN const ib_qp_create_t* const p_qp_create, + IN const ib_pfn_event_cb_t pfn_qp_event_cb ); + +ib_api_status_t +init_mad_dgrm_svc( + IN const ib_qp_handle_t h_qp, + IN const ib_dgrm_info_t* const p_dgrm_info ); + + +ib_api_status_t +al_modify_qp( + IN const ib_qp_handle_t h_qp, + IN const ib_qp_mod_t* const p_qp_mod, + IN OUT ci_umv_buf_t* const p_umv_buf ); + + +ib_api_status_t +init_dgrm_svc( + IN const ib_qp_handle_t h_qp, + IN const ib_dgrm_info_t* const p_dgrm_info ); + +ib_api_status_t +mad_qp_post_recvs( + IN al_mad_qp_t* const p_mad_qp ); + +ib_api_status_t +ud_post_send( + IN const ib_qp_handle_t h_qp, + IN ib_send_wr_t* const p_send_wr, + OUT ib_send_wr_t **pp_send_failure ); + +ib_api_status_t +special_qp_post_send( + IN const ib_qp_handle_t h_qp, + IN ib_send_wr_t* const p_send_wr, + OUT ib_send_wr_t **pp_send_failure ); + +void +mad_qp_queue_mad( + IN const ib_qp_handle_t h_qp, + IN al_mad_wr_t* const p_mad_wr ); + +void +mad_qp_resume_sends( + IN ib_qp_handle_t h_qp ); + +void +mad_qp_flush_send( + IN al_mad_qp_t* p_mad_qp, + IN al_mad_wr_t* const p_mad_wr ); + +void +mad_recv_comp_cb( + IN const ib_cq_handle_t h_cq, + IN void *cq_context ); + +void +mad_send_comp_cb( + IN const ib_cq_handle_t h_cq, + IN void *cq_context ); + +void +mad_qp_comp( + IN al_mad_qp_t* p_mad_qp, + IN const ib_cq_handle_t h_cq, + IN ib_wc_type_t wc_type ); + +void +mad_qp_cq_event_cb( + IN ib_async_event_rec_t *p_event_rec ); + + + +/* + * Allocates a structure to store QP information. + */ +ib_api_status_t +alloc_qp( + IN const ib_qp_type_t qp_type, + OUT ib_qp_handle_t* const ph_qp ) +{ + ib_qp_handle_t h_qp; + + switch( qp_type ) + { + case IB_QPT_RELIABLE_CONN: + case IB_QPT_UNRELIABLE_CONN: + h_qp = (ib_qp_handle_t)cl_zalloc( sizeof( al_conn_qp_t ) ); + break; + + case IB_QPT_UNRELIABLE_DGRM: + h_qp = (ib_qp_handle_t)cl_zalloc( sizeof( al_dgrm_qp_t ) ); + break; + + case IB_QPT_QP0: + case IB_QPT_QP1: + h_qp = (ib_qp_handle_t)cl_zalloc( sizeof( al_special_qp_t ) ); + break; + + case IB_QPT_RAW_IPV6: + case IB_QPT_RAW_ETHER: + h_qp = (ib_qp_handle_t)cl_zalloc( sizeof( ib_qp_t ) ); + break; + + case IB_QPT_MAD: + h_qp = (ib_qp_handle_t)cl_zalloc( sizeof( al_mad_qp_t ) ); + break; + + case IB_QPT_QP0_ALIAS: + case IB_QPT_QP1_ALIAS: + h_qp = (ib_qp_handle_t)cl_zalloc( sizeof( al_qp_alias_t ) ); + break; + + default: + CL_ASSERT( qp_type == IB_QPT_RELIABLE_CONN || + qp_type == IB_QPT_UNRELIABLE_CONN || + qp_type == IB_QPT_UNRELIABLE_DGRM || + qp_type == IB_QPT_QP0 || + qp_type == IB_QPT_QP1 || + qp_type == IB_QPT_RAW_IPV6 || + qp_type == IB_QPT_RAW_ETHER || + qp_type == IB_QPT_MAD || + qp_type == IB_QPT_QP0_ALIAS || + qp_type == IB_QPT_QP1_ALIAS ); + return IB_INVALID_SETTING; + } + + if( !h_qp ) + { + return IB_INSUFFICIENT_MEMORY; + } + + h_qp->type = qp_type; + + *ph_qp = h_qp; + return IB_SUCCESS; +} + + + +/* + * Initializes the QP information structure. + */ +ib_api_status_t +create_qp( + IN const ib_pd_handle_t h_pd, + IN const ib_qp_create_t* const p_qp_create, + IN const void* const qp_context, + IN const ib_pfn_event_cb_t pfn_qp_event_cb, + OUT ib_qp_handle_t* const ph_qp, + IN OUT ci_umv_buf_t* const p_umv_buf ) +{ + ib_api_status_t status; + ib_qp_handle_t h_qp; + + if( !p_qp_create || !ph_qp ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + if (p_qp_create->h_srq && + AL_OBJ_INVALID_HANDLE( p_qp_create->h_srq, AL_OBJ_TYPE_H_SRQ ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_SRQ_HANDLE\n") ); + return IB_INVALID_SRQ_HANDLE; + } + + /* Allocate a QP. */ + status = alloc_qp( p_qp_create->qp_type, &h_qp ); + if( status != IB_SUCCESS ) + { + return status; + } + + /* Init the base QP first. */ + status = init_base_qp( h_qp, qp_context, pfn_qp_event_cb, p_umv_buf ); + if( status != IB_SUCCESS ) + return status; + + /* Initialize the QP based on its type. */ + switch( h_qp->type ) + { + case IB_QPT_RELIABLE_CONN: + case IB_QPT_UNRELIABLE_CONN: + if( AL_OBJ_INVALID_HANDLE( p_qp_create->h_sq_cq, AL_OBJ_TYPE_H_CQ ) || + AL_OBJ_INVALID_HANDLE( p_qp_create->h_rq_cq, AL_OBJ_TYPE_H_CQ ) ) + { + status = IB_INVALID_CQ_HANDLE; + break; + } + status = init_conn_qp( (al_conn_qp_t*)h_qp, h_pd, p_qp_create, p_umv_buf ); + break; + + case IB_QPT_UNRELIABLE_DGRM: + if( AL_OBJ_INVALID_HANDLE( p_qp_create->h_sq_cq, AL_OBJ_TYPE_H_CQ ) || + AL_OBJ_INVALID_HANDLE( p_qp_create->h_rq_cq, AL_OBJ_TYPE_H_CQ ) ) + { + status = IB_INVALID_CQ_HANDLE; + break; + } + status = init_dgrm_qp( (al_dgrm_qp_t*)h_qp, h_pd, p_qp_create, p_umv_buf ); + break; + + case IB_QPT_MAD: + if( p_qp_create->h_sq_cq || p_qp_create->h_rq_cq ) + { + status = IB_INVALID_CQ_HANDLE; + break; + } + status = init_mad_qp( (al_mad_qp_t*)h_qp, h_pd, p_qp_create, + pfn_qp_event_cb ); + break; + + default: + CL_ASSERT( h_qp->type == IB_QPT_RELIABLE_CONN || + h_qp->type == IB_QPT_UNRELIABLE_CONN || + h_qp->type == IB_QPT_UNRELIABLE_DGRM || + h_qp->type == IB_QPT_MAD ); + status = IB_INVALID_SETTING; + break; + } + + if( status != IB_SUCCESS ) + { + h_qp->obj.pfn_destroy( &h_qp->obj, NULL ); + return status; + } + + *ph_qp = h_qp; + + /* + * Note that we don't release the reference taken in init_al_obj here. + * For kernel clients, it is release in ib_create_qp. For user-mode + * clients is is released by the proxy after the handle is extracted. + */ + return IB_SUCCESS; +} + + + +ib_api_status_t +get_spl_qp( + IN const ib_pd_handle_t h_pd, + IN const ib_net64_t port_guid, + IN const ib_qp_create_t* const p_qp_create, + IN const void* const qp_context, + IN const ib_pfn_event_cb_t pfn_qp_event_cb, + OUT ib_pool_key_t* const p_pool_key OPTIONAL, + OUT ib_qp_handle_t* const ph_qp, + IN OUT ci_umv_buf_t* const p_umv_buf ) +{ + ib_api_status_t status; + ib_qp_handle_t h_qp; + + if( !p_qp_create || !ph_qp ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + /* Only allow creation of the special QP types. */ + switch( p_qp_create->qp_type ) + { +#ifdef CL_KERNEL + case IB_QPT_QP0: + case IB_QPT_QP1: +#endif + case IB_QPT_QP0_ALIAS: + case IB_QPT_QP1_ALIAS: + case IB_QPT_RAW_IPV6: + case IB_QPT_RAW_ETHER: + break; /* The QP type is valid. */ + + default: + return IB_INVALID_SETTING; + } + + /* Allocate a QP. */ + status = alloc_qp( p_qp_create->qp_type, &h_qp ); + if( status != IB_SUCCESS ) + { + return status; + } + + /* Init the base QP first. */ + status = init_base_qp( h_qp, qp_context, pfn_qp_event_cb, p_umv_buf ); + if( status != IB_SUCCESS ) + return status; + + /* Initialize the QP based on its type. */ + switch( h_qp->type ) + { +#ifdef CL_KERNEL + case IB_QPT_QP0: + case IB_QPT_QP1: + if( AL_OBJ_INVALID_HANDLE( p_qp_create->h_sq_cq, AL_OBJ_TYPE_H_CQ ) || + AL_OBJ_INVALID_HANDLE( p_qp_create->h_rq_cq, AL_OBJ_TYPE_H_CQ ) ) + { + status = IB_INVALID_CQ_HANDLE; + break; + } + status = init_special_qp( (al_special_qp_t*)h_qp, h_pd, port_guid, + p_qp_create ); + break; +#endif /* CL_KERNEL */ + + case IB_QPT_QP0_ALIAS: + case IB_QPT_QP1_ALIAS: + if( p_qp_create->h_sq_cq || p_qp_create->h_rq_cq ) + { + status = IB_INVALID_CQ_HANDLE; + break; + } + status = init_alias_qp( (al_qp_alias_t*)h_qp, h_pd, port_guid, + p_qp_create ); + if( status == IB_SUCCESS && p_pool_key ) + { + /* Create a pool_key to access to the global MAD pool. */ + status = ib_reg_mad_pool( gh_mad_pool, h_pd, + &((al_qp_alias_t*)h_qp)->pool_key ); + if( status == IB_SUCCESS ) + { + /* + * Take a reference on the pool key since we don't have a + * mechanism for the pool key to clear the QP's pointer to it. + */ + ref_al_obj( &((al_qp_alias_t*)h_qp)->pool_key->obj ); + *p_pool_key = ((al_qp_alias_t*)h_qp)->pool_key; + } + } + break; + + case IB_QPT_RAW_IPV6: + case IB_QPT_RAW_ETHER: + if( AL_OBJ_INVALID_HANDLE( p_qp_create->h_sq_cq, AL_OBJ_TYPE_H_CQ ) || + AL_OBJ_INVALID_HANDLE( p_qp_create->h_rq_cq, AL_OBJ_TYPE_H_CQ ) ) + { + status = IB_INVALID_CQ_HANDLE; + break; + } + status = init_raw_qp( h_qp, h_pd, port_guid, p_qp_create, p_umv_buf ); + break; + + default: + CL_ASSERT( h_qp->type == IB_QPT_QP0 || + h_qp->type == IB_QPT_QP1 || + h_qp->type == IB_QPT_QP0_ALIAS || + h_qp->type == IB_QPT_QP1_ALIAS || + h_qp->type == IB_QPT_RAW_IPV6 || + h_qp->type == IB_QPT_RAW_ETHER ); + + status = IB_INVALID_SETTING; + break; + } + + if( status != IB_SUCCESS ) + { + h_qp->obj.pfn_destroy( &h_qp->obj, NULL ); + return status; + } + + *ph_qp = h_qp; + + return IB_SUCCESS; +} + + +static ib_api_status_t +al_bad_modify_qp( + IN const ib_qp_handle_t h_qp, + IN const ib_qp_mod_t* const p_qp_mod, + IN OUT ci_umv_buf_t* const p_umv_buf ) +{ + UNUSED_PARAM( h_qp ); + UNUSED_PARAM( p_qp_mod ); + UNUSED_PARAM( p_umv_buf ); + return IB_INVALID_PARAMETER; +} + + +static ib_api_status_t +al_bad_post_send( + IN const ib_qp_handle_t h_qp, + IN ib_send_wr_t* const p_send_wr, + IN ib_send_wr_t **pp_send_failure OPTIONAL ) +{ + UNUSED_PARAM( h_qp ); + UNUSED_PARAM( p_send_wr ); + UNUSED_PARAM( pp_send_failure ); + return IB_INVALID_PARAMETER; +} + + +static ib_api_status_t +al_bad_post_recv( + IN const ib_qp_handle_t h_qp, + IN ib_recv_wr_t* const p_recv_wr, + IN ib_recv_wr_t **p_recv_failure OPTIONAL ) +{ + UNUSED_PARAM( h_qp ); + UNUSED_PARAM( p_recv_wr ); + UNUSED_PARAM( p_recv_failure ); + return IB_INVALID_PARAMETER; +} + + +static ib_api_status_t +al_bad_init_dgrm_svc( + IN const ib_qp_handle_t h_qp, + IN const ib_dgrm_info_t* const p_dgrm_info ) +{ + UNUSED_PARAM( h_qp ); + UNUSED_PARAM( p_dgrm_info ); + return IB_INVALID_PARAMETER; +} + + +static ib_api_status_t +al_bad_reg_mad_svc( + IN const ib_qp_handle_t h_qp, + IN const ib_mad_svc_t* const p_mad_svc, + OUT ib_mad_svc_handle_t* const ph_mad_svc ) +{ + UNUSED_PARAM( h_qp ); + UNUSED_PARAM( p_mad_svc ); + UNUSED_PARAM( ph_mad_svc ); + return IB_INVALID_PARAMETER; +} + + +static ib_api_status_t +al_bad_dereg_mad_svc( + IN const ib_mad_svc_handle_t h_mad_svc ) +{ + UNUSED_PARAM( h_mad_svc ); + return IB_INVALID_PARAMETER; +} + + +static void +al_bad_queue_mad( + IN const ib_qp_handle_t h_qp, + IN al_mad_wr_t* const p_mad_wr ) +{ + UNUSED_PARAM( h_qp ); + UNUSED_PARAM( p_mad_wr ); +} + + +static void +al_bad_resume_mad( + IN const ib_qp_handle_t h_qp ) +{ + UNUSED_PARAM( h_qp ); + return; +} + + +static ib_api_status_t +al_bad_join_mcast( + IN const ib_qp_handle_t h_qp, + IN const ib_mcast_req_t* const p_mcast_req ) +{ + UNUSED_PARAM( h_qp ); + UNUSED_PARAM( p_mcast_req ); + return IB_INVALID_PARAMETER; +} + + +ib_api_status_t +init_base_qp( + IN ib_qp_t* const p_qp, + IN const void* const qp_context, + IN const ib_pfn_event_cb_t pfn_qp_event_cb, + IN OUT ci_umv_buf_t* const p_umv_buf ) +{ + ib_api_status_t status; + al_obj_type_t obj_type = AL_OBJ_TYPE_H_QP; + + CL_ASSERT( p_qp ); + + if( p_umv_buf ) + obj_type |= AL_OBJ_SUBTYPE_UM_EXPORT; + + construct_al_obj( &p_qp->obj, obj_type ); + status = init_al_obj( &p_qp->obj, qp_context, TRUE, + destroying_qp, cleanup_qp, free_qp ); + if( status != IB_SUCCESS ) + { + free_qp( &p_qp->obj ); + return status; + } + + p_qp->pfn_event_cb = pfn_qp_event_cb; + + /* + * All function pointers should be invalid. They will be set by + * derived QP types where appropriate. + */ + p_qp->pfn_modify_qp = al_bad_modify_qp; + p_qp->pfn_post_recv = al_bad_post_recv; + p_qp->pfn_post_send = al_bad_post_send; + p_qp->pfn_reg_mad_svc = al_bad_reg_mad_svc; + p_qp->pfn_dereg_mad_svc = al_bad_dereg_mad_svc; + p_qp->pfn_queue_mad = al_bad_queue_mad; + p_qp->pfn_resume_mad = al_bad_resume_mad; + p_qp->pfn_init_dgrm_svc = al_bad_init_dgrm_svc; + p_qp->pfn_join_mcast = al_bad_join_mcast; + + if( p_qp->type == IB_QPT_RELIABLE_CONN || + p_qp->type == IB_QPT_UNRELIABLE_CONN ) + { + ((al_conn_qp_t*)p_qp)->cid = AL_INVALID_CID; + } + + return status; +} + + + +ib_api_status_t +init_raw_qp( + IN const ib_qp_handle_t h_qp, + IN const ib_pd_handle_t h_pd, + IN const ib_net64_t port_guid OPTIONAL, + IN const ib_qp_create_t* const p_qp_create, + IN OUT ci_umv_buf_t* const p_umv_buf ) +{ + ib_api_status_t status; + ib_qp_create_t qp_create; + ib_qp_attr_t qp_attr; + uint8_t port_num; + + status = attach_al_obj( &h_pd->obj, &h_qp->obj ); + if( status != IB_SUCCESS ) + return status; + + /* Convert AL handles to CI handles. */ + qp_create = *p_qp_create; + convert_qp_handle( qp_create ); + + /* Clear the QP attributes to ensure non-set values are 0. */ + cl_memclr( &qp_attr, sizeof( ib_qp_attr_t ) ); + + h_qp->port_guid = port_guid; + + /* + * Allocate a QP from the channel adapter. Note that these calls + * set the send and receive pointers appropriately for posting + * work requests. + */ + if( port_guid == UNBOUND_PORT_GUID ) + { + status = + verbs_create_qp( h_pd, h_qp, &qp_create, &qp_attr, p_umv_buf ); + } + else + { + status = get_port_num( h_pd->obj.p_ci_ca, port_guid, &port_num ); + if( status == IB_SUCCESS ) + { + status = verbs_get_spl_qp( h_pd, port_num, h_qp, + &qp_create, &qp_attr ); + } + } + if( status != IB_SUCCESS ) + { + return status; + } + + /* Override function pointers. */ + h_qp->pfn_modify_qp = al_modify_qp; + + if( h_qp->type == IB_QPT_UNRELIABLE_DGRM || + h_qp->type == IB_QPT_QP0 || + h_qp->type == IB_QPT_QP1 ) + { + /* We have to mess with the AV handles. */ + h_qp->pfn_ud_post_send = h_qp->pfn_post_send; + h_qp->h_ud_send_qp = h_qp->h_send_qp; + + h_qp->pfn_post_send = ud_post_send; + h_qp->h_send_qp = h_qp; + } + + h_qp->h_recv_cq = p_qp_create->h_rq_cq; + h_qp->h_send_cq = p_qp_create->h_sq_cq; + + h_qp->recv_cq_rel.p_child_obj = (cl_obj_t*)h_qp; + h_qp->send_cq_rel.p_child_obj = (cl_obj_t*)h_qp; + + cq_attach_qp( h_qp->h_recv_cq, &h_qp->recv_cq_rel ); + cq_attach_qp( h_qp->h_send_cq, &h_qp->send_cq_rel ); + + h_qp->h_srq = p_qp_create->h_srq; + h_qp->srq_rel.p_child_obj = (cl_obj_t*)h_qp; + if (h_qp->h_srq) + srq_attach_qp( h_qp->h_srq, &h_qp->srq_rel ); + + h_qp->num = qp_attr.num; + + return IB_SUCCESS; +} + + + +ib_api_status_t +init_conn_qp( + IN al_conn_qp_t* const p_conn_qp, + IN const ib_pd_handle_t h_pd, + IN const ib_qp_create_t* const p_qp_create, + IN OUT ci_umv_buf_t* const p_umv_buf ) +{ + ib_api_status_t status; + CL_ASSERT( p_conn_qp ); + + /* Initialize the inherited QP first. */ + status = init_raw_qp( &p_conn_qp->qp, h_pd, UNBOUND_PORT_GUID, + p_qp_create, p_umv_buf ); + + return status; +} + + + +ib_api_status_t +init_dgrm_qp( + IN al_dgrm_qp_t* const p_dgrm_qp, + IN const ib_pd_handle_t h_pd, + IN const ib_qp_create_t* const p_qp_create, + IN OUT ci_umv_buf_t* const p_umv_buf ) +{ + ib_api_status_t status; + CL_ASSERT( p_dgrm_qp ); + + /* Initialize the inherited QP first. */ + status = init_raw_qp( p_dgrm_qp, h_pd, UNBOUND_PORT_GUID, + p_qp_create, p_umv_buf ); + if( status != IB_SUCCESS ) + { + return status; + } + + /* Override function pointers. */ + p_dgrm_qp->pfn_init_dgrm_svc = init_dgrm_svc; + p_dgrm_qp->pfn_join_mcast = al_join_mcast; + + return IB_SUCCESS; +} + + +#ifdef CL_KERNEL +ib_api_status_t +init_special_qp( + IN al_special_qp_t* const p_special_qp, + IN const ib_pd_handle_t h_pd, + IN const ib_net64_t port_guid, + IN const ib_qp_create_t* const p_qp_create ) +{ + ib_api_status_t status; + CL_ASSERT( p_special_qp ); + + /* Construct the special QP. */ + cl_qlist_init( &p_special_qp->to_send_queue ); + + /* Initialize the inherited QP first. */ + status = + init_raw_qp( &p_special_qp->qp, h_pd, port_guid, p_qp_create, NULL ); + if( status != IB_SUCCESS ) + { + return status; + } + + /* Override function pointers. */ + p_special_qp->qp.pfn_init_dgrm_svc = init_dgrm_svc; + p_special_qp->qp.pfn_queue_mad = special_qp_queue_mad; + p_special_qp->qp.pfn_resume_mad = special_qp_resume_sends; + + return IB_SUCCESS; +} + + +ib_api_status_t +init_qp_alias( + IN al_qp_alias_t* const p_qp_alias, + IN const ib_pd_handle_t h_pd, + IN const ib_net64_t port_guid, + IN const ib_qp_create_t* const p_qp_create ) +{ + ib_api_status_t status; + + CL_ASSERT( p_qp_alias ); + UNUSED_PARAM( p_qp_create ); + + if( h_pd->type != IB_PDT_ALIAS ) + { + return IB_INVALID_PD_HANDLE; + } + + status = attach_al_obj( &h_pd->obj, &p_qp_alias->qp.obj ); + if( status != IB_SUCCESS ) + return status; + + switch( p_qp_alias->qp.type ) + { + case IB_QPT_QP0_ALIAS: + status = acquire_smi_disp( port_guid, &p_qp_alias->h_mad_disp ); + break; + + case IB_QPT_QP1_ALIAS: + status = acquire_gsi_disp( port_guid, &p_qp_alias->h_mad_disp ); + break; + + default: + CL_ASSERT( p_qp_alias->qp.type == IB_QPT_QP0_ALIAS || + p_qp_alias->qp.type == IB_QPT_QP1_ALIAS ); + return IB_ERROR; + } + + if( status != IB_SUCCESS ) + return status; + + /* Get a copy of the QP used by the MAD dispatcher. */ + ref_al_obj( &p_qp_alias->h_mad_disp->h_qp->obj ); + p_qp_alias->qp.h_ci_qp = p_qp_alias->h_mad_disp->h_qp->h_ci_qp; + + /* Override function pointers. */ + p_qp_alias->qp.pfn_reg_mad_svc = reg_mad_svc; + + return IB_SUCCESS; +} +#endif /* CL_KERNEL */ + + + +ib_api_status_t +init_mad_qp( + IN al_mad_qp_t* const p_mad_qp, + IN const ib_pd_handle_t h_pd, + IN const ib_qp_create_t* const p_qp_create, + IN const ib_pfn_event_cb_t pfn_qp_event_cb ) +{ + ib_cq_create_t cq_create; + ib_qp_create_t qp_create; + ib_al_handle_t h_al; + ib_ca_handle_t h_ca; + ib_api_status_t status; + + CL_ASSERT( p_mad_qp ); + + /* Initialize the send and receive tracking queues. */ + cl_qlist_init( &p_mad_qp->to_send_queue ); + cl_qlist_init( &p_mad_qp->send_queue ); + cl_qlist_init( &p_mad_qp->recv_queue ); + + /* The CQ handles must be NULL when creating a MAD queue pair. */ + if( p_qp_create->h_sq_cq || p_qp_create->h_rq_cq ) + { + return IB_INVALID_SETTING; + } + + /* Initialize the CQs used with the MAD QP. */ + cl_memclr( &cq_create, sizeof( ib_cq_create_t ) ); + + /* Create the send CQ. */ + cq_create.size = p_qp_create->sq_depth; + cq_create.pfn_comp_cb = mad_send_comp_cb; + + status = ib_create_cq( h_pd->obj.p_ci_ca->h_ca, &cq_create, + p_mad_qp, mad_qp_cq_event_cb, &p_mad_qp->h_send_cq ); + + if( status != IB_SUCCESS ) + { + return status; + } + + /* Reference the MAD QP on behalf of ib_create_cq. */ + ref_al_obj( &p_mad_qp->qp.obj ); + + /* Create the receive CQ. */ + cq_create.size = p_qp_create->rq_depth; + cq_create.pfn_comp_cb = mad_recv_comp_cb; + + h_ca = PARENT_STRUCT( h_pd->obj.p_parent_obj, ib_ca_t, obj ); + status = ib_create_cq( h_ca, &cq_create, p_mad_qp, mad_qp_cq_event_cb, + &p_mad_qp->h_recv_cq ); + + if( status != IB_SUCCESS ) + { + return status; + } + + /* Reference the MAD QP on behalf of ib_create_cq. */ + ref_al_obj( &p_mad_qp->qp.obj ); + + /* Save the requested receive queue depth. This is used to post MADs. */ + p_mad_qp->max_rq_depth = p_qp_create->rq_depth; + + /* Allocate a datagram QP for the MAD QP. */ + qp_create = *p_qp_create; + qp_create.qp_type = IB_QPT_UNRELIABLE_DGRM; + qp_create.sq_sge = 1; + qp_create.rq_sge = 1; + qp_create.h_rq_cq = p_mad_qp->h_recv_cq; + qp_create.h_sq_cq = p_mad_qp->h_send_cq; + + status = ib_create_qp( h_pd, &qp_create, p_mad_qp, pfn_qp_event_cb, + &p_mad_qp->h_dgrm_qp ); + + if( status != IB_SUCCESS ) + { + return status; + } + + /* Reference the MAD QP on behalf of ib_create_qp. */ + ref_al_obj( &p_mad_qp->qp.obj ); + + /* Create the MAD dispatch service. */ + status = create_mad_disp( &p_mad_qp->qp.obj, &p_mad_qp->qp, + &p_mad_qp->h_mad_disp ); + if( status != IB_SUCCESS ) + { + return status; + } + + /* Override function pointers. */ + p_mad_qp->qp.pfn_init_dgrm_svc = init_mad_dgrm_svc; + p_mad_qp->qp.pfn_queue_mad = mad_qp_queue_mad; + p_mad_qp->qp.pfn_resume_mad = mad_qp_resume_sends; + p_mad_qp->qp.pfn_reg_mad_svc = reg_mad_svc; + + /* The client's AL handle is the grandparent of the PD. */ + h_al = PARENT_STRUCT( h_pd->obj.p_parent_obj->p_parent_obj, ib_al_t, obj ); + + /* Create a receive MAD pool. */ + status = ib_create_mad_pool( h_al, p_mad_qp->max_rq_depth + 16, 0, 16, + &p_mad_qp->h_pool ); + + if (status != IB_SUCCESS) + { + return status; + } + + /* + * The MAD pool is a child of the client's AL instance. If the client + * closes AL, the MAD pool will be destroyed before the MAD queue pair. + * Therefore, we hold a reference on the MAD pool to keep it from being + * destroyed until the MAD queue pair is destroyed. Refer to the MAD + * queue pair cleanup code. + */ + ref_al_obj( &p_mad_qp->h_pool->obj ); + + /* Register the MAD pool with the PD. */ + status = ib_reg_mad_pool( p_mad_qp->h_pool, h_pd, &p_mad_qp->pool_key ); + + if (status != IB_SUCCESS) + { + return status; + } + + /* + * Attach the MAD queue pair to the protection domain. This must be + * done after creating the datagram queue pair and the MAD pool to set + * the correct order of object destruction. + */ + status = attach_al_obj( &h_pd->obj, &p_mad_qp->qp.obj ); + + /* Get a copy of the CI datagram QP for ib_query_qp. */ + p_mad_qp->qp.h_ci_qp = p_mad_qp->h_dgrm_qp->h_ci_qp; + + return status; +} + + + +ib_api_status_t +ib_destroy_qp( + IN const ib_qp_handle_t h_qp, + IN const ib_pfn_destroy_cb_t pfn_destroy_cb OPTIONAL ) +{ + AL_ENTER( AL_DBG_QP ); + + if( AL_OBJ_INVALID_HANDLE( h_qp, AL_OBJ_TYPE_H_QP ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_QP_HANDLE\n") ); + return IB_INVALID_QP_HANDLE; + } + + ref_al_obj( &h_qp->obj ); + h_qp->obj.pfn_destroy( &h_qp->obj, pfn_destroy_cb ); + + AL_EXIT( AL_DBG_QP ); + return IB_SUCCESS; +} + + + +/* + * Release any resources that must be cleaned up immediately, such as + * any AL resources acquired by calling through the main API. + */ +void +destroying_qp( + IN al_obj_t *p_obj ) +{ + ib_qp_handle_t h_qp; + al_mad_qp_t *p_mad_qp; + al_qp_alias_t *p_qp_alias; + + CL_ASSERT( p_obj ); + h_qp = PARENT_STRUCT( p_obj, ib_qp_t, obj ); + + switch( h_qp->type ) + { + case IB_QPT_MAD: + /* Destroy QP and CQ services required for MAD QP support. */ + p_mad_qp = PARENT_STRUCT( h_qp, al_mad_qp_t, qp ); + + if( p_mad_qp->h_dgrm_qp ) + { + ib_destroy_qp( p_mad_qp->h_dgrm_qp, + (ib_pfn_destroy_cb_t)deref_al_obj ); + p_mad_qp->qp.h_ci_qp = NULL; + } + + if( p_mad_qp->h_recv_cq ) + { + ib_destroy_cq( p_mad_qp->h_recv_cq, + (ib_pfn_destroy_cb_t)deref_al_obj ); + } + + if( p_mad_qp->h_send_cq ) + { + ib_destroy_cq( p_mad_qp->h_send_cq, + (ib_pfn_destroy_cb_t)deref_al_obj ); + } + break; + + case IB_QPT_QP0_ALIAS: + case IB_QPT_QP1_ALIAS: + p_qp_alias = PARENT_STRUCT( h_qp, al_qp_alias_t, qp ); + + if( p_qp_alias->pool_key ) + { + ib_api_status_t status; + /* Deregister the pool_key. */ + status = dereg_mad_pool( p_qp_alias->pool_key, AL_KEY_ALIAS ); + if( status != IB_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("dereg_mad_pool returned %s.\n", + ib_get_err_str(status)) ); + /* Release the reference taken when we created the pool key. */ + deref_al_obj( &p_qp_alias->pool_key->obj ); + } + p_qp_alias->pool_key = NULL; + } + + if( p_qp_alias->qp.h_ci_qp ) + { + deref_al_obj( &p_qp_alias->h_mad_disp->h_qp->obj ); + p_qp_alias->qp.h_ci_qp = NULL; + } + + /* + * If the pool_key still exists here, then the QP is being destroyed + * by destroying its parent (the PD). Destruction of the PD will also + * destroy the pool_key. + */ + + if( p_qp_alias->h_mad_disp ) + deref_al_obj( &p_qp_alias->h_mad_disp->obj ); + break; + + case IB_QPT_RELIABLE_CONN: + case IB_QPT_UNRELIABLE_CONN: + al_destroy_cep( h_qp->obj.h_al, &((al_conn_qp_t*)h_qp)->cid, FALSE ); + + /* Fall through. */ + case IB_QPT_UNRELIABLE_DGRM: + default: + /* Multicast membership gets cleaned up by object hierarchy. */ + cq_detach_qp( h_qp->h_recv_cq, &h_qp->recv_cq_rel ); + cq_detach_qp( h_qp->h_send_cq, &h_qp->send_cq_rel ); + if (h_qp->h_srq) + srq_detach_qp( h_qp->h_srq, &h_qp->srq_rel ); + } +} + + + +/* + * Release any HW resources. + */ +void +cleanup_qp( + IN al_obj_t *p_obj ) +{ + ib_qp_handle_t h_qp; + al_mad_qp_t* p_mad_qp; + al_mad_wr_t* p_mad_wr; + cl_list_item_t* p_list_item; + al_mad_element_t* p_al_mad; + ib_api_status_t status; + + CL_ASSERT( p_obj ); + h_qp = PARENT_STRUCT( p_obj, ib_qp_t, obj ); + + if( verbs_check_qp( h_qp ) ) + { + status = verbs_destroy_qp( h_qp ); + if( status != IB_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("verbs_destroy_qp failed with status %s.\n", + ib_get_err_str(status)) ); + } + h_qp->h_ci_qp = NULL; + } + + if( h_qp->type == IB_QPT_MAD ) + { + /* All MAD queue pair operations are complete. */ + p_mad_qp = PARENT_STRUCT( h_qp, al_mad_qp_t, qp ); + + /* Append the pending MAD send queue to the posted MAD send queue. */ + cl_qlist_insert_list_tail( &p_mad_qp->send_queue, + &p_mad_qp->to_send_queue ); + + /* Complete all MAD sends as "flushed". */ + for( p_list_item = cl_qlist_remove_head( &p_mad_qp->send_queue ); + p_list_item != cl_qlist_end( &p_mad_qp->send_queue ); + p_list_item = cl_qlist_remove_head( &p_mad_qp->send_queue ) ) + { + p_mad_wr = PARENT_STRUCT( p_list_item, al_mad_wr_t, list_item ); + mad_qp_flush_send( p_mad_qp, p_mad_wr ); + } + + /* Return any posted receive MAD elements to the pool. */ + for( p_list_item = cl_qlist_remove_head( &p_mad_qp->recv_queue ); + p_list_item != cl_qlist_end( &p_mad_qp->recv_queue ); + p_list_item = cl_qlist_remove_head( &p_mad_qp->recv_queue ) ) + { + p_al_mad = PARENT_STRUCT( p_list_item, al_mad_element_t, + list_item ); + + status = ib_put_mad( &p_al_mad->element ); + CL_ASSERT( status == IB_SUCCESS ); + } + + if( p_mad_qp->h_pool ) + { + /* + * Destroy the receive MAD pool. If the client has closed the + * AL instance, the MAD pool should already be destroying. In + * this case, we simply release our reference on the pool to + * allow it to cleanup and deallocate. Otherwise, we initiate + * the destruction of the MAD pool and release our reference. + */ + cl_spinlock_acquire( &p_mad_qp->h_pool->obj.lock ); + if( p_mad_qp->h_pool->obj.state == CL_DESTROYING ) + { + cl_spinlock_release( &p_mad_qp->h_pool->obj.lock ); + } + else + { + cl_spinlock_release( &p_mad_qp->h_pool->obj.lock ); + ib_destroy_mad_pool( p_mad_qp->h_pool ); + } + deref_al_obj( &p_mad_qp->h_pool->obj ); + } + } + else + { + if( h_qp->h_recv_cq ) + deref_al_obj( &h_qp->h_recv_cq->obj ); + if( h_qp->h_send_cq ) + deref_al_obj( &h_qp->h_send_cq->obj ); + if( h_qp->h_srq ) + deref_al_obj( &h_qp->h_srq->obj ); + } +} + + + +void +free_qp( + IN al_obj_t *p_obj ) +{ + ib_qp_handle_t h_qp; + + CL_ASSERT( p_obj ); + h_qp = PARENT_STRUCT( p_obj, ib_qp_t, obj ); + + destroy_al_obj( p_obj ); + cl_free( h_qp ); +} + + + +ib_api_status_t +ib_query_qp( + IN const ib_qp_handle_t h_qp, + OUT ib_qp_attr_t* const p_qp_attr ) +{ + return query_qp( h_qp, p_qp_attr, NULL ); +} + + +ib_api_status_t +query_qp( + IN const ib_qp_handle_t h_qp, + OUT ib_qp_attr_t* const p_qp_attr, + IN OUT ci_umv_buf_t* const p_umv_buf ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_QP ); + + if( AL_OBJ_INVALID_HANDLE( h_qp, AL_OBJ_TYPE_H_QP ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_QP_HANDLE\n") ); + return IB_INVALID_QP_HANDLE; + } + if( !p_qp_attr ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + status = verbs_query_qp( h_qp, p_qp_attr ); + if( status != IB_SUCCESS ) + { + AL_EXIT( AL_DBG_QP ); + return status; + } + + /* Convert to using AL's handles. */ + p_qp_attr->h_pd = PARENT_STRUCT( h_qp->obj.p_parent_obj, ib_pd_t, obj ); + p_qp_attr->h_rq_cq = h_qp->h_recv_cq; + p_qp_attr->h_sq_cq = h_qp->h_send_cq; + p_qp_attr->qp_type = h_qp->type; + p_qp_attr->h_srq = h_qp->h_srq; + + AL_EXIT( AL_DBG_QP ); + return IB_SUCCESS; +} + + + +ib_api_status_t +ib_modify_qp( + IN const ib_qp_handle_t h_qp, + IN const ib_qp_mod_t* const p_qp_mod ) +{ + return modify_qp( h_qp, p_qp_mod, NULL ); +} + + + +ib_api_status_t +modify_qp( + IN const ib_qp_handle_t h_qp, + IN const ib_qp_mod_t* const p_qp_mod, + IN OUT ci_umv_buf_t* const p_umv_buf ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_QP ); + + if( AL_OBJ_INVALID_HANDLE( h_qp, AL_OBJ_TYPE_H_QP ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_QP_HANDLE\n") ); + return IB_INVALID_QP_HANDLE; + } + if( !p_qp_mod ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + status = h_qp->pfn_modify_qp( h_qp, p_qp_mod, p_umv_buf ); + + AL_EXIT( AL_DBG_QP ); + return status; +} + + + +ib_api_status_t +al_modify_qp( + IN const ib_qp_handle_t h_qp, + IN const ib_qp_mod_t* const p_qp_mod, + IN OUT ci_umv_buf_t* const p_umv_buf ) +{ + ib_api_status_t status; + + CL_ASSERT( h_qp ); + +#ifdef CL_KERNEL + /* Only allow ERROR and RESET state changes during timewait. */ + if( (h_qp->type == IB_QPT_RELIABLE_CONN || + h_qp->type == IB_QPT_UNRELIABLE_CONN) && + p_qp_mod->req_state != IB_QPS_ERROR && + p_qp_mod->req_state != IB_QPS_RESET && + p_qp_mod->req_state != IB_QPS_INIT && + cl_get_time_stamp() < h_qp->timewait ) + { + return IB_QP_IN_TIMEWAIT; + } +#endif /* CL_KERNEL */ + + /* Modify the actual QP attributes. */ + status = verbs_modify_qp( h_qp, p_qp_mod, NULL ); + + /* Record the QP state if the modify was successful. */ + if( status == IB_SUCCESS ) + h_qp->state = p_qp_mod->req_state; + + return status; +} + + +#ifdef CL_KERNEL + +ib_api_status_t +ndi_modify_qp( + IN const ib_qp_handle_t h_qp, + IN const ib_qp_mod_t* const p_qp_mod, + IN const uint32_t buf_size, + IN uint8_t* const p_outbuf) +{ + ib_api_status_t status; + ib_qp_attr_t qp_attr; + + CL_ASSERT( h_qp ); + + /* Modify the actual QP attributes. */ + status = verbs_ndi_modify_qp( h_qp, p_qp_mod, qp_attr, buf_size, p_outbuf ); + + /* Record the QP state if the modify was successful. */ + if( status == IB_SUCCESS ) + h_qp->state = p_qp_mod->req_state; + + return status; +} + +#endif + +ib_api_status_t +ib_init_dgrm_svc( + IN const ib_qp_handle_t h_qp, + IN const ib_dgrm_info_t* const p_dgrm_info OPTIONAL ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_QP ); + + if( AL_OBJ_INVALID_HANDLE( h_qp, AL_OBJ_TYPE_H_QP ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_QP_HANDLE\n") ); + return IB_INVALID_QP_HANDLE; + } + + switch( h_qp->type ) + { + case IB_QPT_QP0: + case IB_QPT_QP1: + case IB_QPT_RAW_IPV6: + case IB_QPT_RAW_ETHER: + break; + + case IB_QPT_UNRELIABLE_DGRM: + case IB_QPT_MAD: + if( !p_dgrm_info ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + break; + + default: + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + status = h_qp->pfn_init_dgrm_svc( h_qp, p_dgrm_info ); + + AL_EXIT( AL_DBG_QP ); + return status; +} + + + +/* + * Initialize a datagram QP to send and receive datagrams. + */ +ib_api_status_t +init_dgrm_svc( + IN const ib_qp_handle_t h_qp, + IN const ib_dgrm_info_t* const p_dgrm_info OPTIONAL ) +{ + al_dgrm_qp_t *p_dgrm_qp; + ib_qp_mod_t qp_mod; + ib_api_status_t status; + + CL_ASSERT( h_qp ); + + p_dgrm_qp = (al_dgrm_qp_t*)h_qp; + + /* Change to the RESET state. */ + cl_memclr( &qp_mod, sizeof( ib_qp_mod_t ) ); + qp_mod.req_state = IB_QPS_RESET; + + status = ib_modify_qp( h_qp, &qp_mod ); + if( status != IB_SUCCESS ) + { + return status; + } + + /* Change to the INIT state. */ + cl_memclr( &qp_mod, sizeof( ib_qp_mod_t ) ); + qp_mod.req_state = IB_QPS_INIT; + if( p_dgrm_info ) + { + qp_mod.state.init.qkey = p_dgrm_info->qkey; + qp_mod.state.init.pkey_index = p_dgrm_info->pkey_index; + status = get_port_num( h_qp->obj.p_ci_ca, p_dgrm_info->port_guid, + &qp_mod.state.init.primary_port ); + } + else + { + if( h_qp->type == IB_QPT_QP0 ) + qp_mod.state.init.qkey = 0; + else + qp_mod.state.init.qkey = IB_QP1_WELL_KNOWN_Q_KEY; + status = get_port_num( h_qp->obj.p_ci_ca, h_qp->port_guid, + &qp_mod.state.init.primary_port ); + } + if( status != IB_SUCCESS ) + { + return status; + } + + status = ib_modify_qp( h_qp, &qp_mod ); + if( status != IB_SUCCESS ) + { + return status; + } + + /* Change to the RTR state. */ + cl_memclr( &qp_mod, sizeof( ib_qp_mod_t ) ); + qp_mod.req_state = IB_QPS_RTR; + + status = ib_modify_qp( h_qp, &qp_mod ); + if( status != IB_SUCCESS ) + { + return status; + } + + /* Change to the RTS state. */ + cl_memclr( &qp_mod, sizeof( ib_qp_mod_t ) ); + qp_mod.req_state = IB_QPS_RTS; + qp_mod.state.rts.sq_psn = CL_HTON32(cl_get_time_stamp_sec() & 0x00ffffff); + status = ib_modify_qp( h_qp, &qp_mod ); + + return status; +} + + + +ib_api_status_t +init_mad_dgrm_svc( + IN const ib_qp_handle_t h_qp, + IN const ib_dgrm_info_t* const p_dgrm_info ) +{ + al_mad_qp_t *p_mad_qp; + ib_api_status_t status; + + CL_ASSERT( h_qp ); + + p_mad_qp = (al_mad_qp_t*)h_qp; + status = ib_init_dgrm_svc( p_mad_qp->h_dgrm_qp, p_dgrm_info ); + if( status != IB_SUCCESS ) + { + return status; + } + + /* Post receive buffers. */ + status = mad_qp_post_recvs( p_mad_qp ); + if (status != IB_SUCCESS) + { + return status; + } + + /* Force a completion callback to rearm the CQs. */ + mad_send_comp_cb( p_mad_qp->h_send_cq, p_mad_qp ); + mad_recv_comp_cb( p_mad_qp->h_recv_cq, p_mad_qp ); + + return status; +} + + + +ib_api_status_t +ib_reg_mad_svc( + IN const ib_qp_handle_t h_qp, + IN const ib_mad_svc_t* const p_mad_svc, + OUT ib_mad_svc_handle_t* const ph_mad_svc ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_MAD_SVC ); + + if( AL_OBJ_INVALID_HANDLE( h_qp, AL_OBJ_TYPE_H_QP ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_QP_HANDLE\n") ); + return IB_INVALID_QP_HANDLE; + } + + status = h_qp->pfn_reg_mad_svc( h_qp, p_mad_svc, ph_mad_svc ); + + /* Release the reference taken in init_al_obj. */ + if( status == IB_SUCCESS ) + deref_al_obj( &(*ph_mad_svc)->obj ); + + AL_EXIT( AL_DBG_MAD_SVC ); + return status; +} + + +ib_api_status_t +ib_join_mcast( + IN const ib_qp_handle_t h_qp, + IN const ib_mcast_req_t* const p_mcast_req ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_MCAST ); + + if( AL_OBJ_INVALID_HANDLE( h_qp, AL_OBJ_TYPE_H_QP ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_QP_HANDLE\n") ); + return IB_INVALID_QP_HANDLE; + } + if( !p_mcast_req ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + status = h_qp->pfn_join_mcast( h_qp, p_mcast_req ); + + AL_EXIT( AL_DBG_MCAST ); + return status; +} + + + +/* + * Post a work request to the send queue of the QP. + */ +ib_api_status_t +ib_post_send( + IN const ib_qp_handle_t h_qp, + IN ib_send_wr_t* const p_send_wr, + OUT ib_send_wr_t **pp_send_failure OPTIONAL ) +{ + ib_api_status_t status; + PERF_DECLARE( IbPostSend ); + PERF_DECLARE( PostSend ); + + cl_perf_start( IbPostSend ); + AL_ENTER( AL_DBG_QP ); + + if( AL_OBJ_INVALID_HANDLE( h_qp, AL_OBJ_TYPE_H_QP ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_QP_HANDLE\n") ); + return IB_INVALID_QP_HANDLE; + } + if( !p_send_wr || ( p_send_wr->p_next && !pp_send_failure ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + cl_perf_start( PostSend ); + status = + h_qp->pfn_post_send( h_qp->h_send_qp, p_send_wr, pp_send_failure ); + cl_perf_stop( &g_perf, PostSend ); + + AL_EXIT( AL_DBG_QP ); + cl_perf_stop( &g_perf, IbPostSend ); + return status; +} + + + +ib_api_status_t +ud_post_send( + IN const ib_qp_handle_t h_qp, + IN ib_send_wr_t* const p_send_wr, + OUT ib_send_wr_t **pp_send_failure ) +{ + ib_api_status_t status; + ib_send_wr_t *p_wr; + + CL_ASSERT( h_qp ); + + /* Convert all AV handles for verb provider usage. */ + for( p_wr = p_send_wr; p_wr; p_wr = p_wr->p_next ) + { + CL_ASSERT( p_wr->dgrm.ud.h_av ); + p_wr->dgrm.ud.rsvd = p_wr->dgrm.ud.h_av; + p_wr->dgrm.ud.h_av = convert_av_handle( h_qp, p_wr->dgrm.ud.h_av ); + } + + status = h_qp->pfn_ud_post_send( + h_qp->h_ud_send_qp, p_send_wr, pp_send_failure ); + + /* Restore all AV handles. */ + for( p_wr = p_send_wr; p_wr; p_wr = p_wr->p_next ) + p_wr->dgrm.ud.h_av = (ib_av_handle_t)p_wr->dgrm.ud.rsvd; + + return status; +} + + + +#ifdef CL_KERNEL +/* + * Post a work request to the send queue of a special QP. + * The special QP is owned by the GSA or SMA, so care must be taken to prevent + * overruning the QP by multiple owners. + */ +void +special_qp_queue_mad( + IN const ib_qp_handle_t h_qp, + IN al_mad_wr_t* const p_mad_wr ) +{ + al_special_qp_t* p_special_qp; + + CL_ASSERT( h_qp ); + CL_ASSERT( p_mad_wr ); + + p_special_qp = (al_special_qp_t*)h_qp; + + /* Queue the send work request. */ + cl_spinlock_acquire( &h_qp->obj.lock ); + cl_qlist_insert_tail( &p_special_qp->to_send_queue, &p_mad_wr->list_item ); + cl_spinlock_release( &h_qp->obj.lock ); +} + + + +void +special_qp_resume_sends( + IN const ib_qp_handle_t h_qp ) +{ + al_special_qp_t* p_special_qp; + cl_list_item_t* p_list_item; + al_mad_wr_t* p_mad_wr; + ib_api_status_t status; + + CL_ASSERT( h_qp ); + p_special_qp = (al_special_qp_t*)h_qp; + + cl_spinlock_acquire( &p_special_qp->qp.obj.lock ); + + for( p_list_item = cl_qlist_remove_head( &p_special_qp->to_send_queue ); + p_list_item != cl_qlist_end( &p_special_qp->to_send_queue ); + p_list_item = cl_qlist_remove_head( &p_special_qp->to_send_queue ) ) + { + p_mad_wr = PARENT_STRUCT( p_list_item, al_mad_wr_t, list_item ); + + cl_spinlock_release( &p_special_qp->qp.obj.lock ); + status = spl_qp_svc_send( &p_special_qp->qp, &p_mad_wr->send_wr ); + cl_spinlock_acquire( &p_special_qp->qp.obj.lock ); + + if( status != IB_SUCCESS ) + { + cl_qlist_insert_head( &p_special_qp->to_send_queue, p_list_item ); + break; + } + } + + cl_spinlock_release( &p_special_qp->qp.obj.lock ); +} +#endif /* CL_KERNEL */ + + +void +mad_qp_queue_mad( + IN const ib_qp_handle_t h_qp, + IN al_mad_wr_t* const p_mad_wr ) +{ + al_mad_qp_t *p_mad_qp; + + CL_ASSERT( h_qp ); + p_mad_qp = (al_mad_qp_t*)h_qp; + + /* Queue the send work request on the to_send_queue. */ + cl_spinlock_acquire( &p_mad_qp->qp.obj.lock ); + cl_qlist_insert_tail( &p_mad_qp->to_send_queue, &p_mad_wr->list_item ); + cl_spinlock_release( &p_mad_qp->qp.obj.lock ); +} + + + +void +mad_qp_resume_sends( + IN ib_qp_handle_t h_qp ) +{ + al_mad_qp_t *p_mad_qp; + cl_list_item_t* p_list_item; + al_mad_wr_t* p_mad_wr; + ib_api_status_t status; + + CL_ASSERT( h_qp ); + + p_mad_qp = (al_mad_qp_t*)h_qp; + + cl_spinlock_acquire( &p_mad_qp->qp.obj.lock ); + + /* Do not post sends if the MAD queue pair is being destroyed. */ + if( p_mad_qp->qp.obj.state == CL_DESTROYING ) + { + cl_spinlock_release( &p_mad_qp->qp.obj.lock ); + return; + } + + for( p_list_item = cl_qlist_remove_head( &p_mad_qp->to_send_queue ); + p_list_item != cl_qlist_end( &p_mad_qp->to_send_queue ); + p_list_item = cl_qlist_remove_head( &p_mad_qp->to_send_queue ) ) + { + p_mad_wr = PARENT_STRUCT( p_list_item, al_mad_wr_t, list_item ); + + /* Always generate send completions. */ + p_mad_wr->send_wr.send_opt |= IB_SEND_OPT_SIGNALED; + + status = ib_post_send( p_mad_qp->h_dgrm_qp, &p_mad_wr->send_wr, NULL ); + + if( status == IB_SUCCESS ) + { + /* Queue the MAD work request on the send tracking queue. */ + cl_qlist_insert_tail( &p_mad_qp->send_queue, &p_mad_wr->list_item ); + } + else + { + /* Re-queue the send work request on the to_send_queue. */ + cl_qlist_insert_head( &p_mad_qp->to_send_queue, p_list_item ); + break; + } + } + + cl_spinlock_release( &p_mad_qp->qp.obj.lock ); +} + + + +void +mad_qp_flush_send( + IN al_mad_qp_t* p_mad_qp, + IN al_mad_wr_t* const p_mad_wr ) +{ + ib_wc_t wc; + + cl_memclr( &wc, sizeof( ib_wc_t ) ); + wc.wr_id = p_mad_wr->send_wr.wr_id; + wc.wc_type = IB_WC_SEND; + wc.status = IB_WCS_WR_FLUSHED_ERR; + + mad_disp_send_done( p_mad_qp->h_mad_disp, p_mad_wr, &wc ); +} + + + +ib_api_status_t +ib_post_recv( + IN const ib_qp_handle_t h_qp, + IN ib_recv_wr_t* const p_recv_wr, + OUT ib_recv_wr_t **pp_recv_failure OPTIONAL ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_QP ); + + if( AL_OBJ_INVALID_HANDLE( h_qp, AL_OBJ_TYPE_H_QP ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_QP_HANDLE\n") ); + return IB_INVALID_QP_HANDLE; + } + if( !p_recv_wr || ( p_recv_wr->p_next && !pp_recv_failure ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + status = + h_qp->pfn_post_recv( h_qp->h_recv_qp, p_recv_wr, pp_recv_failure ); + + AL_EXIT( AL_DBG_QP ); + return status; +} + + + +/* + * Post receive buffers to a MAD QP. + */ +ib_api_status_t +mad_qp_post_recvs( + IN al_mad_qp_t* const p_mad_qp ) +{ + ib_mad_element_t* p_mad_element; + al_mad_element_t* p_al_element; + ib_recv_wr_t recv_wr; + ib_api_status_t status = IB_SUCCESS; + + CL_ASSERT( p_mad_qp ); + + /* Attempt to post receive buffers up to the max_rq_depth limit. */ + cl_spinlock_acquire( &p_mad_qp->qp.obj.lock ); + while( p_mad_qp->cur_rq_depth < (int32_t)p_mad_qp->max_rq_depth ) + { + /* Get a MAD element from the pool. */ + status = ib_get_mad( p_mad_qp->pool_key, MAD_BLOCK_SIZE, + &p_mad_element ); + + if( status != IB_SUCCESS ) break; + + p_al_element = PARENT_STRUCT( p_mad_element, al_mad_element_t, + element ); + + /* Build the receive work request. */ + recv_wr.p_next = NULL; + recv_wr.wr_id = (uintn_t)p_al_element; + recv_wr.num_ds = 1; + recv_wr.ds_array = &p_al_element->grh_ds; + + /* Queue the receive on the service tracking list. */ + cl_qlist_insert_tail( &p_mad_qp->recv_queue, &p_al_element->list_item ); + + /* Post the receive. */ + status = ib_post_recv( p_mad_qp->h_dgrm_qp, &recv_wr, NULL ); + + if( status != IB_SUCCESS ) + { + cl_qlist_remove_item( &p_mad_qp->recv_queue, + &p_al_element->list_item ); + + ib_put_mad( p_mad_element ); + break; + } + + cl_atomic_inc( &p_mad_qp->cur_rq_depth ); + } + cl_spinlock_release( &p_mad_qp->qp.obj.lock ); + + return status; +} + + + +void +mad_recv_comp_cb( + IN const ib_cq_handle_t h_cq, + IN void *cq_context ) +{ + al_mad_qp_t *p_mad_qp; + + CL_ASSERT( cq_context ); + p_mad_qp = (al_mad_qp_t*)cq_context; + + CL_ASSERT( h_cq == p_mad_qp->h_recv_cq ); + mad_qp_comp( p_mad_qp, h_cq, IB_WC_RECV ); +} + + + +void +mad_send_comp_cb( + IN const ib_cq_handle_t h_cq, + IN void *cq_context ) +{ + al_mad_qp_t *p_mad_qp; + + CL_ASSERT( cq_context ); + p_mad_qp = (al_mad_qp_t*)cq_context; + + CL_ASSERT( h_cq == p_mad_qp->h_send_cq ); + mad_qp_comp( p_mad_qp, h_cq, IB_WC_SEND ); + + /* Continue processing any queued MADs on the QP. */ + mad_qp_resume_sends( &p_mad_qp->qp ); +} + + + +void +mad_qp_comp( + IN al_mad_qp_t* p_mad_qp, + IN const ib_cq_handle_t h_cq, + IN ib_wc_type_t wc_type ) +{ + ib_wc_t wc; + ib_wc_t* p_free_wc = &wc; + ib_wc_t* p_done_wc; + al_mad_wr_t* p_mad_wr; + al_mad_element_t* p_al_mad; + ib_mad_element_t* p_mad_element; + ib_api_status_t status; + + CL_ASSERT( p_mad_qp ); + CL_ASSERT( h_cq ); + + /* Rearm the CQ before polling to avoid missing completions. */ + status = ib_rearm_cq( h_cq, FALSE ); + CL_ASSERT( status == IB_SUCCESS ); + + wc.p_next = NULL; + /* Process work completions. */ + while( ib_poll_cq( h_cq, &p_free_wc, &p_done_wc ) == IB_SUCCESS ) + { + /* Process completions one at a time. */ + + /* + * Process the work completion. Per IBA specification, the + * wc.wc_type is undefined if wc.status is not IB_WCS_SUCCESS. + * Use the wc_type function parameter instead of wc.wc_type. + */ + switch( wc_type ) + { + case IB_WC_SEND: + /* Get a pointer to the MAD work request. */ + p_mad_wr = (al_mad_wr_t*)((uintn_t)wc.wr_id); + + /* Remove the MAD work request from the send tracking queue. */ + cl_spinlock_acquire( &p_mad_qp->qp.obj.lock ); + cl_qlist_remove_item( &p_mad_qp->send_queue, &p_mad_wr->list_item ); + cl_spinlock_release( &p_mad_qp->qp.obj.lock ); + + /* Report the send completion to the dispatcher. */ + mad_disp_send_done( p_mad_qp->h_mad_disp, p_mad_wr, &wc ); + break; + + case IB_WC_RECV: + /* A receive buffer was consumed. */ + cl_atomic_dec( &p_mad_qp->cur_rq_depth ); + + /* Replenish the receive buffer. */ + mad_qp_post_recvs( p_mad_qp ); + + /* Initialize pointers to the MAD element. */ + p_al_mad = (al_mad_element_t*)((uintn_t)wc.wr_id); + p_mad_element = &p_al_mad->element; + + /* Remove the AL MAD element from the receive tracking queue. */ + cl_spinlock_acquire( &p_mad_qp->qp.obj.lock ); + cl_qlist_remove_item( &p_mad_qp->recv_queue, &p_al_mad->list_item ); + cl_spinlock_release( &p_mad_qp->qp.obj.lock ); + + /* Construct the MAD element from the receive work completion. */ + build_mad_recv( p_mad_element, &wc ); + + /* Process the received MAD. */ + status = mad_disp_recv_done( p_mad_qp->h_mad_disp, + p_mad_element ); + + /* Discard this MAD on error. */ + if( status != IB_SUCCESS ) + { + status = ib_put_mad( p_mad_element ); + CL_ASSERT( status == IB_SUCCESS ); + } + break; + + default: + CL_ASSERT( wc_type == IB_WC_SEND || wc_type == IB_WC_RECV ); + break; + } + p_free_wc = &wc; + } +} + + + +/* + * Process an event on a CQ associated with a MAD QP. + */ +void +mad_qp_cq_event_cb( + IN ib_async_event_rec_t *p_event_rec ) +{ + al_mad_qp_t *p_mad_qp; + + CL_ASSERT( p_event_rec ); + CL_ASSERT( p_event_rec->context ); + + if( p_event_rec->code == IB_AE_SQ_DRAINED ) + return; + + p_mad_qp = (al_mad_qp_t*)p_event_rec->context; + + /* Nothing to do here. */ +} + + + +/* + * Process an asynchronous event on the QP. Notify the user of the event. + */ +void +qp_async_event_cb( + IN ib_async_event_rec_t* const p_event_rec ) +{ + ib_qp_handle_t h_qp; + + CL_ASSERT( p_event_rec ); + h_qp = (ib_qp_handle_t)p_event_rec->context; + +#if defined(CL_KERNEL) + switch( p_event_rec->code ) + { + case IB_AE_QP_COMM: + al_cep_established( h_qp->obj.h_al, ((al_conn_qp_t*)h_qp)->cid ); + break; + + case IB_AE_QP_APM: + al_cep_migrate( h_qp->obj.h_al, ((al_conn_qp_t*)h_qp)->cid ); + break; + + case IB_AE_QP_APM_ERROR: + //***TODO: Figure out how to handle these errors. + break; + + default: + break; + } +#endif + + p_event_rec->context = (void*)h_qp->obj.context; + p_event_rec->handle.h_qp = h_qp; + + if( h_qp->pfn_event_cb ) + h_qp->pfn_event_cb( p_event_rec ); +} + + + +ib_api_status_t +ib_bind_mw( + IN const ib_mw_handle_t h_mw, + IN const ib_qp_handle_t h_qp, + IN ib_bind_wr_t * const p_mw_bind, + OUT net32_t * const p_rkey ) +{ + ib_mr_handle_t h_mr; + ib_api_status_t status; + + AL_ENTER( AL_DBG_MW ); + + if( AL_OBJ_INVALID_HANDLE( h_mw, AL_OBJ_TYPE_H_MW ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_MW_HANDLE\n") ); + return IB_INVALID_MW_HANDLE; + } + if( AL_OBJ_INVALID_HANDLE( h_qp, AL_OBJ_TYPE_H_QP ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_QP_HANDLE\n") ); + return IB_INVALID_QP_HANDLE; + } + if( !p_mw_bind || !p_rkey ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + /* Convert to the CI handles. */ + h_mr = p_mw_bind->h_mr; + p_mw_bind->h_mr = convert_mr_handle( h_mr ); + + status = verbs_bind_mw(h_mw, h_qp, p_mw_bind, p_rkey); + + p_mw_bind->h_mr = h_mr; + + AL_EXIT( AL_DBG_MW ); + return status; +} diff --git a/branches/WOF2-3/core/al/al_qp.h b/branches/WOF2-3/core/al/al_qp.h new file mode 100644 index 00000000..f2deaf46 --- /dev/null +++ b/branches/WOF2-3/core/al/al_qp.h @@ -0,0 +1,295 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#if !defined(__AL_QP_H__) +#define __AL_QP_H__ + +#include +#include +#include +#include + +#include "al_ca.h" +#include "al_common.h" +#include "al_mad.h" +#include "al_mcast.h" +#ifdef CL_KERNEL +#include "al_smi.h" +#include "al_ndi_cm.h" +#endif /* CL_KERNEL */ + + +/* + * Queue pair information required by the access layer. This structure + * is referenced by a user's QP handle. + * + * Other QP types are derived from this base object. + */ +typedef struct _ib_qp +{ + al_obj_t obj; /* Must be first. */ + + ib_qp_handle_t h_ci_qp; + ib_qp_type_t type; + ib_net32_t num; + ib_qp_state_t state; + net64_t port_guid; + +#ifdef CL_KERNEL + /* Timewait timeout time. */ + uint64_t timewait; +#endif /* CL_KERNEL */ + + /* Handles to pass to post_send and post_recv. */ + ib_qp_handle_t h_recv_qp; + ib_qp_handle_t h_send_qp; + + /* + * For UD QPs, we have to mess with AV handles. This is + * where we store the actual post send function and appropriate + * handle. + */ + ib_qp_handle_t h_ud_send_qp; + ib_api_status_t + (*pfn_ud_post_send)( + IN const ib_qp_handle_t h_qp, + IN ib_send_wr_t* const p_send_wr, + IN ib_send_wr_t **pp_send_failure OPTIONAL ); + + ib_cq_handle_t h_recv_cq; + ib_cq_handle_t h_send_cq; + cl_obj_rel_t recv_cq_rel; + cl_obj_rel_t send_cq_rel; + + ib_srq_handle_t h_srq; + cl_obj_rel_t srq_rel; + + ib_pfn_event_cb_t pfn_event_cb; + + ib_api_status_t + (*pfn_modify_qp)( + IN const ib_qp_handle_t h_qp, + IN const ib_qp_mod_t* const p_qp_mod, + IN OUT ci_umv_buf_t* const p_umv_buf ); + ib_api_status_t + (*pfn_post_recv)( + IN const ib_qp_handle_t h_qp, + IN ib_recv_wr_t* const p_recv_wr, + IN ib_recv_wr_t **p_recv_failure OPTIONAL ); + ib_api_status_t + (*pfn_post_send)( + IN const ib_qp_handle_t h_qp, + IN ib_send_wr_t* const p_send_wr, + IN ib_send_wr_t **pp_send_failure OPTIONAL ); + ib_api_status_t + (*pfn_reg_mad_svc)( + IN const ib_qp_handle_t h_qp, + IN const ib_mad_svc_t* const p_mad_svc, + OUT ib_mad_svc_handle_t* const ph_mad_svc ); + ib_api_status_t + (*pfn_dereg_mad_svc)( + IN const ib_mad_svc_handle_t h_mad_svc ); + void + (*pfn_queue_mad)( + IN const ib_qp_handle_t h_qp, + IN al_mad_wr_t* const p_mad_wr ); + void + (*pfn_resume_mad)( + IN const ib_qp_handle_t h_qp ); + ib_api_status_t + (*pfn_init_dgrm_svc)( + IN const ib_qp_handle_t h_qp, + IN const ib_dgrm_info_t* const p_dgrm_info ); + ib_api_status_t + (*pfn_join_mcast)( + IN const ib_qp_handle_t h_qp, + IN const ib_mcast_req_t* const p_mcast_req ); + +} ib_qp_t; + + +/* + * Connected QP type. + */ +typedef struct _al_conn_qp +{ + ib_qp_t qp; /* Must be first. */ + + ib_cm_handle_t p_conn; + + net32_t cid; + + /* Callback table. */ + ib_pfn_cm_req_cb_t pfn_cm_req_cb; + ib_pfn_cm_rep_cb_t pfn_cm_rep_cb; + ib_pfn_cm_mra_cb_t pfn_cm_mra_cb; + ib_pfn_cm_rtu_cb_t pfn_cm_rtu_cb; + ib_pfn_cm_lap_cb_t pfn_cm_lap_cb; + ib_pfn_cm_apr_cb_t pfn_cm_apr_cb; + ib_pfn_cm_dreq_cb_t pfn_cm_dreq_cb; + ib_pfn_cm_drep_cb_t pfn_cm_drep_cb; + ib_pfn_cm_rej_cb_t pfn_cm_rej_cb; /* If RTU times out */ + + +} al_conn_qp_t; + + +/* + * Datagram QP type. + */ +typedef ib_qp_t al_dgrm_qp_t; + + +/* + * Special QPs - SMI, GSI. + */ +typedef struct _al_special_qp +{ + ib_qp_t qp; /* Must be first. */ + cl_qlist_t to_send_queue; + +} al_special_qp_t; + + +/* + * QP alias to SMI, GSI QPs. + */ +typedef struct _al_qp_alias +{ + ib_qp_t qp; /* Must be first. */ + al_mad_disp_handle_t h_mad_disp; + ib_pool_key_t pool_key; /* Global MAD pool. */ + +} al_qp_alias_t; + + +/* + * QPs that support MAD operations. + */ +typedef struct _al_mad_qp +{ + ib_qp_t qp; /* Must be first. */ + ib_qp_handle_t h_dgrm_qp; + al_mad_disp_handle_t h_mad_disp; + + ib_cq_handle_t h_recv_cq; + ib_cq_handle_t h_send_cq; + + cl_qlist_t to_send_queue; /* Waiting to be posted */ + cl_qlist_t send_queue; /* Posted sends */ + cl_qlist_t recv_queue; /* Posted receives */ + uint32_t max_rq_depth; /* Maximum recv queue depth */ + atomic32_t cur_rq_depth; /* Current recv queue depth */ + + ib_pool_handle_t h_pool; + ib_pool_key_t pool_key; + +} al_mad_qp_t; + + + +ib_api_status_t +create_qp( + IN const ib_pd_handle_t h_pd, + IN const ib_qp_create_t* const p_qp_create, + IN const void* const qp_context, + IN const ib_pfn_event_cb_t pfn_qp_event_cb, + OUT ib_qp_handle_t* const ph_qp, + IN OUT ci_umv_buf_t* const p_umv_buf ); + + +ib_api_status_t +query_qp( + IN const ib_qp_handle_t h_qp, + OUT ib_qp_attr_t* const p_qp_attr, + IN OUT ci_umv_buf_t* const p_umv_buf ); + + +ib_api_status_t +modify_qp( + IN const ib_qp_handle_t h_qp, + IN const ib_qp_mod_t* const p_qp_mod, + IN OUT ci_umv_buf_t* const p_umv_buf ); + + +ib_api_status_t +get_spl_qp( + IN const ib_pd_handle_t h_pd, + IN const ib_net64_t port_guid, + IN const ib_qp_create_t* const p_qp_create, + IN const void* const qp_context, + IN const ib_pfn_event_cb_t pfn_qp_event_cb, + OUT ib_pool_key_t* const p_pool_key OPTIONAL, + OUT ib_qp_handle_t* const ph_qp, + IN OUT ci_umv_buf_t* const p_umv_buf ); + + + +ib_mad_send_handle_t +get_send_mad_wp( + IN const al_qp_alias_t *p_qp_alias ); + + + +void +put_send_mad_wp( + IN const al_qp_alias_t *p_qp_alias, + IN const ib_mad_send_handle_t h_send_mad ); + + +void +special_qp_resume_sends( + IN const ib_qp_handle_t h_qp ); + + +void +special_qp_queue_mad( + IN const ib_qp_handle_t h_qp, + IN al_mad_wr_t* const p_mad_wr ); + + +void +qp_async_event_cb( + IN ib_async_event_rec_t* const p_event_rec ); + + +/* Return the AL instance associated with this QP. */ +static inline ib_al_handle_t +qp_get_al( + IN const ib_qp_handle_t h_qp ) +{ + return h_qp->obj.h_al; +} + + +#endif /* __AL_QP_H__ */ diff --git a/branches/WOF2-3/core/al/al_query.c b/branches/WOF2-3/core/al/al_query.c new file mode 100644 index 00000000..d382e065 --- /dev/null +++ b/branches/WOF2-3/core/al/al_query.c @@ -0,0 +1,377 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include +#include + +#include "al.h" +#include "al_ca.h" +#include "al_common.h" +#include "al_debug.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "al_query.tmh" +#endif +#include "al_mgr.h" +#include "al_query.h" +#include "ib_common.h" + + +#define PR102982 + + +static ib_api_status_t +query_sa( + IN al_query_t *p_query, + IN const ib_query_req_t* const p_query_req, + IN const ib_al_flags_t flags ); + +void +query_req_cb( + IN al_sa_req_t *p_sa_req, + IN ib_mad_element_t *p_mad_response ); + + +ib_api_status_t +ib_query( + IN const ib_al_handle_t h_al, + IN const ib_query_req_t* const p_query_req, + OUT ib_query_handle_t* const ph_query OPTIONAL ) +{ + al_query_t *p_query; + ib_api_status_t status; + + AL_ENTER( AL_DBG_QUERY ); + + if( AL_OBJ_INVALID_HANDLE( h_al, AL_OBJ_TYPE_H_AL ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_AL_HANDLE\n") ); + return IB_INVALID_AL_HANDLE; + } + if( !p_query_req ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + if( (p_query_req->flags & IB_FLAGS_SYNC) && !cl_is_blockable() ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_UNSUPPORTED\n") ); + return IB_UNSUPPORTED; + } + + /* Allocate a new query. */ + p_query = cl_zalloc( sizeof( al_query_t ) ); + if( !p_query ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("insufficient memory\n") ); + return IB_INSUFFICIENT_MEMORY; + } + + /* Copy the query context information. */ + p_query->sa_req.pfn_sa_req_cb = query_req_cb; + p_query->sa_req.user_context = p_query_req->query_context; + p_query->pfn_query_cb = p_query_req->pfn_query_cb; + p_query->query_type = p_query_req->query_type; + + /* Track the query with the AL instance. */ + al_insert_query( h_al, p_query ); + + /* Issue the MAD to the SA. */ + status = query_sa( p_query, p_query_req, p_query_req->flags ); + if( status != IB_SUCCESS && status != IB_INVALID_GUID ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("query_sa failed: %s\n", ib_get_err_str(status) ) ); + } + + /* Cleanup from issuing the query if it failed or was synchronous. */ + if( status != IB_SUCCESS ) + { + al_remove_query( p_query ); + cl_free( p_query ); + } + else if( ph_query ) + { + *ph_query = p_query; + } + + AL_EXIT( AL_DBG_QUERY ); + return status; +} + + + +/* + * Query the SA based on the user's request. + */ +static ib_api_status_t +query_sa( + IN al_query_t *p_query, + IN const ib_query_req_t* const p_query_req, + IN const ib_al_flags_t flags ) +{ + ib_user_query_t sa_req, *p_sa_req; + union _query_sa_recs + { + ib_service_record_t svc; + ib_node_record_t node; + ib_portinfo_record_t portinfo; + ib_path_rec_t path; + ib_class_port_info_t class_port_info; + } rec; + ib_api_status_t status; + + AL_ENTER( AL_DBG_QUERY ); + + cl_memclr( &rec, sizeof(rec) ); + + /* Set the request information. */ + p_sa_req = &sa_req; + sa_req.method = IB_MAD_METHOD_GETTABLE; + + /* Set the MAD attributes and component mask correctly. */ + switch( p_query_req->query_type ) + { + case IB_QUERY_USER_DEFINED: + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_QUERY, ("USER_DEFINED\n") ); + p_sa_req = (ib_user_query_t*)p_query_req->p_query_input; + if( !p_sa_req->method ) + { + AL_EXIT( AL_DBG_QUERY ); + return IB_INVALID_SETTING; + } + break; + + case IB_QUERY_ALL_SVC_RECS: + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_QUERY, ("IB_QUERY_ALL_SVC_RECS\n") ); + sa_req.attr_id = IB_MAD_ATTR_SERVICE_RECORD; + sa_req.attr_size = sizeof( ib_service_record_t ); + sa_req.comp_mask = 0; + sa_req.p_attr = &rec.svc; + break; + + case IB_QUERY_SVC_REC_BY_NAME: + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_QUERY, ("SVC_REC_BY_NAME\n") ); + sa_req.attr_id = IB_MAD_ATTR_SERVICE_RECORD; + sa_req.attr_size = sizeof( ib_service_record_t ); + sa_req.comp_mask = IB_SR_COMPMASK_SNAME; + sa_req.p_attr = &rec.svc; + cl_memcpy( rec.svc.service_name, p_query_req->p_query_input, + sizeof( ib_svc_name_t ) ); + break; + + case IB_QUERY_SVC_REC_BY_ID: + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_QUERY, ("SVC_REC_BY_ID\n") ); + sa_req.attr_id = IB_MAD_ATTR_SERVICE_RECORD; + sa_req.attr_size = sizeof( ib_service_record_t ); + sa_req.comp_mask = IB_SR_COMPMASK_SID; + sa_req.p_attr = &rec.svc; + rec.svc.service_id = *(ib_net64_t*)(p_query_req->p_query_input); + break; + + case IB_QUERY_CLASS_PORT_INFO: + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_QUERY, ("IB_QUERY_CLASS_PORT_INFO\n") ); + sa_req.method = IB_MAD_METHOD_GET; + sa_req.attr_id = IB_MAD_ATTR_CLASS_PORT_INFO; + sa_req.attr_size = sizeof( ib_class_port_info_t ); + sa_req.comp_mask = 0; + sa_req.p_attr = &rec.class_port_info; + break; + + case IB_QUERY_NODE_REC_BY_NODE_GUID: + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_QUERY, ("NODE_REC_BY_NODE_GUID\n") ); + /* + * 15.2.5.2: + * if >1 ports on of a CA/RTR the subnet return multiple + * record + */ + sa_req.attr_id = IB_MAD_ATTR_NODE_RECORD; + sa_req.attr_size = sizeof( ib_node_record_t ); + sa_req.comp_mask = IB_NR_COMPMASK_NODEGUID; + sa_req.p_attr = &rec.node; + rec.node.node_info.node_guid = + *(ib_net64_t*)(p_query_req->p_query_input); + break; + + case IB_QUERY_PORT_REC_BY_LID: + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_QUERY, ("PORT_REC_BY_LID\n") ); + sa_req.attr_id = IB_MAD_ATTR_PORTINFO_RECORD; + sa_req.attr_size = sizeof( ib_portinfo_record_t ); + sa_req.comp_mask = IB_PIR_COMPMASK_BASELID; + sa_req.p_attr = &rec.portinfo; + rec.portinfo.port_info.base_lid = + *(ib_net16_t*)(p_query_req->p_query_input); + break; + + case IB_QUERY_PATH_REC_BY_PORT_GUIDS: + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_QUERY, ("PATH_REC_BY_PORT_GUIDS\n") ); + sa_req.attr_id = IB_MAD_ATTR_PATH_RECORD; + sa_req.attr_size = sizeof( ib_path_rec_t ); + sa_req.comp_mask = (IB_PR_COMPMASK_DGID | + IB_PR_COMPMASK_SGID | IB_PR_COMPMASK_NUMBPATH); + sa_req.p_attr = &rec.path; + ib_gid_set_default( &rec.path.dgid, ((ib_guid_pair_t*) + (p_query_req->p_query_input))->dest_guid ); + ib_gid_set_default( &rec.path.sgid, ((ib_guid_pair_t*) + (p_query_req->p_query_input))->src_guid ); + rec.path.num_path = 1; + break; + + case IB_QUERY_PATH_REC_BY_GIDS: + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_QUERY, ("PATH_REC_BY_GIDS\n") ); + sa_req.attr_id = IB_MAD_ATTR_PATH_RECORD; + sa_req.attr_size = sizeof( ib_path_rec_t ); + sa_req.comp_mask = (IB_PR_COMPMASK_DGID | + IB_PR_COMPMASK_SGID | IB_PR_COMPMASK_NUMBPATH); + sa_req.p_attr = &rec.path; + cl_memcpy( &rec.path.dgid, &((ib_gid_pair_t*) + (p_query_req->p_query_input))->dest_gid, sizeof( ib_gid_t ) ); + cl_memcpy( &rec.path.sgid, &((ib_gid_pair_t*) + (p_query_req->p_query_input))->src_gid, sizeof( ib_gid_t ) ); + rec.path.num_path = 1; + break; + + case IB_QUERY_PATH_REC_BY_LIDS: + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_QUERY, ("PATH_REC_BY_LIDS\n") ); + /* SGID must be provided for GET_TABLE requests. */ + sa_req.method = IB_MAD_METHOD_GET; + sa_req.attr_id = IB_MAD_ATTR_PATH_RECORD; + sa_req.attr_size = sizeof( ib_path_rec_t ); + sa_req.comp_mask = + (IB_PR_COMPMASK_DLID | IB_PR_COMPMASK_SLID); + sa_req.p_attr = &rec.path; + rec.path.dlid = + ((ib_lid_pair_t*)(p_query_req->p_query_input))->dest_lid; + rec.path.slid = + ((ib_lid_pair_t*)(p_query_req->p_query_input))->src_lid; +#ifdef PR102982 + rec.path.num_path = 1; +#endif + break; + + default: + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("UNKNOWN\n") ); + CL_ASSERT( p_query_req->query_type == IB_QUERY_USER_DEFINED || + p_query_req->query_type == IB_QUERY_ALL_SVC_RECS || + p_query_req->query_type == IB_QUERY_SVC_REC_BY_NAME || + p_query_req->query_type == IB_QUERY_SVC_REC_BY_ID || + p_query_req->query_type == IB_QUERY_CLASS_PORT_INFO || + p_query_req->query_type == IB_QUERY_NODE_REC_BY_NODE_GUID || + p_query_req->query_type == IB_QUERY_PORT_REC_BY_LID || + p_query_req->query_type == IB_QUERY_PATH_REC_BY_PORT_GUIDS || + p_query_req->query_type == IB_QUERY_PATH_REC_BY_GIDS || + p_query_req->query_type == IB_QUERY_PATH_REC_BY_LIDS ); + + return IB_ERROR; + } + + status = al_send_sa_req( + &p_query->sa_req, p_query_req->port_guid, p_query_req->timeout_ms, + p_query_req->retry_cnt, p_sa_req, flags ); + AL_EXIT( AL_DBG_QUERY ); + return status; +} + + + +/* + * Query request completion callback. + */ +void +query_req_cb( + IN al_sa_req_t *p_sa_req, + IN ib_mad_element_t *p_mad_response ) +{ + al_query_t *p_query; + ib_query_rec_t query_rec; + ib_sa_mad_t *p_sa_mad; + + AL_ENTER( AL_DBG_QUERY ); + p_query = PARENT_STRUCT( p_sa_req, al_query_t, sa_req ); + + /* Initialize the results of the query. */ + cl_memclr( &query_rec, sizeof( ib_query_rec_t ) ); + query_rec.status = p_sa_req->status; + query_rec.query_context = p_query->sa_req.user_context; + query_rec.query_type = p_query->query_type; + + /* Form the result of the query, if we got one. */ + if( query_rec.status == IB_SUCCESS ) + { + + CL_ASSERT( p_mad_response ); + p_sa_mad = (ib_sa_mad_t*)p_mad_response->p_mad_buf; + + if (ib_get_attr_size( p_sa_mad->attr_offset ) != 0) + { + query_rec.result_cnt = + ( ( p_mad_response->size - IB_SA_MAD_HDR_SIZE ) / + ib_get_attr_size( p_sa_mad->attr_offset ) ); + } + else + { + query_rec.result_cnt = 0; + } + + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_QUERY, + ("query succeeded with result_cnt = %d\n", query_rec.result_cnt) ); + + query_rec.p_result_mad = p_mad_response; + } + else + { + AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_QUERY, + ("query failed: %s\n", ib_get_err_str(query_rec.status) ) ); + if( p_mad_response ) + query_rec.p_result_mad = p_mad_response; + } + + /* + * Handing an internal MAD to a client. + * Track the MAD element with the client's AL instance. + */ + if( p_mad_response ) + al_handoff_mad( p_query->h_al, p_mad_response ); + + /* Notify the user of the result. */ + p_query->pfn_query_cb( &query_rec ); + + /* Cleanup from issuing the query. */ + al_remove_query( p_query ); + cl_free( p_query ); + + AL_EXIT( AL_DBG_QUERY ); +} diff --git a/branches/WOF2-3/core/al/al_query.h b/branches/WOF2-3/core/al/al_query.h new file mode 100644 index 00000000..e32dfb2e --- /dev/null +++ b/branches/WOF2-3/core/al/al_query.h @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#if !defined(__AL_QUERY_H__) +#define __AL_QUERY_H__ + + +#include "al_common.h" +#include +#include + + +/* Per port sa_req service */ +typedef struct _sa_req_svc +{ + al_obj_t obj; + + ib_net64_t port_guid; + uint8_t port_num; + ib_net16_t sm_lid; + uint8_t sm_sl; + + ib_qp_handle_t h_qp; + ib_mad_svc_handle_t h_mad_svc; + ib_av_handle_t h_av; + + ib_pool_key_t pool_key; + atomic32_t trans_id; + +} sa_req_svc_t; + + + +struct _al_sa_req; + + +typedef void +(*pfn_sa_req_cb_t)( + IN struct _al_sa_req *p_sa_req, + IN ib_mad_element_t *p_mad_response ); + + + +typedef enum _al_sa_reg_state +{ + SA_REG_STARTING = 0, /* Request sent to SA - awaiting response. */ + SA_REG_ACTIVE, /* Request successfully ack'ed by SA. */ + SA_REG_CANCELING, /* Canceling STARTING request to SA. */ + SA_REG_HALTING, /* Deregistering from SA. */ + SA_REG_ERROR /* There was an error registering. */ + +} al_sa_reg_state_t; + + +/* Notes: Only the pfn_sa_req_cb field is required to send a request. */ +typedef struct _al_sa_req +{ + cl_list_item_t list_item; + + ib_api_status_t status; + +#ifdef CL_KERNEL + sa_req_svc_t *p_sa_req_svc; /* For cancellation */ + ib_mad_element_t *p_mad_response; + ib_mad_element_t *p_mad_request; /* For cancellation */ + KEVENT *p_sync_event; +#else /* defined( CL_KERNEL ) */ + uint64_t hdl; + ual_send_sa_req_ioctl_t ioctl; + OVERLAPPED ov; +#endif /* defined( CL_KERNEL ) */ + const void *user_context; + pfn_sa_req_cb_t pfn_sa_req_cb; + +} al_sa_req_t; + + + +typedef struct _al_query +{ + al_sa_req_t sa_req; /* Must be first. */ + + ib_al_handle_t h_al; + ib_pfn_query_cb_t pfn_query_cb; + ib_query_type_t query_type; + +} al_query_t; + + + +ib_api_status_t +create_sa_req_mgr( + IN al_obj_t* const p_parent_obj ); + +ib_api_status_t +al_send_sa_req( + IN al_sa_req_t *p_sa_req, + IN const net64_t port_guid, + IN const uint32_t timeout_ms, + IN const uint32_t retry_cnt, + IN const ib_user_query_t* const p_sa_req_data, + IN const ib_al_flags_t flags ); + +#if defined( CL_KERNEL ) +static __inline void +al_cancel_sa_req( + IN const al_sa_req_t *p_sa_req ) +{ + ib_cancel_mad( p_sa_req->p_sa_req_svc->h_mad_svc, + p_sa_req->p_mad_request ); +} +#else /* defined( CL_KERNEL ) */ +void +al_cancel_sa_req( + IN const al_sa_req_t *p_sa_req ); +#endif /* defined( CL_KERNEL ) */ + +ib_api_status_t +convert_wc_status( + IN const ib_wc_status_t wc_status ); + + +#endif /* __AL_QUERY_H__ */ diff --git a/branches/WOF2-3/core/al/al_reg_svc.c b/branches/WOF2-3/core/al/al_reg_svc.c new file mode 100644 index 00000000..09c0dd0f --- /dev/null +++ b/branches/WOF2-3/core/al/al_reg_svc.c @@ -0,0 +1,359 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include + +#include "al.h" +#include "al_debug.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "al_reg_svc.tmh" +#endif +#include "al_reg_svc.h" +#include "ib_common.h" +#include "al_mgr.h" + + + +static void +__dereg_svc_cb( + IN al_sa_req_t *p_sa_req, + IN ib_mad_element_t *p_mad_response ) +{ + ib_reg_svc_handle_t h_reg_svc; + + /* + * Note that we come into this callback with a reference + * on the registration object. + */ + h_reg_svc = PARENT_STRUCT( p_sa_req, al_reg_svc_t, sa_req ); + + if( p_mad_response ) + ib_put_mad( p_mad_response ); + + h_reg_svc->obj.pfn_destroy( &h_reg_svc->obj, NULL ); +} + + +static void +__sa_dereg_svc( + IN const ib_reg_svc_handle_t h_reg_svc ) +{ + ib_user_query_t sa_mad_data; + + ref_al_obj( &h_reg_svc->obj ); + + /* Set the request information. */ + h_reg_svc->sa_req.pfn_sa_req_cb = __dereg_svc_cb; + + /* Set the MAD attributes and component mask correctly. */ + sa_mad_data.method = IB_MAD_METHOD_DELETE; + sa_mad_data.attr_id = IB_MAD_ATTR_SERVICE_RECORD; + sa_mad_data.attr_size = sizeof(ib_service_record_t); + + sa_mad_data.p_attr = &h_reg_svc->svc_rec; + sa_mad_data.comp_mask = ~CL_CONST64(0); + + if( al_send_sa_req( &h_reg_svc->sa_req, h_reg_svc->port_guid, + 500, 0, &sa_mad_data, 0 ) != IB_SUCCESS ) + { + /* Cleanup from the registration. */ + deref_al_obj( &h_reg_svc->obj ); + } +} + + +void +reg_svc_req_cb( + IN al_sa_req_t *p_sa_req, + IN ib_mad_element_t *p_mad_response ) +{ + ib_reg_svc_handle_t h_reg_svc; + ib_sa_mad_t *p_sa_mad; + ib_reg_svc_rec_t reg_svc_rec; + + /* + * Note that we come into this callback with a reference + * on the registration object. + */ + h_reg_svc = PARENT_STRUCT( p_sa_req, al_reg_svc_t, sa_req ); + + CL_ASSERT( h_reg_svc->pfn_reg_svc_cb ); + + /* Record the status of the registration request. */ + h_reg_svc->req_status = p_sa_req->status; + + if( p_mad_response ) + { + p_sa_mad = (ib_sa_mad_t *)p_mad_response->p_mad_buf; + h_reg_svc->resp_status = p_sa_mad->status; + + if ( h_reg_svc->req_status == IB_SUCCESS ) + { + /* Save the service registration results. */ + h_reg_svc->svc_rec = *((ib_service_record_t *)p_sa_mad->data); + } + + /* We no longer need the response MAD. */ + ib_put_mad( p_mad_response ); + } + + /* Initialize the user's callback record. */ + cl_memclr( ®_svc_rec, sizeof( ib_reg_svc_rec_t ) ); + reg_svc_rec.svc_context = h_reg_svc->sa_req.user_context; + reg_svc_rec.req_status = h_reg_svc->req_status; + reg_svc_rec.resp_status = h_reg_svc->resp_status; + reg_svc_rec.svc_rec = h_reg_svc->svc_rec; + + cl_spinlock_acquire( &h_reg_svc->obj.lock ); + /* See if the registration was successful. */ + if( reg_svc_rec.req_status == IB_SUCCESS ) + { + /* Ensure that the user wants the registration to proceed. */ + if( h_reg_svc->state == SA_REG_STARTING ) + { + h_reg_svc->state = SA_REG_ACTIVE; + reg_svc_rec.h_reg_svc = h_reg_svc; + } + else + { + CL_ASSERT( h_reg_svc->state == SA_REG_CANCELING ); + reg_svc_rec.req_status = IB_CANCELED; + + /* Notify the SA that we're deregistering. */ + __sa_dereg_svc( h_reg_svc ); + } + } + else + { + h_reg_svc->state = SA_REG_ERROR; + } + cl_spinlock_release( &h_reg_svc->obj.lock ); + + h_reg_svc->pfn_reg_svc_cb( ®_svc_rec ); + + if( p_sa_req->status != IB_SUCCESS ) + { + h_reg_svc->obj.pfn_destroy( &h_reg_svc->obj, NULL ); + } + else + { + /* Release the reference taken when issuing the request. */ + deref_al_obj( &h_reg_svc->obj ); + } +} + + +static void +__destroying_sa_reg( + IN al_obj_t* const p_obj ) +{ + ib_reg_svc_handle_t h_sa_reg; + + AL_ENTER( AL_DBG_SA_REQ ); + + h_sa_reg = PARENT_STRUCT( p_obj, al_reg_svc_t, obj ); + + cl_spinlock_acquire( &p_obj->lock ); + + CL_ASSERT( h_sa_reg->state != SA_REG_HALTING ); + switch( h_sa_reg->state ) + { + case SA_REG_STARTING: + /* + * Cancel registration. Note that there is a reference held until + * this completes. + */ + h_sa_reg->state = SA_REG_CANCELING; + al_cancel_sa_req( &h_sa_reg->sa_req ); + break; + + case SA_REG_ERROR: + /* Nothing to do. */ + break; + + default: + h_sa_reg->state = SA_REG_HALTING; + + __sa_dereg_svc( h_sa_reg ); + } + cl_spinlock_release( &p_obj->lock ); + +} + + +static void +__free_sa_reg( + IN al_obj_t* const p_obj ) +{ + ib_reg_svc_handle_t h_sa_reg; + + AL_ENTER( AL_DBG_SA_REQ ); + + h_sa_reg = PARENT_STRUCT( p_obj, al_reg_svc_t, obj ); + + destroy_al_obj( p_obj ); + cl_free( h_sa_reg ); + + AL_EXIT( AL_DBG_SA_REQ ); +} + + +static ib_api_status_t +sa_reg_svc( + IN const ib_reg_svc_handle_t h_reg_svc, + IN const ib_reg_svc_req_t* const p_reg_svc_req ) +{ + ib_user_query_t sa_mad_data; + + /* Set the request information. */ + h_reg_svc->sa_req.pfn_sa_req_cb = reg_svc_req_cb; + + /* Set the MAD attributes and component mask correctly. */ + sa_mad_data.method = IB_MAD_METHOD_SET; + sa_mad_data.attr_id = IB_MAD_ATTR_SERVICE_RECORD; + sa_mad_data.attr_size = sizeof(ib_service_record_t); + + /* Initialize the component mask. */ + sa_mad_data.comp_mask = p_reg_svc_req->svc_data_mask; + sa_mad_data.p_attr = &h_reg_svc->svc_rec; + + return al_send_sa_req( &h_reg_svc->sa_req, h_reg_svc->port_guid, + p_reg_svc_req->timeout_ms, p_reg_svc_req->retry_cnt, &sa_mad_data, + p_reg_svc_req->flags ); +} + + +ib_api_status_t +ib_reg_svc( + IN const ib_al_handle_t h_al, + IN const ib_reg_svc_req_t* const p_reg_svc_req, + OUT ib_reg_svc_handle_t* const ph_reg_svc ) +{ + ib_reg_svc_handle_t h_sa_reg = NULL; + ib_api_status_t status; + + AL_ENTER( AL_DBG_SA_REQ ); + + if( AL_OBJ_INVALID_HANDLE( h_al, AL_OBJ_TYPE_H_AL ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_AL_HANDLE\n") ); + return IB_INVALID_AL_HANDLE; + } + if( !p_reg_svc_req ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + /* Allocate a new service registration request. */ + h_sa_reg = cl_zalloc( sizeof( al_reg_svc_t ) ); + if( !h_sa_reg ) + { + AL_EXIT( AL_DBG_SA_REQ ); + return IB_INSUFFICIENT_MEMORY; + } + + construct_al_obj( &h_sa_reg->obj, AL_OBJ_TYPE_H_SA_REG ); + + status = init_al_obj( &h_sa_reg->obj, p_reg_svc_req->svc_context, TRUE, + __destroying_sa_reg, NULL, __free_sa_reg ); + if( status != IB_SUCCESS ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("init_al_obj returned %s.\n", ib_get_err_str( status )) ); + __free_sa_reg( &h_sa_reg->obj ); + return status; + } + + /* Track the registered service with the AL instance. */ + status = attach_al_obj( &h_al->obj, &h_sa_reg->obj ); + if( status != IB_SUCCESS ) + { + h_sa_reg->obj.pfn_destroy( &h_sa_reg->obj, NULL ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("attach_al_obj returned %s.\n", ib_get_err_str( status )) ); + return status; + } + + /* Store the port GUID on which to issue the request. */ + h_sa_reg->port_guid = p_reg_svc_req->port_guid; + + /* Copy the service registration information. */ + h_sa_reg->sa_req.user_context = p_reg_svc_req->svc_context; + h_sa_reg->pfn_reg_svc_cb = p_reg_svc_req->pfn_reg_svc_cb; + h_sa_reg->svc_rec = p_reg_svc_req->svc_rec; + + h_sa_reg->state = SA_REG_STARTING; + + /* Issue the MAD to the SA. */ + status = sa_reg_svc( h_sa_reg, p_reg_svc_req ); + if( status != IB_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("sa_reg_svc failed: %s\n", ib_get_err_str(status) ) ); + h_sa_reg->state = SA_REG_ERROR; + + h_sa_reg->obj.pfn_destroy( &h_sa_reg->obj, NULL ); + } + else + { + *ph_reg_svc = h_sa_reg; + } + + AL_EXIT( AL_DBG_SA_REQ ); + return status; +} + + +ib_api_status_t +ib_dereg_svc( + IN const ib_reg_svc_handle_t h_reg_svc, + IN const ib_pfn_destroy_cb_t pfn_destroy_cb OPTIONAL ) +{ + AL_ENTER( AL_DBG_SA_REQ ); + + if( AL_OBJ_INVALID_HANDLE( h_reg_svc, AL_OBJ_TYPE_H_SA_REG) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_HANDLE\n") ); + return IB_INVALID_HANDLE; + } + + ref_al_obj( &h_reg_svc->obj ); + h_reg_svc->obj.pfn_destroy( &h_reg_svc->obj, pfn_destroy_cb ); + + AL_EXIT( AL_DBG_SA_REQ ); + return IB_SUCCESS; +} diff --git a/branches/WOF2-3/core/al/al_reg_svc.h b/branches/WOF2-3/core/al/al_reg_svc.h new file mode 100644 index 00000000..56f6dbc5 --- /dev/null +++ b/branches/WOF2-3/core/al/al_reg_svc.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#if !defined(__AL_REG_SVC_H__) +#define __AL_REG_SVC_H__ + +#include + +#include "al_common.h" +#include "al_query.h" + + + +typedef struct _al_reg_svc +{ + al_obj_t obj; + + al_sa_req_t sa_req; + + /* Status of the registration request. */ + ib_api_status_t req_status; + /* Additional status information returned in the registration response. */ + ib_net16_t resp_status; + + al_sa_reg_state_t state; + ib_pfn_reg_svc_cb_t pfn_reg_svc_cb; + + /* Store service record to report to SA later. */ + ib_service_record_t svc_rec; + ib_net64_t port_guid; + +} al_reg_svc_t; + + + +#endif /* __AL_REG_SVC_H__ */ diff --git a/branches/WOF2-3/core/al/al_res_mgr.c b/branches/WOF2-3/core/al/al_res_mgr.c new file mode 100644 index 00000000..4e4746cd --- /dev/null +++ b/branches/WOF2-3/core/al/al_res_mgr.c @@ -0,0 +1,300 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include + +#include "al_mgr.h" +#include "ib_common.h" +#include "al_res_mgr.h" +#include "al_debug.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "al_res_mgr.tmh" +#endif + + +#define AL_MR_POOL_SIZE (4096 / sizeof( ib_mr_t )) +#define AL_AV_POOL_SIZE (4096 / sizeof( ib_av_t )) +#ifdef CL_KERNEL +#define AL_FMR_POOL_SIZE (4096 / sizeof( mlnx_fmr_t )) +#endif + +al_res_mgr_t *gp_res_mgr; + + +void +free_res_mgr( + IN al_obj_t *p_obj ); + + + +ib_api_status_t +create_res_mgr( + IN al_obj_t *p_parent_obj ) +{ + ib_api_status_t status; + cl_status_t cl_status; + + gp_res_mgr = (al_res_mgr_t*)cl_zalloc( sizeof( al_res_mgr_t ) ); + if( !gp_res_mgr ) + { + return IB_INSUFFICIENT_MEMORY; + } + + /* Construct the resource manager. */ + cl_qpool_construct( &gp_res_mgr->av_pool ); + cl_qpool_construct( &gp_res_mgr->mr_pool ); +#ifdef CL_KERNEL + cl_qpool_construct( &gp_res_mgr->fmr_pool ); +#endif + + construct_al_obj( &gp_res_mgr->obj, AL_OBJ_TYPE_RES_MGR ); + status = init_al_obj( &gp_res_mgr->obj, gp_res_mgr, TRUE, + NULL, NULL, free_res_mgr ); + if( status != IB_SUCCESS ) + { + free_res_mgr( &gp_res_mgr->obj ); + return status; + } + + status = attach_al_obj( p_parent_obj, &gp_res_mgr->obj ); + if( status != IB_SUCCESS ) + { + gp_res_mgr->obj.pfn_destroy( &gp_res_mgr->obj, NULL ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("attach_al_obj returned %s.\n", ib_get_err_str(status)) ); + return status; + } + + /* Initialize the pool of address vectors. */ + cl_status = cl_qpool_init( &gp_res_mgr->av_pool, + AL_AV_POOL_SIZE, 0, AL_AV_POOL_SIZE, sizeof( ib_av_t ), + av_ctor, av_dtor, gp_res_mgr ); + if( cl_status != CL_SUCCESS ) + { + gp_res_mgr->obj.pfn_destroy( &gp_res_mgr->obj, NULL ); + return ib_convert_cl_status( cl_status ); + } + + /* Initialize the pool of memory regions. */ + cl_status = cl_qpool_init( &gp_res_mgr->mr_pool, + AL_MR_POOL_SIZE, 0, AL_MR_POOL_SIZE, sizeof( ib_mr_t ), + mr_ctor, mr_dtor, gp_res_mgr ); + if( cl_status != CL_SUCCESS ) + { + gp_res_mgr->obj.pfn_destroy( &gp_res_mgr->obj, NULL ); + return ib_convert_cl_status( cl_status ); + } + +#ifdef CL_KERNEL + /* Initialize the pool of fast memory regions. */ + cl_status = cl_qpool_init( &gp_res_mgr->fmr_pool, + AL_FMR_POOL_SIZE, 0, AL_FMR_POOL_SIZE, sizeof(mlnx_fmr_t), + mlnx_fmr_ctor, mlnx_fmr_dtor, gp_res_mgr ); + if( cl_status != CL_SUCCESS ) + { + gp_res_mgr->obj.pfn_destroy( &gp_res_mgr->obj, NULL ); + return ib_convert_cl_status( cl_status ); + } +#endif + + /* Release the reference taken in init_al_obj. */ + deref_al_obj( &gp_res_mgr->obj ); + + return IB_SUCCESS; +} + + + +/* + * Destroy the resource manager. + */ +void +free_res_mgr( + IN al_obj_t *p_obj ) +{ + CL_ASSERT( p_obj == &gp_res_mgr->obj ); + + cl_qpool_destroy( &gp_res_mgr->av_pool ); + cl_qpool_destroy( &gp_res_mgr->mr_pool ); +#ifdef CL_KERNEL + cl_qpool_destroy( &gp_res_mgr->fmr_pool ); +#endif + + destroy_al_obj( p_obj ); + cl_free ( gp_res_mgr ); + gp_res_mgr = NULL; +} + + + +/* + * Get a memory region structure to track registration requests. + */ +ib_mr_handle_t +alloc_mr() +{ + al_obj_t *p_obj; + cl_pool_item_t *p_pool_item; + + cl_spinlock_acquire( &gp_res_mgr->obj.lock ); + p_pool_item = cl_qpool_get( &gp_res_mgr->mr_pool ); + cl_spinlock_release( &gp_res_mgr->obj.lock ); + + if( !p_pool_item ) + return NULL; + + ref_al_obj( &gp_res_mgr->obj ); + p_obj = PARENT_STRUCT( p_pool_item, al_obj_t, pool_item ); + + /* + * Hold an extra reference on the object until creation is complete. + * This prevents a client's destruction of the object during asynchronous + * event callback processing from deallocating the object before the + * creation is complete. + */ + ref_al_obj( p_obj ); + + return PARENT_STRUCT( p_obj, ib_mr_t, obj ); +} + + + +/* + * Return a memory region structure to the available pool. + */ +void +put_mr( + IN ib_mr_handle_t h_mr ) +{ + cl_spinlock_acquire( &gp_res_mgr->obj.lock ); + cl_qpool_put( &gp_res_mgr->mr_pool, &h_mr->obj.pool_item ); + cl_spinlock_release( &gp_res_mgr->obj.lock ); + deref_al_obj( &gp_res_mgr->obj ); +} + + +#ifdef CL_KERNEL +/* + * Get a fast memory region structure to track registration requests. + */ +mlnx_fmr_handle_t +alloc_mlnx_fmr() +{ + al_obj_t *p_obj; + cl_pool_item_t *p_pool_item; + + cl_spinlock_acquire( &gp_res_mgr->obj.lock ); + p_pool_item = cl_qpool_get( &gp_res_mgr->fmr_pool ); + cl_spinlock_release( &gp_res_mgr->obj.lock ); + + if( !p_pool_item ) + return NULL; + + ref_al_obj( &gp_res_mgr->obj ); + p_obj = PARENT_STRUCT( p_pool_item, al_obj_t, pool_item ); + + /* + * Hold an extra reference on the object until creation is complete. + * This prevents a client's destruction of the object during asynchronous + * event callback processing from deallocating the object before the + * creation is complete. + */ + ref_al_obj( p_obj ); + + return PARENT_STRUCT( p_obj, mlnx_fmr_t, obj ); +} + + + +/* + * Return a memory region structure to the available pool. + */ +void +put_mlnx_fmr( + IN mlnx_fmr_handle_t h_fmr ) +{ + cl_spinlock_acquire( &gp_res_mgr->obj.lock ); + cl_qpool_put( &gp_res_mgr->fmr_pool, &h_fmr->obj.pool_item ); + cl_spinlock_release( &gp_res_mgr->obj.lock ); + deref_al_obj( &gp_res_mgr->obj ); +} +#endif + + +/* + * Get an address vector from the available pool. + */ +ib_av_handle_t +alloc_av() +{ + al_obj_t *p_obj; + cl_pool_item_t *p_pool_item; + + cl_spinlock_acquire( &gp_res_mgr->obj.lock ); + p_pool_item = cl_qpool_get( &gp_res_mgr->av_pool ); + cl_spinlock_release( &gp_res_mgr->obj.lock ); + + if( !p_pool_item ) + return NULL; + + ref_al_obj( &gp_res_mgr->obj ); + p_obj = PARENT_STRUCT( p_pool_item, al_obj_t, pool_item ); + + /* + * Hold an extra reference on the object until creation is complete. + * This prevents a client's destruction of the object during asynchronous + * event callback processing from deallocating the object before the + * creation is complete. + */ + ref_al_obj( p_obj ); + return PARENT_STRUCT( p_obj, ib_av_t, obj ); +} + + + +/* + * Return an address vector to the available pool. + */ +void +put_av( + IN ib_av_handle_t h_av ) +{ + cl_spinlock_acquire( &gp_res_mgr->obj.lock ); + cl_qpool_put( &gp_res_mgr->av_pool, &h_av->obj.pool_item ); + cl_spinlock_release( &gp_res_mgr->obj.lock ); + deref_al_obj( &gp_res_mgr->obj ); +} diff --git a/branches/WOF2-3/core/al/al_res_mgr.h b/branches/WOF2-3/core/al/al_res_mgr.h new file mode 100644 index 00000000..65eb54aa --- /dev/null +++ b/branches/WOF2-3/core/al/al_res_mgr.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#if !defined(__AL_RES_MGR_H__) +#define __AL_RES_MGR_H__ + + +#include + +#include "al_av.h" +#include "al_mr.h" +#include "al_qp.h" +#include "al_mad.h" + +#include +#include +#include +#include + + + +typedef struct _al_res_mgr +{ + al_obj_t obj; + + cl_qpool_t mr_pool; + cl_qpool_t av_pool; +#ifdef CL_KERNEL + cl_qpool_t fmr_pool; +#endif + +} al_res_mgr_t; + + + +ib_api_status_t +create_res_mgr( + IN al_obj_t *p_parent_obj ); + + +ib_mr_handle_t +alloc_mr(void); + + +void +put_mr( + IN ib_mr_handle_t h_mr ); + +#ifdef CL_KERNEL +mlnx_fmr_handle_t +alloc_mlnx_fmr(void); + + +void +put_mlnx_fmr( + IN mlnx_fmr_handle_t h_fmr ); +#endif + +ib_av_handle_t +alloc_av(void); + + +void +put_av( + IN ib_av_handle_t h_av ); + + +#endif /* __AL_RES_MGR_H__ */ diff --git a/branches/WOF2-3/core/al/al_srq.c b/branches/WOF2-3/core/al/al_srq.c new file mode 100644 index 00000000..97802408 --- /dev/null +++ b/branches/WOF2-3/core/al/al_srq.c @@ -0,0 +1,439 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: al_qp.c 1611 2006-08-20 14:48:55Z leonid $ + */ + +#include +#include +#include + +#include "al.h" +#include "al_ca.h" +#include "al_debug.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "al_srq.tmh" +#endif +#include "al_mgr.h" +#include "al_mr.h" +#include "al_pd.h" +#include "al_srq.h" +#include "al_verbs.h" + +#include "ib_common.h" + +/* + * Function prototypes. + */ +void +destroying_srq( + IN struct _al_obj *p_obj ); + +void +cleanup_srq( + IN al_obj_t *p_obj ); + +void +free_srq( + IN al_obj_t *p_obj ); + + +ib_destroy_srq( + IN const ib_srq_handle_t h_srq, + IN const ib_pfn_destroy_cb_t pfn_destroy_cb OPTIONAL ) +{ + AL_ENTER( AL_DBG_SRQ ); + + if( AL_OBJ_INVALID_HANDLE( h_srq, AL_OBJ_TYPE_H_SRQ ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_SRQ_HANDLE\n") ); + return IB_INVALID_SRQ_HANDLE; + } + + /* Don't destroy while there are bound QPs. */ + cl_spinlock_acquire( &h_srq->obj.lock ); + if (!cl_is_qlist_empty( &h_srq->qp_list )) + { + cl_spinlock_release( &h_srq->obj.lock ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_RESOURCE_BUSY\n") ); + return IB_RESOURCE_BUSY; + } + cl_spinlock_release( &h_srq->obj.lock ); + + ref_al_obj( &h_srq->obj ); + h_srq->obj.pfn_destroy( &h_srq->obj, pfn_destroy_cb ); + + AL_EXIT( AL_DBG_SRQ ); + return IB_SUCCESS; +} + + +void +destroying_srq( + IN struct _al_obj *p_obj ) +{ + ib_srq_handle_t h_srq; + cl_list_item_t *p_item; + cl_obj_rel_t *p_rel; + ib_qp_handle_t h_qp; + + CL_ASSERT( p_obj ); + h_srq = PARENT_STRUCT( p_obj, ib_srq_t, obj ); + + /* Initiate destruction of all bound QPs. */ + cl_spinlock_acquire( &h_srq->obj.lock ); + for( p_item = cl_qlist_remove_tail( &h_srq->qp_list ); + p_item != cl_qlist_end( &h_srq->qp_list ); + p_item = cl_qlist_remove_tail( &h_srq->qp_list ) ) + { + p_rel = PARENT_STRUCT( p_item, cl_obj_rel_t, pool_item.list_item ); + p_rel->p_parent_obj = NULL; + h_qp = (ib_qp_handle_t)p_rel->p_child_obj; + if( h_qp ) + { + /* Take a reference to prevent the QP from being destroyed. */ + ref_al_obj( &h_qp->obj ); + cl_spinlock_release( &h_srq->obj.lock ); + h_qp->obj.pfn_destroy( &h_qp->obj, NULL ); + cl_spinlock_acquire( &h_srq->obj.lock ); + } + } + cl_spinlock_release( &h_srq->obj.lock ); +} + +void +cleanup_srq( + IN struct _al_obj *p_obj ) +{ + ib_srq_handle_t h_srq; + ib_api_status_t status; + + CL_ASSERT( p_obj ); + h_srq = PARENT_STRUCT( p_obj, ib_srq_t, obj ); + + /* Deallocate the CI srq. */ + if( verbs_check_srq( h_srq ) ) + { + status = verbs_destroy_srq( h_srq ); + CL_ASSERT( status == IB_SUCCESS ); + } +} + + +/* + * Release all resources associated with the completion queue. + */ +void +free_srq( + IN al_obj_t *p_obj ) +{ + ib_srq_handle_t h_srq; + + CL_ASSERT( p_obj ); + h_srq = PARENT_STRUCT( p_obj, ib_srq_t, obj ); + + destroy_al_obj( &h_srq->obj ); + cl_free( h_srq ); +} + + +void +srq_attach_qp( + IN const ib_srq_handle_t h_srq, + IN cl_obj_rel_t* const p_qp_rel ) +{ + p_qp_rel->p_parent_obj = (cl_obj_t*)h_srq; + ref_al_obj( &h_srq->obj ); + cl_spinlock_acquire( &h_srq->obj.lock ); + cl_qlist_insert_tail( &h_srq->qp_list, &p_qp_rel->pool_item.list_item ); + cl_spinlock_release( &h_srq->obj.lock ); +} + + +void +srq_detach_qp( + IN const ib_srq_handle_t h_srq, + IN cl_obj_rel_t* const p_qp_rel ) +{ + if( p_qp_rel->p_parent_obj ) + { + CL_ASSERT( p_qp_rel->p_parent_obj == (cl_obj_t*)h_srq ); + p_qp_rel->p_parent_obj = NULL; + cl_spinlock_acquire( &h_srq->obj.lock ); + cl_qlist_remove_item( &h_srq->qp_list, &p_qp_rel->pool_item.list_item ); + cl_spinlock_release( &h_srq->obj.lock ); + } +} + + +ib_api_status_t +ib_modify_srq( + IN const ib_srq_handle_t h_srq, + IN const ib_srq_attr_t* const p_srq_attr, + IN const ib_srq_attr_mask_t srq_attr_mask ) +{ + return modify_srq( h_srq, p_srq_attr, srq_attr_mask, NULL ); +} + + +ib_api_status_t +modify_srq( + IN const ib_srq_handle_t h_srq, + IN const ib_srq_attr_t* const p_srq_attr, + IN const ib_srq_attr_mask_t srq_attr_mask, + IN OUT ci_umv_buf_t* const p_umv_buf ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_SRQ ); + + if( AL_OBJ_INVALID_HANDLE( h_srq, AL_OBJ_TYPE_H_SRQ ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_SRQ_HANDLE\n") ); + return IB_INVALID_SRQ_HANDLE; + } + + if( !p_srq_attr ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + if( !( srq_attr_mask & (IB_SRQ_MAX_WR |IB_SRQ_LIMIT)) || + ( srq_attr_mask & ~(IB_SRQ_MAX_WR |IB_SRQ_LIMIT))) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_SETTING; + } + + if((srq_attr_mask & IB_SRQ_LIMIT) && h_srq->obj.p_ci_ca && h_srq->obj.p_ci_ca->p_pnp_attr ) + { + if (p_srq_attr->srq_limit > h_srq->obj.p_ci_ca->p_pnp_attr->max_srq_wrs) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_SETTING\n") ); + return IB_INVALID_SETTING; + } + } + + if((srq_attr_mask & IB_SRQ_MAX_WR) && !p_srq_attr->max_wr) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_SETTING\n") ); + return IB_INVALID_SETTING; + } + + if ((srq_attr_mask & IB_SRQ_MAX_WR) && h_srq->obj.p_ci_ca && h_srq->obj.p_ci_ca->p_pnp_attr) + { + if (p_srq_attr->max_wr > h_srq->obj.p_ci_ca->p_pnp_attr->max_srq_wrs) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_MAX_WRS\n") ); + return IB_INVALID_MAX_WRS; + } + } + + status = verbs_modify_srq( h_srq, p_srq_attr, srq_attr_mask ); + + AL_EXIT( AL_DBG_SRQ ); + return status; +} + + + +ib_api_status_t +ib_query_srq( + IN const ib_srq_handle_t h_srq, + OUT ib_srq_attr_t* const p_srq_attr ) +{ + return query_srq( h_srq, p_srq_attr, NULL ); +} + + + +ib_api_status_t +query_srq( + IN const ib_srq_handle_t h_srq, + OUT ib_srq_attr_t* const p_srq_attr, + IN OUT ci_umv_buf_t* const p_umv_buf ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_SRQ ); + + if( AL_OBJ_INVALID_HANDLE( h_srq, AL_OBJ_TYPE_H_SRQ ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_SRQ_HANDLE\n") ); + return IB_INVALID_SRQ_HANDLE; + } + if( !p_srq_attr ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + status = verbs_query_srq( h_srq, p_srq_attr ); + + AL_EXIT( AL_DBG_SRQ ); + return status; +} + + +/* + * Initializes the QP information structure. + */ +ib_api_status_t +create_srq( + IN const ib_pd_handle_t h_pd, + IN const ib_srq_attr_t* const p_srq_attr, + IN const void* const srq_context, + IN const ib_pfn_event_cb_t pfn_srq_event_cb, + OUT ib_srq_handle_t* const ph_srq, + IN OUT ci_umv_buf_t* const p_umv_buf ) +{ + ib_srq_handle_t h_srq; + ib_api_status_t status; + al_obj_type_t obj_type = AL_OBJ_TYPE_H_SRQ; + + h_srq = cl_zalloc( sizeof( ib_srq_t ) ); + if( !h_srq ) + { + return IB_INSUFFICIENT_MEMORY; + } + + if( p_umv_buf ) + obj_type |= AL_OBJ_SUBTYPE_UM_EXPORT; + + /* Construct the SRQ. */ + construct_al_obj( &h_srq->obj, obj_type ); + + cl_qlist_init( &h_srq->qp_list ); + h_srq->pfn_event_cb = pfn_srq_event_cb; + + /* Initialize the SRQ. */ + status = init_al_obj( &h_srq->obj, srq_context, TRUE, + destroying_srq, cleanup_srq, free_srq ); + if( status != IB_SUCCESS ) + { + free_srq( &h_srq->obj ); + return status; + } + status = attach_al_obj( &h_pd->obj, &h_srq->obj ); + if( status != IB_SUCCESS ) + { + h_srq->obj.pfn_destroy( &h_srq->obj, NULL ); + return status; + } + + status = verbs_create_srq( h_pd, h_srq, p_srq_attr, p_umv_buf ); + if( status != IB_SUCCESS ) + { + h_srq->obj.pfn_destroy( &h_srq->obj, NULL ); + return status; + } + + *ph_srq = h_srq; + + /* + * Note that we don't release the reference taken in init_al_obj here. + * For kernel clients, it is release in ib_create_srq. For user-mode + * clients is released by the proxy after the handle is extracted. + */ + return IB_SUCCESS; +} + + +/* + * Process an asynchronous event on the QP. Notify the user of the event. + */ +void +srq_async_event_cb( + IN ib_async_event_rec_t* const p_event_rec ) +{ + ib_srq_handle_t h_srq; + + CL_ASSERT( p_event_rec ); + h_srq = (ib_srq_handle_t)p_event_rec->context; + +#if defined(CL_KERNEL) + switch( p_event_rec->code ) + { + case IB_AE_SRQ_LIMIT_REACHED: + AL_PRINT_EXIT( TRACE_LEVEL_WARNING, AL_DBG_SRQ, + ("IB_AE_SRQ_LIMIT_REACHED for srq %p \n", h_srq) ); + //TODO: handle this error. + break; + case IB_AE_SRQ_CATAS_ERROR: + AL_PRINT_EXIT( TRACE_LEVEL_WARNING, AL_DBG_SRQ, + ("IB_AE_SRQ_CATAS_ERROR for srq %p \n", h_srq) ); + //TODO: handle this error. + break; + default: + break; + } +#endif + + p_event_rec->context = (void*)h_srq->obj.context; + p_event_rec->handle.h_srq = h_srq; + + if( h_srq->pfn_event_cb ) + h_srq->pfn_event_cb( p_event_rec ); +} + +ib_api_status_t +ib_post_srq_recv( + IN const ib_srq_handle_t h_srq, + IN ib_recv_wr_t* const p_recv_wr, + OUT ib_recv_wr_t **pp_recv_failure OPTIONAL ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_SRQ ); + + if( AL_OBJ_INVALID_HANDLE( h_srq, AL_OBJ_TYPE_H_SRQ ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_SRQ_HANDLE\n") ); + return IB_INVALID_QP_HANDLE; + } + if( !p_recv_wr || ( p_recv_wr->p_next && !pp_recv_failure ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + status = + h_srq->pfn_post_srq_recv( h_srq->h_recv_srq, p_recv_wr, pp_recv_failure ); + + AL_EXIT( AL_DBG_SRQ ); + return status; +} + + + diff --git a/branches/WOF2-3/core/al/al_srq.h b/branches/WOF2-3/core/al/al_srq.h new file mode 100644 index 00000000..1c50176a --- /dev/null +++ b/branches/WOF2-3/core/al/al_srq.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: al_srq.h 1611 2006-08-20 14:48:55Z leonid $ + */ + +#if !defined(__AL_SRQ_H__) +#define __AL_SRQ_H__ + +#include +#include +#include +#include + +#include "al_ca.h" +#include "al_common.h" + + +typedef ib_api_status_t +(*ib_pfn_post_srq_recv_t)( + IN const ib_srq_handle_t h_srq, + IN ib_recv_wr_t* const p_recv_wr, + IN ib_recv_wr_t **p_recv_failure OPTIONAL ); + + +/* + * Shared queue pair information required by the access layer. This structure + * is referenced by a user's SRQ handle. + */ +typedef struct _ib_srq +{ + al_obj_t obj; /* Must be first. */ + + ib_srq_handle_t h_ci_srq; /* kernel SRQ handle */ + ib_pfn_post_srq_recv_t pfn_post_srq_recv; /* post_srq_recv call */ + ib_srq_handle_t h_recv_srq; /* srq handle for the post_srq_recv call */ + ib_pfn_event_cb_t pfn_event_cb; /* user async event handler */ + cl_qlist_t qp_list; /* List of QPs bound to this CQ. */ + +} ib_srq_t; + +ib_api_status_t +create_srq( + IN const ib_pd_handle_t h_pd, + IN const ib_srq_attr_t* const p_srq_attr, + IN const void* const srq_context, + IN const ib_pfn_event_cb_t pfn_srq_event_cb, + OUT ib_srq_handle_t* const ph_srq, + IN OUT ci_umv_buf_t* const p_umv_buf ); + + +ib_api_status_t +query_srq( + IN const ib_srq_handle_t h_srq, + OUT ib_srq_attr_t* const p_srq_attr, + IN OUT ci_umv_buf_t* const p_umv_buf ); + + +ib_api_status_t +modify_srq( + IN const ib_srq_handle_t h_srq, + IN const ib_srq_attr_t* const p_srq_attr, + IN const ib_srq_attr_mask_t srq_attr_mask, + IN OUT ci_umv_buf_t* const p_umv_buf ); + + +void +srq_async_event_cb( + IN ib_async_event_rec_t* const p_event_rec ); + +void +srq_attach_qp( + IN const ib_srq_handle_t h_srq, + IN cl_obj_rel_t* const p_qp_rel ); + +void +srq_detach_qp( + IN const ib_srq_handle_t h_srq, + IN cl_obj_rel_t* const p_qp_rel ); + +#endif /* __AL_QP_H__ */ + diff --git a/branches/WOF2-3/core/al/al_sub.c b/branches/WOF2-3/core/al/al_sub.c new file mode 100644 index 00000000..664e833b --- /dev/null +++ b/branches/WOF2-3/core/al/al_sub.c @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include + +#include "al.h" +#include "al_common.h" +#include "al_debug.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "al_sub.tmh" +#endif + + +ib_api_status_t +ib_subscribe( + IN const ib_al_handle_t h_al, + IN const ib_sub_req_t* const p_sub_req, + OUT ib_sub_handle_t* const ph_sub ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_SUB ); + + if( AL_OBJ_INVALID_HANDLE( h_al, AL_OBJ_TYPE_H_AL ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_AL_HANDLE\n") ); + return IB_INVALID_AL_HANDLE; + } + if( !p_sub_req || !ph_sub ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + status = IB_UNSUPPORTED; + + AL_EXIT( AL_DBG_SUB ); + return status; +} + + +ib_api_status_t +ib_unsubscribe( + IN const ib_sub_handle_t h_sub, + IN const ib_pfn_destroy_cb_t pfn_destroy_cb OPTIONAL ) +{ + AL_ENTER( AL_DBG_SUB ); + + if( !h_sub ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_HANDLE\n") ); + return IB_INVALID_HANDLE; + } + + UNUSED_PARAM( pfn_destroy_cb ); + + AL_EXIT( AL_DBG_SUB ); + return IB_UNSUPPORTED; +} diff --git a/branches/WOF2-3/core/al/al_verbs.h b/branches/WOF2-3/core/al/al_verbs.h new file mode 100644 index 00000000..98c1e677 --- /dev/null +++ b/branches/WOF2-3/core/al/al_verbs.h @@ -0,0 +1,645 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#if !defined(__AL_VERBS_H__) +#define __AL_VERBS_H__ + +#include "al_ca.h" +#include "al_cq.h" +#include "al_pd.h" +#include "al_qp.h" +#include "al_srq.h" + +#ifndef CL_KERNEL +#include "ual_mad.h" +#include "ual_qp.h" +#include "ual_mcast.h" +#endif + +#ifdef CL_KERNEL + + /* Macros for kernel-mode only */ +#define verbs_create_av(h_pd, p_av_attr, h_av) \ + h_av->obj.p_ci_ca->verbs.create_av( h_pd->h_ci_pd,\ + p_av_attr, &h_av->h_ci_av, p_umv_buf ) + +#define verbs_check_av(h_av) ((h_av)->h_ci_av) +#define convert_av_handle(h_qp, h_av) ((h_av)->h_ci_av) +#define verbs_destroy_av(h_av) \ + h_av->obj.p_ci_ca->verbs.destroy_av( h_av->h_ci_av ) + +#define verbs_query_av(h_av, p_av_attr, ph_pd) \ + h_av->obj.p_ci_ca->verbs.query_av( h_av->h_ci_av,\ + p_av_attr, ph_pd, p_umv_buf ) + +#define verbs_modify_av(h_av, p_av_mod) \ + h_av->obj.p_ci_ca->verbs.modify_av( h_av->h_ci_av, p_av_mod, p_umv_buf ) + +#define verbs_query_ca(h_ca, p_ca_attr, p_size) \ + h_ca->obj.p_ci_ca->verbs.query_ca( h_ca->obj.p_ci_ca->h_ci_ca,\ + p_ca_attr, p_size, p_umv_buf ) + +#define verbs_modify_ca(h_ca, port_num, ca_mod, p_port_attr_mod) \ + h_ca->obj.p_ci_ca->verbs.modify_ca( h_ca->obj.p_ci_ca->h_ci_ca,\ + port_num, ca_mod, p_port_attr_mod ) + +void ci_ca_comp_cb(void *cq_context); +void ci_ca_async_event_cb(ib_event_rec_t* p_event_record); + +static inline ib_api_status_t +verbs_create_cq( + IN const ib_ca_handle_t h_ca, + IN OUT ib_cq_create_t* const p_cq_create, + IN ib_cq_handle_t h_cq, + IN OUT ci_umv_buf_t* const p_umv_buf ) +{ + return h_ca->obj.p_ci_ca->verbs.create_cq( + (p_umv_buf) ? h_ca->h_um_ca : h_ca->obj.p_ci_ca->h_ci_ca, + h_cq, ci_ca_async_event_cb, ci_ca_comp_cb, &p_cq_create->size, + &h_cq->h_ci_cq, p_umv_buf ); +} + +#define verbs_check_cq(h_cq) ((h_cq)->h_ci_cq) +#define verbs_destroy_cq(h_cq) \ + h_cq->obj.p_ci_ca->verbs.destroy_cq( h_cq->h_ci_cq ) + +#define verbs_modify_cq(h_cq, p_size) \ + h_cq->obj.p_ci_ca->verbs.resize_cq( h_cq->h_ci_cq, p_size, p_umv_buf ) + +#define verbs_query_cq(h_cq, p_size) \ + h_cq->obj.p_ci_ca->verbs.query_cq( h_cq->h_ci_cq, p_size, p_umv_buf ) + +#define verbs_peek_cq(h_cq, p_n_cqes) \ + ( ( h_cq->obj.p_ci_ca->verbs.peek_cq ) ? \ + h_cq->obj.p_ci_ca->verbs.peek_cq( h_cq->h_ci_cq, p_n_cqes) : \ + IB_UNSUPPORTED ) + +#define verbs_poll_cq(h_cq, pp_free_wclist, pp_done_wclist) \ + h_cq->obj.p_ci_ca->verbs.poll_cq( h_cq->h_ci_cq,\ + pp_free_wclist, pp_done_wclist ) + +#define verbs_rearm_cq(h_cq, solicited) \ + h_cq->obj.p_ci_ca->verbs.enable_cq_notify( h_cq->h_ci_cq,\ + solicited ) + +#define verbs_rearm_n_cq(h_cq, n_cqes) \ + ( ( h_cq->obj.p_ci_ca->verbs.enable_ncomp_cq_notify ) ? \ + h_cq->obj.p_ci_ca->verbs.enable_ncomp_cq_notify(h_cq->h_ci_cq,n_cqes): \ + IB_UNSUPPORTED ) + +#define verbs_register_mr(h_pd, p_mr_create, p_lkey, p_rkey, h_mr) \ + h_mr->obj.p_ci_ca->verbs.register_mr( h_pd->h_ci_pd,\ + p_mr_create, p_lkey, p_rkey, &h_mr->h_ci_mr, um_call ) + +#define verbs_register_pmr(h_pd, p_phys_create, p_vaddr,\ + p_lkey, p_rkey, h_mr) \ + h_mr->obj.p_ci_ca->verbs.register_pmr( h_pd->h_ci_pd,\ + p_phys_create, p_vaddr, p_lkey, p_rkey, &h_mr->h_ci_mr, FALSE ) + +#define verbs_check_mr(h_mr) ((h_mr)->h_ci_mr) +#define verbs_check_mlnx_fmr(h_fmr) ((h_fmr)->h_ci_fmr) +#define verbs_deregister_mr(h_mr) \ + h_mr->obj.p_ci_ca->verbs.deregister_mr( h_mr->h_ci_mr ) + +/* + * Remove this registration from the shmid's list to prevent any + * new registrations from accessing it once it is deregistered. + */ +#define verbs_release_shmid(h_mr) \ + if( h_mr->p_shmid ) \ + { \ + cl_spinlock_acquire( &h_mr->p_shmid->obj.lock ); \ + cl_list_remove_object( &h_mr->p_shmid->mr_list, h_mr ); \ + cl_spinlock_release( &h_mr->p_shmid->obj.lock ); \ + release_shmid( h_mr->p_shmid ); \ + h_mr->p_shmid = NULL; \ + } +#define verbs_query_mr(h_mr, p_mr_attr) \ + h_mr->obj.p_ci_ca->verbs.query_mr( h_mr->h_ci_mr, p_mr_attr ) + +#define verbs_modify_mr(h_mr, mr_modify_mask, p_mr_create, \ + p_lkey, p_rkey, h_pd ) \ + h_mr->obj.p_ci_ca->verbs.modify_mr( h_mr->h_ci_mr, mr_modify_mask, \ + p_mr_create, p_lkey, p_rkey, h_pd ? h_pd->h_ci_pd : NULL, \ + um_call ) + +#define verbs_modify_pmr(h_mr, mr_modify_mask, p_pmr_create, \ + p_vaddr, p_lkey, p_rkey, h_pd ) \ + h_mr->obj.p_ci_ca->verbs.modify_pmr( h_mr->h_ci_mr, mr_modify_mask, \ + p_pmr_create, p_vaddr, p_lkey, p_rkey, \ + h_pd ? h_pd->h_ci_pd : NULL, FALSE ) + +#define verbs_register_smr(h_mr, h_pd, access_ctrl, p_vaddr, p_lkey, \ + p_rkey, ph_mr ) \ + h_mr->obj.p_ci_ca->verbs.register_smr( h_mr->h_ci_mr, h_pd->h_ci_pd,\ + access_ctrl, p_vaddr, p_lkey, p_rkey, &(ph_mr->h_ci_mr), \ + um_call ) + +#define verbs_create_mlnx_fmr(h_pd, p_fmr_create, h_fmr ) \ + h_fmr->obj.p_ci_ca->verbs.alloc_mlnx_fmr( h_pd->h_ci_pd,\ + p_fmr_create, &h_fmr->h_ci_fmr ) + +#define verbs_map_phys_mlnx_fmr( h_fmr, plist_addr, list_len, p_vaddr, p_lkey, p_rkey) \ + h_fmr->obj.p_ci_ca->verbs.map_phys_mlnx_fmr( h_fmr->h_ci_fmr,\ + plist_addr, list_len, p_vaddr, p_lkey, p_rkey ) + +#define verbs_unmap_mlnx_fmr( h_fmr, p_fmr_array ) \ + h_fmr->obj.p_ci_ca->verbs.unmap_mlnx_fmr( p_fmr_array) + +#define verbs_destroy_mlnx_fmr( h_fmr ) \ + h_fmr->obj.p_ci_ca->verbs.dealloc_mlnx_fmr( h_fmr->h_ci_fmr ) + + +#define verbs_create_mw(h_pd, p_rkey, h_mw) \ + h_mw->obj.p_ci_ca->verbs.create_mw( h_pd->h_ci_pd,\ + p_rkey, &h_mw->h_ci_mw, p_umv_buf ) + +#define verbs_check_mw(h_mw) ((h_mw)->h_ci_mw) +#define verbs_destroy_mw(h_mw) \ + h_mw->obj.p_ci_ca->verbs.destroy_mw( h_mw->h_ci_mw ) + +#define verbs_query_mw(h_mw, ph_pd, p_rkey) \ + h_mw->obj.p_ci_ca->verbs.query_mw(\ + h_mw->h_ci_mw, ph_pd, p_rkey, p_umv_buf ) + +#define convert_mr_handle(h_mr) ((h_mr)->h_ci_mr) + +#define verbs_bind_mw(h_mw, h_qp, p_mw_bind, p_rkey) \ + h_qp->obj.p_ci_ca->verbs.bind_mw( h_mw->h_ci_mw,\ + h_qp->h_ci_qp, p_mw_bind, p_rkey ) + +static inline ib_api_status_t +verbs_allocate_pd( + IN const ib_ca_handle_t h_ca, + IN ib_pd_handle_t h_pd, + IN OUT ci_umv_buf_t* const p_umv_buf ) +{ + return h_ca->obj.p_ci_ca->verbs.allocate_pd( + (p_umv_buf) ? h_ca->h_um_ca : h_ca->obj.p_ci_ca->h_ci_ca, + h_pd->type, &h_pd->h_ci_pd, p_umv_buf ); +} + +/* + * Reference the hardware PD. + */ +static inline ib_api_status_t +allocate_pd_alias( + IN const ib_ca_handle_t h_ca, + IN const ib_pd_handle_t h_pd ) +{ + UNUSED_PARAM( h_ca ); + h_pd->h_ci_pd = h_pd->obj.p_ci_ca->h_pd->h_ci_pd; + ref_al_obj( &h_pd->obj.p_ci_ca->h_pd->obj ); + return IB_SUCCESS; +} + +static inline void +deallocate_pd_alias( + IN const ib_pd_handle_t h_pd ) +{ + deref_al_obj( &h_pd->obj.p_ci_ca->h_pd->obj ); +} + + + +#define verbs_check_pd(h_pd) ((h_pd)->h_ci_pd) +#define verbs_deallocate_pd(h_pd) \ + h_pd->obj.p_ci_ca->verbs.deallocate_pd( h_pd->h_ci_pd ) + +static inline ib_api_status_t +verbs_create_srq( + IN const ib_pd_handle_t h_pd, + IN ib_srq_handle_t h_srq, + IN const ib_srq_attr_t* const p_srq_attr, + IN OUT ci_umv_buf_t* const p_umv_buf ) +{ + ib_api_status_t status; + + status = h_srq->obj.p_ci_ca->verbs.create_srq( + h_pd->h_ci_pd, h_srq, ci_ca_async_event_cb, p_srq_attr, + &h_srq->h_ci_srq, p_umv_buf ); + + h_srq->h_recv_srq = h_srq->h_ci_srq; + h_srq->pfn_post_srq_recv = h_srq->obj.p_ci_ca->verbs.post_srq_recv; + return status; +} + +#define verbs_check_srq(h_srq) ((h_srq)->h_ci_srq) + +#define verbs_destroy_srq(h_srq) \ + h_srq->obj.p_ci_ca->verbs.destroy_srq( h_srq->h_ci_srq ) + +#define verbs_query_srq(h_srq, p_srq_attr) \ + h_srq->obj.p_ci_ca->verbs.query_srq( h_srq->h_ci_srq,\ + p_srq_attr, p_umv_buf ) + +#define verbs_modify_srq(h_srq, p_srq_attr, srq_attr_mask) \ + h_srq->obj.p_ci_ca->verbs.modify_srq( h_srq->h_ci_srq,\ + p_srq_attr, srq_attr_mask, p_umv_buf ) + +#define verbs_post_srq_recv(h_srq, p_recv_wr, pp_recv_failure) \ + h_srq->obj.p_ci_ca->verbs.post_srq_recv( h_srq->h_ci_srq,\ + p_recv_wr, pp_recv_failure ) + +#define convert_qp_handle( qp_create ) {\ + CL_ASSERT( qp_create.h_rq_cq ); \ + qp_create.h_rq_cq = qp_create.h_rq_cq->h_ci_cq; \ + CL_ASSERT( qp_create.h_sq_cq ); \ + qp_create.h_sq_cq = qp_create.h_sq_cq->h_ci_cq; \ + if (qp_create.h_srq) \ + qp_create.h_srq = qp_create.h_srq->h_ci_srq; \ +} + +static inline ib_api_status_t +verbs_get_spl_qp( + IN ib_pd_handle_t h_pd, + IN uint8_t port_num, + IN ib_qp_handle_t h_qp, + IN ib_qp_create_t *p_qp_create, + IN ib_qp_attr_t *p_qp_attr ) +{ + ib_api_status_t status; + + status = h_qp->obj.p_ci_ca->verbs.create_spl_qp( + h_pd->h_ci_pd, port_num, h_qp, ci_ca_async_event_cb, p_qp_create, + p_qp_attr, &h_qp->h_ci_qp ); + + h_qp->h_recv_qp = h_qp->h_ci_qp; + h_qp->h_send_qp = h_qp->h_ci_qp; + + h_qp->pfn_post_send = h_qp->obj.p_ci_ca->verbs.post_send; + h_qp->pfn_post_recv = h_qp->obj.p_ci_ca->verbs.post_recv; + return status; +} + + +static inline ib_api_status_t +verbs_create_qp( + IN ib_pd_handle_t h_pd, + IN ib_qp_handle_t h_qp, + IN ib_qp_create_t *p_qp_create, + IN ib_qp_attr_t *p_qp_attr, + IN OUT ci_umv_buf_t* const p_umv_buf ) +{ + ib_api_status_t status; + + status = h_qp->obj.p_ci_ca->verbs.create_qp( + h_pd->h_ci_pd, h_qp, ci_ca_async_event_cb, p_qp_create, p_qp_attr, + &h_qp->h_ci_qp, p_umv_buf ); + + h_qp->h_recv_qp = h_qp->h_ci_qp; + h_qp->h_send_qp = h_qp->h_ci_qp; + + h_qp->pfn_post_send = h_qp->obj.p_ci_ca->verbs.post_send; + h_qp->pfn_post_recv = h_qp->obj.p_ci_ca->verbs.post_recv; + return status; +} + +#define verbs_check_qp(h_qp) ((h_qp)->h_ci_qp) +#define verbs_destroy_qp(h_qp) \ + h_qp->obj.p_ci_ca->verbs.destroy_qp( h_qp->h_ci_qp, h_qp->timewait ) + +#define verbs_query_qp(h_qp, p_qp_attr) \ + h_qp->obj.p_ci_ca->verbs.query_qp( h_qp->h_ci_qp,\ + p_qp_attr, p_umv_buf ) + +#define verbs_modify_qp(h_qp, p_qp_mod, p_qp_attr) \ + h_qp->obj.p_ci_ca->verbs.modify_qp( h_qp->h_ci_qp,\ + p_qp_mod, p_qp_attr, p_umv_buf ) + +#define verbs_ndi_modify_qp(h_qp, p_qp_mod, qp_attr, buf_size, p_buf) \ + h_qp->obj.p_ci_ca->verbs.ndi_modify_qp( h_qp->h_ci_qp,\ + p_qp_mod, &qp_attr, buf_size, p_buf ) + +#define verbs_post_send(h_qp, p_send_wr, pp_send_failure) \ + h_qp->obj.p_ci_ca->verbs.post_send( h_qp->h_ci_qp,\ + p_send_wr, pp_send_failure ) + +#define verbs_post_recv(h_qp, p_recv_wr, pp_recv_failure) \ + h_qp->obj.p_ci_ca->verbs.post_recv( h_qp->h_ci_qp,\ + p_recv_wr, pp_recv_failure ) + +#define verbs_local_mad(h_ca, port_num, p_src_av_attr, p_mad_in, p_mad_out) \ + h_ca->obj.p_ci_ca->verbs.local_mad( h_ca->obj.p_ci_ca->h_ci_ca,\ + port_num, p_src_av_attr, p_mad_in, p_mad_out) + +#define check_local_mad(h_qp) \ + (h_qp->obj.p_ci_ca->verbs.local_mad) + +#define init_alias_qp( h_qp, h_pd, port_guid, p_qp_create ) \ + init_qp_alias( h_qp, h_pd, port_guid, p_qp_create ) + +#define spl_qp_mad_send( h_mad_svc, p_mad_element_list, pp_mad_failure ) \ + IB_ERROR + +#define spl_qp_cancel_mad( h_mad_svc, h_mad_send ) \ + IB_ERROR + +#define create_reg_mad_pool( h_pool, h_pd, p_pool_key ) \ + IB_SUCCESS + +#define dereg_destroy_mad_pool( pool_key ) + +#define verbs_attach_mcast(h_mcast) \ + h_mcast->obj.p_ci_ca->verbs.attach_mcast( \ + ((ib_qp_handle_t)h_mcast->obj.p_parent_obj)->h_ci_qp, &h_mcast->member_rec.mgid, \ + h_mcast->member_rec.mlid, &h_mcast->h_ci_mcast, \ + NULL) + +#define verbs_detach_mcast(h_mcast) \ + h_mcast->obj.p_ci_ca->verbs.detach_mcast( \ + h_mcast->h_ci_mcast ) + +static inline ib_api_status_t +verbs_ci_call( + IN ib_ca_handle_t h_ca, + IN const void** const handle_array OPTIONAL, + IN uint32_t num_handles, + IN ib_ci_op_t* const p_ci_op, + IN ci_umv_buf_t* const p_umv_buf OPTIONAL ) +{ + return h_ca->obj.p_ci_ca->verbs.vendor_call( + p_umv_buf ? h_ca->h_um_ca : h_ca->obj.p_ci_ca->h_ci_ca, + handle_array, num_handles, p_ci_op, p_umv_buf ); +} + + +#else + + + + /* Macros for user-mode only */ +#define verbs_create_av(h_pd, p_av_attr, h_av) \ + (h_pd->type == IB_PDT_ALIAS) ?\ + ual_pd_alias_create_av(h_pd, p_av_attr, h_av):\ + ual_create_av(h_pd, p_av_attr, h_av); \ + UNUSED_PARAM( p_umv_buf ) + +#define verbs_check_av(h_av) ((h_av)->h_ci_av || (h_av)->obj.hdl) +#define convert_av_handle(h_qp, h_av) \ + ((h_qp)->h_ci_qp?(h_av)->h_ci_av:(ib_av_handle_t)(ULONG_PTR)(h_av)->obj.hdl) +#define verbs_destroy_av(h_av) \ + ual_destroy_av(h_av) + +#define verbs_query_av(h_av, p_av_attr, ph_pd) \ + ual_query_av(h_av, p_av_attr, ph_pd); \ + UNUSED_PARAM( p_umv_buf ) + +#define verbs_modify_av(h_av, p_av_mod) \ + ual_modify_av(h_av, p_av_mod); \ + UNUSED_PARAM( p_umv_buf ) + +#define verbs_query_ca(h_ca, p_ca_attr, p_size) \ + ual_query_ca(h_ca, p_ca_attr, p_size); \ + UNUSED_PARAM( p_umv_buf ) + +#define verbs_modify_ca(h_ca, port_num, ca_mod, p_port_attr_mod) \ + ual_modify_ca(h_ca, port_num, ca_mod, p_port_attr_mod) + +static inline ib_api_status_t +verbs_create_cq( + IN const ib_ca_handle_t h_ca, + IN OUT ib_cq_create_t* const p_cq_create, + IN ib_cq_handle_t h_cq, + IN OUT ci_umv_buf_t* const p_umv_buf ) +{ + UNUSED_PARAM( p_umv_buf ); + return ual_create_cq( h_ca->obj.p_ci_ca, p_cq_create, h_cq ); +} + + +#define verbs_check_cq(h_cq) ((h_cq)->h_ci_cq || (h_cq)->obj.hdl) +#define verbs_destroy_cq(h_cq) \ + ual_destroy_cq(h_cq) + +#define verbs_modify_cq(h_cq, p_size) \ + ual_modify_cq(h_cq, p_size); \ + UNUSED_PARAM( p_umv_buf ) + +#define verbs_query_cq(h_cq, p_size) \ + ual_query_cq(h_cq, p_size); \ + UNUSED_PARAM( p_umv_buf ) + +#define verbs_peek_cq(h_cq, p_n_cqes) \ + h_cq->pfn_peek( h_cq->h_peek_cq, p_n_cqes ) + +#define verbs_poll_cq(h_cq, pp_free_wclist, pp_done_wclist) \ + h_cq->pfn_poll( h_cq->h_poll_cq, pp_free_wclist, pp_done_wclist ) + +#define verbs_rearm_cq(h_cq, solicited) \ + h_cq->pfn_rearm( h_cq->h_rearm_cq, solicited ) + +#define verbs_rearm_n_cq(h_cq, n_cqes) \ + h_cq->pfn_rearm_n( h_cq->h_rearm_n_cq, n_cqes ) + +#define verbs_register_mr(h_pd, p_mr_create, p_lkey, p_rkey, h_mr) \ + ual_reg_mem(h_pd, p_mr_create, p_lkey, p_rkey, h_mr); \ + UNUSED_PARAM( um_call ) + +#define verbs_register_pmr(h_pd, p_phys_create, p_vaddr, p_lkey, p_rkey, h_mr) \ + IB_UNSUPPORTED; \ + UNUSED_PARAM( h_pd ); \ + UNUSED_PARAM( p_phys_create ); \ + UNUSED_PARAM( p_vaddr ); \ + UNUSED_PARAM( p_lkey ); \ + UNUSED_PARAM( p_rkey ); \ + UNUSED_PARAM( h_mr ) + +#define verbs_check_mr(h_mr) ((h_mr)->h_ci_mr || (h_mr)->obj.hdl) +#define verbs_deregister_mr(h_mr) \ + ual_dereg_mr(h_mr) + +/* For user-mode, this is nop */ +#define verbs_release_shmid(h_mr) + +#define verbs_query_mr(h_mr, p_mr_attr) \ + ual_query_mr(h_mr, p_mr_attr) + +#define verbs_modify_mr(h_mr, mr_modify_mask, p_mr_create, \ + p_lkey, p_rkey, h_pd ) \ + ual_modify_mr( h_mr, mr_modify_mask, p_mr_create, \ + p_lkey, p_rkey, h_pd ); \ + UNUSED_PARAM( um_call ) + +#define verbs_modify_pmr( h_mr, mr_mod_mask, p_phys_create, \ + p_vaddr, p_lkey, p_rkey, h_pd ) \ + IB_UNSUPPORTED; \ + UNUSED_PARAM( h_mr ); \ + UNUSED_PARAM( mr_mod_mask ); \ + UNUSED_PARAM( p_phys_create ); \ + UNUSED_PARAM( p_vaddr ); \ + UNUSED_PARAM( p_lkey ); \ + UNUSED_PARAM( p_rkey ); \ + UNUSED_PARAM( h_pd ) + +#define verbs_register_smr(h_mr, h_pd, access_ctrl, p_vaddr, p_lkey, \ + p_rkey, ph_mr ) \ + ual_reg_shared( h_mr, h_pd, access_ctrl, p_vaddr, p_lkey, \ + p_rkey, ph_mr ); \ + UNUSED_PARAM( um_call ) + +#define verbs_create_mw(h_pd, p_rkey, h_mw) \ + ual_create_mw(h_pd, p_rkey, h_mw); \ + UNUSED_PARAM( p_umv_buf ) + +#define verbs_check_mw(h_mw) ((h_mw)->h_ci_mw || (h_mw)->obj.hdl) +#define verbs_destroy_mw(h_mw) \ + ual_destroy_mw(h_mw) + +#define verbs_query_mw(h_mw, ph_pd, p_rkey) \ + ual_query_mw(h_mw, ph_pd, p_rkey); \ + UNUSED_PARAM( p_umv_buf ) + +#define convert_mr_handle(h_mr) (h_mr) + +#define verbs_bind_mw(h_mw, h_qp, p_mw_bind, p_rkey) \ + ual_bind_mw(h_mw, h_qp, p_mw_bind, p_rkey) + +static inline ib_api_status_t +verbs_allocate_pd( + IN const ib_ca_handle_t h_ca, + IN ib_pd_handle_t h_pd, + IN OUT ci_umv_buf_t* const p_umv_buf ) +{ + UNUSED_PARAM( p_umv_buf ); + return ual_allocate_pd( h_ca, h_pd->type, h_pd ); +} + +/* + * Get an alias to the kernel's hardware PD. + */ +static inline ib_api_status_t +allocate_pd_alias( + IN const ib_ca_handle_t h_ca, + IN const ib_pd_handle_t h_pd ) +{ + return ual_allocate_pd( h_ca, h_pd->type, h_pd ); +} + +#define deallocate_pd_alias( h_pd ) /* no action to take */ + +#define verbs_check_pd(h_pd) ((h_pd)->h_ci_pd || (h_pd)->obj.hdl) +#define verbs_deallocate_pd(h_pd) \ + ual_deallocate_pd(h_pd) + +#define verbs_create_srq(h_pd, h_srq, p_srq_attr, p_umv_buf) \ + ual_create_srq (h_pd, h_srq, p_srq_attr); \ + UNUSED_PARAM( p_umv_buf ) + +#define verbs_check_srq(h_srq) ((h_srq)->h_ci_srq || (h_srq)->obj.hdl) + +#define verbs_destroy_srq(h_srq) \ + ual_destroy_srq(h_srq) + +#define verbs_query_srq(h_srq, p_srq_attr) \ + ual_query_srq(h_srq, p_srq_attr); \ + UNUSED_PARAM( p_umv_buf ); + +#define verbs_modify_srq(h_srq, p_srq_attr, srq_attr_mask) \ + ual_modify_srq(h_srq, p_srq_attr, srq_attr_mask); \ + UNUSED_PARAM( p_umv_buf ); + +#define verbs_post_srq_recv(h_srq, p_recv_wr, pp_recv_failure) \ + ual_post_srq_recv(h_srq, p_recv_wr, pp_recv_failure) + + +/* For user-mode, handle conversion is done in ual files */ + +#define convert_qp_handle( qp_create ) + +/* TBD: Do we need to support this in user-mode? */ +#define verbs_get_spl_qp(h_pd, port_num, h_qp, p_qp_create, p_qp_attr) \ + IB_UNSUPPORTED + +#define verbs_create_qp(h_pd, h_qp, p_qp_create, p_qp_attr, p_umv_buf) \ + ual_create_qp (h_pd, h_qp, p_qp_create, p_qp_attr); \ + UNUSED_PARAM( p_umv_buf ) + +#define verbs_check_qp(h_qp) ((h_qp)->h_ci_qp || (h_qp)->obj.hdl) +#define verbs_destroy_qp(h_qp) \ + ual_destroy_qp(h_qp) + +#define verbs_query_qp(h_qp, p_qp_attr) \ + ual_query_qp(h_qp, p_qp_attr); \ + UNUSED_PARAM( p_umv_buf ); + +#define verbs_modify_qp(h_qp, p_qp_mod, p_qp_attr) \ + ual_modify_qp(h_qp, p_qp_mod, p_qp_attr); \ + UNUSED_PARAM( p_umv_buf ); + +#define verbs_post_send(h_qp, p_send_wr, pp_send_failure) \ + ual_post_send(h_qp, p_send_wr, pp_send_failure) + +#define verbs_post_recv(h_qp, p_recv_wr, pp_recv_failure) \ + ual_post_recv(h_qp, p_recv_wr, pp_recv_failure) + +static inline ib_api_status_t +verbs_local_mad( + IN const ib_ca_handle_t h_ca, + IN const uint8_t port_num, + IN const ib_av_attr_t* p_src_av_attr, + IN const void* const p_mad_in, + IN void* p_mad_out ) +{ + return ual_local_mad( h_ca, port_num, p_mad_in, p_mad_out ); + UNUSED_PARAM( p_src_av_attr ); +} + +#define check_local_mad(h_qp) \ + (!h_qp) + +#define init_alias_qp( h_qp, h_pd, port_guid, p_qp_create ) \ + ual_init_qp_alias( h_qp, h_pd, port_guid, p_qp_create ) + +#define spl_qp_mad_send( h_mad_svc, p_mad_element_list, pp_mad_failure ) \ + ual_spl_qp_mad_send( h_mad_svc, p_mad_element_list, pp_mad_failure ) + +#define spl_qp_cancel_mad( h_mad_svc, p_mad_element ) \ + ual_spl_qp_cancel_mad( h_mad_svc, p_mad_element ) + +#define create_reg_mad_pool( h_pool, h_pd, p_pool_key ) \ + ual_create_reg_mad_pool( h_pool, h_pd, p_pool_key ) + +#define dereg_destroy_mad_pool( pool_key ) \ + ual_dereg_destroy_mad_pool( pool_key ) + +#define verbs_attach_mcast(h_mcast) \ + ual_attach_mcast( h_mcast ) + +#define verbs_detach_mcast(h_mcast) \ + ual_detach_mcast( h_mcast ) + +#endif /* CL_KERNEL */ + + +#endif /* __AL_VERBS_H__ */ diff --git a/branches/WOF2-3/core/al/dirs b/branches/WOF2-3/core/al/dirs new file mode 100644 index 00000000..ddf0ed7d --- /dev/null +++ b/branches/WOF2-3/core/al/dirs @@ -0,0 +1,3 @@ +DIRS=\ + user \ + kernel diff --git a/branches/WOF2-3/core/al/ib_common.c b/branches/WOF2-3/core/al/ib_common.c new file mode 100644 index 00000000..9fa149ac --- /dev/null +++ b/branches/WOF2-3/core/al/ib_common.c @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include +#include "ib_common.h" + + + +ib_api_status_t +ib_convert_cl_status( + IN const cl_status_t cl_status ) +{ + switch( cl_status ) + { + case CL_SUCCESS: + return IB_SUCCESS; + case CL_INVALID_STATE: + return IB_INVALID_STATE; + case CL_INVALID_SETTING: + return IB_INVALID_SETTING; + case CL_INVALID_PARAMETER: + return IB_INVALID_PARAMETER; + case CL_INSUFFICIENT_RESOURCES: + return IB_INSUFFICIENT_RESOURCES; + case CL_INSUFFICIENT_MEMORY: + return IB_INSUFFICIENT_MEMORY; + case CL_INVALID_PERMISSION: + return IB_INVALID_PERMISSION; + case CL_COMPLETED: + return IB_SUCCESS; + case CL_INVALID_OPERATION: + return IB_UNSUPPORTED; + case CL_TIMEOUT: + return IB_TIMEOUT; + case CL_NOT_DONE: + return IB_NOT_DONE; + case CL_CANCELED: + return IB_CANCELED; + case CL_NOT_FOUND: + return IB_NOT_FOUND; + case CL_BUSY: + return IB_RESOURCE_BUSY; + case CL_PENDING: + return IB_PENDING; + case CL_OVERRUN: + return IB_OVERFLOW; + case CL_ERROR: + case CL_REJECT: + case CL_UNAVAILABLE: + case CL_DISCONNECT: + case CL_DUPLICATE: + default: + return IB_ERROR; + } +} + + +void +ib_fixup_ca_attr( + IN ib_ca_attr_t* const p_dest, + IN const ib_ca_attr_t* const p_src ) +{ + uint8_t i; + uintn_t offset = (uintn_t)p_dest - (uintn_t)p_src; + ib_port_attr_t *p_tmp_port_attr = NULL; + + CL_ASSERT( p_dest ); + CL_ASSERT( p_src ); + + /* Fix up the pointers to point within the destination buffer. */ + p_dest->p_page_size = + (uint32_t*)(((uint8_t*)p_dest->p_page_size) + offset); + + p_tmp_port_attr = + (ib_port_attr_t*)(((uint8_t*)p_dest->p_port_attr) + offset); + + /* Fix up each port attribute's gid and pkey table pointers. */ + for( i = 0; i < p_dest->num_ports; i++ ) + { + p_tmp_port_attr[i].p_gid_table = (ib_gid_t*) + (((uint8_t*)p_tmp_port_attr[i].p_gid_table) + offset); + + p_tmp_port_attr[i].p_pkey_table =(ib_net16_t*) + (((uint8_t*)p_tmp_port_attr[i].p_pkey_table) + offset); + } + p_dest->p_port_attr = p_tmp_port_attr; +} + + +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 ) +{ + CL_ASSERT( p_dest ); + CL_ASSERT( p_src ); + + /* Copy the attibutes buffer. */ + cl_memcpy( p_dest, p_src, p_src->size ); + + ib_fixup_ca_attr( p_dest, p_src ); + + return p_dest; +} diff --git a/branches/WOF2-3/core/al/ib_common.h b/branches/WOF2-3/core/al/ib_common.h new file mode 100644 index 00000000..456217b1 --- /dev/null +++ b/branches/WOF2-3/core/al/ib_common.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#if !defined(__IB_COMMON_H__) +#define __IB_COMMON_H__ + + +#include +#include + + +AL_EXPORT ib_api_status_t AL_API +ib_convert_cl_status( + IN const cl_status_t cl_status ); + +AL_EXPORT void AL_API +ib_fixup_ca_attr( + IN ib_ca_attr_t* const p_dest, + IN const ib_ca_attr_t* const p_src ); + +#endif /* __IB_COMMON_H__ */ diff --git a/branches/WOF2-3/core/al/ib_statustext.c b/branches/WOF2-3/core/al/ib_statustext.c new file mode 100644 index 00000000..43e0ae51 --- /dev/null +++ b/branches/WOF2-3/core/al/ib_statustext.c @@ -0,0 +1,271 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * Abstract: + * Defines string to decode ib_api_status_t return values. + * + * Environment: + * All + */ + + +#include + + +/* ib_api_status_t values above converted to text for easier printing. */ +static const char* const __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_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_SRQ_SIZE", + "IB_INVALID_SERVICE_TYPE", + "IB_INVALID_GID", + "IB_INVALID_LID", + "IB_INVALID_GUID", + "IB_INVALID_GUID_MASK", + "IB_INVALID_CA_HANDLE", + "IB_INVALID_AV_HANDLE", + "IB_INVALID_CQ_HANDLE", + "IB_INVALID_QP_HANDLE", + "IB_INVALID_SRQ_HANDLE", + "IB_INVALID_PD_HANDLE", + "IB_INVALID_MR_HANDLE", + "IB_INVALID_FMR_HANDLE", + "IB_INVALID_MW_HANDLE", + "IB_INVALID_MCAST_HANDLE", + "IB_INVALID_CALLBACK", + "IB_INVALID_AL_HANDLE", + "IB_INVALID_HANDLE", + "IB_ERROR", + "IB_REMOTE_ERROR", + "IB_VERBS_PROCESSING_DONE", + "IB_INVALID_WR_TYPE", + "IB_QP_IN_TIMEWAIT", + "IB_EE_IN_TIMEWAIT", + "IB_INVALID_PORT", + "IB_NOT_DONE", + "IB_INVALID_INDEX", + "IB_NO_MATCH", + "IB_PENDING", + "IB_UNKNOWN_ERROR" +}; + + +const char* +ib_get_err_str( + IN ib_api_status_t status ) +{ + if( status > IB_UNKNOWN_ERROR ) + status = IB_UNKNOWN_ERROR; + return( __ib_error_str[status] ); +} + + +/* ib_async_event_t values above converted to text for easier printing. */ +static const char* const __ib_async_event_str[] = +{ + "IB_AE_DUMMY", /*place holder*/ + "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_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_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_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] ); +} + + +static const char* const __ib_wc_status_str[] = +{ + "IB_WCS_SUCCESS", + "IB_WCS_LOCAL_LEN_ERR", + "IB_WCS_LOCAL_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_BAD_RESP_ERR", + "IB_WCS_LOCAL_ACCESS_ERR", + "IB_WCS_GENERAL_ERR", + "IB_WCS_UNMATCHED_RESPONSE", /* InfiniBand Access Layer */ + "IB_WCS_CANCELED", /* InfiniBand Access Layer */ + "IB_WCS_REM_ABORT_ERR", + "IB_WCS_UNKNOWN" +}; + + +const char* +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] ); +} + + +static const char* const __ib_wc_send_type_str[] = +{ + "IB_WC_SEND", + "IB_WC_RDMA_WRITE", + "IB_WC_RDMA_READ", + "IB_WC_COMPARE_SWAP", + "IB_WC_FETCH_ADD", + "IB_WC_MW_BIND", +}; + +static const char* const __ib_wc_recv_type_str[] = +{ + "IB_WC_RECV", + "IB_WC_RECV_RDMA_WRITE" +}; + +const char* +ib_get_wc_type_str( + IN ib_wc_type_t wc_type ) +{ + if ( wc_type & IB_WC_RECV ) + if ( wc_type - IB_WC_RECV >= IB_WC_UNKNOWN2) + return "IB_WC_UNKNOWN"; + else + return __ib_wc_recv_type_str[wc_type - IB_WC_RECV]; + else + if ( wc_type >= IB_WC_UNKNOWN1 ) + return "IB_WC_UNKNOWN"; + else + return __ib_wc_send_type_str[wc_type]; +} + + +static const char* const __ib_wr_type_str[] = +{ + "WR_SEND", + "WR_RDMA_WRITE", + "WR_RDMA_READ", + "WR_COMPARE_SWAP", + "WR_FETCH_ADD", + "WR_LSO" +}; + + +const char* +ib_get_wr_type_str( + IN uint8_t wr_type ) +{ + if( wr_type >= WR_UNKNOWN ) + return "WR_UNKNOWN"; + return( __ib_wr_type_str[wr_type] ); +} + +static const char* const __ib_qp_type_str[] = +{ + "IB_QPT_RELIABLE_CONN", + "IB_QPT_UNRELIABLE_CONN", + "IB_QPT_UNKNOWN", + "IB_QPT_UNRELIABLE_DGRM", + "IB_QPT_QP0", + "IB_QPT_QP1", + "IB_QPT_RAW_IPV6", + "IB_QPT_RAW_ETHER", + "IB_QPT_MAD", + "IB_QPT_QP0_ALIAS", + "IB_QPT_QP1_ALIAS", + "IB_QPT_UNKNOWN" + +}; + + +const char* +ib_get_qp_type_str( + IN uint8_t qp_type ) +{ + if( qp_type > IB_QPT_UNKNOWN ) + qp_type = IB_QPT_UNKNOWN; + return( __ib_qp_type_str[qp_type] ); +} + + + diff --git a/branches/WOF2-3/core/al/kernel/SOURCES b/branches/WOF2-3/core/al/kernel/SOURCES new file mode 100644 index 00000000..f4a2cc79 --- /dev/null +++ b/branches/WOF2-3/core/al/kernel/SOURCES @@ -0,0 +1,78 @@ +TARGETNAME=ibal +TARGETPATH=..\..\..\bin\kernel\obj$(BUILD_ALT_DIR) +TARGETTYPE=DRIVER_LIBRARY + + + +!if $(FREEBUILD) +ENABLE_EVENT_TRACING=1 +!else +#ENABLE_EVENT_TRACING=1 +!endif + + +SOURCES= ibal.rc \ + al_ci_ca.c \ + al_cm.c \ + al_cm_cep.c \ + al_dev.c \ + al_ioc_pnp.c \ + al_mad_pool.c \ + al_fmr_pool.c \ + al_mgr.c \ + al_mr.c \ + al_pnp.c \ + al_proxy.c \ + al_proxy_cep.c \ + al_proxy_ioc.c \ + al_proxy_subnet.c \ + al_proxy_verbs.c \ + al_proxy_ndi.c \ + al_ndi_cq.c \ + al_ndi_cm.c \ + al_sa_req.c \ + al_smi.c \ + ..\al.c \ + ..\al_av.c \ + ..\al_ca.c \ + ..\al_ci_ca_shared.c \ + ..\al_cm_qp.c \ + ..\al_common.c \ + ..\al_cq.c \ + ..\al_dm.c \ + ..\al_init.c \ + ..\al_mad.c \ + ..\al_mcast.c \ + ..\al_mgr_shared.c \ + ..\al_mr_shared.c \ + ..\al_mw.c \ + ..\al_pd.c \ + ..\al_qp.c \ + ..\al_query.c \ + ..\al_reg_svc.c \ + ..\al_res_mgr.c \ + ..\al_srq.c \ + ..\al_sub.c \ + ..\ib_common.c \ + ..\ib_statustext.c + +INCLUDES=..;..\..\..\inc;..\..\..\inc\kernel;..\..\bus\kernel;..\..\bus\kernel\$O; + +C_DEFINES=$(C_DEFINES) -DDRIVER -DDEPRECATE_DDK_FUNCTIONS \ + -DEXPORT_AL_SYMBOLS + +TARGETLIBS= \ + $(DDK_LIB_PATH)\ntstrsafe.lib \ + $(TARGETPATH)\*\complib.lib + +!IFDEF ENABLE_EVENT_TRACING + +C_DEFINES = $(C_DEFINES) -DEVENT_TRACING + +RUN_WPP = $(SOURCES) -km -ext: .c .h .C .H \ + -scan:..\al_debug.h \ + -func:AL_PRINT(LEVEL,FLAGS,(MSG,...)) \ + -func:AL_PRINT_EXIT(LEVEL,FLAGS,(MSG,...)) +!ENDIF + +MSC_WARNING_LEVEL= /W4 diff --git a/branches/WOF2-3/core/al/kernel/al_ci_ca.c b/branches/WOF2-3/core/al/kernel/al_ci_ca.c new file mode 100644 index 00000000..8f62030b --- /dev/null +++ b/branches/WOF2-3/core/al/kernel/al_ci_ca.c @@ -0,0 +1,532 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include "al_ci_ca.h" +#include "al_verbs.h" +#include "al_cq.h" +#include "al_debug.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "al_ci_ca.tmh" +#endif +#include "al_mad_pool.h" +#include "al_mgr.h" +#include "al_mr.h" +#include "al_pnp.h" +#include "al_mad_pool.h" + +#include "ib_common.h" + + +#define EVENT_POOL_MIN 4 +#define EVENT_POOL_MAX 0 +#define EVENT_POOL_GROW 1 + + +void +destroying_ci_ca( + IN al_obj_t* p_obj ); + +void +cleanup_ci_ca( + IN al_obj_t* p_obj ); + +void +free_ci_ca( + IN al_obj_t* p_obj ); + +void +ci_ca_comp_cb( + IN void *cq_context ); + +void +ci_ca_async_proc_cb( + IN struct _cl_async_proc_item *p_item ); + +void +ci_ca_async_event_cb( + IN ib_event_rec_t* p_event_record ); + + + +ib_api_status_t +create_ci_ca( + IN al_obj_t *p_parent_obj, + IN const ci_interface_t* p_ci, + IN const PDEVICE_OBJECT p_hca_dev, + IN const PDEVICE_OBJECT p_fdo + ) +{ + ib_api_status_t status; + cl_status_t cl_status; + al_ci_ca_t *p_ci_ca; + + AL_ENTER( AL_DBG_CA ); + + CL_ASSERT( p_ci ); + + /* Allocate the CI CA. */ + p_ci_ca = (al_ci_ca_t*)cl_zalloc( sizeof( al_ci_ca_t ) ); + if( !p_ci_ca ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("cl_zalloc failed\n") ); + return IB_INSUFFICIENT_MEMORY; + } + + /* Construct the CI CA. */ + construct_al_obj( &p_ci_ca->obj, AL_OBJ_TYPE_CI_CA ); + cl_spinlock_construct( &p_ci_ca->attr_lock ); + cl_qlist_init( &p_ci_ca->ca_list ); + cl_qlist_init( &p_ci_ca->shmid_list ); + cl_qpool_construct( &p_ci_ca->event_pool ); + p_ci_ca->verbs = *p_ci; + cl_event_construct( &p_ci_ca->event ); + cl_event_init( &p_ci_ca->event, FALSE ); + + cl_status = cl_spinlock_init( &p_ci_ca->attr_lock ); + if( cl_status != CL_SUCCESS ) + { + free_ci_ca( &p_ci_ca->obj ); + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("cl_spinlock_init failed, status = 0x%x.\n", + ib_convert_cl_status( cl_status ) ) ); + return ib_convert_cl_status( cl_status ); + } + + /* Create a pool of items to report asynchronous events. */ + cl_status = cl_qpool_init( &p_ci_ca->event_pool, EVENT_POOL_MIN, + EVENT_POOL_MAX, EVENT_POOL_GROW, sizeof( event_item_t ), NULL, + NULL, p_ci_ca ); + if( cl_status != CL_SUCCESS ) + { + free_ci_ca( &p_ci_ca->obj ); + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("cl_qpool_init failed, status = 0x%x.\n", + ib_convert_cl_status( cl_status ) ) ); + return ib_convert_cl_status( cl_status ); + } + + status = init_al_obj( &p_ci_ca->obj, p_ci_ca, FALSE, + destroying_ci_ca, cleanup_ci_ca, free_ci_ca ); + if( status != IB_SUCCESS ) + { + free_ci_ca( &p_ci_ca->obj ); + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("init_al_obj failed, status = 0x%x.\n", status) ); + return status; + } + status = attach_al_obj( p_parent_obj, &p_ci_ca->obj ); + if( status != IB_SUCCESS ) + { + p_ci_ca->obj.pfn_destroy( &p_ci_ca->obj, NULL ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("attach_al_obj returned %s.\n", ib_get_err_str(status)) ); + return status; + } + + p_ci_ca->dereg_async_item.pfn_callback = ci_ca_async_proc_cb; + + /* Open the CI CA. */ + status = p_ci_ca->verbs.open_ca( p_ci_ca->verbs.guid, + ci_ca_async_event_cb, p_ci_ca, &p_ci_ca->h_ci_ca ); + if( status != IB_SUCCESS ) + { + p_ci_ca->obj.pfn_destroy( &p_ci_ca->obj, NULL ); + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("open_ca failed, status = 0x%x.\n", status) ); + return status; + } + + /* Increase the max timeout for the CI CA to handle driver unload. */ + set_al_obj_timeout( &p_ci_ca->obj, AL_MAX_TIMEOUT_MS ); + + /* + * Register ourselves with the AL manager, so that the open call below + * will succeed. + */ + add_ci_ca( p_ci_ca ); + + /* Open the AL CA. */ + status = ib_open_ca( gh_al, p_ci_ca->verbs.guid, ca_event_cb, p_ci_ca, + &p_ci_ca->h_ca ); + if( status != IB_SUCCESS ) + { + p_ci_ca->obj.pfn_destroy( &p_ci_ca->obj, NULL ); + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("ib_open_ca failed, status = 0x%x.\n", status) ); + return status; + } + + + /* store HCA device object into CA object */ + p_ci_ca->h_ca->p_hca_dev = p_hca_dev; + p_ci_ca->h_ca->p_fdo = p_fdo; + + /* Get a list of the port GUIDs on this CI CA. */ + status = get_port_info( p_ci_ca ); + if( status != IB_SUCCESS ) + { + p_ci_ca->obj.pfn_destroy( &p_ci_ca->obj, NULL ); + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("get_port_guids failed, status = 0x%x.\n", status) ); + return status; + } + + /* Allocate a PD for use by AL itself. */ + status = ib_alloc_pd( p_ci_ca->h_ca, IB_PDT_SQP, p_ci_ca, + &p_ci_ca->h_pd ); + if( status != IB_SUCCESS ) + { + p_ci_ca->obj.pfn_destroy( &p_ci_ca->obj, NULL ); + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("ib_alloc_pd failed, status = 0x%x.\n", status) ); + return status; + } + + /* Allocate a PD for use by AL itself. */ + status = ib_alloc_pd( p_ci_ca->h_ca, IB_PDT_ALIAS, p_ci_ca, + &p_ci_ca->h_pd_alias ); + if( status != IB_SUCCESS ) + { + p_ci_ca->obj.pfn_destroy( &p_ci_ca->obj, NULL ); + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("ib_alloc_pd alias failed, status = 0x%x.\n", status) ); + return status; + } + + /* Register the global MAD pool on this CA. */ + status = ib_reg_mad_pool( gh_mad_pool, p_ci_ca->h_pd, &p_ci_ca->pool_key ); + if( status != IB_SUCCESS ) + { + p_ci_ca->obj.pfn_destroy( &p_ci_ca->obj, NULL ); + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("ib_reg_mad_pool failed, status = 0x%x.\n", status) ); + return status; + } + + /* + * Notify the PnP manager that a CA has been added. + * NOTE: PnP Manager must increment the CA reference count. + */ + status = pnp_ca_event( p_ci_ca, IB_PNP_CA_ADD ); + if( status != IB_SUCCESS ) + { + /* Destroy the CA */ + p_ci_ca->obj.pfn_destroy( &p_ci_ca->obj, NULL ); + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("al_pnp_add_ca failed, status = 0x%x.\n", status) ); + return status; + } + + /* Release the reference taken in init_al_obj. */ + deref_al_obj( &p_ci_ca->obj ); + + AL_EXIT( AL_DBG_CA ); + return IB_SUCCESS; +} + + + +void +destroying_ci_ca( + IN al_obj_t* p_obj ) +{ + al_ci_ca_t *p_ci_ca; + + CL_ASSERT( p_obj ); + p_ci_ca = PARENT_STRUCT( p_obj, al_ci_ca_t, obj ); + + /* + * Notify the PnP manager that this CA is being removed. + * NOTE: PnP Manager must decrement the CA reference count. + */ + pnp_ca_event( p_ci_ca, IB_PNP_CA_REMOVE ); + + /* + * We queue a request to the asynchronous processing manager to close + * the CA after the PNP remove CA event has been delivered. This avoids + * the ib_close_ca() call from immediately removing resouces (PDs, QPs) + * that are in use by clients waiting on the remove CA event. + */ + if( p_ci_ca->h_ca ) + cl_async_proc_queue( gp_async_pnp_mgr, &p_ci_ca->dereg_async_item ); +} + + + +void +ci_ca_async_proc_cb( + IN struct _cl_async_proc_item *p_item ) +{ + al_ci_ca_t *p_ci_ca; + + p_ci_ca = PARENT_STRUCT( p_item, al_ci_ca_t, dereg_async_item ); + + /* Release all AL resources acquired by the CI CA. */ + ib_close_ca( p_ci_ca->h_ca, NULL ); +} + + + +void +cleanup_ci_ca( + IN al_obj_t* p_obj ) +{ + ib_api_status_t status; + al_ci_ca_t *p_ci_ca; + + AL_ENTER( AL_DBG_CA ); + + CL_ASSERT( p_obj ); + p_ci_ca = PARENT_STRUCT( p_obj, al_ci_ca_t, obj ); + + CL_ASSERT( cl_is_qlist_empty( &p_ci_ca->shmid_list ) ); + + if( p_ci_ca->h_ci_ca ) + { + remove_ci_ca( p_ci_ca ); + status = p_ci_ca->verbs.close_ca( p_ci_ca->h_ci_ca ); + CL_ASSERT( status == IB_SUCCESS ); + } + + AL_EXIT( AL_DBG_CA ); +} + + + +void +ci_ca_comp_cb( + IN void *cq_context ) +{ + ib_cq_handle_t h_cq = (ib_cq_handle_t)cq_context; + + if( h_cq->h_wait_obj ) + KeSetEvent( h_cq->h_wait_obj, IO_NETWORK_INCREMENT, FALSE ); + else + h_cq->pfn_user_comp_cb( h_cq, (void*)h_cq->obj.context ); +} + + + +/* + * CI CA asynchronous event callback. + */ +void +ci_ca_async_event_cb( + IN ib_event_rec_t* p_event_record ) +{ + ib_async_event_rec_t event_rec; + + AL_ENTER( AL_DBG_CA ); + + CL_ASSERT( p_event_record ); + + event_rec.code = p_event_record->type; + event_rec.context = p_event_record->context; + event_rec.vendor_specific = p_event_record->vendor_specific; + event_rec.port_number = p_event_record->port_number; + + ci_ca_async_event( &event_rec ); + + AL_EXIT( AL_DBG_CA ); +} + + + +/* + * Insert a new shmid tracking structure into the CI CA's list. + */ +void +add_shmid( + IN al_ci_ca_t* const p_ci_ca, + IN struct _al_shmid *p_shmid ) +{ + CL_ASSERT( p_ci_ca && p_shmid ); + + p_shmid->obj.p_ci_ca = p_ci_ca; + + /* Insert the shmid structure into the shmid list. */ + cl_spinlock_acquire( &p_ci_ca->obj.lock ); + cl_qlist_insert_head( &p_ci_ca->shmid_list, &p_shmid->list_item ); + cl_spinlock_release( &p_ci_ca->obj.lock ); +} + + + +ib_api_status_t +acquire_shmid( + IN al_ci_ca_t* const p_ci_ca, + IN int shmid, + OUT struct _al_shmid **pp_shmid ) +{ + al_shmid_t *p_shmid; + cl_list_item_t *p_list_item; + + /* Try to find the shmid. */ + cl_spinlock_acquire( &p_ci_ca->obj.lock ); + for( p_list_item = cl_qlist_head( &p_ci_ca->shmid_list ); + p_list_item != cl_qlist_end( &p_ci_ca->shmid_list ); + p_list_item = cl_qlist_next( p_list_item ) ) + { + p_shmid = PARENT_STRUCT( p_list_item, al_shmid_t, list_item ); + if( p_shmid->id == shmid ) + { + ref_al_obj( &p_shmid->obj ); + *pp_shmid = p_shmid; + break; + } + } + cl_spinlock_release( &p_ci_ca->obj.lock ); + + if( p_list_item == cl_qlist_end( &p_ci_ca->shmid_list ) ) + return IB_NOT_FOUND; + else + return IB_SUCCESS; +} + + + +void +release_shmid( + IN struct _al_shmid *p_shmid ) +{ + al_ci_ca_t *p_ci_ca; + int32_t ref_cnt; + + CL_ASSERT( p_shmid ); + + p_ci_ca = p_shmid->obj.p_ci_ca; + + cl_spinlock_acquire( &p_ci_ca->obj.lock ); + + /* Dereference the shmid. */ + ref_cnt = deref_al_obj( &p_shmid->obj ); + + /* If the shmid is no longer in active use, remove it. */ + if( ref_cnt == 1 ) + cl_qlist_remove_item( &p_ci_ca->shmid_list, &p_shmid->list_item ); + + cl_spinlock_release( &p_ci_ca->obj.lock ); + + /* Destroy the shmid if it is not needed. */ + if( ref_cnt == 1 ) + { + ref_al_obj( &p_shmid->obj ); + p_shmid->obj.pfn_destroy( &p_shmid->obj, NULL ); + } +} + + + +ib_api_status_t +ib_ci_call( + IN ib_ca_handle_t h_ca, + IN const void** const handle_array OPTIONAL, + IN uint32_t num_handles, + IN ib_ci_op_t* const p_ci_op ) +{ + return ci_call( h_ca, handle_array, num_handles, p_ci_op, NULL ); +} + + + +ib_api_status_t +ci_call( + IN ib_ca_handle_t h_ca, + IN const void** const handle_array OPTIONAL, + IN uint32_t num_handles, + IN ib_ci_op_t* const p_ci_op, + IN ci_umv_buf_t* const p_umv_buf OPTIONAL ) +{ + void** p_handle_array; + ib_api_status_t status; + + AL_ENTER( AL_DBG_CA ); + + if( AL_OBJ_INVALID_HANDLE( h_ca, AL_OBJ_TYPE_H_CA ) ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_CA_HANDLE\n") ); + return IB_INVALID_CA_HANDLE; + } + if( !p_ci_op ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + p_handle_array = NULL; + if ( num_handles ) + { + p_handle_array = cl_zalloc( sizeof(void*) * num_handles ); + if( !p_handle_array ) + return IB_INSUFFICIENT_MEMORY; + + status = al_convert_to_ci_handles( p_handle_array, handle_array, + num_handles ); + + if( status != IB_SUCCESS ) + { + cl_free( p_handle_array ); + return status; + } + } + + if( h_ca->obj.p_ci_ca->verbs.vendor_call ) + { + status = verbs_ci_call( + h_ca, p_handle_array, num_handles, p_ci_op, p_umv_buf ); + } + else + { + status = IB_UNSUPPORTED; + } + + if ( num_handles ) + cl_free( p_handle_array ); + + AL_EXIT( AL_DBG_QUERY ); + return status; +} + + +DEVICE_OBJECT* +get_ca_dev( + IN const ib_ca_handle_t h_ca ) +{ + ASSERT( h_ca ); + + ObReferenceObject( h_ca->p_hca_dev ); + return h_ca->p_hca_dev; +} diff --git a/branches/WOF2-3/core/al/kernel/al_cm.c b/branches/WOF2-3/core/al/kernel/al_cm.c new file mode 100644 index 00000000..8ba28f1e --- /dev/null +++ b/branches/WOF2-3/core/al/kernel/al_cm.c @@ -0,0 +1,393 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include "al_cm_cep.h" +#include "al_mgr.h" +#include "al_proxy.h" +#include "al_cm_conn.h" +#include "al_cm_sidr.h" + +typedef struct _iba_cm_id_priv +{ + iba_cm_id id; + KEVENT destroy_event; + +} iba_cm_id_priv; + +static iba_cm_id* +cm_alloc_id(NTSTATUS (*callback)(iba_cm_id *p_id, iba_cm_event *p_event), + void *context) +{ + iba_cm_id_priv *id; + + id = ExAllocatePoolWithTag(NonPagedPool, sizeof(iba_cm_id_priv), 'mcbi'); + if (id == NULL) { + return NULL; + } + + KeInitializeEvent(&id->destroy_event, NotificationEvent, FALSE); + id->id.callback = callback; + id->id.context = context; + return &id->id; +} + +static void +cm_free_id(iba_cm_id *id) +{ + ExFreePool(CONTAINING_RECORD(id, iba_cm_id_priv, id)); +} + +static void +cm_destroy_handler(void *context) +{ + iba_cm_id_priv *id = context; + KeSetEvent(&id->destroy_event, 0, FALSE); +} + +static void +cm_cep_handler(const ib_al_handle_t h_al, const net32_t cid) +{ + void *context; + net32_t new_cid; + ib_mad_element_t *mad; + iba_cm_id *id; + iba_cm_event event; + NTSTATUS status; + + while (al_cep_poll(h_al, cid, &context, &new_cid, &mad) == IB_SUCCESS) { + + id = (iba_cm_id *) context; + kal_cep_format_event(h_al, id->cid, mad, &event); + + status = id->callback(id, &event); + if (!NT_SUCCESS(status)) { + kal_cep_config(h_al, new_cid, NULL, NULL, NULL); + kal_cep_destroy(h_al, id->cid, status); + cm_free_id(id); + } + ib_put_mad(mad); + } +} + +static void +cm_listen_handler(const ib_al_handle_t h_al, const net32_t cid) +{ + iba_cm_id *id; + iba_cm_event event; + + id = (iba_cm_id *) kal_cep_get_context(h_al, cid, NULL, NULL); + memset(&event, 0, sizeof event); + event.type = iba_cm_req_received; + id->callback(id, &event); +} + +static NTSTATUS +cm_get_request(iba_cm_id *p_listen_id, iba_cm_id **pp_id, iba_cm_event *p_event) +{ + void *context; + net32_t new_cid; + ib_mad_element_t *mad; + ib_api_status_t ib_status; + NTSTATUS status; + + ib_status = al_cep_poll(gh_al, p_listen_id->cid, &context, &new_cid, &mad); + if (ib_status != IB_SUCCESS) { + return STATUS_NO_MORE_ENTRIES; + } + + *pp_id = cm_alloc_id(p_listen_id->callback, p_listen_id); + if (*pp_id == NULL) { + kal_cep_destroy(gh_al, new_cid, STATUS_NO_MORE_ENTRIES); + status = STATUS_NO_MEMORY; + goto out; + } + + kal_cep_config(gh_al, new_cid, cm_cep_handler, *pp_id, cm_destroy_handler); + (*pp_id)->cid = new_cid; + kal_cep_format_event(gh_al, new_cid, mad, p_event); + status = STATUS_SUCCESS; + +out: + ib_put_mad(mad); + return status; +} + +static NTSTATUS +cm_create_id(NTSTATUS (*callback)(iba_cm_id *p_id, iba_cm_event *p_event), + void *context, iba_cm_id **pp_id) +{ + iba_cm_id *id; + ib_api_status_t ib_status; + + id = cm_alloc_id(callback, context); + if (id == NULL) { + return STATUS_NO_MEMORY; + } + + ib_status = kal_cep_alloc(gh_al, &id->cid); + if (ib_status != IB_SUCCESS) { + cm_free_id(id); + return ib_to_ntstatus(ib_status); + } + + kal_cep_config(gh_al, id->cid, cm_cep_handler, id, cm_destroy_handler); + *pp_id = id; + return STATUS_SUCCESS; +} + +static void +cm_destroy_id(iba_cm_id *p_id) +{ + iba_cm_id_priv *id; + + id = CONTAINING_RECORD(p_id, iba_cm_id_priv, id); + kal_cep_destroy(gh_al, p_id->cid, STATUS_SUCCESS); + KeWaitForSingleObject(&id->destroy_event, Executive, KernelMode, FALSE, NULL); + cm_free_id(p_id); +} + +static NTSTATUS +cm_listen(iba_cm_id *p_id, net64_t service_id, void *p_compare_buf, + uint8_t compare_len, uint8_t compare_offset) +{ + ib_cep_listen_t info; + ib_api_status_t ib_status; + + info.svc_id = service_id; + info.port_guid = IB_ALL_PORTS; + info.p_cmp_buf = p_compare_buf; + info.cmp_len = compare_len; + info.cmp_offset = compare_offset; + + kal_cep_config(gh_al, p_id->cid, cm_listen_handler, p_id, cm_destroy_handler); + ib_status = al_cep_listen(gh_al, p_id->cid, &info); + return ib_to_ntstatus(ib_status); +} + +static NTSTATUS +cm_send_req(iba_cm_id *p_id, iba_cm_req *p_req) +{ + ib_api_status_t ib_status; + + ib_status = kal_cep_pre_req(gh_al, p_id->cid, p_req, 0, NULL); + if (ib_status != IB_SUCCESS) { + return ib_to_ntstatus(ib_status); + } + + ib_status = al_cep_send_req(gh_al, p_id->cid); + return ib_to_ntstatus(ib_status); +} + +static NTSTATUS +cm_send_rep(iba_cm_id *p_id, iba_cm_rep *p_rep) +{ + ib_api_status_t ib_status; + + ib_status = kal_cep_pre_rep(gh_al, p_id->cid, p_rep, 0, NULL); + if (ib_status != IB_SUCCESS) { + return ib_to_ntstatus(ib_status); + } + + ib_status = al_cep_send_rep(gh_al, p_id->cid); + return ib_to_ntstatus(ib_status); +} + +static NTSTATUS +cm_send_rtu(iba_cm_id *p_id, void *p_pdata, uint8_t pdata_len) +{ + ib_api_status_t ib_status; + + ib_status = al_cep_rtu(gh_al, p_id->cid, p_pdata, pdata_len); + return ib_to_ntstatus(ib_status); +} + +static NTSTATUS +cm_send_dreq(iba_cm_id *p_id, void *p_pdata, uint8_t pdata_len) +{ + ib_api_status_t ib_status; + + ib_status = al_cep_dreq(gh_al, p_id->cid, p_pdata, pdata_len); + return ib_to_ntstatus(ib_status); +} + +static NTSTATUS +cm_send_drep(iba_cm_id *p_id, void *p_pdata, uint8_t pdata_len) +{ + ib_api_status_t ib_status; + + ib_status = al_cep_drep(gh_al, p_id->cid, p_pdata, pdata_len); + return ib_to_ntstatus(ib_status); +} + +static NTSTATUS +cm_send_rej(iba_cm_id *p_id, ib_rej_status_t status, + void *p_ari, uint8_t ari_len, + void *p_pdata, uint8_t pdata_len) +{ + ib_api_status_t ib_status; + + ib_status = al_cep_rej(gh_al, p_id->cid, status, p_ari, ari_len, + p_pdata, pdata_len); + return ib_to_ntstatus(ib_status); +} + +static NTSTATUS +cm_send_mra(iba_cm_id *p_id, uint8_t service_timeout, + void *p_pdata, uint8_t pdata_len) +{ + ib_cm_mra_t mra; + ib_api_status_t ib_status; + + mra.svc_timeout = service_timeout; + mra.p_mra_pdata = p_pdata; + mra.mra_length = pdata_len; + + ib_status = al_cep_mra(gh_al, p_id->cid, &mra); + return ib_to_ntstatus(ib_status); +} + +static NTSTATUS +cm_send_lap(iba_cm_id *p_id, iba_cm_lap *p_lap) +{ + ib_cm_lap_t lap; + ib_api_status_t ib_status; + + RtlZeroMemory(&lap, sizeof lap); + lap.p_lap_pdata = p_lap->p_pdata; + lap.lap_length = p_lap->pdata_len; + lap.remote_resp_timeout = p_lap->remote_resp_timeout; + lap.p_alt_path = p_lap->p_alt_path; + + ib_status = al_cep_lap(gh_al, p_id->cid, &lap); + return ib_to_ntstatus(ib_status); +} + +static NTSTATUS +cm_send_apr(iba_cm_id *p_id, iba_cm_apr *p_apr) +{ + ib_cm_apr_t apr; + ib_qp_mod_t attr; + ib_api_status_t ib_status; + + RtlZeroMemory(&apr, sizeof apr); + apr.p_apr_pdata = p_apr->p_pdata; + apr.apr_length = p_apr->pdata_len; + apr.apr_status = p_apr->status; + apr.info_length = p_apr->info_length; + apr.p_info = p_apr->p_info; + + ib_status = al_cep_pre_apr(gh_al, p_id->cid, &apr, &attr); + if (ib_status != IB_SUCCESS) { + return ib_to_ntstatus(ib_status); + } + + ib_status = al_cep_send_apr(gh_al, p_id->cid); + return ib_to_ntstatus(ib_status); +} + +static NTSTATUS +cm_send_sidr_req(iba_cm_id *p_id, iba_cm_sidr_req *p_req) +{ + UNUSED_PARAM(p_id); + UNUSED_PARAM(p_req); + + return STATUS_NOT_SUPPORTED; +} + +static NTSTATUS +cm_send_sidr_rep(iba_cm_id *p_id, iba_cm_sidr_rep *p_rep) +{ + UNUSED_PARAM(p_id); + UNUSED_PARAM(p_rep); + + return STATUS_NOT_SUPPORTED; +} + +static NTSTATUS +cm_get_qp_attr(iba_cm_id *p_id, ib_qp_state_t state, ib_qp_mod_t *p_attr) +{ + ib_api_status_t ib_status; + + switch (state) { + case IB_QPS_INIT: + ib_status = al_cep_get_init_attr(gh_al, p_id->cid, p_attr); + break; + case IB_QPS_RTR: + ib_status = al_cep_get_rtr_attr(gh_al, p_id->cid, p_attr); + break; + case IB_QPS_RTS: + ib_status = al_cep_get_rts_attr(gh_al, p_id->cid, p_attr); + break; + default: + return STATUS_INVALID_PARAMETER; + } + + return ib_to_ntstatus(ib_status); +} + +static NTSTATUS +cm_migrate(iba_cm_id *p_id) +{ + ib_api_status_t ib_status; + + ib_status = al_cep_migrate(gh_al, p_id->cid); + return ib_to_ntstatus(ib_status); +} + +static NTSTATUS +cm_establish(iba_cm_id *p_id) +{ + ib_api_status_t ib_status; + + ib_status = al_cep_established(gh_al, p_id->cid); + return ib_to_ntstatus(ib_status); +} + +void cm_get_interface(iba_cm_interface *p_ifc) +{ + p_ifc->create_id = cm_create_id; + p_ifc->destroy_id = cm_destroy_id; + p_ifc->listen = cm_listen; + p_ifc->get_request = cm_get_request; + p_ifc->send_req = cm_send_req; + p_ifc->send_rep = cm_send_rep; + p_ifc->send_rtu = cm_send_rtu; + p_ifc->send_dreq = cm_send_dreq; + p_ifc->send_drep = cm_send_drep; + p_ifc->send_rej = cm_send_rej; + p_ifc->send_mra = cm_send_mra; + p_ifc->send_lap = cm_send_lap; + p_ifc->send_apr = cm_send_apr; + p_ifc->send_sidr_req = cm_send_sidr_req; + p_ifc->send_sidr_rep = cm_send_sidr_rep; + p_ifc->get_qp_attr = cm_get_qp_attr; + p_ifc->migrate = cm_migrate; + p_ifc->established = cm_establish; +} diff --git a/branches/WOF2-3/core/al/kernel/al_cm_cep.c b/branches/WOF2-3/core/al/kernel/al_cm_cep.c new file mode 100644 index 00000000..6255846d --- /dev/null +++ b/branches/WOF2-3/core/al/kernel/al_cm_cep.c @@ -0,0 +1,6670 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include +#include +#include +#include +#include +#include +#include "al_common.h" +#include "al_cm_cep.h" +#include "al_cm_conn.h" +#include "al_cm_sidr.h" +#include "al_debug.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "al_cm_cep.tmh" +#endif +#include "ib_common.h" +#include "al_mgr.h" +#include "al_ca.h" +#include "al.h" +#include "al_mad.h" +#include "al_qp.h" + + +/* + * The vector object uses a list item at the front of the buffers + * it allocates. Take the list item into account so that allocations + * are for full page sizes. + */ +#define CEP_CID_MIN \ + ((PAGE_SIZE - sizeof(cl_list_item_t)) / sizeof(cep_cid_t)) +#define CEP_CID_GROW \ + ((PAGE_SIZE - sizeof(cl_list_item_t)) / sizeof(cep_cid_t)) + +/* + * We reserve the upper byte of the connection ID as a revolving counter so + * that connections that are retried by the client change connection ID. + * This counter is never zero, so it is OK to use all CIDs since we will never + * have a full CID (base + counter) that is zero. + * See the IB spec, section 12.9.8.7 for details about REJ retry. + */ +#define CEP_MAX_CID (0x00FFFFFF) +#define CEP_MAX_CID_MASK (0x00FFFFFF) + +#define CEP_MAD_SQ_DEPTH (128) +#define CEP_MAD_RQ_DEPTH (1) /* ignored. */ +#define CEP_MAD_SQ_SGE (1) +#define CEP_MAD_RQ_SGE (1) /* ignored. */ + + +/* Global connection manager object. */ +typedef struct _al_cep_mgr +{ + al_obj_t obj; + + cl_qmap_t port_map; + + KSPIN_LOCK lock; + + /* Bitmap of CEPs, indexed by CID. */ + cl_vector_t cid_vector; + uint32_t free_cid; + + /* List of active listens. */ + cl_rbmap_t listen_map; + + /* Map of CEP by remote CID and CA GUID. */ + cl_rbmap_t conn_id_map; + /* Map of CEP by remote QPN, used for stale connection matching. */ + cl_rbmap_t conn_qp_map; + + NPAGED_LOOKASIDE_LIST cep_pool; + NPAGED_LOOKASIDE_LIST req_pool; + + /* + * Periodically walk the list of connections in the time wait state + * and flush them as appropriate. + */ + cl_timer_t timewait_timer; + cl_qlist_t timewait_list; + + ib_pnp_handle_t h_pnp; + +} al_cep_mgr_t; + + +/* Per-port CM object. */ +typedef struct _cep_port_agent +{ + al_obj_t obj; + + cl_map_item_t item; + + ib_ca_handle_t h_ca; + ib_pd_handle_t h_pd; + ib_qp_handle_t h_qp; + ib_pool_key_t pool_key; + ib_mad_svc_handle_t h_mad_svc; + + net64_t port_guid; + uint8_t port_num; + net16_t base_lid; + +} cep_agent_t; + + +/* + * Note: the REQ, REP, and LAP values must be 1, 2, and 4 respectively. + * This allows shifting 1 << msg_mraed from an MRA to figure out for what + * message the MRA was sent for. + */ +#define CEP_STATE_RCVD 0x10000000 +#define CEP_STATE_SENT 0x20000000 +#define CEP_STATE_MRA 0x01000000 +#define CEP_STATE_REQ 0x00000001 +#define CEP_STATE_REP 0x00000002 +#define CEP_STATE_LAP 0x00000004 +#define CEP_STATE_RTU 0x00000008 +#define CEP_STATE_DREQ 0x00000010 +#define CEP_STATE_DREP 0x00000020 +#define CEP_STATE_DESTROYING 0x00010000 +#define CEP_STATE_USER 0x00020000 + +#define CEP_MSG_MASK 0x000000FF +#define CEP_OP_MASK 0xF0000000 + +#define CEP_STATE_PREP 0x00100000 + +/* States match CM state transition diagrams from spec. */ +typedef enum _cep_state +{ + CEP_STATE_IDLE, + CEP_STATE_LISTEN, + CEP_STATE_ESTABLISHED, + CEP_STATE_TIMEWAIT, + CEP_STATE_SREQ_SENT, + CEP_STATE_SREQ_RCVD, + CEP_STATE_ERROR, + CEP_STATE_DESTROY = CEP_STATE_DESTROYING, + CEP_STATE_PRE_REQ = CEP_STATE_IDLE | CEP_STATE_PREP, + CEP_STATE_REQ_RCVD = CEP_STATE_REQ | CEP_STATE_RCVD, + CEP_STATE_PRE_REP = CEP_STATE_REQ_RCVD | CEP_STATE_PREP, + CEP_STATE_REQ_SENT = CEP_STATE_REQ | CEP_STATE_SENT, + CEP_STATE_REQ_MRA_RCVD = CEP_STATE_REQ_SENT | CEP_STATE_MRA, + CEP_STATE_REQ_MRA_SENT = CEP_STATE_REQ_RCVD | CEP_STATE_MRA, + CEP_STATE_PRE_REP_MRA_SENT = CEP_STATE_REQ_MRA_SENT | CEP_STATE_PREP, + CEP_STATE_REP_RCVD = CEP_STATE_REP | CEP_STATE_RCVD, + CEP_STATE_REP_SENT = CEP_STATE_REP | CEP_STATE_SENT, + CEP_STATE_REP_MRA_RCVD = CEP_STATE_REP_SENT | CEP_STATE_MRA, + CEP_STATE_REP_MRA_SENT = CEP_STATE_REP_RCVD | CEP_STATE_MRA, + CEP_STATE_LAP_RCVD = CEP_STATE_LAP | CEP_STATE_RCVD, + CEP_STATE_PRE_APR = CEP_STATE_LAP_RCVD | CEP_STATE_PREP, + CEP_STATE_LAP_SENT = CEP_STATE_LAP | CEP_STATE_SENT, + CEP_STATE_LAP_MRA_RCVD = CEP_STATE_LAP_SENT | CEP_STATE_MRA, + CEP_STATE_LAP_MRA_SENT = CEP_STATE_LAP_RCVD | CEP_STATE_MRA, + CEP_STATE_PRE_APR_MRA_SENT = CEP_STATE_LAP_MRA_SENT | CEP_STATE_PREP, + CEP_STATE_DREQ_SENT = CEP_STATE_DREQ | CEP_STATE_SENT, + CEP_STATE_DREQ_RCVD = CEP_STATE_DREQ | CEP_STATE_RCVD, + CEP_STATE_DREQ_DESTROY = CEP_STATE_DREQ_SENT | CEP_STATE_DESTROYING + +} cep_state_t; + + +/* Active side CEP state transitions: +* al_create_cep -> IDLE +* al_cep_pre_req -> PRE_REQ +* al_cep_send_req -> REQ_SENT +* Recv REQ MRA -> REQ_MRA_RCVD +* Recv REP -> REP_RCVD +* al_cep_mra -> REP_MRA_SENT +* al_cep_rtu -> ESTABLISHED +* +* Passive side CEP state transitions: +* al_create_cep -> IDLE +* Recv REQ -> REQ_RCVD +* al_cep_mra* -> REQ_MRA_SENT +* al_cep_pre_rep -> PRE_REP +* al_cep_mra* -> PRE_REP_MRA_SENT +* al_cep_send_rep -> REP_SENT +* Recv RTU -> ESTABLISHED +* +* *al_cep_mra can only be called once - either before or after PRE_REP. +*/ + +typedef struct _al_kcep_av +{ + ib_av_attr_t attr; + net64_t port_guid; + uint16_t pkey_index; + +} kcep_av_t; + + +typedef struct _al_kcep +{ + net32_t cid; + void* context; + + struct _cep_cid *p_cid; + + net64_t sid; + + /* Port guid for filtering incoming requests. */ + net64_t port_guid; + + uint8_t* p_cmp_buf; + uint8_t cmp_offset; + uint8_t cmp_len; + + boolean_t p2p; + + /* Used to store connection structure with owning AL instance. */ + cl_list_item_t al_item; + + /* Flag to indicate whether a user is processing events. */ + boolean_t signalled; + + /* Destroy callback. */ + ib_pfn_destroy_cb_t pfn_destroy_cb; + + ib_mad_element_t *p_mad_head; + ib_mad_element_t *p_mad_tail; + al_pfn_cep_cb_t pfn_cb; + + IRP *p_irp; + + /* MAP item for finding listen CEPs. */ + cl_rbmap_item_t listen_item; + + /* Map item for finding CEPs based on remote comm ID & CA GUID. */ + cl_rbmap_item_t rem_id_item; + + /* Map item for finding CEPs based on remote QP number. */ + cl_rbmap_item_t rem_qp_item; + + /* Communication ID's for the connection. */ + net32_t local_comm_id; + net32_t remote_comm_id; + + net64_t local_ca_guid; + net64_t remote_ca_guid; + + /* Remote QP, used for stale connection checking. */ + net32_t remote_qpn; + + /* Parameters to format QP modification structure. */ + net32_t sq_psn; + net32_t rq_psn; + /* + * Note that we store the requested initiator depth as received in the REQ + * and cap it when sending the REP to the actual capabilities of the HCA. + */ + uint8_t resp_res; + uint8_t init_depth; + uint8_t rnr_nak_timeout; + + /* + * Local QP number, used for the "additional check" required + * of the DREQ. + */ + net32_t local_qpn; + + /* PKEY to make sure a LAP is on the same partition. */ + net16_t pkey; + + /* + * Primary and alternate path info, used to create the address vectors for + * sending MADs, to locate the port CM agent to use for outgoing sends, + * and for creating the address vectors for transitioning QPs. + */ + kcep_av_t av[2]; + uint8_t idx_primary; + + /* Temporary AV and CEP port GUID used when processing LAP. */ + kcep_av_t alt_av; + uint8_t alt_2pkt_life; + + /* maxium packet lifetime * 2 of any path used on a connection. */ + uint8_t max_2pkt_life; + /* Given by the REP, used for alternate path setup. */ + uint8_t target_ack_delay; + /* Stored to help calculate the local ACK delay in the LAP. */ + uint8_t local_ack_delay; + + /* Volatile to allow using atomic operations for state checks. */ + cep_state_t state; + + /* + * Flag that indicates whether a connection took the active role during + * establishment. + */ + boolean_t was_active; + + /* + * Handle to the sent MAD, used for cancelling. We store the handle to + * the mad service so that we can properly cancel. This should not be a + * problem since all outstanding sends should be completed before the + * mad service completes its destruction and the handle becomes invalid. + */ + ib_mad_svc_handle_t h_mad_svc; + ib_mad_element_t *p_send_mad; + + atomic32_t ref_cnt; + + /* MAD transaction ID to use when sending MADs. */ + uint64_t tid; + + /* Maximum retries per MAD. Set at REQ time, stored to retry LAP. */ + uint8_t max_cm_retries; + /* Timeout value, in milliseconds. Set at REQ time, stored to retry LAP. */ + uint32_t retry_timeout; + + /* Timer that will be signalled when the CEP exits timewait. */ + KTIMER timewait_timer; + LARGE_INTEGER timewait_time; + cl_list_item_t timewait_item; + + /* + * Pointer to a formatted MAD. The pre_req, pre_rep and pre_apr calls + * allocate and format the MAD, and the send_req, send_rep and send_apr + * calls send it. + */ + ib_mad_element_t *p_mad; + + /* Cache the last MAD sent for retransmission. */ + union _mads + { + ib_mad_t hdr; + mad_cm_mra_t mra; + mad_cm_rtu_t rtu; + mad_cm_drep_t drep; + + } mads; + + /* + * NDI stuff - TODO: manage above core kernel CM code + */ + + /* private data of REQ, REP, REJ CM requests */ + uint8_t psize; + uint8_t pdata[IB_REP_PDATA_SIZE]; + +} kcep_t; + + +/* Structures stored in the CID vector. */ +typedef struct _cep_cid +{ + /* Owning AL handle. NULL if invalid. */ + ib_al_handle_t h_al; + /* Pointer to CEP, or index of next free entry if h_al is NULL. */ + kcep_t *p_cep; + /* For REJ Retry support */ + uint8_t modifier; + +} cep_cid_t; + + +/* Global instance of the CM agent. */ +al_cep_mgr_t *gp_cep_mgr = NULL; + + +static ib_api_status_t +__format_drep( + IN kcep_t* const p_cep, + IN const uint8_t* p_pdata OPTIONAL, + IN uint8_t pdata_len, + IN OUT mad_cm_drep_t* const p_drep ); + +static ib_api_status_t +__cep_queue_mad( + IN kcep_t* const p_cep, + IN ib_mad_element_t* p_mad ); + +static inline void +__process_cep( + IN kcep_t* const p_cep ); + +static inline uint32_t +__calc_mad_timeout( + IN const uint8_t pkt_life ); + +static inline void +__calc_timewait( + IN kcep_t* const p_cep ); + +static kcep_t* +__create_cep( void ); + +static int32_t +__cleanup_cep( + IN kcep_t* const p_cep ); + +static void +__destroy_cep( + IN kcep_t* const p_cep ); + +static inline void +__bind_cep( + IN kcep_t* const p_cep, + IN ib_al_handle_t h_al, + IN al_pfn_cep_cb_t pfn_cb, + IN void* context ); + +static inline void +__unbind_cep( + IN kcep_t* const p_cep ); + +static void +__pre_destroy_cep( + IN kcep_t* const p_cep ); + +static kcep_t* +__lookup_by_id( + IN net32_t remote_comm_id, + IN net64_t remote_ca_guid ); + +static kcep_t* +__lookup_listen( + IN net64_t sid, + IN net64_t port_guid, + IN void *p_pdata ); + +static inline kcep_t* +__lookup_cep( + IN ib_al_handle_t h_al OPTIONAL, + IN net32_t cid ); + +static inline kcep_t* +__insert_cep( + IN kcep_t* const p_new_cep ); + +static inline void +__remove_cep( + IN kcep_t* const p_cep ); + +static inline void +__insert_timewait( + IN kcep_t* const p_cep ); + +static ib_api_status_t +__cep_get_mad( + IN kcep_t* const p_cep, + IN net16_t attr_id, + OUT cep_agent_t** const pp_port_cep, + OUT ib_mad_element_t** const pp_mad ); + +static ib_api_status_t +__cep_send_mad( + IN cep_agent_t* const p_port_cep, + IN ib_mad_element_t* const p_mad ); + +/* Returns the 1-based port index of the CEP agent with the specified GID. */ +static cep_agent_t* +__find_port_cep( + IN const ib_gid_t* const p_gid, + IN const net16_t lid, + IN const net16_t pkey, + OUT uint16_t* const p_pkey_index ); + +static cep_cid_t* +__get_lcid( + OUT net32_t* const p_cid ); + +static void +__process_cep_send_comp( + IN cl_async_proc_item_t *p_item ); + + +/****************************************************************************** +* Per-port CEP agent +******************************************************************************/ + + +static inline void +__format_mad_hdr( + IN ib_mad_t* const p_mad, + IN const kcep_t* const p_cep, + IN net16_t attr_id ) +{ + p_mad->base_ver = 1; + p_mad->mgmt_class = IB_MCLASS_COMM_MGMT; + p_mad->class_ver = IB_MCLASS_CM_VER_2; + p_mad->method = IB_MAD_METHOD_SEND; + p_mad->status = 0; + p_mad->class_spec = 0; + p_mad->trans_id = p_cep->tid; + p_mad->attr_id = attr_id; + p_mad->resv = 0; + p_mad->attr_mod = 0; +} + + +/* Consumes the input MAD. */ +static void +__reject_mad( + IN cep_agent_t* const p_port_cep, + IN kcep_t* const p_cep, + IN ib_mad_element_t* const p_mad, + IN ib_rej_status_t reason ) +{ + mad_cm_rej_t *p_rej; + + AL_ENTER( AL_DBG_CM ); + + p_rej = (mad_cm_rej_t*)p_mad->p_mad_buf; + + __format_mad_hdr( p_mad->p_mad_buf, p_cep, CM_REJ_ATTR_ID ); + + p_rej->local_comm_id = p_cep->local_comm_id; + p_rej->remote_comm_id = p_cep->remote_comm_id; + p_rej->reason = reason; + + switch( p_cep->state ) + { + case CEP_STATE_REQ_RCVD: + case CEP_STATE_REQ_MRA_SENT: + case CEP_STATE_PRE_REP: + case CEP_STATE_PRE_REP_MRA_SENT: + conn_rej_set_msg_rejected( 0, p_rej ); + break; + + case CEP_STATE_REP_RCVD: + case CEP_STATE_REP_MRA_SENT: + conn_rej_set_msg_rejected( 1, p_rej ); + break; + + default: + CL_ASSERT( reason == IB_REJ_TIMEOUT ); + conn_rej_set_msg_rejected( 2, p_rej ); + break; + } + + conn_rej_clr_rsvd_fields( p_rej ); + __cep_send_mad( p_port_cep, p_mad ); + + AL_EXIT( AL_DBG_CM ); +} + + +static void +__reject_timeout( + IN cep_agent_t* const p_port_cep, + IN kcep_t* const p_cep, + IN const ib_mad_element_t* const p_mad ) +{ + ib_api_status_t status; + ib_mad_element_t *p_rej_mad; + ib_mad_t *p_mad_buf; + ib_grh_t *p_grh; + + AL_ENTER( AL_DBG_CM ); + + status = ib_get_mad( p_port_cep->pool_key, MAD_BLOCK_SIZE, &p_rej_mad ); + if( status != IB_SUCCESS ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("ib_get_mad returned %s\n", ib_get_err_str( status )) ); + return; + } + + /* Save the buffer pointers from the new element. */ + p_mad_buf = p_rej_mad->p_mad_buf; + p_grh = p_rej_mad->p_grh; + + /* + * Copy the input MAD element to the reject - this gives us + * all appropriate addressing information. + */ + cl_memcpy( p_rej_mad, p_mad, sizeof(ib_mad_element_t) ); + cl_memcpy( p_grh, p_mad->p_grh, sizeof(ib_grh_t) ); + + /* Restore the buffer pointers now that the copy is complete. */ + p_rej_mad->p_mad_buf = p_mad_buf; + p_rej_mad->p_grh = p_grh; + + status = conn_rej_set_pdata( NULL, 0, (mad_cm_rej_t*)p_mad_buf ); + CL_ASSERT( status == IB_SUCCESS ); + + /* Copy the local CA GUID into the ARI. */ + switch( p_mad->p_mad_buf->attr_id ) + { + case CM_REQ_ATTR_ID: + status = conn_rej_set_ari( + (uint8_t*)&p_cep->local_ca_guid, + sizeof(p_cep->local_ca_guid), (mad_cm_rej_t*)p_mad_buf ); + CL_ASSERT( status == IB_SUCCESS ); + __reject_mad( p_port_cep, p_cep, p_rej_mad, IB_REJ_TIMEOUT ); + break; + + case CM_REP_ATTR_ID: + status = conn_rej_set_ari( + (uint8_t*)&p_cep->local_ca_guid, + sizeof(p_cep->local_ca_guid), (mad_cm_rej_t*)p_mad_buf ); + CL_ASSERT( status == IB_SUCCESS ); + __reject_mad( p_port_cep, p_cep, p_rej_mad, IB_REJ_TIMEOUT ); + break; + + default: + CL_ASSERT( p_mad->p_mad_buf->attr_id == CM_REQ_ATTR_ID || + p_mad->p_mad_buf->attr_id == CM_REP_ATTR_ID ); + ib_put_mad( p_rej_mad ); + return; + } + + AL_EXIT( AL_DBG_CM ); +} + + +static void +__reject_req( + IN cep_agent_t* const p_port_cep, + IN ib_mad_element_t* const p_mad, + IN const ib_rej_status_t reason ) +{ + mad_cm_req_t *p_req; + mad_cm_rej_t *p_rej; + + AL_ENTER( AL_DBG_CM ); + + CL_ASSERT( p_port_cep ); + CL_ASSERT( p_mad ); + CL_ASSERT( reason != 0 ); + + p_req = (mad_cm_req_t*)p_mad->p_mad_buf; + p_rej = (mad_cm_rej_t*)p_mad->p_mad_buf; + + /* + * Format the reject information, overwriting the REQ data and send + * the response. + */ + p_rej->hdr.attr_id = CM_REJ_ATTR_ID; + p_rej->remote_comm_id = p_req->local_comm_id; + p_rej->local_comm_id = 0; + conn_rej_set_msg_rejected( 0, p_rej ); + p_rej->reason = reason; + conn_rej_set_ari( NULL, 0, p_rej ); + conn_rej_set_pdata( NULL, 0, p_rej ); + conn_rej_clr_rsvd_fields( p_rej ); + + p_mad->retry_cnt = 0; + p_mad->send_opt = 0; + p_mad->timeout_ms = 0; + p_mad->resp_expected = FALSE; + + __cep_send_mad( p_port_cep, p_mad ); + + AL_EXIT( AL_DBG_CM ); +} + + +static void +__format_req_av( + IN kcep_t* const p_cep, + IN const mad_cm_req_t* const p_req, + IN const uint8_t idx ) +{ + cep_agent_t *p_port_cep; + const req_path_info_t *p_path; + + AL_ENTER( AL_DBG_CM ); + + CL_ASSERT( p_cep ); + CL_ASSERT( p_req ); + + cl_memclr( &p_cep->av[idx], sizeof(kcep_av_t) ); + + p_path = &((&p_req->primary_path)[idx]); + + p_port_cep = __find_port_cep( &p_path->remote_gid, + p_path->remote_lid, p_req->pkey, &p_cep->av[idx].pkey_index ); + if( !p_port_cep ) + { + if( !idx ) + p_cep->local_ca_guid = 0; + AL_EXIT( AL_DBG_CM ); + return; + } + + if( !idx ) + p_cep->local_ca_guid = p_port_cep->h_ca->obj.p_ci_ca->verbs.guid; + + /* Check that CA GUIDs match if formatting the alternate path. */ + if( idx && + p_port_cep->h_ca->obj.p_ci_ca->verbs.guid != p_cep->local_ca_guid ) + { + AL_EXIT( AL_DBG_CM ); + return; + } + + /* + * Pkey indeces must match if formating the alternat path - the QP + * modify structure only allows for a single PKEY index to be specified. + */ + if( idx && + p_cep->av[0].pkey_index != p_cep->av[1].pkey_index ) + { + AL_EXIT( AL_DBG_CM ); + return; + } + + p_cep->av[idx].port_guid = p_port_cep->port_guid; + p_cep->av[idx].attr.port_num = p_port_cep->port_num; + + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_CM, ("Received REQ SL %d", conn_req_path_get_svc_lvl( p_path )) ); + p_cep->av[idx].attr.sl = conn_req_path_get_svc_lvl( p_path ); + p_cep->av[idx].attr.dlid = p_path->local_lid; + + if( !conn_req_path_get_subn_lcl( p_path ) ) + { + p_cep->av[idx].attr.grh_valid = TRUE; + p_cep->av[idx].attr.grh.ver_class_flow = ib_grh_set_ver_class_flow( + 1, p_path->traffic_class, conn_req_path_get_flow_lbl( p_path ) ); + p_cep->av[idx].attr.grh.hop_limit = p_path->hop_limit; + p_cep->av[idx].attr.grh.dest_gid = p_path->local_gid; + p_cep->av[idx].attr.grh.src_gid = p_path->remote_gid; + } + else + { + p_cep->av[idx].attr.grh_valid = FALSE; + } + p_cep->av[idx].attr.static_rate = conn_req_path_get_pkt_rate( p_path ); + p_cep->av[idx].attr.path_bits = + (uint8_t)(p_path->remote_lid - p_port_cep->base_lid); + + /* + * Note that while we never use the connected AV attributes internally, + * we store them so we can pass them back to users. + */ + p_cep->av[idx].attr.conn.path_mtu = conn_req_get_mtu( p_req ); + p_cep->av[idx].attr.conn.local_ack_timeout = + conn_req_path_get_lcl_ack_timeout( p_path ); + p_cep->av[idx].attr.conn.seq_err_retry_cnt = + conn_req_get_retry_cnt( p_req ); + p_cep->av[idx].attr.conn.rnr_retry_cnt = + conn_req_get_rnr_retry_cnt( p_req ); + + AL_EXIT( AL_DBG_CM ); +} + + +/* + * + Validates the path information provided in the REQ and stores the + * associated CA attributes and port indeces. + * + Transitions a connection object from active to passive in the peer case. + * + Sets the path information in the connection and sets the CA GUID + * in the REQ callback record. + */ +static void +__save_wire_req( + IN OUT kcep_t* const p_cep, + IN OUT mad_cm_req_t* const p_req ) +{ + AL_ENTER( AL_DBG_CM ); + + p_cep->state = CEP_STATE_REQ_RCVD; + p_cep->was_active = FALSE; + + p_cep->sid = p_req->sid; + + /* Store pertinent information in the connection. */ + p_cep->remote_comm_id = p_req->local_comm_id; + p_cep->remote_ca_guid = p_req->local_ca_guid; + + p_cep->remote_qpn = conn_req_get_lcl_qpn( p_req ); + p_cep->local_qpn = 0; + + p_cep->retry_timeout = + __calc_mad_timeout( conn_req_get_lcl_resp_timeout( p_req ) ); + + /* Store the retry count. */ + p_cep->max_cm_retries = conn_req_get_max_cm_retries( p_req ); + + /* + * Copy the paths from the req_rec into the connection for + * future use. Note that if the primary path is invalid, + * the REP will fail. + */ + __format_req_av( p_cep, p_req, 0 ); + + if( p_req->alternate_path.local_lid ) + __format_req_av( p_cep, p_req, 1 ); + else + cl_memclr( &p_cep->av[1], sizeof(kcep_av_t) ); + + p_cep->idx_primary = 0; + + /* Store the maximum packet lifetime, used to calculate timewait. */ + p_cep->max_2pkt_life = conn_req_path_get_lcl_ack_timeout( &p_req->primary_path ); + p_cep->max_2pkt_life = max( p_cep->max_2pkt_life, + conn_req_path_get_lcl_ack_timeout( &p_req->alternate_path ) ); + + /* + * Make sure the target ack delay is cleared - the above + * "packet life" includes it. + */ + p_cep->target_ack_delay = 0; + + /* Store the requested initiator depth. */ + p_cep->resp_res = conn_req_get_init_depth( p_req ); + + /* + * Store the provided responder resources. These turn into the local + * QP's initiator depth. + */ + p_cep->init_depth = conn_req_get_resp_res( p_req ); + + p_cep->sq_psn = conn_req_get_starting_psn( p_req ); + + p_cep->tid = p_req->hdr.trans_id; + /* copy mad info for cm handoff */ + /* TODO: Do need to support CM handoff? */ + //p_cep->mads.req = *p_req; + + /* Cache the private data. */ + p_cep->psize = IB_REQ_PDATA_SIZE; + memcpy( p_cep->pdata, p_req->pdata, IB_REQ_PDATA_SIZE ); + + AL_EXIT( AL_DBG_CM ); +} + + +/* Must be called with the CEP lock held. */ +static void +__repeat_mad( + IN cep_agent_t* const p_port_cep, + IN kcep_t* const p_cep, + IN ib_mad_element_t* const p_mad ) +{ + AL_ENTER( AL_DBG_CM ); + + CL_ASSERT( p_port_cep ); + CL_ASSERT( p_cep ); + CL_ASSERT( p_mad ); + + /* Repeat the last mad sent for the connection. */ + switch( p_cep->state ) + { + case CEP_STATE_REQ_MRA_SENT: /* resend MRA(REQ) */ + case CEP_STATE_REP_MRA_SENT: /* resend MRA(REP) */ + case CEP_STATE_LAP_MRA_SENT: /* resend MRA(LAP) */ + case CEP_STATE_ESTABLISHED: /* resend RTU */ + case CEP_STATE_TIMEWAIT: /* resend the DREP */ + cl_memcpy( p_mad->p_mad_buf, &p_cep->mads, MAD_BLOCK_SIZE ); + p_mad->send_context1 = NULL; + p_mad->send_context2 = NULL; + __cep_send_mad( p_port_cep, p_mad ); + break; + + default: + /* Return the MAD to the mad pool */ + ib_put_mad( p_mad ); + break; + } + + AL_EXIT( AL_DBG_CM ); +} + + +static ib_api_status_t +__process_rej( + IN kcep_t* const p_cep, + IN ib_mad_element_t* const p_mad ) +{ + ib_api_status_t status; + mad_cm_rej_t *p_rej; + + AL_ENTER( AL_DBG_CM ); + + ASSERT( p_cep ); + ASSERT( p_mad ); + ASSERT( p_mad->p_mad_buf ); + + p_rej = (mad_cm_rej_t*)p_mad->p_mad_buf; + + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_CM, + ("Request rejected p_rej %p, reason - %d.\n", + p_rej, cl_ntoh16(p_rej->reason) ) ); + + switch( p_cep->state ) + { + case CEP_STATE_REQ_SENT: + /* + * Ignore rejects with the status set to IB_REJ_INVALID_SID. We will + * continue to retry (up to max_cm_retries) to connect to the remote + * side. This is required to support peer-to-peer connections. + */ + if( p_cep->p2p && p_rej->reason == IB_REJ_INVALID_SID ) + { + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_CM, + ("Request rejected (invalid SID) - retrying.\n") ); + goto err1; + } + + /* Fall through */ + case CEP_STATE_REP_SENT: + case CEP_STATE_REQ_MRA_RCVD: + case CEP_STATE_REP_MRA_RCVD: + /* Cancel any outstanding MAD. */ + if( p_cep->p_send_mad ) + { + ib_cancel_mad( p_cep->h_mad_svc, p_cep->p_send_mad ); + p_cep->p_send_mad = NULL; + } + + /* Fall through */ + case CEP_STATE_REP_RCVD: + case CEP_STATE_REQ_MRA_SENT: + case CEP_STATE_REP_MRA_SENT: + case CEP_STATE_PRE_REP: + case CEP_STATE_PRE_REP_MRA_SENT: + if( p_cep->state & CEP_STATE_PREP ) + { + CL_ASSERT( p_cep->p_mad ); + ib_put_mad( p_cep->p_mad ); + p_cep->p_mad = NULL; + } + /* Abort connection establishment. No transition to timewait. */ + __remove_cep( p_cep ); + p_cep->state = CEP_STATE_IDLE; + break; + + case CEP_STATE_REQ_RCVD: + __remove_cep( p_cep ); + p_cep->state = CEP_STATE_IDLE; + ib_put_mad( p_mad ); + AL_EXIT( AL_DBG_CM ); + return IB_NO_MATCH; + + case CEP_STATE_ESTABLISHED: + case CEP_STATE_LAP_RCVD: + case CEP_STATE_LAP_SENT: + case CEP_STATE_LAP_MRA_RCVD: + case CEP_STATE_LAP_MRA_SENT: + case CEP_STATE_PRE_APR: + case CEP_STATE_PRE_APR_MRA_SENT: + if( p_cep->state & CEP_STATE_PREP ) + { + CL_ASSERT( p_cep->p_mad ); + ib_put_mad( p_cep->p_mad ); + p_cep->p_mad = NULL; + } + p_cep->state = CEP_STATE_TIMEWAIT; + __insert_timewait( p_cep ); + break; + + default: + /* Ignore the REJ. */ + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_CM, ("REJ received in invalid state.\n") ); +err1: + ib_put_mad( p_mad ); + AL_EXIT( AL_DBG_CM ); + return IB_NO_MATCH; + } + + /* Cache the private data. */ + p_cep->psize = IB_REJ_PDATA_SIZE; + memcpy( p_cep->pdata, p_rej->pdata, IB_REJ_PDATA_SIZE ); + + status = __cep_queue_mad( p_cep, p_mad ); + + AL_EXIT( AL_DBG_CM ); + return status; +} + + +static ib_api_status_t +__process_stale( + IN kcep_t* const p_cep ) +{ + ib_api_status_t status; + cep_agent_t *p_port_cep; + ib_mad_element_t *p_mad; + mad_cm_rej_t *p_rej; + + status = __cep_get_mad( p_cep, CM_REJ_ATTR_ID, &p_port_cep, &p_mad ); + if( status != IB_SUCCESS ) + return status; + + p_rej = ib_get_mad_buf( p_mad ); + + conn_rej_set_ari( NULL, 0, p_rej ); + conn_rej_set_pdata( NULL, 0, p_rej ); + + p_rej->local_comm_id = p_cep->remote_comm_id; + p_rej->remote_comm_id = p_cep->local_comm_id; + p_rej->reason = IB_REJ_STALE_CONN; + + switch( p_cep->state ) + { + case CEP_STATE_REQ_RCVD: + case CEP_STATE_REQ_MRA_SENT: + case CEP_STATE_PRE_REP: + case CEP_STATE_PRE_REP_MRA_SENT: + conn_rej_set_msg_rejected( 0, p_rej ); + break; + + case CEP_STATE_REQ_SENT: + case CEP_STATE_REP_RCVD: + case CEP_STATE_REP_MRA_SENT: + conn_rej_set_msg_rejected( 1, p_rej ); + break; + + default: + conn_rej_set_msg_rejected( 2, p_rej ); + break; + } + conn_rej_clr_rsvd_fields( p_rej ); + + return __process_rej( p_cep, p_mad ); +} + + +static void +__req_handler( + IN cep_agent_t* const p_port_cep, + IN ib_mad_element_t* const p_mad ) +{ + ib_api_status_t status = IB_SUCCESS; + mad_cm_req_t *p_req; + kcep_t *p_cep, *p_new_cep, *p_stale_cep = NULL; + KLOCK_QUEUE_HANDLE hdl; + ib_rej_status_t reason; + + AL_ENTER( AL_DBG_CM ); + + CL_ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL ); + + p_req = (mad_cm_req_t*)p_mad->p_mad_buf; + + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_CM, + ("REQ: comm_id (x%x) qpn (x%x) received\n", + p_req->local_comm_id, conn_req_get_lcl_qpn( p_req )) ); + + KeAcquireInStackQueuedSpinLockAtDpcLevel( &gp_cep_mgr->lock, &hdl ); + + if( conn_req_get_qp_type( p_req ) > IB_QPT_UNRELIABLE_CONN || + conn_req_get_lcl_qpn( p_req ) == 0 ) + { + /* Reserved value. Reject. */ + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("Invalid transport type received.\n") ); + reason = IB_REJ_INVALID_XPORT; + goto reject; + } + + /* Match against pending connections using remote comm ID and CA GUID. */ + p_cep = __lookup_by_id( p_req->local_comm_id, p_req->local_ca_guid ); + if( p_cep ) + { + /* Already received the REQ. */ + switch( p_cep->state ) + { + case CEP_STATE_REQ_MRA_SENT: + __repeat_mad( p_port_cep, p_cep, p_mad ); + break; + + case CEP_STATE_TIMEWAIT: + case CEP_STATE_DESTROY: + /* Send a reject. */ + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_CM, + ("REQ received for connection in TIME_WAIT state.\n") ); + __reject_req( p_port_cep, p_mad, IB_REJ_STALE_CONN ); + break; + + default: + /* + * Let regular retries repeat the MAD. If our last message was + * dropped, resending only adds to the congestion. If it wasn't + * dropped, then the remote CM will eventually process it, and + * we'd just be adding traffic. + */ + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_CM, ("Duplicate REQ received.\n") ); + ib_put_mad( p_mad ); + } + KeReleaseInStackQueuedSpinLockFromDpcLevel( &hdl ); + AL_EXIT( AL_DBG_CM ); + return; + } + + /* + * Match against listens using SID and compare data, also provide the receiving + * MAD service's port GUID so we can properly filter. + */ + p_cep = __lookup_listen( p_req->sid, p_port_cep->port_guid, p_req->pdata ); + if( p_cep ) + { + /* + * Allocate a new CEP for the new request. This will + * prevent multiple identical REQs from queueing up for processing. + */ + p_new_cep = __create_cep(); + if( !p_new_cep ) + { + /* Reject the request for insufficient resources. */ + reason = IB_REJ_INSUF_RESOURCES; + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("__create_cep failed\nREJ sent for insufficient resources.\n") ); + goto reject; + } + + __save_wire_req( p_new_cep, p_req ); + + __bind_cep( p_new_cep, p_cep->p_cid->h_al, p_cep->pfn_cb, NULL ); + AL_PRINT( TRACE_LEVEL_VERBOSE, AL_DBG_CM, + ("Created CEP with CID = %d, h_al %p, remote = %d\n", + p_new_cep->cid, p_cep->p_cid->h_al, p_new_cep->remote_comm_id) ); + + /* Add the new CEP to the map so that repeated REQs match up. */ + p_stale_cep = __insert_cep( p_new_cep ); + if( p_stale_cep != p_new_cep ) + { + /* Duplicate - must be a stale connection. */ + reason = IB_REJ_STALE_CONN; + /* Fail the local stale CEP. */ + status = __process_stale( p_stale_cep ); + goto unbind; + } + + /* __cep_queue_mad may complete a pending IRP */ + p_mad->send_context1 = p_new_cep; + + /* + * Queue the mad - the return value indicates whether we should + * invoke the callback. + */ + status = __cep_queue_mad( p_cep, p_mad ); + switch( status ) + { + case IB_SUCCESS: + case IB_PENDING: + break; + + case IB_UNSUPPORTED: + p_mad->send_context1 = NULL; + reason = IB_REJ_USER_DEFINED; + goto unbind; + + default: + p_mad->send_context1 = NULL; + reason = IB_REJ_INSUF_RESOURCES; + goto unbind; + } + } + else + { + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_CM, ("No listens active!\n") ); + + /* Match against peer-to-peer requests using SID and compare data. */ + //p_cep = __lookup_peer(); + //if( p_cep ) + //{ + // p_mad->send_context2 = NULL; + // p_list_item = cl_qlist_find_from_head( &gp_cep_mgr->pending_list, + // __match_peer, p_req ); + // if( p_list_item != cl_qlist_end( &gp_cep_mgr->pending_list ) ) + // { + // KeReleaseInStackQueuedSpinLockFromDpcLevel( &hdl ); + // p_conn = PARENT_STRUCT( p_list_item, kcep_t, map_item ); + // __peer_req( p_port_cep, p_conn, p_async_mad->p_mad ); + // cl_free( p_async_mad ); + // AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM, + // ("REQ matched a peer-to-peer request.\n") ); + // return; + // } + // reason = IB_REJ_INVALID_SID; + // goto free; + //} + //else + { + /* No match found. Reject. */ + reason = IB_REJ_INVALID_SID; + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_CM, ("REQ received but no match found.\n") ); + goto reject; + } + } + + KeReleaseInStackQueuedSpinLockFromDpcLevel( &hdl ); + + /* Process any queued MADs for the CEP. */ + if( status == IB_SUCCESS ) + __process_cep( p_cep ); + + AL_EXIT( AL_DBG_CM ); + return; + +unbind: + __unbind_cep( p_new_cep ); + + /* + * Move the CEP in the idle state so that we don't send a reject + * for it when cleaning up. Also clear the RQPN and RCID so that + * we don't try to remove it from our maps (since it isn't inserted). + */ + p_new_cep->state = CEP_STATE_IDLE; + p_new_cep->remote_comm_id = 0; + p_new_cep->remote_qpn = 0; + __cleanup_cep( p_new_cep ); + +reject: + __reject_req( p_port_cep, p_mad, reason ); + + KeReleaseInStackQueuedSpinLockFromDpcLevel( &hdl ); + + if( reason == IB_REJ_STALE_CONN && status == IB_SUCCESS ) + __process_cep( p_stale_cep ); + + AL_EXIT( AL_DBG_CM ); +} + + +static void +__save_wire_rep( + IN OUT kcep_t* const p_cep, + IN const mad_cm_rep_t* const p_rep ) +{ + AL_ENTER( AL_DBG_CM ); + + /* The send should have been cancelled during MRA processing. */ + p_cep->state = CEP_STATE_REP_RCVD; + + /* Store pertinent information in the connection. */ + p_cep->remote_comm_id = p_rep->local_comm_id; + p_cep->remote_ca_guid = p_rep->local_ca_guid; + + p_cep->remote_qpn = conn_rep_get_lcl_qpn( p_rep ); + + /* Store the remote endpoint's target ACK delay. */ + p_cep->target_ack_delay = conn_rep_get_target_ack_delay( p_rep ); + + /* Update the local ACK delay stored in the AV's. */ + p_cep->av[0].attr.conn.local_ack_timeout = calc_lcl_ack_timeout( + p_cep->av[0].attr.conn.local_ack_timeout, p_cep->target_ack_delay ); + p_cep->av[0].attr.conn.rnr_retry_cnt = conn_rep_get_rnr_retry_cnt( p_rep ); + + if( p_cep->av[1].port_guid ) + { + p_cep->av[1].attr.conn.local_ack_timeout = calc_lcl_ack_timeout( + p_cep->av[1].attr.conn.local_ack_timeout, + p_cep->target_ack_delay ); + p_cep->av[1].attr.conn.rnr_retry_cnt = + p_cep->av[0].attr.conn.rnr_retry_cnt; + } + + p_cep->init_depth = p_rep->resp_resources; + p_cep->resp_res = p_rep->initiator_depth; + + p_cep->sq_psn = conn_rep_get_starting_psn( p_rep ); + + /* Cache the private data. */ + p_cep->psize = IB_REP_PDATA_SIZE; + memcpy( p_cep->pdata, p_rep->pdata, IB_REP_PDATA_SIZE ); + + AL_EXIT( AL_DBG_CM ); +} + + +static void +__mra_handler( + IN ib_mad_element_t* const p_mad ) +{ + ib_api_status_t status; + mad_cm_mra_t *p_mra; + kcep_t *p_cep; + KLOCK_QUEUE_HANDLE hdl; + + AL_ENTER( AL_DBG_CM ); + + CL_ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL ); + + p_mra = (mad_cm_mra_t*)p_mad->p_mad_buf; + + KeAcquireInStackQueuedSpinLockAtDpcLevel( &gp_cep_mgr->lock, &hdl ); + p_cep = __lookup_cep( NULL, p_mra->remote_comm_id ); + if( !p_cep ) + { + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_CM, + ("MRA received that could not be matched.\n") ); + goto err; + } + + if( p_cep->remote_comm_id ) + { + if( p_cep->remote_comm_id != p_mra->local_comm_id ) + { + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_CM, + ("MRA received that could not be matched.\n") ); + goto err; + } + } + + /* + * Note that we don't update the CEP's remote comm ID - it messes up REP + * processing since a non-zero RCID implies the connection is in the RCID + * map. Adding it here requires checking there and conditionally adding + * it. Ignoring it is a valid thing to do. + */ + if( !(p_cep->state & CEP_STATE_SENT) || + (1 << conn_mra_get_msg_mraed( p_mra ) != + (p_cep->state & CEP_MSG_MASK)) ) + { + /* Invalid state. */ + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_CM, ("MRA received in invalid state.\n") ); + goto err; + } + + /* Delay the current send. */ + CL_ASSERT( p_cep->p_send_mad ); + ib_delay_mad( p_cep->h_mad_svc, p_cep->p_send_mad, + __calc_mad_timeout( conn_mra_get_svc_timeout( p_mra ) ) + + __calc_mad_timeout( p_cep->max_2pkt_life - 1 ) ); + + /* We only invoke a single callback for MRA. */ + if( p_cep->state & CEP_STATE_MRA ) + { + /* Invalid state. */ + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_CM, ("Already received MRA.\n") ); + goto err; + } + + p_cep->state |= CEP_STATE_MRA; + + status = __cep_queue_mad( p_cep, p_mad ); + + KeReleaseInStackQueuedSpinLockFromDpcLevel( &hdl ); + + if( status == IB_SUCCESS ) + __process_cep( p_cep ); + + AL_EXIT( AL_DBG_CM ); + return; + +err: + KeReleaseInStackQueuedSpinLockFromDpcLevel( &hdl ); + ib_put_mad( p_mad ); + AL_EXIT( AL_DBG_CM ); +} + + +static void +__rej_handler( + IN ib_mad_element_t* const p_mad ) +{ + ib_api_status_t status; + mad_cm_rej_t *p_rej; + kcep_t *p_cep = NULL; + KLOCK_QUEUE_HANDLE hdl; + net64_t ca_guid; + + AL_ENTER( AL_DBG_CM ); + + CL_ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL ); + + p_rej = (mad_cm_rej_t*)p_mad->p_mad_buf; + + /* Either one of the communication IDs must be set. */ + if( !p_rej->remote_comm_id && !p_rej->local_comm_id ) + goto err1; + + /* Check the pending list by the remote CA GUID and connection ID. */ + KeAcquireInStackQueuedSpinLockAtDpcLevel( &gp_cep_mgr->lock, &hdl ); + if( p_rej->remote_comm_id ) + { + p_cep = __lookup_cep( NULL, p_rej->remote_comm_id ); + } + else if( p_rej->reason == IB_REJ_TIMEOUT && + conn_rej_get_ari_len( p_rej ) == sizeof(net64_t) ) + { + cl_memcpy( &ca_guid, p_rej->ari, sizeof(net64_t) ); + p_cep = __lookup_by_id( p_rej->local_comm_id, ca_guid ); + } + + if( !p_cep ) + { + goto err2; + } + + if( p_cep->remote_comm_id && + p_cep->remote_comm_id != p_rej->local_comm_id ) + { + err2: + KeReleaseInStackQueuedSpinLockFromDpcLevel( &hdl ); + err1: + ib_put_mad( p_mad ); + AL_EXIT( AL_DBG_CM ); + return; + } + + status = __process_rej( p_cep, p_mad ); + + KeReleaseInStackQueuedSpinLockFromDpcLevel( &hdl ); + + if( status == IB_SUCCESS ) + __process_cep( p_cep ); + + AL_EXIT( AL_DBG_CM ); +} + + +static void +__rep_handler( + IN cep_agent_t* const p_port_cep, + IN ib_mad_element_t* const p_mad ) +{ + ib_api_status_t status; + mad_cm_rep_t *p_rep; + kcep_t *p_cep; + KLOCK_QUEUE_HANDLE hdl; + cep_state_t old_state; + + AL_ENTER( AL_DBG_CM ); + + CL_ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL ); + + p_rep = (mad_cm_rep_t*)p_mad->p_mad_buf; + + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_CM, + ("REP: comm_id (x%x) received\n", p_rep->local_comm_id ) ); + + KeAcquireInStackQueuedSpinLockAtDpcLevel( &gp_cep_mgr->lock, &hdl ); + p_cep = __lookup_cep( NULL, p_rep->remote_comm_id ); + if( !p_cep ) + { + KeReleaseInStackQueuedSpinLockFromDpcLevel( &hdl ); + ib_put_mad( p_mad ); + AL_PRINT_EXIT( TRACE_LEVEL_INFORMATION, AL_DBG_CM, + ("REP received that could not be matched.\n") ); + return; + } + + switch( p_cep->state ) + { + case CEP_STATE_REQ_MRA_RCVD: + case CEP_STATE_REQ_SENT: + old_state = p_cep->state; + /* Save pertinent information and change state. */ + __save_wire_rep( p_cep, p_rep ); + + if( __insert_cep( p_cep ) != p_cep ) + { + /* Roll back the state change. */ + __reject_mad( p_port_cep, p_cep, p_mad, IB_REJ_STALE_CONN ); + p_cep->state = old_state; + status = __process_stale( p_cep ); + } + else + { + /* + * Cancel any outstanding send. Note that we do this only after + * inserting the CEP - if we failed, then the send will timeout + * and we'll finish our way through the state machine. + */ + if( p_cep->p_send_mad ) + { + ib_cancel_mad( p_cep->h_mad_svc, p_cep->p_send_mad ); + p_cep->p_send_mad = NULL; + } + + status = __cep_queue_mad( p_cep, p_mad ); + } + + KeReleaseInStackQueuedSpinLockFromDpcLevel( &hdl ); + + if( status == IB_SUCCESS ) + __process_cep( p_cep ); + + AL_EXIT( AL_DBG_CM ); + return; + + case CEP_STATE_ESTABLISHED: + case CEP_STATE_LAP_RCVD: + case CEP_STATE_LAP_SENT: + case CEP_STATE_LAP_MRA_RCVD: + case CEP_STATE_LAP_MRA_SENT: + case CEP_STATE_REP_MRA_SENT: + /* Repeate the MRA or RTU. */ + __repeat_mad( p_port_cep, p_cep, p_mad ); + break; + + default: + ib_put_mad( p_mad ); + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_CM, ("REP received in invalid state.\n") ); + break; + } + + KeReleaseInStackQueuedSpinLockFromDpcLevel( &hdl ); + + AL_EXIT( AL_DBG_CM ); +} + + +static void +__rtu_handler( + IN ib_mad_element_t* const p_mad ) +{ + ib_api_status_t status; + mad_cm_rtu_t *p_rtu; + kcep_t *p_cep; + KLOCK_QUEUE_HANDLE hdl; + + AL_ENTER( AL_DBG_CM ); + + CL_ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL ); + + p_rtu = (mad_cm_rtu_t*)p_mad->p_mad_buf; + + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_CM, + ("RTU: comm_id (x%x) received\n", p_rtu->local_comm_id) ); + + /* Find the connection by local connection ID. */ + KeAcquireInStackQueuedSpinLockAtDpcLevel( &gp_cep_mgr->lock, &hdl ); + p_cep = __lookup_cep( NULL, p_rtu->remote_comm_id ); + if( !p_cep || p_cep->remote_comm_id != p_rtu->local_comm_id ) + { + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_CM, ("RTU received that could not be matched.\n") ); + goto done; + } + + switch( p_cep->state ) + { + case CEP_STATE_REP_SENT: + case CEP_STATE_REP_MRA_RCVD: + /* Cancel any outstanding send. */ + if( p_cep->p_send_mad ) + { + ib_cancel_mad( p_cep->h_mad_svc, p_cep->p_send_mad ); + p_cep->p_send_mad = NULL; + } + + p_cep->state = CEP_STATE_ESTABLISHED; + + status = __cep_queue_mad( p_cep, p_mad ); + + /* Update timewait time. */ + __calc_timewait( p_cep ); + + KeReleaseInStackQueuedSpinLockFromDpcLevel( &hdl ); + + if( status == IB_SUCCESS ) + __process_cep( p_cep ); + + AL_EXIT( AL_DBG_CM ); + return; + + default: + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_CM, ("RTU received in invalid state.\n") ); + break; + } + +done: + KeReleaseInStackQueuedSpinLockFromDpcLevel( &hdl ); + ib_put_mad( p_mad ); + AL_EXIT( AL_DBG_CM ); +} + + +static void +__dreq_handler( + IN cep_agent_t* const p_port_cep, + IN ib_mad_element_t* const p_mad ) +{ + ib_api_status_t status; + mad_cm_dreq_t *p_dreq; + kcep_t *p_cep; + KLOCK_QUEUE_HANDLE hdl; + + AL_ENTER( AL_DBG_CM ); + + CL_ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL ); + + p_dreq = (mad_cm_dreq_t*)p_mad->p_mad_buf; + + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_CM, + ("DREQ: comm_id (x%x) qpn (x%x) received\n", + p_dreq->local_comm_id, conn_dreq_get_remote_qpn( p_dreq )) ); + + /* Find the connection by connection IDs. */ + KeAcquireInStackQueuedSpinLockAtDpcLevel( &gp_cep_mgr->lock, &hdl ); + p_cep = __lookup_cep( NULL, p_dreq->remote_comm_id ); + if( !p_cep || + p_cep->remote_comm_id != p_dreq->local_comm_id || + p_cep->local_qpn != conn_dreq_get_remote_qpn( p_dreq ) ) + { + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_CM, ("DREQ received that could not be matched.\n") ); + KeReleaseInStackQueuedSpinLockFromDpcLevel( &hdl ); + ib_put_mad( p_mad ); + AL_EXIT( AL_DBG_CM ); + return; + } + + switch( p_cep->state ) + { + case CEP_STATE_REP_SENT: + case CEP_STATE_REP_MRA_RCVD: + case CEP_STATE_DREQ_SENT: + /* Cancel the outstanding MAD. */ + if( p_cep->p_send_mad ) + { + ib_cancel_mad( p_cep->h_mad_svc, p_cep->p_send_mad ); + p_cep->p_send_mad = NULL; + } + + /* Fall through and process as DREQ received case. */ + case CEP_STATE_ESTABLISHED: + case CEP_STATE_LAP_RCVD: + case CEP_STATE_LAP_SENT: + case CEP_STATE_LAP_MRA_RCVD: + case CEP_STATE_LAP_MRA_SENT: + p_cep->state = CEP_STATE_DREQ_RCVD; + + status = __cep_queue_mad( p_cep, p_mad ); + + /* Store the TID for use in the reply DREP. */ + p_cep->tid = p_dreq->hdr.trans_id; + + KeReleaseInStackQueuedSpinLockFromDpcLevel( &hdl ); + + if( status == IB_SUCCESS ) + __process_cep( p_cep ); + AL_EXIT( AL_DBG_CM ); + return; + + case CEP_STATE_TIMEWAIT: + case CEP_STATE_DESTROY: + /* Repeat the DREP. */ + __repeat_mad( p_port_cep, p_cep, p_mad ); + break; + + case CEP_STATE_DREQ_DESTROY: + /* Send the DREP with no private data. */ + + ib_put_mad( p_mad ); /* release DREQ MAD */ + + status = __cep_get_mad( p_cep, CM_DREP_ATTR_ID, &(cep_agent_t*)p_port_cep, + &(ib_mad_element_t*)p_mad ); + if( status != IB_SUCCESS ) + break; + + p_mad->p_mad_buf->attr_id = CM_DREP_ATTR_ID; + /* __format_drep returns always SUCCESS while no private data */ + __format_drep( p_cep, NULL, 0, (mad_cm_drep_t*)p_mad->p_mad_buf ); + __cep_send_mad( p_port_cep, p_mad ); + break; + + default: + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_CM, ("DREQ received in invalid state.\n") ); + case CEP_STATE_DREQ_RCVD: + ib_put_mad( p_mad ); + break; + } + + KeReleaseInStackQueuedSpinLockFromDpcLevel( &hdl ); + AL_EXIT( AL_DBG_CM ); +} + + +static void +__drep_handler( + IN ib_mad_element_t* const p_mad ) +{ + ib_api_status_t status; + mad_cm_drep_t *p_drep; + kcep_t *p_cep; + KLOCK_QUEUE_HANDLE hdl; + + AL_ENTER( AL_DBG_CM ); + + CL_ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL ); + + p_drep = (mad_cm_drep_t*)p_mad->p_mad_buf; + + /* Find the connection by local connection ID. */ + KeAcquireInStackQueuedSpinLockAtDpcLevel( &gp_cep_mgr->lock, &hdl ); + p_cep = __lookup_cep( NULL, p_drep->remote_comm_id ); + if( !p_cep || p_cep->remote_comm_id != p_drep->local_comm_id ) + { + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_CM, ("DREP received that could not be matched.\n") ); + KeReleaseInStackQueuedSpinLockFromDpcLevel( &hdl ); + ib_put_mad( p_mad ); + AL_EXIT( AL_DBG_CM ); + return; + } + + if( p_cep->state != CEP_STATE_DREQ_SENT && + p_cep->state != CEP_STATE_DREQ_DESTROY ) + { + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_CM, ("DREP received in invalid state.\n") ); + + KeReleaseInStackQueuedSpinLockFromDpcLevel( &hdl ); + ib_put_mad( p_mad ); + AL_EXIT( AL_DBG_CM ); + return; + } + + /* Cancel the DREQ. */ + if( p_cep->p_send_mad ) + { + ib_cancel_mad( p_cep->h_mad_svc, p_cep->p_send_mad ); + p_cep->p_send_mad = NULL; + } + + if( p_cep->state == CEP_STATE_DREQ_SENT ) + { + p_cep->state = CEP_STATE_TIMEWAIT; + + status = __cep_queue_mad( p_cep, p_mad ); + } + else + { + /* State is DREQ_DESTROY - move to DESTROY to allow cleanup. */ + CL_ASSERT( p_cep->state == CEP_STATE_DREQ_DESTROY ); + p_cep->state = CEP_STATE_DESTROY; + + ib_put_mad( p_mad ); + status = IB_INVALID_STATE; + } + + __insert_timewait( p_cep ); + + KeReleaseInStackQueuedSpinLockFromDpcLevel( &hdl ); + + if( status == IB_SUCCESS ) + __process_cep( p_cep ); + + AL_EXIT( AL_DBG_CM ); +} + + +static boolean_t +__format_lap_av( + IN kcep_t* const p_cep, + IN const lap_path_info_t* const p_path ) +{ + cep_agent_t *p_port_cep; + + AL_ENTER( AL_DBG_CM ); + + CL_ASSERT( p_cep ); + CL_ASSERT( p_path ); + + cl_memclr( &p_cep->alt_av, sizeof(kcep_av_t) ); + + p_port_cep = __find_port_cep( &p_path->remote_gid, p_path->remote_lid, + p_cep->pkey, &p_cep->alt_av.pkey_index ); + if( !p_port_cep ) + { + AL_EXIT( AL_DBG_CM ); + return FALSE; + } + + if( p_port_cep->h_ca->obj.p_ci_ca->verbs.guid != p_cep->local_ca_guid ) + { + AL_EXIT( AL_DBG_CM ); + return FALSE; + } + + p_cep->alt_av.port_guid = p_port_cep->port_guid; + p_cep->alt_av.attr.port_num = p_port_cep->port_num; + + p_cep->alt_av.attr.sl = conn_lap_path_get_svc_lvl( p_path ); + p_cep->alt_av.attr.dlid = p_path->local_lid; + + if( !conn_lap_path_get_subn_lcl( p_path ) ) + { + p_cep->alt_av.attr.grh_valid = TRUE; + p_cep->alt_av.attr.grh.ver_class_flow = ib_grh_set_ver_class_flow( + 1, conn_lap_path_get_tclass( p_path ), + conn_lap_path_get_flow_lbl( p_path ) ); + p_cep->alt_av.attr.grh.hop_limit = p_path->hop_limit; + p_cep->alt_av.attr.grh.dest_gid = p_path->local_gid; + p_cep->alt_av.attr.grh.src_gid = p_path->remote_gid; + } + else + { + p_cep->alt_av.attr.grh_valid = FALSE; + } + p_cep->alt_av.attr.static_rate = conn_lap_path_get_pkt_rate( p_path ); + p_cep->alt_av.attr.path_bits = + (uint8_t)(p_path->remote_lid - p_port_cep->base_lid); + + /* + * Note that while we never use the connected AV attributes internally, + * we store them so we can pass them back to users. For the LAP, we + * first copy the settings from the current primary - MTU and retry + * counts are only specified in the REQ. + */ + p_cep->alt_av.attr.conn = p_cep->av[p_cep->idx_primary].attr.conn; + p_cep->alt_av.attr.conn.local_ack_timeout = + conn_lap_path_get_lcl_ack_timeout( p_path ); + + AL_EXIT( AL_DBG_CM ); + return TRUE; +} + + +static void +__lap_handler( + IN cep_agent_t* const p_port_cep, + IN ib_mad_element_t* const p_mad ) +{ + ib_api_status_t status; + mad_cm_lap_t *p_lap; + kcep_t *p_cep; + KLOCK_QUEUE_HANDLE hdl; + + AL_ENTER( AL_DBG_CM ); + + CL_ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL ); + + p_lap = (mad_cm_lap_t*)p_mad->p_mad_buf; + + /* Find the connection by local connection ID. */ + KeAcquireInStackQueuedSpinLockAtDpcLevel( &gp_cep_mgr->lock, &hdl ); + p_cep = __lookup_cep( NULL, p_lap->remote_comm_id ); + if( !p_cep || p_cep->remote_comm_id != p_lap->local_comm_id ) + { + KeReleaseInStackQueuedSpinLockFromDpcLevel( &hdl ); + ib_put_mad( p_mad ); + AL_PRINT_EXIT( TRACE_LEVEL_INFORMATION, AL_DBG_CM, ("LAP received that could not be matched.\n") ); + return; + } + + switch( p_cep->state ) + { + case CEP_STATE_REP_SENT: + case CEP_STATE_REP_MRA_RCVD: + /* + * These two cases handle the RTU being dropped. Receipt of + * a LAP indicates that the connection is established. + */ + case CEP_STATE_ESTABLISHED: + /* + * We don't check for other "established" states related to + * alternate path management (CEP_STATE_LAP_RCVD, etc) + */ + + /* We only support receiving LAP if we took the passive role. */ + if( p_cep->was_active ) + { + ib_put_mad( p_mad ); + break; + } + + /* Store the transaction ID for use during the LAP exchange. */ + p_cep->tid = p_lap->hdr.trans_id; + + /* + * Copy the path record into the connection for use when + * sending the APR and loading the path. + */ + if( !__format_lap_av( p_cep, &p_lap->alternate_path ) ) + { + /* Trap an invalid path. */ + ib_put_mad( p_mad ); + break; + } + + p_cep->state = CEP_STATE_LAP_RCVD; + + status = __cep_queue_mad( p_cep, p_mad ); + + KeReleaseInStackQueuedSpinLockFromDpcLevel( &hdl ); + + if( status == IB_SUCCESS ) + __process_cep( p_cep ); + + AL_EXIT( AL_DBG_CM ); + return; + + case CEP_STATE_LAP_MRA_SENT: + __repeat_mad( p_port_cep, p_cep, p_mad ); + break; + + default: + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_CM, ("LAP received in invalid state.\n") ); + ib_put_mad( p_mad ); + break; + } + + KeReleaseInStackQueuedSpinLockFromDpcLevel( &hdl ); + AL_EXIT( AL_DBG_CM ); +} + + +static void +__apr_handler( + IN ib_mad_element_t* const p_mad ) +{ + ib_api_status_t status; + mad_cm_apr_t *p_apr; + kcep_t *p_cep; + KLOCK_QUEUE_HANDLE hdl; + + AL_ENTER( AL_DBG_CM ); + + CL_ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL ); + + p_apr = (mad_cm_apr_t*)p_mad->p_mad_buf; + + KeAcquireInStackQueuedSpinLockAtDpcLevel( &gp_cep_mgr->lock, &hdl ); + p_cep = __lookup_cep( NULL, p_apr->remote_comm_id ); + if( !p_cep || p_cep->remote_comm_id != p_apr->local_comm_id ) + { + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_CM, ("APR received that could not be matched.\n") ); + goto done; + } + + switch( p_cep->state ) + { + case CEP_STATE_LAP_SENT: + case CEP_STATE_LAP_MRA_RCVD: + /* Cancel sending the LAP. */ + if( p_cep->p_send_mad ) + { + ib_cancel_mad( p_cep->h_mad_svc, p_cep->p_send_mad ); + p_cep->p_send_mad = NULL; + } + + /* Copy the temporary alternate AV. */ + p_cep->av[(p_cep->idx_primary + 1) & 0x1] = p_cep->alt_av; + + /* Update the maximum packet lifetime. */ + p_cep->max_2pkt_life = max( p_cep->max_2pkt_life, p_cep->alt_2pkt_life ); + + /* Update the timewait time. */ + __calc_timewait( p_cep ); + + p_cep->state = CEP_STATE_ESTABLISHED; + + status = __cep_queue_mad( p_cep, p_mad ); + + KeReleaseInStackQueuedSpinLockFromDpcLevel( &hdl ); + + if( status == IB_SUCCESS ) + __process_cep( p_cep ); + + AL_EXIT( AL_DBG_CM ); + return; + + default: + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_CM, ("APR received in invalid state.\n") ); + break; + } + +done: + KeReleaseInStackQueuedSpinLockFromDpcLevel( &hdl ); + ib_put_mad( p_mad ); + AL_EXIT( AL_DBG_CM ); +} + + +static void +__cep_mad_recv_cb( + IN ib_mad_svc_handle_t h_mad_svc, + IN void *context, + IN ib_mad_element_t *p_mad ) +{ + cep_agent_t *p_port_cep; + ib_mad_t *p_hdr; + + AL_ENTER( AL_DBG_CM ); + + CL_ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL ); + + UNUSED_PARAM( h_mad_svc ); + p_port_cep = (cep_agent_t*)context; + + CL_ASSERT( p_mad->p_next == NULL ); + + p_hdr = (ib_mad_t*)p_mad->p_mad_buf; + + /* + * TODO: Add filtering in all the handlers for unsupported class version. + * See 12.6.7.2 Rejection Reason, code 31. + */ + + switch( p_hdr->attr_id ) + { + case CM_REQ_ATTR_ID: + __req_handler( p_port_cep, p_mad ); + break; + + case CM_MRA_ATTR_ID: + __mra_handler( p_mad ); + break; + + case CM_REJ_ATTR_ID: + __rej_handler( p_mad ); + break; + + case CM_REP_ATTR_ID: + __rep_handler( p_port_cep, p_mad ); + break; + + case CM_RTU_ATTR_ID: + __rtu_handler( p_mad ); + break; + + case CM_DREQ_ATTR_ID: + __dreq_handler( p_port_cep, p_mad ); + break; + + case CM_DREP_ATTR_ID: + __drep_handler( p_mad ); + break; + + case CM_LAP_ATTR_ID: + __lap_handler( p_port_cep, p_mad ); + break; + + case CM_APR_ATTR_ID: + __apr_handler( p_mad ); + break; + + case CM_SIDR_REQ_ATTR_ID: +// p_async_mad->item.pfn_callback = __process_cm_sidr_req; +// break; +// + case CM_SIDR_REP_ATTR_ID: +// p_async_mad->item.pfn_callback = __process_cm_sidr_rep; +// break; +// + default: + ib_put_mad( p_mad ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("Invalid CM MAD attribute ID.\n") ); + return; + } + + AL_EXIT( AL_DBG_CM ); +} + + +static inline cep_agent_t* +__get_cep_agent( + IN kcep_t* const p_cep ) +{ + cl_map_item_t *p_item; + + CL_ASSERT( p_cep ); + + /* Look up the primary CEP port agent */ + p_item = cl_qmap_get( &gp_cep_mgr->port_map, + p_cep->av[p_cep->idx_primary].port_guid ); + if( p_item == cl_qmap_end( &gp_cep_mgr->port_map ) ) + return NULL; + + return PARENT_STRUCT( p_item, cep_agent_t, item ); +} + + +static inline void +__format_mad_av( + OUT ib_mad_element_t* const p_mad, + IN kcep_av_t* const p_av ) +{ + /* Set the addressing information in the MAD. */ + p_mad->grh_valid = p_av->attr.grh_valid; + if( p_av->attr.grh_valid ) + cl_memcpy( p_mad->p_grh, &p_av->attr.grh, sizeof(ib_grh_t) ); + + p_mad->remote_sl = p_av->attr.sl; + p_mad->remote_lid = p_av->attr.dlid; + p_mad->path_bits = p_av->attr.path_bits; + p_mad->pkey_index = p_av->pkey_index; + p_mad->remote_qp = IB_QP1; + p_mad->send_opt = IB_SEND_OPT_SIGNALED; + p_mad->remote_qkey = IB_QP1_WELL_KNOWN_Q_KEY; + /* Let the MAD service manage the AV for us. */ + p_mad->h_av = NULL; +} + + +static ib_api_status_t +__cep_send_mad( + IN cep_agent_t* const p_port_cep, + IN ib_mad_element_t* const p_mad ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_CM ); + + CL_ASSERT( p_port_cep ); + CL_ASSERT( p_mad ); + + /* Use the mad's attributes already present */ + p_mad->resp_expected = FALSE; + p_mad->retry_cnt = 0; + p_mad->timeout_ms = 0; + + /* Clear the contexts since the send isn't associated with a CEP. */ + p_mad->context1 = NULL; + p_mad->context2 = NULL; + + status = ib_send_mad( p_port_cep->h_mad_svc, p_mad, NULL ); + if( status != IB_SUCCESS ) + { + ib_put_mad( p_mad ); + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("ib_send_mad failed with status %s.\n", ib_get_err_str(status)) ); + } + + AL_EXIT( AL_DBG_CM ); + return status; +} + + +static ib_api_status_t +__cep_send_retry( + IN cep_agent_t* const p_port_cep, + IN kcep_t* const p_cep, + IN ib_mad_element_t* const p_mad ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_CM ); + + CL_ASSERT( p_cep ); + CL_ASSERT( p_mad ); + CL_ASSERT( p_mad->p_mad_buf->attr_id == CM_REQ_ATTR_ID || + p_mad->p_mad_buf->attr_id == CM_REP_ATTR_ID || + p_mad->p_mad_buf->attr_id == CM_LAP_ATTR_ID || + p_mad->p_mad_buf->attr_id == CM_DREQ_ATTR_ID ); + + /* + * REQ, REP, and DREQ are retried until either a response is + * received or the operation times out. + */ + p_mad->resp_expected = TRUE; + p_mad->retry_cnt = p_cep->max_cm_retries; + p_mad->timeout_ms = p_cep->retry_timeout; + + CL_ASSERT( !p_cep->p_send_mad ); + + /* Store the mad & mad service handle in the CEP for cancelling. */ + p_cep->h_mad_svc = p_port_cep->h_mad_svc; + p_cep->p_send_mad = p_mad; + + /* reference the connection for which we are sending the MAD. */ + cl_atomic_inc( &p_cep->ref_cnt ); + + /* Set the context. */ + p_mad->context1 = p_cep; + p_mad->context2 = NULL; + + /* Fire in the hole! */ + status = ib_send_mad( p_cep->h_mad_svc, p_mad, NULL ); + if( status != IB_SUCCESS ) + { + /* + * Note that we don't need to check for destruction here since + * we're holding the global lock. + */ + cl_atomic_dec( &p_cep->ref_cnt ); + p_cep->p_send_mad = NULL; + ib_put_mad( p_mad ); + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("ib_send_mad failed with status %s.\n", ib_get_err_str(status)) ); + } + + AL_EXIT( AL_DBG_CM ); + return status; +} + + +static void +__cep_mad_send_cb( + IN ib_mad_svc_handle_t h_mad_svc, + IN void *context, + IN ib_mad_element_t *p_mad ) +{ + ib_api_status_t status; + cep_agent_t *p_port_cep; + kcep_t *p_cep; + KLOCK_QUEUE_HANDLE hdl; + ib_pfn_destroy_cb_t pfn_destroy_cb; + void *cep_context; + + AL_ENTER( AL_DBG_CM ); + + UNUSED_PARAM( h_mad_svc ); + CL_ASSERT( p_mad->p_next == NULL ); + CL_ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL ); + + p_port_cep = (cep_agent_t*)context; + + p_cep = (kcep_t*)p_mad->context1; + + /* The cep context is only set for MADs that are retried. */ + if( !p_cep ) + { + ib_put_mad( p_mad ); + AL_EXIT( AL_DBG_CM ); + return; + } + + CL_ASSERT( p_mad->status != IB_WCS_SUCCESS ); + p_mad->context1 = NULL; + + KeAcquireInStackQueuedSpinLockAtDpcLevel( &gp_cep_mgr->lock, &hdl ); + if( p_cep->p_send_mad != p_mad ) + { + KeReleaseInStackQueuedSpinLockFromDpcLevel( &hdl ); + ib_put_mad( p_mad ); + goto done; + } + + /* Clear the sent MAD pointer so that we don't try cancelling again. */ + p_cep->p_send_mad = NULL; + + switch( p_cep->state ) + { + case CEP_STATE_REQ_SENT: + case CEP_STATE_REQ_MRA_RCVD: + case CEP_STATE_REP_SENT: + case CEP_STATE_REP_MRA_RCVD: + /* Send the REJ. */ + __reject_timeout( p_port_cep, p_cep, p_mad ); + __remove_cep( p_cep ); + p_cep->state = CEP_STATE_IDLE; + break; + + case CEP_STATE_DREQ_DESTROY: + p_cep->state = CEP_STATE_DESTROY; + __insert_timewait( p_cep ); + /* Fall through. */ + + case CEP_STATE_DESTROY: + KeReleaseInStackQueuedSpinLockFromDpcLevel( &hdl ); + ib_put_mad( p_mad ); + goto done; + + case CEP_STATE_DREQ_SENT: + /* + * Make up a DREP mad so we can respond if we receive + * a DREQ while in timewait. + */ + __format_mad_hdr( &p_cep->mads.drep.hdr, p_cep, CM_DREP_ATTR_ID ); + __format_drep( p_cep, NULL, 0, &p_cep->mads.drep ); + p_cep->state = CEP_STATE_TIMEWAIT; + __insert_timewait( p_cep ); + break; + + case CEP_STATE_LAP_SENT: + /* + * Before CEP was sent, we have been in CEP_STATE_ESTABLISHED as we + * failed to send, we return to that state. + */ + p_cep->state = CEP_STATE_ESTABLISHED; + break; + default: + break; + } + + status = __cep_queue_mad( p_cep, p_mad ); + CL_ASSERT( status != IB_INVALID_STATE ); + KeReleaseInStackQueuedSpinLockFromDpcLevel( &hdl ); + + if( status == IB_SUCCESS ) + __process_cep( p_cep ); + +done: + pfn_destroy_cb = p_cep->pfn_destroy_cb; + cep_context = p_cep->context; + + if( !cl_atomic_dec( &p_cep->ref_cnt ) && pfn_destroy_cb ) + pfn_destroy_cb( cep_context ); + AL_EXIT( AL_DBG_CM ); +} + + +static void +__cep_qp_event_cb( + IN ib_async_event_rec_t *p_event_rec ) +{ + UNUSED_PARAM( p_event_rec ); + + /* + * Most of the QP events are trapped by the real owner of the QP. + * For real events, the CM may not be able to do much anyways! + */ +} + + +static ib_api_status_t +__init_data_svc( + IN cep_agent_t* const p_port_cep, + IN const ib_port_attr_t* const p_port_attr ) +{ + ib_api_status_t status; + ib_qp_create_t qp_create; + ib_mad_svc_t mad_svc; + + AL_ENTER( AL_DBG_CM ); + + /* + * Create the PD alias. We use the port CM's al_obj_t as the context + * to allow using deref_al_obj as the destroy callback. + */ + status = ib_alloc_pd( p_port_cep->h_ca, IB_PDT_ALIAS, &p_port_cep->obj, + &p_port_cep->h_pd ); + if( status != IB_SUCCESS ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("ib_alloc_pd failed with status %s\n", ib_get_err_str(status)) ); + return status; + } + /* Reference the port object on behalf of the PD. */ + ref_al_obj( &p_port_cep->obj ); + + /* Create the MAD QP. */ + cl_memclr( &qp_create, sizeof( ib_qp_create_t ) ); + qp_create.qp_type = IB_QPT_QP1_ALIAS; + qp_create.rq_depth = CEP_MAD_RQ_DEPTH; + qp_create.sq_depth = CEP_MAD_SQ_DEPTH; + qp_create.rq_sge = CEP_MAD_RQ_SGE; + qp_create.sq_sge = CEP_MAD_SQ_SGE; + qp_create.sq_signaled = TRUE; + /* + * We use the port CM's al_obj_t as the context to allow using + * deref_al_obj as the destroy callback. + */ + status = ib_get_spl_qp( p_port_cep->h_pd, p_port_attr->port_guid, + &qp_create, &p_port_cep->obj, __cep_qp_event_cb, &p_port_cep->pool_key, + &p_port_cep->h_qp ); + if( status != IB_SUCCESS ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("ib_get_spl_qp failed with status %s\n", ib_get_err_str(status)) ); + return status; + } + /* Reference the port object on behalf of the QP. */ + ref_al_obj( &p_port_cep->obj ); + + /* Create the MAD service. */ + cl_memclr( &mad_svc, sizeof(mad_svc) ); + mad_svc.mad_svc_context = p_port_cep; + mad_svc.pfn_mad_recv_cb = __cep_mad_recv_cb; + mad_svc.pfn_mad_send_cb = __cep_mad_send_cb; + mad_svc.support_unsol = TRUE; + mad_svc.mgmt_class = IB_MCLASS_COMM_MGMT; + mad_svc.mgmt_version = IB_MCLASS_CM_VER_2; + mad_svc.method_array[IB_MAD_METHOD_SEND] = TRUE; + status = + ib_reg_mad_svc( p_port_cep->h_qp, &mad_svc, &p_port_cep->h_mad_svc ); + if( status != IB_SUCCESS ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("ib_reg_mad_svc failed with status %s\n", ib_get_err_str(status)) ); + return status; + } + + AL_EXIT( AL_DBG_CM ); + return IB_SUCCESS; +} + + +/* + * Performs immediate cleanup of resources. + */ +static void +__destroying_port_cep( + IN al_obj_t *p_obj ) +{ + cep_agent_t *p_port_cep; + KLOCK_QUEUE_HANDLE hdl; + ib_port_attr_mod_t port_attr_mod; + + AL_ENTER( AL_DBG_CM ); + + p_port_cep = PARENT_STRUCT( p_obj, cep_agent_t, obj ); + + if( p_port_cep->port_guid ) + { + KeAcquireInStackQueuedSpinLock( &gp_cep_mgr->lock, &hdl ); + cl_qmap_remove_item( &gp_cep_mgr->port_map, &p_port_cep->item ); + KeReleaseInStackQueuedSpinLock( &hdl ); + } + + if( p_port_cep->h_qp ) + { + ib_destroy_qp( p_port_cep->h_qp, (ib_pfn_destroy_cb_t)deref_al_obj ); + p_port_cep->h_qp = NULL; + } + + if( p_port_cep->h_pd ) + { + ib_dealloc_pd( p_port_cep->h_pd, (ib_pfn_destroy_cb_t)deref_al_obj ); + p_port_cep->h_pd = NULL; + } + + if( p_port_cep->h_ca ) + { + /* Update local port attributes */ + port_attr_mod.cap.cm = FALSE; + ib_modify_ca( p_port_cep->h_ca, p_port_cep->port_num, + IB_CA_MOD_IS_CM_SUPPORTED, &port_attr_mod ); + deref_al_obj( &p_port_cep->h_ca->obj ); + p_port_cep->h_ca = NULL; + } + + AL_EXIT( AL_DBG_CM ); +} + + + +/* + * Release all resources allocated by a port CM agent. Finishes any cleanup + * for a port agent. + */ +static void +__free_port_cep( + IN al_obj_t *p_obj ) +{ + cep_agent_t *p_port_cep; + + AL_ENTER( AL_DBG_CM ); + + p_port_cep = PARENT_STRUCT( p_obj, cep_agent_t, obj ); + destroy_al_obj( &p_port_cep->obj ); + cl_free( p_port_cep ); + + AL_EXIT( AL_DBG_CM ); +} + + +/* + * Create a port agent for a given port. + */ +static ib_api_status_t +__create_port_cep( + IN ib_pnp_port_rec_t *p_pnp_rec ) +{ + cep_agent_t *p_port_cep; + ib_api_status_t status; + ib_port_attr_mod_t port_attr_mod; + KLOCK_QUEUE_HANDLE hdl; + + AL_ENTER( AL_DBG_CM ); + + /* calculate size of port_cm struct */ + p_port_cep = (cep_agent_t*)cl_zalloc( sizeof(cep_agent_t) ); + if( !p_port_cep ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("Failed to cl_zalloc port CM agent.\n") ); + return IB_INSUFFICIENT_MEMORY; + } + + construct_al_obj( &p_port_cep->obj, AL_OBJ_TYPE_CM ); + + status = init_al_obj( &p_port_cep->obj, p_port_cep, TRUE, + __destroying_port_cep, NULL, __free_port_cep ); + if( status != IB_SUCCESS ) + { + __free_port_cep( &p_port_cep->obj ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("init_al_obj failed with status %s.\n", ib_get_err_str(status)) ); + return status; + } + + /* Attach to the global CM object. */ + status = attach_al_obj( &gp_cep_mgr->obj, &p_port_cep->obj ); + if( status != IB_SUCCESS ) + { + p_port_cep->obj.pfn_destroy( &p_port_cep->obj, NULL ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("attach_al_obj returned %s.\n", ib_get_err_str(status)) ); + return status; + } + + p_port_cep->port_guid = p_pnp_rec->p_port_attr->port_guid; + p_port_cep->port_num = p_pnp_rec->p_port_attr->port_num; + p_port_cep->base_lid = p_pnp_rec->p_port_attr->lid; + + KeAcquireInStackQueuedSpinLock( &gp_cep_mgr->lock, &hdl ); + cl_qmap_insert( + &gp_cep_mgr->port_map, p_port_cep->port_guid, &p_port_cep->item ); + KeReleaseInStackQueuedSpinLock( &hdl ); + + /* Get a reference to the CA on which we are loading. */ + p_port_cep->h_ca = acquire_ca( p_pnp_rec->p_ca_attr->ca_guid ); + if( !p_port_cep->h_ca ) + { + p_port_cep->obj.pfn_destroy( &p_port_cep->obj, NULL ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("acquire_ca failed.\n") ); + return IB_INVALID_GUID; } + + status = __init_data_svc( p_port_cep, p_pnp_rec->p_port_attr ); + if( status != IB_SUCCESS ) + { + p_port_cep->obj.pfn_destroy( &p_port_cep->obj, NULL ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("__init_data_svc failed with status %s.\n", + ib_get_err_str(status)) ); + return status; + } + + /* Update local port attributes */ + cl_memclr( &port_attr_mod, sizeof(ib_port_attr_mod_t) ); + port_attr_mod.cap.cm = TRUE; + status = ib_modify_ca( p_port_cep->h_ca, p_pnp_rec->p_port_attr->port_num, + IB_CA_MOD_IS_CM_SUPPORTED, &port_attr_mod ); + + /* Update the PNP context to reference this port. */ + p_pnp_rec->pnp_rec.context = p_port_cep; + + /* Release the reference taken in init_al_obj. */ + deref_al_obj( &p_port_cep->obj ); + + AL_EXIT( AL_DBG_CM ); + return IB_SUCCESS; +} + + +/****************************************************************************** +* Global CEP manager +******************************************************************************/ + +static cep_cid_t* +__get_lcid( + OUT net32_t* const p_cid ) +{ + cl_status_t status; + uint32_t size, cid; + cep_cid_t *p_cep_cid; + + AL_ENTER( AL_DBG_CM ); + + size = (uint32_t)cl_vector_get_size( &gp_cep_mgr->cid_vector ); + cid = gp_cep_mgr->free_cid; + if( gp_cep_mgr->free_cid == size ) + { + /* Grow the vector pool. */ + status = + cl_vector_set_size( &gp_cep_mgr->cid_vector, size + CEP_CID_GROW ); + if( status != CL_SUCCESS ) + { + AL_EXIT( AL_DBG_CM ); + return NULL; + } + /* + * Return the the start of the free list since the + * entry initializer incremented it. + */ + gp_cep_mgr->free_cid = size; + } + + /* Get the next free entry. */ + p_cep_cid = (cep_cid_t*)cl_vector_get_ptr( &gp_cep_mgr->cid_vector, cid ); + + /* Update the next entry index. */ + gp_cep_mgr->free_cid = (uint32_t)(uintn_t)p_cep_cid->p_cep; + + *p_cid = cid; + + AL_EXIT( AL_DBG_CM ); + return p_cep_cid; +} + + +static inline kcep_t* +__lookup_cep( + IN ib_al_handle_t h_al OPTIONAL, + IN net32_t cid ) +{ + size_t idx; + cep_cid_t *p_cid; + + /* Mask off the counter bits so we get the index in our vector. */ + idx = cid & CEP_MAX_CID_MASK; + + if( idx >= cl_vector_get_size( &gp_cep_mgr->cid_vector ) ) + return NULL; + + p_cid = (cep_cid_t*)cl_vector_get_ptr( &gp_cep_mgr->cid_vector, idx ); + if( !p_cid->h_al ) + return NULL; + + /* + * h_al is NULL when processing MADs, so we need to match on + * the actual local communication ID. If h_al is non-NULL, we + * are doing a lookup from a call to our API, and only need to match + * on the index in the vector (without the modifier). + */ + if( h_al ) + { + if( p_cid->h_al != h_al ) + return NULL; + } + else if( p_cid->p_cep->local_comm_id != cid ) + { + return NULL; + } + + return p_cid->p_cep; +} + + +/* + * Lookup a CEP by remote comm ID and CA GUID. + */ +static kcep_t* +__lookup_by_id( + IN net32_t remote_comm_id, + IN net64_t remote_ca_guid ) +{ + cl_rbmap_item_t *p_item; + kcep_t *p_cep; + + AL_ENTER( AL_DBG_CM ); + + /* Match against pending connections using remote comm ID and CA GUID. */ + p_item = cl_rbmap_root( &gp_cep_mgr->conn_id_map ); + while( p_item != cl_rbmap_end( &gp_cep_mgr->conn_id_map ) ) + { + p_cep = PARENT_STRUCT( p_item, kcep_t, rem_id_item ); + + if( remote_comm_id < p_cep->remote_comm_id ) + p_item = cl_rbmap_left( p_item ); + else if( remote_comm_id > p_cep->remote_comm_id ) + p_item = cl_rbmap_right( p_item ); + else if( remote_ca_guid < p_cep->remote_ca_guid ) + p_item = cl_rbmap_left( p_item ); + else if( remote_ca_guid > p_cep->remote_ca_guid ) + p_item = cl_rbmap_right( p_item ); + else + return p_cep; + } + + AL_EXIT( AL_DBG_CM ); + return NULL; +} + + +/* + * Lookup a CEP by Service ID and private data. + */ +static kcep_t* +__lookup_listen( + IN net64_t sid, + IN net64_t port_guid, + IN uint8_t *p_pdata ) +{ + cl_rbmap_item_t *p_item; + kcep_t *p_cep; + intn_t cmp; + + AL_ENTER( AL_DBG_CM ); + + /* Match against pending connections using remote comm ID and CA GUID. */ + p_item = cl_rbmap_root( &gp_cep_mgr->listen_map ); + while( p_item != cl_rbmap_end( &gp_cep_mgr->listen_map ) ) + { + p_cep = PARENT_STRUCT( p_item, kcep_t, listen_item ); + + if( sid == p_cep->sid ) + goto port_cmp; + else if( sid < p_cep->sid ) + p_item = cl_rbmap_left( p_item ); + else + p_item = cl_rbmap_right( p_item ); + + continue; + +port_cmp: + if( p_cep->port_guid != IB_ALL_PORTS ) + { + if( port_guid == p_cep->port_guid ) + goto pdata_cmp; + else if( port_guid < p_cep->port_guid ) + p_item = cl_rbmap_left( p_item ); + else + p_item = cl_rbmap_right( p_item ); + + continue; + } + +pdata_cmp: + if( p_cep->p_cmp_buf && p_pdata ) + { + cmp = cl_memcmp( &p_pdata[p_cep->cmp_offset], + p_cep->p_cmp_buf, p_cep->cmp_len ); + + if( !cmp ) + goto match; + else if( cmp < 0 ) + p_item = cl_rbmap_left( p_item ); + else + p_item = cl_rbmap_right( p_item ); + + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_CM, + ("Svc ID match but compare buffer mismatch.\n") ); + continue; + } + +match: + /* Everything matched. */ + AL_PRINT( TRACE_LEVEL_VERBOSE, AL_DBG_CM, ("] matched CID = %d\n", p_cep->cid) ); + return p_cep; + } + + AL_PRINT( TRACE_LEVEL_VERBOSE, AL_DBG_CM, ("] not found\n") ); + return NULL; +} + + +static kcep_t* +__insert_by_id( + IN kcep_t* const p_new_cep ) +{ + kcep_t *p_cep; + cl_rbmap_item_t *p_item, *p_insert_at; + boolean_t left = TRUE; + + AL_ENTER( AL_DBG_CM ); + + p_item = cl_rbmap_root( &gp_cep_mgr->conn_id_map ); + p_insert_at = p_item; + while( p_item != cl_rbmap_end( &gp_cep_mgr->conn_id_map ) ) + { + p_insert_at = p_item; + p_cep = PARENT_STRUCT( p_item, kcep_t, rem_id_item ); + + if( p_new_cep->remote_comm_id < p_cep->remote_comm_id ) + p_item = cl_rbmap_left( p_item ), left = TRUE; + else if( p_new_cep->remote_comm_id > p_cep->remote_comm_id ) + p_item = cl_rbmap_right( p_item ), left = FALSE; + else if( p_new_cep->remote_ca_guid < p_cep->remote_ca_guid ) + p_item = cl_rbmap_left( p_item ), left = TRUE; + else if( p_new_cep->remote_ca_guid > p_cep->remote_ca_guid ) + p_item = cl_rbmap_right( p_item ), left = FALSE; + else + { + AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM, + ("WARNING: Duplicate remote CID and CA GUID.\n") ); + goto done; + } + } + + cl_rbmap_insert( + &gp_cep_mgr->conn_id_map, p_insert_at, &p_new_cep->rem_id_item, left ); + p_cep = p_new_cep; + +done: + AL_EXIT( AL_DBG_CM ); + return p_cep; +} + + +static kcep_t* +__insert_by_qpn( + IN kcep_t* const p_new_cep ) +{ + kcep_t *p_cep; + cl_rbmap_item_t *p_item, *p_insert_at; + boolean_t left = TRUE; + + AL_ENTER( AL_DBG_CM ); + + p_item = cl_rbmap_root( &gp_cep_mgr->conn_qp_map ); + p_insert_at = p_item; + while( p_item != cl_rbmap_end( &gp_cep_mgr->conn_qp_map ) ) + { + p_insert_at = p_item; + p_cep = PARENT_STRUCT( p_item, kcep_t, rem_id_item ); + + if( p_new_cep->remote_qpn < p_cep->remote_qpn ) + p_item = cl_rbmap_left( p_item ), left = TRUE; + else if( p_new_cep->remote_qpn > p_cep->remote_qpn ) + p_item = cl_rbmap_right( p_item ), left = FALSE; + else if( p_new_cep->remote_ca_guid < p_cep->remote_ca_guid ) + p_item = cl_rbmap_left( p_item ), left = TRUE; + else if( p_new_cep->remote_ca_guid > p_cep->remote_ca_guid ) + p_item = cl_rbmap_right( p_item ), left = FALSE; + else + { + AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM, + ("WARNING: Duplicate remote QPN and CA GUID.\n") ); + goto done; + } + } + + cl_rbmap_insert( + &gp_cep_mgr->conn_qp_map, p_insert_at, &p_new_cep->rem_qp_item, left ); + p_cep = p_new_cep; + +done: + AL_EXIT( AL_DBG_CM ); + return p_cep; +} + + +static inline kcep_t* +__insert_cep( + IN kcep_t* const p_new_cep ) +{ + kcep_t *p_cep; + + AL_ENTER( AL_DBG_CM ); + + p_cep = __insert_by_qpn( p_new_cep ); + if( p_cep != p_new_cep ) + goto err; + + p_cep = __insert_by_id( p_new_cep ); + if( p_cep != p_new_cep ) + { + cl_rbmap_remove_item( + &gp_cep_mgr->conn_qp_map, &p_new_cep->rem_qp_item ); +err: + /* + * Clear the remote QPN and comm ID so that we don't try + * to remove the CEP from those maps. + */ + p_new_cep->remote_qpn = 0; + p_new_cep->remote_comm_id = 0; + } + + AL_EXIT( AL_DBG_CM ); + return p_cep; +} + + +static inline void +__remove_cep( + IN kcep_t* const p_cep ) +{ + AL_ENTER( AL_DBG_CM ); + + if( p_cep->remote_comm_id ) + { + cl_rbmap_remove_item( + &gp_cep_mgr->conn_id_map, &p_cep->rem_id_item ); + p_cep->remote_comm_id = 0; + } + if( p_cep->remote_qpn ) + { + cl_rbmap_remove_item( + &gp_cep_mgr->conn_qp_map, &p_cep->rem_qp_item ); + p_cep->remote_qpn = 0; + } + + AL_EXIT( AL_DBG_CM ); +} + + +static boolean_t +__is_lid_valid( + IN ib_net16_t lid, + IN ib_net16_t port_lid, + IN uint8_t lmc ) +{ + uint16_t lid1; + uint16_t lid2; + uint16_t path_bits; + + if(lmc) + { + lid1 = CL_NTOH16(lid); + lid2 = CL_NTOH16(port_lid); + path_bits = 0; + + if( lid1 < lid2 ) + return FALSE; + + while( lmc-- ) + path_bits = (uint16_t)( (path_bits << 1) | 1 ); + + lid2 |= path_bits; + + if( lid1 > lid2) + return FALSE; + } + else + { + if (lid != port_lid) + return FALSE; + } + + return TRUE; +} + + +static inline boolean_t +__is_gid_valid( + IN const ib_port_attr_t* const p_port_attr, + IN const ib_gid_t* const p_gid ) +{ + uint16_t idx; + + for( idx = 0; idx < p_port_attr->num_gids; idx++ ) + { + if( !cl_memcmp( + p_gid, &p_port_attr->p_gid_table[idx], sizeof(ib_gid_t) ) ) + { + return TRUE; + } + } + return FALSE; +} + + +static inline boolean_t +__get_pkey_index( + IN const ib_port_attr_t* const p_port_attr, + IN const net16_t pkey, + OUT uint16_t* const p_pkey_index ) +{ + uint16_t idx; + + for( idx = 0; idx < p_port_attr->num_pkeys; idx++ ) + { + if( p_port_attr->p_pkey_table[idx] == pkey ) + { + *p_pkey_index = idx; + return TRUE; + } + } + + return FALSE; +} + + +/* Returns the 1-based port index of the CEP agent with the specified GID. */ +static cep_agent_t* +__find_port_cep( + IN const ib_gid_t* const p_gid, + IN const net16_t lid, + IN const net16_t pkey, + OUT uint16_t* const p_pkey_index ) +{ + cep_agent_t *p_port_cep; + cl_list_item_t *p_item; + const ib_port_attr_t *p_port_attr; + + AL_ENTER( AL_DBG_CM ); + + cl_spinlock_acquire( &gp_cep_mgr->obj.lock ); + for( p_item = cl_qlist_head( &gp_cep_mgr->obj.obj_list ); + p_item != cl_qlist_end( &gp_cep_mgr->obj.obj_list ); + p_item = cl_qlist_next( p_item ) ) + { + p_port_cep = PARENT_STRUCT( p_item, cep_agent_t, obj.pool_item ); + + CL_ASSERT( p_port_cep->port_num ); + + ci_ca_lock_attr( p_port_cep->h_ca->obj.p_ci_ca ); + + p_port_attr = p_port_cep->h_ca->obj.p_ci_ca->p_pnp_attr->p_port_attr; + p_port_attr += (p_port_cep->port_num - 1); + + if( __is_lid_valid( lid, p_port_attr->lid, p_port_attr->lmc ) && + __is_gid_valid( p_port_attr, p_gid ) && + __get_pkey_index( p_port_attr, pkey, p_pkey_index ) ) + { + ci_ca_unlock_attr( p_port_cep->h_ca->obj.p_ci_ca ); + cl_spinlock_release( &gp_cep_mgr->obj.lock ); + AL_EXIT( AL_DBG_CM ); + return p_port_cep; + } + + ci_ca_unlock_attr( p_port_cep->h_ca->obj.p_ci_ca ); + } + cl_spinlock_release( &gp_cep_mgr->obj.lock ); + AL_EXIT( AL_DBG_CM ); + return NULL; +} + + +/* + * PnP callback for port event notifications. + */ +static ib_api_status_t +__cep_pnp_cb( + IN ib_pnp_rec_t *p_pnp_rec ) +{ + ib_api_status_t status = IB_SUCCESS; + + AL_ENTER( AL_DBG_CM ); + + switch( p_pnp_rec->pnp_event ) + { + case IB_PNP_PORT_ADD: + /* Create the port agent. */ + CL_ASSERT( !p_pnp_rec->context ); + status = __create_port_cep( (ib_pnp_port_rec_t*)p_pnp_rec ); + break; + + case IB_PNP_PORT_REMOVE: + CL_ASSERT( p_pnp_rec->context ); + + /* Destroy the port agent. */ + ref_al_obj( &((cep_agent_t*)p_pnp_rec->context)->obj ); + ((cep_agent_t*)p_pnp_rec->context)->obj.pfn_destroy( + &((cep_agent_t*)p_pnp_rec->context)->obj, NULL ); + break; + + default: + break; /* Ignore other PNP events. */ + } + + AL_EXIT( AL_DBG_CM ); + return status; +} + + +static inline int64_t +__min_timewait( + IN int64_t current_min, + IN kcep_t* const p_cep ) +{ + /* + * The minimum timer interval is 50 milliseconds. This means + * 500000 100ns increments. Since __process_timewait divides the + * result in half (so that the worst cast timewait interval is 150%) + * we compensate for this here. Note that relative time values are + * expressed as negative. + */ +#define MIN_TIMEWAIT_100NS -1000000 + + /* Still in timewait - try again next time. */ + if( !current_min ) + { + return min( p_cep->timewait_time.QuadPart, MIN_TIMEWAIT_100NS ); + } + else + { + return max( current_min, + min( p_cep->timewait_time.QuadPart, MIN_TIMEWAIT_100NS ) ); + } +} + + +/* + * Timer callback to process CEPs in timewait state. Returns time in ms. + */ +static uint32_t +__process_timewait() +{ + cl_list_item_t *p_item; + kcep_t *p_cep; + LARGE_INTEGER timeout; + int64_t min_timewait = 0; + + AL_ENTER( AL_DBG_CM ); + + CL_ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL ); + + timeout.QuadPart = 0; + + p_item = cl_qlist_head( &gp_cep_mgr->timewait_list ); + while( p_item != cl_qlist_end( &gp_cep_mgr->timewait_list ) ) + { + p_cep = PARENT_STRUCT( p_item, kcep_t, timewait_item ); + p_item = cl_qlist_next( p_item ); + + CL_ASSERT( p_cep->state == CEP_STATE_DESTROY || + p_cep->state == CEP_STATE_TIMEWAIT ); + + CL_ASSERT( !p_cep->p_mad ); + + if( KeWaitForSingleObject( &p_cep->timewait_timer, Executive, + KernelMode, FALSE, &timeout ) != STATUS_SUCCESS ) + { + /* Still in timewait - try again next time. */ + min_timewait = __min_timewait( min_timewait, p_cep ); + continue; + } + + if( p_cep->ref_cnt ) + { + /* Send outstanding or destruction in progress. */ + min_timewait = __min_timewait( min_timewait, p_cep ); + continue; + } + + /* Remove from the timewait list. */ + cl_qlist_remove_item( &gp_cep_mgr->timewait_list, &p_cep->timewait_item ); + + /* + * Not in timewait. Remove the CEP from the maps - it should + * no longer be matched against. + */ + __remove_cep( p_cep ); + + if( p_cep->state == CEP_STATE_DESTROY ) + { + __destroy_cep( p_cep ); + } + else + { + /* Move the CEP to the IDLE state so that it can be used again. */ + p_cep->state = CEP_STATE_IDLE; + } + } + + AL_EXIT( AL_DBG_CM ); + return (uint32_t)(min_timewait / -20000); +} + + +/* + * Timer callback to process CEPs in timewait state. + */ +static void +__cep_timewait_cb( + IN void *context ) +{ + KLOCK_QUEUE_HANDLE hdl; + uint32_t min_timewait; + + AL_ENTER( AL_DBG_CM ); + + UNUSED_PARAM( context ); + + CL_ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL ); + + KeAcquireInStackQueuedSpinLockAtDpcLevel( &gp_cep_mgr->lock, &hdl ); + + min_timewait = __process_timewait(); + + if( cl_qlist_count( &gp_cep_mgr->timewait_list ) ) + { + /* + * Reset the timer for half of the shortest timeout - this results + * in a worst case timeout of 150% of timewait. + */ + cl_timer_trim( &gp_cep_mgr->timewait_timer, min_timewait ); + } + + KeReleaseInStackQueuedSpinLockFromDpcLevel( &hdl ); + + AL_EXIT( AL_DBG_CM ); +} + + +/* + * Starts immediate cleanup of the CM. Invoked during al_obj destruction. + */ +static void +__destroying_cep_mgr( + IN al_obj_t* p_obj ) +{ + ib_api_status_t status; + KLOCK_QUEUE_HANDLE hdl; + cl_list_item_t *p_item; + kcep_t *p_cep; + LARGE_INTEGER timeout; + + AL_ENTER( AL_DBG_CM ); + + CL_ASSERT( &gp_cep_mgr->obj == p_obj ); + UNUSED_PARAM( p_obj ); + + /* Deregister from PnP notifications. */ + if( gp_cep_mgr->h_pnp ) + { + status = ib_dereg_pnp( + gp_cep_mgr->h_pnp, (ib_pfn_destroy_cb_t)deref_al_obj ); + if( status != IB_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("ib_dereg_pnp failed with status %s.\n", + ib_get_err_str(status)) ); + deref_al_obj( &gp_cep_mgr->obj ); + } + } + + /* Cancel all timewait timers. */ + timeout.QuadPart = 0; + KeAcquireInStackQueuedSpinLock( &gp_cep_mgr->lock, &hdl ); + for( p_item = cl_qlist_head( &gp_cep_mgr->timewait_list ); + p_item != cl_qlist_end( &gp_cep_mgr->timewait_list ); + p_item = cl_qlist_next( p_item ) ) + { + p_cep = PARENT_STRUCT( p_item, kcep_t, timewait_item ); + KeSetTimer( &p_cep->timewait_timer, timeout, NULL ); + } + __process_timewait(); + KeReleaseInStackQueuedSpinLock( &hdl ); + + AL_EXIT( AL_DBG_CM ); +} + + +/* + * Frees the global CEP agent. Invoked during al_obj destruction. + */ +static void +__free_cep_mgr( + IN al_obj_t* p_obj ) +{ + AL_ENTER( AL_DBG_CM ); + + CL_ASSERT( &gp_cep_mgr->obj == p_obj ); + /* All listen request should have been cleaned up by this point. */ + CL_ASSERT( cl_is_rbmap_empty( &gp_cep_mgr->listen_map ) ); + /* All connections should have been cancelled/disconnected by now. */ + CL_ASSERT( cl_is_rbmap_empty( &gp_cep_mgr->conn_id_map ) ); + CL_ASSERT( cl_is_rbmap_empty( &gp_cep_mgr->conn_qp_map ) ); + + cl_vector_destroy( &gp_cep_mgr->cid_vector ); + + cl_timer_destroy( &gp_cep_mgr->timewait_timer ); + + /* + * All CM port agents should have been destroyed by now via the + * standard child object destruction provided by the al_obj. + */ + ExDeleteNPagedLookasideList( &gp_cep_mgr->cep_pool ); + destroy_al_obj( p_obj ); + + cl_free( gp_cep_mgr ); + gp_cep_mgr = NULL; + + AL_EXIT( AL_DBG_CM ); +} + + +static cl_status_t +__cid_init( + IN void* const p_element, + IN void* context ) +{ + cep_cid_t *p_cid; + + UNUSED_PARAM( context ); + + p_cid = (cep_cid_t*)p_element; + + p_cid->h_al = NULL; + p_cid->p_cep = (kcep_t*)(uintn_t)++gp_cep_mgr->free_cid; + p_cid->modifier = 0; + + return CL_SUCCESS; +} + + +/* + * Allocates and initialized the global CM agent. + */ +ib_api_status_t +create_cep_mgr( + IN al_obj_t* const p_parent_obj ) +{ + ib_api_status_t status; + cl_status_t cl_status; + ib_pnp_req_t pnp_req; + + AL_ENTER( AL_DBG_CM ); + + CL_ASSERT( gp_cep_mgr == NULL ); + + /* Allocate the global CM agent. */ + gp_cep_mgr = (al_cep_mgr_t*)cl_zalloc( sizeof(al_cep_mgr_t) ); + if( !gp_cep_mgr ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("Failed allocation of global CM agent.\n") ); + return IB_INSUFFICIENT_MEMORY; + } + + construct_al_obj( &gp_cep_mgr->obj, AL_OBJ_TYPE_CM ); + ExInitializeNPagedLookasideList( &gp_cep_mgr->cep_pool, NULL, NULL, + 0, sizeof(kcep_t), 'PECK', 0 ); + cl_qmap_init( &gp_cep_mgr->port_map ); + cl_rbmap_init( &gp_cep_mgr->listen_map ); + cl_rbmap_init( &gp_cep_mgr->conn_id_map ); + cl_rbmap_init( &gp_cep_mgr->conn_qp_map ); + cl_qlist_init( &gp_cep_mgr->timewait_list ); + /* Timer initialization can't fail in kernel-mode. */ + cl_timer_init( &gp_cep_mgr->timewait_timer, __cep_timewait_cb, NULL ); + cl_vector_construct( &gp_cep_mgr->cid_vector ); + + status = init_al_obj( &gp_cep_mgr->obj, NULL, FALSE, + __destroying_cep_mgr, NULL, __free_cep_mgr ); + if( status != IB_SUCCESS ) + { + __free_cep_mgr( &gp_cep_mgr->obj ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("init_al_obj failed with status %s.\n", ib_get_err_str(status)) ); + return status; + } + /* Attach to the parent object. */ + status = attach_al_obj( p_parent_obj, &gp_cep_mgr->obj ); + if( status != IB_SUCCESS ) + { + gp_cep_mgr->obj.pfn_destroy( &gp_cep_mgr->obj, NULL ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("attach_al_obj returned %s.\n", ib_get_err_str(status)) ); + return status; + } + + cl_status = cl_vector_init( &gp_cep_mgr->cid_vector, + CEP_CID_MIN, CEP_CID_GROW, sizeof(cep_cid_t), __cid_init, NULL, NULL ); + if( cl_status != CL_SUCCESS ) + { + gp_cep_mgr->obj.pfn_destroy( &gp_cep_mgr->obj, NULL ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("cl_vector_init failed with status %#x.\n", + cl_status) ); + return ib_convert_cl_status( cl_status ); + } + + gp_cep_mgr->free_cid = 1; + + /* Register for port PnP notifications. */ + cl_memclr( &pnp_req, sizeof(pnp_req) ); + pnp_req.pnp_class = IB_PNP_PORT; + pnp_req.pnp_context = &gp_cep_mgr->obj; + pnp_req.pfn_pnp_cb = __cep_pnp_cb; + status = ib_reg_pnp( gh_al, &pnp_req, &gp_cep_mgr->h_pnp ); + if( status != IB_SUCCESS ) + { + gp_cep_mgr->obj.pfn_destroy( &gp_cep_mgr->obj, NULL ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("ib_reg_pnp failed with status %s.\n", ib_get_err_str(status)) ); + return status; + } + + /* + * Leave the reference taken in init_al_obj oustanding since PnP + * deregistration is asynchronous. This replaces a call to ref and + * deref the object. + */ + + AL_EXIT( AL_DBG_CM ); + return IB_SUCCESS; +} + +/****************************************************************************** +* CEP manager API +******************************************************************************/ + + +/* Called with the CEP and CEP manager locks held */ +static ib_api_status_t +__cep_queue_mad( + IN kcep_t* const p_cep, + IN ib_mad_element_t* p_mad ) +{ + AL_PRINT( TRACE_LEVEL_VERBOSE, AL_DBG_CM, ("[ CID = %d\n", p_cep->cid) ); + + CL_ASSERT( !p_mad->p_next ); + + if( p_cep->state == CEP_STATE_DESTROY ) + { + AL_EXIT( AL_DBG_CM ); + return IB_INVALID_STATE; + } + + // TODO: Remove - manage above core kernel CM code + /* NDI connection request case */ + if ( p_cep->state == CEP_STATE_LISTEN && + (p_cep->sid & ~0x0ffffffI64) == IB_REQ_CM_RDMA_SID_PREFIX ) + { /* Try to complete pending IRP, if any */ + mad_cm_req_t* p_req = (mad_cm_req_t*)ib_get_mad_buf( p_mad ); + ib_cm_rdma_req_t *p_rdma_req = (ib_cm_rdma_req_t *)p_req->pdata; + + /* reject connection request with incorrect version parameters */ + if ( ((p_rdma_req->maj_min_ver >> 4) != IB_REQ_CM_RDMA_MAJOR_VERSION) || + ((p_rdma_req->maj_min_ver & 0x0f) > IB_REQ_CM_RDMA_MINOR_VERSION) || + (p_rdma_req->ipv != 0x40 && p_rdma_req->ipv != 0x60) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("NDI connection req is rejected: maj_min_ver %d, ipv %#x \n", + p_rdma_req->maj_min_ver, p_rdma_req->ipv ) ); + return IB_UNSUPPORTED; + } + } + + /* Queue this MAD for processing. */ + if( p_cep->p_mad_head ) + { + CL_ASSERT( p_cep->signalled ); + /* + * If there's already a MAD at the head of the list, we will not + * invoke the callback. Just queue and exit. + */ + CL_ASSERT( p_cep->p_mad_tail ); + p_cep->p_mad_tail->p_next = p_mad; + p_cep->p_mad_tail = p_mad; + AL_EXIT( AL_DBG_CM ); + return IB_PENDING; + } + + p_cep->p_mad_head = p_mad; + p_cep->p_mad_tail = p_mad; + + if( p_cep->signalled ) + { + /* signalled was already non-zero. Don't invoke the callback again. */ + AL_EXIT( AL_DBG_CM ); + return IB_PENDING; + } + + p_cep->signalled = TRUE; + + /* Take a reference since we're about to invoke the callback. */ + cl_atomic_inc( &p_cep->ref_cnt ); + + AL_EXIT( AL_DBG_CM ); + return IB_SUCCESS; +} + + +static inline void +__cep_complete_irp( + IN kcep_t* const p_cep, + IN NTSTATUS status, + IN CCHAR increment ) +{ + IRP *p_irp; + + AL_ENTER( AL_DBG_CM ); + + p_irp = InterlockedExchangePointer( &p_cep->p_irp, NULL ); + + if( p_irp ) + { +#pragma warning(push, 3) + IoSetCancelRoutine( p_irp, NULL ); +#pragma warning(pop) + + /* Complete the IRP. */ + p_irp->IoStatus.Status = status; + p_irp->IoStatus.Information = 0; + IoCompleteRequest( p_irp, increment ); + } + + AL_EXIT( AL_DBG_CM ); +} + + +static inline void +__process_cep( + IN kcep_t* const p_cep ) +{ + ib_pfn_destroy_cb_t pfn_destroy_cb; + void *context; + + AL_ENTER( AL_DBG_CM ); + + CL_ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL ); + + /* Signal to the user there are callback waiting. */ + if( p_cep->pfn_cb ) + p_cep->pfn_cb( p_cep->p_cid->h_al, p_cep->cid ); + else + __cep_complete_irp( p_cep, STATUS_SUCCESS, IO_NETWORK_INCREMENT ); + + pfn_destroy_cb = p_cep->pfn_destroy_cb; + context = p_cep->context; + + /* + * Release the reference for the callback and invoke the destroy + * callback if necessary. + */ + if( !cl_atomic_dec( &p_cep->ref_cnt ) && pfn_destroy_cb ) + pfn_destroy_cb( context ); + + AL_EXIT( AL_DBG_CM ); +} + + +static uint32_t +__calc_mad_timeout( + IN const uint8_t pkt_life ) +{ + /* + * Calculate the retry timeout. + * All timeout values in micro seconds are expressed as 4.096 * 2^x, + * where x is the timeout. The formula to approximates this to + * milliseconds using just shifts and subtraction is: + * timeout_ms = 67 << (x - 14) + * The results are off by 0.162%. + * + * Note that we will never return less than 1 millisecond. We also + * trap exceedingly large values to prevent wrapping. + */ + if( pkt_life > 39 ) + return ~0UL; + if( pkt_life > 14 ) + return 67 << (pkt_life - 14); + else if( pkt_life > 8 ) + return 67 >> (14 - pkt_life); + else + return 1; +} + + +/* CEP manager lock is held when calling this function. */ +static kcep_t* +__create_cep() +{ + kcep_t *p_cep; + + AL_ENTER( AL_DBG_CM ); + + p_cep = ExAllocateFromNPagedLookasideList( &gp_cep_mgr->cep_pool ); + if( !p_cep ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("Failed to allocate CEP.\n") ); + return NULL; + } + + cl_memclr( p_cep, sizeof(kcep_t) ); + + KeInitializeTimer( &p_cep->timewait_timer ); + + p_cep->state = CEP_STATE_IDLE; + + /* + * Pre-charge the reference count to 1. The code will invoke the + * destroy callback once the ref count reaches to zero. + */ + p_cep->ref_cnt = 1; + p_cep->signalled = FALSE; + + /* Find a free entry in the CID vector. */ + p_cep->p_cid = __get_lcid( &p_cep->cid ); + + if( !p_cep->p_cid ) + { + ExFreeToNPagedLookasideList( &gp_cep_mgr->cep_pool, p_cep ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("Failed to get CID.\n") ); + return NULL; + } + + p_cep->p_cid->modifier++; + /* + * We don't ever want a modifier of zero for the CID at index zero + * since it would result in a total CID of zero. + */ + if( !p_cep->cid && !p_cep->p_cid->modifier ) + p_cep->p_cid->modifier++; + + p_cep->local_comm_id = p_cep->cid | (p_cep->p_cid->modifier << 24); + p_cep->tid = p_cep->local_comm_id; + + p_cep->p_cid->p_cep = p_cep; + + ref_al_obj( &gp_cep_mgr->obj ); + + AL_EXIT( AL_DBG_CM ); + return p_cep; +} + + +static inline void +__bind_cep( + IN kcep_t* const p_cep, + IN ib_al_handle_t h_al, + IN al_pfn_cep_cb_t pfn_cb, + IN void* context ) +{ + CL_ASSERT( p_cep ); + CL_ASSERT( p_cep->p_cid ); + CL_ASSERT( h_al ); + + p_cep->p_cid->h_al = h_al; + p_cep->pfn_cb = pfn_cb; + p_cep->context = context; + + /* Track the CEP in its owning AL instance. */ + cl_spinlock_acquire( &h_al->obj.lock ); + cl_qlist_insert_tail( &h_al->cep_list, &p_cep->al_item ); + cl_spinlock_release( &h_al->obj.lock ); +} + +ib_api_status_t +kal_cep_alloc( + IN ib_al_handle_t h_al, + IN OUT net32_t* const p_cid ) +{ + kcep_t *p_cep; + KLOCK_QUEUE_HANDLE hdl; + + KeAcquireInStackQueuedSpinLock( &gp_cep_mgr->lock, &hdl ); + p_cep = __create_cep(); + KeReleaseInStackQueuedSpinLock( &hdl ); + + if( !p_cep ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("Failed\n") ); + return IB_INSUFFICIENT_MEMORY; + } + + __bind_cep(p_cep, h_al, NULL, NULL); + *p_cid = p_cep->cid; + AL_PRINT( TRACE_LEVEL_VERBOSE, AL_DBG_CM, ("allocated CID = %d\n", p_cep->cid) ); + return IB_SUCCESS; +} + +ib_api_status_t +kal_cep_config( + IN ib_al_handle_t h_al, + IN net32_t cid, + IN al_pfn_cep_cb_t pfn_cb, + IN void* context, + IN ib_pfn_destroy_cb_t pfn_destroy_cb ) +{ + kcep_t *p_cep; + KLOCK_QUEUE_HANDLE hdl; + + KeAcquireInStackQueuedSpinLock( &gp_cep_mgr->lock, &hdl ); + p_cep = __lookup_cep( h_al, cid ); + if( p_cep == NULL ) + { + KeReleaseInStackQueuedSpinLock( &hdl ); + return IB_INVALID_HANDLE; + } + + p_cep->pfn_cb = pfn_cb; + p_cep->context = context; + p_cep->pfn_destroy_cb = pfn_destroy_cb; + + KeReleaseInStackQueuedSpinLock( &hdl ); + return IB_SUCCESS; +} + +static inline void +__unbind_cep( + IN kcep_t* const p_cep ) +{ + CL_ASSERT( p_cep ); + CL_ASSERT( p_cep->p_cid ); + CL_ASSERT( p_cep->p_cid->h_al ); + + /* Track the CEP in its owning AL instance. */ + cl_spinlock_acquire( &p_cep->p_cid->h_al->obj.lock ); + cl_qlist_remove_item( &p_cep->p_cid->h_al->cep_list, &p_cep->al_item ); + cl_spinlock_release( &p_cep->p_cid->h_al->obj.lock ); + + /* + * Set to the internal AL handle - it needs to be non-NULL to indicate it's + * a valid entry, and it can't be a user's AL instance to prevent using a + * destroyed CEP. + */ + p_cep->p_cid->h_al = gh_al; +#ifdef _DEBUG_ + p_cep->pfn_cb = NULL; +#endif /* _DEBUG_ */ +} + + +static inline void +__calc_timewait( + IN kcep_t* const p_cep ) +{ + + /* + * Use the CEP's stored packet lifetime to calculate the time at which + * the CEP exits timewait. Packet lifetime is expressed as + * 4.096 * 2^pkt_life microseconds, and we need a timeout in 100ns + * increments. The formual using just shifts and subtraction is this: + * timeout = (41943 << (pkt_life - 10)); + * The results are off by .0001%, which should be more than adequate. + */ + if( p_cep->max_2pkt_life > 10 ) + { + p_cep->timewait_time.QuadPart = + -(41943i64 << (p_cep->max_2pkt_life - 10)); + } + else + { + p_cep->timewait_time.QuadPart = + -(41943i64 >> (10 - p_cep->max_2pkt_life)); + } + if( p_cep->target_ack_delay > 10 ) + { + p_cep->timewait_time.QuadPart -= + (41943i64 << (p_cep->target_ack_delay - 10)); + } + else + { + p_cep->timewait_time.QuadPart -= + (41943i64 >> (10 - p_cep->target_ack_delay)); + } +} + + +/* Called with CEP manager and CEP locks held. */ +static inline void +__insert_timewait( + IN kcep_t* const p_cep ) +{ + cl_qlist_insert_tail( &gp_cep_mgr->timewait_list, &p_cep->timewait_item ); + + KeSetTimer( &p_cep->timewait_timer, p_cep->timewait_time, NULL ); + + /* + * Reset the timer for half of the shortest timeout - this results + * in a worst case timeout of 150% of timewait. + */ + cl_timer_trim( &gp_cep_mgr->timewait_timer, + (uint32_t)(-p_cep->timewait_time.QuadPart / 20000) ); +} + + +static inline ib_api_status_t +__do_cep_rej( + IN kcep_t* const p_cep, + IN ib_rej_status_t rej_status, + IN const uint8_t* const p_ari, + IN uint8_t ari_len, + IN const uint8_t* const p_pdata, + IN uint8_t pdata_len ) +{ + ib_api_status_t status; + cep_agent_t *p_port_cep; + ib_mad_element_t *p_mad; + + p_port_cep = __get_cep_agent( p_cep ); + if( !p_port_cep ) + return IB_INSUFFICIENT_RESOURCES; + + status = ib_get_mad( p_port_cep->pool_key, MAD_BLOCK_SIZE, &p_mad ); + if( status != IB_SUCCESS ) + return status; + + __format_mad_av( p_mad, &p_cep->av[p_cep->idx_primary] ); + + status = conn_rej_set_ari( + p_ari, ari_len, (mad_cm_rej_t*)p_mad->p_mad_buf ); + if( status != IB_SUCCESS ) + return status; + + status = conn_rej_set_pdata( + p_pdata, pdata_len, (mad_cm_rej_t*)p_mad->p_mad_buf ); + if( status != IB_SUCCESS ) + return status; + + __reject_mad( p_port_cep, p_cep, p_mad, rej_status ); + return IB_SUCCESS; +} + + +static ib_api_status_t +__cep_get_mad( + IN kcep_t* const p_cep, + IN net16_t attr_id, + OUT cep_agent_t** const pp_port_cep, + OUT ib_mad_element_t** const pp_mad ) +{ + cep_agent_t *p_port_cep; + ib_api_status_t status; + + AL_ENTER( AL_DBG_CM ); + + p_port_cep = __get_cep_agent( p_cep ); + if( !p_port_cep ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("__get_cep_agent failed.\n") ); + return IB_INSUFFICIENT_RESOURCES; + } + + status = ib_get_mad( p_port_cep->pool_key, MAD_BLOCK_SIZE, pp_mad ); + if( status != IB_SUCCESS ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("ib_get_mad returned %s.\n", ib_get_err_str( status )) ); + return status; + } + + __format_mad_av( *pp_mad, &p_cep->av[p_cep->idx_primary] ); + + __format_mad_hdr( (*pp_mad)->p_mad_buf, p_cep, attr_id ); + + *pp_port_cep = p_port_cep; + AL_EXIT( AL_DBG_CM ); + return status; +} + + +static ib_api_status_t +__format_dreq( + IN kcep_t* const p_cep, + IN const uint8_t* p_pdata OPTIONAL, + IN uint8_t pdata_len, + IN OUT ib_mad_element_t* const p_mad ) +{ + ib_api_status_t status; + mad_cm_dreq_t *p_dreq; + + AL_ENTER( AL_DBG_CM ); + + p_dreq = (mad_cm_dreq_t*)p_mad->p_mad_buf; + + p_dreq->local_comm_id = p_cep->local_comm_id; + p_dreq->remote_comm_id = p_cep->remote_comm_id; + + conn_dreq_set_remote_qpn( p_cep->remote_qpn, p_dreq ); + + /* copy optional data */ + status = conn_dreq_set_pdata( p_pdata, pdata_len, p_dreq ); + + AL_EXIT( AL_DBG_CM ); + return status; +} + + +static ib_api_status_t +__dreq_cep( + IN kcep_t* const p_cep ) +{ + ib_api_status_t status; + cep_agent_t *p_agt; + ib_mad_element_t *p_mad; + + status = __cep_get_mad( p_cep, CM_DREQ_ATTR_ID, &p_agt, &p_mad ); + if( status != IB_SUCCESS ) + return status; + + status = __format_dreq( p_cep, NULL, 0, p_mad ); + if( status != IB_SUCCESS ) + return status; + + return __cep_send_retry( p_agt, p_cep, p_mad ); +} + + +static ib_api_status_t +__format_drep( + IN kcep_t* const p_cep, + IN const uint8_t* p_pdata OPTIONAL, + IN uint8_t pdata_len, + IN OUT mad_cm_drep_t* const p_drep ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_CM ); + + p_drep->local_comm_id = p_cep->local_comm_id; + p_drep->remote_comm_id = p_cep->remote_comm_id; + + /* copy optional data */ + status = conn_drep_set_pdata( p_pdata, pdata_len, p_drep ); + + /* Store the RTU MAD so we can repeat it if we get a repeated DREP. */ + if( status == IB_SUCCESS && p_drep != &p_cep->mads.drep ) + p_cep->mads.drep = *p_drep; + + AL_EXIT( AL_DBG_CM ); + return status; +} + + +static void +__drep_cep( + IN kcep_t* const p_cep ) +{ + cep_agent_t *p_agt; + ib_mad_element_t *p_mad; + + AL_ENTER( AL_DBG_CM ); + + if( __cep_get_mad( p_cep, CM_DREP_ATTR_ID, &p_agt, &p_mad ) != IB_SUCCESS ) + return; + + if( __format_drep( p_cep, NULL, 0, (mad_cm_drep_t*)p_mad->p_mad_buf ) + != IB_SUCCESS ) + { + return; + } + + __cep_send_mad( p_agt, p_mad ); + + AL_EXIT( AL_DBG_CM ); +} + +/* Called with CEP manager lock held. */ +static int32_t +__cleanup_cep( + IN kcep_t* const p_cep ) +{ + ib_mad_element_t *p_mad; + kcep_t *p_new_cep; + + AL_PRINT( TRACE_LEVEL_VERBOSE, AL_DBG_CM, + ("[ p_cep = %p (CID = %d)\n", p_cep, p_cep->cid) ); + + CL_ASSERT( p_cep ); + CL_ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL ); + + /* If we've already come through here, we're done. */ + CL_ASSERT( p_cep->state != CEP_STATE_DESTROY && + p_cep->state != CEP_STATE_DREQ_DESTROY ); + + /* Cleanup the pending MAD list. */ + while( p_cep->p_mad_head ) + { + p_mad = p_cep->p_mad_head; + p_cep->p_mad_head = p_mad->p_next; + p_mad->p_next = NULL; + if( p_mad->send_context1 ) + { + p_new_cep = (kcep_t*)p_mad->send_context1; + + __unbind_cep( p_new_cep ); + __cleanup_cep( p_new_cep ); + } + ib_put_mad( p_mad ); + } + + switch( p_cep->state ) + { + case CEP_STATE_PRE_REP: + case CEP_STATE_PRE_REP_MRA_SENT: + CL_ASSERT( p_cep->p_mad ); + ib_put_mad( p_cep->p_mad ); + p_cep->p_mad = NULL; + /* Fall through. */ + case CEP_STATE_REQ_RCVD: + case CEP_STATE_REP_RCVD: + case CEP_STATE_REQ_MRA_SENT: + case CEP_STATE_REP_MRA_SENT: + /* Reject the connection. */ + __do_cep_rej( p_cep, IB_REJ_USER_DEFINED, NULL, 0, NULL, 0 ); + break; + + case CEP_STATE_REQ_SENT: + case CEP_STATE_REQ_MRA_RCVD: + case CEP_STATE_REP_SENT: + case CEP_STATE_REP_MRA_RCVD: + /* Cancel the send. */ + CL_ASSERT( p_cep->h_mad_svc ); + CL_ASSERT( p_cep->p_send_mad ); + ib_cancel_mad( p_cep->h_mad_svc, p_cep->p_send_mad ); + /* Reject the connection. */ + __do_cep_rej( p_cep, IB_REJ_TIMEOUT, (uint8_t*)&p_cep->local_ca_guid, + sizeof(p_cep->local_ca_guid), NULL, 0 ); + break; + + case CEP_STATE_LAP_SENT: + case CEP_STATE_LAP_MRA_RCVD: + ib_cancel_mad( p_cep->h_mad_svc, p_cep->p_send_mad ); + /* fall through */ + case CEP_STATE_ESTABLISHED: + case CEP_STATE_LAP_RCVD: + case CEP_STATE_LAP_MRA_SENT: + case CEP_STATE_PRE_APR: + case CEP_STATE_PRE_APR_MRA_SENT: + /* Disconnect the connection. */ + if( __dreq_cep( p_cep ) != IB_SUCCESS ) + break; + /* Fall through. */ + + case CEP_STATE_DREQ_SENT: + ib_cancel_mad( p_cep->h_mad_svc, p_cep->p_send_mad ); + p_cep->state = CEP_STATE_DREQ_DESTROY; + goto out; + + case CEP_STATE_DREQ_RCVD: + /* Send the DREP. */ + __drep_cep( p_cep ); + break; + + case CEP_STATE_SREQ_RCVD: + /* TODO: Reject the SIDR request. */ + break; + + case CEP_STATE_LISTEN: + /* Remove from listen map. */ + cl_rbmap_remove_item( &gp_cep_mgr->listen_map, &p_cep->listen_item ); + + if( p_cep->p_cmp_buf ) + { + cl_free( p_cep->p_cmp_buf ); + p_cep->p_cmp_buf = NULL; + } + break; + + case CEP_STATE_PRE_REQ: + CL_ASSERT( p_cep->p_mad ); + ib_put_mad( p_cep->p_mad ); + p_cep->p_mad = NULL; + /* Fall through. */ + case CEP_STATE_IDLE: + break; + + default: + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("CEP in state %d.\n", p_cep->state) ); + case CEP_STATE_TIMEWAIT: + /* Already in timewait - so all is good. */ + p_cep->state = CEP_STATE_DESTROY; + goto out; + } + + p_cep->state = CEP_STATE_DESTROY; + __insert_timewait( p_cep ); + +out: + AL_EXIT( AL_DBG_CM ); + return cl_atomic_dec( &p_cep->ref_cnt ); +} + + +static void +__destroy_cep( + IN kcep_t* const p_cep ) +{ + AL_ENTER( AL_DBG_CM ); + + CL_ASSERT( + p_cep->cid < cl_vector_get_size( &gp_cep_mgr->cid_vector ) ); + + CL_ASSERT( p_cep->p_cid == (cep_cid_t*)cl_vector_get_ptr( + &gp_cep_mgr->cid_vector, p_cep->cid ) ); + + /* Free the CID. */ + p_cep->p_cid->p_cep = (kcep_t*)(uintn_t)gp_cep_mgr->free_cid; + p_cep->p_cid->h_al = NULL; + gp_cep_mgr->free_cid = p_cep->cid; + + KeCancelTimer( &p_cep->timewait_timer ); + + ExFreeToNPagedLookasideList( &gp_cep_mgr->cep_pool, p_cep ); + + deref_al_obj( &gp_cep_mgr->obj ); + + AL_EXIT( AL_DBG_CM ); +} + + +ib_api_status_t +al_create_cep( + IN ib_al_handle_t h_al, + IN al_pfn_cep_cb_t pfn_cb, + IN void* context, + IN ib_pfn_destroy_cb_t pfn_destroy_cb, + IN OUT net32_t* const p_cid ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_CM ); + CL_ASSERT( h_al ); + + status = kal_cep_alloc(h_al, p_cid); + if ( status == IB_SUCCESS ) + { + status = kal_cep_config(h_al, *p_cid, pfn_cb, context, pfn_destroy_cb); + } + + AL_EXIT( AL_DBG_CM ); + return status; +} + + +void +al_destroy_cep( + IN ib_al_handle_t h_al, + IN OUT net32_t* const p_cid, + IN boolean_t reusable ) +{ + net32_t cid; + kcep_t *p_cep; + KLOCK_QUEUE_HANDLE hdl; + void *context; + ib_pfn_destroy_cb_t pfn_destroy_cb; + int32_t ref_cnt; + + AL_PRINT( TRACE_LEVEL_VERBOSE, AL_DBG_CM,("[ CID = %d\n", *p_cid) ); + + CL_ASSERT( h_al ); + + /* + * Remove the CEP from the CID vector - no further API calls + * will succeed for it. + */ + KeAcquireInStackQueuedSpinLock( &gp_cep_mgr->lock, &hdl ); + cid = *p_cid; + p_cep = __lookup_cep( h_al, cid ); + if( !p_cep ) + { + /* Invalid handle. */ + if( !reusable ) + *p_cid = AL_RESERVED_CID; + + KeReleaseInStackQueuedSpinLock( &hdl ); + AL_EXIT( AL_DBG_CM ); + return; + } + + context = p_cep->context; + pfn_destroy_cb = p_cep->pfn_destroy_cb; + + /* Cancel any queued IRP */ + __cep_complete_irp( p_cep, STATUS_CANCELLED, IO_NO_INCREMENT ); + + __unbind_cep( p_cep ); + ref_cnt = __cleanup_cep( p_cep ); + if( reusable ) + *p_cid = AL_INVALID_CID; + else + *p_cid = AL_RESERVED_CID; + + KeReleaseInStackQueuedSpinLock( &hdl ); + + if( !ref_cnt && pfn_destroy_cb ) + pfn_destroy_cb( context ); + + AL_PRINT(TRACE_LEVEL_INFORMATION ,AL_DBG_CM , + ("Destroyed CEP with cid %d, h_al %p, context %p \n", + cid, h_al, context )); + + AL_EXIT( AL_DBG_CM ); +} + +void +kal_cep_destroy( + IN ib_al_handle_t h_al, + IN net32_t cid, + IN NTSTATUS status ) +{ + KLOCK_QUEUE_HANDLE hdl; + kcep_t *p_cep; + ib_pfn_destroy_cb_t pfn_destroy_cb; + void *context; + int32_t ref_cnt; + + KeAcquireInStackQueuedSpinLock( &gp_cep_mgr->lock, &hdl ); + p_cep = __lookup_cep( h_al, cid ); + CL_ASSERT( p_cep ); + + context = p_cep->context; + pfn_destroy_cb = p_cep->pfn_destroy_cb; + + __unbind_cep( p_cep ); + /* Drop new REQs so they can be retried when resources may be available */ + if( status == STATUS_NO_MORE_ENTRIES && + (p_cep->state == CEP_STATE_REQ_RCVD || + p_cep->state == CEP_STATE_REQ_MRA_SENT) ) + { + p_cep->state = CEP_STATE_IDLE; + } + ref_cnt = __cleanup_cep( p_cep ); + KeReleaseInStackQueuedSpinLock( &hdl ); + + if( !ref_cnt && pfn_destroy_cb ) + pfn_destroy_cb( context ); +} + + +ib_api_status_t +al_cep_listen( + IN ib_al_handle_t h_al, + IN net32_t cid, + IN ib_cep_listen_t* const p_listen_info ) +{ + ib_api_status_t status; + kcep_t *p_cep, *p_listen; + cl_rbmap_item_t *p_item, *p_insert_at; + boolean_t left = TRUE; + intn_t cmp; + KLOCK_QUEUE_HANDLE hdl; + + AL_PRINT( TRACE_LEVEL_VERBOSE, AL_DBG_CM, ("[ CID = %d\n", cid) ); + + CL_ASSERT( h_al ); + CL_ASSERT( p_listen_info ); + + KeAcquireInStackQueuedSpinLock( &gp_cep_mgr->lock, &hdl ); + p_cep = __lookup_cep( h_al, cid ); + if( !p_cep ) + { + KeReleaseInStackQueuedSpinLock( &hdl ); + AL_EXIT( AL_DBG_CM ); + return IB_INVALID_HANDLE; + } + + switch( p_cep->state ) + { + case CEP_STATE_PRE_REQ: + CL_ASSERT( p_cep->p_mad ); + ib_put_mad( p_cep->p_mad ); + p_cep->p_mad = NULL; + /* Must change state here in case listen fails */ + p_cep->state = CEP_STATE_IDLE; + /* Fall through. */ + case CEP_STATE_IDLE: + break; + default: + AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM, + ("Invalid state: %d\n", p_cep->state) ); + status = IB_INVALID_STATE; + goto done; + } + + /* Insert the CEP into the listen map. */ + p_item = cl_rbmap_root( &gp_cep_mgr->listen_map ); + p_insert_at = p_item; + while( p_item != cl_rbmap_end( &gp_cep_mgr->listen_map ) ) + { + p_insert_at = p_item; + + p_listen = PARENT_STRUCT( p_item, kcep_t, listen_item ); + + if( p_listen_info->svc_id == p_listen->sid ) + goto port_cmp; + + if( p_listen_info->svc_id < p_listen->sid ) + p_item = cl_rbmap_left( p_item ), left = TRUE; + else + p_item = cl_rbmap_right( p_item ), left = FALSE; + + continue; + +port_cmp: + if( p_listen_info->port_guid != IB_ALL_PORTS ) + { + if( p_listen_info->port_guid == p_listen->port_guid ) + goto pdata_cmp; + + if( p_listen_info->port_guid < p_listen->port_guid ) + p_item = cl_rbmap_left( p_item ), left = TRUE; + else + p_item = cl_rbmap_right( p_item ), left = FALSE; + + continue; + } + +pdata_cmp: + /* + * If an existing listen doesn't have a compare buffer, + * then we found a duplicate. + */ + if( !p_listen->p_cmp_buf || !p_listen_info->p_cmp_buf ) + break; + + if( p_listen_info->p_cmp_buf ) + { + /* Compare length must match. */ + if( p_listen_info->cmp_len != p_listen->cmp_len ) + break; + + /* Compare offset must match. */ + if( p_listen_info->cmp_offset != p_listen->cmp_offset ) + break; + + cmp = cl_memcmp( &p_listen_info->p_cmp_buf, + p_listen->p_cmp_buf, p_listen->cmp_len ); + + if( cmp < 0 ) + p_item = cl_rbmap_left( p_item ), left = TRUE; + else if( cmp > 0 ) + p_item = cl_rbmap_right( p_item ), left = FALSE; + else + break; + + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_CM, + ("Svc ID match but compare buffer mismatch.\n") ); + continue; + } + } + + if( p_item != cl_rbmap_end( &gp_cep_mgr->listen_map ) ) + { + /* Duplicate!!! */ + status = IB_INVALID_SETTING; + goto done; + } + + /* Set up the CEP. */ + if( p_listen_info->p_cmp_buf ) + { + p_cep->p_cmp_buf = cl_malloc( p_listen_info->cmp_len ); + if( !p_cep->p_cmp_buf ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("Failed to allocate compare buffer.\n") ); + status = IB_INSUFFICIENT_MEMORY; + goto done; + } + + cl_memcpy( p_cep->p_cmp_buf, + p_listen_info->p_cmp_buf, p_listen_info->cmp_len ); + } + p_cep->cmp_len = p_listen_info->cmp_len; + p_cep->cmp_offset = p_listen_info->cmp_offset; + p_cep->sid = p_listen_info->svc_id; + p_cep->port_guid = p_listen_info->port_guid; + p_cep->state = CEP_STATE_LISTEN; + + cl_rbmap_insert( &gp_cep_mgr->listen_map, p_insert_at, + &p_cep->listen_item, left ); + + status = IB_SUCCESS; + +done: + KeReleaseInStackQueuedSpinLock( &hdl ); + + AL_EXIT( AL_DBG_CM ); + return status; +} + + +static cep_agent_t* +__format_path_av( + IN const ib_path_rec_t* const p_path, + OUT kcep_av_t* const p_av ) +{ + cep_agent_t* p_port_cep; + + AL_ENTER( AL_DBG_CM ); + + CL_ASSERT( p_path ); + CL_ASSERT( p_av ); + + cl_memclr( p_av, sizeof(kcep_av_t) ); + + p_port_cep = __find_port_cep( &p_path->sgid, p_path->slid, + p_path->pkey, &p_av->pkey_index ); + if( !p_port_cep ) + { + AL_EXIT( AL_DBG_CM ); + return NULL; + } + + p_av->port_guid = p_port_cep->port_guid; + + p_av->attr.port_num = p_port_cep->port_num; + + p_av->attr.sl = ib_path_rec_sl( p_path ); + p_av->attr.dlid = p_path->dlid; + + p_av->attr.grh.ver_class_flow = ib_grh_set_ver_class_flow( + 1, p_path->tclass, ib_path_rec_flow_lbl( p_path ) ); + p_av->attr.grh.hop_limit = ib_path_rec_hop_limit( p_path ); + p_av->attr.grh.src_gid = p_path->sgid; + p_av->attr.grh.dest_gid = p_path->dgid; + + p_av->attr.grh_valid = !ib_gid_is_link_local( &p_path->dgid ); + + p_av->attr.static_rate = ib_path_rec_rate( p_path ); + p_av->attr.path_bits = (uint8_t)(p_path->slid - p_port_cep->base_lid); + + /* + * Note that while we never use the connected AV attributes internally, + * we store them so we can pass them back to users. + */ + p_av->attr.conn.path_mtu = ib_path_rec_mtu( p_path ); + p_av->attr.conn.local_ack_timeout = calc_lcl_ack_timeout( + ib_path_rec_pkt_life( p_path ) + 1, 0 ); + + AL_EXIT( AL_DBG_CM ); + return p_port_cep; +} + + +/* + * Formats a REQ mad's path information given a path record. + */ +static void +__format_req_path( + IN const ib_path_rec_t* const p_path, + IN const uint8_t ack_delay, + OUT req_path_info_t* const p_req_path ) +{ + AL_ENTER( AL_DBG_CM ); + + p_req_path->local_lid = p_path->slid; + p_req_path->remote_lid = p_path->dlid; + p_req_path->local_gid = p_path->sgid; + p_req_path->remote_gid = p_path->dgid; + + conn_req_path_set_flow_lbl( ib_path_rec_flow_lbl( p_path ), + p_req_path ); + conn_req_path_set_pkt_rate( ib_path_rec_rate( p_path ), + p_req_path ); + + /* Traffic class & hop limit */ + p_req_path->traffic_class = p_path->tclass; + p_req_path->hop_limit = ib_path_rec_hop_limit( p_path ); + + /* SL & Subnet Local fields */ + conn_req_path_set_svc_lvl( ib_path_rec_sl( p_path ), + p_req_path ); + conn_req_path_set_subn_lcl( + ib_gid_is_link_local( &p_path->dgid ), p_req_path ); + + conn_req_path_set_lcl_ack_timeout( + calc_lcl_ack_timeout( ib_path_rec_pkt_life( p_path ) + 1, + ack_delay ), p_req_path ); + + conn_req_path_clr_rsvd_fields( p_req_path ); + + AL_EXIT( AL_DBG_CM ); +} + + +static ib_api_status_t +__format_req( + IN cep_agent_t* const p_port_cep, + IN kcep_t* const p_cep, + IN const iba_cm_req* const p_cm_req ) +{ + ib_api_status_t status; + mad_cm_req_t* p_req; + + AL_ENTER( AL_DBG_CM ); + + CL_ASSERT( p_cep ); + CL_ASSERT( p_cm_req ); + CL_ASSERT( p_cep->p_mad ); + + /* Format the MAD header. */ + __format_mad_hdr( p_cep->p_mad->p_mad_buf, p_cep, CM_REQ_ATTR_ID ); + + /* Set the addressing information in the MAD. */ + __format_mad_av( p_cep->p_mad, &p_cep->av[p_cep->idx_primary] ); + + p_req = (mad_cm_req_t*)p_cep->p_mad->p_mad_buf; + + ci_ca_lock_attr( p_port_cep->h_ca->obj.p_ci_ca ); + /* + * Store the local CA's ack timeout for use when computing + * the local ACK timeout. + */ + p_cep->local_ack_delay = + p_port_cep->h_ca->obj.p_ci_ca->p_pnp_attr->local_ack_delay; + ci_ca_unlock_attr( p_port_cep->h_ca->obj.p_ci_ca ); + + /* Format the primary path. */ + __format_req_path( p_cm_req->p_primary_path, + p_cep->local_ack_delay, &p_req->primary_path ); + + if( p_cm_req->p_alt_path ) + { + /* Format the alternate path. */ + __format_req_path( p_cm_req->p_alt_path, + p_cep->local_ack_delay, &p_req->alternate_path ); + } + else + { + cl_memclr( &p_req->alternate_path, sizeof(req_path_info_t) ); + } + + /* Set the local communication in the REQ. */ + p_req->local_comm_id = p_cep->local_comm_id; + p_req->sid = p_cm_req->service_id; + p_req->local_ca_guid = p_port_cep->h_ca->obj.p_ci_ca->verbs.guid; + + conn_req_set_lcl_qpn( p_cep->local_qpn, p_req ); + conn_req_set_resp_res( p_cm_req->resp_res, p_req ); + conn_req_set_init_depth( p_cm_req->init_depth, p_req ); + conn_req_set_remote_resp_timeout( p_cm_req->remote_resp_timeout, p_req ); + conn_req_set_qp_type( p_cm_req->qp_type, p_req ); + conn_req_set_flow_ctrl( p_cm_req->flow_ctrl, p_req ); + conn_req_set_starting_psn( p_cm_req->starting_psn, p_req ); + + conn_req_set_lcl_resp_timeout( p_cm_req->local_resp_timeout, p_req ); + conn_req_set_retry_cnt( p_cm_req->retry_cnt, p_req ); + + p_req->pkey = p_cm_req->p_primary_path->pkey; + + conn_req_set_mtu( ib_path_rec_mtu( p_cm_req->p_primary_path ), p_req ); + conn_req_set_rnr_retry_cnt( p_cm_req->rnr_retry_cnt, p_req ); + + conn_req_set_max_cm_retries( p_cm_req->max_cm_retries, p_req ); + status = conn_req_set_pdata( + p_cm_req->p_pdata, p_cm_req->pdata_len, p_req ); + + conn_req_clr_rsvd_fields( p_req ); + + AL_EXIT( AL_DBG_CM ); + return status; +} + + +static ib_api_status_t +__save_user_req( + IN kcep_t* const p_cep, + IN const iba_cm_req* const p_cm_req, + IN uint8_t rnr_nak_timeout, + OUT cep_agent_t** const pp_port_cep ) +{ + cep_agent_t *p_port_cep; + + AL_ENTER( AL_DBG_CM ); + + if( !p_cm_req->p_primary_path ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("Invalid primary path record.\n") ); + return IB_INVALID_SETTING; + } + + p_cep->sid = p_cm_req->service_id; + p_cep->idx_primary = 0; + p_cep->p2p = FALSE; + p_cep->p_cmp_buf = NULL; + p_cep->cmp_len = 0; + p_cep->cmp_offset = 0; + p_cep->was_active = TRUE; + + /* Validate the primary path. */ + p_port_cep = __format_path_av( p_cm_req->p_primary_path, &p_cep->av[0] ); + if( !p_port_cep ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("Primary path unrealizable.\n") ); + return IB_INVALID_SETTING; + } + + p_cep->av[0].attr.conn.seq_err_retry_cnt = p_cm_req->retry_cnt; + + p_cep->local_ca_guid = p_port_cep->h_ca->obj.p_ci_ca->verbs.guid; + + *pp_port_cep = p_port_cep; + + /* + * Store the PKEY so we can ensure that alternate paths are + * on the same partition. + */ + p_cep->pkey = p_cm_req->p_primary_path->pkey; + + p_cep->max_2pkt_life = ib_path_rec_pkt_life( p_cm_req->p_primary_path ) + 1; + + if( p_cm_req->p_alt_path ) + { + /* MTUs must match since they are specified only once. */ + if( ib_path_rec_mtu( p_cm_req->p_primary_path ) != + ib_path_rec_mtu( p_cm_req->p_alt_path ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("Mismatched primary and alternate path MTUs.\n") ); + return IB_INVALID_SETTING; + } + + /* The PKEY must match too. */ + if( p_cm_req->p_alt_path->pkey != p_cm_req->p_primary_path->pkey ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("Mismatched pimary and alternate PKEYs.\n") ); + return IB_INVALID_SETTING; + } + + p_port_cep = + __format_path_av( p_cm_req->p_alt_path, &p_cep->av[1] ); + if( p_port_cep && + p_port_cep->h_ca->obj.p_ci_ca->verbs.guid != p_cep->local_ca_guid ) + { + /* Alternate path is not on same CA. */ + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("Alternate path unrealizable.\n") ); + return IB_INVALID_SETTING; + } + + p_cep->av[1].attr.conn.seq_err_retry_cnt = p_cm_req->retry_cnt; + + p_cep->max_2pkt_life = max( p_cep->max_2pkt_life, + (ib_path_rec_pkt_life( p_cm_req->p_alt_path ) + 1) ); + } + else + { + cl_memclr( &p_cep->av[1], sizeof(kcep_av_t) ); + } + + p_cep->p_cid->modifier++; + /* + * We don't ever want a modifier of zero for the CID at index zero + * since it would result in a total CID of zero. + */ + if( !p_cep->cid && !p_cep->p_cid->modifier ) + p_cep->p_cid->modifier++; + + /* Store pertinent information in the connection. */ + p_cep->local_comm_id = p_cep->cid | (p_cep->p_cid->modifier << 24); + p_cep->remote_comm_id = 0; + + /* Cache the local QPN. */ + p_cep->local_qpn = p_cm_req->qpn; + p_cep->remote_ca_guid = 0; + p_cep->remote_qpn = 0; + + /* Retry timeout is remote CM response timeout plus 2 * packet life. */ + p_cep->retry_timeout = __calc_mad_timeout( p_cep->max_2pkt_life ) + + __calc_mad_timeout( p_cm_req->remote_resp_timeout ); + + + /* Store the retry count. */ + p_cep->max_cm_retries = p_cm_req->max_cm_retries; + + /* + * Clear the maximum packet lifetime, used to calculate timewait. + * It will be set when we transition into the established state. + */ + p_cep->timewait_time.QuadPart = 0; + + p_cep->rq_psn = p_cm_req->starting_psn; + + p_cep->rnr_nak_timeout = rnr_nak_timeout; + + AL_EXIT( AL_DBG_CM ); + return IB_SUCCESS; +} + + +ib_api_status_t +kal_cep_pre_req( + IN ib_al_handle_t h_al, + IN net32_t cid, + IN const iba_cm_req* const p_cm_req, + IN uint8_t rnr_nak_timeout, + IN OUT ib_qp_mod_t* const p_init OPTIONAL ) +{ + ib_api_status_t status; + kcep_t *p_cep; + KLOCK_QUEUE_HANDLE hdl; + cep_agent_t *p_port_cep; + + AL_PRINT( TRACE_LEVEL_VERBOSE, AL_DBG_CM, ("[ CID = %d\n", cid) ); + + CL_ASSERT( h_al ); + CL_ASSERT( p_cm_req ); + + KeAcquireInStackQueuedSpinLock( &gp_cep_mgr->lock, &hdl ); + p_cep = __lookup_cep( h_al, cid ); + if( !p_cep ) + { + KeReleaseInStackQueuedSpinLock( &hdl ); + AL_EXIT( AL_DBG_CM ); + return IB_INVALID_HANDLE; + } + + switch( p_cep->state ) + { + case CEP_STATE_PRE_REQ: + CL_ASSERT( p_cep->p_mad ); + ib_put_mad( p_cep->p_mad ); + p_cep->p_mad = NULL; + /* Fall through. */ + case CEP_STATE_IDLE: + status = __save_user_req( p_cep, p_cm_req, rnr_nak_timeout, &p_port_cep ); + if( status != IB_SUCCESS ) + break; + + status = + ib_get_mad( p_port_cep->pool_key, MAD_BLOCK_SIZE, &p_cep->p_mad ); + if( status != IB_SUCCESS ) + break; + + status = __format_req( p_port_cep, p_cep, p_cm_req ); + if( status != IB_SUCCESS ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("Invalid pdata length.\n") ); + ib_put_mad( p_cep->p_mad ); + p_cep->p_mad = NULL; + break; + } + + /* Format the INIT qp modify attributes. */ + if( p_init ) + { + p_init->req_state = IB_QPS_INIT; + p_init->state.init.primary_port = + p_cep->av[p_cep->idx_primary].attr.port_num; + p_init->state.init.qkey = 0; + p_init->state.init.pkey_index = + p_cep->av[p_cep->idx_primary].pkey_index; + p_init->state.init.access_ctrl = IB_AC_LOCAL_WRITE; + } + p_cep->state = CEP_STATE_PRE_REQ; + break; + + case CEP_STATE_TIMEWAIT: + status = IB_QP_IN_TIMEWAIT; + break; + + default: + AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM, + ("Invalid state: %d\n", p_cep->state) ); + status = IB_INVALID_STATE; + } + KeReleaseInStackQueuedSpinLock( &hdl ); + AL_EXIT( AL_DBG_CM ); + return status; +} + +ib_api_status_t +al_cep_pre_req( + IN ib_al_handle_t h_al, + IN net32_t cid, + IN const ib_cm_req_t* const p_cm_req, + OUT ib_qp_mod_t* const p_init ) +{ + iba_cm_req req; + + RtlZeroMemory(&req, sizeof req); + req.service_id = p_cm_req->svc_id; + + req.p_primary_path = p_cm_req->p_primary_path; + req.p_alt_path = p_cm_req->p_alt_path; + + req.qpn = p_cm_req->h_qp->num; + req.qp_type = p_cm_req->qp_type; + req.starting_psn = req.qpn; + + req.p_pdata = (void *) p_cm_req->p_req_pdata; + req.pdata_len = p_cm_req->req_length; + + req.max_cm_retries = p_cm_req->max_cm_retries; + req.resp_res = p_cm_req->resp_res; + req.init_depth = p_cm_req->init_depth; + req.remote_resp_timeout = p_cm_req->remote_resp_timeout; + req.flow_ctrl = (uint8_t) p_cm_req->flow_ctrl; + req.local_resp_timeout = p_cm_req->local_resp_timeout; + req.rnr_retry_cnt = p_cm_req->rnr_retry_cnt; + req.retry_cnt = p_cm_req->retry_cnt; + req.srq = (uint8_t) (p_cm_req->h_qp->h_srq != NULL); + + return kal_cep_pre_req(h_al, cid, &req, p_cm_req->rnr_nak_timeout, p_init); +} + +ib_api_status_t +al_cep_send_req( + IN ib_al_handle_t h_al, + IN net32_t cid ) +{ + ib_api_status_t status; + kcep_t *p_cep; + KLOCK_QUEUE_HANDLE hdl; + cep_agent_t *p_port_cep; + + AL_PRINT( TRACE_LEVEL_VERBOSE, AL_DBG_CM, ("[ CID = %d\n", cid) ); + + CL_ASSERT( h_al ); + + KeAcquireInStackQueuedSpinLock( &gp_cep_mgr->lock, &hdl ); + p_cep = __lookup_cep( h_al, cid ); + if( !p_cep ) + { + KeReleaseInStackQueuedSpinLock( &hdl ); + AL_EXIT( AL_DBG_CM ); + return IB_INVALID_HANDLE; + } + + switch( p_cep->state ) + { + case CEP_STATE_PRE_REQ: + CL_ASSERT( p_cep->p_mad ); + p_port_cep = __get_cep_agent( p_cep ); + if( !p_port_cep ) + { + ib_put_mad( p_cep->p_mad ); + p_cep->state = CEP_STATE_IDLE; + status = IB_INVALID_SETTING; + } + else + { + status = __cep_send_retry( p_port_cep, p_cep, p_cep->p_mad ); + + if( status == IB_SUCCESS ) + p_cep->state = CEP_STATE_REQ_SENT; + else + p_cep->state = CEP_STATE_IDLE; + } + p_cep->p_mad = NULL; + break; + + default: + AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM, + ("Invalid state: %d\n", p_cep->state) ); + status = IB_INVALID_STATE; + } + KeReleaseInStackQueuedSpinLock( &hdl ); + AL_EXIT( AL_DBG_CM ); + return status; +} + + +static void +__save_user_rep( + IN cep_agent_t* const p_port_cep, + IN kcep_t* const p_cep, + IN const iba_cm_rep* const p_cm_rep, + IN uint8_t rnr_nak_timeout ) +{ + AL_ENTER( AL_DBG_CM ); + + p_cep->local_qpn = p_cm_rep->qpn; + p_cep->rq_psn = p_cm_rep->starting_psn; + p_cep->init_depth = p_cm_rep->init_depth; + + ci_ca_lock_attr( p_port_cep->h_ca->obj.p_ci_ca ); + /* Check the CA's responder resource max and trim if necessary. */ + if( p_port_cep->h_ca->obj.p_ci_ca->p_pnp_attr->max_qp_resp_res < + p_cep->resp_res ) + { + /* + * The CA cannot handle the requested responder resources. + * Set the response to the CA's maximum. + */ + p_cep->resp_res = + p_port_cep->h_ca->obj.p_ci_ca->p_pnp_attr->max_qp_resp_res; + } + ci_ca_unlock_attr( p_port_cep->h_ca->obj.p_ci_ca ); + + p_cep->rnr_nak_timeout = rnr_nak_timeout; + + AL_EXIT( AL_DBG_CM ); +} + + +static ib_api_status_t +__format_rep( + IN cep_agent_t* const p_port_cep, + IN kcep_t* const p_cep, + IN const iba_cm_rep* const p_cm_rep ) +{ + ib_api_status_t status; + mad_cm_rep_t *p_rep; + + AL_ENTER( AL_DBG_CM ); + + CL_ASSERT( p_cep ); + CL_ASSERT( p_cm_rep ); + CL_ASSERT( p_cep->p_mad ); + + /* Format the MAD header. */ + __format_mad_hdr( p_cep->p_mad->p_mad_buf, p_cep, CM_REP_ATTR_ID ); + + /* Set the addressing information in the MAD. */ + __format_mad_av( p_cep->p_mad, &p_cep->av[p_cep->idx_primary] ); + + p_rep = (mad_cm_rep_t*)p_cep->p_mad->p_mad_buf; + + p_rep->local_comm_id = p_cep->local_comm_id; + p_rep->remote_comm_id = p_cep->remote_comm_id; + conn_rep_set_lcl_qpn( p_cep->local_qpn, p_rep ); + conn_rep_set_starting_psn( p_cep->rq_psn, p_rep ); + + if( p_cm_rep->failover_accepted != IB_FAILOVER_ACCEPT_SUCCESS ) + { + /* + * Failover rejected - clear the alternate AV information. + * Note that at this point, the alternate is always at index 1. + */ + cl_memclr( &p_cep->av[1], sizeof(kcep_av_t) ); + } + else if( !p_cep->av[1].port_guid ) + { + /* + * Always reject alternate path if it's zero. We might + * have cleared the AV because it was unrealizable when + * processing the REQ. + */ + conn_rep_set_failover( IB_FAILOVER_ACCEPT_ERROR, p_rep ); + } + else + { + conn_rep_set_failover( p_cm_rep->failover_accepted, p_rep ); + } + + p_rep->resp_resources = p_cep->resp_res; + + ci_ca_lock_attr( p_port_cep->h_ca->obj.p_ci_ca ); + conn_rep_set_target_ack_delay( + p_port_cep->h_ca->obj.p_ci_ca->p_pnp_attr->local_ack_delay, p_rep ); + ci_ca_unlock_attr( p_port_cep->h_ca->obj.p_ci_ca ); + + p_rep->initiator_depth = p_cep->init_depth; + + conn_rep_set_e2e_flow_ctl( p_cm_rep->flow_ctrl, p_rep ); + + conn_rep_set_rnr_retry_cnt( + (uint8_t)(p_cm_rep->rnr_retry_cnt & 0x07), p_rep ); + + /* Local CA guid should have been set when processing the received REQ. */ + CL_ASSERT( p_cep->local_ca_guid ); + p_rep->local_ca_guid = p_cep->local_ca_guid; + + status = conn_rep_set_pdata( + p_cm_rep->p_pdata, p_cm_rep->pdata_len, p_rep ); + + conn_rep_clr_rsvd_fields( p_rep ); + + AL_EXIT( AL_DBG_CM ); + return status; +} + + + +static ib_api_status_t +__al_cep_pre_rep( + IN kcep_t *p_cep, + IN const iba_cm_rep* const p_cm_rep, + IN uint8_t rnr_nak_timeout, + OUT ib_qp_mod_t* const p_init OPTIONAL ) +{ + ib_api_status_t status; + cep_agent_t *p_port_cep; + + AL_ENTER( AL_DBG_CM ); + + CL_ASSERT( p_cm_rep ); + + switch( p_cep->state ) + { + case CEP_STATE_PRE_REP: + case CEP_STATE_PRE_REP_MRA_SENT: + CL_ASSERT( p_cep->p_mad ); + ib_put_mad( p_cep->p_mad ); + p_cep->p_mad = NULL; + /* Fall through. */ + case CEP_STATE_REQ_RCVD: + case CEP_STATE_REQ_MRA_SENT: + CL_ASSERT( !p_cep->p_mad ); + status = + __cep_get_mad( p_cep, CM_REP_ATTR_ID, &p_port_cep, &p_cep->p_mad ); + if( status != IB_SUCCESS ) + break; + + __save_user_rep( p_port_cep, p_cep, p_cm_rep, rnr_nak_timeout ); + + status = __format_rep( p_port_cep, p_cep, p_cm_rep ); + if( status != IB_SUCCESS ) + { + ib_put_mad( p_cep->p_mad ); + p_cep->p_mad = NULL; + break; + } + + /* Format the INIT qp modify attributes. */ + if( p_init ) + { + p_init->req_state = IB_QPS_INIT; + p_init->state.init.primary_port = + p_cep->av[p_cep->idx_primary].attr.port_num; + p_init->state.init.qkey = 0; + p_init->state.init.pkey_index = + p_cep->av[p_cep->idx_primary].pkey_index; + p_init->state.init.access_ctrl = IB_AC_LOCAL_WRITE; + } + /* Just OR in the PREP bit into the state. */ + p_cep->state |= CEP_STATE_PREP; + break; + + default: + AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM, + ("Invalid state: %d\n", p_cep->state) ); + status = IB_INVALID_STATE; + } + AL_EXIT( AL_DBG_CM ); + return status; +} + + +ib_api_status_t +al_cep_pre_rep( + IN ib_al_handle_t h_al, + IN net32_t cid, + IN void* context, + IN ib_pfn_destroy_cb_t pfn_destroy_cb, + IN const ib_cm_rep_t* const p_cm_rep, + IN OUT net32_t* const p_cid, + OUT ib_qp_mod_t* const p_init ) +{ + kcep_t *p_cep; + iba_cm_rep rep; + KLOCK_QUEUE_HANDLE hdl; + ib_api_status_t status; + + RtlZeroMemory(&rep, sizeof rep); + rep.qpn = p_cm_rep->h_qp->num; + rep.starting_psn = rep.qpn; + + rep.p_pdata = (void *) p_cm_rep->p_rep_pdata; + rep.pdata_len = p_cm_rep->rep_length; + + rep.failover_accepted = p_cm_rep->failover_accepted; + rep.init_depth = p_cm_rep->init_depth; + rep.flow_ctrl = (uint8_t) p_cm_rep->flow_ctrl; + rep.rnr_retry_cnt = p_cm_rep->rnr_retry_cnt; + rep.srq = (uint8_t) (p_cm_rep->h_qp->h_srq != NULL); + + KeAcquireInStackQueuedSpinLock( &gp_cep_mgr->lock, &hdl ); + p_cep = __lookup_cep( h_al, cid ); + if (!p_cep ) + { + status = IB_INVALID_HANDLE; + goto out; + } + + rep.resp_res = p_cep->resp_res; + status = __al_cep_pre_rep( p_cep, &rep, p_cm_rep->rnr_nak_timeout, p_init ); + if ( status == IB_SUCCESS ) + { + p_cep->context = context; + p_cep->pfn_destroy_cb = pfn_destroy_cb; + *p_cid = cid; + } + +out: + KeReleaseInStackQueuedSpinLock( &hdl ); + return status; +} + + +ib_api_status_t +kal_cep_pre_rep( + IN ib_al_handle_t h_al, + IN net32_t cid, + IN const iba_cm_rep* const p_cm_rep, + IN uint8_t rnr_nak_timeout, + OUT ib_qp_mod_t* const p_init OPTIONAL ) +{ + ib_api_status_t status; + kcep_t *p_cep; + KLOCK_QUEUE_HANDLE hdl; + + AL_PRINT( TRACE_LEVEL_VERBOSE, AL_DBG_CM, ("[ CID = %d\n", cid) ); + + CL_ASSERT( h_al ); + CL_ASSERT( p_cm_rep ); + + KeAcquireInStackQueuedSpinLock( &gp_cep_mgr->lock, &hdl ); + p_cep = __lookup_cep( h_al, cid ); + if( !p_cep ) + { + status = IB_INVALID_HANDLE; + goto out; + } + + status = __al_cep_pre_rep( p_cep, p_cm_rep, rnr_nak_timeout, p_init ); + +out: + KeReleaseInStackQueuedSpinLock( &hdl ); + AL_EXIT( AL_DBG_CM ); + return status; +} + +ib_api_status_t +al_cep_send_rep( + IN ib_al_handle_t h_al, + IN net32_t cid ) +{ + ib_api_status_t status; + kcep_t *p_cep; + KLOCK_QUEUE_HANDLE hdl; + cep_agent_t *p_port_cep; + + AL_PRINT( TRACE_LEVEL_VERBOSE, AL_DBG_CM, ("[ CID = %d\n", cid) ); + + CL_ASSERT( h_al ); + + KeAcquireInStackQueuedSpinLock( &gp_cep_mgr->lock, &hdl ); + p_cep = __lookup_cep( h_al, cid ); + if( !p_cep ) + { + status = IB_INVALID_HANDLE; + goto out; + } + + switch( p_cep->state ) + { + case CEP_STATE_PRE_REP: + case CEP_STATE_PRE_REP_MRA_SENT: + CL_ASSERT( p_cep->p_mad ); + p_port_cep = __get_cep_agent( p_cep ); + if( !p_port_cep ) + { + // Why call ib_put_mad() here but not below? + ib_put_mad( p_cep->p_mad ); + // Why call __remove_cep() below but not here? + p_cep->state = CEP_STATE_IDLE; + status = IB_INSUFFICIENT_RESOURCES; + } + else + { + status = __cep_send_retry( p_port_cep, p_cep, p_cep->p_mad ); + if( status == IB_SUCCESS ) + { + p_cep->state = CEP_STATE_REP_SENT; + } + else + { + __remove_cep( p_cep ); + p_cep->state = CEP_STATE_IDLE; + } + } + p_cep->p_mad = NULL; + break; + + default: + AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM, + ("Invalid state: %d\n", p_cep->state) ); + status = IB_INVALID_STATE; + } +out: + KeReleaseInStackQueuedSpinLock( &hdl ); + AL_EXIT( AL_DBG_CM ); + return status; +} + + +static inline ib_api_status_t +__format_rtu( + IN kcep_t* const p_cep, + IN const uint8_t* p_pdata OPTIONAL, + IN uint8_t pdata_len, + IN OUT ib_mad_element_t* const p_mad ) +{ + ib_api_status_t status; + mad_cm_rtu_t *p_rtu; + + AL_ENTER( AL_DBG_CM ); + + p_rtu = (mad_cm_rtu_t*)p_mad->p_mad_buf; + + p_rtu->local_comm_id = p_cep->local_comm_id; + p_rtu->remote_comm_id = p_cep->remote_comm_id; + + /* copy optional data */ + status = conn_rtu_set_pdata( p_pdata, pdata_len, p_rtu ); + + /* Store the RTU MAD so we can repeat it if we get a repeated REP. */ + if( status == IB_SUCCESS ) + p_cep->mads.rtu = *p_rtu; + + AL_EXIT( AL_DBG_CM ); + return status; +} + + +ib_api_status_t +al_cep_rtu( + IN ib_al_handle_t h_al, + IN net32_t cid, + IN const uint8_t* p_pdata OPTIONAL, + IN uint8_t pdata_len ) +{ + ib_api_status_t status; + kcep_t *p_cep; + KLOCK_QUEUE_HANDLE hdl; + cep_agent_t *p_port_cep; + ib_mad_element_t *p_mad; + + AL_PRINT( TRACE_LEVEL_VERBOSE, AL_DBG_CM, ("[ CID = %d\n", cid) ); + + CL_ASSERT( h_al ); + + KeAcquireInStackQueuedSpinLock( &gp_cep_mgr->lock, &hdl ); + p_cep = __lookup_cep( h_al, cid ); + if( !p_cep ) + { + KeReleaseInStackQueuedSpinLock( &hdl ); + AL_EXIT( AL_DBG_CM ); + return IB_INVALID_HANDLE; + } + + switch( p_cep->state ) + { + case CEP_STATE_REP_RCVD: + case CEP_STATE_REP_MRA_SENT: + status = __cep_get_mad( p_cep, CM_RTU_ATTR_ID, &p_port_cep, &p_mad ); + if( status != IB_SUCCESS ) + break; + + status = __format_rtu( p_cep, p_pdata, pdata_len, p_mad ); + if( status != IB_SUCCESS ) + { + ib_put_mad( p_mad ); + break; + } + + /* Update the timewait time. */ + __calc_timewait( p_cep ); + + p_cep->state = CEP_STATE_ESTABLISHED; + + __cep_send_mad( p_port_cep, p_mad ); + /* Send failures will get another chance if we receive a repeated REP. */ + status = IB_SUCCESS; + break; + + default: + AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM, + ("Invalid state: %d\n", p_cep->state) ); + status = IB_INVALID_STATE; + } + KeReleaseInStackQueuedSpinLock( &hdl ); + AL_EXIT( AL_DBG_CM ); + return status; +} + + +ib_api_status_t +al_cep_rej( + IN ib_al_handle_t h_al, + IN net32_t cid, + IN ib_rej_status_t rej_status, + IN const uint8_t* const p_ari, + IN uint8_t ari_len, + IN const uint8_t* const p_pdata, + IN uint8_t pdata_len ) +{ + ib_api_status_t status; + kcep_t *p_cep; + KLOCK_QUEUE_HANDLE hdl; + + AL_PRINT( TRACE_LEVEL_VERBOSE, AL_DBG_CM, ("[ CID = %d\n", cid) ); + + CL_ASSERT( h_al ); + + KeAcquireInStackQueuedSpinLock( &gp_cep_mgr->lock, &hdl ); + p_cep = __lookup_cep( h_al, cid ); + if( !p_cep ) + { + KeReleaseInStackQueuedSpinLock( &hdl ); + AL_EXIT( AL_DBG_CM ); + return IB_INVALID_HANDLE; + } + + switch( p_cep->state ) + { + case CEP_STATE_REQ_RCVD: + case CEP_STATE_REQ_MRA_SENT: + status = __do_cep_rej( + p_cep, rej_status, p_ari, ari_len, p_pdata, pdata_len ); + __remove_cep( p_cep ); + p_cep->state = CEP_STATE_IDLE; + break; + + case CEP_STATE_REP_RCVD: + case CEP_STATE_REP_MRA_SENT: + status = __do_cep_rej( + p_cep, rej_status, p_ari, ari_len, p_pdata, pdata_len ); + p_cep->state = CEP_STATE_TIMEWAIT; + __insert_timewait( p_cep ); + break; + + default: + AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM, + ("Invalid state: %d\n", p_cep->state) ); + status = IB_INVALID_STATE; + } + + KeReleaseInStackQueuedSpinLock( &hdl ); + AL_EXIT( AL_DBG_CM ); + return status; +} + + +static ib_api_status_t +__format_mra( + IN kcep_t* const p_cep, + IN const uint8_t msg_mraed, + IN const ib_cm_mra_t* const p_cm_mra, + IN OUT ib_mad_element_t* const p_mad ) +{ + ib_api_status_t status; + mad_cm_mra_t *p_mra; + + AL_ENTER( AL_DBG_CM ); + + p_mra = (mad_cm_mra_t*)p_mad->p_mad_buf; + + conn_mra_set_msg_mraed( msg_mraed, p_mra ); + + p_mra->local_comm_id = p_cep->local_comm_id; + p_mra->remote_comm_id = p_cep->remote_comm_id; + + conn_mra_set_svc_timeout( p_cm_mra->svc_timeout, p_mra ); + status = conn_mra_set_pdata( + p_cm_mra->p_mra_pdata, p_cm_mra->mra_length, p_mra ); + if( status != IB_SUCCESS ) + { + AL_EXIT( AL_DBG_CM ); + return status; + } + conn_mra_clr_rsvd_fields( p_mra ); + + /* Save the MRA so we can repeat it if we get a repeated message. */ + p_cep->mads.mra = *p_mra; + + AL_EXIT( AL_DBG_CM ); + return IB_SUCCESS; +} + + +ib_api_status_t +al_cep_mra( + IN ib_al_handle_t h_al, + IN net32_t cid, + IN const ib_cm_mra_t* const p_cm_mra ) +{ + ib_api_status_t status; + kcep_t *p_cep; + KLOCK_QUEUE_HANDLE hdl; + cep_agent_t *p_port_cep; + ib_mad_element_t *p_mad; + uint8_t msg_mraed; + + AL_PRINT( TRACE_LEVEL_VERBOSE, AL_DBG_CM, ("[ CID = %d\n", cid) ); + + CL_ASSERT( h_al ); + CL_ASSERT( p_cm_mra ); + + KeAcquireInStackQueuedSpinLock( &gp_cep_mgr->lock, &hdl ); + p_cep = __lookup_cep( h_al, cid ); + if( !p_cep ) + { + KeReleaseInStackQueuedSpinLock( &hdl ); + AL_EXIT( AL_DBG_CM ); + return IB_INVALID_HANDLE; + } + + switch( p_cep->state ) + { + case CEP_STATE_REQ_RCVD: + case CEP_STATE_PRE_REP: + msg_mraed = 0; + break; + + case CEP_STATE_REP_RCVD: + msg_mraed = 1; + break; + + case CEP_STATE_PRE_APR: + case CEP_STATE_LAP_RCVD: + msg_mraed = 2; + break; + + default: + status = IB_INVALID_STATE; + goto done; + } + + status = __cep_get_mad( p_cep, CM_MRA_ATTR_ID, &p_port_cep, &p_mad ); + if( status != IB_SUCCESS ) + goto done; + + status = __format_mra( p_cep, msg_mraed, p_cm_mra, p_mad ); + if( status != IB_SUCCESS ) + { + ib_put_mad( p_mad ); + goto done; + } + + p_cep->state |= CEP_STATE_MRA; + + __cep_send_mad( p_port_cep, p_mad ); + status = IB_SUCCESS; + +done: + KeReleaseInStackQueuedSpinLock( &hdl ); + AL_EXIT( AL_DBG_CM ); + return status; +} + + + +static ib_api_status_t +__format_lap( + IN kcep_t* const p_cep, + IN const ib_cm_lap_t* const p_cm_lap, + IN OUT ib_mad_element_t* const p_mad ) +{ + ib_api_status_t status; + mad_cm_lap_t *p_lap; + + AL_ENTER( AL_DBG_CM ); + + __format_mad_hdr( p_mad->p_mad_buf, p_cep, CM_LAP_ATTR_ID ); + + __format_mad_av( p_mad, &p_cep->av[((p_cep->idx_primary + 1) & 0x1)] ); + + p_lap = (mad_cm_lap_t*)p_mad->p_mad_buf; + + p_lap->alternate_path.local_lid = p_cm_lap->p_alt_path->slid; + p_lap->alternate_path.remote_lid = p_cm_lap->p_alt_path->dlid; + p_lap->alternate_path.local_gid = p_cm_lap->p_alt_path->sgid; + p_lap->alternate_path.remote_gid = p_cm_lap->p_alt_path->dgid; + + /* Set Flow Label and Packet Rate */ + conn_lap_path_set_flow_lbl( + ib_path_rec_flow_lbl( p_cm_lap->p_alt_path ), &p_lap->alternate_path ); + conn_lap_path_set_tclass( + p_cm_lap->p_alt_path->tclass, &p_lap->alternate_path ); + + p_lap->alternate_path.hop_limit = + ib_path_rec_hop_limit( p_cm_lap->p_alt_path ); + conn_lap_path_set_pkt_rate( + ib_path_rec_rate( p_cm_lap->p_alt_path ), &p_lap->alternate_path ); + + /* Set SL and Subnet Local */ + conn_lap_path_set_svc_lvl( + ib_path_rec_sl( p_cm_lap->p_alt_path ), &p_lap->alternate_path ); + conn_lap_path_set_subn_lcl( + ib_gid_is_link_local( &p_cm_lap->p_alt_path->dgid ), + &p_lap->alternate_path ); + + conn_lap_path_set_lcl_ack_timeout( + calc_lcl_ack_timeout( ib_path_rec_pkt_life( p_cm_lap->p_alt_path ) + 1, + p_cep->local_ack_delay), &p_lap->alternate_path ); + + conn_lap_path_clr_rsvd_fields( &p_lap->alternate_path ); + + p_lap->local_comm_id = p_cep->local_comm_id; + p_lap->remote_comm_id = p_cep->remote_comm_id; + conn_lap_set_remote_qpn( p_cep->remote_qpn, p_lap ); + conn_lap_set_resp_timeout( p_cm_lap->remote_resp_timeout, p_lap ); + + status = conn_lap_set_pdata( + p_cm_lap->p_lap_pdata, p_cm_lap->lap_length, p_lap ); + if( status != IB_SUCCESS ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("lap pdata invalid.\n") ); + return status; + } + + conn_lap_clr_rsvd_fields( p_lap ); + + AL_EXIT( AL_DBG_CM ); + return IB_SUCCESS; +} + + +ib_api_status_t +al_cep_lap( + IN ib_al_handle_t h_al, + IN net32_t cid, + IN const ib_cm_lap_t* const p_cm_lap ) +{ + ib_api_status_t status; + kcep_t *p_cep; + KLOCK_QUEUE_HANDLE hdl; + cep_agent_t *p_port_cep; + ib_mad_element_t *p_mad; + + AL_PRINT( TRACE_LEVEL_VERBOSE, AL_DBG_CM, ("[ CID = %d\n", cid) ); + + CL_ASSERT( h_al ); + CL_ASSERT( p_cm_lap ); + CL_ASSERT( p_cm_lap->p_alt_path ); + + KeAcquireInStackQueuedSpinLock( &gp_cep_mgr->lock, &hdl ); + p_cep = __lookup_cep( h_al, cid ); + if( !p_cep ) + { + KeReleaseInStackQueuedSpinLock( &hdl ); + AL_EXIT( AL_DBG_CM ); + return IB_INVALID_HANDLE; + } + + switch( p_cep->state ) + { + case CEP_STATE_ESTABLISHED: + if( !p_cep->was_active ) + { + /* Only the side that took the active role can initialte a LAP. */ + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("Only the active side of a connection can initiate a LAP.\n") ); + status = IB_INVALID_STATE; + break; + } + + /* + * Format the AV information - store in the temporary location until we + * get the APR indicating acceptance. + */ + p_port_cep = __format_path_av( p_cm_lap->p_alt_path, &p_cep->alt_av ); + if( !p_port_cep ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("Alternate path invalid!\n") ); + status = IB_INVALID_SETTING; + break; + } + + p_cep->alt_av.attr.conn.seq_err_retry_cnt = + p_cep->av[p_cep->idx_primary].attr.conn.seq_err_retry_cnt; + p_cep->alt_av.attr.conn.rnr_retry_cnt = + p_cep->av[p_cep->idx_primary].attr.conn.rnr_retry_cnt; + + if( p_port_cep->h_ca->obj.p_ci_ca->verbs.guid != p_cep->local_ca_guid ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("Alternate CA GUID different from current!\n") ); + status = IB_INVALID_SETTING; + break; + } + + /* Store the alternate path info temporarilly. */ + p_cep->alt_2pkt_life = ib_path_rec_pkt_life( p_cm_lap->p_alt_path ) + 1; + + status = ib_get_mad( p_port_cep->pool_key, MAD_BLOCK_SIZE, &p_mad ); + if( status != IB_SUCCESS ) + break; + + status = __format_lap( p_cep, p_cm_lap, p_mad ); + if( status != IB_SUCCESS ) + break; + + status = __cep_send_retry( p_port_cep, p_cep, p_mad ); + if( status == IB_SUCCESS ) + p_cep->state = CEP_STATE_LAP_SENT; + break; + + default: + AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM, + ("Invalid state: %d\n", p_cep->state) ); + status = IB_INVALID_STATE; + break; + } + KeReleaseInStackQueuedSpinLock( &hdl ); + AL_EXIT( AL_DBG_CM ); + return status; +} + + +static ib_api_status_t +__format_apr( + IN kcep_t* const p_cep, + IN const ib_cm_apr_t* const p_cm_apr, + IN OUT ib_mad_element_t* const p_mad ) +{ + ib_api_status_t status; + mad_cm_apr_t *p_apr; + + AL_ENTER( AL_DBG_CM ); + + p_apr = (mad_cm_apr_t*)p_mad->p_mad_buf; + + p_apr->local_comm_id = p_cep->local_comm_id; + p_apr->remote_comm_id = p_cep->remote_comm_id; + p_apr->status = p_cm_apr->apr_status; + + status = conn_apr_set_apr_info( p_cm_apr->p_info->data, + p_cm_apr->info_length, p_apr ); + if( status != IB_SUCCESS ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("apr_info invalid\n") ); + return status; + } + + status = conn_apr_set_pdata( p_cm_apr->p_apr_pdata, + p_cm_apr->apr_length, p_apr ); + if( status != IB_SUCCESS ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("apr pdata invalid\n") ); + return status; + } + + conn_apr_clr_rsvd_fields( p_apr ); + AL_EXIT( AL_DBG_CM ); + return IB_SUCCESS; +} + + +ib_api_status_t +al_cep_pre_apr( + IN ib_al_handle_t h_al, + IN net32_t cid, + IN const ib_cm_apr_t* const p_cm_apr, + OUT ib_qp_mod_t* const p_apr ) +{ + ib_api_status_t status; + kcep_t *p_cep; + KLOCK_QUEUE_HANDLE hdl; + cep_agent_t *p_port_cep; + + AL_PRINT( TRACE_LEVEL_VERBOSE, AL_DBG_CM, ("[ CID = %d\n", cid) ); + + CL_ASSERT( h_al ); + CL_ASSERT( p_cm_apr ); + CL_ASSERT( p_apr ); + + KeAcquireInStackQueuedSpinLock( &gp_cep_mgr->lock, &hdl ); + p_cep = __lookup_cep( h_al, cid ); + if( !p_cep ) + { + KeReleaseInStackQueuedSpinLock( &hdl ); + AL_EXIT( AL_DBG_CM ); + return IB_INVALID_HANDLE; + } + + switch( p_cep->state ) + { + case CEP_STATE_PRE_APR: + case CEP_STATE_PRE_APR_MRA_SENT: + CL_ASSERT( p_cep->p_mad ); + ib_put_mad( p_cep->p_mad ); + p_cep->p_mad = NULL; + /* Fall through. */ + case CEP_STATE_LAP_RCVD: + case CEP_STATE_LAP_MRA_SENT: + CL_ASSERT( !p_cep->p_mad ); + status = __cep_get_mad( p_cep, CM_APR_ATTR_ID, &p_port_cep, &p_cep->p_mad ); + if( status != IB_SUCCESS ) + break; + + status = __format_apr( p_cep, p_cm_apr, p_cep->p_mad ); + if( status != IB_SUCCESS ) + { + ib_put_mad( p_cep->p_mad ); + p_cep->p_mad = NULL; + break; + } + + if( !p_cm_apr->apr_status ) + { + /* + * Copy the temporary AV and port GUID information into + * the alternate path. + */ + p_cep->av[((p_cep->idx_primary + 1) & 0x1)] = p_cep->alt_av; + + /* Update our maximum packet lifetime. */ + p_cep->max_2pkt_life = + max( p_cep->max_2pkt_life, p_cep->alt_2pkt_life ); + + /* Update our timewait time. */ + __calc_timewait( p_cep ); + + /* Fill in the QP attributes. */ + cl_memclr( p_apr, sizeof(ib_qp_mod_t) ); + p_apr->req_state = IB_QPS_RTS; + p_apr->state.rts.opts = + IB_MOD_QP_ALTERNATE_AV | IB_MOD_QP_APM_STATE; + p_apr->state.rts.alternate_av = p_cep->alt_av.attr; + p_apr->state.rts.apm_state = IB_APM_REARM; + } + + p_cep->state |= CEP_STATE_PREP; + status = IB_SUCCESS; + break; + + default: + AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM, + ("Invalid state: %d\n", p_cep->state) ); + status = IB_INVALID_STATE; + break; + } + KeReleaseInStackQueuedSpinLock( &hdl ); + AL_EXIT( AL_DBG_CM ); + return status; +} + + +ib_api_status_t +al_cep_send_apr( + IN ib_al_handle_t h_al, + IN net32_t cid ) +{ + ib_api_status_t status; + kcep_t *p_cep; + KLOCK_QUEUE_HANDLE hdl; + cep_agent_t *p_port_cep; + + AL_PRINT( TRACE_LEVEL_VERBOSE, AL_DBG_CM, ("[ CID = %d\n", cid) ); + + CL_ASSERT( h_al ); + + KeAcquireInStackQueuedSpinLock( &gp_cep_mgr->lock, &hdl ); + p_cep = __lookup_cep( h_al, cid ); + if( !p_cep ) + { + KeReleaseInStackQueuedSpinLock( &hdl ); + AL_EXIT( AL_DBG_CM ); + return IB_INVALID_HANDLE; + } + + switch( p_cep->state ) + { + case CEP_STATE_PRE_APR: + case CEP_STATE_PRE_APR_MRA_SENT: + CL_ASSERT( p_cep->p_mad ); + p_port_cep = __get_cep_agent( p_cep ); + if( !p_port_cep ) + { + ib_put_mad( p_cep->p_mad ); + status = IB_INSUFFICIENT_RESOURCES; + } + else + { + p_cep->state = CEP_STATE_ESTABLISHED; + + __cep_send_mad( p_port_cep, p_cep->p_mad ); + status = IB_SUCCESS; + } + p_cep->p_mad = NULL; + break; + + default: + AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM, + ("Invalid state: %d\n", p_cep->state) ); + status = IB_INVALID_STATE; + break; + } + KeReleaseInStackQueuedSpinLock( &hdl ); + AL_EXIT( AL_DBG_CM ); + return status; +} + + +ib_api_status_t +al_cep_dreq( + IN ib_al_handle_t h_al, + IN net32_t cid, + IN const uint8_t* const p_pdata, + IN const uint8_t pdata_len ) +{ + ib_api_status_t status; + kcep_t *p_cep; + KLOCK_QUEUE_HANDLE hdl; + cep_agent_t *p_port_cep; + ib_mad_element_t *p_mad; + + AL_PRINT( TRACE_LEVEL_VERBOSE, AL_DBG_CM, ("[ CID = %d\n", cid) ); + + CL_ASSERT( h_al ); + + KeAcquireInStackQueuedSpinLock( &gp_cep_mgr->lock, &hdl ); + p_cep = __lookup_cep( h_al, cid ); + if( !p_cep ) + { + KeReleaseInStackQueuedSpinLock( &hdl ); + AL_EXIT( AL_DBG_CM ); + return IB_INVALID_HANDLE; + } + + switch( p_cep->state ) + { + case CEP_STATE_ESTABLISHED: + case CEP_STATE_LAP_SENT: + case CEP_STATE_LAP_RCVD: + case CEP_STATE_LAP_MRA_SENT: + case CEP_STATE_LAP_MRA_RCVD: + status = __cep_get_mad( p_cep, CM_DREQ_ATTR_ID, &p_port_cep, &p_mad ); + if( status != IB_SUCCESS ) + break; + + status = __format_dreq( p_cep, p_pdata, pdata_len, p_mad ); + if( status != IB_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("__format_dreq returned %s.\n", ib_get_err_str( status )) ); + break; + } + + if( __cep_send_retry( p_port_cep, p_cep, p_mad ) == IB_SUCCESS ) + { + p_cep->state = CEP_STATE_DREQ_SENT; + } + else + { + p_cep->state = CEP_STATE_TIMEWAIT; + __insert_timewait( p_cep ); + } + + status = IB_SUCCESS; + break; + + default: + AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM, + ("Invalid state: %d\n", p_cep->state) ); + status = IB_INVALID_STATE; + break; + } + KeReleaseInStackQueuedSpinLock( &hdl ); + AL_EXIT( AL_DBG_CM ); + return status; +} + + +ib_api_status_t +al_cep_drep( + IN ib_al_handle_t h_al, + IN net32_t cid, + IN const uint8_t* const p_pdata OPTIONAL, + IN const uint8_t pdata_len ) +{ + ib_api_status_t status; + kcep_t *p_cep; + KLOCK_QUEUE_HANDLE hdl; + cep_agent_t *p_port_cep; + ib_mad_element_t *p_mad; + + AL_PRINT( TRACE_LEVEL_VERBOSE, AL_DBG_CM, ("[ CID = %d\n", cid) ); + + CL_ASSERT( h_al ); + + KeAcquireInStackQueuedSpinLock( &gp_cep_mgr->lock, &hdl ); + p_cep = __lookup_cep( h_al, cid ); + if( !p_cep ) + { + KeReleaseInStackQueuedSpinLock( &hdl ); + AL_EXIT( AL_DBG_CM ); + return IB_INVALID_HANDLE; + } + + switch( p_cep->state ) + { + case CEP_STATE_DREQ_RCVD: + status = __cep_get_mad( p_cep, CM_DREP_ATTR_ID, &p_port_cep, &p_mad ); + if( status != IB_SUCCESS ) + break; + + status = __format_drep( p_cep, p_pdata, + pdata_len, (mad_cm_drep_t*)p_mad->p_mad_buf ); + if( status != IB_SUCCESS ) + break; + + __cep_send_mad( p_port_cep, p_mad ); + p_cep->state = CEP_STATE_TIMEWAIT; + __insert_timewait( p_cep ); + break; + + default: + AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM, + ("Invalid state: %d\n", p_cep->state) ); + status = IB_INVALID_STATE; + break; + } + KeReleaseInStackQueuedSpinLock( &hdl ); + AL_EXIT( AL_DBG_CM ); + return status; +} + + +ib_api_status_t +al_cep_migrate( + IN ib_al_handle_t h_al, + IN net32_t cid ) +{ + ib_api_status_t status; + kcep_t *p_cep; + KLOCK_QUEUE_HANDLE hdl; + + AL_PRINT( TRACE_LEVEL_VERBOSE, AL_DBG_CM, ("[ CID = %d\n", cid) ); + + CL_ASSERT( h_al ); + + KeAcquireInStackQueuedSpinLock( &gp_cep_mgr->lock, &hdl ); + p_cep = __lookup_cep( h_al, cid ); + if( !p_cep ) + { + KeReleaseInStackQueuedSpinLock( &hdl ); + AL_EXIT( AL_DBG_CM ); + return IB_INVALID_HANDLE; + } + + switch( p_cep->state ) + { + case CEP_STATE_ESTABLISHED: + case CEP_STATE_LAP_SENT: + case CEP_STATE_LAP_RCVD: + case CEP_STATE_LAP_MRA_SENT: + case CEP_STATE_LAP_MRA_RCVD: + if( p_cep->av[(p_cep->idx_primary + 1) & 0x1].port_guid ) + { + p_cep->idx_primary++; + p_cep->idx_primary &= 0x1; + status = IB_SUCCESS; + break; + } + + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("No alternate path avaialble.\n") ); + + /* Fall through. */ + default: + AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM, + ("Invalid state: %d\n", p_cep->state) ); + status = IB_INVALID_STATE; + break; + } + KeReleaseInStackQueuedSpinLock( &hdl ); + AL_EXIT( AL_DBG_CM ); + return status; +} + + +ib_api_status_t +al_cep_established( + IN ib_al_handle_t h_al, + IN net32_t cid ) +{ + ib_api_status_t status; + kcep_t *p_cep; + KLOCK_QUEUE_HANDLE hdl; + + AL_PRINT( TRACE_LEVEL_VERBOSE, AL_DBG_CM, ("[ CID = %d\n", cid) ); + + CL_ASSERT( h_al ); + + KeAcquireInStackQueuedSpinLock( &gp_cep_mgr->lock, &hdl ); + p_cep = __lookup_cep( h_al, cid ); + if( !p_cep ) + { + KeReleaseInStackQueuedSpinLock( &hdl ); + AL_EXIT( AL_DBG_CM ); + return IB_INVALID_HANDLE; + } + + switch( p_cep->state ) + { + case CEP_STATE_REP_SENT: + case CEP_STATE_REP_MRA_RCVD: + CL_ASSERT( p_cep->p_send_mad ); + ib_cancel_mad( p_cep->h_mad_svc, p_cep->p_send_mad ); + p_cep->p_send_mad = NULL; + p_cep->state = CEP_STATE_ESTABLISHED; + status = IB_SUCCESS; + break; + + default: + AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM, + ("Invalid state: %d\n", p_cep->state) ); + status = IB_INVALID_STATE; + break; + } + KeReleaseInStackQueuedSpinLock( &hdl ); + AL_EXIT( AL_DBG_CM ); + return status; +} + +static void +__format_path(ib_path_rec_t *p_path, req_path_info_t *p_info, + ib_net16_t pkey, uint8_t mtu) +{ + p_path->service_id = 0; + p_path->dgid = p_info->local_gid; + p_path->sgid = p_info->remote_gid; + p_path->dlid = p_info->local_lid; + p_path->slid = p_info->remote_lid; + ib_path_rec_set_hop_flow_raw(p_path, p_info->hop_limit, + conn_req_path_get_flow_lbl(p_info), 0); + p_path->tclass = p_info->traffic_class; + p_path->num_path = 0; + p_path->pkey = pkey; + ib_path_rec_set_sl(p_path, conn_req_path_get_svc_lvl(p_info)); + ib_path_rec_set_qos_class(p_path, 0); + p_path->mtu = mtu; + p_path->rate = conn_req_path_get_pkt_rate(p_info); + p_path->pkt_life = conn_req_path_get_lcl_ack_timeout(p_info); + p_path->preference = 0; + memset(p_path->resv2, 0, sizeof(p_path->resv2)); +} + +static void +__format_event_req(kcep_t *p_cep, mad_cm_req_t *p_mad, iba_cm_req_event *p_req) +{ + p_req->local_ca_guid = p_cep->local_ca_guid; + p_req->remote_ca_guid = p_cep->remote_ca_guid; + p_req->pkey_index = p_cep->av[0].pkey_index; + p_req->port_num = p_cep->av[0].attr.port_num; + p_req->service_id = p_mad->sid; + + p_req->qpn = conn_req_get_lcl_qpn(p_mad); + p_req->qp_type = conn_req_get_qp_type(p_mad); + p_req->starting_psn = conn_req_get_starting_psn(p_mad); + + cl_memcpy(p_req->pdata, p_mad->pdata, IB_REQ_PDATA_SIZE); + + p_req->max_cm_retries = conn_req_get_max_cm_retries(p_mad); + p_req->resp_res = conn_req_get_init_depth(p_mad); + p_req->init_depth = conn_req_get_resp_res(p_mad); + p_req->remote_resp_timeout = conn_req_get_resp_timeout(p_mad); + p_req->flow_ctrl = (uint8_t) conn_req_get_flow_ctrl(p_mad); + p_req->local_resp_timeout = conn_req_get_lcl_resp_timeout(p_mad); + p_req->rnr_retry_cnt = conn_req_get_rnr_retry_cnt(p_mad); + p_req->retry_cnt = conn_req_get_retry_cnt(p_mad); + p_req->srq = 0; // TODO: fix mad_cm_req_t + + __format_path(&p_req->primary_path, &p_mad->primary_path, + p_mad->pkey, conn_req_get_mtu(p_mad)); + + if (p_mad->alternate_path.remote_lid != 0) { + __format_path(&p_req->alt_path, &p_mad->alternate_path, + p_req->primary_path.pkey, p_req->primary_path.mtu); + } else { + cl_memclr(&p_req->alt_path, sizeof p_req->alt_path); + } +} + +static void +__format_event_rep(mad_cm_rep_t *p_mad, iba_cm_rep_event *p_rep) +{ + p_rep->ca_guid = p_mad->local_ca_guid; + p_rep->target_ack_delay = conn_rep_get_target_ack_delay(p_mad); + p_rep->rep.qpn = conn_rep_get_lcl_qpn(p_mad); + p_rep->rep.starting_psn = conn_rep_get_starting_psn(p_mad); + + p_rep->rep.p_pdata = p_mad->pdata; + p_rep->rep.pdata_len = IB_REP_PDATA_SIZE; + + p_rep->rep.failover_accepted = conn_rep_get_failover(p_mad); + p_rep->rep.resp_res = p_mad->initiator_depth; + p_rep->rep.init_depth = p_mad->resp_resources; + p_rep->rep.flow_ctrl = (uint8_t) conn_rep_get_e2e_flow_ctl(p_mad); + p_rep->rep.rnr_retry_cnt = conn_rep_get_rnr_retry_cnt(p_mad); +} + +static void +__format_event_rej(mad_cm_rej_t *p_mad, iba_cm_rej_event *p_rej) +{ + p_rej->ari = p_mad->ari; + p_rej->p_pdata = p_mad->pdata; + p_rej->reason = p_mad->reason; + p_rej->ari_length = conn_rej_get_ari_len(p_mad); + p_rej->pdata_len = IB_REJ_PDATA_SIZE; +} + +static void +__format_event_mra(mad_cm_mra_t *p_mad, iba_cm_mra_event *p_mra) +{ + p_mra->p_pdata = p_mad->pdata; + p_mra->pdata_len = IB_MRA_PDATA_SIZE; + p_mra->service_timeout = conn_mra_get_svc_timeout(p_mad); +} + +/* + * Called after polling a MAD from a CEP to parse the received CM message + * into readable event data. + */ +void +kal_cep_format_event( + IN ib_al_handle_t h_al, + IN net32_t cid, + IN ib_mad_element_t *p_mad, + IN OUT iba_cm_event *p_event) +{ + KLOCK_QUEUE_HANDLE hdl; + kcep_t *p_cep; + + KeAcquireInStackQueuedSpinLock( &gp_cep_mgr->lock, &hdl ); + p_cep = __lookup_cep( h_al, cid ); + KeReleaseInStackQueuedSpinLock( &hdl ); + + switch (p_mad->p_mad_buf->attr_id) { + case CM_REQ_ATTR_ID: + if (p_mad->status == IB_SUCCESS) { + p_event->type = iba_cm_req_received; + __format_event_req(p_cep, (mad_cm_req_t*) p_mad->p_mad_buf, &p_event->data.req); + } else { + p_event->type = iba_cm_req_error; + } + break; + case CM_REP_ATTR_ID: + if (p_mad->status == IB_SUCCESS) { + p_event->type = iba_cm_rep_received; + __format_event_rep((mad_cm_rep_t*) p_mad->p_mad_buf, &p_event->data.rep); + } else { + p_event->type = iba_cm_rep_error; + } + break; + case CM_RTU_ATTR_ID: + p_event->type = iba_cm_rtu_received; + p_event->data.rtu.p_pdata = ((mad_cm_rtu_t*) p_mad)->pdata; + p_event->data.rtu.pdata_len = IB_RTU_PDATA_SIZE; + break; + case CM_DREQ_ATTR_ID: + if (p_mad->status == IB_SUCCESS) { + p_event->type = iba_cm_dreq_received; + p_event->data.dreq.p_pdata = ((mad_cm_dreq_t*) p_mad)->pdata; + p_event->data.dreq.pdata_len = IB_DREQ_PDATA_SIZE; + } else { + p_event->type = iba_cm_dreq_error; + } + break; + case CM_DREP_ATTR_ID: + p_event->type = iba_cm_drep_received; + p_event->data.drep.p_pdata = ((mad_cm_drep_t*) p_mad)->pdata; + p_event->data.drep.pdata_len = IB_DREP_PDATA_SIZE; + break; + case CM_REJ_ATTR_ID: + p_event->type = iba_cm_rej_received; + __format_event_rej((mad_cm_rej_t*) p_mad->p_mad_buf, &p_event->data.rej); + break; + case CM_MRA_ATTR_ID: + p_event->type = iba_cm_mra_received; + __format_event_mra((mad_cm_mra_t*) p_mad->p_mad_buf, &p_event->data.mra); + break; + case CM_LAP_ATTR_ID: + if (p_mad->status == IB_SUCCESS) { + p_event->type = iba_cm_lap_received; + // TODO: format lap event + } else { + p_event->type = iba_cm_lap_error; + } + break; + case CM_APR_ATTR_ID: + p_event->type = iba_cm_apr_received;; + // TODO: format apr event + break; + case CM_SIDR_REQ_ATTR_ID: + if (p_mad->status == IB_SUCCESS) { + p_event->type = iba_cm_sidr_req_received; + // TODO: format sidr req event + } else { + p_event->type = iba_cm_sidr_req_error; + } + break; + case CM_SIDR_REP_ATTR_ID: + p_event->type = iba_cm_sidr_rep_received; + // TODO: format sidr rep event + break; + default: + CL_ASSERT(0); + } +} + + +ib_api_status_t +al_cep_get_init_attr( + IN ib_al_handle_t h_al, + IN net32_t cid, + OUT ib_qp_mod_t* const p_init ) +{ + ib_api_status_t status; + kcep_t *p_cep; + KLOCK_QUEUE_HANDLE hdl; + + AL_ENTER( AL_DBG_CM ); + + KeAcquireInStackQueuedSpinLock( &gp_cep_mgr->lock, &hdl ); + p_cep = __lookup_cep( h_al, cid ); + if( !p_cep ) + { + status = IB_INVALID_HANDLE; + goto out; + } + + switch( p_cep->state ) + { + case CEP_STATE_PRE_REQ: + case CEP_STATE_REQ_RCVD: + case CEP_STATE_PRE_REP: + case CEP_STATE_REQ_SENT: + case CEP_STATE_REQ_MRA_RCVD: + case CEP_STATE_REQ_MRA_SENT: + case CEP_STATE_PRE_REP_MRA_SENT: + case CEP_STATE_REP_RCVD: + case CEP_STATE_REP_SENT: + case CEP_STATE_REP_MRA_RCVD: + case CEP_STATE_REP_MRA_SENT: + case CEP_STATE_ESTABLISHED: + /* Format the INIT qp modify attributes. */ + cl_memclr(p_init, sizeof(ib_qp_mod_t)); + p_init->req_state = IB_QPS_INIT; + p_init->state.init.primary_port = + p_cep->av[p_cep->idx_primary].attr.port_num; + p_init->state.init.pkey_index = + p_cep->av[p_cep->idx_primary].pkey_index; + p_init->state.init.access_ctrl = IB_AC_LOCAL_WRITE | IB_AC_RDMA_WRITE; + if ( p_cep->resp_res ) + { + p_init->state.init.access_ctrl |= IB_AC_RDMA_READ | IB_AC_ATOMIC; + } + status = IB_SUCCESS; + break; + default: + status = IB_INVALID_STATE; + break; + } + +out: + KeReleaseInStackQueuedSpinLock( &hdl ); + AL_EXIT( AL_DBG_CM ); + return status; +} + +ib_api_status_t +al_cep_get_rtr_attr( + IN ib_al_handle_t h_al, + IN net32_t cid, + OUT ib_qp_mod_t* const p_rtr ) +{ + ib_api_status_t status; + kcep_t *p_cep; + KLOCK_QUEUE_HANDLE hdl; + + AL_PRINT( TRACE_LEVEL_VERBOSE, AL_DBG_CM, ("[ CID = %d\n", cid) ); + + CL_ASSERT( h_al ); + CL_ASSERT( p_rtr ); + + KeAcquireInStackQueuedSpinLock( &gp_cep_mgr->lock, &hdl ); + p_cep = __lookup_cep( h_al, cid ); + if( !p_cep ) + { + KeReleaseInStackQueuedSpinLock( &hdl ); + AL_EXIT( AL_DBG_CM ); + return IB_INVALID_HANDLE; + } + + switch( p_cep->state ) + { + case CEP_STATE_REQ_RCVD: + case CEP_STATE_REQ_MRA_SENT: + case CEP_STATE_PRE_REP: + case CEP_STATE_PRE_REP_MRA_SENT: + case CEP_STATE_REP_SENT: + case CEP_STATE_REP_MRA_RCVD: + case CEP_STATE_REP_RCVD: + case CEP_STATE_REP_MRA_SENT: + case CEP_STATE_ESTABLISHED: + cl_memclr( p_rtr, sizeof(ib_qp_mod_t) ); + p_rtr->req_state = IB_QPS_RTR; + + /* Required params. */ + p_rtr->state.rtr.rq_psn = p_cep->rq_psn; + p_rtr->state.rtr.dest_qp = p_cep->remote_qpn; + p_rtr->state.rtr.primary_av = p_cep->av[p_cep->idx_primary].attr; + p_rtr->state.rtr.resp_res = p_cep->resp_res; + p_rtr->state.rtr.rnr_nak_timeout = p_cep->rnr_nak_timeout; + + /* Optional params. */ + p_rtr->state.rtr.opts = 0; + if( p_cep->av[(p_cep->idx_primary + 1) & 0x1].port_guid ) + { + p_rtr->state.rtr.opts |= IB_MOD_QP_ALTERNATE_AV; + p_rtr->state.rtr.alternate_av = + p_cep->av[(p_cep->idx_primary + 1) & 0x1].attr; + } + status = IB_SUCCESS; + break; + + default: + AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM, + ("Invalid state: %d\n", p_cep->state) ); + status = IB_INVALID_STATE; + break; + } + KeReleaseInStackQueuedSpinLock( &hdl ); + AL_EXIT( AL_DBG_CM ); + return status; +} + + +ib_api_status_t +al_cep_get_rts_attr( + IN ib_al_handle_t h_al, + IN net32_t cid, + OUT ib_qp_mod_t* const p_rts ) +{ + ib_api_status_t status; + kcep_t *p_cep; + KLOCK_QUEUE_HANDLE hdl; + + AL_PRINT( TRACE_LEVEL_VERBOSE, AL_DBG_CM, ("[ CID = %d\n", cid) ); + + CL_ASSERT( h_al ); + CL_ASSERT( p_rts ); + + KeAcquireInStackQueuedSpinLock( &gp_cep_mgr->lock, &hdl ); + p_cep = __lookup_cep( h_al, cid ); + if( !p_cep ) + { + KeReleaseInStackQueuedSpinLock( &hdl ); + AL_EXIT( AL_DBG_CM ); + return IB_INVALID_HANDLE; + } + + switch( p_cep->state ) + { + case CEP_STATE_REQ_SENT: + case CEP_STATE_REQ_RCVD: + case CEP_STATE_REQ_MRA_SENT: + case CEP_STATE_REQ_MRA_RCVD: + case CEP_STATE_REP_SENT: + case CEP_STATE_REP_RCVD: + case CEP_STATE_REP_MRA_SENT: + case CEP_STATE_REP_MRA_RCVD: + case CEP_STATE_PRE_REP: + case CEP_STATE_PRE_REP_MRA_SENT: + case CEP_STATE_ESTABLISHED: + cl_memclr( p_rts, sizeof(ib_qp_mod_t) ); + p_rts->req_state = IB_QPS_RTS; + + /* Required params. */ + p_rts->state.rts.sq_psn = p_cep->sq_psn; + p_rts->state.rts.retry_cnt = + p_cep->av[p_cep->idx_primary].attr.conn.seq_err_retry_cnt; + p_rts->state.rts.rnr_retry_cnt = + p_cep->av[p_cep->idx_primary].attr.conn.rnr_retry_cnt; + p_rts->state.rts.local_ack_timeout = + p_cep->av[p_cep->idx_primary].attr.conn.local_ack_timeout; + p_rts->state.rts.init_depth = p_cep->init_depth; + + /* Optional params. */ + p_rts->state.rts.opts = 0; + if( p_cep->av[(p_cep->idx_primary + 1) & 0x1].port_guid ) + { + p_rts->state.rts.opts = + IB_MOD_QP_ALTERNATE_AV | IB_MOD_QP_APM_STATE; + p_rts->state.rts.apm_state = IB_APM_REARM; + p_rts->state.rts.alternate_av = + p_cep->av[(p_cep->idx_primary + 1) & 0x1].attr; + } + status = IB_SUCCESS; + break; + + default: + AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM, + ("Invalid state: %d\n", p_cep->state) ); + status = IB_INVALID_STATE; + break; + } + KeReleaseInStackQueuedSpinLock( &hdl ); + AL_EXIT( AL_DBG_CM ); + return status; +} + + +ib_api_status_t +al_cep_get_timewait( + IN ib_al_handle_t h_al, + IN net32_t cid, + OUT uint64_t* const p_timewait_us ) +{ + kcep_t *p_cep; + KLOCK_QUEUE_HANDLE hdl; + + AL_ENTER( AL_DBG_CM ); + + CL_ASSERT( h_al ); + + KeAcquireInStackQueuedSpinLock( &gp_cep_mgr->lock, &hdl ); + p_cep = __lookup_cep( h_al, cid ); + if( !p_cep ) + { + KeReleaseInStackQueuedSpinLock( &hdl ); + AL_EXIT( AL_DBG_CM ); + return IB_INVALID_HANDLE; + } + + *p_timewait_us = p_cep->timewait_time.QuadPart / 10; + KeReleaseInStackQueuedSpinLock( &hdl ); + AL_EXIT( AL_DBG_CM ); + return IB_SUCCESS; +} + + +ib_api_status_t +al_cep_poll( + IN ib_al_handle_t h_al, + IN net32_t cid, + OUT void** p_context, + OUT net32_t* const p_new_cid, + OUT ib_mad_element_t** const pp_mad ) +{ + ib_api_status_t status; + kcep_t *p_cep; + KLOCK_QUEUE_HANDLE hdl; + + AL_PRINT( TRACE_LEVEL_VERBOSE, AL_DBG_CM, ("[ CID = %d\n", cid) ); + + CL_ASSERT( h_al ); + CL_ASSERT( p_new_cid ); + CL_ASSERT( pp_mad ); + + KeAcquireInStackQueuedSpinLock( &gp_cep_mgr->lock, &hdl ); + p_cep = __lookup_cep( h_al, cid ); + if( !p_cep ) + { + KeReleaseInStackQueuedSpinLock( &hdl ); + AL_EXIT( AL_DBG_CM ); + return IB_INVALID_HANDLE; + } + + *p_context = p_cep->context; + + if( !p_cep->p_mad_head ) + { + p_cep->signalled = FALSE; + status = IB_NOT_DONE; + goto done; + } + + /* Set the MAD. */ + *pp_mad = p_cep->p_mad_head; + p_cep->p_mad_head = p_cep->p_mad_head->p_next; + (*pp_mad)->p_next = NULL; + + /* We're done with the input CEP. Reuse the variable */ + p_cep = (kcep_t*)(*pp_mad)->send_context1; + if( p_cep ) + *p_new_cid = p_cep->cid; + else + *p_new_cid = AL_INVALID_CID; + + status = IB_SUCCESS; + +done: + KeReleaseInStackQueuedSpinLock( &hdl ); + AL_PRINT( TRACE_LEVEL_VERBOSE, AL_DBG_CM, ("] return %d\n", status) ); + return status; +} + + +static void +__cep_cancel_irp( + IN DEVICE_OBJECT* p_dev_obj, + IN IRP* p_irp ) +{ + net32_t cid; + ib_al_handle_t h_al; + KLOCK_QUEUE_HANDLE hdl; + kcep_t *p_cep; + + AL_ENTER( AL_DBG_CM ); + + UNUSED_PARAM( p_dev_obj ); + CL_ASSERT( p_irp ); + + cid = (net32_t)(size_t)p_irp->Tail.Overlay.DriverContext[0]; + h_al = (ib_al_handle_t)p_irp->Tail.Overlay.DriverContext[1]; + CL_ASSERT( h_al ); + + KeAcquireInStackQueuedSpinLock( &gp_cep_mgr->lock, &hdl ); + p_cep = __lookup_cep( h_al, cid ); + if( p_cep ) + __cep_complete_irp( p_cep, STATUS_CANCELLED, IO_NO_INCREMENT ); + + KeReleaseInStackQueuedSpinLock( &hdl ); + + IoReleaseCancelSpinLock( p_irp->CancelIrql ); + + AL_EXIT( AL_DBG_CM ); +} + + +NTSTATUS +al_cep_queue_irp( + IN ib_al_handle_t h_al, + IN net32_t cid, + IN IRP* const p_irp ) +{ + kcep_t *p_cep; + KLOCK_QUEUE_HANDLE hdl; + + AL_ENTER( AL_DBG_CM ); + + CL_ASSERT( h_al ); + CL_ASSERT( p_irp ); + + KeAcquireInStackQueuedSpinLock( &gp_cep_mgr->lock, &hdl ); + p_cep = __lookup_cep( h_al, cid ); + if( !p_cep ) + { + KeReleaseInStackQueuedSpinLock( &hdl ); + AL_EXIT( AL_DBG_CM ); + return STATUS_INVALID_PARAMETER; + } + + /* + * Store the CID an AL handle in the IRP's driver context + * so we can cancel it. + */ + p_irp->Tail.Overlay.DriverContext[0] = (void*)(size_t)cid; + p_irp->Tail.Overlay.DriverContext[1] = (void*)h_al; +#pragma warning(push, 3) + IoSetCancelRoutine( p_irp, __cep_cancel_irp ); +#pragma warning(pop) + IoMarkIrpPending( p_irp ); + + /* Always dequeue and complete whatever IRP is there. */ + __cep_complete_irp( p_cep, STATUS_CANCELLED, IO_NO_INCREMENT ); + + InterlockedExchangePointer( &p_cep->p_irp, p_irp ); + + /* Complete the IRP if there are MADs to be reaped. */ + if( p_cep->p_mad_head ) + __cep_complete_irp( p_cep, STATUS_SUCCESS, IO_NETWORK_INCREMENT ); + + KeReleaseInStackQueuedSpinLock( &hdl ); + AL_EXIT( AL_DBG_CM ); + return STATUS_PENDING; +} + + +void +al_cep_cleanup_al( + IN const ib_al_handle_t h_al ) +{ + cl_list_item_t *p_item; + net32_t cid; + + AL_ENTER( AL_DBG_CM ); + + /* Destroy all CEPs associated with the input instance of AL. */ + cl_spinlock_acquire( &h_al->obj.lock ); + for( p_item = cl_qlist_head( &h_al->cep_list ); + p_item != cl_qlist_end( &h_al->cep_list ); + p_item = cl_qlist_head( &h_al->cep_list ) ) + { + /* + * Note that we don't walk the list - we can't hold the AL + * lock when cleaning up its CEPs because the cleanup path + * takes the CEP's lock. We always want to take the CEP + * before the AL lock to prevent any possibilities of deadlock. + * + * So we just get the CID, and then release the AL lock and try to + * destroy. This should unbind the CEP from the AL instance and + * remove it from the list, allowing the next CEP to be cleaned up + * in the next pass through. + */ + cid = PARENT_STRUCT( p_item, kcep_t, al_item )->cid; + cl_spinlock_release( &h_al->obj.lock ); + al_destroy_cep( h_al, &cid, FALSE ); + cl_spinlock_acquire( &h_al->obj.lock ); + } + cl_spinlock_release( &h_al->obj.lock ); + + AL_EXIT( AL_DBG_CM ); +} + +static void +__cep_cancel_ndi_irp( + IN DEVICE_OBJECT* p_dev_obj, + IN IRP* p_irp ) +{ + KLOCK_QUEUE_HANDLE hdl; + + AL_ENTER( AL_DBG_CM ); + + UNUSED_PARAM( p_dev_obj ); + CL_ASSERT( p_irp ); + + KeAcquireInStackQueuedSpinLock( &gp_cep_mgr->lock, &hdl ); + RemoveEntryList( &p_irp->Tail.Overlay.ListEntry ); + KeReleaseInStackQueuedSpinLock( &hdl ); + +#pragma warning(push, 3) + IoSetCancelRoutine( p_irp, NULL ); +#pragma warning(pop) + IoReleaseCancelSpinLock( p_irp->CancelIrql ); + + /* Complete the IRP. */ + p_irp->IoStatus.Status = STATUS_CANCELLED; + p_irp->IoStatus.Information = 0; + IoCompleteRequest( p_irp, IO_NO_INCREMENT ); + + AL_EXIT( AL_DBG_CM ); +} + + +NTSTATUS +al_cep_get_pdata( + IN ib_al_handle_t h_al, + IN net32_t cid, + OUT uint8_t *p_init_depth, + OUT uint8_t *p_resp_res, + IN OUT uint8_t *p_psize, + OUT uint8_t* pdata ) +{ + kcep_t *p_cep; + KLOCK_QUEUE_HANDLE hdl; + uint8_t copy_len; + + AL_PRINT( TRACE_LEVEL_VERBOSE, AL_DBG_CM, ("[ CID = %d\n", cid) ); + + CL_ASSERT( h_al ); + + KeAcquireInStackQueuedSpinLock( &gp_cep_mgr->lock, &hdl ); + p_cep = __lookup_cep( h_al, cid ); + if( !p_cep ) + { + KeReleaseInStackQueuedSpinLock( &hdl ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("CEP not found for cid %d, h_al %p\n", cid, h_al )); + return STATUS_CONNECTION_INVALID; + } + + *p_init_depth = p_cep->init_depth; + *p_resp_res = p_cep->resp_res; + + copy_len = min( *p_psize, p_cep->psize ); + + if( copy_len ) + RtlCopyMemory( pdata, p_cep->pdata, copy_len ); + + // Always report the maximum available user private data. + *p_psize = p_cep->psize; + + AL_PRINT(TRACE_LEVEL_INFORMATION ,AL_DBG_CM , + ("al_cep_get_pdata: get %d of pdata from CEP with cid %d, h_al %p, context %p \n", + copy_len, cid, h_al, p_cep->context )); + + KeReleaseInStackQueuedSpinLock( &hdl ); + AL_EXIT( AL_DBG_CM ); + return STATUS_SUCCESS; +} + + +/* + * This function is designed to support moving the NetorkDirect IRP queue to the CEP + * without performing major surgery on the CEP manager. + * + * It retrieves the context associated with a CEP, using the pfn_addref function + * to prevent the context from being destroyed after it is returned. + * + * It returns NULL if there is no context, requiring contexts to be pointers. + */ +void* +kal_cep_get_context( + IN ib_al_handle_t h_al, + IN net32_t cid, + IN al_pfn_cep_cb_t pfn_cb, + IN ib_pfn_destroy_cb_t pfn_addref ) +{ + kcep_t *p_cep; + void* context = NULL; + KLOCK_QUEUE_HANDLE hdl; + + AL_PRINT( TRACE_LEVEL_VERBOSE, AL_DBG_CM, ("[ CID = %d\n", cid) ); + + CL_ASSERT( h_al ); + + KeAcquireInStackQueuedSpinLock( &gp_cep_mgr->lock, &hdl ); + p_cep = __lookup_cep( h_al, cid ); + if( !p_cep ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("CEP not found for cid %d, h_al %p\n", cid, h_al )); + goto out; + } + + if( pfn_cb && p_cep->pfn_cb != pfn_cb ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("CEP callback mismatch for cid %d, h_al %p\n", cid, h_al )); + goto out; + } + + context = p_cep->context; + if( pfn_addref && context != NULL ) + { + pfn_addref( context ); + } + +out: + KeReleaseInStackQueuedSpinLock( &hdl ); + AL_PRINT( TRACE_LEVEL_VERBOSE, AL_DBG_CM, ("] returning %p\n", context) ); + return context; +} diff --git a/branches/WOF2-3/core/al/kernel/al_dev.c b/branches/WOF2-3/core/al/kernel/al_dev.c new file mode 100644 index 00000000..a861866d --- /dev/null +++ b/branches/WOF2-3/core/al/kernel/al_dev.c @@ -0,0 +1,499 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "al.h" +#include "al_ca.h" +#include "al_common.h" +#include "al_cq.h" +#include "al_debug.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "al_dev.tmh" +#endif +#include "al_dev.h" +#include "al_qp.h" +#include "al_mgr.h" +#include "al_proxy.h" + + + +static cl_status_t +__proxy_reg_pnp( + IN al_dev_open_context_t *p_context ); + +static void +__proxy_cancel_cblists( + IN al_dev_open_context_t *p_context ); + + + + +static void +__construct_open_context( + IN al_dev_open_context_t *p_context ) +{ + cl_event_construct( &p_context->close_event ); + + cl_qpool_construct( &p_context->cb_pool ); + cl_spinlock_construct( &p_context->cb_pool_lock ); + + cl_qlist_init( &p_context->cm_cb_list ); + cl_qlist_init( &p_context->comp_cb_list ); + cl_qlist_init( &p_context->misc_cb_list ); + cl_spinlock_construct( &p_context->cb_lock ); + cl_mutex_construct( &p_context->pnp_mutex ); +} + + + +/* + * Initialize all objects used by the per client open context. + */ +static cl_status_t +__init_open_context( + IN al_dev_open_context_t *p_context ) +{ + cl_status_t cl_status; + NTSTATUS status; + + cl_status = cl_event_init( &p_context->close_event, FALSE ); + if( cl_status != CL_SUCCESS ) + return cl_status; + + /* Allocate pool for storing callback info or requests. */ + cl_status = cl_qpool_init( &p_context->cb_pool, + AL_CB_POOL_START_SIZE, 0, AL_CB_POOL_GROW_SIZE, + sizeof(al_proxy_cb_info_t), NULL, NULL, NULL ); + if( cl_status != CL_SUCCESS ) + return cl_status; + + cl_status = cl_spinlock_init( &p_context->cb_pool_lock ); + if( cl_status != CL_SUCCESS ) + return cl_status; + + cl_status = cl_spinlock_init( &p_context->cb_lock ); + if( cl_status != CL_SUCCESS ) + return cl_status; + + cl_status = cl_mutex_init( &p_context->pnp_mutex ); + if( cl_status != CL_SUCCESS ) + return cl_status; + + status = al_csq_init( p_context, &p_context->al_csq ); + if ( !NT_SUCCESS( status ) ) + return (cl_status_t)status; + + return CL_SUCCESS; +} + + + +static void +__destroy_open_context( + IN al_dev_open_context_t *p_context ) +{ + cl_event_destroy( &p_context->close_event ); + + cl_qpool_destroy( &p_context->cb_pool ); + cl_spinlock_destroy( &p_context->cb_pool_lock ); + cl_spinlock_destroy( &p_context->cb_lock ); + cl_mutex_destroy( &p_context->pnp_mutex ); +} + + + +cl_status_t +al_dev_open( + IN cl_ioctl_handle_t h_ioctl ) +{ + al_dev_open_context_t *p_context; + ib_api_status_t status; + cl_status_t cl_status; + IO_STACK_LOCATION *p_io_stack; + ULONG *p_ver; + + AL_ENTER( AL_DBG_DEV ); + + p_io_stack = IoGetCurrentIrpStackLocation( h_ioctl ); + + p_ver = cl_ioctl_in_buf( h_ioctl ); + + if( p_io_stack->FileObject->FsContext || + cl_ioctl_in_size( h_ioctl ) != sizeof(ULONG) || + !p_ver || + cl_ioctl_out_size( h_ioctl ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("context already exists or bad parameters.\n") ); + return CL_INVALID_PARAMETER; + } + + if( *p_ver != AL_IOCTL_VERSION ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("Unsupported client version: %d\n", *p_ver) ); + return CL_INVALID_PARAMETER; + } + + /* Allocate the client's context structure. */ + p_context = (al_dev_open_context_t*) + cl_zalloc( sizeof(al_dev_open_context_t) ); + if( !p_context ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("cl_malloc( %d ) failed.\n", sizeof(al_dev_open_context_t)) ); + return CL_INSUFFICIENT_MEMORY; + } + + /* Construct the open context to allow destruction. */ + __construct_open_context( p_context ); + + /* Initialize the open context elements. */ + cl_status = __init_open_context( p_context ); + if( cl_status != CL_SUCCESS ) + { + __destroy_open_context( p_context ); + cl_free( p_context ); + return cl_status; + } + + /* Open an internal AL instance for this process. */ + status = ib_open_al( &p_context->h_al ); + if( status == IB_SUCCESS ) + { + /* Register for PnP events. */ + status = __proxy_reg_pnp( p_context ); + } + + /* Make sure that we were able to open AL and register for PnP. */ + if( status == IB_SUCCESS ) + { + /* + * Store the reference from the AL instance back to this + * open context. This allows using the user-mode context + * for resource creation. + */ + p_context->h_al->p_context = p_context; + /* We successfully opened the device. */ + p_io_stack->FileObject->FsContext = p_context; + } + else + { + __destroy_open_context( p_context ); + cl_free( p_context ); + cl_status = CL_INSUFFICIENT_RESOURCES; + } + + AL_EXIT( AL_DBG_DEV ); + return cl_status; +} + + + +/* + * To be called by al_dev_open(). This will register for PnP events + * on behalf of user process (UAL). It uses the implicit global + * al instance created by AL manager. PnP events are propagated + * to UAL automatically from the time AL device is open till the + * process exits. + */ +static ib_api_status_t +__proxy_reg_pnp( + IN al_dev_open_context_t *p_context ) +{ + ib_pnp_req_t pnp_req; + ib_pnp_handle_t h_pnp; + ib_api_status_t status; + + /* Register for PnP events. */ + cl_memclr( &pnp_req, sizeof( ib_pnp_req_t ) ); + pnp_req.pnp_class = IB_PNP_CA | IB_PNP_FLAG_REG_COMPLETE; + pnp_req.pnp_context = p_context; + pnp_req.pfn_pnp_cb = proxy_pnp_ca_cb; + + /* No need to track the registration. We'll deregister when closing AL. */ + status = ib_reg_pnp( p_context->h_al, &pnp_req, &h_pnp ); + if( status != IB_SUCCESS ) + return status; + + /* Register for port events. */ + pnp_req.pfn_pnp_cb = proxy_pnp_port_cb; + pnp_req.pnp_class = IB_PNP_PORT | IB_PNP_FLAG_REG_COMPLETE; + status = ib_reg_pnp( p_context->h_al, &pnp_req, &h_pnp ); + + return status; +} + + + +/* + * Cleanup the handle map. Remove all mappings. Perform all necessary + * operations. + */ +static void +__proxy_cleanup_map( + IN al_dev_open_context_t *p_context ) +{ + al_handle_t *p_h; + size_t i; + + AL_ENTER( AL_DBG_DEV ); + + cl_spinlock_acquire( &p_context->h_al->obj.lock ); + for( i = 0; i < cl_vector_get_size( &p_context->h_al->hdl_vector ); i++ ) + { + p_h = (al_handle_t*) + cl_vector_get_ptr( &p_context->h_al->hdl_vector, i ); + + switch( AL_BASE_TYPE( p_h->type ) ) + { + /* Return any MADs not reported to the user. */ + case AL_OBJ_TYPE_H_MAD: + ib_put_mad( (ib_mad_element_t*)p_h->p_obj ); + al_hdl_free( p_context->h_al, i ); + break; + + case AL_OBJ_TYPE_H_CA_ATTR: + /* Release a saved CA attribute. */ + cl_free( p_h->p_obj ); + al_hdl_free( p_context->h_al, i ); + break; + + case AL_OBJ_TYPE_H_SA_REQ: + al_cancel_sa_req( (al_sa_req_t*)p_h->p_obj ); + break; + + case AL_OBJ_TYPE_H_PNP_EVENT: + cl_event_signal( &((proxy_pnp_evt_t*)p_h->p_obj)->event ); + break; + + default: + /* Nothing else to do for other handle types. */ + break; + } + } + cl_spinlock_release( &p_context->h_al->obj.lock ); + + AL_EXIT( AL_DBG_DEV ); +} + + +cl_status_t +al_dev_close( + IN cl_ioctl_handle_t h_ioctl ) +{ + al_dev_open_context_t *p_context; + IO_STACK_LOCATION *p_io_stack; + + AL_ENTER( AL_DBG_DEV ); + + p_io_stack = IoGetCurrentIrpStackLocation( h_ioctl ); + + /* Determine if the client closed the al_handle. */ + if (!p_io_stack->FileObject) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("Client closed with a null open context .\n") ); + return CL_SUCCESS; + } + p_context = (al_dev_open_context_t*)p_io_stack->FileObject->FsContext; + if( !p_context ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("Client closed with a null open context .\n") ); + return CL_SUCCESS; + } + if( p_io_stack->FileObject->FsContext2 ) + { + /* Not the main file object - ignore. */ + AL_EXIT( AL_DBG_DEV ); + return CL_SUCCESS; + } + + /* Mark that we're closing this device. */ + p_context->closing = TRUE; + + /* Flush any pending IOCTLs in case user-mode threads died on us. */ + al_csq_flush_que( &p_context->al_csq, STATUS_CANCELLED ); + + while( p_context->ref_cnt ) + { +#ifdef _DEBUG_ + cl_status_t cl_status; + + cl_status = cl_event_wait_on( &p_context->close_event, 1000, FALSE ); + ASSERT( cl_status == IB_SUCCESS ); + if( cl_status != IB_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("Waiting on ref_cnt timed out!\n") ); + break; + } +#else + cl_event_wait_on( &p_context->close_event, EVENT_NO_TIMEOUT, FALSE ); +#endif + } + + /* Cleanup any leftover callback resources. */ + __proxy_cancel_cblists( p_context ); + + /* Close the AL instance for this process. */ + if( p_context->h_al ) + { + /* Cleanup all user to kernel handle mappings. */ + __proxy_cleanup_map( p_context ); + + ib_close_al( p_context->h_al ); + p_context->h_al = NULL; + } + + /* Destroy the open context now. */ + __destroy_open_context( p_context ); + cl_free( p_context ); + + AL_EXIT( AL_DBG_DEV ); + return CL_SUCCESS; +} + + + +/* + * Remove all callbacks on the given callback queue and return them to + * the callback pool. + */ +static void +__proxy_dq_cblist( + IN al_dev_open_context_t *p_context, + IN cl_qlist_t *p_cblist ) +{ + cl_list_item_t *p_list_item; + al_proxy_cb_info_t *p_cb_info; + + cl_spinlock_acquire( &p_context->cb_lock ); + for( p_list_item = cl_qlist_remove_head( p_cblist ); + p_list_item != cl_qlist_end( p_cblist ); + p_list_item = cl_qlist_remove_head( p_cblist ) ) + { + p_cb_info = (al_proxy_cb_info_t*)p_list_item; + if( p_cb_info->p_al_obj ) + deref_al_obj( p_cb_info->p_al_obj ); + proxy_cb_put( p_cb_info ); + } + cl_spinlock_release( &p_context->cb_lock ); +} + + + +/* + * Remove all queued callbacks from all callback lists. + */ +static void +__proxy_cancel_cblists( + IN al_dev_open_context_t *p_context ) +{ + __proxy_dq_cblist( p_context, &p_context->cm_cb_list ); + __proxy_dq_cblist( p_context, &p_context->comp_cb_list ); + __proxy_dq_cblist( p_context, &p_context->misc_cb_list ); +} + + +cl_status_t +al_dev_ioctl( + IN cl_ioctl_handle_t h_ioctl ) +{ + cl_status_t cl_status; + size_t ret_bytes = 0; + void *p_open_context; + IO_STACK_LOCATION *p_io_stack; + + AL_ENTER( AL_DBG_DEV ); + + p_io_stack = IoGetCurrentIrpStackLocation( h_ioctl ); + p_open_context = p_io_stack->FileObject->FsContext; + + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_DEV, + ("al_dev_ioctl: buf_size (%d) p_buf (%p).\n", + cl_ioctl_in_size( h_ioctl ), cl_ioctl_in_buf( h_ioctl )) ); + + /* Process the ioctl command. */ + if( IS_AL_PROXY_IOCTL(cl_ioctl_ctl_code( h_ioctl )) ) + cl_status = proxy_ioctl( h_ioctl, &ret_bytes ); + else if( IS_VERBS_IOCTL(cl_ioctl_ctl_code( h_ioctl )) ) + cl_status = verbs_ioctl( h_ioctl, &ret_bytes ); + //else if( IS_CM_IOCTL(cl_ioctl_ctl_code( h_ioctl )) ) + // cl_status = cm_ioctl( h_ioctl, &ret_bytes ); + else if( IS_CEP_IOCTL(cl_ioctl_ctl_code( h_ioctl )) ) + cl_status = cep_ioctl( h_ioctl, &ret_bytes ); + else if( IS_AL_IOCTL(cl_ioctl_ctl_code( h_ioctl )) ) + cl_status = al_ioctl( h_ioctl, &ret_bytes ); + else if( IS_SUBNET_IOCTL(cl_ioctl_ctl_code( h_ioctl )) ) + cl_status = subnet_ioctl( h_ioctl, &ret_bytes ); + else if( IS_IOC_IOCTL(cl_ioctl_ctl_code( h_ioctl )) ) + cl_status = ioc_ioctl( h_ioctl, &ret_bytes ); + else if( IS_NDI_IOCTL(cl_ioctl_ctl_code( h_ioctl )) ) + cl_status = ndi_ioctl( h_ioctl, &ret_bytes ); + else + cl_status = CL_INVALID_REQUEST; + + switch( cl_status ) + { + case CL_COMPLETED: + /* Flip the status since the IOCTL was completed. */ + cl_status = CL_SUCCESS; + /* Fall through */ + case CL_PENDING: + break; + case CL_INVALID_REQUEST: + /* + * In Windows, Driver Verifier sends bogus IOCTLs to the device. + * These must be passed down the device stack, and so cannot be + * completed in the IOCTL handler. They are properly cleaned up, + * though no data is returned to the user. + */ + break; + default: + cl_ioctl_complete( h_ioctl, cl_status, ret_bytes ); + } + + AL_EXIT( AL_DBG_DEV ); + return cl_status; +} diff --git a/branches/WOF2-3/core/al/kernel/al_exports.def b/branches/WOF2-3/core/al/kernel/al_exports.def new file mode 100644 index 00000000..217e2fde --- /dev/null +++ b/branches/WOF2-3/core/al/kernel/al_exports.def @@ -0,0 +1,7 @@ +LIBRARY ibal.sys + +EXPORTS +; DllInitialize and DllUnload must be exported for the OS reference counting to +; work, and must be private for the compiler to accept them. +DllInitialize private +DllUnload private diff --git a/branches/WOF2-3/core/al/kernel/al_fmr_pool.c b/branches/WOF2-3/core/al/kernel/al_fmr_pool.c new file mode 100644 index 00000000..2525813e --- /dev/null +++ b/branches/WOF2-3/core/al/kernel/al_fmr_pool.c @@ -0,0 +1,750 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: al_fmr_pool.h 1611 2006-08-20 14:48:55Z sleybo $ + */ + + + + +#include "al_debug.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "al_fmr_pool.tmh" +#endif + +#include "al_fmr_pool.h" +#include "al_mr.h" +#include "al_pd.h" + +#define hash_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); \ +} + +static inline uint32_t hash_2words(uint32_t a, uint32_t b, uint32_t c) +{ + a += 0x9e3779b9; + b += 0x9e3779b9; + hash_mix(a, b, c); + return c; +} + +enum { + IB_FMR_MAX_REMAPS = 32, + + IB_FMR_HASH_BITS = 8, + IB_FMR_HASH_SIZE = 1 << IB_FMR_HASH_BITS, + IB_FMR_HASH_MASK = IB_FMR_HASH_SIZE - 1 +}; + + +static inline uint32_t __fmr_hash(uint64_t first_page) +{ + return hash_2words((uint32_t) first_page, (uint32_t) (first_page >> 32), 0) & + (IB_FMR_HASH_SIZE - 1); +} + +/* Caller must hold pool_lock */ +static inline mlnx_fmr_pool_element_t *__fmr_cache_lookup( + mlnx_fmr_pool_t *p_pool, + const uint64_t* const page_list, + int page_list_len, + uint64_t io_virtual_address) +{ + cl_qlist_t *bucket; + cl_list_item_t *p_list_item; + mlnx_fmr_pool_element_t *p_fmr_el; + + if (!p_pool->cache_bucket) + return NULL; + + bucket = p_pool->cache_bucket + __fmr_hash(*page_list); + + for( p_list_item = cl_qlist_head( bucket ); + p_list_item != cl_qlist_end( bucket); + p_list_item = cl_qlist_next( p_list_item ) ) + { + p_fmr_el = PARENT_STRUCT( p_list_item, mlnx_fmr_pool_element_t, cache_node ); + if (io_virtual_address == p_fmr_el->io_virtual_address && + page_list_len == p_fmr_el->page_list_len && + !memcmp(page_list, p_fmr_el->page_list, page_list_len * sizeof *page_list)) + return p_fmr_el; + } + + return NULL; +} + + +static void +__fmr_pool_batch_release(mlnx_fmr_pool_t *p_pool) +{ + ib_api_status_t status; + mlnx_fmr_pool_element_t *p_fmr_el; + mlnx_fmr_handle_t h_fmr = NULL; + cl_qlist_t unmap_list; + cl_list_item_t *p_list_item; + cl_qlist_t *bucket; + + cl_qlist_init(&unmap_list); + + cl_spinlock_acquire(&p_pool->pool_lock); + + for( p_list_item = cl_qlist_head( &p_pool->dirty_list ); + p_list_item != cl_qlist_end( &p_pool->dirty_list); + p_list_item = cl_qlist_next( p_list_item ) ) + { + p_fmr_el = PARENT_STRUCT( p_list_item, mlnx_fmr_pool_element_t, list_item ); + if (p_fmr_el->in_cash) + { + p_fmr_el->in_cash = FALSE; + bucket = p_pool->cache_bucket + __fmr_hash(p_fmr_el->page_list[0]); + cl_qlist_remove_item( bucket, &p_fmr_el->cache_node ); + } + p_fmr_el->remap_count = 0; + p_fmr_el->h_fmr->p_next = h_fmr; + h_fmr = p_fmr_el->h_fmr; + if (p_fmr_el->ref_count !=0) + { + AL_PRINT(TRACE_LEVEL_WARNING, AL_DBG_FMR_POOL, ("Unmapping FMR 0x%p with ref count %d", + p_fmr_el, p_fmr_el->ref_count)); + } + } + + cl_qlist_insert_list_head(&unmap_list, &p_pool->dirty_list ); + cl_qlist_init(&p_pool->dirty_list); + p_pool->dirty_len = 0; + + cl_spinlock_release( &p_pool->pool_lock ); + + if (cl_is_qlist_empty(&unmap_list)) { + return; + } + + status = mlnx_unmap_fmr(h_fmr); + if (status != IB_SUCCESS) + AL_PRINT(TRACE_LEVEL_WARNING, AL_DBG_FMR_POOL, ("mlnx_unmap_fmr returned %s", ib_get_err_str(status))); + + + cl_spinlock_acquire( &p_pool->pool_lock ); + cl_qlist_insert_list_head(&p_pool->free_list,&unmap_list); + cl_spinlock_release( &p_pool->pool_lock ); +} + + + +static int +__fmr_cleanup_thread(void * p_pool_ptr) +{ + mlnx_fmr_pool_t *p_pool = p_pool_ptr; + atomic32_t flush_req; + int forever = 1; + + do { + flush_req = 0; + if (p_pool->flush_req || p_pool->dirty_len >= p_pool->dirty_watermark) + { + __fmr_pool_batch_release(p_pool); + + if (p_pool->flush_req) + { + cl_event_signal(&p_pool->flush_done_event); + flush_req = cl_atomic_dec( &p_pool->flush_req ); + } + + if (p_pool->flush_function) + p_pool->flush_function( (mlnx_fmr_pool_handle_t)p_pool, p_pool->flush_arg); + } + + if (!flush_req) + { + if (p_pool->should_stop) + break; + cl_event_wait_on(&p_pool->do_flush_event, EVENT_NO_TIMEOUT, TRUE); + } + } while (forever); + + return 0; +} + +/* + * Destroying the pool. + */ +static void +__destroying_fmr_pool( + IN al_obj_t* p_obj ) +{ + mlnx_fmr_pool_t* p_pool; + + CL_ASSERT( p_obj ); + p_pool = PARENT_STRUCT( p_obj, mlnx_fmr_pool_t, obj ); + AL_PRINT(TRACE_LEVEL_ERROR, AL_DBG_FMR_POOL, ("pool %p\n", p_pool)); + + // notify cleaning thread to exit + cl_atomic_inc( &p_pool->should_stop ); + cl_event_signal(&p_pool->do_flush_event); + cl_thread_destroy(&p_pool->thread); +} + +/* + * Cleanup the pool. + */ +static void +__cleanup_fmr_pool( + IN al_obj_t* p_obj ) +{ + int i=0; + ib_api_status_t status = IB_SUCCESS; + mlnx_fmr_pool_t* p_pool; + mlnx_fmr_pool_element_t *p_fmr_el; + cl_list_item_t *p_list_item; + cl_qlist_t *bucket; + + CL_ASSERT( p_obj ); + p_pool = PARENT_STRUCT( p_obj, mlnx_fmr_pool_t, obj ); + AL_PRINT(TRACE_LEVEL_ERROR, AL_DBG_FMR_POOL, ("pool %p\n", p_pool)); + + // cleanup the dirty list stuff + __fmr_pool_batch_release(p_pool); + + cl_spinlock_acquire(&p_pool->pool_lock); + + // merge the rest with free list + for( p_list_item = cl_qlist_head( &p_pool->rest_list ); + p_list_item != cl_qlist_end( &p_pool->rest_list ); + p_list_item = cl_qlist_head( &p_pool->rest_list ) ) + { + p_fmr_el = PARENT_STRUCT( p_list_item, mlnx_fmr_pool_element_t, list_item ); + if (p_fmr_el->in_cash) + { + p_fmr_el->in_cash = FALSE; + bucket = p_pool->cache_bucket + __fmr_hash(p_fmr_el->page_list[0]); + cl_qlist_remove_item( bucket, &p_fmr_el->cache_node ); + } + cl_qlist_remove_item(&p_pool->rest_list, p_list_item); + cl_qlist_insert_tail(&p_pool->free_list, &p_fmr_el->list_item); + p_fmr_el->p_cur_list = &p_pool->free_list; + } + + // cleanup the free list + for( p_list_item = cl_qlist_head( &p_pool->free_list ); + p_list_item != cl_qlist_end( &p_pool->free_list ); + p_list_item = cl_qlist_head( &p_pool->free_list ) ) + { + p_fmr_el = PARENT_STRUCT( p_list_item, mlnx_fmr_pool_element_t, list_item); + cl_spinlock_release( &p_pool->pool_lock ); + if (p_fmr_el->remap_count) + { + p_fmr_el->h_fmr->p_next = NULL; + status = mlnx_unmap_fmr(p_fmr_el->h_fmr); + if (status != IB_SUCCESS) + AL_PRINT(TRACE_LEVEL_WARNING, AL_DBG_FMR_POOL, ("mlnx_unmap_fmr returned %s\n", ib_get_err_str(status))); + + } + status = mlnx_destroy_fmr(p_fmr_el->h_fmr); + if (status != IB_SUCCESS) + AL_PRINT(TRACE_LEVEL_WARNING, AL_DBG_FMR_POOL, ("mlnx_destroy_fmr returned %s\n", ib_get_err_str(status))); + + cl_spinlock_acquire(&p_pool->pool_lock); + cl_qlist_remove_item(&p_pool->free_list, p_list_item); + cl_free(p_fmr_el); + ++i; + } + + cl_spinlock_release( &p_pool->pool_lock ); + + if (i < p_pool->pool_size) + AL_PRINT(TRACE_LEVEL_ERROR, AL_DBG_FMR_POOL, ("pool still has %d regions registered\n", + p_pool->pool_size - i)); +} + + +/* + * Free the pool. + */ +static void +__free_fmr_pool( + IN al_obj_t* p_obj ) +{ + mlnx_fmr_pool_t* p_pool; + + CL_ASSERT( p_obj ); + p_pool = PARENT_STRUCT( p_obj, mlnx_fmr_pool_t, obj ); + + cl_spinlock_destroy(&p_pool->pool_lock); + destroy_al_obj( &p_pool->obj ); + if (p_pool->cache_bucket) + cl_free( p_pool->cache_bucket ); + cl_free( p_pool ); + AL_PRINT(TRACE_LEVEL_ERROR, AL_DBG_FMR_POOL, ("__free_pool: pool %p\n", p_pool)); +} + + + +ib_api_status_t +mlnx_create_fmr_pool( + IN const ib_pd_handle_t h_pd, + IN const mlnx_fmr_pool_create_t *p_fmr_pool_attr, + OUT mlnx_fmr_pool_handle_t* const ph_pool ) +{ + ib_api_status_t status = IB_SUCCESS; + mlnx_fmr_pool_t *p_pool; + int i; + int max_remaps; + cl_status_t cl_status; + mlnx_fmr_pool_element_t *p_fmr_el; + + + AL_ENTER( AL_DBG_FMR_POOL ); + + if( AL_OBJ_INVALID_HANDLE( h_pd, AL_OBJ_TYPE_H_PD ) ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PD_HANDLE\n") ); + status = IB_INVALID_AL_HANDLE; + goto end; + } + + if( !ph_pool ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + status = IB_INVALID_PARAMETER; + goto end; + } + + if( !p_fmr_pool_attr || !p_fmr_pool_attr->dirty_watermark) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + status = IB_INVALID_PARAMETER; + goto end; + } + + if (!h_pd->obj.p_ci_ca || !h_pd->obj.p_ci_ca->p_pnp_attr) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_STATE\n") ); + status = IB_INVALID_STATE; + goto end; + } + + // check whether the device support FMR + if (!h_pd->obj.p_ci_ca->verbs.alloc_mlnx_fmr|| !h_pd->obj.p_ci_ca->verbs.dealloc_mlnx_fmr || + !h_pd->obj.p_ci_ca->verbs.map_phys_mlnx_fmr || !h_pd->obj.p_ci_ca->verbs.unmap_mlnx_fmr) { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("Device does not support fast memory regions")); + status = IB_UNSUPPORTED; + goto end; + } + + if (!h_pd->obj.p_ci_ca->p_pnp_attr->max_map_per_fmr) + { + max_remaps = IB_FMR_MAX_REMAPS; + } + else + { + max_remaps = h_pd->obj.p_ci_ca->p_pnp_attr->max_map_per_fmr; + } + + // allocate pool object + p_pool = cl_zalloc( sizeof( mlnx_fmr_pool_t ) ); + if( !p_pool ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("Couldn't allocate pool struct")); + status = IB_INSUFFICIENT_MEMORY; + goto err_alloc_pool_obj; + } + + // construct pool objects + cl_spinlock_construct( &p_pool->pool_lock); + cl_thread_construct(&p_pool->thread); + cl_event_construct(&p_pool->do_flush_event); + cl_event_construct(&p_pool->flush_done_event); + + + // init pool objects + p_pool->pool_size = 0; + p_pool->max_pages = p_fmr_pool_attr->max_pages_per_fmr; + p_pool->max_remaps = max_remaps; + p_pool->dirty_watermark = p_fmr_pool_attr->dirty_watermark; + p_pool->dirty_len = 0; + p_pool->cache_bucket = NULL; + p_pool->flush_function = p_fmr_pool_attr->flush_function; + p_pool->flush_arg = p_fmr_pool_attr->flush_arg; + cl_qlist_init(&p_pool->dirty_list); + cl_qlist_init(&p_pool->free_list); + cl_qlist_init(&p_pool->rest_list); + + if (p_fmr_pool_attr->cache) { + p_pool->cache_bucket = + cl_zalloc(IB_FMR_HASH_SIZE * sizeof *p_pool->cache_bucket); + if (!p_pool->cache_bucket) { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("Failed to allocate cache in pool")); + status = IB_INSUFFICIENT_MEMORY; + goto err_alloc_cache; + } + + for (i = 0; i < IB_FMR_HASH_SIZE; ++i) + cl_qlist_init(p_pool->cache_bucket + i); + } + + cl_status = cl_spinlock_init( &p_pool->pool_lock ); + if( cl_status != CL_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("Failed cl_spinlock_init")); + status = IB_ERROR; + goto err_pool_init; + } + + cl_event_init(&p_pool->do_flush_event,FALSE); + if( cl_status != CL_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("Failed cl_event_init")); + status = IB_ERROR; + goto err_pool_init; + } + + cl_event_init(&p_pool->flush_done_event,FALSE); + if( cl_status != CL_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("Failed cl_event_init")); + status = IB_ERROR; + goto err_pool_init; + } + + cl_thread_init(&p_pool->thread ,__fmr_cleanup_thread,p_pool,"fmr_cleanup"); + if( cl_status != CL_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("Failed cl_thread_init")); + status = IB_ERROR; + goto err_pool_init; + } + + { + mlnx_fmr_create_t fmr_attr; + + fmr_attr.max_pages = p_fmr_pool_attr->max_pages_per_fmr, + fmr_attr.max_maps = p_pool->max_remaps, + fmr_attr.page_size = p_fmr_pool_attr->page_size; + fmr_attr.access_ctrl = p_fmr_pool_attr->access_ctrl; + + + for (i = 0; i < p_fmr_pool_attr->pool_size; ++i) + { + p_fmr_el = cl_zalloc(sizeof (mlnx_fmr_pool_element_t) + p_fmr_pool_attr->max_pages_per_fmr * sizeof (uint64_t)); + if (!p_fmr_el) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, (" failed to allocate struct for FMR %d \n",i)); + status = IB_INSUFFICIENT_MEMORY; + goto err_alloc_cache_el; + } + + p_fmr_el->h_pool = (mlnx_fmr_pool_handle_t)p_pool; + p_fmr_el->remap_count = 0; + p_fmr_el->ref_count = 0; + + status = mlnx_create_fmr(h_pd, &fmr_attr,&p_fmr_el->h_fmr); + if (status != IB_SUCCESS) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("mlnx_create_fmr failed for FMR %d with status %s.\n",i,ib_get_err_str(status))); + cl_free(p_fmr_el); + goto err_alloc_cache_el; + } + + cl_qlist_insert_tail(&p_pool->free_list, &p_fmr_el->list_item); + p_fmr_el->p_cur_list = &p_pool->free_list; + ++p_pool->pool_size; + } + + } + + /* Do IBAL stuff for creating and iniitializing the object */ + construct_al_obj( &p_pool->obj, AL_OBJ_TYPE_H_FMR_POOL); + + status = init_al_obj( &p_pool->obj, p_pool, FALSE, __destroying_fmr_pool, __cleanup_fmr_pool, __free_fmr_pool ); + if( status != IB_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("init_al_obj failed with status %s.\n", ib_get_err_str(status)) ); + goto err_init_al_obj; + } + + /* Attach the pool to the AL object. */ + status = attach_al_obj( &h_pd->obj, &p_pool->obj ); + if( status != IB_SUCCESS ) + { + ref_al_obj( &p_pool->obj ); + p_pool->obj.pfn_destroy( &p_pool->obj, NULL ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("attach_al_obj returned %s.\n", ib_get_err_str(status)) ); + goto end; + } + + + /* Release the reference taken in init_al_obj */ + deref_al_obj( &p_pool->obj ); + + *ph_pool = p_pool; + status = IB_SUCCESS; + goto end; + +err_init_al_obj: + destroy_al_obj( &p_pool->obj ); + +err_alloc_cache_el: + __destroying_fmr_pool( &p_pool->obj ); + __cleanup_fmr_pool( &p_pool->obj ); + +err_pool_init: + if (p_pool->cache_bucket) + cl_free( p_pool->cache_bucket ); + +err_alloc_cache: + cl_free( p_pool ); + +err_alloc_pool_obj: +end: + AL_EXIT( AL_DBG_FMR_POOL ); + return status; +} + +/** + * ib_destroy_fmr_pool - Free FMR pool + * @pool:FMR pool to free + * + * Destroy an FMR pool and free all associated resources. + */ +ib_api_status_t +mlnx_destroy_fmr_pool( + IN const mlnx_fmr_pool_handle_t h_pool) +{ + mlnx_fmr_pool_t *p_pool = (mlnx_fmr_pool_t*)h_pool; + + AL_ENTER( AL_DBG_FMR_POOL ); + + if( AL_OBJ_INVALID_HANDLE( h_pool, AL_OBJ_TYPE_H_FMR_POOL ) ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_HANDLE\n") ); + return IB_INVALID_HANDLE; + } + + ref_al_obj( &p_pool->obj ); + p_pool->obj.pfn_destroy( &p_pool->obj, NULL ); + + AL_EXIT( AL_DBG_FMR_POOL ); + return IB_SUCCESS; +} + + + +ib_api_status_t +mlnx_flush_fmr_pool(mlnx_fmr_pool_handle_t h_pool) +{ + + ib_api_status_t status = IB_SUCCESS; + mlnx_fmr_pool_t *p_pool = (mlnx_fmr_pool_t*)h_pool; + + if( AL_OBJ_INVALID_HANDLE( h_pool, AL_OBJ_TYPE_H_FMR_POOL ) ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_HANDLE\n") ); + return IB_INVALID_HANDLE; + } + + ref_al_obj( &p_pool->obj ); + + cl_atomic_inc( &p_pool->flush_req ); + cl_event_signal(&p_pool->do_flush_event); + if (cl_event_wait_on(&p_pool->flush_done_event, EVENT_NO_TIMEOUT, TRUE)) + status = IB_ERROR; + + deref_al_obj( &p_pool->obj ); + + return status; +} + +ib_api_status_t +mlnx_map_phys_fmr_pool( + IN const mlnx_fmr_pool_handle_t h_pool , + IN const uint64_t* const page_list, + IN const int list_len, + IN OUT uint64_t* const p_vaddr, + OUT net32_t* const p_lkey, + OUT net32_t* const p_rkey, + OUT mlnx_fmr_pool_el_t *pp_fmr_el) +{ + + ib_api_status_t status = IB_SUCCESS; + mlnx_fmr_pool_t *p_pool = (mlnx_fmr_pool_t*)h_pool; + mlnx_fmr_pool_element_t *p_fmr_el; + cl_qlist_t *bucket; + + if( AL_OBJ_INVALID_HANDLE( h_pool, AL_OBJ_TYPE_H_FMR_POOL ) ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_HANDLE\n") ); + return IB_INVALID_HANDLE; + } + + if (list_len < 1 || list_len > p_pool->max_pages) + return IB_INVALID_PARAMETER; + + ref_al_obj( &p_pool->obj ); + + cl_spinlock_acquire(&p_pool->pool_lock); + + p_fmr_el = __fmr_cache_lookup( p_pool, page_list, list_len, *p_vaddr ); + if (p_fmr_el) { + /* found in cache */ + ++p_fmr_el->ref_count; + if (p_fmr_el->ref_count == 1) { + cl_qlist_remove_item( p_fmr_el->p_cur_list, &p_fmr_el->list_item ); + cl_qlist_insert_tail(&p_pool->rest_list, &p_fmr_el->list_item); + p_fmr_el->p_cur_list = &p_pool->rest_list; + } + + cl_spinlock_release(&p_pool->pool_lock); + goto end; + } + + if (cl_is_qlist_empty(&p_pool->free_list)) { + cl_spinlock_release(&p_pool->pool_lock); + status = IB_RESOURCE_BUSY; + goto exit; + } + + p_fmr_el = PARENT_STRUCT(cl_qlist_remove_head(&p_pool->free_list),mlnx_fmr_pool_element_t,list_item); + if (p_fmr_el->in_cash) + { + p_fmr_el->in_cash = FALSE; + bucket = p_pool->cache_bucket + __fmr_hash(p_fmr_el->page_list[0]); + cl_qlist_remove_item( bucket, &p_fmr_el->cache_node ); + } + cl_spinlock_release(&p_pool->pool_lock); + + status = mlnx_map_phys_fmr(p_fmr_el->h_fmr, page_list, + list_len, p_vaddr, p_lkey, p_rkey); + + if (status != IB_SUCCESS) { + cl_spinlock_acquire(&p_pool->pool_lock); + cl_qlist_insert_tail(&p_pool->free_list, &p_fmr_el->list_item); + p_fmr_el->p_cur_list = &p_pool->free_list; + cl_spinlock_release(&p_pool->pool_lock); + goto exit; + } + + ++p_fmr_el->remap_count; + p_fmr_el->ref_count = 1; + p_fmr_el->lkey = *p_lkey; + p_fmr_el->rkey = *p_rkey; + p_fmr_el->io_virtual_address = *p_vaddr; + cl_spinlock_acquire(&p_pool->pool_lock); + cl_qlist_insert_tail(&p_pool->rest_list, &p_fmr_el->list_item); + p_fmr_el->p_cur_list = &p_pool->rest_list; + cl_spinlock_release(&p_pool->pool_lock); + + if (p_pool->cache_bucket) { + p_fmr_el->io_virtual_address = *p_vaddr; + p_fmr_el->page_list_len = list_len; + memcpy(p_fmr_el->page_list, page_list, list_len * sizeof(*page_list)); + + cl_spinlock_acquire(&p_pool->pool_lock); + bucket = p_pool->cache_bucket + __fmr_hash(p_fmr_el->page_list[0]); + cl_qlist_insert_head( bucket, &p_fmr_el->cache_node ); + p_fmr_el->in_cash = TRUE; + cl_spinlock_release(&p_pool->pool_lock); + } + +end: + *pp_fmr_el = (mlnx_fmr_pool_el_t)p_fmr_el; + *p_lkey = p_fmr_el->lkey; + *p_rkey = p_fmr_el->rkey; + *p_vaddr = p_fmr_el->io_virtual_address; + +exit: + deref_al_obj( &p_pool->obj ); + return status; +} + + + +ib_api_status_t +mlnx_unmap_fmr_pool( + IN mlnx_fmr_pool_el_t p_fmr_el ) +{ + mlnx_fmr_pool_t *p_pool; + + p_pool = (mlnx_fmr_pool_t*)p_fmr_el->h_pool; + + if( AL_OBJ_INVALID_HANDLE( (mlnx_fmr_pool_handle_t)p_pool, AL_OBJ_TYPE_H_FMR_POOL ) ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_HANDLE\n") ); + return IB_INVALID_HANDLE; + } + + ref_al_obj( &p_pool->obj ); + + cl_spinlock_acquire(&p_pool->pool_lock); + + --p_fmr_el->ref_count; + if (!p_fmr_el->ref_count) + { + if (p_fmr_el->p_cur_list == &p_pool->rest_list) + cl_qlist_remove_item( p_fmr_el->p_cur_list, &p_fmr_el->list_item ); + + if (p_fmr_el->remap_count < p_pool->max_remaps) + { + cl_qlist_insert_tail(&p_pool->free_list,&p_fmr_el->list_item); + p_fmr_el->p_cur_list = &p_pool->free_list; + } + else + { + cl_qlist_insert_tail(&p_pool->dirty_list, &p_fmr_el->list_item); + p_fmr_el->p_cur_list = &p_pool->dirty_list; + ++p_pool->dirty_len; + cl_event_signal(&p_pool->do_flush_event); + } + } + + if (p_fmr_el->ref_count < 0) + { + AL_PRINT(TRACE_LEVEL_WARNING, AL_DBG_FMR_POOL, ("FMR %p has ref count %d < 0\n",p_fmr_el, p_fmr_el->ref_count)); + } + cl_spinlock_release( &p_pool->pool_lock ); + + deref_al_obj( &p_pool->obj ); + return IB_SUCCESS; +} diff --git a/branches/WOF2-3/core/al/kernel/al_fmr_pool.h b/branches/WOF2-3/core/al/kernel/al_fmr_pool.h new file mode 100644 index 00000000..2f7624a2 --- /dev/null +++ b/branches/WOF2-3/core/al/kernel/al_fmr_pool.h @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: al_fmr_pool.h 1611 2006-08-20 14:48:55Z sleybo $ + */ + + +#if !defined(__AL_FMR_POOL_H__) +#define __AL_FMR_POOL_H__ + +#include +#include +#include "al_common.h" + + +/* + * If an FMR is not in use, then the list member will point to either + * its pool's free_list (if the FMR can be mapped again; that is, + * remap_count < pool->max_remaps) or its pool's dirty_list (if the + * FMR needs to be unmapped before being remapped). In either of + * these cases it is a bug if the ref_count is not 0. In other words, + * if ref_count is > 0, then the list member must not be linked into + * either free_list or dirty_list. + * + * The cache_node member is used to link the FMR into a cache bucket + * (if caching is enabled). This is independent of the reference + * count of the FMR. When a valid FMR is released, its ref_count is + * decremented, and if ref_count reaches 0, the FMR is placed in + * either free_list or dirty_list as appropriate. However, it is not + * removed from the cache and may be "revived" if a call to + * ib_fmr_register_physical() occurs before the FMR is remapped. In + * this case we just increment the ref_count and remove the FMR from + * free_list/dirty_list. + * + * Before we remap an FMR from free_list, we remove it from the cache + * (to prevent another user from obtaining a stale FMR). When an FMR + * is released, we add it to the tail of the free list, so that our + * cache eviction policy is "least recently used." + * + * All manipulation of ref_count, list and cache_node is protected by + * pool_lock to maintain consistency. + */ + +#pragma warning( disable : 4200) +typedef struct _mlnx_fmr_pool_element { + mlnx_fmr_handle_t h_fmr; + mlnx_fmr_pool_handle_t h_pool; + cl_list_item_t list_item; + cl_qlist_t *p_cur_list; + cl_list_item_t cache_node; + boolean_t in_cash; + int ref_count; + int remap_count; + uint64_t io_virtual_address; + net32_t lkey; + net32_t rkey; + int page_list_len; + uint64_t page_list[0]; +} mlnx_fmr_pool_element_t; +#pragma warning( default : 4200) + + +typedef struct _mlnx_fmr_pool { + + al_obj_t obj; /* Child of ib_al_handle_t */ + cl_spinlock_t pool_lock; + + int pool_size; + int max_pages; + int max_remaps; + int dirty_watermark; + int dirty_len; + cl_qlist_t free_list; + cl_qlist_t dirty_list; + cl_qlist_t rest_list; /* those, that not in free and not in dirty */ + cl_qlist_t *cache_bucket; + + void (*flush_function) (mlnx_fmr_pool_handle_t h_pool,void* arg); + void *flush_arg; + + cl_thread_t thread; + cl_event_t do_flush_event; + cl_event_t flush_done_event; + atomic32_t flush_req; + atomic32_t should_stop; +} mlnx_fmr_pool_t; + + +#endif /* IB_FMR_POOL_H */ + diff --git a/branches/WOF2-3/core/al/kernel/al_ioc_pnp.c b/branches/WOF2-3/core/al/kernel/al_ioc_pnp.c new file mode 100644 index 00000000..feb9f557 --- /dev/null +++ b/branches/WOF2-3/core/al/kernel/al_ioc_pnp.c @@ -0,0 +1,3329 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include +#include "al_pnp.h" +#include "al_ioc_pnp.h" +#include "al_debug.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "al_ioc_pnp.tmh" +#endif +#include "ib_common.h" +#include "al_mgr.h" +#include "al_ca.h" +#include +#include +#include +#include +#include + + +/* Basic sweep operation flow: + * + * NOTE: Empty lines indicate asynchronous decoupling. + * 1. Timer expires + * 2. Issue SA query for all CA nodes + * 3. Issue SA query for all paths + * + * 4. Query callback for first query - store results. + * 5. Query callback for second query - process results. + * 6. Associate paths to nodes. + * 7. For each node, use the first path to send a IOU Info query. + * + * 8a. Recv callback (success) - record IOU info, decrement ref count. + * 8b. Recv callback (failure) - decrement ref count. + * 8c. Send failure - decrement ref count. + * 8d. Send timeout - pick next path and repeate IOU info query. + * 9. Queue results to async proc thread once ref count hits zero + * + * 10. Discard any nodes that failed IOU info query, or reported no IOCs. + * 11. For each node scanned that is already known, compare change ID + * 12a. Change ID identical - report any path changes. + * 12b. Change ID different - for each active IOC slot, query IOC profile. + * + * 13a. Recv callback (success) - associate IOC with IOU, decrement ref count. + * 13b. Recv callback (failure) - decrement ref count. + * 13c. Send failure - decrement ref count. + * 14. Queue results to async proc thread once ref count hits zero. + * + * 15. Discard any nodes that have no IOCs. + * 16. For each IOC of each node, query all service entries. + * + * 17a. Recv callback (success) - copy service entries, decrement ref count. + * 17b. Recv callback (failure) - Remove IOC from IOU, decrement ref count. + * 17c. Send failure - Remove IOC from IOU, decrement ref count. + * 18. Queue results to async proc thread once ref count hits zero. + * + * 19. Discard any nodes that have no IOCs. + * 20. Compare new node map to known nodes and report changes. + * 21. Compare IOCs for any duplicates and report changes. + * 22. Compare paths for any duplicates and report changes. + * 23. Reset sweep timer. + * + * Note: the sweep timer is reset at any point where there can be no further + * progress towards. + */ + + +/* Number of entries in the various pools to grow by. */ +#define IOC_PNP_POOL_GROW (10) + + +/* IOC PnP Manager structure. */ +typedef struct _ioc_pnp_mgr +{ + al_obj_t obj; + + cl_qlist_t iou_reg_list; + cl_qlist_t ioc_reg_list; + + ib_pnp_handle_t h_pnp; + + cl_async_proc_item_t async_item; + boolean_t async_item_is_busy; + + cl_spinlock_t iou_pool_lock; + cl_qpool_t iou_pool; + cl_spinlock_t ioc_pool_lock; + cl_qpool_t ioc_pool; + cl_spinlock_t path_pool_lock; + cl_qpool_t path_pool; + + cl_fmap_t iou_map; /* Map of currently known IOUs */ + cl_fmap_t sweep_map; /* Map of IOUs from sweep results. */ + cl_timer_t sweep_timer;/* Timer to trigger sweep. */ + atomic32_t query_cnt; /* Number of sweep results outstanding. */ + +} ioc_pnp_mgr_t; + + +/* Per-port IOC PnP agent. */ +typedef struct _ioc_pnp_svc +{ + al_obj_t obj; + + net64_t ca_guid; + net64_t port_guid; + + ib_qp_handle_t h_qp; + ib_pool_key_t pool_key; + ib_mad_svc_handle_t h_mad_svc; + + atomic32_t query_cnt; + ib_query_handle_t h_node_query; + ib_query_handle_t h_path_query; + ib_mad_element_t *p_node_element; + ib_mad_element_t *p_path_element; + uint32_t num_nodes; + uint32_t num_paths; + +} ioc_pnp_svc_t; + + +/****d* Access Layer:IOC PnP/iou_path_t +* NAME +* iou_path_t +* +* DESCRIPTION +* Describes a path to an IOU node. +* +* SYNOPSIS +*/ +typedef struct _iou_path +{ + cl_fmap_item_t map_item; + net64_t ca_guid; + net64_t port_guid; + ib_path_rec_t rec; + +} iou_path_t; +/* +* FIELDS +* map_item +* Map item for storing paths in a map. +* +* path_rec +* Path record. +* +* SEE ALSO +* IOC PnP +*********/ + + +/****d* Access Layer:IOC PnP/iou_node_t +* NAME +* iou_node_t +* +* DESCRIPTION +* Describes an IOU node on the fabric. +* +* SYNOPSIS +*/ +typedef struct _iou_node +{ + cl_fmap_item_t map_item; + cl_fmap_t path_map; + cl_qmap_t ioc_map; + cl_spinlock_t lock; + + iou_path_t *p_config_path; + + net64_t ca_guid; + net64_t guid; + net64_t chassis_guid; + uint8_t slot; + net32_t vend_id; + net16_t dev_id; + net32_t revision; + ib_iou_info_t info; + + char desc[IB_NODE_DESCRIPTION_SIZE + 1]; + +} iou_node_t; +/* +* FIELDS +* map_item +* Map item for storing IOUs in a map. +* +* path_map +* Map of paths to the IOU. +* +* ioc_map +* Map of IOCs on the IOU. +* +* p_config_path +* Path used to get configuration information from the IOU. +* +* ca_guid +* CA GUID through which the IOU is accessible. +* +* guid +* Node GUID used as key when storing IOUs in the map. +* +* chassis_guid +* GUID of the chassis in which the IOU is installed. +* +* slot +* Slot number in the chassis in which the IOU is installed. +* +* vend_id +* Vendor ID of the IOU. +* +* dev_id +* Device ID of the IOU. +* +* revision +* Device revision of the IOU. +* +* info +* I/O unit info structure. +* +* desc +* Node description as provided in ib_node_record_t, along with space for +* terminating NULL. +* +* NOTES +* The guid member must follow the ca_guid member to allow both guids to +* be compared in single call to cl_memcmp. +* +* SEE ALSO +* IOC PnP +*********/ + + +#pragma warning(disable:4324) +typedef struct _iou_ioc +{ + cl_map_item_t map_item; + iou_node_t *p_iou; + uint8_t slot; + ib_ioc_profile_t profile; + uint8_t num_valid_entries; + ib_svc_entry_t *p_svc_entries; + atomic32_t ref_cnt; + +} iou_ioc_t; +#pragma warning(default:4324) + + +typedef enum _sweep_state +{ + SWEEP_IOU_INFO, + SWEEP_IOC_PROFILE, + SWEEP_SVC_ENTRIES, + SWEEP_COMPLETE + +} sweep_state_t; + + +typedef struct _ioc_sweep_results +{ + cl_async_proc_item_t async_item; + sweep_state_t state; + ioc_pnp_svc_t *p_svc; + atomic32_t query_cnt; + cl_fmap_t iou_map; + +} ioc_sweep_results_t; + + +typedef struct _al_pnp_ioc_event +{ + size_t rec_size; + ib_pnp_rec_t *p_rec; + ib_pnp_rec_t *p_user_rec; + +} al_pnp_ioc_event_t; + + +/* Global instance of the IOC PnP manager. */ +ioc_pnp_mgr_t *gp_ioc_pnp = NULL; +uint32_t g_ioc_query_timeout = 250; +uint32_t g_ioc_query_retries = 4; +uint32_t g_ioc_poll_interval = 30000; + + + +/****************************************************************************** +* +* IOC PnP Manager functions - global object. +* +******************************************************************************/ +static void +__construct_ioc_pnp( + IN ioc_pnp_mgr_t* const p_ioc_mgr ); + +static ib_api_status_t +__init_ioc_pnp( + IN ioc_pnp_mgr_t* const p_ioc_mgr ); + +static void +__destroying_ioc_pnp( + IN al_obj_t *p_obj ); + +static void +__free_ioc_pnp( + IN al_obj_t *p_obj ); + +static ib_api_status_t +__ioc_pnp_cb( + IN ib_pnp_rec_t *p_pnp_rec ); + +static cl_status_t +__init_iou( + IN void* const p_obj, + IN void* context, + OUT cl_pool_item_t** const pp_pool_item ); + +/****************************************************************************** +* +* IOC PnP manager sweep-related functions. +* +******************************************************************************/ +static iou_node_t* +__get_iou( + IN ioc_pnp_mgr_t* const p_ioc_mgr, + IN const net64_t ca_guid, + IN const ib_node_record_t* const p_node_rec ); + +static void +__put_iou( + IN ioc_pnp_mgr_t* const p_ioc_mgr, + IN iou_node_t* const p_iou ); + +static void +__put_iou_map( + IN ioc_pnp_mgr_t* const p_ioc_mgr, + IN cl_fmap_t* const p_iou_map ); + +static iou_path_t* +__get_path( + IN ioc_pnp_mgr_t* const p_ioc_mgr, + IN const net64_t ca_guid, + IN const net64_t port_guid, + IN const ib_path_rec_t* const p_path_rec ); + +static void +__put_path( + IN ioc_pnp_mgr_t* const p_ioc_mgr, + IN iou_path_t* const p_path ); + +static void +__put_path_map( + IN ioc_pnp_mgr_t* const p_ioc_mgr, + IN cl_fmap_t* const p_path_map ); + +static iou_ioc_t* +__get_ioc( + IN ioc_pnp_mgr_t* const p_ioc_mgr, + IN const uint32_t ioc_slot, + IN const ib_ioc_profile_t* const p_profile ); + +static void +__put_ioc( + IN ioc_pnp_mgr_t* const p_ioc_mgr, + IN iou_ioc_t* const p_ioc ); + +static void +__put_ioc_map( + IN ioc_pnp_mgr_t* const p_ioc_mgr, + IN cl_qmap_t* const p_ioc_map ); + +static int +__iou_cmp( + IN const void* const p_key1, + IN const void* const p_key2 ); + +static int +__path_cmp( + IN const void* const p_key1, + IN const void* const p_key2 ); + +static void +__ioc_pnp_timer_cb( + IN void *context ); + +static void +__ioc_async_cb( + IN cl_async_proc_item_t *p_async_item ); + +/****************************************************************************** +* +* IOC PnP service - per local port child of IOC PnP manager. +* +******************************************************************************/ +static ib_api_status_t +__create_ioc_pnp_svc( + IN ib_pnp_rec_t *p_pnp_rec ); + +static ib_api_status_t +__init_ioc_pnp_svc( + IN ioc_pnp_svc_t* const p_ioc_pnp_svc, + IN const ib_pnp_rec_t* const p_pnp_rec ); + +static void +__destroying_ioc_pnp_svc( + IN al_obj_t *p_obj ); + +static void +__free_ioc_pnp_svc( + IN al_obj_t *p_obj ); + +/****************************************************************************** +* +* IOC PnP service sweep functions. +* +******************************************************************************/ +static void +__ioc_pnp_recv_cb( + IN const ib_mad_svc_handle_t h_mad_svc, + IN void *mad_svc_context, + IN ib_mad_element_t *p_request_mad ); + +static void +__ioc_pnp_send_cb( + IN const ib_mad_svc_handle_t h_mad_svc, + IN void *mad_svc_context, + IN ib_mad_element_t *p_mad_response ); + +static void +__node_rec_cb( + IN ib_query_rec_t *p_query_rec ); + +static void +__path_rec_cb( + IN ib_query_rec_t *p_query_rec ); + +static void +__process_sweep( + IN cl_async_proc_item_t *p_async_item ); + +static void +__process_query( + IN ioc_pnp_svc_t* const p_svc ); + +static void +__process_nodes( + IN ioc_pnp_svc_t* const p_svc, + IN cl_qmap_t* const p_iou_map ); + +static void +__process_paths( + IN ioc_pnp_svc_t* const p_svc, + IN cl_qmap_t* const p_iou_map ); + +static void +__build_iou_map( + IN cl_qmap_t* const p_port_map, + IN OUT cl_fmap_t* const p_iou_map ); + +static void +__format_dm_get( + IN const void* const context1, + IN const void* const context2, + IN const iou_path_t* const p_path, + IN const net16_t attr_id, + IN const net32_t attr_mod, + IN OUT ib_mad_element_t* const p_mad_element ); + +static ib_api_status_t +__ioc_query_sa( + IN ioc_pnp_svc_t* const p_svc ); + +static ib_api_status_t +__query_ious( + IN ioc_sweep_results_t* const p_results ); + +static ib_api_status_t +__query_ioc_profiles( + IN ioc_sweep_results_t* const p_results ); + +static ib_api_status_t +__query_svc_entries( + IN ioc_sweep_results_t* const p_results ); + +static void +__update_results( + IN ioc_sweep_results_t* const p_results ); + +static void +__iou_info_resp( + IN OUT iou_node_t* const p_iou, + IN const ib_dm_mad_t* const p_mad ); + +static void +__ioc_profile_resp( + IN OUT iou_node_t* const p_iou, + IN const ib_dm_mad_t* const p_mad ); + +static void +__svc_entry_resp( + IN OUT iou_ioc_t* const p_ioc, + IN const ib_dm_mad_t* const p_mad ); + +/****************************************************************************** +* +* Client registration and notification management +* +******************************************************************************/ +static void +__change_ious( + IN cl_fmap_t* const p_cur_ious, + IN cl_fmap_t* const p_dup_ious ); + +static void +__add_ious( + IN cl_fmap_t* const p_cur_ious, + IN cl_fmap_t* const p_new_ious, + IN al_pnp_t* const p_reg OPTIONAL ); + +static void +__remove_ious( + IN cl_fmap_t* const p_old_ious ); + +static void +__add_iocs( + IN iou_node_t* const p_iou, + IN cl_qmap_t* const p_new_iocs, + IN al_pnp_t* const p_reg OPTIONAL ); + +static void +__remove_iocs( + IN iou_node_t* const p_iou, + IN cl_qmap_t* const p_old_iocs ); + +static void +__add_paths( + IN iou_node_t* const p_iou, + IN cl_qmap_t* const p_ioc_map, + IN cl_fmap_t* const p_new_paths, + IN al_pnp_t* const p_reg OPTIONAL ); + +static void +__add_ioc_paths( + IN iou_ioc_t* const p_ioc, + IN cl_fmap_t* const p_new_paths, + IN al_pnp_t* const p_reg OPTIONAL ); + +static void +__remove_paths( + IN cl_qmap_t* const p_ioc_map, + IN cl_fmap_t* const p_old_paths ); + +static void +__report_iou_add( + IN iou_node_t* const p_iou, + IN al_pnp_t* const p_reg OPTIONAL ); + +static void +__report_iou_remove( + IN iou_node_t* const p_iou ); + +static void +__report_ioc_add( + IN iou_node_t* const p_iou, + IN iou_ioc_t* const p_ioc, + IN al_pnp_t* const p_reg OPTIONAL ); + +static void +__report_ioc_remove( + IN iou_node_t* const p_iou, + IN iou_ioc_t* const p_ioc ); + +static void +__report_path( + IN iou_ioc_t* const p_ioc, + IN iou_path_t* const p_path, + IN ib_pnp_event_t pnp_event, + IN al_pnp_t* const p_reg OPTIONAL ); + + +/****************************************************************************** +* +* Implementation +* +******************************************************************************/ +ib_api_status_t +create_ioc_pnp( + IN al_obj_t* const p_parent_obj ) +{ + ib_api_status_t status; + ib_pnp_req_t pnp_req; + + AL_ENTER( AL_DBG_PNP ); + + CL_ASSERT( !gp_ioc_pnp ); + + gp_ioc_pnp = (ioc_pnp_mgr_t*)cl_zalloc( sizeof(ioc_pnp_mgr_t) ); + if( !gp_ioc_pnp ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("Failed to allocate IOC PnP manager.\n") ); + return IB_INSUFFICIENT_MEMORY; + } + + __construct_ioc_pnp( gp_ioc_pnp ); + + status = __init_ioc_pnp( gp_ioc_pnp ); + if( status != IB_SUCCESS ) + { + __free_ioc_pnp( &gp_ioc_pnp->obj ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("__construct_ioc_pnp returned %s\n", ib_get_err_str( status )) ); + return status; + } + + /* Attach to the parent object. */ + status = attach_al_obj( p_parent_obj, &gp_ioc_pnp->obj ); + if( status != IB_SUCCESS ) + { + gp_ioc_pnp->obj.pfn_destroy( &gp_ioc_pnp->obj, NULL ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("attach_al_obj returned %s.\n", ib_get_err_str(status)) ); + return status; + } + + /* Register for port PnP notifications. */ + cl_memclr( &pnp_req, sizeof(pnp_req) ); + pnp_req.pnp_class = IB_PNP_PORT; + pnp_req.pnp_context = gp_ioc_pnp; + pnp_req.pfn_pnp_cb = __ioc_pnp_cb; + status = ib_reg_pnp( gh_al, &pnp_req, &gp_ioc_pnp->h_pnp ); + if( status != IB_SUCCESS ) + { + gp_ioc_pnp->obj.pfn_destroy( &gp_ioc_pnp->obj, NULL ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("ib_reg_pnp failed with status %s.\n", + ib_get_err_str( status )) ); + return status; + } + /* + * We don't release the reference taken in init_al_obj + * since PnP deregistration is asynchronous. + */ + + AL_EXIT( AL_DBG_PNP ); + return IB_SUCCESS; +} + + +static void +__construct_ioc_pnp( + IN ioc_pnp_mgr_t* const p_ioc_mgr ) +{ + AL_ENTER( AL_DBG_PNP ); + + cl_qlist_init( &p_ioc_mgr->iou_reg_list ); + cl_qlist_init( &p_ioc_mgr->ioc_reg_list ); + cl_fmap_init( &p_ioc_mgr->iou_map, __iou_cmp ); + construct_al_obj( &p_ioc_mgr->obj, AL_OBJ_TYPE_IOC_PNP_MGR ); + cl_spinlock_construct( &p_ioc_mgr->iou_pool_lock ); + cl_spinlock_construct( &p_ioc_mgr->path_pool_lock ); + cl_spinlock_construct( &p_ioc_mgr->ioc_pool_lock ); + cl_qpool_construct( &p_ioc_mgr->iou_pool ); + cl_qpool_construct( &p_ioc_mgr->path_pool ); + cl_qpool_construct( &p_ioc_mgr->ioc_pool ); + cl_fmap_init( &p_ioc_mgr->sweep_map, __iou_cmp ); + cl_timer_construct( &p_ioc_mgr->sweep_timer ); + p_ioc_mgr->async_item.pfn_callback = __ioc_async_cb; + + AL_EXIT( AL_DBG_PNP ); +} + + +static ib_api_status_t +__init_ioc_pnp( + IN ioc_pnp_mgr_t* const p_ioc_mgr ) +{ + ib_api_status_t status; + cl_status_t cl_status; + + AL_ENTER( AL_DBG_PNP ); + + /* Initialize the pool locks. */ + cl_status = cl_spinlock_init( &p_ioc_mgr->iou_pool_lock ); + if( cl_status != CL_SUCCESS ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("cl_spinlock_init returned %#x\n", cl_status) ); + return ib_convert_cl_status( cl_status ); + } + + cl_status = cl_spinlock_init( &p_ioc_mgr->path_pool_lock ); + if( cl_status != CL_SUCCESS ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("cl_spinlock_init returned %#x\n", cl_status) ); + return ib_convert_cl_status( cl_status ); + } + + cl_status = cl_spinlock_init( &p_ioc_mgr->ioc_pool_lock ); + if( cl_status != CL_SUCCESS ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("cl_spinlock_init returned %#x\n", cl_status) ); + return ib_convert_cl_status( cl_status ); + } + + /* Initialize the pools */ + cl_status = cl_qpool_init( &p_ioc_mgr->iou_pool, 0, 0, IOC_PNP_POOL_GROW, + sizeof(iou_node_t), __init_iou, NULL, p_ioc_mgr ); + if( cl_status != CL_SUCCESS ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("cl_qpool_init returned %#x\n", cl_status) ); + return ib_convert_cl_status( cl_status ); + } + + cl_status = cl_qpool_init( &p_ioc_mgr->path_pool, 0, 0, IOC_PNP_POOL_GROW, + sizeof(iou_path_t), NULL, NULL, NULL ); + if( cl_status != CL_SUCCESS ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("cl_qpool_init returned %#x\n", cl_status) ); + return ib_convert_cl_status( cl_status ); + } + + cl_status = cl_qpool_init( &p_ioc_mgr->ioc_pool, 0, 0, IOC_PNP_POOL_GROW, + sizeof(iou_ioc_t), NULL, NULL, NULL ); + if( cl_status != CL_SUCCESS ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("cl_qpool_init returned %#x\n", cl_status) ); + return ib_convert_cl_status( cl_status ); + } + + /* Initialize the sweep timer. */ + cl_status = cl_timer_init( &p_ioc_mgr->sweep_timer, + __ioc_pnp_timer_cb, p_ioc_mgr ); + if( cl_status != CL_SUCCESS ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("cl_timer_init failed with %#x\n", cl_status) ); + return ib_convert_cl_status( cl_status ); + } + + status = init_al_obj( &p_ioc_mgr->obj, p_ioc_mgr, TRUE, + __destroying_ioc_pnp, NULL, __free_ioc_pnp ); + if( status != IB_SUCCESS ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("init_al_obj returned %s\n", ib_get_err_str( status )) ); + return status; + } + + AL_EXIT( AL_DBG_PNP ); + return IB_SUCCESS; +} + + +static void +__destroying_ioc_pnp( + IN al_obj_t *p_obj ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_PNP ); + + UNUSED_PARAM( p_obj ); + CL_ASSERT( &gp_ioc_pnp->obj == p_obj ); + + /* Stop the timer. */ + cl_timer_stop( &gp_ioc_pnp->sweep_timer ); + + if( gp_ioc_pnp->h_pnp ) + { + status = ib_dereg_pnp( gp_ioc_pnp->h_pnp, + (ib_pfn_destroy_cb_t)deref_al_obj ); + CL_ASSERT( status == IB_SUCCESS ); + } + + AL_EXIT( AL_DBG_PNP ); +} + + +static void +__free_ioc_pnp( + IN al_obj_t *p_obj ) +{ + AL_ENTER( AL_DBG_PNP ); + + CL_ASSERT( &gp_ioc_pnp->obj == p_obj ); + + /* + * Return all items from the maps to their pools before + * destroying the pools + */ + __put_iou_map( gp_ioc_pnp, &gp_ioc_pnp->iou_map ); + cl_timer_destroy( &gp_ioc_pnp->sweep_timer ); + cl_qpool_destroy( &gp_ioc_pnp->ioc_pool ); + cl_qpool_destroy( &gp_ioc_pnp->path_pool ); + cl_qpool_destroy( &gp_ioc_pnp->iou_pool ); + cl_spinlock_destroy( &gp_ioc_pnp->ioc_pool_lock ); + cl_spinlock_destroy( &gp_ioc_pnp->path_pool_lock ); + cl_spinlock_destroy( &gp_ioc_pnp->iou_pool_lock ); + destroy_al_obj( p_obj ); + cl_free( gp_ioc_pnp ); + gp_ioc_pnp = NULL; + + AL_EXIT( AL_DBG_PNP ); +} + + +static cl_status_t +__init_iou( + IN void* const p_obj, + IN void* context, + OUT cl_pool_item_t** const pp_pool_item ) +{ + iou_node_t *p_iou; + + UNUSED_PARAM( context ); + + p_iou = (iou_node_t*)p_obj; + + cl_spinlock_construct( &p_iou->lock ); + cl_qmap_init( &p_iou->ioc_map ); + cl_fmap_init( &p_iou->path_map, __path_cmp ); + + *pp_pool_item = &p_iou->map_item.pool_item; + return cl_spinlock_init( &p_iou->lock ); +} + + +static iou_node_t* +__get_iou( + IN ioc_pnp_mgr_t* const p_ioc_mgr, + IN const net64_t ca_guid, + IN const ib_node_record_t* const p_node_rec ) +{ + iou_node_t *p_iou; + cl_pool_item_t *p_item; + + cl_spinlock_acquire( &p_ioc_mgr->iou_pool_lock ); + p_item = cl_qpool_get( &p_ioc_mgr->iou_pool ); + cl_spinlock_release( &p_ioc_mgr->iou_pool_lock ); + if( !p_item ) + return NULL; + + p_iou = PARENT_STRUCT( PARENT_STRUCT( p_item, cl_map_item_t, pool_item ), + iou_node_t, map_item ); + + p_iou->ca_guid = ca_guid; + p_iou->guid = p_node_rec->node_info.node_guid; + p_iou->chassis_guid = p_node_rec->node_info.sys_guid; + p_iou->vend_id = ib_node_info_get_vendor_id( &p_node_rec->node_info ); + p_iou->dev_id = p_node_rec->node_info.device_id; + p_iou->revision = p_node_rec->node_info.revision; + + cl_memclr( &p_iou->info, sizeof(ib_iou_info_t) ); + + cl_memcpy( p_iou->desc, p_node_rec->node_desc.description, + IB_NODE_DESCRIPTION_SIZE ); + + /* The terminating NULL should never get overwritten. */ + CL_ASSERT( p_iou->desc[IB_NODE_DESCRIPTION_SIZE] == '\0' ); + + return p_iou; +} + + +static void +__put_iou( + IN ioc_pnp_mgr_t* const p_ioc_mgr, + IN iou_node_t* const p_iou ) +{ + __put_path_map( p_ioc_mgr, &p_iou->path_map ); + __put_ioc_map( p_ioc_mgr, &p_iou->ioc_map ); + + cl_spinlock_acquire( &p_ioc_mgr->iou_pool_lock ); + cl_qpool_put( &p_ioc_mgr->iou_pool, &p_iou->map_item.pool_item ); + cl_spinlock_release( &p_ioc_mgr->iou_pool_lock ); +} + + +static void +__put_iou_map( + IN ioc_pnp_mgr_t* const p_ioc_mgr, + IN cl_fmap_t* const p_iou_map ) +{ + cl_qlist_t list; + cl_fmap_item_t *p_item; + iou_node_t *p_iou; + + cl_qlist_init( &list ); + + p_item = cl_fmap_head( p_iou_map ); + while( p_item != cl_fmap_end( p_iou_map ) ) + { + cl_fmap_remove_item( p_iou_map, p_item ); + + p_iou = PARENT_STRUCT( + PARENT_STRUCT( p_item, cl_map_item_t, pool_item ), + iou_node_t, map_item ); + + __put_path_map( p_ioc_mgr, &p_iou->path_map ); + __put_ioc_map( p_ioc_mgr, &p_iou->ioc_map ); + cl_qlist_insert_head( &list, &p_item->pool_item.list_item ); + p_item = cl_fmap_head( p_iou_map ); + } + cl_spinlock_acquire( &p_ioc_mgr->iou_pool_lock ); + cl_qpool_put_list( &p_ioc_mgr->iou_pool, &list ); + cl_spinlock_release( &p_ioc_mgr->iou_pool_lock ); +} + + +static iou_path_t* +__get_path( + IN ioc_pnp_mgr_t* const p_ioc_mgr, + IN const net64_t ca_guid, + IN const net64_t port_guid, + IN const ib_path_rec_t* const p_path_rec ) +{ + cl_pool_item_t *p_item; + iou_path_t *p_path; + + cl_spinlock_acquire( &p_ioc_mgr->path_pool_lock ); + p_item = cl_qpool_get( &p_ioc_mgr->path_pool ); + cl_spinlock_release( &p_ioc_mgr->path_pool_lock ); + if( !p_item ) + return NULL; + + p_path = PARENT_STRUCT( PARENT_STRUCT( p_item, cl_fmap_item_t, pool_item ), + iou_path_t, map_item ); + + /* + * Store the local CA and port GUID for this path to let recipients + * of a PATH_ADD event avoid a CA lookup based on GID. + */ + p_path->ca_guid = ca_guid; + p_path->port_guid = port_guid; + + p_path->rec = *p_path_rec; + /* Clear the num_path field since it is just "undefined". */ + p_path->rec.num_path = 0; + /* + * Clear reserved fields in case they were set to prevent undue path + * thrashing. + */ + memset(p_path->rec.resv2, 0, sizeof(p_path->rec.resv2)); + + return p_path; +} + + +static void +__put_path( + IN ioc_pnp_mgr_t* const p_ioc_mgr, + IN iou_path_t* const p_path ) +{ + cl_spinlock_acquire( &p_ioc_mgr->path_pool_lock ); + cl_qpool_put( &p_ioc_mgr->path_pool, &p_path->map_item.pool_item ); + cl_spinlock_release( &p_ioc_mgr->path_pool_lock ); +} + + +static void +__put_path_map( + IN ioc_pnp_mgr_t* const p_ioc_mgr, + IN cl_fmap_t* const p_path_map ) +{ + cl_qlist_t list; + cl_fmap_item_t *p_item; + iou_path_t *p_path; + + cl_qlist_init( &list ); + + p_item = cl_fmap_head( p_path_map ); + while( p_item != cl_fmap_end( p_path_map ) ) + { + cl_fmap_remove_item( p_path_map, p_item ); + + p_path = PARENT_STRUCT( PARENT_STRUCT( p_item, cl_fmap_item_t, pool_item ), + iou_path_t, map_item ); + + cl_qlist_insert_head( &list, &p_item->pool_item.list_item ); + p_item = cl_fmap_head( p_path_map ); + } + cl_spinlock_acquire( &p_ioc_mgr->path_pool_lock ); + cl_qpool_put_list( &p_ioc_mgr->path_pool, &list ); + cl_spinlock_release( &p_ioc_mgr->path_pool_lock ); +} + + +static iou_ioc_t* +__get_ioc( + IN ioc_pnp_mgr_t* const p_ioc_mgr, + IN const uint32_t ioc_slot, + IN const ib_ioc_profile_t* const p_profile ) +{ + cl_pool_item_t *p_item; + iou_ioc_t *p_ioc; + ib_svc_entry_t *p_svc_entries; + + if( !p_profile->num_svc_entries ) + return NULL; + + p_svc_entries = + cl_zalloc( sizeof(ib_svc_entry_t) * p_profile->num_svc_entries ); + if( !p_svc_entries ) + return NULL; + + cl_spinlock_acquire( &p_ioc_mgr->ioc_pool_lock ); + p_item = cl_qpool_get( &p_ioc_mgr->ioc_pool ); + cl_spinlock_release( &p_ioc_mgr->ioc_pool_lock ); + if( !p_item ) + { + cl_free( p_svc_entries ); + return NULL; + } + + p_ioc = PARENT_STRUCT( PARENT_STRUCT( p_item, cl_map_item_t, pool_item ), + iou_ioc_t, map_item ); + + CL_ASSERT( !p_ioc->ref_cnt ); + + CL_ASSERT( !(ioc_slot >> 8) ); + p_ioc->slot = (uint8_t)ioc_slot; + p_ioc->profile = *p_profile; + p_ioc->num_valid_entries = 0; + p_ioc->p_svc_entries = p_svc_entries; + cl_atomic_inc( &p_ioc->ref_cnt ); + return p_ioc; +} + + +static void +__put_ioc( + IN ioc_pnp_mgr_t* const p_ioc_mgr, + IN iou_ioc_t* const p_ioc ) +{ + if( cl_atomic_dec( &p_ioc->ref_cnt ) == 0 ) + { + cl_free( p_ioc->p_svc_entries ); + + cl_spinlock_acquire( &p_ioc_mgr->ioc_pool_lock ); + cl_qpool_put( &p_ioc_mgr->ioc_pool, &p_ioc->map_item.pool_item ); + cl_spinlock_release( &p_ioc_mgr->ioc_pool_lock ); + } +} + + +static void +__put_ioc_map( + IN ioc_pnp_mgr_t* const p_ioc_mgr, + IN cl_qmap_t* const p_ioc_map ) +{ + cl_qlist_t list; + cl_map_item_t *p_item; + iou_ioc_t *p_ioc; + + cl_qlist_init( &list ); + + p_item = cl_qmap_head( p_ioc_map ); + while( p_item != cl_qmap_end( p_ioc_map ) ) + { + cl_qmap_remove_item( p_ioc_map, p_item ); + + p_ioc = PARENT_STRUCT( + PARENT_STRUCT( p_item, cl_map_item_t, pool_item ), + iou_ioc_t, map_item ); + + if( cl_atomic_dec( &p_ioc->ref_cnt ) == 0 ) + { + cl_free( p_ioc->p_svc_entries ); + cl_qlist_insert_head( &list, &p_item->pool_item.list_item ); + } + p_item = cl_qmap_head( p_ioc_map ); + } + cl_spinlock_acquire( &p_ioc_mgr->ioc_pool_lock ); + cl_qpool_put_list( &p_ioc_mgr->ioc_pool, &list ); + cl_spinlock_release( &p_ioc_mgr->ioc_pool_lock ); +} + + +/* + * Compares two IOUs for inserts/lookups in a flexi map. Keys are the + * address of the ca_guid, which is adjacent to the node GUID of the IOU. + * This allows for a single call to cl_memcmp. + */ +static int +__iou_cmp( + IN const void* const p_key1, + IN const void* const p_key2 ) +{ + return cl_memcmp( p_key1, p_key2, sizeof(uint64_t) * 2 ); +} + + +/* + * Compares two paths for inserts/lookups in a flexi map. + */ +static int +__path_cmp( + IN const void* const p_key1, + IN const void* const p_key2 ) +{ + return cl_memcmp( p_key1, p_key2, sizeof(ib_path_rec_t) ); +} + + +/* + * Removes all paths and orphaned IOC/IOUs upon a port DOWN event. + */ +static void +__process_port_down( + IN const net64_t port_guid ) +{ + cl_fmap_item_t *p_path_item; + cl_fmap_item_t *p_iou_item; + iou_node_t *p_iou; + iou_path_t *p_path; + cl_fmap_t old_paths; + cl_fmap_t old_ious; + + AL_ENTER( AL_DBG_PNP ); + + cl_fmap_init( &old_paths, __path_cmp ); + cl_fmap_init( &old_ious, __iou_cmp ); + + p_iou_item = cl_fmap_head( &gp_ioc_pnp->iou_map ); + while( p_iou_item != cl_fmap_end( &gp_ioc_pnp->iou_map ) ) + { + p_iou = PARENT_STRUCT( p_iou_item, iou_node_t, map_item ); + /* + * Note that it is safe to move to the next item even if we remove + * the IOU from the map since the map effectively maintains an ordered + * list of its contents. + */ + p_iou_item = cl_fmap_next( p_iou_item ); + + p_path_item = cl_fmap_head( &p_iou->path_map ); + while( p_path_item != cl_fmap_end( &p_iou->path_map ) ) + { + p_path = PARENT_STRUCT( p_path_item, iou_path_t, map_item ); + p_path_item = cl_fmap_next( p_path_item ); + if( p_path->rec.sgid.unicast.interface_id == port_guid ) + { + cl_fmap_remove_item( &p_iou->path_map, &p_path->map_item ); + cl_fmap_insert( &old_paths, &p_path->rec, &p_path->map_item ); + } + } + + if( !cl_fmap_count( &p_iou->path_map ) ) + { + /* Move the paths back to the IOU so that they get freed. */ + cl_fmap_merge( &p_iou->path_map, &old_paths ); + cl_fmap_remove_item( &gp_ioc_pnp->iou_map, &p_iou->map_item ); + cl_fmap_insert( &old_ious, &p_iou->ca_guid, &p_iou->map_item ); + } + else + { + /* Report the removed paths. */ + __remove_paths( &p_iou->ioc_map, &old_paths ); + } + } + + /* Report any removed IOUs. */ + __remove_ious( &old_ious ); + + AL_EXIT( AL_DBG_PNP ); +} + + +/* + * PnP callback for port event notifications. + */ +static ib_api_status_t +__ioc_pnp_cb( + IN ib_pnp_rec_t *p_pnp_rec ) +{ + ib_api_status_t status = IB_SUCCESS; + cl_status_t cl_status; + + AL_ENTER( AL_DBG_PNP ); + + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_PNP, + ("p_pnp_rec->pnp_event = 0x%x (%s)\n", + p_pnp_rec->pnp_event, ib_get_pnp_event_str( p_pnp_rec->pnp_event )) ); + + switch( p_pnp_rec->pnp_event ) + { + case IB_PNP_PORT_ADD: + /* Create the port service. */ + CL_ASSERT( !p_pnp_rec->context ); + status = __create_ioc_pnp_svc( p_pnp_rec ); + break; + + case IB_PNP_SM_CHANGE: + case IB_PNP_PORT_ACTIVE: + /* Initiate a sweep - delay a bit to allow the ports to come up. */ + if( g_ioc_poll_interval && !gp_ioc_pnp->query_cnt) + { + cl_status = cl_timer_start( &gp_ioc_pnp->sweep_timer, 250 ); + CL_ASSERT( cl_status == CL_SUCCESS ); + } + break; + + case IB_PNP_PORT_DOWN: + case IB_PNP_PORT_INIT: + case IB_PNP_PORT_ARMED: + CL_ASSERT( p_pnp_rec->context ); + + /* + * Report IOC and IOU remove events for any IOU/IOCs that only have + * paths through this port. Note, no need to synchronize with a + * sweep since synchronization is provided by the PnP thread. + */ + __process_port_down( p_pnp_rec->guid ); + break; + + case IB_PNP_PORT_REMOVE: + /* Destroy the port service. */ + ref_al_obj( &((ioc_pnp_svc_t*)p_pnp_rec->context)->obj ); + ((ioc_pnp_svc_t*)p_pnp_rec->context)->obj.pfn_destroy( + &((ioc_pnp_svc_t*)p_pnp_rec->context)->obj, NULL ); + p_pnp_rec->context = NULL; + + default: + break; /* Ignore other PNP events. */ + } + + AL_EXIT( AL_DBG_PNP ); + return status; +} + + +static ib_api_status_t +__init_ioc_pnp_svc( + IN ioc_pnp_svc_t* const p_ioc_pnp_svc, + IN const ib_pnp_rec_t* const p_pnp_rec ) +{ + ib_api_status_t status; + ib_ca_handle_t h_ca; + ib_qp_create_t qp_create; + ib_mad_svc_t mad_svc; + ib_pnp_port_rec_t *p_pnp_port_rec; + + AL_ENTER( AL_DBG_PNP ); + + p_pnp_port_rec = PARENT_STRUCT( p_pnp_rec, ib_pnp_port_rec_t, pnp_rec ); + + /* Store the CA and port GUID so we can issue SA queries. */ + p_ioc_pnp_svc->ca_guid = p_pnp_port_rec->p_ca_attr->ca_guid; + p_ioc_pnp_svc->port_guid = p_pnp_rec->guid; + + /* Acquire the correct CI CA for this port. */ + h_ca = acquire_ca( p_pnp_port_rec->p_ca_attr->ca_guid ); + if( !h_ca ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("acquire_ca failed.\n") ); + return IB_INVALID_GUID; + } + p_ioc_pnp_svc->obj.p_ci_ca = h_ca->obj.p_ci_ca; + + /* Create the MAD QP. */ + cl_memclr( &qp_create, sizeof( ib_qp_create_t ) ); + qp_create.qp_type = IB_QPT_QP1_ALIAS; + qp_create.sq_depth = p_pnp_port_rec->p_ca_attr->max_wrs; + qp_create.sq_sge = 1; + qp_create.sq_signaled = TRUE; + /* + * We use the IOC PnP service's al_obj_t as the context to allow using + * deref_al_obj as the destroy callback. + */ + status = ib_get_spl_qp( h_ca->obj.p_ci_ca->h_pd_alias, + p_pnp_port_rec->p_port_attr->port_guid, &qp_create, + &p_ioc_pnp_svc->obj, NULL, &p_ioc_pnp_svc->pool_key, + &p_ioc_pnp_svc->h_qp ); + + /* + * Release the CI CA once we've allocated the QP. The CI CA will not + * go away while we hold the QP. + */ + deref_al_obj( &h_ca->obj ); + + /* Check for failure allocating the QP. */ + if( status != IB_SUCCESS ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("ib_get_spl_qp failed with status %s\n", + ib_get_err_str( status )) ); + return status; + } + /* Reference the port object on behalf of the QP. */ + ref_al_obj( &p_ioc_pnp_svc->obj ); + + /* Create the MAD service. */ + cl_memclr( &mad_svc, sizeof(ib_mad_svc_t) ); + mad_svc.mad_svc_context = p_ioc_pnp_svc; + mad_svc.pfn_mad_recv_cb = __ioc_pnp_recv_cb; + mad_svc.pfn_mad_send_cb = __ioc_pnp_send_cb; + status = + ib_reg_mad_svc( p_ioc_pnp_svc->h_qp, &mad_svc, + &p_ioc_pnp_svc->h_mad_svc ); + if( status != IB_SUCCESS ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("ib_reg_mad_svc failed with status %s\n", + ib_get_err_str( status )) ); + return status; + } + + AL_EXIT( AL_DBG_PNP ); + return IB_SUCCESS; +} + + +/* + * Create a port agent for a given port. + */ +static ib_api_status_t +__create_ioc_pnp_svc( + IN ib_pnp_rec_t *p_pnp_rec ) +{ + ioc_pnp_svc_t *p_ioc_pnp_svc; + ib_api_status_t status; + + AL_ENTER( AL_DBG_PNP ); + + /* calculate size of port_cm struct */ + p_ioc_pnp_svc = (ioc_pnp_svc_t*)cl_zalloc( sizeof(ioc_pnp_svc_t) ); + if( !p_ioc_pnp_svc ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("Failed to cl_zalloc port CM agent.\n") ); + return IB_INSUFFICIENT_MEMORY; + } + + construct_al_obj( &p_ioc_pnp_svc->obj, AL_OBJ_TYPE_IOC_PNP_SVC ); + + status = init_al_obj( &p_ioc_pnp_svc->obj, p_ioc_pnp_svc, TRUE, + __destroying_ioc_pnp_svc, NULL, __free_ioc_pnp_svc ); + if( status != IB_SUCCESS ) + { + __free_ioc_pnp_svc( &p_ioc_pnp_svc->obj ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("init_al_obj failed with status %s.\n", + ib_get_err_str( status )) ); + return status; + } + + /* Attach to the global CM object. */ + status = attach_al_obj( &gp_ioc_pnp->obj, &p_ioc_pnp_svc->obj ); + if( status != IB_SUCCESS ) + { + p_ioc_pnp_svc->obj.pfn_destroy( &p_ioc_pnp_svc->obj, NULL ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("attach_al_obj returned %s.\n", ib_get_err_str(status)) ); + return status; + } + + status = __init_ioc_pnp_svc( p_ioc_pnp_svc, p_pnp_rec ); + if( status != IB_SUCCESS ) + { + p_ioc_pnp_svc->obj.pfn_destroy( &p_ioc_pnp_svc->obj, NULL ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("__init_data_svc failed with status %s.\n", + ib_get_err_str( status )) ); + return status; + } + + /* Set the PnP context to reference this service. */ + p_pnp_rec->context = p_ioc_pnp_svc; + + /* Release the reference taken in init_al_obj. */ + deref_al_obj( &p_ioc_pnp_svc->obj ); + + AL_EXIT( AL_DBG_PNP ); + return status; +} + + +static void +__destroying_ioc_pnp_svc( + IN al_obj_t *p_obj ) +{ + ib_api_status_t status; + ioc_pnp_svc_t *p_svc; + + CL_ASSERT( p_obj ); + p_svc = PARENT_STRUCT( p_obj, ioc_pnp_svc_t, obj ); + + if( p_svc->h_node_query ) + ib_cancel_query( gh_al, p_svc->h_node_query ); + + if( p_svc->h_path_query ) + ib_cancel_query( gh_al, p_svc->h_path_query ); + + /* Destroy the QP. */ + if( p_svc->h_qp ) + { + status = + ib_destroy_qp( p_svc->h_qp, (ib_pfn_destroy_cb_t)deref_al_obj ); + CL_ASSERT( status == IB_SUCCESS ); + } +} + + +static void +__free_ioc_pnp_svc( + IN al_obj_t *p_obj ) +{ + ioc_pnp_svc_t* p_svc; + + CL_ASSERT( p_obj ); + p_svc = PARENT_STRUCT( p_obj, ioc_pnp_svc_t, obj ); + + CL_ASSERT( !p_svc->query_cnt ); + + destroy_al_obj( p_obj ); + cl_free( p_svc ); +} + + +static void +__ioc_pnp_timer_cb( + IN void *context ) +{ + ib_api_status_t status; + ioc_pnp_mgr_t *p_mgr; + cl_list_item_t *p_item; + ioc_pnp_svc_t *p_svc; + + AL_ENTER( AL_DBG_PNP ); + + p_mgr = (ioc_pnp_mgr_t*)context; + + cl_spinlock_acquire( &p_mgr->obj.lock ); + if( p_mgr->obj.state == CL_DESTROYING ) + { + AL_PRINT_EXIT( TRACE_LEVEL_INFORMATION, AL_DBG_PNP, + ("Destroying - not resetting timer.\n") ); + cl_spinlock_release( &p_mgr->obj.lock ); + return; + } + + CL_ASSERT( !cl_fmap_count( &p_mgr->sweep_map ) ); + + /* Pre-charge the ref count so that we don't toggle between 0 and 1. */ + cl_atomic_inc( &p_mgr->query_cnt ); + /* Take a reference on the object for the duration of the sweep process. */ + ref_al_obj( &p_mgr->obj ); + for( p_item = cl_qlist_head( &p_mgr->obj.obj_list ); + p_item != cl_qlist_end( &p_mgr->obj.obj_list ); + p_item = cl_qlist_next( p_item ) ) + { + p_svc = PARENT_STRUCT( PARENT_STRUCT( p_item, al_obj_t, pool_item ), + ioc_pnp_svc_t, obj ); + cl_atomic_inc( &p_mgr->query_cnt ); + status = __ioc_query_sa( p_svc ); + if( status != IB_SUCCESS ) + cl_atomic_dec( &p_mgr->query_cnt ); + } + /* Release the reference we took and see if we're done sweeping. */ + if( !cl_atomic_dec( &p_mgr->query_cnt ) ) + cl_async_proc_queue( gp_async_pnp_mgr, &p_mgr->async_item ); + + cl_spinlock_release( &p_mgr->obj.lock ); + + AL_EXIT( AL_DBG_PNP ); +} + + +static ib_api_status_t +__ioc_query_sa( + IN ioc_pnp_svc_t* const p_svc ) +{ + ib_api_status_t status = IB_NOT_DONE; + ib_query_req_t query; + ib_user_query_t info; + union _ioc_pnp_timer_cb_u + { + ib_node_record_t node_rec; + ib_path_rec_t path_rec; + + } u; + + AL_ENTER( AL_DBG_PNP ); + + if( p_svc->h_node_query ) + return IB_NOT_DONE; + if( p_svc->h_path_query ) + return IB_NOT_DONE; + + if( p_svc->obj.state == CL_DESTROYING ) + { + AL_PRINT_EXIT( TRACE_LEVEL_INFORMATION, AL_DBG_PNP, + ("Destroying - not resetting timer.\n") ); + return IB_NOT_DONE; + } + + info.method = IB_MAD_METHOD_GETTABLE; + info.attr_id = IB_MAD_ATTR_NODE_RECORD; + info.attr_size = sizeof(ib_node_record_t); + info.comp_mask = IB_NR_COMPMASK_NODETYPE; + info.p_attr = &u.node_rec; + + cl_memclr( &u.node_rec, sizeof(ib_node_record_t) ); + u.node_rec.node_info.node_type = IB_NODE_TYPE_CA; + + cl_memclr( &query, sizeof(ib_query_req_t) ); + query.query_type = IB_QUERY_USER_DEFINED; + query.p_query_input = &info; + query.port_guid = p_svc->port_guid; + query.timeout_ms = g_ioc_query_timeout; + query.retry_cnt = g_ioc_query_retries; + query.query_context = p_svc; + query.pfn_query_cb = __node_rec_cb; + + /* Reference the service for the node record query. */ + ref_al_obj( &p_svc->obj ); + cl_atomic_inc( &p_svc->query_cnt ); + + status = ib_query( gh_al, &query, &p_svc->h_node_query ); + if( status != IB_SUCCESS ) + { + cl_atomic_dec( &p_svc->query_cnt ); + deref_al_obj( &p_svc->obj ); + AL_PRINT_EXIT( TRACE_LEVEL_WARNING, AL_DBG_PNP, + ("ib_query returned %s\n", ib_get_err_str( status )) ); + return status; + } + + /* Setup the path query. */ + info.method = IB_MAD_METHOD_GETTABLE; + info.attr_id = IB_MAD_ATTR_PATH_RECORD; + info.attr_size = sizeof(ib_path_rec_t); + info.comp_mask = IB_PR_COMPMASK_SGID | IB_PR_COMPMASK_NUMBPATH | + IB_PR_COMPMASK_PKEY; + info.p_attr = &u.path_rec; + + cl_memclr( &u.path_rec, sizeof(ib_path_rec_t) ); + ib_gid_set_default( &u.path_rec.sgid, p_svc->port_guid ); + /* Request all the paths available, setting the reversible bit. */ + u.path_rec.num_path = 0xFF; + /* Request only paths from the default partition */ + u.path_rec.pkey = cl_hton16(IB_DEFAULT_PKEY); + + query.pfn_query_cb = __path_rec_cb; + + /* Reference the service for the node record query. */ + ref_al_obj( &p_svc->obj ); + cl_atomic_inc( &p_svc->query_cnt ); + + status = ib_query( gh_al, &query, &p_svc->h_path_query ); + if( status != IB_SUCCESS ) + { + cl_atomic_dec( &p_svc->query_cnt ); + deref_al_obj( &p_svc->obj ); + AL_PRINT_EXIT( TRACE_LEVEL_WARNING, AL_DBG_PNP, + ("ib_query returned %s\n", ib_get_err_str( status )) ); + } + + AL_EXIT( AL_DBG_PNP ); + return IB_SUCCESS; +} + + +static void +__node_rec_cb( + IN ib_query_rec_t *p_query_rec ) +{ + ioc_pnp_svc_t *p_svc; + + AL_ENTER( AL_DBG_PNP ); + + p_svc = (ioc_pnp_svc_t*)p_query_rec->query_context; + + if( p_svc->obj.state != CL_DESTROYING && + p_query_rec->status == IB_SUCCESS && p_query_rec->result_cnt ) + { + CL_ASSERT( p_query_rec->p_result_mad ); + CL_ASSERT( !p_svc->p_node_element ); + CL_ASSERT( p_query_rec->p_result_mad->p_next == NULL ); + p_svc->p_node_element = p_query_rec->p_result_mad; + p_svc->num_nodes = p_query_rec->result_cnt; + } + else if( p_query_rec->p_result_mad ) + { + ib_put_mad( p_query_rec->p_result_mad ); + } + + p_svc->h_node_query = NULL; + if( !cl_atomic_dec( &p_svc->query_cnt ) ) + { + /* The path query has already completed. Process the results. */ + __process_query( p_svc ); + } + + /* Release the reference taken for the query. */ + deref_al_obj( &p_svc->obj ); + + AL_EXIT( AL_DBG_PNP ); +} + + +static void +__path_rec_cb( + IN ib_query_rec_t *p_query_rec ) +{ + ioc_pnp_svc_t *p_svc; + + AL_ENTER( AL_DBG_PNP ); + + p_svc = (ioc_pnp_svc_t*)p_query_rec->query_context; + + if( p_svc->obj.state != CL_DESTROYING && + p_query_rec->status == IB_SUCCESS && p_query_rec->result_cnt ) + { + CL_ASSERT( p_query_rec->p_result_mad ); + CL_ASSERT( !p_svc->p_path_element ); + CL_ASSERT( p_query_rec->p_result_mad->p_next == NULL ); + p_svc->p_path_element = p_query_rec->p_result_mad; + p_svc->num_paths = p_query_rec->result_cnt; + } + else if( p_query_rec->p_result_mad ) + { + ib_put_mad( p_query_rec->p_result_mad ); + } + + p_svc->h_path_query = NULL; + if( !cl_atomic_dec( &p_svc->query_cnt ) ) + { + /* The node query has already completed. Process the results. */ + __process_query( p_svc ); + } + + /* Release the reference taken for the query. */ + deref_al_obj( &p_svc->obj ); + + AL_EXIT( AL_DBG_PNP ); +} + +static void +__process_query( + IN ioc_pnp_svc_t* const p_svc ) +{ + ib_api_status_t status; + ioc_sweep_results_t *p_results; + cl_qmap_t port_map; + + AL_ENTER( AL_DBG_PNP ); + + cl_qmap_init( &port_map ); + + if( !p_svc->p_node_element || !p_svc->p_path_element ) + { + /* One of the queries failed. Release the MADs and reset the timer. */ + if( p_svc->p_node_element ) + { + ib_put_mad( p_svc->p_node_element ); + p_svc->p_node_element = NULL; + } + + if( p_svc->p_path_element ) + { + ib_put_mad( p_svc->p_path_element ); + p_svc->p_path_element = NULL; + } + + /* Decrement the IOC PnP manager's query count. */ + if( !cl_atomic_dec( &gp_ioc_pnp->query_cnt ) ) + cl_async_proc_queue( gp_async_pnp_mgr, &gp_ioc_pnp->async_item ); + AL_EXIT( AL_DBG_PNP ); + return; + } + + /* + * Allocate the sweep results structure to allow processing + * asynchronously. + */ + p_results = cl_zalloc( sizeof(ioc_sweep_results_t) ); + if( p_results ) + { + p_results->async_item.pfn_callback = __process_sweep; + p_results->p_svc = p_svc; + cl_fmap_init( &p_results->iou_map, __iou_cmp ); + + /* Reference the service till the end of sweep processing */ + ref_al_obj( &p_results->p_svc->obj ); + + /* Build the map of nodes by port GUID. */ + __process_nodes( p_svc, &port_map ); + + /* Build the map of paths for each node. */ + __process_paths( p_svc, &port_map ); + + /* Collapse the map of nodes to be keyed by node GUID. */ + __build_iou_map( &port_map, &p_results->iou_map ); + + /* Send the IOU Info queries to the nodes. */ + status = __query_ious( p_results ); + } + else + { + status = IB_INSUFFICIENT_MEMORY; + } + + /* Release the query result MADs now that we're done with them. */ + ib_put_mad( p_svc->p_node_element ); + ib_put_mad( p_svc->p_path_element ); + p_svc->p_node_element = NULL; + p_svc->p_path_element = NULL; + + switch( status ) + { + case IB_SUCCESS: + break; + default: + CL_ASSERT( p_results ); + /* Release the reference taken for the sweep. */ + deref_al_obj( &p_results->p_svc->obj ); + cl_free( p_results ); + /* Fall through */ + case IB_INSUFFICIENT_MEMORY: + /* Decrement the IOC PnP manager's query count. */ + if( !cl_atomic_dec( &gp_ioc_pnp->query_cnt ) ) + cl_async_proc_queue( gp_async_pnp_mgr, &gp_ioc_pnp->async_item ); + } + AL_EXIT( AL_DBG_PNP ); +} + + +static void +__process_nodes( + IN ioc_pnp_svc_t* const p_svc, + IN cl_qmap_t* const p_port_map ) +{ + iou_node_t *p_iou; + ib_node_record_t *p_node_rec; + uint32_t i; + void *p_item; + + AL_ENTER( AL_DBG_PNP ); + + CL_ASSERT( p_svc ); + CL_ASSERT( p_svc->p_node_element ); + CL_ASSERT( p_port_map ); + + for( i = 0; i < p_svc->num_nodes; i++ ) + { + p_node_rec = ib_get_query_node_rec( p_svc->p_node_element, i ); + + p_iou = __get_iou( gp_ioc_pnp, p_svc->ca_guid, p_node_rec ); + if( !p_iou ) + break; + + /* + * We insert by port GUID, not node GUID so that we can match + * to paths using DGID. Note that it is safe to cast between + * a flexi-map item and a map item since the pointer to the key + * in a flexi-map item is always a 64-bit pointer. + */ + p_item = cl_qmap_insert( + p_port_map, p_node_rec->node_info.port_guid, + (cl_map_item_t*)&p_iou->map_item ); + if( p_item != &p_iou->map_item ) + { + /* Duplicate node - discard. */ + __put_iou( gp_ioc_pnp, p_iou ); + } + } + + AL_EXIT( AL_DBG_PNP ); +} + + +static void +__process_paths( + IN ioc_pnp_svc_t* const p_svc, + IN cl_qmap_t* const p_port_map ) +{ + iou_node_t *p_iou; + iou_path_t *p_path; + ib_path_rec_t *p_path_rec; + uint32_t i; + cl_map_item_t *p_iou_item; + cl_fmap_item_t *p_item; + + AL_ENTER( AL_DBG_PNP ); + + CL_ASSERT( p_svc ); + CL_ASSERT( p_svc->p_node_element ); + CL_ASSERT( p_port_map ); + + for( i = 0; i < p_svc->num_paths; i++ ) + { + p_path_rec = ib_get_query_path_rec( p_svc->p_path_element, i ); + + p_iou_item = + cl_qmap_get( p_port_map, p_path_rec->dgid.unicast.interface_id ); + if( p_iou_item == cl_qmap_end( p_port_map ) ) + continue; + + p_iou = PARENT_STRUCT( p_iou_item, iou_node_t, map_item ); + + p_path = __get_path( gp_ioc_pnp, p_svc->ca_guid, + p_svc->port_guid, p_path_rec ); + if( !p_path ) + break; + + p_item = cl_fmap_insert( &p_iou->path_map, &p_path->rec, + &p_path->map_item ); + if( p_item != &p_path->map_item ) + { + /* Duplicate path - discard. */ + __put_path( gp_ioc_pnp, p_path ); + } + } + + AL_EXIT( AL_DBG_PNP ); +} + + +static void +__build_iou_map( + IN cl_qmap_t* const p_port_map, + IN OUT cl_fmap_t* const p_iou_map ) +{ + cl_fmap_t map1, map2; + void *p_item; + iou_node_t *p_iou, *p_dup; + + AL_ENTER( AL_DBG_PNP ); + + CL_ASSERT( !cl_fmap_count( p_iou_map ) ); + + cl_fmap_init( &map1, __path_cmp ); + cl_fmap_init( &map2, __path_cmp ); + + /* + * Now collapse the map so that IOUs aren't repeated. + * This is needed because the IOU map is keyed by port GUID, and thus + * a multi-port IOU could be listed twice. + */ + /* Merge the port map into a map of IOUs. */ + for( p_item = cl_qmap_head( p_port_map ); + p_item != cl_qmap_end( p_port_map ); + p_item = cl_qmap_head( p_port_map ) ) + { + cl_qmap_remove_item( p_port_map, (cl_map_item_t*)p_item ); + p_iou = PARENT_STRUCT( p_item, iou_node_t, map_item ); + + p_item = cl_fmap_insert( p_iou_map, &p_iou->ca_guid, p_item ); + if( p_item != &p_iou->map_item ) + { + /* Duplicate IOU information - merge the paths. */ + p_dup = PARENT_STRUCT( p_item, iou_node_t, map_item ); + CL_ASSERT( p_dup != p_iou ); + cl_fmap_delta( &p_dup->path_map, &p_iou->path_map, &map1, &map2 ); + /* + * The path map in p_iou->path_map is duplicate paths. + * map1 contains paths unique to p_iou->path_map, map2 contains + * paths unique to p_dup->path_map. Add the unique paths back to + * p_dup->path_map since that IOU is already in the IOU map. + * Note that we are keeping the p_dup IOU node. + */ + cl_fmap_merge( &p_dup->path_map, &map1 ); + cl_fmap_merge( &p_dup->path_map, &map2 ); + /* All unique items should have merged without duplicates. */ + CL_ASSERT( !cl_fmap_count( &map1 ) ); + CL_ASSERT( !cl_fmap_count( &map2 ) ); + + __put_iou( gp_ioc_pnp, p_iou ); + } + } + + AL_EXIT( AL_DBG_PNP ); +} + + +static void +__format_dm_get( + IN const void* const context1, + IN const void* const context2, + IN const iou_path_t* const p_path, + IN const net16_t attr_id, + IN const net32_t attr_mod, + IN OUT ib_mad_element_t* const p_mad_element ) +{ + static uint64_t tid = 0; + + AL_ENTER( AL_DBG_PNP ); + + /* + * Context information so that we can continue processing when + * the query completes. + */ + p_mad_element->context1 = context1; + p_mad_element->context2 = context2; + + /* + * Set the addressing bits necessary for the mad service to + * create the address vector + */ + p_mad_element->h_av = NULL; + p_mad_element->remote_sl = ib_path_rec_sl( &p_path->rec ); + p_mad_element->remote_lid = p_path->rec.dlid; + p_mad_element->grh_valid = FALSE; + p_mad_element->path_bits = p_path->rec.num_path; + + /* Request response processing. */ + p_mad_element->resp_expected = TRUE; + p_mad_element->retry_cnt = g_ioc_query_retries; + p_mad_element->timeout_ms = g_ioc_query_timeout; + + /* Set the destination information for the send. */ + p_mad_element->remote_qp = IB_QP1; + p_mad_element->remote_qkey = IB_QP1_WELL_KNOWN_Q_KEY; + + /* Format the MAD payload. */ + cl_memclr( p_mad_element->p_mad_buf, sizeof(ib_dm_mad_t) ); + ib_mad_init_new( p_mad_element->p_mad_buf, IB_MCLASS_DEV_MGMT, 1, + IB_MAD_METHOD_GET, cl_ntoh64( tid++ ), attr_id, attr_mod ); + + AL_EXIT( AL_DBG_PNP ); +} + + +static ib_api_status_t +__query_ious( + IN ioc_sweep_results_t* const p_results ) +{ + ib_api_status_t status; + iou_node_t *p_iou; + iou_path_t *p_path; + cl_fmap_item_t *p_iou_item; + cl_fmap_item_t *p_path_item; + ib_mad_element_t *p_mad, *p_mad_list = NULL; + + AL_ENTER( AL_DBG_PNP ); + + p_results->state = SWEEP_IOU_INFO; + + /* Send a IOU Info query on the first path to every IOU. */ + p_iou_item = cl_fmap_head( &p_results->iou_map ); + while( p_iou_item != cl_fmap_end( &p_results->iou_map ) ) + { + p_iou = PARENT_STRUCT( p_iou_item, iou_node_t, map_item ); + p_iou_item = cl_fmap_next( p_iou_item ); + if( !cl_fmap_count( &p_iou->path_map ) ) + { + /* No paths for this node. Discard it. */ + cl_fmap_remove_item( &p_results->iou_map, &p_iou->map_item ); + __put_iou( gp_ioc_pnp, p_iou ); + continue; + } + + p_path_item = cl_fmap_head( &p_iou->path_map ); + + p_path = PARENT_STRUCT( p_path_item, iou_path_t, map_item ); + + status = ib_get_mad( p_results->p_svc->pool_key, + MAD_BLOCK_SIZE, &p_mad ); + if( status != IB_SUCCESS ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("ib_get_mad for IOU Info query returned %s.\n", + ib_get_err_str( status )) ); + break; + } + + p_iou->p_config_path = p_path; + __format_dm_get( p_results, p_iou, p_path, + IB_MAD_ATTR_IO_UNIT_INFO, 0, p_mad ); + + /* Link the elements together. */ + p_mad->p_next = p_mad_list; + p_mad_list = p_mad; + + cl_atomic_inc( &p_results->p_svc->query_cnt ); + } + + if( !p_mad_list ) + { + AL_EXIT( AL_DBG_PNP ); + return IB_ERROR; + } + + status = ib_send_mad( p_results->p_svc->h_mad_svc, p_mad_list, &p_mad ); + if( status != IB_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("ib_send_mad returned %s\n", ib_get_err_str( status )) ); + + /* If some sends succeeded, change the status. */ + if( p_mad_list != p_mad ) + status = IB_SUCCESS; + + while( p_mad ) + { + p_mad_list = p_mad->p_next; + p_mad->p_next = NULL; + ib_put_mad( p_mad ); + if( !cl_atomic_dec( &p_results->p_svc->query_cnt ) && + status == IB_SUCCESS ) + { + cl_async_proc_queue( gp_async_pnp_mgr, + &p_results->async_item ); + } + p_mad = p_mad_list; + } + } + AL_EXIT( AL_DBG_PNP ); + return status; +} + + +static void +__ioc_pnp_recv_cb( + IN const ib_mad_svc_handle_t h_mad_svc, + IN void *mad_svc_context, + IN ib_mad_element_t *p_mad_response ) +{ + ioc_sweep_results_t *p_results; + iou_node_t *p_iou; + iou_ioc_t *p_ioc; + + AL_ENTER( AL_DBG_PNP ); + + UNUSED_PARAM( h_mad_svc ); + UNUSED_PARAM( mad_svc_context ); + CL_ASSERT( !p_mad_response->p_next ); + + p_results = (ioc_sweep_results_t*)p_mad_response->send_context1; + if( !p_mad_response->p_mad_buf->status ) + { + /* Query was successful */ + switch( p_mad_response->p_mad_buf->attr_id ) + { + case IB_MAD_ATTR_IO_UNIT_INFO: + p_iou = (iou_node_t*)p_mad_response->send_context2; + __iou_info_resp( p_iou, + (ib_dm_mad_t*)p_mad_response->p_mad_buf ); + break; + + case IB_MAD_ATTR_IO_CONTROLLER_PROFILE: + p_iou = (iou_node_t*)p_mad_response->send_context2; + __ioc_profile_resp( p_iou, + (ib_dm_mad_t*)p_mad_response->p_mad_buf ); + break; + + case IB_MAD_ATTR_SERVICE_ENTRIES: + p_ioc = (iou_ioc_t*)p_mad_response->send_context2; + __svc_entry_resp( p_ioc, + (ib_dm_mad_t*)p_mad_response->p_mad_buf ); + break; + + default: + break; + } + } + + ib_put_mad( p_mad_response ); + AL_EXIT( AL_DBG_PNP ); +} + + +static void +__iou_info_resp( + IN OUT iou_node_t* const p_iou, + IN const ib_dm_mad_t* const p_mad ) +{ + AL_ENTER( AL_DBG_PNP ); + /* Copy the IOU info for post-processing. */ + p_iou->info = *((ib_iou_info_t*)p_mad->data); + AL_EXIT( AL_DBG_PNP ); +} + + +static void +__ioc_profile_resp( + IN OUT iou_node_t* const p_iou, + IN const ib_dm_mad_t* const p_mad ) +{ + iou_ioc_t *p_ioc; + cl_map_item_t *p_item; + + AL_ENTER( AL_DBG_PNP ); + p_ioc = __get_ioc( gp_ioc_pnp, cl_ntoh32(p_mad->hdr.attr_mod), + (ib_ioc_profile_t*)p_mad->data ); + if( p_ioc ) + { + /* Need back link to process service entry failures. */ + p_ioc->p_iou = p_iou; + cl_spinlock_acquire( &p_iou->lock ); + p_item = cl_qmap_insert( &p_iou->ioc_map, + p_ioc->profile.ioc_guid, &p_ioc->map_item ); + cl_spinlock_release( &p_iou->lock ); + /* Return the IOC if it's a duplicate. */ + if( p_item != &p_ioc->map_item ) + __put_ioc( gp_ioc_pnp, p_ioc ); + } + AL_EXIT( AL_DBG_PNP ); +} + + +static void +__svc_entry_resp( + IN OUT iou_ioc_t* const p_ioc, + IN const ib_dm_mad_t* const p_mad ) +{ + uint16_t idx; + uint8_t lo, hi; + ib_svc_entries_t *p_svc_entries; + + AL_ENTER( AL_DBG_PNP ); + + ib_dm_get_slot_lo_hi( p_mad->hdr.attr_mod, NULL, &lo, &hi ); + CL_ASSERT( (hi - lo) < SVC_ENTRY_COUNT ); + p_svc_entries = (ib_svc_entries_t*)p_mad->data; + + /* Copy the entries. */ + for( idx = lo; idx <= hi; idx++ ) + p_ioc->p_svc_entries[idx] = p_svc_entries->service_entry[idx - lo]; + + /* Update the number of entries received so far. */ + p_ioc->num_valid_entries += (hi - lo) + 1; + cl_atomic_dec(&p_ioc->ref_cnt); + AL_EXIT( AL_DBG_PNP ); +} + + +static void +__ioc_pnp_send_cb( + IN const ib_mad_svc_handle_t h_mad_svc, + IN void *mad_svc_context, + IN ib_mad_element_t *p_request_mad ) +{ + ib_api_status_t status; + ioc_sweep_results_t *p_results; + iou_node_t *p_iou; + iou_ioc_t *p_ioc; + cl_fmap_item_t *p_item; + + AL_ENTER( AL_DBG_PNP ); + + UNUSED_PARAM( h_mad_svc ); + UNUSED_PARAM( mad_svc_context ); + + CL_ASSERT( p_request_mad->p_next == NULL ); + + p_results = (ioc_sweep_results_t*)p_request_mad->context1; + + if( p_request_mad->status != IB_WCS_SUCCESS ) + { + switch( p_request_mad->p_mad_buf->attr_id ) + { + case IB_MAD_ATTR_IO_UNIT_INFO: + p_iou = (iou_node_t*)p_request_mad->context2; + if( p_request_mad->status == IB_WCS_TIMEOUT_RETRY_ERR ) + { + /* Move to the next path for the node and try the query again. */ + p_item = cl_fmap_next( &p_iou->p_config_path->map_item ); + if( p_item != cl_fmap_end( &p_iou->path_map ) ) + { + p_iou->p_config_path = + PARENT_STRUCT( p_item, iou_path_t, map_item ); + __format_dm_get( p_results, p_iou, p_iou->p_config_path, + IB_MAD_ATTR_IO_UNIT_INFO, 0, p_request_mad ); + + status = ib_send_mad( p_results->p_svc->h_mad_svc, + p_request_mad, &p_request_mad ); + if( status == IB_SUCCESS ) + { + AL_EXIT( AL_DBG_PNP ); + return; + } + } + } + break; + + case IB_MAD_ATTR_SERVICE_ENTRIES: + p_ioc = (iou_ioc_t*)p_request_mad->context2; + cl_spinlock_acquire( &p_ioc->p_iou->lock ); + cl_qmap_remove_item( &p_ioc->p_iou->ioc_map, &p_ioc->map_item ); + cl_spinlock_release( &p_ioc->p_iou->lock ); + __put_ioc( gp_ioc_pnp, p_ioc ); + break; + + default: + break; + } + } + + /* Cleanup. */ + ib_put_mad( p_request_mad ); + + /* + * If this is the last MAD, finish processing the IOU queries + * in the PnP thread. + */ + if( !cl_atomic_dec( &p_results->p_svc->query_cnt ) ) + cl_async_proc_queue( gp_async_pnp_mgr, &p_results->async_item ); + + AL_EXIT( AL_DBG_PNP ); +} + + +static void +__flush_duds( + IN OUT ioc_sweep_results_t *p_results ) +{ + cl_fmap_item_t *p_item; + cl_map_item_t *p_ioc_item; + iou_node_t *p_iou; + iou_ioc_t *p_ioc; + + AL_ENTER( AL_DBG_PNP ); + + /* Walk the map of IOUs and discard any that didn't respond to IOU info. */ + p_item = cl_fmap_head( &p_results->iou_map ); + /* + * No locking required since we're protected by the serialization of the + * PnP thread. + */ + while( p_item != cl_fmap_end( &p_results->iou_map ) ) + { + p_iou = PARENT_STRUCT( p_item, iou_node_t, map_item ); + + p_item = cl_fmap_next( p_item ); + switch( p_results->state ) + { + case SWEEP_IOU_INFO: + if( p_iou->info.max_controllers ) + continue; + break; + + case SWEEP_SVC_ENTRIES: + CL_ASSERT( cl_qmap_count( &p_iou->ioc_map ) ); + p_ioc_item = cl_qmap_head( &p_iou->ioc_map ); + while( p_ioc_item != cl_qmap_end( &p_iou->ioc_map ) ) + { + p_ioc = PARENT_STRUCT( p_ioc_item, iou_ioc_t, map_item ); + p_ioc_item = cl_qmap_next( p_ioc_item ); + + if( !p_ioc->num_valid_entries || + p_ioc->num_valid_entries != p_ioc->profile.num_svc_entries ) + { + cl_qmap_remove_item( &p_iou->ioc_map, &p_ioc->map_item ); + __put_ioc( gp_ioc_pnp, p_ioc ); + } + } + /* Fall through. */ + case SWEEP_IOC_PROFILE: + if( cl_qmap_count( &p_iou->ioc_map ) ) + continue; + break; + + default: + CL_ASSERT( p_results->state != SWEEP_COMPLETE ); + break; + } + + cl_fmap_remove_item( &p_results->iou_map, &p_iou->map_item ); + __put_iou( gp_ioc_pnp, p_iou ); + } + + AL_EXIT( AL_DBG_PNP ); +} + +static void +__process_sweep( + IN cl_async_proc_item_t *p_async_item ) +{ + ib_api_status_t status; + ioc_sweep_results_t *p_results; + + AL_ENTER( AL_DBG_PNP ); + + p_results = PARENT_STRUCT( p_async_item, ioc_sweep_results_t, async_item ); + CL_ASSERT( !p_results->p_svc->query_cnt ); + + if( p_results->p_svc->obj.state == CL_DESTROYING ) + { + __put_iou_map( gp_ioc_pnp, &p_results->iou_map ); + goto err; + } + + /* Walk the map of IOUs and discard any that didn't respond to IOU info. */ + __flush_duds( p_results ); + switch( p_results->state ) + { + case SWEEP_IOU_INFO: + /* Next step, query IOC profiles for all IOUs. */ + p_results->state = SWEEP_IOC_PROFILE; + status = __query_ioc_profiles( p_results ); + break; + + case SWEEP_IOC_PROFILE: + /* Next step: query service entries for all IOCs. */ + p_results->state = SWEEP_SVC_ENTRIES; + status = __query_svc_entries( p_results ); + break; + + case SWEEP_SVC_ENTRIES: + /* Filter results and report changes. */ + p_results->state = SWEEP_COMPLETE; + __update_results( p_results ); + status = IB_SUCCESS; + break; + + default: + CL_ASSERT( p_results->state == SWEEP_IOU_INFO || + p_results->state == SWEEP_IOC_PROFILE || + p_results->state == SWEEP_SVC_ENTRIES ); + status = IB_ERROR; + } + + if( p_results->state == SWEEP_COMPLETE || status != IB_SUCCESS ) + { +err: + if( !cl_atomic_dec( &gp_ioc_pnp->query_cnt ) ) + cl_async_proc_queue( gp_async_pnp_mgr, &gp_ioc_pnp->async_item ); + /* Release the reference taken for the sweep. */ + deref_al_obj( &p_results->p_svc->obj ); + cl_free( p_results ); + } + + AL_EXIT( AL_DBG_PNP ); +} + + +static ib_api_status_t +__query_ioc_profiles( + IN ioc_sweep_results_t* const p_results ) +{ + ib_api_status_t status; + cl_fmap_item_t *p_item; + iou_node_t *p_iou; + uint8_t slot; + ib_mad_element_t *p_mad, *p_mad_list = NULL; + + AL_ENTER( AL_DBG_PNP ); + + p_item = cl_fmap_head( &p_results->iou_map ); + while( p_item != cl_fmap_end( &p_results->iou_map ) ) + { + p_iou = PARENT_STRUCT( p_item, iou_node_t, map_item ); + CL_ASSERT( p_iou->info.max_controllers ); + CL_ASSERT( cl_fmap_count( &p_iou->path_map ) ); + CL_ASSERT( p_iou->p_config_path ); + p_item = cl_fmap_next( p_item ); + + p_mad = NULL; + for( slot = 1; slot <= p_iou->info.max_controllers; slot++ ) + { + if( ioc_at_slot( &p_iou->info, slot ) == IOC_INSTALLED ) + { + status = ib_get_mad( p_results->p_svc->pool_key, + MAD_BLOCK_SIZE, &p_mad ); + if( status != IB_SUCCESS ) + break; + + __format_dm_get( p_results, p_iou, p_iou->p_config_path, + IB_MAD_ATTR_IO_CONTROLLER_PROFILE, cl_hton32( slot ), p_mad ); + + /* Chain the MAD up. */ + p_mad->p_next = p_mad_list; + p_mad_list = p_mad; + + cl_atomic_inc( &p_results->p_svc->query_cnt ); + } + } + if( !p_mad ) + { + /* No IOCs installed in this IOU, or failed to get MAD. */ + cl_fmap_remove_item( &p_results->iou_map, &p_iou->map_item ); + __put_iou( gp_ioc_pnp, p_iou ); + } + } + + /* Trap the case where there are no queries to send. */ + if( !p_mad_list ) + { + AL_EXIT( AL_DBG_PNP ); + return IB_NOT_DONE; + } + + status = ib_send_mad( p_results->p_svc->h_mad_svc, p_mad_list, &p_mad ); + if( status != IB_SUCCESS ) + { + /* If some of the MADs were sent wait for their completion. */ + if( p_mad_list != p_mad ) + status = IB_SUCCESS; + + while( p_mad ) + { + p_mad_list = p_mad->p_next; + p_mad->p_next = NULL; + ib_put_mad( p_mad ); + if( !cl_atomic_dec( &p_results->p_svc->query_cnt ) && + status == IB_SUCCESS ) + { + cl_async_proc_queue( gp_async_pnp_mgr, + &p_results->async_item ); + } + p_mad = p_mad_list; + } + } + AL_EXIT( AL_DBG_PNP ); + return status; +} + + +static ib_api_status_t +__query_svc_entries( + IN ioc_sweep_results_t* const p_results ) +{ + ib_api_status_t status; + cl_fmap_item_t *p_iou_item; + cl_map_item_t *p_ioc_item; + iou_node_t *p_iou; + iou_ioc_t *p_ioc; + uint8_t i; + uint32_t attr_mod; + ib_mad_element_t *p_mad, *p_mad_list = NULL; + + AL_ENTER( AL_DBG_PNP ); + + for( p_iou_item = cl_fmap_head( &p_results->iou_map ); + p_iou_item != cl_fmap_end( &p_results->iou_map ); + p_iou_item = cl_fmap_next( p_iou_item ) ) + { + p_iou = PARENT_STRUCT( p_iou_item, iou_node_t, map_item ); + CL_ASSERT( cl_qmap_count( &p_iou->ioc_map ) ); + CL_ASSERT( cl_fmap_count( &p_iou->path_map ) ); + CL_ASSERT( p_iou->p_config_path ); + + for( p_ioc_item = cl_qmap_head( &p_iou->ioc_map ); + p_ioc_item != cl_qmap_end( &p_iou->ioc_map ); + p_ioc_item = cl_qmap_next( p_ioc_item ) ) + { + p_ioc = PARENT_STRUCT( p_ioc_item, iou_ioc_t, map_item ); + CL_ASSERT( p_ioc->p_iou == p_iou ); + + for( i = 0; i < p_ioc->profile.num_svc_entries; i += 4 ) + { + status = ib_get_mad( p_results->p_svc->pool_key, + MAD_BLOCK_SIZE, &p_mad ); + if( status != IB_SUCCESS ) + break; + + attr_mod = (((uint32_t)p_ioc->slot) << 16) | i; + if( (i + 3) > p_ioc->profile.num_svc_entries ) + attr_mod |= ((p_ioc->profile.num_svc_entries - 1) << 8); + else + attr_mod |= ((i + 3) << 8); + + __format_dm_get( p_results, p_ioc, p_iou->p_config_path, + IB_MAD_ATTR_SERVICE_ENTRIES, cl_hton32( attr_mod ), + p_mad ); + + /* Chain the MAD up. */ + p_mad->p_next = p_mad_list; + p_mad_list = p_mad; + + cl_atomic_inc( &p_ioc->ref_cnt ); + cl_atomic_inc( &p_results->p_svc->query_cnt ); + } + } + } + + /* Trap the case where there are no queries to send. */ + if( !p_mad_list ) + { + AL_EXIT( AL_DBG_PNP ); + return IB_NOT_DONE; + } + + status = ib_send_mad( p_results->p_svc->h_mad_svc, p_mad_list, &p_mad ); + if( status != IB_SUCCESS ) + { + /* If some of the MADs were sent wait for their completion. */ + if( p_mad_list != p_mad ) + status = IB_SUCCESS; + + while( p_mad ) + { + p_mad_list = p_mad->p_next; + p_mad->p_next = NULL; + p_ioc = (iou_ioc_t*)p_mad->context2; + cl_atomic_dec( &p_ioc->ref_cnt ); + ib_put_mad( p_mad ); + if( !cl_atomic_dec( &p_results->p_svc->query_cnt ) && + status == IB_SUCCESS ) + { + cl_async_proc_queue( gp_async_pnp_mgr, + &p_results->async_item ); + } + p_mad = p_mad_list; + } + } + AL_EXIT( AL_DBG_PNP ); + return status; +} + + +static void +__update_results( + IN ioc_sweep_results_t* const p_results ) +{ + cl_fmap_t iou_map1, iou_map2; + cl_fmap_item_t *p_item1, *p_item2; + iou_node_t *p_iou1, *p_iou2; + + AL_ENTER( AL_DBG_PNP ); + + cl_fmap_init( &iou_map1, __iou_cmp ); + cl_fmap_init( &iou_map2, __iou_cmp ); + + /* + * No need to lock on the sweep map since all accesses are serialized + * by the PnP thread. + */ + cl_fmap_delta( &gp_ioc_pnp->sweep_map, &p_results->iou_map, + &iou_map1, &iou_map2 ); + /* sweep_map and iou_map now contain exactly the same items. */ + p_item1 = cl_fmap_head( &gp_ioc_pnp->sweep_map ); + p_item2 = cl_fmap_head( &p_results->iou_map ); + while( p_item1 != cl_fmap_end( &gp_ioc_pnp->sweep_map ) ) + { + CL_ASSERT( p_item2 != cl_fmap_end( &p_results->iou_map ) ); + p_iou1 = PARENT_STRUCT( p_item1, iou_node_t, map_item ); + p_iou2 = PARENT_STRUCT( p_item2, iou_node_t, map_item ); + CL_ASSERT( p_iou1->guid == p_iou2->guid ); + + /* + * Merge the IOC maps - this leaves all duplicates in + * p_iou2->ioc_map. + */ + cl_qmap_merge( &p_iou1->ioc_map, &p_iou2->ioc_map ); + + /* + * Merge the path maps - this leaves all duplicates in + * p_iou2->path_map + */ + cl_fmap_merge( &p_iou1->path_map, &p_iou2->path_map ); + + /* Return the duplicate IOU (and whatever duplicate paths and IOCs) */ + cl_fmap_remove_item( &p_results->iou_map, p_item2 ); + __put_iou( gp_ioc_pnp, p_iou2 ); + + p_item1 = cl_fmap_next( p_item1 ); + p_item2 = cl_fmap_head( &p_results->iou_map ); + } + CL_ASSERT( !cl_fmap_count( &p_results->iou_map ) ); + + /* Merge in the unique items. */ + cl_fmap_merge( &gp_ioc_pnp->sweep_map, &iou_map1 ); + CL_ASSERT( !cl_fmap_count( &iou_map1 ) ); + cl_fmap_merge( &gp_ioc_pnp->sweep_map, &iou_map2 ); + CL_ASSERT( !cl_fmap_count( &iou_map2 ) ); + + AL_EXIT( AL_DBG_PNP ); + return; +} + + +static void +__ioc_async_cb( + IN cl_async_proc_item_t *p_item ) +{ + cl_status_t status; + cl_fmap_t old_ious, new_ious; + + AL_ENTER( AL_DBG_PNP ); + + CL_ASSERT( p_item == &gp_ioc_pnp->async_item ); + UNUSED_PARAM( p_item ); + + CL_ASSERT( !gp_ioc_pnp->query_cnt ); + + cl_fmap_init( &old_ious, __iou_cmp ); + cl_fmap_init( &new_ious, __iou_cmp ); + cl_fmap_delta( + &gp_ioc_pnp->iou_map, &gp_ioc_pnp->sweep_map, &new_ious, &old_ious ); + + /* For each duplicate IOU, report changes in IOCs or paths. */ + __change_ious( &gp_ioc_pnp->iou_map, &gp_ioc_pnp->sweep_map ); + + /* Report all new IOUs. */ + __add_ious( &gp_ioc_pnp->iou_map, &new_ious, NULL ); + CL_ASSERT( !cl_fmap_count( &new_ious ) ); + + /* Report all removed IOUs. */ + __remove_ious( &old_ious ); + CL_ASSERT( !cl_fmap_count( &old_ious ) ); + + /* Reset the sweep timer. */ + if( g_ioc_poll_interval ) + { + status = cl_timer_start( + &gp_ioc_pnp->sweep_timer, g_ioc_poll_interval ); + CL_ASSERT( status == CL_SUCCESS ); + } + + /* Release the reference we took in the timer callback. */ + deref_al_obj( &gp_ioc_pnp->obj ); + + AL_EXIT( AL_DBG_PNP ); +} + + +static void +__change_ious( + IN cl_fmap_t* const p_cur_ious, + IN cl_fmap_t* const p_dup_ious ) +{ + cl_fmap_t new_paths, old_paths; + cl_qmap_t new_iocs, old_iocs; + cl_fmap_item_t *p_item1, *p_item2; + iou_node_t *p_iou1, *p_iou2; + + AL_ENTER( AL_DBG_PNP ); + + cl_fmap_init( &new_paths, __path_cmp ); + cl_fmap_init( &old_paths, __path_cmp ); + cl_qmap_init( &new_iocs ); + cl_qmap_init( &old_iocs ); + + p_item1 = cl_fmap_head( p_cur_ious ); + p_item2 = cl_fmap_head( p_dup_ious ); + while( p_item1 != cl_fmap_end( p_cur_ious ) ) + { + p_iou1 = PARENT_STRUCT( p_item1, iou_node_t, map_item ); + p_iou2 = PARENT_STRUCT( p_item2, iou_node_t, map_item ); + CL_ASSERT( p_iou1->guid == p_iou2->guid ); + + /* Figure out what changed. */ + cl_fmap_delta( + &p_iou1->path_map, &p_iou2->path_map, &new_paths, &old_paths ); + cl_qmap_delta( + &p_iou1->ioc_map, &p_iou2->ioc_map, &new_iocs, &old_iocs ); + + /* + * Report path changes before IOC changes so that new IOCs + * report up-to-date paths. Report new paths before removing + * old ones to minimize the chance of disruption of service - + * i.e. the last path being removed before an alternate is available. + */ + __add_paths( p_iou1, &p_iou1->ioc_map, &new_paths, NULL ); + CL_ASSERT( !cl_fmap_count( &new_paths ) ); + + __remove_paths( &p_iou1->ioc_map, &old_paths ); + CL_ASSERT( !cl_fmap_count( &old_paths ) ); + + /* Report IOCs. */ + __add_iocs( p_iou1, &new_iocs, NULL ); + CL_ASSERT( !cl_qmap_count( &new_iocs ) ); + + __remove_iocs( p_iou1, &old_iocs ); + CL_ASSERT( !cl_qmap_count( &old_iocs ) ); + + /* Done with the duplicate IOU. Return it to the pool */ + cl_fmap_remove_item( p_dup_ious, p_item2 ); + __put_iou( gp_ioc_pnp, p_iou2 ); + + p_item1 = cl_fmap_next( p_item1 ); + p_item2 = cl_fmap_head( p_dup_ious ); + } + CL_ASSERT( !cl_fmap_count( p_dup_ious ) ); + + AL_EXIT( AL_DBG_PNP ); +} + + +static void +__add_ious( + IN cl_fmap_t* const p_cur_ious, + IN cl_fmap_t* const p_new_ious, + IN al_pnp_t* const p_reg OPTIONAL ) +{ + cl_fmap_item_t *p_item; + iou_node_t *p_iou; + + AL_ENTER( AL_DBG_PNP ); + + p_item = cl_fmap_head( p_new_ious ); + while( p_item != cl_fmap_end( p_new_ious ) ) + { + p_iou = PARENT_STRUCT( p_item, iou_node_t, map_item ); + + /* Report the IOU addition. */ + __report_iou_add( p_iou, p_reg ); + + p_item = cl_fmap_next( p_item ); + } + + if( p_cur_ious != p_new_ious ) + { + cl_fmap_merge( p_cur_ious, p_new_ious ); + CL_ASSERT( !cl_fmap_count( p_new_ious ) ); + } + + AL_EXIT( AL_DBG_PNP ); +} + + +static void +__remove_ious( + IN cl_fmap_t* const p_old_ious ) +{ + cl_fmap_item_t *p_item; + iou_node_t *p_iou; + + AL_ENTER( AL_DBG_PNP ); + + p_item = cl_fmap_head( p_old_ious ); + while( p_item != cl_fmap_end( p_old_ious ) ) + { + p_iou = PARENT_STRUCT( p_item, iou_node_t, map_item ); + + /* Report the IOU removal. */ + __report_iou_remove( p_iou ); + + cl_fmap_remove_item( p_old_ious, p_item ); + __put_iou( gp_ioc_pnp, p_iou ); + p_item = cl_fmap_head( p_old_ious ); + } + CL_ASSERT( !cl_fmap_count( p_old_ious ) ); + + AL_EXIT( AL_DBG_PNP ); +} + + +static void +__add_iocs( + IN iou_node_t* const p_iou, + IN cl_qmap_t* const p_new_iocs, + IN al_pnp_t* const p_reg OPTIONAL ) +{ + cl_map_item_t *p_item; + iou_ioc_t *p_ioc; + + AL_ENTER( AL_DBG_PNP ); + + p_item = cl_qmap_head( p_new_iocs ); + while( p_item != cl_qmap_end( p_new_iocs ) ) + { + p_ioc = PARENT_STRUCT( p_item, iou_ioc_t, map_item ); + + /* Report the IOU addition. */ + __report_ioc_add( p_iou, p_ioc, p_reg ); + + p_item = cl_qmap_next( p_item ); + } + + if( p_new_iocs != &p_iou->ioc_map ) + { + cl_qmap_merge( &p_iou->ioc_map, p_new_iocs ); + CL_ASSERT( !cl_qmap_count( p_new_iocs ) ); + } + AL_EXIT( AL_DBG_PNP ); +} + + +static void +__remove_iocs( + IN iou_node_t* const p_iou, + IN cl_qmap_t* const p_old_iocs ) +{ + cl_map_item_t *p_item; + iou_ioc_t *p_ioc; + + AL_ENTER( AL_DBG_PNP ); + + p_item = cl_qmap_tail( p_old_iocs ); + while( p_item != cl_qmap_end( p_old_iocs ) ) + { + p_ioc = PARENT_STRUCT( p_item, iou_ioc_t, map_item ); + + /* Report the IOC removal. */ + __report_ioc_remove( p_iou, p_ioc ); + + cl_qmap_remove_item( p_old_iocs, p_item ); + __put_ioc( gp_ioc_pnp, p_ioc ); + p_item = cl_qmap_tail( p_old_iocs ); + } + CL_ASSERT( !cl_qmap_count( p_old_iocs ) ); + + AL_EXIT( AL_DBG_PNP ); +} + + +static void +__add_paths( + IN iou_node_t* const p_iou, + IN cl_qmap_t* const p_ioc_map, + IN cl_fmap_t* const p_new_paths, + IN al_pnp_t* const p_reg OPTIONAL ) +{ + cl_map_item_t *p_ioc_item; + cl_fmap_item_t *p_item; + iou_ioc_t *p_ioc; + iou_path_t *p_path; + + AL_ENTER( AL_DBG_PNP ); + + p_item = cl_fmap_head( p_new_paths ); + while( p_item != cl_fmap_end( p_new_paths ) ) + { + p_path = PARENT_STRUCT( p_item, iou_path_t, map_item ); + + /* Report the path to all IOCs. */ + for( p_ioc_item = cl_qmap_head( p_ioc_map ); + p_ioc_item != cl_qmap_end( p_ioc_map ); + p_ioc_item = cl_qmap_next( p_ioc_item ) ) + { + p_ioc = PARENT_STRUCT( p_ioc_item, iou_ioc_t, map_item ); + __report_path( p_ioc, p_path, IB_PNP_IOC_PATH_ADD, p_reg ); + } + + p_item = cl_fmap_next( p_item ); + } + + ASSERT( &p_iou->path_map != p_new_paths ); + + cl_fmap_merge( &p_iou->path_map, p_new_paths ); + CL_ASSERT( !cl_fmap_count( p_new_paths ) ); + + AL_EXIT( AL_DBG_PNP ); +} + + +static void +__add_ioc_paths( + IN iou_ioc_t* const p_ioc, + IN cl_fmap_t* const p_new_paths, + IN al_pnp_t* const p_reg OPTIONAL ) +{ + cl_fmap_item_t *p_item; + iou_path_t *p_path; + + AL_ENTER( AL_DBG_PNP ); + + p_item = cl_fmap_head( p_new_paths ); + while( p_item != cl_fmap_end( p_new_paths ) ) + { + p_path = PARENT_STRUCT( p_item, iou_path_t, map_item ); + + __report_path( p_ioc, p_path, IB_PNP_IOC_PATH_ADD, p_reg ); + + p_item = cl_fmap_next( p_item ); + } + + AL_EXIT( AL_DBG_PNP ); +} + + +static void +__remove_paths( + IN cl_qmap_t* const p_ioc_map, + IN cl_fmap_t* const p_old_paths ) +{ + cl_map_item_t *p_ioc_item; + cl_fmap_item_t *p_item; + iou_ioc_t *p_ioc; + iou_path_t *p_path; + + AL_ENTER( AL_DBG_PNP ); + + p_item = cl_fmap_tail( p_old_paths ); + while( p_item != cl_fmap_end( p_old_paths ) ) + { + p_path = PARENT_STRUCT( p_item, iou_path_t, map_item ); + + for( p_ioc_item = cl_qmap_tail( p_ioc_map ); + p_ioc_item != cl_qmap_end( p_ioc_map ); + p_ioc_item = cl_qmap_prev( p_ioc_item ) ) + { + p_ioc = PARENT_STRUCT( p_ioc_item, iou_ioc_t, map_item ); + __report_path( p_ioc, p_path, IB_PNP_IOC_PATH_REMOVE, NULL ); + } + + cl_fmap_remove_item( p_old_paths, p_item ); + __put_path( gp_ioc_pnp, p_path ); + p_item = cl_fmap_tail( p_old_paths ); + } + CL_ASSERT( !cl_fmap_count( p_old_paths ) ); + + AL_EXIT( AL_DBG_PNP ); +} + + +static cl_status_t +__notify_users( + IN const cl_list_item_t* const p_item, + IN al_pnp_ioc_event_t* const p_event ) +{ + ib_api_status_t status; + al_pnp_t *p_reg; + al_pnp_context_t *p_context; + + AL_ENTER( AL_DBG_PNP ); + + p_reg = PARENT_STRUCT( p_item, al_pnp_t, list_item ); + + /* Copy the source record into the user's record. */ + cl_memcpy( p_event->p_user_rec, p_event->p_rec, p_event->rec_size ); + p_event->p_user_rec->h_pnp = p_reg; + p_event->p_user_rec->pnp_context = (void*)p_reg->obj.context; + + switch( p_event->p_rec->pnp_event ) + { + case IB_PNP_IOU_ADD: + CL_ASSERT( pnp_get_class( p_reg->pnp_class ) == IB_PNP_IOU ); + p_context = pnp_create_context( p_reg, &p_event->p_rec->guid); + break; + + case IB_PNP_IOU_REMOVE: + CL_ASSERT( pnp_get_class( p_reg->pnp_class ) == IB_PNP_IOU ); + /* Lookup the context for this IOU. */ + p_context = pnp_get_context( p_reg, &p_event->p_rec->guid ); + break; + + case IB_PNP_IOC_ADD: + CL_ASSERT( pnp_get_class( p_reg->pnp_class ) == IB_PNP_IOC ); + p_context = pnp_create_context( p_reg, &p_event->p_rec->guid); + break; + case IB_PNP_IOC_REMOVE: + case IB_PNP_IOC_PATH_ADD: + case IB_PNP_IOC_PATH_REMOVE: + CL_ASSERT( pnp_get_class( p_reg->pnp_class ) == IB_PNP_IOC ); + p_context = pnp_get_context( p_reg, &p_event->p_rec->guid ); + break; + default: + AL_PRINT_EXIT(TRACE_LEVEL_WARNING, AL_DBG_PNP,("Invalid PnP event %#x\n", + p_event->p_rec->pnp_event)); + return CL_NOT_DONE; + break; + } + if( !p_context ) + return CL_NOT_FOUND; + + p_event->p_user_rec->context = (void*)p_context->context; + + /* Notify user. */ + status = p_reg->pfn_pnp_cb( p_event->p_user_rec ); + + /* Update contexts */ + if( status != IB_SUCCESS || + p_event->p_rec->pnp_event == IB_PNP_IOU_REMOVE || + p_event->p_rec->pnp_event == IB_PNP_IOC_REMOVE ) + { + cl_fmap_remove_item( &p_reg->context_map, &p_context->map_item ); + cl_free( p_context ); + } + else + { + p_context->context = p_event->p_user_rec->context; + } + + AL_EXIT( AL_DBG_PNP ); + return CL_NOT_FOUND; +} + + +static void +__report_iou_add( + IN iou_node_t* const p_iou, + IN al_pnp_t* const p_reg OPTIONAL ) +{ + al_pnp_ioc_event_t event; + ib_pnp_iou_rec_t *p_rec, *p_user_rec; + + AL_ENTER( AL_DBG_PNP ); + + event.rec_size = sizeof(ib_pnp_iou_rec_t); + event.rec_size = ROUNDUP( event.rec_size, sizeof(void*) ); + + p_rec = cl_zalloc( event.rec_size * 2 ); + if( !p_rec ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("Failed to allocate user record.\n") ); + return; + } + p_rec->pnp_rec.pnp_event = IB_PNP_IOU_ADD; + p_rec->pnp_rec.guid = p_iou->guid; + p_rec->pnp_rec.ca_guid = p_iou->ca_guid; + + p_rec->ca_guid = p_iou->ca_guid; + p_rec->guid = p_iou->guid; + p_rec->chassis_guid = p_iou->chassis_guid; + p_rec->vend_id = p_iou->vend_id; + p_rec->dev_id = p_iou->dev_id; + p_rec->revision = p_iou->revision; + cl_memcpy( p_rec->desc, p_iou->desc, sizeof(p_rec->desc) ); + p_user_rec = (ib_pnp_iou_rec_t*)(((uint8_t*)p_rec) + event.rec_size); + + event.p_rec = (ib_pnp_rec_t*)p_rec; + event.p_user_rec = (ib_pnp_rec_t*)p_user_rec; + + if( p_reg ) + { + if( pnp_get_class( p_reg->pnp_class ) == IB_PNP_IOU ) + __notify_users( &p_reg->list_item, &event ); + else + __add_iocs( p_iou, &p_iou->ioc_map, p_reg ); + } + else + { + /* Report the IOU to all clients registered for IOU events. */ + cl_qlist_find_from_head( &gp_ioc_pnp->iou_reg_list, + __notify_users, &event ); + + /* Report IOCs - this will in turn report the paths. */ + __add_iocs( p_iou, &p_iou->ioc_map, NULL ); + } + + cl_free( p_rec ); + AL_EXIT( AL_DBG_PNP ); +} + + +static void +__report_iou_remove( + IN iou_node_t* const p_iou ) +{ + al_pnp_ioc_event_t event; + ib_pnp_iou_rec_t rec, user_rec; + + AL_ENTER( AL_DBG_PNP ); + + /* Report IOCs - this will in turn report the paths. */ + __remove_iocs( p_iou, &p_iou->ioc_map ); + + cl_memclr( &rec, sizeof(ib_pnp_iou_rec_t) ); + rec.pnp_rec.pnp_event = IB_PNP_IOU_REMOVE; + rec.pnp_rec.guid = p_iou->guid; + rec.pnp_rec.ca_guid = p_iou->ca_guid; + + event.rec_size = sizeof(ib_pnp_iou_rec_t); + event.p_rec = (ib_pnp_rec_t*)&rec; + event.p_user_rec = (ib_pnp_rec_t*)&user_rec; + + /* + * Report the IOU to all clients registered for IOU events in + * reverse order than ADD notifications. + */ + cl_qlist_find_from_tail( &gp_ioc_pnp->iou_reg_list, + __notify_users, &event ); + + AL_EXIT( AL_DBG_PNP ); +} + + +static void +__report_ioc_add( + IN iou_node_t* const p_iou, + IN iou_ioc_t* const p_ioc, + IN al_pnp_t* const p_reg OPTIONAL ) +{ + al_pnp_ioc_event_t event; + ib_pnp_ioc_rec_t *p_rec; + + AL_ENTER( AL_DBG_PNP ); + + event.rec_size = sizeof(ib_pnp_ioc_rec_t) + + (sizeof(ib_svc_entry_t) * (p_ioc->profile.num_svc_entries - 1)); + event.rec_size = ROUNDUP( event.rec_size, sizeof(void*) ); + + /* + * The layout of the pnp record is as follows: + * ib_pnp_rec_t + * ib_svc_entry_t + * ib_ioc_info_t + * + * This is needed to keep the service entries contiguous to the first + * entry in the pnp record. + */ + p_rec = (ib_pnp_ioc_rec_t*)cl_zalloc( event.rec_size * 2 ); + if( !p_rec ) + return; + + p_rec->pnp_rec.pnp_event = IB_PNP_IOC_ADD; + p_rec->pnp_rec.guid = p_ioc->profile.ioc_guid; + p_rec->pnp_rec.ca_guid = p_ioc->p_iou->ca_guid; + + p_rec->ca_guid = p_ioc->p_iou->ca_guid; + cl_memcpy( p_rec->svc_entry_array, p_ioc->p_svc_entries, + p_ioc->profile.num_svc_entries * sizeof(ib_svc_entry_t) ); + p_rec->info.chassis_guid = p_iou->chassis_guid; + p_rec->info.chassis_slot = p_iou->slot; + p_rec->info.iou_guid = p_iou->guid; + p_rec->info.iou_slot = p_ioc->slot; + p_rec->info.profile = p_ioc->profile; + + event.p_rec = (ib_pnp_rec_t*)p_rec; + event.p_user_rec = (ib_pnp_rec_t*)(((uint8_t*)p_rec) + event.rec_size); + + if( p_reg ) + { + __notify_users( &p_reg->list_item, &event ); + } + else + { + /* Report the IOC to all clients registered for IOC events. */ + cl_qlist_find_from_head( &gp_ioc_pnp->ioc_reg_list, + __notify_users, &event ); + } + cl_free( p_rec ); + + /* Report the paths for this IOC only. */ + __add_ioc_paths( p_ioc, &p_iou->path_map, p_reg ); + + AL_EXIT( AL_DBG_PNP ); +} + + +static void +__report_ioc_remove( + IN iou_node_t* const p_iou, + IN iou_ioc_t* const p_ioc ) +{ + al_pnp_ioc_event_t event; + ib_pnp_ioc_rec_t rec, user_rec; + + AL_ENTER( AL_DBG_PNP ); + + UNUSED_PARAM( p_iou ); + + cl_memclr( &rec, sizeof(ib_pnp_ioc_rec_t) ); + rec.pnp_rec.pnp_event = IB_PNP_IOC_REMOVE; + rec.pnp_rec.guid = p_ioc->profile.ioc_guid; + rec.pnp_rec.ca_guid = p_ioc->p_iou->ca_guid; + + event.rec_size = sizeof(ib_pnp_ioc_rec_t); + event.p_rec = (ib_pnp_rec_t*)&rec; + event.p_user_rec = (ib_pnp_rec_t*)&user_rec; + + /* + * Report the IOC removal to all clients registered for IOC events in + * reverse order than ADD notifications. + */ + cl_qlist_find_from_tail( &gp_ioc_pnp->ioc_reg_list, + __notify_users, &event ); + + AL_EXIT( AL_DBG_PNP ); +} + + +static void +__report_path( + IN iou_ioc_t* const p_ioc, + IN iou_path_t* const p_path, + IN ib_pnp_event_t pnp_event, + IN al_pnp_t* const p_reg OPTIONAL ) +{ + al_pnp_ioc_event_t event; + ib_pnp_ioc_path_rec_t *p_rec; + + AL_ENTER( AL_DBG_PNP ); + + CL_ASSERT( pnp_event == IB_PNP_IOC_PATH_ADD || + pnp_event == IB_PNP_IOC_PATH_REMOVE ); + + event.rec_size = sizeof(ib_pnp_ioc_path_rec_t); + event.rec_size = ROUNDUP( event.rec_size, sizeof(void*) ); + + /* + * The layout of the pnp record is as follows: + * ib_pnp_rec_t + * ib_svc_entry_t + * ib_ioc_info_t + * + * This is needed to keep the service entries contiguous to the first + * entry in the pnp record. + */ + p_rec = (ib_pnp_ioc_path_rec_t*)cl_zalloc( event.rec_size * 2 ); + if( !p_rec ) + return; + p_rec->pnp_rec.pnp_event = pnp_event; + p_rec->pnp_rec.guid = p_ioc->profile.ioc_guid; + p_rec->pnp_rec.ca_guid = p_path->ca_guid; + + p_rec->ca_guid = p_path->ca_guid; + p_rec->port_guid = p_path->port_guid; + p_rec->path = p_path->rec; + + event.p_rec = (ib_pnp_rec_t*)p_rec; + event.p_user_rec = (ib_pnp_rec_t*)(((uint8_t*)p_rec) + event.rec_size); + + /* Report the IOC to all clients registered for IOC events. */ + if( p_reg ) + { + __notify_users( &p_reg->list_item, &event ); + } + else + { + if( pnp_event == IB_PNP_IOC_PATH_ADD ) + { + cl_qlist_find_from_head( &gp_ioc_pnp->ioc_reg_list, + __notify_users, &event ); + } + else + { + cl_qlist_find_from_tail( &gp_ioc_pnp->ioc_reg_list, + __notify_users, &event ); + } + } + + cl_free( p_rec ); + + AL_EXIT( AL_DBG_PNP ); +} + + +void +ioc_pnp_process_reg( + IN cl_async_proc_item_t *p_item ) +{ + al_pnp_t *p_reg; + + AL_ENTER( AL_DBG_PNP ); + + p_reg = PARENT_STRUCT( p_item, al_pnp_t, async_item ); + + /* Add the registrant to the list. */ + switch( pnp_get_class( p_reg->pnp_class ) ) + { + case IB_PNP_IOU: + cl_qlist_insert_tail( &gp_ioc_pnp->iou_reg_list, &p_reg->list_item ); + break; + + case IB_PNP_IOC: + cl_qlist_insert_tail( &gp_ioc_pnp->ioc_reg_list, &p_reg->list_item ); + break; + + default: + CL_ASSERT( pnp_get_class( p_reg->pnp_class ) == IB_PNP_IOU || + pnp_get_class( p_reg->pnp_class ) == IB_PNP_IOC ); + } + + /* Generate all relevant events for the registration. */ + __add_ious( &gp_ioc_pnp->iou_map, &gp_ioc_pnp->iou_map, p_reg ); + + /* Notify the user that the registration is complete. */ + pnp_reg_complete( p_reg ); + + /* Release the reference taken in init_al_obj. */ + deref_al_obj( &p_reg->obj ); + + AL_EXIT( AL_DBG_PNP ); +} + + +void +ioc_pnp_process_dereg( + IN cl_async_proc_item_t *p_item ) +{ + al_pnp_t *p_reg; + + AL_ENTER( AL_DBG_PNP ); + + p_reg = PARENT_STRUCT( p_item, al_pnp_t, dereg_item ); + + /* Remove the registration information from the list. */ + switch( pnp_get_class( p_reg->pnp_class ) ) + { + case IB_PNP_IOU: + cl_qlist_remove_item( &gp_ioc_pnp->iou_reg_list, &p_reg->list_item ); + break; + + case IB_PNP_IOC: + cl_qlist_remove_item( &gp_ioc_pnp->ioc_reg_list, &p_reg->list_item ); + break; + + default: + CL_ASSERT( pnp_get_class( p_reg->pnp_class ) == IB_PNP_IOU || + pnp_get_class( p_reg->pnp_class ) == IB_PNP_IOC ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("Invalid PnP registartion type.\n") ); + } + + /* Release the reference we took for processing the deregistration. */ + deref_al_obj( &p_reg->obj ); + + AL_EXIT( AL_DBG_PNP ); +} + + + + + + diff --git a/branches/WOF2-3/core/al/kernel/al_mad_pool.c b/branches/WOF2-3/core/al/kernel/al_mad_pool.c new file mode 100644 index 00000000..252f72b8 --- /dev/null +++ b/branches/WOF2-3/core/al/kernel/al_mad_pool.c @@ -0,0 +1,961 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include "al.h" +#include "al_ci_ca.h" +#include "al_debug.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "al_mad_pool.tmh" +#endif + +#include "al_mad_pool.h" +#include "al_pd.h" +#include "al_verbs.h" +#include "ib_common.h" + + +typedef struct _mad_send +{ + al_mad_send_t mad_send; + ib_pool_handle_t h_pool; + +} mad_send_t; + + + + +typedef struct _mad_rmpp +{ + al_mad_rmpp_t mad_rmpp; + ib_pool_handle_t h_pool; + +} mad_rmpp_t; + + + +/* + * Function prototypes. + */ +static void +__destroying_pool( + IN al_obj_t* p_obj ); + +static void +__free_pool( + IN al_obj_t* p_obj ); + +static void +__destroying_pool_key( + IN al_obj_t* p_obj ); + +static void +__cleanup_pool_key( + IN al_obj_t* p_obj ); + +static void +__free_pool_key( + IN al_obj_t* p_obj ); + +static cl_status_t +__mad_send_init( + IN void* const p_object, + IN void* context, + OUT cl_pool_item_t** const pp_pool_item ); + +static cl_status_t +__mad_rmpp_init( + IN void* const p_object, + IN void* context, + OUT cl_pool_item_t** const pp_pool_item ); + + + +/* + * Create a MAD pool. + */ +ib_api_status_t +ib_create_mad_pool( + IN const ib_al_handle_t h_al, + IN const size_t min, + IN const size_t max, + IN const size_t grow_size, + OUT ib_pool_handle_t* const ph_pool ) +{ + ib_pool_handle_t h_pool; + ib_api_status_t status; + + AL_ENTER( AL_DBG_MAD_POOL ); + + if( AL_OBJ_INVALID_HANDLE( h_al, AL_OBJ_TYPE_H_AL ) ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_AL_HANDLE\n") ); + return IB_INVALID_AL_HANDLE; + } + if( !ph_pool ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + /* Validate the min and max parameters. */ + if( (min > 0) && (max > 0) && (min > max) ) + return IB_INVALID_SETTING; + + h_pool = cl_zalloc( sizeof( al_pool_t ) ); + if( !h_pool ) + return IB_INSUFFICIENT_MEMORY; + + /* Initialize the pool lists. */ + cl_qlist_init( &h_pool->key_list ); + ExInitializeNPagedLookasideList( &h_pool->mad_stack, NULL, NULL, + 0, sizeof(mad_item_t), 'dmla', 0 ); + ExInitializeNPagedLookasideList( &h_pool->mad_send_pool, NULL, NULL, + 0, sizeof(mad_send_t), 'dmla', 0 ); + ExInitializeNPagedLookasideList( &h_pool->mad_rmpp_pool, NULL, NULL, + 0, sizeof(mad_rmpp_t), 'dmla', 0 ); + + /* Initialize the pool object. */ + construct_al_obj( &h_pool->obj, AL_OBJ_TYPE_H_MAD_POOL ); + status = init_al_obj( &h_pool->obj, h_pool, TRUE, + __destroying_pool, NULL, __free_pool ); + if( status != IB_SUCCESS ) + { + __free_pool( &h_pool->obj ); + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("init_al_obj failed with status %s.\n", ib_get_err_str(status)) ); + return status; + } + + /* Attach the pool to the AL object. */ + status = attach_al_obj( &h_al->obj, &h_pool->obj ); + if( status != IB_SUCCESS ) + { + h_pool->obj.pfn_destroy( &h_pool->obj, NULL ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("attach_al_obj returned %s.\n", ib_get_err_str(status)) ); + return status; + } + + /* Save the pool parameters. Set grow_size to min for initialization. */ + h_pool->max = max; + h_pool->grow_size = min; + + /* Save the grow_size for subsequent allocations. */ + h_pool->grow_size = grow_size; + + /* Return the pool handle. */ + *ph_pool = h_pool; + + /* Release the reference taken in init_al_obj. */ + deref_al_obj( &h_pool->obj ); + + AL_EXIT( AL_DBG_MAD_POOL ); + return IB_SUCCESS; +} + + + +/* + * Pre-destory the pool. + */ +static void +__destroying_pool( + IN al_obj_t* p_obj ) +{ + ib_pool_handle_t h_pool; + ib_al_handle_t h_al; + + AL_ENTER( AL_DBG_MAD_POOL ); + + CL_ASSERT( p_obj ); + h_pool = PARENT_STRUCT( p_obj, al_pool_t, obj ); + + /* Get the AL instance of this MAD pool. */ + p_obj = h_pool->obj.p_parent_obj; + h_al = PARENT_STRUCT( p_obj, ib_al_t, obj ); + + /* Deregister this MAD pool from all protection domains. */ + al_dereg_pool( h_al, h_pool ); + + AL_EXIT( AL_DBG_MAD_POOL ); +} + + + +/* + * Free the pool. + */ +static void +__free_pool( + IN al_obj_t* p_obj ) +{ + ib_pool_handle_t h_pool; + + CL_ASSERT( p_obj ); + h_pool = PARENT_STRUCT( p_obj, al_pool_t, obj ); + + ExDeleteNPagedLookasideList( &h_pool->mad_send_pool ); + ExDeleteNPagedLookasideList( &h_pool->mad_rmpp_pool ); + ExDeleteNPagedLookasideList( &h_pool->mad_stack ); + destroy_al_obj( &h_pool->obj ); + cl_free( h_pool ); +} + + + +/* + * Destory a MAD pool. + */ +ib_api_status_t +ib_destroy_mad_pool( + IN const ib_pool_handle_t h_pool ) +{ + cl_list_item_t* p_array_item; + al_obj_t* p_obj; + boolean_t busy; + + AL_ENTER( AL_DBG_MAD_POOL ); + + if( AL_OBJ_INVALID_HANDLE( h_pool, AL_OBJ_TYPE_H_MAD_POOL ) ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_HANDLE\n") ); + return IB_INVALID_HANDLE; + } + + /* Verify that all send handles and MAD elements are in pool. */ + cl_spinlock_acquire( &h_pool->obj.lock ); + busy = ( h_pool->obj.ref_cnt > 1 ); + for( p_array_item = cl_qlist_head( &h_pool->obj.obj_list ); + p_array_item != cl_qlist_end( &h_pool->obj.obj_list ) && !busy; + p_array_item = cl_qlist_next( p_array_item ) ) + { + p_obj = PARENT_STRUCT( p_array_item, al_obj_t, pool_item ); + busy = ( p_obj->ref_cnt > 1 ); + } + cl_spinlock_release( &h_pool->obj.lock ); + + /* Return an error if the pool is busy. */ + if( busy ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("h_pool (0x%p) is busy!.\n", h_pool) ); + return IB_RESOURCE_BUSY; + } + + ref_al_obj( &h_pool->obj ); + h_pool->obj.pfn_destroy( &h_pool->obj, NULL ); + + AL_EXIT( AL_DBG_MAD_POOL ); + return IB_SUCCESS; +} + + + +/* + * Register a MAD pool with a protection domain. + */ +ib_api_status_t +ib_reg_mad_pool( + IN const ib_pool_handle_t h_pool, + IN const ib_pd_handle_t h_pd, + OUT ib_pool_key_t* const pp_pool_key ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_MAD_POOL ); + + if( AL_OBJ_INVALID_HANDLE( h_pool, AL_OBJ_TYPE_H_MAD_POOL ) ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_HANDLE\n") ); + return IB_INVALID_HANDLE; + } + /* Alias keys require an alias PD. */ + if( AL_OBJ_INVALID_HANDLE( h_pd, AL_OBJ_TYPE_H_PD ) ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PD_HANDLE\n") ); + return IB_INVALID_PD_HANDLE; + } + + status = reg_mad_pool( h_pool, h_pd, pp_pool_key ); + /* Release the reference taken in init_al_obj. */ + if( status == IB_SUCCESS ) + deref_al_obj( &(*pp_pool_key)->obj ); + + AL_EXIT( AL_DBG_MAD_POOL ); + return status; +} + + +ib_api_status_t +reg_mad_pool( + IN const ib_pool_handle_t h_pool, + IN const ib_pd_handle_t h_pd, + OUT ib_pool_key_t* const pp_pool_key ) +{ + al_pool_key_t* p_pool_key; + ib_al_handle_t h_al; + ib_api_status_t status; + al_key_type_t key_type; + + AL_ENTER( AL_DBG_MAD_POOL ); + + if( !pp_pool_key ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + /* Set the type of key to create. */ + if( h_pd->type != IB_PDT_ALIAS ) + key_type = AL_KEY_NORMAL; + else + key_type = AL_KEY_ALIAS; + + /* Allocate a pool key structure. */ + p_pool_key = cl_zalloc( sizeof( al_pool_key_t ) ); + if( !p_pool_key ) + return IB_INSUFFICIENT_MEMORY; + + /* Initialize the pool key. */ + construct_al_obj( &p_pool_key->obj, AL_OBJ_TYPE_H_POOL_KEY ); + p_pool_key->type = key_type; + p_pool_key->h_pool = h_pool; + + /* Initialize the pool key object. */ + status = init_al_obj( &p_pool_key->obj, p_pool_key, TRUE, + __destroying_pool_key, __cleanup_pool_key, __free_pool_key ); + if( status != IB_SUCCESS ) + { + __free_pool_key( &p_pool_key->obj ); + + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("init_al_obj failed with status %s.\n", ib_get_err_str(status)) ); + return status; + } + + /* Register the pool on the protection domain. */ + if( key_type == AL_KEY_NORMAL ) + { + ib_phys_create_t phys_create; + ib_phys_range_t phys_range; + uint64_t vaddr; + net32_t rkey; + + /* Register all of physical memory. */ + phys_create.length = 0xFFFFFFFFFFFFFFFF; + phys_create.num_ranges = 1; + phys_create.range_array = &phys_range; + phys_create.buf_offset = 0; + phys_create.hca_page_size = PAGE_SIZE; + phys_create.access_ctrl = IB_AC_LOCAL_WRITE; + phys_range.base_addr = 0; + phys_range.size = 0xFFFFFFFFFFFFFFFF; + vaddr = 0; + status = ib_reg_phys( h_pd, &phys_create, &vaddr, + &p_pool_key->lkey, &rkey, &p_pool_key->h_mr ); + if( status != IB_SUCCESS ) + { + p_pool_key->obj.pfn_destroy( &p_pool_key->obj, NULL ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("ib_reg_phys returned %s\n", ib_get_err_str( status )) ); + return status; + } + + /* Chain the pool key onto the pool. */ + cl_spinlock_acquire( &h_pool->obj.lock ); + cl_qlist_insert_tail( &h_pool->key_list, &p_pool_key->pool_item ); + cl_spinlock_release( &h_pool->obj.lock ); + } + + /* + * Attach to the pool after we register the memory so that PD destruction + * will cleanup the pool key before its memory region. + */ + status = attach_al_obj( &h_pd->obj, &p_pool_key->obj ); + if( status != IB_SUCCESS ) + { + p_pool_key->obj.pfn_destroy( &p_pool_key->obj, NULL ); + + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("attach_al_obj returned %s\n", ib_get_err_str(status)) ); + return status; + } + + /* From the PD, get the AL handle of the pool_key. */ + h_al = h_pd->obj.h_al; + + /* Add this pool_key to the AL instance. */ + al_insert_key( h_al, p_pool_key ); + + ref_al_obj( &h_pool->obj ); + + /* + * Take a reference on the global pool_key for this CA, if it exists. + * Note that the pool_key does not exist for the global MAD pool in + * user-mode, as that MAD pool never registers memory on a PD. + */ + /* TODO: Is the pool_key check here needed since this is a kernel-only implementation? */ + if( key_type == AL_KEY_ALIAS && h_pd->obj.p_ci_ca->pool_key ) + { + ref_al_obj( &h_pd->obj.p_ci_ca->pool_key->obj ); + p_pool_key->pool_key = h_pd->obj.p_ci_ca->pool_key; + } + + /* Return the pool key. */ + *pp_pool_key = (ib_pool_key_t)p_pool_key; + + AL_EXIT( AL_DBG_MAD_POOL ); + return IB_SUCCESS; +} + + +/* + * The destroying callback releases the memory registration. This is needed + * to maintain the destroy semantics, where the pool key's destruction is + * async, but the MAD registrations are sync. This means that all memory + * registered on a pool key is deregistered before the pool key leaves the + * destroy call. + */ +static void +__destroying_pool_key( + IN al_obj_t* p_obj ) +{ + al_pool_key_t* p_pool_key; + + CL_ASSERT( p_obj ); + p_pool_key = PARENT_STRUCT( p_obj, al_pool_key_t, obj ); + + /* Remove this pool_key from the AL instance. */ + al_remove_key( p_pool_key ); + if( p_pool_key->h_mr ) + ib_dereg_mr( p_pool_key->h_mr ); + + p_pool_key->lkey = 0; +} + + +/* + * Release all references on objects that were needed by the pool key. + */ +static void +__cleanup_pool_key( + IN al_obj_t* p_obj ) +{ + cl_list_item_t *p_list_item, *p_next_item; + ib_mad_element_t *p_mad_element_list, *p_last_mad_element; + al_mad_element_t *p_mad; + ib_api_status_t status; + al_pool_key_t* p_pool_key; + + CL_ASSERT( p_obj ); + p_pool_key = PARENT_STRUCT( p_obj, al_pool_key_t, obj ); + + CL_ASSERT( !p_pool_key->mad_cnt ); + + /* Search for any outstanding MADs associated with the given pool key. */ + if( p_pool_key->mad_cnt ) + { + p_mad_element_list = p_last_mad_element = NULL; + + cl_spinlock_acquire( &p_pool_key->obj.h_al->mad_lock ); + for( p_list_item = cl_qlist_head( &p_pool_key->obj.h_al->mad_list ); + p_list_item != cl_qlist_end( &p_pool_key->obj.h_al->mad_list ); + p_list_item = p_next_item ) + { + p_next_item = cl_qlist_next( p_list_item ); + p_mad = PARENT_STRUCT( p_list_item, al_mad_element_t, al_item ); + + if( p_mad->pool_key != p_pool_key ) continue; + + /* Build the list of MADs to be returned to pool. */ + if( p_last_mad_element ) + p_last_mad_element->p_next = &p_mad->element; + else + p_mad_element_list = &p_mad->element; + + p_last_mad_element = &p_mad->element; + p_last_mad_element->p_next = NULL; + } + cl_spinlock_release( &p_pool_key->obj.h_al->mad_lock ); + + /* Return any outstanding MADs to the pool. */ + if( p_mad_element_list ) + { + status = ib_put_mad( p_mad_element_list ); + if( status != IB_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("ib_put_mad failed with status %s, continuing.\n", + ib_get_err_str(status)) ); + } + } + } + + /* + * Remove the pool key from the pool to prevent further registrations + * against this pool. + */ + if( p_pool_key->type == AL_KEY_NORMAL ) + { + cl_spinlock_acquire( &p_pool_key->h_pool->obj.lock ); + cl_qlist_remove_item( &p_pool_key->h_pool->key_list, + &p_pool_key->pool_item ); + cl_spinlock_release( &p_pool_key->h_pool->obj.lock ); + } + + deref_al_obj( &p_pool_key->h_pool->obj ); + p_pool_key->h_pool = NULL; + if( p_pool_key->pool_key ) + deref_al_obj( &p_pool_key->pool_key->obj ); +} + + + +/* + * Free a pool key. + */ +static void +__free_pool_key( + IN al_obj_t* p_obj ) +{ + al_pool_key_t* p_pool_key; + + CL_ASSERT( p_obj ); + p_pool_key = PARENT_STRUCT( p_obj, al_pool_key_t, obj ); + + destroy_al_obj( &p_pool_key->obj ); + cl_free( p_pool_key ); +} + + +/* + * Deregister a MAD pool from a protection domain. Only normal pool_keys + * can be destroyed using this routine. + */ +ib_api_status_t +ib_dereg_mad_pool( + IN const ib_pool_key_t pool_key ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_MAD_POOL ); + + if( AL_OBJ_INVALID_HANDLE( pool_key, AL_OBJ_TYPE_H_POOL_KEY ) ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + ref_al_obj( &pool_key->obj ); + status = dereg_mad_pool( pool_key, AL_KEY_NORMAL ); + + if( status != IB_SUCCESS ) + deref_al_obj( &pool_key->obj ); + + AL_EXIT( AL_DBG_MAD_POOL ); + return status; +} + + + +/* + * Deregister a MAD pool from a protection domain. + */ +ib_api_status_t +dereg_mad_pool( + IN const ib_pool_key_t pool_key, + IN const al_key_type_t expected_type ) +{ + AL_ENTER( AL_DBG_MAD_POOL ); + + if( pool_key->type != expected_type ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + /* Check mad_cnt to see if MADs are still outstanding. */ + //if( pool_key->mad_cnt ) + //{ + // AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_MAD_POOL, ("IB_RESOURCE_BUSY\n") ); + // return IB_RESOURCE_BUSY; + //} + + pool_key->obj.pfn_destroy( &pool_key->obj, NULL ); + + AL_EXIT( AL_DBG_MAD_POOL ); + return IB_SUCCESS; +} + + + +/* + * Obtain a MAD element from the pool. + */ +static ib_api_status_t +__get_mad_element( + IN const ib_pool_key_t pool_key, + OUT al_mad_element_t** pp_mad_element ) +{ + mad_item_t* p_mad_item; + net32_t lkey; + + AL_ENTER( AL_DBG_MAD_POOL ); + + CL_ASSERT( pool_key ); + CL_ASSERT( pp_mad_element ); + + /* Obtain a MAD item from the stack. */ + p_mad_item = (mad_item_t*)ExAllocateFromNPagedLookasideList( + &pool_key->h_pool->mad_stack ); + if( !p_mad_item ) + return IB_INSUFFICIENT_RESOURCES; + + p_mad_item->pool_key = pool_key; + + if( pool_key->type == AL_KEY_NORMAL ) + lkey = pool_key->lkey; + else + lkey = pool_key->pool_key->lkey; + + CL_ASSERT( ADDRESS_AND_SIZE_TO_SPAN_PAGES( + p_mad_item->al_mad_element.mad_buf, MAD_BLOCK_GRH_SIZE ) == 1 ); + + /* Clear the element. */ + cl_memclr( &p_mad_item->al_mad_element, sizeof(al_mad_element_t) ); + + /* Initialize the receive data segment information. */ + p_mad_item->al_mad_element.grh_ds.vaddr = + cl_get_physaddr( p_mad_item->al_mad_element.mad_buf ); + p_mad_item->al_mad_element.grh_ds.length = MAD_BLOCK_GRH_SIZE; + p_mad_item->al_mad_element.grh_ds.lkey = lkey; + + /* Initialize the send data segment information. */ + p_mad_item->al_mad_element.mad_ds.vaddr = + p_mad_item->al_mad_element.grh_ds.vaddr + sizeof(ib_grh_t); + p_mad_item->al_mad_element.mad_ds.length = MAD_BLOCK_SIZE; + p_mad_item->al_mad_element.mad_ds.lkey = lkey; + + /* Initialize grh */ + p_mad_item->al_mad_element.element.p_grh = + (ib_grh_t*)p_mad_item->al_mad_element.mad_buf; + + /* Hold a reference on the pool key while a MAD element is removed. */ + ref_al_obj( &pool_key->obj ); + cl_atomic_inc( &pool_key->mad_cnt ); + + p_mad_item->al_mad_element.pool_key = (ib_pool_key_t)pool_key; + /* Return the MAD element. */ + *pp_mad_element = &p_mad_item->al_mad_element; + + AL_EXIT( AL_DBG_MAD_POOL ); + return IB_SUCCESS; +} + + + +/* + * Return a MAD element to the pool. + */ +static void +__put_mad_element( + IN al_mad_element_t* p_mad_element ) +{ + mad_item_t* p_mad_item; + ib_pool_key_t pool_key; + + CL_ASSERT( p_mad_element ); + p_mad_item = PARENT_STRUCT( p_mad_element, mad_item_t, al_mad_element ); + pool_key = p_mad_item->pool_key; + CL_ASSERT( pool_key ); + CL_ASSERT( pool_key->h_pool ); + + /* Clear the MAD buffer. */ + cl_memclr( p_mad_element->mad_buf, MAD_BLOCK_GRH_SIZE ); + p_mad_element->element.p_next = NULL; + + /* Return the MAD element to the pool. */ + ExFreeToNPagedLookasideList( &pool_key->h_pool->mad_stack, p_mad_item ); + + cl_atomic_dec( &pool_key->mad_cnt ); + deref_al_obj( &pool_key->obj ); +} + + + +ib_mad_send_handle_t +get_mad_send( + IN const al_mad_element_t *p_mad_element ) +{ + mad_item_t* p_mad_item; + mad_send_t *p_mad_send; + + CL_ASSERT( p_mad_element ); + + /* Get a handle to the pool. */ + p_mad_item = PARENT_STRUCT( p_mad_element, mad_item_t, al_mad_element ); + CL_ASSERT( p_mad_item->pool_key ); + CL_ASSERT( p_mad_item->pool_key->h_pool ); + + p_mad_send = ExAllocateFromNPagedLookasideList( + &p_mad_item->pool_key->h_pool->mad_send_pool ); + if( !p_mad_send ) + return NULL; + + p_mad_send->mad_send.canceled = FALSE; + p_mad_send->mad_send.p_send_mad = NULL; + p_mad_send->mad_send.p_resp_mad = NULL; + p_mad_send->mad_send.h_av = NULL; + p_mad_send->mad_send.retry_cnt = 0; + p_mad_send->mad_send.retry_time = 0; + p_mad_send->mad_send.delay = 0; + p_mad_send->h_pool = p_mad_item->pool_key->h_pool; + + ref_al_obj( &p_mad_item->pool_key->h_pool->obj ); + return &p_mad_send->mad_send; +} + + + +void +put_mad_send( + IN ib_mad_send_handle_t h_mad_send ) +{ + mad_send_t *p_mad_send; + ib_pool_handle_t h_pool; + + p_mad_send = PARENT_STRUCT( h_mad_send, mad_send_t, mad_send ); + h_pool = p_mad_send->h_pool; + + ExFreeToNPagedLookasideList( &h_pool->mad_send_pool, p_mad_send ); + deref_al_obj( &h_pool->obj ); +} + + + +al_mad_rmpp_t* +get_mad_rmpp( + IN const al_mad_element_t *p_mad_element ) +{ + mad_item_t *p_mad_item; + mad_rmpp_t *p_mad_rmpp; + + CL_ASSERT( p_mad_element ); + + /* Get a handle to the pool. */ + p_mad_item = PARENT_STRUCT( p_mad_element, mad_item_t, al_mad_element ); + CL_ASSERT( p_mad_item->pool_key ); + CL_ASSERT( p_mad_item->pool_key->h_pool ); + + p_mad_rmpp = ExAllocateFromNPagedLookasideList( + &p_mad_item->pool_key->h_pool->mad_rmpp_pool ); + if( !p_mad_rmpp ) + return NULL; + + p_mad_rmpp->h_pool = p_mad_item->pool_key->h_pool; + + ref_al_obj( &p_mad_item->pool_key->h_pool->obj ); + return &p_mad_rmpp->mad_rmpp; +} + + + +void +put_mad_rmpp( + IN al_mad_rmpp_t* h_mad_rmpp ) +{ + mad_rmpp_t *p_mad_rmpp; + ib_pool_handle_t h_pool; + + p_mad_rmpp = PARENT_STRUCT( h_mad_rmpp, mad_rmpp_t, mad_rmpp ); + + h_pool = p_mad_rmpp->h_pool; + + ExFreeToNPagedLookasideList( &h_pool->mad_rmpp_pool, p_mad_rmpp ); + deref_al_obj( &h_pool->obj ); +} + + + +ib_api_status_t +ib_get_mad( + IN const ib_pool_key_t pool_key, + IN const size_t buf_size, + OUT ib_mad_element_t **pp_mad_element ) +{ + al_mad_element_t* p_mad; + ib_api_status_t status; + + AL_ENTER( AL_DBG_MAD_POOL ); + + if( AL_OBJ_INVALID_HANDLE( pool_key, AL_OBJ_TYPE_H_POOL_KEY ) ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + if( !buf_size || !pp_mad_element ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + status = __get_mad_element( pool_key, &p_mad ); + if( status != IB_SUCCESS ) + { + AL_EXIT( AL_DBG_MAD_POOL ); + return status; + } + + /* Set the user accessible buffer. */ + if( buf_size <= MAD_BLOCK_SIZE ) + { + /* Use the send buffer for 256 byte MADs. */ + p_mad->element.p_mad_buf = (ib_mad_t*)(p_mad->mad_buf + sizeof(ib_grh_t)); + } + else if( buf_size >= 0xFFFFFFFF ) + { + __put_mad_element( p_mad ); + return IB_INVALID_SETTING; + } + else + { + /* Allocate a new buffer for the MAD. */ + p_mad->p_al_mad_buf = cl_zalloc( buf_size ); + if( !p_mad->p_al_mad_buf ) + { + __put_mad_element( p_mad ); + AL_EXIT( AL_DBG_MAD_POOL ); + return IB_INSUFFICIENT_MEMORY; + } + p_mad->element.p_mad_buf = p_mad->p_al_mad_buf; + } + p_mad->element.size = (uint32_t)buf_size; + + /* Track the MAD element with the requesting AL instance. */ + al_insert_mad( pool_key->h_al, p_mad ); + + /* Return the MAD element to the client. */ + *pp_mad_element = &p_mad->element; + + AL_EXIT( AL_DBG_MAD_POOL ); + return IB_SUCCESS; +} + + + +ib_api_status_t +ib_put_mad( + IN const ib_mad_element_t* p_mad_element_list ) +{ + al_mad_element_t* p_mad; + + if( !p_mad_element_list ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + while( p_mad_element_list ) + { + p_mad = PARENT_STRUCT( p_mad_element_list, al_mad_element_t, element ); + p_mad_element_list = p_mad_element_list->p_next; + + /* Deallocate any buffers allocated for the user. */ + if( p_mad->p_al_mad_buf ) + { + cl_free( p_mad->p_al_mad_buf ); + p_mad->p_al_mad_buf = NULL; + } + + /* See if the MAD has already been returned to the MAD pool. */ + CL_ASSERT( p_mad->h_al ); + + /* Remove the MAD element from the owning AL instance. */ + al_remove_mad( p_mad ); + + /* Return the MAD element to the pool. */ + __put_mad_element( p_mad ); + } + + return IB_SUCCESS; +} + + + +/* + * Resize the data buffer associated with a MAD element. + */ +ib_api_status_t +al_resize_mad( + OUT ib_mad_element_t *p_mad_element, + IN const size_t buf_size ) +{ + al_mad_element_t *p_al_element; + ib_mad_t *p_new_buf; + + CL_ASSERT( p_mad_element ); + + /* We only support growing the buffer for now. */ + CL_ASSERT( buf_size > p_mad_element->size ); + + /* Cap the size. */ + if( buf_size >= 0xFFFFFFFF ) + return IB_INVALID_SETTING; + + p_al_element = PARENT_STRUCT( p_mad_element, al_mad_element_t, element ); + + /* Allocate a new buffer. */ + p_new_buf = cl_malloc( buf_size ); + if( !p_new_buf ) + return IB_INSUFFICIENT_MEMORY; + + /* Copy the existing buffer's data into the new buffer. */ + cl_memcpy( p_new_buf, p_mad_element->p_mad_buf, p_mad_element->size ); + cl_memclr( (uint8_t*)p_new_buf + p_mad_element->size, + buf_size - p_mad_element->size ); + + /* Update the MAD element to use the new buffer. */ + p_mad_element->p_mad_buf = p_new_buf; + p_mad_element->size = (uint32_t)buf_size; + + /* Free any old buffer. */ + if( p_al_element->p_al_mad_buf ) + cl_free( p_al_element->p_al_mad_buf ); + p_al_element->p_al_mad_buf = p_new_buf; + + return IB_SUCCESS; +} + diff --git a/branches/WOF2-3/core/al/kernel/al_mgr.c b/branches/WOF2-3/core/al/kernel/al_mgr.c new file mode 100644 index 00000000..313a8404 --- /dev/null +++ b/branches/WOF2-3/core/al/kernel/al_mgr.c @@ -0,0 +1,626 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "al.h" +#include "al_cm_cep.h" +#include "al_debug.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "al_mgr.tmh" +#endif + +#include "al_dm.h" +#include "al_mad_pool.h" +#include "al_mcast.h" +#include "al_mgr.h" +#include "al_pnp.h" +#include "al_ioc_pnp.h" +#include "al_query.h" +#include "al_res_mgr.h" +#include "al_smi.h" +#include "ib_common.h" + +#ifndef CL_KERNEL +#include "ual_mgr.h" +#endif + + +#define AL_HDL_VECTOR_MIN 64 +#define AL_HDL_VECTOR_GROW 64 + + +static void +__free_al_mgr( + IN al_obj_t *p_obj ); + +void +free_al( + IN al_obj_t *p_obj ); + + + +ib_api_status_t +create_al_mgr() +{ + cl_status_t cl_status; + ib_api_status_t status; + + AL_ENTER( AL_DBG_MGR ); + + CL_ASSERT( !gp_al_mgr ); + + gp_al_mgr = cl_zalloc( sizeof( al_mgr_t ) ); + if( !gp_al_mgr ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("cl_zalloc failed.\n") ); + return IB_INSUFFICIENT_MEMORY; + } + + /* Construct the AL manager components. */ + cl_qlist_init( &gp_al_mgr->ci_ca_list ); + cl_qlist_init( &gp_al_mgr->al_obj_list ); + cl_spinlock_construct( &gp_al_mgr->lock ); + + /* Initialize the AL management components. */ + construct_al_obj( &gp_al_mgr->obj, AL_OBJ_TYPE_AL_MGR ); + status = init_al_obj( &gp_al_mgr->obj, gp_al_mgr, FALSE, + NULL, NULL, __free_al_mgr ); + if( status != IB_SUCCESS ) + { + __free_al_mgr( &gp_al_mgr->obj ); + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("init_al_obj failed, status = 0x%x.\n", status) ); + return status; + } + + cl_status = cl_spinlock_init( &gp_al_mgr->lock ); + if( cl_status != CL_SUCCESS ) + { + gp_al_mgr->obj.pfn_destroy( &gp_al_mgr->obj, NULL ); + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("cl_spinlock_init failed\n") ); + return ib_convert_cl_status( cl_status ); + } + + /* We should be able to open AL now. */ + status = ib_open_al( &gh_al ); + if( status != IB_SUCCESS ) + { + gp_al_mgr->obj.pfn_destroy( &gp_al_mgr->obj, NULL ); + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("ib_open_al failed, status = 0x%x.\n", status) ); + return status; + } + + /* + * Initialize the AL management services. + * Create the PnP manager first - the other services depend on PnP. + */ + status = create_pnp( &gp_al_mgr->obj ); + if( status != IB_SUCCESS ) + { + gp_al_mgr->obj.pfn_destroy( &gp_al_mgr->obj, NULL ); + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("al_pnp_create failed with %s.\n", ib_get_err_str(status)) ); + return status; + } + + /* Create the global AL MAD pool. */ + status = ib_create_mad_pool( gh_al, 0, 0, 64, &gh_mad_pool ); + if( status != IB_SUCCESS ) + { + gp_al_mgr->obj.pfn_destroy( &gp_al_mgr->obj, NULL ); + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("ib_create_mad_pool failed with %s.\n", ib_get_err_str(status)) ); + return status; + } + + /* Initialize the AL resource manager. */ + status = create_res_mgr( &gp_al_mgr->obj ); + if( status != IB_SUCCESS ) + { + gp_al_mgr->obj.pfn_destroy( &gp_al_mgr->obj, NULL ); + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("create_res_mgr failed with %s.\n", ib_get_err_str(status)) ); + return status; + } + + /* Initialize the AL special QP manager. */ + status = create_spl_qp_mgr( &gp_al_mgr->obj ); + if( status != IB_SUCCESS ) + { + gp_al_mgr->obj.pfn_destroy( &gp_al_mgr->obj, NULL ); + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("create_spl_qp_mgr failed with %s.\n", ib_get_err_str(status)) ); + return status; + } + + /* Initialize the AL SA request manager. */ + status = create_sa_req_mgr( &gp_al_mgr->obj ); + if( status != IB_SUCCESS ) + { + gp_al_mgr->obj.pfn_destroy( &gp_al_mgr->obj, NULL ); + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("create_sa_req_mgr failed, status = 0x%x.\n", status) ); + return status; + } + + /* Initialize CM */ + status = create_cep_mgr( &gp_al_mgr->obj ); + if( status != IB_SUCCESS ) + { + gp_al_mgr->obj.pfn_destroy( &gp_al_mgr->obj, NULL ); + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("create_cm_mgr failed, status = 0x%x.\n", status) ); + return status; + } + + /* Initialize the AL device management agent. */ + +/* + Disable support of DM agent. + + status = create_dm_agent( &gp_al_mgr->obj ); + if( status != IB_SUCCESS ) + { + gp_al_mgr->obj.pfn_destroy( &gp_al_mgr->obj, NULL ); + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("create_dm_agent failed, status = 0x%x.\n", status) ); + return status; + } +*/ + status = create_ioc_pnp( &gp_al_mgr->obj ); + if( status != IB_SUCCESS ) + { + gp_al_mgr->obj.pfn_destroy( &gp_al_mgr->obj, NULL ); + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("create_ioc_pnp failed, status = 0x%x.\n", status) ); + return status; + } + + /* Release the reference taken in init_al_obj. */ + deref_al_obj( &gp_al_mgr->obj ); + + AL_EXIT( AL_DBG_MGR ); + return IB_SUCCESS; +} + + + +static void +__free_al_mgr( + IN al_obj_t *p_obj ) +{ + CL_ASSERT( p_obj == &gp_al_mgr->obj ); + + /* + * We need to destroy the AL object before the spinlock, since + * destroying the AL object will try to acquire the spinlock. + */ + destroy_al_obj( p_obj ); + + /* Verify that the object list is empty. */ + print_al_objs( NULL ); + + cl_spinlock_destroy( &gp_al_mgr->lock ); + cl_free( gp_al_mgr ); + gp_al_mgr = NULL; +} + + + +/* + * Register a new CI CA with the access layer. + */ +ib_api_status_t +ib_register_ca( + IN const ci_interface_t* p_ci, + IN const PDEVICE_OBJECT p_hca_dev, + IN const PDEVICE_OBJECT p_fdo + ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_MGR ); + + if( !p_ci ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + CL_ASSERT( !find_ci_ca( p_ci->guid ) ); + + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MGR, + ("CA guid %I64x.\n", p_ci->guid) ); + + /* Check the channel interface verbs version. */ + if( p_ci->version != VERBS_VERSION ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("Unsupported channel interface version, " + "expected = 0x%x, actual = 0x%x.\n", + VERBS_VERSION, p_ci->version) ); + return IB_UNSUPPORTED; + } + + /* Construct and initialize the CA structure. */ + status = create_ci_ca( &gp_al_mgr->obj, p_ci, p_hca_dev, p_fdo ); + if( status != IB_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("al_mgr_ca_init failed.\n") ); + return status; + } + + AL_EXIT( AL_DBG_MGR ); + return status; +} + + + +/* + * Process the removal of a CI CA from the system. + */ +ib_api_status_t +ib_deregister_ca( + IN const net64_t ca_guid ) +{ + al_ci_ca_t *p_ci_ca; + + AL_ENTER( AL_DBG_MGR ); + + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MGR, + ("Deregistering CA guid %I64x.\n", ca_guid) ); + + /* Locate the CA. */ + cl_spinlock_acquire( &gp_al_mgr->obj.lock ); + p_ci_ca = find_ci_ca( ca_guid ); + cl_spinlock_release( &gp_al_mgr->obj.lock ); + + if( !p_ci_ca ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("CA not found.\n") ); + return IB_NOT_FOUND; + } + + /* + * TODO: Before destroying, do a query PnP call and return IB_BUSY + * as needed. + */ + /* Destroy the CI CA. */ + ref_al_obj( &p_ci_ca->obj ); + p_ci_ca->obj.pfn_destroy( &p_ci_ca->obj, NULL ); + + AL_EXIT( AL_DBG_MGR ); + return IB_SUCCESS; +} + + +/* + * Initialize a proxy entry used to map user-mode to kernel-mode resources. + */ +static cl_status_t +__init_hdl( + IN void* const p_element, + IN void* context ) +{ + al_handle_t *p_h; + + p_h = (al_handle_t*)p_element; + + /* Chain free entries one after another. */ + p_h->p_obj = (al_obj_t*)(uintn_t)++(((ib_al_handle_t)context)->free_hdl); + p_h->type = AL_OBJ_TYPE_UNKNOWN; + + return CL_SUCCESS; +} + + +/* + * Create a new instance of the access layer. This function is placed here + * to prevent sharing the implementation with user-mode. + */ +ib_api_status_t +ib_open_al( + OUT ib_al_handle_t* const ph_al ) +{ + ib_al_handle_t h_al; + ib_api_status_t status; + cl_status_t cl_status; + + AL_ENTER( AL_DBG_MGR ); + + if( !ph_al ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + /* Allocate an access layer instance. */ + h_al = cl_zalloc( sizeof( ib_al_t ) ); + if( !h_al ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("cl_zalloc failed\n") ); + return IB_INSUFFICIENT_MEMORY; + } + + /* Construct the instance. */ + construct_al_obj( &h_al->obj, AL_OBJ_TYPE_H_AL ); + cl_spinlock_construct( &h_al->mad_lock ); + cl_qlist_init( &h_al->mad_list ); + cl_qlist_init( &h_al->key_list ); + cl_qlist_init( &h_al->query_list ); + cl_qlist_init( &h_al->cep_list ); + + cl_vector_construct( &h_al->hdl_vector ); + + cl_status = cl_spinlock_init( &h_al->mad_lock ); + if( cl_status != CL_SUCCESS ) + { + free_al( &h_al->obj ); + AL_EXIT( AL_DBG_MGR ); + return ib_convert_cl_status( cl_status ); + } + + /* Initialize the handle vector. */ + cl_status = cl_vector_init( &h_al->hdl_vector, AL_HDL_VECTOR_MIN, + AL_HDL_VECTOR_GROW, sizeof(al_handle_t), __init_hdl, NULL, h_al ); + if( cl_status != CL_SUCCESS ) + { + free_al( &h_al->obj ); + AL_EXIT( AL_DBG_MGR ); + return ib_convert_cl_status( cl_status ); + } + h_al->free_hdl = 1; + + /* Initialize the base object. */ + status = init_al_obj( &h_al->obj, NULL, FALSE, + destroying_al, NULL, free_al ); + if( status != IB_SUCCESS ) + { + free_al( &h_al->obj ); + AL_EXIT( AL_DBG_MGR ); + return status; + } + status = attach_al_obj( &gp_al_mgr->obj, &h_al->obj ); + if( status != IB_SUCCESS ) + { + h_al->obj.pfn_destroy( &h_al->obj, NULL ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("attach_al_obj returned %s.\n", ib_get_err_str(status)) ); + return status; + } + + /* + * Self reference the AL instance so that all attached objects + * insert themselve in the instance's handle manager automatically. + */ + h_al->obj.h_al = h_al; + + *ph_al = h_al; + + /* Release the reference taken in init_al_obj. */ + deref_al_obj( &h_al->obj ); + + AL_EXIT( AL_DBG_MGR ); + return IB_SUCCESS; +} + + +uint64_t +al_hdl_insert( + IN const ib_al_handle_t h_al, + IN void* const p_obj, + IN const uint32_t type ) +{ + cl_status_t status; + size_t size; + uint64_t hdl; + al_handle_t *p_h; + + AL_ENTER( AL_DBG_HDL ); + + size = cl_vector_get_size( &h_al->hdl_vector ); + hdl = h_al->free_hdl; + if( h_al->free_hdl == size ) + { + /* Grow the vector pool. */ + status = + cl_vector_set_size( &h_al->hdl_vector, size + AL_HDL_VECTOR_GROW ); + if( status != CL_SUCCESS ) + { + AL_EXIT( AL_DBG_HDL ); + return AL_INVALID_HANDLE; + } + /* + * Return the the start of the free list since the + * entry initializer incremented it. + */ + h_al->free_hdl = size; + } + + /* Get the next free entry. */ + p_h = (al_handle_t*)cl_vector_get_ptr( &h_al->hdl_vector, (size_t)hdl ); + + /* Update the next entry index. */ + h_al->free_hdl = (size_t)p_h->p_obj; + + /* Update the entry. */ + p_h->type = type; + p_h->p_obj = (al_obj_t*)p_obj; + + return hdl; +} + + +void +al_hdl_free( + IN const ib_al_handle_t h_al, + IN const uint64_t hdl ) +{ + al_handle_t *p_h; + + CL_ASSERT( hdl < cl_vector_get_size( &h_al->hdl_vector ) ); + + p_h = (al_handle_t*)cl_vector_get_ptr( &h_al->hdl_vector, (size_t)hdl ); + p_h->type = AL_OBJ_TYPE_UNKNOWN; + p_h->p_obj = (al_obj_t*)(uintn_t)h_al->free_hdl; + h_al->free_hdl = hdl; +} + + +al_obj_t* +al_hdl_ref( + IN const ib_al_handle_t h_al, + IN const uint64_t hdl, + IN const uint32_t type ) +{ + al_handle_t *p_h; + al_obj_t *p_obj; + + CL_ASSERT( type != AL_OBJ_TYPE_H_MAD && type != AL_OBJ_TYPE_H_CONN ); + + cl_spinlock_acquire( &h_al->obj.lock ); + + /* Validate index. */ + if( hdl >= cl_vector_get_size( &h_al->hdl_vector ) ) + { + cl_spinlock_release( &h_al->obj.lock ); + return NULL; + } + + /* Get the specified entry. */ + p_h = (al_handle_t*)cl_vector_get_ptr( &h_al->hdl_vector, (size_t)hdl ); + + /* Make sure that the handle is valid and the correct type. */ + if( type == AL_OBJ_TYPE_UNKNOWN && + p_h->type != AL_OBJ_TYPE_H_PD && p_h->type != AL_OBJ_TYPE_H_CQ && + p_h->type != AL_OBJ_TYPE_H_AV && p_h->type != AL_OBJ_TYPE_H_QP && + p_h->type != AL_OBJ_TYPE_H_MR && p_h->type != AL_OBJ_TYPE_H_MW && + p_h->type != AL_OBJ_TYPE_H_SRQ ) + { + cl_spinlock_release( &h_al->obj.lock ); + return NULL; + } + else if( p_h->type != type ) + { + cl_spinlock_release( &h_al->obj.lock ); + return NULL; + } + + p_obj = p_h->p_obj; + if( !p_obj->hdl_valid ) + { + cl_spinlock_release( &h_al->obj.lock ); + return NULL; + } + ref_al_obj( p_obj ); + cl_spinlock_release( &h_al->obj.lock ); + return p_obj; +} + + +void* +al_hdl_chk( + IN const ib_al_handle_t h_al, + IN const uint64_t hdl, + IN const uint32_t type ) +{ + al_handle_t *p_h; + + /* Validate index. */ + if( hdl >= cl_vector_get_size( &h_al->hdl_vector ) ) + return NULL; + + /* Get the specified entry. */ + p_h = (al_handle_t*)cl_vector_get_ptr( &h_al->hdl_vector, (size_t)hdl ); + + /* Make sure that the handle is valid and the correct type. */ + if( (p_h->type != type) ) + return NULL; + + return p_h->p_obj; +} + + +void* +al_hdl_get( + IN const ib_al_handle_t h_al, + IN const uint64_t hdl, + IN const uint32_t type ) +{ + al_handle_t *p_h; + void *p_obj; + + cl_spinlock_acquire( &h_al->obj.lock ); + + /* Validate index. */ + if( hdl >= cl_vector_get_size( &h_al->hdl_vector ) ) + { + cl_spinlock_release( &h_al->obj.lock ); + return NULL; + } + + /* Get the specified entry. */ + p_h = (al_handle_t*)cl_vector_get_ptr( &h_al->hdl_vector, (size_t)hdl ); + + /* Make sure that the handle is valid and the correct type. */ + if( (p_h->type != type) ) + { + cl_spinlock_release( &h_al->obj.lock ); + return NULL; + } + + p_obj = (void*)p_h->p_obj; + + /* Clear the entry. */ + p_h->type = AL_OBJ_TYPE_UNKNOWN; + p_h->p_obj = (al_obj_t*)(uintn_t)h_al->free_hdl; + h_al->free_hdl = hdl; + + cl_spinlock_release( &h_al->obj.lock ); + return p_obj; +} + diff --git a/branches/WOF2-3/core/al/kernel/al_mr.c b/branches/WOF2-3/core/al/kernel/al_mr.c new file mode 100644 index 00000000..8080c61c --- /dev/null +++ b/branches/WOF2-3/core/al/kernel/al_mr.c @@ -0,0 +1,615 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include + +#include "al_debug.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "al_mr.tmh" +#endif +#include "al_mr.h" +#include "al_pd.h" +#include "al_res_mgr.h" +#include "al_verbs.h" + +#include "ib_common.h" + + +static void +__cleanup_mlnx_fmr( + IN struct _al_obj *p_obj ); + +static void +__return_mlnx_fmr( + IN al_obj_t *p_obj ); + + +static al_shmid_t* +__create_shmid( + IN const int shmid ); + +static void +__free_shmid( + IN struct _al_obj *p_obj ); + + +cl_status_t +mlnx_fmr_ctor( + IN void* const p_object, + IN void* context, + OUT cl_pool_item_t** const pp_pool_item ) +{ + ib_api_status_t status; + mlnx_fmr_handle_t h_fmr; + + UNUSED_PARAM( context ); + + h_fmr = (mlnx_fmr_handle_t)p_object; + cl_memclr( h_fmr, sizeof(mlnx_fmr_t) ); + + construct_al_obj( &h_fmr->obj, AL_OBJ_TYPE_H_FMR ); + status = init_al_obj( &h_fmr->obj, NULL, FALSE, NULL, + __cleanup_mlnx_fmr, __return_mlnx_fmr ); + if( status != IB_SUCCESS ) + { + return CL_ERROR; + } + + *pp_pool_item = &((mlnx_fmr_handle_t)p_object)->obj.pool_item; + + /* Release the reference taken in init_al_obj. */ + deref_al_obj( &h_fmr->obj ); + + return CL_SUCCESS; +} + + + +void +mlnx_fmr_dtor( + IN const cl_pool_item_t* const p_pool_item, + IN void* context ) +{ + al_obj_t *p_obj; + + UNUSED_PARAM( context ); + + p_obj = PARENT_STRUCT( p_pool_item, al_obj_t, pool_item ); + + /* + * The FMR is being totally destroyed. Modify the free_cb to destroy the + * AL object. + */ + p_obj->pfn_free = (al_pfn_free_t)destroy_al_obj; + ref_al_obj( p_obj ); + p_obj->pfn_destroy( p_obj, NULL ); +} + + + +static void +__cleanup_mlnx_fmr( + IN struct _al_obj *p_obj ) +{ + ib_api_status_t status; + mlnx_fmr_handle_t h_fmr; + + CL_ASSERT( p_obj ); + h_fmr = PARENT_STRUCT( p_obj, mlnx_fmr_t, obj ); + + /* Deregister the memory. */ + if( verbs_check_mlnx_fmr( h_fmr ) ) + { + status = verbs_destroy_mlnx_fmr( h_fmr ); + CL_ASSERT( status == IB_SUCCESS ); + + h_fmr->h_ci_fmr = NULL; + h_fmr->p_next = NULL; + } +} + + + +static void +__return_mlnx_fmr( + IN al_obj_t *p_obj ) +{ + mlnx_fmr_handle_t h_fmr; + + h_fmr = PARENT_STRUCT( p_obj, mlnx_fmr_t, obj ); + reset_al_obj( p_obj ); + put_mlnx_fmr( h_fmr ); +} + + + +ib_api_status_t +mlnx_create_fmr( + IN const ib_pd_handle_t h_pd, + IN const mlnx_fmr_create_t* const p_fmr_create, + OUT mlnx_fmr_handle_t* const ph_fmr ) +{ + mlnx_fmr_handle_t h_fmr; + ib_api_status_t status; + + AL_ENTER( AL_DBG_MR ); + + if( AL_OBJ_INVALID_HANDLE( h_pd, AL_OBJ_TYPE_H_PD ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PD_HANDLE\n") ); + return IB_INVALID_PD_HANDLE; + } + + if( !p_fmr_create || !ph_fmr ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + /* Get a FMR tracking structure. */ + h_fmr = alloc_mlnx_fmr(); + if( !h_fmr ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("unable to allocate memory handle\n") ); + return IB_INSUFFICIENT_MEMORY; + } + + status = attach_al_obj( &h_pd->obj, &h_fmr->obj ); + if( status != IB_SUCCESS ) + { + h_fmr->obj.pfn_destroy( &h_fmr->obj, NULL ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("attach_al_obj returned %s.\n", ib_get_err_str(status)) ); + return status; + } + + /* Register the memory region. */ + status = verbs_create_mlnx_fmr( h_pd, p_fmr_create, h_fmr ); + if( status != IB_SUCCESS ) + { + h_fmr->obj.pfn_destroy( &h_fmr->obj, NULL ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("unable to register memory: %s\n", ib_get_err_str(status)) ); + return status; + } + + *ph_fmr = h_fmr; + /* Release the reference taken in alloc_mlnx_fmr for initialization. */ + deref_al_obj( &(*ph_fmr )->obj ); + + AL_EXIT( AL_DBG_MR ); + return IB_SUCCESS; +} + + +ib_api_status_t +mlnx_map_phys_fmr( + IN const mlnx_fmr_handle_t h_fmr, + IN const uint64_t* const paddr_list, + IN const int list_len, + IN OUT uint64_t* const p_vaddr, + OUT net32_t* const p_lkey, + OUT net32_t* const p_rkey) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_MR ); + + if( AL_OBJ_INVALID_HANDLE( h_fmr, AL_OBJ_TYPE_H_FMR ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_FMR_HANDLE\n") ); + return IB_INVALID_FMR_HANDLE; + } + + if( !paddr_list || !p_vaddr || !p_lkey || !p_rkey ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + ref_al_obj( &h_fmr->obj ); + + /* Register the memory region. */ + status = verbs_map_phys_mlnx_fmr( h_fmr, paddr_list, list_len, p_vaddr, p_lkey, p_rkey); + if( status != IB_SUCCESS ) + { + //TODO: do we need to do something more about the error ? + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("unable to map FMR: %s\n", ib_get_err_str(status)) ); + } + + deref_al_obj( &h_fmr->obj ); + + AL_EXIT( AL_DBG_MR ); + return status; +} + + +ib_api_status_t +mlnx_unmap_fmr( + IN const mlnx_fmr_handle_t h_fmr ) +{ + ib_api_status_t status; + mlnx_fmr_t *p_fmr = (mlnx_fmr_t*)h_fmr; + mlnx_fmr_t *p_cur_fmr; + mlnx_fmr_handle_t *p_fmr_array; + int i; + + AL_ENTER( AL_DBG_MR ); + + if( AL_OBJ_INVALID_HANDLE( h_fmr, AL_OBJ_TYPE_H_FMR ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_FMR_HANDLE\n") ); + return IB_INVALID_FMR_HANDLE; + } + + // calculate the list size + for ( i=0, p_cur_fmr = p_fmr; p_cur_fmr; p_cur_fmr = p_cur_fmr->p_next) + i++; + + // allocate the array + p_fmr_array = cl_zalloc((i+1)*sizeof(mlnx_fmr_handle_t)); + if (!p_fmr_array) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_FMR_HANDLE\n") ); + return IB_INSUFFICIENT_MEMORY; + } + + // fill the array + for ( i=0, p_cur_fmr = p_fmr; p_cur_fmr; p_cur_fmr = p_cur_fmr->p_next) + { + p_fmr_array[i++] = p_cur_fmr->h_ci_fmr; + ref_al_obj( &p_cur_fmr->obj ); + } + p_fmr_array[i] = NULL; + + // unmap the array of FMRs + status = verbs_unmap_mlnx_fmr( h_fmr, p_fmr_array ); + + // deref the objects + for ( p_cur_fmr = p_fmr; p_cur_fmr; p_cur_fmr = p_cur_fmr->p_next) + deref_al_obj( &p_cur_fmr->obj ); + + cl_free( p_fmr_array ); + + AL_EXIT( AL_DBG_MR ); + return status; +} + + +ib_api_status_t +mlnx_destroy_fmr( + IN const mlnx_fmr_handle_t h_fmr ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_MR ); + + if( AL_OBJ_INVALID_HANDLE( h_fmr, AL_OBJ_TYPE_H_FMR ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_FMR_HANDLE\n") ); + return IB_INVALID_FMR_HANDLE; + } + + if( !verbs_check_mlnx_fmr( h_fmr ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_FMR_HANDLE\n") ); + return IB_INVALID_FMR_HANDLE; + } + + ref_al_obj( &h_fmr->obj ); + + /* FMR's are destroyed synchronously */ + status = verbs_destroy_mlnx_fmr( h_fmr ); + + if( status == IB_SUCCESS ) + { + h_fmr->h_ci_fmr = NULL; + /* We're good to destroy the object. + NOTE: No need to deref the al object , + we are resetting the fmr obj before inserting it back to the pool */ + + h_fmr->obj.pfn_destroy( &h_fmr->obj, NULL ); + } + else + { + deref_al_obj( &h_fmr->obj ); + } + AL_EXIT( AL_DBG_MR ); + return status; +} + + + +ib_api_status_t +ib_create_shmid( + IN const ib_pd_handle_t h_pd, + IN const int shmid, + IN const ib_mr_create_t* const p_mr_create, + OUT net32_t* const p_lkey, + OUT net32_t* const p_rkey, + OUT ib_mr_handle_t* const ph_mr ) +{ + ib_api_status_t status; + cl_status_t cl_status; + net32_t lkey; + net32_t rkey; + ib_mr_handle_t h_mr; + + AL_ENTER( AL_DBG_MR ); + + if( AL_OBJ_INVALID_HANDLE( h_pd, AL_OBJ_TYPE_H_PD ) ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PD_HANDLE\n") ); + return IB_INVALID_PD_HANDLE; + } + if( !p_mr_create || !p_lkey || !p_rkey || !ph_mr ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + /* Register the memory region. */ + status = ib_reg_mem( h_pd, p_mr_create, &lkey, &rkey, &h_mr ); + if( status != IB_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("unable to register memory: %s\n", ib_get_err_str(status)) ); + return status; + } + + /* Create the shmid tracking structure. */ + h_mr->p_shmid = __create_shmid( shmid ); + if( !h_mr->p_shmid ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("unable to allocate shmid\n") ); + ib_dereg_mr( h_mr ); + return IB_INSUFFICIENT_MEMORY; + } + + /* + * Record that the memory region is associated with this shmid. The + * insertion should automatically succeed since the list has a minimum + * size of 1. + */ + ref_al_obj( &h_mr->p_shmid->obj ); + cl_status = cl_list_insert_head( &h_mr->p_shmid->mr_list, h_mr ); + CL_ASSERT( cl_status == CL_SUCCESS ); + + /* Add the shmid to the CI CA for tracking. */ + add_shmid( h_pd->obj.p_ci_ca, h_mr->p_shmid ); + + /* Return the results. */ + *p_lkey = lkey; + *p_rkey = rkey; + *ph_mr = h_mr; + AL_EXIT( AL_DBG_MR ); + return IB_SUCCESS; +} + + + +/* + * Allocate a new structure to track memory registrations shared across + * processes. + */ +static al_shmid_t* +__create_shmid( + IN const int shmid ) +{ + al_shmid_t *p_shmid; + ib_api_status_t status; + cl_status_t cl_status; + + /* Allocate the shmid structure. */ + p_shmid = cl_zalloc( sizeof( al_shmid_t ) ); + if( !p_shmid ) + { + return NULL; + } + + /* Construct the shmid structure. */ + construct_al_obj( &p_shmid->obj, AL_OBJ_TYPE_H_MR ); + cl_list_construct( &p_shmid->mr_list ); + + /* Initialize the shmid structure. */ + status = init_al_obj( &p_shmid->obj, p_shmid, TRUE, + NULL, NULL, __free_shmid ); + if( status != IB_SUCCESS ) + { + __free_shmid( &p_shmid->obj ); + return NULL; + } + + cl_status = cl_list_init( &p_shmid->mr_list, 1 ); + if( cl_status != CL_SUCCESS ) + { + p_shmid->obj.pfn_destroy( &p_shmid->obj, NULL ); + return NULL; + } + + p_shmid->id = shmid; + + /* Release the reference taken in init_al_obj. */ + deref_al_obj( &p_shmid->obj ); + + return p_shmid; +} + + + +static void +__free_shmid( + IN struct _al_obj *p_obj ) +{ + al_shmid_t *p_shmid; + + p_shmid = PARENT_STRUCT( p_obj, al_shmid_t, obj ); + + CL_ASSERT( cl_is_list_empty( &p_shmid->mr_list ) ); + + cl_list_destroy( &p_shmid->mr_list ); + destroy_al_obj( p_obj ); + cl_free( p_shmid ); +} + + + +ib_api_status_t +ib_reg_shmid( + IN const ib_pd_handle_t h_pd, + IN const ib_shmid_t shmid, + IN const ib_mr_create_t* const p_mr_create, + IN OUT uint64_t* const p_vaddr, + OUT net32_t* const p_lkey, + OUT net32_t* const p_rkey, + OUT ib_mr_handle_t* const ph_mr ) +{ + return reg_shmid( h_pd, shmid, p_mr_create, p_vaddr, p_lkey, p_rkey, ph_mr ); +} + + +ib_api_status_t +reg_shmid( + IN const ib_pd_handle_t h_pd, + IN const ib_shmid_t shmid, + IN const ib_mr_create_t* const p_mr_create, + IN OUT uint64_t* const p_vaddr, + OUT net32_t* const p_lkey, + OUT net32_t* const p_rkey, + OUT ib_mr_handle_t* const ph_mr ) +{ + UNUSED_PARAM( h_pd ); + UNUSED_PARAM( shmid ); + UNUSED_PARAM( p_mr_create ); + UNUSED_PARAM( p_vaddr ); + UNUSED_PARAM( p_lkey ); + UNUSED_PARAM( p_rkey ); + UNUSED_PARAM( ph_mr ); + return IB_ERROR; +#if 0 + ib_api_status_t status; + cl_status_t cl_status; + al_shmid_t *p_shmid; + uint64_t vaddr; + net32_t lkey; + net32_t rkey; + ib_mr_handle_t h_mr, h_reg_mr; + + AL_ENTER( AL_DBG_MR ); + + if( AL_OBJ_INVALID_HANDLE( h_pd, AL_OBJ_TYPE_H_PD ) ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PD_HANDLE\n") ); + return IB_INVALID_PD_HANDLE; + } + if( !p_vaddr || !p_lkey || !p_rkey || !ph_mr ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + /* Let's see if we can acquire the registered memory region. */ + status = acquire_shmid( h_pd->obj.p_ci_ca, shmid, &p_shmid ); + if( status != IB_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("shmid not found: %s\n", ib_get_err_str(status)) ); + return IB_NOT_FOUND; + } + + /* Lock down the shmid to prevent deregistrations while we register. */ + cl_spinlock_acquire( &p_shmid->obj.lock ); + + /* + * There's a chance after we acquired the shmid, all current + * registrations were deregistered. + */ + if( cl_is_list_empty( &p_shmid->mr_list ) ) + { + /* There are no registrations left to share. */ + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("shmid not found\n") ); + cl_spinlock_release( &p_shmid->obj.lock ); + release_shmid( p_shmid ); + return IB_NOT_FOUND; + } + + /* Get a handle to an existing registered memory region. */ + h_reg_mr = cl_list_obj( cl_list_head( &p_shmid->mr_list ) ); + +// BUGBUG: This release is not safe since the h_reg_mr can be deregistered. + cl_spinlock_release( &p_shmid->obj.lock ); + + /* Register the memory region. */ + vaddr = *p_vaddr; + status = ib_reg_shared( h_reg_mr, h_pd, access_ctrl, &vaddr, + &lkey, &rkey, &h_mr ); + if( status != IB_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("unable to register shared memory: 0x%0I64x %s\n", + vaddr, ib_get_err_str(status)) ); + release_shmid( p_shmid ); + return status; + } + + cl_spinlock_acquire( &p_shmid->obj.lock ); + + /* Track the registration with the shmid structure. */ + cl_status = cl_list_insert_head( &p_shmid->mr_list, h_mr ); + if( cl_status != CL_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("insertion into shmid list failed\n") ); + cl_spinlock_release( &p_shmid->obj.lock ); + release_shmid( p_shmid ); + return ib_convert_cl_status( cl_status ); + } + + cl_spinlock_release( &p_shmid->obj.lock ); + + /* Return the results. */ + h_mr->p_shmid = p_shmid; + *p_vaddr = vaddr; + *p_lkey = lkey; + *p_rkey = rkey; + *ph_mr = h_mr; + AL_EXIT( AL_DBG_MR ); + return IB_SUCCESS; +#endif +} diff --git a/branches/WOF2-3/core/al/kernel/al_ndi_cm.c b/branches/WOF2-3/core/al/kernel/al_ndi_cm.c new file mode 100644 index 00000000..4e17d66b --- /dev/null +++ b/branches/WOF2-3/core/al/kernel/al_ndi_cm.c @@ -0,0 +1,2014 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: al_proxy_verbs.c 548 2006-11-27 20:03:51Z leonidk $ + */ + + +#include +#include +#include +#include "al.h" +#include "al_mgr.h" +#include "al_debug.h" +#if WINVER <= 0x501 +#include "csq.h" +#endif + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "al_ndi_cm.tmh" +#endif + +#include "al_dev.h" +/* Get the internal definitions of apis for the proxy */ +#include "al_ca.h" +#include "ib_common.h" +#include "al_qp.h" +#include "al_cm_conn.h" +#include "al_cm_cep.h" +#include "al_ndi_cm.h" + +uint32_t g_sa_timeout = 500; +uint32_t g_sa_retries = 4; +uint8_t g_qp_retries = QP_ATTRIB_RETRY_COUNT; +uint8_t g_pkt_life_modifier = 0; +uint8_t g_max_cm_retries = CM_RETRIES; + +NTSTATUS +__ndi_ats_query( + IN IRP* p_irp + ); + +NTSTATUS +__ndi_pr_query( + IN IRP* p_irp + ); + +NTSTATUS +__ndi_send_req( + IN IRP* p_irp + ); + +NTSTATUS +__ndi_send_rep( + IN nd_csq_t *p_csq, + IN PIRP p_irp + ); + +NTSTATUS +__ndi_send_dreq( + IN IRP* p_irp + ); + +NTSTATUS +__ndi_get_req( + IN nd_csq_t *p_csq, + IN IRP* p_irp + ); + +static void +__ndi_queue_drep( + IN IRP *p_irp + ); + + +/******************************************************************* + * + * Helpers + * + ******************************************************************/ + +static char * State2String(ndi_cm_state_t state) +{ + switch (state) + { + case NDI_CM_IDLE : return "NDI_CM_IDLE"; + case NDI_CM_CONNECTING_QPR_SENT : return "NDI_CM_CONNECTING_QPR_SENT"; + case NDI_CM_CONNECTING_REQ_SENT : return "NDI_CM_CONNECTING_REQ_SENT"; + case NDI_CM_CONNECTING_REP_SENT : return "NDI_CM_CONNECTING_REP_SENT"; + case NDI_CM_CONNECTING_REP_RCVD : return "NDI_CM_CONNECTING_REP_RCVD"; + case NDI_CM_CONNECTED : return "NDI_CM_CONNECTED"; + case NDI_CM_DISCONNECTING : return "NDI_CM_DISCONNECTING"; + case NDI_CM_CONNECTED_DREQ_RCVD : return "NDI_CM_CONNECTED_DREQ_RCVD"; + case NDI_CM_INVALID : return "NDI_CM_CONNECTING_REP_SENT"; + default : + ASSERT(FALSE); + } + return "Unknown state"; +} + + +static inline void +__ndi_complete_irp( + IN nd_csq_t* p_csq, + IN PIRP p_irp, + IN NTSTATUS status + ) +{ + AL_PRINT( TRACE_LEVEL_VERBOSE, AL_DBG_NDI, ("[ CID = %d\n", p_csq->cid) ); + + CL_ASSERT( p_irp ); + CL_ASSERT( p_irp->Tail.Overlay.DriverContext[1] == NULL ); + + p_irp->IoStatus.Status = status; + if( status == STATUS_SUCCESS ) + { + p_irp->IoStatus.Information = cl_ioctl_out_size( p_irp ); + IoCompleteRequest( p_irp, IO_NETWORK_INCREMENT ); + } + else + { + p_irp->IoStatus.Information = 0; + IoCompleteRequest( p_irp, 0 ); + } + nd_csq_release( p_csq ); /* Release IRP reference */ + + AL_EXIT( AL_DBG_NDI ); +} + + +/* + * Transition the QP to the error state to flush all oustanding work + * requests and sets the timewait time. This function may be called + * when destroying the QP in order to flush all work requests, so we + * cannot call through the main API, or the call will fail since the + * QP is no longer in the initialize state. + */ +static void +__cep_timewait_qp( + IN nd_csq_t *p_csq ) +{ + uint64_t timewait = 0; + ib_qp_handle_t h_qp; + ib_qp_mod_t qp_mod; + ib_api_status_t status; + + AL_ENTER( AL_DBG_CM ); + + CL_ASSERT( p_csq != NULL ); + + /* + * The CM should have set the proper timewait time-out value. Reset + * the QP and let it enter the timewait state. + */ + if( al_cep_get_timewait( p_csq->h_al, p_csq->cid, &timewait ) == IB_SUCCESS ) + { + h_qp = CONTAINING_RECORD( + al_hdl_ref( p_csq->h_al, p_csq->h_qp, AL_OBJ_TYPE_H_QP ), + ib_qp_t, + obj ); + + /* Special checks on the QP state for error handling - see above. */ + if( !h_qp || !AL_OBJ_IS_TYPE( h_qp, AL_OBJ_TYPE_H_QP ) || + ( (h_qp->obj.state != CL_INITIALIZED) && + (h_qp->obj.state != CL_DESTROYING) ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_QP_HANDLE\n") ); + return; + } + + cl_memclr( &qp_mod, sizeof(ib_qp_mod_t) ); + qp_mod.req_state = IB_QPS_ERROR; + + /* Modify to error state using function pointers - see above. */ + status = h_qp->pfn_modify_qp( h_qp, &qp_mod, NULL ); + if( status != IB_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("pfn_modify_qp to IB_QPS_ERROR returned %s\n", + ib_get_err_str( status )) ); + } + else + { + /* Store the timestamp after which the QP exits timewait. */ + h_qp->timewait = cl_get_time_stamp() + timewait; + } + deref_al_obj( &h_qp->obj ); + } + + AL_EXIT( AL_DBG_CM ); +} + +static ib_api_status_t +__ndi_qp2rts( + IN nd_csq_t* p_csq, + IN PIRP p_irp + ) +{ + ib_api_status_t status; + ib_qp_handle_t h_qp; + ib_qp_mod_t qp_mod; + + AL_PRINT( TRACE_LEVEL_VERBOSE, AL_DBG_NDI, + ("[ CID = %d\n", p_csq->cid) ); + + h_qp = CONTAINING_RECORD( + al_hdl_ref( p_csq->h_al, p_csq->h_qp, AL_OBJ_TYPE_H_QP ), + ib_qp_t, + obj ); + if( h_qp == NULL ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("Bad QP %I64d\n", p_csq->h_qp) ); + status = IB_INVALID_HANDLE; + goto err; + } + + AL_PRINT( TRACE_LEVEL_VERBOSE, AL_DBG_NDI, + ("QP %p state %d\n", h_qp, h_qp->state) ); + + /* fill required qp attributes */ + status = al_cep_get_rtr_attr( p_csq->h_al, p_csq->cid, &qp_mod ); + if ( status != IB_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("al_cep_get_rtr_attr for CID %d returned %s\n", + p_csq->cid, ib_get_err_str( status )) ); + goto exit; + } + + /* perform the request: INIT->RTR */ + status = ndi_modify_qp( h_qp, &qp_mod, + cl_ioctl_out_size( p_irp ), cl_ioctl_out_buf( p_irp ) ); + if ( status != IB_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("ndi_modify_qp %p from %d to RTR returned %s.\n", + h_qp, h_qp->state, ib_get_err_str(status) ) ); + goto exit; + } + + /* fill required qp attributes */ + status = al_cep_get_rts_attr( p_csq->h_al, p_csq->cid, &qp_mod ); + if ( status != IB_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("al_cep_get_rts_attr for CID %d returned %s\n", + p_csq->cid, ib_get_err_str( status )) ); + goto exit; + } + + /* perform the request: RTR->RTS */ + status = ndi_modify_qp( h_qp, &qp_mod, + cl_ioctl_out_size( p_irp ), cl_ioctl_out_buf( p_irp ) ); + if ( status != IB_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("ndi_modify_qp %p from %d to RTS returned %s.\n", + h_qp, h_qp->state, ib_get_err_str(status) ) ); + } + +exit: + deref_al_obj( &h_qp->obj ); +err: + AL_EXIT( AL_DBG_NDI ); + return status; +} + + +/******************************************************************* + * + * CSQ + * + ******************************************************************/ + + +static NTSTATUS __ndi_insert_irp_ex( + IN PIO_CSQ pCsq, + IN PIRP pIrp, + IN VOID *Context + ) +{ + NTSTATUS status; + nd_csq_t *p_ndi_csq = CONTAINING_RECORD( pCsq, nd_csq_t, csq ); + + AL_PRINT( TRACE_LEVEL_VERBOSE, AL_DBG_NDI, ("[ CID = %d\n", p_ndi_csq->cid) ); + switch( (ULONG_PTR)Context ) + { + case NDI_CM_LISTEN: + status = __ndi_get_req( p_ndi_csq, pIrp ); + break; + + case NDI_CM_CONNECTING_QPR_SENT: + status = __ndi_pr_query( pIrp ); + break; + + case NDI_CM_CONNECTING_REQ_SENT: + status = __ndi_send_req( pIrp ); + break; + + case NDI_CM_DISCONNECTING: + status = __ndi_send_dreq( pIrp ); + break; + + case NDI_CM_CONNECTED_DREQ_RCVD: + if( p_ndi_csq->state == NDI_CM_LISTEN ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_NDI, + ("] Invalid state (%d).\n", p_ndi_csq->state) ); + return STATUS_INVALID_DEVICE_REQUEST; + } + + /* + * Overwrite the context so that the state change + * below turns into a noop. + */ + Context = (VOID*)(ULONG_PTR)p_ndi_csq->state; + status = STATUS_PENDING; + break; + + default: + status = STATUS_INVALID_DEVICE_REQUEST; + ASSERT( FALSE ); + } + + ASSERT( status == STATUS_PENDING || !NT_SUCCESS( status ) ); + if( NT_SUCCESS( status ) ) + { + AL_PRINT( TRACE_LEVEL_VERBOSE, AL_DBG_NDI, ("] Queueing IRP\n") ); + p_ndi_csq->state = (ndi_cm_state_t)(ULONG_PTR)Context; + InsertTailList( &p_ndi_csq->queue, &pIrp->Tail.Overlay.ListEntry ); + nd_csq_ref( p_ndi_csq ); /* Take IRP reference. */ + } + AL_EXIT( AL_DBG_NDI ); + return status; +} + +static VOID __ndi_remove_irp( + IN PIO_CSQ Csq, + IN PIRP Irp + ) +{ + UNUSED_PARAM( Csq ); + + AL_ENTER( AL_DBG_NDI ); + RemoveEntryList( &Irp->Tail.Overlay.ListEntry ); + AL_EXIT( AL_DBG_NDI ); +} + +static PIRP __ndi_peek_next_irp( + IN PIO_CSQ Csq, + IN PIRP Irp, + IN PVOID PeekContext + ) +{ + PIRP nextIrp = NULL; + PLIST_ENTRY nextEntry; + PLIST_ENTRY listHead; + nd_csq_t *p_ndi_csq = (nd_csq_t*)Csq; + + AL_ENTER( AL_DBG_NDI ); + + listHead = &p_ndi_csq->queue; + + // + // If the IRP is NULL, we will start peeking from the listhead, else + // we will start from that IRP onwards. This is done under the + // assumption that new IRPs are always inserted at the tail. + // + + if(Irp == NULL) + nextEntry = listHead->Flink; + else + nextEntry = Irp->Tail.Overlay.ListEntry.Flink; + + while(nextEntry != listHead) { + nextIrp = CONTAINING_RECORD(nextEntry, IRP, Tail.Overlay.ListEntry); + + // + // If context is present, continue until you find a matching one. + // Else you break out as you got next one. + // + + if(PeekContext) + { + if( cl_ioctl_ctl_code( nextIrp ) == (ULONG_PTR)PeekContext ) + break; + } + else + { + if( cl_ioctl_ctl_code( nextIrp ) != UAL_NDI_NOTIFY_DREQ ) + break; + } + + nextIrp = NULL; + nextEntry = nextEntry->Flink; + } + + AL_EXIT( AL_DBG_NDI ); + return nextIrp; +} + +static VOID __ndi_acquire_lock( + IN PIO_CSQ Csq, + OUT PKIRQL pIrql + ) +{ + nd_csq_t *p_ndi_csq = (nd_csq_t*)Csq; + + KeAcquireSpinLock( &p_ndi_csq->lock, pIrql ); +} + +static VOID __ndi_release_lock( + IN PIO_CSQ Csq, + IN KIRQL Irql + ) +{ + nd_csq_t *p_ndi_csq = (nd_csq_t*)Csq; + + KeReleaseSpinLock( &p_ndi_csq->lock, Irql ); +} + +static VOID __ndi_complete_cancelled_irp( + IN PIO_CSQ Csq, + IN PIRP p_irp + ) +{ + nd_csq_t *p_ndi_csq = (nd_csq_t*)Csq; + KIRQL irql; + ib_query_handle_t h_query; + + AL_ENTER( AL_DBG_NDI ); + + switch( cl_ioctl_ctl_code( p_irp ) ) + { + case UAL_NDI_REQ_CM: + __ndi_acquire_lock( Csq, &irql ); + /* + * Note that al_cancel_sa_req is synchronized with any potential + * SA callback by the CSQ lock. + */ +#pragma warning( disable:4305 ) + h_query = InterlockedExchangePointer( &p_ndi_csq->h_query, NULL ); +#pragma warning( default:4305 ) + if( h_query != NULL ) + al_cancel_sa_req( &h_query->sa_req ); + + if( p_ndi_csq->state != NDI_CM_INVALID ) + p_ndi_csq->state = NDI_CM_IDLE; + + __ndi_release_lock( Csq, irql ); + + __fallthrough; + + case UAL_NDI_NOTIFY_DREQ: + case UAL_NDI_GET_REQ_CM: + __ndi_complete_irp( p_ndi_csq, p_irp, STATUS_CANCELLED ); + break; + + case UAL_NDI_DREQ_CM: + __ndi_queue_drep( p_irp ); + break; + } + + AL_EXIT( AL_DBG_NDI ); +} + + + +NTSTATUS +nd_csq_init( + IN ib_al_handle_t h_al, + IN net32_t cid, + IN uint64_t h_qp, + OUT nd_csq_t **pp_csq ) +{ + nd_csq_t *p_nd_csq; + NTSTATUS status; + ib_api_status_t ib_status; + + AL_ENTER( AL_DBG_NDI ); + + p_nd_csq = (nd_csq_t*)cl_zalloc( sizeof(*p_nd_csq) ); + if( p_nd_csq == NULL ) + { + status = STATUS_NO_MEMORY; + goto exit; + } + + KeInitializeSpinLock( &p_nd_csq->lock ); + InitializeListHead( &p_nd_csq->queue ); + p_nd_csq->h_al = h_al; + p_nd_csq->h_qp = h_qp; + p_nd_csq->h_query = NULL; + p_nd_csq->state = NDI_CM_IDLE; + p_nd_csq->cid = cid; + + status = IoCsqInitializeEx( &p_nd_csq->csq, + __ndi_insert_irp_ex, __ndi_remove_irp, + __ndi_peek_next_irp, __ndi_acquire_lock, + __ndi_release_lock, __ndi_complete_cancelled_irp ); + if ( !NT_SUCCESS( status ) ) + { + cl_free( p_nd_csq ); + goto exit; + } + + /* + * One reference for the CEP, one for the caller (so that if the CEP + * gets destroyed we don't blow up.) + */ + p_nd_csq->ref_cnt = 2; + + ib_status = kal_cep_config( + h_al, cid, nd_cm_handler, p_nd_csq, nd_csq_release ); + + if( ib_status != IB_SUCCESS ) + { + status = STATUS_UNSUCCESSFUL; + cl_free( p_nd_csq ); + goto exit; + } + + *pp_csq = p_nd_csq; + status = STATUS_SUCCESS; + + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI, + ("Creating CSQ %p, uhdl %#I64x \n", p_nd_csq, h_qp) ); + +exit: + AL_EXIT( AL_DBG_NDI ); + return status; +} + + +void +ndi_cancel_cm_irps( + IN nd_csq_t *p_nd_csq ) +{ + PIRP Irp; + + AL_PRINT( TRACE_LEVEL_VERBOSE, AL_DBG_NDI, + ("[ CSQ %p (CID = %d)\n", + p_nd_csq, p_nd_csq->cid ) ); + + /* cancel pending IRPS for NDI type CQ */ + AL_ENTER( AL_DBG_NDI ); + for( Irp = IoCsqRemoveNextIrp( &p_nd_csq->csq, NULL ); + Irp != NULL; + Irp = IoCsqRemoveNextIrp( &p_nd_csq->csq, NULL ) ) + { + __ndi_complete_cancelled_irp( &p_nd_csq->csq, Irp ); + } + for( Irp = IoCsqRemoveNextIrp( &p_nd_csq->csq, (VOID*)(ULONG_PTR)UAL_NDI_NOTIFY_DREQ ); + Irp != NULL; + Irp = IoCsqRemoveNextIrp( &p_nd_csq->csq, (VOID*)(ULONG_PTR)UAL_NDI_NOTIFY_DREQ ) ) + { + __ndi_complete_cancelled_irp( &p_nd_csq->csq, Irp ); + } + + AL_EXIT( AL_DBG_NDI ); +} + + +void +nd_csq_destroy( + IN nd_csq_t *p_nd_csq ) +{ + KIRQL irql; + + AL_PRINT( TRACE_LEVEL_VERBOSE, AL_DBG_NDI, + ("[ CSQ %p (CID = %d)\n", + p_nd_csq, p_nd_csq->cid ) ); + + /* Move the state before flushing, so that all new IRPs fail to queue. */ + __ndi_acquire_lock( &p_nd_csq->csq, &irql ); + p_nd_csq->state = NDI_CM_INVALID; + __ndi_release_lock( &p_nd_csq->csq, irql ); + + /* cancel pending IRPS */ + ndi_cancel_cm_irps( p_nd_csq ); + + cl_free( p_nd_csq ); + + AL_EXIT( AL_DBG_NDI ); +} + + +void +nd_csq_ref( nd_csq_t* p_csq ) +{ + InterlockedIncrement( &p_csq->ref_cnt ); +} + + +void +nd_csq_release( nd_csq_t* p_csq ) +{ + if( InterlockedDecrement( &p_csq->ref_cnt ) == 0 ) + { + nd_csq_destroy( p_csq ); + } +} + + +static inline void +__ndi_timeout_req_irp( + __in nd_csq_t* p_csq ) +{ + PIRP Irp; + KIRQL irql; + + AL_ENTER( AL_DBG_NDI ); + Irp = IoCsqRemoveNextIrp( &p_csq->csq, (VOID*)(ULONG_PTR)UAL_NDI_REQ_CM ); + if( Irp ) + { + __ndi_acquire_lock( &p_csq->csq, &irql ); + if( p_csq->state != NDI_CM_INVALID ) + p_csq->state = NDI_CM_IDLE; + __ndi_release_lock( &p_csq->csq, irql ); + __ndi_complete_irp( p_csq, Irp, STATUS_TIMEOUT ); + } + AL_EXIT( AL_DBG_NDI ); +} + +/******************************************************************* + * + * REQ CM request + * + ******************************************************************/ + +static void +__ndi_notify_dreq( + __in nd_csq_t* p_csq ) +{ + IRP *p_irp; + do + { + p_irp = IoCsqRemoveNextIrp( + &p_csq->csq, (VOID*)(ULONG_PTR)UAL_NDI_NOTIFY_DREQ ); + + if( p_irp ) + { + __ndi_complete_irp( p_csq, p_irp, STATUS_SUCCESS ); + } + + } while ( p_irp ); +} + + +static void +__ndi_proc_dreq( + IN nd_csq_t *p_csq) +{ + IRP *p_irp; + KIRQL irql; + + __ndi_notify_dreq( p_csq ); + + __ndi_acquire_lock( &p_csq->csq, &irql ); + if( p_csq->state == NDI_CM_CONNECTED ) + { + p_csq->state = NDI_CM_CONNECTED_DREQ_RCVD; + } + __ndi_release_lock( &p_csq->csq, irql ); + + p_irp = IoCsqRemoveNextIrp( + &p_csq->csq, (VOID*)(ULONG_PTR)UAL_NDI_DREQ_CM ); + if( p_irp != NULL ) + { + __ndi_queue_drep( p_irp ); + } +} + + +/* + * A user-specified callback that is invoked after receiving a connection + * rejection message (REJ). + */ +static void +__ndi_proc_rej( + IN nd_csq_t* p_csq, + IN const mad_cm_rej_t* const p_rej ) +{ + KIRQL irql; + IRP* p_irp; + + AL_ENTER( AL_DBG_NDI ); + + AL_PRINT(TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("p_rej %p, CID=%d, uhdl %#I64x, connect reject, reason=%hd\n", + p_rej, p_csq->cid, p_csq->h_qp, cl_ntoh16(p_rej->reason) ) ); + + p_irp = IoCsqRemoveNextIrp( &p_csq->csq, NULL ); + __ndi_notify_dreq( p_csq ); + __ndi_acquire_lock( &p_csq->csq, &irql ); + if( p_irp != NULL ) + { + switch( cl_ioctl_ctl_code( p_irp ) ) + { + case UAL_NDI_REQ_CM: + if( p_csq->state != NDI_CM_INVALID ) + p_csq->state = NDI_CM_IDLE; + if( p_rej->reason == IB_REJ_USER_DEFINED ) + __ndi_complete_irp( p_csq, p_irp, STATUS_CONNECTION_REFUSED ); + else + __ndi_complete_irp( p_csq, p_irp, STATUS_TIMEOUT ); + + /* We leave the CEP active so that the private data can be retrieved. */ + break; + + case UAL_NDI_DREQ_CM: + __ndi_queue_drep( p_irp ); + break; + + case UAL_NDI_NOTIFY_DREQ: + __ndi_complete_irp( p_csq, p_irp, STATUS_CONNECTION_ABORTED ); + break; + + default: + ASSERT( cl_ioctl_ctl_code( p_irp ) == UAL_NDI_REQ_CM || + cl_ioctl_ctl_code( p_irp ) == UAL_NDI_DREQ_CM || + cl_ioctl_ctl_code( p_irp ) == UAL_NDI_NOTIFY_DREQ ); + } + } + else if( p_csq->state == NDI_CM_CONNECTED || p_csq->state == NDI_CM_CONNECTING_REQ_RCVD ) + { + p_csq->state = NDI_CM_CONNECTED_DREQ_RCVD; + } + __ndi_release_lock( &p_csq->csq, irql ); + + AL_EXIT( AL_DBG_NDI ); +} + + +static void +__ndi_proc_req( + IN nd_csq_t* p_csq, + IN net32_t new_cid, + IN ib_mad_element_t *p_mad ) +{ + IRP* p_irp; + KIRQL irql; + NTSTATUS status; + nd_csq_t* p_new_csq; + + AL_ENTER( AL_DBG_NDI ); + + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI ,("CID = %d\n", p_csq->cid)); + + status = nd_csq_init( p_csq->h_al, new_cid, 0, &p_new_csq ); + if( status != STATUS_SUCCESS ) + { + // Ignore the request. + kal_cep_destroy( p_csq->h_al, new_cid, STATUS_NO_MORE_ENTRIES ); + ib_put_mad( p_mad ); + return; + } + + __ndi_acquire_lock( &p_new_csq->csq, &irql ); + p_new_csq->state = NDI_CM_CONNECTING_REQ_RCVD; + __ndi_release_lock( &p_new_csq->csq, irql ); + nd_csq_release( p_new_csq ); + + p_irp = IoCsqRemoveNextIrp( &p_csq->csq, (VOID*)(ULONG_PTR)UAL_NDI_GET_REQ_CM ); + if( p_irp == NULL ) + { + p_mad->send_context1 = (VOID*)(ULONG_PTR)new_cid; + __ndi_acquire_lock( &p_csq->csq, &irql ); + if( p_csq->p_mad_head == NULL ) + { + p_csq->p_mad_head = p_mad; + } + else + { + p_csq->p_mad_tail->p_next = p_mad; + } + p_csq->p_mad_tail = p_mad; + __ndi_release_lock( &p_csq->csq, irql ); + } + else + { + *(net32_t*)cl_ioctl_out_buf( p_irp ) = new_cid; + __ndi_complete_irp( p_csq, p_irp, STATUS_SUCCESS ); + ib_put_mad( p_mad ); + } + + AL_EXIT( AL_DBG_NDI ); + return; +} + + +static void +__ndi_proc_rep( + IN nd_csq_t* p_csq ) +{ + IRP* p_irp; + KIRQL irql; + + AL_ENTER( AL_DBG_NDI ); + + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI ,("CID = %d\n", p_csq->cid)); + + p_irp = IoCsqRemoveNextIrp( &p_csq->csq, (VOID*)(ULONG_PTR)UAL_NDI_REQ_CM ); + __ndi_acquire_lock( &p_csq->csq, &irql ); + if( p_irp == NULL ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("Not the expected state %s\n", State2String( p_csq->state ))); + CL_ASSERT( IsListEmpty( &p_csq->queue ) ); + al_cep_rej( p_csq->h_al, p_csq->cid, IB_REJ_INVALID_COMM_INSTANCE, NULL, 0, NULL, 0 ); + } + else + { + p_csq->state = NDI_CM_CONNECTING_REP_RCVD; + + __ndi_complete_irp( p_csq, p_irp, STATUS_SUCCESS ); + } + __ndi_release_lock( &p_csq->csq, irql ); + + AL_EXIT( AL_DBG_NDI ); + return; +} + + +void +__ndi_do_drep( + IN DEVICE_OBJECT* p_dev_obj, + IN PIRP p_irp ) +{ + nd_csq_t* p_csq = p_irp->Tail.Overlay.DriverContext[0]; + ib_qp_handle_t h_qp; + ib_qp_mod_t qp_mod; + ib_api_status_t status; + uint64_t timewait_us; + KIRQL irql; + NTSTATUS nt_status; + + UNREFERENCED_PARAMETER( p_dev_obj ); + + AL_ENTER( AL_DBG_NDI ); + + CL_ASSERT( p_irp->Tail.Overlay.DriverContext[1] ); + IoFreeWorkItem( p_irp->Tail.Overlay.DriverContext[1] ); + p_irp->Tail.Overlay.DriverContext[1] = NULL; + + status = al_cep_get_timewait( p_csq->h_al, p_csq->cid, &timewait_us ); + if (status != IB_SUCCESS) + { + nt_status = STATUS_CONNECTION_INVALID; + goto exit; + } + + /* Store the timestamp after which the QP exits timewait. */ + h_qp = CONTAINING_RECORD( + al_hdl_ref( p_csq->h_al, p_csq->h_qp, AL_OBJ_TYPE_H_QP ), + ib_qp_t, + obj ); + if( h_qp != NULL ) + { + h_qp->timewait = cl_get_time_stamp() + timewait_us; + } + + /* Send the DREP. */ + al_cep_drep( p_csq->h_al, p_csq->cid, NULL, 0 ); + + /* bring QP to error state */ + if( h_qp != NULL ) + { + cl_memclr( &qp_mod, sizeof(qp_mod) ); + qp_mod.req_state = IB_QPS_ERROR; + + status = ndi_modify_qp( h_qp, &qp_mod, + cl_ioctl_out_size( p_irp ), cl_ioctl_out_buf( p_irp ) ); + if ( status != IB_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("ndi_modify_qp to ERROR returned %s.\n", ib_get_err_str(status) ) ); + } + deref_al_obj( &h_qp->obj ); + } + + nt_status = ib_to_ntstatus( status ); + +exit: + __ndi_acquire_lock( &p_csq->csq, &irql ); + if( p_csq->state != NDI_CM_INVALID ) + p_csq->state = NDI_CM_IDLE; + __ndi_release_lock( &p_csq->csq, irql ); + + __ndi_complete_irp( p_csq, p_irp, nt_status ); + nd_csq_release( p_csq ); /* Release work item reference. */ + AL_EXIT( AL_DBG_NDI ); +} + + +static void +__ndi_queue_drep( + IN IRP *p_irp ) +{ + CL_ASSERT( p_irp->Tail.Overlay.DriverContext[1] != NULL ); + IoQueueWorkItem( p_irp->Tail.Overlay.DriverContext[1], + __ndi_do_drep, DelayedWorkQueue, p_irp ); +} + + +static void +__ndi_proc_drep( + IN nd_csq_t* p_csq ) +{ + IRP* p_irp; + + AL_ENTER( AL_DBG_NDI ); + + p_irp = IoCsqRemoveNextIrp( + &p_csq->csq, (VOID*)(ULONG_PTR)UAL_NDI_DREQ_CM ); + if( p_irp != NULL ) + { + CL_ASSERT( p_irp->Tail.Overlay.DriverContext[0] == p_csq ); + __ndi_queue_drep( p_irp ); + } + + AL_EXIT( AL_DBG_NDI ); +} + + +void +nd_cm_handler( + IN const ib_al_handle_t h_al, + IN const net32_t cid ) +{ + void* context; + net32_t new_cid; + ib_mad_element_t *p_mad_el; + + AL_ENTER( AL_DBG_NDI ); + + while( al_cep_poll( h_al, cid, &context, &new_cid, &p_mad_el ) == IB_SUCCESS ) + { + ib_mad_t* p_mad = ib_get_mad_buf( p_mad_el ); + nd_csq_t* p_csq = (nd_csq_t*)context; + + CL_ASSERT( p_csq != NULL ); + CL_ASSERT( p_csq->cid == cid ); + + if( p_mad_el->status != IB_SUCCESS ) + { + switch( p_mad->attr_id ) + { + case CM_REQ_ATTR_ID: + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI, + ("REQ timed out for CEP with cid %d, h_al %p, context %p.\n", + cid, h_al, p_csq ) ); + __ndi_timeout_req_irp( p_csq ); + break; + + case CM_REP_ATTR_ID: + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI, + ("REP timed out for CEP with cid %d, h_al %p, context %p.\n", + cid, h_al, p_csq ) ); + break; + + case CM_DREQ_ATTR_ID: + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI, + ("DREQ timed out for CEP with cid %d, h_al %p, context %p.\n", + cid, h_al, p_csq ) ); + __ndi_proc_drep( p_csq ); + break; + + default: + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("Unhandled failed MAD attr ID %d for CEP with cid %d, h_al %p, context %p, new_cid %d .\n", + p_mad->attr_id, cid, h_al, p_csq, new_cid ) ); + break; + } + } + else + { + switch( p_mad->attr_id ) + { + case CM_REQ_ATTR_ID: + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI, + ("REQ received for CEP with cid %d, h_al %p, context %p.\n", + cid, h_al, p_csq ) ); + __ndi_proc_req( p_csq, new_cid, p_mad_el ); + continue; + + case CM_REP_ATTR_ID: + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI, + ("REP received for CEP with cid %d, h_al %p, context %p.\n", + cid, h_al, p_csq ) ); + __ndi_proc_rep( p_csq ); + break; + + case CM_REJ_ATTR_ID: + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI, + ("REJ received for CEP with cid %d, h_al %p, context %p.\n", + cid, h_al, p_csq ) ); + __ndi_proc_rej( p_csq, (mad_cm_rej_t*)p_mad ); + break; + + case CM_DREQ_ATTR_ID: + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI, + ("DREQ received for CEP with cid %d, h_al %p, context %p.\n", + cid, h_al, p_csq ) ); + __ndi_proc_dreq( p_csq ); + break; + + case CM_DREP_ATTR_ID: + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI, + ("DREP received for CEP with cid %d, h_al %p, context %p.\n", + cid, h_al, p_csq ) ); + __ndi_proc_drep( p_csq ); + break; + + case CM_RTU_ATTR_ID: + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI, + ("RTU received for CEP with cid %d, h_al %p, context %p.\n", + cid, h_al, p_csq ) ); + break; + + default: + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("Unhandled MAD attr ID %d for CEP with cid %d, h_al %p, context %p, new_cid %d .\n", + p_mad->attr_id, cid, h_al, p_csq, new_cid ) ); + } + } + + ib_put_mad( p_mad_el ); + } + + AL_EXIT( AL_DBG_NDI ); +} + +static void +__ndi_fill_cm_req( + IN net32_t qpn, + IN ual_ndi_req_cm_ioctl_in_t *p_req, + IN ib_path_rec_t *p_path_rec, + OUT iba_cm_req *p_cm_req) +{ + AL_ENTER( AL_DBG_NDI ); + + memset( p_cm_req, 0, sizeof(*p_cm_req) ); + + p_cm_req->service_id = IB_REQ_CM_RDMA_SID_PREFIX | (p_req->prot << 16) | p_req->dst_port; + p_cm_req->p_primary_path = p_path_rec; + + p_cm_req->qpn = qpn; + p_cm_req->qp_type = IB_QPT_RELIABLE_CONN; + p_cm_req->starting_psn = qpn; + + p_cm_req->p_pdata = (uint8_t *)&p_req->pdata; + p_cm_req->pdata_len = sizeof(p_req->pdata); + + p_cm_req->max_cm_retries = g_max_cm_retries; + p_cm_req->resp_res = p_req->resp_res; + p_cm_req->init_depth = p_req->init_depth; + + p_cm_req->remote_resp_timeout = + ib_path_rec_pkt_life( p_path_rec ) + CM_REMOTE_TIMEOUT; + if( p_cm_req->remote_resp_timeout > 0x1F ) + p_cm_req->remote_resp_timeout = 0x1F; + else if( p_cm_req->remote_resp_timeout < CM_MIN_REMOTE_TIMEOUT ) + p_cm_req->remote_resp_timeout = CM_MIN_REMOTE_TIMEOUT; + + p_cm_req->flow_ctrl = TRUE; /* HCAs must support end-to-end flow control. */ + + p_cm_req->local_resp_timeout = + ib_path_rec_pkt_life( p_path_rec ) + CM_LOCAL_TIMEOUT; + if( p_cm_req->local_resp_timeout > 0x1F ) + p_cm_req->local_resp_timeout = 0x1F; + else if( p_cm_req->local_resp_timeout < CM_MIN_LOCAL_TIMEOUT ) + p_cm_req->local_resp_timeout = CM_MIN_LOCAL_TIMEOUT; + + p_cm_req->rnr_retry_cnt = QP_ATTRIB_RNR_RETRY; + p_cm_req->retry_cnt = g_qp_retries; + + AL_EXIT( AL_DBG_NDI ); +} + + +NTSTATUS +__ndi_send_req( + IN IRP* p_irp + ) +{ + ib_api_status_t status; + nd_csq_t* p_csq = (nd_csq_t*)p_irp->Tail.Overlay.DriverContext[0]; + ib_path_rec_t *p_path_rec = p_irp->Tail.Overlay.DriverContext[1]; + ual_ndi_req_cm_ioctl_in_t *p_req = + (ual_ndi_req_cm_ioctl_in_t*)cl_ioctl_in_buf( p_irp ); + NTSTATUS nt_status; + ib_qp_handle_t h_qp; + iba_cm_req cm_req; + + AL_PRINT( TRACE_LEVEL_VERBOSE, AL_DBG_NDI, + ("[ CID = %d, h_al %p, context %p\n", + p_req->cid, p_csq->h_al, p_csq) ); + + p_irp->Tail.Overlay.DriverContext[1] = NULL; + + if( p_csq->state != NDI_CM_CONNECTING_QPR_SENT && + p_csq->state != NDI_CM_IDLE ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("Unexpected state: %d\n", p_csq->state) ); + return STATUS_CONNECTION_ACTIVE; + } + + h_qp = CONTAINING_RECORD( + al_hdl_ref( p_csq->h_al, p_req->h_qp, AL_OBJ_TYPE_H_QP ), + ib_qp_t, + obj ); + if( !h_qp ) + { + /* The QP was valid when the IOCTL first came in... */ + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("Invalid QP: %I64d\n", p_req->h_qp) ); + return STATUS_CONNECTION_ABORTED; + } + + /* Format ib_cm_req_t structure */ + __ndi_fill_cm_req( h_qp->num, p_req, p_path_rec, &cm_req ); + deref_al_obj( &h_qp->obj ); + + /* prepare CEP for connection */ + status = kal_cep_pre_req( + p_csq->h_al, p_csq->cid, &cm_req, QP_ATTRIB_RNR_NAK_TIMEOUT, NULL ); + if( status != STATUS_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("al_cep_pre_req returned %s.\n", ib_get_err_str( status )) ); + goto error; + } + + /* send CM REQ */ + status = al_cep_send_req( p_csq->h_al, p_csq->cid ); + if( status != IB_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("al_cep_send_req returned %s.\n", ib_get_err_str( status )) ); + goto error; + } + + /* SUCCESS ! */ + AL_EXIT( AL_DBG_NDI ); + return STATUS_PENDING; + +error: + switch( status ) + { + case IB_INVALID_HANDLE: + nt_status = STATUS_CANCELLED; + break; + + case IB_INVALID_STATE: + nt_status = STATUS_CONNECTION_ABORTED; + break; + + default: + nt_status = ib_to_ntstatus( status ); + } + + p_csq->state = NDI_CM_IDLE; + AL_EXIT( AL_DBG_NDI ); + return nt_status; +} + + +static void AL_API +__ndi_pr_query_cb( + ib_query_rec_t *p_query_rec ) +{ + cl_ioctl_handle_t p_irp; + uint8_t pkt_life; + ib_path_rec_t *p_path_rec; + nd_csq_t* p_csq = (nd_csq_t*)p_query_rec->query_context; + NTSTATUS status; + KIRQL irql; + + AL_ENTER( AL_DBG_NDI ); + + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI, + ("status is %d, count is %d, context %p\n", p_query_rec->status, + p_query_rec->result_cnt, p_query_rec->query_context) ); + + p_irp = IoCsqRemoveNextIrp( &p_csq->csq, (VOID*)(ULONG_PTR)UAL_NDI_REQ_CM ); + if( p_irp == NULL ) + { + goto exit; + } + +#pragma warning( disable:4305 ) + InterlockedExchangePointer( &p_csq->h_query, NULL ); +#pragma warning( default:4305 ) + + if( p_query_rec->status != IB_SUCCESS || p_query_rec->result_cnt == 0 ) + { + __ndi_acquire_lock( &p_csq->csq, &irql ); + if( p_csq->state != NDI_CM_INVALID ) + p_csq->state = NDI_CM_IDLE; + __ndi_release_lock( &p_csq->csq, irql ); + switch( p_query_rec->status ) + { + case IB_TIMEOUT: + case IB_CANCELED: + status = ib_to_ntstatus( p_query_rec->status ); + break; + + case IB_REMOTE_ERROR: + CL_ASSERT( p_query_rec->p_result_mad ); + switch( p_query_rec->p_result_mad->p_mad_buf->status ) + { + case IB_MAD_STATUS_BUSY: + case IB_SA_MAD_STATUS_NO_RESOURCES: + status = STATUS_TIMEOUT; + break; + + default: + status = STATUS_INVALID_PARAMETER_1 + + (p_query_rec->p_result_mad->p_mad_buf->status & 0xFF); + break; + } + break; + + default: + status = STATUS_HOST_UNREACHABLE; + break; + } + __ndi_complete_irp( p_csq, p_irp, status ); + goto exit; + } + + /* Path Record has been received ! */ + p_path_rec = ib_get_query_path_rec( p_query_rec->p_result_mad, 0 ); + + /* fix packet life */ + CL_ASSERT( p_path_rec ); + pkt_life = ib_path_rec_pkt_life( p_path_rec ) + g_pkt_life_modifier; + if( pkt_life > 0x1F ) + pkt_life = 0x1F; + + p_path_rec->pkt_life &= IB_PATH_REC_SELECTOR_MASK; + p_path_rec->pkt_life |= pkt_life; + + p_irp->Tail.Overlay.DriverContext[1] = p_path_rec; + + status = IoCsqInsertIrpEx( + &p_csq->csq, + p_irp, + NULL, + (VOID*)(ULONG_PTR)NDI_CM_CONNECTING_REQ_SENT + ); + if( !NT_SUCCESS( status ) ) + { + p_irp->Tail.Overlay.DriverContext[1] = NULL; + __ndi_complete_irp( p_csq, p_irp, status ); + } + else + { + /* + * Release the previous reference because IoCsqInsertIrpEx + * took a new one. + */ + nd_csq_release( p_csq ); /* Release IRP reference. */ + } + +exit: + if( p_query_rec->p_result_mad ) + ib_put_mad( p_query_rec->p_result_mad ); + + nd_csq_release( p_csq ); /* release path query reference */ + AL_EXIT( AL_DBG_NDI ); +} + + +/* + * Send asynchronous query to the SA for a path record. + * + * Called from the __ndi_insert_irp_ex function, so the CSQ lock is held. + */ +NTSTATUS +__ndi_pr_query( + IN IRP* p_irp + ) +{ + ib_query_req_t query_req; + ib_api_status_t status; + ual_ndi_req_cm_ioctl_in_t *p_req = + (ual_ndi_req_cm_ioctl_in_t*)cl_ioctl_in_buf( p_irp ); + nd_csq_t* p_csq = (nd_csq_t*)p_irp->Tail.Overlay.DriverContext[0]; + ib_gid_pair_t gids; + + AL_ENTER( AL_DBG_NDI ); + + if ( p_csq->state != NDI_CM_IDLE ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("STATUS_CONNECTION_ACTIVE: CID=%d, uhdl %#I64x, ref_cnt %d\n", + p_csq->cid, p_csq->h_qp, p_csq->ref_cnt ) ); + return STATUS_CONNECTION_ACTIVE; + } + + gids.src_gid = p_req->path.sgid; + gids.dest_gid = p_req->path.dgid; + + query_req.query_type = IB_QUERY_PATH_REC_BY_GIDS; + query_req.p_query_input = &gids; + query_req.port_guid = p_req->guid; + query_req.timeout_ms = g_sa_timeout; + query_req.retry_cnt = g_sa_retries; + query_req.flags = 0; /* IB_FLAGS_SYNC */ + query_req.query_context = p_csq; + query_req.pfn_query_cb = __ndi_pr_query_cb; + + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI, + ("Query for path from %I64x to %I64x\n", + p_req->guid, ib_gid_get_guid( &p_req->path.dgid )) ); + + nd_csq_ref( p_csq ); /* take path query reference */ + status = ib_query( p_csq->h_al, &query_req, &p_csq->h_query ); + if( status != IB_SUCCESS ) + { + p_csq->state = NDI_CM_IDLE; + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("ib_query failed (%d)\n", status) ); + nd_csq_release( p_csq ); /* release path query reference */ + return ib_to_ntstatus( status ); + } + + AL_EXIT( AL_DBG_NDI ); + return STATUS_PENDING; +} + + +NTSTATUS +ndi_req_cm( + IN ib_al_handle_t h_al, + IN IRP *p_irp + ) +{ + NTSTATUS status; + nd_csq_t* p_csq; + ual_ndi_req_cm_ioctl_in_t *p_req = + (ual_ndi_req_cm_ioctl_in_t*)cl_ioctl_in_buf( p_irp ); + + AL_ENTER( AL_DBG_NDI ); + + p_csq = kal_cep_get_context( h_al, p_req->cid, nd_cm_handler, nd_csq_ref ); + if( p_csq == NULL ) + { + status = nd_csq_init( h_al, p_req->cid, p_req->h_qp, &p_csq ); + if( status != STATUS_SUCCESS ) + goto err; + } + + p_irp->Tail.Overlay.DriverContext[0] = p_csq; + + if( p_req->path.dlid != 0 ) + { + /* fix packet life */ + uint8_t pkt_life = ib_path_rec_pkt_life( &p_req->path ) + g_pkt_life_modifier; + if( pkt_life > 0x1F ) + pkt_life = 0x1F; + + p_req->path.pkt_life &= IB_PATH_REC_SELECTOR_MASK; + p_req->path.pkt_life |= pkt_life; + + p_irp->Tail.Overlay.DriverContext[1] = &p_req->path; + status = IoCsqInsertIrpEx( + &p_csq->csq, + p_irp, + NULL, + (VOID*)(ULONG_PTR)NDI_CM_CONNECTING_REQ_SENT + ); + } + else + { + status = IoCsqInsertIrpEx( + &p_csq->csq, + p_irp, + NULL, + (VOID*)(ULONG_PTR)NDI_CM_CONNECTING_QPR_SENT + ); + } + + nd_csq_release( p_csq ); +err: + AL_EXIT( AL_DBG_NDI ); + return status; +} + + +/******************************************************************* + * + * RTU CM request + * + ******************************************************************/ + +static void +__ndi_do_rtu( + IN DEVICE_OBJECT* p_dev_obj, + IN PIRP p_irp ) +{ + ib_api_status_t status; + nd_csq_t* p_csq = p_irp->Tail.Overlay.DriverContext[0]; + KIRQL irql; + NTSTATUS nt_status; + + UNUSED_PARAM(p_dev_obj); + + AL_ENTER( AL_DBG_NDI ); + + /* free the work item if any */ + if ( p_irp->Tail.Overlay.DriverContext[1] ) + { + IoFreeWorkItem( p_irp->Tail.Overlay.DriverContext[1] ); + p_irp->Tail.Overlay.DriverContext[1] = NULL; + nd_csq_release( p_csq ); /* Release work item reference. */ + } + + __ndi_acquire_lock( &p_csq->csq, &irql ); + if( p_csq->state != NDI_CM_CONNECTING_REP_RCVD ) + { + __ndi_release_lock( &p_csq->csq, irql ); + nt_status = STATUS_CONNECTION_ABORTED; + goto exit; + } + __ndi_release_lock( &p_csq->csq, irql ); + + /* change the QP state to RTS */ + status = __ndi_qp2rts( p_csq, p_irp ); + if ( status != IB_SUCCESS ) + { + goto err; + } + + /* send RTU */ + status = al_cep_rtu( p_csq->h_al, p_csq->cid, NULL, 0 ); + if( status != IB_SUCCESS ) + { +err: + /* + * Reject the connection. Note that we don't free the CEP since the + * usermode INDConnector object references it, and the CEP will be + * freed when that object is freed. + */ + al_cep_rej( p_csq->h_al, p_csq->cid, IB_REJ_INSUF_QP, NULL, 0, NULL, 0 ); + + __cep_timewait_qp( p_csq ); + + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI, + ("al_cep_rtu returned %s.\n", ib_get_err_str( status )) ); + + __ndi_acquire_lock( &p_csq->csq, &irql ); + if( p_csq->state != NDI_CM_INVALID ) + p_csq->state = NDI_CM_IDLE; + __ndi_release_lock( &p_csq->csq, irql ); + + nt_status = STATUS_CONNECTION_ABORTED; + goto exit; + } + + __ndi_acquire_lock( &p_csq->csq, &irql ); + if( p_csq->state == NDI_CM_CONNECTING_REP_RCVD ) + p_csq->state = NDI_CM_CONNECTED; + __ndi_release_lock( &p_csq->csq, irql ); + + nt_status = STATUS_SUCCESS; + +exit: + __ndi_complete_irp( p_csq, p_irp, nt_status ); + AL_EXIT( AL_DBG_NDI ); +} + + +cl_status_t +ndi_rtu_cm( + IN nd_csq_t *p_csq, + IN PIRP p_irp + ) +{ + IO_STACK_LOCATION *p_io_stack; + + AL_ENTER( AL_DBG_NDI ); + + p_irp->Tail.Overlay.DriverContext[0] = p_csq; + nd_csq_ref( p_csq ); /* Take IRP reference. */ + p_io_stack = IoGetCurrentIrpStackLocation( p_irp ); + p_irp->Tail.Overlay.DriverContext[1] = IoAllocateWorkItem( p_io_stack->DeviceObject ); + + IoMarkIrpPending( p_irp ); + if ( p_irp->Tail.Overlay.DriverContext[1] ) + { /* asyncronous performing */ + /* take a ref to prevent QP destroy before calling work item */ + nd_csq_ref( p_csq ); /* Take work item reference. */ + IoQueueWorkItem( p_irp->Tail.Overlay.DriverContext[1], + __ndi_do_rtu, DelayedWorkQueue, p_irp ); + } + else + { /* syncronous performing */ + __ndi_do_rtu( p_io_stack->DeviceObject, p_irp ); + } + + AL_EXIT( AL_DBG_NDI ); + return CL_PENDING; +} + + +/******************************************************************* + * + * REP CM request + * + ******************************************************************/ + +static void +__ndi_do_rep( + IN DEVICE_OBJECT* p_dev_obj, + IN PIRP p_irp ) +{ + nd_csq_t* p_csq = p_irp->Tail.Overlay.DriverContext[0]; + ib_api_status_t status; + KIRQL irql; + NTSTATUS nt_status; + + UNUSED_PARAM(p_dev_obj); + + AL_PRINT( TRACE_LEVEL_VERBOSE, AL_DBG_NDI, ("[ CID = %d\n", p_csq->cid) ); + + /* free the work item if any */ + CL_ASSERT( p_irp->Tail.Overlay.DriverContext[1] != NULL ); + IoFreeWorkItem( p_irp->Tail.Overlay.DriverContext[1] ); + p_irp->Tail.Overlay.DriverContext[1] = NULL; + + /* change the QP state to RTS */ + status = __ndi_qp2rts( p_csq, p_irp ); + if ( status != IB_SUCCESS ) + { + goto err; + } + + /* send REP */ + status = al_cep_send_rep ( p_csq->h_al, p_csq->cid ); + if( status != IB_SUCCESS ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("al_cep_send_rep returned %s\n", ib_get_err_str(status)) ); +err: + /* + * Reject the connection. Note that we don't free the CEP since the + * usermode INDConnector object references it, and the CEP will be + * freed when that object is freed. + */ + al_cep_rej( p_csq->h_al, p_csq->cid, IB_REJ_INSUF_QP, NULL, 0, NULL, 0 ); + + /* transit QP to error state */ + __cep_timewait_qp( p_csq ); + + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("al_cep_rtu returned %s.\n", ib_get_err_str( status )) ); + __ndi_acquire_lock( &p_csq->csq, &irql ); + if( p_csq->state != NDI_CM_INVALID ) + p_csq->state = NDI_CM_IDLE; + __ndi_release_lock( &p_csq->csq, irql ); + if (status == IB_INVALID_STATE ) + nt_status = STATUS_CONNECTION_ABORTED; + /* The HCA driver will return IB_INVALID_PARAMETER if the QP is in the wrong state. */ + else if( status == IB_INVALID_HANDLE || status == IB_INVALID_PARAMETER ) + nt_status = STATUS_CANCELLED; + else + nt_status = STATUS_INSUFFICIENT_RESOURCES; + goto exit; + } + + __ndi_acquire_lock( &p_csq->csq, &irql ); + if( p_csq->state == NDI_CM_CONNECTING_REP_SENT ) + p_csq->state = NDI_CM_CONNECTED; + __ndi_release_lock( &p_csq->csq, irql ); + nt_status = STATUS_SUCCESS; + +exit: + __ndi_complete_irp( p_csq, p_irp, nt_status ); + nd_csq_release( p_csq ); /* Release work item reference. */ + AL_EXIT( AL_DBG_NDI ); +} + +static void +__ndi_fill_cm_rep( + IN net32_t qpn, + IN ual_ndi_rep_cm_ioctl_in_t *p_rep, + OUT iba_cm_rep *p_cm_rep) +{ + AL_ENTER( AL_DBG_NDI ); + + memset( p_cm_rep, 0, sizeof(*p_cm_rep) ); + + p_cm_rep->p_pdata = p_rep->pdata; + p_cm_rep->pdata_len = sizeof(p_rep->pdata); + + p_cm_rep->qpn = qpn; + + p_cm_rep->init_depth = p_rep->init_depth; + p_cm_rep->failover_accepted = IB_FAILOVER_ACCEPT_UNSUPPORTED; + p_cm_rep->flow_ctrl = TRUE; /* HCAs must support end-to-end flow control. */ + p_cm_rep->rnr_retry_cnt = QP_ATTRIB_RNR_RETRY; + + AL_EXIT( AL_DBG_NDI ); +} + + +NTSTATUS +__ndi_send_rep( + IN nd_csq_t *p_csq, + IN PIRP p_irp ) +{ + IO_STACK_LOCATION *p_io_stack; + ib_qp_handle_t h_qp; + iba_cm_rep cm_rep; + ib_api_status_t status; + ual_ndi_rep_cm_ioctl_in_t *p_rep = + (ual_ndi_rep_cm_ioctl_in_t*)cl_ioctl_in_buf( p_irp ); + + AL_PRINT( TRACE_LEVEL_VERBOSE, AL_DBG_NDI, + ("[ CID = %d\n", p_csq->cid) ); + + switch( p_csq->state ) + { + case NDI_CM_CONNECTING_REQ_RCVD: + break; + + case NDI_CM_CONNECTED_DREQ_RCVD: + AL_EXIT( AL_DBG_NDI ); + return STATUS_CONNECTION_ABORTED; + + default: + AL_EXIT( AL_DBG_NDI ); + return STATUS_CONNECTION_ACTIVE; + } + + p_io_stack = IoGetCurrentIrpStackLocation( p_irp ); + p_irp->Tail.Overlay.DriverContext[1] = IoAllocateWorkItem( p_io_stack->DeviceObject ); + if( p_irp->Tail.Overlay.DriverContext[1] == NULL ) + { + AL_EXIT( AL_DBG_NDI ); + return STATUS_NO_MEMORY; + } + nd_csq_ref( p_csq ); /* Take work item reference. */ + + h_qp = CONTAINING_RECORD( + al_hdl_ref( p_csq->h_al, p_csq->h_qp, AL_OBJ_TYPE_H_QP ), + ib_qp_t, + obj ); + if( !h_qp ) + { + /* The QP was valid when the IOCTL first came in... */ + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("Invalid QP: %I64d\n", p_rep->h_qp) ); + status = IB_INVALID_HANDLE; + goto err; + } + + /* Format ib_cm_req_t structure */ + __ndi_fill_cm_rep( h_qp->num, p_rep, &cm_rep ); + deref_al_obj( &h_qp->obj ); + + /* prepare Passive CEP for connection */ + status = kal_cep_pre_rep( + p_csq->h_al, p_csq->cid, &cm_rep, QP_ATTRIB_RNR_NAK_TIMEOUT, NULL ); + if( status != IB_SUCCESS ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("kal_cep_pre_rep returned %s.\n", ib_get_err_str( status )) ); +err: + IoFreeWorkItem( p_irp->Tail.Overlay.DriverContext[1] ); + p_irp->Tail.Overlay.DriverContext[1] = NULL; + nd_csq_release( p_csq ); /* Release work item reference. */ + switch (status) + { + case IB_INVALID_HANDLE: + return STATUS_CANCELLED; + case IB_INVALID_STATE: + return STATUS_CONNECTION_ABORTED; + case IB_RESOURCE_BUSY: + return STATUS_CONNECTION_ACTIVE; + default: + return ib_to_ntstatus( status ); + } + } + + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI, + ("Prepared Passive CEP with cid %d, h_al %p, context %p\n", + p_csq->cid, p_csq->h_al, h_qp ) ); + + /* + * transfer work to a worker thread so that QP transitions can be done + * at PASSIVE_LEVEL + */ + IoQueueWorkItem( p_irp->Tail.Overlay.DriverContext[1], + __ndi_do_rep, DelayedWorkQueue, p_irp ); + + AL_EXIT( AL_DBG_NDI ); + return STATUS_PENDING; +} + + +NTSTATUS +ndi_rep_cm( + IN ib_al_handle_t h_al, + IN PIRP p_irp + ) +{ + NTSTATUS status; + nd_csq_t* p_csq; + ual_ndi_rep_cm_ioctl_in_t *p_rep = + (ual_ndi_rep_cm_ioctl_in_t*)cl_ioctl_in_buf( p_irp ); + KIRQL irql; + + AL_ENTER( AL_DBG_NDI ); + + p_csq = kal_cep_get_context( h_al, p_rep->cid, nd_cm_handler, nd_csq_ref ); + if( p_csq == NULL ) + { + status = STATUS_CONNECTION_ABORTED; + goto err; + } + + p_csq->h_qp = p_rep->h_qp; + + p_irp->Tail.Overlay.DriverContext[0] = p_csq; + + __ndi_acquire_lock( &p_csq->csq, &irql ); + status = __ndi_send_rep( p_csq, p_irp ); + if( status == STATUS_PENDING ) + { + /* + * We're going to keep the IRP dangling for a bit - take a reference + * on the QP until it completes. + */ + nd_csq_ref( p_csq ); /* Take IRP reference. */ + p_csq->state = NDI_CM_CONNECTING_REP_SENT; + IoMarkIrpPending( p_irp ); + } + __ndi_release_lock( &p_csq->csq, irql ); + + nd_csq_release( p_csq ); +err: + AL_PRINT( TRACE_LEVEL_VERBOSE, AL_DBG_NDI, ("] returning %08x\n", status) ); + return status; +} + + + +/******************************************************************* + * + * DREQ CM request + * + ******************************************************************/ + + +NTSTATUS +__ndi_send_dreq( + IN IRP* p_irp + ) +{ + nd_csq_t *p_csq = (nd_csq_t*)p_irp->Tail.Overlay.DriverContext[0]; + IO_STACK_LOCATION *p_io_stack; + ib_api_status_t status; + NTSTATUS nt_status; + + AL_ENTER( AL_DBG_NDI ); + + if ( p_csq->state != NDI_CM_CONNECTED && + p_csq->state != NDI_CM_CONNECTED_DREQ_RCVD ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("STATUS_CONNECTION_ACTIVE: CID = %d, uhdl %#I64x, ref_cnt %d\n", + p_csq->cid, p_csq->h_qp, p_csq->ref_cnt ) ); + return STATUS_CONNECTION_INVALID; + } + + /* + * Allocate a work item to perform the QP transition when disconnection + * completes (or the IRP is cancelled). We allocate here to trap errors + * properly. + */ + p_io_stack = IoGetCurrentIrpStackLocation( p_irp ); + p_irp->Tail.Overlay.DriverContext[1] = IoAllocateWorkItem( p_io_stack->DeviceObject ); + if( p_irp->Tail.Overlay.DriverContext[1] == NULL ) + { + AL_EXIT( AL_DBG_NDI ); + return STATUS_NO_MEMORY; + } + nd_csq_ref( p_csq ); /* Take work item reference. */ + + status = al_cep_dreq( p_csq->h_al, p_csq->cid, NULL, 0 ); + switch( status ) + { + case IB_INVALID_STATE: + /* + * We're going to keep the IRP dangling for a bit - take a reference + * on the CSQ until it completes. + */ + nd_csq_ref( p_csq ); /* Take IRP reference. */ + /* We might have just received a DREQ, so try sending a DREP. */ + IoMarkIrpPending( p_irp ); + __ndi_queue_drep( p_irp ); + AL_EXIT( AL_DBG_NDI ); + return STATUS_INVALID_DEVICE_STATE; + + case IB_SUCCESS: + AL_EXIT( AL_DBG_NDI ); + return STATUS_PENDING; + + case IB_INVALID_HANDLE: + nt_status = STATUS_CONNECTION_INVALID; + break; + default: + nt_status = ib_to_ntstatus( status ); + } + IoFreeWorkItem( p_irp->Tail.Overlay.DriverContext[1] ); + p_irp->Tail.Overlay.DriverContext[1] = NULL; + nd_csq_release( p_csq ); /* Release work item reference. */ + AL_EXIT( AL_DBG_NDI ); + return nt_status; +} + + +NTSTATUS +ndi_dreq_cm( + IN nd_csq_t* p_csq, + IN PIRP p_irp + ) +{ + NTSTATUS status; + + AL_ENTER( AL_DBG_NDI ); + + p_irp->Tail.Overlay.DriverContext[0] = p_csq; + + status = IoCsqInsertIrpEx( + &p_csq->csq, + p_irp, + NULL, + (VOID*)(ULONG_PTR)NDI_CM_DISCONNECTING + ); + /* + * Note that if al_cep_dreq returned IB_INVALID_STATE, we queued the + * work item and will try sending the DREP and move the QP to error. + * + * The IRP should never be queued if the work item is queued, so + * we trap the special error code for INVALID_STATE. + */ + if( status == STATUS_INVALID_DEVICE_STATE ) + status = STATUS_PENDING; + + AL_EXIT( AL_DBG_NDI ); + return status; +} + + +NTSTATUS +ndi_listen_cm( + IN ib_al_handle_t h_al, + IN ib_cep_listen_t *p_listen, + OUT net32_t *p_cid, + OUT size_t *p_ret_bytes + ) +{ + NTSTATUS status; + net32_t cid; + ib_api_status_t ib_status; + nd_csq_t *p_csq; + KIRQL irql; + + AL_ENTER( AL_DBG_NDI ); + + ib_status = al_create_cep( h_al, NULL, NULL, NULL, &cid ); + if( ib_status != IB_SUCCESS ) + { + AL_EXIT( AL_DBG_NDI ); + return ib_to_ntstatus( ib_status ); + } + + status = nd_csq_init( h_al, cid, 0, &p_csq ); + if( status != STATUS_SUCCESS ) + { + kal_cep_destroy( h_al, cid, STATUS_SUCCESS ); + AL_EXIT( AL_DBG_NDI ); + return status; + } + + __ndi_acquire_lock( &p_csq->csq, &irql ); + p_csq->state = NDI_CM_LISTEN; + __ndi_release_lock( &p_csq->csq, irql ); + + if( (p_listen->svc_id & 0xFFFF) == 0 ) + { + p_listen->svc_id |= (USHORT)cid | (USHORT)(cid >> 16); + } + + ib_status = al_cep_listen( h_al, cid, p_listen ); + if( ib_status == IB_SUCCESS ) + { + *p_cid = cid; + *p_ret_bytes = sizeof(*p_cid); + } + + nd_csq_release( p_csq ); + status = ib_to_ntstatus( ib_status ); + AL_EXIT( AL_DBG_NDI ); + return status; +} + + +NTSTATUS +__ndi_get_req( + IN nd_csq_t *p_csq, + IN IRP* p_irp + ) +{ + AL_PRINT( TRACE_LEVEL_VERBOSE, AL_DBG_NDI, ("[ CID = %d\n", p_csq->cid) ); + + if( p_csq->state != NDI_CM_LISTEN ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_NDI, + ("] Invalid state (%d).\n", p_csq->state) ); + return STATUS_INVALID_DEVICE_REQUEST; + } + + /* Check the MAD list. */ + if( p_csq->p_mad_head != NULL ) + { + ib_mad_element_t* p_mad = p_csq->p_mad_head; + net32_t cid = (net32_t)(ULONG_PTR)p_mad->send_context1; + p_csq->p_mad_head = p_mad->p_next; + p_mad->p_next = NULL; + + *(net32_t*)cl_ioctl_out_buf( p_irp ) = cid; + p_irp->IoStatus.Information = sizeof(net32_t); + p_irp->IoStatus.Status = STATUS_SUCCESS; + IoMarkIrpPending( p_irp ); + IoCompleteRequest( p_irp, IO_NETWORK_INCREMENT ); + ib_put_mad( p_mad ); + AL_PRINT( TRACE_LEVEL_VERBOSE, AL_DBG_NDI, ("] Returned new CID = %d\n", cid) ); + return STATUS_INVALID_DEVICE_STATE; + } + + AL_PRINT( TRACE_LEVEL_VERBOSE, AL_DBG_NDI, ("] Queueing IRP\n") ); + return STATUS_PENDING; +} + + +NTSTATUS +ndi_get_req_cm( + IN nd_csq_t *p_csq, + IN PIRP p_irp + ) +{ + NTSTATUS status; + + AL_ENTER( AL_DBG_NDI ); + + status = IoCsqInsertIrpEx( + &p_csq->csq, + p_irp, + NULL, + (VOID*)(ULONG_PTR)NDI_CM_LISTEN + ); + + /* + * __ndi_get_req will return STATUS_INVALID_DEVICE_STATE to prevent the IRP + * from being inserted into the CSQ because the IRP was immediately completed. + * In this case, we need to return STATUS_PENDING. + */ + if( status == STATUS_INVALID_DEVICE_STATE ) + { + status = STATUS_PENDING; + } + + AL_EXIT( AL_DBG_NDI ); + return status; +} + + + diff --git a/branches/WOF2-3/core/al/kernel/al_ndi_cm.h b/branches/WOF2-3/core/al/kernel/al_ndi_cm.h new file mode 100644 index 00000000..554e3978 --- /dev/null +++ b/branches/WOF2-3/core/al/kernel/al_ndi_cm.h @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: al_proxy.h 33 2005-07-11 19:51:17Z ftillier $ + */ + +/* + * Abstract: + * This header file defines data structures for the kernel-mode NDI support + * + * Environment: + * Kernel . + */ + + +#ifndef _AL_NDI_CM_H_ +#define _AL_NDI_CM_H_ + +#include "complib/cl_ioctl_osd.h" + +/* QP creation parameters */ +#define QP_ATTRIB_RESPONDER_RESOURCES 4 +#define QP_ATTRIB_INITIATOR_DEPTH 4 +#define QP_ATTRIB_RETRY_COUNT 6 +#define QP_ATTRIB_RNR_RETRY 7 +#define QP_ATTRIB_RNR_NAK_TIMEOUT 8 /* 16 ms */ + +#define QP_ATTRIB_SQ_DEPTH 16 + +/* CM timeouts */ +#define CM_MIN_LOCAL_TIMEOUT (18) +#define CM_LOCAL_TIMEOUT (1) +#define CM_MIN_REMOTE_TIMEOUT (18) +#define CM_REMOTE_TIMEOUT (2) +#define CM_RETRIES 4 + +typedef enum _ndi_cm_state +{ + NDI_CM_IDLE, + NDI_CM_LISTEN, + NDI_CM_CONNECTING_QPR_SENT, // QPR = Query path record + NDI_CM_CONNECTING_REQ_SENT, + NDI_CM_CONNECTING_REQ_RCVD, + NDI_CM_CONNECTING_REP_SENT, + NDI_CM_CONNECTING_REP_RCVD, + NDI_CM_CONNECTED, + NDI_CM_DISCONNECTING, + NDI_CM_CONNECTED_DREQ_RCVD, + NDI_CM_INVALID + +} ndi_cm_state_t; + +typedef struct _ib_qp ib_qp_t; + +typedef struct _nd_csq +{ + IO_CSQ csq; + LIST_ENTRY queue; + ib_al_handle_t h_al; + union { + uint64_t h_qp; + ib_mad_element_t *p_mad_head; + }; + union { + ib_query_handle_t h_query; + ib_mad_element_t *p_mad_tail; + }; + net32_t cid; + ndi_cm_state_t state; + PIO_WORKITEM p_workitem; + volatile LONG ref_cnt; + KSPIN_LOCK lock; + +} nd_csq_t; + + +ib_api_status_t +ndi_modify_qp( + IN const ib_qp_handle_t h_qp, + IN const ib_qp_mod_t* const p_qp_mod, + IN const uint32_t buf_size, + IN uint8_t* const p_outbuf); + +void +nd_csq_ref( nd_csq_t* p_csq ); + +void +nd_csq_release( nd_csq_t* p_csq ); + +void +nd_cm_handler( + IN const ib_al_handle_t h_al, + IN const net32_t cid ); + +NTSTATUS +ndi_req_cm( + IN ib_al_handle_t h_al, + IN PIRP p_irp + ); + +NTSTATUS +ndi_rep_cm( + IN ib_al_handle_t h_al, + IN PIRP p_irp + ); + +cl_status_t +ndi_rtu_cm( + IN nd_csq_t *p_csq, + IN PIRP p_irp + ); + +NTSTATUS +ndi_dreq_cm( + IN nd_csq_t *p_csq, + IN PIRP p_irp + ); + +void +ndi_cancel_cm_irps( + IN nd_csq_t *p_csq + ); + +NTSTATUS +ndi_listen_cm( + IN ib_al_handle_t h_al, + IN ib_cep_listen_t *p_listen, + OUT net32_t *p_cid, + OUT size_t *p_ret_bytes + ); + +NTSTATUS +ndi_get_req_cm( + IN nd_csq_t *p_csq, + IN PIRP p_irp + ); + +#endif + diff --git a/branches/WOF2-3/core/al/kernel/al_ndi_cq.c b/branches/WOF2-3/core/al/kernel/al_ndi_cq.c new file mode 100644 index 00000000..5ae46422 --- /dev/null +++ b/branches/WOF2-3/core/al/kernel/al_ndi_cq.c @@ -0,0 +1,294 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: al_proxy_verbs.c 548 2006-11-27 20:03:51Z leonidk $ + */ + + +#include +#include +#include +#include "al.h" +#include "al_debug.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "al_ndi_cq.tmh" +#endif + +#include "al_dev.h" +/* Get the internal definitions of apis for the proxy */ +#include "al_ca.h" +#include "al_cq.h" +#include "ib_common.h" + +/******************************************************************* + * + * Helpers + * + ******************************************************************/ + +#pragma warning(disable:4706) +static inline void __ndi_flush_que( + IN ndi_cq_csq_t* p_ndi_csq, + IN NTSTATUS completion_code + ) +{ + PIRP Irp; + while( Irp = IoCsqRemoveNextIrp( &p_ndi_csq->csq, NULL ) ) + { + cl_ioctl_complete( Irp, completion_code, 0 ); + deref_al_obj( &p_ndi_csq->h_cq->obj ); + } +} +#pragma warning(default:4706) + +/******************************************************************* + * + * Callbacks + * + ******************************************************************/ + +#pragma warning(disable:4706) +void ndi_cq_compl_cb( + IN const ib_cq_handle_t h_cq, + IN void *cq_context ) +{ + PIRP Irp; + ndi_cq_csq_t*p_ndi_csq = &h_cq->compl; + UNUSED_PARAM( cq_context ); + + AL_ENTER( AL_DBG_NDI ); + + while( Irp = IoCsqRemoveNextIrp( &p_ndi_csq->csq, NULL ) ) + { + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = 0; + IoCompleteRequest( Irp, IO_NETWORK_INCREMENT ); + deref_al_obj( &p_ndi_csq->h_cq->obj ); + } + + AL_EXIT( AL_DBG_NDI ); +} +#pragma warning(default:4706) + +void ndi_cq_error_cb( + IN ib_async_event_rec_t *p_err_rec) +{ + ib_cq_handle_t h_cq = p_err_rec->handle.h_cq; + AL_ENTER( AL_DBG_NDI ); + __ndi_flush_que( &h_cq->compl, STATUS_INTERNAL_ERROR ); + __ndi_flush_que( &h_cq->error, STATUS_INTERNAL_ERROR ); + AL_EXIT( AL_DBG_NDI ); +} + +/******************************************************************* + * + * Public routines + * + ******************************************************************/ + +/* flush a queue of pending requests */ +void +ndi_cq_flush_ques( + IN ib_cq_handle_t h_cq + ) +{ + AL_ENTER( AL_DBG_NDI ); + if ( h_cq->pfn_user_comp_cb == ndi_cq_compl_cb ) + { + __ndi_flush_que( &h_cq->compl, STATUS_CANCELLED ); + __ndi_flush_que( &h_cq->error, STATUS_CANCELLED ); + } + AL_EXIT( AL_DBG_NDI ); +} + + +/******************************************************************* + * + * CSQ + * + ******************************************************************/ + +static VOID __ndi_insert_irp( + IN PIO_CSQ Csq, + IN PIRP Irp + ) +{ + ndi_cq_csq_t *p_ndi_csq = (ndi_cq_csq_t*)Csq; + + AL_ENTER( AL_DBG_NDI ); + InsertTailList( &p_ndi_csq->queue, &Irp->Tail.Overlay.ListEntry ); + AL_EXIT( AL_DBG_NDI ); +} + +static VOID __ndi_remove_irp( + IN PIO_CSQ Csq, + IN PIRP Irp + ) +{ + UNUSED_PARAM( Csq ); + + AL_ENTER( AL_DBG_NDI ); + RemoveEntryList( &Irp->Tail.Overlay.ListEntry ); + AL_EXIT( AL_DBG_NDI ); +} + +static PIRP __ndi_peek_next_irp( + IN PIO_CSQ Csq, + IN PIRP Irp, + IN PVOID PeekContext + ) +{ + PIRP nextIrp = NULL; + PLIST_ENTRY nextEntry; + PLIST_ENTRY listHead; + ndi_cq_csq_t *p_ndi_csq = (ndi_cq_csq_t*)Csq; + + AL_ENTER( AL_DBG_NDI ); + + listHead = &p_ndi_csq->queue; + + // + // If the IRP is NULL, we will start peeking from the listhead, else + // we will start from that IRP onwards. This is done under the + // assumption that new IRPs are always inserted at the tail. + // + + if(Irp == NULL) + nextEntry = listHead->Flink; + else + nextEntry = Irp->Tail.Overlay.ListEntry.Flink; + + while(nextEntry != listHead) { + nextIrp = CONTAINING_RECORD(nextEntry, IRP, Tail.Overlay.ListEntry); + + // + // If context is present, continue until you find a matching one. + // Else you break out as you got next one. + // + + if(PeekContext) + { + /* for now PeekContext is not used */ + } + else + { + break; + } + + nextIrp = NULL; + nextEntry = nextEntry->Flink; + } + + AL_EXIT( AL_DBG_NDI ); + return nextIrp; +} + +static VOID __ndi_acquire_lock( + IN PIO_CSQ Csq, + OUT PKIRQL Irql + ) +{ + ndi_cq_csq_t *p_ndi_csq = (ndi_cq_csq_t*)Csq; + ib_cq_handle_t h_cq = p_ndi_csq->h_cq; + UNUSED_PARAM( Irql ); + + AL_ENTER( AL_DBG_NDI ); + cl_spinlock_acquire( &h_cq->obj.lock ); + AL_EXIT( AL_DBG_NDI ); +} + +static VOID __ndi_release_lock( + IN PIO_CSQ Csq, + IN KIRQL Irql + ) +{ + ndi_cq_csq_t *p_ndi_csq = (ndi_cq_csq_t*)Csq; + ib_cq_handle_t h_cq = p_ndi_csq->h_cq; + UNUSED_PARAM( Irql ); + + AL_ENTER( AL_DBG_NDI ); + cl_spinlock_release( &h_cq->obj.lock ); + AL_EXIT( AL_DBG_NDI ); +} + +static VOID __ndi_complete_cancelled_irp( + IN PIO_CSQ Csq, + IN PIRP Irp + ) +{ + ndi_cq_csq_t *p_ndi_csq = (ndi_cq_csq_t*)Csq; + ib_cq_handle_t h_cq = p_ndi_csq->h_cq; + + AL_ENTER( AL_DBG_NDI ); + cl_ioctl_complete( Irp, CL_CANCELED, 0 ); + deref_al_obj( &h_cq->obj ); + AL_EXIT( AL_DBG_NDI ); +} + +NTSTATUS +ndi_cq_init( + IN ib_cq_handle_t h_cq ) +{ + + NTSTATUS status; + + AL_ENTER( AL_DBG_NDI ); + + status = IoCsqInitialize( &h_cq->compl.csq, + __ndi_insert_irp, __ndi_remove_irp, + __ndi_peek_next_irp, __ndi_acquire_lock, + __ndi_release_lock, __ndi_complete_cancelled_irp ); + if ( !NT_SUCCESS( status ) ) + goto exit; + + status = IoCsqInitialize( &h_cq->error.csq, + __ndi_insert_irp, __ndi_remove_irp, + __ndi_peek_next_irp, __ndi_acquire_lock, + __ndi_release_lock, __ndi_complete_cancelled_irp ); + if ( !NT_SUCCESS( status ) ) + goto exit; + + InitializeListHead( &h_cq->compl.queue ); + InitializeListHead( &h_cq->error.queue ); + h_cq->compl.h_cq = h_cq; + h_cq->error.h_cq = h_cq; + status = STATUS_SUCCESS; + +exit: + AL_EXIT( AL_DBG_NDI ); + return status; +} + + + diff --git a/branches/WOF2-3/core/al/kernel/al_ndi_cq.h b/branches/WOF2-3/core/al/kernel/al_ndi_cq.h new file mode 100644 index 00000000..21b339a7 --- /dev/null +++ b/branches/WOF2-3/core/al/kernel/al_ndi_cq.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: al_proxy.h 33 2005-07-11 19:51:17Z ftillier $ + */ + +/* + * Abstract: + * This header file defines data structures for the kernel-mode NDI support + * + * Environment: + * Kernel . + */ + + +#ifndef _AL_NDI_CQ_H_ +#define _AL_NDI_CQ_H_ + +void +ndi_cq_flush_ques( + IN ib_cq_handle_t h_cq ); + +NTSTATUS +ndi_cq_init( + IN ib_cq_handle_t h_cq ); + +void +ndi_cq_compl_cb( + IN const ib_cq_handle_t h_cq, + IN void *cq_context ); + +void +ndi_cq_error_cb( + IN ib_async_event_rec_t *p_err_rec ); + +#endif diff --git a/branches/WOF2-3/core/al/kernel/al_pnp.c b/branches/WOF2-3/core/al/kernel/al_pnp.c new file mode 100644 index 00000000..cca4fde6 --- /dev/null +++ b/branches/WOF2-3/core/al/kernel/al_pnp.c @@ -0,0 +1,1824 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include + +#include "al.h" +#include "al_debug.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "al_pnp.tmh" +#endif +#include "al_mgr.h" +#include "al_pnp.h" +#include "ib_common.h" +#include "al_ioc_pnp.h" + + +#define PNP_CA_VECTOR_MIN 0 +#define PNP_CA_VECTOR_GROW 10 + + +/* ib_pnp_event_t values converted to text strings. */ +char* ib_pnp_event_str[] = +{ + "IB_PNP_CA_ADD", + "IB_PNP_CA_REMOVE", + "IB_PNP_PORT_ADD", + "IB_PNP_PORT_REMOVE", + "IB_PNP_PORT_INIT", + "IB_PNP_PORT_ARMED", + "IB_PNP_PORT_ACTIVE", + "IB_PNP_PORT_DOWN", + "IB_PNP_PKEY_CHANGE", + "IB_PNP_SM_CHANGE", + "IB_PNP_GID_CHANGE", + "IB_PNP_LID_CHANGE", + "IB_PNP_SUBNET_TIMEOUT_CHANGE", + "IB_PNP_IOU_ADD", + "IB_PNP_IOU_REMOVE", + "IB_PNP_IOC_ADD", + "IB_PNP_IOC_REMOVE", + "IB_PNP_IOC_PATH_ADD", + "IB_PNP_IOC_PATH_REMOVE" +}; + + +/* + * Declarations. + */ +static void +__pnp_free( + IN al_obj_t *p_obj ); + + +/* + * Compares two context for inserts/lookups in a flexi map. Keys are the + * address of the reg guid1, which is adjacent to the context guid2 (if exist). + * This allows for a single call to cl_memcmp. + */ +static int +__context_cmp128( + IN const void* const p_key1, + IN const void* const p_key2 ) +{ + return cl_memcmp( p_key1, p_key2, sizeof(uint64_t) * 2 ); +} + +/* + * Compares two context for inserts/lookups in a flexi map. Keys are the + * address of the reg guid1, which is adjacent to the context guid2 (if exist). + * This allows for a single call to cl_memcmp. + */ +static int +__context_cmp64( + IN const void* const p_key1, + IN const void* const p_key2 ) +{ + return cl_memcmp( p_key1, p_key2, sizeof(uint64_t) ); +} + + +/* + * Event structures for queuing to the async proc manager. + */ +typedef struct _al_pnp_ca_change +{ + cl_async_proc_item_t async_item; + al_ci_ca_t *p_ci_ca; + ib_ca_attr_t *p_new_ca_attr; + +} al_pnp_ca_change_t; + + +typedef struct _al_pnp_ca_event +{ + cl_async_proc_item_t async_item; + ib_pnp_event_t pnp_event; + al_ci_ca_t *p_ci_ca; + uint8_t port_index; + +} al_pnp_ca_event_t; + + +typedef struct _al_pnp_reg_event +{ + cl_async_proc_item_t async_item; + al_pnp_t *p_reg; + +} al_pnp_reg_event_t; + + +/* PnP Manager structure. */ +typedef struct _al_pnp_mgr +{ + al_obj_t obj; + + cl_qlist_t ca_reg_list; + cl_qlist_t port_reg_list; + + cl_ptr_vector_t ca_vector; + + cl_async_proc_item_t async_item; + boolean_t async_item_is_busy; + +} al_pnp_mgr_t; + + +/* + * PnP Manager instance, creation, destruction. + */ + +/* Global instance of the PnP manager. */ +al_pnp_mgr_t *gp_pnp = NULL; + + +static void +__pnp_check_events( + IN cl_async_proc_item_t* p_item ); + +static void +__al_pnp_process_dereg( + IN cl_async_proc_item_t* p_item ); + + +ib_api_status_t +create_pnp( + IN al_obj_t* const p_parent_obj ) +{ + ib_api_status_t status; + cl_status_t cl_status; + + AL_ENTER( AL_DBG_PNP ); + + CL_ASSERT( gp_pnp == NULL ); + + gp_pnp = (al_pnp_mgr_t*)cl_zalloc( sizeof(al_pnp_mgr_t) ); + if( !gp_pnp ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("Failed to allocate PnP manager.\n") ); + return IB_INSUFFICIENT_MEMORY; + } + + cl_qlist_init( &gp_pnp->ca_reg_list ); + cl_qlist_init( &gp_pnp->port_reg_list ); + construct_al_obj( &gp_pnp->obj, AL_OBJ_TYPE_PNP_MGR ); + cl_ptr_vector_construct( &gp_pnp->ca_vector ); + + cl_status = cl_ptr_vector_init( &gp_pnp->ca_vector, PNP_CA_VECTOR_MIN, + PNP_CA_VECTOR_GROW ); + if( cl_status != CL_SUCCESS ) + { + __pnp_free( &gp_pnp->obj ); + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("cl_ptr_vector_init failed with status %#x.\n", + cl_status) ); + return IB_ERROR; + } + + gp_pnp->async_item.pfn_callback = __pnp_check_events; + + status = init_al_obj( &gp_pnp->obj, NULL, TRUE, NULL, NULL, __pnp_free ); + if( status != IB_SUCCESS ) + { + __pnp_free( &gp_pnp->obj ); + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("init_al_obj() failed with status %s.\n", ib_get_err_str(status)) ); + return status; + } + status = attach_al_obj( p_parent_obj, &gp_pnp->obj ); + if( status != IB_SUCCESS ) + { + gp_pnp->obj.pfn_destroy( &gp_pnp->obj, NULL ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("attach_al_obj returned %s.\n", ib_get_err_str(status)) ); + return status; + } + + /* Release the reference taken in init_al_obj. */ + deref_al_obj( &gp_pnp->obj ); + + AL_EXIT( AL_DBG_PNP ); + return( IB_SUCCESS ); +} + + +static void +__pnp_free( + IN al_obj_t *p_obj ) +{ + AL_ENTER( AL_DBG_PNP ); + + CL_ASSERT( PARENT_STRUCT( p_obj, al_pnp_mgr_t, obj ) == gp_pnp ); + CL_ASSERT( cl_is_qlist_empty( &gp_pnp->ca_reg_list ) ); + CL_ASSERT( cl_is_qlist_empty( &gp_pnp->port_reg_list ) ); + UNUSED_PARAM( p_obj ); + + /* All CA's should have been removed by now. */ + CL_ASSERT( !cl_ptr_vector_get_size( &gp_pnp->ca_vector ) ); + cl_ptr_vector_destroy( &gp_pnp->ca_vector ); + + destroy_al_obj( &gp_pnp->obj ); + cl_free( gp_pnp ); + gp_pnp = NULL; + + AL_EXIT( AL_DBG_PNP ); +} + + +static void +__pnp_reg_destroying( + IN al_obj_t *p_obj ) +{ + al_pnp_t *p_reg; + + AL_ENTER( AL_DBG_PNP ); + + p_reg = PARENT_STRUCT( p_obj, al_pnp_t, obj ); + + /* Reference the registration entry while we queue it to our PnP thread. */ + ref_al_obj( &p_reg->obj ); + + /* Queue the registration for removal from the list. */ + cl_async_proc_queue( gp_async_pnp_mgr, &p_reg->dereg_item ); + + AL_EXIT( AL_DBG_PNP ); +} + + +static void +__al_pnp_process_dereg( + IN cl_async_proc_item_t* p_item ) +{ + al_pnp_t* p_reg; + + AL_ENTER( AL_DBG_PNP ); + + p_reg = PARENT_STRUCT( p_item, al_pnp_t, dereg_item ); + + /* Remove the registration information from the list. */ + switch( pnp_get_class( p_reg->pnp_class ) ) + { + case IB_PNP_CA: + cl_qlist_remove_item( &gp_pnp->ca_reg_list, &p_reg->list_item ); + break; + + case IB_PNP_PORT: + cl_qlist_remove_item( &gp_pnp->port_reg_list, &p_reg->list_item ); + break; + + default: + CL_ASSERT( pnp_get_class( p_reg->pnp_class ) == IB_PNP_CA || + pnp_get_class( p_reg->pnp_class ) == IB_PNP_PORT ); + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("Invalid PnP registartion type.\n") ); + } + + /* Release the reference we took for processing the deregistration. */ + deref_al_obj( &p_reg->obj ); + + AL_EXIT( AL_DBG_PNP ); +} + + +static void +__pnp_reg_cleanup( + IN al_obj_t *p_obj ) +{ + al_pnp_t *p_reg; + cl_fmap_item_t *p_item; + IRP *p_irp; + + AL_ENTER( AL_DBG_PNP ); + + p_reg = PARENT_STRUCT( p_obj, al_pnp_t, obj ); + + /* Cleanup the context list. */ + while( cl_fmap_count( &p_reg->context_map ) ) + { + p_item = cl_fmap_tail( &p_reg->context_map ); + cl_fmap_remove_item( &p_reg->context_map, p_item ); + cl_free( p_item ); + } + + p_irp = InterlockedExchangePointer( &p_reg->p_rearm_irp, NULL ); + if( p_irp ) + { +#pragma warning(push, 3) + IoSetCancelRoutine( p_irp, NULL ); +#pragma warning(pop) + /* Complete the IRP. */ + p_irp->IoStatus.Status = STATUS_CANCELLED; + p_irp->IoStatus.Information = 0; + IoCompleteRequest( p_irp, IO_NO_INCREMENT ); + } + + if( p_reg->p_dereg_irp ) + { + p_reg->p_dereg_irp->IoStatus.Status = STATUS_SUCCESS; + p_reg->p_dereg_irp->IoStatus.Information = 0; + IoCompleteRequest( p_reg->p_dereg_irp, IO_NO_INCREMENT ); + p_reg->p_dereg_irp = NULL; + } + + /* Dereference the PnP manager. */ + deref_al_obj( &gp_pnp->obj ); + + AL_EXIT( AL_DBG_PNP ); +} + + +static void +__pnp_reg_free( + IN al_obj_t *p_obj ) +{ + al_pnp_t *p_reg; + cl_fmap_item_t *p_item; + + AL_ENTER( AL_DBG_PNP ); + + p_reg = PARENT_STRUCT( p_obj, al_pnp_t, obj ); + + /* Cleanup the context list. */ + while( cl_fmap_count( &p_reg->context_map ) ) + { + p_item = cl_fmap_tail( &p_reg->context_map ); + cl_fmap_remove_item( &p_reg->context_map, p_item ); + cl_free( p_item ); + } + + /* Free the registration structure. */ + destroy_al_obj( &p_reg->obj ); + cl_free( p_reg ); + + AL_EXIT( AL_DBG_PNP ); +} + + +/* + * Helper functions. + */ + + + +/* + * Returns the context structure stored in a registration for + * a given CA or port GUID. + */ +al_pnp_context_t* +pnp_get_context( + IN const al_pnp_t* const p_reg, + IN const void* const p_key ) +{ + cl_fmap_item_t *p_context_item; + + AL_ENTER( AL_DBG_PNP ); + + /* Search the context list for this CA. */ + p_context_item = cl_fmap_get( &p_reg->context_map, p_key ); + if( p_context_item != cl_fmap_end( &p_reg->context_map ) ) + { + AL_EXIT( AL_DBG_PNP ); + return PARENT_STRUCT( p_context_item, al_pnp_context_t, map_item ); + } + + AL_EXIT( AL_DBG_PNP ); + return NULL; +} + + +void +pnp_reg_complete( + IN al_pnp_t* const p_reg ) +{ + ib_pnp_rec_t user_rec; + + AL_ENTER( AL_DBG_PNP ); + + /* Notify the user that the registration is complete. */ + if( (pnp_get_flag( p_reg->pnp_class ) & IB_PNP_FLAG_REG_COMPLETE) ) + { + /* Setup the PnP record for the callback. */ + cl_memclr( &user_rec, sizeof(user_rec) ); + user_rec.h_pnp = p_reg; + user_rec.pnp_event = IB_PNP_REG_COMPLETE; + user_rec.pnp_context = (void*)p_reg->obj.context; + + /* Invoke the user callback. */ + p_reg->pfn_pnp_cb( &user_rec ); + } + + if( pnp_get_flag( p_reg->pnp_class ) & IB_PNP_FLAG_REG_SYNC ) + { + KeSetEvent( p_reg->p_sync_event, 0, FALSE ); + /* + * Proxy synchronizes PnP callbacks with registration, and thus can + * safely set the UM_EXPORT subtype after al_reg_pnp returns. + */ + if( p_reg->obj.type & AL_OBJ_SUBTYPE_UM_EXPORT ) + ObDereferenceObject( p_reg->p_sync_event ); + p_reg->p_sync_event = NULL; + } + + AL_EXIT( AL_DBG_PNP ); +} + +/* + * User notification. Formats the PnP record delivered by the + * callback, invokes the callback, and updates the contexts. + */ +static ib_api_status_t +__pnp_notify_user( + IN al_pnp_t* const p_reg, + IN al_pnp_context_t* const p_context, + IN const al_pnp_ca_event_t* const p_event_rec ) +{ + ib_api_status_t status; + union + { + ib_pnp_rec_t user_rec; + ib_pnp_ca_rec_t ca_rec; + ib_pnp_port_rec_t port_rec; + } u; + + AL_ENTER( AL_DBG_PNP ); + + CL_ASSERT( p_reg ); + CL_ASSERT( p_context ); + CL_ASSERT( p_event_rec ); + + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_PNP, + ("p_event_rec->pnp_event = 0x%x (%s)\n", + p_event_rec->pnp_event, ib_get_pnp_event_str( p_event_rec->pnp_event )) ); + + /* Setup the PnP record for the callback. */ + cl_memclr( &u, sizeof(u) ); + u.user_rec.h_pnp = p_reg; + u.user_rec.pnp_event = p_event_rec->pnp_event; + u.user_rec.pnp_context = (void*)p_reg->obj.context; + u.user_rec.context = (void*)p_context->context; + + switch( p_event_rec->pnp_event ) + { + case IB_PNP_CA_ADD: + /* Copy the attributes for use in calling users back. */ + u.ca_rec.p_ca_attr = ib_copy_ca_attr( + p_event_rec->p_ci_ca->p_user_attr, + p_event_rec->p_ci_ca->p_pnp_attr ); + + /* Fall through */ + case IB_PNP_CA_REMOVE: + u.user_rec.guid = p_event_rec->p_ci_ca->p_pnp_attr->ca_guid; + break; + + case IB_PNP_PORT_ADD: + case IB_PNP_PORT_INIT: + case IB_PNP_PORT_ARMED: + case IB_PNP_PORT_ACTIVE: + case IB_PNP_PORT_DOWN: + case IB_PNP_PKEY_CHANGE: + case IB_PNP_SM_CHANGE: + case IB_PNP_GID_CHANGE: + case IB_PNP_LID_CHANGE: + case IB_PNP_SUBNET_TIMEOUT_CHANGE: + /* Copy the attributes for use in calling users back. */ + u.port_rec.p_ca_attr = ib_copy_ca_attr( + p_event_rec->p_ci_ca->p_user_attr, + p_event_rec->p_ci_ca->p_pnp_attr ); + + /* Setup the port attribute pointer. */ + u.port_rec.p_port_attr = + &u.port_rec.p_ca_attr->p_port_attr[p_event_rec->port_index]; + + /* Fall through */ + case IB_PNP_PORT_REMOVE: + u.user_rec.guid = p_event_rec->p_ci_ca->p_pnp_attr->p_port_attr[ + p_event_rec->port_index].port_guid; + break; + + case IB_PNP_REG_COMPLETE: + break; + + default: + /* Invalid event type. */ + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("Invalid event type (%d).\n", p_event_rec->pnp_event) ); + CL_ASSERT( p_event_rec->pnp_event == IB_PNP_CA_ADD || + p_event_rec->pnp_event == IB_PNP_PORT_ADD || + p_event_rec->pnp_event == IB_PNP_PORT_INIT || + p_event_rec->pnp_event == IB_PNP_PORT_ACTIVE || + p_event_rec->pnp_event == IB_PNP_PORT_DOWN || + p_event_rec->pnp_event == IB_PNP_PKEY_CHANGE || + p_event_rec->pnp_event == IB_PNP_SM_CHANGE || + p_event_rec->pnp_event == IB_PNP_GID_CHANGE || + p_event_rec->pnp_event == IB_PNP_LID_CHANGE || + p_event_rec->pnp_event == IB_PNP_SUBNET_TIMEOUT_CHANGE || + p_event_rec->pnp_event == IB_PNP_CA_REMOVE || + p_event_rec->pnp_event == IB_PNP_PORT_REMOVE ); + return IB_SUCCESS; + } + + /* Invoke the user callback. */ + status = p_reg->pfn_pnp_cb( &u.user_rec ); + + if( status == IB_SUCCESS ) + { + /* Store the user's event context in the context block. */ + p_context->context = u.user_rec.context; + } + else + { + cl_fmap_remove_item( &p_reg->context_map, &p_context->map_item ); + cl_free( p_context ); + } + + AL_EXIT( AL_DBG_PNP ); + return status; +} + + + +/* + * Context creation. + */ +al_pnp_context_t* +pnp_create_context( + IN al_pnp_t* const p_reg, + IN const void* const p_key ) +{ + al_pnp_context_t *p_context; + cl_fmap_item_t *p_item; + + AL_ENTER( AL_DBG_PNP ); + + CL_ASSERT( p_reg ); + + /* No context exists for this port. Create one. */ + p_context = (al_pnp_context_t*)cl_zalloc( sizeof(al_pnp_context_t) ); + if( !p_context ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("Failed to cl_zalloc al_pnp_context_t (%I64d bytes).\n", + sizeof(al_pnp_context_t)) ); + return NULL; + } + /* Store the GUID in the context record. */ + cl_memcpy(&p_context->guid, p_key, sizeof(ib_net64_t) * 2); + + /* Add the context to the context list. */ + p_item = cl_fmap_insert( &p_reg->context_map, &p_context->guid, + &p_context->map_item ); + if( p_item != &p_context->map_item ) + { + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_PNP, + ("p_context is already in context map %I64x \n",p_context->guid)); + cl_free( p_context ); + p_context = NULL; + } + + + AL_EXIT( AL_DBG_PNP ); + return p_context; +} + + + +/* + * Report all local port information. This notifies the user of PORT_ADD + * events, along with port state events (PORT_INIT, PORT_ACTIVE). + */ +static void +__pnp_port_notify( + IN al_pnp_t *p_reg, + IN al_ci_ca_t *p_ci_ca ) +{ + ib_api_status_t status; + al_pnp_context_t *p_context; + ib_port_attr_t *p_port_attr; + al_pnp_ca_event_t event_rec; + + AL_ENTER( AL_DBG_PNP ); + + event_rec.p_ci_ca = p_ci_ca; + + for( event_rec.port_index = 0; + event_rec.port_index < p_ci_ca->num_ports; + event_rec.port_index++ ) + { + p_port_attr = p_ci_ca->p_pnp_attr->p_port_attr; + p_port_attr += event_rec.port_index; + + /* Create a new context for user port information. */ + p_context = pnp_create_context( p_reg, &p_port_attr->port_guid); + if( !p_context ) + continue; + + /* Notify the user of the port's existence. */ + event_rec.pnp_event = IB_PNP_PORT_ADD; + status = __pnp_notify_user( p_reg, p_context, &event_rec ); + if( status != IB_SUCCESS ) + continue; + + /* Generate a port down event if the port is currently down. */ + if( p_port_attr->link_state == IB_LINK_DOWN ) + { + event_rec.pnp_event = IB_PNP_PORT_DOWN; + __pnp_notify_user( p_reg, p_context, &event_rec ); + } + else + { + /* Generate port init event. */ + if( p_port_attr->link_state >= IB_LINK_INIT ) + { + event_rec.pnp_event = IB_PNP_PORT_INIT; + status = __pnp_notify_user( p_reg, p_context, &event_rec ); + if( status != IB_SUCCESS ) + continue; + } + /* Generate port armed event. */ + if( p_port_attr->link_state >= IB_LINK_ARMED ) + { + event_rec.pnp_event = IB_PNP_PORT_ARMED; + status = __pnp_notify_user( p_reg, p_context, &event_rec ); + if( status != IB_SUCCESS ) + continue; + } + /* Generate port up event. */ + if( p_port_attr->link_state >= IB_LINK_ACTIVE ) + { + event_rec.pnp_event = IB_PNP_PORT_ACTIVE; + __pnp_notify_user( p_reg, p_context, &event_rec ); + } + } + } + AL_EXIT( AL_DBG_PNP ); +} + + +/* + * Registration and deregistration. + */ +static void +__pnp_reg_notify( + IN al_pnp_t* const p_reg ) +{ + al_pnp_ca_event_t event_rec; + size_t i; + al_pnp_context_t *p_context; + + AL_ENTER( AL_DBG_PNP ); + + for( i = 0; i < cl_ptr_vector_get_size( &gp_pnp->ca_vector ); i++ ) + { + event_rec.p_ci_ca = (al_ci_ca_t*) + cl_ptr_vector_get( &gp_pnp->ca_vector, i ); + if( !event_rec.p_ci_ca ) + continue; + + switch( pnp_get_class( p_reg->pnp_class ) ) + { + case IB_PNP_CA: + event_rec.pnp_event = IB_PNP_CA_ADD; + p_context = pnp_create_context( p_reg, + &event_rec.p_ci_ca->p_pnp_attr->ca_guid); + if( !p_context ) + break; + + __pnp_notify_user( p_reg, p_context, &event_rec ); + break; + + case IB_PNP_PORT: + __pnp_port_notify( p_reg, event_rec.p_ci_ca ); + break; + + default: + CL_ASSERT( pnp_get_class( p_reg->pnp_class ) == IB_PNP_CA || + pnp_get_class( p_reg->pnp_class ) == IB_PNP_PORT ); + continue; + } + } + + /* Notify the user that the registration is complete. */ + pnp_reg_complete( p_reg ); + + AL_EXIT( AL_DBG_PNP ); +} + + +static void +__al_pnp_process_reg( + IN cl_async_proc_item_t* p_item ) +{ + al_pnp_t* p_reg; + + AL_ENTER( AL_DBG_PNP ); + + p_reg = PARENT_STRUCT( p_item, al_pnp_t, async_item ); + + /* Add the registrant to the list. */ + switch( pnp_get_class( p_reg->pnp_class ) ) + { + case IB_PNP_CA: + cl_qlist_insert_tail( &gp_pnp->ca_reg_list, &p_reg->list_item ); + break; + + case IB_PNP_PORT: + cl_qlist_insert_tail( &gp_pnp->port_reg_list, &p_reg->list_item ); + break; + + default: + CL_ASSERT( pnp_get_class( p_reg->pnp_class ) == IB_PNP_CA || + pnp_get_class( p_reg->pnp_class ) == IB_PNP_PORT ); + } + + /* Generate all relevant events for the registration. */ + __pnp_reg_notify( p_reg ); + + /* Release the reference taken in init_al_obj. */ + deref_al_obj( &p_reg->obj ); + + AL_EXIT( AL_DBG_PNP ); +} + + +ib_api_status_t +ib_reg_pnp( + IN const ib_al_handle_t h_al, + IN const ib_pnp_req_t* const p_pnp_req, + OUT ib_pnp_handle_t* const ph_pnp ) +{ + ib_api_status_t status; + KEVENT event; + + AL_ENTER( AL_DBG_PNP ); + + if( AL_OBJ_INVALID_HANDLE( h_al, AL_OBJ_TYPE_H_AL ) ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_AL_HANDLE\n") ); + return IB_INVALID_AL_HANDLE; + } + if( !p_pnp_req || !ph_pnp ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + if( pnp_get_flag( p_pnp_req->pnp_class ) & IB_PNP_FLAG_REG_SYNC ) + KeInitializeEvent( &event, SynchronizationEvent, FALSE ); + + status = al_reg_pnp( h_al, p_pnp_req, &event, ph_pnp ); + /* Release the reference taken in init_al_obj. */ + if( status == IB_SUCCESS ) + { + deref_al_obj( &(*ph_pnp)->obj ); + + /* Wait for registration to complete if synchronous. */ + if( pnp_get_flag( p_pnp_req->pnp_class ) & IB_PNP_FLAG_REG_SYNC ) + { + KeWaitForSingleObject( + &event, Executive, KernelMode, TRUE, NULL ); + } + } + + AL_EXIT( AL_DBG_PNP ); + return status; +} + + +ib_api_status_t +al_reg_pnp( + IN const ib_al_handle_t h_al, + IN const ib_pnp_req_t* const p_pnp_req, + IN KEVENT *p_sync_event, + OUT ib_pnp_handle_t* const ph_pnp ) +{ + ib_api_status_t status; + al_pnp_t* p_reg; + + AL_ENTER( AL_DBG_PNP ); + + /* Allocate a new registration info structure. */ + p_reg = (al_pnp_t*)cl_zalloc( sizeof(al_pnp_t) ); + if( !p_reg ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("Failed to cl_zalloc al_pnp_t (%I64d bytes).\n", + sizeof(al_pnp_t)) ); + return( IB_INSUFFICIENT_MEMORY ); + } + + /* Initialize the registration info. */ + construct_al_obj( &p_reg->obj, AL_OBJ_TYPE_H_PNP ); + switch(pnp_get_class(p_pnp_req->pnp_class)){ + case IB_PNP_IOU: + case IB_PNP_IOC: + cl_fmap_init( &p_reg->context_map, __context_cmp128 ); + break; + case IB_PNP_PORT: + case IB_PNP_CA: + cl_fmap_init( &p_reg->context_map, __context_cmp64 ); + break; + default: + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("unknown pnp_class 0x%x.\n", pnp_get_class(p_pnp_req->pnp_class))); + } + status = init_al_obj( &p_reg->obj, p_pnp_req->pnp_context, TRUE, + __pnp_reg_destroying, __pnp_reg_cleanup, __pnp_reg_free ); + if( status != IB_SUCCESS ) + { + __pnp_reg_free( &p_reg->obj ); + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("init_al_obj() failed with status %s.\n", ib_get_err_str(status)) ); + return( status ); + } + status = attach_al_obj( &h_al->obj, &p_reg->obj ); + if( status != IB_SUCCESS ) + { + p_reg->obj.pfn_destroy( &p_reg->obj, NULL ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("attach_al_obj returned %s.\n", ib_get_err_str(status)) ); + return status; + } + + /* Reference the PnP Manager. */ + ref_al_obj( &gp_pnp->obj ); + + /* Copy the request information. */ + p_reg->pnp_class = p_pnp_req->pnp_class; + p_reg->pfn_pnp_cb = p_pnp_req->pfn_pnp_cb; + + p_reg->p_sync_event = p_sync_event; + + /* Send IOU/IOC registration to the IOC PnP manager. */ + if( pnp_get_class(p_pnp_req->pnp_class) == IB_PNP_IOU || + pnp_get_class(p_pnp_req->pnp_class) == IB_PNP_IOC ) + { + p_reg->async_item.pfn_callback = ioc_pnp_process_reg; + p_reg->dereg_item.pfn_callback = ioc_pnp_process_dereg; + } + else + { + p_reg->async_item.pfn_callback = __al_pnp_process_reg; + p_reg->dereg_item.pfn_callback = __al_pnp_process_dereg; + } + + /* Queue the registrant for addition to the list. */ + ref_al_obj( &p_reg->obj ); + cl_async_proc_queue( gp_async_pnp_mgr, &p_reg->async_item ); + + /* Set the user handle. */ + *ph_pnp = p_reg; + + AL_EXIT( AL_DBG_PNP ); + return( IB_SUCCESS ); +} + + +ib_api_status_t +ib_dereg_pnp( + IN const ib_pnp_handle_t h_pnp, + IN const ib_pfn_destroy_cb_t pfn_destroy_cb OPTIONAL ) +{ + AL_ENTER( AL_DBG_PNP ); + + if( AL_OBJ_INVALID_HANDLE( h_pnp, AL_OBJ_TYPE_H_PNP ) ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_HANDLE\n") ); + return IB_INVALID_HANDLE; + } + + ref_al_obj( &h_pnp->obj ); + h_pnp->obj.pfn_destroy( &h_pnp->obj, pfn_destroy_cb ); + + AL_EXIT( AL_DBG_PNP ); + return( IB_SUCCESS ); +} + + +/* + * CA event handling. + */ +static void +__pnp_process_add_ca( + IN cl_async_proc_item_t *p_item ) +{ + al_pnp_t *p_reg; + al_pnp_ca_event_t *p_event_rec; + cl_list_item_t *p_reg_item; + al_pnp_context_t *p_context; + cl_status_t cl_status; + size_t i; + + AL_ENTER( AL_DBG_PNP ); + + p_event_rec = PARENT_STRUCT( p_item, al_pnp_ca_event_t, async_item ); + + cl_spinlock_acquire( &gp_pnp->obj.lock ); + /* Add the CA to the CA vector. */ + for( i = 0; i < cl_ptr_vector_get_size( &gp_pnp->ca_vector ); i++ ) + { + if( !cl_ptr_vector_get( &gp_pnp->ca_vector, i ) ) + { + cl_status = cl_ptr_vector_set( &gp_pnp->ca_vector, i, + p_event_rec->p_ci_ca ); + CL_ASSERT( cl_status == CL_SUCCESS ); + break; + } + } + cl_spinlock_release( &gp_pnp->obj.lock ); + CL_ASSERT( i < cl_ptr_vector_get_size( &gp_pnp->ca_vector ) ); + + /* Walk the list of registrants for notification. */ + for( p_reg_item = cl_qlist_head( &gp_pnp->ca_reg_list ); + p_reg_item != cl_qlist_end( &gp_pnp->ca_reg_list ); + p_reg_item = cl_qlist_next( p_reg_item ) ) + { + p_reg = PARENT_STRUCT( p_reg_item, al_pnp_t, list_item ); + CL_ASSERT( pnp_get_class( p_reg->pnp_class ) == IB_PNP_CA ); + + /* Allocate the user's context. */ + /* + * Moving this allocation to the pnp_ca_event call is left as an + * exercise to the open source community. + */ + p_context = pnp_create_context( p_reg, + &p_event_rec->p_ci_ca->p_pnp_attr->ca_guid); + if( !p_context ) + continue; + + /* Notify the user. */ + __pnp_notify_user( p_reg, p_context, p_event_rec ); + } + + /* Generate port add and state events. */ + for( p_reg_item = cl_qlist_head( &gp_pnp->port_reg_list ); + p_reg_item != cl_qlist_end( &gp_pnp->port_reg_list ); + p_reg_item = cl_qlist_next( p_reg_item ) ) + { + p_reg = PARENT_STRUCT( p_reg_item, al_pnp_t, list_item ); + CL_ASSERT( pnp_get_class( p_reg->pnp_class ) == IB_PNP_PORT ); + __pnp_port_notify( p_reg, p_event_rec->p_ci_ca ); + } + + /* Cleanup the event record. */ + deref_al_obj( &gp_pnp->obj ); + cl_event_signal( &p_event_rec->p_ci_ca->event ); + cl_free( p_event_rec ); + + AL_EXIT( AL_DBG_PNP ); +} + + +static void +__pnp_process_remove_port( + IN const al_pnp_ca_event_t* const p_event_rec ) +{ + ib_api_status_t status; + al_pnp_t *p_reg; + cl_list_item_t *p_reg_item; + uint8_t port_index; + al_pnp_context_t *p_context; + al_pnp_ca_event_t event_rec; + ib_port_attr_t *p_port_attr; + + AL_ENTER( AL_DBG_PNP ); + + CL_ASSERT( p_event_rec->p_ci_ca->p_pnp_attr ); + CL_ASSERT( p_event_rec->p_ci_ca->p_pnp_attr->p_port_attr ); + + /* Notify the IOC PnP manager of the port down event. */ + //***TODO: Make some call to the IOC PnP manager here, such as + //***TODO: al_ioc_pnp_process_port_down( p_event_rec->p_ci_ca, + //***TODO: p_event_rec->port_index ); + + cl_memclr( &event_rec, sizeof( al_pnp_ca_event_t ) ); + event_rec = *p_event_rec; + + /* Walk the list of registrants for notification. */ + for( p_reg_item = cl_qlist_tail( &gp_pnp->port_reg_list ); + p_reg_item != cl_qlist_end( &gp_pnp->port_reg_list ); + p_reg_item = cl_qlist_prev( p_reg_item ) ) + { + p_reg = PARENT_STRUCT( p_reg_item, al_pnp_t, list_item ); + + CL_ASSERT( pnp_get_class( p_reg->pnp_class ) == IB_PNP_PORT ); + + for( port_index = 0; + port_index < p_event_rec->p_ci_ca->num_ports; + port_index++ ) + { + p_port_attr = p_event_rec->p_ci_ca->p_pnp_attr->p_port_attr; + p_port_attr += port_index; + p_context = pnp_get_context( p_reg, &p_port_attr->port_guid ); + if( !p_context ) + continue; + + event_rec.port_index = port_index; + + if( p_port_attr->link_state >= IB_LINK_INIT ) + { + /* Notify the user of the port down. */ + event_rec.pnp_event = IB_PNP_PORT_DOWN; + status = __pnp_notify_user( p_reg, p_context, &event_rec ); + if( status != IB_SUCCESS ) + continue; + } + + /* Notify the user of the port remove. */ + event_rec.pnp_event = IB_PNP_PORT_REMOVE; + status = __pnp_notify_user( p_reg, p_context, &event_rec ); + if( status == IB_SUCCESS ) + { + /* + * Remove the port context from the registrant's + * context list. + */ + cl_fmap_remove_item( &p_reg->context_map, + &p_context->map_item ); + /* Free the context. */ + cl_free( p_context ); + } + } + } + + AL_EXIT( AL_DBG_PNP ); +} + + +static void +__pnp_process_remove_ca( + IN cl_async_proc_item_t *p_item ) +{ + al_pnp_t *p_reg; + al_pnp_ca_event_t *p_event_rec; + cl_list_item_t *p_reg_item; + al_pnp_context_t *p_context = NULL; + size_t i; + + AL_ENTER( AL_DBG_PNP ); + + p_event_rec = PARENT_STRUCT( p_item, al_pnp_ca_event_t, async_item ); + + /* Generate port remove events. */ + __pnp_process_remove_port( p_event_rec ); + + /* Walk the list of registrants for notification. */ + for( p_reg_item = cl_qlist_tail( &gp_pnp->ca_reg_list ); + p_reg_item != cl_qlist_end( &gp_pnp->ca_reg_list ); + p_reg_item = cl_qlist_prev( p_reg_item ) ) + { + p_reg = PARENT_STRUCT( p_reg_item, al_pnp_t, list_item ); + + CL_ASSERT( pnp_get_class( p_reg->pnp_class ) == IB_PNP_CA ); + + /* Search the context list for this CA. */ + p_context = + pnp_get_context( p_reg, &p_event_rec->p_ci_ca->p_pnp_attr->ca_guid); + + /* Make sure we found a context. */ + if( !p_context ) + continue; + + /* Notify the user. */ + if( __pnp_notify_user( p_reg, p_context, p_event_rec ) == IB_SUCCESS ) + { + /* Remove the context from the context list. */ + cl_fmap_remove_item( &p_reg->context_map, &p_context->map_item ); + + /* Deallocate the context block. */ + cl_free( p_context ); + } + } + + /* Remove the CA from the CA vector. */ + for( i = 0; i < cl_ptr_vector_get_size( &gp_pnp->ca_vector ); i++ ) + { + if( cl_ptr_vector_get( &gp_pnp->ca_vector, i ) == + p_event_rec->p_ci_ca ) + { + cl_ptr_vector_remove( &gp_pnp->ca_vector, i ); + break; + } + } + + /* Release the reference to the CA. */ + deref_al_obj( &p_event_rec->p_ci_ca->obj ); + + /* Cleanup the event record. */ + deref_al_obj( &gp_pnp->obj ); + cl_event_signal( &p_event_rec->p_ci_ca->event ); + cl_free( p_event_rec ); + + AL_EXIT( AL_DBG_PNP ); +} + + +ib_api_status_t +pnp_ca_event( + IN al_ci_ca_t* const p_ci_ca, + IN const ib_pnp_event_t event ) +{ + ib_api_status_t status; + cl_status_t cl_status; + al_pnp_ca_event_t *p_event_rec; + ib_ca_attr_t *p_old_ca_attr; + + AL_ENTER( AL_DBG_PNP ); + + /* Allocate an event record. */ + p_event_rec = (al_pnp_ca_event_t*)cl_zalloc( sizeof(al_pnp_ca_event_t) ); + if( !p_event_rec ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("Failed to cl_zalloc al_pnp_ca_event_t (%I64d bytes).\n", + sizeof(al_pnp_ca_event_t)) ); + return IB_INSUFFICIENT_MEMORY; + } + + /* Store the event type. */ + p_event_rec->pnp_event = event; + /* Store a pointer to the ca. */ + p_event_rec->p_ci_ca = p_ci_ca; + + switch( event ) + { + case IB_PNP_CA_ADD: + p_event_rec->async_item.pfn_callback = __pnp_process_add_ca; + + /* Reserve space for the CA in the CA vector. */ + cl_spinlock_acquire( &gp_pnp->obj.lock ); + cl_status = cl_ptr_vector_set_size( &gp_pnp->ca_vector, + cl_ptr_vector_get_size( &gp_pnp->ca_vector ) + 1 ); + cl_spinlock_release( &gp_pnp->obj.lock ); + + if( cl_status != CL_SUCCESS ) + { + cl_free( p_event_rec ); + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("cl_ptr_vector_set_size failed with status %#x.\n", + cl_status) ); + return ib_convert_cl_status( cl_status ); + } + + /* Read the CA attributes required to process the event. */ + status = ci_ca_update_attr( p_ci_ca, &p_old_ca_attr ); + if( status != IB_SUCCESS ) + { + cl_spinlock_acquire( &gp_pnp->obj.lock ); + cl_status = cl_ptr_vector_set_size( &gp_pnp->ca_vector, + cl_ptr_vector_get_size( &gp_pnp->ca_vector ) - 1 ); + CL_ASSERT( cl_status == CL_SUCCESS ); + cl_spinlock_release( &gp_pnp->obj.lock ); + cl_free( p_event_rec ); + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("ci_ca_update_attr failed.\n") ); + return status; + } + + /* Take out a reference to the CA until it is removed. */ + ref_al_obj( &p_ci_ca->obj ); + break; + + case IB_PNP_CA_REMOVE: + if( !p_event_rec->p_ci_ca->p_pnp_attr ) + { + /* The CA was never added by the PNP manager. */ + cl_free( p_event_rec ); + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("Ignoring removal request for unknown CA.\n") ); + return IB_NOT_FOUND; + } + + p_event_rec->async_item.pfn_callback = __pnp_process_remove_ca; + break; + + default: + /* Invalid event for this function. */ + CL_ASSERT( event == IB_PNP_CA_ADD || event == IB_PNP_CA_REMOVE ); + cl_free( p_event_rec ); + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("Invalid event type.\n") ); + return IB_ERROR; + } + + /* Queue the event to the async processing manager. */ + ref_al_obj( &gp_pnp->obj ); + cl_async_proc_queue( gp_async_pnp_mgr, &p_event_rec->async_item ); + + /* wait for the end of event propagation + It is needed for enabling quick HCA disable/enable scenarios. */ + cl_status = cl_event_wait_on( &p_ci_ca->event, + EVENT_NO_TIMEOUT, AL_WAIT_ALERTABLE ); + if (cl_status != CL_SUCCESS) + return IB_ERROR; + + AL_EXIT( AL_DBG_PNP ); + return IB_SUCCESS; +} + + +/* + * Port event handling. + */ + +/* + * Processes a port event, reporting it to clients from the first + * registrant to the last. + */ +static void +__pnp_process_port_forward( + IN al_pnp_ca_event_t* p_event_rec ) +{ + al_pnp_t *p_reg; + cl_list_item_t *p_reg_item; + al_pnp_context_t *p_context; + ib_port_attr_t *p_port_attr; + + AL_ENTER( AL_DBG_PNP ); + + /* Walk the list of registrants for notification. */ + for( p_reg_item = cl_qlist_head( &gp_pnp->port_reg_list ); + p_reg_item != cl_qlist_end( &gp_pnp->port_reg_list ); + p_reg_item = cl_qlist_next( p_reg_item ) ) + { + p_reg = PARENT_STRUCT( p_reg_item, al_pnp_t, list_item ); + + CL_ASSERT( pnp_get_class( p_reg->pnp_class ) == IB_PNP_PORT ); + + p_port_attr = p_event_rec->p_ci_ca->p_pnp_attr->p_port_attr; + p_port_attr += p_event_rec->port_index; + + p_context = pnp_get_context( p_reg, &p_port_attr->port_guid ); + if( !p_context ) + continue; + + /* Notify the user. */ + __pnp_notify_user( p_reg, p_context, p_event_rec ); + } + + AL_EXIT( AL_DBG_PNP ); +} + + +/* + * Processes a port event, reporting it to clients from the last + * registrant to the first. + */ +static void +__pnp_process_port_backward( + IN al_pnp_ca_event_t* p_event_rec ) +{ + al_pnp_t *p_reg; + cl_list_item_t *p_reg_item; + al_pnp_context_t *p_context; + ib_port_attr_t *p_port_attr; + + AL_ENTER( AL_DBG_PNP ); + + /* Walk the list of registrants for notification. */ + for( p_reg_item = cl_qlist_tail( &gp_pnp->port_reg_list ); + p_reg_item != cl_qlist_end( &gp_pnp->port_reg_list ); + p_reg_item = cl_qlist_prev( p_reg_item ) ) + { + p_reg = PARENT_STRUCT( p_reg_item, al_pnp_t, list_item ); + + CL_ASSERT( pnp_get_class( p_reg->pnp_class ) == IB_PNP_PORT ); + + p_port_attr = p_event_rec->p_ci_ca->p_pnp_attr->p_port_attr; + p_port_attr += p_event_rec->port_index; + + p_context = pnp_get_context( p_reg, &p_port_attr->port_guid ); + if( !p_context ) + continue; + + /* Notify the user. */ + __pnp_notify_user( p_reg, p_context, p_event_rec ); + } + + AL_EXIT( AL_DBG_PNP ); +} + + +/* + *send asynchronous events + */ +static void +__pnp_send_ae( + IN al_ci_ca_t* const p_ci_ca ) +{ + int ci, cnt, i; + al_pnp_ca_event_t event_rec; + al_ae_info_t ae[MAX_AE]; /* pending Asynchronic Events */ + + if (!p_ci_ca->cnt) + return; + + /* copy events in temp array */ + ci_ca_lock_attr( p_ci_ca ); + cnt = p_ci_ca->cnt; + ci = p_ci_ca->ci; + for (i=0; iae[ci]; + if ( ++ci >= MAX_AE ) + ci = 0; + } + cnt = p_ci_ca->cnt; + p_ci_ca->cnt = 0; + p_ci_ca->ci = ci; + ci_ca_unlock_attr( p_ci_ca ); + + event_rec.p_ci_ca = p_ci_ca; + for (i=0; ip_pnp_attr->num_ports; + event_rec.port_index++ ) + { + p_old_port_attr = p_old_ca_attr->p_port_attr; + p_old_port_attr += event_rec.port_index; + p_new_port_attr = p_ci_ca->p_pnp_attr->p_port_attr; + p_new_port_attr += event_rec.port_index; + + /* Check the link state. */ + if( p_old_port_attr->link_state != p_new_port_attr->link_state ) + { + switch( p_new_port_attr->link_state ) + { + case IB_LINK_DOWN: + event_rec.pnp_event = IB_PNP_PORT_DOWN; + __pnp_process_port_backward( &event_rec ); + break; + + case IB_LINK_INIT: + if( p_old_port_attr->link_state > IB_LINK_INIT ) + { + /* Missed the down event. */ + event_rec.pnp_event = IB_PNP_PORT_DOWN; + __pnp_process_port_backward( &event_rec ); + } + event_rec.pnp_event = IB_PNP_PORT_INIT; + __pnp_process_port_forward( &event_rec ); + break; + + case IB_LINK_ARMED: + if( p_old_port_attr->link_state > IB_LINK_ARMED ) + { + /* Missed the down and init events. */ + event_rec.pnp_event = IB_PNP_PORT_DOWN; + __pnp_process_port_backward( &event_rec ); + event_rec.pnp_event = IB_PNP_PORT_INIT; + __pnp_process_port_forward( &event_rec ); + } + event_rec.pnp_event = IB_PNP_PORT_ARMED; + __pnp_process_port_forward( &event_rec ); + break; + + case IB_LINK_ACTIVE: + case IB_LINK_ACT_DEFER: + if( p_old_port_attr->link_state == IB_LINK_DOWN ) + { + /* Missed the init and armed event. */ + event_rec.pnp_event = IB_PNP_PORT_INIT; + __pnp_process_port_forward( &event_rec ); + event_rec.pnp_event = IB_PNP_PORT_ARMED; + __pnp_process_port_forward( &event_rec ); + } + if( p_old_port_attr->link_state < IB_LINK_ACTIVE ) + { + event_rec.pnp_event = IB_PNP_PORT_ACTIVE; + __pnp_process_port_forward( &event_rec ); + } + break; + + default: + break; + } + } + + /* + * Check for P_Key and GID table changes. + * The tables are only valid in the armed or active states. + */ + if( ( (p_old_port_attr->link_state == IB_LINK_ARMED) || + (p_old_port_attr->link_state == IB_LINK_ACTIVE) ) + && + ( (p_new_port_attr->link_state == IB_LINK_ARMED) || + (p_new_port_attr->link_state == IB_LINK_ACTIVE) ) ) + { + /* A different number of P_Keys indicates a change.*/ + if( p_old_port_attr->num_pkeys != p_new_port_attr->num_pkeys ) + { + event_rec.pnp_event = IB_PNP_PKEY_CHANGE; + __pnp_process_port_forward( &event_rec ); + } + else + { + /* Same number of P_Keys - compare the table contents. */ + for( index = 0; index < p_old_port_attr->num_pkeys; index++ ) + { + if( p_old_port_attr->p_pkey_table[index] != + p_new_port_attr->p_pkey_table[index] ) + { + event_rec.pnp_event = IB_PNP_PKEY_CHANGE; + __pnp_process_port_forward( &event_rec ); + break; + } + } + } + + /* A different number of GIDs indicates a change.*/ + if( p_old_port_attr->num_gids != p_new_port_attr->num_gids ) + { + event_rec.pnp_event = IB_PNP_GID_CHANGE; + __pnp_process_port_forward( &event_rec ); + } + else + { + /* Same number of GIDs - compare the table contents. */ + for( index = 0; index < p_old_port_attr->num_gids; index++ ) + { + if( cl_memcmp( p_old_port_attr->p_gid_table[index].raw, + p_new_port_attr->p_gid_table[index].raw, + sizeof( ib_gid_t ) ) ) + { + event_rec.pnp_event = IB_PNP_GID_CHANGE; + __pnp_process_port_forward( &event_rec ); + break; + } + } + } + } + + /* Check for LID change. */ + if( (p_old_port_attr->lid != p_new_port_attr->lid) || + (p_old_port_attr->lmc != p_new_port_attr->lmc) ) + { + event_rec.pnp_event = IB_PNP_LID_CHANGE; + __pnp_process_port_forward( &event_rec ); + } + /* Check for SM related changes. */ + if( (p_old_port_attr->sm_lid != p_new_port_attr->sm_lid) || + (p_old_port_attr->sm_sl != p_new_port_attr->sm_sl) ) + { + event_rec.pnp_event = IB_PNP_SM_CHANGE; + __pnp_process_port_forward( &event_rec ); + } + /* Check for subnet timeout change. */ + if( p_old_port_attr->subnet_timeout != + p_new_port_attr->subnet_timeout ) + { + event_rec.pnp_event = IB_PNP_SUBNET_TIMEOUT_CHANGE; + __pnp_process_port_forward( &event_rec ); + } + } + +} + + + +static boolean_t +__pnp_cmp_attr( + IN ib_ca_attr_t *p_attr_1, + IN ib_ca_attr_t *p_attr_2 + ) +{ + uint8_t port_index; + ib_port_attr_t* p_port_attr_1; + ib_port_attr_t* p_port_attr_2; + + CL_ASSERT( p_attr_1 && p_attr_2 ); + + for( port_index = 0; + port_index < p_attr_1->num_ports; + port_index++ ) + { + /* Initialize pointers to the port attributes. */ + p_port_attr_1 = &p_attr_1->p_port_attr[port_index]; + p_port_attr_2 = &p_attr_2->p_port_attr[port_index]; + + CL_ASSERT( p_port_attr_1->port_guid == p_port_attr_2->port_guid ); + + if( (cl_memcmp( p_port_attr_1, p_port_attr_2, + offsetof( ib_port_attr_t, p_gid_table ) ) != 0 ) || + (cl_memcmp(p_port_attr_1->p_gid_table,p_port_attr_2->p_gid_table, + p_port_attr_1->num_gids*sizeof(p_port_attr_1->p_gid_table[0]))) || + (cl_memcmp(p_port_attr_1->p_pkey_table,p_port_attr_2->p_pkey_table, + p_port_attr_1->num_pkeys*sizeof(p_port_attr_1->p_pkey_table[0]))) + ) + + { + return FALSE; + } + } + + return TRUE; +} + + + +static void +__pnp_check_events( + IN cl_async_proc_item_t* p_item ) +{ + al_ci_ca_t *p_ci_ca; + size_t i; + uint32_t attr_size; + ib_ca_attr_t *p_old_ca_attr; + ib_api_status_t status; + + AL_ENTER( AL_DBG_PNP ); + + UNUSED_PARAM( p_item ); + CL_ASSERT( gp_pnp ); + + /* Walk all known CAs. */ + for( i = 0; i < cl_ptr_vector_get_size( &gp_pnp->ca_vector ); i++ ) + { + p_ci_ca = (al_ci_ca_t*)cl_ptr_vector_get( &gp_pnp->ca_vector, i ); + + /* Check if the CA was just added to our list but is not ready. */ + if( !p_ci_ca ) + continue; + + attr_size = p_ci_ca->p_pnp_attr->size; + status = ib_query_ca( p_ci_ca->h_ca, p_ci_ca->p_user_attr, &attr_size ); + + /* Report changes if there is an attribute size difference. */ + if( ( attr_size != p_ci_ca->p_pnp_attr->size ) || + !__pnp_cmp_attr( p_ci_ca->p_pnp_attr, p_ci_ca->p_user_attr ) ) + { + status = ci_ca_update_attr( p_ci_ca, &p_old_ca_attr ); + if( status == IB_SUCCESS ) + { + /* Check port attributes and report changes. */ + __pnp_check_ports( p_ci_ca, p_old_ca_attr ); + + /* Free the old CA attributes. */ + cl_free( p_old_ca_attr ); + } + else + { + /* + * Could not get new attribute buffers. + * Skip this event - it should be picked up on the next check. + */ + continue; + } + } + + /* send asynchronous events */ + __pnp_send_ae( p_ci_ca ); + + } + + /* Dereference the PnP Manager. */ + deref_al_obj( &gp_pnp->obj ); + gp_pnp->async_item_is_busy = FALSE; + + AL_EXIT( AL_DBG_PNP ); +} + + + +/* + * Check and report PnP events. + */ +void +pnp_poll( + void ) +{ + AL_ENTER( AL_DBG_PNP ); + + CL_ASSERT( gp_pnp ); + + /* Determine if the PnP manager asynchronous processing item is busy. */ + cl_spinlock_acquire( &gp_pnp->obj.lock ); + + if( gp_pnp->async_item_is_busy ) + { + cl_spinlock_release( &gp_pnp->obj.lock ); + return; + } + + gp_pnp->async_item_is_busy = TRUE; + + cl_spinlock_release( &gp_pnp->obj.lock ); + + /* Reference the PnP Manager. */ + ref_al_obj( &gp_pnp->obj ); + + /* Queue the request to check for PnP events. */ + cl_async_proc_queue( gp_async_pnp_mgr, &gp_pnp->async_item ); + + AL_EXIT( AL_DBG_PNP ); +} + + + +static void +__pnp_process_ca_change( + IN cl_async_proc_item_t* p_item ) +{ + al_pnp_ca_change_t *p_pnp_ca_change; + ib_ca_attr_t *p_old_ca_attr; + al_ci_ca_t *p_ci_ca; + + AL_ENTER( AL_DBG_PNP ); + + CL_ASSERT( p_item ); + CL_ASSERT( gp_pnp ); + + p_pnp_ca_change = PARENT_STRUCT( p_item, al_pnp_ca_change_t, async_item ); + + p_ci_ca = p_pnp_ca_change->p_ci_ca; + + /* + * Prevent readers of the CA attributes from accessing them while + * we are updating the pointers. + */ + ci_ca_excl_lock_attr( p_ci_ca ); + + /* Swap the old and new CA attributes. */ + p_old_ca_attr = p_ci_ca->p_pnp_attr; + p_ci_ca->p_pnp_attr = p_pnp_ca_change->p_new_ca_attr; + p_ci_ca->p_user_attr = (ib_ca_attr_t*)(((uint8_t*)p_ci_ca->p_pnp_attr) + + p_ci_ca->p_pnp_attr->size); + ci_ca_unlock_attr( p_ci_ca ); + + /* Report changes. */ + __pnp_check_ports( p_ci_ca, p_old_ca_attr ); + + /* Free the old CA attributes. */ + cl_free( p_old_ca_attr ); + + /* Dereference the PnP Manager. */ + deref_al_obj( &gp_pnp->obj ); + + AL_EXIT( AL_DBG_PNP ); +} + + + +/* + * Called by user mode AL to report a CA attribute change. + */ +ib_api_status_t +pnp_ca_change( + IN al_ci_ca_t* const p_ci_ca, + IN const ib_ca_attr_t* p_ca_attr ) +{ + ib_ca_attr_t* p_new_ca_attr; + al_pnp_ca_change_t* p_pnp_ca_change; + size_t size; + + AL_ENTER( AL_DBG_PNP ); + + CL_ASSERT( p_ci_ca ); + CL_ASSERT( p_ca_attr ); + + /* + * Allocate the new CA attributes buffer. + * Double the buffer size for PnP and user reporting halves. + * Also include the CA change event structure in the allocation. + */ + size = ( p_ca_attr->size * 2 ) + sizeof( al_pnp_ca_change_t ); + p_new_ca_attr = (ib_ca_attr_t*)cl_zalloc( size ); + if( !p_new_ca_attr ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR,AL_DBG_PNP, + ("Unable to allocate buffer for changed CA attributes\n") ); + return IB_INSUFFICIENT_MEMORY; + } + + /* Copy the attributes. */ + ib_copy_ca_attr( p_new_ca_attr, p_ca_attr ); + + /* Initialize a pointer to the CA change event structure. */ + p_pnp_ca_change = (al_pnp_ca_change_t*) + (((uint8_t*)p_new_ca_attr) + ( p_ca_attr->size * 2 )); + + /* Initialize the CA change event strucuture. */ + p_pnp_ca_change->async_item.pfn_callback = __pnp_process_ca_change; + p_pnp_ca_change->p_ci_ca = p_ci_ca; + p_pnp_ca_change->p_new_ca_attr = p_new_ca_attr; + + /* Reference the PnP Manager. */ + ref_al_obj( &gp_pnp->obj ); + + /* Queue the CA change event. */ + cl_async_proc_queue( gp_async_pnp_mgr, &p_pnp_ca_change->async_item ); + + AL_EXIT( AL_DBG_PNP ); + return IB_SUCCESS; +} + + + +ib_api_status_t +ib_reject_ioc( + IN const ib_al_handle_t h_al, + IN const ib_pnp_handle_t h_event ) +{ + AL_ENTER( AL_DBG_PNP ); + + if( AL_OBJ_INVALID_HANDLE( h_al, AL_OBJ_TYPE_H_AL ) ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_AL_HANDLE\n") ); + return IB_INVALID_AL_HANDLE; + } + if( !h_event ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_HANDLE\n") ); + return IB_INVALID_HANDLE; + } + + AL_EXIT( AL_DBG_PNP ); + return IB_UNSUPPORTED; +} + +void +pnp_force_event( + IN struct _al_ci_ca * p_ci_ca, + IN ib_pnp_event_t pnp_event, + IN uint8_t port_num) +{ +#define PORT_INDEX_OFFSET 1 + + ASSERT(p_ci_ca); + + if (!p_ci_ca) + return; + + p_ci_ca->ae[p_ci_ca->pi].pnp_event = pnp_event; + p_ci_ca->ae[p_ci_ca->pi].port_index = port_num - PORT_INDEX_OFFSET; + ci_ca_lock_attr( p_ci_ca ); + if ( ++p_ci_ca->pi >= MAX_AE ) + p_ci_ca->pi = 0; + ASSERT(p_ci_ca->cnt < MAX_AE); + if ( ++p_ci_ca->cnt > MAX_AE ) + { + p_ci_ca->cnt = MAX_AE; + p_ci_ca->ci =p_ci_ca->pi; + } + ci_ca_unlock_attr( p_ci_ca ); +} + + diff --git a/branches/WOF2-3/core/al/kernel/al_proxy.c b/branches/WOF2-3/core/al/kernel/al_proxy.c new file mode 100644 index 00000000..41bc2030 --- /dev/null +++ b/branches/WOF2-3/core/al/kernel/al_proxy.c @@ -0,0 +1,1276 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include +#include +#include +#include "al.h" +#include "al_mr.h" +#include "al_debug.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "al_proxy.tmh" +#endif +#include "al_dev.h" +#include "al_ci_ca.h" +#include "al_mgr.h" +#include "al_pnp.h" +#include "al_proxy.h" +#include "ib_common.h" + + + +/* + * Acquire an object used to queue callbacks. + */ +al_proxy_cb_info_t* +proxy_cb_get( + IN al_dev_open_context_t *p_context ) +{ + al_proxy_cb_info_t *p_cb_info; + + if( !p_context ) + return NULL; + + cl_spinlock_acquire( &p_context->cb_pool_lock ); + p_cb_info = (al_proxy_cb_info_t*)cl_qpool_get( &p_context->cb_pool ); + cl_spinlock_release( &p_context->cb_pool_lock ); + + if( p_cb_info ) + p_cb_info->p_context = p_context; + + return p_cb_info; +} + + + +/* + * Release an object used to report callbacks. + */ +void +proxy_cb_put( + IN al_proxy_cb_info_t *p_cb_info ) +{ + al_dev_open_context_t *p_context; + + if( !p_cb_info ) + return; + + p_context = p_cb_info->p_context; + + p_cb_info->reported = FALSE; + p_cb_info->p_al_obj = NULL; + + cl_spinlock_acquire( &p_context->cb_pool_lock ); + cl_qpool_put( &p_context->cb_pool, &p_cb_info->pool_item ); + cl_spinlock_release( &p_context->cb_pool_lock ); +} + + + +/* + * Process the ioctl UAL_REG_SHMID: + */ +static +cl_status_t +proxy_reg_shmid( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_reg_shmid_ioctl_t *p_ioctl = + (ual_reg_shmid_ioctl_t *)cl_ioctl_in_buf( h_ioctl ); + al_dev_open_context_t *p_context = + (al_dev_open_context_t *)p_open_context; + ib_pd_handle_t h_pd; + ib_mr_handle_t h_mr; + uint64_t vaddr; + net32_t lkey, rkey; + + AL_ENTER( AL_DBG_DEV ); + + if( !cl_ioctl_in_buf( h_ioctl ) || !cl_ioctl_out_buf( h_ioctl ) || + cl_ioctl_in_size( h_ioctl ) < sizeof(ual_reg_shmid_ioctl_t) || + cl_ioctl_out_size( h_ioctl ) < sizeof(ual_reg_shmid_ioctl_t) ) + { + AL_EXIT( AL_DBG_DEV ); + return CL_INVALID_PARAMETER; + } + + /* Validate PD handle */ + h_pd = (ib_pd_handle_t) + al_hdl_ref( p_context->h_al, p_ioctl->in.h_pd, AL_OBJ_TYPE_H_PD ); + if( !h_pd ) + { + cl_memclr( &p_ioctl->out, sizeof(p_ioctl->out) ); + p_ioctl->out.status = IB_INVALID_PD_HANDLE; + goto done; + } + + /* Validate input region size. */ + if( p_ioctl->in.mr_create.length > ~((size_t)0) ) + { + cl_memclr( &p_ioctl->out, sizeof(p_ioctl->out) ); + p_ioctl->out.status = IB_INVALID_SETTING; + goto done; + } + + p_ioctl->out.status = reg_shmid( + h_pd, + p_ioctl->in.shmid, + &p_ioctl->in.mr_create, + &vaddr, + &lkey, + &rkey, + &h_mr ); + + if( p_ioctl->out.status == IB_SUCCESS ) + { + /* We put the kernel al handle itself in the al_list for the process */ + p_ioctl->out.vaddr = vaddr; + p_ioctl->out.lkey = lkey; + p_ioctl->out.rkey = rkey; + p_ioctl->out.h_mr = h_mr->obj.hdl; + h_mr->obj.hdl_valid = TRUE; + deref_al_obj( &h_mr->obj ); + } + else + { + /* release the memory handle allocated */ + p_ioctl->out.vaddr = 0; + p_ioctl->out.lkey = 0; + p_ioctl->out.rkey = 0; + p_ioctl->out.h_mr = AL_INVALID_HANDLE; + } + +done: + *p_ret_bytes = sizeof(p_ioctl->out); + AL_EXIT( AL_DBG_DEV ); + return CL_SUCCESS; +} + + +/* + * Retrieve a callback record from the appropriate callback list + * and fill the ioctl buffer. + * + * If no callback record is available, queue the ioctl buffer. + * Queued ioctl buffer will put the calling process to sleep and complete + * when complete when a callback record is available. + */ +static cl_status_t +proxy_queue_ioctl_buf( + IN uintn_t cb_type, + IN al_dev_open_context_t *p_context, + IN cl_ioctl_handle_t h_ioctl ) +{ + cl_qlist_t *p_cb_list; + al_proxy_cb_info_t *p_cb_info; + al_csq_t *p_al_csq = &p_context->al_csq; + uintn_t ioctl_size; + + AL_ENTER( AL_DBG_DEV ); + + /* Set up the appropriate callback list. */ + switch( cb_type ) + { + case UAL_GET_COMP_CB_INFO: + p_cb_list = &p_context->comp_cb_list; + /* TODO: Use output size only. */ + ioctl_size = sizeof( comp_cb_ioctl_info_t ); + break; + + case UAL_GET_MISC_CB_INFO: + p_cb_list = &p_context->misc_cb_list; + /* TODO: Use output size only. */ + ioctl_size = sizeof( misc_cb_ioctl_info_t ); + break; + + default: + AL_EXIT( AL_DBG_DEV ); + return CL_INVALID_PARAMETER; + } + + /* Process queued callbacks. */ + cl_spinlock_acquire( &p_context->cb_lock ); + while( !cl_is_qlist_empty( p_cb_list ) ) + { + p_cb_info = (al_proxy_cb_info_t*)cl_qlist_head( p_cb_list ); + + /* Check to see if we've already reported the callback. */ + if( !p_cb_info->reported ) + { + p_cb_info->reported = TRUE; + + /* Return the callback to the user. */ + CL_ASSERT( cl_ioctl_out_size( h_ioctl ) >= ioctl_size ); + cl_memcpy( + cl_ioctl_out_buf( h_ioctl ), &p_cb_info->cb_type, ioctl_size ); + cl_ioctl_complete( h_ioctl, CL_SUCCESS, ioctl_size ); + cl_spinlock_release( &p_context->cb_lock ); + AL_EXIT( AL_DBG_DEV ); + return CL_COMPLETED; + } + if( p_cb_info->p_al_obj ) + deref_al_obj( p_cb_info->p_al_obj ); + + cl_qlist_remove_head( p_cb_list ); + proxy_cb_put( p_cb_info ); + } + + /* There are no callbacks to report. Mark this IOCTL as pending. */ + + /* If we're closing down, complete the IOCTL with a canceled status. */ + if( p_context->closing ) + { + cl_spinlock_release( &p_context->cb_lock ); + AL_EXIT( AL_DBG_DEV ); + return CL_CANCELED; + } + + /* put ioctl on the cancel-safe queue (it makes it pending) */ + IoCsqInsertIrp( (PIO_CSQ)p_al_csq, h_ioctl, NULL ); + + /* Ref the context until the IOCTL is either completed or cancelled. */ + proxy_context_ref( p_context ); + cl_spinlock_release( &p_context->cb_lock ); + + AL_EXIT( AL_DBG_DEV ); + return CL_PENDING; +} + + + +/* + * Process the ioctl UAL_GET_COMP_CB_INFO: + * Get a completion callback record from the queue of CM callback records + */ +static cl_status_t +proxy_get_comp_cb( + IN cl_ioctl_handle_t h_ioctl ) +{ + cl_status_t cl_status; + IO_STACK_LOCATION *p_io_stack; + al_dev_open_context_t *p_context; + + AL_ENTER( AL_DBG_DEV ); + + p_io_stack = IoGetCurrentIrpStackLocation( h_ioctl ); + p_context = (al_dev_open_context_t*)p_io_stack->FileObject->FsContext; + if( (uintn_t)p_io_stack->FileObject->FsContext2 != AL_OBJ_TYPE_H_CQ ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("Invalid file object type for request: %p\n", + p_io_stack->FileObject->FsContext2) ); + return CL_INVALID_PARAMETER; + } + + /* Check the size of the ioctl */ + if( !p_context || !cl_ioctl_out_buf( h_ioctl ) || + cl_ioctl_out_size( h_ioctl ) != sizeof(comp_cb_ioctl_info_t) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("No output buffer, or buffer too small.\n") ); + return CL_INVALID_PARAMETER; + } + + cl_status = proxy_queue_ioctl_buf( UAL_GET_COMP_CB_INFO, + p_context, h_ioctl ); + + AL_EXIT( AL_DBG_DEV ); + return cl_status; +} + + + +/* + * Process the ioctl UAL_GET_MISC_CB_INFO: + * Get a miscellaneous callback record from the queue of CM callback records + */ +static cl_status_t +proxy_get_misc_cb( + IN cl_ioctl_handle_t h_ioctl ) +{ + cl_status_t cl_status; + IO_STACK_LOCATION *p_io_stack; + al_dev_open_context_t *p_context; + + AL_ENTER( AL_DBG_DEV ); + + p_io_stack = IoGetCurrentIrpStackLocation( h_ioctl ); + p_context = (al_dev_open_context_t*)p_io_stack->FileObject->FsContext; + if( (uintn_t)p_io_stack->FileObject->FsContext2 != AL_OBJ_TYPE_AL_MGR ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("Invalid file object type for request: %p\n", + p_io_stack->FileObject->FsContext2) ); + return CL_INVALID_PARAMETER; + } + + /* Check the size of the ioctl */ + if( !p_context || !cl_ioctl_out_buf( h_ioctl ) || + cl_ioctl_out_size( h_ioctl ) != sizeof(misc_cb_ioctl_info_t) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("No output buffer, or buffer too small.\n") ); + return CL_INVALID_PARAMETER; + } + + cl_status = proxy_queue_ioctl_buf( UAL_GET_MISC_CB_INFO, + p_context, h_ioctl ); + + AL_EXIT( AL_DBG_DEV ); + return cl_status; +} + + + +/* + * Process a PnP callback for a CA. + */ +ib_api_status_t +proxy_pnp_ca_cb( + IN ib_pnp_rec_t *p_pnp_rec ) +{ + misc_cb_ioctl_info_t misc_cb_info; + misc_cb_ioctl_rec_t *p_misc_rec = &misc_cb_info.ioctl_rec; + al_dev_open_context_t *p_context; + + AL_ENTER( AL_DBG_PROXY_CB ); + + p_context = p_pnp_rec->pnp_context; + + /* + * If we're already closing the device - do not queue a callback, since + * we're cleaning up the callback lists. + */ + if( !proxy_context_ref( p_context ) ) + { + proxy_context_deref( p_context ); + return IB_ERROR; + } + + /* Initialize the PnP callback information to return to user-mode. */ + cl_memclr( &misc_cb_info, sizeof(misc_cb_info) ); + misc_cb_info.rec_type = PNP_REC; + p_misc_rec->pnp_cb_ioctl_rec.pnp_event = p_pnp_rec->pnp_event; + + switch( p_pnp_rec->pnp_event ) + { + case IB_PNP_CA_ADD: + case IB_PNP_CA_REMOVE: + /* Queue the add/remove pnp record */ + p_misc_rec->pnp_cb_ioctl_rec.pnp_info.ca.ca_guid = p_pnp_rec->guid; + proxy_queue_cb_buf( UAL_GET_MISC_CB_INFO, p_context, &misc_cb_info, + NULL ); + break; + + default: + /* We only handle CA adds and removals. */ + break; + } + + proxy_context_deref( p_context ); + AL_EXIT( AL_DBG_PROXY_CB ); + return IB_SUCCESS; +} + + + +/* + * Process a PnP callback for a port. + */ +ib_api_status_t +proxy_pnp_port_cb( + IN ib_pnp_rec_t *p_pnp_rec ) +{ + ib_pnp_port_rec_t *p_port_rec; + misc_cb_ioctl_info_t misc_cb_info; + misc_cb_ioctl_rec_t *p_misc_rec = &misc_cb_info.ioctl_rec; + al_dev_open_context_t *p_context; + + AL_ENTER( AL_DBG_PROXY_CB ); + + p_context = p_pnp_rec->pnp_context; + + /* + * If we're already closing the device - do not queue a callback, since + * we're cleaning up the callback lists. + */ + if( !proxy_context_ref( p_context ) ) + { + proxy_context_deref( p_context ); + return IB_ERROR; + } + + p_port_rec = (ib_pnp_port_rec_t*)p_pnp_rec; + + /* Initialize the PnP callback information to return to user-mode. */ + cl_memclr( &misc_cb_info, sizeof(misc_cb_info) ); + misc_cb_info.rec_type = PNP_REC; + p_misc_rec->pnp_cb_ioctl_rec.pnp_event = p_pnp_rec->pnp_event; + + switch( p_pnp_rec->pnp_event ) + { + case IB_PNP_PORT_ADD: + case IB_PNP_PORT_REMOVE: + /* Port add/remove will be generated automatically by uAL. */ + break; + + case IB_PNP_REG_COMPLETE: + /* + * Once our registration for ports is complete, report this to the + * user-mode library. This indicates to the that the current + * system state has been reported. + */ + proxy_queue_cb_buf( UAL_GET_MISC_CB_INFO, p_context, &misc_cb_info, + NULL ); + break; + + default: + p_misc_rec->pnp_cb_ioctl_rec.pnp_info.ca.ca_guid = + p_port_rec->p_ca_attr->ca_guid; + + proxy_queue_cb_buf( UAL_GET_MISC_CB_INFO, p_context, &misc_cb_info, + NULL ); + break; + } + + proxy_context_deref( p_context ); + AL_EXIT( AL_DBG_PROXY_CB ); + return IB_SUCCESS; +} + + + +cl_status_t +proxy_get_ca_attr( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + al_dev_open_context_t *p_context; + uint64_t *ph_ca_attr; + ib_ca_attr_t *p_src; + + AL_ENTER( AL_DBG_DEV ); + + UNREFERENCED_PARAMETER( p_ret_bytes ); + + /* Check the size of the ioctl */ + if( !cl_ioctl_in_buf( h_ioctl ) || + cl_ioctl_in_size( h_ioctl ) < sizeof(uint64_t) ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("invalid buffer size\n") ); + return CL_INVALID_PARAMETER; + } + p_context = (al_dev_open_context_t*)p_open_context; + ph_ca_attr = (uint64_t*)cl_ioctl_in_buf( h_ioctl ); + + p_src = (ib_ca_attr_t*)al_hdl_get( + p_context->h_al, *ph_ca_attr, AL_OBJ_TYPE_H_CA_ATTR ); + if( !p_src ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("invalid attr handle\n") ); + return CL_INVALID_PARAMETER; + } + + cl_free(p_src); + + AL_EXIT( AL_DBG_DEV ); + return CL_SUCCESS; +} + + +/* + * Process the ioctl UAL_BIND_SA: + * Get a completion callback record from the queue of CM callback records + */ +static cl_status_t +proxy_bind_file( + IN cl_ioctl_handle_t h_ioctl, + IN const uint32_t type ) +{ + NTSTATUS status; + IO_STACK_LOCATION *p_io_stack; + al_dev_open_context_t *p_context; + ual_bind_file_ioctl_t *p_ioctl; + FILE_OBJECT *p_file_obj; + + AL_ENTER( AL_DBG_DEV ); + + p_io_stack = IoGetCurrentIrpStackLocation( h_ioctl ); + p_context = (al_dev_open_context_t*)p_io_stack->FileObject->FsContext; + + /* Check the size of the ioctl */ + if( !p_context || + !cl_ioctl_in_buf( h_ioctl ) || cl_ioctl_out_size( h_ioctl ) || + cl_ioctl_in_size( h_ioctl ) != sizeof(ual_bind_file_ioctl_t) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("No input buffer, or buffer too small.\n") ); + return CL_INVALID_PARAMETER; + } + + p_ioctl = cl_ioctl_in_buf( h_ioctl ); + + status = ObReferenceObjectByHandle( p_ioctl->h_file, + READ_CONTROL, *IoFileObjectType, h_ioctl->RequestorMode, + &p_file_obj, NULL ); + if( !NT_SUCCESS(status) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("ObReferenceObjectByHandle returned 0x%08X\n", status) ); + return CL_INVALID_PARAMETER; + } + + p_file_obj->FsContext = p_context; + p_file_obj->FsContext2 = (void*)(ULONG_PTR)type; + + ObDereferenceObject( p_file_obj ); + + AL_EXIT( AL_DBG_DEV ); + return CL_SUCCESS; +} + + + +cl_status_t +proxy_ioctl( + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + cl_status_t cl_status; + + AL_ENTER( AL_DBG_DEV ); + + UNUSED_PARAM( p_ret_bytes ); + + switch( cl_ioctl_ctl_code( h_ioctl ) ) + { + case UAL_GET_MISC_CB_INFO: + cl_status = proxy_get_misc_cb( h_ioctl ); + break; + case UAL_GET_COMP_CB_INFO: + cl_status = proxy_get_comp_cb( h_ioctl ); + break; + case UAL_BIND: + cl_status = al_dev_open( h_ioctl ); + break; + case UAL_BIND_SA: + cl_status = proxy_bind_file( h_ioctl, AL_OBJ_TYPE_SA_REQ_SVC ); + break; + case UAL_BIND_DESTROY: + case UAL_BIND_PNP: + cl_status = proxy_bind_file( h_ioctl, AL_OBJ_TYPE_PNP_MGR ); + break; + case UAL_BIND_CM: + cl_status = proxy_bind_file( h_ioctl, AL_OBJ_TYPE_CM ); + break; + case UAL_BIND_CQ: + cl_status = proxy_bind_file( h_ioctl, AL_OBJ_TYPE_H_CQ ); + break; + case UAL_BIND_MISC: + cl_status = proxy_bind_file( h_ioctl, AL_OBJ_TYPE_AL_MGR ); + break; + case UAL_BIND_ND: + cl_status = proxy_bind_file( h_ioctl, AL_OBJ_TYPE_NDI ); + break; + default: + cl_status = CL_INVALID_PARAMETER; + break; + } + + AL_EXIT( AL_DBG_DEV ); + return cl_status; +} + + +static ib_api_status_t +__proxy_pnp_cb( + IN ib_pnp_rec_t *p_pnp_rec ) +{ + proxy_pnp_evt_t *p_evt; + uint32_t rec_size; + proxy_pnp_recs_t *p_evt_rec, *p_rec; + IRP *p_irp; + IO_STACK_LOCATION *p_io_stack; + ual_rearm_pnp_ioctl_out_t *p_ioctl; + al_dev_open_context_t *p_context; + uint64_t hdl; + cl_status_t cl_status; + ib_api_status_t ret_status; + + AL_ENTER( AL_DBG_PNP ); + + p_rec = (proxy_pnp_recs_t*)p_pnp_rec; + + /* + * If an add event, return error to suppress all further + * events for this target. + */ + if( p_pnp_rec->pnp_event & IB_PNP_EVENT_ADD ) + ret_status = IB_ERROR; + else + ret_status = IB_SUCCESS; + + p_context = p_pnp_rec->pnp_context; + ASSERT( p_context ); + + /* Must take and release mutex to synchronize with registration. */ + cl_mutex_acquire( &p_context->pnp_mutex ); + cl_mutex_release( &p_context->pnp_mutex ); + + p_irp = InterlockedExchangePointer( &p_pnp_rec->h_pnp->p_rearm_irp, NULL ); + if( !p_irp ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("No rearm IRP queued for PnP event.\n") ); + return ret_status; + } + + p_io_stack = IoGetCurrentIrpStackLocation( p_irp ); + + p_context = p_io_stack->FileObject->FsContext; + ASSERT( p_context ); +#pragma warning(push, 3) + IoSetCancelRoutine( p_irp, NULL ); +#pragma warning(pop) + switch( pnp_get_class( p_pnp_rec->pnp_event ) ) + { + case IB_PNP_CA: + if( p_pnp_rec->pnp_event == IB_PNP_CA_REMOVE ) + rec_size = sizeof(ib_pnp_ca_rec_t); + else + rec_size = sizeof(ib_pnp_ca_rec_t) + p_rec->ca.p_ca_attr->size; + break; + case IB_PNP_PORT: + if( p_pnp_rec->pnp_event == IB_PNP_PORT_REMOVE ) + rec_size = sizeof(ib_pnp_port_rec_t); + else + rec_size = sizeof(ib_pnp_port_rec_t) + p_rec->port.p_ca_attr->size; + break; + case IB_PNP_IOU: + rec_size = sizeof(ib_pnp_iou_rec_t); + break; + case IB_PNP_IOC: + switch( p_pnp_rec->pnp_event ) + { + case IB_PNP_IOC_PATH_ADD: + case IB_PNP_IOC_PATH_REMOVE: + rec_size = sizeof( ib_pnp_ioc_path_rec_t); + break; + default: + rec_size = sizeof( ib_pnp_ioc_rec_t ) + (sizeof(ib_svc_entry_t) * + (p_rec->ioc.info.profile.num_svc_entries - 1)); + } + break; + default: + /* The REG_COMPLETE event is not associated with any class. */ + rec_size = sizeof( ib_pnp_rec_t ); + break; + } + + p_evt = cl_zalloc( rec_size + sizeof(proxy_pnp_evt_t) ); + if( !p_evt ) + return ret_status; + + /* Note that cl_event_init cannot fail in kernel-mode. */ + cl_event_init( &p_evt->event, FALSE ); + + p_evt->rec_size = rec_size; + + p_evt_rec = (proxy_pnp_recs_t*)(p_evt + 1); + + /* Copy the PnP event data. */ + switch( pnp_get_class( p_pnp_rec->pnp_event ) ) + { + case IB_PNP_CA: + cl_memcpy( p_evt_rec, p_pnp_rec, sizeof(ib_pnp_ca_rec_t) ); + if( p_pnp_rec->pnp_event == IB_PNP_CA_REMOVE ) + { + p_evt_rec->ca.p_ca_attr = NULL; + } + else + { + p_evt_rec->ca.p_ca_attr = (ib_ca_attr_t*)(&p_evt_rec->ca + 1); + ib_copy_ca_attr( p_evt_rec->ca.p_ca_attr, p_rec->ca.p_ca_attr ); + } + break; + case IB_PNP_PORT: + cl_memcpy( p_evt_rec, p_pnp_rec, sizeof(ib_pnp_port_rec_t) ); + if( p_pnp_rec->pnp_event == IB_PNP_PORT_REMOVE ) + { + p_evt_rec->port.p_ca_attr = NULL; + p_evt_rec->port.p_port_attr = NULL; + } + else + { + p_evt_rec->port.p_ca_attr = (ib_ca_attr_t*)(&p_evt_rec->port + 1); + ib_copy_ca_attr( + p_evt_rec->port.p_ca_attr, p_rec->port.p_ca_attr ); + p_evt_rec->port.p_port_attr = &p_evt_rec->port.p_ca_attr-> + p_port_attr[p_rec->port.p_port_attr->port_num - 1]; + } + break; + case IB_PNP_IOU: + cl_memcpy( p_evt_rec, p_pnp_rec, sizeof(ib_pnp_iou_rec_t) ); + break; + case IB_PNP_IOC: + switch( p_pnp_rec->pnp_event ) + { + case IB_PNP_IOC_PATH_ADD: + case IB_PNP_IOC_PATH_REMOVE: + cl_memcpy( p_evt_rec, p_pnp_rec, sizeof(ib_pnp_ioc_path_rec_t) ); + break; + default: + cl_memcpy( p_evt_rec, p_pnp_rec, sizeof(ib_pnp_ioc_rec_t) ); + } + break; + default: + p_evt_rec->pnp = *p_pnp_rec; + break; + } + + p_evt_rec->pnp.h_pnp_padding = p_pnp_rec->h_pnp->obj.hdl; + p_pnp_rec->h_pnp->obj.hdl_valid = TRUE; + + hdl = + al_hdl_lock_insert( p_context->h_al, p_evt, AL_OBJ_TYPE_H_PNP_EVENT ); + if( hdl == AL_INVALID_HANDLE ) + { + cl_free( p_evt ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("Failed to insert PnP event in handle map.\n") ); + return ret_status; + } + + p_ioctl = cl_ioctl_out_buf( p_irp ); + p_ioctl->evt_hdl = hdl; + p_ioctl->evt_size = rec_size; + + /* Hold callback lock to synchronize with registration. */ + cl_spinlock_acquire( &p_context->cb_lock ); + p_irp->IoStatus.Status = STATUS_SUCCESS; + p_irp->IoStatus.Information = sizeof(ual_rearm_pnp_ioctl_out_t); + IoCompleteRequest( p_irp, IO_NO_INCREMENT ); + cl_spinlock_release( &p_context->cb_lock ); + + /* Now wait on the event. */ + cl_status = cl_event_wait_on( &p_evt->event, PROXY_PNP_TIMEOUT_US, FALSE ); + if( cl_status == CL_SUCCESS ) + { + /* Update the event context with the user's requested value. */ + p_pnp_rec->context = p_evt->evt_context; + /* Forward the user's status. */ + ret_status = p_evt->evt_status; + } + cl_spinlock_acquire( &p_context->h_al->obj.lock ); + al_hdl_free( p_context->h_al, hdl ); + cl_spinlock_release( &p_context->h_al->obj.lock ); + cl_event_destroy( &p_evt->event ); + cl_free( p_evt ); + + AL_EXIT( AL_DBG_PNP ); + return ret_status; +} + + +static void +__cancel_rearm_pnp( + IN DEVICE_OBJECT* p_dev_obj, + IN IRP* p_irp ) +{ + al_dev_open_context_t *p_context; + PIO_STACK_LOCATION p_io_stack; + uint64_t hdl; + al_pnp_t *h_pnp; + + AL_ENTER( AL_DBG_DEV ); + + UNUSED_PARAM( p_dev_obj ); + + /* Get the stack location. */ + p_io_stack = IoGetCurrentIrpStackLocation( p_irp ); + + p_context = (al_dev_open_context_t *)p_io_stack->FileObject->FsContext; + ASSERT( p_context ); + + hdl = (size_t)InterlockedExchangePointer( + &p_irp->Tail.Overlay.DriverContext[0], NULL ); + if( hdl != AL_INVALID_HANDLE ) + { + h_pnp = (al_pnp_t*) + al_hdl_ref( p_context->h_al, hdl, AL_OBJ_TYPE_H_PNP ); + if( h_pnp ) + { + if( InterlockedExchangePointer( &h_pnp->p_rearm_irp, NULL ) == + p_irp ) + { +#pragma warning(push, 3) + IoSetCancelRoutine( p_irp, NULL ); +#pragma warning(pop) + /* Complete the IRP. */ + p_irp->IoStatus.Status = STATUS_CANCELLED; + p_irp->IoStatus.Information = 0; + IoCompleteRequest( p_irp, IO_NO_INCREMENT ); + } + deref_al_obj( &h_pnp->obj ); + } + } + + IoReleaseCancelSpinLock( p_irp->CancelIrql ); +} + + +/* + * Process the ioctl UAL_REG_PNP: + */ +static cl_status_t +proxy_reg_pnp( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl ) +{ + ual_reg_pnp_ioctl_in_t *p_ioctl; + al_dev_open_context_t *p_context; + IO_STACK_LOCATION *p_io_stack; + ib_pnp_req_t pnp_req; + ib_api_status_t status, *p_user_status; + uint64_t *p_user_hdl; + ib_pnp_handle_t h_pnp; + cl_status_t cl_status; + KEVENT *p_sync_event; + NTSTATUS nt_status; + + AL_ENTER( AL_DBG_PNP ); + + p_context = p_open_context; + + p_io_stack = IoGetCurrentIrpStackLocation( h_ioctl ); + if( (uintn_t)p_io_stack->FileObject->FsContext2 != AL_OBJ_TYPE_PNP_MGR ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("Invalid file object type for request: %p\n", + p_io_stack->FileObject->FsContext2) ); + return CL_INVALID_PARAMETER; + } + + if( cl_ioctl_in_size( h_ioctl ) < sizeof(ual_reg_pnp_ioctl_in_t) || + cl_ioctl_out_size( h_ioctl ) < sizeof(ual_rearm_pnp_ioctl_out_t) ) + { + AL_EXIT( AL_DBG_PNP ); + return CL_INVALID_PARAMETER; + } + + p_ioctl = cl_ioctl_in_buf( h_ioctl ); + + pnp_req.pnp_class = p_ioctl->pnp_class; + pnp_req.pnp_context = p_open_context; + pnp_req.pfn_pnp_cb = __proxy_pnp_cb; + + p_user_status = (ib_api_status_t*)(ULONG_PTR)p_ioctl->p_status; + p_user_hdl = (uint64_t*)(ULONG_PTR)p_ioctl->p_hdl; + + if( pnp_get_flag( p_ioctl->pnp_class ) & IB_PNP_FLAG_REG_SYNC ) + { + nt_status = ObReferenceObjectByHandle( p_ioctl->sync_event, + STANDARD_RIGHTS_ALL, *ExEventObjectType, h_ioctl->RequestorMode, + (PVOID*)&p_sync_event, NULL ); + if( !NT_SUCCESS( nt_status ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("Invalid sync event handle\n") ); + return CL_INVALID_PARAMETER; + } + } + else + { + p_sync_event = NULL; + } + + cl_mutex_acquire( &p_context->pnp_mutex ); + status = al_reg_pnp( p_context->h_al, &pnp_req, p_sync_event, &h_pnp ); + if( status == IB_SUCCESS ) + { + CL_ASSERT( h_pnp ); + h_pnp->p_rearm_irp = h_ioctl; + + h_ioctl->Tail.Overlay.DriverContext[0] = (void*)(size_t)h_pnp->obj.hdl; +#pragma warning(push, 3) + IoSetCancelRoutine( h_ioctl, __cancel_rearm_pnp ); +#pragma warning(pop) + IoMarkIrpPending( h_ioctl ); + + cl_copy_to_user( p_user_hdl, &h_pnp->obj.hdl, sizeof(uint64_t) ); + + /* Mark the registration as a user-mode one. */ + h_pnp->obj.type |= AL_OBJ_SUBTYPE_UM_EXPORT; + h_pnp->obj.hdl_valid = TRUE; + deref_al_obj( &h_pnp->obj ); + + cl_status = CL_PENDING; + } + else + { + cl_status = CL_INVALID_PARAMETER; + } + + cl_copy_to_user( p_user_status, &status, sizeof(ib_api_status_t) ); + cl_mutex_release( &p_context->pnp_mutex ); + + AL_EXIT( AL_DBG_PNP ); + return cl_status; +} + + +/* + * Process the ioctl UAL_REG_PNP: + */ +static cl_status_t +proxy_poll_pnp( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_poll_pnp_ioctl_t *p_ioctl; + al_dev_open_context_t *p_context; + proxy_pnp_evt_t *p_evt; + + AL_ENTER( AL_DBG_PNP ); + + p_context = p_open_context; + + if( cl_ioctl_in_size( h_ioctl ) < sizeof(uint64_t) || + cl_ioctl_out_size( h_ioctl ) < sizeof(ib_pnp_rec_t) ) + { + AL_EXIT( AL_DBG_PNP ); + return CL_INVALID_PARAMETER; + } + + p_ioctl = cl_ioctl_in_buf( h_ioctl ); + CL_ASSERT( cl_ioctl_in_buf( h_ioctl ) == cl_ioctl_out_buf( h_ioctl ) ); + + cl_spinlock_acquire( &p_context->h_al->obj.lock ); + p_evt = al_hdl_chk( + p_context->h_al, p_ioctl->in.evt_hdl, AL_OBJ_TYPE_H_PNP_EVENT ); + if( p_evt ) + { + if( cl_ioctl_out_size( h_ioctl ) < p_evt->rec_size ) + { + cl_spinlock_release( &p_context->h_al->obj.lock ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("Buffer too small!\n") ); + return CL_INVALID_PARAMETER; + } + + cl_memcpy( &p_ioctl->out.pnp_rec, p_evt + 1, p_evt->rec_size ); + *p_ret_bytes = p_evt->rec_size; + } + cl_spinlock_release( &p_context->h_al->obj.lock ); + + AL_EXIT( AL_DBG_PNP ); + return CL_SUCCESS; +} + + +/* + * Process the ioctl UAL_REG_PNP: + */ +static cl_status_t +proxy_rearm_pnp( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl ) +{ + ual_rearm_pnp_ioctl_in_t *p_ioctl; + al_dev_open_context_t *p_context; + IO_STACK_LOCATION *p_io_stack; + proxy_pnp_evt_t *p_evt; + ib_pnp_handle_t h_pnp; + IRP *p_old_irp; + + AL_ENTER( AL_DBG_PNP ); + + p_context = p_open_context; + + p_io_stack = IoGetCurrentIrpStackLocation( h_ioctl ); + if( (uintn_t)p_io_stack->FileObject->FsContext2 != AL_OBJ_TYPE_PNP_MGR ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("Invalid file object type for request: %p\n", + p_io_stack->FileObject->FsContext2) ); + return CL_INVALID_PARAMETER; + } + + if( cl_ioctl_in_size( h_ioctl ) != sizeof(ual_rearm_pnp_ioctl_in_t) || + cl_ioctl_out_size( h_ioctl ) != sizeof(ual_rearm_pnp_ioctl_out_t) ) + { + AL_EXIT( AL_DBG_PNP ); + return CL_INVALID_PARAMETER; + } + + p_ioctl = cl_ioctl_in_buf( h_ioctl ); + + h_pnp = (al_pnp_t*) + al_hdl_ref( p_context->h_al, p_ioctl->pnp_hdl, AL_OBJ_TYPE_H_PNP ); + if( !h_pnp ) + { + AL_PRINT_EXIT( TRACE_LEVEL_WARNING, AL_DBG_PNP, + ("Invalid PNP handle.\n") ); + return CL_INVALID_PARAMETER; + } +#pragma warning(push, 3) + IoSetCancelRoutine( h_ioctl, __cancel_rearm_pnp ); +#pragma warning(pop) + IoMarkIrpPending( h_ioctl ); + h_ioctl->Tail.Overlay.DriverContext[0] = (void*)(size_t)h_pnp->obj.hdl; + + /* + * Update the object context before signalling the event since that value + * is returned by the PnP callback. + */ + p_old_irp = InterlockedExchangePointer( &h_pnp->p_rearm_irp, h_ioctl ); + if( p_old_irp ) + { +#pragma warning(push, 3) + IoSetCancelRoutine( p_old_irp, NULL ); +#pragma warning(pop) + /* Complete the IRP. */ + p_old_irp->IoStatus.Status = STATUS_CANCELLED; + p_old_irp->IoStatus.Information = 0; + IoCompleteRequest( p_old_irp, IO_NO_INCREMENT ); + } + + cl_spinlock_acquire( &p_context->h_al->obj.lock ); + p_evt = al_hdl_chk( + p_context->h_al, p_ioctl->last_evt_hdl, AL_OBJ_TYPE_H_PNP_EVENT ); + if( p_evt ) + { + p_evt->evt_context = (void*)(ULONG_PTR)p_ioctl->last_evt_context; + p_evt->evt_status = p_ioctl->last_evt_status; + cl_event_signal( &p_evt->event ); + } + cl_spinlock_release( &p_context->h_al->obj.lock ); + + deref_al_obj( &h_pnp->obj ); + + AL_EXIT( AL_DBG_PNP ); + return CL_PENDING; +} + + +/* + * Process the ioctl UAL_DEREG_PNP: + */ +static cl_status_t +proxy_dereg_pnp( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl ) +{ + uint64_t *p_hdl; + al_dev_open_context_t *p_context; + IO_STACK_LOCATION *p_io_stack; + ib_pnp_handle_t h_pnp; + + AL_ENTER( AL_DBG_PNP ); + p_context = p_open_context; + + p_io_stack = IoGetCurrentIrpStackLocation( h_ioctl ); + if( (uintn_t)p_io_stack->FileObject->FsContext2 != AL_OBJ_TYPE_PNP_MGR ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("Invalid file object type for request: %p\n", + p_io_stack->FileObject->FsContext2) ); + return CL_INVALID_PARAMETER; + } + + if( cl_ioctl_in_size( h_ioctl ) < sizeof(ual_dereg_pnp_ioctl_t) || + cl_ioctl_out_size( h_ioctl ) ) + { + AL_EXIT( AL_DBG_DEV ); + return CL_INVALID_PARAMETER; + } + + p_hdl = cl_ioctl_in_buf( h_ioctl ); + + h_pnp = (ib_pnp_handle_t) + al_hdl_ref( p_context->h_al, *p_hdl, AL_OBJ_TYPE_H_PNP ); + if( !h_pnp ) + { + AL_EXIT( AL_DBG_DEV ); + return CL_INVALID_PARAMETER; + } + + h_pnp->p_dereg_irp = h_ioctl; + + IoMarkIrpPending( h_ioctl ); + + h_pnp->obj.pfn_destroy( &h_pnp->obj, NULL ); + + AL_EXIT( AL_DBG_PNP ); + return CL_PENDING; +} + + + +cl_status_t +al_ioctl( + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + cl_status_t cl_status; + IO_STACK_LOCATION *p_io_stack; + void *p_context; + + AL_ENTER( AL_DBG_DEV ); + + CL_ASSERT( h_ioctl && p_ret_bytes ); + + p_io_stack = IoGetCurrentIrpStackLocation( h_ioctl ); + p_context = p_io_stack->FileObject->FsContext; + + if( !p_context ) + { + AL_EXIT( AL_DBG_DEV ); + return CL_INVALID_PARAMETER; + } + + switch( cl_ioctl_ctl_code( h_ioctl ) ) + { + case UAL_REG_SHMID: + cl_status = proxy_reg_shmid( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_GET_CA_ATTR_INFO: + cl_status = proxy_get_ca_attr( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_REG_PNP: + cl_status = proxy_reg_pnp( p_context, h_ioctl ); + break; + case UAL_POLL_PNP: + cl_status = proxy_poll_pnp( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_REARM_PNP: + cl_status = proxy_rearm_pnp( p_context, h_ioctl ); + break; + case UAL_DEREG_PNP: + cl_status = proxy_dereg_pnp( p_context, h_ioctl ); + break; + default: + cl_status = CL_INVALID_PARAMETER; + break; + } + + AL_EXIT( AL_DBG_DEV ); + return cl_status; +} + + +NTSTATUS +ib_to_ntstatus( + IN ib_api_status_t ib_status ) +{ + switch( ib_status ) + { + case IB_SUCCESS: + return STATUS_SUCCESS; + case IB_INSUFFICIENT_RESOURCES: + case IB_MAX_MCAST_QPS_REACHED: + return STATUS_INSUFFICIENT_RESOURCES; + case IB_INSUFFICIENT_MEMORY: + return STATUS_NO_MEMORY; + case IB_INVALID_PARAMETER: + case IB_INVALID_SETTING: + case IB_INVALID_PKEY: + case IB_INVALID_LKEY: + case IB_INVALID_RKEY: + case IB_INVALID_MAX_WRS: + case IB_INVALID_MAX_SGE: + case IB_INVALID_CQ_SIZE: + case IB_INVALID_SRQ_SIZE: + case IB_INVALID_SERVICE_TYPE: + case IB_INVALID_GID: + case IB_INVALID_LID: + case IB_INVALID_GUID: + case IB_INVALID_WR_TYPE: + case IB_INVALID_PORT: + case IB_INVALID_INDEX: + return STATUS_INVALID_PARAMETER; + case IB_NO_MATCH: + case IB_NOT_FOUND: + return STATUS_NOT_FOUND; + case IB_TIMEOUT: + return STATUS_TIMEOUT; + case IB_CANCELED: + return STATUS_CANCELLED; + case IB_INTERRUPTED: + case IB_NOT_DONE: + return STATUS_ABANDONED; + case IB_INVALID_PERMISSION: + return STATUS_ACCESS_DENIED; + case IB_UNSUPPORTED: + case IB_QP_IN_TIMEWAIT: + case IB_EE_IN_TIMEWAIT: + return STATUS_INVALID_DEVICE_REQUEST; + case IB_OVERFLOW: + return STATUS_BUFFER_OVERFLOW; + case IB_INVALID_QP_STATE: + case IB_INVALID_APM_STATE: + case IB_INVALID_PORT_STATE: + case IB_INVALID_STATE: + return STATUS_INVALID_DEVICE_STATE; + case IB_RESOURCE_BUSY: + return STATUS_DEVICE_BUSY; + case IB_INVALID_CA_HANDLE: + case IB_INVALID_AV_HANDLE: + case IB_INVALID_CQ_HANDLE: + case IB_INVALID_QP_HANDLE: + case IB_INVALID_SRQ_HANDLE: + case IB_INVALID_PD_HANDLE: + case IB_INVALID_MR_HANDLE: + case IB_INVALID_FMR_HANDLE: + case IB_INVALID_MW_HANDLE: + case IB_INVALID_MCAST_HANDLE: + case IB_INVALID_CALLBACK: + case IB_INVALID_AL_HANDLE: + case IB_INVALID_HANDLE: + return STATUS_INVALID_HANDLE; + case IB_VERBS_PROCESSING_DONE: + return STATUS_EVENT_DONE; + case IB_PENDING: + return STATUS_PENDING; + case IB_ERROR: + case IB_REMOTE_ERROR: + default: + return STATUS_UNSUCCESSFUL; + } +} diff --git a/branches/WOF2-3/core/al/kernel/al_proxy.h b/branches/WOF2-3/core/al/kernel/al_proxy.h new file mode 100644 index 00000000..6d6430c4 --- /dev/null +++ b/branches/WOF2-3/core/al/kernel/al_proxy.h @@ -0,0 +1,405 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: al_proxy.h 2726 2008-07-09 10:31:33Z leonid $ + */ + + + +/* + * Abstract: + * This header file defines data structures for the user-mode proxy + * and UAL support + * + * Environment: + * Kernel Mode. + */ + + +#ifndef _ALPROXY_H_ +#define _ALPROXY_H_ + + + +/* Just include everything */ +#include +#include + +#include "al_proxy_ioctl.h" +#include "al_mcast.h" + +#define AL_CB_POOL_START_SIZE 10 +#define AL_CB_POOL_GROW_SIZE 5 + + +#define PROXY_PNP_TIMEOUT_US (5000000) + + +typedef struct _proxy_pnp_evt +{ + cl_event_t event; + ib_api_status_t evt_status; + void* evt_context; + size_t rec_size; + +} proxy_pnp_evt_t; + + +typedef union _proxy_pnp_recs +{ + ib_pnp_rec_t pnp; + ib_pnp_ca_rec_t ca; + ib_pnp_port_rec_t port; + ib_pnp_iou_rec_t iou; + ib_pnp_ioc_rec_t ioc; + ib_pnp_ioc_path_rec_t ioc_path; + +} proxy_pnp_recs_t; + +typedef struct _al_dev_open_context al_dev_open_context_t; + +typedef struct _al_csq +{ + IO_CSQ csq; + KSPIN_LOCK lock; + LIST_ENTRY queue; + al_dev_open_context_t *dev_ctx; +} al_csq_t; + + +/********************************************************** + * + * Per-process device context. + * + **********************************************************/ +typedef struct _al_dev_open_context +{ + volatile boolean_t closing; + atomic32_t ref_cnt; + cl_event_t close_event; + + /* General purpose pool of list objects */ + cl_qpool_t cb_pool; + cl_spinlock_t cb_pool_lock; + + /* User-mode callback queues. */ + cl_qlist_t cm_cb_list; + cl_qlist_t comp_cb_list; + cl_qlist_t misc_cb_list; + cl_spinlock_t cb_lock; + + /* PnP synchronization mutex. */ + cl_mutex_t pnp_mutex; + + /* Pending IOCTLs. */ + al_csq_t al_csq; + + /* Per-process AL handle. */ + ib_al_handle_t h_al; + +} al_dev_open_context_t; + + + +/****f* Access Layer - Proxy/proxy_context_ref +* NAME +* proxy_context_ref +* +* DESCRIPTION +* Function to reference the open context. +* It fails if the context is closing. +* +* SYNOPSIS +*/ +inline boolean_t +proxy_context_ref( + IN al_dev_open_context_t *p_context ) +{ + cl_atomic_inc( &p_context->ref_cnt ); + + return( !p_context->closing ); +} +/*********/ + + +/****f* Access Layer - Proxy/proxy_context_deref +* NAME +* proxy_context_deref +* +* DESCRIPTION +* Releases a reference on an open context acquired via a call to +* proxy_context_ref. +* +* SYNOPSIS +*/ +inline void +proxy_context_deref( + IN al_dev_open_context_t *p_context ) +{ + cl_atomic_dec( &p_context->ref_cnt ); + cl_event_signal( &p_context->close_event ); +} +/*********/ + + + +/* + * Generic callback information. Used to report callbacks from kernel to + * user-mode. + */ +typedef struct _al_proxy_cb_info +{ + cl_pool_item_t pool_item; /* must be first */ + al_dev_open_context_t *p_context; + + union _cb_type + { + comp_cb_ioctl_info_t comp; + misc_cb_ioctl_info_t misc; + + } cb_type; + + /* + * AL object to dereference after processing callback. We use this to + * ensure that a kernel object is not destroyed while a callback is in + * progress to user-mode. Since user-mode objects are not destroyed until + * the associated kernel objects are, this ensures that all callbacks + * from the kernel reference valid user-mode objects. + */ + al_obj_t *p_al_obj; + boolean_t reported; + +} al_proxy_cb_info_t; + +#pragma warning(disable:4706) +static inline void al_csq_flush_que( + IN al_csq_t* p_al_csq, + IN NTSTATUS completion_code + ) +{ + PIRP Irp; + while( Irp = IoCsqRemoveNextIrp( &p_al_csq->csq, NULL ) ) + { + cl_ioctl_complete( Irp, completion_code, 0 ); + proxy_context_deref( p_al_csq->dev_ctx ); + } +} +#pragma warning(default:4706) + +static VOID __insert_irp( + IN PIO_CSQ Csq, + IN PIRP Irp + ) +{ + al_csq_t *p_al_csq = (al_csq_t*)Csq; + InsertTailList( &p_al_csq->queue, &Irp->Tail.Overlay.ListEntry ); +} + +static VOID __remove_irp( + IN PIO_CSQ Csq, + IN PIRP Irp + ) +{ + UNUSED_PARAM( Csq ); + RemoveEntryList( &Irp->Tail.Overlay.ListEntry ); +} + +static PIRP __peek_next_irp( + IN PIO_CSQ Csq, + IN PIRP Irp, + IN PVOID PeekContext + ) +{ + PIRP nextIrp = NULL; + PLIST_ENTRY nextEntry; + PLIST_ENTRY listHead; + al_csq_t *p_al_csq = (al_csq_t*)Csq; + + listHead = &p_al_csq->queue; + + // + // If the IRP is NULL, we will start peeking from the listhead, else + // we will start from that IRP onwards. This is done under the + // assumption that new IRPs are always inserted at the tail. + // + + if(Irp == NULL) + nextEntry = listHead->Flink; + else + nextEntry = Irp->Tail.Overlay.ListEntry.Flink; + + while(nextEntry != listHead) + { + nextIrp = CONTAINING_RECORD(nextEntry, IRP, Tail.Overlay.ListEntry); + + // + // If context is present, continue until you find a matching one. + // Else you break out as you got next one. + // + + if(PeekContext) + { + if( cl_ioctl_ctl_code( nextIrp ) == (ULONG_PTR)PeekContext ) + break; + } + else + { + break; + } + + nextIrp = NULL; + nextEntry = nextEntry->Flink; + } + + return nextIrp; +} + +static VOID __acquire_lock( + IN PIO_CSQ Csq, + OUT PKIRQL Irql + ) +{ + al_csq_t *p_al_csq = (al_csq_t*)Csq; + KeAcquireSpinLock( &p_al_csq->lock, Irql ); +} + +static VOID __release_lock( + IN PIO_CSQ Csq, + IN KIRQL Irql + ) +{ + al_csq_t *p_al_csq = (al_csq_t*)Csq; + KeReleaseSpinLock( &p_al_csq->lock, Irql ); +} + +static VOID __complete_cancelled_irp( + IN PIO_CSQ Csq, + IN PIRP Irp + ) +{ + al_csq_t *p_al_csq = (al_csq_t*)Csq; + + cl_ioctl_complete( Irp, CL_CANCELED, 0 ); + proxy_context_deref( p_al_csq->dev_ctx ); +} + +static inline NTSTATUS +al_csq_init( + IN al_dev_open_context_t * dev_ctx, + IN al_csq_t * p_al_csq) +{ + NTSTATUS status; + + status = IoCsqInitialize( &p_al_csq->csq, + __insert_irp, __remove_irp, + __peek_next_irp, __acquire_lock, + __release_lock, __complete_cancelled_irp ); + if ( !NT_SUCCESS( status ) ) + goto exit; + + InitializeListHead( &p_al_csq->queue ); + KeInitializeSpinLock( &p_al_csq->lock ); + p_al_csq->dev_ctx = dev_ctx; + status = STATUS_SUCCESS; + +exit: + return status; +} + + +al_proxy_cb_info_t* +proxy_cb_get( + IN al_dev_open_context_t *p_context ); + + +void +proxy_cb_put( + IN al_proxy_cb_info_t *p_cbinfo ); + + + +void +proxy_cb_put_list( + IN al_dev_open_context_t *p_context, + IN cl_qlist_t *p_cb_list ); + + +cl_status_t proxy_ioctl( + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ); + +cl_status_t al_ioctl( + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ); + +cl_status_t verbs_ioctl( + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ); + +cl_status_t subnet_ioctl( + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ); + +cl_status_t cm_ioctl( + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ); + +cl_status_t cep_ioctl( + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ); + +cl_status_t ioc_ioctl( + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ); + +cl_status_t ndi_ioctl( + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ); + +boolean_t +proxy_queue_cb_buf( + IN uintn_t cb_type, + IN al_dev_open_context_t *p_context, + IN void *p_cb_data, + IN al_obj_t *p_al_obj OPTIONAL ); + + +ib_api_status_t +proxy_pnp_ca_cb( + IN ib_pnp_rec_t *p_pnp_rec ); + +ib_api_status_t +proxy_pnp_port_cb( + IN ib_pnp_rec_t *p_pnp_rec ); + +NTSTATUS +ib_to_ntstatus( + IN ib_api_status_t ib_status ); +#endif /* _AL_PROXY_H_ */ diff --git a/branches/WOF2-3/core/al/kernel/al_proxy_cep.c b/branches/WOF2-3/core/al/kernel/al_proxy_cep.c new file mode 100644 index 00000000..dc5ec8e0 --- /dev/null +++ b/branches/WOF2-3/core/al/kernel/al_proxy_cep.c @@ -0,0 +1,1005 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include "al_debug.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "al_proxy_cep.tmh" +#endif +#include "al_cm_cep.h" +#include "al_dev.h" +#include +#include "al_proxy.h" +#include "al.h" +#include "al_qp.h" + + +static cl_status_t +proxy_create_cep( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + al_dev_open_context_t *p_context; + ual_create_cep_ioctl_t *p_ioctl; + + AL_ENTER( AL_DBG_CM ); + + p_context = (al_dev_open_context_t*)p_open_context; + p_ioctl = (ual_create_cep_ioctl_t*)cl_ioctl_out_buf( h_ioctl ); + + /* Validate user parameters. */ + if( cl_ioctl_out_size( h_ioctl ) != sizeof(ual_create_cep_ioctl_t) ) + { + AL_EXIT( AL_DBG_CM ); + return CL_INVALID_PARAMETER; + } + /* We use IRPs as notification mechanism so the callback is NULL. */ + p_ioctl->status = kal_cep_alloc( p_context->h_al, &p_ioctl->cid ); + + *p_ret_bytes = sizeof(ual_create_cep_ioctl_t); + + AL_EXIT( AL_DBG_CM ); + return CL_SUCCESS; +} + + +static inline void +__complete_get_event_ioctl( + IN ib_al_handle_t h_al, + IN IRP* const p_irp, + IN NTSTATUS status ) +{ +#pragma warning(push, 3) + IoSetCancelRoutine( p_irp, NULL ); +#pragma warning(pop) + + /* Complete the IRP. */ + p_irp->IoStatus.Status = status; + p_irp->IoStatus.Information = 0; + IoCompleteRequest( p_irp, IO_NETWORK_INCREMENT ); + + deref_al_obj( &h_al->obj ); +} + + +static cl_status_t +proxy_destroy_cep( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + al_dev_open_context_t *p_context; + + AL_ENTER( AL_DBG_CM ); + + UNUSED_PARAM( p_ret_bytes ); + + p_context = (al_dev_open_context_t*)p_open_context; + + /* Validate user parameters. */ + if( cl_ioctl_in_size( h_ioctl ) != sizeof(net32_t) ) + { + AL_EXIT( AL_DBG_CM ); + return CL_INVALID_PARAMETER; + } + + al_destroy_cep( p_context->h_al, + (net32_t*)cl_ioctl_in_buf( h_ioctl ), TRUE ); + + AL_EXIT( AL_DBG_CM ); + return CL_SUCCESS; +} + + +static cl_status_t +proxy_cep_listen( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + al_dev_open_context_t *p_context; + ual_cep_listen_ioctl_t *p_ioctl; + ib_api_status_t status; + + AL_ENTER( AL_DBG_CM ); + + p_context = (al_dev_open_context_t*)p_open_context; + p_ioctl = (ual_cep_listen_ioctl_t*)cl_ioctl_in_buf( h_ioctl ); + + /* Validate user parameters. */ + if( cl_ioctl_in_size( h_ioctl ) != sizeof(ual_cep_listen_ioctl_t) || + cl_ioctl_out_size( h_ioctl ) != sizeof(ib_api_status_t) ) + { + AL_EXIT( AL_DBG_CM ); + return CL_INVALID_PARAMETER; + } + + /* Set the private data compare buffer to our kernel copy. */ + if( p_ioctl->cep_listen.p_cmp_buf ) + p_ioctl->cep_listen.p_cmp_buf = p_ioctl->compare; + + status = + al_cep_listen( p_context->h_al, p_ioctl->cid, &p_ioctl->cep_listen ); + + (*(ib_api_status_t*)cl_ioctl_out_buf( h_ioctl )) = status; + + *p_ret_bytes = sizeof(ib_api_status_t); + + AL_EXIT( AL_DBG_CM ); + return CL_SUCCESS; +} + + +static cl_status_t +proxy_cep_pre_req( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + al_dev_open_context_t *p_context; + ual_cep_req_ioctl_t *p_ioctl; + ib_qp_handle_t h_qp; + + AL_ENTER( AL_DBG_CM ); + + p_context = (al_dev_open_context_t*)p_open_context; + p_ioctl = (ual_cep_req_ioctl_t*)cl_ioctl_in_buf( h_ioctl ); + + /* Validate user parameters. */ + if( cl_ioctl_in_size( h_ioctl ) != sizeof(struct _ual_cep_req_ioctl_in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(struct _ual_cep_req_ioctl_out) ) + { + AL_EXIT( AL_DBG_CM ); + return CL_INVALID_PARAMETER; + } + + *p_ret_bytes = sizeof(struct _ual_cep_req_ioctl_out); + + p_ioctl->in.cm_req.h_al = p_context->h_al; + p_ioctl->in.cm_req.p_primary_path = &p_ioctl->in.paths[0]; + if( p_ioctl->in.cm_req.p_alt_path ) + p_ioctl->in.cm_req.p_alt_path = &p_ioctl->in.paths[1]; + if( p_ioctl->in.cm_req.p_compare_buffer ) + p_ioctl->in.cm_req.p_compare_buffer = p_ioctl->in.compare; + if( p_ioctl->in.cm_req.p_req_pdata ) + p_ioctl->in.cm_req.p_req_pdata = p_ioctl->in.pdata; + + /* Get the kernel QP handle. */ + h_qp = (ib_qp_handle_t)al_hdl_ref( + p_context->h_al, p_ioctl->in.cm_req.h_qp_padding, AL_OBJ_TYPE_H_QP ); + if( !h_qp ) + { + p_ioctl->out.status = IB_INVALID_QP_HANDLE; + goto done; + } + + p_ioctl->in.cm_req.h_qp = h_qp; + + if(h_qp->type == IB_QPT_RELIABLE_CONN || + h_qp->type == IB_QPT_UNRELIABLE_CONN) + { + ((al_conn_qp_t *)(h_qp))->cid = p_ioctl->in.cid; + } + + p_ioctl->out.status = al_cep_pre_req( p_context->h_al, p_ioctl->in.cid, + &p_ioctl->in.cm_req, &p_ioctl->out.init ); + + deref_al_obj( &h_qp->obj ); + + if( p_ioctl->out.status != IB_SUCCESS ) + { +done: + cl_memclr( &p_ioctl->out.init, sizeof(ib_qp_mod_t) ); + } + + AL_EXIT( AL_DBG_CM ); + return CL_SUCCESS; +} + + +static cl_status_t +proxy_cep_send_req( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + al_dev_open_context_t *p_context; + + AL_ENTER( AL_DBG_CM ); + + p_context = (al_dev_open_context_t*)p_open_context; + + /* Validate user parameters. */ + if( cl_ioctl_in_size( h_ioctl ) != sizeof(net32_t) || + cl_ioctl_out_size( h_ioctl ) != sizeof(ib_api_status_t) ) + { + AL_EXIT( AL_DBG_CM ); + return CL_INVALID_PARAMETER; + } + + (*(ib_api_status_t*)cl_ioctl_out_buf( h_ioctl )) = al_cep_send_req( + p_context->h_al, *(net32_t*)cl_ioctl_in_buf( h_ioctl ) ); + + *p_ret_bytes = sizeof(ib_api_status_t); + + AL_EXIT( AL_DBG_CM ); + return CL_SUCCESS; +} + + +static cl_status_t +proxy_cep_pre_rep( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + al_dev_open_context_t *p_context; + ual_cep_rep_ioctl_t *p_ioctl; + ib_qp_handle_t h_qp; + net32_t cid; + + AL_ENTER( AL_DBG_CM ); + + p_context = (al_dev_open_context_t*)p_open_context; + p_ioctl = (ual_cep_rep_ioctl_t*)cl_ioctl_in_buf( h_ioctl ); + + /* Validate user parameters. */ + if( cl_ioctl_in_size( h_ioctl ) != sizeof(struct _ual_cep_rep_ioctl_in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(struct _ual_cep_rep_ioctl_out) ) + { + AL_EXIT( AL_DBG_CM ); + return CL_INVALID_PARAMETER; + } + + *p_ret_bytes = sizeof(struct _ual_cep_rep_ioctl_out); + + if( p_ioctl->in.cm_rep.p_rep_pdata ) + p_ioctl->in.cm_rep.p_rep_pdata = p_ioctl->in.pdata; + + /* Get the kernel QP handle. */ + h_qp = (ib_qp_handle_t)al_hdl_ref( + p_context->h_al, p_ioctl->in.cm_rep.h_qp_padding, AL_OBJ_TYPE_H_QP ); + if( !h_qp ) + { + p_ioctl->out.status = IB_INVALID_QP_HANDLE; + goto done; + } + + p_ioctl->in.cm_rep.h_qp = h_qp; + + cid = AL_INVALID_CID; + p_ioctl->out.status = al_cep_pre_rep( p_context->h_al, p_ioctl->in.cid, + (void*)(ULONG_PTR)p_ioctl->in.context, NULL, &p_ioctl->in.cm_rep, + &cid, &p_ioctl->out.init ); + + deref_al_obj( &h_qp->obj ); + + if( p_ioctl->out.status != IB_SUCCESS ) + { +done: + cl_memclr( &p_ioctl->out.init, sizeof(ib_qp_mod_t) ); + } + + AL_EXIT( AL_DBG_CM ); + return CL_SUCCESS; +} + + +static cl_status_t +proxy_cep_send_rep( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + al_dev_open_context_t *p_context; + + AL_ENTER( AL_DBG_CM ); + + p_context = (al_dev_open_context_t*)p_open_context; + + /* Validate user parameters. */ + if( cl_ioctl_in_size( h_ioctl ) != sizeof(net32_t) || + cl_ioctl_out_size( h_ioctl ) != sizeof(ib_api_status_t) ) + { + AL_EXIT( AL_DBG_CM ); + return CL_INVALID_PARAMETER; + } + + (*(ib_api_status_t*)cl_ioctl_out_buf( h_ioctl )) = al_cep_send_rep( + p_context->h_al, *(net32_t*)cl_ioctl_in_buf( h_ioctl ) ); + + *p_ret_bytes = sizeof(ib_api_status_t); + + AL_EXIT( AL_DBG_CM ); + return CL_SUCCESS; +} + + +static cl_status_t +proxy_cep_get_rtr( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + al_dev_open_context_t *p_context; + ual_cep_get_rtr_ioctl_t *p_ioctl; + + AL_ENTER( AL_DBG_CM ); + + p_context = (al_dev_open_context_t*)p_open_context; + p_ioctl = (ual_cep_get_rtr_ioctl_t*)cl_ioctl_out_buf( h_ioctl ); + + /* Validate user parameters. */ + if( cl_ioctl_in_size( h_ioctl ) != sizeof(net32_t) || + cl_ioctl_out_size( h_ioctl ) != sizeof(ual_cep_get_rtr_ioctl_t) ) + { + AL_EXIT( AL_DBG_CM ); + return CL_INVALID_PARAMETER; + } + + *p_ret_bytes = sizeof(ual_cep_get_rtr_ioctl_t); + + p_ioctl->status = al_cep_get_rtr_attr( p_context->h_al, + *(net32_t*)cl_ioctl_in_buf( h_ioctl ), &p_ioctl->rtr ); + + if( p_ioctl->status != IB_SUCCESS ) + cl_memclr( &p_ioctl->rtr, sizeof(ib_qp_mod_t) ); + + AL_EXIT( AL_DBG_CM ); + return CL_SUCCESS; +} + + +static cl_status_t +proxy_cep_get_rts( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + al_dev_open_context_t *p_context; + ual_cep_get_rts_ioctl_t *p_ioctl; + + AL_ENTER( AL_DBG_CM ); + + p_context = (al_dev_open_context_t*)p_open_context; + p_ioctl = (ual_cep_get_rts_ioctl_t*)cl_ioctl_out_buf( h_ioctl ); + + /* Validate user parameters. */ + if( cl_ioctl_in_size( h_ioctl ) != sizeof(net32_t) || + cl_ioctl_out_size( h_ioctl ) != sizeof(ual_cep_get_rts_ioctl_t) ) + { + AL_EXIT( AL_DBG_CM ); + return CL_INVALID_PARAMETER; + } + + *p_ret_bytes = sizeof(ual_cep_get_rts_ioctl_t); + + p_ioctl->status = al_cep_get_rts_attr( p_context->h_al, + *(net32_t*)cl_ioctl_in_buf( h_ioctl ), &p_ioctl->rts ); + + if( p_ioctl->status != IB_SUCCESS ) + cl_memclr( &p_ioctl->rts, sizeof(ib_qp_mod_t) ); + + AL_EXIT( AL_DBG_CM ); + return CL_SUCCESS; +} + + +static cl_status_t +proxy_cep_rtu( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + al_dev_open_context_t *p_context; + ual_cep_rtu_ioctl_t *p_ioctl; + ib_api_status_t status; + + AL_ENTER( AL_DBG_CM ); + + p_context = (al_dev_open_context_t*)p_open_context; + p_ioctl = (ual_cep_rtu_ioctl_t*)cl_ioctl_in_buf( h_ioctl ); + + /* Validate user parameters. */ + if( cl_ioctl_in_size( h_ioctl ) != sizeof(ual_cep_rtu_ioctl_t) || + cl_ioctl_out_size( h_ioctl ) != sizeof(ib_api_status_t) ) + { + AL_EXIT( AL_DBG_CM ); + return CL_INVALID_PARAMETER; + } + + status = al_cep_rtu( p_context->h_al, + p_ioctl->cid, p_ioctl->pdata, p_ioctl->pdata_len ); + + (*(ib_api_status_t*)cl_ioctl_out_buf( h_ioctl )) = status; + + *p_ret_bytes = sizeof(ib_api_status_t); + + AL_EXIT( AL_DBG_CM ); + return CL_SUCCESS; +} + + +static cl_status_t +proxy_cep_rej( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + al_dev_open_context_t *p_context; + ual_cep_rej_ioctl_t *p_ioctl; + + AL_ENTER( AL_DBG_CM ); + + p_context = (al_dev_open_context_t*)p_open_context; + p_ioctl = (ual_cep_rej_ioctl_t*)cl_ioctl_in_buf( h_ioctl ); + + /* Validate user parameters. */ + if( cl_ioctl_in_size( h_ioctl ) != sizeof(ual_cep_rej_ioctl_t) || + cl_ioctl_out_size( h_ioctl ) != sizeof(ib_api_status_t) ) + { + AL_EXIT( AL_DBG_CM ); + return CL_INVALID_PARAMETER; + } + + (*(ib_api_status_t*)cl_ioctl_out_buf( h_ioctl )) = al_cep_rej( + p_context->h_al, p_ioctl->cid, p_ioctl->rej_status, p_ioctl->ari, + p_ioctl->ari_len, p_ioctl->pdata, p_ioctl->pdata_len ); + + *p_ret_bytes = sizeof(ib_api_status_t); + + AL_EXIT( AL_DBG_CM ); + return CL_SUCCESS; +} + + +static cl_status_t +proxy_cep_mra( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + al_dev_open_context_t *p_context; + ual_cep_mra_ioctl_t *p_ioctl; + + AL_ENTER( AL_DBG_CM ); + + p_context = (al_dev_open_context_t*)p_open_context; + p_ioctl = (ual_cep_mra_ioctl_t*)cl_ioctl_in_buf( h_ioctl ); + + /* Validate user parameters. */ + if( cl_ioctl_in_size( h_ioctl ) != sizeof(ual_cep_mra_ioctl_t) || + cl_ioctl_out_size( h_ioctl ) != sizeof(ib_api_status_t) ) + { + AL_EXIT( AL_DBG_CM ); + return CL_INVALID_PARAMETER; + } + + p_ioctl->cm_mra.p_mra_pdata = p_ioctl->pdata; + + (*(ib_api_status_t*)cl_ioctl_out_buf( h_ioctl )) = al_cep_mra( + p_context->h_al, p_ioctl->cid, &p_ioctl->cm_mra ); + + *p_ret_bytes = sizeof(ib_api_status_t); + + AL_EXIT( AL_DBG_CM ); + return CL_SUCCESS; +} + + +static cl_status_t +proxy_cep_lap( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + al_dev_open_context_t *p_context; + ual_cep_lap_ioctl_t *p_ioctl; + ib_api_status_t status; + ib_qp_handle_t h_qp; + + AL_ENTER( AL_DBG_CM ); + + p_context = (al_dev_open_context_t*)p_open_context; + p_ioctl = (ual_cep_lap_ioctl_t*)cl_ioctl_in_buf( h_ioctl ); + + /* Validate user parameters. */ + if( cl_ioctl_in_size( h_ioctl ) != sizeof(ual_cep_lap_ioctl_t) || + cl_ioctl_out_size( h_ioctl ) != sizeof(ib_api_status_t) ) + { + AL_EXIT( AL_DBG_CM ); + return CL_INVALID_PARAMETER; + } + + *p_ret_bytes = sizeof(ib_api_status_t); + + p_ioctl->cm_lap.p_alt_path = &p_ioctl->alt_path; + if( p_ioctl->cm_lap.p_lap_pdata ) + p_ioctl->pdata; + + /* Get the kernel QP handle. */ + h_qp = (ib_qp_handle_t)al_hdl_ref( + p_context->h_al, p_ioctl->cm_lap.h_qp_padding, AL_OBJ_TYPE_H_QP ); + if( !h_qp ) + { + status = IB_INVALID_QP_HANDLE; + goto done; + } + + p_ioctl->cm_lap.h_qp = h_qp; + + status = al_cep_lap( p_context->h_al, p_ioctl->cid, &p_ioctl->cm_lap ); + + deref_al_obj( &h_qp->obj ); + +done: + (*(ib_api_status_t*)cl_ioctl_out_buf( h_ioctl )) = status; + + AL_EXIT( AL_DBG_CM ); + return CL_SUCCESS; +} + + +static cl_status_t +proxy_cep_pre_apr( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + al_dev_open_context_t *p_context; + ual_cep_apr_ioctl_t *p_ioctl; + ib_qp_handle_t h_qp; + + AL_ENTER( AL_DBG_CM ); + + p_context = (al_dev_open_context_t*)p_open_context; + p_ioctl = (ual_cep_apr_ioctl_t*)cl_ioctl_in_buf( h_ioctl ); + + /* Validate user parameters. */ + if( cl_ioctl_in_size( h_ioctl ) != sizeof(struct _ual_cep_apr_ioctl_in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(struct _ual_cep_apr_ioctl_out) ) + { + AL_EXIT( AL_DBG_CM ); + return CL_INVALID_PARAMETER; + } + + *p_ret_bytes = sizeof(struct _ual_cep_apr_ioctl_out); + + if( p_ioctl->in.cm_apr.p_info ) + p_ioctl->in.cm_apr.p_info = (ib_apr_info_t*)p_ioctl->in.apr_info; + if( p_ioctl->in.cm_apr.p_apr_pdata ) + p_ioctl->in.cm_apr.p_apr_pdata = p_ioctl->in.pdata; + + /* Get the kernel QP handle. */ + h_qp = (ib_qp_handle_t)al_hdl_ref( + p_context->h_al, p_ioctl->in.cm_apr.h_qp_padding, AL_OBJ_TYPE_H_QP ); + if( !h_qp ) + { + p_ioctl->out.status = IB_INVALID_QP_HANDLE; + goto done; + } + + p_ioctl->in.cm_apr.h_qp = h_qp; + + p_ioctl->out.status = al_cep_pre_apr( p_context->h_al, p_ioctl->in.cid, + &p_ioctl->in.cm_apr, &p_ioctl->out.apr ); + + deref_al_obj( &h_qp->obj ); + + if( p_ioctl->out.status != IB_SUCCESS ) + { +done: + cl_memclr( &p_ioctl->out.apr, sizeof(ib_qp_mod_t) ); + } + + AL_EXIT( AL_DBG_CM ); + return CL_SUCCESS; +} + + +static cl_status_t +proxy_cep_send_apr( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + al_dev_open_context_t *p_context; + + AL_ENTER( AL_DBG_CM ); + + p_context = (al_dev_open_context_t*)p_open_context; + + /* Validate user parameters. */ + if( cl_ioctl_in_size( h_ioctl ) != sizeof(net32_t) || + cl_ioctl_out_size( h_ioctl ) != sizeof(ib_api_status_t) ) + { + AL_EXIT( AL_DBG_CM ); + return CL_INVALID_PARAMETER; + } + + (*(ib_api_status_t*)cl_ioctl_out_buf( h_ioctl )) = al_cep_send_apr( + p_context->h_al, *(net32_t*)cl_ioctl_in_buf( h_ioctl ) ); + + *p_ret_bytes = sizeof(ib_api_status_t); + + AL_EXIT( AL_DBG_CM ); + return CL_SUCCESS; +} + + +static cl_status_t +proxy_cep_dreq( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + al_dev_open_context_t *p_context; + ual_cep_dreq_ioctl_t *p_ioctl; + ib_api_status_t status; + + AL_ENTER( AL_DBG_CM ); + + p_context = (al_dev_open_context_t*)p_open_context; + p_ioctl = (ual_cep_dreq_ioctl_t*)cl_ioctl_in_buf( h_ioctl ); + + /* Validate user parameters. */ + if( cl_ioctl_in_size( h_ioctl ) != sizeof(ual_cep_dreq_ioctl_t) || + cl_ioctl_out_size( h_ioctl ) != sizeof(ib_api_status_t) ) + { + AL_EXIT( AL_DBG_CM ); + return CL_INVALID_PARAMETER; + } + + /* Set the private data compare buffer to our kernel copy. */ + status = al_cep_dreq( p_context->h_al, + p_ioctl->cid, p_ioctl->pdata, p_ioctl->pdata_len ); + + (*(ib_api_status_t*)cl_ioctl_out_buf( h_ioctl )) = status; + + *p_ret_bytes = sizeof(ib_api_status_t); + + AL_EXIT( AL_DBG_CM ); + return CL_SUCCESS; +} + + +static cl_status_t +proxy_cep_drep( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + al_dev_open_context_t *p_context; + ual_cep_drep_ioctl_t *p_ioctl; + + AL_ENTER( AL_DBG_CM ); + + p_context = (al_dev_open_context_t*)p_open_context; + p_ioctl = (ual_cep_drep_ioctl_t*)cl_ioctl_in_buf( h_ioctl ); + + /* Validate user parameters. */ + if( cl_ioctl_in_size( h_ioctl ) != sizeof(ual_cep_drep_ioctl_t) || + cl_ioctl_out_size( h_ioctl ) != sizeof(ib_api_status_t) ) + { + AL_EXIT( AL_DBG_CM ); + return CL_INVALID_PARAMETER; + } + + (*(ib_api_status_t*)cl_ioctl_out_buf( h_ioctl )) = al_cep_drep( + p_context->h_al, p_ioctl->cid, p_ioctl->pdata, p_ioctl->pdata_len ); + + *p_ret_bytes = sizeof(ib_api_status_t); + + AL_EXIT( AL_DBG_CM ); + return CL_SUCCESS; +} + + +static cl_status_t +proxy_cep_get_timewait( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + al_dev_open_context_t *p_context; + ual_cep_get_timewait_ioctl_t *p_ioctl; + + AL_ENTER( AL_DBG_CM ); + + p_context = (al_dev_open_context_t*)p_open_context; + p_ioctl = (ual_cep_get_timewait_ioctl_t*)cl_ioctl_out_buf( h_ioctl ); + + /* Validate user parameters. */ + if( cl_ioctl_in_size( h_ioctl ) != sizeof(net32_t) || + cl_ioctl_out_size( h_ioctl ) != sizeof(ual_cep_get_timewait_ioctl_t) ) + { + AL_EXIT( AL_DBG_CM ); + return CL_INVALID_PARAMETER; + } + + p_ioctl->status = al_cep_get_timewait( p_context->h_al, + *(net32_t*)cl_ioctl_in_buf( h_ioctl ), &p_ioctl->timewait_us ); + + *p_ret_bytes = sizeof(ual_cep_get_timewait_ioctl_t); + + AL_EXIT( AL_DBG_CM ); + return CL_SUCCESS; +} + + +static cl_status_t +proxy_cep_poll( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + al_dev_open_context_t *p_context; + ual_cep_poll_ioctl_t *p_ioctl; + ib_mad_element_t *p_mad = NULL; + void* dummy; + + AL_ENTER( AL_DBG_CM ); + + p_context = (al_dev_open_context_t*)p_open_context; + p_ioctl = (ual_cep_poll_ioctl_t*)cl_ioctl_out_buf( h_ioctl ); + + /* Validate user parameters. */ + if( cl_ioctl_in_size( h_ioctl ) != sizeof(net32_t) || + cl_ioctl_out_size( h_ioctl ) != sizeof(ual_cep_poll_ioctl_t) ) + { + AL_EXIT( AL_DBG_CM ); + return CL_INVALID_PARAMETER; + } + + *p_ret_bytes = sizeof(ual_cep_poll_ioctl_t); + + p_ioctl->status = al_cep_poll( p_context->h_al, + *(net32_t*)cl_ioctl_in_buf( h_ioctl ), + &dummy, + &p_ioctl->new_cid, &p_mad ); + + if( p_ioctl->status == IB_SUCCESS ) + { + /* Copy the MAD for user consumption and free the it. */ + CL_ASSERT( p_mad ); + p_ioctl->element = *p_mad; + if( p_mad->grh_valid ) + p_ioctl->grh = *p_mad->p_grh; + else + cl_memclr( &p_ioctl->grh, sizeof(ib_grh_t) ); + cl_memcpy( p_ioctl->mad_buf, p_mad->p_mad_buf, MAD_BLOCK_SIZE ); + ib_put_mad( p_mad ); + } + else + { + cl_memclr( &p_ioctl->mad_buf, sizeof(MAD_BLOCK_SIZE) ); + p_ioctl->new_cid = AL_INVALID_CID; + } + + AL_EXIT( AL_DBG_CM ); + return CL_SUCCESS; +} + + +static cl_status_t +proxy_cep_get_event( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + NTSTATUS status; + IO_STACK_LOCATION *p_io_stack; + al_dev_open_context_t *p_context; + net32_t cid; + + AL_ENTER( AL_DBG_CM ); + + UNUSED_PARAM( p_ret_bytes ); + + p_context = p_open_context; + + p_io_stack = IoGetCurrentIrpStackLocation( h_ioctl ); + if( (uintn_t)p_io_stack->FileObject->FsContext2 != AL_OBJ_TYPE_CM ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("Invalid file object type for request: %p\n", + p_io_stack->FileObject->FsContext2) ); + return CL_INVALID_PARAMETER; + } + + /* Check the size of the ioctl */ + if( cl_ioctl_in_size( h_ioctl ) != sizeof(net32_t) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("Invalid IOCTL input buffer.\n") ); + return CL_INVALID_PARAMETER; + } + + cid = *(net32_t*)cl_ioctl_in_buf( h_ioctl ); + + status = al_cep_queue_irp( p_context->h_al, cid, h_ioctl ); + if( status != STATUS_PENDING ) + { + /* Invalid CID. Complete the request. */ + AL_EXIT( AL_DBG_CM ); + return CL_INVALID_PARAMETER; + } + + AL_EXIT( AL_DBG_CM ); + return CL_PENDING; +} + + + +static cl_status_t +proxy_cep_get_pdata( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + al_dev_open_context_t *p_context; + ual_cep_get_pdata_ioctl_t *p_ioctl; + NTSTATUS status; + net32_t cid; + + AL_ENTER( AL_DBG_CM ); + + p_context = (al_dev_open_context_t*)p_open_context; + p_ioctl = (ual_cep_get_pdata_ioctl_t*)cl_ioctl_in_buf( h_ioctl ); + + /* Validate user parameters. */ + if( cl_ioctl_in_size( h_ioctl ) != sizeof(struct _ual_cep_get_pdata_ioctl_in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(struct _ual_cep_get_pdata_ioctl_out) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("Incorrect sizes: in %d, out %d (expected - %d, %d)\n", + cl_ioctl_in_size( h_ioctl ), cl_ioctl_out_size( h_ioctl ), + sizeof(struct _ual_cep_get_pdata_ioctl_in), + sizeof(struct _ual_cep_get_pdata_ioctl_out) ) ); + return CL_INVALID_PARAMETER; + } + + cid = p_ioctl->in.cid; + p_ioctl->out.pdata_len = sizeof(p_ioctl->out.pdata); + status = al_cep_get_pdata( p_context->h_al, cid, + &p_ioctl->out.init_depth, &p_ioctl->out.resp_res, + (uint8_t*)&p_ioctl->out.pdata_len, p_ioctl->out.pdata ); + + if( NT_SUCCESS( status ) ) + { + *p_ret_bytes = sizeof(struct _ual_cep_get_pdata_ioctl_out); + AL_PRINT(TRACE_LEVEL_INFORMATION ,AL_DBG_CM , + ("proxy_cep_get_pdata: get %d of pdata \n", (int)*p_ret_bytes )); + } + + AL_EXIT( AL_DBG_CM ); + return status; +} + + +cl_status_t cep_ioctl( + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + cl_status_t cl_status; + IO_STACK_LOCATION *p_io_stack; + void *p_context; + + AL_ENTER( AL_DBG_DEV ); + + CL_ASSERT( h_ioctl && p_ret_bytes ); + + p_io_stack = IoGetCurrentIrpStackLocation( h_ioctl ); + p_context = p_io_stack->FileObject->FsContext; + + if( !p_context ) + { + AL_EXIT( AL_DBG_DEV ); + return CL_INVALID_PARAMETER; + } + + switch( cl_ioctl_ctl_code( h_ioctl ) ) + { + case UAL_CREATE_CEP: + cl_status = proxy_create_cep( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_DESTROY_CEP: + cl_status = proxy_destroy_cep( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_CEP_LISTEN: + cl_status = proxy_cep_listen( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_CEP_PRE_REQ: + cl_status = proxy_cep_pre_req( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_CEP_SEND_REQ: + cl_status = proxy_cep_send_req( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_CEP_PRE_REP: + cl_status = proxy_cep_pre_rep( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_CEP_SEND_REP: + cl_status = proxy_cep_send_rep( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_CEP_GET_RTR: + cl_status = proxy_cep_get_rtr( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_CEP_GET_RTS: + cl_status = proxy_cep_get_rts( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_CEP_RTU: + cl_status = proxy_cep_rtu( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_CEP_REJ: + cl_status = proxy_cep_rej( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_CEP_MRA: + cl_status = proxy_cep_mra( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_CEP_LAP: + cl_status = proxy_cep_lap( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_CEP_PRE_APR: + cl_status = proxy_cep_pre_apr( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_CEP_SEND_APR: + cl_status = proxy_cep_send_apr( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_CEP_DREQ: + cl_status = proxy_cep_dreq( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_CEP_DREP: + cl_status = proxy_cep_drep( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_CEP_GET_TIMEWAIT: + cl_status = proxy_cep_get_timewait( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_CEP_GET_EVENT: + cl_status = proxy_cep_get_event( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_CEP_POLL: + cl_status = proxy_cep_poll( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_CEP_GET_PDATA: + cl_status = proxy_cep_get_pdata( p_context, h_ioctl, p_ret_bytes ); + break; + default: + cl_status = CL_INVALID_PARAMETER; + break; + } + + AL_EXIT( AL_DBG_DEV ); + return cl_status; +} diff --git a/branches/WOF2-3/core/al/kernel/al_proxy_ioc.c b/branches/WOF2-3/core/al/kernel/al_proxy_ioc.c new file mode 100644 index 00000000..aa4a9a68 --- /dev/null +++ b/branches/WOF2-3/core/al/kernel/al_proxy_ioc.c @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include +#include +#include +#include "al_debug.h" +#include "al.h" +#include "al_dev.h" +#include "al_proxy.h" +#include "ib_common.h" + +cl_status_t +ioc_ioctl( + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + cl_status_t cl_status; + + UNUSED_PARAM( p_ret_bytes ); + + switch( cl_ioctl_ctl_code( h_ioctl ) ) + { + case UAL_REQ_CREATE_PDO: + { + cl_status = bus_add_pkey(h_ioctl); + break; + } + + case UAL_REQ_REMOVE_PDO: + { + cl_status = bus_rem_pkey(h_ioctl); + break; + } + default: + cl_status = CL_INVALID_PARAMETER; + break; + } + return cl_status; +} diff --git a/branches/WOF2-3/core/al/kernel/al_proxy_ndi.c b/branches/WOF2-3/core/al/kernel/al_proxy_ndi.c new file mode 100644 index 00000000..9d16ceb2 --- /dev/null +++ b/branches/WOF2-3/core/al/kernel/al_proxy_ndi.c @@ -0,0 +1,814 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: al_proxy_verbs.c 548 2006-11-27 20:03:51Z leonidk $ + */ + + +#include +#include +#include +#include "al.h" +#include "al_qp.h" +#include "al_debug.h" +#include "al_cm_cep.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "al_proxy_ndi.tmh" +#endif + +#include "al_dev.h" +/* Get the internal definitions of apis for the proxy */ +#include "al_ca.h" +#include "ib_common.h" +#include "al_proxy_ndi.h" +#include "al_ndi_cm.h" + +#if WINVER <= 0x501 +#include "csq.h" +#endif + +/******************************************************************* + * + * IOCTLS + * + ******************************************************************/ + +/* + * Process the ioctl UAL_NDI_CREATE_CQ: + */ +static cl_status_t +__ndi_create_cq( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_create_cq_ioctl_t *p_ioctl = + (ual_create_cq_ioctl_t *)cl_ioctl_in_buf( h_ioctl ); + al_dev_open_context_t *p_context = + (al_dev_open_context_t *)p_open_context; + ib_ca_handle_t h_ca; + ib_cq_handle_t h_cq; + ib_cq_create_t cq_create; + ci_umv_buf_t *p_umv_buf = NULL; + ib_api_status_t status; + ib_pfn_event_cb_t pfn_ev; + + AL_ENTER( AL_DBG_NDI ); + + /* Validate input buffers. */ + if( !cl_ioctl_in_buf( h_ioctl ) || !cl_ioctl_out_buf( h_ioctl ) || + cl_ioctl_in_size( h_ioctl ) != sizeof(p_ioctl->in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(p_ioctl->out) ) + { + status = CL_INVALID_PARAMETER; + goto exit; + } + + /* Validate CA handle */ + h_ca = (ib_ca_handle_t) + al_hdl_ref( p_context->h_al, p_ioctl->in.h_ca, AL_OBJ_TYPE_H_CA ); + if( !h_ca ) + { + status = IB_INVALID_CA_HANDLE; + goto proxy_create_cq_err1; + } + + cq_create.size = p_ioctl->in.size; + + /* Override with proxy's cq callback */ + cq_create.pfn_comp_cb = ndi_cq_compl_cb; + cq_create.h_wait_obj = NULL; + pfn_ev = ndi_cq_error_cb; + + status = cpyin_umvbuf( &p_ioctl->in.umv_buf, &p_umv_buf ); + if( status != IB_SUCCESS ) + goto proxy_create_cq_err2; + + status = create_cq( h_ca, &cq_create, + (void*)(ULONG_PTR)p_ioctl->in.context, pfn_ev, &h_cq, p_umv_buf ); + + if( status != IB_SUCCESS ) + goto proxy_create_cq_err2; + + status = cpyout_umvbuf( &p_ioctl->out.umv_buf, p_umv_buf ); + if( status == IB_SUCCESS ) + { + p_ioctl->out.size = cq_create.size; + p_ioctl->out.h_cq = h_cq->obj.hdl; + h_cq->obj.hdl_valid = TRUE; + deref_al_obj( &h_cq->obj ); + } + else + { + h_cq->obj.pfn_destroy( &h_cq->obj, NULL ); + +proxy_create_cq_err2: + cl_waitobj_deref( cq_create.h_wait_obj ); + +proxy_create_cq_err1: + p_ioctl->out.umv_buf = p_ioctl->in.umv_buf; + p_ioctl->out.h_cq = AL_INVALID_HANDLE; + p_ioctl->out.size = 0; + } + free_umvbuf( p_umv_buf ); + + if( h_ca ) + deref_al_obj( &h_ca->obj ); + + p_ioctl->out.status = status; + *p_ret_bytes = sizeof(p_ioctl->out); + +exit: + AL_EXIT( AL_DBG_NDI ); + return CL_SUCCESS; +} + + +static cl_status_t +__ndi_notify_cq( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + cl_status_t cl_status; + ual_ndi_notify_cq_ioctl_in_t *p_ioctl; + al_dev_open_context_t *p_context; + ib_cq_handle_t h_cq; + UNUSED_PARAM(p_ret_bytes); + + AL_ENTER( AL_DBG_NDI ); + + p_context = (al_dev_open_context_t*)p_open_context; + p_ioctl = (ual_ndi_notify_cq_ioctl_in_t*)cl_ioctl_in_buf( h_ioctl ); + + /* Validate user parameters. */ + if( cl_ioctl_in_size( h_ioctl ) != sizeof(ual_ndi_notify_cq_ioctl_in_t) ) + { + cl_status = CL_INVALID_PARAMETER; + goto exit; + } + + /* Validate CQ handle */ + h_cq = (ib_cq_handle_t) + al_hdl_ref( p_context->h_al, p_ioctl->h_cq, AL_OBJ_TYPE_H_CQ ); + if( !h_cq ) + { + cl_status = CL_INVALID_HANDLE; + goto exit; + } + + /* enqueue the IRP (h_cq is referenced in al_hdl_ref) */ + if (p_ioctl->notify_comps) + IoCsqInsertIrp( &h_cq->compl.csq, h_ioctl, NULL ); + else + IoCsqInsertIrp( &h_cq->error.csq, h_ioctl, NULL ); + + cl_status = CL_PENDING; + +exit: + AL_EXIT( AL_DBG_NDI ); + return cl_status; +} + +static cl_status_t +__ndi_cancel_cq( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + cl_status_t cl_status; + ib_cq_handle_t h_cq = NULL; + al_dev_open_context_t *p_context; + UNUSED_PARAM(p_ret_bytes); + + AL_ENTER( AL_DBG_NDI ); + + p_context = (al_dev_open_context_t*)p_open_context; + + /* Validate user parameters. */ + if( cl_ioctl_in_size( h_ioctl ) != sizeof(uint64_t) ) + { + cl_status = CL_INVALID_PARAMETER; + goto exit; + } + + /* Validate CQ handle */ + h_cq = (ib_cq_handle_t) + al_hdl_ref( p_context->h_al, + *(uint64_t*)cl_ioctl_in_buf( h_ioctl ), AL_OBJ_TYPE_H_CQ ); + if( !h_cq ) + { + cl_status = CL_INVALID_HANDLE; + goto exit; + } + + /* flush IRP queues */ + ndi_cq_flush_ques( h_cq ); + + cl_status = CL_SUCCESS; + deref_al_obj( &h_cq->obj ); + +exit: + AL_EXIT( AL_DBG_NDI ); + return cl_status; +} + +static cl_status_t +__ndi_modify_qp( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + cl_status_t cl_status; + ib_api_status_t status; + ib_qp_handle_t h_qp = NULL; + al_dev_open_context_t *p_context; + ual_ndi_modify_qp_ioctl_in_t *p_req = + (ual_ndi_modify_qp_ioctl_in_t*)cl_ioctl_in_buf( h_ioctl ); + + UNUSED_PARAM(p_ret_bytes); + + AL_ENTER( AL_DBG_NDI ); + + p_context = (al_dev_open_context_t*)p_open_context; + + /* Validate user parameters. */ + if( cl_ioctl_in_size( h_ioctl ) < sizeof(ual_ndi_modify_qp_ioctl_in_t)) + { + cl_status = CL_INVALID_PARAMETER; + goto exit; + } + + /* Validate QP handle */ + h_qp = (ib_qp_handle_t)al_hdl_ref( p_context->h_al, p_req->h_qp, AL_OBJ_TYPE_H_QP ); + if( !h_qp ) + { + cl_status = CL_INVALID_HANDLE; + goto exit; + } + + /* Check QP type */ + if( h_qp->type != IB_QPT_RELIABLE_CONN ) + { + cl_status = CL_INVALID_HANDLE; + goto err; + } + + /* perform the ioctl */ + status = ndi_modify_qp( h_qp, &p_req->qp_mod, + cl_ioctl_out_size( h_ioctl ), cl_ioctl_out_buf( h_ioctl ) ); + if ( status != IB_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("ndi_modify_qp returned %s.\n", ib_get_err_str(status) ) ); + cl_status = CL_ERROR; + } + else + { + cl_status = CL_SUCCESS; + *p_ret_bytes = cl_ioctl_out_size( h_ioctl ); + } + +err: + deref_al_obj( &h_qp->obj ); + +exit: + AL_EXIT( AL_DBG_NDI ); + return cl_status; +} + +static cl_status_t +__ndi_req_cm( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + cl_status_t cl_status; + ib_qp_handle_t h_qp = NULL; + al_dev_open_context_t *p_context; + ual_ndi_req_cm_ioctl_in_t *p_req = + (ual_ndi_req_cm_ioctl_in_t*)cl_ioctl_in_buf( h_ioctl ); + UNUSED_PARAM(p_ret_bytes); + + AL_ENTER( AL_DBG_NDI ); + + p_context = (al_dev_open_context_t*)p_open_context; + + /* Validate user parameters. */ + if( cl_ioctl_in_size( h_ioctl ) < sizeof(ual_ndi_req_cm_ioctl_in_t) ) + { + cl_status = CL_INVALID_PARAMETER; + goto exit; + } + + /* Validate QP handle */ + h_qp = (ib_qp_handle_t)al_hdl_ref( p_context->h_al, p_req->h_qp, AL_OBJ_TYPE_H_QP ); + if( !h_qp ) + { + cl_status = CL_INVALID_HANDLE; + goto exit; + } + + /* Check QP type */ + if( h_qp->type != IB_QPT_RELIABLE_CONN ) + { + cl_status = CL_INVALID_HANDLE; + goto err; + } + + /* Check psize */ + if ( p_req->pdata_size > sizeof(p_req->pdata) ) + { + cl_status = CL_INVALID_PARAMETER; + goto err; + } + + /* perform the ioctl */ + cl_status = ndi_req_cm( p_context->h_al, h_ioctl ); + +err: + deref_al_obj( &h_qp->obj ); + +exit: + AL_EXIT( AL_DBG_NDI ); + return cl_status; +} + +static cl_status_t +__ndi_rep_cm( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + cl_status_t cl_status; + ib_qp_handle_t h_qp = NULL; + al_dev_open_context_t *p_context; + ual_ndi_rep_cm_ioctl_in_t *p_rep = + (ual_ndi_rep_cm_ioctl_in_t*)cl_ioctl_in_buf( h_ioctl ); + UNUSED_PARAM(p_ret_bytes); + + AL_ENTER( AL_DBG_NDI ); + + p_context = (al_dev_open_context_t*)p_open_context; + + /* Validate user parameters. */ + if( (cl_ioctl_in_size( h_ioctl ) < sizeof(ual_ndi_rep_cm_ioctl_in_t)) ) + { + cl_status = CL_INVALID_PARAMETER; + goto exit; + } + + AL_PRINT( TRACE_LEVEL_VERBOSE, AL_DBG_NDI, + ("CID = %d\n", p_rep->cid) ); + + /* Get and validate QP handle */ + h_qp = (ib_qp_handle_t)al_hdl_ref( p_context->h_al, p_rep->h_qp, AL_OBJ_TYPE_H_QP ); + if( !h_qp ) + { + cl_status = CL_INVALID_HANDLE; + goto exit; + } + + if( h_qp->type != IB_QPT_RELIABLE_CONN ) + { + cl_status = CL_INVALID_HANDLE; + goto err; + } + + /* Check psize */ + if ( p_rep->pdata_size >= sizeof(p_rep->pdata) ) + { + cl_status = CL_INVALID_PARAMETER; + goto err; + } + + /* perform the ioctls */ + cl_status = ndi_rep_cm( p_context->h_al, h_ioctl ); + +err: + deref_al_obj( &h_qp->obj ); + +exit: + AL_EXIT( AL_DBG_NDI ); + return cl_status; +} + + +static cl_status_t +__ndi_rej_cm( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + al_dev_open_context_t *p_context; + ib_api_status_t status; + ual_ndi_rej_cm_ioctl_in_t *p_rej = + (ual_ndi_rej_cm_ioctl_in_t*)cl_ioctl_in_buf( h_ioctl ); + NTSTATUS ntstatus; + UNUSED_PARAM(p_ret_bytes); + + AL_ENTER( AL_DBG_NDI ); + + p_context = (al_dev_open_context_t*)p_open_context; + + /* Check psize */ + if ( p_rej->pdata_size >= sizeof(p_rej->pdata) ) + { + ntstatus = CL_INVALID_PARAMETER; + goto exit; + } + + /* perform the ioctl */ + status = al_cep_rej( p_context->h_al, p_rej->cid, IB_REJ_USER_DEFINED, + NULL, 0, p_rej->pdata, p_rej->pdata_size); + if (status != IB_SUCCESS) + { + ntstatus = CL_INVALID_HANDLE; + goto exit; + } + + ntstatus = STATUS_SUCCESS; + +exit: + AL_EXIT( AL_DBG_NDI ); + return ntstatus; +} + +static cl_status_t +__ndi_rtu_cm( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + cl_status_t cl_status; + nd_csq_t* p_csq; + al_dev_open_context_t *p_context; + + UNUSED_PARAM(p_ret_bytes); + + AL_ENTER( AL_DBG_NDI ); + + p_context = (al_dev_open_context_t*)p_open_context; + + /* Validate user parameters. */ + if( cl_ioctl_in_size( h_ioctl ) < sizeof(net32_t) ) + { + cl_status = CL_INVALID_PARAMETER; + goto exit; + } + + p_csq = kal_cep_get_context( + p_context->h_al, + *(net32_t*)cl_ioctl_in_buf( h_ioctl ), + nd_cm_handler, + nd_csq_ref + ); + if( p_csq == NULL ) + { + cl_status = CL_INVALID_HANDLE; + goto exit; + } + + /* perform the ioctl */ + cl_status = ndi_rtu_cm( p_csq, h_ioctl ); + + nd_csq_release( p_csq ); + +exit: + AL_EXIT( AL_DBG_NDI ); + return cl_status; +} + +static cl_status_t +__ndi_dreq_cm( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + cl_status_t cl_status; + nd_csq_t *p_csq; + al_dev_open_context_t *p_context; + + UNUSED_PARAM(p_ret_bytes); + + AL_ENTER( AL_DBG_NDI ); + + p_context = (al_dev_open_context_t*)p_open_context; + + /* Validate user parameters. */ + if( cl_ioctl_in_size( h_ioctl ) < sizeof(net32_t) ) + { + cl_status = CL_INVALID_PARAMETER; + goto exit; + } + + /* Validate CID */ + p_csq = (nd_csq_t*)kal_cep_get_context( + p_context->h_al, + *(net32_t*)cl_ioctl_in_buf( h_ioctl ), + nd_cm_handler, + nd_csq_ref + ); + + if( p_csq == NULL ) + { + cl_status = CL_CONNECTION_INVALID; + goto exit; + } + + /* perform the ioctl */ + cl_status = ndi_dreq_cm( p_csq, h_ioctl ); + + nd_csq_release( p_csq ); + +exit: + AL_EXIT( AL_DBG_NDI ); + return cl_status; +} + +static NTSTATUS +__ndi_notify_dreq_cm( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + NTSTATUS status; + nd_csq_t *p_csq; + al_dev_open_context_t *p_context; + + UNUSED_PARAM(p_ret_bytes); + + AL_ENTER( AL_DBG_NDI ); + + p_context = (al_dev_open_context_t*)p_open_context; + + /* Validate user parameters. */ + if( cl_ioctl_in_size( h_ioctl ) < sizeof(net32_t) ) + { + status = STATUS_INVALID_PARAMETER; + goto exit; + } + + /* Validate CID */ + p_csq = (nd_csq_t*)kal_cep_get_context( + p_context->h_al, + *(net32_t*)cl_ioctl_in_buf( h_ioctl ), + nd_cm_handler, + nd_csq_ref + ); + + if( p_csq == NULL ) + { + status = STATUS_CONNECTION_INVALID; + goto exit; + } + + /* perform the ioctl */ + status = IoCsqInsertIrpEx( + &p_csq->csq, + h_ioctl, + NULL, + (VOID*)(ULONG_PTR)NDI_CM_CONNECTED_DREQ_RCVD + ); + + nd_csq_release( p_csq ); + +exit: + AL_EXIT( AL_DBG_NDI ); + return status; +} + +static cl_status_t +__ndi_cancel_cm_irps( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + nd_csq_t *p_csq; + al_dev_open_context_t *p_context; + + UNUSED_PARAM(p_ret_bytes); + + AL_ENTER( AL_DBG_NDI ); + + p_context = (al_dev_open_context_t*)p_open_context; + + /* Validate user parameters. */ + if( cl_ioctl_in_size( h_ioctl ) < sizeof(net32_t) ) + { + AL_EXIT( AL_DBG_NDI ); + return STATUS_INVALID_PARAMETER; + } + + /* Validate CID */ + p_csq = (nd_csq_t*)kal_cep_get_context( + p_context->h_al, + *(net32_t*)cl_ioctl_in_buf( h_ioctl ), + nd_cm_handler, + nd_csq_ref + ); + + if( p_csq == NULL ) + { + AL_EXIT( AL_DBG_NDI ); + return STATUS_UNSUCCESSFUL; + } + + /* perform the ioctl */ + ndi_cancel_cm_irps( p_csq ); + nd_csq_release( p_csq ); + + AL_EXIT( AL_DBG_NDI ); + return STATUS_SUCCESS; +} + +static cl_status_t +__ndi_listen_cm( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + al_dev_open_context_t *p_context; + ual_cep_listen_ioctl_t *p_listen = + (ual_cep_listen_ioctl_t*)cl_ioctl_in_buf( h_ioctl ); + net32_t* p_cid = + (net32_t*)cl_ioctl_out_buf( h_ioctl ); + + AL_ENTER( AL_DBG_NDI ); + + p_context = (al_dev_open_context_t*)p_open_context; + + /* Validate user parameters. */ + if( cl_ioctl_in_size( h_ioctl ) < sizeof(*p_listen) || + cl_ioctl_out_size( h_ioctl ) != sizeof(*p_cid) ) + { + AL_EXIT( AL_DBG_NDI ); + return CL_INVALID_PARAMETER; + } + + /* Set the private data compare buffer to our kernel copy. */ + if( p_listen->cep_listen.p_cmp_buf ) + p_listen->cep_listen.p_cmp_buf = p_listen->compare; + + AL_EXIT( AL_DBG_NDI ); + return ndi_listen_cm( p_context->h_al, &p_listen->cep_listen, p_cid, p_ret_bytes ); +} + +static cl_status_t +__ndi_get_req_cm( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + al_dev_open_context_t *p_context; + nd_csq_t *p_csq; + NTSTATUS status; + + AL_ENTER( AL_DBG_NDI ); + + UNREFERENCED_PARAMETER( p_ret_bytes ); + + p_context = (al_dev_open_context_t*)p_open_context; + + /* Validate user parameters. */ + if( cl_ioctl_in_size( h_ioctl ) != sizeof(net32_t) || + cl_ioctl_out_size( h_ioctl ) != sizeof(net32_t) ) + { + AL_EXIT( AL_DBG_NDI ); + return CL_INVALID_PARAMETER; + } + + /* Validate CID */ + p_csq = (nd_csq_t*)kal_cep_get_context( + p_context->h_al, + *(net32_t*)cl_ioctl_in_buf( h_ioctl ), + nd_cm_handler, + nd_csq_ref + ); + + if( p_csq == NULL ) + { + AL_EXIT( AL_DBG_NDI ); + return STATUS_UNSUCCESSFUL; + } + + status = ndi_get_req_cm( p_csq, h_ioctl ); + nd_csq_release( p_csq ); + AL_EXIT( AL_DBG_NDI ); + return status; +} + +cl_status_t +ndi_ioctl( + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + cl_status_t cl_status; + IO_STACK_LOCATION *p_io_stack; + void *p_context; + + AL_ENTER( AL_DBG_NDI ); + + p_io_stack = IoGetCurrentIrpStackLocation( h_ioctl ); + p_context = p_io_stack->FileObject->FsContext; + + if( !p_context ) + { + AL_EXIT( AL_DBG_DEV ); + return CL_INVALID_PARAMETER; + } + + switch( cl_ioctl_ctl_code( h_ioctl ) ) + { + case UAL_NDI_CREATE_CQ: + cl_status = __ndi_create_cq( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_NDI_NOTIFY_CQ: + cl_status = __ndi_notify_cq( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_NDI_CANCEL_CQ: + cl_status = __ndi_cancel_cq( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_NDI_MODIFY_QP: + cl_status = __ndi_modify_qp( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_NDI_REQ_CM: + cl_status = __ndi_req_cm( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_NDI_REP_CM: + cl_status = __ndi_rep_cm( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_NDI_RTU_CM: + cl_status = __ndi_rtu_cm( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_NDI_REJ_CM: + cl_status = __ndi_rej_cm( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_NDI_DREQ_CM: + cl_status = __ndi_dreq_cm( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_NDI_NOOP: + IoMarkIrpPending( h_ioctl ); + if( cl_ioctl_in_size( h_ioctl ) != 0 ) + h_ioctl->IoStatus.Status = STATUS_TIMEOUT; + else + h_ioctl->IoStatus.Status = CL_SUCCESS; + h_ioctl->IoStatus.Information = 0; + + AL_PRINT( TRACE_LEVEL_VERBOSE, AL_DBG_NDI, + ("UAL_NDI_NOOP completed with %08x\n", h_ioctl->IoStatus.Status) ); + IoCompleteRequest( h_ioctl, IO_NETWORK_INCREMENT ); + cl_status = CL_PENDING; + break; + case UAL_NDI_NOTIFY_DREQ: + cl_status = __ndi_notify_dreq_cm( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_NDI_CANCEL_CM_IRPS: + cl_status = __ndi_cancel_cm_irps( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_NDI_LISTEN_CM: + cl_status = __ndi_listen_cm( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_NDI_GET_REQ_CM: + cl_status = __ndi_get_req_cm( p_context, h_ioctl, p_ret_bytes ); + break; + default: + cl_status = CL_INVALID_PARAMETER; + break; + } + + AL_EXIT( AL_DBG_NDI ); + return cl_status; +} + diff --git a/branches/WOF2-3/core/al/kernel/al_proxy_subnet.c b/branches/WOF2-3/core/al/kernel/al_proxy_subnet.c new file mode 100644 index 00000000..07ec17af --- /dev/null +++ b/branches/WOF2-3/core/al/kernel/al_proxy_subnet.c @@ -0,0 +1,1162 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include +#include +#include + +#include "al.h" +#include "al_av.h" +#include "al_ca.h" +#include "al_cq.h" +#include "al_debug.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "al_proxy_subnet.tmh" +#endif +#include "al_dev.h" +#include "al_mad_pool.h" +#include "al_mr.h" +#include "al_mw.h" +#include "al_pd.h" +#include "al_qp.h" +#include "ib_common.h" +#include "al_proxy.h" + + +extern ib_pool_handle_t gh_mad_pool; + + + +static +cl_status_t +proxy_reg_svc( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + UNUSED_PARAM( p_open_context ); + UNUSED_PARAM( h_ioctl ); + UNUSED_PARAM( p_ret_bytes ); + return CL_ERROR; +} +static +cl_status_t +proxy_dereg_svc( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + UNUSED_PARAM( p_open_context ); + UNUSED_PARAM( h_ioctl ); + UNUSED_PARAM( p_ret_bytes ); + return CL_ERROR; +} + + +static void +__proxy_sa_req_cb( + IN al_sa_req_t *p_sa_req, + IN ib_mad_element_t *p_mad_response ) +{ + IRP *p_irp; + IO_STACK_LOCATION *p_io_stack; + ual_send_sa_req_ioctl_t *p_ioctl; + al_dev_open_context_t *p_context; + uint64_t hdl; + + AL_ENTER( AL_DBG_QUERY ); + + p_irp = (IRP*)p_sa_req->user_context; + CL_ASSERT( p_irp ); + + p_io_stack = IoGetCurrentIrpStackLocation( p_irp ); + p_ioctl = cl_ioctl_out_buf( p_irp ); + + p_context = p_io_stack->FileObject->FsContext; + ASSERT( p_context ); +#pragma warning(push, 3) + IoSetCancelRoutine( p_irp, NULL ); +#pragma warning(pop) + /* Clear the pointer to the query to prevent cancelation. */ + hdl = (size_t)InterlockedExchangePointer( + &p_irp->Tail.Overlay.DriverContext[0], AL_INVALID_HANDLE ); + + cl_spinlock_acquire( &p_context->h_al->obj.lock ); + if( hdl != AL_INVALID_HANDLE ) + { + CL_ASSERT( p_sa_req == + al_hdl_chk( p_context->h_al, hdl, AL_OBJ_TYPE_H_SA_REQ ) ); + al_hdl_free( p_context->h_al, hdl ); + } + + p_ioctl->out.status = p_sa_req->status; + if( p_mad_response ) + { + /* Insert an item to track the MAD until the user fetches it. */ + hdl = al_hdl_insert( p_context->h_al, + p_mad_response, AL_OBJ_TYPE_H_MAD ); + if( hdl != AL_INVALID_HANDLE ) + { + p_ioctl->out.h_resp = hdl; + p_ioctl->out.resp_size = p_mad_response->size; + } + else + { + p_ioctl->out.h_resp = AL_INVALID_HANDLE; + p_ioctl->out.resp_size = 0; + p_ioctl->out.status = IB_TIMEOUT; + ib_put_mad( p_sa_req->p_mad_response ); + } + } + else + { + p_ioctl->out.h_resp = AL_INVALID_HANDLE; + p_ioctl->out.resp_size = 0; + } + cl_spinlock_release( &p_context->h_al->obj.lock ); + + p_irp->IoStatus.Status = STATUS_SUCCESS; + p_irp->IoStatus.Information = sizeof(p_ioctl->out); + IoCompleteRequest( p_irp, IO_NO_INCREMENT ); + + /* Release the reference taken when the query was initiated. */ + proxy_context_deref( p_context ); + + cl_free( p_sa_req ); + + AL_EXIT( AL_DBG_QUERY ); +} + + +static void +__proxy_cancel_sa_req( + IN DEVICE_OBJECT* p_dev_obj, + IN IRP* p_irp ) +{ + al_dev_open_context_t *p_context; + PIO_STACK_LOCATION p_io_stack; + uint64_t hdl; + al_sa_req_t *p_sa_req; + + AL_ENTER( AL_DBG_DEV ); + + UNUSED_PARAM( p_dev_obj ); + + /* Get the stack location. */ + p_io_stack = IoGetCurrentIrpStackLocation( p_irp ); + + p_context = (al_dev_open_context_t *)p_io_stack->FileObject->FsContext; + ASSERT( p_context ); + + hdl = (size_t)InterlockedExchangePointer( + &p_irp->Tail.Overlay.DriverContext[0], NULL ); + if( hdl != AL_INVALID_HANDLE ) + { +#pragma warning(push, 3) + IoSetCancelRoutine( p_irp, NULL ); +#pragma warning(pop) + cl_spinlock_acquire( &p_context->h_al->obj.lock ); + p_sa_req = al_hdl_chk( p_context->h_al, hdl, AL_OBJ_TYPE_H_SA_REQ ); + CL_ASSERT( p_sa_req ); + al_cancel_sa_req( p_sa_req ); + al_hdl_free( p_context->h_al, hdl ); + cl_spinlock_release( &p_context->h_al->obj.lock ); + } + + IoReleaseCancelSpinLock( p_irp->CancelIrql ); +} + + +static cl_status_t +proxy_send_sa_req( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_send_sa_req_ioctl_t *p_ioctl; + cl_status_t status; + ib_api_status_t ib_status, *p_usr_status; + IO_STACK_LOCATION *p_io_stack; + al_dev_open_context_t *p_context; + al_sa_req_t *p_sa_req; + uint64_t hdl, *p_usr_hdl; + + AL_ENTER( AL_DBG_QUERY ); + + UNUSED_PARAM( p_ret_bytes ); + + p_context = p_open_context; + + p_io_stack = IoGetCurrentIrpStackLocation( h_ioctl ); + /* + * We support SA requests coming in either through the main file object + * or the async file handle. + */ + if( p_io_stack->FileObject->FsContext2 && + (uintn_t)p_io_stack->FileObject->FsContext2 != AL_OBJ_TYPE_SA_REQ_SVC ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("Invalid file object type for request: %p\n", + p_io_stack->FileObject->FsContext2) ); + return CL_INVALID_PARAMETER; + } + + /* Check the size of the ioctl */ + if( cl_ioctl_in_size( h_ioctl ) != sizeof(p_ioctl->in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(p_ioctl->out) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("Invalid IOCTL buffers.\n") ); + return CL_INVALID_PARAMETER; + } + + p_ioctl = cl_ioctl_in_buf( h_ioctl ); + CL_ASSERT( p_ioctl ); + + /* Must save user's pointers in case req completes before call returns. */ + p_usr_status = (ib_api_status_t*)(ULONG_PTR)p_ioctl->in.p_status; + p_usr_hdl = (uint64_t*)(ULONG_PTR)p_ioctl->in.ph_sa_req; + + if( p_ioctl->in.sa_req.attr_size > IB_SA_DATA_SIZE ) + { + ib_status = IB_INVALID_SETTING; + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("Invalid SA data size: %d\n", + p_ioctl->in.sa_req.attr_size) ); + goto proxy_send_sa_req_err1; + } + + p_sa_req = (al_sa_req_t*)cl_zalloc( sizeof(al_sa_req_t) ); + if( !p_sa_req ) + { + ib_status = IB_INSUFFICIENT_MEMORY; + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("Failed to allocate SA req.\n") ); + goto proxy_send_sa_req_err1; + } + + /* Synchronize with callbacks. */ + cl_spinlock_acquire( &p_context->h_al->obj.lock ); + + /* Track the request. */ + hdl = al_hdl_insert( p_context->h_al, p_sa_req, AL_OBJ_TYPE_H_SA_REQ ); + if( hdl == AL_INVALID_HANDLE ) + { + ib_status = IB_INSUFFICIENT_MEMORY; + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("Failed to create handle.\n") ); + goto proxy_send_sa_req_err2; + } + + /* + * Store the handle in the IRP's driver context so we can cancel it. + * Note that the handle is really a size_t variable, but is cast to a + * uint64_t to provide constant size in mixed 32- and 64-bit environments. + */ + h_ioctl->Tail.Overlay.DriverContext[0] = (void*)(size_t)hdl; + + /* Format the SA request */ + p_sa_req->user_context = h_ioctl; + p_sa_req->pfn_sa_req_cb = __proxy_sa_req_cb; + + p_ioctl->in.sa_req.p_attr = p_ioctl->in.attr; + + /* + * We never pass the user-mode flag when sending SA requests - the + * I/O manager will perform all synchronization to make this IRP sync + * if it needs to. + */ + ib_status = al_send_sa_req( p_sa_req, p_ioctl->in.port_guid, + p_ioctl->in.timeout_ms, p_ioctl->in.retry_cnt, + &p_ioctl->in.sa_req, 0 ); + if( ib_status == IB_SUCCESS ) + { + /* Hold a reference on the proxy context until the request completes. */ + proxy_context_ref( p_context ); +#pragma warning(push, 3) + IoSetCancelRoutine( h_ioctl, __proxy_cancel_sa_req ); +#pragma warning(pop) + IoMarkIrpPending( h_ioctl ); + + cl_spinlock_release( &p_context->h_al->obj.lock ); + + cl_copy_to_user( p_usr_hdl, &hdl, sizeof(hdl) ); + status = CL_PENDING; + } + else + { + al_hdl_free( p_context->h_al, hdl ); + +proxy_send_sa_req_err2: + cl_spinlock_release( &p_context->h_al->obj.lock ); + cl_free( p_sa_req ); + +proxy_send_sa_req_err1: + status = CL_INVALID_PARAMETER; + } + + cl_copy_to_user( p_usr_status, &ib_status, sizeof(ib_api_status_t) ); + + AL_EXIT( AL_DBG_QUERY ); + return status; +} + + +static cl_status_t +proxy_cancel_sa_req( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_cancel_sa_req_ioctl_t *p_ioctl; + al_dev_open_context_t *p_context; + al_sa_req_t *p_sa_req; + + AL_ENTER( AL_DBG_QUERY ); + + UNUSED_PARAM( p_ret_bytes ); + + p_context = p_open_context; + + /* Check the size of the ioctl */ + if( cl_ioctl_in_size( h_ioctl ) != sizeof(ual_cancel_sa_req_ioctl_t) || + cl_ioctl_out_size( h_ioctl ) ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("Invalid input buffer.\n") ); + return CL_INVALID_PARAMETER; + } + + p_ioctl = cl_ioctl_in_buf( h_ioctl ); + CL_ASSERT( p_ioctl ); + + cl_spinlock_acquire( &p_context->h_al->obj.lock ); + p_sa_req = + al_hdl_chk( p_context->h_al, p_ioctl->h_sa_req, AL_OBJ_TYPE_H_SA_REQ ); + if( p_sa_req ) + al_cancel_sa_req( p_sa_req ); + cl_spinlock_release( &p_context->h_al->obj.lock ); + + AL_EXIT( AL_DBG_QUERY ); + return CL_SUCCESS; +} + + +static cl_status_t +proxy_send_mad( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_send_mad_ioctl_t *p_ioctl = + (ual_send_mad_ioctl_t *)cl_ioctl_in_buf( h_ioctl ); + al_dev_open_context_t *p_context = + (al_dev_open_context_t *)p_open_context; + ib_mad_svc_handle_t h_mad_svc; + ib_pool_key_t pool_key = NULL; + ib_av_handle_t h_av = NULL; + ib_mad_element_t *p_mad_el; + al_mad_element_t *p_al_el; + ib_mad_t *p_mad_buf, *p_usr_buf; + ib_grh_t *p_grh, *p_usr_grh; + ib_api_status_t status; + + AL_ENTER( AL_DBG_MAD ); + /* Validate input buffers. */ + if( !cl_ioctl_in_buf( h_ioctl ) || !cl_ioctl_out_buf( h_ioctl ) || + cl_ioctl_in_size( h_ioctl ) != sizeof(p_ioctl->in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(p_ioctl->out) ) + { + AL_EXIT( AL_DBG_MAD ); + return CL_INVALID_PARAMETER; + } + + /* Validate mad svc handle. */ + h_mad_svc = (ib_mad_svc_handle_t)al_hdl_ref( + p_context->h_al, p_ioctl->in.h_mad_svc, AL_OBJ_TYPE_H_MAD_SVC ); + if( !h_mad_svc ) + { + status = IB_INVALID_HANDLE; + goto proxy_send_mad_err1; + } + + /* Validate the pool key */ + pool_key = (ib_pool_key_t)al_hdl_ref( + p_context->h_al, p_ioctl->in.pool_key, AL_OBJ_TYPE_H_POOL_KEY ); + if( !pool_key ) + { + status = IB_INVALID_HANDLE; + goto proxy_send_mad_err1; + } + + /* Validate the AV handle in the mad element if it is not NULL. */ + if( p_ioctl->in.h_av ) + { + h_av = (ib_av_handle_t) + al_hdl_ref( p_context->h_al, p_ioctl->in.h_av, AL_OBJ_TYPE_H_AV ); + if( !h_av ) + { + status = IB_INVALID_AV_HANDLE; + goto proxy_send_mad_err1; + } + } + + /* + * Get a mad element from kernel MAD pool + * This should not fail since the pool is set to grow + * dynamically + */ + status = ib_get_mad( pool_key, p_ioctl->in.size, &p_mad_el ); + if( status != IB_SUCCESS ) + goto proxy_send_mad_err1; + + /* Store the MAD and GRH buffers pointers. */ + p_mad_buf = p_mad_el->p_mad_buf; + p_grh = p_mad_el->p_grh; + + /* Now copy the mad element with all info */ + status = ib_convert_cl_status( cl_copy_from_user( p_mad_el, + (void*)(ULONG_PTR)p_ioctl->in.p_mad_element, + sizeof(ib_mad_element_t) ) ); + if( status != IB_SUCCESS ) + goto proxy_send_mad_err2; + + /* Store the UM pointers. */ + p_usr_buf = p_mad_el->p_mad_buf; + p_usr_grh = p_mad_el->p_grh; + /* Restore the MAD and GRH buffer pointers. */ + p_mad_el->p_mad_buf = p_mad_buf; + p_mad_el->p_grh = p_grh; + /* Clear the next pointer. */ + p_mad_el->p_next = NULL; + /* + * Override the send context so that a response's MAD has a way + * of getting back to the associated send. This is needed because a + * MAD receive completion could fail to be delivered to the app even though + * the response was properly received in the kernel. + */ + p_mad_el->context1 = (void*)(ULONG_PTR)p_ioctl->in.p_mad_element; + + /* Set the kernel AV handle. This is either NULL or a valid KM handle. */ + p_mad_el->h_av = h_av; + + /* Copy the GRH, if valid. */ + if( p_mad_el->grh_valid ) + { + status = ib_convert_cl_status( + cl_copy_from_user( p_grh, p_usr_grh, sizeof(ib_grh_t) ) ); + if( status != IB_SUCCESS ) + goto proxy_send_mad_err2; + } + + /* Copy the mad payload. */ + status = ib_convert_cl_status( + cl_copy_from_user( p_mad_buf, p_usr_buf, p_ioctl->in.size ) ); + if( status != IB_SUCCESS ) + goto proxy_send_mad_err2; + + /* Copy the handle to UM to allow cancelling. */ + status = ib_convert_cl_status( cl_copy_to_user( + (void*)(ULONG_PTR)p_ioctl->in.ph_proxy, + &p_mad_el, sizeof(ib_mad_element_t*) ) ); + if( status != IB_SUCCESS ) + goto proxy_send_mad_err2; + + /* + * Copy the UM element pointer to the kernel's AL element + * for use in completion generation. + */ + p_al_el = PARENT_STRUCT( p_mad_el, al_mad_element_t, element ); + p_al_el->h_proxy_element = p_ioctl->in.p_mad_element; + + /* Post the element. */ + status = ib_send_mad( h_mad_svc, p_mad_el, NULL ); + + if( status != IB_SUCCESS ) + { +proxy_send_mad_err2: + ib_put_mad( p_mad_el ); + } +proxy_send_mad_err1: + + if( h_av ) + deref_al_obj( &h_av->obj ); + if( pool_key ) + deref_al_obj( &pool_key->obj ); + if( h_mad_svc ) + deref_al_obj( &h_mad_svc->obj ); + + p_ioctl->out.status = status; + *p_ret_bytes = sizeof(p_ioctl->out); + + AL_EXIT( AL_DBG_MAD ); + return CL_SUCCESS; +} + + + +/* + * Process the ioctl to retrieve a received MAD. + */ +static cl_status_t +proxy_mad_comp( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_mad_recv_ioctl_t *p_ioctl; + al_dev_open_context_t *p_context; + ib_mad_element_t *p_mad; + ib_api_status_t status; + + AL_ENTER( AL_DBG_MAD ); + + /* Validate input buffers. */ + if( !cl_ioctl_in_buf( h_ioctl ) || !cl_ioctl_out_buf( h_ioctl ) || + cl_ioctl_in_size( h_ioctl ) != sizeof(p_ioctl->in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(p_ioctl->out) ) + { + AL_EXIT( AL_DBG_MAD ); + return CL_INVALID_PARAMETER; + } + + p_ioctl = (ual_mad_recv_ioctl_t*)cl_ioctl_in_buf( h_ioctl ); + p_context = (al_dev_open_context_t*)p_open_context; + + /* Validate the MAD handle and remove it from the handle manager. */ + p_mad = al_hdl_get_mad( p_context->h_al, p_ioctl->in.h_mad ); + if( !p_mad ) + { + status = IB_INVALID_HANDLE; + goto proxy_mad_comp_err1; + } + + /* + * Return the MAD to the user. The user-mode library is responsible + * for correcting all pointers. + */ + status = ib_convert_cl_status( cl_copy_to_user( + (void*)(ULONG_PTR)p_ioctl->in.p_user_mad, + p_mad, sizeof(ib_mad_element_t) ) ); + if( status != IB_SUCCESS ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("Unable to copy element to user's MAD\n") ); + goto proxy_mad_comp_err2; + } + + /* Copy the MAD buffer. */ + status = ib_convert_cl_status( cl_copy_to_user( + (void*)(ULONG_PTR)p_ioctl->in.p_mad_buf, p_mad->p_mad_buf, p_mad->size ) ); + if( status != IB_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("Unable to copy buffer to user's MAD\n") ); + goto proxy_mad_comp_err2; + } + + /* Copy the GRH if it is valid. */ + if( p_mad->grh_valid ) + { + status = ib_convert_cl_status( cl_copy_to_user( + (void*)(ULONG_PTR)p_ioctl->in.p_grh, p_mad->p_grh, sizeof(ib_grh_t) ) ); + if( status != IB_SUCCESS ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("Unable to copy GRH to user's MAD\n") ); + goto proxy_mad_comp_err2; + } + } + + if( status == IB_SUCCESS ) + { + ib_put_mad( p_mad ); + } + else + { +proxy_mad_comp_err2: + ib_put_mad( p_mad ); +proxy_mad_comp_err1: + cl_memclr( &p_ioctl->out, sizeof(p_ioctl->out) ); + } + + p_ioctl->out.status = status; + *p_ret_bytes = sizeof(p_ioctl->out); + + AL_EXIT( AL_DBG_MAD ); + return CL_SUCCESS; +} + + + +static cl_status_t +proxy_init_dgrm( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + UNUSED_PARAM( p_open_context ); + UNUSED_PARAM( h_ioctl ); + UNUSED_PARAM( p_ret_bytes ); + return CL_ERROR; +} + + + +static void +__proxy_mad_send_cb( + IN ib_mad_svc_handle_t h_mad_svc, + IN void *mad_svc_context, + IN ib_mad_element_t *p_mad_element ) +{ + misc_cb_ioctl_info_t cb_info; + al_dev_open_context_t *p_context; + al_mad_element_t *p_al_el; + + AL_ENTER( AL_DBG_MAD ); + + CL_ASSERT( p_mad_element ); + CL_ASSERT( !p_mad_element->p_next ); + p_context = h_mad_svc->obj.h_al->p_context; + p_al_el = PARENT_STRUCT( p_mad_element, al_mad_element_t, element ); + + /* + * If we're already closing the device - do not queue a callback, since + * we're cleaning up the callback lists. + */ + if( proxy_context_ref( p_context ) ) + { + /* Set up context and callback record type appropriate for UAL */ + cb_info.rec_type = MAD_SEND_REC; + cb_info.ioctl_rec.mad_send_cb_ioctl_rec.wc_status = + p_mad_element->status; + cb_info.ioctl_rec.mad_send_cb_ioctl_rec.p_um_mad = + p_al_el->h_proxy_element; + cb_info.ioctl_rec.mad_send_cb_ioctl_rec.mad_svc_context = + (ULONG_PTR)mad_svc_context; + + /* Queue this mad completion notification for the user. */ + proxy_queue_cb_buf( UAL_GET_MISC_CB_INFO, p_context, &cb_info, + &h_mad_svc->obj ); + } + + /* Return the MAD. */ + ib_put_mad( p_mad_element ); + + proxy_context_deref( p_context ); + AL_EXIT( AL_DBG_MAD ); +} + + + +static void +__proxy_mad_recv_cb( + IN ib_mad_svc_handle_t h_mad_svc, + IN void *mad_svc_context, + IN ib_mad_element_t *p_mad_element ) +{ + misc_cb_ioctl_info_t cb_info; + al_dev_open_context_t *p_context; + al_mad_element_t *p_al_mad; + uint64_t hdl; + + AL_ENTER( AL_DBG_MAD ); + + p_context = h_mad_svc->obj.h_al->p_context; + + p_al_mad = PARENT_STRUCT( p_mad_element, al_mad_element_t, element ); + + /* Set up context and callback record type appropriate for UAL */ + cb_info.rec_type = MAD_RECV_REC; + cb_info.ioctl_rec.mad_recv_cb_ioctl_rec.mad_svc_context = (ULONG_PTR)mad_svc_context; + cb_info.ioctl_rec.mad_recv_cb_ioctl_rec.elem_size = p_mad_element->size; + cb_info.ioctl_rec.mad_recv_cb_ioctl_rec.p_send_mad = + (ULONG_PTR)p_mad_element->send_context1; + + /* + * If we're already closing the device - do not queue a callback, since + * we're cleaning up the callback lists. + */ + if( !proxy_context_ref( p_context ) ) + { + ib_put_mad( p_mad_element ); + AL_EXIT( AL_DBG_MAD ); + return; + } + + /* Insert an item to track the MAD until the user fetches it. */ + cl_spinlock_acquire( &p_context->h_al->obj.lock ); + hdl = al_hdl_insert( p_context->h_al, p_mad_element, AL_OBJ_TYPE_H_MAD ); + if( hdl == AL_INVALID_HANDLE ) + goto proxy_mad_recv_cb_err; + + cb_info.ioctl_rec.mad_recv_cb_ioctl_rec.h_mad = hdl; + + /* Queue this mad completion notification for the user. */ + if( !proxy_queue_cb_buf( UAL_GET_MISC_CB_INFO, p_context, &cb_info, + &h_mad_svc->obj ) ) + { + al_hdl_free( p_context->h_al, hdl ); +proxy_mad_recv_cb_err: + ib_put_mad( p_mad_element ); + } + cl_spinlock_release( &p_context->h_al->obj.lock ); + + proxy_context_deref( p_context ); + + AL_EXIT( AL_DBG_MAD ); +} + + + +static cl_status_t +proxy_reg_mad_svc( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_reg_mad_svc_ioctl_t *p_ioctl = + (ual_reg_mad_svc_ioctl_t *)cl_ioctl_in_buf( h_ioctl ); + al_dev_open_context_t *p_context = + (al_dev_open_context_t *)p_open_context; + ib_qp_handle_t h_qp; + ib_mad_svc_handle_t h_mad_svc; + + AL_ENTER( AL_DBG_MAD ); + + /* Validate input buffers. */ + if( !cl_ioctl_in_buf( h_ioctl ) || !cl_ioctl_out_buf( h_ioctl ) || + cl_ioctl_in_size( h_ioctl ) != sizeof(p_ioctl->in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(p_ioctl->out) ) + { + AL_EXIT( AL_DBG_MAD ); + return CL_INVALID_PARAMETER; + } + + /* Set the return bytes in all cases */ + *p_ret_bytes = sizeof(p_ioctl->out); + + /* Validate QP handle */ + h_qp = (ib_qp_handle_t) + al_hdl_ref( p_context->h_al, p_ioctl->in.h_qp, AL_OBJ_TYPE_H_QP ); + if( !h_qp ) + { + p_ioctl->out.status = IB_INVALID_QP_HANDLE; + p_ioctl->out.h_mad_svc = AL_INVALID_HANDLE; + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_QP_HANDLE\n") ); + return CL_SUCCESS; + } + + /* Now proxy's mad_svc overrides */ + p_ioctl->in.mad_svc.pfn_mad_send_cb = __proxy_mad_send_cb; + p_ioctl->in.mad_svc.pfn_mad_recv_cb = __proxy_mad_recv_cb; + + p_ioctl->out.status = reg_mad_svc( h_qp, + &p_ioctl->in.mad_svc, &h_mad_svc ); + if( p_ioctl->out.status == IB_SUCCESS ) + { + p_ioctl->out.h_mad_svc = h_mad_svc->obj.hdl; + h_mad_svc->obj.hdl_valid = TRUE; + deref_al_obj( &h_mad_svc->obj ); + } + else + { + p_ioctl->out.h_mad_svc = AL_INVALID_HANDLE; + } + + deref_al_obj( &h_qp->obj ); + + AL_EXIT( AL_DBG_MAD ); + return CL_SUCCESS; +} + + + +/* + * Deregister the MAD service. + */ +static cl_status_t +proxy_dereg_mad_svc( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_dereg_mad_svc_ioctl_t *p_ioctl; + al_dev_open_context_t *p_context; + ib_mad_svc_handle_t h_mad_svc; + + AL_ENTER( AL_DBG_MAD ); + + if( !cl_ioctl_in_buf( h_ioctl ) || !cl_ioctl_out_buf( h_ioctl ) || + cl_ioctl_in_size( h_ioctl ) != sizeof(p_ioctl->in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(p_ioctl->out) ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("IOCTL buffer is invalid\n") ); + return CL_INVALID_PARAMETER; + } + + p_ioctl = (ual_dereg_mad_svc_ioctl_t*)cl_ioctl_in_buf( h_ioctl ); + p_context = (al_dev_open_context_t*)p_open_context; + + /* Set the return bytes in all cases */ + *p_ret_bytes = sizeof(p_ioctl->out); + + /* Validate MAD service. */ + h_mad_svc = (ib_mad_svc_handle_t)al_hdl_ref( + p_context->h_al, p_ioctl->in.h_mad_svc, AL_OBJ_TYPE_H_MAD_SVC ); + if( !h_mad_svc ) + { + p_ioctl->out.status = IB_INVALID_HANDLE; + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_HANDLE\n") ); + return CL_SUCCESS; + } + + /* Destroy the MAD service. */ + h_mad_svc->obj.pfn_destroy( &h_mad_svc->obj, ib_sync_destroy ); + p_ioctl->out.status = IB_SUCCESS; + + AL_EXIT( AL_DBG_MAD ); + return CL_SUCCESS; +} + + + +/* + * UAL only uses reg_mad_pool/dereg_mad_pool ioctls + * create/destroy mad pool is implicit in these ioctls + */ +static +cl_status_t +proxy_reg_mad_pool( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_reg_mad_pool_ioctl_t *p_ioctl = + (ual_reg_mad_pool_ioctl_t *)cl_ioctl_in_buf( h_ioctl ); + al_dev_open_context_t *p_context = + (al_dev_open_context_t *)p_open_context; + ib_pd_handle_t h_pd; + ib_pool_key_t pool_key; + + AL_ENTER( AL_DBG_MAD ); + + /* Validate input buffers. */ + if( !cl_ioctl_in_buf( h_ioctl ) || !cl_ioctl_out_buf( h_ioctl ) || + cl_ioctl_in_size( h_ioctl ) != sizeof(p_ioctl->in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(p_ioctl->out) ) + { + AL_EXIT( AL_DBG_MAD ); + return CL_INVALID_PARAMETER; + } + + /* Set the return bytes in all cases */ + *p_ret_bytes = sizeof(p_ioctl->out); + + /* Validate PD handle */ + h_pd = (ib_pd_handle_t) + al_hdl_ref( p_context->h_al, p_ioctl->in.h_pd, AL_OBJ_TYPE_H_PD ); + if( !h_pd ) + { + p_ioctl->out.status = IB_INVALID_PD_HANDLE; + p_ioctl->out.pool_key = AL_INVALID_HANDLE; + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PD_HANDLE\n") ); + return CL_SUCCESS; + } + + /* + * If we're in the kernel, we are using the global MAD pool. Other + * MAD pools remain entirely in user-mode. + */ + + /* Register the PD with the MAD pool to obtain a pool_key. */ + p_ioctl->out.status = reg_mad_pool( gh_mad_pool, h_pd, &pool_key ); + if( p_ioctl->out.status == IB_SUCCESS ) + { + /* Track the pool info with the process context. */ + p_ioctl->out.pool_key = pool_key->obj.hdl; + pool_key->obj.hdl_valid = TRUE; + deref_al_obj( &pool_key->obj ); + } + else + { + p_ioctl->out.pool_key = AL_INVALID_HANDLE; + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("reg_mad_pool returned %s.\n", + ib_get_err_str(p_ioctl->out.status)) ); + } + + deref_al_obj( &h_pd->obj ); + + AL_EXIT( AL_DBG_MAD ); + return CL_SUCCESS; +} + + + +/* + * Deregister the pool_key with the MAD pool. Destroy the MAD pool if we + * created one. + */ +static +cl_status_t +proxy_dereg_mad_pool( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_dereg_mad_pool_ioctl_t *p_ioctl = + (ual_dereg_mad_pool_ioctl_t *)cl_ioctl_in_buf( h_ioctl ); + al_dev_open_context_t *p_context = + (al_dev_open_context_t *)p_open_context; + ib_pool_key_t pool_key; + + AL_ENTER( AL_DBG_MAD ); + + /* Validate input buffers. */ + if( !cl_ioctl_in_buf( h_ioctl ) || !cl_ioctl_out_buf( h_ioctl ) || + cl_ioctl_in_size( h_ioctl ) != sizeof(p_ioctl->in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(p_ioctl->out) ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("IOCTL buffer is invalid\n") ); + return CL_INVALID_PARAMETER; + } + + /* Set the return bytes in all cases */ + *p_ret_bytes = sizeof(p_ioctl->out); + + /* Validate pool key */ + pool_key = (ib_pool_key_t)al_hdl_ref( + p_context->h_al, p_ioctl->in.pool_key, AL_OBJ_TYPE_H_POOL_KEY ); + if( !pool_key ) + { + p_ioctl->out.status = IB_INVALID_HANDLE; + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("User-mode provided pool key is invalid\n") ); + return CL_SUCCESS; + } + + /* We should only have alias pool keys exported to user-mode. */ + p_ioctl->out.status = dereg_mad_pool( pool_key, AL_KEY_ALIAS ); + if( p_ioctl->out.status != IB_SUCCESS ) + { + deref_al_obj( &pool_key->obj ); + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("dereg_mad_pool failed: %s\n", + ib_get_err_str( p_ioctl->out.status )) ); + } + + AL_EXIT( AL_DBG_MAD ); + return CL_SUCCESS; +} + + + +cl_status_t +proxy_cancel_mad( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_cancel_mad_ioctl_t *p_ioctl; + al_dev_open_context_t *p_context; + ib_mad_svc_handle_t h_mad_svc; + + AL_ENTER( AL_DBG_MAD ); + + /* Validate input buffers. */ + if( !cl_ioctl_in_buf( h_ioctl ) || !cl_ioctl_out_buf( h_ioctl ) || + cl_ioctl_in_size( h_ioctl ) != sizeof(p_ioctl->in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(p_ioctl->out) ) + { + AL_EXIT( AL_DBG_MAD ); + return CL_INVALID_PARAMETER; + } + + p_ioctl = (ual_cancel_mad_ioctl_t*)cl_ioctl_in_buf( h_ioctl ); + p_context = (al_dev_open_context_t*)p_open_context; + + /* Set the return bytes in all cases */ + *p_ret_bytes = sizeof(p_ioctl->out); + + /* Validate MAD service handle. */ + h_mad_svc = (ib_mad_svc_handle_t)al_hdl_ref( + p_context->h_al, p_ioctl->in.h_mad_svc, AL_OBJ_TYPE_H_MAD_SVC ); + if( !h_mad_svc ) + { + p_ioctl->out.status = IB_INVALID_HANDLE; + AL_EXIT( AL_DBG_MAD ); + return CL_SUCCESS; + } + + p_ioctl->out.status = ib_cancel_mad( h_mad_svc, + (ib_mad_element_t*)(ULONG_PTR)p_ioctl->in.h_proxy_element ); + + /* + * The clean up of resources allocated for the sent mad will + * be handled in the send completion callback + */ + AL_EXIT( AL_DBG_MAD ); + return CL_SUCCESS; +} + + +/* + * Process the ioctl UAL_LOCAL_MAD: + */ +static cl_status_t +proxy_local_mad( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_local_mad_ioctl_t *p_ioctl = + (ual_local_mad_ioctl_t *)cl_ioctl_in_buf( h_ioctl ); + al_dev_open_context_t *p_context = + (al_dev_open_context_t *)p_open_context; + ib_ca_handle_t h_ca; + ib_api_status_t status; + + AL_ENTER( AL_DBG_MAD ); + + /* Validate input buffers. */ + if( !cl_ioctl_in_buf( h_ioctl ) || !cl_ioctl_out_buf( h_ioctl ) || + cl_ioctl_in_size( h_ioctl ) != sizeof(p_ioctl->in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(p_ioctl->out) ) + { + AL_EXIT( AL_DBG_MAD ); + return CL_INVALID_PARAMETER; + } + + if( ((ib_mad_t*)p_ioctl->in.mad_in)->method != IB_MAD_METHOD_GET ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("invalid method %d\n", ((ib_mad_t*)p_ioctl->in.mad_in)->method) ); + status = IB_UNSUPPORTED; + goto proxy_local_mad_err; + } + + /* Validate CA handle */ + h_ca = (ib_ca_handle_t) + al_hdl_ref( p_context->h_al, p_ioctl->in.h_ca, AL_OBJ_TYPE_H_CA ); + if( !h_ca ) + { + status = IB_INVALID_CA_HANDLE; + goto proxy_local_mad_err; + } + + /* Set the return bytes in all cases */ + *p_ret_bytes = sizeof(p_ioctl->out); + + status = ib_local_mad( + h_ca, p_ioctl->in.port_num, p_ioctl->in.mad_in, p_ioctl->out.mad_out ); + + deref_al_obj( &h_ca->obj ); + +proxy_local_mad_err: + p_ioctl->out.status = status; + + AL_EXIT( AL_DBG_MAD ); + return CL_SUCCESS; +} + + +cl_status_t +subnet_ioctl( + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + cl_status_t cl_status; + IO_STACK_LOCATION *p_io_stack; + void *p_context; + + AL_ENTER( AL_DBG_DEV ); + + CL_ASSERT( h_ioctl && p_ret_bytes ); + + p_io_stack = IoGetCurrentIrpStackLocation( h_ioctl ); + p_context = p_io_stack->FileObject->FsContext; + + if( !p_context ) + { + AL_EXIT( AL_DBG_DEV ); + return CL_INVALID_PARAMETER; + } + + switch( cl_ioctl_ctl_code( h_ioctl ) ) + { + case UAL_REG_SVC: + cl_status = proxy_reg_svc( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_SEND_SA_REQ: + cl_status = proxy_send_sa_req( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_CANCEL_SA_REQ: + cl_status = proxy_cancel_sa_req( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_MAD_SEND: + cl_status = proxy_send_mad( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_INIT_DGRM_SVC: + cl_status = proxy_init_dgrm( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_REG_MAD_SVC: + cl_status = proxy_reg_mad_svc( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_REG_MAD_POOL: + cl_status = proxy_reg_mad_pool( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_CANCEL_MAD: + cl_status = proxy_cancel_mad( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_MAD_RECV_COMP: + cl_status = proxy_mad_comp( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_DEREG_SVC: + cl_status = proxy_dereg_svc( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_DEREG_MAD_SVC: + cl_status = proxy_dereg_mad_svc( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_DEREG_MAD_POOL: + cl_status = proxy_dereg_mad_pool( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_LOCAL_MAD: + cl_status = proxy_local_mad( p_context, h_ioctl, p_ret_bytes ); + break; + default: + cl_status = CL_INVALID_PARAMETER; + break; + } + + return cl_status; +} diff --git a/branches/WOF2-3/core/al/kernel/al_proxy_verbs.c b/branches/WOF2-3/core/al/kernel/al_proxy_verbs.c new file mode 100644 index 00000000..a0178f77 --- /dev/null +++ b/branches/WOF2-3/core/al/kernel/al_proxy_verbs.c @@ -0,0 +1,3909 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include +#include +#include +#include "al.h" +#include "al_debug.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "al_proxy_verbs.tmh" +#endif + +#include "al_dev.h" +/* Get the internal definitions of apis for the proxy */ +#include "al_ca.h" +#include "al_pd.h" +#include "al_qp.h" +#include "al_srq.h" +#include "al_cq.h" +#include "al_mr.h" +#include "al_mw.h" +#include "al_av.h" +#include "al_ci_ca.h" +#include "al_mgr.h" +#include "ib_common.h" +#include "al_proxy.h" + + +extern al_mgr_t *gp_al_mgr; + + +/* + * + * Utility function to: + * a. allocate an umv_buf and p_buf in kernel space + * b. copy umv_buf and the contents of p_buf from user-mode + * + * It is assumed that the p_buf does not have any embedded user-mode pointers + */ + +ib_api_status_t +cpyin_umvbuf( + IN ci_umv_buf_t *p_src, + OUT ci_umv_buf_t **pp_dst ) +{ + size_t umv_buf_size; + ci_umv_buf_t *p_dest; + + /* Allocate space for umv_buf */ + CL_ASSERT( pp_dst ); + + umv_buf_size = sizeof(ci_umv_buf_t); + umv_buf_size += MAX(p_src->input_size, p_src->output_size); + + if( p_src->p_inout_buf ) + { + if( p_src->input_size && cl_check_for_read( + (void*)(ULONG_PTR)p_src->p_inout_buf, (size_t)p_src->input_size ) + != CL_SUCCESS ) + { + /* user-supplied memory area not readable */ + return IB_INVALID_PERMISSION; + } + if( p_src->output_size && cl_check_for_write( + (void*)(ULONG_PTR)p_src->p_inout_buf, (size_t)p_src->output_size ) + != CL_SUCCESS ) + { + /* user-supplied memory area not writeable */ + return IB_INVALID_PERMISSION; + } + } + p_dest = (ci_umv_buf_t*)cl_zalloc( (size_t)umv_buf_size ); + if( !p_dest ) + return IB_INSUFFICIENT_MEMORY; + + /* Copy the umv_buf structure. */ + *p_dest = *p_src; + if( p_src->p_inout_buf ) + p_dest->p_inout_buf = (ULONG_PTR)(p_dest + 1); + + /* Setup the buffer - either we have an input or output buffer */ + if( p_src->input_size ) + { + if( cl_copy_from_user( (void*)(ULONG_PTR)p_dest->p_inout_buf, + (void*)(ULONG_PTR)p_src->p_inout_buf, + (size_t)p_src->input_size ) != CL_SUCCESS ) + { + cl_free( p_dest ); + return IB_INVALID_PERMISSION; + } + } + *pp_dst = p_dest; + return IB_SUCCESS; +} + + + +/* + * + * Utility function to copy the results of umv_buf and the contents + * of p_buf to umv_buf in user-space. + * + * It is assumed that the p_buf does not have any embedded user-mode pointers + * + * This function can NOT be called from asynchronous callbacks where + * user process context may not be valid + * + */ +ib_api_status_t +cpyout_umvbuf( + IN ci_umv_buf_t *p_dest, + IN ci_umv_buf_t *p_src) +{ + CL_ASSERT( p_dest ); + + if( p_src ) + { + CL_ASSERT( p_dest->command == p_src->command ); + CL_ASSERT( p_dest->input_size == p_src->input_size ); + /* Copy output buf only on success. */ + if( p_src->status == IB_SUCCESS ) + { + uint32_t out_size; + + out_size = MIN( p_dest->output_size, p_src->output_size ); + + if( cl_copy_to_user( + (void*)(ULONG_PTR)p_dest->p_inout_buf, + (void*)(ULONG_PTR)p_src->p_inout_buf, + out_size ) != CL_SUCCESS ) + { + p_dest->output_size = 0; + return IB_INVALID_PERMISSION; + } + p_dest->status = p_src->status; + p_dest->output_size = out_size; + } + } + return IB_SUCCESS; +} + + +void +free_umvbuf( + IN ci_umv_buf_t *p_umv_buf ) +{ + if( p_umv_buf ) + cl_free( p_umv_buf ); +} + + + +/* + * Process the ioctl UAL_GET_VENDOR_LIBCFG: + */ +static cl_status_t +proxy_get_vendor_libcfg( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_get_uvp_name_ioctl_t *p_ioctl = + (ual_get_uvp_name_ioctl_t*)cl_ioctl_in_buf( h_ioctl ); + al_ci_ca_t *p_ci_ca; + + AL_ENTER( AL_DBG_CA ); + + UNUSED_PARAM( p_open_context ); + + /* Validate input buffers. */ + if( !cl_ioctl_in_buf( h_ioctl ) || !cl_ioctl_out_buf( h_ioctl ) || + cl_ioctl_in_size( h_ioctl ) != sizeof(p_ioctl->in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(p_ioctl->out) ) + { + AL_EXIT( AL_DBG_CA ); + return CL_INVALID_PARAMETER; + } + + /* Find the CAguid */ + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_CA, + ("CA guid %I64x.\n", p_ioctl->in.ca_guid) ); + + cl_spinlock_acquire( &gp_al_mgr->obj.lock ); + p_ci_ca = find_ci_ca( p_ioctl->in.ca_guid ); + + if( !p_ci_ca ) + { + cl_spinlock_release( &gp_al_mgr->obj.lock ); + p_ioctl->out.status = IB_NOT_FOUND; + } + else + { + /* found the ca guid, copy the user-mode verbs provider libname */ + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_CA, + ("CA guid %I64x. libname (%s)\n", + p_ioctl->in.ca_guid, p_ci_ca->verbs.libname) ); + cl_memcpy( p_ioctl->out.uvp_lib_name, p_ci_ca->verbs.libname, + sizeof(p_ci_ca->verbs.libname)); + cl_spinlock_release( &gp_al_mgr->obj.lock ); + p_ioctl->out.status = IB_SUCCESS; + } + *p_ret_bytes = sizeof(p_ioctl->out); + AL_EXIT( AL_DBG_CA ); + return CL_SUCCESS; +} + + +/* + * Allocate an ioctl buffer of appropriate size + * Copy the given ioctl buffer + * Queue the ioctl buffer as needed + */ +boolean_t +proxy_queue_cb_buf( + IN uintn_t cb_type, + IN al_dev_open_context_t *p_context, + IN void *p_cb_data, + IN al_obj_t *p_al_obj OPTIONAL ) +{ + cl_qlist_t *p_cb_list; + al_proxy_cb_info_t *p_cb_info; + cl_ioctl_handle_t h_ioctl; + al_csq_t *p_al_csq = &p_context->al_csq; + uintn_t ioctl_size; + + AL_ENTER( AL_DBG_DEV ); + + /* Set up the appropriate callback list. */ + switch( cb_type ) + { + case UAL_GET_COMP_CB_INFO: + p_cb_list = &p_context->comp_cb_list; + ioctl_size = sizeof( comp_cb_ioctl_info_t ); + break; + + case UAL_GET_MISC_CB_INFO: + p_cb_list = &p_context->misc_cb_list; + ioctl_size = sizeof( misc_cb_ioctl_info_t ); + break; + + default: + return FALSE; + } + + /* Get a callback record to queue the callback. */ + p_cb_info = proxy_cb_get( p_context ); + if( !p_cb_info ) + return FALSE; + + cl_memcpy( &p_cb_info->cb_type, p_cb_data, ioctl_size ); + + /* + * If an AL object was specified, we need to reference it to prevent its + * destruction until the callback has been fully specified. + */ + if( p_al_obj ) + { + p_cb_info->p_al_obj = p_al_obj; + ref_al_obj( p_al_obj ); + } + + /* Insert the callback record into the callback list */ + cl_spinlock_acquire( &p_context->cb_lock ); + cl_qlist_insert_tail( p_cb_list, &p_cb_info->pool_item.list_item ); + + /* remove ioctl from the cancel-safe queue (it makes it unpending) */ + h_ioctl = IoCsqRemoveNextIrp( (PIO_CSQ)p_al_csq, (PVOID)(ULONG_PTR)cb_type ); + if (h_ioctl) + { + p_cb_info->reported = TRUE; + /* Complete the IOCTL to return the callback information. */ + CL_ASSERT( cl_ioctl_out_size( h_ioctl ) >= ioctl_size ); + cl_memcpy( cl_ioctl_out_buf( h_ioctl ), p_cb_data, ioctl_size ); + cl_ioctl_complete( h_ioctl, CL_SUCCESS, ioctl_size ); + proxy_context_deref( p_context ); + } + cl_spinlock_release( &p_context->cb_lock ); + + AL_EXIT( AL_DBG_DEV ); + return TRUE; +} + + +/* + * Proxy's ca error callback + * The context in the error record is proxy's ca context + * Context is the a list object in the CA list + */ +static void +proxy_ca_err_cb( + IN ib_async_event_rec_t *p_err_rec) +{ + ib_ca_handle_t h_ca = p_err_rec->handle.h_ca; + al_dev_open_context_t *p_context = h_ca->obj.h_al->p_context; + misc_cb_ioctl_info_t cb_info; + + /* + * If we're already closing the device - do not queue a callback, since + * we're cleaning up the callback lists. + */ + if( !proxy_context_ref( p_context ) ) + { + proxy_context_deref( p_context ); + return; + } + + /* Set up context and callback record type appropriate for UAL */ + cb_info.rec_type = CA_ERROR_REC; + /* Return the Proxy's open_ca handle and the user's context */ + cb_info.ioctl_rec.event_rec = *p_err_rec; + cb_info.ioctl_rec.event_rec.handle.h_ca_padding = h_ca->obj.hdl; + + /* The proxy handle must be valid now. */ + if( !h_ca->obj.hdl_valid ) + h_ca->obj.hdl_valid = TRUE; + + proxy_queue_cb_buf( UAL_GET_MISC_CB_INFO, p_context, &cb_info, + &h_ca->obj ); + + proxy_context_deref( p_context ); +} + + +/* + * Process the ioctl UAL_OPEN_CA: + * + * Returns the ca_list_obj as the handle to UAL + */ +static cl_status_t +proxy_open_ca( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_open_ca_ioctl_t *p_ioctl = + (ual_open_ca_ioctl_t *)cl_ioctl_in_buf( h_ioctl ); + al_dev_open_context_t *p_context = + (al_dev_open_context_t *)p_open_context; + ib_ca_handle_t h_ca; + ci_umv_buf_t *p_umv_buf = NULL; + ib_api_status_t status; + + AL_ENTER( AL_DBG_CA ); + + /* Validate input buffers. */ + if( !cl_ioctl_in_buf( h_ioctl ) || !cl_ioctl_out_buf( h_ioctl ) || + cl_ioctl_in_size( h_ioctl ) != sizeof(p_ioctl->in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(p_ioctl->out) ) + { + AL_EXIT( AL_DBG_CA ); + return CL_INVALID_PARAMETER; + } + + /* Set the return bytes in all cases. */ + *p_ret_bytes = sizeof(p_ioctl->out); + + status = cpyin_umvbuf( &p_ioctl->in.umv_buf, &p_umv_buf ); + if( status != IB_SUCCESS ) + goto proxy_open_ca_err; + + status = open_ca( p_context->h_al, p_ioctl->in.guid, proxy_ca_err_cb, + (void*)(ULONG_PTR)p_ioctl->in.context, &h_ca, p_umv_buf ); + if( status != IB_SUCCESS ) + goto proxy_open_ca_err; + + status = cpyout_umvbuf( &p_ioctl->out.umv_buf, p_umv_buf ); + if( status == IB_SUCCESS ) + { + p_ioctl->out.h_ca = h_ca->obj.hdl; + h_ca->obj.hdl_valid = TRUE; + /* Release the reference taken in init_al_obj */ + deref_al_obj( &h_ca->obj ); + } + else + { + h_ca->obj.pfn_destroy( &h_ca->obj, NULL ); + +proxy_open_ca_err: /* getting a handle failed. */ + p_ioctl->out.umv_buf = p_ioctl->in.umv_buf; + p_ioctl->out.h_ca = AL_INVALID_HANDLE; + } + free_umvbuf( p_umv_buf ); + + p_ioctl->out.status = status; + + AL_EXIT( AL_DBG_CA ); + return CL_SUCCESS; +} + + + +/* + * Process the ioctl UAL_QUERY_CA: + */ +static cl_status_t +proxy_query_ca( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_query_ca_ioctl_t *p_ioctl = + (ual_query_ca_ioctl_t *)cl_ioctl_in_buf( h_ioctl ); + al_dev_open_context_t *p_context = + (al_dev_open_context_t *)p_open_context; + ib_ca_handle_t h_ca; + ib_ca_attr_t *p_ca_attr = NULL; + ci_umv_buf_t *p_umv_buf = NULL; + ib_api_status_t status; + uint32_t byte_cnt = 0; + + AL_ENTER( AL_DBG_CA ); + + /* Validate input buffers. */ + if( !cl_ioctl_in_buf( h_ioctl ) || !cl_ioctl_out_buf( h_ioctl ) || + cl_ioctl_in_size( h_ioctl ) != sizeof(p_ioctl->in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(p_ioctl->out) ) + { + AL_EXIT( AL_DBG_CA ); + return CL_INVALID_PARAMETER; + } + + /* Set the return bytes in all cases */ + *p_ret_bytes = sizeof(p_ioctl->out); + + /* Validate CA handle */ + h_ca = (ib_ca_handle_t) + al_hdl_ref( p_context->h_al, p_ioctl->in.h_ca, AL_OBJ_TYPE_H_CA ); + if( !h_ca ) + { + status = IB_INVALID_CA_HANDLE; + goto proxy_query_ca_err; + } + + status = cpyin_umvbuf( &p_ioctl->in.umv_buf, &p_umv_buf ); + if( status != IB_SUCCESS ) + goto proxy_query_ca_err; + + byte_cnt = p_ioctl->in.byte_cnt; + if( p_ioctl->in.p_ca_attr && byte_cnt ) + { + p_ca_attr = (ib_ca_attr_t*)cl_zalloc( byte_cnt ); + if( !p_ca_attr ) + { + status = IB_INSUFFICIENT_MEMORY; + goto proxy_query_ca_err; + } + } + status = query_ca( h_ca, p_ca_attr, &byte_cnt, p_umv_buf ); + + if( status != IB_SUCCESS ) + goto proxy_query_ca_err; + + status = cpyout_umvbuf( &p_ioctl->out.umv_buf, p_umv_buf ); + + if( status != IB_SUCCESS ) + goto proxy_query_ca_err; + + /* copy CA attribute back to user */ + if( p_ca_attr ) + { + __try + { + ProbeForWrite( (void*)(ULONG_PTR)p_ioctl->in.p_ca_attr, + byte_cnt, sizeof(void*) ); + ib_copy_ca_attr( (void*)(ULONG_PTR)p_ioctl->in.p_ca_attr, + p_ca_attr ); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("Failed to copy CA attributes to user buffer %016I64x\n", + p_ioctl->in.p_ca_attr) ); + status = IB_INVALID_PERMISSION; + } + } + + /* Free the ca_attr buffer allocated locally */ + if( status != IB_SUCCESS ) + { +proxy_query_ca_err: + p_ioctl->out.umv_buf = p_ioctl->in.umv_buf; + } + if( p_ca_attr ) + cl_free( p_ca_attr ); + + free_umvbuf( p_umv_buf ); + + if( h_ca ) + deref_al_obj( &h_ca->obj ); + + p_ioctl->out.status = status; + p_ioctl->out.byte_cnt = byte_cnt; + + AL_EXIT( AL_DBG_CA ); + return CL_SUCCESS; +} + + +/* + * Process the ioctl UAL_MODIFY_CA: + */ +static +cl_status_t +proxy_modify_ca( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_modify_ca_ioctl_t *p_ioctl = + (ual_modify_ca_ioctl_t *)cl_ioctl_in_buf( h_ioctl ); + al_dev_open_context_t *p_context = + (al_dev_open_context_t *)p_open_context; + ib_ca_handle_t h_ca; + + AL_ENTER( AL_DBG_CA ); + + /* Validate input buffers. */ + if( !cl_ioctl_in_buf( h_ioctl ) || !cl_ioctl_out_buf( h_ioctl ) || + cl_ioctl_in_size( h_ioctl ) != sizeof(p_ioctl->in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(p_ioctl->out) ) + { + AL_EXIT( AL_DBG_CA ); + return CL_INVALID_PARAMETER; + } + + /* Set the return bytes in all cases */ + *p_ret_bytes = sizeof(p_ioctl->out); + + /* Validate CA handle */ + h_ca = (ib_ca_handle_t) + al_hdl_ref( p_context->h_al, p_ioctl->in.h_ca, AL_OBJ_TYPE_H_CA ); + if( !h_ca ) + { + p_ioctl->out.status = IB_INVALID_CA_HANDLE; + AL_EXIT( AL_DBG_CA ); + return CL_SUCCESS; + } + + p_ioctl->out.status = ib_modify_ca( h_ca, p_ioctl->in.port_num, + p_ioctl->in.ca_mod, &p_ioctl->in.port_attr_mod ); + + deref_al_obj( &h_ca->obj ); + + AL_EXIT( AL_DBG_CA ); + return CL_SUCCESS; +} + + +/* + * Process the ioctl UAL_CLOSE_CA: + */ +static +cl_status_t +proxy_close_ca( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_close_ca_ioctl_t *p_ioctl = + (ual_close_ca_ioctl_t *)cl_ioctl_in_buf( h_ioctl ); + al_dev_open_context_t *p_context = + (al_dev_open_context_t *)p_open_context; + ib_ca_handle_t h_ca; + + AL_ENTER( AL_DBG_CA ); + + /* Validate input buffers. */ + if( !cl_ioctl_in_buf( h_ioctl ) || !cl_ioctl_out_buf( h_ioctl ) || + cl_ioctl_in_size( h_ioctl ) != sizeof(p_ioctl->in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(p_ioctl->out) ) + { + AL_EXIT( AL_DBG_CA ); + return CL_INVALID_PARAMETER; + } + + /* Set the return bytes in all cases */ + *p_ret_bytes = sizeof(p_ioctl->out); + + /* Validate CA handle */ + h_ca = (ib_ca_handle_t) + al_hdl_ref( p_context->h_al, p_ioctl->in.h_ca, AL_OBJ_TYPE_H_CA ); + if( !h_ca ) + { + p_ioctl->out.status = IB_INVALID_CA_HANDLE; + AL_EXIT( AL_DBG_CA ); + return CL_SUCCESS; + } + + /* + * Note that we hold a reference on the CA, so we need to + * call close_ca, not ib_close_ca. We also don't release the reference + * since close_ca will do so (by destroying the object). + */ + h_ca->obj.pfn_destroy( &h_ca->obj, ib_sync_destroy ); + p_ioctl->out.status = IB_SUCCESS; + + AL_EXIT( AL_DBG_CA ); + return CL_SUCCESS; +} + + +/* + * Validates the proxy handles and converts them to AL handles + */ +static ib_api_status_t +__convert_to_al_handles( + IN al_dev_open_context_t* const p_context, + IN uint64_t* const um_handle_array, + IN uint32_t num_handles, + OUT void** const p_handle_array ) +{ + uint32_t i; + + for( i = 0; i < num_handles; i++ ) + { + /* Validate the handle in the resource map */ + p_handle_array[i] = al_hdl_ref( + p_context->h_al, um_handle_array[i], AL_OBJ_TYPE_UNKNOWN ); + if( !p_handle_array[i] ) + { + /* Release references taken so far. */ + while( i-- ) + deref_al_obj( p_handle_array[i] ); + + /* Could not find the handle in the map */ + return IB_INVALID_HANDLE; + } + } + + return IB_SUCCESS; +} + + + +static +cl_status_t +proxy_ci_call( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_ci_call_ioctl_t *p_ioctl = + (ual_ci_call_ioctl_t *)cl_ioctl_in_buf( h_ioctl ); + al_dev_open_context_t *p_context = + (al_dev_open_context_t *)p_open_context; + ib_ca_handle_t h_ca; + ci_umv_buf_t *p_umv_buf = NULL; + void* p_ci_op_buf = NULL; + void* p_ci_op_user_buf = NULL; + void** p_handle_array = NULL; + size_t ci_op_buf_size; + ib_api_status_t status; + uint32_t num_handles; + + AL_ENTER( AL_DBG_CA ); + + /* Validate input buffers. */ + if( !cl_ioctl_in_buf( h_ioctl ) || !cl_ioctl_out_buf( h_ioctl ) || + cl_ioctl_in_size( h_ioctl ) < sizeof(p_ioctl->in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(p_ioctl->out) ) + { + AL_EXIT( AL_DBG_CA ); + return CL_INVALID_PARAMETER; + } + + num_handles = p_ioctl->in.num_handles; + if( num_handles > 1 && + cl_ioctl_in_size( h_ioctl ) != (sizeof(uint64_t) * (num_handles - 1)) ) + { + AL_EXIT( AL_DBG_CA ); + return CL_INVALID_PARAMETER; + } + + ci_op_buf_size = (size_t)p_ioctl->in.ci_op.buf_size; + + /* Set the return bytes in all cases */ + *p_ret_bytes = sizeof(p_ioctl->out); + + /* Validate CA handle */ + h_ca = (ib_ca_handle_t) + al_hdl_ref( p_context->h_al, p_ioctl->in.h_ca, AL_OBJ_TYPE_H_CA ); + if( !h_ca ) + { + p_ioctl->out.status = IB_INVALID_CA_HANDLE; + AL_EXIT( AL_DBG_CA ); + return CL_SUCCESS; + } + + /* Save the user buffer address */ + p_ci_op_user_buf = p_ioctl->in.ci_op.p_buf; + + /* Validate the handle array */ + if( num_handles ) + { + p_handle_array = cl_malloc( sizeof(void*) * num_handles ); + if( !p_handle_array ) + { + p_ioctl->out.status = IB_INSUFFICIENT_MEMORY; + deref_al_obj( &h_ca->obj ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("Failed to allocate handle array.\n") ); + return CL_SUCCESS; + } + + /* + * Now we have the handle array in kernel space. Replace + * the handles with the correct AL handles based on the + * type + */ + status = __convert_to_al_handles( p_context, p_ioctl->in.handle_array, + num_handles, p_handle_array ); + if( status != IB_SUCCESS ) + { + cl_free( p_handle_array ); + p_ioctl->out.status = status; + deref_al_obj( &h_ca->obj ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("Failed to convert handles.\n") ); + return CL_SUCCESS; + } + } + + /* Copy in the UMV buffer */ + status = cpyin_umvbuf( &p_ioctl->in.umv_buf, &p_umv_buf ); + if( status != IB_SUCCESS ) + goto proxy_ci_call_err; + + if( p_ioctl->in.ci_op.buf_size && p_ioctl->in.ci_op.p_buf ) + { + p_ci_op_buf = cl_zalloc( ci_op_buf_size ); + if( !p_ci_op_buf ) + { + status = IB_INSUFFICIENT_MEMORY; + goto proxy_ci_call_err; + } + + /* Copy from user the buffer */ + if( cl_copy_from_user( p_ci_op_buf, p_ioctl->in.ci_op.p_buf, + ci_op_buf_size ) != CL_SUCCESS ) + { + status = IB_INVALID_PERMISSION; + goto proxy_ci_call_err; + } + /* Update the buffer pointer to reference the kernel copy. */ + p_ioctl->in.ci_op.p_buf = p_ci_op_buf; + } + + status = ci_call( h_ca, p_handle_array, + num_handles, &p_ioctl->in.ci_op, p_umv_buf ); + if( status != IB_SUCCESS ) + goto proxy_ci_call_err; + + /* Copy the umv_buf back to user space */ + status = cpyout_umvbuf( &p_ioctl->out.umv_buf, p_umv_buf ); + if( status != IB_SUCCESS ) + { + status = IB_INVALID_PERMISSION; + goto proxy_ci_call_err; + } + + /* + * Copy the data buffer. Copy the buf size so that if the + * num_bytes_ret is greater than the buffer size, we copy + * only what the buffer can hold + */ + if( cl_copy_to_user( p_ci_op_user_buf, p_ioctl->in.ci_op.p_buf, + ci_op_buf_size ) != CL_SUCCESS ) + { + status = IB_INVALID_PERMISSION; + } + +proxy_ci_call_err: + + /* Restore the data buffer */ + p_ioctl->out.ci_op.p_buf = p_ci_op_user_buf; + p_ioctl->out.status = status; + + /* Release the resources allocated */ + if( p_handle_array ) + { + while( num_handles-- ) + deref_al_obj( (al_obj_t*)p_handle_array[num_handles] ); + cl_free( p_handle_array ); + } + if( p_ci_op_buf ) + cl_free( p_ci_op_buf ); + + free_umvbuf( p_umv_buf ); + + deref_al_obj( &h_ca->obj ); + + AL_EXIT( AL_DBG_CA ); + return CL_SUCCESS; +} + + +/* + * Process the ioctl UAL_ALLOC_PD: + * + * Returns the pd_list_obj as the handle to UAL + */ +static +cl_status_t +proxy_alloc_pd( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_alloc_pd_ioctl_t *p_ioctl = + (ual_alloc_pd_ioctl_t *)cl_ioctl_in_buf( h_ioctl ); + al_dev_open_context_t *p_context = + (al_dev_open_context_t *)p_open_context; + ib_ca_handle_t h_ca; + ib_pd_handle_t h_pd; + ci_umv_buf_t *p_umv_buf = NULL; + ib_api_status_t status; + + AL_ENTER( AL_DBG_PD ); + + /* Validate input buffers. */ + if( !cl_ioctl_in_buf( h_ioctl ) || !cl_ioctl_out_buf( h_ioctl ) || + cl_ioctl_in_size( h_ioctl ) != sizeof(p_ioctl->in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(p_ioctl->out) ) + { + AL_EXIT( AL_DBG_PD ); + return CL_INVALID_PARAMETER; + } + + /* Validate CA handle */ + h_ca = (ib_ca_handle_t) + al_hdl_ref( p_context->h_al, p_ioctl->in.h_ca, AL_OBJ_TYPE_H_CA ); + if( !h_ca ) + { + status = IB_INVALID_CA_HANDLE; + goto proxy_alloc_pd_err; + } + + status = cpyin_umvbuf( &p_ioctl->in.umv_buf, &p_umv_buf ); + if( status != IB_SUCCESS ) + goto proxy_alloc_pd_err; + + status = alloc_pd( h_ca, p_ioctl->in.type, + (void*)(ULONG_PTR)p_ioctl->in.context, &h_pd, p_umv_buf ); + + if( status != IB_SUCCESS ) + goto proxy_alloc_pd_err; + + status = cpyout_umvbuf( &p_ioctl->out.umv_buf, p_umv_buf ); + if( status == IB_SUCCESS ) + { + p_ioctl->out.h_pd = h_pd->obj.hdl; + h_pd->obj.hdl_valid = TRUE; + deref_al_obj( &h_pd->obj ); + } + else + { + h_pd->obj.pfn_destroy( &h_pd->obj, NULL ); + +proxy_alloc_pd_err: + p_ioctl->out.umv_buf = p_ioctl->in.umv_buf; + p_ioctl->out.h_pd = AL_INVALID_HANDLE; + } + free_umvbuf( p_umv_buf ); + + if( h_ca ) + deref_al_obj( &h_ca->obj ); + + p_ioctl->out.status = status; + *p_ret_bytes = sizeof(p_ioctl->out); + + AL_EXIT( AL_DBG_PD ); + return CL_SUCCESS; +} + + +/* + * Process the ioctl UAL_DEALLOC_PD: + */ +static cl_status_t +proxy_dealloc_pd( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_dealloc_pd_ioctl_t *p_ioctl = + (ual_dealloc_pd_ioctl_t *)cl_ioctl_in_buf( h_ioctl ); + al_dev_open_context_t *p_context = + (al_dev_open_context_t *)p_open_context; + ib_pd_handle_t h_pd; + + AL_ENTER( AL_DBG_PD ); + + /* Validate input buffers. */ + if( !cl_ioctl_in_buf( h_ioctl ) || !cl_ioctl_out_buf( h_ioctl ) || + cl_ioctl_in_size( h_ioctl ) != sizeof(p_ioctl->in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(p_ioctl->out) ) + { + AL_EXIT( AL_DBG_PD ); + return CL_INVALID_PARAMETER; + } + + /* Set the return bytes in all cases */ + *p_ret_bytes = sizeof(p_ioctl->out); + + /* Validate PD handle */ + h_pd = (ib_pd_handle_t)al_hdl_ref( + p_context->h_al, p_ioctl->in.h_pd, AL_OBJ_TYPE_H_PD ); + if( !h_pd ) + { + p_ioctl->out.status = IB_INVALID_PD_HANDLE; + AL_EXIT( AL_DBG_PD ); + return CL_SUCCESS; + } + + h_pd->obj.pfn_destroy( &h_pd->obj, ib_sync_destroy ); + p_ioctl->out.status = IB_SUCCESS; + + AL_EXIT( AL_DBG_PD ); + return CL_SUCCESS; +} + + +/* + * Proxy's SRQ error handler + */ +static void +proxy_srq_err_cb( + IN ib_async_event_rec_t *p_err_rec ) +{ + ib_srq_handle_t h_srq = p_err_rec->handle.h_srq; + al_dev_open_context_t *p_context = h_srq->obj.h_al->p_context; + misc_cb_ioctl_info_t cb_info; + + AL_ENTER( AL_DBG_QP ); + + /* + * If we're already closing the device - do not queue a callback, since + * we're cleaning up the callback lists. + */ + if( !proxy_context_ref( p_context ) ) + { + proxy_context_deref( p_context ); + return; + } + + /* Set up context and callback record type appropriate for UAL */ + cb_info.rec_type = SRQ_ERROR_REC; + /* Return the Proxy's SRQ handle and the user's context */ + cb_info.ioctl_rec.event_rec = *p_err_rec; + cb_info.ioctl_rec.event_rec.handle.h_srq_padding = h_srq->obj.hdl; + + /* The proxy handle must be valid now. */ + if( !h_srq->obj.hdl_valid ) + h_srq->obj.hdl_valid = TRUE; + + proxy_queue_cb_buf( + UAL_GET_MISC_CB_INFO, p_context, &cb_info, &h_srq->obj ); + + proxy_context_deref( p_context ); + + AL_EXIT( AL_DBG_QP ); +} + +/* + * Process the ioctl UAL_CREATE_SRQ + * + * Returns the srq_list_obj as the handle to UAL + */ +static cl_status_t +proxy_create_srq( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_create_srq_ioctl_t *p_ioctl = + (ual_create_srq_ioctl_t*)cl_ioctl_in_buf( h_ioctl ); + al_dev_open_context_t *p_context = + (al_dev_open_context_t *)p_open_context; + ib_pd_handle_t h_pd; + ib_srq_handle_t h_srq; + ci_umv_buf_t *p_umv_buf = NULL; + ib_api_status_t status; + ib_pfn_event_cb_t pfn_ev; + + AL_ENTER( AL_DBG_SRQ ); + + /* Validate input buffers. */ + if( !cl_ioctl_in_buf( h_ioctl ) || !cl_ioctl_out_buf( h_ioctl ) || + cl_ioctl_in_size( h_ioctl ) != sizeof(p_ioctl->in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(p_ioctl->out) ) + { + AL_EXIT( AL_DBG_SRQ ); + return CL_INVALID_PARAMETER; + } + + /* Validate handles. */ + h_pd = (ib_pd_handle_t) + al_hdl_ref( p_context->h_al, p_ioctl->in.h_pd, AL_OBJ_TYPE_H_PD ); + if( !h_pd) + { + status = IB_INVALID_PD_HANDLE; + goto proxy_create_srq_err1; + } + + status = cpyin_umvbuf( &p_ioctl->in.umv_buf, &p_umv_buf ); + if( status != IB_SUCCESS ) + goto proxy_create_srq_err1; + + if( p_ioctl->in.ev_notify ) + pfn_ev = proxy_srq_err_cb; + else + pfn_ev = NULL; + + status = create_srq( h_pd, &p_ioctl->in.srq_attr, + (void*)(ULONG_PTR)p_ioctl->in.context, pfn_ev, &h_srq, p_umv_buf ); + if( status != IB_SUCCESS ) + goto proxy_create_srq_err1; + + status = cpyout_umvbuf( &p_ioctl->out.umv_buf, p_umv_buf ); + if( status == IB_SUCCESS ) + { + p_ioctl->out.h_srq = h_srq->obj.hdl; + h_srq->obj.hdl_valid = TRUE; + /* Release the reference taken in create_srq (by init_al_obj) */ + deref_al_obj( &h_srq->obj ); + } + else + { +proxy_create_srq_err1: + p_ioctl->out.umv_buf = p_ioctl->in.umv_buf; + p_ioctl->out.h_srq = AL_INVALID_HANDLE; + } + free_umvbuf( p_umv_buf ); + + p_ioctl->out.status = status; + *p_ret_bytes = sizeof(p_ioctl->out); + + if( h_pd ) + deref_al_obj( &h_pd->obj ); + + AL_EXIT( AL_DBG_SRQ ); + return CL_SUCCESS; +} + + +/* + * Process the ioctl UAL_QUERY_SRQ: + */ +static +cl_status_t +proxy_query_srq( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_query_srq_ioctl_t *p_ioctl = + (ual_query_srq_ioctl_t *)cl_ioctl_in_buf( h_ioctl ); + al_dev_open_context_t *p_context = + (al_dev_open_context_t *)p_open_context; + ib_srq_handle_t h_srq; + ci_umv_buf_t *p_umv_buf = NULL; + ib_api_status_t status; + + AL_ENTER( AL_DBG_SRQ ); + + /* Validate input buffers. */ + if( !cl_ioctl_in_buf( h_ioctl ) || !cl_ioctl_out_buf( h_ioctl ) || + cl_ioctl_in_size( h_ioctl ) != sizeof(p_ioctl->in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(p_ioctl->out) ) + { + AL_EXIT( AL_DBG_SRQ ); + return CL_INVALID_PARAMETER; + } + + /* Validate SRQ handle */ + h_srq = (ib_srq_handle_t) + al_hdl_ref( p_context->h_al, p_ioctl->in.h_srq, AL_OBJ_TYPE_H_SRQ ); + if( !h_srq ) + { + status = IB_INVALID_SRQ_HANDLE; + goto proxy_query_srq_err; + } + + status = cpyin_umvbuf( &p_ioctl->in.umv_buf, &p_umv_buf ); + if( status != IB_SUCCESS ) + goto proxy_query_srq_err; + + status = query_srq( h_srq, &p_ioctl->out.srq_attr, p_umv_buf ); + if( status != IB_SUCCESS ) + goto proxy_query_srq_err; + + status = cpyout_umvbuf( &p_ioctl->out.umv_buf, p_umv_buf ); + if( status != IB_SUCCESS ) + { +proxy_query_srq_err: + p_ioctl->out.umv_buf = p_ioctl->in.umv_buf; + cl_memclr( &p_ioctl->out.srq_attr, sizeof(ib_srq_attr_t) ); + } + free_umvbuf( p_umv_buf ); + + if( h_srq ) + deref_al_obj( &h_srq->obj ); + + p_ioctl->out.status = status; + *p_ret_bytes = sizeof(p_ioctl->out); + + AL_EXIT( AL_DBG_SRQ ); + return CL_SUCCESS; +} + + + +/* + * Process the ioctl UAL_MODIFY_SRQ: + */ +static +cl_status_t +proxy_modify_srq( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_modify_srq_ioctl_t *p_ioctl = + (ual_modify_srq_ioctl_t *)cl_ioctl_in_buf( h_ioctl ); + al_dev_open_context_t *p_context = + (al_dev_open_context_t *)p_open_context; + ib_srq_handle_t h_srq; + ci_umv_buf_t *p_umv_buf = NULL; + ib_api_status_t status; + + AL_ENTER( AL_DBG_SRQ ); + + /* Validate input buffers. */ + if( !cl_ioctl_in_buf( h_ioctl ) || !cl_ioctl_out_buf( h_ioctl ) || + cl_ioctl_in_size( h_ioctl ) != sizeof(p_ioctl->in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(p_ioctl->out) ) + { + AL_EXIT( AL_DBG_SRQ ); + return CL_INVALID_PARAMETER; + } + + /* Validate SRQ handle */ + h_srq = (ib_srq_handle_t) + al_hdl_ref( p_context->h_al, p_ioctl->in.h_srq, AL_OBJ_TYPE_H_SRQ ); + if( !h_srq ) + { + status = IB_INVALID_SRQ_HANDLE; + goto proxy_modify_srq_err; + } + + status = cpyin_umvbuf( &p_ioctl->in.umv_buf, &p_umv_buf ); + if( status != IB_SUCCESS ) + goto proxy_modify_srq_err; + + status = modify_srq( h_srq, &p_ioctl->in.srq_attr, p_ioctl->in.srq_attr_mask, p_umv_buf ); + + if( status != IB_SUCCESS ) + goto proxy_modify_srq_err; + + status = cpyout_umvbuf( &p_ioctl->out.umv_buf, p_umv_buf ); + if( status != IB_SUCCESS ) + { +proxy_modify_srq_err: + p_ioctl->out.umv_buf = p_ioctl->in.umv_buf; + } + free_umvbuf( p_umv_buf ); + + if( h_srq ) + deref_al_obj( &h_srq->obj ); + + p_ioctl->out.status = status; + *p_ret_bytes = sizeof(p_ioctl->out); + + AL_EXIT( AL_DBG_SRQ ); + return CL_SUCCESS; +} + + +/* + * Process the ioctl UAL_DESTROY_SRQ + */ +static cl_status_t +proxy_destroy_srq( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_destroy_srq_ioctl_t *p_ioctl = + (ual_destroy_srq_ioctl_t *)cl_ioctl_in_buf( h_ioctl ); + al_dev_open_context_t *p_context = + (al_dev_open_context_t *)p_open_context; + ib_srq_handle_t h_srq; + + AL_ENTER( AL_DBG_SRQ ); + + /* Validate input buffers. */ + if( !cl_ioctl_in_buf( h_ioctl ) || !cl_ioctl_out_buf( h_ioctl ) || + cl_ioctl_in_size( h_ioctl ) != sizeof(p_ioctl->in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(p_ioctl->out) ) + { + AL_EXIT( AL_DBG_SRQ ); + return CL_INVALID_PARAMETER; + } + + /* Set the return bytes in all cases */ + *p_ret_bytes = sizeof(p_ioctl->out); + + /* Validate SRQ handle */ + h_srq = (ib_srq_handle_t) + al_hdl_ref( p_context->h_al, p_ioctl->in.h_srq, AL_OBJ_TYPE_H_SRQ ); + if( !h_srq ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_SRQ_HANDLE\n") ); + p_ioctl->out.status = IB_INVALID_SRQ_HANDLE; + } + else + { + h_srq->obj.pfn_destroy( &h_srq->obj, ib_sync_destroy ); + p_ioctl->out.status = IB_SUCCESS; + } + + AL_EXIT( AL_DBG_SRQ ); + return CL_SUCCESS; +} + + +/* + * Proxy's QP error handler + */ +static void +proxy_qp_err_cb( + IN ib_async_event_rec_t *p_err_rec ) +{ + ib_qp_handle_t h_qp = p_err_rec->handle.h_qp; + al_dev_open_context_t *p_context = h_qp->obj.h_al->p_context; + misc_cb_ioctl_info_t cb_info; + + AL_ENTER( AL_DBG_QP ); + + /* + * If we're already closing the device - do not queue a callback, since + * we're cleaning up the callback lists. + */ + if( !proxy_context_ref( p_context ) ) + { + proxy_context_deref( p_context ); + return; + } + + /* Set up context and callback record type appropriate for UAL */ + cb_info.rec_type = QP_ERROR_REC; + /* Return the Proxy's QP handle and the user's context */ + cb_info.ioctl_rec.event_rec = *p_err_rec; + cb_info.ioctl_rec.event_rec.handle.h_qp_padding = h_qp->obj.hdl; + + /* The proxy handle must be valid now. */ + if( !h_qp->obj.hdl_valid ) + h_qp->obj.hdl_valid = TRUE; + + proxy_queue_cb_buf( + UAL_GET_MISC_CB_INFO, p_context, &cb_info, &h_qp->obj ); + + proxy_context_deref( p_context ); + + AL_EXIT( AL_DBG_QP ); +} + + + +/* + * Process the ioctl UAL_CREATE_QP + * + * Returns the qp_list_obj as the handle to UAL + */ +static cl_status_t +proxy_create_qp( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_create_qp_ioctl_t *p_ioctl = + (ual_create_qp_ioctl_t*)cl_ioctl_in_buf( h_ioctl ); + al_dev_open_context_t *p_context = + (al_dev_open_context_t *)p_open_context; + ib_pd_handle_t h_pd; + ib_qp_handle_t h_qp; + ib_srq_handle_t h_srq = NULL; + ib_cq_handle_t h_sq_cq, h_rq_cq; + ci_umv_buf_t *p_umv_buf = NULL; + ib_api_status_t status; + ib_pfn_event_cb_t pfn_ev; + + AL_ENTER( AL_DBG_QP ); + + /* Validate input buffers. */ + if( !cl_ioctl_in_buf( h_ioctl ) || !cl_ioctl_out_buf( h_ioctl ) || + cl_ioctl_in_size( h_ioctl ) != sizeof(p_ioctl->in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(p_ioctl->out) ) + { + AL_EXIT( AL_DBG_QP ); + return CL_INVALID_PARAMETER; + } + + /* Validate handles. */ + h_pd = (ib_pd_handle_t) + al_hdl_ref( p_context->h_al, p_ioctl->in.h_pd, AL_OBJ_TYPE_H_PD ); + h_sq_cq = (ib_cq_handle_t)al_hdl_ref( p_context->h_al, + p_ioctl->in.qp_create.h_sq_cq_padding, AL_OBJ_TYPE_H_CQ ); + h_rq_cq = (ib_cq_handle_t)al_hdl_ref( p_context->h_al, + p_ioctl->in.qp_create.h_rq_cq_padding, AL_OBJ_TYPE_H_CQ ); + if (p_ioctl->in.qp_create.h_srq) { + h_srq = (ib_srq_handle_t)al_hdl_ref( p_context->h_al, + p_ioctl->in.qp_create.h_srq_padding, AL_OBJ_TYPE_H_SRQ ); + if( !h_srq) + { + status = IB_INVALID_SRQ_HANDLE; + goto proxy_create_qp_err1; + } + } + if( !h_pd) + { + status = IB_INVALID_PD_HANDLE; + goto proxy_create_qp_err1; + } + if( !h_sq_cq ) + { + status = IB_INVALID_CQ_HANDLE; + goto proxy_create_qp_err1; + } + if( !h_rq_cq ) + { + status = IB_INVALID_CQ_HANDLE; + goto proxy_create_qp_err1; + } + + /* Substitute rq_cq handle with AL's cq handle */ + p_ioctl->in.qp_create.h_sq_cq = h_sq_cq; + /* Substitute rq_cq handle with AL's cq handle */ + p_ioctl->in.qp_create.h_rq_cq = h_rq_cq; + /* Substitute srq handle with AL's srq handle */ + p_ioctl->in.qp_create.h_srq = h_srq; + + status = cpyin_umvbuf( &p_ioctl->in.umv_buf, &p_umv_buf ); + if( status != IB_SUCCESS ) + goto proxy_create_qp_err1; + + if( p_ioctl->in.ev_notify ) + pfn_ev = proxy_qp_err_cb; + else + pfn_ev = NULL; + + status = create_qp( h_pd, &p_ioctl->in.qp_create, + (void*)(ULONG_PTR)p_ioctl->in.context, pfn_ev, &h_qp, p_umv_buf ); + /* TODO: The create_qp call should return the attributes... */ + if( status != IB_SUCCESS ) + goto proxy_create_qp_err1; + + status = query_qp( h_qp, &p_ioctl->out.attr, NULL ); + if( status != IB_SUCCESS ) + goto proxy_create_qp_err2; + + status = cpyout_umvbuf( &p_ioctl->out.umv_buf, p_umv_buf ); + if( status == IB_SUCCESS ) + { + p_ioctl->out.h_qp = h_qp->obj.hdl; + h_qp->obj.hdl_valid = TRUE; + /* Release the reference taken in create_qp (by init_al_obj) */ + deref_al_obj( &h_qp->obj ); + } + else + { +proxy_create_qp_err2: + /* + * Note that we hold the reference taken in create_qp (by init_al_obj) + */ + h_qp->obj.pfn_destroy( &h_qp->obj, NULL ); + +proxy_create_qp_err1: + p_ioctl->out.umv_buf = p_ioctl->in.umv_buf; + p_ioctl->out.h_qp = AL_INVALID_HANDLE; + cl_memclr( &p_ioctl->out.attr, sizeof(ib_qp_attr_t) ); + } + free_umvbuf( p_umv_buf ); + + p_ioctl->out.status = status; + *p_ret_bytes = sizeof(p_ioctl->out); + + if( h_pd ) + deref_al_obj( &h_pd->obj ); + if( h_rq_cq ) + deref_al_obj( &h_rq_cq->obj ); + if( h_sq_cq ) + deref_al_obj( &h_sq_cq->obj ); + if( h_srq ) + deref_al_obj( &h_srq->obj ); + + AL_EXIT( AL_DBG_QP ); + return CL_SUCCESS; +} + + +/* + * Process the ioctl UAL_QUERY_QP: + */ +static +cl_status_t +proxy_query_qp( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_query_qp_ioctl_t *p_ioctl = + (ual_query_qp_ioctl_t *)cl_ioctl_in_buf( h_ioctl ); + al_dev_open_context_t *p_context = + (al_dev_open_context_t *)p_open_context; + ib_qp_handle_t h_qp; + ci_umv_buf_t *p_umv_buf = NULL; + ib_api_status_t status; + + AL_ENTER( AL_DBG_QP ); + + /* Validate input buffers. */ + if( !cl_ioctl_in_buf( h_ioctl ) || !cl_ioctl_out_buf( h_ioctl ) || + cl_ioctl_in_size( h_ioctl ) != sizeof(p_ioctl->in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(p_ioctl->out) ) + { + AL_EXIT( AL_DBG_QP ); + return CL_INVALID_PARAMETER; + } + + /* Validate QP handle */ + h_qp = (ib_qp_handle_t) + al_hdl_ref( p_context->h_al, p_ioctl->in.h_qp, AL_OBJ_TYPE_H_QP ); + if( !h_qp ) + { + status = IB_INVALID_QP_HANDLE; + goto proxy_query_qp_err; + } + + status = cpyin_umvbuf( &p_ioctl->in.umv_buf, &p_umv_buf ); + if( status != IB_SUCCESS ) + goto proxy_query_qp_err; + + status = query_qp( h_qp, &p_ioctl->out.attr, p_umv_buf ); + if( status != IB_SUCCESS ) + goto proxy_query_qp_err; + + status = cpyout_umvbuf( &p_ioctl->out.umv_buf, p_umv_buf ); + if( status == IB_SUCCESS ) + { + if( p_ioctl->out.attr.h_pd ) + { + p_ioctl->out.attr.h_pd_padding = p_ioctl->out.attr.h_pd->obj.hdl; + } + + if( p_ioctl->out.attr.h_sq_cq ) + { + p_ioctl->out.attr.h_sq_cq_padding = + p_ioctl->out.attr.h_sq_cq->obj.hdl; + } + + if( p_ioctl->out.attr.h_rq_cq ) + { + p_ioctl->out.attr.h_rq_cq_padding = + p_ioctl->out.attr.h_rq_cq->obj.hdl; + } + + if( p_ioctl->out.attr.h_srq ) + { + p_ioctl->out.attr.h_srq_padding = p_ioctl->out.attr.h_srq->obj.hdl; + } + } + else + { +proxy_query_qp_err: + p_ioctl->out.umv_buf = p_ioctl->in.umv_buf; + cl_memclr( &p_ioctl->out.attr, sizeof(ib_qp_attr_t) ); + } + free_umvbuf( p_umv_buf ); + + if( h_qp ) + deref_al_obj( &h_qp->obj ); + + p_ioctl->out.status = status; + *p_ret_bytes = sizeof(p_ioctl->out); + + AL_EXIT( AL_DBG_QP ); + return CL_SUCCESS; +} + + + +/* + * Process the ioctl UAL_MODIFY_QP: + */ +static +cl_status_t +proxy_modify_qp( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_modify_qp_ioctl_t *p_ioctl = + (ual_modify_qp_ioctl_t *)cl_ioctl_in_buf( h_ioctl ); + al_dev_open_context_t *p_context = + (al_dev_open_context_t *)p_open_context; + ib_qp_handle_t h_qp; + ci_umv_buf_t *p_umv_buf = NULL; + ib_api_status_t status; + + AL_ENTER( AL_DBG_QP ); + + /* Validate input buffers. */ + if( !cl_ioctl_in_buf( h_ioctl ) || !cl_ioctl_out_buf( h_ioctl ) || + cl_ioctl_in_size( h_ioctl ) != sizeof(p_ioctl->in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(p_ioctl->out) ) + { + AL_EXIT( AL_DBG_QP ); + return CL_INVALID_PARAMETER; + } + + /* Validate QP handle */ + h_qp = (ib_qp_handle_t) + al_hdl_ref( p_context->h_al, p_ioctl->in.h_qp, AL_OBJ_TYPE_H_QP ); + if( !h_qp ) + { + status = IB_INVALID_QP_HANDLE; + goto proxy_modify_qp_err; + } + + status = cpyin_umvbuf( &p_ioctl->in.umv_buf, &p_umv_buf ); + if( status != IB_SUCCESS ) + goto proxy_modify_qp_err; + + status = modify_qp( h_qp, &p_ioctl->in.modify_attr, p_umv_buf ); + + if( status != IB_SUCCESS ) + goto proxy_modify_qp_err; + + status = cpyout_umvbuf( &p_ioctl->out.umv_buf, p_umv_buf ); + if( status != IB_SUCCESS ) + { +proxy_modify_qp_err: + p_ioctl->out.umv_buf = p_ioctl->in.umv_buf; + } + free_umvbuf( p_umv_buf ); + + if( h_qp ) + deref_al_obj( &h_qp->obj ); + + p_ioctl->out.status = status; + *p_ret_bytes = sizeof(p_ioctl->out); + + AL_EXIT( AL_DBG_QP ); + return CL_SUCCESS; +} + + +/* + * Process the ioctl UAL_DESTROY_QP + */ +static cl_status_t +proxy_destroy_qp( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_destroy_qp_ioctl_t *p_ioctl = + (ual_destroy_qp_ioctl_t *)cl_ioctl_in_buf( h_ioctl ); + al_dev_open_context_t *p_context = + (al_dev_open_context_t *)p_open_context; + ib_qp_handle_t h_qp; + + AL_ENTER( AL_DBG_QP ); + + /* Validate input buffers. */ + if( !cl_ioctl_in_buf( h_ioctl ) || !cl_ioctl_out_buf( h_ioctl ) || + cl_ioctl_in_size( h_ioctl ) != sizeof(p_ioctl->in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(p_ioctl->out) ) + { + AL_EXIT( AL_DBG_QP ); + return CL_INVALID_PARAMETER; + } + + /* Set the return bytes in all cases */ + *p_ret_bytes = sizeof(p_ioctl->out); + + /* Validate QP handle */ + h_qp = (ib_qp_handle_t) + al_hdl_ref( p_context->h_al, p_ioctl->in.h_qp, AL_OBJ_TYPE_H_QP ); + if( !h_qp ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_QP_HANDLE\n") ); + p_ioctl->out.status = IB_INVALID_QP_HANDLE; + } + else + { + h_qp->obj.pfn_destroy( &h_qp->obj, ib_sync_destroy ); + p_ioctl->out.status = IB_SUCCESS; + } + + AL_EXIT( AL_DBG_QP ); + return CL_SUCCESS; +} + + + +/* + * Process the ioctl UAL_CREATE_AV: + */ +static +cl_status_t +proxy_create_av( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_create_av_ioctl_t *p_ioctl = + (ual_create_av_ioctl_t *)cl_ioctl_in_buf( h_ioctl ); + al_dev_open_context_t *p_context = + (al_dev_open_context_t *)p_open_context; + ib_pd_handle_t h_pd; + ib_av_handle_t h_av; + ci_umv_buf_t *p_umv_buf = NULL; + ib_api_status_t status; + + AL_ENTER( AL_DBG_AV ); + + /* Validate input buffers. */ + if( !cl_ioctl_in_buf( h_ioctl ) || !cl_ioctl_out_buf( h_ioctl ) || + cl_ioctl_in_size( h_ioctl ) != sizeof(p_ioctl->in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(p_ioctl->out) ) + { + AL_EXIT( AL_DBG_AV ); + return CL_INVALID_PARAMETER; + } + + /* Validate PD handle */ + h_pd = (ib_pd_handle_t) + al_hdl_ref( p_context->h_al, p_ioctl->in.h_pd, AL_OBJ_TYPE_H_PD ); + if( !h_pd ) + { + status = IB_INVALID_PD_HANDLE; + goto proxy_create_av_err; + } + + status = cpyin_umvbuf( &p_ioctl->in.umv_buf, &p_umv_buf ); + if( status != IB_SUCCESS ) + goto proxy_create_av_err; + + status = create_av( h_pd, &p_ioctl->in.attr, &h_av, p_umv_buf ); + + if( status != IB_SUCCESS ) + goto proxy_create_av_err; + + status = cpyout_umvbuf( &p_ioctl->out.umv_buf, p_umv_buf ); + if( status == IB_SUCCESS ) + { + p_ioctl->out.h_av = h_av->obj.hdl; + h_av->obj.hdl_valid = TRUE; + /* Release the reference taken in create_av. */ + deref_al_obj( &h_av->obj ); + } + else + { + h_av->obj.pfn_destroy( &h_av->obj, NULL ); + +proxy_create_av_err: + p_ioctl->out.umv_buf = p_ioctl->in.umv_buf; + p_ioctl->out.h_av = AL_INVALID_HANDLE; + } + free_umvbuf( p_umv_buf ); + + if( h_pd ) + deref_al_obj( &h_pd->obj ); + + p_ioctl->out.status = status; + *p_ret_bytes = sizeof(p_ioctl->out); + + AL_EXIT( AL_DBG_AV ); + return CL_SUCCESS; +} + + + +/* + * Process the ioctl UAL_QUERY_AV: + */ +static +cl_status_t +proxy_query_av( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_query_av_ioctl_t *p_ioctl = + (ual_query_av_ioctl_t *)cl_ioctl_in_buf( h_ioctl ); + al_dev_open_context_t *p_context = + (al_dev_open_context_t *)p_open_context; + ib_av_handle_t h_av; + ib_pd_handle_t h_pd; + ci_umv_buf_t *p_umv_buf = NULL; + ib_api_status_t status; + + AL_ENTER( AL_DBG_AV ); + + /* Validate input buffers. */ + if( !cl_ioctl_in_buf( h_ioctl ) || !cl_ioctl_out_buf( h_ioctl ) || + cl_ioctl_in_size( h_ioctl ) != sizeof(p_ioctl->in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(p_ioctl->out) ) + { + AL_EXIT( AL_DBG_AV ); + return CL_INVALID_PARAMETER; + } + + /* Validate AV handle */ + h_av = (ib_av_handle_t) + al_hdl_ref( p_context->h_al, p_ioctl->in.h_av, AL_OBJ_TYPE_H_AV ); + if( !h_av ) + { + status = IB_INVALID_AV_HANDLE; + goto proxy_query_av_err; + } + + status = cpyin_umvbuf( &p_ioctl->in.umv_buf, &p_umv_buf ); + if( status != IB_SUCCESS ) + goto proxy_query_av_err; + + status = query_av( h_av, &p_ioctl->out.attr, &h_pd, p_umv_buf ); + + if( status != IB_SUCCESS ) + goto proxy_query_av_err; + + status = cpyout_umvbuf( &p_ioctl->out.umv_buf, p_umv_buf ); + if( status != IB_SUCCESS ) + { +proxy_query_av_err: + p_ioctl->out.umv_buf = p_ioctl->in.umv_buf; + cl_memclr( &p_ioctl->out.attr, sizeof(ib_av_attr_t) ); + } + free_umvbuf( p_umv_buf ); + + if( h_av ) + deref_al_obj( &h_av->obj ); + + p_ioctl->out.status = status; + *p_ret_bytes = sizeof(p_ioctl->out); + + AL_EXIT( AL_DBG_AV ); + return CL_SUCCESS; +} + + + +/* + * Process the ioctl UAL_MODIFY_AV: + */ +static +cl_status_t +proxy_modify_av( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_modify_av_ioctl_t *p_ioctl = + (ual_modify_av_ioctl_t *)cl_ioctl_in_buf( h_ioctl ); + al_dev_open_context_t *p_context = + (al_dev_open_context_t *)p_open_context; + ib_av_handle_t h_av; + ci_umv_buf_t *p_umv_buf = NULL; + ib_api_status_t status; + + AL_ENTER( AL_DBG_AV ); + + /* Validate input buffers. */ + if( !cl_ioctl_in_buf( h_ioctl ) || !cl_ioctl_out_buf( h_ioctl ) || + cl_ioctl_in_size( h_ioctl ) != sizeof(p_ioctl->in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(p_ioctl->out) ) + { + AL_EXIT( AL_DBG_AV ); + return CL_INVALID_PARAMETER; + } + + /* Validate AV handle */ + h_av = (ib_av_handle_t) + al_hdl_ref( p_context->h_al, p_ioctl->in.h_av, AL_OBJ_TYPE_H_AV ); + if( !h_av ) + { + status = IB_INVALID_AV_HANDLE; + goto proxy_modify_av_err; + } + + status = cpyin_umvbuf( &p_ioctl->in.umv_buf, &p_umv_buf ); + if( status != IB_SUCCESS ) + goto proxy_modify_av_err; + + status = modify_av( h_av, &p_ioctl->in.attr, p_umv_buf ); + + if( status != IB_SUCCESS ) + goto proxy_modify_av_err; + + status = cpyout_umvbuf( &p_ioctl->out.umv_buf, p_umv_buf ); + if( status != IB_SUCCESS ) + { +proxy_modify_av_err: + p_ioctl->out.umv_buf = p_ioctl->in.umv_buf; + } + free_umvbuf( p_umv_buf ); + + if( h_av ) + deref_al_obj( &h_av->obj ); + + p_ioctl->out.status = status; + *p_ret_bytes = sizeof(p_ioctl->out); + + AL_EXIT( AL_DBG_AV ); + return CL_SUCCESS; +} + + + +/* + * Process the ioctl UAL_DESTROY_AV: + */ +static +cl_status_t +proxy_destroy_av( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_destroy_av_ioctl_t *p_ioctl = + (ual_destroy_av_ioctl_t *)cl_ioctl_in_buf( h_ioctl ); + al_dev_open_context_t *p_context = + (al_dev_open_context_t *)p_open_context; + ib_av_handle_t h_av; + + AL_ENTER( AL_DBG_AV ); + + /* Validate input buffers. */ + if( !cl_ioctl_in_buf( h_ioctl ) || !cl_ioctl_out_buf( h_ioctl ) || + cl_ioctl_in_size( h_ioctl ) != sizeof(p_ioctl->in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(p_ioctl->out) ) + { + AL_EXIT( AL_DBG_AV ); + return CL_INVALID_PARAMETER; + } + + /* Set the return bytes in all cases */ + *p_ret_bytes = sizeof(p_ioctl->out); + + /* Validate AV handle */ + h_av = (ib_av_handle_t) + al_hdl_ref( p_context->h_al, p_ioctl->in.h_av, AL_OBJ_TYPE_H_AV ); + if( !h_av ) + { + p_ioctl->out.status = IB_INVALID_AV_HANDLE; + AL_EXIT( AL_DBG_AV ); + return CL_SUCCESS; + } + + h_av->obj.pfn_destroy( &h_av->obj, NULL ); + p_ioctl->out.status = IB_SUCCESS; + + AL_EXIT( AL_DBG_AV ); + return CL_SUCCESS; +} + + + +/* + * Process the ioctl UAL_MODIFY_CQ: + */ +static +cl_status_t +proxy_modify_cq( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_modify_cq_ioctl_t *p_ioctl = + (ual_modify_cq_ioctl_t *)cl_ioctl_in_buf( h_ioctl ); + al_dev_open_context_t *p_context = + (al_dev_open_context_t *)p_open_context; + ib_cq_handle_t h_cq; + ci_umv_buf_t *p_umv_buf = NULL; + ib_api_status_t status; + uint32_t size; + + AL_ENTER( AL_DBG_CQ ); + + /* Validate input buffers. */ + if( !cl_ioctl_in_buf( h_ioctl ) || !cl_ioctl_out_buf( h_ioctl ) || + cl_ioctl_in_size( h_ioctl ) != sizeof(p_ioctl->in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(p_ioctl->out) ) + { + AL_EXIT( AL_DBG_CQ ); + return CL_INVALID_PARAMETER; + } + + /* Validate CQ handle */ + h_cq = (ib_cq_handle_t) + al_hdl_ref( p_context->h_al, p_ioctl->in.h_cq, AL_OBJ_TYPE_H_CQ ); + if( !h_cq ) + { + status = IB_INVALID_CQ_HANDLE; + goto proxy_modify_cq_err; + } + + status = cpyin_umvbuf( &p_ioctl->in.umv_buf, &p_umv_buf ); + if( status != IB_SUCCESS ) + goto proxy_modify_cq_err; + + size = p_ioctl->in.size; + status = modify_cq( h_cq, &size, p_umv_buf ); + if( status != IB_SUCCESS ) + goto proxy_modify_cq_err; + + status = cpyout_umvbuf( &p_ioctl->out.umv_buf, p_umv_buf ); + if( status == IB_SUCCESS ) + { + p_ioctl->out.size = size; + } + else + { +proxy_modify_cq_err: + p_ioctl->out.umv_buf = p_ioctl->in.umv_buf; + p_ioctl->out.size = 0; + } + free_umvbuf( p_umv_buf ); + + if( h_cq ) + deref_al_obj( &h_cq->obj ); + + p_ioctl->out.status = status; + *p_ret_bytes = sizeof(p_ioctl->out); + + AL_EXIT( AL_DBG_CQ ); + return CL_SUCCESS; +} + + + +/* + * Proxy's CQ completion callback + */ +static void +proxy_cq_comp_cb( + IN ib_cq_handle_t h_cq, + IN void *cq_context ) +{ + comp_cb_ioctl_info_t cb_info; + al_dev_open_context_t *p_context = h_cq->obj.h_al->p_context; + + /* + * If we're already closing the device - do not queue a callback, since + * we're cleaning up the callback lists. + */ + if( !proxy_context_ref( p_context ) ) + { + proxy_context_deref( p_context ); + return; + } + + /* Set up context and callback record type appropriate for UAL */ + cb_info.cq_context = (ULONG_PTR)cq_context; + + /* The proxy handle must be valid now. */ + if( !h_cq->obj.hdl_valid ) + h_cq->obj.hdl_valid = TRUE; + + proxy_queue_cb_buf( UAL_GET_COMP_CB_INFO, p_context, &cb_info, + &h_cq->obj ); + + proxy_context_deref( p_context ); +} + + + +/* + * Proxy's CQ error callback + */ +static void +proxy_cq_err_cb( + IN ib_async_event_rec_t *p_err_rec) +{ + ib_cq_handle_t h_cq = p_err_rec->handle.h_cq; + al_dev_open_context_t *p_context = h_cq->obj.h_al->p_context; + misc_cb_ioctl_info_t cb_info; + + /* + * If we're already closing the device - do not queue a callback, since + * we're cleaning up the callback lists. + */ + if( !proxy_context_ref( p_context ) ) + { + proxy_context_deref( p_context ); + return; + } + + /* Set up context and callback record type appropriate for UAL */ + cb_info.rec_type = CQ_ERROR_REC; + /* Return the Proxy's cq handle and the user's context */ + cb_info.ioctl_rec.event_rec = *p_err_rec; + cb_info.ioctl_rec.event_rec.handle.h_cq_padding = h_cq->obj.hdl; + + /* The proxy handle must be valid now. */ + if( !h_cq->obj.hdl_valid ) + h_cq->obj.hdl_valid = TRUE; + + proxy_queue_cb_buf( UAL_GET_MISC_CB_INFO, p_context, &cb_info, + &h_cq->obj ); + proxy_context_deref( p_context ); +} + + + +/* + * Process the ioctl UAL_CREATE_CQ: + */ +static cl_status_t +proxy_create_cq( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_create_cq_ioctl_t *p_ioctl = + (ual_create_cq_ioctl_t *)cl_ioctl_in_buf( h_ioctl ); + al_dev_open_context_t *p_context = + (al_dev_open_context_t *)p_open_context; + ib_ca_handle_t h_ca; + ib_cq_handle_t h_cq; + ib_cq_create_t cq_create; + ci_umv_buf_t *p_umv_buf = NULL; + ib_api_status_t status; + ib_pfn_event_cb_t pfn_ev; + + AL_ENTER( AL_DBG_CQ ); + + /* Validate input buffers. */ + if( !cl_ioctl_in_buf( h_ioctl ) || !cl_ioctl_out_buf( h_ioctl ) || + cl_ioctl_in_size( h_ioctl ) != sizeof(p_ioctl->in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(p_ioctl->out) ) + { + AL_EXIT( AL_DBG_CQ ); + return CL_INVALID_PARAMETER; + } + + /* Validate CA handle */ + h_ca = (ib_ca_handle_t) + al_hdl_ref( p_context->h_al, p_ioctl->in.h_ca, AL_OBJ_TYPE_H_CA ); + if( !h_ca ) + { + status = IB_INVALID_CA_HANDLE; + goto proxy_create_cq_err1; + } + + cq_create.size = p_ioctl->in.size; + + if( p_ioctl->in.h_wait_obj ) + { + cq_create.pfn_comp_cb = NULL; + cq_create.h_wait_obj = cl_waitobj_ref( p_ioctl->in.h_wait_obj ); + if( !cq_create.h_wait_obj ) + { + status = IB_INVALID_PARAMETER; + goto proxy_create_cq_err1; + } + } + else + { + /* Override with proxy's cq callback */ + cq_create.pfn_comp_cb = proxy_cq_comp_cb; + cq_create.h_wait_obj = NULL; + } + + status = cpyin_umvbuf( &p_ioctl->in.umv_buf, &p_umv_buf ); + if( status != IB_SUCCESS ) + goto proxy_create_cq_err2; + + if( p_ioctl->in.ev_notify ) + pfn_ev = proxy_cq_err_cb; + else + pfn_ev = NULL; + + status = create_cq( h_ca, &cq_create, + (void*)(ULONG_PTR)p_ioctl->in.context, pfn_ev, &h_cq, p_umv_buf ); + + if( status != IB_SUCCESS ) + goto proxy_create_cq_err2; + + status = cpyout_umvbuf( &p_ioctl->out.umv_buf, p_umv_buf ); + if( status == IB_SUCCESS ) + { + p_ioctl->out.size = cq_create.size; + p_ioctl->out.h_cq = h_cq->obj.hdl; + h_cq->obj.hdl_valid = TRUE; + deref_al_obj( &h_cq->obj ); + } + else + { + h_cq->obj.pfn_destroy( &h_cq->obj, NULL ); + +proxy_create_cq_err2: + if( cq_create.h_wait_obj ) + cl_waitobj_deref( cq_create.h_wait_obj ); + +proxy_create_cq_err1: + p_ioctl->out.umv_buf = p_ioctl->in.umv_buf; + p_ioctl->out.h_cq = AL_INVALID_HANDLE; + p_ioctl->out.size = 0; + } + free_umvbuf( p_umv_buf ); + + if( h_ca ) + deref_al_obj( &h_ca->obj ); + + p_ioctl->out.status = status; + *p_ret_bytes = sizeof(p_ioctl->out); + + AL_EXIT( AL_DBG_CQ ); + return CL_SUCCESS; +} + + +/* + * Process the ioctl UAL_QUERY_CQ: + */ +static +cl_status_t +proxy_query_cq( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_query_cq_ioctl_t *p_ioctl = + (ual_query_cq_ioctl_t *)cl_ioctl_in_buf( h_ioctl ); + al_dev_open_context_t *p_context = + (al_dev_open_context_t *)p_open_context; + ib_cq_handle_t h_cq; + ci_umv_buf_t *p_umv_buf = NULL; + ib_api_status_t status; + + AL_ENTER( AL_DBG_CQ ); + + /* Validate input buffers. */ + if( !cl_ioctl_in_buf( h_ioctl ) || !cl_ioctl_out_buf( h_ioctl ) || + cl_ioctl_in_size( h_ioctl ) != sizeof(p_ioctl->in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(p_ioctl->out) ) + { + AL_EXIT( AL_DBG_CQ ); + return CL_INVALID_PARAMETER; + } + + /* Validate CQ handle */ + h_cq = (ib_cq_handle_t) + al_hdl_ref( p_context->h_al, p_ioctl->in.h_cq, AL_OBJ_TYPE_H_CQ ); + if( !h_cq ) + { + status = IB_INVALID_CQ_HANDLE; + goto proxy_query_cq_err; + } + + status = cpyin_umvbuf( &p_ioctl->in.umv_buf, &p_umv_buf ); + if( status != IB_SUCCESS ) + goto proxy_query_cq_err; + + status = query_cq( h_cq, &p_ioctl->out.size, p_umv_buf ); + + if( status != IB_SUCCESS ) + goto proxy_query_cq_err; + + status = cpyout_umvbuf( &p_ioctl->out.umv_buf, p_umv_buf ); + if( status != IB_SUCCESS ) + { +proxy_query_cq_err: + p_ioctl->out.umv_buf = p_ioctl->in.umv_buf; + p_ioctl->out.size = 0; + } + free_umvbuf( p_umv_buf ); + + if( h_cq ) + deref_al_obj( &h_cq->obj ); + + p_ioctl->out.status = status; + *p_ret_bytes = sizeof(p_ioctl->out); + + AL_EXIT( AL_DBG_CQ ); + return CL_SUCCESS; +} + + +/* + * Process the ioctl UAL_DESTROY_CQ + */ +static +cl_status_t +proxy_destroy_cq( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_destroy_cq_ioctl_t *p_ioctl = + (ual_destroy_cq_ioctl_t *)cl_ioctl_in_buf( h_ioctl ); + al_dev_open_context_t *p_context = + (al_dev_open_context_t *)p_open_context; + ib_cq_handle_t h_cq; + cl_waitobj_handle_t h_wait_obj; + + AL_ENTER( AL_DBG_CQ ); + + /* Validate input buffers. */ + if( !cl_ioctl_in_buf( h_ioctl ) || !cl_ioctl_out_buf( h_ioctl ) || + cl_ioctl_in_size( h_ioctl ) != sizeof(p_ioctl->in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(p_ioctl->out) ) + { + AL_EXIT( AL_DBG_CQ ); + return CL_INVALID_PARAMETER; + } + + /* Set the return bytes in all cases */ + *p_ret_bytes = sizeof(p_ioctl->out); + + /* Validate CQ handle */ + h_cq = (ib_cq_handle_t) + al_hdl_ref( p_context->h_al, p_ioctl->in.h_cq, AL_OBJ_TYPE_H_CQ ); + if( !h_cq ) + { + p_ioctl->out.status = IB_INVALID_CQ_HANDLE; + AL_EXIT( AL_DBG_CQ ); + return CL_SUCCESS; + } + + h_wait_obj = h_cq->h_wait_obj; + + h_cq->obj.pfn_destroy( &h_cq->obj, ib_sync_destroy ); + + /* Deref the wait object, if any. */ + if( h_wait_obj ) + cl_waitobj_deref( h_wait_obj ); + + p_ioctl->out.status = IB_SUCCESS; + + AL_EXIT( AL_DBG_CQ ); + return CL_SUCCESS; +} + + +/* + * Process the ioctl UAL_POST_SEND + */ +static +cl_status_t +proxy_post_send( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_post_send_ioctl_t *p_ioctl = + (ual_post_send_ioctl_t *)cl_ioctl_in_buf( h_ioctl ); + al_dev_open_context_t *p_context = + (al_dev_open_context_t *)p_open_context; + ib_qp_handle_t h_qp; + ib_av_handle_t h_av; + ib_send_wr_t *p_wr; + ib_send_wr_t *p_send_failure; + uintn_t i = 0; + ib_local_ds_t *p_ds; + uintn_t num_ds = 0; + ib_api_status_t status; + size_t in_buf_sz; + + AL_ENTER( AL_DBG_QP ); + /* Validate input buffers. */ + if( !cl_ioctl_in_buf( h_ioctl ) || !cl_ioctl_out_buf( h_ioctl ) || + cl_ioctl_in_size( h_ioctl ) < sizeof(p_ioctl->in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(p_ioctl->out) ) + { + AL_EXIT( AL_DBG_QP ); + return CL_INVALID_PARAMETER; + } + + /* + * Additional input buffer validation based on actual settings. + * Note that this validates that work requests are actually + * being passed in. + */ + in_buf_sz = sizeof(p_ioctl->in); + in_buf_sz += sizeof(ib_send_wr_t) * (p_ioctl->in.num_wr - 1); + in_buf_sz += sizeof(ib_local_ds_t) * p_ioctl->in.num_ds; + if( cl_ioctl_in_size( h_ioctl ) != in_buf_sz ) + { + AL_EXIT( AL_DBG_QP ); + return CL_INVALID_PARAMETER; + } + + /* Setup p_send_failure to head of list. */ + p_send_failure = p_wr = p_ioctl->in.send_wr; + + /* Validate QP handle */ + h_qp = (ib_qp_handle_t) + al_hdl_ref( p_context->h_al, p_ioctl->in.h_qp, AL_OBJ_TYPE_H_QP ); + if( !h_qp ) + { + status = IB_INVALID_QP_HANDLE; + goto proxy_post_send_done; + } + + /* Setup the base data segment pointer. */ + p_ds = (ib_local_ds_t*)&p_ioctl->in.send_wr[p_ioctl->in.num_wr]; + + /* Setup the user's work requests and data segments and translate. */ + for( i = 0; i < p_ioctl->in.num_wr; i++ ) + { + if( h_qp->type == IB_QPT_UNRELIABLE_DGRM ) + { + /* Validate the AV handle for UD */ + h_av = (ib_av_handle_t)al_hdl_ref( p_context->h_al, + (ULONG_PTR) p_wr[i].dgrm.ud.h_av, AL_OBJ_TYPE_H_AV ); + if( !h_av ) + { + status = IB_INVALID_AV_HANDLE; + goto proxy_post_send_done; + } + /* substitute with KAL AV handle */ + p_wr[i].dgrm.ud.h_av = h_av; + } + + /* Setup the data segments, if any. */ + if( p_wr[i].num_ds ) + { + num_ds += p_wr[i].num_ds; + if( num_ds > p_ioctl->in.num_ds ) + { + /* + * The work request submitted exceed the number of data + * segments specified in the IOCTL. + */ + status = IB_INVALID_PARAMETER; + goto proxy_post_send_done; + } + p_wr[i].ds_array = p_ds; + p_ds += p_wr->num_ds; + } + else + { + p_wr[i].ds_array = NULL; + } + + p_wr[i].p_next = &p_wr[i + 1]; + } + + /* Mark the end of list. */ + p_wr[i - 1].p_next = NULL; + + /* so much for the set up, let's roll! */ + status = ib_post_send( h_qp, p_wr, &p_send_failure ); + + if( status == IB_SUCCESS ) + { + p_ioctl->out.failed_cnt = 0; + } + else + { +proxy_post_send_done: + /* First set up as if all failed. */ + p_ioctl->out.failed_cnt = p_ioctl->in.num_wr; + /* Now subtract successful ones. */ + p_ioctl->out.failed_cnt -= (uint32_t)( + (((uintn_t)p_send_failure) - ((uintn_t)p_wr)) + / sizeof(ib_send_wr_t)); + } + + /* releases the references on address vectors. */ + if( h_qp ) + { + if( h_qp->type == IB_QPT_UNRELIABLE_DGRM ) + { + while( i-- ) + deref_al_obj( &p_wr[i].dgrm.ud.h_av->obj ); + } + deref_al_obj( &h_qp->obj ); + } + + p_ioctl->out.status = status; + *p_ret_bytes = sizeof(p_ioctl->out); + + AL_EXIT( AL_DBG_QP ); + return CL_SUCCESS; +} + + + +/* + * Process the ioctl UAL_POST_RECV + */ +static +cl_status_t +proxy_post_recv( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_post_recv_ioctl_t *p_ioctl = + (ual_post_recv_ioctl_t *)cl_ioctl_in_buf( h_ioctl ); + al_dev_open_context_t *p_context = + (al_dev_open_context_t *)p_open_context; + ib_qp_handle_t h_qp; + ib_recv_wr_t *p_wr; + ib_recv_wr_t *p_recv_failure; + uintn_t i; + ib_local_ds_t *p_ds; + uintn_t num_ds = 0; + ib_api_status_t status; + size_t in_buf_sz; + + AL_ENTER( AL_DBG_QP ); + + /* Validate input buffers. */ + if( !cl_ioctl_in_buf( h_ioctl ) || !cl_ioctl_out_buf( h_ioctl ) || + cl_ioctl_in_size( h_ioctl ) < sizeof(p_ioctl->in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(p_ioctl->out) ) + { + AL_EXIT( AL_DBG_QP ); + return CL_INVALID_PARAMETER; + } + + /* + * Additional input buffer validation based on actual settings. + * Note that this validates that work requests are actually + * being passed in. + */ + in_buf_sz = sizeof(p_ioctl->in); + in_buf_sz += sizeof(ib_recv_wr_t) * (p_ioctl->in.num_wr - 1); + in_buf_sz += sizeof(ib_local_ds_t) * p_ioctl->in.num_ds; + if( cl_ioctl_in_size( h_ioctl ) != in_buf_sz ) + { + AL_EXIT( AL_DBG_QP ); + return CL_INVALID_PARAMETER; + } + + /* Setup p_send_failure to head of list. */ + p_recv_failure = p_wr = p_ioctl->in.recv_wr; + + /* Validate QP handle */ + h_qp = (ib_qp_handle_t) + al_hdl_ref( p_context->h_al, p_ioctl->in.h_qp, AL_OBJ_TYPE_H_QP ); + if( !h_qp ) + { + status = IB_INVALID_QP_HANDLE; + goto proxy_post_recv_done; + } + + /* Setup the base data segment pointer. */ + p_ds = (ib_local_ds_t*)&p_ioctl->in.recv_wr[p_ioctl->in.num_wr]; + + /* Setup the user's work requests and data segments and translate. */ + for( i = 0; i < p_ioctl->in.num_wr; i++ ) + { + /* Setup the data segments, if any. */ + if( p_wr[i].num_ds ) + { + num_ds += p_wr[i].num_ds; + if( num_ds > p_ioctl->in.num_ds ) + { + /* + * The work request submitted exceed the number of data + * segments specified in the IOCTL. + */ + status = IB_INVALID_PARAMETER; + goto proxy_post_recv_done; + } + p_wr[i].ds_array = p_ds; + p_ds += p_wr->num_ds; + } + else + { + p_wr[i].ds_array = NULL; + } + + p_wr[i].p_next = &p_wr[i + 1]; + } + + /* Mark the end of list. */ + p_wr[i-1].p_next = NULL; + + status = ib_post_recv( h_qp, p_wr, &p_recv_failure ); + + if( status == IB_SUCCESS ) + { + p_ioctl->out.failed_cnt = 0; + } + else + { +proxy_post_recv_done: + /* First set up as if all failed. */ + p_ioctl->out.failed_cnt = p_ioctl->in.num_wr; + /* Now subtract successful ones. */ + p_ioctl->out.failed_cnt -= (uint32_t)( + (((uintn_t)p_recv_failure) - ((uintn_t)p_wr)) + / sizeof(ib_recv_wr_t)); + } + + if( h_qp ) + deref_al_obj( &h_qp->obj ); + + p_ioctl->out.status = status; + *p_ret_bytes = sizeof(p_ioctl->out); + + AL_EXIT( AL_DBG_QP ); + return CL_SUCCESS; +} + + +/* + * Process the ioctl UAL_POST_SRQ_RECV + */ +static +cl_status_t +proxy_post_srq_recv( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_post_srq_recv_ioctl_t *p_ioctl = + (ual_post_srq_recv_ioctl_t *)cl_ioctl_in_buf( h_ioctl ); + al_dev_open_context_t *p_context = + (al_dev_open_context_t *)p_open_context; + ib_srq_handle_t h_srq; + ib_recv_wr_t *p_wr; + ib_recv_wr_t *p_recv_failure; + uintn_t i; + ib_local_ds_t *p_ds; + uintn_t num_ds = 0; + ib_api_status_t status; + size_t in_buf_sz; + + AL_ENTER( AL_DBG_QP ); + + /* Validate input buffers. */ + if( !cl_ioctl_in_buf( h_ioctl ) || !cl_ioctl_out_buf( h_ioctl ) || + cl_ioctl_in_size( h_ioctl ) < sizeof(p_ioctl->in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(p_ioctl->out) ) + { + AL_EXIT( AL_DBG_QP ); + return CL_INVALID_PARAMETER; + } + + /* + * Additional input buffer validation based on actual settings. + * Note that this validates that work requests are actually + * being passed in. + */ + in_buf_sz = sizeof(p_ioctl->in); + in_buf_sz += sizeof(ib_recv_wr_t) * (p_ioctl->in.num_wr - 1); + in_buf_sz += sizeof(ib_local_ds_t) * p_ioctl->in.num_ds; + if( cl_ioctl_in_size( h_ioctl ) != in_buf_sz ) + { + AL_EXIT( AL_DBG_QP ); + return CL_INVALID_PARAMETER; + } + + /* Setup p_send_failure to head of list. */ + p_recv_failure = p_wr = p_ioctl->in.recv_wr; + + /* Validate SRQ handle */ + h_srq = (ib_srq_handle_t) + al_hdl_ref( p_context->h_al, p_ioctl->in.h_srq, AL_OBJ_TYPE_H_QP ); + if( !h_srq ) + { + status = IB_INVALID_SRQ_HANDLE; + goto proxy_post_recv_done; + } + + /* Setup the base data segment pointer. */ + p_ds = (ib_local_ds_t*)&p_ioctl->in.recv_wr[p_ioctl->in.num_wr]; + + /* Setup the user's work requests and data segments and translate. */ + for( i = 0; i < p_ioctl->in.num_wr; i++ ) + { + /* Setup the data segments, if any. */ + if( p_wr[i].num_ds ) + { + num_ds += p_wr[i].num_ds; + if( num_ds > p_ioctl->in.num_ds ) + { + /* + * The work request submitted exceed the number of data + * segments specified in the IOCTL. + */ + status = IB_INVALID_PARAMETER; + goto proxy_post_recv_done; + } + p_wr[i].ds_array = p_ds; + p_ds += p_wr->num_ds; + } + else + { + p_wr[i].ds_array = NULL; + } + + p_wr[i].p_next = &p_wr[i + 1]; + } + + /* Mark the end of list. */ + p_wr[i-1].p_next = NULL; + + status = ib_post_srq_recv( h_srq, p_wr, &p_recv_failure ); + + if( status == IB_SUCCESS ) + { + p_ioctl->out.failed_cnt = 0; + } + else + { +proxy_post_recv_done: + /* First set up as if all failed. */ + p_ioctl->out.failed_cnt = p_ioctl->in.num_wr; + /* Now subtract successful ones. */ + p_ioctl->out.failed_cnt -= (uint32_t)( + (((uintn_t)p_recv_failure) - ((uintn_t)p_wr)) + / sizeof(ib_recv_wr_t)); + } + + if( h_srq ) + deref_al_obj( &h_srq->obj ); + + p_ioctl->out.status = status; + *p_ret_bytes = sizeof(p_ioctl->out); + + AL_EXIT( AL_DBG_QP ); + return CL_SUCCESS; +} + + +/* + * Process the ioctl UAL_PEEK_CQ + */ +static cl_status_t +proxy_peek_cq( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_peek_cq_ioctl_t *p_ioctl = + (ual_peek_cq_ioctl_t *)cl_ioctl_in_buf( h_ioctl ); + al_dev_open_context_t *p_context = + (al_dev_open_context_t *)p_open_context; + ib_cq_handle_t h_cq; + + AL_ENTER( AL_DBG_CQ ); + + /* Validate input buffers. */ + if( !cl_ioctl_in_buf( h_ioctl ) || !cl_ioctl_out_buf( h_ioctl ) || + cl_ioctl_in_size( h_ioctl ) != sizeof(p_ioctl->in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(p_ioctl->out) ) + { + AL_EXIT( AL_DBG_CQ ); + return CL_INVALID_PARAMETER; + } + + /* Set the return bytes in all cases */ + *p_ret_bytes = sizeof(p_ioctl->out); + + /* Validate CQ handle */ + h_cq = (ib_cq_handle_t) + al_hdl_ref( p_context->h_al, p_ioctl->in.h_cq, AL_OBJ_TYPE_H_CQ ); + if( !h_cq ) + { + p_ioctl->out.status = IB_INVALID_CQ_HANDLE; + p_ioctl->out.n_cqes = 0; + AL_EXIT( AL_DBG_CQ ); + return CL_SUCCESS; + } + + p_ioctl->out.status = ib_peek_cq( h_cq, &p_ioctl->out.n_cqes ); + + deref_al_obj( &h_cq->obj ); + + AL_EXIT( AL_DBG_CQ ); + return CL_SUCCESS; +} + + + +/* + * Process the ioctl UAL_POLL_CQ + */ +static cl_status_t +proxy_poll_cq( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_poll_cq_ioctl_t *p_ioctl; + al_dev_open_context_t *p_context; + ib_cq_handle_t h_cq; + ib_wc_t *p_free_wc; + ib_wc_t *p_done_wc = NULL; + uint32_t i, num_wc; + size_t out_buf_sz; + ib_api_status_t status; + + AL_ENTER( AL_DBG_CQ ); + + p_ioctl = (ual_poll_cq_ioctl_t*)cl_ioctl_in_buf( h_ioctl ); + p_context = (al_dev_open_context_t*)p_open_context; + + /* Validate input buffers. */ + if( !cl_ioctl_in_buf( h_ioctl ) || !cl_ioctl_out_buf( h_ioctl ) || + cl_ioctl_in_size( h_ioctl ) != sizeof(p_ioctl->in) || + cl_ioctl_out_size( h_ioctl ) < sizeof(p_ioctl->out) ) + { + AL_EXIT( AL_DBG_CQ ); + return CL_INVALID_PARAMETER; + } + + /* + * Additional validation of input and output sizes. + * Note that this also checks that work completions are actually + * being passed in. + */ + out_buf_sz = sizeof(p_ioctl->out); + out_buf_sz += sizeof(ib_wc_t) * (p_ioctl->in.num_wc - 1); + if( cl_ioctl_out_size( h_ioctl ) != out_buf_sz ) + { + AL_EXIT( AL_DBG_CQ ); + return CL_INVALID_PARAMETER; + } + + /* Validate CQ handle. */ + h_cq = (ib_cq_handle_t) + al_hdl_ref( p_context->h_al, p_ioctl->in.h_cq, AL_OBJ_TYPE_H_CQ ); + if( !h_cq ) + { + status = IB_INVALID_CQ_HANDLE; + goto proxy_poll_cq_err; + } + + p_free_wc = p_ioctl->out.wc; + num_wc = p_ioctl->in.num_wc; + for( i = 0; i < num_wc; i++ ) + p_free_wc[i].p_next = &p_free_wc[i+1]; + p_free_wc[i - 1].p_next = NULL; + + status = ib_poll_cq( h_cq, &p_free_wc, &p_done_wc ); + + /* + * If any of the completions are done, copy to user + * otherwise, just return + */ + if( status == IB_SUCCESS ) + { + CL_ASSERT( p_done_wc ); + /* Calculate the number of WCs. */ + if( !p_free_wc ) + { + p_ioctl->out.num_wc = num_wc; + } + else + { + p_ioctl->out.num_wc = (uint32_t) + (((uintn_t)p_free_wc) - ((uintn_t)p_done_wc)) / + sizeof(ib_wc_t); + } + } + else + { +proxy_poll_cq_err: + p_ioctl->out.num_wc = 0; + } + + if( h_cq ) + deref_al_obj( &h_cq->obj ); + + p_ioctl->out.status = status; + *p_ret_bytes = sizeof(p_ioctl->out) - sizeof(ib_wc_t); + if( p_ioctl->out.num_wc ) + *p_ret_bytes += (sizeof(ib_wc_t) * (p_ioctl->out.num_wc)); + + AL_EXIT( AL_DBG_CQ ); + return CL_SUCCESS; +} + + + +/* + * Process the ioctl UAL_REARM_CQ + */ +static cl_status_t +proxy_rearm_cq( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_rearm_cq_ioctl_t *p_ioctl = + (ual_rearm_cq_ioctl_t *)cl_ioctl_in_buf( h_ioctl ); + al_dev_open_context_t *p_context = + (al_dev_open_context_t *)p_open_context; + ib_cq_handle_t h_cq; + + AL_ENTER( AL_DBG_CQ ); + + /* Validate input buffers. */ + if( !cl_ioctl_in_buf( h_ioctl ) || !cl_ioctl_out_buf( h_ioctl ) || + cl_ioctl_in_size( h_ioctl ) != sizeof(p_ioctl->in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(p_ioctl->out) ) + { + AL_EXIT( AL_DBG_CQ ); + return CL_INVALID_PARAMETER; + } + + /* Set the return bytes in all cases */ + *p_ret_bytes = sizeof(p_ioctl->out); + + /* Validate CQ handle */ + h_cq = (ib_cq_handle_t) + al_hdl_ref( p_context->h_al, p_ioctl->in.h_cq, AL_OBJ_TYPE_H_CQ ); + if( !h_cq ) + { + p_ioctl->out.status = IB_INVALID_CQ_HANDLE; + AL_EXIT( AL_DBG_CQ ); + return CL_SUCCESS; + } + + p_ioctl->out.status = ib_rearm_cq( h_cq, p_ioctl->in.solicited ); + + deref_al_obj( &h_cq->obj ); + + AL_EXIT( AL_DBG_CQ ); + return CL_SUCCESS; +} + + + +/* + * Process the ioctl UAL_REARM_N_CQ + */ +static +cl_status_t +proxy_rearm_n_cq( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_rearm_n_cq_ioctl_t *p_ioctl = + (ual_rearm_n_cq_ioctl_t *)cl_ioctl_in_buf( h_ioctl ); + al_dev_open_context_t *p_context = + (al_dev_open_context_t *)p_open_context; + ib_cq_handle_t h_cq; + + AL_ENTER( AL_DBG_CQ ); + + /* Validate input buffers. */ + if( !cl_ioctl_in_buf( h_ioctl ) || !cl_ioctl_out_buf( h_ioctl ) || + cl_ioctl_in_size( h_ioctl ) != sizeof(p_ioctl->in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(p_ioctl->out) ) + { + AL_EXIT( AL_DBG_CQ ); + return CL_INVALID_PARAMETER; + } + + /* Set the return bytes in all cases */ + *p_ret_bytes = sizeof(p_ioctl->out); + + /* Validate CQ handle */ + h_cq = (ib_cq_handle_t) + al_hdl_ref( p_context->h_al, p_ioctl->in.h_cq, AL_OBJ_TYPE_H_CQ ); + if( !h_cq ) + { + p_ioctl->out.status = IB_INVALID_CQ_HANDLE; + AL_EXIT( AL_DBG_CQ ); + return CL_SUCCESS; + } + + p_ioctl->out.status = ib_rearm_n_cq( h_cq, p_ioctl->in.n_cqes ); + + deref_al_obj( &h_cq->obj ); + + AL_EXIT( AL_DBG_CQ ); + return CL_SUCCESS; +} + + + +/* + * Process the ioctl UAL_REGISTER_MEM: + */ +static cl_status_t +proxy_register_mr( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_reg_mem_ioctl_t *p_ioctl = + (ual_reg_mem_ioctl_t *)cl_ioctl_in_buf( h_ioctl ); + al_dev_open_context_t *p_context = + (al_dev_open_context_t *)p_open_context; + ib_pd_handle_t h_pd; + ib_mr_handle_t h_mr; + ib_api_status_t status; + + AL_ENTER( AL_DBG_MR ); + + /* Validate input buffers. */ + if( !cl_ioctl_in_buf( h_ioctl ) || !cl_ioctl_out_buf( h_ioctl ) || + cl_ioctl_in_size( h_ioctl ) != sizeof(p_ioctl->in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(p_ioctl->out) ) + { + AL_EXIT( AL_DBG_MR ); + return CL_INVALID_PARAMETER; + } + + /* Validate PD handle */ + h_pd = (ib_pd_handle_t) + al_hdl_ref( p_context->h_al, p_ioctl->in.h_pd, AL_OBJ_TYPE_H_PD ); + if( !h_pd ) + { + status = IB_INVALID_PD_HANDLE; + goto proxy_register_mr_err; + } + + /* Validate input region size. */ + if( p_ioctl->in.mem_create.length > ~((size_t)0) ) + { + status = IB_INVALID_SETTING; + goto proxy_register_mr_err; + } + + status = reg_mem( h_pd, &p_ioctl->in.mem_create, &p_ioctl->out.lkey, + &p_ioctl->out.rkey, &h_mr, TRUE ); + + if( status == IB_SUCCESS ) + { + p_ioctl->out.h_mr = h_mr->obj.hdl; + h_mr->obj.hdl_valid = TRUE; + deref_al_obj( &h_mr->obj ); + } + else + { +proxy_register_mr_err: + p_ioctl->out.h_mr = AL_INVALID_HANDLE; + p_ioctl->out.lkey = 0; + p_ioctl->out.rkey = 0; + } + + if( h_pd ) + deref_al_obj( &h_pd->obj ); + + p_ioctl->out.status = status; + *p_ret_bytes = sizeof(p_ioctl->out); + + AL_EXIT( AL_DBG_MR ); + return CL_SUCCESS; +} + + + +/* + * Process the ioctl UAL_QUERY_MEM: + */ +static cl_status_t +proxy_query_mr( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_query_mr_ioctl_t *p_ioctl = + (ual_query_mr_ioctl_t *)cl_ioctl_in_buf( h_ioctl ); + al_dev_open_context_t *p_context = + (al_dev_open_context_t *)p_open_context; + ib_mr_handle_t h_mr; + ib_api_status_t status; + + AL_ENTER( AL_DBG_MR ); + + /* Validate input buffers. */ + if( !cl_ioctl_in_buf( h_ioctl ) || !cl_ioctl_out_buf( h_ioctl ) || + cl_ioctl_in_size( h_ioctl ) != sizeof(p_ioctl->in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(p_ioctl->out) ) + { + AL_EXIT( AL_DBG_MR ); + return CL_INVALID_PARAMETER; + } + + /* Validate MR handle */ + h_mr = (ib_mr_handle_t) + al_hdl_ref( p_context->h_al, p_ioctl->in.h_mr, AL_OBJ_TYPE_H_MR ); + if( !h_mr ) + { + status = IB_INVALID_MR_HANDLE; + goto proxy_query_mr_err; + } + + status = ib_query_mr( h_mr, &p_ioctl->out.attr ); + + if( status == IB_SUCCESS ) + { + /* Replace the pd handle with proxy's handle */ + p_ioctl->out.attr.h_pd_padding = p_ioctl->out.attr.h_pd->obj.hdl; + } + else + { +proxy_query_mr_err: + cl_memclr( &p_ioctl->out.attr, sizeof(ib_mr_attr_t) ); + } + + if( h_mr ) + deref_al_obj( &h_mr->obj ); + + p_ioctl->out.status = status; + *p_ret_bytes = sizeof(p_ioctl->out); + + AL_EXIT( AL_DBG_MR ); + return CL_SUCCESS; +} + + + +/* + * Process the ioctl UAL_MODIFY_MEM: + */ +static cl_status_t +proxy_modify_mr( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_rereg_mem_ioctl_t *p_ioctl = + (ual_rereg_mem_ioctl_t *)cl_ioctl_in_buf( h_ioctl ); + al_dev_open_context_t *p_context = + (al_dev_open_context_t *)p_open_context; + ib_mr_handle_t h_mr; + ib_pd_handle_t h_pd = NULL; + ib_mr_create_t *p_mr_create; + ib_api_status_t status; + + AL_ENTER( AL_DBG_MR ); + + /* Validate input buffers. */ + if( !cl_ioctl_in_buf( h_ioctl ) || !cl_ioctl_out_buf( h_ioctl ) || + cl_ioctl_in_size( h_ioctl ) != sizeof(p_ioctl->in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(p_ioctl->out) ) + { + AL_EXIT( AL_DBG_MR ); + return CL_INVALID_PARAMETER; + } + + /* Validate MR handle */ + h_mr = (ib_mr_handle_t) + al_hdl_ref( p_context->h_al, p_ioctl->in.h_mr, AL_OBJ_TYPE_H_MR ); + if( !h_mr ) + { + status = IB_INVALID_MR_HANDLE; + goto proxy_modify_mr_err; + } + + /* Validate input region size. */ + if( p_ioctl->in.mem_create.length > ~((size_t)0) ) + { + status = IB_INVALID_SETTING; + goto proxy_modify_mr_err; + } + + if( p_ioctl->in.mem_mod_mask & IB_MR_MOD_PD ) + { + if( !p_ioctl->in.h_pd ) + { + status = IB_INVALID_PD_HANDLE; + goto proxy_modify_mr_err; + } + /* This is a modify PD request, validate the PD handle */ + h_pd = (ib_pd_handle_t) + al_hdl_ref( p_context->h_al, p_ioctl->in.h_pd, AL_OBJ_TYPE_H_PD ); + if( !h_pd ) + { + status = IB_INVALID_PD_HANDLE; + goto proxy_modify_mr_err; + } + } + else + { + h_pd = NULL; + } + + if( p_ioctl->in.mem_mod_mask != IB_MR_MOD_PD ) + p_mr_create = &p_ioctl->in.mem_create; + else + p_mr_create = NULL; + + status = rereg_mem( h_mr, p_ioctl->in.mem_mod_mask, + p_mr_create, &p_ioctl->out.lkey, &p_ioctl->out.rkey, h_pd, TRUE ); + + if( status != IB_SUCCESS ) + { +proxy_modify_mr_err: + p_ioctl->out.lkey = 0; + p_ioctl->out.rkey = 0; + } + + if( h_pd ) + deref_al_obj( &h_pd->obj ); + + if( h_mr ) + deref_al_obj( &h_mr->obj ); + + p_ioctl->out.status = status; + *p_ret_bytes = sizeof(p_ioctl->out); + + AL_EXIT( AL_DBG_MR ); + return CL_SUCCESS; +} + + + +/* + * Process the ioctl UAL_REG_SHARED_MEM: + */ +static cl_status_t +proxy_shared_mr( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_reg_shared_ioctl_t *p_ioctl = + (ual_reg_shared_ioctl_t *)cl_ioctl_in_buf( h_ioctl ); + al_dev_open_context_t *p_context = + (al_dev_open_context_t *)p_open_context; + ib_pd_handle_t h_pd; + ib_mr_handle_t h_mr, h_cur_mr; + ib_api_status_t status; + uint64_t vaddr; + + AL_ENTER( AL_DBG_MR ); + + /* Validate input buffers. */ + if( !cl_ioctl_in_buf( h_ioctl ) || !cl_ioctl_out_buf( h_ioctl ) || + cl_ioctl_in_size( h_ioctl ) != sizeof(p_ioctl->in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(p_ioctl->out) ) + { + AL_EXIT( AL_DBG_MR ); + return CL_INVALID_PARAMETER; + } + + /* + * TODO: Must support taking an input handle that isn't + * in this process's context. + */ + /* Validate MR handle */ + h_cur_mr = (ib_mr_handle_t) + al_hdl_ref( p_context->h_al, p_ioctl->in.h_mr, AL_OBJ_TYPE_H_MR ); + if( !h_cur_mr ) + { + h_pd = NULL; + status = IB_INVALID_MR_HANDLE; + goto proxy_shared_mr_err; + } + + /* Validate the PD handle */ + h_pd = (ib_pd_handle_t) + al_hdl_ref( p_context->h_al, p_ioctl->in.h_pd, AL_OBJ_TYPE_H_PD ); + if( !h_pd ) + { + status = IB_INVALID_PD_HANDLE; + goto proxy_shared_mr_err; + } + + vaddr = p_ioctl->in.vaddr; + status = reg_shared( h_cur_mr, h_pd, + p_ioctl->in.access_ctrl, &vaddr, &p_ioctl->out.lkey, + &p_ioctl->out.rkey, &h_mr, TRUE ); + + if( status == IB_SUCCESS ) + { + p_ioctl->out.h_new_mr = h_mr->obj.hdl; + p_ioctl->out.vaddr = vaddr; + h_mr->obj.hdl_valid = TRUE; + deref_al_obj( &h_mr->obj ); + } + else + { +proxy_shared_mr_err: + cl_memclr( &p_ioctl->out, sizeof(p_ioctl->out) ); + } + + if( h_pd ) + deref_al_obj( &h_pd->obj ); + + if( h_cur_mr ) + deref_al_obj( &h_cur_mr->obj ); + + p_ioctl->out.status = status; + *p_ret_bytes = sizeof(p_ioctl->out); + + AL_EXIT( AL_DBG_MR ); + return CL_SUCCESS; +} + + + +/* + * Process the ioctl UAL_DEREGISTER_MEM: + */ +static cl_status_t +proxy_deregister_mr( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_dereg_mr_ioctl_t *p_ioctl = + (ual_dereg_mr_ioctl_t *)cl_ioctl_in_buf( h_ioctl ); + al_dev_open_context_t *p_context = + (al_dev_open_context_t *)p_open_context; + ib_mr_handle_t h_mr; + + AL_ENTER( AL_DBG_MR ); + + /* Validate input buffers. */ + if( !cl_ioctl_in_buf( h_ioctl ) || !cl_ioctl_out_buf( h_ioctl ) || + cl_ioctl_in_size( h_ioctl ) != sizeof(p_ioctl->in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(p_ioctl->out) ) + { + AL_EXIT( AL_DBG_MR ); + return CL_INVALID_PARAMETER; + } + + /* Set the return bytes in all cases */ + *p_ret_bytes = sizeof(p_ioctl->out); + + /* Validate MR handle */ + h_mr = (ib_mr_handle_t) + al_hdl_ref( p_context->h_al, p_ioctl->in.h_mr, AL_OBJ_TYPE_H_MR ); + if( !h_mr ) + { + p_ioctl->out.status = IB_INVALID_MR_HANDLE; + AL_EXIT( AL_DBG_MR ); + return CL_SUCCESS; + } + + p_ioctl->out.status = dereg_mr( h_mr ); + + if( p_ioctl->out.status != IB_SUCCESS ) + deref_al_obj( &h_mr->obj ); + + AL_EXIT( AL_DBG_MR ); + return CL_SUCCESS; +} + + + +/* + * Process the ioctl UAL_CREATE_MW: + */ +static cl_status_t +proxy_create_mw( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_create_mw_ioctl_t *p_ioctl = + (ual_create_mw_ioctl_t *)cl_ioctl_in_buf( h_ioctl ); + al_dev_open_context_t *p_context = + (al_dev_open_context_t *)p_open_context; + ib_pd_handle_t h_pd; + ib_mw_handle_t h_mw; + ci_umv_buf_t *p_umv_buf = NULL; + ib_api_status_t status; + + AL_ENTER( AL_DBG_MW ); + + /* Validate input buffers. */ + if( !cl_ioctl_in_buf( h_ioctl ) || !cl_ioctl_out_buf( h_ioctl ) || + cl_ioctl_in_size( h_ioctl ) != sizeof(p_ioctl->in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(p_ioctl->out) ) + { + AL_EXIT( AL_DBG_MW ); + return CL_INVALID_PARAMETER; + } + + /* Validate PD handle */ + h_pd = (ib_pd_handle_t) + al_hdl_ref( p_context->h_al, p_ioctl->in.h_pd, AL_OBJ_TYPE_H_PD ); + if( !h_pd ) + { + status = IB_INVALID_PD_HANDLE; + goto proxy_create_mw_err; + } + + status = cpyin_umvbuf( &p_ioctl->in.umv_buf, &p_umv_buf ); + if( status != IB_SUCCESS ) + goto proxy_create_mw_err; + + status = create_mw( h_pd, &p_ioctl->out.rkey, &h_mw, p_umv_buf ); + if( status != IB_SUCCESS ) + goto proxy_create_mw_err; + + status = cpyout_umvbuf( &p_ioctl->out.umv_buf, p_umv_buf ); + if( status == IB_SUCCESS ) + { + p_ioctl->out.h_mw = h_mw->obj.hdl; + h_mw->obj.hdl_valid = TRUE; + deref_al_obj( &h_mw->obj ); + } + else + { + h_mw->obj.pfn_destroy( &h_mw->obj, NULL ); + +proxy_create_mw_err: + p_ioctl->out.umv_buf = p_ioctl->in.umv_buf; + p_ioctl->out.rkey = 0; + p_ioctl->out.h_mw = AL_INVALID_HANDLE; + } + free_umvbuf( p_umv_buf ); + + if( h_pd ) + deref_al_obj( &h_pd->obj ); + + p_ioctl->out.status = status; + *p_ret_bytes = sizeof(p_ioctl->out); + + AL_EXIT( AL_DBG_MW ); + return CL_SUCCESS; +} + + + +/* + * Process the ioctl UAL_QUERY_MW: + */ +static cl_status_t +proxy_query_mw( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_query_mw_ioctl_t *p_ioctl = + (ual_query_mw_ioctl_t *)cl_ioctl_in_buf( h_ioctl ); + al_dev_open_context_t *p_context = + (al_dev_open_context_t *)p_open_context; + ib_mw_handle_t h_mw; + ci_umv_buf_t *p_umv_buf = NULL; + ib_api_status_t status; + ib_pd_handle_t h_pd; + + AL_ENTER( AL_DBG_MW ); + + /* Validate input buffers. */ + if( !cl_ioctl_in_buf( h_ioctl ) || !cl_ioctl_out_buf( h_ioctl ) || + cl_ioctl_in_size( h_ioctl ) != sizeof(p_ioctl->in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(p_ioctl->out) ) + { + AL_EXIT( AL_DBG_MW ); + return CL_INVALID_PARAMETER; + } + + /* Validate MW handle */ + h_mw = (ib_mw_handle_t) + al_hdl_ref( p_context->h_al, p_ioctl->in.h_mw, AL_OBJ_TYPE_H_MW ); + if( !h_mw ) + { + status = IB_INVALID_MW_HANDLE; + goto proxy_query_mw_err; + } + + status = cpyin_umvbuf( &p_ioctl->in.umv_buf, &p_umv_buf ); + if( status != IB_SUCCESS ) + goto proxy_query_mw_err; + + status = query_mw( h_mw, &h_pd, &p_ioctl->out.rkey, p_umv_buf ); + + if( status != IB_SUCCESS ) + goto proxy_query_mw_err; + + status = cpyout_umvbuf( &p_ioctl->out.umv_buf, p_umv_buf ); + if( status != IB_SUCCESS ) + { +proxy_query_mw_err: + p_ioctl->out.umv_buf = p_ioctl->in.umv_buf; + p_ioctl->out.rkey = 0; + } + free_umvbuf( p_umv_buf ); + + if( h_mw ) + deref_al_obj( &h_mw->obj ); + + p_ioctl->out.status = status; + *p_ret_bytes = sizeof(p_ioctl->out); + + AL_EXIT( AL_DBG_MW ); + return CL_SUCCESS; +} + + + +/* + * Process the ioctl UAL_BIND_MW: + */ +static cl_status_t +proxy_bind_mw( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_bind_mw_ioctl_t *p_ioctl = + (ual_bind_mw_ioctl_t *)cl_ioctl_in_buf( h_ioctl ); + al_dev_open_context_t *p_context = + (al_dev_open_context_t *)p_open_context; + ib_mw_handle_t h_mw; + ib_qp_handle_t h_qp; + ib_mr_handle_t h_mr; + ib_api_status_t status; + + AL_ENTER( AL_DBG_MW ); + + /* Validate input buffers. */ + if( !cl_ioctl_in_buf( h_ioctl ) || !cl_ioctl_out_buf( h_ioctl ) || + cl_ioctl_in_size( h_ioctl ) != sizeof(p_ioctl->in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(p_ioctl->out) ) + { + AL_EXIT( AL_DBG_MW ); + return CL_INVALID_PARAMETER; + } + + /* Validate MW handle */ + h_mw = (ib_mw_handle_t) + al_hdl_ref( p_context->h_al, p_ioctl->in.h_mw, AL_OBJ_TYPE_H_MW ); + if( !h_mw ) + { + status = IB_INVALID_MW_HANDLE; + goto proxy_bind_mw_err1; + } + + /* Validate QP handle */ + h_qp = (ib_qp_handle_t) + al_hdl_ref( p_context->h_al, p_ioctl->in.h_qp, AL_OBJ_TYPE_H_QP ); + if( !h_qp ) + { + status = IB_INVALID_QP_HANDLE; + goto proxy_bind_mw_err2; + } + + /* Validate MR handle */ + h_mr = (ib_mr_handle_t)al_hdl_ref( p_context->h_al, + p_ioctl->in.mw_bind.h_mr_padding, AL_OBJ_TYPE_H_MR ); + if( !h_mr ) + { + status = IB_INVALID_MR_HANDLE; + goto proxy_bind_mw_err3; + } + + /* Update bind attribute with the kernel space handles */ + p_ioctl->in.mw_bind.h_mr = h_mr; + + status = ib_bind_mw( h_mw, h_qp, + &p_ioctl->in.mw_bind, &p_ioctl->out.r_key ); + + deref_al_obj( &h_mr->obj ); +proxy_bind_mw_err3: + deref_al_obj( &h_qp->obj ); +proxy_bind_mw_err2: + deref_al_obj( &h_mw->obj ); +proxy_bind_mw_err1: + + if( status != IB_SUCCESS ) + p_ioctl->out.r_key = 0; + + p_ioctl->out.status = status; + *p_ret_bytes = sizeof(p_ioctl->out); + + AL_EXIT( AL_DBG_MW ); + return CL_SUCCESS; +} + + + +/* + * Process the ioctl UAL_DESTROY_MW: + */ +static cl_status_t +proxy_destroy_mw( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_destroy_mw_ioctl_t *p_ioctl = + (ual_destroy_mw_ioctl_t *)cl_ioctl_in_buf( h_ioctl ); + al_dev_open_context_t *p_context = + (al_dev_open_context_t *)p_open_context; + ib_mw_handle_t h_mw; + + AL_ENTER( AL_DBG_MW ); + + /* Validate input buffers. */ + if( !cl_ioctl_in_buf( h_ioctl ) || !cl_ioctl_out_buf( h_ioctl ) || + cl_ioctl_in_size( h_ioctl ) != sizeof(p_ioctl->in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(p_ioctl->out) ) + { + AL_EXIT( AL_DBG_MW ); + return CL_INVALID_PARAMETER; + } + + /* Set the return bytes in all cases */ + *p_ret_bytes = sizeof(p_ioctl->out); + + /* Validate MW handle */ + h_mw = (ib_mw_handle_t) + al_hdl_ref( p_context->h_al, p_ioctl->in.h_mw, AL_OBJ_TYPE_H_MW ); + if( !h_mw ) + { + p_ioctl->out.status = IB_INVALID_MW_HANDLE; + AL_EXIT( AL_DBG_MW ); + return CL_SUCCESS; + } + p_ioctl->out.status = destroy_mw( h_mw ); + + if( p_ioctl->out.status != IB_SUCCESS ) + deref_al_obj( &h_mw->obj ); + + AL_EXIT( AL_DBG_MW ); + return CL_SUCCESS; +} + + +cl_status_t +proxy_get_spl_qp( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_spl_qp_ioctl_t *p_ioctl = + (ual_spl_qp_ioctl_t *)cl_ioctl_in_buf( h_ioctl ); + al_dev_open_context_t *p_context = + (al_dev_open_context_t *)p_open_context; + ib_pd_handle_t h_pd; + ib_qp_handle_t h_qp; + ci_umv_buf_t *p_umv_buf = NULL; + ib_api_status_t status; + + AL_ENTER( AL_DBG_QP ); + + /* Validate input buffers. */ + if( !cl_ioctl_in_buf( h_ioctl ) || !cl_ioctl_out_buf( h_ioctl ) || + cl_ioctl_in_size( h_ioctl ) != sizeof(p_ioctl->in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(p_ioctl->out) ) + { + AL_EXIT( AL_DBG_QP ); + return CL_INVALID_PARAMETER; + } + + /* Validate pd handle */ + h_pd = (ib_pd_handle_t) + al_hdl_ref( p_context->h_al, p_ioctl->in.h_pd, AL_OBJ_TYPE_H_PD ); + if( !h_pd ) + { + status = IB_INVALID_PD_HANDLE; + goto proxy_get_spl_qp_err; + } + + status = cpyin_umvbuf( &p_ioctl->in.umv_buf, &p_umv_buf ); + if( status != IB_SUCCESS ) + goto proxy_get_spl_qp_err; + + /* We obtain the pool_key separately from the special QP. */ + status = get_spl_qp( h_pd, p_ioctl->in.port_guid, + &p_ioctl->in.qp_create, (void*)(ULONG_PTR)p_ioctl->in.context, + proxy_qp_err_cb, NULL, &h_qp, p_umv_buf ); + if( status != IB_SUCCESS ) + goto proxy_get_spl_qp_err; + + status = cpyout_umvbuf( &p_ioctl->out.umv_buf, p_umv_buf ); + if( status == IB_SUCCESS ) + { + p_ioctl->out.h_qp = h_qp->obj.hdl; + h_qp->obj.hdl_valid = TRUE; + deref_al_obj( &h_qp->obj ); + } + else + { + h_qp->obj.pfn_destroy( &h_qp->obj, NULL ); + +proxy_get_spl_qp_err: + p_ioctl->out.umv_buf = p_ioctl->in.umv_buf; + p_ioctl->out.h_qp = AL_INVALID_HANDLE; + } + free_umvbuf( p_umv_buf ); + + if( h_pd ) + deref_al_obj( &h_pd->obj ); + + p_ioctl->out.status = status; + *p_ret_bytes = sizeof(p_ioctl->out); + + AL_EXIT( AL_DBG_QP ); + return CL_SUCCESS; +} + + + +static cl_status_t +proxy_attach_mcast( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_attach_mcast_ioctl_t *p_ioctl = + (ual_attach_mcast_ioctl_t *)cl_ioctl_in_buf( h_ioctl ); + al_dev_open_context_t *p_context = + (al_dev_open_context_t *)p_open_context; + ib_qp_handle_t h_qp; + al_attach_handle_t h_attach; + ci_umv_buf_t *p_umv_buf = NULL; + ib_api_status_t status; + + AL_ENTER( AL_DBG_MCAST ); + + /* Validate input buffers. */ + if( !cl_ioctl_in_buf( h_ioctl ) || !cl_ioctl_out_buf( h_ioctl ) || + cl_ioctl_in_size( h_ioctl ) != sizeof(p_ioctl->in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(p_ioctl->out) ) + { + AL_EXIT( AL_DBG_MCAST ); + return CL_INVALID_PARAMETER; + } + + /* Validate QP handle */ + h_qp = (ib_qp_handle_t) + al_hdl_ref( p_context->h_al, p_ioctl->in.h_qp, AL_OBJ_TYPE_H_QP ); + if( !h_qp ) + { + status = IB_INVALID_QP_HANDLE; + goto proxy_attach_mcast_err; + } + + status = cpyin_umvbuf( &p_ioctl->in.umv_buf, &p_umv_buf ); + if( status != IB_SUCCESS ) + goto proxy_attach_mcast_err; + + status = al_attach_mcast( h_qp, &p_ioctl->in.mgid, + p_ioctl->in.mlid, &h_attach, p_umv_buf ); + if( status != IB_SUCCESS ) + goto proxy_attach_mcast_err; + + status = cpyout_umvbuf( &p_ioctl->out.umv_buf, p_umv_buf ); + if( status == IB_SUCCESS ) + { + p_ioctl->out.h_attach = h_attach->obj.hdl; + h_attach->obj.hdl_valid = TRUE; + deref_al_obj( &h_attach->obj ); + } + else + { + h_attach->obj.pfn_destroy( &h_attach->obj, NULL ); + +proxy_attach_mcast_err: + p_ioctl->out.umv_buf = p_ioctl->in.umv_buf; + p_ioctl->out.h_attach = AL_INVALID_HANDLE; + } + free_umvbuf( p_umv_buf ); + + if( h_qp ) + deref_al_obj( &h_qp->obj ); + + p_ioctl->out.status = status; + *p_ret_bytes = sizeof(p_ioctl->out); + + AL_EXIT( AL_DBG_MCAST ); + return CL_SUCCESS; +} + + + +static cl_status_t +proxy_detach_mcast( + IN void *p_open_context, + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + ual_detach_mcast_ioctl_t *p_ioctl = + (ual_detach_mcast_ioctl_t *)cl_ioctl_in_buf( h_ioctl ); + al_dev_open_context_t *p_context = + (al_dev_open_context_t *)p_open_context; + al_attach_handle_t h_attach; + + AL_ENTER( AL_DBG_MCAST ); + + /* Validate input buffers. */ + if( !cl_ioctl_in_buf( h_ioctl ) || !cl_ioctl_out_buf( h_ioctl ) || + cl_ioctl_in_size( h_ioctl ) != sizeof(p_ioctl->in) || + cl_ioctl_out_size( h_ioctl ) != sizeof(p_ioctl->out) ) + { + AL_EXIT( AL_DBG_MCAST ); + return CL_INVALID_PARAMETER; + } + + /* Set the return bytes in all cases */ + *p_ret_bytes = sizeof(p_ioctl->out); + + /* Validate mcast handle */ + h_attach = (al_attach_handle_t)al_hdl_ref( + p_context->h_al, p_ioctl->in.h_attach, AL_OBJ_TYPE_H_ATTACH ); + if( !h_attach ) + { + p_ioctl->out.status = IB_INVALID_MCAST_HANDLE; + AL_EXIT( AL_DBG_MCAST ); + return CL_SUCCESS; + } + + h_attach->obj.pfn_destroy( &h_attach->obj, ib_sync_destroy ); + p_ioctl->out.status = IB_SUCCESS; + + AL_EXIT( AL_DBG_MCAST ); + return CL_SUCCESS; +} + + + +cl_status_t +verbs_ioctl( + IN cl_ioctl_handle_t h_ioctl, + OUT size_t *p_ret_bytes ) +{ + cl_status_t cl_status; + IO_STACK_LOCATION *p_io_stack; + void *p_context; + + AL_ENTER( AL_DBG_DEV ); + + p_io_stack = IoGetCurrentIrpStackLocation( h_ioctl ); + p_context = p_io_stack->FileObject->FsContext; + + if( !p_context ) + { + AL_EXIT( AL_DBG_DEV ); + return CL_INVALID_PARAMETER; + } + + switch( cl_ioctl_ctl_code( h_ioctl ) ) + { + case UAL_OPEN_CA: + cl_status = proxy_open_ca( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_QUERY_CA: + cl_status = proxy_query_ca( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_MODIFY_CA: + cl_status = proxy_modify_ca( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_CI_CALL: + cl_status = proxy_ci_call( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_ALLOC_PD: + cl_status = proxy_alloc_pd( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_CREATE_AV: + cl_status = proxy_create_av( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_QUERY_AV: + cl_status = proxy_query_av( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_MODIFY_AV: + cl_status = proxy_modify_av( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_CREATE_SRQ: + cl_status = proxy_create_srq( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_QUERY_SRQ: + cl_status = proxy_query_srq( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_MODIFY_SRQ: + cl_status = proxy_modify_srq( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_DESTROY_SRQ: + cl_status = proxy_destroy_srq( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_POST_SRQ_RECV: + cl_status = proxy_post_srq_recv( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_CREATE_QP: + cl_status = proxy_create_qp( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_QUERY_QP: + cl_status = proxy_query_qp( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_MODIFY_QP: + cl_status = proxy_modify_qp( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_CREATE_CQ: + cl_status = proxy_create_cq( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_QUERY_CQ: + cl_status = proxy_query_cq( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_MODIFY_CQ: + cl_status = proxy_modify_cq( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_REG_MR: + cl_status = proxy_register_mr( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_QUERY_MR: + cl_status = proxy_query_mr( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_MODIFY_MR: + cl_status = proxy_modify_mr( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_REG_SHARED: + cl_status = proxy_shared_mr( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_CREATE_MW: + cl_status = proxy_create_mw( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_QUERY_MW: + cl_status = proxy_query_mw( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_BIND_MW: + cl_status = proxy_bind_mw( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_POST_SEND: + cl_status = proxy_post_send( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_POST_RECV: + cl_status = proxy_post_recv( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_PEEK_CQ: + cl_status = proxy_peek_cq( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_POLL_CQ: + cl_status = proxy_poll_cq( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_REARM_CQ: + cl_status = proxy_rearm_cq( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_REARM_N_CQ: + cl_status = proxy_rearm_n_cq( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_ATTACH_MCAST: + cl_status = proxy_attach_mcast( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_GET_SPL_QP_ALIAS: + cl_status = proxy_get_spl_qp( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_CLOSE_CA: + cl_status = proxy_close_ca( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_DEALLOC_PD: + cl_status = proxy_dealloc_pd( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_DESTROY_AV: + cl_status = proxy_destroy_av( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_DESTROY_QP: + cl_status = proxy_destroy_qp( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_DESTROY_CQ: + cl_status = proxy_destroy_cq( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_DEREG_MR: + cl_status = proxy_deregister_mr( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_DESTROY_MW: + cl_status = proxy_destroy_mw( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_DETACH_MCAST: + cl_status = proxy_detach_mcast( p_context, h_ioctl, p_ret_bytes ); + break; + case UAL_GET_VENDOR_LIBCFG: + cl_status = + proxy_get_vendor_libcfg( p_context, h_ioctl, p_ret_bytes ); + break; + default: + cl_status = CL_INVALID_PARAMETER; + break; + } + + AL_EXIT( AL_DBG_DEV ); + return cl_status; +} diff --git a/branches/WOF2-3/core/al/kernel/al_sa_req.c b/branches/WOF2-3/core/al/kernel/al_sa_req.c new file mode 100644 index 00000000..05418d76 --- /dev/null +++ b/branches/WOF2-3/core/al/kernel/al_sa_req.c @@ -0,0 +1,812 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include +#include + +#include "al.h" +#include "al_ca.h" +#include "al_common.h" +#include "al_debug.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "al_sa_req.tmh" +#endif +#include "al_mgr.h" +#include "al_query.h" +#include "ib_common.h" + + +/* Global SA request manager */ +typedef struct _sa_req_mgr +{ + al_obj_t obj; /* Child of gp_al_mgr */ + ib_pnp_handle_t h_pnp; /* Handle for CA PnP events */ + +} sa_req_mgr_t; + + +static sa_req_mgr_t *gp_sa_req_mgr = NULL; + + + +/* + * Function prototypes. + */ +void +destroying_sa_req_mgr( + IN al_obj_t* p_obj ); + +void +free_sa_req_mgr( + IN al_obj_t* p_obj ); + +ib_api_status_t +sa_req_mgr_pnp_cb( + IN ib_pnp_rec_t* p_pnp_rec ); + +ib_api_status_t +create_sa_req_svc( + IN ib_pnp_port_rec_t* p_pnp_rec ); + +void +destroying_sa_req_svc( + IN al_obj_t* p_obj ); + +void +free_sa_req_svc( + IN al_obj_t* p_obj ); + +ib_api_status_t +init_sa_req_svc( + IN sa_req_svc_t* p_sa_req_svc, + IN const ib_pnp_port_rec_t *p_pnp_rec ); + +void +sa_req_send_comp_cb( + IN const ib_mad_svc_handle_t h_mad_svc, + IN void *mad_svc_context, + IN ib_mad_element_t *p_mad ); + +void +sa_req_recv_comp_cb( + IN const ib_mad_svc_handle_t h_mad_svc, + IN void *mad_svc_context, + IN ib_mad_element_t *p_mad ); + +void +sa_req_svc_event_cb( + IN ib_async_event_rec_t *p_event_rec ); + + +/* + * Create the sa_req manager. + */ +ib_api_status_t +create_sa_req_mgr( + IN al_obj_t* const p_parent_obj ) +{ + ib_pnp_req_t pnp_req; + ib_api_status_t status; + + AL_ENTER( AL_DBG_SA_REQ ); + CL_ASSERT( p_parent_obj ); + CL_ASSERT( gp_sa_req_mgr == NULL ); + + gp_sa_req_mgr = cl_zalloc( sizeof( sa_req_mgr_t ) ); + if( gp_sa_req_mgr == NULL ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("cl_zalloc failed\n") ); + return IB_INSUFFICIENT_MEMORY; + } + + /* Construct the sa_req manager. */ + construct_al_obj( &gp_sa_req_mgr->obj, AL_OBJ_TYPE_SA_REQ_SVC ); + + /* Initialize the global sa_req manager object. */ + status = init_al_obj( &gp_sa_req_mgr->obj, gp_sa_req_mgr, TRUE, + destroying_sa_req_mgr, NULL, free_sa_req_mgr ); + if( status != IB_SUCCESS ) + { + free_sa_req_mgr( &gp_sa_req_mgr->obj ); + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("cl_spinlock_init failed\n") ); + return status; + } + status = attach_al_obj( p_parent_obj, &gp_sa_req_mgr->obj ); + if( status != IB_SUCCESS ) + { + gp_sa_req_mgr->obj.pfn_destroy( &gp_sa_req_mgr->obj, NULL ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("attach_al_obj returned %s.\n", ib_get_err_str(status)) ); + return status; + } + + /* Register for CA PnP events. */ + cl_memclr( &pnp_req, sizeof( ib_pnp_req_t ) ); + pnp_req.pnp_class = IB_PNP_PORT; + pnp_req.pnp_context = &gp_sa_req_mgr->obj; + pnp_req.pfn_pnp_cb = sa_req_mgr_pnp_cb; + + status = ib_reg_pnp( gh_al, &pnp_req, &gp_sa_req_mgr->h_pnp ); + if (status != IB_SUCCESS) + { + gp_sa_req_mgr->obj.pfn_destroy( &gp_sa_req_mgr->obj, NULL ); + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("ib_reg_pnp failed: %s\n", ib_get_err_str( status ) ) ); + return status; + } + + /* + * Note that we don't release the reference from init_al_obj because + * we need a reference on behalf of the ib_reg_pnp call. This avoids + * a call to ref_al_obj and deref_al_obj. + */ + + AL_EXIT( AL_DBG_SA_REQ ); + return IB_SUCCESS; +} + + + +/* + * Pre-destroy the sa_req manager. + */ +void +destroying_sa_req_mgr( + IN al_obj_t* p_obj ) +{ + ib_api_status_t status; + + CL_ASSERT( p_obj ); + CL_ASSERT( gp_sa_req_mgr == PARENT_STRUCT( p_obj, sa_req_mgr_t, obj ) ); + UNUSED_PARAM( p_obj ); + + /* Deregister for PnP events. */ + if( gp_sa_req_mgr->h_pnp ) + { + status = ib_dereg_pnp( gp_sa_req_mgr->h_pnp, + (ib_pfn_destroy_cb_t)deref_al_obj ); + CL_ASSERT( status == IB_SUCCESS ); + } +} + + + +/* + * Free the sa_req manager. + */ +void +free_sa_req_mgr( + IN al_obj_t* p_obj ) +{ + CL_ASSERT( p_obj ); + CL_ASSERT( gp_sa_req_mgr == PARENT_STRUCT( p_obj, sa_req_mgr_t, obj ) ); + UNUSED_PARAM( p_obj ); + + destroy_al_obj( &gp_sa_req_mgr->obj ); + cl_free( gp_sa_req_mgr ); + gp_sa_req_mgr = NULL; +} + + + +/* + * SA request manager PnP event callback. + */ +ib_api_status_t +sa_req_mgr_pnp_cb( + IN ib_pnp_rec_t* p_pnp_rec ) +{ + sa_req_svc_t *p_sa_req_svc; + ib_av_attr_t av_attr; + ib_pd_handle_t h_pd; + ib_api_status_t status; + + AL_ENTER( AL_DBG_SA_REQ ); + CL_ASSERT( p_pnp_rec ); + CL_ASSERT( p_pnp_rec->pnp_context == &gp_sa_req_mgr->obj ); + + /* Dispatch based on the PnP event type. */ + switch( p_pnp_rec->pnp_event ) + { + case IB_PNP_PORT_ADD: + status = create_sa_req_svc( (ib_pnp_port_rec_t*)p_pnp_rec ); + if( status != IB_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("create_sa_req_svc failed: %s\n", ib_get_err_str(status)) ); + } + break; + + case IB_PNP_PORT_REMOVE: + CL_ASSERT( p_pnp_rec->context ); + p_sa_req_svc = p_pnp_rec->context; + ref_al_obj( &p_sa_req_svc->obj ); + p_sa_req_svc->obj.pfn_destroy( &p_sa_req_svc->obj, NULL ); + p_pnp_rec->context = NULL; + status = IB_SUCCESS; + break; + + case IB_PNP_PORT_ACTIVE: + case IB_PNP_SM_CHANGE: + CL_ASSERT( p_pnp_rec->context ); + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_SA_REQ, + ("updating SM information\n") ); + + p_sa_req_svc = p_pnp_rec->context; + p_sa_req_svc->sm_lid = + ((ib_pnp_port_rec_t*)p_pnp_rec)->p_port_attr->sm_lid; + p_sa_req_svc->sm_sl = + ((ib_pnp_port_rec_t*)p_pnp_rec)->p_port_attr->sm_sl; + + /* Update the address vector. */ + status = ib_query_av( p_sa_req_svc->h_av, &av_attr, &h_pd ); + if( status != IB_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("AV query failed: %s\n", ib_get_err_str(status)) ); + status = IB_SUCCESS; + break; + } + + av_attr.dlid = p_sa_req_svc->sm_lid; + av_attr.sl = p_sa_req_svc->sm_sl; + status = ib_modify_av( p_sa_req_svc->h_av, &av_attr ); + if( status != IB_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("modify AV failed: %s\n", ib_get_err_str(status) ) ); + status = IB_SUCCESS; + break; + } + break; + + case IB_PNP_PORT_INIT: + case IB_PNP_PORT_ARMED: + case IB_PNP_PORT_DOWN: + CL_ASSERT( p_pnp_rec->context ); + p_sa_req_svc = p_pnp_rec->context; + p_sa_req_svc->sm_lid = 0; + p_sa_req_svc->sm_sl = 0; + + default: + status = IB_SUCCESS; + break; + } + AL_EXIT( AL_DBG_SA_REQ ); + return status; +} + + + +/* + * Create an sa_req service. + */ +ib_api_status_t +create_sa_req_svc( + IN ib_pnp_port_rec_t* p_pnp_rec ) +{ + sa_req_svc_t* p_sa_req_svc; + ib_api_status_t status; + + AL_ENTER( AL_DBG_SA_REQ ); + CL_ASSERT( p_pnp_rec ); + CL_ASSERT( p_pnp_rec->p_ca_attr ); + CL_ASSERT( p_pnp_rec->p_port_attr ); + + p_sa_req_svc = cl_zalloc( sizeof( sa_req_svc_t ) ); + if( p_sa_req_svc == NULL ) + return IB_INSUFFICIENT_MEMORY; + + /* Construct the sa_req service object. */ + construct_al_obj( &p_sa_req_svc->obj, AL_OBJ_TYPE_SA_REQ_SVC ); + + /* Initialize the sa_req service object. */ + status = init_al_obj( &p_sa_req_svc->obj, p_sa_req_svc, TRUE, + destroying_sa_req_svc, NULL, free_sa_req_svc ); + if( status != IB_SUCCESS ) + { + free_sa_req_svc( &p_sa_req_svc->obj ); + return status; + } + + /* Attach to the sa_req_mgr. */ + status = attach_al_obj( &gp_sa_req_mgr->obj, &p_sa_req_svc->obj ); + if( status != IB_SUCCESS ) + { + p_sa_req_svc->obj.pfn_destroy( &p_sa_req_svc->obj, NULL ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("attach_al_obj returned %s.\n", ib_get_err_str(status)) ); + return status; + } + + /* Allocate a QP alias and MAD service to send queries on. */ + status = init_sa_req_svc( p_sa_req_svc, p_pnp_rec ); + if( status != IB_SUCCESS ) + { + p_sa_req_svc->obj.pfn_destroy( &p_sa_req_svc->obj, NULL ); + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("init_sa_req_svc failed: %s\n", ib_get_err_str(status) ) ); + return status; + } + + /* Set the context of the PnP event to this child object. */ + p_pnp_rec->pnp_rec.context = p_sa_req_svc; + + /* Release the reference taken in init_al_obj. */ + deref_al_obj( &p_sa_req_svc->obj ); + + AL_EXIT( AL_DBG_SA_REQ ); + return IB_SUCCESS; +} + + + +/* + * Pre-destroy a sa_req service. + */ +void +destroying_sa_req_svc( + IN al_obj_t* p_obj ) +{ + sa_req_svc_t* p_sa_req_svc; + ib_api_status_t status; + + CL_ASSERT( p_obj ); + p_sa_req_svc = PARENT_STRUCT( p_obj, sa_req_svc_t, obj ); + + /* Destroy the AV. */ + if( p_sa_req_svc->h_av ) + ib_destroy_av( p_sa_req_svc->h_av ); + + /* Destroy the QP. */ + if( p_sa_req_svc->h_qp ) + { + status = ib_destroy_qp( p_sa_req_svc->h_qp, + (ib_pfn_destroy_cb_t)deref_al_obj ); + CL_ASSERT( status == IB_SUCCESS ); + } +} + + + +/* + * Free a sa_req service. + */ +void +free_sa_req_svc( + IN al_obj_t* p_obj ) +{ + sa_req_svc_t* p_sa_req_svc; + + CL_ASSERT( p_obj ); + p_sa_req_svc = PARENT_STRUCT( p_obj, sa_req_svc_t, obj ); + + destroy_al_obj( p_obj ); + cl_free( p_sa_req_svc ); +} + + + +/* + * Initialize an sa_req service. + */ +ib_api_status_t +init_sa_req_svc( + IN sa_req_svc_t *p_sa_req_svc, + IN const ib_pnp_port_rec_t *p_pnp_rec ) +{ + ib_qp_create_t qp_create; + ib_mad_svc_t mad_svc; + ib_api_status_t status; + ib_ca_handle_t h_ca; + ib_av_attr_t av_attr; + + AL_ENTER( AL_DBG_SA_REQ ); + CL_ASSERT( p_sa_req_svc && p_pnp_rec ); + + /* Acquire the correct CI CA for this port. */ + h_ca = acquire_ca( p_pnp_rec->p_ca_attr->ca_guid ); + if( !h_ca ) + { + AL_PRINT_EXIT( TRACE_LEVEL_INFORMATION, AL_DBG_SA_REQ, ("Failed to acquire CA\n") ); + return IB_INVALID_GUID; + } + p_sa_req_svc->obj.p_ci_ca = h_ca->obj.p_ci_ca; + + /* Record which port this service operates on. */ + p_sa_req_svc->port_guid = p_pnp_rec->p_port_attr->port_guid; + p_sa_req_svc->port_num = p_pnp_rec->p_port_attr->port_num; + p_sa_req_svc->sm_lid = p_pnp_rec->p_port_attr->sm_lid; + p_sa_req_svc->sm_sl = p_pnp_rec->p_port_attr->sm_sl; + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_SA_REQ, + ("using port: 0x%x\tsm lid: 0x%x\tsm sl: 0x%x\n", + p_sa_req_svc->port_num, p_sa_req_svc->sm_lid, p_sa_req_svc->sm_sl) ); + + /* Create the QP. */ + cl_memclr( &qp_create, sizeof( ib_qp_create_t ) ); + qp_create.qp_type = IB_QPT_QP1_ALIAS; + qp_create.sq_depth = p_pnp_rec->p_ca_attr->max_wrs; + qp_create.rq_depth = 0; + qp_create.sq_sge = 1; + qp_create.rq_sge = 0; + qp_create.h_sq_cq = NULL; + qp_create.h_rq_cq = NULL; + qp_create.sq_signaled = TRUE; + + status = ib_get_spl_qp( h_ca->obj.p_ci_ca->h_pd_alias, + p_sa_req_svc->port_guid, &qp_create, p_sa_req_svc, + sa_req_svc_event_cb, &p_sa_req_svc->pool_key, &p_sa_req_svc->h_qp ); + + /* + * Release the CI CA once we've allocated the QP. The CI CA will not + * go away while we hold the QP. + */ + deref_al_obj( &h_ca->obj ); + + /* Check for failure allocating the QP. */ + if( status != IB_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("failed to create QP1 alias: %s\n", ib_get_err_str(status) ) ); + return status; + } + + /* Reference the sa_req service on behalf of QP alias. */ + ref_al_obj( &p_sa_req_svc->obj ); + + /* Create a MAD service. */ + cl_memclr( &mad_svc, sizeof( ib_mad_svc_t ) ); + mad_svc.mad_svc_context = p_sa_req_svc; + mad_svc.pfn_mad_send_cb = sa_req_send_comp_cb; + mad_svc.pfn_mad_recv_cb = sa_req_recv_comp_cb; + + status = ib_reg_mad_svc( p_sa_req_svc->h_qp, &mad_svc, + &p_sa_req_svc->h_mad_svc ); + if( status != IB_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("failed to register MAD service: %s\n", ib_get_err_str(status) ) ); + return status; + } + + /* Create an address vector for the SA. */ + av_attr.port_num = p_sa_req_svc->port_num; + av_attr.sl = p_sa_req_svc->sm_sl; + av_attr.dlid = cl_hton16(1); + av_attr.grh_valid = FALSE; + av_attr.static_rate = IB_PATH_RECORD_RATE_10_GBS; + av_attr.path_bits = 0; + + status = ib_create_av( p_sa_req_svc->obj.p_ci_ca->h_pd_alias, + &av_attr, &p_sa_req_svc->h_av ); + if( status != IB_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("failed to create AV: %s\n", ib_get_err_str(status) ) ); + return status; + } + + AL_EXIT( AL_DBG_SA_REQ ); + return IB_SUCCESS; +} + + + +/* + * SA request service asynchronous event callback. Our QP is an alias, + * so if we've received an error, the QP is unusable. + */ +void +sa_req_svc_event_cb( + IN ib_async_event_rec_t *p_event_rec ) +{ + sa_req_svc_t *p_sa_req_svc; + + CL_ASSERT( p_event_rec ); + CL_ASSERT( p_event_rec->context ); + + p_sa_req_svc = p_event_rec->context; + ref_al_obj( &p_sa_req_svc->obj ); + p_sa_req_svc->obj.pfn_destroy( &p_sa_req_svc->obj, NULL ); +} + + + +/* + * Acquire the sa_req service for the given port. + */ +static sa_req_svc_t* +acquire_sa_req_svc( + IN const ib_net64_t port_guid ) +{ + cl_list_item_t *p_list_item; + sa_req_svc_t *p_sa_req_svc; + al_obj_t *p_obj; + + CL_ASSERT( gp_sa_req_mgr ); + + /* Search for the sa_req service for the given port. */ + cl_spinlock_acquire( &gp_sa_req_mgr->obj.lock ); + for( p_list_item = cl_qlist_head( &gp_sa_req_mgr->obj.obj_list ); + p_list_item != cl_qlist_end( &gp_sa_req_mgr->obj.obj_list ); + p_list_item = cl_qlist_next( p_list_item ) ) + { + p_obj = PARENT_STRUCT( p_list_item, al_obj_t, pool_item ); + p_sa_req_svc = PARENT_STRUCT( p_obj, sa_req_svc_t, obj ); + + /* Make sure that the REQ service isn't being destroyed. */ + if( p_sa_req_svc->obj.state != CL_INITIALIZED || !p_sa_req_svc->sm_lid ) + continue; + + /* Check for a port match. */ + if( p_sa_req_svc->port_guid == port_guid ) + { + /* Reference the service on behalf of the client. */ + ref_al_obj( &p_sa_req_svc->obj ); + cl_spinlock_release( &gp_sa_req_mgr->obj.lock ); + return p_sa_req_svc; + } + } + cl_spinlock_release( &gp_sa_req_mgr->obj.lock ); + + return NULL; +} + + + +ib_api_status_t +al_send_sa_req( + IN al_sa_req_t *p_sa_req, + IN const net64_t port_guid, + IN const uint32_t timeout_ms, + IN const uint32_t retry_cnt, + IN const ib_user_query_t* const p_sa_req_data, + IN const ib_al_flags_t flags ) +{ + ib_api_status_t status; + sa_req_svc_t *p_sa_req_svc; + ib_mad_element_t *p_mad_request; + ib_mad_t *p_mad_hdr; + ib_sa_mad_t *p_sa_mad; + KEVENT event; + + AL_ENTER( AL_DBG_SA_REQ ); + + if( flags & IB_FLAGS_SYNC ) + { + if( !cl_is_blockable() ) + { + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("Thread context not blockable\n") ); + return IB_INVALID_SETTING; + } + + KeInitializeEvent( &event, NotificationEvent, FALSE ); + p_sa_req->p_sync_event = &event; + } + else + { + p_sa_req->p_sync_event = NULL; + } + + /* Locate the sa_req service to issue the sa_req on. */ + p_sa_req->p_sa_req_svc = acquire_sa_req_svc( port_guid ); + if( !p_sa_req->p_sa_req_svc ) + { + AL_PRINT_EXIT( TRACE_LEVEL_INFORMATION, AL_DBG_QUERY, ("invalid port GUID %#I64x\n", port_guid) ); + return IB_INVALID_GUID; + } + + /* Get a MAD element for the send request. */ + p_sa_req_svc = p_sa_req->p_sa_req_svc; + status = ib_get_mad( p_sa_req_svc->pool_key, MAD_BLOCK_SIZE, + &p_mad_request ); + if( status != IB_SUCCESS ) + { + deref_al_obj( &p_sa_req_svc->obj ); + AL_EXIT( AL_DBG_SA_REQ ); + return status; + } + + /* Store the MAD request so it can be cancelled. */ + p_sa_req->p_mad_request = p_mad_request; + + /* Initialize the MAD buffer for the send operation. */ + p_mad_hdr = p_sa_req->p_mad_request->p_mad_buf; + p_sa_mad = (ib_sa_mad_t*)p_mad_hdr; + + /* Initialize the standard MAD header. */ + ib_mad_init_new( p_mad_hdr, IB_MCLASS_SUBN_ADM, (uint8_t)2, + p_sa_req_data->method, + cl_hton64( (uint64_t)cl_atomic_inc( &p_sa_req_svc->trans_id ) ), + 0, 0 ); + + /* Set the query information. */ + p_sa_mad->attr_id = p_sa_req_data->attr_id; + p_sa_mad->attr_offset = ib_get_attr_offset( p_sa_req_data->attr_size ); + p_sa_mad->comp_mask = p_sa_req_data->comp_mask; + /* + * Most set operations don't use the component mask. + * Check the method and copy the attributes if it's a set too. + */ + if( p_sa_mad->comp_mask || p_sa_mad->method == IB_MAD_METHOD_SET ) + { + cl_memcpy( p_sa_mad->data, p_sa_req_data->p_attr, + p_sa_req_data->attr_size ); + } + + /* Set the MAD element information. */ + p_mad_request->context1 = p_sa_req; + p_mad_request->send_context1 = p_sa_req; + p_mad_request->remote_qp = IB_QP1; + p_mad_request->h_av = p_sa_req_svc->h_av; + p_mad_request->send_opt = 0; + p_mad_request->remote_qkey = IB_QP1_WELL_KNOWN_Q_KEY; + p_mad_request->resp_expected = TRUE; + p_mad_request->timeout_ms = timeout_ms; + p_mad_request->retry_cnt = retry_cnt; + + status = ib_send_mad( p_sa_req_svc->h_mad_svc, p_mad_request, NULL ); + if( status != IB_SUCCESS ) + { + p_sa_req->p_mad_request = NULL; + ib_put_mad( p_mad_request ); + deref_al_obj( &p_sa_req->p_sa_req_svc->obj ); + } + else if( flags & IB_FLAGS_SYNC ) + { + /* Wait for the MAD completion. */ + KeWaitForSingleObject( &event, Executive, KernelMode, FALSE, NULL ); + } + + AL_EXIT( AL_DBG_SA_REQ ); + return status; +} + + + +/* + * SA request send completion callback. + */ +void +sa_req_send_comp_cb( + IN const ib_mad_svc_handle_t h_mad_svc, + IN void *mad_svc_context, + IN ib_mad_element_t *p_request_mad ) +{ + al_sa_req_t *p_sa_req; + sa_req_svc_t *p_sa_req_svc; + KEVENT *p_sync_event; + + AL_ENTER( AL_DBG_SA_REQ ); + + UNUSED_PARAM( h_mad_svc ); + UNUSED_PARAM( mad_svc_context ); + + /* + * Check the result of the send operation. If the send was successful, + * we will be getting a receive callback with the response. + */ + if( p_request_mad->status != IB_WCS_SUCCESS ) + { + /* Notify the requestor of the result. */ + AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_QUERY, + ("request failed - notifying user\n") ); + + p_sa_req = p_request_mad->send_context1; + p_sa_req_svc = p_sa_req->p_sa_req_svc; + p_sync_event = p_sa_req->p_sync_event; + + p_sa_req->status = convert_wc_status( p_request_mad->status ); + p_sa_req->pfn_sa_req_cb( p_sa_req, NULL ); + if( p_sync_event ) + KeSetEvent( p_sync_event, 0, FALSE ); + deref_al_obj( &p_sa_req_svc->obj ); + } + + /* Return the MAD. */ + ib_put_mad( p_request_mad ); + + AL_EXIT( AL_DBG_SA_REQ ); +} + + + +/* + * SA request receive completion callback. + */ +void +sa_req_recv_comp_cb( + IN const ib_mad_svc_handle_t h_mad_svc, + IN void *mad_svc_context, + IN ib_mad_element_t *p_mad_response ) +{ + al_sa_req_t *p_sa_req; + sa_req_svc_t *p_sa_req_svc; + ib_sa_mad_t *p_sa_mad; + KEVENT *p_sync_event; + + AL_ENTER( AL_DBG_SA_REQ ); + + UNUSED_PARAM( h_mad_svc ); + UNUSED_PARAM( mad_svc_context ); + + p_sa_req = p_mad_response->send_context1; + p_sa_req_svc = p_sa_req->p_sa_req_svc; + p_sync_event = p_sa_req->p_sync_event; + + //*** check for SA redirection... + + /* Record the results of the request. */ + p_sa_mad = (ib_sa_mad_t*)ib_get_mad_buf( p_mad_response ); + if( p_sa_mad->status == IB_SA_MAD_STATUS_SUCCESS ) + p_sa_req->status = IB_SUCCESS; + else + p_sa_req->status = IB_REMOTE_ERROR; + + /* Notify the requestor of the result. */ + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_SA_REQ, ("notifying user\n") ); + p_sa_req->pfn_sa_req_cb( p_sa_req, p_mad_response ); + if( p_sync_event ) + KeSetEvent( p_sync_event, 0, FALSE ); + deref_al_obj( &p_sa_req_svc->obj ); + + AL_EXIT( AL_DBG_SA_REQ ); +} + + + +ib_api_status_t +convert_wc_status( + IN const ib_wc_status_t wc_status ) +{ + switch( wc_status ) + { + case IB_WCS_SUCCESS: + return IB_SUCCESS; + + case IB_WCS_TIMEOUT_RETRY_ERR: + return IB_TIMEOUT; + + case IB_WCS_CANCELED: + return IB_CANCELED; + + default: + return IB_ERROR; + } +} diff --git a/branches/WOF2-3/core/al/kernel/al_smi.c b/branches/WOF2-3/core/al/kernel/al_smi.c new file mode 100644 index 00000000..43bd54e9 --- /dev/null +++ b/branches/WOF2-3/core/al/kernel/al_smi.c @@ -0,0 +1,3770 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Copyright (c) 2006 Voltaire Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include +#include + +#include "ib_common.h" +#include "al_common.h" +#include "al_debug.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "al_smi.tmh" +#endif +#include "al_verbs.h" +#include "al_mgr.h" +#include "al_pnp.h" +#include "al_qp.h" +#include "al_smi.h" +#include "al_av.h" + + +extern char node_desc[IB_NODE_DESCRIPTION_SIZE]; + +#define SMI_POLL_INTERVAL 20000 /* Milliseconds */ +#define LOCAL_MAD_TIMEOUT 50 /* Milliseconds */ +#define DEFAULT_QP0_DEPTH 256 +#define DEFAULT_QP1_DEPTH 1024 + +uint32_t g_smi_poll_interval = SMI_POLL_INTERVAL; +spl_qp_mgr_t* gp_spl_qp_mgr = NULL; + + +/* + * Function prototypes. + */ +void +destroying_spl_qp_mgr( + IN al_obj_t* p_obj ); + +void +free_spl_qp_mgr( + IN al_obj_t* p_obj ); + +ib_api_status_t +spl_qp0_agent_pnp_cb( + IN ib_pnp_rec_t* p_pnp_rec ); + +ib_api_status_t +spl_qp1_agent_pnp_cb( + IN ib_pnp_rec_t* p_pnp_rec ); + +ib_api_status_t +spl_qp_agent_pnp( + IN ib_pnp_rec_t* p_pnp_rec, + IN ib_qp_type_t qp_type ); + +ib_api_status_t +create_spl_qp_svc( + IN ib_pnp_port_rec_t* p_pnp_rec, + IN const ib_qp_type_t qp_type ); + +void +destroying_spl_qp_svc( + IN al_obj_t* p_obj ); + +void +free_spl_qp_svc( + IN al_obj_t* p_obj ); + +void +spl_qp_svc_lid_change( + IN al_obj_t* p_obj, + IN ib_pnp_port_rec_t* p_pnp_rec ); + +ib_api_status_t +remote_mad_send( + IN spl_qp_svc_t* p_spl_qp_svc, + IN al_mad_wr_t* const p_mad_wr ); + +static ib_api_status_t +local_mad_send( + IN spl_qp_svc_t* p_spl_qp_svc, + IN al_mad_wr_t* const p_mad_wr ); + +static ib_api_status_t +loopback_mad( + IN spl_qp_svc_t* p_spl_qp_svc, + IN al_mad_wr_t* const p_mad_wr ); + +static ib_api_status_t +__process_subn_mad( + IN spl_qp_svc_t* p_spl_qp_svc, + IN al_mad_wr_t* const p_mad_wr ); + +static ib_api_status_t +fwd_local_mad( + IN spl_qp_svc_t* p_spl_qp_svc, + IN al_mad_wr_t* const p_mad_wr ); + +void +send_local_mad_cb( + IN cl_async_proc_item_t* p_item ); + +void +spl_qp_send_comp_cb( + IN const ib_cq_handle_t h_cq, + IN void *cq_context ); + +void +spl_qp_send_dpc_cb( + IN KDPC *p_dpc, + IN void *context, + IN void *arg1, + IN void *arg2 + ); + +void +spl_qp_recv_dpc_cb( + IN KDPC *p_dpc, + IN void *context, + IN void *arg1, + IN void *arg2 + ); + +void +spl_qp_recv_comp_cb( + IN const ib_cq_handle_t h_cq, + IN void *cq_context ); + +void +spl_qp_comp( + IN spl_qp_svc_t* p_spl_qp_svc, + IN const ib_cq_handle_t h_cq, + IN ib_wc_type_t wc_type ); + +ib_api_status_t +process_mad_recv( + IN spl_qp_svc_t* p_spl_qp_svc, + IN ib_mad_element_t* p_mad_element ); + +static mad_route_t +route_recv_smp( + IN ib_mad_element_t* p_mad_element ); + +static mad_route_t +route_recv_smp_attr( + IN ib_mad_element_t* p_mad_element ); + +mad_route_t +route_recv_dm_mad( + IN ib_mad_element_t* p_mad_element ); + +static mad_route_t +route_recv_bm( + IN ib_mad_element_t* p_mad_element ); + +static mad_route_t +route_recv_perf( + IN ib_mad_element_t* p_mad_element ); + +static mad_route_t +route_recv_vendor( + IN ib_mad_element_t* p_mad_element ); + +ib_api_status_t +forward_sm_trap( + IN spl_qp_svc_t* p_spl_qp_svc, + IN ib_mad_element_t* p_mad_element ); + +ib_api_status_t +recv_local_mad( + IN spl_qp_svc_t* p_spl_qp_svc, + IN ib_mad_element_t* p_mad_request ); + +void +spl_qp_alias_send_cb( + IN ib_mad_svc_handle_t h_mad_svc, + IN void *mad_svc_context, + IN ib_mad_element_t *p_mad_element ); + +void +spl_qp_alias_recv_cb( + IN ib_mad_svc_handle_t h_mad_svc, + IN void *mad_svc_context, + IN ib_mad_element_t *p_mad_response ); + +static ib_api_status_t +spl_qp_svc_post_recvs( + IN spl_qp_svc_t* const p_spl_qp_svc ); + +void +spl_qp_svc_event_cb( + IN ib_async_event_rec_t *p_event_rec ); + +void +spl_qp_alias_event_cb( + IN ib_async_event_rec_t *p_event_rec ); + +void +spl_qp_svc_reset( + IN spl_qp_svc_t* p_spl_qp_svc ); + +void +spl_qp_svc_reset_cb( + IN cl_async_proc_item_t* p_item ); + +ib_api_status_t +acquire_svc_disp( + IN const cl_qmap_t* const p_svc_map, + IN const ib_net64_t port_guid, + OUT al_mad_disp_handle_t *ph_mad_disp ); + +void +smi_poll_timer_cb( + IN void* context ); + +void +smi_post_recvs( + IN cl_list_item_t* const p_list_item, + IN void* context ); + +#if defined( CL_USE_MUTEX ) +void +spl_qp_send_async_cb( + IN cl_async_proc_item_t* p_item ); + +void +spl_qp_recv_async_cb( + IN cl_async_proc_item_t* p_item ); +#endif + +/* + * Create the special QP manager. + */ +ib_api_status_t +create_spl_qp_mgr( + IN al_obj_t* const p_parent_obj ) +{ + ib_pnp_req_t pnp_req; + ib_api_status_t status; + cl_status_t cl_status; + + AL_ENTER( AL_DBG_SMI ); + + CL_ASSERT( p_parent_obj ); + CL_ASSERT( !gp_spl_qp_mgr ); + + gp_spl_qp_mgr = cl_zalloc( sizeof( spl_qp_mgr_t ) ); + if( !gp_spl_qp_mgr ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("IB_INSUFFICIENT_MEMORY\n") ); + return IB_INSUFFICIENT_MEMORY; + } + + /* Construct the special QP manager. */ + construct_al_obj( &gp_spl_qp_mgr->obj, AL_OBJ_TYPE_SMI ); + cl_timer_construct( &gp_spl_qp_mgr->poll_timer ); + + /* Initialize the lists. */ + cl_qmap_init( &gp_spl_qp_mgr->smi_map ); + cl_qmap_init( &gp_spl_qp_mgr->gsi_map ); + + /* Initialize the global SMI/GSI manager object. */ + status = init_al_obj( &gp_spl_qp_mgr->obj, gp_spl_qp_mgr, TRUE, + destroying_spl_qp_mgr, NULL, free_spl_qp_mgr ); + if( status != IB_SUCCESS ) + { + free_spl_qp_mgr( &gp_spl_qp_mgr->obj ); + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("init_al_obj failed, %s\n", ib_get_err_str( status ) ) ); + return status; + } + + /* Attach the special QP manager to the parent object. */ + status = attach_al_obj( p_parent_obj, &gp_spl_qp_mgr->obj ); + if( status != IB_SUCCESS ) + { + gp_spl_qp_mgr->obj.pfn_destroy( &gp_spl_qp_mgr->obj, NULL ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("attach_al_obj returned %s.\n", ib_get_err_str(status)) ); + return status; + } + + /* Initialize the SMI polling timer. */ + cl_status = cl_timer_init( &gp_spl_qp_mgr->poll_timer, smi_poll_timer_cb, + gp_spl_qp_mgr ); + if( cl_status != CL_SUCCESS ) + { + gp_spl_qp_mgr->obj.pfn_destroy( &gp_spl_qp_mgr->obj, NULL ); + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("cl_timer_init failed, status 0x%x\n", cl_status ) ); + return ib_convert_cl_status( cl_status ); + } + + /* + * Note: PnP registrations for port events must be done + * when the special QP manager is created. This ensures that + * the registrations are listed sequentially and the reporting + * of PnP events occurs in the proper order. + */ + + /* + * Separate context is needed for each special QP. Therefore, a + * separate PnP event registration is performed for QP0 and QP1. + */ + + /* Register for port PnP events for QP0. */ + cl_memclr( &pnp_req, sizeof( ib_pnp_req_t ) ); + pnp_req.pnp_class = IB_PNP_PORT; + pnp_req.pnp_context = &gp_spl_qp_mgr->obj; + pnp_req.pfn_pnp_cb = spl_qp0_agent_pnp_cb; + + status = ib_reg_pnp( gh_al, &pnp_req, &gp_spl_qp_mgr->h_qp0_pnp ); + + if( status != IB_SUCCESS ) + { + gp_spl_qp_mgr->obj.pfn_destroy( &gp_spl_qp_mgr->obj, NULL ); + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("ib_reg_pnp QP0 failed, %s\n", ib_get_err_str( status ) ) ); + return status; + } + + /* Reference the special QP manager on behalf of the ib_reg_pnp call. */ + ref_al_obj( &gp_spl_qp_mgr->obj ); + + /* Register for port PnP events for QP1. */ + cl_memclr( &pnp_req, sizeof( ib_pnp_req_t ) ); + pnp_req.pnp_class = IB_PNP_PORT; + pnp_req.pnp_context = &gp_spl_qp_mgr->obj; + pnp_req.pfn_pnp_cb = spl_qp1_agent_pnp_cb; + + status = ib_reg_pnp( gh_al, &pnp_req, &gp_spl_qp_mgr->h_qp1_pnp ); + + if( status != IB_SUCCESS ) + { + gp_spl_qp_mgr->obj.pfn_destroy( &gp_spl_qp_mgr->obj, NULL ); + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("ib_reg_pnp QP1 failed, %s\n", ib_get_err_str( status ) ) ); + return status; + } + + /* + * Note that we don't release the referende taken in init_al_obj + * because we need one on behalf of the ib_reg_pnp call. + */ + + AL_EXIT( AL_DBG_SMI ); + return IB_SUCCESS; +} + + + +/* + * Pre-destroy the special QP manager. + */ +void +destroying_spl_qp_mgr( + IN al_obj_t* p_obj ) +{ + ib_api_status_t status; + + CL_ASSERT( p_obj ); + CL_ASSERT( gp_spl_qp_mgr == PARENT_STRUCT( p_obj, spl_qp_mgr_t, obj ) ); + UNUSED_PARAM( p_obj ); + + /* Deregister for port PnP events for QP0. */ + if( gp_spl_qp_mgr->h_qp0_pnp ) + { + status = ib_dereg_pnp( gp_spl_qp_mgr->h_qp0_pnp, + (ib_pfn_destroy_cb_t)deref_al_obj ); + CL_ASSERT( status == IB_SUCCESS ); + } + + /* Deregister for port PnP events for QP1. */ + if( gp_spl_qp_mgr->h_qp1_pnp ) + { + status = ib_dereg_pnp( gp_spl_qp_mgr->h_qp1_pnp, + (ib_pfn_destroy_cb_t)deref_al_obj ); + CL_ASSERT( status == IB_SUCCESS ); + } + + /* Destroy the SMI polling timer. */ + cl_timer_destroy( &gp_spl_qp_mgr->poll_timer ); +} + + + +/* + * Free the special QP manager. + */ +void +free_spl_qp_mgr( + IN al_obj_t* p_obj ) +{ + CL_ASSERT( p_obj ); + CL_ASSERT( gp_spl_qp_mgr == PARENT_STRUCT( p_obj, spl_qp_mgr_t, obj ) ); + UNUSED_PARAM( p_obj ); + + destroy_al_obj( &gp_spl_qp_mgr->obj ); + cl_free( gp_spl_qp_mgr ); + gp_spl_qp_mgr = NULL; +} + + + +/* + * Special QP0 agent PnP event callback. + */ +ib_api_status_t +spl_qp0_agent_pnp_cb( + IN ib_pnp_rec_t* p_pnp_rec ) +{ + ib_api_status_t status; + AL_ENTER( AL_DBG_SMI ); + + status = spl_qp_agent_pnp( p_pnp_rec, IB_QPT_QP0 ); + + AL_EXIT( AL_DBG_SMI ); + return status; +} + + + +/* + * Special QP1 agent PnP event callback. + */ +ib_api_status_t +spl_qp1_agent_pnp_cb( + IN ib_pnp_rec_t* p_pnp_rec ) +{ + ib_api_status_t status; + AL_ENTER( AL_DBG_SMI ); + + status = spl_qp_agent_pnp( p_pnp_rec, IB_QPT_QP1 ); + + AL_EXIT( AL_DBG_SMI ); + return status; +} + + + +/* + * Special QP agent PnP event callback. + */ +ib_api_status_t +spl_qp_agent_pnp( + IN ib_pnp_rec_t* p_pnp_rec, + IN ib_qp_type_t qp_type ) +{ + ib_api_status_t status; + al_obj_t* p_obj; + + AL_ENTER( AL_DBG_SMI ); + + CL_ASSERT( p_pnp_rec ); + p_obj = p_pnp_rec->context; + + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_SMI, + ("p_pnp_rec->pnp_event = 0x%x (%s)\n", + p_pnp_rec->pnp_event, ib_get_pnp_event_str( p_pnp_rec->pnp_event )) ); + /* Dispatch based on the PnP event type. */ + switch( p_pnp_rec->pnp_event ) + { + case IB_PNP_PORT_ADD: + CL_ASSERT( !p_obj ); + status = create_spl_qp_svc( (ib_pnp_port_rec_t*)p_pnp_rec, qp_type ); + break; + + case IB_PNP_PORT_REMOVE: + CL_ASSERT( p_obj ); + ref_al_obj( p_obj ); + p_obj->pfn_destroy( p_obj, NULL ); + status = IB_SUCCESS; + break; + + case IB_PNP_LID_CHANGE: + CL_ASSERT( p_obj ); + spl_qp_svc_lid_change( p_obj, (ib_pnp_port_rec_t*)p_pnp_rec ); + status = IB_SUCCESS; + break; + + default: + /* All other events are ignored. */ + status = IB_SUCCESS; + break; + } + + AL_EXIT( AL_DBG_SMI ); + return status; +} + + + +/* + * Create a special QP service. + */ +ib_api_status_t +create_spl_qp_svc( + IN ib_pnp_port_rec_t* p_pnp_rec, + IN const ib_qp_type_t qp_type ) +{ + cl_status_t cl_status; + spl_qp_svc_t* p_spl_qp_svc; + ib_ca_handle_t h_ca; + ib_cq_create_t cq_create; + ib_qp_create_t qp_create; + ib_qp_attr_t qp_attr; + ib_mad_svc_t mad_svc; + ib_api_status_t status; + + AL_ENTER( AL_DBG_SMI ); + + CL_ASSERT( p_pnp_rec ); + + if( ( qp_type != IB_QPT_QP0 ) && ( qp_type != IB_QPT_QP1 ) ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + CL_ASSERT( p_pnp_rec->pnp_rec.pnp_context ); + CL_ASSERT( p_pnp_rec->p_ca_attr ); + CL_ASSERT( p_pnp_rec->p_port_attr ); + + p_spl_qp_svc = cl_zalloc( sizeof( spl_qp_svc_t ) ); + if( !p_spl_qp_svc ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("IB_INSUFFICIENT_MEMORY\n") ); + return IB_INSUFFICIENT_MEMORY; + } + + /* Tie the special QP service to the port by setting the port number. */ + p_spl_qp_svc->port_num = p_pnp_rec->p_port_attr->port_num; + /* Store the port GUID to allow faster lookups of the dispatchers. */ + p_spl_qp_svc->port_guid = p_pnp_rec->p_port_attr->port_guid; + + /* Initialize the send and receive queues. */ + cl_qlist_init( &p_spl_qp_svc->send_queue ); + cl_qlist_init( &p_spl_qp_svc->recv_queue ); + cl_spinlock_init(&p_spl_qp_svc->cache_lock); + + /* Initialize the DPCs. */ + KeInitializeDpc( &p_spl_qp_svc->send_dpc, spl_qp_send_dpc_cb, p_spl_qp_svc ); + KeInitializeDpc( &p_spl_qp_svc->recv_dpc, spl_qp_recv_dpc_cb, p_spl_qp_svc ); + + if( qp_type == IB_QPT_QP0 ) + { + KeSetImportanceDpc( &p_spl_qp_svc->send_dpc, HighImportance ); + KeSetImportanceDpc( &p_spl_qp_svc->recv_dpc, HighImportance ); + } + +#if defined( CL_USE_MUTEX ) + /* Initialize async callbacks and flags for send/receive processing. */ + p_spl_qp_svc->send_async_queued = FALSE; + p_spl_qp_svc->send_async_cb.pfn_callback = spl_qp_send_async_cb; + p_spl_qp_svc->recv_async_queued = FALSE; + p_spl_qp_svc->recv_async_cb.pfn_callback = spl_qp_recv_async_cb; +#endif + + /* Initialize the async callback function to process local sends. */ + p_spl_qp_svc->send_async.pfn_callback = send_local_mad_cb; + + /* Initialize the async callback function to reset the QP on error. */ + p_spl_qp_svc->reset_async.pfn_callback = spl_qp_svc_reset_cb; + + /* Construct the special QP service object. */ + construct_al_obj( &p_spl_qp_svc->obj, AL_OBJ_TYPE_SMI ); + + /* Initialize the special QP service object. */ + status = init_al_obj( &p_spl_qp_svc->obj, p_spl_qp_svc, TRUE, + destroying_spl_qp_svc, NULL, free_spl_qp_svc ); + if( status != IB_SUCCESS ) + { + free_spl_qp_svc( &p_spl_qp_svc->obj ); + return status; + } + + /* Attach the special QP service to the parent object. */ + status = attach_al_obj( + (al_obj_t*)p_pnp_rec->pnp_rec.pnp_context, &p_spl_qp_svc->obj ); + if( status != IB_SUCCESS ) + { + p_spl_qp_svc->obj.pfn_destroy( &p_spl_qp_svc->obj, NULL ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("attach_al_obj returned %s.\n", ib_get_err_str(status)) ); + return status; + } + + h_ca = acquire_ca( p_pnp_rec->p_ca_attr->ca_guid ); + CL_ASSERT( h_ca ); + if( !h_ca ) + { + p_spl_qp_svc->obj.pfn_destroy( &p_spl_qp_svc->obj, NULL ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("acquire_ca failed.\n") ); + return IB_INVALID_GUID; + } + + p_spl_qp_svc->obj.p_ci_ca = h_ca->obj.p_ci_ca; + + /* Determine the maximum queue depth of the QP and CQs. */ + p_spl_qp_svc->max_qp_depth = + ( p_pnp_rec->p_ca_attr->max_wrs < + p_pnp_rec->p_ca_attr->max_cqes ) ? + p_pnp_rec->p_ca_attr->max_wrs : + p_pnp_rec->p_ca_attr->max_cqes; + + /* Compare this maximum to the default special queue depth. */ + if( ( qp_type == IB_QPT_QP0 ) && + ( p_spl_qp_svc->max_qp_depth > DEFAULT_QP0_DEPTH ) ) + p_spl_qp_svc->max_qp_depth = DEFAULT_QP0_DEPTH; + if( ( qp_type == IB_QPT_QP1 ) && + ( p_spl_qp_svc->max_qp_depth > DEFAULT_QP1_DEPTH ) ) + p_spl_qp_svc->max_qp_depth = DEFAULT_QP1_DEPTH; + + /* Create the send CQ. */ + cl_memclr( &cq_create, sizeof( ib_cq_create_t ) ); + cq_create.size = p_spl_qp_svc->max_qp_depth; + cq_create.pfn_comp_cb = spl_qp_send_comp_cb; + + status = ib_create_cq( p_spl_qp_svc->obj.p_ci_ca->h_ca, &cq_create, + p_spl_qp_svc, spl_qp_svc_event_cb, &p_spl_qp_svc->h_send_cq ); + + if( status != IB_SUCCESS ) + { + p_spl_qp_svc->obj.pfn_destroy( &p_spl_qp_svc->obj, NULL ); + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("ib_create_cq send CQ failed, %s\n", ib_get_err_str( status ) ) ); + return status; + } + + /* Reference the special QP service on behalf of ib_create_cq. */ + ref_al_obj( &p_spl_qp_svc->obj ); + + /* Check the result of the creation request. */ + if( cq_create.size < p_spl_qp_svc->max_qp_depth ) + { + p_spl_qp_svc->obj.pfn_destroy( &p_spl_qp_svc->obj, NULL ); + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("ib_create_cq allocated insufficient send CQ size\n") ); + return IB_INSUFFICIENT_RESOURCES; + } + + /* Create the receive CQ. */ + cl_memclr( &cq_create, sizeof( ib_cq_create_t ) ); + cq_create.size = p_spl_qp_svc->max_qp_depth; + cq_create.pfn_comp_cb = spl_qp_recv_comp_cb; + + status = ib_create_cq( p_spl_qp_svc->obj.p_ci_ca->h_ca, &cq_create, + p_spl_qp_svc, spl_qp_svc_event_cb, &p_spl_qp_svc->h_recv_cq ); + + if( status != IB_SUCCESS ) + { + p_spl_qp_svc->obj.pfn_destroy( &p_spl_qp_svc->obj, NULL ); + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("ib_create_cq recv CQ failed, %s\n", ib_get_err_str( status ) ) ); + return status; + } + + /* Reference the special QP service on behalf of ib_create_cq. */ + ref_al_obj( &p_spl_qp_svc->obj ); + + /* Check the result of the creation request. */ + if( cq_create.size < p_spl_qp_svc->max_qp_depth ) + { + p_spl_qp_svc->obj.pfn_destroy( &p_spl_qp_svc->obj, NULL ); + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("ib_create_cq allocated insufficient recv CQ size\n") ); + return IB_INSUFFICIENT_RESOURCES; + } + + /* Create the special QP. */ + cl_memclr( &qp_create, sizeof( ib_qp_create_t ) ); + qp_create.qp_type = qp_type; + qp_create.sq_depth = p_spl_qp_svc->max_qp_depth; + qp_create.rq_depth = p_spl_qp_svc->max_qp_depth; + qp_create.sq_sge = 3; /* Three entries are required for segmentation. */ + qp_create.rq_sge = 1; + qp_create.h_sq_cq = p_spl_qp_svc->h_send_cq; + qp_create.h_rq_cq = p_spl_qp_svc->h_recv_cq; + qp_create.sq_signaled = TRUE; + + status = ib_get_spl_qp( p_spl_qp_svc->obj.p_ci_ca->h_pd, + p_pnp_rec->p_port_attr->port_guid, &qp_create, + p_spl_qp_svc, spl_qp_svc_event_cb, NULL, &p_spl_qp_svc->h_qp ); + + if( status != IB_SUCCESS ) + { + p_spl_qp_svc->obj.pfn_destroy( &p_spl_qp_svc->obj, NULL ); + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("ib_get_spl_qp failed, %s\n", ib_get_err_str( status ) ) ); + return status; + } + + /* Reference the special QP service on behalf of ib_get_spl_qp. */ + ref_al_obj( &p_spl_qp_svc->obj ); + + /* Check the result of the creation request. */ + status = ib_query_qp( p_spl_qp_svc->h_qp, &qp_attr ); + if( status != IB_SUCCESS ) + { + p_spl_qp_svc->obj.pfn_destroy( &p_spl_qp_svc->obj, NULL ); + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("ib_query_qp failed, %s\n", ib_get_err_str( status ) ) ); + return status; + } + + if( ( qp_attr.rq_depth < p_spl_qp_svc->max_qp_depth ) || + ( qp_attr.sq_depth < p_spl_qp_svc->max_qp_depth ) || + ( qp_attr.sq_sge < 3 ) || ( qp_attr.rq_sge < 1 ) ) + { + p_spl_qp_svc->obj.pfn_destroy( &p_spl_qp_svc->obj, NULL ); + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("ib_get_spl_qp allocated attributes are insufficient\n") ); + return IB_INSUFFICIENT_RESOURCES; + } + + /* Initialize the QP for use. */ + status = ib_init_dgrm_svc( p_spl_qp_svc->h_qp, NULL ); + if( status != IB_SUCCESS ) + { + p_spl_qp_svc->obj.pfn_destroy( &p_spl_qp_svc->obj, NULL ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("ib_init_dgrm_svc failed, %s\n", ib_get_err_str( status ) ) ); + return status; + } + + /* Post receive buffers. */ + cl_spinlock_acquire( &p_spl_qp_svc->obj.lock ); + status = spl_qp_svc_post_recvs( p_spl_qp_svc ); + cl_spinlock_release( &p_spl_qp_svc->obj.lock ); + if( status != IB_SUCCESS ) + { + p_spl_qp_svc->obj.pfn_destroy( &p_spl_qp_svc->obj, NULL ); + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("spl_qp_svc_post_recvs failed, %s\n", + ib_get_err_str( status ) ) ); + return status; + } + + /* Create the MAD dispatcher. */ + status = create_mad_disp( &p_spl_qp_svc->obj, p_spl_qp_svc->h_qp, + &p_spl_qp_svc->h_mad_disp ); + if( status != IB_SUCCESS ) + { + p_spl_qp_svc->obj.pfn_destroy( &p_spl_qp_svc->obj, NULL ); + AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("create_mad_disp failed, %s\n", ib_get_err_str( status ) ) ); + return status; + } + + /* + * Add this service to the special QP manager lookup lists. + * The service must be added to allow the creation of a QP alias. + */ + cl_spinlock_acquire( &gp_spl_qp_mgr->obj.lock ); + if( qp_type == IB_QPT_QP0 ) + { + cl_qmap_insert( &gp_spl_qp_mgr->smi_map, p_spl_qp_svc->port_guid, + &p_spl_qp_svc->map_item ); + } + else + { + cl_qmap_insert( &gp_spl_qp_mgr->gsi_map, p_spl_qp_svc->port_guid, + &p_spl_qp_svc->map_item ); + } + cl_spinlock_release( &gp_spl_qp_mgr->obj.lock ); + + /* + * If the CA does not support HW agents, create a QP alias and register + * a MAD service for sending responses from the local MAD interface. + */ + if( check_local_mad( p_spl_qp_svc->h_qp ) ) + { + /* Create a QP alias. */ + cl_memclr( &qp_create, sizeof( ib_qp_create_t ) ); + qp_create.qp_type = + ( qp_type == IB_QPT_QP0 ) ? IB_QPT_QP0_ALIAS : IB_QPT_QP1_ALIAS; + qp_create.sq_depth = p_spl_qp_svc->max_qp_depth; + qp_create.sq_sge = 1; + qp_create.sq_signaled = TRUE; + + status = ib_get_spl_qp( p_spl_qp_svc->obj.p_ci_ca->h_pd_alias, + p_pnp_rec->p_port_attr->port_guid, &qp_create, + p_spl_qp_svc, spl_qp_alias_event_cb, &p_spl_qp_svc->pool_key, + &p_spl_qp_svc->h_qp_alias ); + + if (status != IB_SUCCESS) + { + p_spl_qp_svc->obj.pfn_destroy( &p_spl_qp_svc->obj, NULL ); + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("ib_get_spl_qp alias failed, %s\n", + ib_get_err_str( status ) ) ); + return status; + } + + /* Reference the special QP service on behalf of ib_get_spl_qp. */ + ref_al_obj( &p_spl_qp_svc->obj ); + + /* Register a MAD service for sends. */ + cl_memclr( &mad_svc, sizeof( ib_mad_svc_t ) ); + mad_svc.mad_svc_context = p_spl_qp_svc; + mad_svc.pfn_mad_send_cb = spl_qp_alias_send_cb; + mad_svc.pfn_mad_recv_cb = spl_qp_alias_recv_cb; + + status = ib_reg_mad_svc( p_spl_qp_svc->h_qp_alias, &mad_svc, + &p_spl_qp_svc->h_mad_svc ); + + if( status != IB_SUCCESS ) + { + p_spl_qp_svc->obj.pfn_destroy( &p_spl_qp_svc->obj, NULL ); + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("ib_reg_mad_svc failed, %s\n", ib_get_err_str( status ) ) ); + return status; + } + } + + /* Set the context of the PnP event to this child object. */ + p_pnp_rec->pnp_rec.context = &p_spl_qp_svc->obj; + + /* The QP is ready. Change the state. */ + p_spl_qp_svc->state = SPL_QP_ACTIVE; + + /* Force a completion callback to rearm the CQs. */ + spl_qp_recv_comp_cb( p_spl_qp_svc->h_recv_cq, p_spl_qp_svc ); + spl_qp_send_comp_cb( p_spl_qp_svc->h_send_cq, p_spl_qp_svc ); + + /* Start the polling thread timer. */ + if( g_smi_poll_interval ) + { + cl_status = + cl_timer_trim( &gp_spl_qp_mgr->poll_timer, g_smi_poll_interval ); + + if( cl_status != CL_SUCCESS ) + { + p_spl_qp_svc->obj.pfn_destroy( &p_spl_qp_svc->obj, NULL ); + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("cl_timer_start failed, status 0x%x\n", cl_status ) ); + return ib_convert_cl_status( cl_status ); + } + } + + /* Release the reference taken in init_al_obj. */ + deref_al_obj( &p_spl_qp_svc->obj ); + + AL_EXIT( AL_DBG_SMI ); + return IB_SUCCESS; +} + + + +/* + * Return a work completion to the MAD dispatcher for the specified MAD. + */ +static void +__complete_send_mad( + IN const al_mad_disp_handle_t h_mad_disp, + IN al_mad_wr_t* const p_mad_wr, + IN const ib_wc_status_t wc_status ) +{ + ib_wc_t wc; + + /* Construct a send work completion. */ + cl_memclr( &wc, sizeof( ib_wc_t ) ); + wc.wr_id = p_mad_wr->send_wr.wr_id; + wc.wc_type = IB_WC_SEND; + wc.status = wc_status; + + /* Set the send size if we were successful with the send. */ + if( wc_status == IB_WCS_SUCCESS ) + wc.length = MAD_BLOCK_SIZE; + + mad_disp_send_done( h_mad_disp, p_mad_wr, &wc ); +} + + + +/* + * Pre-destroy a special QP service. + */ +void +destroying_spl_qp_svc( + IN al_obj_t* p_obj ) +{ + spl_qp_svc_t* p_spl_qp_svc; + cl_list_item_t* p_list_item; + al_mad_wr_t* p_mad_wr; + + ib_api_status_t status; + KIRQL irql; + + AL_ENTER( AL_DBG_SMI ); + + CL_ASSERT( p_obj ); + p_spl_qp_svc = PARENT_STRUCT( p_obj, spl_qp_svc_t, obj ); + + /* Change the state to prevent processing new send requests. */ + cl_spinlock_acquire( &p_spl_qp_svc->obj.lock ); + p_spl_qp_svc->state = SPL_QP_DESTROYING; + cl_spinlock_release( &p_spl_qp_svc->obj.lock ); + + /* Wait here until the special QP service is no longer in use. */ + while( p_spl_qp_svc->in_use_cnt ) + { + cl_thread_suspend( 0 ); + } + + /* Destroy the special QP. */ + if( p_spl_qp_svc->h_qp ) + { + /* If present, remove the special QP service from the tracking map. */ + cl_spinlock_acquire( &gp_spl_qp_mgr->obj.lock ); + if( p_spl_qp_svc->h_qp->type == IB_QPT_QP0 ) + { + cl_qmap_remove( &gp_spl_qp_mgr->smi_map, p_spl_qp_svc->port_guid ); + } + else + { + cl_qmap_remove( &gp_spl_qp_mgr->gsi_map, p_spl_qp_svc->port_guid ); + } + cl_spinlock_release( &gp_spl_qp_mgr->obj.lock ); + + status = ib_destroy_qp( p_spl_qp_svc->h_qp, + (ib_pfn_destroy_cb_t)deref_al_obj ); + CL_ASSERT( status == IB_SUCCESS ); + + irql = KeRaiseIrqlToDpcLevel(); + cl_spinlock_acquire( &p_spl_qp_svc->obj.lock ); + + /* Complete any outstanding MAD sends operations as "flushed". */ + for( p_list_item = cl_qlist_remove_head( &p_spl_qp_svc->send_queue ); + p_list_item != cl_qlist_end( &p_spl_qp_svc->send_queue ); + p_list_item = cl_qlist_remove_head( &p_spl_qp_svc->send_queue ) ) + { + cl_spinlock_release( &p_spl_qp_svc->obj.lock ); + p_mad_wr = PARENT_STRUCT( p_list_item, al_mad_wr_t, list_item ); + __complete_send_mad( p_spl_qp_svc->h_mad_disp, p_mad_wr, + IB_WCS_WR_FLUSHED_ERR ); + cl_spinlock_acquire( &p_spl_qp_svc->obj.lock ); + } + + cl_spinlock_release( &p_spl_qp_svc->obj.lock ); + KeLowerIrql(irql); + /* Receive MAD elements are returned to the pool by the free routine. */ + } + + /* Destroy the special QP alias and CQs. */ + if( p_spl_qp_svc->h_qp_alias ) + { + status = ib_destroy_qp( p_spl_qp_svc->h_qp_alias, + (ib_pfn_destroy_cb_t)deref_al_obj ); + CL_ASSERT( status == IB_SUCCESS ); + } + if( p_spl_qp_svc->h_send_cq ) + { + status = ib_destroy_cq( p_spl_qp_svc->h_send_cq, + (ib_pfn_destroy_cb_t)deref_al_obj ); + CL_ASSERT( status == IB_SUCCESS ); + } + if( p_spl_qp_svc->h_recv_cq ) + { + status = ib_destroy_cq( p_spl_qp_svc->h_recv_cq, + (ib_pfn_destroy_cb_t)deref_al_obj ); + CL_ASSERT( status == IB_SUCCESS ); + } + + AL_EXIT( AL_DBG_SMI ); +} + + + +/* + * Free a special QP service. + */ +void +free_spl_qp_svc( + IN al_obj_t* p_obj ) +{ + spl_qp_svc_t* p_spl_qp_svc; + cl_list_item_t* p_list_item; + al_mad_element_t* p_al_mad; + ib_api_status_t status; + + AL_ENTER( AL_DBG_SMI ); + + CL_ASSERT( p_obj ); + p_spl_qp_svc = PARENT_STRUCT( p_obj, spl_qp_svc_t, obj ); + + /* Dereference the CA. */ + if( p_spl_qp_svc->obj.p_ci_ca ) + deref_al_obj( &p_spl_qp_svc->obj.p_ci_ca->h_ca->obj ); + + /* Return receive MAD elements to the pool. */ + for( p_list_item = cl_qlist_remove_head( &p_spl_qp_svc->recv_queue ); + p_list_item != cl_qlist_end( &p_spl_qp_svc->recv_queue ); + p_list_item = cl_qlist_remove_head( &p_spl_qp_svc->recv_queue ) ) + { + p_al_mad = PARENT_STRUCT( p_list_item, al_mad_element_t, list_item ); + + status = ib_put_mad( &p_al_mad->element ); + CL_ASSERT( status == IB_SUCCESS ); + } + + CL_ASSERT( cl_is_qlist_empty( &p_spl_qp_svc->send_queue ) ); + + destroy_al_obj( &p_spl_qp_svc->obj ); + cl_free( p_spl_qp_svc ); + + AL_EXIT( AL_DBG_SMI ); +} + + + +/* + * Update the base LID of a special QP service. + */ +void +spl_qp_svc_lid_change( + IN al_obj_t* p_obj, + IN ib_pnp_port_rec_t* p_pnp_rec ) +{ + spl_qp_svc_t* p_spl_qp_svc; + + AL_ENTER( AL_DBG_SMI ); + + CL_ASSERT( p_obj ); + CL_ASSERT( p_pnp_rec ); + CL_ASSERT( p_pnp_rec->p_port_attr ); + + p_spl_qp_svc = PARENT_STRUCT( p_obj, spl_qp_svc_t, obj ); + + p_spl_qp_svc->base_lid = p_pnp_rec->p_port_attr->lid; + p_spl_qp_svc->lmc = p_pnp_rec->p_port_attr->lmc; + + AL_EXIT( AL_DBG_SMI ); +} + + + +/* + * Route a send work request. + */ +mad_route_t +route_mad_send( + IN spl_qp_svc_t* p_spl_qp_svc, + IN ib_send_wr_t* const p_send_wr ) +{ + al_mad_wr_t* p_mad_wr; + al_mad_send_t* p_mad_send; + ib_mad_t* p_mad; + ib_smp_t* p_smp; + ib_av_handle_t h_av; + mad_route_t route; + boolean_t local, loopback, discard; + + AL_ENTER( AL_DBG_SMI ); + + CL_ASSERT( p_spl_qp_svc ); + CL_ASSERT( p_send_wr ); + + /* Initialize a pointers to the MAD work request and the MAD. */ + p_mad_wr = PARENT_STRUCT( p_send_wr, al_mad_wr_t, send_wr ); + p_mad_send = PARENT_STRUCT( p_mad_wr, al_mad_send_t, mad_wr ); + p_mad = get_mad_hdr_from_wr( p_mad_wr ); + p_smp = (ib_smp_t*)p_mad; + + /* Check if the CA has a local MAD interface. */ + local = loopback = discard = FALSE; + if( check_local_mad( p_spl_qp_svc->h_qp ) ) + { + /* + * If the MAD is a locally addressed Subnet Management, Performance + * Management, or Connection Management datagram, process the work + * request locally. + */ + h_av = p_send_wr->dgrm.ud.h_av; + switch( p_mad->mgmt_class ) + { + case IB_MCLASS_SUBN_DIR: + /* Perform special checks on directed route SMPs. */ + if( ib_smp_is_response( p_smp ) ) + { + /* + * This node is the originator of the response. Discard + * if the hop count or pointer is zero, an intermediate hop, + * out of bounds hop, or if the first port of the directed + * route retrun path is not this port. + */ + if( ( p_smp->hop_count == 0 ) || ( p_smp->hop_ptr == 0 ) ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("hop cnt or hop ptr set to 0...discarding\n") ); + discard = TRUE; + } + else if( p_smp->hop_count != ( p_smp->hop_ptr - 1 ) ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("hop cnt != (hop ptr - 1)...discarding\n") ); + discard = TRUE; + } + else if( p_smp->hop_count >= IB_SUBNET_PATH_HOPS_MAX ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("hop cnt > max hops...discarding\n") ); + discard = TRUE; + } + else if( ( p_smp->dr_dlid == IB_LID_PERMISSIVE ) && + ( p_smp->return_path[ p_smp->hop_ptr - 1 ] != + p_spl_qp_svc->port_num ) ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("return path[hop ptr - 1] != port num...discarding\n") ); + discard = TRUE; + } + } + else + { + /* The SMP is a request. */ + if( ( p_smp->hop_count >= IB_SUBNET_PATH_HOPS_MAX ) || + ( p_smp->hop_ptr >= IB_SUBNET_PATH_HOPS_MAX ) ) + { + discard = TRUE; + } + else if( ( p_smp->hop_count == 0 ) && ( p_smp->hop_ptr == 0 ) ) + { + /* Self Addressed: Sent locally, routed locally. */ + local = TRUE; + discard = ( p_smp->dr_slid != IB_LID_PERMISSIVE ) || + ( p_smp->dr_dlid != IB_LID_PERMISSIVE ); + } + else if( ( p_smp->hop_count != 0 ) && + ( p_smp->hop_count == ( p_smp->hop_ptr - 1 ) ) ) + { + /* End of Path: Sent remotely, routed locally. */ + local = TRUE; + } + else if( ( p_smp->hop_count != 0 ) && + ( p_smp->hop_ptr == 0 ) ) + { + /* Beginning of Path: Sent locally, routed remotely. */ + if( p_smp->dr_slid == IB_LID_PERMISSIVE ) + { + discard = + ( p_smp->initial_path[ p_smp->hop_ptr + 1 ] != + p_spl_qp_svc->port_num ); + } + } + else + { + /* Intermediate hop. */ + discard = TRUE; + } + } + /* Loopback locally addressed SM to SM "heartbeat" messages. */ + loopback = (p_mad->attr_id == IB_MAD_ATTR_SM_INFO); + break; + + case IB_MCLASS_SUBN_LID: + /* Loopback locally addressed SM to SM "heartbeat" messages. */ + loopback = (p_mad->attr_id == IB_MAD_ATTR_SM_INFO); + + /* Fall through to check for a local MAD. */ + + case IB_MCLASS_PERF: + case IB_MCLASS_BM: + case IB_MLX_VENDOR_CLASS1: + case IB_MLX_VENDOR_CLASS2: + local = !(p_mad->method & IB_MAD_METHOD_RESP_MASK) && ( h_av && + ( h_av->av_attr.dlid == + ( h_av->av_attr.path_bits | p_spl_qp_svc->base_lid ) ) ); + break; + } + } + + route = ( p_mad_send->p_send_mad->send_opt & IB_SEND_OPT_LOCAL ) ? + ROUTE_LOCAL : ROUTE_REMOTE; + if( local ) route = ROUTE_LOCAL; + if( loopback && local ) route = ROUTE_LOOPBACK; + if( discard ) route = ROUTE_DISCARD; + + AL_EXIT( AL_DBG_SMI ); + return route; +} + + + +/* + * Send a work request on the special QP. + */ +ib_api_status_t +spl_qp_svc_send( + IN const ib_qp_handle_t h_qp, + IN ib_send_wr_t* const p_send_wr ) +{ + spl_qp_svc_t* p_spl_qp_svc; + al_mad_wr_t* p_mad_wr; + mad_route_t route; + ib_api_status_t status; + + AL_ENTER( AL_DBG_SMI ); + + CL_ASSERT( h_qp ); + CL_ASSERT( p_send_wr ); + + /* Get the special QP service. */ + p_spl_qp_svc = (spl_qp_svc_t*)h_qp->obj.context; + CL_ASSERT( p_spl_qp_svc ); + CL_ASSERT( p_spl_qp_svc->h_qp == h_qp ); + + /* Determine how to route the MAD. */ + route = route_mad_send( p_spl_qp_svc, p_send_wr ); + + /* + * Check the QP state and guard against error handling. Also, + * to maintain proper order of work completions, delay processing + * a local MAD until any remote MAD work requests have completed, + * and delay processing a remote MAD until local MAD work requests + * have completed. + */ + cl_spinlock_acquire( &p_spl_qp_svc->obj.lock ); + if( (p_spl_qp_svc->state != SPL_QP_ACTIVE) || p_spl_qp_svc->local_mad_wr || + (is_local(route) && !cl_is_qlist_empty( &p_spl_qp_svc->send_queue )) || + ( cl_qlist_count( &p_spl_qp_svc->send_queue ) >= + p_spl_qp_svc->max_qp_depth ) ) + { + /* + * Return busy status. + * The special QP will resume sends at this point. + */ + cl_spinlock_release( &p_spl_qp_svc->obj.lock ); + + AL_EXIT( AL_DBG_SMI ); + return IB_RESOURCE_BUSY; + } + + p_mad_wr = PARENT_STRUCT( p_send_wr, al_mad_wr_t, send_wr ); + + if( is_local( route ) ) + { + /* Save the local MAD work request for processing. */ + p_spl_qp_svc->local_mad_wr = p_mad_wr; + + /* Flag the service as in use by the asynchronous processing thread. */ + cl_atomic_inc( &p_spl_qp_svc->in_use_cnt ); + + cl_spinlock_release( &p_spl_qp_svc->obj.lock ); + + status = local_mad_send( p_spl_qp_svc, p_mad_wr ); + } + else + { + /* Process a remote MAD send work request. */ + status = remote_mad_send( p_spl_qp_svc, p_mad_wr ); + + cl_spinlock_release( &p_spl_qp_svc->obj.lock ); + } + + AL_EXIT( AL_DBG_SMI ); + return status; +} + + + +/* + * Process a remote MAD send work request. Called holding the spl_qp_svc lock. + */ +ib_api_status_t +remote_mad_send( + IN spl_qp_svc_t* p_spl_qp_svc, + IN al_mad_wr_t* const p_mad_wr ) +{ + ib_smp_t* p_smp; + ib_api_status_t status; + + AL_ENTER( AL_DBG_SMI ); + + CL_ASSERT( p_spl_qp_svc ); + CL_ASSERT( p_mad_wr ); + + /* Initialize a pointers to the MAD work request and outbound MAD. */ + p_smp = (ib_smp_t*)get_mad_hdr_from_wr( p_mad_wr ); + + /* Perform outbound MAD processing. */ + + /* Adjust directed route SMPs as required by IBA. */ + if( p_smp->mgmt_class == IB_MCLASS_SUBN_DIR ) + { + if( ib_smp_is_response( p_smp ) ) + { + if( p_smp->dr_dlid == IB_LID_PERMISSIVE ) + p_smp->hop_ptr--; + } + else if( p_smp->dr_slid == IB_LID_PERMISSIVE ) + { + /* + * Only update the pointer if the hw_agent is not implemented. + * Fujitsu implements SMI in hardware, so the following has to + * be passed down to the hardware SMI. + */ + ci_ca_lock_attr( p_spl_qp_svc->obj.p_ci_ca ); + if( !p_spl_qp_svc->obj.p_ci_ca->p_pnp_attr->hw_agents ) + p_smp->hop_ptr++; + ci_ca_unlock_attr( p_spl_qp_svc->obj.p_ci_ca ); + } + } + + /* Always generate send completions. */ + p_mad_wr->send_wr.send_opt |= IB_SEND_OPT_SIGNALED; + + /* Queue the MAD work request on the service tracking queue. */ + cl_qlist_insert_tail( &p_spl_qp_svc->send_queue, &p_mad_wr->list_item ); + + status = ib_post_send( p_spl_qp_svc->h_qp, &p_mad_wr->send_wr, NULL ); + + if( status != IB_SUCCESS ) + { + cl_qlist_remove_item( &p_spl_qp_svc->send_queue, &p_mad_wr->list_item ); + + /* Reset directed route SMPs as required by IBA. */ + if( p_smp->mgmt_class == IB_MCLASS_SUBN_DIR ) + { + if( ib_smp_is_response( p_smp ) ) + { + if( p_smp->dr_dlid == IB_LID_PERMISSIVE ) + p_smp->hop_ptr++; + } + else if( p_smp->dr_slid == IB_LID_PERMISSIVE ) + { + /* Only update if the hw_agent is not implemented. */ + ci_ca_lock_attr( p_spl_qp_svc->obj.p_ci_ca ); + if( p_spl_qp_svc->obj.p_ci_ca->p_pnp_attr->hw_agents == FALSE ) + p_smp->hop_ptr--; + ci_ca_unlock_attr( p_spl_qp_svc->obj.p_ci_ca ); + } + } + } + + AL_EXIT( AL_DBG_SMI ); + return status; +} + + +/* + * Handle a MAD destined for the local CA, using cached data + * as much as possible. + */ +static ib_api_status_t +local_mad_send( + IN spl_qp_svc_t* p_spl_qp_svc, + IN al_mad_wr_t* const p_mad_wr ) +{ + mad_route_t route; + ib_api_status_t status = IB_SUCCESS; + + AL_ENTER( AL_DBG_SMI ); + + CL_ASSERT( p_spl_qp_svc ); + CL_ASSERT( p_mad_wr ); + + /* Determine how to route the MAD. */ + route = route_mad_send( p_spl_qp_svc, &p_mad_wr->send_wr ); + + /* Check if this MAD should be discarded. */ + if( is_discard( route ) ) + { + /* Deliver a "work completion" to the dispatcher. */ + __complete_send_mad( p_spl_qp_svc->h_mad_disp, p_mad_wr, + IB_WCS_LOCAL_OP_ERR ); + status = IB_INVALID_SETTING; + } + else if( is_loopback( route ) ) + { + /* Loopback local SM to SM "heartbeat" messages. */ + status = loopback_mad( p_spl_qp_svc, p_mad_wr ); + } + else + { + switch( get_mad_hdr_from_wr( p_mad_wr )->mgmt_class ) + { + case IB_MCLASS_SUBN_DIR: + case IB_MCLASS_SUBN_LID: + //DO not use the cache in order to force Mkey check + status = __process_subn_mad( p_spl_qp_svc, p_mad_wr ); + //status = IB_NOT_DONE; + break; + + default: + status = IB_NOT_DONE; + } + } + + if( status == IB_NOT_DONE ) + { + /* Queue an asynchronous processing item to process the local MAD. */ + cl_async_proc_queue( gp_async_proc_mgr, &p_spl_qp_svc->send_async ); + } + else + { + /* + * Clear the local MAD pointer to allow processing of other MADs. + * This is done after polling for attribute changes to ensure that + * subsequent MADs pick up any changes performed by this one. + */ + cl_spinlock_acquire( &p_spl_qp_svc->obj.lock ); + p_spl_qp_svc->local_mad_wr = NULL; + cl_spinlock_release( &p_spl_qp_svc->obj.lock ); + + /* No longer in use by the asynchronous processing thread. */ + cl_atomic_dec( &p_spl_qp_svc->in_use_cnt ); + + /* Special QP operations will resume by unwinding. */ + } + + AL_EXIT( AL_DBG_SMI ); + return IB_SUCCESS; +} + + +static ib_api_status_t +get_resp_mad( + IN spl_qp_svc_t* p_spl_qp_svc, + IN al_mad_wr_t* const p_mad_wr, + OUT ib_mad_element_t** const pp_mad_resp ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_SMI ); + + CL_ASSERT( p_spl_qp_svc ); + CL_ASSERT( p_mad_wr ); + CL_ASSERT( pp_mad_resp ); + + /* Get a MAD element from the pool for the response. */ + status = ib_get_mad( p_spl_qp_svc->h_qp->obj.p_ci_ca->pool_key, + MAD_BLOCK_SIZE, pp_mad_resp ); + if( status != IB_SUCCESS ) + { + __complete_send_mad( p_spl_qp_svc->h_mad_disp, p_mad_wr, + IB_WCS_LOCAL_OP_ERR ); + } + + AL_EXIT( AL_DBG_SMI ); + return status; +} + + +static ib_api_status_t +complete_local_mad( + IN spl_qp_svc_t* p_spl_qp_svc, + IN al_mad_wr_t* const p_mad_wr, + IN ib_mad_element_t* const p_mad_resp ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_SMI ); + + CL_ASSERT( p_spl_qp_svc ); + CL_ASSERT( p_mad_wr ); + CL_ASSERT( p_mad_resp ); + + /* Construct the receive MAD element. */ + p_mad_resp->status = IB_WCS_SUCCESS; + p_mad_resp->remote_qp = p_mad_wr->send_wr.dgrm.ud.remote_qp; + p_mad_resp->remote_lid = p_spl_qp_svc->base_lid; + if( p_mad_wr->send_wr.send_opt & IB_RECV_OPT_IMMEDIATE ) + { + p_mad_resp->immediate_data = p_mad_wr->send_wr.immediate_data; + p_mad_resp->recv_opt |= IB_RECV_OPT_IMMEDIATE; + } + + /* + * Hand the receive MAD element to the dispatcher before completing + * the send. This guarantees that the send request cannot time out. + */ + status = mad_disp_recv_done( p_spl_qp_svc->h_mad_disp, p_mad_resp ); + + /* Forward the send work completion to the dispatcher. */ + __complete_send_mad( p_spl_qp_svc->h_mad_disp, p_mad_wr, IB_WCS_SUCCESS ); + + AL_EXIT( AL_DBG_SMI ); + return status; +} + + +static ib_api_status_t +loopback_mad( + IN spl_qp_svc_t* p_spl_qp_svc, + IN al_mad_wr_t* const p_mad_wr ) +{ + ib_mad_t *p_mad; + ib_mad_element_t *p_mad_resp; + ib_api_status_t status; + + AL_ENTER( AL_DBG_SMI ); + + CL_ASSERT( p_spl_qp_svc ); + CL_ASSERT( p_mad_wr ); + + /* Get a MAD element from the pool for the response. */ + status = get_resp_mad( p_spl_qp_svc, p_mad_wr, &p_mad_resp ); + if( status == IB_SUCCESS ) + { + /* Initialize a pointers to the MAD work request and outbound MAD. */ + p_mad = get_mad_hdr_from_wr( p_mad_wr ); + + /* Simulate a send/receive between local managers. */ + cl_memcpy( p_mad_resp->p_mad_buf, p_mad, MAD_BLOCK_SIZE ); + + /* Construct the receive MAD element. */ + p_mad_resp->status = IB_WCS_SUCCESS; + p_mad_resp->remote_qp = p_mad_wr->send_wr.dgrm.ud.remote_qp; + p_mad_resp->remote_lid = p_spl_qp_svc->base_lid; + if( p_mad_wr->send_wr.send_opt & IB_RECV_OPT_IMMEDIATE ) + { + p_mad_resp->immediate_data = p_mad_wr->send_wr.immediate_data; + p_mad_resp->recv_opt |= IB_RECV_OPT_IMMEDIATE; + } + + /* + * Hand the receive MAD element to the dispatcher before completing + * the send. This guarantees that the send request cannot time out. + */ + status = mad_disp_recv_done( p_spl_qp_svc->h_mad_disp, p_mad_resp ); + + /* Forward the send work completion to the dispatcher. */ + __complete_send_mad( p_spl_qp_svc->h_mad_disp, p_mad_wr, IB_WCS_SUCCESS ); + + } + + AL_EXIT( AL_DBG_SMI ); + return status; +} + + +static void +__update_guid_info( + IN spl_qp_cache_t* const p_cache, + IN const ib_smp_t* const p_mad ) +{ + uint32_t idx; + + /* Get the table selector from the attribute */ + idx = cl_ntoh32( p_mad->attr_mod ); + + /* + * We only get successful MADs here, so invalid settings + * shouldn't happen. + */ + CL_ASSERT( idx <= 31 ); + + cl_memcpy( &p_cache->guid_block[idx].tbl, + ib_smp_get_payload_ptr( p_mad ), + sizeof(ib_guid_info_t) ); + p_cache->guid_block[idx].valid = TRUE; +} + + +static void +__update_pkey_table( + IN spl_qp_cache_t* const p_cache, + IN const ib_smp_t* const p_mad ) +{ + uint16_t idx; + + /* Get the table selector from the attribute */ + idx = ((uint16_t)cl_ntoh32( p_mad->attr_mod )); + + CL_ASSERT( idx <= 2047 ); + + cl_memcpy( &p_cache->pkey_tbl[idx].tbl, + ib_smp_get_payload_ptr( p_mad ), + sizeof(ib_pkey_table_t) ); + p_cache->pkey_tbl[idx].valid = TRUE; +} + + +static void +__update_sl_vl_table( + IN spl_qp_cache_t* const p_cache, + IN const ib_smp_t* const p_mad ) +{ + cl_memcpy( &p_cache->sl_vl.tbl, + ib_smp_get_payload_ptr( p_mad ), + sizeof(ib_slvl_table_t) ); + p_cache->sl_vl.valid = TRUE; +} + + +static void +__update_vl_arb_table( + IN spl_qp_cache_t* const p_cache, + IN const ib_smp_t* const p_mad ) +{ + uint16_t idx; + + /* Get the table selector from the attribute */ + idx = ((uint16_t)(cl_ntoh32( p_mad->attr_mod ) >> 16)) - 1; + + CL_ASSERT( idx <= 3 ); + + cl_memcpy( &p_cache->vl_arb[idx].tbl, + ib_smp_get_payload_ptr( p_mad ), + sizeof(ib_vl_arb_table_t) ); + p_cache->vl_arb[idx].valid = TRUE; +} + + + +void +spl_qp_svc_update_cache( + IN spl_qp_svc_t *p_spl_qp_svc, + IN ib_smp_t *p_mad ) +{ + + + + CL_ASSERT( p_spl_qp_svc ); + CL_ASSERT( p_mad ); + CL_ASSERT( p_mad->mgmt_class == IB_MCLASS_SUBN_DIR || + p_mad->mgmt_class == IB_MCLASS_SUBN_LID); + CL_ASSERT(!p_mad->status); + + cl_spinlock_acquire(&p_spl_qp_svc->cache_lock); + + switch( p_mad->attr_id ) + { + case IB_MAD_ATTR_GUID_INFO: + __update_guid_info( + &p_spl_qp_svc->cache, p_mad ); + break; + + case IB_MAD_ATTR_P_KEY_TABLE: + __update_pkey_table( + &p_spl_qp_svc->cache, p_mad ); + break; + + case IB_MAD_ATTR_SLVL_TABLE: + __update_sl_vl_table( + &p_spl_qp_svc->cache, p_mad ); + break; + + case IB_MAD_ATTR_VL_ARBITRATION: + __update_vl_arb_table( + &p_spl_qp_svc->cache, p_mad ); + break; + + default: + break; + } + + cl_spinlock_release(&p_spl_qp_svc->cache_lock); +} + + + +static ib_api_status_t +__process_node_info( + IN spl_qp_svc_t* p_spl_qp_svc, + IN al_mad_wr_t* const p_mad_wr ) +{ + ib_mad_t *p_mad; + ib_mad_element_t *p_mad_resp; + ib_smp_t *p_smp; + ib_node_info_t *p_node_info; + ib_ca_attr_t *p_ca_attr; + ib_port_attr_t *p_port_attr; + ib_api_status_t status; + + AL_ENTER( AL_DBG_SMI ); + + CL_ASSERT( p_spl_qp_svc ); + CL_ASSERT( p_mad_wr ); + + /* Initialize a pointers to the MAD work request and outbound MAD. */ + p_mad = get_mad_hdr_from_wr( p_mad_wr ); + if( p_mad->method != IB_MAD_METHOD_GET ) + { + /* Node description is a GET-only attribute. */ + __complete_send_mad( p_spl_qp_svc->h_mad_disp, p_mad_wr, + IB_WCS_LOCAL_OP_ERR ); + AL_EXIT( AL_DBG_SMI ); + return IB_INVALID_SETTING; + } + + /* Get a MAD element from the pool for the response. */ + status = get_resp_mad( p_spl_qp_svc, p_mad_wr, &p_mad_resp ); + if( status == IB_SUCCESS ) + { + p_smp = (ib_smp_t*)p_mad_resp->p_mad_buf; + cl_memcpy( p_smp, p_mad, MAD_BLOCK_SIZE ); + p_smp->method = (IB_MAD_METHOD_RESP_MASK | IB_MAD_METHOD_GET); + if( p_smp->mgmt_class == IB_MCLASS_SUBN_DIR ) + p_smp->status = IB_SMP_DIRECTION; + else + p_smp->status = 0; + + p_node_info = (ib_node_info_t*)ib_smp_get_payload_ptr( p_smp ); + + /* + * Fill in the node info, protecting against the + * attributes being changed by PnP. + */ + cl_spinlock_acquire( &p_spl_qp_svc->obj.p_ci_ca->obj.lock ); + + p_ca_attr = p_spl_qp_svc->obj.p_ci_ca->p_pnp_attr; + p_port_attr = &p_ca_attr->p_port_attr[p_spl_qp_svc->port_num - 1]; + + p_node_info->base_version = 1; + p_node_info->class_version = 1; + p_node_info->node_type = IB_NODE_TYPE_CA; + p_node_info->num_ports = p_ca_attr->num_ports; + p_node_info->sys_guid = p_ca_attr->system_image_guid; + p_node_info->node_guid = p_ca_attr->ca_guid; + p_node_info->port_guid = p_port_attr->port_guid; + p_node_info->partition_cap = cl_hton16( p_port_attr->num_pkeys ); + p_node_info->device_id = cl_hton16( p_ca_attr->dev_id ); + p_node_info->revision = cl_hton32( p_ca_attr->revision ); + p_node_info->port_num_vendor_id = + cl_hton32( p_ca_attr->vend_id & 0x00FFFFFF ) | p_port_attr->port_num; + cl_spinlock_release( &p_spl_qp_svc->obj.p_ci_ca->obj.lock ); + + status = complete_local_mad( p_spl_qp_svc, p_mad_wr, p_mad_resp ); + } + + AL_EXIT( AL_DBG_SMI ); + return status; +} + + +static ib_api_status_t +__process_node_desc( + IN spl_qp_svc_t* p_spl_qp_svc, + IN al_mad_wr_t* const p_mad_wr ) +{ + ib_mad_t *p_mad; + ib_mad_element_t *p_mad_resp; + ib_api_status_t status; + + AL_ENTER( AL_DBG_SMI ); + + CL_ASSERT( p_spl_qp_svc ); + CL_ASSERT( p_mad_wr ); + + /* Initialize a pointers to the MAD work request and outbound MAD. */ + p_mad = get_mad_hdr_from_wr( p_mad_wr ); + if( p_mad->method != IB_MAD_METHOD_GET ) + { + /* Node info is a GET-only attribute. */ + __complete_send_mad( p_spl_qp_svc->h_mad_disp, p_mad_wr, + IB_WCS_LOCAL_OP_ERR ); + AL_EXIT( AL_DBG_SMI ); + return IB_INVALID_SETTING; + } + + /* Get a MAD element from the pool for the response. */ + status = get_resp_mad( p_spl_qp_svc, p_mad_wr, &p_mad_resp ); + if( status == IB_SUCCESS ) + { + cl_memcpy( p_mad_resp->p_mad_buf, p_mad, MAD_BLOCK_SIZE ); + p_mad_resp->p_mad_buf->method = + (IB_MAD_METHOD_RESP_MASK | IB_MAD_METHOD_GET); + if( p_mad_resp->p_mad_buf->mgmt_class == IB_MCLASS_SUBN_DIR ) + p_mad_resp->p_mad_buf->status = IB_SMP_DIRECTION; + else + p_mad_resp->p_mad_buf->status = 0; + /* Set the node description to the machine name. */ + cl_memcpy( ((ib_smp_t*)p_mad_resp->p_mad_buf)->data, + node_desc, sizeof(node_desc) ); + + status = complete_local_mad( p_spl_qp_svc, p_mad_wr, p_mad_resp ); + } + + AL_EXIT( AL_DBG_SMI ); + return status; +} + +static ib_api_status_t +__process_guid_info( + IN spl_qp_svc_t* p_spl_qp_svc, + IN al_mad_wr_t* const p_mad_wr ) +{ + + ib_mad_t *p_mad; + ib_mad_element_t *p_mad_resp; + ib_smp_t *p_smp; + ib_guid_info_t *p_guid_info; + uint16_t idx; + ib_api_status_t status; + + + /* Initialize a pointers to the MAD work request and outbound MAD. */ + p_mad = get_mad_hdr_from_wr( p_mad_wr ); + + /* Get the table selector from the attribute */ + idx = ((uint16_t)cl_ntoh32( p_mad->attr_mod )); + + /* + * TODO : Setup the response to fail the MAD instead of sending + * it down to the HCA. + */ + if( idx > 31 ) + { + AL_EXIT( AL_DBG_SMI ); + return IB_NOT_DONE; + } + if( !p_spl_qp_svc->cache.guid_block[idx].valid ) + { + AL_EXIT( AL_DBG_SMI ); + return IB_NOT_DONE; + } + + /* + * If a SET, see if the set is identical to the cache, + * in which case it's a no-op. + */ + if( p_mad->method == IB_MAD_METHOD_SET ) + { + if( cl_memcmp( ib_smp_get_payload_ptr( (ib_smp_t*)p_mad ), + &p_spl_qp_svc->cache.guid_block[idx].tbl, sizeof(ib_guid_info_t) ) ) + { + /* The set is requesting a change. */ + return IB_NOT_DONE; + } + } + + /* Get a MAD element from the pool for the response. */ + status = get_resp_mad( p_spl_qp_svc, p_mad_wr, &p_mad_resp ); + if( status == IB_SUCCESS ) + { + p_smp = (ib_smp_t*)p_mad_resp->p_mad_buf; + + /* Setup the response mad. */ + cl_memcpy( p_smp, p_mad, MAD_BLOCK_SIZE ); + p_smp->method = (IB_MAD_METHOD_RESP_MASK | IB_MAD_METHOD_GET); + if( p_smp->mgmt_class == IB_MCLASS_SUBN_DIR ) + p_smp->status = IB_SMP_DIRECTION; + else + p_smp->status = 0; + + p_guid_info = (ib_guid_info_t*)ib_smp_get_payload_ptr( p_smp ); + + // TODO: do we need lock on the cache ????? + + + /* Copy the cached data. */ + cl_memcpy( p_guid_info, + &p_spl_qp_svc->cache.guid_block[idx].tbl, sizeof(ib_guid_info_t) ); + + status = complete_local_mad( p_spl_qp_svc, p_mad_wr, p_mad_resp ); + } + + AL_EXIT( AL_DBG_SMI ); + return status; +} + + +static ib_api_status_t +__process_pkey_table( + IN spl_qp_svc_t* p_spl_qp_svc, + IN al_mad_wr_t* const p_mad_wr ) +{ + + ib_mad_t *p_mad; + ib_mad_element_t *p_mad_resp; + ib_smp_t *p_smp; + ib_pkey_table_t *p_pkey_table; + uint16_t idx; + ib_api_status_t status; + + AL_ENTER( AL_DBG_SMI ); + + CL_ASSERT( p_spl_qp_svc ); + CL_ASSERT( p_mad_wr ); + + /* Initialize a pointers to the MAD work request and outbound MAD. */ + p_mad = get_mad_hdr_from_wr( p_mad_wr ); + + /* Get the table selector from the attribute */ + idx = ((uint16_t)cl_ntoh32( p_mad->attr_mod )); + + /* + * TODO : Setup the response to fail the MAD instead of sending + * it down to the HCA. + */ + if( idx > 2047 ) + { + AL_EXIT( AL_DBG_SMI ); + return IB_NOT_DONE; + } + + + if( !p_spl_qp_svc->cache.pkey_tbl[idx].valid ) + { + AL_EXIT( AL_DBG_SMI ); + return IB_NOT_DONE; + } + + /* + * If a SET, see if the set is identical to the cache, + * in which case it's a no-op. + */ + if( p_mad->method == IB_MAD_METHOD_SET ) + { + if( cl_memcmp( ib_smp_get_payload_ptr( (ib_smp_t*)p_mad ), + &p_spl_qp_svc->cache.pkey_tbl[idx].tbl, sizeof(ib_pkey_table_t) ) ) + { + /* The set is requesting a change. */ + AL_EXIT( AL_DBG_SMI ); + return IB_NOT_DONE; + } + } + + /* Get a MAD element from the pool for the response. */ + status = get_resp_mad( p_spl_qp_svc, p_mad_wr, &p_mad_resp ); + if( status == IB_SUCCESS ) + { + p_smp = (ib_smp_t*)p_mad_resp->p_mad_buf; + + /* Setup the response mad. */ + cl_memcpy( p_smp, p_mad, MAD_BLOCK_SIZE ); + p_smp->method = (IB_MAD_METHOD_RESP_MASK | IB_MAD_METHOD_GET); + if( p_smp->mgmt_class == IB_MCLASS_SUBN_DIR ) + p_smp->status = IB_SMP_DIRECTION; + else + p_smp->status = 0; + + p_pkey_table = (ib_pkey_table_t*)ib_smp_get_payload_ptr( p_smp ); + + // TODO: do we need lock on the cache ????? + + + /* Copy the cached data. */ + cl_memcpy( p_pkey_table, + &p_spl_qp_svc->cache.pkey_tbl[idx].tbl, sizeof(ib_pkey_table_t) ); + + status = complete_local_mad( p_spl_qp_svc, p_mad_wr, p_mad_resp ); + } + + AL_EXIT( AL_DBG_SMI ); + return status; +} + + +static ib_api_status_t +__process_slvl_table( + IN spl_qp_svc_t* p_spl_qp_svc, + IN al_mad_wr_t* const p_mad_wr ) +{ + + + ib_mad_t *p_mad; + ib_mad_element_t *p_mad_resp; + ib_smp_t *p_smp; + ib_slvl_table_t *p_slvl_table; + ib_api_status_t status; + + AL_ENTER( AL_DBG_SMI ); + + CL_ASSERT( p_spl_qp_svc ); + CL_ASSERT( p_mad_wr ); + + /* Initialize a pointers to the MAD work request and outbound MAD. */ + p_mad = get_mad_hdr_from_wr( p_mad_wr ); + + if( !p_spl_qp_svc->cache.sl_vl.valid ) + { + AL_EXIT( AL_DBG_SMI ); + return IB_NOT_DONE; + } + + /* + * If a SET, see if the set is identical to the cache, + * in which case it's a no-op. + */ + if( p_mad->method == IB_MAD_METHOD_SET ) + { + if( cl_memcmp( ib_smp_get_payload_ptr( (ib_smp_t*)p_mad ), + &p_spl_qp_svc->cache.sl_vl.tbl, sizeof(ib_slvl_table_t) ) ) + { + /* The set is requesting a change. */ + AL_EXIT( AL_DBG_SMI ); + return IB_NOT_DONE; + } + } + + /* Get a MAD element from the pool for the response. */ + status = get_resp_mad( p_spl_qp_svc, p_mad_wr, &p_mad_resp ); + if( status == IB_SUCCESS ) + { + p_smp = (ib_smp_t*)p_mad_resp->p_mad_buf; + + /* Setup the response mad. */ + cl_memcpy( p_smp, p_mad, MAD_BLOCK_SIZE ); + p_smp->method = (IB_MAD_METHOD_RESP_MASK | IB_MAD_METHOD_GET); + if( p_smp->mgmt_class == IB_MCLASS_SUBN_DIR ) + p_smp->status = IB_SMP_DIRECTION; + else + p_smp->status = 0; + + p_slvl_table = (ib_slvl_table_t*)ib_smp_get_payload_ptr( p_smp ); + + // TODO: do we need lock on the cache ????? + + + /* Copy the cached data. */ + cl_memcpy( p_slvl_table, + &p_spl_qp_svc->cache.sl_vl.tbl, sizeof(ib_slvl_table_t) ); + + status = complete_local_mad( p_spl_qp_svc, p_mad_wr, p_mad_resp ); + } + + AL_EXIT( AL_DBG_SMI ); + return status; +} + + + +static ib_api_status_t +__process_vl_arb_table( + IN spl_qp_svc_t* p_spl_qp_svc, + IN al_mad_wr_t* const p_mad_wr ) +{ + + ib_mad_t *p_mad; + ib_mad_element_t *p_mad_resp; + ib_smp_t *p_smp; + ib_vl_arb_table_t *p_vl_arb_table; + uint16_t idx; + ib_api_status_t status; + + AL_ENTER( AL_DBG_SMI ); + + CL_ASSERT( p_spl_qp_svc ); + CL_ASSERT( p_mad_wr ); + + /* Initialize a pointers to the MAD work request and outbound MAD. */ + p_mad = get_mad_hdr_from_wr( p_mad_wr ); + + /* Get the table selector from the attribute */ + idx = ((uint16_t)(cl_ntoh32( p_mad->attr_mod ) >> 16)) - 1; + + /* + * TODO : Setup the response to fail the MAD instead of sending + * it down to the HCA. + */ + if( idx > 3 ) + { + AL_EXIT( AL_DBG_SMI ); + return IB_NOT_DONE; + } + + + if( !p_spl_qp_svc->cache.vl_arb[idx].valid ) + { + AL_EXIT( AL_DBG_SMI ); + return IB_NOT_DONE; + } + + /* + * If a SET, see if the set is identical to the cache, + * in which case it's a no-op. + */ + if( p_mad->method == IB_MAD_METHOD_SET ) + { + if( cl_memcmp( ib_smp_get_payload_ptr( (ib_smp_t*)p_mad ), + &p_spl_qp_svc->cache.vl_arb[idx].tbl, sizeof(ib_vl_arb_table_t) ) ) + { + /* The set is requesting a change. */ + AL_EXIT( AL_DBG_SMI ); + return IB_NOT_DONE; + } + } + + /* Get a MAD element from the pool for the response. */ + status = get_resp_mad( p_spl_qp_svc, p_mad_wr, &p_mad_resp ); + if( status == IB_SUCCESS ) + { + p_smp = (ib_smp_t*)p_mad_resp->p_mad_buf; + + /* Setup the response mad. */ + cl_memcpy( p_smp, p_mad, MAD_BLOCK_SIZE ); + p_smp->method = (IB_MAD_METHOD_RESP_MASK | IB_MAD_METHOD_GET); + if( p_smp->mgmt_class == IB_MCLASS_SUBN_DIR ) + p_smp->status = IB_SMP_DIRECTION; + else + p_smp->status = 0; + + p_vl_arb_table = (ib_vl_arb_table_t*)ib_smp_get_payload_ptr( p_smp ); + + // TODO: do we need lock on the cache ????? + + + /* Copy the cached data. */ + cl_memcpy( p_vl_arb_table, + &p_spl_qp_svc->cache.pkey_tbl[idx].tbl, sizeof(ib_vl_arb_table_t) ); + + status = complete_local_mad( p_spl_qp_svc, p_mad_wr, p_mad_resp ); + } + + AL_EXIT( AL_DBG_SMI ); + return status; +} + + + + +/* + * Process subnet administration MADs using cached data if possible. + */ +static ib_api_status_t +__process_subn_mad( + IN spl_qp_svc_t* p_spl_qp_svc, + IN al_mad_wr_t* const p_mad_wr ) +{ + ib_api_status_t status; + ib_smp_t *p_smp; + + AL_ENTER( AL_DBG_SMI ); + + CL_ASSERT( p_spl_qp_svc ); + CL_ASSERT( p_mad_wr ); + + p_smp = (ib_smp_t*)get_mad_hdr_from_wr( p_mad_wr ); + + CL_ASSERT( p_smp->mgmt_class == IB_MCLASS_SUBN_DIR || + p_smp->mgmt_class == IB_MCLASS_SUBN_LID ); + + /* simple m-key check */ + if( p_spl_qp_svc->m_key && p_smp->m_key == p_spl_qp_svc->m_key ) + { + if(!p_spl_qp_svc->cache_en ) + { + p_spl_qp_svc->cache_en = TRUE; + AL_EXIT( AL_DBG_SMI ); + return IB_NOT_DONE; + } + } + else + { + AL_PRINT(TRACE_LEVEL_WARNING, AL_DBG_SMI, ("Mkey check failed \n")); + AL_PRINT(TRACE_LEVEL_WARNING, AL_DBG_SMI, ("Mkey check SMP= 0x%08x:%08x SVC = 0x%08x:%08x \n", + ((uint32_t*)&p_smp->m_key)[0],((uint32_t*)&p_smp->m_key)[1], + ((uint32_t*)&p_spl_qp_svc->m_key)[0],((uint32_t*)&p_spl_qp_svc->m_key)[1])); + + p_spl_qp_svc->cache_en = FALSE; + AL_EXIT( AL_DBG_SMI ); + return IB_NOT_DONE; + } + + cl_spinlock_acquire(&p_spl_qp_svc->cache_lock); + + switch( p_smp->attr_id ) + { + case IB_MAD_ATTR_NODE_INFO: + status = __process_node_info( p_spl_qp_svc, p_mad_wr ); + break; + + case IB_MAD_ATTR_NODE_DESC: + status = __process_node_desc( p_spl_qp_svc, p_mad_wr ); + break; + + case IB_MAD_ATTR_GUID_INFO: + status = __process_guid_info( p_spl_qp_svc, p_mad_wr ); + break; + + case IB_MAD_ATTR_P_KEY_TABLE: + status = __process_pkey_table( p_spl_qp_svc, p_mad_wr ); + break; + + case IB_MAD_ATTR_SLVL_TABLE: + status = __process_slvl_table( p_spl_qp_svc, p_mad_wr ); + break; + + case IB_MAD_ATTR_VL_ARBITRATION: + status = __process_vl_arb_table( p_spl_qp_svc, p_mad_wr ); + break; + + default: + status = IB_NOT_DONE; + break; + } + + cl_spinlock_release(&p_spl_qp_svc->cache_lock); + + AL_EXIT( AL_DBG_SMI ); + return status; +} + + +/* + * Process a local MAD send work request. + */ +static ib_api_status_t +fwd_local_mad( + IN spl_qp_svc_t* p_spl_qp_svc, + IN al_mad_wr_t* const p_mad_wr ) +{ + ib_mad_t* p_mad; + ib_smp_t* p_smp; + al_mad_send_t* p_mad_send; + ib_mad_element_t* p_send_mad; + ib_mad_element_t* p_mad_response = NULL; + ib_mad_t* p_mad_response_buf; + ib_api_status_t status = IB_SUCCESS; + boolean_t smp_is_set; + + AL_ENTER( AL_DBG_SMI ); + + CL_ASSERT( p_spl_qp_svc ); + CL_ASSERT( p_mad_wr ); + + /* Initialize a pointers to the MAD work request and outbound MAD. */ + p_mad = get_mad_hdr_from_wr( p_mad_wr ); + p_smp = (ib_smp_t*)p_mad; + + smp_is_set = (p_smp->method == IB_MAD_METHOD_SET); + + /* Get a MAD element from the pool for the response. */ + p_mad_send = PARENT_STRUCT( p_mad_wr, al_mad_send_t, mad_wr ); + if( p_mad_send->p_send_mad->resp_expected ) + { + status = get_resp_mad( p_spl_qp_svc, p_mad_wr, &p_mad_response ); + if( status != IB_SUCCESS ) + { + __complete_send_mad( p_spl_qp_svc->h_mad_disp, p_mad_wr, + IB_WCS_LOCAL_OP_ERR ); + AL_EXIT( AL_DBG_SMI ); + return status; + } + p_mad_response_buf = p_mad_response->p_mad_buf; + /* Copy MAD to dispatch locally in case CA doesn't handle it. */ + *p_mad_response_buf = *p_mad; + } + else + { + p_mad_response_buf = NULL; + } + + /* Adjust directed route SMPs as required by IBA. */ + if( p_mad->mgmt_class == IB_MCLASS_SUBN_DIR ) + { + CL_ASSERT( !ib_smp_is_response( p_smp ) ); + + /* + * If this was a self addressed, directed route SMP, increment + * the hop pointer in the request before delivery as required + * by IBA. Otherwise, adjustment for remote requests occurs + * during inbound processing. + */ + if( p_smp->hop_count == 0 ) + p_smp->hop_ptr++; + } + + /* Forward the locally addressed MAD to the CA interface. */ + status = al_local_mad( p_spl_qp_svc->h_qp->obj.p_ci_ca->h_ca, + p_spl_qp_svc->port_num, &p_mad_wr->send_wr.dgrm.ud.h_av->av_attr, p_mad, p_mad_response_buf ); + + /* Reset directed route SMPs as required by IBA. */ + if( p_mad->mgmt_class == IB_MCLASS_SUBN_DIR ) + { + /* + * If this was a self addressed, directed route SMP, decrement + * the hop pointer in the response before delivery as required + * by IBA. Otherwise, adjustment for remote responses occurs + * during outbound processing. + */ + if( p_smp->hop_count == 0 ) + { + /* Adjust the request SMP. */ + p_smp->hop_ptr--; + + /* Adjust the response SMP. */ + if( p_mad_response_buf ) + { + p_smp = (ib_smp_t*)p_mad_response_buf; + p_smp->hop_ptr--; + } + } + } + + if( status != IB_SUCCESS ) + { + if( p_mad_response ) + ib_put_mad( p_mad_response ); + + __complete_send_mad( p_spl_qp_svc->h_mad_disp, p_mad_wr, + IB_WCS_LOCAL_OP_ERR ); + AL_EXIT( AL_DBG_SMI ); + return status; + } + + /* Check the completion status of this simulated send. */ + if( p_mad_send->p_send_mad->resp_expected ) + { + /* + * The SMI is uses PnP polling to refresh the base_lid and lmc. + * Polling takes time, so we update the values here to prevent + * the failure of LID routed MADs sent immediately following this + * assignment. Check the response to see if the port info was set. + */ + if( smp_is_set ) + { + ib_smp_t* p_smp_response = NULL; + + switch( p_mad_response_buf->mgmt_class ) + { + case IB_MCLASS_SUBN_DIR: + if( ib_smp_get_status( p_smp ) == IB_SA_MAD_STATUS_SUCCESS ) + { + p_smp_response = p_smp; + //p_port_info = + // (ib_port_info_t*)ib_smp_get_payload_ptr( p_smp ); + } + break; + + case IB_MCLASS_SUBN_LID: + if( p_mad_response_buf->status == IB_SA_MAD_STATUS_SUCCESS ) + { + p_smp_response = (ib_smp_t*)p_mad_response_buf; + //p_port_info = + // (ib_port_info_t*)ib_smp_get_payload_ptr((ib_smp_t*)p_mad_response_buf); + } + break; + + default: + break; + } + + if( p_smp_response ) + { + switch( p_smp_response->attr_id ) + { + case IB_MAD_ATTR_PORT_INFO: + { + ib_port_info_t *p_port_info = + (ib_port_info_t*)ib_smp_get_payload_ptr(p_smp_response); + p_spl_qp_svc->base_lid = p_port_info->base_lid; + p_spl_qp_svc->lmc = ib_port_info_get_lmc( p_port_info ); + p_spl_qp_svc->sm_lid = p_port_info->master_sm_base_lid; + p_spl_qp_svc->sm_sl = ib_port_info_get_sm_sl( p_port_info ); + + if(p_port_info->m_key) + p_spl_qp_svc->m_key = p_port_info->m_key; + if (p_port_info->subnet_timeout & 0x80) + { + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_PNP, + ("Client reregister event, setting sm_lid to 0.\n")); + ci_ca_lock_attr(p_spl_qp_svc->obj.p_ci_ca); + p_spl_qp_svc->obj.p_ci_ca->p_pnp_attr-> + p_port_attr[p_port_info->local_port_num - 1].sm_lid= 0; + ci_ca_unlock_attr(p_spl_qp_svc->obj.p_ci_ca); + } + } + break; + case IB_MAD_ATTR_P_KEY_TABLE: + case IB_MAD_ATTR_GUID_INFO: + case IB_MAD_ATTR_SLVL_TABLE: + case IB_MAD_ATTR_VL_ARBITRATION: + spl_qp_svc_update_cache( p_spl_qp_svc, p_smp_response); + break; + default : + break; + } + } + } + + + /* Construct the receive MAD element. */ + p_send_mad = p_mad_send->p_send_mad; + p_mad_response->status = IB_WCS_SUCCESS; + p_mad_response->grh_valid = p_send_mad->grh_valid; + if( p_mad_response->grh_valid ) + *p_mad_response->p_grh = *p_send_mad->p_grh; + p_mad_response->path_bits = p_send_mad->path_bits; + p_mad_response->pkey_index = p_send_mad->pkey_index; + p_mad_response->remote_lid = p_send_mad->remote_lid; + p_mad_response->remote_qkey = p_send_mad->remote_qkey; + p_mad_response->remote_qp = p_send_mad->remote_qp; + p_mad_response->remote_sl = p_send_mad->remote_sl; + if( p_mad_wr->send_wr.send_opt & IB_RECV_OPT_IMMEDIATE ) + { + p_mad_response->immediate_data = p_mad_wr->send_wr.immediate_data; + p_mad_response->recv_opt |= IB_RECV_OPT_IMMEDIATE; + } + + /* + * Hand the receive MAD element to the dispatcher before completing + * the send. This guarantees that the send request cannot time out. + */ + status = mad_disp_recv_done( p_spl_qp_svc->h_mad_disp, p_mad_response ); + if( status != IB_SUCCESS ) + ib_put_mad( p_mad_response ); + } + + __complete_send_mad( p_spl_qp_svc->h_mad_disp, p_mad_wr,IB_WCS_SUCCESS); + + + + /* If the SMP was a Get, no need to trigger a PnP poll. */ + if( status == IB_SUCCESS && !smp_is_set ) + status = IB_NOT_DONE; + + AL_EXIT( AL_DBG_SMI ); + return status; +} + + + +/* + * Asynchronous processing thread callback to send a local MAD. + */ +void +send_local_mad_cb( + IN cl_async_proc_item_t* p_item ) +{ + spl_qp_svc_t* p_spl_qp_svc; + ib_api_status_t status; + + AL_ENTER( AL_DBG_SMI ); + + CL_ASSERT( p_item ); + p_spl_qp_svc = PARENT_STRUCT( p_item, spl_qp_svc_t, send_async ); + + /* Process a local MAD send work request. */ + CL_ASSERT( p_spl_qp_svc->local_mad_wr ); + status = fwd_local_mad( p_spl_qp_svc, p_spl_qp_svc->local_mad_wr ); + + /* + * If we successfully processed a local MAD, which could have changed + * something (e.g. the LID) on the HCA. Scan for changes. + */ + if( status == IB_SUCCESS ) + pnp_poll(); + + /* + * Clear the local MAD pointer to allow processing of other MADs. + * This is done after polling for attribute changes to ensure that + * subsequent MADs pick up any changes performed by this one. + */ + cl_spinlock_acquire( &p_spl_qp_svc->obj.lock ); + p_spl_qp_svc->local_mad_wr = NULL; + cl_spinlock_release( &p_spl_qp_svc->obj.lock ); + + /* Continue processing any queued MADs on the QP. */ + special_qp_resume_sends( p_spl_qp_svc->h_qp ); + + /* No longer in use by the asynchronous processing thread. */ + cl_atomic_dec( &p_spl_qp_svc->in_use_cnt ); + + AL_EXIT( AL_DBG_SMI ); +} + + + +/* + * Special QP send completion callback. + */ +void +spl_qp_send_comp_cb( + IN const ib_cq_handle_t h_cq, + IN void* cq_context ) +{ + spl_qp_svc_t* p_spl_qp_svc; + + AL_ENTER( AL_DBG_SMI ); + + UNREFERENCED_PARAMETER( h_cq ); + + CL_ASSERT( cq_context ); + p_spl_qp_svc = cq_context; + +#if defined( CL_USE_MUTEX ) + + /* Queue an asynchronous processing item to process sends. */ + cl_spinlock_acquire( &p_spl_qp_svc->obj.lock ); + if( !p_spl_qp_svc->send_async_queued ) + { + p_spl_qp_svc->send_async_queued = TRUE; + ref_al_obj( &p_spl_qp_svc->obj ); + cl_async_proc_queue( gp_async_proc_mgr, &p_spl_qp_svc->send_async_cb ); + } + cl_spinlock_release( &p_spl_qp_svc->obj.lock ); + +#else + cl_spinlock_acquire( &p_spl_qp_svc->obj.lock ); + if( p_spl_qp_svc->state != SPL_QP_ACTIVE ) + { + cl_spinlock_release( &p_spl_qp_svc->obj.lock ); + AL_EXIT( AL_DBG_SMI ); + return; + } + cl_atomic_inc( &p_spl_qp_svc->in_use_cnt ); + cl_spinlock_release( &p_spl_qp_svc->obj.lock ); + + /* Queue the DPC. */ + CL_ASSERT( h_cq == p_spl_qp_svc->h_send_cq ); + KeInsertQueueDpc( &p_spl_qp_svc->send_dpc, NULL, NULL ); +#endif + + AL_EXIT( AL_DBG_SMI ); +} + + +void +spl_qp_send_dpc_cb( + IN KDPC *p_dpc, + IN void *context, + IN void *arg1, + IN void *arg2 + ) +{ + spl_qp_svc_t* p_spl_qp_svc; + + AL_ENTER( AL_DBG_SMI ); + + CL_ASSERT( context ); + p_spl_qp_svc = context; + + UNREFERENCED_PARAMETER( p_dpc ); + UNREFERENCED_PARAMETER( arg1 ); + UNREFERENCED_PARAMETER( arg2 ); + + spl_qp_comp( p_spl_qp_svc, p_spl_qp_svc->h_send_cq, IB_WC_SEND ); + + /* Continue processing any queued MADs on the QP. */ + special_qp_resume_sends( p_spl_qp_svc->h_qp ); + + cl_atomic_dec( &p_spl_qp_svc->in_use_cnt ); + + AL_EXIT( AL_DBG_SMI ); +} + + +#if defined( CL_USE_MUTEX ) +void +spl_qp_send_async_cb( + IN cl_async_proc_item_t* p_item ) +{ + spl_qp_svc_t* p_spl_qp_svc; + ib_api_status_t status; + + AL_ENTER( AL_DBG_SMI ); + + CL_ASSERT( p_item ); + p_spl_qp_svc = PARENT_STRUCT( p_item, spl_qp_svc_t, send_async_cb ); + + /* Reset asynchronous queue flag. */ + cl_spinlock_acquire( &p_spl_qp_svc->obj.lock ); + p_spl_qp_svc->send_async_queued = FALSE; + cl_spinlock_release( &p_spl_qp_svc->obj.lock ); + + spl_qp_comp( p_spl_qp_svc, p_spl_qp_svc->h_send_cq, IB_WC_SEND ); + + /* Continue processing any queued MADs on the QP. */ + status = special_qp_resume_sends( p_spl_qp_svc->h_qp ); + CL_ASSERT( status == IB_SUCCESS ); + + deref_al_obj( &p_spl_qp_svc->obj ); + + AL_EXIT( AL_DBG_SMI ); +} +#endif + + + +/* + * Special QP receive completion callback. + */ +void +spl_qp_recv_comp_cb( + IN const ib_cq_handle_t h_cq, + IN void* cq_context ) +{ + spl_qp_svc_t* p_spl_qp_svc; + + AL_ENTER( AL_DBG_SMI ); + + UNREFERENCED_PARAMETER( h_cq ); + + CL_ASSERT( cq_context ); + p_spl_qp_svc = cq_context; + +#if defined( CL_USE_MUTEX ) + + /* Queue an asynchronous processing item to process receives. */ + cl_spinlock_acquire( &p_spl_qp_svc->obj.lock ); + if( !p_spl_qp_svc->recv_async_queued ) + { + p_spl_qp_svc->recv_async_queued = TRUE; + ref_al_obj( &p_spl_qp_svc->obj ); + cl_async_proc_queue( gp_async_proc_mgr, &p_spl_qp_svc->recv_async_cb ); + } + cl_spinlock_release( &p_spl_qp_svc->obj.lock ); + +#else + cl_spinlock_acquire( &p_spl_qp_svc->obj.lock ); + if( p_spl_qp_svc->state != SPL_QP_ACTIVE ) + { + cl_spinlock_release( &p_spl_qp_svc->obj.lock ); + AL_EXIT( AL_DBG_SMI ); + return; + } + cl_atomic_inc( &p_spl_qp_svc->in_use_cnt ); + cl_spinlock_release( &p_spl_qp_svc->obj.lock ); + + /* Queue the DPC. */ + CL_ASSERT( h_cq == p_spl_qp_svc->h_recv_cq ); + KeInsertQueueDpc( &p_spl_qp_svc->recv_dpc, NULL, NULL ); +#endif + + AL_EXIT( AL_DBG_SMI ); +} + + +void +spl_qp_recv_dpc_cb( + IN KDPC *p_dpc, + IN void *context, + IN void *arg1, + IN void *arg2 + ) +{ + spl_qp_svc_t* p_spl_qp_svc; + + AL_ENTER( AL_DBG_SMI ); + + CL_ASSERT( context ); + p_spl_qp_svc = context; + + UNREFERENCED_PARAMETER( p_dpc ); + UNREFERENCED_PARAMETER( arg1 ); + UNREFERENCED_PARAMETER( arg2 ); + + spl_qp_comp( p_spl_qp_svc, p_spl_qp_svc->h_recv_cq, IB_WC_RECV ); + + cl_atomic_dec( &p_spl_qp_svc->in_use_cnt ); + + AL_EXIT( AL_DBG_SMI ); +} + + +#if defined( CL_USE_MUTEX ) +void +spl_qp_recv_async_cb( + IN cl_async_proc_item_t* p_item ) +{ + spl_qp_svc_t* p_spl_qp_svc; + + AL_ENTER( AL_DBG_SMI ); + + CL_ASSERT( p_item ); + p_spl_qp_svc = PARENT_STRUCT( p_item, spl_qp_svc_t, recv_async_cb ); + + /* Reset asynchronous queue flag. */ + cl_spinlock_acquire( &p_spl_qp_svc->obj.lock ); + p_spl_qp_svc->recv_async_queued = FALSE; + cl_spinlock_release( &p_spl_qp_svc->obj.lock ); + + spl_qp_comp( p_spl_qp_svc, p_spl_qp_svc->h_recv_cq, IB_WC_RECV ); + + deref_al_obj( &p_spl_qp_svc->obj ); + + AL_EXIT( AL_DBG_SMI ); +} +#endif + + +#define SPL_QP_MAX_POLL 16 +/* + * Special QP completion handler. + */ +void +spl_qp_comp( + IN spl_qp_svc_t* p_spl_qp_svc, + IN const ib_cq_handle_t h_cq, + IN ib_wc_type_t wc_type ) +{ + ib_wc_t wc; + ib_wc_t* p_free_wc = &wc; + ib_wc_t* p_done_wc; + al_mad_wr_t* p_mad_wr; + al_mad_element_t* p_al_mad; + ib_mad_element_t* p_mad_element; + ib_smp_t* p_smp; + ib_api_status_t status; + int max_poll = SPL_QP_MAX_POLL; + + AL_ENTER( AL_DBG_SMI_CB ); + + CL_ASSERT( p_spl_qp_svc ); + CL_ASSERT( h_cq ); + + /* Check the QP state and guard against error handling. */ + cl_spinlock_acquire( &p_spl_qp_svc->obj.lock ); + if( p_spl_qp_svc->state != SPL_QP_ACTIVE ) + { + cl_spinlock_release( &p_spl_qp_svc->obj.lock ); + return; + } + cl_atomic_inc( &p_spl_qp_svc->in_use_cnt ); + cl_spinlock_release( &p_spl_qp_svc->obj.lock ); + + wc.p_next = NULL; + /* Process work completions. */ + while( max_poll && ib_poll_cq( h_cq, &p_free_wc, &p_done_wc ) == IB_SUCCESS ) + { + /* Process completions one at a time. */ + CL_ASSERT( p_done_wc ); + + /* Flushed completions are handled elsewhere. */ + if( wc.status == IB_WCS_WR_FLUSHED_ERR ) + { + p_free_wc = &wc; + continue; + } + + /* + * Process the work completion. Per IBA specification, the + * wc.wc_type is undefined if wc.status is not IB_WCS_SUCCESS. + * Use the wc_type parameter. + */ + switch( wc_type ) + { + case IB_WC_SEND: + /* Get a pointer to the MAD work request. */ + p_mad_wr = (al_mad_wr_t*)((uintn_t)wc.wr_id); + + /* Remove the MAD work request from the service tracking queue. */ + cl_spinlock_acquire( &p_spl_qp_svc->obj.lock ); + cl_qlist_remove_item( &p_spl_qp_svc->send_queue, + &p_mad_wr->list_item ); + cl_spinlock_release( &p_spl_qp_svc->obj.lock ); + + /* Reset directed route SMPs as required by IBA. */ + p_smp = (ib_smp_t*)get_mad_hdr_from_wr( p_mad_wr ); + if( p_smp->mgmt_class == IB_MCLASS_SUBN_DIR ) + { + if( ib_smp_is_response( p_smp ) ) + p_smp->hop_ptr++; + else + p_smp->hop_ptr--; + } + + /* Report the send completion to the dispatcher. */ + mad_disp_send_done( p_spl_qp_svc->h_mad_disp, p_mad_wr, &wc ); + break; + + case IB_WC_RECV: + + /* Initialize pointers to the MAD element. */ + p_al_mad = (al_mad_element_t*)((uintn_t)wc.wr_id); + p_mad_element = &p_al_mad->element; + + /* Remove the AL MAD element from the service tracking list. */ + cl_spinlock_acquire( &p_spl_qp_svc->obj.lock ); + + cl_qlist_remove_item( &p_spl_qp_svc->recv_queue, + &p_al_mad->list_item ); + + /* Replenish the receive buffer. */ + spl_qp_svc_post_recvs( p_spl_qp_svc ); + cl_spinlock_release( &p_spl_qp_svc->obj.lock ); + + /* Construct the MAD element from the receive work completion. */ + build_mad_recv( p_mad_element, &wc ); + + /* Process the received MAD. */ + status = process_mad_recv( p_spl_qp_svc, p_mad_element ); + + /* Discard this MAD on error. */ + if( status != IB_SUCCESS ) + { + status = ib_put_mad( p_mad_element ); + CL_ASSERT( status == IB_SUCCESS ); + } + break; + + default: + CL_ASSERT( wc_type == IB_WC_SEND || wc_type == IB_WC_RECV ); + break; + } + + if( wc.status != IB_WCS_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("special QP completion error: %s! internal syndrome 0x%I64x\n", + ib_get_wc_status_str( wc.status ), wc.vendor_specific) ); + + /* Reset the special QP service and return. */ + spl_qp_svc_reset( p_spl_qp_svc ); + } + p_free_wc = &wc; + --max_poll; + } + + if( max_poll == 0 ) + { + /* We already have an in_use_cnt reference - use it to queue the DPC. */ + if( wc_type == IB_WC_SEND ) + KeInsertQueueDpc( &p_spl_qp_svc->send_dpc, NULL, NULL ); + else + KeInsertQueueDpc( &p_spl_qp_svc->recv_dpc, NULL, NULL ); + } + else + { + /* Rearm the CQ. */ + status = ib_rearm_cq( h_cq, FALSE ); + CL_ASSERT( status == IB_SUCCESS ); + + cl_atomic_dec( &p_spl_qp_svc->in_use_cnt ); + } + AL_EXIT( AL_DBG_SMI_CB ); +} + + + +/* + * Process a received MAD. + */ +ib_api_status_t +process_mad_recv( + IN spl_qp_svc_t* p_spl_qp_svc, + IN ib_mad_element_t* p_mad_element ) +{ + ib_smp_t* p_smp; + mad_route_t route; + ib_api_status_t status; + + AL_ENTER( AL_DBG_SMI ); + + CL_ASSERT( p_spl_qp_svc ); + CL_ASSERT( p_mad_element ); + + /* + * If the CA has a HW agent then this MAD should have been + * consumed below verbs. The fact that it was received here + * indicates that it should be forwarded to the dispatcher + * for delivery to a class manager. Otherwise, determine how + * the MAD should be routed. + */ + route = ROUTE_DISPATCHER; + if( check_local_mad( p_spl_qp_svc->h_qp ) ) + { + /* + * SMP and GMP processing is branched here to handle overlaps + * between class methods and attributes. + */ + switch( p_mad_element->p_mad_buf->mgmt_class ) + { + case IB_MCLASS_SUBN_DIR: + /* Perform special checks on directed route SMPs. */ + p_smp = (ib_smp_t*)p_mad_element->p_mad_buf; + + if( ( p_smp->hop_count >= IB_SUBNET_PATH_HOPS_MAX ) || + ( p_smp->hop_ptr >= IB_SUBNET_PATH_HOPS_MAX ) ) + { + route = ROUTE_DISCARD; + } + else if( ib_smp_is_response( p_smp ) ) + { + /* + * This node is the destination of the response. Discard + * the source LID or hop pointer are incorrect. + */ + if( p_smp->dr_slid == IB_LID_PERMISSIVE ) + { + if( p_smp->hop_ptr == 1 ) + { + p_smp->hop_ptr--; /* Adjust ptr per IBA spec. */ + } + else + { + route = ROUTE_DISCARD; + } + } + else if( ( p_smp->dr_slid < p_spl_qp_svc->base_lid ) || + ( p_smp->dr_slid >= p_spl_qp_svc->base_lid + + ( 1 << p_spl_qp_svc->lmc ) ) ) + { + route = ROUTE_DISCARD; + } + } + else + { + /* + * This node is the destination of the request. Discard + * the destination LID or hop pointer are incorrect. + */ + if( p_smp->dr_dlid == IB_LID_PERMISSIVE ) + { + if( p_smp->hop_count == p_smp->hop_ptr ) + { + p_smp->return_path[ p_smp->hop_ptr++ ] = + p_spl_qp_svc->port_num; /* Set path per IBA spec. */ + } + else + { + route = ROUTE_DISCARD; + } + } + else if( ( p_smp->dr_dlid < p_spl_qp_svc->base_lid ) || + ( p_smp->dr_dlid >= p_spl_qp_svc->base_lid + + ( 1 << p_spl_qp_svc->lmc ) ) ) + { + route = ROUTE_DISCARD; + } + } + + if( route == ROUTE_DISCARD ) break; + /* else fall through next case */ + + case IB_MCLASS_SUBN_LID: + route = route_recv_smp( p_mad_element ); + break; + + case IB_MCLASS_PERF: + route = route_recv_perf( p_mad_element ); + break; + + case IB_MCLASS_BM: + route = route_recv_bm( p_mad_element ); + break; + + case IB_MLX_VENDOR_CLASS1: + case IB_MLX_VENDOR_CLASS2: + route = route_recv_vendor( p_mad_element ); + break; + + default: + break; + } + } + + /* Route the MAD. */ + if( is_discard( route ) ) + status = IB_ERROR; + else if( is_dispatcher( route ) ) + status = mad_disp_recv_done( p_spl_qp_svc->h_mad_disp, p_mad_element ); + else if( is_remote( route ) ) + status = forward_sm_trap( p_spl_qp_svc, p_mad_element ); + else + status = recv_local_mad( p_spl_qp_svc, p_mad_element ); + + AL_EXIT( AL_DBG_SMI ); + return status; +} + + + +/* + * Route a received SMP. + */ +static mad_route_t +route_recv_smp( + IN ib_mad_element_t* p_mad_element ) +{ + mad_route_t route; + + AL_ENTER( AL_DBG_SMI ); + + CL_ASSERT( p_mad_element ); + + /* Process the received SMP. */ + switch( p_mad_element->p_mad_buf->method ) + { + case IB_MAD_METHOD_GET: + case IB_MAD_METHOD_SET: + route = route_recv_smp_attr( p_mad_element ); + break; + + case IB_MAD_METHOD_TRAP: + /* + * Special check to route locally generated traps to the remote SM. + * Distinguished from other receives by the p_wc->recv.ud.recv_opt + * IB_RECV_OPT_FORWARD flag. + * + * Note that because forwarded traps use AL MAD services, the upper + * 32-bits of the TID are reserved by the access layer. When matching + * a Trap Repress MAD, the SMA must only use the lower 32-bits of the + * TID. + */ + AL_PRINT(TRACE_LEVEL_INFORMATION, AL_DBG_SMI, ("Trap TID = 0x%08x:%08x \n", + ((uint32_t*)&p_mad_element->p_mad_buf->trans_id)[0], + ((uint32_t*)&p_mad_element->p_mad_buf->trans_id)[1])); + + route = ( p_mad_element->recv_opt & IB_RECV_OPT_FORWARD ) ? + ROUTE_REMOTE : ROUTE_DISPATCHER; + break; + + case IB_MAD_METHOD_TRAP_REPRESS: + /* + * Note that because forwarded traps use AL MAD services, the upper + * 32-bits of the TID are reserved by the access layer. When matching + * a Trap Repress MAD, the SMA must only use the lower 32-bits of the + * TID. + */ + AL_PRINT(TRACE_LEVEL_INFORMATION, AL_DBG_SMI, ("TrapRepress TID = 0x%08x:%08x \n", + ((uint32_t*)&p_mad_element->p_mad_buf->trans_id)[0], + ((uint32_t*)&p_mad_element->p_mad_buf->trans_id)[1])); + + route = ROUTE_LOCAL; + break; + + default: + route = ROUTE_DISPATCHER; + break; + } + + AL_EXIT( AL_DBG_SMI ); + return route; +} + + + +/* + * Route received SMP attributes. + */ +static mad_route_t +route_recv_smp_attr( + IN ib_mad_element_t* p_mad_element ) +{ + mad_route_t route; + + AL_ENTER( AL_DBG_SMI ); + + CL_ASSERT( p_mad_element ); + + /* Process the received SMP attributes. */ + switch( p_mad_element->p_mad_buf->attr_id ) + { + case IB_MAD_ATTR_NODE_DESC: + case IB_MAD_ATTR_NODE_INFO: + case IB_MAD_ATTR_GUID_INFO: + case IB_MAD_ATTR_PORT_INFO: + case IB_MAD_ATTR_P_KEY_TABLE: + case IB_MAD_ATTR_SLVL_TABLE: + case IB_MAD_ATTR_VL_ARBITRATION: + case IB_MAD_ATTR_VENDOR_DIAG: + case IB_MAD_ATTR_LED_INFO: + case IB_MAD_ATTR_SWITCH_INFO: + route = ROUTE_LOCAL; + break; + + default: + route = ROUTE_DISPATCHER; + break; + } + + AL_EXIT( AL_DBG_SMI ); + return route; +} + + +static mad_route_t +route_recv_bm( + IN ib_mad_element_t* p_mad_element ) +{ + switch( p_mad_element->p_mad_buf->method ) + { + case IB_MAD_METHOD_GET: + case IB_MAD_METHOD_SET: + if( p_mad_element->p_mad_buf->attr_id == IB_MAD_ATTR_CLASS_PORT_INFO ) + return ROUTE_LOCAL; + break; + default: + break; + } + return ROUTE_DISPATCHER; +} + +static mad_route_t +route_recv_perf( + IN ib_mad_element_t* p_mad_element ) +{ + switch( p_mad_element->p_mad_buf->method ) + { + case IB_MAD_METHOD_GET: + case IB_MAD_METHOD_SET: + return ROUTE_LOCAL; + default: + break; + } + return ROUTE_DISPATCHER; +} + +static mad_route_t +route_recv_vendor( + IN ib_mad_element_t* p_mad_element ) +{ + return ( p_mad_element->p_mad_buf->method & IB_MAD_METHOD_RESP_MASK ) ? + ROUTE_DISPATCHER : ROUTE_LOCAL; +} + +/* + * Forward a locally generated Subnet Management trap. + */ +ib_api_status_t +forward_sm_trap( + IN spl_qp_svc_t* p_spl_qp_svc, + IN ib_mad_element_t* p_mad_element ) +{ + ib_av_attr_t av_attr; + ib_api_status_t status; + + AL_ENTER( AL_DBG_SMI ); + + CL_ASSERT( p_spl_qp_svc ); + CL_ASSERT( p_mad_element ); + + /* Check the SMP class. */ + if( p_mad_element->p_mad_buf->mgmt_class != IB_MCLASS_SUBN_LID ) + { + /* + * Per IBA Specification Release 1.1 Section 14.2.2.1, + * "C14-5: Only a SM shall originate a directed route SMP." + * Therefore all traps should be LID routed; drop this one. + */ + AL_EXIT( AL_DBG_SMI ); + return IB_ERROR; + } + + if(p_spl_qp_svc->sm_lid == p_spl_qp_svc->base_lid) + return mad_disp_recv_done(p_spl_qp_svc->h_mad_disp,p_mad_element); + + /* Create an address vector for the SM. */ + cl_memclr( &av_attr, sizeof( ib_av_attr_t ) ); + av_attr.port_num = p_spl_qp_svc->port_num; + av_attr.sl = p_spl_qp_svc->sm_sl; + av_attr.dlid = p_spl_qp_svc->sm_lid; + av_attr.grh_valid = FALSE; + + status = ib_create_av( p_spl_qp_svc->h_qp->obj.p_ci_ca->h_pd_alias, + &av_attr, &p_mad_element->h_av ); + + if( status != IB_SUCCESS ) + { + AL_EXIT( AL_DBG_SMI ); + return status; + } + + /* Complete the initialization of the MAD element. */ + p_mad_element->p_next = NULL; + p_mad_element->remote_qkey = IB_QP_PRIVILEGED_Q_KEY; + p_mad_element->resp_expected = FALSE; + + /* Clear context1 for proper send completion callback processing. */ + p_mad_element->context1 = NULL; + + /* + * Forward the trap. Note that because forwarded traps use AL MAD + * services, the upper 32-bits of the TID are reserved by the access + * layer. When matching a Trap Repress MAD, the SMA must only use + * the lower 32-bits of the TID. + */ + status = ib_send_mad( p_spl_qp_svc->h_mad_svc, p_mad_element, NULL ); + + if( status != IB_SUCCESS ) + ib_destroy_av( p_mad_element->h_av ); + + AL_EXIT( AL_DBG_SMI ); + return status; +} + + +/* + * Process a locally routed MAD received from the special QP. + */ +ib_api_status_t +recv_local_mad( + IN spl_qp_svc_t* p_spl_qp_svc, + IN ib_mad_element_t* p_mad_request ) +{ + ib_mad_t* p_mad_hdr; + ib_api_status_t status; + + AL_ENTER( AL_DBG_SMI ); + + CL_ASSERT( p_spl_qp_svc ); + CL_ASSERT( p_mad_request ); + + /* Initialize the MAD element. */ + p_mad_hdr = ib_get_mad_buf( p_mad_request ); + p_mad_request->context1 = p_mad_request; + + /* Save the TID. */ + p_mad_request->context2 = + (void*)(uintn_t)al_get_al_tid( p_mad_hdr->trans_id ); +/* + * Disable warning about passing unaligned 64-bit value. + * The value is always aligned given how buffers are allocated + * and given the layout of a MAD. + */ +#pragma warning( push, 3 ) + al_set_al_tid( &p_mad_hdr->trans_id, 0 ); +#pragma warning( pop ) + + /* + * We need to get a response from the local HCA to this MAD only if this + * MAD is not itself a response. + */ + p_mad_request->resp_expected = !ib_mad_is_response( p_mad_hdr ); + p_mad_request->timeout_ms = LOCAL_MAD_TIMEOUT; + p_mad_request->send_opt = IB_SEND_OPT_LOCAL; + + /* Send the locally addressed MAD request to the CA for processing. */ + status = ib_send_mad( p_spl_qp_svc->h_mad_svc, p_mad_request, NULL ); + + AL_EXIT( AL_DBG_SMI ); + return status; +} + + + +/* + * Special QP alias send completion callback. + */ +void +spl_qp_alias_send_cb( + IN ib_mad_svc_handle_t h_mad_svc, + IN void* mad_svc_context, + IN ib_mad_element_t* p_mad_element ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_SMI ); + + UNUSED_PARAM( h_mad_svc ); + UNUSED_PARAM( mad_svc_context ); + CL_ASSERT( p_mad_element ); + + if( p_mad_element->h_av ) + { + status = ib_destroy_av( p_mad_element->h_av ); + CL_ASSERT( status == IB_SUCCESS ); + } + + status = ib_put_mad( p_mad_element ); + CL_ASSERT( status == IB_SUCCESS ); + + AL_EXIT( AL_DBG_SMI ); +} + + + +/* + * Special QP alias receive completion callback. + */ +void +spl_qp_alias_recv_cb( + IN ib_mad_svc_handle_t h_mad_svc, + IN void* mad_svc_context, + IN ib_mad_element_t* p_mad_response ) +{ + spl_qp_svc_t* p_spl_qp_svc; + ib_mad_element_t* p_mad_request; + ib_mad_t* p_mad_hdr; + ib_av_attr_t av_attr; + ib_api_status_t status; + + AL_ENTER( AL_DBG_SMI ); + + CL_ASSERT( mad_svc_context ); + CL_ASSERT( p_mad_response ); + + if ( !p_mad_response->send_context1 ) { + CL_ASSERT( p_mad_response->send_context1 ); + ib_put_mad( p_mad_response ); + AL_EXIT( AL_DBG_SMI ); + return; + } + + /* Initialize pointers. */ + p_spl_qp_svc = mad_svc_context; + p_mad_request = p_mad_response->send_context1; + p_mad_hdr = ib_get_mad_buf( p_mad_response ); + + /* Restore the TID, so it will match on the remote side. */ +#pragma warning( push, 3 ) + al_set_al_tid( &p_mad_hdr->trans_id, + (uint32_t)(uintn_t)p_mad_response->send_context2 ); +#pragma warning( pop ) + + /* Set the remote QP. */ + p_mad_response->remote_qp = p_mad_request->remote_qp; + p_mad_response->remote_qkey = p_mad_request->remote_qkey; + + /* Prepare to create an address vector. */ + cl_memclr( &av_attr, sizeof( ib_av_attr_t ) ); + av_attr.port_num = p_spl_qp_svc->port_num; + av_attr.sl = p_mad_request->remote_sl; + av_attr.static_rate = IB_PATH_RECORD_RATE_10_GBS; + av_attr.path_bits = p_mad_request->path_bits; + if( p_mad_request->grh_valid ) + { + cl_memcpy( &av_attr.grh, p_mad_request->p_grh, sizeof( ib_grh_t ) ); + av_attr.grh.src_gid = p_mad_request->p_grh->dest_gid; + av_attr.grh.dest_gid = p_mad_request->p_grh->src_gid; + av_attr.grh_valid = TRUE; + } + if( ( p_mad_hdr->mgmt_class == IB_MCLASS_SUBN_DIR ) && + ( ((ib_smp_t *)p_mad_hdr)->dr_dlid == IB_LID_PERMISSIVE ) ) + av_attr.dlid = IB_LID_PERMISSIVE; + else + av_attr.dlid = p_mad_request->remote_lid; + + /* Create an address vector. */ + status = ib_create_av( p_spl_qp_svc->h_qp->obj.p_ci_ca->h_pd_alias, + &av_attr, &p_mad_response->h_av ); + + if( status != IB_SUCCESS ) + { + ib_put_mad( p_mad_response ); + + AL_EXIT( AL_DBG_SMI ); + return; + } + + /* Send the response. */ + status = ib_send_mad( h_mad_svc, p_mad_response, NULL ); + + if( status != IB_SUCCESS ) + { + ib_destroy_av( p_mad_response->h_av ); + ib_put_mad( p_mad_response ); + } + + AL_EXIT( AL_DBG_SMI ); +} + + + +/* + * Post receive buffers to a special QP. + */ +static ib_api_status_t +spl_qp_svc_post_recvs( + IN spl_qp_svc_t* const p_spl_qp_svc ) +{ + ib_mad_element_t* p_mad_element; + al_mad_element_t* p_al_element; + ib_recv_wr_t recv_wr; + ib_api_status_t status = IB_SUCCESS; + + /* Attempt to post receive buffers up to the max_qp_depth limit. */ + while( cl_qlist_count( &p_spl_qp_svc->recv_queue ) < + (int32_t)p_spl_qp_svc->max_qp_depth ) + { + /* Get a MAD element from the pool. */ + status = ib_get_mad( p_spl_qp_svc->obj.p_ci_ca->pool_key, + MAD_BLOCK_SIZE, &p_mad_element ); + + if( status != IB_SUCCESS ) break; + + p_al_element = PARENT_STRUCT( p_mad_element, al_mad_element_t, + element ); + + /* Build the receive work request. */ + recv_wr.p_next = NULL; + recv_wr.wr_id = (uintn_t)p_al_element; + recv_wr.num_ds = 1; + recv_wr.ds_array = &p_al_element->grh_ds; + + /* Queue the receive on the service tracking list. */ + cl_qlist_insert_tail( &p_spl_qp_svc->recv_queue, + &p_al_element->list_item ); + + /* Post the receive. */ + status = ib_post_recv( p_spl_qp_svc->h_qp, &recv_wr, NULL ); + + if( status != IB_SUCCESS ) + { + AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + ("Failed to post receive %p\n", + p_al_element) ); + cl_qlist_remove_item( &p_spl_qp_svc->recv_queue, + &p_al_element->list_item ); + + ib_put_mad( p_mad_element ); + break; + } + } + + return status; +} + + + +/* + * Special QP service asynchronous event callback. + */ +void +spl_qp_svc_event_cb( + IN ib_async_event_rec_t *p_event_rec ) +{ + spl_qp_svc_t* p_spl_qp_svc; + + AL_ENTER( AL_DBG_SMI ); + + CL_ASSERT( p_event_rec ); + CL_ASSERT( p_event_rec->context ); + + if( p_event_rec->code == IB_AE_SQ_DRAINED ) + { + AL_EXIT( AL_DBG_SMI ); + return; + } + + p_spl_qp_svc = p_event_rec->context; + + spl_qp_svc_reset( p_spl_qp_svc ); + + AL_EXIT( AL_DBG_SMI ); +} + + + +/* + * Special QP service reset. + */ +void +spl_qp_svc_reset( + IN spl_qp_svc_t* p_spl_qp_svc ) +{ + cl_spinlock_acquire( &p_spl_qp_svc->obj.lock ); + + if( p_spl_qp_svc->state != SPL_QP_ACTIVE ) + { + cl_spinlock_release( &p_spl_qp_svc->obj.lock ); + return; + } + + /* Change the special QP service to the error state. */ + p_spl_qp_svc->state = SPL_QP_ERROR; + + /* Flag the service as in use by the asynchronous processing thread. */ + cl_atomic_inc( &p_spl_qp_svc->in_use_cnt ); + + cl_spinlock_release( &p_spl_qp_svc->obj.lock ); + + /* Queue an asynchronous processing item to reset the special QP. */ + cl_async_proc_queue( gp_async_proc_mgr, &p_spl_qp_svc->reset_async ); +} + + + +/* + * Asynchronous processing thread callback to reset the special QP service. + */ +void +spl_qp_svc_reset_cb( + IN cl_async_proc_item_t* p_item ) +{ + spl_qp_svc_t* p_spl_qp_svc; + cl_list_item_t* p_list_item; + ib_wc_t wc; + ib_wc_t* p_free_wc; + ib_wc_t* p_done_wc; + al_mad_wr_t* p_mad_wr; + al_mad_element_t* p_al_mad; + ib_qp_mod_t qp_mod; + ib_api_status_t status; + cl_qlist_t mad_wr_list; + + AL_ENTER( AL_DBG_SMI ); + + CL_ASSERT( p_item ); + p_spl_qp_svc = PARENT_STRUCT( p_item, spl_qp_svc_t, reset_async ); + + /* Wait here until the special QP service is only in use by this thread. */ + while( p_spl_qp_svc->in_use_cnt != 1 ) + { + cl_thread_suspend( 0 ); + } + + /* Change the QP to the RESET state. */ + cl_memclr( &qp_mod, sizeof( ib_qp_mod_t ) ); + qp_mod.req_state = IB_QPS_RESET; + + status = ib_modify_qp( p_spl_qp_svc->h_qp, &qp_mod ); + CL_ASSERT( status == IB_SUCCESS ); + + /* Return receive MAD elements to the pool. */ + cl_spinlock_acquire( &p_spl_qp_svc->obj.lock ); + for( p_list_item = cl_qlist_remove_head( &p_spl_qp_svc->recv_queue ); + p_list_item != cl_qlist_end( &p_spl_qp_svc->recv_queue ); + p_list_item = cl_qlist_remove_head( &p_spl_qp_svc->recv_queue ) ) + { + p_al_mad = PARENT_STRUCT( p_list_item, al_mad_element_t, list_item ); + + status = ib_put_mad( &p_al_mad->element ); + CL_ASSERT( status == IB_SUCCESS ); + } + cl_spinlock_release( &p_spl_qp_svc->obj.lock ); + + /* Re-initialize the QP. */ + status = ib_init_dgrm_svc( p_spl_qp_svc->h_qp, NULL ); + CL_ASSERT( status == IB_SUCCESS ); + + /* Poll to remove any remaining send completions from the CQ. */ + do + { + cl_memclr( &wc, sizeof( ib_wc_t ) ); + p_free_wc = &wc; + status = ib_poll_cq( p_spl_qp_svc->h_send_cq, &p_free_wc, &p_done_wc ); + + } while( status == IB_SUCCESS ); + + /* Post receive buffers. */ + cl_spinlock_acquire( &p_spl_qp_svc->obj.lock ); + spl_qp_svc_post_recvs( p_spl_qp_svc ); + + /* Re-queue any outstanding MAD send operations. */ + cl_qlist_init( &mad_wr_list ); + cl_qlist_insert_list_tail( &mad_wr_list, &p_spl_qp_svc->send_queue ); + cl_spinlock_release( &p_spl_qp_svc->obj.lock ); + + for( p_list_item = cl_qlist_remove_head( &mad_wr_list ); + p_list_item != cl_qlist_end( &mad_wr_list ); + p_list_item = cl_qlist_remove_head( &mad_wr_list ) ) + { + p_mad_wr = PARENT_STRUCT( p_list_item, al_mad_wr_t, list_item ); + special_qp_queue_mad( p_spl_qp_svc->h_qp, p_mad_wr ); + } + + cl_spinlock_acquire( &p_spl_qp_svc->obj.lock ); + if( p_spl_qp_svc->state == SPL_QP_ERROR ) + { + /* The QP is ready. Change the state. */ + p_spl_qp_svc->state = SPL_QP_ACTIVE; + cl_spinlock_release( &p_spl_qp_svc->obj.lock ); + + /* Re-arm the CQs. */ + status = ib_rearm_cq( p_spl_qp_svc->h_recv_cq, FALSE ); + CL_ASSERT( status == IB_SUCCESS ); + status = ib_rearm_cq( p_spl_qp_svc->h_send_cq, FALSE ); + CL_ASSERT( status == IB_SUCCESS ); + + /* Resume send processing. */ + special_qp_resume_sends( p_spl_qp_svc->h_qp ); + } + else + { + cl_spinlock_release( &p_spl_qp_svc->obj.lock ); + } + + /* No longer in use by the asynchronous processing thread. */ + cl_atomic_dec( &p_spl_qp_svc->in_use_cnt ); + + AL_EXIT( AL_DBG_SMI ); +} + + + +/* + * Special QP alias asynchronous event callback. + */ +void +spl_qp_alias_event_cb( + IN ib_async_event_rec_t *p_event_rec ) +{ + UNUSED_PARAM( p_event_rec ); +} + + + +/* + * Acquire the SMI dispatcher for the given port. + */ +ib_api_status_t +acquire_smi_disp( + IN const ib_net64_t port_guid, + OUT al_mad_disp_handle_t* const ph_mad_disp ) +{ + CL_ASSERT( gp_spl_qp_mgr ); + return acquire_svc_disp( &gp_spl_qp_mgr->smi_map, port_guid, ph_mad_disp ); +} + + + +/* + * Acquire the GSI dispatcher for the given port. + */ +ib_api_status_t +acquire_gsi_disp( + IN const ib_net64_t port_guid, + OUT al_mad_disp_handle_t* const ph_mad_disp ) +{ + CL_ASSERT( gp_spl_qp_mgr ); + return acquire_svc_disp( &gp_spl_qp_mgr->gsi_map, port_guid, ph_mad_disp ); +} + + + +/* + * Acquire the service dispatcher for the given port. + */ +ib_api_status_t +acquire_svc_disp( + IN const cl_qmap_t* const p_svc_map, + IN const ib_net64_t port_guid, + OUT al_mad_disp_handle_t *ph_mad_disp ) +{ + cl_map_item_t* p_svc_item; + spl_qp_svc_t* p_spl_qp_svc; + + AL_ENTER( AL_DBG_SMI ); + + CL_ASSERT( p_svc_map ); + CL_ASSERT( gp_spl_qp_mgr ); + + /* Search for the SMI or GSI service for the given port. */ + cl_spinlock_acquire( &gp_spl_qp_mgr->obj.lock ); + p_svc_item = cl_qmap_get( p_svc_map, port_guid ); + cl_spinlock_release( &gp_spl_qp_mgr->obj.lock ); + if( p_svc_item == cl_qmap_end( p_svc_map ) ) + { + /* The port does not have an active agent. */ + AL_EXIT( AL_DBG_SMI ); + return IB_INVALID_GUID; + } + + p_spl_qp_svc = PARENT_STRUCT( p_svc_item, spl_qp_svc_t, map_item ); + + /* Found a match. Get MAD dispatcher handle. */ + *ph_mad_disp = p_spl_qp_svc->h_mad_disp; + + /* Reference the MAD dispatcher on behalf of the client. */ + ref_al_obj( &p_spl_qp_svc->h_mad_disp->obj ); + + AL_EXIT( AL_DBG_SMI ); + return IB_SUCCESS; +} + + + +/* + * Force a poll for CA attribute changes. + */ +void +force_smi_poll( + void ) +{ + AL_ENTER( AL_DBG_SMI ); + + /* + * Stop the poll timer. Just invoke the timer callback directly to + * save the thread context switching. + */ + smi_poll_timer_cb( gp_spl_qp_mgr ); + + AL_EXIT( AL_DBG_SMI ); +} + + + +/* + * Poll for CA port attribute changes. + */ +void +smi_poll_timer_cb( + IN void* context ) +{ + cl_status_t cl_status; + + AL_ENTER( AL_DBG_SMI ); + + CL_ASSERT( context ); + CL_ASSERT( gp_spl_qp_mgr == context ); + UNUSED_PARAM( context ); + + /* + * Scan for changes on the local HCAs. Since the PnP manager has its + * own thread for processing changes, we kick off that thread in parallel + * reposting receive buffers to the SQP agents. + */ + pnp_poll(); + + /* + * To handle the case where force_smi_poll is called at the same time + * the timer expires, check if the asynchronous processing item is in + * use. If it is already in use, it means that we're about to poll + * anyway, so just ignore this call. + */ + cl_spinlock_acquire( &gp_spl_qp_mgr->obj.lock ); + + /* Perform port processing on the special QP agents. */ + cl_qlist_apply_func( &gp_spl_qp_mgr->obj.obj_list, smi_post_recvs, + gp_spl_qp_mgr ); + + /* Determine if there are any special QP agents to poll. */ + if( !cl_is_qlist_empty( &gp_spl_qp_mgr->obj.obj_list ) && g_smi_poll_interval ) + { + /* Restart the polling timer. */ + cl_status = + cl_timer_start( &gp_spl_qp_mgr->poll_timer, g_smi_poll_interval ); + CL_ASSERT( cl_status == CL_SUCCESS ); + } + cl_spinlock_release( &gp_spl_qp_mgr->obj.lock ); + + AL_EXIT( AL_DBG_SMI ); +} + + + +/* + * Post receive buffers to a special QP. + */ +void +smi_post_recvs( + IN cl_list_item_t* const p_list_item, + IN void* context ) +{ + al_obj_t* p_obj; + spl_qp_svc_t* p_spl_qp_svc; + + AL_ENTER( AL_DBG_SMI ); + + CL_ASSERT( p_list_item ); + UNUSED_PARAM( context ); + + p_obj = PARENT_STRUCT( p_list_item, al_obj_t, pool_item ); + p_spl_qp_svc = PARENT_STRUCT( p_obj, spl_qp_svc_t, obj ); + + cl_spinlock_acquire( &p_spl_qp_svc->obj.lock ); + if( p_spl_qp_svc->state != SPL_QP_ACTIVE ) + { + cl_spinlock_release( &p_spl_qp_svc->obj.lock ); + return; + } + + spl_qp_svc_post_recvs( p_spl_qp_svc ); + cl_spinlock_release( &p_spl_qp_svc->obj.lock ); + + AL_EXIT( AL_DBG_SMI ); +} diff --git a/branches/WOF2-3/core/al/kernel/al_smi.h b/branches/WOF2-3/core/al/kernel/al_smi.h new file mode 100644 index 00000000..62cb0fe2 --- /dev/null +++ b/branches/WOF2-3/core/al/kernel/al_smi.h @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#if !defined( __AL_SMI_H__ ) +#define __AL_SMI_H__ + + +#include +#include +#include "al_common.h" +#include "al_mad.h" + + +/* Global special QP manager */ +typedef struct _spl_qp_mgr +{ + al_obj_t obj; /* Child of gp_al_mgr */ + ib_pnp_handle_t h_qp0_pnp; /* Handle for QP0 port PnP events */ + ib_pnp_handle_t h_qp1_pnp; /* Handle for QP1 port PnP events */ + + cl_timer_t poll_timer; /* Timer for polling HW SMIs */ + + cl_qmap_t smi_map; /* List of SMI services */ + cl_qmap_t gsi_map; /* List of GSI services */ + +} spl_qp_mgr_t; + + + +typedef enum _spl_qp_svc_state +{ + SPL_QP_INIT = 0, + SPL_QP_ACTIVE, + SPL_QP_ERROR, + SPL_QP_DESTROYING + +} spl_qp_svc_state_t; + +/* + * Attribute cache for port info saved to expedite local MAD processing. + * Note that the cache accounts for the worst case GID and PKEY table size + * but is allocated from paged pool, so it's nothing to worry about. + */ + +typedef struct _guid_block +{ + boolean_t valid; + ib_guid_info_t tbl; + +} guid_block_t; + + +typedef struct _pkey_block +{ + boolean_t valid; + ib_pkey_table_t tbl; + +} pkey_block_t; + +typedef struct _sl_vl_cache +{ + boolean_t valid; + ib_slvl_table_t tbl; + +} sl_vl_cache_t; + +typedef struct _vl_arb_block +{ + boolean_t valid; + ib_vl_arb_table_t tbl; + +} vl_arb_block_t; + +typedef struct _attr_cache +{ + guid_block_t guid_block[32]; + pkey_block_t pkey_tbl[2048]; + sl_vl_cache_t sl_vl; + vl_arb_block_t vl_arb[4]; + +} spl_qp_cache_t; + + +/* Per port special QP service */ +typedef struct _spl_qp_svc +{ + al_obj_t obj; /* Child of spl_qp_agent_t */ + cl_map_item_t map_item; /* Item on SMI/GSI list */ + + net64_t port_guid; + uint8_t port_num; + ib_net16_t base_lid; + uint8_t lmc; + + ib_net16_t sm_lid; + uint8_t sm_sl; + ib_net64_t m_key; + + spl_qp_cache_t cache; + cl_spinlock_t cache_lock; + boolean_t cache_en; + + al_mad_disp_handle_t h_mad_disp; + ib_cq_handle_t h_send_cq; + ib_cq_handle_t h_recv_cq; + ib_qp_handle_t h_qp; + +#if defined( CL_USE_MUTEX ) + boolean_t send_async_queued; + cl_async_proc_item_t send_async_cb; + boolean_t recv_async_queued; + cl_async_proc_item_t recv_async_cb; +#endif + + spl_qp_svc_state_t state; + atomic32_t in_use_cnt; + cl_async_proc_item_t reset_async; + + uint32_t max_qp_depth; + al_mad_wr_t* local_mad_wr; + cl_qlist_t send_queue; + cl_qlist_t recv_queue; + cl_async_proc_item_t send_async; + + ib_qp_handle_t h_qp_alias; + ib_pool_key_t pool_key; + ib_mad_svc_handle_t h_mad_svc; + + KDPC send_dpc; + KDPC recv_dpc; + +} spl_qp_svc_t; + + +typedef enum _mad_route +{ + ROUTE_DISPATCHER = 0, + ROUTE_REMOTE, + ROUTE_LOCAL, + ROUTE_LOOPBACK, + ROUTE_DISCARD + +} mad_route_t; + + +static inline boolean_t +is_dispatcher( + IN const mad_route_t route ) +{ + return( route == ROUTE_DISPATCHER ); +} + + +static inline boolean_t +is_remote( + IN const mad_route_t route ) +{ + return( route == ROUTE_REMOTE ); +} + + +static inline boolean_t +is_discard( + IN const mad_route_t route ) +{ + return( route == ROUTE_DISCARD ); +} + + +static inline boolean_t +is_loopback( + IN const mad_route_t route ) +{ + return( route == ROUTE_LOOPBACK ); +} + + +static inline boolean_t +is_local( + IN const mad_route_t route ) +{ + /* + * Loopback implies a locally routed MAD. Discarded MADs are always + * handled locally to maintain proper order of work completions. + */ + return( ( route == ROUTE_LOCAL ) || + is_loopback( route ) || is_discard( route ) ); +} + + +ib_api_status_t +create_spl_qp_mgr( + IN al_obj_t* const p_parent_obj ); + + +ib_api_status_t +acquire_smi_disp( + IN const ib_net64_t port_guid, + OUT al_mad_disp_handle_t* const ph_mad_disp ); + + +ib_api_status_t +acquire_gsi_disp( + IN const ib_net64_t port_guid, + OUT al_mad_disp_handle_t* const ph_mad_disp ); + + +ib_api_status_t +spl_qp_svc_send( + IN const ib_qp_handle_t h_qp, + IN ib_send_wr_t* const p_send_wr ); + + +void +force_smi_poll( + void ); + + +#endif diff --git a/branches/WOF2-3/core/al/kernel/ibal.rc b/branches/WOF2-3/core/al/kernel/ibal.rc new file mode 100644 index 00000000..608d6f38 --- /dev/null +++ b/branches/WOF2-3/core/al/kernel/ibal.rc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef _DEBUG_ +#define VER_FILEDESCRIPTION_STR "Kernel Mode InfiniBand Access Layer (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "Kernel Mode InfiniBand Access Layer" +#endif + +#define VER_INTERNALNAME_STR "ibal.sys" +#define VER_ORIGINALFILENAME_STR "ibal.sys" + +#include diff --git a/branches/WOF2-3/core/al/kernel/makefile b/branches/WOF2-3/core/al/kernel/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-3/core/al/kernel/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\inc\openib.def diff --git a/branches/WOF2-3/core/al/user/SOURCES b/branches/WOF2-3/core/al/user/SOURCES new file mode 100644 index 00000000..bc294a53 --- /dev/null +++ b/branches/WOF2-3/core/al/user/SOURCES @@ -0,0 +1,100 @@ +!if $(FREEBUILD) +TARGETNAME=ibal +!else +TARGETNAME=ibald +!endif + +TARGETPATH=..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE=DYNLINK +DLLENTRY=DllMain + + + +!if $(FREEBUILD) +ENABLE_EVENT_TRACING=1 +#!else +#ENABLE_EVENT_TRACING=1 +!endif + + + +!if $(_NT_TOOLS_VERSION) == 0x700 +# DDK +DLLDEF=$O\al_exports.def +!else +# WDK +DLLDEF=$(OBJ_PATH)\$O\al_exports.def +!endif + +USE_NTDLL=1 + +SOURCES=\ + ibal.rc \ + al_dll.c \ + al_mad_pool.c \ + ual_av.c \ + ual_ca.c \ + ual_ci_ca.c \ + ual_cm_cep.c \ + ual_cq.c \ + ual_mad.c \ + ual_mad_pool.c \ + ual_mcast.c \ + ual_mgr.c \ + ual_mr.c \ + ual_mw.c \ + ual_pd.c \ + ual_pnp.c \ + ual_qp.c \ + ual_sa_req.c \ + ual_srq.c \ + ..\al.c \ + ..\al_av.c \ + ..\al_ca.c \ + ..\al_ci_ca_shared.c \ + ..\al_cm_qp.c \ + ..\al_common.c \ + ..\al_cq.c \ + ..\al_dm.c \ + ..\al_init.c \ + ..\al_mad.c \ + ..\al_mcast.c \ + ..\al_mgr_shared.c \ + ..\al_mr_shared.c \ + ..\al_mw.c \ + ..\al_pd.c \ + ..\al_qp.c \ + ..\al_query.c \ + ..\al_reg_svc.c \ + ..\al_res_mgr.c \ + ..\al_srq.c \ + ..\al_sub.c \ + ..\ib_common.c \ + ..\ib_statustext.c + +INCLUDES=..;..\..\..\inc;..\..\..\inc\user;;..\..\bus\kernel\$O; + +USER_C_FLAGS=$(USER_C_FLAGS) -DEXPORT_AL_SYMBOLS -DCL_NO_TRACK_MEM -DWPP_OLDCC + +TARGETLIBS= \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\Advapi32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\complib.lib +!else + $(TARGETPATH)\*\complibd.lib +!endif + +!IFDEF ENABLE_EVENT_TRACING + +C_DEFINES = $(C_DEFINES) -DEVENT_TRACING + +RUN_WPP = $(SOURCES) -ext: .c .h .C .H \ + -scan:..\al_debug.h \ + -func:AL_PRINT(LEVEL,FLAGS,(MSG,...)) \ + -func:AL_PRINT_EXIT(LEVEL,FLAGS,(MSG,...)) \ + -dll +!ENDIF + + +MSC_WARNING_LEVEL= /W4 diff --git a/branches/WOF2-3/core/al/user/al_dll.c b/branches/WOF2-3/core/al/user/al_dll.c new file mode 100644 index 00000000..85aef032 --- /dev/null +++ b/branches/WOF2-3/core/al/user/al_dll.c @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include +#include +#include "ual_support.h" +#include "al_mgr.h" +#include "ib_common.h" +#include "al_init.h" + +#include "al_debug.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "al_dll.tmh" +#endif + + + +HANDLE g_al_device = INVALID_HANDLE_VALUE; +cl_mutex_t g_open_close_mutex; +cl_perf_t g_perf; + +extern al_mgr_t* gp_al_mgr; +extern cl_async_proc_t *gp_async_proc_mgr; + + +static BOOL +_DllMain( + IN HINSTANCE h_module, + IN DWORD ul_reason_for_call, + IN LPVOID lp_reserved ) +{ + +#if !defined(EVENT_TRACING) +#if DBG + +#define ENV_BUFSIZE 16 + + TCHAR dbg_lvl_str[ENV_BUFSIZE]; + DWORD i; +#endif +#endif + + UNUSED_PARAM( lp_reserved ); + + switch( ul_reason_for_call ) + { + case DLL_PROCESS_ATTACH: + +#if defined(EVENT_TRACING) +#if DBG + WPP_INIT_TRACING(L"ibald.dll"); +#else + WPP_INIT_TRACING(L"ibal.dll"); +#endif +#endif + cl_perf_init( &g_perf, AlMaxPerf ); + DisableThreadLibraryCalls( h_module ); + + cl_mutex_construct( &g_open_close_mutex ); + if( cl_mutex_init( &g_open_close_mutex ) != CL_SUCCESS ) + return FALSE; + +#if !defined(EVENT_TRACING) +#if DBG + + i = GetEnvironmentVariable( "IBAL_UAL_DBG_LEVEL", dbg_lvl_str, ENV_BUFSIZE ); + if( i && i <= 16 ) + { + g_al_dbg_level = _tcstoul( dbg_lvl_str, NULL, ENV_BUFSIZE ); + } + + i = GetEnvironmentVariable( "IBAL_UAL_DBG_FLAGS", dbg_lvl_str, ENV_BUFSIZE ); + if( i && i <= 16 ) + { + g_al_dbg_flags = _tcstoul( dbg_lvl_str, NULL, ENV_BUFSIZE ); + } + + if( g_al_dbg_flags & AL_DBG_ERR ) + g_al_dbg_flags |= CL_DBG_ERROR; + + AL_PRINT(TRACE_LEVEL_INFORMATION ,AL_DBG_DEV , + ("Given IBAL_UAL_DBG debug level:%d debug flags 0x%x\n", + g_al_dbg_level ,g_al_dbg_flags) ); + +#endif +#endif + + break; + + case DLL_PROCESS_DETACH: + + cl_mutex_destroy( &g_open_close_mutex ); + cl_perf_destroy( &g_perf, TRUE ); + +#if defined(EVENT_TRACING) + WPP_CLEANUP(); +#endif + break; + } + return TRUE; +} + + +extern BOOL APIENTRY +_DllMainCRTStartupForGS( + IN HINSTANCE h_module, + IN DWORD ul_reason_for_call, + IN LPVOID lp_reserved ); + + +BOOL APIENTRY +DllMain( + IN HINSTANCE h_module, + IN DWORD ul_reason_for_call, + IN LPVOID lp_reserved ) +{ + switch( ul_reason_for_call ) + { + case DLL_PROCESS_ATTACH: + if( !_DllMainCRTStartupForGS( + h_module, ul_reason_for_call, lp_reserved ) ) + { + return FALSE; + } + + return _DllMain( h_module, ul_reason_for_call, lp_reserved ); + + case DLL_PROCESS_DETACH: + _DllMain( h_module, ul_reason_for_call, lp_reserved ); + + return _DllMainCRTStartupForGS( + h_module, ul_reason_for_call, lp_reserved ); + } + return TRUE; +} + + +cl_status_t +do_al_dev_ioctl( + IN uint32_t command, + IN void *p_in_buf, + IN uintn_t in_buf_size, + IN void *p_out_buf, + IN uintn_t out_buf_size, + OUT uintn_t *p_bytes_ret ) +{ + cl_status_t cl_status; + + AL_ENTER( AL_DBG_DEV ); + + CL_ASSERT( g_al_device != INVALID_HANDLE_VALUE ); + + cl_status = cl_ioctl_request( g_al_device, + command, + p_in_buf, + in_buf_size, + p_out_buf, + out_buf_size, + p_bytes_ret, + NULL ); + + if( cl_status != CL_SUCCESS ) + { + CL_ASSERT( cl_status != CL_PENDING ); + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("Error performing IOCTL 0x%08x to AL driver (%s)\n", + command, CL_STATUS_MSG(cl_status)) ); + return CL_ERROR; + } + + AL_EXIT( AL_DBG_DEV ); + return cl_status; +} diff --git a/branches/WOF2-3/core/al/user/al_exports.src b/branches/WOF2-3/core/al/user/al_exports.src new file mode 100644 index 00000000..02d80658 --- /dev/null +++ b/branches/WOF2-3/core/al/user/al_exports.src @@ -0,0 +1,191 @@ +#if DBG +LIBRARY ibald.dll +#else +LIBRARY ibal.dll +#endif + +#ifndef _WIN64 +EXPORTS +acquire_ca +deref_al_obj +ib_add_svc_entry +ib_alloc_pd +ib_bind_mw +ib_cancel_mad +ib_cancel_query +ib_ci_call +ib_close_al +ib_close_ca +ib_cm_apr +ib_cm_cancel +ib_cm_drep +ib_cm_dreq +ib_cm_handoff +ib_cm_lap +ib_cm_listen +ib_cm_mra +ib_cm_rej +ib_cm_rep +ib_cm_req +ib_cm_rtu +ib_convert_cl_status +ib_copy_ca_attr +ib_create_av +ib_create_cq +ib_create_ioc +ib_create_mad_pool +ib_create_mw +ib_create_qp +ib_dealloc_pd +ib_dereg_mad_pool +ib_dereg_mr +ib_dereg_pnp +ib_dereg_svc +ib_destroy_av +ib_destroy_cq +ib_destroy_ioc +ib_destroy_mad_pool +ib_destroy_mw +ib_destroy_qp +ib_dm_get_slot_lo_hi +ib_dm_set_slot_lo_hi +ib_force_apm +ib_get_async_event_str +ib_get_attr_offset +ib_get_attr_size +ib_get_ca_by_gid +ib_get_ca_guids +ib_get_err_str +ib_get_guid +ib_get_mad +ib_get_mad_buf +ib_get_node_type_str +ib_get_port_by_gid +ib_get_port_state_from_str +ib_get_port_state_str +ib_get_query_node_rec +ib_get_query_path_rec +ib_get_query_portinfo_rec +ib_get_query_result +ib_get_query_svc_rec +ib_get_spl_qp +ib_get_wc_status_str +ib_get_wc_type_str +ib_gid_get_guid +ib_gid_get_subnet_prefix +ib_gid_is_multicast +ib_gid_set_default +ib_grh_get_ver_class_flow +ib_grh_set_ver_class_flow +ib_init_dgrm_svc +ib_ioc_profile_get_subsys_vend_id +ib_ioc_profile_get_vend_id +ib_ioc_profile_set_subsys_vend_id +ib_ioc_profile_set_vend_id +ib_iou_info_diag_dev_id +ib_iou_info_option_rom +ib_join_mcast +ib_leave_mcast +ib_local_mad +ib_mad_init_new +ib_mad_init_response +ib_mad_is_response +ib_member_get_scope +ib_member_get_scope_state +ib_member_get_sl_flow_hop +ib_member_get_state +ib_member_set_join_state +ib_member_set_scope +ib_member_set_scope_state +ib_member_set_sl_flow_hop +ib_member_set_state +ib_modify_av +ib_modify_ca +ib_modify_cq +ib_modify_qp +ib_node_info_get_local_port_num +ib_node_info_get_vendor_id +ib_open_al +ib_open_ca +ib_path_get_ipd +ib_path_rec_flow_lbl +ib_path_rec_hop_limit +ib_path_rec_init_local +ib_path_rec_mtu +ib_path_rec_mtu_sel +ib_path_rec_pkt_life +ib_path_rec_pkt_life_sel +ib_path_rec_rate +ib_path_rec_rate_sel +ib_path_rec_set_hop_flow_raw +ib_path_rec_sl +ib_peek_cq +ib_pkey_get_base +ib_pkey_is_full_member +ib_poll_cq +ib_port_info_compute_rate +ib_port_info_get_link_speed_sup +ib_port_info_get_lmc +ib_port_info_get_mpb +ib_port_info_get_mtu_cap +ib_port_info_get_neighbor_mtu +ib_port_info_get_op_vls +ib_port_info_get_port_state +ib_port_info_get_vl_cap +ib_port_info_set_link_speed_sup +ib_port_info_set_lmc +ib_port_info_set_mpb +ib_port_info_set_neighbor_mtu +ib_port_info_set_op_vls +ib_port_info_set_port_state +ib_port_info_set_state_no_change +ib_port_info_set_timeout +ib_post_recv +ib_post_send +ib_put_mad +ib_query +ib_query_av +ib_query_ca +ib_query_ca_by_guid +ib_query_cq +ib_query_mr +ib_query_mw +ib_query_qp +ib_rearm_cq +ib_rearm_n_cq +ib_reg_ioc +ib_reg_mad_pool +ib_reg_mad_svc +ib_reg_mem +ib_reg_phys +ib_reg_pnp +ib_reg_shared +ib_reg_shmid +ib_reg_svc +ib_reject_ioc +ib_remove_svc_entry +ib_rereg_mem +ib_rereg_phys +ib_rmpp_get_resp_time +ib_rmpp_is_flag_set +ib_rmpp_set_resp_time +ib_sa_mad_get_payload_ptr +ib_send_mad +ib_slvl_table_set +ib_slvl_table_get +ib_sminfo_get_priority +ib_sminfo_get_state +ib_smp_get_payload_ptr +ib_smp_get_status +ib_smp_init_new +ib_smp_is_d +ib_smp_is_response +ib_subscribe +ib_switch_info_clear_state_change +ib_switch_info_get_state_change +ib_unsubscribe +ib_vl_arb_element_get_vl +ib_vl_arb_element_set_vl +ioc_at_slot +ual_close_ca +#endif diff --git a/branches/WOF2-3/core/al/user/al_mad_pool.c b/branches/WOF2-3/core/al/user/al_mad_pool.c new file mode 100644 index 00000000..6b582342 --- /dev/null +++ b/branches/WOF2-3/core/al/user/al_mad_pool.c @@ -0,0 +1,1508 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include "al.h" +#include "al_ci_ca.h" +#include "al_debug.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "al_mad_pool.tmh" +#endif + +#include "al_mad_pool.h" +#include "al_pd.h" +#include "al_verbs.h" +#include "ib_common.h" + + +typedef struct _mad_reg +{ + al_obj_t obj; /* Child of al_pool_key_t */ + ib_mr_handle_t h_mr; + net32_t lkey; + net32_t rkey; + mad_array_t* p_mad_array; + +} mad_reg_t; + + + +typedef struct _mad_send +{ + al_mad_send_t mad_send; + ib_pool_handle_t h_pool; + +} mad_send_t; + + + + +typedef struct _mad_rmpp +{ + al_mad_rmpp_t mad_rmpp; + ib_pool_handle_t h_pool; + +} mad_rmpp_t; + + + +/* + * Function prototypes. + */ +static void +__destroying_pool( + IN al_obj_t* p_obj ); + +static void +__free_pool( + IN al_obj_t* p_obj ); + +static void +__cleanup_pool_key( + IN al_obj_t* p_obj ); + +static void +__free_pool_key( + IN al_obj_t* p_obj ); + +static ib_api_status_t +__reg_mad_array( + IN al_pool_key_t* const p_pool_key, + IN mad_array_t* const p_mad_array ); + +static void +__free_mad_reg( + IN al_obj_t* p_obj ); + +static ib_api_status_t +__init_mad_element( + IN const al_pool_key_t* p_pool_key, + IN OUT mad_item_t* p_mad_item ); + +static cl_status_t +__locate_reg_cb( + IN const cl_list_item_t* const p_list_item, + IN void* context ); + +static ib_api_status_t +__grow_mad_pool( + IN const ib_pool_handle_t h_pool, + OUT mad_item_t** pp_mad_item OPTIONAL ); + +static void +__free_mad_array( + IN al_obj_t* p_obj ); + +static cl_status_t +__mad_send_init( + IN void* const p_object, + IN void* context, + OUT cl_pool_item_t** const pp_pool_item ); + +static cl_status_t +__mad_rmpp_init( + IN void* const p_object, + IN void* context, + OUT cl_pool_item_t** const pp_pool_item ); + + + +/* + * Create a MAD pool. + */ +ib_api_status_t +ib_create_mad_pool( + IN const ib_al_handle_t h_al, + IN const size_t min, + IN const size_t max, + IN const size_t grow_size, + OUT ib_pool_handle_t* const ph_pool ) +{ + ib_pool_handle_t h_pool; + ib_api_status_t status; + cl_status_t cl_status; + + AL_ENTER(AL_DBG_MAD_POOL); + + if( AL_OBJ_INVALID_HANDLE( h_al, AL_OBJ_TYPE_H_AL ) ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , ("IB_INVALID_AL_HANDLE\n") ); + return IB_INVALID_AL_HANDLE; + } + if( !ph_pool ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + /* Validate the min and max parameters. */ + if( (min > 0) && (max > 0) && (min > max) ) + return IB_INVALID_SETTING; + + h_pool = cl_zalloc( sizeof( al_pool_t ) ); + if( !h_pool ) + return IB_INSUFFICIENT_MEMORY; + + /* Initialize the pool lists. */ + cl_qlist_init( &h_pool->mad_stack ); + cl_qlist_init( &h_pool->key_list ); + cl_qpool_construct( &h_pool->mad_send_pool ); + cl_qpool_construct( &h_pool->mad_rmpp_pool ); + + /* Initialize the pool object. */ + construct_al_obj( &h_pool->obj, AL_OBJ_TYPE_H_MAD_POOL ); + status = init_al_obj( &h_pool->obj, h_pool, TRUE, + __destroying_pool, NULL, __free_pool ); + if( status != IB_SUCCESS ) + { + __free_pool( &h_pool->obj ); + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("init_al_obj failed with status %s.\n", ib_get_err_str(status)) ); + return status; + } + + /* Attach the pool to the AL object. */ + attach_al_obj( &h_al->obj, &h_pool->obj ); + + /* Save the pool parameters. Set grow_size to min for initialization. */ + h_pool->max = max; + if( min ) + { + h_pool->grow_size = min; + + /* Grow the pool to the minimum size. */ + status = __grow_mad_pool( h_pool, NULL ); + if( status != IB_SUCCESS ) + { + h_pool->obj.pfn_destroy( &h_pool->obj, NULL ); + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("grow_mad_pool failed with status %s.\n", + ib_get_err_str(status)) ); + return status; + } + } + + /* Save the grow_size for subsequent allocations. */ + h_pool->grow_size = grow_size; + + /* Initialize the pool of mad send tracking structures. */ + cl_status = cl_qpool_init( &h_pool->mad_send_pool, + min, max, grow_size, sizeof( mad_send_t ), + __mad_send_init, NULL, h_pool ); + if( cl_status != CL_SUCCESS ) + { + h_pool->obj.pfn_destroy( &h_pool->obj, NULL ); + status = ib_convert_cl_status( cl_status ); + h_pool->obj.pfn_destroy( &h_pool->obj, NULL ); + + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("cl_qpool_init failed with status %s.\n", ib_get_err_str(status)) ); + return status; + } + + /* Initialize the pool of mad send tracking structures. */ + cl_status = cl_qpool_init( &h_pool->mad_rmpp_pool, + min, max, grow_size, sizeof( mad_rmpp_t ), + __mad_rmpp_init, NULL, h_pool ); + if( cl_status != CL_SUCCESS ) + { + h_pool->obj.pfn_destroy( &h_pool->obj, NULL ); + status = ib_convert_cl_status( cl_status ); + h_pool->obj.pfn_destroy( &h_pool->obj, NULL ); + + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("cl_qpool_init failed with status %s.\n", ib_get_err_str(status)) ); + return status; + } + + /* Return the pool handle. */ + *ph_pool = h_pool; + + /* Release the reference taken in init_al_obj. */ + deref_al_obj( &h_pool->obj ); + + AL_EXIT(AL_DBG_MAD_POOL); + return IB_SUCCESS; +} + + + +/* + * Pre-destory the pool. + */ +static void +__destroying_pool( + IN al_obj_t* p_obj ) +{ + ib_pool_handle_t h_pool; + ib_al_handle_t h_al; + + AL_ENTER(AL_DBG_MAD_POOL); + + CL_ASSERT( p_obj ); + h_pool = PARENT_STRUCT( p_obj, al_pool_t, obj ); + + /* Get the AL instance of this MAD pool. */ + p_obj = h_pool->obj.p_parent_obj; + h_al = PARENT_STRUCT( p_obj, ib_al_t, obj ); + + /* Deregister this MAD pool from all protection domains. */ + al_dereg_pool( h_al, h_pool ); + + AL_EXIT(AL_DBG_MAD_POOL); +} + + + +/* + * Free the pool. + */ +static void +__free_pool( + IN al_obj_t* p_obj ) +{ + ib_pool_handle_t h_pool; + + CL_ASSERT( p_obj ); + h_pool = PARENT_STRUCT( p_obj, al_pool_t, obj ); + + cl_qpool_destroy( &h_pool->mad_send_pool ); + cl_qpool_destroy( &h_pool->mad_rmpp_pool ); + destroy_al_obj( &h_pool->obj ); + cl_free( h_pool ); +} + + + +/* + * Destory a MAD pool. + */ +ib_api_status_t +ib_destroy_mad_pool( + IN const ib_pool_handle_t h_pool ) +{ + cl_list_item_t* p_array_item; + al_obj_t* p_obj; + boolean_t busy; + + AL_ENTER(AL_DBG_MAD_POOL); + + if( AL_OBJ_INVALID_HANDLE( h_pool, AL_OBJ_TYPE_H_MAD_POOL ) ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , ("IB_INVALID_HANDLE\n") ); + return IB_INVALID_HANDLE; + } + + /* Verify that all send handles and MAD elements are in pool. */ + cl_spinlock_acquire( &h_pool->obj.lock ); + busy = ( h_pool->obj.ref_cnt > 1 ); + for( p_array_item = cl_qlist_head( &h_pool->obj.obj_list ); + p_array_item != cl_qlist_end( &h_pool->obj.obj_list ) && !busy; + p_array_item = cl_qlist_next( p_array_item ) ) + { + p_obj = PARENT_STRUCT( p_array_item, al_obj_t, pool_item ); + busy = ( p_obj->ref_cnt > 1 ); + } + cl_spinlock_release( &h_pool->obj.lock ); + + /* Return an error if the pool is busy. */ + if( busy ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("h_pool (0x%p) is busy!.\n", h_pool) ); + return IB_RESOURCE_BUSY; + } + + ref_al_obj( &h_pool->obj ); + h_pool->obj.pfn_destroy( &h_pool->obj, NULL ); + + AL_EXIT(AL_DBG_MAD_POOL); + return IB_SUCCESS; +} + + + +/* + * Register a MAD pool with a protection domain. + */ +ib_api_status_t +ib_reg_mad_pool( + IN const ib_pool_handle_t h_pool, + IN const ib_pd_handle_t h_pd, + OUT ib_pool_key_t* const pp_pool_key ) +{ + al_pool_key_t* p_pool_key; + cl_list_item_t* p_array_item; + al_obj_t* p_obj; + ib_al_handle_t h_al; + mad_array_t* p_mad_array; + ib_api_status_t status; + al_key_type_t key_type; + + AL_ENTER(AL_DBG_MAD_POOL); + + if( AL_OBJ_INVALID_HANDLE( h_pool, AL_OBJ_TYPE_H_MAD_POOL ) ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , ("IB_INVALID_HANDLE\n") ); + return IB_INVALID_HANDLE; + } + /* Alias keys require an alias PD. */ + if( AL_OBJ_INVALID_HANDLE( h_pd, AL_OBJ_TYPE_H_PD ) ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , ("IB_INVALID_PD_HANDLE\n") ); + return IB_INVALID_PD_HANDLE; + } + if( !pp_pool_key ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + /* Set the type of key to create. */ + if( h_pd->type != IB_PDT_ALIAS ) + key_type = AL_KEY_NORMAL; + else + key_type = AL_KEY_ALIAS; + + /* Allocate a pool key structure. */ + p_pool_key = cl_zalloc( sizeof( al_pool_key_t ) ); + if( !p_pool_key ) + return IB_INSUFFICIENT_MEMORY; + + /* Initialize the pool key. */ + construct_al_obj( &p_pool_key->obj, AL_OBJ_TYPE_H_POOL_KEY ); + p_pool_key->type = key_type; + p_pool_key->h_pool = h_pool; + p_pool_key->h_pd = h_pd; + + /* Initialize the pool key object. */ + status = init_al_obj( &p_pool_key->obj, p_pool_key, TRUE, + NULL, __cleanup_pool_key, __free_pool_key ); + if( status != IB_SUCCESS ) + { + __free_pool_key( &p_pool_key->obj ); + + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("init_al_obj failed with status %s.\n", ib_get_err_str(status)) ); + return status; + } + + status = attach_al_obj( &h_pd->obj, &p_pool_key->obj ); + if( status != IB_SUCCESS ) + { + p_pool_key->obj.pfn_destroy( &p_pool_key->obj, NULL ); + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("attach_al_obj returned %s.\n", ib_get_err_str(status)) ); + return status; + } + + /* From the PD, get the AL handle of the pool_key. */ + p_obj = h_pd->obj.p_parent_obj->p_parent_obj; + h_al = PARENT_STRUCT( p_obj, ib_al_t, obj ); + + /* Add this pool_key to the AL instance. */ + al_insert_key( h_al, p_pool_key ); + + ref_al_obj( &h_pd->obj ); + ref_al_obj( &h_pool->obj ); + + /* + * Take a reference on the global pool_key for this CA, if it exists. + * Note that the pool_key does not exist for the global MAD pool in + * user-mode, as that MAD pool never registers memory on a PD. + */ + if( key_type == AL_KEY_ALIAS && h_pd->obj.p_ci_ca->pool_key ) + { + ref_al_obj( &h_pd->obj.p_ci_ca->pool_key->obj ); + p_pool_key->pool_key = h_pd->obj.p_ci_ca->pool_key; + } + + /* Register the pool on the protection domain. */ + if( key_type == AL_KEY_NORMAL ) + { + /* Chain the pool key onto the pool. */ + cl_spinlock_acquire( &h_pool->obj.lock ); + cl_qlist_insert_tail( &h_pool->key_list, &p_pool_key->pool_item ); + + /* Synchronize with growing the MAD pool. */ + for( p_array_item = cl_qlist_head( &h_pool->obj.obj_list ); + p_array_item != cl_qlist_end( &h_pool->obj.obj_list ); + p_array_item = cl_qlist_next( p_array_item ) ) + { + p_obj = PARENT_STRUCT( p_array_item, al_obj_t, pool_item ); + p_mad_array = PARENT_STRUCT( p_obj, mad_array_t, obj ); + + status = __reg_mad_array( p_pool_key, p_mad_array ); + + if( status != IB_SUCCESS ) + { + cl_spinlock_release( &h_pool->obj.lock ); + p_pool_key->obj.pfn_destroy( &p_pool_key->obj, NULL ); + + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("reg_mad_array failed with status %s.\n", + ib_get_err_str(status)) ); + return status; + } + } + cl_spinlock_release( &h_pool->obj.lock ); + } + + /* + * If the PD is of alias type, then we need to create/register an + * equivalent pool key in the kernel. + */ + if( h_pd->type == IB_PDT_ALIAS ) + { + status = create_reg_mad_pool( h_pool, h_pd, p_pool_key ); + if( status != IB_SUCCESS ) + { + p_pool_key->obj.pfn_destroy( &p_pool_key->obj, NULL ); + return status; + } + } + + /* Return the pool key. */ + *pp_pool_key = (ib_pool_key_t)p_pool_key; + + /* Release the reference taken in init_al_obj. */ + deref_al_obj( &p_pool_key->obj ); + + AL_EXIT(AL_DBG_MAD_POOL); + return IB_SUCCESS; +} + + + +/* + * Release all references on objects that were needed by the pool key. + */ +static void +__cleanup_pool_key( + IN al_obj_t* p_obj ) +{ + cl_list_item_t *p_list_item, *p_next_item; + ib_mad_element_t *p_mad_element_list, *p_last_mad_element; + al_mad_element_t *p_mad; + ib_api_status_t status; + al_pool_key_t* p_pool_key; + + CL_ASSERT( p_obj ); + p_pool_key = PARENT_STRUCT( p_obj, al_pool_key_t, obj ); + + /* Search for any outstanding MADs associated with the given pool key. */ + if( p_pool_key->mad_cnt ) + { + p_mad_element_list = p_last_mad_element = NULL; + + cl_spinlock_acquire( &p_pool_key->h_al->mad_lock ); + for( p_list_item = cl_qlist_head( &p_pool_key->h_al->mad_list ); + p_list_item != cl_qlist_end( &p_pool_key->h_al->mad_list ); + p_list_item = p_next_item ) + { + p_next_item = cl_qlist_next( p_list_item ); + p_mad = PARENT_STRUCT( p_list_item, al_mad_element_t, al_item ); + + if( p_mad->pool_key != p_pool_key ) continue; + + /* Build the list of MADs to be returned to pool. */ + if( p_last_mad_element ) + p_last_mad_element->p_next = &p_mad->element; + else + p_mad_element_list = &p_mad->element; + + p_last_mad_element = &p_mad->element; + p_last_mad_element->p_next = NULL; + } + cl_spinlock_release( &p_pool_key->h_al->mad_lock ); + + /* Return any outstanding MADs to the pool. */ + if( p_mad_element_list ) + { + status = ib_put_mad( p_mad_element_list ); + if( status != IB_SUCCESS ) + { + AL_PRINT(TRACE_LEVEL_ERROR , AL_DBG_ERROR , + ("ib_put_mad failed with status %s, continuing.\n", + ib_get_err_str(status)) ); + } + } + } + + /* + * Remove the pool key from the pool to prevent further registrations + * against this pool. + * + * Warning: There is a small window where a pool key can be destroyed + * while its associated pool is growing. In this case, the pool key + * will receive a new registration after it has been destroyed. This + * is a result of having to register memory with the HCA without holding + * a lock, making correct synchronization impossible. One solution to + * this problem is to register all of physical memory, which avoids + * having to register more memory as a MAD pool grows. + */ + if( p_pool_key->type == AL_KEY_NORMAL ) + { + cl_spinlock_acquire( &p_pool_key->h_pool->obj.lock ); + cl_qlist_remove_item( &p_pool_key->h_pool->key_list, + &p_pool_key->pool_item ); + cl_spinlock_release( &p_pool_key->h_pool->obj.lock ); + } + + /* Remove this pool_key from the AL instance. */ + al_remove_key( p_pool_key ); + + /* User-mode only: cleanup kernel resources. */ + dereg_destroy_mad_pool( p_pool_key ); + + deref_al_obj( &p_pool_key->h_pool->obj ); + p_pool_key->h_pool = NULL; + deref_al_obj( &p_pool_key->h_pd->obj ); + p_pool_key->h_pd = NULL; + if( p_pool_key->pool_key ) + deref_al_obj( &p_pool_key->pool_key->obj ); +} + + + +/* + * Free a pool key. + */ +static void +__free_pool_key( + IN al_obj_t* p_obj ) +{ + al_pool_key_t* p_pool_key; + + CL_ASSERT( p_obj ); + p_pool_key = PARENT_STRUCT( p_obj, al_pool_key_t, obj ); + + destroy_al_obj( &p_pool_key->obj ); + cl_free( p_pool_key ); +} + + + +/* + * Register a MAD array with a protection domain. + */ +static ib_api_status_t +__reg_mad_array( + IN al_pool_key_t* const p_pool_key, + IN mad_array_t* const p_mad_array ) +{ + mad_reg_t* p_reg; + ib_mr_create_t mr_create; + ib_api_status_t status; + + CL_ASSERT( p_pool_key ); + CL_ASSERT( p_mad_array ); + + /* Determine if there is memory to register. */ + if( p_mad_array->sizeof_array == 0 ) + return IB_SUCCESS; + + p_reg = cl_zalloc( sizeof( mad_reg_t ) ); + if( p_reg == NULL ) + return IB_INSUFFICIENT_MEMORY; + + /* + * Initialize the registration object. We use synchronous + * destruction to deregister memory immediately. Otherwise, the + * memory will be automatically deregistered when destroying the + * PD, which can lead to trying to deregister the memory twice. + */ + construct_al_obj( &p_reg->obj, AL_OBJ_TYPE_MAD_POOL ); + status = init_al_obj( &p_reg->obj, p_reg, FALSE, + NULL, NULL, __free_mad_reg ); + if( status != IB_SUCCESS ) + { + __free_mad_reg( &p_reg->obj ); + return status; + } + + /* Attach the registration to the pool key. */ + attach_al_obj( &p_pool_key->obj, &p_reg->obj ); + + if( p_pool_key->h_pd->type != IB_PDT_ALIAS ) + { + /* Register the MAD array on the protection domain. */ + cl_memclr( &mr_create, sizeof( ib_mr_create_t ) ); + mr_create.vaddr = p_mad_array->p_data; + mr_create.length = p_mad_array->sizeof_array; + mr_create.access_ctrl = IB_AC_LOCAL_WRITE; + + status = ib_reg_mem( p_pool_key->h_pd, &mr_create, &p_reg->lkey, + &p_reg->rkey, &p_reg->h_mr ); + } + + if( status != IB_SUCCESS ) + { + p_reg->obj.pfn_destroy( &p_reg->obj, NULL ); + return status; + } + + /* Save p_mad_array to match the registration with the array. */ + p_reg->p_mad_array = p_mad_array; + + /* Release the reference taken in init_al_obj. */ + deref_al_obj( &p_reg->obj ); + + return IB_SUCCESS; +} + + + +/* + * Free a MAD registration. + */ +static void +__free_mad_reg( + IN al_obj_t* p_obj ) +{ + mad_reg_t* p_reg; + ib_api_status_t status; + + CL_ASSERT( p_obj ); + p_reg = PARENT_STRUCT( p_obj, mad_reg_t, obj ); + + /* Deregister the MAD array if it was registered. */ + if( p_reg->h_mr ) + { + status = ib_dereg_mr( p_reg->h_mr ); + CL_ASSERT( status == IB_SUCCESS ); + } + + destroy_al_obj( &p_reg->obj ); + cl_free( p_reg ); +} + + + +/* + * Deregister a MAD pool from a protection domain. Only normal pool_keys + * can be destroyed using this routine. + */ +ib_api_status_t +ib_dereg_mad_pool( + IN const ib_pool_key_t pool_key ) +{ + ib_api_status_t status; + + AL_ENTER(AL_DBG_MAD_POOL); + + if( AL_OBJ_INVALID_HANDLE( pool_key, AL_OBJ_TYPE_H_POOL_KEY ) ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + ref_al_obj( &pool_key->obj ); + status = dereg_mad_pool( pool_key, AL_KEY_NORMAL ); + + if( status != IB_SUCCESS ) + deref_al_obj( &pool_key->obj ); + + AL_EXIT(AL_DBG_MAD_POOL); + return status; +} + + + +/* + * Deregister a MAD pool from a protection domain. + */ +ib_api_status_t +dereg_mad_pool( + IN const ib_pool_key_t pool_key , + IN const al_key_type_t expected_type ) +{ + AL_ENTER(AL_DBG_MAD_POOL); + + if( pool_key->type != expected_type ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + ///* Check mad_cnt to see if MADs are still outstanding. */ + //if( pool_key->mad_cnt ) + //{ + // AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_MAD_POOL, ("IB_RESOURCE_BUSY\n") ); + // return IB_RESOURCE_BUSY; + //} + + pool_key->obj.pfn_destroy( &pool_key->obj, NULL ); + + AL_EXIT(AL_DBG_MAD_POOL); + return IB_SUCCESS; +} + + + +/* + * Obtain a MAD element from the pool. + */ +static ib_api_status_t +__get_mad_element( + IN const ib_pool_key_t pool_key, + OUT al_mad_element_t** pp_mad_element ) +{ + al_pool_key_t* p_pool_key; + ib_pool_handle_t h_pool; + cl_list_item_t* p_item; + mad_item_t* p_mad_item; + ib_api_status_t status; + + AL_ENTER(AL_DBG_MAD_POOL); + + CL_ASSERT( pool_key ); + CL_ASSERT( pp_mad_element ); + + p_pool_key = (al_pool_key_t*)pool_key; + h_pool = p_pool_key->h_pool; + + /* Obtain a MAD item from the stack. */ + cl_spinlock_acquire( &h_pool->obj.lock ); + p_item = cl_qlist_remove_head( &h_pool->mad_stack ); + p_mad_item = PARENT_STRUCT( p_item, mad_item_t, al_mad_element.list_item ); + if( p_item == cl_qlist_end( &h_pool->mad_stack ) ) + { + /* The stack was empty. Grow the pool and obtain a new item. */ + cl_spinlock_release( &h_pool->obj.lock ); + status = __grow_mad_pool( h_pool, &p_mad_item ); + if( status != IB_SUCCESS ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("grow_mad_pool failed with status %s.\n", + ib_get_err_str(status)) ); + return status; + } + } + else + { + cl_spinlock_release( &h_pool->obj.lock ); + } + + /* Get the local data segment information for this pool key. */ + status = __init_mad_element( p_pool_key, p_mad_item ); + if( status != IB_SUCCESS ) + { + cl_spinlock_acquire( &h_pool->obj.lock ); + cl_qlist_insert_head( &h_pool->mad_stack, + &p_mad_item->al_mad_element.list_item ); + cl_spinlock_release( &h_pool->obj.lock ); + + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("init_mad_element failed with status %s.\n", + ib_get_err_str(status)) ); + return status; + } + + /* Hold a reference on the array while a MAD element is removed. */ + ref_al_obj( &p_mad_item->p_mad_array->obj ); + + p_mad_item->al_mad_element.pool_key = (ib_pool_key_t)pool_key; + /* Return the MAD element. */ + *pp_mad_element = &p_mad_item->al_mad_element; + + AL_EXIT(AL_DBG_MAD_POOL); + return IB_SUCCESS; +} + + + +static void +__setup_mad_element( + IN OUT al_mad_element_t* const p_al_mad_element, + IN const uint32_t lkey ) +{ + /* Clear the MAD element. */ + cl_memclr( &p_al_mad_element->element, sizeof( ib_mad_element_t ) ); + + /* Initialize the receive data segment information. */ + p_al_mad_element->grh_ds.lkey = lkey; + + /* Initialize the send data segment information. */ + p_al_mad_element->mad_ds.lkey = lkey; + + /* Initialize grh */ + p_al_mad_element->element.p_grh = + (ib_grh_t*)(uintn_t)p_al_mad_element->grh_ds.vaddr; +} + + + +/* + * Initialize the MAD element local data segment for this pool key. + */ +static ib_api_status_t +__init_mad_element( + IN const al_pool_key_t* p_pool_key, + IN OUT mad_item_t* p_mad_item ) +{ + cl_list_item_t *p_item; + cl_qlist_t *p_list; + al_obj_t *p_obj; + mad_reg_t *p_reg; + ib_pool_handle_t h_pool; + + CL_ASSERT( p_pool_key ); + CL_ASSERT( p_mad_item != NULL ); + + /* Find the MAD array registration entry. */ + if( p_pool_key->type == AL_KEY_NORMAL ) + { + p_list = (cl_qlist_t*)&p_pool_key->obj.obj_list; + } + else + { +#if defined( CL_KERNEL ) + /* Search the registrations on the actual pool key, not the alias. */ + p_list = (cl_qlist_t*)&p_pool_key->pool_key->obj.obj_list; +#else + /* + * Note that MAD elements used by user-mode clients on special QPs + * are not registered on a user-mode PD. The user-mode MAD elements + * must be copied into a kernel-mode MAD element before being sent. + */ + __setup_mad_element( &p_mad_item->al_mad_element, 0 ); + return IB_SUCCESS; +#endif + } + + /* Prevent MAD array registrations. */ + h_pool = p_pool_key->h_pool; + cl_spinlock_acquire( &h_pool->obj.lock ); + + /* Search for the registration entry. */ + p_item = cl_qlist_find_from_head( p_list, __locate_reg_cb, + p_mad_item->p_mad_array ); + if( p_item == cl_qlist_end( p_list ) ) + { + cl_spinlock_release( &h_pool->obj.lock ); + return IB_NOT_FOUND; + } + + /* Allow MAD array registrations. */ + cl_spinlock_release( &h_pool->obj.lock ); + + /* Get a pointer to the registration. */ + p_obj = PARENT_STRUCT( p_item, al_obj_t, pool_item ); + p_reg = PARENT_STRUCT( p_obj, mad_reg_t, obj ); + __setup_mad_element( &p_mad_item->al_mad_element, p_reg->lkey ); + + return IB_SUCCESS; +} + + + +/* + * Determine if a registration is for a given array. + */ +static cl_status_t +__locate_reg_cb( + IN const cl_list_item_t* const p_list_item, + IN void* context ) +{ + al_obj_t* p_obj; + mad_reg_t* p_reg; + mad_array_t* p_mad_array; + + CL_ASSERT( p_list_item ); + CL_ASSERT( context ); + + p_obj = PARENT_STRUCT( p_list_item, al_obj_t, pool_item ); + p_reg = PARENT_STRUCT( p_obj, mad_reg_t, obj ); + p_mad_array = context; + + return ( p_reg->p_mad_array == p_mad_array ) ? CL_SUCCESS : CL_NOT_FOUND; +} + + + +/* + * Return a MAD element to the pool. + */ +static void +__put_mad_element( + IN al_mad_element_t* p_mad_element ) +{ + mad_item_t* p_mad_item; + ib_pool_handle_t h_pool; + + CL_ASSERT( p_mad_element ); + p_mad_item = PARENT_STRUCT( p_mad_element, mad_item_t, al_mad_element ); + + /* Get a handle to the pool. */ + h_pool = p_mad_item->p_mad_array->h_pool; + + /* Clear the MAD buffer. */ + cl_memclr( + (uint8_t*)(uintn_t)p_mad_element->grh_ds.vaddr, MAD_BLOCK_GRH_SIZE ); + p_mad_element->element.p_next = NULL; + + /* Return the MAD element to the pool. */ + cl_spinlock_acquire( &h_pool->obj.lock ); + cl_qlist_insert_head( &h_pool->mad_stack, + &p_mad_item->al_mad_element.list_item ); + cl_spinlock_release( &h_pool->obj.lock ); + + /* Dereference the array when a MAD element is returned. */ + deref_al_obj( &p_mad_item->p_mad_array->obj ); +} + + + +/* + * Grow a MAD pool. + */ +static ib_api_status_t +__grow_mad_pool( + IN const ib_pool_handle_t h_pool, + OUT mad_item_t** pp_mad_item OPTIONAL ) +{ + size_t i; + size_t alloc_size; + uint8_t* p_data; + mad_array_t* p_mad_array; + mad_item_t* p_mad_item; + mad_item_t* p_mad_items; + cl_list_item_t* p_key_item; + al_pool_key_t* p_pool_key; + ib_api_status_t status; + + AL_ENTER(AL_DBG_MAD_POOL); + + CL_ASSERT( h_pool ); + + /* Determine if the pool is allowed to grow. */ + if( h_pool->grow_size == 0 ) + return IB_INSUFFICIENT_RESOURCES; + + /* Lock the pool. */ + cl_spinlock_acquire( &h_pool->obj.lock ); + + /* Determine if the pool has a maximum. */ + if( h_pool->max != 0 ) + { + /* Determine if the pool maximum has been reached. */ + if( h_pool->actual >= h_pool->max ) + { + cl_spinlock_release( &h_pool->obj.lock ); + + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("h_pool's (0x%p) maximum has been reached.\n", h_pool) ); + return IB_INSUFFICIENT_RESOURCES; + } + + /* Determine if growing the pool will exceed the maximum. */ + if( (h_pool->actual + h_pool->grow_size) > h_pool->max ) + { + cl_spinlock_release( &h_pool->obj.lock ); + + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("h_pool's (0x%p) will exceed maximum on grow.\n", h_pool) ); + return IB_INSUFFICIENT_RESOURCES; + } + } + + /* Calculate the allocation size. */ + alloc_size = sizeof( mad_item_t ); + alloc_size += MAD_BLOCK_GRH_SIZE; + alloc_size *= h_pool->grow_size; + alloc_size += sizeof( mad_array_t ); + + /* Allocate a MAD data array and item structures. */ + p_data = cl_zalloc( alloc_size ); + if( p_data == NULL ) + { + cl_spinlock_release( &h_pool->obj.lock ); + return IB_INSUFFICIENT_MEMORY; + } + + /* Offset to the MAD array structure. */ + alloc_size -= sizeof( mad_array_t ); + p_mad_array = (mad_array_t*)(p_data + alloc_size); + + /* Offset to the array of MAD item structures. */ + alloc_size -= sizeof( mad_item_t ) * h_pool->grow_size; + p_mad_items = (mad_item_t*)(p_data + alloc_size); + + /* Initialize the MAD array structure. */ + p_mad_array->h_pool = h_pool; + p_mad_array->p_data = p_data; + p_mad_array->sizeof_array = alloc_size; + + /* Initialize the MAD array object. */ + construct_al_obj( &p_mad_array->obj, AL_OBJ_TYPE_MAD_POOL ); + status = init_al_obj( &p_mad_array->obj, p_mad_array, TRUE, + NULL, NULL, __free_mad_array ); + if( status != IB_SUCCESS ) + { + cl_spinlock_release( &h_pool->obj.lock ); + __free_mad_array( &p_mad_array->obj ); + + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("init_al_obj failed with status %s.\n", ib_get_err_str(status)) ); + return status; + } + + /* Register the MAD array on the existing pool protection domains. */ + for( p_key_item = cl_qlist_head( &h_pool->key_list ); + p_key_item != cl_qlist_end( &h_pool->key_list ); + p_key_item = cl_qlist_next( p_key_item ) ) + { + p_pool_key = PARENT_STRUCT( p_key_item, al_pool_key_t, pool_item ); + ref_al_obj( &p_pool_key->obj ); + status = __reg_mad_array( p_pool_key, p_mad_array ); + deref_al_obj( &p_pool_key->obj ); + if( status != IB_SUCCESS ) + break; + } + + if( status != IB_SUCCESS ) + { + cl_spinlock_release( &h_pool->obj.lock ); + p_mad_array->obj.pfn_destroy( &p_mad_array->obj, NULL ); + return status; + } + + /* The pool has been successfully grown. Update the actual size. */ + h_pool->actual += h_pool->grow_size; + + /* Intialize the MAD stack item structures. */ + p_mad_item = p_mad_items; + for( i = 0; i < h_pool->grow_size; i++ ) + { + p_mad_item->p_mad_array = p_mad_array; + + p_mad_item->al_mad_element.grh_ds.vaddr = (uintn_t)p_data; + p_mad_item->al_mad_element.grh_ds.length = MAD_BLOCK_GRH_SIZE; + + p_mad_item->al_mad_element.mad_ds.vaddr = + (uintn_t)(p_data + sizeof( ib_grh_t )); + p_mad_item->al_mad_element.mad_ds.length = MAD_BLOCK_SIZE; + p_data += MAD_BLOCK_GRH_SIZE; + p_mad_item++; + } + + /* Return a MAD item to the caller if one was requested. */ + if( pp_mad_item != NULL ) + { + *pp_mad_item = p_mad_items; + p_mad_items++; + i--; + } + + /* Append the remaining MAD items to the existing stack. */ + cl_qlist_insert_array_tail( &h_pool->mad_stack, + &p_mad_items->al_mad_element.list_item, i, sizeof( mad_item_t ) ); + + /* Unlock the pool. */ + cl_spinlock_release( &h_pool->obj.lock ); + + /* Attach the array object to the pool. */ + attach_al_obj( &h_pool->obj, &p_mad_array->obj ); + + /* Release the reference taken in init_al_obj. */ + deref_al_obj( &p_mad_array->obj ); + + AL_EXIT(AL_DBG_MAD_POOL); + return IB_SUCCESS; +} + + + +/* + * Free the MAD array structure. + */ +static void +__free_mad_array( + IN al_obj_t* p_obj ) +{ + mad_array_t* p_mad_array; + ib_pool_handle_t h_pool; + cl_list_item_t* p_key_item; + al_pool_key_t* p_pool_key; + cl_list_item_t* p_reg_item; + cl_list_item_t* p_next_item; + mad_reg_t* p_reg; + + AL_ENTER(AL_DBG_MAD_POOL); + + CL_ASSERT( p_obj ); + p_mad_array = PARENT_STRUCT( p_obj, mad_array_t, obj ); + + /* Destroy any registrations for this MAD array. */ + h_pool = p_mad_array->h_pool; + cl_spinlock_acquire( &h_pool->obj.lock ); + + /* Walk the pool key list. */ + p_key_item = cl_qlist_head( &h_pool->key_list ); + while( p_key_item != cl_qlist_end( &h_pool->key_list ) ) + { + p_pool_key = PARENT_STRUCT( p_key_item, al_pool_key_t, pool_item ); + + /* Walk the pool key registrations. */ + for( p_reg_item = cl_qlist_head( &p_pool_key->obj.obj_list ); + p_reg_item != cl_qlist_end( &p_pool_key->obj.obj_list ); + p_reg_item = p_next_item ) + { + p_next_item = cl_qlist_next( p_reg_item ); + + p_obj = PARENT_STRUCT( p_reg_item, al_obj_t, pool_item ); + p_reg = PARENT_STRUCT( p_obj, mad_reg_t, obj ); + + /* Destroy registrations for this MAD array. */ + if( p_reg->p_mad_array == p_mad_array ) + { + ref_al_obj( &p_reg->obj ); + p_reg->obj.pfn_destroy( &p_reg->obj, NULL ); + } + } + + p_key_item = cl_qlist_next( p_key_item ); + } + cl_spinlock_release( &h_pool->obj.lock ); + + destroy_al_obj( &p_mad_array->obj ); + cl_free( p_mad_array->p_data ); + + AL_EXIT(AL_DBG_MAD_POOL); +} + + + +/* + * Initialize a MAD send tracking structure to reference the pool from + * whence it came. + */ +static cl_status_t +__mad_send_init( + IN void* const p_object, + IN void* context, + OUT cl_pool_item_t** const pp_pool_item ) +{ + mad_send_t *p_mad_send; + + p_mad_send = (mad_send_t*)p_object; + p_mad_send->h_pool = context; + *pp_pool_item = &p_mad_send->mad_send.pool_item; + return CL_SUCCESS; +} + + + +ib_mad_send_handle_t +get_mad_send( + IN const al_mad_element_t *p_mad_element ) +{ + mad_item_t* p_mad_item; + ib_pool_handle_t h_pool; + cl_pool_item_t *p_pool_item; + ib_mad_send_handle_t h_send; + + CL_ASSERT( p_mad_element ); + + /* Get a handle to the pool. */ + p_mad_item = PARENT_STRUCT( p_mad_element, mad_item_t, al_mad_element ); + h_pool = p_mad_item->p_mad_array->h_pool; + + cl_spinlock_acquire( &h_pool->obj.lock ); + p_pool_item = cl_qpool_get( &h_pool->mad_send_pool ); + cl_spinlock_release( &h_pool->obj.lock ); + + if( !p_pool_item ) + return NULL; + + ref_al_obj( &h_pool->obj ); + h_send = PARENT_STRUCT( p_pool_item, al_mad_send_t, pool_item ); + h_send->canceled = FALSE; + h_send->p_send_mad = NULL; + h_send->p_resp_mad = NULL; + h_send->h_av = NULL; + h_send->retry_cnt = 0; + h_send->retry_time = 0; + + return h_send; +} + + + +void +put_mad_send( + IN ib_mad_send_handle_t h_mad_send ) +{ + mad_send_t *p_mad_send; + + p_mad_send = PARENT_STRUCT( h_mad_send, mad_send_t, mad_send ); + + cl_spinlock_acquire( &p_mad_send->h_pool->obj.lock ); + cl_qpool_put( &p_mad_send->h_pool->mad_send_pool, &h_mad_send->pool_item ); + cl_spinlock_release( &p_mad_send->h_pool->obj.lock ); + deref_al_obj( &p_mad_send->h_pool->obj ); +} + + + +/* + * Initialize a MAD RMPP tracking structure to reference the pool from + * whence it came. + */ +static cl_status_t +__mad_rmpp_init( + IN void* const p_object, + IN void* context, + OUT cl_pool_item_t** const pp_pool_item ) +{ + mad_rmpp_t *p_mad_rmpp; + + p_mad_rmpp = (mad_rmpp_t*)p_object; + p_mad_rmpp->h_pool = context; + *pp_pool_item = &p_mad_rmpp->mad_rmpp.pool_item; + return CL_SUCCESS; +} + + + +al_mad_rmpp_t* +get_mad_rmpp( + IN const al_mad_element_t *p_mad_element ) +{ + mad_item_t* p_mad_item; + ib_pool_handle_t h_pool; + cl_pool_item_t *p_pool_item; + + CL_ASSERT( p_mad_element ); + + /* Get a handle to the pool. */ + p_mad_item = PARENT_STRUCT( p_mad_element, mad_item_t, al_mad_element ); + h_pool = p_mad_item->p_mad_array->h_pool; + + cl_spinlock_acquire( &h_pool->obj.lock ); + p_pool_item = cl_qpool_get( &h_pool->mad_rmpp_pool ); + cl_spinlock_release( &h_pool->obj.lock ); + + if( !p_pool_item ) + return NULL; + + ref_al_obj( &h_pool->obj ); + return PARENT_STRUCT( p_pool_item, al_mad_rmpp_t, pool_item ); +} + + + +void +put_mad_rmpp( + IN al_mad_rmpp_t* h_mad_rmpp ) +{ + mad_rmpp_t *p_mad_rmpp; + + p_mad_rmpp = PARENT_STRUCT( h_mad_rmpp, mad_rmpp_t, mad_rmpp ); + + cl_spinlock_acquire( &p_mad_rmpp->h_pool->obj.lock ); + cl_qpool_put( &p_mad_rmpp->h_pool->mad_rmpp_pool, &h_mad_rmpp->pool_item ); + cl_spinlock_release( &p_mad_rmpp->h_pool->obj.lock ); + deref_al_obj( &p_mad_rmpp->h_pool->obj ); +} + + + +ib_api_status_t +ib_get_mad( + IN const ib_pool_key_t pool_key, + IN const size_t buf_size, + OUT ib_mad_element_t **pp_mad_element ) +{ + al_pool_key_t* p_pool_key; + al_mad_element_t* p_mad; + ib_api_status_t status; + + AL_ENTER(AL_DBG_MAD_POOL); + + if( AL_OBJ_INVALID_HANDLE( pool_key, AL_OBJ_TYPE_H_POOL_KEY ) ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + if( !buf_size || !pp_mad_element ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + p_pool_key = (al_pool_key_t*)pool_key; + + status = __get_mad_element( pool_key, &p_mad ); + if( status != IB_SUCCESS ) + { + AL_EXIT(AL_DBG_MAD_POOL); + return status; + } + + /* Set the user accessible buffer. */ + if( buf_size <= MAD_BLOCK_SIZE ) + { + /* Use the send buffer for 256 byte MADs. */ + p_mad->element.p_mad_buf = (ib_mad_t*)(uintn_t)p_mad->mad_ds.vaddr; + } + else if( buf_size >= 0xFFFFFFFF ) + { + __put_mad_element( p_mad ); + return IB_INVALID_SETTING; + } + else + { + /* Allocate a new buffer for the MAD. */ + p_mad->p_al_mad_buf = cl_zalloc( buf_size ); + if( !p_mad->p_al_mad_buf ) + { + __put_mad_element( p_mad ); + AL_EXIT(AL_DBG_MAD_POOL); + return IB_INSUFFICIENT_MEMORY; + } + p_mad->element.p_mad_buf = p_mad->p_al_mad_buf; + } + p_mad->element.size = (uint32_t)buf_size; + + /* Track the MAD element with the requesting AL instance. */ + al_insert_mad( p_pool_key->h_al, p_mad ); + + ref_al_obj( &p_pool_key->obj ); + cl_atomic_inc( &p_pool_key->mad_cnt ); + + /* Return the MAD element to the client. */ + *pp_mad_element = &p_mad->element; + + AL_EXIT(AL_DBG_MAD_POOL); + return IB_SUCCESS; +} + + + +ib_api_status_t +ib_put_mad( + IN const ib_mad_element_t* p_mad_element_list ) +{ + al_mad_element_t* p_mad; + + if( !p_mad_element_list ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + while( p_mad_element_list ) + { + p_mad = PARENT_STRUCT( p_mad_element_list, al_mad_element_t, element ); + p_mad_element_list = p_mad_element_list->p_next; + + /* Deallocate any buffers allocated for the user. */ + if( p_mad->p_al_mad_buf ) + { + cl_free( p_mad->p_al_mad_buf ); + p_mad->p_al_mad_buf = NULL; + } + + /* See if the MAD has already been returned to the MAD pool. */ + if( p_mad->h_al ) + { + /* Remove the MAD element from the owning AL instance. */ + al_remove_mad( p_mad ); + + /* Return the MAD element to the pool. */ + cl_atomic_dec( &p_mad->pool_key->mad_cnt ); + deref_al_obj( &p_mad->pool_key->obj ); + __put_mad_element( p_mad ); + } + else + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("MAD has already been returned to MAD pool.\n") ); + } + } + + return IB_SUCCESS; +} + + + +/* + * Resize the data buffer associated with a MAD element. + */ +ib_api_status_t +al_resize_mad( + OUT ib_mad_element_t *p_mad_element, + IN const size_t buf_size ) +{ + al_mad_element_t *p_al_element; + ib_mad_t *p_new_buf; + + CL_ASSERT( p_mad_element ); + + /* We only support growing the buffer for now. */ + CL_ASSERT( buf_size > p_mad_element->size ); + + /* Cap the size. */ + if( buf_size >= 0xFFFFFFFF ) + return IB_INVALID_SETTING; + + p_al_element = PARENT_STRUCT( p_mad_element, al_mad_element_t, element ); + + /* Allocate a new buffer. */ + p_new_buf = cl_malloc( buf_size ); + if( !p_new_buf ) + return IB_INSUFFICIENT_MEMORY; + + /* Copy the existing buffer's data into the new buffer. */ + cl_memcpy( p_new_buf, p_mad_element->p_mad_buf, p_mad_element->size ); + cl_memclr( (uint8_t*)p_new_buf + p_mad_element->size, + buf_size - p_mad_element->size ); + + /* Update the MAD element to use the new buffer. */ + p_mad_element->p_mad_buf = p_new_buf; + p_mad_element->size = (uint32_t)buf_size; + + /* Free any old buffer. */ + if( p_al_element->p_al_mad_buf ) + cl_free( p_al_element->p_al_mad_buf ); + p_al_element->p_al_mad_buf = p_new_buf; + + return IB_SUCCESS; +} + diff --git a/branches/WOF2-3/core/al/user/ibal.rc b/branches/WOF2-3/core/al/user/ibal.rc new file mode 100644 index 00000000..e2d86f5f --- /dev/null +++ b/branches/WOF2-3/core/al/user/ibal.rc @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef _DEBUG_ +#define VER_FILEDESCRIPTION_STR "InfiniBand Access Layer (Debug)" +#define VER_INTERNALNAME_STR "ibald.dll" +#define VER_ORIGINALFILENAME_STR "ibald.dll" +#else +#define VER_FILEDESCRIPTION_STR "InfiniBand Access Layer" +#define VER_INTERNALNAME_STR "ibal.dll" +#define VER_ORIGINALFILENAME_STR "ibal.dll" +#endif + +#include diff --git a/branches/WOF2-3/core/al/user/makefile b/branches/WOF2-3/core/al/user/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-3/core/al/user/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\inc\openib.def diff --git a/branches/WOF2-3/core/al/user/ual_av.c b/branches/WOF2-3/core/al/user/ual_av.c new file mode 100644 index 00000000..83ffcec9 --- /dev/null +++ b/branches/WOF2-3/core/al/user/ual_av.c @@ -0,0 +1,404 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include "ual_support.h" +#include "al_pd.h" +#include "al_av.h" + +#include "al_debug.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "ual_av.tmh" +#endif + + +static void +ual_get_gid_index( + IN struct _al_ci_ca *p_ci_ca, + IN uint8_t port_num, + IN ib_gid_t *p_gid, + OUT uint8_t *p_index) +{ + ib_port_attr_t *p_port_attr; + uint8_t i; + + ci_ca_lock_attr( p_ci_ca ); + p_port_attr = &p_ci_ca->p_pnp_attr->p_port_attr[port_num-1]; + *p_index = 0; + for( i = 0; i < p_port_attr->num_gids; i++ ) + { + if( !cl_memcmp(p_gid, &p_port_attr->p_gid_table[i], sizeof(ib_gid_t)) ) + { + *p_index = i; + break; + } + } + ci_ca_unlock_attr( p_ci_ca ); +} + +ib_api_status_t +ual_create_av( + IN const ib_pd_handle_t h_pd, + IN const ib_av_attr_t* const p_av_attr, + IN OUT ib_av_handle_t h_av ) +{ + ual_create_av_ioctl_t ioctl_buf; + uintn_t bytes_ret; + cl_status_t cl_status = CL_ERROR; + ib_api_status_t status = IB_ERROR; + uvp_interface_t uvp_intf = h_pd->obj.p_ci_ca->verbs.user_verbs; + ib_av_attr_t av_attr; + + AL_ENTER( AL_DBG_AV ); + /* Clear the ioctl_buf */ + cl_memclr( &ioctl_buf, sizeof(ioctl_buf) ); + av_attr = *p_av_attr; + + /* Pre call to the UVP library */ + if( h_pd->h_ci_pd && uvp_intf.pre_create_av ) + { + if( p_av_attr->grh_valid ) + { + ual_get_gid_index(h_pd->obj.p_ci_ca, av_attr.port_num, + &av_attr.grh.src_gid, &av_attr.grh.resv2); + } + + status = uvp_intf.pre_create_av( h_pd->h_ci_pd, + &av_attr, &ioctl_buf.in.umv_buf, &h_av->h_ci_av ); + if( status != IB_SUCCESS ) + { + AL_EXIT( AL_DBG_AV ); + return (status == IB_VERBS_PROCESSING_DONE) ? IB_SUCCESS : status; + } + } + + ioctl_buf.in.h_pd = h_pd->obj.hdl; + ioctl_buf.in.attr = *p_av_attr; + + cl_status = do_al_dev_ioctl( UAL_CREATE_AV, + &ioctl_buf.in, sizeof(ioctl_buf.in), + &ioctl_buf.out, sizeof(ioctl_buf.out), &bytes_ret ); + + if( cl_status != CL_SUCCESS || bytes_ret != sizeof(ioctl_buf.out) ) + status = IB_ERROR; + else + { + status = ioctl_buf.out.status; + if(status == IB_SUCCESS) + h_av->obj.hdl = ioctl_buf.out.h_av; + } + + /* Post uvp call */ + if( h_pd->h_ci_pd && uvp_intf.post_create_av ) + { + uvp_intf.post_create_av( h_pd->h_ci_pd, + status, &h_av->h_ci_av, &ioctl_buf.out.umv_buf); + } + + AL_EXIT( AL_DBG_AV ); + return status; +} + + +/* + * This call does not go to the uvp library. The handle should be + * always created in the kernel if it is an alias pd. + */ +ib_api_status_t +ual_pd_alias_create_av( + IN const ib_pd_handle_t h_pd, + IN const ib_av_attr_t* const p_av_attr, + IN OUT ib_av_handle_t h_av ) +{ + ual_create_av_ioctl_t ioctl_buf; + uintn_t bytes_ret; + cl_status_t cl_status = CL_ERROR; + ib_api_status_t status = IB_ERROR; + + AL_ENTER( AL_DBG_AV ); + /* Clear the ioctl_buf */ + cl_memclr( &ioctl_buf, sizeof(ioctl_buf) ); + + ioctl_buf.in.h_pd = h_pd->obj.hdl; + ioctl_buf.in.attr = *p_av_attr; + + cl_status = do_al_dev_ioctl( UAL_CREATE_AV, + &ioctl_buf.in, sizeof(ioctl_buf.in), + &ioctl_buf.out, sizeof(ioctl_buf.out), + &bytes_ret ); + + if( cl_status != CL_SUCCESS || bytes_ret != sizeof(ioctl_buf.out) ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("UAL_CREATE_AV IOCTL returned %s\n", CL_STATUS_MSG(cl_status)) ); + status = IB_ERROR; + }else + { + status = ioctl_buf.out.status; + if(status == IB_SUCCESS) + h_av->obj.hdl = ioctl_buf.out.h_av; + } + + + AL_EXIT( AL_DBG_AV ); + return status; +} + + +/* + * The functions below can be used by both the alias_pd as well as real pd. + * For alias_pd, there won't be a uvp_av_handle, as the create call doesn't + * go to uvp. Since there is no uvp_av_handle, the query, modify and + * destroy calls also will not call uvp library. So the rest of the + * functions can be shared by both the real pd, and alias pd. + */ +ib_api_status_t +ual_destroy_av( + IN ib_av_handle_t h_av ) +{ + ual_destroy_av_ioctl_t ioctl_buf; + uintn_t bytes_ret; + cl_status_t cl_status = CL_ERROR; + ib_api_status_t status = IB_ERROR; + uvp_interface_t uvp_intf = h_av->obj.p_ci_ca->verbs.user_verbs; + + AL_ENTER( AL_DBG_AV ); + /* Clear the ioctl_buf */ + cl_memclr( &ioctl_buf, sizeof(ioctl_buf) ); + + if( h_av->h_ci_av && uvp_intf.pre_destroy_av ) + { + /* Pre call to the UVP library */ + status = uvp_intf.pre_destroy_av( h_av->h_ci_av ); + CL_ASSERT( (status == IB_SUCCESS) || + (status == IB_VERBS_PROCESSING_DONE) ); + if( status != IB_SUCCESS ) + { + AL_EXIT( AL_DBG_AV ); + return (status == IB_VERBS_PROCESSING_DONE) ? IB_SUCCESS : status; + } + } + + ioctl_buf.in.h_av = h_av->obj.hdl; + + cl_status = do_al_dev_ioctl( UAL_DESTROY_AV, + &ioctl_buf.in, sizeof(ioctl_buf.in), + &ioctl_buf.out, sizeof(ioctl_buf.out), + &bytes_ret ); + + if( cl_status != CL_SUCCESS || bytes_ret != sizeof(ioctl_buf.out) ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("UAL_DESTROY_AV IOCTL returned %s\n", CL_STATUS_MSG(cl_status)) ); + status = IB_ERROR; + } + else if( ioctl_buf.out.status != IB_SUCCESS ) + { + CL_ASSERT( status == IB_SUCCESS ); + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("UAL_DESTROY_AV IOCTL status %s\n", + ib_get_err_str(ioctl_buf.out.status)) ); + status = ioctl_buf.out.status; + } + else + { + status = ioctl_buf.out.status; + } + + /* Call vendor's post call */ + if( h_av->h_ci_av && uvp_intf.post_destroy_av ) + uvp_intf.post_destroy_av( h_av->h_ci_av, status ); + + AL_EXIT( AL_DBG_AV ); + return status; +} + + + +ib_api_status_t +ual_modify_av( + IN ib_av_handle_t h_av, + IN const ib_av_attr_t* const p_av_attr) +{ + ual_modify_av_ioctl_t ioctl_buf; + uintn_t bytes_ret; + cl_status_t cl_status = CL_ERROR; + ib_api_status_t status = IB_ERROR; + ib_av_t* p_av = (ib_av_t*) h_av; + uvp_interface_t uvp_intf = p_av->obj.p_ci_ca->verbs.user_verbs; + ib_av_attr_t av_attr; + + AL_ENTER( AL_DBG_AV ); + /* Clear the ioctl_buf */ + cl_memclr( &ioctl_buf, sizeof(ioctl_buf) ); + av_attr = *p_av_attr; + + /* Call the uvp pre call if the vendor library provided a valid ca handle */ + if( p_av->h_ci_av && uvp_intf.pre_modify_av ) + { + if( p_av_attr->grh_valid ) + { + ual_get_gid_index(p_av->obj.p_ci_ca, av_attr.port_num, + &av_attr.grh.src_gid, &av_attr.grh.resv2); + } + + /* Pre call to the UVP library */ + status = uvp_intf.pre_modify_av( p_av->h_ci_av, + &av_attr, &ioctl_buf.in.umv_buf ); + if( status == IB_VERBS_PROCESSING_DONE ) + { + /* Modification is done in user mode. Issue the post call */ + if( uvp_intf.post_modify_av ) + { + uvp_intf.post_modify_av( + p_av->h_ci_av, IB_SUCCESS, &ioctl_buf.in.umv_buf ); + } + + AL_EXIT( AL_DBG_AV ); + return IB_SUCCESS; + } + else if( status != IB_SUCCESS ) + { + AL_EXIT( AL_DBG_AV ); + return status; + } + } + + ioctl_buf.in.h_av = p_av->obj.hdl; + ioctl_buf.in.attr = *p_av_attr; + + cl_status = do_al_dev_ioctl( UAL_MODIFY_AV, + &ioctl_buf.in, sizeof(ioctl_buf.in), + &ioctl_buf.out, sizeof(ioctl_buf.out), + &bytes_ret ); + + if( cl_status != CL_SUCCESS || bytes_ret != sizeof(ioctl_buf.out) ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("UAL_MODIFY_AV IOCTL returned %s\n", CL_STATUS_MSG(cl_status)) ); + status = IB_ERROR; + } + else + { + status = ioctl_buf.out.status; + } + + /* Post uvp call */ + if( h_av->h_ci_av && uvp_intf.post_modify_av ) + { + uvp_intf.post_modify_av( + p_av->h_ci_av, status, &ioctl_buf.out.umv_buf ); + } + + AL_EXIT( AL_DBG_AV ); + return status; +} + + +ib_api_status_t +ual_query_av( + IN ib_av_handle_t h_av, + OUT ib_av_attr_t* const p_av_attr, + OUT ib_pd_handle_t* const ph_pd ) +{ + ual_query_av_ioctl_t ioctl_buf; + uintn_t bytes_ret; + cl_status_t cl_status = CL_ERROR; + ib_api_status_t status = IB_ERROR; + uvp_interface_t uvp_intf = h_av->obj.p_ci_ca->verbs.user_verbs; + + AL_ENTER( AL_DBG_AV ); + /* Clear the ioctl_buf */ + cl_memclr( &ioctl_buf, sizeof(ioctl_buf) ); + + /* Call the uvp pre call if the vendor library provided a valid ca handle */ + if( h_av->h_ci_av && uvp_intf.pre_query_av ) + { + /* Pre call to the UVP library */ + status = uvp_intf.pre_query_av( + h_av->h_ci_av, &ioctl_buf.in.umv_buf ); + if( status == IB_VERBS_PROCESSING_DONE ) + { + /* Query is done in user mode. Issue the post call */ + if( uvp_intf.post_query_av ) + { + uvp_intf.post_query_av( h_av->h_ci_av, + IB_SUCCESS, p_av_attr, ph_pd, &ioctl_buf.in.umv_buf ); + } + AL_EXIT( AL_DBG_AV ); + return IB_SUCCESS; + } + else if( status != IB_SUCCESS ) + { + AL_EXIT( AL_DBG_AV ); + return status; + } + } + + ioctl_buf.in.h_av = h_av->obj.hdl; + + cl_status = do_al_dev_ioctl( UAL_QUERY_AV, + &ioctl_buf.in, sizeof(ioctl_buf.in), + &ioctl_buf.out, sizeof(ioctl_buf.out), + &bytes_ret ); + + if( cl_status != CL_SUCCESS || bytes_ret != sizeof(ioctl_buf.out) ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("UAL_QUERY_AV IOCTL returned %s\n", CL_STATUS_MSG(cl_status)) ); + status = IB_ERROR; + } + else + { + status = ioctl_buf.out.status; + } + + /* Post uvp call */ + if( h_av->h_ci_av && uvp_intf.post_query_av ) + { + uvp_intf.post_query_av( h_av->h_ci_av, + status, &ioctl_buf.out.attr, ph_pd, + &ioctl_buf.out.umv_buf ); + } + + if( status == IB_SUCCESS ) + *p_av_attr = ioctl_buf.out.attr; + + AL_EXIT( AL_DBG_AV ); + return status; +} + diff --git a/branches/WOF2-3/core/al/user/ual_ca.c b/branches/WOF2-3/core/al/user/ual_ca.c new file mode 100644 index 00000000..3e595c28 --- /dev/null +++ b/branches/WOF2-3/core/al/user/ual_ca.c @@ -0,0 +1,535 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include "ual_support.h" +#include "al.h" +#include "al_ca.h" +#include "al_debug.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "ual_ca.tmh" +#endif + +#include "ual_ca.h" +#include "ual_ci_ca.h" + + +void +close_vendor_lib( + IN verbs_interface_t *p_vca_intf ) +{ + if( p_vca_intf->h_uvp_lib ) + al_unload_uvp( p_vca_intf->h_uvp_lib ); +} + + + +ib_api_status_t +open_vendor_lib( + IN const ib_net64_t ca_guid, + IN OUT verbs_interface_t *p_vca_intf ) +{ + ual_get_uvp_name_ioctl_t al_ioctl; + uintn_t bytes_ret; + cl_status_t cl_status; + void *h_lib; + uvp_get_interface_t pfn_uvp_ifc; + + AL_ENTER( AL_DBG_CA ); + + /* Initialize assuming no user-mode support */ + cl_memclr( &al_ioctl, sizeof(al_ioctl) ); + cl_memclr( p_vca_intf, sizeof(verbs_interface_t) ); + + /* init with the guid */ + p_vca_intf->guid = ca_guid; + + al_ioctl.in.ca_guid = ca_guid; + + cl_status = do_al_dev_ioctl( UAL_GET_VENDOR_LIBCFG, + &al_ioctl.in, sizeof(al_ioctl.in), + &al_ioctl.out, sizeof(al_ioctl.out), + &bytes_ret ); + + if( cl_status != CL_SUCCESS || bytes_ret != sizeof(al_ioctl.out) ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("IOCTL returned %s\n", CL_STATUS_MSG(cl_status)) ); + return IB_ERROR; + } + + if( !strlen( al_ioctl.out.uvp_lib_name ) ) + { + /* Vendor does not implement user-mode library */ + AL_PRINT_EXIT(TRACE_LEVEL_WARNING ,AL_DBG_CA , + ("No vendor lib for CA guid %I64x.\n", ca_guid) ); + return IB_UNSUPPORTED; + } + + /* + * The vendor supports a user-mode library + * open the library and get the interfaces supported + */ + AL_PRINT(TRACE_LEVEL_INFORMATION ,AL_DBG_CA , + ("Loading vendor lib (%s)\n", al_ioctl.out.uvp_lib_name) ); + h_lib = al_load_uvp( al_ioctl.out.uvp_lib_name ); + if (h_lib == NULL) + { +#if defined( _DEBUG_ ) + al_uvp_lib_err( TRACE_LEVEL_WARNING, + "!vendor lib (%s) not found for CA guid %"PRIx64".", + al_ioctl.out.uvp_lib_name, ca_guid ); +#endif + AL_EXIT( AL_DBG_CA ); + return IB_SUCCESS; + } + + pfn_uvp_ifc = (uvp_get_interface_t) + GetProcAddress( h_lib, "uvp_get_interface" ); + if( !pfn_uvp_ifc ) + { +#if defined( _DEBUG_ ) + al_uvp_lib_err( TRACE_LEVEL_ERROR, + "failed to get vendor lib interface (%s) " + "for CA guid %"PRIx64" returned ", + al_ioctl.out.uvp_lib_name, ca_guid ); +#endif + al_unload_uvp( h_lib ); + AL_EXIT( AL_DBG_CA ); + return IB_SUCCESS; + } + + /* Query the vendor-supported user-mode functions */ + pfn_uvp_ifc( IID_UVP, &p_vca_intf->user_verbs ); + p_vca_intf->h_uvp_lib = h_lib; + AL_EXIT( AL_DBG_CA ); + return IB_SUCCESS; +} + + + +ib_api_status_t +ual_open_ca( + IN const ib_net64_t ca_guid, + IN OUT al_ci_ca_t* const p_ci_ca ) +{ + ual_open_ca_ioctl_t ca_ioctl; + uintn_t bytes_ret; + cl_status_t cl_status = CL_ERROR; + ib_api_status_t status = IB_ERROR; + ib_api_status_t uvp_status = IB_SUCCESS; + uvp_interface_t uvp_intf = p_ci_ca->verbs.user_verbs; + + AL_ENTER( AL_DBG_CA ); + + cl_memclr( &ca_ioctl, sizeof(ca_ioctl) ); + + /* Pre call to the UVP library */ + if( uvp_intf.pre_open_ca ) + { + status = uvp_intf.pre_open_ca( ca_guid, &ca_ioctl.in.umv_buf, &p_ci_ca->h_ci_ca ); + if( status != IB_SUCCESS ) + { + CL_ASSERT( status != IB_VERBS_PROCESSING_DONE ); + AL_EXIT(AL_DBG_CA); + return status; + } + } + + ca_ioctl.in.guid = ca_guid; + ca_ioctl.in.context = (ULONG_PTR)p_ci_ca; + + cl_status = do_al_dev_ioctl( UAL_OPEN_CA, + &ca_ioctl.in, sizeof(ca_ioctl.in), &ca_ioctl.out, sizeof(ca_ioctl.out), + &bytes_ret ); + + if( cl_status != CL_SUCCESS || bytes_ret != sizeof(ca_ioctl.out) ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , ("UAL_OPEN_CA IOCTL returned %s\n", + CL_STATUS_MSG(cl_status)) ); + status = IB_ERROR; + } + else + { + status = ca_ioctl.out.status; + p_ci_ca->obj.hdl = ca_ioctl.out.h_ca; + } + + /* Post uvp call */ + if( uvp_intf.post_open_ca ) + { + uvp_status = uvp_intf.post_open_ca( ca_guid, status, + &p_ci_ca->h_ci_ca, &ca_ioctl.out.umv_buf ); + } + + if( (status == IB_SUCCESS) && (uvp_status != IB_SUCCESS) ) + status = uvp_status; + + AL_EXIT( AL_DBG_CA ); + return status; +} + + +ib_api_status_t +ual_close_ca( + IN al_ci_ca_t *p_ci_ca ) +{ + ual_close_ca_ioctl_t ca_ioctl; + uintn_t bytes_ret; + cl_status_t cl_status = CL_ERROR; + ib_api_status_t status = IB_ERROR; + uvp_interface_t uvp_intf = p_ci_ca->verbs.user_verbs; + + AL_ENTER( AL_DBG_CA ); + + cl_memclr( &ca_ioctl, sizeof(ca_ioctl) ); + + /* Call the uvp pre call if the vendor library provided a valid ca handle */ + if( p_ci_ca->h_ci_ca && uvp_intf.pre_close_ca ) + { + /* Pre call to the UVP library */ + status = uvp_intf.pre_close_ca( p_ci_ca->h_ci_ca ); + if( status != IB_SUCCESS ) + { + AL_EXIT( AL_DBG_CA ); + return status; + } + } + + ca_ioctl.in.h_ca = p_ci_ca->obj.hdl; + + cl_status = do_al_dev_ioctl( UAL_CLOSE_CA, + &ca_ioctl.in, sizeof(ca_ioctl.in), &ca_ioctl.out, sizeof(ca_ioctl.out), + &bytes_ret ); + + if( cl_status != CL_SUCCESS || bytes_ret != sizeof(ca_ioctl.out) ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("UAL_CLOSE_CA IOCTL returned %s\n", CL_STATUS_MSG(cl_status)) ); + status = IB_ERROR; + } + else + { + status = ca_ioctl.out.status; + } + + if( p_ci_ca->h_ci_ca && uvp_intf.post_close_ca ) + uvp_intf.post_close_ca( p_ci_ca->h_ci_ca, status ); + + AL_EXIT( AL_DBG_CA ); + return status; +} + + + +ib_api_status_t +ual_query_ca( + IN const ib_ca_handle_t h_ca, + OUT ib_ca_attr_t* const p_ca_attr OPTIONAL, + IN OUT uint32_t* const p_size ) +{ + /* Do we need to do any special checking here ?? */ + + ual_query_ca_ioctl_t ca_ioctl; + uintn_t bytes_ret; + cl_status_t cl_status = CL_SUCCESS; + ib_api_status_t status = IB_SUCCESS; + uvp_interface_t uvp_intf = h_ca->obj.p_ci_ca->verbs.user_verbs; + + AL_ENTER( AL_DBG_CA ); + + cl_memclr( &ca_ioctl, sizeof(ca_ioctl) ); + + ca_ioctl.in.h_ca = h_ca->obj.p_ci_ca->obj.hdl; + ca_ioctl.in.p_ca_attr = (ULONG_PTR)p_ca_attr; + ca_ioctl.in.byte_cnt = *p_size; + + /* Call the uvp pre call if the vendor library provided a valid ca handle */ + if( h_ca->obj.p_ci_ca->h_ci_ca && uvp_intf.pre_query_ca ) + { + /* Pre call to the UVP library */ + status = uvp_intf.pre_query_ca( h_ca->obj.p_ci_ca->h_ci_ca, + p_ca_attr, *p_size, &ca_ioctl.in.umv_buf ); + + if( status != IB_SUCCESS ) + { + AL_EXIT( AL_DBG_CA ); + return status; + } + } + + cl_status = do_al_dev_ioctl( UAL_QUERY_CA, + &ca_ioctl.in, sizeof(ca_ioctl.in), &ca_ioctl.out, sizeof(ca_ioctl.out), + &bytes_ret ); + + if( cl_status != CL_SUCCESS || bytes_ret != sizeof(ca_ioctl.out) ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("UAL_QUERY_CA IOCTL returned %s\n", CL_STATUS_MSG(cl_status)) ); + status = IB_ERROR; + } + else + { + *p_size = ca_ioctl.out.byte_cnt; + status = ca_ioctl.out.status; + } + + /* The attributes, if any, will be directly copied by proxy */ + /* Post uvp call */ + if( h_ca->obj.p_ci_ca->h_ci_ca && uvp_intf.post_query_ca ) + { + uvp_intf.post_query_ca( h_ca->obj.p_ci_ca->h_ci_ca, + status, p_ca_attr, ca_ioctl.out.byte_cnt, &ca_ioctl.out.umv_buf ); + } + + AL_EXIT( AL_DBG_CA ); + return status; +} + + + +ib_api_status_t +ual_modify_ca( + IN const ib_ca_handle_t h_ca, + IN const uint8_t port_num, + IN const ib_ca_mod_t ca_mod, + IN const ib_port_attr_mod_t* const p_port_attr_mod ) +{ + /* Do we need to do any special checking here ?? */ + + ual_modify_ca_ioctl_t ca_ioctl; + uintn_t bytes_ret; + cl_status_t cl_status = CL_SUCCESS; + ib_api_status_t status = IB_SUCCESS; + uvp_interface_t uvp_intf = h_ca->obj.p_ci_ca->verbs.user_verbs; + + AL_ENTER( AL_DBG_CA ); + + /* Call the uvp pre call if the vendor library provided a valid ca handle */ + if( h_ca->obj.p_ci_ca->h_ci_ca && uvp_intf.pre_modify_ca ) + { + /* Pre call to the UVP library */ + status = uvp_intf.pre_modify_ca( + h_ca->obj.p_ci_ca->h_ci_ca, port_num, ca_mod, p_port_attr_mod ); + if( status != IB_SUCCESS ) + { + AL_EXIT( AL_DBG_CA ); + return status; + } + } + + ca_ioctl.in.h_ca = h_ca->obj.p_ci_ca->obj.hdl; + ca_ioctl.in.port_num = port_num; + ca_ioctl.in.ca_mod = ca_mod; + ca_ioctl.in.port_attr_mod = *p_port_attr_mod; + + cl_status = do_al_dev_ioctl( UAL_MODIFY_CA, + &ca_ioctl.in, sizeof(ca_ioctl.in), &ca_ioctl.out, sizeof(ca_ioctl.out), + &bytes_ret ); + + if( cl_status != CL_SUCCESS || bytes_ret != sizeof(ca_ioctl.out) ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("UAL_MODIFY_CA IOCTL returned %s\n", CL_STATUS_MSG(cl_status)) ); + status = IB_ERROR; + } + else + { + status = ca_ioctl.out.status; + } + + /* Post uvp call */ + if( h_ca->obj.p_ci_ca->h_ci_ca && uvp_intf.post_modify_ca ) + uvp_intf.post_modify_ca( h_ca->obj.p_ci_ca->h_ci_ca, status ); + + AL_EXIT( AL_DBG_CA ); + return status; +} + + + +static ib_api_status_t +__convert_to_proxy_handles( + IN uint64_t* const dst_handle_array, + IN const void** const src_handle_array, + IN uint32_t num_handles ) +{ + uint32_t i; + al_obj_t *p_al_obj; + + for( i = 0; i < num_handles; i++ ) + { + p_al_obj = (al_obj_t*)src_handle_array[i]; + if( (p_al_obj->type != AL_OBJ_TYPE_H_PD) && + (p_al_obj->type != AL_OBJ_TYPE_H_CQ) && + (p_al_obj->type != AL_OBJ_TYPE_H_AV) && + (p_al_obj->type != AL_OBJ_TYPE_H_QP) && + (p_al_obj->type != AL_OBJ_TYPE_H_MR) && + (p_al_obj->type != AL_OBJ_TYPE_H_MW) ) + { + return IB_INVALID_HANDLE; + } + + dst_handle_array[i] = p_al_obj->hdl; + } + return IB_SUCCESS; +} + + + +ib_api_status_t +ib_ci_call( + IN ib_ca_handle_t h_ca, + IN const void** const handle_array OPTIONAL, + IN uint32_t num_handles, + IN ib_ci_op_t* const p_ci_op ) +{ + ual_ci_call_ioctl_t *p_ca_ioctl; + size_t in_sz; + uintn_t bytes_ret; + cl_status_t cl_status; + ib_api_status_t status; + uvp_interface_t uvp_intf; + void** p_uvp_handle_array = NULL; + + AL_ENTER( AL_DBG_CA ); + + if( AL_OBJ_INVALID_HANDLE( h_ca, AL_OBJ_TYPE_H_CA ) ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, ("IB_INVALID_CA_HANDLE\n") ); + return IB_INVALID_CA_HANDLE; + } + if( !p_ci_op ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + uvp_intf = h_ca->obj.p_ci_ca->verbs.user_verbs; + + in_sz = sizeof(ual_ci_call_ioctl_t); + if( num_handles > 1 ) + in_sz += (sizeof(uint64_t) * (num_handles - 1)); + + p_ca_ioctl = cl_zalloc( in_sz ); + if( !p_ca_ioctl ) + { + AL_EXIT( AL_DBG_CA ); + return IB_INSUFFICIENT_MEMORY; + } + + if( num_handles > 0 ) + { + status = __convert_to_proxy_handles( + p_ca_ioctl->in.handle_array, handle_array, num_handles ); + if( status != IB_SUCCESS ) + { + cl_free( p_ca_ioctl ); + AL_EXIT( AL_DBG_CA ); + return status; + } + + p_uvp_handle_array = cl_zalloc( sizeof(void*) * num_handles ); + if( !p_uvp_handle_array ) + { + cl_free( p_ca_ioctl ); + AL_EXIT( AL_DBG_CA ); + return IB_INSUFFICIENT_MEMORY; + } + + /* Convert the handle array */ + status = al_convert_to_ci_handles( + p_uvp_handle_array, handle_array, num_handles ); + if( status != IB_SUCCESS ) + { + cl_free( p_uvp_handle_array ); + cl_free( p_ca_ioctl ); + AL_EXIT( AL_DBG_CA ); + return status; + } + } + + /* Pre call to the UVP library */ + if( h_ca->obj.p_ci_ca->h_ci_ca && uvp_intf.pre_ci_call ) + { + status = uvp_intf.pre_ci_call( + h_ca->obj.p_ci_ca->h_ci_ca, p_uvp_handle_array, + num_handles, p_ci_op, &p_ca_ioctl->in.umv_buf ); + if( status != IB_SUCCESS ) + { + cl_free( p_uvp_handle_array ); + cl_free( p_ca_ioctl ); + AL_EXIT( AL_DBG_CA ); + return status; + } + } + + p_ca_ioctl->in.h_ca = h_ca->obj.p_ci_ca->obj.hdl; + p_ca_ioctl->in.num_handles = num_handles; + p_ca_ioctl->in.ci_op = *p_ci_op; + + cl_status = do_al_dev_ioctl( UAL_CI_CALL, + &p_ca_ioctl->in, sizeof(p_ca_ioctl->in), + &p_ca_ioctl->out, sizeof(p_ca_ioctl->out), + &bytes_ret ); + + if( cl_status != CL_SUCCESS || bytes_ret != sizeof(p_ca_ioctl->out) ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("UAL_CI_CALL IOCTL returned %s\n", CL_STATUS_MSG(cl_status)) ); + status = IB_ERROR; + } + else + { + status = p_ca_ioctl->out.status; + } + + /* Post uvp call */ + if( h_ca->obj.p_ci_ca->h_ci_ca && uvp_intf.post_ci_call ) + { + uvp_intf.post_ci_call( + h_ca->obj.p_ci_ca->h_ci_ca, + status, p_uvp_handle_array, num_handles, p_ci_op, + &p_ca_ioctl->out.umv_buf ); + } + + if( num_handles > 0 ) + cl_free( p_uvp_handle_array ); + cl_free( p_ca_ioctl ); + + AL_EXIT( AL_DBG_CA ); + return status; +} diff --git a/branches/WOF2-3/core/al/user/ual_ca.h b/branches/WOF2-3/core/al/user/ual_ca.h new file mode 100644 index 00000000..671eaad1 --- /dev/null +++ b/branches/WOF2-3/core/al/user/ual_ca.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#if !defined(__IB_UAL_CA_H__) +#define __IB_UAL_CA_H__ + +#include +#include "al_ci_ca.h" + +void +close_vendor_lib( + IN verbs_interface_t *p_vca_intf ); + +ib_api_status_t +open_vendor_lib( + IN const ib_net64_t ca_guid, + IN OUT verbs_interface_t *p_vca_intf); + + +void +ual_ca_completion_cb( + IN void* cq_context ); + + +void +ual_ca_async_event_cb( + IN ib_event_rec_t* event_record ); + + +#endif /* __IB_UAL_CA_H__ */ diff --git a/branches/WOF2-3/core/al/user/ual_ci_ca.c b/branches/WOF2-3/core/al/user/ual_ci_ca.c new file mode 100644 index 00000000..e2294e98 --- /dev/null +++ b/branches/WOF2-3/core/al/user/ual_ci_ca.c @@ -0,0 +1,339 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include "al.h" +#include "al_mgr.h" +#include "al_ci_ca.h" +#include "ual_ca.h" +#include "al_pnp.h" +#include "al_pd.h" +#include "ib_common.h" + + +#include "al_debug.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "ual_ci_ca.tmh" +#endif + + +extern ib_pool_handle_t gh_mad_pool; +extern ib_al_handle_t gh_al; +extern cl_async_proc_t *gp_async_proc_mgr; + +#define EVENT_POOL_MIN 4 +#define EVENT_POOL_MAX 0 +#define EVENT_POOL_GROW 1 + + +static void +ci_ca_async_proc_cb( + IN struct _cl_async_proc_item *p_item ); + +void +destroying_ci_ca( + IN al_obj_t* p_obj ); + +void +cleanup_ci_ca( + IN al_obj_t* p_obj ); + +/* To be called only if a CI is not opened yet by UAL */ + +/* This gets called by ual_mgr when a CA is opened for the first time. + * The CA remains open for the process life-time. + * ib_open_ca will not go through this code. + */ + +ib_api_status_t +create_ci_ca( + IN ib_al_handle_t h_al, + IN al_obj_t *p_parent_obj, + IN ib_net64_t ca_guid ) +{ + ib_api_status_t status; + cl_status_t cl_status; + al_ci_ca_t *p_ci_ca; + + AL_ENTER(AL_DBG_CA); + + /* Allocate a new CA structure. */ + p_ci_ca = (al_ci_ca_t *)cl_zalloc( sizeof( al_ci_ca_t ) ); + if( p_ci_ca == NULL ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("Failed to cl_malloc al_ci_ca_t\n") ); + return IB_INSUFFICIENT_MEMORY; + } + + /* Construct the CI CA */ + construct_al_obj( &p_ci_ca->obj, AL_OBJ_TYPE_CI_CA ); + cl_qlist_init( &p_ci_ca->ca_list ); + cl_qpool_construct( &p_ci_ca->event_pool ); + cl_spinlock_construct( &p_ci_ca->attr_lock ); + + cl_status = cl_spinlock_init( &p_ci_ca->attr_lock ); + if( cl_status != CL_SUCCESS ) + { + free_ci_ca( &p_ci_ca->obj ); + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("cl_spinlock_init failed, status = 0x%x.\n", + ib_convert_cl_status(cl_status) ) ); + return ib_convert_cl_status( cl_status ); + } + + /* Create a pool of items to report asynchronous events. */ + cl_status = cl_qpool_init( &p_ci_ca->event_pool, EVENT_POOL_MIN, + EVENT_POOL_MAX, EVENT_POOL_GROW, sizeof( event_item_t ), NULL, + NULL, p_ci_ca ); + if( cl_status != CL_SUCCESS ) + { + free_ci_ca( &p_ci_ca->obj ); + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("cl_qpool_init failed, status = 0x%x.\n", + ib_convert_cl_status(cl_status) ) ); + return ib_convert_cl_status( cl_status ); + } + + /* Initialize the al object and attach it to the parent so that the + * cleanups will work fine on all cases including error conditions + * encountered here. We use synchronous destruction to ensure that + * the internal CA handle is destroyed before the global AL instance + * is destroyed during the shutdown procedure. + */ + status = init_al_obj( &p_ci_ca->obj, p_ci_ca, FALSE, + destroying_ci_ca, cleanup_ci_ca, free_ci_ca ); + if( status != IB_SUCCESS ) + { + free_ci_ca( &p_ci_ca->obj ); + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("init_al_obj failed, status = 0x%x.\n", status) ); + return status; + } + + attach_al_obj( p_parent_obj, &p_ci_ca->obj ); + + p_ci_ca->dereg_async_item.pfn_callback = ci_ca_async_proc_cb; + + /* We need to open a CA and allocate a PD for internal use. Doing this + * will result in the creation of user-mode and kernel-mode objects that + * will be children under our global AL instance and associated kernel AL + * instance. We need to take a reference on our user-mode AL instance + * while the CI CA exists, to ensure that our kernel-mode counterpart + * does not go away during application exit. + */ + ref_al_obj( &gh_al->obj ); + + /* Register ourselves with the AL manager, so that the open call below + * will succeed. + */ + add_ci_ca( p_ci_ca ); + open_vendor_lib( ca_guid, &p_ci_ca->verbs ); + + /* Now open the UAL CA to be assigned to p_ci_ca */ + status = ib_open_ca( h_al, ca_guid, ca_event_cb, p_ci_ca, + &p_ci_ca->h_ca ); + if( status != IB_SUCCESS ) + { + p_ci_ca->obj.pfn_destroy( &p_ci_ca->obj, NULL ); + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("ib_open_ca failed, status = 0x%x.\n", status) ); + return status; + } + + /* Now open the CA by sending the ioctl down to kernel */ + status = ual_open_ca( ca_guid, p_ci_ca ); + if (status != IB_SUCCESS) + { + p_ci_ca->obj.pfn_destroy( &p_ci_ca->obj, NULL ); + + /* Note that we don't release it here. + * It is done through async queuing and the callback + * and the associated destroy/cleanup in the AL's + * object model + */ + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("ual_open_ca failed, status = 0x%x.\n", status) ); + return IB_ERROR; + } + + /* Increase the max timeout for the CI CA to handle driver unload. */ + set_al_obj_timeout( &p_ci_ca->obj, AL_MAX_TIMEOUT_MS ); + + /* + * Allocate a PD for use by AL itself. Note that we need to use the + * PD in the kernel, so we create an alias PD for the global PD. + */ + status = ib_alloc_pd( p_ci_ca->h_ca, IB_PDT_ALIAS, p_ci_ca, + &p_ci_ca->h_pd ); + if( status != IB_SUCCESS ) + { + p_ci_ca->obj.pfn_destroy( &p_ci_ca->obj, NULL ); + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("ib_alloc_pd failed, status = 0x%x.\n", status) ); + return status; + } + + /* Allocate an alias in the kernel for this global PD alias. */ + status = ual_allocate_pd( p_ci_ca->h_ca, IB_PDT_ALIAS, p_ci_ca->h_pd ); + if( status != IB_SUCCESS ) + { + p_ci_ca->obj.pfn_destroy( &p_ci_ca->obj, NULL ); + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("ual_allocate_pd returned %s\n", ib_get_err_str( status )) ); + return status; + } + + /* Now create an alias PD in user-mode for AL services. */ + status = ib_alloc_pd( p_ci_ca->h_ca, IB_PDT_ALIAS, p_ci_ca, + &p_ci_ca->h_pd_alias ); + if( status != IB_SUCCESS ) + { + p_ci_ca->obj.pfn_destroy( &p_ci_ca->obj, NULL ); + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("ib_alloc_pd failed, status = 0x%x.\n", status) ); + return status; + } + + status = get_port_info( p_ci_ca ); + if( status != IB_SUCCESS ) + { + p_ci_ca->obj.pfn_destroy( &p_ci_ca->obj, NULL ); + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("get_port_info failed, status = 0x%x.\n", status) ); + return status; + } + + /* Register the global MAD pool on this CA. */ + status = ib_reg_mad_pool( gh_mad_pool, p_ci_ca->h_pd, &p_ci_ca->pool_key ); + if( status != IB_SUCCESS ) + { + p_ci_ca->obj.pfn_destroy( &p_ci_ca->obj, NULL ); + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("ib_reg_mad_pool failed, status = 0x%x.\n", status) ); + return status; + } + + /* Update the PnP attributes buffer. */ + ci_ca_update_attr( p_ci_ca, NULL ); + + /* Release the reference taken in init_al_obj. */ + deref_al_obj( &p_ci_ca->obj ); + + AL_EXIT(AL_DBG_CA); + return IB_SUCCESS; +} + + + +static void +ci_ca_async_proc_cb( + IN struct _cl_async_proc_item *p_item ) +{ + al_ci_ca_t *p_ci_ca; + + p_ci_ca = PARENT_STRUCT( p_item, al_ci_ca_t, dereg_async_item ); + + /* Release all AL resources acquired by the CI CA. */ + ib_close_ca( p_ci_ca->h_ca, NULL ); +} + + + +/* + * This overrides the implementation in shared AL + * UAL-specific destroy_ci_ca + */ +void +destroying_ci_ca( + IN al_obj_t* p_obj ) +{ + al_ci_ca_t *p_ci_ca; + + AL_ENTER(AL_DBG_CA); + CL_ASSERT( p_obj ); + p_ci_ca = PARENT_STRUCT( p_obj, al_ci_ca_t, obj ); + + /* + * We queue a request to the asynchronous processing manager to close + * the CA after the PNP remove CA event has been delivered. This avoids + * the ib_close_ca() call from immediately removing resouces (PDs, QPs) + * that are in use by clients waiting on the remove CA event. + */ + if( p_ci_ca->h_ca ) + cl_async_proc_queue( gp_async_pnp_mgr, &p_ci_ca->dereg_async_item ); + + AL_EXIT(AL_DBG_CA); +} + + + +/* + * This overrides the implementation in shared AL + * + * Remove H/W resource used. From UAL perspective, it is the UVP lib + * UAL-specific + */ +void +cleanup_ci_ca( + IN al_obj_t* p_obj ) +{ + ib_api_status_t status; + al_ci_ca_t *p_ci_ca; + + AL_ENTER(AL_DBG_CA); + + CL_ASSERT( p_obj ); + p_ci_ca = PARENT_STRUCT( p_obj, al_ci_ca_t, obj ); + + if( p_ci_ca->h_ca ) + { + /* Remove the associated kernel CA object. */ + status = ual_close_ca( p_ci_ca ); + CL_ASSERT( status == IB_SUCCESS ); + } + + remove_ci_ca( p_ci_ca ); + + /* We have finished cleaning up all associated kernel resources. We can + * now safely dereference the global AL instance. + */ + deref_al_obj( &gh_al->obj ); + + close_vendor_lib( &p_ci_ca->verbs ); + + AL_EXIT(AL_DBG_CA); +} diff --git a/branches/WOF2-3/core/al/user/ual_ci_ca.h b/branches/WOF2-3/core/al/user/ual_ci_ca.h new file mode 100644 index 00000000..6dd42670 --- /dev/null +++ b/branches/WOF2-3/core/al/user/ual_ci_ca.h @@ -0,0 +1,287 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#if !defined(__UAL_CI_CA_H__) +#define __UAL_CI_CA_H__ + +#include +#include "al_common.h" +/* #include "al_ci_ca.h" */ +/* Dummy function declerations */ +/* The arguments must be defined later */ + + + +ib_api_status_t +create_ci_ca( + IN ib_al_handle_t h_al, + IN al_obj_t *p_parent_obj, + IN ib_net64_t ca_guid ); + +ib_api_status_t +ual_open_ca( + IN const ib_net64_t ca_guid, + IN OUT struct _al_ci_ca* const p_ci_ca ); + +#if 0 +ib_api_status_t +ual_close_ca( + IN ib_ca_handle_t h_ca); +#else +ib_api_status_t +ual_close_ca( + IN struct _al_ci_ca *p_ci_ca ); +#endif + +ib_api_status_t +ual_modify_ca( + IN const ib_ca_handle_t h_ca, + IN const uint8_t port_num, + IN const ib_ca_mod_t ca_mod, + IN const ib_port_attr_mod_t* const p_port_attr_mod ); + +ib_api_status_t +ual_query_ca( + IN const ib_ca_handle_t h_ca, + OUT ib_ca_attr_t* const p_ca_attr OPTIONAL, + IN OUT uint32_t* const p_size ); + +ib_api_status_t +ual_allocate_pd( + IN ib_ca_handle_t h_ca, + IN const ib_pd_type_t pd_type, + IN OUT ib_pd_handle_t h_pd ); + +ib_api_status_t +ual_deallocate_pd( + IN ib_pd_handle_t h_pd ); + +ib_api_status_t +ual_create_av( + IN const ib_pd_handle_t h_pd, + IN const ib_av_attr_t* const p_av_attr, + IN OUT ib_av_handle_t h_av ); + +ib_api_status_t +ual_pd_alias_create_av( + IN const ib_pd_handle_t h_pd, + IN const ib_av_attr_t* const p_av_attr, + IN OUT ib_av_handle_t h_av ); + +ib_api_status_t +ual_destroy_av( + IN ib_av_handle_t h_av ); + +ib_api_status_t +ual_modify_av( + IN ib_av_handle_t h_av, + IN const ib_av_attr_t* const p_av_attr); + +ib_api_status_t +ual_query_av( + IN ib_av_handle_t h_av, + OUT ib_av_attr_t* const p_av_attr, + OUT ib_pd_handle_t* const ph_pd ); + +ib_api_status_t +ual_create_srq( + IN const ib_pd_handle_t h_pd, + IN OUT ib_srq_handle_t h_srq, + IN const ib_srq_attr_t* const p_srq_attr); + +ib_api_status_t +ual_modify_srq( + IN ib_srq_handle_t h_srq, + IN const ib_srq_attr_t* const p_srq_attr, + IN const ib_srq_attr_mask_t srq_attr_mask ); + +ib_api_status_t +ual_query_srq( + IN ib_srq_handle_t h_srq, + OUT ib_srq_attr_t* p_srq_attr ); + +ib_api_status_t +ual_destroy_srq( + IN ib_srq_handle_t h_srq ); + +ib_api_status_t +ual_create_qp( + IN const ib_pd_handle_t h_pd, + IN OUT ib_qp_handle_t h_qp, + IN const ib_qp_create_t* const p_qp_create, + IN ib_qp_attr_t* p_qp_attr ); + +ib_api_status_t +ual_modify_qp( + IN ib_qp_handle_t h_qp, + IN const ib_qp_mod_t* const p_qp_mod, + IN ib_qp_attr_t* p_qp_attr ); + +ib_api_status_t +ual_query_qp( + IN ib_qp_handle_t h_qp, + OUT ib_qp_attr_t* p_qp_attr ); + +ib_api_status_t +ual_destroy_qp( + IN ib_qp_handle_t h_qp ); + +ib_api_status_t +ual_create_cq( + IN struct _al_ci_ca* const p_ci_ca, + IN ib_cq_create_t* const p_cq_create, + IN OUT ib_cq_handle_t h_cq ); + +ib_api_status_t +ual_modify_cq( + IN ib_cq_handle_t h_cq, + IN OUT uint32_t* p_size ); + +ib_api_status_t +ual_query_cq( + IN ib_cq_handle_t h_cq, + OUT uint32_t* p_size ); + +ib_api_status_t +ual_destroy_cq( + IN ib_cq_handle_t h_cq ); + +ib_api_status_t +ual_reg_mem( + IN const ib_pd_handle_t h_pd, + IN const ib_mr_create_t* const p_mr_create, + OUT net32_t* const p_lkey, + OUT net32_t* const p_rkey, + IN OUT ib_mr_handle_t h_mr ); + +ib_api_status_t +ual_dereg_mr( + IN ib_mr_handle_t h_mr ); + +ib_api_status_t +ual_modify_mr( + IN const ib_mr_handle_t h_mr, + IN const ib_mr_mod_t mr_mod_mask, + IN const ib_mr_create_t* const p_mr_create OPTIONAL, + OUT net32_t* const p_lkey, + OUT net32_t* const p_rkey, + IN const ib_pd_handle_t h_pd OPTIONAL ); + +ib_api_status_t +ual_query_mr( + IN ib_mr_handle_t h_mr, + OUT ib_mr_attr_t* p_mr_attr ); + +ib_api_status_t +ual_reg_shared( + IN const ib_mr_handle_t h_mr, + IN const ib_pd_handle_t h_pd, + IN const ib_access_t access_ctrl, + IN OUT uint64_t* const p_vaddr, + OUT net32_t* const p_lkey, + OUT net32_t* const p_rkey, + IN OUT ib_mr_handle_t h_new_mr ); + +ib_api_status_t +ual_create_mw( + IN const ib_pd_handle_t h_pd, + OUT net32_t* const p_rkey, + IN OUT ib_mw_handle_t h_mw ); + +ib_api_status_t +ual_destroy_mw( + IN ib_mw_handle_t h_mw ); + +ib_api_status_t +ual_query_mw( + IN ib_mw_handle_t h_mw, + OUT ib_pd_handle_t* ph_pd, + OUT net32_t* const p_rkey ); + +ib_api_status_t +ual_bind_mw( + IN const ib_mw_handle_t h_mw, + IN const ib_qp_handle_t h_qp, + IN ib_bind_wr_t* p_mw_bind, + OUT net32_t* const p_rkey ); + +ib_api_status_t +ual_post_send( + IN const ib_qp_handle_t h_qp, + IN ib_send_wr_t* const p_send_wr, + OUT ib_send_wr_t **pp_send_failure ); + +ib_api_status_t +ual_post_recv( + IN const ib_qp_handle_t h_qp, + IN ib_recv_wr_t* const p_recv_wr, + OUT ib_recv_wr_t **pp_recv_failure ); + +ib_api_status_t +ual_post_srq_recv( + IN const ib_srq_handle_t h_srq, + IN ib_recv_wr_t* const p_recv_wr, + OUT ib_recv_wr_t **pp_recv_failure ); + +ib_api_status_t +ual_peek_cq( + IN const ib_cq_handle_t h_cq, + OUT uint32_t* const p_n_cqes ); + +ib_api_status_t +ual_poll_cq( + IN const ib_cq_handle_t h_cq, + IN OUT ib_wc_t** const pp_free_wclist, + OUT ib_wc_t** const pp_done_wclist ); + +ib_api_status_t +ual_rearm_cq( + IN const ib_cq_handle_t h_cq, + IN const boolean_t solicited ); + +ib_api_status_t +ual_rearm_n_cq( + IN const ib_cq_handle_t h_cq, + IN const uint32_t n_cqes ); + +typedef struct _ual_ci_interface +{ + uvp_interface_t user_verbs; + HMODULE h_uvp_lib; /* UVP Library Handle */ + ib_net64_t guid; + +} ual_ci_interface_t; + +typedef ual_ci_interface_t verbs_interface_t; + +#endif /* (__UAL_CI_CA_H__) */ diff --git a/branches/WOF2-3/core/al/user/ual_cm_cep.c b/branches/WOF2-3/core/al/user/ual_cm_cep.c new file mode 100644 index 00000000..5cfc9c1b --- /dev/null +++ b/branches/WOF2-3/core/al/user/ual_cm_cep.c @@ -0,0 +1,1475 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include +#include +#include +#include "al_common.h" +#include "al_cm_cep.h" +#include "al_cm_conn.h" +#include "al_cm_sidr.h" +#include "al_debug.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "ual_cm_cep.tmh" +#endif + +#include "ib_common.h" +#include "al_mgr.h" +//#include "al_ca.h" +#include "al.h" +//#include "al_mad.h" +#include "al_qp.h" + + +#define UAL_CEP_MIN (512) +#define UAL_CEP_GROW (256) + + +/* Global connection manager object. */ +typedef struct _ual_cep_mgr +{ + al_obj_t obj; + + cl_ptr_vector_t cep_vector; + + /* File handle on which to issue query IOCTLs. */ + HANDLE h_file; + +} ual_cep_mgr_t; + + +typedef struct _al_ucep +{ + al_pfn_cep_cb_t pfn_cb; + ib_al_handle_t h_al; + cl_list_item_t al_item; + + ib_pfn_destroy_cb_t pfn_destroy_cb; + void* destroy_context; + net32_t cid; + + OVERLAPPED ov; + atomic32_t ref_cnt; + +} ucep_t; + + +/* Global instance of the CM agent. */ +ual_cep_mgr_t *gp_cep_mgr = NULL; + + +/* + * Frees the global CEP manager. Invoked during al_obj destruction. + */ +static void +__free_cep_mgr( + IN al_obj_t* p_obj ) +{ + AL_ENTER( AL_DBG_CM ); + + CL_ASSERT( &gp_cep_mgr->obj == p_obj ); + + if( gp_cep_mgr->h_file != INVALID_HANDLE_VALUE ) + CloseHandle( gp_cep_mgr->h_file ); + + cl_ptr_vector_destroy( &gp_cep_mgr->cep_vector ); + + destroy_al_obj( p_obj ); + + cl_free( gp_cep_mgr ); + gp_cep_mgr = NULL; + + AL_EXIT( AL_DBG_CM ); +} + + +/* + * Allocates and initialized the global user-mode CM agent. + */ +ib_api_status_t +create_cep_mgr( + IN al_obj_t* const p_parent_obj ) +{ + ib_api_status_t status; + cl_status_t cl_status; + + AL_ENTER( AL_DBG_CM ); + + CL_ASSERT( gp_cep_mgr == NULL ); + + /* Allocate the global CM agent. */ + gp_cep_mgr = (ual_cep_mgr_t*)cl_zalloc( sizeof(ual_cep_mgr_t) ); + if( !gp_cep_mgr ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("Failed allocation of global CEP manager.\n") ); + return IB_INSUFFICIENT_MEMORY; + } + + construct_al_obj( &gp_cep_mgr->obj, AL_OBJ_TYPE_CM ); + cl_ptr_vector_construct( &gp_cep_mgr->cep_vector ); + gp_cep_mgr->h_file = INVALID_HANDLE_VALUE; + + status = init_al_obj( &gp_cep_mgr->obj, NULL, FALSE, + NULL, NULL, __free_cep_mgr ); + if( status != IB_SUCCESS ) + { + __free_cep_mgr( &gp_cep_mgr->obj ); + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("init_al_obj failed with status %s.\n", ib_get_err_str(status)) ); + return status; + } + /* Attach to the parent object. */ + status = attach_al_obj( p_parent_obj, &gp_cep_mgr->obj ); + if( status != IB_SUCCESS ) + { + gp_cep_mgr->obj.pfn_destroy( &gp_cep_mgr->obj, NULL ); + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("attach_al_obj returned %s.\n", ib_get_err_str(status)) ); + return status; + } + + cl_status = cl_ptr_vector_init( + &gp_cep_mgr->cep_vector, UAL_CEP_MIN, UAL_CEP_GROW ); + if( cl_status != CL_SUCCESS ) + { + gp_cep_mgr->obj.pfn_destroy( &gp_cep_mgr->obj, NULL ); + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("cl_vector_init failed with status %s.\n", + CL_STATUS_MSG(cl_status)) ); + return ib_convert_cl_status( cl_status ); + } + + /* Create a file object on which to issue all CM requests. */ + gp_cep_mgr->h_file = ual_create_async_file( UAL_BIND_CM ); + if( gp_cep_mgr->h_file == INVALID_HANDLE_VALUE ) + { + gp_cep_mgr->obj.pfn_destroy( &gp_cep_mgr->obj, NULL ); + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("ual_create_async_file for UAL_BIND_CM returned %d.\n", + GetLastError()) ); + return IB_ERROR; + } + + /* Release the reference from init_al_obj */ + deref_al_obj( &gp_cep_mgr->obj ); + + AL_EXIT( AL_DBG_CM ); + return IB_SUCCESS; +} + + +void +al_cep_cleanup_al( + IN const ib_al_handle_t h_al ) +{ + cl_list_item_t *p_item; + net32_t cid; + + AL_ENTER( AL_DBG_CM ); + + /* Destroy all CEPs associated with the input instance of AL. */ + cl_spinlock_acquire( &h_al->obj.lock ); + for( p_item = cl_qlist_head( &h_al->cep_list ); + p_item != cl_qlist_end( &h_al->cep_list ); + p_item = cl_qlist_head( &h_al->cep_list ) ) + { + /* + * Note that we don't walk the list - we can't hold the AL + * lock when cleaning up its CEPs because the cleanup path + * takes the CEP's lock. We always want to take the CEP + * before the AL lock to prevent any possibilities of deadlock. + * + * So we just get the CID, and then release the AL lock and try to + * destroy. This should unbind the CEP from the AL instance and + * remove it from the list, allowing the next CEP to be cleaned up + * in the next pass through. + */ + cid = PARENT_STRUCT( p_item, ucep_t, al_item )->cid; + cl_spinlock_release( &h_al->obj.lock ); + al_destroy_cep( h_al, &cid, FALSE ); + cl_spinlock_acquire( &h_al->obj.lock ); + } + cl_spinlock_release( &h_al->obj.lock ); + + AL_EXIT( AL_DBG_CM ); +} + + +static void +__destroy_ucep( + IN ucep_t* const p_cep ) +{ + if( p_cep->pfn_destroy_cb ) + p_cep->pfn_destroy_cb( p_cep->destroy_context ); + cl_free( p_cep ); +} + + +ib_api_status_t +__create_ucep( + IN ib_al_handle_t h_al, + IN net32_t cid, + IN al_pfn_cep_cb_t pfn_cb, + IN void* context, + IN ib_pfn_destroy_cb_t pfn_destroy_cb, + IN OUT net32_t* const p_cid ) +{ + ucep_t *p_cep; + DWORD bytes_ret; + ual_create_cep_ioctl_t ioctl; + + AL_ENTER( AL_DBG_CM ); + + p_cep = cl_zalloc( sizeof(ucep_t) ); + if( !p_cep ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, ("Failed to allocate ucep_t\n") ); + return IB_INSUFFICIENT_MEMORY; + } + + /* Initialize to two - one for the CEP, and one for the IOCTL. */ + p_cep->ref_cnt = 2; + + /* Store user parameters. */ + p_cep->pfn_cb = pfn_cb; + p_cep->destroy_context = context; + + /* Create a kernel CEP only if we don't already have a CID. */ + if( cid == AL_INVALID_CID ) + { + if( !DeviceIoControl( g_al_device, UAL_CREATE_CEP, NULL, + 0, &ioctl, sizeof(ioctl), &bytes_ret, NULL ) || + bytes_ret != sizeof(ioctl) ) + { + __destroy_ucep( p_cep ); + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("UAL_CREATE_CEP IOCTL failed with %d.\n", GetLastError()) ); + return IB_ERROR; + } + + if( ioctl.status != IB_SUCCESS ) + { + __destroy_ucep( p_cep ); + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, ("UAL_CREATE_CEP IOCTL returned %s\n", + ib_get_err_str( ioctl.status )) ); + return ioctl.status; + } + + p_cep->cid = ioctl.cid; + } + else + { + p_cep->cid = cid; + } + + /* Track the CEP before we issue any further IOCTLs on it. */ + cl_spinlock_acquire( &gp_cep_mgr->obj.lock ); + cl_ptr_vector_set_min_size( &gp_cep_mgr->cep_vector, p_cep->cid + 1 ); + CL_ASSERT( !cl_ptr_vector_get( &gp_cep_mgr->cep_vector, p_cep->cid ) ); + cl_ptr_vector_set( &gp_cep_mgr->cep_vector, p_cep->cid, p_cep ); + cl_spinlock_release( &gp_cep_mgr->obj.lock ); + + /* Now issue a poll request. This request is async. */ + if( DeviceIoControl( gp_cep_mgr->h_file, UAL_CEP_GET_EVENT, + &p_cep->cid, sizeof(p_cep->cid), + NULL, 0, NULL, &p_cep->ov ) || + GetLastError() != ERROR_IO_PENDING ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , ("Failed to issue CEP poll IOCTL.\n") ); + cl_spinlock_acquire( &gp_cep_mgr->obj.lock ); + cl_ptr_vector_set( &gp_cep_mgr->cep_vector, p_cep->cid, NULL ); + cl_spinlock_release( &gp_cep_mgr->obj.lock ); + + DeviceIoControl( g_al_device, UAL_DESTROY_CEP, &p_cep->cid, + sizeof(p_cep->cid), NULL, 0, &bytes_ret, NULL ); + + __destroy_ucep( p_cep ); + AL_EXIT( AL_DBG_CM ); + return IB_ERROR; + } + + p_cep->h_al = h_al; + + /* Track the CEP in its owning AL instance. */ + cl_spinlock_acquire( &h_al->obj.lock ); + if( p_cid ) + { + if( *p_cid != AL_INVALID_CID ) + { + cl_spinlock_release( &h_al->obj.lock ); + al_destroy_cep( h_al, &cid, TRUE ); + return IB_INVALID_STATE; + } + p_cep->pfn_destroy_cb = pfn_destroy_cb; + *p_cid = p_cep->cid; + } + + cl_qlist_insert_tail( &h_al->cep_list, &p_cep->al_item ); + + cl_spinlock_release( &h_al->obj.lock ); + + AL_EXIT( AL_DBG_CM ); + return IB_SUCCESS; +} + + +ib_api_status_t +al_create_cep( + IN ib_al_handle_t h_al, + IN al_pfn_cep_cb_t pfn_cb, + IN void* context, + IN ib_pfn_destroy_cb_t pfn_destroy_cb, + IN OUT net32_t* const p_cid ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_CM ); + + status = __create_ucep( + h_al, AL_INVALID_CID, pfn_cb, context, pfn_destroy_cb, p_cid ); + + AL_EXIT( AL_DBG_CM ); + return status; +} + + +/* + * Note that destroy_cep is synchronous. It does however handle the case + * where a user calls it from a callback context. + */ +void +al_destroy_cep( + IN ib_al_handle_t h_al, + IN OUT net32_t* const p_cid, + IN boolean_t reusable ) +{ + ucep_t *p_cep; + DWORD bytes_ret; + + AL_ENTER( AL_DBG_CM ); + + CL_ASSERT( h_al ); + + cl_spinlock_acquire( &gp_cep_mgr->obj.lock ); + if( *p_cid < cl_ptr_vector_get_size( &gp_cep_mgr->cep_vector ) ) + { + p_cep = cl_ptr_vector_get( &gp_cep_mgr->cep_vector, *p_cid ); + if( p_cep && p_cep->h_al == h_al ) + cl_ptr_vector_set( &gp_cep_mgr->cep_vector, *p_cid, NULL ); + else + goto invalid; + } + else + { +invalid: + if( !reusable ) + *p_cid = AL_RESERVED_CID; + + cl_spinlock_release( &gp_cep_mgr->obj.lock ); + AL_EXIT( AL_DBG_CM ); + return; + } + + /* + * Destroy the kernel CEP right away. We must synchronize with issuing + * the next GET_EVENT IOCTL. + */ + DeviceIoControl( g_al_device, UAL_DESTROY_CEP, &p_cep->cid, + sizeof(p_cep->cid), NULL, 0, &bytes_ret, NULL ); + if( reusable ) + *p_cid = AL_INVALID_CID; + else + *p_cid = AL_RESERVED_CID; + + cl_spinlock_release( &gp_cep_mgr->obj.lock ); + + /* + * Remove from the AL instance. Note that once removed, all + * callbacks for an item will stop. + */ + cl_spinlock_acquire( &h_al->obj.lock ); + cl_qlist_remove_item( &h_al->cep_list, &p_cep->al_item ); + + cl_spinlock_release( &h_al->obj.lock ); + + if( !cl_atomic_dec( &p_cep->ref_cnt ) ) + { + /* We have no remaining refrences. */ + __destroy_ucep( p_cep ); + } + + AL_EXIT( AL_DBG_CM ); +} + + +ib_api_status_t +al_cep_listen( + IN ib_al_handle_t h_al, + IN net32_t cid, + IN ib_cep_listen_t* const p_listen_info ) +{ + ual_cep_listen_ioctl_t ioctl; + ib_api_status_t status; + DWORD bytes_ret; + + AL_ENTER( AL_DBG_CM ); + + if( !h_al ) + { + AL_EXIT( AL_DBG_CM ); + return IB_INVALID_HANDLE; + } + + if( !p_listen_info ) + { + AL_EXIT( AL_DBG_CM ); + return IB_INVALID_PARAMETER; + } + + ioctl.cid = cid; + ioctl.cep_listen = *p_listen_info; + ioctl.cep_listen.p_cmp_buf_padding = 0; + if( p_listen_info->p_cmp_buf ) + { + if( p_listen_info->cmp_len > IB_REQ_PDATA_SIZE ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("Listen compare data larger than REQ private data.\n") ); + return IB_INVALID_SETTING; + } + + ioctl.cep_listen.p_cmp_buf_padding = 1; + cl_memcpy( ioctl.compare, p_listen_info->p_cmp_buf, + p_listen_info->cmp_len ); + } + + if( !DeviceIoControl( g_al_device, UAL_CEP_LISTEN, &ioctl, + sizeof(ioctl), &status, sizeof(status), &bytes_ret, NULL ) || + bytes_ret != sizeof(status) ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("ual_cep_listen IOCTL failed with %d.\n", GetLastError()) ); + return IB_ERROR; + } + + AL_EXIT( AL_DBG_CM ); + return status; +} + + +ib_api_status_t +al_cep_pre_req( + IN ib_al_handle_t h_al, + IN net32_t cid, + IN const ib_cm_req_t* const p_cm_req, + OUT ib_qp_mod_t* const p_init ) +{ + ual_cep_req_ioctl_t ioctl; + DWORD bytes_ret; + + AL_ENTER( AL_DBG_CM ); + + if( !h_al ) + { + AL_EXIT( AL_DBG_CM ); + return IB_INVALID_HANDLE; + } + + if( !p_cm_req ) + { + AL_EXIT( AL_DBG_CM ); + return IB_INVALID_PARAMETER; + } + + if( !p_init ) + { + AL_EXIT( AL_DBG_ERROR ); + return IB_INVALID_PARAMETER; + } + + ioctl.in.cid = cid; + ioctl.in.cm_req = *p_cm_req; + ioctl.in.cm_req.h_qp_padding = p_cm_req->h_qp->obj.hdl; + ioctl.in.paths[0] = *(p_cm_req->p_primary_path); + ioctl.in.cm_req.p_alt_path_padding = 0; + if( p_cm_req->p_alt_path ) + { + ioctl.in.cm_req.p_alt_path_padding = 1; + ioctl.in.paths[1] = *(p_cm_req->p_alt_path); + } + /* Copy private data, if any. */ + ioctl.in.cm_req.p_req_pdata_padding = 0; + if( p_cm_req->p_req_pdata ) + { + if( p_cm_req->req_length > IB_REQ_PDATA_SIZE ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("private data larger than REQ private data.\n") ); + return IB_INVALID_SETTING; + } + + ioctl.in.cm_req.p_req_pdata_padding = 1; + cl_memcpy( ioctl.in.pdata, p_cm_req->p_req_pdata, + p_cm_req->req_length ); + } + + /* Copy compare data, if any. */ + ioctl.in.cm_req.p_compare_buffer_padding = 0; + if( p_cm_req->p_compare_buffer ) + { + if( p_cm_req->compare_length > IB_REQ_PDATA_SIZE ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("REQ compare data larger than REQ private data.\n") ); + return IB_INVALID_SETTING; + } + + ioctl.in.cm_req.p_compare_buffer_padding = 1; + cl_memcpy( ioctl.in.compare, p_cm_req->p_compare_buffer, + p_cm_req->compare_length ); + } + + if( !DeviceIoControl( g_al_device, UAL_CEP_PRE_REQ, &ioctl, + sizeof(ioctl.in), &ioctl, sizeof(ioctl.out), &bytes_ret, NULL ) || + bytes_ret != sizeof(ioctl.out) ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("UAL_CEP_PRE_REQ IOCTL failed with %d.\n", GetLastError()) ); + return IB_ERROR; + } + + if( ioctl.out.status == IB_SUCCESS ) + *p_init = ioctl.out.init; + + AL_EXIT( AL_DBG_CM ); + return ioctl.out.status; +} + + +ib_api_status_t +al_cep_send_req( + IN ib_al_handle_t h_al, + IN net32_t cid ) +{ + ib_api_status_t status; + DWORD bytes_ret; + + AL_ENTER( AL_DBG_CM ); + + if( !h_al ) + { + AL_EXIT( AL_DBG_CM ); + return IB_INVALID_HANDLE; + } + + if( !DeviceIoControl( g_al_device, UAL_CEP_SEND_REQ, &cid, + sizeof(cid), &status, sizeof(status), &bytes_ret, NULL ) || + bytes_ret != sizeof(status) ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("UAL_CEP_SEND_REQ IOCTL failed with %d.\n", GetLastError()) ); + return IB_ERROR; + } + + AL_EXIT( AL_DBG_CM ); + return status; +} + + +ib_api_status_t +al_cep_pre_rep( + IN ib_al_handle_t h_al, + IN net32_t cid, + IN void* context, + IN ib_pfn_destroy_cb_t pfn_destroy_cb, + IN const ib_cm_rep_t* const p_cm_rep, + IN OUT net32_t* const p_cid, + OUT ib_qp_mod_t* const p_init ) +{ + ucep_t *p_cep; + ual_cep_rep_ioctl_t ioctl; + DWORD bytes_ret; + + AL_ENTER( AL_DBG_CM ); + + if( !h_al ) + { + AL_EXIT( AL_DBG_CM ); + return IB_INVALID_HANDLE; + } + + if( !p_cm_rep ) + { + AL_EXIT( AL_DBG_CM ); + return IB_INVALID_PARAMETER; + } + + if( !p_init ) + { + AL_EXIT( AL_DBG_ERROR ); + return IB_INVALID_PARAMETER; + } + + /* Store the context for the CEP. */ + cl_spinlock_acquire( &gp_cep_mgr->obj.lock ); + p_cep = cl_ptr_vector_get( &gp_cep_mgr->cep_vector, cid ); + if( !p_cep ) + { + cl_spinlock_release( &gp_cep_mgr->obj.lock ); + AL_EXIT( AL_DBG_ERROR ); + return IB_INVALID_PARAMETER; + } + p_cep->destroy_context = context; + cl_spinlock_release( &gp_cep_mgr->obj.lock ); + + ioctl.in.context = (ULONG_PTR)context; + ioctl.in.cid = cid; + ioctl.in.cm_rep = *p_cm_rep; + ioctl.in.cm_rep.h_qp_padding = p_cm_rep->h_qp->obj.hdl; + /* Copy private data, if any. */ + ioctl.in.cm_rep.p_rep_pdata_padding = 0; + if( p_cm_rep->p_rep_pdata ) + { + if( p_cm_rep->rep_length > IB_REP_PDATA_SIZE ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("private data larger than REP private data.\n") ); + return IB_INVALID_SETTING; + } + + ioctl.in.cm_rep.p_rep_pdata_padding = 1; + cl_memcpy( ioctl.in.pdata, p_cm_rep->p_rep_pdata, + p_cm_rep->rep_length ); + } + + if( !DeviceIoControl( g_al_device, UAL_CEP_PRE_REP, &ioctl, + sizeof(ioctl.in), &ioctl, sizeof(ioctl.out), &bytes_ret, NULL ) || + bytes_ret != sizeof(ioctl.out) ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("UAL_CEP_PRE_REQ IOCTL failed with %d.\n", GetLastError()) ); + return IB_ERROR; + } + + if( ioctl.out.status == IB_SUCCESS ) + { + cl_spinlock_acquire( &h_al->obj.lock ); + if( *p_cid != AL_INVALID_CID ) + { + cl_spinlock_release( &h_al->obj.lock ); + return IB_INVALID_STATE; + } + p_cep->pfn_destroy_cb = pfn_destroy_cb; + *p_cid = p_cep->cid; + *p_init = ioctl.out.init; + cl_spinlock_release( &h_al->obj.lock ); + } + + AL_EXIT( AL_DBG_CM ); + return ioctl.out.status; +} + + +ib_api_status_t +al_cep_send_rep( + IN ib_al_handle_t h_al, + IN net32_t cid ) +{ + ib_api_status_t status; + DWORD bytes_ret; + + AL_ENTER( AL_DBG_CM ); + + if( !h_al ) + { + AL_EXIT( AL_DBG_CM ); + return IB_INVALID_HANDLE; + } + + if( !DeviceIoControl( g_al_device, UAL_CEP_SEND_REP, &cid, + sizeof(cid), &status, sizeof(status), &bytes_ret, NULL ) || + bytes_ret != sizeof(status) ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("UAL_CEP_SEND_REP IOCTL failed with %d.\n", GetLastError()) ); + return IB_ERROR; + } + + AL_EXIT( AL_DBG_CM ); + return status; +} + + +ib_api_status_t +al_cep_get_rtr_attr( + IN ib_al_handle_t h_al, + IN net32_t cid, + OUT ib_qp_mod_t* const p_rtr ) +{ + ual_cep_get_rtr_ioctl_t ioctl; + DWORD bytes_ret; + + AL_ENTER( AL_DBG_CM ); + + if( !h_al ) + { + AL_EXIT( AL_DBG_CM ); + return IB_INVALID_HANDLE; + } + + if( !p_rtr ) + { + AL_EXIT( AL_DBG_ERROR ); + return IB_INVALID_PARAMETER; + } + + if( !DeviceIoControl( g_al_device, UAL_CEP_GET_RTR, &cid, + sizeof(cid), &ioctl, sizeof(ioctl), &bytes_ret, NULL ) || + bytes_ret != sizeof(ioctl) ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("UAL_CEP_GET_RTR IOCTL failed with %d.\n", GetLastError()) ); + return IB_ERROR; + } + + if( ioctl.status == IB_SUCCESS ) + *p_rtr = ioctl.rtr; + + AL_EXIT( AL_DBG_CM ); + return ioctl.status; +} + + +ib_api_status_t +al_cep_get_rts_attr( + IN ib_al_handle_t h_al, + IN net32_t cid, + OUT ib_qp_mod_t* const p_rts ) +{ + ual_cep_get_rts_ioctl_t ioctl; + DWORD bytes_ret; + + AL_ENTER( AL_DBG_CM ); + + if( !h_al ) + { + AL_EXIT( AL_DBG_CM ); + return IB_INVALID_HANDLE; + } + + if( !p_rts ) + { + AL_EXIT( AL_DBG_ERROR ); + return IB_INVALID_PARAMETER; + } + + if( !DeviceIoControl( g_al_device, UAL_CEP_GET_RTS, &cid, + sizeof(cid), &ioctl, sizeof(ioctl), &bytes_ret, NULL ) || + bytes_ret != sizeof(ioctl) ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("UAL_CEP_GET_RTS IOCTL failed with %d.\n", GetLastError()) ); + return IB_ERROR; + } + + if( ioctl.status == IB_SUCCESS ) + *p_rts = ioctl.rts; + + AL_EXIT( AL_DBG_CM ); + return ioctl.status; +} + + +ib_api_status_t +al_cep_rtu( + IN ib_al_handle_t h_al, + IN net32_t cid, + IN const uint8_t* p_pdata OPTIONAL, + IN uint8_t pdata_len ) +{ + ib_api_status_t status; + ual_cep_rtu_ioctl_t ioctl; + DWORD bytes_ret; + + AL_ENTER( AL_DBG_CM ); + + if( !h_al ) + { + AL_EXIT( AL_DBG_CM ); + return IB_INVALID_HANDLE; + } + + ioctl.cid = cid; + /* Copy private data, if any. */ + if( p_pdata ) + { + if( pdata_len > IB_RTU_PDATA_SIZE ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("private data larger than RTU private data.\n") ); + return IB_INVALID_SETTING; + } + + cl_memcpy( ioctl.pdata, p_pdata, pdata_len ); + } + ioctl.pdata_len = pdata_len; + + if( !DeviceIoControl( g_al_device, UAL_CEP_RTU, &ioctl, + sizeof(ioctl), &status, sizeof(status), &bytes_ret, NULL ) || + bytes_ret != sizeof(status) ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("UAL_CEP_RTU IOCTL failed with %d.\n", GetLastError()) ); + return IB_ERROR; + } + + AL_EXIT( AL_DBG_CM ); + return status; +} + + +ib_api_status_t +al_cep_rej( + IN ib_al_handle_t h_al, + IN net32_t cid, + IN ib_rej_status_t rej_status, + IN const uint8_t* const p_ari, + IN uint8_t ari_len, + IN const uint8_t* const p_pdata, + IN uint8_t pdata_len ) +{ + ib_api_status_t status; + ual_cep_rej_ioctl_t ioctl; + DWORD bytes_ret; + + AL_ENTER( AL_DBG_CM ); + + if( !h_al ) + { + AL_EXIT( AL_DBG_CM ); + return IB_INVALID_HANDLE; + } + + ioctl.cid = cid; + ioctl.rej_status = rej_status; + if( p_ari ) + { + if( ari_len > IB_ARI_SIZE ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("private data larger than REJ ARI data.\n") ); + return IB_INVALID_SETTING; + } + + cl_memcpy( ioctl.ari, p_ari, ari_len ); + ioctl.ari_len = ari_len; + } + else + { + ioctl.ari_len = 0; + } + /* Copy private data, if any. */ + if( p_pdata) + { + if( pdata_len > IB_REJ_PDATA_SIZE ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("private data larger than REJ private data.\n") ); + return IB_INVALID_SETTING; + } + + cl_memcpy( ioctl.pdata, p_pdata, pdata_len ); + ioctl.pdata_len = pdata_len; + } + else + { + ioctl.pdata_len = 0; + } + + if( !DeviceIoControl( g_al_device, UAL_CEP_REJ, &ioctl, + sizeof(ioctl), &status, sizeof(status), &bytes_ret, NULL ) || + bytes_ret != sizeof(status) ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("UAL_CEP_PRE_REQ IOCTL failed with %d.\n", GetLastError()) ); + return IB_ERROR; + } + + AL_EXIT( AL_DBG_CM ); + return status; +} + + +ib_api_status_t +al_cep_mra( + IN ib_al_handle_t h_al, + IN net32_t cid, + IN const ib_cm_mra_t* const p_cm_mra ) +{ + ib_api_status_t status; + ual_cep_mra_ioctl_t ioctl; + DWORD bytes_ret; + + AL_ENTER( AL_DBG_CM ); + + if( !h_al ) + { + AL_EXIT( AL_DBG_CM ); + return IB_INVALID_HANDLE; + } + + if( !p_cm_mra ) + { + AL_EXIT( AL_DBG_CM ); + return IB_INVALID_HANDLE; + } + + ioctl.cid = cid; + ioctl.cm_mra = *p_cm_mra; + ioctl.cm_mra.p_mra_pdata_padding = 0; + /* Copy private data, if any. */ + if( p_cm_mra->p_mra_pdata ) + { + if( p_cm_mra->mra_length > IB_MRA_PDATA_SIZE ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("private data larger than MRA private data.\n") ); + return IB_INVALID_SETTING; + } + + ioctl.cm_mra.p_mra_pdata_padding = 1; + cl_memcpy( + ioctl.pdata, p_cm_mra->p_mra_pdata, p_cm_mra->mra_length ); + } + + if( !DeviceIoControl( g_al_device, UAL_CEP_MRA, &ioctl, + sizeof(ioctl), &status, sizeof(status), &bytes_ret, NULL ) || + bytes_ret != sizeof(status) ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("UAL_CEP_MRA IOCTL failed with %d.\n", GetLastError()) ); + return IB_ERROR; + } + + AL_EXIT( AL_DBG_CM ); + return status; +} + + +ib_api_status_t +al_cep_lap( + IN ib_al_handle_t h_al, + IN net32_t cid, + IN const ib_cm_lap_t* const p_cm_lap ) +{ + ib_api_status_t status; + ual_cep_lap_ioctl_t ioctl; + DWORD bytes_ret; + + AL_ENTER( AL_DBG_CM ); + + if( !h_al ) + { + AL_EXIT( AL_DBG_CM ); + return IB_INVALID_HANDLE; + } + + if( !p_cm_lap ) + { + AL_EXIT( AL_DBG_CM ); + return IB_INVALID_HANDLE; + } + + if( !p_cm_lap->p_alt_path ) + { + AL_EXIT( AL_DBG_CM ); + return IB_INVALID_HANDLE; + } + + ioctl.cid = cid; + ioctl.cm_lap = *p_cm_lap; + ioctl.cm_lap.h_qp_padding = p_cm_lap->h_qp->obj.hdl; + ioctl.alt_path = *(p_cm_lap->p_alt_path); + /* Copy private data, if any. */ + ioctl.cm_lap.p_lap_pdata_padding = 0; + if( p_cm_lap->p_lap_pdata ) + { + if( p_cm_lap->lap_length > IB_LAP_PDATA_SIZE ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("private data larger than LAP private data.\n") ); + return IB_INVALID_SETTING; + } + + ioctl.cm_lap.p_lap_pdata_padding = 1; + cl_memcpy( + ioctl.pdata, p_cm_lap->p_lap_pdata, p_cm_lap->lap_length ); + } + + if( !DeviceIoControl( g_al_device, UAL_CEP_LAP, &ioctl, + sizeof(ioctl), &status, sizeof(status), &bytes_ret, NULL ) || + bytes_ret != sizeof(status) ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("UAL_CEP_LAP IOCTL failed with %d.\n", GetLastError()) ); + return IB_ERROR; + } + + AL_EXIT( AL_DBG_CM ); + return status; +} + + +ib_api_status_t +al_cep_pre_apr( + IN ib_al_handle_t h_al, + IN net32_t cid, + IN const ib_cm_apr_t* const p_cm_apr, + OUT ib_qp_mod_t* const p_apr ) +{ + ual_cep_apr_ioctl_t ioctl; + DWORD bytes_ret; + + AL_ENTER( AL_DBG_CM ); + + if( !h_al ) + { + AL_EXIT( AL_DBG_CM ); + return IB_INVALID_HANDLE; + } + + if( !p_cm_apr || !p_apr ) + { + AL_EXIT( AL_DBG_CM ); + return IB_INVALID_PARAMETER; + } + + ioctl.in.cid = cid; + ioctl.in.cm_apr = *p_cm_apr; + ioctl.in.cm_apr.h_qp_padding = p_cm_apr->h_qp->obj.hdl; + ioctl.in.cm_apr.p_info_padding = 0; + if( p_cm_apr->p_info ) + { + if( p_cm_apr->info_length > IB_APR_INFO_SIZE ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("private data larger than APR info data.\n") ); + return IB_INVALID_SETTING; + } + + ioctl.in.cm_apr.p_info_padding = 1; + cl_memcpy( + ioctl.in.apr_info, p_cm_apr->p_info, p_cm_apr->info_length ); + } + /* Copy private data, if any. */ + ioctl.in.cm_apr.p_apr_pdata_padding = 0; + if( p_cm_apr->p_apr_pdata ) + { + if( p_cm_apr->apr_length > IB_APR_PDATA_SIZE ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("private data larger than APR private data.\n") ); + return IB_INVALID_SETTING; + } + + ioctl.in.cm_apr.p_apr_pdata_padding = 1; + cl_memcpy( + ioctl.in.pdata, p_cm_apr->p_apr_pdata, p_cm_apr->apr_length ); + } + + if( !DeviceIoControl( g_al_device, UAL_CEP_PRE_APR, &ioctl.in, + sizeof(ioctl.in), &ioctl.out, sizeof(ioctl.out), &bytes_ret, NULL ) || + bytes_ret != sizeof(ioctl.out) ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("UAL_CEP_PRE_REQ IOCTL failed with %d.\n", GetLastError()) ); + return IB_ERROR; + } + + if( ioctl.out.status == IB_SUCCESS ) + *p_apr = ioctl.out.apr; + + AL_EXIT( AL_DBG_CM ); + return ioctl.out.status; +} + + +ib_api_status_t +al_cep_send_apr( + IN ib_al_handle_t h_al, + IN net32_t cid ) +{ + ib_api_status_t status; + DWORD bytes_ret; + + AL_ENTER( AL_DBG_CM ); + + if( !h_al ) + { + AL_EXIT( AL_DBG_CM ); + return IB_INVALID_HANDLE; + } + + if( !DeviceIoControl( g_al_device, UAL_CEP_SEND_APR, &cid, + sizeof(cid), &status, sizeof(status), &bytes_ret, NULL ) || + bytes_ret != sizeof(status) ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("UAL_CEP_SEND_APR IOCTL failed with %d.\n", GetLastError()) ); + return IB_ERROR; + } + + AL_EXIT( AL_DBG_CM ); + return status; +} + + +ib_api_status_t +al_cep_dreq( + IN ib_al_handle_t h_al, + IN net32_t cid, + IN const uint8_t* const p_pdata OPTIONAL, + IN const uint8_t pdata_len ) +{ + ib_api_status_t status; + ual_cep_dreq_ioctl_t ioctl; + DWORD bytes_ret; + + AL_ENTER( AL_DBG_CM ); + + if( !h_al ) + { + AL_EXIT( AL_DBG_CM ); + return IB_INVALID_HANDLE; + } + + ioctl.cid = cid; + /* Copy private data, if any. */ + if( p_pdata ) + { + if( pdata_len > IB_DREQ_PDATA_SIZE ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("private data larger than DREQ private data.\n") ); + return IB_INVALID_SETTING; + } + + cl_memcpy( ioctl.pdata, p_pdata, pdata_len ); + ioctl.pdata_len = pdata_len; + } + else + { + ioctl.pdata_len = 0; + } + + if( !DeviceIoControl( g_al_device, UAL_CEP_DREQ, &ioctl, + sizeof(ioctl), &status, sizeof(status), &bytes_ret, NULL ) || + bytes_ret != sizeof(status) ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("UAL_CEP_DREQ IOCTL failed with %d.\n", GetLastError()) ); + return IB_ERROR; + } + + AL_EXIT( AL_DBG_CM ); + return status; +} + + +ib_api_status_t +al_cep_drep( + IN ib_al_handle_t h_al, + IN net32_t cid, + IN const uint8_t* const p_pdata OPTIONAL, + IN const uint8_t pdata_len ) +{ + ib_api_status_t status; + ual_cep_drep_ioctl_t ioctl; + DWORD bytes_ret; + + AL_ENTER( AL_DBG_CM ); + + if( !h_al ) + { + AL_EXIT( AL_DBG_CM ); + return IB_INVALID_HANDLE; + } + + ioctl.cid = cid; + /* Copy private data, if any. */ + if( p_pdata ) + { + if( pdata_len > IB_DREP_PDATA_SIZE ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("private data larger than DREP private data.\n") ); + return IB_INVALID_SETTING; + } + + cl_memcpy( ioctl.pdata, p_pdata, pdata_len ); + ioctl.pdata_len = pdata_len; + } + else + { + ioctl.pdata_len = 0; + } + + if( !DeviceIoControl( g_al_device, UAL_CEP_DREP, &ioctl, + sizeof(ioctl), &status, sizeof(status), &bytes_ret, NULL ) || + bytes_ret != sizeof(status) ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("UAL_CEP_DREP IOCTL failed with %d.\n", GetLastError()) ); + return IB_ERROR; + } + + AL_EXIT( AL_DBG_CM ); + return status; +} + + +ib_api_status_t +al_cep_get_timewait( + IN ib_al_handle_t h_al, + IN net32_t cid, + OUT uint64_t* const p_timewait_us ) +{ + ual_cep_get_timewait_ioctl_t ioctl; + DWORD bytes_ret; + + AL_ENTER( AL_DBG_CM ); + + if( !h_al ) + { + AL_EXIT( AL_DBG_CM ); + return IB_INVALID_HANDLE; + } + + if( !p_timewait_us ) + { + AL_EXIT( AL_DBG_CM ); + return IB_INVALID_HANDLE; + } + + if( !DeviceIoControl( g_al_device, UAL_CEP_GET_TIMEWAIT, &cid, sizeof(cid), + &ioctl, sizeof(ioctl), &bytes_ret, NULL ) || + bytes_ret != sizeof(ioctl) ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("UAL_CEP_DREP IOCTL failed with %d.\n", GetLastError()) ); + return IB_ERROR; + } + + if( ioctl.status == IB_SUCCESS ) + *p_timewait_us = ioctl.timewait_us; + + AL_EXIT( AL_DBG_CM ); + return ioctl.status; +} +// +// +//ib_api_status_t +//al_cep_migrate( +// IN ib_al_handle_t h_al, +// IN net32_t cid ); +// +// +//ib_api_status_t +//al_cep_established( +// IN ib_al_handle_t h_al, +// IN net32_t cid ); + + +ib_api_status_t +al_cep_poll( + IN ib_al_handle_t h_al, + IN net32_t cid, + OUT void** p_context, + OUT net32_t* const p_new_cid, + OUT ib_mad_element_t** const pp_mad ) +{ + ucep_t *p_cep; + ib_api_status_t status; + ual_cep_poll_ioctl_t ioctl; + DWORD bytes_ret; + ib_mad_element_t *p_mad; + ib_grh_t *p_grh; + ib_mad_t *p_mad_buf; + + AL_ENTER( AL_DBG_CM ); + + if( !h_al ) + { + AL_EXIT( AL_DBG_CM ); + return IB_INVALID_HANDLE; + } + + if( !p_new_cid || !pp_mad ) + { + AL_EXIT( AL_DBG_CM ); + return IB_INVALID_PARAMETER; + } + + cl_spinlock_acquire( &gp_cep_mgr->obj.lock ); + if( cid > cl_ptr_vector_get_size( &gp_cep_mgr->cep_vector ) ) + p_cep = NULL; + else + p_cep = cl_ptr_vector_get( &gp_cep_mgr->cep_vector, cid ); + cl_spinlock_release( &gp_cep_mgr->obj.lock ); + if( !p_cep ) + { + AL_EXIT( AL_DBG_CM ); + return IB_INVALID_PARAMETER; + } + + status = ib_get_mad( g_pool_key, MAD_BLOCK_SIZE, &p_mad ); + if( status != IB_SUCCESS ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("ib_get_mad returned %s.\n", ib_get_err_str( status )) ); + return status; + } + + p_mad_buf = p_mad->p_mad_buf; + p_grh = p_mad->p_grh; + + if( !DeviceIoControl( g_al_device, UAL_CEP_POLL, &cid, + sizeof(cid), &ioctl, sizeof(ioctl), &bytes_ret, NULL ) || + bytes_ret != sizeof(ioctl) ) + { + ib_put_mad( p_mad ); + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("UAL_CEP_POLL IOCTL failed with %d.\n", GetLastError()) ); + return IB_ERROR; + } + + if( ioctl.status == IB_SUCCESS ) + { + if( ioctl.new_cid != AL_INVALID_CID ) + { + /* Need to create a new CEP for user-mode. */ + status = __create_ucep( p_cep->h_al, ioctl.new_cid, + p_cep->pfn_cb, NULL, NULL, NULL ); + if( status != IB_SUCCESS ) + { + DeviceIoControl( g_al_device, UAL_DESTROY_CEP, + &ioctl.new_cid, sizeof(ioctl.new_cid), + NULL, 0, &bytes_ret, NULL ); + goto err; + } + } + + /* Copy the MAD payload as it's all that's used. */ + *p_mad = ioctl.element; + p_mad->p_grh = p_grh; + if( p_mad->grh_valid ) + cl_memcpy( p_mad->p_grh, &ioctl.grh, sizeof(ib_grh_t) ); + p_mad->p_mad_buf = p_mad_buf; + + cl_memcpy( p_mad->p_mad_buf, ioctl.mad_buf, MAD_BLOCK_SIZE ); + + *p_context = p_cep->destroy_context; + *p_new_cid = ioctl.new_cid; + *pp_mad = p_mad; + } + else + { +err: + ib_put_mad( p_mad ); + } + + AL_EXIT( AL_DBG_CM ); + return ioctl.status; +} + + +/* Callback to process CM events */ +void +cm_cb( + IN DWORD error_code, + IN DWORD ret_bytes, + IN LPOVERLAPPED p_ov ) +{ + ucep_t *p_cep; + BOOL ret; + + AL_ENTER( AL_DBG_CM ); + + /* The UAL_CEP_GET_EVENT IOCTL does not have any output data. */ + UNUSED_PARAM( ret_bytes ); + + p_cep = PARENT_STRUCT( p_ov, ucep_t, ov ); + + if( !error_code ) + { + p_cep->pfn_cb( p_cep->h_al, p_cep->cid ); + + /* Synchronize with destruction. */ + cl_spinlock_acquire( &gp_cep_mgr->obj.lock ); + ret = DeviceIoControl( gp_cep_mgr->h_file, UAL_CEP_GET_EVENT, + &p_cep->cid, sizeof(p_cep->cid), NULL, 0, + NULL, &p_cep->ov ); + cl_spinlock_release( &gp_cep_mgr->obj.lock ); + if( !ret && GetLastError() == ERROR_IO_PENDING ) + { + AL_EXIT( AL_DBG_CM ); + return; + } + else if( GetLastError() != ERROR_INVALID_PARAMETER ) + { + /* We can get ERROR_INVALID_PARAMETER if the CEP was destroyed. */ + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("DeviceIoControl for CEP callback request returned %d.\n", + GetLastError()) ); + } + } + else + { + AL_PRINT(TRACE_LEVEL_WARNING ,AL_DBG_CM , + ("UAL_CEP_GET_EVENT IOCTL returned %d.\n", error_code) ); + } + + /* + * We failed to issue the next request or the previous request was + * cancelled. Release the reference held by the previous IOCTL and exit. + */ + if( !cl_atomic_dec( &p_cep->ref_cnt ) ) + __destroy_ucep( p_cep ); + + AL_EXIT( AL_DBG_CM ); +} diff --git a/branches/WOF2-3/core/al/user/ual_cq.c b/branches/WOF2-3/core/al/user/ual_cq.c new file mode 100644 index 00000000..5e7116dc --- /dev/null +++ b/branches/WOF2-3/core/al/user/ual_cq.c @@ -0,0 +1,550 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include "ual_support.h" +#include "al.h" +#include "al_ca.h" +#include "al_ci_ca.h" +#include "al_cq.h" + +#include "al_debug.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "ual_cq.tmh" +#endif + + +ib_api_status_t +ual_create_cq( + IN al_ci_ca_t* const p_ci_ca, + IN ib_cq_create_t* const p_cq_create, + IN OUT ib_cq_handle_t h_cq ) +{ + ual_create_cq_ioctl_t cq_ioctl; + uintn_t bytes_ret; + cl_status_t cl_status; + ib_api_status_t status; + uvp_interface_t uvp_intf = p_ci_ca->verbs.user_verbs; + + AL_ENTER( AL_DBG_CQ ); + + /* Clear the IOCTL buffer */ + cl_memclr( &cq_ioctl, sizeof(cq_ioctl) ); + + /* Pre call to the UVP library */ + if( p_ci_ca->h_ci_ca && uvp_intf.pre_create_cq ) + { + status = uvp_intf.pre_create_cq( p_ci_ca->h_ci_ca, + &p_cq_create->size, &cq_ioctl.in.umv_buf, &h_cq->h_ci_cq ); + if( status != IB_SUCCESS ) + { + AL_EXIT( AL_DBG_CQ ); + return status; + } + } + + cq_ioctl.in.h_ca = p_ci_ca->obj.hdl; + cq_ioctl.in.size = p_cq_create->size; + cq_ioctl.in.h_wait_obj = HandleToHandle64( p_cq_create->h_wait_obj ); + cq_ioctl.in.context = (ULONG_PTR)h_cq; + cq_ioctl.in.ev_notify = (h_cq->pfn_event_cb != NULL) ? TRUE : FALSE; + + cl_status = do_al_dev_ioctl( UAL_CREATE_CQ, + &cq_ioctl.in, sizeof(cq_ioctl.in), &cq_ioctl.out, sizeof(cq_ioctl.out), + &bytes_ret ); + + if( cl_status != CL_SUCCESS || bytes_ret != sizeof(cq_ioctl.out) ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("UAL_CREATE_CQ IOCTL returned %s.\n", CL_STATUS_MSG(cl_status)) ); + status = IB_ERROR; + } + else + { + status = cq_ioctl.out.status; + } + + h_cq->obj.hdl = cq_ioctl.out.h_cq; + + /* Post uvp call */ + if( p_ci_ca->h_ci_ca && uvp_intf.post_create_cq ) + { + uvp_intf.post_create_cq( p_ci_ca->h_ci_ca, + status, cq_ioctl.out.size, &h_cq->h_ci_cq, + &cq_ioctl.out.umv_buf ); + + if( uvp_intf.peek_cq ) + { + h_cq->pfn_peek = uvp_intf.peek_cq; + h_cq->h_peek_cq = h_cq->h_ci_cq; + } + else + { + h_cq->pfn_peek = ual_peek_cq; + h_cq->h_peek_cq = h_cq; + } + + if( uvp_intf.poll_cq ) + { + h_cq->pfn_poll = uvp_intf.poll_cq; + h_cq->h_poll_cq = h_cq->h_ci_cq; + } + else + { + h_cq->pfn_poll = ual_poll_cq; + h_cq->h_poll_cq = h_cq; + } + + if( uvp_intf.rearm_cq ) + { + h_cq->pfn_rearm = uvp_intf.rearm_cq; + h_cq->h_rearm_cq = h_cq->h_ci_cq; + } + else + { + h_cq->pfn_rearm = ual_rearm_cq; + h_cq->h_rearm_cq = h_cq; + } + + if( uvp_intf.rearm_n_cq ) + { + h_cq->pfn_rearm_n = uvp_intf.rearm_n_cq; + h_cq->h_rearm_n_cq = h_cq->h_ci_cq; + } + else + { + h_cq->pfn_rearm_n = ual_rearm_n_cq; + h_cq->h_rearm_n_cq = h_cq; + } + } + else + { + h_cq->pfn_peek = ual_peek_cq; + h_cq->pfn_poll = ual_poll_cq; + h_cq->pfn_rearm = ual_rearm_cq; + h_cq->pfn_rearm_n = ual_rearm_n_cq; + h_cq->h_peek_cq = h_cq; + h_cq->h_poll_cq = h_cq; + h_cq->h_rearm_cq = h_cq; + h_cq->h_rearm_n_cq = h_cq; + } + + AL_EXIT( AL_DBG_CQ ); + return status; +} + + +ib_api_status_t +ual_destroy_cq( + IN ib_cq_handle_t h_cq ) +{ + ual_destroy_cq_ioctl_t cq_ioctl; + uintn_t bytes_ret; + cl_status_t cl_status; + ib_api_status_t status; + uvp_interface_t uvp_intf = h_cq->obj.p_ci_ca->verbs.user_verbs; + + AL_ENTER( AL_DBG_CQ ); + + /* Clear the IOCTL buffer */ + cl_memclr( &cq_ioctl, sizeof(cq_ioctl) ); + + if( h_cq->h_ci_cq && uvp_intf.pre_destroy_cq ) + { + /* Pre call to the UVP library */ + status = uvp_intf.pre_destroy_cq( h_cq->h_ci_cq ); + if( status != IB_SUCCESS ) + { + AL_EXIT( AL_DBG_CQ ); + return status; + } + } + + cq_ioctl.in.h_cq = h_cq->obj.hdl; + + cl_status = do_al_dev_ioctl( UAL_DESTROY_CQ, + &cq_ioctl.in, sizeof(cq_ioctl.in), &cq_ioctl.out, sizeof(cq_ioctl.out), + &bytes_ret ); + + if( cl_status != CL_SUCCESS || bytes_ret != sizeof(cq_ioctl.out ) ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("UAL_DESTROY_CQ IOCTL returned %s.\n", + CL_STATUS_MSG(cl_status)) ); + status = IB_ERROR; + } + else + { + status = cq_ioctl.out.status; + } + + if( h_cq->h_ci_cq && uvp_intf.post_destroy_cq ) + uvp_intf.post_destroy_cq( h_cq->h_ci_cq, status ); + + AL_EXIT( AL_DBG_CQ ); + return status; +} + + +ib_api_status_t +ual_modify_cq( + IN ib_cq_handle_t h_cq, + IN OUT uint32_t* p_size ) +{ + ual_modify_cq_ioctl_t cq_ioctl; + uintn_t bytes_ret; + cl_status_t cl_status; + ib_api_status_t status; + uvp_interface_t uvp_intf = h_cq->obj.p_ci_ca->verbs.user_verbs; + + AL_ENTER( AL_DBG_CQ ); + + /* Clear the IOCTL buffer */ + cl_memclr( &cq_ioctl, sizeof(cq_ioctl) ); + + /* Call the uvp pre call if the vendor library provided a valid ca handle */ + if( h_cq->h_ci_cq && uvp_intf.pre_resize_cq ) + { + /* Pre call to the UVP library */ + status = uvp_intf.pre_resize_cq( h_cq->h_ci_cq, + p_size, &cq_ioctl.in.umv_buf ); + if( status != IB_SUCCESS ) + { + AL_EXIT( AL_DBG_CQ ); + return status; + } + } + + cq_ioctl.in.h_cq = h_cq->obj.hdl; + cq_ioctl.in.size = *p_size; + + cl_status = do_al_dev_ioctl( UAL_MODIFY_CQ, + &cq_ioctl.in, sizeof(cq_ioctl.in), &cq_ioctl.out, sizeof(cq_ioctl.out), + &bytes_ret ); + + if( cl_status != CL_SUCCESS || bytes_ret != sizeof(cq_ioctl.out) ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("UAL_MODIFY_CQ IOCTL returned %s.\n", + CL_STATUS_MSG(cl_status)) ); + status = IB_ERROR; + } + else + { + status = cq_ioctl.out.status; + if( status == IB_SUCCESS ) + *p_size = cq_ioctl.out.size; + } + + /* Post uvp call */ + if( h_cq->h_ci_cq && uvp_intf.post_resize_cq ) + { + uvp_intf.post_resize_cq( h_cq->h_ci_cq, + status, cq_ioctl.out.size, &cq_ioctl.out.umv_buf ); + } + + AL_EXIT( AL_DBG_CQ ); + return status; +} + + +ib_api_status_t +ual_query_cq( + IN ib_cq_handle_t h_cq, + OUT uint32_t* p_size ) +{ + ual_query_cq_ioctl_t cq_ioctl; + uintn_t bytes_ret; + cl_status_t cl_status; + ib_api_status_t status; + uvp_interface_t uvp_intf = h_cq->obj.p_ci_ca->verbs.user_verbs; + + AL_ENTER( AL_DBG_CQ ); + + /* Clear the IOCTL buffer */ + cl_memclr( &cq_ioctl, sizeof(cq_ioctl) ); + + /* Call the uvp pre call if the vendor library provided a valid cq handle */ + if( h_cq->h_ci_cq && uvp_intf.pre_query_cq ) + { + /* Pre call to the UVP library */ + status = uvp_intf.pre_query_cq( + h_cq->h_ci_cq, p_size, &cq_ioctl.in.umv_buf ); + if( status == IB_VERBS_PROCESSING_DONE ) + { + AL_EXIT( AL_DBG_CQ ); + return IB_SUCCESS; + } + if( status != IB_SUCCESS ) + { + AL_EXIT( AL_DBG_CQ ); + return status; + } + } + + cq_ioctl.in.h_cq = h_cq->obj.hdl; + + cl_status = do_al_dev_ioctl( UAL_QUERY_CQ, + &cq_ioctl.in, sizeof(cq_ioctl.in), &cq_ioctl.out, sizeof(cq_ioctl.out), + &bytes_ret ); + + if( cl_status != CL_SUCCESS || bytes_ret != sizeof(cq_ioctl.out) ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("UAL_QUERY_CQ IOCTL returned %s.\n", + CL_STATUS_MSG(cl_status)) ); + status = IB_ERROR; + } + else + { + status = cq_ioctl.out.status; + if( status == IB_SUCCESS ) + *p_size = cq_ioctl.out.size; + } + + /* Post uvp call */ + if( h_cq->h_ci_cq && uvp_intf.post_query_cq ) + { + uvp_intf.post_query_cq( h_cq->h_ci_cq, + status, cq_ioctl.out.size, &cq_ioctl.out.umv_buf ); + } + + AL_EXIT( AL_DBG_CQ ); + return status; +} + + +ib_api_status_t +ual_peek_cq( + IN const ib_cq_handle_t h_cq, + OUT uint32_t* const p_n_cqes ) +{ + ual_peek_cq_ioctl_t cq_ioctl; + cl_status_t cl_status; + uintn_t bytes_ret; + + AL_ENTER( AL_DBG_CQ ); + + /* Clear the IOCTL buffer */ + cl_memclr(&cq_ioctl, sizeof(cq_ioctl)); + + cq_ioctl.in.h_cq = h_cq->obj.hdl; + + cl_status = do_al_dev_ioctl( UAL_PEEK_CQ, + &cq_ioctl.in, sizeof(cq_ioctl.in), &cq_ioctl.out, sizeof(cq_ioctl.out), + &bytes_ret ); + + if( cl_status != CL_SUCCESS || bytes_ret != sizeof(cq_ioctl.out) ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("UAL_PEEK_CQ IOCTL returned %s.\n", + CL_STATUS_MSG(cl_status)) ); + return IB_ERROR; + } + + if( cq_ioctl.out.status == IB_SUCCESS ) + *p_n_cqes = cq_ioctl.out.n_cqes; + + AL_EXIT( AL_DBG_CQ ); + return cq_ioctl.out.status; +} + + +ib_api_status_t +ual_poll_cq( + IN const ib_cq_handle_t h_cq, + IN OUT ib_wc_t** const pp_free_wclist, + OUT ib_wc_t** const pp_done_wclist ) +{ + uintn_t bytes_ret; + ual_poll_cq_ioctl_t *p_cq_ioctl; + size_t ioctl_buf_sz; + uint32_t num_wc; + ib_wc_t* p_wc_start; + ib_wc_t* p_next_wc; + cl_status_t cl_status; + ib_api_status_t status; + + AL_ENTER( AL_DBG_CQ ); + + /* + * Since the work request is a link list and we need to pass this + * to the kernel as a array of work requests. So first walk through + * the list and find out how much memory we need to allocate. + */ + p_next_wc = *pp_free_wclist; + num_wc = 0; + while( p_next_wc ) + { + num_wc++; + + /* Check for overflow */ + if( !num_wc ) + break; + + p_next_wc = p_next_wc->p_next; + } + if( !num_wc ) + { + AL_EXIT( AL_DBG_CQ ); + return IB_INVALID_PARAMETER; + } + + ioctl_buf_sz = sizeof(p_cq_ioctl->out); + ioctl_buf_sz += sizeof(ib_wc_t) * (num_wc - 1); + + p_cq_ioctl = (ual_poll_cq_ioctl_t*)cl_zalloc( ioctl_buf_sz ); + + /* Now populate the ioctl buffer and send down the ioctl */ + p_cq_ioctl->in.h_cq = h_cq->obj.hdl; + p_cq_ioctl->in.num_wc = num_wc; + + cl_status = do_al_dev_ioctl( UAL_POLL_CQ, + p_cq_ioctl, sizeof(p_cq_ioctl->in), p_cq_ioctl, ioctl_buf_sz, + &bytes_ret ); + + /* Make sure we got the right amount of data returned. */ + if( cl_status != CL_SUCCESS || + bytes_ret < (sizeof(p_cq_ioctl->out) - sizeof(ib_wc_t)) || + (cl_status == CL_SUCCESS && bytes_ret < (sizeof(p_cq_ioctl->out) - + sizeof(ib_wc_t) + (sizeof(ib_wc_t) * p_cq_ioctl->out.num_wc))) ) + { + cl_free( p_cq_ioctl ); + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("UAL_POLL_CQ IOCTL returned %s.\n", + CL_STATUS_MSG(cl_status)) ); + return IB_ERROR; + } + + status = p_cq_ioctl->out.status; + if( status == IB_SUCCESS ) + { + CL_ASSERT( p_cq_ioctl->out.num_wc ); + /* Fix up the free and done lists. */ + p_next_wc = *pp_free_wclist; + num_wc = 0; + p_wc_start = p_next_wc; + do + { + p_wc_start = p_next_wc; + CL_ASSERT( p_wc_start ); + /* Save next pointer. */ + p_next_wc = p_wc_start->p_next; + /* Copy WC contents back to user. */ + cl_memcpy( + p_wc_start, &p_cq_ioctl->out.wc[num_wc], sizeof(ib_wc_t) ); + /* Restore next pointer. */ + p_wc_start->p_next = p_next_wc; + } while( ++num_wc < p_cq_ioctl->out.num_wc ); + + p_wc_start->p_next = NULL; + *pp_done_wclist = *pp_free_wclist; + *pp_free_wclist = p_next_wc; + } + + cl_free( p_cq_ioctl ); + + AL_EXIT( AL_DBG_CQ ); + return status; +} + + +ib_api_status_t +ual_rearm_cq( + IN const ib_cq_handle_t h_cq, + IN const boolean_t solicited ) +{ + ual_rearm_cq_ioctl_t cq_ioctl; + cl_status_t cl_status; + uintn_t bytes_ret; + + AL_ENTER( AL_DBG_CQ ); + + /* Clear the IOCTL buffer */ + cl_memclr(&cq_ioctl, sizeof(cq_ioctl)); + + cq_ioctl.in.h_cq = h_cq->obj.hdl; + cq_ioctl.in.solicited = solicited; + + cl_status = do_al_dev_ioctl( UAL_REARM_CQ, + &cq_ioctl.in, sizeof(cq_ioctl.in), &cq_ioctl.out, sizeof(cq_ioctl.out), + &bytes_ret ); + + if( cl_status != CL_SUCCESS || bytes_ret != sizeof(cq_ioctl.out) ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("UAL_REARM_CQ IOCTL returned %s.\n", + CL_STATUS_MSG(cl_status)) ); + return IB_ERROR; + } + + AL_EXIT( AL_DBG_CQ ); + return cq_ioctl.out.status; +} + + +ib_api_status_t +ual_rearm_n_cq( + IN const ib_cq_handle_t h_cq, + IN const uint32_t n_cqes ) +{ + ual_rearm_n_cq_ioctl_t cq_ioctl; + cl_status_t cl_status; + uintn_t bytes_ret; + + AL_ENTER( AL_DBG_CQ ); + + /* Clear the IOCTL buffer */ + cl_memclr(&cq_ioctl, sizeof(cq_ioctl)); + + cq_ioctl.in.h_cq = h_cq->obj.hdl; + cq_ioctl.in.n_cqes = n_cqes; + + cl_status = do_al_dev_ioctl( UAL_REARM_N_CQ, + &cq_ioctl.in, sizeof(cq_ioctl.in), &cq_ioctl.out, sizeof(cq_ioctl.out), + &bytes_ret ); + + if( cl_status != CL_SUCCESS || bytes_ret != sizeof(cq_ioctl.out) ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("UAL_REARM_N_CQ IOCTL returned %s.\n", + CL_STATUS_MSG(cl_status)) ); + return IB_ERROR; + } + + AL_EXIT( AL_DBG_CQ ); + return cq_ioctl.out.status; +} diff --git a/branches/WOF2-3/core/al/user/ual_mad.c b/branches/WOF2-3/core/al/user/ual_mad.c new file mode 100644 index 00000000..e175ee51 --- /dev/null +++ b/branches/WOF2-3/core/al/user/ual_mad.c @@ -0,0 +1,531 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include "al.h" +#include "al_av.h" +#include "al_common.h" +#include "al_debug.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "ual_mad.tmh" +#endif + +#include "al_dev.h" +#include "al_qp.h" +#include "al_pd.h" +#include "ual_mad.h" +#include "ual_support.h" + + +static void +__destroying_ual_mad_svc( + IN struct _al_obj *p_obj ) +{ + ib_mad_svc_handle_t h_mad_svc; + + AL_ENTER(AL_DBG_MAD_SVC); + CL_ASSERT( p_obj ); + h_mad_svc = PARENT_STRUCT( p_obj, al_mad_svc_t, obj ); + + /* Deregister the MAD service. */ + ual_dereg_mad_svc( h_mad_svc ); + + AL_EXIT(AL_DBG_MAD_SVC); +} + + +ib_api_status_t +ual_reg_mad_svc( + IN const ib_qp_handle_t h_qp, + IN const ib_mad_svc_t* const p_mad_svc, + OUT ib_mad_svc_handle_t* const ph_mad_svc ) +{ + ib_api_status_t status; + cl_status_t cl_status; + uintn_t bytes_ret; + ib_mad_svc_handle_t h_mad_svc; + al_qp_alias_t *p_qp_alias; + ual_reg_mad_svc_ioctl_t ioctl_buf; + + AL_ENTER( AL_DBG_MAD ); + + CL_ASSERT( h_qp && p_mad_svc && ph_mad_svc ); + + h_mad_svc = cl_zalloc( sizeof( al_mad_svc_t) ); + if( !h_mad_svc ) + { + AL_EXIT( AL_DBG_MAD ); + return IB_INSUFFICIENT_MEMORY; + } + + /* Construct the MAD service. */ + construct_al_obj( &h_mad_svc->obj, AL_OBJ_TYPE_H_MAD_SVC ); + + p_qp_alias = PARENT_STRUCT( h_qp, al_qp_alias_t, qp ); + h_mad_svc->obj.context = p_mad_svc->mad_svc_context; + h_mad_svc->pfn_user_recv_cb = p_mad_svc->pfn_mad_recv_cb; + h_mad_svc->pfn_user_send_cb = p_mad_svc->pfn_mad_send_cb; + + /* Initialize the MAD service. */ + status = init_al_obj( &h_mad_svc->obj, p_mad_svc->mad_svc_context, + TRUE, NULL, __destroying_ual_mad_svc, free_mad_svc ); + if( status != IB_SUCCESS ) + { + cl_free( h_mad_svc ); + AL_EXIT( AL_DBG_MAD ); + return status; + } + attach_al_obj( &h_qp->obj, &h_mad_svc->obj ); + + cl_memclr( &ioctl_buf, sizeof(ioctl_buf) ); + + ioctl_buf.in.h_qp = h_qp->obj.hdl; + ioctl_buf.in.mad_svc = *p_mad_svc; + + /* Replace the context in mad_svc */ + ioctl_buf.in.mad_svc.mad_svc_context = h_mad_svc; + + cl_status = do_al_dev_ioctl( UAL_REG_MAD_SVC, + &ioctl_buf.in, sizeof(ioctl_buf.in), + &ioctl_buf.out, sizeof(ioctl_buf.out), + &bytes_ret ); + + if( cl_status != CL_SUCCESS || bytes_ret != sizeof(ioctl_buf.out) ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("UAL_REG_MAD_SVC IOCTL returned %s.\n", + CL_STATUS_MSG(cl_status)) ); + status = IB_ERROR; + } + else + { + status = ioctl_buf.out.status; + if(status == IB_SUCCESS) + h_mad_svc->obj.hdl = ioctl_buf.out.h_mad_svc; + + } + + if( status != IB_SUCCESS ) + { + h_mad_svc->obj.pfn_destroy( &h_mad_svc->obj, NULL ); + AL_EXIT( AL_DBG_MAD ); + return status; + } + + *ph_mad_svc = h_mad_svc; + + AL_EXIT( AL_DBG_MAD ); + return status; +} + + + +ib_api_status_t +ual_dereg_mad_svc( + IN const ib_mad_svc_handle_t h_mad_svc ) +{ + ual_dereg_mad_svc_ioctl_t ioctl_buf; + uintn_t bytes_ret; + cl_status_t cl_status; + ib_api_status_t status; + + AL_ENTER(AL_DBG_MAD); + + cl_memclr( &ioctl_buf, sizeof(ioctl_buf) ); + + ioctl_buf.in.h_mad_svc = h_mad_svc->obj.hdl; + + cl_status = do_al_dev_ioctl( UAL_DEREG_MAD_SVC, &ioctl_buf, + sizeof(ioctl_buf.in), &ioctl_buf, sizeof(ioctl_buf.out), &bytes_ret ); + if( cl_status != CL_SUCCESS || bytes_ret != sizeof(ioctl_buf.out) ) + status = IB_ERROR; + else + status = ioctl_buf.out.status; + + if( status != IB_SUCCESS ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("Error deregistering MAD svc: %s\n", ib_get_err_str( status ) ) ); + } + + AL_EXIT(AL_DBG_MAD); + return status; +} + + + +ib_api_status_t +ual_send_one_mad( + IN const ib_mad_svc_handle_t h_mad_svc, + IN ib_mad_element_t* const p_mad_element ) +{ + ual_send_mad_ioctl_t ioctl_buf; + uintn_t bytes_ret; + cl_status_t cl_status; + ib_api_status_t status; + al_mad_element_t* p_al_element; + + AL_ENTER( AL_DBG_MAD ); + + CL_ASSERT( p_mad_element ); + + p_al_element = PARENT_STRUCT( + p_mad_element, al_mad_element_t, element ); + + p_mad_element->status = IB_WCS_UNKNOWN; + + ioctl_buf.in.h_mad_svc = h_mad_svc->obj.hdl; + + /* Update the pool key to the proxy's handle. */ + ioctl_buf.in.pool_key = p_al_element->pool_key->obj.hdl; + + /* + * Convert user-mode AV handles to kernel AV handles. Note that + * the completion handler will convert the handles back before + * returning the MAD to the user. + */ + if( p_mad_element->h_av ) + ioctl_buf.in.h_av = p_mad_element->h_av->obj.hdl; + else + ioctl_buf.in.h_av = AL_INVALID_HANDLE; + + ioctl_buf.in.p_mad_element = (ULONG_PTR)p_mad_element; + ioctl_buf.in.size = p_mad_element->size; + ioctl_buf.in.ph_proxy = (ULONG_PTR)&p_al_element->h_proxy_element; + + cl_status = do_al_dev_ioctl( UAL_MAD_SEND, + &ioctl_buf.in, sizeof(ioctl_buf.in), + &ioctl_buf.out, sizeof(ioctl_buf.out), + &bytes_ret ); + + if( cl_status != CL_SUCCESS || bytes_ret != sizeof(ioctl_buf.out) ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("UAL_MAD_SEND IOCTL returned %s.\n", + CL_STATUS_MSG(cl_status)) ); + status = IB_ERROR; + } + else + { + status = ioctl_buf.out.status; + } + + AL_EXIT( AL_DBG_MAD ); + return status; +} + + + +ib_api_status_t +ual_spl_qp_mad_send( + IN const ib_mad_svc_handle_t h_mad_svc, + IN ib_mad_element_t* const p_mad_element_list, + OUT ib_mad_element_t **pp_mad_failure OPTIONAL ) +{ + ib_api_status_t status; + ib_mad_element_t* p_next_element; + + AL_ENTER( AL_DBG_MAD ); + + /* Count up the mads in the list. */ + p_next_element = p_mad_element_list; + do + { + status = ual_send_one_mad( h_mad_svc, p_next_element ); + if( status != IB_SUCCESS ) + break; + + p_next_element = p_next_element->p_next; + + } while( p_next_element ); + + if( status != IB_SUCCESS && pp_mad_failure ) + *pp_mad_failure = p_next_element; + + AL_EXIT( AL_DBG_MAD ); + return status; +} + + + +ib_api_status_t +ual_spl_qp_cancel_mad( + IN const ib_mad_svc_handle_t h_mad_svc, + IN ib_mad_element_t* const p_mad_element ) +{ + ual_cancel_mad_ioctl_t ioctl_buf; + uintn_t bytes_ret; + cl_status_t cl_status; + al_mad_element_t* p_al_mad; + + AL_ENTER( AL_DBG_MAD ); + + cl_memclr( &ioctl_buf, sizeof(ioctl_buf) ); + + ioctl_buf.in.h_mad_svc = h_mad_svc->obj.hdl; + /* + * Pass the corresponding kernel mode mad_element as KAL knows + * only about kernel mads. This gets set when we send the mad. + */ + p_al_mad = PARENT_STRUCT(p_mad_element, al_mad_element_t, element); + ioctl_buf.in.h_proxy_element = p_al_mad->h_proxy_element; + + cl_status = do_al_dev_ioctl( UAL_CANCEL_MAD, + &ioctl_buf.in, sizeof(ioctl_buf.in), + &ioctl_buf.out, sizeof(ioctl_buf.out), + &bytes_ret ); + + if( cl_status != CL_SUCCESS || bytes_ret != sizeof(ioctl_buf.out) ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("UAL_CANCEL_MAD IOCTL returned %s.\n", + CL_STATUS_MSG(cl_status)) ); + return IB_ERROR; + } + + AL_EXIT( AL_DBG_MAD ); + return ioctl_buf.out.status; +} + + +ib_api_status_t +ual_create_reg_mad_pool( + IN const ib_pool_handle_t h_pool, + IN const ib_pd_handle_t h_pd, + IN OUT ib_pool_key_t p_pool_key ) +{ + ual_reg_mad_pool_ioctl_t ioctl_buf; + uintn_t bytes_ret; + cl_status_t cl_status; + ib_api_status_t status = IB_ERROR; + + AL_ENTER( AL_DBG_MAD ); + + /*TODO: Can h_pool be removed as a param? */ + UNUSED_PARAM( h_pool ); + + cl_memclr( &ioctl_buf, sizeof(ioctl_buf) ); + + ioctl_buf.in.h_pd = h_pd->obj.hdl; + + cl_status = do_al_dev_ioctl( UAL_REG_MAD_POOL, + &ioctl_buf.in, sizeof(ioctl_buf.in), + &ioctl_buf.out, sizeof(ioctl_buf.out), + &bytes_ret ); + + if( cl_status != CL_SUCCESS || bytes_ret != sizeof(ioctl_buf.out) ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("UAL_REG_MAD_POOL IOCTL returned %s.\n", + CL_STATUS_MSG(cl_status)) ); + status = IB_ERROR; + } + else + { + status = ioctl_buf.out.status; + if(status == IB_SUCCESS ) + p_pool_key->obj.hdl = ioctl_buf.out.pool_key; + } + + if( ioctl_buf.out.status == IB_SUCCESS ) + p_pool_key->obj.hdl = ioctl_buf.out.pool_key; + + AL_EXIT( AL_DBG_MAD ); + return status; +} + + +void +ual_dereg_destroy_mad_pool( + IN const ib_pool_key_t pool_key ) +{ + ual_dereg_mad_pool_ioctl_t ioctl_buf; + uintn_t bytes_ret; + cl_status_t cl_status; + + AL_ENTER( AL_DBG_MAD ); + + cl_memclr( &ioctl_buf, sizeof(ioctl_buf) ); + + ioctl_buf.in.pool_key = pool_key->obj.hdl; + + cl_status = do_al_dev_ioctl( UAL_DEREG_MAD_POOL, + &ioctl_buf.in, sizeof(ioctl_buf.in), + &ioctl_buf.out, sizeof(ioctl_buf.out), + &bytes_ret ); + + if( cl_status != CL_SUCCESS || bytes_ret != sizeof(ioctl_buf.out) ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("UAL_DEREG_MAD_POOL IOCTL returned %s.\n", + CL_STATUS_MSG(cl_status))); + } + else if( ioctl_buf.out.status != IB_SUCCESS ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("Error deregistering MAD pool: %s\n", + ib_get_err_str( ioctl_buf.out.status )) ); + } + AL_EXIT( AL_DBG_MAD ); +} + + +/* + * We've receive a MAD. We need to get a user-mode MAD of the + * correct size, then send it down to retrieve the received MAD + * from the kernel. + */ +ib_api_status_t +ual_get_recv_mad( + IN ib_pool_key_t p_pool_key, + IN const uint64_t h_mad, + IN const size_t buf_size, + OUT ib_mad_element_t** const pp_mad_element ) +{ + ual_mad_recv_ioctl_t ioctl_buf; + uintn_t bytes_ret; + cl_status_t cl_status; + ib_api_status_t status; + ib_mad_element_t *p_mad = NULL; + ib_mad_t *p_mad_buf = NULL; + ib_grh_t *p_grh = NULL; + + AL_ENTER( AL_DBG_MAD ); + + cl_memclr( &ioctl_buf, sizeof(ioctl_buf) ); + + /* + * Get a MAD large enough to receive the MAD. If we can't get a + * MAD, we still perform the IOCTL so that the kernel will return + * the MAD to its pool, resulting in a dropped MAD. + */ + status = ib_get_mad( p_pool_key, buf_size, &p_mad ); + + /* + * Note that we issue the IOCTL regardless of failure of ib_get_mad. + * This is done in order to release the kernel-mode MAD. + */ + ioctl_buf.in.p_user_mad = (ULONG_PTR)p_mad; + + if( p_mad ) + { + /* Save off the pointers since the proxy overwrites the element. */ + p_mad_buf = p_mad->p_mad_buf; + p_grh = p_mad->p_grh; + + ioctl_buf.in.p_mad_buf = (ULONG_PTR)p_mad_buf; + ioctl_buf.in.p_grh = (ULONG_PTR)p_grh; + } + ioctl_buf.in.h_mad = h_mad; + + cl_status = do_al_dev_ioctl( UAL_MAD_RECV_COMP, + &ioctl_buf.in, sizeof(ioctl_buf.in), + &ioctl_buf.out, sizeof(ioctl_buf.out), + &bytes_ret ); + if( cl_status != CL_SUCCESS || bytes_ret != sizeof(ioctl_buf.out) ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("UAL_MAD_RECV_COMP IOCTL returned %s.\n", + CL_STATUS_MSG(cl_status)) ); + status = IB_ERROR; + } + else + { + status = ioctl_buf.out.status; + } + + if( p_mad ) + { + /* We need to reset MAD data pointers. */ + p_mad->p_mad_buf = p_mad_buf; + p_mad->p_grh = p_grh; + if( status != IB_SUCCESS ) + { + ib_put_mad( p_mad ); + p_mad = NULL; + } + } + + *pp_mad_element = p_mad; + + AL_EXIT( AL_DBG_MAD ); + return status; +} + + +ib_api_status_t +ual_local_mad( + IN const ib_ca_handle_t h_ca, + IN const uint8_t port_num, + IN ib_mad_t* const p_mad_in, + IN ib_mad_t* p_mad_out ) +{ + ual_local_mad_ioctl_t local_mad_ioctl; + uintn_t bytes_ret; + cl_status_t cl_status = CL_SUCCESS; + ib_api_status_t status = IB_SUCCESS; + + AL_ENTER( AL_DBG_CA ); + + local_mad_ioctl.in.h_ca = h_ca->obj.p_ci_ca->obj.hdl; + local_mad_ioctl.in.port_num = port_num; + cl_memcpy( local_mad_ioctl.in.mad_in, p_mad_in, + sizeof(local_mad_ioctl.in.mad_in) ); + + cl_status = do_al_dev_ioctl( UAL_LOCAL_MAD, + &local_mad_ioctl.in, sizeof(local_mad_ioctl.in), + &local_mad_ioctl.out, sizeof(local_mad_ioctl.out), + &bytes_ret ); + + if( cl_status != CL_SUCCESS || bytes_ret != sizeof(local_mad_ioctl.out) ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("UAL_LOCAL_MAD IOCTL returned %s\n", CL_STATUS_MSG(cl_status)) ); + status = IB_ERROR; + } + else + { + status = local_mad_ioctl.out.status; + cl_memcpy( p_mad_out, local_mad_ioctl.out.mad_out, + sizeof(local_mad_ioctl.out.mad_out) ); + } + + AL_EXIT( AL_DBG_CA ); + return status; +} + + diff --git a/branches/WOF2-3/core/al/user/ual_mad.h b/branches/WOF2-3/core/al/user/ual_mad.h new file mode 100644 index 00000000..ea090e13 --- /dev/null +++ b/branches/WOF2-3/core/al/user/ual_mad.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#if !defined(__IB_UAL_MAD_H__) +#define __IB_UAL_MAD_H__ + +#include +#include "al_mad_pool.h" + + +/* + * Create a pool key for the internal mad pool. This pool key will never + * be registered on anything. + */ +ib_api_status_t +ual_reg_global_mad_pool( + IN const ib_pool_handle_t h_pool, + OUT ib_pool_key_t* const pp_pool_key ); + +ib_api_status_t +ual_reg_mad_svc( + IN const ib_qp_handle_t h_qp, + IN const ib_mad_svc_t* const p_mad_svc, + OUT ib_mad_svc_handle_t* const ph_mad_svc ); + +ib_api_status_t +ual_dereg_mad_svc( + IN const ib_mad_svc_handle_t h_mad_svc ); + + +ib_api_status_t +ual_spl_qp_mad_send( + IN const ib_mad_svc_handle_t h_mad_svc, + IN ib_mad_element_t* const p_mad_element_list, + OUT ib_mad_element_t **pp_mad_failure OPTIONAL ); + +ib_api_status_t +ual_spl_qp_cancel_mad( + IN const ib_mad_svc_handle_t h_mad_svc, + IN ib_mad_element_t* const p_mad_element ); + +void +ual_dereg_destroy_mad_pool( + IN const ib_pool_key_t pool_key ); + +ib_api_status_t +ual_create_reg_mad_pool( + IN const ib_pool_handle_t h_pool, + IN const ib_pd_handle_t h_pd, + IN ib_pool_key_t p_pool_key ); + + +ib_api_status_t +ual_get_recv_mad( + IN ib_pool_key_t p_pool_key, + IN const uint64_t h_mad, + IN const size_t buf_size, + OUT ib_mad_element_t** const pp_mad_element ); + +ib_api_status_t +ual_local_mad( +IN const ib_ca_handle_t h_ca, + IN const uint8_t port_num, + IN const void* const p_mad_in, + IN void* p_mad_out ); + +#endif /* __IB_UAL_MAD_H__ */ diff --git a/branches/WOF2-3/core/al/user/ual_mad_pool.c b/branches/WOF2-3/core/al/user/ual_mad_pool.c new file mode 100644 index 00000000..411dd7ee --- /dev/null +++ b/branches/WOF2-3/core/al/user/ual_mad_pool.c @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include "al_mad_pool.h" +#include "al_debug.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "ual_mad_pool.tmh" +#endif + + + + +/* + * Function prototypes. + */ +static void +__ual_free_pool_key( + IN al_obj_t* p_obj ); + + +/* + * Register a MAD pool with a protection domain. + */ +ib_api_status_t +ual_reg_global_mad_pool( + IN const ib_pool_handle_t h_pool, + OUT ib_pool_key_t* const pp_pool_key ) +{ + al_pool_key_t* p_pool_key; + ib_api_status_t status; + + AL_ENTER(AL_DBG_MAD_POOL); + + if( AL_OBJ_INVALID_HANDLE( h_pool, AL_OBJ_TYPE_H_MAD_POOL ) ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , ("IB_INVALID_HANDLE\n") ); + return IB_INVALID_HANDLE; + } + if( !pp_pool_key ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + /* Allocate a pool key structure. */ + p_pool_key = cl_zalloc( sizeof( al_pool_key_t ) ); + if( !p_pool_key ) + return IB_INSUFFICIENT_MEMORY; + + /* Initialize the pool key. */ + construct_al_obj( &p_pool_key->obj, AL_OBJ_TYPE_H_POOL_KEY ); + p_pool_key->type = AL_KEY_ALIAS; + p_pool_key->h_pool = h_pool; + p_pool_key->h_pd = NULL; + + /* Initialize the pool key object. */ + status = init_al_obj( &p_pool_key->obj, p_pool_key, TRUE, + NULL, NULL, __ual_free_pool_key ); + if( status != IB_SUCCESS ) + { + __ual_free_pool_key( &p_pool_key->obj ); + + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("init_al_obj failed with status %s.\n", ib_get_err_str(status)) ); + return status; + } + + status = attach_al_obj( &h_pool->obj, &p_pool_key->obj ); + if( status != IB_SUCCESS ) + { + p_pool_key->obj.pfn_destroy( &p_pool_key->obj, NULL ); + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("attach_al_obj returned %s.\n", ib_get_err_str(status)) ); + return status; + } + p_pool_key->h_al = p_pool_key->obj.h_al; + + /* Return the pool key. */ + *pp_pool_key = (ib_pool_key_t)p_pool_key; + + /* Release the reference taken in init_al_obj. */ + deref_al_obj( &p_pool_key->obj ); + + AL_EXIT(AL_DBG_MAD_POOL); + return IB_SUCCESS; +} + + + +/* + * Free a pool key. + */ +static void +__ual_free_pool_key( + IN al_obj_t* p_obj ) +{ + al_pool_key_t* p_pool_key; + + CL_ASSERT( p_obj ); + p_pool_key = PARENT_STRUCT( p_obj, al_pool_key_t, obj ); + + CL_ASSERT( !p_pool_key->mad_cnt ); + destroy_al_obj( &p_pool_key->obj ); + cl_free( p_pool_key ); +} + diff --git a/branches/WOF2-3/core/al/user/ual_mcast.c b/branches/WOF2-3/core/al/user/ual_mcast.c new file mode 100644 index 00000000..7c17f07f --- /dev/null +++ b/branches/WOF2-3/core/al/user/ual_mcast.c @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include +#include "al_qp.h" +#include "ual_support.h" +#include "ual_mcast.h" + +#include "al_debug.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "ual_mcast.tmh" +#endif + +ib_api_status_t +ual_attach_mcast( + IN ib_mcast_handle_t h_mcast ) +{ + ual_attach_mcast_ioctl_t ioctl_buf; + uintn_t bytes_ret; + cl_status_t cl_status; + ib_api_status_t status = IB_ERROR; + ib_qp_handle_t h_qp; + uvp_interface_t uvp_intf; + + AL_ENTER( AL_DBG_MCAST ); + + h_qp = PARENT_STRUCT( h_mcast->obj.p_parent_obj, + al_dgrm_qp_t, obj ); + uvp_intf = h_qp->obj.p_ci_ca->verbs.user_verbs; + + /* Clear the ioctl_buf */ + cl_memclr( &ioctl_buf, sizeof(ioctl_buf) ); + + /* Pre call to the UVP library */ + if( h_qp->h_ci_qp && uvp_intf.pre_attach_mcast ) + { + status = uvp_intf.pre_attach_mcast( h_qp->h_ci_qp, + &h_mcast->member_rec.mgid, h_mcast->member_rec.mlid, + &ioctl_buf.in.umv_buf, &h_mcast->h_ci_mcast ); + if( status != IB_SUCCESS ) + { + AL_EXIT( AL_DBG_PD ); + return status; + } + } + + ioctl_buf.in.h_qp = h_qp->obj.hdl; + ioctl_buf.in.mgid = h_mcast->member_rec.mgid; + ioctl_buf.in.mlid = h_mcast->member_rec.mlid; + + cl_status = do_al_dev_ioctl( UAL_ATTACH_MCAST, + &ioctl_buf.in, sizeof(ioctl_buf.in), + &ioctl_buf.out, sizeof(ioctl_buf.out), + &bytes_ret ); + + if( cl_status != CL_SUCCESS || bytes_ret != sizeof(ioctl_buf.out) ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("UAL_ATTACH_MCAST IOCTL returned %s.\n", + CL_STATUS_MSG(cl_status)) ); + status = IB_ERROR; + } + else + { + status = ioctl_buf.out.status; + if( status == IB_SUCCESS ){ + h_mcast->obj.hdl = ioctl_buf.out.h_attach; + h_mcast->h_ci_mcast = (ib_mcast_handle_t)(ULONG_PTR)ioctl_buf.out.h_attach; + } + } + + /* Post uvp call */ + if( h_qp->h_ci_qp && uvp_intf.post_attach_mcast ) + { + uvp_intf.post_attach_mcast( h_qp->h_ci_qp, + status, &h_mcast->h_ci_mcast, &ioctl_buf.out.umv_buf); + } + + AL_EXIT( AL_DBG_MCAST ); + return status; +} + + +ib_api_status_t +ual_detach_mcast( + IN ib_mcast_handle_t h_mcast ) +{ + ual_detach_mcast_ioctl_t ioctl_buf; + uintn_t bytes_ret; + cl_status_t cl_status; + ib_api_status_t status; + ib_qp_handle_t h_qp; + uvp_interface_t uvp_intf; + + AL_ENTER( AL_DBG_MCAST ); + + h_qp = PARENT_STRUCT( h_mcast->obj.p_parent_obj, + al_dgrm_qp_t, obj ); + uvp_intf = h_qp->obj.p_ci_ca->verbs.user_verbs; + + /* Clear the ioctl_buf */ + cl_memclr( &ioctl_buf, sizeof(ioctl_buf) ); + + /* Pre call to the UVP library */ + if( h_qp->h_ci_qp && uvp_intf.pre_detach_mcast ) + { + status = uvp_intf.pre_detach_mcast( h_mcast->h_ci_mcast ); + if( status != IB_SUCCESS ) + { + AL_EXIT( AL_DBG_MCAST ); + return status; + } + } + + ioctl_buf.in.h_attach = h_mcast->obj.hdl; + + cl_status = do_al_dev_ioctl( UAL_DETACH_MCAST, + &ioctl_buf.in, sizeof(ioctl_buf.in), + &ioctl_buf.out, sizeof(ioctl_buf.out), + &bytes_ret ); + + if( cl_status != CL_SUCCESS || bytes_ret != sizeof(ioctl_buf.out) ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("UAL_DETACH_MCAST IOCTL returned %s.\n", + CL_STATUS_MSG(cl_status)) ); + status = IB_ERROR; + } + else + { + status = ioctl_buf.out.status; + } + + /* Post uvp call */ + if( h_mcast->h_ci_mcast && uvp_intf.post_detach_mcast ) + uvp_intf.post_detach_mcast( h_mcast->h_ci_mcast, status ); + + AL_EXIT( AL_DBG_MCAST ); + return status; +} diff --git a/branches/WOF2-3/core/al/user/ual_mcast.h b/branches/WOF2-3/core/al/user/ual_mcast.h new file mode 100644 index 00000000..b74e6eeb --- /dev/null +++ b/branches/WOF2-3/core/al/user/ual_mcast.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#if !defined(__UAL_MCAST_H__) +#define __UAL_MCAST_H__ + +ib_api_status_t +ual_attach_mcast( + IN ib_mcast_handle_t h_mcast ); + +ib_api_status_t +ual_detach_mcast( + IN ib_mcast_handle_t h_mcast ); + +#endif /* __UAL_MCAST_H__ */ diff --git a/branches/WOF2-3/core/al/user/ual_mgr.c b/branches/WOF2-3/core/al/user/ual_mgr.c new file mode 100644 index 00000000..e92ac6b6 --- /dev/null +++ b/branches/WOF2-3/core/al/user/ual_mgr.c @@ -0,0 +1,1061 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include "ual_support.h" +#include "al_debug.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "ual_mgr.tmh" +#endif + +#include "al_mgr.h" +#include "al_init.h" +#include "al_res_mgr.h" +#include "al_proxy_ioctl.h" +#include "al.h" +#include "al_ci_ca.h" +#include "al_pnp.h" +#include "al_ioc_pnp.h" +#include "al_cq.h" +#include "ual_ca.h" +#include "ual_qp.h" +#include "ual_mad.h" +#include "ib_common.h" +#include "al_cm_cep.h" + + +/* Global AL manager handle is defined in al_mgr_shared.c */ +extern ib_al_handle_t gh_al; +extern al_mgr_t* gp_al_mgr; +extern ib_pool_handle_t gh_mad_pool; + + +atomic32_t g_open_cnt = 0; + +/* Define the thread names to handle various notifications */ +#define CM_THREAD_NAME "CM_Thread" +#define COMP_THREAD_NAME "Comp_Thread" +#define MISC_THREAD_NAME "Misc_Thread" + +static DWORD WINAPI +__cb_thread_routine( + IN void *context ); + +static void +__process_misc_cb( + IN misc_cb_ioctl_info_t* p_misc_cb_info ); + + +static void +__cleanup_ual_mgr( + IN al_obj_t *p_obj ) +{ + AL_ENTER(AL_DBG_MGR); + + UNUSED_PARAM( p_obj ); + + /* Set the callback thread state to exit. */ + gp_al_mgr->ual_mgr.exit_thread = TRUE; + + /* Closing the file handles cancels any pending I/O requests. */ + //CloseHandle( gp_al_mgr->ual_mgr.h_cm_file ); + CloseHandle( gp_al_mgr->ual_mgr.h_cq_file ); + CloseHandle( gp_al_mgr->ual_mgr.h_misc_file ); + CloseHandle( g_al_device ); + g_al_device = INVALID_HANDLE_VALUE; +} + + +static void +__free_ual_mgr( + IN al_obj_t *p_obj ) +{ + size_t i; + HANDLE h_thread; + + UNUSED_PARAM( p_obj ); + + /* + * We need to destroy the AL object before the spinlock, since + * destroying the AL object will try to acquire the spinlock. + */ + destroy_al_obj( &gp_al_mgr->obj ); + + /* Verify that the object list is empty. */ + print_al_objs( NULL ); + + if( gp_al_mgr->ual_mgr.h_cb_port ) + { + /* Post a notification to the completion port to make threads exit. */ + for( i = 0; + i < cl_ptr_vector_get_size( &gp_al_mgr->ual_mgr.cb_threads ); + i++ ) + { + if( !PostQueuedCompletionStatus( gp_al_mgr->ual_mgr.h_cb_port, + 0, 0, NULL ) ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("PostQueuedCompletionStatus returned %d\n", + GetLastError()) ); + } + } + + while( cl_ptr_vector_get_size( &gp_al_mgr->ual_mgr.cb_threads ) ) + { + h_thread = cl_ptr_vector_get( &gp_al_mgr->ual_mgr.cb_threads, 0 ); + WaitForSingleObject( h_thread, INFINITE ); + CloseHandle( h_thread ); + cl_ptr_vector_remove( &gp_al_mgr->ual_mgr.cb_threads, 0 ); + } + + CloseHandle( gp_al_mgr->ual_mgr.h_cb_port ); + } + + cl_ptr_vector_destroy( &gp_al_mgr->ual_mgr.cb_threads ); + cl_spinlock_destroy( &gp_al_mgr->lock ); + + cl_free( gp_al_mgr ); + gp_al_mgr = NULL; +} + + +HANDLE +ual_create_async_file( + IN uint32_t type ) +{ + cl_status_t cl_status; + ual_bind_file_ioctl_t ioctl; + uintn_t bytes_ret; + + AL_ENTER( AL_DBG_MGR ); + + /* Create a file object on which to issue all SA requests. */ + ioctl.h_file = HandleToHandle64( CreateFileW( L"\\\\.\\ibal", + GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL ) ); + if( ioctl.h_file == INVALID_HANDLE_VALUE ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("CreateFile returned %d.\n", GetLastError()) ); + return INVALID_HANDLE_VALUE; + } + + /* Bind this file object to the completion port. */ + if( !CreateIoCompletionPort( + ioctl.h_file, gp_al_mgr->ual_mgr.h_cb_port, type, 0 ) ) + { + CloseHandle( ioctl.h_file ); + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("CreateIoCompletionPort for file of type %d returned %d.\n", + type, GetLastError()) ); + return INVALID_HANDLE_VALUE; + } + + /* + * Send an IOCTL down on the main file handle to bind this file + * handle with our proxy context. + */ + cl_status = do_al_dev_ioctl( + type, &ioctl, sizeof(ioctl), NULL, 0, &bytes_ret ); + if( cl_status != CL_SUCCESS ) + { + CloseHandle( ioctl.h_file ); + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("Bind IOCTL for type %d returned %s.\n", + type,CL_STATUS_MSG(cl_status)) ); + return INVALID_HANDLE_VALUE; + } + + AL_EXIT( AL_DBG_MGR ); + return ioctl.h_file; +} + + +ib_api_status_t +ual_create_cb_threads( void ) +{ + cl_status_t cl_status; + uint32_t i; + HANDLE h_thread; + + AL_ENTER( AL_DBG_MGR ); + + cl_status = cl_ptr_vector_init( + &gp_al_mgr->ual_mgr.cb_threads, cl_proc_count(), 0 ); + if( cl_status != CL_SUCCESS ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("cl_ptr_vector_init returned %s.\n", CL_STATUS_MSG( cl_status )) ); + return IB_ERROR; + } + + for( i = 0; i < cl_proc_count(); i++ ) + { + h_thread = CreateThread( NULL, 0, __cb_thread_routine, NULL, 0, NULL ); + if( !h_thread ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("CreateThread returned %d.\n", GetLastError()) ); + return IB_ERROR; + } + + /* We already sized the vector, so insertion should work. */ + cl_status = cl_ptr_vector_insert( &gp_al_mgr->ual_mgr.cb_threads, + h_thread, NULL ); + CL_ASSERT( cl_status == CL_SUCCESS ); + } + + AL_EXIT( AL_DBG_MGR ); + return IB_SUCCESS; +} + + +/* + * Create the ual manager for the process + */ +ib_api_status_t +create_al_mgr() +{ + ib_api_status_t ib_status; + cl_status_t cl_status; + uintn_t bytes_ret; + ULONG ver; + + AL_ENTER(AL_DBG_MGR); + + CL_ASSERT( !gp_al_mgr ); + + /* First open the kernel device. */ + CL_ASSERT( g_al_device == INVALID_HANDLE_VALUE ); + g_al_device = CreateFileW( L"\\\\.\\ibal", + GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, 0, NULL ); + if( g_al_device == INVALID_HANDLE_VALUE ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("CreateFile returned %d.\n", GetLastError()) ); + return IB_ERROR; + } + + + ver = AL_IOCTL_VERSION; + + cl_status = + do_al_dev_ioctl( UAL_BIND, &ver, sizeof(ver), NULL, 0, &bytes_ret ); + if( cl_status != CL_SUCCESS ) + return IB_ERROR; + + gp_al_mgr = cl_zalloc( sizeof( al_mgr_t ) ); + if( !gp_al_mgr ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("Failed to cl_zalloc ual_mgr_t.\n") ); + return IB_INSUFFICIENT_MEMORY; + } + + /* Construct the AL manager. */ + cl_event_construct( &gp_al_mgr->ual_mgr.sync_event ); + cl_ptr_vector_construct( &gp_al_mgr->ual_mgr.cb_threads ); + cl_qlist_init( &gp_al_mgr->al_obj_list ); + cl_qlist_init( &gp_al_mgr->ci_ca_list ); + cl_spinlock_construct( &gp_al_mgr->lock ); + gp_al_mgr->ual_mgr.h_cb_port = NULL; + + /* Init the al object in the ual manager */ + construct_al_obj(&gp_al_mgr->obj, AL_OBJ_TYPE_AL_MGR); + ib_status = init_al_obj( &gp_al_mgr->obj, gp_al_mgr, FALSE, + NULL, __cleanup_ual_mgr, __free_ual_mgr ); + if( ib_status != IB_SUCCESS ) + { + __free_ual_mgr( &gp_al_mgr->obj ); + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("init_al_obj failed, status = 0x%x.\n", ib_status) ); + return ib_status; + } + + /* Allocate the I/O completion port for async operations. */ + gp_al_mgr->ual_mgr.h_cb_port = CreateIoCompletionPort( + INVALID_HANDLE_VALUE, NULL, 0, 0 ); + if( !gp_al_mgr->ual_mgr.h_cb_port ) + { + gp_al_mgr->obj.pfn_destroy( &gp_al_mgr->obj, NULL ); + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("Failed to create I/O completion port.\n") ); + return IB_ERROR; + } + + /* Create the threads to process completion callbacks. */ + ib_status = ual_create_cb_threads(); + if( ib_status != IB_SUCCESS ) + { + gp_al_mgr->obj.pfn_destroy( &gp_al_mgr->obj, NULL ); + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, ("ual_create_cb_threads failed.\n") ); + return ib_status; + } + + /* Create CM callback file handle. */ + //gp_al_mgr->ual_mgr.h_cm_file = ual_create_async_file( UAL_BIND_CM ); + //if( gp_al_mgr->ual_mgr.h_cq_file == INVALID_HANDLE_VALUE ) + //{ + // gp_al_mgr->obj.pfn_destroy( &gp_al_mgr->obj, NULL ); + // AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + // ("ual_create_async_file for UAL_BIND_CM returned %d.\n", + // GetLastError()) ); + // return IB_ERROR; + //} + + /* Create the CQ completion callback file handle. */ + gp_al_mgr->ual_mgr.h_cq_file = ual_create_async_file( UAL_BIND_CQ ); + if( gp_al_mgr->ual_mgr.h_cq_file == INVALID_HANDLE_VALUE ) + { + gp_al_mgr->obj.pfn_destroy( &gp_al_mgr->obj, NULL ); + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("ual_create_async_file for UAL_BIND_CQ returned %d.\n", + GetLastError()) ); + return IB_ERROR; + } + + /* Create the miscelaneous callback file handle. */ + gp_al_mgr->ual_mgr.h_misc_file = ual_create_async_file( UAL_BIND_MISC ); + if( gp_al_mgr->ual_mgr.h_misc_file == INVALID_HANDLE_VALUE ) + { + gp_al_mgr->obj.pfn_destroy( &gp_al_mgr->obj, NULL ); + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("ual_create_async_file for UAL_BIND_CQ returned %d.\n", + GetLastError()) ); + return IB_ERROR; + } + + cl_status = cl_spinlock_init( &gp_al_mgr->lock ); + if( cl_status != CL_SUCCESS ) + { + gp_al_mgr->obj.pfn_destroy(&gp_al_mgr->obj, NULL); + return ib_convert_cl_status( cl_status ); + } + + /* With PnP support, open the AL instance before the threads + * get a chance to process async events + */ + + /* Open an implicit al instance for UAL's internal usage. This call will + * automatically create the gh_al. + */ + gh_al = NULL; + if ((ib_status = do_open_al(&gp_al_mgr->ual_mgr.h_al)) != IB_SUCCESS) + { + gp_al_mgr->obj.pfn_destroy(&gp_al_mgr->obj, NULL); + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("do_open_al() failed, status = 0x%x.\n", ib_status) ); + return ( ib_status ); + } + + /* Create the global AL MAD pool. */ + ib_status = ib_create_mad_pool( gh_al, 0, 0, 64, &gh_mad_pool ); + if( ib_status != IB_SUCCESS ) + { + gp_al_mgr->obj.pfn_destroy(&gp_al_mgr->obj, NULL); + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("ib_create_mad_pool failed with %s.\n", ib_get_err_str(ib_status)) ); + return ib_status; + } + + /* + * Create a global pool key for internal MADs - they are never + * registered on any CA. + */ + ib_status = ual_reg_global_mad_pool( gh_mad_pool, &g_pool_key ); + if( ib_status != IB_SUCCESS ) + { + gp_al_mgr->obj.pfn_destroy(&gp_al_mgr->obj, NULL); + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("ual_reg_global_mad_pool failed with %s.\n", ib_get_err_str(ib_status)) ); + return ib_status; + } + + /* Create the pnp manager before the thread initialize. This makes + * sure that the pnp manager is ready to process pnp callbacks as + * soon as the callback threads start running + */ + ib_status = create_pnp( &gp_al_mgr->obj ); + if( ib_status != IB_SUCCESS ) + { + gp_al_mgr->obj.pfn_destroy(&gp_al_mgr->obj, NULL); + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("al_pnp_create failed with %s.\n", ib_get_err_str(ib_status)) ); + return ib_status; + } + + /* Initialize the AL resource manager. */ + ib_status = create_res_mgr( &gp_al_mgr->obj ); + if( ib_status != IB_SUCCESS ) + { + gp_al_mgr->obj.pfn_destroy(&gp_al_mgr->obj, NULL); + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("create_res_mgr failed with %s.\n", ib_get_err_str(ib_status)) ); + return ib_status; + } + + /* Initialize the AL SA request manager. */ + ib_status = create_sa_req_mgr( &gp_al_mgr->obj ); + if( ib_status != IB_SUCCESS ) + { + gp_al_mgr->obj.pfn_destroy(&gp_al_mgr->obj, NULL); + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("create_sa_req_mgr failed with %s.\n", ib_get_err_str(ib_status)) ); + return ib_status; + } + + /* Initialize CM */ + ib_status = create_cep_mgr( &gp_al_mgr->obj ); + if( ib_status != IB_SUCCESS ) + { + gp_al_mgr->obj.pfn_destroy( &gp_al_mgr->obj, NULL ); + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("create_cm_mgr failed, status = 0x%x.\n", ib_status) ); + return ib_status; + } + + cl_status = cl_event_init( &gp_al_mgr->ual_mgr.sync_event, FALSE ); + if( cl_status != CL_SUCCESS ) + { + gp_al_mgr->obj.pfn_destroy(&gp_al_mgr->obj, NULL); + return ib_convert_cl_status( cl_status ); + } + + /* Everything is ready now. Issue the first callback requests. */ + if( !DeviceIoControl( gp_al_mgr->ual_mgr.h_misc_file, UAL_GET_MISC_CB_INFO, + NULL, 0, + &gp_al_mgr->ual_mgr.misc_cb_info, sizeof(misc_cb_ioctl_info_t), + NULL, &gp_al_mgr->ual_mgr.misc_ov ) ) + { + if( GetLastError() != ERROR_IO_PENDING ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("DeviceIoControl for misc callback request returned %d.\n", + GetLastError()) ); + gp_al_mgr->obj.pfn_destroy(&gp_al_mgr->obj, NULL); + return IB_ERROR; + } + } + + if( !DeviceIoControl( gp_al_mgr->ual_mgr.h_cq_file, UAL_GET_COMP_CB_INFO, + NULL, 0, + &gp_al_mgr->ual_mgr.comp_cb_info, sizeof(comp_cb_ioctl_info_t), + NULL, &gp_al_mgr->ual_mgr.cq_ov ) ) + { + if( GetLastError() != ERROR_IO_PENDING ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("DeviceIoControl for CM callback request returned %d.\n", + GetLastError()) ); + gp_al_mgr->obj.pfn_destroy(&gp_al_mgr->obj, NULL); + return IB_ERROR; + } + } + + /* + * Wait until the associated kernel PnP registration completes. This + * indicates that all known CAs have been reported to user-space + * and are being processed by the PnP manager. + */ +#ifdef _DEBUG_ + cl_status = cl_event_wait_on( &gp_al_mgr->ual_mgr.sync_event, + EVENT_NO_TIMEOUT, TRUE ); + CL_ASSERT ( cl_status == CL_SUCCESS); +#else + cl_status = cl_event_wait_on( &gp_al_mgr->ual_mgr.sync_event, + EVENT_NO_TIMEOUT, TRUE ); +#endif + + if( cl_status != CL_SUCCESS ) + { + gp_al_mgr->obj.pfn_destroy(&gp_al_mgr->obj, NULL); + return ib_convert_cl_status( cl_status ); + } + /* Release the reference taken in init_al_obj. */ + deref_al_obj( &gp_al_mgr->obj ); + + AL_EXIT(AL_DBG_MGR); + return IB_SUCCESS; +} + + + +/* + * UAL thread start routines. + */ +static void +__process_comp_cb( + IN comp_cb_ioctl_info_t* p_comp_cb_info ) +{ + ib_cq_handle_t h_cq; + CL_ASSERT( p_comp_cb_info->cq_context ); + h_cq = (ib_cq_handle_t)(ULONG_PTR)p_comp_cb_info->cq_context; + + if( ref_al_obj( &h_cq->obj ) > 1 ) + { + CL_ASSERT( h_cq->pfn_user_comp_cb ); + h_cq->pfn_user_comp_cb( h_cq, (void*)h_cq->obj.context ); + } + deref_al_obj( &h_cq->obj ); +} + + + +/* Thread to process the asynchronous completion notifications */ +void +cq_cb( + IN DWORD error_code, + IN DWORD ret_bytes, + IN LPOVERLAPPED p_ov ) +{ + AL_ENTER( AL_DBG_CQ ); + + UNUSED_PARAM( p_ov ); + + if( !error_code && ret_bytes ) + { + /* Check the record type and adjust the pointers */ + /* TBD */ + __process_comp_cb( &gp_al_mgr->ual_mgr.comp_cb_info ); + } + + if( error_code != ERROR_OPERATION_ABORTED ) + { + if( !DeviceIoControl( gp_al_mgr->ual_mgr.h_cq_file, UAL_GET_COMP_CB_INFO, + NULL, 0, + &gp_al_mgr->ual_mgr.comp_cb_info, sizeof(comp_cb_ioctl_info_t), + NULL, &gp_al_mgr->ual_mgr.cq_ov ) ) + { + if( GetLastError() != ERROR_IO_PENDING ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("DeviceIoControl for CM callback request returned %d.\n", + GetLastError()) ); + } + } + } + + AL_EXIT( AL_DBG_CQ ); +} + + + +/* Thread to process miscellaneous asynchronous events */ +void +misc_cb( + IN DWORD error_code, + IN DWORD ret_bytes, + IN LPOVERLAPPED p_ov ) +{ + AL_ENTER( AL_DBG_MGR ); + + UNUSED_PARAM( p_ov ); + + if( !error_code && ret_bytes ) + { + /* Check the record type and adjust the pointers */ + /* TBD */ + __process_misc_cb( &gp_al_mgr->ual_mgr.misc_cb_info ); + } + + if( error_code != ERROR_OPERATION_ABORTED ) + { + /* Issue the next request. */ + if( !DeviceIoControl( gp_al_mgr->ual_mgr.h_misc_file, UAL_GET_MISC_CB_INFO, + NULL, 0, + &gp_al_mgr->ual_mgr.misc_cb_info, sizeof(misc_cb_ioctl_info_t), + NULL, &gp_al_mgr->ual_mgr.misc_ov ) ) + { + if( GetLastError() != ERROR_IO_PENDING ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("DeviceIoControl for misc callback request returned %d.\n", + GetLastError()) ); + } + } + } + + AL_EXIT( AL_DBG_MGR ); +} + + + +void +__process_misc_cb( + IN misc_cb_ioctl_info_t* p_misc_cb_info ) +{ + switch( p_misc_cb_info->rec_type ) + { + case CA_ERROR_REC: + case QP_ERROR_REC: + case SRQ_ERROR_REC: + case CQ_ERROR_REC: + { + /* Initiate user-mode asynchronous event processing. */ + ci_ca_async_event( &p_misc_cb_info->ioctl_rec.event_rec ); + break; + } + case MCAST_REC: + { + ib_mcast_rec_t mcast_rec; + cl_memcpy((void *)&mcast_rec, + (void*)&p_misc_cb_info->ioctl_rec.mcast_cb_ioctl_rec, + sizeof(ib_mcast_rec_t)); + mcast_rec.p_member_rec = + &p_misc_cb_info->ioctl_rec.mcast_cb_ioctl_rec.member_rec; + /******* Call the cb function for app callback *****/ + break; + } + case MAD_SEND_REC: + { + /* We got a send completion. */ + ib_mad_element_t *p_element; + + ib_mad_svc_handle_t h_mad_svc = (ib_mad_svc_handle_t)(ULONG_PTR) + p_misc_cb_info->ioctl_rec.mad_send_cb_ioctl_rec.mad_svc_context; + + /* Copy the data to the user's element. */ + p_element = (ib_mad_element_t*)(ULONG_PTR) + p_misc_cb_info->ioctl_rec.mad_send_cb_ioctl_rec.p_um_mad; + /* Only update the status if a receive wasn't failed. */ + if( p_element->status != IB_WCS_TIMEOUT_RETRY_ERR ) + { + p_element->status = + p_misc_cb_info->ioctl_rec.mad_send_cb_ioctl_rec.wc_status; + } + p_element->p_next = NULL; + + /* Now the user mad_elements should have the right data + * Make the client callback + */ + h_mad_svc->pfn_user_send_cb( h_mad_svc, + (void*)h_mad_svc->obj.context, p_element ); + break; + } + case MAD_RECV_REC: + { + /* + * We've receive a MAD. We need to get a user-mode MAD of the + * correct size, then send it down to retrieve the received MAD. + */ + ual_mad_recv_ioctl_t ioctl_buf; + uintn_t bytes_ret; + cl_status_t cl_status; + ib_api_status_t status; + ib_mad_svc_handle_t h_mad_svc; + ib_mad_element_t *p_mad = NULL; + ib_mad_element_t *p_send_mad; + ib_mad_t *p_mad_buf = NULL; + ib_grh_t *p_grh = NULL; + + h_mad_svc = (ib_mad_svc_handle_t)(ULONG_PTR) + p_misc_cb_info->ioctl_rec.mad_recv_cb_ioctl_rec.mad_svc_context; + + p_send_mad = (ib_mad_element_t*)(ULONG_PTR) + p_misc_cb_info->ioctl_rec.mad_recv_cb_ioctl_rec.p_send_mad; + + cl_memclr( &ioctl_buf, sizeof(ioctl_buf) ); + + /* + * Get a MAD large enough to receive the MAD. If we can't get a + * MAD, we still perform the IOCTL so that the kernel will return + * the MAD to its pool, resulting in a dropped MAD. + */ + status = ib_get_mad( h_mad_svc->obj.p_ci_ca->pool_key, + p_misc_cb_info->ioctl_rec.mad_recv_cb_ioctl_rec.elem_size, + &p_mad ); + + /* + * Note that we set any associated send MAD's status here + * in case of failure. + */ + if( status == IB_SUCCESS ) + al_handoff_mad( (ib_al_handle_t)h_mad_svc->obj.h_al, p_mad ); + else if( p_send_mad ) + p_send_mad->status = IB_WCS_TIMEOUT_RETRY_ERR; + + ioctl_buf.in.p_user_mad = (ULONG_PTR)p_mad; + + if( p_mad ) + { + /* Save off the pointers since the proxy overwrites the element. */ + p_mad_buf = p_mad->p_mad_buf; + p_grh = p_mad->p_grh; + + ioctl_buf.in.p_mad_buf = (ULONG_PTR)p_mad_buf; + ioctl_buf.in.p_grh = (ULONG_PTR)p_grh; + } + ioctl_buf.in.h_mad = p_misc_cb_info->ioctl_rec.mad_recv_cb_ioctl_rec.h_mad; + + cl_status = do_al_dev_ioctl( UAL_MAD_RECV_COMP, + &ioctl_buf.in, sizeof(ioctl_buf.in), + &ioctl_buf.out, sizeof(ioctl_buf.out), + &bytes_ret ); + if( cl_status != CL_SUCCESS || bytes_ret != sizeof(ioctl_buf.out) ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("UAL_MAD_RECV_COMP IOCTL returned %s.\n", + CL_STATUS_MSG(cl_status)) ); + status = IB_ERROR; + } + else + { + status = ioctl_buf.out.status; + } + if( p_mad ) + { + if( status == IB_SUCCESS ) + { + /* We need to reset MAD data pointers. */ + p_mad->p_mad_buf = p_mad_buf; + p_mad->p_grh = p_grh; + /* Restore the client's send context1 */ + if( p_send_mad ) + p_mad->send_context1 = (void*)p_send_mad->context1; + + h_mad_svc->pfn_user_recv_cb( h_mad_svc, + (void*)h_mad_svc->obj.context, p_mad ); + } + else + { + ib_put_mad( p_mad ); + } + } + break; + } + case SVC_REG_REC: + { + break; + } + case QUERY_REC: + { + break; + } + case PNP_REC: + { + ib_pnp_event_t pnp_event; + ib_net64_t ca_guid; + al_ci_ca_t *p_ci_ca; + ib_ca_attr_t *p_old_ca_attr; + ib_api_status_t status; + + pnp_event = p_misc_cb_info->ioctl_rec.pnp_cb_ioctl_rec.pnp_event; + ca_guid = p_misc_cb_info->ioctl_rec.pnp_cb_ioctl_rec.pnp_info.ca.ca_guid; + + switch( pnp_event ) + { + case IB_PNP_CA_ADD: + /* Create a new CI CA. */ + create_ci_ca( gh_al, &gp_al_mgr->obj, + p_misc_cb_info->ioctl_rec.pnp_cb_ioctl_rec.pnp_info.ca.ca_guid ); + break; + + case IB_PNP_CA_REMOVE: + /* Destroy the CI CA. */ + cl_spinlock_acquire( &gp_al_mgr->obj.lock ); + p_ci_ca = find_ci_ca( ca_guid ); + if( !p_ci_ca ) + { + cl_spinlock_release( &gp_al_mgr->obj.lock ); + break; + } + ref_al_obj( &p_ci_ca->obj ); + cl_spinlock_release( &gp_al_mgr->obj.lock ); + + p_ci_ca->obj.pfn_destroy( &p_ci_ca->obj, NULL ); + break; + + case IB_PNP_PORT_ADD: + case IB_PNP_PORT_REMOVE: + /* Should never get these. */ + break; + + case IB_PNP_REG_COMPLETE: + /* + * Signal that the kernel PnP registration is done, indicating + * that the current system state has been reported to the user. + */ + cl_event_signal( &gp_al_mgr->ual_mgr.sync_event ); + break; + + default: + /* Process the PnP event - most likely a port change event. */ + cl_spinlock_acquire( &gp_al_mgr->obj.lock ); + p_ci_ca = find_ci_ca( ca_guid ); + if( !p_ci_ca ) + { + cl_spinlock_release( &gp_al_mgr->obj.lock ); + break; + } + ref_al_obj( &p_ci_ca->obj ); + cl_spinlock_release( &gp_al_mgr->obj.lock ); + + status = ci_ca_update_attr( p_ci_ca, &p_old_ca_attr ); + if( status != IB_SUCCESS) { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("update CA attributes returned %#x.\n", status) ); + + /* Dereference the CA now. */ + deref_al_obj( &p_ci_ca->obj ); + break; + } + if ( p_old_ca_attr ) + cl_free( p_old_ca_attr ); + + /* Dereference the CA now. */ + deref_al_obj( &p_ci_ca->obj ); + break; + } + + break; /* For PNP_EVENT_REC */ + } + default: + CL_ASSERT (0); + break; + } +} + + + +/* + * Create a new instance of the access layer. + */ +ib_api_status_t +ib_open_al( + OUT ib_al_handle_t* const ph_al ) +{ + ib_api_status_t status; + + cl_mutex_acquire( &g_open_close_mutex ); + status = do_open_al( ph_al ); + if( status == IB_SUCCESS ) + { + /* + * Bump the open count. Note that we only do this for external + * calls, not the internal ib_open_al call. + */ + cl_atomic_inc( &g_open_cnt ); + } + cl_mutex_release( &g_open_close_mutex ); + return status; +} + + +ib_api_status_t +ib_close_al( + IN const ib_al_handle_t h_al ) +{ + ib_api_status_t status; + + cl_mutex_acquire( &g_open_close_mutex ); + status = do_close_al( h_al ); + if( status == IB_SUCCESS && !cl_atomic_dec( &g_open_cnt ) ) + al_cleanup(); + cl_mutex_release( &g_open_close_mutex ); + return status; +} + + +ib_api_status_t +do_open_al( + OUT ib_al_handle_t* const ph_al ) +{ + ib_al_handle_t h_al; + ib_api_status_t status; + + AL_ENTER(AL_DBG_MGR); + + if( !ph_al ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + /* + * Initialize AL if needed. + * This should only occur on the first ib_open_al call. + */ + if( !gp_al_mgr ) + { + status = al_initialize(); + if( status != IB_SUCCESS ) + { + al_cleanup(); + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("ual_init failed, status = %s\n", ib_get_err_str(status) ) ); + return status; + } + /* + * Wait for 50ms before returning. This ensures the pnp events are + * delivered before any special qp services are invoked. + */ + cl_thread_suspend( 50 ); + } + + /* Allocate an access layer instance. */ + h_al = (ib_al_handle_t)cl_zalloc( sizeof( ib_al_t ) ); + if( !h_al ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , ("cl_malloc failed\n") ); + return IB_INSUFFICIENT_MEMORY; + } + + /* Construct the instance. */ + construct_al_obj( &h_al->obj, AL_OBJ_TYPE_H_AL ); + cl_spinlock_construct( &h_al->mad_lock ); + cl_qlist_init( &h_al->mad_list ); + cl_qlist_init( &h_al->key_list ); + cl_qlist_init( &h_al->query_list ); + cl_qlist_init( &h_al->cep_list ); + + if( cl_spinlock_init( &h_al->mad_lock ) != CL_SUCCESS ) + { + free_al( &h_al->obj ); + AL_EXIT( AL_DBG_ERROR ); + return IB_ERROR; + } + + /* Initialize the base object. */ + status = init_al_obj( &h_al->obj, NULL, FALSE, + destroying_al, NULL, free_al ); + if( status != IB_SUCCESS ) + { + free_al( &h_al->obj ); + AL_EXIT(AL_DBG_MGR); + return status; + } + attach_al_obj( &gp_al_mgr->obj, &h_al->obj ); + + /* + * Self reference the AL instance so that all attached objects + * insert themselve in the instance's handle manager automatically. + */ + h_al->obj.h_al = h_al; + + /* + * We only maintain a single AL instance in the kernel. It is created + * automatically when the device is opened. + */ + if( !gh_al ) + { + /* Save a copy of the implicit al handle in a global */ + gh_al = h_al; + } + + /* Return UAL's handle to caller */ + *ph_al = (ib_al_handle_t)h_al; + + /* Release the reference taken in init_al_obj. */ + deref_al_obj( &h_al->obj ); + + AL_EXIT(AL_DBG_MGR); + return IB_SUCCESS; +} + + +static DWORD WINAPI +__cb_thread_routine( + IN void *context ) +{ + DWORD ret_bytes, err; + OVERLAPPED *p_ov; + ULONG_PTR key; + BOOL ret; + + AL_ENTER( AL_DBG_MGR ); + + UNUSED_PARAM( context ); + + do + { + ret = GetQueuedCompletionStatus( gp_al_mgr->ual_mgr.h_cb_port, + &ret_bytes, &key, &p_ov, INFINITE ); + + if( ret && !p_ov ) + break; + + if( !ret ) + err = GetLastError(); + else + err = 0; + + CL_ASSERT( p_ov ); + switch( key ) + { + case UAL_BIND_CM: + //DebugBreak(); + /* CM callback. */ + cm_cb( err, ret_bytes, p_ov ); + break; + + case UAL_BIND_CQ: + /* CQ completion callback. */ + cq_cb( err, ret_bytes, p_ov ); + break; + + case UAL_BIND_MISC: + /* Misc callback. */ + misc_cb( err, ret_bytes, p_ov ); + break; + + case UAL_BIND_PNP: + /* PnP callback. */ + pnp_cb( err, ret_bytes, p_ov ); + break; + + case UAL_BIND_SA: + /* SA callback. */ + sa_req_cb( err, ret_bytes, p_ov ); + break; + + case UAL_BIND_DESTROY: + if( p_ov ) + deref_al_obj( (al_obj_t*)p_ov->Pointer ); + break; + + default: + CL_ASSERT( key == UAL_BIND_CM || key == UAL_BIND_CQ || + key == UAL_BIND_MISC || key == UAL_BIND_PNP || + key == UAL_BIND_SA || key == UAL_BIND_DESTROY ); + break; + } + } while( !ret || p_ov ); + + AL_EXIT( AL_DBG_MGR ); + ExitThread( 0 ); +} diff --git a/branches/WOF2-3/core/al/user/ual_mgr.h b/branches/WOF2-3/core/al/user/ual_mgr.h new file mode 100644 index 00000000..e1b37044 --- /dev/null +++ b/branches/WOF2-3/core/al/user/ual_mgr.h @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#if !defined(__UAL_MGR_H__) +#define __UAL_MGR_H__ + +#include "ual_support.h" +#include "al_ci_ca.h" +#include +#include + + +typedef struct _ual_mgr +{ + ib_al_handle_t h_al; /* UAL's internal implicit open_al */ + + cl_event_t sync_event; + + boolean_t exit_thread; + + /* Pointer vector of threads used to handle async IOCTL completions. */ + cl_ptr_vector_t cb_threads; + /* Completion port handle that cb threads use to get I/O completions. */ + HANDLE h_cb_port; + + /* Thread to handle work request completions */ + HANDLE h_cq_file; + comp_cb_ioctl_info_t comp_cb_info; + OVERLAPPED cq_ov; + + /* Thread to handle Miscellaneous notifications such as: + * cq/qp error + * cq/qp destroyed notification + * MAD notifications, SM, Query + * mcast_join completion + * pnp event + * completion of subscription + * Fabric event + * ca destroyed + * cancellation of subscription, notify req + */ + HANDLE h_misc_file; + misc_cb_ioctl_info_t misc_cb_info; + OVERLAPPED misc_ov; + +} ual_mgr_t; + + +/* Global mad pool key for internal MADs. */ +ib_pool_key_t g_pool_key; + + +ib_api_status_t +do_open_al( + OUT ib_al_handle_t* const ph_al ); + +ib_api_status_t +do_close_al( + IN const ib_al_handle_t h_al ); + + +/* + * Proto types for asynchronous event processing threads + */ +void +ual_cm_thread_start( + IN void *context); + +void +ual_comp_thread_start( + IN void *context); + +void +ual_misc_thread_start( + IN void *context); + + +/* Prototype for creating a file and binding it to the internal thread pool */ +HANDLE +ual_create_async_file( + IN uint32_t type ); + +void +sa_req_cb( + IN DWORD error_code, + IN DWORD ret_bytes, + IN LPOVERLAPPED p_ov ); + +void +pnp_cb( + IN DWORD error_code, + IN DWORD ret_bytes, + IN LPOVERLAPPED p_ov ); + +void +cm_cb( + IN DWORD error_code, + IN DWORD ret_bytes, + IN LPOVERLAPPED p_ov ); + +void +cq_cb( + IN DWORD error_code, + IN DWORD ret_bytes, + IN LPOVERLAPPED p_ov ); + +void +misc_cb( + IN DWORD error_code, + IN DWORD ret_bytes, + IN LPOVERLAPPED p_ov ); + +#endif // __UAL_MGR_H__ diff --git a/branches/WOF2-3/core/al/user/ual_mr.c b/branches/WOF2-3/core/al/user/ual_mr.c new file mode 100644 index 00000000..6ed32168 --- /dev/null +++ b/branches/WOF2-3/core/al/user/ual_mr.c @@ -0,0 +1,354 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + +#include +#include "al.h" +#include "ual_support.h" +#include "al_debug.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "ual_mr.tmh" +#endif + +#include "al_mr.h" +#include "al_pd.h" +#include "al_res_mgr.h" + + +ib_api_status_t +ual_reg_mem( + IN const ib_pd_handle_t h_pd, + IN const ib_mr_create_t* const p_mr_create, + OUT net32_t* const p_lkey, + OUT net32_t* const p_rkey, + IN OUT ib_mr_handle_t h_mr ) +{ + ual_reg_mem_ioctl_t mr_ioctl; + uintn_t bytes_ret; + cl_status_t cl_status; + ib_api_status_t status = IB_ERROR; + + AL_ENTER( AL_DBG_MR ); + + mr_ioctl.in.h_pd = h_pd->obj.hdl; + mr_ioctl.in.mem_create = *p_mr_create; + mr_ioctl.in.mem_create.vaddr_padding = (ULONG_PTR)p_mr_create->vaddr; + + cl_status = do_al_dev_ioctl( UAL_REG_MR, + &mr_ioctl.in, sizeof(mr_ioctl.in), &mr_ioctl.out, sizeof(mr_ioctl.out), + &bytes_ret ); + + if( cl_status != CL_SUCCESS || bytes_ret != sizeof(mr_ioctl.out) ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("UAL_REG_MR IOCTL returned %s.\n", + CL_STATUS_MSG(cl_status)) ); + status = IB_ERROR; + } + else + { + status = mr_ioctl.out.status; + if( status == IB_SUCCESS ) + { + h_mr->obj.hdl = mr_ioctl.out.h_mr; + *p_lkey = mr_ioctl.out.lkey; + *p_rkey = mr_ioctl.out.rkey; + } + } + + AL_EXIT( AL_DBG_MR ); + return status; +} + + +ib_api_status_t +ual_dereg_mr( + IN ib_mr_handle_t h_mr ) +{ + ual_dereg_mr_ioctl_t mr_ioctl; + uintn_t bytes_ret; + cl_status_t cl_status; + + AL_ENTER( AL_DBG_MR ); + + /* Clear the mr_ioctl */ + cl_memclr( &mr_ioctl, sizeof(mr_ioctl) ); + + mr_ioctl.in.h_mr = h_mr->obj.hdl; + + cl_status = do_al_dev_ioctl( UAL_DEREG_MR, + &mr_ioctl.in, sizeof(mr_ioctl.in), &mr_ioctl.out, sizeof(mr_ioctl.out), + &bytes_ret ); + + if( cl_status != CL_SUCCESS || bytes_ret != sizeof(mr_ioctl.out) ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("UAL_DEREG_MR IOCTL returned %s.\n", + CL_STATUS_MSG(cl_status)) ); + return IB_ERROR; + } + + AL_EXIT( AL_DBG_MR ); + return mr_ioctl.out.status; +} + + +ib_api_status_t +ual_modify_mr( + IN const ib_mr_handle_t h_mr, + IN const ib_mr_mod_t mr_mod_mask, + IN const ib_mr_create_t* const p_mr_create OPTIONAL, + OUT net32_t* const p_lkey, + OUT net32_t* const p_rkey, + IN const ib_pd_handle_t h_pd OPTIONAL ) +{ + ual_rereg_mem_ioctl_t mr_ioctl; + uintn_t bytes_ret; + uint64_t h_al_pd = AL_INVALID_HANDLE; + cl_status_t cl_status; + + AL_ENTER( AL_DBG_MR ); + + /* Clear the mr_ioctl */ + cl_memclr( &mr_ioctl, sizeof(mr_ioctl) ); + + if( h_pd ) + h_al_pd = h_pd->obj.hdl; + + mr_ioctl.in.h_mr = h_mr->obj.hdl; + mr_ioctl.in.mem_mod_mask = mr_mod_mask; + if( p_mr_create ) + mr_ioctl.in.mem_create = *p_mr_create; + + mr_ioctl.in.h_pd = h_al_pd; + + cl_status = do_al_dev_ioctl( UAL_MODIFY_MR, + &mr_ioctl.in, sizeof(mr_ioctl.in), &mr_ioctl.out, sizeof(mr_ioctl.out), + &bytes_ret ); + + if( cl_status != CL_SUCCESS || bytes_ret != sizeof(mr_ioctl.out) ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("UAL_MODIFY_MR IOCTL returned %s.\n", + CL_STATUS_MSG(cl_status)) ); + return IB_ERROR; + } + else if( mr_ioctl.out.status == IB_SUCCESS ) + { + *p_lkey = mr_ioctl.out.lkey; + *p_rkey = mr_ioctl.out.rkey; + } + + AL_EXIT( AL_DBG_MR ); + return mr_ioctl.out.status; +} + + +ib_api_status_t +ual_query_mr( + IN ib_mr_handle_t h_mr, + OUT ib_mr_attr_t* p_mr_attr ) +{ + ual_query_mr_ioctl_t mr_ioctl; + uintn_t bytes_ret; + cl_status_t cl_status; + + AL_ENTER( AL_DBG_MR ); + + /* Clear the mr_ioctl */ + cl_memclr( &mr_ioctl, sizeof(mr_ioctl) ); + + mr_ioctl.in.h_mr = h_mr->obj.hdl; + + cl_status = do_al_dev_ioctl( UAL_QUERY_MR, + &mr_ioctl.in, sizeof(mr_ioctl.in), &mr_ioctl.out, sizeof(mr_ioctl.out), + &bytes_ret ); + + if( cl_status != CL_SUCCESS || bytes_ret != sizeof(mr_ioctl.out) ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("UAL_QUERY_MR IOCTL returned %s.\n", + CL_STATUS_MSG(cl_status)) ); + return IB_ERROR; + } + else if( mr_ioctl.out.status == IB_SUCCESS ) + { + *p_mr_attr = mr_ioctl.out.attr; + p_mr_attr->h_pd_padding = 0; + p_mr_attr->h_pd = CONTAINING_RECORD( h_mr->obj.p_parent_obj, ib_pd_t, obj ); + } + + AL_EXIT( AL_DBG_MR ); + return mr_ioctl.out.status; +} + + +ib_api_status_t +ual_reg_shared( + IN const ib_mr_handle_t h_mr, + IN const ib_pd_handle_t h_pd, + IN const ib_access_t access_ctrl, + IN OUT uint64_t* const p_vaddr, + OUT net32_t* const p_lkey, + OUT net32_t* const p_rkey, + IN OUT ib_mr_handle_t h_new_mr ) +{ + ual_reg_shared_ioctl_t mr_ioctl; + uintn_t bytes_ret; + cl_status_t cl_status; + + AL_ENTER( AL_DBG_MR ); + + /* Clear the mr_ioctl */ + cl_memclr( &mr_ioctl, sizeof(mr_ioctl) ); + + mr_ioctl.in.h_mr = h_mr->obj.hdl; + mr_ioctl.in.h_pd = h_pd->obj.hdl; + mr_ioctl.in.access_ctrl = access_ctrl; + mr_ioctl.in.vaddr = *p_vaddr; + + cl_status = do_al_dev_ioctl( UAL_REG_SHARED, + &mr_ioctl.in, sizeof(mr_ioctl.in), &mr_ioctl.out, sizeof(mr_ioctl.out), + &bytes_ret ); + + if( cl_status != CL_SUCCESS || bytes_ret != sizeof(mr_ioctl.out) ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("UAL_REG_SHARED IOCTL returned %s.\n", + CL_STATUS_MSG(cl_status)) ); + return IB_ERROR; + } + else if( mr_ioctl.out.status == IB_SUCCESS ) + { + h_new_mr->obj.hdl = mr_ioctl.out.h_new_mr; + *p_lkey = mr_ioctl.out.lkey; + *p_rkey = mr_ioctl.out.rkey; + *p_vaddr = mr_ioctl.out.vaddr; + } + + AL_EXIT( AL_DBG_MR ); + return mr_ioctl.out.status; +} + + +ib_api_status_t +ib_reg_shmid( + IN const ib_pd_handle_t h_pd, + IN const ib_shmid_t shmid, + IN const ib_mr_create_t* const p_mr_create, + OUT uint64_t* const p_vaddr, + OUT net32_t* const p_lkey, + OUT net32_t* const p_rkey, + OUT ib_mr_handle_t* const ph_mr ) +{ + ual_reg_shmid_ioctl_t mr_ioctl; + uintn_t bytes_ret; + cl_status_t cl_status; + ib_api_status_t status; + ib_mr_handle_t h_mr; + + AL_ENTER( AL_DBG_MR ); + + if( AL_OBJ_INVALID_HANDLE( h_pd, AL_OBJ_TYPE_H_PD ) ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , ("IB_INVALID_PD_HANDLE\n") ); + return IB_INVALID_PD_HANDLE; + } + if( !p_mr_create || !p_vaddr || !p_lkey || !p_rkey || !ph_mr ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + /* Allocate a user mode memory handle */ + h_mr = alloc_mr(); + if( !h_mr ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("unable to allocate memory handle\n") ); + return IB_INSUFFICIENT_MEMORY; + } + + /* Attach this under the pd */ + attach_al_obj( &h_pd->obj, &h_mr->obj ); + + /* Clear the mr_ioctl */ + cl_memclr( &mr_ioctl, sizeof(mr_ioctl) ); + + cl_memcpy( mr_ioctl.in.shmid, shmid, sizeof(ib_shmid_t) ); + mr_ioctl.in.mr_create = *p_mr_create; + mr_ioctl.in.h_pd = h_pd->obj.hdl; + + cl_status = do_al_dev_ioctl( UAL_REG_SHMID, + &mr_ioctl.in, sizeof(mr_ioctl.in), &mr_ioctl.out, sizeof(mr_ioctl.out), + &bytes_ret ); + + if( cl_status != CL_SUCCESS || bytes_ret != sizeof(mr_ioctl.out) ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("UAL_REG_SHMID IOCTL returned %s.\n", + CL_STATUS_MSG(cl_status)) ); + status = IB_ERROR; + } + else + { + status = mr_ioctl.out.status; + } + + if( IB_SUCCESS == status ) + { + *p_vaddr = mr_ioctl.out.vaddr; + *p_lkey = mr_ioctl.out.lkey; + *p_rkey = mr_ioctl.out.rkey; + + /* Store the kernel handle and return the user handle */ + h_mr->obj.hdl = mr_ioctl.out.h_mr; + *ph_mr = h_mr; + + /* Release the reference taken in alloc_mr. */ + deref_al_obj( &h_mr->obj ); + } + else + { + h_mr->obj.pfn_destroy( &h_mr->obj, NULL ); + } + + AL_EXIT( AL_DBG_MR ); + return status; +} + diff --git a/branches/WOF2-3/core/al/user/ual_mw.c b/branches/WOF2-3/core/al/user/ual_mw.c new file mode 100644 index 00000000..8e969d9a --- /dev/null +++ b/branches/WOF2-3/core/al/user/ual_mw.c @@ -0,0 +1,303 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include +#include "ual_support.h" +#include "al.h" +#include "al_pd.h" +#include "al_qp.h" +#include "al_mw.h" +#include "al_mr.h" + + +#include "al_debug.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "ual_mw.tmh" +#endif + +ib_api_status_t +ual_create_mw( + IN const ib_pd_handle_t h_pd, + OUT net32_t* const p_rkey, + IN OUT ib_mw_handle_t h_mw ) +{ + ual_create_mw_ioctl_t mw_ioctl; + uintn_t bytes_ret; + cl_status_t cl_status; + ib_api_status_t status; + uvp_interface_t uvp_intf = h_pd->obj.p_ci_ca->verbs.user_verbs; + + AL_ENTER( AL_DBG_MW ); + + /* Clear the mw_ioctl */ + cl_memclr( &mw_ioctl, sizeof(mw_ioctl) ); + + /* Pre call to the UVP library */ + if( h_pd->h_ci_pd && uvp_intf.pre_create_mw ) + { + status = uvp_intf.pre_create_mw( + h_pd->h_ci_pd, &mw_ioctl.in.umv_buf, &h_mw->h_ci_mw ); + if( status != IB_SUCCESS ) + { + AL_EXIT( AL_DBG_MW ); + return status; + } + } + + mw_ioctl.in.h_pd = h_pd->obj.hdl; + + cl_status = do_al_dev_ioctl( UAL_CREATE_MW, + &mw_ioctl.in, sizeof(mw_ioctl.in), &mw_ioctl.out, sizeof(mw_ioctl.out), + &bytes_ret ); + + if( cl_status != CL_SUCCESS || bytes_ret != sizeof(mw_ioctl.out) ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("UAL_CREATE_MW IOCTL returned %s.\n", + CL_STATUS_MSG(cl_status)) ); + status = IB_ERROR; + } + else + { + status = mw_ioctl.out.status; + if( status == IB_SUCCESS ) + { + h_mw->obj.hdl = mw_ioctl.out.h_mw; + *p_rkey = mw_ioctl.out.rkey; + } + } + + /* Post uvp call */ + if( h_pd->h_ci_pd && uvp_intf.post_create_mw ) + { + uvp_intf.post_create_mw( h_pd->h_ci_pd, status, + mw_ioctl.out.rkey, &h_mw->h_ci_mw, + &mw_ioctl.out.umv_buf ); + } + + + + AL_EXIT( AL_DBG_MW ); + return status; +} + + +ib_api_status_t +ual_destroy_mw( + IN ib_mw_handle_t h_mw ) +{ + ual_destroy_mw_ioctl_t mw_ioctl; + uintn_t bytes_ret; + cl_status_t cl_status; + ib_api_status_t status; + uvp_interface_t uvp_intf = h_mw->obj.p_ci_ca->verbs.user_verbs; + + AL_ENTER( AL_DBG_MW ); + + /* Clear the mw_ioctl */ + cl_memclr( &mw_ioctl, sizeof(mw_ioctl) ); + + /* Call the uvp pre call if the vendor library provided a valid handle */ + if( h_mw->h_ci_mw && uvp_intf.pre_destroy_mw ) + { + /* Pre call to the UVP library */ + status = uvp_intf.pre_destroy_mw( h_mw->h_ci_mw ); + if( status != IB_SUCCESS ) + { + AL_EXIT( AL_DBG_MW ); + return status; + } + } + + mw_ioctl.in.h_mw = h_mw->obj.hdl; + + cl_status = do_al_dev_ioctl( UAL_DESTROY_MW, + &mw_ioctl.in, sizeof(mw_ioctl.in), &mw_ioctl.out, sizeof(mw_ioctl.out), + &bytes_ret ); + + if( cl_status != CL_SUCCESS || bytes_ret != sizeof(mw_ioctl.out) ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("UAL_DESTROY_MW IOCTL returned %s.\n", + CL_STATUS_MSG(cl_status)) ); + status = IB_ERROR; + } + else + { + status = mw_ioctl.out.status; + } + + /* Post uvp call */ + if( h_mw->h_ci_mw && uvp_intf.post_destroy_mw ) + uvp_intf.post_destroy_mw( h_mw->h_ci_mw, status ); + + if( status == IB_SUCCESS ) + { + h_mw->obj.hdl = AL_INVALID_HANDLE; + h_mw->h_ci_mw = NULL; + } + + AL_EXIT( AL_DBG_MW ); + return status; +} + + +ib_api_status_t +ual_query_mw( + IN ib_mw_handle_t h_mw, + OUT ib_pd_handle_t* ph_pd, + OUT net32_t* const p_rkey ) +{ + ual_query_mw_ioctl_t mw_ioctl; + uintn_t bytes_ret; + cl_status_t cl_status; + ib_api_status_t status; + uvp_interface_t uvp_intf = h_mw->obj.p_ci_ca->verbs.user_verbs; + + AL_ENTER( AL_DBG_MW ); + /* Clear the mw_ioctl */ + cl_memclr( &mw_ioctl, sizeof(mw_ioctl) ); + + /* Pre call to the UVP library */ + if( h_mw->h_ci_mw && uvp_intf.pre_query_mw ) + { + status = uvp_intf.pre_query_mw( + h_mw->h_ci_mw, &mw_ioctl.in.umv_buf ); + if( status != IB_SUCCESS ) + { + AL_EXIT( AL_DBG_MW ); + return status; + } + } + + mw_ioctl.in.h_mw = h_mw->obj.hdl; + + cl_status = do_al_dev_ioctl( UAL_QUERY_MW, + &mw_ioctl.in, sizeof(mw_ioctl.in), &mw_ioctl.out, sizeof(mw_ioctl.out), + &bytes_ret ); + + if( cl_status != CL_SUCCESS || bytes_ret != sizeof(mw_ioctl.out) ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("UAL_QUERY_MW IOCTL returned %s.\n", + CL_STATUS_MSG(cl_status)) ); + status = IB_ERROR; + } + else + { + status = mw_ioctl.out.status; + } + + if( IB_SUCCESS == status ) + { + *p_rkey = mw_ioctl.out.rkey; + *ph_pd = (ib_pd_handle_t)h_mw->obj.p_parent_obj; + } + + /* Post uvp call */ + if( h_mw->h_ci_mw && uvp_intf.post_query_mw ) + { + ib_pd_handle_t junk; + uvp_intf.post_query_mw( h_mw->h_ci_mw, status, + mw_ioctl.out.rkey, &junk, &mw_ioctl.out.umv_buf ); + } + + AL_EXIT( AL_DBG_MW ); + return status; +} + + +ib_api_status_t +ual_bind_mw( + IN const ib_mw_handle_t h_mw, + IN const ib_qp_handle_t h_qp, + IN ib_bind_wr_t* p_mw_bind, + OUT net32_t* const p_rkey ) +{ + ual_bind_mw_ioctl_t mw_ioctl; + cl_status_t cl_status; + ib_api_status_t status; + uintn_t bytes_ret; + ib_mr_handle_t h_user_mr; + /* + * Check whether a vendor library is available and the + * bind_mw call is implemented. If so, the call terminates + * at the UVP library. If not, pass this to kernel. + */ + uvp_interface_t uvp_intf = h_mw->obj.p_ci_ca->verbs.user_verbs; + + AL_ENTER( AL_DBG_MW ); + + /* Clear the mw_ioctl */ + cl_memclr( &mw_ioctl, sizeof(mw_ioctl) ); + + /* Call to the UVP library */ + if( h_mw->h_ci_mw && h_qp->h_ci_qp && uvp_intf.bind_mw ) + { + h_user_mr = p_mw_bind->h_mr; + p_mw_bind->h_mr = p_mw_bind->h_mr->h_ci_mr; + status = uvp_intf.bind_mw( h_mw->h_ci_mw, + h_qp->h_ci_qp, p_mw_bind, p_rkey); + p_mw_bind->h_mr = h_user_mr; + AL_EXIT( AL_DBG_MW ); + return status; + } + + mw_ioctl.in.h_mw = h_mw->obj.hdl; + mw_ioctl.in.h_qp = h_qp->obj.hdl; + mw_ioctl.in.mw_bind = *p_mw_bind; + mw_ioctl.in.mw_bind.h_mr_padding = p_mw_bind->h_mr->obj.hdl; + + cl_status = do_al_dev_ioctl( UAL_BIND_MW, + &mw_ioctl.in, sizeof(mw_ioctl.in), &mw_ioctl.out, sizeof(mw_ioctl.out), + &bytes_ret ); + + if( cl_status != CL_SUCCESS || bytes_ret != sizeof(mw_ioctl.out) ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("UAL_BIND_MW IOCTL returned %s.\n", + CL_STATUS_MSG(cl_status)) ); + status = IB_ERROR; + } + else if( mw_ioctl.out.status == IB_SUCCESS ) + { + *p_rkey = mw_ioctl.out.r_key; + } + + AL_EXIT( AL_DBG_MW ); + return mw_ioctl.out.status; +} diff --git a/branches/WOF2-3/core/al/user/ual_pd.c b/branches/WOF2-3/core/al/user/ual_pd.c new file mode 100644 index 00000000..3d58cd09 --- /dev/null +++ b/branches/WOF2-3/core/al/user/ual_pd.c @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include "ual_support.h" +#include "al.h" +#include "al_ca.h" +#include "al_pd.h" + + +#include "al_debug.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "ual_pd.tmh" +#endif + +ib_api_status_t +ual_allocate_pd( + IN ib_ca_handle_t h_ca, + IN const ib_pd_type_t pd_type, + IN OUT ib_pd_handle_t h_pd ) +{ + /* The first two arguments is probably not needed */ + ual_alloc_pd_ioctl_t pd_ioctl; + uintn_t bytes_ret; + cl_status_t cl_status; + ib_api_status_t status; + ib_ca_handle_t h_uvp_ca; + uvp_interface_t uvp_intf = h_ca->obj.p_ci_ca->verbs.user_verbs; + + AL_ENTER( AL_DBG_PD ); + + /* Clear the pd_ioctl */ + cl_memclr( &pd_ioctl, sizeof(pd_ioctl) ); + + h_uvp_ca = h_ca->obj.p_ci_ca->h_ci_ca; + + /* Pre call to the UVP library */ + if( pd_type != IB_PDT_ALIAS && h_uvp_ca && uvp_intf.pre_allocate_pd ) + { + status = uvp_intf.pre_allocate_pd( h_uvp_ca, &pd_ioctl.in.umv_buf, &h_pd->h_ci_pd ); + if( status != IB_SUCCESS ) + { + AL_EXIT( AL_DBG_PD ); + return status; + } + } + + pd_ioctl.in.h_ca = h_ca->obj.p_ci_ca->obj.hdl; + pd_ioctl.in.type = pd_type; + pd_ioctl.in.context = (ULONG_PTR)h_pd; + + cl_status = do_al_dev_ioctl( UAL_ALLOC_PD, + &pd_ioctl.in, sizeof(pd_ioctl.in), &pd_ioctl.out, sizeof(pd_ioctl.out), + &bytes_ret ); + + if( cl_status != CL_SUCCESS || bytes_ret != sizeof(pd_ioctl.out) ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("UAL_ALLOC_PD IOCTL returned %s.\n", + CL_STATUS_MSG(cl_status)) ); + status = IB_ERROR; + } + else + { + status = pd_ioctl.out.status; + if( status == IB_SUCCESS ) + h_pd->obj.hdl = pd_ioctl.out.h_pd; + + } + + + + /* Post uvp call */ + if( pd_type != IB_PDT_ALIAS && h_uvp_ca && uvp_intf.post_allocate_pd ) + { + uvp_intf.post_allocate_pd( h_uvp_ca, status, + &h_pd->h_ci_pd, &pd_ioctl.out.umv_buf ); + } + + AL_EXIT( AL_DBG_PD ); + return status; +} + + +ib_api_status_t +ual_deallocate_pd( + IN ib_pd_handle_t h_pd ) +{ + ual_dealloc_pd_ioctl_t pd_ioctl; + uintn_t bytes_ret; + cl_status_t cl_status; + ib_api_status_t status; + uvp_interface_t uvp_intf = h_pd->obj.p_ci_ca->verbs.user_verbs; + + AL_ENTER( AL_DBG_PD ); + + /* Clear the pd_ioctl */ + cl_memclr( &pd_ioctl, sizeof(pd_ioctl) ); + + /* Call the uvp pre call if the vendor library provided a valid ca handle */ + if( h_pd->h_ci_pd && uvp_intf.pre_deallocate_pd ) + { + /* Pre call to the UVP library */ + status = uvp_intf.pre_deallocate_pd( h_pd->h_ci_pd ); + if( status != IB_SUCCESS ) + { + AL_EXIT( AL_DBG_PD ); + return status; + } + } + + pd_ioctl.in.h_pd = h_pd->obj.hdl; + + cl_status = do_al_dev_ioctl( UAL_DEALLOC_PD, + &pd_ioctl.in, sizeof(pd_ioctl.in), &pd_ioctl.out, sizeof(pd_ioctl.out), + &bytes_ret ); + + if( cl_status != CL_SUCCESS || bytes_ret != sizeof(pd_ioctl.out) ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("UAL_DEALLOC_PD IOCTL returned %s.\n", + CL_STATUS_MSG(cl_status)) ); + status = IB_ERROR; + } + else + { + status = pd_ioctl.out.status; + } + + /* Call vendor's post_close ca */ + if( h_pd->h_ci_pd && uvp_intf.post_deallocate_pd ) + uvp_intf.post_deallocate_pd( h_pd->h_ci_pd, status ); + + + AL_EXIT( AL_DBG_PD ); + return status; +} diff --git a/branches/WOF2-3/core/al/user/ual_pnp.c b/branches/WOF2-3/core/al/user/ual_pnp.c new file mode 100644 index 00000000..d0eb3972 --- /dev/null +++ b/branches/WOF2-3/core/al/user/ual_pnp.c @@ -0,0 +1,568 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +/* + * Handles all PnP-related interaction for user-mode: + */ +#include + +#include "al.h" +#include "al_debug.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "ual_pnp.tmh" +#endif + +#include "al_mgr.h" +#include "al_pnp.h" +#include "ib_common.h" +#include "al_ioc_pnp.h" + + +#define PNP_CA_VECTOR_MIN 0 +#define PNP_CA_VECTOR_GROW 10 + + +/* ib_pnp_event_t values converted to text strings. */ +char* ib_pnp_event_str[] = +{ + "IB_PNP_CA_ADD", + "IB_PNP_CA_REMOVE", + "IB_PNP_PORT_ADD", + "IB_PNP_PORT_REMOVE", + "IB_PNP_PORT_INIT", + "IB_PNP_PORT_ARMED", + "IB_PNP_PORT_ACTIVE", + "IB_PNP_PORT_DOWN", + "IB_PNP_PKEY_CHANGE", + "IB_PNP_SM_CHANGE", + "IB_PNP_GID_CHANGE", + "IB_PNP_LID_CHANGE", + "IB_PNP_SUBNET_TIMEOUT_CHANGE", + "IB_PNP_IOU_ADD", + "IB_PNP_IOU_REMOVE", + "IB_PNP_IOC_ADD", + "IB_PNP_IOC_REMOVE", + "IB_PNP_IOC_PATH_ADD", + "IB_PNP_IOC_PATH_REMOVE" +}; + + +/* PnP Manager structure. */ +typedef struct _ual_pnp_mgr +{ + al_obj_t obj; + + /* File handle on which to issue asynchronous PnP IOCTLs. */ + HANDLE h_file; + HANDLE h_destroy_file; + +} ual_pnp_mgr_t; + + +/* + * PnP Manager instance, creation, destruction. + */ + +/* Global instance of the PnP manager. */ +ual_pnp_mgr_t *gp_pnp = NULL; + + +/* + * Declarations. + */ +static void +__pnp_free( + IN al_obj_t *p_obj ); + +static void +__pnp_async_cb( + IN cl_async_proc_item_t *p_item ); + + +ib_api_status_t +create_pnp( + IN al_obj_t* const p_parent_obj ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_PNP ); + + CL_ASSERT( gp_pnp == NULL ); + + gp_pnp = (ual_pnp_mgr_t*)cl_zalloc( sizeof(ual_pnp_mgr_t) ); + if( !gp_pnp ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("Failed to allocate PnP manager.\n") ); + return IB_INSUFFICIENT_MEMORY; + } + + construct_al_obj( &gp_pnp->obj, AL_OBJ_TYPE_PNP_MGR ); + gp_pnp->h_file = INVALID_HANDLE_VALUE; + gp_pnp->h_destroy_file = INVALID_HANDLE_VALUE; + + status = init_al_obj( &gp_pnp->obj, NULL, TRUE, NULL, NULL, __pnp_free ); + if( status != IB_SUCCESS ) + { + __pnp_free( &gp_pnp->obj ); + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("init_al_obj() failed with status %s.\n", ib_get_err_str(status)) ); + return status; + } + status = attach_al_obj( p_parent_obj, &gp_pnp->obj ); + if( status != IB_SUCCESS ) + { + gp_pnp->obj.pfn_destroy( &gp_pnp->obj, NULL ); + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("attach_al_obj returned %s.\n", ib_get_err_str(status)) ); + return status; + } + + /* Create a file object on which to issue all PNP requests. */ + gp_pnp->h_file = ual_create_async_file( UAL_BIND_PNP ); + if( gp_pnp->h_file == INVALID_HANDLE_VALUE ) + { + gp_pnp->obj.pfn_destroy( &gp_pnp->obj, NULL ); + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("ual_create_async_file for UAL_BIND_PNP returned %d.\n", + GetLastError()) ); + return IB_ERROR; + } + + /* Create a file object on which to issue all dereg request. */ + gp_pnp->h_destroy_file = ual_create_async_file( UAL_BIND_DESTROY ); + if( gp_pnp->h_destroy_file == INVALID_HANDLE_VALUE ) + { + gp_pnp->obj.pfn_destroy( &gp_pnp->obj, NULL ); + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("ual_create_async_file for UAL_BIND_DESTROY returned %d.\n", + GetLastError()) ); + return IB_ERROR; + } + + /* Release the reference taken in init_al_obj. */ + deref_al_obj( &gp_pnp->obj ); + + AL_EXIT( AL_DBG_PNP ); + return( IB_SUCCESS ); +} + + +static void +__pnp_free( + IN al_obj_t *p_obj ) +{ + AL_ENTER( AL_DBG_PNP ); + + CL_ASSERT( PARENT_STRUCT( p_obj, ual_pnp_mgr_t, obj ) == gp_pnp ); + UNUSED_PARAM( p_obj ); + + if( gp_pnp->h_file != INVALID_HANDLE_VALUE ) + CloseHandle( gp_pnp->h_file ); + if( gp_pnp->h_destroy_file != INVALID_HANDLE_VALUE ) + CloseHandle( gp_pnp->h_destroy_file ); + + destroy_al_obj( &gp_pnp->obj ); + cl_free( gp_pnp ); + gp_pnp = NULL; + + AL_EXIT( AL_DBG_PNP ); +} + + +static void +__pnp_reg_destroying( + IN al_obj_t *p_obj ) +{ + al_pnp_t *p_reg; + + AL_ENTER( AL_DBG_PNP ); + + p_reg = PARENT_STRUCT( p_obj, al_pnp_t, obj ); + + /* Reference the registration entry while we queue it to our PnP thread. */ + ref_al_obj( &p_reg->obj ); + + /* + * Store the pointer to the object so we can dereference it + * in the completion callback. + */ + p_reg->destroy_ov.Pointer = &p_reg->obj; + + if( !DeviceIoControl( gp_pnp->h_destroy_file, UAL_DEREG_PNP, + &p_reg->obj.hdl, sizeof(uint64_t), NULL, 0, + NULL, &p_reg->destroy_ov ) ) + { + if( GetLastError() != ERROR_IO_PENDING ) + deref_al_obj( &p_reg->obj ); + } + else + { + CL_ASSERT( GetLastError() == ERROR_IO_PENDING ); + deref_al_obj( &p_reg->obj ); + } + + AL_EXIT( AL_DBG_PNP ); +} + + +static void +__pnp_reg_free( + IN al_obj_t *p_obj ) +{ + al_pnp_t *p_reg; + + AL_ENTER( AL_DBG_PNP ); + + p_reg = PARENT_STRUCT( p_obj, al_pnp_t, obj ); + + /* Dereference the PnP manager. */ + deref_al_obj( &gp_pnp->obj ); + + /* Free the registration structure. */ + destroy_al_obj( &p_reg->obj ); + cl_free( p_reg ); + + AL_EXIT( AL_DBG_PNP ); +} + + +ib_api_status_t +ib_reg_pnp( + IN const ib_al_handle_t h_al, + IN const ib_pnp_req_t* const p_pnp_req, + OUT ib_pnp_handle_t* const ph_pnp ) +{ + ib_api_status_t status; + al_pnp_t* p_reg; + ual_reg_pnp_ioctl_in_t in; + + AL_ENTER( AL_DBG_PNP ); + + if( AL_OBJ_INVALID_HANDLE( h_al, AL_OBJ_TYPE_H_AL ) ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, ("IB_INVALID_AL_HANDLE\n") ); + return IB_INVALID_AL_HANDLE; + } + if( !p_pnp_req || !ph_pnp ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") ); + return IB_INVALID_PARAMETER; + } + + /* Allocate a new registration info structure. */ + p_reg = (al_pnp_t*)cl_zalloc( sizeof(al_pnp_t) ); + if( !p_reg ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("Failed to cl_zalloc al_pnp_t (%I64d bytes).\n", + sizeof(al_pnp_t)) ); + return( IB_INSUFFICIENT_MEMORY ); + } + + /* Initialize the registration info. */ + construct_al_obj( &p_reg->obj, AL_OBJ_TYPE_H_PNP ); + p_reg->async_item.pfn_callback = __pnp_async_cb; + + status = init_al_obj( &p_reg->obj, p_pnp_req->pnp_context, TRUE, + __pnp_reg_destroying, NULL, __pnp_reg_free ); + if( status != IB_SUCCESS ) + { + __pnp_reg_free( &p_reg->obj ); + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("init_al_obj() failed with status %s.\n", ib_get_err_str(status)) ); + return( status ); + } + status = attach_al_obj( &h_al->obj, &p_reg->obj ); + if( status != IB_SUCCESS ) + { + p_reg->obj.pfn_destroy( &p_reg->obj, NULL ); + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("attach_al_obj returned %s.\n", ib_get_err_str(status)) ); + return status; + } + + /* Reference the PnP Manager. */ + ref_al_obj( &gp_pnp->obj ); + + /* Copy the request information. */ + p_reg->pfn_pnp_cb = p_pnp_req->pfn_pnp_cb; + + in.pnp_class = p_pnp_req->pnp_class; + in.p_status = (ULONG_PTR)&status; + in.p_hdl = (ULONG_PTR)&p_reg->obj.hdl; + + if( pnp_get_flag( p_pnp_req->pnp_class ) & IB_PNP_FLAG_REG_SYNC ) + { + in.sync_event = HandleToHandle64( CreateEvent( NULL, FALSE, FALSE, NULL ) ); + if( !in.sync_event ) + { + p_reg->obj.pfn_destroy( &p_reg->obj, NULL ); + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("CreateEvent returned %d\n", GetLastError()) ); + return IB_ERROR; + } + } + + status = IB_ERROR; + + /* The IOCTL handler will update status as needed. */ + DeviceIoControl( gp_pnp->h_file, UAL_REG_PNP, + &in, sizeof(in), &p_reg->rearm, sizeof(p_reg->rearm), + NULL, &p_reg->ov ); + + if( status == IB_SUCCESS ) + { + /* Set the user handle. */ + *ph_pnp = p_reg; + + /* + * Note that we don't release the reference taken by init_al_obj while + * any IOCTLs are in progress. + */ + + if( pnp_get_flag( p_pnp_req->pnp_class ) & IB_PNP_FLAG_REG_SYNC ) + { + WaitForSingleObject( in.sync_event, INFINITE ); + CloseHandle( in.sync_event ); + } + } + else + { + p_reg->obj.pfn_destroy( &p_reg->obj, NULL ); + } + + AL_EXIT( AL_DBG_PNP ); + return status; +} + + +ib_api_status_t +ib_dereg_pnp( + IN const ib_pnp_handle_t h_pnp, + IN const ib_pfn_destroy_cb_t pfn_destroy_cb OPTIONAL ) +{ + AL_ENTER( AL_DBG_PNP ); + + if( AL_OBJ_INVALID_HANDLE( h_pnp, AL_OBJ_TYPE_H_PNP ) ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, ("IB_INVALID_HANDLE\n") ); + return IB_INVALID_HANDLE; + } + + ref_al_obj( &h_pnp->obj ); + h_pnp->obj.pfn_destroy( &h_pnp->obj, pfn_destroy_cb ); + + AL_EXIT( AL_DBG_PNP ); + return( IB_SUCCESS ); +} + + +ib_api_status_t +ib_reject_ioc( + IN const ib_al_handle_t h_al, + IN const ib_pnp_handle_t h_event ) +{ + AL_ENTER( AL_DBG_PNP ); + + if( AL_OBJ_INVALID_HANDLE( h_al, AL_OBJ_TYPE_H_AL ) ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, ("IB_INVALID_AL_HANDLE\n") ); + return IB_INVALID_AL_HANDLE; + } + if( !h_event ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, ("IB_INVALID_HANDLE\n") ); + return IB_INVALID_HANDLE; + } + + AL_EXIT( AL_DBG_PNP ); + return IB_UNSUPPORTED; +} + + +static void +__fix_port_attr( + IN OUT ib_pnp_port_rec_t* const p_port_rec ) +{ + uintn_t offset; + + if( !p_port_rec->p_ca_attr ) + return; + + offset = (uintn_t)(p_port_rec + 1) - + (uintn_t)(ib_ca_attr_t*)p_port_rec->p_ca_attr; + ib_fixup_ca_attr( (ib_ca_attr_t*)(p_port_rec + 1), p_port_rec->p_ca_attr ); + p_port_rec->p_ca_attr = (ib_ca_attr_t*)(size_t)(p_port_rec + 1); + p_port_rec->p_port_attr = (ib_port_attr_t*) + (((uint8_t*)p_port_rec->p_port_attr) + offset); +} + + +static void +__fix_ca_attr( + IN OUT ib_pnp_ca_rec_t* const p_ca_rec ) +{ + if( !p_ca_rec->p_ca_attr ) + return; + + ib_fixup_ca_attr( (ib_ca_attr_t*)(p_ca_rec + 1), p_ca_rec->p_ca_attr ); + p_ca_rec->p_ca_attr = (ib_ca_attr_t*)(size_t)(p_ca_rec + 1); +} + + +static void +__pnp_async_cb( + IN cl_async_proc_item_t *p_item ) +{ + al_pnp_t *p_reg; + ual_rearm_pnp_ioctl_in_t in; + cl_status_t status; + size_t bytes_ret; + ib_pnp_rec_t *p_pnp_rec; + + AL_ENTER( AL_DBG_PNP ); + + p_reg = PARENT_STRUCT( p_item, al_pnp_t, async_item ); + + in.pnp_hdl = p_reg->obj.hdl; + in.last_evt_hdl = p_reg->rearm.evt_hdl; + in.last_evt_context = 0; + + if( p_reg->rearm.evt_size ) + { + /* Retrieve the PnP event and report it to the client. */ + CL_ASSERT( p_reg->rearm.evt_size >= sizeof(ib_pnp_rec_t) ); + + p_pnp_rec = (ib_pnp_rec_t*)cl_malloc( p_reg->rearm.evt_size ); + if( p_pnp_rec ) + { + status = do_al_dev_ioctl( UAL_POLL_PNP, + &p_reg->rearm.evt_hdl, sizeof(uint64_t), + p_pnp_rec, p_reg->rearm.evt_size, &bytes_ret ); + + if( status == CL_SUCCESS ) + { + CL_ASSERT( bytes_ret == p_reg->rearm.evt_size ); + /* Fixup pointers. */ + switch( pnp_get_class( p_pnp_rec->pnp_event ) ) + { + case IB_PNP_PORT: + __fix_port_attr( (ib_pnp_port_rec_t*)p_pnp_rec ); + break; + case IB_PNP_CA: + __fix_ca_attr( (ib_pnp_ca_rec_t*)p_pnp_rec ); + break; + default: + break; + } + p_pnp_rec->pnp_context = (void*)p_reg->obj.context; + in.last_evt_status = p_reg->pfn_pnp_cb( p_pnp_rec ); + in.last_evt_context = (ULONG_PTR)p_pnp_rec->context; + } + else + { + in.last_evt_status = IB_SUCCESS; + } + + if( p_pnp_rec ) + cl_free( p_pnp_rec ); + } + else + { + in.last_evt_status = IB_SUCCESS; + } + } + else + { + in.last_evt_status = IB_SUCCESS; + } + + /* Request the next PnP event. */ + DeviceIoControl( gp_pnp->h_file, UAL_REARM_PNP, + &in, sizeof(in), &p_reg->rearm, sizeof(p_reg->rearm), + NULL, &p_reg->ov ); + + if( GetLastError() != ERROR_IO_PENDING ) + { + /* Release the reference taken for the IOCTL. */ + deref_al_obj( &p_reg->obj ); + } + + CL_ASSERT( GetLastError() == ERROR_IO_PENDING || + GetLastError() == ERROR_CANCELLED || + GetLastError() == ERROR_OPERATION_ABORTED ); + + AL_EXIT( AL_DBG_PNP ); +} + + +void CALLBACK +pnp_cb( + IN DWORD error_code, + IN DWORD ret_bytes, + IN LPOVERLAPPED p_ov ) +{ + al_pnp_t *p_reg; + + AL_ENTER( AL_DBG_PNP ); + + CL_ASSERT( p_ov ); + + p_reg = PARENT_STRUCT( p_ov, al_pnp_t, ov ); + if( error_code || ret_bytes != sizeof(p_reg->rearm) ) + { + if( error_code == ERROR_CANCELLED || + error_code == ERROR_OPERATION_ABORTED || + p_reg->obj.state != CL_INITIALIZED ) + { + /* Release the reference taken for the IOCTL. */ + deref_al_obj( &p_reg->obj ); + AL_EXIT( AL_DBG_PNP ); + return; + } + + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , ("IOCTL failed with error code %d\n", + error_code) ); + p_reg->rearm.evt_hdl = AL_INVALID_HANDLE; + p_reg->rearm.evt_size = 0; + } + + cl_async_proc_queue( gp_async_pnp_mgr, &p_reg->async_item ); + + AL_EXIT( AL_DBG_PNP ); +} diff --git a/branches/WOF2-3/core/al/user/ual_qp.c b/branches/WOF2-3/core/al/user/ual_qp.c new file mode 100644 index 00000000..0b39de4a --- /dev/null +++ b/branches/WOF2-3/core/al/user/ual_qp.c @@ -0,0 +1,673 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include "al.h" +#include "al_av.h" +#include "al_ci_ca.h" +#include "al_cq.h" +#include "al_pd.h" +#include "al_qp.h" +#include "al_srq.h" +#include "ual_mad.h" +#include "ual_support.h" + + +#include "al_debug.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "ual_qp.tmh" +#endif +ib_api_status_t +ual_post_send( + IN const ib_qp_handle_t h_qp, + IN ib_send_wr_t* const p_send_wr, + OUT ib_send_wr_t **pp_send_failure OPTIONAL ) +{ + uintn_t failed_index; + uintn_t bytes_ret; + uint32_t num_wr = 0; + uint32_t num_ds = 0; + ib_send_wr_t *p_wr; + ib_local_ds_t *p_ds; + ual_post_send_ioctl_t *p_qp_ioctl; + size_t ioctl_buf_sz; + cl_status_t cl_status; + ib_api_status_t status; + + AL_ENTER( AL_DBG_QP ); + + /* + * Since the work request is a link list and we need to pass this + * to the kernel as a array of work requests. So first walk through + * the list and find out how much memory we need to allocate. + */ + for( p_wr = p_send_wr; p_wr; p_wr = p_wr->p_next ) + { + num_wr++; + + /* Check for overflow */ + if( !num_wr ) + break; + if( num_ds > num_ds + p_wr->num_ds ) + { + num_wr = 0; + break; + } + + num_ds += p_wr->num_ds; + } + if( !num_wr ) + { + AL_EXIT( AL_DBG_QP ); + return IB_INVALID_PARAMETER; + } + + ioctl_buf_sz = sizeof(ual_post_send_ioctl_t); + ioctl_buf_sz += sizeof(ib_send_wr_t) * (num_wr - 1); + ioctl_buf_sz += sizeof(ib_local_ds_t) * num_ds; + + p_qp_ioctl = (ual_post_send_ioctl_t*)cl_zalloc( ioctl_buf_sz ); + if( !p_qp_ioctl ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("Failed to allocate IOCTL buffer.\n") ); + return IB_INSUFFICIENT_MEMORY; + } + p_ds = (ib_local_ds_t*)&p_qp_ioctl->in.send_wr[num_wr]; + + /* Now populate the ioctl buffer and send down the ioctl */ + p_qp_ioctl->in.h_qp = h_qp->obj.hdl; + p_qp_ioctl->in.num_wr = num_wr; + p_qp_ioctl->in.num_ds = num_ds; + num_wr = 0; + for( p_wr = p_send_wr; p_wr; p_wr = p_wr->p_next ) + { + /* pNext and pDs pointer is set by the kernel proxy. */ + p_qp_ioctl->in.send_wr[num_wr] = *p_wr; + if( h_qp->type == IB_QPT_UNRELIABLE_DGRM ) + { + p_qp_ioctl->in.send_wr[num_wr].dgrm.ud.h_av = + (ib_av_handle_t) (ULONG_PTR) p_wr->dgrm.ud.h_av->obj.hdl; + } + num_wr++; + cl_memcpy( + p_ds, p_wr->ds_array, sizeof(ib_local_ds_t) * p_wr->num_ds ); + p_ds += p_wr->num_ds; + } + + cl_status = do_al_dev_ioctl( UAL_POST_SEND, + &p_qp_ioctl->in, ioctl_buf_sz, + &p_qp_ioctl->out, sizeof(p_qp_ioctl->out), + &bytes_ret ); + + if( cl_status != CL_SUCCESS || bytes_ret != sizeof(p_qp_ioctl->out) ) + { + if( pp_send_failure ) + *pp_send_failure = p_send_wr; + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("UAL_POST_SEND IOCTL returned %s.\n", + CL_STATUS_MSG(cl_status)) ); + status = IB_ERROR; + } + else + { + status = p_qp_ioctl->out.status; + + if( status != IB_SUCCESS && pp_send_failure ) + { + /* Get the failed index */ + failed_index = num_wr - p_qp_ioctl->out.failed_cnt; + p_wr = p_send_wr; + while( failed_index-- ) + p_wr = p_wr->p_next; + + *pp_send_failure = p_wr; + } + } + + cl_free( p_qp_ioctl ); + AL_EXIT( AL_DBG_QP ); + return status; +} + + +ib_api_status_t +ual_post_recv( + IN const ib_qp_handle_t h_qp, + IN ib_recv_wr_t* const p_recv_wr, + OUT ib_recv_wr_t **pp_recv_failure OPTIONAL ) +{ + uintn_t failed_index; + uintn_t bytes_ret; + uint32_t num_wr = 0; + uint32_t num_ds = 0; + ib_recv_wr_t* p_wr; + ib_local_ds_t* p_ds; + ual_post_recv_ioctl_t *p_qp_ioctl; + size_t ioctl_buf_sz; + cl_status_t cl_status; + ib_api_status_t status; + + AL_ENTER( AL_DBG_QP ); + + /* + * Since the work request is a link list and we need to pass this + * to the kernel as a array of work requests. So first walk through + * the list and find out how much memory we need to allocate. + */ + for( p_wr = p_recv_wr; p_wr; p_wr = p_wr->p_next ) + { + num_wr++; + + /* Check for overflow */ + if( !num_wr ) + break; + if( num_ds > num_ds + p_wr->num_ds ) + { + num_wr = 0; + break; + } + + num_ds += p_wr->num_ds; + } + if( !num_wr ) + { + AL_EXIT( AL_DBG_QP ); + return IB_INVALID_PARAMETER; + } + + ioctl_buf_sz = sizeof(ual_post_recv_ioctl_t); + ioctl_buf_sz += sizeof(ib_recv_wr_t) * (num_wr - 1); + ioctl_buf_sz += sizeof(ib_local_ds_t) * num_ds; + + p_qp_ioctl = (ual_post_recv_ioctl_t*)cl_zalloc( ioctl_buf_sz ); + if( !p_qp_ioctl ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("Failed to allocate IOCTL buffer.\n") ); + return IB_INSUFFICIENT_MEMORY; + } + p_ds = (ib_local_ds_t*)&p_qp_ioctl->in.recv_wr[num_wr]; + + /* Now populate the ioctl buffer and send down the ioctl */ + p_qp_ioctl->in.h_qp = h_qp->obj.hdl; + p_qp_ioctl->in.num_wr = num_wr; + p_qp_ioctl->in.num_ds = num_ds; + num_wr = 0; + for( p_wr = p_recv_wr; p_wr; p_wr = p_wr->p_next ) + { + /* pNext and pDs pointer is set by the kernel proxy. */ + p_qp_ioctl->in.recv_wr[num_wr++] = *p_wr; + cl_memcpy( + p_ds, p_wr->ds_array, sizeof(ib_local_ds_t) * p_wr->num_ds ); + p_ds += p_wr->num_ds; + } + + cl_status = do_al_dev_ioctl( UAL_POST_RECV, + &p_qp_ioctl->in, ioctl_buf_sz, + &p_qp_ioctl->out, sizeof(p_qp_ioctl->out), + &bytes_ret ); + + if( cl_status != CL_SUCCESS || bytes_ret != sizeof(p_qp_ioctl->out) ) + { + if( pp_recv_failure ) + *pp_recv_failure = p_recv_wr; + + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("UAL_POST_RECV IOCTL returned %s.\n", + CL_STATUS_MSG(cl_status)) ); + status = IB_ERROR; + } + else + { + status = p_qp_ioctl->out.status; + + if( status != IB_SUCCESS && pp_recv_failure ) + { + /* Get the failed index */ + failed_index = num_wr - p_qp_ioctl->out.failed_cnt; + p_wr = p_recv_wr; + while( failed_index-- ) + p_wr = p_wr->p_next; + + *pp_recv_failure = p_wr; + } + } + + cl_free( p_qp_ioctl ); + AL_EXIT( AL_DBG_QP ); + return status; +} + + + +ib_api_status_t +ual_create_qp( + IN const ib_pd_handle_t h_pd, + IN OUT ib_qp_handle_t h_qp, + IN const ib_qp_create_t* const p_qp_create, + IN ib_qp_attr_t* p_qp_attr ) +{ + /* The first argument is probably not needed */ + ual_create_qp_ioctl_t qp_ioctl; + uintn_t bytes_ret; + cl_status_t cl_status; + ib_api_status_t status; + ib_api_status_t uvp_status = IB_SUCCESS; + uvp_interface_t uvp_intf = h_qp->obj.p_ci_ca->verbs.user_verbs; + ib_qp_create_t qp_create; + + AL_ENTER( AL_DBG_QP ); + UNUSED_PARAM( p_qp_attr ); + + /* Clear the qp_ioctl */ + cl_memclr( &qp_ioctl, sizeof(qp_ioctl) ); + + /* Pre call to the UVP library */ + if( h_pd->h_ci_pd && uvp_intf.pre_create_qp ) + { + /* The post call MUST exist as it sets the UVP QP handle. */ + CL_ASSERT( uvp_intf.post_create_qp ); + /* Convert the handles to UVP handles */ + qp_create = *p_qp_create; + qp_create.h_rq_cq = qp_create.h_rq_cq->h_ci_cq; + qp_create.h_sq_cq = qp_create.h_sq_cq->h_ci_cq; + if (qp_create.h_srq) + qp_create.h_srq = qp_create.h_srq->h_ci_srq; + status = uvp_intf.pre_create_qp( h_pd->h_ci_pd, + &qp_create, &qp_ioctl.in.umv_buf, &h_qp->h_ci_qp ); + if( status != IB_SUCCESS ) + { + AL_EXIT( AL_DBG_QP ); + return status; + } + } + /* + * Convert the handles to KAL handles once again starting + * from the input qp attribute + */ + qp_ioctl.in.h_pd = h_pd->obj.hdl; + qp_ioctl.in.qp_create = *p_qp_create; + qp_ioctl.in.qp_create.h_rq_cq_padding = p_qp_create->h_rq_cq->obj.hdl; + qp_ioctl.in.qp_create.h_sq_cq_padding = p_qp_create->h_sq_cq->obj.hdl; + if (p_qp_create->h_srq) + { + qp_ioctl.in.qp_create.h_srq_padding = p_qp_create->h_srq->obj.hdl; + } + qp_ioctl.in.context = (ULONG_PTR)h_qp; + qp_ioctl.in.ev_notify = (h_qp->pfn_event_cb != NULL) ? TRUE : FALSE; + + cl_status = do_al_dev_ioctl( UAL_CREATE_QP, + &qp_ioctl.in, sizeof(qp_ioctl.in), &qp_ioctl.out, sizeof(qp_ioctl.out), + &bytes_ret ); + + if( cl_status != CL_SUCCESS || bytes_ret != sizeof(qp_ioctl.out) ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("UAL_CREATE_QP IOCTL returned %s.\n", + CL_STATUS_MSG(cl_status)) ); + status = IB_ERROR; + } + else + { + status = qp_ioctl.out.status; + + if( status == IB_SUCCESS ) + { + h_qp->obj.hdl = qp_ioctl.out.h_qp; + *p_qp_attr = qp_ioctl.out.attr; + } + } + + /* Post uvp call */ + if( h_pd->h_ci_pd && uvp_intf.post_create_qp ) + { + uvp_status = uvp_intf.post_create_qp( h_pd->h_ci_pd, + status, &h_qp->h_ci_qp, &qp_ioctl.out.umv_buf ); + + if( uvp_intf.post_recv ) + { + h_qp->h_recv_qp = h_qp->h_ci_qp; + h_qp->pfn_post_recv = uvp_intf.post_recv; + } + else + { + h_qp->h_recv_qp = h_qp; + h_qp->pfn_post_recv = ual_post_recv; + } + + if( uvp_intf.post_send ) + { + h_qp->h_send_qp = h_qp->h_ci_qp; + h_qp->pfn_post_send = uvp_intf.post_send; + } + else + { + h_qp->h_send_qp = h_qp; + h_qp->pfn_post_send = ual_post_send; + } + } + else + { + h_qp->h_recv_qp = h_qp; + h_qp->pfn_post_recv = ual_post_recv; + h_qp->h_send_qp = h_qp; + h_qp->pfn_post_send = ual_post_send; + } + + if( (status == IB_SUCCESS) && (uvp_status != IB_SUCCESS) ) + status = uvp_status; + + AL_EXIT( AL_DBG_QP ); + return status; +} + + + +ib_api_status_t +ual_destroy_qp( + IN ib_qp_handle_t h_qp ) +{ + ual_destroy_qp_ioctl_t qp_ioctl; + uintn_t bytes_ret; + cl_status_t cl_status; + ib_api_status_t status; + uvp_interface_t uvp_intf = h_qp->obj.p_ci_ca->verbs.user_verbs; + + AL_ENTER( AL_DBG_QP ); + + /* Call the uvp pre call if the vendor library provided a valid QP handle */ + if( h_qp->h_ci_qp && uvp_intf.pre_destroy_qp ) + { + status = uvp_intf.pre_destroy_qp( h_qp->h_ci_qp ); + if (status != IB_SUCCESS) + { + AL_EXIT( AL_DBG_QP ); + return status; + } + } + + cl_memclr( &qp_ioctl, sizeof(qp_ioctl) ); + qp_ioctl.in.h_qp = h_qp->obj.hdl; + cl_status = do_al_dev_ioctl( UAL_DESTROY_QP, + &qp_ioctl.in, sizeof(qp_ioctl.in), &qp_ioctl.out, sizeof(qp_ioctl.out), + &bytes_ret ); + + if( cl_status != CL_SUCCESS || bytes_ret != sizeof(qp_ioctl.out) ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("UAL_DESTROY_QP IOCTL returned %s.\n", + CL_STATUS_MSG(cl_status)) ); + status = IB_ERROR; + } + else + { + status = qp_ioctl.out.status; + } + + /* Call vendor's post_destroy_qp */ + if( h_qp->h_ci_qp && uvp_intf.post_destroy_qp ) + uvp_intf.post_destroy_qp( h_qp->h_ci_qp, status ); + + AL_EXIT( AL_DBG_QP ); + return status; +} + + +ib_api_status_t +ual_modify_qp( + IN ib_qp_handle_t h_qp, + IN const ib_qp_mod_t* const p_qp_mod, + IN ib_qp_attr_t* p_qp_attr) +{ + ual_modify_qp_ioctl_t qp_ioctl; + uintn_t bytes_ret; + cl_status_t cl_status; + ib_api_status_t status; + uvp_interface_t uvp_intf = h_qp->obj.p_ci_ca->verbs.user_verbs; + + AL_ENTER( AL_DBG_QP ); + + /* Clear the qp_ioctl */ + cl_memclr( &qp_ioctl, sizeof(qp_ioctl) ); + + /* Call the uvp pre call if the vendor library provided a valid QP handle */ + if( h_qp->h_ci_qp && uvp_intf.pre_modify_qp ) + { + /* Pre call to the UVP library */ + status = uvp_intf.pre_modify_qp( h_qp->h_ci_qp, + p_qp_mod, &qp_ioctl.in.umv_buf ); + if( status != IB_SUCCESS ) + { + AL_EXIT( AL_DBG_QP ); + return status; + } + } + + qp_ioctl.in.h_qp = h_qp->obj.hdl; + qp_ioctl.in.modify_attr = *p_qp_mod; + + cl_status = do_al_dev_ioctl( UAL_MODIFY_QP, + &qp_ioctl.in, sizeof(qp_ioctl.in), &qp_ioctl.out, sizeof(qp_ioctl.out), + &bytes_ret ); + + if( cl_status != CL_SUCCESS || bytes_ret != sizeof(qp_ioctl.out) ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("UAL_MODIFY_QP IOCTL returned %s.\n", + CL_STATUS_MSG(cl_status)) ); + status = IB_ERROR; + } + else + { + status = qp_ioctl.out.status; + } + + /* Post uvp call */ + if( h_qp->h_ci_qp && uvp_intf.post_modify_qp ) + { + uvp_intf.post_modify_qp( h_qp->h_ci_qp, status, + &qp_ioctl.out.umv_buf ); + } + + UNUSED_PARAM( p_qp_attr ); + //if( status == IB_SUCCESS ) + //{ + // *p_qp_attr = qp_ioctl.out.qp_attr; + //} + + AL_EXIT( AL_DBG_QP ); + return status; +} + + +ib_api_status_t +ual_query_qp( + IN ib_qp_handle_t h_qp, + OUT ib_qp_attr_t* p_qp_attr ) +{ + ual_query_qp_ioctl_t qp_ioctl; + uintn_t bytes_ret; + cl_status_t cl_status; + ib_api_status_t status; + uvp_interface_t uvp_intf = h_qp->obj.p_ci_ca->verbs.user_verbs; + ib_qp_attr_t* p_attr; + ib_pd_handle_t h_ual_pd; + + AL_ENTER( AL_DBG_QP ); + + /* Clear the qp_ioctl */ + cl_memclr( &qp_ioctl, sizeof(qp_ioctl) ); + + /* Call the uvp pre call if the vendor library provided a valid ca handle */ + if( h_qp->h_ci_qp && uvp_intf.pre_query_qp ) + { + /* Pre call to the UVP library */ + status = uvp_intf.pre_query_qp( h_qp->h_ci_qp, &qp_ioctl.in.umv_buf ); + if( status != IB_SUCCESS ) + { + AL_EXIT( AL_DBG_QP ); + return status; + } + } + + qp_ioctl.in.h_qp = h_qp->obj.hdl; + + cl_status = do_al_dev_ioctl( UAL_QUERY_QP, + &qp_ioctl.in, sizeof(qp_ioctl.in), &qp_ioctl.out, sizeof(qp_ioctl.out), + &bytes_ret ); + + if( cl_status != CL_SUCCESS || bytes_ret != sizeof(qp_ioctl.out) ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("UAL_QUERY_QP IOCTL returned %s.\n", + CL_STATUS_MSG(cl_status)) ); + status = IB_ERROR; + } + else + { + status = qp_ioctl.out.status; + } + + p_attr = &qp_ioctl.out.attr; + /* + * Convert the handles in qp_attr to UVP handles + */ + h_ual_pd = PARENT_STRUCT( h_qp->obj.p_parent_obj, ib_pd_t, obj ); + p_attr->h_pd = h_ual_pd->h_ci_pd; + if( h_qp->h_recv_cq ) + p_attr->h_rq_cq = h_qp->h_recv_cq->h_ci_cq; + if( h_qp->h_send_cq ) + p_attr->h_sq_cq = h_qp->h_send_cq->h_ci_cq; + if( h_qp->h_srq ) + p_attr->h_srq = h_qp->h_srq->h_ci_srq; + + /* Post uvp call */ + if( h_qp->h_ci_qp && uvp_intf.post_query_qp ) + { + uvp_intf.post_query_qp( h_qp->h_ci_qp, status, + p_attr, &qp_ioctl.out.umv_buf ); + } + + if( IB_SUCCESS == status ) + { + /* UVP handles in qp_attr will be converted to UAL's handles + * by the common code + */ + *p_qp_attr = *p_attr; + } + + AL_EXIT( AL_DBG_QP ); + return status; +} + + +ib_api_status_t +ual_init_qp_alias( + IN al_qp_alias_t* const p_qp_alias, + IN const ib_pd_handle_t h_pd, + IN const ib_net64_t port_guid, + IN const ib_qp_create_t* const p_qp_create ) +{ + ual_spl_qp_ioctl_t qp_ioctl; + uintn_t bytes_ret; + cl_status_t cl_status; + + AL_ENTER( AL_DBG_QP ); + + CL_ASSERT( p_qp_alias ); + + if( h_pd->type != IB_PDT_ALIAS ) + { + AL_EXIT( AL_DBG_QP ); + return IB_INVALID_PD_HANDLE; + } + + attach_al_obj( &h_pd->obj, &p_qp_alias->qp.obj ); + + switch( p_qp_alias->qp.type ) + { + case IB_QPT_QP0_ALIAS: + case IB_QPT_QP1_ALIAS: + /* Send an ioctl to kernel to get the alias qp */ + cl_memclr( &qp_ioctl, sizeof(qp_ioctl) ); + qp_ioctl.in.h_pd = h_pd->obj.hdl; + qp_ioctl.in.port_guid = port_guid; + qp_ioctl.in.qp_create = *p_qp_create; + qp_ioctl.in.context = (ULONG_PTR)&p_qp_alias->qp; + + cl_status = do_al_dev_ioctl( UAL_GET_SPL_QP_ALIAS, + &qp_ioctl.in, sizeof(qp_ioctl.in), + &qp_ioctl.out, sizeof(qp_ioctl.out), + &bytes_ret ); + + if( cl_status != CL_SUCCESS || bytes_ret != sizeof(qp_ioctl.out) ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("UAL_GET_SPL_QP_ALIAS IOCTL returned %s.\n", + CL_STATUS_MSG(cl_status)) ); + return IB_ERROR; + } + else if( qp_ioctl.out.status != IB_SUCCESS ) + { + AL_EXIT( AL_DBG_QP ); + return qp_ioctl.out.status; + } + p_qp_alias->qp.obj.hdl = qp_ioctl.out.h_qp; + p_qp_alias->h_mad_disp = NULL; + break; + + case IB_QPT_MAD: + /* The MAD QP should have created the MAD dispatcher. */ + CL_ASSERT( p_qp_alias->h_mad_disp ); + break; + + default: + CL_ASSERT( p_qp_alias->qp.type == IB_QPT_QP0_ALIAS || + p_qp_alias->qp.type == IB_QPT_QP1_ALIAS || + p_qp_alias->qp.type == IB_QPT_MAD ); + AL_EXIT( AL_DBG_QP ); + return IB_ERROR; + } + + + /* Override function pointers. */ + p_qp_alias->qp.pfn_reg_mad_svc = ual_reg_mad_svc; + p_qp_alias->qp.pfn_dereg_mad_svc = ual_dereg_mad_svc; + + AL_EXIT( AL_DBG_QP ); + return IB_SUCCESS; +} diff --git a/branches/WOF2-3/core/al/user/ual_qp.h b/branches/WOF2-3/core/al/user/ual_qp.h new file mode 100644 index 00000000..0d736efe --- /dev/null +++ b/branches/WOF2-3/core/al/user/ual_qp.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#if !defined(__UAL_QP_H__) +#define __UAL_QP_H__ + +#include "al_qp.h" + + +ib_api_status_t +ual_init_qp_alias( + IN al_qp_alias_t* const p_qp_alias, + IN const ib_pd_handle_t h_pd, + IN const ib_net64_t port_guid, + IN const ib_qp_create_t* const p_qp_create ); + +#endif // __UAL_QP_H__ diff --git a/branches/WOF2-3/core/al/user/ual_res_mgr.h b/branches/WOF2-3/core/al/user/ual_res_mgr.h new file mode 100644 index 00000000..84d848e4 --- /dev/null +++ b/branches/WOF2-3/core/al/user/ual_res_mgr.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#if !defined(__UAL_RES_MGR_H__) +#define __UAL_RES_MGR_H__ + +/* Commented out until we define them */ +/* +#include "ual_pd.h" +#include "ual_mr.h" +#include "ual_mw.h" +#include "ual_qp.h" +#include "ual_cq.h" +#include "ual_av.h" +#include "ual_mcast.h" +*/ + + + +/* + * Global handle to the access layer. This is used by internal components + * when calling the external API. This handle is initialized by the access + * layer manager. + */ +extern ib_al_handle_t gh_al; + + +/* + * + * + * Resource list structure with a lock + * + */ +typedef struct _ual_res +{ + cl_qlist_t list; + cl_spinlock_t lock; + +} ual_res_t; + +#endif // __UAL_RES_MGR_H__ diff --git a/branches/WOF2-3/core/al/user/ual_sa_req.c b/branches/WOF2-3/core/al/user/ual_sa_req.c new file mode 100644 index 00000000..5f1363c7 --- /dev/null +++ b/branches/WOF2-3/core/al/user/ual_sa_req.c @@ -0,0 +1,309 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +/* + * Handles all SA-related interaction for user-mode: + * queries + * service registration + * multicast + */ + + +#include +#include + +#include "al.h" +#include "al_ca.h" +#include "al_common.h" +#include "al_debug.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "ual_sa_req.tmh" +#endif + +#include "al_mgr.h" +#include "al_query.h" +#include "ib_common.h" +#include "ual_mad.h" + + +typedef struct _sa_req_mgr +{ + al_obj_t obj; /* Child of gp_al_mgr */ + + /* File handle on which to issue query IOCTLs. */ + HANDLE h_sa_dev; + +} sa_req_mgr_t; + + +/* Global SA request manager */ +sa_req_mgr_t *gp_sa_req_mgr = NULL; + + + +/* + * Function prototypes. + */ +static void +free_sa_req_mgr( + IN al_obj_t* p_obj ); + +void +destroying_sa_req_svc( + IN al_obj_t* p_obj ); + +void +free_sa_req_svc( + IN al_obj_t* p_obj ); + + +/* + * Create the sa_req manager. + */ +ib_api_status_t +create_sa_req_mgr( + IN al_obj_t* const p_parent_obj ) +{ + ib_api_status_t status; + + AL_ENTER( AL_DBG_SA_REQ ); + CL_ASSERT( p_parent_obj ); + CL_ASSERT( gp_sa_req_mgr == NULL ); + + gp_sa_req_mgr = cl_zalloc( sizeof( sa_req_mgr_t ) ); + if( gp_sa_req_mgr == NULL ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, ("cl_zalloc failed\n") ); + return IB_INSUFFICIENT_MEMORY; + } + + /* Construct the sa_req manager. */ + construct_al_obj( &gp_sa_req_mgr->obj, AL_OBJ_TYPE_SA_REQ_SVC ); + gp_sa_req_mgr->h_sa_dev = INVALID_HANDLE_VALUE; + + /* Initialize the global sa_req manager object. */ + status = init_al_obj( &gp_sa_req_mgr->obj, gp_sa_req_mgr, TRUE, + NULL, NULL, free_sa_req_mgr ); + if( status != IB_SUCCESS ) + { + free_sa_req_mgr( &gp_sa_req_mgr->obj ); + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, ("cl_spinlock_init failed\n") ); + return status; + } + status = attach_al_obj( p_parent_obj, &gp_sa_req_mgr->obj ); + if( status != IB_SUCCESS ) + { + gp_sa_req_mgr->obj.pfn_destroy( &gp_sa_req_mgr->obj, NULL ); + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("attach_al_obj returned %s.\n", ib_get_err_str(status)) ); + return status; + } + + /* Create a file object on which to issue all SA requests. */ + gp_sa_req_mgr->h_sa_dev = ual_create_async_file( UAL_BIND_SA ); + if( gp_sa_req_mgr->h_sa_dev == INVALID_HANDLE_VALUE ) + { + gp_sa_req_mgr->obj.pfn_destroy( &gp_sa_req_mgr->obj, NULL ); + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("ual_create_async_file returned %d.\n", GetLastError()) ); + return IB_ERROR; + } + + /* Release the reference from init_al_obj */ + deref_al_obj( &gp_sa_req_mgr->obj ); + + AL_EXIT( AL_DBG_SA_REQ ); + return IB_SUCCESS; +} + + +/* + * Free the sa_req manager. + */ +static void +free_sa_req_mgr( + IN al_obj_t* p_obj ) +{ + CL_ASSERT( p_obj ); + CL_ASSERT( gp_sa_req_mgr == PARENT_STRUCT( p_obj, sa_req_mgr_t, obj ) ); + UNUSED_PARAM( p_obj ); + + if( gp_sa_req_mgr->h_sa_dev != INVALID_HANDLE_VALUE ) + CloseHandle( gp_sa_req_mgr->h_sa_dev ); + + destroy_al_obj( &gp_sa_req_mgr->obj ); + cl_free( gp_sa_req_mgr ); + gp_sa_req_mgr = NULL; +} + + +ib_api_status_t +al_send_sa_req( + IN al_sa_req_t *p_sa_req, + IN const net64_t port_guid, + IN const uint32_t timeout_ms, + IN const uint32_t retry_cnt, + IN const ib_user_query_t* const p_sa_req_data, + IN const ib_al_flags_t flags ) +{ + ib_api_status_t status; + HANDLE h_dev; + DWORD ret_bytes; + + AL_ENTER( AL_DBG_QUERY ); + + CL_ASSERT( p_sa_req ); + CL_ASSERT( p_sa_req_data ); + + /* Copy the query context information. */ + p_sa_req->status = IB_ERROR; + + /* Issue the query IOCTL */ + p_sa_req->ioctl.in.port_guid = port_guid; + p_sa_req->ioctl.in.timeout_ms = timeout_ms; + p_sa_req->ioctl.in.retry_cnt = retry_cnt; + p_sa_req->ioctl.in.sa_req = *p_sa_req_data; + cl_memcpy( p_sa_req->ioctl.in.attr, + p_sa_req_data->p_attr, p_sa_req_data->attr_size ); + p_sa_req->ioctl.in.ph_sa_req = (ULONG_PTR)&p_sa_req->hdl; + p_sa_req->ioctl.in.p_status = (ULONG_PTR)&p_sa_req->status; + + if( flags & IB_FLAGS_SYNC ) + h_dev = g_al_device; + else + h_dev = gp_sa_req_mgr->h_sa_dev; + + if( !DeviceIoControl( h_dev, UAL_SEND_SA_REQ, + &p_sa_req->ioctl.in, sizeof(p_sa_req->ioctl.in), + &p_sa_req->ioctl.out, sizeof(p_sa_req->ioctl.out), + NULL, &p_sa_req->ov ) ) + { + if( GetLastError() != ERROR_IO_PENDING ) + { + status = p_sa_req->status; + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , ("UAL_SEND_SA_REQ IOCTL returned %s\n", + ib_get_err_str(status)) ); + } + else + { + status = IB_SUCCESS; + } + } + else + { + /* Completed synchronously. */ + if( GetOverlappedResult( h_dev, &p_sa_req->ov, &ret_bytes, FALSE ) ) + { + status = IB_SUCCESS; + /* Process the completion. */ + sa_req_cb( 0, ret_bytes, &p_sa_req->ov ); + } + else + { + sa_req_cb( GetLastError(), 0, &p_sa_req->ov ); + status = IB_ERROR; + } + } + + AL_EXIT( AL_DBG_QUERY ); + return status; +} + + +void CALLBACK +sa_req_cb( + IN DWORD error_code, + IN DWORD ret_bytes, + IN LPOVERLAPPED p_ov ) +{ + al_sa_req_t *p_sa_req; + ib_mad_element_t *p_mad_response = NULL; + + AL_ENTER( AL_DBG_QUERY ); + + CL_ASSERT( p_ov ); + + p_sa_req = PARENT_STRUCT( p_ov, al_sa_req_t, ov ); + + if( error_code ) + { + /* Some sort of failure. :( */ + p_sa_req->status = IB_ERROR; + goto sa_req_cb_err; + } + else if( ret_bytes != sizeof(p_sa_req->ioctl.out) ) + { + /* Check for expected returned data. */ + p_sa_req->status = IB_ERROR; + goto sa_req_cb_err; + } + + /* Retrieve the response */ + if( p_sa_req->ioctl.out.h_resp != AL_INVALID_HANDLE ) + { + p_sa_req->status = + ual_get_recv_mad( g_pool_key, p_sa_req->ioctl.out.h_resp, + p_sa_req->ioctl.out.resp_size, &p_mad_response ); + + if( p_sa_req->status != IB_SUCCESS ) + goto sa_req_cb_err; + } + + p_sa_req->status = p_sa_req->ioctl.out.status; + +sa_req_cb_err: + p_sa_req->pfn_sa_req_cb( p_sa_req, p_mad_response ); + + AL_EXIT( AL_DBG_QUERY ); +} + + +void +al_cancel_sa_req( + IN const al_sa_req_t *p_sa_req ) +{ + ual_cancel_sa_req_ioctl_t ioctl; + size_t bytes_ret; + + AL_ENTER( AL_DBG_SA_REQ ); + + ioctl.h_sa_req = p_sa_req->hdl; + + do_al_dev_ioctl( + UAL_CANCEL_SA_REQ, &ioctl, sizeof(ioctl), NULL, 0, &bytes_ret ); + + AL_EXIT( AL_DBG_SA_REQ ); +} diff --git a/branches/WOF2-3/core/al/user/ual_srq.c b/branches/WOF2-3/core/al/user/ual_srq.c new file mode 100644 index 00000000..a9d0d1e4 --- /dev/null +++ b/branches/WOF2-3/core/al/user/ual_srq.c @@ -0,0 +1,439 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: ual_qp.c 1611 2006-08-20 14:48:55Z sleybo $ + */ + + +#include "al.h" +#include "al_av.h" +#include "al_ci_ca.h" +#include "al_cq.h" +#include "al_pd.h" +#include "al_srq.h" +#include "ual_mad.h" +#include "ual_support.h" + + +#include "al_debug.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "ual_srq.tmh" +#endif + + +ib_api_status_t +ual_post_srq_recv( + IN const ib_srq_handle_t h_srq, + IN ib_recv_wr_t* const p_recv_wr, + OUT ib_recv_wr_t **pp_recv_failure OPTIONAL ) +{ + uintn_t failed_index; + uintn_t bytes_ret; + uint32_t num_wr = 0; + uint32_t num_ds = 0; + ib_recv_wr_t* p_wr; + ib_local_ds_t* p_ds; + ual_post_srq_recv_ioctl_t *p_srq_ioctl; + size_t ioctl_buf_sz; + cl_status_t cl_status; + ib_api_status_t status; + + AL_ENTER( AL_DBG_SRQ ); + + /* + * Since the work request is a link list and we need to pass this + * to the kernel as a array of work requests. So first walk through + * the list and find out how much memory we need to allocate. + */ + for( p_wr = p_recv_wr; p_wr; p_wr = p_wr->p_next ) + { + num_wr++; + + /* Check for overflow */ + if( !num_wr ) + break; + if( num_ds > num_ds + p_wr->num_ds ) + { + num_wr = 0; + break; + } + + num_ds += p_wr->num_ds; + } + if( !num_wr ) + { + AL_EXIT( AL_DBG_SRQ ); + return IB_INVALID_PARAMETER; + } + + ioctl_buf_sz = sizeof(ual_post_recv_ioctl_t); + ioctl_buf_sz += sizeof(ib_recv_wr_t) * (num_wr - 1); + ioctl_buf_sz += sizeof(ib_local_ds_t) * num_ds; + + p_srq_ioctl = (ual_post_srq_recv_ioctl_t*)cl_zalloc( ioctl_buf_sz ); + if( !p_srq_ioctl ) + { + AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, + ("Failed to allocate IOCTL buffer.\n") ); + return IB_INSUFFICIENT_MEMORY; + } + p_ds = (ib_local_ds_t*)&p_srq_ioctl->in.recv_wr[num_wr]; + + /* Now populate the ioctl buffer and send down the ioctl */ + p_srq_ioctl->in.h_srq = h_srq->obj.hdl; + p_srq_ioctl->in.num_wr = num_wr; + p_srq_ioctl->in.num_ds = num_ds; + num_wr = 0; + for( p_wr = p_recv_wr; p_wr; p_wr = p_wr->p_next ) + { + p_srq_ioctl->in.recv_wr[num_wr++] = *p_wr; + cl_memcpy( + p_ds, p_wr->ds_array, sizeof(ib_local_ds_t) * p_wr->num_ds ); + p_ds += p_wr->num_ds; + } + + cl_status = do_al_dev_ioctl( UAL_POST_SRQ_RECV, + &p_srq_ioctl->in, ioctl_buf_sz, + &p_srq_ioctl->out, sizeof(p_srq_ioctl->out), + &bytes_ret ); + + if( cl_status != CL_SUCCESS || bytes_ret != sizeof(p_srq_ioctl->out) ) + { + if( pp_recv_failure ) + *pp_recv_failure = p_recv_wr; + + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("UAL_POST_SRQ_RECV IOCTL returned %s.\n", + CL_STATUS_MSG(cl_status)) ); + status = IB_ERROR; + } + else + { + status = p_srq_ioctl->out.status; + + if( status != IB_SUCCESS && pp_recv_failure ) + { + /* Get the failed index */ + failed_index = num_wr - p_srq_ioctl->out.failed_cnt; + p_wr = p_recv_wr; + while( failed_index-- ) + p_wr = p_wr->p_next; + + *pp_recv_failure = p_wr; + } + } + + cl_free( p_srq_ioctl ); + AL_EXIT( AL_DBG_SRQ ); + return status; +} + + + +ib_api_status_t +ual_create_srq( + IN const ib_pd_handle_t h_pd, + IN OUT ib_srq_handle_t h_srq, + IN const ib_srq_attr_t* const p_srq_attr) +{ + /* The first argument is probably not needed */ + ual_create_srq_ioctl_t srq_ioctl; + uintn_t bytes_ret; + cl_status_t cl_status; + ib_api_status_t status; + uvp_interface_t uvp_intf = h_srq->obj.p_ci_ca->verbs.user_verbs; + ib_srq_attr_t srq_attr; + + AL_ENTER( AL_DBG_SRQ ); + + /* Clear the srq_ioctl */ + cl_memclr( &srq_ioctl, sizeof(srq_ioctl) ); + + /* Pre call to the UVP library */ + if( h_pd->h_ci_pd && uvp_intf.pre_create_srq ) + { + /* The post call MUST exist as it sets the UVP srq handle. */ + CL_ASSERT( uvp_intf.post_create_srq ); + /* Convert the handles to UVP handles */ + srq_attr = *p_srq_attr; + status = uvp_intf.pre_create_srq( h_pd->h_ci_pd, + &srq_attr, &srq_ioctl.in.umv_buf, &h_srq->h_ci_srq ); + if( status != IB_SUCCESS ) + { + AL_EXIT( AL_DBG_SRQ ); + return status; + } + } + /* + * Convert the handles to KAL handles once again starting + * from the input srq attribute + */ + srq_ioctl.in.h_pd = h_pd->obj.hdl; + srq_ioctl.in.srq_attr = *p_srq_attr; + srq_ioctl.in.context = (ULONG_PTR)h_srq; + srq_ioctl.in.ev_notify = (h_srq->pfn_event_cb != NULL) ? TRUE : FALSE; + + cl_status = do_al_dev_ioctl( UAL_CREATE_SRQ, + &srq_ioctl.in, sizeof(srq_ioctl.in), &srq_ioctl.out, sizeof(srq_ioctl.out), + &bytes_ret ); + + if( cl_status != CL_SUCCESS || bytes_ret != sizeof(srq_ioctl.out) ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("UAL_CREATE_SRQ IOCTL returned %s.\n", + CL_STATUS_MSG(cl_status)) ); + status = IB_ERROR; + } + else + { + status = srq_ioctl.out.status; + } + + /* Post uvp call */ + if( h_pd->h_ci_pd && uvp_intf.post_create_srq ) + { + uvp_intf.post_create_srq( h_pd->h_ci_pd, + status, &h_srq->h_ci_srq, &srq_ioctl.out.umv_buf ); + + if( uvp_intf.post_recv ) + { + h_srq->h_recv_srq = h_srq->h_ci_srq; + h_srq->pfn_post_srq_recv = uvp_intf.post_srq_recv; + } + else + { + h_srq->h_recv_srq = h_srq; + h_srq->pfn_post_srq_recv = ual_post_srq_recv; + } + } + else + { + h_srq->h_recv_srq = h_srq; + h_srq->pfn_post_srq_recv = ual_post_srq_recv; + } + + if( status == IB_SUCCESS ) + { + h_srq->obj.hdl = srq_ioctl.out.h_srq; + } + + AL_EXIT( AL_DBG_SRQ ); + return status; +} + + +ib_api_status_t +ual_modify_srq( + IN ib_srq_handle_t h_srq, + IN const ib_srq_attr_t* const p_srq_attr, + IN const ib_srq_attr_mask_t srq_attr_mask) +{ + ual_modify_srq_ioctl_t srq_ioctl; + uintn_t bytes_ret; + cl_status_t cl_status; + ib_api_status_t status; + uvp_interface_t uvp_intf = h_srq->obj.p_ci_ca->verbs.user_verbs; + + AL_ENTER( AL_DBG_SRQ ); + + /* Clear the srq_ioctl */ + cl_memclr( &srq_ioctl, sizeof(srq_ioctl) ); + + /* Call the uvp pre call if the vendor library provided a valid srq handle */ + if( h_srq->h_ci_srq && uvp_intf.pre_modify_srq ) + { + /* Pre call to the UVP library */ + status = uvp_intf.pre_modify_srq( h_srq->h_ci_srq, + p_srq_attr, srq_attr_mask, &srq_ioctl.in.umv_buf ); + if( status != IB_SUCCESS ) + { + AL_EXIT( AL_DBG_SRQ ); + return status; + } + } + + srq_ioctl.in.h_srq = h_srq->obj.hdl; + srq_ioctl.in.srq_attr = *p_srq_attr; + srq_ioctl.in.srq_attr_mask = srq_attr_mask; + + cl_status = do_al_dev_ioctl( UAL_MODIFY_SRQ, + &srq_ioctl.in, sizeof(srq_ioctl.in), &srq_ioctl.out, sizeof(srq_ioctl.out), + &bytes_ret ); + + if( cl_status != CL_SUCCESS || bytes_ret != sizeof(srq_ioctl.out) ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("UAL_MODIFY_SRQ IOCTL returned %s.\n", + CL_STATUS_MSG(cl_status)) ); + status = IB_ERROR; + } + else + { + status = srq_ioctl.out.status; + } + + /* Post uvp call */ + if( h_srq->h_ci_srq && uvp_intf.post_modify_srq ) + { + uvp_intf.post_modify_srq( h_srq->h_ci_srq, status, + &srq_ioctl.out.umv_buf ); + } + + //if( status == IB_SUCCESS ) + //{ + // *p_srq_attr = srq_ioctl.out.srq_attr; + //} + + AL_EXIT( AL_DBG_SRQ ); + return status; +} + + +ib_api_status_t +ual_query_srq( + IN ib_srq_handle_t h_srq, + OUT ib_srq_attr_t* p_srq_attr ) +{ + ual_query_srq_ioctl_t srq_ioctl; + uintn_t bytes_ret; + cl_status_t cl_status; + ib_api_status_t status; + uvp_interface_t uvp_intf = h_srq->obj.p_ci_ca->verbs.user_verbs; + ib_srq_attr_t* p_attr; + + AL_ENTER( AL_DBG_SRQ ); + + /* Clear the srq_ioctl */ + cl_memclr( &srq_ioctl, sizeof(srq_ioctl) ); + + /* Call the uvp pre call if the vendor library provided a valid ca handle */ + if( h_srq->h_ci_srq && uvp_intf.pre_query_srq ) + { + /* Pre call to the UVP library */ + status = uvp_intf.pre_query_srq( h_srq->h_ci_srq, &srq_ioctl.in.umv_buf ); + if( status != IB_SUCCESS ) + { + AL_EXIT( AL_DBG_SRQ ); + return status; + } + } + + srq_ioctl.in.h_srq = h_srq->obj.hdl; + + cl_status = do_al_dev_ioctl( UAL_QUERY_SRQ, + &srq_ioctl.in, sizeof(srq_ioctl.in), &srq_ioctl.out, sizeof(srq_ioctl.out), + &bytes_ret ); + + if( cl_status != CL_SUCCESS || bytes_ret != sizeof(srq_ioctl.out) ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("UAL_QUERY_SRQ IOCTL returned %s.\n", + CL_STATUS_MSG(cl_status)) ); + status = IB_ERROR; + } + else + { + status = srq_ioctl.out.status; + } + + p_attr = &srq_ioctl.out.srq_attr; + + /* Post uvp call */ + if( h_srq->h_ci_srq && uvp_intf.post_query_srq ) + { + uvp_intf.post_query_srq( h_srq->h_ci_srq, status, + p_attr, &srq_ioctl.out.umv_buf ); + } + + if( IB_SUCCESS == status ) + { + /* UVP handles in srq_attr will be converted to UAL's handles + * by the common code + */ + *p_srq_attr = *p_attr; + } + + AL_EXIT( AL_DBG_SRQ ); + return status; +} + + +ib_api_status_t +ual_destroy_srq( + IN ib_srq_handle_t h_srq ) +{ + ual_destroy_srq_ioctl_t srq_ioctl; + uintn_t bytes_ret; + cl_status_t cl_status; + ib_api_status_t status; + uvp_interface_t uvp_intf = h_srq->obj.p_ci_ca->verbs.user_verbs; + + AL_ENTER( AL_DBG_SRQ ); + + /* Call the uvp pre call if the vendor library provided a valid srq handle */ + if( h_srq->h_ci_srq && uvp_intf.pre_destroy_srq ) + { + status = uvp_intf.pre_destroy_srq( h_srq->h_ci_srq ); + if (status != IB_SUCCESS) + { + AL_EXIT( AL_DBG_SRQ ); + return status; + } + } + + cl_memclr( &srq_ioctl, sizeof(srq_ioctl) ); + srq_ioctl.in.h_srq = h_srq->obj.hdl; + cl_status = do_al_dev_ioctl( UAL_DESTROY_SRQ, + &srq_ioctl.in, sizeof(srq_ioctl.in), &srq_ioctl.out, sizeof(srq_ioctl.out), + &bytes_ret ); + + if( cl_status != CL_SUCCESS || bytes_ret != sizeof(srq_ioctl.out) ) + { + AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , + ("UAL_DESTROY_SRQ IOCTL returned %s.\n", + CL_STATUS_MSG(cl_status)) ); + status = IB_ERROR; + } + else + { + status = srq_ioctl.out.status; + } + + /* Call vendor's post_destroy_srq */ + if( h_srq->h_ci_srq && uvp_intf.post_destroy_srq ) + uvp_intf.post_destroy_srq( h_srq->h_ci_srq, status ); + + AL_EXIT( AL_DBG_SRQ ); + return status; +} + diff --git a/branches/WOF2-3/core/al/user/ual_support.h b/branches/WOF2-3/core/al/user/ual_support.h new file mode 100644 index 00000000..04deb8be --- /dev/null +++ b/branches/WOF2-3/core/al/user/ual_support.h @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + +/* + * Device and complib support for UAL + */ + +#if !defined(__UAL_SUPPORT_H__) +#define __UAL_SUPPORT_H__ + +#include +#include +#include +#include +#include "al_dev.h" +#include "al_debug.h" + + + +#include + + +/* File handle to kernel transport. */ +extern HANDLE g_al_device; + +/* + * Mutex to serialize open/close AL calls so that we can properly synchronize + * initializing and cleaning up AL internally. + */ +extern cl_mutex_t g_open_close_mutex; + + +/* Helper functions for UVP library access. */ +static inline void* +al_load_uvp( + IN char* const uvp_lib_name ) +{ +#ifdef _DEBUG_ + StringCbCatA( uvp_lib_name, 32, "d.dll" ); +#else /* _DEBUG_ */ + StringCbCatA( uvp_lib_name, 32, ".dll" ); +#endif /* _DEBUG_ */ + return LoadLibrary( uvp_lib_name ); +} + +static inline void +al_unload_uvp( + IN void *h_uvp_lib ) +{ + FreeLibrary( h_uvp_lib ); +} + +static inline void +al_uvp_lib_err( + IN uint32_t dbg_lvl, + IN char* const msg, + IN ... ) +{ + char buffer[256]; + char* error; + va_list args; + + /* Make free build warning go away. */ + UNUSED_PARAM( dbg_lvl ); + + va_start( args, msg ); + + if( StringCbVPrintfA( buffer, 256, msg, args ) == + STRSAFE_E_INSUFFICIENT_BUFFER ) + { + /* Overflow... */ + buffer[252] = '.'; + buffer[253] = '.'; + buffer[254] = '.'; + } + va_end(args); + + if( !FormatMessageA( FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPSTR)&error, 0, NULL ) ) + { + //AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, ("%s (%d)\n", buffer, GetLastError()) ); + } + else + { + //AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, ("%s (%s)\n", buffer, error) ); + LocalFree( error ); + } +} + +#endif // __UAL_SUPPORT_H__ diff --git a/branches/WOF2-3/core/bus/dirs b/branches/WOF2-3/core/bus/dirs new file mode 100644 index 00000000..ed41dcf4 --- /dev/null +++ b/branches/WOF2-3/core/bus/dirs @@ -0,0 +1,2 @@ +DIRS=\ + kernel diff --git a/branches/WOF2-3/core/bus/kernel/SOURCES b/branches/WOF2-3/core/bus/kernel/SOURCES new file mode 100644 index 00000000..42bfa26f --- /dev/null +++ b/branches/WOF2-3/core/bus/kernel/SOURCES @@ -0,0 +1,42 @@ +TARGETNAME=ibbus +TARGETPATH=..\..\..\bin\kernel\obj$(BUILD_ALT_DIR) +TARGETTYPE=DRIVER + +!if $(FREEBUILD) +ENABLE_EVENT_TRACING=1 +!else +#ENABLE_EVENT_TRACING=1 +!endif + + +SOURCES= ibbus.rc \ + bus_ev_log.mc \ + bus_driver.c \ + bus_pnp.c \ + bus_port_mgr.c \ + bus_iou_mgr.c \ + bus_stat.c + +INCLUDES=..\..\..\inc;..\..\..\inc\kernel;..\..\al;..\..\al\kernel;..\..\bus\kernel\$O; + +C_DEFINES=$(C_DEFINES) -DDRIVER -DDEPRECATE_DDK_FUNCTIONS -DNEED_CL_OBJ + +TARGETLIBS= \ + $(DDK_LIB_PATH)\ntstrsafe.lib \ + $(TARGETPATH)\*\complib.lib \ + $(TARGETPATH)\*\ibal.lib + +!if !defined(DDK_TARGET_OS) || "$(DDK_TARGET_OS)"=="WinXP" +TARGETLIBS=$(TARGETLIBS) $(DDK_LIB_PATH)\csq.lib +!endif + +!IFDEF ENABLE_EVENT_TRACING + +C_DEFINES = $(C_DEFINES) -DEVENT_TRACING + +RUN_WPP = $(SOURCES) -km -ext: .c .h .C .H + +!ENDIF + + +MSC_WARNING_LEVEL= /W4 diff --git a/branches/WOF2-3/core/bus/kernel/bus_driver.c b/branches/WOF2-3/core/bus/kernel/bus_driver.c new file mode 100644 index 00000000..c190c93b --- /dev/null +++ b/branches/WOF2-3/core/bus/kernel/bus_driver.c @@ -0,0 +1,1086 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2006 Mellanox Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * Provides the driver entry points for the InfiniBand Bus Driver. + */ + +#include +#include "bus_driver.h" +#include "bus_pnp.h" +#include "al_mgr.h" +#include "al_dev.h" +#include "al_debug.h" +#include +#include "iba/ipoib_ifc.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "bus_driver.tmh" +#endif + +#ifdef WINIB +#define DEFAULT_NODE_DESC "Mellanox Windows® Host" +#else +#define DEFAULT_NODE_DESC "OpenIB Windows® Host" +#endif + + + +char node_desc[IB_NODE_DESCRIPTION_SIZE]; +PDEVICE_OBJECT g_ControlDeviceObject=NULL; +UNICODE_STRING g_CDO_dev_name, g_CDO_dos_name; + +bus_globals_t bus_globals = { + BUS_DBG_ERROR, + TRUE, + NULL, + NULL, + NULL, + NULL +}; + +static void +__read_machine_name( void ); + +static NTSTATUS +__read_registry( + IN UNICODE_STRING* const p_Param_Path ); + +static NTSTATUS +bus_drv_open( + IN DEVICE_OBJECT *p_dev_obj, + IN IRP *p_irp ); + +static NTSTATUS +bus_drv_cleanup( + IN DEVICE_OBJECT *p_dev_obj, + IN IRP *p_irp ); + +static NTSTATUS +bus_drv_close( + IN DEVICE_OBJECT *p_dev_obj, + IN IRP *p_irp ); + +static NTSTATUS +bus_drv_ioctl( + IN DEVICE_OBJECT *p_dev_obj, + IN IRP *p_irp ); + +/***f* InfiniBand Bus Driver/bus_drv_sysctl +* NAME +* bus_drv_sysctl +* +* DESCRIPTION +* Entry point for handling WMI IRPs. +* +* SYNOPSIS +*/ +static NTSTATUS +bus_drv_sysctl( + IN DEVICE_OBJECT *p_dev_obj, + IN IRP *p_irp ); +/**********/ + +static void +bus_drv_unload( + IN DRIVER_OBJECT *p_driver_obj ); + +NTSTATUS +DriverEntry( + IN DRIVER_OBJECT *p_driver_obj, + IN UNICODE_STRING *p_registry_path ); + + +child_device_info_t g_default_device_info; + +static void __create_default_dev_info(child_device_info_t *pNewDevList) +{ + UNICODE_STRING keyValue; + + /* DeviceId*/ + RtlInitUnicodeString(&keyValue, L"IBA\\IPoIBP\0"); + pNewDevList->device_id_size = keyValue.Length + sizeof(WCHAR); + RtlStringCchCopyW( pNewDevList->device_id, + sizeof(pNewDevList->device_id)/sizeof(wchar_t), keyValue.Buffer ); + /* HardwareId*/ + RtlInitUnicodeString(&keyValue, L"IBA\\IPoIBP\0\0"); + pNewDevList->hardware_id_size = keyValue.Length + 2*sizeof(WCHAR); + RtlStringCchCopyW( pNewDevList->hardware_id, + sizeof(pNewDevList->hardware_id)/sizeof(wchar_t), keyValue.Buffer ); + /* CompatibleId*/ + RtlInitUnicodeString(&keyValue, L"IBA\\SID_1000066a00020000\0\0"); + pNewDevList->compatible_id_size = keyValue.Length + 2*sizeof(WCHAR); //2 + RtlStringCchCopyW( pNewDevList->compatible_id, + sizeof(pNewDevList->compatible_id)/sizeof(wchar_t), keyValue.Buffer ); + /* Device Description */ + RtlInitUnicodeString(&keyValue, L"OpenIB IPoIB Adapter"); + pNewDevList->description_size = keyValue.Length + sizeof(WCHAR); + RtlStringCchCopyW( pNewDevList->description, + sizeof(pNewDevList->description)/sizeof(wchar_t), keyValue.Buffer ); + /* Pkey */ + RtlInitUnicodeString(&keyValue, L"FFFF"); /* Pkey */ + RtlStringCchCopyW( pNewDevList->pkey, + sizeof(pNewDevList->pkey)/sizeof(wchar_t), keyValue.Buffer ); +} + + +static void +__read_machine_name( void ) +{ + NTSTATUS status; + /* Remember the terminating entry in the table below. */ + RTL_QUERY_REGISTRY_TABLE table[2]; + UNICODE_STRING hostNamePath; + UNICODE_STRING hostNameW; + ANSI_STRING hostName; + + BUS_ENTER( BUS_DBG_DRV ); + + /* Get the host name. */ + RtlInitUnicodeString( &hostNamePath, L"ComputerName\\ComputerName" ); + RtlInitUnicodeString( &hostNameW, NULL ); + + /* + * Clear the table. This clears all the query callback pointers, + * and sets up the terminating table entry. + */ + cl_memclr( table, sizeof(table) ); + cl_memclr( node_desc, sizeof(node_desc) ); + + /* Setup the table entries. */ + table[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED; + table[0].Name = L"ComputerName"; + table[0].EntryContext = &hostNameW; + table[0].DefaultType = REG_SZ; + table[0].DefaultData = &hostNameW; + table[0].DefaultLength = 0; + + /* Have at it! */ + status = RtlQueryRegistryValues( RTL_REGISTRY_CONTROL, + hostNamePath.Buffer, table, NULL, NULL ); + if( NT_SUCCESS( status ) ) + { + /* Convert the UNICODE host name to UTF-8 (ASCII). */ + hostName.Length = 0; + hostName.MaximumLength = sizeof(node_desc); + hostName.Buffer = node_desc; + status = RtlUnicodeStringToAnsiString( &hostName, &hostNameW, FALSE ); + RtlFreeUnicodeString( &hostNameW ); + } + else + { + BUS_TRACE(BUS_DBG_ERROR , ("Failed to get host name.\n") ); + /* Use the default name... */ + RtlStringCbCopyNA( node_desc, sizeof(node_desc), + DEFAULT_NODE_DESC, sizeof(DEFAULT_NODE_DESC) ); + } + BUS_EXIT( BUS_DBG_DRV ); +} + +/************************************************************************************ +* name : __prepare_pKey_array +* parses registry string and exrtacts pkey value(s) from it. +* pkey pattern is 0xABCD +* input : UNICODE_STRING *str +* output: pkey_array +* return: uint16_t number of pkey(s) found +*************************************************************************************/ +static void __prepare_pKey_array(IN const char *str, size_t str_len,OUT pkey_array_t *cur_pkey) +{ + NTSTATUS status; + size_t i; + uint8_t j; + char pkey_str[7]; + ULONG tmp_val; + BUS_ENTER( BUS_DBG_DRV ); + + CL_ASSERT(cur_pkey); + CL_ASSERT(str); + + cur_pkey->pkey_num = 0; + j = 0; + + for (i = 0; (i < str_len) && (cur_pkey->pkey_num < MAX_NUM_PKEY) ; i++) + { + if(str[i] == ' ') + continue; + + if( (str[i] != ',') && (str[i] != '\0')) + { + if(j >= 7) + { + BUS_TRACE(BUS_DBG_ERROR , + ("Incorrect format of pkey value\n") ); + break; + } + pkey_str[j] = str[i]; + j++; + } + else + { + pkey_str[j] = '\0'; + status = RtlCharToInteger(&pkey_str[2],16,&tmp_val); + if(! NT_SUCCESS(status)) + { + BUS_TRACE(BUS_DBG_ERROR , + ("Failed to convert, status = 0x%08X\n",status) ); + break; + } + cur_pkey->pkey_array[cur_pkey->pkey_num++] = (uint16_t)tmp_val; + j = 0; + } + } + BUS_EXIT( BUS_DBG_DRV ); +} + + +static void _free_static_iodevices() +{ + child_device_info_list_t *pDevList, *pDevList1; + + pDevList = bus_globals.p_device_list; + + while(pDevList) + { + pDevList1 = pDevList->next_device_info; + cl_free(pDevList); + pDevList = pDevList1; + } + +} + +static NTSTATUS __create_static_devices(PUNICODE_STRING p_param_path) +{ + RTL_QUERY_REGISTRY_TABLE table[2]; + UNICODE_STRING keyPath; + UNICODE_STRING keyValue; + UNICODE_STRING defaultKeyValue; + UNICODE_STRING child_name; + WCHAR *key_path_buffer; + WCHAR *key_value_buffer; + WCHAR *static_child_name; + NTSTATUS status; + #define BUF_SIZE 256 /* use hard-coded size to make it simple*/ + + cl_memclr( table, sizeof(table) ); + + + key_path_buffer = cl_zalloc(BUF_SIZE*sizeof(WCHAR)*3); + + if(!key_path_buffer) + { + BUS_TRACE(BUS_DBG_ERROR ,("Not enough memory for key_path_buffer.\n") ); + status = STATUS_UNSUCCESSFUL; + goto __create_static_devices_exit; + } + + key_value_buffer = key_path_buffer + BUF_SIZE; + static_child_name = key_value_buffer + BUF_SIZE; + + RtlInitUnicodeString( &keyPath, NULL ); + keyPath.MaximumLength = BUF_SIZE*sizeof(WCHAR); + keyPath.Buffer = key_path_buffer; + + RtlInitUnicodeString( &keyValue, NULL ); + keyValue.MaximumLength = BUF_SIZE*sizeof(WCHAR); + keyValue.Buffer = key_value_buffer; + + RtlInitUnicodeString( &child_name, NULL ); + child_name.MaximumLength = BUF_SIZE*sizeof(WCHAR); + child_name.Buffer = static_child_name; + + + RtlCopyUnicodeString( &keyPath, p_param_path ); + + RtlInitUnicodeString(&defaultKeyValue, L"IPoIB\0\0"); + + /* Setup the table entries. */ + table[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOEXPAND; + table[0].Name = L"StaticChild"; + table[0].EntryContext = &child_name; + table[0].DefaultType = REG_MULTI_SZ; + table[0].DefaultData = defaultKeyValue.Buffer; + table[0].DefaultLength = defaultKeyValue.Length; + + status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE, + keyPath.Buffer, table, NULL, NULL ); + + if(NT_SUCCESS(status)) + { + WCHAR *curChild; + child_device_info_list_t *pPrevList, *pNewDevList; + + curChild = static_child_name; + pPrevList = bus_globals.p_device_list; + while(*curChild) + { + RtlCopyUnicodeString(&keyPath, p_param_path); + RtlAppendUnicodeToString(&keyPath, L"\\"); + RtlAppendUnicodeToString(&keyPath, curChild); + + pNewDevList = cl_zalloc(sizeof(child_device_info_list_t)); + if(!pNewDevList) + { + BUS_TRACE(BUS_DBG_ERROR ,("Not enough memory for key_path_buffer.\n") ); + status = STATUS_UNSUCCESSFUL; + goto __create_static_devices_exit; + } + pNewDevList->next_device_info = NULL; + + if(pPrevList == NULL) + { + bus_globals.p_device_list = pNewDevList; + }else + { + pPrevList->next_device_info = pNewDevList; + } + + pPrevList = pNewDevList; + + /* get DeviceId*/ + RtlInitUnicodeString(&defaultKeyValue, L"IBA\\IPoIB\0"); + RtlInitUnicodeString( &keyValue, NULL ); + keyValue.MaximumLength = sizeof(pNewDevList->io_device_info.device_id); + keyValue.Buffer = pNewDevList->io_device_info.device_id; + + /* Setup the table entries. */ + table[0].Flags = RTL_QUERY_REGISTRY_DIRECT; + table[0].Name = L"DeviceId"; + table[0].EntryContext = &keyValue; + table[0].DefaultType = REG_SZ; + table[0].DefaultData = defaultKeyValue.Buffer; + table[0].DefaultLength = defaultKeyValue.Length; + + status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE, + keyPath.Buffer, table, NULL, NULL ); + if(!NT_SUCCESS(status)) + { + BUS_TRACE(BUS_DBG_ERROR ,("Failed to read DeviceId.\n") ); + goto __create_static_devices_exit; + } + pNewDevList->io_device_info.device_id_size = keyValue.Length + sizeof(WCHAR); + + /* Get HardwareId*/ + RtlInitUnicodeString(&defaultKeyValue, L"IBA\\IPoIB\0\0"); + RtlInitUnicodeString( &keyValue, NULL ); + keyValue.MaximumLength = sizeof(pNewDevList->io_device_info.hardware_id); + keyValue.Buffer = pNewDevList->io_device_info.hardware_id; + + /* Setup the table entries. */ + table[0].Flags = RTL_QUERY_REGISTRY_DIRECT; + table[0].Name = L"HardwareId"; + table[0].EntryContext = &keyValue; + table[0].DefaultType = REG_MULTI_SZ; + table[0].DefaultData = defaultKeyValue.Buffer; + table[0].DefaultLength = defaultKeyValue.Length; + + status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE, + keyPath.Buffer, table, NULL, NULL ); + if(!NT_SUCCESS(status)) + { + BUS_TRACE(BUS_DBG_ERROR ,("Failed to read HardwareId.\n") ); + goto __create_static_devices_exit; + } + pNewDevList->io_device_info.hardware_id_size = keyValue.Length + 2*sizeof(WCHAR); + + /* Get CompatibleId*/ + RtlInitUnicodeString(&defaultKeyValue, L"IBA\\SID_1000066a00020000\0\0"); + RtlInitUnicodeString( &keyValue, NULL ); + keyValue.MaximumLength = sizeof(pNewDevList->io_device_info.compatible_id); + keyValue.Buffer = pNewDevList->io_device_info.compatible_id; + + /* Setup the table entries. */ + table[0].Flags = RTL_QUERY_REGISTRY_DIRECT; + table[0].Name = L"CompatibleId"; + table[0].EntryContext = &keyValue; + table[0].DefaultType = REG_MULTI_SZ; + table[0].DefaultData = defaultKeyValue.Buffer; + table[0].DefaultLength = defaultKeyValue.Length; + + status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE, + keyPath.Buffer, table, NULL, NULL ); + if(!NT_SUCCESS(status)) + { + BUS_TRACE(BUS_DBG_ERROR ,("Failed to read CompatibleId.\n") ); + goto __create_static_devices_exit; + } + pNewDevList->io_device_info.compatible_id_size = keyValue.Length + 2*sizeof(WCHAR); //2 null + + /* Get Description*/ + RtlInitUnicodeString(&defaultKeyValue, L"OpenIB IPoIB Adapter"); + RtlInitUnicodeString( &keyValue, NULL ); + keyValue.MaximumLength = sizeof(pNewDevList->io_device_info.description); + keyValue.Buffer = pNewDevList->io_device_info.description; + + /* Setup the table entries. */ + table[0].Flags = RTL_QUERY_REGISTRY_DIRECT; + table[0].Name = L"Description"; + table[0].EntryContext = &keyValue; + table[0].DefaultType = REG_SZ; + table[0].DefaultData = defaultKeyValue.Buffer; + table[0].DefaultLength = defaultKeyValue.Length; + + status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE, + keyPath.Buffer, table, NULL, NULL ); + if(!NT_SUCCESS(status)) + { + BUS_TRACE(BUS_DBG_ERROR ,("Failed to read Description.\n") ); + goto __create_static_devices_exit; + } + + pNewDevList->io_device_info.description_size = keyValue.Length + sizeof(WCHAR); + + + if((pNewDevList->io_device_info.description_size > MAX_DEVICE_ID_LEN) || + (pNewDevList->io_device_info.hardware_id_size > MAX_DEVICE_ID_LEN) || + (pNewDevList->io_device_info.compatible_id_size > MAX_DEVICE_ID_LEN) || + (pNewDevList->io_device_info.device_id_size > MAX_DEVICE_ID_LEN) + ) + { + BUS_TRACE(BUS_DBG_ERROR ,("Id or description size is too big.\n") ); + status = STATUS_UNSUCCESSFUL; + goto __create_static_devices_exit; + } + + /* Get Pkey */ + RtlInitUnicodeString(&defaultKeyValue, L"FFFF"); + RtlInitUnicodeString( &keyValue, NULL ); + keyValue.MaximumLength = sizeof(pNewDevList->io_device_info.pkey); + keyValue.Buffer = pNewDevList->io_device_info.pkey; + + /* Setup the table entries. */ + table[0].Flags = RTL_QUERY_REGISTRY_DIRECT; + table[0].Name = L"PartitionKey"; + table[0].EntryContext = &keyValue; + table[0].DefaultType = REG_SZ; + table[0].DefaultData = defaultKeyValue.Buffer; + table[0].DefaultLength = defaultKeyValue.Length; + + status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE, + keyPath.Buffer, table, NULL, NULL ); + if(!NT_SUCCESS(status)) + { + BUS_TRACE(BUS_DBG_ERROR ,("Failed to read PartitionKey.\n") ); + goto __create_static_devices_exit; + } + + while(*curChild) curChild++; + curChild++; + } + } + +__create_static_devices_exit: + if(key_path_buffer) + { + cl_free(key_path_buffer); + } + + if(!NT_SUCCESS(status)) + { + _free_static_iodevices(); + } + + return status; +} + +static pkey_conf_t* +create_pkey_conf(pkey_conf_t **pp_cur_conf, char *guid_str, uint32_t guid_str_len) +{ + NTSTATUS status; + char tmp_char; + uint32_t tmp_val; + + if (! *pp_cur_conf) + pp_cur_conf = &bus_globals.p_pkey_conf; + else + pp_cur_conf = &((*pp_cur_conf)->next_conf); + + *pp_cur_conf = cl_zalloc( sizeof( pkey_conf_t ) ); + if (!(*pp_cur_conf) ) + { + BUS_TRACE(BUS_DBG_ERROR , + ("Failed to allocate pkey configuration\n") ); + return NULL; + } + + tmp_char = guid_str[1 + guid_str_len/2]; + guid_str[1 + guid_str_len/2] = '\0'; + status = RtlCharToInteger(&guid_str[2],16,(PULONG)&tmp_val); + if(! NT_SUCCESS(status)) + { + cl_free((*pp_cur_conf)); + (*pp_cur_conf) = NULL; + BUS_TRACE(BUS_DBG_ERROR , + ("Failed to convert, status = 0x%08X\n",status) ); + return NULL; + } + guid_str[1 + guid_str_len/2] = tmp_char; + (*pp_cur_conf)->pkeys_per_port.port_guid = tmp_val; + + status = RtlCharToInteger(&guid_str[1 + guid_str_len/2],16,(PULONG)&tmp_val); + if(! NT_SUCCESS(status)) + { + cl_free((*pp_cur_conf)); + (*pp_cur_conf) = NULL; + BUS_TRACE(BUS_DBG_ERROR , + ("Failed to convert, status = 0x%08X\n",status) ); + return NULL; + } + (*pp_cur_conf)->pkeys_per_port.port_guid = ((*pp_cur_conf)->pkeys_per_port.port_guid << 32) | tmp_val; + return (*pp_cur_conf); +} + +/************************************************************************ +* name: __build_pkeys_per_port +* extracts pkeys and port guids from registry string. +* builds pkey array per port +* input: UNICODE_STRING *str +* return: NTSTATUS +************************************************************************/ +static NTSTATUS +__build_pkeys_per_port(IN const UNICODE_STRING *str) +{ + NTSTATUS status; + ANSI_STRING ansi_str; + uint32_t i,j; + char *p_end, *p_start; + boolean_t port_guid_found; + pkey_conf_t *cur_pkey_conf = NULL; + char tmp_guid[32] = {'\0'}; + p_start = NULL; + + status = RtlUnicodeStringToAnsiString(&ansi_str,str,TRUE); + if(! NT_SUCCESS(status)) + { + BUS_TRACE(BUS_DBG_ERROR , + ("RtlUnicodeStringToAnsiString returned 0x%.8x\n", status) ); + return status; + } + + port_guid_found = FALSE; + j = 0; + for ( i = 0; i < ansi_str.MaximumLength; i++) + { + if(! port_guid_found) + { + if(ansi_str.Buffer[i] == ':') + { + port_guid_found = TRUE; + tmp_guid[j] = '\0'; + cur_pkey_conf = create_pkey_conf(&cur_pkey_conf,(char*)tmp_guid,j); + if(! cur_pkey_conf) + { + RtlFreeAnsiString(&ansi_str); + BUS_TRACE(BUS_DBG_ERROR , + ("Failed to create pkey configuration\n")); + return STATUS_INVALID_PARAMETER; + } + RtlZeroMemory(tmp_guid,sizeof(tmp_guid)); + j = 0; + p_start = NULL; + } + else + { + tmp_guid[j] = ansi_str.Buffer[i]; + j++; + continue; + } + } + else + { + if(!p_start) + p_start = &ansi_str.Buffer[i]; + + if(ansi_str.Buffer[i] == ';') + { + p_end = &ansi_str.Buffer[i]; + ansi_str.Buffer[i] = '\0'; + __prepare_pKey_array(p_start,(size_t)(p_end - p_start) + 1,&cur_pkey_conf->pkeys_per_port); + + ansi_str.Buffer[i] = ';'; + p_start = NULL; + port_guid_found = FALSE; + } + } + } + RtlFreeAnsiString(&ansi_str); + return STATUS_SUCCESS; +} + +static NTSTATUS +__read_registry( + IN UNICODE_STRING* const p_registry_path ) +{ + NTSTATUS status; + /* Remember the terminating entry in the table below. */ + RTL_QUERY_REGISTRY_TABLE table[12]; + UNICODE_STRING param_path; + UNICODE_STRING pkeyString; + UNICODE_STRING empty_string; + + BUS_ENTER( BUS_DBG_DRV ); + + __read_machine_name(); + + RtlInitUnicodeString( &empty_string,NULL); + RtlInitUnicodeString( ¶m_path, NULL ); + param_path.MaximumLength = p_registry_path->Length + + sizeof(L"\\Parameters"); + param_path.Buffer = cl_zalloc( param_path.MaximumLength ); + if( !param_path.Buffer ) + { + BUS_TRACE_EXIT( BUS_DBG_ERROR, + ("Failed to allocate parameters path buffer.\n") ); + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlAppendUnicodeStringToString( ¶m_path, p_registry_path ); + RtlAppendUnicodeToString( ¶m_path, L"\\Parameters" ); + RtlInitUnicodeString( &pkeyString, NULL ); + pkeyString.MaximumLength = 1024*sizeof(WCHAR); + pkeyString.Buffer = cl_zalloc( pkeyString.MaximumLength ); + if( !pkeyString.Buffer ) + { + cl_free(param_path.Buffer); + BUS_TRACE_EXIT( BUS_DBG_ERROR, + ("Failed to allocate parameters path pkeyString.\n") ); + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* + * Clear the table. This clears all the query callback pointers, + * and sets up the terminating table entry. + */ + cl_memclr( table, sizeof(table) ); + + /* Setup the table entries. */ + table[0].Flags = RTL_QUERY_REGISTRY_DIRECT; + table[0].Name = L"ReportPortNIC"; + table[0].EntryContext = &bus_globals.b_report_port_nic; + table[0].DefaultType = REG_DWORD; + table[0].DefaultData = &bus_globals.b_report_port_nic; + table[0].DefaultLength = sizeof(ULONG); + + table[1].Flags = RTL_QUERY_REGISTRY_DIRECT; + table[1].Name = L"DebugFlags"; + table[1].EntryContext = &bus_globals.dbg_lvl; + table[1].DefaultType = REG_DWORD; + table[1].DefaultData = &bus_globals.dbg_lvl; + table[1].DefaultLength = sizeof(ULONG); + + table[2].Flags = RTL_QUERY_REGISTRY_DIRECT; + table[2].Name = L"IbalDebugLevel"; + table[2].EntryContext = &g_al_dbg_level; + table[2].DefaultType = REG_DWORD; + table[2].DefaultData = &g_al_dbg_level; + table[2].DefaultLength = sizeof(ULONG); + + table[3].Flags = RTL_QUERY_REGISTRY_DIRECT; + table[3].Name = L"IbalDebugFlags"; + table[3].EntryContext = &g_al_dbg_flags; + table[3].DefaultType = REG_DWORD; + table[3].DefaultData = &g_al_dbg_flags; + table[3].DefaultLength = sizeof(ULONG); + + + table[4].Flags = RTL_QUERY_REGISTRY_DIRECT; + table[4].Name = L"SmiPollInterval"; + table[4].EntryContext = &g_smi_poll_interval; + table[4].DefaultType = REG_DWORD; + table[4].DefaultData = &g_smi_poll_interval; + table[4].DefaultLength = sizeof(ULONG); + + table[5].Flags = RTL_QUERY_REGISTRY_DIRECT; + table[5].Name = L"IocQueryTimeout"; + table[5].EntryContext = &g_ioc_query_timeout; + table[5].DefaultType = REG_DWORD; + table[5].DefaultData = &g_ioc_query_timeout; + table[5].DefaultLength = sizeof(ULONG); + + table[6].Flags = RTL_QUERY_REGISTRY_DIRECT; + table[6].Name = L"IocQueryRetries"; + table[6].EntryContext = &g_ioc_query_retries; + table[6].DefaultType = REG_DWORD; + table[6].DefaultData = &g_ioc_query_retries; + table[6].DefaultLength = sizeof(ULONG); + + table[7].Flags = RTL_QUERY_REGISTRY_DIRECT; + table[7].Name = L"IocPollInterval"; + table[7].EntryContext = &g_ioc_poll_interval; + table[7].DefaultType = REG_DWORD; + table[7].DefaultData = &g_ioc_poll_interval; + table[7].DefaultLength = sizeof(ULONG); + + table[8].Flags = RTL_QUERY_REGISTRY_DIRECT; + table[8].Name = L"PartitionKey"; + table[8].EntryContext = &pkeyString; + table[8].DefaultType = REG_SZ; + table[8].DefaultData = &empty_string; + table[8].DefaultLength = 0; + + /* Have at it! */ + status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE, + param_path.Buffer, table, NULL, NULL ); + if (NT_SUCCESS(status)) + { + if( !NT_SUCCESS(__build_pkeys_per_port(&pkeyString))) + BUS_TRACE(BUS_DBG_ERROR , + ("Failed to build pkey configuration\n")); + + if(!NT_SUCCESS(__create_static_devices(¶m_path))){ + BUS_TRACE(BUS_DBG_ERROR , + ("Failed to create devices\n")); + } + } +#if DBG & !defined( EVENT_TRACING ) + if( g_al_dbg_flags & AL_DBG_ERR ) + g_al_dbg_flags |= CL_DBG_ERROR; + + //bus_globals.dbg_lvl |= BUS_DBG_DRV | BUS_DBG_PNP | BUS_DBG_POWER; +#endif + + BUS_TRACE(BUS_DBG_DRV , + ("debug level %d debug flags 0x%.8x\n", + g_al_dbg_level, + g_al_dbg_flags)); + + cl_free( pkeyString.Buffer ); + cl_free( param_path.Buffer ); + BUS_EXIT( BUS_DBG_DRV ); + return status; +} + + +static NTSTATUS +bus_drv_open( + IN DEVICE_OBJECT *p_dev_obj, + IN IRP *p_irp ) +{ + UNUSED_PARAM( p_dev_obj ); + + CL_ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL ); + + /* We always succeed file handles creation. */ + p_irp->IoStatus.Status = STATUS_SUCCESS; + p_irp->IoStatus.Information = 0; + IoCompleteRequest( p_irp, IO_NO_INCREMENT ); + + return STATUS_SUCCESS; +} + + +static NTSTATUS +bus_drv_cleanup( + IN DEVICE_OBJECT *p_dev_obj, + IN IRP *p_irp ) +{ + NTSTATUS status; + + UNUSED_PARAM( p_dev_obj ); + + CL_ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL ); + + /* + * Note that we don't acquire the remove and stop lock on close to allow + * applications to close the device when the locks are already held. + */ + status = cl_to_ntstatus( al_dev_close( p_irp ) ); + + /* Complete the IRP. */ + p_irp->IoStatus.Status = status; + p_irp->IoStatus.Information = 0; + IoCompleteRequest( p_irp, IO_NO_INCREMENT ); + + return status; +} + + +static NTSTATUS +bus_drv_close( + IN DEVICE_OBJECT *p_dev_obj, + IN IRP *p_irp ) +{ + UNUSED_PARAM( p_dev_obj ); + + p_irp->IoStatus.Status = STATUS_SUCCESS; + p_irp->IoStatus.Information = 0; + IoCompleteRequest( p_irp, IO_NO_INCREMENT ); + + return STATUS_SUCCESS; +} + + +static NTSTATUS +bus_drv_ioctl( + IN DEVICE_OBJECT *p_dev_obj, + IN IRP *p_irp ) +{ + NTSTATUS status; + bus_fdo_ext_t *p_ext; + PIO_STACK_LOCATION p_io_stack; + + /* Get the extension. */ + p_ext = p_dev_obj->DeviceExtension; + + /* Get the stack location. */ + p_io_stack = IoGetCurrentIrpStackLocation( p_irp ); + + /* Acquire the stop lock. */ + status = IoAcquireRemoveLock( &p_ext->cl_ext.stop_lock, p_irp ); + if( !NT_SUCCESS( status ) ) + { + p_irp->IoStatus.Status = status; + p_irp->IoStatus.Information = 0; + IoCompleteRequest( p_irp, IO_NO_INCREMENT ); + BUS_EXIT( BUS_DBG_DRV ); + return status; + } + + /* Acquire the remove lock. */ + status = IoAcquireRemoveLock( &p_ext->cl_ext.remove_lock, p_irp ); + if( !NT_SUCCESS( status ) ) + { + IoReleaseRemoveLock( &p_ext->cl_ext.stop_lock, p_irp ); + p_irp->IoStatus.Status = status; + p_irp->IoStatus.Information = 0; + IoCompleteRequest( p_irp, IO_NO_INCREMENT ); + BUS_EXIT( BUS_DBG_DRV ); + return status; + } + + status = cl_to_ntstatus( al_dev_ioctl( p_irp ) ); + + /* Only pass down if not handled and not PDO device. */ + if( status == STATUS_INVALID_DEVICE_REQUEST && p_ext->cl_ext.p_next_do ) + { + IoSkipCurrentIrpStackLocation( p_irp ); + status = IoCallDriver( p_ext->cl_ext.p_next_do, p_irp ); + } + + /* Release the remove and stop locks. */ + IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp ); + IoReleaseRemoveLock( &p_ext->cl_ext.stop_lock, p_irp ); + + return status; +} + +cl_status_t +bus_add_pkey(cl_ioctl_handle_t h_ioctl) +{ + cl_status_t status; + pkey_array_t *pkeys; + PIO_STACK_LOCATION pIoStack; + + BUS_ENTER( BUS_DBG_DRV ); + + pIoStack = IoGetCurrentIrpStackLocation(h_ioctl); + if ( (! h_ioctl->AssociatedIrp.SystemBuffer) || + pIoStack->Parameters.DeviceIoControl.InputBufferLength < sizeof (pkey_array_t)) + { + BUS_TRACE_EXIT( BUS_DBG_ERROR, + ("Invalid parameters.\n") ); + return CL_INVALID_PARAMETER; + } + + pkeys = (pkey_array_t*)h_ioctl->AssociatedIrp.SystemBuffer; + + /* create additional pdo */ + status = port_mgr_pkey_add(pkeys); + if (! NT_SUCCESS(status)) + { + BUS_TRACE_EXIT( BUS_DBG_ERROR, + ("port_mgr_pkey_add returned %08x.\n", status) ); + } + + BUS_EXIT( BUS_DBG_DRV ); + return status; +} + +cl_status_t +bus_rem_pkey(cl_ioctl_handle_t h_ioctl) +{ + cl_status_t status; + pkey_array_t *pkeys; + PIO_STACK_LOCATION pIoStack; + + BUS_ENTER( BUS_DBG_DRV ); + + pIoStack = IoGetCurrentIrpStackLocation(h_ioctl); + if ( (! h_ioctl->AssociatedIrp.SystemBuffer) || + pIoStack->Parameters.DeviceIoControl.InputBufferLength < sizeof (pkey_array_t)) + { + BUS_TRACE_EXIT( BUS_DBG_ERROR, + ("Invalid parameters.\n") ); + return CL_INVALID_PARAMETER; + } + + pkeys = (pkey_array_t*)h_ioctl->AssociatedIrp.SystemBuffer; + + /* removes pdo */ + status = port_mgr_pkey_rem(pkeys); + if (! NT_SUCCESS(status)) + { + BUS_TRACE_EXIT( BUS_DBG_ERROR, + ("port_mgr_pkey_rem returned %08x.\n", status) ); + } + + BUS_EXIT( BUS_DBG_DRV ); + return status; +} +static NTSTATUS +bus_drv_sysctl( + IN DEVICE_OBJECT *p_dev_obj, + IN IRP *p_irp ) +{ + NTSTATUS status; + bus_fdo_ext_t *p_ext; + + BUS_ENTER( BUS_DBG_DRV ); + + CL_ASSERT( p_dev_obj ); + CL_ASSERT( p_irp ); + + p_ext = p_dev_obj->DeviceExtension; + + if( p_ext->cl_ext.p_next_do ) + { + IoSkipCurrentIrpStackLocation( p_irp ); + status = IoCallDriver( p_ext->cl_ext.p_next_do, p_irp ); + } + else + { + status = p_irp->IoStatus.Status; + IoCompleteRequest( p_irp, IO_NO_INCREMENT ); + } + + BUS_EXIT( BUS_DBG_DRV ); + return status; +} + + +static void +bus_drv_unload( + IN DRIVER_OBJECT *p_driver_obj ) +{ + pkey_conf_t *cur_conf,*tmp; + UNUSED_PARAM( p_driver_obj ); + + BUS_ENTER( BUS_DBG_DRV ); + + cur_conf = bus_globals.p_pkey_conf; + while(cur_conf) + { + tmp = cur_conf; + cur_conf = cur_conf->next_conf; + cl_free(tmp); + } + + _free_static_iodevices(); + + + CL_DEINIT; + +#if defined(EVENT_TRACING) + WPP_CLEANUP(p_driver_obj); +#endif + + BUS_TRACE_EXIT( BUS_DBG_DRV, + ("=====> IBBUS: bus_drv_unload exited\n") ); +} + + +NTSTATUS +DriverEntry( + IN DRIVER_OBJECT *p_driver_obj, + IN UNICODE_STRING *p_registry_path ) +{ + NTSTATUS status; + + BUS_ENTER( BUS_DBG_DRV ); + +#if defined(EVENT_TRACING) + WPP_INIT_TRACING(p_driver_obj ,p_registry_path); +#endif + + status = CL_INIT; + if( !NT_SUCCESS(status) ) + { + BUS_TRACE_EXIT( BUS_DBG_ERROR, + ("cl_init returned %08X.\n", status) ); + return status; + } + + /* Store the driver object pointer in the global parameters. */ + bus_globals.p_driver_obj = p_driver_obj; + bus_st_init(); + g_stat.drv.p_globals = &bus_globals; + + /* Get the registry values. */ + status = __read_registry( p_registry_path ); + if( !NT_SUCCESS(status) ) + { + CL_DEINIT; + BUS_TRACE_EXIT( BUS_DBG_ERROR, + ("__read_registry returned %08x.\n", status) ); + return status; + } + + /* create default device descrition for Partition Manager */ + __create_default_dev_info( &g_default_device_info ); + + /* Setup the entry points. */ + p_driver_obj->MajorFunction[IRP_MJ_CREATE] = bus_drv_open; + p_driver_obj->MajorFunction[IRP_MJ_CLEANUP] = bus_drv_cleanup; + p_driver_obj->MajorFunction[IRP_MJ_CLOSE] = bus_drv_close; + p_driver_obj->MajorFunction[IRP_MJ_PNP] = cl_pnp; + p_driver_obj->MajorFunction[IRP_MJ_POWER] = cl_power; + p_driver_obj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = bus_drv_ioctl; + p_driver_obj->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = bus_drv_sysctl; + p_driver_obj->DriverUnload = bus_drv_unload; + p_driver_obj->DriverExtension->AddDevice = bus_add_device; + + // Mutex to synchronize multiple threads creating & deleting + // control deviceobjects. + + KeInitializeEvent(&g_ControlEvent, SynchronizationEvent, TRUE); + g_bfi_InstanceCount = 0; + memset( __out_bcount(sizeof(g_bus_filters)) (void*)g_bus_filters, 0, + sizeof(g_bus_filters) ); + + BUS_TRACE_EXIT( BUS_DBG_DRV, + ("=====> IBBUS: Driver exited\n") ); + return STATUS_SUCCESS; +} diff --git a/branches/WOF2-3/core/bus/kernel/bus_driver.h b/branches/WOF2-3/core/bus/kernel/bus_driver.h new file mode 100644 index 00000000..368b6f95 --- /dev/null +++ b/branches/WOF2-3/core/bus/kernel/bus_driver.h @@ -0,0 +1,317 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + +#if !defined _BUS_DRIVER_H_ +#define _BUS_DRIVER_H_ + +#include "complib/cl_types.h" +#include "complib/cl_atomic.h" +#include "complib/cl_debug.h" +#include "complib/cl_mutex.h" +#include "complib/cl_qlist.h" +#include "complib/cl_ptr_vector.h" +#include "complib/cl_pnp_po.h" +#include "iba/ib_al.h" +#include "bus_port_mgr.h" +#include "bus_iou_mgr.h" +#include "al_dev.h" +#include +#include "bus_stat.h" + +/* Safe string functions. */ +#if WINVER == 0x500 +/* + * Windows 2000 doesn't support the inline version of safe strings. + * Force the use of the library version of safe strings. + */ +#define NTSTRSAFE_LIB +#endif +#include + + +/* + * Main header for IB Bus driver. + */ + +#define BUS_ENTER( lvl ) \ + CL_ENTER( lvl, bus_globals.dbg_lvl ) + +#define BUS_EXIT( lvl ) \ + CL_EXIT( lvl, bus_globals.dbg_lvl ) + +#define BUS_TRACE( lvl, msg ) \ + CL_TRACE( lvl, bus_globals.dbg_lvl, msg ) + +#define BUS_TRACE_EXIT( lvl, msg ) \ + CL_TRACE_EXIT( lvl, bus_globals.dbg_lvl, msg ) + +#define BUS_PRINT( lvl, msg ) \ + CL_PRINT( lvl, bus_globals.dbg_lvl, msg ) + +/* single character Macro elemination */ +#define XBUS_PRINT( lvl, msg ) +#define XBUS_ENTER( lvl ) +#define XBUS_EXIT( lvl ) + +#define BUS_DBG_ERROR CL_DBG_ERROR +#define BUS_DBG_DRV (1 << 0) +#define BUS_DBG_PNP (1 << 1) +#define BUS_DBG_POWER (1 << 2) +#define BUS_DBG_PORT (1 << 3) +#define BUS_DBG_IOU (1 << 4) + +/* + * ALLOC_PRAGMA sections: + * PAGE + * Default pagable code. Won't be locked in memory. + * + * PAGE_PNP + * Code that needs to be locked in memory when the device is + * in the paging, crash dump, or hibernation path. + */ + +/* + * Device extension for the device object that serves as entry point for + * the interface and IOCTL requests. + */ +typedef struct _bus_fdo_ext +{ + cl_pnp_po_ext_t cl_ext; + + /* + * Device power map returned by the bus driver for the device, used + * when sending IRP_MN_SET_POWER for device state in response to + * IRP_MN_SET_POWER for system state. + */ + DEVICE_POWER_STATE po_state[PowerSystemMaximum]; + + /* Number of references on the upper interface. */ + atomic32_t n_al_ifc_ref; + /* Number of references on the CI interface. */ + atomic32_t n_ci_ifc_ref; + /* HCA interface stuff */ + RDMA_INTERFACE_VERBS hca_ifc; + boolean_t hca_ifc_taken; + + struct _bus_filter_instance *bus_filter; + + /* flag, indicating that FDO resources have been released */ + boolean_t ca_registered; + /* current device power state */ + DEVICE_POWER_STATE device_power_state; + /* current system power state */ + SYSTEM_POWER_STATE system_power_state; + /* work item for power operations */ + PIO_WORKITEM p_po_work_item; + /* current PnP state */ + PNP_DEVICE_STATE pnp_state; /* state for PnP Manager */ + /* statistics */ + PBUS_ST_DEVICE p_stat; + +} bus_fdo_ext_t; + + +/* Windows pnp device information */ +#define MAX_DEVICE_ID_LEN 200 +#define MAX_DEVICE_STRING_LEN MAX_DEVICE_ID_LEN + 2 //add extra 4 bytes in case we need double NULL ending +typedef struct _child_device_info { + wchar_t device_id[MAX_DEVICE_STRING_LEN]; + uint32_t device_id_size; + wchar_t compatible_id[MAX_DEVICE_STRING_LEN]; + uint32_t compatible_id_size; + wchar_t hardware_id[MAX_DEVICE_STRING_LEN]; + uint32_t hardware_id_size; + wchar_t description[MAX_DEVICE_STRING_LEN]; + uint32_t description_size; + wchar_t pkey[20]; +} child_device_info_t; + +typedef struct _child_device_info_list{ + child_device_info_t io_device_info; + struct _child_device_info_list *next_device_info; +}child_device_info_list_t; + + +/* + * Device extension for bus driver PDOs. + */ +typedef struct _bus_pdo_ext +{ + cl_pnp_po_ext_t cl_ext; + + cl_list_item_t list_item; + + /* All reported PDOs are children of an HCA. */ + ib_ca_handle_t h_ca; + + /* + * CA GUID copy - in case we get IRPs after the CA + * handle has been released. + */ + net64_t ca_guid; + + POWER_STATE dev_po_state; + + /* + * Pointer to the bus root device extension. Used to manage access to + * child PDO pointer vector when a child is removed politely. + */ + bus_fdo_ext_t *p_parent_ext; + + /* + * The following two flags are exclusively set, but can both be FALSE. + * Flag that indicates whether the device is present in the system or not. + * This affects how a IRP_MN_REMOVE_DEVICE IRP is handled for a child PDO. + * This flag is cleared when: + * - an HCA (for IPoIB devices) is removed from the system for all port + * devices loaded for that HCA + * - an IOU is reported as removed by the CIA. + */ + boolean_t b_present; + + /* + * Flag that indicates whether the device has been reported to the PnP + * manager as having been removed. That is, the device was reported + * in a previous BusRelations query and not in a subsequent one. + * This flag is set when + * - the device is in the surprise remove state when the parent bus + * device is removed + * - the device is found to be not present during a BusRelations query + * and thus not reported. + */ + boolean_t b_reported_missing; + + /* Flag to control the behaviour of the driver during hibernation */ + uint32_t b_hibernating; + + /* work item for handling Power Management request */ + PIO_WORKITEM p_po_work_item; + boolean_t hca_acquired; + child_device_info_t *p_pdo_device_info; +} bus_pdo_ext_t; + +/* pkey configuration */ +typedef struct _pkey_conf_t +{ + pkey_array_t pkeys_per_port; + struct _pkey_conf_t *next_conf; +}pkey_conf_t; + + +/* + * Global Driver parameters. + */ +typedef struct _bus_globals +{ + /* Debug level. */ + uint32_t dbg_lvl; + + /* Flag to control loading of Ip Over Ib driver for each HCA port. */ + uint32_t b_report_port_nic; + + /* Driver object. Used for registering of Plug and Play notifications. */ + DRIVER_OBJECT *p_driver_obj; + + /* IBAL PNP event register handles */ + ib_pnp_handle_t h_pnp_port; + ib_pnp_handle_t h_pnp_iou; + + /* pkey array to be read */ + pkey_conf_t *p_pkey_conf; + + /* saved devices info*/ + child_device_info_list_t *p_device_list; + +} bus_globals_t; + + +extern bus_globals_t bus_globals; + +/* + * Each instance of a bus filter on an HCA device stack (InfiniBandController) + * populates a bus_filter_t slot in g_bus_filters[MAX_BUS_FILTERS]; see + * bus_add_device(). Therefore MAX_BUS_FILTERS represents the MAX number of + * HCA's supported in a single system. + */ +#define MAX_BUS_FILTERS 16 +#define BFI_MAGIC 0xcafebabe + +#define BFI_PORT_MGR_OBJ 1 +#define BFI_IOU_MGR_OBJ 2 + + +typedef struct _bus_filter_instance +{ + /* Pointer to the bus filter instance FDO extention. + * if p_bus_ext is NULL, then it's an empty slot available for allocation + */ + bus_fdo_ext_t *p_bus_ext; + + /* HCA guid for which this bus filter is servicing */ + ib_net64_t ca_guid; + + /* PORT management - on a per HCA basis */ + port_mgr_t *p_port_mgr; + cl_obj_t *p_port_mgr_obj; + + /* IOU management - on a per HCA basis */ + iou_mgr_t *p_iou_mgr; + cl_obj_t *p_iou_mgr_obj; +#if DBG + ULONG magic; // initial/temp debug + char whoami[8]; +#endif + +} bus_filter_t; + +extern bus_filter_t g_bus_filters[MAX_BUS_FILTERS]; +extern ULONG g_bfi_InstanceCount; +extern KEVENT g_ControlEvent; // serializes InstanceCount & g_bus_filters + +extern bus_filter_t *alloc_bfi( IN DRIVER_OBJECT *, OUT int * ); +extern int free_bfi( IN bus_filter_t *p_bfi ); +extern int get_bfi_count( void ); +extern bus_filter_t *get_bfi_by_obj( IN int obj_type, IN cl_obj_t *p_obj ); +extern bus_filter_t *get_bfi_by_ca_guid( IN net64_t ca_guid ); +extern char *get_obj_state_str(cl_state_t state); + +inline VOID lock_control_event() { + KeWaitForSingleObject(&g_ControlEvent, Executive, KernelMode , FALSE, NULL); +} + +inline VOID unlock_control_event() { + KeSetEvent(&g_ControlEvent, 0, FALSE); +} + +#endif /* !defined _BUS_DRIVER_H_ */ diff --git a/branches/WOF2-3/core/bus/kernel/bus_ev_log.mc b/branches/WOF2-3/core/bus/kernel/bus_ev_log.mc new file mode 100644 index 00000000..e60869f1 --- /dev/null +++ b/branches/WOF2-3/core/bus/kernel/bus_ev_log.mc @@ -0,0 +1,56 @@ +;/*++ +;============================================================================= +;Copyright (c) 2009 Mellanox Technologies +; +;Module Name: +; +; bus_ev_log.mc +; +;Abstract: +; +; IB Driver event log messages +; +;Authors: +; +; Leonid Keller +; +;Environment: +; +; Kernel Mode . +; +;============================================================================= +;--*/ +; +MessageIdTypedef = NTSTATUS + +SeverityNames = ( + Success = 0x0:STATUS_SEVERITY_SUCCESS + Informational = 0x1:STATUS_SEVERITY_INFORMATIONAL + Warning = 0x2:STATUS_SEVERITY_WARNING + Error = 0x3:STATUS_SEVERITY_ERROR + ) + +FacilityNames = ( + System = 0x0 + RpcRuntime = 0x2:FACILITY_RPC_RUNTIME + RpcStubs = 0x3:FACILITY_RPC_STUBS + Io = 0x4:FACILITY_IO_ERROR_CODE + IBBUS = 0x9:FACILITY_IB_ERROR_CODE + ) + + +MessageId=0x0001 Facility=IBBUS Severity=Informational SymbolicName=EVENT_IBBUS_ANY_INFO +Language=English +%2 +. + +MessageId=0x0002 Facility=IBBUS Severity=Warning SymbolicName=EVENT_IBBUS_ANY_WARN +Language=English +%2 +. + +MessageId=0x0003 Facility=IBBUS Severity=Error SymbolicName=EVENT_IBBUS_ANY_ERROR +Language=English +%2 +. + diff --git a/branches/WOF2-3/core/bus/kernel/bus_iou_mgr.c b/branches/WOF2-3/core/bus/kernel/bus_iou_mgr.c new file mode 100644 index 00000000..3f1015b0 --- /dev/null +++ b/branches/WOF2-3/core/bus/kernel/bus_iou_mgr.c @@ -0,0 +1,1698 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2006 Mellanox Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include +#include +#include +#include "ib_common.h" +#include "al_ca.h" +#include "al_mgr.h" +#include "bus_pnp.h" +#include "bus_iou_mgr.h" +#include +#include +#include "iba/iou_ifc.h" + + +/* {5A9649F4-0101-4a7c-8337-796C48082DA2} */ +DEFINE_GUID(GUID_BUS_TYPE_IBA, +0x5a9649f4, 0x101, 0x4a7c, 0x83, 0x37, 0x79, 0x6c, 0x48, 0x8, 0x2d, 0xa2); + + +/* + * Size of device descriptions, in the format: + * IBA\VxxxxxxPxxxxxxxxvxxxxxxxx + */ +#define IOU_DEV_ID_SIZE sizeof(L"IBA\\VxxxxxxPxxxxvxxxxxxxx") +#define IOU_DEV_ID_STRING1 L"IBA\\V%06xP%04hxv%08x" +#define IOU_DEV_ID_STRING2 L"IBA\\V%06xP%04hx" +#define IOU_HW_ID_SIZE \ + sizeof(L"IBA\\VxxxxxxPxxxxvxxxxxxxx\0IBA\\VxxxxxxPxxxx\0\0") +#define IOU_COMPAT_ID L"IBA\\IB_IOU\0\0" +#define IOU_LOCATION_SIZE \ + sizeof(L"Chassis 0xxxxxxxxxxxxxxxxx, Slot xx") + +/* + * Device extension for IOU PDOs. + */ +typedef struct _bus_iou_ext +{ + bus_pdo_ext_t pdo; + + net64_t chassis_guid; + uint8_t slot; + net64_t guid; + net32_t vend_id; + net16_t dev_id; + net32_t revision; + char desc[IB_NODE_DESCRIPTION_SIZE + 1]; + + /* Number of references on the upper interface. */ + atomic32_t n_ifc_ref; + +} bus_iou_ext_t; + + +typedef struct _iou_pnp_context +{ + bus_filter_t *p_bus_filter; + void *p_pdo_ext; + +} iou_pnp_ctx_t; + + +/* + * Function prototypes. + */ +void +destroying_iou_mgr( + IN cl_obj_t* p_obj ); + +void +free_iou_mgr( + IN cl_obj_t* p_obj ); + +ib_api_status_t +bus_reg_iou_pnp( + IN bus_filter_t* p_bfi ); + +ib_api_status_t +iou_mgr_pnp_cb( + IN ib_pnp_rec_t* p_pnp_rec ); + +ib_api_status_t +iou_mgr_iou_add( + IN ib_pnp_iou_rec_t* p_pnp_rec ); + +void +iou_mgr_iou_remove( + IN ib_pnp_iou_rec_t* p_pnp_rec ); + +static NTSTATUS +iou_start( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +iou_query_remove( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static void +iou_release_resources( + IN DEVICE_OBJECT* const p_dev_obj ); + +static NTSTATUS +iou_remove( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +iou_surprise_remove( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +iou_query_capabilities( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +iou_query_target_relations( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +iou_query_device_id( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp ); + +static NTSTATUS +iou_query_hardware_ids( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp ); + +static NTSTATUS +iou_query_compatible_ids( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp ); + +static NTSTATUS +iou_query_unique_id( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp ); + +static NTSTATUS +iou_query_description( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp ); + +static NTSTATUS +iou_query_location( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp ); + +static NTSTATUS +iou_query_bus_info( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +iou_query_interface( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +iou_set_power( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + + + +/* + * Global virtual function pointer tables shared between all + * instances of Port PDOs. + */ +static const cl_vfptr_pnp_po_t vfptr_iou_pnp = { + "IB IOU", + iou_start, + cl_irp_succeed, + cl_irp_succeed, + cl_irp_succeed, + iou_query_remove, + iou_release_resources, + iou_remove, + cl_irp_succeed, + iou_surprise_remove, + iou_query_capabilities, + cl_irp_complete, + cl_irp_complete, + cl_irp_succeed, + cl_irp_complete, + cl_irp_complete, + cl_irp_complete, + iou_query_target_relations, + cl_irp_complete, + cl_irp_complete, + cl_irp_complete, + iou_query_bus_info, + iou_query_interface, + cl_irp_complete, + cl_irp_complete, + cl_irp_complete, + cl_irp_complete, + cl_irp_succeed, // QueryPower + iou_set_power, // SetPower + cl_irp_unsupported, // PowerSequence + cl_irp_unsupported // WaitWake +}; + + +static const cl_vfptr_query_txt_t vfptr_iou_query_txt = { + iou_query_device_id, + iou_query_hardware_ids, + iou_query_compatible_ids, + iou_query_unique_id, + iou_query_description, + iou_query_location +}; + + +/* + * Create the AL load service. + */ +ib_api_status_t +create_iou_mgr( + IN bus_filter_t* p_bfi ) +{ + ib_api_status_t status; + cl_status_t cl_status; + iou_mgr_t *p_iou_mgr; + + BUS_ENTER( BUS_DBG_PNP ); + + CL_ASSERT( p_bfi->p_iou_mgr == NULL ); + + p_iou_mgr = cl_zalloc( sizeof(iou_mgr_t) ); + if( !p_iou_mgr ) + { + BUS_TRACE_EXIT( BUS_DBG_ERROR, + ("Failed to allocate IOU manager.\n") ); + return IB_INSUFFICIENT_MEMORY; + } + p_bfi->p_iou_mgr = p_iou_mgr; + + /* Construct the load service. */ + cl_obj_construct( &p_iou_mgr->obj, AL_OBJ_TYPE_LOADER ); + + p_bfi->p_iou_mgr_obj = &p_bfi->p_iou_mgr->obj; // save for destroy & free + + cl_mutex_construct( &p_iou_mgr->pdo_mutex ); + cl_qlist_init( &p_iou_mgr->iou_list ); + + cl_status = cl_mutex_init( &p_iou_mgr->pdo_mutex ); + if( cl_status != CL_SUCCESS ) + { + free_iou_mgr( &p_iou_mgr->obj ); + BUS_TRACE_EXIT( BUS_DBG_ERROR, + ("cl_mutex_init returned %#x.\n", cl_status) ); + return ib_convert_cl_status( cl_status ); + } + + /* Initialize the load service object. */ + cl_status = cl_obj_init( &p_iou_mgr->obj, CL_DESTROY_SYNC, + destroying_iou_mgr, NULL, free_iou_mgr ); + if( cl_status != CL_SUCCESS ) + { + free_iou_mgr( &p_iou_mgr->obj ); + BUS_TRACE_EXIT( BUS_DBG_ERROR, + ("cl_obj_init returned %#x.\n", cl_status) ); + return ib_convert_cl_status( cl_status ); + } + + /* Register for IOU PnP events. */ + status = bus_reg_iou_pnp( p_bfi ); + if( status != IB_SUCCESS ) + { + free_iou_mgr( &p_iou_mgr->obj ); + BUS_TRACE_EXIT( BUS_DBG_ERROR, + ("bus_reg_iou_pnp returned %s.\n", ib_get_err_str(status)) ); + return status; + } + + BUS_EXIT( BUS_DBG_PNP ); + return IB_SUCCESS; +} + + +/* + * Pre-destroy the load service. + */ +void +destroying_iou_mgr( + IN cl_obj_t* p_obj ) +{ + ib_api_status_t status; + bus_filter_t *p_bfi; + iou_mgr_t *p_iou_mgr; + + BUS_ENTER( BUS_DBG_PNP ); + + CL_ASSERT( p_obj ); + p_bfi = get_bfi_by_obj( BFI_IOU_MGR_OBJ, p_obj ); + if (p_bfi == NULL) { + BUS_PRINT(BUS_DBG_PNP, ("Failed to find p_bfi by obj %p?\n", p_obj)); + return; + } + p_iou_mgr = p_bfi->p_iou_mgr; + + BUS_PRINT(BUS_DBG_PNP, ("%s obj %p iou_mgr %p iou_mgr_obj %p\n", + p_bfi->whoami, p_obj,p_iou_mgr,&p_iou_mgr->obj)); + + CL_ASSERT( p_iou_mgr == PARENT_STRUCT( p_obj, iou_mgr_t, obj ) ); + + /* Deregister for iou PnP events. */ + if( get_bfi_count() == 1 && bus_globals.h_pnp_iou ) + { + status = ib_dereg_pnp( bus_globals.h_pnp_iou, NULL ); + bus_globals.h_pnp_iou = NULL; + CL_ASSERT( status == IB_SUCCESS ); + } + cl_obj_deref( p_bfi->p_iou_mgr_obj ); + + BUS_EXIT( BUS_DBG_PNP ); +} + + +/* + * Free the load service. + */ +void +free_iou_mgr( + IN cl_obj_t* p_obj ) +{ + bus_pdo_ext_t *p_ext; + cl_list_item_t *p_list_item; + bus_filter_t *p_bfi; + iou_mgr_t *p_iou_mgr; + + BUS_ENTER( BUS_DBG_PNP ); + + CL_ASSERT( p_obj ); + p_bfi = get_bfi_by_obj( BFI_IOU_MGR_OBJ, p_obj ); + if ( p_bfi == NULL ) { + BUS_TRACE( BUS_DBG_ERROR, ("Unable to get p_bfi iou_obj %p?\n", p_obj) ); + return; + } + p_iou_mgr = p_bfi->p_iou_mgr; + if ( !p_iou_mgr ) { + BUS_TRACE_EXIT( BUS_DBG_ERROR, ("%s IOU mgr?\n",p_bfi->whoami) ); + // if create fails & then free is called, p_bfi->p_iou_mgr == NULL + return; + } + + CL_ASSERT( p_iou_mgr == PARENT_STRUCT( p_obj, iou_mgr_t, obj ) ); + + BUS_PRINT( BUS_DBG_PNP, ("%s Mark all IOU PDOs as no longer present\n", + p_bfi->whoami)); + /* + * Mark all IOU PDOs as no longer present. This will cause them + * to be removed when they process the IRP_MN_REMOVE_DEVICE. + */ + p_list_item = cl_qlist_remove_head( &p_iou_mgr->iou_list ); + while( p_list_item != cl_qlist_end( &p_iou_mgr->iou_list ) ) + { + p_ext = PARENT_STRUCT( p_list_item, bus_pdo_ext_t, list_item ); + p_list_item = cl_qlist_remove_head( &p_iou_mgr->iou_list ); + if( p_ext->cl_ext.pnp_state == SurpriseRemoved ) + { + CL_ASSERT( !p_ext->b_present ); + p_ext->b_reported_missing = TRUE; + BUS_TRACE( BUS_DBG_PNP, + ("%s Surprise-remove %s: ext %p, present %d, missing %d\n", + p_bfi->whoami, + p_ext->cl_ext.vfptr_pnp_po->identity, p_ext, + p_ext->b_present, p_ext->b_reported_missing ) ); + continue; + } + + if( p_ext->h_ca ) + { + /* Invalidate bus relations for the HCA. */ + IoInvalidateDeviceRelations( + p_ext->h_ca->p_hca_dev, BusRelations ); + + /* Release the reference on the CA object. */ + deref_al_obj( &p_ext->h_ca->obj ); + } + + BUS_TRACE( BUS_DBG_PNP, ("Deleted device %s %s: PDO %p, ext %p\n", + p_bfi->whoami, p_ext->cl_ext.vfptr_pnp_po->identity, + p_ext->cl_ext.p_self_do, p_ext ) ); + + IoDeleteDevice( p_ext->cl_ext.p_self_do ); + } + + cl_mutex_destroy( &p_iou_mgr->pdo_mutex ); + cl_obj_deinit( p_obj ); + cl_free( p_iou_mgr ); + + p_bfi->p_iou_mgr = NULL; + p_bfi->p_iou_mgr_obj = NULL; + + BUS_EXIT( BUS_DBG_PNP ); +} + + +/* + * Register the load service for the given PnP class events. + */ +ib_api_status_t +bus_reg_iou_pnp( IN bus_filter_t *p_bfi ) +{ + ib_pnp_req_t pnp_req; + ib_api_status_t status = IB_SUCCESS; + boolean_t need_pnp_reg = FALSE; + + /* only need to register for IOU PNP events once. + * do not hold mutex over pnp_reg() call as callback which needs mutex + * could occur. + */ + if ( !bus_globals.h_pnp_iou ) + { + lock_control_event(); + if ( !bus_globals.h_pnp_iou ) + { + bus_globals.h_pnp_iou = (ib_pnp_handle_t)1; /* block others */ + need_pnp_reg = TRUE; + } + unlock_control_event(); + + if ( need_pnp_reg ) + { + cl_memclr( &pnp_req, sizeof( ib_pnp_req_t ) ); + pnp_req.pnp_class = IB_PNP_IOU | IB_PNP_FLAG_REG_SYNC; + pnp_req.pnp_context = NULL; + pnp_req.pfn_pnp_cb = iou_mgr_pnp_cb; + + status = ib_reg_pnp( gh_al, &pnp_req, &bus_globals.h_pnp_iou ); + } + } + + if ( status == IB_SUCCESS ) + { + /* Reference the load service on behalf of the ib_reg_pnp call. */ + cl_obj_ref( p_bfi->p_iou_mgr_obj ); + } + + return status; +} + + +/* + * Load service PnP event callback. + */ +ib_api_status_t +iou_mgr_pnp_cb( + IN ib_pnp_rec_t* p_pnp_rec ) +{ + ib_api_status_t status=IB_SUCCESS; + + BUS_ENTER( BUS_DBG_PNP ); + + CL_ASSERT( p_pnp_rec ); + + switch( p_pnp_rec->pnp_event ) + { + case IB_PNP_IOU_ADD: + status = iou_mgr_iou_add( (ib_pnp_iou_rec_t*)p_pnp_rec ); + break; + + case IB_PNP_IOU_REMOVE: + iou_mgr_iou_remove( (ib_pnp_iou_rec_t*)p_pnp_rec ); + break; + + default: + BUS_PRINT( BUS_DBG_PNP, ("Unhandled PNP Event %s\n", + ib_get_pnp_event_str(p_pnp_rec->pnp_event) )); + break; + } + BUS_EXIT( BUS_DBG_PNP ); + return status; +} + + +/* + * Called to get child relations for the bus root. + */ +NTSTATUS +iou_mgr_get_bus_relations( + IN const net64_t ca_guid, + IN IRP* const p_irp ) +{ + NTSTATUS status; + bus_filter_t *p_bfi; + iou_mgr_t *p_iou_mgr; + DEVICE_RELATIONS *p_rel; + + BUS_ENTER( BUS_DBG_PNP ); + + BUS_PRINT(BUS_DBG_PNP, ("CA_guid %I64x\n",ca_guid)); + + /* special case guid == 0 - walk all bus filter instances */ + if ( ca_guid == 0ULL ) { + for(p_bfi=g_bus_filters; p_bfi < &g_bus_filters[MAX_BUS_FILTERS]; p_bfi++) { + p_iou_mgr = p_bfi->p_iou_mgr; + if ( !p_iou_mgr ) + continue; + cl_mutex_acquire( &p_iou_mgr->pdo_mutex ); + status = bus_get_relations( &p_iou_mgr->iou_list, ca_guid, p_irp ); + cl_mutex_release( &p_iou_mgr->pdo_mutex ); + } + p_rel = (DEVICE_RELATIONS*)p_irp->IoStatus.Information; + if ( p_rel ) { + BUS_PRINT(BUS_DBG_PNP, ("CA_guid 0 Reports %d relations\n", p_rel->Count)); + } + BUS_EXIT( BUS_DBG_PNP ); + return STATUS_SUCCESS; + } + + p_bfi = get_bfi_by_ca_guid(ca_guid); + if (p_bfi == NULL) { + BUS_TRACE_EXIT(BUS_DBG_PNP, + ("NULL p_bfi from ca_guid %I64x ?\n",ca_guid)); + return STATUS_UNSUCCESSFUL; + } + p_iou_mgr = p_bfi->p_iou_mgr; + + BUS_PRINT(BUS_DBG_PNP, ("%s for ca_guid %I64x iou_mgr %p\n", + p_bfi->whoami, ca_guid, p_iou_mgr) ); + if (!p_iou_mgr) + return STATUS_NO_SUCH_DEVICE; + + cl_mutex_acquire( &p_iou_mgr->pdo_mutex ); + status = bus_get_relations( &p_iou_mgr->iou_list, ca_guid, p_irp ); + cl_mutex_release( &p_iou_mgr->pdo_mutex ); + + BUS_EXIT( BUS_DBG_PNP ); + return status; +} + + +static ib_api_status_t +__iou_was_hibernated( + IN ib_pnp_iou_rec_t* p_pnp_rec, + IN bus_filter_t* p_bfi ) +{ + ib_api_status_t status; + cl_list_item_t *p_list_item; + bus_iou_ext_t *p_iou_ext; + bus_pdo_ext_t *p_pdo_ext = NULL; + size_t n_devs = 0; + iou_mgr_t *p_iou_mgr = p_bfi->p_iou_mgr; + cl_qlist_t *p_pdo_list = &p_iou_mgr->iou_list; + iou_pnp_ctx_t *p_ctx = p_pnp_rec->pnp_rec.context; + + BUS_ENTER( BUS_DBG_PNP ); + + cl_mutex_acquire( &p_iou_mgr->pdo_mutex ); + + /* Count the number of child devices. */ + for( p_list_item = cl_qlist_head( p_pdo_list ); + p_list_item != cl_qlist_end( p_pdo_list ); + p_list_item = cl_qlist_next( p_list_item ) ) + { + p_pdo_ext = PARENT_STRUCT( p_list_item, bus_pdo_ext_t, list_item ); + p_iou_ext = (bus_iou_ext_t*)p_pdo_ext; + + /* TODO: maybe we need more search patterns like vend_id, dev_id ... */ + if( p_pdo_ext->b_present && p_pdo_ext->b_hibernating && + (p_iou_ext->guid == p_pnp_rec->pnp_rec.guid) ) + { + n_devs++; + break; + } + + BUS_TRACE( BUS_DBG_PNP, ("%s Skipped PDO for %s: PDO %p, ext %p, " + "present %d, missing %d, hibernating %d, port_guid %I64x.\n", + p_bfi->whoami, + p_pdo_ext->cl_ext.vfptr_pnp_po->identity, + p_pdo_ext->cl_ext.p_self_do, + p_pdo_ext, p_pdo_ext->b_present, p_pdo_ext->b_reported_missing, + p_pdo_ext->b_hibernating, p_iou_ext->guid ) ); + } + + if (n_devs) + { + /* Take a reference on the parent HCA. */ + p_pdo_ext->h_ca = acquire_ca( p_pnp_rec->ca_guid ); + if( !p_pdo_ext->h_ca ) + { + BUS_TRACE( BUS_DBG_ERROR, + ("acquire_ca failed to find CA by guid %I64x\n", + p_pnp_rec->ca_guid ) ); + status = IB_INVALID_GUID; + } + else + { + p_pdo_ext->b_hibernating = FALSE; + p_ctx->p_pdo_ext = p_pdo_ext; // for iou_mgr_iou_remove() + + status = IB_SUCCESS; + p_iou_ext = (bus_iou_ext_t*)p_pdo_ext; + BUS_TRACE( BUS_DBG_PNP, ("%s Found PDO for %s: PDO %p, ext %p, " + "present %d, missing %d, hibernating %d, port_guid %I64x.\n", + p_bfi->whoami, + p_pdo_ext->cl_ext.vfptr_pnp_po->identity, + p_pdo_ext->cl_ext.p_self_do, + p_pdo_ext, p_pdo_ext->b_present, p_pdo_ext->b_reported_missing, + p_pdo_ext->b_hibernating, p_iou_ext->guid ) ); + } + } + else + { + BUS_TRACE( BUS_DBG_PNP, ("%s Failed to find PDO for guid %I64x\n", + p_bfi->whoami, p_pnp_rec->pnp_rec.guid ) ); + status = IB_NOT_FOUND; + } + + cl_mutex_release( &p_iou_mgr->pdo_mutex ); + + BUS_EXIT( BUS_DBG_PNP ); + return status; +} + +ib_api_status_t +iou_mgr_iou_add( + IN ib_pnp_iou_rec_t* p_pnp_rec ) +{ + NTSTATUS status; + DEVICE_OBJECT *p_pdo; + bus_iou_ext_t *p_iou_ext; + bus_filter_t *p_bfi; + iou_mgr_t *p_iou_mgr; + iou_pnp_ctx_t *p_ctx = p_pnp_rec->pnp_rec.context; + + BUS_ENTER( BUS_DBG_PNP ); + + p_bfi = get_bfi_by_ca_guid( p_pnp_rec->ca_guid ); + if ( !p_bfi ) { + BUS_TRACE_EXIT( BUS_DBG_PNP,("NULL p_bfi? ca_guid 0x%I64x\n", + p_pnp_rec->ca_guid ) ); + return IB_ERROR; + } + + if ( !p_ctx ) { + /* + * Allocate a PNP context for this object. pnp_rec.context is object + * unique. + */ + p_ctx = cl_zalloc( sizeof(*p_ctx) ); + if( !p_ctx ) + { + BUS_TRACE_EXIT(BUS_DBG_PNP, ("%s ca_guid %I64x iou_guid(%I64x) " + "BAD alloc for PNP context\n", p_bfi->whoami, + p_bfi->ca_guid, p_pnp_rec->guid )); + + return IB_ERROR; + } + p_ctx->p_bus_filter = p_bfi; + p_pnp_rec->pnp_rec.context = p_ctx; + + BUS_PRINT(BUS_DBG_PNP, + ("%s ca_guid %I64x iou_guid(%I64x) ALLOC p_ctx @ %p\n", + p_bfi->whoami, p_bfi->ca_guid, p_pnp_rec->guid,p_ctx)); + } + p_iou_mgr = p_bfi->p_iou_mgr; + + /* Upon hibernating the computer IB_BUS driver doesn't remove PDO, but + marks with a flag. So we first try to find an existing PDO for this port, + marked with this flag. If it was found, we turn off the flag and use + this PDO */ + status = __iou_was_hibernated( p_pnp_rec, p_bfi ); + if( status != IB_NOT_FOUND ) + { + BUS_EXIT( BUS_DBG_PNP ); + return status; + } + + /* Create the PDO for the new port device. */ + status = IoCreateDevice( bus_globals.p_driver_obj, sizeof(bus_iou_ext_t), + NULL, FILE_DEVICE_CONTROLLER, + FILE_DEVICE_SECURE_OPEN | + FILE_AUTOGENERATED_DEVICE_NAME, + FALSE, &p_pdo ); + + if( !NT_SUCCESS( status ) ) + { + BUS_TRACE_EXIT( BUS_DBG_ERROR, + ("IoCreateDevice returned %08x.\n", status) ); + return IB_ERROR; + } + + p_iou_ext = p_pdo->DeviceExtension; + memset( p_iou_ext, 0, sizeof(bus_iou_ext_t) ); + + /* Initialize the device extension. */ + cl_init_pnp_po_ext( p_pdo, NULL, p_pdo, bus_globals.dbg_lvl, + &vfptr_iou_pnp, &vfptr_iou_query_txt ); + + /* Set the DO_BUS_ENUMERATED_DEVICE flag to mark it as a PDO. */ + p_pdo->Flags |= DO_BUS_ENUMERATED_DEVICE; + + p_iou_ext->pdo.dev_po_state.DeviceState = PowerDeviceD0; + p_iou_ext->pdo.p_parent_ext = p_bfi->p_bus_ext; + p_iou_ext->pdo.b_present = TRUE; + p_iou_ext->pdo.b_reported_missing = FALSE; + + BUS_TRACE( BUS_DBG_PNP, ("%s: ext %p, present %d, missing %d .\n", + p_iou_ext->pdo.cl_ext.vfptr_pnp_po->identity, p_iou_ext, + p_iou_ext->pdo.b_present, p_iou_ext->pdo.b_reported_missing ) ); + + p_iou_ext->guid = p_pnp_rec->guid; + p_iou_ext->chassis_guid = p_pnp_rec->chassis_guid; + p_iou_ext->slot = p_pnp_rec->slot; + p_iou_ext->vend_id = cl_ntoh32( p_pnp_rec->vend_id ); + if( p_iou_ext->vend_id == 0x00066a ) + p_iou_ext->dev_id = (net16_t)(p_pnp_rec->pnp_rec.guid >> 32) & 0x00FF; + else + p_iou_ext->dev_id = cl_ntoh16( p_pnp_rec->dev_id ); + p_iou_ext->revision = cl_ntoh32( p_pnp_rec->revision ); + cl_memcpy( p_iou_ext->desc, p_pnp_rec->desc, + IB_NODE_DESCRIPTION_SIZE + 1 ); + p_iou_ext->n_ifc_ref = 0; + + /* Cache the CA GUID. */ + p_iou_ext->pdo.ca_guid = p_pnp_rec->ca_guid; + + /* Take a reference on the parent HCA. */ + p_iou_ext->pdo.h_ca = acquire_ca( p_pnp_rec->ca_guid ); + if( !p_iou_ext->pdo.h_ca ) + { + IoDeleteDevice( p_pdo ); + BUS_TRACE_EXIT( BUS_DBG_ERROR, ("acquire_ca failed to find CA.\n") ); + return IB_INVALID_GUID; + } + + /* Store the device extension in the PDO list for future queries. */ + cl_mutex_acquire( &p_iou_mgr->pdo_mutex ); + cl_qlist_insert_tail( &p_iou_mgr->iou_list, &p_iou_ext->pdo.list_item ); + cl_mutex_release( &p_iou_mgr->pdo_mutex ); + + /* + * Set the context of the PNP event. The context is passed in for future + * events on the same port. + */ + /* if not set in iou_was_hibernated(), set now */ + if ( !p_ctx->p_pdo_ext ) + p_ctx->p_pdo_ext = p_iou_ext; + + /* Tell the PnP Manager to rescan for the HCA's bus relations. */ + IoInvalidateDeviceRelations( + p_iou_ext->pdo.h_ca->p_hca_dev, BusRelations ); + + /* Invalidate removal relations for the bus driver. */ + IoInvalidateDeviceRelations( + p_bfi->p_bus_ext->cl_ext.p_pdo, RemovalRelations ); + + BUS_EXIT( BUS_DBG_PNP ); + + return IB_SUCCESS; +} + + +void +iou_mgr_iou_remove( + IN ib_pnp_iou_rec_t* p_pnp_rec ) +{ + bus_pdo_ext_t *p_ext; + iou_mgr_t *p_iou_mgr; + bus_filter_t *p_bfi; + iou_pnp_ctx_t *p_ctx = p_pnp_rec->pnp_rec.context; + + BUS_ENTER( BUS_DBG_PNP ); + + if ( !p_ctx ) { + BUS_EXIT( BUS_DBG_PNP ); + return; + } + + CL_ASSERT( p_ctx->p_bus_filter->magic == BFI_MAGIC ); + p_bfi = p_ctx->p_bus_filter; + CL_ASSERT( p_bfi ); + + BUS_PRINT(BUS_DBG_PNP,("%s ca_guid 0x%I64x iou_mgr %p\n", + p_bfi->whoami, p_bfi->ca_guid, p_bfi->p_iou_mgr)); + + /* fdo_release_resources() has destroyed the IOU mgr, all that needs to be + * done is cleanup the PNP IOU context; one per port. + */ + if ( p_bfi->ca_guid == 0ULL || !p_bfi->p_iou_mgr ) { + cl_free( p_ctx ); + p_pnp_rec->pnp_rec.context = NULL; + BUS_EXIT( BUS_DBG_PNP ); + return; + } + + p_iou_mgr = p_bfi->p_iou_mgr; + + /* Within the PNP record's context is the IOU extension; see + * was_hibernated(). + */ + p_ext = p_ctx->p_pdo_ext; + CL_ASSERT( p_ext ); + + if (p_bfi != p_ext->p_parent_ext->bus_filter) { + BUS_PRINT(BUS_DBG_PNP, + ("p_bfi(%p) != p_ext->bus_filter(%p) line %d file %s\n", + p_bfi,p_ext->p_parent_ext->bus_filter, __LINE__,__FILE__)); + CL_ASSERT (p_bfi == p_ext->p_parent_ext->bus_filter); + } + + /* + * Flag the port PDO as no longer being present. We have to wait until + * the PnP manager removes it to clean up. However, we do release the + * reference on the CA object in order to allow the removal of the HCA + * to proceed should it occur before the port's PDO is cleaned up. + */ + cl_mutex_acquire( &p_iou_mgr->pdo_mutex ); + if ( !p_ext->h_ca ) + { + BUS_TRACE_EXIT( BUS_DBG_PNP, ("NULL h_ca? p_ext %p\n", p_ext ) ); + return; + } + + if( p_ext->b_hibernating ) + { + BUS_TRACE( BUS_DBG_PNP, ("%s Skip port removing for %s: PDO %p ext %p " + "present %d missing %d hibernating %d\n", + p_bfi->whoami, + p_ext->cl_ext.vfptr_pnp_po->identity, p_ext->cl_ext.p_self_do, + p_ext, p_ext->b_present, + p_ext->b_reported_missing, p_ext->b_hibernating ) ); + goto hca_deref; + } + + p_ext->b_present = FALSE; + p_ext->b_reported_missing = TRUE; + + BUS_TRACE( BUS_DBG_PNP, ("%s %s: ext %p, present %d, missing %d .\n", + p_bfi->whoami, + p_ext->cl_ext.vfptr_pnp_po->identity, p_ext, p_ext->b_present, + p_ext->b_reported_missing ) ); + + /* Invalidate removal relations for the bus driver. */ + IoInvalidateDeviceRelations( + p_bfi->p_bus_ext->cl_ext.p_pdo, RemovalRelations ); + + /* Invalidate bus relations for the HCA. */ + IoInvalidateDeviceRelations( + p_ext->h_ca->p_hca_dev, BusRelations ); + +hca_deref: + /* free PNP context */ + cl_free( p_ctx ); + p_pnp_rec->pnp_rec.context = NULL; + + deref_al_obj( &p_ext->h_ca->obj ); + p_ext->h_ca = NULL; + + cl_mutex_release( &p_iou_mgr->pdo_mutex ); + + BUS_EXIT( BUS_DBG_PNP ); +} + + +static NTSTATUS +iou_start( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + bus_pdo_ext_t *p_ext; + + BUS_ENTER( BUS_DBG_PNP ); + + UNUSED_PARAM( p_irp ); + + p_ext = p_dev_obj->DeviceExtension; + + /* Notify the Power Manager that the device is started. */ + PoSetPowerState( p_dev_obj, DevicePowerState, p_ext->dev_po_state ); + + *p_action = IrpComplete; + BUS_EXIT( BUS_DBG_PNP ); + return STATUS_SUCCESS; +} + + +static NTSTATUS +iou_query_remove( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + bus_iou_ext_t *p_ext; + + BUS_ENTER( BUS_DBG_PNP ); + + UNUSED_PARAM( p_irp ); + + p_ext = p_dev_obj->DeviceExtension; + + *p_action = IrpComplete; + if( p_ext->n_ifc_ref ) + { + /* + * Our interface is still being held by someone. + * Rollback the PnP state that was changed in the complib handler. + */ + cl_rollback_pnp_state( &p_ext->pdo.cl_ext ); + + /* Fail the query. */ + BUS_TRACE_EXIT( BUS_DBG_PNP, ("Failing IRP_MN_QUERY_REMOVE_DEVICE:\n" + "\tInterface has %d reference\n", p_ext->n_ifc_ref ) ); + return STATUS_UNSUCCESSFUL; + } + + BUS_EXIT( BUS_DBG_PNP ); + return STATUS_SUCCESS; +} + + +static void +iou_release_resources( + IN DEVICE_OBJECT* const p_dev_obj ) +{ + bus_iou_ext_t *p_ext; + POWER_STATE po_state; + iou_mgr_t *p_iou_mgr; + + BUS_ENTER( BUS_DBG_PNP ); + + p_ext = p_dev_obj->DeviceExtension; + p_iou_mgr = p_ext->pdo.p_parent_ext->bus_filter->p_iou_mgr; + + /* Remove this PDO from its list. */ + cl_mutex_acquire( &p_iou_mgr->pdo_mutex ); + BUS_TRACE( BUS_DBG_PNP, ("Removing IOU from list.\n") ); + cl_qlist_remove_item( &p_iou_mgr->iou_list, &p_ext->pdo.list_item ); + cl_mutex_release( &p_iou_mgr->pdo_mutex ); + po_state.DeviceState = PowerDeviceD3; + PoSetPowerState( p_ext->pdo.cl_ext.p_pdo, DevicePowerState, po_state ); + + BUS_EXIT( BUS_DBG_PNP ); +} + + +static NTSTATUS +iou_remove( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + bus_iou_ext_t *p_ext; + + BUS_ENTER( BUS_DBG_PNP ); + + p_ext = p_dev_obj->DeviceExtension; + + if( p_ext->pdo.b_present ) + { + CL_ASSERT( p_ext->pdo.cl_ext.pnp_state != NotStarted ); + CL_ASSERT( !p_ext->pdo.b_reported_missing ); + /* Reset the state to NotStarted. CompLib set it to Deleted. */ + cl_set_pnp_state( &p_ext->pdo.cl_ext, NotStarted ); + /* Don't delete the device. It may simply be disabled. */ + *p_action = IrpComplete; + BUS_TRACE_EXIT( BUS_DBG_PNP, + ("Device %s still present: PDO %p, ext %p\n", + p_ext->pdo.cl_ext.vfptr_pnp_po->identity, p_dev_obj, p_ext) ); + return STATUS_SUCCESS; + } + + if( !p_ext->pdo.b_reported_missing ) + { + /* Reset the state to RemovePending. Complib set it to Deleted. */ + cl_rollback_pnp_state( &p_ext->pdo.cl_ext ); + *p_action = IrpComplete; + BUS_TRACE_EXIT( BUS_DBG_PNP, ("Device not reported missing yet.\n") ); + return STATUS_SUCCESS; + } + + /* Wait for all I/O operations to complete. */ + IoReleaseRemoveLockAndWait( &p_ext->pdo.cl_ext.remove_lock, p_irp ); + + /* Release resources if it was not done yet. */ + if( p_ext->pdo.cl_ext.last_pnp_state != SurpriseRemoved ) + p_ext->pdo.cl_ext.vfptr_pnp_po->pfn_release_resources( p_dev_obj ); + + p_irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest( p_irp, IO_NO_INCREMENT ); + + IoDeleteDevice( p_dev_obj ); + + *p_action = IrpDoNothing; + BUS_EXIT( BUS_DBG_PNP ); + return STATUS_SUCCESS; +} + + +static NTSTATUS +iou_surprise_remove( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + bus_iou_ext_t *p_ext; + + BUS_ENTER( BUS_DBG_PNP ); + + UNUSED_PARAM( p_irp ); + + p_ext = p_dev_obj->DeviceExtension; + p_ext->pdo.b_present = FALSE; + p_ext->pdo.b_reported_missing = TRUE; + + BUS_TRACE( BUS_DBG_PNP, ("%s: ext %p, present %d, missing %d .\n", + p_ext->pdo.cl_ext.vfptr_pnp_po->identity, p_ext, + p_ext->pdo.b_present, p_ext->pdo.b_reported_missing ) ); + + *p_action = IrpComplete; + + BUS_EXIT( BUS_DBG_PNP ); + return STATUS_SUCCESS; +} + + +static NTSTATUS +iou_query_capabilities( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + DEVICE_CAPABILITIES *p_caps; + IO_STACK_LOCATION *p_io_stack; + + BUS_ENTER( BUS_DBG_PNP ); + + UNUSED_PARAM( p_dev_obj ); + + p_io_stack = IoGetCurrentIrpStackLocation( p_irp ); + p_caps = p_io_stack->Parameters.DeviceCapabilities.Capabilities; + + p_caps->DeviceD1 = FALSE; + p_caps->DeviceD2 = FALSE; + p_caps->LockSupported = FALSE; + p_caps->EjectSupported = FALSE; + p_caps->Removable = TRUE; + p_caps->DockDevice = FALSE; + p_caps->UniqueID = TRUE; + p_caps->SilentInstall = TRUE; + p_caps->RawDeviceOK = FALSE; + p_caps->SurpriseRemovalOK = FALSE; + p_caps->WakeFromD0 = FALSE; + p_caps->WakeFromD1 = FALSE; + p_caps->WakeFromD2 = FALSE; + p_caps->WakeFromD3 = FALSE; + p_caps->HardwareDisabled = FALSE; + p_caps->DeviceState[PowerSystemWorking] = PowerDeviceD0; + p_caps->DeviceState[PowerSystemSleeping1] = PowerDeviceD3; + p_caps->DeviceState[PowerSystemSleeping2] = PowerDeviceD3; + p_caps->DeviceState[PowerSystemSleeping3] = PowerDeviceD3; + p_caps->DeviceState[PowerSystemHibernate] = PowerDeviceD3; + p_caps->DeviceState[PowerSystemShutdown] = PowerDeviceD3; + p_caps->SystemWake = PowerSystemUnspecified; + p_caps->DeviceWake = PowerDeviceUnspecified; + p_caps->D1Latency = 0; + p_caps->D2Latency = 0; + p_caps->D3Latency = 0; + + *p_action = IrpComplete; + BUS_EXIT( BUS_DBG_PNP ); + return STATUS_SUCCESS; +} + + +static NTSTATUS +iou_query_target_relations( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + NTSTATUS status; + DEVICE_RELATIONS *p_rel; + + BUS_ENTER( BUS_DBG_PNP ); + + *p_action = IrpComplete; + + status = cl_alloc_relations( p_irp, 1 ); + if( !NT_SUCCESS( status ) ) + { + BUS_TRACE_EXIT( BUS_DBG_ERROR, + ("cl_alloc_relations returned 0x%08x.\n", status) ); + return status; + } + + p_rel = (DEVICE_RELATIONS*)p_irp->IoStatus.Information; + p_rel->Count = 1; + p_rel->Objects[0] = p_dev_obj; + + ObReferenceObject( p_dev_obj ); + + BUS_EXIT( BUS_DBG_PNP ); + return status; +} + + +static NTSTATUS +iou_query_device_id( + IN DEVICE_OBJECT* const p_dev_obj, + OUT IRP* const p_irp ) +{ + NTSTATUS status; + bus_iou_ext_t *p_ext; + WCHAR *p_string; + + BUS_ENTER( BUS_DBG_PNP ); + + p_ext = (bus_iou_ext_t*)p_dev_obj->DeviceExtension; + if( !p_ext->pdo.b_present ) + { + BUS_TRACE_EXIT( BUS_DBG_ERROR, ("Device not present.\n") ); + return STATUS_NO_SUCH_DEVICE; + } + + /* Device ID is "IBA\SID_ where is the IPoIB Service ID. */ + p_string = ExAllocatePoolWithTag( NonPagedPool, IOU_DEV_ID_SIZE, 'didq' ); + if( !p_string ) + { + BUS_TRACE_EXIT( BUS_DBG_ERROR, + ("Failed to allocate device ID buffer (%d bytes).\n", + IOU_DEV_ID_SIZE) ); + return STATUS_INSUFFICIENT_RESOURCES; + } + + status = + RtlStringCbPrintfW( p_string, IOU_DEV_ID_SIZE, IOU_DEV_ID_STRING1, + p_ext->vend_id, p_ext->dev_id, p_ext->revision ); + if( !NT_SUCCESS( status ) ) + { + ExFreePool( p_string ); + BUS_TRACE_EXIT( BUS_DBG_ERROR, + ("Failed to format device ID string.\n") ); + return status; + } + p_irp->IoStatus.Information = (ULONG_PTR)p_string; + + BUS_EXIT( BUS_DBG_PNP ); + return STATUS_SUCCESS; +} + + +static NTSTATUS +iou_query_hardware_ids( + IN DEVICE_OBJECT* const p_dev_obj, + OUT IRP* const p_irp ) +{ + NTSTATUS status; + bus_iou_ext_t *p_ext; + WCHAR *p_string, *p_start; + size_t size; + + BUS_ENTER( BUS_DBG_PNP ); + + p_ext = (bus_iou_ext_t*)p_dev_obj->DeviceExtension; + if( !p_ext->pdo.b_present ) + { + BUS_TRACE_EXIT( BUS_DBG_ERROR, ("Device not present.\n") ); + return STATUS_NO_SUCH_DEVICE; + } + + p_string = ExAllocatePoolWithTag( NonPagedPool, IOU_HW_ID_SIZE, 'dihq' ); + if( !p_string ) + { + BUS_TRACE_EXIT( BUS_DBG_ERROR, + ("Failed to allocate hardware ID buffer (%d bytes).\n", + IOU_HW_ID_SIZE) ); + return STATUS_INSUFFICIENT_RESOURCES; + } + + p_start = p_string; + size = IOU_HW_ID_SIZE; + /* Fill in the first HW ID. */ + status = RtlStringCbPrintfExW( p_start, size, &p_start, &size, + STRSAFE_FILL_BEHIND_NULL | STRSAFE_NO_TRUNCATION, IOU_DEV_ID_STRING1, + p_ext->vend_id, p_ext->dev_id, p_ext->revision ); + if( !NT_SUCCESS( status ) ) + { + ExFreePool( p_string ); + BUS_TRACE_EXIT( BUS_DBG_ERROR, + ("Failed to format device ID string.\n") ); + return status; + } + /* Fill in the second HW ID. */ + CL_ASSERT( *p_start == L'\0' ); + p_start++; + size -= sizeof(WCHAR); + status = RtlStringCbPrintfExW( p_start, size, NULL, NULL, + STRSAFE_FILL_BEHIND_NULL | STRSAFE_NO_TRUNCATION, IOU_DEV_ID_STRING2, + p_ext->vend_id, p_ext->dev_id ); + if( !NT_SUCCESS( status ) ) + { + ExFreePool( p_string ); + BUS_TRACE_EXIT( BUS_DBG_ERROR, + ("Failed to format device ID string.\n") ); + return status; + } + p_irp->IoStatus.Information = (ULONG_PTR)p_string; + + BUS_EXIT( BUS_DBG_PNP ); + return STATUS_SUCCESS; +} + + +static NTSTATUS +iou_query_compatible_ids( + IN DEVICE_OBJECT* const p_dev_obj, + OUT IRP* const p_irp ) +{ + WCHAR *p_string; + + BUS_ENTER( BUS_DBG_PNP ); + + UNUSED_PARAM( p_dev_obj ); + + p_string = ExAllocatePoolWithTag( NonPagedPool, sizeof(IOU_COMPAT_ID), 'dicq' ); + if( !p_string ) + { + BUS_TRACE_EXIT( BUS_DBG_ERROR, + ("Failed to allocate compatible ID buffer (%d bytes).\n", + IOU_HW_ID_SIZE) ); + return STATUS_INSUFFICIENT_RESOURCES; + } + + cl_memcpy( p_string, IOU_COMPAT_ID, sizeof(IOU_COMPAT_ID) ); + p_irp->IoStatus.Information = (ULONG_PTR)p_string; + + BUS_EXIT( BUS_DBG_PNP ); + return STATUS_SUCCESS; +} + + +static NTSTATUS +iou_query_unique_id( + IN DEVICE_OBJECT* const p_dev_obj, + OUT IRP* const p_irp ) +{ + NTSTATUS status; + WCHAR *p_string; + bus_iou_ext_t *p_ext; + + BUS_ENTER( BUS_DBG_PNP ); + + p_ext = p_dev_obj->DeviceExtension; + if( !p_ext->pdo.b_present ) + { + BUS_TRACE_EXIT( BUS_DBG_ERROR, ("Device not present.\n") ); + return STATUS_NO_SUCH_DEVICE; + } + + /* The instance ID is the port GUID. */ + p_string = ExAllocatePoolWithTag( NonPagedPool, sizeof(WCHAR) * 33, 'diuq' ); + if( !p_string ) + { + BUS_TRACE_EXIT( BUS_DBG_ERROR, + ("Failed to allocate instance ID buffer (%d bytes).\n", + sizeof(WCHAR) * 17) ); + return STATUS_NO_MEMORY; + } + + status = RtlStringCchPrintfW( p_string, 33, L"%016I64x%016I64x", + p_ext->guid, p_ext->pdo.ca_guid ); + if( !NT_SUCCESS( status ) ) + { + CL_ASSERT( NT_SUCCESS( status ) ); + ExFreePool( p_string ); + BUS_TRACE_EXIT( BUS_DBG_ERROR, + ("RtlStringCchPrintfW returned %08x.\n", status) ); + return status; + } + + p_irp->IoStatus.Information = (ULONG_PTR)p_string; + + BUS_EXIT( BUS_DBG_PNP ); + return STATUS_SUCCESS; +} + + +static NTSTATUS +iou_query_description( + IN DEVICE_OBJECT* const p_dev_obj, + OUT IRP* const p_irp ) +{ + NTSTATUS status; + WCHAR *p_string; + bus_iou_ext_t *p_ext; + + BUS_ENTER( BUS_DBG_PNP ); + + p_ext = p_dev_obj->DeviceExtension; + if( !p_ext->pdo.b_present ) + { + BUS_TRACE_EXIT( BUS_DBG_ERROR, ("Device not present.\n") ); + return STATUS_NO_SUCH_DEVICE; + } + + /* The instance ID is the port GUID. */ + p_string = ExAllocatePoolWithTag( NonPagedPool, + sizeof(WCHAR) * sizeof(p_ext->desc), + 'sedq' ); + if( !p_string ) + { + BUS_TRACE_EXIT( BUS_DBG_ERROR, + ("Failed to allocate device description buffer (%d bytes).\n", + sizeof(WCHAR) * sizeof(p_ext->desc)) ); + return STATUS_INSUFFICIENT_RESOURCES; + } + + status = RtlStringCchPrintfW( p_string, sizeof(p_ext->desc), + L"%S", p_ext->desc ); + if( !NT_SUCCESS( status ) ) + { + CL_ASSERT( NT_SUCCESS( status ) ); + ExFreePool( p_string ); + BUS_TRACE_EXIT( BUS_DBG_ERROR, + ("RtlStringCchPrintfW returned %08x.\n", status) ); + return status; + } + p_irp->IoStatus.Information = (ULONG_PTR)p_string; + + BUS_EXIT( BUS_DBG_PNP ); + return STATUS_SUCCESS; +} + + +static NTSTATUS +iou_query_location( + IN DEVICE_OBJECT* const p_dev_obj, + OUT IRP* const p_irp ) +{ + NTSTATUS status; + bus_iou_ext_t *p_ext; + WCHAR *p_string; + + BUS_ENTER( BUS_DBG_PNP ); + + p_ext = (bus_iou_ext_t*)p_dev_obj->DeviceExtension; + if( !p_ext->pdo.b_present ) + { + BUS_TRACE_EXIT( BUS_DBG_ERROR, ("Device not present.\n") ); + return STATUS_NO_SUCH_DEVICE; + } + + p_string = ExAllocatePoolWithTag( NonPagedPool, IOU_LOCATION_SIZE, 'colq' ); + if( !p_string ) + { + BUS_TRACE_EXIT( BUS_DBG_ERROR, + ("Failed to allocate location buffer (%d bytes).\n", + IOU_LOCATION_SIZE) ); + return STATUS_INSUFFICIENT_RESOURCES; + } + + status = RtlStringCbPrintfW( p_string, IOU_LOCATION_SIZE, + L"Chassis 0x%016I64x, Slot %d", p_ext->chassis_guid, p_ext->slot ); + if( !NT_SUCCESS( status ) ) + { + ExFreePool( p_string ); + BUS_TRACE_EXIT( BUS_DBG_ERROR, + ("Failed to format device ID string.\n") ); + return status; + } + p_irp->IoStatus.Information = (ULONG_PTR)p_string; + + BUS_EXIT( BUS_DBG_PNP ); + return STATUS_SUCCESS; +} + + +static NTSTATUS +iou_query_bus_info( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + PNP_BUS_INFORMATION *p_bus_info; + + BUS_ENTER( BUS_DBG_PNP ); + + UNUSED_PARAM( p_dev_obj ); + + *p_action = IrpComplete; + + p_bus_info = ExAllocatePoolWithTag( NonPagedPool, sizeof(PNP_BUS_INFORMATION), 'subq' ); + if( !p_bus_info ) + { + BUS_TRACE_EXIT( BUS_DBG_ERROR, + ("Failed to allocate PNP_BUS_INFORMATION (%d bytes).\n", + sizeof(PNP_BUS_INFORMATION)) ); + return STATUS_INSUFFICIENT_RESOURCES; + } + + p_bus_info->BusTypeGuid = GUID_BUS_TYPE_IBA; + //TODO: Memory from Intel - storage miniport would not stay loaded unless + //TODO: bus type was PCI. Look here if SRP is having problems staying + //TODO: loaded. + p_bus_info->LegacyBusType = PNPBus; + p_bus_info->BusNumber = 0; + + p_irp->IoStatus.Information = (ULONG_PTR)p_bus_info; + BUS_EXIT( BUS_DBG_PNP ); + return STATUS_SUCCESS; +} + + +static NTSTATUS +iou_query_iou_ifc( + IN DEVICE_OBJECT* const p_dev_obj, + IN IO_STACK_LOCATION* const p_io_stack ) +{ + NTSTATUS status; + ib_al_ifc_t *p_ifc; + ib_al_ifc_data_t *p_ifc_data; + iou_ifc_data_t *p_iou_data; + bus_iou_ext_t *p_ext; + const GUID *p_guid; + + BUS_ENTER( BUS_DBG_PNP ); + + CL_ASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL ); + + p_ext = p_dev_obj->DeviceExtension; + + /* Get the interface. */ + status = cl_fwd_query_ifc( + p_ext->pdo.p_parent_ext->cl_ext.p_self_do, p_io_stack ); + if( !NT_SUCCESS( status ) ) + { + BUS_TRACE_EXIT( BUS_DBG_ERROR, + ("Failed to forward interface query: %08X\n", status) ); + return status; + } + + if( !p_io_stack->Parameters.QueryInterface.InterfaceSpecificData ) + { + BUS_TRACE_EXIT( BUS_DBG_ERROR, ("No interface specific data!\n") ); + return status; + } + + p_ifc = (ib_al_ifc_t*)p_io_stack->Parameters.QueryInterface.Interface; + + p_ifc_data = (ib_al_ifc_data_t*) + p_io_stack->Parameters.QueryInterface.InterfaceSpecificData; + p_guid = p_ifc_data->type; + if( !IsEqualGUID( p_guid, &GUID_IOU_INTERFACE_DATA ) ) + { + BUS_TRACE_EXIT( BUS_DBG_PNP, ("Unsupported interface data: \n\t" + "0x%08x, 0x%04x, 0x%04x, 0x%02x, 0x%02x, 0x%02x," + "0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x.\n", + p_guid->Data1, p_guid->Data2, p_guid->Data3, + p_guid->Data4[0], p_guid->Data4[1], p_guid->Data4[2], + p_guid->Data4[3], p_guid->Data4[4], p_guid->Data4[5], + p_guid->Data4[6], p_guid->Data4[7]) ); + return status; + } + + if( p_ifc_data->version != IOU_INTERFACE_DATA_VERSION ) + { + p_ifc->wdm.InterfaceDereference( p_ifc->wdm.Context ); + BUS_TRACE_EXIT( BUS_DBG_ERROR, + ("Unsupported version %d, expected %d\n", + p_ifc_data->version, IOU_INTERFACE_DATA_VERSION) ); + return STATUS_NOT_SUPPORTED; + } + + ASSERT( p_ifc_data->p_data ); + + if( p_ifc_data->size != sizeof(iou_ifc_data_t) ) + { + p_ifc->wdm.InterfaceDereference( p_ifc->wdm.Context ); + BUS_TRACE_EXIT( BUS_DBG_PNP, + ("Buffer too small (%d given, %d required).\n", + p_ifc_data->size, + sizeof(iou_ifc_data_t)) ); + return STATUS_BUFFER_TOO_SMALL; + } + + /* Set the interface data. */ + p_iou_data = (iou_ifc_data_t*)p_ifc_data->p_data; + + p_iou_data->ca_guid = p_ext->pdo.ca_guid; + p_iou_data->chassis_guid = p_ext->chassis_guid; + p_iou_data->slot = p_ext->slot; + p_iou_data->guid = p_ext->guid; + + BUS_EXIT( BUS_DBG_PNP ); + return STATUS_SUCCESS; +} + + +static NTSTATUS +iou_query_interface( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + bus_pdo_ext_t *p_ext; + NTSTATUS status; + IO_STACK_LOCATION *p_io_stack; + + BUS_ENTER( BUS_DBG_PNP ); + + CL_ASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL ); + + p_io_stack = IoGetCurrentIrpStackLocation( p_irp ); + + /* Bottom of the stack - IRP must be completed. */ + *p_action = IrpComplete; + + /* Compare requested GUID with our supported interface GUIDs. */ + if( IsEqualGUID( p_io_stack->Parameters.QueryInterface.InterfaceType, + &GUID_IB_AL_INTERFACE ) ) + { + status = iou_query_iou_ifc( p_dev_obj, p_io_stack ); + } + else if( IsEqualGUID( p_io_stack->Parameters.QueryInterface.InterfaceType, + &GUID_BUS_INTERFACE_STANDARD ) ) + { + p_ext = p_dev_obj->DeviceExtension; + if( !p_ext->h_ca || + !p_ext->b_present || + !p_ext->h_ca->p_hca_dev || + p_ext->b_reported_missing ) + { + return STATUS_NO_SUCH_DEVICE; + } + + + status = cl_fwd_query_ifc( + p_ext->h_ca->p_hca_dev, p_io_stack ); + } + else + { + status = p_irp->IoStatus.Status; + } + + BUS_EXIT( BUS_DBG_PNP ); + return status; +} + + + +/* Work item callback to handle DevicePowerD3 IRPs at passive level. */ +static void +__HibernateUpWorkItem( + IN DEVICE_OBJECT* p_dev_obj, + IN void* context ) +{ + IO_STACK_LOCATION *p_io_stack; + bus_pdo_ext_t *p_ext; + IRP *p_irp; + POWER_STATE powerState; + + BUS_ENTER( BUS_DBG_POWER ); + + p_ext = (bus_pdo_ext_t*)p_dev_obj->DeviceExtension; + p_irp = (IRP*)context; + p_io_stack = IoGetCurrentIrpStackLocation( p_irp ); + + IoFreeWorkItem( p_ext->p_po_work_item ); + p_ext->p_po_work_item = NULL; + + while (!p_ext->h_ca) { + BUS_TRACE( BUS_DBG_PNP, ("Waiting for the end of HCA registration ... \n")); + cl_thread_suspend( 200 ); /* suspend for 200 ms */ + } + + p_ext->dev_po_state = p_io_stack->Parameters.Power.State; + powerState = PoSetPowerState( p_dev_obj, DevicePowerState, p_ext->dev_po_state ); + + BUS_TRACE( BUS_DBG_POWER, + ("PoSetPowerState: old state %d, new state to %d\n", + powerState.DeviceState, p_ext->dev_po_state )); + + p_irp->IoStatus.Status = STATUS_SUCCESS; + PoStartNextPowerIrp( p_irp ); + IoCompleteRequest( p_irp, IO_NO_INCREMENT ); + IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp ); + + BUS_EXIT( BUS_DBG_POWER ); +} + +/* + * The PDOs created by the IB Bus driver are software devices. As such, + * all power states are supported. It is left to the HCA power policy + * owner to handle which states can be supported by the HCA. + */ +static NTSTATUS +iou_set_power( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + NTSTATUS status = STATUS_SUCCESS; + IO_STACK_LOCATION *p_io_stack; + bus_pdo_ext_t *p_ext; + + BUS_ENTER( BUS_DBG_POWER ); + + p_ext = p_dev_obj->DeviceExtension; + p_io_stack = IoGetCurrentIrpStackLocation( p_irp ); + + BUS_TRACE( BUS_DBG_POWER, + ("SET_POWER for PDO %p (ext %p): type %s, state %d, action %d \n", + p_dev_obj, p_ext, + (p_io_stack->Parameters.Power.Type) ? "DevicePowerState" : "SystemPowerState", + p_io_stack->Parameters.Power.State.DeviceState, + p_io_stack->Parameters.Power.ShutdownType )); + + if ((p_io_stack->Parameters.Power.Type == SystemPowerState) && + (p_io_stack->Parameters.Power.State.SystemState ==PowerSystemHibernate || + p_io_stack->Parameters.Power.State.SystemState ==PowerSystemSleeping1 || + p_io_stack->Parameters.Power.State.SystemState ==PowerSystemSleeping2 || + p_io_stack->Parameters.Power.State.SystemState ==PowerSystemSleeping3 )) + { + BUS_TRACE( BUS_DBG_POWER, ("Setting b_hibernating flag for PDO %p \n", p_dev_obj)); + p_ext->b_hibernating = TRUE; + } + + if( p_io_stack->Parameters.Power.Type == DevicePowerState ) + { + /* after hibernation PDO is not ready for work. we need to wait for finishing of the HCA registration */ + if( p_io_stack->Parameters.Power.State.DeviceState == PowerDeviceD0 && p_ext->b_hibernating) + { + /* Process in a work item - deregister_ca and HcaDeinit block. */ + ASSERT( !p_ext->p_po_work_item ); + p_ext->p_po_work_item = IoAllocateWorkItem( p_dev_obj ); + if( !p_ext->p_po_work_item ) + status = STATUS_INSUFFICIENT_RESOURCES; + else { + /* Process in work item callback. */ + IoMarkIrpPending( p_irp ); + IoQueueWorkItem( + p_ext->p_po_work_item, __HibernateUpWorkItem, DelayedWorkQueue, p_irp ); + *p_action = IrpDoNothing; + BUS_EXIT( BUS_DBG_POWER ); + return STATUS_PENDING; + } + } + + /* Notify the power manager. */ + p_ext->dev_po_state = p_io_stack->Parameters.Power.State; + PoSetPowerState( p_dev_obj, DevicePowerState, p_ext->dev_po_state ); + } + + *p_action = IrpComplete; + BUS_EXIT( BUS_DBG_POWER ); + return STATUS_SUCCESS; +} diff --git a/branches/WOF2-3/core/bus/kernel/bus_iou_mgr.h b/branches/WOF2-3/core/bus/kernel/bus_iou_mgr.h new file mode 100644 index 00000000..debca84a --- /dev/null +++ b/branches/WOF2-3/core/bus/kernel/bus_iou_mgr.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#if !defined( __BUS_IOU_MGR_H__ ) +#define __BUS_IOU_MGR_H__ + +#include +#include +#include + + +/* Global load service */ +typedef struct _iou_mgr +{ + cl_obj_t obj; + + /* Mutex protects both pointer vectors. */ + cl_mutex_t pdo_mutex; + + /* Pointer vector of child IOU PDOs. */ + cl_qlist_t iou_list; + +} iou_mgr_t; + + +struct _bus_filter_instance; + +ib_api_status_t +create_iou_mgr( + IN struct _bus_filter_instance* p_bfi ); + +NTSTATUS +iou_mgr_get_bus_relations( + IN const net64_t ca_guid, + IN IRP* const p_irp ); + +#endif diff --git a/branches/WOF2-3/core/bus/kernel/bus_pnp.c b/branches/WOF2-3/core/bus/kernel/bus_pnp.c new file mode 100644 index 00000000..87647fca --- /dev/null +++ b/branches/WOF2-3/core/bus/kernel/bus_pnp.c @@ -0,0 +1,1868 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2006 Mellanox Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + +/* + * Implemenation of all PnP functionality for FDO (power policy owners). + */ + +#include "bus_pnp.h" +#include "al_ca.h" +#include "al_init.h" +#include "al_dev.h" +#include "al_debug.h" +#include "bus_port_mgr.h" +#include "bus_iou_mgr.h" +#include "complib/cl_memory.h" +#include +#include "iba/ib_ci_ifc.h" +#include "iba/ib_cm_ifc.h" +#include "al_cm_cep.h" +#include "al_mgr.h" +#include "bus_ev_log.h" + + +/* Interface names are generated by IoRegisterDeviceInterface. */ +static UNICODE_STRING al_ifc_name; +static UNICODE_STRING ci_ifc_name; +static UNICODE_STRING cm_ifc_name; + +KEVENT g_ControlEvent; +ULONG g_bfi_InstanceCount; +bus_filter_t g_bus_filters[MAX_BUS_FILTERS]; + +extern PDEVICE_OBJECT g_ControlDeviceObject; +extern UNICODE_STRING g_CDO_dev_name, g_CDO_dos_name; + + +static NTSTATUS +fdo_start( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static void +fdo_release_resources( + IN DEVICE_OBJECT* const p_dev_obj ); + +static NTSTATUS +fdo_query_remove( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +fdo_query_capabilities( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +fdo_query_bus_relations( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +__query_al_ifc( + IN DEVICE_OBJECT* const p_dev_obj, + IN IO_STACK_LOCATION* const p_io_stack ); + +static NTSTATUS +__get_relations( + IN const net64_t ca_guid, + IN IRP* const p_irp ); + +static NTSTATUS +__query_ci_ifc( + IN DEVICE_OBJECT* const p_dev_obj, + IN IO_STACK_LOCATION* const p_io_stack ); + +static NTSTATUS +__query_cm_ifc( + IN DEVICE_OBJECT* const p_dev_obj, + IN IO_STACK_LOCATION* const p_io_stack ); + +static NTSTATUS +fdo_query_pnp_state( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + + +static NTSTATUS +fdo_query_interface( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +__fdo_query_power( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +__fdo_set_power( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static void +__set_ifc( + OUT ib_al_ifc_t* const p_ifc ); + + + + +/* Global virtual function pointer tables shared between all instances of FDO. */ +static const cl_vfptr_pnp_po_t vfptr_fdo_pnp = { + "IB Bus", + fdo_start, + cl_irp_skip, + cl_irp_skip, + cl_do_sync_pnp, + fdo_query_remove, + fdo_release_resources, + cl_do_remove, + cl_do_sync_pnp, + cl_irp_skip, + fdo_query_capabilities, + fdo_query_pnp_state, + cl_irp_skip, + cl_do_sync_pnp, + fdo_query_bus_relations, + cl_irp_ignore, + cl_irp_skip, + cl_irp_ignore, + cl_irp_ignore, + cl_irp_ignore, + cl_irp_ignore, + cl_irp_ignore, + fdo_query_interface, /* QueryInterface */ + cl_irp_ignore, + cl_irp_ignore, + cl_irp_ignore, + cl_irp_ignore, + __fdo_query_power, /* QueryPower */ + __fdo_set_power, /* SetPower */ + cl_irp_ignore, /* PowerSequence */ + cl_irp_ignore /* WaitWake */ +}; + + +NTSTATUS +bus_add_device( + IN DRIVER_OBJECT *p_driver_obj, + IN DEVICE_OBJECT *p_pdo ) +{ + NTSTATUS status; + DEVICE_OBJECT *p_dev_obj, *p_next_do; + bus_fdo_ext_t *p_ext=NULL; + bus_filter_t *p_bfi; + int ic; + + BUS_ENTER( BUS_DBG_PNP ); + + /* allocate a Bus Filter Instance */ + p_bfi = alloc_bfi( p_driver_obj, &ic ); + if ( !p_bfi ) + { + BUS_TRACE_EXIT( BUS_DBG_PNP, + ("%s() Err - Exceeded MAX_BUS_FILTERS(%d)\n",MAX_BUS_FILTERS)); + return STATUS_UNSUCCESSFUL; + } + + /* if 1st Bus Filter Instance, then create device names for user ioctl */ + if ( ic == 1 && !g_ControlDeviceObject) + { + RtlInitUnicodeString( &g_CDO_dev_name, AL_DEVICE_NAME ); + RtlInitUnicodeString( &g_CDO_dos_name, L"\\DosDevices\\Global\\ibal" ); + + status = IoCreateDevice( p_driver_obj, sizeof(bus_fdo_ext_t), + &g_CDO_dev_name, FILE_DEVICE_BUS_EXTENDER, + FILE_DEVICE_SECURE_OPEN, FALSE, &g_ControlDeviceObject ); + if( !NT_SUCCESS(status) ) + { + g_ControlDeviceObject = NULL; + BUS_PRINT( BUS_DBG_ERROR, + ("Failed to create ControlDeviceObject, status %x.\n",status) ); + goto err1; + } + else { + p_ext = g_ControlDeviceObject->DeviceExtension; + RtlZeroMemory(p_ext, sizeof *p_ext); + cl_init_pnp_po_ext( g_ControlDeviceObject, NULL, + NULL, bus_globals.dbg_lvl, NULL, NULL ); + + /* enable user-mode access to IB stack */ + BUS_PRINT( BUS_DBG_PNP, ("Remove-n-reCreate dos_name symlink\n") ); + IoDeleteSymbolicLink( &g_CDO_dos_name ); + status = IoCreateSymbolicLink( &g_CDO_dos_name, &g_CDO_dev_name ); + if( !NT_SUCCESS(status) ) + { + BUS_PRINT( BUS_DBG_ERROR, + ("Failed to create symlink for dos name.\n") ); + IoDeleteDevice( g_ControlDeviceObject ); + g_ControlDeviceObject = NULL; + goto err1; + } + BUS_TRACE( BUS_DBG_PNP, ("Created dos_name symlink\n") ); + } + } + + /* Create the FDO device object to attach to the stack. */ + status = IoCreateDevice( p_driver_obj, sizeof(bus_fdo_ext_t), + NULL, FILE_DEVICE_BUS_EXTENDER, + FILE_DEVICE_SECURE_OPEN, FALSE, &p_dev_obj ); + if( !NT_SUCCESS(status) ) + { + BUS_PRINT( BUS_DBG_ERROR, + ("Failed to create bus root FDO device.\n") ); + goto err1; + } + + p_ext = p_dev_obj->DeviceExtension; + cl_memclr( p_ext, sizeof(bus_fdo_ext_t) ); + + p_next_do = IoAttachDeviceToDeviceStack( p_dev_obj, p_pdo ); + if( !p_next_do ) + { + BUS_PRINT( BUS_DBG_ERROR, ("IoAttachToDeviceStack failed.\n") ); + status = STATUS_NO_SUCH_DEVICE; + goto err2; + } + + cl_init_pnp_po_ext( p_dev_obj, p_next_do, p_pdo, bus_globals.dbg_lvl, + &vfptr_fdo_pnp, NULL ); + + p_bfi->p_bus_ext = p_ext; + p_ext->bus_filter = p_bfi; + + /* + * if not 1st Bus Filter Instance, then finished... + */ + if ( ic > 1 ) + goto adxit; + + /* Register the upper interface (the one used by clients). */ + status = IoRegisterDeviceInterface( p_pdo, &GUID_IB_AL_INTERFACE, NULL, + &al_ifc_name ); + if( !NT_SUCCESS( status ) ) + { + BUS_PRINT( BUS_DBG_ERROR, + ("IoRegisterDeviceInterface for upper interface returned %08x\n", + status) ); + status = STATUS_NO_SUCH_DEVICE; + goto err3; + } + + /* Register the lower (CI) interface (the one used by HCA VPDs). */ + status = IoRegisterDeviceInterface( p_pdo, &GUID_IB_CI_INTERFACE, NULL, + &ci_ifc_name ); + if( !NT_SUCCESS( status ) ) + { + BUS_PRINT( BUS_DBG_ERROR, + ("IoRegisterDeviceInterface for lower interface returned %08x\n", + status) ); + status = STATUS_NO_SUCH_DEVICE; + goto err3; + } + + status = IoRegisterDeviceInterface( p_pdo, &GUID_INFINIBAND_INTERFACE_CM, NULL, + &cm_ifc_name ); + if( !NT_SUCCESS( status ) ) + { + BUS_PRINT( BUS_DBG_ERROR, + ("IoRegisterDeviceInterface for cm interface returned %08x\n", + status) ); + status = STATUS_NO_SUCH_DEVICE; + goto err3; + } + +adxit: + BUS_PRINT( BUS_DBG_PNP, ("%s exit status 0\n", p_bfi->whoami) ); + + BUS_EXIT( BUS_DBG_PNP ); + return STATUS_SUCCESS; + +err3: + IoDetachDevice( p_ext->cl_ext.p_next_do ); +err2: + IoDeleteDevice( p_dev_obj ); +err1: + BUS_PRINT( BUS_DBG_PNP, ("%s exit status 0x%x\n", p_bfi->whoami,status) ); + ic = free_bfi(p_bfi); + BUS_EXIT( BUS_DBG_PNP ); + return status; +} + + +/* Forwards the request to the HCA's FDO. */ +static NTSTATUS +__get_ifc( + IN DEVICE_OBJECT* const pDevObj, + IN const GUID* const pGuid, + IN USHORT size, + IN USHORT Version, + IN OUT PVOID InterfaceSpecificData, + OUT PINTERFACE pHcaIfc ) +{ + NTSTATUS status; + IRP *pIrp; + IO_STATUS_BLOCK ioStatus; + IO_STACK_LOCATION *pIoStack; + DEVICE_OBJECT *pDev; + KEVENT event; + + BUS_ENTER( BUS_DBG_PNP ); + + CL_ASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL ); + + pDev = IoGetAttachedDeviceReference( pDevObj ); + + KeInitializeEvent( &event, NotificationEvent, FALSE ); + + /* Build the IRP for the HCA. */ + pIrp = IoBuildSynchronousFsdRequest( IRP_MJ_PNP, pDev, + NULL, 0, NULL, &event, &ioStatus ); + if( !pIrp ) + { + ObDereferenceObject( pDev ); + BUS_PRINT( BUS_DBG_PNP, + ("IoBuildSynchronousFsdRequest failed.\n")); + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* Copy the request query parameters. */ + pIoStack = IoGetNextIrpStackLocation( pIrp ); + pIoStack->MinorFunction = IRP_MN_QUERY_INTERFACE; + pIoStack->Parameters.QueryInterface.Size = size; + pIoStack->Parameters.QueryInterface.Version = Version; + pIoStack->Parameters.QueryInterface.InterfaceType = pGuid; + pIoStack->Parameters.QueryInterface.Interface = (INTERFACE*)pHcaIfc; + pIoStack->Parameters.QueryInterface.InterfaceSpecificData = InterfaceSpecificData; + + pIrp->IoStatus.Status = STATUS_NOT_SUPPORTED; + + /* Send the IRP. */ + status = IoCallDriver( pDev, pIrp ); + if( status == STATUS_PENDING ) + { + KeWaitForSingleObject( &event, Executive, KernelMode, + FALSE, NULL ); + + status = ioStatus.Status; + } + ObDereferenceObject( pDev ); + + BUS_EXIT( BUS_DBG_PNP ); + return status; +} + + +static NTSTATUS +__register_ca( + IN DEVICE_OBJECT* const p_dev_obj + ) +{ + NTSTATUS status; + bus_fdo_ext_t *p_ext; + ib_api_status_t ib_status; + bus_filter_t *p_bfi; + + BUS_ENTER( BUS_DBG_PNP ); + + p_ext = p_dev_obj->DeviceExtension; + p_bfi = p_ext->bus_filter; + + /* get HCA verbs interface */ + status = __get_ifc( p_dev_obj, &GUID_RDMA_INTERFACE_VERBS, + sizeof(RDMA_INTERFACE_VERBS), + VerbsVersion(VERBS_MAJOR_VER, VERBS_MINOR_VER), + p_ext, (PINTERFACE)&p_ext->hca_ifc ); + if( !NT_SUCCESS( status ) ) + { + BUS_TRACE_EXIT(BUS_DBG_PNP, + ("Getting MLX4 BUS interface failed: status=0x%x\n", status)); + return STATUS_UNSUCCESSFUL; + } + p_ext->hca_ifc_taken = TRUE; + + /* bind BFI to HCA by CA GUID. Have to be before ib_register_ca */ + p_bfi->ca_guid = p_ext->hca_ifc.Verbs.guid; + + /* register HCA */ + ib_status = ib_register_ca( &p_ext->hca_ifc.Verbs, p_ext->cl_ext.p_pdo, p_dev_obj ); + if( ib_status != IB_SUCCESS ) + { + BUS_TRACE_EXIT( BUS_DBG_ERROR, ("ib_register_ca returned %s.\n", + ib_get_err_str(ib_status)) ); + p_ext->hca_ifc.InterfaceHeader.InterfaceDereference( + p_ext->hca_ifc.InterfaceHeader.Context); + p_ext->hca_ifc_taken = FALSE; + + return STATUS_UNSUCCESSFUL; + } + BUS_TRACE_EXIT(BUS_DBG_PNP, ("%s bound to CA guid %I64x\n", + p_bfi->whoami,p_bfi->ca_guid)); + + p_ext->ca_registered = TRUE; + return status; +} + +static NTSTATUS +fdo_start( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + NTSTATUS status; + bus_fdo_ext_t *p_ext; + ib_api_status_t ib_status; + bus_filter_t *p_bfi; + boolean_t AL_init_here = FALSE; + + BUS_ENTER( BUS_DBG_PNP ); + + p_ext = p_dev_obj->DeviceExtension; + p_bfi = p_ext->bus_filter; + ASSERT( !p_ext->ca_registered ); + + /* Handled on the way up. */ + status = cl_do_sync_pnp( p_dev_obj, p_irp, p_action ); + if( !NT_SUCCESS( status ) ) + { + BUS_TRACE_EXIT( BUS_DBG_ERROR, + ("Lower drivers failed IRP_MN_START_DEVICE.\n") ); + return status; + } + p_ext->device_power_state = PowerDeviceD0; + + p_ext->p_stat = bus_st_dev_add(); + if ( p_ext->p_stat ) + p_ext->p_stat->p_fdo = p_ext; + + + lock_control_event(); + if ( !gp_async_proc_mgr ) { + /* Initialize AL */ + ib_status = al_initialize(); + if( ib_status != IB_SUCCESS ) + { + al_cleanup(); + BUS_TRACE_EXIT( BUS_DBG_ERROR, ("al_initialize returned %s.\n", + ib_get_err_str(ib_status)) ); + unlock_control_event(); + return STATUS_UNSUCCESSFUL; + } + AL_init_here = TRUE; + BUS_TRACE( BUS_DBG_PNP, ("AL initialized\n")); + /* for debug */ + g_stat.drv.gp_async_obj_mgr = gp_async_obj_mgr; + g_stat.drv.gp_async_proc_mgr = gp_async_proc_mgr; + g_stat.drv.gp_async_pnp_mgr = gp_async_pnp_mgr; + g_stat.drv.gp_al_mgr = gp_al_mgr; + g_stat.drv.gp_obj_mgr = gp_obj_mgr; + } + unlock_control_event(); + + /* Initialize the port manager. */ + ib_status = create_port_mgr( p_ext->bus_filter ); + if( ib_status != IB_SUCCESS ) + { + BUS_TRACE_EXIT( BUS_DBG_ERROR, ("create_port_mgr returned %s.\n", + ib_get_err_str(ib_status)) ); + return STATUS_UNSUCCESSFUL; + } + + /* Initialize the IOU manager. */ + ib_status = create_iou_mgr( p_ext->bus_filter ); + if( ib_status != IB_SUCCESS ) + { + BUS_TRACE_EXIT( BUS_DBG_ERROR, ("create_iou_mgr returned %s.\n", + ib_get_err_str(ib_status)) ); + return STATUS_UNSUCCESSFUL; + } + + /* start IBAL */ + status = __register_ca( p_dev_obj ); + if( !NT_SUCCESS( status ) ) + return status; + + if ( AL_init_here ) { + status = IoSetDeviceInterfaceState( &al_ifc_name, TRUE ); + ASSERT( NT_SUCCESS( status ) ); + + status = IoSetDeviceInterfaceState( &ci_ifc_name, TRUE ); + ASSERT( NT_SUCCESS( status ) ); + + status = IoSetDeviceInterfaceState( &cm_ifc_name, TRUE ); + ASSERT( NT_SUCCESS( status ) ); + } + + BUS_TRACE( BUS_DBG_DRV, + ("IBBUS started \n") ); + CL_PRINT_TO_EVENT_LOG( p_dev_obj, EVENT_IBBUS_ANY_INFO, + ("IBBUS started \n" )); + + return status; +} + + +static NTSTATUS +fdo_query_remove( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + bus_fdo_ext_t *p_ext; + + BUS_ENTER( BUS_DBG_PNP ); + + p_ext = p_dev_obj->DeviceExtension; + + CL_ASSERT(p_ext->bus_filter); + BUS_PRINT( BUS_DBG_PNP, + ("IRP_MN_QUERY_REMOVE_DEVICE %s @ FDO %p refs(CI %d AL %d)\n" + " %s CA %I64x\n", + p_ext->cl_ext.vfptr_pnp_po->identity, p_ext, p_ext->n_ci_ifc_ref, + p_ext->n_al_ifc_ref, + p_ext->bus_filter->whoami, p_ext->bus_filter->ca_guid) ); + + if( p_ext->n_ci_ifc_ref ) + { + /* + * Our interface is still being held by someone. + * Rollback the PnP state that was changed in the cl_ext handler. + */ + cl_rollback_pnp_state( &p_ext->cl_ext ); + + /* Fail the query. */ + *p_action = IrpComplete; + BUS_TRACE_EXIT( BUS_DBG_PNP, + ("Failing IRP_MN_QUERY_REMOVE_DEVICE:\n" + "\tLowerInterface has %d references\n", + p_ext->n_ci_ifc_ref ) ); + return STATUS_UNSUCCESSFUL; + } + + /* remove port & iou managers */ + CL_ASSERT( p_ext->bus_filter ); + + //TODO: Fail outstanding I/O operations. + + *p_action = IrpSkip; + /* The FDO driver must set the status even when passing down. */ + p_irp->IoStatus.Status = STATUS_SUCCESS; + + BUS_EXIT( BUS_DBG_PNP ); + return STATUS_SUCCESS; +} + + +static void +__deregister_ca( + IN DEVICE_OBJECT* const p_dev_obj ) +{ + bus_fdo_ext_t *p_ext; + bus_filter_t *p_bfi; + ib_api_status_t ib_status; + + BUS_ENTER( BUS_DBG_PNP ); + + p_ext = p_dev_obj->DeviceExtension; + p_bfi = p_ext->bus_filter; + + if ( !p_ext->ca_registered ) + return; + p_ext->ca_registered = FALSE; + + //TODO: Fail outstanding I/O operations. + + ib_status = ib_deregister_ca( p_ext->hca_ifc.Verbs.guid ); + if( ib_status != IB_SUCCESS ) { + BUS_PRINT( BUS_DBG_ERROR, ("ib_deregister_ca returned %s.\n", + ib_get_err_str(ib_status)) ); + } + + if ( p_ext->hca_ifc_taken ) { + p_ext->hca_ifc.InterfaceHeader.InterfaceDereference( + p_ext->hca_ifc.InterfaceHeader.Context); + p_ext->hca_ifc_taken = FALSE; + } + + BUS_EXIT( BUS_DBG_PNP ); +} + +/* + * This function gets called after releasing the remove lock and waiting + * for all other threads to release the lock. No more modifications will + * occur to the PDO pointer vectors. + */ +static void +fdo_release_resources( + IN DEVICE_OBJECT* const p_dev_obj ) +{ + bus_fdo_ext_t *p_ext; + NTSTATUS status; + bus_filter_t *p_bfi; + int ic; + PBUS_ST_DEVICE p_stat; + + BUS_ENTER( BUS_DBG_PNP ); + + p_ext = p_dev_obj->DeviceExtension; + ic = get_bfi_count(); + p_stat = p_ext->p_stat; + + p_bfi = p_ext->bus_filter; + CL_ASSERT( p_bfi ); + + __deregister_ca( p_dev_obj ); + + if ( p_bfi->p_port_mgr ) + cl_obj_destroy( p_bfi->p_port_mgr_obj ); + + if ( p_bfi->p_iou_mgr ) + cl_obj_destroy( p_bfi->p_iou_mgr_obj ); + +#if 0 + // IBAL has no right to work with CA after it deregister. + // So there is no need to release interface only after IBAL cleanup + + /* if not last HCA then release IFC reference, otherwise release IFC after + * IBAL has shutdown; keep the HCA present until IBAL is terminated. + */ + if ( ic > 1 && p_ext->hca_ifc_taken ) { + p_ext->hca_ifc.InterfaceHeader.InterfaceDereference( + p_ext->hca_ifc.InterfaceHeader.Context); + p_ext->hca_ifc_taken = FALSE; + } +#endif + + BUS_TRACE( BUS_DBG_PNP, ("Releasing BusFilter %s\n", p_bfi->whoami )); + if (p_bfi) { + p_ext->bus_filter = NULL; + p_bfi->p_bus_ext = NULL; + } + + ic = free_bfi( p_bfi ); + + /* if not last Buf Filter Instance, then exit, otherwise cleanup/shutdown */ + if ( ic > 0 ) { + BUS_TRACE_EXIT( BUS_DBG_PNP, ("%d remaining BusFilters\n", ic )); + bus_st_dev_rmv( p_stat ); + return; + } + + if (g_ControlDeviceObject) + { + IoDeleteSymbolicLink( &g_CDO_dos_name ); + IoDeleteDevice(g_ControlDeviceObject); + g_ControlDeviceObject = NULL; + } + + /* Disable any exported interfaces. */ + status = IoSetDeviceInterfaceState( &al_ifc_name, FALSE ); + ASSERT( NT_SUCCESS( status ) ); + status = IoSetDeviceInterfaceState( &ci_ifc_name, FALSE ); + ASSERT( NT_SUCCESS( status ) ); + status = IoSetDeviceInterfaceState( &cm_ifc_name, FALSE ); + ASSERT( NT_SUCCESS( status ) ); + + /* Release the memory allocated for the interface symbolic names. */ + RtlFreeUnicodeString( &cm_ifc_name ); + RtlFreeUnicodeString( &ci_ifc_name ); + RtlFreeUnicodeString( &al_ifc_name ); + + al_cleanup(); + cl_thread_suspend(50); /* allow time for AL's async procs to run to exit */ + + CL_ASSERT( !gp_async_proc_mgr && !gp_async_pnp_mgr && !gp_al_mgr ); + +#if 0 + // IBAL has no right to work with CA after it deregister. + // So there is no need to release interface only after IBAL cleanup + + /* AL needs the HCA to stick around until AL cleanup has completed. + * Now that it's done, let the HCA fade away. + */ + if ( p_ext->hca_ifc_taken ) { + p_ext->hca_ifc.InterfaceHeader.InterfaceDereference( + p_ext->hca_ifc.InterfaceHeader.Context); + p_ext->hca_ifc_taken = FALSE; + } +#endif + + bus_st_dev_rmv( p_stat ); + + BUS_TRACE_EXIT( BUS_DBG_PNP, + ("=====> IBBUS: fdo_release_resources exited \n") ); +} + + +static NTSTATUS +fdo_query_capabilities( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + NTSTATUS status; + bus_fdo_ext_t *p_ext; + IO_STACK_LOCATION *p_io_stack; + + BUS_ENTER( BUS_DBG_PNP ); + + p_ext = p_dev_obj->DeviceExtension; + + /* Process on the way up. */ + status = cl_do_sync_pnp( p_dev_obj, p_irp, p_action ); + + if( !NT_SUCCESS( status ) ) + { + BUS_TRACE_EXIT( BUS_DBG_ERROR, + ("cl_do_sync_pnp returned %08x.\n", status) ); + return status; + } + + p_io_stack = IoGetCurrentIrpStackLocation( p_irp ); + + /* + * Store the device power maping into our extension since we're + * the power policy owner. The mapping is used when handling + * IRP_MN_SET_POWER IRPs. + */ + cl_memcpy( p_ext->po_state, + p_io_stack->Parameters.DeviceCapabilities.Capabilities->DeviceState, + sizeof( p_ext->po_state ) ); + + BUS_EXIT( BUS_DBG_PNP ); + return status; +} + + +static NTSTATUS +fdo_query_bus_relations( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + NTSTATUS status = STATUS_SUCCESS; /*default to success*/ + bus_fdo_ext_t *p_ext; + bus_filter_t *p_bfi; + int waitLoop = 0; + + BUS_ENTER( BUS_DBG_PNP ); + + p_ext = p_dev_obj->DeviceExtension; + + if ( !p_ext->bus_filter ) + { + /* BFI has already been released */ + *p_action = IrpComplete; + BUS_TRACE_EXIT( BUS_DBG_PNP, ("NULL BFI\n") ); + return STATUS_SUCCESS; + } + + p_bfi = p_ext->bus_filter; + CL_ASSERT( p_bfi->magic == BFI_MAGIC ); + + while ( p_bfi->ca_guid == 0ULL ) + { + /* HCA not yet bound to a BFI slot (no PNP ADD event seen), no bus + * relations yet. + */ + BUS_PRINT(BUS_DBG_ERROR, ("%s ca_guid %I64x\n",p_bfi->whoami, + p_bfi->ca_guid)); + cl_thread_suspend( 100 ); /* suspend for 100 ms */ + waitLoop++; + if(waitLoop>50) break; + } + if ( p_bfi->ca_guid != 0ULL ) + { + status = port_mgr_get_bus_relations( p_bfi->ca_guid, p_irp ); + if( status == STATUS_SUCCESS || + status == STATUS_NO_SUCH_DEVICE ) + { + status = iou_mgr_get_bus_relations( p_bfi->ca_guid, p_irp ); + } + if( status == STATUS_NO_SUCH_DEVICE ) + status = STATUS_SUCCESS; + } + + switch( status ) + { + case STATUS_NO_SUCH_DEVICE: + *p_action = IrpSkip; + status = STATUS_SUCCESS; + break; + + case STATUS_SUCCESS: + *p_action = IrpPassDown; + break; + + default: + *p_action = IrpComplete; + break; + } + + BUS_EXIT( BUS_DBG_PNP ); + return status; +} + + +void +al_ref_ifc( + IN DEVICE_OBJECT* p_dev_obj ) +{ + bus_fdo_ext_t *p_ext; + + BUS_ENTER( BUS_DBG_PNP ); + + p_ext = p_dev_obj->DeviceExtension; + + CL_ASSERT( p_ext->n_al_ifc_ref >= 0 ); + + cl_atomic_inc( &p_ext->n_al_ifc_ref ); + ObReferenceObject( p_dev_obj ); + + BUS_EXIT( BUS_DBG_PNP ); +} + + +void +al_deref_ifc( + IN DEVICE_OBJECT* p_dev_obj ) +{ + bus_fdo_ext_t *p_ext; + + BUS_ENTER( BUS_DBG_PNP ); + + p_ext = p_dev_obj->DeviceExtension; + + CL_ASSERT( p_ext->n_al_ifc_ref > 0 ); + cl_atomic_dec( &p_ext->n_al_ifc_ref ); + ObDereferenceObject( p_dev_obj ); + + BUS_EXIT( BUS_DBG_PNP ); +} + + +void +al_ref_ci_ifc( + IN DEVICE_OBJECT* p_dev_obj ) +{ + bus_fdo_ext_t *p_ext; + + BUS_ENTER( BUS_DBG_PNP ); + + p_ext = p_dev_obj->DeviceExtension; + + CL_ASSERT( p_ext->n_ci_ifc_ref >= 0 ); + cl_atomic_inc( &p_ext->n_ci_ifc_ref ); + ObReferenceObject( p_dev_obj ); + + BUS_EXIT( BUS_DBG_PNP ); +} + + +void +al_deref_ci_ifc( + IN DEVICE_OBJECT* p_dev_obj ) +{ + bus_fdo_ext_t *p_ext; + + BUS_ENTER( BUS_DBG_PNP ); + + p_ext = p_dev_obj->DeviceExtension; + + CL_ASSERT( p_ext->n_ci_ifc_ref > 0 ); + + cl_atomic_dec( &p_ext->n_ci_ifc_ref ); + ObDereferenceObject( p_dev_obj ); + + + BUS_EXIT( BUS_DBG_PNP ); +} + + +static NTSTATUS +__query_al_ifc( + IN DEVICE_OBJECT* const p_dev_obj, + IN IO_STACK_LOCATION* const p_io_stack ) +{ + ib_al_ifc_t *p_ifc; + + BUS_ENTER( BUS_DBG_PNP ); + + if( p_io_stack->Parameters.QueryInterface.Version != + AL_INTERFACE_VERSION ) + { + BUS_TRACE_EXIT( BUS_DBG_PNP, ("Incorrect interface version (%d)\n", + p_io_stack->Parameters.QueryInterface.Version ) ); + return STATUS_NOT_SUPPORTED; + } + + if( p_io_stack->Parameters.QueryInterface.Size < sizeof(ib_al_ifc_t) ) + { + BUS_TRACE_EXIT( BUS_DBG_PNP, + ("Buffer too small (%d given, %d required).\n", + p_io_stack->Parameters.QueryInterface.Size, sizeof(ib_al_ifc_t)) ); + return STATUS_BUFFER_TOO_SMALL; + } + + // Copy the interface. + p_ifc = (ib_al_ifc_t*)p_io_stack->Parameters.QueryInterface.Interface; + + p_ifc->wdm.Size = sizeof(ib_al_ifc_t); + p_ifc->wdm.Version = AL_INTERFACE_VERSION; + p_ifc->wdm.Context = p_dev_obj; + p_ifc->wdm.InterfaceReference = al_ref_ifc; + p_ifc->wdm.InterfaceDereference = al_deref_ifc; + + __set_ifc( p_ifc ); + + // take the reference before returning. + al_ref_ifc( p_dev_obj ); + BUS_EXIT( BUS_DBG_PNP ); + return STATUS_SUCCESS; +} + +static void +__set_ifc( + OUT ib_al_ifc_t* const p_ifc ) +{ + BUS_ENTER( BUS_DBG_PNP ); + + p_ifc->wdm.Size = sizeof(ib_al_ifc_t); + p_ifc->wdm.InterfaceReference = al_ref_ifc; + p_ifc->wdm.InterfaceDereference = al_deref_ifc; + + p_ifc->sync_destroy = ib_sync_destroy; + p_ifc->open_ca = ib_open_ca; + p_ifc->query_ca = ib_query_ca; + p_ifc->modify_ca = ib_modify_ca; + p_ifc->get_dev = get_ca_dev; + p_ifc->close_ca = ib_close_ca; + p_ifc->alloc_pd = ib_alloc_pd; + p_ifc->dealloc_pd = ib_dealloc_pd; + p_ifc->create_av = ib_create_av; + p_ifc->query_av = ib_query_av; + p_ifc->modify_av = ib_modify_av; + p_ifc->destroy_av = ib_destroy_av; + p_ifc->create_qp = ib_create_qp; + p_ifc->get_spl_qp = ib_get_spl_qp; + p_ifc->query_qp = ib_query_qp; + p_ifc->modify_qp = ib_modify_qp; + p_ifc->destroy_qp = ib_destroy_qp; + p_ifc->create_cq = ib_create_cq; + p_ifc->modify_cq = ib_modify_cq; + p_ifc->query_cq = ib_query_cq; + p_ifc->destroy_cq = ib_destroy_cq; + p_ifc->reg_mem = ib_reg_mem; + p_ifc->reg_phys = ib_reg_phys; + p_ifc->query_mr = ib_query_mr; + p_ifc->rereg_mem = ib_rereg_mem; + p_ifc->reg_shmid = ib_reg_shmid; + p_ifc->dereg_mr = ib_dereg_mr; + p_ifc->create_mw = ib_create_mw; + p_ifc->query_mw = ib_query_mw; + p_ifc->bind_mw = ib_bind_mw; + p_ifc->destroy_mw = ib_destroy_mw; + p_ifc->post_send = ib_post_send; + p_ifc->post_recv = ib_post_recv; + p_ifc->send_mad = ib_send_mad; + p_ifc->cancel_mad = ib_cancel_mad; + p_ifc->poll_cq = ib_poll_cq; + p_ifc->rearm_cq = ib_rearm_cq; + p_ifc->join_mcast = ib_join_mcast; + p_ifc->leave_mcast = ib_leave_mcast; + p_ifc->local_mad = ib_local_mad; + p_ifc->cm_listen = ib_cm_listen; + p_ifc->cm_cancel = ib_cm_cancel; + p_ifc->cm_req = ib_cm_req; + p_ifc->cm_rep = ib_cm_rep; + p_ifc->cm_rtu = ib_cm_rtu; + p_ifc->cm_rej = ib_cm_rej; + p_ifc->cm_mra = ib_cm_mra; + p_ifc->cm_lap = ib_cm_lap; + p_ifc->cm_apr = ib_cm_apr; + p_ifc->force_apm = ib_force_apm; + p_ifc->cm_dreq = ib_cm_dreq; + p_ifc->cm_drep = ib_cm_drep; + p_ifc->cm_handoff = ib_cm_handoff; + p_ifc->create_ioc = ib_create_ioc; + p_ifc->destroy_ioc = ib_destroy_ioc; + p_ifc->reg_ioc = ib_reg_ioc; + p_ifc->add_svc_entry = ib_add_svc_entry; + p_ifc->remove_svc_entry = ib_remove_svc_entry; + p_ifc->get_ca_guids = ib_get_ca_guids; + p_ifc->get_ca_by_gid = ib_get_ca_by_gid; + p_ifc->get_port_by_gid = ib_get_port_by_gid; + p_ifc->create_mad_pool = ib_create_mad_pool; + p_ifc->destroy_mad_pool = ib_destroy_mad_pool; + p_ifc->reg_mad_pool = ib_reg_mad_pool; + p_ifc->dereg_mad_pool = ib_dereg_mad_pool; + p_ifc->get_mad = ib_get_mad; + p_ifc->put_mad = ib_put_mad; + p_ifc->init_dgrm_svc = ib_init_dgrm_svc; + p_ifc->reg_mad_svc = ib_reg_mad_svc; + p_ifc->reg_svc = ib_reg_svc; + p_ifc->dereg_svc = ib_dereg_svc; + p_ifc->query = ib_query; + p_ifc->cancel_query = ib_cancel_query; + p_ifc->reg_pnp = ib_reg_pnp; + p_ifc->dereg_pnp = ib_dereg_pnp; + p_ifc->subscribe = ib_subscribe; + p_ifc->unsubscribe = ib_unsubscribe; + p_ifc->reject_ioc = ib_reject_ioc; + p_ifc->ci_call = ib_ci_call; + p_ifc->open_al = ib_open_al; + p_ifc->close_al = ib_close_al; + p_ifc->get_err_str = ib_get_err_str; + p_ifc->get_wc_status_str = ib_get_wc_status_str; + p_ifc->create_mlnx_fmr = mlnx_create_fmr; + p_ifc->map_phys_mlnx_fmr = mlnx_map_phys_fmr; + p_ifc->unmap_mlnx_fmr = mlnx_unmap_fmr; + p_ifc->destroy_mlnx_fmr = mlnx_destroy_fmr; + p_ifc->create_mlnx_fmr_pool = mlnx_create_fmr_pool; + p_ifc->destroy_mlnx_fmr_pool = mlnx_destroy_fmr_pool; + p_ifc->map_phys_mlnx_fmr_pool = mlnx_map_phys_fmr_pool; + p_ifc->unmap_mlnx_fmr_pool = mlnx_unmap_fmr_pool; + p_ifc->flush_mlnx_fmr_pool = mlnx_flush_fmr_pool; + p_ifc->create_srq = ib_create_srq; + p_ifc->modify_srq = ib_modify_srq; + p_ifc->query_srq = ib_query_srq; + p_ifc->destroy_srq = ib_destroy_srq; + p_ifc->post_srq_recv = ib_post_srq_recv; + + BUS_EXIT( BUS_DBG_PNP ); +} + + +static NTSTATUS +__get_relations( + IN const net64_t ca_guid, + IN IRP* const p_irp ) +{ + UNUSED_PARAM( ca_guid ); + UNUSED_PARAM( p_irp ); + + BUS_ENTER( BUS_DBG_PNP ); + + /* + * Now that ibbus is in the same device stack as the HCA driver, skip + * returning relations here as ibbus has already done the deed. + * This interface remains to minimize changes to HCA drivers for now. + */ + + BUS_EXIT( BUS_DBG_PNP ); + return STATUS_SUCCESS; +} + + +static NTSTATUS +__query_ci_ifc( + IN DEVICE_OBJECT* const p_dev_obj, + IN IO_STACK_LOCATION* const p_io_stack ) +{ + ib_ci_ifc_t *p_ifc; + + BUS_ENTER( BUS_DBG_PNP ); + + if( p_io_stack->Parameters.QueryInterface.Version != + IB_CI_INTERFACE_VERSION ) + { + BUS_TRACE_EXIT( BUS_DBG_PNP, ("Incorrect interface version (%d)\n", + p_io_stack->Parameters.QueryInterface.Version ) ); + return STATUS_NOT_SUPPORTED; + } + + if( p_io_stack->Parameters.QueryInterface.Size < sizeof(ib_ci_ifc_t) ) + { + BUS_TRACE_EXIT( BUS_DBG_PNP, + ("Buffer too small (%d given, %d required).\n", + p_io_stack->Parameters.QueryInterface.Size, sizeof(ib_ci_ifc_t)) ); + return STATUS_BUFFER_TOO_SMALL; + } + + /* Copy the interface. */ + p_ifc = (ib_ci_ifc_t*)p_io_stack->Parameters.QueryInterface.Interface; + + p_ifc->wdm.Size = sizeof(ib_ci_ifc_t); + p_ifc->wdm.Version = IB_CI_INTERFACE_VERSION; + p_ifc->wdm.Context = p_dev_obj; + p_ifc->wdm.InterfaceReference = al_ref_ci_ifc; + p_ifc->wdm.InterfaceDereference = al_deref_ci_ifc; + + /* Set the entry points. */ + p_ifc->register_ca = ib_register_ca; + p_ifc->deregister_ca = ib_deregister_ca; + p_ifc->get_relations = __get_relations; + p_ifc->get_err_str = ib_get_err_str; + + /* take the reference before returning. */ + al_ref_ci_ifc( p_dev_obj ); + BUS_EXIT( BUS_DBG_PNP ); + return STATUS_SUCCESS; +} + + +static NTSTATUS +__query_cm_ifc( + IN DEVICE_OBJECT* const p_dev_obj, + IN IO_STACK_LOCATION* const p_io_stack ) +{ + INFINIBAND_INTERFACE_CM *p_ifc; + + BUS_ENTER( BUS_DBG_PNP ); + + if( p_io_stack->Parameters.QueryInterface.Version != IbaCmVersion(1, 0) ) + { + BUS_TRACE_EXIT( BUS_DBG_PNP, ("Incorrect interface version (%d)\n", + p_io_stack->Parameters.QueryInterface.Version ) ); + return STATUS_NOT_SUPPORTED; + } + + if( p_io_stack->Parameters.QueryInterface.Size < sizeof(INFINIBAND_INTERFACE_CM) ) + { + BUS_TRACE_EXIT( BUS_DBG_PNP, + ("Buffer too small (%d given, %d required).\n", + p_io_stack->Parameters.QueryInterface.Size, sizeof(INFINIBAND_INTERFACE_CM)) ); + return STATUS_BUFFER_TOO_SMALL; + } + + /* Copy the interface. */ + p_ifc = (INFINIBAND_INTERFACE_CM*)p_io_stack->Parameters.QueryInterface.Interface; + + p_ifc->InterfaceHeader.Size = sizeof(INFINIBAND_INTERFACE_CM); + p_ifc->InterfaceHeader.Version = IbaCmVersion(1, 0); + p_ifc->InterfaceHeader.Context = p_dev_obj; + p_ifc->InterfaceHeader.InterfaceReference = al_ref_ifc; + p_ifc->InterfaceHeader.InterfaceDereference = al_deref_ifc; + cm_get_interface(&p_ifc->CM); + + /* take the reference before returning. */ + al_ref_ifc( p_dev_obj ); + BUS_EXIT( BUS_DBG_PNP ); + return STATUS_SUCCESS; +} + +static NTSTATUS +fdo_query_pnp_state( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + bus_fdo_ext_t *p_ext; + + BUS_ENTER( BUS_DBG_PNP ); + + p_ext = (bus_fdo_ext_t*)p_dev_obj->DeviceExtension; + + p_irp->IoStatus.Information |= p_ext->pnp_state; + + *p_action = IrpSkip; + + BUS_EXIT( BUS_DBG_PNP ); + return STATUS_SUCCESS;; +} + + +static NTSTATUS +fdo_query_interface( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + NTSTATUS status; + IO_STACK_LOCATION *p_io_stack; + + BUS_ENTER( BUS_DBG_PNP ); + + PAGED_CODE(); + + p_io_stack = IoGetCurrentIrpStackLocation( p_irp ); + + /* Compare requested GUID with our supported interface GUIDs. */ + if( IsEqualGUID( p_io_stack->Parameters.QueryInterface.InterfaceType, + &GUID_IB_AL_INTERFACE ) ) + { + status = __query_al_ifc( p_dev_obj, p_io_stack ); + } + else if( IsEqualGUID( p_io_stack->Parameters.QueryInterface.InterfaceType, + &GUID_IB_CI_INTERFACE ) ) + { + status = __query_ci_ifc( p_dev_obj, p_io_stack ); + } + else if( IsEqualGUID( p_io_stack->Parameters.QueryInterface.InterfaceType, + &GUID_INFINIBAND_INTERFACE_CM ) ) + { + status = __query_cm_ifc( p_dev_obj, p_io_stack ); + } + else + { + status = p_irp->IoStatus.Status; + } + + if( NT_SUCCESS( status ) ) + *p_action = IrpSkip; + else if( status == STATUS_BUFFER_TOO_SMALL ) + *p_action = IrpComplete; + else + *p_action = IrpIgnore; + + BUS_EXIT( BUS_DBG_PNP ); + return status; +} + + +static NTSTATUS +__fdo_query_power( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + NTSTATUS status = STATUS_SUCCESS; + IO_STACK_LOCATION *p_io_stack; + + BUS_ENTER( BUS_DBG_POWER ); + + UNUSED_PARAM( p_dev_obj ); + + p_io_stack = IoGetCurrentIrpStackLocation( p_irp ); + + switch( p_io_stack->Parameters.Power.Type ) + { + case SystemPowerState: + /* Fail any requests to hibernate or sleep the system. */ + switch( p_io_stack->Parameters.Power.State.SystemState ) + { + case PowerSystemHibernate: + case PowerSystemSleeping1: // STANDBY support + case PowerSystemSleeping2: // STANDBY support + case PowerSystemSleeping3: // STANDBY support + case PowerSystemWorking: + case PowerSystemShutdown: + break; + + default: + status = STATUS_NOT_SUPPORTED; + } + break; + + case DevicePowerState: + /* Fail any query for low power states. */ + switch( p_io_stack->Parameters.Power.State.DeviceState ) + { + case PowerDeviceD0: + case PowerDeviceD3: + /* We only support fully powered or off power states. */ + break; + + default: + status = STATUS_NOT_SUPPORTED; + } + break; + } + + if( status == STATUS_NOT_SUPPORTED ) + *p_action = IrpComplete; + else + *p_action = IrpSkip; + + BUS_EXIT( BUS_DBG_POWER ); + return status; +} + + + +/* Work item callback to handle DevicePowerD0 IRPs at passive level. */ + +static void +__device_power_up_completion_workItem( + IN DEVICE_OBJECT* p_dev_obj, + IN void* context ) +{ + NTSTATUS status; + IO_STACK_LOCATION *p_io_stack; + bus_fdo_ext_t *p_ext; + IRP *p_irp; + POWER_STATE power_state; + + BUS_ENTER( BUS_DBG_POWER ); + + p_ext = (bus_fdo_ext_t*)p_dev_obj->DeviceExtension; + p_irp = (IRP*)context; + p_io_stack = IoGetCurrentIrpStackLocation( p_irp ); + + IoFreeWorkItem( p_ext->p_po_work_item ); + p_ext->p_po_work_item = NULL; + + /* re-register CA */ + BUS_PRINT( BUS_DBG_POWER, + ("***** re-register CA, IRQL %d\n", KeGetCurrentIrql())); + + // stat + if ( p_ext->p_stat ) { + p_ext->p_stat->thread[BUS_ST_THREAD_POWER_UP].p_thread = KeGetCurrentThread(); + memcpy( p_ext->p_stat->thread[BUS_ST_THREAD_POWER_UP].thread_name, "PowerUp", 8 ); + } + + status = __register_ca( p_dev_obj ); + if( !NT_SUCCESS( status ) ) { + BUS_PRINT( BUS_DBG_POWER, + ("!!! __register_ca failed (%#x) \n", status)); + goto err_fdo_start; + } + + p_ext->device_power_state = p_io_stack->Parameters.Power.State.DeviceState; + power_state = PoSetPowerState( p_dev_obj, DevicePowerState, + p_io_stack->Parameters.Power.State ); + + BUS_PRINT( BUS_DBG_POWER, + ("PoSetPowerState: old state %d, new state to %d\n", + power_state.DeviceState, p_ext->device_power_state )); + + CL_PRINT_TO_EVENT_LOG( p_dev_obj, EVENT_IBBUS_ANY_WARN, + ("Power increased to: device %d, system %d.\n", + (int)p_ext->device_power_state, (int)p_ext->system_power_state)); + + if ( p_ext->p_stat ) { + p_ext->p_stat->thread[BUS_ST_THREAD_POWER_UP].p_thread = NULL; + *p_ext->p_stat->thread[BUS_ST_THREAD_POWER_UP].thread_name = '\0'; + } + + goto exit; + +err_fdo_start: + /* Flag device as having failed. */ + p_ext->pnp_state |= PNP_DEVICE_FAILED; + IoInvalidateDeviceState( p_ext->cl_ext.p_pdo ); +exit: + PoStartNextPowerIrp( p_irp ); + IoCompleteRequest( p_irp, IO_NO_INCREMENT ); + IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp ); + BUS_EXIT( BUS_DBG_POWER ); +} + + +/*NOTE: Completion routines must NEVER be pageable. */ +static NTSTATUS +__device_power_up_completion( + IN DEVICE_OBJECT *p_dev_obj, + IN IRP *p_irp, + IN void *context ) +{ + NTSTATUS status = STATUS_SUCCESS; + bus_fdo_ext_t *p_ext; + IO_STACK_LOCATION *p_io_stack; + + BUS_ENTER( BUS_DBG_POWER ); + + UNUSED_PARAM( context ); + + p_ext = (bus_fdo_ext_t*)p_dev_obj->DeviceExtension; + p_io_stack = IoGetCurrentIrpStackLocation( p_irp ); + + if( !NT_SUCCESS( p_irp->IoStatus.Status ) ) { + BUS_PRINT( BUS_DBG_POWER, + ("IRP_MN_SET_POWER for device failed by lower driver with %08x.\n", + p_irp->IoStatus.Status)); + status = STATUS_SUCCESS; + PoStartNextPowerIrp( p_irp ); + goto release; + } + + /* Process in a work item to allow blocking. */ + ASSERT( !p_ext->p_po_work_item ); + p_ext->p_po_work_item = IoAllocateWorkItem( p_dev_obj ); + if( !p_ext->p_po_work_item ) { + BUS_PRINT( BUS_DBG_POWER, + ("Failed to allocate work item.\n" )); + status = STATUS_SUCCESS; + p_ext->pnp_state |= PNP_DEVICE_FAILED; + IoInvalidateDeviceState( p_ext->cl_ext.p_pdo ); + PoStartNextPowerIrp( p_irp ); + goto release; + } + + /* Process in work item callback. */ + IoMarkIrpPending( p_irp ); + IoQueueWorkItem( p_ext->p_po_work_item, + __device_power_up_completion_workItem, DelayedWorkQueue, p_irp ); + status = STATUS_MORE_PROCESSING_REQUIRED; + goto exit; + +release: + IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp ); +exit: + BUS_EXIT( BUS_DBG_POWER ); + return status; +} + + +static NTSTATUS __device_power_down_workItem_completion( + IN DEVICE_OBJECT *p_dev_obj, + IN IRP *p_irp, + IN void *context ) +{ + bus_fdo_ext_t *p_ext = (bus_fdo_ext_t*)p_dev_obj->DeviceExtension; + UNUSED_PARAM( context ); + + BUS_ENTER( BUS_DBG_POWER ); + + PoStartNextPowerIrp( p_irp ); + IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp ); + + // stat + if ( p_ext->p_stat ) { + p_ext->p_stat->thread[BUS_ST_THREAD_POWER_DOWN].p_thread = NULL; + *p_ext->p_stat->thread[BUS_ST_THREAD_POWER_DOWN].thread_name = '\0'; + } + + BUS_EXIT( BUS_DBG_POWER ); + return STATUS_SUCCESS; +} + +/* Work item callback to handle DevicePowerD3 IRPs at passive level. */ +static void +__device_power_down_workItem( + IN DEVICE_OBJECT* p_dev_obj, + IN void* context ) +{ + IO_STACK_LOCATION *p_io_stack; + bus_fdo_ext_t *p_ext; + IRP *p_irp; + POWER_STATE power_state; + + BUS_ENTER( BUS_DBG_POWER ); + + p_ext = (bus_fdo_ext_t*)p_dev_obj->DeviceExtension; + p_irp = (IRP*)context; + p_io_stack = IoGetCurrentIrpStackLocation( p_irp ); + + IoFreeWorkItem( p_ext->p_po_work_item ); + p_ext->p_po_work_item = NULL; + + p_ext->device_power_state = p_io_stack->Parameters.Power.State.DeviceState; + power_state = PoSetPowerState( p_dev_obj, DevicePowerState, + p_io_stack->Parameters.Power.State ); + + BUS_PRINT( BUS_DBG_POWER, + ("PoSetPowerState: old state %d, new state to %d, IRQL %d\n", + power_state.DeviceState, p_ext->device_power_state, KeGetCurrentIrql() )); + + CL_PRINT_TO_EVENT_LOG( p_dev_obj, EVENT_IBBUS_ANY_WARN, + ("Power decreased to: device %d, system %d.\n", + (int)p_ext->device_power_state, (int)p_ext->system_power_state)); + + BUS_PRINT( BUS_DBG_POWER, + ("***** deregister CA \n")); + + // stat + if ( p_ext->p_stat ) { + p_ext->p_stat->thread[BUS_ST_THREAD_POWER_DOWN].p_thread = KeGetCurrentThread(); + memcpy( p_ext->p_stat->thread[BUS_ST_THREAD_POWER_DOWN].thread_name, "PowerDown", 10 ); + } + + __deregister_ca( p_dev_obj ); + + IoCopyCurrentIrpStackLocationToNext( p_irp ); +#pragma warning( push, 3 ) + IoSetCompletionRoutine( p_irp, __device_power_down_workItem_completion, + NULL, TRUE, TRUE, TRUE ); +#pragma warning( pop ) + PoCallDriver( p_ext->cl_ext.p_next_do, p_irp ); + + BUS_EXIT( BUS_DBG_POWER ); +} + + + +static NTSTATUS +__fdo_set_power( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + NTSTATUS status; + IO_STACK_LOCATION *p_io_stack; + bus_fdo_ext_t *p_ext; + + BUS_ENTER( BUS_DBG_POWER ); + + p_ext = p_dev_obj->DeviceExtension; + p_io_stack = IoGetCurrentIrpStackLocation( p_irp ); + + BUS_TRACE( BUS_DBG_POWER, + ("SET_POWER for FDO %p (ext %p): type %s, state %d, action %d, IRQL %d \n", + p_dev_obj, p_ext, + (p_io_stack->Parameters.Power.Type) + ? "DevicePowerState" : "SystemPowerState", + p_io_stack->Parameters.Power.State.DeviceState, + p_io_stack->Parameters.Power.ShutdownType, KeGetCurrentIrql() )); + + switch( p_io_stack->Parameters.Power.Type ) + { + case SystemPowerState: + /* Pass down and let the PDO driver handle it. */ + p_ext->system_power_state = p_io_stack->Parameters.Power.State.SystemState; + *p_action = IrpIgnore; + status = STATUS_SUCCESS; + break; + + case DevicePowerState: + IoMarkIrpPending( p_irp ); + if( p_io_stack->Parameters.Power.State.DeviceState == PowerDeviceD0 && + p_ext->system_power_state == PowerSystemWorking) + { /* power up */ + /* If we're already powered up, just pass down. */ + if( p_ext->device_power_state == PowerDeviceD0 ) + { + status = STATUS_SUCCESS; + *p_action = IrpIgnore; + break; + } + + /* Process in I/O completion callback. */ + IoCopyCurrentIrpStackLocationToNext( p_irp ); +#pragma warning( push, 3 ) + IoSetCompletionRoutine( p_irp, __device_power_up_completion, NULL, + TRUE, TRUE, TRUE ); +#pragma warning( pop ) + PoCallDriver( p_ext->cl_ext.p_next_do, p_irp ); + } + else + { /* power down */ + + /* Process in a work item - deregister_ca and HcaDeinit block. */ + ASSERT( !p_ext->p_po_work_item ); + p_ext->p_po_work_item = IoAllocateWorkItem( p_dev_obj ); + if( !p_ext->p_po_work_item ) + { + status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + + /* Process in work item callback. */ + IoQueueWorkItem( + p_ext->p_po_work_item, __device_power_down_workItem, DelayedWorkQueue, p_irp ); + } + *p_action = IrpDoNothing; + status = STATUS_PENDING; + break; + + default: + /* Pass down and let the PDO driver handle it. */ + *p_action = IrpIgnore; + status = STATUS_SUCCESS; + break; + } + + if( !NT_SUCCESS( status ) ) + *p_action = IrpComplete; + + BUS_EXIT( BUS_DBG_POWER ); + return status; +} + + +/* + * A CA GUID of zero means that all devices should be reported. + */ +NTSTATUS +bus_get_relations( + IN cl_qlist_t* const p_pdo_list, + IN const net64_t ca_guid, + IN IRP* const p_irp ) +{ + NTSTATUS status; + DEVICE_RELATIONS *p_rel; + cl_list_item_t *p_list_item; + bus_pdo_ext_t *p_pdo_ext; + size_t n_devs = 0; + + BUS_ENTER( BUS_DBG_PNP ); + + /* Count the number of child devices. */ + for( p_list_item = cl_qlist_head( p_pdo_list ); + p_list_item != cl_qlist_end( p_pdo_list ); + p_list_item = cl_qlist_next( p_list_item ) ) + { + p_pdo_ext = PARENT_STRUCT( p_list_item, bus_pdo_ext_t, list_item ); + + if( !p_pdo_ext->b_present ) + { + // mark it missing to be removed in port_remove + p_pdo_ext->b_reported_missing = TRUE; + /* + * We don't report a PDO that is no longer present. This is how + * the PDO will get cleaned up. + */ + BUS_TRACE( BUS_DBG_PNP, ("Don't report PDO! %s: PDO %p, ext %p, " + "present %d, missing %d .\n", + p_pdo_ext->cl_ext.vfptr_pnp_po->identity, + p_pdo_ext->cl_ext.p_self_do, p_pdo_ext, p_pdo_ext->b_present, + p_pdo_ext->b_reported_missing ) ); + continue; + } + + if( ca_guid && p_pdo_ext->ca_guid != ca_guid ) + continue; + + n_devs++; + } + + if( !n_devs ) + { + BUS_TRACE_EXIT( BUS_DBG_PNP, ("Found 0 PDOs ca_guid %I64x\n", ca_guid)); + return STATUS_NO_SUCH_DEVICE; + } + + BUS_TRACE( BUS_DBG_PNP, ("Found %d PDOs ca_guid %I64x\n", n_devs, ca_guid)); + + /* Add space for our child IOUs. */ + status = cl_alloc_relations( p_irp, n_devs ); + if( !NT_SUCCESS( status ) ) + { + BUS_TRACE_EXIT( BUS_DBG_ERROR, + ("cl_alloc_relations returned %08x.\n", status) ); + return status; + } + + p_rel = (DEVICE_RELATIONS*)p_irp->IoStatus.Information; + + for( p_list_item = cl_qlist_head( p_pdo_list ); + p_list_item != cl_qlist_end( p_pdo_list ); + p_list_item = cl_qlist_next( p_list_item ) ) + { + p_pdo_ext = PARENT_STRUCT( p_list_item, bus_pdo_ext_t, list_item ); + + if( !p_pdo_ext->b_present ) + continue; + + if( ca_guid && p_pdo_ext->ca_guid != ca_guid ) + continue; + + BUS_TRACE( BUS_DBG_PNP, ("Reported PDO %p(=%p), ext %p\n", + p_pdo_ext->cl_ext.p_self_do, p_pdo_ext->cl_ext.p_pdo, p_pdo_ext )); + + p_rel->Objects[p_rel->Count] = p_pdo_ext->cl_ext.p_pdo; + ObReferenceObject( p_rel->Objects[p_rel->Count++] ); + } + + BUS_EXIT( BUS_DBG_PNP ); + return STATUS_SUCCESS; +} + + +/* + * find a bus filter instance (p_bfi) given an *cl_obj: port_mgr or iou_mgr. + */ + +bus_filter_t * +get_bfi_by_obj(IN int obj_type, IN cl_obj_t *p_obj ) +{ + bus_filter_t *p_bfi; + bus_filter_t *matched=NULL; + + CL_ASSERT((obj_type == BFI_PORT_MGR_OBJ) || (obj_type == BFI_IOU_MGR_OBJ)); + + lock_control_event(); + + for(p_bfi=g_bus_filters; p_bfi < &g_bus_filters[MAX_BUS_FILTERS]; p_bfi++) { + + if ( !p_bfi->p_bus_ext ) + continue; + + if ( obj_type == BFI_PORT_MGR_OBJ ) { + if ( p_obj == p_bfi->p_port_mgr_obj ) { + matched = p_bfi; + break; + } + } + else { + if ( p_obj == p_bfi->p_iou_mgr_obj ) { + matched = p_bfi; + break; + } + } + } + unlock_control_event(); + + BUS_TRACE( BUS_DBG_PNP, + ("cl_obj %p type %s_MGR_OBJ --> bfi[%d] %p\n", p_obj, + (obj_type == BFI_PORT_MGR_OBJ ? "PORT": "IOU"), + (matched ? (matched - g_bus_filters) : (-1)), matched ) ); + + return matched; +} + +/* + * find a bus filter instance given an HCA guid. + * BFIs are bound to GUIDs in fdo_start(). + */ + +bus_filter_t * +get_bfi_by_ca_guid( IN net64_t ca_guid ) +{ + bus_filter_t *p_bfi; + bus_filter_t *matched=NULL; + + if ( ca_guid == 0ULL ) + { + matched = g_bus_filters; + BUS_TRACE( BUS_DBG_PNP, ("ERR guid %I64x -> bfi[0] %p\n", + ca_guid, matched) ); + CL_ASSERT( ca_guid ); + return matched; + } + + lock_control_event(); + + for(p_bfi=g_bus_filters; p_bfi < &g_bus_filters[MAX_BUS_FILTERS]; p_bfi++) + { + if ( !p_bfi->p_bus_ext ) + continue; + + if ( ca_guid == p_bfi->ca_guid ) + { + matched = p_bfi; + break; + } + } + unlock_control_event(); + +#if DBG + if ( !matched ) + { + BUS_PRINT( BUS_DBG_PNP, ("No Match ca_guid 0x%I64x -> bfi[%d] %p\n", + ca_guid, -1, matched ) ); + } +#endif + return matched; +} + + +bus_filter_t * +alloc_bfi( IN DRIVER_OBJECT *p_driver_obj, OUT int *p_instance_count ) +{ + bus_filter_t *p_bfi; + bus_filter_t *matched=NULL; + + /* Using unsafe function so that the IRQL remains at PASSIVE_LEVEL. + * IoCreateDeviceSecure & IoCreateSymbolicLink must be called at + * PASSIVE_LEVEL. + */ + lock_control_event(); + + // find 1st unused bfi slot. + for(p_bfi=g_bus_filters; p_bfi < &g_bus_filters[MAX_BUS_FILTERS]; p_bfi++) + { + if ( !p_bfi->p_bus_ext ) + { + /* temp setting until 'real' p_bus_ext is alloc; see bus_add_device. + * If p_bus_ext is ! 0, then bfi slot is allocated, although it + * may not yet have a bound CA guid; set set_get_ + */ + p_bfi->p_bus_ext = (bus_fdo_ext_t*)p_driver_obj; + matched = p_bfi; + *p_instance_count = ++g_bfi_InstanceCount; // record in-use + break; + } + } + unlock_control_event(); + +#if DBG + RtlStringCbPrintfA ( p_bfi->whoami, + sizeof(p_bfi->whoami), + "bfi-%d", + (g_bfi_InstanceCount - 1) ); + + p_bfi->magic = BFI_MAGIC; +#endif + + BUS_TRACE( BUS_DBG_PNP, ("%s %p\n", + (matched ? matched->whoami:"Nobody"), matched) ); + + return matched; +} + + +int +free_bfi( IN bus_filter_t *p_bfi ) +{ + int remaining; + + lock_control_event(); + p_bfi->p_bus_ext = NULL; + p_bfi->ca_guid = 0ULL; + remaining = --g_bfi_InstanceCount; // one less bfi in-use + unlock_control_event(); + + return remaining; +} + +int +get_bfi_count( void ) +{ + int ic; + + lock_control_event(); + ic = g_bfi_InstanceCount; + unlock_control_event(); + + return ic; +} + +#if DBG +char *get_obj_state_str(cl_state_t state) +{ + switch( state ) { + case CL_UNINITIALIZED: + return "UNINITIALIZED"; + case CL_INITIALIZED: + return "INITIALIZED"; + case CL_DESTROYING: + return "DESTROYING"; + case CL_DESTROYED: + return "DESTROYED"; + default: + break; + } + return "Err - Bad obj state"; +} +#endif + diff --git a/branches/WOF2-3/core/bus/kernel/bus_pnp.h b/branches/WOF2-3/core/bus/kernel/bus_pnp.h new file mode 100644 index 00000000..681d8449 --- /dev/null +++ b/branches/WOF2-3/core/bus/kernel/bus_pnp.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + +#if !defined _BUS_DRV_PNP_H_ +#define _BUS_DRV_PNP_H_ + +#include "bus_driver.h" + +/****f* InfiniBand Bus Driver: Plug and Play/bus_add_device +* NAME +* bus_add_device +* +* DESCRIPTION +* Main AddDevice entrypoint for the IB Bus driver. +* Adds the bus root functional device object to the device node. The +* bus root FDO performs all PnP operations for fabric attached devices. +* +* SYNOPSIS +*/ +NTSTATUS +bus_add_device( + IN PDRIVER_OBJECT p_driver_obj, + IN PDEVICE_OBJECT p_pdo ); +/* +* PARAMETERS +* p_driver_obj +* Driver object for the BUS driver. +* +* p_pdo +* Pointer to the device object representing the PDO for the device on +* which we are loading. +* +* RETURN VBUSUES +* STATUS_SUCCESS if the device was successfully added. +* +* Other NTSTATUS error values if errors are encountered. +* +* SEE ALSO +*********/ + + +void +al_ref_ifc( + IN DEVICE_OBJECT* p_dev_obj ); + +NTSTATUS +bus_get_relations( + IN cl_qlist_t* const p_pdo_list, + IN const net64_t ca_guid, + IN IRP* const p_irp ); + +NTSTATUS port_mgr_pkey_add(); +NTSTATUS port_mgr_pkey_rem(); +#endif // !defined _BUS_DRV_PNP_H_ diff --git a/branches/WOF2-3/core/bus/kernel/bus_port_mgr.c b/branches/WOF2-3/core/bus/kernel/bus_port_mgr.c new file mode 100644 index 00000000..a15cf9e5 --- /dev/null +++ b/branches/WOF2-3/core/bus/kernel/bus_port_mgr.c @@ -0,0 +1,2155 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2006 Mellanox Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include +#include +#include +#include "ib_common.h" +#include "bus_pnp.h" +#include "bus_port_mgr.h" +#include "al_ca.h" +#include "al_mgr.h" +#include +#include +#include "iba/ipoib_ifc.h" +#include "al_dev.h" + +/* {5A9649F4-0101-4a7c-8337-796C48082DA2} */ +DEFINE_GUID(GUID_BUS_TYPE_IBA, +0x5a9649f4, 0x101, 0x4a7c, 0x83, 0x37, 0x79, 0x6c, 0x48, 0x8, 0x2d, 0xa2); + + +/* + * Device extension for IPoIB port PDOs. + */ +typedef struct _bus_port_ext +{ + bus_pdo_ext_t pdo; + + port_guid_pkey_t port_guid; + uint32_t n_port; + + /* Number of references on the upper interface. */ + atomic32_t n_ifc_ref; + +} bus_port_ext_t; + + +typedef struct _port_pnp_context +{ + bus_filter_t *p_bus_filter; + void *p_pdo_ext; + int port_num; + +} port_pnp_ctx_t; + + +extern pkey_array_t g_pkeys; + +/* + * Function prototypes. + */ +void +destroying_port_mgr( + IN cl_obj_t* p_obj ); + +void +free_port_mgr( + IN cl_obj_t* p_obj ); + +ib_api_status_t +bus_reg_port_pnp( + IN bus_filter_t* p_bfi ); + +ib_api_status_t +port_mgr_pnp_cb( + IN ib_pnp_rec_t* p_pnp_rec ); + +ib_api_status_t +port_mgr_port_add( + IN ib_pnp_port_rec_t* p_pnp_rec ); + +void +port_mgr_port_remove( + IN ib_pnp_port_rec_t* p_pnp_rec ); + +static NTSTATUS +port_start( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +port_query_remove( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static void +port_release_resources( + IN DEVICE_OBJECT* const p_dev_obj ); + +static NTSTATUS +port_remove( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +port_surprise_remove( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +port_query_capabilities( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +port_query_target_relations( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +port_query_device_id( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp ); + +static NTSTATUS +port_query_hardware_ids( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp ); + +static NTSTATUS +port_query_compatible_ids( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp ); + +static NTSTATUS +port_query_unique_id( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp ); + +static NTSTATUS +port_query_description( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp ); + + +static NTSTATUS +port_query_location( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp ); + +static NTSTATUS +port_query_bus_info( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +port_query_ipoib_ifc( + IN DEVICE_OBJECT* const p_dev_obj, + IN IO_STACK_LOCATION* const p_io_stack ); + +static NTSTATUS +port_query_interface( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +port_set_power( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + + + +/* + * Global virtual function pointer tables shared between all + * instances of Port PDOs. + */ +static const cl_vfptr_pnp_po_t vfptr_port_pnp = { + "IODEVICE", + port_start, + cl_irp_succeed, + cl_irp_succeed, + cl_irp_succeed, + port_query_remove, + port_release_resources, + port_remove, + cl_irp_succeed, + port_surprise_remove, + port_query_capabilities, + cl_irp_complete, + cl_irp_complete, + cl_irp_succeed, + cl_irp_complete, + cl_irp_complete, + cl_irp_complete, + port_query_target_relations, + cl_irp_complete, + cl_irp_complete, + cl_irp_complete, + port_query_bus_info, + port_query_interface, + cl_irp_complete, + cl_irp_complete, + cl_irp_complete, + cl_irp_complete, + cl_irp_succeed, // QueryPower + port_set_power, // SetPower + cl_irp_unsupported, // PowerSequence + cl_irp_unsupported // WaitWake +}; + + +static const cl_vfptr_query_txt_t vfptr_port_query_txt = { + port_query_device_id, + port_query_hardware_ids, + port_query_compatible_ids, + port_query_unique_id, + port_query_description, + port_query_location +}; + + + +/* + * Create the AL load service. + */ +ib_api_status_t +create_port_mgr( + IN bus_filter_t* p_bfi ) +{ + ib_api_status_t status; + cl_status_t cl_status; + port_mgr_t *p_port_mgr; + + BUS_ENTER( BUS_DBG_PNP ); + + CL_ASSERT( p_bfi->p_port_mgr == NULL ); + + p_port_mgr = cl_zalloc( sizeof( port_mgr_t ) ); + if( !p_port_mgr ) + { + BUS_TRACE_EXIT( BUS_DBG_ERROR, + ("Failed to allocate port manager.\n") ); + return IB_INSUFFICIENT_MEMORY; + } + p_bfi->p_port_mgr = p_port_mgr; + + /* Construct the load service. */ + cl_obj_construct( &p_port_mgr->obj, AL_OBJ_TYPE_LOADER ); + + p_bfi->p_port_mgr_obj = &p_port_mgr->obj; + + cl_mutex_construct( &p_port_mgr->pdo_mutex ); + cl_qlist_init( &p_port_mgr->port_list ); + + cl_status = cl_mutex_init( &p_port_mgr->pdo_mutex ); + if( cl_status != CL_SUCCESS ) + { + free_port_mgr( &p_port_mgr->obj ); + BUS_TRACE_EXIT( BUS_DBG_ERROR, + ("cl_mutex_init returned %#x.\n", cl_status) ); + return ib_convert_cl_status( cl_status ); + } + + /* Initialize the load service object. */ + cl_status = cl_obj_init( &p_port_mgr->obj, CL_DESTROY_SYNC, + destroying_port_mgr, NULL, free_port_mgr ); + + if( cl_status != CL_SUCCESS ) + { + free_port_mgr( &p_port_mgr->obj ); + BUS_TRACE_EXIT( BUS_DBG_ERROR, + ("cl_obj_init returned %#x.\n", cl_status) ); + return ib_convert_cl_status( cl_status ); + } + + /* Register for port PnP events */ + status = bus_reg_port_pnp( p_bfi ); + if( status != IB_SUCCESS ) + { + BUS_TRACE_EXIT( BUS_DBG_ERROR, + ("bus_reg_port_pnp returned %s.\n", ib_get_err_str(status)) ); + free_port_mgr( &p_port_mgr->obj ); + return status; + } + + BUS_EXIT( BUS_DBG_PNP ); + return IB_SUCCESS; +} + + +/* + * Pre-destroy the load service. + */ +void +destroying_port_mgr( + IN cl_obj_t* p_obj ) +{ + ib_api_status_t status; + bus_filter_t *p_bfi; + port_mgr_t *p_port_mgr; + + BUS_ENTER( BUS_DBG_PNP ); + + CL_ASSERT( p_obj ); + p_bfi = get_bfi_by_obj(BFI_PORT_MGR_OBJ, p_obj); + if (p_bfi == NULL) { + BUS_PRINT(BUS_DBG_PNP, ("Failed to find p_bfi by obj %p?\n", p_obj)); + return; + } + p_port_mgr = p_bfi->p_port_mgr; + + BUS_PRINT(BUS_DBG_PNP, ("%s obj %p port_mgr %p port_mgr_obj %p\n", + p_bfi->whoami,p_obj,p_port_mgr, p_bfi->p_port_mgr_obj) ); + + CL_ASSERT( p_port_mgr == PARENT_STRUCT( p_obj, port_mgr_t, obj ) ); + + /* Deregister for port PnP events if this is the last Port manager. */ + if ( get_bfi_count() == 1 && bus_globals.h_pnp_port ) { + status = ib_dereg_pnp( bus_globals.h_pnp_port, NULL ); + bus_globals.h_pnp_port = NULL; + CL_ASSERT( status == IB_SUCCESS ); + } + cl_obj_deref( p_bfi->p_port_mgr_obj ); + + BUS_EXIT( BUS_DBG_PNP ); +} + + +/* + * Free the load service. + */ +void +free_port_mgr( + IN cl_obj_t* p_obj ) +{ + bus_pdo_ext_t *p_ext; + cl_list_item_t *p_list_item; + bus_filter_t *p_bfi; + port_mgr_t *p_port_mgr; + + BUS_ENTER( BUS_DBG_PNP ); + + CL_ASSERT( p_obj ); + p_bfi = get_bfi_by_obj(BFI_PORT_MGR_OBJ, p_obj); + if (p_bfi == NULL) { + BUS_PRINT(BUS_DBG_PNP, ("No p_bfi for port obj %p?\n", p_obj)); + return; + } + p_port_mgr = p_bfi->p_port_mgr; + if ( !p_port_mgr ) { + // if create fails & then free is called, p_bfi->p_port_mgr == NULL + return; + } + CL_ASSERT( p_port_mgr == PARENT_STRUCT( p_obj, port_mgr_t, obj ) ); + + BUS_PRINT(BUS_DBG_PNP, ("%s obj %p port_mgr %p port_mgr_obj %p\n", + p_bfi->whoami, p_obj,p_port_mgr, + p_bfi->p_port_mgr_obj) ); + + BUS_PRINT( BUS_DBG_PNP, + ("%s Mark all IPoIB PDOs no longer present\n", p_bfi->whoami)); + /* + * Mark all IPoIB PDOs as no longer present. This will cause them + * to be removed when they process the IRP_MN_REMOVE_DEVICE. + */ + p_list_item = cl_qlist_remove_head( &p_port_mgr->port_list ); + while( p_list_item != cl_qlist_end( &p_port_mgr->port_list ) ) + { + p_ext = PARENT_STRUCT( p_list_item, bus_pdo_ext_t, list_item ); + p_list_item = cl_qlist_remove_head( &p_port_mgr->port_list ); + if( p_ext->cl_ext.pnp_state == SurpriseRemoved ) + { + CL_ASSERT( !p_ext->b_present ); + p_ext->b_reported_missing = TRUE; + BUS_TRACE( BUS_DBG_PNP, + ("%s %s: PDO %p, ext %p, present %d, missing %d .\n", + p_bfi->whoami, + p_ext->cl_ext.vfptr_pnp_po->identity, p_ext->cl_ext.p_self_do, + p_ext, p_ext->b_present, p_ext->b_reported_missing ) ); + continue; + } + + if( p_ext->h_ca && p_ext->hca_acquired ) + { + /* Invalidate bus relations for the HCA. */ + IoInvalidateDeviceRelations( + p_ext->h_ca->p_hca_dev, BusRelations ); + + /* Release the reference on the CA object. */ + deref_al_obj( &p_ext->h_ca->obj ); + } + + BUS_TRACE( BUS_DBG_PNP, ("%s Deleted device %s: PDO %p, ext %p\n", + p_bfi->whoami, p_ext->cl_ext.vfptr_pnp_po->identity, + p_ext->cl_ext.p_self_do, p_ext ) ); + + IoDeleteDevice( p_ext->cl_ext.p_self_do ); + } + + cl_mutex_destroy( &p_port_mgr->pdo_mutex ); + cl_obj_deinit( p_obj ); + cl_free( p_port_mgr ); + + p_bfi->p_port_mgr = NULL; + p_bfi->p_port_mgr_obj = NULL; + + BUS_EXIT( BUS_DBG_PNP ); +} + + +/* + * Register the load service for the given PnP class events. + */ +ib_api_status_t +bus_reg_port_pnp( IN bus_filter_t *p_bfi ) +{ + ib_pnp_req_t pnp_req; + ib_api_status_t status = IB_SUCCESS; + boolean_t need_pnp_reg = FALSE; + + /* only need to register for port PNP events once. + * Do not hold mutex over pnp_reg() call as callback which needs mutex + * could occur. + */ + if ( !bus_globals.h_pnp_port ) + { + lock_control_event(); + if ( !bus_globals.h_pnp_port ) { + bus_globals.h_pnp_port = (ib_pnp_handle_t)1; /* block others */ + need_pnp_reg = TRUE; + } + unlock_control_event(); + + if ( need_pnp_reg ) + { + cl_memclr( &pnp_req, sizeof( ib_pnp_req_t ) ); + pnp_req.pnp_class = IB_PNP_PORT | IB_PNP_FLAG_REG_SYNC; + pnp_req.pnp_context = NULL; + pnp_req.pfn_pnp_cb = port_mgr_pnp_cb; + + status = ib_reg_pnp( gh_al, &pnp_req, &bus_globals.h_pnp_port ); + } + } + + if ( status == IB_SUCCESS ) + { + /* Reference this bus filter's port load service */ + cl_obj_ref( p_bfi->p_port_mgr_obj ); + } + + return status; +} + + +/* + * Load service PnP event callback. + */ +ib_api_status_t +port_mgr_pnp_cb( + IN ib_pnp_rec_t* p_pnp_rec ) +{ + ib_api_status_t status=IB_SUCCESS; + + BUS_ENTER( BUS_DBG_PNP ); + + CL_ASSERT( p_pnp_rec ); + + switch( p_pnp_rec->pnp_event ) + { + case IB_PNP_PORT_ADD: + status = port_mgr_port_add( (ib_pnp_port_rec_t*)p_pnp_rec ); + break; + + case IB_PNP_PORT_REMOVE: + port_mgr_port_remove( (ib_pnp_port_rec_t*)p_pnp_rec ); + break; + + default: + XBUS_PRINT( BUS_DBG_PNP, ("Unhandled PNP Event %s\n", + ib_get_pnp_event_str(p_pnp_rec->pnp_event) )); + break; + } + BUS_EXIT( BUS_DBG_PNP ); + + return status; +} + + +/* + * Called to get bus relations for an HCA. + */ +NTSTATUS +port_mgr_get_bus_relations( + IN const net64_t ca_guid, + IN IRP* const p_irp ) +{ + NTSTATUS status; + bus_filter_t *p_bfi; + port_mgr_t *p_port_mgr; + DEVICE_RELATIONS *p_rel; + + BUS_ENTER( BUS_DBG_PNP ); + + BUS_PRINT(BUS_DBG_PNP, ("CA_guid %I64x\n",ca_guid)); + + /* special case guid == 0 - walk all bus filter instances */ + if ( ca_guid == 0ULL ) { + BUS_PRINT(BUS_DBG_PNP, ("CA_guid 0\n")); + for(p_bfi=g_bus_filters; p_bfi < &g_bus_filters[MAX_BUS_FILTERS]; p_bfi++) { + p_port_mgr = p_bfi->p_port_mgr; + if ( !p_port_mgr ) + continue; + cl_mutex_acquire( &p_port_mgr->pdo_mutex ); + status = bus_get_relations( &p_port_mgr->port_list, + p_bfi->ca_guid, + p_irp ); + cl_mutex_release( &p_port_mgr->pdo_mutex ); + } + + p_rel = (DEVICE_RELATIONS*)p_irp->IoStatus.Information; + if ( p_rel ) { + BUS_PRINT(BUS_DBG_PNP, ("CA_guid 0 Reports %d\n", p_rel->Count)); + } + BUS_EXIT( BUS_DBG_PNP ); + return STATUS_SUCCESS; + } + + p_bfi = get_bfi_by_ca_guid(ca_guid); + if (p_bfi == NULL) { + BUS_PRINT(BUS_DBG_PNP, + ("Null *p_bfi from ca_guid %I64x\n",ca_guid)); + BUS_EXIT( BUS_DBG_PNP ); + return STATUS_NO_SUCH_DEVICE; + } + p_port_mgr = p_bfi->p_port_mgr; + + BUS_PRINT(BUS_DBG_PNP, ("%s for ca_guid %I64x port_mgr %p\n", + p_bfi->whoami, ca_guid, p_port_mgr) ); + if (!p_port_mgr) + return STATUS_NO_SUCH_DEVICE; + + cl_mutex_acquire( &p_port_mgr->pdo_mutex ); + status = bus_get_relations( &p_port_mgr->port_list, ca_guid, p_irp ); + cl_mutex_release( &p_port_mgr->pdo_mutex ); + + BUS_EXIT( BUS_DBG_PNP ); + return STATUS_SUCCESS; +} + +static ib_api_status_t +__port_was_hibernated( + IN ib_pnp_port_rec_t* p_pnp_rec, + IN bus_filter_t* p_bfi ) +{ + ib_api_status_t status; + cl_list_item_t *p_list_item; + bus_port_ext_t *p_port_ext; + bus_pdo_ext_t *p_shadow_pdo_ext, *p_pdo_ext = NULL; + size_t n_devs = 0; + port_mgr_t *p_port_mgr = p_bfi->p_port_mgr; + cl_qlist_t *p_pdo_list = &p_port_mgr->port_list; + port_pnp_ctx_t *p_ctx = p_pnp_rec->pnp_rec.context; + + BUS_ENTER( BUS_DBG_PNP ); + + if ( !p_port_mgr ) { + // if free_port_mgr has been called , p_bfi->p_port_mgr == NULL + // this will cause crash on cl_mutex_acquire + // (leo) i'm not sure when it happens, but i saw it happened + status = IB_NOT_FOUND; + goto end; + } + + cl_mutex_acquire( &p_port_mgr->pdo_mutex ); + + /* Count the number of child devices. */ + for( p_list_item = cl_qlist_head( p_pdo_list ); + p_list_item != cl_qlist_end( p_pdo_list ); + p_list_item = cl_qlist_next( p_list_item ) ) + { + p_pdo_ext = PARENT_STRUCT( p_list_item, bus_pdo_ext_t, list_item ); + p_port_ext = (bus_port_ext_t*)p_pdo_ext; + + if( p_pdo_ext->b_present && p_pdo_ext->b_hibernating && p_pdo_ext->hca_acquired && + (p_port_ext->port_guid.guid == p_pnp_rec->p_port_attr->port_guid) ) + { + n_devs++; + break; + } + + BUS_TRACE( BUS_DBG_PNP, ("%s Skipped acquire hca on PDO for %s: PDO %p, ext %p, " + "present %d, missing %d, hibernating %d, port_guid %I64x.\n", + p_bfi->whoami, + p_pdo_ext->cl_ext.vfptr_pnp_po->identity, + p_pdo_ext->cl_ext.p_self_do, + p_pdo_ext, p_pdo_ext->b_present, p_pdo_ext->b_reported_missing, + p_pdo_ext->b_hibernating, p_port_ext->port_guid.guid ) ); + } + + if (n_devs) + { + /* Take a reference on the parent HCA. */ + p_pdo_ext->h_ca = acquire_ca( p_pnp_rec->p_ca_attr->ca_guid ); + if( !p_pdo_ext->h_ca ) + { + BUS_TRACE( BUS_DBG_ERROR, + ("%s acquire_ca failed to find CA by guid %I64x\n", + p_bfi->whoami, p_pnp_rec->p_ca_attr->ca_guid ) ); + status = IB_INVALID_GUID; + } + else + { + p_pdo_ext->b_hibernating = FALSE; + + CL_ASSERT( p_ctx ); + p_ctx->p_pdo_ext = p_pdo_ext; // save for port_mgr_port_remove + + status = IB_SUCCESS; + p_port_ext = (bus_port_ext_t*)p_pdo_ext; + BUS_TRACE( BUS_DBG_PNP, ("%s Found PDO for %s: PDO %p, ext %p, " + "present %d, missing %d, hibernating %d, port_guid %I64x.\n", + p_bfi->whoami, + p_pdo_ext->cl_ext.vfptr_pnp_po->identity, + p_pdo_ext->cl_ext.p_self_do, + p_pdo_ext, p_pdo_ext->b_present, p_pdo_ext->b_reported_missing, + p_pdo_ext->b_hibernating, p_port_ext->port_guid.guid ) ); + + for( p_list_item = cl_qlist_head( p_pdo_list ); + p_list_item != cl_qlist_end( p_pdo_list ); + p_list_item = cl_qlist_next( p_list_item ) ) + { + p_shadow_pdo_ext = PARENT_STRUCT( p_list_item, bus_pdo_ext_t, list_item ); + p_port_ext = (bus_port_ext_t*)p_shadow_pdo_ext; + + if( p_shadow_pdo_ext->b_present && p_shadow_pdo_ext->b_hibernating && + (p_port_ext->port_guid.guid == p_pnp_rec->p_port_attr->port_guid) ) + { + p_shadow_pdo_ext->b_hibernating = FALSE; + p_shadow_pdo_ext->h_ca = p_pdo_ext->h_ca; + + + BUS_TRACE( BUS_DBG_PNP, ("%s set shadow h_ca PDO for %s: PDO %p, ext %p, " + "present %d, missing %d, hibernating %d, port_guid %I64x.\n", + p_bfi->whoami, + p_shadow_pdo_ext->cl_ext.vfptr_pnp_po->identity, + p_shadow_pdo_ext->cl_ext.p_self_do, + p_shadow_pdo_ext, p_shadow_pdo_ext->b_present, p_shadow_pdo_ext->b_reported_missing, + p_shadow_pdo_ext->b_hibernating, p_port_ext->port_guid.guid ) ); + } + } + + } + } + else + { + BUS_TRACE( BUS_DBG_PNP, ("%s Failed to find PDO for guid %I64x .\n", + p_bfi->whoami, p_pnp_rec->p_ca_attr->ca_guid ) ); + status = IB_NOT_FOUND; + } + + cl_mutex_release( &p_port_mgr->pdo_mutex ); + +end: + BUS_EXIT( BUS_DBG_PNP ); + return status; +} + +#if DBG + +void +dump_pnp_port_rec( ib_pnp_port_rec_t* pr ) +{ + BUS_TRACE( BUS_DBG_PNP, ("ib_pnp_port_rec_t* @ %p\nib_pnp_rec_t*:\n", pr)); + + + BUS_PRINT( BUS_DBG_PNP, (" Event %s\n", + ib_get_pnp_event_str(pr->pnp_rec.pnp_event) )); + + BUS_PRINT( BUS_DBG_PNP, (" pnp_context %p\n",pr->pnp_rec.pnp_context)); + BUS_PRINT( BUS_DBG_PNP, (" context %p\n",pr->pnp_rec.context)); + BUS_PRINT( BUS_DBG_PNP, (" guid %I64x\n",pr->pnp_rec.guid)); + BUS_PRINT( BUS_DBG_PNP, (" ca_guid %I64x\n",pr->pnp_rec.ca_guid)); + + if ( !pr->p_ca_attr ) { + BUS_PRINT( BUS_DBG_PNP, (" NULL *p_ca_attr ?\n")); + } + else { + BUS_PRINT( BUS_DBG_PNP, ("*p_ca_attr\n")); + BUS_PRINT( BUS_DBG_PNP, (" ca_guid 0x%I64x\n", + pr->p_ca_attr->ca_guid ) ); + } + if ( !pr->p_port_attr ) { + BUS_PRINT( BUS_DBG_PNP, (" NULL *p_port_attr?\n")); + } + else { + BUS_PRINT( BUS_DBG_PNP, ("*p_port_attr:\n")); + BUS_PRINT( BUS_DBG_PNP, (" port_guid 0x%I64x port_num %d\n", + pr->p_port_attr->port_guid, + pr->p_port_attr->port_num )); + } +} + +void +dump_pnp_iou_rec( ib_pnp_iou_rec_t* pr ) +{ + BUS_TRACE( BUS_DBG_PNP, ("ib_pnp_iou_rec_t* @ %p\nib_pnp_rec_t*:\n", pr)); + + + BUS_PRINT( BUS_DBG_PNP, (" Event %s\n", + ib_get_pnp_event_str(pr->pnp_rec.pnp_event) )); + + BUS_PRINT( BUS_DBG_PNP, (" pnp_context %p\n",pr->pnp_rec.pnp_context)); + BUS_PRINT( BUS_DBG_PNP, (" context %p\n",pr->pnp_rec.context)); + BUS_PRINT( BUS_DBG_PNP, (" guid %I64x\n",pr->pnp_rec.guid)); + BUS_PRINT( BUS_DBG_PNP, (" ca_guid %I64x\n",pr->pnp_rec.ca_guid)); + + BUS_PRINT( BUS_DBG_PNP, ("pnp_iou_rec_t:\n" )); + BUS_PRINT( BUS_DBG_PNP, + (" guid 0x%I64x\n ca_guid %I64x\n chassis_guid %I64x\n", + pr->guid, pr->ca_guid, pr->chassis_guid )); + BUS_PRINT( BUS_DBG_PNP, + (" slot 0x%x\n vend_id 0x%x\n dev_id 0x%x revision 0x%x\n", + pr->slot, pr->vend_id, pr->dev_id, pr->revision )); + if ( pr->desc[0] ) { + BUS_PRINT( BUS_DBG_PNP, (" Desc %s\n",pr->desc )); + } +} +#endif + + +ib_api_status_t +port_mgr_port_add( + IN ib_pnp_port_rec_t* p_pnp_rec ) +{ + NTSTATUS status; + DEVICE_OBJECT *p_pdo; + bus_port_ext_t *p_port_ext; + bus_filter_t *p_bfi; + port_mgr_t *p_port_mgr; + port_pnp_ctx_t *p_ctx = p_pnp_rec->pnp_rec.context; + child_device_info_list_t *pCurList; + ib_ca_handle_t h_ca = NULL; + ULONG pKey; + UNICODE_STRING uniKey; + + + BUS_ENTER( BUS_DBG_PNP ); + + CL_ASSERT( p_pnp_rec->p_ca_attr->ca_guid ); + + p_bfi = get_bfi_by_ca_guid( p_pnp_rec->p_ca_attr->ca_guid ); + if ( !p_bfi ) { + BUS_TRACE_EXIT( BUS_DBG_PNP,("NULL p_bfi? ca_guid 0x%I64x\n", + p_pnp_rec->p_ca_attr->ca_guid ) ); + return IB_ERROR; + } + + /* + * Allocate a PNP context for this object. pnp_rec.context is obj unique. + */ + if ( !p_ctx ) { + p_ctx = cl_zalloc( sizeof(*p_ctx) ); + if( !p_ctx ) + { + BUS_TRACE_EXIT(BUS_DBG_PNP, + ("%s ca_guid %I64x port(%d) BAD alloc PNP context\n", + p_bfi->whoami, p_bfi->ca_guid, + p_pnp_rec->p_port_attr->port_num)); + return IB_ERROR; + } + p_ctx->p_bus_filter = p_bfi; + p_ctx->port_num = p_pnp_rec->p_port_attr->port_num; + p_pnp_rec->pnp_rec.context = p_ctx; + + BUS_PRINT(BUS_DBG_PNP, + ("%s ca_guid %I64x port %d ALLOC p_ctx @ %p\n", + p_bfi->whoami, p_bfi->ca_guid, + p_pnp_rec->p_port_attr->port_num,p_ctx)); + } + + p_port_mgr = p_bfi->p_port_mgr; + + if( !bus_globals.b_report_port_nic ) + { + BUS_EXIT( BUS_DBG_PNP ); + return IB_NOT_DONE; + } + + /* Upon hibernating the computer IB_BUS driver doesn't remove PDO, but + marks with a flag. So we first try to find an existing PDO for this port, + marked with this flag. If it was found, we turn off the flag and use + this PDO */ + status = __port_was_hibernated( p_pnp_rec, p_bfi ); + if( status != IB_NOT_FOUND ) + { + BUS_EXIT( BUS_DBG_PNP ); + return status; + } + + pCurList = bus_globals.p_device_list; + + while(pCurList) + { + /* Create the PDO for the new port device. */ + status = IoCreateDevice( bus_globals.p_driver_obj, + sizeof(bus_port_ext_t), + NULL, FILE_DEVICE_CONTROLLER, + FILE_DEVICE_SECURE_OPEN | + FILE_AUTOGENERATED_DEVICE_NAME, + FALSE, &p_pdo ); + if( !NT_SUCCESS( status ) ) + { + BUS_TRACE_EXIT( BUS_DBG_ERROR, + ("IoCreateDevice returned %08x.\n", status) ); + return IB_ERROR; + } + + /* clean the extension (must be before initializing) */ + p_port_ext = p_pdo->DeviceExtension; + memset( p_port_ext, 0, sizeof(bus_port_ext_t) ); + + /* Initialize the device extension. */ + cl_init_pnp_po_ext( p_pdo, NULL, p_pdo, + bus_globals.dbg_lvl, &vfptr_port_pnp, + &vfptr_port_query_txt ); + + /* Set the DO_BUS_ENUMERATED_DEVICE flag to mark it as a PDO. */ + p_pdo->Flags |= DO_BUS_ENUMERATED_DEVICE; + + p_port_ext->pdo.dev_po_state.DeviceState = PowerDeviceD0; + p_port_ext->pdo.p_parent_ext = p_bfi->p_bus_ext; + p_port_ext->pdo.b_present = TRUE; + p_port_ext->pdo.b_reported_missing = FALSE; + p_port_ext->pdo.b_hibernating = FALSE; + p_port_ext->pdo.p_po_work_item = NULL; + p_port_ext->pdo.p_pdo_device_info = &pCurList->io_device_info; + BUS_TRACE( BUS_DBG_PNP, + ("Created %s %s: PDO %p,ext %p, present %d, missing %d .\n", + p_bfi->whoami, + p_port_ext->pdo.cl_ext.vfptr_pnp_po->identity, p_pdo, + p_port_ext, p_port_ext->pdo.b_present, + p_port_ext->pdo.b_reported_missing ) ); + + /* Cache the CA GUID. */ + p_port_ext->pdo.ca_guid = p_pnp_rec->p_ca_attr->ca_guid; + + /*Only acquire one hca for each port*/ + if(h_ca) + { + p_port_ext->pdo.h_ca = h_ca; + p_port_ext->pdo.hca_acquired = FALSE; + }else + { + /* Acquire CA for the first child pdo*/ + h_ca = p_port_ext->pdo.h_ca = acquire_ca( p_pnp_rec->p_ca_attr->ca_guid ); + p_port_ext->pdo.hca_acquired = TRUE; + } + + if( !p_port_ext->pdo.h_ca ) + { + BUS_TRACE( BUS_DBG_PNP, ("Deleted device: PDO %p\n", p_pdo)); + IoDeleteDevice( p_pdo); + BUS_TRACE_EXIT( BUS_DBG_ERROR, ("acquire_ca failed to find CA.\n") ); + return IB_INVALID_GUID; + } + + p_port_ext->port_guid.guid = p_pnp_rec->p_port_attr->port_guid; + p_port_ext->n_port = p_pnp_rec->p_port_attr->port_num; + + RtlInitUnicodeString(&uniKey, pCurList->io_device_info.pkey); + RtlUnicodeStringToInteger(&uniKey,16,&pKey); + p_port_ext->port_guid.pkey = (ib_net16_t)pKey; + + p_port_ext->n_ifc_ref = 0; + + + /* Store the device extension in the port vector for future queries. */ + cl_mutex_acquire( &p_port_mgr->pdo_mutex ); + cl_qlist_insert_tail( &p_port_mgr->port_list, + &p_port_ext->pdo.list_item ); + cl_mutex_release( &p_port_mgr->pdo_mutex ); + + /* + * Set the context of the PNP event. The context is passed in for future + * events on the same port. + */ + if(p_port_ext->pdo.hca_acquired) + { + p_ctx->p_pdo_ext = p_port_ext; + } + + pCurList = pCurList->next_device_info; + + /* Tell the PnP Manager to rescan for the HCA's bus relations. */ + IoInvalidateDeviceRelations( + p_port_ext->pdo.h_ca->p_hca_dev, BusRelations ); + } + + /* Invalidate removal relations for the bus driver. */ + IoInvalidateDeviceRelations( + p_bfi->p_bus_ext->cl_ext.p_pdo, RemovalRelations ); + + BUS_EXIT( BUS_DBG_PNP ); + return IB_SUCCESS; +} + + + +/************************************************************************************ +* name : port_mgr_pkey_rem +* removes pdo for each pkey value in pkey_array +* input : g_pkeys +* output: none +* return: cl_status +*************************************************************************************/ +cl_status_t _port_mgr_pkey_rem( IN pkey_array_t *pkeys, + IN port_mgr_t *p_port_mgr ) +{ + + uint16_t cnt; + cl_list_item_t *p_list_item; + bus_port_ext_t *p_port_ext; + bus_pdo_ext_t *p_pdo_ext = NULL; + cl_qlist_t* p_pdo_list = &p_port_mgr->port_list; + + BUS_ENTER( BUS_DBG_PNP ); + + p_port_ext = NULL; + cl_mutex_acquire( &p_port_mgr->pdo_mutex ); + + /* Count the number of child devices. */ + for( p_list_item = cl_qlist_head( p_pdo_list ); + p_list_item != cl_qlist_end( p_pdo_list ); + p_list_item = cl_qlist_next( p_list_item ) ) + { + p_pdo_ext = PARENT_STRUCT( p_list_item, bus_pdo_ext_t, list_item ); + p_port_ext = (bus_port_ext_t*)p_pdo_ext; + + if(p_port_ext->port_guid.guid == pkeys->port_guid) + { + for(cnt = 0; cnt < pkeys->pkey_num; cnt++) + { + if( (p_port_ext->port_guid.pkey == pkeys->pkey_array[cnt]) && + (p_port_ext->port_guid.pkey != IB_DEFAULT_PKEY)) + { + p_port_ext->pdo.b_present = FALSE; + break; + } + } + } + } + cl_mutex_release( &p_port_mgr->pdo_mutex ); + + /* Tell the PnP Manager to rescan for the HCA's bus relations. */ + IoInvalidateDeviceRelations( + p_port_ext->pdo.h_ca->p_hca_dev, BusRelations ); + + BUS_EXIT( BUS_DBG_PNP ); + return CL_SUCCESS; +} + + +cl_status_t port_mgr_pkey_rem( IN pkey_array_t *pkeys ) +{ + bus_filter_t *p_bfi; + cl_status_t status; + boolean_t GO; + int success_cnt=0; + + for(p_bfi=&g_bus_filters[0]; p_bfi < &g_bus_filters[MAX_BUS_FILTERS]; p_bfi++) + { + if ( !p_bfi->p_bus_ext ) + continue; + GO = FALSE; + lock_control_event(); + if ( p_bfi->ca_guid && p_bfi->p_port_mgr ) + GO = TRUE; + unlock_control_event(); + if ( GO == FALSE ) + continue; + status = _port_mgr_pkey_rem( pkeys, p_bfi->p_port_mgr ); + if ( status == CL_SUCCESS ) + success_cnt++; + } + return ( success_cnt ? CL_SUCCESS : CL_ERROR ); +} + +extern child_device_info_t g_default_device_info; + +/************************************************************************************ +* name : port_mgr_pkey_add +* creates pdo for each pkey value in pkey_array +* input : g_pkeys +* output: none +* return: cl_status +*************************************************************************************/ +cl_status_t _port_mgr_pkey_add( IN pkey_array_t *req_pkeys, + IN bus_filter_t *p_bfi, + IN port_mgr_t *p_port_mgr ) +{ + uint16_t cnt; + NTSTATUS status; + cl_list_item_t *p_list_item; + bus_port_ext_t *p_port_ext, *pkey_port_ext, *pmatched_guid_ext; + DEVICE_OBJECT *p_pdo[MAX_NUM_PKEY]; + cl_qlist_t* p_pdo_list = &p_port_mgr->port_list; + + BUS_ENTER( BUS_DBG_PNP ); + + pmatched_guid_ext = NULL; + p_port_ext = NULL; + cl_mutex_acquire( &p_port_mgr->pdo_mutex ); + + /* Count the number of child devices. */ + for( p_list_item = cl_qlist_head( p_pdo_list ); + p_list_item != cl_qlist_end( p_pdo_list ); + p_list_item = cl_qlist_next( p_list_item ) ) + { + p_port_ext = (bus_port_ext_t*)PARENT_STRUCT( p_list_item, bus_pdo_ext_t, list_item ); + + if(p_port_ext->port_guid.guid == req_pkeys->port_guid) + { + uint16_t i; + for(i = 0; i < req_pkeys->pkey_num; i++) + { + if(p_port_ext->port_guid.pkey == req_pkeys->pkey_array[i]) + { + /* was removed previously */ + p_port_ext->pdo.b_present = TRUE; + p_port_ext->pdo.b_reported_missing = FALSE; + req_pkeys->pkey_array[i] = 0; + } + } + if(!pmatched_guid_ext) + pmatched_guid_ext = p_port_ext; + } + } + cl_mutex_release( &p_port_mgr->pdo_mutex ); + + if (!pmatched_guid_ext) + { + BUS_TRACE_EXIT( BUS_DBG_ERROR, + ("No existed pdo found.\n") ); + return CL_NOT_FOUND; + } + + for (cnt = 0; cnt < req_pkeys->pkey_num; cnt++) + { + if(! (cl_hton16(req_pkeys->pkey_array[cnt]) & IB_PKEY_BASE_MASK) ) + continue; + + /* Create the PDO for the new port device. */ + status = IoCreateDevice( bus_globals.p_driver_obj, sizeof(bus_port_ext_t), + NULL, FILE_DEVICE_CONTROLLER, + FILE_DEVICE_SECURE_OPEN | FILE_AUTOGENERATED_DEVICE_NAME, + FALSE, &p_pdo[cnt] ); + if( !NT_SUCCESS( status ) ) + { + BUS_TRACE_EXIT( BUS_DBG_ERROR, + ("IoCreateDevice returned %08x.\n", status) ); + return CL_ERROR; + } + + /* Initialize the device extension. */ + cl_init_pnp_po_ext( p_pdo[cnt], NULL, p_pdo[cnt], bus_globals.dbg_lvl, + &vfptr_port_pnp, &vfptr_port_query_txt ); + + /* Set the DO_BUS_ENUMERATED_DEVICE flag to mark it as a PDO. */ + p_pdo[cnt]->Flags |= DO_BUS_ENUMERATED_DEVICE; + + pkey_port_ext = p_pdo[cnt]->DeviceExtension; + pkey_port_ext->pdo.dev_po_state.DeviceState = PowerDeviceD0; + pkey_port_ext->pdo.p_parent_ext = p_bfi->p_bus_ext; + pkey_port_ext->pdo.b_present = TRUE; + pkey_port_ext->pdo.b_reported_missing = FALSE; + pkey_port_ext->pdo.b_hibernating = FALSE; + pkey_port_ext->pdo.p_po_work_item = NULL; + pkey_port_ext->pdo.p_pdo_device_info = &g_default_device_info; + BUS_TRACE( BUS_DBG_PNP, ("Created device for %s: PDO %p,ext %p, present %d, missing %d .\n", + pkey_port_ext->pdo.cl_ext.vfptr_pnp_po->identity, p_pdo[cnt], pkey_port_ext, pkey_port_ext->pdo.b_present, + pkey_port_ext->pdo.b_reported_missing ) ); + + /* Cache the CA GUID. */ + pkey_port_ext->pdo.ca_guid = pmatched_guid_ext->pdo.ca_guid; + pkey_port_ext->pdo.h_ca = pmatched_guid_ext->pdo.h_ca; + pkey_port_ext->port_guid.guid = pmatched_guid_ext->port_guid.guid; + pkey_port_ext->n_port = pmatched_guid_ext->n_port; + pkey_port_ext->port_guid.pkey = req_pkeys->pkey_array[cnt]; + /* Store the device extension in the port vector for future queries. */ + cl_mutex_acquire( &p_port_mgr->pdo_mutex ); + cl_qlist_insert_tail( &p_port_mgr->port_list, + &pkey_port_ext->pdo.list_item ); + cl_mutex_release( &p_port_mgr->pdo_mutex ); + } + + /* Tell the PnP Manager to rescan for the HCA's bus relations. */ + IoInvalidateDeviceRelations( + pmatched_guid_ext->pdo.h_ca->p_hca_dev, BusRelations ); + + /* Invalidate removal relations for the bus driver. */ + IoInvalidateDeviceRelations( + p_bfi->p_bus_ext->cl_ext.p_pdo, RemovalRelations ); + + BUS_EXIT( BUS_DBG_PNP ); + return CL_SUCCESS; +} + +cl_status_t port_mgr_pkey_add(pkey_array_t *pkeys) +{ + bus_filter_t *p_bfi; + cl_status_t status; + boolean_t GO; + int success_cnt=0; + + for(p_bfi=&g_bus_filters[0]; p_bfi < &g_bus_filters[MAX_BUS_FILTERS]; p_bfi++) + { + if ( !p_bfi->p_bus_ext ) + continue; + GO = FALSE; + lock_control_event(); + if ( p_bfi->ca_guid && p_bfi->p_port_mgr ) + GO = TRUE; + unlock_control_event(); + if ( GO == FALSE ) + continue; + status = _port_mgr_pkey_add( pkeys, p_bfi, p_bfi->p_port_mgr ); + if ( status == CL_SUCCESS ) + success_cnt++; + } + return ( success_cnt ? CL_SUCCESS : CL_ERROR ); +} + + +void +port_mgr_port_remove( + IN ib_pnp_port_rec_t* p_pnp_rec ) +{ + bus_pdo_ext_t *p_ext; + port_mgr_t *p_port_mgr; + bus_filter_t *p_bfi; + port_pnp_ctx_t *p_ctx = p_pnp_rec->pnp_rec.context; + cl_list_item_t *p_list_item; + bus_port_ext_t *p_port_ext; + bus_pdo_ext_t *p_pdo_ext; + cl_qlist_t* p_pdo_list; + + BUS_ENTER( BUS_DBG_PNP ); + + if ( !p_ctx ) { + BUS_EXIT( BUS_DBG_PNP ); + return; + } + + CL_ASSERT( p_ctx->p_bus_filter->magic == BFI_MAGIC ); + p_bfi = p_ctx->p_bus_filter; + CL_ASSERT( p_bfi ); + + BUS_PRINT(BUS_DBG_PNP,("%s ca_guid 0x%I64x port_num %d port_mgr %p\n", + p_bfi->whoami, p_bfi->ca_guid, + p_ctx->port_num, p_bfi->p_port_mgr)); + + /* in the process of device remove, port_mgr has been destroyed. + * cleanup allocated PNP port context; one per port. + * The issue is the PNP PORT_REMOVE event occurs after + * fdo_release_resources() completes. + */ + if ( p_bfi->ca_guid == 0ULL || !p_bfi->p_port_mgr ) { + cl_free( p_ctx ); + p_pnp_rec->pnp_rec.context = NULL; + BUS_EXIT( BUS_DBG_PNP ); + return; + } + + p_port_mgr = p_bfi->p_port_mgr; + + /* Within the PNP record's context is the port extension ptr; + * see port_was_hibernated(). + */ + p_ext = p_ctx->p_pdo_ext; + CL_ASSERT( p_ext ); + + /* + * Flag the port PDO as no longer being present. We have to wait until + * the PnP manager removes it to clean up. However, we do release the + * reference on the CA object in order to allow the removal of the HCA + * to proceed should it occur before the port's PDO is cleaned up. + */ + if ( !p_ext->h_ca ) + { + BUS_TRACE_EXIT( BUS_DBG_PNP, + ("%s NULL h_ca? p_ext %p\n", p_bfi->whoami, p_ext ) ); + return; + } + + // Don't crash if p_ext->p_parent_ext is NULL + CL_ASSERT((p_ext->p_parent_ext == NULL) || p_bfi == p_ext->p_parent_ext->bus_filter); + + cl_mutex_acquire( &p_port_mgr->pdo_mutex ); + CL_ASSERT( p_ext->h_ca ); + + if( p_ext->b_hibernating ) + { + BUS_TRACE( BUS_DBG_PNP, ("Skip port removing for %s: PDO %p, ext %p, " + "present %d, missing %d, hibernating %d .\n", + p_ext->cl_ext.vfptr_pnp_po->identity, p_ext->cl_ext.p_self_do, + p_ext, p_ext->b_present, p_ext->b_reported_missing, + p_ext->b_hibernating ) ); + goto hca_deref; + } + + p_ext->b_present = FALSE; + + p_pdo_list = &p_port_mgr->port_list; + + for( p_list_item = cl_qlist_head( p_pdo_list ); + p_list_item != cl_qlist_end( p_pdo_list ); + p_list_item = cl_qlist_next( p_list_item ) ) + { + p_pdo_ext = PARENT_STRUCT( p_list_item, bus_pdo_ext_t, list_item ); + p_port_ext = (bus_port_ext_t*) p_pdo_ext; + + if( (p_port_ext->port_guid.guid == ((bus_port_ext_t*)p_ext)->port_guid.guid) ) + { + p_pdo_ext->b_present = FALSE; + } + } + + BUS_TRACE( BUS_DBG_PNP, + ("Mark removing %s: PDO %p, ext %p, present %d, missing %d .\n", + p_ext->cl_ext.vfptr_pnp_po->identity, p_ext->cl_ext.p_self_do, p_ext, + p_ext->b_present, p_ext->b_reported_missing ) ); + + /* Invalidate removal relations for the bus driver. */ + IoInvalidateDeviceRelations( + p_bfi->p_bus_ext->cl_ext.p_pdo, RemovalRelations ); + + /* Invalidate bus relations for the HCA. */ + IoInvalidateDeviceRelations( + p_ext->h_ca->p_hca_dev, BusRelations ); + +hca_deref: + /* Free PNP context memory */ + cl_free( p_ctx ); + p_pnp_rec->pnp_rec.context = NULL; + + deref_al_obj( &p_ext->h_ca->obj ); + + /* Setting h_ca to be NULL forces IPoIB to start only after re-acquiring + * new CA object. The latter happens in __port_was_hibernated or + * port_mgr_port_add functions after arriving IB_PNP_PORT_ADD event + * from IBAL. + */ + p_ext->h_ca = NULL; + + p_pdo_list = &p_port_mgr->port_list; + + for( p_list_item = cl_qlist_head( p_pdo_list ); + p_list_item != cl_qlist_end( p_pdo_list ); + p_list_item = cl_qlist_next( p_list_item ) ) + { + p_pdo_ext = PARENT_STRUCT( p_list_item, bus_pdo_ext_t, list_item ); + p_port_ext = (bus_port_ext_t*) p_pdo_ext; + + if( p_port_ext->port_guid.guid == ((bus_port_ext_t*)p_ext)->port_guid.guid ) + { + p_pdo_ext->h_ca = NULL; + } + } + + cl_mutex_release( &p_port_mgr->pdo_mutex ); + + BUS_EXIT( BUS_DBG_PNP ); +} + + +static NTSTATUS +port_start( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + bus_pdo_ext_t *p_ext; + + BUS_ENTER( BUS_DBG_PNP ); + + UNUSED_PARAM( p_irp ); + + p_ext = p_dev_obj->DeviceExtension; + + /* Notify the Power Manager that the device is started. */ + PoSetPowerState( p_dev_obj, DevicePowerState, p_ext->dev_po_state ); + *p_action = IrpComplete; + BUS_EXIT( BUS_DBG_PNP ); + + return STATUS_SUCCESS; +} + + +static NTSTATUS +port_query_remove( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + bus_port_ext_t *p_ext; + + BUS_ENTER( BUS_DBG_PNP ); + + UNUSED_PARAM( p_irp ); + + p_ext = p_dev_obj->DeviceExtension; + + *p_action = IrpComplete; + + if( p_ext->n_ifc_ref ) + { + /* + * Our interface is still being held by someone. + * Rollback the PnP state that was changed in the complib handler. + */ + cl_rollback_pnp_state( &p_ext->pdo.cl_ext ); + + /* Fail the query. */ + BUS_TRACE_EXIT( BUS_DBG_PNP, ("Failing IRP_MN_QUERY_REMOVE_DEVICE:\n" + "\tInterface has %d reference\n", p_ext->n_ifc_ref ) ); + return STATUS_UNSUCCESSFUL; + } + + CL_ASSERT(p_ext->pdo.p_parent_ext->bus_filter); + BUS_TRACE_EXIT( BUS_DBG_PNP, + ("OK IRP_MN_QUERY_REMOVE_DEVICE:\n %s HCA guid %I64x port %d\n", + p_ext->pdo.p_parent_ext->bus_filter->whoami, + p_ext->pdo.ca_guid, p_ext->n_port ) ); + + return STATUS_SUCCESS; +} + + +static void +port_release_resources( + IN DEVICE_OBJECT* const p_dev_obj ) +{ + bus_port_ext_t *p_ext; + POWER_STATE po_state; + port_mgr_t *p_port_mgr; + + BUS_ENTER( BUS_DBG_PNP ); + + p_ext = p_dev_obj->DeviceExtension; + p_port_mgr = p_ext->pdo.p_parent_ext->bus_filter->p_port_mgr; + + /* skip releasing resources if PDO has not been yet reported missing */ + if (!p_ext->pdo.b_reported_missing) { + BUS_TRACE_EXIT( BUS_DBG_PNP, ("PDO is not yet reported missing - skip the removing port from vector: PDO %p, ext %p\n", + p_dev_obj, p_ext) ); + return; + } + + /* Remove this PDO from its list. */ + cl_mutex_acquire( &p_port_mgr->pdo_mutex ); + BUS_TRACE( BUS_DBG_PNP, ("Removing port from vector: PDO %p, ext %p\n", + p_dev_obj, p_ext) ); + cl_qlist_remove_item( &p_port_mgr->port_list, &p_ext->pdo.list_item ); + cl_mutex_release( &p_port_mgr->pdo_mutex ); + po_state.DeviceState = PowerDeviceD3; + PoSetPowerState( p_ext->pdo.cl_ext.p_pdo, DevicePowerState, po_state ); + + BUS_EXIT( BUS_DBG_PNP ); +} + + +static NTSTATUS +port_remove( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + bus_port_ext_t *p_ext; + + BUS_ENTER( BUS_DBG_PNP ); + + p_ext = p_dev_obj->DeviceExtension; + + if( p_ext->pdo.b_present ) + { + CL_ASSERT( p_ext->pdo.cl_ext.pnp_state != NotStarted ); + CL_ASSERT( !p_ext->pdo.b_reported_missing ); + /* Reset the state to NotStarted. CompLib set it to Deleted. */ + cl_set_pnp_state( &p_ext->pdo.cl_ext, NotStarted ); + /* Don't delete the device. It may simply be disabled. */ + *p_action = IrpComplete; + BUS_TRACE_EXIT( BUS_DBG_PNP, + ("Device %s still present: PDO %p, ext %p\n", + p_ext->pdo.cl_ext.vfptr_pnp_po->identity, p_dev_obj, p_ext) ); + return STATUS_SUCCESS; + } + + if( !p_ext->pdo.b_reported_missing ) + { + /* Reset the state to RemovePending. Complib set it to Deleted. */ + cl_rollback_pnp_state( &p_ext->pdo.cl_ext ); + *p_action = IrpComplete; + BUS_TRACE_EXIT( BUS_DBG_PNP, + ("Device %s not reported missing yet: PDO %p, ext %p\n", + p_ext->pdo.cl_ext.vfptr_pnp_po->identity, + p_dev_obj, p_ext) ); + return STATUS_SUCCESS; + } + + /* Wait for all I/O operations to complete. */ + IoReleaseRemoveLockAndWait( &p_ext->pdo.cl_ext.remove_lock, p_irp ); + + /* Release resources if it was not done yet. */ + if( p_ext->pdo.cl_ext.last_pnp_state != SurpriseRemoved ) + p_ext->pdo.cl_ext.vfptr_pnp_po->pfn_release_resources( p_dev_obj ); + + p_irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest( p_irp, IO_NO_INCREMENT ); + + BUS_TRACE( BUS_DBG_PNP, ("Deleted device %s: PDO %p(=%p), ext %p\n", + p_ext->pdo.cl_ext.vfptr_pnp_po->identity, p_ext->pdo.cl_ext.p_self_do, + p_dev_obj, p_ext ) ); + + IoDeleteDevice( p_dev_obj ); + + *p_action = IrpDoNothing; + BUS_EXIT( BUS_DBG_PNP ); + return STATUS_SUCCESS; +} + + +static NTSTATUS +port_surprise_remove( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + bus_port_ext_t *p_ext; + + BUS_ENTER( BUS_DBG_PNP ); + + UNUSED_PARAM( p_irp ); + + p_ext = p_dev_obj->DeviceExtension; + // + // Setting 2 following flags seems like the right behaviour + // according to DDK, but it causes + // WHQL PnP SurpriseRemoval test to fail + // So, as a work around, they are disabled for now. + // The best solution is to rewrite all the drivers + // to WDF model, hoping it will handle right all PnP/Power issues + // +// p_ext->pdo.b_present = FALSE; +// p_ext->pdo.b_reported_missing = TRUE; + if (!p_ext->pdo.b_reported_missing) { + // we have not yet reported the device absence + cl_rollback_pnp_state( &p_ext->pdo.cl_ext ); + } + BUS_TRACE( BUS_DBG_PNP, ("%s: PDO %p, ext %p, present %d, missing %d .\n", + p_ext->pdo.cl_ext.vfptr_pnp_po->identity, p_ext->pdo.cl_ext.p_self_do, + p_ext, p_ext->pdo.b_present, p_ext->pdo.b_reported_missing ) ); + + *p_action = IrpComplete; + + BUS_EXIT( BUS_DBG_PNP ); + return STATUS_SUCCESS; +} + + +static NTSTATUS +port_query_capabilities( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + DEVICE_CAPABILITIES *p_caps; + IO_STACK_LOCATION *p_io_stack; + + BUS_ENTER( BUS_DBG_PNP ); + + UNUSED_PARAM( p_dev_obj ); + + p_io_stack = IoGetCurrentIrpStackLocation( p_irp ); + p_caps = p_io_stack->Parameters.DeviceCapabilities.Capabilities; + + p_caps->DeviceD1 = FALSE; + p_caps->DeviceD2 = FALSE; + p_caps->LockSupported = FALSE; + p_caps->EjectSupported = FALSE; + p_caps->Removable = FALSE; + p_caps->DockDevice = FALSE; + p_caps->UniqueID = TRUE; + p_caps->SilentInstall = TRUE; + p_caps->RawDeviceOK = FALSE; + p_caps->SurpriseRemovalOK = FALSE; + p_caps->WakeFromD0 = FALSE; + p_caps->WakeFromD1 = FALSE; + p_caps->WakeFromD2 = FALSE; + p_caps->WakeFromD3 = FALSE; + p_caps->HardwareDisabled = FALSE; + p_caps->DeviceState[PowerSystemWorking] = PowerDeviceD0; + p_caps->DeviceState[PowerSystemSleeping1] = PowerDeviceD3; + p_caps->DeviceState[PowerSystemSleeping2] = PowerDeviceD3; + p_caps->DeviceState[PowerSystemSleeping3] = PowerDeviceD3; + p_caps->DeviceState[PowerSystemHibernate] = PowerDeviceD3; + p_caps->DeviceState[PowerSystemShutdown] = PowerDeviceD3; + p_caps->SystemWake = PowerSystemUnspecified; + p_caps->DeviceWake = PowerDeviceUnspecified; + p_caps->D1Latency = 0; + p_caps->D2Latency = 0; + p_caps->D3Latency = 0; + + *p_action = IrpComplete; + BUS_EXIT( BUS_DBG_PNP ); + return STATUS_SUCCESS; +} + + +static NTSTATUS +port_query_target_relations( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + NTSTATUS status; + DEVICE_RELATIONS *p_rel; + + BUS_ENTER( BUS_DBG_PNP ); + + *p_action = IrpComplete; + + status = cl_alloc_relations( p_irp, 1 ); + if( !NT_SUCCESS( status ) ) + { + BUS_TRACE_EXIT( BUS_DBG_ERROR, + ("cl_alloc_relations returned 0x%08x.\n", status) ); + return status; + } + + p_rel = (DEVICE_RELATIONS*)p_irp->IoStatus.Information; + p_rel->Count = 1; + p_rel->Objects[0] = p_dev_obj; + + ObReferenceObject( p_dev_obj ); + + BUS_EXIT( BUS_DBG_PNP ); + return status; +} + + +static NTSTATUS +port_query_device_id( + IN DEVICE_OBJECT* const p_dev_obj, + OUT IRP* const p_irp ) +{ + WCHAR *p_string; + bus_port_ext_t *p_ext; + size_t dev_id_size; + + BUS_ENTER( BUS_DBG_PNP ); + + + p_ext = (bus_port_ext_t*)p_dev_obj->DeviceExtension; + if( !p_ext->pdo.b_present ) + { + BUS_TRACE_EXIT( BUS_DBG_ERROR, ("Device not present.\n") ); + return STATUS_NO_SUCH_DEVICE; + } + + dev_id_size = p_ext->pdo.p_pdo_device_info->device_id_size; + + /* Device ID is "IBA\SID_ where is the IO device Service ID. */ + p_string = ExAllocatePoolWithTag( NonPagedPool, dev_id_size, 'vedq' ); + if( !p_string ) + { + BUS_TRACE_EXIT( BUS_DBG_ERROR, + ("Failed to allocate device ID buffer (%d bytes).\n", + dev_id_size) ); + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlZeroMemory(p_string, dev_id_size); + + cl_memcpy( p_string, p_ext->pdo.p_pdo_device_info->device_id, dev_id_size ); + + p_irp->IoStatus.Information = (ULONG_PTR)p_string; + + BUS_EXIT( BUS_DBG_PNP ); + return STATUS_SUCCESS; +} + + +static NTSTATUS +port_query_hardware_ids( + IN DEVICE_OBJECT* const p_dev_obj, + OUT IRP* const p_irp ) +{ + WCHAR *p_string; + bus_port_ext_t *p_ext; + size_t dev_id_size; + + BUS_ENTER( BUS_DBG_PNP ); + + + p_ext = (bus_port_ext_t*)p_dev_obj->DeviceExtension; + + dev_id_size = p_ext->pdo.p_pdo_device_info->hardware_id_size; + + p_string = ExAllocatePoolWithTag( NonPagedPool, dev_id_size, 'ihqp' ); + if( !p_string ) + { + BUS_TRACE_EXIT( BUS_DBG_ERROR, + ("Failed to allocate hardware ID buffer (%d bytes).\n", + dev_id_size) ); + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlZeroMemory(p_string, dev_id_size); + + cl_memcpy( p_string, p_ext->pdo.p_pdo_device_info->hardware_id, dev_id_size ); + + p_irp->IoStatus.Information = (ULONG_PTR)p_string; + + BUS_EXIT( BUS_DBG_PNP ); + return STATUS_SUCCESS; +} + + +static NTSTATUS +port_query_compatible_ids( + IN DEVICE_OBJECT* const p_dev_obj, + OUT IRP* const p_irp ) +{ + WCHAR *p_string; + bus_port_ext_t *p_ext; + size_t dev_id_size; + + BUS_ENTER( BUS_DBG_PNP ); + + p_ext = (bus_port_ext_t*)p_dev_obj->DeviceExtension; + + dev_id_size = p_ext->pdo.p_pdo_device_info->compatible_id_size; + + p_string = ExAllocatePoolWithTag( NonPagedPool, dev_id_size, 'ihqp' ); + if( !p_string ) + { + BUS_TRACE_EXIT( BUS_DBG_ERROR, + ("Failed to allocate hardware ID buffer (%d bytes).\n", + dev_id_size) ); + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlZeroMemory(p_string, dev_id_size); + + cl_memcpy( p_string, p_ext->pdo.p_pdo_device_info->compatible_id, dev_id_size ); + + p_irp->IoStatus.Information = (ULONG_PTR)p_string; + + BUS_EXIT( BUS_DBG_PNP ); + return STATUS_SUCCESS; +} + + +static NTSTATUS +port_query_unique_id( + IN DEVICE_OBJECT* const p_dev_obj, + OUT IRP* const p_irp ) +{ + NTSTATUS status; + WCHAR *p_string; + bus_port_ext_t *p_ext; + + BUS_ENTER( BUS_DBG_PNP ); + + p_ext = p_dev_obj->DeviceExtension; + + if( !p_ext->pdo.b_present ) + { + BUS_TRACE_EXIT( BUS_DBG_ERROR, ("Device not present.\n") ); + return STATUS_NO_SUCH_DEVICE; + } + + /* The instance ID is the port GUID. */ + p_string = ExAllocatePoolWithTag( NonPagedPool, sizeof(WCHAR) * 21, 'iuqp' ); + if( !p_string ) + { + BUS_TRACE_EXIT( BUS_DBG_ERROR, + ("Failed to allocate instance ID buffer (%d bytes).\n", + sizeof(WCHAR) * 21) ); + return STATUS_NO_MEMORY; + } + + status = RtlStringCchPrintfW( p_string, 21, L"%016I64x%04x",p_ext->port_guid.guid,p_ext->port_guid.pkey ); + if( !NT_SUCCESS( status ) ) + { + CL_ASSERT( NT_SUCCESS( status ) ); + ExFreePool( p_string ); + BUS_TRACE_EXIT( BUS_DBG_ERROR, + ("RtlStringCchPrintfW returned %08x.\n", status) ); + return status; + } + + p_irp->IoStatus.Information = (ULONG_PTR)p_string; + + BUS_EXIT( BUS_DBG_PNP ); + return STATUS_SUCCESS; +} + + +static NTSTATUS +port_query_description( + IN DEVICE_OBJECT* const p_dev_obj, + OUT IRP* const p_irp ) +{ + WCHAR *p_string; + bus_port_ext_t *p_ext; + + BUS_ENTER( BUS_DBG_PNP ); + + p_ext = p_dev_obj->DeviceExtension; + if( !p_ext->pdo.b_present ) + { + BUS_TRACE_EXIT( BUS_DBG_ERROR, ("Device not present.\n") ); + return STATUS_NO_SUCH_DEVICE; + } + + + p_string = ExAllocatePoolWithTag( NonPagedPool, p_ext->pdo.p_pdo_device_info->description_size, 'edqp' ); + + if( !p_string ) + { + BUS_TRACE_EXIT( BUS_DBG_ERROR, + ("Failed to allocate device description buffer (%d bytes).\n", + p_ext->pdo.p_pdo_device_info->description_size) ); + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlZeroMemory(p_string,p_ext->pdo.p_pdo_device_info->description_size); + + cl_memcpy( p_string, p_ext->pdo.p_pdo_device_info->description, p_ext->pdo.p_pdo_device_info->description_size ); + + p_irp->IoStatus.Information = (ULONG_PTR)p_string; + + BUS_EXIT( BUS_DBG_PNP ); + return STATUS_SUCCESS; +} + + +static NTSTATUS +port_query_location( + IN DEVICE_OBJECT* const p_dev_obj, + OUT IRP* const p_irp ) +{ + WCHAR *p_string; + bus_port_ext_t *p_ext; + size_t size; + ULONG len; + NTSTATUS status; + DEVICE_OBJECT *p_hca_dev; + + BUS_ENTER( BUS_DBG_PNP ); + + p_ext = p_dev_obj->DeviceExtension; + if( !p_ext->pdo.b_present ) + { + BUS_TRACE_EXIT( BUS_DBG_ERROR, ("Device not present.\n") ); + return STATUS_NO_SUCH_DEVICE; + } + + if (!p_ext->pdo.h_ca) + { + BUS_TRACE_EXIT( BUS_DBG_ERROR, ("HCA is still or already not acquired !\n") ); + return STATUS_DEVICE_NOT_READY; + } + + p_hca_dev = p_ext->pdo.h_ca->p_hca_dev; + + /* Get the length of the HCA's location. */ + status = IoGetDeviceProperty( p_hca_dev, + DevicePropertyLocationInformation, 0, NULL, &len ); + if( status != STATUS_BUFFER_TOO_SMALL ) + { + BUS_TRACE_EXIT( BUS_DBG_ERROR, + ("IoGetDeviceProperty for device location size returned %08x.\n", + status) ); + return status; + } + + /* + * Allocate the string buffer to hold the HCA's location along with the + * port number. The port number is 32-bits, so in decimal it can be at + * most 10 characters. + */ + size = len + sizeof(L", port ") + (sizeof(WCHAR) * 10); + if( size > (USHORT)-1 ) + { + BUS_TRACE_EXIT( BUS_DBG_ERROR, + ("Length beyond limits.\n") ); + return STATUS_INSUFFICIENT_RESOURCES; + } + + p_string = ExAllocatePoolWithTag( NonPagedPool, size, 'olqp' ); + if( !p_string ) + { + BUS_TRACE_EXIT( BUS_DBG_ERROR, + ("Failed to allocate device location buffer (%d bytes).\n", len) ); + return STATUS_NO_MEMORY; + } + + /* Get the HCA's location information. */ + status = IoGetDeviceProperty( p_hca_dev, + DevicePropertyLocationInformation, len, p_string, &len ); + if( !NT_SUCCESS( status ) ) + { + ExFreePool( p_string ); + BUS_TRACE_EXIT( BUS_DBG_ERROR, + ("IoGetDeviceProperty for device location returned %08x.\n", + status) ); + return status; + } + + /* Append the port number to the HCA's location. */ + status = RtlStringCbPrintfW( p_string + (len/2) - 1, size - len + 1, + L", port %d", p_ext->n_port ); + if( !NT_SUCCESS( status ) ) + { + CL_ASSERT( NT_SUCCESS( status ) ); + ExFreePool( p_string ); + BUS_TRACE_EXIT( BUS_DBG_ERROR, + ("RtlStringCbPrintfW returned %08x.\n", status) ); + return status; + } + + p_irp->IoStatus.Information = (ULONG_PTR)p_string; + + BUS_EXIT( BUS_DBG_PNP ); + return STATUS_SUCCESS; +} + + +static NTSTATUS +port_query_bus_info( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + PNP_BUS_INFORMATION *p_bus_info; + + BUS_ENTER( BUS_DBG_PNP ); + + UNUSED_PARAM( p_dev_obj ); + + *p_action = IrpComplete; + + p_bus_info = ExAllocatePoolWithTag( NonPagedPool, sizeof(PNP_BUS_INFORMATION), 'ibqp' ); + if( !p_bus_info ) + { + BUS_TRACE_EXIT( BUS_DBG_ERROR, + ("Failed to allocate PNP_BUS_INFORMATION (%d bytes).\n", + sizeof(PNP_BUS_INFORMATION)) ); + return STATUS_INSUFFICIENT_RESOURCES; + } + + p_bus_info->BusTypeGuid = GUID_BUS_TYPE_IBA; + //TODO: Memory from Intel - storage miniport would not stay loaded unless + //TODO: bus type was PCI. Look here if SRP is having problems staying + //TODO: loaded. + p_bus_info->LegacyBusType = PNPBus; + p_bus_info->BusNumber = 0; + + p_irp->IoStatus.Information = (ULONG_PTR)p_bus_info; + BUS_EXIT( BUS_DBG_PNP ); + return STATUS_SUCCESS; +} + + +static NTSTATUS +port_query_ipoib_ifc( + IN DEVICE_OBJECT* const p_dev_obj, + IN IO_STACK_LOCATION* const p_io_stack ) +{ + NTSTATUS status; + ib_al_ifc_t *p_ifc; + ib_al_ifc_data_t *p_ifc_data; + ipoib_ifc_data_t *p_ipoib_data; + bus_port_ext_t *p_ext; + const GUID *p_guid; + + BUS_ENTER( BUS_DBG_PNP ); + + CL_ASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL ); + + p_ext = p_dev_obj->DeviceExtension; + + BUS_TRACE( BUS_DBG_PNP, ("Query i/f for %s: PDO %p (=%p),ext %p, present %d, missing %d, hibernated %d .\n", + p_ext->pdo.cl_ext.vfptr_pnp_po->identity, p_ext->pdo.cl_ext.p_self_do, + p_dev_obj, p_ext, p_ext->pdo.b_present, p_ext->pdo.b_reported_missing, + p_ext->pdo.b_hibernating ) ); + + /* Get the interface. */ + status = cl_fwd_query_ifc( + p_ext->pdo.p_parent_ext->cl_ext.p_self_do, p_io_stack ); + if( !NT_SUCCESS( status ) ) + { + BUS_TRACE_EXIT( BUS_DBG_ERROR, + ("Failed to forward interface query: %08X\n", status) ); + return status; + } + + if( !p_io_stack->Parameters.QueryInterface.InterfaceSpecificData ) + { + BUS_TRACE_EXIT( BUS_DBG_ERROR, ("No interface specific data!\n") ); + return status; + } + + p_ifc = (ib_al_ifc_t*)p_io_stack->Parameters.QueryInterface.Interface; + + p_ifc_data = (ib_al_ifc_data_t*) + p_io_stack->Parameters.QueryInterface.InterfaceSpecificData; + p_guid = p_ifc_data->type; + if( !IsEqualGUID( p_guid, &GUID_IPOIB_INTERFACE_DATA ) ) + { + BUS_TRACE_EXIT( BUS_DBG_PNP, ("Unsupported interface data: \n\t" + "0x%08x, 0x%04x, 0x%04x, 0x%02x, 0x%02x, 0x%02x," + "0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x.\n", + p_guid->Data1, p_guid->Data2, p_guid->Data3, + p_guid->Data4[0], p_guid->Data4[1], p_guid->Data4[2], + p_guid->Data4[3], p_guid->Data4[4], p_guid->Data4[5], + p_guid->Data4[6], p_guid->Data4[7]) ); + return status; + } + + if( p_ifc_data->version != IPOIB_INTERFACE_DATA_VERSION ) + { + p_ifc->wdm.InterfaceDereference( p_ifc->wdm.Context ); + BUS_TRACE_EXIT( BUS_DBG_ERROR, + ("Unsupported version %d, expected %d\n", + p_ifc_data->version, IPOIB_INTERFACE_DATA_VERSION) ); + return STATUS_NOT_SUPPORTED; + } + + ASSERT( p_ifc_data->p_data ); + + if( p_ifc_data->size != sizeof(ipoib_ifc_data_t) ) + { + p_ifc->wdm.InterfaceDereference( p_ifc->wdm.Context ); + BUS_TRACE_EXIT( BUS_DBG_PNP, + ("Buffer too small (%d given, %d required).\n", + p_ifc_data->size, + sizeof(ipoib_ifc_data_t)) ); + return STATUS_BUFFER_TOO_SMALL; + } + + /* Set the interface data. */ + p_ipoib_data = (ipoib_ifc_data_t*)p_ifc_data->p_data; + + p_ipoib_data->ca_guid = p_ext->pdo.h_ca->obj.p_ci_ca->verbs.guid; + p_ipoib_data->port_guid = p_ext->port_guid; + p_ipoib_data->port_num = (uint8_t)p_ext->n_port; + + BUS_EXIT( BUS_DBG_PNP ); + return STATUS_SUCCESS; +} + + +static NTSTATUS +port_query_interface( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + bus_pdo_ext_t *p_ext; + NTSTATUS status; + IO_STACK_LOCATION *p_io_stack; + + BUS_ENTER( BUS_DBG_PNP ); + + PAGED_CODE(); + + p_io_stack = IoGetCurrentIrpStackLocation( p_irp ); + + /* Bottom of the stack - IRP must be completed. */ + *p_action = IrpComplete; + + /* Compare requested GUID with our supported interface GUIDs. */ + if( IsEqualGUID( p_io_stack->Parameters.QueryInterface.InterfaceType, + &GUID_IB_AL_INTERFACE ) ) + { + status = port_query_ipoib_ifc( p_dev_obj, p_io_stack ); + } + else if( IsEqualGUID( p_io_stack->Parameters.QueryInterface.InterfaceType, + &GUID_BUS_INTERFACE_STANDARD ) ) + { + p_ext = p_dev_obj->DeviceExtension; + if( !p_ext->h_ca || + !p_ext->b_present || + !p_ext->h_ca->p_hca_dev || + p_ext->b_reported_missing ) + { + return STATUS_NO_SUCH_DEVICE; + } + + status = cl_fwd_query_ifc( + p_ext->h_ca->p_hca_dev, p_io_stack ); + } + else + { + status = p_irp->IoStatus.Status; + } + + BUS_EXIT( BUS_DBG_PNP ); + return status; +} + + +/* Work item callback to handle DevicePowerD3 IRPs at passive level. */ +static void +__HibernateUpWorkItem( + IN DEVICE_OBJECT* p_dev_obj, + IN void* context ) +{ + IO_STACK_LOCATION *p_io_stack; + bus_pdo_ext_t *p_ext; + IRP *p_irp; + POWER_STATE powerState; + + BUS_ENTER( BUS_DBG_POWER ); + + p_ext = (bus_pdo_ext_t*)p_dev_obj->DeviceExtension; + p_irp = (IRP*)context; + p_io_stack = IoGetCurrentIrpStackLocation( p_irp ); + + IoFreeWorkItem( p_ext->p_po_work_item ); + p_ext->p_po_work_item = NULL; + + while (!p_ext->h_ca) { + BUS_TRACE( BUS_DBG_PNP, ("Waiting for the end of HCA registration ... \n")); + cl_thread_suspend( 200 ); /* suspend for 200 ms */ + } + + p_ext->dev_po_state = p_io_stack->Parameters.Power.State; + powerState = PoSetPowerState( p_dev_obj, DevicePowerState, p_ext->dev_po_state ); + + BUS_TRACE( BUS_DBG_POWER, + ("PoSetPowerState: old state %d, new state to %d\n", + powerState.DeviceState, p_ext->dev_po_state )); + + p_irp->IoStatus.Status = STATUS_SUCCESS; + PoStartNextPowerIrp( p_irp ); + IoCompleteRequest( p_irp, IO_NO_INCREMENT ); + IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp ); + + BUS_EXIT( BUS_DBG_POWER ); +} + + +/* + * The PDOs created by the IB Bus driver are software devices. As such, + * all power states are supported. It is left to the HCA power policy + * owner to handle which states can be supported by the HCA. + */ +static NTSTATUS +port_set_power( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + NTSTATUS status = STATUS_SUCCESS; + IO_STACK_LOCATION *p_io_stack; + bus_pdo_ext_t *p_ext; + + BUS_ENTER( BUS_DBG_POWER ); + + p_ext = p_dev_obj->DeviceExtension; + p_io_stack = IoGetCurrentIrpStackLocation( p_irp ); + + BUS_TRACE( BUS_DBG_POWER, + ("SET_POWER for PDO %p (ext %p): type %s, state %d, action %d \n", + p_dev_obj, p_ext, + (p_io_stack->Parameters.Power.Type) ? "DevicePowerState" : "SystemPowerState", + p_io_stack->Parameters.Power.State.DeviceState, + p_io_stack->Parameters.Power.ShutdownType )); + + if ((p_io_stack->Parameters.Power.Type == SystemPowerState) && + (p_io_stack->Parameters.Power.State.SystemState ==PowerSystemHibernate || + p_io_stack->Parameters.Power.State.SystemState ==PowerSystemSleeping1 || + p_io_stack->Parameters.Power.State.SystemState ==PowerSystemSleeping2 || + p_io_stack->Parameters.Power.State.SystemState ==PowerSystemSleeping3 )) + { + BUS_TRACE( BUS_DBG_POWER, ("Setting b_hibernating flag for PDO %p \n", p_dev_obj)); + p_ext->b_hibernating = TRUE; + } + + if( p_io_stack->Parameters.Power.Type == DevicePowerState ) + { + /* after hibernation PDO is not ready for work. we need to wait for finishing of the HCA registration */ + if( p_io_stack->Parameters.Power.State.DeviceState == PowerDeviceD0 && p_ext->b_hibernating) + { + /* Process in a work item - deregister_ca and HcaDeinit block. */ + ASSERT( !p_ext->p_po_work_item ); + p_ext->p_po_work_item = IoAllocateWorkItem( p_dev_obj ); + if( !p_ext->p_po_work_item ) + status = STATUS_INSUFFICIENT_RESOURCES; + else { + /* Process in work item callback. */ + IoMarkIrpPending( p_irp ); + IoQueueWorkItem( + p_ext->p_po_work_item, __HibernateUpWorkItem, DelayedWorkQueue, p_irp ); + *p_action = IrpDoNothing; + BUS_EXIT( BUS_DBG_POWER ); + return STATUS_PENDING; + } + } + + /* Notify the power manager. */ + p_ext->dev_po_state = p_io_stack->Parameters.Power.State; + PoSetPowerState( p_dev_obj, DevicePowerState, p_ext->dev_po_state ); + } + + *p_action = IrpComplete; + BUS_EXIT( BUS_DBG_POWER ); + return status; +} + + + diff --git a/branches/WOF2-3/core/bus/kernel/bus_port_mgr.h b/branches/WOF2-3/core/bus/kernel/bus_port_mgr.h new file mode 100644 index 00000000..c3cd60aa --- /dev/null +++ b/branches/WOF2-3/core/bus/kernel/bus_port_mgr.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#if !defined( __BUS_PORT_MGR_H__ ) +#define __BUS_PORT_MGR_H__ + +#include +#include +#include + + +/* Global load service */ +typedef struct _port_mgr +{ + cl_obj_t obj; + + /* Mutex protects both pointer vectors. */ + cl_mutex_t pdo_mutex; + + /* Pointer vector of child IPoIB port PDOs. */ + cl_qlist_t port_list; + +} port_mgr_t; + + +struct _bus_filter_instance; + +ib_api_status_t +create_port_mgr( + IN struct _bus_filter_instance *p_bfi ); + + +NTSTATUS +port_mgr_get_bus_relations( + IN const net64_t ca_guid, + IN IRP* const p_irp ); + +#endif diff --git a/branches/WOF2-3/core/bus/kernel/bus_stat.c b/branches/WOF2-3/core/bus/kernel/bus_stat.c new file mode 100644 index 00000000..19579f33 --- /dev/null +++ b/branches/WOF2-3/core/bus/kernel/bus_stat.c @@ -0,0 +1,53 @@ +/*++ + +Copyright (c) 2005-2009 Mellanox Technologies. All rights reserved. + +Module Name: + bus_stat.h + +Abstract: + Statistics Collector header file + +Revision History: + +Notes: + +--*/ + +#include "al_debug.h" +#include "bus_stat.h" + +#if defined (EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "bus_stat.tmh" +#endif + +BUS_ST_STAT g_stat; + +void bus_st_dev_rmv( PBUS_ST_DEVICE p_stat ) +{ + if ( p_stat ) + p_stat->valid = FALSE; +} + +PBUS_ST_DEVICE bus_st_dev_add() +{ + int i; + + for ( i = 0; i < BUS_ST_MAX_DEVICES; ++i ) { + if ( g_stat.dev[i].valid == FALSE ) { + g_stat.dev[i].valid = TRUE; + return &g_stat.dev[i]; + } + } + + return NULL; +} + +void bus_st_init() +{ + memset( &g_stat, 0, sizeof(g_stat) ); +} + diff --git a/branches/WOF2-3/core/bus/kernel/bus_stat.h b/branches/WOF2-3/core/bus/kernel/bus_stat.h new file mode 100644 index 00000000..374a2572 --- /dev/null +++ b/branches/WOF2-3/core/bus/kernel/bus_stat.h @@ -0,0 +1,94 @@ +/*++ + +Copyright (c) 2005-2009 Mellanox Technologies. All rights reserved. + +Module Name: + bus_stat.h + +Abstract: + Statistics Collector header file + +Revision History: + +Notes: + +--*/ + +#pragma once + +#include +#include "al_mgr.h" +// +// restrictions +// + +#define BUS_ST_MAX_DEVICES 8 +#define BUS_ST_MAX_THREADS 4 + +// +// enums +// + +// +// structures +// + +// device + +typedef struct _bus_fdo_ext bus_fdo_ext_t; +typedef struct _bus_globals bus_globals_t; +typedef struct _al_mgr al_mgr_t; + +#define BUS_ST_THREAD_POWER_DOWN 0 +#define BUS_ST_THREAD_POWER_UP 1 + +typedef struct _BUS_ST_THREAD +{ + PKTHREAD p_thread; + char thread_name[16]; + +} BUS_ST_THREAD, *PBUS_ST_THREAD; + +typedef struct _BUS_ST_DEVICE +{ + boolean_t valid; + bus_fdo_ext_t *p_fdo; + BUS_ST_THREAD thread[BUS_ST_MAX_THREADS]; + +} BUS_ST_DEVICE, *PBUS_ST_DEVICE; + +// driver +typedef struct _BUS_ST_DRIVER +{ + bus_globals_t *p_globals; + cl_obj_mgr_t *gp_obj_mgr; + cl_async_proc_t *gp_async_proc_mgr; + cl_async_proc_t *gp_async_pnp_mgr; + cl_async_proc_t *gp_async_obj_mgr; + al_mgr_t *gp_al_mgr; + +} BUS_ST_DRIVER, *PBUS_ST_DRIVER; + +// driver stack + +typedef struct _BUS_ST_STAT +{ + BUS_ST_DRIVER drv; + BUS_ST_DEVICE dev[BUS_ST_MAX_DEVICES]; + +} BUS_ST_STAT, *PBUS_ST_STAT; + +extern BUS_ST_STAT g_stat; + +// +// functions +// + +void bus_st_dev_rmv( PBUS_ST_DEVICE p_stat ); + +PBUS_ST_DEVICE bus_st_dev_add(); + +void bus_st_init(); + + + diff --git a/branches/WOF2-3/core/bus/kernel/ibbus.rc b/branches/WOF2-3/core/bus/kernel/ibbus.rc new file mode 100644 index 00000000..ba5e0b7a --- /dev/null +++ b/branches/WOF2-3/core/bus/kernel/ibbus.rc @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef _DEBUG_ +#define VER_FILEDESCRIPTION_STR "InfiniBand Fabric Bus Driver (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "InfiniBand Fabric Bus Driver" +#endif + +#define VER_INTERNALNAME_STR "ibbus.sys" +#define VER_ORIGINALFILENAME_STR "ibbus.sys" + +#include "bus_ev_log.rc" + +#include diff --git a/branches/WOF2-3/core/bus/kernel/makefile b/branches/WOF2-3/core/bus/kernel/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-3/core/bus/kernel/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\inc\openib.def diff --git a/branches/WOF2-3/core/complib/cl_async_proc.c b/branches/WOF2-3/core/complib/cl_async_proc.c new file mode 100644 index 00000000..c8dbbe12 --- /dev/null +++ b/branches/WOF2-3/core/complib/cl_async_proc.c @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + +#include + +#define CL_ASYNC_PROC_MIN 16 +#define CL_ASYNC_PROC_GROWSIZE 16 + + +/* Worker function declaration. */ +static void +__cl_async_proc_worker( + IN void* const context ); + + +void +cl_async_proc_construct( + IN cl_async_proc_t* const p_async_proc ) +{ + CL_ASSERT( p_async_proc ); + + cl_qlist_init( &p_async_proc->item_queue ); + cl_spinlock_construct( &p_async_proc->lock ); + cl_thread_pool_construct( &p_async_proc->thread_pool ); + p_async_proc->state = CL_UNINITIALIZED; +} + + +cl_status_t +cl_async_proc_init( + IN cl_async_proc_t* const p_async_proc, + IN const uint32_t thread_count, + IN const char* const name ) +{ + cl_status_t status; + + CL_ASSERT( p_async_proc ); + + cl_async_proc_construct( p_async_proc ); + + status = cl_spinlock_init( &p_async_proc->lock ); + if( status != CL_SUCCESS ) + { + cl_async_proc_destroy( p_async_proc ); + return( status ); + } + + status = cl_thread_pool_init( &p_async_proc->thread_pool, thread_count, + __cl_async_proc_worker, p_async_proc, name ); + if( status != CL_SUCCESS ) + { + cl_async_proc_destroy( p_async_proc ); + return (status); + } + + p_async_proc->state = CL_INITIALIZED; + return( status ); +} + + +void +cl_async_proc_destroy( + IN cl_async_proc_t* const p_async_proc ) +{ + /* Destroy the thread pool first so that the threads stop. */ + cl_thread_pool_destroy( &p_async_proc->thread_pool ); + + /* Flush all queued callbacks. */ + if( p_async_proc->state == CL_INITIALIZED ) + __cl_async_proc_worker( p_async_proc ); + + /* Destroy the spinlock. */ + cl_spinlock_destroy( &p_async_proc->lock ); + + p_async_proc->state = CL_DESTROYED; +} + + +void +cl_async_proc_queue( + IN cl_async_proc_t* const p_async_proc, + IN cl_async_proc_item_t* const p_item ) +{ + CL_ASSERT( p_async_proc ); + CL_ASSERT( p_item->pfn_callback ); + CL_ASSERT( p_async_proc->state == CL_INITIALIZED ); + + /* Enqueue this item for processing. */ + cl_spinlock_acquire( &p_async_proc->lock ); + cl_qlist_insert_tail( &p_async_proc->item_queue, + &p_item->pool_item.list_item ); + cl_spinlock_release( &p_async_proc->lock ); + + /* Signal the thread pool to wake up. */ + cl_thread_pool_signal( &p_async_proc->thread_pool ); +} + + +static void +__cl_async_proc_worker( + IN void* const context) +{ + cl_async_proc_t *p_async_proc = (cl_async_proc_t*)context; + cl_list_item_t *p_list_item; + cl_async_proc_item_t *p_item; + + CL_ASSERT( p_async_proc->state == CL_INITIALIZED ); + + /* Process items from the head of the queue until it is empty. */ + cl_spinlock_acquire( &p_async_proc->lock ); + p_list_item = cl_qlist_remove_head( &p_async_proc->item_queue ); + while( p_list_item != cl_qlist_end( &p_async_proc->item_queue ) ) + { + /* Release the lock during the user's callback. */ + cl_spinlock_release( &p_async_proc->lock ); + + /* Invoke the user callback. */ + p_item = (cl_async_proc_item_t*)p_list_item; + p_item->pfn_callback( p_item ); + + /* Acquire the lock again to continue processing. */ + cl_spinlock_acquire( &p_async_proc->lock ); + /* Get the next item in the queue. */ + p_list_item = cl_qlist_remove_head( &p_async_proc->item_queue ); + } + + /* The queue is empty. Release the lock and return. */ + cl_spinlock_release( &p_async_proc->lock ); +} diff --git a/branches/WOF2-3/core/complib/cl_list.c b/branches/WOF2-3/core/complib/cl_list.c new file mode 100644 index 00000000..ea65b8fc --- /dev/null +++ b/branches/WOF2-3/core/complib/cl_list.c @@ -0,0 +1,652 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + +/* + * Abstract: + * Implementation of quick list, and list. + * + * Environment: + * All + */ + + +#include +#include + + +#define FREE_ITEM_GROW_SIZE 10 + + +/****************************************************************************** +******************************************************************************* +************** ************ +************** IMPLEMENTATION OF QUICK LIST ************ +************** ************ +******************************************************************************* +******************************************************************************/ + +void +cl_qlist_insert_array_head( + IN cl_qlist_t* const p_list, + IN cl_list_item_t* const p_array, + IN size_t item_count, + IN const size_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 size_t item_count, + IN const size_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 ) +{ + size_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 = 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; + uint32_t i = 0; + + 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( i++ < 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; + uint32_t i = 0; + + 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( i++ < 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 ); +} + + +const 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 ); +} + + +const 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/branches/WOF2-3/core/complib/cl_map.c b/branches/WOF2-3/core/complib/cl_map.c new file mode 100644 index 00000000..4d897b0e --- /dev/null +++ b/branches/WOF2-3/core/complib/cl_map.c @@ -0,0 +1,2278 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + +/* + * Abstract: + * Implementation of quick map, a binary tree where the caller always provides + * all necessary storage. + * + * Environment: + * All + */ + + +/***************************************************************************** +* +* 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. +* +*****************************************************************************/ + + +#include +#include +#include +#include +#include + + +/****************************************************************************** +******************************************************************************* +************** ************ +************** IMPLEMENTATION OF RB MAP ************ +************** ************ +******************************************************************************* +******************************************************************************/ + + +/* + * Returns whether a given item is on the left of its parent. + */ +static boolean_t +__cl_rbmap_is_left_child( + IN const cl_rbmap_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_rbmap_item_t** +__cl_rbmap_get_parent_ptr_to_item( + IN cl_rbmap_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_rbmap_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_rbmap_rot_left( + IN cl_rbmap_t* const p_map, + IN cl_rbmap_item_t* const p_item ) +{ + cl_rbmap_item_t **pp_root; + + CL_ASSERT( p_map ); + CL_ASSERT( p_item ); + CL_ASSERT( p_item->p_right != &p_map->nil ); + + pp_root = __cl_rbmap_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_rbmap_rot_right( + IN cl_rbmap_t* const p_map, + IN cl_rbmap_item_t* const p_item ) +{ + cl_rbmap_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_rbmap_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; +} + + +/* + * Balance a tree starting at a given item back to the root. + */ +static void +__cl_rbmap_ins_bal( + IN cl_rbmap_t* const p_map, + IN cl_rbmap_item_t* p_item ) +{ + cl_rbmap_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_rbmap_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_rbmap_is_left_child( p_item ) ) + { + p_item = p_item->p_up; + __cl_rbmap_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_rbmap_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_rbmap_is_left_child( p_item ) ) + { + p_item = p_item->p_up; + __cl_rbmap_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_rbmap_rot_left( p_map, p_item->p_up->p_up ); + } + } +} + + +void +cl_rbmap_insert( + IN cl_rbmap_t* const p_map, + IN cl_rbmap_item_t* const p_insert_at, + IN cl_rbmap_item_t* const p_item, + IN boolean_t left ) +{ + CL_ASSERT( p_map ); + CL_ASSERT( p_map->state == CL_INITIALIZED ); + CL_ASSERT( p_insert_at ); + 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->color = CL_MAP_RED; + + if( p_insert_at == cl_rbmap_end( p_map ) ) + { + p_map->root.p_left = p_item; + p_item->p_up = &p_map->root; + } + else + { + if( left ) + p_insert_at->p_left = p_item; + else + p_insert_at->p_right = p_item; + + p_item->p_up = p_insert_at; + } + + /* Increase the count. */ + p_map->count++; + + /* + * 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_rbmap_ins_bal( p_map, p_item ); + + cl_rbmap_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 +} + + +static void +__cl_rbmap_del_bal( + IN cl_rbmap_t* const p_map, + IN cl_rbmap_item_t* p_item ) +{ + cl_rbmap_item_t *p_uncle; + + while( (p_item->color != CL_MAP_RED) && (p_item->p_up != &p_map->root) ) + { + if( __cl_rbmap_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_rbmap_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_rbmap_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_rbmap_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_rbmap_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_rbmap_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_rbmap_rot_right( p_map, p_item->p_up ); + break; + } + } + p_item->color = CL_MAP_BLACK; +} + + +void +cl_rbmap_remove_item( + IN cl_rbmap_t* const p_map, + IN cl_rbmap_item_t* const p_item ) +{ + cl_rbmap_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_rbmap_end( p_map ) ) + return; + + if( p_item->p_right == &p_map->nil ) + { + /* The item being removed has children on at most its left. */ + p_del_item = p_item; + p_child = p_del_item->p_left; + } + else if( p_item->p_left == &p_map->nil ) + { + /* The item being removed has children on at most its right. */ + p_del_item = p_item; + p_child = p_del_item->p_right; + } + 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 = p_item->p_right; + CL_ASSERT( p_del_item != &p_map->nil ); + while( p_del_item->p_left != &p_map->nil ) + p_del_item = p_del_item->p_left; + p_child = p_del_item->p_right; + } + + /* Decrement the item count. */ + p_map->count--; + + /* + * This assignment may modify the parent pointer of the nil node. + * This is inconsequential. + */ + p_child->p_up = p_del_item->p_up; + (*__cl_rbmap_get_parent_ptr_to_item( p_del_item )) = p_child; // 2 right = 5 + + if( p_del_item->color != CL_MAP_RED ) + __cl_rbmap_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_rbmap_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 +} + + +/****************************************************************************** +******************************************************************************* +************** ************ +************** 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 ); + + cl_memclr( p_map, 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; + +#ifdef _DEBUG_ + p_map->root.p_map = p_map; + p_map->nil.p_map = p_map; +#endif + + 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 ); +} + +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 ); + CL_ASSERT( p_item->p_map == p_map ); + + if( p_item == cl_qmap_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_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 size_t min_items ) +{ + size_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_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; + + CL_ASSERT( p_map ); + + p_item = cl_qmap_remove( &p_map->qmap, key ); + + if( p_item == cl_qmap_end( &p_map->qmap ) ) + return( NULL ); + + cl_qpool_put( &p_map->pool, &p_item->pool_item ); + + return( cl_qmap_obj( (cl_map_obj_t*)p_item ) ); +} + + +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 ); + + cl_memclr( p_map, 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_match( + IN const cl_fmap_t *const p_map, + IN const void *const p_key, + IN cl_pfn_fmap_cmp_t pfn_compare) +{ + cl_fmap_item_t *p_item; + int 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 = pfn_compare ? pfn_compare(p_key, p_item->p_key) : + 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; + int 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); +} + + +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; + int 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 ); +} + + +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; + int 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; + int 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/branches/WOF2-3/core/complib/cl_memory.c b/branches/WOF2-3/core/complib/cl_memory.c new file mode 100644 index 00000000..6dde71ef --- /dev/null +++ b/branches/WOF2-3/core/complib/cl_memory.c @@ -0,0 +1,353 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + +/* + * Abstract: + * Implementation of memory allocation tracking functions. + * + * Environment: + * All + */ + + +#include "cl_memtrack.h" + + +cl_mem_tracker_t *gp_mem_tracker = NULL; + + +/* + * Allocates memory. + */ +void* +__cl_malloc_priv( + IN const size_t size, + IN const boolean_t pageable ); + + +/* + * Deallocates memory. + */ +void +__cl_free_priv( + IN void* const p_memory ); + + +/* + * Allocate and initialize the memory tracker object. + */ +static inline void +__cl_mem_track_start( void ) +{ + cl_status_t status; + + if( gp_mem_tracker ) + return; + + /* Allocate the memory tracker object. */ + gp_mem_tracker = (cl_mem_tracker_t*) + __cl_malloc_priv( sizeof(cl_mem_tracker_t), FALSE ); + + if( !gp_mem_tracker ) + return; + + /* Initialize the free list. */ + cl_qlist_init( &gp_mem_tracker->free_hdr_list ); + /* Initialize the allocation list. */ + cl_qmap_init( &gp_mem_tracker->alloc_map ); + + /* Initialize the spin lock to protect list operations. */ + status = cl_spinlock_init( &gp_mem_tracker->lock ); + if( status != CL_SUCCESS ) + { + __cl_free_priv( gp_mem_tracker ); + return; + } +} + + +/* + * Clean up memory tracking. + */ +static inline void +__cl_mem_track_stop( void ) +{ + cl_map_item_t *p_map_item; + cl_list_item_t *p_list_item; + + if( !gp_mem_tracker ) + return; + + if( cl_qmap_count( &gp_mem_tracker->alloc_map ) ) + { + /* There are still items in the list. Print them out. */ + cl_mem_display(); + } + + /* Free all allocated headers. */ + cl_spinlock_acquire( &gp_mem_tracker->lock ); + while( cl_qmap_count( &gp_mem_tracker->alloc_map ) ) + { + p_map_item = cl_qmap_head( &gp_mem_tracker->alloc_map ); + cl_qmap_remove_item( &gp_mem_tracker->alloc_map, p_map_item ); + __cl_free_priv( + PARENT_STRUCT( p_map_item, cl_malloc_hdr_t, map_item ) ); + } + + while( cl_qlist_count( &gp_mem_tracker->free_hdr_list ) ) + { + p_list_item = cl_qlist_remove_head( &gp_mem_tracker->free_hdr_list ); + __cl_free_priv( PARENT_STRUCT( + p_list_item, cl_malloc_hdr_t, map_item.pool_item.list_item ) ); + } + cl_spinlock_release( &gp_mem_tracker->lock ); + + /* Destory all objects in the memory tracker object. */ + cl_spinlock_destroy( &gp_mem_tracker->lock ); + + /* Free the memory allocated for the memory tracker object. */ + __cl_free_priv( gp_mem_tracker ); + gp_mem_tracker = NULL; +} + + +/* + * Enables memory allocation tracking. + */ +void +__cl_mem_track( + IN const boolean_t start ) +{ + if( start ) + __cl_mem_track_start(); + else + __cl_mem_track_stop(); +} + + +/* + * Display memory usage. + */ +void +cl_mem_display( void ) +{ + cl_map_item_t *p_map_item; + cl_malloc_hdr_t *p_hdr; + + if( !gp_mem_tracker ) + return; + + cl_spinlock_acquire( &gp_mem_tracker->lock ); + cl_msg_out( "\n\n\n*** Memory Usage ***\n" ); + p_map_item = cl_qmap_head( &gp_mem_tracker->alloc_map ); + while( p_map_item != cl_qmap_end( &gp_mem_tracker->alloc_map ) ) + { + /* + * Get the pointer to the header. Note that the object member of the + * list item will be used to store the pointer to the user's memory. + */ + p_hdr = PARENT_STRUCT( p_map_item, cl_malloc_hdr_t, map_item ); + + cl_msg_out( "\tMemory block at %p allocated in file %s line %d\n", + p_hdr->p_mem, p_hdr->file_name, p_hdr->line_num ); + + p_map_item = cl_qmap_next( p_map_item ); + } + cl_msg_out( "*** End of Memory Usage ***\n\n" ); + cl_spinlock_release( &gp_mem_tracker->lock ); +} + + +/* + * Allocates memory and stores information about the allocation in a list. + * The contents of the list can be printed out by calling the function + * "MemoryReportUsage". Memory allocation will succeed even if the list + * cannot be created. + */ +void* +__cl_malloc_trk( + IN const char* const p_file_name, + IN const int32_t line_num, + IN const size_t size, + IN const boolean_t pageable ) +{ + cl_malloc_hdr_t *p_hdr; + cl_list_item_t *p_list_item; + void *p_mem; + uint64_t temp_buf[FILE_NAME_LENGTH/sizeof(uint64_t)]; + int32_t temp_line; + + /* + * Allocate the memory first, so that we give the user's allocation + * priority over the the header allocation. + */ + p_mem = __cl_malloc_priv( size, pageable ); + + if( !p_mem ) + return( NULL ); + + if( !gp_mem_tracker ) + return( p_mem ); + + /* + * Make copies of the file name and line number in case those + * parameters are in paged pool. + */ + temp_line = line_num; + strncpy( (char*)temp_buf, p_file_name, FILE_NAME_LENGTH ); + /* Make sure the string is null terminated. */ + ((char*)temp_buf)[FILE_NAME_LENGTH - 1] = '\0'; + + cl_spinlock_acquire( &gp_mem_tracker->lock ); + + /* Get a header from the free header list. */ + p_list_item = cl_qlist_remove_head( &gp_mem_tracker->free_hdr_list ); + if( p_list_item != cl_qlist_end( &gp_mem_tracker->free_hdr_list ) ) + { + /* Set the header pointer to the header retrieved from the list. */ + p_hdr = PARENT_STRUCT( p_list_item, cl_malloc_hdr_t, + map_item.pool_item.list_item ); + } + else + { + /* We failed to get a free header. Allocate one. */ + p_hdr = __cl_malloc_priv( sizeof(cl_malloc_hdr_t), FALSE ); + if( !p_hdr ) + { + /* We failed to allocate the header. Return the user's memory. */ + cl_spinlock_release( &gp_mem_tracker->lock ); + return( p_mem ); + } + } + cl_memcpy( p_hdr->file_name, temp_buf, FILE_NAME_LENGTH ); + p_hdr->line_num = temp_line; + /* + * We store the pointer to the memory returned to the user. This allows + * searching the list of allocated memory even if the buffer allocated is + * not in the list without dereferencing memory we do not own. + */ + p_hdr->p_mem = p_mem; + + /* Insert the header structure into our allocation list. */ + cl_qmap_insert( &gp_mem_tracker->alloc_map, (uintptr_t)p_mem, &p_hdr->map_item ); + cl_spinlock_release( &gp_mem_tracker->lock ); + + return( p_mem ); +} + + +/* + * Allocate non-tracked memory. + */ +void* +__cl_malloc_ntrk( + IN const size_t size, + IN const boolean_t pageable ) +{ + return( __cl_malloc_priv( size, pageable ) ); +} + + +void* +__cl_zalloc_trk( + IN const char* const p_file_name, + IN const int32_t line_num, + IN const size_t size, + IN const boolean_t pageable ) +{ + void *p_buffer; + + p_buffer = __cl_malloc_trk( p_file_name, line_num, size, pageable ); + if( p_buffer ) + cl_memclr( p_buffer, size ); + + return( p_buffer ); +} + + +void* +__cl_zalloc_ntrk( + IN const size_t size, + IN const boolean_t pageable ) +{ + void *p_buffer; + + p_buffer = __cl_malloc_priv( size, pageable ); + if( p_buffer ) + cl_memclr( p_buffer, size ); + + return( p_buffer ); +} + + +void +__cl_free_trk( + IN void* const p_memory ) +{ + cl_malloc_hdr_t *p_hdr; + cl_map_item_t *p_map_item; + + if( gp_mem_tracker ) + { + cl_spinlock_acquire( &gp_mem_tracker->lock ); + + /* + * Removes an item from the allocation tracking list given a pointer + * To the user's data and returns the pointer to header referencing the + * allocated memory block. + */ + p_map_item = cl_qmap_get( &gp_mem_tracker->alloc_map, (uintptr_t)p_memory ); + if( p_map_item != cl_qmap_end( &gp_mem_tracker->alloc_map ) ) + { + /* Get the pointer to the header. */ + p_hdr = PARENT_STRUCT( p_map_item, cl_malloc_hdr_t, map_item ); + /* Remove the item from the list. */ + cl_qmap_remove_item( &gp_mem_tracker->alloc_map, p_map_item ); + + /* Return the header to the free header list. */ + cl_qlist_insert_head( &gp_mem_tracker->free_hdr_list, + &p_hdr->map_item.pool_item.list_item ); + } + cl_spinlock_release( &gp_mem_tracker->lock ); + } + __cl_free_priv( p_memory ); +} + + +void +__cl_free_ntrk( + IN void* const p_memory ) +{ + __cl_free_priv( p_memory ); +} diff --git a/branches/WOF2-3/core/complib/cl_memtrack.h b/branches/WOF2-3/core/complib/cl_memtrack.h new file mode 100644 index 00000000..43e8deab --- /dev/null +++ b/branches/WOF2-3/core/complib/cl_memtrack.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * Abstract: + * Definitions of Data-Structures for memory allocation tracking functions. + * + * Environment: + * All + */ + + +#ifndef _CL_MEMTRACK_H_ +#define _CL_MEMTRACK_H_ + + +#include +#include +#include +#include +#include + + +/* Structure to track memory allocations. */ +typedef struct _cl_mem_tracker +{ + /* List for tracking memory allocations. */ + cl_qmap_t alloc_map; + + /* Lock for synchronization. */ + cl_spinlock_t lock; + + /* List to manage free headers. */ + cl_qlist_t free_hdr_list; + +} cl_mem_tracker_t; + + +#define FILE_NAME_LENGTH 64 + + +/* Header for all memory allocations. */ +typedef struct _cl_malloc_hdr +{ + cl_map_item_t map_item; + void *p_mem; + char file_name[FILE_NAME_LENGTH]; + int32_t line_num; + +} cl_malloc_hdr_t; + + +extern cl_mem_tracker_t *gp_mem_tracker; + +#endif /* _CL_MEMTRACK_H_ */ + diff --git a/branches/WOF2-3/core/complib/cl_obj.c b/branches/WOF2-3/core/complib/cl_obj.c new file mode 100644 index 00000000..5f256354 --- /dev/null +++ b/branches/WOF2-3/core/complib/cl_obj.c @@ -0,0 +1,782 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include +#include +#include + + +/* Number of relation objects to add to the global pool when growing. */ +#define CL_REL_POOL_SIZE ( 4096 / sizeof( cl_obj_rel_t ) ) + + + +/* The global object manager. */ +cl_obj_mgr_t *gp_obj_mgr = NULL; + + + +/******************************************************************** + * Global Object Manager + *******************************************************************/ + +cl_status_t +cl_obj_mgr_create() +{ + cl_status_t status; + + /* See if the object manager has already been created. */ + if( gp_obj_mgr ) + return CL_SUCCESS; + + /* Allocate the object manager. */ + gp_obj_mgr = cl_zalloc( sizeof( cl_obj_mgr_t ) ); + if( !gp_obj_mgr ) + return CL_INSUFFICIENT_MEMORY; + + /* Construct the object manager. */ + cl_qlist_init( &gp_obj_mgr->obj_list ); + cl_spinlock_construct( &gp_obj_mgr->lock ); + cl_async_proc_construct( &gp_obj_mgr->async_proc_mgr ); + cl_qpool_construct( &gp_obj_mgr->rel_pool ); + + /* Initialize the spinlock. */ + status = cl_spinlock_init( &gp_obj_mgr->lock ); + if( status != CL_SUCCESS ) + { + cl_obj_mgr_destroy(); + return status; + } + + /* Initialize the asynchronous processing manager. */ + status = cl_async_proc_init( &gp_obj_mgr->async_proc_mgr, 0, "obj_mgr" ); + if( status != CL_SUCCESS ) + { + cl_obj_mgr_destroy(); + return status; + } + + /* Initialize the relationship pool. */ + status = cl_qpool_init( &gp_obj_mgr->rel_pool, 0, 0, CL_REL_POOL_SIZE, + sizeof( cl_obj_rel_t ), NULL, NULL, gp_obj_mgr ); + if( status != CL_SUCCESS ) + { + cl_obj_mgr_destroy(); + return status; + } + + return CL_SUCCESS; +} + + + +void +cl_obj_mgr_destroy() +{ + cl_list_item_t *p_list_item; + cl_obj_t *p_obj; + + /* See if the object manager had been created. */ + if( !gp_obj_mgr ) + return; + + /* Verify that all object's have been destroyed. */ + for( p_list_item = cl_qlist_head( &gp_obj_mgr->obj_list ); + p_list_item != cl_qlist_end( &gp_obj_mgr->obj_list ); + p_list_item = cl_qlist_next( p_list_item ) ) + { + p_obj = PARENT_STRUCT( p_list_item, cl_obj_t, pool_item ); +#if defined( _DEBUG_ ) + cl_dbg_out( "object not destroyed %p(%i), ref_cnt: %d\n", + p_obj, p_obj->type, p_obj->ref_cnt ); +#endif + } + + /* Destroy all object manager resources. */ + cl_spinlock_destroy( &gp_obj_mgr->lock ); + cl_async_proc_destroy( &gp_obj_mgr->async_proc_mgr ); + cl_qpool_destroy( &gp_obj_mgr->rel_pool ); + + /* Free the object manager and clear the global pointer. */ + cl_free( gp_obj_mgr ); + gp_obj_mgr = NULL; +} + + + +/* + * Get an item to track object relationships. + */ +cl_obj_rel_t* +cl_rel_alloc() +{ + cl_obj_rel_t *p_rel; + + CL_ASSERT( gp_obj_mgr ); + + cl_spinlock_acquire( &gp_obj_mgr->lock ); + p_rel = (cl_obj_rel_t*)cl_qpool_get( &gp_obj_mgr->rel_pool ); + cl_spinlock_release( &gp_obj_mgr->lock ); + + return p_rel; +} + + + +/* + * Return an item used to track relationships back to the pool. + */ +void +cl_rel_free( + IN cl_obj_rel_t * const p_rel ) +{ + CL_ASSERT( gp_obj_mgr && p_rel ); + + cl_spinlock_acquire( &gp_obj_mgr->lock ); + cl_qpool_put( &gp_obj_mgr->rel_pool, &p_rel->pool_item ); + cl_spinlock_release( &gp_obj_mgr->lock ); +} + + + +/* + * Insert an object into the global object manager's list. + */ +static void +__track_obj( + IN cl_obj_t *p_obj ) +{ + CL_ASSERT( gp_obj_mgr && p_obj ); + + cl_spinlock_acquire( &gp_obj_mgr->lock ); + cl_qlist_insert_tail( &gp_obj_mgr->obj_list, + (cl_list_item_t*)&p_obj->pool_item ); + cl_spinlock_release( &gp_obj_mgr->lock ); +} + + + +/* + * Remove an object from the global object manager's list. + */ +static void +__remove_obj( + IN cl_obj_t *p_obj ) +{ + CL_ASSERT( gp_obj_mgr && p_obj ); + + cl_spinlock_acquire( &gp_obj_mgr->lock ); + cl_qlist_remove_item( &gp_obj_mgr->obj_list, + (cl_list_item_t*)&p_obj->pool_item ); + cl_spinlock_release( &gp_obj_mgr->lock ); +} + + + +/******************************************************************** + * Generic Object Class + *******************************************************************/ + +/* Function prototypes. */ +static void +__destroy_obj( + IN cl_obj_t *p_obj ); + +static void +__destroy_cb( + IN cl_async_proc_item_t *p_item ); + +/* Sets the state of an object and returns the old state. */ +static cl_state_t +__obj_set_state( + IN cl_obj_t * const p_obj, + IN const cl_state_t new_state ); + + + + +void +cl_obj_construct( + IN cl_obj_t * const p_obj, + IN const uint32_t obj_type ) +{ + CL_ASSERT( p_obj ); + cl_memclr( p_obj, sizeof( cl_obj_t ) ); + + cl_spinlock_construct( &p_obj->lock ); + p_obj->state = CL_UNINITIALIZED; + p_obj->type = obj_type; + cl_event_construct( &p_obj->event ); + + cl_qlist_init( &p_obj->parent_list ); + cl_qlist_init( &p_obj->child_list ); + + /* Insert the object into the global tracking list. */ + __track_obj( p_obj ); +} + + + +cl_status_t +cl_obj_init( + IN cl_obj_t * const p_obj, + IN cl_destroy_type_t destroy_type, + IN const cl_pfn_obj_call_t pfn_destroying OPTIONAL, + IN const cl_pfn_obj_call_t pfn_cleanup OPTIONAL, + IN const cl_pfn_obj_call_t pfn_free ) +{ + cl_status_t status; + + CL_ASSERT( p_obj && pfn_free ); + CL_ASSERT( p_obj->state == CL_UNINITIALIZED ); + + /* The object references itself until it is destroyed. */ + p_obj->ref_cnt = 1; + + /* Record destruction callbacks. */ + p_obj->pfn_destroying = pfn_destroying; + p_obj->pfn_cleanup = pfn_cleanup; + p_obj->pfn_free = pfn_free; + + /* Set the destroy function pointer based on the destruction type. */ + p_obj->destroy_type = destroy_type; + p_obj->async_item.pfn_callback = __destroy_cb; + + /* Initialize the spinlock. */ + status = cl_spinlock_init( &p_obj->lock ); + if( status != CL_SUCCESS ) + return status; + + /* Initialize the synchronous cleanup event. */ + status = cl_event_init( &p_obj->event, FALSE ); + if( status != CL_SUCCESS ) + return status; + + p_obj->state = CL_INITIALIZED; + + return CL_SUCCESS; +} + + + +void +cl_obj_destroy( + IN cl_obj_t * p_obj ) +{ + cl_state_t old_state; + + CL_ASSERT( p_obj ); + + /* Mark that we're destroying the object. */ + old_state = __obj_set_state( p_obj, CL_DESTROYING ); + + /* + * Only a single thread can actually destroy the object. Multiple + * threads can initiate destruction as long as the callers can ensure + * their object reference is valid. + */ + if( old_state == CL_DESTROYING ) + return; + + /* Destroy the object. */ + __destroy_obj( p_obj ); +} + + + +void +cl_obj_reset( + IN cl_obj_t * const p_obj ) +{ + CL_ASSERT( p_obj ); + CL_ASSERT( p_obj->ref_cnt == 0 ); + CL_ASSERT( p_obj->state == CL_DESTROYING ); + + p_obj->ref_cnt = 1; + p_obj->state = CL_INITIALIZED; + + cl_qlist_remove_all( &p_obj->parent_list ); + cl_qlist_remove_all( &p_obj->child_list ); +} + + + +static cl_state_t +__obj_set_state( + IN cl_obj_t * const p_obj, + IN const cl_state_t new_state ) +{ + cl_state_t old_state; + + cl_spinlock_acquire( &p_obj->lock ); + old_state = p_obj->state; + p_obj->state = new_state; + cl_spinlock_release( &p_obj->lock ); + + return old_state; +} + + + +/* + * Add a dependent relationship between two objects. + */ +cl_status_t +cl_obj_insert_rel( + IN cl_obj_rel_t * const p_rel, + IN cl_obj_t * const p_parent_obj, + IN cl_obj_t * const p_child_obj ) +{ + cl_status_t status; + CL_ASSERT( p_rel && p_parent_obj && p_child_obj ); + + cl_spinlock_acquire( &p_parent_obj->lock ); + status = cl_obj_insert_rel_parent_locked( p_rel, p_parent_obj, p_child_obj ); + cl_spinlock_release( &p_parent_obj->lock ); + return status; +} + + + +/* + * Add a dependent relationship between two objects. + */ +cl_status_t +cl_obj_insert_rel_parent_locked( + IN cl_obj_rel_t * const p_rel, + IN cl_obj_t * const p_parent_obj, + IN cl_obj_t * const p_child_obj ) +{ + CL_ASSERT( p_rel && p_parent_obj && p_child_obj ); + + if(p_parent_obj->state != CL_INITIALIZED) + return CL_INVALID_STATE; + /* The child object needs to maintain a reference on the parent. */ + cl_obj_ref( p_parent_obj ); + cl_obj_ref( p_child_obj ); + + /* Save the relationship details. */ + p_rel->p_child_obj = p_child_obj; + p_rel->p_parent_obj = p_parent_obj; + + /* + * Track the object - hold both locks to ensure that the relationship is + * viewable in the child and parent lists at the same time. + */ + cl_spinlock_acquire( &p_child_obj->lock ); + + cl_qlist_insert_tail( &p_child_obj->parent_list, &p_rel->list_item ); + cl_qlist_insert_tail( &p_parent_obj->child_list, + (cl_list_item_t*)&p_rel->pool_item ); + + cl_spinlock_release( &p_child_obj->lock ); + return CL_SUCCESS; +} + + + +/* + * Remove an existing relationship. + */ +void +cl_obj_remove_rel( + IN cl_obj_rel_t * const p_rel ) +{ + cl_obj_t *p_child_obj; + cl_obj_t *p_parent_obj; + + CL_ASSERT( p_rel ); + CL_ASSERT( p_rel->p_child_obj && p_rel->p_parent_obj ); + + p_child_obj = p_rel->p_child_obj; + p_parent_obj = p_rel->p_parent_obj; + + /* + * Release the objects - hold both locks to ensure that the relationship is + * removed from the child and parent lists at the same time. + */ + cl_spinlock_acquire( &p_parent_obj->lock ); + cl_spinlock_acquire( &p_child_obj->lock ); + + cl_qlist_remove_item( &p_child_obj->parent_list, &p_rel->list_item ); + cl_qlist_remove_item( &p_parent_obj->child_list, + (cl_list_item_t*)&p_rel->pool_item ); + + cl_spinlock_release( &p_child_obj->lock ); + cl_spinlock_release( &p_parent_obj->lock ); + + /* Dereference the objects. */ + cl_obj_deref( p_parent_obj ); + cl_obj_deref( p_child_obj ); + + p_rel->p_child_obj = NULL; + p_rel->p_parent_obj = NULL; +} + + + +/* + * Increment a reference count on an object. + */ +int32_t +cl_obj_ref( + IN cl_obj_t * const p_obj ) +{ + CL_ASSERT( p_obj ); + + /* + * We need to allow referencing the object during destruction in order + * to properly synchronize destruction between parent and child objects. + */ + CL_ASSERT( p_obj->state == CL_INITIALIZED || + p_obj->state == CL_DESTROYING ); + + return cl_atomic_inc( &p_obj->ref_cnt ); +} + + + +/* + * Decrement the reference count on an AL object. Destroy the object if + * it is no longer referenced. This object should not be an object's parent. + */ +int32_t +cl_obj_deref( + IN cl_obj_t * const p_obj ) +{ + int32_t ref_cnt; + + CL_ASSERT( p_obj ); + CL_ASSERT( p_obj->state == CL_INITIALIZED || + p_obj->state == CL_DESTROYING ); + + ref_cnt = cl_atomic_dec( &p_obj->ref_cnt ); + + /* If the reference count went to 0, the object should be destroyed. */ + if( ref_cnt == 0 ) + { + CL_ASSERT( p_obj->state == CL_DESTROYING ); + if( p_obj->destroy_type == CL_DESTROY_ASYNC ) + { + /* Queue the object for asynchronous destruction. */ + CL_ASSERT( gp_obj_mgr ); + cl_async_proc_queue( &gp_obj_mgr->async_proc_mgr, + &p_obj->async_item ); + } + else + { + /* Signal an event for synchronous destruction. */ + cl_event_signal( &p_obj->event ); + } + } + + return ref_cnt; +} + + + +/* + * Called to cleanup all resources allocated by an object. + */ +void +cl_obj_deinit( + IN cl_obj_t * const p_obj ) +{ + CL_ASSERT( p_obj ); + CL_ASSERT( p_obj->state == CL_UNINITIALIZED || + p_obj->state == CL_DESTROYING ); +#if defined( _DEBUG_ ) + { + cl_list_item_t *p_list_item; + cl_obj_rel_t *p_rel; + + /* + * Check that we didn't leave any list items in the parent list + * that came from the global pool. Ignore list items allocated by + * the user to simplify their usage model. + */ + for( p_list_item = cl_qlist_head( &p_obj->parent_list ); + p_list_item != cl_qlist_end( &p_obj->parent_list ); + p_list_item = cl_qlist_next( p_list_item ) ) + { + p_rel = (cl_obj_rel_t*)PARENT_STRUCT( p_list_item, + cl_obj_rel_t, list_item ); + CL_ASSERT( p_rel->pool_item.p_pool != + &gp_obj_mgr->rel_pool.qcpool ); + } + } +#endif + CL_ASSERT( cl_is_qlist_empty( &p_obj->child_list ) ); + + /* Remove the object from the global tracking list. */ + __remove_obj( p_obj ); + + cl_event_destroy( &p_obj->event ); + cl_spinlock_destroy( &p_obj->lock ); + + /* Mark the object as destroyed for debugging purposes. */ + p_obj->state = CL_DESTROYED; +} + + + +/* + * Remove the given object from its relationships with all its parents. + * This call requires synchronization to the given object. + */ +static void +__remove_parent_rel( + IN cl_obj_t * const p_obj ) +{ + cl_list_item_t *p_list_item; + cl_obj_rel_t *p_rel; + + /* Remove this child object from all its parents. */ + for( p_list_item = cl_qlist_tail( &p_obj->parent_list ); + p_list_item != cl_qlist_end( &p_obj->parent_list ); + p_list_item = cl_qlist_prev( p_list_item ) ) + { + p_rel = (cl_obj_rel_t*)PARENT_STRUCT( p_list_item, + cl_obj_rel_t, list_item ); + + /* + * Remove the child from the parent's list, but do not dereference + * the parent. This lets the user access the parent in the callback + * routines, but allows destruction to proceed. + */ + cl_spinlock_acquire( &p_rel->p_parent_obj->lock ); + cl_qlist_remove_item( &p_rel->p_parent_obj->child_list, + (cl_list_item_t*)&p_rel->pool_item ); + + /* + * Remove the relationship's reference to the child. Use an atomic + * decrement rather than cl_obj_deref, since we're already holding the + * child object's lock. + */ + cl_atomic_dec( &p_obj->ref_cnt ); + CL_ASSERT( p_obj->ref_cnt > 0 ); + + cl_spinlock_release( &p_rel->p_parent_obj->lock ); + + /* + * Mark that the child is no longer related to the parent. We still + * hold a reference on the parent object, so we don't clear the parent + * pointer until that reference is released. + */ + p_rel->p_child_obj = NULL; + } +} + + + +static void +__destroy_child_obj( + IN cl_obj_t * p_obj ) +{ + cl_list_item_t *p_list_item; + cl_obj_rel_t *p_rel; + cl_obj_t *p_child_obj; + cl_state_t old_state; + + /* Destroy all child objects. */ + cl_spinlock_acquire( &p_obj->lock ); + for( p_list_item = cl_qlist_tail( &p_obj->child_list ); + p_list_item != cl_qlist_end( &p_obj->child_list ); + p_list_item = cl_qlist_tail( &p_obj->child_list ) ) + { + p_rel = (cl_obj_rel_t*)PARENT_STRUCT( p_list_item, + cl_obj_rel_t, pool_item ); + + /* + * Take a reference on the child to protect against another parent + * of the object destroying it while we are trying to access it. + * If the child object is being destroyed, it will try to remove + * this relationship from this parent. + */ + p_child_obj = p_rel->p_child_obj; + cl_obj_ref( p_child_obj ); + + /* + * We cannot hold the parent lock when acquiring the child's lock, or + * a deadlock can occur if the child is in the process of destroying + * itself and its parent relationships. + */ + cl_spinlock_release( &p_obj->lock ); + + /* + * Mark that we wish to destroy the object. If the old state indicates + * that we should destroy the object, continue with the destruction. + * Note that there is a reference held on the child object from its + * creation. We no longer need the prior reference taken above. + */ + old_state = __obj_set_state( p_child_obj, CL_DESTROYING ); + cl_obj_deref( p_child_obj ); + + if( old_state != CL_DESTROYING ) + __destroy_obj( p_child_obj ); + + /* Continue processing the relationship list. */ + cl_spinlock_acquire( &p_obj->lock ); + } + cl_spinlock_release( &p_obj->lock ); +} + + + +/* + * Destroys an object. This call returns TRUE if the destruction process + * should proceed, or FALSE if destruction is already in progress. + */ +static void +__destroy_obj( + IN cl_obj_t *p_obj ) +{ + uint32_t ref_cnt; + cl_destroy_type_t destroy_type; + + CL_ASSERT( p_obj ); + CL_ASSERT( p_obj->state == CL_DESTROYING ); + + /* Remove this child object from all its parents. */ + __remove_parent_rel( p_obj ); + + /* Notify the user that the object is being destroyed. */ + if( p_obj->pfn_destroying ) + p_obj->pfn_destroying( p_obj ); + + /* Destroy all child objects. */ + __destroy_child_obj( p_obj ); + + /* + * Cache the destroy_type because the object could be freed by the time + * cl_obj_deref below returns. + */ + destroy_type = p_obj->destroy_type; + + /* Dereference this object as it is being destroyed. */ + ref_cnt = cl_obj_deref( p_obj ); + + if( destroy_type == CL_DESTROY_SYNC ) + { + if( ref_cnt ) + { + /* Wait for all other references to go away. */ +#if DBG + /* + * In debug builds, we assert every 10 seconds - a synchronous + * destruction should not take that long. + */ + while( cl_event_wait_on( &p_obj->event, 10000000, FALSE ) == + CL_TIMEOUT ) + { + CL_ASSERT( !p_obj->ref_cnt ); + } +#else /* DBG */ + cl_event_wait_on( &p_obj->event, EVENT_NO_TIMEOUT, FALSE ); +#endif /* DBG */ + } + __destroy_cb( &p_obj->async_item ); + } +} + + + +/* + * Dereference all parents the object was related to. + */ +static cl_obj_t* +__deref_parents( + IN cl_obj_t * const p_obj ) +{ + cl_list_item_t *p_list_item; + cl_obj_rel_t *p_rel; + cl_obj_t *p_parent_obj; + + /* Destruction of the object is already serialized - no need to lock. */ + + /* + * Dereference all parents. Keep the relationship items in the child's + * list, so that they can be returned to the user through the free callback. + */ + for( p_list_item = cl_qlist_head( &p_obj->parent_list ); + p_list_item != cl_qlist_end( &p_obj->parent_list ); + p_list_item = cl_qlist_next( p_list_item ) ) + { + p_rel = (cl_obj_rel_t*)PARENT_STRUCT( p_list_item, + cl_obj_rel_t, list_item ); + + p_parent_obj = p_rel->p_parent_obj; + p_rel->p_parent_obj = NULL; + CL_ASSERT( !p_rel->p_child_obj ); + if( cl_qlist_next( p_list_item ) == + cl_qlist_end( &p_obj->parent_list ) ) + { + /* Last parent - don't dereference it until after the "free" cb. */ + return p_parent_obj; + } + else + { + cl_obj_deref( p_parent_obj ); + } + } + return NULL; +} + + + +static void +__destroy_cb( + IN cl_async_proc_item_t *p_item ) +{ + cl_obj_t *p_obj, *p_last_parent; + + CL_ASSERT( p_item ); + + p_obj = PARENT_STRUCT( p_item, cl_obj_t, async_item ); + CL_ASSERT( !p_obj->ref_cnt ); + CL_ASSERT( p_obj->state == CL_DESTROYING ); + + /* Cleanup any hardware related resources. */ + if( p_obj->pfn_cleanup ) + p_obj->pfn_cleanup( p_obj ); + + /* We can now safely dereference all but the last parent. */ + p_last_parent = __deref_parents( p_obj ); + + /* Free the resources associated with the object. */ + CL_ASSERT( p_obj->pfn_free ); + p_obj->pfn_free( p_obj ); + + if( p_last_parent ) + cl_obj_deref( p_last_parent ); +} diff --git a/branches/WOF2-3/core/complib/cl_perf.c b/branches/WOF2-3/core/complib/cl_perf.c new file mode 100644 index 00000000..49675786 --- /dev/null +++ b/branches/WOF2-3/core/complib/cl_perf.c @@ -0,0 +1,269 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * Abstract: + * Implementation of performance tracking. + * + * Environment: + * All supported environments. + */ + + +/* + * Always turn on performance tracking when building this file to allow the + * performance counter functions to be built into the component library. + * Users control their use of the functions by defining the PERF_TRACK_ON + * keyword themselves before including cl_perf.h to enable the macros to + * resolve to the internal functions. + */ +#define PERF_TRACK_ON + +#include +#include +#include + + + +uint64_t +__cl_perf_run_calibration( + IN cl_perf_t* const p_perf ); + + +/* + * Initialize the state of the performance tracker. + */ +void +__cl_perf_construct( + IN cl_perf_t* const p_perf ) +{ + cl_memclr( p_perf, sizeof(cl_perf_t) ); + p_perf->state = CL_UNINITIALIZED; +} + + +/* + * Initialize the performance tracker. + */ +cl_status_t +__cl_perf_init( + IN cl_perf_t* const p_perf, + IN const uintn_t num_counters ) +{ + cl_status_t status; + cl_spinlock_t lock; + uintn_t i; + static uint64_t locked_calibration_time = 0; + static uint64_t normal_calibration_time; + + CL_ASSERT( p_perf ); + CL_ASSERT( !p_perf->size && num_counters ); + + /* Construct the performance tracker. */ + __cl_perf_construct( p_perf ); + + /* Allocate an array of counters. */ + p_perf->size = num_counters; + p_perf->data_array = (cl_perf_data_t*) + cl_zalloc( sizeof(cl_perf_data_t) * num_counters ); + + if( !p_perf->data_array ) + return( CL_INSUFFICIENT_MEMORY ); + + /* Initialize the user's counters. */ + for( i = 0; i < num_counters; i++ ) + { + p_perf->data_array[i].min_time = ((uint64_t)~0); + cl_spinlock_construct( &p_perf->data_array[i].lock ); + } + + for( i = 0; i < num_counters; i++ ) + { + status = cl_spinlock_init( &p_perf->data_array[i].lock ); + if( status != CL_SUCCESS ) + { + __cl_perf_destroy( p_perf, FALSE ); + return( status ); + } + } + + /* + * Run the calibration only if it has not been run yet. Subsequent + * calls will use the results from the first calibration. + */ + if( !locked_calibration_time ) + { + /* + * Perform the calibration under lock to prevent thread context + * switches. + */ + cl_spinlock_construct( &lock ); + status = cl_spinlock_init( &lock ); + if( status != CL_SUCCESS ) + { + __cl_perf_destroy( p_perf, FALSE ); + return( status ); + } + + /* Measure the impact when running at elevated thread priority. */ + cl_spinlock_acquire( &lock ); + locked_calibration_time = __cl_perf_run_calibration( p_perf ); + cl_spinlock_release( &lock ); + cl_spinlock_destroy( &lock ); + + /* Measure the impact when runnin at normal thread priority. */ + normal_calibration_time = __cl_perf_run_calibration( p_perf ); + } + + /* Reset the user's performance counter. */ + p_perf->normal_calibration_time = locked_calibration_time; + p_perf->locked_calibration_time = normal_calibration_time; + p_perf->data_array[0].count = 0; + p_perf->data_array[0].total_time = 0; + p_perf->data_array[0].min_time = ((uint64_t)~0); + + p_perf->state = CL_INITIALIZED; + + return( CL_SUCCESS ); +} + + +/* + * Measure the time to take performance counters. + */ +uint64_t +__cl_perf_run_calibration( + IN cl_perf_t* const p_perf ) +{ + uint64_t start_time; + uintn_t i; + PERF_DECLARE( 0 ); + + /* Start timing. */ + start_time = cl_get_time_stamp(); + + /* + * Get the performance counter repeatedly in a loop. Use the first + * user counter as our test counter. + */ + for( i = 0; i < PERF_CALIBRATION_TESTS; i++ ) + { + cl_perf_start( 0 ); + cl_perf_stop( p_perf, 0 ); + } + + /* Calculate the total time for the calibration. */ + return( cl_get_time_stamp() - start_time ); +} + + +/* + * Destroy the performance tracker. + */ +void +__cl_perf_destroy( + IN cl_perf_t* const p_perf, + IN const boolean_t display ) +{ + uintn_t i; + + CL_ASSERT( cl_is_state_valid( p_perf->state ) ); + + if( !p_perf->data_array ) + return; + + /* Display the performance data as requested. */ + if( display && p_perf->state == CL_INITIALIZED ) + __cl_perf_display( p_perf ); + + /* Destroy the user's counters. */ + for( i = 0; i < p_perf->size; i++ ) + cl_spinlock_destroy( &p_perf->data_array[i].lock ); + + cl_free( p_perf->data_array ); + p_perf->data_array = NULL; + + p_perf->state = CL_UNINITIALIZED; +} + + +/* + * Reset the performance counters. + */ +void +__cl_perf_reset( + IN cl_perf_t* const p_perf ) +{ + uintn_t i; + + for( i = 0; i < p_perf->size; i++ ) + { + cl_spinlock_acquire( &p_perf->data_array[i].lock ); + p_perf->data_array[i].min_time = ((uint64_t)~0); + p_perf->data_array[i].total_time = 0; + p_perf->data_array[i].count = 0; + cl_spinlock_release( &p_perf->data_array[i].lock ); + } +} + + +/* + * Display the captured performance data. + */ +void +__cl_perf_display( + IN const cl_perf_t* const p_perf ) +{ + uintn_t i; + + CL_ASSERT( p_perf ); + CL_ASSERT( p_perf->state == CL_INITIALIZED ); + + cl_msg_out( "\n\n\nCL Perf:\tPerformance Data\n" ); + + cl_msg_out( "CL Perf:\tCounter Calibration Time\n" ); + cl_msg_out( "CL Perf:\tLocked TotalTime\tNormal TotalTime\tTest Count\n" ); + cl_msg_out( "CL Perf:\t%"PRIu64"\t%"PRIu64"\t%u\n", + p_perf->locked_calibration_time, p_perf->normal_calibration_time, + PERF_CALIBRATION_TESTS ); + + cl_msg_out( "CL Perf:\tUser Performance Counters\n" ); + cl_msg_out( "CL Perf:\tIndex\tTotalTime\tMinTime\tCount\n" ); + for( i = 0; i < p_perf->size; i++ ) + { + cl_msg_out( "CL Perf:\t%lu\t%"PRIu64"\t%"PRIu64"\t%"PRIu64"\n", + i, p_perf->data_array[i].total_time, + p_perf->data_array[i].min_time, p_perf->data_array[i].count ); + } + cl_msg_out( "CL Perf:\tEnd of User Performance Counters\n" ); +} diff --git a/branches/WOF2-3/core/complib/cl_pool.c b/branches/WOF2-3/core/complib/cl_pool.c new file mode 100644 index 00000000..f5128c75 --- /dev/null +++ b/branches/WOF2-3/core/complib/cl_pool.c @@ -0,0 +1,708 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * 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. + * + * Environment: + * All + */ + + +#include +#include +#include +#include +#include +#include + + +/* + * IMPLEMENTATION OF QUICK COMPOSITE POOL + */ + +void +cl_qcpool_construct( + IN cl_qcpool_t* const p_pool ) +{ + CL_ASSERT( p_pool ); + + cl_memclr( p_pool, 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*)cl_zalloc( + (sizeof(size_t) + sizeof(void*)) * num_components ); + + if( !p_pool->component_sizes ) + return( CL_INSUFFICIENT_MEMORY ); + + /* 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. */ + cl_memcpy( p_pool->component_sizes, component_sizes, + sizeof(uint32_t) * 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(uintptr_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! + */ + +// Assert can happen in shutdown. Need to find a way to distinguish between the cases +// CL_ASSERT( cl_qcpool_count( p_pool ) == p_pool->num_objects ); + + /* 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 alocated memory blocks. */ + while( !cl_is_qlist_empty( &p_pool->alloc_list ) ) + cl_free( cl_qlist_remove_head( &p_pool->alloc_list ) ); + + if( p_pool->component_sizes ) + { + cl_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*) + cl_zalloc( sizeof(cl_list_item_t) + (obj_size * obj_count) ); + + /* Make sure the allocation succeeded. */ + if( !p_objects ) + return( CL_INSUFFICIENT_MEMORY ); + + /* 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 ) +{ + cl_memclr( p_pool, 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 = (cl_pool_item_t*)p_pool_obj; + + /* 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->list_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)->list_obj.p_object ); + + /* Invoke the user's destructor callback. */ + p_pool->pfn_dtor( (void*)((cl_pool_obj_t*)p_pool_item)->list_obj.p_object, + (void*)p_pool->context ); +} + + +void +cl_cpool_construct( + IN cl_cpool_t* const p_pool ) +{ + CL_ASSERT( p_pool ); + + cl_memclr( p_pool, 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 = (cl_pool_item_t*)p_pool_obj; + + /* 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->list_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)->list_obj.p_object ); + + /* Invoke the user's destructor callback. */ + p_pool->pfn_dtor( (void*)((cl_pool_obj_t*)p_pool_item)->list_obj.p_object, + (void*)p_pool->context ); +} + + +void +cl_pool_construct( + IN cl_pool_t* const p_pool ) +{ + CL_ASSERT( p_pool ); + + cl_memclr( p_pool, 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/branches/WOF2-3/core/complib/cl_ptr_vector.c b/branches/WOF2-3/core/complib/cl_ptr_vector.c new file mode 100644 index 00000000..dc049b6f --- /dev/null +++ b/branches/WOF2-3/core/complib/cl_ptr_vector.c @@ -0,0 +1,358 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * Abstract: + * This file contains ivector and isvector implementations. + * + * Environment: + * All + */ + + +#include +#include + + +void +cl_ptr_vector_construct( + IN cl_ptr_vector_t* const p_vector ) +{ + CL_ASSERT( p_vector ); + + cl_memclr( p_vector, 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_cap, + 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_cap ) + { + status = cl_ptr_vector_set_capacity( p_vector, min_cap ); + 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 ) + { + cl_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 = cl_zalloc( new_capacity * sizeof(void*) ); + if( !p_new_ptr_array ) + return( CL_INSUFFICIENT_MEMORY ); + + if( p_vector->p_ptr_array ) + { + /* Copy the old pointer array into the new. */ + cl_memcpy( p_new_ptr_array, p_vector->p_ptr_array, + p_vector->capacity * sizeof(void*) ); + + /* Free the old pointer array. */ + cl_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 ); + } + i--; + } + + return( p_vector->size ); +} + + diff --git a/branches/WOF2-3/core/complib/cl_reqmgr.c b/branches/WOF2-3/core/complib/cl_reqmgr.c new file mode 100644 index 00000000..9ea1f08d --- /dev/null +++ b/branches/WOF2-3/core/complib/cl_reqmgr.c @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * Abstract: + * Implementation of asynchronous request manager. + * + * Environment: + * All + */ + + +#include +#include + + +/* minimum number of objects to allocate */ +#define REQ_MGR_START_SIZE 10 +/* minimum number of objects to grow */ +#define REQ_MGR_GROW_SIZE 10 + + +/****i* Component Library: Request Manager/cl_request_object_t +* NAME +* cl_request_object_t +* +* DESCRIPTION +* Request manager structure. +* +* The cl_request_object_t structure should be treated as opaque and should be +* manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _cl_request_object +{ + cl_pool_item_t pool_item; + size_t count; + boolean_t partial_ok; + cl_pfn_req_cb_t pfn_callback; + const void *context1; + const void *context2; + +} cl_request_object_t; +/* +* FIELDS +* pool_item +* Pool item to store request in a pool or list. +* +* count +* Number of items requested. +* +* partial_ok +* Is it okay to return some of the items. +* +* pfn_callback +* Notification routine when completed. +* +* context1 +* Callback context information. +* +* context2 +* Callback context information. +* +* SEE ALSO +* Overview +*********/ + + +void +cl_req_mgr_construct( + IN cl_req_mgr_t* const p_req_mgr ) +{ + CL_ASSERT( p_req_mgr ); + + /* Clear the structure. */ + cl_memclr( p_req_mgr, sizeof(cl_req_mgr_t) ); + + /* Initialize the state of the free request stack. */ + cl_qpool_construct( &p_req_mgr->request_pool ); +} + + +cl_status_t +cl_req_mgr_init( + IN cl_req_mgr_t* const p_req_mgr, + IN cl_pfn_reqmgr_get_count_t pfn_get_count, + IN const void* const get_context ) +{ + cl_status_t status; + + CL_ASSERT( p_req_mgr ); + CL_ASSERT( pfn_get_count ); + + cl_qlist_init( &p_req_mgr->request_queue ); + + status = cl_qpool_init( &p_req_mgr->request_pool, REQ_MGR_START_SIZE, 0, + REQ_MGR_GROW_SIZE, sizeof(cl_request_object_t), NULL, NULL, NULL ); + + if( status != CL_SUCCESS ) + return( status ); + + /* Store callback information for the count function. */ + p_req_mgr->pfn_get_count = pfn_get_count; + p_req_mgr->get_context = get_context; + + return( CL_SUCCESS ); +} + + +void +cl_req_mgr_destroy( + IN cl_req_mgr_t* const p_req_mgr ) +{ + CL_ASSERT( p_req_mgr ); + + /* Return all requests to the grow pool. */ + if( cl_is_qpool_inited( &p_req_mgr->request_pool ) ) + { + cl_qpool_put_list( &p_req_mgr->request_pool, + &p_req_mgr->request_queue ); + } + + cl_qpool_destroy( &p_req_mgr->request_pool ); +} + + +cl_status_t +cl_req_mgr_get( + IN cl_req_mgr_t* const p_req_mgr, + IN OUT size_t* const p_count, + IN const cl_req_type_t req_type, + IN cl_pfn_req_cb_t pfn_callback, + IN const void* const context1, + IN const void* const context2 ) +{ + size_t available_count; + size_t count; + cl_request_object_t *p_request; + + CL_ASSERT( p_req_mgr ); + CL_ASSERT( cl_is_qpool_inited( &p_req_mgr->request_pool ) ); + CL_ASSERT( p_count ); + CL_ASSERT( *p_count ); + + /* Get the number of available objects in the grow pool. */ + available_count = + p_req_mgr->pfn_get_count( (void*)p_req_mgr->get_context ); + + /* + * Check to see if there is nothing on the queue, and there are + * enough items to satisfy the whole request. + */ + if( cl_is_qlist_empty( &p_req_mgr->request_queue ) && + *p_count <= available_count ) + { + return( CL_SUCCESS ); + } + + if( req_type == REQ_GET_SYNC ) + return( CL_INSUFFICIENT_RESOURCES ); + + /* We need a request object to place on the request queue. */ + p_request = (cl_request_object_t*) + cl_qpool_get( &p_req_mgr->request_pool ); + + if( !p_request ) + return( CL_INSUFFICIENT_MEMORY ); + + /* + * We can return the available number of objects but we still need + * to queue a request for the remainder. + */ + if( req_type == REQ_GET_PARTIAL_OK && + cl_is_qlist_empty( &p_req_mgr->request_queue ) ) + { + count = *p_count - available_count; + *p_count = available_count; + p_request->partial_ok = TRUE; + } + else + { + /* + * We cannot return any objects. We queue a request for + * all of them. + */ + count = *p_count; + *p_count = 0; + p_request->partial_ok = FALSE; + } + + /* Set the request fields and enqueue it. */ + p_request->pfn_callback = pfn_callback; + p_request->context1 = context1; + p_request->context2 = context2; + p_request->count = count; + + cl_qlist_insert_tail( &p_req_mgr->request_queue, + &p_request->pool_item.list_item ); + + return( CL_PENDING ); +} + + +cl_status_t +cl_req_mgr_resume( + IN cl_req_mgr_t* const p_req_mgr, + OUT size_t* const p_count, + OUT cl_pfn_req_cb_t* const ppfn_callback, + OUT const void** const p_context1, + OUT const void** const p_context2 ) +{ + size_t available_count; + cl_request_object_t *p_queued_request; + + CL_ASSERT( p_req_mgr ); + CL_ASSERT( cl_is_qpool_inited( &p_req_mgr->request_pool ) ); + + /* If no requests are pending, there's nothing to return. */ + if( cl_is_qlist_empty( &p_req_mgr->request_queue ) ) + return( CL_NOT_DONE ); + + /* + * Get the item at the head of the request queue, + * but do not remove it yet. + */ + p_queued_request = (cl_request_object_t*) + cl_qlist_head( &p_req_mgr->request_queue ); + + *ppfn_callback = p_queued_request->pfn_callback; + *p_context1 = p_queued_request->context1; + *p_context2 = p_queued_request->context2; + + available_count = + p_req_mgr->pfn_get_count( (void*)p_req_mgr->get_context ); + + /* See if the request can be fulfilled. */ + if( p_queued_request->count > available_count ) + { + if( !p_queued_request->partial_ok ) + return( CL_INSUFFICIENT_RESOURCES ); + + p_queued_request->count -= available_count; + + *p_count = available_count; + return( CL_PENDING ); + } + + *p_count = p_queued_request->count; + + /* The entire request can be met. Remove it from the request queue. */ + cl_qlist_remove_head( &p_req_mgr->request_queue ); + + /* Return the internal request object to the free stack. */ + cl_qpool_put( &p_req_mgr->request_pool, + &p_queued_request->pool_item ); + return( CL_SUCCESS ); +} diff --git a/branches/WOF2-3/core/complib/cl_statustext.c b/branches/WOF2-3/core/complib/cl_statustext.c new file mode 100644 index 00000000..76441704 --- /dev/null +++ b/branches/WOF2-3/core/complib/cl_statustext.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * Abstract: + * Defines string to decode cl_status_t return values. + * + * Environment: + * All + */ + + +#include + + +/* Status values above converted to text for easier printing. */ +const char* cl_status_text[] = +{ + "CL_SUCCESS", + "CL_ERROR", + "CL_INVALID_STATE", + "CL_INVALID_OPERATION", + "CL_INVALID_SETTING", + "CL_INVALID_PARAMETER", + "CL_INSUFFICIENT_RESOURCES", + "CL_INSUFFICIENT_MEMORY", + "CL_INVALID_PERMISSION", + "CL_COMPLETED", + "CL_NOT_DONE", + "CL_PENDING", + "CL_TIMEOUT", + "CL_CANCELED", + "CL_REJECT", + "CL_OVERRUN", + "CL_NOT_FOUND", + "CL_UNAVAILABLE", + "CL_BUSY", + "CL_DISCONNECT", + "CL_DUPLICATE", + "CL_INVALID_REQUEST" +}; diff --git a/branches/WOF2-3/core/complib/cl_threadpool.c b/branches/WOF2-3/core/complib/cl_threadpool.c new file mode 100644 index 00000000..d45ca3f4 --- /dev/null +++ b/branches/WOF2-3/core/complib/cl_threadpool.c @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * Abstract: + * Implementation of thread pool. + * + * Environment: + * All + */ + + +#include +#include +#include + +void +__cl_thread_pool_routine( + IN void* const context ) +{ + cl_status_t status = CL_SUCCESS; + cl_thread_pool_t *p_thread_pool = (cl_thread_pool_t*)context; + + /* Continue looping until signalled to end. */ + while( !p_thread_pool->exit ) + { + /* Wait for the specified event to occur. */ + status = cl_event_wait_on( &p_thread_pool->wakeup_event, + EVENT_NO_TIMEOUT, TRUE ); + + /* See if we've been signalled to end execution. */ + if( (p_thread_pool->exit) || (status == CL_NOT_DONE) ) + break; + + /* The event has been signalled. Invoke the callback. */ + (*p_thread_pool->pfn_callback)( (void*)p_thread_pool->context ); + } + + /* + * Decrement the running count to notify the destroying thread + * that the event was received and processed. + */ + cl_atomic_dec( &p_thread_pool->running_count ); + cl_event_signal( &p_thread_pool->destroy_event ); +} + + +void +cl_thread_pool_construct( + IN cl_thread_pool_t* const p_thread_pool ) +{ + CL_ASSERT( p_thread_pool); + + cl_memclr( p_thread_pool, sizeof(cl_thread_pool_t) ); + cl_event_construct( &p_thread_pool->wakeup_event ); + cl_event_construct( &p_thread_pool->destroy_event ); + cl_list_construct( &p_thread_pool->thread_list ); + p_thread_pool->state = CL_UNINITIALIZED; +} + + +cl_status_t +cl_thread_pool_init( + IN cl_thread_pool_t* const p_thread_pool, + IN uint32_t count, + IN cl_pfn_thread_callback_t pfn_callback, + IN const void* const context, + IN const char* const name ) +{ + cl_status_t status; + cl_thread_t *p_thread; + uint32_t i; + + CL_ASSERT( p_thread_pool ); + CL_ASSERT( pfn_callback ); + + cl_thread_pool_construct( p_thread_pool ); + + if( !count ) + count = cl_proc_count(); + + status = cl_list_init( &p_thread_pool->thread_list, count ); + if( status != CL_SUCCESS ) + { + cl_thread_pool_destroy( p_thread_pool ); + return( status ); + } + + /* Initialize the event that the threads wait on. */ + status = cl_event_init( &p_thread_pool->wakeup_event, FALSE ); + if( status != CL_SUCCESS ) + { + cl_thread_pool_destroy( p_thread_pool ); + return( status ); + } + + /* Initialize the event used to destroy the threadpool. */ + status = cl_event_init( &p_thread_pool->destroy_event, FALSE ); + if( status != CL_SUCCESS ) + { + cl_thread_pool_destroy( p_thread_pool ); + return( status ); + } + + p_thread_pool->pfn_callback = pfn_callback; + p_thread_pool->context = context; + + for( i = 0; i < count; i++ ) + { + /* Create a new thread. */ + p_thread = (cl_thread_t*)cl_malloc( sizeof(cl_thread_t) ); + if( !p_thread ) + { + cl_thread_pool_destroy( p_thread_pool ); + return( CL_INSUFFICIENT_MEMORY ); + } + + cl_thread_construct( p_thread ); + + /* + * Add it to the list. This is guaranteed to work since we + * initialized the list to hold at least the number of threads we want + * to store there. + */ + status = cl_list_insert_head( &p_thread_pool->thread_list, p_thread ); + CL_ASSERT( status == CL_SUCCESS ); + + /* Start the thread. */ + status = cl_thread_init( p_thread, __cl_thread_pool_routine, + p_thread_pool, name ); + if( status != CL_SUCCESS ) + { + cl_thread_pool_destroy( p_thread_pool ); + return( status ); + } + + /* + * Increment the running count to insure that a destroying thread + * will signal all the threads. + */ + cl_atomic_inc( &p_thread_pool->running_count ); + + /* for debug only */ + if ( i < sizeof(p_thread_pool->p_thread)/sizeof(cl_thread_t*) ) + p_thread_pool->p_thread[i] = p_thread; + } + p_thread_pool->state = CL_INITIALIZED; + return( CL_SUCCESS ); +} + + +void +cl_thread_pool_destroy( + IN cl_thread_pool_t* const p_thread_pool ) +{ + cl_thread_t *p_thread; + + CL_ASSERT( p_thread_pool ); + CL_ASSERT( cl_is_state_valid( p_thread_pool->state ) ); + + /* Indicate to all threads that they need to exit. */ + p_thread_pool->exit = TRUE; + + /* + * Signal the threads until they have all exited. Signalling + * once for each thread is not guaranteed to work since two events + * could release only a single thread, depending on the rate at which + * the events are set and how the thread scheduler processes notifications. + */ + while( p_thread_pool->running_count ) + { + cl_event_signal( &p_thread_pool->wakeup_event ); + /* + * Wait for the destroy event to occur, indicating that the thread + * has exited. + */ + cl_event_wait_on( &p_thread_pool->destroy_event, + 2000000, TRUE ); + } + + /* + * Stop each thread one at a time. Note that this cannot be done in the + * above for loop because signal will wake up an unknown thread. + */ + if( cl_is_list_inited( &p_thread_pool->thread_list ) ) + { + while( !cl_is_list_empty( &p_thread_pool->thread_list ) ) + { + p_thread = + (cl_thread_t*)cl_list_remove_head( &p_thread_pool->thread_list ); + cl_thread_destroy( p_thread ); + cl_free( p_thread ); + } + } + + cl_event_destroy( &p_thread_pool->destroy_event ); + cl_event_destroy( &p_thread_pool->wakeup_event ); + cl_list_destroy( &p_thread_pool->thread_list ); + p_thread_pool->state = CL_UNINITIALIZED; +} + + +cl_status_t +cl_thread_pool_signal( + IN cl_thread_pool_t* const p_thread_pool ) +{ + CL_ASSERT( p_thread_pool ); + CL_ASSERT( p_thread_pool->state == CL_INITIALIZED ); + + return( cl_event_signal( &p_thread_pool->wakeup_event ) ); +} diff --git a/branches/WOF2-3/core/complib/cl_vector.c b/branches/WOF2-3/core/complib/cl_vector.c new file mode 100644 index 00000000..843d9f4e --- /dev/null +++ b/branches/WOF2-3/core/complib/cl_vector.c @@ -0,0 +1,617 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies, Inc. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * Abstract: + * This file contains ivector and isvector implementations. + * + * Environment: + * All + */ + + +#include +#include + + +/* + * Define the maximum size for array pages in an cl_vector_t. + * This size is in objects, not bytes. + */ +#define SVEC_MAX_PAGE_SIZE 0x1000 + + + +/* + * cl_vector_copy_general + * + * Description: + * copy operator used when size of the user object doesn't fit one of the + * other optimized copy functions. + * + * Inputs: + * p_src - source for copy + * + * Outputs: + * p_dest - destination for copy + * + * Returns: + * None + * + */ +static void +cl_vector_copy_general( + OUT void* const p_dest, + IN const void* const p_src, + IN const size_t size ) +{ + cl_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 ); + + cl_memclr( p_vector, 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 ) ) + cl_free( cl_qlist_remove_head( &p_vector->alloc_list ) ); + + /* Destroy the page vector. */ + if( p_vector->p_ptr_array ) + { + cl_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 = cl_zalloc( new_capacity * sizeof(void*) ); + if( !p_new_ptr_array ) + return( CL_INSUFFICIENT_MEMORY ); + + if( p_vector->p_ptr_array ) + { + /* Copy the old pointer array into the new. */ + cl_memcpy( p_new_ptr_array, p_vector->p_ptr_array, + p_vector->capacity * sizeof(void*) ); + + /* Free the old pointer array. */ + cl_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*)cl_zalloc( alloc_size + sizeof(cl_list_item_t) ); + if( !p_buf ) + return( CL_INSUFFICIENT_MEMORY ); + + 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/branches/WOF2-3/core/complib/dirs b/branches/WOF2-3/core/complib/dirs new file mode 100644 index 00000000..ddf0ed7d --- /dev/null +++ b/branches/WOF2-3/core/complib/dirs @@ -0,0 +1,3 @@ +DIRS=\ + user \ + kernel diff --git a/branches/WOF2-3/core/complib/kernel/SOURCES b/branches/WOF2-3/core/complib/kernel/SOURCES new file mode 100644 index 00000000..dd385750 --- /dev/null +++ b/branches/WOF2-3/core/complib/kernel/SOURCES @@ -0,0 +1,32 @@ +TARGETNAME=complib +TARGETPATH=..\..\..\bin\kernel\obj$(BUILD_ALT_DIR) +TARGETTYPE=DRIVER_LIBRARY + +SOURCES= \ + cl_driver.c \ + cl_event.c \ + cl_log.c \ + cl_memory_osd.c \ + cl_syscallback.c \ + cl_thread.c \ + cl_timer.c \ + cl_pnp_po.c \ + cl_bus_ifc.c \ + ..\cl_async_proc.c \ + ..\cl_list.c \ + ..\cl_map.c \ + ..\cl_memory.c \ + ..\cl_obj.c \ + ..\cl_perf.c \ + ..\cl_pool.c \ + ..\cl_ptr_vector.c \ + ..\cl_reqmgr.c \ + ..\cl_statustext.c \ + ..\cl_threadpool.c \ + ..\cl_vector.c + +INCLUDES=..\..\..\inc;..\..\..\inc\kernel; + +C_DEFINES=$(C_DEFINES) -DDRIVER -DDEPRECATE_DDK_FUNCTIONS + +MSC_WARNING_LEVEL= /W4 diff --git a/branches/WOF2-3/core/complib/kernel/cl_bus_ifc.c b/branches/WOF2-3/core/complib/kernel/cl_bus_ifc.c new file mode 100644 index 00000000..6c0810dd --- /dev/null +++ b/branches/WOF2-3/core/complib/kernel/cl_bus_ifc.c @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + + +#include + + +/* Forwards the request to the HCA's PDO. */ +NTSTATUS +cl_fwd_query_ifc( + IN DEVICE_OBJECT* const p_dev_obj, + IN IO_STACK_LOCATION* const p_io_stack ) +{ + NTSTATUS status; + IRP *p_irp; + IO_STATUS_BLOCK io_status; + IO_STACK_LOCATION *p_fwd_io_stack; + DEVICE_OBJECT *p_target; + KEVENT event; + + CL_ASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL ); + CL_ASSERT( p_io_stack->MinorFunction == IRP_MN_QUERY_INTERFACE ); + + p_target = IoGetAttachedDeviceReference( p_dev_obj ); + + KeInitializeEvent( &event, NotificationEvent, FALSE ); + + /* Build the IRP for the HCA. */ + p_irp = IoBuildSynchronousFsdRequest( IRP_MJ_PNP, p_target, + NULL, 0, NULL, &event, &io_status ); + if( !p_irp ) + { + ObDereferenceObject( p_target ); + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* Copy the request query parameters. */ + p_fwd_io_stack = IoGetNextIrpStackLocation( p_irp ); + p_fwd_io_stack->MinorFunction = IRP_MN_QUERY_INTERFACE; + p_fwd_io_stack->Parameters.QueryInterface = + p_io_stack->Parameters.QueryInterface; + p_irp->IoStatus.Status = STATUS_NOT_SUPPORTED; + + /* Send the IRP. */ + status = IoCallDriver( p_target, p_irp ); + if( status == STATUS_PENDING ) + { + KeWaitForSingleObject( &event, Executive, KernelMode, + FALSE, NULL ); + + status = io_status.Status; + } + + ObDereferenceObject( p_target ); + return status; +} diff --git a/branches/WOF2-3/core/complib/kernel/cl_driver.c b/branches/WOF2-3/core/complib/kernel/cl_driver.c new file mode 100644 index 00000000..1e72606f --- /dev/null +++ b/branches/WOF2-3/core/complib/kernel/cl_driver.c @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include "complib/comp_lib.h" +#include + + +CL_EXPORT NTSTATUS +cl_to_ntstatus( + IN cl_status_t status ) +{ + return (NTSTATUS)status; +} + + +CL_EXPORT cl_status_t +cl_from_ntstatus( + IN NTSTATUS status ) +{ + switch( status ) + { + case STATUS_SUCCESS: case STATUS_DRIVER_INTERNAL_ERROR: + case STATUS_INVALID_DEVICE_STATE: case STATUS_NOT_SUPPORTED: + case STATUS_INVALID_PARAMETER_1: case STATUS_INVALID_PARAMETER: + case STATUS_INSUFFICIENT_RESOURCES: case STATUS_NO_MEMORY: + case STATUS_ACCESS_DENIED: case STATUS_EVENT_DONE: + case STATUS_ABANDONED: case STATUS_PENDING: + case STATUS_TIMEOUT: case STATUS_CANCELLED: + case STATUS_REQUEST_NOT_ACCEPTED: case STATUS_DATA_OVERRUN: + case STATUS_NOT_FOUND: case STATUS_DEVICE_NOT_READY: + case STATUS_DEVICE_BUSY: case STATUS_LOCAL_DISCONNECT: + case STATUS_DUPLICATE_NAME: case STATUS_INVALID_DEVICE_REQUEST: + case STATUS_INVALID_HANDLE: case STATUS_CONNECTION_INVALID: + return (cl_status_t)status; + default: + return CL_ERROR; + } +} + + +#if defined( _DEBUG_ ) + +VOID cl_dbg_out( IN const char* const format, ...) +{ + va_list list; + va_start(list, format); + vDbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, format, list); + va_end(list); +} +#endif + diff --git a/branches/WOF2-3/core/complib/kernel/cl_event.c b/branches/WOF2-3/core/complib/kernel/cl_event.c new file mode 100644 index 00000000..07f9790d --- /dev/null +++ b/branches/WOF2-3/core/complib/kernel/cl_event.c @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include "complib/cl_event.h" + + +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 ) +{ + NTSTATUS status; + LARGE_INTEGER wait; + + CL_ASSERT( p_event ); + + if( wait_us == EVENT_NO_TIMEOUT ) + { + CL_ASSERT( KeGetCurrentIrql() <= DISPATCH_LEVEL ); + status = KeWaitForSingleObject( p_event, Executive, KernelMode, + (BOOLEAN)interruptible, NULL ); + } + else + { + CL_ASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL ); + /* Timeout is in 100 ns increments. */ + wait.QuadPart = -(int64_t)(((uint64_t)wait_us) * 10); + status = KeWaitForSingleObject( p_event, Executive, KernelMode, + (BOOLEAN)interruptible, &wait ); + } + + switch( status ) + { + case STATUS_SUCCESS: + return( CL_SUCCESS ); + case STATUS_USER_APC: + return( CL_NOT_DONE ); + case STATUS_TIMEOUT: + return( CL_TIMEOUT ); + case STATUS_ALERTED: + default: + return( CL_ERROR ); + } +} diff --git a/branches/WOF2-3/core/complib/kernel/cl_exports.def b/branches/WOF2-3/core/complib/kernel/cl_exports.def new file mode 100644 index 00000000..7d05000b --- /dev/null +++ b/branches/WOF2-3/core/complib/kernel/cl_exports.def @@ -0,0 +1,7 @@ +LIBRARY complib.sys + +EXPORTS +; DllInitialize and DllUnload must be exported for the OS reference counting to +; work, and must be private for the compiler to accept them. +DllInitialize private +DllUnload private diff --git a/branches/WOF2-3/core/complib/kernel/cl_log.c b/branches/WOF2-3/core/complib/kernel/cl_log.c new file mode 100644 index 00000000..5aa2b0bf --- /dev/null +++ b/branches/WOF2-3/core/complib/kernel/cl_log.c @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include +#include "complib/cl_log.h" + +WCHAR g_cl_wlog[ CL_LOG_BUF_LEN ]; +UCHAR g_cl_slog[ CL_LOG_BUF_LEN ]; + + +VOID +cl_event_log_write( + PVOID p_io_object, + ULONG p_error_code, + ULONG p_unique_error_code, + ULONG p_final_status, + PWCHAR p_insertion_string, + ULONG p_n_data_items, + ... + ) +/*++ + +Routine Description: + Writes an event log entry to the event log. + +Arguments: + + p_io_object......... The IO object ( driver object or device object ). + p_error_code......... The error code. + p_unique_error_code... A specific error code. + p_final_status....... The final status. + p_n_data_items........ Number of data items. + . + . data items values + . + +Return Value: + + None . + +--*/ +{ /* WriteEventLogEntryStr */ + + /* Variable argument list */ + va_list l_Argptr; + /* Pointer to an error log entry */ + PIO_ERROR_LOG_PACKET l_pErrorLogEntry; + /* sizeof insertion string */ + int l_Size = (int)((p_insertion_string) ? ((wcslen(p_insertion_string) + 1) * sizeof( WCHAR )) : 0); + int l_PktSize =sizeof(IO_ERROR_LOG_PACKET)+p_n_data_items*sizeof(ULONG); + int l_TotalSize =l_PktSize +l_Size; + + if (p_io_object == NULL) { + ASSERT(p_io_object != NULL); + return; + } + + /* Init the variable argument list */ + va_start(l_Argptr, p_n_data_items); + + /* Allocate an error log entry */ + if (l_TotalSize >= ERROR_LOG_MAXIMUM_SIZE - 2) + l_TotalSize = ERROR_LOG_MAXIMUM_SIZE - 2; + l_pErrorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry( + p_io_object, (UCHAR)l_TotalSize ); + + /* Check allocation */ + if ( l_pErrorLogEntry != NULL) + { /* OK */ + + /* Data item index */ + USHORT l_nDataItem ; + + /* Set the error log entry header */ + l_pErrorLogEntry->ErrorCode = p_error_code; + l_pErrorLogEntry->DumpDataSize = (USHORT) (p_n_data_items*sizeof(ULONG)); + l_pErrorLogEntry->SequenceNumber = 0; + l_pErrorLogEntry->MajorFunctionCode = 0; + l_pErrorLogEntry->IoControlCode = 0; + l_pErrorLogEntry->RetryCount = 0; + l_pErrorLogEntry->UniqueErrorValue = p_unique_error_code; + l_pErrorLogEntry->FinalStatus = p_final_status; + + /* Insert the data items */ + for (l_nDataItem = 0; l_nDataItem < p_n_data_items; l_nDataItem++) + { /* Inset a data item */ + + /* Current data item */ + int l_CurDataItem ; + + /* Get next data item */ + l_CurDataItem = va_arg( l_Argptr, int); + + /* Put it into the data array */ + l_pErrorLogEntry->DumpData[l_nDataItem] = l_CurDataItem ; + + } /* Inset a data item */ + + /* add insertion string */ + if (p_insertion_string) { + char *ptr; + int sz = min( l_TotalSize - l_PktSize, l_Size ); + l_pErrorLogEntry->NumberOfStrings = 1; + l_pErrorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET) + l_pErrorLogEntry->DumpDataSize; + ptr = (char*)l_pErrorLogEntry + l_pErrorLogEntry->StringOffset; + memcpy( ptr, p_insertion_string, sz ); + *(WCHAR*)&ptr[sz - 2] = (WCHAR)0; + } + + /* Write the packet */ + IoWriteErrorLogEntry(l_pErrorLogEntry); + + } /* OK */ + + /* Term the variable argument list */ + va_end(l_Argptr); + +} /* WriteEventLogEntry */ + + +/* + * The IO Object required to allocate an event log entry is passed in + * via the "name" parameter. + */ +void +cl_log_event( + IN const char* const name, + IN const cl_log_type_t type, + IN const char* const p_message, + IN const void* const p_data, + IN const uint32_t data_len ) +{ + UNUSED_PARAM( name ); + UNUSED_PARAM( type ); + UNUSED_PARAM( p_message ); + UNUSED_PARAM( p_data ); + UNUSED_PARAM( data_len ); + /* + * To log errors requires setting up custom error strings and registering + * them with the system. Do this later. + */ + //IO_ERROR_LOG_PACKET *p_entry; + //size_t size = sizeof(IO_ERROR_LOG_PACKET); + //UCHAR *p_dump_data; + //WCHAR *p_str; + + //if( p_message ) + // size += strlen( p_message ); + + //size += data_len; + + //if( size > ERROR_LOG_MAXIMUM_SIZE ) + // return; + + //p_entry = IoAllocateErrorLogEntry( name, (UCHAR)size ); + //if( !p_entry ) + // return; + + //cl_memclr( p_entry, size ); + + //p_dump_data = p_entry->DumpData; + + ///* Copy the string to the dump data. */ + //if( p_message ) + //{ + // cl_memcpy( p_dump_data, p_message, strlen( p_message ) + 1 ); + // p_dump_data += strlen( p_message ) + 1; + //} + + //if( data_len ) + // cl_memcpy( p_dump_data, p_data, data_len ); + + //switch( type ) + //{ + //case CL_LOG_ERROR: + // p_entry->ErrorCode = STATUS_UNSUCCESSFUL; + // break; + + //case CL_LOG_WARN: + // p_entry->ErrorCode = STATUS_UNSUCCESSFUL; + // break; + + //default: + //case CL_LOG_INFO: + // p_entry->ErrorCode = STATUS_SERVICE_NOTIFICATION; + // break; + //} +} diff --git a/branches/WOF2-3/core/complib/kernel/cl_memory_osd.c b/branches/WOF2-3/core/complib/kernel/cl_memory_osd.c new file mode 100644 index 00000000..6205a5a6 --- /dev/null +++ b/branches/WOF2-3/core/complib/kernel/cl_memory_osd.c @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include "complib/cl_memory.h" + + +void* +__cl_malloc_priv( + IN const size_t size, + IN const boolean_t pageable ) +{ + if( pageable ) + { + CL_ASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL ); + return( ExAllocatePoolWithTag( PagedPool, size, 'virp' ) ); + } + else + { + CL_ASSERT( KeGetCurrentIrql() <= DISPATCH_LEVEL ); + return( ExAllocatePoolWithTag( NonPagedPool, size, 'virp' ) ); + } +} + + +void +__cl_free_priv( + IN void* const p_memory ) +{ + CL_ASSERT( KeGetCurrentIrql() <= DISPATCH_LEVEL ); + ExFreePoolWithTag( p_memory, 'virp' ); +} diff --git a/branches/WOF2-3/core/complib/kernel/cl_pnp_po.c b/branches/WOF2-3/core/complib/kernel/cl_pnp_po.c new file mode 100644 index 00000000..ad7a71ea --- /dev/null +++ b/branches/WOF2-3/core/complib/kernel/cl_pnp_po.c @@ -0,0 +1,1404 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include "complib/cl_pnp_po.h" +#include "complib/cl_debug.h" +#include "complib/cl_atomic.h" + + +static NTSTATUS +__start( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +__query_stop( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +__stop( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +__cancel_stop( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +__query_remove( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +__remove( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +__cancel_remove( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +__surprise_remove( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +__query_pnp_state( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +__device_usage_notification( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +__query_device_relations( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +__query_id( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +__query_device_text( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + + + + + +void +cl_init_pnp_po_ext( + IN OUT DEVICE_OBJECT* const p_dev_obj, + IN DEVICE_OBJECT* const p_next_do, + IN DEVICE_OBJECT* const p_pdo, + IN const uint32_t pnp_po_dbg_lvl, + IN const cl_vfptr_pnp_po_t* const vfptr_pnp_po, + IN const cl_vfptr_query_txt_t* const vfptr_query_txt OPTIONAL ) +{ + cl_pnp_po_ext_t *p_ext; + + CL_ENTER( CL_DBG_PNP, pnp_po_dbg_lvl ); + + p_ext = p_dev_obj->DeviceExtension; + + p_ext->dbg_lvl = pnp_po_dbg_lvl; + + /* Store the pointer to our own device. */ + p_ext->p_self_do = p_dev_obj; + + IoInitializeRemoveLock( &p_ext->remove_lock, 'bilc', 15, 1000 ); + IoInitializeRemoveLock( &p_ext->stop_lock, 'dtci', 0, 1000 ); + + /* Initialize the PnP states. */ + p_ext->pnp_state = NotStarted; + p_ext->last_pnp_state = NotStarted; + + /* Store the pointer to the next device in the stack. */ + p_ext->p_next_do = p_next_do; + + /* Store the pointer to the underlying PDO. */ + p_ext->p_pdo = p_pdo; + + /* Store the PnP virtual function pointer table. */ + p_ext->vfptr_pnp_po = vfptr_pnp_po; + + /* Store the Power Management virtual function pointer table. */ + p_ext->vfptr_query_txt = vfptr_query_txt; + + /* + * Mark power routines as pageable. This changes when the device is + * notified of being in the paging path. + */ + p_dev_obj->Flags |= DO_POWER_PAGABLE; + + /* Clear the initializing flag before returning. */ + p_dev_obj->Flags &= ~DO_DEVICE_INITIALIZING; + + CL_EXIT( CL_DBG_PNP, p_ext->dbg_lvl ); +} + + +NTSTATUS +cl_pnp( + IN PDEVICE_OBJECT p_dev_obj, + IN PIRP p_irp ) +{ + NTSTATUS status; + IO_STACK_LOCATION *p_io_stack; + cl_pnp_po_ext_t *p_ext; + cl_irp_action_t action; + + p_ext = p_dev_obj->DeviceExtension; + + CL_ENTER( CL_DBG_PNP, p_ext->dbg_lvl ); + + CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, + ("PDO %p, ext %p\n", p_dev_obj, p_ext) ); + + CL_ASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL ); + + status = IoAcquireRemoveLock( &p_ext->remove_lock, p_irp ); + if( !NT_SUCCESS( status ) ) + { + CL_TRACE_EXIT( CL_DBG_ERROR, p_ext->dbg_lvl, + ("IoAcquireRemoveLock returned %08x.\n", status) ); + p_io_stack = IoGetCurrentIrpStackLocation( p_irp ); + CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, + ("Minor function %x for %s\n", p_io_stack->MinorFunction, p_ext->vfptr_pnp_po->identity) ); + p_irp->IoStatus.Status = status; + IoCompleteRequest( p_irp, IO_NO_INCREMENT ); + return status; + } + + p_io_stack = IoGetCurrentIrpStackLocation( p_irp ); + ASSERT( p_io_stack->MajorFunction == IRP_MJ_PNP ); + + switch( p_io_stack->MinorFunction ) + { + case IRP_MN_START_DEVICE: + CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, + ("IRP_MN_START_DEVICE for %s\n", p_ext->vfptr_pnp_po->identity) ); + status = __start( p_dev_obj, p_irp, &action ); + break; + + case IRP_MN_QUERY_STOP_DEVICE: + CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, ("IRP_MN_QUERY_STOP_DEVICE for %s\n", + p_ext->vfptr_pnp_po->identity) ); + status = __query_stop( p_dev_obj, p_irp, &action ); + break; + + case IRP_MN_STOP_DEVICE: + CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, + ("IRP_MN_STOP_DEVICE for %s\n", p_ext->vfptr_pnp_po->identity) ); + status = __stop( p_dev_obj, p_irp, &action ); + break; + + case IRP_MN_CANCEL_STOP_DEVICE: + CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, + ("IRP_MN_CANCEL_STOP_DEVICE for %s\n", p_ext->vfptr_pnp_po->identity) ); + status = __cancel_stop( p_dev_obj, p_irp, &action ); + break; + + case IRP_MN_QUERY_REMOVE_DEVICE: + CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, + ("IRP_MN_QUERY_REMOVE_DEVICE for %s\n", + p_ext->vfptr_pnp_po->identity) ); + status = __query_remove( p_dev_obj, p_irp, &action ); + break; + + case IRP_MN_REMOVE_DEVICE: + CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, + ("IRP_MN_REMOVE_DEVICE for %s\n", p_ext->vfptr_pnp_po->identity) ); + status = __remove( p_dev_obj, p_irp, &action ); + break; + + case IRP_MN_CANCEL_REMOVE_DEVICE: + CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, + ("IRP_MN_CANCEL_REMOVE_DEVICE for %s\n", + p_ext->vfptr_pnp_po->identity) ); + status = __cancel_remove( p_dev_obj, p_irp, &action ); + break; + + case IRP_MN_SURPRISE_REMOVAL: + CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, ("IRP_MN_SURPRISE_REMOVAL for %s\n", + p_ext->vfptr_pnp_po->identity) ); + status = __surprise_remove( p_dev_obj, p_irp, &action ); + break; + + case IRP_MN_QUERY_CAPABILITIES: + CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, + ("IRP_MN_QUERY_CAPABILITIES for %s\n", + p_ext->vfptr_pnp_po->identity) ); + status = p_ext->vfptr_pnp_po->pfn_query_capabilities( + p_dev_obj, p_irp, &action ); + break; + + case IRP_MN_QUERY_PNP_DEVICE_STATE: + CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, + ("IRP_MN_QUERY_PNP_DEVICE_STATE for %s\n", + p_ext->vfptr_pnp_po->identity) ); + status = __query_pnp_state( p_dev_obj, p_irp, &action ); + break; + + case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: + CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, + ("IRP_MN_FILTER_RESOURCE_REQUIREMENTS for %s\n", + p_ext->vfptr_pnp_po->identity) ); + status = p_ext->vfptr_pnp_po->pfn_filter_res_req( + p_dev_obj, p_irp, &action ); + break; + + case IRP_MN_DEVICE_USAGE_NOTIFICATION: + CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, + ("IRP_MN_DEVICE_USAGE_NOTIFICATION for %s\n", + p_ext->vfptr_pnp_po->identity) ); + status = __device_usage_notification( p_dev_obj, p_irp, &action ); + break; + + case IRP_MN_QUERY_DEVICE_RELATIONS: + CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, + ("IRP_MN_QUERY_DEVICE_RELATIONS for %s\n", + p_ext->vfptr_pnp_po->identity) ); + status = __query_device_relations( p_dev_obj, p_irp, &action ); + break; + + case IRP_MN_QUERY_RESOURCES: + CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, ("IRP_MN_QUERY_RESOURCES for %s\n", + p_ext->vfptr_pnp_po->identity) ); + status = p_ext->vfptr_pnp_po->pfn_query_resources( + p_dev_obj, p_irp, &action ); + break; + + case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: + CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, + ("IRP_MN_QUERY_RESOURCE_REQUIREMENTS for %s\n", + p_ext->vfptr_pnp_po->identity) ); + status = p_ext->vfptr_pnp_po->pfn_query_res_req( + p_dev_obj, p_irp, &action ); + break; + + case IRP_MN_QUERY_ID: + CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, + ("IRP_MN_QUERY_ID for %s\n", p_ext->vfptr_pnp_po->identity) ); + status = __query_id( p_dev_obj, p_irp, &action ); + break; + + case IRP_MN_QUERY_DEVICE_TEXT: + CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, + ("IRP_MN_QUERY_DEVICE_TEXT for %s\n", + p_ext->vfptr_pnp_po->identity) ); + status = __query_device_text( p_dev_obj, p_irp, &action ); + break; + + case IRP_MN_QUERY_BUS_INFORMATION: + CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, + ("IRP_MN_QUERY_BUS_INFORMATION for %s\n", + p_ext->vfptr_pnp_po->identity) ); + status = p_ext->vfptr_pnp_po->pfn_query_bus_info( + p_dev_obj, p_irp, &action ); + break; + + case IRP_MN_QUERY_INTERFACE: + CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, ("IRP_MN_QUERY_INTERFACE for %s\n", + p_ext->vfptr_pnp_po->identity) ); + status = p_ext->vfptr_pnp_po->pfn_query_interface( + p_dev_obj, p_irp, &action ); + break; + + case IRP_MN_READ_CONFIG: + CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, + ("IRP_MN_READ_CONFIG for %s\n", p_ext->vfptr_pnp_po->identity) ); + status = p_ext->vfptr_pnp_po->pfn_read_config( + p_dev_obj, p_irp, &action ); + break; + + case IRP_MN_WRITE_CONFIG: + CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, + ("IRP_MN_WRITE_CONFIG for %s\n", p_ext->vfptr_pnp_po->identity) ); + status = p_ext->vfptr_pnp_po->pfn_write_config( + p_dev_obj, p_irp, &action ); + break; + + case IRP_MN_EJECT: + CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, + ("IRP_MN_EJECT for %s\n", p_ext->vfptr_pnp_po->identity) ); + status = p_ext->vfptr_pnp_po->pfn_eject( + p_dev_obj, p_irp, &action ); + break; + + case IRP_MN_SET_LOCK: + CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, + ("IRP_MN_SET_LOCK for %s\n", p_ext->vfptr_pnp_po->identity) ); + status = p_ext->vfptr_pnp_po->pfn_set_lock( + p_dev_obj, p_irp, &action ); + break; + + default: + CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, + ("Unknown IRP minor function 0x%x for %s\n", + p_io_stack->MinorFunction, p_ext->vfptr_pnp_po->identity) ); + status = p_ext->vfptr_pnp_po->pfn_unknown( + p_dev_obj, p_irp, &action ); + break; + } + + switch( action ) + { + case IrpPassDown: + p_irp->IoStatus.Status = status; + CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, ("IrpPassDown: passing down to PDO %p, ext %p, status %#x\n", + p_ext->p_next_do, p_ext, p_irp->IoStatus.Status) ); + IoCopyCurrentIrpStackLocationToNext( p_irp ); + status = IoCallDriver( p_ext->p_next_do, p_irp ); + break; + + case IrpSkip: + p_irp->IoStatus.Status = status; + + case IrpIgnore: + CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, ("IrpSkip/IrpIgnore: skipping down to PDO %p, ext %p, status %#x\n", + p_ext->p_next_do, p_ext, p_irp->IoStatus.Status) ); + IoSkipCurrentIrpStackLocation( p_irp ); + status = IoCallDriver( p_ext->p_next_do, p_irp ); + break; + + case IrpComplete: + p_irp->IoStatus.Status = status; + CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, ("IrpComplete: complete IRP with status %#x\n", + p_irp->IoStatus.Status) ); + IoCompleteRequest( p_irp, IO_NO_INCREMENT ); + break; + + case IrpDoNothing: + CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, ("IrpDoNothing: do nothing\n") ); + break; + } + + CL_TRACE_EXIT( CL_DBG_PNP, p_ext->dbg_lvl, ("returned with status %#x, p_irp->IoStatus.Status %#x\n", + status, p_irp->IoStatus.Status ) ); + + if( action != IrpDoNothing ) + IoReleaseRemoveLock( &p_ext->remove_lock, p_irp ); + + return status; +} + + +static NTSTATUS +__start( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + cl_pnp_po_ext_t *p_ext; + NTSTATUS status; + + p_ext = p_dev_obj->DeviceExtension; + + CL_ENTER( CL_DBG_PNP, p_ext->dbg_lvl ); + + status = p_ext->vfptr_pnp_po->pfn_start( p_dev_obj, p_irp, p_action ); + if( NT_SUCCESS( status ) ) + { + cl_set_pnp_state( p_ext, Started ); + } + else + { + CL_TRACE( CL_DBG_ERROR, p_ext->dbg_lvl, + ("p_ext->vfptr_pnp_po->pfn_start returned %08x. \n", status) ); + } + + CL_EXIT( CL_DBG_PNP, p_ext->dbg_lvl ); + return status; +} + + +static NTSTATUS +__query_stop( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + cl_pnp_po_ext_t *p_ext; + NTSTATUS status; + + p_ext = p_dev_obj->DeviceExtension; + + CL_ENTER( CL_DBG_PNP, p_ext->dbg_lvl ); + + /* + * We must fail the query if there are any paging, dump, or hibernation + * files on the device. + */ + if( p_ext->n_crash_files || + p_ext->n_hibernate_files || + p_ext->n_paging_files ) + { + *p_action = IrpComplete; + /* Fail the request. */ + CL_TRACE_EXIT( CL_DBG_PNP, p_ext->dbg_lvl, + ("Failing IRP_MN_QUERY_STOP_DEVICE - device %s has:\n" + "\t\t%d paging files\n\t\t%d crash files\n" + "\t\t%d hibernate files\n", p_ext->vfptr_pnp_po->identity, + p_ext->n_paging_files, p_ext->n_crash_files, + p_ext->n_hibernate_files) ); + return STATUS_UNSUCCESSFUL; + } + + /* + * Mark the device as stop pending so that all new non-_PnP and non-_Power + * IRPs get queued or failed. + */ + cl_set_pnp_state( p_ext, StopPending ); + + if( p_ext->last_pnp_state == Started ) + { + /* Acquire the lock so we can release and wait. */ + status = IoAcquireRemoveLock( &p_ext->stop_lock, p_irp ); + if( !NT_SUCCESS( status ) ) + { + CL_TRACE( CL_DBG_ERROR, p_ext->dbg_lvl, + ("IoAcquireRemoveLock returned %08x. Continue anyway ...\n", status) ); + } + /* Wait for all IO operations to complete. */ + IoReleaseRemoveLockAndWait( &p_ext->stop_lock, p_irp ); + } + + status = p_ext->vfptr_pnp_po->pfn_query_stop( p_dev_obj, p_irp, p_action ); + CL_EXIT( CL_DBG_PNP, p_ext->dbg_lvl ); + return status; +} + + +static NTSTATUS +__stop( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + NTSTATUS status; + cl_pnp_po_ext_t *p_ext; + + p_ext = p_dev_obj->DeviceExtension; + + CL_ENTER( CL_DBG_PNP, p_ext->dbg_lvl ); + + ASSERT( p_ext->pnp_state == StopPending ); + + cl_set_pnp_state( p_ext, Stopped ); + + status = p_ext->vfptr_pnp_po->pfn_stop( p_dev_obj, p_irp, p_action ); + + /* Release resources. */ + if( p_ext->vfptr_pnp_po->pfn_release_resources ) + p_ext->vfptr_pnp_po->pfn_release_resources( p_dev_obj ); + + CL_EXIT( CL_DBG_PNP, p_ext->dbg_lvl ); + return status; +} + + +static NTSTATUS +__cancel_stop( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + cl_pnp_po_ext_t* p_ext; + NTSTATUS status; + + p_ext = p_dev_obj->DeviceExtension; + + CL_ENTER( CL_DBG_PNP, p_ext->dbg_lvl ); + + /* Call the device specific handler. */ + status = p_ext->vfptr_pnp_po->pfn_cancel_stop( p_dev_obj, p_irp, p_action ); + ASSERT( NT_SUCCESS(status) ); + + /* + * If we were never stopped (a higher level driver failed the + * IRP_MN_QUERY_STOP but passed down the cancel), just return. + */ + if( p_ext->pnp_state != StopPending ) + { + CL_TRACE_EXIT( CL_DBG_PNP, p_ext->dbg_lvl, + ("IRP_MN_CANCEL_STOP_DEVICE received in invalid state.\n") ); + return status; + } + + /* Return to the previous PnP state. */ + cl_rollback_pnp_state( p_ext ); + + CL_EXIT( CL_DBG_PNP, p_ext->dbg_lvl ); + return status; +} + + +static NTSTATUS +__query_remove( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + cl_pnp_po_ext_t *p_ext; + NTSTATUS status; + + p_ext = p_dev_obj->DeviceExtension; + + CL_ENTER( CL_DBG_PNP, p_ext->dbg_lvl ); + + /* + * We must fail the query if there are any paging, dump, or hibernation + * files on the device. + */ + if( p_ext->n_crash_files || + p_ext->n_hibernate_files || + p_ext->n_paging_files ) + { + *p_action = IrpComplete; + /* Fail the request. */ + CL_TRACE_EXIT( CL_DBG_PNP, p_ext->dbg_lvl, + ("Failing IRP_MN_QUERY_REMOVE_DEVICE - device has:\n" + "\t\t%d paging files\n\t\t%d crash files\n" + "\t\t%d hibernate files\n", p_ext->n_paging_files, + p_ext->n_crash_files, p_ext->n_hibernate_files) ); + return STATUS_UNSUCCESSFUL; + } + + /* We fail the query if we have any interface outstanding. */ + if( p_ext->n_ifc_ref ) + { + *p_action = IrpComplete; + CL_TRACE_EXIT( CL_DBG_PNP, p_ext->dbg_lvl, + ("Failing IRP_MN_QUERY_REMOVE_DEVICE - interface ref count: %d\n", + p_ext->n_ifc_ref) ); + return STATUS_UNSUCCESSFUL; + } + + /* + * Mark the device as remove pending so that all new non-PnP and + * non-Power IRPs get queued or failed. + */ + cl_set_pnp_state( p_ext, RemovePending ); + + /* Call type specific handler. */ + status = + p_ext->vfptr_pnp_po->pfn_query_remove( p_dev_obj, p_irp, p_action ); + + CL_EXIT( CL_DBG_PNP, p_ext->dbg_lvl ); + return status; +} + + +static NTSTATUS +__remove( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + NTSTATUS status; + cl_pnp_po_ext_t *p_ext; + + p_ext = p_dev_obj->DeviceExtension; + + CL_ENTER( CL_DBG_PNP, p_ext->dbg_lvl ); + + ASSERT( p_ext->pnp_state == NotStarted || + p_ext->pnp_state == Started || + p_ext->pnp_state == RemovePending || + p_ext->pnp_state == SurpriseRemoved || + // it can be on this state if IRP_MN_START_DEVICE failed + // pnpdtest /rebalance FailRestart creates this situation + p_ext->pnp_state == Stopped); + + /* Set the device state. */ + cl_set_pnp_state( p_ext, Deleted ); + + status = p_ext->vfptr_pnp_po->pfn_remove( p_dev_obj, p_irp, p_action ); + + CL_EXIT( CL_DBG_PNP, p_ext->dbg_lvl ); + return status; +} + + +NTSTATUS +cl_do_remove( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + NTSTATUS status; + cl_pnp_po_ext_t *p_ext; + + p_ext = p_dev_obj->DeviceExtension; + + CL_ENTER( CL_DBG_PNP, p_ext->dbg_lvl ); + + /* Wait for all I/O operations to complete. */ + IoReleaseRemoveLockAndWait( &p_ext->remove_lock, p_irp ); + + /* Release resources if it was not done yet. */ + if( p_ext->last_pnp_state != SurpriseRemoved && + p_ext->last_pnp_state != Stopped && + p_ext->vfptr_pnp_po->pfn_release_resources ) + { + p_ext->vfptr_pnp_po->pfn_release_resources( p_dev_obj ); + } + + /* Set the IRP status. */ + p_irp->IoStatus.Status = STATUS_SUCCESS; + + /* Pass the IRP down. */ + IoSkipCurrentIrpStackLocation( p_irp ); + status = IoCallDriver( p_ext->p_next_do, p_irp ); + *p_action = IrpDoNothing; + + /* Detach and destroy the device. */ + IoDetachDevice( p_ext->p_next_do ); + IoDeleteDevice( p_dev_obj ); + + CL_EXIT( CL_DBG_PNP, p_ext->dbg_lvl ); + return status; +} + + +static NTSTATUS +__cancel_remove( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + cl_pnp_po_ext_t *p_ext; + NTSTATUS status; + + p_ext = p_dev_obj->DeviceExtension; + + CL_ENTER( CL_DBG_PNP, p_ext->dbg_lvl ); + + status = + p_ext->vfptr_pnp_po->pfn_cancel_remove( p_dev_obj, p_irp, p_action ); + ASSERT( NT_SUCCESS(status) ); + + if( p_ext->pnp_state != RemovePending ) + { + CL_TRACE_EXIT( CL_DBG_PNP, p_ext->dbg_lvl, + ("IRP_MN_CANCEL_REMOVE_DEVICE received in invalid state.\n") ); + return status; + } + + cl_rollback_pnp_state( p_ext ); + + CL_EXIT( CL_DBG_PNP, p_ext->dbg_lvl ); + return status; +} + + +static NTSTATUS +__surprise_remove( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + NTSTATUS status; + cl_pnp_po_ext_t *p_ext; + + p_ext = p_dev_obj->DeviceExtension; + + CL_ENTER( CL_DBG_PNP, p_ext->dbg_lvl ); + + cl_set_pnp_state( p_ext, SurpriseRemoved ); + + /* Call handler before releasing resources. */ + status = + p_ext->vfptr_pnp_po->pfn_surprise_remove( p_dev_obj, p_irp, p_action ); + + /* Release resources. */ + if( p_ext->last_pnp_state != Stopped && + p_ext->vfptr_pnp_po->pfn_release_resources ) + { + p_ext->vfptr_pnp_po->pfn_release_resources( p_dev_obj ); + } + + CL_EXIT( CL_DBG_PNP, p_ext->dbg_lvl ); + return status; +} + + +static NTSTATUS +__query_pnp_state( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + cl_pnp_po_ext_t *p_ext; + NTSTATUS status; + + p_ext = p_dev_obj->DeviceExtension; + + CL_ENTER( CL_DBG_PNP, p_ext->dbg_lvl ); + + /* + * Flag the device as not removable if there are any special files on it. + */ + if( p_ext->n_paging_files || + p_ext->n_crash_files || + p_ext->n_hibernate_files ) + { + p_irp->IoStatus.Information |= PNP_DEVICE_NOT_DISABLEABLE; + } + + status = + p_ext->vfptr_pnp_po->pfn_query_pnp_state( p_dev_obj, p_irp, p_action ); + CL_EXIT( CL_DBG_PNP, p_ext->dbg_lvl ); + return status; +} + + +static inline void +__lock_po_code( + IN OUT cl_pnp_po_ext_t* const p_ext ) +{ + if( !p_ext->h_cl_locked_section ) + { + /* + * No handle exists. This is the first lock. Once locked, the + * handle is valid as long as the driver is loaded. Lock any + * function in the PAGE_PNP section. + */ +#pragma warning( push, 3 ) + p_ext->h_cl_locked_section = MmLockPagableCodeSection( cl_power ); + /* TODO: Pick first non-CL function */ + p_ext->h_user_locked_section = MmLockPagableCodeSection( + p_ext->vfptr_pnp_po->pfn_set_power ); +#pragma warning( pop ) + } + else + { + /* Handle already exists. Locking by handle is faster. */ + MmLockPagableSectionByHandle( p_ext->h_cl_locked_section ); + if( p_ext->h_user_locked_section ) + MmLockPagableSectionByHandle( p_ext->h_user_locked_section ); + } +} + + +static inline void +__unlock_po_code( + IN OUT cl_pnp_po_ext_t* const p_ext ) +{ + ASSERT( p_ext->h_cl_locked_section ); + MmUnlockPagableImageSection( p_ext->h_cl_locked_section ); + if( p_ext->h_user_locked_section ) + MmUnlockPagableImageSection( p_ext->h_user_locked_section ); +} + + +static NTSTATUS +__device_usage_notification( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + cl_pnp_po_ext_t *p_ext; + IO_STACK_LOCATION *p_io_stack; + atomic32_t *p_val; + NTSTATUS status; + + p_ext = p_dev_obj->DeviceExtension; + + CL_ENTER( CL_DBG_PNP, p_ext->dbg_lvl ); + p_io_stack = IoGetCurrentIrpStackLocation( p_irp ); + + switch( p_io_stack->Parameters.UsageNotification.Type ) + { + case DeviceUsageTypePaging: + p_val = &p_ext->n_paging_files; + break; + + case DeviceUsageTypeDumpFile: + p_val = &p_ext->n_crash_files; + break; + + case DeviceUsageTypeHibernation: + p_val = &p_ext->n_hibernate_files; + break; + + default: + CL_TRACE_EXIT( CL_DBG_ERROR, p_ext->dbg_lvl, + ("Invalid notification type.\n") ); + return STATUS_INVALID_PARAMETER; + } + + if( p_io_stack->Parameters.UsageNotification.InPath ) + { + cl_atomic_inc( p_val ); + __lock_po_code( p_ext ); + } + else + { + __unlock_po_code( p_ext ); + cl_atomic_dec( p_val ); + } + + /* + * Set the flag in the device extension to indicate that power management + * can happen at elevated IRQL. + */ + if( p_ext->n_paging_files || + p_ext->n_crash_files || + p_ext->n_hibernate_files ) + { + p_dev_obj->Flags &= ~DO_POWER_PAGABLE; + } + else + { + p_dev_obj->Flags |= DO_POWER_PAGABLE; + } + + /* Call type specific (FDO, PDO) function for propagating the IRP. */ + status = p_ext->vfptr_pnp_po->pfn_dev_usage_notification( + p_dev_obj, p_irp, p_action ); + + if( NT_SUCCESS( status ) ) + { + /* Notify the PnP manager that the device state may have changed. */ + IoInvalidateDeviceState( p_ext->p_pdo ); + } + else + { + /* Propagation failed. Undo. */ + if( p_io_stack->Parameters.UsageNotification.InPath ) + { + /* Someone does not support the type of special file requested. */ + __unlock_po_code( p_ext ); + cl_atomic_dec( p_val ); + } + else + { + /* + * Someone failed the notification for the removal of a special + * file. This is unlikely to happen, but handle it anyway. + */ + cl_atomic_inc( p_val ); + __lock_po_code( p_ext ); + } + + /* + * Set the flag in the device extension to indicate that power + * management can happen at elevated IRQL. + */ + if( p_ext->n_paging_files || + p_ext->n_crash_files || + p_ext->n_hibernate_files ) + { + p_dev_obj->Flags &= ~DO_POWER_PAGABLE; + } + else + { + p_dev_obj->Flags |= DO_POWER_PAGABLE; + } + } + + CL_EXIT( CL_DBG_PNP, p_ext->dbg_lvl ); + return status; +} + + +static NTSTATUS +__query_device_relations( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + NTSTATUS status; + IO_STACK_LOCATION *p_io_stack; + cl_pnp_po_ext_t *p_ext; + + p_ext = p_dev_obj->DeviceExtension; + + CL_ENTER( CL_DBG_PNP, p_ext->dbg_lvl ); + + p_io_stack = IoGetCurrentIrpStackLocation( p_irp ); + + switch( p_io_stack->Parameters.QueryDeviceRelations.Type ) + { + case BusRelations: + CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, ("BusRelations for %s\n", + p_ext->vfptr_pnp_po->identity) ); + status = p_ext->vfptr_pnp_po->pfn_query_bus_relations( + p_dev_obj, p_irp, p_action ); + break; + + case EjectionRelations: + CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, ("EjectionRelations for %s\n", + p_ext->vfptr_pnp_po->identity) ); + status = p_ext->vfptr_pnp_po->pfn_query_ejection_relations( + p_dev_obj, p_irp, p_action ); + break; + + case RemovalRelations: + CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, ("RemovalRelations for %s\n", + p_ext->vfptr_pnp_po->identity) ); + status = p_ext->vfptr_pnp_po->pfn_query_removal_relations( + p_dev_obj, p_irp, p_action ); + break; + + case TargetDeviceRelation: + CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, ("TargetDeviceRelation for %s\n", + p_ext->vfptr_pnp_po->identity) ); + status = p_ext->vfptr_pnp_po->pfn_query_target_relations( + p_dev_obj, p_irp, p_action ); + break; + + default: + CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, ("Unknown Relation for %s\n", + p_ext->vfptr_pnp_po->identity) ); + status = p_ext->vfptr_pnp_po->pfn_unknown( + p_dev_obj, p_irp, p_action ); + break; + } + + CL_EXIT( CL_DBG_PNP, p_ext->dbg_lvl ); + return status; +} + + +static NTSTATUS +__query_id( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + NTSTATUS status; + IO_STACK_LOCATION *p_io_stack; + cl_pnp_po_ext_t *p_ext; + + p_ext = p_dev_obj->DeviceExtension; + + CL_ENTER( CL_DBG_PNP, p_ext->dbg_lvl ); + p_io_stack = IoGetCurrentIrpStackLocation( p_irp ); + + /* Only PDOs handle query ID and query text IRPs */ + if( p_ext->p_next_do ) + { + status = cl_irp_ignore( p_dev_obj, p_irp, p_action ); + CL_EXIT( CL_DBG_PNP, p_ext->dbg_lvl ); + return status; + } + + *p_action = IrpComplete; + + switch( p_io_stack->Parameters.QueryId.IdType ) + { + case BusQueryDeviceID: + CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, ("BusQueryDeviceID for %s\n", + p_ext->vfptr_pnp_po->identity) ); + status = + p_ext->vfptr_query_txt->pfn_query_device_id( p_dev_obj, p_irp ); + break; + + case BusQueryHardwareIDs: + CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, ("BusQueryHardwareIDs for %s\n", + p_ext->vfptr_pnp_po->identity) ); + status = + p_ext->vfptr_query_txt->pfn_query_hardware_id( p_dev_obj, p_irp ); + break; + + case BusQueryCompatibleIDs: + CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, ("BusQueryCompatibleIDs for %s\n", + p_ext->vfptr_pnp_po->identity) ); + status = p_ext->vfptr_query_txt->pfn_query_compatible_id( + p_dev_obj, p_irp ); + break; + + case BusQueryInstanceID: + CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, ("BusQueryInstanceID for %s\n", + p_ext->vfptr_pnp_po->identity) ); + status = + p_ext->vfptr_query_txt->pfn_query_unique_id( p_dev_obj, p_irp ); + break; + + default: + CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, ("Unsupported ID type for %s\n", + p_ext->vfptr_pnp_po->identity) ); + status = p_irp->IoStatus.Status; + break; + } + + CL_EXIT( CL_DBG_PNP, p_ext->dbg_lvl ); + return status; +} + + +static NTSTATUS +__query_device_text( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + NTSTATUS status; + cl_pnp_po_ext_t *p_ext; + IO_STACK_LOCATION *p_io_stack; + + p_ext = p_dev_obj->DeviceExtension; + + CL_ENTER( CL_DBG_PNP, p_ext->dbg_lvl ); + + p_io_stack = IoGetCurrentIrpStackLocation( p_irp ); + + /* Only PDOs handle query ID and query text IRPs */ + if( p_ext->p_next_do ) + { + status = cl_irp_ignore( p_dev_obj, p_irp, p_action ); + CL_EXIT( CL_DBG_PNP, p_ext->dbg_lvl ); + return status; + } + + *p_action = IrpComplete; + + switch( p_io_stack->Parameters.QueryDeviceText.DeviceTextType ) + { + case DeviceTextDescription: + status = + p_ext->vfptr_query_txt->pfn_query_description( p_dev_obj, p_irp ); + break; + + case DeviceTextLocationInformation: + status = + p_ext->vfptr_query_txt->pfn_query_location( p_dev_obj, p_irp ); + break; + + default: + status = p_irp->IoStatus.Status; + break; + } + + CL_EXIT( CL_DBG_PNP, p_ext->dbg_lvl ); + return status; +} + + +static NTSTATUS +__sync_completion( + IN DEVICE_OBJECT *p_dev_obj, + IN IRP *p_irp, + IN void *context ) +{ + UNUSED_PARAM( p_dev_obj ); + + ASSERT( p_irp ); + ASSERT( context ); + + /* + * We only wait if IoCallDriver returned STATUS_PENDING. Only set + * the event if the IRP returned pending, so that we don't needlessly + * signal it. + */ + if( p_irp->PendingReturned ) + KeSetEvent( (KEVENT*)context, IO_NO_INCREMENT, FALSE ); + + /* We need to process the IRP further. */ + return STATUS_MORE_PROCESSING_REQUIRED; +} + + +NTSTATUS +cl_do_sync_pnp( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + KEVENT event; + NTSTATUS status; + cl_pnp_po_ext_t *p_ext; + + p_ext = p_dev_obj->DeviceExtension; + + CL_ENTER( CL_DBG_PNP, p_ext->dbg_lvl ); + + KeInitializeEvent( &event, NotificationEvent, FALSE ); + + /* Setup the IRP. */ + IoCopyCurrentIrpStackLocationToNext( p_irp ); +#pragma warning( push, 3 ) + IoSetCompletionRoutine( p_irp, __sync_completion, &event, + TRUE, TRUE, TRUE ); +#pragma warning( pop ) + + status = IoCallDriver( p_ext->p_next_do, p_irp ); + if( status == STATUS_PENDING ) + { + /* Wait for the completion. */ + KeWaitForSingleObject( &event, Executive, KernelMode, + FALSE, NULL ); + + status = p_irp->IoStatus.Status; + } + *p_action = IrpComplete; + CL_EXIT( CL_DBG_PNP, p_ext->dbg_lvl ); + return status; +} + + +NTSTATUS +cl_alloc_relations( + IN IRP* const p_irp, + IN const size_t n_devs ) +{ + DEVICE_RELATIONS *p_rel, *p_old_rel; + size_t alloc_size; +#ifdef _DEBUG_ + /* Debug variable to prevent warnings when using CL_TRACE macros. */ + uint32_t dbg_error = CL_DBG_ERROR; +#endif + + ASSERT( n_devs ); + + alloc_size = sizeof(DEVICE_RELATIONS) + + (sizeof(PDEVICE_OBJECT) * (n_devs - 1)); + + /* If there are already relations, copy them. */ + p_old_rel = (DEVICE_RELATIONS*)p_irp->IoStatus.Information; + if( p_old_rel ) + alloc_size += (sizeof(PDEVICE_OBJECT) * p_old_rel->Count); + + /* Allocate the new relations structure. */ + p_rel = ExAllocatePoolWithTag( NonPagedPool, alloc_size, 'ralc' ); + p_irp->IoStatus.Information = (ULONG_PTR)p_rel; + if( !p_rel ) + { + /* + * Allocation failed. Release the existing relations and fail the IRP. + */ + if( p_old_rel ) + ExFreePool( p_old_rel ); + CL_TRACE( CL_DBG_ERROR, dbg_error, + ("Failed to allocate DEVICE_RELATIONS (%d bytes).\n", alloc_size) ); + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* + * Since the structure doesn't contain the callers target devices, + * the count is only set to what existing relations specify. + */ + if( p_old_rel ) + { + /* Copy the existing relations. */ + RtlCopyMemory( p_rel->Objects, p_old_rel->Objects, + sizeof(PDEVICE_OBJECT) * p_old_rel->Count ); + p_rel->Count = p_old_rel->Count; + /* Done with the copy, free the old relations structure. */ + ExFreePool( p_old_rel ); + } + else + { + p_rel->Count = 0; + } + + return STATUS_SUCCESS; +} + + +NTSTATUS +cl_power( + IN PDEVICE_OBJECT p_dev_obj, + IN PIRP p_irp ) +{ + NTSTATUS status; + IO_STACK_LOCATION *p_io_stack; + cl_pnp_po_ext_t *p_ext; + cl_irp_action_t action; + + p_ext = p_dev_obj->DeviceExtension; + + CL_ENTER( CL_DBG_PNP, p_ext->dbg_lvl ); + + status = IoAcquireRemoveLock( &p_ext->remove_lock, p_irp ); + if( !NT_SUCCESS( status ) ) + { + CL_TRACE_EXIT( CL_DBG_ERROR, p_ext->dbg_lvl, + ("IoAcquireRemoveLock returned %08x for %s.\n", + status, p_ext->vfptr_pnp_po->identity) ); + PoStartNextPowerIrp( p_irp ); + p_irp->IoStatus.Status = status; + IoCompleteRequest( p_irp, IO_NO_INCREMENT ); + return status; + } + + p_io_stack = IoGetCurrentIrpStackLocation( p_irp ); + ASSERT( p_io_stack->MajorFunction == IRP_MJ_POWER ); + + switch( p_io_stack->MinorFunction ) + { + case IRP_MN_QUERY_POWER: + CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, ("IRP_MN_QUERY_POWER for %s\n", + p_ext->vfptr_pnp_po->identity) ); + status = + p_ext->vfptr_pnp_po->pfn_query_power( p_dev_obj, p_irp, &action ); + break; + + case IRP_MN_SET_POWER: + CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, ("IRP_MN_SET_POWER for %s\n", + p_ext->vfptr_pnp_po->identity) ); + status = + p_ext->vfptr_pnp_po->pfn_set_power( p_dev_obj, p_irp, &action ); + break; + + case IRP_MN_WAIT_WAKE: + CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, ("IRP_MN_WAIT_WAKE for %s\n", + p_ext->vfptr_pnp_po->identity) ); + status = + p_ext->vfptr_pnp_po->pfn_wait_wake( p_dev_obj, p_irp, &action ); + break; + + case IRP_MN_POWER_SEQUENCE: + CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, ("IRP_MN_POWER_SEQUENCE for %s\n", + p_ext->vfptr_pnp_po->identity) ); + status = + p_ext->vfptr_pnp_po->pfn_power_sequence( p_dev_obj, p_irp, &action ); + break; + + default: + CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, ("Unknown IRP minor function for %s\n", + p_ext->vfptr_pnp_po->identity) ); + status = p_ext->vfptr_pnp_po->pfn_unknown( + p_dev_obj, p_irp, &action ); + } + + switch( action ) + { + case IrpPassDown: + /* + * A completion routine has already been set. + * PoStartNextPowerIrp should be called in the completion routine. + */ + status = PoCallDriver( p_ext->p_next_do, p_irp ); + break; + + case IrpSkip: + p_irp->IoStatus.Status = status; + + case IrpIgnore: + PoStartNextPowerIrp( p_irp ); + IoSkipCurrentIrpStackLocation( p_irp ); + /* TODO: Documentation says to return STATUS_PENDING. Seems odd. */ + status = PoCallDriver( p_ext->p_next_do, p_irp ); + break; + + case IrpComplete: + p_irp->IoStatus.Status = status; + PoStartNextPowerIrp( p_irp ); + IoCompleteRequest( p_irp, IO_NO_INCREMENT ); + break; + + case IrpDoNothing: + /* + * Returned when sending a device IRP_MN_SET_POWER IRP so that + * processing can continue in the completion routine without releasing + * the remove lock. + */ + break; + } + + if( action != IrpDoNothing ) + IoReleaseRemoveLock( &p_ext->remove_lock, p_irp ); + + CL_EXIT( CL_DBG_PNP, p_ext->dbg_lvl ); + return status; +} + + +NTSTATUS +cl_irp_skip( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + UNUSED_PARAM( p_dev_obj ); + UNUSED_PARAM( p_irp ); + *p_action = IrpSkip; + return STATUS_SUCCESS; +} + + +NTSTATUS +cl_irp_ignore( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + UNUSED_PARAM( p_dev_obj ); + UNUSED_PARAM( p_irp ); + *p_action = IrpIgnore; + return STATUS_SUCCESS; +} + + + +NTSTATUS +cl_irp_complete( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + UNUSED_PARAM( p_dev_obj ); + *p_action = IrpComplete; + return p_irp->IoStatus.Status; +} + + +NTSTATUS +cl_irp_succeed( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + UNUSED_PARAM( p_dev_obj ); + UNUSED_PARAM( p_irp ); + *p_action = IrpComplete; + return STATUS_SUCCESS; +} + + +NTSTATUS +cl_irp_unsupported( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + UNUSED_PARAM( p_dev_obj ); + UNUSED_PARAM( p_irp ); + *p_action = IrpComplete; + return STATUS_NOT_SUPPORTED; +} diff --git a/branches/WOF2-3/core/complib/kernel/cl_syscallback.c b/branches/WOF2-3/core/complib/kernel/cl_syscallback.c new file mode 100644 index 00000000..98246763 --- /dev/null +++ b/branches/WOF2-3/core/complib/kernel/cl_syscallback.c @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include "complib/cl_syscallback.h" +#include "complib/cl_memory.h" + + +/* The OS porvides the thread pool, so this is a no-op. */ +cl_status_t +cl_sys_callback_init( void ) +{ + return( CL_SUCCESS ); +} + + +/* The OS porvides the thread pool, so this is a no-op. */ +void +cl_sys_callback_destroy( void ) +{ +} + + +/* Note: This could be improved to pull items out of a pool. */ +cl_sys_callback_item_t* +cl_sys_callback_get( + IN const void* const get_context ) +{ + return IoAllocateWorkItem( (PDEVICE_OBJECT)get_context ); +} + + +void +cl_sys_callback_put( + IN cl_sys_callback_item_t* const p_item ) +{ + CL_ASSERT( p_item ); + IoFreeWorkItem( p_item ); +} + + +cl_status_t +cl_sys_callback_queue( + IN cl_sys_callback_item_t* const p_item, + IN cl_pfn_sys_callback_t pfn_callback, + IN const void* const queue_context, + IN const boolean_t high_priority ) +{ + WORK_QUEUE_TYPE type; + + /* Execute as an APC if the requested priority is high. */ + if( high_priority ) + type = CriticalWorkQueue; + else + type = DelayedWorkQueue; + + IoQueueWorkItem( p_item, pfn_callback, type, (void*)queue_context ); + + return( CL_SUCCESS ); +} diff --git a/branches/WOF2-3/core/complib/kernel/cl_thread.c b/branches/WOF2-3/core/complib/kernel/cl_thread.c new file mode 100644 index 00000000..f9ebd427 --- /dev/null +++ b/branches/WOF2-3/core/complib/kernel/cl_thread.c @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include "complib/cl_thread.h" + + +static void +__thread_callback( + IN cl_thread_t* p_thread ) +{ + /* Store the thread pointer so that destroy and is_current_thread work. */ + p_thread->osd.p_thread = KeGetCurrentThread(); + + /* Bump the thread's priority. */ + KeSetPriorityThread( p_thread->osd.p_thread, LOW_REALTIME_PRIORITY ); + + /* Call the user's thread function. */ + (*p_thread->pfn_callback)( (void*)p_thread->context ); + + PsTerminateSystemThread( STATUS_SUCCESS ); +} + + +void +cl_thread_construct( + IN cl_thread_t* const p_thread ) +{ + p_thread->osd.h_thread = NULL; + p_thread->osd.p_thread = NULL; +} + + +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 ) +{ + NTSTATUS status; + OBJECT_ATTRIBUTES attr; + + CL_ASSERT( p_thread && pfn_callback ); + CL_ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL ); + + cl_thread_construct( p_thread ); + + p_thread->pfn_callback = pfn_callback; + p_thread->context = context; + strncpy( &p_thread->name[0], name, sizeof(p_thread->name) ); + + /* Create a new thread, storing both the handle and thread id. */ + InitializeObjectAttributes( &attr, NULL, OBJ_KERNEL_HANDLE, NULL, NULL ); + status = PsCreateSystemThread( &p_thread->osd.h_thread, THREAD_ALL_ACCESS, + &attr, NULL, NULL, __thread_callback, p_thread ); + + if( !NT_SUCCESS( status ) ) + return( CL_ERROR ); + + return( CL_SUCCESS ); +} + + +void +cl_thread_destroy( + IN cl_thread_t* const p_thread ) +{ + CL_ASSERT( p_thread ); + + if( !p_thread->osd.h_thread ) + return; + + /* Wait until the kernel thread pointer is stored in the thread object. */ + while( !p_thread->osd.p_thread ) + cl_thread_suspend( 0 ); + + /* Wait for the thread to exit. */ + KeWaitForSingleObject( p_thread->osd.p_thread, Executive, KernelMode, + FALSE, NULL ); + + /* Close the handle to the thread. */ + ZwClose( p_thread->osd.h_thread ); + + /* + * Reset the handle in case the user calls destroy and the thread is + * no longer active. + */ + cl_thread_construct( p_thread ); +} + + +uint32_t +cl_proc_count( void ) +{ +#if WINVER > 0x500 + return KeNumberProcessors; +#else + return *KeNumberProcessors; +#endif +} + + +boolean_t +cl_is_current_thread( + IN const cl_thread_t* const p_thread ) +{ + return( p_thread->osd.p_thread == KeGetCurrentThread() ); +} diff --git a/branches/WOF2-3/core/complib/kernel/cl_timer.c b/branches/WOF2-3/core/complib/kernel/cl_timer.c new file mode 100644 index 00000000..e235642d --- /dev/null +++ b/branches/WOF2-3/core/complib/kernel/cl_timer.c @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include "complib/cl_timer.h" +#include "complib/cl_memory.h" + + +static void +__timer_callback( + IN PRKDPC p_dpc, + IN cl_timer_t* p_timer, + IN void* arg1, + IN void* arg2 ) +{ + KLOCK_QUEUE_HANDLE hlock; + + UNUSED_PARAM( p_dpc ); + UNUSED_PARAM( arg1 ); + UNUSED_PARAM( arg2 ); + + KeAcquireInStackQueuedSpinLockAtDpcLevel( &p_timer->spinlock, &hlock ); + p_timer->timeout_time = 0; + KeReleaseInStackQueuedSpinLockFromDpcLevel( &hlock ); + + KeAcquireInStackQueuedSpinLockAtDpcLevel( &p_timer->cb_lock, &hlock ); + (p_timer->pfn_callback)( (void*)p_timer->context ); + KeReleaseInStackQueuedSpinLockFromDpcLevel( &hlock ); +} + + +void +cl_timer_construct( + IN cl_timer_t* const p_timer ) +{ + cl_memclr( p_timer, sizeof(cl_timer_t) ); +} + + + +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 && pfn_callback ); + + cl_timer_construct( p_timer ); + + p_timer->pfn_callback = pfn_callback; + p_timer->context = context; + + KeInitializeTimer( &p_timer->timer ); + KeInitializeDpc( &p_timer->dpc, __timer_callback, p_timer ); + KeInitializeSpinLock( &p_timer->spinlock ); + KeInitializeSpinLock( &p_timer->cb_lock ); + + return( CL_SUCCESS ); +} + + +void +cl_timer_destroy( + IN cl_timer_t* const p_timer ) +{ + CL_ASSERT( p_timer ); + + if( !p_timer->pfn_callback ) + return; + + /* Ensure that the timer is stopped. */ + cl_timer_stop( p_timer ); + + /* + * Flush the DPCs to ensure that no callbacks occur after the timer is + * destroyed. + */ + KeFlushQueuedDpcs(); + + p_timer->pfn_callback = NULL; +} + + +cl_status_t +cl_timer_start( + IN cl_timer_t* const p_timer, + IN const uint32_t time_ms ) +{ + LARGE_INTEGER due_time; + uint64_t timeout_time; + KLOCK_QUEUE_HANDLE hlock; + + CL_ASSERT( p_timer ); + CL_ASSERT( p_timer->pfn_callback ); + CL_ASSERT( KeGetCurrentIrql() <= DISPATCH_LEVEL ); + + /* Due time is in 100 ns increments. Negative for relative time. */ + due_time.QuadPart = -(int64_t)(((uint64_t)time_ms) * 10000); + timeout_time = cl_get_time_stamp() + (((uint64_t)time_ms) * 1000); + + KeAcquireInStackQueuedSpinLock( &p_timer->spinlock, &hlock ); + p_timer->timeout_time = timeout_time; + KeSetTimer( &p_timer->timer, due_time, &p_timer->dpc ); + KeReleaseInStackQueuedSpinLock( &hlock ); + + return( CL_SUCCESS ); +} + + +cl_status_t +cl_timer_trim( + IN cl_timer_t* const p_timer, + IN const uint32_t time_ms ) +{ + LARGE_INTEGER due_time; + uint64_t timeout_time; + KLOCK_QUEUE_HANDLE hlock; + + CL_ASSERT( p_timer ); + CL_ASSERT( p_timer->pfn_callback ); + + timeout_time = cl_get_time_stamp() + (((uint64_t)time_ms) * 1000); + + /* Only pull in the timeout time. */ + KeAcquireInStackQueuedSpinLock( &p_timer->spinlock, &hlock ); + if( !p_timer->timeout_time || p_timer->timeout_time > timeout_time ) + { + p_timer->timeout_time = timeout_time; + due_time.QuadPart = -(int64_t)(((uint64_t)time_ms) * 10000); + KeSetTimer( &p_timer->timer, due_time, &p_timer->dpc ); + } + KeReleaseInStackQueuedSpinLock( &hlock ); + return( CL_SUCCESS ); +} + + +void +cl_timer_stop( + IN cl_timer_t* const p_timer ) +{ + KLOCK_QUEUE_HANDLE hlock; + + CL_ASSERT( p_timer ); + CL_ASSERT( p_timer->pfn_callback ); + CL_ASSERT( KeGetCurrentIrql() <= DISPATCH_LEVEL ); + + /* Cancel the timer. This also cancels any queued DPCs for the timer. */ + KeAcquireInStackQueuedSpinLock( &p_timer->spinlock, &hlock ); + p_timer->timeout_time = 0; + KeCancelTimer( &p_timer->timer ); + KeReleaseInStackQueuedSpinLock( &hlock ); +} diff --git a/branches/WOF2-3/core/complib/kernel/makefile b/branches/WOF2-3/core/complib/kernel/makefile new file mode 100644 index 00000000..9c985f57 --- /dev/null +++ b/branches/WOF2-3/core/complib/kernel/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the Windows NT DDK +# + +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/branches/WOF2-3/core/complib/user/SOURCES b/branches/WOF2-3/core/complib/user/SOURCES new file mode 100644 index 00000000..f960a00a --- /dev/null +++ b/branches/WOF2-3/core/complib/user/SOURCES @@ -0,0 +1,50 @@ +!if $(FREEBUILD) +TARGETNAME=complib +!else +TARGETNAME=complibd +!endif +TARGETPATH=..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE=DYNLINK +DLLENTRY=DllMain +!if $(_NT_TOOLS_VERSION) == 0x700 +# DDK +DLLDEF=$O\complib.def +!else +# WDK +DLLDEF=$(OBJ_PATH)\$O\complib.def +!endif +USE_MSVCRT=1 + +SOURCES=\ + complib.rc \ + cl_debug.c \ + cl_dll.c \ + cl_event.c \ + cl_log.c \ + cl_memory_osd.c \ + cl_syscallback.c \ + cl_thread.c \ + cl_timer.c \ + cl_nodenamemap.c \ + ..\cl_async_proc.c \ + ..\cl_list.c \ + ..\cl_map.c \ + ..\cl_memory.c \ + ..\cl_obj.c \ + ..\cl_perf.c \ + ..\cl_pool.c \ + ..\cl_ptr_vector.c \ + ..\cl_reqmgr.c \ + ..\cl_statustext.c \ + ..\cl_threadpool.c \ + ..\cl_vector.c \ + +INCLUDES=..\..\..\inc;..\..\..\inc\user;..\..\..\inc\user\linux; + +USER_C_FLAGS=$(USER_C_FLAGS) -DEXPORT_CL_SYMBOLS + +TARGETLIBS=\ + $(SDK_LIB_PATH)\advapi32.lib \ + $(SDK_LIB_PATH)\kernel32.lib + +MSC_WARNING_LEVEL= /W4 /wd4706 diff --git a/branches/WOF2-3/core/complib/user/cl_debug.c b/branches/WOF2-3/core/complib/user/cl_debug.c new file mode 100644 index 00000000..5ee2a650 --- /dev/null +++ b/branches/WOF2-3/core/complib/user/cl_debug.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + +#include "complib/cl_debug.h" +#include +#include + + +void +cl_msg_out( + IN const char* const message, + IN ... ) +{ + char buffer[256]; + + va_list args; + va_start( args, message ); + if( _vsnprintf( buffer, 256, message, args ) == -1 ) + { + /* Overflow... */ + buffer[252] = '.'; + buffer[253] = '.'; + buffer[254] = '.'; + buffer[255] = '\0'; + OutputDebugStringA( buffer ); + OutputDebugStringA( "WARNING: Buffer truncated." ); + } + OutputDebugStringA( buffer ); + va_end(args); +} + diff --git a/branches/WOF2-3/core/complib/user/cl_dll.c b/branches/WOF2-3/core/complib/user/cl_dll.c new file mode 100644 index 00000000..dbc6405e --- /dev/null +++ b/branches/WOF2-3/core/complib/user/cl_dll.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include + + +static BOOL +_DllMain( + IN HINSTANCE h_module, + IN DWORD ul_reason_for_call, + IN LPVOID lp_reserved ) +{ + UNUSED_PARAM( lp_reserved ); + + switch( ul_reason_for_call ) + { + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls( h_module ); + __cl_mem_track( TRUE ); + break; + + case DLL_PROCESS_DETACH: + __cl_mem_track( FALSE ); + } + return TRUE; +} + + +extern BOOL APIENTRY +_DllMainCRTStartupForGS( + IN HINSTANCE h_module, + IN DWORD ul_reason_for_call, + IN LPVOID lp_reserved ); + + +BOOL APIENTRY +DllMain( + IN HINSTANCE h_module, + IN DWORD ul_reason_for_call, + IN LPVOID lp_reserved ) +{ + switch( ul_reason_for_call ) + { + case DLL_PROCESS_ATTACH: + if( !_DllMainCRTStartupForGS( + h_module, ul_reason_for_call, lp_reserved ) ) + { + return FALSE; + } + + return _DllMain( h_module, ul_reason_for_call, lp_reserved ); + + case DLL_PROCESS_DETACH: + _DllMain( h_module, ul_reason_for_call, lp_reserved ); + + return _DllMainCRTStartupForGS( + h_module, ul_reason_for_call, lp_reserved ); + } + return TRUE; +} + diff --git a/branches/WOF2-3/core/complib/user/cl_event.c b/branches/WOF2-3/core/complib/user/cl_event.c new file mode 100644 index 00000000..2ec5b1cd --- /dev/null +++ b/branches/WOF2-3/core/complib/user/cl_event.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + +#include "complib/cl_event.h" + + +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 ) +{ + DWORD wait_ms; + + CL_ASSERT( p_event ); + CL_ASSERT( *p_event ); + + if( wait_us == EVENT_NO_TIMEOUT ) + wait_ms = INFINITE; + else + wait_ms = (DWORD)(wait_us / 1000); + + switch( WaitForSingleObjectEx( *p_event, wait_ms, interruptible ) ) + { + case WAIT_OBJECT_0: + return( CL_SUCCESS ); + case WAIT_IO_COMPLETION: + return( CL_NOT_DONE ); + case WAIT_TIMEOUT: + return( CL_TIMEOUT ); + default: + return( CL_ERROR ); + } +} diff --git a/branches/WOF2-3/core/complib/user/cl_log.c b/branches/WOF2-3/core/complib/user/cl_log.c new file mode 100644 index 00000000..a5821814 --- /dev/null +++ b/branches/WOF2-3/core/complib/user/cl_log.c @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + +#include "complib/cl_log.h" + + +void +cl_log_event( + IN const char* const name, + IN const cl_log_type_t type, + IN const char* const p_message, + IN const void* const p_data, + IN const uint32_t data_len ) +{ + HANDLE h; + WORD log_type; + WORD num_str = 0; + + h = RegisterEventSource( NULL, name ); + + if( !h ) + return; + + switch( type ) + { + case CL_LOG_ERROR: + log_type = EVENTLOG_ERROR_TYPE; + break; + + case CL_LOG_WARN: + log_type = EVENTLOG_WARNING_TYPE; + break; + + default: + case CL_LOG_INFO: + log_type = EVENTLOG_INFORMATION_TYPE; + break; + } + + if( p_message ) + num_str = 1; + + /* User the ASCII version of ReportEvent. */ + ReportEventA( h, log_type, 0, 0, NULL, num_str, data_len, + (LPCTSTR*)&p_message, (LPVOID)p_data ); + + DeregisterEventSource( h ); +} diff --git a/branches/WOF2-3/core/complib/user/cl_memory_osd.c b/branches/WOF2-3/core/complib/user/cl_memory_osd.c new file mode 100644 index 00000000..643e1b26 --- /dev/null +++ b/branches/WOF2-3/core/complib/user/cl_memory_osd.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + +#include "complib/cl_memory.h" +#include "stdlib.h" + + +void* +__cl_malloc_priv( + IN const size_t size, + IN const boolean_t pageable ) +{ + UNUSED_PARAM( pageable ); + return( HeapAlloc( GetProcessHeap(), 0, size ) ); +} + + +void +__cl_free_priv( + IN void* const p_memory ) +{ + HeapFree( GetProcessHeap(), 0, p_memory ); +} + diff --git a/branches/WOF2-3/core/complib/user/cl_nodenamemap.c b/branches/WOF2-3/core/complib/user/cl_nodenamemap.c new file mode 100644 index 00000000..c3b6d65d --- /dev/null +++ b/branches/WOF2-3/core/complib/user/cl_nodenamemap.c @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2007 Lawrence Livermore National Lab + * Copyright (c) 2009 Intel Corp., Inc. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#include +#include +#include <_string.h> +#include + +#include + +static int map_name(void *cxt, uint64_t guid, char *p) +{ + cl_qmap_t *map = cxt; + name_map_item_t *item; + + p = strtok(p, "\"#"); + if (!p) + return 0; + + item = malloc(sizeof(*item)); + if (!item) + return -1; + item->guid = guid; + item->name = strdup(p); + cl_qmap_insert(map, item->guid, (cl_map_item_t *)item); + return 0; +} + +nn_map_t * +open_node_name_map(char *node_name_map) +{ + nn_map_t *map; + + if (!node_name_map) { +#ifdef HAVE_DEFAULT_NODENAME_MAP + struct stat buf; + node_name_map = HAVE_DEFAULT_NODENAME_MAP; + if (stat(node_name_map, &buf)) + return NULL; +#else + return NULL; +#endif /* HAVE_DEFAULT_NODENAME_MAP */ + } + + map = malloc(sizeof(*map)); + if (!map) + return NULL; + cl_qmap_init(map); + + if (parse_node_map(node_name_map, map_name, map)) { + fprintf(stderr, + "WARNING failed to open node name map \"%s\" (%s)\n", + node_name_map, strerror(errno)); + close_node_name_map(map); + return NULL; + } + + return map; +} + +void +close_node_name_map(nn_map_t *map) +{ + name_map_item_t *item = NULL; + + if (!map) + return; + + item = (name_map_item_t *)cl_qmap_head(map); + while (item != (name_map_item_t *)cl_qmap_end(map)) { + item = (name_map_item_t *)cl_qmap_remove(map, item->guid); + free(item->name); + free(item); + item = (name_map_item_t *)cl_qmap_head(map); + } + free(map); +} + +char * +remap_node_name(nn_map_t *map, uint64_t target_guid, char *nodedesc) +{ + char *rc = NULL; + name_map_item_t *item = NULL; + + if (!map) + goto done; + + item = (name_map_item_t *)cl_qmap_get(map, target_guid); + if (item != (name_map_item_t *)cl_qmap_end(map)) + rc = strdup(item->name); + +done: + if (rc == NULL) + rc = strdup(clean_nodedesc(nodedesc)); + return (rc); +} + +char * +clean_nodedesc(char *nodedesc) +{ + int i = 0; + + nodedesc[63] = '\0'; + while (nodedesc[i]) { + if (!isprint(nodedesc[i])) + nodedesc[i] = ' '; + i++; + } + + return (nodedesc); +} + +int parse_node_map(const char *file_name, + int (*create)(void *, uint64_t, char *), void *cxt) +{ + char line[256]; + FILE *f; + + if (!(f = fopen(file_name, "r"))) + return -1; + + while (fgets(line, sizeof(line), f)) { + uint64_t guid; + char *p, *e; + + p = line; + while (isspace(*p)) + p++; + if (*p == '\0' || *p == '\n' || *p == '#') + continue; + + guid = strtoull(p, &e, 0); + if (e == p || (!isspace(*e) && *e != '#' && *e != '\0')) { + fclose(f); + return -1; + } + + p = e; + while (isspace(*p)) + p++; + + e = strpbrk(p, "\n"); + if (e) + *e = '\0'; + + if (create(cxt, guid, p)) { + fclose(f); + return -1; + } + } + + fclose(f); + return 0; +} diff --git a/branches/WOF2-3/core/complib/user/cl_syscallback.c b/branches/WOF2-3/core/complib/user/cl_syscallback.c new file mode 100644 index 00000000..feec61ce --- /dev/null +++ b/branches/WOF2-3/core/complib/user/cl_syscallback.c @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + +#include "complib/cl_syscallback.h" +#include "complib/cl_memory.h" + + +/* + * Callback function invoked by the thread pool in response to a + * call to QueueUserWorkItem. + */ +static DWORD WINAPI +cl_sys_callback_wrapper( + IN cl_sys_callback_item_t* const p_item ) +{ + CL_ASSERT( p_item ); + + p_item->pfn_callback( (void*)p_item->get_context, + (void*)p_item->queue_context ); + + return( 0 ); +} + + +/* The OS porvides the thread pool, so this is a no-op. */ +cl_status_t +cl_sys_callback_init( void ) +{ + return( CL_SUCCESS ); +} + + +/* The OS porvides the thread pool, so this is a no-op. */ +void +cl_sys_callback_destroy( void ) +{ +} + + +/* Note: This could be improved to pull items out of a pool. */ +cl_sys_callback_item_t* +cl_sys_callback_get( + IN const void* const get_context ) +{ + cl_sys_callback_item_t *p_item; + + p_item = (cl_sys_callback_item_t*) + cl_zalloc( sizeof(cl_sys_callback_item_t) ); + + if( !p_item ) + return( NULL ); + + p_item->get_context = get_context; + + return p_item; +} + + +void +cl_sys_callback_put( + IN cl_sys_callback_item_t* const p_item ) +{ + CL_ASSERT( p_item ); + cl_free( p_item ); +} + + +cl_status_t +cl_sys_callback_queue( + IN cl_sys_callback_item_t* const p_item, + IN cl_pfn_sys_callback_t pfn_callback, + IN const void* const queue_context, + IN const boolean_t high_priority ) +{ + ULONG flags; + + /* Store the callback and context in the item */ + p_item->pfn_callback = pfn_callback; + p_item->queue_context = queue_context; + + /* Execute as an APC if the requested priority is high. */ + if( high_priority ) + flags = WT_EXECUTEINIOTHREAD; + else + flags = WT_EXECUTEDEFAULT; + + /* Queue the internal callback with a pointer to the callback item. */ + if( !QueueUserWorkItem( cl_sys_callback_wrapper, p_item, flags ) ) + return( CL_ERROR ); + + return( CL_SUCCESS ); +} diff --git a/branches/WOF2-3/core/complib/user/cl_thread.c b/branches/WOF2-3/core/complib/user/cl_thread.c new file mode 100644 index 00000000..2edaee95 --- /dev/null +++ b/branches/WOF2-3/core/complib/user/cl_thread.c @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + +#include "complib/cl_thread.h" +#include + + +static DWORD WINAPI +cl_thread_callback( + IN cl_thread_t* p_thread ) +{ + /* Call the user's thread function. */ + (*p_thread->pfn_callback)( (void*)p_thread->context ); + + /* + * Use endthreadex so that the thread handle is not closed. It will + * be closed in the cl_thread_destroy. + */ + ExitThread( 0 ); +} + + +void +cl_thread_construct( + IN cl_thread_t* const p_thread ) +{ + p_thread->osd.h_thread = NULL; + p_thread->osd.thread_id = 0; +} + + +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 ) +{ + CL_ASSERT( p_thread && pfn_callback ); + + UNUSED_PARAM( name ); + + cl_thread_construct( p_thread ); + + p_thread->pfn_callback = pfn_callback; + p_thread->context = context; + + /* Create a new thread, storing both the handle and thread id. */ + p_thread->osd.h_thread = (HANDLE)CreateThread( NULL, 0, + cl_thread_callback, p_thread, 0, &p_thread->osd.thread_id ); + + if( !p_thread->osd.h_thread ) + return( CL_ERROR ); + + return( CL_SUCCESS ); +} + + +void +cl_thread_destroy( + IN cl_thread_t* const p_thread ) +{ + CL_ASSERT( p_thread ); + + if( !p_thread->osd.h_thread ) + return; + + /* Wait for the thread to exit. */ + WaitForSingleObject( p_thread->osd.h_thread, INFINITE ); + + /* Close the handle to the thread. */ + CloseHandle( p_thread->osd.h_thread ); + + /* + * Reset the handle in case the user calls destroy and the thread is + * no longer active. + */ + p_thread->osd.h_thread = NULL; +} + + +uint32_t +cl_proc_count( void ) +{ + SYSTEM_INFO system_info; + + GetSystemInfo( &system_info ); + return system_info.dwNumberOfProcessors; +} + + +boolean_t +cl_is_current_thread( + IN const cl_thread_t* const p_thread ) +{ + return( p_thread->osd.thread_id == GetCurrentThreadId() ); +} \ No newline at end of file diff --git a/branches/WOF2-3/core/complib/user/cl_timer.c b/branches/WOF2-3/core/complib/user/cl_timer.c new file mode 100644 index 00000000..5cab378a --- /dev/null +++ b/branches/WOF2-3/core/complib/user/cl_timer.c @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + +#include "complib/cl_timer.h" + + +#define CL_MAX_TIME 0xFFFFFFFF + + +/* + * If timeout_time is 0, the timer has been stopped. + */ +static void CALLBACK +__timer_callback( + IN cl_timer_t* const p_timer, + IN BOOLEAN timer_signalled ) +{ + uint64_t timeout; + UNUSED_PARAM( timer_signalled ); + + EnterCriticalSection( &p_timer->cb_lock ); + EnterCriticalSection( &p_timer->lock ); + timeout = p_timer->timeout_time; + p_timer->timeout_time = 0; + LeaveCriticalSection( &p_timer->lock ); + + if( timeout ) + (p_timer->pfn_callback)( (void*)p_timer->context ); + LeaveCriticalSection( &p_timer->cb_lock ); +} + + +void +cl_timer_construct( + IN cl_timer_t* const p_timer ) +{ + memset(p_timer, 0, sizeof *p_timer); +} + + + +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 ); + + p_timer->pfn_callback = pfn_callback; + p_timer->context = context; + InitializeCriticalSection( &p_timer->lock ); + InitializeCriticalSection( &p_timer->cb_lock ); + if( !CreateTimerQueueTimer( &p_timer->h_timer, NULL, __timer_callback, + p_timer, CL_MAX_TIME, CL_MAX_TIME, WT_EXECUTEINIOTHREAD ) ) + return CL_ERROR; + return( CL_SUCCESS ); +} + + +void +cl_timer_destroy( + IN cl_timer_t* const p_timer ) +{ + CL_ASSERT( p_timer ); + + DeleteTimerQueueTimer( NULL, p_timer->h_timer, INVALID_HANDLE_VALUE ); + DeleteCriticalSection( &p_timer->lock ); + DeleteCriticalSection( &p_timer->cb_lock ); +} + + +cl_status_t +cl_timer_start( + IN cl_timer_t* const p_timer, + IN const uint32_t time_ms ) +{ + return cl_timer_trim( p_timer, time_ms ); +} + + +cl_status_t +cl_timer_trim( + IN cl_timer_t* const p_timer, + IN const uint32_t time_ms ) +{ + uint64_t timeout; + cl_status_t status = CL_SUCCESS; + + CL_ASSERT( p_timer ); + CL_ASSERT( p_timer->pfn_callback ); + + EnterCriticalSection( &p_timer->lock ); + timeout = cl_get_time_stamp() + (((uint64_t)time_ms) * 1000); + if ( !p_timer->timeout_time || timeout < p_timer->timeout_time ) + { + if( ChangeTimerQueueTimer( NULL, p_timer->h_timer, time_ms, CL_MAX_TIME ) ) + p_timer->timeout_time = timeout; + else + status = CL_ERROR; + } + LeaveCriticalSection( &p_timer->lock ); + return status; +} + + +/* + * Acquire cb_lock to ensure that all callbacks have completed. + */ +void +cl_timer_stop( + IN cl_timer_t* const p_timer ) +{ + CL_ASSERT( p_timer ); + + EnterCriticalSection( &p_timer->cb_lock ); + EnterCriticalSection( &p_timer->lock ); + p_timer->timeout_time = 0; + ChangeTimerQueueTimer( NULL, p_timer->h_timer, CL_MAX_TIME, CL_MAX_TIME ); + LeaveCriticalSection( &p_timer->lock ); + LeaveCriticalSection( &p_timer->cb_lock ); +} + + +#define SEC_TO_MICRO CL_CONST64(1000000) // s to µs conversion + +uint64_t +cl_get_time_stamp( void ) +{ + LARGE_INTEGER tick_count, frequency; + + if( !QueryPerformanceFrequency( &frequency ) ) + return( 0 ); + + if( !QueryPerformanceCounter( &tick_count ) ) + return( 0 ); + + return( SEC_TO_MICRO * tick_count.QuadPart / frequency.QuadPart ); +} + +uint32_t +cl_get_time_stamp_sec( void ) +{ + return( (uint32_t)(cl_get_time_stamp() / SEC_TO_MICRO) ); +} + + +uint64_t +cl_get_tick_count( void ) +{ + LARGE_INTEGER tick_count; + + if( !QueryPerformanceCounter( &tick_count ) ) + return( 0 ); + + return tick_count.QuadPart; +} + + +uint64_t +cl_get_tick_freq( void ) +{ + LARGE_INTEGER frequency; + + if( !QueryPerformanceFrequency( &frequency ) ) + return( 0 ); + + return frequency.QuadPart; +} diff --git a/branches/WOF2-3/core/complib/user/complib.rc b/branches/WOF2-3/core/complib/user/complib.rc new file mode 100644 index 00000000..6237874c --- /dev/null +++ b/branches/WOF2-3/core/complib/user/complib.rc @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef _DEBUG_ +#define VER_FILEDESCRIPTION_STR "Component Library (Debug)" +#define VER_INTERNALNAME_STR "complibd.dll" +#define VER_ORIGINALFILENAME_STR "complibd.dll" +#else +#define VER_FILEDESCRIPTION_STR "Component Library" +#define VER_INTERNALNAME_STR "complib.dll" +#define VER_ORIGINALFILENAME_STR "complib.dll" +#endif + +#include diff --git a/branches/WOF2-3/core/complib/user/complib.src b/branches/WOF2-3/core/complib/user/complib.src new file mode 100644 index 00000000..58416100 --- /dev/null +++ b/branches/WOF2-3/core/complib/user/complib.src @@ -0,0 +1,298 @@ +#if DBG +LIBRARY complibd.dll +#else +LIBRARY complib.dll +#endif + +#ifndef _WIN64 +EXPORTS +__cl_free_ntrk +__cl_free_trk +__cl_malloc_ntrk +__cl_malloc_trk +__cl_mem_track +__cl_perf_construct +__cl_perf_destroy +__cl_perf_display +__cl_perf_init +__cl_perf_reset +__cl_primitive_insert +__cl_primitive_remove +__cl_qlist_reset +__cl_zalloc_ntrk +__cl_zalloc_trk +cl_async_proc_construct +cl_async_proc_init +cl_async_proc_destroy +cl_async_proc_queue +cl_atomic_inc +cl_atomic_dec +cl_atomic_add +cl_atomic_sub +cl_atomic_xchg +cl_atomic_comp_xchg +cl_ntoh +cl_cpool_construct +cl_is_cpool_inited +cl_cpool_init +cl_cpool_destroy +cl_cpool_count +cl_cpool_get +cl_cpool_put +cl_cpool_grow +cl_msg_out +cl_event_construct +cl_event_init +cl_event_destroy +cl_event_signal +cl_event_reset +cl_event_wait_on +cl_fmap_count +cl_is_fmap_empty +cl_fmap_key +cl_fmap_init +cl_fmap_end +cl_fmap_head +cl_fmap_tail +cl_fmap_next +cl_fmap_prev +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_apply_func +cl_ioctl_request +cl_ioctl_result +cl_list_construct +cl_is_list_inited +cl_list_init +cl_list_destroy +cl_is_list_empty +cl_list_insert_head +cl_list_insert_tail +cl_list_insert_array_head +cl_list_insert_array_tail +cl_list_insert_next +cl_list_insert_prev +cl_list_remove_head +cl_list_remove_tail +cl_list_remove_all +cl_list_remove_object +cl_list_remove_item +cl_is_object_in_list +cl_list_end +cl_list_head +cl_list_tail +cl_list_next +cl_list_prev +cl_list_obj +cl_list_find_from_head +cl_list_find_from_tail +cl_list_apply_func +cl_list_count +cl_log_event +cl_map_count +cl_is_map_empty +cl_map_key +cl_map_construct +cl_is_map_inited +cl_map_init +cl_map_destroy +cl_map_end +cl_map_head +cl_map_tail +cl_map_next +cl_map_prev +cl_map_insert +cl_map_get +cl_map_remove_item +cl_map_remove +cl_map_remove_all +cl_map_obj +cl_map_merge +cl_map_delta +cl_mem_display +cl_memset +cl_memclr +cl_memcpy +cl_memcmp +cl_mutex_construct +cl_mutex_init +cl_mutex_destroy +cl_mutex_acquire +cl_mutex_release +cl_obj_mgr_create +cl_obj_mgr_destroy +cl_obj_construct +cl_obj_init +cl_obj_destroy +cl_obj_deinit +cl_obj_reset +cl_obj_ref +cl_obj_deref +cl_obj_type +cl_obj_lock +cl_obj_unlock +cl_rel_alloc +cl_rel_free +cl_obj_insert_rel +cl_obj_remove_rel +cl_plock_construct +cl_plock_destroy +cl_plock_init +cl_plock_acquire +cl_plock_excl_acquire +cl_plock_release +cl_pool_construct +cl_is_pool_inited +cl_pool_init +cl_pool_destroy +cl_pool_count +cl_pool_get +cl_pool_put +cl_pool_grow +cl_ptr_vector_construct +cl_ptr_vector_init +cl_ptr_vector_destroy +cl_ptr_vector_get_capacity +cl_ptr_vector_get_size +cl_ptr_vector_get +cl_ptr_vector_at +cl_ptr_vector_set +cl_ptr_vector_insert +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_qcpool_construct +cl_is_qcpool_inited +cl_qcpool_init +cl_qcpool_destroy +cl_qcpool_count +cl_qcpool_get +cl_qcpool_put +cl_qcpool_put_list +cl_qcpool_grow +cl_qlist_set_obj +cl_qlist_obj +cl_qlist_init +cl_qlist_count +cl_is_qlist_empty +cl_qlist_next +cl_qlist_prev +cl_qlist_head +cl_qlist_tail +cl_qlist_end +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 +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 +cl_qmap_count +cl_is_qmap_empty +cl_qmap_set_obj +cl_qmap_obj +cl_qmap_key +cl_qmap_init +cl_qmap_end +cl_qmap_head +cl_qmap_tail +cl_qmap_next +cl_qmap_prev +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_apply_func +cl_qpool_construct +cl_is_qpool_inited +cl_qpool_init +cl_qpool_destroy +cl_qpool_count +cl_qpool_get +cl_qpool_put +cl_qpool_put_list +cl_qpool_grow +cl_req_mgr_construct +cl_req_mgr_init +cl_req_mgr_destroy +cl_req_mgr_get +cl_req_mgr_resume +cl_spinlock_construct +cl_spinlock_init +cl_spinlock_destroy +cl_spinlock_acquire +cl_spinlock_release +cl_sys_callback_get +cl_sys_callback_put +cl_sys_callback_queue +cl_thread_construct +cl_thread_init +cl_thread_destroy +cl_thread_suspend +cl_thread_stall +cl_proc_count +cl_is_current_thread +cl_is_blockable +cl_thread_pool_construct +cl_thread_pool_init +cl_thread_pool_destroy +cl_thread_pool_signal +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_is_state_valid +cl_vector_construct +cl_vector_init +cl_vector_destroy +cl_vector_get_capacity +cl_vector_get_size +cl_vector_get_ptr +cl_vector_get +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_waitobj_create +cl_waitobj_destroy +cl_waitobj_signal +cl_waitobj_reset +cl_waitobj_wait_on +clean_nodedesc +open_node_name_map +close_node_name_map +remap_node_name +parse_node_map +#endif diff --git a/branches/WOF2-3/core/complib/user/makefile b/branches/WOF2-3/core/complib/user/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-3/core/complib/user/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\inc\openib.def diff --git a/branches/WOF2-3/core/dirs b/branches/WOF2-3/core/dirs new file mode 100644 index 00000000..73c7806e --- /dev/null +++ b/branches/WOF2-3/core/dirs @@ -0,0 +1,8 @@ +DIRS=\ + complib \ + al \ + bus \ + iou \ + ibat \ + winverbs \ + winmad diff --git a/branches/WOF2-3/core/ibat/dirs b/branches/WOF2-3/core/ibat/dirs new file mode 100644 index 00000000..389156fd --- /dev/null +++ b/branches/WOF2-3/core/ibat/dirs @@ -0,0 +1,2 @@ +DIRS=\ + user diff --git a/branches/WOF2-3/core/ibat/user/SOURCES b/branches/WOF2-3/core/ibat/user/SOURCES new file mode 100644 index 00000000..bc2f63af --- /dev/null +++ b/branches/WOF2-3/core/ibat/user/SOURCES @@ -0,0 +1,9 @@ +TARGETNAME = ibat + +TARGETPATH = ..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = LIBRARY + +SOURCES = ibat.cpp + +INCLUDES = ..\..\..\inc;..\..\..\inc\user; +MSC_WARNING_LEVEL= /W4 diff --git a/branches/WOF2-3/core/ibat/user/ibat.cpp b/branches/WOF2-3/core/ibat/user/ibat.cpp new file mode 100644 index 00000000..acd11d7d --- /dev/null +++ b/branches/WOF2-3/core/ibat/user/ibat.cpp @@ -0,0 +1,412 @@ +/* + * Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id:$ + */ + +// +// IBAT: InfiniBand Address Translation +// +// Description: +// Maps source & remote IP addresses (IPv4 and IPv6) to a path record. +// +// The mapping requires two steps: +// 1. Mapping the remote IP address to the remote Ethernet MAC address +// 2. Retrieve the path given the remote Ethernet MAC address from IPoIB +// +// The first step is accomplished as follows on Windows Server 2008: +// 1. Lookup the desired MAC from the OS using GetIpNetEntry2 +// 2. If the remote IP isn't found, resolve the remote IP address +// using ResolveIpNetEntry2 +// +// The first step is accomplished as follows on Windows Server 2003: +// 1. Retrieve the whole IP->MAC mapping table from the OS using +// GetIpNetTable. +// 2. Walk the returned table looking for the destination IP to +// find the destination Ethernet MAC address. +// 3. If the remote IP isn't found, resolve the remote IP address using +// SendARP. +// +// The second step is accomplished by asking IPoIB for the path +// given the remote MAC. IPoIB creates the path internally without going to +// the SA. + +#pragma warning( push, 3 ) +#include + +#include +#include +#pragma warning( pop ) +#include "iba/ibat.h" +#include +#include "iba/ib_at_ioctl.h" + +C_ASSERT( sizeof(IBAT_PATH_BLOB) == sizeof(ib_path_rec_t) ); + +namespace IBAT +{ + + const IN6_ADDR x_DefaultGid = {0xFE,0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + +class H +{ +public: + H( HANDLE h = INVALID_HANDLE_VALUE ) : m_h( h ) {}; + ~H(){ if( m_h != INVALID_HANDLE_VALUE ) CloseHandle( m_h ); } + + H& operator =(HANDLE h){ CloseHandle( m_h ); m_h = h; } + operator HANDLE() const { return m_h; } + +private: + HANDLE m_h; +}; + +#if WINVER >= 0x600 +HRESULT +Resolve( + __in const struct sockaddr* pSrcAddr, + __in const struct sockaddr* pDestAddr, + __out IBAT_PATH_BLOB* pPath + ) +{ + if( pSrcAddr->sa_family != pDestAddr->sa_family ) + return E_INVALIDARG; + + H hIbatDev = CreateFileW( IBAT_WIN32_NAME, + MAXIMUM_ALLOWED,(FILE_SHARE_READ|FILE_SHARE_WRITE), NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); + if( hIbatDev == INVALID_HANDLE_VALUE ) + return HRESULT_FROM_WIN32( GetLastError() ); + + bool fLoopback; + IOCTL_IBAT_IP_TO_PORT_IN port_in; + port_in.Version = IBAT_IOCTL_VERSION; + if( pSrcAddr->sa_family == AF_INET ) + { + port_in.Address.IpVersion = 4; + RtlCopyMemory( + &port_in.Address.Address[12], + &((struct sockaddr_in*)pSrcAddr)->sin_addr, + sizeof( ((struct sockaddr_in*)pSrcAddr)->sin_addr ) ); + + fLoopback = ((struct sockaddr_in*)pDestAddr)->sin_addr.s_addr == + ((struct sockaddr_in*)pSrcAddr)->sin_addr.s_addr; + } + else + { + port_in.Address.IpVersion = 6; + RtlCopyMemory( + port_in.Address.Address, + &((struct sockaddr_in6*)pSrcAddr)->sin6_addr, + sizeof(port_in.Address.Address) ); + fLoopback = IN6_ADDR_EQUAL( + &((struct sockaddr_in6*)pDestAddr)->sin6_addr, + &((struct sockaddr_in6*)pSrcAddr)->sin6_addr + ) == TRUE; + } + + IBAT_PORT_RECORD port_out; + DWORD size; + BOOL fSuccess = DeviceIoControl( hIbatDev, IOCTL_IBAT_IP_TO_PORT, + &port_in, sizeof(port_in), &port_out, sizeof(port_out), &size, NULL ); + + if( !fSuccess ) + return HRESULT_FROM_WIN32( GetLastError() ); + + // Check for loopback. + IOCTL_IBAT_MAC_TO_PATH_IN mac_in = {0}; + mac_in.Version = IBAT_IOCTL_VERSION; + mac_in.PortGuid = port_out.PortGuid; + if( !fLoopback ) + { + NET_LUID luid; + DWORD ret; + do + { + DWORD iIf; + ret = GetBestInterfaceEx( (struct sockaddr*)pSrcAddr, &iIf ); + if( ret != NO_ERROR ) + return HRESULT_FROM_WIN32( ret ); + + // Interface indexes are not constant, so get the LUID mapping for the + // returned interface for use in the rest of the function. + ret = ConvertInterfaceIndexToLuid( iIf, &luid ); + + } while( ret != NO_ERROR ); + + SOCKADDR_INET src; + MIB_IPNET_ROW2 net = {0}; + net.InterfaceLuid = luid; + switch( pDestAddr->sa_family ) + { + case AF_INET: + net.Address.si_family = src.si_family = AF_INET; + net.Address.Ipv4 = *(struct sockaddr_in*)pDestAddr; + src.Ipv4 = *(struct sockaddr_in*)pSrcAddr; + break; + + case AF_INET6: + net.Address.si_family = src.si_family = AF_INET6; + net.Address.Ipv6 = *(struct sockaddr_in6*)pDestAddr; + src.Ipv6 = *(struct sockaddr_in6*)pSrcAddr; + break; + + default: + return E_INVALIDARG; + } + + bool fRetry = true; + retry: + ret = GetIpNetEntry2( &net ); + if( ret == ERROR_NOT_FOUND ) + { + net.State = NlnsUnreachable; + } + else if( ret != NO_ERROR ) + { + return HRESULT_FROM_WIN32( ret ); + } + + switch( net.State ) + { + default: + case NlnsUnreachable: + ret = ResolveIpNetEntry2( &net, &src ); + if( ret == ERROR_BAD_NET_NAME && fRetry ) + { + fRetry = false; + goto retry; + } + else if( ret != NO_ERROR ) + { + return HRESULT_FROM_WIN32( ret ); + } + break; + + case NlnsReachable: + case NlnsPermanent: + break; + + case NlnsIncomplete: + return E_PENDING; + } + + if( net.PhysicalAddressLength > 6 ) + return E_UNEXPECTED; + + RtlCopyMemory( mac_in.DestMac, net.PhysicalAddress, IBAT_MAC_LEN ); + } + + fSuccess = DeviceIoControl( hIbatDev, IOCTL_IBAT_MAC_TO_PATH, + &mac_in, sizeof(mac_in), pPath, sizeof(*pPath), &size, NULL ); + if( !fSuccess ) + return HRESULT_FROM_WIN32( GetLastError() ); + + return S_OK; +} +#else // Back compatibility with Windows Server 2003 + + +static HRESULT +GetDestMac( + __in struct sockaddr_in* pDestAddr, + __out BYTE* pDestMac + ) +{ + DWORD ret; + + MIB_IPNETTABLE* pTable = NULL; + ULONG len = 0; + do + { + ret = GetIpNetTable( pTable, &len, FALSE ); + if( ret != ERROR_INSUFFICIENT_BUFFER ) + break; + + if( pTable != NULL ) + { + HeapFree( GetProcessHeap(), 0, pTable ); + } + + pTable = (MIB_IPNETTABLE*)HeapAlloc( GetProcessHeap(), 0, len ); + } while( ret == ERROR_INSUFFICIENT_BUFFER ); + + if( ret != NO_ERROR ) + { + if( pTable != NULL ) + { + HeapFree( GetProcessHeap(), 0, pTable ); + } + return HRESULT_FROM_WIN32( ret ); + } + + ret = ERROR_NOT_SUPPORTED; + DWORD i; + for( i = 0; i < pTable->dwNumEntries; i++ ) + { + if( pTable->table[i].dwType == MIB_IPNET_TYPE_OTHER || + pTable->table[i].dwType == MIB_IPNET_TYPE_INVALID ) + { + continue; + } + + if( pTable->table[i].dwAddr != + ((struct sockaddr_in*)pDestAddr)->sin_addr.s_addr ) + { + continue; + } + + if( pTable->table[i].dwPhysAddrLen != IBAT_MAC_LEN ) + { + continue; + } + + RtlCopyMemory( pDestMac, pTable->table[i].bPhysAddr, IBAT_MAC_LEN ); + ret = S_OK; + break; + } + HeapFree( GetProcessHeap(), 0, pTable ); + + return HRESULT_FROM_WIN32( ret ); +} + +HRESULT +Resolve( + __in const struct sockaddr* pSrcAddr, + __in const struct sockaddr* pDestAddr, + __out IBAT_PATH_BLOB* pPath + ) +{ + if( pDestAddr->sa_family != AF_INET ) + return E_NOTIMPL; + + H hIbatDev = CreateFileW( IBAT_WIN32_NAME, + MAXIMUM_ALLOWED,(FILE_SHARE_READ|FILE_SHARE_WRITE), NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); + if( hIbatDev == INVALID_HANDLE_VALUE ) + return HRESULT_FROM_WIN32( GetLastError() ); + + IOCTL_IBAT_IP_TO_PORT_IN port_in; + port_in.Version = IBAT_IOCTL_VERSION; + port_in.Address.IpVersion = 4; + RtlCopyMemory( + &port_in.Address.Address[12], + &((struct sockaddr_in*)pSrcAddr)->sin_addr, + sizeof( ((struct sockaddr_in*)pSrcAddr)->sin_addr ) ); + + IBAT_PORT_RECORD port_out; + DWORD size; + BOOL fSuccess = DeviceIoControl( hIbatDev, IOCTL_IBAT_IP_TO_PORT, + &port_in, sizeof(port_in), &port_out, sizeof(port_out), &size, NULL ); + + if( !fSuccess ) + return HRESULT_FROM_WIN32( GetLastError() ); + + // Check for loopback. + IOCTL_IBAT_MAC_TO_GID_IN mac_in = {0}; + mac_in.Version = IBAT_IOCTL_VERSION; + mac_in.PortGuid = port_out.PortGuid; + + if( ((struct sockaddr_in*)pDestAddr)->sin_addr.s_addr != + ((struct sockaddr_in*)pSrcAddr)->sin_addr.s_addr ) + { + HRESULT hr = GetDestMac( (struct sockaddr_in*)pDestAddr, mac_in.DestMac ); + if( FAILED( hr ) ) + { + ULONG len = sizeof(mac_in.DestMac); + DWORD ret = SendARP( + ((struct sockaddr_in*)pDestAddr)->sin_addr.s_addr, + ((struct sockaddr_in*)pSrcAddr)->sin_addr.s_addr, + (ULONG*)mac_in.DestMac, + &len + ); + if( ret != NO_ERROR ) + return HRESULT_FROM_WIN32( ret ); + } + } + + fSuccess = DeviceIoControl( hIbatDev, IOCTL_IBAT_MAC_TO_PATH, + &mac_in, sizeof(mac_in), pPath, sizeof(*pPath), &size, NULL ); + if( !fSuccess ) + return HRESULT_FROM_WIN32( GetLastError() ); + + return S_OK; +} + +#endif // WINVER >= 0x600 + + +HRESULT +ResolvePath( + __in const struct sockaddr* pSrcAddr, + __in const struct sockaddr* pDestAddr, + __out IBAT_PATH_BLOB* pPath, + __in DWORD Timeout) +{ + INT64 to; + HRESULT hr; + + to = (Timeout == INFINITE) ? 0x7FFFFFFFFFFFFFFFL : (INT64) ((UINT64) Timeout); + for (;;) { + hr = Resolve(pSrcAddr, pDestAddr, pPath); + if( hr != E_PENDING || to <= 0 ) + break; + + to -= 10; + Sleep(10); + }; + + return hr; +} + +} /* IBAT namespace */ + +extern "C" +{ + +HRESULT +IbatResolve( + __in const struct sockaddr* pSrcAddr, + __in const struct sockaddr* pDestAddr, + __out IBAT_PATH_BLOB* pPath + ) +{ + return IBAT::Resolve( pSrcAddr, pDestAddr, pPath ); +} + +HRESULT +IbatResolvePath( + __in const struct sockaddr* pSrcAddr, + __in const struct sockaddr* pDestAddr, + __out IBAT_PATH_BLOB* pPath, + __in DWORD Timeout) +{ + return IBAT::ResolvePath(pSrcAddr, pDestAddr, pPath, Timeout); +} + +} /* extern "C" */ diff --git a/branches/WOF2-3/core/ibat/user/makefile b/branches/WOF2-3/core/ibat/user/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-3/core/ibat/user/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\inc\openib.def diff --git a/branches/WOF2-3/core/iou/dirs b/branches/WOF2-3/core/iou/dirs new file mode 100644 index 00000000..ed41dcf4 --- /dev/null +++ b/branches/WOF2-3/core/iou/dirs @@ -0,0 +1,2 @@ +DIRS=\ + kernel diff --git a/branches/WOF2-3/core/iou/kernel/SOURCES b/branches/WOF2-3/core/iou/kernel/SOURCES new file mode 100644 index 00000000..1a628db1 --- /dev/null +++ b/branches/WOF2-3/core/iou/kernel/SOURCES @@ -0,0 +1,52 @@ +TARGETNAME=ibiou +TARGETPATH=..\..\..\bin\kernel\obj$(BUILD_ALT_DIR) +TARGETTYPE=DRIVER + +!if $(_NT_TOOLS_VERSION) != 0x700 +# WDK build only - transform .inx --> .inf adding date & version stamp. +# see .\makefile.inc +INF_NAME=ib_iou +INF_TARGET=..\..\..\bin\kernel\$(O)\$(INF_NAME).inf +NTTARGETFILES=$(INF_TARGET) +!endif + +!if $(FREEBUILD) +ENABLE_EVENT_TRACING=1 +!else +#ENABLE_EVENT_TRACING=1 +!endif + + +SOURCES= ibiou.rc \ + iou_driver.c \ + iou_pnp.c \ + iou_ioc_mgr.c + +INCLUDES=..\..\..\inc;..\..\..\inc\kernel;..\..\..\core\al + +C_DEFINES=$(C_DEFINES) -DDRIVER -DDEPRECATE_DDK_FUNCTIONS -DNEED_CL_OBJ -DWPP_OLDCC + + +TARGETLIBS= \ + $(TARGETPATH)\*\complib.lib + +!if !defined(DDK_TARGET_OS) || "$(DDK_TARGET_OS)"=="Win2K" +# +# The driver is built in the Win2K build environment +# - use the library version of safe strings +# +TARGETLIBS= $(TARGETLIBS) $(DDK_LIB_PATH)\ntstrsafe.lib +!endif + +!IFDEF ENABLE_EVENT_TRACING + +C_DEFINES = $(C_DEFINES) -DEVENT_TRACING + +RUN_WPP = $(SOURCES) -km -ext: .c .h .C .H \ + -scan:iou_driver.h \ + -func:IOU_PRINT(LEVEL,FLAGS,(MSG,...)) \ + -func:IOU_PRINT_EXIT(LEVEL,FLAGS,(MSG,...)) + +!ENDIF + +MSC_WARNING_LEVEL= /W4 diff --git a/branches/WOF2-3/core/iou/kernel/ib_iou.cdf b/branches/WOF2-3/core/iou/kernel/ib_iou.cdf new file mode 100644 index 00000000..ecc21ac2 --- /dev/null +++ b/branches/WOF2-3/core/iou/kernel/ib_iou.cdf @@ -0,0 +1,8 @@ +[CatalogHeader] +Name=ib_iou.cat +PublicVersion=0x0000001 +EncodingType=0x00010001 +CATATTR1=0x10010001:OSAttr:2:6.0 +[CatalogFiles] +ib_iou.inf=ib_iou.inf +ibiou.sys=ibiou.sys diff --git a/branches/WOF2-3/core/iou/kernel/ib_iou.inx b/branches/WOF2-3/core/iou/kernel/ib_iou.inx new file mode 100644 index 00000000..08fe50bb --- /dev/null +++ b/branches/WOF2-3/core/iou/kernel/ib_iou.inx @@ -0,0 +1,128 @@ +; OpenIB InfiniBand IOU Driver. +; Copyright 2005 SilverStorm Technologies all Rights Reserved. +; Copyright 2006 Mellanox Technologies all Rights Reserved. + +[Version] +Signature="$Windows NT$" +Class=System +ClassGuid={4D36E97D-E325-11CE-BFC1-08002BE10318} +Provider=%OPENIB% +DriverVer=04/29/2008,1.1.0000.1085 +CatalogFile=ib_iou.cat + +; ================= Device Install section ===================== + +; 64-bit platforms also copy 32-bit user-mode binaries. +[DestinationDirs] +DefaultDestDir=%DIRID_DRIVERS% + +[SourceDisksNames.x86] +1=%DiskId%,,,"" + +[SourceDisksNames.amd64] +1=%DiskId%,,,"" + +[SourceDisksNames.ia64] +1=%DiskId%,,,"" + +[SourceDisksFiles.x86] +ibiou.sys=1 + +[SourceDisksFiles.amd64] +ibiou.sys=1 + +[SourceDisksFiles.ia64] +ibiou.sys=1 + +[Manufacturer] +%OPENIB% = GenIOU.DeviceSection,ntx86,ntamd64,ntia64 +%SST% = QLogicIOU.DeviceSection,ntx86,ntamd64,ntia64 + +[GenIOU.DeviceSection] +; empty since we don't support W9x/Me + +[GenIOU.DeviceSection.ntx86] +%Iou.DeviceDesc% = Iou.DDInstall,IBA\IB_IOU + +[GenIOU.DeviceSection.ntamd64] +%Iou.DeviceDesc% = Iou.DDInstall,IBA\IB_IOU + +[GenIOU.DeviceSection.ntia64] +%Iou.DeviceDesc% = Iou.DDInstall,IBA\IB_IOU + +[QLogicIOU.DeviceSection] +; empty since we don't support W9x/Me + +[QLogicIOU.DeviceSection.ntx86] +%VFx.DeviceDesc% = Iou.DDInstall,IBA\V00066aP0060,IBA\V00066aP0010 +%VEx.DeviceDesc% = Iou.DDInstall,IBA\V00066aP0058 +%FVIC.DeviceDesc% = Iou.DDInstall,IBA\V00066aP00dd +%EVIC.DeviceDesc% = Iou.DDInstall,IBA\V00066aP00de +%BC2FC.DeviceDesc% = Iou.DDInstall,IBA\V00066aP00e0 +%BC2GE.DeviceDesc% = Iou.DDInstall,IBA\V00066aP00e1 + +[QLogicIOU.DeviceSection.ntamd64] +%VFx.DeviceDesc% = Iou.DDInstall,IBA\V00066aP0060,IBA\V00066aP0010 +%VEx.DeviceDesc% = Iou.DDInstall,IBA\V00066aP0058 +%FVIC.DeviceDesc% = Iou.DDInstall,IBA\V00066aP00dd +%EVIC.DeviceDesc% = Iou.DDInstall,IBA\V00066aP00de +%BC2FC.DeviceDesc% = Iou.DDInstall,IBA\V00066aP00e0 +%BC2GE.DeviceDesc% = Iou.DDInstall,IBA\V00066aP00e1 + +[QLogicIOU.DeviceSection.ntia64] +%VFx.DeviceDesc% = Iou.DDInstall,IBA\V00066aP0060,IBA\V00066aP0010 +%VEx.DeviceDesc% = Iou.DDInstall,IBA\V00066aP0058 +%FVIC.DeviceDesc% = Iou.DDInstall,IBA\V00066aP00dd +%EVIC.DeviceDesc% = Iou.DDInstall,IBA\V00066aP00de +%BC2FC.DeviceDesc% = Iou.DDInstall,IBA\V00066aP00e0 +%BC2GE.DeviceDesc% = Iou.DDInstall,IBA\V00066aP00e1 + +[Iou.DDInstall.nt] +CopyFiles = Iou.CopyFiles + +[Iou.DDInstall.nt.Services] +AddService = ibiou,%SPSVCINST_ASSOCSERVICE%,Iou.ServiceInstall +;AddService = ibiou,,Iou.ServiceInstall + +[Iou.CopyFiles] +ibiou.sys + +; +; ============= Service Install section ============== +; + +[Iou.ServiceInstall] +DisplayName = %Iou.ServiceDesc% +ServiceType = %SERVICE_KERNEL_DRIVER% +StartType = %SERVICE_DEMAND_START% +ErrorControl = %SERVICE_ERROR_NORMAL% +ServiceBinary = %12%\ibiou.sys +AddReg = Iou.ParamsReg + +[Iou.ParamsReg] +HKR,"Parameters","DebugLevel",%REG_DWORD%,2 +HKR,"Parameters","DebugFlags",%REG_DWORD%,0x00ffffff + +[Strings] +OPENIB = "OpenFabrics Alliance" +SST = "SilverStorm Technologies" +VFx.DeviceDesc = "SilverStorm VFx" +VEx.DeviceDesc = "SilverStorm VEx" +FVIC.DeviceDesc = "SilverStorm FVIC" +EVIC.DeviceDesc = "SilverStorm EVIC" +BC2FC.DeviceDesc = "QLogic InfiniBand Fibre Channel Bridge Module" +BC2GE.DeviceDesc = "QLogic InfiniBand Ethernet Bridge Module" + +Iou.DeviceDesc = "InfiniBand I/O Unit" +Iou.ServiceDesc = "OpenIB InfiniBand I/O Unit Driver" +DiskId = "OpenIB InfiniBand Access Layer installation disk" +SPSVCINST_NULL = 0x0 +SPSVCINST_ASSOCSERVICE = 0x00000002 +SERVICE_KERNEL_DRIVER = 1 +SERVICE_DEMAND_START = 3 +SERVICE_ERROR_NORMAL = 1 +REG_DWORD = 0x00010001 +REG_DWORD_NO_CLOBBER = 0x00010003 +DIRID_SYSTEM = 11 +DIRID_DRIVERS = 12 +DIRID_SYSTEM_X86 = 16425 diff --git a/branches/WOF2-3/core/iou/kernel/ibiou.rc b/branches/WOF2-3/core/iou/kernel/ibiou.rc new file mode 100644 index 00000000..56b995af --- /dev/null +++ b/branches/WOF2-3/core/iou/kernel/ibiou.rc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef _DEBUG_ +#define VER_FILEDESCRIPTION_STR "InfiniBand I/O Unit Driver (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "InfiniBand I/O Unit Driver" +#endif + +#define VER_INTERNALNAME_STR "ibiou.sys" +#define VER_ORIGINALFILENAME_STR "ibiou.sys" + +#include diff --git a/branches/WOF2-3/core/iou/kernel/iou_driver.c b/branches/WOF2-3/core/iou/kernel/iou_driver.c new file mode 100644 index 00000000..60b1b55b --- /dev/null +++ b/branches/WOF2-3/core/iou/kernel/iou_driver.c @@ -0,0 +1,903 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * Provides the driver entry points for the InfiniBand I/O Unit Bus Driver. + */ + +#include +#include "iou_driver.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "iou_driver.tmh" +#endif +#include "iou_pnp.h" +#include "al_dev.h" +#include "iou_ioc_mgr.h" +#include +#include + +iou_globals_t iou_globals = { + NULL +}; + +uint32_t g_iou_dbg_level = TRACE_LEVEL_ERROR; +uint32_t g_iou_dbg_flags = 0x00000fff; + +static NTSTATUS +__read_registry( + IN UNICODE_STRING* const p_Param_Path ); + +static NTSTATUS +iou_drv_open( + IN DEVICE_OBJECT *p_dev_obj, + IN IRP *p_irp ); + +static NTSTATUS +iou_drv_close( + IN DEVICE_OBJECT *p_dev_obj, + IN IRP *p_irp ); + +static NTSTATUS +iou_drv_cleanup( + IN DEVICE_OBJECT *p_dev_obj, + IN IRP *p_irp); + +static NTSTATUS +iou_drv_ioctl( + IN DEVICE_OBJECT *p_dev_obj, + IN IRP *p_irp ); + +/***f* InfiniBand Bus Driver/iou_sysctl +* NAME +* iou_sysctl +* +* DESCRIPTION +* Entry point for handling WMI IRPs. +* +* SYNOPSIS +*/ +static NTSTATUS +iou_sysctl( + IN DEVICE_OBJECT *p_dev_obj, + IN IRP *p_irp ); + +/**********/ + +static void +iou_unload( + IN DRIVER_OBJECT *p_driver_obj ); + +NTSTATUS +DriverEntry( + IN DRIVER_OBJECT *p_driver_obj, + IN UNICODE_STRING *p_registry_path ); + + +static void _free_child_device_list() +{ + child_device_info_list_t *pDevList, *pDevList1; + + pDevList = iou_globals.p_device_list; + + while( pDevList ) + { + pDevList1 = pDevList->next_device_info; + cl_free( pDevList ); + pDevList = pDevList1; + } + +} + +static NTSTATUS _build_child_device_list( PUNICODE_STRING p_param_path ) +{ + RTL_QUERY_REGISTRY_TABLE table[2]; + UNICODE_STRING keyPath; + UNICODE_STRING keyValue; + UNICODE_STRING child_name; + WCHAR *key_path_buffer; + WCHAR *key_value_buffer; + WCHAR *static_child_name; + NTSTATUS status; + uint32_t instanceid = 1; + HANDLE hParamKey = NULL; + UNICODE_STRING valuename; + ULONG sizeofbuf; + PVOID pBuf = NULL; + PKEY_VALUE_FULL_INFORMATION pKeyVal = NULL; + uint64_t guid_val = 0; + OBJECT_ATTRIBUTES objattr; + WCHAR *curChild; + child_device_info_list_t *pPrevList, *pNewDevList; + + cl_memclr( table, sizeof( table) ); + + /* use hard-coded size 256 to make it simple*/ + key_path_buffer = cl_zalloc( 256*sizeof( WCHAR )*3 ) ; + + if( !key_path_buffer ) + { + IOU_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IOU_DBG_ERROR ,( "Not enough memeory for key_path_buffer.\n" ) ); + status = STATUS_UNSUCCESSFUL; + goto _build_child_device_list_exit; + } + + key_value_buffer = key_path_buffer + 256; + static_child_name = key_value_buffer + 256; + + RtlInitUnicodeString( &keyPath, NULL ); + keyPath.MaximumLength = 256*sizeof( WCHAR ); + keyPath.Buffer = key_path_buffer; + + RtlInitUnicodeString( &keyValue, NULL ); + keyValue.MaximumLength = 256*sizeof( WCHAR ); + keyValue.Buffer = key_value_buffer; + + RtlInitUnicodeString( &child_name, NULL ); + child_name.MaximumLength = 256*sizeof( WCHAR ); + child_name.Buffer = static_child_name; + + + RtlCopyUnicodeString( &keyPath, p_param_path ); + + /* Setup the table entries. */ + table[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOEXPAND; + table[0].Name = L"StaticChild"; + table[0].EntryContext = &child_name; + table[0].DefaultType = REG_NONE; + + status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE, + keyPath.Buffer, table, NULL, NULL ); + + if( !NT_SUCCESS( status ) ) + { + if ( status == STATUS_INVALID_PARAMETER ) + { + IOU_PRINT(TRACE_LEVEL_WARNING, IOU_DBG_ERROR, + ("Failed to read registry values\n") ); + } + goto _build_child_device_list_exit; + } + + curChild = static_child_name; + pPrevList = iou_globals.p_device_list; + while( *curChild ) + { + RtlCopyUnicodeString( &keyPath, p_param_path ); + RtlAppendUnicodeToString( &keyPath, L"\\" ); + RtlAppendUnicodeToString( &keyPath, curChild ); + + pNewDevList = cl_zalloc( sizeof( child_device_info_list_t ) ); + if( !pNewDevList ) + { + IOU_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IOU_DBG_ERROR, + ( "Not enough memeory for key_path_buffer.\n" ) ); + status = STATUS_UNSUCCESSFUL; + goto _build_child_device_list_exit; + } + pNewDevList->next_device_info = NULL; + + if( pPrevList == NULL ) + { + iou_globals.p_device_list = pNewDevList; + } + else + { + pPrevList->next_device_info = pNewDevList; + } + + pPrevList = pNewDevList; + + RtlInitUnicodeString( &keyValue, NULL ); + keyValue.MaximumLength = sizeof( pNewDevList->io_device_info.device_id ); + keyValue.Buffer = pNewDevList->io_device_info.device_id; + + /* Setup the table entries. */ + table[0].Flags = RTL_QUERY_REGISTRY_DIRECT; + table[0].Name = L"DeviceId"; + table[0].EntryContext = &keyValue; + table[0].DefaultType = REG_NONE; + + status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE, + keyPath.Buffer, table, NULL, NULL ); + if( !NT_SUCCESS( status ) ) + { + IOU_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IOU_DBG_ERROR, + ( "Failed to read DeviceId.\n" ) ); + goto _build_child_device_list_exit; + } + pNewDevList->io_device_info.device_id_size = keyValue.Length + sizeof( WCHAR); + + /* Get HardwareId*/ + RtlInitUnicodeString( &keyValue, NULL ); + keyValue.MaximumLength = sizeof( pNewDevList->io_device_info.hardware_id ); + keyValue.Buffer = pNewDevList->io_device_info.hardware_id; + + /* Setup the table entries. */ + table[0].Flags = RTL_QUERY_REGISTRY_DIRECT; + table[0].Name = L"HardwareId"; + table[0].EntryContext = &keyValue; + table[0].DefaultType = REG_NONE; + + status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE, + keyPath.Buffer, table, NULL, NULL ); + if( !NT_SUCCESS( status ) ) + { + IOU_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IOU_DBG_ERROR , + ( "Failed to read HardwareId.\n" ) ); + goto _build_child_device_list_exit; + } + pNewDevList->io_device_info.hardware_id_size = keyValue.Length + 2*sizeof( WCHAR ); + /* Get CompatibleId*/ + RtlInitUnicodeString( &keyValue, NULL ); + keyValue.MaximumLength = sizeof( pNewDevList->io_device_info.compatible_id ); + keyValue.Buffer = pNewDevList->io_device_info.compatible_id; + /* Setup the table entries. */ + table[0].Flags = RTL_QUERY_REGISTRY_DIRECT; + table[0].Name = L"CompatibleId"; + table[0].EntryContext = &keyValue; + table[0].DefaultType = REG_NONE; + + status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE, + keyPath.Buffer, table, NULL, NULL ); + if( !NT_SUCCESS( status ) ) + { + IOU_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IOU_DBG_ERROR , + ( "Failed to read CompatibleId.\n" ) ); + goto _build_child_device_list_exit; + } + pNewDevList->io_device_info.compatible_id_size = keyValue.Length + 2*sizeof( WCHAR ); //2 null + + /* Get Description*/ + RtlInitUnicodeString( &keyValue, NULL ); + keyValue.MaximumLength = sizeof( pNewDevList->io_device_info.description ); + keyValue.Buffer = pNewDevList->io_device_info.description; + + /* Setup the table entries. */ + table[0].Flags = RTL_QUERY_REGISTRY_DIRECT; + table[0].Name = L"Description"; + table[0].EntryContext = &keyValue; + table[0].DefaultType = REG_NONE; + + status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE, + keyPath.Buffer, table, NULL, NULL ); + if( !NT_SUCCESS( status ) ) + { + IOU_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IOU_DBG_ERROR, + ( "Failed to read Description.\n" ) ); + goto _build_child_device_list_exit; + } + + pNewDevList->io_device_info.description_size = keyValue.Length + sizeof( WCHAR ); + + if( ( pNewDevList->io_device_info.description_size > MAX_DEVICE_ID_LEN) || + ( pNewDevList->io_device_info.hardware_id_size > MAX_DEVICE_ID_LEN) || + ( pNewDevList->io_device_info.compatible_id_size > MAX_DEVICE_ID_LEN) || + ( pNewDevList->io_device_info.device_id_size > MAX_DEVICE_ID_LEN) + ) + { + IOU_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IOU_DBG_ERROR, + ( "Id or description size is too big.\n" ) ); + status = STATUS_UNSUCCESSFUL; + goto _build_child_device_list_exit; + } + + InitializeObjectAttributes( &objattr, &keyPath, OBJ_KERNEL_HANDLE, NULL, NULL ); + + status = ZwOpenKey( &hParamKey, GENERIC_READ, &objattr ); + + if ( !NT_SUCCESS( status ) ) + { + IOU_PRINT( TRACE_LEVEL_INFORMATION, IOU_DBG_ERROR, + ( "ZwOpenKey failed with status %u\n",status ) ); + goto _build_child_device_list_exit; + } + + RtlInitUnicodeString( &valuename, L"IOCGUID" ); + status = ZwQueryValueKey( hParamKey, &valuename, KeyValueFullInformation, NULL, 0, &sizeofbuf ); + + if ( status == STATUS_BUFFER_OVERFLOW || status == STATUS_BUFFER_TOO_SMALL ) + { + pBuf = cl_zalloc( sizeofbuf ); + } + + if ( !pBuf && !NT_SUCCESS( status ) ) + { + IOU_PRINT( TRACE_LEVEL_INFORMATION, IOU_DBG_ERROR, + ( "Either ZwQueryValueKey failed with status %u" + "or cl_zalloc failed\n",status ) ); + goto _build_child_device_list_exit; + } + + status = ZwQueryValueKey( hParamKey, &valuename, KeyValueFullInformation, pBuf, sizeofbuf, &sizeofbuf ); + + if ( !NT_SUCCESS( status ) ) + { + IOU_PRINT( TRACE_LEVEL_INFORMATION, IOU_DBG_ERROR, + ( "ZwQueryValueKey failed with status %u\n",status ) ); + goto _build_child_device_list_exit; + } + + pKeyVal = ( PKEY_VALUE_FULL_INFORMATION ) pBuf; + + if ( pKeyVal->Type & REG_BINARY ) + { + memcpy( &guid_val, ( ( ( char * ) pBuf ) + pKeyVal->DataOffset ), sizeof( uint64_t ) ); + pNewDevList->io_device_info.ca_ioc_path.info.profile.ioc_guid = guid_val; + guid_val = 0; + } + else + { + IOU_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IOU_DBG_ERROR, + ( "IOC GUID is not of REG_BINARY type\n" ) ); + goto _build_child_device_list_exit; + } + cl_free( pBuf ); + pBuf = NULL; + + RtlInitUnicodeString( &valuename, L"CAGUID" ); + status = ZwQueryValueKey( hParamKey, &valuename, KeyValueFullInformation, NULL, 0, &sizeofbuf ); + + if ( status == STATUS_BUFFER_OVERFLOW || status == STATUS_BUFFER_TOO_SMALL ) + { + pBuf = cl_zalloc( sizeofbuf ); + } + + if ( !pBuf && !NT_SUCCESS( status ) ) + { + IOU_PRINT( TRACE_LEVEL_INFORMATION, IOU_DBG_ERROR, + ( "Either ZwQueryValueKey failed with status %u" + "or cl_zalloc failed\n",status ) ); + goto _build_child_device_list_exit; + } + + status = ZwQueryValueKey( hParamKey, &valuename, KeyValueFullInformation, pBuf, sizeofbuf, &sizeofbuf ); + + if ( !NT_SUCCESS( status ) ) + { + IOU_PRINT( TRACE_LEVEL_INFORMATION, IOU_DBG_ERROR, + ( "ZwQueryValueKey failed with status %u\n",status ) ); + goto _build_child_device_list_exit; + } + + pKeyVal = ( PKEY_VALUE_FULL_INFORMATION ) pBuf; + + if ( pKeyVal->Type & REG_BINARY ) + { + memcpy( &guid_val, ( ( ( char * ) pBuf ) + pKeyVal->DataOffset ), sizeof( uint64_t ) ); + pNewDevList->io_device_info.ca_ioc_path.ca_guid = guid_val; + } + else + { + IOU_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IOU_DBG_ERROR, + ( "CA GUID is not of REG_BINARY type\n")); + goto _build_child_device_list_exit; + } + + cl_free( pBuf); + pBuf = NULL; + + RtlInitUnicodeString( &valuename, L"InstanceId"); + status = ZwQueryValueKey( hParamKey, &valuename, KeyValueFullInformation, NULL, 0, &sizeofbuf ); + + if ( status == STATUS_BUFFER_OVERFLOW || status == STATUS_BUFFER_TOO_SMALL ) + { + pBuf = cl_zalloc( sizeofbuf ); + } + + if ( !pBuf && !NT_SUCCESS( status ) ) + { + IOU_PRINT( TRACE_LEVEL_INFORMATION, IOU_DBG_ERROR, + ( "Either ZwQueryValueKey failed with status %u" + "or cl_zalloc failed\n",status ) ); + goto _build_child_device_list_exit; + } + + status = ZwQueryValueKey( hParamKey, &valuename, KeyValueFullInformation, + pBuf, sizeofbuf, &sizeofbuf ); + + if ( !NT_SUCCESS( status ) ) + { + IOU_PRINT( TRACE_LEVEL_INFORMATION, IOU_DBG_ERROR, + ( "ZwQueryValueKey failed with status %u\n",status ) ); + goto _build_child_device_list_exit; + } + + pKeyVal = ( PKEY_VALUE_FULL_INFORMATION ) pBuf; + + memcpy( &instanceid, ( ( ( char * ) pBuf ) + pKeyVal->DataOffset ), sizeof( instanceid ) ); + pNewDevList->io_device_info.uniqueinstanceid = instanceid; + + cl_free( pBuf ); + pBuf = NULL; + + ZwClose( hParamKey ); + hParamKey = NULL; + + while( *curChild ) curChild++; + curChild++; + + } + + +_build_child_device_list_exit: + if( key_path_buffer ) + { + cl_free( key_path_buffer ); + } + + if( !NT_SUCCESS( status ) ) + { + _free_child_device_list(); + } + + if ( hParamKey != NULL ) + { + ZwClose( hParamKey ); + } + + if ( pBuf ) + { + cl_free( pBuf ); + } + + return status; +} + +static NTSTATUS +__read_registry( + IN UNICODE_STRING* const p_registry_path ) +{ + NTSTATUS status; + /* Remember the terminating entry in the table below. */ + RTL_QUERY_REGISTRY_TABLE table[3]; + UNICODE_STRING param_path; + + IOU_ENTER( IOU_DBG_DRV ); + + RtlInitUnicodeString( ¶m_path, NULL ); + param_path.MaximumLength = p_registry_path->Length + + sizeof(L"\\Parameters"); + param_path.Buffer = cl_zalloc( param_path.MaximumLength ); + if( !param_path.Buffer ) + { + IOU_PRINT_EXIT( TRACE_LEVEL_ERROR,IOU_DBG_ERROR, + ("Failed to allocate parameters path buffer.\n") ); + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlAppendUnicodeStringToString( ¶m_path, p_registry_path ); + RtlAppendUnicodeToString( ¶m_path, L"\\Parameters" ); + + /* + * Clear the table. This clears all the query callback pointers, + * and sets up the terminating table entry. + */ + cl_memclr( table, sizeof(table) ); + + /* Setup the table entries. */ + table[0].Flags = RTL_QUERY_REGISTRY_DIRECT; + table[0].Name = L"DebugLevel"; + table[0].EntryContext = &g_iou_dbg_level; + table[0].DefaultType = REG_DWORD; + table[0].DefaultData = &g_iou_dbg_level; + table[0].DefaultLength = sizeof(ULONG); + + table[1].Flags = RTL_QUERY_REGISTRY_DIRECT; + table[1].Name = L"DebugFlags"; + table[1].EntryContext = &g_iou_dbg_flags; + table[1].DefaultType = REG_DWORD; + table[1].DefaultData = &g_iou_dbg_flags; + table[1].DefaultLength = sizeof(ULONG); + /* Have at it! */ + status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE, + param_path.Buffer, table, NULL, NULL ); + +#ifndef EVENT_TRACING + if( g_iou_dbg_flags & IOU_DBG_ERR ) + g_iou_dbg_flags |= CL_DBG_ERROR; +#endif + + if(!NT_SUCCESS( _build_child_device_list (¶m_path) ) ){ + IOU_PRINT( TRACE_LEVEL_INFORMATION, IOU_DBG_DRV, + ( "Failed to create devices\n" ) ); + } + + + IOU_PRINT( TRACE_LEVEL_INFORMATION, IOU_DBG_DRV, + ("debug level %d debug flags 0x%.8x\n", + g_iou_dbg_level, + g_iou_dbg_flags) ); + + cl_free( param_path.Buffer ); + IOU_EXIT( IOU_DBG_DRV ); + return status; +} + +static NTSTATUS +_create_child_ioc_device( + IN child_device_info_t *p_child_dev ) +{ + child_device_info_list_t *p_prev_list, *p_new_dev_list, *temp = NULL; + ca_ioc_map_t *p_ca_ioc_map; + ib_api_status_t ib_status; + + p_prev_list = iou_globals.p_device_list; + + p_ca_ioc_map = find_ca_ioc_map( p_child_dev->ca_ioc_path.ca_guid, + p_child_dev->ca_ioc_path.info.profile.ioc_guid ); + + if ( p_ca_ioc_map == NULL ) + { + return STATUS_INTERNAL_ERROR; + } + + p_new_dev_list = cl_zalloc( sizeof( child_device_info_list_t ) ); + + if ( !p_new_dev_list ) + { + IOU_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IOU_DBG_ERROR, + ( "Insufficient Memory\n" ) ); + return STATUS_INSUFFICIENT_RESOURCES; + } + + p_new_dev_list->io_device_info = *p_child_dev; + p_new_dev_list->next_device_info = NULL; + + if( p_prev_list == NULL ) + { + iou_globals.p_device_list = p_new_dev_list; + } + else + { + temp = p_prev_list->next_device_info; + p_prev_list->next_device_info = p_new_dev_list; + } + p_new_dev_list->next_device_info = temp; + + ib_status = _create_ioc_pdo( &p_new_dev_list->io_device_info, p_ca_ioc_map ); + + if ( ib_status != IB_SUCCESS ) + { + IOU_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IOU_DBG_ERROR, + ( "PDO creation for IOC failed\n" ) ); + cl_free( p_new_dev_list ); + return STATUS_INTERNAL_ERROR; + } + + return STATUS_SUCCESS; +} + +static ULONG +_build_ca_ioc_list( ca_ioc_info_t *p_info ) +{ + cl_list_item_t *p_item; + ca_ioc_map_t *p_map; + + p_item = cl_qlist_head( &iou_globals.ca_ioc_map_list ); + + while ( p_item != cl_qlist_end( &iou_globals.ca_ioc_map_list ) ) + { + p_map = ( ca_ioc_map_t *) p_item; + p_info->ca_guid = p_map->ca_guid; + p_info->info = p_map->info; + cl_memcpy( p_info->svc_entry_array, p_map->svc_entry_array, + sizeof( p_map->svc_entry_array ) ); + + p_item = cl_qlist_next( p_item ); + p_info++; + } + + return ( (ULONG) (sizeof(ca_ioc_info_t)*cl_qlist_count( &iou_globals.ca_ioc_map_list )) ); +} + +static NTSTATUS +iou_drv_open( + IN DEVICE_OBJECT *p_dev_obj, + IN IRP *p_irp ) +{ + IOU_ENTER( IOU_DBG_DRV ); + + UNUSED_PARAM( p_dev_obj ); + + CL_ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL ); + + /* We always succeed file handles creation. */ + p_irp->IoStatus.Status = STATUS_SUCCESS; + p_irp->IoStatus.Information = 0; + IoCompleteRequest( p_irp, IO_NO_INCREMENT ); + + IOU_EXIT( IOU_DBG_DRV ); + return STATUS_SUCCESS; + +} + +static NTSTATUS +iou_drv_close( + IN DEVICE_OBJECT *p_dev_obj, + IN IRP *p_irp ) +{ + UNUSED_PARAM( p_dev_obj ); + + p_irp->IoStatus.Status = STATUS_SUCCESS; + p_irp->IoStatus.Information = 0; + IoCompleteRequest( p_irp, IO_NO_INCREMENT ); + + return STATUS_SUCCESS; +} + +static NTSTATUS +iou_drv_cleanup( + IN DEVICE_OBJECT *p_dev_obj, + IN IRP *p_irp) +{ + IOU_ENTER( IOU_DBG_DRV ); + + UNUSED_PARAM( p_dev_obj ); + + CL_ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL ); + + /* + * Note that we don't acquire the remove and stop lock on close to allow + * applications to close the device when the locks are already held. + */ + + /* Complete the IRP. */ + p_irp->IoStatus.Status = STATUS_SUCCESS; + p_irp->IoStatus.Information = 0; + IoCompleteRequest( p_irp, IO_NO_INCREMENT ); + + IOU_EXIT( IOU_DBG_DRV ); + return STATUS_SUCCESS; +} + +static NTSTATUS +iou_drv_ioctl( + IN DEVICE_OBJECT *p_dev_obj, + IN IRP *p_irp ) +{ + NTSTATUS status = STATUS_SUCCESS; + PIO_STACK_LOCATION p_io_stack; + ULONG controlcode, n_bytes; + size_t n_iocs; + ca_ioc_info_t *p_ca_ioc_info; + child_device_info_t *p_child_dev; + + IOU_ENTER( IOU_DBG_DRV ); + CL_ASSERT( p_dev_obj ); + CL_ASSERT( p_irp ); + UNUSED_PARAM( p_dev_obj ); + + /* Get the stack location. */ + p_io_stack = IoGetCurrentIrpStackLocation( p_irp ); + controlcode = p_io_stack->Parameters.DeviceIoControl.IoControlCode; + p_irp->IoStatus.Information = 0; + + switch ( controlcode ) + { + case UAL_IOC_DEVICE_CREATE: + p_child_dev = p_irp->AssociatedIrp.SystemBuffer; + + if ( sizeof( child_device_info_t) > + ( p_io_stack->Parameters.DeviceIoControl. + InputBufferLength ) ) + { + status = STATUS_BUFFER_TOO_SMALL; + } + else + { + status = _create_child_ioc_device( p_child_dev ); + } + break; + + case UAL_IOC_LIST: + p_ca_ioc_info = p_irp->AssociatedIrp.SystemBuffer; + cl_mutex_acquire( &iou_globals.list_mutex ); + n_iocs = cl_qlist_count( &iou_globals.ca_ioc_map_list ); + + if ( n_iocs*sizeof( ca_ioc_info_t) <= + p_io_stack->Parameters.DeviceIoControl. + OutputBufferLength ) + { + n_bytes = _build_ca_ioc_list( p_ca_ioc_info ); + p_irp->IoStatus.Information = n_bytes; + status = STATUS_SUCCESS; + } + else + { + status = STATUS_BUFFER_TOO_SMALL; + } + + cl_mutex_release( &iou_globals.list_mutex ); + + break; + default: + status = STATUS_INVALID_DEVICE_REQUEST; + break; + } + + p_irp->IoStatus.Status = status; + IoCompleteRequest( p_irp, IO_NO_INCREMENT ); + return status; +} + +static NTSTATUS +iou_sysctl( + IN DEVICE_OBJECT *p_dev_obj, + IN IRP *p_irp ) +{ + NTSTATUS status; + cl_pnp_po_ext_t *p_ext; + + IOU_ENTER( IOU_DBG_DRV ); + + CL_ASSERT( p_dev_obj ); + CL_ASSERT( p_irp ); + + p_ext = p_dev_obj->DeviceExtension; + + if( p_ext->p_next_do ) + { + IoSkipCurrentIrpStackLocation( p_irp ); + status = IoCallDriver( p_ext->p_next_do, p_irp ); + } + else + { + status = p_irp->IoStatus.Status; + IoCompleteRequest( p_irp, IO_NO_INCREMENT ); + } + + IOU_EXIT( IOU_DBG_DRV ); + return status; +} + +static void +iou_unload( + IN DRIVER_OBJECT *p_driver_obj ) +{ + UNICODE_STRING dos_name; + + IOU_ENTER( IOU_DBG_DRV ); + +#if defined(EVENT_TRACING) + WPP_CLEANUP( p_driver_obj ); +#else + UNUSED_PARAM( p_driver_obj ); +#endif + + CL_DEINIT; + + _free_child_device_list(); + + RtlInitUnicodeString( &dos_name, + L"\\DosDevices\\Global\\VNICCONFIG" ); + IoDeleteSymbolicLink( &dos_name ); + + + IOU_EXIT( IOU_DBG_DRV ); +} + +static +PDEVICE_OBJECT +initialize_ioctl_interface( + IN PDRIVER_OBJECT p_driver_obj ) +{ + NTSTATUS status; + UNICODE_STRING dev_name, dos_name; + PDEVICE_OBJECT p_dev_obj = NULL; + + RtlInitUnicodeString( &dev_name, L"\\Device\\VNICCONFIG" ); + RtlInitUnicodeString( &dos_name, + L"\\DosDevices\\Global\\VNICCONFIG" ); + + status = IoCreateDevice( p_driver_obj, 0, + &dev_name, FILE_DEVICE_UNKNOWN, + FILE_DEVICE_SECURE_OPEN, FALSE, &p_dev_obj ); + + if( !NT_SUCCESS( status ) ) + { + IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR, + ( "Failed to create VNIC CONFIG device.\n" ) ); + return NULL; + } + + IoDeleteSymbolicLink( &dos_name ); + + status = IoCreateSymbolicLink( &dos_name, &dev_name ); + if( !NT_SUCCESS( status ) ) + { + IoDeleteDevice( p_dev_obj ); + IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR, + ( "Failed to create symlink for dos name.\n" ) ); + p_dev_obj = NULL; + } + + return p_dev_obj; +} + +NTSTATUS +DriverEntry( + IN DRIVER_OBJECT *p_driver_obj, + IN UNICODE_STRING *p_registry_path ) +{ + NTSTATUS status; + + IOU_ENTER( IOU_DBG_DRV ); + +#if defined(EVENT_TRACING) + WPP_INIT_TRACING( p_driver_obj, p_registry_path ); +#endif + + status = CL_INIT; + if( !NT_SUCCESS(status) ) + { + IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR, + ("cl_init returned %08X.\n", status) ); + return status; + } + + /* Store the driver object pointer in the global parameters. */ + iou_globals.p_driver_obj = p_driver_obj; + iou_globals.p_device_list = NULL; + + /* Get the registry values. */ + status = __read_registry( p_registry_path ); + if( !NT_SUCCESS(status) ) + { + CL_DEINIT; + IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR, + ("__read_registry returned %08x.\n", status) ); + return status; + } + + /* Setup the entry points. */ + p_driver_obj->MajorFunction[IRP_MJ_CREATE] = iou_drv_open; + p_driver_obj->MajorFunction[IRP_MJ_CLEANUP] = iou_drv_cleanup; + p_driver_obj->MajorFunction[IRP_MJ_CLOSE] = iou_drv_close; + + p_driver_obj->MajorFunction[IRP_MJ_PNP] = cl_pnp; + p_driver_obj->MajorFunction[IRP_MJ_POWER] = cl_power; + p_driver_obj->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = iou_sysctl; + p_driver_obj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = iou_drv_ioctl; + p_driver_obj->DriverUnload = iou_unload; + p_driver_obj->DriverExtension->AddDevice = iou_add_device; + + iou_globals.p_config_device = initialize_ioctl_interface( p_driver_obj ); + + cl_qlist_init( &iou_globals.ca_ioc_map_list ); + cl_mutex_init( &iou_globals.list_mutex ); + + IOU_EXIT( IOU_DBG_DRV ); + return STATUS_SUCCESS; +} diff --git a/branches/WOF2-3/core/iou/kernel/iou_driver.h b/branches/WOF2-3/core/iou/kernel/iou_driver.h new file mode 100644 index 00000000..b779cec7 --- /dev/null +++ b/branches/WOF2-3/core/iou/kernel/iou_driver.h @@ -0,0 +1,263 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + +#if !defined _IOU_DRIVER_H_ +#define _IOU_DRIVER_H_ + +#include "complib/cl_types.h" +#include "complib/cl_atomic.h" +#include "complib/cl_debug.h" +#include "complib/cl_mutex.h" +#include "complib/cl_qlist.h" +#include "complib/cl_ptr_vector.h" +#include "complib/cl_pnp_po.h" +#include "iba/ib_al.h" +#include "iou_ioc_mgr.h" + +/* Safe string functions. */ +#if WINVER == 0x500 +/* + * Windows 2000 doesn't support the inline version of safe strings. + * Force the use of the library version of safe strings. + */ +#define NTSTRSAFE_LIB +#endif +#include + +extern uint32_t g_iou_dbg_level; +extern uint32_t g_iou_dbg_flags; + +#if defined(EVENT_TRACING) +// +// Software Tracing Definitions +// + +#define WPP_CONTROL_GUIDS \ + WPP_DEFINE_CONTROL_GUID(IOUCtlGuid,(A0090FEF,01BB,4617,AF1E,FD02FD5B24ED), \ + WPP_DEFINE_BIT( IOU_DBG_ERROR) \ + WPP_DEFINE_BIT( IOU_DBG_DRV) \ + WPP_DEFINE_BIT( IOU_DBG_PNP) \ + WPP_DEFINE_BIT( IOU_DBG_POWER) \ + WPP_DEFINE_BIT( IOU_DBG_PORT) \ + WPP_DEFINE_BIT( IOU_DBG_IOU)) + + + +#define WPP_LEVEL_FLAGS_ENABLED(lvl, flags) (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= lvl) +#define WPP_LEVEL_FLAGS_LOGGER(lvl,flags) WPP_LEVEL_LOGGER(flags) +#define WPP_FLAG_ENABLED(flags)(WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= TRACE_LEVEL_VERBOSE) +#define WPP_FLAG_LOGGER(flags) WPP_LEVEL_LOGGER(flags) + + +// begin_wpp config +// IOU_ENTER(FLAG); +// IOU_EXIT(FLAG); +// USEPREFIX(IOU_PRINT, "%!STDPREFIX! [IOU] :%!FUNC!() :"); +// USESUFFIX(IOU_ENTER, " [IOU] :%!FUNC!():["); +// USESUFFIX(IOU_EXIT, " [IOU] :%!FUNC!():]"); +// end_wpp + + +#else + + +#include + +/* + * Debug macros + */ + + +#define IOU_DBG_ERR (1 << 0) +#define IOU_DBG_DRV (1 << 1) +#define IOU_DBG_PNP (1 << 2) +#define IOU_DBG_POWER (1 << 3) +#define IOU_DBG_PORT (1 << 4) +#define IOU_DBG_IOU (1 << 5) + +#define IOU_DBG_ERROR (CL_DBG_ERROR | IOU_DBG_ERR) +#define IOU_DBG_ALL CL_DBG_ALL + +#if DBG + +// assignment of _level_ is need to to overcome warning C4127 +#define IOU_PRINT(_level_,_flag_,_msg_) \ + { \ + if( g_iou_dbg_level >= (_level_) ) \ + CL_TRACE( _flag_, g_iou_dbg_flags, _msg_ ); \ + } + +#define IOU_PRINT_EXIT(_level_,_flag_,_msg_) \ + { \ + if( g_iou_dbg_level >= (_level_) ) \ + CL_TRACE( _flag_, g_iou_dbg_flags, _msg_ );\ + IOU_EXIT(_flag_);\ + } + +#define IOU_ENTER(_flag_) \ + { \ + if( g_iou_dbg_level >= TRACE_LEVEL_VERBOSE ) \ + CL_ENTER( _flag_, g_iou_dbg_flags ); \ + } + +#define IOU_EXIT(_flag_)\ + { \ + if( g_iou_dbg_level >= TRACE_LEVEL_VERBOSE ) \ + CL_EXIT( _flag_, g_iou_dbg_flags ); \ + } + + +#else + +#define IOU_PRINT(lvl, flags, msg) + +#define IOU_PRINT_EXIT(_level_,_flag_,_msg_) + +#define IOU_ENTER(_flag_) + +#define IOU_EXIT(_flag_) + + +#endif + + +#endif //EVENT_TRACING + +/* + * Main header for IB Bus driver. + */ + + + +/* + * ALLOC_PRAGMA sections: + * PAGE + * Default pagable code. Won't be locked in memory. + * + * PAGE_PNP + * Code that needs to be locked in memory when the device is + * in the paging, crash dump, or hibernation path. + */ + + +/* + * Device extension for the device object that serves as entry point for + * the interface and IOCTL requests. + */ +typedef struct _iou_fdo_ext +{ + cl_pnp_po_ext_t cl_ext; + + /* + * Device power map returned by the bus driver for the device, used + * when sending IRP_MN_SET_POWER for device state in response to + * IRP_MN_SET_POWER for system state. + */ + DEVICE_POWER_STATE po_state[PowerSystemMaximum]; + + ioc_mgr_t ioc_mgr; + +} iou_fdo_ext_t; + +/* + * Device extension for bus driver PDOs. + */ +typedef struct _iou_pdo_ext +{ + cl_pnp_po_ext_t cl_ext; + + cl_list_item_t list_item; + + /* All reported PDOs are children of an HCA. */ + ib_ca_handle_t h_ca; + + /* + * CA GUID copy - in case we get IRPs after the CA + * handle has been released. + */ + net64_t ca_guid; + POWER_STATE dev_po_state; + + /* + * Pointer to the bus root device extension. Used to manage access to + * child PDO pointer vector when a child is removed politely. + */ + iou_fdo_ext_t *p_parent_ext; + + /* + * The following two flags are exclusively set, but can both be FALSE. + * Flag that indicates whether the device is present in the system or not. + * This affects how a IRP_MN_REMOVE_DEVICE IRP is handled for a child PDO. + * This flag is cleared when: + * - an HCA (for IPoIB devices) is removed from the system for all port + * devices loaded for that HCA + * - an IOU is reported as removed by the CIA. + */ + boolean_t b_present; + + /* + * Flag that indicates whether the device has been reported to the PnP + * manager as having been removed. That is, the device was reported + * in a previous BusRelations query and not in a subsequent one. + * This flag is set when + * - the device is in the surprise remove state when the parent bus + * device is removed + * - the device is found to be not present during a BusRelations query + * and thus not reported. + */ + boolean_t b_reported_missing; + struct _child_device_info *p_pdo_device_info; +} iou_pdo_ext_t; + + +/* + * Global Driver parameters. + */ +typedef struct _iou_globals +{ + /* Driver object. Used for creating child devices. */ + DRIVER_OBJECT *p_driver_obj; + struct _child_device_info_list *p_device_list; + cl_mutex_t list_mutex; + cl_qlist_t ca_ioc_map_list; + PDEVICE_OBJECT p_config_device; +} iou_globals_t; + + +extern iou_globals_t iou_globals; + + + + +#endif /* !defined _IOU_DRIVER_H_ */ diff --git a/branches/WOF2-3/core/iou/kernel/iou_ioc_mgr.c b/branches/WOF2-3/core/iou/kernel/iou_ioc_mgr.c new file mode 100644 index 00000000..8ad88a7e --- /dev/null +++ b/branches/WOF2-3/core/iou/kernel/iou_ioc_mgr.c @@ -0,0 +1,1716 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + +#include +#include +#include +#include "iou_driver.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "iou_ioc_mgr.tmh" +#endif +#include "iou_pnp.h" +#include "iou_ioc_mgr.h" +#include +#include +#include "iba/ioc_ifc.h" + + +/* {5A9649F4-0101-4a7c-8337-796C48082DA2} */ +DEFINE_GUID(GUID_BUS_TYPE_IBA, +0x5a9649f4, 0x101, 0x4a7c, 0x83, 0x37, 0x79, 0x6c, 0x48, 0x8, 0x2d, 0xa2); + + +/* + * Size of device descriptions, as defined in + * A1.2.3.1.1 - Creating Compatibility Strings for an I/O Controller + */ +#define IOC_DEV_ID_SIZE \ + sizeof(L"IBA\\VxxxxxxPxxxxxxxxSxxxxxxsxxxxxxxxvxxxx") +#define IOC_HW_ID_SIZE \ + sizeof(L"IBA\\VxxxxxxPxxxxxxxxSxxxxxxsxxxxxxxxvxxxx") + \ + sizeof(L"IBA\\VxxxxxxPxxxxxxxxSxxxxxxsxxxxxxxx") + \ + sizeof(L"IBA\\VxxxxxxPxxxxxxxxvxxxx") + \ + sizeof(L"IBA\\VxxxxxxPxxxxxxxx\0\0") +#define IOC_COMPAT_ID_SIZE \ + sizeof(L"IBA\\Cxxxxcxxxxpxxxxrxxxx") + \ + sizeof(L"IBA\\Cxxxxcxxxxpxxxx\0\0") +#define IOC_LOCATION_SIZE \ + sizeof(L"Chassis 0xxxxxxxxxxxxxxxxx, Slot xx, IOC xx") + +/* + * Device extension for IOU PDOs. + */ +typedef struct _ioc_ext +{ + iou_pdo_ext_t pdo; + + ib_ioc_info_t info; + ib_svc_entry_t svc_entries[1]; + +} ioc_ext_t; + + +/* + * Function prototypes. + */ +void +destroying_ioc_mgr( + IN cl_obj_t* p_obj ); + +void +free_ioc_mgr( + IN cl_obj_t* p_obj ); + +ib_api_status_t +ioc_mgr_pnp_cb( + IN ib_pnp_rec_t* p_pnp_rec ); + +ib_api_status_t +ioc_mgr_ioc_add( + IN ib_pnp_ioc_rec_t* p_pnp_rec ); + +void +ioc_mgr_ioc_remove( + IN ib_pnp_ioc_rec_t* p_pnp_rec ); + +static NTSTATUS +ioc_start( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static void +ioc_release_resources( + IN DEVICE_OBJECT* const p_dev_obj ); + +static NTSTATUS +ioc_remove( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +ioc_surprise_remove( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +ioc_query_capabilities( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +ioc_query_target_relations( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +ioc_query_device_id( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp ); + +static NTSTATUS +ioc_query_hardware_ids( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp ); + +static NTSTATUS +ioc_query_compatible_ids( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp ); + +static NTSTATUS +ioc_query_unique_id( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp ); + +static NTSTATUS +ioc_query_description( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp ); + +static NTSTATUS +ioc_query_location( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp ); + +static NTSTATUS +ioc_query_bus_info( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +ioc_query_interface( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +ioc_set_power( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + + + +/* + * Global virtual function pointer tables shared between all + * instances of Port PDOs. + */ +static const cl_vfptr_pnp_po_t vfptr_ioc_pnp = { + "IB IOC", + ioc_start, + cl_irp_succeed, + cl_irp_succeed, + cl_irp_succeed, + cl_irp_succeed, + ioc_release_resources, + ioc_remove, + cl_irp_succeed, + ioc_surprise_remove, + ioc_query_capabilities, + cl_irp_complete, + cl_irp_complete, + cl_irp_succeed, + cl_irp_complete, + cl_irp_complete, + cl_irp_complete, + ioc_query_target_relations, + cl_irp_complete, + cl_irp_complete, + cl_irp_complete, + ioc_query_bus_info, + ioc_query_interface, + cl_irp_complete, + cl_irp_complete, + cl_irp_complete, + cl_irp_complete, + cl_irp_succeed, // QueryPower + ioc_set_power, // SetPower + cl_irp_unsupported, // PowerSequence + cl_irp_unsupported // WaitWake +}; + + +static const cl_vfptr_query_txt_t vfptr_iou_query_txt = { + ioc_query_device_id, + ioc_query_hardware_ids, + ioc_query_compatible_ids, + ioc_query_unique_id, + ioc_query_description, + ioc_query_location +}; + + +void +ioc_mgr_construct( + IN OUT ioc_mgr_t* const p_ioc_mgr ) +{ + IOU_ENTER( IOU_DBG_PNP ); + + /* Construct the IOC manager service. */ + cl_obj_construct( &p_ioc_mgr->obj, 0 ); + cl_mutex_construct( &p_ioc_mgr->pdo_mutex ); + cl_qlist_init( &p_ioc_mgr->pdo_list ); + + IOU_EXIT( IOU_DBG_PNP ); +} + + +ib_api_status_t +ioc_mgr_init( + IN OUT ioc_mgr_t* const p_ioc_mgr ) +{ + ib_pnp_req_t pnp_req; + ib_api_status_t status; + cl_status_t cl_status; + + IOU_ENTER( IOU_DBG_PNP ); + + cl_status = cl_mutex_init( &p_ioc_mgr->pdo_mutex ); + if( cl_status != CL_SUCCESS ) + { + free_ioc_mgr( &p_ioc_mgr->obj ); + IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR, + ("cl_mutex_init returned %#x.\n", cl_status) ); + return IB_ERROR; + } + + cl_status = cl_mutex_init( &p_ioc_mgr->pdo_mutex ); + if( cl_status != CL_SUCCESS ) + { + free_ioc_mgr( &p_ioc_mgr->obj ); + IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR, + ("cl_mutex_init returned %#x.\n", cl_status) ); + return IB_ERROR; + } + + /* Initialize the load service object. */ + cl_status = cl_obj_init( &p_ioc_mgr->obj, CL_DESTROY_SYNC, + destroying_ioc_mgr, NULL, free_ioc_mgr ); + if( cl_status != CL_SUCCESS ) + { + free_ioc_mgr( &p_ioc_mgr->obj ); + IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR, + ("cl_obj_init returned %#x.\n", cl_status) ); + return IB_ERROR; + } + + status = p_ioc_mgr->ifc.open_al( &p_ioc_mgr->h_al ); + if( status != IB_SUCCESS ) + { + cl_obj_destroy( &p_ioc_mgr->obj ); + IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR, + ("open_al returned %s.\n", + p_ioc_mgr->ifc.get_err_str(status)) ); + return status; + } + + /* Register for IOC PnP events. */ + cl_memclr( &pnp_req, sizeof( ib_pnp_req_t ) ); + pnp_req.pnp_class = IB_PNP_IOC; + pnp_req.pnp_context = p_ioc_mgr; + pnp_req.pfn_pnp_cb = ioc_mgr_pnp_cb; + + status = p_ioc_mgr->ifc.reg_pnp( + p_ioc_mgr->h_al, &pnp_req, &p_ioc_mgr->h_pnp ); + if( status != IB_SUCCESS ) + { + cl_obj_destroy( &p_ioc_mgr->obj ); + IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR, + ("ib_reg_pnp returned %s.\n", + p_ioc_mgr->ifc.get_err_str(status)) ); + return status; + } + + /* Reference the load service on behalf of the ib_reg_pnp call. */ + cl_obj_ref( &p_ioc_mgr->obj ); + + IOU_EXIT( IOU_DBG_PNP ); + return IB_SUCCESS; +} + + +/* + * Pre-destroy the load service. + */ +void +destroying_ioc_mgr( + IN cl_obj_t* p_obj ) +{ + ioc_mgr_t *p_ioc_mgr; + ib_api_status_t status; + + IOU_ENTER( IOU_DBG_PNP ); + + CL_ASSERT( p_obj ); + + p_ioc_mgr = PARENT_STRUCT( p_obj, ioc_mgr_t, obj ); + + /* Deregister for port PnP events. */ + if( p_ioc_mgr->h_pnp ) + { + status = p_ioc_mgr->ifc.dereg_pnp( + p_ioc_mgr->h_pnp, (ib_pfn_destroy_cb_t)cl_obj_deref ); + CL_ASSERT( status == IB_SUCCESS ); + } + IOU_EXIT( IOU_DBG_PNP ); +} + + +/* + * Free the load service. + */ +void +free_ioc_mgr( + IN cl_obj_t* p_obj ) +{ + ioc_mgr_t *p_ioc_mgr; + ioc_ext_t *p_iou_ext; + cl_list_item_t *p_list_item; + + IOU_ENTER( IOU_DBG_PNP ); + + CL_ASSERT( p_obj ); + p_ioc_mgr = PARENT_STRUCT( p_obj, ioc_mgr_t, obj ); + + /* + * Mark all IOCs as no longer present. This will cause them + * to be removed when they process the IRP_MN_REMOVE_DEVICE. + */ + p_list_item = cl_qlist_remove_head( &p_ioc_mgr->pdo_list ); + while( p_list_item != cl_qlist_end( &p_ioc_mgr->pdo_list ) ) + { + p_iou_ext = PARENT_STRUCT( + PARENT_STRUCT( p_list_item, iou_pdo_ext_t, list_item ), + ioc_ext_t, pdo ); + p_list_item = cl_qlist_remove_head( &p_ioc_mgr->pdo_list ); + if( p_iou_ext->pdo.cl_ext.pnp_state == SurpriseRemoved ) + { + CL_ASSERT( !p_iou_ext->pdo.b_present ); + p_iou_ext->pdo.b_reported_missing = TRUE; + continue; + } + IoDeleteDevice( p_iou_ext->pdo.cl_ext.p_self_do ); + } + + cl_mutex_destroy( &p_ioc_mgr->pdo_mutex ); + cl_obj_deinit( p_obj ); + IOU_EXIT( IOU_DBG_PNP ); +} + + +/* + * Load service PnP event callback. + */ +ib_api_status_t +ioc_mgr_pnp_cb( + IN ib_pnp_rec_t* p_pnp_rec ) +{ + ib_api_status_t status; + ioc_mgr_t *p_ioc_mgr; + + IOU_ENTER( IOU_DBG_PNP ); + + CL_ASSERT( p_pnp_rec ); + p_ioc_mgr = (ioc_mgr_t*)p_pnp_rec->pnp_context; + + switch( p_pnp_rec->pnp_event ) + { + case IB_PNP_IOC_ADD: + status = ioc_mgr_ioc_add( (ib_pnp_ioc_rec_t*)p_pnp_rec ); + break; + + case IB_PNP_IOC_REMOVE: + ioc_mgr_ioc_remove( (ib_pnp_ioc_rec_t*)p_pnp_rec ); + + default: + status = IB_SUCCESS; + break; + } + IOU_EXIT( IOU_DBG_PNP ); + return status; +} + + +/* + * Called to get child relations for the bus root. + */ +NTSTATUS +ioc_mgr_get_iou_relations( + IN ioc_mgr_t* const p_ioc_mgr, + IN IRP* const p_irp ) +{ + NTSTATUS status; + size_t n_devs; + DEVICE_RELATIONS *p_rel; + + IOU_ENTER( IOU_DBG_PNP ); + + /* If there are already relations, copy them. */ + cl_mutex_acquire( &p_ioc_mgr->pdo_mutex ); + n_devs = cl_qlist_count( &p_ioc_mgr->pdo_list ); + if( !n_devs ) + { + cl_mutex_release( &p_ioc_mgr->pdo_mutex ); + IOU_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IOU_DBG_PNP, + ("No child PDOs.\n") ); + return STATUS_NO_SUCH_DEVICE; + } + + /* Add space for our child IOUs. */ + status = cl_alloc_relations( p_irp, n_devs ); + if( !NT_SUCCESS( status ) ) + { + cl_mutex_release( &p_ioc_mgr->pdo_mutex ); + IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR, + ("cl_alloc_relations returned %08x.\n", status) ); + return status; + } + + p_rel = (DEVICE_RELATIONS*)p_irp->IoStatus.Information; + update_relations( &p_ioc_mgr->pdo_list, p_rel ); + cl_mutex_release( &p_ioc_mgr->pdo_mutex ); + IOU_EXIT( IOU_DBG_PNP ); + return STATUS_SUCCESS; +} + +BOOLEAN is_vnic_profile_ioc(ib_ioc_profile_t *p_profile) +{ + BOOLEAN b_vnic = FALSE; + + if( ib_ioc_profile_get_vend_id( p_profile ) == 0x00066a && + p_profile->dev_id == CL_HTON32(0x00000030) ) + { + + b_vnic = TRUE; + } + + return b_vnic; + +} + +ib_api_status_t +ioc_mgr_ioc_add( + IN ib_pnp_ioc_rec_t* p_pnp_rec ) +{ + NTSTATUS status; + DEVICE_OBJECT *p_pdo = NULL; + iou_fdo_ext_t *p_ext; + ioc_mgr_t *p_ioc_mgr; + ioc_ext_t *p_ioc_ext; + uint32_t ext_size; + child_device_info_list_t *pCurList; + BOOLEAN b_vnic_ioc = FALSE; + ca_ioc_map_t *p_map = NULL; + + IOU_ENTER( IOU_DBG_PNP ); + + p_ioc_mgr = PARENT_STRUCT( p_pnp_rec->pnp_rec.pnp_context, ioc_mgr_t, obj ); + p_ext = PARENT_STRUCT( p_ioc_mgr, iou_fdo_ext_t, ioc_mgr ); + + if( p_pnp_rec->ca_guid != p_ioc_mgr->info.ca_guid || + p_pnp_rec->info.chassis_guid != p_ioc_mgr->info.chassis_guid || + p_pnp_rec->info.chassis_slot != p_ioc_mgr->info.slot|| + p_pnp_rec->info.iou_guid != p_ioc_mgr->info.guid ) + { + IOU_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IOU_DBG_PNP, + ("IOC not in this IOU.\n") ); + return IB_NOT_DONE; + } + + p_map = cl_zalloc(sizeof(ca_ioc_map_t)); + + if ( !p_map ) + { + IOU_PRINT_EXIT(TRACE_LEVEL_INFORMATION, IOU_DBG_PNP, + (" Insufficient Memory.\n" )); + return IB_INSUFFICIENT_MEMORY; + } + + p_map->ca_guid = p_pnp_rec->ca_guid; + p_map->info = p_pnp_rec->info; + p_map->p_ioc_mgr = p_ioc_mgr; + cl_memcpy( p_map->svc_entry_array, p_pnp_rec->svc_entry_array, + p_pnp_rec->info.profile.num_svc_entries ); + + cl_mutex_acquire(&iou_globals.list_mutex); + cl_qlist_insert_tail( &iou_globals.ca_ioc_map_list, &p_map->ioc_list); + cl_mutex_release( &iou_globals.list_mutex ); + + b_vnic_ioc = is_vnic_profile_ioc( &p_pnp_rec->info.profile ); + pCurList = iou_globals.p_device_list; + + if ( b_vnic_ioc && !pCurList ) + { + IOU_PRINT_EXIT(TRACE_LEVEL_INFORMATION, IOU_DBG_PNP, + ("There is no device list for VNIC IOCs\n")); + return IB_NOT_DONE; + } + + ext_size = sizeof(ioc_ext_t) + + (sizeof(ib_svc_entry_t) * p_pnp_rec->info.profile.num_svc_entries); + + do + { + if ( b_vnic_ioc ) + { + if ( p_pnp_rec->ca_guid != + pCurList->io_device_info.ca_ioc_path.ca_guid || + p_pnp_rec->info.profile.ioc_guid != + pCurList->io_device_info.ca_ioc_path.info.profile.ioc_guid) + { + pCurList = pCurList->next_device_info; + continue; + } + } + /* Create the PDO for the new port device. */ + status = IoCreateDevice( iou_globals.p_driver_obj, ext_size, + NULL, FILE_DEVICE_CONTROLLER, + FILE_DEVICE_SECURE_OPEN | FILE_AUTOGENERATED_DEVICE_NAME, + FALSE, &p_pdo ); + if( !NT_SUCCESS( status ) ) + { + IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR, + ("IoCreateDevice returned %08x.\n", status) ); + return IB_ERROR; + } + + /* Initialize the device extension. */ + cl_init_pnp_po_ext( p_pdo, NULL, p_pdo, g_iou_dbg_flags, + &vfptr_ioc_pnp, &vfptr_iou_query_txt ); + + /* Set the DO_BUS_ENUMERATED_DEVICE flag to mark it as a PDO. */ + p_pdo->Flags |= DO_BUS_ENUMERATED_DEVICE; + + p_ioc_ext = p_pdo->DeviceExtension; + p_ioc_ext->pdo.dev_po_state.DeviceState = PowerDeviceD0; + p_ioc_ext->pdo.p_parent_ext = p_ext; + p_ioc_ext->pdo.b_present = TRUE; + p_ioc_ext->pdo.b_reported_missing = FALSE; + p_ioc_ext->pdo.ca_guid = p_pnp_rec->ca_guid; + + + if ( b_vnic_ioc ) + { + p_ioc_ext->pdo.p_pdo_device_info = &pCurList->io_device_info; + } + + + /* Copy the IOC profile and service entries. */ + p_ioc_ext->info = p_pnp_rec->info; + cl_memcpy( p_ioc_ext->svc_entries, p_pnp_rec->svc_entry_array, + p_pnp_rec->info.profile.num_svc_entries ); + /* Make sure the IOC string is null terminated. */ + p_ioc_ext->info.profile.id_string[CTRL_ID_STRING_LEN-1] = '\0'; + + /* Store the device extension in the PDO list for future queries. */ + cl_mutex_acquire( &p_ioc_mgr->pdo_mutex ); + cl_qlist_insert_tail( &p_ioc_mgr->pdo_list, + &p_ioc_ext->pdo.list_item ); + cl_mutex_release( &p_ioc_mgr->pdo_mutex ); + + IoInvalidateDeviceRelations( p_ext->cl_ext.p_pdo, BusRelations ); + + if ( b_vnic_ioc ) + { + pCurList = pCurList->next_device_info; + } + else + { + break; + } + + + } while( pCurList ); + + /* + * Set the context of the PNP event. The context is passed in for future + * events on the same port. + */ + + //p_pnp_rec->pnp_rec.context = p_ioc_ext; + /* Tell the PnP Manager to rescan for bus relations. */ + + IOU_EXIT( IOU_DBG_PNP ); + return IB_SUCCESS; +} + + +ca_ioc_map_t *find_ca_ioc_map(net64_t ca_guid, + ib_net64_t ioc_guid/*ib_pnp_ioc_rec_t *p_pnp_rec*/) +{ + cl_list_item_t *list_item; + ca_ioc_map_t *p_map = NULL; + + cl_mutex_acquire( &iou_globals.list_mutex ); + + list_item = cl_qlist_head( &iou_globals.ca_ioc_map_list ); + + while( list_item != cl_qlist_end( &iou_globals.ca_ioc_map_list ) ) + { + p_map = ( ca_ioc_map_t * ) list_item; + if ( p_map->ca_guid != ca_guid || + p_map->info.profile.ioc_guid != ioc_guid ) + { + + list_item = cl_qlist_next( list_item ); + continue; + } + break; + } + + if ( list_item == cl_qlist_end( &iou_globals.ca_ioc_map_list ) ) + p_map = NULL; + + cl_mutex_release( &iou_globals.list_mutex ); + return p_map; +} + +void +ioc_mgr_ioc_remove( + IN ib_pnp_ioc_rec_t* p_pnp_rec ) +{ + ioc_mgr_t *p_ioc_mgr; + ioc_ext_t *p_ioc_ext; + iou_pdo_ext_t *p_iou_pdo_ext; + + ca_ioc_map_t *p_map; + cl_list_item_t *list_item; + + IOU_ENTER( IOU_DBG_PNP ); + + p_ioc_mgr = PARENT_STRUCT( p_pnp_rec->pnp_rec.pnp_context, ioc_mgr_t, obj ); + + p_map = find_ca_ioc_map( p_pnp_rec->ca_guid, + p_pnp_rec->info.profile.ioc_guid ); + + if ( p_map ) + { + cl_mutex_acquire( &iou_globals.list_mutex ); + cl_qlist_remove_item( &iou_globals.ca_ioc_map_list, &p_map->ioc_list ); + cl_mutex_release( &iou_globals.list_mutex ); + cl_free(p_map); + } + + list_item = cl_qlist_head(&p_ioc_mgr->pdo_list); + + while ( list_item != cl_qlist_end(&p_ioc_mgr->pdo_list) ) + { + p_iou_pdo_ext = PARENT_STRUCT(list_item, iou_pdo_ext_t, list_item); + p_ioc_ext = PARENT_STRUCT(p_iou_pdo_ext, ioc_ext_t, pdo); + + if ( p_pnp_rec->ca_guid != p_ioc_ext->pdo.ca_guid || + p_pnp_rec->info.profile.ioc_guid != + p_ioc_ext->info.profile.ioc_guid ) + { + list_item = cl_qlist_next( list_item ); + continue; + } + cl_mutex_acquire( &p_ioc_mgr->pdo_mutex ); + p_ioc_ext->pdo.b_present = FALSE; + cl_mutex_release( &p_ioc_mgr->pdo_mutex ); + + list_item = cl_qlist_next( list_item ); + /* Invalidate bus relations for the bus root. */ + IoInvalidateDeviceRelations( + p_ioc_ext->pdo.p_parent_ext->cl_ext.p_pdo, BusRelations ); + + + } + + IOU_EXIT( IOU_DBG_PNP ); +} + + +static NTSTATUS +ioc_start( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + iou_pdo_ext_t *p_ext; + + IOU_ENTER( IOU_DBG_PNP ); + + UNUSED_PARAM( p_irp ); + + p_ext = p_dev_obj->DeviceExtension; + + /* Notify the Power Manager that the device is started. */ + PoSetPowerState( p_dev_obj, DevicePowerState, p_ext->dev_po_state ); + + *p_action = IrpComplete; + IOU_EXIT( IOU_DBG_PNP ); + return STATUS_SUCCESS; +} + + +static void +ioc_release_resources( + IN DEVICE_OBJECT* const p_dev_obj ) +{ + ioc_mgr_t *p_ioc_mgr; + ioc_ext_t *p_ext; + POWER_STATE po_state; + + IOU_ENTER( IOU_DBG_PNP ); + + p_ext = p_dev_obj->DeviceExtension; + p_ioc_mgr = &p_ext->pdo.p_parent_ext->ioc_mgr; + + /* Remove this PDO from its list. */ + cl_mutex_acquire( &p_ioc_mgr->pdo_mutex ); + IOU_PRINT( TRACE_LEVEL_INFORMATION, IOU_DBG_PNP, + ("Removing IOC from list.\n") ); + cl_qlist_remove_item( &p_ioc_mgr->pdo_list, &p_ext->pdo.list_item ); + cl_mutex_release( &p_ioc_mgr->pdo_mutex ); + po_state.DeviceState = PowerDeviceD3; + PoSetPowerState( p_ext->pdo.cl_ext.p_pdo, DevicePowerState, po_state ); + + IOU_EXIT( IOU_DBG_PNP ); +} + + +static NTSTATUS +ioc_remove( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + ioc_ext_t *p_ext; + + IOU_ENTER( IOU_DBG_PNP ); + + p_ext = p_dev_obj->DeviceExtension; + + if( p_ext->pdo.b_present ) + { + CL_ASSERT( p_ext->pdo.cl_ext.pnp_state != NotStarted ); + CL_ASSERT( !p_ext->pdo.b_reported_missing ); + /* Reset the state to NotStarted. CompLib set it to Deleted. */ + cl_set_pnp_state( &p_ext->pdo.cl_ext, NotStarted ); + /* Don't delete the device. It may simply be disabled. */ + *p_action = IrpComplete; + IOU_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IOU_DBG_PNP, + ("Device still present.\n") ); + return STATUS_SUCCESS; + } + + if( !p_ext->pdo.b_reported_missing ) + { + /* Reset the state to RemovePending. Complib set it to Deleted. */ + cl_rollback_pnp_state( &p_ext->pdo.cl_ext ); + *p_action = IrpComplete; + IOU_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IOU_DBG_PNP, + ("Device not reported missing yet.\n") ); + return STATUS_SUCCESS; + } + + /* Wait for all I/O operations to complete. */ + IoReleaseRemoveLockAndWait( &p_ext->pdo.cl_ext.remove_lock, p_irp ); + + /* Release resources if it was not done yet. */ + if( p_ext->pdo.cl_ext.last_pnp_state != SurpriseRemoved ) + p_ext->pdo.cl_ext.vfptr_pnp_po->pfn_release_resources( p_dev_obj ); + + p_irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest( p_irp, IO_NO_INCREMENT ); + + IoDeleteDevice( p_dev_obj ); + + *p_action = IrpDoNothing; + IOU_EXIT( IOU_DBG_PNP ); + return STATUS_SUCCESS; +} + + +static NTSTATUS +ioc_surprise_remove( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + ioc_ext_t *p_ext; + + IOU_ENTER( IOU_DBG_PNP ); + + UNUSED_PARAM( p_irp ); + + p_ext = p_dev_obj->DeviceExtension; + p_ext->pdo.b_present = FALSE; + p_ext->pdo.b_reported_missing = TRUE; + + *p_action = IrpComplete; + + IOU_EXIT( IOU_DBG_PNP ); + return STATUS_SUCCESS; +} + + +static NTSTATUS +ioc_query_capabilities( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + DEVICE_CAPABILITIES *p_caps; + IO_STACK_LOCATION *p_io_stack; + + IOU_ENTER( IOU_DBG_PNP ); + + UNUSED_PARAM( p_dev_obj ); + + p_io_stack = IoGetCurrentIrpStackLocation( p_irp ); + p_caps = p_io_stack->Parameters.DeviceCapabilities.Capabilities; + + p_caps->DeviceD1 = FALSE; + p_caps->DeviceD2 = FALSE; + p_caps->LockSupported = FALSE; + p_caps->EjectSupported = FALSE; + p_caps->Removable = TRUE; + p_caps->DockDevice = FALSE; + p_caps->UniqueID = TRUE; + p_caps->SilentInstall = TRUE; + p_caps->RawDeviceOK = FALSE; + p_caps->SurpriseRemovalOK = FALSE; + p_caps->WakeFromD0 = FALSE; + p_caps->WakeFromD1 = FALSE; + p_caps->WakeFromD2 = FALSE; + p_caps->WakeFromD3 = FALSE; + p_caps->HardwareDisabled = FALSE; + p_caps->DeviceState[PowerSystemWorking] = PowerDeviceD0; + p_caps->DeviceState[PowerSystemSleeping1] = PowerDeviceD3; + p_caps->DeviceState[PowerSystemSleeping2] = PowerDeviceD3; + p_caps->DeviceState[PowerSystemSleeping3] = PowerDeviceD3; + p_caps->DeviceState[PowerSystemHibernate] = PowerDeviceD3; + p_caps->DeviceState[PowerSystemShutdown] = PowerDeviceD3; + p_caps->SystemWake = PowerSystemUnspecified; + p_caps->DeviceWake = PowerDeviceUnspecified; + p_caps->D1Latency = 0; + p_caps->D2Latency = 0; + p_caps->D3Latency = 0; + + *p_action = IrpComplete; + IOU_EXIT( IOU_DBG_PNP ); + return STATUS_SUCCESS; +} + + +static NTSTATUS +ioc_query_target_relations( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + NTSTATUS status; + DEVICE_RELATIONS *p_rel; + + IOU_ENTER( IOU_DBG_PNP ); + + *p_action = IrpComplete; + + status = cl_alloc_relations( p_irp, 1 ); + if( !NT_SUCCESS( status ) ) + { + IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR, + ("cl_alloc_relations returned 0x%08x.\n", status) ); + return status; + } + + p_rel = (DEVICE_RELATIONS*)p_irp->IoStatus.Information; + p_rel->Count = 1; + p_rel->Objects[0] = p_dev_obj; + + ObReferenceObject( p_dev_obj ); + + IOU_EXIT( IOU_DBG_PNP ); + return status; +} + + +static NTSTATUS +ioc_query_device_id( + IN DEVICE_OBJECT* const p_dev_obj, + OUT IRP* const p_irp ) +{ + ioc_ext_t *p_ext; + WCHAR *p_string; + uint32_t dev_id_size; + NTSTATUS status; + + IOU_ENTER( IOU_DBG_PNP ); + + p_ext = (ioc_ext_t*)p_dev_obj->DeviceExtension; + + if( !p_ext->pdo.b_present ) + { + IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR, + ("Device not present.\n") ); + return STATUS_NO_SUCH_DEVICE; + } + + if (p_ext->pdo.p_pdo_device_info) + { + + dev_id_size = (p_ext->pdo.p_pdo_device_info)->device_id_size; + p_string = ExAllocatePoolWithTag( NonPagedPool, dev_id_size, 'didq' ); + + if( !p_string ) + { + IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR, + ( "Failed to allocate device ID buffer (%u bytes).\n", + dev_id_size ) ); + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlZeroMemory( p_string, dev_id_size ); + + cl_memcpy( p_string, p_ext->pdo.p_pdo_device_info->device_id, dev_id_size ); + } + else + { + p_string = ExAllocatePoolWithTag( NonPagedPool, IOC_DEV_ID_SIZE, 'didq' ); + if( !p_string ) + { + IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR, + ("Failed to allocate device ID buffer (%d bytes).\n", + IOC_DEV_ID_SIZE) ); + return STATUS_INSUFFICIENT_RESOURCES; + } + + status = RtlStringCbPrintfW( p_string, IOC_DEV_ID_SIZE, + L"IBA\\V%06xP%08xS%06xs%08xv%04x", + ib_ioc_profile_get_vend_id( &p_ext->info.profile ), + cl_ntoh32( p_ext->info.profile.dev_id ), + ib_ioc_profile_get_subsys_vend_id( &p_ext->info.profile ), + cl_ntoh32( p_ext->info.profile.subsys_id ), + cl_ntoh16( p_ext->info.profile.dev_ver ) ); + if( !NT_SUCCESS( status ) ) + { + ExFreePool( p_string ); + IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR, + ("Failed to format device ID string.\n") ); + return status; + } + + } + + p_irp->IoStatus.Information = (ULONG_PTR)p_string; + + IOU_EXIT( IOU_DBG_PNP ); + return STATUS_SUCCESS; +} + + +static NTSTATUS +ioc_query_hardware_ids( + IN DEVICE_OBJECT* const p_dev_obj, + OUT IRP* const p_irp ) +{ + ioc_ext_t *p_ext; + WCHAR *p_string, *p_start; + size_t size; + uint32_t V,P,S,s, hw_id_size; + uint16_t v; + NTSTATUS status; + + IOU_ENTER( IOU_DBG_PNP ); + + p_ext = (ioc_ext_t*)p_dev_obj->DeviceExtension; + if( !p_ext->pdo.b_present ) + { + IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR, + ("Device not present.\n") ); + return STATUS_NO_SUCH_DEVICE; + } + + if (p_ext->pdo.p_pdo_device_info) + { + hw_id_size = p_ext->pdo.p_pdo_device_info->hardware_id_size; + + p_string = ExAllocatePoolWithTag( NonPagedPool, hw_id_size, 'ihqi' ); + if( !p_string ) + { + IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR, + ( "Failed to allocate hardware ID buffer (%d bytes).\n", + hw_id_size ) ); + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlZeroMemory( p_string, hw_id_size ); + + cl_memcpy( p_string, p_ext->pdo.p_pdo_device_info->hardware_id, hw_id_size ); + } + else + { + p_string = ExAllocatePoolWithTag( NonPagedPool, IOC_HW_ID_SIZE, 'ihqi' ); + if( !p_string ) + { + IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR, + ("Failed to allocate hardware ID buffer (%d bytes).\n", + IOC_HW_ID_SIZE) ); + return STATUS_INSUFFICIENT_RESOURCES; + } + + V = ib_ioc_profile_get_vend_id( &p_ext->info.profile ); + P = cl_ntoh32( p_ext->info.profile.dev_id ); + S = ib_ioc_profile_get_subsys_vend_id( &p_ext->info.profile ); + s = cl_ntoh32( p_ext->info.profile.subsys_id ); + v = cl_ntoh16( p_ext->info.profile.dev_ver ); + + /* Fill in the first hardware ID. */ + p_start = p_string; + size = IOC_HW_ID_SIZE; + status = RtlStringCbPrintfExW( p_start, size, &p_start, &size, + STRSAFE_FILL_BEHIND_NULL, L"IBA\\V%06xP%08xS%06xs%08xv%04x", + V, P, S, s, v ); + if( !NT_SUCCESS( status ) ) + { + ExFreePool( p_string ); + IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR, + ("Failed to format hardware ID string.\n") ); + return status; + } + /* Fill in the second hardware ID. */ + p_start++; + size -= sizeof(WCHAR); + status = RtlStringCbPrintfExW( p_start, size, &p_start, &size, + STRSAFE_FILL_BEHIND_NULL, L"IBA\\V%06xP%08xS%06xs%08x", V, P, S, s ); + if( !NT_SUCCESS( status ) ) + { + ExFreePool( p_string ); + IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR, + ("Failed to format hardware ID string.\n") ); + return status; + } + /* Fill in the third hardware ID. */ + p_start++; + size -= sizeof(WCHAR); + status = RtlStringCbPrintfExW( p_start, size, &p_start, &size, + STRSAFE_FILL_BEHIND_NULL, L"IBA\\V%06xP%08xv%04x", V, P, v ); + if( !NT_SUCCESS( status ) ) + { + ExFreePool( p_string ); + IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR, + ("Failed to format hardware ID string.\n") ); + return status; + } + /* Fill in the fourth hardware ID. */ + p_start++; + size -= sizeof(WCHAR); + status = RtlStringCbPrintfExW( p_start, size, &p_start, &size, + STRSAFE_FILL_BEHIND_NULL, L"IBA\\V%06xP%08x", V, P ); + if( !NT_SUCCESS( status ) ) + { + ExFreePool( p_string ); + IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR, + ("Failed to format hardware ID string.\n") ); + return status; + } + } + + p_irp->IoStatus.Information = (ULONG_PTR)p_string; + + IOU_EXIT( IOU_DBG_PNP ); + return STATUS_SUCCESS; +} + + +static NTSTATUS +ioc_query_compatible_ids( + IN DEVICE_OBJECT* const p_dev_obj, + OUT IRP* const p_irp ) +{ + ioc_ext_t *p_ext; + WCHAR *p_string, *p_start; + uint32_t compat_id_size; + size_t size; + uint16_t C, c, p, r; + NTSTATUS status; + + + IOU_ENTER( IOU_DBG_PNP ); + + p_ext = (ioc_ext_t*)p_dev_obj->DeviceExtension; + if( !p_ext->pdo.b_present ) + { + IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR, + ("Device not present.\n") ); + return STATUS_NO_SUCH_DEVICE; + } + + if ( p_ext->pdo.p_pdo_device_info ) + { + + compat_id_size = p_ext->pdo.p_pdo_device_info->compatible_id_size; + + p_string = ExAllocatePoolWithTag( NonPagedPool, compat_id_size, 'icqi' ); + + if( !p_string ) + { + IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR, + ("Failed to allocate compatible ID buffer (%d bytes).\n", + compat_id_size) ); + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlZeroMemory( p_string, compat_id_size ); + + cl_memcpy( p_string, p_ext->pdo.p_pdo_device_info->compatible_id, compat_id_size ); + } + else + { + p_string = ExAllocatePoolWithTag( NonPagedPool, IOC_COMPAT_ID_SIZE, 'icqi' ); + if( !p_string ) + { + IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR, + ("Failed to allocate compatible ID buffer (%d bytes).\n", + IOC_HW_ID_SIZE) ); + return STATUS_INSUFFICIENT_RESOURCES; + } + + C = cl_ntoh16( p_ext->info.profile.io_class ); + c = cl_ntoh16( p_ext->info.profile.io_subclass ); + p = cl_ntoh16( p_ext->info.profile.protocol ); + r = cl_ntoh16( p_ext->info.profile.protocol_ver ); + + p_start = p_string; + size = IOC_COMPAT_ID_SIZE; + /* Fill in the first compatible ID. */ + status = RtlStringCbPrintfExW( p_start, size, &p_start, &size, + STRSAFE_FILL_BEHIND_NULL, L"IBA\\C%04xc%04xp%04xr%04x", C, c, p, r ); + if( !NT_SUCCESS( status ) ) + { + ExFreePool( p_string ); + IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR, + ("Failed to format device ID string.\n") ); + return status; + } + /* Fill in the second compatible ID. */ + p_start++; + size -= sizeof(WCHAR); + status = RtlStringCbPrintfExW( p_start, size, NULL, NULL, + STRSAFE_FILL_BEHIND_NULL, L"IBA\\C%04xc%04xp%04x", C, c, p ); + if( !NT_SUCCESS( status ) ) + { + ExFreePool( p_string ); + IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR, + ("Failed to format device ID string.\n") ); + return status; + } + } + + p_irp->IoStatus.Information = (ULONG_PTR)p_string; + + IOU_EXIT( IOU_DBG_PNP ); + return STATUS_SUCCESS; +} + + +static NTSTATUS +ioc_query_unique_id( + IN DEVICE_OBJECT* const p_dev_obj, + OUT IRP* const p_irp ) +{ + NTSTATUS status; + WCHAR *p_string; + ioc_ext_t *p_ext; + + IOU_ENTER( IOU_DBG_PNP ); + + p_ext = p_dev_obj->DeviceExtension; + if( !p_ext->pdo.b_present ) + { + IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR, + ("Device not present.\n") ); + return STATUS_NO_SUCH_DEVICE; + } + + /* The instance ID is the port GUID. */ + if ( p_ext->pdo.p_pdo_device_info ) + { + + p_string = ExAllocatePoolWithTag( NonPagedPool, sizeof(WCHAR) * 41, 'iuqi' ); + if( !p_string ) + { + IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR, + ("Failed to allocate instance ID buffer (%d bytes).\n", + sizeof(WCHAR) * 41) ); + return STATUS_NO_MEMORY; + } + + status = RtlStringCchPrintfW ( p_string, 41, L"%016I64x%016I64x%08x", + p_ext->info.profile.ioc_guid, p_ext->pdo.ca_guid, + p_ext->pdo.p_pdo_device_info->uniqueinstanceid); + if( !NT_SUCCESS( status ) ) + { + CL_ASSERT( NT_SUCCESS( status ) ); + ExFreePool( p_string ); + IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR, + ("RtlStringCchPrintfW returned %08x.\n", status) ); + return status; + } + } + else + { + p_string = ExAllocatePoolWithTag( NonPagedPool, sizeof(WCHAR) * 33, 'iuqi' ); + if( !p_string ) + { + IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR, + ("Failed to allocate instance ID buffer (%d bytes).\n", + sizeof(WCHAR) * 17) ); + return STATUS_NO_MEMORY; + } + + status = RtlStringCchPrintfW(p_string, 33, L"%016I64x%016I64x", + p_ext->info.profile.ioc_guid,p_ext->pdo.ca_guid); + if( !NT_SUCCESS( status ) ) + { + CL_ASSERT( NT_SUCCESS( status ) ); + ExFreePool( p_string ); + IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR, + ("RtlStringCchPrintfW returned %08x.\n", status) ); + return status; + } + + } + + p_irp->IoStatus.Information = (ULONG_PTR)p_string; + + IOU_EXIT( IOU_DBG_PNP ); + return STATUS_SUCCESS; +} + + +static NTSTATUS +ioc_query_description( + IN DEVICE_OBJECT* const p_dev_obj, + OUT IRP* const p_irp ) +{ + NTSTATUS status; + WCHAR *p_string; + ioc_ext_t *p_ext; + + IOU_ENTER( IOU_DBG_PNP ); + + p_ext = p_dev_obj->DeviceExtension; + if( !p_ext->pdo.b_present ) + { + IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR, + ("Device not present.\n") ); + return STATUS_NO_SUCH_DEVICE; + } + + if ( p_ext->pdo.p_pdo_device_info ) + { + p_string = ExAllocatePoolWithTag( NonPagedPool, p_ext->pdo.p_pdo_device_info->description_size, + 'edqi' ); + if( !p_string ) + { + IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR, + ( "Failed to allocate description buffer (%d bytes).\n", + p_ext->pdo.p_pdo_device_info->description_size ) ); + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlZeroMemory( p_string, p_ext->pdo.p_pdo_device_info->description_size ); + + cl_memcpy( p_string, p_ext->pdo.p_pdo_device_info->description, + p_ext->pdo.p_pdo_device_info->description_size ); + + } + else + { + p_string = ExAllocatePoolWithTag( NonPagedPool, + sizeof(WCHAR) * sizeof(p_ext->info.profile.id_string), + 'edqi'); + if( !p_string ) + { + IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR, + ("Failed to allocate device description buffer (%d bytes).\n", + sizeof(WCHAR) * sizeof(p_ext->info.profile.id_string)) ); + return STATUS_INSUFFICIENT_RESOURCES; + } + + if( ib_ioc_profile_get_vend_id( &p_ext->info.profile ) == 0x00066a && + p_ext->info.profile.dev_id == CL_HTON32(0x00000030) ) + { + status = RtlStringCchPrintfW( + p_string, sizeof(p_ext->info.profile.id_string), + L"SilverStorm Technologies VEx I/O Controller" ); + } + else if( ib_ioc_profile_get_vend_id( &p_ext->info.profile ) == 0x00066a && + p_ext->info.profile.dev_id == CL_HTON32(0x00000038) ) + { + status = RtlStringCchPrintfW( + p_string, sizeof(p_ext->info.profile.id_string), + L"SilverStorm Technologies VFx I/O Controller" ); + } + else + { + status = RtlStringCchPrintfW( + p_string, sizeof(p_ext->info.profile.id_string), + L"%S", p_ext->info.profile.id_string ); + } + if( !NT_SUCCESS( status ) ) + { + CL_ASSERT( NT_SUCCESS( status ) ); + ExFreePool( p_string ); + IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR, + ("RtlStringCchPrintfW returned %08x.\n", status) ); + return status; + } + } + + p_irp->IoStatus.Information = (ULONG_PTR)p_string; + + IOU_EXIT( IOU_DBG_PNP ); + return STATUS_SUCCESS; +} + + +static NTSTATUS +ioc_query_location( + IN DEVICE_OBJECT* const p_dev_obj, + OUT IRP* const p_irp ) +{ + NTSTATUS status; + ioc_ext_t *p_ext; + WCHAR *p_string; + + IOU_ENTER( IOU_DBG_PNP ); + + p_ext = (ioc_ext_t*)p_dev_obj->DeviceExtension; + if( !p_ext->pdo.b_present ) + { + IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR, + ("Device not present.\n") ); + return STATUS_NO_SUCH_DEVICE; + } + + p_string = ExAllocatePoolWithTag( NonPagedPool, + max( IOC_LOCATION_SIZE, sizeof( WCHAR ) * + ( sizeof( p_ext->info.profile.id_string ) + 1 )), + 'olqi'); + if( !p_string ) + { + IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR, + ("Failed to allocate location buffer (%d bytes).\n", + IOC_LOCATION_SIZE) ); + return STATUS_INSUFFICIENT_RESOURCES; + } + + if( ib_ioc_profile_get_vend_id( &p_ext->info.profile ) == 0x00066a ) + { + status = RtlStringCchPrintfW( + p_string, sizeof(p_ext->info.profile.id_string), + L"%S", p_ext->info.profile.id_string ); + } + else + { + status = RtlStringCbPrintfW( p_string, IOC_LOCATION_SIZE, + L"Chassis 0x%016I64x, Slot %d, IOC %d", + cl_ntoh64( p_ext->info.chassis_guid ), + p_ext->info.chassis_slot, p_ext->info.iou_slot ); + } + if( !NT_SUCCESS( status ) ) + { + ExFreePool( p_string ); + IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR, + ("Failed to format device ID string.\n") ); + return status; + } + p_irp->IoStatus.Information = (ULONG_PTR)p_string; + + IOU_EXIT( IOU_DBG_PNP ); + return STATUS_SUCCESS; +} + + +static NTSTATUS +ioc_query_bus_info( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + ioc_ext_t *p_ext; + PNP_BUS_INFORMATION *p_iou_info; + + IOU_ENTER( IOU_DBG_PNP ); + + p_ext = (ioc_ext_t*)p_dev_obj->DeviceExtension; + if( !p_ext->pdo.b_present ) + { + IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR, + ("Device not present.\n") ); + return STATUS_NO_SUCH_DEVICE; + } + + *p_action = IrpComplete; + + p_iou_info = ExAllocatePoolWithTag( NonPagedPool, sizeof(PNP_BUS_INFORMATION), 'ibqi' ); + if( !p_iou_info ) + { + IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR, + ("Failed to allocate PNP_BUS_INFORMATION (%d bytes).\n", + sizeof(PNP_BUS_INFORMATION)) ); + return STATUS_INSUFFICIENT_RESOURCES; + } + + + p_iou_info->BusTypeGuid = GUID_BUS_TYPE_IBA; + //TODO: Memory from Intel - storage miniport would not stay loaded unless + //TODO: bus type was PCI. Look here if SRP is having problems staying + //TODO: loaded. + p_iou_info->LegacyBusType = PNPBus; + p_iou_info->BusNumber = p_ext->info.iou_slot; + + p_irp->IoStatus.Information = (ULONG_PTR)p_iou_info; + IOU_EXIT( IOU_DBG_PNP ); + return STATUS_SUCCESS; +} + + +static __ref_ioc_ifc( + IN ioc_ext_t* p_ext ) +{ + IOU_ENTER( IOU_DBG_PNP ); + + cl_atomic_inc( &p_ext->pdo.p_parent_ext->cl_ext.n_ifc_ref ); + ObReferenceObject( p_ext->pdo.p_parent_ext->cl_ext.p_self_do ); + + IOU_EXIT( IOU_DBG_PNP ); +} + + +static void +__deref_ioc_ifc( + IN ioc_ext_t* p_ext ) +{ + IOU_ENTER( IOU_DBG_PNP ); + + cl_atomic_dec( &p_ext->pdo.p_parent_ext->cl_ext.n_ifc_ref ); + ObDereferenceObject( p_ext->pdo.p_parent_ext->cl_ext.p_self_do ); + + IOU_EXIT( IOU_DBG_PNP ); +} + + + + +static NTSTATUS +ioc_query_interface( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + NTSTATUS status; + IO_STACK_LOCATION *p_io_stack; + ib_al_ifc_t *p_ifc; + ib_al_ifc_data_t *p_ifc_data; + ioc_ifc_data_t *p_ioc_data; + ioc_ext_t *p_ext; + const GUID *p_guid; + + IOU_ENTER( IOU_DBG_PNP ); + + CL_ASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL ); + + p_ext = p_dev_obj->DeviceExtension; + p_io_stack = IoGetCurrentIrpStackLocation( p_irp ); + p_guid = p_io_stack->Parameters.QueryInterface.InterfaceType; + /* Bottom of the stack - IRP must be completed. */ + *p_action = IrpComplete; + + /* Compare requested GUID with our supported interface GUIDs. */ + if( IsEqualGUID( p_guid, &GUID_BUS_INTERFACE_STANDARD ) ) + { + IOU_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IOU_DBG_PNP, + ("BUS_INTERFACE_STANDARD\n") ); + return cl_fwd_query_ifc( + p_ext->pdo.p_parent_ext->cl_ext.p_self_do, p_io_stack ); + } + + if( !IsEqualGUID( p_guid, &GUID_IB_AL_INTERFACE ) ) + { + IOU_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IOU_DBG_PNP, + ("Unsupported interface: \n\t" + "0x%08x, 0x%04x, 0x%04x, 0x%02x, 0x%02x, 0x%02x," + "0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x.\n", + p_guid->Data1, p_guid->Data2, p_guid->Data3, + p_guid->Data4[0], p_guid->Data4[1], p_guid->Data4[2], + p_guid->Data4[3], p_guid->Data4[4], p_guid->Data4[5], + p_guid->Data4[6], p_guid->Data4[7]) ); + return p_irp->IoStatus.Status; + } + + /* Get the interface. */ + status = cl_fwd_query_ifc( + p_ext->pdo.p_parent_ext->cl_ext.p_self_do, p_io_stack ); + if( !NT_SUCCESS( status ) ) + { + IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR, + ("Failed to forward interface query: %08X\n", status) ); + return status; + } + + if( !p_io_stack->Parameters.QueryInterface.InterfaceSpecificData ) + { + IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR, + ("No interface specific data!\n") ); + return status; + } + + p_ifc = (ib_al_ifc_t*)p_io_stack->Parameters.QueryInterface.Interface; + + p_ifc_data = (ib_al_ifc_data_t*) + p_io_stack->Parameters.QueryInterface.InterfaceSpecificData; + p_guid = p_ifc_data->type; + if( !IsEqualGUID( p_guid, &GUID_IOC_INTERFACE_DATA ) || + p_ifc_data->version != IOC_INTERFACE_DATA_VERSION ) + { + p_ifc->wdm.InterfaceDereference( p_ifc->wdm.Context ); + IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR, + ("Unsupported interface data: \n\t" + "0x%08x, 0x%04x, 0x%04x, 0x%02x, 0x%02x, 0x%02x," + "0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x.\n", + p_guid->Data1, p_guid->Data2, p_guid->Data3, + p_guid->Data4[0], p_guid->Data4[1], p_guid->Data4[2], + p_guid->Data4[3], p_guid->Data4[4], p_guid->Data4[5], + p_guid->Data4[6], p_guid->Data4[7]) ); + return STATUS_INVALID_PARAMETER; + } + + ASSERT( p_ifc_data->p_data ); + + if( p_ifc_data->size != sizeof(ioc_ifc_data_t) ) + { + p_ifc->wdm.InterfaceDereference( p_ifc->wdm.Context ); + IOU_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IOU_DBG_PNP, + ("Buffer too small (%d given, %d required).\n", + p_ifc_data->size, + sizeof(ioc_ifc_data_t)) ); + return STATUS_BUFFER_TOO_SMALL; + } + + /* Set the interface data. */ + p_ioc_data = (ioc_ifc_data_t*)p_ifc_data->p_data; + + p_ioc_data->ca_guid = p_ext->pdo.p_parent_ext->ioc_mgr.info.ca_guid; + p_ioc_data->guid = p_ext->info.profile.ioc_guid; + + IOU_EXIT( IOU_DBG_PNP ); + return STATUS_SUCCESS; +} + + +/* + * The PDOs created by the IB Bus driver are software devices. As such, + * all power states are supported. It is left to the HCA power policy + * owner to handle which states can be supported by the HCA. + */ +static NTSTATUS +ioc_set_power( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + IO_STACK_LOCATION *p_io_stack; + iou_pdo_ext_t *p_ext; + + IOU_ENTER( IOU_DBG_POWER ); + + p_ext = p_dev_obj->DeviceExtension; + p_io_stack = IoGetCurrentIrpStackLocation( p_irp ); + + if( p_io_stack->Parameters.Power.Type == DevicePowerState ) + { + /* Notify the power manager. */ + p_ext->dev_po_state = p_io_stack->Parameters.Power.State; + PoSetPowerState( p_dev_obj, DevicePowerState, p_ext->dev_po_state ); + } + + *p_action = IrpComplete; + IOU_EXIT( IOU_DBG_POWER ); + return STATUS_SUCCESS; +} + +ib_api_status_t +_create_ioc_pdo( + IN child_device_info_t* p_child_dev, + IN ca_ioc_map_t* p_ca_ioc_map) +{ + NTSTATUS status; + DEVICE_OBJECT *p_pdo = NULL; + iou_fdo_ext_t *p_ext; + ioc_mgr_t *p_ioc_mgr; + ioc_ext_t *p_ioc_ext; + uint32_t ext_size; + BOOLEAN b_vnic_ioc = FALSE; + + p_ioc_mgr = p_ca_ioc_map->p_ioc_mgr; + + p_ext = PARENT_STRUCT( p_ioc_mgr, iou_fdo_ext_t, ioc_mgr ); + + if( p_child_dev->ca_ioc_path.ca_guid != p_ioc_mgr->info.ca_guid || + p_child_dev->ca_ioc_path.info.chassis_guid != p_ioc_mgr->info.chassis_guid || + p_child_dev->ca_ioc_path.info.chassis_slot != p_ioc_mgr->info.slot|| + p_child_dev->ca_ioc_path.info.iou_guid != p_ioc_mgr->info.guid ) + { + IOU_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IOU_DBG_PNP, + ("Child PDO's IOC not in this IOU.\n") ); + return IB_NOT_DONE; + } + + ext_size = sizeof(ioc_ext_t) + + ( sizeof(ib_svc_entry_t) * p_ca_ioc_map->info.profile.num_svc_entries ); + + status = IoCreateDevice( iou_globals.p_driver_obj, ext_size, + NULL, FILE_DEVICE_CONTROLLER, + FILE_DEVICE_SECURE_OPEN | FILE_AUTOGENERATED_DEVICE_NAME, + FALSE, &p_pdo ); + if( !NT_SUCCESS( status ) ) + { + IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR, + ( "IoCreateDevice returned %08x.\n", status ) ); + return IB_ERROR; + } + + b_vnic_ioc = is_vnic_profile_ioc( &p_ca_ioc_map->info.profile ); + + /* Initialize the device extension. */ + cl_init_pnp_po_ext( p_pdo, NULL, p_pdo, g_iou_dbg_flags, + &vfptr_ioc_pnp, &vfptr_iou_query_txt ); + /* Set the DO_BUS_ENUMERATED_DEVICE flag to mark it as a PDO. */ + p_pdo->Flags |= DO_BUS_ENUMERATED_DEVICE; + + p_ioc_ext = p_pdo->DeviceExtension; + p_ioc_ext->pdo.dev_po_state.DeviceState = PowerDeviceD0; + p_ioc_ext->pdo.p_parent_ext = p_ext; + p_ioc_ext->pdo.b_present = TRUE; + p_ioc_ext->pdo.b_reported_missing = FALSE; + p_ioc_ext->pdo.ca_guid = p_child_dev->ca_ioc_path.ca_guid; + + if ( b_vnic_ioc ) + { + p_ioc_ext->pdo.p_pdo_device_info = p_child_dev; + } + + /* Copy the IOC profile and service entries. */ + p_ioc_ext->info = p_child_dev->ca_ioc_path.info; + cl_memcpy( p_ioc_ext->svc_entries, p_child_dev->ca_ioc_path.svc_entry_array, + p_child_dev->ca_ioc_path.info.profile.num_svc_entries ); + /* Make sure the IOC string is null terminated. */ + p_ioc_ext->info.profile.id_string[CTRL_ID_STRING_LEN-1] = '\0'; + + /* Store the device extension in the PDO list for future queries. */ + cl_mutex_acquire( &p_ioc_mgr->pdo_mutex ); + cl_qlist_insert_tail( &p_ioc_mgr->pdo_list, + &p_ioc_ext->pdo.list_item ); + cl_mutex_release( &p_ioc_mgr->pdo_mutex ); + + IoInvalidateDeviceRelations( p_ext->cl_ext.p_pdo, BusRelations ); + + IOU_EXIT(IOU_DBG_PNP); + + return IB_SUCCESS; +} diff --git a/branches/WOF2-3/core/iou/kernel/iou_ioc_mgr.h b/branches/WOF2-3/core/iou/kernel/iou_ioc_mgr.h new file mode 100644 index 00000000..330b2411 --- /dev/null +++ b/branches/WOF2-3/core/iou/kernel/iou_ioc_mgr.h @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + +#if !defined( __IOU_IOU_MGR_H__ ) +#define __IOU_IOU_MGR_H__ + +#include +#include +#include +#include + +/* Global load service */ +typedef struct _ioc_mgr +{ + cl_obj_t obj; + + ib_al_ifc_t ifc; + + ib_al_handle_t h_al; + ib_pnp_handle_t h_pnp; /* Handle for iou PnP events */ + + /* Attributes for this IOU. */ + iou_ifc_data_t info; + + /* Mutex protects both pointer vectors. */ + cl_mutex_t pdo_mutex; + + /* Pointer vector of child IOC PDOs. */ + cl_qlist_t pdo_list; + +} ioc_mgr_t; + + +#pragma pack(push, 1) + +/* Windows pnp device information */ +#define MAX_DEVICE_ID_LEN 200 +#define MAX_DEVICE_STRING_LEN MAX_DEVICE_ID_LEN + 2 //add extra 4 bytes in case we need double NULL ending + +typedef struct _ca_ioc_info { + net64_t ca_guid; + ib_ioc_info_t info; + ib_svc_entry_t svc_entry_array[1]; +} ca_ioc_info_t; + +typedef struct _child_device_info { + wchar_t device_id[MAX_DEVICE_STRING_LEN]; + uint32_t device_id_size; + wchar_t compatible_id[MAX_DEVICE_STRING_LEN]; + uint32_t compatible_id_size; + wchar_t hardware_id[MAX_DEVICE_STRING_LEN]; + uint32_t hardware_id_size; + wchar_t description[MAX_DEVICE_STRING_LEN]; + uint32_t description_size; + ca_ioc_info_t ca_ioc_path; + uint32_t uniqueinstanceid; +} child_device_info_t; + +typedef struct _child_device_info_list{ + struct _child_device_info_list *next_device_info; + child_device_info_t io_device_info; +}child_device_info_list_t; + +typedef struct _ca_ioc_map { + cl_list_item_t ioc_list; + ioc_mgr_t *p_ioc_mgr; + net64_t ca_guid; + ib_ioc_info_t info; + ib_svc_entry_t svc_entry_array[1]; +} ca_ioc_map_t; +#pragma pack(pop) + +ib_api_status_t +_create_ioc_pdo( + IN child_device_info_t* p_child_dev, + IN ca_ioc_map_t* p_ca_ioc_map); + +ca_ioc_map_t *find_ca_ioc_map(net64_t ca_guid, + ib_net64_t ioc_guid); + + +void +ioc_mgr_construct( + IN OUT ioc_mgr_t* const p_ioc_mgr ); + +ib_api_status_t +ioc_mgr_init( + IN OUT ioc_mgr_t* const p_ioc_mgr ); + +NTSTATUS +ioc_mgr_get_iou_relations( + IN ioc_mgr_t* const p_ioc_mgr, + IN IRP* const p_irp ); + +#endif diff --git a/branches/WOF2-3/core/iou/kernel/iou_pnp.c b/branches/WOF2-3/core/iou/kernel/iou_pnp.c new file mode 100644 index 00000000..002412e2 --- /dev/null +++ b/branches/WOF2-3/core/iou/kernel/iou_pnp.c @@ -0,0 +1,637 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + +/* + * Implemenation of all PnP functionality for FDO (power policy owners). + */ + + +#include "iou_driver.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "iou_pnp.tmh" +#endif +#include "iou_pnp.h" +#include "iou_ioc_mgr.h" +#include +#include +#include +#include + + +static NTSTATUS +fdo_start( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static void +fdo_release_resources( + IN DEVICE_OBJECT* const p_dev_obj ); + +static NTSTATUS +fdo_query_remove( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +fdo_query_capabilities( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +fdo_query_iou_relations( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +fdo_query_interface( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +__fdo_query_power( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +__fdo_set_power( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + + + +/* Global virtual function pointer tables shared between all instances of FDO. */ +static const cl_vfptr_pnp_po_t vfptr_fdo_pnp = { + "IB IOU", + fdo_start, + cl_irp_skip, + cl_irp_skip, + cl_do_sync_pnp, + fdo_query_remove, + fdo_release_resources, + cl_do_remove, + cl_do_sync_pnp, + cl_irp_skip, + fdo_query_capabilities, + cl_irp_skip, + cl_irp_skip, + cl_do_sync_pnp, + fdo_query_iou_relations, + cl_irp_ignore, + cl_irp_ignore, + cl_irp_ignore, + cl_irp_ignore, + cl_irp_ignore, + cl_irp_ignore, + cl_irp_ignore, + cl_irp_ignore, /* QueryInterface */ + cl_irp_ignore, + cl_irp_ignore, + cl_irp_ignore, + cl_irp_ignore, + __fdo_query_power, /* QueryPower */ + __fdo_set_power, /* SetPower */ + cl_irp_ignore, /* PowerSequence */ + cl_irp_ignore /* WaitWake */ +}; +/* + * NOTE: The QueryInterface entry point is not used because we only enable/disable + * our interface so that user-mode AL can find a device to perform IOCTLs to. + */ + +NTSTATUS +iou_add_device( + IN DRIVER_OBJECT *p_driver_obj, + IN DEVICE_OBJECT *p_pdo ) +{ + NTSTATUS status; + DEVICE_OBJECT *p_dev_obj, *p_next_do; + iou_fdo_ext_t *p_ext; + + IOU_ENTER( IOU_DBG_PNP ); + + /* Create the FDO device object to attach to the stack. */ + status = IoCreateDevice( p_driver_obj, sizeof(iou_fdo_ext_t), + NULL, FILE_DEVICE_BUS_EXTENDER, + FILE_DEVICE_SECURE_OPEN, FALSE, &p_dev_obj ); + if( !NT_SUCCESS(status) ) + { + IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR, + ("Failed to create bus root FDO device.\n") ); + return status; + } + + p_ext = p_dev_obj->DeviceExtension; + + ioc_mgr_construct( &p_ext->ioc_mgr ); + + p_next_do = IoAttachDeviceToDeviceStack( p_dev_obj, p_pdo ); + if( !p_next_do ) + { + IoDeleteDevice( p_dev_obj ); + IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR, + ("IoAttachToDeviceStack failed.\n") ); + return STATUS_NO_SUCH_DEVICE; + } + + cl_init_pnp_po_ext( p_dev_obj, p_next_do, p_pdo, g_iou_dbg_flags, + &vfptr_fdo_pnp, NULL ); + + IOU_EXIT( IOU_DBG_PNP ); + return STATUS_SUCCESS; +} + + +static NTSTATUS +__get_iou_ifc( + IN iou_fdo_ext_t* const p_ext ) +{ + NTSTATUS status; + IO_STACK_LOCATION io_stack; + ib_al_ifc_data_t data; + + IOU_ENTER( IOU_DBG_PNP ); + + data.type = &GUID_IOU_INTERFACE_DATA; + data.version = IOU_INTERFACE_DATA_VERSION; + data.size = sizeof(iou_ifc_data_t); + data.p_data = &p_ext->ioc_mgr.info; + + io_stack.MinorFunction = IRP_MN_QUERY_INTERFACE; + io_stack.Parameters.QueryInterface.Version = AL_INTERFACE_VERSION; + io_stack.Parameters.QueryInterface.Size = sizeof(ib_al_ifc_t); + io_stack.Parameters.QueryInterface.Interface = + (INTERFACE*)&p_ext->ioc_mgr.ifc; + io_stack.Parameters.QueryInterface.InterfaceSpecificData = + &data; + io_stack.Parameters.QueryInterface.InterfaceType = &GUID_IB_AL_INTERFACE; + + status = cl_fwd_query_ifc( p_ext->cl_ext.p_next_do, &io_stack ); + + /* + * Dereference the interface now so that the bus driver doesn't fail a + * query remove IRP. We will always get unloaded before the bus driver + * since we're a child device. + */ + if( NT_SUCCESS( status ) ) + { + p_ext->ioc_mgr.ifc.wdm.InterfaceDereference( + p_ext->ioc_mgr.ifc.wdm.Context ); + } + + IOU_EXIT( IOU_DBG_PNP ); + return status; +} + + +static NTSTATUS +fdo_start( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + NTSTATUS status; + iou_fdo_ext_t *p_ext; + ib_api_status_t ib_status; + + IOU_ENTER( IOU_DBG_PNP ); + + p_ext = p_dev_obj->DeviceExtension; + + /* Handled on the way up. */ + status = cl_do_sync_pnp( p_dev_obj, p_irp, p_action ); + if( !NT_SUCCESS( status ) ) + { + IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR, + ("Lower drivers failed IRP_MN_START_DEVICE.\n") ); + return status; + } + + status = __get_iou_ifc( p_ext ); + if( !NT_SUCCESS( status ) ) + { + IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR, + ("Failed to get IOU interface.\n") ); + return status; + } + + /* Initialize the IOU manager. */ + ib_status = ioc_mgr_init( &p_ext->ioc_mgr ); + if( ib_status != IB_SUCCESS ) + { + IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR, + ("ioc_mgr_init returned %s.\n", + p_ext->ioc_mgr.ifc.get_err_str(ib_status)) ); + return STATUS_UNSUCCESSFUL; + } + + IOU_EXIT( IOU_DBG_PNP ); + return status; +} + + +static NTSTATUS +fdo_query_remove( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + iou_fdo_ext_t *p_ext; + + IOU_ENTER( IOU_DBG_PNP ); + + p_ext = p_dev_obj->DeviceExtension; + + *p_action = IrpSkip; + /* The FDO driver must set the status even when passing down. */ + p_irp->IoStatus.Status = STATUS_SUCCESS; + IOU_EXIT( IOU_DBG_PNP ); + return STATUS_SUCCESS; +} + +static void _destroy_ca_ioc_maps( + IN ioc_mgr_t *p_ioc_mgr) +{ + ca_ioc_map_t *p_map = NULL; + cl_list_item_t *list_item; + + cl_mutex_acquire( &iou_globals.list_mutex ); + + list_item = cl_qlist_head( &iou_globals.ca_ioc_map_list ); + + while( list_item != cl_qlist_end( &iou_globals.ca_ioc_map_list ) ) { + p_map = ( ca_ioc_map_t * ) list_item; + list_item = cl_qlist_next( list_item ); // Get the next element before freeing it + + if ( p_map->p_ioc_mgr == p_ioc_mgr ) { + cl_qlist_remove_item( &iou_globals.ca_ioc_map_list, ( cl_list_item_t * )p_map ); + cl_free( p_map ); + } + + } + + cl_mutex_release( &iou_globals.list_mutex ); +} + +/* + * This function gets called after releasing the remove lock and waiting + * for all other threads to release the lock. No more modifications will + * occur to the PDO pointer vectors. + */ +static void +fdo_release_resources( + IN DEVICE_OBJECT* const p_dev_obj ) +{ + iou_fdo_ext_t *p_ext; + + IOU_ENTER( IOU_DBG_PNP ); + + p_ext = p_dev_obj->DeviceExtension; + + _destroy_ca_ioc_maps(&p_ext->ioc_mgr); + + //TODO: Fail outstanding I/O operations. + cl_obj_destroy( &p_ext->ioc_mgr.obj ); + + IOU_EXIT( IOU_DBG_PNP ); +} + + +static NTSTATUS +fdo_query_capabilities( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + NTSTATUS status; + iou_fdo_ext_t *p_ext; + IO_STACK_LOCATION *p_io_stack; + + IOU_ENTER( IOU_DBG_PNP ); + + p_ext = p_dev_obj->DeviceExtension; + + /* Process on the way up. */ + status = cl_do_sync_pnp( p_dev_obj, p_irp, p_action ); + + if( !NT_SUCCESS( status ) ) + { + IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR, + ("cl_do_sync_pnp returned %08x.\n", status) ); + return status; + } + + p_io_stack = IoGetCurrentIrpStackLocation( p_irp ); + + /* + * Store the device power maping into our extension since we're + * the power policy owner. The mapping is used when handling + * IRP_MN_SET_POWER IRPs. + */ + cl_memcpy( p_ext->po_state, + p_io_stack->Parameters.DeviceCapabilities.Capabilities->DeviceState, + sizeof( p_ext->po_state ) ); + + IOU_EXIT( IOU_DBG_PNP ); + return status; +} + + +static NTSTATUS +fdo_query_iou_relations( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + iou_fdo_ext_t *p_ext; + NTSTATUS status; + + IOU_ENTER( IOU_DBG_PNP ); + + p_ext = p_dev_obj->DeviceExtension; + + status = ioc_mgr_get_iou_relations( &p_ext->ioc_mgr, p_irp ); + switch( status ) + { + case STATUS_NO_SUCH_DEVICE: + *p_action = IrpSkip; + status = STATUS_SUCCESS; + break; + + case STATUS_SUCCESS: + *p_action = IrpPassDown; + break; + + default: + *p_action = IrpComplete; + break; + } + + IOU_EXIT( IOU_DBG_PNP ); + return status; +} + + +static NTSTATUS +__fdo_query_power( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + NTSTATUS status = STATUS_SUCCESS; + IO_STACK_LOCATION *p_io_stack; + + IOU_ENTER( IOU_DBG_POWER ); + + UNUSED_PARAM( p_dev_obj ); + + p_io_stack = IoGetCurrentIrpStackLocation( p_irp ); + + switch( p_io_stack->Parameters.Power.Type ) + { + case SystemPowerState: + /* Fail any requests to hibernate or sleep the system. */ + switch( p_io_stack->Parameters.Power.State.SystemState ) + { + case PowerSystemWorking: + case PowerSystemShutdown: + /* We only support fully working and shutdown system states. */ + break; + + default: + status = STATUS_NOT_SUPPORTED; + } + break; + + case DevicePowerState: + /* Fail any query for low power states. */ + switch( p_io_stack->Parameters.Power.State.DeviceState ) + { + case PowerDeviceD0: + case PowerDeviceD3: + /* We only support fully powered or off power states. */ + break; + + default: + status = STATUS_NOT_SUPPORTED; + } + break; + } + + if( status == STATUS_NOT_SUPPORTED ) + *p_action = IrpComplete; + else + *p_action = IrpSkip; + + IOU_EXIT( IOU_DBG_POWER ); + return status; +} + + +static void +__request_power_completion( + IN DEVICE_OBJECT *p_dev_obj, + IN UCHAR minor_function, + IN POWER_STATE power_state, + IN void *context, + IN IO_STATUS_BLOCK *p_io_status ) +{ + IRP *p_irp; + cl_pnp_po_ext_t *p_ext; + + IOU_ENTER( IOU_DBG_PNP ); + + UNUSED_PARAM( minor_function ); + UNUSED_PARAM( power_state ); + + p_irp = (IRP*)context; + p_ext = p_dev_obj->DeviceExtension; + + /* Propagate the device IRP status to the system IRP status. */ + p_irp->IoStatus.Status = p_io_status->Status; + + /* Continue Power IRP processing. */ + PoStartNextPowerIrp( p_irp ); + IoCompleteRequest( p_irp, IO_NO_INCREMENT ); + IoReleaseRemoveLock( &p_ext->remove_lock, p_irp ); + IOU_EXIT( IOU_DBG_PNP ); +} + + +/*NOTE: Completion routines must NEVER be pageable. */ +static NTSTATUS +__set_power_completion( + IN DEVICE_OBJECT *p_dev_obj, + IN IRP *p_irp, + IN void *context ) +{ + NTSTATUS status; + POWER_STATE state; + iou_fdo_ext_t *p_ext; + IO_STACK_LOCATION *p_io_stack; + + IOU_ENTER( IOU_DBG_PNP ); + + UNUSED_PARAM( context ); + + p_ext = p_dev_obj->DeviceExtension; + p_io_stack = IoGetCurrentIrpStackLocation( p_irp ); + + if( !NT_SUCCESS( p_irp->IoStatus.Status ) ) + { + PoStartNextPowerIrp( p_irp ); + IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp ); + IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR, + ("IRP_MN_SET_POWER for system failed by lower driver with %08x.\n", + p_irp->IoStatus.Status) ); + return STATUS_SUCCESS; + } + + state.DeviceState = + p_ext->po_state[p_io_stack->Parameters.Power.State.SystemState]; + + /* + * Send a device power IRP to our devnode. Using our device object will + * only work on win2k and other NT based systems. + */ + status = PoRequestPowerIrp( p_dev_obj, IRP_MN_SET_POWER, state, + __request_power_completion, p_irp, NULL ); + + if( !NT_SUCCESS( p_irp->IoStatus.Status ) ) + { + PoStartNextPowerIrp( p_irp ); + /* Propagate the failure. */ + p_irp->IoStatus.Status = status; + IoCompleteRequest( p_irp, IO_NO_INCREMENT ); + IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp ); + IOU_PRINT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR, + ("PoRequestPowerIrp returned %08x.\n", status) ); + } + + IOU_EXIT( IOU_DBG_PNP ); + return STATUS_MORE_PROCESSING_REQUIRED; +} + + +static NTSTATUS +__fdo_set_power( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + NTSTATUS status; + IO_STACK_LOCATION *p_io_stack; + iou_fdo_ext_t *p_ext; + + IOU_ENTER( IOU_DBG_POWER ); + + p_ext = p_dev_obj->DeviceExtension; + p_io_stack = IoGetCurrentIrpStackLocation( p_irp ); + + switch( p_io_stack->Parameters.Power.Type ) + { + case SystemPowerState: + /* + * Process on the way up the stack. We cannot block since the + * power dispatch function can be called at elevated IRQL if the + * device is in a paging/hibernation/crash dump path. + */ + IoMarkIrpPending( p_irp ); + IoCopyCurrentIrpStackLocationToNext( p_irp ); +#pragma warning( push, 3 ) + IoSetCompletionRoutine( p_irp, __set_power_completion, NULL, + TRUE, TRUE, TRUE ); +#pragma warning( pop ) + PoCallDriver( p_ext->cl_ext.p_next_do, p_irp ); + + *p_action = IrpDoNothing; + status = STATUS_PENDING; + break; + + case DevicePowerState: + default: + /* Pass down and let the PDO driver handle it. */ + *p_action = IrpIgnore; + status = STATUS_SUCCESS; + break; + } + + IOU_EXIT( IOU_DBG_POWER ); + return status; +} + + +void +update_relations( + IN cl_qlist_t* const p_pdo_list, + IN OUT DEVICE_RELATIONS* const p_rel ) +{ + cl_list_item_t *p_list_item; + iou_pdo_ext_t *p_pdo_ext; + + IOU_ENTER( IOU_DBG_PNP ); + + p_list_item = cl_qlist_head( p_pdo_list ); + while( p_list_item != cl_qlist_end( p_pdo_list ) ) + { + p_pdo_ext = PARENT_STRUCT( p_list_item, iou_pdo_ext_t, list_item ); + + /* Move the list item to the next object. */ + p_list_item = cl_qlist_next( p_list_item ); + + if( !p_pdo_ext->b_present ) + { + /* + * We don't report a PDO that is no longer present. This is how + * the PDO will get cleaned up. + */ + p_pdo_ext->b_reported_missing = TRUE; + continue; + } + p_rel->Objects[p_rel->Count] = p_pdo_ext->cl_ext.p_pdo; + ObReferenceObject( p_rel->Objects[p_rel->Count++] ); + } + + IOU_EXIT( IOU_DBG_PNP ); +} + + diff --git a/branches/WOF2-3/core/iou/kernel/iou_pnp.h b/branches/WOF2-3/core/iou/kernel/iou_pnp.h new file mode 100644 index 00000000..80a53a54 --- /dev/null +++ b/branches/WOF2-3/core/iou/kernel/iou_pnp.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + +#if !defined _IOU_DRV_PNP_H_ +#define _IOU_DRV_PNP_H_ + + +#include "iou_driver.h" + + +/****f* InfiniBand Bus Driver: Plug and Play/iou_add_device +* NAME +* iou_add_device +* +* DESCRIPTION +* Main AddDevice entrypoint for the IB Bus driver. +* Adds the bus root functional device object to the device node. The +* bus root FDO performs all PnP operations for fabric attached devices. +* +* SYNOPSIS +*/ +NTSTATUS +iou_add_device( + IN PDRIVER_OBJECT p_driver_obj, + IN PDEVICE_OBJECT p_pdo ); +/* +* PARAMETERS +* p_driver_obj +* Driver object for the IOU driver. +* +* p_pdo +* Pointer to the device object representing the PDO for the device on +* which we are loading. +* +* RETURN VIOUUES +* STATUS_SUCCESS if the device was successfully added. +* +* Other NTSTATUS error values if errors are encountered. +* +* SEE ALSO +*********/ + + +void +update_relations( + IN cl_qlist_t* const p_pdo_list, + IN OUT DEVICE_RELATIONS* const p_rel ); + + +#endif // !defined _IOU_DRV_PNP_H_ diff --git a/branches/WOF2-3/core/iou/kernel/makefile b/branches/WOF2-3/core/iou/kernel/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-3/core/iou/kernel/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\inc\openib.def diff --git a/branches/WOF2-3/core/iou/kernel/makefile.inc b/branches/WOF2-3/core/iou/kernel/makefile.inc new file mode 100644 index 00000000..4f29f500 --- /dev/null +++ b/branches/WOF2-3/core/iou/kernel/makefile.inc @@ -0,0 +1,17 @@ + +# Transform .inx file to .inf file adding date + major,min & svn.version stamp +# Output .inf file is copied to the $(INF_TARGET) folder (commonly where .sys file resides). + +_LNG=$(LANGUAGE) + +!IF !DEFINED(_INX) +_INX=. +!ENDIF + +STAMP=stampinf -a $(_BUILDARCH) + +!INCLUDE mod_ver.def + +$(INF_TARGET) : $(_INX)\$(INF_NAME).inx + copy $(_INX)\$(@B).inx $@ + $(STAMP) -f $@ -d * -v $(IB_MAJORVERSION).$(IB_MINORVERSION).$(IB_BUILDVERSION).$(OPENIB_REV) diff --git a/branches/WOF2-3/core/winmad/dirs b/branches/WOF2-3/core/winmad/dirs new file mode 100644 index 00000000..697ddcdb --- /dev/null +++ b/branches/WOF2-3/core/winmad/dirs @@ -0,0 +1,3 @@ +DIRS=\ + kernel \ + user \ No newline at end of file diff --git a/branches/WOF2-3/core/winmad/kernel/SOURCES b/branches/WOF2-3/core/winmad/kernel/SOURCES new file mode 100644 index 00000000..653e0fad --- /dev/null +++ b/branches/WOF2-3/core/winmad/kernel/SOURCES @@ -0,0 +1,22 @@ +TARGETNAME = winmad +TARGETPATH = ..\..\..\bin\kernel\obj$(BUILD_ALT_DIR) +TARGETTYPE = DRIVER + +KMDF_VERSION_MAJOR = 1 +INF_NAME = winmad +INF_TARGET=..\..\..\bin\kernel\$(O)\$(INF_NAME).inf +NTTARGETFILES = $(INF_TARGET) +MISCFILES = $(NTTARGETFILES) +TARGETLIBS = $(TARGETLIBS) \ + $(DDK_LIB_PATH)\wdmsec.lib \ + $(TARGETPATH)\*\complib.lib + +SOURCES = \ + winmad.rc \ + wm_driver.c \ + wm_provider.c \ + wm_reg.c + +INCLUDES = ..;..\..\..\inc;..\..\..\inc\kernel;..\..\..\inc\user;..\..\..\etc\kernel; + +C_DEFINES = $(C_DEFINES) -DIOCTL_INTERFACE=1 diff --git a/branches/WOF2-3/core/winmad/kernel/makefile b/branches/WOF2-3/core/winmad/kernel/makefile new file mode 100644 index 00000000..128ed372 --- /dev/null +++ b/branches/WOF2-3/core/winmad/kernel/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the Windows NT DDK +# + +!INCLUDE ..\..\..\inc\openib.def diff --git a/branches/WOF2-3/core/winmad/kernel/makefile.inc b/branches/WOF2-3/core/winmad/kernel/makefile.inc new file mode 100644 index 00000000..81c144d2 --- /dev/null +++ b/branches/WOF2-3/core/winmad/kernel/makefile.inc @@ -0,0 +1,13 @@ +_LNG=$(LANGUAGE) + +!IF !DEFINED(_INX) +_INX=. +!ENDIF + +STAMP=stampinf -f $@ -a $(_BUILDARCH) -k $(KMDF_VERSION_MAJOR).$(KMDF_VERSION_MINOR) + +!INCLUDE mod_ver.def + +$(INF_TARGET) : $(_INX)\$(INF_NAME).inx + copy $(_INX)\$(@B).inx $@ + $(STAMP) -f $@ -d * -v $(IB_MAJORVERSION).$(IB_MINORVERSION).$(IB_BUILDVERSION).$(OPENIB_REV) diff --git a/branches/WOF2-3/core/winmad/kernel/winmad.inx b/branches/WOF2-3/core/winmad/kernel/winmad.inx new file mode 100644 index 00000000..4b53398a --- /dev/null +++ b/branches/WOF2-3/core/winmad/kernel/winmad.inx @@ -0,0 +1,108 @@ +; +; Copyright (c) 2008 Intel Corporation. All rights reserved. +; +; This software is available to you under the OpenIB.org BSD license +; below: +; +; Redistribution and use in source and binary forms, with or +; without modification, are permitted provided that the following +; conditions are met: +; +; - Redistributions of source code must retain the above +; copyright notice, this list of conditions and the following +; disclaimer. +; +; - Redistributions in binary form must reproduce the above +; copyright notice, this list of conditions and the following +; disclaimer in the documentation and/or other materials +; provided with the distribution. +; +; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV +; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +; BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +; ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +; CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +; SOFTWARE. +; + +[Version] +Signature = "$WINDOWS NT$" +Class = InfiniBandController +ClassGUID = {58517E00-D3CF-40c9-A679-CEE5752F4491} +Provider = %OFA% +DriverVer = 05/20/2008 +CatalogFile = winmad.cat + +[SourceDisksNames] +1 = %DiskId% + +[SourceDisksFiles] +winmad.sys = 1 +winmad.dll = 1 +winmadd.dll = 1 + +[DefaultInstall] +AddReg = WmClassAddReg +CopyFiles = WmClassCopySysFiles, WmClassCopyDllFiles + +[WmClassAddReg] +HKLM, System\CurrentControlSet\Control\Class\{58517E00-D3CF-40c9-A679-CEE5752F4491}, UpperFilters, 0x00010008, winmad + +[DestinationDirs] +WmClassCopySysFiles = 12 +WmClassCopyDllFiles = 11 + +[WmClassCopySysFiles] +winmad.sys + +[WmClassCopyDllFiles] +winmad.dll +winmadd.dll + +[Manufacturer] +%OFA% = WmModel, NT$ARCH$ + +[WmModel] +%winmad.DeviceDesc% = WmDevice, root\winmad + +[DefaultInstall.Services] +AddService = winmad,, WmClassService + +[WmClassService] +DisplayName = %winmad.ServiceDesc% +ServiceType = 1 +StartType = 3 +ErrorControl = 1 +ServiceBinary = %12%\winmad.sys +LoadOrderGroup = PNP Filter + +[WmDevice.CoInstallers] +AddReg = WmDeviceCoInstAddReg +CopyFiles = WmDeviceCoInstCopyFiles + +[DestinationDirs] +WmDeviceCoInstCopyFiles = 11 + +[WmDeviceCoInstAddReg] +HKR,,CoInstallers32,0x00010000, "WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll, WdfCoInstaller" + +[WmDeviceCoInstCopyFiles] +WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll + +[SourceDisksFiles] +WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll=1 + +[WmDevice.Wdf] +KmdfService = winmad, WmWdfSect + +[WmWdfSect] +KmdfLibraryVersion = $KMDFVERSION$ + +[Strings] +OFA = "OpenFabrics" +DiskId = "OpenFabrics WinMad Installation" +winmad.DeviceDesc = "WinMad Driver" +winmad.ServiceDesc = "WinMad Service" +ClassName = "WinMad Device" diff --git a/branches/WOF2-3/core/winmad/kernel/winmad.rc b/branches/WOF2-3/core/winmad/kernel/winmad.rc new file mode 100644 index 00000000..3669ed26 --- /dev/null +++ b/branches/WOF2-3/core/winmad/kernel/winmad.rc @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_DRV_SYSTEM + +#ifdef _DEBUG_ +#define VER_FILEDESCRIPTION_STR "Kernel WinMad (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "Kernel WinMad" +#endif + +#define VER_INTERNALNAME_STR "winmad.sys" +#define VER_ORIGINALFILENAME_STR "winmad.sys" + +#include diff --git a/branches/WOF2-3/core/winmad/kernel/wm_driver.c b/branches/WOF2-3/core/winmad/kernel/wm_driver.c new file mode 100644 index 00000000..6d3cbdff --- /dev/null +++ b/branches/WOF2-3/core/winmad/kernel/wm_driver.c @@ -0,0 +1,415 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#include "wm_ioctl.h" +#include "wm_driver.h" +#include "wm_provider.h" +#include "wm_reg.h" + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(WM_IB_DEVICE, WmIbDeviceGetContext) +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(WM_PROVIDER, WmProviderGetContext) + +WDFDEVICE ControlDevice; +static LIST_ENTRY DevList; +static LIST_ENTRY ProvList; +static KGUARDED_MUTEX Lock; + +static EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL WmIoDeviceControl; +static EVT_WDF_IO_QUEUE_IO_READ WmIoRead; +static EVT_WDF_IO_QUEUE_IO_WRITE WmIoWrite; +static EVT_WDF_DEVICE_FILE_CREATE WmFileCreate; +static EVT_WDF_FILE_CLEANUP WmFileCleanup; +static EVT_WDF_FILE_CLOSE WmFileClose; + +static WM_IB_DEVICE *WmIbDeviceFind(NET64 Guid) +{ + WM_IB_DEVICE *cur_dev, *dev = NULL; + LIST_ENTRY *entry; + + for (entry = DevList.Flink; entry != &DevList; entry = entry->Flink) { + cur_dev = CONTAINING_RECORD(entry, WM_IB_DEVICE, Entry); + if (cur_dev->Guid == Guid) { + dev = cur_dev; + break; + } + } + return dev; +} + +WM_IB_DEVICE *WmIbDeviceGet(NET64 Guid) +{ + WM_IB_DEVICE *dev; + + KeAcquireGuardedMutex(&Lock); + dev = WmIbDeviceFind(Guid); + if (dev != NULL) { + InterlockedIncrement(&dev->Ref); + } + KeReleaseGuardedMutex(&Lock); + return dev; +} + +void WmIbDevicePut(WM_IB_DEVICE *pDevice) +{ + if (InterlockedDecrement(&pDevice->Ref) == 0) { + KeSetEvent(&pDevice->Event, 0, FALSE); + } +} + +static VOID WmIoDeviceControl(WDFQUEUE Queue, WDFREQUEST Request, + size_t OutLen, size_t InLen, ULONG IoControlCode) +{ + WDFFILEOBJECT file; + WM_PROVIDER *prov; + UNREFERENCED_PARAMETER(OutLen); + UNREFERENCED_PARAMETER(InLen); + UNREFERENCED_PARAMETER(Queue); + + file = WdfRequestGetFileObject(Request); + prov = WmProviderGetContext(file); + + switch (IoControlCode) { + case WM_IOCTL_REGISTER: + WmRegister(prov, Request); + break; + case WM_IOCTL_DEREGISTER: + WmDeregister(prov, Request); + break; + case WM_IOCTL_CANCEL: + WmProviderCancel(prov, Request); + break; + default: + WdfRequestComplete(Request, STATUS_PROCEDURE_NOT_FOUND); + break; + } +} + +static VOID WmIoRead(WDFQUEUE Queue, WDFREQUEST Request, size_t Length) +{ + WDFFILEOBJECT file; + WM_PROVIDER *prov; + UNREFERENCED_PARAMETER(Queue); + + file = WdfRequestGetFileObject(Request); + prov = WmProviderGetContext(file); + WmProviderRead(prov, Request); +} + +static VOID WmIoWrite(WDFQUEUE Queue, WDFREQUEST Request, size_t Length) +{ + WDFFILEOBJECT file; + WM_PROVIDER *prov; + UNREFERENCED_PARAMETER(Queue); + + file = WdfRequestGetFileObject(Request); + prov = WmProviderGetContext(file); + WmProviderWrite(prov, Request); +} + +static VOID WmFileCreate(WDFDEVICE Device, WDFREQUEST Request, + WDFFILEOBJECT FileObject) +{ + WM_PROVIDER *prov = WmProviderGetContext(FileObject); + UNREFERENCED_PARAMETER(Device); + + WmProviderInit(prov); + KeAcquireGuardedMutex(&Lock); + InsertHeadList(&ProvList, &prov->Entry); + KeReleaseGuardedMutex(&Lock); + WdfRequestComplete(Request, STATUS_SUCCESS); +} + +static VOID WmFileCleanup(WDFFILEOBJECT FileObject) +{ + WM_PROVIDER *prov = WmProviderGetContext(FileObject); + + KeAcquireGuardedMutex(&Lock); + RemoveEntryList(&prov->Entry); + KeReleaseGuardedMutex(&Lock); + WmProviderCleanup(prov); +} + +static VOID WmFileClose(WDFFILEOBJECT FileObject) +{ + UNREFERENCED_PARAMETER(FileObject); +} + +static VOID WmCreateControlDevice(WDFDRIVER Driver) +{ + PWDFDEVICE_INIT pinit; + WDF_FILEOBJECT_CONFIG fileconfig; + WDF_OBJECT_ATTRIBUTES attr; + WDF_IO_QUEUE_CONFIG ioconfig; + NTSTATUS status; + WDFQUEUE queue; + DECLARE_CONST_UNICODE_STRING(name, L"\\Device\\WinMad"); + DECLARE_CONST_UNICODE_STRING(symlink, L"\\DosDevices\\WinMad"); + + pinit = WdfControlDeviceInitAllocate(Driver, + &SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_RW_RES_R); + if (pinit == NULL) { + return; + } + + WdfDeviceInitSetExclusive(pinit, FALSE); + status = WdfDeviceInitAssignName(pinit, &name); + if (!NT_SUCCESS(status)) { + goto err1; + } + + WDF_FILEOBJECT_CONFIG_INIT(&fileconfig, WmFileCreate, WmFileClose, + WmFileCleanup); + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attr, WM_PROVIDER); + WdfDeviceInitSetFileObjectConfig(pinit, &fileconfig, &attr); + + WDF_OBJECT_ATTRIBUTES_INIT(&attr); + status = WdfDeviceCreate(&pinit, &attr, &ControlDevice); + if (!NT_SUCCESS(status)) { + goto err1; + } + + status = WdfDeviceCreateSymbolicLink(ControlDevice, &symlink); + if (!NT_SUCCESS(status)) { + goto err2; + } + + WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&ioconfig, WdfIoQueueDispatchParallel); + ioconfig.EvtIoDeviceControl = WmIoDeviceControl; + ioconfig.EvtIoRead = WmIoRead; + ioconfig.EvtIoWrite = WmIoWrite; + status = WdfIoQueueCreate(ControlDevice, &ioconfig, + WDF_NO_OBJECT_ATTRIBUTES, &queue); + if (!NT_SUCCESS(status)) { + goto err2; + } + + WdfControlFinishInitializing(ControlDevice); + return; + +err2: + WdfObjectDelete(ControlDevice); + return; +err1: + WdfDeviceInitFree(pinit); +} + +static ib_ca_attr_t *WmQueryCaAttributes(WM_IB_DEVICE *pDevice) +{ + ib_ca_attr_t *attr; + UINT32 size; + ib_api_status_t ib_status; + + size = 0; + ib_status = pDevice->VerbsInterface.Verbs. + query_ca(pDevice->VerbsInterface.Verbs.p_hca_obj, NULL, &size, NULL); + if (ib_status != IB_INSUFFICIENT_MEMORY) { + attr = NULL; + goto out; + } + + attr = ExAllocatePoolWithTag(PagedPool, size, 'acmw'); + if (attr == NULL) { + goto out; + } + + ib_status = pDevice->VerbsInterface.Verbs. + query_ca(pDevice->VerbsInterface.Verbs.p_hca_obj, attr, &size, NULL); + if (ib_status != IB_SUCCESS) { + ExFreePoolWithTag(attr, 'acmw'); + attr = NULL; + } + +out: + return attr; +} + +static NTSTATUS WmAddCa(WM_IB_DEVICE *pDevice) +{ + NTSTATUS status; + ib_api_status_t ib_status; + ib_ca_attr_t *attr; + UINT32 size; + UINT8 i; + + attr = WmQueryCaAttributes(pDevice); + if (attr == NULL) { + return STATUS_NO_MEMORY; + } + + size = sizeof(WM_IB_PORT) * attr->num_ports; + pDevice->pPortArray = ExAllocatePoolWithTag(PagedPool, size, 'pimw'); + if (pDevice->pPortArray == NULL) { + status = STATUS_NO_MEMORY; + goto out; + } + + for (i = 0; i < attr->num_ports; i++) { + pDevice->pPortArray[i].Guid = attr->p_port_attr[i].port_guid; + } + pDevice->PortCount = attr->num_ports; + + status = STATUS_SUCCESS; +out: + ExFreePoolWithTag(attr, 'acmw'); + return status; +} + +static NTSTATUS WmPowerD0Entry(WDFDEVICE Device, WDF_POWER_DEVICE_STATE PreviousState) +{ + WM_IB_DEVICE *dev; + BOOLEAN create; + NTSTATUS status; + + dev = WmIbDeviceGetContext(Device); + RtlZeroMemory(dev, sizeof *dev); + dev->Ref = 1; + KeInitializeEvent(&dev->Event, NotificationEvent, FALSE); + + status = WdfFdoQueryForInterface(Device, &GUID_RDMA_INTERFACE_VERBS, + (PINTERFACE) &dev->VerbsInterface, + sizeof(dev->VerbsInterface), VerbsVersion(2, 0), + NULL); + if (!NT_SUCCESS(status)) { + return status; + } + + dev->Guid = dev->VerbsInterface.Verbs.guid; + status = WmAddCa(dev); + + dev->VerbsInterface.InterfaceHeader.InterfaceDereference(dev->VerbsInterface. + InterfaceHeader.Context); + if (!NT_SUCCESS(status)) { + return status; + } + + status = WdfFdoQueryForInterface(Device, &GUID_IB_AL_INTERFACE, + (PINTERFACE) &dev->IbInterface, + sizeof(dev->IbInterface), + AL_INTERFACE_VERSION, NULL); + if (!NT_SUCCESS(status)) { + return status; + } + + KeAcquireGuardedMutex(&Lock); + create = IsListEmpty(&DevList); + InsertHeadList(&DevList, &dev->Entry); + KeReleaseGuardedMutex(&Lock); + + if (create) { + WmCreateControlDevice(WdfGetDriver()); + } + return STATUS_SUCCESS; +} + +static NTSTATUS WmPowerD0Exit(WDFDEVICE Device, WDF_POWER_DEVICE_STATE TargetState) +{ + WM_PROVIDER *prov; + WM_IB_DEVICE *pdev; + WM_REGISTRATION *reg; + LIST_ENTRY *entry; + BOOLEAN destroy; + WDFDEVICE ctrldev; + + pdev = WmIbDeviceGetContext(Device); + + KeAcquireGuardedMutex(&Lock); + RemoveEntryList(&pdev->Entry); + destroy = IsListEmpty(&DevList); + ctrldev = ControlDevice; + + for (entry = ProvList.Flink; entry != &ProvList; entry = entry->Flink) { + prov = CONTAINING_RECORD(entry, WM_PROVIDER, Entry); + WmProviderRemoveHandler(prov, pdev); + } + KeReleaseGuardedMutex(&Lock); + + if (InterlockedDecrement(&pdev->Ref) > 0) { + KeWaitForSingleObject(&pdev->Event, Executive, KernelMode, FALSE, NULL); + } + + pdev->IbInterface.wdm.InterfaceDereference(pdev->IbInterface.wdm.Context); + if (pdev->pPortArray != NULL) { + ExFreePoolWithTag(pdev->pPortArray, 'pimw'); + } + + if (destroy) { + WdfObjectDelete(ctrldev); + } + + return STATUS_SUCCESS; +} + +static NTSTATUS WmIbDeviceAdd(WDFDRIVER Driver, PWDFDEVICE_INIT DeviceInit) +{ + WDF_OBJECT_ATTRIBUTES attr; + WDF_PNPPOWER_EVENT_CALLBACKS power; + WDFDEVICE dev; + NTSTATUS status; + + WdfFdoInitSetFilter(DeviceInit); + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attr, WM_IB_DEVICE); + WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&power); + power.EvtDeviceD0Entry = WmPowerD0Entry; + power.EvtDeviceD0Exit = WmPowerD0Exit; + WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &power); + + status = WdfDeviceCreate(&DeviceInit, &attr, &dev); + if (!NT_SUCCESS(status)) { + return status; + } + + return STATUS_SUCCESS; +} + +NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) +{ + WDF_DRIVER_CONFIG config; + NTSTATUS status; + WDFDRIVER driv; + + InitializeListHead(&DevList); + InitializeListHead(&ProvList); + KeInitializeGuardedMutex(&Lock); + + WDF_DRIVER_CONFIG_INIT(&config, WmIbDeviceAdd); + status = WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES, + &config, &driv); + if (!NT_SUCCESS(status)) { + return status; + } + + return STATUS_SUCCESS; +} diff --git a/branches/WOF2-3/core/winmad/kernel/wm_driver.h b/branches/WOF2-3/core/winmad/kernel/wm_driver.h new file mode 100644 index 00000000..423b1bf8 --- /dev/null +++ b/branches/WOF2-3/core/winmad/kernel/wm_driver.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#ifndef _WM_DRIVER_H_ +#define _WM_DRIVER_H_ + +#include +#include +#include + +#include +#include +#include "wm_ioctl.h" + +#if WINVER <= _WIN32_WINNT_WINXP +#define KGUARDED_MUTEX FAST_MUTEX +#define KeInitializeGuardedMutex ExInitializeFastMutex +#define KeAcquireGuardedMutex ExAcquireFastMutex +#define KeReleaseGuardedMutex ExReleaseFastMutex +#endif + +extern WDFDEVICE ControlDevice; + +typedef struct _WM_IB_PORT +{ + NET64 Guid; + +} WM_IB_PORT; + +typedef struct _WM_IB_DEVICE +{ + LIST_ENTRY Entry; + LONG Ref; + KEVENT Event; + NET64 Guid; + union + { + RDMA_INTERFACE_VERBS VerbsInterface; + ib_al_ifc_t IbInterface; + }; + ib_al_handle_t hIbal; + ib_pnp_handle_t hPnp; + //ib_ca_handle_t hDevice; + //ib_pd_handle_t hPd; + int PortCount; + WM_IB_PORT *pPortArray; + +} WM_IB_DEVICE; + +WM_IB_DEVICE *WmIbDeviceGet(NET64 Guid); +void WmIbDevicePut(WM_IB_DEVICE *pDevice); + +#endif // _WM_DRIVER_H_ diff --git a/branches/WOF2-3/core/winmad/kernel/wm_provider.c b/branches/WOF2-3/core/winmad/kernel/wm_provider.c new file mode 100644 index 00000000..f3926f9e --- /dev/null +++ b/branches/WOF2-3/core/winmad/kernel/wm_provider.c @@ -0,0 +1,434 @@ +/* + * Copyright (c) 2008-2010 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "index_list.c" +#include "wm_driver.h" +#include "wm_ioctl.h" +#include "wm_provider.h" +#include "wm_reg.h" + +void WmProviderGet(WM_PROVIDER *pProvider) +{ + InterlockedIncrement(&pProvider->Ref); +} + +void WmProviderPut(WM_PROVIDER *pProvider) +{ + if (InterlockedDecrement(&pProvider->Ref) == 0) { + KeSetEvent(&pProvider->Event, 0, FALSE); + } +} + +NTSTATUS WmProviderInit(WM_PROVIDER *pProvider) +{ + WDF_IO_QUEUE_CONFIG config; + NTSTATUS status; + + IndexListInit(&pProvider->RegIndex); + pProvider->MadHead = NULL; + pProvider->MadTail = NULL; + + KeInitializeGuardedMutex(&pProvider->Lock); + pProvider->Ref = 1; + KeInitializeEvent(&pProvider->Event, NotificationEvent, FALSE); + + pProvider->Pending = 0; + pProvider->Active = 0; + KeInitializeEvent(&pProvider->SharedEvent, NotificationEvent, FALSE); + pProvider->Exclusive = 0; + KeInitializeEvent(&pProvider->ExclusiveEvent, SynchronizationEvent, FALSE); + + WDF_IO_QUEUE_CONFIG_INIT(&config, WdfIoQueueDispatchManual); + status = WdfIoQueueCreate(ControlDevice, &config, + WDF_NO_OBJECT_ATTRIBUTES, &pProvider->ReadQueue); + return status; +} + +static void WmInsertMad(WM_PROVIDER *pProvider, ib_mad_element_t *pMad) +{ + if (pProvider->MadHead == NULL) { + pProvider->MadHead = pMad; + } else { + pProvider->MadTail->p_next = pMad; + } + pProvider->MadTail = pMad; +} + +static ib_mad_element_t *WmRemoveMad(WM_PROVIDER *pProvider) +{ + ib_mad_element_t *mad; + + mad = pProvider->MadHead; + if (mad != NULL) { + pProvider->MadHead = (ib_mad_element_t *) mad->p_next; + mad->p_next = NULL; + } + return mad; +} + +void WmProviderDeregister(WM_PROVIDER *pProvider, WM_REGISTRATION *pRegistration) +{ + ib_mad_element_t *mad, *next, *list; + + WdfObjectAcquireLock(pProvider->ReadQueue); + pRegistration->hService = NULL; + + list = pProvider->MadHead; + pProvider->MadHead = NULL; + + for (mad = list; mad != NULL; mad = next) { + next = mad->p_next; + mad->p_next = NULL; + + if (mad->context1 == pRegistration) { + pRegistration->pDevice->IbInterface.put_mad(mad); + } else { + WmInsertMad(pProvider, mad); + } + } + WdfObjectReleaseLock(pProvider->ReadQueue); +} + +void WmProviderCleanup(WM_PROVIDER *pProvider) +{ + WM_REGISTRATION *reg; + + while ((reg = IndexListRemoveHead(&pProvider->RegIndex)) != NULL) { + WmRegFree(reg); + } + + if (InterlockedDecrement(&pProvider->Ref) > 0) { + KeWaitForSingleObject(&pProvider->Event, Executive, KernelMode, FALSE, NULL); + } + + WdfIoQueuePurgeSynchronously(pProvider->ReadQueue); + WdfObjectDelete(pProvider->ReadQueue); + + IndexListDestroy(&pProvider->RegIndex); +} + +// See comment above WmProviderRemoveHandler. +static void WmProviderLockRemove(WM_PROVIDER *pProvider) +{ + KeAcquireGuardedMutex(&pProvider->Lock); + pProvider->Exclusive++; + KeClearEvent(&pProvider->SharedEvent); + while (pProvider->Active > 0) { + KeReleaseGuardedMutex(&pProvider->Lock); + KeWaitForSingleObject(&pProvider->ExclusiveEvent, Executive, KernelMode, + FALSE, NULL); + KeAcquireGuardedMutex(&pProvider->Lock); + } + pProvider->Active++; + KeReleaseGuardedMutex(&pProvider->Lock); +} + +// See comment above WmProviderRemoveHandler. +static void WmProviderUnlockRemove(WM_PROVIDER *pProvider) +{ + KeAcquireGuardedMutex(&pProvider->Lock); + pProvider->Exclusive--; + pProvider->Active--; + if (pProvider->Exclusive > 0) { + KeSetEvent(&pProvider->ExclusiveEvent, 0, FALSE); + } else if (pProvider->Pending > 0) { + KeSetEvent(&pProvider->SharedEvent, 0, FALSE); + } + KeReleaseGuardedMutex(&pProvider->Lock); +} + +/* + * Must hold pProvider->Lock. Function may release and re-acquire. + * See comment above WmProviderRemoveHandler. + */ +void WmProviderDisableRemove(WM_PROVIDER *pProvider) +{ + while (pProvider->Exclusive > 0) { + pProvider->Pending++; + KeReleaseGuardedMutex(&pProvider->Lock); + KeWaitForSingleObject(&pProvider->SharedEvent, Executive, KernelMode, + FALSE, NULL); + KeAcquireGuardedMutex(&pProvider->Lock); + pProvider->Pending--; + } + InterlockedIncrement(&pProvider->Active); +} + +/* + * No need to hold pProvider->Lock when releasing. + * See comment above WmProviderRemoveHandler. + */ +void WmProviderEnableRemove(WM_PROVIDER *pProvider) +{ + InterlockedDecrement(&pProvider->Active); + if (pProvider->Exclusive > 0) { + KeSetEvent(&pProvider->ExclusiveEvent, 0, FALSE); + } +} + +/* + * The remove handler blocks all other threads executing through this + * provider until the remove has been processed. Because device removal is + * rare, we want a simple, optimized code path for all calls that access + * the underlying hardware device, making use of any locks that we would + * have to acquire anyway. The locking for exclusive access can be + * as ugly and slow as needed. + */ +void WmProviderRemoveHandler(WM_PROVIDER *pProvider, WM_IB_DEVICE *pDevice) +{ + WM_REGISTRATION *reg; + SIZE_T i; + + WmProviderLockRemove(pProvider); + IndexListForEach(&pProvider->RegIndex, i) { + reg = IndexListAt(&pProvider->RegIndex, i); + if (reg->pDevice == pDevice) { + WmRegRemoveHandler(reg); + } + } + WmProviderUnlockRemove(pProvider); +} + +static NTSTATUS WmCopyMad(WM_IO_MAD *pIoMad, ib_mad_element_t *pMad, size_t *pLen) +{ + pIoMad->Id = ((WM_REGISTRATION *) pMad->context1)->Id; + pIoMad->Status = pMad->status; + pIoMad->Timeout = pMad->timeout_ms; + pIoMad->Retries = pMad->retry_cnt; + pIoMad->Length = pMad->size; + + pIoMad->Address.Qpn = pMad->remote_qp; + pIoMad->Address.Qkey = pMad->remote_qkey; + pIoMad->Address.PkeyIndex = pMad->pkey_index; + + if ((pIoMad->Address.GrhValid = (UINT8) pMad->grh_valid)) { + pIoMad->Address.VersionClassFlow = pMad->p_grh->ver_class_flow; + pIoMad->Address.HopLimit = pMad->p_grh->hop_limit; + pIoMad->Address.GidIndex = 0; // TODO: update IBAL to use SGID index + RtlCopyMemory(pIoMad->Address.Gid, pMad->p_grh->dest_gid.raw, 16); + } + + pIoMad->Address.Lid = pMad->remote_lid; + pIoMad->Address.ServiceLevel = pMad->remote_sl; + pIoMad->Address.PathBits = pMad->path_bits; + pIoMad->Address.StaticRate = 0; + pIoMad->Address.Reserved = 0; + + if (*pLen >= sizeof(WM_IO_MAD) + pMad->size) { + RtlCopyMemory(pIoMad + 1, pMad->p_mad_buf, pMad->size); + *pLen = sizeof(WM_IO_MAD) + pMad->size; + return STATUS_SUCCESS; + } else { + *pLen = sizeof(WM_IO_MAD); + return STATUS_MORE_ENTRIES; + } +} + +void WmProviderRead(WM_PROVIDER *pProvider, WDFREQUEST Request) +{ + WM_REGISTRATION *reg; + NTSTATUS status; + WM_IO_MAD *wmad; + size_t outlen, len = 0; + + status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WM_IO_MAD), &wmad, &outlen); + if (!NT_SUCCESS(status)) { + goto out; + } + + WdfObjectAcquireLock(pProvider->ReadQueue); + if (pProvider->MadHead == NULL) { + status = WdfRequestForwardToIoQueue(Request, pProvider->ReadQueue); + WdfObjectReleaseLock(pProvider->ReadQueue); + if (NT_SUCCESS(status)) { + return; + } + goto out; + } + + len = outlen; + status = WmCopyMad(wmad, pProvider->MadHead, &len); + if (status == STATUS_SUCCESS) { + reg = (WM_REGISTRATION *) pProvider->MadHead->context1; + reg->pDevice->IbInterface.put_mad(WmRemoveMad(pProvider)); + } + WdfObjectReleaseLock(pProvider->ReadQueue); + +out: + WdfRequestCompleteWithInformation(Request, status, len); +} + +static NTSTATUS WmSendMad(WM_REGISTRATION *pRegistration, WM_IO_MAD *pIoMad, UINT32 size) +{ + ib_al_ifc_t *pifc; + NTSTATUS status; + ib_mad_element_t *mad; + ib_api_status_t ib_status; + + pifc = &pRegistration->pDevice->IbInterface; + ib_status = pifc->get_mad(pRegistration->hMadPool, size, &mad); + if (ib_status != IB_SUCCESS) { + return STATUS_NO_MEMORY; + } + + RtlCopyMemory(mad->p_mad_buf, pIoMad + 1, size); + mad->remote_qp = pIoMad->Address.Qpn; + mad->remote_qkey = pIoMad->Address.Qkey; + mad->resp_expected = (pIoMad->Timeout > 0); + mad->timeout_ms = pIoMad->Timeout; + mad->retry_cnt = pIoMad->Retries; + + if ((mad->grh_valid = pIoMad->Address.GrhValid)) { + mad->p_grh->ver_class_flow = pIoMad->Address.VersionClassFlow; + mad->p_grh->hop_limit = pIoMad->Address.HopLimit; + // TODO: update IBAL to use SGID index + // mad->p_grh->src_gid_index = pIoMad->Address.GidIndex; + RtlCopyMemory(mad->p_grh->dest_gid.raw, pIoMad->Address.Gid, 16); + } + + mad->remote_lid = pIoMad->Address.Lid; + mad->remote_sl = pIoMad->Address.ServiceLevel; + mad->pkey_index = pIoMad->Address.PkeyIndex; + mad->path_bits = pIoMad->Address.PathBits; + if (!ib_mad_is_response(mad->p_mad_buf)) { + mad->p_mad_buf->trans_id &= 0xFFFFFFFF00000000; + } + + ib_status = pifc->send_mad(pRegistration->hService, mad, NULL); + if (ib_status != IB_SUCCESS) { + status = STATUS_UNSUCCESSFUL; + goto err; + } + + return STATUS_SUCCESS; + +err: + pRegistration->pDevice->IbInterface.put_mad(mad); + return status; +} + +void WmProviderWrite(WM_PROVIDER *pProvider, WDFREQUEST Request) +{ + WM_REGISTRATION *reg; + NTSTATUS status; + WM_IO_MAD *wmad; + size_t inlen; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(WM_IO_MAD) + 24, + &wmad, &inlen); + if (!NT_SUCCESS(status)) { + goto out; + } + + reg = WmRegAcquire(pProvider, wmad->Id); + if (reg == NULL) { + status = STATUS_NOT_FOUND; + goto out; + } + + status = WmSendMad(reg, wmad, (UINT32) (inlen - sizeof(WM_IO_MAD))); + WmRegRelease(reg); + +out: + WdfRequestComplete(Request, status); +} + +void WmReceiveHandler(ib_mad_svc_handle_t hService, void *Context, + ib_mad_element_t *pMad) +{ + WM_REGISTRATION *reg = Context; + WM_PROVIDER *prov; + WDFREQUEST request; + NTSTATUS status; + WM_IO_MAD *wmad; + size_t len = 0; + + UNREFERENCED_PARAMETER(hService); + prov = reg->pProvider; + pMad->context1 = reg; + + WdfObjectAcquireLock(prov->ReadQueue); + if (reg->hService == NULL) { + reg->pDevice->IbInterface.put_mad(pMad); + goto unlock; + } + + status = WdfIoQueueRetrieveNextRequest(prov->ReadQueue, &request); + if (!NT_SUCCESS(status)) { + WmInsertMad(prov, pMad); + goto unlock; + } + + status = WdfRequestRetrieveOutputBuffer(request, sizeof(WM_IO_MAD), &wmad, &len); + if (!NT_SUCCESS(status)) { + reg->pDevice->IbInterface.put_mad(pMad); + goto complete; + } + + status = WmCopyMad(wmad, pMad, &len); + if (status == STATUS_SUCCESS) { + reg->pDevice->IbInterface.put_mad(pMad); + } else { + WmInsertMad(prov, pMad); + } + +complete: + WdfRequestCompleteWithInformation(request, status, len); +unlock: + WdfObjectReleaseLock(prov->ReadQueue); +} + +void WmSendHandler(ib_mad_svc_handle_t hService, void *Context, + ib_mad_element_t *pMad) +{ + if (pMad->status == IB_WCS_SUCCESS) { + ((WM_REGISTRATION *) Context)->pDevice->IbInterface.put_mad(pMad); + } else { + pMad->status = WM_IO_TIMEOUT; + WmReceiveHandler(hService, Context, pMad); + } +} + +void WmProviderCancel(WM_PROVIDER *pProvider, WDFREQUEST Request) +{ + WDFREQUEST request; + NTSTATUS status, result; + + WdfObjectAcquireLock(pProvider->ReadQueue); + status = WdfIoQueueRetrieveNextRequest(pProvider->ReadQueue, &request); + result = status; + + while (NT_SUCCESS(status)) { + WdfRequestComplete(request, STATUS_CANCELLED); + status = WdfIoQueueRetrieveNextRequest(pProvider->ReadQueue, &request); + } + WdfObjectReleaseLock(pProvider->ReadQueue); + + WdfRequestComplete(Request, result); +} diff --git a/branches/WOF2-3/core/winmad/kernel/wm_provider.h b/branches/WOF2-3/core/winmad/kernel/wm_provider.h new file mode 100644 index 00000000..3088f3d2 --- /dev/null +++ b/branches/WOF2-3/core/winmad/kernel/wm_provider.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#ifndef _WM_PROVIDER_H_ +#define _WM_PROVIDER_H_ + +#include +#include +#include + +#include +#include "wm_driver.h" +#include "index_list.h" + +typedef struct _WM_PROVIDER +{ + LIST_ENTRY Entry; + INDEX_LIST RegIndex; + WDFQUEUE ReadQueue; + + ib_mad_element_t *MadHead; + ib_mad_element_t *MadTail; + + KGUARDED_MUTEX Lock; + LONG Ref; + KEVENT Event; + LONG Pending; + LONG Active; + KEVENT SharedEvent; + LONG Exclusive; + KEVENT ExclusiveEvent; + +} WM_PROVIDER; + +void WmProviderGet(WM_PROVIDER *pProvider); +void WmProviderPut(WM_PROVIDER *pProvider); +NTSTATUS WmProviderInit(WM_PROVIDER *pProvider); +void WmProviderCleanup(WM_PROVIDER *pProvider); + +void WmProviderRemoveHandler(WM_PROVIDER *pProvider, WM_IB_DEVICE *pDevice); +void WmProviderDisableRemove(WM_PROVIDER *pProvider); +void WmProviderEnableRemove(WM_PROVIDER *pProvider); + +void WmProviderRead(WM_PROVIDER *pProvider, WDFREQUEST Request); +void WmProviderWrite(WM_PROVIDER *pProvider, WDFREQUEST Request); +void WmReceiveHandler(ib_mad_svc_handle_t hService, void *Context, + ib_mad_element_t *pMad); +void WmSendHandler(ib_mad_svc_handle_t hService, void *Context, + ib_mad_element_t *pMad); +void WmProviderDeregister(WM_PROVIDER *pProvider, + struct _WM_REGISTRATION *pRegistration); +void WmProviderCancel(WM_PROVIDER *pProvider, WDFREQUEST Request); + +#endif // _WM_PROVIDER_H_ diff --git a/branches/WOF2-3/core/winmad/kernel/wm_reg.c b/branches/WOF2-3/core/winmad/kernel/wm_reg.c new file mode 100644 index 00000000..448387e1 --- /dev/null +++ b/branches/WOF2-3/core/winmad/kernel/wm_reg.c @@ -0,0 +1,311 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include "wm_driver.h" +#include "wm_reg.h" +#include "wm_ioctl.h" + +WM_REGISTRATION *WmRegAcquire(WM_PROVIDER *pProvider, UINT64 Id) +{ + WM_REGISTRATION *reg; + + KeAcquireGuardedMutex(&pProvider->Lock); + WmProviderDisableRemove(pProvider); + reg = IndexListAt(&pProvider->RegIndex, (SIZE_T) Id); + if (reg != NULL && reg->pDevice != NULL) { + InterlockedIncrement(®->Ref); + } else { + reg = NULL; + WmProviderEnableRemove(pProvider); + } + KeReleaseGuardedMutex(&pProvider->Lock); + return reg; +} + +void WmRegRelease(WM_REGISTRATION *pRegistration) +{ + WmProviderEnableRemove(pRegistration->pProvider); + InterlockedDecrement(&pRegistration->Ref); +} + +static WM_REGISTRATION *WmRegAlloc(WM_PROVIDER *pProvider) +{ + WM_REGISTRATION *reg; + + reg = ExAllocatePoolWithTag(NonPagedPool, sizeof(WM_REGISTRATION), 'grmw'); + if (reg == NULL) { + return NULL; + } + + RtlZeroMemory(reg, sizeof(WM_REGISTRATION)); + reg->Ref = 1; + + reg->pProvider = pProvider; + WmProviderGet(pProvider); + return reg; +} + +static int WmConvertMethods(ib_mad_svc_t *svc, WM_IO_REGISTER *pAttributes) +{ + int i, j, unsolicited = 0; + + for (i = 0; i < 16; i++) { + for (j = 0; j < 8; j++) { + if (((pAttributes->Methods[i] >> j) & 0x01) != 0) { + svc->method_array[i * 8 + j] = 1; + unsolicited = 1; + } + } + } + return unsolicited; +} + +static NTSTATUS WmRegInit(WM_REGISTRATION *pRegistration, WM_IO_REGISTER *pAttributes) +{ + WM_IB_DEVICE *dev; + ib_qp_create_t attr; + ib_mad_svc_t svc; + ib_port_attr_mod_t port_cap; + ib_api_status_t ib_status; + NTSTATUS status; + + RtlZeroMemory(&attr, sizeof attr); + if (pAttributes->Qpn == 0) { + attr.qp_type = IB_QPT_QP0_ALIAS; + } else if (pAttributes->Qpn == IB_QP1) { + attr.qp_type = IB_QPT_QP1_ALIAS; + } else { + return STATUS_BAD_NETWORK_PATH; + } + + dev = WmIbDeviceGet(pAttributes->Guid); + if (dev == NULL) { + return STATUS_NO_SUCH_DEVICE; + } + + pRegistration->PortNum = pAttributes->Port; + if (--pAttributes->Port > dev->PortCount) { + status = STATUS_INVALID_PORT_HANDLE; + goto err1; + } + + ib_status = dev->IbInterface.open_al(&pRegistration->hIbal); + if (ib_status != IB_SUCCESS) { + status = STATUS_UNSUCCESSFUL; + goto err1; + } + + ib_status = dev->IbInterface.open_ca(pRegistration->hIbal, pAttributes->Guid, + NULL, NULL, &pRegistration->hCa); + if (ib_status != IB_SUCCESS) { + goto err2; + } + + ib_status = dev->IbInterface.alloc_pd(pRegistration->hCa, IB_PDT_ALIAS, + NULL, &pRegistration->hPd); + if (ib_status != IB_SUCCESS) { + goto err3; + } + + attr.sq_depth = attr.rq_depth = 1; + attr.sq_sge = attr.rq_sge = 1; + attr.sq_signaled = 1; + + ib_status = dev->IbInterface.get_spl_qp(pRegistration->hPd, + dev->pPortArray[pAttributes->Port].Guid, + &attr, pRegistration, NULL, + &pRegistration->hMadPool, + &pRegistration->hQp); + if (ib_status != IB_SUCCESS) { + status = STATUS_UNSUCCESSFUL; + goto err4; + } + + RtlZeroMemory(&svc, sizeof svc); + svc.mad_svc_context = pRegistration; + svc.pfn_mad_send_cb = WmSendHandler; + svc.pfn_mad_recv_cb = WmReceiveHandler; + svc.support_unsol = WmConvertMethods(&svc, pAttributes); + svc.mgmt_class = pAttributes->Class; + svc.mgmt_version = pAttributes->Version; + svc.svc_type = IB_MAD_SVC_DEFAULT; + + ib_status = dev->IbInterface.reg_mad_svc(pRegistration->hQp, &svc, + &pRegistration->hService); + if (ib_status != IB_SUCCESS) { + status = STATUS_UNSUCCESSFUL; + goto err5; + } + + if (svc.mgmt_class == IB_MCLASS_SUBN_DIR && svc.support_unsol) { + RtlZeroMemory(&port_cap, sizeof port_cap); + port_cap.cap.sm = 1; + ib_status = dev->IbInterface.modify_ca(pRegistration->hCa, + pRegistration->PortNum, + IB_CA_MOD_IS_SM, &port_cap); + if (ib_status != IB_SUCCESS) { + status = STATUS_UNSUCCESSFUL; + goto err5; + } + pRegistration->PortCapMask = IB_CA_MOD_IS_SM; + } + + pRegistration->pDevice = dev; + return STATUS_SUCCESS; + +err5: + dev->IbInterface.destroy_qp(pRegistration->hQp, NULL); +err4: + dev->IbInterface.dealloc_pd(pRegistration->hPd, NULL); +err3: + dev->IbInterface.close_ca(pRegistration->hCa, NULL); +err2: + dev->IbInterface.close_al(pRegistration->hIbal); +err1: + WmIbDevicePut(dev); + pRegistration->pDevice = NULL; + return status; +} + +void WmRegister(WM_PROVIDER *pProvider, WDFREQUEST Request) +{ + WM_REGISTRATION *reg; + WM_IO_REGISTER *attr; + UINT64 *id; + NTSTATUS status; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(WM_IO_REGISTER), &attr, NULL); + if (!NT_SUCCESS(status)) { + goto err1; + } + status = WdfRequestRetrieveOutputBuffer(Request, sizeof(UINT64), &id, NULL); + if (!NT_SUCCESS(status)) { + goto err1; + } + + reg = WmRegAlloc(pProvider); + if (reg == NULL) { + status = STATUS_NO_MEMORY; + goto err1; + } + + KeAcquireGuardedMutex(&pProvider->Lock); + WmProviderDisableRemove(pProvider); + KeReleaseGuardedMutex(&pProvider->Lock); + + status = WmRegInit(reg, attr); + if (!NT_SUCCESS(status)) { + goto err2; + } + + KeAcquireGuardedMutex(&pProvider->Lock); + reg->Id = IndexListInsertHead(&pProvider->RegIndex, reg); + if (reg->Id == 0) { + status = STATUS_NO_MEMORY; + goto err2; + } + KeReleaseGuardedMutex(&pProvider->Lock); + + WmProviderEnableRemove(pProvider); + *id = reg->Id; + WdfRequestCompleteWithInformation(Request, status, sizeof(UINT64)); + return; + +err2: + WmRegFree(reg); + WmProviderEnableRemove(pProvider); +err1: + WdfRequestComplete(Request, status); +} + +void WmDeregister(WM_PROVIDER *pProvider, WDFREQUEST Request) +{ + WM_REGISTRATION *reg; + UINT64 *id; + NTSTATUS status; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL); + if (!NT_SUCCESS(status)) { + goto out; + } + + KeAcquireGuardedMutex(&pProvider->Lock); + WmProviderDisableRemove(pProvider); + reg = IndexListAt(&pProvider->RegIndex, (SIZE_T) *id); + if (reg == NULL) { + status = STATUS_NO_SUCH_DEVICE; + } else if (reg->Ref > 1) { + status = STATUS_ACCESS_DENIED; + } else { + IndexListRemove(&pProvider->RegIndex, (SIZE_T) *id); + status = STATUS_SUCCESS; + } + KeReleaseGuardedMutex(&pProvider->Lock); + + if (NT_SUCCESS(status)) { + WmRegFree(reg); + } + WmProviderEnableRemove(pProvider); +out: + WdfRequestComplete(Request, status); +} + +void WmRegFree(WM_REGISTRATION *pRegistatration) +{ + WmRegRemoveHandler(pRegistatration); + WmProviderPut(pRegistatration->pProvider); + ExFreePoolWithTag(pRegistatration, 'grmw'); +} + +void WmRegRemoveHandler(WM_REGISTRATION *pRegistration) +{ + ib_port_attr_mod_t port_cap; + + if (pRegistration->pDevice == NULL) { + return; + } + + if (pRegistration->PortCapMask) { + RtlZeroMemory(&port_cap.cap, sizeof(port_cap.cap)); + pRegistration->pDevice->IbInterface.modify_ca(pRegistration->hCa, + pRegistration->PortNum, + pRegistration->PortCapMask, + &port_cap); + } + + WmProviderDeregister(pRegistration->pProvider, pRegistration); + pRegistration->pDevice->IbInterface.destroy_qp(pRegistration->hQp, NULL); + pRegistration->pDevice->IbInterface.dealloc_pd(pRegistration->hPd, NULL); + pRegistration->pDevice->IbInterface.close_ca(pRegistration->hCa, NULL); + pRegistration->pDevice->IbInterface.close_al(pRegistration->hIbal); + + WmIbDevicePut(pRegistration->pDevice); + pRegistration->pDevice = NULL; +} diff --git a/branches/WOF2-3/core/winmad/kernel/wm_reg.h b/branches/WOF2-3/core/winmad/kernel/wm_reg.h new file mode 100644 index 00000000..5f947e40 --- /dev/null +++ b/branches/WOF2-3/core/winmad/kernel/wm_reg.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#ifndef _WM_REG_H_ +#define _WM_REG_H_ + +#include +#include +#include + +#include "wm_driver.h" +#include "wm_provider.h" + +typedef struct _WM_REGISTRATION +{ + WM_PROVIDER *pProvider; + WM_IB_DEVICE *pDevice; + + ib_al_handle_t hIbal; + ib_ca_handle_t hCa; + UINT8 PortNum; + ib_pd_handle_t hPd; + ib_qp_handle_t hQp; + ib_pool_key_t hMadPool; + ib_mad_svc_handle_t hService; + ib_ca_mod_t PortCapMask; + + SIZE_T Id; + LONG Ref; + +} WM_REGISTRATION; + +void WmRegister(WM_PROVIDER *pProvider, WDFREQUEST Request); +void WmDeregister(WM_PROVIDER *pProvider, WDFREQUEST Request); +void WmRegFree(WM_REGISTRATION *pRegistration); +void WmRegRemoveHandler(WM_REGISTRATION *pRegistration); + +WM_REGISTRATION *WmRegAcquire(WM_PROVIDER *pProvider, UINT64 Id); +void WmRegRelease(WM_REGISTRATION *pRegistration); + +#endif // __WM_REG_H_ diff --git a/branches/WOF2-3/core/winmad/user/SOURCES b/branches/WOF2-3/core/winmad/user/SOURCES new file mode 100644 index 00000000..7d3d7c57 --- /dev/null +++ b/branches/WOF2-3/core/winmad/user/SOURCES @@ -0,0 +1,27 @@ +!if $(FREEBUILD) +TARGETNAME = winmad +!else +TARGETNAME = winmadd +!endif + +TARGETPATH = ..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = DYNLINK + +!if $(_NT_TOOLS_VERSION) == 0x700 +DLLDEF = $O\wm_exports.def +!else +DLLDEF = $(OBJ_PATH)\$O\wm_exports.def +!endif + +DLLENTRY = DllMain +USE_NTDLL = 1 + +SOURCES = winmad.rc wm_main.cpp wm_provider.cpp + +INCLUDES = ..;..\..\..\inc;..\..\..\inc\user; + +USER_C_FLAGS = $(USER_C_FLAGS) -DEXPORT_WM_SYMBOLS + +TARGETLIBS = \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\uuid.lib diff --git a/branches/WOF2-3/core/winmad/user/makefile b/branches/WOF2-3/core/winmad/user/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-3/core/winmad/user/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\inc\openib.def diff --git a/branches/WOF2-3/core/winmad/user/winmad.rc b/branches/WOF2-3/core/winmad/user/winmad.rc new file mode 100644 index 00000000..ab68fe77 --- /dev/null +++ b/branches/WOF2-3/core/winmad/user/winmad.rc @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + +#include + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef _DEBUG_ +#define VER_FILEDESCRIPTION_STR "WinMad (Debug)" +#define VER_INTERNALNAME_STR "winmadd.dll" +#define VER_ORIGINALFILENAME_STR "winmadd.dll" +#else +#define VER_FILEDESCRIPTION_STR "WinMad" +#define VER_INTERNALNAME_STR "winmad.dll" +#define VER_ORIGINALFILENAME_STR "winmad.dll" +#endif + +#include diff --git a/branches/WOF2-3/core/winmad/user/wm_exports.src b/branches/WOF2-3/core/winmad/user/wm_exports.src new file mode 100644 index 00000000..2c26af39 --- /dev/null +++ b/branches/WOF2-3/core/winmad/user/wm_exports.src @@ -0,0 +1,9 @@ +#if DBG +LIBRARY winmadd.dll +#else +LIBRARY winmad.dll +#endif + +EXPORTS +DllCanUnloadNow PRIVATE + diff --git a/branches/WOF2-3/core/winmad/user/wm_main.cpp b/branches/WOF2-3/core/winmad/user/wm_main.cpp new file mode 100644 index 00000000..e8c6d57c --- /dev/null +++ b/branches/WOF2-3/core/winmad/user/wm_main.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "wm_provider.h" + +volatile LONG WmRef; + +BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) +{ + UNREFERENCED_PARAMETER(hInstance); + UNREFERENCED_PARAMETER(dwReason); + UNREFERENCED_PARAMETER(lpReserved); + + return TRUE; +} + +STDAPI DllCanUnloadNow(void) +{ + return WmRef ? S_FALSE : S_OK; +} + +__declspec(dllexport) HRESULT WmGetObject(REFIID riid, LPVOID FAR* ppvObj) +{ + if (riid != IID_IWMProvider) { + *ppvObj = NULL; + return E_NOINTERFACE; + } + + return CWMProvider::CreateInstance((IWMProvider **) ppvObj); +} diff --git a/branches/WOF2-3/core/winmad/user/wm_memory.h b/branches/WOF2-3/core/winmad/user/wm_memory.h new file mode 100644 index 00000000..30cbfb9b --- /dev/null +++ b/branches/WOF2-3/core/winmad/user/wm_memory.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#ifndef _WM_MEMORY_H_ +#define _WM_MEMORY_H_ + +#include + +__inline void* __cdecl operator new(size_t size) +{ + return HeapAlloc(GetProcessHeap(), 0, size); +} + +__inline void __cdecl operator delete(void *pObj) +{ + HeapFree(GetProcessHeap(), 0, pObj); +} + +#endif // _WM_MEMORY_H_ \ No newline at end of file diff --git a/branches/WOF2-3/core/winmad/user/wm_provider.cpp b/branches/WOF2-3/core/winmad/user/wm_provider.cpp new file mode 100644 index 00000000..4dca5691 --- /dev/null +++ b/branches/WOF2-3/core/winmad/user/wm_provider.cpp @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include + +#include "wm_memory.h" +#include "wm_provider.h" +#include "wm_ioctl.h" + +CWMProvider::CWMProvider() +{ + InitializeCriticalSection(&m_CritSecRead); + InitializeCriticalSection(&m_CritSecWrite); + RtlZeroMemory(&m_OverlapRead, sizeof m_OverlapRead); + RtlZeroMemory(&m_OverlapWrite, sizeof m_OverlapWrite); + m_nRef = 1; + m_hFile = INVALID_HANDLE_VALUE; + InterlockedIncrement(&WmRef); +} + +STDMETHODIMP CWMProvider:: +Init(void) +{ + m_OverlapRead.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + m_OverlapWrite.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + + return (m_OverlapRead.hEvent != NULL && m_OverlapWrite.hEvent != NULL) ? + NOERROR : E_OUTOFMEMORY; +} + +CWMProvider::~CWMProvider() +{ + if (m_OverlapRead.hEvent != NULL) { + CloseHandle(m_OverlapRead.hEvent); + } + if (m_OverlapWrite.hEvent != NULL) { + CloseHandle(m_OverlapWrite.hEvent); + } + CloseHandle(m_hFile); + DeleteCriticalSection(&m_CritSecRead); + DeleteCriticalSection(&m_CritSecWrite); + InterlockedDecrement(&WmRef); +} + +STDMETHODIMP CWMProvider:: +QueryInterface(REFIID riid, LPVOID FAR* ppvObj) +{ + if (riid != IID_IUnknown && riid != IID_IWMProvider) { + *ppvObj = NULL; + return E_NOINTERFACE; + } + + *ppvObj = this; + AddRef(); + return NOERROR; +} + +STDMETHODIMP_(ULONG) CWMProvider:: +AddRef(void) +{ + return InterlockedIncrement(&m_nRef); +} + +STDMETHODIMP_(ULONG) CWMProvider:: +Release(void) +{ + ULONG ref; + + ref = (ULONG) InterlockedDecrement(&m_nRef); + if (ref == 0) { + Delete(); + } + return ref; +} + +STDMETHODIMP CWMProvider:: +CancelOverlappedRequests(void) +{ + DWORD bytes; + + return WmDeviceIoControl(m_hFile, WM_IOCTL_CANCEL, NULL, 0, + NULL, 0, &bytes, NULL) ? + NOERROR : HRESULT_FROM_WIN32(GetLastError()); +} + +STDMETHODIMP CWMProvider:: +GetOverlappedResult(OVERLAPPED *pOverlapped, + DWORD *pNumberOfBytesTransferred, BOOL bWait) +{ + ::GetOverlappedResult(m_hFile, pOverlapped, pNumberOfBytesTransferred, bWait); + return (HRESULT) pOverlapped->Internal; +} + +STDMETHODIMP_(HANDLE) CWMProvider:: +GetFileHandle(void) +{ + return m_hFile; +} + +STDMETHODIMP_(BOOL) CWMProvider:: +WmDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, + LPVOID lpInBuffer, DWORD nInBufferSize, + LPVOID lpOutBuffer, DWORD nOutBufferSize, + LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) +{ + BOOL ret; + + if (lpOverlapped == NULL) { + EnterCriticalSection(&m_CritSecWrite); + DeviceIoControl(hDevice, dwIoControlCode, + lpInBuffer, nInBufferSize, + lpOutBuffer, nOutBufferSize, + lpBytesReturned, &m_OverlapWrite); + ret = ::GetOverlappedResult(m_hFile, &m_OverlapWrite, lpBytesReturned, TRUE); + LeaveCriticalSection(&m_CritSecWrite); + } else { + ret = DeviceIoControl(hDevice, dwIoControlCode, + lpInBuffer, nInBufferSize, + lpOutBuffer, nOutBufferSize, + lpBytesReturned, lpOverlapped); + } + + return ret; +} + +STDMETHODIMP CWMProvider:: +Register(WM_REGISTER *pAttributes, UINT64 *pId) +{ + DWORD bytes; + + if (WmDeviceIoControl(m_hFile, WM_IOCTL_REGISTER, + pAttributes, sizeof WM_REGISTER, + pId, sizeof UINT64, &bytes, NULL)) { + return NOERROR; + } else { + return HRESULT_FROM_WIN32(GetLastError()); + } +} + +STDMETHODIMP CWMProvider:: +Deregister(UINT64 Id) +{ + DWORD bytes; + + if (WmDeviceIoControl(m_hFile, WM_IOCTL_DEREGISTER, + &Id, sizeof UINT64, + NULL, 0, &bytes, NULL)) { + return NOERROR; + } else { + return HRESULT_FROM_WIN32(GetLastError()); + } +} + +STDMETHODIMP CWMProvider:: +Send(WM_MAD *pMad, OVERLAPPED *pOverlapped) +{ + DWORD bytes; + HRESULT hr; + + bytes = (DWORD) sizeof(WM_MAD) + pMad->Length; + if (pOverlapped == NULL) { + EnterCriticalSection(&m_CritSecWrite); + WriteFile(m_hFile, pMad, bytes, &bytes, &m_OverlapWrite); + hr = GetOverlappedResult(&m_OverlapWrite, &bytes, TRUE); + LeaveCriticalSection(&m_CritSecWrite); + } else { + if (WriteFile(m_hFile, pMad, bytes, &bytes, pOverlapped)) { + hr = NOERROR; + } else { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + } + + return hr; +} + +STDMETHODIMP CWMProvider:: +Receive(WM_MAD *pMad, SIZE_T BufferSize, OVERLAPPED *pOverlapped) +{ + DWORD bytes; + HRESULT hr; + + if (pOverlapped == NULL) { + EnterCriticalSection(&m_CritSecRead); + ReadFile(m_hFile, pMad, (DWORD) BufferSize, &bytes, &m_OverlapRead); + hr = GetOverlappedResult(&m_OverlapRead, &bytes, TRUE); + LeaveCriticalSection(&m_CritSecRead); + } else { + if (ReadFile(m_hFile, pMad, (DWORD) BufferSize, &bytes, pOverlapped)) { + hr = NOERROR; + } else { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + } + + return hr; +} diff --git a/branches/WOF2-3/core/winmad/user/wm_provider.h b/branches/WOF2-3/core/winmad/user/wm_provider.h new file mode 100644 index 00000000..47b23ad7 --- /dev/null +++ b/branches/WOF2-3/core/winmad/user/wm_provider.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#ifndef _WM_PROVIDER_H_ +#define _WM_PROVIDER_H_ + +#include + +extern volatile LONG WmRef; + +class CWMProvider : IWMProvider +{ +public: + // IUnknown methods + STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + // IWVProvider methods + STDMETHODIMP CancelOverlappedRequests(); + STDMETHODIMP GetOverlappedResult(OVERLAPPED *pOverlapped, + DWORD *pNumberOfBytesTransferred, BOOL bWait); + + STDMETHODIMP_(HANDLE) GetFileHandle(); + STDMETHODIMP Register(WM_REGISTER *pAttributes, UINT64 *pId); + STDMETHODIMP Deregister(UINT64 Id); + STDMETHODIMP Send(WM_MAD *pMad, OVERLAPPED *pOverlapped); + STDMETHODIMP Receive(WM_MAD *pMad, SIZE_T BufferSize, OVERLAPPED *pOverlapped); + + CWMProvider(); + STDMETHODIMP Init(); + ~CWMProvider(); + void Delete() {delete this;} + static STDMETHODIMP CreateInstance(IWMProvider** ppProvider) + { + HRESULT hr; + CWMProvider *wm; + + wm = new CWMProvider; + if (wm == NULL) { + hr = E_OUTOFMEMORY; + goto err1; + } + + hr = wm->Init(); + if (FAILED(hr)) { + goto err2; + } + + wm->m_hFile = CreateFileW(L"\\\\.\\WinMad", GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); + if (wm->m_hFile == INVALID_HANDLE_VALUE) { + hr = HRESULT_FROM_WIN32(GetLastError()); + goto err2; + } + *ppProvider = wm; + return NOERROR; + + err2: + wm->Release(); + err1: + *ppProvider = NULL; + return hr; + } + + HANDLE m_hFile; + volatile LONG m_nRef; +protected: + STDMETHODIMP_(BOOL) WmDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, + LPVOID lpInBuffer, DWORD nInBufferSize, + LPVOID lpOutBuffer, DWORD nOutBufferSize, + LPDWORD lpBytesReturned, + LPOVERLAPPED lpOverlapped); + + OVERLAPPED m_OverlapWrite; + OVERLAPPED m_OverlapRead; + CRITICAL_SECTION m_CritSecWrite; + CRITICAL_SECTION m_CritSecRead; +}; + +#endif // _WM_PROVIDER_H_ \ No newline at end of file diff --git a/branches/WOF2-3/core/winmad/wm_ioctl.h b/branches/WOF2-3/core/winmad/wm_ioctl.h new file mode 100644 index 00000000..56063e0e --- /dev/null +++ b/branches/WOF2-3/core/winmad/wm_ioctl.h @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#ifndef _WM_IOCTL_H_ +#define _WM_IOCTL_H_ + +typedef UINT16 NET16; +typedef UINT32 NET32; +typedef UINT64 NET64; + +#define WM_IOCTL(f) CTL_CODE(FILE_DEVICE_INFINIBAND, f, METHOD_BUFFERED,\ + FILE_READ_DATA | FILE_WRITE_DATA) + +// input parameter / output parameter +// IOCTL +#define WM_IO_FUNCTION_BASE 0x800 + +enum { + WM_IO_FUNCTION_MIN, + WM_IO_FUNCTION_REGISTER, + WM_IO_FUNCTION_DEREGISTER, + WM_IO_FUNCTION_CANCEL, + WM_IO_FUNCTION_MAX +}; + +// WM_IO_REGISTER / UINT64 Id +#define WM_IOCTL_REGISTER WM_IOCTL(WM_IO_FUNCTION_BASE + \ + WM_IO_FUNCTION_REGISTER) + +// UINT64 Id / none +#define WM_IOCTL_DEREGISTER WM_IOCTL(WM_IO_FUNCTION_BASE + \ + WM_IO_FUNCTION_DEREGISTER) + +// none / none +#define WM_IOCTL_CANCEL WM_IOCTL(WM_IO_FUNCTION_BASE + \ + WM_IO_FUNCTION_CANCEL) + +#define WM_IOCTL_MIN WM_IO_FUNCTION_BASE + WM_IO_FUNCTION_MIN +#define WM_IOCTL_MAX WM_IO_FUNCTION_BASE + WM_IO_FUNCTION_MAX + +typedef struct _WM_IO_REGISTER +{ + NET64 Guid; + NET32 Qpn; + UINT8 Port; + UINT8 Class; + UINT8 Version; + UINT8 Reserved[6]; + UINT8 Oui[3]; + UINT8 Methods[16]; + +} WM_IO_REGISTER; + +typedef struct _WM_IO_MAD_AV +{ + NET32 Qpn; + NET32 Qkey; + NET32 VersionClassFlow; + UINT16 PkeyIndex; + UINT8 HopLimit; + UINT8 GidIndex; + UINT8 Gid[16]; + + UINT16 Reserved; + NET16 Lid; + UINT8 ServiceLevel; + UINT8 PathBits; + UINT8 StaticRate; + UINT8 GrhValid; + +} WM_IO_MAD_AV; + +#define WM_IO_SUCCESS 0 +#define WM_IO_TIMEOUT 138 + +#pragma warning(push) +#pragma warning(disable: 4200) +typedef struct _WM_IO_MAD +{ + UINT64 Id; + WM_IO_MAD_AV Address; + + UINT32 Status; + UINT32 Timeout; + UINT32 Retries; + UINT32 Length; + + UINT8 Data[0]; + +} WM_IO_MAD; +#pragma warning(pop) + +#endif // _WM_IOCTL_H_ diff --git a/branches/WOF2-3/core/winverbs/dirs b/branches/WOF2-3/core/winverbs/dirs new file mode 100644 index 00000000..a5a581d5 --- /dev/null +++ b/branches/WOF2-3/core/winverbs/dirs @@ -0,0 +1,3 @@ +DIRS=\ + kernel \ + user diff --git a/branches/WOF2-3/core/winverbs/kernel/SOURCES b/branches/WOF2-3/core/winverbs/kernel/SOURCES new file mode 100644 index 00000000..3322a7d6 --- /dev/null +++ b/branches/WOF2-3/core/winverbs/kernel/SOURCES @@ -0,0 +1,28 @@ +TARGETNAME = winverbs +TARGETPATH = ..\..\..\bin\kernel\obj$(BUILD_ALT_DIR) +TARGETTYPE = DRIVER + +KMDF_VERSION_MAJOR = 1 +INF_NAME = winverbs +INF_TARGET=..\..\..\bin\kernel\$(O)\$(INF_NAME).inf +NTTARGETFILES = $(INF_TARGET) +MISCFILES = $(NTTARGETFILES) +TARGETLIBS = $(TARGETLIBS) \ + $(DDK_LIB_PATH)\wdmsec.lib \ + $(TARGETPATH)\*\complib.lib + +SOURCES = \ + winverbs.rc \ + wv_driver.c \ + wv_provider.c \ + wv_device.c \ + wv_cq.c \ + wv_pd.c \ + wv_srq.c \ + wv_qp.c \ + wv_ep.c + +INCLUDES = ..;..\..\..\inc;..\..\..\inc\kernel;..\..\..\inc\user;..\..\..\etc\kernel; + +C_DEFINES = $(C_DEFINES) -DIOCTL_INTERFACE=1 + diff --git a/branches/WOF2-3/core/winverbs/kernel/makefile b/branches/WOF2-3/core/winverbs/kernel/makefile new file mode 100644 index 00000000..128ed372 --- /dev/null +++ b/branches/WOF2-3/core/winverbs/kernel/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the Windows NT DDK +# + +!INCLUDE ..\..\..\inc\openib.def diff --git a/branches/WOF2-3/core/winverbs/kernel/makefile.inc b/branches/WOF2-3/core/winverbs/kernel/makefile.inc new file mode 100644 index 00000000..400aaaf2 --- /dev/null +++ b/branches/WOF2-3/core/winverbs/kernel/makefile.inc @@ -0,0 +1,13 @@ +_LNG=$(LANGUAGE) + +!IF !DEFINED(_INX) +_INX=. +!ENDIF + +STAMP=stampinf -a $(_BUILDARCH) -k $(KMDF_VERSION_MAJOR).$(KMDF_VERSION_MINOR) + +!INCLUDE mod_ver.def + +$(INF_TARGET) : $(_INX)\$(INF_NAME).inx + copy $(_INX)\$(@B).inx $@ + $(STAMP) -f $@ -d * -v $(IB_MAJORVERSION).$(IB_MINORVERSION).$(IB_BUILDVERSION).$(OPENIB_REV) diff --git a/branches/WOF2-3/core/winverbs/kernel/winverbs.cdf b/branches/WOF2-3/core/winverbs/kernel/winverbs.cdf new file mode 100644 index 00000000..4e67010f --- /dev/null +++ b/branches/WOF2-3/core/winverbs/kernel/winverbs.cdf @@ -0,0 +1,11 @@ +[CatalogHeader] +Name=winverbs.cat +PublicVersion=0x0000001 +EncodingType=0x00010001 +CATATTR1=0x10010001:OSAttr:2:6.0 +[CatalogFiles] +winverbs.inf=winverbs.inf +winverbs.sys=winverbs.sys +winverbs.dll=winverbs.dll +winverbsd.dll=winverbsd.dll +WdfCoInstaller01007.dll=WdfCoInstaller01007.dll diff --git a/branches/WOF2-3/core/winverbs/kernel/winverbs.inx b/branches/WOF2-3/core/winverbs/kernel/winverbs.inx new file mode 100644 index 00000000..225df71c --- /dev/null +++ b/branches/WOF2-3/core/winverbs/kernel/winverbs.inx @@ -0,0 +1,108 @@ +; +; Copyright (c) 2008 Intel Corporation. All rights reserved. +; +; This software is available to you under the OpenIB.org BSD license +; below: +; +; Redistribution and use in source and binary forms, with or +; without modification, are permitted provided that the following +; conditions are met: +; +; - Redistributions of source code must retain the above +; copyright notice, this list of conditions and the following +; disclaimer. +; +; - Redistributions in binary form must reproduce the above +; copyright notice, this list of conditions and the following +; disclaimer in the documentation and/or other materials +; provided with the distribution. +; +; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV +; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +; BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +; ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +; CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +; SOFTWARE. +; + +[Version] +Signature = "$WINDOWS NT$" +Class = InfiniBandController +ClassGUID = {58517E00-D3CF-40c9-A679-CEE5752F4491} +Provider = %OFA% +DriverVer = 05/20/2008 +CatalogFile = winverbs.cat + +[SourceDisksNames] +1 = %DiskId% + +[SourceDisksFiles] +winverbs.sys = 1 +winverbs.dll = 1 +winverbsd.dll = 1 + +[DefaultInstall] +AddReg = WvClassAddReg +CopyFiles = WvClassCopySysFiles, WvClassCopyDllFiles + +[WvClassAddReg] +HKLM, System\CurrentControlSet\Control\Class\{58517E00-D3CF-40c9-A679-CEE5752F4491}, UpperFilters, 0x00010008, WinVerbs + +[DestinationDirs] +WvClassCopySysFiles = 12 +WvClassCopyDllFiles = 11 + +[WvClassCopySysFiles] +winverbs.sys + +[WvClassCopyDllFiles] +winverbs.dll +winverbsd.dll + +[Manufacturer] +%OFA% = WvModel, NT$ARCH$ + +[WvModel] +%WinVerbs.DeviceDesc% = WvDevice, root\WinVerbs + +[DefaultInstall.Services] +AddService = WinVerbs,, WvClassService + +[WvClassService] +DisplayName = %WinVerbs.ServiceDesc% +ServiceType = 1 +StartType = 3 +ErrorControl = 1 +ServiceBinary = %12%\winverbs.sys +LoadOrderGroup = PNP Filter + +[WvDevice.CoInstallers] +AddReg = WvDeviceCoInstAddReg +CopyFiles = WvDeviceCoInstCopyFiles + +[DestinationDirs] +WvDeviceCoInstCopyFiles = 11 + +[WvDeviceCoInstAddReg] +HKR,, CoInstallers32, 0x00010000, "WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll, WdfCoInstaller" + +[WvDeviceCoInstCopyFiles] +WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll + +[SourceDisksFiles] +WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll = 1 + +[WvDevice.Wdf] +KmdfService = WinVerbs, WvWdfSect + +[WvWdfSect] +KmdfLibraryVersion = $KMDFVERSION$ + +[Strings] +OFA = "OpenFabrics" +DiskId = "OpenFabrics WinVerbs Installation" +WinVerbs.DeviceDesc = "WinVerbs Driver" +WinVerbs.ServiceDesc = "WinVerbs Service" +ClassName = "WinVerbs Device" diff --git a/branches/WOF2-3/core/winverbs/kernel/winverbs.rc b/branches/WOF2-3/core/winverbs/kernel/winverbs.rc new file mode 100644 index 00000000..50b57592 --- /dev/null +++ b/branches/WOF2-3/core/winverbs/kernel/winverbs.rc @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_DRV_SYSTEM + +#ifdef _DEBUG_ +#define VER_FILEDESCRIPTION_STR "Kernel WinVerbs (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "Kernel WinVerbs" +#endif + +#define VER_INTERNALNAME_STR "winverbs.sys" +#define VER_ORIGINALFILENAME_STR "winverbs.sys" + +#include diff --git a/branches/WOF2-3/core/winverbs/kernel/wv_cq.c b/branches/WOF2-3/core/winverbs/kernel/wv_cq.c new file mode 100644 index 00000000..76e79db5 --- /dev/null +++ b/branches/WOF2-3/core/winverbs/kernel/wv_cq.c @@ -0,0 +1,335 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "wv_driver.h" +#include "wv_cq.h" +#include "wv_ioctl.h" + +void WvCqGet(WV_COMPLETION_QUEUE *pCq) +{ + InterlockedIncrement(&pCq->Ref); +} + +void WvCqPut(WV_COMPLETION_QUEUE *pCq) +{ + if (InterlockedDecrement(&pCq->Ref) == 0) { + KeSetEvent(&pCq->Event, 0, FALSE); + } +} + +WV_COMPLETION_QUEUE *WvCqAcquire(WV_PROVIDER *pProvider, UINT64 Id) +{ + WV_COMPLETION_QUEUE *cq; + + KeAcquireGuardedMutex(&pProvider->Lock); + WvProviderDisableRemove(pProvider); + cq = IndexListAt(&pProvider->CqIndex, (SIZE_T) Id); + if (cq != NULL && cq->hVerbsCq != NULL) { + WvCqGet(cq); + } else { + cq = NULL; + WvProviderEnableRemove(pProvider); + } + KeReleaseGuardedMutex(&pProvider->Lock); + + return cq; +} + +void WvCqRelease(WV_COMPLETION_QUEUE *pCq) +{ + WvProviderEnableRemove(pCq->pDevice->pProvider); + WvCqPut(pCq); +} + +static void WvCqEventHandler(ib_event_rec_t *pEvent) +{ + WV_COMPLETION_QUEUE *cq = pEvent->context; + WvFlushQueue(cq->Queue, STATUS_UNEXPECTED_IO_ERROR); + WvFlushQueue(cq->ErrorQueue, STATUS_UNEXPECTED_IO_ERROR); +} + +static void WvCqHandler(void *Context) +{ + WV_COMPLETION_QUEUE *cq = Context; + + WvFlushQueue(cq->Queue, STATUS_SUCCESS); +} + +static NTSTATUS WvCqAlloc(WV_DEVICE *pDevice, UINT32 *pSize, + WV_COMPLETION_QUEUE **ppCq, ci_umv_buf_t *pVerbsData) +{ + ib_api_status_t ib_status; + WV_COMPLETION_QUEUE *cq; + WDF_IO_QUEUE_CONFIG config; + NTSTATUS status; + + cq = ExAllocatePoolWithTag(NonPagedPool, sizeof(WV_COMPLETION_QUEUE), 'qcvw'); + if (cq == NULL) { + return STATUS_NO_MEMORY; + } + + cq->Ref = 1; + KeInitializeEvent(&cq->Event, NotificationEvent, FALSE); + + WDF_IO_QUEUE_CONFIG_INIT(&config, WdfIoQueueDispatchManual); + status = WdfIoQueueCreate(ControlDevice, &config, + WDF_NO_OBJECT_ATTRIBUTES, &cq->Queue); + if (!NT_SUCCESS(status)) { + goto err1; + } + + status = WdfIoQueueCreate(ControlDevice, &config, + WDF_NO_OBJECT_ATTRIBUTES, &cq->ErrorQueue); + if (!NT_SUCCESS(status)) { + goto err2; + } + + ib_status = pDevice->pVerbs->create_cq(pDevice->hVerbsDevice, cq, + WvCqEventHandler, WvCqHandler, + pSize, &cq->hVerbsCq, pVerbsData); + if (ib_status != IB_SUCCESS) { + status = STATUS_UNSUCCESSFUL; + goto err3; + } + + cq->pDevice = pDevice; + cq->pVerbs = pDevice->pVerbs; + *ppCq = cq; + return STATUS_SUCCESS; + +err3: + WdfObjectDelete(cq->ErrorQueue); +err2: + WdfObjectDelete(cq->Queue); +err1: + ExFreePoolWithTag(cq, 'qcvw'); + return status; +} + +void WvCqCreate(WV_PROVIDER *pProvider, WDFREQUEST Request) +{ + WV_IO_ID *inid, *outid; + size_t inlen, outlen; + WV_DEVICE *dev; + WV_COMPLETION_QUEUE *cq; + NTSTATUS status; + ci_umv_buf_t verbsData; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_ID), &inid, &inlen); + if (!NT_SUCCESS(status)) { + goto err1; + } + status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_ID), &outid, &outlen); + if (!NT_SUCCESS(status)) { + goto err1; + } + + dev = WvDeviceAcquire(pProvider, inid->Id); + if (dev == NULL) { + status = STATUS_NO_SUCH_DEVICE; + goto err1; + } + + WvInitVerbsData(&verbsData, inid->VerbInfo, inlen - sizeof(WV_IO_ID), + outlen - sizeof(WV_IO_ID), inid + 1); + status = WvCqAlloc(dev, &inid->Data, &cq, &verbsData); + if (!NT_SUCCESS(status)) { + goto err2; + } + + KeAcquireGuardedMutex(&pProvider->Lock); + outid->Id = IndexListInsertHead(&pProvider->CqIndex, cq); + if (outid->Id == 0) { + status = STATUS_NO_MEMORY; + goto err3; + } + InsertHeadList(&dev->CqList, &cq->Entry); + KeReleaseGuardedMutex(&pProvider->Lock); + + WvProviderEnableRemove(pProvider); + outid->Data = inid->Data; + outid->VerbInfo = verbsData.status; + WdfRequestCompleteWithInformation(Request, status, outlen); + return; + +err3: + KeReleaseGuardedMutex(&pProvider->Lock); + WvCqFree(cq); +err2: + WvDeviceRelease(dev); +err1: + WdfRequestComplete(Request, status); +} + +void WvCqDestroy(WV_PROVIDER *pProvider, WDFREQUEST Request) +{ + WV_COMPLETION_QUEUE *cq; + UINT64 *id; + NTSTATUS status; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL); + if (!NT_SUCCESS(status)) { + goto out; + } + + KeAcquireGuardedMutex(&pProvider->Lock); + WvProviderDisableRemove(pProvider); + cq = IndexListAt(&pProvider->CqIndex, (SIZE_T) *id); + if (cq == NULL) { + status = STATUS_NOT_FOUND; + } else if (cq->Ref > 1) { + status = STATUS_ACCESS_DENIED; + } else { + IndexListRemove(&pProvider->CqIndex, (SIZE_T) *id); + RemoveEntryList(&cq->Entry); + status = STATUS_SUCCESS; + } + KeReleaseGuardedMutex(&pProvider->Lock); + + if (NT_SUCCESS(status)) { + WvCqFree(cq); + } + WvProviderEnableRemove(pProvider); +out: + WdfRequestComplete(Request, status); +} + +void WvCqFree(WV_COMPLETION_QUEUE *pCq) +{ + if (InterlockedDecrement(&pCq->Ref) > 0) { + KeWaitForSingleObject(&pCq->Event, Executive, KernelMode, FALSE, NULL); + } + + if (pCq->hVerbsCq != NULL) { + pCq->pVerbs->destroy_cq(pCq->hVerbsCq); + } + + WdfIoQueuePurgeSynchronously(pCq->Queue); + WdfIoQueuePurgeSynchronously(pCq->ErrorQueue); + WdfObjectDelete(pCq->Queue); + WdfObjectDelete(pCq->ErrorQueue); + WvDevicePut(pCq->pDevice); + ExFreePoolWithTag(pCq, 'qcvw'); +} + +void WvCqResize(WV_PROVIDER *pProvider, WDFREQUEST Request) +{ + WV_IO_ID *inid, *outid; + size_t inlen, outlen, len = 0; + WV_COMPLETION_QUEUE *cq; + NTSTATUS status; + ib_api_status_t ib_status; + ci_umv_buf_t verbsData; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_ID), &inid, &inlen); + if (!NT_SUCCESS(status)) { + goto complete; + } + status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_ID), &outid, &outlen); + if (!NT_SUCCESS(status)) { + goto complete; + } + + cq = WvCqAcquire(pProvider, inid->Id); + if (cq == NULL) { + status = STATUS_NOT_FOUND; + goto complete; + } + + WvInitVerbsData(&verbsData, inid->VerbInfo, inlen - sizeof(WV_IO_ID), + outlen - sizeof(WV_IO_ID), inid + 1); + ib_status = cq->pVerbs->resize_cq(cq->hVerbsCq, &inid->Data, &verbsData); + WvCqRelease(cq); + + if (ib_status != IB_SUCCESS) { + status = STATUS_UNSUCCESSFUL; + } + + len = outlen; + outid->Data = inid->Data; + outid->VerbInfo = verbsData.status; + +complete: + WdfRequestCompleteWithInformation(Request, status, len); +} + +void WvCqNotify(WV_PROVIDER *pProvider, WDFREQUEST Request) +{ + WV_IO_ID *id; + WV_COMPLETION_QUEUE *cq; + NTSTATUS status; + WDFQUEUE queue; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_ID), &id, NULL); + if (!NT_SUCCESS(status)) { + goto out; + } + + cq = WvCqAcquire(pProvider, id->Id); + if (cq == NULL) { + status = STATUS_NOT_FOUND; + goto out; + } + + queue = (id->Data == WV_CQ_ERROR) ? cq->ErrorQueue : cq->Queue; + WdfObjectAcquireLock(queue); + status = WdfRequestForwardToIoQueue(Request, queue); + WdfObjectReleaseLock(queue); + WvCqRelease(cq); + +out: + if (!NT_SUCCESS(status)) { + WdfRequestComplete(Request, status); + } +} + +void WvCqCancel(WV_PROVIDER *pProvider, WDFREQUEST Request) +{ + UINT64 *id; + WV_COMPLETION_QUEUE *cq; + NTSTATUS status; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL); + if (!NT_SUCCESS(status)) { + goto out; + } + + cq = WvCqAcquire(pProvider, *id); + if (cq == NULL) { + status = STATUS_NOT_FOUND; + goto out; + } + + WvFlushQueue(cq->Queue, STATUS_CANCELLED); + WvFlushQueue(cq->ErrorQueue, STATUS_CANCELLED); + WvCqRelease(cq); + +out: + WdfRequestComplete(Request, status); +} diff --git a/branches/WOF2-3/core/winverbs/kernel/wv_cq.h b/branches/WOF2-3/core/winverbs/kernel/wv_cq.h new file mode 100644 index 00000000..d0e20ae7 --- /dev/null +++ b/branches/WOF2-3/core/winverbs/kernel/wv_cq.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#ifndef _WV_CQ_H_ +#define _WV_CQ_H_ + +#include +#include +#include +#include + +#include "wv_device.h" +#include "wv_provider.h" + +typedef struct _WV_COMPLETION_QUEUE +{ + WV_DEVICE *pDevice; + ci_interface_t *pVerbs; + ib_cq_handle_t hVerbsCq; + LIST_ENTRY Entry; + + KEVENT Event; + LONG Ref; + WDFQUEUE Queue; + WDFQUEUE ErrorQueue; + +} WV_COMPLETION_QUEUE; + + +void WvCqCreate(WV_PROVIDER *pProvider, WDFREQUEST Request); +void WvCqDestroy(WV_PROVIDER *pProvider, WDFREQUEST Request); +void WvCqFree(WV_COMPLETION_QUEUE *pCq); + +WV_COMPLETION_QUEUE *WvCqAcquire(WV_PROVIDER *pProvider, UINT64 Id); +void WvCqRelease(WV_COMPLETION_QUEUE *pCq); +void WvCqGet(WV_COMPLETION_QUEUE *pCq); +void WvCqPut(WV_COMPLETION_QUEUE *pCq); + +void WvCqResize(WV_PROVIDER *pProvider, WDFREQUEST Request); +void WvCqNotify(WV_PROVIDER *pProvider, WDFREQUEST Request); +void WvCqBatchNotify(WV_PROVIDER *pProvider, WDFREQUEST Request); +void WvCqCancel(WV_PROVIDER *pProvider, WDFREQUEST Request); + +#endif //_WV_CQ_H_ diff --git a/branches/WOF2-3/core/winverbs/kernel/wv_device.c b/branches/WOF2-3/core/winverbs/kernel/wv_device.c new file mode 100644 index 00000000..31750111 --- /dev/null +++ b/branches/WOF2-3/core/winverbs/kernel/wv_device.c @@ -0,0 +1,819 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "wv_device.h" +#include "wv_pd.h" +#include "wv_cq.h" +#include "wv_ioctl.h" + +void WvDeviceGet(WV_DEVICE *pDevice) +{ + InterlockedIncrement(&pDevice->Ref); +} + +void WvDevicePut(WV_DEVICE *pDevice) +{ + if (InterlockedDecrement(&pDevice->Ref) == 0) { + KeSetEvent(&pDevice->Event, 0, FALSE); + } +} + +WV_DEVICE *WvDeviceAcquire(WV_PROVIDER *pProvider, UINT64 Id) +{ + WV_DEVICE *dev; + + KeAcquireGuardedMutex(&pProvider->Lock); + WvProviderDisableRemove(pProvider); + dev = IndexListAt(&pProvider->DevIndex, (SIZE_T) Id); + if (dev != NULL && dev->hVerbsDevice != NULL) { + WvDeviceGet(dev); + } else { + dev = NULL; + WvProviderEnableRemove(pProvider); + } + KeReleaseGuardedMutex(&pProvider->Lock); + + return dev; +} + +void WvDeviceRelease(WV_DEVICE *pDevice) +{ + WvProviderEnableRemove(pDevice->pProvider); + WvDevicePut(pDevice); +} + +static UINT32 WvDeviceConvertEvent(ib_async_event_t event) +{ + switch (event) { + case IB_AE_LOCAL_FATAL: + return WV_IO_EVENT_ERROR; + case IB_AE_PORT_ACTIVE: + case IB_AE_PORT_DOWN: + return WV_IO_EVENT_STATE; + case IB_AE_CLIENT_REREGISTER: + case IB_AE_SM_CHANGE: + return WV_IO_EVENT_MANAGEMENT; + case IB_AE_GID_CHANGE: + return WV_IO_EVENT_ADDRESS; + case IB_AE_LID_CHANGE: + return WV_IO_EVENT_LINK_ADDRESS; + case IB_AE_PKEY_CHANGE: + return WV_IO_EVENT_PARTITION; + default: + return 0; + } +} + +static void WvDeviceCompleteRequests(WV_PORT *pPort, NTSTATUS ReqStatus, UINT32 Event) +{ + WDFREQUEST request; + NTSTATUS status; + UINT32 *flags; + + WdfObjectAcquireLock(pPort->Queue); + pPort->Flags |= Event; + Event = pPort->Flags; + + status = WdfIoQueueRetrieveNextRequest(pPort->Queue, &request); + while (NT_SUCCESS(status)) { + pPort->Flags = 0; + + status = WdfRequestRetrieveOutputBuffer(request, sizeof(UINT32), &flags, NULL); + if (NT_SUCCESS(status)) { + *flags = Event; + WdfRequestCompleteWithInformation(request, ReqStatus, sizeof(UINT32)); + } else { + WdfRequestComplete(request, status); + } + status = WdfIoQueueRetrieveNextRequest(pPort->Queue, &request); + } + + WdfObjectReleaseLock(pPort->Queue); +} + +static void WvDeviceEventHandler(ib_event_rec_t *pEvent) +{ + WV_DEVICE *dev; + UINT32 event; + UINT8 i; + + event = WvDeviceConvertEvent(pEvent->type); + if (event == 0) { + return; + } + + dev = CONTAINING_RECORD(pEvent->context, WV_DEVICE, EventHandler); + + if (event == WV_IO_EVENT_ERROR) { + for (i = 0; i < dev->PortCount; i++) { + WvDeviceCompleteRequests(&dev->pPorts[i], STATUS_SUCCESS, event); + } + } else { + WvDeviceCompleteRequests(&dev->pPorts[pEvent->port_number - 1], + STATUS_SUCCESS, event); + } +} + +static WV_DEVICE *WvDeviceAlloc(WV_PROVIDER *pProvider) +{ + WV_DEVICE *dev; + + dev = ExAllocatePoolWithTag(NonPagedPool, sizeof(WV_DEVICE), 'cdvw'); + if (dev == NULL) { + return NULL; + } + + dev->pDevice = NULL; + dev->pVerbs = NULL; + dev->hVerbsDevice = NULL; + dev->pPorts = NULL; + dev->PortCount = 0; + dev->Ref = 1; + InitializeListHead(&dev->PdList); + InitializeListHead(&dev->CqList); + KeInitializeEvent(&dev->Event, NotificationEvent, FALSE); + dev->EventHandler.pfn_async_event_cb = WvDeviceEventHandler; + + dev->pProvider = pProvider; + WvProviderGet(pProvider); + return dev; +} + +static ib_ca_attr_t *WvQueryCaAttributes(WV_DEVICE *pDevice) +{ + ib_ca_attr_t *attr; + UINT32 size; + ib_api_status_t ib_status; + + size = 0; + ib_status = pDevice->pVerbs->query_ca(pDevice->pDevice->hDevice, NULL, + &size, NULL); + if (ib_status != IB_INSUFFICIENT_MEMORY) { + attr = NULL; + goto out; + } + + attr = ExAllocatePoolWithTag(PagedPool, size, 'acvw'); + if (attr == NULL) { + goto out; + } + + ib_status = pDevice->pVerbs->query_ca(pDevice->pDevice->hDevice, attr, + &size, NULL); + if (ib_status != IB_SUCCESS) { + ExFreePoolWithTag(attr, 'acvw'); + attr = NULL; + } + +out: + return attr; +} + +static NTSTATUS WvDeviceCreatePorts(WV_DEVICE *pDevice) +{ + WDF_IO_QUEUE_CONFIG config; + ib_ca_attr_t *attr; + NTSTATUS status; + UINT8 i; + + attr = WvQueryCaAttributes(pDevice); + if (attr == NULL) { + return STATUS_NO_MEMORY; + } + + pDevice->PortCount = attr->num_ports; + ExFreePoolWithTag(attr, 'acvw'); + + pDevice->pPorts = ExAllocatePoolWithTag(NonPagedPool, sizeof(WV_PORT) * + pDevice->PortCount, 'cpvw'); + if (pDevice->pPorts == NULL) { + return STATUS_NO_MEMORY; + } + + WDF_IO_QUEUE_CONFIG_INIT(&config, WdfIoQueueDispatchManual); + for (i = 0; i < pDevice->PortCount; i++) { + pDevice->pPorts[i].Flags = 0; + status = WdfIoQueueCreate(ControlDevice, &config, WDF_NO_OBJECT_ATTRIBUTES, + &pDevice->pPorts[i].Queue); + if (!NT_SUCCESS(status)) { + goto err; + } + } + + return STATUS_SUCCESS; + +err: + while (i-- > 0) { + WdfObjectDelete(pDevice->pPorts[i].Queue); + } + pDevice->PortCount = 0; + return status; +} + +static NTSTATUS WvDeviceInit(WV_DEVICE *pDevice, NET64 Guid, + ci_umv_buf_t *pVerbsData) +{ + WV_RDMA_DEVICE *dev; + ib_api_status_t ib_status; + NTSTATUS status; + + dev = WvRdmaDeviceGet(Guid); + if (dev == NULL) { + return STATUS_NO_SUCH_DEVICE; + } + + pDevice->pDevice = dev; + pDevice->pVerbs = &dev->Interface.Verbs; + + ib_status = pDevice->pVerbs->um_open_ca(dev->hDevice, pVerbsData, + &pDevice->hVerbsDevice); + if (ib_status != IB_SUCCESS) { + goto err1; + } + + status = WvDeviceCreatePorts(pDevice); + if (!NT_SUCCESS(status)) { + goto err2; + } + + pDevice->pVerbs->register_event_handler(dev->hDevice, &pDevice->EventHandler); + return STATUS_SUCCESS; + +err2: + pDevice->pVerbs->um_close_ca(dev->hDevice, pDevice->hVerbsDevice); +err1: + WvRdmaDevicePut(dev); + pDevice->hVerbsDevice = NULL; + return STATUS_UNSUCCESSFUL; +} + +void WvDeviceOpen(WV_PROVIDER *pProvider, WDFREQUEST Request) +{ + WV_IO_ID *inid, *outid; + size_t inlen, outlen; + WV_DEVICE *dev; + NTSTATUS status; + ci_umv_buf_t verbsData; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_ID), &inid, &inlen); + if (!NT_SUCCESS(status)) { + goto err1; + } + status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_ID), &outid, &outlen); + if (!NT_SUCCESS(status)) { + goto err1; + } + + dev = WvDeviceAlloc(pProvider); + if (dev == NULL) { + status = STATUS_NO_MEMORY; + goto err1; + } + + KeAcquireGuardedMutex(&pProvider->Lock); + WvProviderDisableRemove(pProvider); + KeReleaseGuardedMutex(&pProvider->Lock); + + WvInitVerbsData(&verbsData, inid->VerbInfo, inlen - sizeof(WV_IO_ID), + outlen - sizeof(WV_IO_ID), inid + 1); + status = WvDeviceInit(dev, inid->Id, &verbsData); + if (!NT_SUCCESS(status)) { + goto err2; + } + + KeAcquireGuardedMutex(&pProvider->Lock); + outid->Id = IndexListInsertHead(&pProvider->DevIndex, dev); + if (outid->Id == 0) { + status = STATUS_NO_MEMORY; + goto err2; + } + KeReleaseGuardedMutex(&pProvider->Lock); + + WvProviderEnableRemove(pProvider); + outid->VerbInfo = verbsData.status; + WdfRequestCompleteWithInformation(Request, status, outlen); + return; + +err2: + WvDeviceFree(dev); + WvProviderEnableRemove(pProvider); +err1: + WdfRequestComplete(Request, status); +} + +void WvDeviceClose(WV_PROVIDER *pProvider, WDFREQUEST Request) +{ + WV_DEVICE *dev; + UINT64 *id; + NTSTATUS status; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL); + if (!NT_SUCCESS(status)) { + goto out; + } + + KeAcquireGuardedMutex(&pProvider->Lock); + WvProviderDisableRemove(pProvider); + dev = IndexListAt(&pProvider->DevIndex, (SIZE_T) *id); + if (dev == NULL) { + status = STATUS_NO_SUCH_DEVICE; + } else if (dev->Ref > 1) { + status = STATUS_ACCESS_DENIED; + } else { + IndexListRemove(&pProvider->DevIndex, (SIZE_T) *id); + status = STATUS_SUCCESS; + } + KeReleaseGuardedMutex(&pProvider->Lock); + + if (NT_SUCCESS(status)) { + WvDeviceFree(dev); + } + WvProviderEnableRemove(pProvider); +out: + WdfRequestComplete(Request, status); +} + +static void WvDeviceFreePorts(WV_DEVICE *pDevice) +{ + UINT8 i; + + for (i = 0; i < pDevice->PortCount; i++) { + WdfIoQueuePurgeSynchronously(pDevice->pPorts[i].Queue); + WdfObjectDelete(pDevice->pPorts[i].Queue); + } + if (pDevice->pPorts != NULL) { + ExFreePoolWithTag(pDevice->pPorts, 'cpvw'); + } +} + +void WvDeviceFree(WV_DEVICE *pDevice) +{ + if (InterlockedDecrement(&pDevice->Ref) > 0) { + KeWaitForSingleObject(&pDevice->Event, Executive, KernelMode, FALSE, NULL); + } + + if (pDevice->hVerbsDevice != NULL) { + pDevice->pVerbs->unregister_event_handler(pDevice->pDevice->hDevice, + &pDevice->EventHandler); + pDevice->pVerbs->um_close_ca(pDevice->pDevice->hDevice, + pDevice->hVerbsDevice); + WvRdmaDevicePut(pDevice->pDevice); + } + + WvDeviceFreePorts(pDevice); + WvProviderPut(pDevice->pProvider); + ExFreePoolWithTag(pDevice, 'cdvw'); +} + +void WvDeviceRemoveHandler(WV_DEVICE *pDevice) +{ + LIST_ENTRY *entry; + WV_PROTECTION_DOMAIN *pd; + WV_COMPLETION_QUEUE *cq; + + for (entry = pDevice->PdList.Flink; entry != &pDevice->PdList; + entry = entry->Flink) { + pd = CONTAINING_RECORD(entry, WV_PROTECTION_DOMAIN, Entry); + WvPdRemoveHandler(pd); + } + + for (entry = pDevice->CqList.Flink; entry != &pDevice->CqList; + entry = entry->Flink) { + cq = CONTAINING_RECORD(entry, WV_COMPLETION_QUEUE, Entry); + pDevice->pVerbs->destroy_cq(cq->hVerbsCq); + cq->hVerbsCq = NULL; + cq->pVerbs = NULL; + } + + pDevice->pVerbs->um_close_ca(pDevice->pDevice->hDevice, + pDevice->hVerbsDevice); + WvRdmaDevicePut(pDevice->pDevice); + pDevice->pDevice = NULL; + pDevice->pVerbs = NULL; + pDevice->hVerbsDevice = NULL; +} + +static void WvSetDeviceCap(UINT32 *pFlags, ib_ca_attr_t *pCaAttr) +{ + *pFlags = 0; + + *pFlags |= pCaAttr->bad_pkey_ctr_support ? WV_IO_BAD_PKEY_COUNTER : 0; + *pFlags |= pCaAttr->bad_qkey_ctr_support ? WV_IO_BAD_QKEY_COUNTER : 0; + *pFlags |= pCaAttr->apm_support ? WV_IO_PATH_MIGRATION : 0; + *pFlags |= pCaAttr->av_port_check ? WV_IO_AH_PORT_CHECKING : 0; + *pFlags |= pCaAttr->change_primary_port ? WV_IO_CHANGE_PHYSICAL_PORT : 0; + *pFlags |= pCaAttr->modify_wr_depth ? WV_IO_RESIZE_MAX_WR : 0; + *pFlags |= pCaAttr->modify_srq_depth ? WV_IO_SRQ_RESIZE : 0; + *pFlags |= pCaAttr->current_qp_state_support ? WV_IO_QP_STATE_MODIFIER : 0; + *pFlags |= pCaAttr->shutdown_port_capability ? WV_IO_SHUTDOWN_PORT : 0; + *pFlags |= pCaAttr->init_type_support ? WV_IO_INIT_TYPE : 0; + *pFlags |= pCaAttr->port_active_event_support ? WV_IO_PORT_ACTIVE_EVENT : 0; + *pFlags |= pCaAttr->system_image_guid_support ? WV_IO_SYSTEM_IMAGE_GUID : 0; + *pFlags |= WV_IO_RC_RNR_NAK_GENERATION; + *pFlags |= WV_IO_BATCH_NOTIFY_CQ; +} + +static void WvSetDevicePages(UINT32 *pFlags, ib_ca_attr_t *pCaAttr) +{ + unsigned int i; + UINT32 size; + + *pFlags = 0; + + for (i = 0; i < pCaAttr->num_page_sizes; i++) { + size = pCaAttr->p_page_size[i]; + *pFlags |= (size & (size - 1)) ? 0 : size; + } +} + +static void WvConvertDevAttr(WV_IO_DEVICE_ATTRIBUTES* pAttributes, + ib_ca_attr_t *pCaAttr) +{ + pAttributes->FwVersion = pCaAttr->fw_ver; + pAttributes->NodeGuid = pCaAttr->ca_guid; + pAttributes->SystemImageGuid = pCaAttr->system_image_guid; + pAttributes->VendorId = pCaAttr->vend_id; + pAttributes->VendorPartId = pCaAttr->dev_id; + pAttributes->HwVersion = pCaAttr->revision; + + WvSetDeviceCap(&pAttributes->CapabilityFlags, pCaAttr); + pAttributes->AtomicCapability = (UINT32) pCaAttr->atomicity; + WvSetDevicePages(&pAttributes->PageSizeCapabilityFlags, pCaAttr); + + pAttributes->MaxMrSize = pCaAttr->init_region_size; + pAttributes->MaxQp = pCaAttr->max_qps; + pAttributes->MaxQpWr = pCaAttr->max_wrs; + pAttributes->MaxSge = pCaAttr->max_sges; + pAttributes->MaxCq = pCaAttr->max_cqs; + pAttributes->MaxCqEntries = pCaAttr->max_cqes; + pAttributes->MaxMr = pCaAttr->init_regions; + pAttributes->MaxPd = pCaAttr->max_pds; + pAttributes->MaxQpResponderResources = pCaAttr->max_qp_resp_res; + pAttributes->MaxResponderResources = pCaAttr->max_resp_res; + pAttributes->MaxQpInitiatorDepth = pCaAttr->max_qp_init_depth; + pAttributes->MaxMw = pCaAttr->init_windows; + pAttributes->MaxMulticast = pCaAttr->max_mcast_grps; + pAttributes->MaxQpAttach = pCaAttr->max_qps_per_mcast_grp; + pAttributes->MaxMulticastQp = pCaAttr->max_mcast_qps; + pAttributes->MaxAh = (UINT32) pCaAttr->max_addr_handles; + pAttributes->MaxFmr = pCaAttr->max_fmr; + pAttributes->MaxMapPerFmr = pCaAttr->max_map_per_fmr; + pAttributes->MaxSrq = pCaAttr->max_srq; + pAttributes->MaxSrqWr = pCaAttr->max_srq_wrs; + pAttributes->MaxSrqSge = pCaAttr->max_srq_sges; + pAttributes->MaxPkeys = pCaAttr->max_partitions; + pAttributes->DeviceType = WV_DEVICE_INFINIBAND; // TODO: missing in ib_ca_attr_t + pAttributes->LocalAckDelay = pCaAttr->local_ack_delay; + pAttributes->PhysPortCount = pCaAttr->num_ports; +} + +static void WvConvertPortCap(UINT32 *pFlags, ib_port_cap_t *pCap) +{ + *pFlags = 0; + + *pFlags |= pCap->qkey_ctr ? WV_IO_BAD_QKEY_COUNTER : 0; + *pFlags |= pCap->pkey_ctr ? WV_IO_BAD_PKEY_COUNTER : 0; + *pFlags |= pCap->apm ? WV_IO_PATH_MIGRATION : 0; + *pFlags |= pCap->sysguid ? WV_IO_SYSTEM_IMAGE_GUID : 0; + *pFlags |= pCap->port_active ? WV_IO_PORT_ACTIVE_EVENT : 0; + + // TODO: missing in ib_port_attr_t: + // WV_IO_RESIZE_MAX_WR + // WV_IO_CHANGE_PHYSICAL_PORT + // WV_IO_AH_PORT_CHECKING + *pFlags |= WV_IO_QP_STATE_MODIFIER; + // WV_IO_SHUTDOWN_PORT + // WV_IO_INIT_TYPE + *pFlags |= WV_IO_RC_RNR_NAK_GENERATION; + // WV_IO_SRQ_RESIZE + *pFlags |= WV_IO_BATCH_NOTIFY_CQ; +} + +static void WvConvertPortAttr(WV_IO_PORT_ATTRIBUTES *pAttributes, + ib_port_attr_t *pPortAttr) +{ + WvConvertPortCap(&pAttributes->PortCabilityFlags, &pPortAttr->cap); + pAttributes->State = pPortAttr->link_state; + pAttributes->MaxMtu = 0x80 << pPortAttr->mtu; + pAttributes->ActiveMtu = 0x80 << pPortAttr->mtu; + pAttributes->GidTableLength = pPortAttr->num_gids; + pAttributes->MaxMessageSize = (UINT32) pPortAttr->max_msg_size; + pAttributes->BadPkeyCounter = pPortAttr->pkey_ctr; + pAttributes->QkeyViolationCounter = pPortAttr->qkey_ctr; + pAttributes->PkeyTableLength = pPortAttr->num_pkeys; + pAttributes->Lid = pPortAttr->lid; + pAttributes->SmLid = pPortAttr->sm_lid; + pAttributes->Lmc = pPortAttr->lmc; + pAttributes->MaxVls = (UINT8) pPortAttr->max_vls; + pAttributes->SmSl = pPortAttr->sm_sl; + pAttributes->SubnetTimeout = pPortAttr->subnet_timeout; + pAttributes->InitTypeReply = pPortAttr->init_type_reply; + pAttributes->ActiveWidth = pPortAttr->active_width; + pAttributes->ActiveSpeed = pPortAttr->active_speed; + pAttributes->PhysicalState = pPortAttr->phys_state; + pAttributes->Reserved[0] = 0; + pAttributes->Reserved[1] = 0; +} + +void WvDeviceQuery(WV_PROVIDER *pProvider, WDFREQUEST Request) +{ + UINT64 *id; + WV_IO_DEVICE_ATTRIBUTES *attr; + WV_DEVICE *dev; + ib_ca_attr_t *ca_attr; + NTSTATUS status; + UINT32 outlen = 0; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL); + if (!NT_SUCCESS(status)) { + goto complete; + } + status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_DEVICE_ATTRIBUTES), + &attr, NULL); + if (!NT_SUCCESS(status)) { + goto complete; + } + + dev = WvDeviceAcquire(pProvider, *id); + if (dev == NULL) { + status = STATUS_NO_SUCH_DEVICE; + goto complete; + } + + ca_attr = WvQueryCaAttributes(dev); + WvDeviceRelease(dev); + + if (ca_attr == NULL) { + status = STATUS_NO_MEMORY; + goto complete; + } + + WvConvertDevAttr(attr, ca_attr); + outlen = sizeof(WV_IO_DEVICE_ATTRIBUTES); + ExFreePoolWithTag(ca_attr, 'acvw'); + +complete: + WdfRequestCompleteWithInformation(Request, status, outlen); +} + +void WvDevicePortQuery(WV_PROVIDER *pProvider, WDFREQUEST Request) +{ + WV_IO_DEVICE_PORT_QUERY *query; + WV_IO_PORT_ATTRIBUTES *attr; + WV_DEVICE *dev; + ib_ca_attr_t *ca_attr; + NTSTATUS status; + UINT32 outlen = 0; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_DEVICE_PORT_QUERY), + &query, NULL); + if (!NT_SUCCESS(status)) { + goto complete; + } + status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_PORT_ATTRIBUTES), + &attr, NULL); + if (!NT_SUCCESS(status)) { + goto complete; + } + + dev = WvDeviceAcquire(pProvider, query->Id); + if (dev == NULL) { + status = STATUS_NO_SUCH_DEVICE; + goto complete; + } + + ca_attr = WvQueryCaAttributes(dev); + WvDeviceRelease(dev); + + if (ca_attr == NULL) { + status = STATUS_NO_MEMORY; + goto complete; + } + + if (--query->PortNumber >= ca_attr->num_ports) { + status = STATUS_INVALID_PORT_HANDLE; + goto free; + } + + WvConvertPortAttr(attr, &ca_attr->p_port_attr[query->PortNumber]); + outlen = sizeof(WV_IO_PORT_ATTRIBUTES); + +free: + ExFreePoolWithTag(ca_attr, 'acvw'); +complete: + WdfRequestCompleteWithInformation(Request, status, outlen); +} + +void WvDeviceGidQuery(WV_PROVIDER *pProvider, WDFREQUEST Request) +{ + WV_IO_DEVICE_PORT_QUERY *query; + WV_IO_GID *gid; + WV_DEVICE *dev; + ib_ca_attr_t *ca_attr; + ib_port_attr_t *port_attr; + NTSTATUS status; + size_t i, size, outlen = 0; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_DEVICE_PORT_QUERY), + &query, NULL); + if (!NT_SUCCESS(status)) { + goto complete; + } + status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_GID), &gid, &size); + if (!NT_SUCCESS(status)) { + goto complete; + } + + dev = WvDeviceAcquire(pProvider, query->Id); + if (dev == NULL) { + status = STATUS_NO_SUCH_DEVICE; + goto complete; + } + + ca_attr = WvQueryCaAttributes(dev); + WvDeviceRelease(dev); + + if (ca_attr == NULL) { + status = STATUS_NO_MEMORY; + goto complete; + } + + if (--query->PortNumber >= ca_attr->num_ports) { + status = STATUS_INVALID_PORT_HANDLE; + goto free; + } + + size /= sizeof(WV_IO_GID); + port_attr = &ca_attr->p_port_attr[query->PortNumber]; + for (i = 0; i < size && i < port_attr->num_gids; i++) { + RtlCopyMemory(&gid[i], &port_attr->p_gid_table[i], sizeof(WV_IO_GID)); + } + + outlen = i * sizeof(WV_IO_GID); + if (i < port_attr->num_gids) { + status = STATUS_MORE_ENTRIES; + } + +free: + ExFreePoolWithTag(ca_attr, 'acvw'); +complete: + WdfRequestCompleteWithInformation(Request, status, outlen); +} + +void WvDevicePkeyQuery(WV_PROVIDER *pProvider, WDFREQUEST Request) +{ + WV_IO_DEVICE_PORT_QUERY *query; + NET16 *pkey; + WV_DEVICE *dev; + ib_ca_attr_t *ca_attr; + ib_port_attr_t *port_attr; + NTSTATUS status; + size_t i, size, outlen = 0; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_DEVICE_PORT_QUERY), + &query, NULL); + if (!NT_SUCCESS(status)) { + goto complete; + } + status = WdfRequestRetrieveOutputBuffer(Request, sizeof(NET16), &pkey, &size); + if (!NT_SUCCESS(status)) { + goto complete; + } + + dev = WvDeviceAcquire(pProvider, query->Id); + if (dev == NULL) { + status = STATUS_NO_SUCH_DEVICE; + goto complete; + } + + ca_attr = WvQueryCaAttributes(dev); + WvDeviceRelease(dev); + + if (ca_attr == NULL) { + status = STATUS_NO_MEMORY; + goto complete; + } + + if (--query->PortNumber >= ca_attr->num_ports) { + status = STATUS_INVALID_PORT_HANDLE; + goto free; + } + + size /= sizeof(NET16); + port_attr = &ca_attr->p_port_attr[query->PortNumber]; + for (i = 0; i < size && i < port_attr->num_pkeys; i++) { + pkey[i] = port_attr->p_pkey_table[i]; + } + + outlen = i * sizeof(NET16); + if (i < port_attr->num_pkeys) { + status = STATUS_MORE_ENTRIES; + } + +free: + ExFreePoolWithTag(ca_attr, 'acvw'); +complete: + WdfRequestCompleteWithInformation(Request, status, outlen); +} + +void WvDeviceNotify(WV_PROVIDER *pProvider, WDFREQUEST Request) +{ + WV_IO_ID *id; + WV_DEVICE *dev; + WV_PORT *port; + NTSTATUS status; + UINT32 *flags; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_ID), &id, NULL); + if (!NT_SUCCESS(status)) { + goto complete; + } + + status = WdfRequestRetrieveOutputBuffer(Request, sizeof(UINT32), &flags, NULL); + if (!NT_SUCCESS(status)) { + goto complete; + } + + dev = WvDeviceAcquire(pProvider, id->Id); + if (dev == NULL) { + status = STATUS_NOT_FOUND; + goto complete; + } + + if (--id->Data >= dev->PortCount) { + status = STATUS_INVALID_PORT_HANDLE; + goto release; + } + + port = &dev->pPorts[id->Data]; + WdfObjectAcquireLock(port->Queue); + + if (port->Flags == 0) { + status = WdfRequestForwardToIoQueue(Request, port->Queue); + } else { + *flags = port->Flags; + WdfRequestCompleteWithInformation(Request, STATUS_SUCCESS, sizeof(UINT32)); + port->Flags = 0; + } + + WdfObjectReleaseLock(port->Queue); +release: + WvDeviceRelease(dev); +complete: + if (!NT_SUCCESS(status)) { + WdfRequestComplete(Request, status); + } +} + +void WvDeviceCancel(WV_PROVIDER *pProvider, WDFREQUEST Request) +{ + UINT64 *id; + WV_DEVICE *dev; + NTSTATUS status; + UINT8 i; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL); + if (!NT_SUCCESS(status)) { + goto out; + } + + dev = WvDeviceAcquire(pProvider, *id); + if (dev == NULL) { + status = STATUS_NOT_FOUND; + goto out; + } + + for (i = 0; i < dev->PortCount; i++) { + WvDeviceCompleteRequests(&dev->pPorts[i], STATUS_CANCELLED, 0); + } + WvDeviceRelease(dev); + +out: + WdfRequestComplete(Request, status); +} diff --git a/branches/WOF2-3/core/winverbs/kernel/wv_device.h b/branches/WOF2-3/core/winverbs/kernel/wv_device.h new file mode 100644 index 00000000..1bbc5fef --- /dev/null +++ b/branches/WOF2-3/core/winverbs/kernel/wv_device.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#ifndef _WV_DEVICE_H_ +#define _WV_DEVICE_H_ + +#include +#include +#include +#include + +#include "wv_driver.h" +#include "wv_provider.h" + +typedef struct _WV_PORT +{ + WDFQUEUE Queue; + UINT32 Flags; + +} WV_PORT; + +typedef struct _WV_DEVICE +{ + WV_PROVIDER *pProvider; + WV_RDMA_DEVICE *pDevice; + ci_interface_t *pVerbs; + LIST_ENTRY Entry; + ib_ca_handle_t hVerbsDevice; + ci_event_handler_t EventHandler; + + LIST_ENTRY PdList; + LIST_ENTRY CqList; + + KEVENT Event; + LONG Ref; + WV_PORT *pPorts; + UINT8 PortCount; + +} WV_DEVICE; + +struct _WV_DEVICE *WvDeviceAcquire(WV_PROVIDER *pProvider, UINT64 Id); +void WvDeviceRelease(WV_DEVICE *pDevice); +void WvDeviceGet(WV_DEVICE *pDevice); +void WvDevicePut(WV_DEVICE *pDevice); + +void WvDeviceOpen(WV_PROVIDER *pProvider, WDFREQUEST Request); +void WvDeviceClose(WV_PROVIDER *pProvider, WDFREQUEST Request); +void WvDeviceFree(WV_DEVICE *pDevice); +void WvDeviceRemoveHandler(WV_DEVICE *pDevice); + +void WvDeviceQuery(WV_PROVIDER *pProvider, WDFREQUEST Request); +void WvDevicePortQuery(WV_PROVIDER *pProvider, WDFREQUEST Request); +void WvDeviceGidQuery(WV_PROVIDER *pProvider, WDFREQUEST Request); +void WvDevicePkeyQuery(WV_PROVIDER *pProvider, WDFREQUEST Request); + +void WvDeviceNotify(WV_PROVIDER *pProvider, WDFREQUEST Request); +void WvDeviceCancel(WV_PROVIDER *pProvider, WDFREQUEST Request); + +#endif // __WV_DEVICE_H_ diff --git a/branches/WOF2-3/core/winverbs/kernel/wv_driver.c b/branches/WOF2-3/core/winverbs/kernel/wv_driver.c new file mode 100644 index 00000000..d5321602 --- /dev/null +++ b/branches/WOF2-3/core/winverbs/kernel/wv_driver.c @@ -0,0 +1,593 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#include "index_list.c" +#include +#include "wv_driver.h" +#include "wv_ioctl.h" +#include "wv_provider.h" +#include "wv_device.h" +#include "wv_pd.h" +#include "wv_srq.h" +#include "wv_cq.h" +#include "wv_srq.h" +#include "wv_qp.h" +#include "wv_ep.h" + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(WV_RDMA_DEVICE, WvRdmaDeviceGetContext) + +WDFDEVICE ControlDevice; +static LIST_ENTRY DevList; +static LIST_ENTRY ProvList; +static KGUARDED_MUTEX Lock; +ULONG RandomSeed; + +INFINIBAND_INTERFACE_CM IbCmInterface; + +static EVT_WDF_DRIVER_DEVICE_ADD WvRdmaDeviceAdd; +static EVT_WDF_OBJECT_CONTEXT_CLEANUP WvRdmaDeviceCleanup; +static EVT_WDF_DEVICE_D0_ENTRY WvPowerD0Entry; +static EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL WvIoDeviceControl; +static EVT_WDF_DEVICE_FILE_CREATE WvFileCreate; +static EVT_WDF_FILE_CLEANUP WvFileCleanup; +static EVT_WDF_FILE_CLOSE WvFileClose; + +WV_RDMA_DEVICE *WvRdmaDeviceGet(NET64 Guid) +{ + WV_RDMA_DEVICE *cur_dev, *dev = NULL; + LIST_ENTRY *entry; + + KeAcquireGuardedMutex(&Lock); + for (entry = DevList.Flink; entry != &DevList; entry = entry->Flink) { + cur_dev = CONTAINING_RECORD(entry, WV_RDMA_DEVICE, Entry); + if (cur_dev->Interface.Verbs.guid == Guid) { + InterlockedIncrement(&cur_dev->Ref); + dev = cur_dev; + break; + } + } + KeReleaseGuardedMutex(&Lock); + return dev; +} + +void WvRdmaDevicePut(WV_RDMA_DEVICE *pDevice) +{ + if (InterlockedDecrement(&pDevice->Ref) == 0) { + KeSetEvent(&pDevice->Event, 0, FALSE); + } +} + + +void WvCompleteRequests(WDFQUEUE Queue, NTSTATUS ReqStatus) +{ + WDFREQUEST request; + NTSTATUS status; + + status = WdfIoQueueRetrieveNextRequest(Queue, &request); + + while (NT_SUCCESS(status)) { + WdfRequestComplete(request, ReqStatus); + status = WdfIoQueueRetrieveNextRequest(Queue, &request); + } +} + +void WvFlushQueue(WDFQUEUE Queue, NTSTATUS ReqStatus) +{ + WdfObjectAcquireLock(Queue); + WvCompleteRequests(Queue, ReqStatus); + WdfObjectReleaseLock(Queue); +} + +void WvCompleteRequestsWithInformation(WDFQUEUE Queue, NTSTATUS ReqStatus) +{ + WDFREQUEST request; + NTSTATUS status; + UINT8 *out; + size_t outlen; + + status = WdfIoQueueRetrieveNextRequest(Queue, &request); + + while (NT_SUCCESS(status)) { + outlen = 0; + WdfRequestRetrieveOutputBuffer(request, 0, &out, &outlen); + WdfRequestCompleteWithInformation(request, ReqStatus, outlen); + status = WdfIoQueueRetrieveNextRequest(Queue, &request); + } +} + +static void WvGuidQuery(WDFREQUEST Request) +{ + WV_IO_GUID_LIST *list; + size_t len = 0; + WV_RDMA_DEVICE *dev; + ULONG count, i; + LIST_ENTRY *entry; + NTSTATUS status; + + status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_GUID_LIST), + &list, &len); + if (!NT_SUCCESS(status)) { + goto out; + } + + count = (ULONG) ((len - sizeof(NET64)) / sizeof(NET64)); + i = 0; + len = sizeof(NET64); + KeAcquireGuardedMutex(&Lock); + for (entry = DevList.Flink; entry != &DevList; entry = entry->Flink) { + dev = CONTAINING_RECORD(entry, WV_RDMA_DEVICE, Entry); + if (i < count) { + list->Guid[i] = dev->Interface.Verbs.guid; + len += sizeof(NET64); + } + i++; + } + list->Count = i; + KeReleaseGuardedMutex(&Lock); + +out: + WdfRequestCompleteWithInformation(Request, status, len); +} + +static void WvLibraryQuery(WDFREQUEST Request) +{ + NET64 *guid; + char *name; + size_t len = 0, bytes; + WV_RDMA_DEVICE *dev; + NTSTATUS status; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(NET64), &guid, NULL); + if (!NT_SUCCESS(status)) { + goto out; + } + status = WdfRequestRetrieveOutputBuffer(Request, 1, &name, &bytes); + if (!NT_SUCCESS(status)) { + goto out; + } + + dev = WvRdmaDeviceGet(*guid); + if (dev == NULL) { + status = STATUS_NO_SUCH_DEVICE; + goto out; + } + + len = strlen(dev->Interface.Verbs.libname) + 1; + if (bytes >= len) { + RtlCopyMemory(name, dev->Interface.Verbs.libname, len); + } else { + status = STATUS_BUFFER_TOO_SMALL; + *name = (char) len; + len = 1; + } + WvRdmaDevicePut(dev); + +out: + WdfRequestCompleteWithInformation(Request, status, len); +} + +static VOID WvIoDeviceControl(WDFQUEUE Queue, WDFREQUEST Request, + size_t OutLen, size_t InLen, ULONG IoControlCode) +{ + WDFFILEOBJECT file; + WV_PROVIDER *prov; + UNREFERENCED_PARAMETER(OutLen); + UNREFERENCED_PARAMETER(InLen); + UNREFERENCED_PARAMETER(Queue); + + file = WdfRequestGetFileObject(Request); + prov = WvProviderGetContext(file); + + // TODO: verify this compiles as a jump table, or use function pointers + switch (IoControlCode) { + case WV_IOCTL_GUID_QUERY: + WvGuidQuery(Request); + break; + case WV_IOCTL_LIBRARY_QUERY: + WvLibraryQuery(Request); + break; + case WV_IOCTL_DEVICE_OPEN: + WvDeviceOpen(prov, Request); + break; + case WV_IOCTL_DEVICE_CLOSE: + WvDeviceClose(prov, Request); + break; + case WV_IOCTL_DEVICE_QUERY: + WvDeviceQuery(prov, Request); + break; + case WV_IOCTL_DEVICE_PORT_QUERY: + WvDevicePortQuery(prov, Request); + break; + case WV_IOCTL_DEVICE_GID_QUERY: + WvDeviceGidQuery(prov, Request); + break; + case WV_IOCTL_DEVICE_PKEY_QUERY: + WvDevicePkeyQuery(prov, Request); + break; + case WV_IOCTL_DEVICE_NOTIFY: + WvDeviceNotify(prov, Request); + break; + case WV_IOCTL_DEVICE_CANCEL: + WvDeviceCancel(prov, Request); + break; + case WV_IOCTL_PD_ALLOCATE: + WvPdAllocate(prov, Request); + break; + case WV_IOCTL_PD_CANCEL: + WvPdCancel(prov, Request); + break; + case WV_IOCTL_PD_DEALLOCATE: + WvPdDeallocate(prov, Request); + break; + case WV_IOCTL_MEMORY_REGISTER: + WvMrRegister(prov, Request); + break; + case WV_IOCTL_MEMORY_DEREGISTER: + WvMrDeregister(prov, Request); + break; + case WV_IOCTL_MW_ALLOCATE: + WvMwAllocate(prov, Request); + break; + case WV_IOCTL_MW_DEALLOCATE: + WvMwDeallocate(prov, Request); + break; + case WV_IOCTL_AH_CREATE: + WvAhCreate(prov, Request); + break; + case WV_IOCTL_AH_DESTROY: + WvAhDestroy(prov, Request); + break; + case WV_IOCTL_CQ_CREATE: + WvCqCreate(prov, Request); + break; + case WV_IOCTL_CQ_DESTROY: + WvCqDestroy(prov, Request); + break; + case WV_IOCTL_CQ_RESIZE: + WvCqResize(prov, Request); + break; + case WV_IOCTL_CQ_NOTIFY: + WvCqNotify(prov, Request); + break; + case WV_IOCTL_CQ_CANCEL: + WvCqCancel(prov, Request); + break; + case WV_IOCTL_SRQ_CREATE: + WvSrqCreate(prov, Request); + break; + case WV_IOCTL_SRQ_DESTROY: + WvSrqDestroy(prov, Request); + break; + case WV_IOCTL_SRQ_QUERY: + WvSrqQuery(prov, Request); + break; + case WV_IOCTL_SRQ_MODIFY: + WvSrqModify(prov, Request); + break; + case WV_IOCTL_SRQ_NOTIFY: + WvSrqNotify(prov, Request); + break; + case WV_IOCTL_SRQ_CANCEL: + WvSrqCancel(prov, Request); + break; + case WV_IOCTL_QP_CREATE: + WvQpCreate(prov, Request); + break; + case WV_IOCTL_QP_DESTROY: + WvQpDestroy(prov, Request); + break; + case WV_IOCTL_QP_QUERY: + WvQpQuery(prov, Request); + break; + case WV_IOCTL_QP_MODIFY: + WvQpModify(prov, Request); + break; + case WV_IOCTL_QP_ATTACH: + WvQpAttach(prov, Request); + break; + case WV_IOCTL_QP_DETACH: + WvQpDetach(prov, Request); + break; + case WV_IOCTL_QP_CANCEL: + WvQpCancel(prov, Request); + break; + case WV_IOCTL_EP_CREATE: + WvEpCreate(prov, Request); + break; + case WV_IOCTL_EP_DESTROY: + WvEpDestroy(prov, Request); + break; + case WV_IOCTL_EP_MODIFY: + WvEpModify(prov, Request); + break; + case WV_IOCTL_EP_BIND: + WvEpBind(prov, Request); + break; + case WV_IOCTL_EP_REJECT: + WvEpReject(prov, Request); + break; + case WV_IOCTL_EP_CONNECT: + WvEpConnect(prov, Request); + break; + case WV_IOCTL_EP_ACCEPT: + WvEpAccept(prov, Request); + break; + case WV_IOCTL_EP_DISCONNECT: + WvEpDisconnect(prov, Request); + break; + case WV_IOCTL_EP_DISCONNECT_NOTIFY: + WvEpDisconnectNotify(prov, Request); + break; + case WV_IOCTL_EP_QUERY: + WvEpQuery(prov, Request); + break; + case WV_IOCTL_EP_LOOKUP: + WvEpLookup(prov, Request); + break; + case WV_IOCTL_EP_MULTICAST_JOIN: + WvEpMulticastJoin(prov, Request); + break; + case WV_IOCTL_EP_MULTICAST_LEAVE: + WvEpMulticastLeave(prov, Request); + break; + case WV_IOCTL_EP_CANCEL: + WvEpCancel(prov, Request); + break; + case WV_IOCTL_EP_LISTEN: + WvEpListen(prov, Request); + break; + case WV_IOCTL_EP_GET_REQUEST: + WvEpGetRequest(prov, Request); + break; + default: + WdfRequestComplete(Request, STATUS_PROCEDURE_NOT_FOUND); + break; + } +} + +static VOID WvFileCreate(WDFDEVICE Device, WDFREQUEST Request, + WDFFILEOBJECT FileObject) +{ + WV_PROVIDER *prov = WvProviderGetContext(FileObject); + NTSTATUS status; + + status = WvProviderInit(Device, prov); + if (NT_SUCCESS(status)) { + KeAcquireGuardedMutex(&Lock); + InsertHeadList(&ProvList, &prov->Entry); + KeReleaseGuardedMutex(&Lock); + } + WdfRequestComplete(Request, STATUS_SUCCESS); +} + +static VOID WvFileCleanup(WDFFILEOBJECT FileObject) +{ + WV_PROVIDER *prov = WvProviderGetContext(FileObject); + + KeAcquireGuardedMutex(&Lock); + RemoveEntryList(&prov->Entry); + KeReleaseGuardedMutex(&Lock); + WvProviderCleanup(prov); +} + +static VOID WvFileClose(WDFFILEOBJECT FileObject) +{ + UNREFERENCED_PARAMETER(FileObject); +} + +static VOID WvCreateControlDevice(WDFDRIVER Driver) +{ + PWDFDEVICE_INIT pinit; + WDF_FILEOBJECT_CONFIG fileconfig; + WDF_OBJECT_ATTRIBUTES attr; + WDF_IO_QUEUE_CONFIG ioconfig; + NTSTATUS status; + WDFQUEUE queue; + DECLARE_CONST_UNICODE_STRING(name, L"\\Device\\WinVerbs"); + DECLARE_CONST_UNICODE_STRING(symlink, L"\\DosDevices\\WinVerbs"); + + pinit = WdfControlDeviceInitAllocate(Driver, + &SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_RW_RES_R); + if (pinit == NULL) { + return; + } + + WdfDeviceInitSetExclusive(pinit, FALSE); + status = WdfDeviceInitAssignName(pinit, &name); + if (!NT_SUCCESS(status)) { + goto err1; + } + + WDF_FILEOBJECT_CONFIG_INIT(&fileconfig, WvFileCreate, WvFileClose, + WvFileCleanup); + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attr, WV_PROVIDER); + WdfDeviceInitSetFileObjectConfig(pinit, &fileconfig, &attr); + + WDF_OBJECT_ATTRIBUTES_INIT(&attr); + status = WdfDeviceCreate(&pinit, &attr, &ControlDevice); + if (!NT_SUCCESS(status)) { + goto err1; + } + + status = WdfDeviceCreateSymbolicLink(ControlDevice, &symlink); + if (!NT_SUCCESS(status)) { + goto err2; + } + + WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&ioconfig, WdfIoQueueDispatchParallel); + ioconfig.EvtIoDeviceControl = WvIoDeviceControl; + status = WdfIoQueueCreate(ControlDevice, &ioconfig, + WDF_NO_OBJECT_ATTRIBUTES, &queue); + if (!NT_SUCCESS(status)) { + goto err2; + } + + WdfControlFinishInitializing(ControlDevice); + return; + +err2: + WdfObjectDelete(ControlDevice); + return; +err1: + WdfDeviceInitFree(pinit); +} + +static NTSTATUS WvPowerD0Entry(WDFDEVICE Device, WDF_POWER_DEVICE_STATE PreviousState) +{ + WV_RDMA_DEVICE *dev; + BOOLEAN create; + NTSTATUS status; + + dev = WvRdmaDeviceGetContext(Device); + if (dev->hDevice != NULL) { + return STATUS_SUCCESS; + } + + status = WdfFdoQueryForInterface(Device, &GUID_RDMA_INTERFACE_VERBS, + (PINTERFACE) &dev->Interface, + sizeof(dev->Interface), VerbsVersion(2, 0), + NULL); + if (!NT_SUCCESS(status)) { + return status; + } + dev->hDevice = dev->Interface.Verbs.p_hca_obj; + + KeAcquireGuardedMutex(&Lock); + create = IsListEmpty(&DevList); + InsertTailList(&DevList, &dev->Entry); + KeReleaseGuardedMutex(&Lock); + + if (create) { + WvCreateControlDevice(WdfGetDriver()); + status = WdfFdoQueryForInterface(Device, &GUID_INFINIBAND_INTERFACE_CM, + (PINTERFACE) &IbCmInterface, + sizeof(IbCmInterface), + IbaCmVersion(1, 0), NULL); + } + + return status; +} + +static NTSTATUS WvRdmaDeviceAdd(WDFDRIVER Driver, PWDFDEVICE_INIT DeviceInit) +{ + WDF_OBJECT_ATTRIBUTES attr; + WDF_PNPPOWER_EVENT_CALLBACKS power; + WDFDEVICE dev; + WV_RDMA_DEVICE *pdev; + NTSTATUS status; + + WdfFdoInitSetFilter(DeviceInit); + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attr, WV_RDMA_DEVICE); + attr.EvtCleanupCallback = WvRdmaDeviceCleanup; + + WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&power); + power.EvtDeviceD0Entry = WvPowerD0Entry; + WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &power); + + status = WdfDeviceCreate(&DeviceInit, &attr, &dev); + if (!NT_SUCCESS(status)) { + return status; + } + + pdev = WvRdmaDeviceGetContext(dev); + RtlZeroMemory(pdev, sizeof *pdev); + pdev->Ref = 1; + KeInitializeEvent(&pdev->Event, NotificationEvent, FALSE); + + return STATUS_SUCCESS; +} + +static VOID WvRdmaDeviceCleanup(WDFDEVICE Device) +{ + WV_RDMA_DEVICE *pdev; + WV_PROVIDER *prov; + LIST_ENTRY *entry; + BOOLEAN destroy; + WDFDEVICE ctrldev; + + pdev = WvRdmaDeviceGetContext(Device); + if (pdev->hDevice == NULL) { + return; + } + + KeAcquireGuardedMutex(&Lock); + RemoveEntryList(&pdev->Entry); + destroy = IsListEmpty(&DevList); + ctrldev = ControlDevice; + + for (entry = ProvList.Flink; entry != &ProvList; entry = entry->Flink) { + prov = CONTAINING_RECORD(entry, WV_PROVIDER, Entry); + WvProviderRemoveHandler(prov, pdev); + } + + KeReleaseGuardedMutex(&Lock); + + if (InterlockedDecrement(&pdev->Ref) > 0) { + KeWaitForSingleObject(&pdev->Event, Executive, KernelMode, FALSE, NULL); + } + + pdev->Interface.InterfaceHeader.InterfaceDereference(pdev->Interface. + InterfaceHeader.Context); + + if (destroy) { + if (IbCmInterface.CM.create_id != NULL) { + IbCmInterface.InterfaceHeader.InterfaceDereference(IbCmInterface. + InterfaceHeader.Context); + } + WdfObjectDelete(ctrldev); + } +} + +NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) +{ + WDF_DRIVER_CONFIG config; + NTSTATUS status; + WDFDRIVER driv; + + InitializeListHead(&DevList); + InitializeListHead(&ProvList); + KeInitializeGuardedMutex(&Lock); + RandomSeed = (ULONG) (ULONG_PTR) DriverObject; + + WDF_DRIVER_CONFIG_INIT(&config, WvRdmaDeviceAdd); + status = WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES, + &config, &driv); + if (!NT_SUCCESS(status)) { + return status; + } + + return STATUS_SUCCESS; +} diff --git a/branches/WOF2-3/core/winverbs/kernel/wv_driver.h b/branches/WOF2-3/core/winverbs/kernel/wv_driver.h new file mode 100644 index 00000000..a9e884e5 --- /dev/null +++ b/branches/WOF2-3/core/winverbs/kernel/wv_driver.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#ifndef _WV_DRIVER_H_ +#define _WV_DRIVER_H_ + +#include +#include +#include + +#include +#include +#include +#include +#include "wv_ioctl.h" + +#if WINVER <= _WIN32_WINNT_WINXP +#define KGUARDED_MUTEX FAST_MUTEX +#define KeInitializeGuardedMutex ExInitializeFastMutex +#define KeAcquireGuardedMutex ExAcquireFastMutex +#define KeReleaseGuardedMutex ExReleaseFastMutex +#endif + +extern WDFDEVICE ControlDevice; +extern INFINIBAND_INTERFACE_CM IbCmInterface; +extern ULONG RandomSeed; + +typedef struct _WV_RDMA_DEVICE +{ + LIST_ENTRY Entry; + LONG Ref; + KEVENT Event; + ib_ca_handle_t hDevice; + RDMA_INTERFACE_VERBS Interface; + +} WV_RDMA_DEVICE; + +WV_RDMA_DEVICE *WvRdmaDeviceGet(NET64 Guid); +void WvRdmaDevicePut(WV_RDMA_DEVICE *pDevice); + +static inline void WvInitVerbsData(ci_umv_buf_t *pVerbsData, UINT32 Command, + SIZE_T InputLength, SIZE_T OutputLength, + void *pBuffer) +{ + pVerbsData->command = Command; + pVerbsData->input_size = (UINT32) InputLength; + pVerbsData->output_size = (UINT32) OutputLength; + pVerbsData->p_inout_buf = (ULONG_PTR) pBuffer; + pVerbsData->status = 0; +} + +void WvCompleteRequests(WDFQUEUE Queue, NTSTATUS ReqStatus); +void WvFlushQueue(WDFQUEUE Queue, NTSTATUS ReqStatus); +void WvCompleteRequestsWithInformation(WDFQUEUE Queue, NTSTATUS ReqStatus); + +#endif // _WV_DRIVER_H_ diff --git a/branches/WOF2-3/core/winverbs/kernel/wv_ep.c b/branches/WOF2-3/core/winverbs/kernel/wv_ep.c new file mode 100644 index 00000000..f7394dc2 --- /dev/null +++ b/branches/WOF2-3/core/winverbs/kernel/wv_ep.c @@ -0,0 +1,1375 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include + +#include "wv_ep.h" +#include "wv_qp.h" +#include "wv_ioctl.h" +#include "wv_driver.h" + +#define WV_AF_INET 2 +#define WV_AF_INET6 23 + +static void WvEpWorkHandler(WORK_ENTRY *pWork); + +static void WvEpGet(WV_ENDPOINT *pEndpoint) +{ + InterlockedIncrement(&pEndpoint->Ref); +} + +static void WvEpPut(WV_ENDPOINT *pEndpoint) +{ + if (InterlockedDecrement(&pEndpoint->Ref) == 0) { + KeSetEvent(&pEndpoint->Event, 0, FALSE); + } +} + +WV_ENDPOINT *WvEpAcquire(WV_PROVIDER *pProvider, UINT64 Id) +{ + WV_ENDPOINT *ep; + + KeAcquireGuardedMutex(&pProvider->Lock); + WvProviderDisableRemove(pProvider); + ep = IndexListAt(&pProvider->EpIndex, (SIZE_T) Id); + if (ep != NULL && ep->State != WvEpDestroying) { + WvEpGet(ep); + } else { + ep = NULL; + WvProviderEnableRemove(pProvider); + } + KeReleaseGuardedMutex(&pProvider->Lock); + + return ep; +} + +void WvEpRelease(WV_ENDPOINT *pEndpoint) +{ + WvProviderEnableRemove(pEndpoint->pProvider); + WvEpPut(pEndpoint); +} + +static NTSTATUS WvEpAllocate(WV_PROVIDER *pProvider, UINT16 EpType, + WV_ENDPOINT **ppEndpoint) +{ + WV_ENDPOINT *ep; + NTSTATUS status; + WDF_IO_QUEUE_CONFIG config; + + ep = ExAllocatePoolWithTag(NonPagedPool, sizeof(WV_ENDPOINT), 'pevw'); + if (ep == NULL) { + return STATUS_NO_MEMORY; + } + + RtlZeroMemory(ep, sizeof(WV_ENDPOINT)); + ep->pWork = ExAllocatePoolWithTag(NonPagedPool, sizeof(WV_WORK_ENTRY), 'wevw'); + if (ep->pWork == NULL) { + status = STATUS_NO_MEMORY; + goto err1; + } + + ep->Ref = 1; + ep->pProvider = pProvider; + ep->EpType = EpType; + KeInitializeEvent(&ep->Event, NotificationEvent, FALSE); + InitializeListHead(&ep->Entry); + + WDF_IO_QUEUE_CONFIG_INIT(&config, WdfIoQueueDispatchManual); + status = WdfIoQueueCreate(ControlDevice, &config, + WDF_NO_OBJECT_ATTRIBUTES, &ep->Queue); + if (!NT_SUCCESS(status)) { + goto err2; + } + + *ppEndpoint = ep; + return STATUS_SUCCESS; + +err2: + ExFreePoolWithTag(ep->pWork, 'wevw'); +err1: + ExFreePoolWithTag(ep, 'pevw'); + return status; +} + +void WvEpCreate(WV_PROVIDER *pProvider, WDFREQUEST Request) +{ + UINT64 *pId; + UINT64 *type; + WV_ENDPOINT *ep; + NTSTATUS status; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &type, NULL); + if (!NT_SUCCESS(status)) { + goto err1; + } + status = WdfRequestRetrieveOutputBuffer(Request, sizeof(UINT64), &pId, NULL); + if (!NT_SUCCESS(status)) { + goto err1; + } + + status = WvEpAllocate(pProvider, (UINT16) *type, &ep); + if (!NT_SUCCESS(status)) { + goto err1; + } + + KeAcquireGuardedMutex(&pProvider->Lock); + *pId = IndexListInsertHead(&pProvider->EpIndex, ep); + if (*pId == 0) { + status = STATUS_NO_MEMORY; + goto err2; + } + KeReleaseGuardedMutex(&pProvider->Lock); + + WvWorkEntryInit(ep->pWork, *pId, WvEpWorkHandler, pProvider); + WdfRequestCompleteWithInformation(Request, status, sizeof(UINT64)); + return; + +err2: + KeReleaseGuardedMutex(&pProvider->Lock); + WvEpFree(ep); +err1: + WdfRequestComplete(Request, status); +} + +void WvEpDestroy(WV_PROVIDER *pProvider, WDFREQUEST Request) +{ + WV_ENDPOINT *ep; + UINT64 *id; + NTSTATUS status; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL); + if (!NT_SUCCESS(status)) { + goto out; + } + + KeAcquireGuardedMutex(&pProvider->Lock); + WvProviderDisableRemove(pProvider); + ep = IndexListAt(&pProvider->EpIndex, (SIZE_T) *id); + if (ep == NULL) { + status = STATUS_NOT_FOUND; + } else if (ep->Ref > 1) { + status = STATUS_ACCESS_DENIED; + } else { + IndexListRemove(&pProvider->EpIndex, (SIZE_T) *id); + status = STATUS_SUCCESS; + } + KeReleaseGuardedMutex(&pProvider->Lock); + + if (NT_SUCCESS(status)) { + WvEpFree(ep); + } + WvProviderEnableRemove(pProvider); +out: + WdfRequestComplete(Request, status); +} + +void WvEpFree(WV_ENDPOINT *pEndpoint) +{ + WdfObjectAcquireLock(pEndpoint->Queue); + pEndpoint->State = WvEpDestroying; + WdfObjectReleaseLock(pEndpoint->Queue); + + if (InterlockedDecrement(&pEndpoint->Ref) > 0) { + KeWaitForSingleObject(&pEndpoint->Event, Executive, KernelMode, FALSE, NULL); + } + + if (pEndpoint->pIbCmId != NULL) { + IbCmInterface.CM.destroy_id(pEndpoint->pIbCmId); + } + + WdfIoQueuePurgeSynchronously(pEndpoint->Queue); + WdfObjectDelete(pEndpoint->Queue); + if (pEndpoint->pWork != NULL) { + ExFreePoolWithTag(pEndpoint->pWork, 'wevw'); + } + ExFreePoolWithTag(pEndpoint, 'pevw'); +} + +void WvEpQuery(WV_PROVIDER *pProvider, WDFREQUEST Request) +{ + UINT64 *id; + WV_IO_EP_ATTRIBUTES *pattr; + WV_ENDPOINT *ep; + size_t len = 0; + NTSTATUS status; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL); + if (!NT_SUCCESS(status)) { + goto complete; + } + status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_EP_ATTRIBUTES), + &pattr, NULL); + if (!NT_SUCCESS(status)) { + goto complete; + } + + ep = WvEpAcquire(pProvider, *id); + if (ep == NULL) { + status = STATUS_NOT_FOUND; + goto complete; + } + + *pattr = ep->Attributes; + WvEpRelease(ep); + len = sizeof(WV_IO_EP_ATTRIBUTES); + +complete: + WdfRequestCompleteWithInformation(Request, status, len); +} + +void WvEpModify(WV_PROVIDER *pProvider, WDFREQUEST Request) +{ + WV_IO_ID *pId; + size_t inlen; + WV_ENDPOINT *ep; + NTSTATUS status; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_ID), &pId, &inlen); + if (!NT_SUCCESS(status)) { + goto complete; + } + + if (pId->Data != WV_IO_EP_OPTION_ROUTE) { + status = STATUS_INVALID_PARAMETER; + goto complete; + } + + if (inlen < sizeof(WV_IO_ID) + sizeof(ib_path_rec_t)) { + status = STATUS_BUFFER_TOO_SMALL; + goto complete; + } + + ep = WvEpAcquire(pProvider, pId->Id); + if (ep == NULL) { + status = STATUS_NOT_FOUND; + goto complete; + } + + WdfObjectAcquireLock(ep->Queue); + if (ep->State != WvEpAddressBound) { + status = STATUS_NOT_SUPPORTED; + goto release; + } + + RtlCopyMemory(&ep->Route, pId + 1, sizeof ep->Route); + ep->State = WvEpRouteResolved; + +release: + WdfObjectReleaseLock(ep->Queue); + WvEpRelease(ep); +complete: + WdfRequestComplete(Request, status); +} + +void WvEpBind(WV_PROVIDER *pProvider, WDFREQUEST Request) +{ + WV_IO_EP_BIND *pattr; + WV_ENDPOINT *ep; + size_t len = 0; + NTSTATUS status; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_EP_BIND), + &pattr, NULL); + if (!NT_SUCCESS(status)) { + goto complete; + } + status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_EP_BIND), + &pattr, NULL); + if (!NT_SUCCESS(status)) { + goto complete; + } + + ep = WvEpAcquire(pProvider, pattr->Id); + if (ep == NULL) { + status = STATUS_NOT_FOUND; + goto complete; + } + + WdfObjectAcquireLock(ep->Queue); + if (ep->State != WvEpIdle) { + status = STATUS_NOT_SUPPORTED; + goto release; + } + + ep->Attributes.LocalAddress = pattr->Address; + ep->Attributes.Device = pattr->Device; + len = sizeof(WV_IO_EP_BIND); + ep->State = WvEpAddressBound; + +release: + WdfObjectReleaseLock(ep->Queue); + WvEpRelease(ep); +complete: + WdfRequestCompleteWithInformation(Request, status, len); +} + +static UINT64 WvGetServiceId(UINT16 EpType, WV_IO_SOCKADDR_DATA *pAddress) +{ + return RtlUlonglongByteSwap(((UINT64)EpType << 16) + + RtlUshortByteSwap(pAddress->SockAddr.In.SinPort)); +} + +static int WvAnyAddress(WV_IO_SOCKADDR_DATA *pAddress) +{ + if (pAddress->SockAddr.Sa.SaFamily == WV_AF_INET) { + return (pAddress->SockAddr.In.SinAddr == 0) || + ((pAddress->SockAddr.In.SinAddr & 0xff) == 0x7f); + } else { + return (RtlCompareMemoryUlong(pAddress->SockAddr.In6.Sin6Addr, 16, 0) == 16); + } +} + +static void WvFormatCmaHeader(IB_CMA_HEADER *pHeader, + WV_IO_SOCKADDR_DATA *pLocalAddress, + WV_IO_SOCKADDR_DATA *pPeerAddress) +{ + pHeader->CmaVersion = IB_CMA_VERSION; + if (pLocalAddress->SockAddr.Sa.SaFamily == WV_AF_INET) { + pHeader->IpVersion = 4 << 4; + pHeader->SrcAddress.Ip4.Address = pLocalAddress->SockAddr.In.SinAddr; + pHeader->DstAddress.Ip4.Address = pPeerAddress->SockAddr.In.SinAddr; + pHeader->Port = pLocalAddress->SockAddr.In.SinPort; + } else { + pHeader->IpVersion = 6 << 4; + RtlCopyMemory(pHeader->SrcAddress.Ip6Address, + pLocalAddress->SockAddr.In6.Sin6Addr, 16); + RtlCopyMemory(pHeader->DstAddress.Ip6Address, + pPeerAddress->SockAddr.In6.Sin6Addr, 16); + pHeader->Port = pLocalAddress->SockAddr.In6.Sin6Port; + } +} + +static void WvEpSaveReply(WV_ENDPOINT *pEndpoint, iba_cm_rep_event *pReply) +{ + UINT8 len; + + len = sizeof(pEndpoint->Attributes.Param.Connect.Data); + RtlCopyMemory(pEndpoint->Attributes.Param.Connect.Data, pReply->rep.p_pdata, len); + pEndpoint->Attributes.Param.Connect.DataLength = len; + pEndpoint->Attributes.Param.Connect.InitiatorDepth = pReply->rep.resp_res; + pEndpoint->Attributes.Param.Connect.ResponderResources = pReply->rep.init_depth; + pEndpoint->Attributes.Param.Connect.RnrRetryCount = pReply->rep.rnr_retry_cnt; +} + +static void WvEpSaveReject(WV_ENDPOINT *pEndpoint, iba_cm_rej_event *pReject) +{ + UINT8 len; + + len = sizeof(pEndpoint->Attributes.Param.Connect.Data); + RtlCopyMemory(pEndpoint->Attributes.Param.Connect.Data, pReject->p_pdata, len); + pEndpoint->Attributes.Param.Connect.DataLength = len; +} + +static NTSTATUS WvEpModifyQpErr(WV_QUEUE_PAIR *pQp, + UINT8 *pVerbsData, UINT32 VerbsSize) +{ + ib_qp_mod_t attr; + ib_api_status_t ib_status; + NTSTATUS status; + + attr.req_state = IB_QPS_ERROR; + ib_status = pQp->pVerbs->ndi_modify_qp(pQp->hVerbsQp, &attr, NULL, + VerbsSize, pVerbsData); + if (ib_status == IB_SUCCESS) { + status = STATUS_SUCCESS; + } else { + status = STATUS_UNSUCCESSFUL; + } + + return status; +} + +static NTSTATUS WvEpDisconnectQp(WV_PROVIDER *pProvider, UINT64 QpId, + UINT8 *pVerbsData, UINT32 VerbsSize) +{ + WV_QUEUE_PAIR *qp; + NTSTATUS status; + + if (QpId == 0) { + return STATUS_SUCCESS; + } + + qp = WvQpAcquire(pProvider, QpId); + if (qp == NULL) { + return STATUS_NOT_FOUND; + } + + status = WvEpModifyQpErr(qp, pVerbsData, VerbsSize); + WvQpRelease(qp); + + return status; +} + +static NTSTATUS WvEpAsyncDisconnect(WV_ENDPOINT *pEndpoint, WDFREQUEST Request) +{ + WV_IO_EP_DISCONNECT *pattr; + UINT8 *out; + size_t outlen = 0; + NTSTATUS status; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_EP_DISCONNECT), + &pattr, NULL); + if (!NT_SUCCESS(status)) { + return status; + } + + status = WdfRequestRetrieveOutputBuffer(Request, 0, &out, &outlen); + if (!NT_SUCCESS(status) && status != STATUS_BUFFER_TOO_SMALL) { + return status; + } + + status = (NTSTATUS) WdfRequestGetInformation(Request); + if (NT_SUCCESS(status)) { + status = WvEpDisconnectQp(pEndpoint->pProvider, pattr->QpId, out, outlen); + } else { + WvEpDisconnectQp(pEndpoint->pProvider, pattr->QpId, out, outlen); + } + + WdfRequestCompleteWithInformation(Request, status, outlen); + return STATUS_SUCCESS; +} + +static void WvEpCompleteDisconnect(WV_ENDPOINT *pEndpoint, NTSTATUS DiscStatus) +{ + WDFREQUEST request; + WDFREQUEST disc_req = NULL; + WDF_REQUEST_PARAMETERS param; + NTSTATUS status; + + WdfObjectAcquireLock(pEndpoint->Queue); + if (pEndpoint->State == WvEpDestroying || !pEndpoint->pWork) { + goto release; + } + pEndpoint->State = WvEpDisconnected; + + status = WdfIoQueueRetrieveNextRequest(pEndpoint->Queue, &request); + while (NT_SUCCESS(status)) { + + WDF_REQUEST_PARAMETERS_INIT(¶m); + WdfRequestGetParameters(request, ¶m); + if (param.Parameters.DeviceIoControl.IoControlCode == WV_IOCTL_EP_DISCONNECT) { + WdfRequestSetInformation(request, DiscStatus); + WvProviderGet(pEndpoint->pProvider); + WorkQueueInsert(&pEndpoint->pProvider->WorkQueue, &pEndpoint->pWork->Work); + pEndpoint->pWork = NULL; + disc_req = request; + } else { + WdfRequestComplete(request, DiscStatus); + } + + status = WdfIoQueueRetrieveNextRequest(pEndpoint->Queue, &request); + } + + if (disc_req != NULL) { + WdfRequestRequeue(disc_req); + } +release: + WdfObjectReleaseLock(pEndpoint->Queue); + +} + +static NTSTATUS WvEpIbCmHandler(iba_cm_id *pId, iba_cm_event *pEvent) +{ + WV_ENDPOINT *ep; + + ep = pId->context; + switch (pEvent->type) { + case iba_cm_req_error: + WdfObjectAcquireLock(ep->Queue); + if (ep->State == WvEpActiveConnect) { + ep->State = WvEpRouteResolved; + WvCompleteRequests(ep->Queue, STATUS_TIMEOUT); + } + WdfObjectReleaseLock(ep->Queue); + break; + case iba_cm_rep_error: + WdfObjectAcquireLock(ep->Queue); + if (ep->State == WvEpPassiveConnect) { + ep->State = WvEpDisconnected; + WvCompleteRequests(ep->Queue, STATUS_IO_TIMEOUT); + } + WdfObjectReleaseLock(ep->Queue); + break; + case iba_cm_dreq_error: + WvEpCompleteDisconnect(ep, STATUS_TIMEOUT); + break; + case iba_cm_rep_received: + WdfObjectAcquireLock(ep->Queue); + if (ep->State == WvEpActiveConnect) { + WvEpSaveReply(ep, &pEvent->data.rep); + WvCompleteRequests(ep->Queue, STATUS_SUCCESS); + } + WdfObjectReleaseLock(ep->Queue); + break; + case iba_cm_rtu_received: + WdfObjectAcquireLock(ep->Queue); + if (ep->State == WvEpPassiveConnect) { + ep->State = WvEpConnected; + WvCompleteRequestsWithInformation(ep->Queue, STATUS_SUCCESS); + } + WdfObjectReleaseLock(ep->Queue); + break; + case iba_cm_dreq_received: + WdfObjectAcquireLock(ep->Queue); + if (ep->State == WvEpConnected) { + ep->State = WvEpPassiveDisconnect; + WvCompleteRequests(ep->Queue, STATUS_SUCCESS); + WdfObjectReleaseLock(ep->Queue); + } else if (ep->State == WvEpPassiveConnect) { + ep->State = WvEpPassiveDisconnect; + WvCompleteRequestsWithInformation(ep->Queue, STATUS_SUCCESS); + WdfObjectReleaseLock(ep->Queue); + } else { + WdfObjectReleaseLock(ep->Queue); + WvEpCompleteDisconnect(ep, STATUS_SUCCESS); + } + break; + case iba_cm_drep_received: + WvEpCompleteDisconnect(ep, STATUS_SUCCESS); + break; + case iba_cm_rej_received: + WdfObjectAcquireLock(ep->Queue); + if (ep->State == WvEpPassiveConnect || ep->State == WvEpActiveConnect) { + ep->State = WvEpDisconnected; + WvEpSaveReject(ep, &pEvent->data.rej); + WvCompleteRequests(ep->Queue, STATUS_CONNECTION_REFUSED); + } + WdfObjectReleaseLock(ep->Queue); + break; + case iba_cm_mra_received: + break; + default: + WdfObjectAcquireLock(ep->Queue); + if (ep->State != WvEpDestroying) { + ep->State = WvEpDisconnected; + WvCompleteRequests(ep->Queue, STATUS_NOT_IMPLEMENTED); + } + WdfObjectReleaseLock(ep->Queue); + break; + } + + return STATUS_SUCCESS; +} + +static NTSTATUS WvEpAsyncConnect(WV_ENDPOINT *pEndpoint, WDFREQUEST Request) +{ + WV_IO_EP_CONNECT *pattr; + WV_QUEUE_PAIR *qp; + iba_cm_req req; + NTSTATUS status; + UINT8 data[IB_REQ_PDATA_SIZE]; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_EP_CONNECT), + &pattr, NULL); + if (!NT_SUCCESS(status)) { + return status; + } + + qp = WvQpAcquire(pEndpoint->pProvider, pattr->QpId); + if (qp == NULL) { + return STATUS_NOT_FOUND; + } + + pEndpoint->Attributes.PeerAddress = pattr->PeerAddress; + WvFormatCmaHeader((IB_CMA_HEADER *) data, &pEndpoint->Attributes.LocalAddress, + &pEndpoint->Attributes.PeerAddress); + + req.service_id = WvGetServiceId(pEndpoint->EpType, &pEndpoint->Attributes.PeerAddress); + req.p_primary_path = &pEndpoint->Route; + req.p_alt_path = NULL; + req.qpn = qp->Qpn; + req.qp_type = IB_QPT_RELIABLE_CONN; + req.starting_psn = (net32_t) RtlRandomEx(&RandomSeed); + req.p_pdata = data; + RtlCopyMemory(data + sizeof(IB_CMA_HEADER), pattr->Param.Data, + pattr->Param.DataLength); + req.pdata_len = sizeof(IB_CMA_HEADER) + pattr->Param.DataLength; + req.max_cm_retries = IB_CMA_MAX_CM_RETRIES; + req.resp_res = (UINT8) pattr->Param.ResponderResources; + req.init_depth = (UINT8) pattr->Param.InitiatorDepth; + req.remote_resp_timeout = IB_CMA_CM_RESPONSE_TIMEOUT; + req.flow_ctrl = 1; + req.local_resp_timeout = IB_CMA_CM_RESPONSE_TIMEOUT; + req.rnr_retry_cnt = pattr->Param.RnrRetryCount; + req.retry_cnt = pattr->Param.RetryCount; + req.srq = (qp->pSrq != NULL); + + WvQpRelease(qp); + RtlCopyMemory(&pEndpoint->Attributes.Param.Connect, &pattr->Param, + sizeof(pattr->Param)); + + WdfObjectAcquireLock(pEndpoint->Queue); + if (pEndpoint->State != WvEpRouteResolved) { + status = STATUS_NOT_SUPPORTED; + goto out; + } + + status = IbCmInterface.CM.create_id(WvEpIbCmHandler, pEndpoint, &pEndpoint->pIbCmId); + if (!NT_SUCCESS(status)) { + goto out; + } + + pEndpoint->State = WvEpActiveConnect; + status = IbCmInterface.CM.send_req(pEndpoint->pIbCmId, &req); + if (NT_SUCCESS(status)) { + status = WdfRequestRequeue(Request); + } + + if (!NT_SUCCESS(status)) { + pEndpoint->State = WvEpDisconnected; + } + +out: + WdfObjectReleaseLock(pEndpoint->Queue); + return status; +} + +static NTSTATUS WvEpProcessAsync(WV_PROVIDER *pProvider, UINT64 Id, WDFREQUEST Request) +{ + WV_ENDPOINT *ep; + NTSTATUS status; + + ep = WvEpAcquire(pProvider, Id); + if (ep == NULL) { + return STATUS_NOT_FOUND; + } + + WdfObjectAcquireLock(ep->Queue); + if (!ep->pWork) { + status = STATUS_TOO_MANY_COMMANDS; + goto out; + } + + status = WdfRequestForwardToIoQueue(Request, ep->Queue); + if (NT_SUCCESS(status)) { + WvProviderGet(pProvider); + WorkQueueInsert(&pProvider->WorkQueue, &ep->pWork->Work); + ep->pWork = NULL; + } + +out: + WdfObjectReleaseLock(ep->Queue); + WvEpRelease(ep); + return status; +} + +void WvEpConnect(WV_PROVIDER *pProvider, WDFREQUEST Request) +{ + WV_IO_EP_CONNECT *pattr; + NTSTATUS status; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_EP_CONNECT), + &pattr, NULL); + if (!NT_SUCCESS(status)) { + goto out; + } + + if (pattr->Param.DataLength > sizeof(pattr->Param.Data)) { + status = STATUS_INVALID_BUFFER_SIZE; + goto out; + } + + status = WvEpProcessAsync(pProvider, pattr->Id, Request); + +out: + if (!NT_SUCCESS(status)) { + WdfRequestComplete(Request, status); + } +} + +static NTSTATUS WvEpModifyQpRtr(WV_ENDPOINT *pEndpoint, WV_QUEUE_PAIR *pQp, + UINT64 ResponderResources, UINT32 Psn, + UINT8 *pVerbsData, UINT32 VerbsSize) +{ + ib_qp_mod_t attr; + ib_api_status_t ib_status; + NTSTATUS status; + + status =IbCmInterface.CM.get_qp_attr(pEndpoint->pIbCmId, IB_QPS_INIT, &attr); + if (!NT_SUCCESS(status)) { + return status; + } + + ib_status = pQp->pVerbs->ndi_modify_qp(pQp->hVerbsQp, &attr, NULL, + VerbsSize, pVerbsData); + if (ib_status != IB_SUCCESS) { + return STATUS_UNSUCCESSFUL; + } + + status = IbCmInterface.CM.get_qp_attr(pEndpoint->pIbCmId, IB_QPS_RTR, &attr); + if (!NT_SUCCESS(status)) { + return status; + } + + if (pEndpoint->State == WvEpPassiveConnect) { + attr.state.rtr.resp_res = (UINT8) ResponderResources; + attr.state.rtr.rq_psn = Psn; + } + + ib_status = pQp->pVerbs->ndi_modify_qp(pQp->hVerbsQp, &attr, NULL, + VerbsSize, pVerbsData); + if (ib_status != IB_SUCCESS) { + return STATUS_UNSUCCESSFUL; + } + + return STATUS_SUCCESS; +} + +static NTSTATUS WvEpModifyQpRts(WV_ENDPOINT *pEndpoint, WV_QUEUE_PAIR *pQp, + UINT64 InitiatorDepth, + UINT8 *pVerbsData, UINT32 VerbsSize) +{ + ib_qp_mod_t attr; + ib_api_status_t ib_status; + NTSTATUS status; + + status = IbCmInterface.CM.get_qp_attr(pEndpoint->pIbCmId, IB_QPS_RTS, &attr); + if (!NT_SUCCESS(status)) { + return status; + } + + if (pEndpoint->State == WvEpPassiveConnect) { + attr.state.rts.init_depth = (UINT8) InitiatorDepth; + } + + ib_status = pQp->pVerbs->ndi_modify_qp(pQp->hVerbsQp, &attr, NULL, + VerbsSize, pVerbsData); + if (ib_status != IB_SUCCESS) { + return STATUS_UNSUCCESSFUL; + } + + return STATUS_SUCCESS; +} + +static NTSTATUS WvEpAcceptActive(WDFREQUEST Request, UINT8 *pVerbsData, size_t VerbsSize, + WV_ENDPOINT *pEndpoint, WV_IO_EP_ACCEPT *pAttr) +{ + WV_QUEUE_PAIR *qp; + NTSTATUS status; + + qp = WvQpAcquire(pEndpoint->pProvider, pAttr->QpId); + if (qp == NULL) { + return STATUS_NOT_FOUND; + } + + status = WvEpModifyQpRtr(pEndpoint, qp, 0, 0, pVerbsData, VerbsSize); + if (NT_SUCCESS(status)) { + status = WvEpModifyQpRts(pEndpoint, qp, 0, pVerbsData, VerbsSize); + } + + WvQpRelease(qp); + + WdfObjectAcquireLock(pEndpoint->Queue); + if (pEndpoint->State != WvEpActiveConnect) { + status = STATUS_NOT_SUPPORTED; + goto release; + } + + pEndpoint->State = WvEpConnected; + status = IbCmInterface.CM.send_rtu(pEndpoint->pIbCmId, pAttr->Param.Data, + pAttr->Param.DataLength); + if (NT_SUCCESS(status)) { + WdfRequestCompleteWithInformation(Request, status, VerbsSize); + } else { + pEndpoint->State = WvEpDisconnected; + } + +release: + WdfObjectReleaseLock(pEndpoint->Queue); + return status; +} + +static NTSTATUS WvEpAcceptPassive(WDFREQUEST Request, UINT8 *pVerbsData, size_t VerbsSize, + WV_ENDPOINT *pEndpoint, WV_IO_EP_ACCEPT *pAttr) +{ + WV_QUEUE_PAIR *qp; + iba_cm_rep rep; + NTSTATUS status; + + qp = WvQpAcquire(pEndpoint->pProvider, pAttr->QpId); + if (qp == NULL) { + return STATUS_NOT_FOUND; + } + + rep.qpn = qp->Qpn; + rep.starting_psn = (net32_t) RtlRandomEx(&RandomSeed); + rep.p_pdata = pAttr->Param.Data; + rep.pdata_len = pAttr->Param.DataLength; + rep.failover_accepted = IB_FAILOVER_ACCEPT_UNSUPPORTED; + rep.resp_res = (UINT8) pAttr->Param.ResponderResources; + rep.init_depth = (UINT8) pAttr->Param.InitiatorDepth; + rep.flow_ctrl = 1; + rep.rnr_retry_cnt = pAttr->Param.RnrRetryCount; + rep.srq = (qp->pSrq != NULL); + + status = WvEpModifyQpRtr(pEndpoint, qp, pAttr->Param.ResponderResources, + rep.starting_psn, pVerbsData, VerbsSize); + if (NT_SUCCESS(status)) { + status = WvEpModifyQpRts(pEndpoint, qp, pAttr->Param.InitiatorDepth, + pVerbsData, VerbsSize); + } + + WvQpRelease(qp); + + if (!NT_SUCCESS(status)) { + goto out; + } + + WdfObjectAcquireLock(pEndpoint->Queue); + if (pEndpoint->State != WvEpPassiveConnect) { + status = STATUS_NOT_SUPPORTED; + goto release; + } + + status = IbCmInterface.CM.send_rep(pEndpoint->pIbCmId, &rep); + if (NT_SUCCESS(status)) { + status = WdfRequestRequeue(Request); + } + + if (!NT_SUCCESS(status)) { + pEndpoint->State = WvEpDisconnected; + } + +release: + WdfObjectReleaseLock(pEndpoint->Queue); +out: + return status; +} + +static NTSTATUS WvEpAsyncAccept(WV_ENDPOINT *pEndpoint, WDFREQUEST Request) +{ + WV_IO_EP_ACCEPT *pattr; + NTSTATUS status; + UINT8 *out; + size_t outlen; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_EP_ACCEPT), + &pattr, NULL); + if (!NT_SUCCESS(status)) { + return status; + } + + status = WdfRequestRetrieveOutputBuffer(Request, 0, &out, &outlen); + if (!NT_SUCCESS(status) && status != STATUS_BUFFER_TOO_SMALL) { + return status; + } + + /* EP state is re-checked under lock in WvEpAccept* calls */ + switch (pEndpoint->State) { + case WvEpActiveConnect: + status = WvEpAcceptActive(Request, out, outlen, pEndpoint, pattr); + break; + case WvEpPassiveConnect: + status = WvEpAcceptPassive(Request, out, outlen, pEndpoint, pattr); + break; + default: + status = STATUS_NOT_SUPPORTED; + break; + } + + return status; +} + +static void WvEpWorkHandler(WORK_ENTRY *pWork) +{ + WV_PROVIDER *prov; + WV_ENDPOINT *ep; + WV_WORK_ENTRY *work; + WDFREQUEST request; + WDF_REQUEST_PARAMETERS param; + NTSTATUS status; + + work = CONTAINING_RECORD(pWork, WV_WORK_ENTRY, Work); + prov = (WV_PROVIDER *) pWork->Context; + + ep = WvEpAcquire(prov, work->Id); + if (ep == NULL) { + ExFreePoolWithTag(work, 'wevw'); + goto out; + } + + WdfObjectAcquireLock(ep->Queue); + ep->pWork = work; + status = WdfIoQueueRetrieveNextRequest(ep->Queue, &request); + WdfObjectReleaseLock(ep->Queue); + + if (!NT_SUCCESS(status)) { + goto put; + } + + WDF_REQUEST_PARAMETERS_INIT(¶m); + WdfRequestGetParameters(request, ¶m); + switch (param.Parameters.DeviceIoControl.IoControlCode) { + case WV_IOCTL_EP_CONNECT: + status = WvEpAsyncConnect(ep, request); + break; + case WV_IOCTL_EP_ACCEPT: + status = WvEpAsyncAccept(ep, request); + break; + case WV_IOCTL_EP_DISCONNECT: + status = WvEpAsyncDisconnect(ep, request); + break; + default: + status = STATUS_NOT_IMPLEMENTED; + } + + if (!NT_SUCCESS(status)) { + WdfRequestComplete(request, status); + } +put: + WvEpRelease(ep); +out: + WvProviderPut(prov); +} + +void WvEpAccept(WV_PROVIDER *pProvider, WDFREQUEST Request) +{ + WV_IO_EP_ACCEPT *pattr; + NTSTATUS status; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_EP_ACCEPT), + &pattr, NULL); + if (!NT_SUCCESS(status)) { + goto out; + } + + if (pattr->Param.DataLength > sizeof(pattr->Param.Data)) { + status = STATUS_INVALID_BUFFER_SIZE; + goto out; + } + + status = WvEpProcessAsync(pProvider, pattr->Id, Request); + +out: + if (!NT_SUCCESS(status)) { + WdfRequestComplete(Request, status); + } +} + +void WvEpReject(WV_PROVIDER *pProvider, WDFREQUEST Request) +{ + WV_IO_ID *id; + WV_ENDPOINT *ep; + NTSTATUS status; + size_t len; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_ID), &id, &len); + if (!NT_SUCCESS(status)) { + goto complete; + } + + ep = WvEpAcquire(pProvider, id->Id); + if (ep == NULL) { + status = STATUS_NOT_FOUND; + goto complete; + } + + WdfObjectAcquireLock(ep->Queue); + if (ep->State != WvEpActiveConnect && ep->State != WvEpPassiveConnect) { + status = STATUS_NOT_SUPPORTED; + goto release; + } + + ep->State = WvEpDisconnected; + status = IbCmInterface.CM.send_rej(ep->pIbCmId, IB_REJ_USER_DEFINED, + NULL, 0, id + 1, len - sizeof(WV_IO_ID)); + +release: + WdfObjectReleaseLock(ep->Queue); + WvEpRelease(ep); +complete: + WdfRequestComplete(Request, status); +} + +// The IB CM could have received and processed a DREQ that we haven't seen yet. +void WvEpDisconnect(WV_PROVIDER *pProvider, WDFREQUEST Request) +{ + WV_IO_EP_DISCONNECT *pattr; + WV_ENDPOINT *ep; + NTSTATUS status; + UINT8 *out; + size_t outlen; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_EP_DISCONNECT), + &pattr, NULL); + if (!NT_SUCCESS(status)) { + goto complete; + } + + status = WdfRequestRetrieveOutputBuffer(Request, 0, &out, &outlen); + if (!NT_SUCCESS(status) && status != STATUS_BUFFER_TOO_SMALL) { + goto complete; + } + + ep = WvEpAcquire(pProvider, pattr->Id); + if (ep == NULL) { + status = STATUS_NOT_FOUND; + goto complete; + } + + WdfObjectAcquireLock(ep->Queue); + switch (ep->State) { + case WvEpConnected: + status = IbCmInterface.CM.send_dreq(ep->pIbCmId, NULL, 0); + if (NT_SUCCESS(status)) { + status = WdfRequestForwardToIoQueue(Request, ep->Queue); + if (NT_SUCCESS(status)) { + ep->State = WvEpActiveDisconnect; + break; + } + } + /* Fall through to passive disconnect case on failure */ + case WvEpActiveDisconnect: + case WvEpPassiveDisconnect: + ep->State = WvEpDisconnected; + WdfObjectReleaseLock(ep->Queue); + + IbCmInterface.CM.send_drep(ep->pIbCmId, NULL, 0); + + status = WvEpDisconnectQp(ep->pProvider, pattr->QpId, out, outlen); + if (NT_SUCCESS(status)) { + WdfRequestCompleteWithInformation(Request, status, outlen); + } + goto release; + default: + status = STATUS_INVALID_DEVICE_STATE; + break; + } + WdfObjectReleaseLock(ep->Queue); + +release: + WvEpRelease(ep); +complete: + if (!NT_SUCCESS(status)) { + WdfRequestComplete(Request, status); + } +} + +void WvEpDisconnectNotify(WV_PROVIDER *pProvider, WDFREQUEST Request) +{ + UINT64 *id; + WV_ENDPOINT *ep; + NTSTATUS status; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL); + if (!NT_SUCCESS(status)) { + goto complete; + } + + ep = WvEpAcquire(pProvider, *id); + if (ep == NULL) { + status = STATUS_NOT_FOUND; + goto complete; + } + + WdfObjectAcquireLock(ep->Queue); + switch (ep->State) { + case WvEpConnected: + case WvEpActiveDisconnect: + status = WdfRequestForwardToIoQueue(Request, ep->Queue); + if (NT_SUCCESS(status)) { + WdfObjectReleaseLock(ep->Queue); + WvEpRelease(ep); + return; + } + break; + case WvEpPassiveDisconnect: + case WvEpDisconnected: + status = STATUS_SUCCESS; + break; + default: + status = STATUS_NOT_SUPPORTED; + break; + } + WdfObjectReleaseLock(ep->Queue); + + WvEpRelease(ep); +complete: + WdfRequestComplete(Request, status); +} + +static void WvEpGetIbRequest(WV_ENDPOINT *pListen) +{ + WV_ENDPOINT *ep; + WDFREQUEST request; + NTSTATUS status; + IB_CMA_HEADER *hdr; + iba_cm_id *id; + iba_cm_event event; + + WdfObjectAcquireLock(pListen->Queue); + while (1) { + status = WdfIoQueueRetrieveNextRequest(pListen->Queue, &request); + if (!NT_SUCCESS(status)) { + break; + } + + status = IbCmInterface.CM.get_request(pListen->pIbCmId, &id, &event); + if (!NT_SUCCESS(status)) { + WdfRequestRequeue(request); + break; + } + + ASSERT(!IsListEmpty(&pListen->Entry)); + ep = CONTAINING_RECORD(RemoveHeadList(&pListen->Entry), WV_ENDPOINT, Entry); + ep->pIbCmId = id; + id->callback = WvEpIbCmHandler; + id->context = ep; + + hdr = (IB_CMA_HEADER *) event.data.req.pdata; + if ((hdr->IpVersion >> 4) == 4) { + ep->Attributes.LocalAddress.SockAddr.In.SinFamily = WV_AF_INET; + ep->Attributes.LocalAddress.SockAddr.In.SinAddr = hdr->DstAddress.Ip4.Address; + ep->Attributes.PeerAddress.SockAddr.In.SinFamily = WV_AF_INET; + ep->Attributes.PeerAddress.SockAddr.In.SinAddr = hdr->SrcAddress.Ip4.Address; + } else { + ep->Attributes.LocalAddress.SockAddr.In6.Sin6Family = WV_AF_INET6; + RtlCopyMemory(ep->Attributes.LocalAddress.SockAddr.In6.Sin6Addr, + hdr->DstAddress.Ip6Address, 16); + ep->Attributes.PeerAddress.SockAddr.In6.Sin6Family = WV_AF_INET6; + RtlCopyMemory(ep->Attributes.PeerAddress.SockAddr.In6.Sin6Addr, + hdr->SrcAddress.Ip6Address, 16); + } + ep->Attributes.Device.DeviceGuid = event.data.req.local_ca_guid; + ep->Attributes.Device.Pkey = event.data.req.primary_path.pkey; + ep->Attributes.Device.PortNumber = event.data.req.port_num; + ep->Attributes.Param.Connect.ResponderResources = event.data.req.resp_res; + ep->Attributes.Param.Connect.InitiatorDepth = event.data.req.init_depth; + ep->Attributes.Param.Connect.RetryCount = event.data.req.retry_cnt; + ep->Attributes.Param.Connect.RnrRetryCount = event.data.req.rnr_retry_cnt; + ep->Attributes.Param.Connect.DataLength = sizeof(ep->Attributes.Param.Connect.Data); + RtlCopyMemory(ep->Attributes.Param.Connect.Data, hdr + 1, + sizeof(ep->Attributes.Param.Connect.Data)); + ep->Route = event.data.req.primary_path; + + ep->State = WvEpPassiveConnect; + WvEpPut(ep); + + WdfRequestComplete(request, STATUS_SUCCESS); + } + WdfObjectReleaseLock(pListen->Queue); +} + +static NTSTATUS WvEpIbListenHandler(iba_cm_id *pId, iba_cm_event *pEvent) +{ + WV_ENDPOINT *listen; + + listen = pId->context; + WvEpGetIbRequest(listen); + return STATUS_SUCCESS; +} + +void WvEpListen(WV_PROVIDER *pProvider, WDFREQUEST Request) +{ + WV_ENDPOINT *ep; + WV_IO_EP_LISTEN *pattr; + NTSTATUS status; + void *buf; + UINT8 offset, len; + UINT64 sid; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_EP_LISTEN), + &pattr, NULL); + if (!NT_SUCCESS(status)) { + goto complete; + } + + ep = WvEpAcquire(pProvider, pattr->Id); + if (ep == NULL) { + status = STATUS_NOT_FOUND; + goto complete; + } + + if (WvAnyAddress(&ep->Attributes.LocalAddress)) { + buf = NULL; + offset = 0; + len = 0; + } else { + if (ep->Attributes.LocalAddress.SockAddr.Sa.SaFamily == WV_AF_INET) { + buf = &ep->Attributes.LocalAddress.SockAddr.In.SinAddr; + len = sizeof ep->Attributes.LocalAddress.SockAddr.In.SinAddr; + offset = FIELD_OFFSET(IB_CMA_HEADER, DstAddress.Ip4.Address); + } else { + buf = ep->Attributes.LocalAddress.SockAddr.In6.Sin6Addr; + len = sizeof ep->Attributes.LocalAddress.SockAddr.In6.Sin6Addr; + offset = FIELD_OFFSET(IB_CMA_HEADER, DstAddress.Ip6Address); + } + } + + WdfObjectAcquireLock(ep->Queue); + if (ep->State != WvEpAddressBound) { + status = STATUS_NOT_SUPPORTED; + goto release; + } + + status = IbCmInterface.CM.create_id(WvEpIbListenHandler, ep, &ep->pIbCmId); + if (!NT_SUCCESS(status)) { + goto release; + } + + ep->Attributes.Param.Backlog = pattr->Backlog; + ep->State = WvEpListening; + sid = WvGetServiceId(ep->EpType, &ep->Attributes.LocalAddress); + status = IbCmInterface.CM.listen(ep->pIbCmId, sid, buf, len, offset); + +release: + WdfObjectReleaseLock(ep->Queue); + WvEpRelease(ep); +complete: + WdfRequestComplete(Request, status); +} + +void WvEpGetRequest(WV_PROVIDER *pProvider, WDFREQUEST Request) +{ + WV_ENDPOINT *listen, *ep; + WV_IO_EP_GET_REQUEST *req; + NTSTATUS status; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_EP_GET_REQUEST), + &req, NULL); + if (!NT_SUCCESS(status)) { + goto err1; + } + + listen = WvEpAcquire(pProvider, req->Id); + if (listen == NULL) { + status = STATUS_NOT_FOUND; + goto err1; + } + + if (listen->State != WvEpListening) { + status = STATUS_NOT_SUPPORTED; + goto err2; + } + + ep = WvEpAcquire(pProvider, req->EpId); + if (ep == NULL) { + status = STATUS_NOT_FOUND; + goto err2; + } + + WdfObjectAcquireLock(ep->Queue); + if (ep->State == WvEpIdle) { + ep->State = WvEpQueued; + } else { + status = STATUS_CONNECTION_IN_USE; + } + WdfObjectReleaseLock(ep->Queue); + if (!NT_SUCCESS(status)) { + goto err3; + } + + WdfObjectAcquireLock(listen->Queue); + status = WdfRequestForwardToIoQueue(Request, listen->Queue); + if (NT_SUCCESS(status)) { + InsertTailList(&listen->Entry, &ep->Entry); + WvEpGet(ep); + } + WdfObjectReleaseLock(listen->Queue); + if (!NT_SUCCESS(status)) { + goto err3; + } + + WvEpRelease(ep); + WvEpGetIbRequest(listen); + WvEpRelease(listen); + return; + +err3: + WvEpRelease(ep); +err2: + WvEpRelease(listen); +err1: + WdfRequestComplete(Request, status); +} + +void WvEpLookup(WV_PROVIDER *pProvider, WDFREQUEST Request) +{ + UNUSED_PARAM(pProvider); + WdfRequestComplete(Request, STATUS_NOT_IMPLEMENTED); +} + +void WvEpMulticastJoin(WV_PROVIDER *pProvider, WDFREQUEST Request) +{ + UNUSED_PARAM(pProvider); + WdfRequestComplete(Request, STATUS_NOT_IMPLEMENTED); +} + +void WvEpMulticastLeave(WV_PROVIDER *pProvider, WDFREQUEST Request) +{ + UNUSED_PARAM(pProvider); + WdfRequestComplete(Request, STATUS_NOT_IMPLEMENTED); +} + +// +// Note that the framework may have already canceled outstanding requests. +// +void WvEpCancelListen(WV_ENDPOINT *pListen) +{ + WV_ENDPOINT *ep; + + WdfObjectAcquireLock(pListen->Queue); + WvCompleteRequests(pListen->Queue, STATUS_CANCELLED); + + while (!IsListEmpty(&pListen->Entry)) { + ep = CONTAINING_RECORD(RemoveHeadList(&pListen->Entry), WV_ENDPOINT, Entry); + ep->State = WvEpIdle; + WvEpPut(ep); + } + WdfObjectReleaseLock(pListen->Queue); +} + +void WvEpCancel(WV_PROVIDER *pProvider, WDFREQUEST Request) +{ + UINT64 *id; + WV_ENDPOINT *ep; + NTSTATUS status; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL); + if (!NT_SUCCESS(status)) { + goto out; + } + + ep = WvEpAcquire(pProvider, *id); + if (ep == NULL) { + status = STATUS_NOT_FOUND; + goto out; + } + + if (ep->State == WvEpListening) { + WvEpCancelListen(ep); + } else { + WvFlushQueue(ep->Queue, STATUS_CANCELLED); + } + WvEpRelease(ep); + +out: + WdfRequestComplete(Request, status); +} diff --git a/branches/WOF2-3/core/winverbs/kernel/wv_ep.h b/branches/WOF2-3/core/winverbs/kernel/wv_ep.h new file mode 100644 index 00000000..650b23c5 --- /dev/null +++ b/branches/WOF2-3/core/winverbs/kernel/wv_ep.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#ifndef _WV_EP_H_ +#define _WV_EP_H_ + +#include +#include + +#include "work_queue.h" +#include +#include +#include "wv_provider.h" +#include "wv_ioctl.h" + +typedef enum _WV_ENDPOINT_STATE +{ + WvEpIdle, + WvEpAddressBound, + WvEpListening, + WvEpQueued, + WvEpRouteResolved, + WvEpPassiveConnect, + WvEpActiveConnect, + WvEpConnected, + WvEpActiveDisconnect, + WvEpPassiveDisconnect, + WvEpDisconnected, + WvEpDestroying + +} WV_ENDPOINT_STATE; + +typedef struct _WV_ENDPOINT +{ + WV_PROVIDER *pProvider; + LIST_ENTRY Entry; + WV_ENDPOINT_STATE State; + + iba_cm_id *pIbCmId; + WV_IO_EP_ATTRIBUTES Attributes; + ib_path_rec_t Route; + + UINT16 EpType; + KEVENT Event; + LONG Ref; + WDFQUEUE Queue; + WV_WORK_ENTRY *pWork; + +} WV_ENDPOINT; + +void WvEpCreate(WV_PROVIDER *pProvider, WDFREQUEST Request); +void WvEpDestroy(WV_PROVIDER *pProvider, WDFREQUEST Request); +void WvEpFree(WV_ENDPOINT *pEndpoint); +void WvEpCancelListen(WV_ENDPOINT *pEndpoint); + +void WvEpQuery(WV_PROVIDER *pProvider, WDFREQUEST Request); +void WvEpModify(WV_PROVIDER *pProvider, WDFREQUEST Request); +void WvEpBind(WV_PROVIDER *pProvider, WDFREQUEST Request); +void WvEpCancel(WV_PROVIDER *pProvider, WDFREQUEST Request); + +void WvEpConnect(WV_PROVIDER *pProvider, WDFREQUEST Request); +void WvEpAccept(WV_PROVIDER *pProvider, WDFREQUEST Request); +void WvEpReject(WV_PROVIDER *pProvider, WDFREQUEST Request); +void WvEpDisconnect(WV_PROVIDER *pProvider, WDFREQUEST Request); +void WvEpDisconnectNotify(WV_PROVIDER *pProvider, WDFREQUEST Request); + +void WvEpListen(WV_PROVIDER *pProvider, WDFREQUEST Request); +void WvEpGetRequest(WV_PROVIDER *pProvider, WDFREQUEST Request); + +void WvEpLookup(WV_PROVIDER *pProvider, WDFREQUEST Request); +void WvEpMulticastJoin(WV_PROVIDER *pProvider, WDFREQUEST Request); +void WvEpMulticastLeave(WV_PROVIDER *pProvider, WDFREQUEST Request); + +#endif // _WV_EP_H_ diff --git a/branches/WOF2-3/core/winverbs/kernel/wv_pd.c b/branches/WOF2-3/core/winverbs/kernel/wv_pd.c new file mode 100644 index 00000000..af9a5509 --- /dev/null +++ b/branches/WOF2-3/core/winverbs/kernel/wv_pd.c @@ -0,0 +1,634 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "wv_pd.h" +#include "wv_srq.h" +#include "wv_qp.h" +#include "wv_ioctl.h" + +void WvPdGet(WV_PROTECTION_DOMAIN *pPd) +{ + InterlockedIncrement(&pPd->Ref); +} + +void WvPdPut(WV_PROTECTION_DOMAIN *pPd) +{ + if (InterlockedDecrement(&pPd->Ref) == 0) { + KeSetEvent(&pPd->Event, 0, FALSE); + } +} + +WV_PROTECTION_DOMAIN *WvPdAcquire(WV_PROVIDER *pProvider, UINT64 Id) +{ + WV_PROTECTION_DOMAIN *pd; + + KeAcquireGuardedMutex(&pProvider->Lock); + WvProviderDisableRemove(pProvider); + pd = IndexListAt(&pProvider->PdIndex, (SIZE_T) Id); + if (pd != NULL && pd->hVerbsPd != NULL) { + WvPdGet(pd); + } else { + pd = NULL; + WvProviderEnableRemove(pProvider); + } + KeReleaseGuardedMutex(&pProvider->Lock); + + return pd; +} + +void WvPdRelease(WV_PROTECTION_DOMAIN *pPd) +{ + WvProviderEnableRemove(pPd->pDevice->pProvider); + WvPdPut(pPd); +} + +static NTSTATUS WvPdAlloc(WV_DEVICE *pDevice, WV_PROTECTION_DOMAIN **ppPd, + ci_umv_buf_t *pVerbsData) +{ + ib_api_status_t ib_status; + WV_PROTECTION_DOMAIN *pd; + + pd = ExAllocatePoolWithTag(NonPagedPool, sizeof(WV_PROTECTION_DOMAIN), 'dpvw'); + if (pd == NULL) { + return STATUS_NO_MEMORY; + } + + pd->Ref = 1; + KeInitializeEvent(&pd->Event, NotificationEvent, FALSE); + InitializeListHead(&pd->QpList); + InitializeListHead(&pd->SrqList); + InitializeListHead(&pd->MwList); + InitializeListHead(&pd->AhList); + cl_qmap_init(&pd->MrMap); + KeInitializeGuardedMutex(&pd->Lock); + + ib_status = pDevice->pVerbs->allocate_pd(pDevice->hVerbsDevice, IB_PDT_NORMAL, + &pd->hVerbsPd, pVerbsData); + if (ib_status != IB_SUCCESS) { + goto err; + } + + WvDeviceGet(pDevice); + pd->pDevice = pDevice; + pd->pVerbs = pDevice->pVerbs; + *ppPd = pd; + return STATUS_SUCCESS; + +err: + ExFreePoolWithTag(pd, 'dpvw'); + return STATUS_UNSUCCESSFUL; +} + +void WvPdAllocate(WV_PROVIDER *pProvider, WDFREQUEST Request) +{ + WV_IO_ID *inid, *outid; + size_t inlen, outlen; + WV_DEVICE *dev; + WV_PROTECTION_DOMAIN *pd; + NTSTATUS status; + ci_umv_buf_t verbsData; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_ID), &inid, &inlen); + if (!NT_SUCCESS(status)) { + goto err1; + } + status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_ID), &outid, &outlen); + if (!NT_SUCCESS(status)) { + goto err1; + } + + dev = WvDeviceAcquire(pProvider, inid->Id); + if (dev == NULL) { + status = STATUS_NO_SUCH_DEVICE; + goto err1; + } + + WvInitVerbsData(&verbsData, inid->VerbInfo, inlen - sizeof(WV_IO_ID), + outlen - sizeof(WV_IO_ID), inid + 1); + status = WvPdAlloc(dev, &pd, &verbsData); + if (!NT_SUCCESS(status)) { + goto err2; + } + + KeAcquireGuardedMutex(&pProvider->Lock); + outid->Id = IndexListInsertHead(&pProvider->PdIndex, pd); + if (outid->Id == 0) { + status = STATUS_NO_MEMORY; + goto err3; + } + InsertHeadList(&dev->PdList, &pd->Entry); + KeReleaseGuardedMutex(&pProvider->Lock); + + WvDeviceRelease(dev); + outid->VerbInfo = verbsData.status; + WdfRequestCompleteWithInformation(Request, status, outlen); + return; + +err3: + KeReleaseGuardedMutex(&pProvider->Lock); + WvPdFree(pd); +err2: + WvDeviceRelease(dev); +err1: + WdfRequestComplete(Request, status); +} + +void WvPdDeallocate(WV_PROVIDER *pProvider, WDFREQUEST Request) +{ + WV_PROTECTION_DOMAIN *pd; + UINT64 *id; + NTSTATUS status; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL); + if (!NT_SUCCESS(status)) { + goto out; + } + + KeAcquireGuardedMutex(&pProvider->Lock); + WvProviderDisableRemove(pProvider); + pd = IndexListAt(&pProvider->PdIndex, (SIZE_T) *id); + if (pd == NULL) { + status = STATUS_NOT_FOUND; + } else if (pd->Ref > 1) { + status = STATUS_ACCESS_DENIED; + } else { + IndexListRemove(&pProvider->PdIndex, (SIZE_T) *id); + RemoveEntryList(&pd->Entry); + status = STATUS_SUCCESS; + } + KeReleaseGuardedMutex(&pProvider->Lock); + + if (NT_SUCCESS(status)) { + WvPdFree(pd); + } + WvProviderEnableRemove(pProvider); +out: + WdfRequestComplete(Request, status); +} + +void WvPdCancel(WV_PROVIDER *pProvider, WDFREQUEST Request) +{ + WV_PROTECTION_DOMAIN *pd; + UINT64 *id; + NTSTATUS status; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL); + if (!NT_SUCCESS(status)) { + goto complete; + } + + pd = WvPdAcquire(pProvider, *id); + if (pd == NULL) { + status = STATUS_NOT_FOUND; + goto complete; + } + + // Registration is currently synchronous - nothing to do. + WvPdRelease(pd); + +complete: + WdfRequestComplete(Request, status); +} + +void WvPdFree(WV_PROTECTION_DOMAIN *pPd) +{ + WV_MEMORY_REGION *mr; + cl_map_item_t *item; + + if (InterlockedDecrement(&pPd->Ref) > 0) { + KeWaitForSingleObject(&pPd->Event, Executive, KernelMode, FALSE, NULL); + } + + for (item = cl_qmap_head(&pPd->MrMap); item != cl_qmap_end(&pPd->MrMap); + item = cl_qmap_head(&pPd->MrMap)) { + mr = CONTAINING_RECORD(item, WV_MEMORY_REGION, Item); + if (mr->hVerbsMr != NULL) { + pPd->pVerbs->deregister_mr(mr->hVerbsMr); + } + + cl_qmap_remove_item(&pPd->MrMap, &mr->Item); + ExFreePoolWithTag(mr, 'rmvw'); + } + + if (pPd->hVerbsPd != NULL) { + pPd->pVerbs->deallocate_pd(pPd->hVerbsPd); + } + + WvDevicePut(pPd->pDevice); + ExFreePoolWithTag(pPd, 'dpvw'); +} + +void WvPdRemoveHandler(WV_PROTECTION_DOMAIN *pPd) +{ + WV_QUEUE_PAIR *qp; + WV_SHARED_RECEIVE_QUEUE *srq; + WV_MEMORY_REGION *mr; + WV_ADDRESS_HANDLE *ah; + WV_MEMORY_WINDOW *mw; + cl_map_item_t *item; + LIST_ENTRY *entry; + + for (entry = pPd->MwList.Flink; entry != &pPd->MwList; entry = entry->Flink) { + mw = CONTAINING_RECORD(entry, WV_MEMORY_WINDOW, Entry); + pPd->pVerbs->destroy_mw(mw->hVerbsMw); + mw->hVerbsMw = NULL; + } + + for (entry = pPd->AhList.Flink; entry != &pPd->AhList; entry = entry->Flink) { + ah = CONTAINING_RECORD(entry, WV_ADDRESS_HANDLE, Entry); + pPd->pVerbs->destroy_av(ah->hVerbsAh); + ah->hVerbsAh = NULL; + } + + for (item = cl_qmap_head(&pPd->MrMap); item != cl_qmap_end(&pPd->MrMap); + item = cl_qmap_next(item)) { + mr = CONTAINING_RECORD(item, WV_MEMORY_REGION, Item); + pPd->pVerbs->deregister_mr(mr->hVerbsMr); + mr->hVerbsMr = NULL; + } + + for (entry = pPd->QpList.Flink; entry != &pPd->QpList; entry = entry->Flink) { + qp = CONTAINING_RECORD(entry, WV_QUEUE_PAIR, Entry); + WvQpRemoveHandler(qp); + } + + for (entry = pPd->SrqList.Flink; entry != &pPd->SrqList; entry = entry->Flink) { + srq = CONTAINING_RECORD(entry, WV_SHARED_RECEIVE_QUEUE, Entry); + pPd->pVerbs->destroy_srq(srq->hVerbsSrq); + srq->hVerbsSrq = NULL; + srq->pVerbs = NULL; + } + + pPd->pVerbs->deallocate_pd(pPd->hVerbsPd); + pPd->pVerbs = NULL; + pPd->hVerbsPd = NULL; +} + +void WvMrRegister(WV_PROVIDER *pProvider, WDFREQUEST Request) +{ + WV_IO_MEMORY_REGISTER *reg; + WV_IO_MEMORY_KEYS *keys; + WV_PROTECTION_DOMAIN *pd; + WV_MEMORY_REGION *mr; + ib_mr_create_t attr; + NTSTATUS status; + ib_api_status_t ib_status; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_MEMORY_REGISTER), + ®, NULL); + if (!NT_SUCCESS(status)) { + goto err1; + } + status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_MEMORY_KEYS), + &keys, NULL); + if (!NT_SUCCESS(status)) { + goto err1; + } + + pd = WvPdAcquire(pProvider, reg->Id); + if (pd == NULL) { + status = STATUS_NOT_FOUND; + goto err1; + } + + mr = ExAllocatePoolWithTag(PagedPool, sizeof(WV_MEMORY_REGION), 'rmvw'); + if (mr == NULL) { + status = STATUS_NO_MEMORY; + goto err2; + } + + attr.access_ctrl = reg->AccessFlags; + attr.length = reg->BufferLength; + attr.vaddr = (void *) (ULONG_PTR) reg->Address; + ib_status = pd->pVerbs->register_mr(pd->hVerbsPd, &attr, &keys->Lkey, + &keys->Rkey, &mr->hVerbsMr, TRUE); + if (ib_status != IB_SUCCESS) { + status = STATUS_UNSUCCESSFUL; + goto err3; + } + + KeAcquireGuardedMutex(&pd->Lock); + cl_qmap_insert(&pd->MrMap, keys->Lkey, &mr->Item); + KeReleaseGuardedMutex(&pd->Lock); + + WvPdRelease(pd); + WdfRequestCompleteWithInformation(Request, status, sizeof(WV_IO_MEMORY_KEYS)); + return; + +err3: + ExFreePoolWithTag(mr, 'rmvw'); +err2: + WvPdRelease(pd); +err1: + WdfRequestComplete(Request, status); +} + +void WvMrDeregister(WV_PROVIDER *pProvider, WDFREQUEST Request) +{ + WV_IO_ID *id; + WV_PROTECTION_DOMAIN *pd; + WV_MEMORY_REGION *mr; + cl_map_item_t *item; + NTSTATUS status; + ib_api_status_t ib_status; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_ID), &id, NULL); + if (!NT_SUCCESS(status)) { + goto complete; + } + + pd = WvPdAcquire(pProvider, id->Id); + if (pd == NULL) { + status = STATUS_NOT_FOUND; + goto complete; + } + + KeAcquireGuardedMutex(&pd->Lock); + item = cl_qmap_remove(&pd->MrMap, id->Data); + KeReleaseGuardedMutex(&pd->Lock); + + if (item == cl_qmap_end(&pd->MrMap)) { + status = STATUS_NOT_FOUND; + goto release; + } + + mr = CONTAINING_RECORD(item, WV_MEMORY_REGION, Item); + + ib_status = pd->pVerbs->deregister_mr(mr->hVerbsMr); + if (ib_status != IB_SUCCESS) { + status = STATUS_UNSUCCESSFUL; + KeAcquireGuardedMutex(&pd->Lock); + cl_qmap_insert(&pd->MrMap, id->Data, &mr->Item); + KeReleaseGuardedMutex(&pd->Lock); + goto release; + } + + ExFreePoolWithTag(mr, 'rmvw'); +release: + WvPdRelease(pd); +complete: + WdfRequestComplete(Request, status); +} + +void WvMwAllocate(WV_PROVIDER *pProvider, WDFREQUEST Request) +{ + WV_IO_ID *inid, *outid; + size_t inlen, outlen; + WV_PROTECTION_DOMAIN *pd; + WV_MEMORY_WINDOW *mw; + NTSTATUS status; + ib_api_status_t ib_status; + ci_umv_buf_t verbsData; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_ID), &inid, &inlen); + if (!NT_SUCCESS(status)) { + goto err1; + } + status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_ID), &outid, &outlen); + if (!NT_SUCCESS(status)) { + goto err1; + } + + pd = WvPdAcquire(pProvider, inid->Id); + if (pd == NULL) { + status = STATUS_NOT_FOUND; + goto err1; + } + + mw = ExAllocatePoolWithTag(PagedPool, sizeof(WV_MEMORY_WINDOW), 'wmvw'); + if (mw == NULL) { + status = STATUS_NO_MEMORY; + goto err2; + } + + WvPdGet(pd); + mw->pPd = pd; + + WvInitVerbsData(&verbsData, inid->VerbInfo, inlen - sizeof(WV_IO_ID), + outlen - sizeof(WV_IO_ID), inid + 1); + ib_status = pd->pVerbs->create_mw(pd->hVerbsPd, &outid->Data, &mw->hVerbsMw, + &verbsData); + if (ib_status != IB_SUCCESS) { + status = STATUS_UNSUCCESSFUL; + goto err3; + } + + KeAcquireGuardedMutex(&pProvider->Lock); + outid->Id = IndexListInsertHead(&pProvider->MwIndex, mw); + if (outid->Id == 0) { + status = STATUS_NO_MEMORY; + goto err4; + } + InsertHeadList(&pd->MwList, &mw->Entry); + KeReleaseGuardedMutex(&pProvider->Lock); + + WvPdRelease(pd); + outid->VerbInfo = verbsData.status; + WdfRequestCompleteWithInformation(Request, status, outlen); + return; + +err4: + KeReleaseGuardedMutex(&pProvider->Lock); +err3: + WvMwFree(mw); +err2: + WvPdRelease(pd); +err1: + WdfRequestComplete(Request, status); +} + +void WvMwDeallocate(WV_PROVIDER *pProvider, WDFREQUEST Request) +{ + WV_MEMORY_WINDOW *mw; + UINT64 *id; + NTSTATUS status; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL); + if (!NT_SUCCESS(status)) { + goto out; + } + + KeAcquireGuardedMutex(&pProvider->Lock); + WvProviderDisableRemove(pProvider); + mw = IndexListAt(&pProvider->MwIndex, (SIZE_T) *id); + if (mw == NULL) { + status = STATUS_NOT_FOUND; + } else { + IndexListRemove(&pProvider->MwIndex, (SIZE_T) *id); + RemoveEntryList(&mw->Entry); + status = STATUS_SUCCESS; + } + KeReleaseGuardedMutex(&pProvider->Lock); + + if (NT_SUCCESS(status)) { + WvMwFree(mw); + } + WvProviderEnableRemove(pProvider); +out: + WdfRequestComplete(Request, status); +} + +void WvMwFree(WV_MEMORY_WINDOW *pMw) +{ + if (pMw->hVerbsMw != NULL) { + pMw->pPd->pVerbs->destroy_mw(pMw->hVerbsMw); + } + + WvPdPut(pMw->pPd); + ExFreePoolWithTag(pMw, 'wmvw'); +} + +static void WvVerbsConvertAv(ib_av_attr_t *pVerbsAv, WV_IO_AV *pAv) +{ + pVerbsAv->grh_valid = pAv->NetworkRouteValid; + if (pVerbsAv->grh_valid) { + pVerbsAv->grh.ver_class_flow = + RtlUlongByteSwap(RtlUlongByteSwap(pAv->FlowLabel) | (pAv->TrafficClass << 20)); + pVerbsAv->grh.hop_limit = pAv->HopLimit; + RtlCopyMemory(&pVerbsAv->grh.src_gid, pAv->SGid, sizeof(pAv->SGid)); + RtlCopyMemory(&pVerbsAv->grh.dest_gid, pAv->DGid, sizeof(pAv->DGid)); + } + + pVerbsAv->port_num = pAv->PortNumber; + pVerbsAv->sl = pAv->ServiceLevel; + pVerbsAv->dlid = pAv->DLid; + pVerbsAv->static_rate = pAv->StaticRate; + pVerbsAv->path_bits = pAv->SourcePathBits; +} + +void WvAhCreate(WV_PROVIDER *pProvider, WDFREQUEST Request) +{ + size_t inlen, outlen; + WV_PROTECTION_DOMAIN *pd; + WV_ADDRESS_HANDLE *ah; + WV_IO_AH_CREATE *pinAv, *poutAv; + ib_av_attr_t av; + NTSTATUS status; + ib_api_status_t ib_status; + ci_umv_buf_t verbsData; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_AH_CREATE), + &pinAv, &inlen); + if (!NT_SUCCESS(status)) { + goto err1; + } + status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_AH_CREATE), + &poutAv, &outlen); + if (!NT_SUCCESS(status)) { + goto err1; + } + + pd = WvPdAcquire(pProvider, pinAv->Id.Id); + if (pd == NULL) { + status = STATUS_NOT_FOUND; + goto err1; + } + + ah = ExAllocatePoolWithTag(PagedPool, sizeof(WV_ADDRESS_HANDLE), 'havw'); + if (ah == NULL) { + status = STATUS_NO_MEMORY; + goto err2; + } + + WvPdGet(pd); + ah->pPd = pd; + + WvVerbsConvertAv(&av, &pinAv->AddressVector); + WvInitVerbsData(&verbsData, pinAv->Id.VerbInfo, inlen - sizeof(WV_IO_AH_CREATE), + outlen - sizeof(WV_IO_AH_CREATE), pinAv + 1); + ib_status = pd->pVerbs->create_av(pd->hVerbsPd, &av, &ah->hVerbsAh, &verbsData); + if (ib_status != IB_SUCCESS) { + status = STATUS_UNSUCCESSFUL; + goto err3; + } + + KeAcquireGuardedMutex(&pProvider->Lock); + poutAv->Id.Id = IndexListInsertHead(&pProvider->AhIndex, ah); + if (poutAv->Id.Id == 0) { + status = STATUS_NO_MEMORY; + goto err4; + } + InsertHeadList(&pd->AhList, &ah->Entry); + KeReleaseGuardedMutex(&pProvider->Lock); + + WvPdRelease(pd); + poutAv->Id.VerbInfo = verbsData.status; + WdfRequestCompleteWithInformation(Request, status, outlen); + return; + +err4: + KeReleaseGuardedMutex(&pProvider->Lock); +err3: + WvAhFree(ah); +err2: + WvPdRelease(pd); +err1: + WdfRequestComplete(Request, status); +} + +void WvAhDestroy(WV_PROVIDER *pProvider, WDFREQUEST Request) +{ + WV_ADDRESS_HANDLE *ah; + UINT64 *id; + NTSTATUS status; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL); + if (!NT_SUCCESS(status)) { + goto out; + } + + KeAcquireGuardedMutex(&pProvider->Lock); + WvProviderDisableRemove(pProvider); + ah = IndexListAt(&pProvider->AhIndex, (SIZE_T) *id); + if (ah == NULL) { + status = STATUS_NOT_FOUND; + } else { + IndexListRemove(&pProvider->AhIndex, (SIZE_T) *id); + RemoveEntryList(&ah->Entry); + status = STATUS_SUCCESS; + } + KeReleaseGuardedMutex(&pProvider->Lock); + + if (NT_SUCCESS(status)) { + WvAhFree(ah); + } + WvProviderEnableRemove(pProvider); +out: + WdfRequestComplete(Request, status); +} + +void WvAhFree(WV_ADDRESS_HANDLE *pAh) +{ + if (pAh->hVerbsAh != NULL) { + pAh->pPd->pVerbs->destroy_av(pAh->hVerbsAh); + } + + WvPdPut(pAh->pPd); + ExFreePoolWithTag(pAh, 'havw'); +} diff --git a/branches/WOF2-3/core/winverbs/kernel/wv_pd.h b/branches/WOF2-3/core/winverbs/kernel/wv_pd.h new file mode 100644 index 00000000..f30cf4e5 --- /dev/null +++ b/branches/WOF2-3/core/winverbs/kernel/wv_pd.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#ifndef _WV_PD_H_ +#define _WV_PD_H_ + +#include +#include +#include +#include + +#include "wv_device.h" +#include "wv_provider.h" + +typedef struct _WV_PROTECTION_DOMAIN +{ + WV_DEVICE *pDevice; + ci_interface_t *pVerbs; + ib_pd_handle_t hVerbsPd; + LIST_ENTRY Entry; + + LIST_ENTRY QpList; + LIST_ENTRY SrqList; + LIST_ENTRY MwList; + LIST_ENTRY AhList; + KGUARDED_MUTEX Lock; + cl_qmap_t MrMap; + + KEVENT Event; + LONG Ref; + +} WV_PROTECTION_DOMAIN; + +WV_PROTECTION_DOMAIN *WvPdAcquire(WV_PROVIDER *pProvider, UINT64 Id); +void WvPdRelease(WV_PROTECTION_DOMAIN *pPd); +void WvPdGet(WV_PROTECTION_DOMAIN *pPd); +void WvPdPut(WV_PROTECTION_DOMAIN *pPd); + +void WvPdAllocate(WV_PROVIDER *pProvider, WDFREQUEST Request); +void WvPdDeallocate(WV_PROVIDER *pProvider, WDFREQUEST Request); +void WvPdCancel(WV_PROVIDER *pProvider, WDFREQUEST Request); +void WvPdFree(WV_PROTECTION_DOMAIN *pPd); +void WvPdRemoveHandler(WV_PROTECTION_DOMAIN *pPd); + + +typedef struct _WV_MEMORY_REGION +{ + ib_mr_handle_t hVerbsMr; + cl_map_item_t Item; + +} WV_MEMORY_REGION; + +void WvMrRegister(WV_PROVIDER *pProvider, WDFREQUEST Request); +void WvMrDeregister(WV_PROVIDER *pProvider, WDFREQUEST Request); + + +typedef struct _WV_MEMORY_WINDOW +{ + WV_PROTECTION_DOMAIN *pPd; + ib_mw_handle_t hVerbsMw; + LIST_ENTRY Entry; + +} WV_MEMORY_WINDOW; + +void WvMwAllocate(WV_PROVIDER *pProvider, WDFREQUEST Request); +void WvMwDeallocate(WV_PROVIDER *pProvider, WDFREQUEST Request); +void WvMwFree(WV_MEMORY_WINDOW *pMw); + + +typedef struct _WV_ADDRESS_HANDLE +{ + WV_PROTECTION_DOMAIN *pPd; + ib_av_handle_t hVerbsAh; + LIST_ENTRY Entry; + +} WV_ADDRESS_HANDLE; + +void WvAhCreate(WV_PROVIDER *pProvider, WDFREQUEST Request); +void WvAhDestroy(WV_PROVIDER *pProvider, WDFREQUEST Request); +void WvAhFree(WV_ADDRESS_HANDLE *pAh); + +#endif // _WV_PD_H_ diff --git a/branches/WOF2-3/core/winverbs/kernel/wv_provider.c b/branches/WOF2-3/core/winverbs/kernel/wv_provider.c new file mode 100644 index 00000000..d8b83f9b --- /dev/null +++ b/branches/WOF2-3/core/winverbs/kernel/wv_provider.c @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include + +#include "work_queue.c" +#include +#include "wv_driver.h" +#include "wv_ioctl.h" +#include "wv_provider.h" +#include "wv_device.h" +#include "wv_pd.h" +#include "wv_srq.h" +#include "wv_cq.h" +#include "wv_qp.h" +#include "wv_ep.h" + +void WvProviderGet(WV_PROVIDER *pProvider) +{ + InterlockedIncrement(&pProvider->Ref); +} + +void WvProviderPut(WV_PROVIDER *pProvider) +{ + if (InterlockedDecrement(&pProvider->Ref) == 0) { + KeSetEvent(&pProvider->Event, 0, FALSE); + } +} + +// See comment above WvProviderRemoveHandler. +static void WvProviderLockRemove(WV_PROVIDER *pProvider) +{ + KeAcquireGuardedMutex(&pProvider->Lock); + pProvider->Exclusive++; + KeClearEvent(&pProvider->SharedEvent); + while (pProvider->Active > 0) { + KeReleaseGuardedMutex(&pProvider->Lock); + KeWaitForSingleObject(&pProvider->ExclusiveEvent, Executive, KernelMode, + FALSE, NULL); + KeAcquireGuardedMutex(&pProvider->Lock); + } + pProvider->Active++; + KeReleaseGuardedMutex(&pProvider->Lock); +} + +// See comment above WvProviderRemoveHandler. +static void WvProviderUnlockRemove(WV_PROVIDER *pProvider) +{ + KeAcquireGuardedMutex(&pProvider->Lock); + pProvider->Exclusive--; + pProvider->Active--; + if (pProvider->Exclusive > 0) { + KeSetEvent(&pProvider->ExclusiveEvent, 0, FALSE); + } else if (pProvider->Pending > 0) { + KeSetEvent(&pProvider->SharedEvent, 0, FALSE); + } + KeReleaseGuardedMutex(&pProvider->Lock); +} + +NTSTATUS WvProviderInit(WDFDEVICE Device, WV_PROVIDER *pProvider) +{ + NTSTATUS status; + + status = WorkQueueInit(&pProvider->WorkQueue, WdfDeviceWdmGetDeviceObject(Device), 0); + if (!NT_SUCCESS(status)) { + return status; + } + + IndexListInit(&pProvider->DevIndex); + IndexListInit(&pProvider->CqIndex); + IndexListInit(&pProvider->PdIndex); + IndexListInit(&pProvider->SrqIndex); + IndexListInit(&pProvider->QpIndex); + IndexListInit(&pProvider->MwIndex); + IndexListInit(&pProvider->AhIndex); + IndexListInit(&pProvider->EpIndex); + + KeInitializeGuardedMutex(&pProvider->Lock); + pProvider->Ref = 1; + KeInitializeEvent(&pProvider->Event, NotificationEvent, FALSE); + + pProvider->Pending = 0; + pProvider->Active = 0; + KeInitializeEvent(&pProvider->SharedEvent, NotificationEvent, FALSE); + pProvider->Exclusive = 0; + KeInitializeEvent(&pProvider->ExclusiveEvent, SynchronizationEvent, FALSE); + return STATUS_SUCCESS; +} + +/* + * We could be processing asynchronous requests or have them queued + * when cleaning up. To synchronize with async request processing, + * acquire the provider lock with exclusive access until we're done + * destroying all resoureces. This will allow active requests to + * complete their processing, but prevent queued requests from + * running until cleanup is done. At that point, queue requests will + * be unable to acquire any winverbs resources. + */ + +void WvProviderCleanup(WV_PROVIDER *pProvider) +{ + WV_DEVICE *dev; + WV_COMPLETION_QUEUE *cq; + WV_PROTECTION_DOMAIN *pd; + WV_SHARED_RECEIVE_QUEUE *srq; + WV_QUEUE_PAIR *qp; + WV_MEMORY_WINDOW *mw; + WV_ADDRESS_HANDLE *ah; + WV_ENDPOINT *ep; + SIZE_T i; + + WvProviderLockRemove(pProvider); + IndexListForEach(&pProvider->EpIndex, i) { + ep = (WV_ENDPOINT *) IndexListAt(&pProvider->EpIndex, i); + if (ep->State == WvEpListening) { + WvEpCancelListen(ep); + } + } + while ((ep = IndexListRemoveHead(&pProvider->EpIndex)) != NULL) { + WvEpFree(ep); + } + while ((ah = IndexListRemoveHead(&pProvider->AhIndex)) != NULL) { + RemoveEntryList(&ah->Entry); + WvAhFree(ah); + } + while ((mw = IndexListRemoveHead(&pProvider->MwIndex)) != NULL) { + RemoveEntryList(&mw->Entry); + WvMwFree(mw); + } + while ((qp = IndexListRemoveHead(&pProvider->QpIndex)) != NULL) { + RemoveEntryList(&qp->Entry); + WvQpFree(qp); + } + while ((srq = IndexListRemoveHead(&pProvider->SrqIndex)) != NULL) { + RemoveEntryList(&srq->Entry); + WvSrqFree(srq); + } + while ((pd = IndexListRemoveHead(&pProvider->PdIndex)) != NULL) { + RemoveEntryList(&pd->Entry); + WvPdFree(pd); + } + while ((cq = IndexListRemoveHead(&pProvider->CqIndex)) != NULL) { + RemoveEntryList(&cq->Entry); + WvCqFree(cq); + } + while ((dev = IndexListRemoveHead(&pProvider->DevIndex)) != NULL) { + WvDeviceFree(dev); + } + WvProviderUnlockRemove(pProvider); + + if (InterlockedDecrement(&pProvider->Ref) > 0) { + KeWaitForSingleObject(&pProvider->Event, Executive, KernelMode, FALSE, NULL); + } + + IndexListDestroy(&pProvider->EpIndex); + IndexListDestroy(&pProvider->AhIndex); + IndexListDestroy(&pProvider->MwIndex); + IndexListDestroy(&pProvider->QpIndex); + IndexListDestroy(&pProvider->SrqIndex); + IndexListDestroy(&pProvider->PdIndex); + IndexListDestroy(&pProvider->CqIndex); + IndexListDestroy(&pProvider->DevIndex); + WorkQueueDestroy(&pProvider->WorkQueue); +} + +/* + * Must hold pProvider->Lock. Function may release and re-acquire. + * See comment above WvProviderRemoveHandler. + */ +void WvProviderDisableRemove(WV_PROVIDER *pProvider) +{ + while (pProvider->Exclusive > 0) { + pProvider->Pending++; + KeReleaseGuardedMutex(&pProvider->Lock); + KeWaitForSingleObject(&pProvider->SharedEvent, Executive, KernelMode, + FALSE, NULL); + KeAcquireGuardedMutex(&pProvider->Lock); + pProvider->Pending--; + } + InterlockedIncrement(&pProvider->Active); +} + +/* + * No need to hold pProvider->Lock when releasing. + * See comment above WvProviderRemoveHandler. + */ +void WvProviderEnableRemove(WV_PROVIDER *pProvider) +{ + InterlockedDecrement(&pProvider->Active); + if (pProvider->Exclusive > 0) { + KeSetEvent(&pProvider->ExclusiveEvent, 0, FALSE); + } +} + +/* + * The remove handler blocks all other threads executing through this + * provider until the remove has been processed. Because device removal is + * rare, we want a simple, optimized code path for all calls that access + * the underlying hardware device, making use of any locks that we would + * have to acquire anyway. The locking for exclusive access can be + * as ugly and slow as needed. + */ +void WvProviderRemoveHandler(WV_PROVIDER *pProvider, WV_RDMA_DEVICE *pDevice) +{ + WV_DEVICE *dev; + SIZE_T i; + + WvProviderLockRemove(pProvider); + IndexListForEach(&pProvider->DevIndex, i) { + dev = IndexListAt(&pProvider->DevIndex, i); + if (dev->pDevice == pDevice) { + WvDeviceRemoveHandler(dev); + } + } + WvProviderUnlockRemove(pProvider); +} diff --git a/branches/WOF2-3/core/winverbs/kernel/wv_provider.h b/branches/WOF2-3/core/winverbs/kernel/wv_provider.h new file mode 100644 index 00000000..bd430fb0 --- /dev/null +++ b/branches/WOF2-3/core/winverbs/kernel/wv_provider.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#ifndef _WV_PROVIDER_H_ +#define _WV_PROVIDER_H_ + +#include +#include +#include + +#include "work_queue.h" +#include +#include "wv_driver.h" +#include "index_list.h" + +struct _WV_DEVICE; +struct _WV_PROTECTION_DOMAIN; + +typedef struct _WV_WORK_ENTRY +{ + WORK_ENTRY Work; + UINT64 Id; + +} WV_WORK_ENTRY; + +static void WvWorkEntryInit(WV_WORK_ENTRY *pWork, UINT64 Id, + void (*WorkHandler)(WORK_ENTRY *Work), void *Context) +{ + pWork->Id = Id; + WorkEntryInit(&pWork->Work, WorkHandler, Context); +} + +typedef struct _WV_PROVIDER +{ + LIST_ENTRY Entry; + INDEX_LIST DevIndex; + INDEX_LIST CqIndex; + INDEX_LIST PdIndex; + INDEX_LIST SrqIndex; + INDEX_LIST QpIndex; + INDEX_LIST MwIndex; + INDEX_LIST AhIndex; + INDEX_LIST EpIndex; + + KGUARDED_MUTEX Lock; + LONG Ref; + KEVENT Event; + LONG Pending; + LONG Active; + KEVENT SharedEvent; + LONG Exclusive; + KEVENT ExclusiveEvent; + + WORK_QUEUE WorkQueue; + +} WV_PROVIDER; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(WV_PROVIDER, WvProviderGetContext) + +void WvProviderGet(WV_PROVIDER *pProvider); +void WvProviderPut(WV_PROVIDER *pProvider); +NTSTATUS WvProviderInit(WDFDEVICE Device, WV_PROVIDER *pProvider); +void WvProviderCleanup(WV_PROVIDER *pProvider); + +void WvProviderRemoveHandler(WV_PROVIDER *pProvider, WV_RDMA_DEVICE *pDevice); +void WvProviderDisableRemove(WV_PROVIDER *pProvider); +void WvProviderEnableRemove(WV_PROVIDER *pProvider); + +#endif // _WV_PROVIDER_H_ diff --git a/branches/WOF2-3/core/winverbs/kernel/wv_qp.c b/branches/WOF2-3/core/winverbs/kernel/wv_qp.c new file mode 100644 index 00000000..8ad87e5b --- /dev/null +++ b/branches/WOF2-3/core/winverbs/kernel/wv_qp.c @@ -0,0 +1,762 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "wv_qp.h" +#include "wv_ioctl.h" + +typedef struct _WV_MULTICAST +{ + LIST_ENTRY Entry; + WV_IO_GID Gid; + NET16 Lid; + ib_mcast_handle_t hVerbsMc; + +} WV_MULTICAST; + +static void WvVerbsConvertCreate(ib_qp_create_t *pVerbsAttr, + WV_IO_QP_CREATE *pAttr, WV_QUEUE_PAIR *pQp) +{ + pVerbsAttr->h_sq_cq = pQp->pSendCq->hVerbsCq; + pVerbsAttr->h_rq_cq = pQp->pReceiveCq->hVerbsCq; + pVerbsAttr->h_srq = (pQp->pSrq != NULL) ? pQp->pSrq->hVerbsSrq : NULL; + + pVerbsAttr->qp_type = (ib_qp_type_t) pAttr->QpType; + pVerbsAttr->sq_max_inline = pAttr->MaxInlineSend; + pVerbsAttr->sq_depth = pAttr->SendDepth; + pVerbsAttr->rq_depth = pAttr->ReceiveDepth; + pVerbsAttr->sq_sge = pAttr->SendSge; + pVerbsAttr->rq_sge = pAttr->ReceiveSge; + + pVerbsAttr->sq_signaled = ((pAttr->QpFlags & WV_IO_QP_SIGNAL_SENDS) != 0); +} + +static UINT8 WvQpStateConvertVerbs(ib_qp_state_t State) +{ + switch (State) { + case IB_QPS_RESET: return WV_IO_QP_STATE_RESET; + case IB_QPS_INIT: return WV_IO_QP_STATE_INIT; + case IB_QPS_RTR: return WV_IO_QP_STATE_RTR; + case IB_QPS_RTS: return WV_IO_QP_STATE_RTS; + case IB_QPS_SQD: return WV_IO_QP_STATE_SQD; + case IB_QPS_SQERR: return WV_IO_QP_STATE_SQERROR; + default: return WV_IO_QP_STATE_ERROR; + } +} + +static UINT8 WvVerbsConvertMtu(UINT32 Mtu) +{ + switch (Mtu) { + case 256: return IB_MTU_LEN_256; + case 512: return IB_MTU_LEN_512; + case 1024: return IB_MTU_LEN_1024; + case 2048: return IB_MTU_LEN_2048; + case 4096: return IB_MTU_LEN_4096; + default: return 0; + } +} +static void WvAvConvertVerbs(WV_IO_AV *pAv, ib_av_attr_t *pVerbsAv) +{ + pAv->NetworkRouteValid = (uint8_t) pVerbsAv->grh_valid; + if (pAv->NetworkRouteValid) { + pAv->FlowLabel = pVerbsAv->grh.ver_class_flow & RtlUlongByteSwap(0x000FFFFF); + pAv->TrafficClass = (UINT8) (RtlUlongByteSwap(pVerbsAv->grh.ver_class_flow) >> 20); + pAv->HopLimit = pVerbsAv->grh.hop_limit; + RtlCopyMemory(pAv->SGid, &pVerbsAv->grh.src_gid, sizeof(pAv->SGid)); + RtlCopyMemory(pAv->DGid, &pVerbsAv->grh.dest_gid, sizeof(pAv->DGid)); + } + + pAv->PortNumber = pVerbsAv->port_num; + pAv->ServiceLevel = pVerbsAv->sl; + pAv->DLid = pVerbsAv->dlid; + pAv->StaticRate = pVerbsAv->static_rate; + pAv->SourcePathBits = pVerbsAv->path_bits; +} + +static void WvVerbsConvertAv(ib_av_attr_t *pVerbsAv, WV_IO_AV *pAv, + WV_IO_QP_ATTRIBUTES *pAttr) +{ + pVerbsAv->grh_valid = pAv->NetworkRouteValid; + if (pVerbsAv->grh_valid) { + pVerbsAv->grh.ver_class_flow = + RtlUlongByteSwap(RtlUlongByteSwap(pAv->FlowLabel) | (pAv->TrafficClass << 20)); + pVerbsAv->grh.hop_limit = pAv->HopLimit; + RtlCopyMemory(&pVerbsAv->grh.src_gid, pAv->SGid, sizeof(pAv->SGid)); + RtlCopyMemory(&pVerbsAv->grh.dest_gid, pAv->DGid, sizeof(pAv->DGid)); + } + + pVerbsAv->port_num = pAv->PortNumber; + pVerbsAv->sl = pAv->ServiceLevel; + pVerbsAv->dlid = pAv->DLid; + pVerbsAv->static_rate = pAv->StaticRate; + pVerbsAv->path_bits = pAv->SourcePathBits; + + pVerbsAv->conn.path_mtu = WvVerbsConvertMtu(pAttr->PathMtu); + pVerbsAv->conn.local_ack_timeout = pAttr->LocalAckTimeout; + pVerbsAv->conn.seq_err_retry_cnt = pAttr->SequenceErrorRetryCount; + pVerbsAv->conn.rnr_retry_cnt = pAttr->RnrRetryCount; +} + +static void WvQpAttrConvertVerbs(WV_IO_QP_ATTRIBUTES *pAttr, ib_qp_attr_t *pVerbsAttr) +{ + pAttr->MaxInlineSend = pVerbsAttr->sq_max_inline; + pAttr->SendDepth = pVerbsAttr->sq_depth; + pAttr->ReceiveDepth = pVerbsAttr->rq_depth; + pAttr->SendSge = pVerbsAttr->sq_sge; + pAttr->ReceiveSge = pVerbsAttr->rq_sge; + pAttr->InitiatorDepth = pVerbsAttr->init_depth; + pAttr->ResponderResources = pVerbsAttr->resp_res; + + pAttr->Options = 0; + pAttr->QpType = pVerbsAttr->qp_type; + pAttr->CurrentQpState = WvQpStateConvertVerbs(pVerbsAttr->state); + pAttr->QpState = pAttr->CurrentQpState; + pAttr->ApmState = pVerbsAttr->apm_state; + pAttr->Qpn = pVerbsAttr->num; + pAttr->DestinationQpn = pVerbsAttr->dest_num; + pAttr->Qkey = pVerbsAttr->qkey; + pAttr->SendPsn = pVerbsAttr->sq_psn; + pAttr->ReceivePsn = pVerbsAttr->rq_psn; + + pAttr->QpFlags = pVerbsAttr->sq_signaled ? WV_IO_QP_SIGNAL_SENDS : 0; + pAttr->AccessFlags = (UINT8) pVerbsAttr->access_ctrl; + + pAttr->AddressVector.PortNumber = pVerbsAttr->primary_port; + pAttr->AlternateAddressVector.PortNumber = pVerbsAttr->alternate_port; + WvAvConvertVerbs(&pAttr->AddressVector, &pVerbsAttr->primary_av); + WvAvConvertVerbs(&pAttr->AlternateAddressVector, &pVerbsAttr->alternate_av); + pAttr->PathMtu = 0x80 << pVerbsAttr->primary_av.conn.path_mtu; + pAttr->AlternatePathMtu = 0x80 << pVerbsAttr->alternate_av.conn.path_mtu; + pAttr->PkeyIndex = pVerbsAttr->pkey_index; + pAttr->AlternatePkeyIndex = pAttr->PkeyIndex; // TODO: missing in ib_qp_attr_t + pAttr->LocalAckTimeout = pVerbsAttr->primary_av.conn.local_ack_timeout; + pAttr->AlternateLocalAckTimeout = pVerbsAttr->alternate_av.conn.local_ack_timeout; + + pAttr->RnrNakTimeout = 0; // TODO: missing in ib_ap_attr_t + pAttr->SequenceErrorRetryCount = pVerbsAttr->primary_av.conn.seq_err_retry_cnt; + pAttr->RnrRetryCount = pVerbsAttr->primary_av.conn.rnr_retry_cnt; +} + +static ib_qp_opts_t WvVerbsConvertOptions(UINT32 Options) +{ + UINT32 opt = 0; + + if ((Options & WV_IO_QP_ATTR_CAPABILITIES) != 0) { + opt |= IB_MOD_QP_SQ_DEPTH | IB_MOD_QP_RQ_DEPTH; + } + if ((Options & WV_IO_QP_ATTR_INITIATOR_DEPTH) != 0) { + opt |= IB_MOD_QP_INIT_DEPTH; + } + if ((Options & WV_IO_QP_ATTR_RESPONDER_RESOURCES) != 0) { + opt |= IB_MOD_QP_RESP_RES; + } + if ((Options & WV_IO_QP_ATTR_CURRENT_STATE) != 0) { + opt |= IB_MOD_QP_CURRENT_STATE; + } + if ((Options & WV_IO_QP_ATTR_PATH_MIG_STATE) != 0) { + opt |= IB_MOD_QP_APM_STATE; + } + if ((Options & WV_IO_QP_ATTR_QKEY) != 0) { + opt |= IB_MOD_QP_QKEY; + } + if ((Options & WV_IO_QP_ATTR_ACCESS_FLAGS) != 0) { + opt |= IB_MOD_QP_ACCESS_CTRL; + } + if ((Options & WV_IO_QP_ATTR_AV) != 0) { + opt |= IB_MOD_QP_PRIMARY_AV; + } + if ((Options & WV_IO_QP_ATTR_ALTERNATE_AV) != 0) { + opt |= IB_MOD_QP_ALTERNATE_AV; + } + if ((Options & WV_IO_QP_ATTR_PORT_NUMBER) != 0) { + opt |= IB_MOD_QP_PRIMARY_PORT; + } + if ((Options & WV_IO_QP_ATTR_PKEY_INDEX) != 0) { + opt |= IB_MOD_QP_PKEY; + } + if ((Options & WV_IO_QP_ATTR_ACK_TIMEOUT) != 0) { + opt |= IB_MOD_QP_LOCAL_ACK_TIMEOUT; + } + if ((Options & WV_IO_QP_ATTR_RNR_NAK_TIMEOUT) != 0) { + opt |= IB_MOD_QP_RNR_NAK_TIMEOUT; + } + if ((Options & WV_IO_QP_ATTR_ERROR_RETRY_COUNT) != 0) { + opt |= IB_MOD_QP_RETRY_CNT; + } + if ((Options & WV_IO_QP_ATTR_RNR_RETRY_COUNT) != 0) { + opt |= IB_MOD_QP_RNR_RETRY_CNT; + } + + return (ib_qp_opts_t) opt; +} + +static ib_qp_state_t WvVerbsConvertState(UINT8 State) +{ + switch (State) { + case WV_IO_QP_STATE_RESET: return IB_QPS_RESET; + case WV_IO_QP_STATE_INIT: return IB_QPS_INIT; + case WV_IO_QP_STATE_RTR: return IB_QPS_RTR; + case WV_IO_QP_STATE_RTS: return IB_QPS_RTS; + case WV_IO_QP_STATE_SQD: return IB_QPS_SQD; + case WV_IO_QP_STATE_SQERROR: return IB_QPS_SQERR; + default: return IB_QPS_ERROR; + } +} + +static void WvVerbsConvertAttr(ib_qp_mod_t *pVerbsAttr, WV_IO_QP_ATTRIBUTES *pAttr) +{ + switch (pAttr->QpState) { + case WV_IO_QP_STATE_RESET: + pVerbsAttr->req_state = IB_QPS_RESET; + break; + case WV_IO_QP_STATE_INIT: + pVerbsAttr->req_state = IB_QPS_INIT; + + pVerbsAttr->state.init.primary_port = pAttr->AddressVector.PortNumber; + pVerbsAttr->state.init.qkey = pAttr->Qkey; + pVerbsAttr->state.init.pkey_index = pAttr->PkeyIndex; + pVerbsAttr->state.init.access_ctrl = pAttr->AccessFlags; + break; + case WV_IO_QP_STATE_RTR: + pVerbsAttr->req_state = IB_QPS_RTR; + + pVerbsAttr->state.rtr.rq_psn = pAttr->ReceivePsn; + pVerbsAttr->state.rtr.dest_qp = pAttr->DestinationQpn; + WvVerbsConvertAv(&pVerbsAttr->state.rtr.primary_av, + &pAttr->AddressVector, pAttr); + pVerbsAttr->state.rtr.resp_res = (UINT8) pAttr->ResponderResources; + pVerbsAttr->state.rtr.rnr_nak_timeout = pAttr->RnrNakTimeout; + + pVerbsAttr->state.rtr.opts = WvVerbsConvertOptions(pAttr->Options); + WvVerbsConvertAv(&pVerbsAttr->state.rtr.alternate_av, + &pAttr->AlternateAddressVector, pAttr); + pVerbsAttr->state.rtr.qkey = pAttr->Qkey; + pVerbsAttr->state.rtr.pkey_index = pAttr->PkeyIndex; + pVerbsAttr->state.rtr.access_ctrl = pAttr->AccessFlags; + pVerbsAttr->state.rtr.sq_depth = pAttr->SendDepth; + pVerbsAttr->state.rtr.rq_depth = pAttr->ReceiveDepth; + break; + case WV_IO_QP_STATE_RTS: + pVerbsAttr->req_state = IB_QPS_RTS; + + pVerbsAttr->state.rts.sq_psn = pAttr->SendPsn; + pVerbsAttr->state.rts.retry_cnt = pAttr->SequenceErrorRetryCount; + pVerbsAttr->state.rts.rnr_retry_cnt = pAttr->RnrRetryCount; + pVerbsAttr->state.rts.local_ack_timeout = pAttr->LocalAckTimeout; + pVerbsAttr->state.rts.init_depth = (UINT8) pAttr->InitiatorDepth; + + pVerbsAttr->state.rts.opts = WvVerbsConvertOptions(pAttr->Options); + pVerbsAttr->state.rts.rnr_nak_timeout = pAttr->RnrNakTimeout; + pVerbsAttr->state.rts.current_state = WvVerbsConvertState(pAttr->CurrentQpState); + pVerbsAttr->state.rts.qkey = pAttr->Qkey; + pVerbsAttr->state.rts.access_ctrl = pAttr->AccessFlags; + pVerbsAttr->state.rts.resp_res = (UINT8) pAttr->ResponderResources; + + WvVerbsConvertAv(&pVerbsAttr->state.rts.primary_av, + &pAttr->AddressVector, pAttr); + WvVerbsConvertAv(&pVerbsAttr->state.rts.alternate_av, + &pAttr->AlternateAddressVector, pAttr); + + pVerbsAttr->state.rts.sq_depth = pAttr->SendDepth; + pVerbsAttr->state.rts.rq_depth = pAttr->ReceiveDepth; + + pVerbsAttr->state.rts.apm_state = pAttr->ApmState; + pVerbsAttr->state.rts.primary_port = pAttr->AddressVector.PortNumber; + pVerbsAttr->state.rts.pkey_index = pAttr->PkeyIndex; + break; + case WV_IO_QP_STATE_SQD: + pVerbsAttr->req_state = IB_QPS_SQD; + pVerbsAttr->state.sqd.sqd_event = 1; + break; + case WV_IO_QP_STATE_SQERROR: + pVerbsAttr->req_state = IB_QPS_SQERR; + break; + default: + pVerbsAttr->req_state = IB_QPS_ERROR; + break; + } +} + +static void WvQpGet(WV_QUEUE_PAIR *pQp) +{ + InterlockedIncrement(&pQp->Ref); +} + +static void WvQpPut(WV_QUEUE_PAIR *pQp) +{ + if (InterlockedDecrement(&pQp->Ref) == 0) { + KeSetEvent(&pQp->Event, 0, FALSE); + } +} + +WV_QUEUE_PAIR *WvQpAcquire(WV_PROVIDER *pProvider, UINT64 Id) +{ + WV_QUEUE_PAIR *qp; + + KeAcquireGuardedMutex(&pProvider->Lock); + WvProviderDisableRemove(pProvider); + qp = IndexListAt(&pProvider->QpIndex, (SIZE_T) Id); + if (qp != NULL && qp->hVerbsQp != NULL) { + WvQpGet(qp); + } else { + qp = NULL; + WvProviderEnableRemove(pProvider); + } + KeReleaseGuardedMutex(&pProvider->Lock); + + return qp; +} + +void WvQpRelease(WV_QUEUE_PAIR *pQp) +{ + WvProviderEnableRemove(pQp->pProvider); + WvQpPut(pQp); +} + +static NTSTATUS WvQpCreateAcquire(WV_PROVIDER *pProvider, WV_QUEUE_PAIR *pQp, + WV_IO_QP_CREATE *pAttributes) +{ + KeAcquireGuardedMutex(&pProvider->Lock); + WvProviderDisableRemove(pProvider); + pQp->pPd = IndexListAt(&pProvider->PdIndex, (SIZE_T) pAttributes->Id.Id); + if (pQp->pPd != NULL && pQp->pPd->hVerbsPd != NULL) { + WvPdGet(pQp->pPd); + pQp->pVerbs = pQp->pPd->pVerbs; + } else { + goto err1; + } + + pQp->pSendCq = IndexListAt(&pProvider->CqIndex, (SIZE_T) pAttributes->SendCqId); + if (pQp->pSendCq != NULL && pQp->pSendCq->hVerbsCq != NULL) { + WvCqGet(pQp->pSendCq); + } else { + goto err2; + } + + pQp->pReceiveCq = IndexListAt(&pProvider->CqIndex, + (SIZE_T) pAttributes->ReceiveCqId); + if (pQp->pReceiveCq != NULL && pQp->pReceiveCq->hVerbsCq != NULL) { + WvCqGet(pQp->pReceiveCq); + } else { + goto err3; + } + + if (pAttributes->SrqId != 0) { + pQp->pSrq = IndexListAt(&pProvider->SrqIndex, (SIZE_T) pAttributes->SrqId); + if (pQp->pSrq != NULL && pQp->pSrq->hVerbsSrq != NULL) { + WvSrqGet(pQp->pSrq); + } else { + goto err4; + } + } else { + pQp->pSrq = NULL; + } + KeReleaseGuardedMutex(&pProvider->Lock); + + return STATUS_SUCCESS; + +err4: + WvCqPut(pQp->pReceiveCq); +err3: + WvCqPut(pQp->pSendCq); +err2: + WvPdPut(pQp->pPd); +err1: + WvProviderEnableRemove(pProvider); + KeReleaseGuardedMutex(&pProvider->Lock); + return STATUS_NOT_FOUND; +} + +static void WvQpCreateRelease(WV_PROVIDER *pProvider, WV_QUEUE_PAIR *pQp) +{ + WvProviderEnableRemove(pProvider); + if (pQp->pSrq != NULL) { + WvSrqPut(pQp->pSrq); + } + WvCqPut(pQp->pReceiveCq); + WvCqPut(pQp->pSendCq); + WvPdPut(pQp->pPd); +} + +static void WvQpEventHandler(ib_event_rec_t *pEvent) +{ + // TODO: Handle QP events when adding connection handling + // IB_AE_QP_FATAL + // IB_AE_QP_COMM + // IB_AE_QP_APM + UNREFERENCED_PARAMETER(pEvent); +} + +void WvQpCreate(WV_PROVIDER *pProvider, WDFREQUEST Request) +{ + WV_IO_QP_CREATE *inattr, *outattr; + size_t inlen, outlen; + WV_QUEUE_PAIR *qp; + ib_qp_create_t create; + ib_qp_attr_t ib_attr; + NTSTATUS status; + ib_api_status_t ib_status; + ci_umv_buf_t verbsData; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_QP_CREATE), + &inattr, &inlen); + if (!NT_SUCCESS(status)) { + goto err1; + } + status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_QP_CREATE), + &outattr, &outlen); + if (!NT_SUCCESS(status)) { + goto err1; + } + + qp = ExAllocatePoolWithTag(NonPagedPool, sizeof(WV_QUEUE_PAIR), 'pqvw'); + if (qp == NULL) { + status = STATUS_NO_MEMORY; + goto err1; + } + + qp->Ref = 1; + qp->pProvider = pProvider; + KeInitializeEvent(&qp->Event, NotificationEvent, FALSE); + InitializeListHead(&qp->McList); + KeInitializeGuardedMutex(&qp->Lock); + status = WvQpCreateAcquire(pProvider, qp, inattr); + if (!NT_SUCCESS(status)) { + goto err2; + } + + WvVerbsConvertCreate(&create, inattr, qp); + WvInitVerbsData(&verbsData, inattr->Id.VerbInfo, inlen - sizeof(WV_IO_QP_CREATE), + outlen - sizeof(WV_IO_QP_CREATE), inattr + 1); + ib_status = qp->pVerbs->create_qp(qp->pPd->hVerbsPd, qp, WvQpEventHandler, + &create, &ib_attr, &qp->hVerbsQp, &verbsData); + if (ib_status != IB_SUCCESS) { + status = STATUS_UNSUCCESSFUL; + goto err3; + } + + qp->Qpn = ib_attr.num; + KeAcquireGuardedMutex(&pProvider->Lock); + outattr->Id.Id = IndexListInsertHead(&pProvider->QpIndex, qp); + if (outattr->Id.Id == 0) { + status = STATUS_NO_MEMORY; + goto err4; + } + InsertHeadList(&qp->pPd->QpList, &qp->Entry); + KeReleaseGuardedMutex(&pProvider->Lock); + + WvProviderEnableRemove(pProvider); + outattr->Id.VerbInfo = verbsData.status; + WdfRequestCompleteWithInformation(Request, status, outlen); + return; + +err4: + KeReleaseGuardedMutex(&pProvider->Lock); + qp->pVerbs->destroy_qp(qp->hVerbsQp, 0); +err3: + WvQpCreateRelease(pProvider, qp); +err2: + ExFreePoolWithTag(qp, 'pqvw'); +err1: + WdfRequestComplete(Request, status); +} + +void WvQpDestroy(WV_PROVIDER *pProvider, WDFREQUEST Request) +{ + WV_QUEUE_PAIR *qp; + UINT64 *id; + NTSTATUS status; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL); + if (!NT_SUCCESS(status)) { + goto out; + } + + KeAcquireGuardedMutex(&pProvider->Lock); + WvProviderDisableRemove(pProvider); + qp = IndexListAt(&pProvider->QpIndex, (SIZE_T) *id); + if (qp == NULL) { + status = STATUS_NOT_FOUND; + } else if (qp->Ref > 1) { + status = STATUS_ACCESS_DENIED; + } else { + IndexListRemove(&pProvider->QpIndex, (SIZE_T) *id); + RemoveEntryList(&qp->Entry); + status = STATUS_SUCCESS; + } + KeReleaseGuardedMutex(&pProvider->Lock); + + if (NT_SUCCESS(status)) { + WvQpFree(qp); + } + WvProviderEnableRemove(pProvider); +out: + WdfRequestComplete(Request, status); +} + +void WvQpFree(WV_QUEUE_PAIR *pQp) +{ + WV_MULTICAST *mc; + LIST_ENTRY *entry; + + while ((entry = RemoveHeadList(&pQp->McList)) != &pQp->McList) { + mc = CONTAINING_RECORD(entry, WV_MULTICAST, Entry); + if (mc->hVerbsMc != NULL) { + pQp->pVerbs->detach_mcast(mc->hVerbsMc); + } + ExFreePoolWithTag(mc, 'cmvw'); + } + + if (InterlockedDecrement(&pQp->Ref) > 0) { + KeWaitForSingleObject(&pQp->Event, Executive, KernelMode, FALSE, NULL); + } + + if (pQp->hVerbsQp != NULL) { + pQp->pVerbs->destroy_qp(pQp->hVerbsQp, 0); + } + + if (pQp->pSrq != NULL) { + WvSrqPut(pQp->pSrq); + } + WvCqPut(pQp->pReceiveCq); + WvCqPut(pQp->pSendCq); + WvPdPut(pQp->pPd); + ExFreePoolWithTag(pQp, 'pqvw'); +} + +void WvQpQuery(WV_PROVIDER *pProvider, WDFREQUEST Request) +{ + UINT64 *id; + WV_IO_QP_ATTRIBUTES *pattr; + size_t inlen, outlen, len = 0; + WV_QUEUE_PAIR *qp; + ib_qp_attr_t attr; + NTSTATUS status; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, &inlen); + if (!NT_SUCCESS(status)) { + goto complete; + } + status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_QP_ATTRIBUTES), + &pattr, &outlen); + if (!NT_SUCCESS(status)) { + goto complete; + } + + qp = WvQpAcquire(pProvider, *id); + if (qp == NULL) { + status = STATUS_NOT_FOUND; + goto complete; + } + + RtlZeroMemory(&attr, sizeof attr); + qp->pVerbs->query_qp(qp->hVerbsQp, &attr, NULL); + WvQpRelease(qp); + + WvQpAttrConvertVerbs(pattr, &attr); + len = outlen; + +complete: + WdfRequestCompleteWithInformation(Request, status, len); +} + +void WvQpModify(WV_PROVIDER *pProvider, WDFREQUEST Request) +{ + WV_IO_QP_ATTRIBUTES *pattr; + UINT8 *out; + size_t outlen, len = 0; + WV_QUEUE_PAIR *qp; + ib_qp_mod_t attr; + NTSTATUS status; + ib_api_status_t ib_status; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_QP_ATTRIBUTES), + &pattr, NULL); + if (!NT_SUCCESS(status)) { + goto complete; + } + status = WdfRequestRetrieveOutputBuffer(Request, 0, &out, &outlen); + if (!NT_SUCCESS(status) && status != STATUS_BUFFER_TOO_SMALL) { + goto complete; + } + + WvVerbsConvertAttr(&attr, pattr); + qp = WvQpAcquire(pProvider, pattr->Id.Id); + if (qp == NULL) { + status = STATUS_NOT_FOUND; + goto complete; + } + + ib_status = qp->pVerbs->ndi_modify_qp(qp->hVerbsQp, &attr, NULL, (UINT32) outlen, out); + if (ib_status != IB_SUCCESS) { + status = STATUS_UNSUCCESSFUL; + } + WvQpRelease(qp); + len = outlen; + +complete: + WdfRequestCompleteWithInformation(Request, status, len); +} + +void WvQpAttach(WV_PROVIDER *pProvider, WDFREQUEST Request) +{ + WV_MULTICAST *pmc; + WV_IO_QP_MULTICAST *mc; + WV_QUEUE_PAIR *qp; + NTSTATUS status; + ib_api_status_t ib_status; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_QP_MULTICAST), + &mc, NULL); + if (!NT_SUCCESS(status)) { + goto err1; + } + + pmc = ExAllocatePoolWithTag(PagedPool, sizeof(WV_MULTICAST), 'cmvw'); + if (pmc == NULL) { + status = STATUS_NO_MEMORY; + goto err1; + } + + qp = WvQpAcquire(pProvider, mc->Id.Id); + if (qp == NULL) { + status = STATUS_NOT_FOUND; + goto err2; + } + + pmc->Gid = mc->Gid; + pmc->Lid = (NET16) mc->Id.Data; + ib_status = qp->pVerbs->attach_mcast(qp->hVerbsQp, (ib_gid_t *) &mc->Gid, + (NET16) mc->Id.Data, &pmc->hVerbsMc, NULL); + + if (ib_status != IB_SUCCESS) { + status = STATUS_UNSUCCESSFUL; + goto err3; + } + + KeAcquireGuardedMutex(&qp->Lock); + InsertHeadList(&qp->McList, &pmc->Entry); + KeReleaseGuardedMutex(&qp->Lock); + + WvQpRelease(qp); + WdfRequestComplete(Request, STATUS_SUCCESS); + return; + +err3: + WvQpRelease(qp); +err2: + ExFreePoolWithTag(pmc, 'cmvw'); +err1: + WdfRequestComplete(Request, status); +} + +void WvQpDetach(WV_PROVIDER *pProvider, WDFREQUEST Request) +{ + WV_MULTICAST *pmc; + WV_IO_QP_MULTICAST *mc; + WV_QUEUE_PAIR *qp; + LIST_ENTRY *entry; + NTSTATUS status; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_QP_MULTICAST), + &mc, NULL); + if (!NT_SUCCESS(status)) { + goto complete; + } + + qp = WvQpAcquire(pProvider, mc->Id.Id); + if (qp == NULL) { + status = STATUS_NOT_FOUND; + goto complete; + } + + KeAcquireGuardedMutex(&qp->Lock); + for (entry = qp->McList.Flink; entry != &qp->McList; entry = entry->Flink) { + pmc = CONTAINING_RECORD(entry, WV_MULTICAST, Entry); + + if (RtlCompareMemory(&pmc->Gid, &mc->Gid, sizeof(pmc->Gid)) == sizeof(pmc->Gid) && + pmc->Lid == (NET16) mc->Id.Data) { + RemoveEntryList(&pmc->Entry); + KeReleaseGuardedMutex(&qp->Lock); + + if (pmc->hVerbsMc != NULL) { + qp->pVerbs->detach_mcast(pmc->hVerbsMc); + } + + ExFreePoolWithTag(pmc, 'cmvw'); + status = STATUS_SUCCESS; + goto release; + } + } + KeReleaseGuardedMutex(&qp->Lock); + status = STATUS_NOT_FOUND; + +release: + WvQpRelease(qp); +complete: + WdfRequestComplete(Request, status); +} + +void WvQpRemoveHandler(WV_QUEUE_PAIR *pQp) +{ + WV_MULTICAST *mc; + LIST_ENTRY *entry; + + for (entry = pQp->McList.Flink; entry != &pQp->McList; entry = entry->Flink) { + mc = CONTAINING_RECORD(entry, WV_MULTICAST, Entry); + pQp->pVerbs->detach_mcast(mc->hVerbsMc); + mc->hVerbsMc = NULL; + } + + pQp->pVerbs->destroy_qp(pQp->hVerbsQp, 0); + pQp->hVerbsQp = NULL; +} + +void WvQpCancel(WV_PROVIDER *pProvider, WDFREQUEST Request) +{ + UINT64 *id; + WV_QUEUE_PAIR *qp; + NTSTATUS status; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL); + if (!NT_SUCCESS(status)) { + goto out; + } + + qp = WvQpAcquire(pProvider, *id); + if (qp == NULL) { + status = STATUS_NOT_FOUND; + goto out; + } + + // CI does not yet support async operations + WvQpRelease(qp); + +out: + WdfRequestComplete(Request, status); +} diff --git a/branches/WOF2-3/core/winverbs/kernel/wv_qp.h b/branches/WOF2-3/core/winverbs/kernel/wv_qp.h new file mode 100644 index 00000000..796fb65e --- /dev/null +++ b/branches/WOF2-3/core/winverbs/kernel/wv_qp.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#ifndef _WV_QP_H_ +#define _WV_QP_H_ + +#include +#include +#include +#include + +#include "wv_pd.h" +#include "wv_provider.h" +#include "wv_cq.h" +#include "wv_srq.h" + +typedef struct _WV_QUEUE_PAIR +{ + WV_PROVIDER *pProvider; + WV_PROTECTION_DOMAIN *pPd; + WV_COMPLETION_QUEUE *pSendCq; + WV_COMPLETION_QUEUE *pReceiveCq; + WV_SHARED_RECEIVE_QUEUE *pSrq; + ci_interface_t *pVerbs; + ib_qp_handle_t hVerbsQp; + UINT32 Qpn; + LIST_ENTRY Entry; + LIST_ENTRY McList; + + KGUARDED_MUTEX Lock; + KEVENT Event; + LONG Ref; + +} WV_QUEUE_PAIR; + +void WvQpCreate(WV_PROVIDER *pProvider, WDFREQUEST Request); +void WvQpDestroy(WV_PROVIDER *pProvider, WDFREQUEST Request); +void WvQpFree(WV_QUEUE_PAIR *pQp); +void WvQpRemoveHandler(WV_QUEUE_PAIR *pQp); + +WV_QUEUE_PAIR *WvQpAcquire(WV_PROVIDER *pProvider, UINT64 Id); +void WvQpRelease(WV_QUEUE_PAIR *pQp); + +void WvQpModify(WV_PROVIDER *pProvider, WDFREQUEST Request); +void WvQpQuery(WV_PROVIDER *pProvider, WDFREQUEST Request); +void WvQpAttach(WV_PROVIDER *pProvider, WDFREQUEST Request); +void WvQpDetach(WV_PROVIDER *pProvider, WDFREQUEST Request); +void WvQpCancel(WV_PROVIDER *pProvider, WDFREQUEST Request); + +#endif // _WV_QP_H_ diff --git a/branches/WOF2-3/core/winverbs/kernel/wv_srq.c b/branches/WOF2-3/core/winverbs/kernel/wv_srq.c new file mode 100644 index 00000000..99f2b492 --- /dev/null +++ b/branches/WOF2-3/core/winverbs/kernel/wv_srq.c @@ -0,0 +1,379 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "wv_driver.h" +#include "wv_srq.h" +#include "wv_ioctl.h" + +void WvSrqGet(WV_SHARED_RECEIVE_QUEUE *pSrq) +{ + InterlockedIncrement(&pSrq->Ref); +} + +void WvSrqPut(WV_SHARED_RECEIVE_QUEUE *pSrq) +{ + if (InterlockedDecrement(&pSrq->Ref) == 0) { + KeSetEvent(&pSrq->Event, 0, FALSE); + } +} + +WV_SHARED_RECEIVE_QUEUE *WvSrqAcquire(WV_PROVIDER *pProvider, UINT64 Id) +{ + WV_SHARED_RECEIVE_QUEUE *srq; + + KeAcquireGuardedMutex(&pProvider->Lock); + WvProviderDisableRemove(pProvider); + srq = IndexListAt(&pProvider->SrqIndex, (SIZE_T) Id); + if (srq != NULL && srq->hVerbsSrq != NULL) { + WvSrqGet(srq); + } else { + srq = NULL; + WvProviderEnableRemove(pProvider); + } + KeReleaseGuardedMutex(&pProvider->Lock); + + return srq; +} + +void WvSrqRelease(WV_SHARED_RECEIVE_QUEUE *pSrq) +{ + WvProviderEnableRemove(pSrq->pProvider); + WvSrqPut(pSrq); +} + +static void WvVerbsConvertSrq(ib_srq_attr_t *pVerbsAttr, + WV_IO_SRQ_ATTRIBUTES *pAttr) +{ + pVerbsAttr->max_wr = pAttr->MaxWr; + pVerbsAttr->max_sge = pAttr->MaxSge; + pVerbsAttr->srq_limit = pAttr->SrqLimit; +} + +static void WvSrqEventHandler(ib_event_rec_t *pEvent) +{ + WV_SHARED_RECEIVE_QUEUE *srq = pEvent->context; + + switch (pEvent->type) { + case IB_AE_SRQ_LIMIT_REACHED: + WvFlushQueue(srq->Queue, STATUS_ALERTED); + break; + case IB_AE_SRQ_QP_LAST_WQE_REACHED: + WvFlushQueue(srq->Queue, STATUS_NOTIFY_CLEANUP); + break; + default: + WvFlushQueue(srq->Queue, STATUS_UNEXPECTED_IO_ERROR); + break; + } +} + +static NTSTATUS WvSrqAlloc(WV_PROTECTION_DOMAIN *pPd, WV_IO_SRQ_ATTRIBUTES *pAttr, + WV_SHARED_RECEIVE_QUEUE **ppSrq, ci_umv_buf_t *pVerbsData) +{ + WV_SHARED_RECEIVE_QUEUE *srq; + ib_srq_attr_t attr; + ib_api_status_t ib_status; + NTSTATUS status; + WDF_IO_QUEUE_CONFIG config; + + srq = ExAllocatePoolWithTag(NonPagedPool, sizeof(WV_SHARED_RECEIVE_QUEUE), 'rsvw'); + if (srq == NULL) { + return STATUS_NO_MEMORY; + } + + srq->Ref = 1; + KeInitializeEvent(&srq->Event, NotificationEvent, FALSE); + + WDF_IO_QUEUE_CONFIG_INIT(&config, WdfIoQueueDispatchManual); + status = WdfIoQueueCreate(ControlDevice, &config, + WDF_NO_OBJECT_ATTRIBUTES, &srq->Queue); + if (!NT_SUCCESS(status)) { + goto err1; + } + + WvVerbsConvertSrq(&attr, pAttr); + ib_status = pPd->pVerbs->create_srq(pPd->hVerbsPd, srq, WvSrqEventHandler, + &attr, &srq->hVerbsSrq, pVerbsData); + if (ib_status != IB_SUCCESS) { + goto err2; + } + + WvPdGet(pPd); + srq->pPd = pPd; + srq->pProvider = pPd->pDevice->pProvider; + srq->pVerbs = pPd->pVerbs; + *ppSrq = srq; + return STATUS_SUCCESS; + +err2: + WdfObjectDelete(srq->Queue); +err1: + ExFreePoolWithTag(srq, 'rsvw'); + return STATUS_UNSUCCESSFUL; +} + +void WvSrqCreate(WV_PROVIDER *pProvider, WDFREQUEST Request) +{ + WV_IO_SRQ_ATTRIBUTES *inAttr, *outAttr; + size_t inlen, outlen; + WV_PROTECTION_DOMAIN *pd; + WV_SHARED_RECEIVE_QUEUE *srq; + NTSTATUS status; + ci_umv_buf_t verbsData; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_SRQ_ATTRIBUTES), + &inAttr, &inlen); + if (!NT_SUCCESS(status)) { + goto err1; + } + status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_SRQ_ATTRIBUTES), + &outAttr, &outlen); + if (!NT_SUCCESS(status)) { + goto err1; + } + + pd = WvPdAcquire(pProvider, inAttr->Id.Id); + if (pd == NULL) { + status = STATUS_NOT_FOUND; + goto err1; + } + + WvInitVerbsData(&verbsData, inAttr->Id.VerbInfo, inlen - sizeof(WV_IO_SRQ_ATTRIBUTES), + outlen - sizeof(WV_IO_SRQ_ATTRIBUTES), inAttr + 1); + status = WvSrqAlloc(pd, inAttr, &srq, &verbsData); + if (!NT_SUCCESS(status)) { + goto err2; + } + + KeAcquireGuardedMutex(&pProvider->Lock); + outAttr->Id.Id = IndexListInsertHead(&pProvider->SrqIndex, srq); + if (outAttr->Id.Id == 0) { + status = STATUS_NO_MEMORY; + goto err3; + } + InsertHeadList(&pd->SrqList, &srq->Entry); + KeReleaseGuardedMutex(&pProvider->Lock); + + WvPdRelease(pd); + outAttr->Id.VerbInfo = verbsData.status; + WdfRequestCompleteWithInformation(Request, status, outlen); + return; + +err3: + KeReleaseGuardedMutex(&pProvider->Lock); + WvSrqFree(srq); +err2: + WvPdRelease(pd); +err1: + WdfRequestComplete(Request, status); +} + +void WvSrqDestroy(WV_PROVIDER *pProvider, WDFREQUEST Request) +{ + WV_SHARED_RECEIVE_QUEUE *srq; + UINT64 *id; + NTSTATUS status; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL); + if (!NT_SUCCESS(status)) { + goto out; + } + + KeAcquireGuardedMutex(&pProvider->Lock); + WvProviderDisableRemove(pProvider); + srq = IndexListAt(&pProvider->SrqIndex, (SIZE_T) *id); + if (srq == NULL) { + status = STATUS_NOT_FOUND; + } else if (srq->Ref > 1) { + status = STATUS_ACCESS_DENIED; + } else { + IndexListRemove(&pProvider->SrqIndex, (SIZE_T) *id); + RemoveEntryList(&srq->Entry); + status = STATUS_SUCCESS; + } + KeReleaseGuardedMutex(&pProvider->Lock); + + if (NT_SUCCESS(status)) { + WvSrqFree(srq); + } + WvProviderEnableRemove(pProvider); +out: + WdfRequestComplete(Request, status); +} + +void WvSrqFree(WV_SHARED_RECEIVE_QUEUE *pSrq) +{ + if (InterlockedDecrement(&pSrq->Ref) > 0) { + KeWaitForSingleObject(&pSrq->Event, Executive, KernelMode, FALSE, NULL); + } + + if (pSrq->hVerbsSrq != NULL) { + pSrq->pVerbs->destroy_srq(pSrq->hVerbsSrq); + } + + WdfIoQueuePurgeSynchronously(pSrq->Queue); + WdfObjectDelete(pSrq->Queue); + WvPdPut(pSrq->pPd); + ExFreePoolWithTag(pSrq, 'rsvw'); +} + +void WvSrqModify(WV_PROVIDER *pProvider, WDFREQUEST Request) +{ + WV_IO_SRQ_ATTRIBUTES *pinAttr, *poutAttr; + size_t inlen, outlen, len = 0; + WV_SHARED_RECEIVE_QUEUE *srq; + ib_srq_attr_t attr; + NTSTATUS status; + ib_api_status_t ib_status; + ci_umv_buf_t verbsData; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_SRQ_ATTRIBUTES), + &pinAttr, &inlen); + if (!NT_SUCCESS(status)) { + goto complete; + } + status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_SRQ_ATTRIBUTES), + &poutAttr, &outlen); + if (!NT_SUCCESS(status)) { + goto complete; + } + + srq = WvSrqAcquire(pProvider, pinAttr->Id.Id); + if (srq == NULL) { + status = STATUS_NOT_FOUND; + goto complete; + } + + WvInitVerbsData(&verbsData, pinAttr->Id.VerbInfo, inlen - sizeof(WV_IO_SRQ_ATTRIBUTES), + outlen - sizeof(WV_IO_SRQ_ATTRIBUTES), pinAttr + 1); + WvVerbsConvertSrq(&attr, pinAttr); + ib_status = srq->pVerbs->modify_srq(srq->hVerbsSrq, &attr, + IB_SRQ_MAX_WR | IB_SRQ_LIMIT, &verbsData); + WvSrqRelease(srq); + + if (ib_status != IB_SUCCESS) { + status = STATUS_UNSUCCESSFUL; + } + + len = outlen; + poutAttr->Id.VerbInfo = verbsData.status; +complete: + WdfRequestCompleteWithInformation(Request, status, len); +} + +void WvSrqQuery(WV_PROVIDER *pProvider, WDFREQUEST Request) +{ + WV_IO_SRQ_ATTRIBUTES *pinAttr, *poutAttr; + size_t inlen, outlen, len = 0; + WV_SHARED_RECEIVE_QUEUE *srq; + ib_srq_attr_t attr; + NTSTATUS status; + ci_umv_buf_t verbsData; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_SRQ_ATTRIBUTES), + &pinAttr, &inlen); + if (!NT_SUCCESS(status)) { + goto complete; + } + status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_SRQ_ATTRIBUTES), + &poutAttr, &outlen); + if (!NT_SUCCESS(status)) { + goto complete; + } + + srq = WvSrqAcquire(pProvider, pinAttr->Id.Id); + if (srq == NULL) { + status = STATUS_NOT_FOUND; + goto complete; + } + + WvInitVerbsData(&verbsData, pinAttr->Id.VerbInfo, inlen - sizeof(WV_IO_SRQ_ATTRIBUTES), + outlen - sizeof(WV_IO_SRQ_ATTRIBUTES), pinAttr + 1); + srq->pVerbs->query_srq(srq->hVerbsSrq, &attr, &verbsData); + WvSrqRelease(srq); + + poutAttr->Id.VerbInfo = verbsData.status; + poutAttr->MaxWr = attr.max_wr; + poutAttr->MaxSge = attr.max_sge; + poutAttr->SrqLimit = attr.srq_limit; + len = outlen; +complete: + WdfRequestCompleteWithInformation(Request, status, len); +} + +void WvSrqNotify(WV_PROVIDER *pProvider, WDFREQUEST Request) +{ + UINT64 *id; + WV_SHARED_RECEIVE_QUEUE *srq; + NTSTATUS status; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL); + if (!NT_SUCCESS(status)) { + goto out; + } + + srq = WvSrqAcquire(pProvider, *id); + if (srq == NULL) { + status = STATUS_NOT_FOUND; + goto out; + } + + WdfObjectAcquireLock(srq->Queue); + status = WdfRequestForwardToIoQueue(Request, srq->Queue); + WdfObjectReleaseLock(srq->Queue); + WvSrqRelease(srq); + +out: + if (!NT_SUCCESS(status)) { + WdfRequestComplete(Request, status); + } +} + +void WvSrqCancel(WV_PROVIDER *pProvider, WDFREQUEST Request) +{ + UINT64 *id; + WV_SHARED_RECEIVE_QUEUE *srq; + NTSTATUS status; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL); + if (!NT_SUCCESS(status)) { + goto out; + } + + srq = WvSrqAcquire(pProvider, *id); + if (srq == NULL) { + status = STATUS_NOT_FOUND; + goto out; + } + + WvFlushQueue(srq->Queue, STATUS_CANCELLED); + WvSrqRelease(srq); + +out: + WdfRequestComplete(Request, status); +} diff --git a/branches/WOF2-3/core/winverbs/kernel/wv_srq.h b/branches/WOF2-3/core/winverbs/kernel/wv_srq.h new file mode 100644 index 00000000..97bb93dd --- /dev/null +++ b/branches/WOF2-3/core/winverbs/kernel/wv_srq.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#ifndef _WV_SRQ_H_ +#define _WV_SRQ_H_ + +#include +#include +#include +#include + +#include "wv_pd.h" +#include "wv_provider.h" + +typedef struct _WV_SHARED_RECEIVE_QUEUE +{ + WV_PROVIDER *pProvider; + WV_PROTECTION_DOMAIN *pPd; + ci_interface_t *pVerbs; + ib_srq_handle_t hVerbsSrq; + LIST_ENTRY Entry; + + KEVENT Event; + LONG Ref; + WDFQUEUE Queue; + +} WV_SHARED_RECEIVE_QUEUE; + +void WvSrqCreate(WV_PROVIDER *pProvider, WDFREQUEST Request); +void WvSrqDestroy(WV_PROVIDER *pProvider, WDFREQUEST Request); +void WvSrqFree(WV_SHARED_RECEIVE_QUEUE *pSrq); + +WV_SHARED_RECEIVE_QUEUE *WvSrqAcquire(WV_PROVIDER *pProvider, UINT64 Id); +void WvSrqRelease(WV_SHARED_RECEIVE_QUEUE *pSrq); +void WvSrqGet(WV_SHARED_RECEIVE_QUEUE *pSrq); +void WvSrqPut(WV_SHARED_RECEIVE_QUEUE *pSrq); + +void WvSrqModify(WV_PROVIDER *pProvider, WDFREQUEST Request); +void WvSrqQuery(WV_PROVIDER *pProvider, WDFREQUEST Request); +void WvSrqNotify(WV_PROVIDER *pProvider, WDFREQUEST Request); +void WvSrqCancel(WV_PROVIDER *pProvider, WDFREQUEST Request); + +#endif // _WV_SRQ_H_ diff --git a/branches/WOF2-3/core/winverbs/user/SOURCES b/branches/WOF2-3/core/winverbs/user/SOURCES new file mode 100644 index 00000000..6939d1e7 --- /dev/null +++ b/branches/WOF2-3/core/winverbs/user/SOURCES @@ -0,0 +1,39 @@ +!if $(FREEBUILD) +TARGETNAME = winverbs +!else +TARGETNAME = winverbsd +!endif + +TARGETPATH = ..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = DYNLINK + +!if $(_NT_TOOLS_VERSION) == 0x700 +DLLDEF = $O\wv_exports.def +!else +DLLDEF = $(OBJ_PATH)\$O\wv_exports.def +!endif + +DLLENTRY = DllMain +USE_NTDLL = 1 + +SOURCES = \ + winverbs.rc \ + wv_main.cpp \ + wv_base.cpp \ + wv_cq.cpp \ + wv_device.cpp \ + wv_ep.cpp \ + wv_pd.cpp \ + wv_provider.cpp \ + wv_qp.cpp \ + wv_srq.cpp \ + wv_uverbs.cpp + +INCLUDES = ..;..\..\..\inc;..\..\..\inc\user; + +USER_C_FLAGS = $(USER_C_FLAGS) -DEXPORT_WV_SYMBOLS + +TARGETLIBS = \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\uuid.lib \ + $(SDK_LIB_PATH)\ws2_32.lib diff --git a/branches/WOF2-3/core/winverbs/user/makefile b/branches/WOF2-3/core/winverbs/user/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-3/core/winverbs/user/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\inc\openib.def diff --git a/branches/WOF2-3/core/winverbs/user/winverbs.rc b/branches/WOF2-3/core/winverbs/user/winverbs.rc new file mode 100644 index 00000000..1be0d5c1 --- /dev/null +++ b/branches/WOF2-3/core/winverbs/user/winverbs.rc @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + +#include + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef _DEBUG_ +#define VER_FILEDESCRIPTION_STR "WinVerbs (Debug)" +#define VER_INTERNALNAME_STR "winverbsd.dll" +#define VER_ORIGINALFILENAME_STR "winverbsd.dll" +#else +#define VER_FILEDESCRIPTION_STR "WinVerbs" +#define VER_INTERNALNAME_STR "winverbs.dll" +#define VER_ORIGINALFILENAME_STR "winverbs.dll" +#endif + +#include diff --git a/branches/WOF2-3/core/winverbs/user/wv_base.cpp b/branches/WOF2-3/core/winverbs/user/wv_base.cpp new file mode 100644 index 00000000..5ed4e9f7 --- /dev/null +++ b/branches/WOF2-3/core/winverbs/user/wv_base.cpp @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2009 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include "wv_base.h" +#include "wv_cq.h" +#include "wv_qp.h" +#include "wv_ioctl.h" + +CWVBase::CWVBase() +{ + InitializeCriticalSection(&m_CritSec); + m_Overlap.hEvent = NULL; + m_nRef = 1; + m_Id = 0; +} + +CWVBase::~CWVBase() +{ + if (m_Overlap.hEvent != NULL) { + CloseHandle(m_Overlap.hEvent); + } + DeleteCriticalSection(&m_CritSec); +} + +STDMETHODIMP CWVBase:: +Init(void) +{ + m_Overlap.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + if (m_Overlap.hEvent == NULL) + return WV_INSUFFICIENT_RESOURCES; + + m_Overlap.hEvent = (HANDLE) ((ULONG_PTR) m_Overlap.hEvent | 1); + return WV_SUCCESS; +} + +STDMETHODIMP_(ULONG) CWVBase:: +AddRef(void) +{ + return InterlockedIncrement(&m_nRef); +} + +STDMETHODIMP_(ULONG) CWVBase:: +Release(void) +{ + ULONG ref; + + ref = (ULONG) InterlockedDecrement(&m_nRef); + if (ref == 0) { + Delete(); + } + return ref; +} + +BOOL CWVBase:: +WvDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, + LPVOID lpInBuffer, DWORD nInBufferSize, + LPVOID lpOutBuffer, DWORD nOutBufferSize, + LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) +{ + BOOL ret; + + if (lpOverlapped == NULL) { + EnterCriticalSection(&m_CritSec); + DeviceIoControl(hDevice, dwIoControlCode, + lpInBuffer, nInBufferSize, + lpOutBuffer, nOutBufferSize, + lpBytesReturned, &m_Overlap); + + ret = GetOverlappedResult(hDevice, &m_Overlap, lpBytesReturned, TRUE); + LeaveCriticalSection(&m_CritSec); + } else { + ret = DeviceIoControl(hDevice, dwIoControlCode, + lpInBuffer, nInBufferSize, + lpOutBuffer, nOutBufferSize, + lpBytesReturned, lpOverlapped); + } + + return ret; +} diff --git a/branches/WOF2-3/core/winverbs/user/wv_base.h b/branches/WOF2-3/core/winverbs/user/wv_base.h new file mode 100644 index 00000000..f37cf96b --- /dev/null +++ b/branches/WOF2-3/core/winverbs/user/wv_base.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#ifndef _WV_BASE_H_ +#define _WV_BASE_H_ + +#include +#include +#include + +#include +#include + +HRESULT WvConvertIbStatus(ib_api_status_t status); +HRESULT WvConvertWSAStatus(int status); +HRESULT WvGetUserVerbs(HMODULE hLib, uvp_interface_t *pVerbs); + + +class CWVBase +{ +public: + CWVBase(); + ~CWVBase(); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + STDMETHODIMP Init(); + virtual void Delete() {}; + BOOL WvDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, + LPVOID lpInBuffer, DWORD nInBufferSize, + LPVOID lpOutBuffer, DWORD nOutBufferSize, + LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped); + + HANDLE m_hFile; + volatile LONG m_nRef; + UINT64 m_Id; + +protected: + OVERLAPPED m_Overlap; + CRITICAL_SECTION m_CritSec; +}; + + +#if defined(_WIN64) + #define WvConvertSgl(pSgl, nSge) ((ib_local_ds_t *) pSgl) +#else + static inline ib_local_ds_t *WvConvertSgl(WV_SGE* pSgl, SIZE_T nSge) + { + SIZE_T n; + + for (n = 0; n < nSge; n++) { + pSgl[n].Reserved = 0; + } + return (ib_local_ds_t *) pSgl; + } +#endif (_WIN64) + +#endif // _WV_BASE_H_ diff --git a/branches/WOF2-3/core/winverbs/user/wv_cq.cpp b/branches/WOF2-3/core/winverbs/user/wv_cq.cpp new file mode 100644 index 00000000..9398a7a5 --- /dev/null +++ b/branches/WOF2-3/core/winverbs/user/wv_cq.cpp @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2009 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include "wv_memory.h" +#include "wv_cq.h" +#include "wv_qp.h" +#include "wv_ioctl.h" + +CWVCompletionQueue::CWVCompletionQueue(CWVDevice *pDevice) +{ + pDevice->AddRef(); + m_pDevice = pDevice; + m_pVerbs = &pDevice->m_Verbs; + m_hFile = pDevice->m_hFile; + + m_hVerbsCq = NULL; +} + +STDMETHODIMP CWVCompletionQueue:: +Create(SIZE_T *pEntries) +{ + WV_IO_ID *pId; + DWORD bytes; + ib_api_status_t stat; + HRESULT hr; + ci_umv_buf_t verbsData; + CWVBuffer buf; + + stat = m_pVerbs->pre_create_cq(m_pDevice->m_hVerbsDevice, (UINT32 *) pEntries, + &verbsData, &m_hVerbsCq); + if (stat != IB_SUCCESS) { + return WvConvertIbStatus(stat); + } + + bytes = sizeof WV_IO_ID + max(verbsData.input_size, verbsData.output_size); + pId = (WV_IO_ID *) buf.Get(bytes); + if (pId == NULL) { + hr = WV_NO_MEMORY; + goto post; + } + + pId->Id = m_pDevice->m_Id; + pId->VerbInfo = verbsData.command; + pId->Data = (UINT32) *pEntries; + RtlCopyMemory(pId + 1, (void *) (ULONG_PTR) verbsData.p_inout_buf, + verbsData.input_size); + + if (WvDeviceIoControl(m_hFile, WV_IOCTL_CQ_CREATE, + pId, sizeof WV_IO_ID + verbsData.input_size, + pId, sizeof WV_IO_ID + verbsData.output_size, + &bytes, NULL)) { + hr = WV_SUCCESS; + m_Id = pId->Id; + *pEntries = pId->Data; + } else { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + + verbsData.status = pId->VerbInfo; + RtlCopyMemory((void *) (ULONG_PTR) verbsData.p_inout_buf, pId + 1, + verbsData.output_size); + buf.Put(); + +post: + m_pVerbs->post_create_cq(m_pDevice->m_hVerbsDevice, (ib_api_status_t) hr, + (UINT32) *pEntries, &m_hVerbsCq, &verbsData); + return hr; +} + +CWVCompletionQueue::~CWVCompletionQueue() +{ + DWORD bytes; + HRESULT hr; + + if (m_Id != 0) { + m_pVerbs->pre_destroy_cq(m_hVerbsCq); + hr = WvDeviceIoControl(m_hFile, WV_IOCTL_CQ_DESTROY, &m_Id, sizeof m_Id, + NULL, 0, &bytes, NULL) ? + WV_SUCCESS : HRESULT_FROM_WIN32(GetLastError()); + m_pVerbs->post_destroy_cq(m_hVerbsCq, (ib_api_status_t) hr); + } + m_pDevice->Release(); +} + +STDMETHODIMP CWVCompletionQueue:: +QueryInterface(REFIID riid, LPVOID FAR* ppvObj) +{ + if (riid != IID_IUnknown && riid != IID_IWVCompletionQueue) { + *ppvObj = NULL; + return E_NOINTERFACE; + } + + *ppvObj = this; + AddRef(); + return WV_SUCCESS; +} + +STDMETHODIMP_(ULONG) CWVCompletionQueue:: +AddRef(void) +{ + return CWVBase::AddRef(); +} + +STDMETHODIMP_(ULONG) CWVCompletionQueue:: +Release(void) +{ + return CWVBase::Release(); +} + +STDMETHODIMP CWVCompletionQueue:: +CancelOverlappedRequests(void) +{ + DWORD bytes; + + return WvDeviceIoControl(m_hFile, WV_IOCTL_CQ_CANCEL, &m_Id, sizeof m_Id, + NULL, 0, &bytes, NULL) ? + WV_SUCCESS : HRESULT_FROM_WIN32(GetLastError()); +} + +STDMETHODIMP CWVCompletionQueue:: +GetOverlappedResult(OVERLAPPED *pOverlapped, + DWORD *pNumberOfBytesTransferred, BOOL bWait) +{ + ::GetOverlappedResult(m_hFile, pOverlapped, pNumberOfBytesTransferred, bWait); + return (HRESULT) pOverlapped->Internal; +} + +STDMETHODIMP CWVCompletionQueue:: +Resize(SIZE_T* pEntries) +{ + WV_IO_ID *pId; + DWORD bytes; + ib_api_status_t stat; + HRESULT hr; + ci_umv_buf_t verbsData; + CWVBuffer buf; + + stat = m_pVerbs->pre_resize_cq(m_hVerbsCq, (UINT32 *) pEntries, &verbsData); + if (stat != IB_SUCCESS) { + return WvConvertIbStatus(stat); + } + + bytes = sizeof WV_IO_ID + max(verbsData.input_size, verbsData.output_size); + pId = (WV_IO_ID *) buf.Get(bytes); + if (pId == NULL) { + hr = WV_NO_MEMORY; + goto post; + } + + pId->Id = m_Id; + pId->VerbInfo = verbsData.command; + pId->Data = (UINT32) *pEntries; + RtlCopyMemory(pId + 1, (void *) (ULONG_PTR) verbsData.p_inout_buf, + verbsData.input_size); + + if (WvDeviceIoControl(m_hFile, WV_IOCTL_CQ_RESIZE, + pId, sizeof WV_IO_ID + verbsData.input_size, + pId, sizeof WV_IO_ID + verbsData.output_size, + &bytes, NULL)) { + hr = WV_SUCCESS; + *pEntries = pId->Data; + } else { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + + verbsData.status = pId->VerbInfo; + RtlCopyMemory((void *) (ULONG_PTR) verbsData.p_inout_buf, pId + 1, + verbsData.output_size); + buf.Put(); + +post: + m_pVerbs->post_resize_cq(m_hVerbsCq, (ib_api_status_t) hr, + (UINT32) *pEntries, &verbsData); + return hr; +} + +STDMETHODIMP CWVCompletionQueue:: +Peek(SIZE_T* pCompletedEntries) +{ + ib_api_status_t stat; + + stat = m_pVerbs->peek_cq(m_hVerbsCq, (UINT32 *) pCompletedEntries); + if (stat != IB_SUCCESS) { + return WvConvertIbStatus(stat); + } + + return WV_SUCCESS; +} + +STDMETHODIMP CWVCompletionQueue:: +Notify(WV_CQ_NOTIFY_TYPE Type, OVERLAPPED* pOverlapped) +{ + WV_IO_ID id; + DWORD bytes; + HRESULT hr; + + id.Id = m_Id; + id.Data = Type; + if (WvDeviceIoControl(m_hFile, WV_IOCTL_CQ_NOTIFY, &id, sizeof id, + NULL, 0, &bytes, pOverlapped)) { + hr = WV_SUCCESS; + } else { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + + if (SUCCEEDED(hr) || hr == WV_IO_PENDING) { + switch (Type) { + case WvCqSolicited: + m_pVerbs->rearm_cq(m_hVerbsCq, 1); + break; + case WvCqNextCompletion: + m_pVerbs->rearm_cq(m_hVerbsCq, 0); + break; + default: + break; + } + } + + return hr; +} + +STDMETHODIMP CWVCompletionQueue:: +BatchNotify(SIZE_T CompletedEntries, OVERLAPPED* pOverlapped) +{ + DWORD bytes; + HRESULT hr; + + if (WvDeviceIoControl(m_hFile, WV_IOCTL_CQ_NOTIFY, &m_Id, sizeof m_Id, + NULL, 0, &bytes, pOverlapped)) { + hr = WV_SUCCESS; + } else { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + + if (SUCCEEDED(hr) || hr == WV_IO_PENDING) { + m_pVerbs->rearm_n_cq(m_hVerbsCq, (UINT32) CompletedEntries); + } + + return hr; +} + +STDMETHODIMP_(SIZE_T) CWVCompletionQueue:: +Poll(WV_COMPLETION Completions[], SIZE_T Entries) +{ + // WV_COMPLETION aligns with uvp_wc_t by design. + return m_pVerbs->poll_cq_array(m_hVerbsCq, (UINT32) Entries, (uvp_wc_t *) Completions); +} diff --git a/branches/WOF2-3/core/winverbs/user/wv_cq.h b/branches/WOF2-3/core/winverbs/user/wv_cq.h new file mode 100644 index 00000000..717d9449 --- /dev/null +++ b/branches/WOF2-3/core/winverbs/user/wv_cq.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#ifndef _WV_CQ_H_ +#define _WV_CQ_H_ + +#include +#include "wv_device.h" +#include "wv_base.h" + +class CWVCompletionQueue : IWVCompletionQueue, public CWVBase +{ +public: + // IUnknown methods + STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + // IWVOverlapped methods + STDMETHODIMP CancelOverlappedRequests(); + STDMETHODIMP GetOverlappedResult(OVERLAPPED *pOverlapped, + DWORD *pNumberOfBytesTransferred, BOOL bWait); + + // IWVCompletionQueue methods + STDMETHODIMP Resize(SIZE_T* pEntries); + STDMETHODIMP Peek(SIZE_T* pCompletedEntries); + STDMETHODIMP Notify(WV_CQ_NOTIFY_TYPE Type, OVERLAPPED* pOverlapped); + STDMETHODIMP BatchNotify(SIZE_T CompletedEntries, OVERLAPPED* pOverlapped); + STDMETHODIMP_(SIZE_T) Poll(WV_COMPLETION Completions[], SIZE_T Entries); + + CWVCompletionQueue(CWVDevice *pDevice); + ~CWVCompletionQueue(); + void Delete() {delete this;} + static STDMETHODIMP + CreateInstance(CWVDevice *pDevice, SIZE_T *pEntries, IWVCompletionQueue** ppCq) + { + HRESULT hr; + CWVCompletionQueue *cq; + + cq = new CWVCompletionQueue(pDevice); + if (cq == NULL) { + hr = WV_NO_MEMORY; + goto err1; + } + + hr = cq->Init(); + if (FAILED(hr)) { + goto err2; + } + + hr = cq->Create(pEntries); + if (FAILED(hr)) { + goto err2; + } + + *ppCq = cq; + return WV_SUCCESS; + + err2: + cq->Release(); + err1: + *ppCq = NULL; + return hr; + } + + CWVDevice *m_pDevice; + uvp_interface_t *m_pVerbs; + + ib_cq_handle_t m_hVerbsCq; + +protected: + STDMETHODIMP Create(SIZE_T *pEntries); +}; + +#endif //_WV_CQ_H_ \ No newline at end of file diff --git a/branches/WOF2-3/core/winverbs/user/wv_device.cpp b/branches/WOF2-3/core/winverbs/user/wv_device.cpp new file mode 100644 index 00000000..b260d418 --- /dev/null +++ b/branches/WOF2-3/core/winverbs/user/wv_device.cpp @@ -0,0 +1,495 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2009 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include "wv_memory.h" +#include "wv_device.h" +#include "wv_cq.h" +#include "wv_ioctl.h" +#include "wv_pd.h" + +#ifdef _DEBUG_ +static char *WV_LIB_EXTENSION = "d.dll"; +#else +static char *WV_LIB_EXTENSION = ".dll"; +#endif + +CWVDevice::CWVDevice(CWVProvider *pProvider) +{ + pProvider->AddRef(); + m_pProvider = pProvider; + m_hFile = pProvider->m_hFile; + + m_PortCount = 0; + m_pPorts = NULL; + m_hVerbsDevice = NULL; + m_hLib = NULL; +} + +// Destructor will do necessary cleanup. +STDMETHODIMP CWVDevice:: +Open(NET64 Guid) +{ + char libname[WV_MAX_LIB_NAME]; + WV_IO_ID *pId; + DWORD bytes; + ib_api_status_t stat; + HRESULT hr; + ci_umv_buf_t verbsData; + CWVBuffer buf; + + m_Guid = Guid; + if (!WvDeviceIoControl(m_hFile, WV_IOCTL_LIBRARY_QUERY, &m_Guid, + (DWORD) sizeof m_Guid, libname, + WV_MAX_LIB_NAME - strlen(WV_LIB_EXTENSION), + &bytes, NULL)) { + return HRESULT_FROM_WIN32(GetLastError()); + } + + strcpy(libname + bytes - 1, WV_LIB_EXTENSION); + m_hLib = LoadLibrary(libname); + if (m_hLib == NULL) { + return HRESULT_FROM_WIN32(GetLastError()); + } + + hr = WvGetUserVerbs(m_hLib, &m_Verbs); + if (FAILED(hr)) { + return hr; + } + + stat = m_Verbs.pre_open_ca(m_Guid, &verbsData, &m_hVerbsDevice); + if (stat != IB_SUCCESS) { + return WvConvertIbStatus(stat); + } + + bytes = sizeof WV_IO_ID + max(verbsData.input_size, verbsData.output_size); + pId = (WV_IO_ID *) buf.Get(bytes); + if (pId == NULL) { + hr = WV_NO_MEMORY; + goto post; + } + + pId->Id = m_Guid; + pId->VerbInfo = verbsData.command; + RtlCopyMemory(pId + 1, (void *) (ULONG_PTR) verbsData.p_inout_buf, + verbsData.input_size); + + if (WvDeviceIoControl(m_hFile, WV_IOCTL_DEVICE_OPEN, + pId, sizeof WV_IO_ID + verbsData.input_size, + pId, sizeof WV_IO_ID + verbsData.output_size, + &bytes, NULL)) { + m_Id = pId->Id; + } else { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + + verbsData.status = pId->VerbInfo; + RtlCopyMemory((void *) (ULONG_PTR) verbsData.p_inout_buf, pId + 1, + verbsData.output_size); + buf.Put(); + +post: + stat = m_Verbs.post_open_ca(m_Guid, (ib_api_status_t) hr, + &m_hVerbsDevice, &verbsData); + if (SUCCEEDED(hr) && stat != IB_SUCCESS) { + hr = WvConvertIbStatus(stat); + } + + if (SUCCEEDED(hr)) { + hr = InitPorts(); + } + + return hr; +} + +STDMETHODIMP CWVDevice:: +InitPorts() +{ + WV_DEVICE_ATTRIBUTES attr; + WV_PORT *port; + HRESULT hr; + + hr = Query(&attr); + if (FAILED(hr)) { + return hr; + } + + m_pPorts = new WV_PORT[attr.PhysPortCount]; + if (m_pPorts == NULL) { + return WV_NO_MEMORY; + } + + RtlZeroMemory(m_pPorts, sizeof(WV_PORT) * attr.PhysPortCount); + for (m_PortCount = 0; m_PortCount < attr.PhysPortCount; m_PortCount++) { + port = &m_pPorts[m_PortCount]; + + port->m_Overlap.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + if (port->m_Overlap.hEvent == NULL) { + hr = WV_INSUFFICIENT_RESOURCES; + break; + } + + port->m_Overlap.hEvent = (HANDLE) ((ULONG_PTR) port->m_Overlap.hEvent | 1); + + port->m_Flags = 0xFFFFFFFF; + hr = UpdatePort(m_PortCount + 1); + if (FAILED(hr)) { + CloseHandle(port->m_Overlap.hEvent); + break; + } + } + + return hr; +} + +CWVDevice::~CWVDevice() +{ + WV_PORT *port; + DWORD bytes; + HRESULT hr; + + if (m_hVerbsDevice != NULL) { + m_Verbs.pre_close_ca(m_hVerbsDevice); + hr = WvDeviceIoControl(m_hFile, WV_IOCTL_DEVICE_CLOSE, &m_Id, sizeof m_Id, + NULL, 0, &bytes, NULL) ? + WV_SUCCESS : HRESULT_FROM_WIN32(GetLastError()); + m_Verbs.post_close_ca(m_hVerbsDevice, (ib_api_status_t) hr); + } + + while (m_PortCount--) { + port = &m_pPorts[m_PortCount]; + GetOverlappedResult(&port->m_Overlap, &bytes, TRUE); + CloseHandle(port->m_Overlap.hEvent); + } + + if (m_pPorts != NULL) { + delete m_pPorts; + } + + if (m_hLib != NULL) { + FreeLibrary(m_hLib); + } + m_pProvider->Release(); +} + +STDMETHODIMP CWVDevice:: +QueryInterface(REFIID riid, LPVOID FAR* ppvObj) +{ + if (riid != IID_IUnknown && riid != IID_IWVDevice) { + *ppvObj = NULL; + return E_NOINTERFACE; + } + + *ppvObj = this; + AddRef(); + return WV_SUCCESS; +} + +STDMETHODIMP_(ULONG) CWVDevice:: +AddRef(void) +{ + return CWVBase::AddRef(); +} + +STDMETHODIMP_(ULONG) CWVDevice:: +Release(void) +{ + return CWVBase::Release(); +} + +STDMETHODIMP CWVDevice:: +CancelOverlappedRequests(void) +{ + DWORD bytes; + + return WvDeviceIoControl(m_hFile, WV_IOCTL_DEVICE_CANCEL, &m_Id, sizeof m_Id, + NULL, 0, &bytes, NULL) ? + WV_SUCCESS : HRESULT_FROM_WIN32(GetLastError()); +} + +STDMETHODIMP CWVDevice:: +GetOverlappedResult(OVERLAPPED *pOverlapped, + DWORD *pNumberOfBytesTransferred, BOOL bWait) +{ + ::GetOverlappedResult(m_hFile, pOverlapped, pNumberOfBytesTransferred, bWait); + return (HRESULT) pOverlapped->Internal; +} + +STDMETHODIMP CWVDevice:: +Query(WV_DEVICE_ATTRIBUTES* pAttributes) +{ + WV_IO_DEVICE_ATTRIBUTES attr; + DWORD bytes; + + if (!WvDeviceIoControl(m_hFile, WV_IOCTL_DEVICE_QUERY, &m_Id, sizeof m_Id, + &attr, sizeof attr, &bytes, NULL)) { + return HRESULT_FROM_WIN32(GetLastError()); + } + + pAttributes->FwVersion = attr.FwVersion; + pAttributes->NodeGuid = attr.NodeGuid; + pAttributes->SystemImageGuid = attr.SystemImageGuid; + pAttributes->VendorId = attr.VendorId; + pAttributes->VendorPartId = attr.VendorPartId; + pAttributes->HwVersion = attr.HwVersion; + pAttributes->CapabilityFlags = attr.CapabilityFlags; + pAttributes->AtomicCapability = (WV_ATOMIC_CAPABILITIES) attr.AtomicCapability; + pAttributes->PageSizeCapabilityFlags = attr.PageSizeCapabilityFlags; + pAttributes->MaxMrSize = (SIZE_T) attr.MaxMrSize; + pAttributes->MaxQp = attr.MaxQp; + pAttributes->MaxQpWr = attr.MaxQpWr; + pAttributes->MaxSge = attr.MaxSge; + pAttributes->MaxCq = attr.MaxCq; + pAttributes->MaxCqEntries = attr.MaxCqEntries; + pAttributes->MaxMr = attr.MaxMr; + pAttributes->MaxPd = attr.MaxPd; + pAttributes->MaxQpResponderResources = attr.MaxQpResponderResources; + pAttributes->MaxResponderResources = attr.MaxResponderResources; + pAttributes->MaxQpInitiatorDepth = attr.MaxQpInitiatorDepth; + pAttributes->MaxInlineSend = attr.MaxInlineSend; + pAttributes->MaxMw = attr.MaxMw; + pAttributes->MaxMulticast = attr.MaxMulticast; + pAttributes->MaxQpAttach = attr.MaxQpAttach; + pAttributes->MaxMulticastQp = attr.MaxMulticastQp; + pAttributes->MaxAh = attr.MaxAh; + pAttributes->MaxFmr = attr.MaxFmr; + pAttributes->MaxMapPerFmr = attr.MaxMapPerFmr; + pAttributes->MaxSrq = attr.MaxSrq; + pAttributes->MaxSrqWr = attr.MaxSrqWr; + pAttributes->MaxSrqSge = attr.MaxSrqSge; + pAttributes->MaxPkeys = attr.MaxPkeys; + pAttributes->DeviceType = (WV_DEVICE_TYPE) attr.DeviceType; + pAttributes->LocalAckDelay = attr.LocalAckDelay; + pAttributes->PhysPortCount = attr.PhysPortCount; + + return WV_SUCCESS; +} + +STDMETHODIMP CWVDevice:: +QueryPort(UINT8 PortNumber, WV_PORT_ATTRIBUTES* pAttributes) +{ + WV_IO_DEVICE_PORT_QUERY query; + DWORD bytes; + + query.Id = m_Id; + query.PortNumber = PortNumber; + RtlZeroMemory(&query.Reserved, sizeof query.Reserved); + + if (!WvDeviceIoControl(m_hFile, WV_IOCTL_DEVICE_PORT_QUERY, &query, + sizeof query, pAttributes, sizeof *pAttributes, + &bytes, NULL)) { + return HRESULT_FROM_WIN32(GetLastError()); + } + + pAttributes->PkeyTableLength = min(pAttributes->PkeyTableLength, WV_MAX_PKEYS); + return WV_SUCCESS; +} + +STDMETHODIMP CWVDevice:: +UpdatePort(UINT8 PortNumber) +{ + WV_PORT *port = &m_pPorts[PortNumber - 1]; + HRESULT hr; + + if (port->m_Flags & WV_EVENT_PARTITION) { + UpdatePkeys(PortNumber); + } + + port->m_Flags = 0; + hr = Notify(PortNumber, &port->m_Overlap, &port->m_Flags); + if (FAILED(hr) && hr != WV_IO_PENDING) { + return hr; + } + + return WV_SUCCESS; +} + +STDMETHODIMP CWVDevice:: +QueryGid(UINT8 PortNumber, DWORD Index, WV_GID* pGid) +{ + WV_IO_DEVICE_PORT_QUERY query; + WV_GID *gidtable; + DWORD ngid, bytes; + HRESULT hr; + CWVBuffer buf; + + bytes = sizeof WV_GID * (Index + 1); + gidtable = (WV_GID *) buf.Get(bytes); + if (gidtable == NULL) { + return WV_NO_MEMORY; + } + + query.Id = m_Id; + query.PortNumber = PortNumber; + RtlZeroMemory(&query.Reserved, sizeof query.Reserved); + + if (!WvDeviceIoControl(m_hFile, WV_IOCTL_DEVICE_GID_QUERY, &query, + sizeof query, gidtable, bytes, &bytes, NULL)) { + hr = HRESULT_FROM_WIN32(GetLastError()); + goto out; + } + + ngid = bytes / sizeof WV_GID; + if (Index >= ngid) { + hr = WV_INVALID_PARAMETER_2; + goto out; + } + *pGid = gidtable[Index]; + hr = WV_SUCCESS; + +out: + buf.Put(); + return hr; +} + +STDMETHODIMP CWVDevice:: +FindGid(UINT8 PortNumber, WV_GID *pGid, DWORD *pIndex) +{ + WV_GID gid; + DWORD index; + HRESULT hr; + + for (index = 0; true; index++) { + hr = QueryGid(PortNumber, index, &gid); + if (FAILED(hr)) { + return hr; + } + + if (RtlEqualMemory(pGid, &gid, sizeof(gid))) { + *pIndex = (UINT16) index; + return WV_SUCCESS; + } + } + + return WV_INVALID_ADDRESS; +} + +STDMETHODIMP CWVDevice:: +UpdatePkeys(UINT8 PortNumber) +{ + WV_IO_DEVICE_PORT_QUERY query; + WV_PORT *port; + DWORD bytes; + + port = &m_pPorts[PortNumber - 1]; + bytes = sizeof(port->m_PkeyTable); + + query.Id = m_Id; + query.PortNumber = PortNumber; + RtlZeroMemory(&query.Reserved, sizeof query.Reserved); + + if (!WvDeviceIoControl(m_hFile, WV_IOCTL_DEVICE_PKEY_QUERY, &query, + sizeof query, port->m_PkeyTable, bytes, &bytes, NULL)) { + port->m_PkeyCount = 0; + return HRESULT_FROM_WIN32(GetLastError()); + } + + port->m_PkeyCount = (UINT16) (bytes / sizeof NET16); + return WV_SUCCESS; +} + +STDMETHODIMP CWVDevice:: +QueryPkey(UINT8 PortNumber, UINT16 Index, NET16* pPkey) +{ + WV_PORT *port = &m_pPorts[PortNumber - 1]; + HRESULT hr; + + EnterCriticalSection(&m_CritSec); + if (HasOverlappedIoCompleted(&port->m_Overlap)) { + UpdatePort(PortNumber); + } + + if (Index < port->m_PkeyCount) { + *pPkey = port->m_PkeyTable[Index]; + hr = WV_SUCCESS; + } else { + hr = WV_INVALID_PARAMETER_2; + } + + LeaveCriticalSection(&m_CritSec); + return hr; +} + +STDMETHODIMP CWVDevice:: +FindPkey(UINT8 PortNumber, NET16 Pkey, UINT16 *pIndex) +{ + WV_PORT *port = &m_pPorts[PortNumber - 1]; + UINT16 index; + HRESULT hr = WV_INVALID_ADDRESS; + + EnterCriticalSection(&m_CritSec); + if (HasOverlappedIoCompleted(&port->m_Overlap)) { + UpdatePort(PortNumber); + } + + for (index = 0; index < port->m_PkeyCount; index++) { + if (Pkey == port->m_PkeyTable[index]) { + *pIndex = index; + hr = WV_SUCCESS; + break; + } + } + + LeaveCriticalSection(&m_CritSec); + return hr; +} + +STDMETHODIMP CWVDevice:: +CreateCompletionQueue(SIZE_T *pEntries, IWVCompletionQueue** ppCq) +{ + return CWVCompletionQueue::CreateInstance(this, pEntries, ppCq); +} + +STDMETHODIMP CWVDevice:: +AllocateProtectionDomain(IWVProtectionDomain** ppPd) +{ + return CWVProtectionDomain::CreateInstance(this, ppPd); +} + +STDMETHODIMP CWVDevice:: +Notify(UINT8 PortNumber, OVERLAPPED* pOverlapped, DWORD* pFlags) +{ + WV_IO_ID id; + DWORD bytes; + HRESULT hr; + + id.Id = m_Id; + id.Data = PortNumber; + + if (WvDeviceIoControl(m_hFile, WV_IOCTL_DEVICE_NOTIFY, &id, sizeof id, + pFlags, sizeof DWORD, &bytes, pOverlapped)) { + hr = WV_SUCCESS; + } else { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + + return hr; +} diff --git a/branches/WOF2-3/core/winverbs/user/wv_device.h b/branches/WOF2-3/core/winverbs/user/wv_device.h new file mode 100644 index 00000000..9f4009cd --- /dev/null +++ b/branches/WOF2-3/core/winverbs/user/wv_device.h @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#ifndef _WV_DEVICE_H_ +#define _WV_DEVICE_H_ + +#include +#include +#include +#include "wv_provider.h" +#include "wv_base.h" + +#define WV_MAX_PKEYS 16 + +typedef struct _WV_PORT +{ + OVERLAPPED m_Overlap; + DWORD m_Flags; + UINT16 m_PkeyCount; + NET16 m_PkeyTable[WV_MAX_PKEYS]; + +} WV_PORT; + + +class CWVDevice : IWVDevice, public CWVBase +{ +public: + // IUnknown methods + STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + // IWVOverlapped methods + STDMETHODIMP CancelOverlappedRequests(); + STDMETHODIMP GetOverlappedResult(OVERLAPPED *pOverlapped, + DWORD *pNumberOfBytesTransferred, BOOL bWait); + + // IWVDevice methods + STDMETHODIMP Query(WV_DEVICE_ATTRIBUTES* pAttributes); + STDMETHODIMP QueryPort(UINT8 PortNumber, WV_PORT_ATTRIBUTES* pAttributes); + STDMETHODIMP QueryGid(UINT8 PortNumber, DWORD Index, WV_GID* pGid); + STDMETHODIMP FindGid(UINT8 PortNumber, WV_GID *pGid, DWORD *pIndex); + STDMETHODIMP QueryPkey(UINT8 PortNumber, UINT16 Index, NET16* pPkey); + STDMETHODIMP FindPkey(UINT8 PortNumber, NET16 Pkey, UINT16 *pIndex); + STDMETHODIMP CreateCompletionQueue(SIZE_T *pEntries, IWVCompletionQueue** ppCq); + STDMETHODIMP AllocateProtectionDomain(IWVProtectionDomain** ppPd); + STDMETHODIMP Notify(UINT8 PortNumber, OVERLAPPED* pOverlapped, DWORD* pFlags); + + CWVDevice(CWVProvider *pProvider); + ~CWVDevice(); + void Delete() {delete this;} + static STDMETHODIMP + CreateInstance(CWVProvider *pProvider, NET64 Guid, IWVDevice** ppDevice) + { + HRESULT hr; + CWVDevice *dev; + + dev = new CWVDevice(pProvider); + if (dev == NULL) { + hr = WV_NO_MEMORY; + goto err1; + } + + hr = dev->Init(); + if (FAILED(hr)) { + goto err2; + } + + hr = dev->Open(Guid); + if (FAILED(hr)) { + goto err2; + } + + *ppDevice = dev; + return WV_SUCCESS; + + err2: + dev->Release(); + err1: + *ppDevice = NULL; + return hr; + } + + CWVProvider *m_pProvider; + uvp_interface_t m_Verbs; + + ib_ca_handle_t m_hVerbsDevice; + NET64 m_Guid; + +protected: + HMODULE m_hLib; + STDMETHODIMP Open(NET64 Guid); + + WV_PORT *m_pPorts; + UINT8 m_PortCount; + STDMETHODIMP InitPorts(); + STDMETHODIMP UpdatePort(UINT8 PortNumber); + STDMETHODIMP UpdatePkeys(UINT8 PortNumber); +}; + +#endif // __WV_DEVICE_H_ diff --git a/branches/WOF2-3/core/winverbs/user/wv_ep.cpp b/branches/WOF2-3/core/winverbs/user/wv_ep.cpp new file mode 100644 index 00000000..28d2f7db --- /dev/null +++ b/branches/WOF2-3/core/winverbs/user/wv_ep.cpp @@ -0,0 +1,588 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2009 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "wv_memory.h" +#include "wv_ep.h" +#include "wv_ioctl.h" +#include "wv_qp.h" + +static void WvIoConvertConnParam(WV_IO_CONNECT_PARAM *pIoParam, + WV_CONNECT_PARAM *pParam) +{ + pIoParam->DataLength = (UINT8) pParam->DataLength; + pIoParam->ResponderResources = pParam->ResponderResources; + pIoParam->InitiatorDepth = pParam->InitiatorDepth; + pIoParam->RetryCount = pParam->RetryCount; + pIoParam->RnrRetryCount = pParam->RnrRetryCount; + RtlZeroMemory(pIoParam->Reserved, sizeof pIoParam->Reserved); + RtlCopyMemory(pIoParam->Data, pParam->Data, pParam->DataLength); +} + +CWVConnectEndpoint::CWVConnectEndpoint(CWVProvider *pProvider) +{ + pProvider->AddRef(); + m_pProvider = pProvider; + m_hFile = pProvider->m_hFile; + m_Socket = INVALID_SOCKET; + m_pQp = NULL; +} + +STDMETHODIMP CWVConnectEndpoint:: +Allocate(void) +{ + UINT64 EpType; + DWORD bytes; + HRESULT hr; + + EpType = WV_IO_EP_TYPE_CONNECT; + if (WvDeviceIoControl(m_hFile, WV_IOCTL_EP_CREATE, &EpType, sizeof EpType, + &m_Id, sizeof m_Id, &bytes, NULL)) { + hr = WV_SUCCESS; + } else { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + + return hr; +} + +CWVConnectEndpoint::~CWVConnectEndpoint() +{ + DWORD bytes; + + if (m_pQp != NULL) { + m_pQp->Release(); + } + + if (m_Id != 0) { + WvDeviceIoControl(m_hFile, WV_IOCTL_EP_DESTROY, &m_Id, sizeof m_Id, + NULL, 0, &bytes, NULL); + } + + if (m_Socket != INVALID_SOCKET) { + closesocket(m_Socket); + } + m_pProvider->Release(); +} + +STDMETHODIMP CWVConnectEndpoint:: +QueryInterface(REFIID riid, LPVOID FAR* ppvObj) +{ + if (riid != IID_IUnknown && riid != IID_IWVEndpoint && + riid != IID_IWVConnectEndpoint) { + *ppvObj = NULL; + return E_NOINTERFACE; + } + + *ppvObj = this; + AddRef(); + return WV_SUCCESS; +} + +STDMETHODIMP_(ULONG) CWVConnectEndpoint:: +AddRef(void) +{ + return CWVBase::AddRef(); +} + +STDMETHODIMP_(ULONG) CWVConnectEndpoint:: +Release(void) +{ + return CWVBase::Release(); +} + +STDMETHODIMP CWVConnectEndpoint:: +CancelOverlappedRequests(void) +{ + DWORD bytes; + + return WvDeviceIoControl(m_hFile, WV_IOCTL_EP_CANCEL, &m_Id, sizeof m_Id, + NULL, 0, &bytes, NULL) ? + WV_SUCCESS : HRESULT_FROM_WIN32(GetLastError()); +} + +STDMETHODIMP CWVConnectEndpoint:: +GetOverlappedResult(OVERLAPPED *pOverlapped, + DWORD *pNumberOfBytesTransferred, BOOL bWait) +{ + ::GetOverlappedResult(m_hFile, pOverlapped, pNumberOfBytesTransferred, bWait); + return (HRESULT) pOverlapped->Internal; +} + +STDMETHODIMP CWVConnectEndpoint:: +Modify(DWORD Option, const VOID* pOptionData, SIZE_T OptionLength) +{ + WV_IO_ID *pId; + DWORD bytes; + HRESULT hr; + CWVBuffer buf; + + bytes = sizeof WV_IO_ID + OptionLength; + pId = (WV_IO_ID *) buf.Get(bytes); + if (pId == NULL) { + return WV_NO_MEMORY; + } + + pId->Id = m_Id; + pId->Data = Option; + RtlCopyMemory(pId + 1, pOptionData, OptionLength); + + if (WvDeviceIoControl(m_hFile, WV_IOCTL_EP_MODIFY, pId, bytes, + NULL, 0, &bytes, NULL)) { + hr = WV_SUCCESS; + } else { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + + buf.Put(); + return hr; +} + +STDMETHODIMP CWVConnectEndpoint:: +BindAddress(SOCKADDR* pAddress) +{ + WV_IO_EP_BIND attr; + BOOLEAN any; + DWORD bytes; + int len; + HRESULT hr; + + if (pAddress->sa_family == AF_INET) { + any = (((SOCKADDR_IN *) pAddress)->sin_addr.S_un.S_addr == INADDR_ANY); + bytes = sizeof(SOCKADDR_IN); + } else { + any = IN6ADDR_ISANY((SOCKADDR_IN6 *) pAddress); + bytes = sizeof(SOCKADDR_IN6); + } + + if (any) { + RtlZeroMemory(&attr.Device, sizeof attr.Device); + } else { + hr = m_pProvider->TranslateAddress(pAddress, (WV_DEVICE_ADDRESS *) &attr.Device); + if (FAILED(hr)) { + return hr; + } + } + + m_Socket = socket(pAddress->sa_family, SOCK_STREAM, IPPROTO_TCP); + if (m_Socket == INVALID_SOCKET) { + return WvConvertWSAStatus(WSAGetLastError()); + } + + hr = bind(m_Socket, pAddress, bytes); + if (FAILED(hr)) { + goto get_err; + } + + attr.Id = m_Id; + len = sizeof attr.Address; + hr = getsockname(m_Socket, (sockaddr *) &attr.Address, &len); + if (FAILED(hr)) { + goto get_err; + } + + if (!WvDeviceIoControl(m_hFile, WV_IOCTL_EP_BIND, &attr, sizeof attr, + &attr, sizeof attr, &bytes, NULL)) { + hr = HRESULT_FROM_WIN32(GetLastError()); + goto err; + } + + return WV_SUCCESS; + +get_err: + hr = WvConvertWSAStatus(WSAGetLastError()); +err: + closesocket(m_Socket); + m_Socket = INVALID_SOCKET; + return hr; +} + +STDMETHODIMP CWVConnectEndpoint:: +Listen(SIZE_T Backlog) +{ + WV_IO_EP_LISTEN attr; + DWORD bytes; + HRESULT hr; + + attr.Id = m_Id; + attr.Backlog = Backlog; + + if (!WvDeviceIoControl(m_hFile, WV_IOCTL_EP_LISTEN, &attr, sizeof attr, + &attr, sizeof attr, &bytes, NULL)) { + hr = HRESULT_FROM_WIN32(GetLastError()); + } else { + hr = WV_SUCCESS; + } + + return hr; +} + +STDMETHODIMP CWVConnectEndpoint:: +Reject(const VOID* pUserData, SIZE_T UserDataLength) +{ + WV_IO_ID *pId; + DWORD bytes; + HRESULT hr; + CWVBuffer buf; + + bytes = sizeof WV_IO_ID + UserDataLength; + pId = (WV_IO_ID *) buf.Get(bytes); + if (pId == NULL) { + return WV_NO_MEMORY; + } + + pId->Id = m_Id; + RtlCopyMemory(pId + 1, pUserData, UserDataLength); + + if (WvDeviceIoControl(m_hFile, WV_IOCTL_EP_REJECT, pId, bytes, + NULL, 0, &bytes, NULL)) { + hr = WV_SUCCESS; + } else { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + + buf.Put(); + return hr; +} + +STDMETHODIMP CWVConnectEndpoint:: +GetRequest(IWVConnectEndpoint* pEndpoint, OVERLAPPED* pOverlapped) +{ + WV_IO_EP_GET_REQUEST req; + DWORD bytes; + HRESULT hr; + + req.Id = m_Id; + req.EpId = ((CWVConnectEndpoint *) pEndpoint)->m_Id; + if (WvDeviceIoControl(m_hFile, WV_IOCTL_EP_GET_REQUEST, + &req, sizeof req, NULL, 0, &bytes, pOverlapped)) { + hr = WV_SUCCESS; + } else { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + + return hr; +} + +STDMETHODIMP CWVConnectEndpoint:: +Connect(IWVConnectQueuePair* pQp, const SOCKADDR* pAddress, + WV_CONNECT_PARAM* pParam, OVERLAPPED* pOverlapped) +{ + WV_IO_EP_CONNECT attr; + DWORD bytes; + HRESULT hr; + + m_pQp = (CWVConnectQueuePair *) pQp; + m_pQp->AddRef(); + attr.Id = m_Id; + attr.QpId = m_pQp->m_Id; + + if (pAddress->sa_family == AF_INET) { + RtlCopyMemory(&attr.PeerAddress, pAddress, sizeof(SOCKADDR_IN)); + } else { + RtlCopyMemory(&attr.PeerAddress, pAddress, sizeof(SOCKADDR_IN6)); + } + WvIoConvertConnParam(&attr.Param, pParam); + + if (WvDeviceIoControl(m_hFile, WV_IOCTL_EP_CONNECT, &attr, sizeof attr, + NULL, 0, &bytes, pOverlapped)) { + hr = WV_SUCCESS; + } else { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + + return hr; +} + +STDMETHODIMP CWVConnectEndpoint:: +Accept(IWVConnectQueuePair* pQp, WV_CONNECT_PARAM* pParam, OVERLAPPED* pOverlapped) +{ + WV_IO_EP_ACCEPT attr; + DWORD bytes; + HRESULT hr; + void *pout; + DWORD size; + + if (m_pQp == NULL) { + m_pQp = (CWVConnectQueuePair *) pQp; + m_pQp->AddRef(); + } + + attr.Id = m_Id; + attr.QpId = m_pQp->m_Id; + m_pQp->m_pVerbs->nd_modify_qp(m_pQp->m_hVerbsQp, &pout, &size); + WvIoConvertConnParam(&attr.Param, pParam); + + if (WvDeviceIoControl(m_hFile, WV_IOCTL_EP_ACCEPT, &attr, sizeof attr, + pout, size, &bytes, pOverlapped)) { + hr = WV_SUCCESS; + } else { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + + return hr; +} + +STDMETHODIMP CWVConnectEndpoint:: +Disconnect(OVERLAPPED* pOverlapped) +{ + WV_IO_EP_DISCONNECT attr; + DWORD bytes; + HRESULT hr; + void *pout; + DWORD size; + + attr.Id = m_Id; + attr.QpId = m_pQp->m_Id; + m_pQp->m_pVerbs->nd_modify_qp(m_pQp->m_hVerbsQp, &pout, &size); + + if (WvDeviceIoControl(m_hFile, WV_IOCTL_EP_DISCONNECT, + &attr, sizeof attr, pout, size, &bytes, pOverlapped)) { + hr = WV_SUCCESS; + } else { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + + return hr; +} + +STDMETHODIMP CWVConnectEndpoint:: +NotifyDisconnect(OVERLAPPED* pOverlapped) +{ + DWORD bytes; + HRESULT hr; + + if (WvDeviceIoControl(m_hFile, WV_IOCTL_EP_DISCONNECT_NOTIFY, + &m_Id, sizeof m_Id, NULL, 0, &bytes, pOverlapped)) { + hr = WV_SUCCESS; + } else { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + + return hr; +} + +STDMETHODIMP CWVConnectEndpoint:: +Query(WV_CONNECT_ATTRIBUTES* pAttributes) +{ + WV_IO_EP_ATTRIBUTES attr; + DWORD bytes; + HRESULT hr; + + if (!WvDeviceIoControl(m_hFile, WV_IOCTL_EP_QUERY, &m_Id, sizeof m_Id, + &attr, sizeof attr, &bytes, NULL)) { + return HRESULT_FROM_WIN32(GetLastError()); + } + + RtlCopyMemory(&pAttributes->LocalAddress, &attr.LocalAddress, + sizeof pAttributes->LocalAddress); + RtlCopyMemory(&pAttributes->PeerAddress, &attr.PeerAddress, + sizeof pAttributes->PeerAddress); + RtlCopyMemory(&pAttributes->Device, &attr.Device, sizeof pAttributes->Device); + pAttributes->Param.DataLength = attr.Param.Connect.DataLength; + pAttributes->Param.ResponderResources = (SIZE_T) attr.Param.Connect.ResponderResources; + pAttributes->Param.InitiatorDepth = (SIZE_T) attr.Param.Connect.InitiatorDepth; + pAttributes->Param.RetryCount = attr.Param.Connect.RetryCount; + pAttributes->Param.RnrRetryCount = attr.Param.Connect.RnrRetryCount; + RtlCopyMemory(pAttributes->Param.Data, attr.Param.Connect.Data, attr.Param.Connect.DataLength); + + return WV_SUCCESS; +} + + +CWVDatagramEndpoint::CWVDatagramEndpoint(CWVProvider *pProvider) +{ + pProvider->AddRef(); + m_pProvider = pProvider; + m_hFile = pProvider->m_hFile; +} + +STDMETHODIMP CWVDatagramEndpoint:: +Allocate(void) +{ + UINT64 EpType; + DWORD bytes; + HRESULT hr; + + EpType = WV_IO_EP_TYPE_DATAGRAM; + if (WvDeviceIoControl(m_hFile, WV_IOCTL_EP_CREATE, &EpType, sizeof EpType, + &m_Id, sizeof m_Id, &bytes, NULL)) { + hr = WV_SUCCESS; + } else { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + + return hr; +} + +CWVDatagramEndpoint::~CWVDatagramEndpoint() +{ + DWORD bytes; + + if (m_Id != 0) { + WvDeviceIoControl(m_hFile, WV_IOCTL_EP_DESTROY, &m_Id, sizeof m_Id, + NULL, 0, &bytes, NULL); + } + m_pProvider->Release(); +} + +STDMETHODIMP CWVDatagramEndpoint:: +QueryInterface(REFIID riid, LPVOID FAR* ppvObj) +{ + if (riid != IID_IUnknown && riid != IID_IWVEndpoint && + riid != IID_IWVDatagramEndpoint) { + *ppvObj = NULL; + return E_NOINTERFACE; + } + + *ppvObj = this; + AddRef(); + return WV_SUCCESS; +} + +STDMETHODIMP_(ULONG) CWVDatagramEndpoint:: +AddRef(void) +{ + return CWVBase::AddRef(); +} + +STDMETHODIMP_(ULONG) CWVDatagramEndpoint:: +Release(void) +{ + return CWVBase::Release(); +} + +STDMETHODIMP CWVDatagramEndpoint:: +CancelOverlappedRequests(void) +{ + DWORD bytes; + + return WvDeviceIoControl(m_hFile, WV_IOCTL_EP_CANCEL, &m_Id, sizeof m_Id, + NULL, 0, &bytes, NULL) ? + WV_SUCCESS : HRESULT_FROM_WIN32(GetLastError()); +} + +STDMETHODIMP CWVDatagramEndpoint:: +GetOverlappedResult(OVERLAPPED *pOverlapped, + DWORD *pNumberOfBytesTransferred, BOOL bWait) +{ + ::GetOverlappedResult(m_hFile, pOverlapped, pNumberOfBytesTransferred, bWait); + return (HRESULT) pOverlapped->Internal; +} + +STDMETHODIMP CWVDatagramEndpoint:: +Modify(DWORD Option, const VOID* pOptionData, SIZE_T OptionLength) +{ + UNREFERENCED_PARAMETER(Option); + UNREFERENCED_PARAMETER(pOptionData); + UNREFERENCED_PARAMETER(OptionLength); + + return E_NOTIMPL; +} + +STDMETHODIMP CWVDatagramEndpoint:: +BindAddress(SOCKADDR* pAddress) +{ + UNREFERENCED_PARAMETER(pAddress); + + return E_NOTIMPL; +} + +STDMETHODIMP CWVDatagramEndpoint:: +Listen(SIZE_T Backlog) +{ + UNREFERENCED_PARAMETER(Backlog); + + return E_NOTIMPL; +} + +STDMETHODIMP CWVDatagramEndpoint:: +Reject(const VOID* pUserData, SIZE_T UserDataLength) +{ + UNREFERENCED_PARAMETER(pUserData); + UNREFERENCED_PARAMETER(UserDataLength); + + return E_NOTIMPL; +} + +STDMETHODIMP CWVDatagramEndpoint:: +GetRequest(IWVDatagramEndpoint* pEndpoint, OVERLAPPED* pOverlapped) +{ + UNREFERENCED_PARAMETER(pEndpoint); + UNREFERENCED_PARAMETER(pOverlapped); + + return E_NOTIMPL; +} + +STDMETHODIMP CWVDatagramEndpoint:: +Lookup(const SOCKADDR* pAddress, const VOID* pUserData, + SIZE_T UserDataLength, OVERLAPPED* pOverlapped) +{ + UNREFERENCED_PARAMETER(pAddress); + UNREFERENCED_PARAMETER(pUserData); + UNREFERENCED_PARAMETER(UserDataLength); + UNREFERENCED_PARAMETER(pOverlapped); + + return E_NOTIMPL; +} + +STDMETHODIMP CWVDatagramEndpoint:: +Accept(WV_DATAGRAM_PARAM* pParam, OVERLAPPED* pOverlapped) +{ + UNREFERENCED_PARAMETER(pParam); + UNREFERENCED_PARAMETER(pOverlapped); + + return E_NOTIMPL; +} + +STDMETHODIMP CWVDatagramEndpoint:: +JoinMulticast(const SOCKADDR* pAddress, OVERLAPPED* pOverlapped) +{ + UNREFERENCED_PARAMETER(pAddress); + UNREFERENCED_PARAMETER(pOverlapped); + + return E_NOTIMPL; +} + +STDMETHODIMP CWVDatagramEndpoint:: +LeaveMulticast(const SOCKADDR* pAddress, OVERLAPPED* pOverlapped) +{ + UNREFERENCED_PARAMETER(pAddress); + UNREFERENCED_PARAMETER(pOverlapped); + + return E_NOTIMPL; +} + +STDMETHODIMP CWVDatagramEndpoint:: +Query(WV_DATAGRAM_ATTRIBUTES* pAttributes) +{ + UNREFERENCED_PARAMETER(pAttributes); + + return E_NOTIMPL; +} diff --git a/branches/WOF2-3/core/winverbs/user/wv_ep.h b/branches/WOF2-3/core/winverbs/user/wv_ep.h new file mode 100644 index 00000000..0d8422bd --- /dev/null +++ b/branches/WOF2-3/core/winverbs/user/wv_ep.h @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#ifndef _WV_EP_H_ +#define _WV_EP_H_ + +#include +#include "wv_provider.h" +#include "wv_base.h" +#include "wv_qp.h" + +class CWVConnectEndpoint : IWVConnectEndpoint, public CWVBase +{ +public: + // IUnknown methods + STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + // IWVOverlapped methods + STDMETHODIMP CancelOverlappedRequests(); + STDMETHODIMP GetOverlappedResult(OVERLAPPED *pOverlapped, + DWORD *pNumberOfBytesTransferred, BOOL bWait); + + // IWVEndpoint methods + STDMETHODIMP Modify(DWORD Option, const VOID* pOptionData, SIZE_T OptionLength); + STDMETHODIMP BindAddress(SOCKADDR* pAddress); + STDMETHODIMP Listen(SIZE_T Backlog); + STDMETHODIMP Reject(const VOID* pUserData, SIZE_T UserDataLength); + + // IWVConnectEndpoint methods + STDMETHODIMP GetRequest(IWVConnectEndpoint* pEndpoint, OVERLAPPED* pOverlapped); + STDMETHODIMP Connect(IWVConnectQueuePair* pQp, const SOCKADDR* pAddress, + WV_CONNECT_PARAM* pParam, OVERLAPPED* pOverlapped); + STDMETHODIMP Accept(IWVConnectQueuePair* pQp, WV_CONNECT_PARAM* pParam, + OVERLAPPED* pOverlapped); + STDMETHODIMP Disconnect(OVERLAPPED* pOverlapped); + STDMETHODIMP NotifyDisconnect(OVERLAPPED* pOverlapped); + STDMETHODIMP Query(WV_CONNECT_ATTRIBUTES* pAttributes); + + CWVConnectEndpoint(CWVProvider *pProvider); + ~CWVConnectEndpoint(); + void Delete() {delete this;} + static STDMETHODIMP + CreateInstance(CWVProvider *pProvider, IWVConnectEndpoint** ppConnectEndpoint) + { + HRESULT hr; + CWVConnectEndpoint *ep; + + ep = new CWVConnectEndpoint(pProvider); + if (ep == NULL) { + hr = WV_NO_MEMORY; + goto err1; + } + + hr = ep->Init(); + if (FAILED(hr)) { + goto err2; + } + + hr = ep->Allocate(); + if (FAILED(hr)) { + goto err2; + } + + *ppConnectEndpoint = ep; + return WV_SUCCESS; + + err2: + ep->Release(); + err1: + *ppConnectEndpoint = NULL; + return hr; + } + + CWVProvider *m_pProvider; + +protected: + SOCKET m_Socket; + CWVConnectQueuePair *m_pQp; + + STDMETHODIMP Allocate(); +}; + +class CWVDatagramEndpoint : IWVDatagramEndpoint, public CWVBase +{ +public: + // IUnknown methods + STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + // IWVOverlapped methods + STDMETHODIMP CancelOverlappedRequests(); + STDMETHODIMP GetOverlappedResult(OVERLAPPED *pOverlapped, + DWORD *pNumberOfBytesTransferred, BOOL bWait); + + // IWVEndpoint methods + STDMETHODIMP Modify(DWORD Option, const VOID* pOptionData, SIZE_T OptionLength); + STDMETHODIMP BindAddress(SOCKADDR* pAddress); + STDMETHODIMP Listen(SIZE_T Backlog); + STDMETHODIMP Reject(const VOID* pUserData, SIZE_T UserDataLength); + + // IWVDatagramEndpoint methods + STDMETHODIMP GetRequest(IWVDatagramEndpoint* pEndpoint, OVERLAPPED* pOverlapped); + STDMETHODIMP Lookup(const SOCKADDR* pAddress, const VOID* pUserData, + SIZE_T UserDataLength, OVERLAPPED* pOverlapped); + STDMETHODIMP Accept(WV_DATAGRAM_PARAM* pParam, OVERLAPPED* pOverlapped); + STDMETHODIMP JoinMulticast(const SOCKADDR* pAddress, + OVERLAPPED* pOverlapped); + STDMETHODIMP LeaveMulticast(const SOCKADDR* pAddress, + OVERLAPPED* pOverlapped); + STDMETHODIMP Query(WV_DATAGRAM_ATTRIBUTES* pAttributes); + + CWVDatagramEndpoint(CWVProvider *pProvider); + ~CWVDatagramEndpoint(); + void Delete() {delete this;} + static STDMETHODIMP + CreateInstance(CWVProvider *pProvider, IWVDatagramEndpoint** ppDatagramEndpoint) + { + HRESULT hr; + CWVDatagramEndpoint *ep; + + ep = new CWVDatagramEndpoint(pProvider); + if (ep == NULL) { + hr = WV_NO_MEMORY; + goto err1; + } + + hr = ep->Init(); + if (FAILED(hr)) { + goto err2; + } + + hr = ep->Allocate(); + if (FAILED(hr)) { + goto err2; + } + + *ppDatagramEndpoint = ep; + return WV_SUCCESS; + + err2: + ep->Release(); + err1: + *ppDatagramEndpoint = NULL; + return hr; + } + + CWVProvider *m_pProvider; + +protected: + STDMETHODIMP Allocate(); +}; + +#endif // _WV_EP_H_ diff --git a/branches/WOF2-3/core/winverbs/user/wv_exports.src b/branches/WOF2-3/core/winverbs/user/wv_exports.src new file mode 100644 index 00000000..ed6a38c0 --- /dev/null +++ b/branches/WOF2-3/core/winverbs/user/wv_exports.src @@ -0,0 +1,9 @@ +#if DBG +LIBRARY winverbsd.dll +#else +LIBRARY winverbs.dll +#endif + +EXPORTS +DllCanUnloadNow PRIVATE + diff --git a/branches/WOF2-3/core/winverbs/user/wv_main.cpp b/branches/WOF2-3/core/winverbs/user/wv_main.cpp new file mode 100644 index 00000000..32d1aaee --- /dev/null +++ b/branches/WOF2-3/core/winverbs/user/wv_main.cpp @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "wv_memory.h" +#include "wv_provider.h" +#include "wv_base.h" + +volatile LONG WvRef; +HANDLE heap; + +BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) +{ + UNREFERENCED_PARAMETER(hInstance); + UNREFERENCED_PARAMETER(lpReserved); + + switch (dwReason) { + case DLL_PROCESS_ATTACH: + heap = HeapCreate(0, 0, 0); + if (heap == NULL) { + return FALSE; + } + break; + case DLL_PROCESS_DETACH: + HeapDestroy(heap); + break; + default: + break; + } + + return TRUE; +} + +STDAPI DllCanUnloadNow(void) +{ + return WvRef ? S_FALSE : S_OK; +} + +__declspec(dllexport) HRESULT WvGetObject(REFIID riid, LPVOID FAR* ppvObj) +{ + if (riid != IID_IWVProvider) { + *ppvObj = NULL; + return E_NOINTERFACE; + } + + return CWVProvider::CreateInstance((IWVProvider **) ppvObj); +} + +HRESULT WvConvertIbStatus(ib_api_status_t status) +{ + switch (status) { + case IB_SUCCESS: return WV_SUCCESS; + case IB_INSUFFICIENT_RESOURCES: return WV_INSUFFICIENT_RESOURCES; + case IB_INSUFFICIENT_MEMORY: return WV_NO_MEMORY; + case IB_INVALID_PARAMETER: return WV_INVALID_PARAMETER; + case IB_INVALID_SETTING: return WV_INVALID_PARAMETER; + case IB_NOT_FOUND: return WV_INVALID_ADDRESS; + case IB_TIMEOUT: return WV_TIMEOUT; + case IB_CANCELED: return WV_CANCELLED; + case IB_INTERRUPTED: return WV_CANCELLED; + case IB_INVALID_PERMISSION: return WV_ACCESS_VIOLATION; + case IB_UNSUPPORTED: return WV_NOT_SUPPORTED; + case IB_OVERFLOW: return WV_BUFFER_OVERFLOW; + case IB_MAX_MCAST_QPS_REACHED: return WV_INSUFFICIENT_RESOURCES; + case IB_INVALID_QP_STATE: return WV_INVALID_PARAMETER; + case IB_INVALID_APM_STATE: return WV_INVALID_PARAMETER; + case IB_INVALID_PORT_STATE: return WV_INVALID_PARAMETER; + case IB_INVALID_STATE: return WV_INVALID_PARAMETER; + case IB_RESOURCE_BUSY: return WV_DEVICE_BUSY; + case IB_INVALID_PKEY: return WV_INVALID_HANDLE; + case IB_INVALID_LKEY: return WV_INVALID_HANDLE; + case IB_INVALID_RKEY: return WV_INVALID_HANDLE; + case IB_INVALID_MAX_WRS: return WV_INSUFFICIENT_RESOURCES; + case IB_INVALID_MAX_SGE: return WV_INSUFFICIENT_RESOURCES; + case IB_INVALID_CQ_SIZE: return WV_INSUFFICIENT_RESOURCES; + case IB_INVALID_SRQ_SIZE: return WV_INSUFFICIENT_RESOURCES; + case IB_INVALID_SERVICE_TYPE: return WV_NOT_SUPPORTED; + case IB_INVALID_GID: return WV_INVALID_ADDRESS; + case IB_INVALID_LID: return WV_INVALID_ADDRESS; + case IB_INVALID_GUID: return WV_INVALID_ADDRESS; + case IB_INVALID_GUID_MASK: return WV_INVALID_ADDRESS; + case IB_INVALID_CA_HANDLE: return WV_INVALID_HANDLE; + case IB_INVALID_AV_HANDLE: return WV_INVALID_HANDLE; + case IB_INVALID_CQ_HANDLE: return WV_INVALID_HANDLE; + case IB_INVALID_QP_HANDLE: return WV_INVALID_HANDLE; + case IB_INVALID_SRQ_HANDLE: return WV_INVALID_HANDLE; + case IB_INVALID_PD_HANDLE: return WV_INVALID_HANDLE; + case IB_INVALID_MR_HANDLE: return WV_INVALID_HANDLE; + case IB_INVALID_FMR_HANDLE: return WV_INVALID_HANDLE; + case IB_INVALID_MW_HANDLE: return WV_INVALID_HANDLE; + case IB_INVALID_MCAST_HANDLE: return WV_INVALID_HANDLE; + case IB_INVALID_CALLBACK: return WV_INVALID_PARAMETER; + case IB_INVALID_AL_HANDLE: return WV_INVALID_HANDLE; + case IB_INVALID_HANDLE: return WV_INVALID_HANDLE; + case IB_ERROR: return WV_UNKNOWN_ERROR; + case IB_REMOTE_ERROR: return WV_REMOTE_OP_ERROR; + case IB_VERBS_PROCESSING_DONE: return WV_SUCCESS; + case IB_INVALID_WR_TYPE: return WV_INVALID_PARAMETER; + case IB_QP_IN_TIMEWAIT: return WV_INVALID_PARAMETER; + case IB_EE_IN_TIMEWAIT: return WV_INVALID_PARAMETER; + case IB_INVALID_PORT: return WV_INVALID_ADDRESS; + case IB_NOT_DONE: return WV_PENDING; + case IB_INVALID_INDEX: return WV_INVALID_PARAMETER; + case IB_NO_MATCH: return WV_INVALID_PARAMETER; + case IB_PENDING: return WV_PENDING; + default: return WV_UNKNOWN_ERROR; + } +} + +HRESULT WvConvertWSAStatus(int status) +{ + switch (status) { + case 0: return WV_SUCCESS; + case WSAEADDRINUSE: return WV_ADDRESS_ALREADY_EXISTS; + case WSAEADDRNOTAVAIL: return WV_INVALID_ADDRESS; + case WSAENETDOWN: return WV_HOST_UNREACHABLE; + case WSAENETUNREACH: return WV_HOST_UNREACHABLE; + case WSAECONNABORTED: return WV_CONNECTION_ABORTED; + case WSAEISCONN: return WV_CONNECTION_ACTIVE; + case WSAENOTCONN: return WV_CONNECTION_INVALID; + case WSAETIMEDOUT: return WV_IO_TIMEOUT; + case WSAECONNREFUSED: return WV_CONNECTION_REFUSED; + case WSAEHOSTUNREACH: return WV_HOST_UNREACHABLE; + case WSAEACCES: return WV_ADDRESS_ALREADY_EXISTS; + default: return WV_UNKNOWN_ERROR; + } +} \ No newline at end of file diff --git a/branches/WOF2-3/core/winverbs/user/wv_memory.h b/branches/WOF2-3/core/winverbs/user/wv_memory.h new file mode 100644 index 00000000..292c2e4a --- /dev/null +++ b/branches/WOF2-3/core/winverbs/user/wv_memory.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#ifndef _WV_MEMORY_H_ +#define _WV_MEMORY_H_ + +#include + +extern HANDLE heap; + +__inline void* __cdecl operator new(size_t size) +{ + return HeapAlloc(heap, 0, size); +} + +__inline void __cdecl operator delete(void *pObj) +{ + HeapFree(heap, 0, pObj); +} + +const int WvDefaultBufferSize = 128; + +class CWVBuffer +{ +public: + void* Get(size_t size) + { + if (size <= WvDefaultBufferSize) { + m_pBuf = m_Buffer; + } else { + m_pBuf = new UINT8[size]; + } + return m_pBuf; + } + + void Put() + { + if (m_pBuf != m_Buffer) { + delete []m_pBuf; + } + } +protected: + UINT8 m_Buffer[WvDefaultBufferSize]; + void *m_pBuf; +}; + +#endif // _WV_MEMORY_H_ diff --git a/branches/WOF2-3/core/winverbs/user/wv_pd.cpp b/branches/WOF2-3/core/winverbs/user/wv_pd.cpp new file mode 100644 index 00000000..ea93e224 --- /dev/null +++ b/branches/WOF2-3/core/winverbs/user/wv_pd.cpp @@ -0,0 +1,471 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "wv_base.h" +#include "wv_memory.h" +#include "wv_pd.h" +#include "wv_srq.h" +#include "wv_qp.h" +#include "wv_ioctl.h" + +CWVProtectionDomain::CWVProtectionDomain(CWVDevice *pDevice) +{ + pDevice->AddRef(); + m_pDevice = pDevice; + m_pVerbs = &pDevice->m_Verbs; + m_hFile = pDevice->m_hFile; + m_hVerbsPd = NULL; +} + +STDMETHODIMP CWVProtectionDomain:: +Allocate(void) +{ + WV_IO_ID *pId; + DWORD bytes; + ib_api_status_t stat; + HRESULT hr; + ci_umv_buf_t verbsData; + CWVBuffer buf; + + stat = m_pVerbs->pre_allocate_pd(m_pDevice->m_hVerbsDevice, &verbsData, + &m_hVerbsPd); + if (stat != IB_SUCCESS) { + return WvConvertIbStatus(stat); + } + + bytes = sizeof WV_IO_ID + max(verbsData.input_size, verbsData.output_size); + pId = (WV_IO_ID *) buf.Get(bytes); + if (pId == NULL) { + hr = WV_NO_MEMORY; + goto post; + } + + pId->Id = m_pDevice->m_Id; + pId->VerbInfo = verbsData.command; + RtlCopyMemory(pId + 1, (void *) (ULONG_PTR) verbsData.p_inout_buf, + verbsData.input_size); + + if (WvDeviceIoControl(m_hFile, WV_IOCTL_PD_ALLOCATE, + pId, sizeof WV_IO_ID + verbsData.input_size, + pId, sizeof WV_IO_ID + verbsData.output_size, + &bytes, NULL)) { + hr = WV_SUCCESS; + m_Id = pId->Id; + } else { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + + verbsData.status = pId->VerbInfo; + RtlCopyMemory((void *) (ULONG_PTR) verbsData.p_inout_buf, pId + 1, + verbsData.output_size); + buf.Put(); + +post: + m_pVerbs->post_allocate_pd(m_pDevice->m_hVerbsDevice, (ib_api_status_t) hr, + &m_hVerbsPd, &verbsData); + return hr; +} + +CWVProtectionDomain::~CWVProtectionDomain() +{ + DWORD bytes; + HRESULT hr; + + if (m_Id != 0) { + m_pVerbs->pre_deallocate_pd(m_hVerbsPd); + hr = WvDeviceIoControl(m_hFile, WV_IOCTL_PD_DEALLOCATE, &m_Id, sizeof m_Id, + NULL, 0, &bytes, NULL) ? + WV_SUCCESS : HRESULT_FROM_WIN32(GetLastError()); + m_pVerbs->post_deallocate_pd(m_hVerbsPd, (ib_api_status_t) hr); + } + m_pDevice->Release(); +} + +STDMETHODIMP CWVProtectionDomain:: +QueryInterface(REFIID riid, LPVOID FAR* ppvObj) +{ + if (riid != IID_IUnknown && riid != IID_IWVProtectionDomain) { + *ppvObj = NULL; + return E_NOINTERFACE; + } + + *ppvObj = this; + AddRef(); + return WV_SUCCESS; +} + +STDMETHODIMP_(ULONG) CWVProtectionDomain:: +AddRef(void) +{ + return CWVBase::AddRef(); +} + +STDMETHODIMP_(ULONG) CWVProtectionDomain:: +Release(void) +{ + return CWVBase::Release(); +} + +STDMETHODIMP CWVProtectionDomain:: +CancelOverlappedRequests(void) +{ + DWORD bytes; + + return WvDeviceIoControl(m_hFile, WV_IOCTL_PD_CANCEL, &m_Id, sizeof m_Id, + NULL, 0, &bytes, NULL) ? + WV_SUCCESS : HRESULT_FROM_WIN32(GetLastError()); +} + +STDMETHODIMP CWVProtectionDomain:: +GetOverlappedResult(OVERLAPPED *pOverlapped, + DWORD *pNumberOfBytesTransferred, BOOL bWait) +{ + ::GetOverlappedResult(m_hFile, pOverlapped, pNumberOfBytesTransferred, bWait); + return (HRESULT) pOverlapped->Internal; +} + +STDMETHODIMP CWVProtectionDomain:: +CreateSharedReceiveQueue(SIZE_T MaxWr, SIZE_T MaxSge, + SIZE_T SrqLimit, IWVSharedReceiveQueue** ppSrq) +{ + return CWVSharedReceiveQueue::CreateInstance(this, MaxWr, MaxSge, + SrqLimit, ppSrq); +} + +STDMETHODIMP CWVProtectionDomain:: +CreateConnectQueuePair(WV_QP_CREATE* pAttributes, IWVConnectQueuePair** ppQp) +{ + return CWVConnectQueuePair::CreateInstance(this, pAttributes, ppQp); +} + +STDMETHODIMP CWVProtectionDomain:: +CreateDatagramQueuePair(WV_QP_CREATE* pAttributes, IWVDatagramQueuePair** ppQp) +{ + return CWVDatagramQueuePair::CreateInstance(this, pAttributes, ppQp); +} + +STDMETHODIMP CWVProtectionDomain:: +RegisterMemory(const VOID* pBuffer, SIZE_T BufferLength, DWORD AccessFlags, + OVERLAPPED* pOverlapped, WV_MEMORY_KEYS *pKeys) +{ + WV_IO_MEMORY_REGISTER reg; + DWORD bytes; + HRESULT hr; + + reg.Id = m_Id; + reg.Address = (UINT64) (ULONG_PTR) pBuffer; + reg.BufferLength = BufferLength; + reg.AccessFlags = AccessFlags; + reg.Reserved = 0; + + if (WvDeviceIoControl(m_hFile, WV_IOCTL_MEMORY_REGISTER, ®, sizeof reg, + pKeys, sizeof WV_MEMORY_KEYS, &bytes, pOverlapped)) { + hr = WV_SUCCESS; + } else { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + + return hr; +} + +STDMETHODIMP CWVProtectionDomain:: +DeregisterMemory(UINT32 Lkey, OVERLAPPED* pOverlapped) +{ + WV_IO_ID id; + DWORD bytes; + HRESULT hr; + + id.Id = m_Id; + id.Data = Lkey; + hr = WvDeviceIoControl(m_hFile, WV_IOCTL_MEMORY_DEREGISTER, &id, sizeof id, + NULL, 0, &bytes, pOverlapped) ? + WV_SUCCESS : HRESULT_FROM_WIN32(GetLastError()); + return hr; +} + +STDMETHODIMP CWVProtectionDomain:: +AllocateMemoryWindow(IWVMemoryWindow** ppMw) +{ + return CWVMemoryWindow::CreateInstance(this, ppMw); +} + +STDMETHODIMP CWVProtectionDomain:: +CreateAddressHandle(WV_ADDRESS_VECTOR* pAddress, IWVAddressHandle** ppAh, ULONG_PTR *pAhKey) +{ + return CWVAddressHandle::CreateInstance(this, pAddress, ppAh, pAhKey); +} + + +//----------------------- +// Memory Window routines +//----------------------- + +CWVMemoryWindow::CWVMemoryWindow(CWVProtectionDomain *pPd) +{ + pPd->AddRef(); + m_pPd = pPd; + m_pVerbs = pPd->m_pVerbs; + m_hFile = pPd->m_hFile; + m_hVerbsMw = NULL; +} + +STDMETHODIMP CWVMemoryWindow:: +Allocate(void) +{ + WV_IO_ID *pId; + DWORD bytes; + ib_api_status_t stat; + HRESULT hr; + ci_umv_buf_t verbsData; + CWVBuffer buf; + + stat = m_pVerbs->pre_create_mw(m_pPd->m_hVerbsPd, &verbsData, &m_hVerbsMw); + if (stat != IB_SUCCESS) { + return WvConvertIbStatus(stat); + } + + bytes = sizeof WV_IO_ID + max(verbsData.input_size, verbsData.output_size); + pId = (WV_IO_ID *) buf.Get(bytes); + if (pId == NULL) { + hr = WV_NO_MEMORY; + goto post; + } + + pId->Id = m_pPd->m_Id; + pId->VerbInfo = verbsData.command; + RtlCopyMemory(pId + 1, (void *) (ULONG_PTR) verbsData.p_inout_buf, + verbsData.input_size); + + if (WvDeviceIoControl(m_hFile, WV_IOCTL_MW_ALLOCATE, + pId, sizeof WV_IO_ID + verbsData.input_size, + pId, sizeof WV_IO_ID + verbsData.output_size, + &bytes, NULL)) { + hr = WV_SUCCESS; + m_Id = pId->Id; + m_Rkey = pId->Data; + } else { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + + verbsData.status = pId->VerbInfo; + RtlCopyMemory((void *) (ULONG_PTR) verbsData.p_inout_buf, pId + 1, + verbsData.output_size); + buf.Put(); + +post: + m_pVerbs->post_create_mw(m_pPd->m_hVerbsPd, (ib_api_status_t) hr, + m_Rkey, &m_hVerbsMw, &verbsData); + return hr; +} + +CWVMemoryWindow::~CWVMemoryWindow() +{ + DWORD bytes; + HRESULT hr; + + if (m_Id != 0) { + m_pVerbs->pre_destroy_mw(m_hVerbsMw); + hr = WvDeviceIoControl(m_hFile, WV_IOCTL_MW_DEALLOCATE, + &m_Id, sizeof m_Id, NULL, 0, &bytes, NULL) ? + WV_SUCCESS : HRESULT_FROM_WIN32(GetLastError()); + m_pVerbs->post_destroy_mw(m_hVerbsMw, (ib_api_status_t) hr); + } + m_pPd->Release(); +} + +STDMETHODIMP CWVMemoryWindow:: +QueryInterface(REFIID riid, LPVOID FAR* ppvObj) +{ + if (riid != IID_IUnknown && riid != IID_IWVMemoryWindow) { + *ppvObj = NULL; + return E_NOINTERFACE; + } + + *ppvObj = this; + AddRef(); + return WV_SUCCESS; +} + +STDMETHODIMP_(ULONG) CWVMemoryWindow:: +AddRef(void) +{ + return CWVBase::AddRef(); +} + +STDMETHODIMP_(ULONG) CWVMemoryWindow:: +Release(void) +{ + return CWVBase::Release(); +} + + +//------------------------ +// Address Handle routines +//------------------------ + +CWVAddressHandle::CWVAddressHandle(CWVProtectionDomain *pPd) +{ + pPd->AddRef(); + m_pPd = pPd; + m_pVerbs = pPd->m_pVerbs; + m_hFile = pPd->m_hFile; + m_hVerbsAh = NULL; +} + +STDMETHODIMP CWVAddressHandle:: +Create(WV_ADDRESS_VECTOR* pAddress) +{ + WV_IO_AH_CREATE *pav; + DWORD bytes; + ib_api_status_t stat; + HRESULT hr; + ci_umv_buf_t verbsData; + ib_av_attr_t attr; + CWVBuffer buf; + + hr = ConvertAv(&attr, pAddress); + if (FAILED(hr)) { + return hr; + } + + stat = m_pVerbs->pre_create_av(m_pPd->m_hVerbsPd, &attr, &verbsData, &m_hVerbsAh); + if (stat != IB_SUCCESS) { + if (stat == IB_VERBS_PROCESSING_DONE) { + m_Id = (ULONG_PTR) m_hVerbsAh; + } + return WvConvertIbStatus(stat); + } + + bytes = sizeof WV_IO_AH_CREATE + max(verbsData.input_size, verbsData.output_size); + pav = (WV_IO_AH_CREATE *) buf.Get(bytes); + if (pav == NULL) { + hr = WV_NO_MEMORY; + goto post; + } + + pav->Id.Id = m_pPd->m_Id; + pav->Id.VerbInfo = verbsData.command; + RtlCopyMemory(&pav->AddressVector, pAddress, sizeof(pav->AddressVector)); + RtlCopyMemory(pav + 1, (void *) (ULONG_PTR) verbsData.p_inout_buf, + verbsData.input_size); + + if (WvDeviceIoControl(m_hFile, WV_IOCTL_AH_CREATE, + pav, sizeof WV_IO_AH_CREATE + verbsData.input_size, + pav, sizeof WV_IO_AH_CREATE + verbsData.output_size, + &bytes, NULL)) { + hr = WV_SUCCESS; + m_Id = pav->Id.Id; + } else { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + + verbsData.status = pav->Id.VerbInfo; + RtlCopyMemory((void *) (ULONG_PTR) verbsData.p_inout_buf, pav + 1, + verbsData.output_size); + buf.Put(); + +post: + m_pVerbs->post_create_av(m_pPd->m_hVerbsPd, (ib_api_status_t) hr, + &m_hVerbsAh, &verbsData); + return hr; +} + +CWVAddressHandle::~CWVAddressHandle() +{ + DWORD bytes; + HRESULT hr; + ib_api_status_t stat; + + if (m_Id != 0) { + stat = m_pVerbs->pre_destroy_av(m_hVerbsAh); + if (stat != IB_VERBS_PROCESSING_DONE) { + hr = WvDeviceIoControl(m_hFile, WV_IOCTL_AH_DESTROY, + &m_Id, sizeof m_Id, NULL, 0, &bytes, NULL) ? + WV_SUCCESS : HRESULT_FROM_WIN32(GetLastError()); + m_pVerbs->post_destroy_av(m_hVerbsAh, (ib_api_status_t) hr); + } + } + m_pPd->Release(); +} + +STDMETHODIMP CWVAddressHandle:: +QueryInterface(REFIID riid, LPVOID FAR* ppvObj) +{ + if (riid != IID_IUnknown && riid != IID_IWVAddressHandle) { + *ppvObj = NULL; + return E_NOINTERFACE; + } + + *ppvObj = this; + AddRef(); + return WV_SUCCESS; +} + +STDMETHODIMP_(ULONG) CWVAddressHandle:: +AddRef(void) +{ + return CWVBase::AddRef(); +} + +STDMETHODIMP_(ULONG) CWVAddressHandle:: +Release(void) +{ + return CWVBase::Release(); +} + +STDMETHODIMP CWVAddressHandle:: +ConvertAv(ib_av_attr_t *pVerbsAv, WV_ADDRESS_VECTOR *pAv) +{ + DWORD index; + HRESULT hr; + + pVerbsAv->grh_valid = pAv->Route.Valid; + if (pVerbsAv->grh_valid) { + hr = m_pPd->m_pDevice->FindGid(pAv->PortNumber, &pAv->Route.SGid, &index); + if (FAILED(hr)) { + return hr; + } + + pVerbsAv->grh.resv1 = (UINT16) index; + pVerbsAv->grh.ver_class_flow = + _byteswap_ulong(_byteswap_ulong(pAv->Route.FlowLabel) | + (pAv->Route.TrafficClass << 20)); + pVerbsAv->grh.hop_limit = pAv->Route.HopLimit; + RtlCopyMemory(&pVerbsAv->grh.src_gid, &pAv->Route.SGid, sizeof(pAv->Route.SGid)); + RtlCopyMemory(&pVerbsAv->grh.dest_gid, &pAv->Route.DGid, sizeof(pAv->Route.DGid)); + } + + pVerbsAv->port_num = pAv->PortNumber; + pVerbsAv->sl = pAv->ServiceLevel; + pVerbsAv->dlid = pAv->DLid; + pVerbsAv->static_rate = pAv->StaticRate; + pVerbsAv->path_bits = pAv->SourcePathBits; + + return WV_SUCCESS; +} \ No newline at end of file diff --git a/branches/WOF2-3/core/winverbs/user/wv_pd.h b/branches/WOF2-3/core/winverbs/user/wv_pd.h new file mode 100644 index 00000000..5f4c21a9 --- /dev/null +++ b/branches/WOF2-3/core/winverbs/user/wv_pd.h @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#ifndef _WV_PD_H_ +#define _WV_PD_H_ + +#include +#include "wv_device.h" +#include "wv_ioctl.h" +#include "wv_base.h" + +class CWVProtectionDomain : IWVProtectionDomain, public CWVBase +{ +public: + // IUnknown methods + STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + // IWVOverlapped methods + STDMETHODIMP CancelOverlappedRequests(); + STDMETHODIMP GetOverlappedResult(OVERLAPPED *pOverlapped, + DWORD *pNumberOfBytesTransferred, BOOL bWait); + + // IWVProtectionDomain methods + STDMETHODIMP CreateSharedReceiveQueue(SIZE_T MaxWr, SIZE_T MaxSge, SIZE_T SrqLimit, + IWVSharedReceiveQueue** ppSrq); + STDMETHODIMP CreateConnectQueuePair(WV_QP_CREATE* pAttributes, + IWVConnectQueuePair** ppQp); + STDMETHODIMP CreateDatagramQueuePair(WV_QP_CREATE* pAttributes, + IWVDatagramQueuePair** ppQp); + STDMETHODIMP RegisterMemory(const VOID* pBuffer, SIZE_T BufferLength, + DWORD AccessFlags, OVERLAPPED* pOverlapped, + WV_MEMORY_KEYS *pKeys); + STDMETHODIMP DeregisterMemory(UINT32 Lkey, OVERLAPPED* pOverlapped); + STDMETHODIMP AllocateMemoryWindow(IWVMemoryWindow** ppMw); + STDMETHODIMP CreateAddressHandle(WV_ADDRESS_VECTOR* pAddress, + IWVAddressHandle** ppAh, ULONG_PTR *pAhKey); + + CWVProtectionDomain(CWVDevice *pDevice); + ~CWVProtectionDomain(); + void Delete() {delete this;} + static STDMETHODIMP + CreateInstance(CWVDevice *pDevice, IWVProtectionDomain** ppPd) + { + HRESULT hr; + CWVProtectionDomain *pd; + + pd = new CWVProtectionDomain(pDevice); + if (pd == NULL) { + hr = WV_NO_MEMORY; + goto err1; + } + + hr = pd->Init(); + if (FAILED(hr)) { + goto err2; + } + + hr = pd->Allocate(); + if (FAILED(hr)) { + goto err2; + } + + *ppPd = pd; + return WV_SUCCESS; + + err2: + pd->Release(); + err1: + *ppPd = NULL; + return hr; + } + + CWVDevice *m_pDevice; + uvp_interface_t *m_pVerbs; + ib_pd_handle_t m_hVerbsPd; + +protected: + STDMETHODIMP Allocate(); +}; + + +class CWVMemoryWindow : IWVMemoryWindow, public CWVBase +{ +public: + // IUnknown methods + STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + CWVMemoryWindow(CWVProtectionDomain *pPd); + ~CWVMemoryWindow(); + void Delete() {delete this;} + static STDMETHODIMP + CreateInstance(CWVProtectionDomain *pPd, IWVMemoryWindow** ppMw) + { + HRESULT hr; + CWVMemoryWindow *mw; + + mw = new CWVMemoryWindow(pPd); + if (mw == NULL) { + hr = WV_NO_MEMORY; + goto err1; + } + + hr = mw->Init(); + if (FAILED(hr)) { + goto err2; + } + + hr = mw->Allocate(); + if (FAILED(hr)) { + goto err2; + } + + *ppMw = mw; + return WV_SUCCESS; + + err2: + mw->Release(); + err1: + *ppMw = NULL; + return hr; + } + + CWVProtectionDomain *m_pPd; + uvp_interface_t *m_pVerbs; + ib_mw_handle_t m_hVerbsMw; + NET32 m_Rkey; + +protected: + STDMETHODIMP Allocate(); +}; + + +class CWVAddressHandle : IWVAddressHandle, public CWVBase +{ +public: + // IUnknown methods + STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + CWVAddressHandle(CWVProtectionDomain *pPd); + ~CWVAddressHandle(); + void Delete() {delete this;} + static STDMETHODIMP + CreateInstance(CWVProtectionDomain *pPd, WV_ADDRESS_VECTOR* pAddress, + IWVAddressHandle** ppAh, ULONG_PTR* pAhKey) + { + HRESULT hr; + CWVAddressHandle *ah; + + ah = new CWVAddressHandle(pPd); + if (ah == NULL) { + hr = WV_NO_MEMORY; + goto err1; + } + + hr = ah->Init(); + if (FAILED(hr)) { + goto err2; + } + + hr = ah->Create(pAddress); + if (FAILED(hr)) { + goto err2; + } + + *ppAh = ah; + *pAhKey = (ULONG_PTR) ah->m_hVerbsAh; + return WV_SUCCESS; + + err2: + ah->Release(); + err1: + *ppAh = NULL; + return hr; + } + + CWVProtectionDomain *m_pPd; + uvp_interface_t *m_pVerbs; + ib_av_handle_t m_hVerbsAh; + +protected: + STDMETHODIMP Create(WV_ADDRESS_VECTOR* pAddress); + STDMETHODIMP ConvertAv(ib_av_attr_t *pVerbsAv, WV_ADDRESS_VECTOR *pAv); +}; + +#endif // _WV_PD_H_ \ No newline at end of file diff --git a/branches/WOF2-3/core/winverbs/user/wv_provider.cpp b/branches/WOF2-3/core/winverbs/user/wv_provider.cpp new file mode 100644 index 00000000..65b0c878 --- /dev/null +++ b/branches/WOF2-3/core/winverbs/user/wv_provider.cpp @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include + +#include "wv_memory.h" +#include "wv_provider.h" +#include "wv_device.h" +#include "wv_ep.h" +#include "wv_ioctl.h" + +CWVProvider::CWVProvider() +{ + InterlockedIncrement(&WvRef); + m_hFile = INVALID_HANDLE_VALUE; +} + +CWVProvider::~CWVProvider() +{ + CloseHandle(m_hFile); + if (InterlockedDecrement(&WvRef) == 0) { + WSACleanup(); + } +} + +STDMETHODIMP CWVProvider:: +QueryInterface(REFIID riid, LPVOID FAR* ppvObj) +{ + if (riid != IID_IUnknown && riid != IID_IWVProvider) { + *ppvObj = NULL; + return E_NOINTERFACE; + } + + *ppvObj = this; + AddRef(); + return WV_SUCCESS; +} + +STDMETHODIMP_(ULONG) CWVProvider:: +AddRef(void) +{ + return CWVBase::AddRef(); +} + +STDMETHODIMP_(ULONG) CWVProvider:: +Release(void) +{ + return CWVBase::Release(); +} + +STDMETHODIMP_(HANDLE) CWVProvider:: +GetFileHandle(void) +{ + return m_hFile; +} + +STDMETHODIMP CWVProvider:: +QueryDeviceList(NET64* pGuidList, SIZE_T* pBufferSize) +{ + CWVBuffer buf; + WV_IO_GUID_LIST *list; + DWORD bytes; + HRESULT hr; + + bytes = sizeof(WV_IO_GUID_LIST) + (DWORD) *pBufferSize; + list = (WV_IO_GUID_LIST *) buf.Get(bytes); + if (list == NULL) { + return WV_NO_MEMORY; + } + + if (!WvDeviceIoControl(m_hFile, WV_IOCTL_GUID_QUERY, NULL, 0, + list, bytes, &bytes, NULL)) { + hr = HRESULT_FROM_WIN32(GetLastError()); + goto out; + } + + bytes = (DWORD) list->Count * sizeof NET64; + if (*pBufferSize >= bytes) { + RtlCopyMemory(pGuidList, list->Guid, (size_t) bytes); + } else if (*pBufferSize > 0) { + RtlCopyMemory(pGuidList, list->Guid, *pBufferSize); + } + + *pBufferSize = (size_t) bytes; + hr = WV_SUCCESS; + +out: + buf.Put(); + return hr; +} + +STDMETHODIMP CWVProvider:: +QueryDevice(NET64 Guid, WV_DEVICE_ATTRIBUTES* pAttributes) +{ + IWVDevice *dev; + HRESULT hr; + + hr = OpenDevice(Guid, &dev); + if (FAILED(hr)) { + goto out; + } + + hr = dev->Query(pAttributes); + dev->Release(); +out: + return hr; +} + +STDMETHODIMP CWVProvider:: +TranslateAddress(const SOCKADDR* pAddress, WV_DEVICE_ADDRESS* pDeviceAddress) +{ + HANDLE hIbat; + IOCTL_IBAT_IP_TO_PORT_IN addr; + IBAT_PORT_RECORD port; + DWORD bytes; + HRESULT hr; + + hIbat = CreateFileW(IBAT_WIN32_NAME, GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (hIbat == INVALID_HANDLE_VALUE) { + return HRESULT_FROM_WIN32(GetLastError()); + } + + addr.Version = IBAT_IOCTL_VERSION; + if (pAddress->sa_family == AF_INET) { + addr.Address.IpVersion = 4; + RtlCopyMemory(addr.Address.Address + 12, + &((SOCKADDR_IN *)pAddress)->sin_addr, 4); + } else { + addr.Address.IpVersion = 6; + RtlCopyMemory(addr.Address.Address, + &((SOCKADDR_IN6 *)pAddress)->sin6_addr, 16); + } + + if (DeviceIoControl(hIbat, IOCTL_IBAT_IP_TO_PORT, + &addr, sizeof addr, &port, sizeof port, &bytes, NULL)) { + hr = WV_SUCCESS; + pDeviceAddress->DeviceGuid = port.CaGuid; + pDeviceAddress->Pkey = port.PKey; + pDeviceAddress->PortNumber = port.PortNum; + } else { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + + CloseHandle(hIbat); + return hr; +} + +STDMETHODIMP CWVProvider:: +OpenDevice(NET64 Guid, IWVDevice** ppDevice) +{ + return CWVDevice::CreateInstance(this, Guid, ppDevice); +} + +STDMETHODIMP CWVProvider:: +CreateConnectEndpoint(IWVConnectEndpoint** ppConnectEndpoint) +{ + return CWVConnectEndpoint::CreateInstance(this, ppConnectEndpoint); +} + +STDMETHODIMP CWVProvider:: +CreateDatagramEndpoint(IWVDatagramEndpoint** ppDatagramEndpoint) +{ + return CWVDatagramEndpoint::CreateInstance(this, ppDatagramEndpoint); +} diff --git a/branches/WOF2-3/core/winverbs/user/wv_provider.h b/branches/WOF2-3/core/winverbs/user/wv_provider.h new file mode 100644 index 00000000..5daa4c77 --- /dev/null +++ b/branches/WOF2-3/core/winverbs/user/wv_provider.h @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#ifndef _WV_PROVIDER_H_ +#define _WV_PROVIDER_H_ + +#include +#include "wv_base.h" + +extern volatile LONG WvRef; + +class CWVProvider : IWVProvider, public CWVBase +{ +public: + // IUnknown methods + STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + // IWVProvider methods + STDMETHODIMP_(HANDLE) GetFileHandle(); + STDMETHODIMP QueryDeviceList(NET64* pGuidList, SIZE_T* pBufferSize); + STDMETHODIMP QueryDevice(NET64 Guid, WV_DEVICE_ATTRIBUTES* pAttributes); + STDMETHODIMP TranslateAddress(const SOCKADDR* pAddress, + WV_DEVICE_ADDRESS* pDeviceAddress); + + STDMETHODIMP OpenDevice(NET64 Guid, IWVDevice** ppDevice); + + STDMETHODIMP CreateConnectEndpoint(IWVConnectEndpoint** ppConnectEndpoint); + STDMETHODIMP CreateDatagramEndpoint(IWVDatagramEndpoint** ppDatagramEndpoint); + + CWVProvider(); + ~CWVProvider(); + void Delete() {delete this;} + static STDMETHODIMP CreateInstance(IWVProvider** ppProvider) + { + WSADATA wsadata; + HRESULT hr; + CWVProvider *wv; + + if (WvRef == 0) { + hr = WSAStartup(MAKEWORD(2, 2), &wsadata); + if (FAILED(hr)) { + return hr; + } + } + + wv = new CWVProvider; + if (wv == NULL) { + hr = WV_NO_MEMORY; + goto err1; + } + + hr = wv->Init(); + if (FAILED(hr)) { + goto err2; + } + + wv->m_hFile = CreateFileW(L"\\\\.\\WinVerbs", GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); + if (wv->m_hFile == INVALID_HANDLE_VALUE) { + hr = HRESULT_FROM_WIN32(GetLastError()); + goto err2; + } + *ppProvider = wv; + return WV_SUCCESS; + + err2: + wv->Release(); + err1: + *ppProvider = NULL; + return hr; + } +}; + +#endif // _WV_PROVIDER_H_ \ No newline at end of file diff --git a/branches/WOF2-3/core/winverbs/user/wv_qp.cpp b/branches/WOF2-3/core/winverbs/user/wv_qp.cpp new file mode 100644 index 00000000..dd1038c8 --- /dev/null +++ b/branches/WOF2-3/core/winverbs/user/wv_qp.cpp @@ -0,0 +1,796 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2009 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "wv_base.h" +#include "wv_memory.h" +#include "wv_cq.h" +#include "wv_qp.h" +#include "wv_srq.h" +#include "wv_ioctl.h" + +static void WvVerbsConvertQpCreate(uvp_qp_create_t *pVerbsAttr, WV_QP_CREATE *pAttr) +{ + pVerbsAttr->qp_create.qp_type = (ib_qp_type_t) pAttr->QpType; + pVerbsAttr->qp_create.sq_depth = (UINT32) pAttr->SendDepth; + pVerbsAttr->qp_create.rq_depth = (UINT32) pAttr->ReceiveDepth; + pVerbsAttr->qp_create.sq_sge = (UINT32) pAttr->SendSge; + pVerbsAttr->qp_create.rq_sge = (UINT32) pAttr->ReceiveSge; + pVerbsAttr->qp_create.sq_max_inline = (UINT32) pAttr->MaxInlineSend; + + pVerbsAttr->qp_create.h_sq_cq = ((CWVCompletionQueue *) pAttr->pSendCq)->m_hVerbsCq; + pVerbsAttr->qp_create.h_rq_cq = ((CWVCompletionQueue *) pAttr->pReceiveCq)->m_hVerbsCq; + if (pAttr->pSharedReceiveQueue != NULL) { + pVerbsAttr->qp_create.h_srq = ((CWVSharedReceiveQueue *) + pAttr->pSharedReceiveQueue)->m_hVerbsSrq; + } else { + pVerbsAttr->qp_create.h_srq = NULL; + } + + pVerbsAttr->qp_create.sq_signaled = ((pAttr->QpFlags & WV_QP_SIGNAL_SENDS) != 0); + + pVerbsAttr->context = pAttr->Context; + pVerbsAttr->max_inline_send = (UINT32) pAttr->MaxInlineSend; + pVerbsAttr->initiator_depth = (UINT32) pAttr->InitiatorDepth; + pVerbsAttr->responder_resources = (UINT32) pAttr->ResponderResources; +} + +static void WvIoConvertQpCreate(WV_IO_QP_CREATE *pIoAttr, WV_QP_CREATE *pAttr) +{ + pIoAttr->SendCqId = ((CWVCompletionQueue *) pAttr->pSendCq)->m_Id; + pIoAttr->ReceiveCqId = ((CWVCompletionQueue *) pAttr->pReceiveCq)->m_Id; + if (pAttr->pSharedReceiveQueue != NULL) { + pIoAttr->SrqId = ((CWVSharedReceiveQueue *) pAttr->pSharedReceiveQueue)->m_Id; + } else { + pIoAttr->SrqId = 0; + } + + pIoAttr->SendDepth = (UINT32) pAttr->SendDepth; + pIoAttr->SendSge = (UINT32) pAttr->SendSge; + pIoAttr->ReceiveDepth = (UINT32) pAttr->ReceiveDepth; + pIoAttr->ReceiveSge = (UINT32) pAttr->ReceiveSge; + pIoAttr->MaxInlineSend = (UINT32) pAttr->MaxInlineSend; + pIoAttr->InitiatorDepth = (UINT32) pAttr->InitiatorDepth; + pIoAttr->ResponderResources = (UINT32) pAttr->ResponderResources; + + pIoAttr->QpType = (UINT8) pAttr->QpType; + pIoAttr->QpFlags = (UINT8) pAttr->QpFlags; + pIoAttr->Reserved = 0; +} + +static void WvQpAttrConvertIo(WV_QP_ATTRIBUTES *pAttr, + WV_IO_QP_ATTRIBUTES *pIoAttr, + CWVProtectionDomain *pPd, + CWVCompletionQueue *pSendCq, + CWVCompletionQueue *pReceiveCq, + CWVSharedReceiveQueue *pSharedReceiveQueue) +{ + if (pPd != NULL) { + pPd->QueryInterface(IID_IWVProtectionDomain, (LPVOID *) &pAttr->pPd); + pAttr->pPd->Release(); + } else { + pAttr->pPd = NULL; + } + if (pSendCq != NULL) { + pSendCq->QueryInterface(IID_IWVCompletionQueue, + (LPVOID *) &pAttr->pSendCq); + pAttr->pSendCq->Release(); + } else { + pAttr->pSendCq = NULL; + } + if (pReceiveCq != NULL) { + pReceiveCq->QueryInterface(IID_IWVCompletionQueue, + (LPVOID *) &pAttr->pReceiveCq); + pAttr->pReceiveCq->Release(); + } else { + pAttr->pReceiveCq = NULL; + } + if (pSharedReceiveQueue != NULL) { + pSharedReceiveQueue->QueryInterface(IID_IWVSharedReceiveQueue, + (LPVOID *) &pAttr->pSharedReceiveQueue); + pAttr->pSharedReceiveQueue->Release(); + } else { + pAttr->pSharedReceiveQueue = NULL; + } + + pAttr->SendDepth = pIoAttr->SendDepth; + pAttr->SendSge = pIoAttr->SendSge; + pAttr->ReceiveDepth = pIoAttr->ReceiveDepth; + pAttr->ReceiveSge = pIoAttr->ReceiveSge; + pAttr->MaxInlineSend = pIoAttr->MaxInlineSend; + pAttr->InitiatorDepth = pIoAttr->InitiatorDepth; + pAttr->ResponderResources = pIoAttr->ResponderResources; + + pAttr->QpType = (WV_QP_TYPE) pIoAttr->QpType; + pAttr->CurrentQpState = (WV_QP_STATE) pIoAttr->CurrentQpState; + pAttr->QpState = (WV_QP_STATE) pIoAttr->QpState; + pAttr->ApmState = (WV_APM_STATE) pIoAttr->ApmState; + pAttr->Qpn = pIoAttr->Qpn; + pAttr->DestinationQpn = pIoAttr->DestinationQpn; + pAttr->Qkey = pIoAttr->Qkey; + pAttr->SendPsn = pIoAttr->SendPsn; + pAttr->ReceivePsn = pIoAttr->ReceivePsn; + + pAttr->QpFlags = pIoAttr->QpFlags; + pAttr->AccessFlags = pIoAttr->AccessFlags; + + RtlCopyMemory(&pAttr->AddressVector, &pIoAttr->AddressVector, + sizeof(pAttr->AddressVector)); + RtlCopyMemory(&pAttr->AlternateAddressVector, &pIoAttr->AlternateAddressVector, + sizeof(pAttr->AlternateAddressVector)); + pAttr->PathMtu = pIoAttr->PathMtu; + pAttr->AlternatePathMtu = pIoAttr->AlternatePathMtu; + pAttr->PkeyIndex = pIoAttr->PkeyIndex; + pAttr->AlternatePkeyIndex = pIoAttr->AlternatePkeyIndex; + pAttr->LocalAckTimeout = pIoAttr->LocalAckTimeout; + pAttr->AlternateLocalAckTimeout = pIoAttr->AlternateLocalAckTimeout; + + pAttr->RnrNakTimeout = pIoAttr->RnrNakTimeout; + pAttr->SequenceErrorRetryCount = pIoAttr->SequenceErrorRetryCount; + pAttr->RnrRetryCount = pIoAttr->RnrRetryCount; +} + +static void WvIoConvertQpAttr(WV_IO_QP_ATTRIBUTES *pIoAttr, + WV_QP_ATTRIBUTES *pAttr, DWORD Options) +{ + pIoAttr->SendDepth = (UINT32) pAttr->SendDepth; + pIoAttr->SendSge = (UINT32) pAttr->SendSge; + pIoAttr->ReceiveDepth = (UINT32) pAttr->ReceiveDepth; + pIoAttr->ReceiveSge = (UINT32) pAttr->ReceiveSge; + pIoAttr->MaxInlineSend = (UINT32) pAttr->MaxInlineSend; + pIoAttr->InitiatorDepth = (UINT32) pAttr->InitiatorDepth; + pIoAttr->ResponderResources = (UINT32) pAttr->ResponderResources; + + pIoAttr->Options = Options; + pIoAttr->QpType = (UINT8) pAttr->QpType; + pIoAttr->CurrentQpState = (UINT8) pAttr->CurrentQpState; + pIoAttr->QpState = (UINT8) pAttr->QpState; + pIoAttr->ApmState = (UINT8) pAttr->ApmState; + pIoAttr->Qpn = pAttr->Qpn; + pIoAttr->DestinationQpn = pAttr->DestinationQpn; + pIoAttr->Qkey = pAttr->Qkey; + pIoAttr->SendPsn = pAttr->SendPsn; + pIoAttr->ReceivePsn = pAttr->ReceivePsn; + + RtlCopyMemory(&pIoAttr->AddressVector, &pAttr->AddressVector, + sizeof(pIoAttr->AddressVector)); + RtlCopyMemory(&pIoAttr->AlternateAddressVector, &pAttr->AlternateAddressVector, + sizeof(pIoAttr->AlternateAddressVector)); + pIoAttr->PathMtu = pAttr->PathMtu; + pIoAttr->AlternatePathMtu = pAttr->AlternatePathMtu; + pIoAttr->PkeyIndex = pAttr->PkeyIndex; + pIoAttr->AlternatePkeyIndex = pAttr->AlternatePkeyIndex; + pIoAttr->LocalAckTimeout = pAttr->LocalAckTimeout; + pIoAttr->AlternateLocalAckTimeout = pAttr->AlternateLocalAckTimeout; + + pIoAttr->RnrNakTimeout = pAttr->RnrNakTimeout; + pIoAttr->SequenceErrorRetryCount = pAttr->SequenceErrorRetryCount; + pIoAttr->RnrRetryCount = pAttr->RnrRetryCount; + + pIoAttr->AccessFlags = (UINT8) pAttr->AccessFlags; + pIoAttr->QpFlags = (UINT8) pAttr->QpFlags; + RtlZeroMemory(pIoAttr->Reserved, sizeof pIoAttr->Reserved); +} + +CWVQueuePair::CWVQueuePair(CWVProtectionDomain *pPd) +{ + pPd->AddRef(); + m_pPd = pPd; + m_pSendCq = NULL; + m_pReceiveCq = NULL; + m_pSrq = NULL; + m_pVerbs = pPd->m_pVerbs; + m_hFile = pPd->m_hFile; + m_hVerbsQp = NULL; +} + +void CWVQueuePair:: +AddReferences(WV_QP_CREATE* pAttributes) +{ + if (pAttributes->pSendCq != NULL) { + pAttributes->pSendCq->AddRef(); + m_pSendCq = (CWVCompletionQueue *) pAttributes->pSendCq; + } + if (pAttributes->pReceiveCq != NULL) { + pAttributes->pReceiveCq->AddRef(); + m_pReceiveCq = (CWVCompletionQueue *) pAttributes->pReceiveCq; + } + if (pAttributes->pSharedReceiveQueue != NULL) { + pAttributes->pSharedReceiveQueue->AddRef(); + m_pSrq = (CWVSharedReceiveQueue *) pAttributes->pSharedReceiveQueue; + } +} + +void CWVQueuePair:: +ReleaseReferences(void) +{ + if (m_pSendCq != NULL) { + m_pSendCq->Release(); + } + if (m_pReceiveCq != NULL) { + m_pReceiveCq->Release(); + } + if (m_pSrq != NULL) { + m_pSrq->Release(); + } +} + +STDMETHODIMP CWVQueuePair:: +Create(WV_QP_CREATE* pAttributes) +{ + WV_IO_QP_CREATE *pattr; + DWORD bytes; + ib_api_status_t stat; + HRESULT hr; + uvp_qp_create_t attr; + ci_umv_buf_t verbsData; + CWVBuffer buf; + + m_Type = pAttributes->QpType; + AddReferences(pAttributes); + WvVerbsConvertQpCreate(&attr, pAttributes); + stat = m_pVerbs->wv_pre_create_qp(m_pPd->m_hVerbsPd, &attr, &verbsData, + &m_hVerbsQp); + if (stat != IB_SUCCESS) { + return WvConvertIbStatus(stat); + } + + bytes = sizeof WV_IO_QP_CREATE + max(verbsData.input_size, verbsData.output_size); + pattr = (WV_IO_QP_CREATE *) buf.Get(bytes); + if (pattr == NULL) { + hr = WV_NO_MEMORY; + goto post; + } + + pattr->Id.Id = m_pPd->m_Id; + pattr->Id.VerbInfo = verbsData.command; + WvIoConvertQpCreate(pattr, pAttributes); + RtlCopyMemory(pattr + 1, (void *) (ULONG_PTR) verbsData.p_inout_buf, + verbsData.input_size); + + if (WvDeviceIoControl(m_hFile, WV_IOCTL_QP_CREATE, + pattr, sizeof WV_IO_QP_CREATE + verbsData.input_size, + pattr, sizeof WV_IO_QP_CREATE + verbsData.output_size, + &bytes, NULL)) { + hr = WV_SUCCESS; + m_Id = pattr->Id.Id; + } else { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + + verbsData.status = pattr->Id.VerbInfo; + RtlCopyMemory((void *) (ULONG_PTR) verbsData.p_inout_buf, pattr + 1, + verbsData.output_size); + buf.Put(); + +post: + m_pVerbs->post_create_qp(m_pPd->m_hVerbsPd, (ib_api_status_t) hr, + &m_hVerbsQp, &verbsData); + return hr; +} + +CWVQueuePair::~CWVQueuePair() +{ + DWORD bytes; + HRESULT hr; + + if (m_Id != 0) { + m_pVerbs->pre_destroy_qp(m_hVerbsQp); + hr = WvDeviceIoControl(m_hFile, WV_IOCTL_QP_DESTROY, &m_Id, sizeof m_Id, + NULL, 0, &bytes, NULL) ? + WV_SUCCESS : HRESULT_FROM_WIN32(GetLastError()); + m_pVerbs->post_destroy_qp(m_hVerbsQp, (ib_api_status_t) hr); + } + ReleaseReferences(); + m_pPd->Release(); +} + +STDMETHODIMP CWVQueuePair:: +QueryInterface(REFIID riid, LPVOID FAR* ppvObj) +{ + if (riid != IID_IUnknown && riid != IID_IWVQueuePair) { + *ppvObj = NULL; + return E_NOINTERFACE; + } + + *ppvObj = this; + AddRef(); + return WV_SUCCESS; +} + +STDMETHODIMP_(ULONG) CWVQueuePair:: +AddRef(void) +{ + return CWVBase::AddRef(); +} + +STDMETHODIMP_(ULONG) CWVQueuePair:: +Release(void) +{ + return CWVBase::Release(); +} + +STDMETHODIMP CWVQueuePair:: +CancelOverlappedRequests(void) +{ + DWORD bytes; + + return WvDeviceIoControl(m_hFile, WV_IOCTL_QP_CANCEL, &m_Id, sizeof m_Id, + NULL, 0, &bytes, NULL) ? + WV_SUCCESS : HRESULT_FROM_WIN32(GetLastError()); +} + +STDMETHODIMP CWVQueuePair:: +GetOverlappedResult(OVERLAPPED *pOverlapped, + DWORD *pNumberOfBytesTransferred, BOOL bWait) +{ + ::GetOverlappedResult(m_hFile, pOverlapped, pNumberOfBytesTransferred, bWait); + return (HRESULT) pOverlapped->Internal; +} + +STDMETHODIMP CWVQueuePair:: +Query(WV_QP_ATTRIBUTES* pAttributes) +{ + WV_IO_QP_ATTRIBUTES attr; + DWORD bytes; + HRESULT hr; + + if (WvDeviceIoControl(m_hFile, WV_IOCTL_QP_QUERY, &m_Id, sizeof m_Id, + &attr, sizeof WV_IO_QP_ATTRIBUTES, &bytes, NULL)) { + hr = WV_SUCCESS; + WvQpAttrConvertIo(pAttributes, &attr, m_pPd, m_pSendCq, + m_pReceiveCq, m_pSrq); + } else { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + + return hr; +} + +STDMETHODIMP CWVQueuePair:: +Modify(WV_QP_ATTRIBUTES* pAttributes, DWORD Options, OVERLAPPED* pOverlapped) +{ + WV_IO_QP_ATTRIBUTES attr; + DWORD bytes; + HRESULT hr; + void *pout; + DWORD size; + + m_pVerbs->nd_modify_qp(m_hVerbsQp, &pout, &size); + + attr.Id.Id = m_Id; + WvIoConvertQpAttr(&attr, pAttributes, Options); + if (WvDeviceIoControl(m_hFile, WV_IOCTL_QP_MODIFY, &attr, sizeof attr, + pout, size, &bytes, pOverlapped)) { + hr = WV_SUCCESS; + } else { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + + return hr; +} + +STDMETHODIMP CWVQueuePair:: +PostReceive(UINT64 WrId, WV_SGE* pSgl, SIZE_T nSge) +{ + ib_recv_wr_t wr, *pwr; + ib_api_status_t stat; + HRESULT hr; + + wr.p_next = NULL; + wr.wr_id = WrId; + wr.num_ds = (UINT32) nSge; + wr.ds_array = WvConvertSgl(pSgl, nSge); + + stat = m_pVerbs->post_recv(m_hVerbsQp, &wr, &pwr); + if (stat == IB_SUCCESS) { + hr = WV_SUCCESS; + } else { + hr = WvConvertIbStatus(stat); + } + + return hr; +} + +STDMETHODIMP CWVQueuePair:: +PostSend(WV_SEND_REQUEST *pSend, WV_SEND_REQUEST **ppFailed) +{ + WV_SEND_REQUEST *wr; + ib_api_status_t stat; + HRESULT hr; + + for (wr = pSend; wr != NULL; wr = wr->pNext) { + if (wr->Opcode != WvSend) { + wr->Wr.Rdma.RemoteAddress = _byteswap_uint64(wr->Wr.Rdma.RemoteAddress); + } + WvConvertSgl(wr->pSgl, wr->nSge); + } + + stat = m_pVerbs->post_send(m_hVerbsQp, (ib_send_wr_t *) pSend, + (ib_send_wr_t **) (ppFailed ? ppFailed : &wr)); + if (stat == IB_SUCCESS) { + hr = WV_SUCCESS; + } else { + hr = WvConvertIbStatus(stat); + } + + for (wr = pSend; wr != NULL; wr = wr->pNext) { + if (wr->Opcode != WvSend) { + wr->Wr.Rdma.RemoteAddress = _byteswap_uint64(wr->Wr.Rdma.RemoteAddress); + } + } + + return hr; +} + + +//----------------------------- +// CWVConnectQueuePair routines +//----------------------------- + +STDMETHODIMP CWVConnectQueuePair:: +QueryInterface(REFIID riid, LPVOID FAR* ppvObj) +{ + if (riid != IID_IWVConnectQueuePair) { + return CWVQueuePair::QueryInterface(riid, ppvObj); + } + + *ppvObj = this; + AddRef(); + return WV_SUCCESS; +} + +STDMETHODIMP_(ULONG) CWVConnectQueuePair:: +AddRef(void) +{ + return CWVBase::AddRef(); +} + +STDMETHODIMP_(ULONG) CWVConnectQueuePair:: +Release(void) +{ + return CWVBase::Release(); +} + +STDMETHODIMP CWVConnectQueuePair:: +CancelOverlappedRequests(void) +{ + return CWVQueuePair::CancelOverlappedRequests(); +} + +STDMETHODIMP CWVConnectQueuePair:: +GetOverlappedResult(OVERLAPPED *pOverlapped, + DWORD *pNumberOfBytesTransferred, BOOL bWait) +{ + ::GetOverlappedResult(m_hFile, pOverlapped, pNumberOfBytesTransferred, bWait); + return (HRESULT) pOverlapped->Internal; +} + +STDMETHODIMP CWVConnectQueuePair:: +Query(WV_QP_ATTRIBUTES* pAttributes) +{ + return CWVQueuePair::Query(pAttributes); +} + +STDMETHODIMP CWVConnectQueuePair:: +Modify(WV_QP_ATTRIBUTES* pAttributes, DWORD Options, OVERLAPPED* pOverlapped) +{ + return CWVQueuePair::Modify(pAttributes, Options, pOverlapped); +} + +STDMETHODIMP CWVConnectQueuePair:: +PostReceive(UINT64 WrId, WV_SGE* pSgl, SIZE_T nSge) +{ + return CWVQueuePair::PostReceive(WrId, pSgl, nSge); +} + +STDMETHODIMP CWVConnectQueuePair:: +PostSend(WV_SEND_REQUEST *pSend, WV_SEND_REQUEST **ppFailed) +{ + return CWVQueuePair::PostSend(pSend, ppFailed); +} + +STDMETHODIMP CWVConnectQueuePair:: +Send(UINT64 WrId, WV_SGE* pSgl, SIZE_T nSge, + DWORD Flags, NET32 ImmediateData) +{ + WV_SEND_REQUEST wr; + HRESULT hr; + + wr.pNext = NULL; + wr.WrId = WrId; + wr.Opcode = WvSend; + wr.Flags = Flags; + wr.nSge = (UINT32) nSge; + wr.pSgl = pSgl; + wr.ImmediateData = ImmediateData; + + hr = PostSend(&wr, NULL); + return hr; +} + +STDMETHODIMP CWVConnectQueuePair:: +Read(UINT64 WrId, WV_SGE* pSgl, SIZE_T nSge, + DWORD Flags, NET64 Address, NET32 Rkey) +{ + WV_SEND_REQUEST wr; + HRESULT hr; + + wr.pNext = NULL; + wr.WrId = WrId; + wr.Opcode = WvRdmaRead; + wr.Flags = Flags; + wr.nSge = (UINT32) nSge; + wr.pSgl = pSgl; + + wr.Wr.Rdma.RemoteAddress = Address; + wr.Wr.Rdma.Rkey = Rkey; + + hr = PostSend(&wr, NULL); + return hr; +} + +STDMETHODIMP CWVConnectQueuePair:: +Write(UINT64 WrId, WV_SGE* pSgl, SIZE_T nSge, + DWORD Flags, NET32 ImmediateData, NET64 Address, NET32 Rkey) +{ + WV_SEND_REQUEST wr; + HRESULT hr; + + wr.pNext = NULL; + wr.WrId = WrId; + wr.Opcode = WvRdmaWrite; + wr.Flags = Flags; + wr.nSge = (UINT32) nSge; + wr.pSgl = pSgl; + wr.ImmediateData = ImmediateData; + + wr.Wr.Rdma.RemoteAddress = Address; + wr.Wr.Rdma.Rkey = Rkey; + + hr = PostSend(&wr, NULL); + return hr; +} + +STDMETHODIMP CWVConnectQueuePair:: +CompareExchange(UINT64 WrId, WV_SGE* pSge, DWORD Flags, + NET64 Compare, NET64 Exchange, NET64 Address, NET32 Rkey) +{ + WV_SEND_REQUEST wr; + HRESULT hr; + + wr.pNext = NULL; + wr.WrId = WrId; + wr.Opcode = WvCompareExchange; + wr.Flags = Flags; + wr.nSge = 1; + wr.pSgl = pSge; + + wr.Wr.CompareExchange.RemoteAddress = Address; + wr.Wr.CompareExchange.Rkey = Rkey; + wr.Wr.CompareExchange.Compare = Compare; + wr.Wr.CompareExchange.Exchange = Exchange; + + hr = PostSend(&wr, NULL); + return hr; +} + +STDMETHODIMP CWVConnectQueuePair:: +FetchAdd(UINT64 WrId, WV_SGE* pSge, DWORD Flags, + NET64 Value, NET64 Address, NET32 Rkey) +{ + WV_SEND_REQUEST wr; + HRESULT hr; + + wr.pNext = NULL; + wr.WrId = WrId; + wr.Opcode = WvFetchAdd; + wr.Flags = Flags; + wr.nSge = 1; + wr.pSgl = pSge; + + wr.Wr.FetchAdd.RemoteAddress = Address; + wr.Wr.FetchAdd.Rkey = Rkey; + wr.Wr.FetchAdd.Add = Value; + wr.Wr.FetchAdd.Reserved = 0; + + hr = PostSend(&wr, NULL); + return hr; +} + +STDMETHODIMP CWVConnectQueuePair:: +BindMemoryWindow(IWVMemoryWindow* pMw, UINT64 WrId, + UINT32 Lkey, DWORD AccessFlags, DWORD SendFlags, + const VOID* pBuffer, SIZE_T BufferLength, NET32 *pRkey) +{ + UNREFERENCED_PARAMETER(pMw); + UNREFERENCED_PARAMETER(WrId); + UNREFERENCED_PARAMETER(Lkey); + UNREFERENCED_PARAMETER(AccessFlags); + UNREFERENCED_PARAMETER(SendFlags); + UNREFERENCED_PARAMETER(pBuffer); + UNREFERENCED_PARAMETER(BufferLength); + UNREFERENCED_PARAMETER(pRkey); + + return E_NOTIMPL; +} + + +//--------------------------- +// DatagramQueuePair routines +//--------------------------- + +STDMETHODIMP CWVDatagramQueuePair:: +QueryInterface(REFIID riid, LPVOID FAR* ppvObj) +{ + if (riid != IID_IWVDatagramQueuePair) { + return CWVQueuePair::QueryInterface(riid, ppvObj); + } + + *ppvObj = this; + AddRef(); + return WV_SUCCESS; +} + +STDMETHODIMP_(ULONG) CWVDatagramQueuePair:: +AddRef(void) +{ + return CWVBase::AddRef(); +} + +STDMETHODIMP_(ULONG) CWVDatagramQueuePair:: +Release(void) +{ + return CWVBase::Release(); +} + +STDMETHODIMP CWVDatagramQueuePair:: +CancelOverlappedRequests(void) +{ + return CWVQueuePair::CancelOverlappedRequests(); +} + +STDMETHODIMP CWVDatagramQueuePair:: +GetOverlappedResult(OVERLAPPED *pOverlapped, + DWORD *pNumberOfBytesTransferred, BOOL bWait) +{ + ::GetOverlappedResult(m_hFile, pOverlapped, pNumberOfBytesTransferred, bWait); + return (HRESULT) pOverlapped->Internal; +} + +STDMETHODIMP CWVDatagramQueuePair:: +Query(WV_QP_ATTRIBUTES* pAttributes) +{ + return CWVQueuePair::Query(pAttributes); +} + +STDMETHODIMP CWVDatagramQueuePair:: +Modify(WV_QP_ATTRIBUTES* pAttributes, DWORD Options, OVERLAPPED* pOverlapped) +{ + return CWVQueuePair::Modify(pAttributes, Options, pOverlapped); +} + +STDMETHODIMP CWVDatagramQueuePair:: +PostReceive(UINT64 WrId, WV_SGE* pSgl, SIZE_T nSge) +{ + return CWVQueuePair::PostReceive(WrId, pSgl, nSge); +} + +STDMETHODIMP CWVDatagramQueuePair:: +PostSend(WV_SEND_REQUEST *pSend, WV_SEND_REQUEST **ppFailed) +{ + return CWVQueuePair::PostSend(pSend, ppFailed); +} + +STDMETHODIMP CWVDatagramQueuePair:: +Send(UINT64 WrId, ULONG_PTR AhKey, + WV_SGE* pSge, DWORD Flags, NET32 DestinationQpn, + NET32 DestinationQkey) +{ + WV_SEND_REQUEST wr; + HRESULT hr; + + wr.pNext = NULL; + wr.WrId = WrId; + wr.Opcode = WvSend; + wr.Flags = Flags; + wr.nSge = 1; + wr.pSgl = pSge; + + wr.Wr.Datagram.DestinationQkey = DestinationQkey; + wr.Wr.Datagram.DestinationQpn = DestinationQpn; + wr.Wr.Datagram.AhKey = AhKey; + + hr = PostSend(&wr, NULL); + return hr; +} + +STDMETHODIMP CWVDatagramQueuePair:: +SendMessage(WV_SEND_DATAGRAM* pSend) +{ + WV_SEND_REQUEST wr; + HRESULT hr; + + wr.pNext = NULL; + wr.WrId = pSend->WrId; + wr.Opcode = WvSend; + wr.Flags = pSend->Flags; + wr.nSge = (UINT32) pSend->nSge; + wr.pSgl = pSend->pSgl; + wr.ImmediateData = pSend->ImmediateData; + + wr.Wr.Datagram.DestinationQkey = pSend->DestinationQkey; + wr.Wr.Datagram.DestinationQpn = pSend->DestinationQpn; + wr.Wr.Datagram.AhKey = pSend->AhKey; + + hr = PostSend(&wr, NULL); + return hr; +} + +STDMETHODIMP CWVDatagramQueuePair:: +AttachMulticast(WV_GID *pGid, NET16 Lid, OVERLAPPED* pOverlapped) +{ + WV_IO_QP_MULTICAST mc; + DWORD bytes; + HRESULT hr; + + mc.Id.Id = m_Id; + mc.Id.Data = (UINT32) Lid; + RtlCopyMemory(mc.Gid.Raw, pGid->Raw, sizeof mc.Gid.Raw); + + if (WvDeviceIoControl(m_hFile, WV_IOCTL_QP_ATTACH, &mc, sizeof mc, + NULL, 0, &bytes, pOverlapped)) { + hr = WV_SUCCESS; + } else { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + + return hr; +} + +STDMETHODIMP CWVDatagramQueuePair:: +DetachMulticast(WV_GID *pGid, NET16 Lid, OVERLAPPED* pOverlapped) +{ + WV_IO_QP_MULTICAST mc; + DWORD bytes; + HRESULT hr; + + mc.Id.Id = m_Id; + mc.Id.Data = (UINT32) Lid; + RtlCopyMemory(mc.Gid.Raw, pGid->Raw, sizeof mc.Gid.Raw); + + if (WvDeviceIoControl(m_hFile, WV_IOCTL_QP_DETACH, &mc, sizeof mc, + NULL, 0, &bytes, pOverlapped)) { + hr = WV_SUCCESS; + } else { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + + return hr; +} diff --git a/branches/WOF2-3/core/winverbs/user/wv_qp.h b/branches/WOF2-3/core/winverbs/user/wv_qp.h new file mode 100644 index 00000000..3060c151 --- /dev/null +++ b/branches/WOF2-3/core/winverbs/user/wv_qp.h @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#ifndef _WV_QP_H_ +#define _WV_QP_H_ + +#include +#include "wv_pd.h" +#include "wv_cq.h" +#include "wv_srq.h" +#include "wv_base.h" + +class CWVQueuePair : IWVQueuePair, public CWVBase +{ +public: + // IUnknown methods + STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + // IWVOverlapped methods + STDMETHODIMP CancelOverlappedRequests(); + STDMETHODIMP GetOverlappedResult(OVERLAPPED *pOverlapped, + DWORD *pNumberOfBytesTransferred, BOOL bWait); + + // IWVQueuePair methods + STDMETHODIMP Query(WV_QP_ATTRIBUTES* pAttributes); + STDMETHODIMP Modify(WV_QP_ATTRIBUTES* pAttributes, DWORD Options, + OVERLAPPED* pOverlapped); + STDMETHODIMP PostReceive(UINT64 WrId, WV_SGE* pSgl, SIZE_T nSge); + STDMETHODIMP PostSend(WV_SEND_REQUEST *pSend, WV_SEND_REQUEST **ppFailed); + + CWVQueuePair(CWVProtectionDomain *pPd); + ~CWVQueuePair(); + virtual void Delete() {}; + + CWVProtectionDomain *m_pPd; + CWVCompletionQueue *m_pSendCq; + CWVCompletionQueue *m_pReceiveCq; + CWVSharedReceiveQueue *m_pSrq; + uvp_interface_t *m_pVerbs; + ib_qp_handle_t m_hVerbsQp; + WV_QP_TYPE m_Type; + +protected: + STDMETHODIMP Create(WV_QP_CREATE* pAttributes); + void AddReferences(WV_QP_CREATE* pAttributes); + void ReleaseReferences(); +}; + +class CWVConnectQueuePair : IWVConnectQueuePair, public CWVQueuePair +{ +public: + // IUnknown methods + STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + // IWVOverlapped methods + STDMETHODIMP CancelOverlappedRequests(); + STDMETHODIMP GetOverlappedResult(OVERLAPPED *pOverlapped, + DWORD *pNumberOfBytesTransferred, BOOL bWait); + + // IWVQueuePair methods + STDMETHODIMP Query(WV_QP_ATTRIBUTES* pAttributes); + STDMETHODIMP Modify(WV_QP_ATTRIBUTES* pAttributes, DWORD Options, + OVERLAPPED* pOverlapped); + STDMETHODIMP PostReceive(UINT64 WrId, WV_SGE* pSgl, SIZE_T nSge); + STDMETHODIMP PostSend(WV_SEND_REQUEST *pSend, WV_SEND_REQUEST **ppFailed); + + // IWVConnectQueuePair methods + STDMETHODIMP Send(UINT64 WrId, WV_SGE* pSgl, SIZE_T nSge, + DWORD Flags, NET32 ImmediateData); + STDMETHODIMP Read(UINT64 WrId, WV_SGE* pSgl, SIZE_T nSge, + DWORD Flags, NET64 Address, NET32 Rkey); + STDMETHODIMP Write(UINT64 WrId, WV_SGE* pSgl, SIZE_T nSge, + DWORD Flags, NET32 ImmediateData, NET64 Address, + NET32 Rkey); + STDMETHODIMP CompareExchange(UINT64 WrId, WV_SGE* pSge, DWORD Flags, + NET64 Compare, NET64 Exchange, NET64 Address, + NET32 Rkey); + STDMETHODIMP FetchAdd(UINT64 WrId, WV_SGE* pSge, DWORD Flags, + NET64 Value, NET64 Address, NET32 Rkey); + STDMETHODIMP BindMemoryWindow(IWVMemoryWindow* pMw, UINT64 WrId, + UINT32 Lkey, DWORD AccessFlags, DWORD SendFlags, + const VOID* pBuffer, SIZE_T BufferLength, + NET32 *pRkey); + + CWVConnectQueuePair(CWVProtectionDomain *pPd) : CWVQueuePair(pPd) {}; + void Delete() {delete this;} + static STDMETHODIMP + CreateInstance(CWVProtectionDomain *pPd, WV_QP_CREATE* pAttributes, + IWVConnectQueuePair** ppQp) + { + HRESULT hr; + CWVConnectQueuePair *qp; + + qp = new CWVConnectQueuePair(pPd); + if (qp == NULL) { + hr = WV_NO_MEMORY; + goto err1; + } + + hr = qp->Init(); + if (FAILED(hr)) { + goto err2; + } + + hr = qp->Create(pAttributes); + if (FAILED(hr)) { + goto err2; + } + + *ppQp = qp; + return WV_SUCCESS; + + err2: + qp->Release(); + err1: + *ppQp = NULL; + return hr; + } +}; + +class CWVDatagramQueuePair : IWVDatagramQueuePair, public CWVQueuePair +{ +public: + // IUnknown methods + STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + // IWVOverlapped methods + STDMETHODIMP CancelOverlappedRequests(); + STDMETHODIMP GetOverlappedResult(OVERLAPPED *pOverlapped, + DWORD *pNumberOfBytesTransferred, BOOL bWait); + + // IWVQueuePair methods + STDMETHODIMP Query(WV_QP_ATTRIBUTES* pAttributes); + STDMETHODIMP Modify(WV_QP_ATTRIBUTES* pAttributes, DWORD Options, + OVERLAPPED* pOverlapped); + STDMETHODIMP PostReceive(UINT64 WrId, WV_SGE* pSgl, SIZE_T nSge); + STDMETHODIMP PostSend(WV_SEND_REQUEST *pSend, WV_SEND_REQUEST **ppFailed); + + // IWVDatagramQueuePair Methods + STDMETHODIMP Send(UINT64 WrId, ULONG_PTR AhKey, + WV_SGE* pSge, DWORD Flags, NET32 DestinationQpn, + NET32 DestinationQkey); + STDMETHODIMP SendMessage(WV_SEND_DATAGRAM* pSend); + STDMETHODIMP AttachMulticast(WV_GID *pGid, NET16 Lid, + OVERLAPPED* pOverlapped); + STDMETHODIMP DetachMulticast(WV_GID *pGid, NET16 Lid, + OVERLAPPED* pOverlapped); + + CWVDatagramQueuePair(CWVProtectionDomain *pPd) : CWVQueuePair(pPd) {}; + void Delete() {delete this;} + static STDMETHODIMP + CreateInstance(CWVProtectionDomain *pPd, WV_QP_CREATE* pAttributes, + IWVDatagramQueuePair** ppQp) + { + HRESULT hr; + CWVDatagramQueuePair *qp; + + qp = new CWVDatagramQueuePair(pPd); + if (qp == NULL) { + hr = WV_NO_MEMORY; + goto err1; + } + + hr = qp->Init(); + if (FAILED(hr)) { + goto err2; + } + + hr = qp->Create(pAttributes); + if (FAILED(hr)) { + goto err2; + } + + *ppQp = qp; + return WV_SUCCESS; + + err2: + qp->Release(); + err1: + *ppQp = NULL; + return hr; + } +}; + +#endif // _WV_QP_H_ \ No newline at end of file diff --git a/branches/WOF2-3/core/winverbs/user/wv_srq.cpp b/branches/WOF2-3/core/winverbs/user/wv_srq.cpp new file mode 100644 index 00000000..d7486a1d --- /dev/null +++ b/branches/WOF2-3/core/winverbs/user/wv_srq.cpp @@ -0,0 +1,306 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2009 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "wv_base.h" +#include "wv_memory.h" +#include "wv_srq.h" +#include "wv_ioctl.h" + +CWVSharedReceiveQueue::CWVSharedReceiveQueue(CWVProtectionDomain *pPd) +{ + pPd->AddRef(); + m_pPd = pPd; + m_pVerbs = pPd->m_pVerbs; + m_hFile = pPd->m_hFile; + m_hVerbsSrq = NULL; +} + +STDMETHODIMP CWVSharedReceiveQueue:: +Create(SIZE_T MaxWr, SIZE_T MaxSge, SIZE_T SrqLimit) +{ + WV_IO_SRQ_ATTRIBUTES *pattr; + DWORD bytes; + ib_api_status_t stat; + HRESULT hr; + ci_umv_buf_t verbsData; + CWVBuffer buf; + ib_srq_attr_t attr; + + attr.max_sge = (UINT32) MaxSge; + attr.max_wr = (UINT32) MaxWr; + attr.srq_limit = (UINT32) SrqLimit; + stat = m_pVerbs->pre_create_srq(m_pPd->m_hVerbsPd, &attr, + &verbsData, &m_hVerbsSrq); + if (stat != IB_SUCCESS) { + return WvConvertIbStatus(stat); + } + + bytes = sizeof WV_IO_SRQ_ATTRIBUTES + max(verbsData.input_size, verbsData.output_size); + pattr = (WV_IO_SRQ_ATTRIBUTES *) buf.Get(bytes); + if (pattr == NULL) { + hr = WV_NO_MEMORY; + goto post; + } + + pattr->Id.Id = m_pPd->m_Id; + pattr->Id.VerbInfo = verbsData.command; + pattr->MaxSge = attr.max_sge; + pattr->MaxWr = attr.max_wr; + pattr->SrqLimit = attr.srq_limit; + pattr->Reserved = 0; + RtlCopyMemory(pattr + 1, (void *) (ULONG_PTR) verbsData.p_inout_buf, + verbsData.input_size); + + if (WvDeviceIoControl(m_hFile, WV_IOCTL_SRQ_CREATE, + pattr, sizeof WV_IO_SRQ_ATTRIBUTES + verbsData.input_size, + pattr, sizeof WV_IO_SRQ_ATTRIBUTES + verbsData.output_size, + &bytes, NULL)) { + hr = WV_SUCCESS; + m_Id = pattr->Id.Id; + } else { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + + verbsData.status = pattr->Id.VerbInfo; + RtlCopyMemory((void *) (ULONG_PTR) verbsData.p_inout_buf, pattr + 1, + verbsData.output_size); + buf.Put(); + +post: + m_pVerbs->post_create_srq(m_pPd->m_hVerbsPd, (ib_api_status_t) hr, + &m_hVerbsSrq, &verbsData); + return hr; +} + +CWVSharedReceiveQueue::~CWVSharedReceiveQueue() +{ + DWORD bytes; + HRESULT hr; + + if (m_Id != 0) { + m_pVerbs->pre_destroy_srq(m_hVerbsSrq); + hr = WvDeviceIoControl(m_hFile, WV_IOCTL_SRQ_DESTROY, &m_Id, sizeof m_Id, + NULL, 0, &bytes, NULL) ? + WV_SUCCESS : HRESULT_FROM_WIN32(GetLastError()); + m_pVerbs->post_destroy_srq(m_hVerbsSrq, (ib_api_status_t) hr); + } + m_pPd->Release(); +} + +STDMETHODIMP CWVSharedReceiveQueue:: +QueryInterface(REFIID riid, LPVOID FAR* ppvObj) +{ + if (riid != IID_IUnknown && riid != IID_IWVSharedReceiveQueue) { + *ppvObj = NULL; + return E_NOINTERFACE; + } + + *ppvObj = this; + AddRef(); + return WV_SUCCESS; +} + +STDMETHODIMP_(ULONG) CWVSharedReceiveQueue:: +AddRef(void) +{ + return CWVBase::AddRef(); +} + +STDMETHODIMP_(ULONG) CWVSharedReceiveQueue:: +Release(void) +{ + return CWVBase::Release(); +} + +STDMETHODIMP CWVSharedReceiveQueue:: +CancelOverlappedRequests(void) +{ + DWORD bytes; + + return WvDeviceIoControl(m_hFile, WV_IOCTL_SRQ_CANCEL, &m_Id, sizeof m_Id, + NULL, 0, &bytes, NULL) ? + WV_SUCCESS : HRESULT_FROM_WIN32(GetLastError()); +} + +STDMETHODIMP CWVSharedReceiveQueue:: +GetOverlappedResult(OVERLAPPED *pOverlapped, + DWORD *pNumberOfBytesTransferred, BOOL bWait) +{ + ::GetOverlappedResult(m_hFile, pOverlapped, pNumberOfBytesTransferred, bWait); + return (HRESULT) pOverlapped->Internal; +} + +STDMETHODIMP CWVSharedReceiveQueue:: +Query(SIZE_T* pMaxWr, SIZE_T* pMaxSge, SIZE_T* pSrqLimit) +{ + WV_IO_SRQ_ATTRIBUTES *pattr; + DWORD bytes; + ib_api_status_t stat; + HRESULT hr; + ci_umv_buf_t verbsData; + CWVBuffer buf; + ib_srq_attr_t attr; + + stat = m_pVerbs->pre_query_srq(m_hVerbsSrq, &verbsData); + if (stat != IB_SUCCESS) { + return WvConvertIbStatus(stat); + } + + bytes = sizeof WV_IO_SRQ_ATTRIBUTES + max(verbsData.input_size, verbsData.output_size); + pattr = (WV_IO_SRQ_ATTRIBUTES *) buf.Get(bytes); + if (pattr == NULL) { + hr = WV_NO_MEMORY; + goto post; + } + + pattr->Id.Id = m_Id; + pattr->Id.VerbInfo = verbsData.command; + pattr->Reserved = 0; + RtlCopyMemory(pattr + 1, (void *) (ULONG_PTR) verbsData.p_inout_buf, + verbsData.input_size); + + if (WvDeviceIoControl(m_hFile, WV_IOCTL_SRQ_QUERY, + pattr, sizeof WV_IO_SRQ_ATTRIBUTES + verbsData.input_size, + pattr, sizeof WV_IO_SRQ_ATTRIBUTES + verbsData.output_size, + &bytes, NULL)) { + hr = WV_SUCCESS; + attr.max_sge = pattr->MaxSge; + attr.max_wr = pattr->MaxWr; + attr.srq_limit = pattr->SrqLimit; + } else { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + + verbsData.status = pattr->Id.VerbInfo; + RtlCopyMemory((void *) (ULONG_PTR) verbsData.p_inout_buf, pattr + 1, + verbsData.output_size); + buf.Put(); + +post: + m_pVerbs->post_query_srq(m_hVerbsSrq, (ib_api_status_t) hr, + &attr, &verbsData); + if (SUCCEEDED(hr)) { + *pMaxWr = attr.max_wr; + *pMaxSge = attr.max_sge; + *pSrqLimit = attr.srq_limit; + } + return hr; +} + +STDMETHODIMP CWVSharedReceiveQueue:: +Modify(SIZE_T MaxWr, SIZE_T SrqLimit) +{ + WV_IO_SRQ_ATTRIBUTES *pattr; + DWORD bytes; + ib_api_status_t stat; + HRESULT hr; + ci_umv_buf_t verbsData; + CWVBuffer buf; + ib_srq_attr_t attr; + + attr.max_wr = (UINT32) MaxWr; + attr.srq_limit = (UINT32) SrqLimit; + stat = m_pVerbs->pre_modify_srq(m_hVerbsSrq, &attr, (ib_srq_attr_mask_t) + (IB_SRQ_MAX_WR & IB_SRQ_LIMIT), &verbsData); + if (stat != IB_SUCCESS) { + return WvConvertIbStatus(stat); + } + + bytes = sizeof WV_IO_SRQ_ATTRIBUTES + max(verbsData.input_size, verbsData.output_size); + pattr = (WV_IO_SRQ_ATTRIBUTES *) buf.Get(bytes); + if (pattr == NULL) { + hr = WV_NO_MEMORY; + goto post; + } + + pattr->Id.Id = m_Id; + pattr->Id.VerbInfo = verbsData.command; + pattr->MaxWr = attr.max_wr; + pattr->SrqLimit = attr.srq_limit; + pattr->Reserved = 0; + RtlCopyMemory(pattr + 1, (void *) (ULONG_PTR) verbsData.p_inout_buf, + verbsData.input_size); + + if (WvDeviceIoControl(m_hFile, WV_IOCTL_SRQ_MODIFY, + pattr, sizeof WV_IO_SRQ_ATTRIBUTES + verbsData.input_size, + pattr, sizeof WV_IO_SRQ_ATTRIBUTES + verbsData.output_size, + &bytes, NULL)) { + hr = WV_SUCCESS; + } else { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + + verbsData.status = pattr->Id.VerbInfo; + RtlCopyMemory((void *) (ULONG_PTR) verbsData.p_inout_buf, pattr + 1, + verbsData.output_size); + buf.Put(); + +post: + m_pVerbs->post_modify_srq(m_hVerbsSrq, (ib_api_status_t) hr, &verbsData); + return hr; +} + +STDMETHODIMP CWVSharedReceiveQueue:: +PostReceive(UINT64 WrId, WV_SGE* pSgl, SIZE_T nSge) +{ + ib_recv_wr_t wr, *pwr; + ib_api_status_t stat; + HRESULT hr; + + wr.p_next = NULL; + wr.wr_id = WrId; + wr.num_ds = (UINT32) nSge; + wr.ds_array = WvConvertSgl(pSgl, nSge); + + stat = m_pVerbs->post_srq_recv(m_hVerbsSrq, &wr, &pwr); + if (stat == IB_SUCCESS) { + hr = WV_SUCCESS; + } else { + hr = WvConvertIbStatus(stat); + } + + return hr; +} + +STDMETHODIMP CWVSharedReceiveQueue:: +Notify(OVERLAPPED* pOverlapped) +{ + DWORD bytes; + HRESULT hr; + + if (WvDeviceIoControl(m_hFile, WV_IOCTL_SRQ_NOTIFY, &m_Id, sizeof m_Id, + NULL, 0, &bytes, pOverlapped)) { + hr = WV_SUCCESS; + } else { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + + return hr; +} diff --git a/branches/WOF2-3/core/winverbs/user/wv_srq.h b/branches/WOF2-3/core/winverbs/user/wv_srq.h new file mode 100644 index 00000000..1527cd4e --- /dev/null +++ b/branches/WOF2-3/core/winverbs/user/wv_srq.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#ifndef _WV_SRQ_H_ +#define _WV_SRQ_H_ + +#include +#include "wv_pd.h" +#include "wv_base.h" + +class CWVSharedReceiveQueue : IWVSharedReceiveQueue, public CWVBase +{ +public: + // IUnknown methods + STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + // IWVOverlapped methods + STDMETHODIMP CancelOverlappedRequests(); + STDMETHODIMP GetOverlappedResult(OVERLAPPED *pOverlapped, + DWORD *pNumberOfBytesTransferred, BOOL bWait); + + // IWVSharedReceiveQueue methods + STDMETHODIMP Query(SIZE_T* pMaxWr, SIZE_T* pMaxSge, SIZE_T* pSrqLimit); + STDMETHODIMP Modify(SIZE_T MaxWr, SIZE_T SrqLimit); + STDMETHODIMP PostReceive(UINT64 WrId, WV_SGE* pSgl, SIZE_T nSge); + STDMETHODIMP Notify(OVERLAPPED* pOverlapped); + + CWVSharedReceiveQueue(CWVProtectionDomain *pPd); + ~CWVSharedReceiveQueue(); + void Delete() {delete this;} + static STDMETHODIMP + CreateInstance(CWVProtectionDomain *pPd, SIZE_T MaxWr, SIZE_T MaxSge, + SIZE_T SrqLimit, IWVSharedReceiveQueue** ppSrq) + { + HRESULT hr; + CWVSharedReceiveQueue *srq; + + srq = new CWVSharedReceiveQueue(pPd); + if (srq == NULL) { + hr = WV_NO_MEMORY; + goto err1; + } + + hr = srq->Init(); + if (FAILED(hr)) { + goto err2; + } + + hr = srq->Create(MaxWr, MaxSge, SrqLimit); + if (FAILED(hr)) { + goto err2; + } + + *ppSrq = srq; + return WV_SUCCESS; + + err2: + srq->Release(); + err1: + *ppSrq = NULL; + return hr; + } + + CWVProtectionDomain *m_pPd; + uvp_interface_t *m_pVerbs; + ib_srq_handle_t m_hVerbsSrq; + +protected: + STDMETHODIMP Create(SIZE_T MaxWr, SIZE_T MaxSge, SIZE_T SrqLimit); +}; + +#endif // _WV_SRQ_H_ \ No newline at end of file diff --git a/branches/WOF2-3/core/winverbs/user/wv_uverbs.cpp b/branches/WOF2-3/core/winverbs/user/wv_uverbs.cpp new file mode 100644 index 00000000..1a315b41 --- /dev/null +++ b/branches/WOF2-3/core/winverbs/user/wv_uverbs.cpp @@ -0,0 +1,512 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include + +#include + +static ib_api_status_t __stdcall +WvPreOpenCa(const ib_net64_t ca_guid, ci_umv_buf_t *p_umv_buf, + ib_ca_handle_t *ph_uvp_ca) +{ + UNREFERENCED_PARAMETER(ca_guid); + UNREFERENCED_PARAMETER(ph_uvp_ca); + + RtlZeroMemory(p_umv_buf, sizeof(*p_umv_buf)); + return IB_SUCCESS; +} + +static ib_api_status_t __stdcall +WvPostOpenCa(const ib_net64_t ca_guid, ib_api_status_t ioctl_status, + ib_ca_handle_t *ph_uvp_ca, ci_umv_buf_t *p_umv_buf) +{ + UNREFERENCED_PARAMETER(ca_guid); + UNREFERENCED_PARAMETER(ioctl_status); + UNREFERENCED_PARAMETER(ph_uvp_ca); + UNREFERENCED_PARAMETER(p_umv_buf); + return IB_SUCCESS; +} + +static ib_api_status_t __stdcall +WvPreCloseCa(ib_ca_handle_t h_uvp_ca) +{ + UNREFERENCED_PARAMETER(h_uvp_ca); + return IB_SUCCESS; +} + +static ib_api_status_t __stdcall +WvPostCloseCa(ib_ca_handle_t h_uvp_ca, ib_api_status_t ioctl_status) +{ + UNREFERENCED_PARAMETER(h_uvp_ca); + UNREFERENCED_PARAMETER(ioctl_status); + return IB_SUCCESS; +} + +static ib_api_status_t __stdcall +WvPreAllocatePd(ib_ca_handle_t h_uvp_ca, ci_umv_buf_t *p_umv_buf, + ib_pd_handle_t *ph_uvp_pd) +{ + UNREFERENCED_PARAMETER(h_uvp_ca); + UNREFERENCED_PARAMETER(ph_uvp_pd); + + RtlZeroMemory(p_umv_buf, sizeof(*p_umv_buf)); + return IB_SUCCESS; +} + +static void __stdcall +WvPostAllocatePd(ib_ca_handle_t h_uvp_ca, ib_api_status_t ioctl_status, + ib_pd_handle_t *ph_uvp_pd, ci_umv_buf_t *p_umv_buf) +{ + UNREFERENCED_PARAMETER(h_uvp_ca); + UNREFERENCED_PARAMETER(ioctl_status); + UNREFERENCED_PARAMETER(ph_uvp_pd); + UNREFERENCED_PARAMETER(p_umv_buf); +} + +static ib_api_status_t __stdcall +WvPreDeallocatePd(const ib_pd_handle_t h_uvp_pd) +{ + UNREFERENCED_PARAMETER(h_uvp_pd); + return IB_SUCCESS; +} + +static void __stdcall +WvPostDeallocatePd(const ib_pd_handle_t h_uvp_pd, ib_api_status_t ioctl_status) +{ + UNREFERENCED_PARAMETER(h_uvp_pd); + UNREFERENCED_PARAMETER(ioctl_status); +} + +static ib_api_status_t __stdcall +WvPreCreateAv(const ib_pd_handle_t h_uvp_pd, const ib_av_attr_t *p_addr_vector, + ci_umv_buf_t *p_umv_buf, ib_av_handle_t *ph_uvp_av) +{ + UNREFERENCED_PARAMETER(h_uvp_pd); + UNREFERENCED_PARAMETER(p_addr_vector); + UNREFERENCED_PARAMETER(ph_uvp_av); + + RtlZeroMemory(p_umv_buf, sizeof(*p_umv_buf)); + return IB_SUCCESS; +} + +static void __stdcall +WvPostCreateAv(const ib_pd_handle_t h_uvp_pd, ib_api_status_t ioctl_status, + ib_av_handle_t *ph_uvp_av, ci_umv_buf_t *p_umv_buf) +{ + UNREFERENCED_PARAMETER(h_uvp_pd); + UNREFERENCED_PARAMETER(ioctl_status); + UNREFERENCED_PARAMETER(ph_uvp_av); + UNREFERENCED_PARAMETER(p_umv_buf); +} + +static ib_api_status_t __stdcall +WvPreDestroyAv(const ib_av_handle_t h_uvp_av) +{ + UNREFERENCED_PARAMETER(h_uvp_av); + return IB_SUCCESS; +} + +static void __stdcall +WvPostDestroyAv(const ib_av_handle_t h_uvp_av, ib_api_status_t ioctl_status) +{ + UNREFERENCED_PARAMETER(h_uvp_av); + UNREFERENCED_PARAMETER(ioctl_status); +} + +static ib_api_status_t __stdcall +WvPreCreateSrq(const ib_pd_handle_t h_uvp_pd, const ib_srq_attr_t* const p_srq_attr, + ci_umv_buf_t *p_umv_buf, ib_srq_handle_t *ph_uvp_srq) +{ + UNREFERENCED_PARAMETER(h_uvp_pd); + UNREFERENCED_PARAMETER(p_srq_attr); + UNREFERENCED_PARAMETER(ph_uvp_srq); + + RtlZeroMemory(p_umv_buf, sizeof(*p_umv_buf)); + return IB_SUCCESS; +} + +static void __stdcall +WvPostCreateSrq(const ib_pd_handle_t h_uvp_pd, ib_api_status_t ioctl_status, + ib_srq_handle_t *ph_uvp_srq, ci_umv_buf_t *p_umv_buf) +{ + UNREFERENCED_PARAMETER(h_uvp_pd); + UNREFERENCED_PARAMETER(ioctl_status); + UNREFERENCED_PARAMETER(ph_uvp_srq); + UNREFERENCED_PARAMETER(p_umv_buf); +} + +static ib_api_status_t __stdcall +WvPreModifySrq(const ib_srq_handle_t h_uvp_srq, const ib_srq_attr_t * const p_srq_attr, + const ib_srq_attr_mask_t srq_attr_mask, ci_umv_buf_t *p_umv_buf) +{ + UNREFERENCED_PARAMETER(h_uvp_srq); + UNREFERENCED_PARAMETER(p_srq_attr); + UNREFERENCED_PARAMETER(srq_attr_mask); + + RtlZeroMemory(p_umv_buf, sizeof(*p_umv_buf)); + return IB_SUCCESS; +} + +static void __stdcall +WvPostModifySrq(const ib_srq_handle_t h_uvp_srq, ib_api_status_t ioctl_status, + ci_umv_buf_t *p_umv_buf) +{ + UNREFERENCED_PARAMETER(h_uvp_srq); + UNREFERENCED_PARAMETER(ioctl_status); + UNREFERENCED_PARAMETER(p_umv_buf); +} + +static ib_api_status_t __stdcall +WvPreQuerySrq(ib_srq_handle_t h_uvp_srq, ci_umv_buf_t *p_umv_buf) +{ + UNREFERENCED_PARAMETER(h_uvp_srq); + + RtlZeroMemory(p_umv_buf, sizeof(*p_umv_buf)); + return IB_SUCCESS; +} + +static void __stdcall +WvPostQuerySrq(ib_srq_handle_t h_uvp_srq, ib_api_status_t ioctl_status, + ib_srq_attr_t *p_query_attr, ci_umv_buf_t *p_umv_buf) +{ + UNREFERENCED_PARAMETER(h_uvp_srq); + UNREFERENCED_PARAMETER(ioctl_status); + UNREFERENCED_PARAMETER(p_query_attr); + UNREFERENCED_PARAMETER(p_umv_buf); +} + +static ib_api_status_t __stdcall +WvPreDestroySrq(const ib_srq_handle_t h_uvp_srq) +{ + UNREFERENCED_PARAMETER(h_uvp_srq); + return IB_SUCCESS; +} + +static void __stdcall +WvPostDestroySrq(const ib_srq_handle_t h_uvp_srq, ib_api_status_t ioctl_status) +{ + UNREFERENCED_PARAMETER(h_uvp_srq); + UNREFERENCED_PARAMETER(ioctl_status); +} + +static ib_api_status_t __stdcall +WvPostCreateQp(const ib_pd_handle_t h_uvp_pd, ib_api_status_t ioctl_status, + ib_qp_handle_t *ph_uvp_qp, ci_umv_buf_t *p_umv_buf) +{ + UNREFERENCED_PARAMETER(h_uvp_pd); + UNREFERENCED_PARAMETER(ioctl_status); + UNREFERENCED_PARAMETER(ph_uvp_qp); + UNREFERENCED_PARAMETER(p_umv_buf); + return IB_SUCCESS; +} + +static ib_api_status_t __stdcall +WvPreModifyQp(const ib_qp_handle_t h_uvp_qp, const ib_qp_mod_t *p_modify_attr, + ci_umv_buf_t *p_umv_buf) +{ + UNREFERENCED_PARAMETER(h_uvp_qp); + UNREFERENCED_PARAMETER(p_modify_attr); + + RtlZeroMemory(p_umv_buf, sizeof(*p_umv_buf)); + return IB_SUCCESS; +} + +static void __stdcall +WvPostModifyQp(const ib_qp_handle_t h_uvp_qp, ib_api_status_t ioctl_status, + ci_umv_buf_t *p_umv_buf) +{ + UNREFERENCED_PARAMETER(h_uvp_qp); + UNREFERENCED_PARAMETER(ioctl_status); + UNREFERENCED_PARAMETER(p_umv_buf); +} + +static ib_api_status_t __stdcall +WvPreQueryQp(ib_qp_handle_t h_uvp_qp, ci_umv_buf_t *p_umv_buf) +{ + UNREFERENCED_PARAMETER(h_uvp_qp); + + RtlZeroMemory(p_umv_buf, sizeof(*p_umv_buf)); + return IB_SUCCESS; +} + +static void __stdcall +WvPostQueryQp(ib_qp_handle_t h_uvp_qp, ib_api_status_t ioctl_status, + ib_qp_attr_t *p_query_attr, ci_umv_buf_t *p_umv_buf) +{ + UNREFERENCED_PARAMETER(h_uvp_qp); + UNREFERENCED_PARAMETER(ioctl_status); + UNREFERENCED_PARAMETER(p_query_attr); + UNREFERENCED_PARAMETER(p_umv_buf); +} + +static ib_api_status_t __stdcall +WvPreDestroyQp(const ib_qp_handle_t h_uvp_qp) +{ + UNREFERENCED_PARAMETER(h_uvp_qp); + return IB_SUCCESS; +} + +static void __stdcall +WvPostDestroyQp(const ib_qp_handle_t h_uvp_qp, ib_api_status_t ioctl_status) +{ + UNREFERENCED_PARAMETER(h_uvp_qp); + UNREFERENCED_PARAMETER(ioctl_status); +} + +static ib_api_status_t __stdcall +WvPreCreateCq(const ib_ca_handle_t h_uvp_ca, uint32_t* const p_size, + ci_umv_buf_t *p_umv_buf, ib_cq_handle_t *ph_uvp_cq) +{ + UNREFERENCED_PARAMETER(h_uvp_ca); + UNREFERENCED_PARAMETER(p_size); + UNREFERENCED_PARAMETER(ph_uvp_cq); + + RtlZeroMemory(p_umv_buf, sizeof(*p_umv_buf)); + return IB_SUCCESS; +} + +static void __stdcall +WvPostCreateCq(const ib_ca_handle_t h_uvp_ca, ib_api_status_t ioctl_status, + const uint32_t size, ib_cq_handle_t *ph_uvp_cq, ci_umv_buf_t *p_umv_buf) +{ + UNREFERENCED_PARAMETER(h_uvp_ca); + UNREFERENCED_PARAMETER(ioctl_status); + UNREFERENCED_PARAMETER(size); + UNREFERENCED_PARAMETER(ph_uvp_cq); + UNREFERENCED_PARAMETER(p_umv_buf); +} + +static ib_api_status_t __stdcall +WvPreResizeCq(const ib_cq_handle_t h_uvp_cq, uint32_t* const p_size, + ci_umv_buf_t *p_umv_buf) +{ + UNREFERENCED_PARAMETER(h_uvp_cq); + UNREFERENCED_PARAMETER(p_size); + + RtlZeroMemory(p_umv_buf, sizeof(*p_umv_buf)); + return IB_SUCCESS; +} + +static void __stdcall +WvPostResizeCq(const ib_cq_handle_t h_uvp_cq, ib_api_status_t ioctl_status, + const uint32_t size, ci_umv_buf_t *p_umv_buf) +{ + UNREFERENCED_PARAMETER(h_uvp_cq); + UNREFERENCED_PARAMETER(ioctl_status); + UNREFERENCED_PARAMETER(size); + UNREFERENCED_PARAMETER(p_umv_buf); +} + +static ib_api_status_t __stdcall +WvPreDestroyCq(const ib_cq_handle_t h_uvp_cq) +{ + UNREFERENCED_PARAMETER(h_uvp_cq); + return IB_SUCCESS; +} + +static void __stdcall +WvPostDestroyCq(const ib_cq_handle_t h_uvp_cq, ib_api_status_t ioctl_status) +{ + UNREFERENCED_PARAMETER(h_uvp_cq); + UNREFERENCED_PARAMETER(ioctl_status); +} + +static ib_api_status_t __stdcall +WvPreCreateMw(const ib_pd_handle_t h_uvp_pd, ci_umv_buf_t *p_umv_buf, + ib_mw_handle_t *ph_uvp_mw) +{ + UNREFERENCED_PARAMETER(h_uvp_pd); + UNREFERENCED_PARAMETER(ph_uvp_mw); + + RtlZeroMemory(p_umv_buf, sizeof(*p_umv_buf)); + return IB_SUCCESS; +} + +static void __stdcall +WvPostCreateMw(const ib_pd_handle_t h_uvp_pd, ib_api_status_t ioctl_status, + net32_t rkey, ib_mw_handle_t *ph_uvp_mw, ci_umv_buf_t *p_umv_buf) +{ + UNREFERENCED_PARAMETER(h_uvp_pd); + UNREFERENCED_PARAMETER(ioctl_status); + UNREFERENCED_PARAMETER(rkey); + UNREFERENCED_PARAMETER(ph_uvp_mw); + UNREFERENCED_PARAMETER(p_umv_buf); +} + +static ib_api_status_t __stdcall +WvPreDestroyMw(const ib_mw_handle_t h_uvp_mw) +{ + UNREFERENCED_PARAMETER(h_uvp_mw); + return IB_SUCCESS; +} + +static void __stdcall +WvPostDestroyMw(const ib_mw_handle_t h_uvp_mw, ib_api_status_t ioctl_status) +{ + UNREFERENCED_PARAMETER(h_uvp_mw); + UNREFERENCED_PARAMETER(ioctl_status); +} + +HRESULT WvGetUserVerbs(HMODULE hLib, uvp_interface_t *pVerbs) +{ + uvp_get_interface_t pfgetif; + ib_api_status_t ib_status; + + pfgetif = (uvp_get_interface_t)GetProcAddress(hLib, "uvp_get_interface"); + if (pfgetif == NULL) { + return GetLastError(); + } + + ib_status = pfgetif(IID_UVP, pVerbs); + if (ib_status != IB_SUCCESS) { + return WV_NOT_SUPPORTED; + } + + // Provide default implementations + if (pVerbs->pre_open_ca == NULL) { + pVerbs->pre_open_ca = WvPreOpenCa; + } + if (pVerbs->post_open_ca == NULL) { + pVerbs->post_open_ca = WvPostOpenCa; + } + if (pVerbs->pre_close_ca == NULL) { + pVerbs->pre_close_ca = WvPreCloseCa; + } + if (pVerbs->post_close_ca == NULL) { + pVerbs->post_close_ca = WvPostCloseCa; + } + + if (pVerbs->pre_allocate_pd == NULL) { + pVerbs->pre_allocate_pd = WvPreAllocatePd; + } + if (pVerbs->post_allocate_pd == NULL) { + pVerbs->post_allocate_pd = WvPostAllocatePd; + } + if (pVerbs->pre_deallocate_pd == NULL) { + pVerbs->pre_deallocate_pd = WvPreDeallocatePd; + } + if (pVerbs->post_deallocate_pd == NULL) { + pVerbs->post_deallocate_pd = WvPostDeallocatePd; + } + + if (pVerbs->pre_create_av == NULL) { + pVerbs->pre_create_av = WvPreCreateAv; + } + if (pVerbs->post_create_av == NULL) { + pVerbs->post_create_av = WvPostCreateAv; + } + if (pVerbs->pre_destroy_av == NULL) { + pVerbs->pre_destroy_av = WvPreDestroyAv; + } + if (pVerbs->post_destroy_av == NULL) { + pVerbs->post_destroy_av = WvPostDestroyAv; + } + + if (pVerbs->pre_create_srq == NULL) { + pVerbs->pre_create_srq = WvPreCreateSrq; + } + if (pVerbs->post_create_srq == NULL) { + pVerbs->post_create_srq = WvPostCreateSrq; + } + if (pVerbs->pre_modify_srq == NULL) { + pVerbs->pre_modify_srq = WvPreModifySrq; + } + if (pVerbs->post_modify_srq == NULL) { + pVerbs->post_modify_srq = WvPostModifySrq; + } + if (pVerbs->pre_query_srq == NULL) { + pVerbs->pre_query_srq = WvPreQuerySrq; + } + if (pVerbs->post_query_srq == NULL) { + pVerbs->post_query_srq = WvPostQuerySrq; + } + if (pVerbs->pre_destroy_srq == NULL) { + pVerbs->pre_destroy_srq = WvPreDestroySrq; + } + if (pVerbs->post_destroy_srq == NULL) { + pVerbs->post_destroy_srq = WvPostDestroySrq; + } + + if (pVerbs->post_create_qp == NULL) { + pVerbs->post_create_qp = WvPostCreateQp; + } + if (pVerbs->pre_modify_qp == NULL) { + pVerbs->pre_modify_qp = WvPreModifyQp; + } + if (pVerbs->post_modify_qp == NULL) { + pVerbs->post_modify_qp = WvPostModifyQp; + } + if (pVerbs->pre_query_qp == NULL) { + pVerbs->pre_query_qp = WvPreQueryQp; + } + if (pVerbs->post_query_qp == NULL) { + pVerbs->post_query_qp = WvPostQueryQp; + } + if (pVerbs->pre_destroy_qp == NULL) { + pVerbs->pre_destroy_qp = WvPreDestroyQp; + } + if (pVerbs->post_destroy_qp == NULL) { + pVerbs->post_destroy_qp = WvPostDestroyQp; + } + + if (pVerbs->pre_create_cq == NULL) { + pVerbs->pre_create_cq = WvPreCreateCq; + } + if (pVerbs->post_create_cq == NULL) { + pVerbs->post_create_cq = WvPostCreateCq; + } + if (pVerbs->pre_resize_cq == NULL) { + pVerbs->pre_resize_cq = WvPreResizeCq; + } + if (pVerbs->post_resize_cq == NULL) { + pVerbs->post_resize_cq = WvPostResizeCq; + } + if (pVerbs->pre_destroy_cq == NULL) { + pVerbs->pre_destroy_cq = WvPreDestroyCq; + } + if (pVerbs->post_destroy_cq == NULL) { + pVerbs->post_destroy_cq = WvPostDestroyCq; + } + + if (pVerbs->pre_create_mw == NULL) { + pVerbs->pre_create_mw = WvPreCreateMw; + } + if (pVerbs->post_create_mw == NULL) { + pVerbs->post_create_mw = WvPostCreateMw; + } + if (pVerbs->pre_destroy_mw == NULL) { + pVerbs->pre_destroy_mw = WvPreDestroyMw; + } + if (pVerbs->post_destroy_mw == NULL) { + pVerbs->post_destroy_mw = WvPostDestroyMw; + } + + return WV_SUCCESS; +} diff --git a/branches/WOF2-3/core/winverbs/wv_ioctl.h b/branches/WOF2-3/core/winverbs/wv_ioctl.h new file mode 100644 index 00000000..898a3920 --- /dev/null +++ b/branches/WOF2-3/core/winverbs/wv_ioctl.h @@ -0,0 +1,752 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#ifndef _WV_IOCTL_H_ +#define _WV_IOCTL_H_ + +typedef UINT16 NET16; +typedef UINT32 NET32; +typedef UINT64 NET64; + +#define WV_IOCTL(f) CTL_CODE(FILE_DEVICE_INFINIBAND, f, METHOD_BUFFERED,\ + FILE_READ_DATA | FILE_WRITE_DATA) + +// input parameter / output parameter +// IOCTL +#define WV_IO_FUNCTION_BASE 0x800 + +enum { + WV_IO_FUNCTION_MIN, + WV_IO_FUNCTION_GUID_QUERY, + WV_IO_FUNCTION_LIBRARY_QUERY, + WV_IO_FUNCTION_DEVICE_OPEN, + WV_IO_FUNCTION_DEVICE_CLOSE, + WV_IO_FUNCTION_DEVICE_QUERY, + WV_IO_FUNCTION_DEVICE_PORT_QUERY, + WV_IO_FUNCTION_DEVICE_GID_QUERY, + WV_IO_FUNCTION_DEVICE_PKEY_QUERY, + WV_IO_FUNCTION_DEVICE_NOTIFY, + WV_IO_FUNCTION_DEVICE_CANCEL, + WV_IO_FUNCTION_PD_ALLOCATE, + WV_IO_FUNCTION_PD_DEALLOCATE, + WV_IO_FUNCTION_MEMORY_REGISTER, + WV_IO_FUNCTION_MEMORY_DEREGISTER, + WV_IO_FUNCTION_MW_ALLOCATE, + WV_IO_FUNCTION_MW_DEALLOCATE, + WV_IO_FUNCTION_AH_CREATE, + WV_IO_FUNCTION_AH_DESTROY, + WV_IO_FUNCTION_CQ_CREATE, + WV_IO_FUNCTION_CQ_DESTROY, + WV_IO_FUNCTION_CQ_RESIZE, + WV_IO_FUNCTION_CQ_NOTIFY, + WV_IO_FUNCTION_CQ_CANCEL, + WV_IO_FUNCTION_SRQ_CREATE, + WV_IO_FUNCTION_SRQ_DESTROY, + WV_IO_FUNCTION_SRQ_QUERY, + WV_IO_FUNCTION_SRQ_MODIFY, + WV_IO_FUNCTION_SRQ_NOTIFY, + WV_IO_FUNCTION_SRQ_CANCEL, + WV_IO_FUNCTION_QP_CREATE, + WV_IO_FUNCTION_QP_DESTROY, + WV_IO_FUNCTION_QP_QUERY, + WV_IO_FUNCTION_QP_MODIFY, + WV_IO_FUNCTION_QP_ATTACH, + WV_IO_FUNCTION_QP_DETACH, + WV_IO_FUNCTION_QP_CANCEL, + WV_IO_FUNCTION_EP_CREATE, + WV_IO_FUNCTION_EP_DESTROY, + WV_IO_FUNCTION_EP_MODIFY, + WV_IO_FUNCTION_EP_BIND, + WV_IO_FUNCTION_EP_REJECT, + WV_IO_FUNCTION_EP_CONNECT, + WV_IO_FUNCTION_EP_ACCEPT, + WV_IO_FUNCTION_EP_DISCONNECT, + WV_IO_FUNCTION_EP_DISCONNECT_NOTIFY, + WV_IO_FUNCTION_EP_QUERY, + WV_IO_FUNCTION_EP_LOOKUP, + WV_IO_FUNCTION_EP_MULTICAST_JOIN, + WV_IO_FUNCTION_EP_MULTICAST_LEAVE, + WV_IO_FUNCTION_EP_CANCEL, + WV_IO_FUNCTION_EP_LISTEN, + WV_IO_FUNCTION_EP_GET_REQUEST, + WV_IO_FUNCTION_PD_CANCEL, + WV_IO_FUNCTION_MAX +}; + +// none / WV_IO_GUID_LIST +#define WV_IOCTL_GUID_QUERY WV_IOCTL(WV_IO_FUNCTION_BASE + \ + WV_IO_FUNCTION_GUID_QUERY) + +// NET64 Guid / LibraryName +#define WV_IOCTL_LIBRARY_QUERY WV_IOCTL(WV_IO_FUNCTION_BASE + \ + WV_IO_FUNCTION_LIBRARY_QUERY) + +// WV_IO_ID / WV_IO_ID +#define WV_IOCTL_DEVICE_OPEN WV_IOCTL(WV_IO_FUNCTION_BASE + \ + WV_IO_FUNCTION_DEVICE_OPEN) + +// UINT64 Id / none +#define WV_IOCTL_DEVICE_CLOSE WV_IOCTL(WV_IO_FUNCTION_BASE + \ + WV_IO_FUNCTION_DEVICE_CLOSE) + +// UINT64 Id / WV_IO_DEVICE_ATTRIBUTES +#define WV_IOCTL_DEVICE_QUERY WV_IOCTL(WV_IO_FUNCTION_BASE + \ + WV_IO_FUNCTION_DEVICE_QUERY) + +// WV_IO_DEVICE_PORT_QUERY / WV_IO_PORT_ATTRIBUTES == WV_PORT_ATTRIBUTES +#define WV_IOCTL_DEVICE_PORT_QUERY WV_IOCTL(WV_IO_FUNCTION_BASE + \ + WV_IO_FUNCTION_DEVICE_PORT_QUERY) + +// WV_IO_DEVICE_PORT_QUERY / WV_IO_GID[] == WV_GID[] +#define WV_IOCTL_DEVICE_GID_QUERY WV_IOCTL(WV_IO_FUNCTION_BASE + \ + WV_IO_FUNCTION_DEVICE_GID_QUERY) + +// WV_IO_DEVICE_PORT_QUERY / NET16 Pkey[] +#define WV_IOCTL_DEVICE_PKEY_QUERY WV_IOCTL(WV_IO_FUNCTION_BASE + \ + WV_IO_FUNCTION_DEVICE_PKEY_QUERY) + +// WV_IO_ID / DWORD +#define WV_IOCTL_DEVICE_NOTIFY WV_IOCTL(WV_IO_FUNCTION_BASE + \ + WV_IO_FUNCTION_DEVICE_NOTIFY) + +// UINT64 Id / none +#define WV_IOCTL_DEVICE_CANCEL WV_IOCTL(WV_IO_FUNCTION_BASE + \ + WV_IO_FUNCTION_DEVICE_CANCEL) + +// WV_IO_ID / WV_IO_ID +#define WV_IOCTL_PD_ALLOCATE WV_IOCTL(WV_IO_FUNCTION_BASE + \ + WV_IO_FUNCTION_PD_ALLOCATE) + +// UINT64 Id / none +#define WV_IOCTL_PD_DEALLOCATE WV_IOCTL(WV_IO_FUNCTION_BASE + \ + WV_IO_FUNCTION_PD_DEALLOCATE) + +// UINT64 Id / none +#define WV_IOCTL_PD_CANCEL WV_IOCTL(WV_IO_FUNCTION_BASE + \ + WV_IO_FUNCTION_PD_CANCEL) + +// WV_IO_MEMORY_REGISTER / WV_IO_MEMORY_KEYS +#define WV_IOCTL_MEMORY_REGISTER WV_IOCTL(WV_IO_FUNCTION_BASE + \ + WV_IO_FUNCTION_MEMORY_REGISTER) + +// WV_IO_ID / none +#define WV_IOCTL_MEMORY_DEREGISTER WV_IOCTL(WV_IO_FUNCTION_BASE + \ + WV_IO_FUNCTION_MEMORY_DEREGISTER) + +// WV_IO_ID / WV_IO_ID +#define WV_IOCTL_MW_ALLOCATE WV_IOCTL(WV_IO_FUNCTION_BASE + \ + WV_IO_FUNCTION_MW_ALLOCATE) + +// UINT64 Id / none +#define WV_IOCTL_MW_DEALLOCATE WV_IOCTL(WV_IO_FUNCTION_BASE + \ + WV_IO_FUNCTION_MW_DEALLOCATE) + +// WV_IO_AH_CREATE / WV_IO_AH_CREATE +#define WV_IOCTL_AH_CREATE WV_IOCTL(WV_IO_FUNCTION_BASE + \ + WV_IO_FUNCTION_AH_CREATE) + +// UINT64 Id / none +#define WV_IOCTL_AH_DESTROY WV_IOCTL(WV_IO_FUNCTION_BASE + \ + WV_IO_FUNCTION_AH_DESTROY) + +// WV_IO_ID / WV_IO_ID +#define WV_IOCTL_CQ_CREATE WV_IOCTL(WV_IO_FUNCTION_BASE + \ + WV_IO_FUNCTION_CQ_CREATE) + +// UINT64 Id / none +#define WV_IOCTL_CQ_DESTROY WV_IOCTL(WV_IO_FUNCTION_BASE + \ + WV_IO_FUNCTION_CQ_DESTROY) + +// WV_IO_ID / WV_IO_ID +#define WV_IOCTL_CQ_RESIZE WV_IOCTL(WV_IO_FUNCTION_BASE + \ + WV_IO_FUNCTION_CQ_RESIZE) + +// WV_IO_ID / none +#define WV_IOCTL_CQ_NOTIFY WV_IOCTL(WV_IO_FUNCTION_BASE + \ + WV_IO_FUNCTION_CQ_NOTIFY) + +// UINT64 Id / none +#define WV_IOCTL_CQ_CANCEL WV_IOCTL(WV_IO_FUNCTION_BASE + \ + WV_IO_FUNCTION_CQ_CANCEL) + +// WV_IO_SRQ_ATTRIBUTES / WV_IO_SRQ_ATTRIBUTES +#define WV_IOCTL_SRQ_CREATE WV_IOCTL(WV_IO_FUNCTION_BASE + \ + WV_IO_FUNCTION_SRQ_CREATE) + +// UINT64 Id / none +#define WV_IOCTL_SRQ_DESTROY WV_IOCTL(WV_IO_FUNCTION_BASE + \ + WV_IO_FUNCTION_SRQ_DESTROY) + +// WV_IO_SRQ_ATTRIBUTES / WV_IO_SRQ_ATTRIBUTES +#define WV_IOCTL_SRQ_QUERY WV_IOCTL(WV_IO_FUNCTION_BASE + \ + WV_IO_FUNCTION_SRQ_QUERY) + +// WV_IO_SRQ_ATTRIBUTES / WV_IO_SRQ_ATTRIBUTES +#define WV_IOCTL_SRQ_MODIFY WV_IOCTL(WV_IO_FUNCTION_BASE + \ + WV_IO_FUNCTION_SRQ_MODIFY) + +// UINT64 Id / none +#define WV_IOCTL_SRQ_NOTIFY WV_IOCTL(WV_IO_FUNCTION_BASE + \ + WV_IO_FUNCTION_SRQ_NOTIFY) + +// UINT64 Id / none +#define WV_IOCTL_SRQ_CANCEL WV_IOCTL(WV_IO_FUNCTION_BASE + \ + WV_IO_FUNCTION_SRQ_CANCEL) + +// WV_IO_QP_CREATE / WV_IO_QP_CREATE +#define WV_IOCTL_QP_CREATE WV_IOCTL(WV_IO_FUNCTION_BASE + \ + WV_IO_FUNCTION_QP_CREATE) + +// UINT64 Id / none +#define WV_IOCTL_QP_DESTROY WV_IOCTL(WV_IO_FUNCTION_BASE + \ + WV_IO_FUNCTION_QP_DESTROY) + +// WV_IO_ID / WV_IO_QP_ATTRIBUTES +#define WV_IOCTL_QP_QUERY WV_IOCTL(WV_IO_FUNCTION_BASE + \ + WV_IO_FUNCTION_QP_QUERY) + +// WV_IO_QP_ATTRIBUTES / verbs specific +#define WV_IOCTL_QP_MODIFY WV_IOCTL(WV_IO_FUNCTION_BASE + \ + WV_IO_FUNCTION_QP_MODIFY) + +// WV_IO_QP_MULTICAST / none +#define WV_IOCTL_QP_ATTACH WV_IOCTL(WV_IO_FUNCTION_BASE + \ + WV_IO_FUNCTION_QP_ATTACH) + +// WV_IO_QP_MULTICAST / none +#define WV_IOCTL_QP_DETACH WV_IOCTL(WV_IO_FUNCTION_BASE + \ + WV_IO_FUNCTION_QP_DETACH) + +// UINT64 Id / none +#define WV_IOCTL_QP_CANCEL WV_IOCTL(WV_IO_FUNCTION_BASE + \ + WV_IO_FUNCTION_QP_CANCEL) + +// UINT64 EpType / UINT64 Id +#define WV_IOCTL_EP_CREATE WV_IOCTL(WV_IO_FUNCTION_BASE + \ + WV_IO_FUNCTION_EP_CREATE) + +// UINT64 Id / none +#define WV_IOCTL_EP_DESTROY WV_IOCTL(WV_IO_FUNCTION_BASE + \ + WV_IO_FUNCTION_EP_DESTROY) + +// WV_IO_ID + UINT8[] / none +#define WV_IOCTL_EP_MODIFY WV_IOCTL(WV_IO_FUNCTION_BASE + \ + WV_IO_FUNCTION_EP_MODIFY) + +// WV_IO_EP_BIND / WV_IO_EP_BIND +#define WV_IOCTL_EP_BIND WV_IOCTL(WV_IO_FUNCTION_BASE + \ + WV_IO_FUNCTION_EP_BIND) + +// WV_IO_ID + UINT8[] / none +#define WV_IOCTL_EP_REJECT WV_IOCTL(WV_IO_FUNCTION_BASE + \ + WV_IO_FUNCTION_EP_REJECT) + +// WV_IO_EP_CONNECT / none +#define WV_IOCTL_EP_CONNECT WV_IOCTL(WV_IO_FUNCTION_BASE + \ + WV_IO_FUNCTION_EP_CONNECT) + +// WV_IO_EP_ACCEPT / verbs specific +#define WV_IOCTL_EP_ACCEPT WV_IOCTL(WV_IO_FUNCTION_BASE + \ + WV_IO_FUNCTION_EP_ACCEPT) + +// WV_IO_EP_DISCONNECT/ verbs specific +#define WV_IOCTL_EP_DISCONNECT WV_IOCTL(WV_IO_FUNCTION_BASE + \ + WV_IO_FUNCTION_EP_DISCONNECT) + +// UINT64 Id / none +#define WV_IOCTL_EP_DISCONNECT_NOTIFY WV_IOCTL(WV_IO_FUNCTION_BASE + \ + WV_IO_FUNCTION_EP_DISCONNECT_NOTIFY) + +// UINT64 Id / WV_IO_EP_ATTRIBUTES +#define WV_IOCTL_EP_QUERY WV_IOCTL(WV_IO_FUNCTION_BASE + \ + WV_IO_FUNCTION_EP_QUERY) + +// TODO +#define WV_IOCTL_EP_LOOKUP WV_IOCTL(WV_IO_FUNCTION_BASE + \ + WV_IO_FUNCTION_EP_LOOKUP) + +// TODO +#define WV_IOCTL_EP_MULTICAST_JOIN WV_IOCTL(WV_IO_FUNCTION_BASE + \ + WV_IO_FUNCTION_EP_MULTICAST_JOIN) + +// TODO +#define WV_IOCTL_EP_MULTICAST_LEAVE WV_IOCTL(WV_IO_FUNCTION_BASE + \ + WV_IO_FUNCTION_EP_MULTICAST_LEAVE) + +// UINT64 Id / none +#define WV_IOCTL_EP_CANCEL WV_IOCTL(WV_IO_FUNCTION_BASE + \ + WV_IO_FUNCTION_EP_CANCEL) + +// WV_IO_EP_LISTEN / none +#define WV_IOCTL_EP_LISTEN WV_IOCTL(WV_IO_FUNCTION_BASE + \ + WV_IO_FUNCTION_EP_LISTEN) + +// WV_IO_EP_GET_REQUEST / none +#define WV_IOCTL_EP_GET_REQUEST WV_IOCTL(WV_IO_FUNCTION_BASE + \ + WV_IO_FUNCTION_EP_GET_REQUEST) + +#define WV_IOCTL_MIN WV_IO_FUNCTION_BASE + WV_IO_FUNCTION_MIN +#define WV_IOCTL_MAX WV_IO_FUNCTION_BASE + WV_IO_FUNCTION_MAX + +// Device specific data follows input / output structures. +typedef struct _WV_IO_ID +{ + UINT64 Id; + UINT32 VerbInfo; + UINT32 Data; + +} WV_IO_ID; + +typedef struct _WV_IO_GUID_LIST +{ + UINT64 Count; + NET64 Guid[1]; + +} WV_IO_GUID_LIST; + +#define WV_MAX_LIB_NAME 32 + +// Device/port capability flags +#define WV_IO_RESIZE_MAX_WR 0x00000001 +#define WV_IO_BAD_PKEY_COUNTER 0x00000002 +#define WV_IO_BAD_QKEY_COUNTER 0x00000004 +// reserved 0x00000008 +#define WV_IO_PATH_MIGRATION 0x00000010 +#define WV_IO_CHANGE_PHYSICAL_PORT 0x00000020 +#define WV_IO_AH_PORT_CHECKING 0x00000040 +#define WV_IO_QP_STATE_MODIFIER 0x00000080 +#define WV_IO_SHUTDOWN_PORT 0x00000100 +#define WV_IO_INIT_TYPE 0x00000200 +#define WV_IO_PORT_ACTIVE_EVENT 0x00000400 +#define WV_IO_SYSTEM_IMAGE_GUID 0x00000800 +#define WV_IO_RC_RNR_NAK_GENERATION 0x00001000 +#define WV_IO_SRQ_RESIZE 0x00002000 +#define WV_IO_BATCH_NOTIFY_CQ 0x00004000 + +#define WV_DEVICE_UNKNOWN 0 +#define WV_DEVICE_INFINIBAND 1 +#define WV_DEVICE_IWARP 2 + +#define WV_IO_ATOMIC_NONE 0 +#define WV_IO_ATOMIC_HCA 1 +#define WV_IO_ATOMIC_NODE 2 + +typedef struct _WV_IO_DEVICE_ATTRIBUTES +{ + UINT64 FwVersion; + NET64 NodeGuid; + NET64 SystemImageGuid; + UINT32 VendorId; + UINT32 VendorPartId; + UINT32 HwVersion; + UINT32 CapabilityFlags; + UINT32 AtomicCapability; + UINT32 PageSizeCapabilityFlags; + UINT64 MaxMrSize; + UINT32 MaxQp; + UINT32 MaxQpWr; + UINT32 MaxSge; + UINT32 MaxCq; + UINT32 MaxCqEntries; + UINT32 MaxMr; + UINT32 MaxPd; + UINT32 MaxQpResponderResources; + UINT32 MaxResponderResources; + UINT32 MaxQpInitiatorDepth; + UINT32 MaxInlineSend; + UINT32 MaxMw; + UINT32 MaxMulticast; + UINT32 MaxQpAttach; + UINT32 MaxMulticastQp; + UINT32 MaxAh; + UINT32 MaxFmr; + UINT32 MaxMapPerFmr; + UINT32 MaxSrq; + UINT32 MaxSrqWr; + UINT32 MaxSrqSge; + UINT32 MaxPkeys; + UINT32 DeviceType; + UINT8 LocalAckDelay; + UINT8 PhysPortCount; + UINT8 Reserved[2]; + +} WV_IO_DEVICE_ATTRIBUTES; + +typedef struct _WV_IO_DEVICE_PORT_QUERY +{ + UINT64 Id; + UINT8 PortNumber; + UINT8 Reserved[7]; + +} WV_IO_DEVICE_PORT_QUERY; + +#define WV_IO_PORT_NOP 0 +#define WV_IO_PORT_DOWN 1 +#define WV_IO_PORT_INIT 2 +#define WV_IO_PORT_ARMED 3 +#define WV_IO_PORT_ACTIVE 4 +#define WV_IO_PORT_ACTIVEDEFER 5 + +typedef struct _WV_IO_PORT_ATTRIBUTES +{ + UINT32 PortCabilityFlags; + UINT32 State; + UINT32 MaxMtu; + UINT32 ActiveMtu; + UINT32 GidTableLength; + UINT32 MaxMessageSize; + UINT32 BadPkeyCounter; + UINT32 QkeyViolationCounter; + UINT16 PkeyTableLength; + NET16 Lid; + NET16 SmLid; + UINT8 Lmc; + UINT8 MaxVls; + UINT8 SmSl; + UINT8 SubnetTimeout; + UINT8 InitTypeReply; + UINT8 ActiveWidth; + UINT8 ActiveSpeed; + UINT8 PhysicalState; + UINT8 Reserved[2]; + +} WV_IO_PORT_ATTRIBUTES; + +// Port notification flags +#define WV_IO_EVENT_ERROR 0x00000001 +#define WV_IO_EVENT_STATE 0x00000002 +#define WV_IO_EVENT_ADDRESS 0x00000004 +#define WV_IO_EVENT_LINK_ADDRESS 0x00000008 +#define WV_IO_EVENT_PARTITION 0x00000010 +#define WV_IO_EVENT_MANAGEMENT 0x00000020 + +typedef struct _WV_IO_GID +{ + UINT8 Raw[16]; + +} WV_IO_GID; + +typedef struct _WV_IO_EVENT +{ + UINT32 Status; + UINT32 Type; + UINT8 PortNumber; + UINT8 Reserved[3]; + +} WV_IO_EVENT; + +typedef struct _WV_IO_MEMORY_REGISTER +{ + UINT64 Id; + UINT64 Address; + UINT64 BufferLength; + UINT32 AccessFlags; + UINT32 Reserved; + +} WV_IO_MEMORY_REGISTER; + +typedef struct _WV_IO_MEMORY_KEYS +{ + UINT32 Lkey; + NET32 Rkey; + +} WV_IO_MEMORY_KEYS; + +typedef struct _WV_IO_AV +{ + UINT8 NetworkRouteValid; + UINT8 Reserved1; + UINT8 HopLimit; + UINT8 TrafficClass; + NET32 FlowLabel; + UINT8 SGid[16]; + UINT8 DGid[16]; + + UINT16 Reserved2; + NET16 DLid; + UINT8 ServiceLevel; + UINT8 SourcePathBits; + UINT8 StaticRate; + UINT8 PortNumber; + +} WV_IO_AV; + +typedef struct _WV_IO_AH_CREATE +{ + WV_IO_ID Id; + WV_IO_AV AddressVector; + +} WV_IO_AH_CREATE; + +#define WV_CQ_ERROR 0 +#define WV_CQ_NEXT_COMPLETION 1 +#define WV_CQ_SOLICITED 2 + +typedef struct _WV_IO_SRQ_ATTRIBUTES +{ + WV_IO_ID Id; + UINT32 MaxWr; + UINT32 MaxSge; + UINT32 SrqLimit; + UINT32 Reserved; + +} WV_IO_SRQ_ATTRIBUTES; + +#define WV_IO_QP_SIGNAL_SENDS 0x00000001 +#define WV_IO_QP_MEMORY_MANAGEMENT 0x00000002 + +typedef struct _WV_IO_QP_CREATE +{ + WV_IO_ID Id; + UINT64 SendCqId; + UINT64 ReceiveCqId; + UINT64 SrqId; + + UINT32 SendDepth; + UINT32 SendSge; + UINT32 ReceiveDepth; + UINT32 ReceiveSge; + UINT32 MaxInlineSend; + UINT32 InitiatorDepth; + UINT32 ResponderResources; + + UINT8 QpType; + UINT8 QpFlags; + UINT16 Reserved; + +} WV_IO_QP_CREATE; + +#define WV_IO_QP_STATE_RESET 0 +#define WV_IO_QP_STATE_INIT 1 +#define WV_IO_QP_STATE_RTR 2 +#define WV_IO_QP_STATE_RTS 3 +#define WV_IO_QP_STATE_SQD 4 +#define WV_IO_QP_STATE_SQERROR 5 +#define WV_IO_QP_STATE_ERROR 6 + +#define WV_IO_QP_ATTR_CAPABILITIES 0x00000001 +#define WV_IO_QP_ATTR_INITIATOR_DEPTH 0x00000002 +#define WV_IO_QP_ATTR_RESPONDER_RESOURCES 0x00000004 +#define WV_IO_QP_ATTR_CURRENT_STATE 0x00000008 +#define WV_IO_QP_ATTR_STATE 0x00000010 +#define WV_IO_QP_ATTR_PATH_MIG_STATE 0x00000020 +#define WV_IO_QP_ATTR_DESTINATION_QPN 0x00000040 +#define WV_IO_QP_ATTR_QKEY 0x00000080 +#define WV_IO_QP_ATTR_SEND_PSN 0x00000100 +#define WV_IO_QP_ATTR_RECEIVE_PSN 0x00000200 +#define WV_IO_QP_ATTR_FLAGS 0x00000400 +#define WV_IO_QP_ATTR_ACCESS_FLAGS 0x00000800 +#define WV_IO_QP_ATTR_AV 0x00001000 +#define WV_IO_QP_ATTR_ALTERNATE_AV 0x00002000 +#define WV_IO_QP_ATTR_PORT_NUMBER 0x00004000 +#define WV_IO_QP_ATTR_PKEY_INDEX 0x00008000 +#define WV_IO_QP_ATTR_ACK_TIMEOUT 0x00010000 +#define WV_IO_QP_ATTR_RNR_NAK_TIMEOUT 0x00020000 +#define WV_IO_QP_ATTR_ERROR_RETRY_COUNT 0x00040000 +#define WV_IO_QP_ATTR_RNR_RETRY_COUNT 0x00080000 + +typedef struct _WV_IO_QP_ATTRIBUTES +{ + WV_IO_ID Id; + UINT32 SendDepth; + UINT32 SendSge; + UINT32 ReceiveDepth; + UINT32 ReceiveSge; + UINT32 MaxInlineSend; + UINT32 InitiatorDepth; + UINT32 ResponderResources; + + UINT32 Options; + UINT8 QpType; + UINT8 CurrentQpState; + UINT8 QpState; + UINT8 ApmState; + NET32 Qpn; + NET32 DestinationQpn; + NET32 Qkey; + NET32 SendPsn; + NET32 ReceivePsn; + + WV_IO_AV AddressVector; + WV_IO_AV AlternateAddressVector; + UINT32 PathMtu; + UINT32 AlternatePathMtu; + UINT16 PkeyIndex; + UINT16 AlternatePkeyIndex; + UINT8 LocalAckTimeout; + UINT8 AlternateLocalAckTimeout; + + UINT8 RnrNakTimeout; + UINT8 SequenceErrorRetryCount; + UINT8 RnrRetryCount; + + UINT8 AccessFlags; + UINT8 QpFlags; + UINT8 Reserved[5]; + +} WV_IO_QP_ATTRIBUTES; + +typedef struct _WV_IO_QP_MULTICAST +{ + WV_IO_ID Id; + WV_IO_GID Gid; + +} WV_IO_QP_MULTICAST; + +// Windows kernel does not define sockaddr* pre-Vista +typedef struct _WV_IO_SOCKADDR +{ + UINT16 SaFamily; + UINT8 SaData[14]; + +} WV_IO_SOCKADDR; + +typedef struct _WV_IO_SOCKADDR_IN +{ + UINT16 SinFamily; + UINT16 SinPort; + UINT32 SinAddr; + UINT8 SinZero[8]; + +} WV_IO_SOCKADDR_IN; + +typedef struct _WV_IO_SOCKADDR_IN6 +{ + UINT16 Sin6Family; + UINT16 Sin6Port; + UINT32 Sin6FlowInfo; + UINT8 Sin6Addr[16]; + UINT32 Sin6ScopeId; + +} WV_IO_SOCKADDR_IN6; + +typedef struct _WV_IO_SOCKADDR_DATA +{ + union + { + WV_IO_SOCKADDR Sa; + WV_IO_SOCKADDR_IN In; + WV_IO_SOCKADDR_IN6 In6; + + } SockAddr; + + UINT32 Reserved; + +} WV_IO_SOCKADDR_DATA; + +typedef struct _WV_IO_DEVICE_ADDRESS +{ + NET64 DeviceGuid; + NET16 Pkey; + UINT8 PortNumber; + UINT8 Reserved[5]; + +} WV_IO_DEVICE_ADDRESS; + +typedef struct _WV_IO_EP_BIND +{ + UINT64 Id; + WV_IO_SOCKADDR_DATA Address; + WV_IO_DEVICE_ADDRESS Device; + +} WV_IO_EP_BIND; + +#define WV_IO_EP_OPTION_ROUTE 0x00000001 + +#define WV_IO_EP_TYPE_CONNECT 0x0106 +#define WV_IO_EP_TYPE_DATAGRAM 0x0111 + +typedef struct _WV_IO_EP_LISTEN +{ + UINT64 Id; + UINT64 Backlog; + +} WV_IO_EP_LISTEN; + +typedef struct _WV_IO_EP_GET_REQUEST +{ + UINT64 Id; + UINT64 EpId; + +} WV_IO_EP_GET_REQUEST; + +typedef struct _WV_IO_CONNECT_PARAM +{ + UINT64 ResponderResources; + UINT64 InitiatorDepth; + UINT8 RetryCount; + UINT8 RnrRetryCount; + UINT8 DataLength; + UINT8 Reserved[5]; + UINT8 Data[56]; + +} WV_IO_CONNECT_PARAM; + +typedef struct _WV_IO_EP_CONNECT +{ + UINT64 Id; + UINT64 QpId; + WV_IO_SOCKADDR_DATA PeerAddress; + WV_IO_CONNECT_PARAM Param; + +} WV_IO_EP_CONNECT; + +typedef struct _WV_IO_EP_ACCEPT +{ + UINT64 Id; + UINT64 QpId; + WV_IO_CONNECT_PARAM Param; + +} WV_IO_EP_ACCEPT; + +typedef struct _WV_IO_EP_ATTRIBUTES +{ + WV_IO_SOCKADDR_DATA LocalAddress; + WV_IO_SOCKADDR_DATA PeerAddress; + WV_IO_DEVICE_ADDRESS Device; + + union { + WV_IO_CONNECT_PARAM Connect; + UINT64 Backlog; + + } Param; + + +} WV_IO_EP_ATTRIBUTES; + +typedef struct _WV_IO_EP_DISCONNECT +{ + UINT64 Id; + UINT64 QpId; + +} WV_IO_EP_DISCONNECT; + +#endif // _WV_IOCTL_H_ diff --git a/branches/WOF2-3/core/winverbs/wv_public.h b/branches/WOF2-3/core/winverbs/wv_public.h new file mode 100644 index 00000000..df0f3b92 --- /dev/null +++ b/branches/WOF2-3/core/winverbs/wv_public.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +// {B3BB7735-327D-4290-AFA1-F40FAC060F97} +DEFINE_GUID(GUID_DEVINTERFACE_WINVERBS, 0xb3bb7735, 0x327d, 0x4290, + 0xaf, 0xa1, 0xf4, 0xf, 0xac, 0x6, 0xf, 0x97); diff --git a/branches/WOF2-3/dirs b/branches/WOF2-3/dirs new file mode 100644 index 00000000..23326682 --- /dev/null +++ b/branches/WOF2-3/dirs @@ -0,0 +1,6 @@ +DIRS=\ + core \ + ulp \ + hw \ + tools \ + tests diff --git a/branches/WOF2-3/docs/Manual.htm b/branches/WOF2-3/docs/Manual.htm new file mode 100644 index 00000000..45feec18 --- /dev/null +++ b/branches/WOF2-3/docs/Manual.htm @@ -0,0 +1,8644 @@ + + + + + + +

OpenFabrics Enterprise Distribution (for Windows)

+

User's Manual

+

Release 2.3

+

+06/18/2010

+

Overview

+

+The OpenFabrics Enterprise Distribution for Windows package is composed of software modules intended +for use on Microsoft Windows based computer systems connected via an InfiniBand +fabric.

+

The OpenFabrics +Enterprise Distribution for Windows software package contains the +following:
+
+OpenFabrics Infiniband core drivers and Upper Level Protocols (ULPs):

+
    +
  • +

    HCA (Host Channel Adapter) driver

  • +
  • +

    MTHCA - + Mellanox + InfiniHost low level driver. See + Release_notes.htm for a list of supported devices.

  • +
  • +

    + MLX4    - Mellanox + ConnectX low level driver. +

  • +
  • +

    Infiniband Core modules: IB verbs and IB access layer

  • +
  • +

    Upper Layer Protocols: IPoIB, WSD, NetworkDirect, VNIC, SRP Initiator and uDAPL

  • +
+

OpenFabrics Tools:

+
    +
  • +

    OpenSM: InfiniBand Subnet Manager

  • +
  • +

    Performance tests

  • +
  • +

    Diagnostic tools

  • +
+

Documentation

+
    +
  • +

    User's manual

  • +
  • +

    Release Notes

  • +
+

 

+

OFED Features

+ + +

 

+

 

+

 

+
+

Tools

+
+
+
+

The OpenFabrics Alliance Enterprise for Windows release contains a set of + user mode tools which are designed to faciliate the smooth operation of an OpenFabrics + Enterprise Distribution installation. These tools are available from a command + window (cmd.exe) as the installation path '%SystemDrive%\Program + Files\OFED' is appended to the system wide search path registry entry. + A start menu short-cut 'OFED Cmd Window' is provided to faciliate + correction tool operation.

+

IPoIB Partition Management

+
    +
  • +

    part_man      + Manage (add/remove/show) IPoIB partitions.

  • +
+

Infiniband Subnet Management

+
    +
  • +

    opensm         Open Subnet + Management - configure and manage an InfiniBand subnet

  • +
  • +

    osmtest         Subnet management tests

  • +
  • +

    ib_trapgen     Generate Infiniband Subnet + Management Traps for testing purposes

  • +
+

QLogic VNIC Child Device Management

+
    +
  • +

    qlgcvnic_config         Configuration + utility used to configure IB Stack to create VNIC child devices as per user's requirement.

  • +
+

Performance

+
    +
  • +

    ib_send_lat     Infiniband send +latency measurement

  • +
  • +

    ib_send_bw    Infiniband send bandwidth + measurement

  • +
  • +

    ib_write_lat     Infiniband RDMA write +latency measurement

  • +
  • +

    ib_write_bw    Infiniband RDMA write bandwidth +measurement

  • +
  • +

    ttcp                 +TCP performance measurements

  • +
+

Diagnostics

+
    +
  • +

    cmtest           Connection Manager tests

  • +
  • +

    ib_limits         + InfiniBand verb tests

  • +
  • +

    printIP          Display +an Internet Protocol address associated with an IB GUID.

  • +
  • +

    vstat              Display HCA attributes (lids), statistics and error counters.

  • +
  • +

    ibaddr              + Query InfiniBand address(es)

  • +
  • +

    iblinkinfo           + Report link info for all links in the fabric

  • +
  • +

    ibnetdiscover    Generate a fabric + topology.

  • +
  • +

    ibping               + Ping an InfiniBand address

  • +
  • +

    ibportstate        + Display InfiniBand port specific information.

  • +
  • +

    ibqueryerrors    Query and report + non-zero IB port counters

  • +
  • +

    ibroute             + Query InfiniBand switch forwarding tables

  • +
  • +

    ibstat                Display HCA stats.

  • +
  • +

    ibsysstat            + System status for an InfiniBand address

  • +
  • +

    ibtracert            + Trace InfiniBand path

  • +
  • +

    ibv_devinfo       + Display HCA device information.

  • +
  • +

    perfquery          + Query InfiniBand performance counters

  • +
  • +

    saquery             SA (Subnet Administrator) query test

  • +
  • +

    sminfo               + Query InfiniBand SMInfo attributes

  • +
  • +

    smpdump          + Dump InfiniBand subnet management attributes

  • +
  • +

    smpquery          + Query InfiniBand subnet management attributes

  • +
  • +

    vendstat            Query InfiniBand vendor specific functions

  • +
+
+
+

<return-to-top>

+

 

+

User mode micro-benchmarks

+
+

The following user-mode test programs are intended as useful +micro-benchmarks for HW or SW +tuning and/or functional testing.

+
+

Tests use CPU cycle counters to get time stamps without + context switch.
+
Tests measure round-trip time but report half of that as one-way latency
+ (i.e.. May not be sufficiently accurate for + asymmetrical configurations).
+
Min/Median/Max result is reported.
The median (vs. average) is less sensitive to extreme scores.
Typically the "Max" value is the first value measured.
+
larger samples only marginally help. The default (1000) is pretty good.
Note that an array of cycles_t (typically unsigned long) is allocated
once to collect samples and again to store the difference between them.
Really big sample sizes (e.g. 1 million) might expose other problems
with the program.
+
"-H" option will dump the histogram for additional statistical analysis.
See xgraph, ygraph, r-base (http://www.r-project.org/), pspp, or other +
statistical math programs.

Architectures tested: x86, x86_64, ia64

+

Also see winverbs performance tools.

+
+


+ib_send_lat.exe      - latency test with +send transactions

+
+

Usage:

+
+

ib_send_lat start a server and wait for connection
+ ib_send_lat <host> connect to server at <host>

+
+

Options:

+
+

-p, --port=<port> listen on/connect to port <port> + (default 18515)
+ -c, --connection=<RC/UC> connection type RC/UC (default RC)
+ -m, --mtu=<mtu> mtu size (default 2048)
+ -d, --ib-dev=<dev> use IB device <dev> (default first device found)
+ -i, --ib-port=<port> use port <port> of IB device (default 1)
+ -s, --size=<size> size of message to exchange (default 1)
+ -t, --tx-depth=<dep> size of tx queue (default 50)
+ -l, --signal signal completion on each msg
+ -a, --all Run sizes from 2 till 2^23
+ -n, --iters=<iters> number of exchanges (at least 2, default 1000)
+ -C, --report-cycles report times in cpu cycle units (default + microseconds)
+ -H, --report-histogram print out all results (default print summary + only)
+ -U, --report-unsorted (implies -H) print out unsorted results (default + sorted)
+ -V, --version display version number
+ -e, --events sleep on CQ events (default poll)

+
+
+


+ib_send_bw.exe     - BW (BandWidth) test with send transactions

+
+

Usage:

+
+

ib_send_bw start a server and wait for connection
+ ib_send_bw <host> connect to server at <host>

+
+

Options:

+
+

-p, --port=<port> listen on/connect to port <port> + (default 18515)
+ -d, --ib-dev=<dev> use IB device <dev> (default first device found)
+ -i, --ib-port=<port> use port <port> of IB device (default 1)
+ -c, --connection=<RC/UC> connection type RC/UC/UD (default RC)
+ -m, --mtu=<mtu> mtu size (default 1024)
+ -s, --size=<size> size of message to exchange (default 65536)
+ -a, --all Run sizes from 2 till 2^23
+ -t, --tx-depth=<dep> size of tx queue (default 300)
+ -n, --iters=<iters> number of exchanges (at least 2, default 1000)
+ -b, --bidirectional measure bidirectional bandwidth (default + unidirectional)
+ -V, --version display version number
+ -e, --events sleep on CQ events (default poll)

+
+
+


+ib_write_lat.exe      - latency test with RDMA write +transactions

+
+

Usage:

+
+

ib_write_lat start a server and wait for connection
+ ib_write_lat <host> connect to server at <host>

+
+

Options:

+
+

-p, --port=<port> listen on/connect to port <port> + (default 18515)
+ -c, --connection=<RC/UC> connection type RC/UC (default RC)
+ -m, --mtu=<mtu> mtu size (default 1024)
+ -d, --ib-dev=<dev> use IB device <dev> (default first device found)
+ -i, --ib-port=<port> use port <port> of IB device (default 1)
+ -s, --size=<size> size of message to exchange (default 1)
+ -a, --all Run sizes from 2 till 2^23
+ -t, --tx-depth=<dep> size of tx queue (default 50)
+ -n, --iters=<iters> number of exchanges (at least 2, default 1000)
+ -C, --report-cycles report times in cpu cycle units (default + microseconds)
+ -H, --report-histogram print out all results (default print summary + only)
+ -U, --report-unsorted (implies -H) print out unsorted results (default + sorted)
+ -V, --version display version number

+
+
+


+ib_write_bw.exe     - BW test with RDMA write transactions

+
+

Usage:

+
+

ib_write_bw                + # start a server and wait for connection
+ ib_write_bw <host>    # connect to server at <host>

+
+

Options:

+
+

-p, --port=<port> listen on/connect to port <port> + (default 18515)
+ -d, --ib-dev=<dev> use IB device <dev> (default first device found)
+ -i, --ib-port=<port> use port <port> of IB device (default 1)
+ -c, --connection=<RC/UC> connection type RC/UC (default RC)
+ -m, --mtu=<mtu> mtu size (default 1024)
+ -g, --post=<num of posts> number of posts for each qp in the chain + (default tx_depth)
+ -q, --qp=<num of qp's> Num of qp's(default 1)
+ -s, --size=<size> size of message to exchange (default 65536)
+ -a, --all Run sizes from 2 till 2^23
+ -t, --tx-depth=<dep> size of tx queue (default 100)
+ -n, --iters=<iters> number of exchanges (at least 2, default 5000)
+ -b, --bidirectional measure bidirectional bandwidth (default + unidirectional)
+ -V, --version display version number

+
+
+

<return-to-top>

+


+


+ttcp - Test TCP performance

+

TTCP accesses the Windows socket layer, hence it does not access +IB verbs directly. IPoIB or WSD layers are invoked beneath the socket layer +depending on configuration. TTCP is included as a quick baseline performance +check.

+
+
Usage: ttcp -t [-options] host 
+       ttcp -r [-options]
+Common options:
+	-l ##	length of bufs read from or written to network (default 8192)
+	-u	use UDP instead of TCP
+	-p ##	port number to send to or listen at (default 5001)
+	-A	align the start of buffers to this modulus (default 16384)
+	-O	start buffers at this offset from the modulus (default 0)
+	-d	set SO_DEBUG socket option
+	-b ##	set socket buffer size (if supported)
+	-f X	format for rate: k,K = kilo{bit,byte}; m,M = mega; g,G = giga
+Options specific to -t:
+	-n##	number of source bufs written to network (default 2048)
+	-D	don't buffer TCP writes (sets TCP_NODELAY socket option)
+Options specific to -r:
+	-B	for -s, only output full blocks as specified by -l (for TAR)
+	-T	"touch": access each byte as it's read
+

Requires a receiver (server) side and a transmitter (client) + side, host1 and host2 are IPoIB connected hosts.

+

at host1 (receiver)        + ttcp -r -f M -l 4096

+

at host2 (transmitter)    ttcp -t -f M -l + 4096 -n1000 host1

+
+

<return-to-top>

+

 

+

 

+

Diagnostics

+
+
+

IBADDR(8) OFED Diagnostics

+

NAME
+ibaddr - query InfiniBand address(es)
+
+SYNOPSIS
+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>]
+
+DESCRIPTION
+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.
+
+Note: this utility can be used as simple address resolver.
+
+OPTIONS
+-G, --Guid
+show lid range and gid for GUID address
+
+-l, --lid_show
+show lid range only
+
+-L, --Lid_show
+show lid range (in decimal) only
+
+-g, --gid_show
+show gid address only
+
+
+COMMON OPTIONS
+Most OFED 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
+
+-d raise the IB debugging level.
+May be used several times (-ddd or -d -d -d).
+
+-e show send and 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 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 argument. In most cases, it is the Port GUID.
+Example:
+"0x08f1040023"
+
+-s <smlid> use Â’smlidÂ’ as the target lid for SM/SA queries.
+
+# Other common flags:
+
+-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.
+
+Multiple CA/Multiple Port Support
+
+When no IB device or port is specified, the port to use is selected 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 user request is attempted to
+be fulfilled, and will fail if it is not possible.
+
+
+EXAMPLES
+ibaddr # local port´s address
+
+ibaddr 32 # show lid range and gid of lid 32
+
+ibaddr -G 0x8f1040023 # same but using guid address
+
+ibaddr -l 32 # show lid range only
+
+ibaddr -L 32 # show decimal lid range only
+
+ibaddr -g 32 # show gid address only
+
+
+SEE ALSO
+ibroute(8), ibtracert(8)
+
+AUTHOR
+Hal Rosenstock
+<halr@voltaire.com>
+
+
+OFED June 18, 2007 IBADDR(8)

+

 

+

IBLINKINFO(8) OFED Diagnostics

+

NAME
+iblinkinfo - report link info for all links in the fabric
+
+
+SYNOPSIS
+iblinkinfo +[-Rhcdl -C <ca_name> -P <ca_port> -v <lt,hoq,vlstall> -S <guid> -D<direct_route>]
+
+
+DESCRIPTION
+iblinkinfo reports the link info for each port of each switch active
+in the IB fabric.
+
+
+OPTIONS
+-R 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.
+
+-S <guid>
+Output only the switch specified by <guid> (hex format)
+
+-D <direct_route>
+Output only the switch specified by the direct route path.
+
+-l 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).
+
+-d Print only switches which have a port in the "Down" state.
+
+-v <lt,hoq,vlstall>
+Verify additional switch settings (<Life-
+Time>,<HoqLife>,<VLStallCount>)
+
+-c Print port capabilities (enabled and supported values)
+
+-C <ca_name> use the specified ca_name for the search.
+
+-P <ca_port> use the specified ca_port for the search.
+
+
+
+AUTHOR
+Ira Weiny <weiny2@llnl.gov>
+
+
+OFED Jan 24, 2008 IBLINKINFO(8)

+

<return-to-top>

+

 

+

IBNETDISCOVER(8) OFED Diagnostics

+

NAME
+ibnetdiscover - discover InfiniBand topology
+
+SYNOPSIS
+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>]
+
+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 dis-
+played (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.
+
+OPTIONS
+-l, --list
+List of connected nodes
+
+-g, --grouping
+Show grouping. Grouping correlates IB nodes by different vendor
+specific schemes. It may also show the switch external ports
+correspondence.
+
+-H, --Hca_list
+List of connected CAs
+
+-S, --Switch_list
+List of connected switches
+
+-R, --Router_list
+List of connected routers
+
+-s, --show
+Show progress information during discovery.
+
+--node-name-map <node-name-map>
+Specify a node name map. The node name map file maps GUIDs to
+more user friendly names. See file format below.
+
+-p, --ports
+Obtain a ports report which is a list of connected ports with
+relevant information (like LID, portnum, GUID, width, speed, and
+NodeDescription).
+
+
+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
+
+-d raise the IB debugging level.
+May be used several times (-ddd or -d -d -d).
+
+-e show send and 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 version info.
+
+# Other common flags:
+
+-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.
+
+Multiple CA/Multiple Port Support
+
+When no IB device or port is specified, the port to use is selected 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 user request is attempted to
+be fulfilled, and will fail if it is not possible.
+
+
+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 num-
+ber 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 NodeDescrip-
+tion 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:
+#
+# 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
+
+When grouping is used, IB nodes are organized into chasses which are
+numbered. Nodes which cannot be determined to be in a chassis are dis-
+played as "Non-Chassis Nodes". External ports are also shown on the
+connectivity lines.
+
+
+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.
+
+Generically:
+
+# comment
+0x<guid> "<name>"
+
+Example:
+
+# IB1
+# Line cards
+0x0008f104003f125c "IB1 (Rack 11 slot 1 ) ISR9288/ISR9096 +Voltaire sLB-24D"
+0x0008f104003f125d "IB1 (Rack 11 slot 1 ) ISR9288/ISR9096 +Voltaire sLB-24D"
+0x0008f104003f10d2 "IB1 (Rack 11 slot 2 ) ISR9288/ISR9096 +Voltaire sLB-24D"
+0x0008f104003f10d3 "IB1 (Rack 11 slot 2 ) ISR9288/ISR9096 +Voltaire sLB-24D"
+0x0008f104003f10bf "IB1 (Rack 11 slot 12 ) ISR9288/ISR9096 +Voltaire sLB-24D"
+# Spines
+0x0008f10400400e2d "IB1 (Rack 11 spine 1 ) ISR9288 Voltaire +sFB-12D"
+0x0008f10400400e2e "IB1 (Rack 11 spine 1 ) ISR9288 Voltaire +sFB-12D"
+0x0008f10400400e2f "IB1 (Rack 11 spine 1 ) ISR9288 Voltaire +sFB-12D"
+0x0008f10400400e31 "IB1 (Rack 11 spine 2 ) ISR9288 Voltaire +sFB-12D"
+0x0008f10400400e32 "IB1 (Rack 11 spine 2 ) ISR9288 Voltaire +sFB-12D"
+# GUID Node Name
+0x0008f10400411a08 "SW1 (Rack 3) ISR9024 Voltaire 9024D"
+0x0008f10400411a28 "SW2 (Rack 3) ISR9024 Voltaire 9024D"
+0x0008f10400411a34 "SW3 (Rack 3) ISR9024 Voltaire 9024D"
+0x0008f104004119d0 "SW4 (Rack 3) ISR9024 Voltaire 9024D"
+
+
+AUTHORS
+Hal Rosenstock    <halr@voltaire.com>
+Ira Weiny    <weiny2@llnl.gov>
+
+
+OFED January 3, 2008 IBNETDISCOVER(8)
+
+<return-to-top>

+

 

+

IBPING(8) OFED Diagnostics

+

NAME
+ibping - ping an InfiniBand address
+
+
+SYNOPSIS
+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>
+
+
+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.
+
+
+OPTIONS
+-c stop after count packets
+
+-f, --flood
+flood destination: send packets back to back without delay
+
+-o, --oui
+use specified OUI number to multiplex vendor mads
+
+-S, --Server
+start in server mode (do not return)
+
+
+COMMON OPTIONS
+Most OFED 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
+
+-d raise the IB debugging level.
+May be used several times (-ddd or -d -d -d).
+
+-e show send and 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 version info.
+
+# Addressing flags
+
+-G use GUID address argument. In most cases, it is the Port GUID.
+Example:
+"0x08f1040023"
+
+-s <smlid> use Â’smlidÂ’ as the target lid for SM/SA queries.
+
+# Other common flags:
+
+-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.
+
+Multiple CA/Multiple Port Support
+
+When no IB device or port is specified, the port to use is selected 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 user request is attempted to
+be fulfilled, and will fail if it is not possible.
+
+
+AUTHOR
+Hal Rosenstock <halr@voltaire.com>
+
+
+OFED August 11, 2006 IBPING(8)

+


+<return-to-top>

+

 

+

IBPORTSTATE(8) OFED Diagnostics

+


+NAME
+ibportstate - handle port (physical) state and link speed of an Infini-
+Band port
+
+
+SYNOPSIS
+ibportstate [-d(ebug)] [-e(rr_show)] [-v(erbose)] [-D(irect)] [-G(uid)] [-s +smlid] [-V(ersion)] [-C ca_name] [-P ca_port] [-t(imeout) time-out_ms] [-h(elp)] +<dest dr_path|lid|guid> <portnum> [<op>]
+
+
+DESCRIPTION
+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 rel-
+ative 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.
+
+
+OPTIONS
+op Port operations allowed
+supported ops: enable, disable, reset, speed, query
+Default is query
+
+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.
+
+
+COMMON OPTIONS
+Most OFED 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
+
+-d raise the IB debugging level.
+May be used several times (-ddd or -d -d -d).
+
+-e show send and 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 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 argument. In most cases, it is the Port GUID.
+Example:
+"0x08f1040023"
+
+-s <smlid> use Â’smlidÂ’ as the target lid for SM/SA queries.
+
+# Other common flags:
+
+-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.
+
+Multiple CA/Multiple Port Support
+
+When no IB device or port is specified, the port to use is selected 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 user request is attempted to
+be fulfilled, and will fail if it is not possible.
+
+
+EXAMPLES
+ibportstate 3 1 disable # by lid
+
+ibportstate -G 0x2C9000100D051 1 enable # by guid
+
+ibportstate -D 0 1 # (query) by direct route
+
+ibportstate 3 1 reset # by lid
+
+ibportstate 3 1 speed 1 # by lid
+
+
+AUTHOR
+Hal Rosenstock <halr@voltaire.com>
+
+
+OFED October 19, 2006 IBPORTSTATE(8)

+


+<return-to-top>

+

 

+

IBQUERYERRORS(8) OFED Diagnostics

+

NAME
+ibqueryerrors - query and report non-zero IB port counters
+
+
+SYNOPSIS
+ibqueryerrors [-a -c -r -R -C <ca_name> -P <ca_port> -s
+<err1,err2,...> -S <switch_guid> -D <direct_route> -d]
+
+
+DESCRIPTION
+ibqueryerrors reports the port counters of switches. This is simi-
+lar 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.
+
+
+OPTIONS
+-a 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.
+
+-c Suppress some of the common "side effect" counters. These coun-
+ters usually do not indicate an error condition and can be usu-
+ally be safely ignored.
+
+-r 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.
+
+-R 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.
+
+-s <err1,err2,...>
+Suppress the errors listed in the comma separated list provided.
+
+-S <switch_guid>
+Report results only for the switch specified. (hex format)
+
+-D <direct_route>
+Report results only for the switch specified by the direct route
+path.
+
+-d Include the optional transmit and receive data counters.
+
+-C <ca_name> use the specified ca_name for the search.
+
+-P <ca_port> use the specified ca_port for the search.
+
+AUTHOR
+Ira Weiny <weiny2@llnl.gov>
+
+
+OFED Jan 24, 2008 IBQUERYERRORS(8)

+


+<return-to-top>

+

 

+

IBROUTE(8) OFED Diagnostics

+

NAME
+ibroute - query InfiniBand switch forwarding tables
+
+
+SYNOPSIS
+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(ime-
+out) timeout_ms] [-V(ersion)] [-h(elp)] [<dest dr_path|lid|guid>
+[<startlid> [<endlid>]]]
+
+
+DESCRIPTION
+ibroute uses SMPs to display the forwarding tables (unicast (LinearFor-
+wardingTable 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.
+
+
+OPTIONS
+-a, --all
+show all lids in range, even invalid entries
+
+-n, --no_dests
+do not try to resolve destinations
+
+-M, --Multicast
+show multicast forwarding tables In this case, the range parame-
+ters are specifying the mlid range.
+
+
+COMMON OPTIONS
+Most OFED 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
+
+-d raise the IB debugging level.
+May be used several times (-ddd or -d -d -d).
+
+-e show send and 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 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 argument. In most cases, it is the Port GUID.
+Example:
+"0x08f1040023"
+
+-s <smlid> use Â’smlidÂ’ as the target lid for SM/SA queries.
+
+# Other common flags:
+
+-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.
+
+Multiple CA/Multiple Port Support
+
+When no IB device or port is specified, the port to use is selected 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 user request is attempted to
+be fulfilled, and will fail if it is not possible.
+
+
+EXAMPLES
+Unicast examples
+
+ibroute 4 # dump all lids with valid out ports of switch with lid 4
+
+ibroute -a 4 # same, but dump all lids, even with invalid out ports
+
+ibroute -n 4 # simple dump format - no destination resolution
+
+ibroute 4 10 # dump lids starting from 10 (up to FDBTop)
+
+ibroute 4 0x10 0x20 # dump lid range
+
+ibroute -G 0x08f1040023 # resolve switch by GUID
+
+ibroute -D 0,1 # resolve switch by direct path
+
+
+Multicast examples
+
+ibroute -M 4 # dump all non empty mlids of switch with lid 4
+
+ibroute -M 4 0xc010 0xc020 # same, but with range
+
+ibroute -M -n 4 # simple dump format
+
+
+SEE ALSO
+ibtracert(8)
+
+AUTHOR
+Hal Rosenstock <halr@voltaire.com>
+
+
+OFED July 25, 2006 IBROUTE(8)

+


+<return-to-top>

+

 

+
+


+ibv_devinfo - print CA (Channel Adapter) attributes

+

usage: ibv_devinfo  [options]
+
+Options:
+   -d, --ib-dev=<dev> use IB device <dev> (default: first device +found)
+    -i, --ib-port=<port> use port <port> of IB device (default: +all ports)
+    -l, --list print only the IB devices names
+    -v, --verbose print all the attributes of the IB device(s)
+
+<return-to-top>

+
+


+IBSTAT(8) OFED Diagnostics

+

NAME
+ibstat - query basic status of InfiniBand device(s)
+
+
+SYNOPSIS
+ibstat [-d(ebug)] [-l(ist_of_cas)] [-s(hort)] [-p(ort_list)] [-V(ersion)] [-h] <ca_name> +[portnum]
+
+
+DESCRIPTION
+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 dis-
+plays more information than ibstatus.
+
+
+OPTIONS
+-l, --list_of_cas
+list all IB devices
+
+-s, --short
+short output
+
+-p, --port_list
+show port list
+
+ca_name
+InfiniBand device name
+
+portnum
+port number of InfiniBand device
+
+
+COMMON OPTIONS
+Most OFED 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
+
+-d raise the IB debugging level.
+May be used several times (-ddd or -d -d -d).
+
+-e show send and 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 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 argument. In most cases, it is the Port GUID.
+Example:
+"0x08f1040023"
+
+-s <smlid> use Â’smlidÂ’ as the target lid for SM/SA queries.
+
+# Other common flags:
+
+-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.
+
+Multiple CA/Multiple Port Support
+
+When no IB device or port is specified, the port to use is selected 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 user request is attempted to
+be fulfilled, and will fail if it is not possible.
+
+
+EXAMPLES
+ibstat # display status of all ports on all IB devices
+
+ibstat -l # list all IB devices
+
+ibstat -p # show port guids
+
+ibstat ibv_device0 2 # show status of port 2 of Â’hca0Â’
+
+
+SEE ALSO
+ibstatus(8)
+
+
+AUTHOR
+Hal Rosenstock <halr@voltaire.com>
+
+
+OFED July 25, 2006 IBSTAT(8)
+
+<return-to-top>

+

 

+

IBSYSSTAT(8) OFED Diagnostics

+

NAME
+ibsysstat - system status on an InfiniBand address
+
+
+SYNOPSIS
+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>]
+
+
+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.
+
+
+OPTIONS
+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, --Server
+start in server mode (do not return)
+
+
+
+COMMON OPTIONS
+Most OFED 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
+
+-d raise the IB debugging level.
+May be used several times (-ddd or -d -d -d).
+
+-e show send and 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 version info.
+
+# Addressing flags
+
+-G use GUID address argument. In most cases, it is the Port GUID.
+Example:
+"0x08f1040023"
+
+-s <smlid> use Â’smlidÂ’ as the target lid for SM/SA queries.
+
+# Other common flags:
+
+-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.
+
+Multiple CA/Multiple Port Support
+
+When no IB device or port is specified, the port to use is selected 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 user request is attempted to
+be fulfilled, and will fail if it is not possible.
+
+
+AUTHOR
+Hal Rosenstock    <halr@voltaire.com>
+
+
+OFED August 11, 2006 IBSYSSTAT(8)

+


+<return-to-top>

+

 

+

IBTRACERT(8) OFED Diagnostics

+


+NAME
+ibtracert- trace InfiniBand path
+
+
+SYNOPSIS
+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>]]]
+
+
+DESCRIPTION
+ibtracert uses SMPs to trace the path from a source GID/LID to a desti-
+nation GID/LID. Each hop along the path is displayed until the destina-
+tion is reached or a hop does not respond. By using the -m option, mul-
+ticast path tracing can be performed between source and destination
+nodes.
+
+
+OPTIONS
+-n, --no_info
+simple format; donÂ’t show additional information
+
+-m show the multicast trace of the specified mlid
+
+--node-name-map <node-name-map>
+Specify a node name map. The node name map file maps GUIDs to
+more user friendly names. See ibnetdiscover(8) for node name
+map file format.
+
+
+COMMON OPTIONS
+Most OFED 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
+
+-d raise the IB debugging level.
+May be used several times (-ddd or -d -d -d).
+
+-h show the usage message
+
+-v increase the application verbosity level.
+May be used several times (-vv or -v -v -v)
+
+-V show the 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 argument. In most cases, it is the Port GUID.
+Example:
+"0x08f1040023"
+
+-s <smlid> use Â’smlidÂ’ as the target lid for SM/SA queries.
+
+# Other common flags:
+
+-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.
+
+Multiple CA/Multiple Port Support
+
+When no IB device or port is specified, the port to use is selected 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 user request is attempted to
+be fulfilled, and will fail if it is not possible.
+
+
+EXAMPLES
+Unicast examples
+
+ibtracert 4 16 # show path between lids 4 and 16
+
+ibtracert -n 4 16 # same, but using simple output format
+
+ibtracert -G 0x8f1040396522d 0x002c9000100d051 # use guid addresses
+
+
+Multicast example
+
+ibtracert -m 0xc000 4 16 # show multicast path of mlid 0xc000
+between lids 4 and 16
+
+
+SEE ALSO
+ibroute(8)
+
+
+AUTHOR
+    Hal Rosenstock    <halr@voltaire.com>
+
+    Ira Weiny    <weiny2@llnl.gov>
+
+OFED April 14, 2007 IBTRACERT(8)

+

<return-to-top>

+

 

+

PERFQUERY(8) OFED Diagnostics

+


+NAME
+perfquery - query InfiniBand port counters
+
+
+SYNOPSIS
+perfquery [-d(ebug)] [-G(uid)] [-x|--extended] [-X|--xmtsl]
+[-S|--rcvsl] [-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]]]
+
+
+DESCRIPTION
+perfquery uses PerfMgt GMPs to obtain the PortCounters (basic perfor-
+mance and error counters), PortExtendedCounters, PortXmitDataSL, or
+PortRcvDataSL 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 PortCounters, PortCountersExtended, PortXmitDataSL, and PortR-
+cvDataSL, components that represent Data (e.g. PortXmitData and PortR-
+cvData) indicate octets divided by 4 rather than just octets.
+
+Note: Inputting a port of 255 indicates an operation be performed on
+all ports.
+
+
+OPTIONS
+-x, --extended
+show extended port counters rather than (basic) port counters.
+Note that extended port counters attribute is optional.
+
+-X, --xmtsl
+show transmit data SL counter. This is an optional counter for
+QoS.
+
+-S, --rcvsl
+show receive data SL counter. This is an optional counter for
+QoS.
+
+-a, --all_ports
+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.
+
+-l, --loop_ports
+If all ports are selected by the user (either through the -a
+option or port 255) iterate through each port rather than doing
+than aggregate operation.
+
+-r, --reset_after_read
+reset counters after read
+
+-R, --Reset_only
+only reset counters
+
+
+COMMON OPTIONS
+Most OFED 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
+
+-d raise the IB debugging level.
+May be used several times (-ddd or -d -d -d).
+
+-e show send and 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 version info.
+
+# Addressing flags
+
+-G use GUID address argument. In most cases, it is the Port GUID.
+Example:
+"0x08f1040023"
+
+-s <smlid> use Â’smlidÂ’ as the target lid for SM/SA queries.
+
+# Other common flags:
+
+-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.
+
+Multiple CA/Multiple Port Support
+
+When no IB device or port is specified, the port to use is selected 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 user request is attempted to
+be fulfilled, and will fail if it is not possible.
+
+
+EXAMPLES
+perfquery # read local port performance counters
+
+perfquery 32 1 # read performance counters from lid 32, port 1
+
+perfquery -x 32 1 # read extended performance counters from lid 32, port 1
+
+perfquery -a 32 # read perf counters from lid 32, all ports
+
+perfquery -r 32 1 # read performance counters and reset
+
+perfquery -x -r 32 1 # read extended performance counters and reset
+
+perfquery -R 0x20 1 # reset performance counters of port 1 only
+
+perfquery -x -R 0x20 1 # reset extended performance counters of port 1 only
+
+perfquery -R -a 32 # reset performance counters of all ports
+
+perfquery -R 32 2 0x0fff # reset only error counters of port 2
+
+perfquery -R 32 2 0xf000 # reset only non-error counters of port 2
+
+
+AUTHOR
+Hal Rosenstock    <halr@voltaire.com>
+
+
+OFED March 10, 2009 PERFQUERY(8)

+


+<return-to-top>

+

 

+

SAQUERY(8) OFED Diagnostics

+


+NAME
+saquery - query InfiniBand subnet administration attributes
+
+
+SYNOPSIS
+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>]
+
+
+DESCRIPTION
+saquery issues the selected SA query. Node records are queried by
+default.
+
+
+OPTIONS
+-p get PathRecord info
+
+-N get NodeRecord info
+
+--list | -D
+get NodeDescriptions of CAs only
+
+-S get ServiceRecord info
+
+-I get InformInfoRecord (subscription) info
+
+-L return the Lids of the name specified
+
+-l return the unique Lid of the name specified
+
+-G return the Guids of the name specified
+
+-O return the name for the Lid specified
+
+-U return the name for the Guid specified
+
+-c get the SAÂ’s class port info
+
+-s return the PortInfoRecords with isSM or isSMdisabled capability
+mask bit on
+
+-g get multicast group info
+
+-m 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
+
+-x get LinkRecord info
+
+--src-to-dst
+get a PathRecord for <src:dst> where src and dst are either node +names or LIDs
+
+--sgid-to-dgid
+get a PathRecord for sgid to dgid where both GIDs are in an IPv6 format +acceptable to inet_pton.
+
+-C <ca_name>
+use the specified ca_name.
+
+-P <ca_port>
+use the specified ca_port.
+
+--smkey <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.
+
+-t, -timeout <msec>
+Specify SA query response timeout in milliseconds. Default is
+100 milliseconds. You may want to use this option if IB_TIMEOUT
+is indicated.
+
+--node-name-map <node-name-map>
+Specify a node name map. The node name map file maps GUIDs to
+more user friendly names. See ibnetdiscover(8) for +node name
+map file format
. Only used with the -O and -U options.
+
+Supported query names (and aliases):
+ClassPortInfo (CPI)
+NodeRecord (NR) [lid]
+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]]
+
+-d enable debugging
+
+-h show help
+
+
+AUTHORS
+Ira Weiny <weiny2@llnl.gov>
+
+Hal Rosenstock <halr@voltaire.com>
+
+
+OFED October 19, 2008 SAQUERY(8)

+

<return-to-top>

+

 

+

SMINFO(8) OFED Diagnostics

+


+NAME
+sminfo - query InfiniBand SMInfo attribute
+
+
+SYNOPSIS
+sminfo [-d(ebug)] [-e(rr_show)] -s state -p prio -a activity
+[-D(irect)] [-G(uid)] [-C ca_name] [-P ca_port] [-t(imeout) time-
+out_ms] [-V(ersion)] [-h(elp)] sm_lid | sm_dr_path [modifier]
+
+
+DESCRIPTION
+Optionally set and display the output of a sminfo query in human read-
+able 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.
+
+
+OPTIONS
+-s set SM state
+0 - not active
+1 - discovering
+2 - standby
+3 - master
+
+-p set priority (0-15)
+
+-a set activity count
+
+COMMON OPTIONS
+
+Most OFED 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
+
+-d raise the IB debugging level.
+May be used several times (-ddd or -d -d -d).
+
+-e show send and 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 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 argument. In most cases, it is the Port GUID.
+Example:
+"0x08f1040023"
+
+-s <smlid> use Â’smlidÂ’ as the target lid for SM/SA queries.
+
+# Other common flags:
+
+-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.
+
+Multiple CA/Multiple Port Support
+
+When no IB device or port is specified, the port to use is selected 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 user request is attempted to
+be fulfilled, and will fail if it is not possible.
+
+
+EXAMPLES
+sminfo         # local port´s sminfo
+
+sminfo 32     # show sminfo of lid 32
+
+sminfo -G 0x8f1040023     # same but using guid address
+
+
+SEE ALSO
+smpdump(8)
+
+
+AUTHOR
+Hal Rosenstock    <halr@voltaire.com>
+
+OFED July 25, 2006 SMINFO(8)

+


+<return-to-top>

+

 

+

SMPDUMP(8) OFED Diagnostics

+


+NAME
+smpdump - dump InfiniBand subnet management attributes
+
+
+SYNOPSIS
+smpdump [-s(ring)] [-D(irect)] [-C ca_name] [-P ca_port] [-t(imeout)
+timeout_ms] [-V(ersion)] [-h(elp)] <dlid|dr_path> <attr> [mod]
+
+
+DESCRIPTION
+smpdump is a general purpose SMP utility which gets SM attributes from
+a specified SMA. The result is dumped in hex by default.
+
+
+OPTIONS
+attr IBA attribute ID for SM attribute
+
+mod IBA modifier for SM attribute
+
+
+COMMON OPTIONS
+Most OFED 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
+
+-d raise the IB debugging level.
+May be used several times (-ddd or -d -d -d).
+
+-e show send and 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 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 argument. In most cases, it is the Port GUID.
+Example:
+"0x08f1040023"
+
+-s <smlid> use Â’smlidÂ’ as the target lid for SM/SA queries.
+
+# Other common flags:
+
+-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.
+
+Multiple CA/Multiple Port Support
+
+When no IB device or port is specified, the port to use is selected 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 user request is attempted to
+be fulfilled, and will fail if it is not possible.
+
+
+EXAMPLES
+Direct Routed Examples
+
+smpdump -D 0,1,2,3,5 16 # NODE DESC
+
+smpdump -D 0,1,2 0x15 2 # PORT INFO, port 2
+
+LID Routed Examples
+
+smpdump 3 0x15 2 # PORT INFO, lid 3 port 2
+
+smpdump 0xa0 0x11 # NODE INFO, lid 0xa0
+
+
+SEE ALSO
+smpquery(8)
+
+
+AUTHOR
+Hal Rosenstock    <halr@voltaire.com>
+
+
+OFED July 25, 2006 SMPDUMP(8)

+


+<return-to-top>

+

 

+

SMPQUERY(8) OFED Diagnostics

+


+NAME
+smpquery - query InfiniBand subnet management attributes
+
+
+SYNOPSIS
+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-file]
+[-V(ersion)] [-h(elp)] <op> <dest dr_path|lid|guid> [op +params]
+
+
+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.
+
+
+OPTIONS
+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>
+
+
+--node-name-map <node-name-map>
+Specify a node name map. The node name map file maps GUIDs to
+more user friendly names. See ibnetdiscover(8) for +node name
+map file format
.
+
+
+COMMON OPTIONS
+Most OFED 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
+
+-d raise the IB debugging level.
+May be used several times (-ddd or -d -d -d).
+
+-e show send and 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 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, ...
+
+-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.
+
+-G use GUID address argument. In most cases, it is the Port GUID.
+Example:
+"0x08f1040023"
+
+-s <smlid> use Â’smlidÂ’ as the target lid for SM/SA queries.
+
+# Other common flags:
+
+-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.
+
+Multiple CA/Multiple Port Support
+
+When no IB device or port is specified, the port to use is selected 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 user request is attempted to
+be fulfilled, and will fail if it is not possible.
+
+
+EXAMPLES
+smpquery portinfo 3 1 # portinfo by lid, with port modifier
+
+smpquery -G switchinfo 0x2C9000100D051 1 # switchinfo by guid
+
+smpquery -D nodeinfo 0 # nodeinfo by direct route
+
+smpquery -c nodeinfo 6 0,12 # nodeinfo by combined route
+
+
+SEE ALSO
+smpdump(8)
+
+
+AUTHOR
+Hal Rosenstock <halr@voltaire.com>
+
+
+OFED March 14, 2007 SMPQUERY(8)

+

<return-to-top>

+

 

+

VENDSTAT(8) OFED Diagnostics

+

NAME
+vendstat - query InfiniBand vendor specific functions
+
+
+SYNOPSIS
+vendstat [-d(ebug)] [-G(uid)] [-N] [-w] [-i] [-c <num,num>] [-C ca_name] [-P +ca_port] [-t(imeout) timeout_ms] [-V(ersion)] [-h(elp)] <lid|guid>
+
+
+DESCRIPTION
+vendstat uses vendor specific MADs to access beyond the IB spec vendor
+specific functionality. Currently, there is support for Mellanox InfiniSwitch-III +(IS3) and InfiniSwitch-IV (IS4).
+
+
+OPTIONS
+-N show IS3 general information.
+
+-w show IS3 port xmit wait counters.
+
+-i show IS4 counter group info.
+
+-c <num,num>
+configure IS4 counter groups.
+
+Configure IS4 counter groups 0 and 1. Such configuration is not
+persistent across IS4 reboot. First number is for counter group
+0 and second is for counter group 1.
+
+Group 0 counter config values:
+0 - PortXmitDataSL0-7
+1 - PortXmitDataSL8-15
+2 - PortRcvDataSL0-7
+
+Group 1 counter config values:
+1 - PortXmitDataSL8-15
+2 - PortRcvDataSL0-7
+8 - PortRcvDataSL8-15
+
+
+COMMON OPTIONS
+Most OFED 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
+
+-d raise the IB debugging level.
+May be used several times (-ddd or -d -d -d).
+
+-e show send and 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 version info.
+
+# Addressing flags
+
+-G use GUID address argument. In most cases, it is the Port GUID.
+Example:
+"0x08f1040023"
+
+-s <smlid> use Â’smlidÂ’ as the target lid for SM/SA queries.
+
+# Other common flags:
+
+-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.
+
+Multiple CA/Multiple Port Support
+
+When no IB device or port is specified, the port to use is selected 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 user request is attempted to
+be fulfilled, and will fail if it is not possible.
+
+
+EXAMPLES
+vendstat -N 6 # read IS3 general information
+
+vendstat -w 6 # read IS3 port xmit wait counters
+
+vendstat -i 6 12 # read IS4 port 12 counter group info
+
+vendstat -c 0,1 6 12 # configure IS4 port 12 counter groups for PortXmitDataSL
+
+vendstat -c 2,8 6 12 # configure IS4 port 12 counter groups for PortRcvDataSL
+
+
+AUTHOR
+Hal Rosenstock    <halr@voltaire.com>
+
+
+OFED April 16, 2009 VENDSTAT(8)

+

<return-to-top>

+


+ib_limits - Infiniband verbs tests

+

Usage: ib_limits [options]

+
+

Options:
-m or --memory
    Direct ib_limits to test memory registration
-c or --cq
    Direct ib_limits to test CQ creation
-r or --resize_cq
    direct ib_limits to test CQ resize
-q or --qp
    Directs ib_limits to test QP creation
-v or --verbose
    Enable verbosity level to debug console.
-h or --help
    Display this usage info then exit.

+
+

<return-to-top>

+

 

+


+cmtest - Connection Manager Tests

+

Usage: cmtest [options]

+

    Options:

+
+

 -s --server This option directs cmtest to act as a Server
+ -l + --local + This option specifies the local endpoint.
+ -r + --remote + This option specifies the remote endpoint LID as a hex integer 0x; see + vstat command for active port LID hex integer.
+ -c + --connect + This option specifies the number of connections to open. Default of + 1.
+ -m + --msize + This option specifies the byte size of each message. Default is 100 + bytes.
+ -n + --nmsgs + This option specifies the number of messages to send at a time.
+ -p --permsg This option indicates if a separate buffer should be used per + message. Default is one buffer for all messages.
+ -i + --iterate + This option specifies the number of times to loop through 'nmsgs'. + Default of 1.
+ -v --verbose This option enables verbosity level to debug console.
+ -h --help Display this usage info then exit.

+
+

<return-to-top>

+

 

+
+

InfiniBand Partition +Management

+

The part_man.exe +application allows creating, deleting and viewing existing +host partitions.

+

Usage : part_man.exe <show|add|rem> <port_guid> <pkey1 pkey2 +...>

+ + show - + + – shows existing partitions

+ Expected results after execution + part_man.exe show

+

+ 1.      + Output has a format 

+

+ port_guid1   pkey1  pkey2  + pkey3  pkey4  pkey5  pkey6  pkey7  pkey8

+

+ port_guid2   + pkey1  pkey2  pkey3  pkey4  pkey5  pkey6  pkey7  pkey8

+

+ where + port_guid is a port guid in + hexadecimal format, pkey – + values of partition key (in hex format) for this port.

+

+ Default + partition key (0xFFFF) is not shown and can not be created by the + part_man.exe.

+

+  

+

+ + add - create new partition(s) + on specified port

+

+ + port_guid  + add   <port_guid> +  <pkey1>   <pkey2> +

+

creates new partition(s) on port specified by port_guid parameter (in + hexadecimal format) and pkey – new partition key value in hexadecimal + format (e.g. 0xABCD or ABCD).

+

+ Port + guid is taken form vstat output and has a following format:

+

+ + XXXX:XXXX:XXXX:XXXX.

+

+ Vstat + prints node guid, so user has to add 1 to node guid value to obtain port + guid. For example, if node guid is + 0008:f104:0397:7ccc, port guid will be

+

+ + 0008:f104:0397:7ccd + – for the first port,

+

+ + 0008:f104:0397:7cce + – for the second port.

+

+ +  

+

+ Expected + results of execution part_man.exe add + 0x0D99:9703:04f1:0800 0xABCD

+

+ 1.      + part_man.exe output ends up with + Â…Done message.

+

+ 2.      + A new instance of a Network Adapter named “OpenFabrics IPoIB + Adapter Partition” will appear in Device manager + window. 
+ If the new adapter appears with yellow label, manual device driver installation is + required.

+
    +
  • +

    In + the device manager view, right click “OpenFabrics IPoIB Adapter Partition”

    +
  • +
  • +

    + select 'update driver' and follow the instructions.

  • +
  • +

    don't + allow Windows Update to search the Internet

  • +
  • +

    + select install software automatically.

  • +
+

+ 3.      + New adapter name ends with “Partition”, e.g. “OpenFabrics IPoIB + Adapter Partition”.

+

+  

+ + + rem + – + removes partition key on specified + port.

+

+ + part_man.exe rem <port_guid> + <pkey1>  <pkey2>

+

+ + Port_guid – in hexadecimal format (same as for + add command), identifies port for + operation.

+

+ Expected + results after execution part_man rem <port_guid> +  <pkey>

+

+ 1.      + Application prints Â…Done + message.

+

+ 2.      + In device manager window IPoIB network adapter will disappear.

+

+ 3.      + Execution of  part_man.exe + show will not show removed adapter.

+

  + +

<return-to-top>

+

 

+


+PrintIP - print ip adapters and their addresses

+
+

PrintIP is used to print IP adapters and their addresses, or + ARP (Address Resolution Protocol) and IP address.
+
+ Usage:
+    printip <print_ips>
+    printip <remoteip> <ip>        + (example printip remoteip 10.10.2.20)

+
+

<return-to-top>

+

 

+

+
+
+vstat - HCA Stats and Counters

+
+

Display HCA (Host channel Adapter) attributes.

+

Usage: vstat [-v] [-c]
+          -v - verbose mode
+          -c - HCA error/statistic + counters
+
+ Includes Node GUID, Subnet Manager and port LIDs.

+
+

<return-to-top>

+

 

+
+

Subnet Management with OpenSM version +3.3.6

+
+

A single running process (opensm.exe) is required to configure +and thus make an Infiniband subnet useable.  For most cases, InfiniBand +Subnet Management as a Windows service is sufficient to correctly configure most +InfiniBand fabrics.

+

The Infiniband subnet management process (opensm) may exist on a +Windows (OFED) node or a Linux (OFED) node.
+
+Limit the number of OpenSM processes per IB fabric; one SM is sufficient +although redundant SMs are supported. You do not need a Subnet Manager per +node/system.

+

OpenIB Subnet Management as a Windows Service

+

InfiniBand subnet management (OpenSM), as a Windows service, is installed by default, although it is NOT +started by default. There are two ways to enable the InfiniBand Subnet +Management service.

+
    +
  1. Reset the installed OpenSM service "InfiniBand Subnet Management" + to start automatically; From a command window type 'services.msc'.
    + Locate the InfiniBand Subnet Management view and select the start option; + additionally select the startup option 'Automatic' to start the OpenSM + service on system startup.
     
  2. +
  3. Install OpenSM as a 'running' Windows service:
    + Select the OpenSM_service_Started install feature. + Once the installation has completed, check the running InfiniBand Subnet + Management service status via the Windows service manager (see #1).
     
  4. +
  5. Consult the OpenSM log files to see what + OpenSM thinks is happening.
    +    %TEMP%\osm.log
    +    %TEMP%\osm.syslog
    + Note:
    +    When opensm.exe is run as a Windows Service, the 'normal' + case, %temp% is defined as %windir%\TEMP\.
    +    If opensm.exe is run from a command window, %TEMP% is not + defined as %windir%\TEMP\.
     
  6. +
+

InfiniBand Subnet Management from a command window

+ +opensm - InfiniBand subnet manager and administration (SM/SA) +

SYNOPSIS

+ +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>] +[--sm_sl <SL number>] +[-r(eassign_lids)] +[-R <engine name(s)> | --routing_engine <engine name(s)>] +[--do_mesh_analysis] +[--lash_start_vl <vl number>] +[-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>] +[-G | --io_guid_file <path to file>] +[-H | --max_reverse_hops <max reverse hops allowed>] +[-X | --guid_routing_order_file <path to file>] +[-m | --ids_guid_file <path to file>] +[-o(nce)] +[-s(weep) <interval>] +[-t(imeout) <milliseconds>] +[--retries <number>] +[-maxsmps <number>] +[-console [off | local | socket | loopback]] +[-console-port <port>] +[-i(gnore-guids) <equalize-ignore-guids-file>] +[-w | --hop_weights_file <path to file>] +[-O | --dimn_ports_file <path to 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 | --service --daemon] +[-I | --inactive] +[--perfmgr] +[--perfmgr_sweep_time_s <seconds>] +[--prefix_routes_file <path>] +[--consolidate_ipv6_snm_req] +[--log_prefix <prefix text>] [-v(erbose)] [-V] [-D <flags>] [-d(ebug) <number>] +[-h(elp)] [-?] +

DESCRIPTION

+ +

+ +opensm is an InfiniBand compliant Subnet Manager and Administration, +and runs on top of OFED for Windows. 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: %TEMP%\osm.syslog (aka +%windir%\temp\osm.syslog) and %windir%\temp\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. Note when opensm.exe is run as a service, %TEMP% == +%windir%\temp .

OPTIONS

+ +

+

+ +

+
--version
+Prints OpenSM version and exits. +
-F, --config <config file>
+The name of the OpenSM config file. When not specified + %ProgramFiles%\OFED\opensm\opensm.conf will be used (if exists). +
-c, --create-config <file name>
+OpenSM will dump its configuration to the specified file and exit. +This is a way to generate OpenSM configuration file template. +
-g, --guid <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. +
-l, --lmc <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. +
-p, --priority <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). +
-smkey <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. +
--sm_sl <SL number>
+This option sets the SL to use for communication with the SM/SA. +Defaults to 0. +
-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. +
-R, --routing_engine <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 +
--do_mesh_analysis
+This option enables additional analysis for the lash routing engine to +precondition switch port assignments in regular cartesian meshes which +may reduce the number of SLs required to give a deadlock free routing. +
--lash_start_vl <vl number>
+This option sets the starting VL to use for the lash routing algorithm. +Defaults to 0. +
-A, --ucast_cache
+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. +
-z, --connect_roots
+This option enforces routing engines (up/down and +fat-tree) 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. +
-M, --lid_matrix_file <file name>
+This option specifies the name of the lid matrix dump file +from where switch lid matrices (min hops tables will be +loaded. +
-U, --lfts_file <file name>
+This option specifies the name of the LFTs file +from where switch forwarding tables will be loaded. +
-S, --sadb_file <file name>
+This option specifies the name of the SA DB dump file +from where SA database will be loaded. +
-a, --root_guid_file <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). +
-u, --cn_guid_file <file name>
+Set the compute nodes for the Fat-Tree routing algorithm +to the guids provided in the given file (one to a line). +
-G, --io_guid_file <file name>
+Set the I/O nodes for the Fat-Tree routing algorithm +to the guids provided in the given file (one to a line). +I/O nodes are non-CN nodes allowed to use up to max_reverse_hops switches +the wrong way around to improve connectivity. +
-H, --max_reverse_hops <file name>
+Set the maximum number of reverse hops an I/O node is allowed +to make. A reverse hop is the use of a switch the wrong way around. +
-m, --ids_guid_file <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). +
-X, --guid_routing_order_file <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). +
-o, --once
+This option causes OpenSM to configure the subnet +once, then exit. Ports remain in the ACTIVE state. +
-s, --sweep <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. +
-t, --timeout <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. +
--retries <number>
+This option specifies the number of retries used +for transactions. +Without --retries, OpenSM defaults to 3 retries +for transactions. +
-maxsmps <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. +
-console [off | local | socket | loopback]
+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. +
-console-port <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. +
-i, -ignore-guids <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. +
-w, --hop_weights_file <path to file>
+This option provides weighting factors per port representing a hop cost in +computing the lid matrix. The file consists of lines containing a switch port +GUID (specified as a 64 bit hex number, with leading 0x), output port number, +and weighting factor. Any port not listed in the file defaults to a weighting +factor of 1. Lines starting with # are comments. Weights affect only the +output route from the port, so many useful configurations will require weights +to be specified in pairs. +
-O, --dimn_ports_file <path to file>
This option provides a +mapping between hypercube dimensions and ports on a per switch basis for the DOR +routing engine. The file consists of lines containing a switch node GUID +(specified as a 64 bit hex number, with leading 0x) followed by a list of +non-zero port numbers, separated by spaces, one switch per line. The order for +the port numbers is in one to one correspondence to the dimensions. Ports not +listed on a line are assigned to the remaining dimensions, in port order. +Anything after a # is a comment.
+
-x, --honor_guid2lid
+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. +
-f, --log_file <file name>
+This option defines the log to be the given file. By default, the log goes to +%windir%\temp\opensm.log. +For the log to go to standard output use -f stdout. +
-L, --log_limit <size in MB>
+This option defines maximal log file size in MB. When +specified the log file will be truncated upon reaching +this limit. +
-e, --erase_log_file
+This option will cause deletion of the log file +(if it previously exists). By default, the log file +is accumulative. +
-P, --Pconfig <partition config file>
+This option defines the optional partition configuration file. +The default name is %ProgramFiles%\OFED\opensm\partitions.conf. +
--prefix_routes_file <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 +PREFIX ROUTES + +section below describes the format of the configuration file. +The default path is %ProgramFiles%\OFED\opensm\prefix-routes.conf. +
-Q, --qos
+This option enables QoS setup. It is disabled by default. +
-Y, --qos_policy_file <file name>
+This option defines the optional QoS policy file. The default +name is %ProgramFiles%\OFED\opensm\qos-policy.conf. See +QoS_management_in_OpenSM.txt in opensm doc for more information on +configuring QoS policy via this file. +
-N, --no_part_enforce
+This option disables partition enforcement on switch external ports. +
-y, --stay_on_fatal
+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. +
-B, --service
+OpenSM will run in the background (without a console window) as a Windows system +service (the preferred Windows mode). +
-I, --inactive
+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. +
-perfmgr
+Enable the perfmgr. Only takes effect if --enable-perfmgr was specified at +configure time. See performance-manager-HOWTO.txt in opensm doc for +more information on running perfmgr. +
-perfmgr_sweep_time_s <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. +
--consolidate_ipv6_snm_req
+Use shared MLID for IPv6 Solicited Node Multicast groups per MGID scope +and P_Key. +
-log_prefix <prefix text>
+This option specifies the prefix to the syslog messages from OpenSM. A suitable +prefix can be used to identify the IB subnet in syslog messages when two or more +instances of OpenSM run in a single node to manage multiple fabrics. For +example, in a dual-fabric (or dual-rail) IB cluster, the prefix for the first +fabric could be "mpi" and the other fabric could be "storage". +
-v, --verbose
+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. +
-V
+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. +
-D <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. +

-d, --debug <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 +
-h, --help
+Display this usage info then exit. +
-?
+Display this usage info then exit. +

+

+

ENVIRONMENT VARIABLES

+ +

+ +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 %ProgramFiles%\OFED\OpenSM\.
  • +
  • OSM_CACHE_DIR - opensm stores certain data to the disk such that + subsequent runs are consistent. The default directory used is %ProgramFiles%\OFED\OpenSM\. +The following file is included in it:
     guid2lid - stores the LID range assigned to each GUID
  • +
+

NOTES

+ +

+ +When opensm running as a windows service, if the opensm process receives a service control code of +129, it starts a new heavy sweep as if a trap was received or a topology change was found.

+ +Also, service control code 128 can be used to trigger a reopen of %windir%\temp\osm.log for +logrotate purposes.

+ +Examples:

+ +    sc.exe control OpenSM 128            +# will clear the contents of %windir%\temp\osm.log, logrotate.
+    sc.exe control OpenSM 129            +# start a new heavy sweep

+ + 

PARTITION CONFIGURATION

+ +

+ +The default name of OpenSM partitions configuration file is +%ProgramFiles\OFED\OpenSM\partitions.conf. The default may be changed +by using the --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 always +have full membership in default partition. All other end ports will have +full membership if the partition configuration file is not found or cannot +be accessed, or limited membership if the file exists and can be accessed +but there is no rule for the Default partition. +

+Effectively, this amounts to the same as if one of the following rules +below appear in the partition configuration file. +

+In the case of no rule for the Default partition: +

+Default=0x7fff : ALL=limited, SELF=full ; +

+In the case of no partition configuration file or file cannot be accessed: +

+Default=0x7fff : ALL=full ; +

+

+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. +
 - 'ALL_CAS' means all Channel Adapter end ports in this subnet. +
 - 'ALL_SWITCHES' means all Switch end ports in this subnet. +
 - 'ALL_ROUTERS' means all Router 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 ; +
 Default=0x7fff : ALL, ALL_SWITCHES=full, 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; + +  +

QOS CONFIGURATION

+ +

+ +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 + +  +

PREFIX ROUTES

+ +

+ +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. +

+ +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 # 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. +

+ +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 behavior formerly achieved by +compiling opensm with -DROUTER_EXP which has been obsoleted. +

ROUTING

+ +

+ +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 +
+ +--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 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. +
+ +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. +

+Routing between non-CN nodes +

+The use of the cn_guid_file option allows non-CN nodes to be located on different levels in the fat tree. +In such case, it is not guaranteed that the Fat Tree algorithm will route between two non-CN nodes. +To solve this problem, a list of non-CN nodes can be specified by '-G' or '--io_guid_file' option. +Theses nodes will be allowed to use switches the wrong way round a specific number of times (specified by '-H' or '--max_reverse_hops'. +With the proper max_reverse_hops and io_guid_file values, you can ensure full connectivity in the Fat Tree. +

+Please note that using max_reverse_hops creates routes that use the switch in a counter-stream way. +This option should never be used to connect nodes with high bandwidth traffic between them ! It should only be used +to allow connectivity for HA purposes or similar. +Also having routes the other way around can in theory cause credit loops. +

+Use these options with extreme care ! +

+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. +

+For open regular cartesian meshes the DOR algorithm is the ideal +routing algorithm. For toroidal meshes on the other hand there +are routing loops that can cause deadlocks. LASH can be used to +route these cases. The performance of LASH can be improved by +preconditioning the mesh in cases where there are multiple links +connecting switches and also in cases where the switches are not +cabled consistently. An option exists for LASH to do this. To +invoke this use '-R lash -Q --do_mesh_analysis'. This will +add an additional phase that analyses the mesh to try to determine +the dimension and size of a mesh. If it determines that the mesh +looks like an open or closed cartesian mesh it reorders the ports +in dimension order before the rest of the LASH algorithm runs. +

+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. Alternatively, the -O option can be
+used to assign a custom mapping between the ports on a given switch, and the +associated 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, or the -O option used to accomplish the +alignment. 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, or the -O option used as an override.

+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 (%TEMP% 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'. +

FILES

+ +
+
%ProgramFiles\OFED\OpenSM\opensm.conf + +
+default OpenSM config file. +

+

%ProgramFiles%\OFED\OpenSM\ib-node-name-map + +
+default node name map file. See ibnetdiscover for more information on format. +

+

%ProgramFiles%\OFED\OpenSM\partitions.conf + +
+default partition config file +

+

%ProgramFiles%\OFED\OpenSM\qos-policy.conf + +
+default QOS policy config file +

+

%ProgramFiles%\OFED\OpenSM\prefix-routes.conf + +
+default prefix routes file. +

+

+

AUTHORS

+ +
+
Hal Rosenstock
+<hal.rosenstock@gmail.com> + +
Sasha Khapyorsky
+<sashak@voltaire.com> + +
Eitan Zahavi
+<eitan@mellanox.co.il> + +
Yevgeny Kliteynik
+<kliteyn@mellanox.co.il> + +
Thomas Sodring
+<tsodring@simula.no> + +
Ira Weiny
+<weiny2@llnl.gov> + +
Stan Smith
+<stan.smith@intel.com>
+Dale Purdy
+    < purdy@sgi.com >
+
+ +

<return-to-top>

+

 

+


+Osmtest - Subnet Management Tests

+

osmtest - InfiniBand subnet manager and administration (SM/SA) +test program
+
+osmtest currently can not +run on the same HCA port which OpenSM is currently using.

+

SYNOPSIS

+ +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)] +

DESCRIPTION

+ +

+ +osmtest is a test program used to validate the correct operation of the 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. +

OPTIONS

+ +

+

+ +

+
-f, --flow
+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) +
-w, --wait
+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) +
-d, --debug
+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 +

-m, --max_lid
+This option specifies the maximal LID number to be searched +for during inventory file build (default to 100) +
-g, --guid
+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. +
-p, --port
+This option displays a menu of possible local port GUID values +with which osmtest could bind +
-i, --inventory
+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 +
-s, --stress
+This option runs the specified stress test instead +of the normal test suite +Stress test options are as follows: +

+ OPT    Description +
 ---    ----------------- +
 -s1  - Single-MAD (RMPP) response SA queries +
 -s2  - Multi-MAD (RMPP) response SA queries +
 -s3  - Multi-MAD (RMPP) Path Record SA queries +
 -s4  - Single-MAD (non RMPP) get Path Record SA queries +

+Without -s, stress testing is not performed +

-M, --Multicast_Mode
+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 +

-t, --timeout
+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. +
-l, --log_file
+This option defines the log to be the given file. +By default the log goes to stdout. +
-v, --verbose
+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. +
-V
+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. +
-vf
+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 +

-h, --help
+Display this usage info then exit. +

+

+

AUTHORS

+ +
+
Hal Rosenstock
+<hal.rosenstock@gmail.com> + +
Eitan Zahavi
+<eitan@mellanox.co.il> + +
 
+

EXAMPLES

+

Note - osmtest will not run on the node where OpenSM is running.
See 'osmtest -h' for all options.

+

Functionality:

+
+

osmtest -f c            + # creates osmtest.dat inventory file in the current directory; + required by other osmtest runs.
+ osmtest -f v            + # validate the default inventory file 'osmtest.dat'.
osmtest -f a            + # run all validation tests (expecting an input inventory file 'osmtest.dat' + in the current folder).

+
+
+

Stress tests

+
+

osmtest -f  f -s1        #  + Single-MAD (RMPP) response SA queries
+ osmtest -f  f -s2        # Multi-MAD + (RMPP) response SA queries
+ osmtest -f  f -s3        # Multi-MAD + (RMPP) Path Record SA queries

+
+

<return-to-top>

+


+
+

+
+ibtrapgen - Generate Infiniband subnet management traps

+ +

Usage: ibtrapgen -t|--trap_num <TRAP_NUM> -n|--number <NUM_TRAP_CREATIONS>
+                          +-r|--rate <TRAP_RATE> -l|--lid <LIDADDR>
+                          +-s|--src_port <SOURCE_PORT> -p|--port_num <PORT_NUM>
+
+Options: one of the following optional flows:

+
+

-t <TRAP_NUM>
+ --trap_num <TRAP_NUM>
+          This option specifies the + number of the trap to generate. Valid values are 128-131.
+ -n <NUM_TRAP_CREATIONS>
+ --number <NUM_TRAP_CREATIONS>
+          This option specifies the + number of times to generate this trap.
+          If not specified - + default to 1.
+ -r <TRAP_RATE>
+ --rate <TRAP_RATE>
+          This option specifies the + rate of the trap generation.
+          What is the time period + between one generation and another?
+          The value is given in + miliseconds.
+          If the number of trap + creations is 1 - this value is ignored.
+ -l <LIDADDR>
+ --lid <LIDADDR>
+          This option specifies the + lid address from where the trap should be generated.
+ -s <SOURCE_PORT>
+ --src_port <SOURCE_PORT>
+          This option specifies the + port number from which the trap should
+          be generated. If trap + number is 128 - this value is ignored (since
+          trap 128 is not sent with + a specific port number)
+ -p <port num>
+ --port_num <port num>
+          This is the port number + used for communicating with the SA.
+ -h
+ --help
+          Display this usage info + then exit.
+ -o
+ --out_log_file
+          This option defines the + log to be the given file.
+          By default the log goes + to stdout.
+ -v
+          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.
+ -V
+          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.
+ -x <flags>
+          This option sets the log + verbosity level.
+          A flags field must follow + the -vf 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 - currently unused.
+ 0x80 - currently unused.
+ Without -x, ibtrapgen defaults to ERROR + INFO (0x3).
+ Specifying -x 0 disables all messages.
+ Specifying -x 0xFF enables all messages (see -V).

+
+
+

<return-to-top>

+

 

+

 

+
+

IPoIB - Internet Protocols over InfiniBand

+
+

IPoIB enables the use of Internet Protocol utilities (e.g., ftp, +telnet) to function correctly over an Infiniband fabric. IPoIB is implemented as +an NDIS Miniport driver with a WDM lower edge.

+

The IPoIB Network adapters are +located via 'My Computer->Manage->Device Manager->Network adapters->IPoIB'.
+'My +Network Places->Properties' will display IPoIB Local Area Connection instances and should be used to +configure IP addresses for the IPoIB interfaces; one Local Area Connection +instance per HCA port. The IP +(Internet Protocol) address bound to the IPoIB adapter instance can be assigned +by DHCP or as a static IP addresses via
+'My Network Places->Properties->Local +Area Connection X->Properties->(General Tab)Internet Protocol(TCP/IP)->Properties'.

+

When the subnet manager (opensm) configures/sweeps the local +Infiniband HCA, the Local Area Connection will become enabled. If you discover +the Local Area Connection to be disabled, then likely your subnet manager +(opensm) is not running or functioning correctly.

+

IPoIB Partition Management

+
    +
  • +

    part_man      + Manage (add/remove/show) IPoIB partitions.

  • +
+

<return-to-top>

+

 

+

 

+
+

Winsock Direct Service Provider

+
+

Winsock Direct (WSD) is Microsoft's proprietary protocol that +predates SDP (Sockets Direct Protocol) for accelerating TCP/IP applications by +using RDMA hardware. Microsoft had a significant role in defining the SDP +protocol, hence SDP and WSD are remarkably similar, though unfortunately +incompatible.
+
+WSD is made up of two parts, the winsock direct switch and the winsock direct +provider. The WSD switch is in the winsock DLL that ships in all editions of +Windows Server 2003/2008, and is responsible for routing socket traffic over either +the regular TCP/IP stack, or offload it to a WSD provider. The WSD provider is a +hardware specific DLL that implements connection management and data transfers +over particular RDMA hardware.

+

OFED WSD is not supported in the Windows XP environment.

+

The WSD Protocol seamlessly transports TCP + data using Infiniband data packets in 'buffered' mode or Infiniband + RDMA in 'direct' mode. Either way the user mode socket application sees no + behavioral difference in the standard Internet Protocol socket it created other than +reduced data transfer times and increased bandwidth.
+
+The Windows OpenFabrics release includes a WSD provider library that has been +extensively tested with Microsoft Windows Server 2003.
+During testing, bugs where found in the WSD switch that could lead to hangs, +crashes, data corruption, and other unwanted behavior. Microsoft released a +hotfix to address these issues which should be installed if using WSD; the +Microsoft Windows Server 2003 hotfix can be found +here.
+Windows Server 2003 (R2) no longer requires this patch, nor does Windows Server +2008.

+
+
+ + + + +
+
+
+ Environment variables can be used to change the behavior + of the WSD provider:
+
+ IBWSD_NO_READ - Disables RDMA Read operations when set + to any value. Note that this variable must be used + consistently throughout the cluster or communication + will fail.
+
+ IBWSD_POLL - Sets the number of times to poll the + completion queue after processing completions in + response to a CQ event. Reduces latency at the cost of + CPU utilization. Default is 500.
+
+ IBWSD_SA_RETRY - Sets the number of times to retry SA + query requests. Default is 4, can be increased if + connection establishment fails.
+
+ IBWSD_SA_TIMEOUT - Sets the number of milliseconds to + wait before retrying SA query requests. Default is 4, + can be increased if connection establishment fails.
+
+ IBWSD_NO_IPOIB - SA query timeouts by default allow the + connection to be established over IPoIB. Setting this + environment variable to any value prevents fall back to + IPoIB if SA queries time out.
+
+ IBWSD_DBG - Controls debug output when using a debug + version of the WSD provider. Takes a hex value, with + leading '0x', default value is '0x80000000'
+
+  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
0x00000001DLL
0x00000002socket info
0x00000004initialization code
0x00000008WQ related functions
0x00000010Enpoints related functions
0x00000020memory registration
0x00000040CM (Connection Manager)
0x00000080connections
0x00000200socket options
0x00000400network events
0x00000800Hardware
0x00001000Overlapped I/O request
0x00002000Socket Duplication
0x00004000Performance Monitoring
0x01000000More verbose than + IBSP_DBG_LEVEL3
0x02000000More verbose than + IBSP_DBG_LEVEL2
0x04000000More verbose than + IBSP_DBG_LEVEL1
0x08000000Verbose output
0x20000000Function enter/exit
0x40000000Warnings
0x80000000Errors
+
+
+
+
+
+


+See +https://wiki.openfabrics.org/tiki-index.php?page=Winsock+Direct for the +latest WSD status.

+

Winsock Direct Service Provider Installation

+

WSD service +is automatically installed and started as part of the 'default' installation; +except on XP systems - WSD not supported.
+Manual control is performed via the \Program Files\OFED\installsp.exe utility.

+
+

usage: installsp [-i | -r | -l]
+
+ -i    Install the Winsock Direct (WSD) service provider
+ -r    Remove the WSD service provider
+ -r <name>    Remove the specified service provider
+ -l    List service providers

+
+

<return-to-top>

+

 

+
+

NetworkDirect +Service Provider


+

NetworkDirect Service Provider Installation

+

ND service +is automatically installed and started as part of the 'default' installation for +Windows server 2008, Vista or HPC systems.
+Manual control is performed via the %windir%\system32\ndinstall.exe utility.

+
+

usage: ndinstall [-l] [-i | -r [ServiceProvider]]
+
+ where ServiceProvider is 'ibal' or 'winverbs' or blank [blank implies the + default Service Provider 'ibal']

+

-i <name>    Install (enable) the NetworkDirect (ND) + Service Provider 'name'
+ -r <name>    Remove the specified Service Provider + 'name'
+ -l    List all service providers; same as 'ndinstall' with no + args.

+
+

The Microsoft Network Direct SDK can be downloaded from + +here.  Once the ND SDK is installed, ND test programs can be located @
+%ProgramFiles%\Microsoft HPC Pack 2008 SDK\NetworkDirect\Bin\amd64\ as nd*.exe.

+

Known working ND test command invocations (loopback or remote +host)

+
+

svr: ndrpingpong s IPoIB_IPv4_addr 4096 p1
+ cli: ndrpingpong c IPoIB_IPv4_addr 4096 p1

+

svr: ndpingpong s IPoIB_IPv4_addr 4096 b1
+ cli: ndpingpong c IPoIB_IPv4_addr 4096 b1

+
+

See ndping.exe /? for details.

+

<return-to-top>

+

 

+
+

Usermode Direct Access Transport and Direct Access Programming +Libraries

+
+

The DAT (Direct Access Transport) +API is a C programming interface developed by the +DAT Collaborative in +order provide a set of transport-independent, platform-independent Application +Programming Interfaces that exploit the RDMA (remote direct memory access) +capabilities of next-generation interconnect technologies such as InfiniBand, +and iWARP.

+

OFED uDAT and uDAPL are based on the +2.0 DAT specification. The DAPL +(Direct Access Provider Library) which now fully supports Infiniband RDMA and +IPoIB.

+

Previous OFED +releases supported the uDAT/uDAPL 1.1 provider which has now been deprecated.
+uDAT/uDAPL version 2.0 runtime libraries along with an optional +v2.0 application build environment are the only options.
+uDAT 2.0 is configured with InfiniBand extensions enabled. The IB extensions +include

+
    +
  • +

    RDMA write with Immediate data

    +
  • +
  • +

    Atomic Compare and Swap + operation

  • +
  • +

    Atomic Fetch and Add operation
     

    +
  • +
+
+
+ + + + +
+
+
+
+ How  DAT objects map to equivalent + + InfiniBand objects:
+  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Interface Adapter (IA) + HCA (Host Channel Adapter)
Protection Zone (PZ) PD (Protection Domain)
Local Memory Region (LMR) + MR (Memory Region)
Remote Memory Region (RMR) + MW (Memory Windows)
Event Dispatcher (EVD) + CQ (Completion Queue)
Endpoint (EP) QP (Queue Pair)
Public Service Point (PSP) + connection identifier
Reserved Service Point (RSP) + connection identifier
Connection Request (CR) + connection manager event +
+
+
+
+
+
+
+


+ DAT ENVIRONMENT
:

+
+
+

DAT/DAPL 2.0 (free-build) libraries are identified in %SystemRoot%\System32 as + dat2.dll and dapl2.dll.  Debug versions of the v2.0 runtime libraries + are located in '%SystemDrive%\%ProgramFiles%\OFED'.

+

IA32 (aka, 32-bit) + versions of DAT/DAPL 2.0 runtime libraries, found only on 64-bit systems, + are identified in '%ProgramFiles%\OFED' as dat32.dll + and dapl32.dll.

+

In order for DAT/DAPL + programs to execute correctly, the runtime library files 'dat2.dll and + dapl2.dll' must be present in one of the following folders: current + directory, %SystemRoot%, %SystemRoot%\System32 or in the library search path.

+

The default OFED + installation places the runtime library files dat2.dll and dapl2.dll in the '%SystemRoot%\System32' folder; + symbol files (.pdb) are located in '%ProgramFiles%\OFED\'.

+

The default DAPL configuration + file is defined as '%SystemDrive%\DAT\dat.conf'. This default + specification can be overriden by use of the environment variable + DAT_OVERRIDE; see following environment variable discussion.

+

Within the dat.conf file, + the DAPL library specification can be located as the 5th whitespace + separated line argument. By default the DAPL library file is installed as + '%SystemRoot%\System32\dapl2.dll'.

+

Should you choose to + relocated the DAPL library file to a path where whitespace appears in the + full library path specification, then the full library file specification + must be contained within double-quotes. A side effect of the double-quotes + is the library specification is treated as a Windows string which implies + the '\' (backslash character) is treated as an 'escape' character.  Hence + all backslashes in the library path must be duplicated when enclosed in + double-quotes + (e.g., "C:\\Programs Files\\OFED\\dapl.dll").

+

A sample InfiniBand dat.conf file is + installed as '\Program Files\OFED\dat.conf'.  If dat.conf does not + exist in the DAT default configuration folder '%SystemDrive%\DAT\', dat.conf + will be copied there.

+
+

+DAPL Providers

+
+

DAT 2.0 (free-build) + libraries utilize the following user application selectable DAPL providers. + Each DAPL provider represents an RDMA hardware interface device type and + it's Connection Manager.
DAPL providers are listed in the file '%SystemDrive%\DAT\dat.conf'.
The dat.conf InfiniBand DAPL provider names are formatted 'ibnic-HCA#-DAPL_Version-CM_type'.
Example:
    ibnic0v2 - InfiniBand HCA #zero, DAPL version 2.0, (default + CM is IBAL).
    ibnic1v2-scm - InfiniBand HCA #one, DAPL version 2.0, CM is + 'socket-CM'
+    ibnic0v2-cma - InfiniBand HCA #zero, DAPL version 2.0, CM is + 'rdma-CM'

+

Each non-comment line in + the dat.conf file describes a DAPL provider interface.
+ The 2nd to the last field on the right (7th from the left) describes the + ia_device_params (Interface Adapter Device Parameters) (aka, RDMA device) in + accordance with the specific DAPL provider specified in the 5th field. +

+
    +
  • +

    IBAL (eye-ball) DAPL + Provider

    +
      +
    • +

      File: + %windir%\System32\dapl2.dll

    • +
    • +

      dat.conf Provider + name: ibnic0v2

    • +
    • +

      ia_device_params - + 'IbalHcaX Y'
      + where 'X' is the IB HCA device instance (0 == 1st HCA), + Y is the port number (1 == 1st port).

    • +
    +

    Use the InfiniBand Access Layer + (IBAL) Connection + Manager (CM) to establish InfiniBand reliable connections to Windows based system. + IBAL is the original DAPL provider.

  • +
  • +

    Socket-CM Provider

    +
      +
    • +

      File: %windir%\System32\dapl2-ofa-scm.dll

      +
    • +
    • +

      dat.conf + Provider name: ibnic0v2-scm

    • +
    • +

      ia_device_params - + "ibv_deviceX Y"
      + where 'X' is the IB HCA device instance (0 == 1st + HCA), Y is the port number (1 == 1st port). Socket-CM uses Winverbs + hence the ibv_deviceX nomenclature; see ibstat command.

    • +
    +

    To facilitate DAT v2.0 + Windows to Linux DAT v2.0 InfiniBand communications, a BSD socket based Connection Manager (socket-cm) is + supported. Both + nodes must use the same Connection Manager IBAL-CM[ibnic0v2] or + Socket-CM[ibnicv2-scm] in order for connections to be + established. For Linux <==> Windows DAT connections, the DAPL provider must + be socket-cm or rdma-cm; IBAL DAPL provider is not supported on Linux.

  • +
  • +

    RDMA-CM Provider

    +
      +
    • +

      File: %windir%\System32\dapl2-ofa-cma.dll

      +
    • +
    • +

      dat.conf Provider + name: ibnic0v2-cma

    • +
    • +

      ia_device_params - + "rdma_devX Y"
      + where 'X' is the RDMA device instance (future iWARP + support, today InfiniBand) with assigned IPv4 address (0 == 1st + IPoIB device with an assigned IPv4 address); Y is ignored although + there must be a digit present.
      + Alternatively, 'rdma_devX' can be replaced with the IP4v address + assigned to an IPoIB device instance. The 'rdma_dev0' is used to + instruct the rdma-cm provider to use the 1st RDMA device (IPoIB) + with an assigned IP4v address such that the dat.conf file does not + have to be specifically tailored for each OFED installation.

    • +
    +

    OFED RDMA CM manager + can be used to establish connections between Windows and/or Linux systems.

  • +
+

 

+
+

DAT application build environment:

+
+

DAT library header files + are selectively installed in the DAT default configuration folder as
'%SystemDrive%\DAT\v2-0'. + Your C language based DAT application compilation command line + should include'/I%SystemDrive%\DAT\v2-0' with C code referencing '#include <DAT\udat.h>'.
+
+ The 'default' DAT/DAPL C language calling convention is '__stdcall', not the + 'normal' Visual Studio C compiler default. __stdcall was chosen as MS + recommended it to be more efficient. An application can freely mix default C + compiler linkages '__cdecl' and '__stdcall'.
+
+ Visual Studio 2005 command window - (nmake) Makefile Fragments:

+
+

DAT_PATH=%SystemDrive%\DAT\v2-0
+ CC = cl
+ INC_FLAGS = /I $(DAT_PATH)
+
+ CC_FLAGS= /nologo /Gy /W3 /Gm- /GR- /GF /O2 /Oi /Oy- /D_CRT_SECURE_NO_WARNINGS + \
+            /D_WIN64 + /D_X64_ /D_AMD64_ $(INC_FLAGS)
+
+ LINK = link
+ LIBS = ws2_32.lib advapi32.lib User32.lib bufferoverflowU.lib dat.lib
+
+ LINK_FLAGS = /nologo /subsystem:console /machine:X64 + /libpath:$(DAT_PATH) $(LIBS)


+
When linking a DEBUG/Checked version make sure to use dat2d.lib .

+
+
+

DAT library environment variables:

+
+
+DAT_OVERRIDE
+------------
+Value used as the static registry configuration file, overriding the
+default location, 'C:\DAT\dat.conf'.
+
+Example: set DAT_OVERRIDE=%SystemDrive%\path\to\my\private.conf
+
+
+DAT_DBG_LEVEL
+-------------
+
+Value specifies which parts of the registry will print debugging
+information, valid values are 
+
+DAT_OS_DBG_TYPE_ERROR        = 0x1
+DAT_OS_DBG_TYPE_GENERIC      = 0x2
+DAT_OS_DBG_TYPE_SR           = 0x4
+DAT_OS_DBG_TYPE_DR           = 0x8
+DAT_OS_DBG_TYPE_PROVIDER_API = 0x10
+DAT_OS_DBG_TYPE_CONSUMER_API = 0x20
+DAT_OS_DBG_TYPE_ALL          = 0xff
+
+or any combination of these. For example you can use 0xC to get both 
+static and dynamic registry output.
+
+Example set DAT_DBG_LEVEL=0xC
+
+DAT_DBG_DEST
+------------ 
+
+Value sets the output destination, valid values are 
+
+DAT_OS_DBG_DEST_STDOUT = 0x1
+DAT_OS_DBG_DEST_SYSLOG = 0x2 
+DAT_OS_DBG_DEST_ALL    = 0x3 
+
+For example, 0x3 will output to both stdout and the syslog. 
+
+
+

DAPL Provider library environment variables

+
+

DAPL_DBG_TYPE
-------------

+ Value specifies which parts of the registry will print +debugging information, valid values are

+ DAPL_DBG_TYPE_ERR          = 0x0001
DAPL_DBG_TYPE_WARN         = 0x0002
DAPL_DBG_TYPE_EVD          = 0x0004
DAPL_DBG_TYPE_CM           = 0x0008
DAPL_DBG_TYPE_EP           = 0x0010
DAPL_DBG_TYPE_UTIL         = 0x0020
DAPL_DBG_TYPE_CALLBACK     = 0x0040
DAPL_DBG_TYPE_DTO_COMP_ERR = 0x0080
DAPL_DBG_TYPE_API          = 0x0100
DAPL_DBG_TYPE_RTN          = 0x0200
DAPL_DBG_TYPE_EXCEPTION    = 0x0400
+
or any combination of these. For example you can use 0xC to get both
EVD and CM output.
+
Example set DAPL_DBG_TYPE=0xC


DAPL_DBG_DEST
-------------
+
Value sets the output destination, valid values are

DAPL_DBG_DEST_STDOUT = 0x1
DAPL_DBG_DEST_SYSLOG = 0x2 +
DAPL_DBG_DEST_ALL    = 0x3

For example, 0x3 will output to both stdout and the syslog.
+


+

<return-to-top>

+

+
+

DAPLTEST

+
+
+    dapltest - test for the Direct Access Provider Library (DAPL) v2.0
+
+DESCRIPTION
+
+    Dapltest is a set of tests developed to exercise, characterize,
+    and verify the DAPL interfaces during development and porting.
+    At least two instantiations of the test must be run.  One acts
+    as the server, fielding requests and spawning server-side test
+    threads as needed.  Other client invocation connects to the
+    Dapltest server and issue test requests.
+
+    The server side of the test, once invoked, listens continuously
+    for client connection requests, until quit or killed.  Upon
+    receipt of a connection request, the connection is established,
+    the server and client sides swap version numbers to verify that
+    they are able to communicate, and the client sends the test
+    request to the server.  If the version numbers match, and the
+    test request is well-formed, the server spawns the threads
+    needed to run the test before awaiting further connections.
+
+USAGE
+
+    dapltest [ -f script_file_name ]
+             [ -T S|Q|T|P|L ] [ -D device_name ] [ -d ] [ -R HT|LL|EC|PM|BE ]
+
+    With no arguments, dapltest runs as a server using default values,
+    and loops accepting requests from clients.  The -f option allows
+    all arguments to be placed in a file, to ease test automation.
+    The following arguments are common to all tests:
+
+    [ -T S|Q|T|P|L ]    Test function to be performed:
+                            S   - server loop
+                            Q   - quit, client requests that server
+                                  wait for any outstanding tests to
+                                  complete, then clean up and exit
+                            T   - transaction test, transfers data between 
+                                  client and server
+                            P   - performance test, times DTO operations
+                            L   - limit test, exhausts various resources,
+                                  runs in client w/o server interaction
+                        Default: S
+
+    [ -D device_name ]  Specifies the name of the device (interface adapter).
+                        Default: host-specific, look for DT_MdepDeviceName
+                                 in dapl_mdep.h
+
+    [ -d ]              Enables extra debug verbosity, primarily tracing
+			of the various DAPL operations as they progress.
+			Repeating this parameter increases debug spew.
+			Errors encountered result in the test spewing some
+			explanatory text and stopping; this flag provides
+			more detail about what lead up to the error.
+                        Default: zero
+
+    [ -R BE ]           Indicate the quality of service (QoS) desired.
+                        Choices are:
+                            HT  - high throughput
+                            LL  - low latency
+                            EC  - economy (neither HT nor LL)
+                            PM  - premium
+                            BE  - best effort
+                        Default: BE
+
+USAGE - Quit test client
+
+    dapltest [Common_Args] [ -s server_name ]
+
+    Quit testing (-T Q) connects to the server to ask it to clean up and
+    exit (after it waits for any outstanding test runs to complete).
+    In addition to being more polite than simply killing the server,
+    this test exercises the DAPL object teardown code paths.
+    There is only one argument other than those supported by all tests:
+
+    -s server_name      Specifies the name of the server interface.
+                        No default.
+
+
+USAGE - Transaction test client
+
+    dapltest [Common_Args] [ -s server_name ]
+             [ -t threads ] [ -w endpoints ] [ -i iterations ] [ -Q ] 
+             [ -V ] [ -P ] OPclient OPserver [ op3, 
+
+    Transaction testing (-T T) transfers a variable amount of data between 
+    client and server.  The data transfer can be described as a sequence of 
+    individual operations; that entire sequence is transferred 'iterations' 
+    times by each thread over all of its endpoint(s).
+
+    The following parameters determine the behavior of the transaction test:
+
+    -s server_name      Specifies the hostname of the dapltest server.
+                        No default.
+
+    [ -t threads ]      Specify the number of threads to be used.
+                        Default: 1
+
+    [ -w endpoints ]    Specify the number of connected endpoints per thread.
+                        Default: 1
+
+    [ -i iterations ]   Specify the number of times the entire sequence
+                        of data transfers will be made over each endpoint.
+                        Default: 1000
+
+    [ -Q ]              Funnel completion events into a CNO.
+			Default: use EVDs
+
+    [ -V ]              Validate the data being transferred.
+			Default: ignore the data
+
+    [ -P ]		Turn on DTO completion polling
+			Default: off
+
+    OP1 OP2 [ OP3, ... ]
+                        A single transaction (OPx) consists of:
+
+                        server|client   Indicates who initiates the
+                                        data transfer.
+
+                        SR|RR|RW        Indicates the type of transfer:
+                                        SR  send/recv
+                                        RR  RDMA read
+                                        RW  RDMA write
+                        Defaults: none
+
+                        [ seg_size [ num_segs ] ]
+                                        Indicates the amount and format
+                                        of the data to be transferred.
+                                        Default:  4096  1
+                                                  (i.e., 1 4KB buffer)
+
+                        [ -f ]          For SR transfers only, indicates
+                                        that a client's send transfer
+                                        completion should be reaped when
+                                        the next recv completion is reaped.
+					Sends and receives must be paired
+					(one client, one server, and in that
+					order) for this option to be used.
+
+    Restrictions:  
+    
+    Due to the flow control algorithm used by the transaction test, there 
+    must be at least one SR OP for both the client and the server.  
+
+    Requesting data validation (-V) causes the test to automatically append 
+    three OPs to those specified. These additional operations provide 
+    synchronization points during each iteration, at which all user-specified 
+    transaction buffers are checked. These three appended operations satisfy 
+    the "one SR in each direction" requirement.
+
+    The transaction OP list is printed out if -d is supplied.
+
+USAGE - Performance test client
+
+    dapltest [Common_Args] -s server_name [ -m p|b ]
+             [ -i iterations ] [ -p pipeline ] OP
+
+    Performance testing (-T P) times the transfer of an operation.
+    The operation is posted 'iterations' times.
+
+    The following parameters determine the behavior of the transaction test:
+
+    -s server_name      Specifies the hostname of the dapltest server.
+                        No default.
+
+    -m b|p		Used to choose either blocking (b) or polling (p)
+                        Default: blocking (b)
+
+    [ -i iterations ]   Specify the number of times the entire sequence
+                        of data transfers will be made over each endpoint.
+                        Default: 1000
+
+    [ -p pipeline ]     Specify the pipline length, valid arguments are in 
+                        the range [0,MAX_SEND_DTOS]. If a value greater than 
+                        MAX_SEND_DTOS is requested the value will be
+                        adjusted down to MAX_SEND_DTOS.
+                        Default: MAX_SEND_DTOS
+
+    OP
+                        An operation consists of:
+
+                        RR|RW           Indicates the type of transfer:
+                                        RR  RDMA read
+                                        RW  RDMA write
+                        Default: none
+
+                        [ seg_size [ num_segs ] ]
+                                        Indicates the amount and format
+                                        of the data to be transferred.
+                                        Default:  4096  1
+                                                  (i.e., 1 4KB buffer)
+
+USAGE - Limit test client
+
+    Limit testing (-T L) neither requires nor connects to any server
+    instance.  The client runs one or more tests which attempt to
+    exhaust various resources to determine DAPL limits and exercise
+    DAPL error paths.  If no arguments are given, all tests are run.
+
+    Limit testing creates the sequence of DAT objects needed to
+    move data back and forth, attempting to find the limits supported
+    for the DAPL object requested.  For example, if the LMR creation
+    limit is being examined, the test will create a set of
+    {IA, PZ, CNO, EVD, EP} before trying to run dat_lmr_create() to
+    failure using that set of DAPL objects.  The 'width' parameter
+    can be used to control how many of these parallel DAPL object
+    sets are created before beating upon the requested constructor.
+    Use of -m limits the number of dat_*_create() calls that will
+    be attempted, which can be helpful if the DAPL in use supports
+    essentailly unlimited numbers of some objects.
+
+    The limit test arguments are:
+
+    [ -m maximum ]      Specify the maximum number of dapl_*_create()
+                        attempts.
+                        Default: run to object creation failure
+
+    [ -w width ]        Specify the number of DAPL object sets to
+                        create while initializing.
+                        Default: 1
+
+    [ limit_ia ]        Attempt to exhaust dat_ia_open()
+
+    [ limit_pz ]        Attempt to exhaust dat_pz_create()
+
+    [ limit_cno ]       Attempt to exhaust dat_cno_create()
+
+    [ limit_evd ]       Attempt to exhaust dat_evd_create()
+
+    [ limit_ep ]        Attempt to exhaust dat_ep_create()
+
+    [ limit_rsp ]       Attempt to exhaust dat_rsp_create()
+
+    [ limit_psp ]       Attempt to exhaust dat_psp_create()
+
+    [ limit_lmr ]       Attempt to exhaust dat_lmr_create(4KB)
+
+    [ limit_rpost ]     Attempt to exhaust dat_ep_post_recv(4KB)
+
+    [ limit_size_lmr ]  Probe maximum size dat_lmr_create()
+
+                        Default: run all tests
+
+
+EXAMPLES
+
+    dapltest -T S -d -D ibnic0v2
+
+                        Starts a local dapltest server process with debug verbosity.
+                        Server loops (listen for dapltest request, process request).
+    
+    dapltest -T T -d -s winIB -D ibnic0v2 -i 100 client SR 4096 2 server SR 4096 2
+
+                        Runs a transaction test, with both sides
+                        sending one buffer with two 4KB segments,
+                        one hundred times; dapltest server is on host winIB.
+
+    dapltest -T P -d -s winIB -D ibnic0v2 -i 100 RW 4096 2
+
+                        Runs a performance test, with the client 
+                        RDMA writing one buffer with two 4KB segments,
+                        one hundred times.
+
+    dapltest -T Q -s winIB -D ibnic0v2
+
+                        Asks the dapltest server at host 'winIB' to clean up and exit.
+
+    dapltest -T L -D ibnic0v2 -d -w 16 -m 1000
+
+                        Runs all of the limit tests, setting up
+                        16 complete sets of DAPL objects, and
+                        creating at most a thousand instances
+                        when trying to exhaust resources.
+
+    dapltest -T T -V -d -t 2 -w 4 -i 55555 -s winIB -D ibnic0v2 \
+       client RW  4096 1    server RW  2048 4    \
+       client SR  1024 4    server SR  4096 2    \
+       client SR  1024 3 -f server SR  2048 1 -f
+
+                        Runs a more complicated transaction test,
+                        with two thread using four EPs each,
+                        sending a more complicated buffer pattern
+                        for a larger number of iterations,
+                        validating the data received.
+
+dt-svr.bat - DAPLtest server script; starts a DAPL2test.exe server on the local system.
+	dt-svr DAPL-provider [-D [hex-debug-bitmask] ]
+
+
+
where: DAPL-provider can be one of [ ibal | scm | cma ]
+
+
    +
  • +
    ibal - Original InfiniBand Access Layer (eye-bal) ibal verbs interface
    +
  • +
  • +
    scm - Socket-CM (Connection Manager), exchanges QP information over a n IP socket.
    +
  • +
  • +
    cma - rdma CM, use the OFED rdma Communications Manager to create the QP connection.
    +
  • +
  • +
    or the DAPL-provider name from %SystemDrive%\DAT\dat.conf
    +
  • +
+
+
+
+
dt-cli.bat - DAPLtest client; drives testing by interacting with dt-svr.bat script.
+	dt-cli DAPL-provider host-IPv4-address testname [-D [hex-debug-bitmask] ]
+		example: dt-cli ibnic0v2 10.10.2.20 trans
+		         dt-cli -h  # outputs help text.
+			 dt-svr ibnic0v2	# IBAL dapltest server listening on port HCA0
+
+Verify dt-*.bat script is running same dapl2test.exe(DAPL v2.0)
+
+
+BUGS  (and To Do List)
+
+    Use of CNOs (-Q) is not yet supported.
+
+    Further limit tests could be added.
+

<return-to-top>

+

 

+

 

+
+

SRP (SCSI RDMA) Protocol Driver

+
+

+The +SCSI RDMA +Protocol  (SRP) is an emerging industry standard protocol for utilizing +block storage devices over an InfiniBand™ fabric. SRP is being defined in the +ANSI T-10 committee.

+

OFED SRP is a storage +driver implementation that enables the SCSI RDMA protocol over an InfiniBand +fabric.
+The implementation conforms +to the T10 Working Group draft + +http://www.t10.org/ftp/t10/drafts/srp/srp-r16a.pdf.

+

Software Dependencies

+

The SRP driver depends on the installation of the OFED stack +with a Subnet
+Manager running somewhere on the IB fabric.
+
+- Supported Operating Systems and Service Packs:
+   o Windows 7 (x86 & x64)
+   o Windows Server 2008 R2  (x86, x64)
+   o Windows Server 2008/Vista  (x86, x64)
+   o Windows Server 2008 HPC (x64,x86)
+   o Windows Server 2003 SP2/R2 (x86, x64, IA64)

+

Testing Levels

+

The SRP driver has undergone basic testing against Mellanox +Technologies' +SRP Targets MTD1000 and MTD2000.
+Additionally the Linux OFED 1.4.1 SRP target with scst 1.0.0.0 (vdisk with +blockio) has been tested.  Note: ONLY the scst-1.0.0.0 release will work as +the OFED 1.4.1 ib_srpt driver has a symbol dependency on scst. later releases of +scst.ko no longer export the required symbol hence ib_srpt fails to load.
+When ib_srpt is updated later versions of scst can be used.
+
+Testing included SRP target drive format, read, write and dismount/offline +operations.

+

Installation

+

The OFED installer does not install the SRP driver as part of a default +installation.  +If the SRP feature is selected in the custom features installation view, an InfiniBand +SRP Miniport driver will be installed; see the device manager view under SCSI +and RAID controllers.

+

The system device 'InfiniBand I/O Unit' (IOU) +device is required for correct SRP operation.  The OFED installer will +install and load the IOU driver if the SRP feature is selected.  See the device +manager view System Devices --> InfiniBand I/O Unit for conformation of correct +IOU driver loading.

+

In order for the SRP miniport driver installation to complete, an SRP target must be +detected by a Subnet Manager running somewhere on the InfiniBand fabric; either +a local or remote Subnet Manager works.

+

SRP Driver Uninstall

+

If the SRP (SCSI RDMA Protocol) driver has been previously +installed, then in order to achieve a 'clean' uninstall, the SRP target drive(s) +must be released.  Unfortunately the 'offline disk' command is only valid +for diskpart (ver 6.0.6001) which is not distributed with Windows Server 2003 or +XP.

+
    +
  • Use the following diskpart.exe commands from an administrator privileged + command window:
  • +
  • + + c:\windows\temp> diskpart.exe
    +    SELECT VOLUME=<Drive Letter of the SRP target to be released>        + # example: SELECT VOLUME=L
    +    OFFLINE DISK
    +    EXIT
  • +
  • For additional SRP drives, repeat SELECT & OFFLINE DISK with new Drive + Letter.
  • +
+

The consequences of not releasing the SRP target drive(s) are that after the +OFED uninstall reboot there are lingering InfiniBand driver files. These driver +files remain because while the SRP target is active they have references, thus +when the OFED uninstall attempts to delete the files the operation fails.

+

SRP supports WPP tracing tools by using the GUID: +'5AF07B3C-D119-4233-9C81-C07EF481CBE6'.  The flags and level of debug can be controlled at load-time or run-time; +see ib_srp.inf file for details.

+

Constructing a RHEL 5.1 OFED 1.4.1 SRP vdisk BLOCKIO target

+

Example assumptions:

+
    +
  • +

    Red Hat Enterprise Linux Server release 5 (Tikanga) EL 5.1 + (2.6.18-8.el5)
    + Later RHEL 5.4 releases will work with some minor scst compile time fixes + and later OFED releases.

  • +
  • +

    Linux SRP Target has /dev/sdb[123]
    + sizeof(sdb1) < sdb2 < sdb3; test convention only.

  • +
  • +

    scst-1.0.0.tgz is required as OFED 1.4.1 ib_srpt has symbol + dependency on
    + scst.ko....sigh. Later scst release do not export the required ib_srpt
    + symbol; stick with scst-1.0.0 until OFED ib_srpt is updated.

  • +
  • +

    + download scst-1.0.0

  • +
+

Use out of the box scst defines which include (#undef +STRICT_SERIALIZING),
+'no' kernel mods are required for BLOCKIO access to /dev/sdb[123].
+
+cd scst-1.0.0.0
+make all
+make install
+
+cd OFED-1.4.1
+build OFED select #3 for 'all' OFED components
+  - no SRP loads in /etc/infiniband/openib.conf, edit prior to reboot.

+

REBOOT.
+
+./LOAD & ./UNLOAD scripts are manual versions of what scstAdmin (separate scst +package) will do minus
+loading the OFED driver ib_srpt.
+
+SRP targets formatted from Windows using default NTFS allocation size.
+Partition size & numbering is derrived from local test conventions; your setup +will be different.
+
+/dev/sdb1 NTFS < 1GB
+/dev/sdb2 NTFS > 1GB
+/dev/sdb3 NTFS > sdb2

+

 

+

Manual SRP Target LOAD script

+
+
#!/bin/sh 
+
+GRP=Default
+
+if [ ! -e /proc/scsi_tgt ] ; then
+  echo -n Loading scst driver
+  modprobe scst
+  if [ $? -ne 0 ] ; then
+    echo
+    echo err $? modprobe scst
+    exit $?
+  fi
+  echo ...OK
+fi 
+
+if [ ! -e /proc/scsi_tgt/vdisk ] ; then
+  echo -n Loading scst_vdisk driver
+  modprobe scst_vdisk
+  if [ $? -ne 0 ] ; then
+    echo
+    echo err $? modprobe scst_vdisk
+    exit $?
+  fi
+  echo ...OK
+fi 
+
+if [ ! -e /proc/scsi_tgt/vdisk ] ; then
+  echo -n Loading scst_vdisk driver
+  modprobe scst_vdisk
+  if [ $? -ne 0 ] ; then
+    echo
+    echo err $? modprobe scst_vdisk
+    exit $?
+  fi
+  echo ...OK
+fi 
+
+fgrep -q ib_srpt /proc/modules
+if [ $? -ne 0 ] ; then
+  modprobe ib_srpt
+  echo ib_srpt...OK
+fi 
+
+echo -n Open SRP devices srp[123]
+echo "open srp1 /dev/sdb1 512 BLOCKIO" > /proc/scsi_tgt/vdisk/vdisk
+if [ $? -ne 0 ] ; then
+  echo err $? open srp1 /dev/sdb1
+  exit $?
+fi
+echo "open srp2 /dev/sdb2 512 BLOCKIO" > /proc/scsi_tgt/vdisk/vdisk
+if [ $? -ne 0 ] ; then
+  echo err $? open srp2 /dev/sdb2
+  exit $?
+fi
+echo "open srp3 /dev/sdb3 512 BLOCKIO" > /proc/scsi_tgt/vdisk/vdisk
+if [ $? -ne 0 ] ; then
+  echo err $? open srp3 /dev/sdb3
+  exit $?
+fi
+echo ...OK
+
+echo -n Set allowed hosts access...
+echo "add *" > /proc/scsi_tgt/groups/Default/names
+echo ...OK
+
+echo -n Adding targets srp[123] as LUNs [012] in group $GRP
+echo "add srp1 0" > /proc/scsi_tgt/groups/Default/devices
+if [ $? -ne 0 ] ; then
+  echo
+  echo err $? add srp1 0
+  exit $?
+fi
+echo "add srp2 1" > /proc/scsi_tgt/groups/Default/devices
+if [ $? -ne 0 ] ; then
+  echo
+  echo err $? add srp2 1
+  exit $?
+fi
+echo "add srp3 2" > /proc/scsi_tgt/groups/Default/devices
+if [ $? -ne 0 ] ; then
+  echo
+  echo err $? add srp3 2
+  exit $?
+fi
+echo ...OK
+
+
+
+

Manual SRP Target UNLOAD script

+
#!/bin/sh
+
+if [ -w /proc/scsi_tgt/vdisk/vdisk ] ; then
+  echo -n Closing SRP Targets srp[321]...
+  echo "close srp3" > /proc/scsi_tgt/vdisk/vdisk
+  echo "close srp2" > /proc/scsi_tgt/vdisk/vdisk
+  echo "close srp1" > /proc/scsi_tgt/vdisk/vdisk
+  echo Done.
+fi
+
+fgrep -q scst_vdisk /proc/modules
+if [ $? -eq 0 ] ; then
+  modprobe -r scst_vdisk
+fi
+
+fgrep -q ib_srpt /proc/modules
+if [ $? -eq 0 ] ; then
+  modprobe -r ib_srpt
+fi
+
+fgrep -q scst /proc/modules
+if [ $? -eq 0 ] ; then
+  modprobe -r scst
+fi
+
+
+

<return-to-top>

+

 

+
+

QLogic VNIC Configuration

+
+

+The QLogic VNIC +(Virtual Network Interface Card) driver in conjunction with the QLogic Ethernet +Virtual I/O Controller (EVIC) provides virtual Ethernet interfaces and transport +for Ethernet packets over Infiniband.
+
+Users can modify NIC parameters through User Interface icon in Network +Connections:
+( Properties->"Configure..." button -> "Advanced" Tab).

+

+Parameters +available:
+
+Vlan Id (802.1Q) 

+

+  values from 0 to +4094 ( default 0, disabled )
+  This specifies if VLAN ID-marked packet transmission is enabled and, if so, +specifies the ID.
+
+Priority (802.1P)

+

+  values from 0 to 7 +( default 0, feature disabled)
+  This specifies if priority-marked packet transmission is enabled.
+
+Payload MTU size 

+

+  values from 1500 +to 9500 (default 1500)
+  This specifies the maximum transfer unit size in 100 bytes increments.
+
+Recv ChkSum offload 

+

+  (default enabled)
+  This specifies if IP protocols checksum calculations for receive is offloaded.
+
+Send ChkSum offload

+

+  (default enabled)
+  This specifies if IP protocols checksum calculations for send is offloaded.

+

+Secondary Path 

+

+   (default +disabled)
+   Enabled - If more than one IB path to IOC exist then secondary IB instance of +virtual port will be created and configured with the same parameters as primary +one. Failover from Primary to Secondary IB path is transparent for user +application sending data through associated NIC.
+
+   Disabled – only one path at a time is allowed. If more than one path to IOC +exists then failed path will be destroyed and next available path will be used +for new connection. With this scenario there is a possibility new interface +instance will be assigned different MAC address when other hosts compete for +EVIC resources.

+

+LBFO Bundle Id
+   (default disabled) Enabling support for OS provided Load Balancing and Fail +Over functionality on adapter level.
+   If enabled group ID can be selected from predefined names.

+

+ 

+

+Heartbeat interval

+

+   configures +interval for VNIC protocol heartbeat messages in milliseconds.
+   0 – heartbeats disabled.
+
+Note:
+   To take advantage of the features supported by these options, ensure that the +Ethernet gateway is also configured appropriately.  For example, if the Payload +MTU for a VNIC interface is set to 4000, +the MTU at the EVIC module must also be set at least 4000 +for the setting to take effect.

+
+

 <return-to-top>

+

 

+

QLogic VNIC Child Device Management

+
+

+Each I/O Controller (IOC) of QLogic's EVIC gateway +device is able to handle 256 connections per host. So a single host can have multiple VNIC interfaces connecting to the same +IOC. So qlgcvnic_config can be used to create multiple VNIC interfaces by giving local channel adapter node guid and +target ioc guid parameters as input.

+

+ +Usage: +

+Create child vnic devices +

+qlgcvnic_config -c {caguid}  {iocguid}  {instanceid}  {interface description} +

+caguid -- Local HCA node guid value in hex format (may start with "0x") +
+iocguid -- Target IOC's guid vale in hex format (may start with "0x") +
+instanceid -- InstanceID is used to distinguish between different child devices created by IBAL. So this must be a unique +value. InstanceID is a 32bit value. User input should be in decimal format. +
+interface description -- Description that should be shown in device manager's device tree for the child device. +

+Listing Channel Adapter to IOC paths +

+Executing qlgcvnic_config without any option or with -l option will list the IOCs reachable from the host. +
+ +

 <return-to-top>

+

 

+
+

OFED Software +Development Kit

+
+

If selected during install, the OFED Software Development Kit will +be installed as '%SystemDrive%\OFED_SDK'. Underneath the OFED_SDK\ folder you will find +the following folders:

+
    +
  •  'Inc\'    include files
  • +
  • 'Lib\'ibrary definition files
  • +
  • 'Samples' example codes to demonstrate building and use of OFED + interfaces.
  • +
+

Compilation:

+
+

Add the additional include path '%SystemDrive%\OFED_SDK\Inc'; resource files + may also use this path.

+
+

Linking:

+
+

Add the additional library search path '%SystemDrive%\OFED_SDK\Lib'.

+

Include dependent libraries: ibal.lib and complib.lib, or ibal32.lib & + complib32.lib for win32 applications on 64-bit platforms.

+
+

Samples:

+
    +
  • WDK\    demonstrates how to build an OFED application in the Windows + Driver Kit (WDK) environment.
    + Consult the README.txt file for details.
    + See + http://www.microsoft.com/whdc/Devtools/wdk/default.mspx  for WDK details.
  • +
  • rdma_bw\    demonstrates how to build an OFED IB verbs + application in the Visual Studio environment.
    + Consult the README.txt file for details.
  • +
  • cmtest\    demonstrates how to build an IB (ibal) application in the + Visual Studio environment.
    + Consult the README.txt file for details.
  • +
+ +

<return-to-top>

+

 

+

OFED InfiniBand Verbs

+
+ + +

NAME
+
    +libibverbs.lib - OpenFabrics Enterprise Distribution (OFED) Infiniband verbs library

+SYNOPSIS
+

    +#include <infiniband/verbs.h>
+
DESCRIPTION

+
+

This library is an implementation of the verbs based on the Infiniband +specification volume 1.2 chapter 11. It handles the control path of creating, +modifying, querying and destroying resources such as Protection Domains (PD), +Completion Queues (CQ), Queue-Pairs (QP), Shared Receive Queues (SRQ), Address +Handles (AH), Memory Regions (MR). It also handles sending and receiving data +posted to QPs and SRQs, getting completions from CQs using polling and +completions events.

The control path is implemented through system calls to the uverbs kernel module +which further calls the low level HW driver. The data path is implemented through +calls made to low level HW library which in most cases interacts directly with +the HW providing kernel and network stack bypass (saving context/mode switches) +along with zero copy and an asynchronous I/O model.

Typically, under network and RDMA programming, there are operations which +involve interaction with remote peers (such as address resolution and connection +establishment) and remote entities (such as route resolution and joining a +multicast group under IB), where a resource managed through IB verbs such as QP +or AH would be eventually created or effected from this interaction. In such +cases, applications whose addressing semantics is based on IP can use librdmacm +(see rdma_cm) which works in conjunction with libibverbs.

This library is thread safe library and verbs can be called from every thread in +the process (the same resource can even be handled from different threads, for +example: ibv_poll_cq can be called from more than one thread).

However, it is up to the user to stop working with a resource after it was +destroyed (by the same thread or by any other thread), this may result a +segmentation fault.

+

The following shall be declared as functions and may also be defined as +macros.

+
+
+

Function prototypes are provided in + + %SystemDrive%\OFED_SDK\inc\infiniband\verbs.h.
+
Link to + %SystemDrive%\OFED_SDK\lib\libibverbs.lib

+
+

Device functions

+
+

struct ibv_device **ibv_get_device_list(int *num_devices);

+

void ibv_free_device_list(struct ibv_device **list);

+

const char *ibv_get_device_name(struct ibv_device *device);

+

uint64_t ibv_get_device_guid(struct ibv_device *device);

+
+

Context functions

+
+

struct ibv_context *ibv_open_device(struct ibv_device *device);

+

int ibv_close_device(struct ibv_context *context);

+
+

Queries

+
+

int ibv_query_device(struct ibv_context *context, +struct ibv_device_attr *device_attr);

+

int ibv_query_port(struct ibv_context *context, uint8_t port_num, +struct ibv_port_attr *port_attr);

+

int ibv_query_pkey(struct ibv_context *context, uint8_t port_num, +int index, uint16_t *pkey);

+

int ibv_query_gid(struct ibv_context *context, uint8_t port_num, +int index, union ibv_gid *gid);

+
+

Asynchronous events

+
+

int ibv_get_async_event(struct ibv_context *context, +struct ibv_async_event *event);

+

void ibv_ack_async_event(struct ibv_async_event *event);

+
+

Protection Domains

+
+

struct ibv_pd *ibv_alloc_pd(struct ibv_context *context);

+

int ibv_dealloc_pd(struct ibv_pd *pd);

+
+

Memory Regions

+
+

struct ibv_mr *ibv_reg_mr(struct ibv_pd *pd, void *addr, +size_t length, enum ibv_access_flags access);

+

int ibv_dereg_mr(struct ibv_mr *mr);

+
+

Address Handles

+
+

struct ibv_ah *ibv_create_ah(struct ibv_pd *pd, struct ibv_ah_attr *attr);

int + ibv_init_ah_from_wc(struct ibv_context *context, uint8_t port_num, +struct ibv_wc *wc, struct ibv_grh *grh, +struct ibv_ah_attr *ah_attr);

struct ibv_ah *ibv_create_ah_from_wc(struct ibv_pd *pd, struct ibv_wc *wc, +struct ibv_grh *grh, uint8_t port_num);

int ibv_destroy_ah(struct ibv_ah *ah);

+
+

Completion event channels

+
+

struct ibv_comp_channel *ibv_create_comp_channel(struct ibv_context + *context);

+
+
+

int ibv_destroy_comp_channel(struct ibv_comp_channel *channel);

+
+

Completion Queues Control

+
+

struct ibv_cq *ibv_create_cq(struct ibv_context *context, int cqe, +void *cq_context, +struct ibv_comp_channel *channel, +int comp_vector);

int ibv_destroy_cq(struct ibv_cq *cq);

int + ibv_resize_cq(struct ibv_cq *cq, int cqe);

+
+

Reading Completions from CQ

+
+

int ibv_poll_cq(struct ibv_cq *cq, int num_entries, struct ibv_wc *wc);

+
+

Requesting / Managing CQ events

+
+

int ibv_req_notify_cq(struct ibv_cq *cq, int solicited_only);

+

int ibv_get_cq_event(struct ibv_comp_channel *channel, +struct ibv_cq **cq, void **cq_context);

+

void ibv_ack_cq_events(struct ibv_cq *cq, unsigned int nevents);

+
+

Shared Receive Queue control

+
+

struct ibv_srq *ibv_create_srq(struct ibv_pd *pd, struct ibv_srq_init_attr *srq_init_attr);
+
int ibv_destroy_srq(struct ibv_srq *srq);

int + ibv_modify_srq(struct ibv_srq *srq, struct ibv_srq_attr *srq_attr, enum ibv_srq_attr_mask srq_attr_mask);
+
int ibv_query_srq(struct ibv_srq *srq, struct ibv_srq_attr *srq_attr);

+
+

eXtended Reliable Connection control

+
+

struct ibv_xrc_domain *ibv_open_xrc_domain(struct ibv_context *context, int fd, int oflag);
+
int ibv_close_xrc_domain(struct ibv_xrc_domain *d);

struct ibv_srq *ibv_create_xrc_srq(struct ibv_pd *pd, struct ibv_xrc_domain *xrc_domain, struct ibv_cq *xrc_cq, struct ibv_srq_init_attr *srq_init_attr);
+
int ibv_create_xrc_rcv_qp(struct ibv_qp_init_attr *init_attr, uint32_t *xrc_rcv_qpn);
+
int ibv_modify_xrc_rcv_qp(struct ibv_xrc_domain *xrc_domain, uint32_t xrc_qp_num, struct ibv_qp_attr *attr, int attr_mask);
+
int ibv_query_xrc_rcv_qp(struct ibv_xrc_domain *xrc_domain, uint32_t xrc_qp_num, struct ibv_qp_attr *attr, int attr_mask, struct ibv_qp_init_attr *init_attr);
+
int ibv_reg_xrc_rcv_qp(struct ibv_xrc_domain *xrc_domain, uint32_t xrc_qp_num);
+
int ibv_unreg_xrc_rcv_qp(struct ibv_xrc_domain *xrc_domain, uint32_t xrc_qp_num);

+
+

Queue Pair control

+
+

struct ibv_qp *ibv_create_qp(struct ibv_pd *pd, struct ibv_qp_init_attr *qp_init_attr);
+
int ibv_destroy_qp(struct ibv_qp *qp);

int + ibv_modify_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr, enum ibv_qp_attr_mask attr_mask);
+
int ibv_query_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr, enum ibv_qp_attr_mask attr_mask, struct ibv_qp_init_attr *init_attr);

+
+

Posting Work Requests to QPs/SRQs

+
+

int ibv_post_send(struct ibv_qp *qp, struct ibv_send_wr *wr, struct ibv_send_wr **bad_wr);
+
int ibv_post_recv(struct ibv_qp *qp, struct ibv_recv_wr *wr, struct ibv_recv_wr **bad_wr);
+
int ibv_post_srq_recv(struct ibv_srq *srq, struct ibv_recv_wr *recv_wr, struct ibv_recv_wr **bad_recv_wr);

+
+

Multicast group

+
+

int ibv_attach_mcast(struct ibv_qp *qp, union ibv_gid *gid, uint16_t lid);

+

int ibv_detach_mcast(struct ibv_qp *qp, union ibv_gid *gid, uint16_t lid);

+
+

General functions

+
+

int ibv_rate_to_mult(enum ibv_rate rate);

enum ibv_rate + mult_to_ibv_rate(int mult);
 

+
+

SEE ALSO

+
+

ibv_get_device_list, + ibv_free_device_list,
+ ibv_get_device_name, + ibv_get_device_guid, + ibv_open_device,
+ ibv_close_device, + ibv_query_device, + ibv_query_port,
+ ibv_query_pkey, ibv_query_gid, + ibv_get_async_event,
+ ibv_ack_async_event, + ibv_alloc_pd, ibv_dealloc_pd, + ibv_reg_mr,
ibv_dereg_mr, + ibv_create_ah, ibv_init_ah_from_wc, + ibv_create_ah_from_wc,
+ ibv_destroy_ah, + ibv_create_comp_channel,
+ ibv_destroy_comp_channel, + ibv_create_cq, ibv_destroy_cq,
+ ibv_resize_cq, ibv_poll_cq, + ibv_req_notify_cq,
+ ibv_get_cq_event, + ibv_ack_cq_events, + ibv_create_srq,
ibv_destroy_srq, + ibv_modify_srq, ibv_query_srq,
+ ibv_open_xrc_domain, + ibv_close_xrc_domain, + ibv_create_xrc_srq,
+ ibv_create_xrc_rcv_qp, + ibv_modify_xrc_rcv_qp,
+ ibv_query_xrc_rcv_qp, + ibv_reg_xrc_rcv_qp, + ibv_unreg_xrc_rcv_qp,
+ ibv_post_srq_recv, ibv_create_qp, + ibv_destroy_qp, ibv_modify_qp,
+ ibv_query_qp, ibv_post_send, + ibv_post_recv,
ibv_attach_mcast, + ibv_detach_mcast, + ibv_rate_to_mult, + mult_to_ibv_rate

+
+


AUTHORS

+
+

Dotan Barak <dotanb@mellanox.co.il>
Or Gerlitz <ogerlitz@voltaire.com>
Stan Smith <stan.smith@intel.com>

+
+

+ +<return-to-top>

+

 

+

IBV_GET_DEVICE_LIST

+

IBV_FREE_DEVICE_LIST

+
+

NAME

+ibv_get_device_list, ibv_free_device_list - get and release list of available +RDMA devices

SYNOPSIS

+
#include <infiniband/verbs.h>
+
+struct ibv_device **ibv_get_device_list(int *num_devices);
+
+void ibv_free_device_list(struct ibv_device **list);
+

DESCRIPTION

+ibv_get_device_list() returns a NULL-terminated array of RDMA devices +currently available. The argument num_devices is optional; if not NULL, +it is set to the number of devices returned in the array. +

ibv_free_device_list() frees the array of devices list returned +by ibv_get_device_list().

+

RETURN VALUE

+ibv_get_device_list() returns the array of available RDMA devices, or +sets errno and returns NULL if the request fails. If no devices are found +then num_devices is set to 0, and non-NULL is returned. +

ibv_free_device_list() returns no value.

+

ERRORS

+
+
EPERM
+
Permission denied. +
+
ENOSYS
+
No kernel support for RDMA. +
+
ENOMEM
+
Insufficient memory to complete the operation.
+
+

NOTES

+Client code should open all the devices it intends to use with +ibv_open_device() before calling ibv_free_device_list(). Once it +frees the array with ibv_free_device_list(), it will be able to use only +the open devices; pointers to unopened devices will no longer be valid. +  +

SEE ALSO

+ibv_get_device_name, +ibv_get_device_guid, +ibv_open_device

 

+

IBV_GET_DEVICE_GUID

+
+

NAME

+ibv_get_device_guid - get an RDMA device's GUID +

SYNOPSIS

+
#include <infiniband/verbs.h>
+
+uint64_t ibv_get_device_guid(struct ibv_device *device); 
+

DESCRIPTION

+ibv_get_device_name() returns the Global Unique IDentifier (GUID) of the +RDMA device device.

RETURN VALUE

+ibv_get_device_guid() returns the GUID of the device in network byte +order.   +

SEE ALSO

+ibv_get_device_list, +ibv_get_device_name, +ibv_open_device

 

+


+IBV_GET_DEVICE_NAME

+
+

NAME

+ibv_get_device_name - get an RDMA device's name

SYNOPSIS

+
#include <infiniband/verbs.h>
+
+const char *ibv_get_device_name(struct ibv_device *device);
+

DESCRIPTION

+ibv_get_device_name() returns a human-readable name associated with the +RDMA device device.

RETURN VALUE

+ibv_get_device_name() returns a pointer to the device name, or NULL if +the request fails.

SEE ALSO

+ibv_get_device_list, +ibv_get_device_guid, +ibv_open_device

+
+
+IBV_OPEN_DEVICE

+

IBV_CLOSE_DEVICE

+
+

NAME

+ibv_open_device, ibv_close_device - open and close an RDMA device context +

SYNOPSIS

+
#include <infiniband/verbs.h>
+
+struct ibv_context *ibv_open_device(struct ibv_device *device);
+
+int ibv_close_device(struct ibv_context *context);
+
+

DESCRIPTION

+ibv_open_device() opens the device device and creates a context +for further use. +

ibv_close_device() closes the device context context.

+

RETURN VALUE

+ibv_open_device() returns a pointer to the allocated device context, or +NULL if the request fails. +

ibv_close_device() returns 0 on success, -1 on failure.

+

NOTES

+ibv_close_device() does not release all the resources allocated using +context context. To avoid resource leaks, the user should release all +associated resources before closing a context. +

SEE ALSO

+ibv_get_device_list, +ibv_query_device, +ibv_query_port, +ibv_query_gid, ibv_query_pkey

 

+

 

+


+IBV_GET_ASYNC_EVENT

+

+
+
+IBV_ACK_ASYNC_EVENT

+
+

NAME

+ibv_get_async_event, ibv_ack_async_event - get or acknowledge asynchronous +events   +

SYNOPSIS

+
#include <infiniband/verbs.h>
+
+int ibv_get_async_event(struct ibv_context *context,
+                        struct ibv_async_event *event);
+
+void ibv_ack_async_event(struct ibv_async_event *event);
+

DESCRIPTION

+ibv_get_async_event() waits for the next async event of the RDMA device +context context and returns it through the pointer event, which is +an ibv_async_event struct, as defined in <infiniband/verbs.h>. +

+
struct ibv_async_event {
+union {
+struct ibv_cq  *cq;             /* CQ that got the event */
+struct ibv_qp  *qp;             /* QP that got the event */
+struct ibv_srq *srq;            /* SRQ that got the event */
+int             port_num;       /* port number that got the event */
+} element;
+enum ibv_event_type     event_type;     /* type of the event */
+};
+
+

One member of the element union will be valid, depending on the event_type +member of the structure. event_type will be one of the following events:

+

QP events:

+
+
IBV_EVENT_QP_FATAL Error occurred on a QP and it transitioned to + error state
+
+
IBV_EVENT_QP_REQ_ERR Invalid Request Local Work Queue Error
+
+
IBV_EVENT_QP_ACCESS_ERR Local access violation error
+
+
IBV_EVENT_COMM_EST Communication was established on a QP
+
+
IBV_EVENT_SQ_DRAINED Send Queue was drained of outstanding + messages in progress
+
+
IBV_EVENT_PATH_MIG A connection has migrated to the alternate + path
+
+
IBV_EVENT_PATH_MIG_ERR A connection failed to migrate to the + alternate path
+
+
IBV_EVENT_QP_LAST_WQE_REACHED Last WQE Reached on a QP associated + with an SRQ
+
+
+

CQ events:

+
+
IBV_EVENT_CQ_ERR CQ is in error (CQ overrun)
+
+
+

SRQ events:

+
+
IBV_EVENT_SRQ_ERR Error occurred on an SRQ
+
+
IBV_EVENT_SRQ_LIMIT_REACHED SRQ limit was reached
+
+
+

Port events:

+
+
IBV_EVENT_PORT_ACTIVE Link became active on a port
+
+
IBV_EVENT_PORT_ERR Link became unavailable on a port
+
+
IBV_EVENT_LID_CHANGE LID was changed on a port
+
+
IBV_EVENT_PKEY_CHANGE P_Key table was changed on a port
+
+
IBV_EVENT_SM_CHANGE SM was changed on a port
+
+
IBV_EVENT_CLIENT_REREGISTER SM sent a CLIENT_REREGISTER request + to a port
+
+
+

CA events:

+
+
IBV_EVENT_DEVICE_FATAL CA is in FATAL state
+
+
+

ibv_ack_async_event() acknowledge the async event event.

+

RETURN VALUE

+ibv_get_async_event() returns 0 on success, and -1 on error. +

ibv_ack_async_event() returns no value.

+

NOTES

+All async events that ibv_get_async_event() returns must be acknowledged +using ibv_ack_async_event(). To avoid races, destroying an object (CQ, +SRQ or QP) will wait for all affiliated events for the object to be +acknowledged; this avoids an application retrieving an affiliated event after +the corresponding object has already been destroyed. +

ibv_get_async_event() is a blocking function. If multiple threads call +this function simultaneously, then when an async event occurs, only one thread +will receive it, and it is not possible to predict which thread will receive it. +

+

EXAMPLES

+The following code example demonstrates one possible way to work with async +events in non-blocking mode. It performs the following steps: +

1. Set the async events queue work mode to be non-blocked
+2. Poll the queue until it has an async event
+3. Get the async event and ack it

+

+
/* change the blocking mode of the async event queue */
+flags = fcntl(ctx->async_fd, F_GETFL);
+rc = fcntl(ctx->async_fd, F_SETFL, flags | O_NONBLOCK);
+if (rc < 0) {
+        fprintf(stderr, "Failed to change file descriptor of async event queue\n");
+        return 1;
+}
+
+/*
+ * poll the queue until it has an event and sleep ms_timeout
+ * milliseconds between any iteration
+ */
+my_pollfd.fd      = ctx->async_fd;
+my_pollfd.events  = POLLIN;
+my_pollfd.revents = 0;
+
+do {
+        rc = poll(&my_pollfd, 1, ms_timeout);
+} while (rc == 0);
+if (rc < 0) {
+        fprintf(stderr, "poll failed\n");
+        return 1;
+}
+
+/* Get the async event */
+if (ibv_get_async_event(ctx, &async_event)) {
+        fprintf(stderr, "Failed to get async_event\n");
+        return 1;
+}
+
+/* Ack the event */
+ibv_ack_async_event(&async_event);
+
+
+

SEE ALSO

+ibv_open_device +

 

+


+IBV_QUERY_DEVICE

+
+

NAME

+ibv_query_device - query an RDMA device's attributes   +

SYNOPSIS

+
#include <infiniband/verbs.h>
+
+int ibv_query_device(struct ibv_context *context,
+                     struct ibv_device_attr *device_attr);
+

DESCRIPTION

+ibv_query_device() returns the attributes of the device with context +context. The argument device_attr is a pointer to an ibv_device_attr +struct, as defined in <infiniband/verbs.h>. +

+
struct ibv_device_attr {
+char                    fw_ver[64];             /* FW version */
+uint64_t                node_guid;              /* Node GUID (in network byte order) */
+uint64_t                sys_image_guid;         /* System image GUID (in network byte order) */
+uint64_t                max_mr_size;            /* Largest contiguous block that can be registered */
+uint64_t                page_size_cap;          /* Supported memory shift sizes */
+uint32_t                vendor_id;              /* Vendor ID, per IEEE */
+uint32_t                vendor_part_id;         /* Vendor supplied part ID */
+uint32_t                hw_ver;                 /* Hardware version */
+int                     max_qp;                 /* Maximum number of supported QPs */
+int                     max_qp_wr;              /* Maximum number of outstanding WR on any work queue */
+int                     device_cap_flags;       /* HCA capabilities mask */
+int                     max_sge;                /* Maximum number of s/g per WR for non-RD QPs */
+int                     max_sge_rd;             /* Maximum number of s/g per WR for RD QPs */
+int                     max_cq;                 /* Maximum number of supported CQs */
+int                     max_cqe;                /* Maximum number of CQE capacity per CQ */
+int                     max_mr;                 /* Maximum number of supported MRs */
+int                     max_pd;                 /* Maximum number of supported PDs */
+int                     max_qp_rd_atom;         /* Maximum number of RDMA Read & Atomic operations that can be outstanding per QP */
+int                     max_ee_rd_atom;         /* Maximum number of RDMA Read & Atomic operations that can be outstanding per EEC */
+int                     max_res_rd_atom;        /* Maximum number of resources used for RDMA Read & Atomic operations by this HCA as the Target */
+int                     max_qp_init_rd_atom;    /* Maximum depth per QP for initiation of RDMA Read & Atomic operations */ 
+int                     max_ee_init_rd_atom;    /* Maximum depth per EEC for initiation of RDMA Read & Atomic operations */
+enum ibv_atomic_cap     atomic_cap;             /* Atomic operations support level */
+int                     max_ee;                 /* Maximum number of supported EE contexts */
+int                     max_rdd;                /* Maximum number of supported RD domains */
+int                     max_mw;                 /* Maximum number of supported MWs */
+int                     max_raw_ipv6_qp;        /* Maximum number of supported raw IPv6 datagram QPs */
+int                     max_raw_ethy_qp;        /* Maximum number of supported Ethertype datagram QPs */
+int                     max_mcast_grp;          /* Maximum number of supported multicast groups */
+int                     max_mcast_qp_attach;    /* Maximum number of QPs per multicast group which can be attached */
+int                     max_total_mcast_qp_attach;/* Maximum number of QPs which can be attached to multicast groups */
+int                     max_ah;                 /* Maximum number of supported address handles */
+int                     max_fmr;                /* Maximum number of supported FMRs */
+int                     max_map_per_fmr;        /* Maximum number of (re)maps per FMR before an unmap operation in required */
+int                     max_srq;                /* Maximum number of supported SRQs */
+int                     max_srq_wr;             /* Maximum number of WRs per SRQ */
+int                     max_srq_sge;            /* Maximum number of s/g per SRQ */
+uint16_t                max_pkeys;              /* Maximum number of partitions */
+uint8_t                 local_ca_ack_delay;     /* Local CA ack delay */
+uint8_t                 phys_port_cnt;          /* Number of physical ports */
+};
+

RETURN VALUE

+ibv_query_device() returns 0 on success, or the value of errno on failure +(which indicates the failure reason).   +

NOTES

+The maximum values returned by this function are the upper limits of supported +resources by the device. However, it may not be possible to use these maximum +values, since the actual number of any resource that can be created may be +limited by the machine configuration, the amount of host memory, user +permissions, and the amount of resources already in use by other +users/processes.

SEE ALSO

+ibv_open_device, +ibv_query_port, ibv_query_pkey, +ibv_query_gid +

 

+


+IBV_QUERY_GID

+
+

NAME

+ibv_query_gid - query an InfiniBand port's GID table

SYNOPSIS

+
#include <infiniband/verbs.h>
+
+int ibv_query_gid(struct ibv_context *context, uint8_t port_num,
+                  int index, union ibv_gid *gid);
+

DESCRIPTION

+ibv_query_gid() returns the GID value in entry index of port +port_num for device context context through the pointer gid.

+RETURN VALUE

+ibv_query_gid() returns 0 on success, and -1 on error.

SEE ALSO

+ibv_open_device, +ibv_query_device, +ibv_query_port, +ibv_query_pkey +

 

+


+IBV_QUERY_PKEY

+
+

NAME

+ibv_query_pkey - query an InfiniBand port's P_Key table +

SYNOPSIS

+
#include <infiniband/verbs.h>
+
+int ibv_query_pkey(struct ibv_context *context, uint8_t port_num,
+                   int index, uint16_t *pkey);
+

DESCRIPTION

+ibv_query_pkey() returns the P_Key value (in network byte order) in entry +index of port port_num for device context context through +the pointer pkey.

RETURN VALUE

+ibv_query_pkey() returns 0 on success, and -1 on error. +

SEE ALSO

+ibv_open_device, +ibv_query_device, +ibv_query_port, +ibv_query_gid

 

+


+IBV_QUERY_PORT

+
+

NAME

+ibv_query_port - query an RDMA port's attributes +

SYNOPSIS

+
#include <infiniband/verbs.h>
+
+int ibv_query_port(struct ibv_context *context, uint8_t port_num,
+                   struct ibv_port_attr *port_attr); 
+

DESCRIPTION

+ibv_query_port() returns the attributes of port port_num for +device context context through the pointer port_attr. The argument +port_attr is an ibv_port_attr struct, as defined in <infiniband/verbs.h>. +

+
struct ibv_port_attr {
+enum ibv_port_state     state;          /* Logical port state */
+enum ibv_mtu            max_mtu;        /* Max MTU supported by port */
+enum ibv_mtu            active_mtu;     /* Actual MTU */
+int                     gid_tbl_len;    /* Length of source GID table */
+uint32_t                port_cap_flags; /* Port capabilities */
+uint32_t                max_msg_sz;     /* Maximum message size */
+uint32_t                bad_pkey_cntr;  /* Bad P_Key counter */
+uint32_t                qkey_viol_cntr; /* Q_Key violation counter */
+uint16_t                pkey_tbl_len;   /* Length of partition table */
+uint16_t                lid;            /* Base port LID */
+uint16_t                sm_lid;         /* SM LID */
+uint8_t                 lmc;            /* LMC of LID */
+uint8_t                 max_vl_num;     /* Maximum number of VLs */
+uint8_t                 sm_sl;          /* SM service level */
+uint8_t                 subnet_timeout; /* Subnet propagation delay */
+uint8_t                 init_type_reply;/* Type of initialization performed by SM */
+uint8_t                 active_width;   /* Currently active link width */
+uint8_t                 active_speed;   /* Currently active link speed */
+uint8_t                 phys_state;     /* Physical port state */
+};
+

RETURN VALUE

+ibv_query_port() returns 0 on success, or the value of errno on failure +(which indicates the failure reason). +

SEE ALSO

+ibv_create_qp, ibv_destroy_qp, +ibv_query_qp, +ibv_create_ah

 

+

 

+

IBV_ALLOC_PD

+

IBV_DEALLOC_PD

+
+

NAME

+ibv_alloc_pd, ibv_dealloc_pd - allocate or deallocate a protection domain (PDs)

+SYNOPSIS

+
#include <infiniband/verbs.h>
+
+struct ibv_pd *ibv_alloc_pd(struct ibv_context *context);
+
+int ibv_dealloc_pd(struct ibv_pd *pd);
+

DESCRIPTION

+ibv_alloc_pd() allocates a PD for the RDMA device context context. + +

ibv_dealloc_pd() deallocates the PD pd.

+

RETURN VALUE

+ibv_alloc_pd() returns a pointer to the allocated PD, or NULL if the +request fails. +

ibv_dealloc_pd() returns 0 on success, or the value of errno on +failure (which indicates the failure reason).  

+

NOTES

+ibv_dealloc_pd() may fail if any other resource is still associated with +the PD being freed.   +

SEE ALSO

+ibv_reg_mr, ibv_create_srq, +ibv_create_qp, +ibv_create_ah, +ibv_create_ah_from_wc

 

+

 

+

IBV_REG_MR

+

IBV_DEREG_MR

+
+

NAME

+ibv_reg_mr, ibv_dereg_mr - register or deregister a memory region (MR) +  +

SYNOPSIS

+
#include <infiniband/verbs.h>
+
+struct ibv_mr *ibv_reg_mr(struct ibv_pd *pd, void *addr,
+                          size_t length, int access);
+
+int ibv_dereg_mr(struct ibv_mr *mr);
+

DESCRIPTION

+ibv_reg_mr() registers a memory region (MR) associated with the +protection domain pd. The MR's starting address is addr and its +size is length. The argument access describes the desired memory +protection attributes; it is either 0 or the bitwise OR of one or more of the +following flags: +

+
+
IBV_ACCESS_LOCAL_WRITE Enable Local Write Access
+
+
IBV_ACCESS_REMOTE_WRITE Enable Remote Write Access
+
+
IBV_ACCESS_REMOTE_READ Enable Remote Read Access
+
+
IBV_ACCESS_REMOTE_ATOMIC Enable Remote Atomic Operation Access + (if supported)
+
+
IBV_ACCESS_MW_BIND Enable Memory Window Binding
+
+
+

If IBV_ACCESS_REMOTE_WRITE or IBV_ACCESS_REMOTE_ATOMIC is set, +then IBV_ACCESS_LOCAL_WRITE must be set too.

+

Local read access is always enabled for the MR.

+

ibv_dereg_mr() deregisters the MR mr.

+

RETURN VALUE

+ibv_reg_mr() returns a pointer to the registered MR, or NULL if the +request fails. The local key (L_Key) field lkey is used as the +lkey field of struct ibv_sge when posting buffers with ibv_post_* verbs, and the +the remote key (R_Key) field rkey is used by remote processes to +perform Atomic and RDMA operations. The remote process places this rkey +as the rkey field of struct ibv_send_wr passed to the ibv_post_send function. +

ibv_dereg_mr() returns 0 on success, or the value of errno on failure +(which indicates the failure reason).

+

NOTES

+ibv_dereg_mr() fails if any memory window is still bound to this MR.

+SEE ALSO

+ibv_alloc_pd, ibv_post_send, +ibv_post_recv, +ibv_post_srq_recv +

 

+


+IBV_CREATE_AH

+


+IBV_DESTROY_AH

+
+

NAME

+ibv_create_ah, ibv_destroy_ah - create or destroy an address handle (AH)

+SYNOPSIS

+
#include <infiniband/verbs.h>
+
+struct ibv_ah *ibv_create_ah(struct ibv_pd *pd,
+                             struct ibv_ah_attr *attr);
+
+int ibv_destroy_ah(struct ibv_ah *ah); 
+

DESCRIPTION

+ibv_create_ah() creates an address handle (AH) associated with the +protection domain pd. The argument attr is an ibv_ah_attr struct, +as defined in <infiniband/verbs.h>. +

+
struct ibv_ah_attr {
+struct ibv_global_route grh;            /* Global Routing Header (GRH) attributes */
+uint16_t                dlid;           /* Destination LID */
+uint8_t                 sl;             /* Service Level */
+uint8_t                 src_path_bits;  /* Source path bits */
+uint8_t                 static_rate;    /* Maximum static rate */
+uint8_t                 is_global;      /* GRH attributes are valid */
+uint8_t                 port_num;       /* Physical port number */
+};
+
+struct ibv_global_route {
+union ibv_gid           dgid;           /* Destination GID or MGID */
+uint32_t                flow_label;     /* Flow label */
+uint8_t                 sgid_index;     /* Source GID index */
+uint8_t                 hop_limit;      /* Hop limit */
+uint8_t                 traffic_class;  /* Traffic class */
+};
+
+

+

ibv_destroy_ah() destroys the AH ah.

+

RETURN VALUE

+ibv_create_ah() returns a pointer to the created AH, or NULL if the +request fails. +

ibv_destroy_ah() returns 0 on success, or the value of errno on +failure (which indicates the failure reason).

+

SEE ALSO

+ibv_alloc_pd, +ibv_init_ah_from_wc, +ibv_create_ah_from_wc +

 

+


+IBV_CREATE_AH_FROM_WC

+


+IBV_INIT_AH_FROM_WC

+
+

NAME

+ibv_init_ah_from_wc, ibv_create_ah_from_wc - initialize or create an address +handle (AH) from a work completion   +

SYNOPSIS

+
#include <infiniband/verbs.h>
+
+int ibv_init_ah_from_wc(struct ibv_context *context, uint8_t port_num,
+                        struct ibv_wc *wc, struct ibv_grh *grh,
+                        struct ibv_ah_attr *ah_attr);
+
+struct ibv_ah *ibv_create_ah_from_wc(struct ibv_pd *pd,
+                                     struct ibv_wc *wc,
+                                     struct ibv_grh *grh,
+                                     uint8_t port_num);
+
+

DESCRIPTION

+ibv_init_ah_from_wc() initializes the address handle (AH) attribute +structure ah_attr for the RDMA device context context using the +port number port_num, using attributes from the work completion wc +and the Global Routing Header (GRH) structure grh. + +

ibv_create_ah_from_wc() creates an AH associated with the protection +domain pd using the port number port_num, using attributes from +the work completion wc and the Global Routing Header (GRH) structure +grh.

+

RETURN VALUE

+ibv_init_ah_from_wc() returns 0 on success, and -1 on error. +

ibv_create_ah_from_wc() returns a pointer to the created AH, or NULL +if the request fails.  

+

NOTES

+The filled structure ah_attr returned from ibv_init_ah_from_wc() +can be used to create a new AH using ibv_create_ah(). +

SEE ALSO

+ibv_open_device, +ibv_alloc_pd, ibv_create_ah, +ibv_destroy_ah, ibv_poll_cq

 

+

IBV_CREATE_COMP_CHANNEL

+

IBV_DESTROY_COMP_CHANNEL

+
+

NAME

+ibv_create_comp_channel, ibv_destroy_comp_channel - create or destroy a +completion event channel

SYNOPSIS

+
#include <infiniband/verbs.h>
+
+struct ibv_comp_channel *ibv_create_comp_channel(struct ibv_context
+                                                 *context);
+
+int ibv_destroy_comp_channel(struct ibv_comp_channel *channel);
+

DESCRIPTION

+ibv_create_comp_channel() creates a completion event channel for the RDMA +device context context. + +

ibv_destroy_comp_channel() destroys the completion event channel +channel.

+

RETURN VALUE

+ibv_create_comp_channel() returns a pointer to the created completion +event channel, or NULL if the request fails. +

ibv_destroy_comp_channel() returns 0 on success, or the value of errno +on failure (which indicates the failure reason).

+

NOTES

+A "completion channel" is an abstraction introduced by libibverbs that does not +exist in the InfiniBand Architecture verbs specification or RDMA Protocol Verbs +Specification. A completion channel is essentially file descriptor that is used +to deliver completion notifications to a userspace process. When a completion +event is generated for a completion queue (CQ), the event is delivered via the +completion channel attached to that CQ. This may be useful to steer completion +events to different threads by using multiple completion channels. +

ibv_destroy_comp_channel() fails if any CQs are still associated with +the completion event channel being destroyed.

+

SEE ALSO

+ibv_open_device, +ibv_create_cq, ibv_get_cq_event

 

+

IBV_CREATE_CQ

+

IBV_DESTROY_CQ

+
+

NAME

+ibv_create_cq, ibv_destroy_cq - create or destroy a completion queue (CQ) +  +

SYNOPSIS

+
#include <infiniband/verbs.h>
+
+struct ibv_cq *ibv_create_cq(struct ibv_context *context, int cqe,
+                             void *cq_context,
+                             struct ibv_comp_channel *channel,
+                             int comp_vector);
+
+int ibv_destroy_cq(struct ibv_cq *cq);
+

DESCRIPTION

+ibv_create_cq() creates a completion queue (CQ) with at least cqe +entries for the RDMA device context context. The pointer cq_context +will be used to set user context pointer of the CQ structure. The argument +channel is optional; if not NULL, the completion channel channel will +be used to return completion events. The CQ will use the completion vector +comp_vector for signaling completion events; it must be at least zero and +less than context->num_comp_vectors. + +

ibv_destroy_cq() destroys the CQ cq.

+

RETURN VALUE

+ibv_create_cq() returns a pointer to the CQ, or NULL if the request +fails. +

ibv_destroy_cq() returns 0 on success, or the value of errno on +failure (which indicates the failure reason).

+

NOTES

+ibv_create_cq() may create a CQ with size greater than or equal to the +requested size. Check the cqe attribute in the returned CQ for the actual size. +

ibv_destroy_cq() fails if any queue pair is still associated with this +CQ.

+

SEE ALSO

+ibv_resize_cq, +ibv_req_notify_cq, +ibv_ack_cq_events, +ibv_create_qp

 

+

IBV_POLL_CQ

+
+

NAME

+ibv_poll_cq - poll a completion queue (CQ)   +

SYNOPSIS

+
#include <infiniband/verbs.h>
+
+int ibv_poll_cq(struct ibv_cq *cq, int num_entries,
+                struct ibv_wc *wc);
+

DESCRIPTION

+ibv_poll_cq() polls the CQ cq for work completions and returns the +first num_entries (or all available completions if the CQ contains fewer +than this number) in the array wc. The argument wc is a pointer to +an array of ibv_wc structs, as defined in <infiniband/verbs.h>. +

+
struct ibv_wc {
+uint64_t                wr_id;          /* ID of the completed Work Request (WR) */
+enum ibv_wc_status      status;         /* Status of the operation */
+enum ibv_wc_opcode      opcode;         /* Operation type specified in the completed WR */
+uint32_t                vendor_err;     /* Vendor error syndrome */
+uint32_t                byte_len;       /* Number of bytes transferred */
+uint32_t                imm_data;       /* Immediate data (in network byte order) */
+uint32_t                qp_num;         /* Local QP number of completed WR */
+uint32_t                src_qp;         /* Source QP number (remote QP number) of completed WR (valid only for UD QPs) */
+int                     wc_flags;       /* Flags of the completed WR */
+uint16_t                pkey_index;     /* P_Key index (valid only for GSI QPs) */
+uint16_t                slid;           /* Source LID */
+uint8_t                 sl;             /* Service Level */
+uint8_t                 dlid_path_bits; /* DLID path bits (not applicable for multicast messages) */
+};
+
+
+

The attribute wc_flags describes the properties of the work completion. It is +either 0 or the bitwise OR of one or more of the following flags:

+

+
+
IBV_WC_GRH GRH is present (valid only for UD QPs)
+
+
IBV_WC_WITH_IMM Immediate data value is valid
+
+
+

Not all wc attributes are always valid. If the completion status is +other than IBV_WC_SUCCESS, only the following attributes are valid: wr_id, +status, qp_num, and vendor_err.

+

RETURN VALUE

+On success, ibv_poll_cq() returns a non-negative value equal to the +number of completions found. On failure, a negative value is returned.

NOTES

+

Each polled completion is removed from the CQ and cannot be returned to it. +

+

The user should consume work completions at a rate that prevents CQ overrun +from occurrence. In case of a CQ overrun, the async event IBV_EVENT_CQ_ERR +will be triggered, and the CQ cannot be used.

+

SEE ALSO

+ibv_post_send, ibv_post_recv

 

+

IBV_RESIZE_CQ

+
+

NAME

+ibv_resize_cq - resize a completion queue (CQ)

SYNOPSIS

+
#include <infiniband/verbs.h>
+
+int ibv_resize_cq(struct ibv_cq *cq, int cqe);
+

DESCRIPTION

+ibv_resize_cq() resizes the completion queue (CQ) cq to have at +least cqe entries. cqe must be at least the number of unpolled +entries in the CQ cq. If cqe is a valid value less than the +current CQ size, ibv_resize_cq() may not do anything, since this function +is only guaranteed to resize the CQ to a size at least as big as the requested +size.

RETURN VALUE

+ibv_resize_cq() returns 0 on success, or the value of errno on failure +(which indicates the failure reason).

NOTES

+ibv_resize_cq() may assign a CQ size greater than or equal to the +requested size. The cqe member of cq will be updated to the actual size.

+SEE ALSO

+ +ibv_create_cq ibv_destroy_cq +

 

+


+IBV_GET_CQ_EVENT

+


+IBV_ACK_CQ_EVENTS

+
+

NAME

+ibv_get_cq_event, ibv_ack_cq_events - get and acknowledge completion queue (CQ) +events +

SYNOPSIS

+
#include <infiniband/verbs.h>
+
+int ibv_get_cq_event(struct ibv_comp_channel *channel,
+                     struct ibv_cq **cq, void **cq_context);
+
+void ibv_ack_cq_events(struct ibv_cq *cq, unsigned int nevents);
+

DESCRIPTION

+ibv_get_cq_event() waits for the next completion event in the completion +event channel channel. Fills the arguments cq with the CQ that got +the event and cq_context with the CQ's context. +

ibv_ack_cq_events() acknowledges nevents events on the CQ cq.

+

RETURN VALUE

+ibv_get_cq_event() returns 0 on success, and -1 on error. +

ibv_ack_cq_events() returns no value.  

+

NOTES

+All completion events that ibv_get_cq_event() returns must be +acknowledged using ibv_ack_cq_events(). To avoid races, destroying a CQ +will wait for all completion events to be acknowledged; this guarantees a +one-to-one correspondence between acks and successful gets. +

Calling ibv_ack_cq_events() may be relatively expensive in the +datapath, since it must take a mutex. Therefore it may be better to amortize +this cost by keeping a count of the number of events needing acknowledgement and +acking several completion events in one call to ibv_ack_cq_events().

+

EXAMPLES

+The following code example demonstrates one possible way to work with completion +events. It performs the following steps: +

Stage I: Preparation
+1. Creates a CQ
+2. Requests for notification upon a new (first) completion event

+

Stage II: Completion Handling Routine
+3. Wait for the completion event and ack it
+4. Request for notification upon the next completion event
+5. Empty the CQ

+

Note that an extra event may be triggered without having a corresponding +completion entry in the CQ. This occurs if a completion entry is added to the CQ +between Step 4 and Step 5, and the CQ is then emptied (polled) in Step 5.

+

+
cq = ibv_create_cq(ctx, 1, ev_ctx, channel, 0);
+if (!cq) {
+        fprintf(stderr, "Failed to create CQ\n");
+        return 1;
+}
+
+/* Request notification before any completion can be created */
+if (ibv_req_notify_cq(cq, 0)) {
+        fprintf(stderr, "Couldn't request CQ notification\n");
+        return 1;
+}
+
+.
+.
+.
+
+/* Wait for the completion event */
+if (ibv_get_cq_event(channel, &ev_cq, &ev_ctx)) {
+        fprintf(stderr, "Failed to get cq_event\n");
+        return 1;
+}
+
+/* Ack the event */
+ibv_ack_cq_events(ev_cq, 1);
+
+/* Request notification upon the next completion event */
+if (ibv_req_notify_cq(ev_cq, 0)) {
+        fprintf(stderr, "Couldn't request CQ notification\n");
+        return 1;
+}
+
+/* Empty the CQ: poll all of the completions from the CQ (if any exist) */
+do {
+        ne = ibv_poll_cq(cq, 1, &wc);
+        if (ne < 0) {
+                fprintf(stderr, "Failed to poll completions from the CQ\n");
+                return 1;
+        }
+
+        /* there may be an extra event with no completion in the CQ */
+        if (ne == 0)
+                continue;
+
+        if (wc.status != IBV_WC_SUCCESS) {
+                fprintf(stderr, "Completion with status 0x%x was found\n", wc.status);
+                return 1;
+        }
+} while (ne);
+
+

The following code example demonstrates one possible way to work with +completion events in non-blocking mode. It performs the following steps:

+

1. Set the completion event channel to be non-blocked
+2. Poll the channel until there it has a completion event
+3. Get the completion event and ack it

+

+
/* change the blocking mode of the completion channel */
+flags = fcntl(channel->fd, F_GETFL);
+rc = fcntl(channel->fd, F_SETFL, flags | O_NONBLOCK);
+if (rc < 0) {
+        fprintf(stderr, "Failed to change file descriptor of completion event channel\n");
+        return 1;
+}
+
+
+/*
+ * poll the channel until it has an event and sleep ms_timeout
+ * milliseconds between any iteration
+ */
+my_pollfd.fd      = channel->fd;
+my_pollfd.events  = POLLIN;
+my_pollfd.revents = 0;
+
+do {
+        rc = poll(&my_pollfd, 1, ms_timeout);
+} while (rc == 0);
+if (rc < 0) {
+        fprintf(stderr, "poll failed\n");
+        return 1;
+}
+ev_cq = cq;
+
+/* Wait for the completion event */
+if (ibv_get_cq_event(channel, &ev_cq, &ev_ctx)) {
+        fprintf(stderr, "Failed to get cq_event\n");
+        return 1;
+}
+
+/* Ack the event */
+ibv_ack_cq_events(ev_cq, 1);
+

SEE ALSO

+ibv_create_comp_channel, +ibv_create_cq, ibv_req_notify_cq, +ibv_poll_cq

 

+


+IBV_REQ_NOTIFY_CQ

+
+

NAME

+ibv_req_notify_cq - request completion notification on a completion queue (CQ)

+SYNOPSIS

+
#include <infiniband/verbs.h>
+
+int ibv_req_notify_cq(struct ibv_cq *cq, int solicited_only);
+

DESCRIPTION

+ibv_req_notify_cq() requests a completion notification on the completion +queue (CQ) cq. + +

Upon the addition of a new CQ entry (CQE) to cq, a completion event +will be added to the completion channel associated with the CQ. If the argument +solicited_only is zero, a completion event is generated for any new CQE. +If solicited_only is non-zero, an event is only generated for a new CQE +with that is considered "solicited." A CQE is solicited if it is a receive +completion for a message with the Solicited Event header bit set, or if the +status is not successful. All other successful receive completions, or any +successful send completion is unsolicited.

+

RETURN VALUE

+ibv_req_notify_cq() returns 0 on success, or the value of errno on +failure (which indicates the failure reason).

NOTES

+The request for notification is "one shot." Only one completion event will be +generated for each call to ibv_req_notify_cq().   +

SEE ALSO

+ibv_create_comp_channel, +ibv_create_cq, ibv_get_cq_event

 

+

 

+


+IBV_CREATE_SRQ

+


+IBV_CREATE_XRC_SRQ

+


+IBV_DESTROY_SRQ

+
+

NAME

+ibv_create_srq, ibv_destroy_srq - create or destroy a shared receive queue (SRQ) +  +

SYNOPSIS

+
#include <infiniband/verbs.h>
+
+struct ibv_srq *ibv_create_srq(struct ibv_pd *pd, struct 
+                               ibv_srq_init_attr *srq_init_attr);
+
+struct ibv_srq *ibv_create_xrc_srq(struct ibv_pd *pd,
+                                   struct ibv_xrc_domain *xrc_domain,
+                                   struct ibv_cq *xrc_cq,
+                                   struct ibv_srq_init_attr *srq_init_attr);
+
+int ibv_destroy_srq(struct ibv_srq *srq);
+

DESCRIPTION

+ibv_create_srq() creates a shared receive queue (SRQ) associated with the +protection domain pd. + +

ibv_create_xrc_srq() creates an XRC shared receive queue (SRQ) +associated with the protection domain pd, the XRC domain xrc_domain +and the CQ which will hold the XRC completion xrc_cq.

+

The argument srq_init_attr is an ibv_srq_init_attr struct, as defined +in <infiniband/verbs.h>.

+

+
struct ibv_srq_init_attr {
+void                   *srq_context;    /* Associated context of the SRQ */
+struct ibv_srq_attr     attr;           /* SRQ attributes */
+};
+
+struct ibv_srq_attr {
+uint32_t                max_wr;         /* Requested max number of outstanding work requests (WRs) in the SRQ */
+uint32_t                max_sge;        /* Requested max number of scatter elements per WR */
+uint32_t                srq_limit;      /* The limit value of the SRQ (irrelevant for ibv_create_srq) */
+};
+
+

The function ibv_create_srq() will update the srq_init_attr +struct with the original values of the SRQ that was created; the values of +max_wr and max_sge will be greater than or equal to the values requested.

+

ibv_destroy_srq() destroys the SRQ srq.

+

RETURN VALUE

+ibv_create_srq() returns a pointer to the created SRQ, or NULL if the +request fails. +

ibv_destroy_srq() returns 0 on success, or the value of errno on +failure (which indicates the failure reason).

+

NOTES

+ibv_destroy_srq() fails if any queue pair is still associated with this +SRQ.

SEE ALSO

+ibv_alloc_pd, ibv_modify_srq, +ibv_query_srq

 

+


+IBV_MODIFY_SRQ

+
+

NAME

+ibv_modify_srq - modify attributes of a shared receive queue (SRQ)

SYNOPSIS

+
#include <infiniband/verbs.h>
+
+int ibv_modify_srq(struct ibv_srq *srq,
+                   struct ibv_srq_attr *srq_attr,
+                   int srq_attr_mask);
+

DESCRIPTION

+ibv_modify_srq() modifies the attributes of SRQ srq with the +attributes in srq_attr according to the mask srq_attr_mask. The +argument srq_attr is an ibv_srq_attr struct, as defined in <infiniband/verbs.h>. +

+
struct ibv_srq_attr {
+uint32_t                max_wr;      /* maximum number of outstanding work requests (WRs) in the SRQ */
+uint32_t                max_sge;     /* number of scatter elements per WR (irrelevant for ibv_modify_srq) */
+uint32_t                srq_limit;   /* the limit value of the SRQ */
+};
+
+

The argument srq_attr_mask specifies the SRQ attributes to be +modified. The argument is either 0 or the bitwise OR of one or more of the +following flags:

+

+
+
IBV_SRQ_MAX_WR Resize the SRQ
+
+
IBV_SRQ_LIMIT Set the SRQ limit
+
+
+

RETURN VALUE

+ibv_modify_srq() returns 0 on success, or the value of errno on failure +(which indicates the failure reason).

NOTES

+If any of the modify attributes is invalid, none of the attributes will be +modified. +

Not all devices support resizing SRQs. To check if a device supports it, +check if the IBV_DEVICE_SRQ_RESIZE bit is set in the device capabilities +flags.

+

Modifying the srq_limit arms the SRQ to produce an +IBV_EVENT_SRQ_LIMIT_REACHED "low watermark" asynchronous event once the +number of WRs in the SRQ drops below srq_limit.

+

SEE ALSO

+ibv_query_device, +ibv_create_srq, ibv_destroy_srq, +ibv_query_srq

 

+


+IBV_QUERY_SRQ

+
+

NAME

+ibv_query_srq - get the attributes of a shared receive queue (SRQ)

SYNOPSIS

+
#include <infiniband/verbs.h>
+
+int ibv_query_srq(struct ibv_srq *srq, struct ibv_srq_attr *srq_attr);
+

DESCRIPTION

+ibv_query_srq() gets the attributes of the SRQ srq and returns +them through the pointer srq_attr. The argument srq_attr is an +ibv_srq_attr struct, as defined in <infiniband/verbs.h>. +

+
struct ibv_srq_attr {
+uint32_t                max_wr;         /* maximum number of outstanding work requests (WRs) in the SRQ */
+uint32_t                max_sge;        /* maximum number of scatter elements per WR */
+uint32_t                srq_limit;      /* the limit value of the SRQ */
+}; 
+

RETURN VALUE

+ibv_query_srq() returns 0 on success, or the value of errno on failure +(which indicates the failure reason).

NOTES

+If the value returned for srq_limit is 0, then the SRQ limit reached ("low +watermark") event is not (or no longer) armed, and no asynchronous events will +be generated until the event is rearmed.   +

SEE ALSO

+ibv_create_srq, +ibv_destroy_srq, +ibv_modify_srq

 

+

 

+

IBV_CREATE_XRC_RCV_QP

+
+

NAME

+ibv_create_xrc_rcv_qp - create an XRC queue pair (QP) for serving as a +receive-side only QP

SYNOPSIS

+
#include <infiniband/verbs.h>
+
+int ibv_create_xrc_rcv_qp(struct ibv_qp_init_attr *init_attr,
+                          uint32_t *xrc_rcv_qpn); 
+

DESCRIPTION

+ibv_create_xrc_rcv_qp() creates an XRC queue pair (QP) for serving as a +receive-side only QP and returns its number through the pointer xrc_rcv_qpn. +This QP number should be passed to the remote node (sender). The remote node +will use xrc_rcv_qpn in ibv_post_send() when sending to an XRC SRQ +on this host in the same xrc domain as the XRC receive QP. This QP is created in +kernel space, and persists until the last process registered for the QP calls +ibv_unreg_xrc_rcv_qp() (at which time the QP is destroyed). +

The process which creates this QP is automatically registered for it, and +should also call ibv_unreg_xrc_rcv_qp() at some point, to unregister.

+

Processes which wish to receive on an XRC SRQ via this QP should call +ibv_reg_xrc_rcv_qp() for this QP, to guarantee that the QP will not be +destroyed while they are still using it for receiving on the XRC SRQ.

+

The argument qp_init_attr is an ibv_qp_init_attr struct, as defined in +<infiniband/verbs.h>.

+

+
struct ibv_qp_init_attr {
+void                   *qp_context;     /* value is being ignored */
+struct ibv_cq          *send_cq;        /* value is being ignored */ 
+struct ibv_cq          *recv_cq;        /* value is being ignored */
+struct ibv_srq         *srq;            /* value is being ignored */
+struct ibv_qp_cap       cap;            /* value is being ignored */
+enum ibv_qp_type        qp_type;        /* value is being ignored */
+int                     sq_sig_all;     /* value is being ignored */
+struct ibv_xrc_domain  *xrc_domain;     /* XRC domain the QP will be associated with */
+};
+
+

Most of the attributes in qp_init_attr are being ignored because this +QP is a receive only QP and all RR are being posted to an SRQ.

+

RETURN VALUE

+ibv_create_xrc_rcv_qp() returns 0 on success, or the value of errno on +failure (which indicates the failure reason).

SEE ALSO

+ibv_open_xrc_domain, +ibv_modify_xrc_rcv_qp, +ibv_query_xrc_rcv_qp, +ibv_reg_xrc_rcv_qp, +ibv_unreg_xrc_rcv_qp, +ibv_post_send

 

+

IBV_MODIFY_XRC_RCV_QP

+
+

NAME

+ibv_modify_xrc_rcv_qp - modify the attributes of an XRC receive queue pair (QP)

+SYNOPSIS

+
#include <infiniband/verbs.h>
+
+int ibv_modify_xrc_rcv_qp(struct ibv_xrc_domain *xrc_domain, uint32_t xrc_qp_num,
+                          struct ibv_qp_attr *attr, int attr_mask);
+

DESCRIPTION

+ibv_modify_qp() modifies the attributes of an XRC receive QP with the +number xrc_qp_num which is associated with the XRC domain xrc_domain +with the attributes in attr according to the mask attr_mask and +move the QP state through the following transitions: Reset -> Init -> RTR. +attr_mask should indicate all of the attributes which will be used in this +QP transition and the following masks (at least) should be set: +

+
Next state     Required attributes
+----------     ----------------------------------------
+Init           IBV_QP_STATE, IBV_QP_PKEY_INDEX, IBV_QP_PORT, 
+               IBV_QP_ACCESS_FLAGS 
+RTR            IBV_QP_STATE, IBV_QP_AV, IBV_QP_PATH_MTU, 
+               IBV_QP_DEST_QPN, IBV_QP_RQ_PSN, 
+               IBV_QP_MAX_DEST_RD_ATOMIC, IBV_QP_MIN_RNR_TIMER 
+
+

The user can add optional attributes as well.

+

The argument attr is an ibv_qp_attr struct, as defined in +<infiniband/verbs.h>.

+

+
struct ibv_qp_attr {
+enum ibv_qp_state       qp_state;               /* Move the QP to this state */
+enum ibv_qp_state       cur_qp_state;           /* Assume this is the current QP state */
+enum ibv_mtu            path_mtu;               /* Path MTU (valid only for RC/UC QPs) */
+enum ibv_mig_state      path_mig_state;         /* Path migration state (valid if HCA supports APM) */
+uint32_t                qkey;                   /* Q_Key for the QP (valid only for UD QPs) */
+uint32_t                rq_psn;                 /* PSN for receive queue (valid only for RC/UC QPs) */
+uint32_t                sq_psn;                 /* PSN for send queue (valid only for RC/UC QPs) */
+uint32_t                dest_qp_num;            /* Destination QP number (valid only for RC/UC QPs) */
+int                     qp_access_flags;        /* Mask of enabled remote access operations (valid only for RC/UC QPs) */
+struct ibv_qp_cap       cap;                    /* QP capabilities (valid if HCA supports QP resizing) */
+struct ibv_ah_attr      ah_attr;                /* Primary path address vector (valid only for RC/UC QPs) */
+struct ibv_ah_attr      alt_ah_attr;            /* Alternate path address vector (valid only for RC/UC QPs) */
+uint16_t                pkey_index;             /* Primary P_Key index */
+uint16_t                alt_pkey_index;         /* Alternate P_Key index */
+uint8_t                 en_sqd_async_notify;    /* Enable SQD.drained async notification (Valid only if qp_state is SQD) */
+uint8_t                 sq_draining;            /* Is the QP draining? Irrelevant for ibv_modify_qp() */
+uint8_t                 max_rd_atomic;          /* Number of outstanding RDMA reads & atomic operations on the destination QP (valid only for RC QPs) */
+uint8_t                 max_dest_rd_atomic;     /* Number of responder resources for handling incoming RDMA reads & atomic operations (valid only for RC QPs) */
+uint8_t                 min_rnr_timer;          /* Minimum RNR NAK timer (valid only for RC QPs) */
+uint8_t                 port_num;               /* Primary port number */
+uint8_t                 timeout;                /* Local ack timeout for primary path (valid only for RC QPs) */
+uint8_t                 retry_cnt;              /* Retry count (valid only for RC QPs) */
+uint8_t                 rnr_retry;              /* RNR retry (valid only for RC QPs) */
+uint8_t                 alt_port_num;           /* Alternate port number */
+uint8_t                 alt_timeout;            /* Local ack timeout for alternate path (valid only for RC QPs) */
+};
+
+

For details on struct ibv_qp_cap see the description of ibv_create_qp(). +For details on struct ibv_ah_attr see the description of ibv_create_ah(). +

+

The argument attr_mask specifies the QP attributes to be modified. The +argument is either 0 or the bitwise OR of one or more of the following flags: +

+

+
+
IBV_QP_STATE Modify qp_state
+
+
IBV_QP_CUR_STATE Set cur_qp_state
+
+
IBV_QP_EN_SQD_ASYNC_NOTIFY Set en_sqd_async_notify
+
+
IBV_QP_ACCESS_FLAGS Set qp_access_flags
+
+
IBV_QP_PKEY_INDEX Set pkey_index
+
+
IBV_QP_PORT Set port_num
+
+
IBV_QP_QKEY Set qkey
+
+
IBV_QP_AV Set ah_attr
+
+
IBV_QP_PATH_MTU Set path_mtu
+
+
IBV_QP_TIMEOUT Set timeout
+
+
IBV_QP_RETRY_CNT Set retry_cnt
+
+
IBV_QP_RNR_RETRY Set rnr_retry
+
+
IBV_QP_RQ_PSN Set rq_psn
+
+
IBV_QP_MAX_QP_RD_ATOMIC Set max_rd_atomic
+
+
IBV_QP_ALT_PATH Set the alternative path via: alt_ah_attr, + alt_pkey_index, alt_port_num, alt_timeout
+
+
IBV_QP_MIN_RNR_TIMER Set min_rnr_timer
+
+
IBV_QP_SQ_PSN Set sq_psn
+
+
IBV_QP_MAX_DEST_RD_ATOMIC Set max_dest_rd_atomic
+
+
IBV_QP_PATH_MIG_STATE Set path_mig_state
+
+
IBV_QP_CAP Set cap
+
+
IBV_QP_DEST_QPN Set dest_qp_num
+
+
+

RETURN VALUE

+ibv_modify_xrc_rcv_qp() returns 0 on success, or the value of errno on +failure (which indicates the failure reason). +

NOTES

+If any of the modify attributes or the modify mask are invalid, none of the +attributes will be modified (including the QP state). +

Not all devices support alternate paths. To check if a device supports it, +check if the IBV_DEVICE_AUTO_PATH_MIG bit is set in the device +capabilities flags.

+

SEE ALSO

+ibv_open_xrc_domain, +ibv_create_xrc_rcv_qp, +ibv_query_xrc_rcv_qp +

 

+


+IBV_OPEN_XRC_DOMAIN

+


+IBV_CLOSE_XRC_DOMAIN

+
+

NAME

+ibv_open_xrc_domain, ibv_close_xrc_domain - open or close an eXtended Reliable +Connection (XRC) domain +

SYNOPSIS

+
#include <fcntl.h>
+#include <infiniband/verbs.h>
+
+struct ibv_xrc_domain *ibv_open_xrc_domain(struct ibv_context *context,
+                                           int fd, int oflag);
+int ibv_close_xrc_domain(struct ibv_xrc_domain *d);
+

DESCRIPTION

+ibv_open_xrc_domain() open an XRC domain for the InfiniBand device +context context or return a reference to an opened one. fd is the +file descriptor to be associated with the XRC domain. The argument oflag +describes the desired file creation attributes; it is either 0 or the bitwise OR +of one or more of the following flags: +

+
+
O_CREAT
+
If a domain belonging to device named by context is already associated + with the inode, this flag has no effect, except as noted under O_EXCL + below. Otherwise, a new XRC domain is created and is associated with inode + specified by fd. + +
+
O_EXCL
+
If O_EXCL and O_CREAT are set, open will fail if a domain + associated with the inode exists. The check for the existence of the domain + and creation of the domain if it does not exist is atomic with respect to + other processes executing open with fd naming the same inode. +
+
+

If fd equals -1, no inode is is associated with the domain, and the +only valid value for oflag is O_CREAT.

+

ibv_close_xrc_domain() closes the XRC domain d. If this is the +last reference, the XRC domain will be destroyed.

+

RETURN VALUE

+ibv_open_xrc_domain() returns a pointer to an opened XRC, or NULL if the +request fails. +

ibv_close_xrc_domain() returns 0 on success, or the value of errno on +failure (which indicates the failure reason).

+

NOTES

+Not all devices support XRC. To check if a device supports it, check if the +IBV_DEVICE_XRC bit is set in the device capabilities flags. +

ibv_close_xrc_domain() may fail if any QP or SRQ are still associated +with the XRC domain being closed.

+

SEE ALSO

+ibv_create_xrc_srq, +ibv_create_qp, +ibv_create_xrc_rcv_qp, +ibv_modify_xrc_rcv_qp, +ibv_query_xrc_rcv_qp, +ibv_reg_xrc_rcv_qp

 

+


+IBV_QUERY_XRC_RCV_QP

+
+

NAME

+ibv_query_xrc_rcv_qp - get the attributes of an XRC receive queue pair (QP) +

SYNOPSIS

+
#include <infiniband/verbs.h>
+
+int ibv_query_xrc_rcv_qp(struct ibv_xrc_domain *xrc_domain, uint32_t xrc_qp_num,
+                         struct ibv_qp_attr *attr, int attr_mask,
+                         struct ibv_qp_init_attr *init_attr);
+

DESCRIPTION

+ibv_query_xrc_rcv_qp() gets the attributes specified in attr_mask +for the XRC receive QP with the number xrc_qp_num which is associated +with the XRC domain xrc_domain and returns them through the pointers +attr and init_attr. The argument attr is an ibv_qp_attr +struct, as defined in <infiniband/verbs.h>. +

+
struct ibv_qp_attr {
+enum ibv_qp_state       qp_state;            /* Current QP state */
+enum ibv_qp_state       cur_qp_state;        /* Current QP state - irrelevant for ibv_query_qp */
+enum ibv_mtu            path_mtu;            /* Path MTU (valid only for RC/UC QPs) */
+enum ibv_mig_state      path_mig_state;      /* Path migration state (valid if HCA supports APM) */
+uint32_t                qkey;                /* Q_Key of the QP (valid only for UD QPs) */
+uint32_t                rq_psn;              /* PSN for receive queue (valid only for RC/UC QPs) */
+uint32_t                sq_psn;              /* PSN for send queue (valid only for RC/UC QPs) */
+uint32_t                dest_qp_num;         /* Destination QP number (valid only for RC/UC QPs) */
+int                     qp_access_flags;     /* Mask of enabled remote access operations (valid only for RC/UC QPs) */
+struct ibv_qp_cap       cap;                 /* QP capabilities */
+struct ibv_ah_attr      ah_attr;             /* Primary path address vector (valid only for RC/UC QPs) */
+struct ibv_ah_attr      alt_ah_attr;         /* Alternate path address vector (valid only for RC/UC QPs) */
+uint16_t                pkey_index;          /* Primary P_Key index */
+uint16_t                alt_pkey_index;      /* Alternate P_Key index */
+uint8_t                 en_sqd_async_notify; /* Enable SQD.drained async notification - irrelevant for ibv_query_qp */
+uint8_t                 sq_draining;         /* Is the QP draining? (Valid only if qp_state is SQD) */
+uint8_t                 max_rd_atomic;       /* Number of outstanding RDMA reads & atomic operations on the destination QP (valid only for RC QPs) */
+uint8_t                 max_dest_rd_atomic;  /* Number of responder resources for handling incoming RDMA reads & atomic operations (valid only for RC QPs) */
+uint8_t                 min_rnr_timer;       /* Minimum RNR NAK timer (valid only for RC QPs) */
+uint8_t                 port_num;            /* Primary port number */
+uint8_t                 timeout;             /* Local ack timeout for primary path (valid only for RC QPs) */
+uint8_t                 retry_cnt;           /* Retry count (valid only for RC QPs) */
+uint8_t                 rnr_retry;           /* RNR retry (valid only for RC QPs) */
+uint8_t                 alt_port_num;        /* Alternate port number */
+uint8_t                 alt_timeout;         /* Local ack timeout for alternate path (valid only for RC QPs) */
+};
+
+

For details on struct ibv_qp_cap see the description of ibv_create_qp(). +For details on struct ibv_ah_attr see the description of ibv_create_ah().

+

RETURN VALUE

+ibv_query_xrc_rcv_qp() returns 0 on success, or the value of errno on +failure (which indicates the failure reason).

NOTES

+The argument attr_mask is a hint that specifies the minimum list of +attributes to retrieve. Some InfiniBand devices may return extra attributes not +requested, for example if the value can be returned cheaply. +

Attribute values are valid if they have been set using +ibv_modify_xrc_rcv_qp(). The exact list of valid attributes depends on the +QP state.

+

Multiple calls to ibv_query_xrc_rcv_qp() may yield some differences in +the values returned for the following attributes: qp_state, path_mig_state, +sq_draining, ah_attr (if APM is enabled).

+

SEE ALSO

+ibv_open_xrc_domain, +ibv_create_xrc_rcv_qp, +ibv_modify_xrc_rcv_qp

 

+


+IBV_REG_XRC_RCV_QP

+


+IBV_UNREG_XRC_RCV_QP

+
+

NAME

+ibv_reg_xrc_rcv_qp, ibv_unreg_xrc_rcv_qp - register and unregister a user +process with an XRC receive queue pair (QP)   +

SYNOPSIS

+
#include <infiniband/verbs.h>
+
+int ibv_reg_xrc_rcv_qp(struct ibv_xrc_domain *xrc_domain, uint32_t xrc_qp_num);
+int ibv_unreg_xrc_rcv_qp(struct ibv_xrc_domain *xrc_domain, uint32_t xrc_qp_num); 
+

DESCRIPTION

+ibv_reg_xrc_rcv_qp() registers a user process with the XRC receive QP +(created via ibv_create_xrc_rcv_qp() ) whose number is xrc_qp_num, +and which is associated with the XRC domain xrc_domain. + +

ibv_unreg_xrc_rcv_qp() unregisters a user process from the XRC receive +QP number xrc_qp_num, which is associated with the XRC domain +xrc_domain. When the number of user processes registered with this XRC +receive QP drops to zero, the QP is destroyed.

+

RETURN VALUE

+ibv_reg_xrc_rcv_qp() and ibv_unreg_xrc_rcv_qp() returns 0 on +success, or the value of errno on failure (which indicates the failure reason).

+NOTES

+ibv_reg_xrc_rcv_qp() and ibv_unreg_xrc_rcv_qp() may fail if the +number xrc_qp_num is not a number of a valid XRC receive QP (the QP is +not allocated or it is the number of a non-XRC QP), or the XRC receive QP was +created with an XRC domain other than xrc_domain. + +

If a process is still registered with any XRC RCV QPs belonging to some +domain, ibv_close_xrc_domain() will return failure if called for that +domain in that process.

+

ibv_create_xrc_rcv_qp() performs an implicit registration for the +creating process; when that process is finished with the XRC RCV QP, it should +call ibv_unreg_xrc_rcv_qp() for that QP. Note that if no other processes +are registered with the QP at this time, its registration count will drop to +zero and it will be destroyed.  

+

SEE ALSO

+ibv_open_xrc_domain, +ibv_create_xrc_rcv_qp

 

+

 

+


+IBV_CREATE_QP

+


+IBV_DESTROY_QP

+
+

NAME

+ibv_create_qp, ibv_destroy_qp - create or destroy a queue pair (QP)

SYNOPSIS

+
#include <infiniband/verbs.h>
+
+struct ibv_qp *ibv_create_qp(struct ibv_pd *pd,
+                             struct ibv_qp_init_attr *qp_init_attr);
+
+int ibv_destroy_qp(struct ibv_qp *qp);
+

DESCRIPTION

+ibv_create_qp() creates a queue pair (QP) associated with the protection +domain pd. The argument qp_init_attr is an ibv_qp_init_attr +struct, as defined in <infiniband/verbs.h>. +

+
struct ibv_qp_init_attr {
+void                   *qp_context;     /* Associated context of the QP */
+struct ibv_cq          *send_cq;        /* CQ to be associated with the Send Queue (SQ) */ 
+struct ibv_cq          *recv_cq;        /* CQ to be associated with the Receive Queue (RQ) */
+struct ibv_srq         *srq;            /* SRQ handle if QP is to be associated with an SRQ, otherwise NULL */
+struct ibv_qp_cap       cap;            /* QP capabilities */
+enum ibv_qp_type        qp_type;        /* QP Transport Service Type: IBV_QPT_RC, IBV_QPT_UC, IBV_QPT_UD or IBV_QPT_XRC */
+int                     sq_sig_all;     /* If set, each Work Request (WR) submitted to the SQ generates a completion entry */
+struct ibv_xrc_domain  *xrc_domain;     /* XRC domain the QP will be associated with (valid only for IBV_QPT_XRC QP), otherwise NULL */
+};
+
+struct ibv_qp_cap {
+uint32_t                max_send_wr;    /* Requested max number of outstanding WRs in the SQ */
+uint32_t                max_recv_wr;    /* Requested max number of outstanding WRs in the RQ */
+uint32_t                max_send_sge;   /* Requested max number of scatter/gather (s/g) elements in a WR in the SQ */
+uint32_t                max_recv_sge;   /* Requested max number of s/g elements in a WR in the SQ */
+uint32_t                max_inline_data;/* Requested max number of data (bytes) that can be posted inline to the SQ, otherwise 0 */
+};
+
+

The function ibv_create_qp() will update the qp_init_attr->cap +struct with the actual QP values of the QP that was +created; the values will be greater than or equal to the values requested.

+

ibv_destroy_qp() destroys the QP qp.

+

RETURN VALUE

+ibv_create_qp() returns a pointer to the created QP, or NULL if the +request fails. Check the QP number (qp_num) in the returned QP. +

ibv_destroy_qp() returns 0 on success, or the value of errno on +failure (which indicates the failure reason).

+

NOTES

+ibv_create_qp() will fail if a it is asked to create QP of a type other +than IBV_QPT_RC or IBV_QPT_UD associated with an SRQ. +

The attributes max_recv_wr and max_recv_sge are ignored by ibv_create_qp() +if the QP is to be associated with an SRQ.

+

ibv_destroy_qp() fails if the QP is attached to a multicast group.

+

SEE ALSO

+ibv_alloc_pd, ibv_modify_qp, +ibv_query_qp +

 

+


+IBV_MODIFY_QP

+
+

NAME

+ibv_modify_qp - modify the attributes of a queue pair (QP) +

SYNOPSIS

+
#include <infiniband/verbs.h>
+
+int ibv_modify_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr,
+                  int attr_mask); 
+

DESCRIPTION

+ibv_modify_qp() modifies the attributes of QP qp with the +attributes in attr according to the mask attr_mask. The argument +attr is an ibv_qp_attr struct, as defined in <infiniband/verbs.h>. +

+
struct ibv_qp_attr {
+enum ibv_qp_state       qp_state;               /* Move the QP to this state */
+enum ibv_qp_state       cur_qp_state;           /* Assume this is the current QP state */
+enum ibv_mtu            path_mtu;               /* Path MTU (valid only for RC/UC QPs) */
+enum ibv_mig_state      path_mig_state;         /* Path migration state (valid if HCA supports APM) */
+uint32_t                qkey;                   /* Q_Key for the QP (valid only for UD QPs) */
+uint32_t                rq_psn;                 /* PSN for receive queue (valid only for RC/UC QPs) */
+uint32_t                sq_psn;                 /* PSN for send queue (valid only for RC/UC QPs) */
+uint32_t                dest_qp_num;            /* Destination QP number (valid only for RC/UC QPs) */
+int                     qp_access_flags;        /* Mask of enabled remote access operations (valid only for RC/UC QPs) */
+struct ibv_qp_cap       cap;                    /* QP capabilities (valid if HCA supports QP resizing) */
+struct ibv_ah_attr      ah_attr;                /* Primary path address vector (valid only for RC/UC QPs) */
+struct ibv_ah_attr      alt_ah_attr;            /* Alternate path address vector (valid only for RC/UC QPs) */
+uint16_t                pkey_index;             /* Primary P_Key index */
+uint16_t                alt_pkey_index;         /* Alternate P_Key index */
+uint8_t                 en_sqd_async_notify;    /* Enable SQD.drained async notification (Valid only if qp_state is SQD) */
+uint8_t                 sq_draining;            /* Is the QP draining? Irrelevant for ibv_modify_qp() */
+uint8_t                 max_rd_atomic;          /* Number of outstanding RDMA reads & atomic operations on the destination QP (valid only for RC QPs) */
+uint8_t                 max_dest_rd_atomic;     /* Number of responder resources for handling incoming RDMA reads & atomic operations (valid only for RC QPs) */
+uint8_t                 min_rnr_timer;          /* Minimum RNR NAK timer (valid only for RC QPs) */
+uint8_t                 port_num;               /* Primary port number */
+uint8_t                 timeout;                /* Local ack timeout for primary path (valid only for RC QPs) */
+uint8_t                 retry_cnt;              /* Retry count (valid only for RC QPs) */
+uint8_t                 rnr_retry;              /* RNR retry (valid only for RC QPs) */
+uint8_t                 alt_port_num;           /* Alternate port number */
+uint8_t                 alt_timeout;            /* Local ack timeout for alternate path (valid only for RC QPs) */
+};
+
+

For details on struct ibv_qp_cap see the description of ibv_create_qp(). +For details on struct ibv_ah_attr see the description of ibv_create_ah(). +

+

The argument attr_mask specifies the QP attributes to be modified. The +argument is either 0 or the bitwise OR of one or more of the following flags: +

+

+
+
IBV_QP_STATE Modify qp_state
+
+
IBV_QP_CUR_STATE Set cur_qp_state
+
+
IBV_QP_EN_SQD_ASYNC_NOTIFY Set en_sqd_async_notify
+
+
IBV_QP_ACCESS_FLAGS Set qp_access_flags
+
+
IBV_QP_PKEY_INDEX Set pkey_index
+
+
IBV_QP_PORT Set port_num
+
+
IBV_QP_QKEY Set qkey
+
+
IBV_QP_AV Set ah_attr
+
+
IBV_QP_PATH_MTU Set path_mtu
+
+
IBV_QP_TIMEOUT Set timeout
+
+
IBV_QP_RETRY_CNT Set retry_cnt
+
+
IBV_QP_RNR_RETRY Set rnr_retry
+
+
IBV_QP_RQ_PSN Set rq_psn
+
+
IBV_QP_MAX_QP_RD_ATOMIC Set max_rd_atomic
+
+
IBV_QP_ALT_PATH Set the alternative path via: alt_ah_attr, + alt_pkey_index, alt_port_num, alt_timeout
+
+
IBV_QP_MIN_RNR_TIMER Set min_rnr_timer
+
+
IBV_QP_SQ_PSN Set sq_psn
+
+
IBV_QP_MAX_DEST_RD_ATOMIC Set max_dest_rd_atomic
+
+
IBV_QP_PATH_MIG_STATE Set path_mig_state
+
+
IBV_QP_CAP Set cap
+
+
IBV_QP_DEST_QPN Set dest_qp_num
+
+
+

RETURN VALUE

+ibv_modify_qp() returns 0 on success, or the value of errno on failure +(which indicates the failure reason).

NOTES

+If any of the modify attributes or the modify mask are invalid, none of the +attributes will be modified (including the QP state). +

Not all devices support resizing QPs. To check if a device supports it, check +if the IBV_DEVICE_RESIZE_MAX_WR bit is set in the device capabilities +flags.

+

Not all devices support alternate paths. To check if a device supports it, +check if the IBV_DEVICE_AUTO_PATH_MIG bit is set in the device +capabilities flags.

+

The following tables indicate for each QP Transport Service Type, the minimum +list of attributes that must be changed upon transitioning QP state from: Reset +--> Init --> RTR --> RTS.

+

+
For QP Transport Service Type  IBV_QPT_UD:
+
+Next state     Required attributes
+----------     ----------------------------------------
+Init           IBV_QP_STATE, IBV_QP_PKEY_INDEX, IBV_QP_PORT, 
+               IBV_QP_QKEY 
+RTR            IBV_QP_STATE 
+RTS            IBV_QP_STATE, IBV_QP_SQ_PSN 
+
+

+
For QP Transport Service Type  IBV_QPT_UC:
+
+Next state     Required attributes
+----------     ----------------------------------------
+Init           IBV_QP_STATE, IBV_QP_PKEY_INDEX, IBV_QP_PORT, 
+               IBV_QP_ACCESS_FLAGS 
+RTR            IBV_QP_STATE, IBV_QP_AV, IBV_QP_PATH_MTU, 
+               IBV_QP_DEST_QPN, IBV_QP_RQ_PSN 
+RTS            IBV_QP_STATE, IBV_QP_SQ_PSN 
+
+

+
For QP Transport Service Type  IBV_QPT_RC:
+
+Next state     Required attributes
+----------     ----------------------------------------
+Init           IBV_QP_STATE, IBV_QP_PKEY_INDEX, IBV_QP_PORT, 
+               IBV_QP_ACCESS_FLAGS 
+RTR            IBV_QP_STATE, IBV_QP_AV, IBV_QP_PATH_MTU, 
+               IBV_QP_DEST_QPN, IBV_QP_RQ_PSN, 
+               IBV_QP_MAX_DEST_RD_ATOMIC, IBV_QP_MIN_RNR_TIMER 
+RTS            IBV_QP_STATE, IBV_QP_SQ_PSN, IBV_QP_MAX_QP_RD_ATOMIC, 
+               IBV_QP_RETRY_CNT, IBV_QP_RNR_RETRY, IBV_QP_TIMEOUT
+

SEE ALSO

+ibv_create_qp, ibv_destroy_qp, +ibv_query_qp, +ibv_create_ah

 

+

 

+


+IBV_POST_RECV

+
+

NAME

+ibv_post_recv - post a list of work requests (WRs) to a receive queue

+SYNOPSIS

+
#include <infiniband/verbs.h>
+
+int ibv_post_recv(struct ibv_qp *qp, struct ibv_recv_wr *wr,
+                  struct ibv_recv_wr **bad_wr);
+

DESCRIPTION

+ibv_post_recv() posts the linked list of work requests (WRs) starting +with wr to the receive queue of the queue pair qp. It stops +processing WRs from this list at the first failure (that can be detected +immediately while requests are being posted), and returns this failing WR +through bad_wr. + +

The argument wr is an ibv_recv_wr struct, as defined in <infiniband/verbs.h>. +

+

+
struct ibv_recv_wr {
+uint64_t                wr_id;     /* User defined WR ID */
+struct ibv_recv_wr     *next;      /* Pointer to next WR in list, NULL if last WR */
+struct ibv_sge         *sg_list;   /* Pointer to the s/g array */
+int                     num_sge;   /* Size of the s/g array */
+};
+
+struct ibv_sge {
+uint64_t                addr;      /* Start address of the local memory buffer */
+uint32_t                length;    /* Length of the buffer */
+uint32_t                lkey;      /* Key of the local Memory Region */
+};
+

RETURN VALUE

+ibv_post_recv() returns 0 on success, or the value of errno on failure +(which indicates the failure reason). +

NOTES

+The buffers used by a WR can only be safely reused after WR the request is fully +executed and a work completion has been retrieved from the corresponding +completion queue (CQ). +

If the QP qp is associated with a shared receive queue, you must use +the function ibv_post_srq_recv(), and not ibv_post_recv(), since +the QP's own receive queue will not be used.

+

If a WR is being posted to a UD QP, the Global Routing Header (GRH) of the +incoming message will be placed in the first 40 bytes of the buffer(s) in the +scatter list. If no GRH is present in the incoming message, then the first bytes +will be undefined. This means that in all cases, the actual data of the incoming +message will start at an offset of 40 bytes into the buffer(s) in the scatter +list.

+

SEE ALSO

+ibv_create_qp, ibv_post_send, +ibv_post_srq_recv, +ibv_poll_cq +

 

+

 

+


+IBV_POST_SEND

+
+

NAME

+ibv_post_send - post a list of work requests (WRs) to a send queue +

SYNOPSIS

+
#include <infiniband/verbs.h>
+
+int ibv_post_send(struct ibv_qp *qp, struct ibv_send_wr *wr,
+                  struct ibv_send_wr **bad_wr); 
+

DESCRIPTION

+ibv_post_send() posts the linked list of work requests (WRs) starting +with wr to the send queue of the queue pair qp. It stops +processing WRs from this list at the first failure (that can be detected +immediately while requests are being posted), and returns this failing WR +through bad_wr. + +

The argument wr is an ibv_send_wr struct, as defined in <infiniband/verbs.h>. +

+

+
struct ibv_send_wr {
+uint64_t                wr_id;                  /* User defined WR ID */
+struct ibv_send_wr     *next;                   /* Pointer to next WR in list, NULL if last WR */
+struct ibv_sge         *sg_list;                /* Pointer to the s/g array */
+int                     num_sge;                /* Size of the s/g array */
+enum ibv_wr_opcode      opcode;                 /* Operation type */
+int                     send_flags;             /* Flags of the WR properties */
+uint32_t                imm_data;               /* Immediate data (in network byte order) */
+union {
+struct {
+uint64_t        remote_addr;    /* Start address of remote memory buffer */
+uint32_t        rkey;           /* Key of the remote Memory Region */
+} rdma;
+struct {
+uint64_t        remote_addr;    /* Start address of remote memory buffer */ 
+uint64_t        compare_add;    /* Compare operand */
+uint64_t        swap;           /* Swap operand */
+uint32_t        rkey;           /* Key of the remote Memory Region */
+} atomic;
+struct {
+struct ibv_ah  *ah;             /* Address handle (AH) for the remote node address */
+uint32_t        remote_qpn;     /* QP number of the destination QP */
+uint32_t        remote_qkey;    /* Q_Key number of the destination QP */
+} ud;
+} wr;
+uint32_t                xrc_remote_srq_num;     /* SRQ number of the destination XRC */
+};
+
+struct ibv_sge {
+uint64_t                addr;                   /* Start address of the local memory buffer */
+uint32_t                length;                 /* Length of the buffer */
+uint32_t                lkey;                   /* Key of the local Memory Region */
+};
+
+

Each QP Transport Service Type supports a specific set of opcodes, as shown +in the following table:

+

+
OPCODE                      | IBV_QPT_UD | IBV_QPT_UC | IBV_QPT_RC | IBV_QPT_XRC
+----------------------------+------------+------------+------------+------------
+IBV_WR_SEND                 |     X      |     X      |     X      |     X
+IBV_WR_SEND_WITH_IMM        |     X      |     X      |     X      |     X
+IBV_WR_RDMA_WRITE           |            |     X      |     X      |     X
+IBV_WR_RDMA_WRITE_WITH_IMM  |            |     X      |     X      |     X
+IBV_WR_RDMA_READ            |            |            |     X      |     X
+IBV_WR_ATOMIC_CMP_AND_SWP   |            |            |     X      |     X
+IBV_WR_ATOMIC_FETCH_AND_ADD |            |            |     X      |     X
+
+

The attribute send_flags describes the properties of the WR. +It is either 0 or the bitwise OR of one or more of the +following flags:

+

+
+
IBV_SEND_FENCE Set the fence indicator. Valid only for QPs with + Transport Service Type IBV_QPT_RC
+
+
IBV_SEND_SIGNALED Set the completion notification indicator. + Relevant only if QP was created with sq_sig_all=0
+
+
IBV_SEND_SOLICITED Set the solicited event indicator. Valid only + for Send and RDMA Write with immediate
+
+
IBV_SEND_INLINE Send data in given gather list as inline data +
+
in a send WQE. Valid only for Send and RDMA Write. The L_Key will not be + checked. +
+
+

RETURN VALUE

+ibv_post_send() returns 0 on success, or the value of errno on failure +(which indicates the failure reason). +

NOTES

+The user should not alter or destroy AHs associated with WRs until request is +fully executed and a work completion has been retrieved from the corresponding +completion queue (CQ) to avoid unexpected behavior. +

The buffers used by a WR can only be safely reused after WR the request is +fully executed and a work completion has been retrieved from the corresponding +completion queue (CQ). However, if the IBV_SEND_INLINE flag was set, the buffer +can be reused immediately after the call returns.

+

SEE ALSO

+ibv_create_qp, +ibv_create_xrc_rcv_qp, +ibv_create_ah, +ibv_post_recv, +ibv_post_srq_recv, +ibv_poll_cq

 

+

 

+


+IBV_POST_SRQ_RECV

+
+

NAME

+ibv_post_srq_recv - post a list of work requests (WRs) to a shared receive queue +(SRQ)

SYNOPSIS

+
#include <infiniband/verbs.h>
+
+int ibv_post_srq_recv(struct ibv_srq *srq, struct ibv_recv_wr *wr,
+                      struct ibv_recv_wr **bad_wr);
+

DESCRIPTION

+ibv_post_srq_recv() posts the linked list of work requests (WRs) starting +with wr to the shared receive queue (SRQ) srq. It stops processing +WRs from this list at the first failure (that can be detected immediately while +requests are being posted), and returns this failing WR through bad_wr. + +

The argument wr is an ibv_recv_wr struct, as defined in <infiniband/verbs.h>. +

+

+
struct ibv_recv_wr {
+uint64_t                wr_id;     /* User defined WR ID */
+struct ibv_recv_wr     *next;      /* Pointer to next WR in list, NULL if last WR */
+struct ibv_sge         *sg_list;   /* Pointer to the s/g array */
+int                     num_sge;   /* Size of the s/g array */
+};
+
+struct ibv_sge {
+uint64_t                addr;      /* Start address of the local memory buffer */
+uint32_t                length;    /* Length of the buffer */
+uint32_t                lkey;      /* Key of the local Memory Region */
+};
+

RETURN VALUE

+ibv_post_srq_recv() returns 0 on success, or the value of errno on +failure (which indicates the failure reason).

NOTES

+The buffers used by a WR can only be safely reused after WR the request is fully +executed and a work completion has been retrieved from the corresponding +completion queue (CQ). +

If a WR is being posted to a UD QP, the Global Routing Header (GRH) of the +incoming message will be placed in the first 40 bytes of the buffer(s) in the +scatter list. If no GRH is present in the incoming message, then the first bytes +will be undefined. This means that in all cases, the actual data of the incoming +message will start at an offset of 40 bytes into the buffer(s) in the scatter +list.

+

SEE ALSO

+ibv_create_qp, ibv_post_send, +ibv_post_recv, +ibv_poll_cq +

 

+

 

+


+IBV_QUERY_QP

+
+

NAME

+ibv_query_qp - get the attributes of a queue pair (QP)

SYNOPSIS

+
#include <infiniband/verbs.h>
+
+int ibv_query_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr,
+                 int attr_mask,
+                 struct ibv_qp_init_attr *init_attr);
+

DESCRIPTION

+ibv_query_qp() gets the attributes specified in attr_mask for the +QP qp and returns them through the pointers attr and init_attr. +The argument attr is an ibv_qp_attr struct, as defined in <infiniband/verbs.h>. +

+
struct ibv_qp_attr {
+enum ibv_qp_state       qp_state;            /* Current QP state */
+enum ibv_qp_state       cur_qp_state;        /* Current QP state - irrelevant for ibv_query_qp */
+enum ibv_mtu            path_mtu;            /* Path MTU (valid only for RC/UC QPs) */
+enum ibv_mig_state      path_mig_state;      /* Path migration state (valid if HCA supports APM) */
+uint32_t                qkey;                /* Q_Key of the QP (valid only for UD QPs) */
+uint32_t                rq_psn;              /* PSN for receive queue (valid only for RC/UC QPs) */
+uint32_t                sq_psn;              /* PSN for send queue (valid only for RC/UC QPs) */
+uint32_t                dest_qp_num;         /* Destination QP number (valid only for RC/UC QPs) */
+int                     qp_access_flags;     /* Mask of enabled remote access operations (valid only for RC/UC QPs) */
+struct ibv_qp_cap       cap;                 /* QP capabilities */
+struct ibv_ah_attr      ah_attr;             /* Primary path address vector (valid only for RC/UC QPs) */
+struct ibv_ah_attr      alt_ah_attr;         /* Alternate path address vector (valid only for RC/UC QPs) */
+uint16_t                pkey_index;          /* Primary P_Key index */
+uint16_t                alt_pkey_index;      /* Alternate P_Key index */
+uint8_t                 en_sqd_async_notify; /* Enable SQD.drained async notification - irrelevant for ibv_query_qp */
+uint8_t                 sq_draining;         /* Is the QP draining? (Valid only if qp_state is SQD) */
+uint8_t                 max_rd_atomic;       /* Number of outstanding RDMA reads & atomic operations on the destination QP (valid only for RC QPs) */
+uint8_t                 max_dest_rd_atomic;  /* Number of responder resources for handling incoming RDMA reads & atomic operations (valid only for RC QPs) */
+uint8_t                 min_rnr_timer;       /* Minimum RNR NAK timer (valid only for RC QPs) */
+uint8_t                 port_num;            /* Primary port number */
+uint8_t                 timeout;             /* Local ack timeout for primary path (valid only for RC QPs) */
+uint8_t                 retry_cnt;           /* Retry count (valid only for RC QPs) */
+uint8_t                 rnr_retry;           /* RNR retry (valid only for RC QPs) */
+uint8_t                 alt_port_num;        /* Alternate port number */
+uint8_t                 alt_timeout;         /* Local ack timeout for alternate path (valid only for RC QPs) */
+};
+
+

For details on struct ibv_qp_cap see the description of ibv_create_qp(). +For details on struct ibv_ah_attr see the description of ibv_create_ah().

+

RETURN VALUE

+ibv_query_qp() returns 0 on success, or the value of errno on failure +(which indicates the failure reason).

NOTES

+The argument attr_mask is a hint that specifies the minimum list of +attributes to retrieve. Some RDMA devices may return extra attributes not +requested, for example if the value can be returned cheaply. This has the same +form as in ibv_modify_qp(). + +

Attribute values are valid if they have been set using ibv_modify_qp(). +The exact list of valid attributes depends on the QP state.

+

Multiple calls to ibv_query_qp() may yield some differences in the +values returned for the following attributes: qp_state, path_mig_state, +sq_draining, ah_attr (if APM is enabled).

+

SEE ALSO

+ibv_create_qp, ibv_destroy_qp, +ibv_modify_qp, +ibv_create_ah

 

+

 

+


+IBV_ATTACH_MCAST

+


+IBV_DETACH_MCAST

+
+

NAME

+ibv_attach_mcast, ibv_detach_mcast - attach and detach a queue pair (QPs) +to/from a multicast group

SYNOPSIS

+
#include <infiniband/verbs.h>
+
+int ibv_attach_mcast(struct ibv_qp *qp, const union ibv_gid *gid, uint16_t lid);
+
+int ibv_detach_mcast(struct ibv_qp *qp, const union ibv_gid *gid, uint16_t lid);
+

DESCRIPTION

+ibv_attach_mcast() attaches the QP qp to the multicast group +having MGID gid and MLID lid. + +

ibv_detach_mcast() detaches the QP qp to the multicast group +having MGID gid and MLID lid.

+

RETURN VALUE

+ibv_attach_mcast() and ibv_detach_mcast() returns 0 on success, or +the value of errno on failure (which indicates the failure reason).

NOTES

+Only QPs of Transport Service Type IBV_QPT_UD may be attached to +multicast groups. +

If a QP is attached to the same multicast group multiple times, the QP will +still receive a single copy of a multicast message.

+

In order to receive multicast messages, a join request for the multicast +group must be sent to the subnet administrator (SA), so that the fabric's +multicast routing is configured to deliver messages to the local port.

+

SEE ALSO

+ibv_create_qp

 

+


+IBV_RATE_TO_MULT

+


+IBV_MULT_TO_RATE

+
+

NAME

+

ibv_rate_to_mult - convert IB rate enumeration to multiplier of 2.5 Gbit/sec
+
+mult_to_ibv_rate - convert multiplier of 2.5 Gbit/sec to an IB rate enumeration

+

SYNOPSIS

+
#include <infiniband/verbs.h>
+
+int ibv_rate_to_mult(enum ibv_rate rate);
+
+enum ibv_rate mult_to_ibv_rate(int mult);
+

DESCRIPTION

+ibv_rate_to_mult() converts the IB transmission rate enumeration rate +to a multiple of 2.5 Gbit/sec (the base rate). For example, if rate is +IBV_RATE_5_GBPS, the value 2 will be returned (5 Gbit/sec = 2 * 2.5 Gbit/sec). +

mult_to_ibv_rate() converts the multiplier value (of 2.5 Gbit/sec) +mult to an IB transmission rate enumeration. For example, if mult is +2, the rate enumeration IBV_RATE_5_GBPS will be returned.

+

RETURN VALUE

+ibv_rate_to_mult() returns the multiplier of the base rate 2.5 Gbit/sec. +

mult_to_ibv_rate() returns the enumeration representing the IB +transmission rate.

+

SEE ALSO

+ibv_query_port +
+ +

<return-to-top>

+

 

+

RDMA CM - Communications Manager

+
+
+ +
+

NAME

+
+

librdmacm.lib - RDMA + communication manager.

+
+

SYNOPSIS

+
+

#include <rdma/rdma_cma.h>

+
+

DESCRIPTION

+
+

Used to establish + communication endpoints over RDMA transports.

+
+

NOTES

+
+

The  RDMA CM is a communication manager used to setup reliable, connected + and unreliable datagram data transfers. It  + provides  an  RDMA transport  + neutral  interface for establishing connections.  The + API is based on sockets, but adapted for + queue pair (QP) based semantics: communication must be over a specific RDMA device, and data transfers are + message based.

+

The RDMA CM only provides + the communication management  (connection + setup / teardown) portion of an RDMA API.  It works in + conjunction with the verbs API  defined + by the libibverbs  library.   The  + libibverbs library provides the + interfaces needed to send and receive data.

+
+

CLIENT OPERATION

+

       This section + provides a general overview of the basic operation for the + active, or client, side of communication.  A  + general  connection  flow would + be:

+

       + rdma_create_event_channel

+

            + create channel to receive events

+

       rdma_create_id

+

            + allocate an rdma_cm_id, this is conceptually + similar to a socket

+

       + rdma_resolve_addr

+

            + obtain a local RDMA device to reach the remote + address

+

       + rdma_get_cm_event

+

            + wait for RDMA_CM_EVENT_ADDR_RESOLVED event

+

       rdma_ack_cm_event

+

            + ack event

+

       rdma_create_qp

+

            + allocate a QP for the communication

+

       + rdma_resolve_route

+

            + determine the route to the remote address

+

       + rdma_get_cm_event

+

            + wait for RDMA_CM_EVENT_ROUTE_RESOLVED event

+

       + rdma_ack_cm_event

+

            + ack event

+

       rdma_connect

+

            + connect to the remote server

+

       + rdma_get_cm_event

+

            + wait for RDMA_CM_EVENT_ESTABLISHED event

+

       + rdma_ack_cm_event

+

            + ack event

+

       Perform data + transfers over connection

+

       rdma_disconnect

+

            + tear-down connection

+

       + rdma_get_cm_event

+

            + wait for RDMA_CM_EVENT_DISCONNECTED event

+

       + rdma_ack_cm_event

+

            + ack event

+

       rdma_destroy_qp

+

            + destroy the QP

+

       rdma_destroy_id

+

            + release the rdma_cm_id

+

       + rdma_destroy_event_channel

+

            + release the event channel

+
+

An almost identical process is used to setup + unreliable datagram  (UD) + communication  between  nodes. 
+ No actual connection is formed between QPs however, so disconnection is not + needed.
+ Although this example shows the client + initiating the disconnect, either side of a + connection may initiate the disconnect.

+
+
+

SERVER OPERATION

+

       This section + provides a general overview of the basic operation for the + passive, or server, side of communication.  + A general  connection  flow + would be:

+

       + rdma_create_event_channel

+

            + create channel to receive events

+

       rdma_create_id

+

            + allocate an rdma_cm_id, this is conceptually + similar to a socket

+

       rdma_bind_addr

+

            + set the local port number to listen on

+

       rdma_listen

+

            + begin listening for connection requests

+

       + rdma_get_cm_event

+

            + wait  for   + RDMA_CM_EVENT_CONNECT_REQUEST  event with a new  rdma_cm_id.

+

       rdma_create_qp

+

            + allocate a QP for the communication on the new + rdma_cm_id

+

       rdma_accept

+

            + accept the connection request

+

       rdma_ack_cm_event

+

            + ack event

+

       + rdma_get_cm_event

+

            + wait for RDMA_CM_EVENT_ESTABLISHED event

+

       + rdma_ack_cm_event

+

            + ack event

+

       Perform data + transfers over connection

+

       + rdma_get_cm_event

+

            + wait for RDMA_CM_EVENT_DISCONNECTED even

+

       + rdma_ack_cm_event

+

            + ack event

+

       rdma_disconnect

+

            + tear-down connection

+

       rdma_destroy_qp

+

            + destroy the QP

+

       rdma_destroy_id

+

            + release the connected rdma_cm_id

+

       rdma_destroy_id

+

            + release the listening rdma_cm_id

+

       + rdma_destroy_event_channel

+

            + release the event channel

+

RETURN CODES

+

       + =  0   success

+

       = -1   + error - see errno for more details

+
+

Librdmacm functions return 0 to indicate + success, and a -1 return value to indicate + failure.

+

If a function operates asynchronously,  + a  return value  of  0  + means  that  the operation was successfully started. 
+ The + operation could still complete in error; + users should check the  status of  the + related event.
+
+ If the return value is -1, then errno will contain + additional information regarding the reason for the failure.
+ Prior + versions of the library would return -errno and not set errno for + some cases related to ENOMEM, ENODEV, ENODATA, + EINVAL, and EADDRNOTAVAIL codes.
+
Applications that want to check these codes and have compatibility  + with prior library versions must manually set errno to the negative + of the return code if it is < -1.

+
+

SEE ALSO

+
+

 rdma_create_event_channel, + rdma_get_cm_eventrdma_create_id,
+ rdma_resolve_addr,  + rdma_bind_addr, rdma_create_qp,
+ rdma_resolve_route, + rdma_connect, rdma_listen, + rdma_accept,
+ rdma_reject, + rdma_join_multicastrdma_leave_multicast,
+ rdma_notify,  rdma_ack_cm_eventrdma_disconnect,
+ rdma_destroy_qp,  + rdma_destroy_id, rdma_destroy_event_channel,
+ rdma_get_devicesrdma_free_devicesrdma_get_peer_addr,
+ rdma_get_local_addr,  rdma_get_dst_portrdma_get_src_port,
+ rdma_set_option

+
+
+

<return-to-top>

+
+ +

 

+


+RDMA_CREATE_ID

+
+

NAME
+
+RDMA_CREATE_ID - Allocate a communication identifier.  

+

SYNOPSIS

+#include <rdma/rdma_cma.h>

 int rdma_create_id (struct +rdma_event_channel *channel, struct rdma_cm_id **id, +void *context, enum rdma_port_space ps);

+

ARGUMENTS

+
+
channel
+
The communication channel that events associated with the allocated + rdma_cm_id will be reported on.
+
id
+
A reference where the allocated communication identifier will be + returned.
+
context
+
User specified context associated with the rdma_cm_id.
+
ps
+
RDMA port space.
+
+

DESCRIPTION

+Creates an identifier that is used to track communication information. +  +

NOTES

+Rdma_cm_id's are conceptually equivalent to a socket for RDMA communication. The +difference is that RDMA communication requires explicitly binding to a specified +RDMA device before communication can occur, and most operations are asynchronous +in nature. Communication events on an rdma_cm_id are reported through the +associated event channel. Users must release the rdma_cm_id by calling +rdma_destroy_id.   +

PORT SPACE

+Details of the services provided by the different port spaces are outlined +below. +
+
RDMA_PS_TCP
+
Provides reliable, connection-oriented QP communication. Unlike TCP, the + RDMA port space provides message, not stream, based communication.
+
RDMA_PS_UDP
+
Provides unreliable, connectionless QP communication. Supports both + datagram and multicast communication.
+
+

SEE ALSO

+rdma_cm, +rdma_create_event_channel, +rdma_destroy_id, rdma_get_devices, +rdma_bind_addr, rdma_resolve_addr, +rdma_connect, rdma_listen, +rdma_set_option

 

+


+RDMA_DESTROY_ID

+
+

NAME
+
+RDMA_DESTROY_ID - Release a communication +identifier.

+

SYNOPSIS

+#include <rdma/rdma_cma.h> int rdma_destroy_id (struct +rdma_cm_id *id);

ARGUMENTS

+
+
id
+
The communication identifier to destroy. +
+
+

DESCRIPTION

+Destroys the specified rdma_cm_id and cancels any outstanding asynchronous +operation.

NOTES

+Users must free any associated QP with the rdma_cm_id before calling this +routine and ack an related events.

SEE ALSO

+rdma_create_id, rdma_destroy_qp, +rdma_ack_cm_event +

 

+


+RDMA_CREATE_EVENT_CHANNEL

+
+

NAME

+rdma_create_event_channel - Open a channel used to report communication events.

+SYNOPSIS

+#include <rdma/rdma_cma.h>

 struct rdma_event_channel * +rdma_create_event_channel (void);

+

ARGUMENTS

+
+
void
+
no arguments +
+
+

DESCRIPTION

+Asynchronous events are reported to users through event channels. +

NOTES

+Event channels are used to direct all events on an rdma_cm_id. For many clients, +a single event channel may be sufficient, however, when managing a large number +of connections or cm_id's, users may find it useful to direct events for +different cm_id's to different channels for processing. All created event +channels must be destroyed by calling rdma_destroy_event_channel. Users should +call rdma_get_cm_event to retrieve events on an event channel. Each event +channel is mapped to a file descriptor. The associated file descriptor can be +used and manipulated like any other fd to change its behavior. Users may make +the fd non-blocking, poll or select the fd, etc.   +

SEE ALSO

+rdma_cm, +rdma_get_cm_event, rdma_destroy_event_channel +

 

+


+RDMA_DESTROY_EVENT_CHANNEL

+
+

NAME

+rdma_destroy_event_channel - Close an event communication channel. +  +

SYNOPSIS

+#include <rdma/rdma_cma.h>

 void rdma_destroy_event_channel (struct +rdma_event_channel *channel);  

+

ARGUMENTS

+
+
channel
+
The communication channel to destroy. +
+
+

DESCRIPTION

+Release all resources associated with an event channel and closes the associated +file descriptor.   +

NOTES

+All rdma_cm_id's associated with the event channel must be destroyed, and all +returned events must be acked before calling this function.   +

SEE ALSO

+rdma_create_event_channel, +rdma_get_cm_event, rdma_ack_cm_event +

 

+


+RDMA_RESOLVE_ADDR

+
+

NAME

+rdma_resolve_addr - Resolve destination and optional source addresses. +

SYNOPSIS

+#include <rdma/rdma_cma.h>

 int rdma_resolve_addr (struct +rdma_cm_id *id, struct sockaddr *src_addr, +struct sockaddr *dst_addr, int timeout_ms);

+

ARGUMENTS

+
+
id
+
RDMA identifier. +
+
src_addr
+
Source address information. This parameter may be NULL. +
+
dst_addr
+
Destination address information. +
+
timeout_ms
+
Time to wait for resolution to complete. +
+
+

DESCRIPTION

+Resolve destination and optional source addresses from IP addresses to an RDMA +address. If successful, the specified rdma_cm_id will be bound to a local +device.   +

NOTES

+This call is used to map a given destination IP address to a usable RDMA +address. The IP to RDMA address mapping is done using the local routing tables, +or via ARP. If a source address is given, the rdma_cm_id is bound to that +address, the same as if rdma_bind_addr were called. If no source address is +given, and the rdma_cm_id has not yet been bound to a device, then the +rdma_cm_id will be bound to a source address based on the local routing tables. +After this call, the rdma_cm_id will be bound to an RDMA device. This call is +typically made from the active side of a connection before calling +rdma_resolve_route and rdma_connect.   +

INFINIBAND SPECIFIC

+This call maps the destination and, if given, source IP addresses to GIDs. In +order to perform the mapping, IPoIB must be running on both the local and remote +nodes.   +

SEE ALSO

+rdma_create_id, rdma_resolve_route, +rdma_connect, rdma_create_qp, +rdma_get_cm_event, rdma_bind_addr, +rdma_get_src_port, rdma_get_dst_port, +rdma_get_local_addr, +rdma_get_peer_addr +

 

+


+RDMA_GET_CM_EVENT

+
+

NAME

+rdma_get_cm_event - Retrieves the next pending communication event. +

SYNOPSIS

+#include <rdma/rdma_cma.h>

 int rdma_get_cm_event (struct +rdma_event_channel *channel, struct rdma_cm_event **event); +

+

ARGUMENTS

+
+
channel
+
Event channel to check for events. +
+
event
+
Allocated information about the next communication event. +
+
+

DESCRIPTION

+Retrieves a communication event. If no events are pending, by default, the call +will block until an event is received. +

NOTES

+The default synchronous behavior of this routine can be changed by modifying the +file descriptor associated with the given channel. All events that are reported +must be acknowledged by calling rdma_ack_cm_event. Destruction of an rdma_cm_id +will block until related events have been acknowledged.

EVENT DATA

+Communication event details are returned in the rdma_cm_event structure. This +structure is allocated by the rdma_cm and released by the rdma_ack_cm_event +routine. Details of the rdma_cm_event structure are given below. +
+
id
+
The rdma_cm identifier associated with the event. If the event type is + RDMA_CM_EVENT_CONNECT_REQUEST, then this references a new id for that + communication. +
+
listen_id
+
For RDMA_CM_EVENT_CONNECT_REQUEST event types, this references the + corresponding listening request identifier. +
+
event
+
Specifies the type of communication event which occurred. See EVENT + TYPES below. +
+
status
+
Returns any asynchronous error information associated with an event. The + status is zero unless the corresponding operation failed. +
+
param
+
Provides additional details based on the type of event. Users should + select the conn or ud subfields based on the rdma_port_space of the + rdma_cm_id associated with the event. See UD EVENT DATA and CONN EVENT DATA + below. +
+
+

UD EVENT DATA

+Event parameters related to unreliable datagram (UD) services: RDMA_PS_UDP and +RDMA_PS_IPOIB. The UD event data is valid for RDMA_CM_EVENT_ESTABLISHED and +RDMA_CM_EVENT_MULTICAST_JOIN events, unless stated otherwise. +
+
private_data
+
References any user-specified data associated with + RDMA_CM_EVENT_CONNECT_REQUEST or RDMA_CM_EVENT_ESTABLISHED events. The data + referenced by this field matches that specified by the remote side when + calling rdma_connect or rdma_accept. This field is NULL if the event does + not include private data. The buffer referenced by this pointer is + deallocated when calling rdma_ack_cm_event. +
+
private_data_len
+
The size of the private data buffer. Users should note that the size of + the private data buffer may be larger than the amount of private data sent + by the remote side. Any additional space in the buffer will be zeroed out. +
+
ah_attr
+
Address information needed to send data to the remote endpoint(s). Users + should use this structure when allocating their address handle. +
+
qp_num
+
QP number of the remote endpoint or multicast group. +
+
qkey
+
QKey needed to send data to the remote endpoint(s).
+
+

CONN EVENT DATA

+Event parameters related to connected QP services: RDMA_PS_TCP. The connection +related event data is valid for RDMA_CM_EVENT_CONNECT_REQUEST and +RDMA_CM_EVENT_ESTABLISHED events, unless stated otherwise. +
+
private_data
+
References any user-specified data associated with the event. The data + referenced by this field matches that specified by the remote side when + calling rdma_connect or rdma_accept. This field is NULL if the event does + not include private data. The buffer referenced by this pointer is + deallocated when calling rdma_ack_cm_event. +
+
private_data_len
+
The size of the private data buffer. Users should note that the size of + the private data buffer may be larger than the amount of private data sent + by the remote side. Any additional space in the buffer will be zeroed out. +
+
responder_resources
+
The number of responder resources requested of the recipient. This field + matches the initiator depth specified by the remote node when calling + rdma_connect and rdma_accept. +
+
initiator_depth
+
The maximum number of outstanding RDMA read/atomic operations that the + recipient may have outstanding. This field matches the responder resources + specified by the remote node when calling rdma_connect and rdma_accept. +
+
flow_control
+
Indicates if hardware level flow control is provided by the sender. +
+
retry_count
+
For RDMA_CM_EVENT_CONNECT_REQUEST events only, indicates the number of + times that the recipient should retry send operations. +
+
rnr_retry_count
+
The number of times that the recipient should retry receiver not ready + (RNR) NACK errors. +
+
srq
+
Specifies if the sender is using a shared-receive queue. +
+
qp_num
+
Indicates the remote QP number for the connection. +
+
+

EVENT TYPES

+The following types of communication events may be reported. +
+
RDMA_CM_EVENT_ADDR_RESOLVED
+
Address resolution (rdma_resolve_addr) completed successfully. +
+
RDMA_CM_EVENT_ADDR_ERROR
+
Address resolution (rdma_resolve_addr) failed. +
+
RDMA_CM_EVENT_ROUTE_RESOLVED
+
Route resolution (rdma_resolve_route) completed successfully. +
+
RDMA_CM_EVENT_ROUTE_ERROR
+
Route resolution (rdma_resolve_route) failed. +
+
RDMA_CM_EVENT_CONNECT_REQUEST
+
Generated on the passive side to notify the user of a new connection + request. +
+
RDMA_CM_EVENT_CONNECT_RESPONSE
+
Generated on the active side to notify the user of a successful response + to a connection request. It is only generated on rdma_cm_id's that do not + have a QP associated with them. +
+
RDMA_CM_EVENT_CONNECT_ERROR
+
Indicates that an error has occurred trying to establish or a + connection. May be generated on the active or passive side of a connection. +
+
RDMA_CM_EVENT_UNREACHABLE
+
Generated on the active side to notify the user that the remote server + is not reachable or unable to respond to a connection request. +
+
RDMA_CM_EVENT_REJECTED
+
Indicates that a connection request or response was rejected by the + remote end point. +
+
RDMA_CM_EVENT_ESTABLISHED
+
Indicates that a connection has been established with the remote end + point. +
+
RDMA_CM_EVENT_DISCONNECTED
+
The connection has been disconnected. +
+
RDMA_CM_EVENT_DEVICE_REMOVAL
+
The local RDMA device associated with the rdma_cm_id has been removed. + Upon receiving this event, the user must destroy the related rdma_cm_id. +
+
RDMA_CM_EVENT_MULTICAST_JOIN
+
The multicast join operation (rdma_join_multicast) completed + successfully. +
+
RDMA_CM_EVENT_MULTICAST_ERROR
+
An error either occurred joining a multicast group, or, if the group had + already been joined, on an existing group. The specified multicast group is + no longer accessible and should be rejoined, if desired. +
+
RDMA_CM_EVENT_ADDR_CHANGE
+
The network device associated with this ID through address resolution + changed its HW address, eg following of bonding failover. This event can + serve as a hint for applications who want the links used for their RDMA + sessions to align with the network stack. +
+
RDMA_CM_EVENT_TIMEWAIT_EXIT
+
The QP associated with a connection has exited its timewait state and is + now ready to be re-used. After a QP has been disconnected, it is maintained + in a timewait state to allow any in flight packets to exit the network. + After the timewait state has completed, the rdma_cm will report this event. +
+
+

SEE ALSO

+rdma_ack_cm_event, +rdma_create_event_channel, +rdma_resolve_addr, +rdma_resolve_route, rdma_connect, +rdma_listen, rdma_join_multicast, +rdma_destroy_id, rdma_event_str

 

+


+RDMA_ACK_CM_EVENT

+
+

NAME

+
+ +rdma_ack_cm_event - Free a communication event.

SYNOPSIS

+
+ +#include <rdma/rdma_cma.h>

 int rdma_ack_cm_event (struct +rdma_cm_event *event);

+

ARGUMENTS

+
+ +
+
event
+
Event to be released. +
+
+
+ +

DESCRIPTION

+
+ +All events which are allocated by rdma_get_cm_event must be released, there +should be a one-to-one correspondence between successful gets and acks. This +call frees the event structure and any memory that it references.

SEE ALSO

+
+ +rdma_get_cm_event, rdma_destroy_id + + +

 

+
+ +


+RDMA_CREATE_QP

+
+

NAME

+rdma_create_qp - Allocate a QP.   +

SYNOPSIS

+#include <rdma/rdma_cma.h>

 int rdma_create_qp (struct +rdma_cm_id *id, struct ibv_pd *pd, +struct ibv_qp_init_attr *qp_init_attr);

+

ARGUMENTS

+
+
id
+
RDMA identifier. +
+
pd
+
protection domain for the QP. +
+
qp_init_attr
+
initial QP attributes. +
+
+

DESCRIPTION

+Allocate a QP associated with the specified rdma_cm_id and transition it for +sending and receiving. +

NOTES

+The rdma_cm_id must be bound to a local RDMA device before calling this +function, and the protection domain must be for that same device. QPs allocated +to an rdma_cm_id are automatically transitioned by the librdmacm through their +states. After being allocated, the QP will be ready to handle posting of +receives. If the QP is unconnected, it will be ready to post sends.

SEE ALSO

+rdma_bind_addr, +rdma_resolve_addr, rdma_destroy_qp, +ibv_create_qp, +ibv_modify_qp +

 

+


+RDMA_DESTROY_QP

+
+

NAME

+rdma_destroy_qp - Deallocate a QP.

SYNOPSIS

+#include <rdma/rdma_cma.h>

 void rdma_destroy_qp (struct +rdma_cm_id *id);

+

ARGUMENTS

+
+
id
+
RDMA identifier. +
+
+

DESCRIPTION

+Destroy a QP allocated on the rdma_cm_id.

NOTES

+Users must destroy any QP associated with an rdma_cm_id before destroying the +ID.

SEE ALSO

+rdma_create_qp, +rdma_destroy_id, ibv_destroy_qp +

 

+


+RDMA_ACCEPT

+
+

NAME

+rdma_accept - Called to accept a connection request.   +

SYNOPSIS

+#include <rdma/rdma_cma.h>

 int rdma_accept (struct +rdma_cm_id *id, struct rdma_conn_param *conn_param); + 

+

ARGUMENTS

+
+
id
+
Connection identifier associated with the request. +
+
conn_param
+
Information needed to establish the connection. See CONNECTION + PROPERTIES below for details. +
+
+

DESCRIPTION

+Called from the listening side to accept a connection or datagram service lookup +request. +

NOTES

+Unlike the socket accept routine, rdma_accept is not called on a listening +rdma_cm_id. Instead, after calling rdma_listen, the user waits for an +RDMA_CM_EVENT_CONNECT_REQUEST event to occur. Connection request events give the +user a newly created rdma_cm_id, similar to a new socket, but the rdma_cm_id is +bound to a specific RDMA device. rdma_accept is called on the new rdma_cm_id.

+CONNECTION PROPERTIES

+The following properties are used to configure the communication and specified +by the conn_param parameter when accepting a connection or datagram +communication request. Users should use the rdma_conn_param values reported in +the connection request event to determine appropriate values for these fields +when accepting. Users may reference the rdma_conn_param structure in the +connection event directly, or can reference their own structure. If the +rdma_conn_param structure from an event is referenced, the event must not be +acked until after this call returns. +
+
private_data
+
References a user-controlled data buffer. The contents of the buffer are + copied and transparently passed to the remote side as part of the + communication request. May be NULL if private_data is not required. +
+
private_data_len
+
Specifies the size of the user-controlled data buffer. Note that the + actual amount of data transferred to the remote side is transport dependent + and may be larger than that requested. +
+
responder_resources
+
The maximum number of outstanding RDMA read and atomic operations that + the local side will accept from the remote side. Applies only to RDMA_PS_TCP. + This value must be less than or equal to the local RDMA device attribute + max_qp_rd_atom and the responder_resources value reported in the connect + request event. +
+
initiator_depth
+
The maximum number of outstanding RDMA read and atomic operations that + the local side will have to the remote side. Applies only to RDMA_PS_TCP. + This value must be less than or equal to the local RDMA device attribute + max_qp_init_rd_atom and the initiator_depth value reported in the connect + request event. +
+
flow_control
+
Specifies if hardware flow control is available. This value is exchanged + with the remote peer and is not used to configure the QP. Applies only to + RDMA_PS_TCP. +
+
retry_count
+
This value is ignored. +
+
rnr_retry_count
+
The maximum number of times that a send operation from the remote peer + should be retried on a connection after receiving a receiver not ready (RNR) + error. RNR errors are generated when a send request arrives before a buffer + has been posted to receive the incoming data. Applies only to RDMA_PS_TCP. +
+
srq
+
Specifies if the QP associated with the connection is using a shared + receive queue. This field is ignored by the library if a QP has been created + on the rdma_cm_id. Applies only to RDMA_PS_TCP. +
+
qp_num
+
Specifies the QP number associated with the connection. This field is + ignored by the library if a QP has been created on the rdma_cm_id. +
+
+

INFINIBAND SPECIFIC

+In addition to the connection properties defined above, InfiniBand QPs are +configured with minimum RNR NAK timer and local ACK timeout values. The minimum +RNR NAK timer value is set to 0, for a delay of 655 ms. The local ACK timeout is +calculated based on the packet lifetime and local HCA ACK delay. The packet +lifetime is determined by the InfiniBand Subnet Administrator and is part of the +route (path record) information obtained by the active side of the connection. +The HCA ACK delay is a property of the locally used HCA. The RNR retry count is +a 3-bit value.

SEE ALSO

+rdma_listen, rdma_reject, +rdma_get_cm_event +

 

+


+RDMA_CONNECT

+
+

NAME

+rdma_connect - Initiate an active connection request.

SYNOPSIS

+#include <rdma/rdma_cma.h>

 int rdma_connect (struct +rdma_cm_id *id, struct rdma_conn_param *conn_param); +

+

ARGUMENTS

+
+
id
+
RDMA identifier. +
+
conn_param
+
connection parameters. See CONNECTION PROPERTIES below for details. +
+
+

DESCRIPTION

+For an rdma_cm_id of type RDMA_PS_TCP, this call initiates a connection request +to a remote destination. For an rdma_cm_id of type RDMA_PS_UDP, it initiates a +lookup of the remote QP providing the datagram service.

NOTES

+Users must have resolved a route to the destination address by having called +rdma_resolve_route before calling this routine. +

CONNECTION PROPERTIES

+The following properties are used to configure the communication and specified +by the conn_param parameter when connecting or establishing datagram +communication. +
+
private_data
+
References a user-controlled data buffer. The contents of the buffer are + copied and transparently passed to the remote side as part of the + communication request. May be NULL if private_data is not required. +
+
private_data_len
+
Specifies the size of the user-controlled data buffer. Note that the + actual amount of data transferred to the remote side is transport dependent + and may be larger than that requested. +
+
responder_resources
+
The maximum number of outstanding RDMA read and atomic operations that + the local side will accept from the remote side. Applies only to RDMA_PS_TCP. + This value must be less than or equal to the local RDMA device attribute + max_qp_rd_atom and remote RDMA device attribute max_qp_init_rd_atom. The + remote endpoint can adjust this value when accepting the connection. +
+
initiator_depth
+
The maximum number of outstanding RDMA read and atomic operations that + the local side will have to the remote side. Applies only to RDMA_PS_TCP. + This value must be less than or equal to the local RDMA device attribute + max_qp_init_rd_atom and remote RDMA device attribute max_qp_rd_atom. The + remote endpoint can adjust this value when accepting the connection. +
+
flow_control
+
Specifies if hardware flow control is available. This value is exchanged + with the remote peer and is not used to configure the QP. Applies only to + RDMA_PS_TCP. +
+
retry_count
+
The maximum number of times that a data transfer operation should be + retried on the connection when an error occurs. This setting controls the + number of times to retry send, RDMA, and atomic operations when timeouts + occur. Applies only to RDMA_PS_TCP. +
+
rnr_retry_count
+
The maximum number of times that a send operation from the remote peer + should be retried on a connection after receiving a receiver not ready (RNR) + error. RNR errors are generated when a send request arrives before a buffer + has been posted to receive the incoming data. Applies only to RDMA_PS_TCP. +
+
srq
+
Specifies if the QP associated with the connection is using a shared + receive queue. This field is ignored by the library if a QP has been created + on the rdma_cm_id. Applies only to RDMA_PS_TCP. +
+
qp_num
+
Specifies the QP number associated with the connection. This field is + ignored by the library if a QP has been created on the rdma_cm_id. Applies + only to RDMA_PS_TCP. +
+
+

INFINIBAND SPECIFIC

+In addition to the connection properties defined above, InfiniBand QPs are +configured with minimum RNR NAK timer and local ACK timeout values. The minimum +RNR NAK timer value is set to 0, for a delay of 655 ms. The local ACK timeout is +calculated based on the packet lifetime and local HCA ACK delay. The packet +lifetime is determined by the InfiniBand Subnet Administrator and is part of the +resolved route (path record) information. The HCA ACK delay is a property of the +locally used HCA. Retry count and RNR retry count values are 3-bit values.

+IWARP SPECIFIC

+Connections established over iWarp RDMA devices currently require that the +active side of the connection send the first message. +

SEE ALSO

+rdma_cm, +rdma_create_id, +rdma_resolve_route, rdma_disconnect, +rdma_listen, +rdma_get_cm_event +

 

+


+RDMA_DISCONNECT

+
+

NAME

+rdma_disconnect - This function disconnects a connection.   +

SYNOPSIS

+#include <rdma/rdma_cma.h>

 int rdma_disconnect (struct +rdma_cm_id *id);

+

ARGUMENTS

+
+
id
+
RDMA identifier. +
+
+

DESCRIPTION

+Disconnects a connection and transitions any associated QP to the error state, +which will flush any posted work requests to the completion queue. This routine +may be called by both the client and server side of a connection. After +successfully disconnecting, an RDMA_CM_EVENT_DISCONNECTED event will be +generated on both sides of the connection.

SEE ALSO

+rdma_connect, rdma_listen, +rdma_accept, +rdma_get_cm_event

 

+


+RDMA_RESOLVE_ROUTE

+
+

NAME

+rdma_resolve_route - Resolve the route information needed to establish a +connection.

SYNOPSIS

+#include <rdma/rdma_cma.h>

 int rdma_resolve_route (struct +rdma_cm_id *id, int timeout_ms);

+

ARGUMENTS

+
+
id
+
RDMA identifier. +
+
timeout_ms
+
Time to wait for resolution to complete. +
+
+

DESCRIPTION

+Resolves an RDMA route to the destination address in order to establish a +connection. The destination address must have already been resolved by calling +rdma_resolve_addr. +

NOTES

+This is called on the client side of a connection after calling +rdma_resolve_addr, but before calling rdma_connect.

INFINIBAND SPECIFIC

+This call obtains a path record that is used by the connection. +

SEE ALSO

+rdma_resolve_addr, +rdma_connect, rdma_get_cm_event +

 

+


+RDMA_BIND_ADDR

+
+

NAME

+rdma_bind_addr - Bind an RDMA identifier to a source address.

SYNOPSIS

+#include <rdma/rdma_cma.h>

 int rdma_bind_addr (struct +rdma_cm_id *id, struct sockaddr *addr); +

+

ARGUMENTS

+
+
id
+
RDMA identifier. +
+
addr
+
Local address information. Wildcard values are permitted. +
+
+

DESCRIPTION

+Associates a source address with an rdma_cm_id. The address may be wildcarded. +If binding to a specific local address, the rdma_cm_id will also be bound to a +local RDMA device.

NOTES

+Typically, this routine is called before calling rdma_listen to bind to a +specific port number, but it may also be called on the active side of a +connection before calling rdma_resolve_addr to bind to a specific address. If +used to bind to port 0, the rdma_cm will select an available port, which can be +retrieved with rdma_get_src_port.

SEE ALSO

+rdma_create_id, rdma_listen, +rdma_resolve_addr, +rdma_create_qp, rdma_get_local_addr, +rdma_get_src_port +

 

+


+RDMA_LISTEN

+
+

NAME

+rdma_listen - Listen for incoming connection requests.

SYNOPSIS

+#include <rdma/rdma_cma.h>

 int rdma_listen (struct +rdma_cm_id *id, int backlog);

+

ARGUMENTS

+
+
id
+
RDMA identifier. +
+
backlog
+
backlog of incoming connection requests. +
+
+

DESCRIPTION

+Initiates a listen for incoming connection requests or datagram service lookup. +The listen will be restricted to the locally bound source address. +

NOTES

+Users must have bound the rdma_cm_id to a local address by calling +rdma_bind_addr before calling this routine. If the rdma_cm_id is bound to a +specific IP address, the listen will be restricted to that address and the +associated RDMA device. If the rdma_cm_id is bound to an RDMA port number only, +the listen will occur across all RDMA devices.

SEE ALSO

+rdma_cm, +rdma_bind_addr, +rdma_connect, rdma_accept, +rdma_reject, rdma_get_cm_event +

 

+


+RDMA_REJECT

+
+

NAME

+rdma_reject - Called to reject a connection request.

SYNOPSIS

+#include <rdma/rdma_cma.h>

 int rdma_reject (struct +rdma_cm_id *id, const void *private_data, +uint8_t private_data_len);

+

ARGUMENTS

+
+
id
+
Connection identifier associated with the request. +
+
private_data
+
Optional private data to send with the reject message. +
+
private_data_len
+
Specifies the size of the user-controlled data buffer. Note that the + actual amount of data transferred to the remote side is transport dependent + and may be larger than that requested. +
+
+

DESCRIPTION

+Called from the listening side to reject a connection or datagram service lookup +request.

NOTES

+After receiving a connection request event, a user may call rdma_reject to +reject the request. If the underlying RDMA transport supports private data in +the reject message, the specified data will be passed to the remote side. +

SEE ALSO

+rdma_listen, rdma_accept, +rdma_get_cm_event +

 

+


+RDMA_GET_SRC_PORT

+
+

NAME

+rdma_get_src_port - Returns the local port number of a bound rdma_cm_id.

+SYNOPSIS

+#include <rdma/rdma_cma.h>

 uint16_t rdma_get_src_port +(struct rdma_cm_id *id);  

+

ARGUMENTS

+
+
id
+
RDMA identifier. +
+
+

DESCRIPTION

+Returns the local port number for an rdma_cm_id that has been bound to a local +address.

SEE ALSO

+rdma_bind_addr, +rdma_resolve_addr, rdma_get_dst_port, +rdma_get_local_addr, +rdma_get_peer_addr +

 

+


+RDMA_GET_DST_PORT

+
+

NAME

+rdma_get_dst_port - Returns the remote port number of a bound rdma_cm_id.

+SYNOPSIS

+#include <rdma/rdma_cma.h>

 uint16_t rdma_get_dst_port +(struct rdma_cm_id *id);

+

ARGUMENTS

+
+
id
+
RDMA identifier.
+
+

DESCRIPTION

+Returns the remote port number for an rdma_cm_id that has been bound to a remote +address.

SEE ALSO

+rdma_connect, rdma_accept, +rdma_get_cm_event, +rdma_get_src_port, rdma_get_local_addr, +rdma_get_peer_addr +

 

+


+RDMA_GET_LOCAL_ADDR

+
+

NAME

+rdma_get_local_addr - Returns the local IP address of a bound rdma_cm_id. +

SYNOPSIS

+#include <rdma/rdma_cma.h>

 struct sockaddr * rdma_get_local_addr +(struct rdma_cm_id *id);

+

ARGUMENTS

+
+
id
+
RDMA identifier. +
+
+

DESCRIPTION

+Returns the local IP address for an rdma_cm_id that has been bound to a local +device.

SEE ALSO

+rdma_bind_addr, +rdma_resolve_addr, rdma_get_src_port, +rdma_get_dst_port, +rdma_get_peer_addr +

 

+


+RDMA_GET_PEER_ADDR

+
+

NAME

+rdma_get_peer_addr - Returns the remote IP address of a bound rdma_cm_id.

+SYNOPSIS

+#include <rdma/rdma_cma.h>

 struct sockaddr * rdma_get_peer_addr +(struct rdma_cm_id *id);

+

ARGUMENTS

+
+
id
+
RDMA identifier.
+
+

DESCRIPTION

+Returns the remote IP address associated with an rdma_cm_id.

SEE ALSO

+rdma_resolve_addr, +rdma_get_src_port, rdma_get_dst_port, +rdma_get_local_addr

 

+


+RDMA_EVENT_STR

+
+

NAME

+rdma_event_str - Returns a string representation of an rdma cm event.

+SYNOPSIS

+#include <rdma/rdma_cma.h>

 char * rdma_event_str (enumrdma_cm_event_type +event );

+

ARGUMENTS

+
+
event
+
Asynchronous event.
+
+

DESCRIPTION

+Returns a string representation of an asynchronous event.

SEE ALSO

+rdma_get_cm_event

 

+


+RDMA_JOIN_MULTICAST

+
+

NAME

+rdma_join_multicast - Joins a multicast group.

SYNOPSIS

+#include <rdma/rdma_cma.h>

 int rdma_join_multicast (struct +rdma_cm_id *id, struct sockaddr *addr, +void *context);

+

ARGUMENTS

+
+
id
+
Communication identifier associated with the request. +
+
addr
+
Multicast address identifying the group to join. +
+
context
+
User-defined context associated with the join request.
+
+

DESCRIPTION

+Joins a multicast group and attaches an associated QP to the group.

NOTES

+Before joining a multicast group, the rdma_cm_id must be bound to an RDMA device +by calling rdma_bind_addr or rdma_resolve_addr. Use of rdma_resolve_addr +requires the local routing tables to resolve the multicast address to an RDMA +device, unless a specific source address is provided. The user must call +rdma_leave_multicast to leave the multicast group and release any multicast +resources. After the join operation completes, any associated QP is +automatically attached to the multicast group, and the join context is returned +to the user through the private_data field in the rdma_cm_event.

SEE ALSO

+rdma_leave_multicast, +rdma_bind_addr, +rdma_resolve_addr, rdma_create_qp, +rdma_get_cm_event +

 

+


+RDMA_LEAVE_MULTICAST

+
+

NAME

+rdma_leave_multicast - Leaves a multicast group. +

SYNOPSIS

+#include <rdma/rdma_cma.h>

 int rdma_leave_multicast (struct +rdma_cm_id *id, struct sockaddr *addr);

+

ARGUMENTS

+
+
id
+
Communication identifier associated with the request. +
+
addr
+
Multicast address identifying the group to leave.
+
+

DESCRIPTION

+Leaves a multicast group and detaches an associated QP from the group.

NOTES

+Calling this function before a group has been fully joined results in canceling +the join operation. Users should be aware that messages received from the +multicast group may stilled be queued for completion processing immediately +after leaving a multicast group. Destroying an rdma_cm_id will automatically +leave all multicast groups.

SEE ALSO

+rdma_join_multicast, +rdma_destroy_qp +

 

+


+RDMA_SET_OPTION

+
+

NAME

+rdma_set_option - Set communication options for an rdma_cm_id.

SYNOPSIS

+#include <rdma/rdma_cma.h>

 int rdma_set_option (struct +rdma_cm_id *id, int level, int +optname, void *optval, size_t optlen); +

+

ARGUMENTS

+
+
id
+
RDMA identifier. +
+
level
+
Protocol level of the option to set. +
+
optname
+
Name of the option, relative to the level, to set. +
+
optval
+
Reference to the option data. The data is dependent on the level and + optname. +
+
optlen
+
The size of the %optval buffer. +
+
+

DESCRIPTION

+Sets communication options for an rdma_cm_id. This call is used to override the +default system settings.

NOTES

+Option details may be found in the relevent header files.

SEE ALSO

+rdma_create_id +

 

+


+RDMA_GET_DEVICES

+
+

NAME

+rdma_get_devices - Get a list of RDMA devices currently available.

SYNOPSIS

+#include <rdma/rdma_cma.h>

 struct ibv_context ** rdma_get_devices +(int *num_devices);

+

ARGUMENTS

+
+
num_devices
+
If non-NULL, set to the number of devices returned. +
+
+

DESCRIPTION

+Return a NULL-terminated array of opened RDMA devices. Callers can use this +routine to allocate resources on specific RDMA devices that will be shared +across multiple rdma_cm_id's.

NOTES

+The returned array must be released by calling rdma_free_devices. Devices remain +opened while the librdmacm is loaded +

SEE ALSO

+rdma_free_devices +

 

+


+RDMA_FREE_DEVICES

+
+

NAME

+rdma_free_devices - Frees the list of devices returned by rdma_get_devices.

+SYNOPSIS

+#include <rdma/rdma_cma.h>

 void rdma_free_devices (struct +ibv_context **list);

+

ARGUMENTS

+
+
list
+
List of devices returned from rdma_get_devices.
+
+

DESCRIPTION

+Frees the device array returned by rdma_get_devices.

SEE ALSO

+rdma_get_devices +

 

+


+RDMA_NOTIFY

+
+

NAME

+rdma_notify - Notifies the librdmacm of an asynchronous event.

SYNOPSIS

+#include <rdma/rdma_cma.h>

 int rdma_notify (struct +rdma_cm_id *id, enum ibv_event_type event);

+

ARGUMENTS

+
+
id
+
RDMA identifier. +
+
event
+
Asynchronous event.
+
+

DESCRIPTION

+Used to notify the librdmacm of asynchronous events that have occurred on a QP +associated with the rdma_cm_id.

NOTES

+Asynchronous events that occur on a QP are reported through the user's device +event handler. This routine is used to notify the librdmacm of communication +events. In most cases, use of this routine is not necessary, however if +connection establishment is done out of band (such as done through Infiniband), +it's possible to receive data on a QP that is not yet considered connected. This +routine forces the connection into an established state in this case in order to +handle the rare situation where the connection never forms on its own. Events +that should be reported to the CM are: IB_EVENT_COMM_EST.

SEE ALSO

+rdma_connect, rdma_accept, +rdma_listen +

+ +<return-to-top>

+

 

+

 

+

WinVerbs

+ +
+
+ +

WinVerbs is a userspace verbs and communication management interface optimized
for the Windows operating system. Its lower interface is designed to support
any RDMA based device, including Infiniband and +future RDMA devices. Its upper interface is
capable of providing a low latency verbs interface, plus supports Microsoft's
NetworkDirect Interface, DAPL and OFED +components: libibverbs, libibmad, rdma_cm interfaces and numerous OFED IB +diagnostic tools.
+
The WinVerbs driver loads as an upper filter driver for Infiniband HCA +devices.
(Open source iWarp drivers for Windows are not yet available.) A corresponding
userspace library installs as part of the Winverbs driver installation package.
Additionally, a Windows port of the OFED libibverbs library and several test
programs are also included.

+

As of the WinOF 2.1 release, Winverbs and Winmad are are fully integrated +into the HCA driver stack load.
+That's to say, Winverbs and Winmad are now integral components of the OFED +stack.
+
Available libibverbs test programs and their usage are listed
below. Note that not all listed options apply to all applications
+
ibv_rc_pingpong, ibv_uc_pingpong, ibv_ud_pingpong
no args start a server and wait for connection
-h <host>     connect to server at <host>
-p <port>     listen on/connect to port <port> (default 18515)
-d <dev>     use IB device <dev> (default first device found)
-i <port>      use port <port> of IB device (default 1)
-s <size>      size of message to exchange (default 4096)
-m <size>     path MTU (default 1024)
-r <dep>      number of receives to post at a time (default 500)
-n <iters>     number of exchanges (default 1000)
-l <sl>          service level value
-e                 sleep on CQ events (default poll)
+
ibv_send_bw, ibv_send_lat
ibv_read_bw, ibv_read_lat
ibv_write_bw, ibv_write_lat
no args start a server and wait for connection
-h <host>              connect to server at <host>
-p <port>              listen on/connect to port <port> (default 18515)
-d <dev>               use IB device <dev> (default first device found)
-i <port>               use port <port> of IB device (default 1)
-c <RC/UC/UD>  connection type RC/UC/UD (default RC)
-m <mtu>              mtu size (256 - 4096. default for hermon is 2048)
-s <size>               size of message to exchange (default 65536)
-a                          Run sizes from 2 till 2^23
-t <dep>                size of tx queue (default 300)
-g                          send messages to multicast group (UD only)
-r <dep>                make rx queue bigger than tx (default 600)
-n <iters>               number of exchanges (at least 2, default 1000)
-I <size>                max size of message to be sent in inline mode (default 400)
-b                          measure bidirectional bandwidth (default unidirectional)
-V                         display version number
-e                          sleep on CQ events (default poll)
-N                         cancel peak-bw calculation (default with peak-bw)
+
To verify correct WinVerbs and libibverbs installation, run ibstat or ibv_devinfo. It
should report all RDMA devices in the system, along with limited port
attributes. Because of limitations in the +OFED for Windows stack +in comparision to the Linux OFED stack, it is normal for the programs to
list several values as unknown.

+

<return-to-top>

+ + diff --git a/branches/WOF2-3/docs/build.txt b/branches/WOF2-3/docs/build.txt new file mode 100644 index 00000000..fcd7dc0c --- /dev/null +++ b/branches/WOF2-3/docs/build.txt @@ -0,0 +1,32 @@ +To build the WinOF tree, you need to have the following installed: + +WDK version 6001.18001 +Windows Platform SDK for Windows Server 2008 and .NET Framework 3.5 (v6.1) + +The WinOF tree (kernel drivers and userspace libraries) is built from the WDK +build environment. You need to set the following environment variables: + +OPENIB_REV (example set OPENIB_REV=0) +PLATFORM_SDK_PATH (example set PLATFORM_SDK_PATH=c:\progra~1\mi2578~1\windows\v6.1) +ND_SDK_PATH (example set ND_SDK_PATH=c:\progra~1\mi3029~1\networ~1) + +The OPENIB_REV variable can be set to the SVN revision number of the code. + +The PLATFORM_SDK_PATH variable must reference the SDK path, using 8.3 notation +(no spaces). You can use 'dir /x' to obtain the correct 8.3 notation for a +given directory. + +The ND_SDK_PATH variable must reference the NetworkDirect directory of the +HPC SDK, using 8.3 notation (no spaces). You can use 'dir /x' to obtain the +correct 8.3 notation for a given directory. + +Environment variables may be set by using the 'set' command in a command prompt +window. Or by selecting Control Panel -> Performance and Maintenance -> System -> +Advanced -> Environment Variables. + +To build the code, cd into the trunk and type 'build -wg'. See 'build -?' for +additional build options. + +A build batch file is also available in etc\bldwo.bat that allows building +for any OS / processor architecture from within a single command window. Run +'bldwo' without any arguments for more details. diff --git a/branches/WOF2-3/docs/complib/cl_async_proc_h.html b/branches/WOF2-3/docs/complib/cl_async_proc_h.html new file mode 100644 index 00000000..a7926d51 --- /dev/null +++ b/branches/WOF2-3/docs/complib/cl_async_proc_h.html @@ -0,0 +1,309 @@ + + + + +./inc_docs/complib/cl_async_proc_h.html + + + + +Generated from ./inc/complib/cl_async_proc.h with ROBODoc v4.99.17 on Sun Mar 04 2007 18:17:52 +
+
+ +

[Modules] +Component Library/Asynchronous Processor

+ +

[top][parent][index]

+

NAME

+
       Asynchronous Processor
+
+

DESCRIPTION

+
       The asynchronous processor provides threads for executing queued callbacks.
+
+       The threads in the asynchronous processor wait for callbacks to be queued.
+
+       The asynchronous processor functions operate on a cl_async_proc_t structure
+       which should be treated as opaque and manipulated only through the provided
+       functions.
+
+

SEE ALSO

+
       Structures:
+               cl_async_proc_t, cl_async_proc_item_t
+
+       Initialization:
+               cl_async_proc_construct, cl_async_proc_init, cl_async_proc_destroy
+
+       Manipulation:
+               cl_async_proc_queue
+
+
+
+ +

[Functions] +Component Library: Asynchronous Processor/cl_async_proc_construct

+ +

[top][index]

+

NAME

+
       cl_async_proc_construct
+
+

DESCRIPTION

+
       The cl_async_proc_construct function initializes the state of a
+       thread pool.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+cl_async_proc_construct(
+        IN      cl_async_proc_t* const  p_async_proc );
+
+

PARAMETERS

+
       p_async_proc
+               [in] Pointer to an asynchronous processor structure.
+
+

RETURN VALUE

+
       This function does not return a value.
+
+

NOTES

+
       Allows calling cl_async_proc_destroy without first calling
+       cl_async_proc_init.
+
+       Calling cl_async_proc_construct is a prerequisite to calling any other
+       thread pool function except cl_async_proc_init.
+
+

SEE ALSO

+
       Asynchronous Processor, cl_async_proc_init, cl_async_proc_destroy
+
+
+
+ +

[Functions] +Component Library: Asynchronous Processor/cl_async_proc_destroy

+ +

[top][index]

+

NAME

+
       cl_async_proc_destroy
+
+

DESCRIPTION

+
       The cl_async_proc_destroy function performs any necessary cleanup
+       for a thread pool.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+cl_async_proc_destroy(
+        IN      cl_async_proc_t* const  p_async_proc );
+
+

PARAMETERS

+
       p_async_proc
+               [in] Pointer to an asynchronous processor 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 asynchronous processor's threads. Because of
+       its blocking nature, callers of cl_async_proc_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_async_proc_construct or cl_async_proc_init.
+
+

SEE ALSO

+
       Asynchronous Processor, cl_async_proc_construct, cl_async_proc_init
+
+
+
+ +

[Functions] +Component Library: Asynchronous Processor/cl_async_proc_init

+ +

[top][index]

+

NAME

+
       cl_async_proc_init
+
+

DESCRIPTION

+
       The cl_async_proc_init function initialized an asynchronous processor
+       for use.
+
+

SYNOPSIS

+
CL_EXPORT cl_status_t CL_API
+cl_async_proc_init(
+        IN      cl_async_proc_t* const  p_async_proc,
+        IN      const uint32_t                  thread_count,
+        IN      const char* const               name );
+
+

PARAMETERS

+
       p_async_proc
+               [in] Pointer to an asynchronous processor structure to initialize.
+
+       thread_count
+               [in] Number of threads to be managed by the asynchronous processor.
+
+       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 asynchronous processor have the same name.
+
+ RETURN VALUES
+       CL_SUCCESS if the asynchronous processor creation succeeded.
+
+       CL_INSUFFICIENT_MEMORY if there was not enough memory to inititalize
+       the asynchronous processor.
+
+       CL_ERROR if the threads could not be created.
+
+

NOTES

+
       cl_async_proc_init creates and starts the specified number of threads.
+       If thread_count is zero, the asynchronous processor creates as many
+       threads as there are processors in the system.
+
+

SEE ALSO

+
       Asynchronous Processor, cl_async_proc_construct, cl_async_proc_destroy,
+       cl_async_proc_queue
+
+
+
+ +

[Structures] +Component Library: Asynchronous Processor/cl_async_proc_item_t

+ +

[top][index]

+

NAME

+
       cl_async_proc_item_t
+
+

DESCRIPTION

+
       Asynchronous processor item structure passed to the cl_async_proc_queue
+       function to queue a callback for execution.
+
+

SYNOPSIS

+
typedef struct _cl_async_proc_item
+{
+        cl_pool_item_t                  pool_item;
+        cl_pfn_async_proc_cb_t  pfn_callback;
+
+} cl_async_proc_item_t;
+
+

FIELDS

+
       pool_item
+               Pool item for queuing the item to be invoked by the asynchronous
+               processor's threads.  This field is defined as a pool item to
+               allow items to be managed by a pool.
+
+       pfn_callback
+               Pointer to a callback function to invoke when the item is dequeued.
+
+

SEE ALSO

+
       Asynchronous Processor, cl_async_proc_queue, cl_pfn_async_proc_cb_t
+
+
+
+ +

[Functions] +Component Library: Asynchronous Processor/cl_async_proc_queue

+ +

[top][index]

+

NAME

+
       cl_async_proc_queue
+
+

DESCRIPTION

+
       The cl_async_proc_queue function queues a callback to an asynchronous
+       processor.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+cl_async_proc_queue(
+        IN      cl_async_proc_t* const          p_async_proc,
+        IN      cl_async_proc_item_t* const     p_item );
+
+

PARAMETERS

+
       p_async_proc
+               [in] Pointer to an asynchronous processor structure to initialize.
+
+       p_item
+               [in] Pointer to an asynchronous processor item to queue for execution.
+               The callback and context fields of the item must be valid.
+
+ RETURN VALUES
+       This function does not return a value.
+
+

SEE ALSO

+
       Asynchronous Processor, cl_async_proc_init, cl_pfn_async_proc_cb_t
+
+
+
+ +

[Structures] +Component Library: Asynchronous Processor/cl_async_proc_t

+ +

[top][index]

+

NAME

+
       cl_async_proc_t
+
+

DESCRIPTION

+
       Asynchronous processor structure.
+
+       The cl_async_proc_t structure should be treated as opaque, and should be
+       manipulated only through the provided functions.
+
+

SYNOPSIS

+
typedef struct _cl_async_proc
+{
+        cl_thread_pool_t        thread_pool;
+        cl_qlist_t                      item_queue;
+        cl_spinlock_t           lock;
+        cl_state_t                      state;
+
+} cl_async_proc_t;
+
+

FIELDS

+
       item_pool
+               Pool of items storing the callback function and contexts to be invoked
+               by the asynchronous processor's threads.
+
+       thread_pool
+               Thread pool that will invoke the callbacks.
+
+       item_queue
+               Queue of items that the threads should process.
+
+       lock
+               Lock used to synchronize access to the item pool and queue.
+
+

SEE ALSO

+
       Asynchronous Processor
+
+
+
+ +

[Definitions] +Component Library: Asynchronous Processor/cl_pfn_async_proc_cb_t

+ +

[top][index]

+

NAME

+
       cl_pfn_async_proc_cb_t
+
+

DESCRIPTION

+
       The cl_pfn_async_proc_cb_t function type defines the prototype for
+       callbacks queued to and invoked by the asynchronous processor.
+
+

SYNOPSIS

+
typedef void
+(CL_API *cl_pfn_async_proc_cb_t)(
+        IN      struct _cl_async_proc_item      *p_item );
+
+

PARAMETERS

+
       p_item
+               Pointer to the cl_async_proc_item_t structure that was queued in
+               a call to cl_async_proc_queue.
+
+

NOTES

+
       This function type is provided as function prototype reference for the
+       function provided by users as a parameter to the cl_async_proc_queue
+       function.
+
+

SEE ALSO

+
       Asynchronous Processor, cl_async_proc_item_t
+
+
+ + diff --git a/branches/WOF2-3/docs/complib/cl_atomic_h.html b/branches/WOF2-3/docs/complib/cl_atomic_h.html new file mode 100644 index 00000000..1d78041a --- /dev/null +++ b/branches/WOF2-3/docs/complib/cl_atomic_h.html @@ -0,0 +1,272 @@ + + + + +./inc_docs/complib/cl_atomic_h.html + + + + +Generated from ./inc/complib/cl_atomic.h with ROBODoc v4.99.17 on Sun Mar 04 2007 18:17:52 +
+
+ +

[Modules] +Component Library/Atomic Operations

+ +

[top][parent][index]

+

NAME

+
       Atomic Operations
+
+

DESCRIPTION

+
       The Atomic Operations functions allow callers to operate on
+       32-bit signed integers in an atomic fashion.
+
+
+
+ +

[Functions] +Component Library: Atomic Operations/cl_atomic_add

+ +

[top][index]

+

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

+
CL_EXPORT int32_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Atomic Operations/cl_atomic_comp_xchg

+ +

[top][index]

+

NAME

+
       cl_atomic_comp_xchg
+
+

DESCRIPTION

+
       The cl_atomic_comp_xchg function atomically compares a 32-bit signed
+       integer to a desired value, sets that integer to the
+       specified value if equal, and returns the initial value.
+
+

SYNOPSIS

+
CL_EXPORT int32_t CL_API
+cl_atomic_comp_xchg(
+        IN      atomic32_t* const       p_value,
+        IN      const int32_t           compare,
+        IN      const int32_t           new_value );
+
+

PARAMETERS

+
       p_value
+               [in] Pointer to a 32-bit integer to exchange with new_value.
+
+       compare
+               [in] Value to compare to the value pointed to by p_value.
+
+       new_value
+               [in] Value to assign if the value pointed to by p_value is equal to
+               the value specified by the compare parameter.
+
+

RETURN VALUE

+
       Returns the initial value of the variable pointed to by p_value.
+
+

NOTES

+
       The value pointed to by p_value is compared to the value specified by the
+       compare parameter.  If the two values are equal, the p_value variable is
+       set to new_value.  The initial value pointed to by p_value is returned.
+
+       cl_atomic_comp_xchg 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_sub, cl_atomic_xchg
+
+
+
+ +

[Functions] +Component Library: Atomic Operations/cl_atomic_dec

+ +

[top][index]

+

NAME

+
       cl_atomic_dec
+
+

DESCRIPTION

+
       The cl_atomic_dec function atomically decrements a 32-bit signed
+       integer and returns the decremented value.
+
+

SYNOPSIS

+
CL_EXPORT int32_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Atomic Operations/cl_atomic_inc

+ +

[top][index]

+

NAME

+
       cl_atomic_inc
+
+

DESCRIPTION

+
       The cl_atomic_inc function atomically increments a 32-bit signed
+       integer and returns the incremented value.
+
+

SYNOPSIS

+
CL_EXPORT int32_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Atomic Operations/cl_atomic_sub

+ +

[top][index]

+

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

+
CL_EXPORT int32_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Atomic Operations/cl_atomic_xchg

+ +

[top][index]

+

NAME

+
       cl_atomic_xchg
+
+

DESCRIPTION

+
       The cl_atomic_xchg function atomically sets a value of a
+       32-bit signed integer and returns the initial value.
+
+

SYNOPSIS

+
CL_EXPORT int32_t CL_API
+cl_atomic_xchg(
+        IN      atomic32_t* const       p_value,
+        IN      const int32_t           new_value );
+
+

PARAMETERS

+
       p_value
+               [in] Pointer to a 32-bit integer to exchange with new_value.
+
+       new_value
+               [in] Value to assign.
+
+

RETURN VALUE

+
       Returns the initial value pointed to by p_value.
+
+

NOTES

+
       The provided value is exchanged with new_value and its initial value
+       returned in one atomic operation.
+
+       cl_atomic_xchg 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_sub, cl_atomic_comp_xchg
+
+
+ + diff --git a/branches/WOF2-3/docs/complib/cl_byteswap_h.html b/branches/WOF2-3/docs/complib/cl_byteswap_h.html new file mode 100644 index 00000000..b9572798 --- /dev/null +++ b/branches/WOF2-3/docs/complib/cl_byteswap_h.html @@ -0,0 +1,500 @@ + + + + +./inc_docs/complib/cl_byteswap_h.html + + + + +Generated from ./inc/complib/cl_byteswap.h with ROBODoc v4.99.17 on Sun Mar 04 2007 18:17:52 +
+
+ +

[Modules] +Component Library/Byte Swapping

+ +

[top][parent][index]

+

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
+
+
+
+ +

[Definitions] +Component Library: Byte Swapping/CL_HTON16

+ +

[top][index]

+

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
+
+
+
+ +

[Functions] +Component Library: Byte Swapping/cl_hton16

+ +

[top][index]

+

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
+
+
+
+ +

[Definitions] +Component Library: Byte Swapping/CL_HTON32

+ +

[top][index]

+

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
+
+
+
+ +

[Functions] +Component Library: Byte Swapping/cl_hton32

+ +

[top][index]

+

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
+
+
+
+ +

[Definitions] +Component Library: Byte Swapping/CL_HTON64

+ +

[top][index]

+

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
+
+
+
+ +

[Functions] +Component Library: Byte Swapping/cl_hton64

+ +

[top][index]

+

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
+
+
+
+ +

[Functions] +Component Library: Byte Swapping/cl_ntoh

+ +

[top][index]

+

NAME

+
       cl_ntoh
+
+

DESCRIPTION

+
       The cl_ntoh function converts a value from network byte order to
+       host byte order.
+
+

SYNOPSIS

+
CL_INLINE void CL_API
+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 )
+                cl_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
+
+
+
+ +

[Definitions] +Component Library: Byte Swapping/CL_NTOH16

+ +

[top][index]

+

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
+
+
+
+ +

[Functions] +Component Library: Byte Swapping/cl_ntoh16

+ +

[top][index]

+

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
+
+
+
+ +

[Functions] +Component Library: Byte Swapping/cl_ntoh32

+ +

[top][index]

+

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
+
+
+
+ +

[Definitions] +Component Library: Byte Swapping/CL_NTOH32

+ +

[top][index]

+

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
+
+
+
+ +

[Definitions] +Component Library: Byte Swapping/CL_NTOH64

+ +

[top][index]

+

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
+
+
+
+ +

[Functions] +Component Library: Byte Swapping/cl_ntoh64

+ +

[top][index]

+

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
+
+
+ + diff --git a/branches/WOF2-3/docs/complib/cl_comppool_h.html b/branches/WOF2-3/docs/complib/cl_comppool_h.html new file mode 100644 index 00000000..fbecd283 --- /dev/null +++ b/branches/WOF2-3/docs/complib/cl_comppool_h.html @@ -0,0 +1,604 @@ + + + + +./inc_docs/complib/cl_comppool_h.html + + + + +Generated from ./inc/complib/cl_comppool.h with ROBODoc v4.99.17 on Sun Mar 04 2007 18:17:52 +
+
+ +

[Modules] +Component Library/Composite Pool

+ +

[top][parent][index]

+

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
+
+
+
+ +

[Functions] +Component Library: Composite Pool/cl_cpool_construct

+ +

[top][index]

+

NAME

+
       cl_cpool_construct
+
+

DESCRIPTION

+
       The cl_cpool_construct function constructs a composite pool.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Composite Pool/cl_cpool_count

+ +

[top][index]

+

NAME

+
       cl_cpool_count
+
+

DESCRIPTION

+
       The cl_cpool_count function returns the number of available objects
+       in a composite pool.
+
+

SYNOPSIS

+
CL_INLINE size_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Composite Pool/cl_cpool_destroy

+ +

[top][index]

+

NAME

+
       cl_cpool_destroy
+
+

DESCRIPTION

+
       The cl_cpool_destroy function destroys a composite pool.
+
+

SYNOPSIS

+
CL_INLINE void CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Composite Pool/cl_cpool_get

+ +

[top][index]

+

NAME

+
       cl_cpool_get
+
+

DESCRIPTION

+
       The cl_cpool_get function retrieves an object from a
+       composite pool.
+
+

SYNOPSIS

+
CL_INLINE void* CL_API
+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->list_obj.p_object );
+        return( (void*)p_pool_obj->list_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
+
+
+
+ +

[Functions] +Component Library: Composite Pool/cl_cpool_grow

+ +

[top][index]

+

NAME

+
       cl_cpool_grow
+
+

DESCRIPTION

+
       The cl_cpool_grow function grows a composite pool by
+       the specified number of objects.
+
+

SYNOPSIS

+
CL_INLINE cl_status_t CL_API
+cl_cpool_grow(
+        IN      cl_cpool_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_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
+
+
+
+ +

[Functions] +Component Library: Composite Pool/cl_cpool_init

+ +

[top][index]

+

NAME

+
       cl_cpool_init
+
+

DESCRIPTION

+
       The cl_cpool_init function initializes a composite pool for use.
+
+

SYNOPSIS

+
CL_EXPORT cl_status_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Composite Pool/cl_cpool_put

+ +

[top][index]

+

NAME

+
       cl_cpool_put
+
+

DESCRIPTION

+
       The cl_cpool_put function returns an object to a composite pool.
+
+

SYNOPSIS

+
CL_INLINE void CL_API
+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->list_obj.p_object == p_object );
+
+        cl_qcpool_put( &p_pool->qcpool, (cl_pool_item_t*)p_pool_obj );
+}
+
+

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
+
+
+
+ +

[Structures] +Component Library: Composite Pool/cl_cpool_t

+ +

[top][index]

+

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
+
+
+
+ +

[Functions] +Component Library: Composite Pool/cl_is_cpool_inited

+ +

[top][index]

+

NAME

+
       cl_is_cpool_inited
+
+

DESCRIPTION

+
       The cl_is_cpool_inited function returns whether a composite pool was
+       successfully initialized.
+
+

SYNOPSIS

+
CL_INLINE boolean_t CL_API
+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
+
+
+
+ +

[Definitions] +Component Library: Composite Pool/cl_pfn_cpool_dtor_t

+ +

[top][index]

+

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_API *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
+
+
+
+ +

[Definitions] +Component Library: Composite Pool/cl_pfn_cpool_init_t

+ +

[top][index]

+

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_API *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
+
+
+ + diff --git a/branches/WOF2-3/docs/complib/cl_debug_h.html b/branches/WOF2-3/docs/complib/cl_debug_h.html new file mode 100644 index 00000000..6b946692 --- /dev/null +++ b/branches/WOF2-3/docs/complib/cl_debug_h.html @@ -0,0 +1,534 @@ + + + + +./inc_docs/complib/cl_debug_h.html + + + + +Generated from ./inc/complib/cl_debug.h with ROBODoc v4.99.17 on Sun Mar 04 2007 18:17:52 +
+
+ +

[Modules] +Component Library/Debug Output

+ +

[top][parent][index]

+

NAME

+
       Debug Output
+
+

DESCRIPTION

+
       The debug output functions and macros send debug messages to the current
+       debug target.
+
+
+
+ +

[Definitions] +Component Library: Debug Output/64-bit Print Format

+ +

[top][index]

+

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.
+
+
+
+ +

[Functions] +Component Library: Debug Output/cl_break

+ +

[top][index]

+

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.
+
+
+
+ +

[Functions] +Component Library: Debug Output/cl_dbg_out

+ +

[top][index]

+

NAME

+
       cl_dbg_out
+
+

DESCRIPTION

+
       The cl_dbg_out function sends a debug message to the debug target in
+       debug builds only.
+
+

SYNOPSIS

+
CL_EXPORT 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
+
+
+
+ +

[Definitions] +Component Library: Debug Output/CL_ENTER

+ +

[top][index]

+

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
+
+
+
+ +

[Definitions] +Component Library: Debug Output/CL_EXIT

+ +

[top][index]

+

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
+
+
+
+ +

[Functions] +Component Library: Debug Output/cl_msg_out

+ +

[top][index]

+

NAME

+
       cl_msg_out
+
+

DESCRIPTION

+
       The cl_msg_out function sends a debug message to the message log target.
+
+

SYNOPSIS

+
CL_EXPORT 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
+
+
+
+ +

[Definitions] +Component Library: Debug Output/CL_PRINT

+ +

[top][index]

+

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
+
+
+
+ +

[Definitions] +Component Library: Debug Output/CL_TRACE

+ +

[top][index]

+

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
+
+
+
+ +

[Definitions] +Component Library: Debug Output/CL_TRACE_EXIT

+ +

[top][index]

+

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
+
+
+
+ +

[Definitions] +Component Library: Debug Output/Debug Levels

+ +

[top][index]

+

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
+
+
+ + diff --git a/branches/WOF2-3/docs/complib/cl_event_h.html b/branches/WOF2-3/docs/complib/cl_event_h.html new file mode 100644 index 00000000..001da4f3 --- /dev/null +++ b/branches/WOF2-3/docs/complib/cl_event_h.html @@ -0,0 +1,274 @@ + + + + +./inc_docs/complib/cl_event_h.html + + + + +Generated from ./inc/complib/cl_event.h with ROBODoc v4.99.17 on Sun Mar 04 2007 18:17:52 +
+
+ +

[Modules] +Component Library/Event

+ +

[top][parent][index]

+

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
+
+
+
+ +

[Functions] +Component Library: Event/cl_event_construct

+ +

[top][index]

+

NAME

+
       cl_event_construct
+
+

DESCRIPTION

+
       The cl_event_construct function constructs an event.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Event/cl_event_destroy

+ +

[top][index]

+

NAME

+
       cl_event_destroy
+
+

DESCRIPTION

+
       The cl_event_destroy function performs any necessary cleanup of an event.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Event/cl_event_init

+ +

[top][index]

+

NAME

+
       cl_event_init
+
+

DESCRIPTION

+
       The cl_event_init function initializes an event for use.
+
+

SYNOPSIS

+
CL_EXPORT cl_status_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Event/cl_event_reset

+ +

[top][index]

+

NAME

+
       cl_event_reset
+
+

DESCRIPTION

+
       The cl_event_reset function sets an event to the non-signalled state.
+
+

SYNOPSIS

+
CL_EXPORT cl_status_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Event/cl_event_signal

+ +

[top][index]

+

NAME

+
       cl_event_signal
+
+

DESCRIPTION

+
       The cl_event_signal function sets an event to the signalled state and
+       releases one or more waiting threads.
+
+

SYNOPSIS

+
CL_EXPORT cl_status_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Event/cl_event_wait_on

+ +

[top][index]

+

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_EXPORT cl_status_t CL_API
+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 in 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
+
+
+ + diff --git a/branches/WOF2-3/docs/complib/cl_fleximap_h.html b/branches/WOF2-3/docs/complib/cl_fleximap_h.html new file mode 100644 index 00000000..6eaf3845 --- /dev/null +++ b/branches/WOF2-3/docs/complib/cl_fleximap_h.html @@ -0,0 +1,948 @@ + + + + +./inc_docs/complib/cl_fleximap_h.html + + + + +Generated from ./inc/complib/cl_fleximap.h with ROBODoc v4.99.17 on Sun Mar 04 2007 18:17:52 +
+
+ +

[Modules] +Component Library/Flexi Map

+ +

[top][parent][index]

+

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 comparisson 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
+
+       Search:
+               cl_fmap_apply_func
+
+       Attributes:
+               cl_fmap_count, cl_is_fmap_empty,
+
+
+
+ +

[Functions] +Component Library: Flexi Map/cl_fmap_apply_func

+ +

[top][index]

+

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

+
CL_EXPORT void CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Flexi Map/cl_fmap_count

+ +

[top][index]

+

NAME

+
       cl_fmap_count
+
+

DESCRIPTION

+
       The cl_fmap_count function returns the number of items stored
+       in a flexi map.
+
+

SYNOPSIS

+
CL_INLINE size_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Flexi Map/cl_fmap_delta

+ +

[top][index]

+

NAME

+
       cl_fmap_delta
+
+

DESCRIPTION

+
       The cl_fmap_delta function computes the differences between two maps.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+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 usefull 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
+
+
+
+ +

[Functions] +Component Library: Flexi Map/cl_fmap_end

+ +

[top][index]

+

NAME

+
       cl_fmap_end
+
+

DESCRIPTION

+
       The cl_fmap_end function returns the end of a flexi map.
+
+

SYNOPSIS

+
CL_INLINE const cl_fmap_item_t* const CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Flexi Map/cl_fmap_get

+ +

[top][index]

+

NAME

+
       cl_fmap_get
+
+

DESCRIPTION

+
       The cl_fmap_get function returns the map item associated with a key.
+
+

SYNOPSIS

+
CL_EXPORT cl_fmap_item_t* CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Flexi Map/cl_fmap_head

+ +

[top][index]

+

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

+
CL_INLINE cl_fmap_item_t* CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Flexi Map/cl_fmap_init

+ +

[top][index]

+

NAME

+
       cl_fmap_init
+
+

DESCRIPTION

+
       The cl_fmap_init function initialized a flexi map for use.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Flexi Map/cl_fmap_insert

+ +

[top][index]

+

NAME

+
       cl_fmap_insert
+
+

DESCRIPTION

+
       The cl_fmap_insert function inserts a map item into a flexi map.
+
+

SYNOPSIS

+
CL_EXPORT cl_fmap_item_t* CL_API
+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
+
+
+
+ +

[Structures] +Component Library: Flexi Map/cl_fmap_item_t

+ +

[top][index]

+

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;
+ TO_LONG_PTR(       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.
+
+       The flexi map item is defined to be identical in layout as a map item.
+
+

SEE ALSO

+
       Flexi Map, cl_fmap_insert, cl_fmap_key, cl_pool_item_t, cl_list_item_t
+
+
+
+ +

[Functions] +Component Library: Flexi Map/cl_fmap_key

+ +

[top][index]

+

NAME

+
       cl_fmap_key
+
+

DESCRIPTION

+
       The cl_fmap_key function retrieves the key value of a map item.
+
+

SYNOPSIS

+
#pragma warning (push)
+#pragma warning (disable :4244)
+CL_INLINE const void* CL_API
+cl_fmap_key(
+        IN      const cl_fmap_item_t* const     p_item )
+{
+        CL_ASSERT( p_item );
+        return( p_item->p_key );
+}
+#pragma warning (pop )
+
+

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
+
+
+
+ +

[Functions] +Component Library: Flexi Map/cl_fmap_merge

+ +

[top][index]

+

NAME

+
       cl_fmap_merge
+
+

DESCRIPTION

+
       The cl_fmap_merge function moves all items from one map to another,
+       excluding duplicates.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Flexi Map/cl_fmap_next

+ +

[top][index]

+

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

+
CL_INLINE cl_fmap_item_t* CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Flexi Map/cl_fmap_prev

+ +

[top][index]

+

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

+
CL_INLINE cl_fmap_item_t* CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Flexi Map/cl_fmap_remove

+ +

[top][index]

+

NAME

+
       cl_fmap_remove
+
+

DESCRIPTION

+
       The cl_fmap_remove function removes the map item with the specified key
+       from a flexi map.
+
+

SYNOPSIS

+
CL_EXPORT cl_fmap_item_t* CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Flexi Map/cl_fmap_remove_all

+ +

[top][index]

+

NAME

+
       cl_fmap_remove_all
+
+

DESCRIPTION

+
       The cl_fmap_remove_all function removes all items in a flexi map,
+       leaving it empty.
+
+

SYNOPSIS

+
CL_INLINE void CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Flexi Map/cl_fmap_remove_item

+ +

[top][index]

+

NAME

+
       cl_fmap_remove_item
+
+

DESCRIPTION

+
       The cl_fmap_remove_item function removes the specified map item
+       from a flexi map.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+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
+       is 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
+
+
+
+ +

[Structures] +Component Library: Flexi Map/cl_fmap_t

+ +

[top][index]

+

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
+
+
+
+ +

[Functions] +Component Library: Flexi Map/cl_fmap_tail

+ +

[top][index]

+

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

+
CL_INLINE cl_fmap_item_t* CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Flexi Map/cl_is_fmap_empty

+ +

[top][index]

+

NAME

+
       cl_is_fmap_empty
+
+

DESCRIPTION

+
       The cl_is_fmap_empty function returns whether a flexi map is empty.
+
+

SYNOPSIS

+
CL_INLINE boolean_t CL_API
+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
+
+
+
+ +

[Definitions] +Component Library: Flexi Map/cl_pfn_fmap_apply_t

+ +

[top][index]

+

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_API *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
+
+
+
+ +

[Definitions] +Component Library: Flexi Map/cl_pfn_fmap_cmp_t

+ +

[top][index]

+

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_API *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
+
+
+ + diff --git a/branches/WOF2-3/docs/complib/cl_ioctl_h.html b/branches/WOF2-3/docs/complib/cl_ioctl_h.html new file mode 100644 index 00000000..86ea18a0 --- /dev/null +++ b/branches/WOF2-3/docs/complib/cl_ioctl_h.html @@ -0,0 +1,609 @@ + + + + +./inc_docs/complib/cl_ioctl_h.html + + + + +Generated from ./inc/complib/cl_ioctl.h with ROBODoc v4.99.17 on Sun Mar 04 2007 18:17:52 +
+
+ +

[Modules] +Component Library/IOCTL Object

+ +

[top][parent][index]

+

NAME

+
       IOCTL Object
+
+

DESCRIPTION

+
       The IOCTL object provides functionality for handling IOCTL requests.
+
+       The IOCTL object is only available in kernel mode and provides
+       functionality for accessing information about IO requests initiated
+       by a user-mode application.  The IOCTL_CODE macro is used in both
+       user and kernel mode to initiate and dispatch IOCTL requests, respectively.
+
+       In Linux, in order for the IOCTL object to be used, requests must be
+       initiated and handled using the Device Framework abstraction.
+
+

SEE ALSO

+
       Structures:
+               cl_ioctl_handle_t
+
+       Callbacks:
+               cl_pfn_ioctl_handler_t
+
+       Control Code Generation
+               IOCTL_CODE
+
+       Kernel Mode Access
+               cl_ioctl_process
+               cl_ioctl_complete
+               cl_ioctl_type
+               cl_ioctl_cmd
+               cl_ioctl_ctl_code
+               cl_ioctl_in_buf
+               cl_ioctl_in_size
+               cl_ioctl_out_buf
+               cl_ioctl_out_size
+
+       User Mode Access
+               cl_ioctl_request
+               cl_ioctl_result
+
+
+
+ +

[Functions] +Component Library: IOCTL Object/cl_ioctl_cmd

+ +

[top][index]

+

NAME

+
       cl_ioctl_cmd
+
+

DESCRIPTION

+
       Returns the command of an IOCTL
+
+

SYNOPSIS

+
CL_EXPORT uint16_t CL_API
+cl_ioctl_cmd(
+        IN      cl_ioctl_handle_t       h_ioctl );
+
+

PARAMETERS

+
       h_ioctl
+               [in] Handle to an IOCTL
+
+

RETURN VALUE

+
       Returns the command of the specified IOCTL request, as defined using
+       the IOCTL_CMD macro.
+
+

NOTES

+
       The cl_ioctl_cmd function is only available in the kernel.
+
+

SEE ALSO

+
       IOCTL Object, cl_ioctl_handle_t, cl_ioctl_type, cl_ioctl_ctl_code
+
+
+
+ +

[Functions] +Component Library: IOCTL Object/cl_ioctl_complete

+ +

[top][index]

+

NAME

+
       cl_ioctl_complete
+
+

DESCRIPTION

+
       Fills in completion information for an IOCTL and releases the IOCTL request
+       for completion.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+cl_ioctl_complete(
+        IN      cl_ioctl_handle_t       h_ioctl,
+        IN      cl_status_t                     io_status,
+        IN      size_t                          ret_bytes );
+
+

PARAMETERS

+
       h_ioctl
+               Handle to the IOCTL being completed.  This handle was provided to
+               the IOCTL handler.
+
+       io_status
+               Status of the IOCTL request.
+
+       ret_bytes
+               Number of bytes written to the output buffer.
+
+ RETURN VALUES
+       This function does not return a value.
+
+

SEE ALSO

+
       IOCTL Object, cl_ioctl_handle_t, cl_ioctl_process
+
+
+
+ +

[Functions] +Component Library: IOCTL Object/cl_ioctl_ctl_code

+ +

[top][index]

+

NAME

+
       cl_ioctl_ctl_code
+
+

DESCRIPTION

+
       Returns the 32-bit control code of an IOCTL
+
+

SYNOPSIS

+
CL_EXPORT uint32_t CL_API
+cl_ioctl_ctl_code(
+        IN      cl_ioctl_handle_t       h_ioctl );
+
+

PARAMETERS

+
       h_ioctl
+               [in] Handle to an IOCTL
+
+

RETURN VALUE

+
       Returns the 32-bit control code of the specified IOCTL request,
+       as defined using the IOCTL_CMD macro.
+
+

NOTES

+
       The cl_ioctl_ctl_code function is only available in the kernel.
+
+

SEE ALSO

+
       IOCTL Object, cl_ioctl_handle_t, cl_ioctl_type, cl_ioctl_cmd
+
+
+
+ +

[Definitions] +Component Library: IOCTL Object/cl_ioctl_handle_t

+ +

[top][index]

+

NAME

+
       cl_ioctl_handle_t
+
+

DESCRIPTION

+
       Opaque handle representing an IO request.
+
+

NOTES

+
       The cl_ioctl_handle_t type is only available in the kernel.
+       The cl_ioctl_handle_t type should be treated as opaque, as it
+       varies from environment to environment.
+
+

SEE ALSO

+
       IOCTL Object, cl_ioctl_type, cl_ioctl_cmd, cl_ioctl_in_buf,
+       cl_ioctl_in_size, cl_ioctl_out_buf, cl_ioctl_out_size,
+       cl_ioctl_set_status, cl_ioctl_set_ret_bytes
+
+
+
+ +

[Functions] +Component Library: IOCTL Object/cl_ioctl_in_buf

+ +

[top][index]

+

NAME

+
       cl_ioctl_in_buf
+
+

DESCRIPTION

+
       Returns a pointer to the input buffer of an IOCTL.
+
+

SYNOPSIS

+
CL_EXPORT void* CL_API
+cl_ioctl_in_buf(
+        IN      cl_ioctl_handle_t       h_ioctl );
+
+

PARAMETERS

+
       h_ioctl
+               [in] Handle to an IOCTL
+
+

RETURN VALUE

+
       Returns the input buffer of the specified IOCTL request.
+
+

NOTES

+
       The cl_ioctl_in_buf function is only available in the kernel.
+
+       In Windows, for IOCTL operations defined as METHOD_IN_DIRECT, the
+       returned pointer points to the MDL describing the input buffer.
+
+

SEE ALSO

+
       IOCTL Object, cl_ioctl_handle_t, cl_ioctl_in_size,
+       cl_ioctl_out_buf, cl_ioctl_out_size
+
+
+
+ +

[Functions] +Component Library: IOCTL Object/cl_ioctl_in_size

+ +

[top][index]

+

NAME

+
       cl_ioctl_in_size
+
+

DESCRIPTION

+
       Returns the size of the input buffer of an IOCTL.
+
+

SYNOPSIS

+
CL_EXPORT ULONG CL_API
+cl_ioctl_in_size(
+        IN      cl_ioctl_handle_t       h_ioctl );
+
+

PARAMETERS

+
       h_ioctl
+               [in] Handle to an IOCTL
+
+

RETURN VALUE

+
       Returns the size, in bytes, of the input buffer of the specified
+       IOCTL request.
+
+

NOTES

+
       The cl_ioctl_in_size function is only available in the kernel.
+
+

SEE ALSO

+
       IOCTL Object, cl_ioctl_handle_t, cl_ioctl_in_buf,
+       cl_ioctl_out_buf, cl_ioctl_out_size
+
+
+
+ +

[Functions] +Component Library: IOCTL Object/cl_ioctl_out_buf

+ +

[top][index]

+

NAME

+
       cl_ioctl_out_buf
+
+

DESCRIPTION

+
       Returns a pointer to the output buffer of an IOCTL.
+
+

SYNOPSIS

+
CL_EXPORT void* CL_API
+cl_ioctl_out_buf(
+        IN      cl_ioctl_handle_t       h_ioctl );
+
+

PARAMETERS

+
       h_ioctl
+               [in] Handle to an IOCTL
+
+

RETURN VALUE

+
       Returns a pointer to the output buffer of the specified IOCTL request.
+
+

NOTES

+
       The cl_ioctl_out_buf function is only available in the kernel.
+
+       In Windows, for IOCTL operations defined as METHOD_IN_DIRECT or
+       METHOD_OUT_DIRECT, the returned pointer points to the MDL describing
+       the input buffer.
+
+

SEE ALSO

+
       IOCTL Object, cl_ioctl_handle_t, cl_ioctl_out_size,
+       cl_ioctl_in_buf, cl_ioctl_in_size
+
+
+
+ +

[Functions] +Component Library: IOCTL Object/cl_ioctl_out_size

+ +

[top][index]

+

NAME

+
       cl_ioctl_out_size
+
+

DESCRIPTION

+
       Returns the size of the output buffer of an IOCTL.
+
+

SYNOPSIS

+
CL_EXPORT ULONG CL_API
+cl_ioctl_out_size(
+        IN      cl_ioctl_handle_t       h_ioctl );
+
+

PARAMETERS

+
       h_ioctl
+               [in] Handle to an IOCTL
+
+

RETURN VALUE

+
       Returns the size, in bytes, of the input buffer of the specified
+       IOCTL request.
+
+

NOTES

+
       The cl_ioctl_out_size function is only available in the kernel.
+
+

SEE ALSO

+
       IOCTL Object, cl_ioctl_handle_t, cl_ioctl_out_buf,
+       cl_ioctl_in_buf, cl_ioctl_in_size
+
+
+
+ +

[Functions] +Component Library: IOCTL Object/cl_ioctl_process

+ +

[top][index]

+

NAME

+
       cl_ioctl_process
+
+

DESCRIPTION

+
       The cl_ioctl_process function unpacks information initiated by a call to
+       cl_ioctl_request function and invokes a user-supplied callback.
+
+

SYNOPSIS

+
CL_EXPORT cl_status_t CL_API
+cl_ioctl_process(
+        IN      void                                    *p_ioctl,
+        IN      cl_pfn_ioctl_handler_t  pfn_ioctl_handler,
+        IN      void                                    *context_1,
+        IN      void                                    *context_2 );
+
+

PARAMETERS

+
       p_ioctl
+               [in] Pointer to an OS specific IOCTL information.  In Linux,
+               this parameter depends on whether the IOCTL is handled synchronously
+               or asynchronously.  See the notes for further detail.
+               In Windows, this is a pointer to an IRP.
+
+       pfn_ioctl_handler
+               [in] Pointer to the callback function to invoke for handling the IOCTL.
+               This callback is independent of the IOCTL command.
+
+       context_1
+               [in] First of two context parameters to pass to the handler.
+
+       context_2
+               [in] Second of two context parameters to pass to the handler.
+
+ RETURN VALUES
+       CL_SUCCESS if the IOCTL was processed successfully.
+
+       Other values to indicate various failures.
+
+

NOTES

+
       Users must call cl_ioctl_complete from within the handler if completing
+       the IOCTL request synchronously.  If the IOCTL request's control code is
+       invalid, the handler should return CL_INVALID_REQUEST.
+
+       In Linux, the p_ioctl parameter is a copy of the argp parameter on input,
+       and on output points to the IOCTL request object passed to the IOCTL
+       handler if and only if the IOCTL handler returned CL_PENDING.
+       This allows the user to cancel the request by passing the same
+       handle to the cancel routine that was passed to the IOCTL handler.
+       If all IOCTLs are handled synchronously, it is acceptable to pass the argp
+       parameter of the IOCTL entry point instead of a copy.
+
+

SEE ALSO

+
       IOCTL Object, cl_ioctl_handle_t, cl_pfn_ioctl_handler_t, cl_ioctl_complete
+
+
+
+ +

[Functions] +Component Library: IOCTL Object/cl_ioctl_request

+ +

[top][index]

+

NAME

+
       cl_ioctl_request
+
+

DESCRIPTION

+
       The cl_ioctl_request is used by user-mode clients to initiate IOCTL
+       requests to a device.
+
+

SYNOPSIS

+
CL_EXPORT cl_status_t CL_API
+cl_ioctl_request(
+        IN              void                    *h_dev,
+        IN              uint32_t                ioctl_code,
+        IN              void                    *p_in_buf,
+        IN              size_t                  in_size,
+                OUT     void                    *p_out_buf,
+        IN              size_t                  out_size,
+                OUT     size_t                  *p_ret_bytes OPTIONAL,
+        IN              void                    *p_async_info OPTIONAL );
+
+

PARAMETERS

+
       h_dev
+               [in] Handle to the device to which the IOCTL request is targetted.
+               In Linux, this is a file descriptor.  In Windows, this is a file
+               handle.
+
+       ioctl_code
+               [in] Control code for the IOCTL request.
+
+       p_in_buf
+               [in] Pointer to the input buffer.
+
+       in_size
+               [in] Size, in bytes, of the input buffer.
+
+       p_out_buf
+               [out] Pointer to the output buffer.
+
+       out_size
+               [in] Size, in bytes, of the output buffer.
+
+       p_ret_bytes
+               [out] Number of bytes written to the output buffer.  This parameter is
+               mutually exclusive of the p_async_info parameter.
+
+       p_async_info
+               [in] For platforms that support asynchronous I/O, supplies a pointer
+               to that platform's async I/O structure, if any.  For Windows, this
+               is a pointer to an OVERLAPPED structure.  This parameter is mutually
+               exclusive of the p_ret_bytes parameter.
+
+

SEE ALSO

+
       IOCTL Object, cl_ioctl_result
+
+
+
+ +

[Functions] +Component Library: IOCTL Object/cl_ioctl_result

+ +

[top][index]

+

NAME

+
       cl_ioctl_result
+
+

DESCRIPTION

+
       Checks the status of an asynchronous IOCTL request.
+
+

SYNOPSIS

+
CL_EXPORT cl_status_t CL_API
+cl_ioctl_result(
+        IN      void            *h_dev,
+        IN      void            *p_async_info,
+        OUT     size_t          *p_ret_bytes,
+        IN      boolean_t       blocking );
+
+

PARAMETERS

+
       h_dev
+               [in] Handle to the device to which the IOCTL request is targetted.
+               In Linux, this is a file descriptor.  In Windows, this is a file
+               handle.
+
+       p_async_info
+               [in] For platforms that support asynchronous I/O, supplies a pointer
+               to that platform's async I/O structure, if any.  For Windows, this
+               is a pointer to an OVERLAPPED structure.  This must be the same
+               as that provided in the cl_ioctl_request function.
+
+       p_ret_bytes
+               [out] Number of bytes written to the output buffer.
+
+       blocking
+               [in] If TRUE, indicates that the call should wait until the
+               specified IOCTL request is complete.
+
+ RETURN VALUES
+       CL_SUCCESS if the IOCTL request was successful.  p_ret_bytes contains
+       the number bytes written to the output buffer.
+
+       CL_PENDING if the IOCTL request is not yet complete.
+
+       Other status values to indicate errors.
+
+

SEE ALSO

+
       IOCTL Object, cl_ioctl_request
+
+
+
+ +

[Functions] +Component Library: IOCTL Object/cl_ioctl_type

+ +

[top][index]

+

NAME

+
       cl_ioctl_type
+
+

DESCRIPTION

+
       Returns the type of an IOCTL.
+
+

SYNOPSIS

+
CL_EXPORT uint16_t CL_API
+cl_ioctl_type(
+        IN      cl_ioctl_handle_t       h_ioctl );
+
+

PARAMETERS

+
       h_ioctl
+               [in] Handle to an IOCTL
+
+

RETURN VALUE

+
       Returns the type of the specified IOCTL request, as defined using
+       the IOCTL_CMD macro.
+
+

NOTES

+
       The cl_ioctl_type function is only available in the kernel.
+
+

SEE ALSO

+
       IOCTL Object, cl_ioctl_handle_t, cl_ioctl_cmd, cl_ioctl_ctl_code
+
+
+
+ +

[Definitions] +Component Library: IOCTL Object/cl_pfn_ioctl_handler_t

+ +

[top][index]

+

NAME

+
       cl_pfn_ioctl_handler_t
+
+

DESCRIPTION

+
       The cl_pfn_ioctl_handler_t function type defines the prototype for
+       IOCTL handlers used when handling IOCTL requests initiated by
+       cl_ioctl_request.
+
+

SYNOPSIS

+
typedef cl_status_t
+(CL_API *cl_pfn_ioctl_handler_t)(
+        IN      cl_ioctl_handle_t       h_ioctl,
+        IN      void                            *context_1,
+        IN      void                            *context_2 );
+
+

PARAMETERS

+
       h_ioctl
+               [in] Handle to the IOCTL request.
+
+       context_1
+               [in] First context parameters, as provided to cl_ioctl_process.
+
+       context_2
+               [in] Second context parameters, as provided to cl_ioctl_process.
+
+ RETURN VALUES
+       CL_SUCCESS if the IOCTL was completed successfully.
+
+       CL_PENDING if the IOCTL is being processed asynchronously.
+
+       Other return values in case of errors.
+
+

NOTES

+
       It is acceptable to complete the IOCTL successfully to report an error
+       status in the output buffer.
+
+

SEE ALSO

+
       IOCTL Object, cl_ioctl_handle_t, cl_ioctl_process
+
+
+
+ +

[Definitions] +Component Library: IOCTL Object/IOCTL_CODE

+ +

[top][index]

+

NAME

+
       IOCTL_CODE
+
+

DESCRIPTION

+
       Macro for defining IO control command codes.
+
+

SYNOPSIS

+
*       uint32_t IOCTL_CODE( uint16_t type, uint16_t cmd )
+
+

PARAMETERS

+
       type
+               [in] user-defined type representing the type of command.  For Linux,
+               the type is truncated to 8-bits.  For Windows, the type is a 16-bit
+               value, as described in "Specifying Device Types" in the DDK docs.
+
+       cmd
+               [in] User-defined command.  For Linux, the command field is truncated
+               to 8-bits.  For Windows, the command can be 12-bits, with values
+               below 0x800 reserved by Microsoft for system defined commands.
+
+

RETURN VALUE

+
       A 32-bit control code.  User-mode clients use the control code to initiate
+       requests.  Kernel-mode clients use the control code to distinguish between
+       different requests.
+
+

NOTE

+
       In Windows, all IOCTL command codes defined with the IOCTL_CODE command
+       result in FILE_ANY_ACCESS and METHOD_BUFFERED being specified.
+
+

SEE ALSO

+
       IOCTL Object, cl_dev_ioctl, cl_ioctl_type, cl_ioctl_cmd
+
+
+ + diff --git a/branches/WOF2-3/docs/complib/cl_irqlock_h.html b/branches/WOF2-3/docs/complib/cl_irqlock_h.html new file mode 100644 index 00000000..527b6ec7 --- /dev/null +++ b/branches/WOF2-3/docs/complib/cl_irqlock_h.html @@ -0,0 +1,221 @@ + + + + +./inc_docs/complib/cl_irqlock_h.html + + + + +Generated from ./inc/complib/cl_irqlock.h with ROBODoc v4.99.17 on Sun Mar 04 2007 18:17:52 +
+
+ +

[Modules] +Component Library/Irqlock

+ +

[top][parent][index]

+

NAME

+
       Irqlock
+
+

DESCRIPTION

+
       Irqlock provides synchronization at interrupt level between threads for 
+       exclusive access to a resource.
+
+       The irqlock functions manipulate a cl_irqlock_t structure which should 
+       be treated as opaque and should be manipulated only through the provided 
+       functions.
+
+

SEE ALSO

+
       Structures:
+               cl_irqlock_t
+
+       Initialization:
+               cl_irqlock_construct, cl_irqlock_init, cl_irqlock_destroy
+
+       Manipulation
+               cl_irqlock_acquire, cl_irqlock_release
+
+
+
+ +

[Functions] +Component Library: Irqlock/cl_irqlock_acquire

+ +

[top][index]

+

NAME

+
       cl_irqlock_acquire
+
+

DESCRIPTION

+
       The cl_irqlock_acquire function acquires a IRQ 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_irqlock_acquire_irq function.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+cl_irqlock_acquire( 
+        IN      cl_irqlock_t* const             p_irqlock );
+
+

PARAMETERS

+
       p_irqlock 
+               [in] Pointer to a IRQ lock structure to acquire.
+
+

RETURN VALUE

+
       This function does not return a value.
+
+

SEE ALSO

+
       Irqlock, cl_irqlock_release
+
+
+
+ +

[Functions] +Component Library: Irqlock/cl_irqlock_construct

+ +

[top][index]

+

NAME

+
       cl_irqlock_construct
+
+

DESCRIPTION

+
       The cl_irqlock_construct function initializes the state of a 
+       IRQ lock.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+cl_irqlock_construct( 
+        IN      cl_irqlock_t* const             p_irqlock );
+
+

PARAMETERS

+
       p_irqlock 
+               [in] Pointer to a IRQ lock structure whose state to initialize.
+
+

RETURN VALUE

+
       This function does not return a value.
+
+

NOTES

+
       Allows calling cl_irqlock_destroy without first calling 
+       cl_irqlock_init.
+
+       Calling cl_irqlock_construct is a prerequisite to calling any other
+       IRQ lock function except cl_irqlock_init.
+
+

SEE ALSO

+
       Irqlock, cl_irqlock_init, cl_irqlock_destroy
+
+
+
+ +

[Functions] +Component Library: Irqlock/cl_irqlock_destroy

+ +

[top][index]

+

NAME

+
       cl_irqlock_destroy
+
+

DESCRIPTION

+
       The cl_irqlock_destroy function performs all necessary cleanup of a 
+       IRQ lock.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+cl_irqlock_destroy( 
+        IN      cl_irqlock_t* const             p_irqlock );
+
+

PARAMETERS

+
       p_irqlock 
+               [in] Pointer to a IRQ lock structure to destroy.
+
+

RETURN VALUE

+
       This function does not return a value.
+
+

NOTES

+
       Performs any necessary cleanup of a IRQ lock. This function must only 
+       be called if either cl_irqlock_construct or cl_irqlock_init has been 
+       called.
+
+

SEE ALSO

+
       Irqlock, cl_irqlock_construct, cl_irqlock_init
+
+
+
+ +

[Functions] +Component Library: Irqlock/cl_irqlock_init

+ +

[top][index]

+

NAME

+
       cl_irqlock_init
+
+

DESCRIPTION

+
       The cl_irqlock_init function initializes a IRQ lock for use.
+
+

SYNOPSIS

+
CL_EXPORT cl_status_t CL_API
+cl_irqlock_init( 
+        IN      cl_irqlock_t* const             p_irqlock,
+        IN      cl_interrupt_t* const   p_interrupt );
+
+

PARAMETERS

+
       p_irqlock 
+               [in] Pointer to a IRQ lock structure to initialize.
+
+       p_interrupt
+               [in] Platform specific pointer conveying information about the
+               interrupt vector and level with which to synchronize.
+
+ RETURN VALUES
+       CL_SUCCESS if initialization succeeded.
+
+       CL_ERROR if initialization failed. Callers should call 
+       cl_irqlock_destroy to clean up any resources allocated during 
+       initialization.
+
+

NOTES

+
       Initialize the IRQ lock structure. Allows calling cl_irqlock_aquire 
+       and cl_irqlock_release.
+
+       In Linux, the p_interrupt parameter is currently ignored.
+
+       In Windows, the p_interrupt parameter is a pointer to a KINTERRUPT object,
+       the value of which is supplied by a call to IoConnectInterrupt.
+
+

SEE ALSO

+
       Irqlock, cl_irqlock_construct, cl_irqlock_destroy, 
+       cl_irqlock_acquire, cl_irqlock_release
+
+
+
+ +

[Functions] +Component Library: Irqlock/cl_irqlock_release

+ +

[top][index]

+

NAME

+
       cl_irqlock_release
+
+

DESCRIPTION

+
       The cl_irqlock_release function releases a IRQ lock object.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+cl_irqlock_release(
+        IN      cl_irqlock_t* const             p_irqlock );
+
+

PARAMETERS

+
       p_irqlock 
+               [in] Pointer to a IRQ lock structure to release.
+
+

RETURN VALUE

+
       This function does not return a value.
+
+

NOTES

+
       Releases a IRQ lock after a call to cl_irqlock_acquire.
+
+

SEE ALSO

+
       Irqlock, cl_irqlock_acquire
+
+
+ + diff --git a/branches/WOF2-3/docs/complib/cl_list_h.html b/branches/WOF2-3/docs/complib/cl_list_h.html new file mode 100644 index 00000000..33a5f936 --- /dev/null +++ b/branches/WOF2-3/docs/complib/cl_list_h.html @@ -0,0 +1,1412 @@ + + + + +./inc_docs/complib/cl_list_h.html + + + + +Generated from ./inc/complib/cl_list.h with ROBODoc v4.99.17 on Sun Mar 04 2007 18:17:52 +
+
+ +

[Modules] +Component Library/List

+ +

[top][parent][index]

+

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
+
+
+
+ +

[Functions] +Component Library: List/cl_is_list_empty

+ +

[top][index]

+

NAME

+
       cl_is_list_empty
+
+

DESCRIPTION

+
       The cl_is_list_empty function returns whether a list is empty.
+
+

SYNOPSIS

+
CL_INLINE boolean_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: List/cl_is_list_inited

+ +

[top][index]

+

NAME

+
       cl_is_list_inited
+
+

DESCRIPTION

+
       The cl_is_list_inited function returns whether a list was
+       initialized successfully.
+
+

SYNOPSIS

+
CL_INLINE boolean_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: List/cl_is_object_in_list

+ +

[top][index]

+

NAME

+
       cl_is_object_in_list
+
+

DESCRIPTION

+
       The cl_is_object_in_list function returns whether an object
+       is stored in a list.
+
+

SYNOPSIS

+
CL_EXPORT boolean_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: List/cl_list_apply_func

+ +

[top][index]

+

NAME

+
       cl_list_apply_func
+
+

DESCRIPTION

+
       The cl_list_apply_func function executes a specified function for every
+       object stored in a list.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+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
+
+
+
+ +

[Functions] +Component Library: List/cl_list_construct

+ +

[top][index]

+

NAME

+
       cl_list_construct
+
+

DESCRIPTION

+
       The cl_list_construct function constructs a list.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+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
+
+
+
+ +

[Functions] +Component Library: List/cl_list_count

+ +

[top][index]

+

NAME

+
       cl_list_count
+
+

DESCRIPTION

+
       The cl_list_count function returns the number of objects stored in a list.
+
+

SYNOPSIS

+
CL_INLINE size_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: List/cl_list_destroy

+ +

[top][index]

+

NAME

+
       cl_list_destroy
+
+

DESCRIPTION

+
       The cl_list_destroy function destroys a list.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+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
+
+
+
+ +

[Functions] +Component Library: List/cl_list_end

+ +

[top][index]

+

NAME

+
       cl_list_end
+
+

DESCRIPTION

+
       The cl_list_end function returns returns the list iterator for
+       the end of a list.
+
+

SYNOPSIS

+
CL_INLINE const cl_list_iterator_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: List/cl_list_find_from_head

+ +

[top][index]

+

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_EXPORT const cl_list_iterator_t CL_API
+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,
+       cl_pfn_list_find_t
+
+
+
+ +

[Functions] +Component Library: List/cl_list_find_from_tail

+ +

[top][index]

+

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_EXPORT const cl_list_iterator_t CL_API
+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,
+       cl_pfn_list_find_t
+
+
+
+ +

[Functions] +Component Library: List/cl_list_head

+ +

[top][index]

+

NAME

+
       cl_list_head
+
+

DESCRIPTION

+
       The cl_list_head function returns returns a list iterator for
+       the head of a list.
+
+

SYNOPSIS

+
CL_INLINE const cl_list_iterator_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: List/cl_list_init

+ +

[top][index]

+

NAME

+
       cl_list_init
+
+

DESCRIPTION

+
       The cl_list_init function initializes a list for use.
+
+

SYNOPSIS

+
CL_EXPORT cl_status_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: List/cl_list_insert_array_head

+ +

[top][index]

+

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_EXPORT cl_status_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: List/cl_list_insert_array_tail

+ +

[top][index]

+

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_EXPORT cl_status_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: List/cl_list_insert_head

+ +

[top][index]

+

NAME

+
       cl_list_insert_head
+
+

DESCRIPTION

+
       The cl_list_insert_head function inserts an object at the head of a list.
+
+

SYNOPSIS

+
CL_INLINE cl_status_t CL_API
+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->list_obj.p_object = p_object;
+        cl_qlist_insert_head( &p_list->list, &p_pool_obj->list_obj.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
+
+
+
+ +

[Functions] +Component Library: List/cl_list_insert_next

+ +

[top][index]

+

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

+
CL_INLINE cl_status_t CL_API
+cl_list_insert_next(
+        IN      cl_list_t* const                        p_list,
+        IN      const 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->list_obj.p_object = p_object;
+        cl_qlist_insert_next( &p_list->list, (cl_list_item_t*)iterator,
+                &p_pool_obj->list_obj.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
+
+
+
+ +

[Functions] +Component Library: List/cl_list_insert_prev

+ +

[top][index]

+

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

+
CL_INLINE cl_status_t CL_API
+cl_list_insert_prev(
+        IN      cl_list_t* const                        p_list,
+        IN      const 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->list_obj.p_object = p_object;
+        cl_qlist_insert_prev( &p_list->list, (cl_list_item_t*)iterator,
+                &p_pool_obj->list_obj.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
+
+
+
+ +

[Functions] +Component Library: List/cl_list_insert_tail

+ +

[top][index]

+

NAME

+
       cl_list_insert_tail
+
+

DESCRIPTION

+
       The cl_list_insert_tail function inserts an object at the head of a list.
+
+

SYNOPSIS

+
CL_INLINE cl_status_t CL_API
+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->list_obj.p_object = p_object;
+        cl_qlist_insert_tail( &p_list->list, &p_pool_obj->list_obj.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
+
+
+
+ +

[Definitions] +Component Library: List/cl_list_iterator_t

+ +

[top][index]

+

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
+
+
+
+ +

[Functions] +Component Library: List/cl_list_next

+ +

[top][index]

+

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

+
CL_INLINE const cl_list_iterator_t CL_API
+cl_list_next(
+        IN      const 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
+
+
+
+ +

[Functions] +Component Library: List/cl_list_obj

+ +

[top][index]

+

NAME

+
       cl_list_obj
+
+

DESCRIPTION

+
       The cl_list_obj function returns the object associated
+       with a list iterator.
+
+

SYNOPSIS

+
CL_INLINE void* CL_API
+cl_list_obj(
+        IN      const cl_list_iterator_t        iterator )
+{
+        CL_ASSERT( iterator );
+
+        return( (void*)((cl_pool_obj_t*)iterator)->list_obj.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
+
+
+
+ +

[Functions] +Component Library: List/cl_list_prev

+ +

[top][index]

+

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

+
CL_INLINE const cl_list_iterator_t CL_API
+cl_list_prev(
+        IN      const 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
+
+
+
+ +

[Functions] +Component Library: List/cl_list_remove_all

+ +

[top][index]

+

NAME

+
       cl_list_remove_all
+
+

DESCRIPTION

+
       The cl_list_remove_all function removes all objects from a list,
+       leaving it empty.
+
+

SYNOPSIS

+
CL_INLINE void CL_API
+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
+
+
+
+ +

[Functions] +Component Library: List/cl_list_remove_head

+ +

[top][index]

+

NAME

+
       cl_list_remove_head
+
+

DESCRIPTION

+
       The cl_list_remove_head function removes an object from the head of a list.
+
+

SYNOPSIS

+
CL_INLINE void* CL_API
+cl_list_remove_head(
+        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_head( &p_list->list );
+
+        /* Place the pool item back into the pool. */
+        cl_qpool_put( &p_list->list_item_pool, (cl_pool_item_t*)p_pool_obj );
+
+        return( (void*)p_pool_obj->list_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 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
+
+
+
+ +

[Functions] +Component Library: List/cl_list_remove_item

+ +

[top][index]

+

NAME

+
       cl_list_remove_item
+
+

DESCRIPTION

+
       The cl_list_remove_item function removes an object from the head of a list.
+
+

SYNOPSIS

+
CL_INLINE void CL_API
+cl_list_remove_item(
+        IN      cl_list_t* const                        p_list,
+        IN      const 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
+
+
+
+ +

[Functions] +Component Library: List/cl_list_remove_object

+ +

[top][index]

+

NAME

+
       cl_list_remove_object
+
+

DESCRIPTION

+
       The cl_list_remove_object function removes a specific object from a list.
+
+

SYNOPSIS

+
CL_EXPORT cl_status_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: List/cl_list_remove_tail

+ +

[top][index]

+

NAME

+
       cl_list_remove_tail
+
+

DESCRIPTION

+
       The cl_list_remove_tail function removes an object from the tail of a list.
+
+

SYNOPSIS

+
CL_INLINE void* CL_API
+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, (cl_pool_item_t*)p_pool_obj );
+
+        return( (void*)p_pool_obj->list_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
+
+
+
+ +

[Structures] +Component Library: List/cl_list_t

+ +

[top][index]

+

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
+
+
+
+ +

[Functions] +Component Library: List/cl_list_tail

+ +

[top][index]

+

NAME

+
       cl_list_tail
+
+

DESCRIPTION

+
       The cl_list_tail function returns returns a list iterator for
+       the tail of a list.
+
+

SYNOPSIS

+
CL_INLINE const cl_list_iterator_t CL_API
+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
+
+
+
+ +

[Definitions] +Component Library: List/cl_pfn_list_apply_t

+ +

[top][index]

+

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_API *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
+
+
+
+ +

[Definitions] +Component Library: List/cl_pfn_list_find_t

+ +

[top][index]

+

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_API *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
+
+
+ + diff --git a/branches/WOF2-3/docs/complib/cl_log_h.html b/branches/WOF2-3/docs/complib/cl_log_h.html new file mode 100644 index 00000000..7c3dffaf --- /dev/null +++ b/branches/WOF2-3/docs/complib/cl_log_h.html @@ -0,0 +1,117 @@ + + + + +./inc_docs/complib/cl_log_h.html + + + + +Generated from ./inc/complib/cl_log.h with ROBODoc v4.99.17 on Sun Mar 04 2007 18:17:52 +
+
+ +

[Modules] +Component Library/Log Provider

+ +

[top][parent][index]

+

NAME

+
       Log Provider
+
+

DESCRIPTION

+
       The log provider allows users to log information in a system log instead of
+       the console or debugger target.
+
+
+
+ +

[Functions] +Component Library: Log Provider/cl_log_event

+ +

[top][index]

+

NAME

+
       cl_log_event
+
+

DESCRIPTION

+
       The cl_log_event function adds a new entry to the system log.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+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
+
+
+
+ +

[Definitions] +Component Library: Log Provider/cl_log_type_t

+ +

[top][index]

+

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
+
+
+ + diff --git a/branches/WOF2-3/docs/complib/cl_map_h.html b/branches/WOF2-3/docs/complib/cl_map_h.html new file mode 100644 index 00000000..2845187a --- /dev/null +++ b/branches/WOF2-3/docs/complib/cl_map_h.html @@ -0,0 +1,898 @@ + + + + +./inc_docs/complib/cl_map_h.html + + + + +Generated from ./inc/complib/cl_map.h with ROBODoc v4.99.17 on Sun Mar 04 2007 18:17:51 +
+
+ +

[Modules] +Component Library/Map

+ +

[top][parent][index]

+

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
+
+       Attributes:
+               cl_map_count, cl_is_map_empty, cl_is_map_inited
+
+
+
+ +

[Functions] +Component Library: Event/cl_is_map_inited

+ +

[top][index]

+

NAME

+
       cl_is_map_inited
+
+

DESCRIPTION

+
       The cl_is_map_inited function returns whether a map was
+       successfully initialized.
+
+

SYNOPSIS

+
CL_INLINE boolean_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Map/cl_is_map_empty

+ +

[top][index]

+

NAME

+
       cl_is_map_empty
+
+

DESCRIPTION

+
       The cl_is_map_empty function returns whether a map is empty.
+
+

SYNOPSIS

+
CL_INLINE boolean_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Map/cl_map_construct

+ +

[top][index]

+

NAME

+
       cl_map_construct
+
+

DESCRIPTION

+
       The cl_map_construct function constructs a map.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Map/cl_map_count

+ +

[top][index]

+

NAME

+
       cl_map_count
+
+

DESCRIPTION

+
       The cl_map_count function returns the number of items stored
+       in a map.
+
+

SYNOPSIS

+
CL_INLINE size_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Map/cl_map_delta

+ +

[top][index]

+

NAME

+
       cl_map_delta
+
+

DESCRIPTION

+
       The cl_map_delta function computes the differences between two maps.
+
+

SYNOPSIS

+
CL_EXPORT cl_status_t CL_API
+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 usefull 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
+
+
+
+ +

[Functions] +Component Library: Map/cl_map_destroy

+ +

[top][index]

+

NAME

+
       cl_map_destroy
+
+

DESCRIPTION

+
       The cl_map_destroy function destroys a map.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Map/cl_map_end

+ +

[top][index]

+

NAME

+
       cl_map_end
+
+

DESCRIPTION

+
       The cl_map_end function returns the iterator for the end of a map.
+
+

SYNOPSIS

+
CL_INLINE const cl_map_iterator_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Map/cl_map_get

+ +

[top][index]

+

NAME

+
       cl_map_get
+
+

DESCRIPTION

+
       The cl_map_get function returns the object associated with a key.
+
+

SYNOPSIS

+
CL_EXPORT void* CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Map/cl_map_head

+ +

[top][index]

+

NAME

+
       cl_map_head
+
+

DESCRIPTION

+
       The cl_map_head function returns the map item with the lowest key
+       value stored in a map.
+
+

SYNOPSIS

+
CL_INLINE cl_map_iterator_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Map/cl_map_init

+ +

[top][index]

+

NAME

+
       cl_map_init
+
+

DESCRIPTION

+
       The cl_map_init function initialized a map for use.
+
+

SYNOPSIS

+
CL_EXPORT cl_status_t CL_API
+cl_map_init(
+        IN      cl_map_t* const p_map,
+        IN      const size_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
+
+
+
+ +

[Functions] +Component Library: Map/cl_map_insert

+ +

[top][index]

+

NAME

+
       cl_map_insert
+
+

DESCRIPTION

+
       The cl_map_insert function inserts a map item into a map.
+
+

SYNOPSIS

+
CL_EXPORT void* CL_API
+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
+
+
+
+ +

[Definitions] +Component Library: Map/cl_map_iterator_t

+ +

[top][index]

+

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
+
+
+
+ +

[Functions] +Component Library: Map/cl_map_key

+ +

[top][index]

+

NAME

+
       cl_map_key
+
+

DESCRIPTION

+
       The cl_map_key function retrieves the key value of a map item.
+
+

SYNOPSIS

+
CL_INLINE uint64_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Map/cl_map_merge

+ +

[top][index]

+

NAME

+
       cl_map_merge
+
+

DESCRIPTION

+
       The cl_map_merge function moves all items from one map to another,
+       excluding duplicates.
+
+

SYNOPSIS

+
CL_EXPORT cl_status_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Map/cl_map_next

+ +

[top][index]

+

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

+
CL_INLINE cl_map_iterator_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Map/cl_map_obj

+ +

[top][index]

+

NAME

+
       cl_map_obj
+
+

DESCRIPTION

+
       The cl_map_obj function returns the object associated with an iterator.
+
+

SYNOPSIS

+
CL_INLINE void* CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Map/cl_map_prev

+ +

[top][index]

+

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

+
CL_INLINE cl_map_iterator_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Map/cl_map_remove

+ +

[top][index]

+

NAME

+
       cl_map_remove
+
+

DESCRIPTION

+
       The cl_map_remove function removes the map item with the specified key
+       from a map.
+
+

SYNOPSIS

+
CL_EXPORT void* CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Map/cl_map_remove_all

+ +

[top][index]

+

NAME

+
       cl_map_remove_all
+
+

DESCRIPTION

+
       The cl_map_remove_all function removes all objects from a map,
+       leaving it empty.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Map/cl_map_remove_item

+ +

[top][index]

+

NAME

+
       cl_map_remove_item
+
+

DESCRIPTION

+
       The cl_map_remove_item function removes the specified map item
+       from a map.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+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
+
+
+
+ +

[Structures] +Component Library: Map/cl_map_t

+ +

[top][index]

+

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
+
+
+
+ +

[Functions] +Component Library: Map/cl_map_tail

+ +

[top][index]

+

NAME

+
       cl_map_tail
+
+

DESCRIPTION

+
       The cl_map_tail function returns the map item with the highest key
+       value stored in a map.
+
+

SYNOPSIS

+
CL_INLINE cl_map_iterator_t CL_API
+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
+
+
+ + diff --git a/branches/WOF2-3/docs/complib/cl_math_h.html b/branches/WOF2-3/docs/complib/cl_math_h.html new file mode 100644 index 00000000..7dc206d8 --- /dev/null +++ b/branches/WOF2-3/docs/complib/cl_math_h.html @@ -0,0 +1,103 @@ + + + + +./inc_docs/complib/cl_math_h.html + + + + +Generated from ./inc/complib/cl_math.h with ROBODoc v4.99.17 on Sun Mar 04 2007 18:17:51 +
+
+ +

[Definitions] +Component Library: Math/MAX

+ +

[top][index]

+

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
+
+
+
+ +

[Definitions] +Component Library: Math/MIN

+ +

[top][index]

+

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
+
+
+
+ +

[Definitions] +Component Library: Math/ROUNDUP

+ +

[top][index]

+

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.
+
+
+ + diff --git a/branches/WOF2-3/docs/complib/cl_memory_h.html b/branches/WOF2-3/docs/complib/cl_memory_h.html new file mode 100644 index 00000000..cd6a1ca0 --- /dev/null +++ b/branches/WOF2-3/docs/complib/cl_memory_h.html @@ -0,0 +1,629 @@ + + + + +./inc_docs/complib/cl_memory_h.html + + + + +Generated from ./inc/complib/cl_memory.h with ROBODoc v4.99.17 on Sun Mar 04 2007 18:17:51 +
+
+ +

[Modules] +Public/Memory Management

+ +

[top][index]

+

NAME

+
       Memory Management
+
+

DESCRIPTION

+
       The memory management functionality provides memory manipulation
+       functions as well as powerful debugging tools.
+
+       The Allocation Tracking functionality provides a means for tracking memory
+       allocations in order to detect memory leaks.
+
+       Memory allocation tracking stores the file name and line number where
+       allocations occur. Gathering this information does have an adverse impact
+       on performance, and memory tracking should therefore not be enabled in
+       release builds of software.
+
+       Memory tracking is compiled into the debug version of the library,
+       and can be enabled for the release version as well. To Enable memory
+       tracking in a release build of the public layer, users should define
+       the MEM_TRACK_ON keyword for compilation.
+
+
+
+ +

[Functions] +Component Library: Memory Management/cl_check_for_read

+ +

[top][index]

+

NAME

+
       cl_check_for_read
+
+

DESCRIPTION

+
       Checks a user-mode virtual address for read access.
+
+

SYNOPSIS

+
CL_EXPORT cl_status_t CL_API
+cl_check_for_read(
+        IN      const void* const       vaddr,
+        IN      const size_t            count );
+
+

PARAMETERS

+
       vaddr
+               [in] Virtual address to check for read access.
+
+       count
+               [in] Number of bytes of the buffer at the specified address
+               to validate.
+
+ RETURN VALUES
+       CL_SUCCESS if the virtual address is valid for a read of the specified
+       size.
+
+       CL_INVALID_PERMISSION if the virtual address or the size is not valid.
+
+

NOTES

+
       This call is only available in the kernel.  The buffer can only be accessed
+       in the context of the application thread (i.e. in the path of an IOCTL
+       request).  Callers cannot be holding a spinlock when calling this function.
+
+

SEE ALSO

+
       Memory Management, cl_check_for_write, cl_copy_to_user, cl_copy_from_user
+
+
+
+ +

[Functions] +Component Library: Memory Management/cl_check_for_write

+ +

[top][index]

+

NAME

+
       cl_check_for_write
+
+

DESCRIPTION

+
       Checks a user-mode virtual address for write access.
+
+

SYNOPSIS

+
CL_EXPORT cl_status_t CL_API
+cl_check_for_write(
+        IN      void* const             vaddr,
+        IN      const size_t    count );
+
+

PARAMETERS

+
       vaddr
+               [in] Virtual address to check for write access.
+
+       count
+               [in] Number of bytes of the buffer at the specified
+               address to validate.
+
+ RETURN VALUES
+       CL_SUCCESS if the virtual address is valid for a write of the specified
+       size.
+
+       CL_INVALID_PERMISSION if the virtual address or the size is not valid.
+
+

NOTES

+
       This call is only available in the kernel.  The buffer can only be accessed
+       in the context of the application thread (i.e. in the path of an IOCTL
+       request).  Callers cannot be holding a spinlock when calling this function.
+
+

SEE ALSO

+
       Memory Management, cl_check_for_read, cl_copy_to_user, cl_copy_from_user
+
+
+
+ +

[Functions] +Component Library: Memory Management/cl_copy_from_user

+ +

[top][index]

+

NAME

+
       cl_copy_from_user
+
+

DESCRIPTION

+
       Copies data from a user-mode buffer, performing access checks.
+
+

SYNOPSIS

+
CL_EXPORT cl_status_t CL_API
+cl_copy_from_user(
+        IN      void* const                     p_dest,
+        IN      const void* const       p_src,
+        IN      const size_t            count );
+
+

PARAMETERS

+
       p_dest
+               [in] Pointer to the buffer being copied to.
+
+       p_src
+               [in] User-mode virtual address from which to copy data.
+
+       count
+               [in] Number of bytes to copy from the source buffer to the
+               destination buffer.
+
+ RETURN VALUES
+       CL_SUCCESS if the user-mode buffer virtual address is valid as the
+       source of the copy.
+
+       CL_INVALID_PERMISSION if the virtual address or the count is not valid.
+
+

NOTES

+
       This call is only available in the kernel.  The buffer can only be accessed
+       in the context of the application thread (i.e. in the path of an IOCTL
+       request).  Callers cannot be holding a spinlock when calling this function.
+
+

SEE ALSO

+
       Memory Management, cl_check_for_read, cl_check_for_write, cl_copy_to_user
+
+
+
+ +

[Functions] +Component Library: Memory Management/cl_copy_to_user

+ +

[top][index]

+

NAME

+
       cl_copy_to_user
+
+

DESCRIPTION

+
       Copies data into a user-mode buffer, performing access checks.
+
+

SYNOPSIS

+
CL_EXPORT cl_status_t CL_API
+cl_copy_to_user(
+        IN      void* const                     p_dest,
+        IN      const void* const       p_src,
+        IN      const size_t            count );
+
+

PARAMETERS

+
       p_dest
+               [in] User-mode virtual address to which to copy data.
+
+       p_src
+               [in] Pointer to the buffer being copied from.
+
+       count
+               [in] Number of bytes to copy from the source buffer to the
+               destination buffer.
+
+ RETURN VALUES
+       CL_SUCCESS if the user-mode buffer virtual address is valid as the
+       destination of the copy.
+
+       CL_INVALID_PERMISSION if the virtual address or the count is not valid.
+
+

NOTES

+
       This call is only available in the kernel.  The buffer can only be accessed
+       in the context of the application thread (i.e. in the path of an IOCTL
+       request).  Callers cannot be holding a spinlock when calling this function.
+
+

SEE ALSO

+
       Memory Management, cl_check_for_read, cl_check_for_write, cl_copy_from_user
+
+
+
+ +

[Functions] +Component Library: Memory Management/cl_free

+ +

[top][index]

+

NAME

+
       cl_free
+
+

DESCRIPTION

+
       The cl_free function deallocates a block of memory.
+
+

SYNOPSIS

+
void
+cl_free(
+        IN      void* const     p_memory );
+
+

PARAMETERS

+
       p_memory
+               [in] Pointer to a memory block.
+
+

RETURN VALUE

+
       This function does not return a value.
+
+

NOTES

+
       The p_memory parameter is the pointer returned by a previous call to
+       cl_malloc, or cl_zalloc.
+
+       cl_free has no effect if p_memory is NULL.
+
+

SEE ALSO

+
       Memory Management, cl_alloc, cl_zalloc
+
+
+
+ +

[Functions] +Component Library: Memory Management/cl_get_pagesize

+ +

[top][index]

+

NAME

+
       cl_get_pagesize
+
+

DESCRIPTION

+
       Returns the number of bytes in a OS defined page.
+
+

SYNOPSIS

+
CL_EXPORT uint32_t CL_API
+cl_get_pagesize( void );
+
+

PARAMETERS

+
       NONE
+
+ RETURN VALUES
+       Returns the number of bytes in a page as defined by the Operating
+       System.
+
+

SEE ALSO

+
       Memory Management
+
+
+
+ +

[Functions] +Component Library: Memory Management/cl_get_physaddr

+ +

[top][index]

+

NAME

+
       cl_get_physaddr
+
+

DESCRIPTION

+
       Returns the Physical address for a kernel virtual address.
+
+

SYNOPSIS

+
CL_EXPORT uint64_t CL_API
+cl_get_physaddr(
+        IN      void *vaddr );
+
+

PARAMETERS

+
       p_addr
+               [in] Pointer to virtual to which the physical address is required.
+
+ RETURN VALUES
+       Returns the physical address for a virtual address.
+
+

NOTES

+
       This call is only available in kernel mode.
+
+

SEE ALSO

+
       Memory Management
+
+
+
+ +

[Functions] +Component Library: Memory Management/cl_malloc

+ +

[top][index]

+

NAME

+
       cl_malloc
+
+

DESCRIPTION

+
       The cl_malloc function allocates a block of memory.
+
+

SYNOPSIS

+
void*
+cl_malloc(
+        IN      const size_t    size );
+
+

PARAMETERS

+
       size
+               [in] Size of the requested allocation.
+
+ RETURN VALUES
+       Pointer to allocated memory if successful.
+
+       NULL otherwise.
+
+

NOTES

+
       Allocated memory follows alignment rules specific to the different
+       environments.
+
+

SEE ALSO

+
       Memory Management, cl_free, cl_zalloc, cl_palloc, cl_pzalloc,
+       cl_memset, cl_memclr, cl_memcpy, cl_memcmp
+
+
+
+ +

[Functions] +Component Library: Memory Management/cl_mem_display

+ +

[top][index]

+

NAME

+
       cl_mem_display
+
+

DESCRIPTION

+
       The cl_mem_display function displays all tracked memory allocations to
+       the applicable debugger.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+cl_mem_display( void );
+
+

RETURN VALUE

+
       This function does not return a value.
+
+

NOTES

+
       Each tracked memory allocation is displayed along with the file name and
+       line number that allocated it.
+
+       Output is sent to the platform's debugging target, which may be the
+       system log file.
+
+

SEE ALSO

+
       Memory Management
+
+
+
+ +

[Functions] +Component Library: Memory Management/cl_memclr

+ +

[top][index]

+

NAME

+
       cl_memclr
+
+

DESCRIPTION

+
       The cl_memclr function sets every byte in a memory range to zero.
+
+

SYNOPSIS

+
CL_INLINE void CL_API
+cl_memclr(
+        IN      void* const             p_memory,
+        IN      const size_t    count )
+{
+        cl_memset( p_memory, 0, count );
+}
+
+

PARAMETERS

+
       p_memory
+               [in] Pointer to a memory block.
+
+       count
+               [in] Number of bytes to set.
+
+

RETURN VALUE

+
       This function does not return a value.
+
+

SEE ALSO

+
       Memory Management, cl_memset, cl_memcpy, cl_memcmp
+
+
+
+ +

[Functions] +Component Library: Memory Management/cl_memcmp

+ +

[top][index]

+

NAME

+
       cl_memcmp
+
+

DESCRIPTION

+
       The cl_memcmp function compares two memory buffers.
+
+

SYNOPSIS

+
CL_EXPORT int32_t CL_API
+cl_memcmp(
+        IN      const void* const       p_mem,
+        IN      const void* const       p_ref,
+        IN      const size_t            count );
+
+

PARAMETERS

+
       p_mem
+               [in] Pointer to a memory block being compared.
+
+       p_ref
+               [in] Pointer to the reference memory block to compare against.
+
+       count
+               [in] Number of bytes to compare.
+
+ RETURN VALUES
+       Returns less than zero if p_mem is less than p_ref.
+
+       Returns greater than zero if p_mem is greater than p_ref.
+
+       Returns zero if the two memory regions are the identical.
+
+

SEE ALSO

+
       Memory Management, cl_memset, cl_memclr, cl_memcpy
+
+
+
+ +

[Functions] +Component Library: Memory Management/cl_memcpy

+ +

[top][index]

+

NAME

+
       cl_memcpy
+
+

DESCRIPTION

+
       The cl_memcpy function copies a given number of bytes from
+       one buffer to another.
+
+

SYNOPSIS

+
CL_EXPORT void* CL_API
+cl_memcpy(
+        IN      void* const                     p_dest,
+        IN      const void* const       p_src,
+        IN      const size_t            count );
+
+

PARAMETERS

+
       p_dest
+               [in] Pointer to the buffer being copied to.
+
+       p_src
+               [in] Pointer to the buffer being copied from.
+
+       count
+               [in] Number of bytes to copy from the source buffer to the
+               destination buffer.
+
+

RETURN VALUE

+
       Returns a pointer to the destination buffer.
+
+

SEE ALSO

+
       Memory Management, cl_memset, cl_memclr, cl_memcmp
+
+
+
+ +

[Functions] +Component Library: Memory Management/cl_memset

+ +

[top][index]

+

NAME

+
       cl_memset
+
+

DESCRIPTION

+
       The cl_memset function sets every byte in a memory range to a given value.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+cl_memset(
+        IN      void* const             p_memory,
+        IN      const uint8_t   fill,
+        IN      const size_t    count );
+
+

PARAMETERS

+
       p_memory
+               [in] Pointer to a memory block.
+
+       fill
+               [in] Byte value with which to fill the memory.
+
+       count
+               [in] Number of bytes to set.
+
+

RETURN VALUE

+
       This function does not return a value.
+
+

SEE ALSO

+
       Memory Management, cl_memclr, cl_memcpy, cl_memcmp
+
+
+
+ +

[Functions] +Component Library: Memory Management/cl_palloc

+ +

[top][index]

+

NAME

+
       cl_palloc
+
+

DESCRIPTION

+
       The cl_palloc function allocates a block of memory from paged pool if the
+       operating system supports it.  If the operating system does not distinguish
+       between pool types, cl_palloc is identical to cl_malloc.
+
+

SYNOPSIS

+
void*
+cl_palloc(
+        IN      const size_t    size );
+
+

PARAMETERS

+
       size
+               [in] Size of the requested allocation.
+
+ RETURN VALUES
+       Pointer to allocated memory if successful.
+
+       NULL otherwise.
+
+

NOTES

+
       Allocated memory follows alignment rules specific to the different
+       environments.
+
+

SEE ALSO

+
       Memory Management, cl_free, cl_malloc, cl_zalloc, cl_pzalloc,
+       cl_memset, cl_memclr, cl_memcpy, cl_memcmp
+
+
+
+ +

[Functions] +Component Library: Memory Management/cl_pzalloc

+ +

[top][index]

+

NAME

+
       cl_pzalloc
+
+

DESCRIPTION

+
       The cl_pzalloc function allocates a block of memory from paged pool if the
+       operating system supports it and initializes it to zero.  If the operating
+       system does not distinguish between pool types, cl_pzalloc is identical
+       to cl_zalloc.
+
+

SYNOPSIS

+
void*
+cl_pzalloc(
+        IN      const size_t    size );
+
+

PARAMETERS

+
       size
+               [in] Size of the requested allocation.
+
+ RETURN VALUES
+       Pointer to allocated memory if successful.
+
+       NULL otherwise.
+
+

NOTES

+
       Allocated memory follows alignment rules specific to the different
+       environments.
+
+

SEE ALSO

+
       Memory Management, cl_free, cl_malloc, cl_zalloc, cl_palloc,
+       cl_memset, cl_memclr, cl_memcpy, cl_memcmp
+
+
+
+ +

[Functions] +Component Library: Memory Management/cl_zalloc

+ +

[top][index]

+

NAME

+
       cl_zalloc
+
+

DESCRIPTION

+
       The cl_zalloc function allocates a block of memory initialized to zero.
+
+

SYNOPSIS

+
void*
+cl_zalloc(
+        IN      const size_t    size );
+
+

PARAMETERS

+
       size
+               [in] Size of the requested allocation.
+
+ RETURN VALUES
+       Pointer to allocated memory if successful.
+
+       NULL otherwise.
+
+

NOTES

+
       Allocated memory follows alignment rules specific to the different
+       environments.
+
+

SEE ALSO

+
       Memory Management, cl_free, cl_malloc, cl_palloc, cl_pzalloc,
+       cl_memset, cl_memclr, cl_memcpy, cl_memcmp
+
+
+ + diff --git a/branches/WOF2-3/docs/complib/cl_mutex_h.html b/branches/WOF2-3/docs/complib/cl_mutex_h.html new file mode 100644 index 00000000..b9bbfdb4 --- /dev/null +++ b/branches/WOF2-3/docs/complib/cl_mutex_h.html @@ -0,0 +1,207 @@ + + + + +./inc_docs/complib/cl_mutex_h.html + + + + +Generated from ./inc/complib/cl_mutex.h with ROBODoc v4.99.17 on Sun Mar 04 2007 18:17:51 +
+
+ +

[Modules] +complib/Mutex

+ +

[top][index]

+

NAME

+
       Mutex
+
+

DESCRIPTION

+
       Mutex provides synchronization between threads for exclusive access to
+       a resource.
+
+       The Mutex functions manipulate a cl_mutex_t structure which should
+       be treated as opaque and should be manipulated only through the provided
+       functions.
+
+

SEE ALSO

+
       Structures:
+               cl_mutex_t
+
+       Initialization:
+               cl_mutex_construct, cl_mutex_init, cl_mutex_destroy
+
+       Manipulation
+               cl_mutex_acquire, cl_mutex_release
+
+
+
+ +

[Functions] +Component Library: Mutex/cl_mutex_acquire

+ +

[top][index]

+

NAME

+
       cl_mutex_acquire
+
+

DESCRIPTION

+
       The cl_mutex_acquire function acquires a mutex.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+cl_mutex_acquire(
+        IN      cl_mutex_t* const       p_mutex );
+
+

PARAMETERS

+
       p_mutex
+               [in] Pointer to a mutex structure to acquire.
+
+

RETURN VALUE

+
       This function does not return a value.
+
+

SEE ALSO

+
       Mutex, cl_mutex_release
+
+
+
+ +

[Functions] +Component Library: Mutex/cl_mutex_construct

+ +

[top][index]

+

NAME

+
       cl_mutex_construct
+
+

DESCRIPTION

+
       The cl_mutex_construct function initializes the state of a
+       mutex.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+cl_mutex_construct(
+        IN      cl_mutex_t* const       p_mutex );
+
+

PARAMETERS

+
       p_mutex
+               [in] Pointer to a mutex structure whose state to initialize.
+
+

RETURN VALUE

+
       This function does not return a value.
+
+

NOTES

+
       Allows calling cl_semphore_destroy without first calling
+       cl_mutex_init.
+
+       Calling cl_mutex_construct is a prerequisite to calling any other
+       mutex function except cl_mutex_init.
+
+

SEE ALSO

+
       Mutex, cl_semphore_init cl_mutex_destroy
+
+
+
+ +

[Functions] +Component Library: Mutex/cl_mutex_destroy

+ +

[top][index]

+

NAME

+
       cl_mutex_destroy
+
+

DESCRIPTION

+
       The cl_mutex_destroy function performs all necessary cleanup of a
+       mutex.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+cl_mutex_destroy(
+        IN      cl_mutex_t* const       p_mutex );
+
+

PARAMETERS

+
       p_mutex
+               [in] Pointer to a mutex structure to destroy.
+
+

RETURN VALUE

+
       This function does not return a value.
+
+

NOTES

+
       Performs any necessary cleanup of a mutex. This function must only
+       be called if either cl_mutex_construct or cl_mutex_init has been
+       called.
+
+

SEE ALSO

+
       Mutex, cl_mutex_construct, cl_mutex_init
+
+
+
+ +

[Functions] +Component Library: Mutex/cl_mutex_init

+ +

[top][index]

+

NAME

+
       cl_mutex_init
+
+

DESCRIPTION

+
       The cl_mutex_init function initializes a mutex for use.
+
+

SYNOPSIS

+
CL_EXPORT cl_status_t CL_API
+cl_mutex_init(
+        IN      cl_mutex_t* const       p_mutex );
+
+

PARAMETERS

+
       p_mutex
+               [in] Pointer to a mutex structure to initialize.
+
+ RETURN VALUES
+       CL_SUCCESS if initialization succeeded.
+
+       CL_ERROR if initialization failed. Callers should call
+       cl_mutex_destroy to clean up any resources allocated during
+       initialization.
+
+

NOTES

+
       Initializes the mutex structure. Allows calling cl_mutex_aquire
+       and cl_mutex_release. The cl_mutex is always created in the unlocked state.
+
+

SEE ALSO

+
       Mutex, cl_mutex_construct, cl_mutex_destroy,
+       cl_mutex_acquire, cl_mutex_release
+
+
+
+ +

[Functions] +Component Library: Mutex/cl_mutex_release

+ +

[top][index]

+

NAME

+
       cl_mutex_release
+
+

DESCRIPTION

+
       The cl_mutex_release function releases a mutex object.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+cl_mutex_release(
+        IN      cl_mutex_t* const       p_mutex );
+
+

PARAMETERS

+
       p_mutex
+               [in] Pointer to a mutex structure to release.
+
+

RETURN VALUE

+
       This function does not return a value.
+
+

NOTES

+
       Releases a mutex after a call to cl_mutex_acquire.
+
+

SEE ALSO

+
       Mutex, cl_mutex_acquire
+
+
+ + diff --git a/branches/WOF2-3/docs/complib/cl_obj_h.html b/branches/WOF2-3/docs/complib/cl_obj_h.html new file mode 100644 index 00000000..9dcd6e3c --- /dev/null +++ b/branches/WOF2-3/docs/complib/cl_obj_h.html @@ -0,0 +1,997 @@ + + + + +./inc_docs/complib/cl_obj_h.html + + + + +Generated from ./inc/complib/cl_obj.h with ROBODoc v4.99.17 on Sun Mar 04 2007 18:17:51 +
+
+ +

[Modules] +Component Library/Object

+ +

[top][parent][index]

+

NAME

+
       Object
+
+

DESCRIPTION

+
       Object describes a basic class that can be used to track accesses to an
+       object and provides automatic cleanup of an object that is dependent
+       on another object.
+
+       Dependencies between objects are described using a relationship.  A
+       child object is considered dependent on a parent object.  Destruction of
+       a parent object automatically results in the destruction of any child
+       objects associated with the parent.
+
+       The relationship between parent and child objects is many to many.
+       Parents can have multiple child objects, and a child can be dependent on
+       multiple parent objects.  In the latter case, destruction of any parent
+       object results in the destruction of the child object.
+
+       Other relationships between objects are described using references.  An
+       object that takes a reference on a second object prevents the second object
+       from being deallocated as long as the reference is held.
+
+

SEE ALSO

+
       Types
+               cl_destroy_type_t
+
+       Structures:
+               cl_obj_t, cl_obj_rel_t
+
+       Callbacks:
+               cl_pfn_obj_call_t
+
+       Initialization/Destruction:
+               cl_obj_mgr_create, cl_obj_mgr_destroy,
+               cl_obj_construct, cl_obj_init, cl_obj_destroy, cl_obj_deinit
+
+       Object Relationships:
+               cl_obj_ref, cl_obj_deref,
+               cl_rel_alloc, cl_rel_free, cl_obj_insert_rel, cl_obj_remove_rel
+
+       Object Manipulation:
+               cl_obj_reset
+
+
+
+ +

[Definitions] +Component Library: Object/cl_destroy_type_t

+ +

[top][index]

+

NAME

+
       cl_destroy_type_t
+
+

DESCRIPTION

+
       Indicates the type of destruction to perform on an object.
+
+

SYNOPSIS

+
typedef enum _cl_destroy_type
+{
+        CL_DESTROY_ASYNC,
+        CL_DESTROY_SYNC
+
+}       cl_destroy_type_t;
+
+

VALUES

+
       CL_DESTROY_ASYNC
+               Indicates that the object should be destroyed asynchronously.  Objects
+               destroyed asynchronously complete initial destruction processing, then
+               return the calling thread.  Once their reference count goes to zero,
+               they are queue onto an asynchronous thread to complete destruction
+               processing.
+
+       CL_DESTROY_SYNC
+               Indicates that the object should be destroyed synchronously.  Objects
+               destroyed synchronously wait (block) until their reference count goes
+               to zero.  Once their reference count goes to zero, destruction
+               processing is completed by the calling thread.
+
+

SEE ALSO

+
       Object, cl_obj_init, cl_obj_destroy, cl_obj_deinit, cl_obj_t
+
+
+
+ +

[Functions] +Component Library: Object/cl_obj_construct

+ +

[top][index]

+

NAME

+
       cl_obj_construct
+
+

DESCRIPTION

+
       This routine prepares an object for use.  The object must be successfully
+       initialized before being used.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+cl_obj_construct(
+        IN                              cl_obj_t * const                        p_obj,
+        IN              const   uint32_t                                        obj_type );
+
+

PARAMETERS

+
       p_obj
+               [in] A pointer to the object to construct.
+
+       obj_type
+               [in] A user-specified type associated with the object.  This type
+               is recorded by the object for debugging purposes and may be accessed
+               by the user.
+
+

RETURN VALUE

+
       None.
+
+

NOTES

+
       This call must succeed before invoking any other function on an object.
+
+

SEE ALSO

+
       Object, cl_obj_init, cl_obj_destroy, cl_obj_deinit.
+
+
+
+ +

[Functions] +Component Library: Object/cl_obj_deinit

+ +

[top][index]

+

NAME

+
       cl_obj_deinit
+
+

DESCRIPTION

+
       Release all resources allocated by an object.  This routine should
+       typically be called from a user's pfn_free routine.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+cl_obj_deinit(
+        IN                              cl_obj_t * const                        p_obj );
+
+

PARAMETERS

+
       p_obj
+               [in] A pointer to the object to free.
+
+

RETURN VALUE

+
       None.
+
+

NOTES

+
       This call must be invoked to release the object from the global object
+       manager.
+
+

SEE ALSO

+
       Object, cl_obj_construct, cl_obj_init, cl_obj_destroy, cl_obj_t
+
+
+
+ +

[Functions] +Component Library: Object/cl_obj_deref

+ +

[top][index]

+

NAME

+
       cl_obj_deref
+
+

DESCRIPTION

+
       Decrements the reference count on an object and returns the updated count.
+       This routine is thread safe, but results in locking the object.
+
+

SYNOPSIS

+
CL_EXPORT int32_t CL_API
+cl_obj_deref(
+        IN                              cl_obj_t * const                        p_obj );
+
+

PARAMETERS

+
       p_obj
+               [in] A pointer to the object to dereference.
+
+

RETURN VALUE

+
       The updated reference count.
+
+

SEE ALSO

+
       Object, cl_obj_t, cl_obj_ref
+
+
+
+ +

[Functions] +Component Library: Object/cl_obj_destroy

+ +

[top][index]

+

NAME

+
       cl_obj_destroy
+
+

DESCRIPTION

+
       This routine destroys the specified object.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+cl_obj_destroy(
+        IN                              cl_obj_t *                                      p_obj );
+
+

PARAMETERS

+
       p_obj
+               [in] A pointer to the object to destroy.
+
+

RETURN VALUE

+
       None.
+
+

NOTES

+
       This routine starts the destruction process for the specified object.  For
+       additional information regarding destruction callbacks, see the following
+       fields in cl_obj_t and parameters in cl_obj_init: pfn_destroying,
+       pfn_cleanup, and pfn_free.
+
+       In most cases, after calling this routine, users should call cl_obj_deinit
+       from within their pfn_free callback routine.
+
+

SEE ALSO

+
       Object, cl_obj_construct, cl_obj_init, cl_obj_deinit,
+       cl_obj_t, cl_destroy_type_t, cl_pfn_obj_call_t
+
+
+
+ +

[Functions] +Component Library: Object/cl_obj_init

+ +

[top][index]

+

NAME

+
       cl_obj_init
+
+

DESCRIPTION

+
       This routine initializes an object for use.  Upon the successful completion
+       of this call, the object is ready for use.
+
+

SYNOPSIS

+
CL_EXPORT cl_status_t CL_API
+cl_obj_init(
+        IN                              cl_obj_t * const                        p_obj,
+        IN                              cl_destroy_type_t                       destroy_type,
+        IN              const   cl_pfn_obj_call_t                       pfn_destroying OPTIONAL,
+        IN              const   cl_pfn_obj_call_t                       pfn_cleanup OPTIONAL,
+        IN              const   cl_pfn_obj_call_t                       pfn_free );
+
+

PARAMETERS

+
       p_obj
+               [in] A pointer to the object to initialize.
+
+       destroy_type
+               [in] Specifies the destruction model used by this object.
+
+       pfn_destroying
+               [in] User-specified callback invoked to notify a user that an object has
+               been marked for destruction.  This callback is invoked directly from
+               the thread destroying the object and is used to notify a user that
+               a parent object has invoked a child object's destructor.
+
+       pfn_cleanup
+               [in] User-specified callback invoked to an object is undergoing
+               destruction.  For object's destroyed asynchronously, this callback
+               is invoked from the context of the asynchronous destruction thread.
+               Users may block in the context of this thread; however, further
+               destruction processing will not continue until this callback returns.
+
+       pfn_free
+               [in] User-specified callback invoked to notify a user that an object has
+               been destroyed and is ready for deallocation.  Users should either
+               call cl_obj_deinit or cl_obj_reset from within this callback.
+
+

RETURN VALUE

+
       CL_SUCCESS
+               The object was successfully initialized.
+
+       CL_INSUFFICIENT_MEMORY
+               The object could not allocate the necessary memory resources to
+               complete initialization.
+
+

NOTES

+
       The three destruction callbacks are used to notify the user of the progress
+       of the destruction, permitting the user to perform an additional processing.
+       Pfn_destroying is used to notify the user that the object is being
+       destroyed.  It is called after an object has removed itself from
+       relationships with its parents, but before it destroys any child objects
+       that it might have.
+
+       Pfn_cleanup is invoked after all child objects have been destroyed, and
+       there are no more references on the object itself.  For objects destroyed
+       asynchronously, pfn_cleanup is invoked from an asynchronous destruction
+       thread.
+
+       Pfn_free is called to notify the user that the destruction of the object has
+       completed.  All relationships have been removed, and all child objects have
+       been destroyed.  Relationship items (cl_obj_rel_t) that were used to
+       identify parent objects are returned to the user through the p_parent_list
+       field of the cl_obj_t structure.
+
+

SEE ALSO

+
       Object, cl_obj_construct, cl_obj_destroy, cl_obj_deinit,
+       cl_obj_t, cl_destroy_type_t, cl_pfn_obj_call_t,
+
+
+
+ +

[Functions] +Component Library: Object/cl_obj_insert_rel

+ +

[top][index]

+

NAME

+
       cl_obj_insert_rel
+
+

DESCRIPTION

+
       Forms a relationship between two objects, with the existence of the child
+       object dependent on the parent.
+
+

SYNOPSIS

+
CL_EXPORT cl_status_t CL_API
+cl_obj_insert_rel(
+        IN                              cl_obj_rel_t * const            p_rel,
+        IN                              cl_obj_t * const                        p_parent_obj,
+        IN                              cl_obj_t * const                        p_child_obj );
+
+

PARAMETERS

+
       p_rel
+               [in] A reference to an unused relationship item.
+
+       p_parent_obj
+               [in] A reference to the parent object.
+
+       p_child_obj
+               [in] A reference to the child object.
+
+

RETURN VALUE

+
       None.
+
+

NOTES

+
       This call inserts a relationship between the parent and child object.
+       The relationship allows for the automatic destruction of the child object
+       if the parent is destroyed.
+
+       A given object can have multiple parent and child objects, but the
+       relationships must form into an object tree.  That is, there cannot be any
+       cycles formed through the parent-child relationships.  (For example, an
+       object cannot be both the parent and a child of a second object.)
+
+

SEE ALSO

+
       Object, cl_rel_alloc, cl_rel_free, cl_obj_remove_rel, cl_obj_destroy
+
+
+
+ +

[Functions] +Component Library: Object/cl_obj_insert_rel_parent_locked

+ +

[top][index]

+

NAME

+
       cl_obj_insert_rel_parent_locked
+
+

DESCRIPTION

+
       Forms a relationship between two objects, with the existence of the child
+       object dependent on the parent.  The parent's object lock is held.
+
+

SYNOPSIS

+
CL_EXPORT cl_status_t CL_API
+cl_obj_insert_rel_parent_locked(
+        IN                              cl_obj_rel_t * const            p_rel,
+        IN                              cl_obj_t * const                        p_parent_obj,
+        IN                              cl_obj_t * const                        p_child_obj );
+
+

PARAMETERS

+
       p_rel
+               [in] A reference to an unused relationship item.
+
+       p_parent_obj
+               [in] A reference to the parent object.
+
+       p_child_obj
+               [in] A reference to the child object.
+
+

RETURN VALUE

+
       None.
+
+

NOTES

+
       This call inserts a relationship between the parent and child object.
+       The relationship allows for the automatic destruction of the child object
+       if the parent is destroyed.
+
+       A given object can have multiple parent and child objects, but the
+       relationships must form into an object tree.  That is, there cannot be any
+       cycles formed through the parent-child relationships.  (For example, an
+       object cannot be both the parent and a child of a second object.)
+
+       This call requires the caller to already hold the parent object's lock.
+
+

SEE ALSO

+
       Object, cl_rel_alloc, cl_rel_free, cl_obj_remove_rel, cl_obj_destroy
+
+
+
+ +

[Functions] +Component Library: Object/cl_obj_lock

+ +

[top][index]

+

NAME

+
       cl_obj_lock
+
+

DESCRIPTION

+
       Acquires an object's lock.
+
+

SYNOPSIS

+
CL_INLINE void CL_API
+cl_obj_lock(
+        IN                              cl_obj_t * const                        p_obj )
+{
+        CL_ASSERT( p_obj->state == CL_INITIALIZED ||
+                p_obj->state == CL_DESTROYING );
+        cl_spinlock_acquire( &p_obj->lock );
+}
+
+

PARAMETERS

+
       p_obj
+               [in] A pointer to the object whose lock to acquire.
+
+

RETURN VALUE

+
       This function does not return a value.
+
+

SEE ALSO

+
       Object, cl_obj_t, cl_obj_unlock
+
+
+
+ +

[Functions] +Component Library: Object/cl_obj_mgr_create

+ +

[top][index]

+

NAME

+
       cl_obj_mgr_create
+
+

DESCRIPTION

+
       This routine creates an object manager used to track all objects by
+       the user.  The object manager assists with debugging efforts by identifying
+       objects that are not destroyed properly.
+
+

SYNOPSIS

+
CL_EXPORT cl_status_t CL_API
+cl_obj_mgr_create(void);
+
+

PARAMETERS

+
       None.
+
+

RETURN VALUE

+
       CL_SUCCESS
+               The object manager was succesfully created.
+
+       CL_INSUFFICIENT_MEMORY
+               The object manager could not be allocated.
+
+

NOTES

+
       This call must succeed before invoking any other object-related function.
+
+

SEE ALSO

+
       Object, cl_obj_mgr_destroy
+
+
+
+ +

[Functions] +Component Library: Object/cl_obj_mgr_destroy

+ +

[top][index]

+

NAME

+
       cl_obj_mgr_destroy
+
+

DESCRIPTION

+
       This routine destroys the object manager created through cl_obj_mgr_create.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+cl_obj_mgr_destroy(void);
+
+

PARAMETERS

+
       None.
+
+

RETURN VALUE

+
       None.
+
+

NOTES

+
       When the object manager is destroyed, it will display information about all
+       objects that have not yet been destroyed.
+
+

SEE ALSO

+
       Object, cl_obj_mgr_create
+
+
+
+ +

[Structures] +Component Library: Object/cl_obj_mgr_t

+ +

[top][index]

+

NAME

+
       cl_obj_mgr_t
+
+

DESCRIPTION

+
       The global object manager.
+
+       The manager must be created before constructing any other objects, and all
+       objects must be destroyed before the object manager is destroyed.
+
+       The manager is used to maintain the list of all objects currently active
+       in the system.  It provides a pool of relationship items used to
+       describe parent-child, or dependent, relationships between two objects.
+       The manager contains an asynchronous processing thread that is used to
+       support asynchronous object destruction.
+
+

SYNOPSIS

+
typedef struct _cl_obj_mgr
+{
+        cl_qlist_t                                      obj_list;
+        cl_spinlock_t                           lock;
+
+        cl_async_proc_t                         async_proc_mgr;
+
+        cl_qpool_t                                      rel_pool;
+
+}       cl_obj_mgr_t;
+
+

FIELDS

+
       obj_list
+               List of all object's in the system.  Object's are inserted into this
+               list when constructed and removed when freed.
+
+       lock
+               A lock used by the object manager for synchronization to the obj_list.
+
+       async_proc_mgr
+               An asynchronous processing manager used to process asynchronous
+               destruction requests.  Users wishing to synchronize the execution of
+               specific routines with object destruction may queue work requests to
+               this processing manager.
+
+       rel_pool
+               Pool of items used to describe dependent relationships.  Users may
+               obtain relationship objects from this pool when forming relationships,
+               but are not required to do so.
+
+

SEE ALSO

+
       Object, cl_obj_mgr_create, cl_obj_mgr_destroy,
+       cl_obj_construct, cl_obj_deinit,
+       cl_qlist_t, cl_spinlock_t, cl_async_proc_t, cl_qpool_t
+
+
+
+ +

[Functions] +Component Library: Object/cl_obj_ref

+ +

[top][index]

+

NAME

+
       cl_obj_ref
+
+

DESCRIPTION

+
       Increments the reference count on an object and returns the updated count.
+       This routine is thread safe, but does not result in locking the object.
+
+

SYNOPSIS

+
CL_EXPORT int32_t CL_API
+cl_obj_ref(
+        IN                              cl_obj_t * const                        p_obj );
+
+

PARAMETERS

+
       p_obj
+               [in] A pointer to the object to reference.
+
+

RETURN VALUE

+
       The updated reference count.
+
+

SEE ALSO

+
       Object, cl_obj_t, cl_obj_deref
+
+
+
+ +

[Structures] +Component Library: Object/cl_obj_rel_t

+ +

[top][index]

+

NAME

+
       cl_obj_rel_t
+
+

DESCRIPTION

+
       Identifies a dependent relationship between two objects.
+
+

SYNOPSIS

+
typedef struct _cl_obj_rel
+{
+        cl_pool_item_t                          pool_item;              /* Must be first. */
+        struct _cl_obj                          *p_parent_obj;
+
+        cl_list_item_t                          list_item;
+        struct _cl_obj                          *p_child_obj;
+
+}       cl_obj_rel_t;
+
+

FIELDS

+
       pool_item
+               An item used to store the relationship in a free pool maintained
+               by the object manager.  This field is also used by the parent object
+               to store the relationship in its child_list.
+
+       p_parent_obj
+               A reference to the parent object for the relationship.
+
+       list_item
+               This field is used by the child object to store the relationship in
+               its parent_list.
+
+       p_child_obj
+               A reference to the child object for the relationship.
+
+

NOTES

+
       This structure is used to define all dependent relationships.  Dependent
+       relationships are those where the destruction of a parent object result in
+       the destruction of child objects.  For other types of relationships, simple
+       references between objects may be used.
+
+       Relationship items are stored in lists maintained by both the parent
+       and child objects.  References to both objects exist while the
+       relationship is maintained.  Typically, relationships are defined by
+       the user by calling cl_obj_insert_rel, but are destroyed automatically
+       via an object's destruction process.
+
+

SEE ALSO

+
       Object, cl_rel_alloc, cl_rel_free, cl_obj_insert_rel, cl_obj_remove_rel,
+       cl_obj_destroy
+
+
+
+ +

[Functions] +Component Library: Object/cl_obj_remove_rel

+ +

[top][index]

+

NAME

+
       cl_obj_remove_rel
+
+

DESCRIPTION

+
       Manually removes a relationship between two objects.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+cl_obj_remove_rel(
+        IN                              cl_obj_rel_t * const            p_rel );
+
+

PARAMETERS

+
       p_rel
+               [in] A reference to the relationship to remove.
+
+

RETURN VALUE

+
       None.
+
+

NOTES

+
       This routine permits a user to manually remove a dependent relationship
+       between two objects.  When removing a relationship using this call, the
+       user must ensure that objects referenced by the relationship are not
+       destroyed, either directly or indirectly via a parent.
+
+

SEE ALSO

+
       Object, cl_rel_alloc, cl_rel_free, cl_obj_insert_rel, cl_obj_destroy
+
+
+
+ +

[Functions] +Component Library: Object/cl_obj_reset

+ +

[top][index]

+

NAME

+
       cl_obj_reset
+
+

DESCRIPTION

+
       Reset an object's state.  This is called after cl_obj_destroy has
+       been called on a object, but before cl_obj_deinit has been invoked.
+       After an object has been reset, it is ready for re-use.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+cl_obj_reset(
+        IN                              cl_obj_t * const                        p_obj );
+
+

PARAMETERS

+
       p_obj
+               [in] A pointer to the object to reset.
+
+

RETURN VALUE

+
       None.
+
+

NOTES

+
       This routine allows an object to be initialized once, then destroyed
+       and re-used multiple times.  This permits the user to allocate and
+       maintain a pool of objects.  The objects may be reset and returned to
+       the pool, rather than freed, after being destroyed.  The objects would
+       not be freed until the pool itself was destroyed.
+
+

SEE ALSO

+
       Object, cl_obj_destroy, cl_obj_free, cl_obj_t
+
+
+
+ +

[Structures] +Component Library: Object/cl_obj_t

+ +

[top][index]

+

NAME

+
       cl_obj_t
+
+

DESCRIPTION

+
       Object structure.
+
+

SYNOPSIS

+
typedef struct _cl_obj
+{
+        cl_pool_item_t                          pool_item;      /* Must be first. */
+        uint32_t                                        type;
+        cl_state_t                                      state;
+        cl_destroy_type_t                       destroy_type;
+
+        cl_async_proc_item_t            async_item;
+        cl_event_t                                      event;
+
+        cl_pfn_obj_call_t                       pfn_destroying;
+        cl_pfn_obj_call_t                       pfn_cleanup;
+        cl_pfn_obj_call_t                       pfn_free;
+
+        cl_spinlock_t                           lock;
+
+        cl_qlist_t                                      parent_list;
+        cl_qlist_t                                      child_list;
+
+        atomic32_t                                      ref_cnt;
+
+}       cl_obj_t;
+
+

FIELDS

+
       pool_item
+               Used to track the object with the global object manager.  We use
+               a pool item, rather than a list item, to let users store the object
+               in a pool.
+
+       type
+               Stores a user-specified object type.
+
+       state
+               Records the current state of the object, such as initialized,
+               destroying, etc.
+
+       destroy_type
+               Specifies the type of destruction, synchronous or asynchronous, to
+               perform on this object.
+
+       async_item
+               Asynchronous item used when destroying the object asynchronously.
+               This item is queued to an asynchronous thread to complete destruction
+               processing.
+
+       event
+               Event used when destroying the object synchronously.  A call to destroy
+               the object will wait on this event until the destruction has completed.
+
+       pfn_destroying
+               User-specified callback invoked to notify a user that an object has
+               been marked for destruction.  This callback is invoked directly from
+               the thread destroying the object and is used to notify a user that
+               a parent object has invoked a child object's destructor.
+
+       pfn_cleanup
+               User-specified callback invoked as an object is undergoing destruction.
+               For object's destroyed asynchronously, this callback is invoked from
+               the context of the asynchronous destruction thread.  Users may block
+               in the context of this thread; however, further destruction processing
+               will not continue until this callback returns.
+
+       pfn_free
+               User-specified callback invoked to notify a user that an object has
+               been destroyed and is ready for deallocation.  Users should either
+               call cl_obj_deinit or cl_obj_reset from within this callback.
+
+       lock
+               A lock provided by the object.
+
+       parent_list
+               A list of relationships to parent objects that an object is dependent
+               on.
+
+       child_list
+               A list of all child objects that are dependent on this object.
+               Destroying this object will result in all related objects maintained
+               in the child list also being destroyed.
+
+       ref_cnt
+               A count of the number of objects still referencing this object.
+
+

SEE ALSO

+
       Object, cl_obj_construct, cl_obj_init, cl_obj_destroy,
+       cl_obj_deinit, cl_pfn_obj_call_t, cl_destroy_type_t,
+       cl_pool_item_t, cl_state_t, cl_async_proc_item_t,
+       cl_event_t, cl_spinlock_t, cl_qlist_t, atomic32_t
+
+
+
+ +

[Functions] +Component Library: Object/cl_obj_type

+ +

[top][index]

+

NAME

+
       cl_obj_type
+
+

DESCRIPTION

+
       Returns the type of an object.
+
+

SYNOPSIS

+
CL_INLINE uint32_t CL_API
+cl_obj_type(
+        IN                              cl_obj_t * const                        p_obj )
+{
+        return p_obj->type;
+}
+
+

PARAMETERS

+
       p_obj
+               [in] A pointer to the object whose type to return.
+
+

RETURN VALUE

+
       The type of the object, as specified in the call to cl_obj_init.
+
+

SEE ALSO

+
       Object, cl_obj_t, cl_obj_init
+
+
+
+ +

[Functions] +Component Library: Object/cl_obj_unlock

+ +

[top][index]

+

NAME

+
       cl_obj_unlock
+
+

DESCRIPTION

+
       Releases an object's lock previously acquired by a call to cl_obj_lock.
+
+

SYNOPSIS

+
CL_INLINE void CL_API
+cl_obj_unlock(
+        IN                              cl_obj_t * const                        p_obj )
+{
+        CL_ASSERT( p_obj->state == CL_INITIALIZED ||
+                p_obj->state == CL_DESTROYING );
+        cl_spinlock_release( &p_obj->lock );
+}
+
+

PARAMETERS

+
       p_obj
+               [in] A pointer to the object whose lock to release.
+
+

RETURN VALUE

+
       This function does not return a value.
+
+

SEE ALSO

+
       Object, cl_obj_t, cl_obj_lock
+
+
+
+ +

[Definitions] +Component Library: Object/cl_pfn_obj_call_t

+ +

[top][index]

+

NAME

+
       cl_pfn_obj_call_t
+
+

DESCRIPTION

+
       The cl_pfn_obj_call_t function type defines the prototype for functions
+       used to return objects to the user.
+
+

SYNOPSIS

+
typedef void
+(CL_API *cl_pfn_obj_call_t)(
+        IN                              struct _cl_obj                          *p_obj );
+
+

PARAMETERS

+
       p_obj
+               [in] Pointer to a cl_obj_t.  This is the object being returned to
+               the user.
+
+ RETURN VALUES
+       None.
+
+

NOTES

+
       This function type is provided as a prototype for functions provided
+       by users as parameters to the cl_obj_init function.
+
+

SEE ALSO

+
       Object, cl_obj_init, cl_obj_t
+
+
+
+ +

[Functions] +Component Library: Object/cl_rel_alloc

+ +

[top][index]

+

NAME

+
       cl_rel_alloc
+
+

DESCRIPTION

+
       Retrieves an object relationship item from the object manager.
+
+

SYNOPSIS

+
CL_EXPORT cl_obj_rel_t* CL_API
+cl_rel_alloc(void);
+
+

PARAMETERS

+
       None.
+
+

RETURN VALUE

+
       A reference to an allocated relationship object, or NULL if no relationship
+       object could be allocated.
+
+

NOTES

+
       This routine retrieves a cl_obj_rel_t structure from a pool maintained
+       by the object manager.  The pool automatically grows as needed.
+
+       Relationship items are used to describe a dependent relationship between
+       a parent and child object.  In cases where a child has a fixed number of
+       relationships, the user may be able to allocate and manage the cl_obj_rel_t
+       structures more efficiently than obtaining the structures through this call.
+
+

SEE ALSO

+
       Object, cl_rel_free, cl_obj_insert_rel, cl_obj_remove_rel, cl_obj_destroy
+
+
+
+ +

[Functions] +Component Library: Object/cl_rel_free

+ +

[top][index]

+

NAME

+
       cl_rel_free
+
+

DESCRIPTION

+
       Return a relationship object to the global object manager.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+cl_rel_free(
+        IN                              cl_obj_rel_t * const            p_rel );
+
+

PARAMETERS

+
       p_rel
+               [in] A reference to the relationship item to free.
+
+

RETURN VALUE

+
       None.
+
+

NOTES

+
       Relationship items must not be freed until both the parent and child
+       object have removed their references to one another.  Relationship items
+       may be freed after calling cl_obj_remove_rel or after the associated
+       child object's free callback has been invoked.  In the latter case, the
+       invalid relationship items are referenced by the child object's parent_list.
+
+

SEE ALSO

+
       Object, cl_rel_alloc, cl_obj_insert_rel, cl_obj_remove_rel, cl_obj_destroy
+
+
+ + diff --git a/branches/WOF2-3/docs/complib/cl_passivelock_h.html b/branches/WOF2-3/docs/complib/cl_passivelock_h.html new file mode 100644 index 00000000..50cdf150 --- /dev/null +++ b/branches/WOF2-3/docs/complib/cl_passivelock_h.html @@ -0,0 +1,417 @@ + + + + +./inc_docs/complib/cl_passivelock_h.html + + + + +Generated from ./inc/complib/cl_passivelock.h with ROBODoc v4.99.17 on Sun Mar 04 2007 18:17:51 +
+
+ +

[Modules] +Component Library/Passive Lock

+ +

[top][parent][index]

+

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
+
+
+
+ +

[Functions] +Component Library: Passive Lock/cl_plock_acquire

+ +

[top][index]

+

NAME

+
       cl_plock_acquire
+
+

DESCRIPTION

+
       The cl_plock_acquire function acquires a passive lock for
+       shared access.
+
+

SYNOPSIS

+
CL_INLINE void CL_API
+cl_plock_acquire(
+        IN      cl_plock_t* const       p_lock )
+{
+        cl_status_t     status;
+
+        CL_ASSERT( p_lock );
+
+        status =
+                cl_event_wait_on( &p_lock->reader_event, EVENT_NO_TIMEOUT, FALSE );
+        CL_ASSERT( status == CL_SUCCESS );
+
+        /*
+         * Increment the reader count to block a thread trying for exclusive
+         * access.
+         */
+        cl_atomic_inc( &p_lock->reader_count );
+#ifdef DBG_PASSIVE_LOCKS
+        cl_dbg_out( "cl_plock_acquire: ReaderCount = %u\n",
+                p_lock->reader_count );
+#endif
+        /*
+         * Release the reader event to satisfy the wait of another reader
+         * or a writer.
+         */
+        cl_event_signal( &p_lock->reader_event );
+}
+
+

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
+
+
+
+ +

[Functions] +Component Library: Passive Lock/cl_plock_construct

+ +

[top][index]

+

NAME

+
       cl_plock_construct
+
+

DESCRIPTION

+
       The cl_plock_construct function initializes the state of a
+       passive lock.
+
+

SYNOPSIS

+
CL_INLINE void CL_API
+cl_plock_construct(
+        IN      cl_plock_t* const       p_lock )
+{
+        CL_ASSERT( p_lock );
+
+        p_lock->reader_count = 0;
+        cl_event_construct( &p_lock->reader_event );
+        cl_event_construct( &p_lock->writer_event );
+}
+
+

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
+
+
+
+ +

[Functions] +Component Library: Passive Lock/cl_plock_destroy

+ +

[top][index]

+

NAME

+
       cl_plock_destroy
+
+

DESCRIPTION

+
       The cl_plock_destroy function performs any necessary cleanup
+       of a passive lock.
+
+

SYNOPSIS

+
CL_INLINE void CL_API
+cl_plock_destroy(
+        IN      cl_plock_t* const       p_lock )
+{
+        CL_ASSERT( p_lock );
+        CL_ASSERT( p_lock->reader_count == 0 );
+
+        cl_event_destroy( &p_lock->writer_event );
+        cl_event_destroy( &p_lock->reader_event );
+}
+
+

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
+
+
+
+ +

[Functions] +Component Library: Passive Lock/cl_plock_excl_acquire

+ +

[top][index]

+

NAME

+
       cl_plock_excl_acquire
+
+

DESCRIPTION

+
       The cl_plock_excl_acquire function acquires exclusive access
+       to a passive lock.
+
+

SYNOPSIS

+
CL_INLINE void CL_API
+cl_plock_excl_acquire(
+        IN      cl_plock_t* const       p_lock )
+{
+        cl_status_t     status;
+
+        CL_ASSERT( p_lock );
+
+        /* Acquire the reader event.  This will block new readers. */
+        status =
+                cl_event_wait_on( &p_lock->reader_event, EVENT_NO_TIMEOUT, FALSE );
+        CL_ASSERT( status == CL_SUCCESS );
+
+        /* Wait for the writer event until all readers have exited. */
+        while( p_lock->reader_count )
+        {
+#ifdef DBG_PASSIVE_LOCKS
+                cl_dbg_out( "cl_plock_excl_acquire: ReaderCount = %u\n",
+                        p_lock->reader_count );
+#endif
+                status =
+                        cl_event_wait_on( &p_lock->writer_event, EVENT_NO_TIMEOUT, FALSE );
+                CL_ASSERT( status == CL_SUCCESS );
+        }
+
+#ifdef DBG_PASSIVE_LOCKS
+        cl_dbg_out( "cl_plock_excl_acquire: Exit\n" );
+#endif
+}
+
+

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
+
+
+
+ +

[Functions] +Component Library: Passive Lock/cl_plock_init

+ +

[top][index]

+

NAME

+
       cl_plock_init
+
+

DESCRIPTION

+
       The cl_plock_init function initializes a passive lock.
+
+

SYNOPSIS

+
CL_INLINE cl_status_t CL_API
+cl_plock_init(
+        IN      cl_plock_t* const       p_lock )
+{
+        cl_status_t     status;
+
+        CL_ASSERT( p_lock );
+
+        cl_plock_construct( p_lock );
+
+        status = cl_event_init( &p_lock->writer_event, FALSE );
+        if( status != CL_SUCCESS )
+        {
+                cl_plock_destroy( p_lock );
+                return( status );
+        }
+
+        status = cl_event_init( &p_lock->reader_event, FALSE );
+        if( status != CL_SUCCESS )
+        {
+                cl_plock_destroy( p_lock );
+                return( status );
+        }
+
+        /*
+         * Set the writer event to signalled so that the first
+         * wait operation succeeds.
+         */
+        status = cl_event_signal( &p_lock->writer_event );
+        if( status != CL_SUCCESS )
+        {
+                cl_plock_destroy( p_lock );
+                return( status );
+        }
+
+        /*
+         * Set the reader event to signalled so that the first
+         * wait operation succeeds.
+         */
+        status = cl_event_signal( &p_lock->reader_event );
+        if( status != CL_SUCCESS )
+        {
+                cl_plock_destroy( p_lock );
+                return( status );
+        }
+
+        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, and cl_plock_excl_release.
+
+

SEE ALSO

+
       Passive Lock, cl_plock_construct, cl_plock_destroy,
+       cl_plock_excl_acquire, cl_plock_excl_release,
+       cl_plock_acquire, cl_plock_release
+
+
+
+ +

[Functions] +Component Library: Passive Lock/cl_plock_release

+ +

[top][index]

+

NAME

+
       cl_plock_release
+
+

DESCRIPTION

+
       The cl_plock_release function releases a passive lock from
+       shared or exclusive access.
+
+

SYNOPSIS

+
CL_INLINE void CL_API
+cl_plock_release(
+        IN      cl_plock_t* const       p_lock )
+{
+        CL_ASSERT( p_lock );
+
+        if( p_lock->reader_count )
+        {
+
+                /*
+                 * Decrement the count to allow a thread waiting for exclusive
+                 * access to continue.
+                 */
+                cl_atomic_dec( &p_lock->reader_count );
+
+                #ifdef DBG_PASSIVE_LOCKS
+                        cl_dbg_out( "cl_plock_release: ReaderCount = %u\n",
+                                p_lock->reader_count );
+                #endif
+
+                /* Release a writer, if any. */
+                cl_event_signal( &p_lock->writer_event );
+        }
+        else
+        {
+                /* Release threads waiting to acquire the lock. */
+                cl_event_signal( &p_lock->reader_event );
+                cl_event_signal( &p_lock->writer_event );
+
+                #ifdef DBG_PASSIVE_LOCKS
+                        cl_dbg_out( "cl_plock_release: Exit\n" );
+                #endif
+        }
+}
+
+

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
+
+
+
+ +

[Structures] +Component Library: Passive Lock/cl_plock_t

+ +

[top][index]

+

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
+{
+        cl_event_t              reader_event;
+        cl_event_t              writer_event;
+        atomic32_t              reader_count;
+
+} cl_plock_t;
+
+

FIELDS

+
       reader_event
+               Event used to synchronize shared access to the lock.
+
+       writer_event
+               Event used to synchronize exclusive access to the lock.
+
+       reader_count
+               Number of threads holding the lock for shared access.
+
+

SEE ALSO

+
       Passive Lock
+
+
+ + diff --git a/branches/WOF2-3/docs/complib/cl_perf_h.html b/branches/WOF2-3/docs/complib/cl_perf_h.html new file mode 100644 index 00000000..df5184f7 --- /dev/null +++ b/branches/WOF2-3/docs/complib/cl_perf_h.html @@ -0,0 +1,583 @@ + + + + +./inc_docs/complib/cl_perf_h.html + + + + +Generated from ./inc/complib/cl_perf.h with ROBODoc v4.99.17 on Sun Mar 04 2007 18:17:51 +
+
+ +

[Modules] +Component Library/Performance Counters

+ +

[top][parent][index]

+

NAME

+
       Performance Counters
+
+

DESCRIPTION

+
       The performance counters allows timing operations to benchmark
+       software performance and help identify potential bottlenecks.
+
+       All performance counters are NULL macros when disabled, preventing them
+       from adversly affecting performance in builds where the counters are not
+       used.
+
+       Each counter records elapsed time in micro-seconds, minimum time elapsed,
+       and total number of samples.
+
+       Each counter is independently protected by a spinlock, allowing use of
+       the counters in multi-processor environments.
+
+       The impact of serializing access to performance counters is measured,
+       allowing measurements to be corrected as necessary.
+
+

NOTES

+
       Performance counters do impact performance, and should only be enabled
+       when gathering data.  Counters can be enabled or disabled on a per-user
+       basis at compile time.  To enable the counters, users should define
+       the PERF_TRACK_ON keyword before including the cl_perf.h file.
+       Undefining the PERF_TRACK_ON keyword disables the performance counters.
+       When disabled, all performance tracking calls resolve to no-ops.
+
+       When using performance counters, it is the user's responsibility to
+       maintain the counter indexes.  It is recomended that users define an
+       enumerated type to use for counter indexes.  It improves readability
+       and simplifies maintenance by reducing the work necessary in managing
+       the counter indexes.
+
+

SEE ALSO

+
       Structures:
+               cl_perf_t
+
+       Initialization:
+               cl_perf_construct, cl_perf_init, cl_perf_destroy
+
+       Manipulation
+               cl_perf_reset, cl_perf_display, cl_perf_start, cl_perf_update,
+               cl_perf_log, cl_perf_stop
+
+       Macros:
+               PERF_DECLARE, PERF_DECLARE_START
+
+
+
+ +

[Definitions] +Component Library: Performance Counters/cl_perf_clr

+ +

[top][index]

+

NAME

+
       cl_perf_clr
+
+

DESCRIPTION

+
       The cl_perf_clr macro clears a counter variable.
+
+

SYNOPSIS

+
void
+cl_perf_inc(
+        IN      const uintn_t index );
+
+

PARAMETERS

+
       index
+               [in] Index of the performance counter to set.
+
+

NOTES

+
       This macro has no effect when performance counters are disabled.
+
+

SEE ALSO

+
       Performance Counters, PERF_DECLARE, PERF_DECLARE_START, cl_perf_log,
+       cl_perf_update, cl_perf_stop
+
+
+
+ +

[Functions] +Component Library: Performance Counters/cl_perf_construct

+ +

[top][index]

+

NAME

+
       cl_perf_construct
+
+

DESCRIPTION

+
       The cl_perf_construct macro constructs a performance
+       tracking container.
+
+

SYNOPSIS

+
void
+cl_perf_construct(
+        IN      cl_perf_t* const        p_perf );
+
+

PARAMETERS

+
       p_perf
+               [in] Pointer to a performance counter container to construct.
+
+

RETURN VALUE

+
       This function does not return a value.
+
+

NOTES

+
       cl_perf_construct allows calling cl_perf_destroy without first calling
+       cl_perf_init.
+
+       Calling cl_perf_construct is a prerequisite to calling any other
+       perfromance counter function except cl_perf_init.
+
+       This function is implemented as a macro and has no effect when
+       performance counters are disabled.
+
+

SEE ALSO

+
       Performance Counters, cl_perf_init, cl_perf_destroy
+
+
+
+ +

[Functions] +Component Library: Performance Counters/cl_perf_destroy

+ +

[top][index]

+

NAME

+
       cl_perf_destroy
+
+

DESCRIPTION

+
       The cl_perf_destroy function destroys a performance tracking container.
+
+

SYNOPSIS

+
void
+cl_perf_destroy(
+        IN      cl_perf_t* const        p_perf,
+        IN      const boolean_t         display );
+
+

PARAMETERS

+
       p_perf
+               [in] Pointer to a performance counter container to destroy.
+
+       display
+               [in] If TRUE, causes the performance counters to be displayed.
+
+

RETURN VALUE

+
       This function does not return a value.
+
+

NOTES

+
       cl_perf_destroy frees all resources allocated in a call to cl_perf_init.
+       If the display parameter is set to TRUE, displays all counter values
+       before deallocating resources.
+
+       This function should only be called after a call to cl_perf_construct
+       or cl_perf_init.
+
+       This function is implemented as a macro and has no effect when
+       performance counters are disabled.
+
+

SEE ALSO

+
       Performance Counters, cl_perf_construct, cl_perf_init
+
+
+
+ +

[Functions] +Component Library: Performance Counters/cl_perf_display

+ +

[top][index]

+

NAME

+
       cl_perf_display
+
+

DESCRIPTION

+
       The cl_perf_display function displays the current performance
+       counter values.
+
+

SYNOPSIS

+
void
+cl_perf_display(
+        IN      const cl_perf_t* const  p_perf );
+
+

PARAMETERS

+
       p_perf
+               [in] Pointer to a performance counter container whose counter
+               values to display.
+
+

RETURN VALUE

+
       This function does not return a value.
+
+

NOTES

+
       This function is implemented as a macro and has no effect when
+       performance counters are disabled.
+
+

SEE ALSO

+
       Performance Counters, cl_perf_init
+
+
+
+ +

[Definitions] +Component Library: Performance Counters/cl_perf_inc

+ +

[top][index]

+

NAME

+
       cl_perf_inc
+
+

DESCRIPTION

+
       The cl_perf_inc macro increments a counter variable by one.
+
+

SYNOPSIS

+
void
+cl_perf_inc(
+        IN      const uintn_t index );
+
+

PARAMETERS

+
       index
+               [in] Index of the performance counter to set.
+
+

NOTES

+
       This macro has no effect when performance counters are disabled.
+
+

SEE ALSO

+
       Performance Counters, PERF_DECLARE, PERF_DECLARE_START, cl_perf_log,
+       cl_perf_update, cl_perf_stop
+
+
+
+ +

[Functions] +Component Library: Performance Counters/cl_perf_init

+ +

[top][index]

+

NAME

+
       cl_perf_init
+
+

DESCRIPTION

+
       The cl_perf_init function initializes a performance counter container
+       for use.
+
+

SYNOPSIS

+
cl_status_t
+cl_perf_init(
+        IN      cl_perf_t* const        p_perf,
+        IN      const uintn_t           num_counters );
+
+

PARAMETERS

+
       p_perf
+               [in] Pointer to a performance counter container to initalize.
+
+       num_cntrs
+               [in] Number of counters to allocate in the container.
+
+ RETURN VALUES
+       CL_SUCCESS if initialization was successful.
+
+       CL_INSUFFICIENT_MEMORY if there was not enough memory to initialize
+       the container.
+
+       CL_ERROR if an error was encountered initializing the locks for the
+       performance counters.
+
+

NOTES

+
       This function allocates all memory required for the requested number of
+       counters and initializes all locks protecting those counters.  After a
+       successful initialization, cl_perf_init calibrates the counters and
+       resets their value.
+
+       This function is implemented as a macro and has no effect when
+       performance counters are disabled.
+
+

SEE ALSO

+
       Performance Counters, cl_perf_construct, cl_perf_destroy, cl_perf_display
+
+
+
+ +

[Definitions] +Component Library: Performance Counters/cl_perf_log

+ +

[top][index]

+

NAME

+
       cl_perf_log
+
+

DESCRIPTION

+
       The cl_perf_log macro adds a given timing sample to a
+       counter in a performance counter container.
+
+

SYNOPSIS

+
void
+cl_perf_log(
+        IN      cl_perf_t* const        p_perf,
+        IN      const uintn_t           index,
+        IN      const uint64_t          pc_total_time );
+
+

PARAMETERS

+
       p_perf
+               [in] Pointer to a performance counter container to whose counter
+               the sample should be added.
+
+       index
+               [in] Number of the performance counter to update with a new sample.
+
+       pc_total_time
+               [in] Total elapsed time for the sample being added.
+
+

RETURN VALUE

+
       This function does not return a value.
+
+

NOTES

+
       This macro has no effect when performance counters are disabled.
+
+

SEE ALSO

+
       Performance Counters, PERF_DECLARE, PERF_DECLARE_START, cl_perf_start,
+       cl_perf_update, cl_perf_stop
+
+
+
+ +

[Functions] +Component Library: Performance Counters/cl_perf_reset

+ +

[top][index]

+

NAME

+
       cl_perf_reset
+
+

DESCRIPTION

+
       The cl_perf_reset function resets the counters contained in
+       a performance tracking container.
+
+

SYNOPSIS

+
void
+cl_perf_reset(
+        IN      cl_perf_t* const        p_perf );
+
+

PARAMETERS

+
       p_perf
+               [in] Pointer to a performance counter container whose counters
+               to reset.
+
+

RETURN VALUE

+
       This function does not return a value.
+
+

NOTES

+
       This function is implemented as a macro and has no effect when
+       performance counters are disabled.
+
+

SEE ALSO

+
       Performance Counters
+
+
+
+ +

[Definitions] +Component Library: Performance Counters/cl_perf_start

+ +

[top][index]

+

NAME

+
       cl_perf_start
+
+

DESCRIPTION

+
       The cl_perf_start macro sets the starting value of a timed sequence.
+
+

SYNOPSIS

+
void
+cl_perf_start(
+        IN      const uintn_t index );
+
+

PARAMETERS

+
       index
+               [in] Index of the performance counter to set.
+
+

NOTES

+
       This macro has no effect when performance counters are disabled.
+
+

SEE ALSO

+
       Performance Counters, PERF_DECLARE, PERF_DECLARE_START, cl_perf_log,
+       cl_perf_update, cl_perf_stop
+
+
+
+ +

[Definitions] +Component Library: Performance Counters/cl_perf_stop

+ +

[top][index]

+

NAME

+
       cl_perf_stop
+
+

DESCRIPTION

+
       The cl_perf_log macro updates a counter in a performance counter
+       container with a new timing sample.
+
+

SYNOPSIS

+
void
+cl_perf_stop(
+        IN      cl_perf_t* const        p_perf,
+        IN      const uintn_t           index );
+
+

PARAMETERS

+
       p_perf
+               [in] Pointer to a performance counter container to whose counter
+               a sample should be added.
+
+       index
+               [in] Number of the performance counter to update with a new sample.
+
+

RETURN VALUE

+
       This function does not return a value.
+
+

NOTES

+
       The ending time stamp is taken and elapsed time calculated before updating
+       the specified counter.
+
+       This macro has no effect when performance counters are disabled.
+
+

SEE ALSO

+
       Performance Counters, PERF_DECLARE, PERF_DECLARE_START, cl_perf_start,
+       cl_perf_log
+
+
+
+ +

[Definitions] +Component Library: Performance Counters/cl_perf_update

+ +

[top][index]

+

NAME

+
       cl_perf_update
+
+

DESCRIPTION

+
       The cl_perf_update macro adds a timing sample based on a provided start
+       time to a counter in a performance counter container.
+
+

SYNOPSIS

+
void
+cl_perf_update(
+        IN      cl_perf_t* const        p_perf,
+        IN      const uintn_t           index,
+        IN      const uint64_t          start_time );
+
+

PARAMETERS

+
       p_perf
+               [in] Pointer to a performance counter container to whose counter
+               the sample should be added.
+
+       index
+               [in] Number of the performance counter to update with a new sample.
+
+       start_time
+               [in] Timestamp to use as the start time for the timing sample.
+
+

RETURN VALUE

+
       This function does not return a value.
+
+

NOTES

+
       This macro has no effect when performance counters are disabled.
+
+

SEE ALSO

+
       Performance Counters, PERF_DECLARE, PERF_DECLARE_START, cl_perf_start,
+       cl_perf_lob, cl_perf_stop
+
+
+
+ +

[Definitions] +Component Library: Performance Counters/cl_perf_update_ctr

+ +

[top][index]

+

NAME

+
       cl_perf_update_ctr
+
+

DESCRIPTION

+
       The cl_perf_update_ctr macro updates a counter in a performance
+       counter container.
+
+

SYNOPSIS

+
void
+cl_perf_update_ctr(
+        IN      cl_perf_t* const        p_perf,
+        IN      const uintn_t           index );
+
+

PARAMETERS

+
       p_perf
+               [in] Pointer to a performance counter container to whose counter
+               the sample should be added.
+
+       index
+               [in] Number of the performance counter to update with a new sample.
+
+

RETURN VALUE

+
       This function does not return a value.
+
+

NOTES

+
       This macro has no effect when performance counters are disabled.
+
+

SEE ALSO

+
       Performance Counters, PERF_DECLARE, PERF_DECLARE_START, cl_perf_start,
+       cl_perf_lob, cl_perf_stop
+
+
+
+ +

[Definitions] +Component Library: Performance Counters/PERF_DECLARE

+ +

[top][index]

+

NAME

+
       PERF_DECLARE
+
+

DESCRIPTION

+
       The PERF_DECLARE macro declares a performance counter variable used
+       to store the starting time of a timing sequence.
+
+

SYNOPSIS

+
*       PERF_DECLARE( index )
+
+

PARAMETERS

+
       index
+               [in] Index of the performance counter for which to use this
+               variable.
+
+

NOTES

+
       Variables should generally be declared on the stack to support
+       multi-threading.  In cases where a counter needs to be used to
+       time operations accross multiple functions, care must be taken to
+       ensure that the start time stored in this variable is not overwritten
+       before the related performance counter has been updated.
+
+       This macro has no effect when performance counters are disabled.
+
+

SEE ALSO

+
       Performance Counters, PERF_DECLARE_START, cl_perf_start, cl_perf_log,
+       cl_perf_stop
+
+
+
+ +

[Definitions] +Component Library: Performance Counters/PERF_DECLARE_START

+ +

[top][index]

+

NAME

+
       PERF_DECLARE_START
+
+

DESCRIPTION

+
       The PERF_DECLARE_START macro declares a performance counter variable
+       and sets it to the starting time of a timed sequence.
+
+

SYNOPSIS

+
*       PERF_DECLARE_START( index )
+
+

PARAMETERS

+
       index
+               [in] Index of the performance counter for which to use this
+               variable.
+
+

NOTES

+
       Variables should generally be declared on the stack to support
+       multi-threading.
+
+       This macro has no effect when performance counters are disabled.
+
+

SEE ALSO

+
       Performance Counters, PERF_DECLARE, cl_perf_start, cl_perf_log,
+       cl_perf_stop
+
+
+ + diff --git a/branches/WOF2-3/docs/complib/cl_pool_h.html b/branches/WOF2-3/docs/complib/cl_pool_h.html new file mode 100644 index 00000000..8502b831 --- /dev/null +++ b/branches/WOF2-3/docs/complib/cl_pool_h.html @@ -0,0 +1,581 @@ + + + + +./inc_docs/complib/cl_pool_h.html + + + + +Generated from ./inc/complib/cl_pool.h with ROBODoc v4.99.17 on Sun Mar 04 2007 18:17:51 +
+
+ +

[Modules] +Component Library/Pool

+ +

[top][parent][index]

+

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
+
+
+
+ +

[Functions] +Component Library: Pool/cl_is_pool_inited

+ +

[top][index]

+

NAME

+
       cl_is_pool_inited
+
+

DESCRIPTION

+
       The cl_is_pool_inited function returns whether a pool was successfully
+       initialized.
+
+

SYNOPSIS

+
CL_INLINE uint32_t CL_API
+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
+
+
+
+ +

[Definitions] +Component Library: Pool/cl_pfn_pool_dtor_t

+ +

[top][index]

+

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_API *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
+
+
+
+ +

[Definitions] +Component Library: Pool/cl_pfn_pool_init_t

+ +

[top][index]

+

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_API *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
+
+
+
+ +

[Functions] +Component Library: Pool/cl_pool_construct

+ +

[top][index]

+

NAME

+
       cl_pool_construct
+
+

DESCRIPTION

+
       The cl_pool_construct function constructs a pool.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Pool/cl_pool_count

+ +

[top][index]

+

NAME

+
       cl_pool_count
+
+

DESCRIPTION

+
       The cl_pool_count function returns the number of available objects
+       in a pool.
+
+

SYNOPSIS

+
CL_INLINE size_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Pool/cl_pool_destroy

+ +

[top][index]

+

NAME

+
       cl_pool_destroy
+
+

DESCRIPTION

+
       The cl_pool_destroy function destroys a pool.
+
+

SYNOPSIS

+
CL_INLINE void CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Pool/cl_pool_get

+ +

[top][index]

+

NAME

+
       cl_pool_get
+
+

DESCRIPTION

+
       The cl_pool_get function retrieves an object from a pool.
+
+

SYNOPSIS

+
CL_INLINE void* CL_API
+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->list_obj.p_object );
+        return( (void*)p_pool_obj->list_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
+
+
+
+ +

[Functions] +Component Library: Pool/cl_pool_grow

+ +

[top][index]

+

NAME

+
       cl_pool_grow
+
+

DESCRIPTION

+
       The cl_pool_grow function grows a pool by
+       the specified number of objects.
+
+

SYNOPSIS

+
CL_INLINE cl_status_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Pool/cl_pool_init

+ +

[top][index]

+

NAME

+
       cl_pool_init
+
+

DESCRIPTION

+
       The cl_pool_init function initializes a pool for use.
+
+

SYNOPSIS

+
CL_EXPORT cl_status_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Pool/cl_pool_put

+ +

[top][index]

+

NAME

+
       cl_pool_put
+
+

DESCRIPTION

+
       The cl_pool_put function returns an object to a pool.
+
+

SYNOPSIS

+
CL_INLINE void CL_API
+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->list_obj.p_object == p_object );
+
+        cl_qcpool_put( &p_pool->qcpool, (cl_pool_item_t*)p_pool_obj );
+}
+
+

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
+
+
+
+ +

[Structures] +Component Library: Pool/cl_pool_t

+ +

[top][index]

+

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
+
+
+ + diff --git a/branches/WOF2-3/docs/complib/cl_ptr_vector_h.html b/branches/WOF2-3/docs/complib/cl_ptr_vector_h.html new file mode 100644 index 00000000..f9419dc2 --- /dev/null +++ b/branches/WOF2-3/docs/complib/cl_ptr_vector_h.html @@ -0,0 +1,890 @@ + + + + +./inc_docs/complib/cl_ptr_vector_h.html + + + + +Generated from ./inc/complib/cl_ptr_vector.h with ROBODoc v4.99.17 on Sun Mar 04 2007 18:17:51 +
+
+ +

[Modules] +Component Library/Pointer Vector

+ +

[top][parent][index]

+

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_obj, 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
+
+
+
+ +

[Definitions] +Component Library: Pointer Vector/cl_pfn_ptr_vec_apply_t

+ +

[top][index]

+

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_API *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
+
+
+
+ +

[Definitions] +Component Library: Pointer Vector/cl_pfn_ptr_vec_find_t

+ +

[top][index]

+

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_API *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
+
+
+
+ +

[Functions] +Component Library: Pointer Vector/cl_ptr_vector_apply_func

+ +

[top][index]

+

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

+
CL_EXPORT void CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Pointer Vector/cl_ptr_vector_at

+ +

[top][index]

+

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_EXPORT cl_status_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Pointer Vector/cl_ptr_vector_construct

+ +

[top][index]

+

NAME

+
       cl_ptr_vector_construct
+
+

DESCRIPTION

+
       The cl_ptr_vector_construct function constructs a pointer vector.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Pointer Vector/cl_ptr_vector_destroy

+ +

[top][index]

+

NAME

+
       cl_ptr_vector_destroy
+
+

DESCRIPTION

+
       The cl_ptr_vector_destroy function destroys a pointer vector.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Pointer Vector/cl_ptr_vector_find_from_end

+ +

[top][index]

+

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

+
CL_EXPORT size_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Pointer Vector/cl_ptr_vector_find_from_start

+ +

[top][index]

+

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

+
CL_EXPORT size_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Pointer Vector/cl_ptr_vector_get

+ +

[top][index]

+

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

+
CL_INLINE void* CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Pointer Vector/cl_ptr_vector_get_capacity

+ +

[top][index]

+

NAME

+
       cl_ptr_vector_get_capacity
+
+

DESCRIPTION

+
       The cl_ptr_vector_get_capacity function returns the capacity of
+       a pointer vector.
+
+

SYNOPSIS

+
CL_INLINE size_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Pointer Vector/cl_ptr_vector_get_size

+ +

[top][index]

+

NAME

+
       cl_ptr_vector_get_size
+
+

DESCRIPTION

+
       The cl_ptr_vector_get_size function returns the size of a pointer vector.
+
+

SYNOPSIS

+
CL_INLINE size_t CL_API
+cl_ptr_vector_get_size(
+        IN      const cl_ptr_vector_t* const    p_vector )
+{
+        CL_ASSERT( p_vector );
+        CL_ASSERT( p_vector->state == CL_UNINITIALIZED ||
+                p_vector->state == CL_INITIALIZED );
+
+        return( 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
+
+
+
+ +

[Functions] +Component Library: Pointer Vector/cl_ptr_vector_init

+ +

[top][index]

+

NAME

+
       cl_ptr_vector_init
+
+

DESCRIPTION

+
       The cl_ptr_vector_init function initializes a pointer vector for use.
+
+

SYNOPSIS

+
CL_EXPORT cl_status_t CL_API
+cl_ptr_vector_init(
+        IN      cl_ptr_vector_t* const  p_vector,
+        IN      const size_t                    min_cap,
+        IN      const size_t                    grow_size );
+
+

PARAMETERS

+
       p_vector
+               [in] Pointer to a cl_ptr_vector_t structure to inititalize.
+
+       min_cap
+               [in] Initial number of elements the vector will support.
+               The vector is always initialized with a size of zero.
+
+       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
+
+
+
+ +

[Functions] +Component Library: Pointer Vector/cl_ptr_vector_insert

+ +

[top][index]

+

NAME

+
       cl_ptr_vector_insert
+
+

DESCRIPTION

+
       The cl_ptr_vector_insert function inserts an element into a pointer vector.
+
+

SYNOPSIS

+
CL_INLINE cl_status_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Pointer Vector/cl_ptr_vector_remove

+ +

[top][index]

+

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

+
CL_EXPORT void* CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Pointer Vector/cl_ptr_vector_set

+ +

[top][index]

+

NAME

+
       cl_ptr_vector_set
+
+

DESCRIPTION

+
       The cl_ptr_vector_set function sets the element at the specified index.
+
+

SYNOPSIS

+
CL_EXPORT cl_status_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Pointer Vector/cl_ptr_vector_set_capacity

+ +

[top][index]

+

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_EXPORT cl_status_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Pointer Vector/cl_ptr_vector_set_min_size

+ +

[top][index]

+

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_EXPORT cl_status_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Pointer Vector/cl_ptr_vector_set_size

+ +

[top][index]

+

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_EXPORT cl_status_t CL_API
+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
+
+
+
+ +

[Structures] +Component Library: Pointer Vector/cl_ptr_vector_t

+ +

[top][index]

+

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
+
+
+ + diff --git a/branches/WOF2-3/docs/complib/cl_qcomppool_h.html b/branches/WOF2-3/docs/complib/cl_qcomppool_h.html new file mode 100644 index 00000000..a89206ab --- /dev/null +++ b/branches/WOF2-3/docs/complib/cl_qcomppool_h.html @@ -0,0 +1,740 @@ + + + + +./inc_docs/complib/cl_qcomppool_h.html + + + + +Generated from ./inc/complib/cl_qcomppool.h with ROBODoc v4.99.17 on Sun Mar 04 2007 18:17:51 +
+
+ +

[Modules] +Component Library/Quick Composite Pool

+ +

[top][parent][index]

+

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
+
+
+
+ +

[Functions] +Component Library: Quick Composite Pool/cl_is_qcpool_inited

+ +

[top][index]

+

NAME

+
       cl_is_qcpool_inited
+
+

DESCRIPTION

+
       The cl_is_qcpool_inited function returns whether a quick composite pool was
+       successfully initialized.
+
+

SYNOPSIS

+
CL_INLINE uint32_t CL_API
+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
+
+
+
+ +

[Definitions] +Component Library: Quick Composite Pool/cl_pfn_qcpool_dtor_t

+ +

[top][index]

+

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_API *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
+
+
+
+ +

[Definitions] +Component Library: Quick Composite Pool/cl_pfn_qcpool_init_t

+ +

[top][index]

+

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_API *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
+
+
+
+ +

[Structures] +Component Library: Quick Composite Pool/cl_pool_item_t

+ +

[top][index]

+

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_
+        /* Pad to make the cl_pool_obj structure line up properly */
+        void                            *pad;
+        /* 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
+
+
+
+ +

[Functions] +Component Library: Quick Composite Pool/cl_qcpool_construct

+ +

[top][index]

+

NAME

+
       cl_qcpool_construct
+
+

DESCRIPTION

+
       The cl_qcpool_construct function constructs a quick composite pool.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Quick Composite Pool/cl_qcpool_count

+ +

[top][index]

+

NAME

+
       cl_qcpool_count
+
+

DESCRIPTION

+
       The cl_qcpool_count function returns the number of available objects
+       in a quick composite pool.
+
+

SYNOPSIS

+
CL_INLINE size_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Quick Composite Pool/cl_qcpool_destroy

+ +

[top][index]

+

NAME

+
       cl_qcpool_destroy
+
+

DESCRIPTION

+
       The cl_qcpool_destroy function destroys a quick composite pool.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Quick Composite Pool/cl_qcpool_get

+ +

[top][index]

+

NAME

+
       cl_qcpool_get
+
+

DESCRIPTION

+
       The cl_qcpool_get function retrieves an object from a
+       quick composite pool.
+
+

SYNOPSIS

+
CL_EXPORT cl_pool_item_t* CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Quick Composite Pool/cl_qcpool_grow

+ +

[top][index]

+

NAME

+
       cl_qcpool_grow
+
+

DESCRIPTION

+
       The cl_qcpool_grow function grows a quick composite pool by
+       the specified number of objects.
+
+

SYNOPSIS

+
CL_EXPORT cl_status_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Quick Composite Pool/cl_qcpool_init

+ +

[top][index]

+

NAME

+
       cl_qcpool_init
+
+

DESCRIPTION

+
       The cl_qcpool_init function initializes a quick composite pool for use.
+
+

SYNOPSIS

+
CL_EXPORT cl_status_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Quick Composite Pool/cl_qcpool_put

+ +

[top][index]

+

NAME

+
       cl_qcpool_put
+
+

DESCRIPTION

+
       The cl_qcpool_put function returns an object to a quick composite pool.
+
+

SYNOPSIS

+
CL_INLINE void CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Quick Composite Pool/cl_qcpool_put_list

+ +

[top][index]

+

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

+
CL_INLINE void CL_API
+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
+
+
+
+ +

[Structures] +Component Library: Quick Composite Pool/cl_qcpool_t

+ +

[top][index]

+

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
+
+
+ + diff --git a/branches/WOF2-3/docs/complib/cl_qlist_h.html b/branches/WOF2-3/docs/complib/cl_qlist_h.html new file mode 100644 index 00000000..e023b863 --- /dev/null +++ b/branches/WOF2-3/docs/complib/cl_qlist_h.html @@ -0,0 +1,1728 @@ + + + + +./inc_docs/complib/cl_qlist_h.html + + + + +Generated from ./inc/complib/cl_qlist.h with ROBODoc v4.99.17 on Sun Mar 04 2007 18:17:51 +
+
+ +

[Modules] +Component Library/Quick List

+ +

[top][parent][index]

+

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
+
+
+
+ +

[Functions] +Component Library: Quick List/cl_is_item_in_qlist

+ +

[top][index]

+

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

+
CL_EXPORT boolean_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Quick List/cl_is_qlist_empty

+ +

[top][index]

+

NAME

+
       cl_is_qlist_empty
+
+

DESCRIPTION

+
       The cl_is_qlist_empty function returns whether a quick list is empty.
+
+

SYNOPSIS

+
CL_INLINE boolean_t CL_API
+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
+
+
+
+ +

[Structures] +Component Library: Quick List/cl_list_item_t

+ +

[top][index]

+

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
+
+
+
+ +

[Structures] +Component Library: Quick List/cl_list_obj_t

+ +

[top][index]

+

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
+
+
+
+ +

[Definitions] +Component Library: Quick List/cl_pfn_qlist_apply_t

+ +

[top][index]

+

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_API *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
+
+
+
+ +

[Definitions] +Component Library: Quick List/cl_pfn_qlist_find_t

+ +

[top][index]

+

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_API *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
+
+
+
+ +

[Functions] +Component Library: Quick List/cl_qlist_apply_func

+ +

[top][index]

+

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

+
CL_EXPORT void CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Quick List/cl_qlist_count

+ +

[top][index]

+

NAME

+
       cl_qlist_count
+
+

DESCRIPTION

+
       The cl_qlist_count function returns the number of list items stored
+       in a quick list.
+
+

SYNOPSIS

+
CL_INLINE size_t CL_API
+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( 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
+
+
+
+ +

[Functions] +Component Library: Quick List/cl_qlist_end

+ +

[top][index]

+

NAME

+
       cl_qlist_end
+
+

DESCRIPTION

+
       The cl_qlist_end function returns the end of a quick list.
+
+

SYNOPSIS

+
CL_INLINE const cl_list_item_t* const CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Quick List/cl_qlist_find_from_head

+ +

[top][index]

+

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

+
CL_INLINE cl_list_item_t* CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Quick List/cl_qlist_find_from_tail

+ +

[top][index]

+

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

+
CL_INLINE cl_list_item_t* CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Quick List/cl_qlist_find_next

+ +

[top][index]

+

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_EXPORT cl_list_item_t* CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Quick List/cl_qlist_find_prev

+ +

[top][index]

+

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_EXPORT cl_list_item_t* CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Quick List/cl_qlist_head

+ +

[top][index]

+

NAME

+
       cl_qlist_head
+
+

DESCRIPTION

+
       The cl_qlist_head function returns the list item at
+       the head of a quick list.
+
+

SYNOPSIS

+
CL_INLINE cl_list_item_t* CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Quick List/cl_qlist_init

+ +

[top][index]

+

NAME

+
       cl_qlist_init
+
+

DESCRIPTION

+
       The cl_qlist_init function initializes a quick list.
+
+

SYNOPSIS

+
CL_INLINE void CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Quick List/cl_qlist_insert_array_head

+ +

[top][index]

+

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

+
CL_EXPORT void CL_API
+cl_qlist_insert_array_head(
+        IN      cl_qlist_t* const               p_list,
+        IN      cl_list_item_t* const   p_array,
+        IN      size_t                                  item_count,
+        IN      const size_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
+
+
+
+ +

[Functions] +Component Library: Quick List/cl_qlist_insert_array_tail

+ +

[top][index]

+

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

+
CL_EXPORT void CL_API
+cl_qlist_insert_array_tail(
+        IN      cl_qlist_t* const               p_list,
+        IN      cl_list_item_t* const   p_array,
+        IN      size_t                                  item_count,
+        IN      const size_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
+
+
+
+ +

[Functions] +Component Library: Quick List/cl_qlist_insert_head

+ +

[top][index]

+

NAME

+
       cl_qlist_insert_head
+
+

DESCRIPTION

+
       The cl_qlist_insert_head function inserts a list item at the
+       head of a quick list.
+
+

SYNOPSIS

+
CL_INLINE void CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Quick List/cl_qlist_insert_list_head

+ +

[top][index]

+

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

+
CL_EXPORT void CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Quick List/cl_qlist_insert_list_tail

+ +

[top][index]

+

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

+
CL_EXPORT void CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Quick List/cl_qlist_insert_next

+ +

[top][index]

+

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

+
CL_INLINE void CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Quick List/cl_qlist_insert_prev

+ +

[top][index]

+

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

+
CL_INLINE void CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Quick List/cl_qlist_insert_tail

+ +

[top][index]

+

NAME

+
       cl_qlist_insert_tail
+
+

DESCRIPTION

+
       The cl_qlist_insert_tail function inserts a list item at the tail
+       of a quick list.
+
+

SYNOPSIS

+
CL_INLINE void CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Quick List/cl_qlist_move_items

+ +

[top][index]

+

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

+
CL_EXPORT void CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Quick List/cl_qlist_next

+ +

[top][index]

+

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

+
CL_INLINE cl_list_item_t* CL_API
+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 );
+
+        /* 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
+
+
+
+ +

[Functions] +Component Library: Quick List/cl_qlist_obj

+ +

[top][index]

+

NAME

+
       cl_qlist_obj
+
+

DESCRIPTION

+
       The cl_qlist_set_obj function returns the object stored in a list object.
+
+

SYNOPSIS

+
CL_INLINE void* CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Quick List/cl_qlist_prev

+ +

[top][index]

+

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

+
CL_INLINE cl_list_item_t* CL_API
+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 );
+
+        /* 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
+
+
+
+ +

[Functions] +Component Library: Quick List/cl_qlist_remove_all

+ +

[top][index]

+

NAME

+
       cl_qlist_remove_all
+
+

DESCRIPTION

+
       The cl_qlist_remove_all function removes all items from a quick list.
+
+

SYNOPSIS

+
CL_INLINE void CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Quick List/cl_qlist_remove_head

+ +

[top][index]

+

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

+
CL_INLINE cl_list_item_t* CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Quick List/cl_qlist_remove_item

+ +

[top][index]

+

NAME

+
       cl_qlist_remove_item
+
+

DESCRIPTION

+
       The cl_qlist_remove_item function removes a specific list item from a quick list.
+
+

SYNOPSIS

+
CL_INLINE void CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Quick List/cl_qlist_remove_tail

+ +

[top][index]

+

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

+
CL_INLINE cl_list_item_t* CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Quick List/cl_qlist_set_obj

+ +

[top][index]

+

NAME

+
       cl_qlist_set_obj
+
+

DESCRIPTION

+
       The cl_qlist_set_obj function sets the object stored in a list object.
+
+

SYNOPSIS

+
CL_INLINE void CL_API
+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
+
+
+
+ +

[Structures] +Component Library: Quick List/cl_qlist_t

+ +

[top][index]

+

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
+
+
+
+ +

[Functions] +Component Library: Quick List/cl_qlist_tail

+ +

[top][index]

+

NAME

+
       cl_qlist_tail
+
+

DESCRIPTION

+
       The cl_qlist_tail function returns the list item at
+       the tail of a quick list.
+
+

SYNOPSIS

+
CL_INLINE cl_list_item_t* CL_API
+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
+
+
+ + diff --git a/branches/WOF2-3/docs/complib/cl_qlockpool_h.html b/branches/WOF2-3/docs/complib/cl_qlockpool_h.html new file mode 100644 index 00000000..f06edb61 --- /dev/null +++ b/branches/WOF2-3/docs/complib/cl_qlockpool_h.html @@ -0,0 +1,340 @@ + + + + +./inc_docs/complib/cl_qlockpool_h.html + + + + +Generated from ./inc/complib/cl_qlockpool.h with ROBODoc v4.99.17 on Sun Mar 04 2007 18:17:51 +
+
+ +

[Modules] +Component Library/Quick Locking Pool

+ +

[top][parent][index]

+

NAME

+
       Quick Locking Pool
+
+

DESCRIPTION

+
       The Quick Locking Pool represents a thread-safe quick pool.
+
+       This object should be treated as opaque and should be
+       manipulated only through the provided functions.
+
+

SEE ALSO

+
       Structures:
+               cl_qlock_pool_t
+
+       Initialization:
+               cl_qlock_pool_construct, cl_qlock_pool_init, cl_qlock_pool_destroy
+
+       Manipulation
+               cl_qlock_pool_get, cl_qlock_pool_put
+
+
+
+ +

[Functions] +Component Library: Quick Locking Pool/cl_qlock_pool_construct

+ +

[top][index]

+

NAME

+
       cl_qlock_pool_construct
+
+

DESCRIPTION

+
       This function constructs a Quick Locking Pool.
+
+

SYNOPSIS

+
static inline void
+cl_qlock_pool_construct(
+        IN cl_qlock_pool_t* const p_pool )
+{
+        cl_qpool_construct( &p_pool->pool );
+        cl_spinlock_construct( &p_pool->lock );
+}
+
+

PARAMETERS

+
       p_pool
+               [in] Pointer to a Quick Locking Pool to construct.
+
+

RETURN VALUE

+
       This function does not return a value.
+
+

NOTES

+
       Allows calling cl_qlock_pool_init, cl_qlock_pool_destroy
+
+       Calling cl_qlock_pool_construct is a prerequisite to calling any other
+       method except cl_qlock_pool_init.
+
+

SEE ALSO

+
       Quick Locking Pool, cl_qlock_pool_init, cl_qlock_pool_destroy
+
+
+
+ +

[Functions] +Component Library: Quick Locking Pool/cl_qlock_pool_destroy

+ +

[top][index]

+

NAME

+
       cl_qlock_pool_destroy
+
+

DESCRIPTION

+
       The cl_qlock_pool_destroy function destroys a node, releasing
+       all resources.
+
+

SYNOPSIS

+
static inline void
+cl_qlock_pool_destroy(
+        IN cl_qlock_pool_t* const p_pool )
+{
+        /*
+                If the pool has already been put into use, grab the lock
+                to sync with other threads before we blow everything away.
+        */
+        if( cl_is_qpool_inited( &p_pool->pool ) )
+        {
+                cl_spinlock_acquire( &p_pool->lock );
+                cl_qpool_destroy( &p_pool->pool );
+                cl_spinlock_release( &p_pool->lock );
+        }
+        else
+                cl_qpool_destroy( &p_pool->pool );
+
+        cl_spinlock_destroy( &p_pool->lock );
+}
+
+

PARAMETERS

+
       p_pool
+               [in] Pointer to a Quick Locking Pool to destroy.
+
+

RETURN VALUE

+
       This function does not return a value.
+
+

NOTES

+
       Performs any necessary cleanup of the specified Quick Locking Pool.
+       Further operations should not be attempted on the destroyed object.
+       This function should only be called after a call to
+       cl_qlock_pool_construct or cl_qlock_pool_init.
+
+

SEE ALSO

+
       Quick Locking Pool, cl_qlock_pool_construct, cl_qlock_pool_init
+
+
+
+ +

[Functions] +Component Library: Quick Locking Pool/cl_qlock_pool_get

+ +

[top][index]

+

NAME

+
       cl_qlock_pool_get
+
+

DESCRIPTION

+
       Gets an object wrapper and wire MAD from the pool.
+
+

SYNOPSIS

+
static inline cl_pool_item_t*
+cl_qlock_pool_get(
+        IN cl_qlock_pool_t* const p_pool )
+{
+        cl_pool_item_t* p_item;
+        cl_spinlock_acquire( &p_pool->lock );
+        p_item = cl_qpool_get( &p_pool->pool );
+        cl_spinlock_release( &p_pool->lock );
+        return( p_item );
+}
+
+

PARAMETERS

+
       p_pool
+               [in] Pointer to an cl_qlock_pool_t object.
+
+ RETURN VALUES
+       Returns a pointer to a cl_pool_item_t contained in the user object.
+
+

NOTES

+
       The object must eventually be returned to the pool with a call to
+       cl_qlock_pool_put.
+
+       The cl_qlock_pool_construct or cl_qlock_pool_init must be called before
+       using this function.
+
+

SEE ALSO

+
       Quick Locking Pool, cl_qlock_pool_put
+
+
+
+ +

[Functions] +Component Library: Quick Locking Pool/cl_qlock_pool_init

+ +

[top][index]

+

NAME

+
       cl_qlock_pool_init
+
+

DESCRIPTION

+
       The cl_qlock_pool_init function initializes a Quick Locking Pool for use.
+
+

SYNOPSIS

+
static inline cl_status_t
+cl_qlock_pool_init(
+        IN cl_qlock_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_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_qlock_pool_construct( p_pool );
+
+        status = cl_spinlock_init( &p_pool->lock );
+        if( status )
+                return( status );
+
+        status = cl_qpool_init( &p_pool->pool, min_size, max_size, grow_size,
+                        object_size, pfn_initializer, pfn_destructor, context );
+
+        return( status );
+}
+
+

PARAMETERS

+
       p_pool
+               [in] Pointer to an cl_qlock_pool_t object 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

+
       Allows calling other Quick Locking Pool methods.
+
+

SEE ALSO

+
       Quick Locking Pool, cl_qlock_pool_construct, cl_qlock_pool_destroy
+
+
+
+ +

[Functions] +Component Library: Quick Locking Pool/cl_qlock_pool_put

+ +

[top][index]

+

NAME

+
       cl_qlock_pool_put
+
+

DESCRIPTION

+
       Returns an object to the pool.
+
+

SYNOPSIS

+
static inline void
+cl_qlock_pool_put(
+        IN cl_qlock_pool_t* const p_pool,
+        IN cl_pool_item_t* const p_item )
+{
+        cl_spinlock_acquire( &p_pool->lock );
+        cl_qpool_put( &p_pool->pool, p_item );
+        cl_spinlock_release( &p_pool->lock );
+}
+
+

PARAMETERS

+
       p_pool
+               [in] Pointer to an cl_qlock_pool_t object.
+
+       p_item
+               [in] Pointer to the cl_pool_item_t in an object that was previously
+               retrieved from the pool.
+
+ RETURN VALUES
+       This function does not return a value.
+
+

NOTES

+
       The cl_qlock_pool_construct or cl_qlock_pool_init must be called before
+       using this function.
+
+

SEE ALSO

+
       Quick Locking Pool, cl_qlock_pool_get
+
+
+
+ +

[Structures] +Component Library: Quick Locking Pool/cl_qlock_pool_t

+ +

[top][index]

+

NAME

+
       cl_qlock_pool_t
+
+

DESCRIPTION

+
       Quick Locking Pool structure.
+
+       This object should be treated as opaque and should
+       be manipulated only through the provided functions.
+
+

SYNOPSIS

+
typedef struct _cl_qlock_pool
+{
+        cl_spinlock_t                           lock;
+        cl_qpool_t                                      pool;
+
+} cl_qlock_pool_t;
+
+

FIELDS

+
       lock
+               Spinlock guarding the pool.
+
+       pool
+               quick_pool of user objects.
+
+

SEE ALSO

+
       Quick Locking Pool
+
+
+ + diff --git a/branches/WOF2-3/docs/complib/cl_qmap_h.html b/branches/WOF2-3/docs/complib/cl_qmap_h.html new file mode 100644 index 00000000..b80ebc54 --- /dev/null +++ b/branches/WOF2-3/docs/complib/cl_qmap_h.html @@ -0,0 +1,998 @@ + + + + +./inc_docs/complib/cl_qmap_h.html + + + + +Generated from ./inc/complib/cl_qmap.h with ROBODoc v4.99.17 on Sun Mar 04 2007 18:17:51 +
+
+ +

[Modules] +Component Library/Quick Map

+ +

[top][parent][index]

+

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
+
+       Search:
+               cl_qmap_apply_func
+
+       Attributes:
+               cl_qmap_count, cl_is_qmap_empty,
+
+
+
+ +

[Functions] +Component Library: Quick Map/cl_is_qmap_empty

+ +

[top][index]

+

NAME

+
       cl_is_qmap_empty
+
+

DESCRIPTION

+
       The cl_is_qmap_empty function returns whether a quick map is empty.
+
+

SYNOPSIS

+
CL_INLINE boolean_t CL_API
+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
+
+
+
+ +

[Structures] +Component Library: Quick Map/cl_map_item_t

+ +

[top][index]

+

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
+
+
+
+ +

[Structures] +Component Library: Quick Map/cl_map_obj_t

+ +

[top][index]

+

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
+
+
+
+ +

[Definitions] +Component Library: Quick Map/cl_pfn_qmap_apply_t

+ +

[top][index]

+

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_API *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
+
+
+
+ +

[Functions] +Component Library: Quick Map/cl_qmap_apply_func

+ +

[top][index]

+

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

+
CL_EXPORT void CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Quick Map/cl_qmap_count

+ +

[top][index]

+

NAME

+
       cl_qmap_count
+
+

DESCRIPTION

+
       The cl_qmap_count function returns the number of items stored
+       in a quick map.
+
+

SYNOPSIS

+
CL_INLINE size_t CL_API
+cl_qmap_count(
+        IN      const cl_qmap_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_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
+
+
+
+ +

[Functions] +Component Library: Quick Map/cl_qmap_delta

+ +

[top][index]

+

NAME

+
       cl_qmap_delta
+
+

DESCRIPTION

+
       The cl_qmap_delta function computes the differences between two maps.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+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 usefull 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
+
+
+
+ +

[Functions] +Component Library: Quick Map/cl_qmap_end

+ +

[top][index]

+

NAME

+
       cl_qmap_end
+
+

DESCRIPTION

+
       The cl_qmap_end function returns the end of a quick map.
+
+

SYNOPSIS

+
CL_INLINE const cl_map_item_t* const CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Quick Map/cl_qmap_get

+ +

[top][index]

+

NAME

+
       cl_qmap_get
+
+

DESCRIPTION

+
       The cl_qmap_get function returns the map item associated with a key.
+
+

SYNOPSIS

+
CL_EXPORT cl_map_item_t* CL_API
+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_remove
+
+
+
+ +

[Functions] +Component Library: Quick Map/cl_qmap_head

+ +

[top][index]

+

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

+
CL_INLINE cl_map_item_t* CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Quick Map/cl_qmap_init

+ +

[top][index]

+

NAME

+
       cl_qmap_init
+
+

DESCRIPTION

+
       The cl_qmap_init function initialized a quick map for use.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Quick Map/cl_qmap_insert

+ +

[top][index]

+

NAME

+
       cl_qmap_insert
+
+

DESCRIPTION

+
       The cl_qmap_insert function inserts a map item into a quick map.
+
+

SYNOPSIS

+
CL_EXPORT cl_map_item_t* CL_API
+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.
+
+

NOTES

+
       Insertion operations may cause the quick map to rebalance.
+
+

SEE ALSO

+
       Quick Map, cl_qmap_remove, cl_map_item_t
+
+
+
+ +

[Functions] +Component Library: Quick Map/cl_qmap_key

+ +

[top][index]

+

NAME

+
       cl_qmap_key
+
+

DESCRIPTION

+
       The cl_qmap_key function retrieves the key value of a map item.
+
+

SYNOPSIS

+
CL_INLINE uint64_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Quick Map/cl_qmap_merge

+ +

[top][index]

+

NAME

+
       cl_qmap_merge
+
+

DESCRIPTION

+
       The cl_qmap_merge function moves all items from one map to another,
+       excluding duplicates.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Quick Map/cl_qmap_next

+ +

[top][index]

+

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

+
CL_INLINE cl_map_item_t* CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Quick Map/cl_qmap_obj

+ +

[top][index]

+

NAME

+
       cl_qmap_obj
+
+

DESCRIPTION

+
       The cl_qmap_obj function returns the object stored in a map object.
+
+

SYNOPSIS

+
CL_INLINE void* CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Quick Map/cl_qmap_prev

+ +

[top][index]

+

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

+
CL_INLINE cl_map_item_t* CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Quick Map/cl_qmap_remove

+ +

[top][index]

+

NAME

+
       cl_qmap_remove
+
+

DESCRIPTION

+
       The cl_qmap_remove function removes the map item with the specified key
+       from a quick map.
+
+

SYNOPSIS

+
CL_EXPORT cl_map_item_t* CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Quick Map/cl_qmap_remove_all

+ +

[top][index]

+

NAME

+
       cl_qmap_remove_all
+
+

DESCRIPTION

+
       The cl_qmap_remove_all function removes all items in a quick map,
+       leaving it empty.
+
+

SYNOPSIS

+
CL_INLINE void CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Quick Map/cl_qmap_remove_item

+ +

[top][index]

+

NAME

+
       cl_qmap_remove_item
+
+

DESCRIPTION

+
       The cl_qmap_remove_item function removes the specified map item
+       from a quick map.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Quick Map/cl_qmap_set_obj

+ +

[top][index]

+

NAME

+
       cl_qmap_set_obj
+
+

DESCRIPTION

+
       The cl_qmap_set_obj function sets the object stored in a map object.
+
+

SYNOPSIS

+
CL_INLINE void CL_API
+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
+
+
+
+ +

[Structures] +Component Library: Quick Map/cl_qmap_t

+ +

[top][index]

+

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
+
+
+
+ +

[Functions] +Component Library: Quick Map/cl_qmap_tail

+ +

[top][index]

+

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

+
CL_INLINE cl_map_item_t* CL_API
+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
+
+
+ + diff --git a/branches/WOF2-3/docs/complib/cl_qpool_h.html b/branches/WOF2-3/docs/complib/cl_qpool_h.html new file mode 100644 index 00000000..69575803 --- /dev/null +++ b/branches/WOF2-3/docs/complib/cl_qpool_h.html @@ -0,0 +1,628 @@ + + + + +./inc_docs/complib/cl_qpool_h.html + + + + +Generated from ./inc/complib/cl_qpool.h with ROBODoc v4.99.17 on Sun Mar 04 2007 18:17:51 +
+
+ +

[Modules] +Component Library/Quick Pool

+ +

[top][parent][index]

+

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
+
+
+
+ +

[Functions] +Component Library: Quick Pool/cl_is_qpool_inited

+ +

[top][index]

+

NAME

+
       cl_is_qpool_inited
+
+

DESCRIPTION

+
       The cl_is_qpool_inited function returns whether a quick pool was
+       successfully initialized.
+
+

SYNOPSIS

+
CL_INLINE uint32_t CL_API
+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
+
+
+
+ +

[Definitions] +Component Library: Quick Pool/cl_pfn_qpool_dtor_t

+ +

[top][index]

+

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_API *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
+
+
+
+ +

[Definitions] +Component Library: Quick Pool/cl_pfn_qpool_init_t

+ +

[top][index]

+

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_API *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
+
+
+
+ +

[Functions] +Component Library: Quick Pool/cl_qpool_construct

+ +

[top][index]

+

NAME

+
       cl_qpool_construct
+
+

DESCRIPTION

+
       The cl_qpool_construct function constructs a quick pool.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+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.
+
+
+
+ +

[Functions] +Component Library: Quick Pool/cl_qpool_count

+ +

[top][index]

+

NAME

+
       cl_qpool_count
+
+

DESCRIPTION

+
       The cl_qpool_count function returns the number of available objects
+       in a quick pool.
+
+

SYNOPSIS

+
CL_INLINE size_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Quick Pool/cl_qpool_destroy

+ +

[top][index]

+

NAME

+
       cl_qpool_destroy
+
+

DESCRIPTION

+
       The cl_qpool_destroy function destroys a quick pool.
+
+

SYNOPSIS

+
CL_INLINE void CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Quick Pool/cl_qpool_get

+ +

[top][index]

+

NAME

+
       cl_qpool_get
+
+

DESCRIPTION

+
       The cl_qpool_get function retrieves an object from a
+       quick pool.
+
+

SYNOPSIS

+
CL_INLINE cl_pool_item_t* CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Quick Pool/cl_qpool_grow

+ +

[top][index]

+

NAME

+
       cl_qpool_grow
+
+

DESCRIPTION

+
       The cl_qpool_grow function grows a quick pool by
+       the specified number of objects.
+
+

SYNOPSIS

+
CL_INLINE cl_status_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Quick Pool/cl_qpool_init

+ +

[top][index]

+

NAME

+
       cl_qpool_init
+
+

DESCRIPTION

+
       The cl_qpool_init function initializes a quick pool for use.
+
+

SYNOPSIS

+
CL_EXPORT cl_status_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Quick Pool/cl_qpool_put

+ +

[top][index]

+

NAME

+
       cl_qpool_put
+
+

DESCRIPTION

+
       The cl_qpool_put function returns an object to the head of a quick pool.
+
+

SYNOPSIS

+
CL_INLINE void CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Quick Pool/cl_qpool_put_list

+ +

[top][index]

+

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

+
CL_INLINE void CL_API
+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
+
+
+
+ +

[Structures] +Component Library: Quick Pool/cl_qpool_t

+ +

[top][index]

+

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
+
+
+ + diff --git a/branches/WOF2-3/docs/complib/cl_rbmap_h.html b/branches/WOF2-3/docs/complib/cl_rbmap_h.html new file mode 100644 index 00000000..f2c76df2 --- /dev/null +++ b/branches/WOF2-3/docs/complib/cl_rbmap_h.html @@ -0,0 +1,563 @@ + + + + +./inc_docs/complib/cl_rbmap_h.html + + + + +Generated from ./inc/complib/cl_rbmap.h with ROBODoc v4.99.17 on Sun Mar 04 2007 18:17:51 +
+
+ +

[Modules] +Component Library/RB Map

+ +

[top][parent][index]

+

NAME

+
       RB Map
+
+

DESCRIPTION

+
       RB map implements a binary tree that stores user provided cl_rbmap_item_t
+       structures.  Each item stored in a RB map has a unique key
+       (duplicates are not allowed).  RB map provides the ability to
+       efficiently search for an item given a key.
+
+       RB map does not allocate any memory, and can therefore not fail
+       any operations due to insufficient memory.  RB map can thus be useful
+       in minimizing the error paths in code.
+
+       RB map is not thread safe, and users must provide serialization when
+       adding and removing items from the map.
+
+       The RB map functions operate on a cl_rbmap_t structure which should be
+       treated as opaque and should be manipulated only through the provided
+       functions.
+
+

SEE ALSO

+
       Structures:
+               cl_rbmap_t, cl_rbmap_item_t
+
+       Initialization:
+               cl_rbmap_init
+
+       Iteration:
+               cl_rbmap_root, cl_rbmap_end, cl_rbmap_left, cl_rbmap_right, cl_rbmap_up
+
+       Manipulation:
+               cl_rbmap_insert, cl_rbmap_get, cl_rbmap_remove_item, cl_rbmap_remove,
+               cl_rbmap_reset, cl_rbmap_merge, cl_rbmap_delta
+
+       Search:
+               cl_rbmap_apply_func
+
+       Attributes:
+               cl_rbmap_count, cl_is_rbmap_empty,
+
+
+
+ +

[Functions] +Component Library: RB Map/cl_is_rbmap_empty

+ +

[top][index]

+

NAME

+
       cl_is_rbmap_empty
+
+

DESCRIPTION

+
       The cl_is_rbmap_empty function returns whether a RB map is empty.
+
+

SYNOPSIS

+
CL_INLINE boolean_t CL_API
+cl_is_rbmap_empty(
+        IN      const cl_rbmap_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_rbmap_t structure to test for emptiness.
+
+ RETURN VALUES
+       TRUE if the RB map is empty.
+
+       FALSE otherwise.
+
+

SEE ALSO

+
       RB Map, cl_rbmap_count, cl_rbmap_reset
+
+
+
+ +

[Functions] +Component Library: RB Map/cl_rbmap_count

+ +

[top][index]

+

NAME

+
       cl_rbmap_count
+
+

DESCRIPTION

+
       The cl_rbmap_count function returns the number of items stored
+       in a RB map.
+
+

SYNOPSIS

+
CL_INLINE size_t CL_API
+cl_rbmap_count(
+        IN      const cl_rbmap_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_rbmap_t structure whose item count to return.
+
+

RETURN VALUE

+
       Returns the number of items stored in the map.
+
+

SEE ALSO

+
       RB Map, cl_is_rbmap_empty
+
+
+
+ +

[Functions] +Component Library: RB Map/cl_rbmap_end

+ +

[top][index]

+

NAME

+
       cl_rbmap_end
+
+

DESCRIPTION

+
       The cl_rbmap_end function returns the end of a RB map.
+
+

SYNOPSIS

+
CL_INLINE const cl_rbmap_item_t* const CL_API
+cl_rbmap_end(
+        IN      const cl_rbmap_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_rbmap_t structure whose end to return.
+
+

RETURN VALUE

+
       Pointer to the end of the map.
+
+

NOTES

+
       cl_rbmap_end is useful for determining the validity of map items returned
+       by cl_rbmap_head, cl_rbmap_tail, cl_rbmap_next, or cl_rbmap_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_rbmap_head or cl_rbmap_tail, this condition indicates that
+       the map is empty.
+
+

SEE ALSO

+
       RB Map, cl_rbmap_head, cl_rbmap_tail, cl_rbmap_next, cl_rbmap_prev
+       cl_rbmap_root, cl_rbmap_left, cl_rbmap_right, cl_rbmap_up
+
+
+
+ +

[Functions] +Component Library: RB Map/cl_rbmap_init

+ +

[top][index]

+

NAME

+
       cl_rbmap_init
+
+

DESCRIPTION

+
       The cl_rbmap_init function initialized a RB map for use.
+
+

SYNOPSIS

+
CL_INLINE void CL_API
+cl_rbmap_init(
+        IN      cl_rbmap_t* const       p_map )
+{
+        CL_ASSERT( p_map );
+
+        /* special setup for the root node */
+        p_map->root.p_left = &p_map->nil;
+        p_map->root.p_right = &p_map->nil;
+        p_map->root.p_up = &p_map->root;
+        p_map->root.color = CL_MAP_BLACK;
+
+        /* Setup the node used as terminator for all leaves. */
+        p_map->nil.p_left = &p_map->nil;
+        p_map->nil.p_right = &p_map->nil;
+        p_map->nil.p_up = &p_map->nil;
+        p_map->nil.color = CL_MAP_BLACK;
+
+#ifdef _DEBUG_
+        p_map->root.p_map = p_map;
+        p_map->nil.p_map = p_map;
+#endif
+
+        p_map->state = CL_INITIALIZED;
+
+        p_map->count = 0;
+}
+
+

PARAMETERS

+
       p_map
+               [in] Pointer to a cl_rbmap_t structure to initialize.
+
+ RETURN VALUES
+       This function does not return a value.
+
+

NOTES

+
       Allows calling RB map manipulation functions.
+
+

SEE ALSO

+
       RB Map, cl_rbmap_insert, cl_rbmap_remove
+
+
+
+ +

[Functions] +Component Library: RB Map/cl_rbmap_insert

+ +

[top][index]

+

NAME

+
       cl_rbmap_insert
+
+

DESCRIPTION

+
       The cl_rbmap_insert function inserts a map item into a RB map.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+cl_rbmap_insert(
+        IN      cl_rbmap_t* const               p_map,
+        IN      cl_rbmap_item_t* const  p_insert_at,
+        IN      cl_rbmap_item_t* const  p_item,
+        IN      boolean_t                               left );
+
+

PARAMETERS

+
       p_map
+               [in] Pointer to a cl_rbmap_t structure into which to add the item.
+
+       p_insert_at
+               [in] Pointer to a cl_rbmap_item_t structure to serve as parent
+               to p_item.
+
+       p_item
+               [in] Pointer to a cl_rbmap_item_t stucture to insert into the RB map.
+
+       left
+               [in] Indicates that p_item should be inserted to the left of p_insert_at.
+
+

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 RB map to rebalance.
+
+

SEE ALSO

+
       RB Map, cl_rbmap_remove, cl_rbmap_item_t
+
+
+
+ +

[Structures] +Component Library: RB Map/cl_rbmap_item_t

+ +

[top][index]

+

NAME

+
       cl_rbmap_item_t
+
+

DESCRIPTION

+
       The cl_rbmap_item_t structure is used by maps to store objects.
+
+       The cl_rbmap_item_t structure should be treated as opaque and should
+       be manipulated only through the provided functions.
+
+

SYNOPSIS

+
typedef struct _cl_rbmap_item
+{
+        struct _cl_rbmap_item           *p_left;
+        struct _cl_rbmap_item           *p_right;
+        struct _cl_rbmap_item           *p_up;
+        cl_map_color_t                          color;
+#ifdef _DEBUG_
+        struct _cl_rbmap                        *p_map;
+#endif
+
+} cl_rbmap_item_t;
+
+

FIELDS

+
       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.
+
+       color
+               Indicates whether a node is red or black in the map.
+
+

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 RB map.
+
+

SEE ALSO

+
       RB Map, cl_rbmap_insert, cl_rbmap_key, cl_pool_item_t, cl_list_item_t
+
+
+
+ +

[Functions] +Component Library: RB Map/cl_rbmap_left

+ +

[top][index]

+

NAME

+
       cl_rbmap_left
+
+

DESCRIPTION

+
       The cl_rbmap_left function returns the map item to the left
+       of the specified map item.
+
+

SYNOPSIS

+
CL_INLINE cl_rbmap_item_t* CL_API
+cl_rbmap_left(
+        IN      const cl_rbmap_item_t* const    p_item )
+{
+        CL_ASSERT( p_item );
+        return( (cl_rbmap_item_t*)p_item->p_left );
+}
+
+

PARAMETERS

+
       p_item
+               [in] Pointer to a map item whose predecessor to return.
+
+ RETURN VALUES
+       Pointer to the map item to the left in a RB map.
+
+       Pointer to the map end if no item is to the left.
+
+

SEE ALSO

+
       RB Map, cl_rbmap_head, cl_rbmap_tail, cl_rbmap_next, cl_rbmap_end,
+       cl_rbmap_item_t
+
+
+
+ +

[Functions] +Component Library: RB Map/cl_rbmap_remove_item

+ +

[top][index]

+

NAME

+
       cl_rbmap_remove_item
+
+

DESCRIPTION

+
       The cl_rbmap_remove_item function removes the specified map item
+       from a RB map.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+cl_rbmap_remove_item(
+        IN      cl_rbmap_t* const               p_map,
+        IN      cl_rbmap_item_t* const  p_item );
+
+

PARAMETERS

+
       p_item
+               [in] Pointer to a map item to remove from its RB map.
+
+ RETURN VALUES
+       This function does not return a value.
+
+       In a debug build, cl_rbmap_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 RB map.
+
+

SEE ALSO

+
       RB Map, cl_rbmap_remove, cl_rbmap_reset, cl_rbmap_insert
+
+
+
+ +

[Functions] +Component Library: RB Map/cl_rbmap_reset

+ +

[top][index]

+

NAME

+
       cl_rbmap_reset
+
+

DESCRIPTION

+
       The cl_rbmap_reset function removes all items in a RB map,
+       leaving it empty.
+
+

SYNOPSIS

+
CL_INLINE void CL_API
+cl_rbmap_reset(
+        IN      cl_rbmap_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->count = 0;
+}
+
+

PARAMETERS

+
       p_map
+               [in] Pointer to a cl_rbmap_t structure to empty.
+
+ RETURN VALUES
+       This function does not return a value.
+
+

SEE ALSO

+
       RB Map, cl_rbmap_remove, cl_rbmap_remove_item
+
+
+
+ +

[Functions] +Component Library: RB Map/cl_rbmap_right

+ +

[top][index]

+

NAME

+
       cl_rbmap_right
+
+

DESCRIPTION

+
       The cl_rbmap_right function returns the map item to the right
+       of the specified map item.
+
+

SYNOPSIS

+
CL_INLINE cl_rbmap_item_t* CL_API
+cl_rbmap_right(
+        IN      const cl_rbmap_item_t* const    p_item )
+{
+        CL_ASSERT( p_item );
+        return( (cl_rbmap_item_t*)p_item->p_right );
+}
+
+

PARAMETERS

+
       p_item
+               [in] Pointer to a map item whose predecessor to return.
+
+ RETURN VALUES
+       Pointer to the map item to the right in a RB map.
+
+       Pointer to the map end if no item is to the right.
+
+

SEE ALSO

+
       RB Map, cl_rbmap_head, cl_rbmap_tail, cl_rbmap_next, cl_rbmap_end,
+       cl_rbmap_item_t
+
+
+
+ +

[Functions] +Component Library: RB Map/cl_rbmap_root

+ +

[top][index]

+

NAME

+
       cl_rbmap_root
+
+

DESCRIPTION

+
       The cl_rbmap_root function returns the root of a RB map.
+
+

SYNOPSIS

+
CL_INLINE cl_rbmap_item_t* const CL_API
+cl_rbmap_root(
+        IN      const cl_rbmap_t* const p_map )
+{
+        CL_ASSERT( p_map );
+        return( p_map->root.p_left );
+}
+
+

PARAMETERS

+
       p_map
+               [in] Pointer to a cl_rbmap_t structure whose root to return.
+
+

RETURN VALUE

+
       Pointer to the end of the map.
+
+

NOTES

+
       cl_rbmap_end is useful for determining the validity of map items returned
+       by cl_rbmap_head, cl_rbmap_tail, cl_rbmap_next, or cl_rbmap_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_rbmap_head or cl_rbmap_tail, this condition indicates that
+       the map is empty.
+
+

SEE ALSO

+
       RB Map, cl_rbmap_head, cl_rbmap_tail, cl_rbmap_next, cl_rbmap_prev,
+       cl_rbmap_end, cl_rbmap_left, cl_rbmap_right, cl_rbmap_up
+
+
+
+ +

[Structures] +Component Library: RB Map/cl_rbmap_t

+ +

[top][index]

+

NAME

+
       cl_rbmap_t
+
+

DESCRIPTION

+
       Quick map structure.
+
+       The cl_rbmap_t structure should be treated as opaque and should
+       be manipulated only through the provided functions.
+
+

SYNOPSIS

+
typedef struct _cl_rbmap
+{
+        cl_rbmap_item_t root;
+        cl_rbmap_item_t nil;
+        cl_state_t              state;
+        size_t                  count;
+
+} cl_rbmap_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

+
       RB Map
+
+
+ + diff --git a/branches/WOF2-3/docs/complib/cl_reqmgr_h.html b/branches/WOF2-3/docs/complib/cl_reqmgr_h.html new file mode 100644 index 00000000..50b7d70d --- /dev/null +++ b/branches/WOF2-3/docs/complib/cl_reqmgr_h.html @@ -0,0 +1,463 @@ + + + + +./inc_docs/complib/cl_reqmgr_h.html + + + + +Generated from ./inc/complib/cl_reqmgr.h with ROBODoc v4.99.17 on Sun Mar 04 2007 18:17:51 +
+
+ +

[Modules] +Component Library/Request Manager

+ +

[top][parent][index]

+

NAME

+
       Request Manager
+
+

DESCRIPTION

+
       The Request Manager manages synchronous as well as asynchronous
+       requests for objects.
+
+       Request manager does not supply the objects, but merely returns whether
+       objects are available to satisfy requests. This allows users to use
+       various sources for objects.
+
+       While the request manager manages synchronous and asynchronous requests
+       for objects, it does not itself operate asynchronously. Instead, the
+       cl_req_mgr_resume function returns information for resuming asynchronous
+       requests. If a call to cl_req_mgr_resume returns CL_SUCCESS, additional
+       requests may be able to resume. It is recommended that users flush
+       pending requests by calling cl_req_mgr_resume while CL_SUCCESS is returned.
+
+       The request manager functions operates on a cl_req_mgr_t structure which
+       should be treated as opaque and should be manipulated only through the
+       provided functions.
+
+

SEE ALSO

+
       Types:
+               cl_req_type_t
+
+       Structures:
+               cl_req_mgr_t
+
+       Callbacks:
+               cl_pfn_req_cb_t, cl_pfn_reqmgr_get_count_t
+
+       Initialization/Destruction:
+               cl_req_mgr_construct, cl_req_mgr_init, cl_req_mgr_destroy
+
+       Manipulation:
+               cl_req_mgr_get, cl_req_mgr_resume
+
+       Attributes:
+               cl_is_req_mgr_inited, cl_req_mgr_count
+
+
+
+ +

[Definitions] +Component Library: Request Manager/cl_pfn_req_cb_t

+ +

[top][index]

+

NAME

+
       cl_pfn_req_cb_t
+
+

DESCRIPTION

+
       The cl_pfn_req_cb_t function type defines the prototype for functions
+       used to store a function pointer to a user defined function.
+
+

SYNOPSIS

+
typedef void
+(CL_API *cl_pfn_req_cb_t)( void );
+
+

PARAMETERS

+
       This function does not take parameters.
+
+

RETURN VALUE

+
       This function does not return a value.
+
+

NOTES

+
       Function pointers specified by this parameter do not have to match the
+       defined syntax, as these callbacks are never invoked directly by the
+       request manager.  When specifying a function with a different prototype,
+       cast the function pointer to this type.
+
+

SEE ALSO

+
       Request Manager, cl_req_mgr_get, cl_req_mgr_resume
+
+
+
+ +

[Definitions] +Component Library: Request Manager/cl_pfn_reqmgr_get_count_t

+ +

[top][index]

+

NAME

+
       cl_pfn_reqmgr_get_count_t
+
+

DESCRIPTION

+
       The cl_pfn_reqmgr_get_count_t function type defines the prototype for
+       functions used to retrieve the number of available objects in a pool.
+
+

SYNOPSIS

+
typedef size_t
+(CL_API *cl_pfn_reqmgr_get_count_t)(
+        IN      void*   context );
+
+

PARAMETERS

+
       Context
+               [in] Context provided in a call to cl_req_mgr_init by
+               the get_context parameter.
+
+

RETURN VALUE

+
       Returns the number of objects available in an object pool for which
+       requests are managed by a request manager.
+
+

NOTES

+
       This function type is provided as function prototype reference for the
+       function passed into cl_req_mgr_init. This function is invoked by the
+       request manager when trying to fulfill requests for resources, either
+       through a call to cl_req_mgr_get or cl_req_mgr_resume.
+
+

SEE ALSO

+
       Request Manager, cl_req_mgr_init, cl_req_mgr_get, cl_req_mgr_resume
+
+
+
+ +

[Functions] +Component Library: Request Manager/cl_req_mgr_construct

+ +

[top][index]

+

NAME

+
       cl_req_mgr_construct
+
+

DESCRIPTION

+
       The cl_req_mgr_construct function constructs a request manager.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+cl_req_mgr_construct(
+        IN      cl_req_mgr_t* const     p_req_mgr );
+
+

PARAMETERS

+
       p_req_mgr
+               [in] Pointer to a cl_req_mgr_t structure to construct.
+
+

RETURN VALUE

+
       This function does not return a value.
+
+

NOTES

+
       cl_req_mgr_construct allows calling cl_req_mgr_destroy without first
+       calling cl_req_mgr_init.
+
+       Calling cl_req_mgr_construct is a prerequisite to calling any other
+       request manager function except cl_req_mgr_init.
+
+

SEE ALSO

+
       Request Manager, cl_req_mgr_init, cl_req_mgr_destroy
+
+
+
+ +

[Functions] +Component Library: Request Manager/cl_req_mgr_destroy

+ +

[top][index]

+

NAME

+
       cl_req_mgr_destroy
+
+

DESCRIPTION

+
       The cl_req_mgr_destroy function destroys a request manager.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+cl_req_mgr_destroy(
+        IN      cl_req_mgr_t* const     p_req_mgr );
+
+

PARAMETERS

+
       p_req_mgr
+               [in] Pointer to a cl_req_mgr_t structure to destroy.
+
+

RETURN VALUE

+
       This function does not return a value.
+
+

NOTES

+
       cl_req_mgr_destroy frees all memory allocated by the request manager.
+       Further operations on the request manager should not be attempted.
+
+       This function should only be called after a call to cl_req_mgr_construct
+       or cl_req_mgr_init.
+
+

SEE ALSO

+
       Request Manager, cl_req_mgr_construct, cl_req_mgr_init
+
+
+
+ +

[Functions] +Component Library: Request Manager/cl_req_mgr_get

+ +

[top][index]

+

NAME

+
       cl_req_mgr_get
+
+

DESCRIPTION

+
       The cl_req_mgr_get function handles synchronous and asynchronous
+       requests for objects.
+
+

SYNOPSIS

+
CL_EXPORT cl_status_t CL_API
+cl_req_mgr_get(
+        IN              cl_req_mgr_t* const     p_req_mgr,
+        IN OUT  size_t* const           p_count,
+        IN              const cl_req_type_t     req_type,
+        IN              cl_pfn_req_cb_t         pfn_callback,
+        IN              const void* const       context1,
+        IN              const void* const       context2 );
+
+

PARAMETERS

+
       p_req_mgr
+               [in] Pointer to a cl_req_mgr_t structure from which to check
+               for resources.
+
+       p_count
+               [in/out] On input, contains the number of objects requested.
+               On output, contains the number of objects available.
+
+       req_type
+               [in] Enumerated type describing the type of request. Valid values are:
+                       ReqGetSync
+                               Synchronous request.
+                       ReqGetAsync
+                               Asynchronous requests for which all objects are required at
+                               once.
+                       ReqGetAsyncPartialOk
+                               Asynchronous requests that may be broken into multiple smaller
+                               requests.
+
+       pfn_callback
+               [in] Pointer to a callback function for use by the caller. This
+               callback function is never invoked by the request manager.
+
+       context1
+               [in] First of two contexts for a resource request.
+
+       context2
+               [in] Second of two contexts for a resource request.
+
+ RETURN VALUES
+       CL_SUCCESS if all objects requested are available.
+
+       CL_PENDING if the request could not be completed in its entirety.
+       The p_count parameter contains the number of objects immediately available.
+
+       CL_INSUFFICIENT_RESOURCES if the request could not be completed due to
+       insufficient objects being available.
+
+       CL_INSUFFICIENT_MEMORY if the request failed due to a lack of system memory.
+
+

NOTES

+
       Upon successful completion of this function, the p_count parameter contains
+       the number of objects available.
+
+       Synchronous requests fail if there are any asynchronous requests pending,
+       or if there are not enough resources to immediately satisfy the request in
+       its entirety .
+
+       Asynchronous requests fail if there is insufficient system memory to
+       queue them.
+
+       Once an asynchronous request is queued, use cl_req_mgr_resume to retrieve
+       information for resuming queued requests.
+
+

SEE ALSO

+
       Request Manager, cl_req_mgr_resume
+
+
+
+ +

[Functions] +Component Library: Request Manager/cl_req_mgr_init

+ +

[top][index]

+

NAME

+
       cl_req_mgr_init
+
+

DESCRIPTION

+
       The cl_req_mgr_init function initializes a request manager for use.
+
+

SYNOPSIS

+
CL_EXPORT cl_status_t CL_API
+cl_req_mgr_init(
+        IN      cl_req_mgr_t* const                     p_req_mgr,
+        IN      cl_pfn_reqmgr_get_count_t       pfn_get_count,
+        IN      const void* const                       get_context );
+
+

PARAMETERS

+
       p_req_mgr
+               [in] Pointer to a cl_req_mgr_t structure to initialize.
+
+       pfn_get_count
+               [in] Callback function invoked by the request manager to get the
+               number of objects available in a pool of objects for which the
+               request manager is managing requests.
+               See the cl_pfn_req_mgr_get_count_t function type declaration for
+               details about the callback function.
+
+       get_context
+               [in] Context to pass into the function specified by the
+               pfn_get_count parameter.
+
+ RETURN VALUES
+       CL_SUCCESS if the request manager was successfully initialized.
+
+       CL_INSUFFICIENT_MEMORY if there was not enough memory to initialize
+       the request manager.
+
+

SEE ALSO

+
       Request Manager, cl_req_mgr_construct, cl_req_mgr_destroy, cl_req_mgr_get,
+       cl_req_mgr_resume, cl_pfn_req_mgr_get_count_t
+
+
+
+ +

[Functions] +Component Library: Request Manager/cl_req_mgr_resume

+ +

[top][index]

+

NAME

+
       cl_req_mgr_resume
+
+

DESCRIPTION

+
       The cl_req_mgr_resume function attempts to resume queued requests.
+
+

SYNOPSIS

+
CL_EXPORT cl_status_t CL_API
+cl_req_mgr_resume(
+        IN      cl_req_mgr_t* const             p_req_mgr,
+        OUT     size_t* const                   p_count,
+        OUT     cl_pfn_req_cb_t* const  ppfn_callback,
+        OUT     const void** const              p_context1,
+        OUT     const void** const              p_context2 );
+
+

PARAMETERS

+
       p_req_mgr
+               [in] Pointer to a cl_req_mgr_t structure from which to resume requests.
+
+       p_count
+               [out] Contains the number of objects available for a resuming request.
+
+       ppfn_callback
+               [out] Contains the pfn_callback value for the resuming request, as
+               provided to the call to the cl_req_mgr_get function.
+
+       p_context1
+               [out] Contains the context1 value for the resuming request, as provided
+               to the call to the cl_req_mgr_get function.
+
+       p_context2
+               [out] Contains the context2 value for the resuming request, as provided
+               to the call to the cl_req_mgr_get function.
+
+ RETURN VALUES
+       CL_SUCCESS if a request was completed.
+
+       CL_PENDING if a request was continued, but not completed.
+
+       CL_INSUFFICIENT_RESOURCES if a request could not be continued due to
+       a lack of resources.
+
+       CL_NOT_DONE if there were no pending requests.
+
+

NOTES

+
       cl_req_mgr_resume resumes at most one request. Further requests may be
+       able to be resumed if this call returns CL_SUCCESS.
+
+

SEE ALSO

+
       Request Manager, cl_req_mgr_get
+
+
+
+ +

[Structures] +Component Library: Request Manager/cl_req_mgr_t

+ +

[top][index]

+

NAME

+
       cl_req_mgr_t
+
+

DESCRIPTION

+
       Quick composite pool structure.
+
+       The cl_req_mgr_t structure should be treated as opaque and should be
+       manipulated only through the provided functions.
+
+

SYNOPSIS

+
typedef struct _cl_req_mgr
+{
+        cl_pfn_reqmgr_get_count_t       pfn_get_count;
+        const void                                      *get_context;
+        cl_qlist_t                                      request_queue;
+        cl_qpool_t                                      request_pool;
+
+} cl_req_mgr_t;
+
+

FIELDS

+
       pfn_get_count
+               Pointer to the count callback function.
+
+       get_context
+               Context to pass as single parameter to count callback.
+
+       request_queue
+               Pending requests for elements.
+
+       request_pool
+               Pool of request structures for storing requests in the request queue.
+
+

SEE ALSO

+
       Request Manager
+
+
+
+ +

[Definitions] +Component Library: Request Manager/cl_req_type_t

+ +

[top][index]

+

NAME

+
       cl_req_type_t
+
+

DESCRIPTION

+
       The cl_req_type_t enumerated type describes the type of request.
+
+

SYNOPSIS

+
typedef enum _cl_req_type
+{
+        REQ_GET_SYNC,
+        REQ_GET_ASYNC,
+        REQ_GET_PARTIAL_OK
+
+} cl_req_type_t;
+
+

VALUES

+
       REQ_GET_SYNC
+               Synchronous request.
+
+       REQ_GET_ASYNC
+               Asynchronous requests for which all objects are required at once.
+
+       REQ_GET_PARTIAL_OK
+               Asynchronous requests that may be broken into multiple smaller requests.
+
+

SEE ALSO

+
       Request Manager, cl_req_mgr_get
+
+
+ + diff --git a/branches/WOF2-3/docs/complib/cl_spinlock_h.html b/branches/WOF2-3/docs/complib/cl_spinlock_h.html new file mode 100644 index 00000000..960e2e2b --- /dev/null +++ b/branches/WOF2-3/docs/complib/cl_spinlock_h.html @@ -0,0 +1,210 @@ + + + + +./inc_docs/complib/cl_spinlock_h.html + + + + +Generated from ./inc/complib/cl_spinlock.h with ROBODoc v4.99.17 on Sun Mar 04 2007 18:17:51 +
+
+ +

[Modules] +Component Library/Spinlock

+ +

[top][parent][index]

+

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
+
+
+
+ +

[Functions] +Component Library: Spinlock/cl_spinlock_acquire

+ +

[top][index]

+

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.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+cl_spinlock_acquire(
+        IN      cl_spinlock_t* const    p_spinlock );
+
+

PARAMETERS

+
       p_spinlock
+               [in] Pointer to a spin lock structure to acquire.
+
+

RETURN VALUE

+
       This function does not return a value.
+
+

SEE ALSO

+
       Spinlock, cl_spinlock_release
+
+
+
+ +

[Functions] +Component Library: Spinlock/cl_spinlock_construct

+ +

[top][index]

+

NAME

+
       cl_spinlock_construct
+
+

DESCRIPTION

+
       The cl_spinlock_construct function initializes the state of a
+       spin lock.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+cl_spinlock_construct(
+        IN      cl_spinlock_t* const    p_spinlock );
+
+

PARAMETERS

+
       p_spinlock
+               [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
+
+
+
+ +

[Functions] +Component Library: Spinlock/cl_spinlock_destroy

+ +

[top][index]

+

NAME

+
       cl_spinlock_destroy
+
+

DESCRIPTION

+
       The cl_spinlock_destroy function performs all necessary cleanup of a
+       spin lock.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+cl_spinlock_destroy(
+        IN      cl_spinlock_t* const    p_spinlock );
+
+

PARAMETERS

+
       p_spinlock
+               [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
+
+
+
+ +

[Functions] +Component Library: Spinlock/cl_spinlock_init

+ +

[top][index]

+

NAME

+
       cl_spinlock_init
+
+

DESCRIPTION

+
       The cl_spinlock_init function initializes a spin lock for use.
+
+

SYNOPSIS

+
CL_EXPORT cl_status_t CL_API
+cl_spinlock_init(
+        IN      cl_spinlock_t* const    p_spinlock );
+
+

PARAMETERS

+
       p_spinlock
+               [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_release
+
+
+
+ +

[Functions] +Component Library: Spinlock/cl_spinlock_release

+ +

[top][index]

+

NAME

+
       cl_spinlock_release
+
+

DESCRIPTION

+
       The cl_spinlock_release function releases a spin lock object.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+cl_spinlock_release(
+        IN      cl_spinlock_t* const    p_spinlock );
+
+

PARAMETERS

+
       p_spinlock
+               [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
+
+
+ + diff --git a/branches/WOF2-3/docs/complib/cl_syscallback_h.html b/branches/WOF2-3/docs/complib/cl_syscallback_h.html new file mode 100644 index 00000000..e02cbcd0 --- /dev/null +++ b/branches/WOF2-3/docs/complib/cl_syscallback_h.html @@ -0,0 +1,243 @@ + + + + +./inc_docs/complib/cl_syscallback_h.html + + + + +Generated from ./inc/complib/cl_syscallback.h with ROBODoc v4.99.17 on Sun Mar 04 2007 18:17:51 +
+
+ +

[Modules] +Component Library/System Callback

+ +

[top][parent][index]

+

NAME

+
       System Callback
+
+

DESCRIPTION

+
       The System Callback provider uses threads from a system thread-pool to
+       invoke specified callback functions.
+
+       Callbacks can be queued in a low- or high-priority queue for processing.
+
+       cl_thread_suspend and cl_thread_stall can be used to delay or stall the
+       callback thread.
+
+       Environments that do not have a native system thread-pool emulate this
+       functionality to provide cross-environment support.
+
+       The cl_sys_callback_item_t structure should be treated as opaque and be
+       manipulated only through the provided functions.
+
+
+
+ +

[Functions] +Component Library: System Callback/cl_is_sys_callback_inited

+ +

[top][index]

+

NAME

+
       cl_is_sys_callback_inited
+
+

DESCRIPTION

+
       The cl_is_sys_callback_inited function returns whether the system
+       callback provider was initialized successfully
+
+

SYNOPSIS

+
boolean_t
+__cl_is_sys_callback_inited( void );
+/*
+* RETURN VALUES
+*       TRUE if the system callback provider was initialized successfully.
+*
+*       FALSE otherwise.
+
+

NOTES

+
       Allows checking the state of the system callback provider to determine
+       if invoking member functions is appropriate.
+
+

SEE ALSO

+
       System Callback
+
+
+
+ +

[Definitions] +Component Library: System Callback/cl_pfn_sys_callback_t

+ +

[top][index]

+

NAME

+
       cl_pfn_sys_callback_t
+
+

DESCRIPTION

+
       The cl_pfn_sys_callback_t function type defines the prototype for
+       functions invoked by the system callback provider.
+
+

SYNOPSIS

+
typedef void
+(CL_API *cl_pfn_sys_callback_t)(
+        IN      void*   get_context,
+        IN      void*   queue_context );
+
+

PARAMETERS

+
       get_context
+               [in] Value of the get_context parameter specified in a call
+               to cl_sys_callback_get.
+
+       queue_context
+               [in] Value of the queue_context parameter specified in a call
+               to cl_sys_callback_queue.
+
+

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_sys_callback_queue function.
+
+

SEE ALSO

+
       System Callback, cl_sys_callback_queue
+
+
+
+ +

[Functions] +Component Library: System Callback/cl_sys_callback_get

+ +

[top][index]

+

NAME

+
       cl_sys_callback_get
+
+

DESCRIPTION

+
       The cl_sys_callback_get function retrieves a system callback item.
+
+

SYNOPSIS

+
CL_EXPORT cl_sys_callback_item_t* CL_API
+cl_sys_callback_get(
+        IN      const void* const get_context );
+
+

PARAMETERS

+
       get_context
+               [in] Context value to pass into the callback function.
+
+ RETURN VALUES
+       Returns a pointer to a system callback item if successful.
+
+       Returns NULL if the call fails.
+
+

NOTES

+
       A system callback item must be released with a call to cl_sys_callback_put.
+
+       Care must be taken to prevent a system callback item from being returned
+       to the pool while it is queued. Callers of cl_sys_callback_queue must not
+       return the system callback item to the pool until their callback has been
+       invoked.
+
+       In Windows 2000 Kernel Mode, the get_context is a pointer to the device
+       object for which the system callback is being used.
+
+

SEE ALSO

+
       System Callback, SysCallbackPut, SysCallbackQueue
+
+
+
+ +

[Functions] +Component Library: System Callback/cl_sys_callback_put

+ +

[top][index]

+

NAME

+
       cl_sys_callback_put
+
+

DESCRIPTION

+
       The cl_sys_callback_put function releases the specified
+       system callback item.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+cl_sys_callback_put(
+        IN      cl_sys_callback_item_t* const   p_item );
+
+

PARAMETERS

+
       p_item
+               [in] Pointer to a system callback item to release.
+
+

RETURN VALUE

+
       This function does not return a value.
+
+

NOTES

+
       The p_item parameter points to a system callback item returned by
+       a previous call to cl_sys_callback_get.
+
+       The specified system callback item must not be queued when making
+       a call to this function.  This function can, however, be called
+       from the callback function.
+
+

SEE ALSO

+
       System Callback, cl_sys_callback_get, cl_sys_callback_queue
+
+
+
+ +

[Functions] +Component Library: System Callback/cl_sys_callback_queue

+ +

[top][index]

+

NAME

+
       cl_sys_callback_queue
+
+

DESCRIPTION

+
       The cl_sys_callback_queue function queues the specified system callback item
+       for execution.
+
+

SYNOPSIS

+
CL_EXPORT cl_status_t CL_API
+cl_sys_callback_queue(
+        IN      cl_sys_callback_item_t* const   p_item,
+        IN      cl_pfn_sys_callback_t                   pfn_callback,
+        IN      const void* const                               queue_context,
+        IN      const boolean_t                                 high_priority );
+
+

PARAMETERS

+
       p_item
+               [in] Pointer to a system callback item.
+
+       pfn_callback
+               [in] Pointer to a function to be invoked by the system callback module.
+               See the cl_pfn_sys_callback_t function type definition for details
+               about the callback function.
+
+       queue_context
+               [in] Value passed to the system callback function.
+
+       high_priority
+               [in] Specifies whether the request should be queued in the high- or
+               low-priority queue.
+
+ RETURN VALUES
+       CL_SUCCESS if the system callback item was successfully queued.
+
+       CL_ERROR otherwise.
+
+

NOTES

+
       A thread from the system thread pool will invoke the specified callback
+       function with the get_context value specified in the call to
+       cl_sys_callback_get and the specified context as parameters.
+
+       The high priority queue is processed before the low priority queue. There
+       is no fairness algorithm implemented for removing items from the queues.
+
+       Care should be taken to only queue a given system callback item once
+       at a time.
+
+

SEE ALSO

+
       System Callback, cl_sys_callback_get, cl_pfn_sys_callback_t
+
+
+ + diff --git a/branches/WOF2-3/docs/complib/cl_thread_h.html b/branches/WOF2-3/docs/complib/cl_thread_h.html new file mode 100644 index 00000000..aeebc824 --- /dev/null +++ b/branches/WOF2-3/docs/complib/cl_thread_h.html @@ -0,0 +1,164 @@ + + + + +./inc_docs/complib/cl_thread_h.html + + + + +Generated from ./inc/complib/cl_thread.h with ROBODoc v4.99.17 on Sun Mar 04 2007 18:17:51 +
+
+ +

[Functions] +Component Library: Thread/cl_is_blockable

+ +

[top][index]

+

NAME

+
       cl_is_blockable
+
+

DESCRIPTION

+
       The cl_is_blockable indicates if the current caller context is
+       blockable.
+
+

SYNOPSIS

+
CL_EXPORT boolean_t CL_API
+cl_is_blockable( void );
+
+

RETURN VALUE

+
       TRUE if the caller's thread context can be blocked, i.e it is safe
+       to perform a sleep, or call a down operation on a semaphore.
+
+       FALSE otherwise
+
+

SEE ALSO

+
       Thread
+
+
+
+ +

[Definitions] +Component Library: Thread/cl_pfn_thread_callback_t

+ +

[top][index]

+

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_API *cl_pfn_thread_callback_t)(
+        IN      void*   context );
+
+

PARAMETERS

+
       context
+               [in] Value specified in a call to cl_thread_init or
+               cl_thread_pool_create.
+
+

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_thread_init
+       and cl_thread_pool_create functions.
+
+

SEE ALSO

+
       Thread Pool
+
+
+
+ +

[Functions] +Component Library: Thread/cl_proc_count

+ +

[top][index]

+

NAME

+
       cl_proc_count
+
+

DESCRIPTION

+
       The cl_proc_count function returns the number of processors in the system.
+
+

SYNOPSIS

+
CL_EXPORT uint32_t CL_API
+cl_proc_count( void );
+
+

RETURN VALUE

+
       Returns the number of processors in the system.
+
+
+
+ +

[Functions] +Component Library: Thread/cl_thread_stall

+ +

[top][index]

+

NAME

+
       cl_thread_stall
+
+

DESCRIPTION

+
       The cl_thread_stall function stalls the calling thread for a minimum of
+       the specified number of microseconds.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Thread/cl_thread_suspend

+ +

[top][index]

+

NAME

+
       cl_thread_suspend
+
+

DESCRIPTION

+
       The cl_thread_suspend function suspends the calling thread for a minimum
+       of the specified number of milliseconds.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+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
+
+
+ + diff --git a/branches/WOF2-3/docs/complib/cl_threadpool_h.html b/branches/WOF2-3/docs/complib/cl_threadpool_h.html new file mode 100644 index 00000000..e6ca4418 --- /dev/null +++ b/branches/WOF2-3/docs/complib/cl_threadpool_h.html @@ -0,0 +1,273 @@ + + + + +./inc_docs/complib/cl_threadpool_h.html + + + + +Generated from ./inc/complib/cl_threadpool.h with ROBODoc v4.99.17 on Sun Mar 04 2007 18:17:51 +
+
+ +

[Modules] +Component Library/Thread Pool

+ +

[top][parent][index]

+

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
+
+
+
+ +

[Functions] +Component Library: Thread Pool/cl_thread_pool_construct

+ +

[top][index]

+

NAME

+
       cl_thread_pool_construct
+
+

DESCRIPTION

+
       The cl_thread_pool_construct function initializes the state of a
+       thread pool.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+cl_thread_pool_construct(
+        IN      cl_thread_pool_t* const p_thread_pool );
+
+

PARAMETERS

+
       p_thread_pool
+               [in] Pointer to a thread pool structure.
+
+

RETURN VALUE

+
       This function does not return a value.
+
+

NOTES

+
       Allows calling cl_thread_pool_destroy without first calling
+       cl_thread_pool_init.
+
+       Calling cl_thread_pool_construct is a prerequisite to calling any other
+       thread pool function except cl_thread_pool_init.
+
+

SEE ALSO

+
       Thread Pool, cl_thread_pool_init, cl_thread_pool_destroy
+
+
+
+ +

[Functions] +Component Library: Thread Pool/cl_thread_pool_destroy

+ +

[top][index]

+

NAME

+
       cl_thread_pool_destroy
+
+

DESCRIPTION

+
       The cl_thread_pool_destroy function performs any necessary cleanup
+       for a thread pool.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Thread Pool/cl_thread_pool_init

+ +

[top][index]

+

NAME

+
       cl_thread_pool_init
+
+

DESCRIPTION

+
       The cl_thread_pool_init function creates the threads to be
+       managed by a thread pool.
+
+

SYNOPSIS

+
CL_EXPORT cl_status_t CL_API
+cl_thread_pool_init(
+        IN      cl_thread_pool_t* const         p_thread_pool,
+        IN      uint32_t                                        thread_count,
+        IN      cl_pfn_thread_callback_t        pfn_callback,
+        IN      const void* const                       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
+
+
+
+ +

[Functions] +Component Library: Thread Pool/cl_thread_pool_signal

+ +

[top][index]

+

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_EXPORT cl_status_t CL_API
+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
+
+
+
+ +

[Structures] +Component Library: Thread Pool/cl_thread_pool_t

+ +

[top][index]

+

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
+{
+        cl_pfn_thread_callback_t        pfn_callback;
+        const void                                      *context;
+        cl_list_t                                       thread_list;
+        cl_event_t                                      wakeup_event;
+        cl_event_t                                      destroy_event;
+        boolean_t                                       exit;
+        cl_state_t                                      state;
+        atomic32_t                                      running_count;
+
+} cl_thread_pool_t;
+
+

FIELDS

+
       pfn_callback
+               Callback function for the thread to invoke.
+
+       context
+               Context to pass to the thread callback function.
+
+       thread_list
+               List of threads managed by the thread pool.
+
+       event
+               Event used to signal threads to wake up and do work.
+
+       destroy_event
+               Event used to signal threads to exit.
+
+       exit
+               Flag used to indicates threads to exit.
+
+       state
+               State of the thread pool.
+
+       running_count
+               Number of threads running.
+
+

SEE ALSO

+
       Thread Pool
+
+
+ + diff --git a/branches/WOF2-3/docs/complib/cl_timer_h.html b/branches/WOF2-3/docs/complib/cl_timer_h.html new file mode 100644 index 00000000..86882a04 --- /dev/null +++ b/branches/WOF2-3/docs/complib/cl_timer_h.html @@ -0,0 +1,432 @@ + + + + +./inc_docs/complib/cl_timer_h.html + + + + +Generated from ./inc/complib/cl_timer.h with ROBODoc v4.99.17 on Sun Mar 04 2007 18:17:51 +
+
+ +

[Modules] +Component Library/Timer

+ +

[top][parent][index]

+

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
+
+
+
+ +

[Functions] +Component Library: Time Stamp/cl_get_tick_count

+ +

[top][index]

+

NAME

+
       cl_get_tick_count
+
+

DESCRIPTION

+
       The cl_get_tick_count function returns the raw high-resolution
+       performance counter value.
+
+

SYNOPSIS

+
CL_EXPORT uint64_t CL_API
+cl_get_tick_count( void );
+
+

RETURN VALUE

+
       Value of the high-resolution performance counter.
+
+

SEE ALSO

+
       Timer, cl_get_time_stamp, cl_get_tick_freq
+
+
+
+ +

[Functions] +Component Library: Time Stamp/cl_get_tick_freq

+ +

[top][index]

+

NAME

+
       cl_get_tick_freq
+
+

DESCRIPTION

+
       The cl_get_tick_freq function returns the frequency of the
+       high-resolution performance counter.
+
+

SYNOPSIS

+
CL_EXPORT uint64_t CL_API
+cl_get_tick_freq( void );
+
+

RETURN VALUE

+
       The frequency of the high-resolution performance counter.
+
+

SEE ALSO

+
       Timer, cl_get_time_stamp, cl_get_tick_count
+
+
+
+ +

[Functions] +Component Library: Time Stamp/cl_get_time_stamp

+ +

[top][index]

+

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

+
CL_EXPORT uint64_t CL_API
+cl_get_time_stamp( void );
+
+

RETURN VALUE

+
       Time elapsed, in microseconds, since the system was booted.
+
+

SEE ALSO

+
       Timer, cl_get_time_stamp_usec, cl_get_time_stamp_sec
+
+
+
+ +

[Functions] +Component Library: Time Stamp/cl_get_time_stamp_sec

+ +

[top][index]

+

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

+
CL_EXPORT uint32_t CL_API
+cl_get_time_stamp_sec( void );
+
+

RETURN VALUE

+
       Time elapsed, in seconds, since the system was booted.
+
+

SEE ALSO

+
       Timer, cl_get_time_stamp
+
+
+
+ +

[Functions] +Component Library: Time Stamp/cl_get_time_stamp_usec

+ +

[top][index]

+

NAME

+
       cl_get_time_stamp_usec
+
+

DESCRIPTION

+
       The cl_get_time_stamp_usec function returns the current time stamp in
+       microseconds since the system was booted.
+
+

SYNOPSIS

+
CL_INLINE uint64_t CL_API
+cl_get_time_stamp_usec( void )
+{
+        return cl_get_time_stamp();
+}
+
+

RETURN VALUE

+
       Time elapsed, in microseconds, since the system was booted.
+
+

SEE ALSO

+
       Timer, cl_get_time_stamp, cl_get_time_stamp_sec
+
+
+
+ +

[Definitions] +Component Library: Timer/cl_pfn_timer_callback_t

+ +

[top][index]

+

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_API *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
+
+
+
+ +

[Functions] +Component Library: Timer/cl_timer_construct

+ +

[top][index]

+

NAME

+
       cl_timer_construct
+
+

DESCRIPTION

+
       The cl_timer_construct function initializes the state of a timer.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Timer/cl_timer_destroy

+ +

[top][index]

+

NAME

+
       cl_timer_destroy
+
+

DESCRIPTION

+
       The cl_timer_destroy function performs any necessary cleanup of a timer.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Timer/cl_timer_init

+ +

[top][index]

+

NAME

+
       cl_timer_init
+
+

DESCRIPTION

+
       The cl_timer_init function initializes a timer for use.
+
+

SYNOPSIS

+
CL_EXPORT cl_status_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Timer/cl_timer_start

+ +

[top][index]

+

NAME

+
       cl_timer_start
+
+

DESCRIPTION

+
       The cl_timer_start function sets a timer to expire after a given interval.
+
+

SYNOPSIS

+
CL_EXPORT cl_status_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Timer/cl_timer_stop

+ +

[top][index]

+

NAME

+
       cl_timer_stop
+
+

DESCRIPTION

+
       The cl_timer_stop function stops a pending timer from expiring.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Timer/cl_timer_trim

+ +

[top][index]

+

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_EXPORT cl_status_t CL_API
+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 reseting 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
+
+
+ + diff --git a/branches/WOF2-3/docs/complib/cl_types_h.html b/branches/WOF2-3/docs/complib/cl_types_h.html new file mode 100644 index 00000000..fc26528f --- /dev/null +++ b/branches/WOF2-3/docs/complib/cl_types_h.html @@ -0,0 +1,410 @@ + + + + +./inc_docs/complib/cl_types_h.html + + + + +Generated from ./inc/complib/cl_types.h with ROBODoc v4.99.17 on Sun Mar 04 2007 18:17:51 +
+
+ +

[Definitions] +Component Library/Data Types

+ +

[top][parent][index]

+

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.
+
+
+
+ +

[Definitions] +Component Library/Object States

+ +

[top][parent][index]

+

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.
+
+
+
+ +

[Definitions] +Component Library/Parameter Keywords

+ +

[top][parent][index]

+

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.
+
+
+
+ +

[Definitions] +Component Library: Data Types/CL_STATUS_MSG

+ +

[top][index]

+

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
+
+
+
+ +

[Definitions] +Component Library: Data Types/cl_status_t

+ +

[top][index]

+

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_INVALID_REQUEST,
+
+        CL_STATUS_COUNT                 /* should be the last value */
+
+} cl_status_t;
+
+

SEE ALSO

+
       Data Types, CL_STATUS_MSG
+
+
+
+ +

[Functions] +Component Library: Error Trapping/cl_panic

+ +

[top][index]

+

NAME

+
       cl_panic
+
+

DESCRIPTION

+
       Halts execution of the current process.  Halts the system if called in
+       from the kernel.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+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.
+
+
+
+ +

[Definitions] +Component Library: Object States/cl_is_state_valid

+ +

[top][index]

+

NAME

+
       cl_is_state_valid
+
+

DESCRIPTION

+
       The cl_is_state_valid function returns whether a state has a valid value.
+
+

SYNOPSIS

+
CL_INLINE boolean_t CL_API
+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
+
+
+
+ +

[Definitions] +Component Library: Pointer Manipulation/offsetof

+ +

[top][index]

+

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
+
+
+
+ +

[Definitions] +Component Library: Pointer Manipulation/PARENT_STRUCT

+ +

[top][index]

+

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
+
+
+
+ +

[Definitions] +Component Library: Unreferenced Parameters/UNUSED_PARAM

+ +

[top][index]

+

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 );
+       }
+
+
+ + diff --git a/branches/WOF2-3/docs/complib/cl_vector_h.html b/branches/WOF2-3/docs/complib/cl_vector_h.html new file mode 100644 index 00000000..e316bdcd --- /dev/null +++ b/branches/WOF2-3/docs/complib/cl_vector_h.html @@ -0,0 +1,984 @@ + + + + +./inc_docs/complib/cl_vector_h.html + + + + +Generated from ./inc/complib/cl_vector.h with ROBODoc v4.99.17 on Sun Mar 04 2007 18:17:51 +
+
+ +

[Modules] +Component Library/Vector

+ +

[top][parent][index]

+

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
+
+
+
+ +

[Definitions] +Component Library: Vector/cl_pfn_vec_apply_t

+ +

[top][index]

+

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_API *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
+
+
+
+ +

[Definitions] +Component Library: Vector/cl_pfn_vec_dtor_t

+ +

[top][index]

+

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_API *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
+
+
+
+ +

[Definitions] +Component Library: Vector/cl_pfn_vec_find_t

+ +

[top][index]

+

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_API *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
+
+
+
+ +

[Definitions] +Component Library: Vector/cl_pfn_vec_init_t

+ +

[top][index]

+

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_API *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
+
+
+
+ +

[Functions] +Component Library: Vector/cl_vector_apply_func

+ +

[top][index]

+

NAME

+
       cl_vector_apply_func
+
+

DESCRIPTION

+
       The cl_vector_apply_func function invokes a specified function for every
+       element in a vector.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Vector/cl_vector_at

+ +

[top][index]

+

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_EXPORT cl_status_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Vector/cl_vector_construct

+ +

[top][index]

+

NAME

+
       cl_vector_construct
+
+

DESCRIPTION

+
       The cl_vector_construct function constructs a vector.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Vector/cl_vector_destroy

+ +

[top][index]

+

NAME

+
       cl_vector_destroy
+
+

DESCRIPTION

+
       The cl_vector_destroy function destroys a vector.
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Vector/cl_vector_find_from_end

+ +

[top][index]

+

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

+
CL_EXPORT size_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Vector/cl_vector_find_from_start

+ +

[top][index]

+

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

+
CL_EXPORT size_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Vector/cl_vector_get

+ +

[top][index]

+

NAME

+
       cl_vector_get
+
+

DESCRIPTION

+
       The cl_vector_get function copies an element stored in a vector at a
+       specified index.
+
+

SYNOPSIS

+
CL_INLINE void CL_API
+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_element, p_src, 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
+
+
+
+ +

[Functions] +Component Library: Vector/cl_vector_get_capacity

+ +

[top][index]

+

NAME

+
       cl_vector_get_capacity
+
+

DESCRIPTION

+
       The cl_vector_get_capacity function returns the capacity of a vector.
+
+

SYNOPSIS

+
CL_INLINE size_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Vector/cl_vector_get_ptr

+ +

[top][index]

+

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

+
CL_INLINE void* CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Vector/cl_vector_get_size

+ +

[top][index]

+

NAME

+
       cl_vector_get_size
+
+

DESCRIPTION

+
       The cl_vector_get_size function returns the size of a vector.
+
+

SYNOPSIS

+
CL_INLINE size_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Vector/cl_vector_init

+ +

[top][index]

+

NAME

+
       cl_vector_init
+
+

DESCRIPTION

+
       The cl_vector_init function initializes a vector for use.
+
+

SYNOPSIS

+
CL_EXPORT cl_status_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Vector/cl_vector_set

+ +

[top][index]

+

NAME

+
       cl_vector_set
+
+

DESCRIPTION

+
       The cl_vector_set function sets the element at the specified index.
+
+

SYNOPSIS

+
CL_EXPORT cl_status_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Vector/cl_vector_set_capacity

+ +

[top][index]

+

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_EXPORT cl_status_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Vector/cl_vector_set_min_size

+ +

[top][index]

+

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_EXPORT cl_status_t CL_API
+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
+
+
+
+ +

[Functions] +Component Library: Vector/cl_vector_set_size

+ +

[top][index]

+

NAME

+
       cl_vector_set_size
+
+

DESCRIPTION

+
       The cl_vector_set_size function resizes a vector, either increasing or
+       decreasing its size.
+
+

SYNOPSIS

+
CL_EXPORT cl_status_t CL_API
+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
+
+
+
+ +

[Structures] +Component Library: Vector/cl_vector_t

+ +

[top][index]

+

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
+
+
+ + diff --git a/branches/WOF2-3/docs/complib/cl_waitobj_h.html b/branches/WOF2-3/docs/complib/cl_waitobj_h.html new file mode 100644 index 00000000..d09adb96 --- /dev/null +++ b/branches/WOF2-3/docs/complib/cl_waitobj_h.html @@ -0,0 +1,356 @@ + + + + +./inc_docs/complib/cl_waitobj_h.html + + + + +Generated from ./inc/complib/cl_waitobj.h with ROBODoc v4.99.17 on Sun Mar 04 2007 18:17:51 +
+
+ +

[Modules] +Component Library/Wait Object

+ +

[top][parent][index]

+

NAME

+
       Wait Object
+
+

DESCRIPTION

+
       The Wait Object provides the capability for a user mode process to
+       create and manipulate a wait object that can also be manipulated from
+       kernel mode.
+
+

SEE ALSO

+
       Structures:
+               cl_waitobj_handle_t
+
+       User Mode Initialization/Destruction:
+               cl_waitobj_create
+               cl_waitobj_destroy
+
+       Kernel Mode Access:
+               cl_waitobj_ref
+               cl_waitobj_deref
+
+       Manipulation:
+               cl_waitobj_signal
+               cl_waitobj_reset
+               cl_waitobj_wait_on
+
+
+
+ +

[Functions] +Component Library: Wait Object/cl_waitobj_create

+ +

[top][index]

+

NAME

+
       cl_waitobj_create
+
+

DESCRIPTION

+
       The cl_waitobj_create function creates a wait object.
+
+

SYNOPSIS

+
CL_EXPORT cl_status_t CL_API
+cl_waitobj_create(
+        IN      const boolean_t                         manual_reset, 
+        OUT     cl_waitobj_handle_t* const      ph_wait_obj );
+
+

PARAMETERS

+
       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.
+
+       ph_wait_obj
+               [out] Pointer to a wait object handle set upon successful creation.
+
+ RETURN VALUES
+       CL_SUCCESS if the wait object was created successfully.
+
+       CL_ERROR if the wait object creation failed.
+
+

NOTES

+
       This function is only available in user mode.
+
+

SEE ALSO

+
       Wait Object, cl_waitobj_handle_t, cl_waitobj_destroy, 
+       cl_waitobj_signal, cl_waitobj_reset, cl_waitobj_wait_on
+
+
+
+ +

[Functions] +Component Library: Wait Object/cl_waitobj_deref

+ +

[top][index]

+

NAME

+
       cl_waitobj_deref
+
+

DESCRIPTION

+
       The cl_waitobj_deref function release a reference on a kernel mode 
+       wait object handle and allows the wait object to be destroyed.
+                                                               
+
+

SYNOPSIS

+
CL_EXPORT void CL_API
+cl_waitobj_deref(
+        IN      cl_waitobj_handle_t     h_kernel_wait_obj );
+
+

PARAMETERS

+
       h_kernel_wait_obj
+               [in] A wait object handle returned by a previous call to cl_waitobj_ref. 
+
+ RETURN VALUES
+       This function does not return a value.
+
+

NOTES

+
       This function is only available in kernel mode.
+
+

SEE ALSO

+
       Wait Object, cl_waitobj_handle_t, cl_waitobj_ref, 
+       cl_waitobj_signal, cl_waitobj_reset, cl_waitobj_wait_on
+
+
+
+ +

[Functions] +Component Library: Wait Object/cl_waitobj_destroy

+ +

[top][index]

+

NAME

+
       cl_waitobj_destroy
+
+

DESCRIPTION

+
       The cl_waitobj_destroy function destroys a wait object.
+
+

SYNOPSIS

+
CL_EXPORT cl_status_t CL_API
+cl_waitobj_destroy(
+        IN      cl_waitobj_handle_t     h_wait_obj );
+
+

PARAMETERS

+
       h_wait_obj
+               [in] A handle to the wait object to destroy, obtained by a pervious
+               call to cl_waitobj_create.
+
+ RETURN VALUES
+       CL_SUCCESS if the wait object handle is destroyed.
+
+       CL_INVALID_PARAMETER if the wait object handle is invalid.
+
+

NOTES

+
       This function is only available in user mode.
+
+

SEE ALSO

+
       Wait Object, cl_waitobj_handle_t, cl_waitobj_create, 
+       cl_waitobj_signal, cl_waitobj_reset, cl_waitobj_wait_on
+
+
+
+ +

[Definitions] +Component Library: Wait Object/cl_waitobj_handle_t

+ +

[top][index]

+

NAME

+
       cl_waitobj_handle_t
+
+

DESCRIPTION

+
       Defines the handle for an OS wait object.
+
+

NOTES

+
       The wait object handle should be treated as opaque and is defined
+       differently depending on the target environment.
+
+

SEE ALSO

+
       Wait Object, cl_waitobj_create, cl_waitobj_destroy,
+       cl_waitobj_ref, cl_waitobj_deref, cl_waitobj_signal,
+       cl_waitobj_reset, cl_waitobj_wait_on
+
+
+
+ +

[Functions] +Component Library: Wait Object/cl_waitobj_ref

+ +

[top][index]

+

NAME

+
       cl_waitobj_ref
+
+

DESCRIPTION

+
       The cl_waitobj_ref function validates a user mode wait object handle 
+       and returns a kernel mode wait object handle.  A reference is taken
+       on the object to prevent its destruction even if the user mode 
+       application destroys it.
+                                                               
+
+

SYNOPSIS

+
CL_EXPORT cl_waitobj_handle_t CL_API
+cl_waitobj_ref(
+        IN      void                                    *h_user_wait_obj );
+
+

PARAMETERS

+
       h_user_wait_obj
+               [in] A wait object handle passed from user mode. 
+
+ RETURN VALUES
+       Returns a kernel wait object handle upon success.  The returned handle 
+       should only be used as parameters to kernel mode calls.
+
+       Returns NULL in case of failure.
+
+

NOTES

+
       This function is only available in kernel mode.
+
+

SEE ALSO

+
       Wait Object, cl_waitobj_handle_t, cl_waitobj_deref,
+       cl_waitobj_signal, cl_waitobj_reset, cl_waitobj_wait_on
+
+
+
+ +

[Functions] +Component Library: Wait Object/cl_waitobj_reset

+ +

[top][index]

+

NAME

+
       cl_waitobj_reset
+
+

DESCRIPTION

+
       The cl_waitobj_reset function sets an wait object to the non-signalled state.
+
+

SYNOPSIS

+
CL_EXPORT cl_status_t CL_API
+cl_waitobj_reset(
+        IN      cl_waitobj_handle_t     h_wait_obj );
+
+

PARAMETERS

+
       h_wait_obj
+               [in] A handle to the wait object that needs to reset.
+
+ RETURN VALUES
+       CL_SUCCESS if the wait object was successfully reset.
+
+       CL_ERROR otherwise.
+
+

NOTES

+
       In kernel mode, a pointer to a cl_event_t can safely be used instead of
+       a wait object handle.
+
+

SEE ALSO

+
       Wait Object, cl_waitobj_create, cl_waitobj_destroy,
+       cl_waitobj_ref, cl_waitobj_deref,
+       cl_waitobj_signal, cl_waitobj_wait_on
+
+
+
+ +

[Functions] +Component Library: Wait Object/cl_waitobj_signal

+ +

[top][index]

+

NAME

+
       cl_waitobj_signal
+
+

DESCRIPTION

+
       The cl_waitobj_signal function sets a wait object to the signalled 
+       state and releases one or more waiting threads.
+
+

SYNOPSIS

+
CL_EXPORT cl_status_t CL_API
+cl_waitobj_signal(
+        IN      cl_waitobj_handle_t     h_wait_obj );
+
+

PARAMETERS

+
       h_wait_obj
+               [in] A handle to the wait object that needs to be signaled.
+ 
+ RETURN VALUES
+       CL_SUCCESS if the event was successfully signalled.
+
+       CL_ERROR otherwise.
+
+

NOTES

+
       For auto-reset wait objects, the wait object is reset automatically once 
+       a wait operation is satisfied. 
+
+       Triggering the wait object multiple times does not guarantee that the same 
+       number of wait operations are satisfied. This is because wait objects are 
+       either in a signalled on non-signalled state, and triggering a wait object 
+       that is already in the signalled state has no effect.
+
+       In kernel mode, a pointer to a cl_event_t can safely be used instead of
+       a wait object handle.
+
+

SEE ALSO

+
       Wait Object, cl_waitobj_create, cl_waitobj_destroy,
+       cl_waitobj_ref, cl_waitobj_deref,
+       cl_waitobj_reset, cl_waitobj_wait_on
+
+
+
+ +

[Functions] +Component Library: Wait Object/cl_waitobj_wait_on

+ +

[top][index]

+

NAME

+
       cl_waitobj_wait_on
+
+

DESCRIPTION

+
       The cl_waitobj_wait_on function waits for the specified wait object to be 
+       triggered for a minimum amount of time.
+
+

SYNOPSIS

+
CL_EXPORT cl_status_t CL_API
+cl_waitobj_wait_on(
+        IN      cl_waitobj_handle_t             h_wait_obj,
+        IN      const uint32_t                  wait_us,
+        IN      const boolean_t                 interruptible );
+
+

PARAMETERS

+
       h_wait_obj
+               [in] A handle to the wait object 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 wait object 
+       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 
+       wait object is triggered and never timeout.
+
+       If the timeout value is zero, this function simply tests the state of 
+       the wait object.
+
+       If the wait object is already in the signalled state at the time of the call
+       to cl_waitobj_wait_on, the call completes immediately with CL_SUCCESS.
+
+       In kernel mode, a pointer to a cl_event_t can safely be used instead of
+       a wait object handle.
+
+

SEE ALSO

+
       Wait Object, cl_waitobj_create, cl_waitobj_destroy,
+       cl_waitobj_ref, cl_waitobj_deref, 
+       cl_waitobj_signal, cl_waitobj_reset
+
+
+ + diff --git a/branches/WOF2-3/docs/complib/comp_lib_h.html b/branches/WOF2-3/docs/complib/comp_lib_h.html new file mode 100644 index 00000000..36e5f2d8 --- /dev/null +++ b/branches/WOF2-3/docs/complib/comp_lib_h.html @@ -0,0 +1,50 @@ + + + + +./inc_docs/complib/comp_lib_h.html + + + + +Generated from ./inc/complib/comp_lib.h with ROBODoc v4.99.17 on Sun Mar 04 2007 18:17:51 +
+
+ +

[Modules] +Component Library/Component Library

+ +

[top][index]

+

NAME

+
       component library 
+
+

DESCRIPTION

+
       The component library is a collection of components that can be used to
+       create complex projects quickly and reliably.
+
+       The component library simplifies development by eliminating the need to
+       re-implement existing functionality. This contributes to shorter
+       development cycles as well as smaller code bases, helping reduce the
+       number of bugs by leveraging tried and tested code.
+
+       The component library also provides the same interface in multiple
+       environments, such as kernel mode and user mode, allowing code to be used
+       in both, again reducing code duplication and development life cycles.
+
+       Components of the library all follow the same usage model, as follows:
+               - The constructor for all components should be called before any other
+               function for that component.  It is acceptable to call the initializer
+               without first calling the constructor.
+
+               - The initializer for all components must be called successfully
+               before any function manipulating that component is called.
+
+               - The destructor for all components must be called if the initializer
+               was called.
+
+       In a debug build, the components assert that the proper sequence is
+       followed.
+
+
+ + diff --git a/branches/WOF2-3/docs/dontdiff.txt b/branches/WOF2-3/docs/dontdiff.txt new file mode 100644 index 00000000..0aeffb62 --- /dev/null +++ b/branches/WOF2-3/docs/dontdiff.txt @@ -0,0 +1,27 @@ +entries +format +*.svn-base +*.tmp +*.obj +*.res +*.mac +*.lib +*.pdb +*.sys +*.exe +*.dll +*.exp +*.tmh +*.tpl +*.log +*.err +*.wrn +*.pch +objchk_* +objfre_* +*.def +*.inc +*.bin +*.rej +*.orig +obj \ No newline at end of file diff --git a/branches/WOF2-3/docs/generate-patch.txt b/branches/WOF2-3/docs/generate-patch.txt new file mode 100644 index 00000000..3210baba --- /dev/null +++ b/branches/WOF2-3/docs/generate-patch.txt @@ -0,0 +1,18 @@ +Patches can be generated using the 'svn diff' utility if the changes are +limited to a single branch in the svn tree. However, to generate a patch +by comparing two branches using a 'diff' program (e.g. GnuWin32 'diff'), +the following syntax will help produce patches that are more easily +reviewable: + +diff -up -r -X trunk\docs\dontdiff.txt -I \$Id: old_path new_path + +For full diff syntax information, see the diff documentation, but as a summary: + +-u provides a unified diff (includes lines around changed lines for context) + p lists the C function name containing the diff +-r does a recursive diff (use when old_path and new_path are directories) +-X excludes files listed in docs\dontdiff from the diff +-I ignores diffs caused by the SVN Id line + +Patches generated using this method can be applied by using a 'patch' program, +such as GnuWin32 'patch'. \ No newline at end of file diff --git a/branches/WOF2-3/docs/iba/ib_al_h.html b/branches/WOF2-3/docs/iba/ib_al_h.html new file mode 100644 index 00000000..3ee78d44 --- /dev/null +++ b/branches/WOF2-3/docs/iba/ib_al_h.html @@ -0,0 +1,10482 @@ + + + + +./inc_docs/iba/ib_al_h.html + + + + +Generated from ./inc/iba/ib_al.h with ROBODoc v4.99.17 on Sun Mar 04 2007 18:17:51 +
+
+ +

[Modules] +IB Access Layer API/Access Layer

+ +

[top][index]

+

NAME

+
       InfiniBand Access Layer
+
+

COPYRIGHT

+
       Copyright (c) 2003 Intel Corporation - All Rights Reserved.
+
+

DESCRIPTION

+
       The access layer provides transport level access to an InfiniBand fabric.
+       It supplies a foundation upon which a channel driver may be built.  The
+       access layer exposes the capabilities of the InfiniBand architecture and
+       adds support for higher-level functionality required by most users of an
+       InfiniBand fabric.  Users define the protocols and policies used by the
+       access layer, and the access layer implements them under the direction
+       of a user.
+
+
+
+ +

[Definitions] +Access Layer/ATS

+ +

[top][parent][index]

+

NAME

+
       DAPL Address Translation Service
+
+

DESCRIPTION

+
       ATS service ID, service name, and IPv4 offset for DAPL-compliant
+       ATS service records.
+
+
+
+ +

[Functions] +Access Layer/ib_add_svc_entry

+ +

[top][parent][index]

+

NAME

+
       ib_add_svc_entry
+
+

DESCRIPTION

+
       Adds a new service entry to an existing I/O controller.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_add_svc_entry(
+        IN              const   ib_ioc_handle_t FUNC_PTR64                         h_ioc,
+        IN              const   ib_svc_entry_t* const           p_svc_entry,
+                OUT                     ib_svc_handle_t FUNC_PTR64* const          ph_svc );
+
+

PARAMETERS

+
       h_ioc
+               [in] A handle to an existing I/O controller that will support the
+               added service.
+
+       p_svc_entry
+               [in] Service entry information that will be reported as part of the
+               controller's service profile.
+
+       ph_svc
+               [out] Upon successful completion of this call, this references a handle
+               to the added service.  This handle may be used to remove the service
+               entry.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The service entry was successfully added.
+
+       IB_INVALID_HANDLE
+               The I/O controller handle was invalid.
+
+       IB_INVALID_PARAMETER
+               A reference to the service entry information or handle was not
+               provided.
+
+       IB_INSUFFICIENT_MEMORY
+               There was insufficient memory to register the service entry.
+
+       IB_INSUFFICIENT_RESOURCES
+               There were insufficient resources currently available on the I/O
+               controller to register the service entry.
+
+

NOTES

+
       This routine adds a new service to an I/O controller.  Once added, the
+       service will be reported with the controller profile, provided that the
+       controller is registered with the local device manager.
+
+

SEE ALSO

+
       ib_create_ioc, ib_remove_svc_entry, ib_reg_ioc, ib_svc_entry_t
+
+
+
+ +

[Definitions] +Access Layer/ib_al_flags_t

+ +

[top][parent][index]

+

NAME

+
       ib_al_flags_t
+
+

DESCRIPTION

+
       Access layer flags used to direct the operation of various calls.
+
+

SYNOPSIS

+
typedef uint32_t                                                        ib_al_flags_t;
+#define IB_FLAGS_SYNC                                           0x00000001
+
+

VALUES

+
       IB_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

+
       ib_cm_req_t, ib_cm_rep_t, ib_cm_dreq_t, ib_cm_lap_t,
+       ib_reg_svc_req_t, ib_mcast_req_t, ib_query_req_t, ib_sub_req_t
+
+
+
+ +

[Functions] +Access Layer/ib_alloc_pd

+ +

[top][parent][index]

+

NAME

+
       ib_alloc_pd
+
+

DESCRIPTION

+
       Allocates a protection domain on the specified channel adapter.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_alloc_pd(
+        IN              const   ib_ca_handle_t FUNC_PTR64                          h_ca,
+        IN              const   ib_pd_type_t                            pd_type,
+        IN              const   void* const                                     pd_context,
+                OUT                     ib_pd_handle_t FUNC_PTR64* const           ph_pd );
+
+

PARAMETERS

+
       h_ca
+               [in] A handle to an opened channel adapter.
+
+       pd_type
+               [in] Indicates the type of protection domain being created.
+
+       pd_context
+               [in] A client-specified context to associate with this allocated
+               protection domain.  This context is returned to the user when
+               invoking asynchronous callbacks referencing this protection domain.
+
+       ph_pd
+               [out] Upon successful completion of this call, this references a
+               handle to the allocated protection domain.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The operation was successful.
+
+       IB_INVALID_CA_HANDLE
+               The channel adapter handle was invalid.
+
+       IB_INVALID_PARAMETER
+               The supplied pd_type value is invalid or a reference to the protection
+               domain handle was not provided.
+
+       IB_INSUFFICIENT_MEMORY
+               There was insufficient memory to allocate the protection domain.
+
+       IB_INSUFFICIENT_RESOURCES
+               There were insufficient resources currently available on the channel
+               adapter to create the protection domain.
+
+

NOTES

+
       When successful, this routine returns a handle to a newly allocated
+       protection domain.
+
+

SEE ALSO

+
       ib_dealloc_pd, ib_pd_type_t
+
+
+
+ +

[Structures] +Access Layer/ib_apr_info_t

+ +

[top][parent][index]

+

NAME

+
       ib_apr_info_t
+
+

DESCRIPTION

+
       Infiniband-defined additional rejection information.
+
+

SYNOPSIS

+
typedef ib_al_handle_tpr_info
+{
+        uint8_t                                         data[IB_APR_INFO_SIZE];
+
+}       ib_apr_info_t;
+
+

SEE ALSO

+
       ib_cm_data_sizes_t
+
+
+
+ +

[Structures] +Access Layer/ib_apr_pdata_t

+ +

[top][parent][index]

+

NAME

+
       ib_apr_pdata_t
+
+

DESCRIPTION

+
       User data sent as part of an alternate path response.
+
+

SYNOPSIS

+
typedef union _ib_apr_pdata
+{
+        uint8_t                                         data[IB_APR_PDATA_SIZE];
+
+}       ib_apr_pdata_t;
+
+

SEE ALSO

+
       ib_cm_data_sizes_t
+
+
+
+ +

[Structures] +Access Layer/ib_ari_t

+ +

[top][parent][index]

+

NAME

+
       ib_ari_t
+
+

DESCRIPTION

+
       Infiniband-defined additional rejection information.
+
+

SYNOPSIS

+
typedef ib_al_handle_tri
+{
+        uint8_t                                         data[IB_ARI_SIZE];
+
+}       ib_ari_t;
+
+

SEE ALSO

+
       ib_cm_data_sizes_t
+
+
+
+ +

[Structures] +Access Layer/ib_async_event_rec_t

+ +

[top][parent][index]

+

NAME

+
       ib_async_event_rec_t
+
+

DESCRIPTION

+
       Information returned when an asynchronous event occurs on an allocated
+       resource.
+
+

SYNOPSIS

+
typedef ib_al_handle_tsync_event_rec
+{
+        ib_async_event_t                                                        code;
+        uint64_t                                                                        vendor_specific;
+
+ TO_LONG_PTR(       void* ,                                                           context) ; 
+        union _handle_t
+        {
+                ib_ca_handle_t __ptr64                                                  h_ca;
+                ib_cq_handle_t __ptr64                                                  h_cq;
+                ib_qp_handle_t __ptr64                                                  h_qp;
+                ib_srq_handle_t __ptr64                                                 h_srq;
+
+        } handle;
+
+}       ib_async_event_rec_t;
+
+

FIELDS

+
       code
+               A code that identifies the type of event being reported.
+
+       vendor_specific
+               A field containing optional vendor specific information.
+
+       context
+               User-defined context information associated with the resource on
+               which the error occurred.
+
+       handle
+               A handle to the resource for which this event record was generated.
+               This handle will match the handle returned during the creation of
+               resource.  It is provided in case an event occurs before a client's
+               call to create a resource can return.
+
+

SEE ALSO

+
       ib_async_event_t, ib_pfn_event_cb_t
+
+
+
+ +

[Functions] +Access Layer/ib_bind_mw

+ +

[top][parent][index]

+

NAME

+
       ib_bind_mw
+
+

DESCRIPTION

+
       Binds a memory window to a registered memory region.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_bind_mw(
+        IN              const   ib_mw_handle_t FUNC_PTR64                          h_mw,
+        IN              const   ib_qp_handle_t FUNC_PTR64                          h_qp,
+        IN                              ib_bind_wr_t* const                     p_mw_bind,
+                OUT                     net32_t* const                          p_rkey );
+
+

PARAMETERS

+
       h_mw
+               [in] A handle to an existing memory window.
+
+       h_qp
+               [in] A handle to a queue pair that the bind request will be posted to.
+
+       p_mw_bind
+               [in] Describes the memory window bind request.
+
+       p_rkey
+               [out] The new rkey for the memory window that may be used by a remote
+               end-point when performing RDMA or atomic operations to this memory
+               region.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The memory window bind operation was successfully posted.
+
+       IB_INVALID_MW_HANDLE
+               The memory window handle was invalid.
+
+       IB_INVALID_QP_HANDLE
+               The queue pair handle was invalid.
+
+       IB_INVALID_PARAMETER
+               A reference to the memory window bind work request or rkey was not
+               provided.
+
+       IB_INVALID_SERVICE_TYPE
+               The queue pair configuration does not support this type of service.
+
+       IB_INVALID_MR_HANDLE
+               The memory region handle was invalid.
+
+       IB_INVALID_RKEY
+               The rkey is invalid for the memory region being bound.
+
+       IB_UNSUPPORTED
+               The requested access rights are not supported by the channel adapter.
+
+       IB_INVALID_PERMISSION
+               The requested access rights are invalid.
+
+       IB_INSUFFICIENT_RESOURCES
+               There were insufficient resources currently available on the channel
+               adapter to bind the memory window.
+
+

NOTES

+
       This routine posts a request to bind a memory window to a registered
+       memory region.  The bind operation occurs on the specified queue pair,
+       but the bound region is usable across all queue pairs within the same
+       protection domain.
+
+

SEE ALSO

+
       ib_create_mw, ib_bind_wr_t
+
+
+
+ +

[Functions] +Access Layer/ib_cancel_mad

+ +

[top][parent][index]

+

NAME

+
       ib_cancel_mad
+
+

DESCRIPTION

+
       This routine cancels a pending send transaction to a MAD service.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_cancel_mad(
+        IN              const   ib_mad_svc_handle_t FUNC_PTR64                     h_mad_svc,
+        IN                              ib_mad_element_t* const         p_mad_element );
+
+

PARAMETERS

+
       h_mad_svc
+               [in] The MAD service to which the send operation was directed.
+
+       p_mad_element
+               [in] A handle to a sent MAD element.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The requested MAD transaction was located and canceled.
+
+       IB_INVALID_PARAMETER
+               A reference to the MAD element list was not provided.
+
+       IB_NOT_FOUND
+               The requested transaction was not located or had already completed.
+
+

NOTES

+
       This routine cancels a pending send transaction to a MAD service.  If
+       the request is successfully located and has not yet completed, it will
+       be completed with its status set to IB_CANCELED.  The canceled operation
+       will be returned to the user through the normal MAD completion callback.
+       If the send transaction has already completed, this call will return
+       IB_NOT_FOUND.
+
+

SEE ALSO

+
       ib_send_mad
+
+
+
+ +

[Functions] +Access Layer/ib_cancel_query

+ +

[top][parent][index]

+

NAME

+
       ib_cancel_query
+
+

DESCRIPTION

+
       Routine used to cancel a query of the subnet administrator.
+
+

SYNOPSIS

+
AL_EXPORT void AL_API
+ib_cancel_query(
+        IN              const   ib_al_handle_t FUNC_PTR64                          h_al,
+        IN              const   ib_query_handle_t FUNC_PTR64                       h_query );
+
+

PARAMETERS

+
       h_al
+               [in] A handle to an open instance of the access layer.
+
+       h_query
+               [in] Query handle returned by a previous call to ib_query().
+
+ RETURN VALUES
+       This function does not return a value.
+
+

NOTES

+
       This routine directs the access layer to cancel a query to the subnet
+       administrator.  The access layer will issue notify the user with the
+       final status of the query through the query callback specified in the
+       call to ib_query().
+
+

SEE ALSO

+
       ib_query
+
+
+
+ +

[Structures] +Access Layer/ib_cep_listen_t

+ +

[top][parent][index]

+

NAME

+
       ib_cep_listen_t
+
+

DESCRIPTION

+
       Request to listen for incoming connection attempts.
+
+

SYNOPSIS

+
typedef struct _ib_cep_listen
+{
+        net64_t                                         svc_id;
+
+        net64_t                                         port_guid;
+
+ TO_LONG_PTR(       uint8_t* ,                        p_cmp_buf) ; 
+        uint8_t                                         cmp_len;
+        uint8_t                                         cmp_offset;
+
+}       ib_cep_listen_t;
+
+

FIELDS

+
       svc_id
+               The identifier of the service to register for incoming connection
+               requests.
+
+       port_guid
+               Directs the communication manager to register the listen only
+               with the specified port.  This should be set to IB_ALL_PORTS
+               if the listen is not directed to a particular port.
+
+       p_cmp_buf
+               An optionally provided buffer that will be used to match incoming
+               connection requests with a registered service.  Use of this buffer
+               permits multiple services to listen on the same service ID as long as
+               they provide different compare buffers.  Incoming requests will
+               be matched against the compare buffer.
+
+       cmp_len
+               Specifies the size of the compare buffer in bytes.  The length must
+               be the same for all requests using the same service ID.
+
+       cmp_offset
+               An offset into the user-defined data area of a connection request
+               which contains the start of the data that will be compared against.
+               The offset must be the same for all requests using the same service ID.
+
+

NOTES

+
       Users fill out this structure when listening on a service ID with the
+       local communication manager.  The communication manager will use the given
+       service ID and compare buffer to route connection requests to the
+       appropriate client.  Users may direct listens requests on a particular
+       channel adapter, port, or LID.
+
+
+
+ +

[Functions] +Access Layer/ib_ci_call

+ +

[top][parent][index]

+

NAME

+
       ib_ci_call
+
+

DESCRIPTION

+
       Performs a vendor specific CA interface function call.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_ci_call(
+        IN                              ib_ca_handle_t FUNC_PTR64                          h_ca,
+        IN              const   void* FUNC_PTR64 *         const   handle_array    OPTIONAL,
+        IN                              uint32_t                                        num_handles,
+        IN                              ib_ci_op_t*                     const   p_ci_op );
+
+

PARAMETERS

+
       h_ca
+               [in] An opened instance of a channel adapter.
+
+       handle_array
+               [in] This parameter references an array containing handles of
+               existing CA resources.  This array should contain all of the
+               handles specified in the vendor specific data provided with this
+               call.  All handles specified through this array are validated by
+               the access layer as existing and belonging to the calling process.
+               The verbs provider driver is responsible for verifying that the
+               number and type of handles are correct for the requested operation.
+
+       num_handles
+               [in] The number of the handles in handle array.  This count is
+               verified by the access layer.
+
+       p_ci_op
+               [in] A reference to the vendor specific CA interface data
+               structure containing the operation parameters.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The operation was successful.
+
+       IB_INVALID_CA_HANDLE
+               The specified CA handle was invalid.
+
+       IB_INVALID_PARAMETER
+               A reference to the vendor specific data was not provided.
+
+       IB_INVALID_HANDLE
+               A handle specified in the handle array was invalid.
+
+       IB_INSUFFICIENT_MEMORY
+               There was insufficient memory to perform the operation.
+
+       IB_ERROR
+               An error occurred while processing the command.  Additional
+               error information is provided in the p_ci_op status field.
+
+

NOTES

+
       This routine performs a vendor specific CA interface function call.
+       The optional p_ci_op structure provides a means to pass vendor
+       specific parameters and data to the verbs provider driver.  If the
+       vendor specific data contains handles, the client should provide the
+       optional handle array that lists all of the handles specified in the
+       vendor specific data.  The handles in the handle array are restricted
+       to the following types:  ib_pd_handle_t __ptr64, ib_cq_handle_t __ptr64,
+       ib_av_handle_t __ptr64, ib_qp_handle_t __ptr64, ib_mr_handle_t __ptr64, or ib_mw_handle_t __ptr64.
+       The contents of the handle array are verified by the access layer and
+       the verbs provider driver.  This call cannot be used to allocate private
+       handles that are passed as parameters in access layer calls.
+
+

SEE ALSO

+
       ib_open_ca, ib_alloc_pd, ib_create_av, ib_create_cq,
+       ib_create_qp, ib_reg_mr, ib_reg_phys, ib_reg_shared,
+       ib_create_mw, ib_ci_op_t
+
+
+
+ +

[Functions] +Access Layer/ib_close_al

+ +

[top][parent][index]

+

NAME

+
       ib_close_al
+
+

DESCRIPTION

+
       Deregisters a channel driver with the access layer and releases all
+       associated resources, including queue pairs, connection requests,
+       and completion queues.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_close_al(
+        IN              const   ib_al_handle_t FUNC_PTR64                          h_al );
+
+

PARAMETERS

+
       h_al
+               [in] A handle to an instance of the access layer.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The access layer was closed successfully.
+
+       IB_INVALID_AL_HANDLE
+               The access layer handle was invalid.
+
+

NOTES

+
       This call destroys an existing instance of the access layer.  Since
+       callbacks may be outstanding against the resources managed by this
+       access layer instance when the destroy operation is invoked, this
+       call may block until all outstanding callbacks complete.  This
+       routine may not be called from a callback invoked by the access layer.
+
+

SEE ALSO

+
       ib_open_al
+
+
+
+ +

[Functions] +Access Layer/ib_close_ca

+ +

[top][parent][index]

+

NAME

+
       ib_close_ca
+
+

DESCRIPTION

+
       Closes an opened channel adapter.  Once closed, no further access to this
+       channel adapter is possible.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_close_ca(
+        IN              const   ib_ca_handle_t FUNC_PTR64                          h_ca,
+        IN              const   ib_pfn_destroy_cb_t                     pfn_destroy_cb OPTIONAL );
+
+

PARAMETERS

+
       h_ca
+               [in] A handle to an opened channel adapter.
+
+       pfn_destroy_cb
+               [in] A user-specified callback that is invoked after the channel
+               adapter has been successfully destroyed.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The close request was registered.
+
+       IB_INVALID_CA_HANDLE
+               The channel adapter handle was invalid.
+
+

NOTES

+
       This call closes the opened channel adapter and frees all associated
+       resources, such as queue pairs, protection domains, and completion
+       queues.  Since callbacks may be outstanding against the channel adapter
+       or one of its resources at the time the close operation is invoked, this
+       call operates asynchronously.  The user will be notified through a callback
+       once the close operation completes, indicating that no additional callbacks
+       will be invoked for the specified channel adapter or a related resource.
+
+

SEE ALSO

+
       ib_open_ca
+
+
+
+ +

[Functions] +Access Layer/ib_cm_apr

+ +

[top][parent][index]

+

NAME

+
       ib_cm_apr
+
+

DESCRIPTION

+
       Responds to a load alternate path request, to accept or reject the
+       proposed alternate path.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_cm_apr(
+        IN              const   ib_cm_handle_t                          h_cm_lap,
+        IN              const   ib_cm_apr_t* const                      p_cm_apr );
+
+

PARAMETERS

+
       h_cm_lap
+               [in] A handle to a load alternate path request corresponding to the
+               response.  This handle is provided through the ib_pfn_cm_lap_cb_t.
+
+       p_cm_apr
+               [in] Information describing the alternate path response.  The response
+               will accept or reject the load request.  If the request is rejected
+               this parameter will reference additional rejection information.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The load alternate path response was sent successfully.
+
+       IB_INVALID_HANDLE
+               The connection manager load alternate path handle was invalid.
+
+       IB_INVALID_PARAMETER
+               A reference to the alternate path information was not provided.
+
+       IB_INVALID_STATE
+               The current connection state does not allow sending this message.
+
+       IB_INVALID_SETTING
+               The private data length specified in alternate path information is
+               invalid.
+
+       IB_INVALID_QP_HANDLE
+               The queue pair handle specified in the alternate path information
+               was invalid.
+
+       IB_INSUFFICIENT_MEMORY
+               There was insufficient memory to send the alternate path response.
+
+

NOTES

+
       This routine responds to a load alternate path request.
+
+

SEE ALSO

+
       ib_cm_lap, ib_cm_apr_t, ib_pfn_cm_lap_cb_t, ib_pfn_cm_apr_cb_t
+
+
+
+ +

[Structures] +Access Layer/ib_cm_apr_rec_t

+ +

[top][parent][index]

+

NAME

+
       ib_cm_apr_rec_t
+
+

DESCRIPTION

+
       Load alternate path response information returned to the user through
+       a callback.
+
+

SYNOPSIS

+
typedef struct _ib_cm_apr_rec
+{
+        ib_api_status_t                         cm_status;
+        ib_apr_status_t                         apr_status;
+
+ TO_LONG_PTR(       const uint8_t* ,          p_info) ; 
+        uint8_t                                         info_length;
+
+ TO_LONG_PTR(       const uint8_t* ,          p_apr_pdata) ; 
+
+        ib_qp_handle_t __ptr64                          h_qp;
+ TO_LONG_PTR(       const void* ,                     qp_context) ; 
+
+}       ib_cm_apr_rec_t;
+
+

FIELDS

+
       cm_status
+               The status of the alternate path response.  IB_SUCCESS indicates that
+               the alternate path was loaded successfully.  IB_TIMEOUT indicates that
+               a reply was not received within the specified timeout and retry count.
+               Other error values indicates that the alternate path was not loaded.
+               if the apr_status is IB_AP_SUCCESS, the QP failed to load the path.
+               Other apr_status values indicate that the request was rejected for some
+               reason.
+
+       apr_status
+               The alternate path response status.  This indicates additional failure
+               information to a load alternate path request and is defined by the
+               InfiniBand specification.
+
+       info_length
+               Length of valid data in the APR additional information buffer.
+
+       p_info
+               APR additional information.
+
+       p_apr_pdata
+               A reference to user-defined private data sent as part of the alternate
+               path response.
+
+       h_qp
+               The queue pair handle associated with the alternate path response.
+
+       qp_context
+               The queue pair context associated with the alternate path response.
+
+

SEE ALSO

+
       ib_cm_lap, ib_pfn_cm_apr_cb_t, ib_apr_status_t, ib_apr_info_t
+       ib_apr_pdata_t, ib_qp_type_t
+
+
+
+ +

[Structures] +Access Layer/ib_cm_apr_t

+ +

[top][parent][index]

+

NAME

+
       ib_cm_apr_t
+
+

DESCRIPTION

+
       Load alternate path information used to configure a queue pair with an
+       alternate path.
+
+

SYNOPSIS

+
typedef struct _ib_cm_apr
+{
+ TO_LONG_PTR(       const uint8_t* ,                  p_apr_pdata) ; 
+        uint8_t                                                 apr_length;
+
+        ib_qp_type_t                                    qp_type;
+
+        /* valid for rc, uc & rd qp_type only */
+        ib_qp_handle_t __ptr64                                  h_qp;
+
+        ib_apr_status_t                                 apr_status;
+        uint8_t                                                 info_length;
+ TO_LONG_PTR(       const ib_apr_info_t* ,    p_info) ; 
+
+}       ib_cm_apr_t;
+
+

FIELDS

+
       p_apr_pdata
+               Optional user-defined private data sent as part of the alternate
+               path response message.
+
+       apr_length
+               Defines the size of the user-defined private data.
+
+       qp_type
+               Indicates the CM service type.
+
+       h_qp
+               A handle to the queue pair that should receive the alternate path.
+
+       apr_status
+               The alternate path response status.  This indicates additional failure
+               information to a load alternate path request and is defined by the
+               Infiniband specification.
+
+       info_length
+               Length of valid data in the APR additional information buffer.
+
+       p_info
+               APR additional information.
+
+

SEE ALSO

+
       ib_cm_apr, ib_pfn_cm_apr_cb_t, ib_lap_pdata_t, ib_qp_type_t
+
+
+
+ +

[Functions] +Access Layer/ib_cm_cancel

+ +

[top][parent][index]

+

NAME

+
       ib_cm_cancel
+
+

DESCRIPTION

+
       Routine used to cancel listening for connection requests.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_cm_cancel(
+        IN              const   ib_listen_handle_t FUNC_PTR64                      h_cm_listen,
+        IN              const   ib_pfn_destroy_cb_t                     pfn_destroy_cb OPTIONAL );
+
+

PARAMETERS

+
       h_cm_listen
+               [in] A handle to an existing listen request.
+
+       pfn_destroy_cb
+               [in] A user-specified callback that is invoked after the listen
+               request has been successfully canceled.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The cancel listen operation was initiated.
+
+       IB_INVALID_HANDLE
+               The connection manager handle was invalid.
+
+

NOTES

+
       This routine cancels a listen request.  To avoid a race condition
+       canceling a request at the same time a connection callback is in
+       progress, the cancel operation operates asynchronously.  For
+       additional details see ib_pfn_destroy_cb_t.
+
+

SEE ALSO

+
       ib_cm_listen, ib_pfn_destroy_cb_t
+
+
+
+ +

[Functions] +Access Layer/ib_cm_drep

+ +

[top][parent][index]

+

NAME

+
       ib_cm_drep
+
+

DESCRIPTION

+
       This routine replies to a disconnection request and disconnects
+       a queue pair or end-to-end context.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_cm_drep(
+        IN              const   ib_cm_handle_t                          h_cm_dreq,
+        IN              const   ib_cm_drep_t* const                     p_cm_drep );
+
+

PARAMETERS

+
       h_cm_dreq
+               [in] A handle to a disconnection request being replied to.  This
+               handle is provided through the ib_pfn_cm_dreq_cb_t callback.
+
+       p_cm_drep
+               [in] Reply information used to respond to the disconnection request.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The disconnect request was sent successfully.
+
+       IB_INVALID_HANDLE
+               The connection manager disconnect request handle was invalid.
+
+       IB_INVALID_PARAMETER
+               A reference to the disconnect repy information was not provided.
+
+       IB_INVALID_STATE
+               The current connection state does not allow sending this message.
+
+       IB_INVALID_SETTING
+               The private data length specified in disconnect reply information is
+               invalid.
+
+       IB_INSUFFICIENT_MEMORY
+               There was insufficient memory to send the disconnect reply.
+
+

NOTES

+
       This function will disconnect a queue pair or end-to-end context.  It
+       results in sending a disconnection reply message to the remote end-point.
+       After calling this routine, data transfers on the specified queue pair or
+       end-to-end context will fail.
+
+

SEE ALSO

+
       ib_cm_dreq, ib_pfn_cm_dreq_cb_t, ib_cm_drep_t
+
+
+
+ +

[Structures] +Access Layer/ib_cm_drep_rec_t

+ +

[top][parent][index]

+

NAME

+
       ib_cm_drep_rec_t
+
+

DESCRIPTION

+
       Disconnection reply information returned to the user through their
+       disconnect reply callback.
+
+

SYNOPSIS

+
typedef struct _ib_cm_drep_rec
+{
+        ib_api_status_t                         cm_status;
+
+ TO_LONG_PTR(       const uint8_t* ,          p_drep_pdata) ; 
+
+        ib_qp_handle_t __ptr64                          h_qp;
+ TO_LONG_PTR(       const void* ,                     qp_context) ; 
+
+}       ib_cm_drep_rec_t;
+
+

FIELDS

+
       cm_status
+               The status of the disconnect request.  Valid values are IB_SUCCESS
+               and IB_TIMEOUT.  IB_TIMEOUT indicates that a reply was not received
+               within the specified timeout and retry count.
+
+       p_drep_pdata
+               A reference to user-defined private data sent as part of the
+               disconnect reply.
+
+       h_qp
+               The queue pair handle associated with the disconnect reply.
+
+       qp_context
+               The queue pair context associated with the disconnect reply.
+
+

SEE ALSO

+
       ib_cm_drep, ib_pfn_cm_drep_cb_t, ib_drep_pdata_t, ib_qp_type_t
+
+
+
+ +

[Structures] +Access Layer/ib_cm_drep_t

+ +

[top][parent][index]

+

NAME

+
       ib_cm_drep_t
+
+

DESCRIPTION

+
       Disconnection reply information used when tearing down a connection.
+
+

SYNOPSIS

+
typedef struct _ib_cm_drep
+{
+ TO_LONG_PTR(       uint8_t* ,                        p_drep_pdata) ; 
+        uint8_t                                         drep_length;
+
+}       ib_cm_drep_t;
+
+

FIELDS

+
       p_drep_pdata
+               A reference to user-defined private data sent as part of the
+               disconnection reply.
+
+       drep_length
+               Defines the size of the user-defined private data.
+
+

SEE ALSO

+
       ib_cm_drep, ib_drep_pdata_t
+
+
+
+ +

[Functions] +Access Layer/ib_cm_dreq

+ +

[top][parent][index]

+

NAME

+
       ib_cm_dreq
+
+

DESCRIPTION

+
       This routine disconnects a queue pair or end-to-end context.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_cm_dreq(
+        IN              const   ib_cm_dreq_t* const                     p_cm_dreq );
+
+

PARAMETERS

+
       p_cm_dreq
+               [in] Information that describes the connection being disconnected.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The disconnect request was sent successfully.
+
+       IB_INVALID_PARAMETER
+               A reference to the disconnect request information was not provided.
+
+       IB_INVALID_STATE
+               The current connection state does not allow sending this message.
+
+       IB_INVALID_SETTING
+               The private data length specified in disconnect request information is
+               invalid.
+
+       IB_INVALID_QP_HANDLE
+               The queue pair handle specified in the disconnect request information
+               was invalid.
+
+       IB_INSUFFICIENT_MEMORY
+               There was insufficient memory to send the disconnect request.
+
+

NOTES

+
       This function will disconnect a queue pair or end-to-end context.
+       It results in sending a disconnection request message to the remote
+       end-point.  After calling this routine, data transfers on the specified
+       queue pair or end-to-end context will fail.
+
+

SEE ALSO

+
       ib_cm_drep, ib_pfn_cm_dreq_cb_t, ib_cm_dreq_t
+
+
+
+ +

[Structures] +Access Layer/ib_cm_dreq_rec_t

+ +

[top][parent][index]

+

NAME

+
       ib_cm_dreq_rec_t
+
+

DESCRIPTION

+
       Disconnection request information returned to the user through their
+       disconnection callback.
+
+

SYNOPSIS

+
typedef struct _ib_cm_dreq_rec
+{
+        ib_cm_handle_t                          h_cm_dreq;
+
+ TO_LONG_PTR(       const uint8_t* ,          p_dreq_pdata) ; 
+
+ TO_LONG_PTR(       const void* ,                     qp_context) ; 
+
+}       ib_cm_dreq_rec_t;
+
+

FIELDS

+
       h_cm_dreq
+               A handle to the disconnection request.  This handle is used to reply
+               to the disconnection request.
+
+       p_dreq_pdata
+               A reference to user-defined private data sent as part of the
+               disconnect request.
+
+       qp_context
+               The queue pair context associated with the disconnect request.
+
+

SEE ALSO

+
       ib_cm_dreq, ib_pfn_cm_dreq_cb_t, ib_dreq_pdata_t, ib_qp_type_t
+
+
+
+ +

[Structures] +Access Layer/ib_cm_dreq_t

+ +

[top][parent][index]

+

NAME

+
       ib_cm_dreq_t
+
+

DESCRIPTION

+
       Disconnection request information used to tear down a connection.
+
+

SYNOPSIS

+
typedef struct _ib_cm_dreq
+{
+        ib_al_flags_t                           flags;
+
+ TO_LONG_PTR(       uint8_t* ,                        p_dreq_pdata) ; 
+        uint8_t                                         dreq_length;
+
+        ib_qp_type_t                            qp_type;
+
+        /* valid for rc, uc & rd qp_type only */
+        ib_qp_handle_t __ptr64                          h_qp;
+        ib_pfn_cm_drep_cb_t                     pfn_cm_drep_cb;
+
+}       ib_cm_dreq_t;
+
+

FIELDS

+
       flags
+               Used to describe the mode of operation.  Set to IB_FLAGS_SYNC to
+               process the called routine synchronously.
+
+       p_dreq_pdata
+               A reference to user-defined private data sent as part of the
+               disconnection request.
+
+       dreq_length
+               Defines the size of the user-defined private data.
+
+       qp_type
+               Indicates the CM service type.
+
+       h_qp
+               A handle to the queue pair to disconnect.
+
+       pfn_cm_drep_cb
+               References a user-defined callback that will be invoked when
+               the reply to the disconnect is received.
+
+

NOTES

+
       Users submit this structure to disconnect a queue pair or end-to-end
+       context.  A single disconnect call disconnects either a queue pair or
+       an end-to-end context, but not both.
+
+

SEE ALSO

+
       ib_cm_dreq, ib_cm_drep, ib_dreq_pdata_t, ib_al_flags_t,
+       ib_qp_type_t
+
+
+
+ +

[Definitions] +Access Layer/ib_cm_failover_t

+ +

[top][parent][index]

+

NAME

+
       ib_cm_failover_t
+
+

DESCRIPTION

+
       Fail over acceptance status returned as part of a connection reply.
+
+

SYNOPSIS

+
typedef uint8_t                                                         ib_cm_failover_t;
+#define IB_FAILOVER_ACCEPT_SUCCESS                      0
+#define IB_FAILOVER_ACCEPT_UNSUPPORTED          1
+#define IB_FAILOVER_ACCEPT_ERROR                        2
+
+

NOTES

+
       These values and their use are defined the Infiniband specification.
+
+

SEE ALSO

+
       ib_cm_rep, ib_cm_rep_t
+
+
+
+ +

[Functions] +Access Layer/ib_cm_handoff

+ +

[top][parent][index]

+

NAME

+
       ib_cm_handoff
+
+

DESCRIPTION

+
       Hands off the received REQ information to svc_id.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_cm_handoff(
+        IN              const   ib_cm_handle_t                          h_cm_req,
+        IN              const   ib_net64_t                                      svc_id );
+
+

PARAMETERS

+
       h_cm_req
+               [in] A handle to the connection request being handed off.
+               This is the h_cm_req handle provided through the ib_pfn_cm_req_cb_t
+               callback.
+
+       svc_id
+               [in] The service id to which this connection request is handed off.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The handoff was initiated.
+
+       IB_INVALID_HANDLE
+               The connection manager handle was invalid.
+
+       IB_INVALID_PARAMETER
+               A valid service id was not provided.
+
+       IB_INVALID_STATE
+               The current connection state does not allow this transfer.
+
+       IB_INSUFFICIENT_MEMORY
+               There was insufficient memory to complete the request.
+
+

NOTES

+
       This routine results in the access layer handing off the connection
+       to the service id as a new incoming connection.
+
+

SEE ALSO

+
       ib_pfn_cm_req_cb_t, ib_cm_rej_t, ib_cm_listen
+
+
+
+ +

[Functions] +Access Layer/ib_cm_lap

+ +

[top][parent][index]

+

NAME

+
       ib_cm_lap
+
+

DESCRIPTION

+
       Issues a load alternate path request to a specified end-point.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_cm_lap(
+        IN              const   ib_cm_lap_t* const                      p_cm_lap );
+
+

PARAMETERS

+
       p_cm_lap
+               [in] Information describing the alternate path to load and the remote
+               endpoint for the connection.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The load alternate path request was sent successfully.
+
+       IB_INVALID_PARAMETER
+               A reference to the load alternate path information was not provided.
+
+       IB_UNSUPPORTED
+               The passive side of the connection attempted to load an alternate path.
+
+       IB_INVALID_STATE
+               The current connection state does not allow sending this message.
+
+       IB_INVALID_SETTING
+               The load alternate path information contains one or more of the
+               following errors:
+                 - The class version, queue pair type, or path is not supported by
+                       connection manager.
+                 - The primary path is not on the same channel adapter as the queue
+                       pair.
+                 - The primary and alternate paths are on different channel adapters.
+                 - The primary and alternate paths specify different MTUs.
+                 - The alternate path record packet lifetime is out of range.
+                 - The alternate path record pkey is out of range.
+                 - The specified private data length is invalid.
+
+       IB_INVALID_QP_HANDLE
+               The queue pair handle specified in the load alternate path information
+               was invalid.
+
+       IB_INSUFFICIENT_MEMORY
+               There was insufficient memory to send the load alternate path request.
+
+

NOTES

+
       This routine issues initiates loading an alternate path on an existing
+       connected queue pair or end-to-end context.  If the request is successful,
+       the alternate path will be loaded and armed for path migration.
+
+       The p_cm_lap parameter describes the alternate path to load and indicates
+       the remote endpoint of an existing connection that will receive the load
+       request.
+
+

SEE ALSO

+
       ib_cm_apr, ib_cm_lap_t, ib_pfn_cm_lap_cb_t, ib_pfn_cm_apr_cb_t
+
+
+
+ +

[Structures] +Access Layer/ib_cm_lap_rec_t

+ +

[top][parent][index]

+

NAME

+
       ib_cm_lap_rec_t
+
+

DESCRIPTION

+
       Load alternate path request information returned to the user through
+       a callback.
+
+

SYNOPSIS

+
typedef struct _ib_cm_lap_rec
+{
+        ib_cm_handle_t                          h_cm_lap;
+        ib_path_rec_t                           alt_path;
+
+ TO_LONG_PTR(       const uint8_t* ,          p_lap_pdata) ; 
+
+ TO_LONG_PTR(       const void* ,                     qp_context) ; 
+
+}       ib_cm_lap_rec_t;
+
+

FIELDS

+
       p_lap_pdata
+               A reference to user-defined private data sent as part of the load
+               alternate path request.
+
+       qp_context
+               The queue pair context associated with a connection request.
+
+       h_cm_lap
+               A handle to the load alternate path request.  This handle is used
+               to reply to the load request.
+
+       alt_path
+               Requested alternate path.  Users must accept or reject the path by
+               calling ib_cm_apr.
+
+

SEE ALSO

+
       ib_cm_lap, ib_pfn_cm_lap_cb_t, ib_lap_pdata_t, ib_qp_type_t
+
+
+
+ +

[Structures] +Access Layer/ib_cm_lap_t

+ +

[top][parent][index]

+

NAME

+
       ib_cm_lap_t
+
+

DESCRIPTION

+
       Load alternate path information used to configure a queue pair with an
+       alternate path.
+
+

SYNOPSIS

+
typedef struct _ib_cm_lap
+{
+        ib_al_flags_t                           flags;
+
+ TO_LONG_PTR(       const uint8_t* ,          p_lap_pdata) ; 
+        uint8_t                                         lap_length;
+
+        ib_qp_type_t                            qp_type;
+
+        /* valid for rc, uc & rd qp_type only */
+        ib_qp_handle_t __ptr64                          h_qp;
+
+        uint8_t                                         remote_resp_timeout;
+ TO_LONG_PTR(       ib_path_rec_t* ,          p_alt_path) ; 
+        ib_pfn_cm_apr_cb_t                      pfn_cm_apr_cb;
+
+}       ib_cm_lap_t;
+
+

FIELDS

+
       flags
+               Used to describe the mode of operation.  Set to IB_FLAGS_SYNC to
+               process the called routine synchronously.
+
+       p_lap_pdata
+               Optional user-defined private data sent as part of the load alternate
+               path message.
+
+       lap_length
+               Defines the size of the user-defined private data.
+
+       qp_type
+               Indicates the CM service type.
+
+       h_qp
+               A handle to the queue pair that should receive the alternate path.
+
+       remote_resp_timeout
+               The time within which the remote CM should transmit a response to
+               the sender.  This value is expressed as
+               4.096 * (2 ^ local_resp_timeout) microseconds.
+
+       p_alt_path
+               The path record to use for the alternate connection.
+
+       pfn_cm_apr_cb
+               References a user-defined callback that will be invoked when the
+               response to the load request is received.
+
+

SEE ALSO

+
       ib_cm_lap, ib_pfn_cm_lap_cb_t, ib_pfn_cm_apr_cb_t, ib_path_rec_t,
+       ib_pfn_lap_pdata_t, ib_qp_type_t
+
+
+
+ +

[Functions] +Access Layer/ib_cm_listen

+ +

[top][parent][index]

+

NAME

+
       ib_cm_listen
+
+

DESCRIPTION

+
       Issues a request to the local communication manager to listen for
+       incoming connection requests.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_cm_listen(
+        IN              const   ib_al_handle_t FUNC_PTR64                          h_al,
+        IN              const   ib_cm_listen_t* const           p_cm_listen,
+        IN              const   ib_pfn_listen_err_cb_t          pfn_listen_err_cb,
+        IN              const   void* const                                     listen_context,
+                OUT                     ib_listen_handle_t FUNC_PTR64* const       ph_cm_listen );
+
+

PARAMETERS

+
       h_al
+               [in] A handle to an opened instance of the access layer.
+
+       p_cm_listen
+               [in] Information used to direct the listen request to match incoming
+               connection requests.
+
+       pfn_listen_err_cb
+               [in] User-specified error callback routine to invoke if an error
+               occurs while listening.
+
+       listen_context
+               User-specified context information that is returned as a part of all
+               connection requests through the pfn_cm_req_cb routine.  The context is
+               also returned through the error and destroy callbacks.
+
+       ph_cm_listen
+               [out] Upon successful completion of this call, this references a handle
+               to the listen request.  This handle may be used to cancel the listen
+               operation.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The listen request was successfully registered with the connection
+               manager.
+
+       IB_INVALID_AL_HANDLE
+               The access layer handle was invalid.
+
+       IB_INVALID_PARAMETER
+               A reference to the listen request information, error callback function,
+               or listen handle was not provided.
+
+       IB_INVALID_SETTING
+               The class version specified in the listen request is not supported by
+               connection manager or the listen request is not unique.
+
+       IB_INSUFFICIENT_MEMORY
+               There was insufficient memory to register the listen request.
+
+       IB_INVALID_GUID
+               A channel adapter or port GUID is not wildcarded and no channel adapter
+               or port in the system was found for the specified GUID.
+
+       IB_INVALID_LID
+               The lid is not wildcarded and is not within the lid range for the port
+               specified in the listen request information.
+
+       IB_INVALID_PKEY
+               The pkey is not wildcarded and is not a valid pkey for the port
+               specified in the listen request information.
+
+

NOTES

+
       This routine directs the access layer to route connection requests
+       matching the specified connection parameters to the client.  Clients
+       listen for connections matching a particular service ID, and may optionally
+       direct their listen request towards a specific channel adapter, port, or
+       LID.
+
+       If local configuration changes occur that invalidate a listen request, the
+       specified error callback will be invoked.  Invalidated listen requests
+       should be canceled by the user.  An example of a configuration change that
+       invalidates listen requests is a LID change for directed listens.  The
+       listen error callback will be invoked within the context of a system
+       thread.
+
+

SEE ALSO

+
       ib_cm_listen_t, ib_pfn_listen_err_cb_t
+
+
+
+ +

[Structures] +Access Layer/ib_cm_listen_t

+ +

[top][parent][index]

+

NAME

+
       ib_cm_listen_t
+
+

DESCRIPTION

+
       Request to listen for incoming connection attempts.
+
+

SYNOPSIS

+
typedef struct _ib_cm_listen
+{
+        ib_net64_t                                      svc_id;
+
+        ib_net64_t                                      ca_guid;
+        ib_net64_t                                      port_guid;
+        ib_net16_t                                      lid;
+        ib_net16_t                                      pkey;
+
+ TO_LONG_PTR(       uint8_t* ,                        p_compare_buffer) ; 
+        uint8_t                                         compare_offset;
+        uint8_t                                         compare_length;
+
+        ib_pfn_cm_req_cb_t                      pfn_cm_req_cb;
+
+        ib_qp_type_t                            qp_type;
+
+        /* valid for ud qp_type only */
+ TO_LONG_PTR(       const void* ,                     sidr_context) ; 
+
+}       ib_cm_listen_t;
+
+

FIELDS

+
       svc_id
+               The identifier of the service to register for incoming connection
+               requests.
+
+       ca_guid
+               Directs the communication manager to register the listen only
+               with the specified channel adapter.  This should be set to IB_ALL_CAS
+               if the listen is not directed to a particular channel adapter.
+
+       port_guid
+               Directs the communication manager to register the listen only
+               with the specified port.  This should be set to IB_ALL_PORTS
+               if the listen is not directed to a particular port.
+
+       lid
+               Directs the communication manager to register the listen only
+               with the specified LID.  This should be set to IB_ALL_LIDS
+               if the listen is not directed to a particular LID.
+
+       pkey
+               Directs the communication manager to register the listen only with
+               the specified pkey value.  This should be set to IB_ALL_PKEYS
+               iv the listen is not directed to a particular partition.
+
+       p_compare_buffer
+               An optionally provided buffer that will be used to match incoming
+               connection requests with a registered service.  Use of this buffer
+               permits multiple services to listen on the same service ID as long as
+               they provide different compare buffers.  Incoming requests will
+               be matched against the compare buffer.
+
+       compare_offset
+               An offset into the user-defined data area of a connection request
+               which contains the start of the data that will be compared against.
+               The offset must be the same for all requests using the same service ID.
+
+       compare_length
+               Specifies the size of the compare buffer in bytes.  The length must
+               be the same for all requests using the same service ID.
+
+       pfn_cm_req_cb
+               References a user-provided callback that will be invoked whenever a
+               connection request is received.
+
+       qp_type
+               Indicates the CM service type.
+
+       pfn_cm_mra_cb
+               References a user-provided callback that will be invoked when
+               a message received acknowledgement is received.
+
+       pfn_cm_rej_cb
+               References a user-provided callback that will be invoked if the
+               connection is rejected by the remote end-point.
+
+       sidr_context
+               sidr specific context for listens. This context is passed back in
+               the ib_pfn_cm_req_cb_t callback.
+
+

NOTES

+
       Users fill out this structure when listening on a service ID with the
+       local communication manager.  The communication manager will use the given
+       service ID and compare buffer to route connection requests to the
+       appropriate client.  Users may direct listens requests on a particular
+       channel adapter, port, or LID.
+
+       Message received acknowledgement (MRA) callbacks will not be invoked
+       until a connection request has been replied to.
+
+

SEE ALSO

+
       ib_listen_info_t, ib_pfn_cm_req_cb_t, ib_pfn_cm_mra_cb_t,
+       ib_qp_type_t
+
+
+
+ +

[Functions] +Access Layer/ib_cm_mra

+ +

[top][parent][index]

+

NAME

+
       ib_cm_mra
+
+

DESCRIPTION

+
       Notifies the remote end-point of a connection or load alternate path
+       request that the request message has been received, but additional
+       processing is required.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_cm_mra(
+        IN              const   ib_cm_handle_t                          h_cm,
+        IN              const   ib_cm_mra_t* const                      p_cm_mra );
+
+

PARAMETERS

+
       h_cm
+               [in] A handle to the connection request, connection reply, or load
+               alternate path request that should receive the message received
+               acknowledgement message.  This is the h_cm_req, h_cm_rep, or
+               h_cm_lap handle provided through the ib_pfn_cm_req_cb_t,
+               ib_pfn_cm_rep_cb_t, or ib_pfn_cm_lap_cb_t callback, respectively.
+
+       p_cm_mra
+               [in] Contains the message received acknowledgement data to return to
+               the requesting end-point.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The message receive acknowledge was sent successfully.
+
+       IB_INVALID_HANDLE
+               The connection manager reply handle was invalid.
+
+       IB_INVALID_PARAMETER
+               A reference to the message receive acknowledge information was not
+               provided.
+
+       IB_INVALID_STATE
+               The current connection state does not allow sending this message.
+
+       IB_INVALID_SETTING
+               The class version is not supported by connection manager or the
+               specified private data length is invalid.
+
+       IB_INSUFFICIENT_MEMORY
+               There was insufficient memory to send the message receive acknowledge.
+
+

NOTES

+
       This routine results in the access layer acknowledging a connection or
+       load alternate path message.  It should be invoked by a client if the
+       client is unable to respond to a request within a specified timeout,
+       in order to prevent the remote end-point from timing out.
+
+

SEE ALSO

+
       ib_pfn_cm_req_cb_t, ib_pfn_cm_rep_cb_t, ib_pfn_cm_lap_cb_t, ib_cm_mra_t
+
+
+
+ +

[Structures] +Access Layer/ib_cm_mra_rec_t

+ +

[top][parent][index]

+

NAME

+
       ib_cm_mra_rec_t
+
+

DESCRIPTION

+
       Message received acknowledgement information returned to the user through
+       a callback.
+
+

SYNOPSIS

+
typedef struct _ib_cm_mra_rec
+{
+ TO_LONG_PTR(       const uint8_t* ,          p_mra_pdata) ; 
+
+        ib_qp_handle_t __ptr64                          h_qp;
+ TO_LONG_PTR(       const void* ,                     qp_context) ; 
+
+}       ib_cm_mra_rec_t;
+
+

FIELDS

+
       p_mra_pdata
+               A reference to user-defined private data sent as part of the MRA.
+
+       h_qp
+               The queue pair handle associated with a connection request.
+
+       qp_context
+               The queue pair context associated with a connection request.
+
+

SEE ALSO

+
       ib_cm_req, ib_cm_mra, ib_pfn_cm_mra_cb_t, ib_mra_pdata_t, ib_qp_type_t
+
+
+
+ +

[Structures] +Access Layer/ib_cm_mra_t

+ +

[top][parent][index]

+

NAME

+
       ib_cm_mra_t
+
+

DESCRIPTION

+
       Connection message received acknowledgement information used to
+       indicate that a connection request, reply, or load alternate path
+       has been received.
+
+

SYNOPSIS

+
typedef struct _ib_cm_mra
+{
+        uint8_t                                         svc_timeout;
+
+ TO_LONG_PTR(       const uint8_t* ,          p_mra_pdata) ; 
+        uint8_t                                         mra_length;
+
+}       ib_cm_mra_t;
+
+

FIELDS

+
       svc_timeout
+               Indicates the amount of time that the local service requires to
+               complete processing of the previously received message.
+
+       p_mra_pdata
+               Optional user-defined private data sent as part of the message
+               received acknowledgement.
+
+       mra_length
+               Defines the size of the user-defined private data.
+
+

SEE ALSO

+
       ib_cm_mra, ib_pfn_cm_req_cb_t, ib_pfn_cm_rep_cb_t, ib_pfn_cm_lap_cb_t,
+       ib_mra_pdata_t
+
+
+
+ +

[Functions] +Access Layer/ib_cm_rej

+ +

[top][parent][index]

+

NAME

+
       ib_cm_rej
+
+

DESCRIPTION

+
       Rejects a connection request from a remote end-point.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_cm_rej(
+        IN              const   ib_cm_handle_t                          h_cm,
+        IN              const   ib_cm_rej_t* const                      p_cm_rej );
+
+

PARAMETERS

+
       h_cm
+               [in] A handle to the connection request or reply being rejected.
+               This is the h_cm_req or h_cm_rep handle provided through the
+               ib_pfn_cm_req_cb_t or ib_pfn_cm_rep_cb_t callback, respectively.
+
+       p_cm_rej
+               [in] Contains the connection rejection information to return to the
+               connecting end-point.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The connection reject was initiated.
+
+       IB_INVALID_HANDLE
+               The connection manager handle was invalid.
+
+       IB_INVALID_PARAMETER
+               A reference to the reject information was not provided.
+
+

NOTES

+
       This routine results in the access layer rejecting a connection
+       and notifying the remote end-point.
+
+

SEE ALSO

+
       ib_pfn_cm_req_cb_t, ib_pfn_cm_rep_cb_t, ib_cm_rej_t
+
+
+
+ +

[Structures] +Access Layer/ib_cm_rej_rec_t

+ +

[top][parent][index]

+

NAME

+
       ib_cm_rej_rec_t
+
+

DESCRIPTION

+
       Connection rejection information returned to the user through their
+       rejection callback.
+
+

SYNOPSIS

+
typedef struct _ib_cm_rej_rec
+{
+        ib_rej_status_t                         rej_status;
+ TO_LONG_PTR(       const uint8_t* ,          p_ari) ; 
+        uint8_t                                         ari_length;
+
+ TO_LONG_PTR(       const uint8_t* ,          p_rej_pdata) ; 
+
+        ib_qp_handle_t __ptr64                          h_qp;
+ TO_LONG_PTR(       const void* ,                     qp_context) ; 
+
+}       ib_cm_rej_rec_t;
+
+

FIELDS

+
       rej_status
+               The reason for the connection rejection.
+
+       p_ari
+               Additional rejection information.  The data referenced by this field
+               is dependent on the rej_status and is defined by the Infiniband
+               specification.
+
+       ari_length
+               Length of valid data provided in the p_ari buffer.
+
+       p_rej_pdata
+               A reference to user-defined private data sent as part of the connection
+               request reply.
+
+       h_qp
+               The queue pair handle associated with a connection request.
+
+       qp_context
+               The queue pair context associated with a connection request.
+
+

SEE ALSO

+
       ib_cm_rej, ib_pfn_cm_rej_cb_t, ib_rej_status_t, ib_ari_t, ib_rej_pdata_t,
+       ib_qp_type_t
+
+
+
+ +

[Structures] +Access Layer/ib_cm_rej_t

+ +

[top][parent][index]

+

NAME

+
       ib_cm_rej_t
+
+

DESCRIPTION

+
       Information used to reject a connection request.
+
+

SYNOPSIS

+
typedef struct _ib_cm_rej
+{
+        ib_rej_status_t                         rej_status;
+
+ TO_LONG_PTR(       ib_ari_t* ,                       p_ari) ; 
+        uint8_t                                         ari_length;
+ TO_LONG_PTR(       const uint8_t* ,          p_rej_pdata) ; 
+        uint8_t                                         rej_length;
+
+}       ib_cm_rej_t;
+
+

FIELDS

+
       rej_status
+               The reason for the connection rejection.
+
+       p_ari
+               Additional rejection information.  The data referenced by this field
+               is dependent on the rej_status and is defined by the Infiniband
+               specification.
+
+       ari_length
+               Length of valid data provided in the p_ari buffer.
+
+       p_rej_pdata
+               A reference to user-defined private data sent as part of the
+               reject message.
+
+       rej_length
+               Defines the size of the user-defined private data.
+
+

SEE ALSO

+
       ib_cm_rej, ib_pfn_cm_rej_cb_t, ib_rej_status_t, ib_ari_t, ib_rej_pdata_t
+
+
+
+ +

[Functions] +Access Layer/ib_cm_rep

+ +

[top][parent][index]

+

NAME

+
       ib_cm_rep
+
+

DESCRIPTION

+
       Sends a reply to a connection request, indicating that the connection
+       has been accepted.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_cm_rep(
+        IN              const   ib_cm_handle_t                          h_cm_req,
+        IN              const   ib_cm_rep_t* const                      p_cm_rep );
+
+

PARAMETERS

+
       h_cm_req
+               [in] A handle to the connection request being replied to.  This handle
+               is provided by the access layer through the ib_pfn_cm_req_cb_t
+               callback.
+
+       p_cm_rep
+               [in] Contains reply information to return to the initiator of the
+               connection request.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The connection reply was initiated.
+
+       IB_INVALID_HANDLE
+               The connection manager request handle was invalid.
+
+       IB_INVALID_PARAMETER
+               A reference to the reply information was not provided.
+
+       IB_INVALID_STATE
+               The current connection state does not allow sending this message.
+
+       IB_INVALID_SETTING
+               The connect reply information contains one or more of the following
+               errors:
+                 - The class version, queue pair type, or path is not supported by
+                       connection manager.
+                 - The private data length exceeds the value allowed by the connection
+                       class version.
+                 - The primary path is not on the same channel adapter as the queue
+                       pair.
+                 - The primary and alternate paths are on different channel adapters.
+                 - The primary and alternate paths specify different MTUs.
+                 - A primary or alternate path record packet lifetime is out of range.
+                 - A primary or alternate path record pkey is out of range.
+                 - The specified private data length is invalid.
+
+       IB_INVALID_QP_HANDLE
+               The queue pair handle specified in the reply was invalid.
+
+       IB_INVALID_QP_STATE
+               The queue pair was in an invalid state to perform the operation.
+
+       IB_INSUFFICIENT_MEMORY
+               There was insufficient memory to send the connect reply.
+
+

NOTES

+
       This routine results in the access layer replying to a connection
+       request from a remote node.  This call results in sending a response
+       to the requesting node that the request has been accepted.
+
+

SEE ALSO

+
       ib_cm_rep_t, ib_pfn_cm_req_cb_t, ib_pfn_cm_rep_cb_t
+
+
+
+ +

[Structures] +Access Layer/ib_cm_rep_rec_t

+ +

[top][parent][index]

+

NAME

+
       ib_cm_rep_rec_t
+
+

DESCRIPTION

+
       Connection request reply information returned to the user through their
+       connection reply callback.
+
+

SYNOPSIS

+
typedef struct _ib_cm_rep_rec
+{
+ TO_LONG_PTR(       const uint8_t* ,          p_rep_pdata) ; 
+
+        ib_qp_type_t                            qp_type;
+
+        ib_cm_handle_t                          h_cm_rep;
+        /* valid for rc, uc & rd qp_type only */
+ TO_LONG_PTR(       const void* ,                     qp_context) ; 
+        uint8_t                                         resp_res;
+        boolean_t                                       flow_ctrl;
+        ib_apr_status_t                         apr_status;
+
+        /* valid for ud qp_type only */
+ TO_LONG_PTR(       const void* ,                     sidr_context) ; 
+        ib_sidr_status_t                        status;
+        ib_net32_t                                      remote_qp;
+        ib_net32_t                                      remote_qkey;
+        ib_class_port_info_t            class_info;
+
+}       ib_cm_rep_rec_t;
+
+

FIELDS

+
       p_rep_pdata
+               A reference to user-defined private data sent as part of the connection
+               request reply.
+
+       qp_type
+               Indicates the CM service type.
+
+       h_cm_rep
+               The handle to the communication manager reply.  This handle is used
+               to issue a ready to use message or to reject the connection.
+
+       h_qp
+               The handle to the queue pair associated with a connection request.
+
+       qp_context
+               The queue pair context associated with a connection request.
+
+       resp_res
+               The maximum number of RDMA read/atomic operations from the recipient
+               that the requestor supports on the connection.  This may be less than
+               the init_depth specified in the call to ib_cm_req.  The local queue
+               pair will be configured with this value unless the connection is
+               rejected.
+
+       flow_ctrl
+               Indicates if the remote CA implements hardware end-to-end flow control.
+
+       apr_status
+               Indicates whether the alternate path information was accepted.
+
+       h_al
+               The AL handle on which the SIDR request was issued.
+
+       sidr_context
+               The sidr_context used in ib_cm_req.
+
+       status
+               Status of the request made previously using ib_cm_req.
+
+       remote_qp
+               Identifies the destination queue pair number.
+
+       remote_qkey
+               Identifies the destination qkey.
+
+       class_info
+               Identifies the class_port_info returned if status was not successful.
+               This field has no value if status is successful.
+
+

SEE ALSO

+
       ib_cm_req, ib_cm_rep, ib_pfn_cm_rep_cb_t, ib_cm_status_t, ib_rep_pdata_t
+       ib_qp_type_t, ib_sidr_status_t
+
+
+
+ +

[Structures] +Access Layer/ib_cm_rep_t

+ +

[top][parent][index]

+

NAME

+
       ib_cm_rep_t
+
+

DESCRIPTION

+
       Connection reply information used when establishing a connection.
+
+

SYNOPSIS

+
typedef struct _ib_cm_rep
+{
+        ib_al_flags_t                           flags;
+
+ TO_LONG_PTR(       const uint8_t* ,          p_rep_pdata) ; 
+        uint8_t                                         rep_length;
+
+        ib_qp_handle_t __ptr64                          h_qp;
+        ib_qp_type_t                            qp_type;
+
+        /* valid for rc, uc & rd qp_type only */
+        ib_access_t                                     access_ctrl;
+        uint32_t                                        sq_depth;
+        uint32_t                                        rq_depth;
+
+        uint8_t                                         init_depth;
+        uint8_t                                         target_ack_delay;
+        ib_cm_failover_t                        failover_accepted;
+        boolean_t                                       flow_ctrl;
+        uint8_t                                         rnr_nak_timeout;
+        uint8_t                                         rnr_retry_cnt;
+
+        ib_pfn_cm_rej_cb_t                      pfn_cm_rej_cb;
+        ib_pfn_cm_mra_cb_t                      pfn_cm_mra_cb;
+        ib_pfn_cm_rtu_cb_t                      pfn_cm_rtu_cb;
+        ib_pfn_cm_lap_cb_t                      pfn_cm_lap_cb;
+        ib_pfn_cm_dreq_cb_t                     pfn_cm_dreq_cb;
+
+ TO_LONG_PTR(       ib_recv_wr_t* ,                   p_recv_wr) ; 
+ TO_LONG_PTR(       ib_recv_wr_t* , *__ptr64  pp_recv_failure) ; 
+
+        /*valid for ud qp_type only */
+        ib_sidr_status_t                        status;
+        ib_class_port_info_t            class_info;
+
+}       ib_cm_rep_t;
+
+

FIELDS

+
       flags
+               Used to describe the mode of operation.  Set to IB_FLAGS_SYNC to
+               process the called routine synchronously.
+
+       p_rep_pdata
+               Optional user-defined private data sent as part of the connection
+               reply.
+
+       rep_length
+               Defines the size of the user-defined private data.
+
+       qp_type
+               Indicates the CM service type.
+
+       h_qp
+               A handle to the queue pair to use in the connection. For SIDR, h_qp
+               is valid only if sidr status is IB_SIDR_SUCCESS.
+
+       access_ctrl
+               Indicates the type of access permitted on the local QP.
+
+       sq_depth
+               The maximum number of outstanding send operations that the local
+               QP needs to support.
+
+       rq_depth
+               The maximum number of outstanding receive operations that the local
+               QP needs to support.
+
+       init_depth
+               The maximum number of outstanding RDMA read/atomic operations the
+               sender of the reply will have outstanding to the remote QP.
+
+       target_ack_delay
+               The time that the remote QP should wait to receive an ACK from the
+               local QP.
+
+       failover_accepted
+               Status indicating if the fail over path was accepted by the sender
+               of the reply.
+
+       flow_ctrl
+               Indicates whether the local CA supports end-to-end flow control.
+
+       rnr_nak_timeout
+               The time to wait before retrying a packet after receiving a RNR NAK.
+
+       rnr_retry_cnt
+               The number of times that the local QP should retry a send operation
+               after receiving an RNR NACK before reporting an error.
+
+       pfn_cm_rtu_cb
+               References a user-defined callback that will be invoked when
+               a connection is ready to use for send operations.
+
+       pfn_cm_lap_cb
+               References a user-defined callback that will be invoked when
+               a load alternate path request is received for the connecting
+               queue pair or end-to-end context.
+
+       pfn_cm_dreq_cb
+               References a user-defined callback that will be invoked when
+               a disconnect request is received is for the connecting
+               queue pair or end-to-end context.
+
+       p_recv_wr
+               A reference to the head of the work request list to be initially
+               posted to the receive queue.  Providing this list closes a potential
+               race condition between sending a CM REP message and posting receives.
+               Use of this field is optional.
+
+       pp_recv_failure
+               If the post receive operation failed, this references the work
+               request in the p_recv_wr list where the first failure occurred.
+               This field is required only if p_recv_wr is used.
+
+       status
+               sidr status value returned back to a previously received REQ.
+
+       class_info
+               The contents of this field are valid only if status is IB_SIDR_REDIRECT.
+
+

SEE ALSO

+
       ib_cm_rep, ib_access_t, ib_cm_failover_t, ib_rep_pdata_t
+       ib_pfn_cm_rtu_cb_t, ib_pfn_cm_lap_cb_t, ib_pfn_cm_dreq_cb_t,
+       ib_qp_type_t
+
+
+
+ +

[Functions] +Access Layer/ib_cm_req

+ +

[top][parent][index]

+

NAME

+
       ib_cm_req
+
+

DESCRIPTION

+
       Issues a connection request to a specified end-point.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_cm_req(
+        IN              const   ib_cm_req_t* const                      p_cm_req );
+
+

PARAMETERS

+
       p_cm_req
+               [in] Information describing the type of connection and the remote
+               endpoint for the connection.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The connection request was initiated.
+
+       IB_INVALID_PARAMETER
+               A reference to the connect request information was not provided.
+
+       IB_INVALID_SETTING
+               The connect request information contains one or more of the following
+               errors:
+                 - The class version, queue pair type, or path is not supported by
+                       connection manager.
+                 - The private data length exceeds the value allowed by the specified
+                       connection class version.
+                 - The primary path is not on the same channel adapter as the queue
+                       pair.
+                 - The primary and alternate paths are on different channel adapters.
+                 - The primary and alternate paths specify different MTUs.
+                 - A primary or alternate path record packet lifetime is out of range.
+                 - A primary or alternate path record pkey is out of range.
+
+       IB_INVALID_QP_HANDLE
+               The queue pair handle specified in the connect request was invalid.
+
+       IB_INVALID_AL_HANDLE
+               The access layer handle was invalid.
+
+       IB_INVALID_STATE
+               The queue pair or end-to-end context is already connected.
+
+       IB_INVALID_QP_STATE
+               The queue pair was in an invalid state to perform the operation.
+
+       IB_INSUFFICIENT_MEMORY
+               There was insufficient memory to initiate the connect request.
+
+

NOTES

+
       This routine issues a connection request through the communication
+       manager to a specified end-point.  The p_cm_req parameter contains
+       details needed to form the connection.  The connection request will
+       match with a remote ib_cm_listen or ib_cm_req connection request.
+
+

SEE ALSO

+
       ib_cm_req_t, ib_cm_listen, ib_pfn_cm_req_cb_t
+
+
+
+ +

[Structures] +Access Layer/ib_cm_req_rec_t

+ +

[top][parent][index]

+

NAME

+
       ib_cm_req_rec_t
+
+

DESCRIPTION

+
       Connection request information returned to the user through their
+       connection request callback.
+
+

SYNOPSIS

+
#pragma warning(disable:4324)
+typedef struct _ib_cm_req_rec
+{
+ TO_LONG_PTR(       const void* ,                     context) ; 
+        ib_cm_handle_t                          h_cm_req;
+        ib_listen_handle_t __ptr64                      h_cm_listen;
+
+ TO_LONG_PTR(       const uint8_t* ,          p_req_pdata) ; 
+
+        ib_qp_type_t                            qp_type;
+
+        /* valid for rc, uc & rd qp_type only */
+        uint8_t                                         resp_res;
+        boolean_t                                       flow_ctrl;
+        uint8_t                                         rnr_retry_cnt;
+        ib_path_rec_t                           primary_path;
+        ib_path_rec_t                           alt_path;
+
+        /* valid for ud qp_type only */
+        ib_net16_t                                      pkey;
+ TO_LONG_PTR(       const void* ,                     sidr_context) ; 
+
+}       ib_cm_req_rec_t;
+#pragma warning(default:4324)
+
+

FIELDS

+
       context
+               For peer-to-peer connections, this is the queue pair context associated
+               with a connection request.  For listens, this is the listen context
+               specified through the ib_cm_listen routine.
+
+       h_cm_req
+               The handle to the communication manager request.  This handle is used
+               to reply to the or reject the connection.
+
+       h_cm_listen
+               For connection request callbacks initiated in response to an
+               ib_cm_listen call, this is a handle to the listen request.  This
+               handle is provided to the user to avoid a race condition between
+               the return of the ib_cm_listen routine and the notification of a
+               connection request.
+
+       p_req_pdata
+               A reference to user-defined private data sent as part of the connection
+               request.
+
+       qp_type
+               Indicates the CM service type.
+
+       resp_res
+               The maximum number of RDMA read/atomic operations from the recipient
+               that the requestor supports on the connection.  The init_depth
+               specified in the call to ib_cm_rep must be less than or equal to
+               this value.
+
+       flow_ctrl
+               Indicates if the remote CA implements hardware end-to-end flow control.
+
+       rnr_retry_cnt
+               Requested number of RNR NAK retries to perform before generating a
+               local error.
+
+       primary_path
+               The path record to use for the primary connection.
+
+       alt_path
+               The path record to use for the alternate connection.
+
+       pkey
+               The pkey used in the user's request.
+
+       sidr_context
+               The sidr_context used in ib_cm_listen.
+
+

SEE ALSO

+
       ib_cm_req, ib_cm_listen, ib_pfn_cm_req_cb_t,
+       ib_access_t, ib_path_rec_t, ib_req_pdata_t, ib_qp_type_t
+
+
+
+ +

[Structures] +Access Layer/ib_cm_req_t

+ +

[top][parent][index]

+

NAME

+
       ib_cm_req_t
+
+

DESCRIPTION

+
       Connection request information used to establish a new connection.
+
+

SYNOPSIS

+
typedef struct _ib_cm_req
+{
+        ib_net64_t                                      svc_id;
+
+        ib_al_flags_t                           flags;
+        uint8_t                                         max_cm_retries;
+
+ TO_LONG_PTR(       ib_path_rec_t* ,          p_primary_path) ; 
+
+        ib_pfn_cm_rep_cb_t                      pfn_cm_rep_cb;
+
+ TO_LONG_PTR(       const uint8_t* ,          p_req_pdata) ; 
+        uint8_t                                         req_length;
+
+        ib_qp_type_t                            qp_type;
+
+        /* valid for rc, uc & rd qp_type only */
+        ib_qp_handle_t __ptr64                          h_qp;
+
+ TO_LONG_PTR(       uint8_t* ,                        p_compare_buffer) ; 
+        uint8_t                                         compare_offset;
+        uint8_t                                         compare_length;
+
+        uint8_t                                         resp_res;
+        uint8_t                                         init_depth;
+        uint8_t                                         remote_resp_timeout;
+        boolean_t                                       flow_ctrl;
+        uint8_t                                         local_resp_timeout;
+        uint8_t                                         rnr_nak_timeout;
+        uint8_t                                         rnr_retry_cnt;
+        uint8_t                                         retry_cnt;
+
+ TO_LONG_PTR(       ib_path_rec_t* ,          p_alt_path OPTIONAL) ; 
+
+        ib_pfn_cm_req_cb_t                      pfn_cm_req_cb;
+        ib_pfn_cm_mra_cb_t                      pfn_cm_mra_cb;
+        ib_pfn_cm_rej_cb_t                      pfn_cm_rej_cb;
+
+        /* valid for ud qp_type only */
+        ib_al_handle_t __ptr64                          h_al;
+ TO_LONG_PTR(       const void* ,                     sidr_context) ; 
+        uint32_t                                        timeout_ms;
+        ib_net16_t                                      pkey;
+
+}       ib_cm_req_t;
+
+

FIELDS

+
       svc_id
+               The ID of the remote service to which the connection request is
+               being made.
+
+       flags
+               Used to describe the mode of operation.  Set to IB_FLAGS_SYNC to
+               process the called routine synchronously.
+
+       max_cm_retries
+               The maximum number of times that either CM should resend a connection
+               establishment message.
+
+       p_primary_path
+               Path information over which to establish the primary connection.
+
+       pfn_cm_rep_cb
+               References a user-provided callback that will be invoked when
+               a reply to the connection request is received.
+
+       p_req_pdata
+               Optional user-defined private data sent as part of the connection
+               request.
+
+       req_length
+               Defines the size of the user-defined private data.
+
+       qp_type
+               Indicates the CM service type.
+
+       h_qp
+               A handle to the queue pair to use in the connection.
+
+       p_compare_buffer
+               An optionally provided buffer that will be used to match incoming
+               connection requests with a registered service.  Use of this buffer
+               permits multiple services to connect using the same service ID as
+               long as they provide different compare buffers.  Incoming requests
+               will be matched against the compare buffer.  Valid for peer-to-peer
+               connection requests only.
+
+       compare_offset
+               An offset into the user-defined data area of a connection request
+               which contains the start of the data that will be compared against.
+               The offset must be the same for all requests using the same service ID.
+               Valid for peer-to-peer connection requests only.
+
+       compare_length
+               Specifies the size of the compare buffer in bytes.  The length must
+               be the same for all requests using the same service ID.  Valid for
+               peer-to-peer connection requests only.
+
+       resp_res
+               The maximum number of outstanding RDMA read/atomic operations the
+               requestor supports from the remote QP.
+
+       init_depth
+               The maximum number of outstanding RDMA read/atomic operations the
+               requestor will have outstanding to the remote QP.
+
+       remote_resp_timeout
+               The time within which the remote CM should transmit a response to
+               the sender.  This value is expressed as
+               4.096 * (2 ^ local_resp_timeout) microseconds.
+
+       flow_ctrl
+               Indicates whether the local CA supports end-to-end flow control.
+
+       local_resp_timeout
+               The time that the remote CM should wait to receive a response from
+               the local CM.  This value is expressed as
+               4.096 * (2 ^ local_resp_timeout) microseconds.
+
+       rnr_nak_timeout
+               The time to wait before retrying a packet after receiving a RNR NAK.
+               This value is defined in section 9.7.5.2.8 of the IB Spec, table 45.
+
+       rnr_retry_cnt
+               The number of times that the local QP should retry a send operation
+               after receiving an RNR NACK before reporting an error.
+
+       retry_cnt
+               The number of times that a QP should retry a send operation before
+               reporting an error.
+
+       p_alt_path
+               Optional path information that will be used as the alternate
+               connection path in the case of failure.
+
+       pfn_cm_req_cb
+               References a user-provided callback that will be invoked when
+               a request for a connection is received.  This is required for peer-to
+               peer connection requests, and must be NULL for client/server
+               connection requests.
+
+       pfn_cm_mra_cb
+               References a user-provided callback that will be invoked when
+               a message received acknowledgement is received.
+
+       pfn_cm_rej_cb
+               References a user-provided callback that will be invoked if the
+               connection is rejected by the remote end-point.
+
+       sidr_context
+               The user-defined sidr context information that will be passed back in a
+               ib_cm_req callback.
+
+       timeout_ms
+               Timeout value in milli-seconds for the REQ to expire.  The CM will add
+               twice packet lifetime to this value to determine the actual timeout
+               value used.
+
+       pkey
+               pkey to be used as part of the request. This field is only valid for
+               IB_MCLASS_CM_VER_2 clients.
+
+

SEE ALSO

+
       ib_cm_req, ib_pfn_cm_req_cb_t, ib_pfn_cm_rep_cb_t, ib_pfn_cm_mra_cb_t,
+       ib_pfn_cm_rej_cb_t, ib_path_rec_t, ib_req_pdata_t, ib_qp_type_t
+
+
+
+ +

[Functions] +Access Layer/ib_cm_rtu

+ +

[top][parent][index]

+

NAME

+
       ib_cm_rtu
+
+

DESCRIPTION

+
       Sends a ready to use message for a connection request, indicating that
+       the connection has been accepted and is ready for use.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_cm_rtu(
+        IN              const   ib_cm_handle_t                          h_cm_rep,
+        IN              const   ib_cm_rtu_t* const                      p_cm_rtu );
+
+

PARAMETERS

+
       h_cm_rep
+               [in] A handle to the connection reply being responded to.  This handle
+               is provided by the access layer through the ib_pfn_cm_rep_cb_t
+               callback.
+
+       p_cm_rtu
+               [in] Contains ready to use information to return to the sender of the
+               connection reply.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The connection ready to use was initiated.
+
+       IB_INVALID_HANDLE
+               The connection manager reply handle was invalid.
+
+       IB_INVALID_PARAMETER
+               A reference to the ready to use information was not provided.
+
+       IB_INVALID_STATE
+               The current connection state does not allow sending this message.
+
+       IB_INVALID_SETTING
+               The specified queue pair attributes were invalid or the private data
+               length exceeds the value allowed by the specified connection class
+               version.
+
+       IB_UNSUPPORTED
+               The specified queue pair access control was not supported.
+
+       IB_INSUFFICIENT_MEMORY
+               There was insufficient memory to send the ready to use response.
+
+

NOTES

+
       This routine results in the access layer marking a connection as ready
+       to use and notifying the remote end-point.
+
+

SEE ALSO

+
       ib_cm_rep_t, ib_pfn_cm_rep_cb_t, ib_cm_rtu_t
+
+
+
+ +

[Structures] +Access Layer/ib_cm_rtu_rec_t

+ +

[top][parent][index]

+

NAME

+
       ib_cm_rtu_rec_t
+
+

DESCRIPTION

+
       Connection ready to use message information returned to the user through
+       their ready to use callback.
+
+

SYNOPSIS

+
typedef struct _ib_cm_rtu_rec
+{
+ TO_LONG_PTR(       const uint8_t* ,          p_rtu_pdata) ; 
+
+        ib_qp_handle_t __ptr64                          h_qp;
+ TO_LONG_PTR(       const void* ,                     qp_context) ; 
+
+}       ib_cm_rtu_rec_t;
+
+

FIELDS

+
       p_rtu_pdata
+               A reference to user-defined private data sent as part of the ready
+               to use message.
+
+       h_qp
+               The queue pair handle associated with the connection request.
+
+       qp_context
+               The queue pair context associated with the connection request.
+
+

SEE ALSO

+
       ib_cm_rtu, ib_pfn_cm_rtu_cb_t, ib_cm_status_t, ib_rtu_pdata_t,
+       ib_qp_type_t
+
+
+
+ +

[Structures] +Access Layer/ib_cm_rtu_t

+ +

[top][parent][index]

+

NAME

+
       ib_cm_rtu_t
+
+

DESCRIPTION

+
       Connection ready to use information used when establishing a connection.
+
+

SYNOPSIS

+
typedef struct _ib_cm_rtu
+{
+        ib_access_t                                     access_ctrl;
+        uint32_t                                        sq_depth;
+        uint32_t                                        rq_depth;
+
+ TO_LONG_PTR(       const uint8_t* ,          p_rtu_pdata) ; 
+        uint8_t                                         rtu_length;
+
+        ib_pfn_cm_apr_cb_t                      pfn_cm_apr_cb;
+        ib_pfn_cm_dreq_cb_t                     pfn_cm_dreq_cb;
+
+}       ib_cm_rtu_t;
+
+

FIELDS

+
       access_ctrl
+               Indicates the type of access permitted on the local QP.
+
+       sq_depth
+               The maximum number of outstanding send operations that the local
+               QP needs to support.  This field should be set to zero if the CA
+               does not support changing the work request depth after the QP is
+               created.
+
+       rq_depth
+               The maximum number of outstanding receive operations that the local
+               QP needs to support.  This field should be set to zero if the CA
+               does not support changing the work request depth after the QP is
+               created.
+
+       p_rtu_pdata
+               Optional user-defined private data sent as part of the connection
+               ready to use message.
+
+       rtu_length
+               Defines the size of the user-defined private data.
+
+       pfn_cm_apr_cb
+               References a user-defined callback that will be invoked when an
+               alternate path response is received for the connecting queue pair
+               or end-to-end context.
+
+       pfn_cm_dreq_cb
+               References a user-defined callback that will be invoked when a
+               disconnect request is received is for the connecting queue pair
+               or end-to-end context.
+
+

SEE ALSO

+
       ib_cm_rtu, ib_access_t, ib_rtu_pdata_t
+
+
+
+ +

[Structures] +Access Layer/ib_cq_create_t

+ +

[top][parent][index]

+

NAME

+
       ib_cq_create_t
+
+

DESCRIPTION

+
       Attributes used to initialize a completion queue at creation time.
+
+

SYNOPSIS

+
typedef struct _ib_cq_create
+{
+        uint32_t                                                                size;
+        ib_pfn_comp_cb_t                                                pfn_comp_cb;
+        cl_waitobj_handle_t                                             h_wait_obj;
+
+}       ib_cq_create_t;
+
+

FIELDS

+
       size
+               Specifies the maximum number of work completions that may be on the
+               completion queue.  If the creation call is successful, the actual
+               size of the completion queue will be returned.  The actual size of
+               the CQ will be greater than or equal to the requested size.
+
+       pfn_comp_cb
+               A callback that is invoked whenever a signaled completion occurs on
+               the completion queue.  This field is mutually exclusive with the
+               p_event field.
+
+       h_wait_obj
+               A wait object that is triggered whenever a signaled completion occurs
+               on the completion queue.  This field is mutually exclusive with the
+               pfn_comp_cb field and is only valid for user-mode clients.  The wait
+               object must be ready for use when the call to ib_create_cq is invoked.
+
+

NOTES

+
       Clients must specify either an event or a callback when creating a
+       completion queue.  When a signaled completion occurs on the completion
+       queue, the client will be notified through the callback or by
+       signaling the specified event.
+
+

SEE ALSO

+
       ib_create_cq, ib_pfn_comp_cb_t
+
+
+
+ +

[Functions] +Access Layer/ib_create_av

+ +

[top][parent][index]

+

NAME

+
       ib_create_av
+
+

DESCRIPTION

+
       Creates an address vector.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_create_av(
+        IN              const   ib_pd_handle_t FUNC_PTR64                          h_pd,
+        IN              const   ib_av_attr_t* const                     p_av_attr,
+                OUT                     ib_av_handle_t FUNC_PTR64* const           ph_av );
+
+

PARAMETERS

+
       h_pd
+               [in] A handle to an allocated protection domain that the address
+               vector will be associated with.
+
+       p_av_attr
+               [in] Attributes for the newly created address vector.
+
+       ph_av
+               [out] Upon successful completion of this call, this references a
+               handle to the newly created address vector.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The operation was successful.
+
+       IB_INVALID_PD_HANDLE
+               The protection domain handle was invalid.
+
+       IB_INVALID_PARAMETER
+               A reference to the address vector attributes or handle was not
+               provided.
+
+       IB_INSUFFICIENT_MEMORY
+               There was insufficient memory to create the address vector.
+
+       IB_INVALID_PORT
+               The port number supplied, through the address vector attributes,
+               was invalid for the given channel adapter.
+
+       IB_INSUFFICIENT_RESOURCES
+               There were insufficient resources currently available on the channel
+               adapter to create the address vector.
+
+

NOTES

+
       This routine creates an address vector.  Clients specify the attributes
+       of the address vector through the p_av_attr parameter.
+
+

SEE ALSO

+
       ib_query_av, ib_modify_av, ib_destroy_av
+
+
+
+ +

[Functions] +Access Layer/ib_create_cq

+ +

[top][parent][index]

+

NAME

+
       ib_create_cq
+
+

DESCRIPTION

+
       Creates a completion queue and returns its handle to the user.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_create_cq(
+        IN              const   ib_ca_handle_t FUNC_PTR64                          h_ca,
+        IN      OUT                     ib_cq_create_t* const           p_cq_create,
+        IN              const   void* const                                     cq_context,
+        IN              const   ib_pfn_event_cb_t                       pfn_cq_event_cb OPTIONAL,
+                OUT                     ib_cq_handle_t FUNC_PTR64* const           ph_cq );
+
+

PARAMETERS

+
       h_ca
+               [in] A handle to an open channel adapter.
+
+       p_cq_create
+               [in] Attributes necessary to allocate and initialize the
+               completion queue.
+
+       cq_context
+               [in] A user-specified context associated with the completion queue.
+
+       pfn_cq_event_cb
+               [in] User-specified error callback routine invoked after an
+               asynchronous event has occurred on the completion queue.
+
+       ph_cq
+               [out] Upon successful completion of this call, this references a
+               handle to the newly created completion queue.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The completion queue was successfully created.
+
+       IB_INVALID_CA_HANDLE
+               The channel adapter handle was invalid.
+
+       IB_INVALID_PARAMETER
+               A reference to the completion queue attributes or handle was not
+               provided.
+
+       IB_INVALID_SETTING
+               The specified attributes that should be used to create the completion
+               queue are invalid.  Both completion callback and wait object
+               information were supplied or are missing.
+
+       IB_INSUFFICIENT_MEMORY
+               There was insufficient memory to create the completion queue.
+
+       IB_INSUFFICIENT_RESOURCES
+               There were insufficient resources currently available on the channel
+               adapter to create the completion queue.
+
+       IB_INVALID_CQ_SIZE
+               The requested size of the completion queue was larger than the
+               maximum supported by the associated channel adapter.
+
+

NOTES

+
       This routine allocates a completion queue on the specified channel
+       adapter.  If the completion queue cannot be allocated, an error is
+       returned.  When creating the completion queue, users associate a context
+       with the completion queue.  This context is returned to the user through
+       the completion and asynchronous event callbacks.
+
+

SEE ALSO

+
       ib_query_cq, ib_modify_cq, ib_destroy_cq, ib_cq_create_t, ib_pfn_event_cb_t
+
+
+
+ +

[Functions] +Access Layer/ib_create_ioc

+ +

[top][parent][index]

+

NAME

+
       ib_create_ioc
+
+

DESCRIPTION

+
       Creates an instance of an I/O controller.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_create_ioc(
+        IN              const   ib_ca_handle_t FUNC_PTR64                          h_ca,
+        IN              const   ib_ioc_profile_t* const         p_ioc_profile,
+                OUT                     ib_ioc_handle_t FUNC_PTR64* const          ph_ioc );
+
+

PARAMETERS

+
       h_ca
+               [in] A handle to an opened channel adapter.  The controller will be
+               created to be exposed through the given adapter.
+
+       p_ioc_profile
+               [in] I/O controller profile information.
+
+       ph_ioc
+               [out] Upon successful completion of this call, this references a
+               handle to the created I/O controller.  This handle may be used to
+               add service entries to the controller and register it.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The I/O controller was successfully created.
+
+       IB_INVALID_CA_HANDLE
+               The channel adapter handle was invalid.
+
+       IB_INVALID_PARAMETER
+               A reference to the I/O controller profile information or handle
+               was not provided.
+
+       IB_INSUFFICIENT_MEMORY
+               There was insufficient memory to create the I/O controller.
+
+

NOTES

+
       This routine creates an I/O controller.  Once created, services may be
+       added to the controller before being registered with the local device
+       manager.
+
+

SEE ALSO

+
       ib_destroy_ioc, ib_add_svc_entry, ib_reg_ioc, ib_ioc_profile_t
+
+
+
+ +

[Functions] +Access Layer/ib_create_mad_pool

+ +

[top][parent][index]

+

NAME

+
       ib_create_mad_pool
+
+

DESCRIPTION

+
       Creates a pool of MAD elements for use sending and receive management
+       datagrams.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_create_mad_pool(
+        IN              const   ib_al_handle_t FUNC_PTR64                          h_al,
+        IN              const   size_t                                          min,
+        IN              const   size_t                                          max,
+        IN              const   size_t                                          grow_size,
+                OUT                     ib_pool_handle_t FUNC_PTR64* const         ph_pool );
+
+

PARAMETERS

+
       h_al
+               [in] A handle to an open instance of the access layer.
+
+       min
+               [in] The minimum number of MAD elements to create in the pool.
+
+       max
+               [in] The maximum number of MAD elements that will be created by the
+               pool.  If max is set to 0, the pool will continue to grow as long
+               as system resources are available.
+
+       grow_size
+               [in] The number of MAD elements to add to the pool when growing it.
+               If set to 0, the pool will not grow beyond the number specified
+               at creation.  This value must be greater than 0, if min is set to 0.
+
+       ph_pool
+               [out] On successful completion of this call, this returns a handle to
+               the newly created pool.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The MAD pool was created successfully.
+
+       IB_INVALID_AL_HANDLE
+               The access layer handle was invalid.
+
+       IB_INVALID_PARAMETER
+               A reference to the pool handle was not provided.
+
+       IB_INVALID_SETTING
+               The maximum number of MAD elements was non-zero and less than the
+               minimum number of MAD elements.
+
+       IB_INSUFFICIENT_MEMORY
+               There was insufficient memory to create the MAD pool.
+
+

NOTES

+
       This routine creates a pool of MAD elements.  The elements may be used
+       to send and receive MADs on alias and MAD type QPs.
+
+

SEE ALSO

+
       ib_destroy_mad_pool, ib_get_mad, ib_put_mad, ib_reg_mad_pool,
+       ib_dereg_mad_pool
+
+
+
+ +

[Functions] +Access Layer/ib_create_mw

+ +

[top][parent][index]

+

NAME

+
       ib_create_mw
+
+

DESCRIPTION

+
       Creates a memory window associated with the specified protection domain.
+       Newly created windows are not bound to any specific memory region.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_create_mw(
+        IN              const   ib_pd_handle_t FUNC_PTR64                          h_pd,
+                OUT                     net32_t* const                          p_rkey,
+                OUT                     ib_mw_handle_t FUNC_PTR64* const           ph_mw );
+
+

PARAMETERS

+
       h_pd
+               [in] A handle to an existing protection domain that the memory window
+               should be created within.
+
+       p_rkey
+               [out] The current rkey associated with the memory window.  This key is
+               used to bind the window to a registered memory region.
+
+       ph_mw
+               [out] Upon successful completion of this call, this references a handle
+               to the memory window.  This handle is used to bind and destroy
+               the window.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The memory window was successfully created.
+
+       IB_INVALID_PD_HANDLE
+               The protection domain handle was invalid.
+
+       IB_INVALID_PARAMETER
+               A reference to the memory window rkey or handle was not provided.
+
+       IB_INSUFFICIENT_MEMORY
+               There was insufficient memory to create the memory window.
+
+       IB_INSUFFICIENT_RESOURCES
+               There were insufficient resources currently available on the channel
+               adapter to create the memory window.
+
+

NOTES

+
       This routine creates an unbound memory window associated with a specified
+       protection domain.  The memory window cannot be used for data transfer
+       operations until being bound to a registered memory region.
+
+

SEE ALSO

+
       ib_destroy_mw, ib_query_mw, ib_bind_mw
+
+
+
+ +

[Functions] +Access Layer/ib_create_qp

+ +

[top][parent][index]

+

NAME

+
       ib_create_qp
+
+

DESCRIPTION

+
       Creates a queue pair and returns its handle to the user.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_create_qp(
+        IN              const   ib_pd_handle_t FUNC_PTR64                          h_pd,
+        IN              const   ib_qp_create_t* const           p_qp_create,
+        IN              const   void* const                                     qp_context,
+        IN              const   ib_pfn_event_cb_t                       pfn_qp_event_cb OPTIONAL,
+                OUT                     ib_qp_handle_t FUNC_PTR64* const           ph_qp );
+
+

PARAMETERS

+
       h_pd
+               [in] This is a handle to a protection domain associated with the queue
+               pair.
+
+       p_qp_create
+               [in] Attributes necessary to allocate and initialize the queue pair.
+
+       qp_context
+               [in] A user-specified context information associated with the
+               queue pair.
+
+       pfn_qp_event_cb
+               [in] User-specified error callback routine invoked after an
+               asynchronous event has occurred on the queue pair.
+
+       ph_qp
+               [out] Upon successful completion of this call, this references a
+               handle to the newly created queue pair.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The queue pair was successfully created.
+
+       IB_INVALID_PD_HANDLE
+               The protection domain to associate with the queue pair was invalid.
+
+       IB_INVALID_PARAMETER
+               A reference to the queue pair attributes or handle was not provided.
+
+       IB_INSUFFICIENT_MEMORY
+               There was insufficient memory to create the queue pair.
+
+       IB_INSUFFICIENT_RESOURCES
+               There were insufficient resources currently available on the channel
+               adapter to create the queue pair.
+
+       IB_INVALID_CQ_HANDLE
+               The send or receive completion queue to associate with the queue pair
+               was invalid.
+
+       IB_INVALID_SRQ_HANDLE
+               The shared receive queue to be associated with the queue pair
+               was invalid.
+
+       IB_INVALID_SETTING
+               The specified queue pair creation attributes are invalid.
+
+       IB_UNSUPPORTED
+               The specified queue pair type was not supported by the channel adapter.
+
+       IB_INVALID_MAX_WRS
+               The requested maximum send or receive work request depth could not be
+               supported.
+
+       IB_INVALID_MAX_SGE
+               The requested maximum number of scatter-gather entries for the send or
+               receive queue could not be supported.
+
+

NOTES

+
       1. This routine allocates a queue pair with the specified attributes.  If
+       the queue pair cannot be allocated, an error is returned.  When creating
+       the queue pair, users associate a context with the queue pair.  This
+       context is returned to the user through the asynchronous event callback
+       if an event occurs.
+
+       2. For QPs that are associated with an SRQ, the Consumer should take
+       the QP through the Error State before invoking a Destroy QP or a Modify
+       QP to the Reset State. The Consumer may invoke the Destroy QP without
+       first performing a Modify QP to the Error State and waiting for the Affiliated 
+       Asynchronous Last WQE Reached Event. However, if the Consumer
+       does not wait for the Affiliated Asynchronous Last WQE Reached Event,
+       then WQE and Data Segment leakage may occur.
+
+       3. This routine is used to create queue pairs of type:
+               IB_QPT_RELIABLE_CONN
+               IB_QPT_UNRELIABLE_CONN
+               IB_QPT_UNRELIABLE_DGRM
+               IB_QPT_MAD
+
+       4. Callers of ib_create_qp should call ib_init_dgrm_svc if the queue pair
+       is of type IB_QPT_UNRELIABLE_DGRM or IB_QPT_MAD before sending or
+       receiving data.  IB_QPT_RELIABLE_CONN, IB_QPT_UNRELIABLE_CONN type
+       queue pairs should be used by the connection establishment process
+       before data may be sent or received on the QP.
+
+       This call does not return the QP attributes as MAD QPs do not support
+       such an operation.  This is a minor specification deviation.
+
+

SEE ALSO

+
       ib_query_qp, ib_modify_qp, ib_destroy_qp, ib_cm_req, ib_cm_rep, ib_cm_rtu
+       ib_init_dgrm_svc, ib_qp_create_t, ib_pfn_event_cb_t, ib_qp_attr_t
+
+
+
+ +

[Functions] +Access Layer/ib_create_srq

+ +

[top][parent][index]

+

NAME

+
       ib_create_srq
+
+

DESCRIPTION

+
       Creates a shared receive queue and returns its handle to the user.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_create_srq(
+        IN              const   ib_pd_handle_t FUNC_PTR64                  h_pd,
+        IN              const   ib_srq_attr_t* const            p_srq_attr,
+        IN              const   void* const                             srq_context,
+        IN              const   ib_pfn_event_cb_t                       pfn_srq_event_cb OPTIONAL,
+                OUT             ib_srq_handle_t FUNC_PTR64* const          ph_srq );
+
+

PARAMETERS

+
       h_pd
+               [in] This is a handle to a protection domain associated with the shared queue
+               pair.
+
+       p_srq_attr
+               [in] Attributes necessary to allocate and initialize a shared receive queue.
+
+       srq_context
+               [in] A user-specified context information associated with the shared
+               receive queue.
+
+       pfn_qp_event_cb
+               [in] User-specified error callback routine invoked after an
+               asynchronous event has occurred on the shared receive queue.
+
+       ph_srq
+               [out] Upon successful completion of this call, this references a
+               handle to the newly created shared receive queue.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The receive queue was successfully created.
+
+       IB_INVALID_PD_HANDLE
+               The protection domain to associate with the shared receive queue was invalid.
+
+       IB_INVALID_PARAMETER
+               A reference to the shared receive queue attributes or handle was not provided.
+
+       IB_INSUFFICIENT_MEMORY
+               There was insufficient memory to create the shared receive queue.
+
+       IB_INSUFFICIENT_RESOURCES
+               There were insufficient resources currently available on the channel
+               adapter to create the shared receive queue.
+
+       IB_INVALID_SETTING
+               The specified shared receive queue creation attributes are invalid.
+
+       IB_INVALID_MAX_WRS
+               The requested maximum send or receive work request depth could not be
+               supported.
+
+       IB_INVALID_MAX_SGE
+               The requested maximum number of scatter-gather entries for the send or
+               receive queue could not be supported.
+
+

NOTES

+
       This routine allocates a shared receive queue with the specified attributes.  If
+       the shared receive queue cannot be allocated, an error is returned.  When creating
+       the shared receive queue, users associate a context with the shared receive queue.  This
+       context is returned to the user through the asynchronous event callback
+       if an event occurs.
+
+       This routine is used to create receive queues, which work with QPs of type:
+
+       IB_QPT_RELIABLE_CONN
+       IB_QPT_UNRELIABLE_CONN
+       IB_QPT_UNRELIABLE_DGRM
+
+

SEE ALSO

+
       ib_query_srq, ib_modify_srq, ib_destroy_srq, ib_srq_attr_t,
+       ib_srq_attr_mask_t, ib_pfn_event_cb_t, ib_qp_attr_t
+
+
+
+ +

[Functions] +Access Layer/ib_dealloc_pd

+ +

[top][parent][index]

+

NAME

+
       ib_dealloc_pd
+
+

DESCRIPTION

+
       Deallocates a protection domain.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_dealloc_pd(
+        IN              const   ib_pd_handle_t FUNC_PTR64                          h_pd,
+        IN              const   ib_pfn_destroy_cb_t                     pfn_destroy_cb OPTIONAL );
+
+

PARAMETERS

+
       h_pd
+               [in] A handle to an allocated protection domain.
+
+       pfn_destroy_cb
+               [in] A user-specified callback that is invoked after the protection
+               domain has been successfully destroyed.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The operation was successful.
+
+       IB_INVALID_PD_HANDLE
+               The protection domain handle was invalid.
+
+

NOTES

+
       This call deallocates a protection domain and releases all associated
+       resources, including queue pairs and registered memory regions.  Since
+       callbacks may be outstanding against one of protection domain's related
+       resources at the time the deallocation call is invoked, this call operates
+       asynchronously.  The user will be notified through a callback once the
+       deallocation call completes, indicating that no additional callbacks
+       will be invoked for a related resource.
+
+

SEE ALSO

+
       ib_alloc_pd
+
+
+
+ +

[Functions] +Access Layer/ib_dereg_mad_pool

+ +

[top][parent][index]

+

NAME

+
       ib_dereg_mad_pool
+
+

DESCRIPTION

+
       Deregisters a MAD pool from a protection domain.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_dereg_mad_pool(
+        IN              const   ib_pool_key_t FUNC_PTR64                           pool_key );
+
+

PARAMETERS

+
       pool_key
+               [in] Key to the MAD pool to deregister.  The specified pool must
+               have been registered with a protection domain through a call to
+               ib_reg_mad_pool.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The MAD pool was successfully deregistered from the protection domain.
+
+       IB_INVALID_PARAMETER
+               The MAD pool key was invalid.
+
+       IB_RESOURCE_BUSY
+               One or more MAD elements were removed from the MAD pool using the
+               specified pool key, and were not returned.
+
+

NOTES

+
       This function deregisters a MAD pool with a protection domain.  After
+       successful completion of this call, the MAD elements of the associated
+       pool are no longer usable on the protection domain.
+
+

SEE ALSO

+
       ib_create_mad_pool, ib_destroy_mad_pool, ib_reg_mad_pool
+
+
+
+ +

[Functions] +Access Layer/ib_dereg_mr

+ +

[top][parent][index]

+

NAME

+
       ib_dereg_mr
+
+

DESCRIPTION

+
       Deregisters a registered memory region.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_dereg_mr(
+        IN              const   ib_mr_handle_t FUNC_PTR64                          h_mr );
+
+

PARAMETERS

+
       h_mr
+               [in] A handle to a registered memory region that will be unregistered.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The memory region was successfully deregistered.
+
+       IB_INVALID_MR_HANDLE
+               The memory region handle was invalid.
+
+       IB_RESOURCE_BUSY
+               The memory region has memory windows bound to it.
+
+

NOTES

+
       This routine deregisters a memory region with a channel adapter.  The
+       region may be deregistered only if there are no memory  windows or
+       existing shared memory regions currently bound to the region.  Work
+       requests referencing this region when it is deregistered will fail
+       with a WRS_LOCAL_PROTECTION_ERR error.
+
+

SEE ALSO

+
       ib_reg_mem, ib_reg_phys, ib_reg_shared
+
+
+
+ +

[Functions] +Access Layer/ib_dereg_pnp

+ +

[top][parent][index]

+

NAME

+
       ib_dereg_pnp
+
+

DESCRIPTION

+
       Routine used to cancel notification of local events or I/O controller
+       assignments.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_dereg_pnp(
+        IN              const   ib_pnp_handle_t FUNC_PTR64                         h_pnp,
+        IN              const   ib_pfn_destroy_cb_t                     pfn_destroy_cb OPTIONAL );
+
+

PARAMETERS

+
       h_pnp
+               [in] A handle returned as a result of an ib_reg_pnp operation.
+
+       pfn_destroy_cb
+               [in] A user-specified callback that is invoked after the PnP
+               registration has been successfully deregistered.
+
+

NOTES

+
       This routine cancels a pending PnP operation.  To avoid a race condition
+       canceling a request at the same time a notification callback is in
+       progress, the cancel operation operates asynchronously.  For additional
+       details see ib_pfn_destroy_cb_t.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The PnP deregistration was initiated.
+
+       IB_INVALID_HANDLE
+               The PnP handle was invalid.
+
+

SEE ALSO

+
       ib_reg_pnp, ib_pfn_destroy_cb_t
+
+
+
+ +

[Functions] +Access Layer/ib_dereg_svc

+ +

[top][parent][index]

+

NAME

+
       ib_dereg_svc
+
+

DESCRIPTION

+
       Remove a service as being registered with the subnet administrator.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_dereg_svc(
+        IN              const   ib_reg_svc_handle_t                     h_reg_svc,
+        IN              const   ib_pfn_destroy_cb_t                     pfn_destroy_cb OPTIONAL );
+
+

PARAMETERS

+
       h_reg_svc
+               [in] A handle to a registered service.
+
+       pfn_destroy_cb
+               [in] A user-specified callback that is invoked after the service
+               has been deregistered.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The service deregistration was initiated.
+
+       IB_INVALID_HANDLE
+               The registered service handle was invalid.
+
+       IB_INSUFFICIENT_MEMORY
+               There was insufficient memory to perform the operation.
+
+       IB_INSUFFICIENT_RESOURCES
+               There were insufficient resources currently available on the channel
+               adapter to perform the operation.
+
+

NOTES

+
       This routine deregisters a service with the subnet administrator.
+       To avoid a race condition deregistering a service at the same time
+       the registration completion callback is in progress, the deregister
+       operation operates asynchronously.  For additional details see
+       ib_pfn_destroy_cb_t.
+
+

SEE ALSO

+
       ib_reg_svc, ib_pfn_destroy_cb_t
+
+
+
+ +

[Functions] +Access Layer/ib_destroy_av

+ +

[top][parent][index]

+

NAME

+
       ib_destroy_av
+
+

DESCRIPTION

+
       Destroys an existing address vector.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_destroy_av(
+        IN              const   ib_av_handle_t FUNC_PTR64                          h_av );
+
+

PARAMETERS

+
       h_av
+               [in] A handle to an existing address vector.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The address vector was successfully destroyed.
+
+       IB_INVALID_AV_HANDLE
+               The address vector handle was invalid.
+
+

NOTES

+
       This routine destroys an existing address vector.
+
+

SEE ALSO

+
       ib_create_av
+
+
+
+ +

[Functions] +Access Layer/ib_destroy_cq

+ +

[top][parent][index]

+

NAME

+
       ib_destroy_cq
+
+

DESCRIPTION

+
       Destroys a completion queue.  Once destroyed, no further access to the
+       completion queue is possible.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_destroy_cq(
+        IN              const   ib_cq_handle_t FUNC_PTR64                          h_cq,
+        IN              const   ib_pfn_destroy_cb_t                     pfn_destroy_cb OPTIONAL );
+
+

PARAMETERS

+
       h_qp
+               [in] A handle to an existing completion queue.
+
+       pfn_destroy_cb
+               [in] A user-provided callback that is invoked after the
+               completion queue has been successfully destroyed.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The destroy request was registered.
+
+       IB_INVALID_CQ_HANDLE
+               The completion queue handle was invalid.
+
+

NOTES

+
       This call destroys an existing completion queue.  Since callbacks may be
+       outstanding against the completion queue at the time the destroy operation
+       is invoked, the this call operates asynchronously.  The user will be
+       notified through a callback once the destroy operation completes,
+       indicating that no additional callbacks will be invoked for the specified
+       completion queue.
+
+       If there are still queue pairs associated with the completion queue when
+       this function is invoked, the destroy operation will fail with status
+       IB_RESOURCE_BUSY.
+
+

SEE ALSO

+
       ib_create_cq, ib_pfn_destroy_cb_t
+
+
+
+ +

[Functions] +Access Layer/ib_destroy_ioc

+ +

[top][parent][index]

+

NAME

+
       ib_destroy_ioc
+
+

DESCRIPTION

+
       Destroys an instance of an I/O controller.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_destroy_ioc(
+        IN              const   ib_ioc_handle_t FUNC_PTR64                         h_ioc );
+
+

PARAMETERS

+
       h_ioc
+               [in] A handle to an existing I/O controller.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The I/O controller was successfully destroyed.
+
+       IB_INVALID_HANDLE
+               The I/O controller handle was invalid.
+
+

NOTES

+
       Once an I/O controller is destroyed, it is no longer reported by the
+       local device manager as an exported device.  This routine automatically
+       removes all services associated with the controller.
+
+

SEE ALSO

+
       ib_create_ioc
+
+
+
+ +

[Functions] +Access Layer/ib_destroy_mad_pool

+ +

[top][parent][index]

+

NAME

+
       ib_destroy_mad_pool
+
+

DESCRIPTION

+
       Destroys a MAD pool and all associated resources.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_destroy_mad_pool(
+        IN              const   ib_pool_handle_t FUNC_PTR64                        h_pool );
+
+

PARAMETERS

+
       h_pool
+               [in] A handle to a MAD pool allocated through the ib_create_mad_pool
+               routine.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The MAD pool was successfully destroyed.
+
+       IB_INVALID_HANDLE
+               The MAD pool handle was invalid.
+
+       IB_RESOURCE_BUSY
+               One or more MAD elements have not been returned to the MAD pool.
+
+

NOTES

+
       This call destroys a MAD pool and all resources allocated by the pool.
+
+

SEE ALSO

+
       ib_create_mad_pool, ib_get_mad, ib_put_mad
+
+
+
+ +

[Functions] +Access Layer/ib_destroy_mw

+ +

[top][parent][index]

+

NAME

+
       ib_destroy_mw
+
+

DESCRIPTION

+
       Destroys a memory window.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_destroy_mw(
+        IN              const   ib_mw_handle_t FUNC_PTR64                          h_mw );
+
+

PARAMETERS

+
       h_mw
+               [in] A handle to an existing memory window.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The memory window was successfully destroyed.
+
+       IB_INVALID_MW_HANDLE
+               The memory window handle was invalid.
+
+

NOTES

+
       This routine deallocates a window entry created via a ib_create_mw.
+       Once this operation is complete, future accesses to the window will fail.
+
+

SEE ALSO

+
       ib_create_mw
+
+
+
+ +

[Functions] +Access Layer/ib_destroy_qp

+ +

[top][parent][index]

+

NAME

+
       ib_destroy_qp
+
+

DESCRIPTION

+
       Release a queue pair.  Once destroyed, no further access to this
+       queue pair is possible.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_destroy_qp(
+        IN              const   ib_qp_handle_t FUNC_PTR64                          h_qp,
+        IN              const   ib_pfn_destroy_cb_t                     pfn_destroy_cb OPTIONAL );
+
+

PARAMETERS

+
       h_qp
+               [in] A handle to an existing queue pair.
+
+       pfn_destroy_cb
+               [in] A user-specified callback that is invoked after the queue pair
+               has been successfully destroyed.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The destroy request was registered.
+
+       IB_INVALID_QP_HANDLE
+               The queue pair handle was invalid.
+
+

NOTES

+
       This call destroys an existing queue pair.  Since callbacks may be
+       outstanding against the queue pair at the time the destroy operation is
+       invoked, the this call operates asynchronously.  The user will be notified
+       through a callback once the destroy operation completes, indicating that
+       no additional callbacks will be invoked for the specified queue pair.
+
+

SEE ALSO

+
       ib_create_qp
+
+
+
+ +

[Functions] +Access Layer/ib_destroy_srq

+ +

[top][parent][index]

+

NAME

+
       ib_destroy_srq
+
+

DESCRIPTION

+
       Release a shared receive queue.  Once destroyed, no further access to this
+       shared receive queue is possible.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_destroy_srq(
+        IN              const   ib_srq_handle_t FUNC_PTR64                         h_srq,
+        IN              const   ib_pfn_destroy_cb_t                     pfn_destroy_cb OPTIONAL );
+
+

PARAMETERS

+
       h_srq
+               [in] A handle to an existing shared shared receive queue.
+
+       pfn_destroy_cb
+               [in] A user-specified callback that is invoked after the shared receive queue
+               has been successfully destroyed.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The destroy request was registered.
+
+       IB_INVALID_SRQ_HANDLE
+               The shared receive queue handle was invalid.
+
+       IB_RESOURCE_BUSY
+               There are QPs, bound to the shared receive queue
+
+

NOTES

+
       This call destroys an existing shared receive queue.  Since callbacks may be
+       outstanding against the shared receive queue at the time the destroy operation is
+       invoked, then this call operates asynchronously.  The user will be notified
+       through a callback once the destroy operation completes, indicating that
+       no additional callbacks will be invoked for the specified shared receive queue.
+
+

SEE ALSO

+
       ib_query_srq, ib_modify_srq, ib_destroy_srq, ib_srq_attr_t,
+       ib_srq_attr_mask_t, ib_pfn_event_cb_t, ib_qp_attr_t
+
+
+
+ +

[Definitions] +Access Layer/ib_device_attr_mask_t

+ +

[top][parent][index]

+

NAME

+
       ib_device_attr_mask_t
+
+

DESCRIPTION

+
       Used to specify desired attributes of a device or port.
+
+

SYNOPSIS

+
#define         IB_DEV_PORT_ACTIVE              0x1
+
+

VALUES

+
       IB_DEV_PORT_ACTIVE
+               Specifies that a port state should be active.  Applies only to port
+               GUIDs.
+
+

SEE ALSO

+
       ib_get_guid
+
+
+
+ +

[Structures] +Access Layer/ib_dgrm_info_t

+ +

[top][parent][index]

+

NAME

+
       ib_dgrm_info_t
+
+

DESCRIPTION

+
       Information specified when initializing a datagram queue pair before its
+       first use.
+
+

SYNOPSIS

+
typedef struct _ib_dgrm_info
+{
+        ib_net64_t                                      port_guid;
+        uint32_t                                        qkey;
+        uint16_t                                        pkey_index;
+
+}       ib_dgrm_info_t;
+
+

FIELDS

+
       port_guid
+               Specifies the port that the datagram service will use.  This field
+               applies only to IB_QPT_UNRELIABLE_DGRM and IB_QPT_MAD QP types.
+
+       qkey
+               Specifies the qkey that the queue pair will use.  Incoming messages
+               must have a matching qkey for the message to be accepted by the
+               receiving QP.
+
+       pkey_index
+               Specifies the pkey associated with this queue pair.
+
+

SEE ALSO

+
       ib_init_dgrm_svc
+
+
+
+ +

[Structures] +Access Layer/ib_drep_pdata_t

+ +

[top][parent][index]

+

NAME

+
       ib_drep_pdata_t
+
+

DESCRIPTION

+
       User data sent as part of a reply to a disconnection request.
+
+

SYNOPSIS

+
typedef union _ib_drep_pdata
+{
+        uint8_t                                         data[IB_DREP_PDATA_SIZE];
+
+}       ib_drep_pdata_t;
+
+

SEE ALSO

+
       ib_cm_data_sizes_t
+
+
+
+ +

[Structures] +Access Layer/ib_dreq_pdata_t

+ +

[top][parent][index]

+

NAME

+
       ib_dreq_pdata_t
+
+

DESCRIPTION

+
       User data sent as part of a disconnection request.
+
+

SYNOPSIS

+
typedef union _ib_dreq_pdata
+{
+        uint8_t                                         data[IB_DREQ_PDATA_SIZE];
+
+}       ib_dreq_pdata_t;
+
+

SEE ALSO

+
       ib_cm_data_sizes_t
+
+
+
+ +

[Functions] +Access Layer/ib_force_apm

+ +

[top][parent][index]

+

NAME

+
       ib_force_apm
+
+

DESCRIPTION

+
       This routine indicates that a queue pair should immediately migrate to its
+       alternate path.  All future data transfers will occur over the new path.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_force_apm(
+        IN              const   ib_qp_handle_t FUNC_PTR64                          h_qp );
+
+

PARAMETERS

+
       h_qp
+               [in] A handle to the queue pair to migrate.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The queue pair or end-to-end context was successfully modified.
+
+       IB_INVALID_PARAMETER
+               Neither or both of the queue pair or the end-to-end context handles
+               were valid.
+
+       IB_INVALID_QP_HANDLE
+               The queue pair handle was invalid.
+
+       IB_INSUFFICIENT_RESOURCES
+               There were insufficient resources currently available on the channel
+               adapter to register the modify the queue pair or end-to-end context.
+
+       IB_UNSUPPORTED
+               The requested modification was not supported.
+
+       IB_INVALID_QP_STATE
+               The queue pair was in an invalid state for the requested operation.
+
+

NOTES

+
       For this routine to operate correctly, the specified queue pair must have
+       an existing alternate path loaded.  If an alternate path is not loaded, or
+       has not yet been armed, this call will fail.
+
+       Use of this call results in additional data transfers that occur on the
+       given queue pair using the alternate path.  Once this call completes, a
+       new alternate path may be loaded using the ib_cm_lap call.
+
+

SEE ALSO

+
       ib_cm_lap
+
+
+
+ +

[Functions] +Access Layer/ib_get_ca_by_gid

+ +

[top][parent][index]

+

NAME

+
       ib_get_ca_by_gid
+
+

DESCRIPTION

+
       Returns the GUID of a channel adapter contain the given port GID.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_get_ca_by_gid(
+        IN                              ib_al_handle_t FUNC_PTR64                          h_al,
+        IN              const   ib_gid_t* const                         p_gid,
+                OUT                     ib_net64_t* const                       p_ca_guid );
+
+

PARAMETERS

+
       h_al
+               [in] A handle to an opened instance of the access layer.
+
+       p_gid
+               [in] A port GID.
+
+       p_ca_guid
+               [out] A GUID to the CA that contains the port matching the user-
+               specified GID.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The operation was successful.
+
+       IB_INVALID_AL_HANDLE
+               The access layer handle was invalid.
+
+       IB_INVALID_PARAMETER
+               A reference to the port GID or CA GUID was not provided.
+
+       IB_INSUFFICIENT_MEMORY
+               There was insufficient memory to perform the operation.
+
+       IB_NOT_FOUND
+               No channel adapters in the system contain the specifed port GID.
+
+

NOTES

+
       This routine returns a CA GUID that contains the user-specified port GID.
+       If no channel adapters in the system contain the port GID, the call will
+       return IB_NOT_FOUND.
+
+

SEE ALSO

+
       ib_open_al, ib_open_ca, ib_get_ca_guids
+
+
+
+ +

[Functions] +Access Layer/ib_get_ca_guids

+ +

[top][parent][index]

+

NAME

+
       ib_get_ca_guids
+
+

DESCRIPTION

+
       Returns a list of GUIDS for all channel adapter currently available in
+       the system.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_get_ca_guids(
+        IN                              ib_al_handle_t FUNC_PTR64                          h_al,
+                OUT                     ib_net64_t* const                       p_guid_array OPTIONAL,
+        IN      OUT                     size_t* const                           p_guid_cnt );
+
+

PARAMETERS

+
       h_al
+               [in] A handle to an opened instance of the access layer.
+
+       p_guid_array
+               [out] An array of GUIDs provided by the user and filled out by the
+               access layer.  If this parameter is NULL, the access layer will return
+               the number of entries in the array necessary to retrieve the GUID list.
+
+       p_guid_cnt
+               [in/out] On input, this specifies the number of entries in the
+               GUID array.
+
+               On output, the access layer will set this to the number of valid
+               entries in the p_guid_array or the minimum number of entries needed
+               in the GUID array in order to return all channel adapter GUIDs.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The operation was successful.
+
+       IB_INVALID_AL_HANDLE
+               The access layer handle was invalid.
+
+       IB_INVALID_PARAMETER
+               A reference to the GUID count was not provided.
+
+       IB_INSUFFICIENT_MEMORY
+               There was insufficient memory to perform the operation.
+
+

NOTES

+
       This routine returns a list of GUIDs for all available channel adapters.
+       When called, the access layer will examine p_guid_cnt to determine the
+       number of entries available in the p_guid_array.  If the count is too
+       small, the function will return IB_INSUFFICIENT_MEMORY, and set p_guid_cnt
+       to the number of needed entries.
+
+

SEE ALSO

+
       ib_open_al, ib_open_ca
+
+
+
+ +

[Functions] +Access Layer/ib_get_guid

+ +

[top][parent][index]

+

NAME

+
       ib_get_guid
+
+

DESCRIPTION

+
       Returns a GUID for a device or port that matches the user-specified
+       attributes.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_get_guid(
+        IN                              ib_al_handle_t FUNC_PTR64                          h_al,
+        IN              const   uint32_t                                        index,
+        IN              const   ib_pnp_class_t                          device_type,
+        IN              const   uint64_t                                        attr_mask,
+                OUT                     ib_net64_t* const                       p_guid );
+
+

PARAMETERS

+
       h_al
+               [in] A handle to an opened instance of the access layer.
+
+       index
+               [in] Specifies the location of the device or port.  Users specify this
+               value to iterate through all devices or ports on the system.  If set
+               to IB_ANY_INDEX, then the first device or port matching the given
+               attributes will be returned.
+
+       device_type
+               [in] Indicates the type of device to retrieve the GUID for.
+
+       attr_mask
+               [in] Specifies a set of attributes that the given device or port
+               must have for a successful match to occur.
+
+       p_guid
+               [out] On successful return, this parameter will reference the GUID
+               of the device or port that contains the specified attributes.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The operation was successful.
+
+       IB_INVALID_AL_HANDLE
+               The access layer handle was invalid.
+
+       IB_INVALID_SETTING
+               The specified device type is invalid.
+
+       IB_INVALID_PARAMETER
+               No p_guid parameter was specified.
+
+       IB_NO_MATCH
+               The device or port at the specified index does not have the given
+               attributes.
+
+       IB_INVALID_INDEX
+               No device or port exists for the specified index.
+
+

NOTES

+
       This routine returns a GUID for a device or port that matches the
+       user-specified attributes.  If index is IB_ANY_INDEX, then the first
+       device or port matching the given attributes is returned if a match is
+       found.  If no match is found, the call will return IB_NO_MATCH.  If a
+       valid index is specified, then the device or port located at that index
+       will be examined to see if it has the given attributes.  If the device
+       or port with those attributes is found, its GUID is returned.
+
+       This routine may be used to locate a device or port with a given set
+       of attributes, or iterate through all devices or ports on the system.
+       The specified index values are set by the access layer, but the index
+       associated with a GUID may change if devices are removed from the system.
+
+

SEE ALSO

+
       ib_open_al, ib_pnp_class_t, ib_get_ca_guids, ib_query_ca_by_guid
+
+
+
+ +

[Functions] +Access Layer/ib_get_mad

+ +

[top][parent][index]

+

NAME

+
       ib_get_mad
+
+

DESCRIPTION

+
       Obtains a MAD element from the pool.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_get_mad(
+        IN              const   ib_pool_key_t FUNC_PTR64                           pool_key,
+        IN              const   size_t                                          buf_size,
+                OUT                     ib_mad_element_t                        **pp_mad_element );
+
+

PARAMETERS

+
       pool_key
+               [in] Key for the pool to obtain a MAD element for the desired
+               protection domain.
+
+       buf_size
+               [in] The size of the buffer referenced by the MAD element.
+
+       pp_mad_element
+               [out] Upon successful completion of this call, this references
+               the returned MAD element.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The MAD element was successfully retrieved from the MAD pool.
+
+       IB_INVALID_PARAMETER
+               The MAD pool key was invalid or a reference to the MAD element
+               pointer was not provided.
+
+       IB_INSUFFICIENT_MEMORY
+               There was insufficient memory to obtain the MAD element.
+
+       IB_INSUFFICIENT_RESOURCES
+               There were insufficient resources currently available on the channel
+               adapter to grow and register the MAD pool.
+
+

NOTES

+
       This function obtains a MAD element containing a data segment
+       that references a data buffer for the given pool key.  The data buffer
+       referenced by the MAD element is zeroed before being returned to the
+       user.
+
+       It is recommended that elements retrieved from a MAD pool for use on
+       the receive queue of a MAD QP have a buffer size of 256 bytes.
+
+       For MADs being sent, buf_size should be set to the size of the relevant
+       data sent as part of the MAD, and should not include any padding needed
+       to make the MAD size a multiple of 256 bytes.  For most MADs, buf_size
+       may be set equal to the size of the MAD header plus the amount of user
+       data transfered as part of the MAD.
+
+

SEE ALSO

+
       ib_put_mad, ib_send_mad, ib_mad_element_t
+
+
+
+ +

[Functions] +Access Layer/ib_get_mad_buf

+ +

[top][parent][index]

+

NAME

+
       ib_get_mad_buf
+
+

DESCRIPTION

+
       Returns a pointer to the MAD buffer associated with a MAD element.
+
+

SYNOPSIS

+
#pragma warning(push)
+#pragma warning(disable: 4244 ) 
+AL_INLINE void* AL_API
+ib_get_mad_buf(
+        IN              const   ib_mad_element_t* const         p_mad_element )
+{
+        CL_ASSERT( p_mad_element );
+        return( p_mad_element->p_mad_buf );
+}
+#pragma warning (pop)
+
+

PARAMETERS

+
       p_mad_element
+               [in] A pointer to a MAD element.
+
+

NOTES

+
       Returns a pointer to the MAD buffer associated with a MAD element.
+
+

SEE ALSO

+
       ib_mad_element_t
+
+
+
+ +

[Functions] +Access Layer/ib_get_port_by_gid

+ +

[top][parent][index]

+

NAME

+
       ib_get_port_by_gid
+
+

DESCRIPTION

+
       Returns the GUID of a port that contains the given port GID.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_get_port_by_gid(
+        IN                              ib_al_handle_t FUNC_PTR64                          h_al,
+        IN              const   ib_gid_t* const                         p_gid,
+                OUT                     ib_net64_t* const                       p_port_guid );
+
+

PARAMETERS

+
       h_al
+               [in] A handle to an opened instance of the access layer.
+
+       p_gid
+               [in] A port GID.
+
+       p_port_guid
+               [out] A GUID to the port that contains the matching user-
+               specified GID.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The operation was successful.
+
+       IB_INVALID_AL_HANDLE
+               The access layer handle was invalid.
+
+       IB_INVALID_PARAMETER
+               A reference to the port GID or port GUID was not provided.
+
+       IB_INSUFFICIENT_MEMORY
+               There was insufficient memory to perform the operation.
+
+       IB_NOT_FOUND
+               No channel adapters in the system contain the specifed port GID.
+
+

NOTES

+
       This routine returns a port GUID that contains the user-specified port GID.
+       If no channel adapters in the system contain the port GID, the call will
+       return IB_NOT_FOUND.
+
+

SEE ALSO

+
       ib_open_al, ib_open_ca, ib_get_ca_guids
+
+
+
+ +

[Functions] +Access Layer/ib_get_query_node_rec

+ +

[top][parent][index]

+

NAME

+
       ib_get_query_node_rec
+
+

DESCRIPTION

+
       Retrieves a node record result from a MAD returned by a call to
+       ib_query().
+
+

SYNOPSIS

+
AL_INLINE ib_node_record_t* AL_API
+ib_get_query_node_rec(
+        IN                              ib_mad_element_t                        *p_result_mad,
+        IN                              uint32_t                                        result_index )
+{
+        ib_sa_mad_t             *p_sa_mad;
+
+        CL_ASSERT( p_result_mad );
+        p_sa_mad = (ib_sa_mad_t*)ib_get_mad_buf( p_result_mad );
+        CL_ASSERT( p_sa_mad && p_sa_mad->attr_id == IB_MAD_ATTR_NODE_RECORD );
+
+        return( (ib_node_record_t*)ib_get_query_result( p_result_mad,
+                result_index ) );
+}
+
+

PARAMETERS

+
       p_result_mad
+               [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 ib_query().
+
+

SEE ALSO

+
       ib_query_rec_t, ib_mad_element_t, ib_get_query_result, ib_node_record_t
+
+
+
+ +

[Functions] +Access Layer/ib_get_query_path_rec

+ +

[top][parent][index]

+

NAME

+
       ib_get_query_path_rec
+
+

DESCRIPTION

+
       Retrieves a path record result from a MAD returned by a call to
+       ib_query().
+
+

SYNOPSIS

+
AL_INLINE ib_path_rec_t* AL_API
+ib_get_query_path_rec(
+        IN                              ib_mad_element_t                        *p_result_mad,
+        IN                              uint32_t                                        result_index )
+{
+        ib_sa_mad_t             *p_sa_mad;
+
+        CL_ASSERT( p_result_mad );
+        p_sa_mad = (ib_sa_mad_t*)ib_get_mad_buf( p_result_mad );
+        CL_ASSERT( p_sa_mad && p_sa_mad->attr_id == IB_MAD_ATTR_PATH_RECORD );
+
+        return( (ib_path_rec_t*)ib_get_query_result( p_result_mad, result_index ) );
+}
+
+

PARAMETERS

+
       p_result_mad
+               [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 ib_query().
+
+

SEE ALSO

+
       ib_query_rec_t, ib_mad_element_t, ib_get_query_result, ib_path_rec_t
+
+
+
+ +

[Functions] +Access Layer/ib_get_query_portinfo_rec

+ +

[top][parent][index]

+

NAME

+
       ib_get_query_portinfo_rec
+
+

DESCRIPTION

+
       Retrieves a port info record result from a MAD returned by a call to
+       ib_query().
+
+

SYNOPSIS

+
AL_INLINE ib_portinfo_record_t* AL_API
+ib_get_query_portinfo_rec(
+        IN                              ib_mad_element_t                        *p_result_mad,
+        IN                              uint32_t                                        result_index )
+{
+        ib_sa_mad_t             *p_sa_mad;
+
+        CL_ASSERT( p_result_mad );
+        p_sa_mad = (ib_sa_mad_t*)ib_get_mad_buf( p_result_mad );
+        CL_ASSERT( p_sa_mad && p_sa_mad->attr_id == IB_MAD_ATTR_PORTINFO_RECORD );
+
+        return( (ib_portinfo_record_t*)ib_get_query_result( p_result_mad,
+                result_index ) );
+}
+
+

PARAMETERS

+
       p_result_mad
+               [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 ib_query().
+
+

SEE ALSO

+
       ib_query_rec_t, ib_mad_element_t, ib_get_query_result, ib_portinfo_record_t
+
+
+
+ +

[Functions] +Access Layer/ib_get_query_result

+ +

[top][parent][index]

+

NAME

+
       ib_get_query_result
+
+

DESCRIPTION

+
       Retrieves a result structure from a MAD returned by a call to ib_query().
+
+

SYNOPSIS

+
AL_INLINE void* AL_API
+ib_get_query_result(
+        IN                              ib_mad_element_t                        *p_result_mad,
+        IN                              uint32_t                                        result_index )
+{
+        ib_sa_mad_t             *p_sa_mad;
+
+        CL_ASSERT( p_result_mad );
+        p_sa_mad = (ib_sa_mad_t*)ib_get_mad_buf( p_result_mad );
+        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_mad->size );
+
+        return( p_sa_mad->data +
+                (ib_get_attr_size( p_sa_mad->attr_offset ) * result_index) );
+}
+
+

PARAMETERS

+
       p_result_mad
+               [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 ib_query().  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 ib_query_rec_t structure.
+
+

SEE ALSO

+
       ib_query_rec_t, ib_mad_element_t
+
+
+
+ +

[Functions] +Access Layer/ib_get_query_svc_rec

+ +

[top][parent][index]

+

NAME

+
       ib_get_query_svc_rec
+
+

DESCRIPTION

+
       Retrieves a service record result from a MAD returned by a call to
+       ib_query().
+
+

SYNOPSIS

+
AL_INLINE ib_service_record_t* AL_API
+ib_get_query_svc_rec(
+        IN                              ib_mad_element_t                        *p_result_mad,
+        IN                              uint32_t                                        result_index )
+{
+        ib_sa_mad_t             *p_sa_mad;
+
+        CL_ASSERT( p_result_mad );
+        p_sa_mad = (ib_sa_mad_t*)ib_get_mad_buf( p_result_mad );
+        CL_ASSERT( p_sa_mad && p_sa_mad->attr_id == IB_MAD_ATTR_SERVICE_RECORD );
+
+        return( (ib_service_record_t*)ib_get_query_result( p_result_mad,
+                result_index ) );
+}
+
+

PARAMETERS

+
       p_result_mad
+               [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 ib_query().
+
+

SEE ALSO

+
       ib_query_rec_t, ib_mad_element_t, ib_get_query_result, ib_service_record_t
+
+
+
+ +

[Functions] +Access Layer/ib_get_spl_qp

+ +

[top][parent][index]

+

NAME

+
       ib_get_spl_qp
+
+

DESCRIPTION

+
       Create a special QP or QP alias.  This call provides access to queue
+       pairs 0 and 1, and the raw queue pair types.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_get_spl_qp(
+        IN              const   ib_pd_handle_t FUNC_PTR64                          h_pd,
+        IN              const   ib_net64_t                                      port_guid,
+        IN              const   ib_qp_create_t* const           p_qp_create,
+        IN              const   void* const                                     qp_context,
+        IN              const   ib_pfn_event_cb_t                       pfn_qp_event_cb OPTIONAL,
+                OUT                     ib_pool_key_t FUNC_PTR64* const            p_pool_key OPTIONAL,
+                OUT                     ib_qp_handle_t FUNC_PTR64* const           ph_qp );
+
+

PARAMETERS

+
       h_pd
+               [in] This is a handle to a protection domain associated with the queue
+               pair.  This must be a protection domain alias for aliased QP types.
+
+       port_guid
+               [in] The port GUID that the special QP will be associated with.
+
+       p_qp_create
+               [in] Attributes necessary to allocate and initialize the queue pair.
+
+       qp_context
+               [in] A user-specified context information associated with the
+               queue pair.
+
+       pfn_qp_ervent_cb
+               [in] User-specified error callback routine invoked after an
+               asynchronous event has occurred on the queue pair.
+
+       p_pool_key
+               [in] A key to a pool of MAD elements that are used to send MADs.
+               This key is only valid for aliased QP types.
+
+       ph_qp
+               [out] Upon successful completion of this call, this references a
+               handle to the newly created queue pair.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The queue pair was successfully created.
+
+       IB_INVALID_PD_HANDLE
+               The protection domain to associate with the queue pair was invalid.
+
+       IB_INVALID_PORT
+               The port number supplied was invalid for the given channel adapter.
+
+       IB_INVALID_PARAMETER
+               A reference to the queue pair attributes or handle was not provided.
+
+       IB_INVALID_PERMISSION
+               The calling process does not have sufficient privilege to create the
+               requested queue pair type.
+
+       IB_INSUFFICIENT_MEMORY
+               There was insufficient memory to create the queue pair.
+
+       IB_INSUFFICIENT_RESOURCES
+               There were insufficient resources currently available on the channel
+               adapter to create the queue pair.
+
+       IB_INVALID_CQ_HANDLE
+               The send or receive completion queue to associate with the queue pair
+               was invalid.
+
+       IB_INVALID_SETTING
+               The specified queue pair type was invalid.
+
+       IB_UNSUPPORTED
+               The specified queue pair type was not supported by the channel adapter.
+
+       IB_INVALID_MAX_WRS
+               The requested maximum send or receive work request depth could not be
+               supported.
+
+       IB_INVALID_MAX_SGE
+               The requested maximum number of scatter-gather entries for the send or
+               receive queue could not be supported.
+
+

NOTES

+
       This routine allocates a queue pair with the specified attributes.  If
+       the queue pair cannot be allocated, an error is returned.  When creating
+       the queue pair, users associate a context with the queue pair.  This
+       context is returned to the user through the asynchronous event callback
+       if an event occurs.
+
+       This routine is used to create queue pairs of type:
+
+       IB_QPT_QP0
+       IB_QPT_QP1
+       IB_QPT_RAW_IPV6
+       IB_QPT_RAW_ETHER
+       IB_QPT_QP0_ALIAS
+       IB_QPT_QP1_ALIAS
+
+       Callers of ib_get_spl_qp should call ib_init_dgrm_svc if the queue pair is
+       of type IB_QPT_QP0, IB_QPT_QP1, IB_QPT_RAW_IPV6, IB_QPT_RAW_ETHER before
+       sending or receiving data.  MADs may be sent on aliased QPs on the
+       successful return of this routine.
+
+

SEE ALSO

+
       ib_query_qp, ib_modify_qp, ib_destroy_qp, ib_get_mad
+       ib_init_dgrm_svc, ib_qp_create_t, ib_pfn_event_cb_t, ib_qp_attr_t
+
+
+
+ +

[Structures] +Access Layer/ib_gid_pair_t

+ +

[top][parent][index]

+

NAME

+
       ib_gid_pair_t
+
+

DESCRIPTION

+
       Source and destination GIDs.
+
+

SYNOPSIS

+
typedef struct _ib_gid_pair
+{
+        ib_gid_t                                        src_gid;
+        ib_gid_t                                        dest_gid;
+
+}       ib_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
+
+
+
+ +

[Structures] +Access Layer/ib_guid_pair_t

+ +

[top][parent][index]

+

NAME

+
       ib_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 _ib_guid_pair
+{
+        ib_net64_t                                      src_guid;
+        ib_net64_t                                      dest_guid;
+
+}       ib_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
+
+
+
+ +

[Functions] +Access Layer/ib_init_dgrm_svc

+ +

[top][parent][index]

+

NAME

+
       ib_init_dgrm_svc
+
+

DESCRIPTION

+
       Initializes a datagram queue pair for use.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_init_dgrm_svc(
+        IN              const   ib_qp_handle_t FUNC_PTR64                          h_qp,
+        IN              const   ib_dgrm_info_t* const           p_dgrm_info OPTIONAL );
+
+

PARAMETERS

+
       h_qp
+               [in] A handle to an existing queue pair.
+
+       p_dgrm_info
+               [in] References information needed to configure the queue pair for
+               use sending and receiving datagrams.  This field is optional for
+               IB_QPT_QP0, IB_QPT_QP1 queue pair types and is not used for
+               IB_QPT_RAW_IPV6, and IB_QPT_RAW_ETHER queue pair types.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The datagram queue pair was initialized successfully.
+
+       IB_INVALID_QP_HANDLE
+               The datagram queue pair handle was invalid.
+
+       IB_INVALID_PARAMETER
+               The queue pair handle was not created as a datagram queue pair type
+               or a reference to the datagram service information was not provided.
+
+       IB_INVALID_QP_STATE
+               The queue pair was in an invalid state for the requested operation.
+
+       IB_INSUFFICIENT_MEMORY
+               There was insufficient memory to initialize the datagram queue pair.
+
+

NOTES

+
       This call binds the queue pair to a given port and transitions its state
+       to ready to send and receive data.  A queue pair must be initialized
+       before it can be used to send and receive datagrams.
+
+       This routine is used to initialize queue pairs of type:
+
+       IB_QPT_QP0
+       IB_QPT_QP1
+       IB_QPT_MAD
+       IB_QPT_RAW_IPV6
+       IB_QPT_RAW_ETHER
+       IB_QPT_UNRELIABLE_DGRM
+
+       For IB_QPT_MAD type queue pairs, receive buffers are automatically posted
+       by the access layer, however, users must call ib_reg_mad_svc to receive
+       MADs.  Received MAD elements must be returned to the access layer through
+       the ib_put_mad() call.
+
+

SEE ALSO

+
       ib_create_qp, ib_get_spl_qp, ib_dgrm_info_t, ib_reg_mad_svc
+
+
+
+ +

[Functions] +Access Layer/ib_join_mcast

+ +

[top][parent][index]

+

NAME

+
       ib_join_mcast
+
+

DESCRIPTION

+
       Attaches a queue pair to a multicast group.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_join_mcast(
+        IN              const   ib_qp_handle_t FUNC_PTR64                          h_qp,
+        IN              const   ib_mcast_req_t* const           p_mcast_req );
+
+

PARAMETERS

+
       h_qp
+               [in] A handle to an unreliable datagram queue pair that will join the
+               multicast group.
+
+       p_mcast_req
+               [in] Specifies the multicast group to join.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The join multicast group request has been initiated.
+
+       IB_INVALID_QP_HANDLE
+               The queue pair handle was invalid.
+
+       IB_INVALID_PARAMETER
+               A reference to the multicast group request information was not
+               provided.
+
+       IB_INVALID_SERVICE_TYPE
+               The queue pair configuration does not support this type of service.
+
+       IB_INSUFFICIENT_MEMORY
+               There was insufficient memory to join the multicast group.
+
+       IB_INVALID_GUID
+               No port was found for the port_guid specified in the request.
+
+       IB_INSUFFICIENT_RESOURCES
+               There were insufficient resources currently available on the channel
+               adapter to perform the operation.
+
+       IB_INVALID_PKEY
+               The pkey specified in the multicast join request does not match the
+               pkey of the queue pair.
+
+       IB_INVALID_PORT
+               The port GUID specified in the multicast join request does not match
+               the port of the queue pair.
+
+       IB_ERROR
+               An error occurred while performing the multicast group join operation.
+
+       IB_INSUFFICIENT_RESOURCES
+               There were insufficient resources currently available to complete
+               the request.
+
+       IB_INSUFFICIENT_MEMORY
+               There was insufficient memory to complete the request.
+
+

NOTES

+
       This routine results in the specified queue pair joining a multicast
+       group.  If the multicast group does not already exist, it will be created
+       at the user's option.  Information about the multicast group is returned
+       to the user through a callback specified through the p_mcast_req
+       parameter.
+
+       If the specified queue pair is already a member of a multicast group when
+       this call is invoked, an error will occur if there are conflicting
+       membership requirements.  The QP is restricted to being bound to a single
+       port_guid and using a single pkey.
+
+

SEE ALSO

+
       ib_leave_mcast, ib_mcast_req_t, ib_create_qp, ib_init_dgrm_svc
+
+
+
+ +

[Structures] +Access Layer/ib_lap_pdata_t

+ +

[top][parent][index]

+

NAME

+
       ib_lap_pdata_t
+
+

DESCRIPTION

+
       User data sent as part of a load alternate path message.
+
+

SYNOPSIS

+
typedef union _ib_lap_pdata
+{
+        uint8_t                                         data[IB_LAP_PDATA_SIZE];
+
+}       ib_lap_pdata_t;
+
+

SEE ALSO

+
       ib_cm_data_sizes_t
+
+
+
+ +

[Functions] +Access Layer/ib_leave_mcast

+ +

[top][parent][index]

+

NAME

+
       ib_leave_mcast
+
+

DESCRIPTION

+
       Removes a queue pair from a multicast group.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_leave_mcast(
+        IN              const   ib_mcast_handle_t FUNC_PTR64                       h_mcast,
+        IN              const   ib_pfn_destroy_cb_t                     pfn_destroy_cb OPTIONAL );
+
+

PARAMETERS

+
       h_mcast
+               [in] A handle to a joined multicast group.
+
+       pfn_destroy_cb
+               [in] An optional user-specified callback that is invoked after the
+               leave request has completed.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The leave multicast group request has been initiated.
+
+       IB_INVALID_MCAST_HANDLE
+               The multicast group handle was invalid.
+
+       IB_ERROR
+               An error occurred while performing the multicast group leave operation.
+
+       IB_INSUFFICIENT_RESOURCES
+               There were insufficient resources currently available on the channel
+               adapter to perform the operation.
+
+

NOTES

+
       This routine detaches a queue pair from a multicast group and removes
+       it as a member of the group with the subnet administrator.
+
+

SEE ALSO

+
       ib_join_mcast, ib_pfn_destroy_cb_t
+
+
+
+ +

[Structures] +Access Layer/ib_lid_pair_t

+ +

[top][parent][index]

+

NAME

+
       ib_lid_pair_t
+
+

DESCRIPTION

+
       Source and destination LIDs.
+
+

SYNOPSIS

+
typedef struct _ib_lid_pair
+{
+        ib_net16_t                                      src_lid;
+        ib_net16_t                                      dest_lid;
+
+}       ib_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.
+
+
+
+ +

[Structures] +Access Layer/ib_listen_err_rec_t

+ +

[top][parent][index]

+

NAME

+
       ib_listen_err_rec_t
+
+

DESCRIPTION

+
       Information returned to the user when an error occurs on a listen request.
+
+

SYNOPSIS

+
typedef struct _ib_listen_err_rec
+{
+ TO_LONG_PTR(       void* ,                                                           listen_context) ; 
+        ib_api_status_t                                                         reason;
+        ib_listen_handle_t __ptr64                                                      h_cm_listen;
+
+}       ib_listen_err_rec_t;
+
+

FIELDS

+
       listen_context
+               User-defined context information associated with the listen request
+               through the ib_cm_listen call.
+
+       reason
+               A status that identifies the reason for error being reported.
+
+       h_cm_listen
+               The handle for the listen request.  This handle will match the handle
+               returned by ib_cm_listen call.  It is provided in case an error event
+               occurs before a client's call to ib_cm_listen can return.
+
+

SEE ALSO

+
       ib_pfn_listen_err_cb_t, ib_api_status_t
+
+
+
+ +

[Definitions] +Access Layer/ib_listen_info_t

+ +

[top][parent][index]

+

NAME

+
       ib_listen_info_t
+
+

DESCRIPTION

+
       Constants used to specify directed listen requests.
+
+

SYNOPSIS

+
#define IB_ALL_CAS                                              0
+#define IB_ALL_PORTS                                    0
+#define IB_ALL_LIDS                                             0
+#define IB_ALL_PKEYS                                    0
+
+

SEE ALSO

+
       ib_cm_listen, ib_cm_listen_t
+
+
+
+ +

[Functions] +Access Layer/ib_local_mad

+ +

[top][parent][index]

+

NAME

+
       ib_local_mad
+
+

DESCRIPTION

+
       Request that a locally received MAD be processed by the channel adapter
+       on which it was received.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_local_mad(
+        IN              const   ib_ca_handle_t FUNC_PTR64                          h_ca,
+        IN              const   uint8_t                                         port_num,
+        IN              const   void* const                                     p_mad_in,
+                OUT                     void*                                           p_mad_out );
+
+

PARAMETERS

+
       h_ca
+               [in] A handle to the channel adapter that should process the MAD.
+               This must be the same adapter that the MAD was received on.
+
+       port_num
+               [in] The port number to which this request is directed.
+
+       p_mad_in
+               [in] Pointer to a management datagram (MAD) structure containing
+               the command to be processed.
+
+       p_mad_out
+               [out] References a MAD that should contain the response to the
+               received input MAD specified through the p_mad_in parameter.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The local MAD was processed successfully.
+
+       IB_INVALID_CA_HANDLE
+               The channel adapter handle was invalid.
+
+       IB_INVALID_PORT
+               The port number was invalid.
+
+       IB_INVALID_PARAMETER
+               A reference to the MAD input or MAD output buffer was not provided.
+
+

NOTES

+
       This call is provided to support SMA and GSA implementations above the
+       verbs interface on ports that the access layer has disabled.  This routine
+       is used to perform local operations by the channel adapter.  On successful
+       return, the provide output MAD should be used when sending a response.
+
+

SEE ALSO

+
       ib_query_ca, ib_ca_attr_t
+
+
+
+ +

[Structures] +Access Layer/ib_mad_element_t

+ +

[top][parent][index]

+

NAME

+
       ib_mad_element_t
+
+

DESCRIPTION

+
       Information used to submit a work request to a management datagram (MAD)
+       queue pair.
+
+

SYNOPSIS

+
typedef struct _ib_mad_element
+{
+ TO_LONG_PTR(       struct _ib_mad_element* , p_next) ; 
+ TO_LONG_PTR(       const void* ,                     context1) ; 
+ TO_LONG_PTR(       const void* ,                     context2) ; 
+
+        /* Request/completion data. */
+ TO_LONG_PTR(       ib_mad_t* ,                       p_mad_buf) ; 
+        uint32_t                                        size;
+        uint32_t                                        immediate_data;
+        ib_net32_t                                      remote_qp;
+
+        /* Send request information. */
+        ib_av_handle_t __ptr64                          h_av;
+        ib_send_opt_t                           send_opt;
+        ib_net32_t                                      remote_qkey;
+        boolean_t                                       resp_expected;
+        uint32_t                                        timeout_ms;
+        uint32_t                                        retry_cnt;
+        uint8_t                                         rmpp_version;
+
+        /* Completion information. */
+        ib_wc_status_t                          status;
+        boolean_t                                       grh_valid;
+ TO_LONG_PTR(       ib_grh_t* ,                       p_grh) ; 
+
+        /* Completed receive data or send request information if h_av is NULL. */
+        uint32_t                                        recv_opt;
+        ib_net16_t                                      remote_lid;
+        uint8_t                                         remote_sl;
+        uint16_t                                        pkey_index;
+        uint8_t                                         path_bits;
+
+        /* Transaction completion data. */
+ TO_LONG_PTR(       void* ,                           send_context1) ; 
+ TO_LONG_PTR(       void* ,                           send_context2) ; 
+
+}       ib_mad_element_t;
+
+

FIELDS

+
       p_next
+               A pointer used to chain MAD elements together.  This value is
+               set to NULL to mark the end of the chain.
+
+       context1
+               User-defined context information associated with the datagram.
+
+       context2
+               User-defined context information associated with the datagram.
+
+       p_buffer
+               The local data buffer contain the MAD.
+
+       size
+               The size of the MAD referenced by p_buffer.
+
+       immediate_data
+               32-bit field sent or received as part of a datagram message.
+               This field is valid for send operations if the send_opt
+               IB_SEND_OPT_IMMEDIATE flag has been set.  This field is valid
+               on received datagram completions if the recv_opt
+               IB_RECV_OPT_IMMEDIATE flag is set.
+
+       remote_qp
+               Identifies the destination queue pair of a datagram send operation or
+               the source queue pair of a received datagram.
+
+       h_av
+               An address vector that specifies the path information used to route
+               the outbound datagram to the destination queue pair.  This handle may
+               be NULL when sending a directed route SMP or if the access layer
+               should create the address vector for the user.
+
+       send_opt
+               Optional send control parameters.  The following options are valid:
+               IB_SEND_OPT_IMMEDIATE and IB_SEND_OPT_SOLICITED.  IB_SEND_OPT_FENCE
+               is only valid on MAD QPs.
+
+       remote_qkey
+               The qkey for the destination queue pair.
+
+       resp_expected
+               This field is used to indicate that the submitted operation expects
+               a response.  When set, the access layer will retry this send operation
+               until the corresponding response is successfully received, or the
+               request times out.  Send operations for which a response is expected
+               will always be completed by the access layer before the corresponding
+               received response.
+
+       timeout_ms
+               Specifies the number of milliseconds to wait for a response to
+               a request until retrying or timing out the request.  This field is
+               ignored if resp_expected is set to FALSE.
+
+       retry_cnt
+               Specifies the number of times that the request will be retried
+               before failing the request.  This field is ignored if resp_expected
+               is set to FALSE.
+
+       rmpp_version
+               Indicates the version of the RMPP protocol to use when sending this
+               MAD.  For MADs posted to MAD services of type IB_MAD_SVC_DEFAULT,
+               setting this field to 0 disables RMPP on user-defined management
+               classes or invokes the default RMPP version for well-defined management
+               classes, if appropriate.  For MADs posted to MAD services of type
+               IB_MAD_SVC_RMPP, setting this field to 0 disables RMPP on the sent
+               MAD.  Note that if the RMPP header exists, but the RMPP protocol is
+               not activated for this MAD, the user must ensure that the RMPP header
+               has been zeroed.  This field is intended to help support backwards
+               compatibility.
+
+       status
+               The result of the MAD work request.
+
+       grh_valid
+               A flag indicating whether the p_grh reference is valid.
+
+       p_grh
+               A reference to the global route header information.
+
+       recv_opt
+               Indicates optional fields valid as part of a work request that
+               completed on an unreliable datagram queue pair.
+
+       remote_lid
+               The source LID of the received datagram.
+
+       remote_sl
+               The service level used by the source of the received datagram.
+
+       pkey_index
+               This is valid only for IB_QPT_QP1 and IB_QPT_QP1_ALIAS QP types.
+               For received datagrams, this field contains the pkey index for
+               the source queue pair.  For send operations, this field contains
+               the pkey index to use when posting the send work request. 
+
+       path_bits
+               The portion of the remote_lid that may be changed to vary the path
+               through the subnet to the remote port.
+
+       send_context1
+               If this datagram was received as a response to a sent datagram, this
+               field contains the context1 value of the send operation.  If this is
+               an unsolicited receive, this field will be 0.
+
+       send_context2
+               If this datagram was received as a response to a sent datagram, this
+               field contains the context2 value of the send operation.  If this is
+               an unsolicited receive, this field will be 0.
+
+       remote_qp
+               Identifies the source queue pair of a received datagram.
+
+

NOTES

+
       The format of data sent over the fabric is expected to be in the form
+       of a MAD.  MADs are expected to match the format defined by the
+       Infiniband specification and must be in network-byte order when posted
+       to a MAD service.
+
+       This structure is received to notify a user that a datagram has been
+       received for a registered management class.  Information of the source
+       of the data is provided, along with the data buffer.
+
+       The MAD element structure is defined such that a received MAD element
+       may be re-used as a sent response.  In such cases, the h_av field may be
+       NULL.  The address vector will be created and destroyed by the access
+       layer.
+
+

SEE ALSO

+
       ib_get_mad, ib_put_mad, ib_send_mad, ib_local_ds_t, ib_send_opt_t,
+       ib_pfn_mad_recv_cb_t, ib_get_mad_buf
+
+
+
+ +

[Structures] +Access Layer/ib_mad_svc_t

+ +

[top][parent][index]

+

NAME

+
       ib_mad_svc_t
+
+

DESCRIPTION

+
       Information used to request management datagram support with a queue pair.
+
+

SYNOPSIS

+
typedef struct _ib_mad_svc
+{
+        void                                            *mad_svc_context;
+        ib_pfn_mad_comp_cb_t            pfn_mad_send_cb;
+        ib_pfn_mad_comp_cb_t            pfn_mad_recv_cb;
+
+        boolean_t                                       support_unsol;
+        uint8_t                                         mgmt_class;
+        uint8_t                                         mgmt_version;
+        boolean_t                                       method_array[IB_MAX_METHODS];
+
+        ib_mad_svc_type_t                       svc_type;
+
+}       ib_mad_svc_t;
+
+

FIELDS

+
       mad_svc_context
+               User-defined context that is returned by the access layer through
+               the pfn_mad_send_cb and pfn_mad_recv_cb.
+
+       pfn_mad_send_cb
+               A send callback that is invoked to notify the user that a send
+               operation has completed for a sent MAD.
+
+       pfn_mad_recv_cb
+               A receive callback that is invoked to notify the user that a MAD
+               has been received.
+
+       support_unsol
+               If set to TRUE, this field indicates that the registering client
+               supports processing unsolicited MADs.  Unsolicited MADs are
+               received MADs that do not have the response bit set.  If set to TRUE,
+               the following fields are required (must be non-zero): mgmt_class,
+               mgmt_version, and method_array.
+
+       mgmt_version
+               Indicates which version of a management class the client requires
+               support for.  The access layer distinguishes between clients
+               requiring different versions of the same management class.
+               This field is ignored if the support_unsol field is set to FALSE.
+
+       mgmt_class
+               Indicates the management class that should be supported by the
+               access layer.  This field is ignored if the support_unsol field is
+               set to FALSE.
+
+       method_array
+               An array of 127 entries specifying which methods are supported by
+               a client when receiving unsolicited MADs.  Each index corresponds to
+               a single method, and each entry in the array indicates if the method
+               is supported by the client.  This field is ignored if the
+               support_unsol field is set to FALSE.
+
+       svc_type
+               Indicates the type of services that should be provided by the MAD
+               service.
+
+

NOTES

+
       Clients use this structure to define which management datagram methods
+       they support, and the type of support required for each.  A received MAD
+       is distinguished by the access layer based on the following three fields:
+       management class, management version, and method.
+
+       Specific combinations of class, version, and method may be registered
+       for unsolicited MADs only once.  The access layer supports multiple
+       clients registering for unsolicited MADs as long as they do not share the
+       same methods, class, or version.
+
+       The svc_type field can be set by a client to indicate that the access
+       layer should invoke RMPP for the specified management class of MADs.  If
+       set to IB_MAD_SVC_DEFAULT, the access layer will automatically invoke RMPP
+       for well known MAD classes (those defined by the 1.1 version of the
+       InfiniBand specification).  The svc_type field is intended to be used by
+       clients sending and receiving vendor specific management class requiring
+       RMPP and clients providing their own MAD services.
+
+

SEE ALSO

+
       ib_reg_mad_svc, ib_pfn_mad_send_cb_t, ib_pfn_mad_recv_cb_t,
+       ib_mad_svc_type_t
+
+
+
+ +

[Definitions] +Access Layer/ib_mad_svc_type_t

+ +

[top][parent][index]

+

NAME

+
       ib_mad_svc_type_t
+
+

DESCRIPTION

+
       Indicates the type of services provided by a MAD service.
+
+

SYNOPSIS

+
typedef enum _ib_mad_svc_type
+{
+        IB_MAD_SVC_DEFAULT = 0,
+        IB_MAD_SVC_RMPP,
+        IB_MAD_SVC_RAW
+
+}       ib_mad_svc_type_t;
+
+

VALUES

+
       IB_MAD_SVC_DEFAULT
+               Indicates that the access layer will provide all necessary services,
+               including retransmissions and RMPP for well-defined management classes.
+
+       IB_MAD_SVC_RMPP
+               Indicates that the MAD service requires retransmissions and the RMPP
+               header is available on all MADs.  (The RMPP protocol will be activated
+               on a per send basis.)  This service type should be used for
+               user-defined management classes requiring RMPP.
+
+       IB_MAD_SVC_RAW
+               Specifies that the MAD service will not perform retransmissions or
+               perform RMPP.  All MADs received or sent on a MAD service of this type
+
+

NOTES

+
       This enum is used to define the types of MAD services available to users.
+
+

SEE ALSO

+
       ib_mad_svc_t, ib_reg_mad_svc
+
+
+
+ +

[Structures] +Access Layer/ib_mcast_rec_t

+ +

[top][parent][index]

+

NAME

+
       ib_mcast_rec_t
+
+

DESCRIPTION

+
       Information returned as a result of joining a multicast group.
+
+

SYNOPSIS

+
typedef struct _ib_mcast_rec
+{
+ TO_LONG_PTR(       const void* ,                     mcast_context) ; 
+        ib_api_status_t                         status;
+        ib_net16_t                                      error_status;
+
+        ib_mcast_handle_t __ptr64                       h_mcast;
+ TO_LONG_PTR(       ib_member_rec_t* ,        p_member_rec) ; 
+
+}       ib_mcast_rec_t;
+
+

FIELDS

+
       mcast_context
+               User-defined context information associated with the multicast join
+               request.
+
+       status
+               Indicates the success of the multicast group join operation.
+
+       error_status
+               Provide additional error information that was provided by the SA.
+               This field is only valid if status is set to IB_REMOTE_ERROR.
+
+       h_mcast
+               Upon successful completion of a multicast join, this references a
+               handle to the multicast group.  This handle is used to leave the
+               multicast group.
+
+       p_member_rec
+               References a member record that provides information about the
+               multicast group.
+
+

NOTES

+
       This structure is returned to a client through a callback to notify them
+       of the result of a multicast join operation.
+
+

SEE ALSO

+
       ib_join_mcast, ib_pfn_mcast_cb_t, ib_leave_mcast
+
+
+
+ +

[Structures] +Access Layer/ib_mcast_req_t

+ +

[top][parent][index]

+

NAME

+
       ib_mcast_req_t
+
+

DESCRIPTION

+
       Information used to join a multicast group.
+
+

SYNOPSIS

+
typedef struct _ib_mcast_req
+{
+        boolean_t                                       create;
+        ib_member_rec_t                         member_rec;
+
+ TO_LONG_PTR(       const void* ,                     mcast_context) ; 
+        ib_pfn_mcast_cb_t                       pfn_mcast_cb;
+
+        uint32_t                                        timeout_ms;
+        uint32_t                                        retry_cnt;
+        ib_al_flags_t                           flags;
+
+        ib_net64_t                                      port_guid;
+        uint16_t                                        pkey_index;
+
+}       ib_mcast_req_t;
+
+

FIELDS

+
       create
+               Indicates that the multicast group should be created if it does not
+               already exist.
+
+       member_rec
+               Specifies the membership information of the multicast group to join
+               or create.  The mgid and join state (scope_state) fields of the
+               member record must be set.  In addition, if create is set to TRUE,
+               the following fields must also be set: qkey, tclass, service level
+               and flow label (sl_flow_hop), and pkey.  All other fields are ignored
+               by the access layer.
+
+       mcast_context
+               User-defined context information associated with the join request.
+               This context is returned to the user through the function specified
+               by the pfn_mcast_cb field.
+
+       pfn_mcast_cb
+               A user-defined callback that is invoked upon completion of the
+               join request.
+
+       timeout_ms
+               Specifies the number of milliseconds to wait for a response for
+               the join request until retrying or timing out the request.
+
+       retry_cnt
+               Specifies the number of times that the join request 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.
+
+       port_guid
+               Indicates the port that will join the multicast group.  The QP
+               specified as part of the ib_join_mast call will bind to this port.
+
+       pkey_index
+               Specifies the pkey associated with this queue pair.
+
+

NOTES

+
       This structure is used when joining an existing multicast group or
+       creating a new multicast group.
+
+

SEE ALSO

+
       ib_join_mcast, ib_pfn_mcast_cb_t, ib_gid_t
+
+
+
+ +

[Functions] +Access Layer/ib_modify_av

+ +

[top][parent][index]

+

NAME

+
       ib_modify_av
+
+

DESCRIPTION

+
       Modifies the attributes of an existing address vector.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_modify_av(
+        IN              const   ib_av_handle_t FUNC_PTR64                          h_av,
+        IN              const   ib_av_attr_t* const                     p_av_attr );
+
+

PARAMETERS

+
       h_av
+               [in] A handle to an existing address vector.
+
+       p_av_attr
+               [in] The new attributes to use when modifying the address vector.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The address vector was successfully modified.
+
+       IB_INVALID_AV_HANDLE
+               The address vector handle was invalid.
+
+       IB_INVALID_PARAMETER
+               A reference to the address vector attributes structure was not
+               provided.
+
+       IB_INVALID_PORT
+               The port number supplied, through the address vector attributes,
+               was invalid for the given channel adapter.
+
+

NOTES

+
       This routine modifies the attributes of an existing address vector.
+       The new attributes are specified through the p_av_attr parameter.
+
+

SEE ALSO

+
       ib_create_av, ib_destroy_av
+
+
+
+ +

[Functions] +Access Layer/ib_modify_ca

+ +

[top][parent][index]

+

NAME

+
       ib_modify_ca
+
+

DESCRIPTION

+
       Modifies the attributes and violation counters associated with a port.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_modify_ca(
+        IN              const   ib_ca_handle_t FUNC_PTR64                          h_ca,
+        IN              const   uint8_t                                         port_num,
+        IN              const   ib_ca_mod_t                                     ca_mod,
+        IN              const   ib_port_attr_mod_t* const       p_port_attr_mod );
+
+

PARAMETERS

+
       h_ca
+               [in] A handle to an opened channel adapter.
+
+       port_num
+               [in] An index to the port that is being modified.  The port_num matches
+               the index of the port as returned through the ib_query_ca call.
+
+       ca_mod
+               [in] A mask of the attributes and counters to modify.
+
+       p_port_attr_mod
+               [in] A list of the specific port attribute information to modify.  For
+               the access layer to modify an attribute, its corresponding bit must be
+               set in the ca_mod parameter.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The attributes were successfully modified.
+
+       IB_INVALID_CA_HANDLE
+               The channel adapter handle was invalid.
+
+       IB_INVALID_PORT
+               The port number supplied was invalid for the given channel adapter.
+
+       IB_INVALID_PARAMETER
+               The supplied ca_mod mask is invalid or a reference to the port
+               attribute information was not provided.
+
+       IB_UNSUPPORTED
+               The optional qkey and pkey violation counters are not supported by
+               this channel adapter, but an attempt was made to modify them.
+
+

NOTES

+
       This call sets the attributes for a port in its associated PORT_INFO
+       structure.  It will also reset pkey and qkey violation counters.
+
+

SEE ALSO

+
       ib_open_ca, ib_query_ca, ib_close_ca, ib_ca_mod_t, ib_port_attr_mod_t
+
+
+
+ +

[Functions] +Access Layer/ib_modify_cq

+ +

[top][parent][index]

+

NAME

+
       ib_modify_cq
+
+

DESCRIPTION

+
       Modifies the attributes associated with a completion queue, allowing the
+       completion queue to be resized.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_modify_cq(
+        IN              const   ib_cq_handle_t FUNC_PTR64                          h_cq,
+        IN      OUT                     uint32_t* const                         p_size );
+
+

PARAMETERS

+
       h_cq
+               [in] A handle to an existing completion queue.
+
+       p_size
+               [in/out] Specifies the new size of the completion queue.  If the
+               modify call is successful, the actual size of the completion queue
+               will be returned.  The actual size of the CQ will be greater than or
+               equal to the requested size.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The completion queue was successfully modified.
+
+       IB_INVALID_CQ_HANDLE
+               The completion queue handle was invalid.
+
+       IB_INVALID_PARAMETER
+               A reference to the completion queue size was not provided.
+
+       IB_INVALID_CQ_SIZE
+               The requested size of the completion queue was larger than the
+               maximum supported by the associated channel adapter.
+
+       IB_OVERFLOW
+               The specified size of the completion queue is smaller than the number
+               of work completions currently on the completion queue.
+
+       IB_INSUFFICIENT_MEMORY
+               There was insufficient memory to modify the completion queue.
+
+

NOTES

+
       This routine allows a client to modify the size of a completion queue.
+       If the new size is larger than what the associated channel adapter can
+       support, an error is returned.  If the completion queue has valid
+       completion entries on it and the requested size is smaller than the
+       number of entries, an overflow error is returned and the modify
+       operation is aborted.
+
+

SEE ALSO

+
       ib_create_cq
+
+
+
+ +

[Functions] +Access Layer/ib_modify_qp

+ +

[top][parent][index]

+

NAME

+
       ib_modify_qp
+
+

DESCRIPTION

+
       Modifies the attributes of an existing queue pair.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_modify_qp(
+        IN              const   ib_qp_handle_t FUNC_PTR64                          h_qp,
+        IN              const   ib_qp_mod_t* const                      p_qp_mod );
+
+

PARAMETERS

+
       h_qp
+               [in] A handle to an existing queue pair.
+
+       p_qp_mod
+               [in] The new attributes to use when modifying the queue pair.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The queue pair was successfully modified.
+
+       IB_INVALID_QP_HANDLE
+               The queue pair handle was invalid.
+
+       IB_INVALID_PARAMETER
+               A reference to the queue pair attributes was not provided.
+
+       IB_INVALID_SETTING
+               The specified queue pair attributes were invalid.
+
+       IB_INSUFFICIENT_RESOURCES
+               There were insufficient resources currently available on the channel
+               adapter to register the modify the queue pair.
+
+       IB_UNSUPPORTED
+               The requested modification was not supported.
+
+       IB_INVALID_QP_STATE
+               The queue pair was in an invalid state for the requested operation.
+
+       IB_INVALID_PKEY
+               The specified pkey was not valid.
+
+       IB_INVALID_APM_STATE
+               The specified automatic path migration state was not valid.
+
+

NOTES

+
       This routine modifies the attributes of an existing queue pair and
+       transitions it to a new state.  The new state and attributes are
+       specified through the p_qp_mod parameter.  Upon successful completion,
+       the queue pair is in the requested state.
+
+

SEE ALSO

+
       ib_create_qp, ib_destroy_qp, ib_qp_mod_t
+
+
+
+ +

[Functions] +Access Layer/ib_modify_srq

+ +

[top][parent][index]

+

NAME

+
       ib_modify_srq
+
+

DESCRIPTION

+
       Modifies the attributes of an existing shared receive queue.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_modify_srq(
+        IN              const   ib_srq_handle_t FUNC_PTR64                 h_srq,
+        IN              const   ib_srq_attr_t* const            p_srq_attr,
+        IN              const   ib_srq_attr_mask_t                      srq_attr_mask );
+
+

PARAMETERS

+
       h_srq
+               [in] A handle to an existing shared receive queue.
+
+       p_srq_attr
+               [in] Attributes necessary to allocate and initialize a shared receive queue.
+
+       srq_attr_mask
+               [in] Flags, indicating which fields in the previous structure are valid.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The shared receive queue was successfully modified.
+
+       IB_INVALID_SRQ_HANDLE
+               The shared receive queue handle was invalid.
+
+       IB_INVALID_PARAMETER
+               A reference to the shared receive queue attributes was not provided.
+
+       IB_INVALID_SETTING
+               The specified shared receive queue attributes were invalid.
+
+       IB_UNSUPPORTED
+               The required action is not supported yet.
+
+       IB_INSUFFICIENT_RESOURCES
+               There were insufficient resources currently available on the channel
+               adapter to register the modify the shared receive queue.
+
+

NOTES

+
       This routine modifies the attributes of an existing shared receive queue and
+       transitions it to a new state.  The new state and attributes are
+       specified through the p_qp_mod parameter.  Upon successful completion,
+       the shared receive queue is in the requested state.
+
+

SEE ALSO

+
       ib_query_srq, ib_modify_srq, ib_destroy_srq, ib_srq_attr_t,
+       ib_srq_attr_mask_t, ib_pfn_event_cb_t, ib_qp_attr_t
+
+
+
+ +

[Structures] +Access Layer/ib_mra_pdata_t

+ +

[top][parent][index]

+

NAME

+
       ib_mra_pdata_t
+
+

DESCRIPTION

+
       User data sent as part of a message receipt acknowledgement.
+
+

SYNOPSIS

+
typedef union _ib_mra_pdata
+{
+        uint8_t                                         data[IB_MRA_PDATA_SIZE];
+
+}       ib_mra_pdata_t;
+
+

SEE ALSO

+
       ib_cm_data_sizes_t
+
+
+
+ +

[Functions] +Access Layer/ib_open_al

+ +

[top][parent][index]

+

NAME

+
       ib_open_al
+
+

DESCRIPTION

+
       This routine opens an instance of the access layer for the user and
+       returns its handle.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_open_al(
+                OUT                     ib_al_handle_t FUNC_PTR64* const           ph_al );
+
+

PARAMETERS

+
       ph_al
+               [in] Upon successful completion of this call, this parameter will
+               reference a handle to the access layer.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The access layer was opened successfully.
+
+       IB_INVALID_PARAMETER
+               A reference to the access layer handle was not provided.
+
+       IB_INSUFFICIENT_MEMORY
+               There was insufficient memory to perform the operation.
+
+

NOTES

+
       This function opens an instance of the access layer.  An instance of the
+       access layer is required before allocating additional resources from the
+       access layer or a channel adapter.  If successful, a handle to the access
+       layer is returned.  User-mode clients should not call ib_open_al from the
+       module initialization routine.
+
+

SEE ALSO

+
       ib_close_al
+
+
+
+ +

[Functions] +Access Layer/ib_open_ca

+ +

[top][parent][index]

+

NAME

+
       ib_open_ca
+
+

DESCRIPTION

+
       Opens a channel adapter for additional access.  A channel adapter must
+       be opened before consuming resources on that adapter.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_open_ca(
+        IN              const   ib_al_handle_t FUNC_PTR64                          h_al,
+        IN              const   ib_net64_t                                      ca_guid,
+        IN              const   ib_pfn_event_cb_t                       pfn_ca_event_cb OPTIONAL,
+        IN              const   void* const                                     ca_context,
+                OUT                     ib_ca_handle_t FUNC_PTR64* const           ph_ca );
+
+

PARAMETERS

+
       h_al
+               [in] The handle to an open instance of AL.
+
+       ca_guid
+               [in] The GUID of the channel adapter to open.
+
+       pfn_ca_event_cb
+               [in] A user-specified callback that is invoked after an
+               asynchronous event has occurred on the channel adapter.
+
+       ca_context
+               [in] A client-specified context to associate with this opened instance
+               of the channel adapter.  This context is returned to the user when
+               invoking asynchronous callbacks referencing this channel adapter.
+
+       ph_ca
+               [out] Upon successful completion of this call, this references a
+               handle to the opened channel adapter.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The operation was successful.
+
+       IB_INVALID_AL_HANDLE
+               The access layer handle was invalid.
+
+       IB_INVALID_GUID
+               No channel adapter in the system was found for the specified ca_guid.
+
+       IB_INVALID_PARAMETER
+               A reference to the CA handle was not provided.
+
+       IB_INSUFFICIENT_MEMORY
+               There was insufficient memory to open the channel adapter.
+
+

NOTES

+
       When successful, this routine returns a handle to an open instance of a CA.
+
+

SEE ALSO

+
       ib_query_ca, ib_modify_ca, ib_close_ca, ib_pfn_event_cb_t
+
+
+
+ +

[Functions] +Access Layer/ib_peek_cq

+ +

[top][parent][index]

+

NAME

+
       ib_peek_cq
+
+

DESCRIPTION

+
       Returns the number of entries currently on the completion queue.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_peek_cq(
+        IN              const   ib_cq_handle_t FUNC_PTR64                          h_cq,
+        OUT                             uint32_t* const                         p_n_cqes );
+
+

PARAMETERS

+
       h_cq
+               [in] Handle to the completion queue to peek.
+
+       p_n_cqes
+               [out] Upon successful completion of this call, contains the number
+               of completion queue entries currently on the completion queue.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The peek operation completed successfully.
+
+       IB_INVALID_CQ_HANDLE
+               The completion queue handle was invalid.
+
+       IB_INVALID_PARAMETER
+               A reference to the completion queue entry count was not provided.
+
+       IB_UNSUPPORTED
+               This operation is not supported by the channel adapter.
+
+

NOTES

+
       The value returned is a snapshot of the number of compleiton queue
+       entries curently on the completion queue.  Support for this operation
+       is optional by a channel adapter vendor.
+
+

SEE ALSO

+
       ib_create_cq, ib_poll_cq, ib_rearm_cq, ib_rearm_n_cq
+
+
+
+ +

[Functions] +Access Layer/ib_pfn_cm_apr_cb_t

+ +

[top][parent][index]

+

NAME

+
       ib_pfn_cm_apr_cb_t
+
+

DESCRIPTION

+
       A user-specified callback that is invoked after receiving a load
+       alternate path response message.
+
+

SYNOPSIS

+
typedef void
+(AL_API * FUNC_PTR64 ib_pfn_cm_apr_cb_t)(
+        IN                              ib_cm_apr_rec_t                         *p_cm_apr_rec );
+
+

PARAMETERS

+
       p_cm_apr_rec
+               [in] Load alternate path response information sent by the remote side.
+
+

NOTES

+
       This callback is invoked to notify the user of a load alternate path
+       response.  If a response is not received within the specified timeout
+       period, this callback will be invoked with the status set to IB_CM_TIMEOUT.
+
+       In the kernel, this callback is typically invoked from within a tasklet,
+       depending on the implementation of the verbs provider driver.
+
+

SEE ALSO

+
       ib_cm_lap, ib_cm_apr, ib_cm_apr_rec_t
+
+
+
+ +

[Functions] +Access Layer/ib_pfn_cm_drep_cb_t

+ +

[top][parent][index]

+

NAME

+
       ib_pfn_cm_drep_cb_t
+
+

DESCRIPTION

+
       A user-specified callback that is invoked after receiving a disconnect
+       reply message.
+
+

SYNOPSIS

+
typedef void
+(AL_API * FUNC_PTR64 ib_pfn_cm_drep_cb_t)(
+        IN                              ib_cm_drep_rec_t                        *p_cm_drep_rec );
+
+

PARAMETERS

+
       p_cm_drep_rec
+               [in] Disconnect reply information returned to the user.
+
+

NOTES

+
       This callback is invoked to notify the user of a disconnect reply.  If
+       no reply was received within the specified timeout period, this callback
+       will be invoked with the status set to IB_CM_TIMEOUT.
+
+       In the kernel, this callback is typically invoked from within a
+       tasklet, depending on the implementation of the verbs provider driver.
+
+

SEE ALSO

+
       ib_cm_dreq, ib_cm_drep, ib_cm_drep_rec_t
+
+
+
+ +

[Functions] +Access Layer/ib_pfn_cm_dreq_cb_t

+ +

[top][parent][index]

+

NAME

+
       ib_pfn_cm_dreq_cb_t
+
+

DESCRIPTION

+
       A user-specified callback that is invoked after receiving a disconnect
+       request message.
+
+

SYNOPSIS

+
typedef void
+(AL_API * FUNC_PTR64 ib_pfn_cm_dreq_cb_t)(
+        IN                              ib_cm_dreq_rec_t                        *p_cm_dreq_rec );
+
+

PARAMETERS

+
       p_cm_dreq_rec
+               [in] Disconnect request information returned to the user.
+
+

NOTES

+
       This callback is invoked to notify the user of a disconnect request.
+       Users must call ib_cm_drep to respond to the disconnect request.  After
+       this callback returns, the queue pair associated with the connection is
+       transitioned to the time-wait state and is no longer usable for sending
+       and receiving data.
+
+       In the kernel, this callback is typically invoked from within a tasklet,
+       depending on the implementation of the verbs provider driver.
+
+

SEE ALSO

+
       ib_cm_req, ib_cm_listen, ib_cm_drep, ib_cm_dreq_rec_t
+
+
+
+ +

[Functions] +Access Layer/ib_pfn_cm_lap_cb_t

+ +

[top][parent][index]

+

NAME

+
       ib_pfn_cm_lap_cb_t
+
+

DESCRIPTION

+
       A user-specified callback that is invoked after receiving a load
+       alternate path message.
+
+

SYNOPSIS

+
typedef void
+(AL_API * FUNC_PTR64 ib_pfn_cm_lap_cb_t)(
+        IN                              ib_cm_lap_rec_t                         *p_cm_lap_rec );
+
+

PARAMETERS

+
       p_cm_lap_rec
+               [in] Load alternate path information sent by the remote side.
+
+

NOTES

+
       This callback is invoked to notify the user of a load alternate path
+       request.  Users must call ib_cm_apr to respond to the load alternate
+       path request from within this callback.  The ib_cm_apr call is used
+       to accept or reject the load alternate path request.
+
+       In the kernel, this callback is typically invoked from within a
+       tasklet, depending on the implementation of the verbs provider driver.
+
+

SEE ALSO

+
       ib_cm_lap, ib_cm_apr, ib_cm_lap_rec_t
+
+
+
+ +

[Functions] +Access Layer/ib_pfn_cm_mra_cb_t

+ +

[top][parent][index]

+

NAME

+
       ib_pfn_cm_mra_cb_t
+
+

DESCRIPTION

+
       A user-specified callback that is invoked after receiving a message
+       received acknowledgement.
+
+

SYNOPSIS

+
typedef void
+(AL_API * FUNC_PTR64 ib_pfn_cm_mra_cb_t)(
+        IN                              ib_cm_mra_rec_t                         *p_cm_mra_rec );
+
+

PARAMETERS

+
       p_cm_mra_rec
+               [in] Message received acknowledgement information received from the
+               remote side.
+
+

NOTES

+
       This callback is invoked to notify the user that their request was
+       successfully received, but additional processing is required.  This
+       callback may be invoked after calling ib_cm_req or ib_cm_rep
+
+       In the kernel, this callback is typically invoked from within a tasklet,
+       depending on the implementation of the verbs provider driver.
+
+

SEE ALSO

+
       ib_cm_req, ib_cm_rep, ib_cm_mra_rec_t
+
+
+
+ +

[Functions] +Access Layer/ib_pfn_cm_rej_cb_t

+ +

[top][parent][index]

+

NAME

+
       ib_pfn_cm_rej_cb_t
+
+

DESCRIPTION

+
       A user-specified callback that is invoked after receiving a connection
+       rejection message.
+
+

SYNOPSIS

+
typedef void
+(AL_API * FUNC_PTR64 ib_pfn_cm_rej_cb_t)(
+        IN                              ib_cm_rej_rec_t                         *p_cm_rej_rec );
+
+

PARAMETERS

+
       p_cm_rej_rec
+               [in] Connection rejection information returned to the user.
+
+

NOTES

+
       This callback is invoked to notify the user that a connection has been
+       rejected.  This routine may be invoked after calling ib_cm_req or
+       ib_cm_rep.
+
+       In the kernel, this callback is typically invoked from within a tasklet,
+       depending on the implementation of the verbs provider driver.
+
+

SEE ALSO

+
       ib_cm_req, ib_cm_rep, ib_cm_rtu, ib_cm_rej, ib_cm_rej_rec_t
+
+
+
+ +

[Functions] +Access Layer/ib_pfn_cm_rep_cb_t

+ +

[top][parent][index]

+

NAME

+
       ib_pfn_cm_rep_cb_t
+
+

DESCRIPTION

+
       A user-specified callback that is invoked after receiving a connection
+       request reply message.
+
+

SYNOPSIS

+
typedef void
+(AL_API * FUNC_PTR64 ib_pfn_cm_rep_cb_t)(
+        IN                              ib_cm_rep_rec_t                         *p_cm_rep_rec );
+
+

PARAMETERS

+
       p_cm_rep_rec
+               [in] Connection request reply information returned to the user,
+               indicating the remote connection data.
+
+

NOTES

+
       This callback is invoked to notify the user of a connection request reply.
+       This routine is invoked after calling ib_cm_req.  Users must call
+       ib_cm_rtu to accept the connection or ib_cm_rej to reject the connection
+       from the callback.
+
+       Users may also call ib_cm_mra to acknowledge the connection request reply
+       and prevent the remote side from timing out the connection request.  The
+       ib_cm_mra routine should be invoked if the user requires substantial
+       processing time to process the connection request reply.
+
+       If a reply is not received within the specified timeout period,
+       this callback will be invoked with the status set to IB_CM_TIMEOUT.  Users
+       may call ib_cm_rej to notify the remote side that the connection request
+       is being rejected due to a timeout.
+
+       In the kernel, this callback is typically invoked from within a tasklet,
+       depending on the implementation of the verbs provider driver.
+
+

SEE ALSO

+
       ib_cm_req, ib_cm_listen, ib_cm_rep, ib_cm_rej, ib_cm_mra, ib_cm_rej,
+       ib_cm_rep_rec_t
+
+
+
+ +

[Functions] +Access Layer/ib_pfn_cm_req_cb_t

+ +

[top][parent][index]

+

NAME

+
       ib_pfn_cm_req_cb_t
+
+

DESCRIPTION

+
       A user-specified callback that is invoked after receiving a connection
+       request message.
+
+

SYNOPSIS

+
typedef void
+(AL_API * FUNC_PTR64 ib_pfn_cm_req_cb_t)(
+        IN                              ib_cm_req_rec_t                         *p_cm_req_rec );
+
+

PARAMETERS

+
       p_cm_req_rec
+               [in] Connection request information returned to the user, indicating
+               the parameters for the connection.
+
+

NOTES

+
       This callback is invoked to notify the user of a connection request.  This
+       routine is invoked for peer to peer connection request calls to ib_cm_req
+       and for calls to ib_cm_listen.  Users must call ib_cm_rep to accept the
+       connection or ib_cm_rej to reject the connection from the callback.
+
+       Users may also call ib_cm_mra to acknowledge the connection request and
+       prevent the remote side from timing out the connection request.  The
+       ib_cm_mra routine should be invoked if the user requires substantial
+       processing time to process the connection request.
+
+       In the kernel, this callback is typically invoked from within a tasklet,
+       depending on the implementation of the verbs provider driver.
+
+

SEE ALSO

+
       ib_cm_req, ib_cm_listen, ib_cm_rep, ib_cm_mra, ib_cm_rej, ib_cm_req_rec_t
+
+
+
+ +

[Functions] +Access Layer/ib_pfn_cm_rtu_cb_t

+ +

[top][parent][index]

+

NAME

+
       ib_pfn_cm_rtu_cb_t
+
+

DESCRIPTION

+
       A user-specified callback that is invoked after receiving a connection
+       ready to use message.
+
+

SYNOPSIS

+
typedef void
+(AL_API * FUNC_PTR64 ib_pfn_cm_rtu_cb_t)(
+        IN                              ib_cm_rtu_rec_t                         *p_cm_rtu_rec );
+
+

PARAMETERS

+
       p_cm_rtu_rec
+               [in] Connection ready to use information returned to the user.
+
+

NOTES

+
       This callback is invoked to notify the user that a connection is ready
+       to use.  This routine is invoked after calling ib_cm_rep.  If a ready to
+       use message is not received within the specified timeout period, this
+       callback will be invoked with the status set to IB_CM_TIMEOUT.
+
+       This callback will be invoked before a user is notified of any completions
+       that has occurred on the associated queue pair.
+
+       In the kernel, this callback is typically invoked from within a tasklet,
+       depending on the implementation of the verbs provider driver.
+
+

SEE ALSO

+
       ib_cm_rep, ib_cm_rtu_rec_t
+
+
+
+ +

[Functions] +Access Layer/ib_pfn_comp_cb_t

+ +

[top][parent][index]

+

NAME

+
       ib_pfn_comp_cb_t
+
+

DESCRIPTION

+
       Completion callback provided by a client.
+
+

SYNOPSIS

+
typedef void
+(AL_API * FUNC_PTR64 ib_pfn_comp_cb_t)(
+        IN              const   ib_cq_handle_t FUNC_PTR64                          h_cq,
+        IN                              void                                            *cq_context );
+
+

PARAMETERS

+
       h_cq
+               [in] Handle for the completion queue on which the completion occurred.
+
+       cq_context
+               [in] User-specified context for the completion queue on which the
+               completion occurred.
+
+

NOTES

+
       This function is invoked upon completion of a work request on a queue pair
+       associated with the completion queue.  The context associated with the
+       completion queue on which the completion occurred is return to the client
+       through the callback.
+
+       In the kernel, this callback is usually invoked using a tasklet, dependent
+       on the implementation of the underlying verbs provider driver.
+
+
+
+ +

[Functions] +Access Layer/ib_pfn_destroy_cb_t

+ +

[top][parent][index]

+

NAME

+
       ib_pfn_destroy_cb_t
+
+

DESCRIPTION

+
       Asynchronous callback invoked after a resource has been successfully
+       destroyed.
+
+

SYNOPSIS

+
typedef void
+(AL_API * FUNC_PTR64 ib_pfn_destroy_cb_t)(
+        IN                              void                                            *context );
+
+

PARAMETERS

+
       context
+               [in] User-specified context associated with the resource being
+               destroyed.  The context for the resource is usually set during the
+               object's creation.
+
+

NOTES

+
       This callback notifies a client that a resource has been successfully
+       destroyed.  It is used to indicate that all pending callbacks associated
+       with the resource have completed, and no additional events will be
+       generated for that resource.
+
+       This callback is invoked within a system thread context in the kernel.
+
+       If the user specifies ib_sync_destroy as the asynchronous callback, then
+       the object being destroyed will be destroyed synchronously.  This may 
+       result in the calling thread blocking while outstanding callbacks complete.
+
+

SEE ALSO

+
       ib_sync_destroy
+
+
+
+ +

[Functions] +Access Layer/ib_pfn_event_cb_t

+ +

[top][parent][index]

+

NAME

+
       ib_pfn_event_cb_t
+
+

DESCRIPTION

+
       A user-specified callback that is invoked after an asynchronous event
+       has occurred on an allocated resource.
+
+

SYNOPSIS

+
typedef void
+(AL_API * FUNC_PTR64 ib_pfn_event_cb_t)(
+        IN                              ib_async_event_rec_t            *p_event_rec );
+
+

PARAMETERS

+
       p_event_rec
+               [in] Information returned to the user, indicating the type of
+               event and the associated user context.
+
+

NOTES

+
       This callback is invoked within a system thread context in the kernel.
+
+

SEE ALSO

+
       ib_async_event_rec_t
+
+
+
+ +

[Functions] +Access Layer/ib_pfn_listen_err_cb_t

+ +

[top][parent][index]

+

NAME

+
       ib_pfn_listen_err_cb_t
+
+

DESCRIPTION

+
       A user-specified callback that is invoked after an error has occurred on
+       a listen request.
+
+

SYNOPSIS

+
typedef void
+(AL_API * FUNC_PTR64 ib_pfn_listen_err_cb_t)(
+        IN                              ib_listen_err_rec_t                     *p_listen_err_rec );
+
+

PARAMETERS

+
       p_listen_err_rec
+               [in] Error information returned to the user, indicating the reason
+               for the error and associated context information.
+
+

NOTES

+
       This callback is invoked within a system thread context in the kernel.
+
+

SEE ALSO

+
       p_listen_err_rec
+
+
+
+ +

[Functions] +Access Layer/ib_pfn_mad_comp_cb_t

+ +

[top][parent][index]

+

NAME

+
       ib_pfn_mad_comp_cb_t
+
+

DESCRIPTION

+
       User-defined callback used to notify the user of a completion for a
+       sent or received datagram.
+
+

SYNOPSIS

+
typedef void
+(AL_API * FUNC_PTR64 ib_pfn_mad_comp_cb_t)(
+        IN              const   ib_mad_svc_handle_t FUNC_PTR64                     h_mad_svc,
+        IN                              void                                            *mad_svc_context,
+        IN                              ib_mad_element_t                        *p_mad_element );
+
+

PARAMETERS

+
       h_mad_svc
+               [in] Handle to the MAD service on which the completion occured.
+
+       mad_svc_context
+               [in] User-defined context information associated with the MAD service
+               on which the completion occurred.
+
+       p_mad_element
+               [in] References information on the completed MAD request.
+
+

NOTES

+
       This function is invoked upon completion of a sent or receive MAD.
+       It is separate from the normal completion callbacks in order to allow
+       the access layer to perform post processing on the MAD, such as
+       segmentation and reassembly, and retransmissions if a response was
+       expected.
+
+       The mad element returned through this call should be returned to its MAD
+       pool after completion processing on the MAD has concluded.  Completed
+       receive MAD elements should not be reposted to the receive queue of a
+       MAD QP.
+
+       In the kernel, this callback is typically invoked from within a
+       tasklet, depending on the implementation of the verbs provider driver.
+
+

SEE ALSO

+
       ib_send_mad, ib_reg_mad_svc
+
+
+
+ +

[Functions] +Access Layer/ib_pfn_mcast_cb_t

+ +

[top][parent][index]

+

NAME

+
       ib_pfn_mcast_cb_t
+
+

DESCRIPTION

+
       User-defined callback invoked on completion of a multicast join request.
+
+

SYNOPSIS

+
typedef void
+(AL_API * FUNC_PTR64 ib_pfn_mcast_cb_t)(
+        IN                              ib_mcast_rec_t                          *p_mcast_rec );
+
+

PARAMETERS

+
       p_mcast_rec
+               [in] References the result of the join operation.
+
+

NOTES

+
       The callback is used to notify a client of the result of a multicast
+       join request.
+
+       This callback is invoked within a system thread context in the kernel.
+
+

SEE ALSO

+
       ib_join_mcast, ib_mcast_rec_t
+
+
+
+ +

[Functions] +Access Layer/ib_pfn_pnp_cb_t

+ +

[top][parent][index]

+

NAME

+
       ib_pfn_pnp_cb_t
+
+

DESCRIPTION

+
       User-defined callback that is invoked to notify a client of the addition
+       or removal of a channel adapter, a port up or down event, port changes,
+       and the assignment of an I/O controller to a local port.
+
+

SYNOPSIS

+
typedef ib_api_status_t
+(AL_API * FUNC_PTR64 ib_pfn_pnp_cb_t)(
+        IN                              ib_pnp_rec_t                            *p_pnp_rec );
+
+

PARAMETERS

+
       p_pnp_rec
+               [in] A reference to a plug and play record.  The plug and play
+               record contains details about the type of local event that has
+               occurred, along with the relevant device information.
+
+ RETURN VALUES
+       IB_SUCCESS
+               Indicates to the PnP manager that the callback client requires it
+               to maintain a context for this event.
+
+       Other
+               Indicates to the PnP manager that the callback client does not need
+               a context for this event.
+
+

NOTES

+
       The callback is used to notify users of local events that have occurred
+       on a given channel adapter.  Information about the type of event that
+       occurred along with the associated device is returned to the user through
+       the p_pnp_rec parameter.
+
+       Users register for plug and play changes by requesting notification from
+       the access layer.  Users may register for notifications either by directly
+       invoking the appropriate function in the access layer, or indirectly by
+       adding the necessary registration data to the access layer device file.
+
+       This callback is invoked from within a system thread context.
+
+       If the callback returns a status other than IB_SUCCESS, no further
+       callback for related events will be delivered.
+
+

SEE ALSO

+
       ib_pnp_rec_t, ib_reg_pnp, ib_dereg_pnp, ib_reject_ioc
+
+
+
+ +

[Functions] +Access Layer/ib_pfn_query_cb_t

+ +

[top][parent][index]

+

NAME

+
       ib_pfn_query_cb_t
+
+

DESCRIPTION

+
       User-defined callback invoked on completion of a subnet administrator
+       query.
+
+

SYNOPSIS

+
typedef void
+(AL_API * FUNC_PTR64 ib_pfn_query_cb_t)(
+        IN                              ib_query_rec_t                          *p_query_rec );
+
+

PARAMETERS

+
       p_query_rec
+               [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 the subnet administrator.
+
+       In the kernel, this callback is usually invoked using a tasklet, dependent
+       on the implementation of the underlying verbs provider driver.
+
+

SEE ALSO

+
       ib_query_rec_t
+
+
+
+ +

[Functions] +Access Layer/ib_pfn_reg_svc_cb_t

+ +

[top][parent][index]

+

NAME

+
       ib_pfn_reg_svc_cb_t
+
+

DESCRIPTION

+
       User-defined callback that is invoked to notify a client of the result
+       of a service registration attempt.
+
+

SYNOPSIS

+
typedef void
+(AL_API * FUNC_PTR64 ib_pfn_reg_svc_cb_t)(
+        IN                              ib_reg_svc_rec_t                        *p_reg_svc_rec );
+
+

PARAMETERS

+
       p_reg_svc_rec
+               [in] References the result of the service registration attempt.
+
+

NOTES

+
       The callback is used to notify a client of the result of a service
+       registration attempt with the subnet administrator.
+
+       In the kernel, this callback is usually invoked using a tasklet, dependent
+       on the implementation of the underlying verbs provider driver.
+
+

SEE ALSO

+
       ib_reg_svc, ib_reg_svc_rec_t
+
+
+
+ +

[Functions] +Access Layer/ib_pfn_report_cb_t

+ +

[top][parent][index]

+

NAME

+
       ib_pfn_report_cb_t
+
+

DESCRIPTION

+
       User-defined callback that is invoked to notify a client of an event
+       that has occurred on the fabric.
+
+

SYNOPSIS

+
typedef void
+(AL_API * FUNC_PTR64 ib_pfn_report_cb_t)(
+        IN                              ib_report_rec_t                         *p_report_rec );
+
+

PARAMETERS

+
       p_report_rec
+               [in] A reference to an event report.  The report contains
+               details about the type of event that has occurred, along with the
+               relevant device information.
+
+

NOTES

+
       The callback is used to notify users of remote events that have been seen
+       by a specified class manager.  Information about the type of event that
+       occurred along with the associated device is returned to the user through
+       the p_report_rec parameter.
+
+       Users register for device changes by subscribing with a class manager.
+       Users may subscribe for events either by directly invoking the
+       appropriate function in the access layer, or indirectly by adding the
+       necessary registration data to the access layer device file.
+
+       This callback is invoked from within a system thread context.
+
+

SEE ALSO

+
       ib_report_rec_t, ib_subscribe, ib_unsubscribe
+
+
+
+ +

[Functions] +Access Layer/ib_pfn_sub_cb_t

+ +

[top][parent][index]

+

NAME

+
       ib_pfn_sub_cb_t
+
+

DESCRIPTION

+
       User-defined callback invoked on completion of a subscription request.
+
+

SYNOPSIS

+
typedef void
+(AL_API * FUNC_PTR64 ib_pfn_sub_cb_t)(
+        IN                              ib_sub_rec_t                            *p_sub_rec );
+
+

PARAMETERS

+
       p_sub_rec
+               [in] This is a reference to a structure containing the result of the
+               subscription request.
+
+

NOTES

+
       This routine is invoked to notify a client of the result of a
+       subscription request with a class manager.  If the subscription request
+       was successful, the client will receive future notifications of the
+       subscribed event from the class manager.
+
+       This callback will always be invoked before a client receives information
+       reported on a subscribed event that has occurred.
+
+       In the kernel, this callback is usually invoked using a tasklet, dependent
+       on the implementation of the underlying verbs provider driver.
+
+

SEE ALSO

+
       ib_subscribe, ib_sub_rec_t
+
+
+
+ +

[Structures] +Access Layer/ib_pnp_ca_rec_t

+ +

[top][parent][index]

+

NAME

+
       ib_pnp_ca_rec_t
+
+

DESCRIPTION

+
       Notification information used to describe local channel adapter events.
+
+

SYNOPSIS

+
typedef struct _ib_pnp_ca_rec
+{
+        ib_pnp_rec_t                            pnp_rec;
+ TO_LONG_PTR(       ib_ca_attr_t* ,           p_ca_attr) ; 
+
+}       ib_pnp_ca_rec_t;
+
+

FIELDS

+
       pnp_rec
+               Structure describing the plug and play event being reported.
+
+       p_ca_attr
+               Attributes of the channel adapter that has experienced the event.
+               NULL for IB_PNP_CA_REMOVE, IB_PNP_PORT_REMOVE, and IB_PNP_IOC_REMOVE
+               events.
+
+

NOTES

+
       This structure is returned to the user to notify them of the addition
+       or the removal of a channel adapter.
+
+       The context field is NULL unless a context value has already been set
+       by the user.
+
+       Context values can be changed by updating the appropriate field
+       and will be take effect once the notification callback returns.
+
+       Once a device has been removed, all context associated with that device
+       is lost.
+
+       Recipients of CA-related PnP events should cast the ib_pnp_rec_t structure
+       returned in the PnP callback to this type to access CA-specific information.
+
+

SEE ALSO

+
       ib_open_al, ib_ca_attr_t, ib_reg_pnp, ib_dereg_pnp, ib_pfn_pnp_cb_t,
+       ib_ioc_info_t, ib_reject_ioc, ib_pnp_event_t
+
+
+
+ +

[Definitions] +Access Layer/ib_pnp_class_t

+ +

[top][parent][index]

+

NAME

+
       ib_pnp_class_t
+
+

DESCRIPTION

+
       Specifies the class of plug and play events that are being subscribed for.
+
+

SYNOPSIS

+
#define IB_PNP_CA                                               0x00000001
+#define IB_PNP_PORT                                             0x00000002
+#define IB_PNP_IOU                                              0x00000004
+#define IB_PNP_IOC                                              0x00000008
+
+#define IB_PNP_FLAG_REG_SYNC                    0x40000000
+#define IB_PNP_FLAG_REG_COMPLETE                0x80000000
+#define IB_PNP_FLAG_MASK                                0xF0000000
+#define IB_PNP_CLASS_MASK                               0x000000FF
+
+typedef uint32_t        ib_pnp_class_t;
+
+

VALUES

+
       IB_PNP_CA
+               Value used to register for local channel adapter events.  These
+                events include the addition or removal of a local channel adapter.
+
+       IB_PNP_PORT
+               Value used to register for local port events.  These events include
+               local port up or down events and port LID or Pkey changes.
+
+       IB_PNP_IOU
+               Value used to register for I/O unit PnP events.  I/O unit events
+               include notifications of I/O unit assignment to and dissociation from
+               the local host.
+
+       IB_PNP_IOC
+               Value used to register for an I/O controller PnP event.  I/O controller
+               events include notification of an I/O controller assignment to a local
+               port and indication that an I/O controller dissociation has occurred.
+
+       IB_PNP_FLAG_REG_SYNC
+               Flag that is ORed with the PnP Class to control behavior of the
+               ib_pnp_reg call.  When set, ib_pnp_reg returns after client has
+               received all events for the current state of the system.
+
+       IB_PNP_FLAG_REG_COMPLETE
+               Flag that is ORed with the PnP Class to control whether an event
+               is generated to indicate that a client has received all events for the
+               current state of the system.
+
+

NOTES

+
       When registering for PnP notification, a client specifies the class of
+       local events that the client wishes to be notified of.  For example to
+       request notification of events on a port, a client would use IB_PNP_PORT.
+       To be notified of the assignment of an I/O controller, a client would use
+       IB_PNP_IOC.
+
+       The PnP APIs do not support registration for multiple event classes at
+       a time.
+
+

SEE ALSO

+
       ib_pfn_pnp_cb_t, ib_pfn_report_cb_t, ib_pnp_rec_t, ib_pnp_event_t
+
+
+
+ +

[Definitions] +Access Layer/ib_pnp_event_t

+ +

[top][parent][index]

+

NAME

+
       ib_pnp_event_t
+
+

DESCRIPTION

+
       Indicates the type of plug and play event that has occurred.
+
+

SYNOPSIS

+
#define IB_PNP_EVENT_PATH                               0x00000800
+#define IB_PNP_EVENT_ADD                                0x00001000
+#define IB_PNP_EVENT_REMOVE                             0x00002000
+#define IB_PNP_EVENT_CHANGE                             0x00004000
+#define IB_PNP_EVENT_INIT                               0x00008000
+#define IB_PNP_EVENT_ARMED                              0x00010000
+#define IB_PNP_EVENT_ACTIVE                             0x00020000
+#define IB_PNP_EVENT_DOWN                               0x00040000
+#define IB_PNP_EVENT_PKEY                               0x00080000
+#define IB_PNP_EVENT_SM                                 0x00100000
+#define IB_PNP_EVENT_GID                                0x00200000
+#define IB_PNP_EVENT_LID                                0x00400000
+#define IB_PNP_EVENT_SUBNET                             0x00800000
+
+#define IB_PNP_CA_ADD                                   (IB_PNP_CA | IB_PNP_EVENT_ADD)
+#define IB_PNP_CA_REMOVE                                (IB_PNP_CA | IB_PNP_EVENT_REMOVE)
+
+#define IB_PNP_PORT_ADD                                 (IB_PNP_PORT | IB_PNP_EVENT_ADD)
+#define IB_PNP_PORT_REMOVE                              (IB_PNP_PORT | IB_PNP_EVENT_REMOVE)
+#define IB_PNP_PORT_INIT                                (IB_PNP_PORT | IB_PNP_EVENT_INIT)
+#define IB_PNP_PORT_ARMED                               (IB_PNP_PORT | IB_PNP_EVENT_ARMED)
+#define IB_PNP_PORT_ACTIVE                              (IB_PNP_PORT | IB_PNP_EVENT_ACTIVE)
+#define IB_PNP_PORT_DOWN                                (IB_PNP_PORT | IB_PNP_EVENT_DOWN)
+#define IB_PNP_PKEY_CHANGE                              (IB_PNP_PORT | IB_PNP_EVENT_PKEY)
+#define IB_PNP_SM_CHANGE                                (IB_PNP_PORT | IB_PNP_EVENT_SM)
+#define IB_PNP_GID_CHANGE                               (IB_PNP_PORT | IB_PNP_EVENT_GID)
+#define IB_PNP_LID_CHANGE                               (IB_PNP_PORT | IB_PNP_EVENT_LID)
+#define IB_PNP_SUBNET_TIMEOUT_CHANGE    (IB_PNP_PORT | IB_PNP_EVENT_SUBNET)
+
+#define IB_PNP_IOU_ADD                                  (IB_PNP_IOU | IB_PNP_EVENT_ADD)
+#define IB_PNP_IOU_REMOVE                               (IB_PNP_IOU | IB_PNP_EVENT_REMOVE)
+#define IB_PNP_IOC_ADD                                  (IB_PNP_IOC | IB_PNP_EVENT_ADD)
+#define IB_PNP_IOC_REMOVE                               (IB_PNP_IOC | IB_PNP_EVENT_REMOVE)
+#define IB_PNP_IOC_PATH_ADD                             (IB_PNP_IOC | IB_PNP_EVENT_PATH | \
+                                                                                IB_PNP_EVENT_ADD)
+#define IB_PNP_IOC_PATH_REMOVE                  (IB_PNP_IOC | IB_PNP_EVENT_PATH | \
+                                                                                IB_PNP_EVENT_REMOVE)
+
+#define IB_PNP_REG_COMPLETE                             IB_PNP_FLAG_REG_COMPLETE
+
+typedef uint32_t        ib_pnp_event_t;
+
+

VALUES

+
       IB_PNP_CA_ADD
+               Indicates that a new channel adapter has been added.
+
+       IB_PNP_CA_REMOVE
+               Indicates that a channel adapter has been removed.
+
+       IB_PNP_PORT_ADD
+               Indicates that a new port has been added.  This callback will always
+               be followed by a callback to indicate the actual port state to allow
+               clients to use the PnP callbacks to drive their state machine.
+
+       IB_PNP_PORT_REMOVE
+               Indicates that a port has been removed.
+               A CA remove event will trigger this event first.
+
+       IB_PNP_PORT_INIT
+               Indicates that a port is in the IB_LINK_INIT state.
+
+       IB_PNP_PORT_ARMED
+               Indicates that a port is in the IB_LINK_ARMED state.
+
+       IB_PNP_PORT_ACTIVE
+               Indicates that a port is in the IB_LINK_ACTIVE state.
+
+       IB_PNP_PORT_DOWN
+               Indicates that a port down event has occurred.
+
+       IB_PNP_PKEY_CHANGE
+               Indicates that port Pkey change has ocurred.
+
+       IB_PNP_SM_CHANGE
+               Indicates that the SM assignment for a port has changed.
+
+       IB_PNP_GID_CHANGE
+               Indicates that the GID assignment for a port has changed.
+
+       IB_PNP_LID_CHANGE
+               Indicates that the LID or LMC assignment for a port has changed.
+
+       IB_PNP_SUBNET_TIMEOUT_CHANGE
+               Indicates that the subnet timeout assignment for a port has changed.
+
+       IB_PNP_IOU_ADD
+               Indicates that an I/O unit assignment has occured.
+
+       IB_PNP_IOU_REMOVE
+               Indicates that an I/O unit disassociation has occured.
+
+       IB_PNP_IOC_ADD
+               Indicates that an I/O controller assignment has occurred.
+
+       IB_PNP_IOC_REMOVE
+               Indicates that an I/O controller dissociation has occurred.
+               A port down event will trigger this event first.
+
+       IB_PNP_IOC_PATH_ADD
+               Indicates that a new path to an I/O controller is available.
+
+       IB_PNP_IOC_PATH_REMOVE
+               Indiactes that a path to an I/O controller is no longer avaialble.
+
+       IB_PNP_REG_COMPLETE
+               Indicates that all events associated with a ib_reg_pnp call have been
+               reported to the user.  The user's state of the system is now in
+               sync with that of the access layer.
+
+

NOTES

+
               The Access Layer maintains a queue of client PnP registrations.
+               Using this queue, PnP events are reported to clients in a specific
+               order.  CA add, port add, and IOC add events are reported from the
+               head of the queue, while CA remove, port remove, and IOC remove events
+               are reported from the tail.  Clients are responsible for performing
+               registrations in the proper sequence to ensure that PnP event
+               notifiations occur in the desired order.
+
+

SEE ALSO

+
       ib_pfn_pnp_cb_t, ib_pfn_report_cb_t, ib_pnp_rec_t, ib_pnp_class_t
+
+
+
+ +

[Structures] +Access Layer/ib_pnp_ioc_path_rec_t

+ +

[top][parent][index]

+

NAME

+
       ib_pnp_ioc_path_rec_t
+
+

DESCRIPTION

+
       Notification information used to describe local channel adapter, port,
+       and I/O controller events.
+
+

SYNOPSIS

+
typedef struct _ib_pnp_ioc_path_rec
+{
+        ib_pnp_rec_t                            pnp_rec;
+        net64_t                                         ca_guid;
+        net64_t                                         port_guid;
+        ib_path_rec_t                           path;
+
+}       ib_pnp_ioc_path_rec_t;
+
+

FIELDS

+
       pnp_rec
+               Structure describing the plug and play event being reported.
+
+       ca_guid
+               GUID of the local HCA through which the I/O controller is accessible.
+               Valid only for IB_PNP_IOC_PATH_ADD and IB_PNP_IOC_PATH_REMOVE events.
+
+       port_guid
+               GUID of the local HCA port through which the I/O controller is
+               accessible.  Valid only for IB_PNP_IOC_PATH_ADD and
+               IB_PNP_IOC_PATH_REMOVE events.
+
+       p_path
+               Path record that provides connectivity with a given I/O controller.
+               Valid only for IB_PNP_IOC_PATH_ADD and IB_PNP_IOC_PATH_REMOVE events.
+
+

NOTES

+
       This structure is returned to the user to notify them of the addition
+       and removal of a path to an I/O controller.  I/O controller path
+       notifications are only delivered with respect to a previously reported
+       I/O controller.
+
+       The context field is NULL unless a context value has already been set
+       by the user.
+
+       Context values can be changed by updating the appropriate field
+       and will be take effect once the notification callback returns.
+
+       Once a device has been removed, all context associated with that device
+       is lost.  Context is maintained between port down and subsequent port up
+       events provided that the channel adapter is not removed.
+
+

SEE ALSO

+
       ib_open_al, ib_ca_attr_t, ib_reg_pnp, ib_dereg_pnp, ib_pfn_pnp_cb_t,
+       ib_ioc_info_t, ib_reject_ioc, ib_pnp_event_t
+
+
+
+ +

[Structures] +Access Layer/ib_pnp_ioc_rec_t

+ +

[top][parent][index]

+

NAME

+
       ib_pnp_ioc_rec_t
+
+

DESCRIPTION

+
       Notification information used to describe local channel adapter, port,
+       and I/O controller events.
+
+

SYNOPSIS

+
typedef struct _ib_pnp_ioc_rec
+{
+        ib_pnp_rec_t                            pnp_rec;
+        net64_t                                         ca_guid;
+        ib_ioc_info_t                           info;
+        ib_svc_entry_t                          svc_entry_array[1];
+
+}       ib_pnp_ioc_rec_t;
+
+

FIELDS

+
       pnp_rec
+               Structure describing the plug and play event being reported.
+
+       ca_guid
+               GUID of the local HCA through which the I/O controller is accessible.
+               Valid only for IB_PNP_IOC_ADD events.
+
+       p_ioc_info
+               The I/O controller information for an assigned controller, including
+               information for the I/O unit.  Valid only for IB_PNP_IOC_ADD events.
+
+       svc_entry_array
+               If an I/O controller is being reported, this will reference an array
+               of service entries associated with the I/O controller.  The actual
+               number of entries in the array may be determined by examining the
+               svc_entries field in the I/O controller profile.  Valid only for
+               IB_PNP_IOC_ADD events.
+
+

NOTES

+
       This structure is returned to the user to notify them of the addition
+       and removal of an I/O controller.
+
+       The context field is NULL unless a context value has already been set
+       by the user.
+
+       Context values can be changed by updating the appropriate field
+       and will be take effect once the notification callback returns.
+
+       Once a device has been removed, all context associated with that device
+       is lost.  Context is maintained between port down and subsequent port up
+       events provided that the channel adapter is not removed.
+
+

SEE ALSO

+
       ib_open_al, ib_ca_attr_t, ib_reg_pnp, ib_dereg_pnp, ib_pfn_pnp_cb_t,
+       ib_ioc_info_t, ib_reject_ioc, ib_pnp_event_t
+
+
+
+ +

[Structures] +Access Layer/ib_pnp_iou_rec_t

+ +

[top][parent][index]

+

NAME

+
       ib_pnp_iou_rec_t
+
+

DESCRIPTION

+
       Notification information used to describe local I/O unit events.
+
+

SYNOPSIS

+
typedef struct _ib_pnp_iou_rec
+{
+        ib_pnp_rec_t                            pnp_rec;
+        net64_t                                         guid;
+        net64_t                                         ca_guid;
+        net64_t                                         chassis_guid;
+        uint8_t                                         slot;
+        net32_t                                         vend_id;
+        net16_t                                         dev_id;
+        net32_t                                         revision;
+        char                                            desc[IB_NODE_DESCRIPTION_SIZE + 1];
+
+}       ib_pnp_iou_rec_t;
+
+

FIELDS

+
       pnp_rec
+               Structure describing the plug and play event being reported.
+
+       ca_guid
+               GUID of the local HCA through which the I/O unit is accessible.  Valid
+               only for IB_PNP_IOU_ADD events.
+
+       chassis guid
+               GUID of the chassis in which an I/O unit is installed.  Valid only for
+               IB_PNP_IOU_ADD events.
+
+       slot
+               Chassis slot number in which an I/O unit is installed.  Valid only for
+               IB_PNP_IOU_ADD events.
+
+       guid
+               GUID of an I/O unit from which one or more I/O controllers are assigned
+               to this host.  Valid only for IB_PNP_IOU_ADD events.
+
+       vend_id
+               Vendor ID of an I/O unit from which one or more I/O controllers are
+               assigned to this host.  Valid only for IB_PNP_IOU_ADD events.
+
+       dev_id
+               Device ID of an I/O unit from which one or more I/O controllers are
+               assigned to this host.  Valid only for IB_PNP_IOU_ADD events.
+
+       revision
+               Revision of an I/O unit from which one or more I/O controllers are
+               assigned to this host.  Valid only for IB_PNP_IOU_ADD events.
+
+       desc
+               Node description string for an I/O unit from which one or more I/O
+               controllers are assigned to this host.  Valid only for IB_PNP_IOU_ADD
+               events.
+
+

NOTES

+
       This structure is returned to the user to notify them of the addition
+       and removal of an I/O Unit.
+
+       The context field is NULL unless a context value has already been set
+       by the user.
+
+       Context values can be changed by updating the appropriate field
+       and will be take effect once the notification callback returns.
+
+       Once a device has been removed, all context associated with that device
+       is lost.  Context is maintained between port down and subsequent port up
+       events provided that the channel adapter is not removed.
+
+

SEE ALSO

+
       ib_open_al, ib_ca_attr_t, ib_reg_pnp, ib_dereg_pnp, ib_pfn_pnp_cb_t,
+       ib_ioc_info_t, ib_reject_ioc, ib_pnp_event_t
+
+
+
+ +

[Structures] +Access Layer/ib_pnp_port_rec_t

+ +

[top][parent][index]

+

NAME

+
       ib_pnp_port_rec_t
+
+

DESCRIPTION

+
       Notification information used to describe local port events.
+
+

SYNOPSIS

+
typedef struct _ib_pnp_port_rec
+{
+        ib_pnp_rec_t                            pnp_rec;
+ TO_LONG_PTR(       ib_ca_attr_t* ,           p_ca_attr) ; 
+ TO_LONG_PTR(       ib_port_attr_t* ,         p_port_attr) ; 
+
+}       ib_pnp_port_rec_t;
+
+

FIELDS

+
       pnp_rec
+               Structure describing the plug and play event being reported.
+
+       p_ca_attr
+               Attributes of the channel adapter that has experienced the event.
+               NULL for IB_PNP_CA_REMOVE, IB_PNP_PORT_REMOVE, and IB_PNP_IOC_REMOVE
+               events.
+
+       p_port_attr
+               Attributes of the port that has experienced the event.  Valid only
+               for IB_PNP_PORT_UP, IB_PNP_PORT_DOWN, IB_PNP_PKEY_CHANGE, and
+               IB_PNP_IOC_ADD events.
+
+

NOTES

+
       This structure is returned to the user to notify them of port events.
+
+       The context field is NULL unless a context value has already been set
+       by the user.
+
+       Context values can be changed by updating the appropriate field
+       and will be take effect once the notification callback returns.
+
+       Once a device has been removed, all context associated with that device
+       is lost.  Context is maintained between port down and subsequent port up
+       events provided that the channel adapter is not removed.
+
+       Recipients of port related PnP events should cast the ib_pnp_rec_t structure
+       returned in the PnP callback to this type to access port specific information.
+
+

SEE ALSO

+
       ib_open_al, ib_ca_attr_t, ib_reg_pnp, ib_dereg_pnp, ib_pfn_pnp_cb_t,
+       ib_ioc_info_t, ib_reject_ioc, ib_pnp_event_t
+
+
+
+ +

[Structures] +Access Layer/ib_pnp_rec_t

+ +

[top][parent][index]

+

NAME

+
       ib_pnp_rec_t
+
+

DESCRIPTION

+
       Notification information used to describe local channel adapter, port,
+       and I/O controller events.
+
+

SYNOPSIS

+
typedef struct _ib_pnp_rec
+{
+        ib_pnp_event_t                          pnp_event;
+
+        ib_pnp_handle_t __ptr64                         h_pnp;
+        ib_pnp_handle_t __ptr64                         h_ioc_event;
+
+ TO_LONG_PTR(       void* ,                           pnp_context) ; 
+ TO_LONG_PTR(       void* ,                           context) ; 
+        //NOTE:
+        //guid and ca_guid use as key to flexi map need to keep these field together
+        ib_net64_t                                      guid;
+        ib_net64_t                                      ca_guid;
+
+}       ib_pnp_rec_t;
+
+

FIELDS

+
       pnp_event
+               Describes the type of plug and play event that is being reported.
+
+       h_pnp
+               A handle to the notification registration for which this PnP record
+               was generated.  This handle will match the handle returned through
+               an ib_reg_pnp call.  It is provided in case a PnP notification event
+               occurs before a client's call to ib_reg_pnp can return.  This handle
+               may be used to cancel further notification of PnP events.
+
+       h_ioc_event
+               A handle that is unique to an I/O controller assignment event.
+               This handle is used to reject the assignment of an I/O controller
+               from within the ib_pfn_pnp_cb_t callback.  Valid for IB_PNP_IOC_ADD
+               events only.
+
+       pnp_context
+               User-defined context information specified when registering for
+               notification of the event.  See the notes section below for
+               more details.
+
+       context
+               This field references a user-specified context on which the event
+               occurred.  See the notes section below for more details.
+
+       guid
+               The GUID of the adapter, port, IOU, or IOC for which
+               the PnP event occurred.
+
+       ca_guid
+               The  GUID of the HCA 
+
+

NOTES

+
       This structure is returned to the user to notify them of: the addition
+       of a channel adapter, the removal of a channel adapter, a port up or down
+       event, a port pkey change, and I/O controller addition and removal events.
+
+       The context field is NULL unless a context value has already been set
+       by the user.
+
+       The context value can be changed by updating its field
+       and will take effect once the notification callback returns.
+
+       Once a device has been removed, all context associated with that device
+       is lost.  Context is maintained between port down and subsequent port up
+       events provided that the channel adapter is not removed.
+
+       I/O controller path notifications are only delivered with respect to a
+       previously reported I/O controller.
+
+

SEE ALSO

+
       ib_open_al, ib_ca_attr_t, ib_reg_pnp, ib_dereg_pnp, ib_pfn_pnp_cb_t,
+       ib_ioc_info_t, ib_reject_ioc, ib_pnp_event_t
+
+
+
+ +

[Structures] +Access Layer/ib_pnp_req_t

+ +

[top][parent][index]

+

NAME

+
       ib_pnp_req_t
+
+

DESCRIPTION

+
       Information used to register for notification of local and I/O
+       controller assignment events.
+
+

SYNOPSIS

+
typedef struct _ib_pnp_req
+{
+        ib_pnp_class_t                          pnp_class;
+        const void                                      *pnp_context;
+        ib_pfn_pnp_cb_t                         pfn_pnp_cb;
+
+}       ib_pnp_req_t;
+
+

FIELDS

+
       pnp_class
+               Specifies the class of PnP events that the client wishes to be
+               notified of.
+
+       pnp_context
+               User-defined context information associated with this notification.
+               The context data is returned to the user as a part of their PnP
+               notification callback.
+
+       pfn_pnp_cb
+               User-defined callback function that is invoked to notify the user of
+               the occurrance of a plug and play event.
+
+

NOTES

+
       This structure is used when requesting notification of local events from
+       the access layer.  The class of PnP events which to be notified of is
+       specified through the pnp_class field.
+
+

SEE ALSO

+
       ib_pnp_class_t, ib_pfn_pnp_cb_t, ib_reg_pnp, ib_pnp_rec_t
+
+
+
+ +

[Functions] +Access Layer/ib_poll_cq

+ +

[top][parent][index]

+

NAME

+
       ib_poll_cq
+
+

DESCRIPTION

+
       Checks a completion queue for completed work requests.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_poll_cq(
+        IN              const   ib_cq_handle_t FUNC_PTR64                          h_cq,
+        IN      OUT                     ib_wc_t** const                         pp_free_wclist,
+                OUT                     ib_wc_t** const                         pp_done_wclist );
+
+

PARAMETERS

+
       h_cq
+               [in] A handle to a completion queue to check for completions on.
+
+       pp_free_wclist
+               [in/out] On input, a list of work completion structures provided by
+               the client.  These are used to report completed work requests through
+               the pp_done_wclist.
+
+               On output, this contains the list of work completions structures for
+               which no work completion was found.
+
+       pp_done_wclist
+               [out] A list of work completions retrieved from the completion queue.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The poll operation completed successfully.  If the work completion
+               structures referenced by the pp_free_wclist list is empty there are
+               potentially more completions available to retrieve.
+
+       IB_INVALID_PARAMETER
+               A reference to the free or done work completion list was not provided.
+
+       IB_INVALID_CQ_HANDLE
+               The completion queue handle was invalid.
+
+       IB_NOT_FOUND
+               No completed work requests were removed from the completion queue.
+
+

NOTES

+
       This routine retrieves completed work requests from the specified
+       completion queue.  This call will retrieve all completed requests,
+       up to to the number of work completion structures referenced by the
+       pp_free_wclist.  Completed requests will be returned through the
+       pp_done_wclist parameter.
+
+

SEE ALSO

+
       ib_create_cq, ib_post_send, ib_post_recv, ib_bind_mw, ib_wc_t
+
+
+
+ +

[Functions] +Access Layer/ib_post_recv

+ +

[top][parent][index]

+

NAME

+
       ib_post_recv
+
+

DESCRIPTION

+
       This routine posts a work request to the receive queue of a queue pair.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_post_recv(
+        IN              const   ib_qp_handle_t FUNC_PTR64                          h_qp,
+        IN                              ib_recv_wr_t* const                     p_recv_wr,
+                OUT                     ib_recv_wr_t                            **pp_recv_failure OPTIONAL );
+
+

PARAMETERS

+
       h_qp
+               [in] The queue pair to which this work request is being submitted.
+
+       p_recv_wr
+               [in] A reference to the head of the work request list.
+
+       pp_recv_failure
+               [out] If the post receive operation failed, this references the work
+               request in the p_recv_wr list where the first failure occurred.
+               This parameter may be NULL if only a single work request is being
+               posted to the QP.
+
+ RETURN VALUES
+       IB_SUCCESS
+               All work requests were successfully posted.
+
+       IB_INVALID_QP_HANDLE
+               The queue pair handle was invalid.
+
+       IB_INVALID_PARAMETER
+               A reference to the receive work request list was not provided.
+
+       IB_INSUFFICIENT_RESOURCES
+               The number of posted work requests exceed the current depth available
+               on the receive queue.
+
+       IB_INVALID_WR_TYPE
+               The work request type was invalid.
+
+       IB_INVALID_QP_STATE
+               The current queue pair state does not allow posting receives.
+
+

NOTES

+
       This routine posts a work request to the receive queue of a queue pair.
+       The type of work to perform is defined by the p_recv_wr parameter.  This
+       call is used to post data buffers to receive incoming message sends.
+
+

SEE ALSO

+
       ib_recv_wr_t
+
+
+
+ +

[Functions] +Access Layer/ib_post_send

+ +

[top][parent][index]

+

NAME

+
       ib_post_send
+
+

DESCRIPTION

+
       This routine posts a work request to the send queue of a queue pair.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_post_send(
+        IN              const   ib_qp_handle_t FUNC_PTR64                          h_qp,
+        IN                              ib_send_wr_t* const                     p_send_wr,
+                OUT                     ib_send_wr_t                            **pp_send_failure OPTIONAL );
+
+

PARAMETERS

+
       h_qp
+               [in] The queue pair to which this work request is being submitted.
+
+       p_send_wr
+               [in] A reference to the head of the work request list.
+
+       pp_send_failure
+               [out] If the post send operation failed, this references the work
+               request in the p_send_wr list where the first failure occurred.
+               This parameter may be NULL if only a single work request is being
+               posted to the QP.
+
+ RETURN VALUES
+       IB_SUCCESS
+               All work requests were successfully posted.
+
+       IB_INVALID_QP_HANDLE
+               The queue pair handle was invalid.
+
+       IB_INVALID_PARAMETER
+               A reference to the send work request list was not provided.
+
+       IB_INSUFFICIENT_RESOURCES
+               The number of posted work requests exceed the current depth available
+               on the send queue.
+
+       IB_INVALID_WR_TYPE
+               The work request type was invalid.
+
+       IB_INVALID_QP_STATE
+               The current queue pair state does not allow posting sends.
+
+       IB_INVALID_MAX_SGE
+               The number of work request scatter gather elements exceed the queue
+               pair configuration.
+
+       IB_UNSUPPORTED
+               The requested operation is not supported by the channel adapter.
+
+

NOTES

+
       This routine posts a work request to the send queue of a queue pair.
+       The type of work to perform is defined by the p_send_wr parameter.
+
+

SEE ALSO

+
       ib_send_wr_t
+
+
+
+ +

[Functions] +Access Layer/ib_post_srq_recv

+ +

[top][parent][index]

+

NAME

+
       ib_post_srq_recv
+
+

DESCRIPTION

+
       This routine posts a work request to the shared receive queue of a shared receive queue.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_post_srq_recv(
+        IN              const   ib_srq_handle_t FUNC_PTR64                         h_srq,
+        IN                              ib_recv_wr_t* const                     p_recv_wr,
+                OUT                     ib_recv_wr_t                            **pp_recv_failure OPTIONAL );
+
+

PARAMETERS

+
       h_srq
+               [in] The shared receive queue to which this work request is being submitted.
+
+       p_recv_wr
+               [in] A reference to the head of the work request list.
+
+       pp_recv_failure
+               [out] If the post receive operation failed, this references the work
+               request in the p_recv_wr list where the first failure occurred.
+               This parameter may be NULL if only a single work request is being
+               posted to the QP.
+
+ RETURN VALUES
+       IB_SUCCESS
+               All work requests were successfully posted.
+
+       IB_INVALID_QP_HANDLE
+               The shared receive queue handle was invalid.
+
+       IB_INVALID_PARAMETER
+               A reference to the receive work request list was not provided.
+
+       IB_INSUFFICIENT_RESOURCES
+               The number of posted work requests exceed the current depth available
+               on the receive queue.
+
+       IB_INVALID_WR_TYPE
+               The work request type was invalid.
+
+       IB_INVALID_QP_STATE
+               The current shared receive queue state does not allow posting receives.
+
+

NOTES

+
       This routine posts a work request to the shared receive queue.
+       The type of work to perform is defined by the p_recv_wr parameter.  This
+       call is used to post data buffers to receive incoming message sends.
+
+

SEE ALSO

+
       ib_recv_wr_t
+
+
+
+ +

[Functions] +Access Layer/ib_put_mad

+ +

[top][parent][index]

+

NAME

+
       ib_put_mad
+
+

DESCRIPTION

+
       Returns a list of MAD elements to the pool.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_put_mad(
+        IN              const   ib_mad_element_t*                       p_mad_element_list );
+
+

PARAMETERS

+
       p_mad_element_list
+               [in] A pointer to a list of MAD elements.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The list of MAD elements was successfully returned to the MAD pool.
+
+       IB_INVALID_PARAMETER
+               A reference to the MAD element list was not provided.
+
+

NOTES

+
       This function returns a list of MAD elements to the pool.
+
+

SEE ALSO

+
       ib_get_mad, ib_mad_element_t
+
+
+
+ +

[Functions] +Access Layer/ib_query

+ +

[top][parent][index]

+

NAME

+
       ib_query
+
+

DESCRIPTION

+
       Routine used to request an access layer provided query of the subnet
+       administrator.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_query(
+        IN              const   ib_al_handle_t FUNC_PTR64                          h_al,
+        IN              const   ib_query_req_t* const           p_query_req,
+                OUT                     ib_query_handle_t FUNC_PTR64* const        ph_query OPTIONAL );
+
+

PARAMETERS

+
       h_al
+               [in] A handle to an open instance of the access layer.
+
+       p_query_req
+               [in] Specifies the type of query that the access layer should perform,
+               along with information needed to process the completed query.
+
+       ph_query
+               [out] Pointer to a query handle that can be used to cancel the query.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The subnet administrator query was initiated.
+
+       IB_INVALID_AL_HANDLE
+               The access layer handle was invalid.
+
+       IB_INVALID_PARAMETER
+               A reference to the query request was not provided.
+
+       IB_INSUFFICIENT_MEMORY
+               There was insufficient memory to perform the operation.
+
+       IB_INVALID_GUID
+               No port was found for the port_guid specified in the request.
+
+       IB_ERROR
+               An invalid query_type was specified in the request.
+
+       IB_INSUFFICIENT_RESOURCES
+               There were insufficient resources currently available on the channel
+               adapter to perform the operation.
+
+

NOTES

+
       This routine directs the access layer to initiate a query to the subnet
+       administrator for desired information.  The access layer will issue the
+       query, collect the results, and report them to the client through a user-
+       specified callback.  The access layer is responsible for retrying the
+       operation as directed by the client.
+
+

SEE ALSO

+
       ib_cancel_query, ib_query_req_t
+
+
+
+ +

[Functions] +Access Layer/ib_query_av

+ +

[top][parent][index]

+

NAME

+
       ib_query_av
+
+

DESCRIPTION

+
       Returns the attributes of an address vector.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_query_av(
+        IN              const   ib_av_handle_t FUNC_PTR64                          h_av,
+                OUT                     ib_av_attr_t* const                     p_av_attr,
+                OUT                     ib_pd_handle_t FUNC_PTR64* const           ph_pd );
+
+

PARAMETERS

+
       h_av
+               [in] A handle to an existing address vector.
+
+       p_av_attr
+               [out] Upon successful completion, the structure referenced by this
+               parameter contains the attributes of the specified address vector.
+
+       ph_pd
+               [out] Upon successful completion, this references a handle to the
+               protection domain associated with the address vector.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The attributes were returned successfully.
+
+       IB_INVALID_AV_HANDLE
+               The address vector handle was invalid.
+
+       IB_INVALID_PARAMETER
+               A reference to the address vector attributes structure or protection
+               domain handle was not provided.
+
+

SEE ALSO

+
       ib_create_av, ib_modify_av, ib_destroy_av, ib_av_attr_t
+
+
+
+ +

[Functions] +Access Layer/ib_query_ca

+ +

[top][parent][index]

+

NAME

+
       ib_query_ca
+
+

DESCRIPTION

+
       Queries the attributes of an opened channel adapter.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_query_ca(
+        IN              const   ib_ca_handle_t FUNC_PTR64                          h_ca,
+                OUT                     ib_ca_attr_t* const                     p_ca_attr OPTIONAL,
+        IN      OUT                     uint32_t* const                         p_size );
+
+

PARAMETERS

+
       h_ca
+               [in] The handle to an open channel adapter.
+
+       p_ca_attr
+               [out] A reference to a buffer where the channel adapter attributes,
+               including port attribute information will be copied.  If this parameter
+               is NULL, then the required buffer size needed to return all of the CA
+               attribute information is returned through the p_size parameter.  The
+               ib_ca_attr_t structure for the specified channel adapter is stored
+               at the top of the buffer.
+
+       p_size
+               [in/out] On input, this references the size of the data buffer
+               referenced by the p_ca_attr parameter.
+
+               On output, the number of bytes used or needed to copy all CA
+               attribute information.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The attributes were returned successfully.
+
+       IB_INVALID_CA_HANDLE
+               The channel adapter handle was invalid.
+
+       IB_INSUFFICIENT_MEMORY
+               The size of the p_ca_attr buffer, specified through p_size, is
+               insufficient to store all of the CA attribute information.
+
+       IB_INVALID_PARAMETER
+               A reference to the size was not provided.
+
+

NOTES

+
       This routine returns information about the specified channel adapter,
+       including port attributes.  The amount of information returned through
+       this call is variable sized.  Users may obtain the size of the data
+       buffer required to obtain the CA attributes by calling this function
+       with p_ca_attr set to NULL.  The access layer will then return the
+       necessary size in the variable referenced by the p_size parameter.
+
+

SEE ALSO

+
       ib_open_ca, ib_query_ca_by_guid, ib_modify_ca, ib_close_ca, ib_ca_attr_t
+
+
+
+ +

[Functions] +Access Layer/ib_query_ca_by_guid

+ +

[top][parent][index]

+

NAME

+
       ib_query_ca_by_guid
+
+

DESCRIPTION

+
       Queries the attributes of an opened channel adapter.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_query_ca_by_guid(
+        IN              const   ib_al_handle_t FUNC_PTR64                          h_al,
+        IN              const   ib_net64_t                                      ca_guid,
+                OUT                     ib_ca_attr_t* const                     p_ca_attr OPTIONAL,
+        IN      OUT                     uint32_t* const                         p_size );
+
+

PARAMETERS

+
       h_al
+               [in] The handle to an open instance of AL.
+
+       ca_guid
+               [in] The GUID of the channel adapter to query.
+
+       p_ca_attr
+               [out] A reference to a buffer where the channel adapter attributes,
+               including port attribute information will be copied.  If this parameter
+               is NULL, then the required buffer size needed to return all of the CA
+               attribute information is returned through the p_size parameter.  The
+               ib_ca_attr_t structure for the specified channel adapter is stored
+               at the top of the buffer.
+
+       p_size
+               [in/out] On input, this references the size of the data buffer
+               referenced by the p_ca_attr parameter.
+
+               On output, the number of bytes used or needed to copy all CA
+               attribute information.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The attributes were returned successfully.
+
+       IB_INVALID_AL_HANDLE
+               The access layer handle was invalid.
+
+       IB_INVALID_GUID
+               No channel adapter in the system was found for the specified ca_guid.
+
+       IB_INSUFFICIENT_MEMORY
+               The size of the p_ca_attr buffer, specified through p_size, is
+               insufficient to store all of the CA attribute information.
+
+       IB_INVALID_PARAMETER
+               A reference to the size was not provided.
+
+

NOTES

+
       This routine returns information about the specified channel adapter,
+       including port attributes.  The amount of information returned through
+       this call is variable sized.  Users may obtain the size of the data
+       buffer required to obtain the CA attributes by calling this function
+       with p_ca_attr set to NULL.  The access layer will then return the
+       necessary size in the variable referenced by the p_size parameter.
+
+

SEE ALSO

+
       ib_open_ca, ib_query_ca, ib_modify_ca, ib_close_ca, ib_ca_attr_t
+
+
+
+ +

[Functions] +Access Layer/ib_query_cq

+ +

[top][parent][index]

+

NAME

+
       ib_query_cq
+
+

DESCRIPTION

+
       Returns information about the specified completion queue.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_query_cq(
+        IN              const   ib_cq_handle_t FUNC_PTR64          h_cq,
+        OUT             uint32_t* const                         p_size );
+
+

PARAMETERS

+
       h_cq
+               [in] A handle to an existing completion queue.
+
+       p_size
+               [out] Upon successful completion of this call, contains the actual
+               size of the completion queue.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The completion queue was successfully queried.
+
+       IB_INVALID_CQ_HANDLE
+               The completion queue handle was invalid.
+
+       IB_INVALID_PARAMETER
+               A reference to the completion queue size was not provided.
+
+

SEE ALSO

+
       ib_create_cq
+
+
+
+ +

[Functions] +Access Layer/ib_query_mr

+ +

[top][parent][index]

+

NAME

+
       ib_query_mr
+
+

DESCRIPTION

+
       Query the current attributes of a memory region.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_query_mr(
+        IN              const   ib_mr_handle_t FUNC_PTR64                          h_mr,
+                OUT                     ib_mr_attr_t* const                     p_mr_attr );
+
+

PARAMETERS

+
       h_mr
+               [in] A handle to a registered memory region.
+
+       p_mr_attr
+               [out] A reference to a structure where the registered memory attributes
+               will be copied.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The memory region attributes were returned successfully.
+
+       IB_INVALID_MR_HANDLE
+               The memory region handle was invalid.
+
+       IB_INVALID_PARAMETER
+               A reference to the memory region attributes was not provided.
+
+

NOTES

+
       This routine returns information about the specified registered memory
+       region.
+
+

SEE ALSO

+
       ib_dereg_mr, ib_reg_mem, ib_reg_shared, ib_mr_attr_t
+
+
+
+ +

[Functions] +Access Layer/ib_query_mw

+ +

[top][parent][index]

+

NAME

+
       ib_query_mw
+
+

DESCRIPTION

+
       Query the current attributes of a memory window.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_query_mw(
+        IN              const   ib_mw_handle_t FUNC_PTR64                          h_mw,
+                OUT                     ib_pd_handle_t FUNC_PTR64* const           ph_pd,
+                OUT                     net32_t* const                          p_rkey );
+
+

PARAMETERS

+
       h_mw
+               [in] A handle to an existing memory window.
+
+       ph_pd
+               [out] Upon successful completion of this call, this will reference
+               the protection domain associated with this memory window.
+
+       p_rkey
+               [out] Upon successful completion of this call, this will reference
+               the current rkey associated with this memory window.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The memory window attributes were returned successfully.
+
+       IB_INVALID_MW_HANDLE
+               The memory window handle was invalid.
+
+       IB_INVALID_PARAMETER
+               A reference to the protection domain handle or rkey was not provided.
+
+

NOTES

+
       This routine returns information about the specified memory window.
+
+

SEE ALSO

+
       ib_create_mw
+
+
+
+ +

[Functions] +Access Layer/ib_query_qp

+ +

[top][parent][index]

+

NAME

+
       ib_query_qp
+
+

DESCRIPTION

+
       Query the current attributes of the queue pair.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_query_qp(
+        IN              const   ib_qp_handle_t FUNC_PTR64                          h_qp,
+                OUT                     ib_qp_attr_t* const                     p_qp_attr );
+
+

PARAMETERS

+
       h_qp
+               [in] A handle to an existing queue pair.
+
+       p_qp_attr
+               [out] Upon successful completion of this call, the structure
+               referenced by this parameter contains the attributes of the specified
+               quere pair.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The queue pair attributes were returned successfully.
+
+       IB_INVALID_QP_HANDLE
+               The queue pair handle was invalid.
+
+       IB_INVALID_PARAMETER
+               A reference to the queue pair attributes structure was not provided.
+
+

NOTES

+
       This routine returns information about the specified queue pair.
+
+

SEE ALSO

+
       ib_create_qp, ib_modify_qp, ib_qp_attr_t
+
+
+
+ +

[Structures] +Access Layer/ib_query_rec_t

+ +

[top][parent][index]

+

NAME

+
       ib_query_rec_t
+
+

DESCRIPTION

+
       Contains the results of a subnet administration query.
+
+

SYNOPSIS

+
typedef struct _ib_query_rec
+{
+ TO_LONG_PTR(       const void* ,                     query_context) ; 
+        ib_api_status_t                         status;
+
+        ib_query_type_t                         query_type;
+        uint32_t                                        result_cnt;
+ TO_LONG_PTR(       ib_mad_element_t* ,       p_result_mad) ; 
+
+}       ib_query_rec_t;
+
+

FIELDS

+
       query_context
+               User-defined context information associated with the query through
+               the ib_reg_query 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 ib_reg_query call.
+
+       result_cnt
+               The number of result structures that were returned by the query.
+
+       p_result_mad
+               For queries returning IB_SUCCESS or IB_REMOTE_ERROR, this references
+               the MAD returned by the subnet administrator containing the list
+               of results or the returned error code.
+
+

NOTES

+
       A query result structure is returned to a client through their
+       ib_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 the subnet administrator, p_result_mad will reference a MAD element
+       containing the results.  The MAD referenced by p_result_mad is owned by
+       the user and remains available even after their callback returns.  Users
+       must call ib_put_mad() to return the MAD element back to the access layer
+       when they are done accessing the results.
+
+       To retrieve individual result structures from the p_result_mad, users
+       may call ib_get_query_result().
+
+

SEE ALSO

+
       ib_query, ib_pfn_query_cb_t, ib_api_status_t, ib_put_mad, ib_mad_element_t
+       ib_query_status_t, ib_query_type_t, ib_get_query_result
+
+
+
+ +

[Structures] +Access Layer/ib_query_req_t

+ +

[top][parent][index]

+

NAME

+
       ib_query_req_t
+
+

DESCRIPTION

+
       Information used to request an access layer provided query of the subnet
+       administrator.
+
+

SYNOPSIS

+
typedef struct _ib_query_req
+{
+        ib_query_type_t                         query_type;
+ TO_LONG_PTR(       const void* ,                     p_query_input) ; 
+        ib_net64_t                                      port_guid;
+
+        uint32_t                                        timeout_ms;
+        uint32_t                                        retry_cnt;
+        ib_al_flags_t                           flags;
+
+ TO_LONG_PTR(       const void* ,                     query_context) ; 
+        ib_pfn_query_cb_t                       pfn_query_cb;
+
+}       ib_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.
+
+       port_guid
+               Directs the query to use the specified port.  The request will
+               contact the management entity reachable through the given port.
+
+       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 access layer provided query
+       of the subnet administrator.  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 ib_guid_pair_t structure
+               -- a pair of GIDs specified through an ib_gid_pair_t structure
+
+

SEE ALSO

+
       ib_query_type_t, ib_pfn_query_cb_t, ib_guid_pair_t,
+       ib_gid_pair_t
+
+
+
+ +

[Functions] +Access Layer/ib_query_srq

+ +

[top][parent][index]

+

NAME

+
       ib_query_srq
+
+

DESCRIPTION

+
       Query the current attributes of the shared receive queue.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_query_srq(
+        IN              const   ib_srq_handle_t FUNC_PTR64                         h_srq,
+                OUT                     ib_srq_attr_t* const                    p_srq_attr );
+
+

PARAMETERS

+
       h_srq
+               [in] A handle to an existing shared receive queue.
+
+       p_srq_attr
+               [out] Upon successful completion of this call, the structure
+               referenced by this parameter contains the attributes of the specified
+               quere pair.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The shared receive queue attributes were returned successfully.
+
+       IB_INVALID_SRQ_HANDLE
+               The shared receive queue handle was invalid.
+
+       IB_INVALID_PARAMETER
+               A reference to the shared receive queue attributes structure was not provided.
+
+

NOTES

+
       This routine returns information about the specified shared receive queue.
+
+

SEE ALSO

+
       ib_query_srq, ib_modify_srq, ib_destroy_srq, ib_srq_attr_t,
+       ib_srq_attr_mask_t, ib_pfn_event_cb_t, ib_qp_attr_t
+
+
+
+ +

[Definitions] +Access Layer/ib_query_type_t

+ +

[top][parent][index]

+

NAME

+
       ib_query_type_t
+
+

DESCRIPTION

+
       Abstracted queries supported by the access layer.
+
+

SYNOPSIS

+
typedef enum _ib_query_type
+{
+        IB_QUERY_USER_DEFINED,
+
+        IB_QUERY_ALL_SVC_RECS,
+        IB_QUERY_SVC_REC_BY_NAME,
+        IB_QUERY_SVC_REC_BY_ID,
+
+        IB_QUERY_CLASS_PORT_INFO,
+
+        IB_QUERY_NODE_REC_BY_NODE_GUID,
+        IB_QUERY_PORT_REC_BY_LID,
+
+        IB_QUERY_VLARB_BY_LID_PORT_BLOCK,
+        IB_QUERY_SLVL_BY_LID_AND_PORTS,
+
+        IB_QUERY_PATH_REC_BY_PORT_GUIDS,
+        IB_QUERY_PATH_REC_BY_GIDS,
+        IB_QUERY_PATH_REC_BY_LIDS,
+
+}       ib_query_type_t;
+
+

VALUES

+
       IB_QUERY_USER_DEFINED
+               Query the SA based on user-defined input.  Queries of this type
+               should reference an ib_user_query_t structure as input into the
+               query.
+
+       IB_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
+               into the query.
+
+       IB_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.
+
+       IB_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.
+
+       IB_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.
+
+       IB_QUERY_PATH_REC_BY_PORT_GUIDS
+               Query for path records between the specified pair of port GUIDs.
+               Queries of this type should reference an ib_guid_pair_t structure
+               that indicates the GUIDs of the path being requested.
+
+       IB_QUERY_PATH_REC_BY_GIDS
+               Query for path records between the specified pair of port GIDs.
+               Queries of this type should reference an ib_gid_pair_t structure
+               that indicates the GIDs of the path being requested.
+
+       IB_QUERY_PATH_REC_BY_LIDS
+               Query for path records between the specified pair of port LIDs.
+               Queries of this type should reference an ib_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 the subnet administrator or a class manager.  These queries are
+       intended to represent those most often used by clients.
+
+

SEE ALSO

+
       ib_query, ib_query_req_t, ib_user_query_t, ib_gid_pair_t, ib_lid_pair_t
+       ib_guid_pair_t
+
+
+
+ +

[Functions] +Access Layer/ib_rearm_cq

+ +

[top][parent][index]

+

NAME

+
       ib_rearm_cq
+
+

DESCRIPTION

+
       This indicates that the completion queue should notify the client when
+       the next completion is added.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_rearm_cq(
+        IN              const   ib_cq_handle_t FUNC_PTR64                          h_cq,
+        IN              const   boolean_t                                       solicited );
+
+

PARAMETERS

+
       h_cq
+               [in] Handle to the completion queue to rearm.
+
+       solicited
+               [in] A flag indicating whether the request is to generate a
+               notification on the next entry, if set to FALSE, or on the next
+               solicited entry being added to the completion queue, if set to TRUE.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The completion queue rearm request was registered successfully.
+
+       IB_INVALID_CQ_HANDLE
+               The completion queue handle was invalid.
+
+

NOTES

+
       This routine instructs the channel interface to invoke the completion
+       handler when the next completion queue entry is added to this CQ.
+
+

SEE ALSO

+
       ib_create_cq, ib_peek_cq, ib_poll_cq, ib_rearm_n_cq
+
+
+
+ +

[Functions] +Access Layer/ib_rearm_n_cq

+ +

[top][parent][index]

+

NAME

+
       ib_rearm_n_cq
+
+

DESCRIPTION

+
       This indicates that the completion queue should notify the client when
+       the next N completions have been added to this CQ.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_rearm_n_cq(
+        IN              const   ib_cq_handle_t FUNC_PTR64                          h_cq,
+        IN              const   uint32_t                                        n_cqes );
+
+

PARAMETERS

+
       h_cq
+               [in] Handle to the completion queue to rearm.
+
+       n_cqes
+               [in] The number of completion queue entries to be added to the
+               completion queue before notifying the client.  This value must
+               greater than or equal to one and less than or equal to the size
+               of the completion queue.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The completion queue rearm request was registered successfully.
+
+       IB_INVALID_CQ_HANDLE
+               The completion queue handle was invalid.
+
+       IB_INVALID_PARAMETER
+               The requested number of completion queue entries was invalid.
+
+       IB_UNSUPPORTED
+               This operation is not supported by the channel adapter.
+
+

NOTES

+
       This routine instructs the channel interface to invoke the completion
+       handler when the next N completions have been added to this CQ regardless
+       of the completion type (solicited or unsolicited).  Any CQ entries that
+       existed before the rearm is enabled will not result in a call to the
+       handler.  Support for this operation is optional by a channel adapter
+       vendor.
+
+

SEE ALSO

+
       ib_create_cq, ib_peek_cq, ib_poll_cq, ib_rearm_cq
+
+
+
+ +

[Functions] +Access Layer/ib_reg_ioc

+ +

[top][parent][index]

+

NAME

+
       ib_reg_ioc
+
+

DESCRIPTION

+
       Registers an I/O controller with the local device manager, which will
+       export the controller to the fabric.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_reg_ioc(
+        IN              const   ib_ioc_handle_t FUNC_PTR64                         h_ioc );
+
+

PARAMETERS

+
       h_ioc
+               [in] A handle to the controller being registered.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The I/O controller was successfully registered.
+
+       IB_INSUFFICIENT_MEMORY
+               There was insufficient memory to register the I/O controller.
+
+       IB_INSUFFICIENT_RESOURCES
+               There were insufficient resources currently available on the I/O
+               unit to register the I/O controller.
+
+       IB_INVALID_HANDLE
+               The I/O controller handle was invalid.
+
+

NOTES

+
       This routine registers an I/O controller with the local device manager.
+       The device manager exports the controller to the fabric as part of an
+       I/O unit.  Typically, clients will call ib_add_svc_entry to add services
+       to the controller before registering it with the device manager.
+
+

SEE ALSO

+
       ib_create_ioc, ib_destroy_ioc, ib_add_svc_entry
+
+
+
+ +

[Functions] +Access Layer/ib_reg_mad_pool

+ +

[top][parent][index]

+

NAME

+
       ib_reg_mad_pool
+
+

DESCRIPTION

+
       Registers a MAD pool for use with a protection domain.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_reg_mad_pool(
+        IN              const   ib_pool_handle_t FUNC_PTR64                        h_pool,
+        IN              const   ib_pd_handle_t FUNC_PTR64                          h_pd,
+                OUT                     ib_pool_key_t FUNC_PTR64* const            p_pool_key );
+
+

PARAMETERS

+
       h_pool
+               [in] A handle to a MAD pool.
+
+       h_pd
+               [in] A handle to a protection domain.
+
+       p_pool_key
+               [out] A key associated with registering the MAD pool with the
+               protection domain.  This key is returned to the user and is used
+               when retrieving MADs from the pool.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The MAD pool was successfully registered with the protection domain.
+
+       IB_INVALID_HANDLE
+               The MAD pool handle was invalid.
+
+       IB_INVALID_PD_HANDLE
+               The protection domain handle was invalid.
+
+       IB_INVALID_PARAMETER
+               A reference to the pool key was not provided.
+
+       IB_INSUFFICIENT_MEMORY
+               There was insufficient memory to register the MAD pool.
+
+       IB_INSUFFICIENT_RESOURCES
+               There were insufficient resources currently available on the channel
+               adapter to register the MAD pool.
+
+

NOTES

+
       This function registers a MAD pool with a protection domain.  After
+       successful completion of this call, the MAD elements of the associated
+       pool are usable on any queue pairs associated with the given protection
+       domain.
+
+

SEE ALSO

+
       ib_create_mad_pool, ib_destroy_mad_pool, ib_dereg_mad_pool, ib_get_mad
+
+
+
+ +

[Functions] +Access Layer/ib_reg_mad_svc

+ +

[top][parent][index]

+

NAME

+
       ib_reg_mad_svc
+
+

DESCRIPTION

+
       Requests management datagram support for a specified class with a
+       queue pair.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_reg_mad_svc(
+        IN              const   ib_qp_handle_t FUNC_PTR64                          h_qp,
+        IN              const   ib_mad_svc_t* const                     p_mad_svc,
+                OUT                     ib_mad_svc_handle_t FUNC_PTR64* const      ph_mad_svc );
+
+

PARAMETERS

+
       h_qp
+               [in] A handle to queue pair.  The queue pair must have been created
+               as one of the following types: IB_QPT_QP0, IB_QPT_QP0_ALIAS,
+               IB_QPT_QP1, IB_QPT_QP1_ALIAS, or IB_QPT_MAD.
+
+       p_mad_svc
+               [in] A reference to the management class and methods supported by
+               this queue pair.
+
+       ph_mad_svc
+               [out] On successful completion of this call, this references a
+               handle to the newly created MAD service.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The queue pair was registered successfully.
+
+       IB_INVALID_QP_HANDLE
+               The queue pair handle was invalid.
+
+       IB_INVALID_PARAMETER
+               The queue pair handle was not created with the proper queue pair
+               type or a reference to the MAD service information or handle was
+               not provided.
+
+       IB_INSUFFICIENT_MEMORY
+               There was insufficient memory to register the queue pair.
+
+

NOTES

+
       This routine registers a queue pair as using a particular management
+       class.  This indicates that the access layer should perform additional
+       processing on MADs sent and received by this queue pair.  Queue pairs
+       registered for MAD support receive access layer SAR and retransmissions
+       services.  A queue pair may be registered for multiple management classes.
+
+

SEE ALSO

+
       ib_create_qp, ib_mad_svc_t
+
+
+
+ +

[Functions] +Access Layer/ib_reg_mem

+ +

[top][parent][index]

+

NAME

+
       ib_reg_mem
+
+

DESCRIPTION

+
       Registers a virtual memory region with a channel adapter.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_reg_mem(
+        IN              const   ib_pd_handle_t FUNC_PTR64                          h_pd,
+        IN              const   ib_mr_create_t* const           p_mr_create,
+                OUT                     net32_t* const                          p_lkey,
+                OUT                     net32_t* const                          p_rkey,
+                OUT                     ib_mr_handle_t FUNC_PTR64* const           ph_mr );
+
+

PARAMETERS

+
       h_pd
+               [in] A handle to an existing protection domain that the memory
+               should be registered with.
+
+       p_mr_create
+               [in] Information describing the memory region to register.
+
+       p_lkey
+               [out] The local access key associated with this registered memory
+               region.
+
+       p_rkey
+               [out] A key that may be used by a remote end-point when performing
+               RDMA or atomic operations to this registered memory region.
+
+       ph_mr
+               [out] Upon successful completion of this call, this references a
+               handle to the registered memory region.  This handle is used when
+               performing data transfers and to deregister the memory.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The memory region was successfully registered.
+
+       IB_INVALID_PD_HANDLE
+               The protection domain to associate with the memory region was invalid.
+
+       IB_INVALID_PARAMETER
+               A reference to the memory region information, lkey, rkey, or handle
+               was not provided.
+
+       IB_INSUFFICIENT_MEMORY
+               There was insufficient memory to register the memory region.
+
+       IB_INSUFFICIENT_RESOURCES
+               There were insufficient resources currently available on the channel
+               adapter to register the memory region.
+
+       IB_UNSUPPORTED
+               The requested access rights are not supported by the channel adapter.
+
+       IB_INVALID_PERMISSION
+               The requested access rights are invalid.
+
+

NOTES

+
       This routine registers a virtual memory region with a channel adapter.
+       Memory must be registered before being used in a data transfer operation.
+
+

SEE ALSO

+
       ib_dereg_mr, ib_reg_phys, ib_reg_shared, ib_mr_create_t
+
+
+
+ +

[Functions] +Access Layer/ib_reg_phys

+ +

[top][parent][index]

+

NAME

+
       ib_reg_phys
+
+

DESCRIPTION

+
       Registers a physical memory region with a channel adapter.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_reg_phys(
+        IN              const   ib_pd_handle_t FUNC_PTR64                          h_pd,
+        IN              const   ib_phys_create_t* const         p_phys_create,
+        IN      OUT                     uint64_t* const                         p_vaddr,
+                OUT                     net32_t* const                          p_lkey,
+                OUT                     net32_t* const                          p_rkey,
+                OUT                     ib_mr_handle_t FUNC_PTR64* const           ph_mr );
+
+

PARAMETERS

+
       h_pd
+               [in] A handle to an existing protection domain that the memory
+               should be registered with.
+
+       p_phys_create
+               [in] Information describing the memory region to register.
+
+       p_vaddr
+               [in/out] On input, references the requested virtual address for the
+               start of the physical region.  On output, references the actual
+               virtual address assigned to the registered region.
+
+       p_lkey
+               [out] The local access key associated with this registered memory
+               region.
+
+       p_rkey
+               [out] A key that may be used by a remote end-point when performing
+               RDMA or atomic operations to this registered memory region.
+
+       ph_mr
+               [out] Upon successful completion of this call, this references a
+               handle to the registered memory region.  This handle is used when
+               performing data transfers and to deregister the memory.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The physical memory region was successfully registered.
+
+       IB_INVALID_PD_HANDLE
+               The protection domain to associate with the physical memory region
+               was invalid.
+
+       IB_INVALID_PARAMETER
+               A reference to the physical memory region information, virtual address,
+               lkey, rkey, or handle was not provided.
+
+       IB_INSUFFICIENT_MEMORY
+               There was insufficient memory to register the physical memory region.
+
+       IB_INSUFFICIENT_RESOURCES
+               There were insufficient resources currently available on the channel
+               adapter to register the physical memory region.
+
+       IB_UNSUPPORTED
+               The requested access rights are not supported by the channel adapter.
+
+       IB_INVALID_PERMISSION
+               The requested access rights are invalid.
+
+

NOTES

+
       This routine registers an array of physical pages as a single virtually
+       contiguous region with a channel adapter.  Memory must be registered
+       before being used in a data transfer operation.
+
+

SEE ALSO

+
       ib_dereg_mr, ib_reg_mem, ib_reg_shared, ib_phys_create_t
+
+
+
+ +

[Functions] +Access Layer/ib_reg_pnp

+ +

[top][parent][index]

+

NAME

+
       ib_reg_pnp
+
+

DESCRIPTION

+
       Routine used to register for notification of local and I/O controller
+       assignment events.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_reg_pnp(
+        IN              const   ib_al_handle_t FUNC_PTR64                          h_al,
+        IN              const   ib_pnp_req_t* const                     p_pnp_req,
+                OUT                     ib_pnp_handle_t FUNC_PTR64* const          ph_pnp );
+
+

PARAMETERS

+
       h_al
+               [in] A handle to an open instance of the access layer.
+
+       p_pnp_req
+               [in] Specifies the type of events that the user wishes to be notified
+               of, along with information needed to process the completed query.
+
+       ph_pnp
+               [out] Upon successful completion of this call, this references a handle
+               to the PnP notification request.  This handle may be used to cancel the
+               notification registration.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The PnP registration was successful.
+
+       IB_INVALID_AL_HANDLE
+               The access layer handle was invalid.
+
+       IB_INVALID_PARAMETER
+               A reference to the PnP request information or handle was not provided.
+
+       IB_INSUFFICIENT_MEMORY
+               There was insufficient memory to register for PnP notification.
+
+

NOTES

+
       This routine registers the calling client with the access layer for
+       notification of locally occurring events, or the assignment of I/O
+       controllers to a local device.  Once registered, a client will receive
+       notification, via a callback, that a given event has occurred on a
+       local device.  Clients may restrict the types of events and devices
+       that are reported.  The p_pnp_req parameter is used to indicate which
+       device events to report to the user.
+
+       Upon invoking this routine, the client may receive a callback through
+       the ib_pfn_pnp_cb_t routine to notify them of the current system state.
+       For example, if a client registers for notification of port up events,
+       then the access layer will notify the client of all available ports when
+       this routine is first invoked.
+
+

SEE ALSO

+
       ib_dereg_pnp, ib_pnp_req_t, ib_pnp_rec_t, ib_pfn_pnp_cb_t
+
+
+
+ +

[Functions] +Access Layer/ib_reg_shared

+ +

[top][parent][index]

+

NAME

+
       ib_reg_shared
+
+

DESCRIPTION

+
       Registers a memory region that has the same physical pages as an
+       existing registered memory region.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_reg_shared(
+        IN              const   ib_mr_handle_t FUNC_PTR64                          h_mr,
+        IN              const   ib_pd_handle_t FUNC_PTR64                          h_pd,
+        IN              const   ib_access_t                                     access_ctrl,
+        IN      OUT                     uint64_t* const                         p_vaddr,
+                OUT                     net32_t* const                          p_lkey,
+                OUT                     net32_t* const                          p_rkey,
+                OUT                     ib_mr_handle_t FUNC_PTR64* const           ph_mr );
+
+

PARAMETERS

+
       h_mr
+               [in] A handle to an existing registered memory region that this
+               registration should share physical pages with.
+
+       h_pd
+               [in] Handle to the PD on which memory is being registered
+
+       access_ctrl
+               [in] Access rights of the registered region.
+
+       p_vaddr
+               [in/out] On input, this specifies the requested virtual address for the
+               start of the physical region.  On output, this references the actual
+               virtual address assigned to the registered region.  This is always a
+               64-bit quantity to support registering more than 4GB of memory on
+               32-bit systems with PAE.
+
+       p_lkey
+               [out] The local access key associated with this registered memory
+               region.
+
+       p_rkey
+               [out] A key that may be used by a remote end-point when performing RDMA
+               or atomic operations to this registered memory region.
+
+       ph_mr
+               [out] Upon successful completion of this call, this references a handle
+               to the registered memory region.  This handle is used when performing
+               data transfers and to deregister the memory.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The shared memory region was successfully registered.
+
+       IB_INVALID_MR_HANDLE
+               The memory region handle was invalid.
+
+       IB_INVALID_PD_HANDLE
+               The protection domain handle was invalid.
+
+       IB_INVALID_PARAMETER
+               A reference to the virtual address, lkey, rkey, or handle was not
+               provided.
+
+       IB_INSUFFICIENT_MEMORY
+               There was insufficient memory to register the shared memory region.
+
+       IB_INSUFFICIENT_RESOURCES
+               There were insufficient resources currently available on the channel
+               adapter to register the shared memory region.
+
+       IB_UNSUPPORTED
+               The requested access rights are not supported by the channel adapter.
+
+       IB_INVALID_PERMISSION
+               The requested access rights are invalid.
+
+

NOTES

+
       This routine registers a memory region that shares the same set of
+       physical pages associated with an existing registered memory region.
+
+

SEE ALSO

+
       ib_dereg_mr, ib_reg_mem, ib_reg_phys, ib_reg_shared, ib_mr_create_t
+
+
+
+ +

[Functions] +Access Layer/ib_reg_shmid

+ +

[top][parent][index]

+

NAME

+
       ib_reg_shmid
+
+

DESCRIPTION

+
       Registers a memory region to be shared across multiple processes.
+       The memory is referenced by a shared memory identifier.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_reg_shmid(
+        IN              const   ib_pd_handle_t FUNC_PTR64                          h_pd,
+        IN              const   ib_shmid_t                                      shmid,
+        IN              const   ib_mr_create_t* const           p_mr_create,
+                OUT                     uint64_t* const                         p_vaddr,
+                OUT                     net32_t* const                          p_lkey,
+                OUT                     net32_t* const                          p_rkey,
+                OUT                     ib_mr_handle_t FUNC_PTR64* const           ph_mr );
+
+

PARAMETERS

+
       h_pd
+               [in] A handle to an existing protection domain that the memory
+               should be registered with.
+
+       shmid
+               [in] An identifier for the shared memory region.
+
+       p_mr_create
+               [in] Information describing the attributes of the memory region to
+               register.
+
+       p_vaddr,
+               [out] The HCA assigned, HCA relative virtual address for the
+               memory region.
+
+       p_lkey
+               [out] The local access key associated with this registered memory
+               region.
+
+       p_rkey
+               [out] A key that may be used by a remote end-point when performing RDMA
+               or atomic operations to this registered memory region.
+
+       ph_mr
+               [out] Upon successful completion of this call, this references a handle
+               to the registered memory region.  This handle is used when performing
+               data transfers and to deregister the memory.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The shared memory region was successfully registered.
+
+       IB_INVALID_PD_HANDLE
+               The protection domain handle was invalid.
+
+       IB_INVALID_PARAMETER
+               A reference to the memory region information, lkey, rkey, or handle
+               was not provided.
+
+       IB_INVALID_SETTING
+               The length and page mapping for the memory region do not match those
+               of the region identified by the provided SHMID.
+
+       IB_INSUFFICIENT_MEMORY
+               There was insufficient memory to register the shared memory region.
+
+       IB_INSUFFICIENT_RESOURCES
+               There were insufficient resources currently available on the channel
+               adapter to register the shared memory region.
+
+       IB_UNSUPPORTED
+               The requested access rights are not supported by the channel adapter.
+
+       IB_INVALID_PERMISSION
+               The requested access rights are invalid.
+
+

NOTES

+
       This routine registers a memory region that is shared between processes.
+       The region being registered is identified through a shared memory
+       identifier.  The registered region shares hardware resources as much
+       as possible.
+
+

SEE ALSO

+
       ib_dereg_mr, ib_reg_mem, ib_reg_shared, ib_mr_create_t
+
+
+
+ +

[Functions] +Access Layer/ib_reg_svc

+ +

[top][parent][index]

+

NAME

+
       ib_reg_svc
+
+

DESCRIPTION

+
       Routine used to register for a service with the subnet administrator.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_reg_svc(
+        IN              const   ib_al_handle_t FUNC_PTR64                          h_al,
+        IN              const   ib_reg_svc_req_t* const         p_reg_svc_req,
+                OUT                     ib_reg_svc_handle_t* const      ph_reg_svc );
+
+

PARAMETERS

+
       h_al
+               [in] A handle to an open instance of the access layer.
+
+       p_reg_svc_req
+               [in] Describes the service to register with the subnet administrator.
+
+       ph_reg_svc
+               [out] Pointer to a service registration handle, used to deregister
+               the service.  Set upon successful completion of the function.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The service registration was initiated.
+
+       IB_INVALID_AL_HANDLE
+               The access layer handle was invalid.
+
+       IB_INVALID_PARAMETER
+               A reference to the service registration request was not provided.
+
+       IB_INSUFFICIENT_MEMORY
+               There was insufficient memory to perform the operation.
+
+       IB_NOT_FOUND
+               No channel adapters in the system contain the GID specified in the
+               service record.
+
+       IB_INVALID_GID
+               No port was found matching the GID specified in the service record.
+
+       IB_INSUFFICIENT_RESOURCES
+               There were insufficient resources currently available on the channel
+               adapter to perform the operation.
+
+

NOTES

+
       This routine registers a service with the subnet administrator.  Registered
+       services are reported by the subnet administrator to clients querying the
+       subnet administrator for service information.
+
+       Once registered, a client will receive notification, via a callback,
+       that a service has been successfully registered.
+
+

SEE ALSO

+
       ib_dereg_svc, ib_reg_svc_req_t
+
+
+
+ +

[Structures] +Access Layer/ib_reg_svc_rec_t

+ +

[top][parent][index]

+

NAME

+
       _ib_reg_svc_rec_t
+
+

DESCRIPTION

+
       Information returned as a result of registering a service with the subnet
+       administrator.  This includes name service registration.
+
+

SYNOPSIS

+
typedef struct _ib_reg_svc_rec
+{
+ TO_LONG_PTR(       const void* ,                     svc_context) ; 
+        ib_reg_svc_handle_t                     h_reg_svc;
+        ib_api_status_t                         req_status;
+        ib_net16_t                                      resp_status;
+        ib_service_record_t                     svc_rec;
+
+}       ib_reg_svc_rec_t;
+
+

FIELDS

+
       svc_context
+               User-defined context information associated with the registration
+               through the ib_reg_svc call.
+
+       req_status
+               Indicates the success of the registration operation.
+
+       resp_status
+               Indicates the status of the response from the SA
+
+       h_reg_svc
+               For successful queries, this references the first record of
+               information returned by the subnet administrator.  If multiple
+               records of information were returned, the ib_reg_svc_rec_t will
+               be chained together.
+
+       svc_rec
+               The service record returned by the SA for the registered service.
+
+

NOTES

+
       A query result structure is returned to a client through their
+       ib_pfn_query_cb_t routine to notify them of the results of a subnet
+       administration query.
+
+

SEE ALSO

+
       ib_reg_svc, ib_pfn_reg_svc_cb_t, ib_reg_svc_status_t
+
+
+
+ +

[Structures] +Access Layer/ib_reg_svc_req_t

+ +

[top][parent][index]

+

NAME

+
       ib_reg_svc_req_t
+
+

DESCRIPTION

+
       Information used to request that a service be registered with the subnet
+       administrator.
+
+

SYNOPSIS

+
typedef struct _ib_reg_svc_req
+{
+        ib_service_record_t                     svc_rec;
+        ib_net64_t                                      port_guid;
+
+        uint32_t                                        timeout_ms;
+        uint32_t                                        retry_cnt;
+        ib_al_flags_t                           flags;
+
+        const void                                      *svc_context;
+        ib_net64_t                                      svc_data_mask;
+
+        ib_pfn_reg_svc_cb_t                     pfn_reg_svc_cb;
+
+}       ib_reg_svc_req_t;
+
+

FIELDS

+
       svc_rec
+               Service record that describes the service being registered.
+
+       port_guid
+               Directs the registration to use the specified port.  The request will
+               contact the management entity reachable through the given port.
+
+       timeout_ms
+               Specifies the number of milliseconds to wait for a response for
+               the registration until retrying or timing out the request.
+
+       retry_cnt
+               Specifies the number of times that the registration 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.
+
+       svc_context
+               User-defined context information associated with this registration
+               request.  This context is returned to the user through the function
+               specified by the pfn_reg_svc_cb field.
+
+       svc_data_mask
+               User-defined component mask indicating which parts of the private
+               data is populated. This is used as an extension to the svc_id
+               for data compare. Also used as a cheap way to communicate data
+               to all clients for this service.
+
+       pfn_reg_svc_cb
+               A user-defined callback that is invoked upon completion of the
+               registration request.
+
+

NOTES

+
       This structure is used to register a service with the subnet administrator.
+       The registration call operates asynchronously unless the flags field is
+       set to IB_FLAGS_SYNC.  If synchronous operation is indicated, the client
+       will receive a callback with the results of the registration attempt
+       before the ib_reg_svc call returns.  Synchronous operation results in
+       the calling thread blocking.
+
+

SEE ALSO

+
       ib_reg_svc, ib_svc_rec_t, ib_pfn_reg_svc_cb_t
+
+
+
+ +

[Structures] +Access Layer/ib_rej_pdata_t

+ +

[top][parent][index]

+

NAME

+
       ib_rej_pdata_t
+
+

DESCRIPTION

+
       User data sent as part of a connection reject message.
+
+

SYNOPSIS

+
typedef union _ib_rej_pdata
+{
+        uint8_t                                         data[IB_REJ_PDATA_SIZE];
+
+}       ib_rej_pdata_t;
+
+

SEE ALSO

+
       ib_cm_data_sizes_t
+
+
+
+ +

[Functions] +Access Layer/ib_reject_ioc

+ +

[top][parent][index]

+

NAME

+
       ib_reject_ioc
+
+

DESCRIPTION

+
       Rejects an I/O controller assignment to a host.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_reject_ioc(
+        IN              const   ib_al_handle_t FUNC_PTR64                          h_al,
+        IN              const   ib_pnp_handle_t FUNC_PTR64                         h_ioc_event );
+
+

PARAMETERS

+
       h_al
+               [in] A handle to an open instance of the access layer.
+
+       h_ioc_event
+               [in] A handle provided as part of the notification of an I/O controller
+               being assigned.  This handle is obtained through the ib_pnp_rec_t
+               structure given to a client through their ib_pfn_pnp_cb_t callback.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The I/O controller reject request was initiated.
+
+       IB_INVALID_AL_HANDLE
+               The access layer handle was invalid.
+
+       IB_INVALID_HANDLE
+               The I/O controller handle was invalid.
+
+       IB_INSUFFICIENT_MEMORY
+               There was insufficient memory to perform the operation.
+
+       IB_INSUFFICIENT_RESOURCES
+               There were insufficient resources currently available on the channel
+               adapter to perform the operation.
+
+

NOTES

+
       This routine rejects an I/O controller assigned by the configuration
+       manager to the local host.  The access layer sends a rejection notification
+       to the configuration manager and disable access to the controller from
+       the local host.  This routine must be called from a client's
+       ib_pfn_pnp_cb_t callback to reject a newly assigned I/O controller.
+
+

SEE ALSO

+
       ib_pfn_pnp_cb_t, ib_pnp_rec_t
+
+
+
+ +

[Functions] +Access Layer/ib_remove_svc_entry

+ +

[top][parent][index]

+

NAME

+
       ib_remove_svc_entry
+
+

DESCRIPTION

+
       This removes a service entry from an I/O controller.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_remove_svc_entry(
+        IN              const   ib_svc_handle_t FUNC_PTR64                         h_svc );
+
+

PARAMETERS

+
       h_svc
+               [in] A handle to an existing service entry.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The service entry was successfully removed.
+
+       IB_INVALID_HANDLE
+               The service entry handle was invalid.
+
+

NOTES

+
       This routine removes the specified service from its associated I/O
+       controller.  Once removed, the service information will no longer be
+       exported along with the controller.
+
+

SEE ALSO

+
       ib_add_svc_entry
+
+
+
+ +

[Structures] +Access Layer/ib_rep_pdata_t

+ +

[top][parent][index]

+

NAME

+
       ib_rep_pdata_t
+
+

DESCRIPTION

+
       User data sent as part of a reply to a request for communication.
+
+

SYNOPSIS

+
typedef union _ib_rep_pdata
+{
+        uint8_t                                         data[IB_REP_PDATA_SIZE];
+
+}       ib_rep_pdata_t;
+
+

SEE ALSO

+
       ib_cm_data_sizes_t
+
+
+
+ +

[Structures] +Access Layer/ib_report_rec_t

+ +

[top][parent][index]

+

NAME

+
       ib_report_rec_t
+
+

DESCRIPTION

+
       Reported event information returned to the user when a subscribed for
+       event occurs.
+
+

SYNOPSIS

+
typedef struct _ib_report_rec
+{
+ TO_LONG_PTR(       const void* ,                             report_context) ; 
+ TO_LONG_PTR(       ib_mad_notice_attr_t* ,   p_notice) ; 
+
+}       ib_report_rec_t;
+
+

FIELDS

+
       report_context
+               Client-defined context information specified when registering for
+               the report.
+
+       p_notice
+               Reported information that describes the event that has occurred.
+
+

NOTES

+
       Subscription for reported events is done through a class manager.  When
+       a class manager detects that such an event occurs, it will generate a
+       report to the subscribed client.  The reported information is referenced
+       through the p_notice field.
+
+

SEE ALSO

+
       ib_mad_notice_attr_t
+
+
+
+ +

[Structures] +Access Layer/ib_req_pdata_t

+ +

[top][parent][index]

+

NAME

+
       ib_req_pdata_t
+
+

DESCRIPTION

+
       User data sent as part of a request for communication.
+
+

SYNOPSIS

+
typedef union _ib_req_pdata
+{
+        uint8_t                                         data[IB_REQ_PDATA_SIZE];
+
+}       ib_req_pdata_t;
+
+

SEE ALSO

+
       ib_cm_data_sizes_t
+
+
+
+ +

[Functions] +Access Layer/ib_rereg_mem

+ +

[top][parent][index]

+

NAME

+
       ib_rereg_mem
+
+

DESCRIPTION

+
       Modifies the attributes of an existing memory region.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_rereg_mem(
+        IN              const   ib_mr_handle_t FUNC_PTR64                          h_mr,
+        IN              const   ib_mr_mod_t                                     mr_mod_mask,
+        IN              const   ib_mr_create_t* const           p_mr_create OPTIONAL,
+                OUT                     net32_t* const                          p_lkey,
+                OUT                     net32_t* const                          p_rkey,
+        IN              const   ib_pd_handle_t FUNC_PTR64                          h_pd OPTIONAL );
+
+

PARAMETERS

+
       h_mr
+               [in] A handle to the registered memory region being modified.
+
+       mr_mod_mask
+               [in] A mask used to specify which attributes of the memory region are
+               being modified.
+
+       p_mr_create
+               [in] This references information needed to perform the modification on
+               the registered memory region.  This parameter may be NULL if only the
+               protection domain will be modified.
+
+       p_lkey
+               [out] The local access key associated with this registered memory
+               region.
+
+       p_rkey
+               [out] A key that may be used by a remote end-point when performing RDMA
+               or atomic operations to this registered memory region.
+
+       h_pd
+               [in] An optionally provided parameter used to modify the protection
+               domain of a registered region.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The memory region attributes were modified successfully.
+
+       IB_INVALID_MR_HANDLE
+               The memory region handle was invalid.
+
+       IB_INVALID_PARAMETER
+               A reference to the lkey or rkey was not provided or the specified
+               modify mask is invalid.
+
+       IB_INVALID_SETTING
+               The specified memory region attributes are invalid.
+
+       IB_INVALID_PD_HANDLE
+               The protection domain handle was invalid.
+
+       IB_INSUFFICIENT_RESOURCES
+               There were insufficient resources currently available on the channel
+               adapter to modify the memory region.
+
+       IB_UNSUPPORTED
+               The requested access rights are not supported by the channel adapter.
+
+       IB_INVALID_PERMISSION
+               The requested access rights are invalid.
+
+       IB_RESOURCE_BUSY
+               The memory region has windows bound to it.
+
+

NOTES

+
       This routine modifies the attributes of the specified memory region.
+       The memory being modified may have been registered using either virtual
+       or physical registration.  Conceptually, this routine is equivalent to
+       to calling ib_dereg_mr, followed by ib_reg_mem, but may be higher
+       performing.
+
+

SEE ALSO

+
       ib_reg_mem, ib_reg_phys, ib_dereg_mr, ib_mr_mod_t, ib_mr_create_t
+
+
+
+ +

[Functions] +Access Layer/ib_rereg_phys

+ +

[top][parent][index]

+

NAME

+
       ib_rereg_phys
+
+

DESCRIPTION

+
       Modifies the attributes of an existing memory region.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_rereg_phys(
+        IN              const   ib_mr_handle_t FUNC_PTR64                          h_mr,
+        IN              const   ib_mr_mod_t                                     mr_mod_mask,
+        IN              const   ib_phys_create_t* const         p_phys_create OPTIONAL,
+        IN      OUT                     uint64_t* const                         p_vaddr,
+                OUT                     net32_t* const                          p_lkey,
+                OUT                     net32_t* const                          p_rkey,
+        IN              const   ib_pd_handle_t FUNC_PTR64                          h_pd OPTIONAL );
+
+

PARAMETERS

+
       h_mr
+               [in] A handle to the registered memory region being modified.
+
+       mr_mod_mask
+               [in] A mask used to specify which attributes of the memory region are
+               being modified.
+
+       p_phys_create
+               [in] This references information needed to perform the modification on
+               the registered memory region.  This parameter may be NULL if
+               only the protection domain will be modified.
+
+       p_vaddr
+               [in/out] On input, this specifies the requested virtual address for the
+               start of the physical region.  On output, this references the actual
+               virtual address assigned to the registered region.
+
+       p_lkey
+               [out] The local access key associated with this registered memory
+               region.
+
+       p_rkey
+               [out] A key that may be used by a remote end-point when performing RDMA
+               or atomic operations to this registered memory region.
+
+       h_pd
+               [in] An optionally provided parameter used to modify the protection
+               domain of a registered region.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The memory region attributes were modified successfully.
+
+       IB_INVALID_MR_HANDLE
+               The memory region handle was invalid.
+
+       IB_INVALID_PARAMETER
+               A reference to the virtual address, lkey, rkey was not provided or
+               the specified modify mask is invalid.
+
+       IB_INVALID_SETTING
+               The specified memory region attributes are invalid.
+
+       IB_INVALID_PD_HANDLE
+               The protection domain handle was invalid.
+
+       IB_INSUFFICIENT_RESOURCES
+               There were insufficient resources currently available on the channel
+               adapter to modify the memory region.
+
+       IB_UNSUPPORTED
+               The requested access rights are not supported by the channel adapter.
+
+       IB_INVALID_PERMISSION
+               The requested access rights are invalid.
+
+       IB_RESOURCE_BUSY
+               The memory region has windows bound to it.
+
+

NOTES

+
       This routine modifies the attributes of the specified memory region.
+       The memory being modified may have been registered using either virtual
+       or physical registration.  Conceptually, this routine is equivalent to
+       to calling ib_dereg_mr, followed by ib_reg_phys, but may be higher
+       performing.
+
+

SEE ALSO

+
       ib_reg_mem, ib_reg_phys, ib_dereg_mr, ib_mr_mod_t, ib_mr_create_t
+
+
+
+ +

[Structures] +Access Layer/ib_rtu_pdata_t

+ +

[top][parent][index]

+

NAME

+
       ib_rtu_pdata_t
+
+

DESCRIPTION

+
       User data sent as part of a ready to use message.
+
+

SYNOPSIS

+
typedef union _ib_rtu_pdata
+{
+        uint8_t                                         data[IB_RTU_PDATA_SIZE];
+
+}       ib_rtu_pdata_t;
+
+

SEE ALSO

+
       ib_cm_data_sizes_t
+
+
+
+ +

[Functions] +Access Layer/ib_send_mad

+ +

[top][parent][index]

+

NAME

+
       ib_send_mad
+
+

DESCRIPTION

+
       This routine posts a work request to the send queue of a queue pair.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_send_mad(
+        IN              const   ib_mad_svc_handle_t FUNC_PTR64                     h_mad_svc,
+        IN                              ib_mad_element_t* const         p_mad_element_list,
+                OUT                     ib_mad_element_t                        **pp_mad_failure OPTIONAL );
+
+

PARAMETERS

+
       h_mad_svc
+               [in] The MAD service to which this work request is being submitted.
+
+       p_mad_element_list
+               [in] A list of MAD elements that will be posted to the send queue.
+
+       pp_mad_failure
+               [out] If the send MAD operation failed, this references the MAD
+               element in the p_mad_element_list where the first failure occurred.
+               This parameter is optional if p_mad_element_list contains a single
+               MAD.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The MAD element list was successfully posted.
+
+       IB_INVALID_HANDLE
+               The MAD service handle was invalid.
+
+       IB_INVALID_PARAMETER
+               A reference to the MAD element list was not provided.
+
+       IB_INSUFFICIENT_RESOURCES
+               There were insufficient resources currently available to complete
+               the request.
+
+       IB_INVALID_SETTING
+               The MAD element RMPP version is not supported by the access layer.
+
+       IB_INSUFFICIENT_MEMORY
+               There was insufficient memory to complete the request.
+
+

NOTES

+
       This routine posts a work request to send a MAD on a MAD service.  All
+       MAD elements successfully posted by this call are under the control of
+       the access layer and should not be accessed until the send operation
+       completes.
+
+       In order to guarantee that MADs sent by separate clients do not use the
+       same transaction ID, the access layer reserves the upper 32-bits of the
+       TID on all unsolicited MADs.  MADs sent with the response bit set will
+       not have their transaction ID's modified.  Unsolicited MADs will have the
+       upper 32-bits of their TID set to an access layer generated client ID.
+
+

SEE ALSO

+
       ib_mad_element_t, ib_cancel_mad
+
+
+
+ +

[Structures] +Access Layer/ib_shmid_t

+ +

[top][parent][index]

+

NAME

+
       ib_shmid_t
+
+

DESCRIPTION

+
       Shared Memory Identifier, used to uniquely identify a shared memory region.
+
+

SYNOPSIS

+
typedef uint8_t         ib_shmid_t[64];
+
+

SEE ALSO

+
       ib_reg_shmid
+
+
+
+ +

[Structures] +Access Layer/ib_sidr_rep_pdata_t

+ +

[top][parent][index]

+

NAME

+
       ib_sidr_rep_pdata_t
+
+

DESCRIPTION

+
       User data sent as part of a service ID resolution reply.
+
+

SYNOPSIS

+
typedef union _ib_sidr_rep_pdata
+{
+        uint8_t                                         data[IB_SIDR_REP_PDATA_SIZE];
+
+}       ib_sidr_rep_pdata_t;
+
+

SEE ALSO

+
       ib_cm_data_sizes_t
+
+
+
+ +

[Structures] +Access Layer/ib_sidr_req_pdata_t

+ +

[top][parent][index]

+

NAME

+
       ib_sidr_req_pdata_t
+
+

DESCRIPTION

+
       User data sent as part of a service ID resolution request.
+
+

SYNOPSIS

+
typedef union _ib_sidr_req_pdata
+{
+        uint8_t                                         data[IB_SIDR_REQ_PDATA_SIZE];
+
+}       ib_sidr_req_pdata_t;
+
+

SEE ALSO

+
       ib_cm_data_sizes_t
+
+
+
+ +

[Structures] +Access Layer/ib_sub_rec_t

+ +

[top][parent][index]

+

NAME

+
       ib_sub_rec_t
+
+

DESCRIPTION

+
       Information returned to a user that indicates the result of a subscription
+       request.
+
+

SYNOPSIS

+
typedef struct _ib_sub_rec
+{
+ TO_LONG_PTR(       const void* ,                     sub_context) ; 
+        ib_api_status_t                         status;
+        ib_sub_handle_t __ptr64                         h_sub;
+
+}       ib_sub_rec_t;
+
+

FIELDS

+
       sub_context
+               References user-defined context information associated with the
+               subscription request.  This field is set by the user through the
+               ib_subscribe routine.
+
+       status
+               Indicates the success of the subscription request.
+
+       h_sub
+               The handle to the subscription request that was returned to the user
+               from the ib_subscribe call.  This handle is provided to the user to
+               avoid a race condition between the return of the ib_subscribe routine
+               and the notification of an event.
+
+

NOTES

+
       This structure is returned to the user to notify them of the results
+       of a subscription request.  After successfully subscribing with a
+       class manager for an event, this structure will be returned to the user
+       with the status set to IB_SUCCESS.  The sub_context field will be set
+       to the context specified through the p_sub_req parameter in the
+       ib_subscribe routine.
+
+

SEE ALSO

+
       ib_subscribe
+
+
+
+ +

[Structures] +Access Layer/ib_sub_req_t

+ +

[top][parent][index]

+

NAME

+
       ib_sub_req_t
+
+

DESCRIPTION

+
       Information used to subscribed for event notification from a class
+       manager.
+
+

SYNOPSIS

+
typedef struct _ib_sub_req
+{
+ TO_LONG_PTR(       ib_svc_name_t* ,          p_class_mgr_name) ; 
+ TO_LONG_PTR(       ib_inform_info_t* ,       p_inform_info) ; 
+        ib_net64_t                                      port_guid;
+
+        uint32_t                                        timeout_ms;
+        uint32_t                                        retry_cnt;
+        ib_al_flags_t                           flags;
+
+ TO_LONG_PTR(       const void* ,                     sub_context) ; 
+        ib_pfn_sub_cb_t                         pfn_sub_cb;
+
+ TO_LONG_PTR(       const void* ,                     report_context) ; 
+        ib_pfn_report_cb_t                      pfn_report_cb;
+
+}       ib_sub_req_t;
+
+

FIELDS

+
       p_class_mgr_name
+               The service name of the class manager to subscribe for events with.
+
+       p_inform_info
+               Information describing the type of event being subscribed to.
+
+       port_guid
+               Directs the subscription request to use the specified port.  The
+               request will contact the subnet administrator reachable through the
+               given port.
+
+       timeout_ms
+               Specifies the number of milliseconds to wait for a response for
+               this subscription 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.
+
+       sub_context
+               User-defined context information associated with this subscription
+               request.  This context is returned to the user through the function
+               specified by the pfn_sub_cb field.
+
+       pfn_sub_cb
+               A user-defined callback that is invoked upon completion of the
+               subscription request.  This is used to notify a client that of the
+               result of their subscription request.
+
+       report_context
+               User-defined context information associated with this subscription.
+               This context is returned to the user through the client's
+               ib_pfn_report_cb_t callback routine specified in ib_open_al.
+
+       pfn_report_cb
+               A user-defined callback that is invoked to notify the user that an
+               event report has been received.
+
+

NOTES

+
       This structure is used to subscribe for events with a class manager.  Both
+       the subscription request and any corresponding event notifications operate
+       asynchronously.  Clients will be notified of the result of their
+       subscription request before receiving notification of associated events.
+
+

SEE ALSO

+
       ib_subscribe, ib_svc_name_t, ib_inform_info_t, ib_pfn_sub_cb_t,
+       ib_pfn_report_cb_t, ib_open_al
+
+
+
+ +

[Functions] +Access Layer/ib_subscribe

+ +

[top][parent][index]

+

NAME

+
       ib_subscribe
+
+

DESCRIPTION

+
       Subscribe with a class manager for event notification.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_subscribe(
+        IN              const   ib_al_handle_t FUNC_PTR64                          h_al,
+        IN              const   ib_sub_req_t* const                     p_sub_req,
+                OUT                     ib_sub_handle_t FUNC_PTR64* const          ph_sub );
+
+

PARAMETERS

+
       h_al
+               [in] A handle to an open instance of the access layer.
+
+       p_sub_req
+               [in] Specifies the type of events that the user wishes to be
+               notified of, along with information needed to process the completed
+               subscription.
+
+       ph_sub
+               [out] Upon successful completion of this call, this references a handle
+               to the subscription request.  This handle may be used to unsubscribe
+               from the events.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The subscription request was initiated.
+
+       IB_INVALID_AL_HANDLE
+               The access layer handle was invalid.
+
+       IB_INVALID_PARAMETER
+               A reference to the subscription request or handle was not provided.
+
+       IB_INSUFFICIENT_MEMORY
+               There was insufficient memory to perform the operation.
+
+       IB_INVALID_GUID
+               No port was found for the port_guid specified in the request.
+
+       IB_INSUFFICIENT_RESOURCES
+               There were insufficient resources currently available on the channel
+               adapter to perform the operation.
+
+

NOTES

+
       This routine registers the calling client with a class manager for
+       notification of events.  Once registered, a client will receive
+       notification, via a callback, that a given event has occurred on
+       a device managed by the class manager.
+
+

SEE ALSO

+
       ib_unsubscribe, ib_sub_req_t, ib_pfn_sub_cb_t, ib_pfn_report_cb_t
+
+
+
+ +

[Functions] +Access Layer/ib_sync_destroy

+ +

[top][parent][index]

+

NAME

+
       ib_sync_destroy
+
+

DESCRIPTION

+
       Access layer routine used to indicate synchronous destruction of an
+       object.
+
+

SYNOPSIS

+
static const ib_pfn_destroy_cb_t ib_sync_destroy = (ib_pfn_destroy_cb_t)-1i64;
+
+

PARAMETERS

+
       Not Applicable.
+
+

NOTES

+
       Users specify ib_sync_destroy as the ib_pfn_destroy_cb_t callback in order
+       to force synchronous object destruction.  This may result in the calling
+       thread blocking while outstanding callbacks complete.
+
+

SEE ALSO

+
       ib_pfn_destroy_cb_t
+
+
+
+ +

[Functions] +Access Layer/ib_unsubscribe

+ +

[top][parent][index]

+

NAME

+
       ib_unsubscribe
+
+

DESCRIPTION

+
       Unsubscribe with a class manager for event notification.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+ib_unsubscribe(
+        IN              const   ib_sub_handle_t FUNC_PTR64                         h_sub,
+        IN              const   ib_pfn_destroy_cb_t                     pfn_destroy_cb OPTIONAL );
+
+

PARAMETERS

+
       h_al
+               [in] A handle to an open instance of the access layer.
+
+       h_sub
+               [in] A handle to a subscribed event.
+
+       pfn_destroy_cb
+               [in] A user-specified callback that is invoked after the subscription
+               request has been successfully canceled.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The unsubscribe request was initiated.
+
+       IB_INVALID_HANDLE
+               The subscription handle was invalid.
+
+       IB_INVALID_PARAMETER
+               A reference to the subscription request or handle was not provided.
+
+       IB_INSUFFICIENT_MEMORY
+               There was insufficient memory to perform the operation.
+
+       IB_INSUFFICIENT_RESOURCES
+               There were insufficient resources currently available on the channel
+               adapter to perform the operation.
+
+

NOTES

+
       This routine cancels an active or pending event subscription with a class
+       manager.  To avoid a race condition canceling a subscription at the same
+       time an event notification callback is in progress, the unsubscribe
+       operation operates asynchronously.  For additional details see
+       ib_pfn_destroy_cb_t.
+
+

SEE ALSO

+
       ib_subscribe, ib_pfn_destroy_cb_t
+
+
+
+ +

[Structures] +Access Layer/ib_user_query_t

+ +

[top][parent][index]

+

NAME

+
       ib_user_query_t
+
+

DESCRIPTION

+
       User-defined query information.
+
+

SYNOPSIS

+
typedef struct _ib_user_query
+{
+        uint8_t                                 method;
+        ib_net16_t                              attr_id;
+        uint32_t                                attr_size;
+        ib_net64_t                              comp_mask;
+ TO_LONG_PTR(       void* ,                   p_attr) ; 
+
+}       ib_user_query_t;
+
+

FIELDS

+
       method
+               Method to be run
+
+       attr_id
+               Attribute identifier of query data.
+
+       attr_size
+               Size of the query attribute in bytes.  This is translated into the
+               attr_offset field of the SA MAD by the ib_query call.
+
+       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

+
       ib_query_type_t, ib_query, ib_get_attr_offset, ib_get_attr_size
+
+
+
+ +

[Functions] +Access Layer/mlnx_create_fmr

+ +

[top][parent][index]

+

NAME

+
       mlnx_create_fmr
+
+

DESCRIPTION

+
       Creates a Mellanox fast memory region.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+mlnx_create_fmr(
+        IN              const   ib_pd_handle_t FUNC_PTR64                          h_pd,
+        IN              const   mlnx_fmr_create_t* const        p_fmr_create,
+                OUT                     mlnx_fmr_handle_t FUNC_PTR64* const        ph_fmr );
+
+

PARAMETERS

+
       h_pd
+               [in] An optionally provided parameter used to modify the protection
+               domain of a registered region.
+       p_fmr_create
+               [in] This references information needed to perform the modification on
+               the registered memory region.  This parameter may be NULL if only the
+               protection domain will be modified.
+       ph_fmr
+               [out] A handle to the registered memory region being modified.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The memory region attributes were modified successfully.
+
+       IB_INVALID_MR_HANDLE
+               The memory region handle was invalid.
+
+       IB_INVALID_PARAMETER
+               A reference to the lkey or rkey was not provided or the specified
+               modify mask is invalid.
+
+       IB_INVALID_SETTING
+               The specified memory region attributes are invalid.
+
+       IB_INVALID_PD_HANDLE
+               The protection domain handle was invalid.
+
+       IB_INSUFFICIENT_RESOURCES
+               There were insufficient resources currently available on the channel
+               adapter to modify the memory region.
+
+       IB_UNSUPPORTED
+               The requested access rights are not supported by the channel adapter.
+
+       IB_INVALID_PERMISSION
+               The requested access rights are invalid.
+
+       IB_RESOURCE_BUSY
+               The memory region has windows bound to it.
+
+

NOTES

+
       This is a Mellanox specific extension to verbs.
+
+

SEE ALSO

+
       mlnx_destroy_fmr, mlnx_fmr_create_t
+
+
+
+ +

[Functions] +Access Layer/mlnx_destroy_fmr

+ +

[top][parent][index]

+

NAME

+
       mlnx_destroy_fmr
+
+

DESCRIPTION

+
       Destroys an existing Mellanox fast memory region.
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+mlnx_destroy_fmr(
+        IN              const   mlnx_fmr_handle_t FUNC_PTR64                       h_fmr );
+
+

PARAMETERS

+
       h_fmr
+               [in] A handle to the registered memory region being modified.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The memory region attributes were modified successfully.
+
+       IB_INVALID_MR_HANDLE
+               The memory region handle was invalid.
+
+       IB_INVALID_PARAMETER
+               A reference to the lkey or rkey was not provided or the specified
+               modify mask is invalid.
+
+       IB_INVALID_SETTING
+               The specified memory region attributes are invalid.
+
+       IB_INVALID_PD_HANDLE
+               The protection domain handle was invalid.
+
+       IB_INSUFFICIENT_RESOURCES
+               There were insufficient resources currently available on the channel
+               adapter to modify the memory region.
+
+       IB_UNSUPPORTED
+               The requested access rights are not supported by the channel adapter.
+
+       IB_INVALID_PERMISSION
+               The requested access rights are invalid.
+
+       IB_RESOURCE_BUSY
+               The memory region has windows bound to it.
+
+

NOTES

+
       This is a Mellanox specific extension to verbs.
+
+

SEE ALSO

+
       mlnx_destroy_fmr, mlnx_fmr_create_t
+
+
+
+ +

[Functions] +Access Layer/mlnx_map_fmr

+ +

[top][parent][index]

+

NAME

+
       mlnx_map_fmr
+
+

DESCRIPTION

+
       //TODO
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+mlnx_map_phys_fmr(
+        IN              const   mlnx_fmr_handle_t FUNC_PTR64                       h_fmr,
+        IN              const   uint64_t* const                         paddr_list,
+        IN              const   int                                                     list_len,
+        IN      OUT                     uint64_t* const                         p_vaddr,
+                OUT                     net32_t* const                          p_lkey,
+                OUT                     net32_t* const                          p_rkey );
+
+

PARAMETERS

+
       h_fmr
+               [in] Handle to the fast memory region that  these pages map to 
+       page_list
+               [in] array of phys address
+       list_len
+               [in] number of pages in the list
+       p_vaddr
+               [in/out] On input, references the requested virtual address for the
+               start of the FMR.  On output, references the actual
+               virtual address assigned to the FMR.
+       p_lkey
+               [out] The local access key associated with this registered memory
+               region.
+       p_rkey
+               [out] A key that may be used by a remote end-point when performing
+               RDMA or atomic operations to this registered memory region.
+
+ RETURN VALUES
+       IB_SUCCESS
+               The memory region attributes were modified successfully.
+
+       IB_INVALID_MR_HANDLE
+               The memory region handle was invalid.
+
+       IB_INVALID_PARAMETER
+               A reference to the lkey or rkey was not provided or the specified
+               modify mask is invalid.
+
+       IB_INVALID_SETTING
+               The specified memory region attributes are invalid.
+
+       IB_INVALID_PD_HANDLE
+               The protection domain handle was invalid.
+
+       IB_INSUFFICIENT_RESOURCES
+               There were insufficient resources currently available on the channel
+               adapter to modify the memory region.
+
+       IB_UNSUPPORTED
+               The requested access rights are not supported by the channel adapter.
+
+       IB_INVALID_PERMISSION
+               The requested access rights are invalid.
+
+       IB_RESOURCE_BUSY
+               The memory region has windows bound to it.
+
+

NOTES

+
       This is a Mellanox specific extension to verbs.
+
+

SEE ALSO

+
       mlnx_destroy_fmr, mlnx_fmr_create_t
+
+
+
+ +

[Functions] +Access Layer/mlnx_unmap_fmr

+ +

[top][parent][index]

+

NAME

+
       mlnx_unmap_fmr
+
+

DESCRIPTION

+
       //TODO
+
+

SYNOPSIS

+
AL_EXPORT ib_api_status_t AL_API
+mlnx_unmap_fmr(
+        IN              const   mlnx_fmr_handle_t FUNC_PTR64                       h_fmr );
+
+

PARAMETERS

+
       h_fmr
+
+ RETURN VALUES
+       IB_SUCCESS
+               The memory region attributes were modified successfully.
+
+       IB_INVALID_MR_HANDLE
+               The memory region handle was invalid.
+
+       IB_INVALID_PARAMETER
+               A reference to the lkey or rkey was not provided or the specified
+               modify mask is invalid.
+
+       IB_INVALID_SETTING
+               The specified memory region attributes are invalid.
+
+       IB_INVALID_PD_HANDLE
+               The protection domain handle was invalid.
+
+       IB_INSUFFICIENT_RESOURCES
+               There were insufficient resources currently available on the channel
+               adapter to modify the memory region.
+
+       IB_UNSUPPORTED
+               The requested access rights are not supported by the channel adapter.
+
+       IB_INVALID_PERMISSION
+               The requested access rights are invalid.
+
+       IB_RESOURCE_BUSY
+               The memory region has windows bound to it.
+
+

NOTES

+
       This is a Mellanox specific extension to verbs.
+
+

SEE ALSO

+
       mlnx_destroy_fmr, mlnx_fmr_create_t
+
+
+ + diff --git a/branches/WOF2-3/docs/iba/ib_types_h.html b/branches/WOF2-3/docs/iba/ib_types_h.html new file mode 100644 index 00000000..085063ca --- /dev/null +++ b/branches/WOF2-3/docs/iba/ib_types_h.html @@ -0,0 +1,10744 @@ + + + + +./inc_docs/iba/ib_types_h.html + + + + +Generated from ./inc/iba/ib_types.h with ROBODoc v4.99.17 on Sun Mar 04 2007 18:17:50 +
+
+ +

[Modules] +IBA Base/Constants

+ +

[top][index]

+

NAME

+
       Constants
+
+

DESCRIPTION

+
       The following constants are used throughout the IBA code base.
+
+       Definitions are from the InfiniBand Architecture Specification v1.2
+
+
+
+ +

[Modules] +IBA Base/Type Definitions

+ +

[top][index]

+

NAME

+
       Type Definitions
+
+

DESCRIPTION

+
       Definitions are from the InfiniBand Architecture Specification v1.2
+
+
+
+ +

[Definitions] +Access Layer/ib_access_t

+ +

[top][parent][index]

+

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.
+
+
+
+ +

[Definitions] +Access Layer/ib_api_status_t

+ +

[top][parent][index]

+

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_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_SRQ_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_QP_HANDLE,
+        IB_INVALID_SRQ_HANDLE,
+        IB_INVALID_PD_HANDLE,
+        IB_INVALID_MR_HANDLE,
+        IB_INVALID_FMR_HANDLE,
+        IB_INVALID_MW_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_INVALID_INDEX,
+        IB_NO_MATCH,
+        IB_PENDING,
+        IB_UNKNOWN_ERROR                                                /* ALWAYS LAST ENUM VALUE! */
+
+}       ib_api_status_t;
+
+
+
+ +

[Definitions] +Access Layer/ib_apm_state_t

+ +

[top][parent][index]

+

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;
+
+
+
+ +

[Definitions] +Access Layer/ib_apr_status_t

+ +

[top][parent][index]

+

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                                       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
+
+
+
+ +

[Definitions] +Access Layer/ib_atomic_t

+ +

[top][parent][index]

+

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.
+
+
+
+ +

[Structures] +Access Layer/ib_av_attr_t

+ +

[top][parent][index]

+

NAME

+
       ib_av_attr_t
+
+

DESCRIPTION

+
       IBA address vector.
+
+

SYNOPSIS

+
typedef _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
+
+
+
+ +

[Structures] +Access Layer/ib_bind_wr_t

+ +

[top][parent][index]

+

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 __ptr64                  h_mr;
+        ib_access_t                             access_ctrl;
+        net32_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
+
+
+
+ +

[Structures] +Access Layer/ib_ca_attr_t

+ +

[top][parent][index]

+

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_resp_res;
+
+        uint8_t                                 max_qp_init_depth;
+
+        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;
+        uint32_t                                max_srq;
+        uint32_t                                max_srq_wrs;
+        uint32_t                                max_srq_sges;
+
+        /*
+         * 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                               modify_srq_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;
+
+ TO_LONG_PTR(       uint32_t* ,               p_page_size) ; 
+ TO_LONG_PTR(       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
+               Maximum limit on number of responder resources for incomming RDMA
+               operations on QPs.
+
+       max_fmr
+               Maximum number of Fast Memory Regions supported.
+
+       max_map_per_fmr
+               Maximum number of mappings, supported by a Fast Memory Region.
+
+       max_srq
+               Maximum number of Shared Receive Queues supported.
+
+       max_srq_wrs
+               Maximum number of work requests supported by this SRQ.
+
+       max_srq_sges
+               Maximum number of scatter gather elements supported per work request on SRQ.
+
+       max_resp_res
+               Maximum number of responder resources per HCA, with this HCA used as
+               the target.
+
+       max_qp_init_depth
+               Maximimum initiator depth per QP for initiating RDMA reads and
+               atomic operations.
+
+       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 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.
+
+       modify_srq_depth
+               Indicates ability to modify SRQ depth during a modify SRQ 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
+
+
+
+ +

[Definitions] +Access Layer/ib_ca_mod_t

+ +

[top][parent][index]

+

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
+#define IB_CA_MOD_IS_CLIENT_REREGISTER_SUPPORTED        0x00800000
+#define IB_CA_MOD_RESERVED_MASK                         0xFF000000
+
+

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 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.
+
+       IB_CA_MOD_IS_CLIENT_REREGISTER_SUPPORTED
+               Used to modify the system image GUID for the port.
+
+       IB_CA_MOD_RESERVED_MASK
+               Mask of all the reserved bits.  If any of these bits are set
+               ib_modify_ca will return IB_INVALID_PARAMETER.
+
+
+
+ +

[Structures] +Access Layer/ib_ci_op_t

+ +

[top][parent][index]

+

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                              uint32_t                                        buf_size;
+        IN                              uint32_t                                        buf_info;
+        IN      OUT                     int32_t                                         status;
+                OUT                     uint32_t                                        num_bytes_ret;
+        IN      OUT                     void* FUNC_PTR64                           p_buf OPTIONAL;
+
+}       ib_ci_op_t;
+
+

FIELDS

+
       command
+               A command code that is understood by the verbs provider.
+
+       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.
+
+       buf_size
+               The size of the buffer in bytes.
+
+       buf_info
+               Additional buffer information
+
+       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.
+
+       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.
+
+

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.
+
+
+
+ +

[Definitions] +Access Layer/ib_cm_cap_mask_t

+ +

[top][parent][index]

+

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

+
*
+
+
+
+ +

[Functions] +Access layer/ib_copy_ca_attr

+ +

[top][index]

+

NAME

+
       ib_copy_ca_attr
+
+

DESCRIPTION

+
       Copies CA attributes.
+
+

SYNOPSIS

+
AL_EXPORT ib_ca_attr_t* AL_API
+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
+
+
+
+ +

[Definitions] +Access Layer/ib_init_type_t

+ +

[top][parent][index]

+

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
+
+
+
+ +

[Structures] +Access Layer/ib_local_ds_t

+ +

[top][parent][index]

+

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
+{
+        uint64_t                                vaddr;
+        uint32_t                                length;
+        uint32_t                                lkey;
+
+}       ib_local_ds_t;
+
+
+
+ +

[Structures] +Access Layer/ib_mr_attr_t

+ +

[top][parent][index]

+

NAME

+
       ib_mr_attr_t
+
+

DESCRIPTION

+
       Attributes of a registered memory region.
+
+

SYNOPSIS

+
typedef struct _ib_mr_attr
+{
+        ib_pd_handle_t __ptr64                  h_pd;
+        uint64_t                                local_lb;
+        uint64_t                                local_ub;
+        uint64_t                                remote_lb;
+        uint64_t                                remote_ub;
+        ib_access_t                             access_ctrl;
+        net32_t                                 lkey;
+        net32_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.  This is always a 64-bit quantity to support registering
+               more than 4GB of memory on 32-bit systems with PAE.
+
+       local_ub
+               The virtual address of the upper bound of protection for local
+               memory access.  This is always a 64-bit quantity to support registering
+               more than 4GB of memory on 32-bit systems with PAE.
+
+       remote_lb
+               The virtual address of the lower bound of protection for remote
+               memory access.  This is always a 64-bit quantity to support registering
+               more than 4GB of memory on 32-bit systems with PAE.
+
+       remote_ub
+               The virtual address of the upper bound of protection for remote
+               memory access.  This is always a 64-bit quantity to support registering
+               more than 4GB of memory on 32-bit systems with PAE.
+
+       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
+
+
+
+ +

[Structures] +Access Layer/ib_mr_create_t

+ +

[top][parent][index]

+

NAME

+
       ib_mr_create_t
+
+

DESCRIPTION

+
       Information required to create a registered memory region.
+
+

SYNOPSIS

+
typedef struct _ib_mr_create
+{
+ TO_LONG_PTR(       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
+
+
+
+ +

[Definitions] +Access Layer/ib_mr_mod_t

+ +

[top][parent][index]

+

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.
+
+
+
+ +

[Definitions] +Access Layer/ib_pd_type_t

+ +

[top][parent][index]

+

NAME

+
       ib_pd_type_t
+
+

DESCRIPTION

+
       Indicates the type of protection domain being allocated.
+
+

SYNOPSIS

+
typedef enum _ib_pd_type
+{
+        IB_PDT_NORMAL,
+        IB_PDT_ALIAS,
+        IB_PDT_SQP,
+        IB_PDT_UD
+
+}       ib_pd_type_t;
+
+

VALUES

+
       IB_PDT_NORMAL
+               Protection domain for all non-aliased QPs.
+
+       IB_PDT_ALIAS
+               Protection domain for IB_QPT_QP0_ALIAS and IB_QPT_QP1_ALIAS QPs.
+
+       IB_PDT_SQP
+               Protection domain for special queue pair usage.
+
+       IB_PDT_UD
+               Protection domain for UD queue pair usage.
+
+
+
+ +

[Structures] +Access Layer/ib_phys_create_t

+ +

[top][parent][index]

+

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_ranges;
+ TO_LONG_PTR(       ib_phys_range_t* ,        range_array) ; 
+        uint32_t                                        buf_offset;
+        uint32_t                                        hca_page_size;
+        ib_access_t                                     access_ctrl;
+
+}       ib_phys_create_t;
+
+

FIELDS

+
       length
+               The length of the memory region in bytes.
+
+       num_ranges
+               Number of ib_phys_range structures listed in the specified range array.
+
+       range_array
+               An array of ib_phys_range structures to be registered as a single memory
+               region.
+
+       buf_offset
+               The offset into the first physical memory range of the specified memory
+               region on which to start the virtual address.
+
+       hca_page_size
+               The HCA page size to use to register the memory.
+
+       access_ctrl
+               Access rights of the registered region.
+
+

SEE ALSO

+
       ib_access_t
+
+
+
+ +

[Structures] +Access Layer/ib_phys_range_t

+ +

[top][parent][index]

+

NAME

+
       ib_phys_range_t
+
+

DESCRIPTION

+
       Information describing a physical memory range.
+
+

SYNOPSIS

+
typedef struct _ib_phys_range
+{
+        uint64_t                                base_addr;
+        uint64_t                                size;
+
+}       ib_phys_range_t;
+
+

FIELDS

+
       base_addr
+               Physical address of the base of the memory range.
+
+       size
+               size, in bytes, of the memory range.
+
+

NOTES

+
       The base address must be start and end on an HCA-supported page boundary.
+
+

SEE ALSO

+
       ib_phys_create_t
+
+
+
+ +

[Structures] +Access Layer/ib_port_attr_mod_t

+ +

[top][parent][index]

+

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
+
+
+
+ +

[Structures] +Access Layer/ib_port_attr_t

+ +

[top][parent][index]

+

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.
+         */
+ TO_LONG_PTR(       ib_gid_t* ,               p_gid_table) ; 
+ TO_LONG_PTR(       ib_net16_t* ,             p_pkey_table) ; 
+
+}       ib_port_attr_t;
+
+

SEE ALSO

+
       uint8_t, ib_port_cap_t, ib_link_states_t
+
+
+
+ +

[Structures] +Access Layer/ib_port_cap_t

+ +

[top][parent][index]

+

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;
+        boolean_t               ipd;
+        boolean_t               pkey_switch_ext_port;
+        boolean_t               bm;
+        boolean_t               link_rtl;
+        boolean_t               client_reregister;
+
+}       ib_port_cap_t;
+
+
+
+ +

[Structures] +Access Layer/ib_qp_attr_t

+ +

[top][parent][index]

+

NAME

+
       ib_qp_attr_t
+
+

DESCRIPTION

+
       Queue pair attributes returned through ib_query_qp.
+
+

SYNOPSIS

+
typedef struct _ib_qp_attr
+{
+        ib_pd_handle_t __ptr64                  h_pd;
+        ib_qp_type_t                    qp_type;
+        ib_access_t                             access_ctrl;
+        uint16_t                                pkey_index;
+
+        uint32_t                                sq_max_inline;
+        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 __ptr64                  h_sq_cq;
+        ib_cq_handle_t __ptr64                  h_rq_cq;
+        ib_srq_handle_t __ptr64                 h_srq;
+
+        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 QP.
+
+       sq_max_inline
+               Maximum payload that can be inlined directly in a WQE, eliminating
+               protection checks and additional DMA operations.
+
+

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
+
+
+
+ +

[Structures] +Access Layer/ib_qp_create_t

+ +

[top][parent][index]

+

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;
+
+        uint32_t                                sq_depth;
+        uint32_t                                rq_depth;
+        uint32_t                                sq_sge;
+        uint32_t                                rq_sge;
+
+        ib_cq_handle_t __ptr64                  h_sq_cq;
+        ib_cq_handle_t __ptr64                  h_rq_cq;
+        ib_srq_handle_t __ptr64                 h_srq;
+
+        boolean_t                               sq_signaled;
+
+}       ib_qp_create_t;
+
+

FIELDS

+
       type
+               Specifies the type of queue pair to create.
+
+       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.
+
+       h_srq
+               A handle to an SRQ to get receive completions via. Must be coded NULL 
+               when QP is not associated with SRQ
+
+       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
+
+
+
+ +

[Structures] +Access Layer/ib_qp_mod_t

+ +

[top][parent][index]

+

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_init
+                {
+                        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;
+                        uint8_t                         rnr_nak_timeout;
+
+                        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;
+
+                }       rtr;
+
+                struct _qp_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_qp_opts_t            opts;
+                        uint8_t                         rnr_nak_timeout;
+                        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
+
+
+
+ +

[Definitions] +Access Layer/ib_qp_opts_t

+ +

[top][parent][index]

+

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
+
+
+
+ +

[Definitions] +Access Layer/ib_qp_state_t

+ +

[top][parent][index]

+

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 */
+
+
+
+ +

[Definitions] +Access Layer/ib_qp_type_t

+ +

[top][parent][index]

+

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_UNRELIABLE_DGRM  = 3,            /* Purposefully skip RDD type. */
+        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_QPT_UNKNOWN
+}       ib_qp_type_t;
+
+

VALUES

+
       IB_QPT_RELIABLE_CONN
+               Reliable, connected queue pair.
+
+       IB_QPT_UNRELIABLE_CONN
+               Unreliable, connected 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.
+
+
+
+ +

[Definitions] +Access Layer/ib_recv_opt_t

+ +

[top][parent][index]

+

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.
+
+
+
+ +

[Structures] +Access Layer/ib_recv_wr_t

+ +

[top][parent][index]

+

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
+{
+ TO_LONG_PTR(       struct _ib_recv_wr* ,     p_next) ; 
+        uint64_t                                        wr_id;
+        uint32_t                                        num_ds;
+ TO_LONG_PTR(       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
+
+
+
+ +

[Definitions] +Access Layer/ib_rej_status_t

+ +

[top][parent][index]

+

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)
+
+
+
+ +

[Definitions] +Access Layer/ib_send_opt_t

+ +

[top][parent][index]

+

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.
+
+
+
+ +

[Structures] +Access Layer/ib_send_wr_t

+ +

[top][parent][index]

+

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
+{
+ TO_LONG_PTR(       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;
+ TO_LONG_PTR(       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 __ptr64  h_av;
+                        uint16_t                pkey_index;
+ TO_LONG_PTR(                       void* ,   rsvd) ; 
+
+                }       ud;
+
+                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;
+                net32_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.ud.pkey_index
+               The pkey index for this send work request.  This is valid only
+               for IB_QPT_QP1 and IB_QPT_QP1_ALIAS QP types.  The work request
+               is posted to using this pkey index build the GMP's BTH instead
+               of the QP's pkey.
+
+       dgrm.ud.rsvd
+               Reserved for use by the Access Layer.
+
+       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
+
+
+
+ +

[Definitions] +Access Layer/ib_srq_attr_mask_t

+ +

[top][parent][index]

+

NAME

+
       ib_srq_attr_mask_t
+
+

DESCRIPTION

+
       Indicates valid fields in ib_srq_attr_t structure
+
+

SYNOPSIS

+
typedef enum _ib_srq_attr_mask {
+        IB_SRQ_MAX_WR   = 1 << 0,
+        IB_SRQ_LIMIT    = 1 << 1,
+} ib_srq_attr_mask_t;
+
+
+
+ +

[Structures] +Access Layer/ib_srq_attr_t

+ +

[top][parent][index]

+

NAME

+
       ib_srq_attr_t
+
+

DESCRIPTION

+
       Attributes used to initialize a shared queue pair at creation time.
+
+

SYNOPSIS

+
typedef struct _ib_srq_attr {
+        uint32_t                                max_wr;
+        uint32_t                                max_sge;
+        uint32_t                                srq_limit;
+} ib_srq_attr_t;
+
+

FIELDS

+
       max_wr
+               Specifies the max number of work request on SRQ.
+
+       max_sge
+               Specifies the max number of scatter/gather elements in one work request.
+
+       srq_limit
+               Specifies the low water mark for SRQ.
+
+

SEE ALSO

+
       ib_qp_type_t, ib_srq_attr_mask_t
+
+
+
+ +

[Definitions] +Access Layer/ib_wc_status_t

+ +

[top][parent][index]

+

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_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_BAD_RESP_ERR,
+        IB_WCS_LOCAL_ACCESS_ERR,
+        IB_WCS_GENERAL_ERR,
+        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_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_BAD_RESP_ERR,
+              An unexpected transport layer opcode was returned
+              by the responder.
+
+      IB_WCS_LOCAL_ACCESS_ERR,
+              A protection error occurred on a local data buffer
+              during the processing of a RDMA Write with Immediate Data 
+              operation sent from the remote node.
+
+       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.
+
+      IB_WCS_GENERAL_ERR,
+              Any other error
+
+
+
+ +

[Structures] +Access Layer/ib_wc_t

+ +

[top][parent][index]

+

NAME

+
       ib_wc_t
+
+

DESCRIPTION

+
       Work completion information.
+
+

SYNOPSIS

+
typedef struct _ib_wc
+{
+ TO_LONG_PTR(       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_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 of the source queue pair. This is valid only for
+               IB_QPT_QP1 and IB_QPT_QP1_ALIAS QP types.
+
+       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.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
+
+
+
+ +

[Definitions] +Access Layer/ib_wc_type_t

+ +

[top][parent][index]

+

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_UNKNOWN
+
+}       ib_wc_type_t;
+
+
+
+ +

[Definitions] +Access Layer/ib_wr_type_t

+ +

[top][parent][index]

+

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,
+        WR_UNKNOWN
+
+}       ib_wr_type_t;
+
+
+
+ +

[Structures] +Access Layer/mlnx_fmr_create_t

+ +

[top][parent][index]

+

NAME

+
       mlnx_fmr_create_t
+
+

DESCRIPTION

+
       Information required to create a Mellanox fast memory region.
+
+

SYNOPSIS

+
typedef struct _mlnx_fmr_create
+{
+        int                                     max_pages;
+        int                                     max_maps;
+        uint8_t                         page_size;
+        ib_access_t                     access_ctrl;
+
+}       mlnx_fmr_create_t;
+
+

FIELDS

+
       max_pages
+               max pages in the region.
+
+       max_maps
+               max times, the region can be mapped before remapping.
+
+       page_size
+               log2 of the page size (e.g. 12 for 4KB).
+
+       access_ctrl
+               Access rights of the registered region.
+
+

NOTES

+
       This is a Mellanox specific extension to verbs.
+
+

SEE ALSO

+
       ib_access_t
+
+
+
+ +

[Structures] +IBA Base: Constants/IB_CLASS_CAP_GETSET

+ +

[top][index]

+

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
+
+
+
+ +

[Structures] +IBA Base: Constants/IB_CLASS_CAP_TRAP

+ +

[top][index]

+

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
+
+
+
+ +

[Structures] +IBA Base: Constants/IB_CLASS_RESP_TIME_MASK

+ +

[top][index]

+

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
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_DEFAULT_PARTIAL_PKEY

+ +

[top][index]

+

NAME

+
       IB_DEFAULT_PARTIAL_PKEY 
+
+

DESCRIPTION

+
       0x7FFF in network order
+
+

SOURCE

+
#define IB_DEFAULT_PARTIAL_PKEY                                (CL_HTON16(0x7FFF))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_DEFAULT_PKEY

+ +

[top][index]

+

NAME

+
       IB_DEFAULT_PKEY
+
+

DESCRIPTION

+
       P_Key value for the default partition.
+
+

SOURCE

+
#define IB_DEFAULT_PKEY                                         0xFFFF
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_DEFAULT_SUBNET_PREFIX

+ +

[top][index]

+

NAME

+
       IB_DEFAULT_SUBNET_PREFIX
+
+

DESCRIPTION

+
       Default subnet GID prefix.
+
+

SOURCE

+
#define IB_DEFAULT_SUBNET_PREFIX                        (CL_HTON64(0xFE80000000000000ULL))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_INVALID_PORT_NUM

+ +

[top][index]

+

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
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_LID_MCAST_END

+ +

[top][index]

+

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))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_LID_MCAST_START

+ +

[top][index]

+

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))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_LID_PERMISSIVE

+ +

[top][index]

+

NAME

+
       IB_LID_PERMISSIVE
+
+

DESCRIPTION

+
       Permissive LID
+
+

SOURCE

+
#define IB_LID_PERMISSIVE                                       0xFFFF
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_LID_UCAST_END

+ +

[top][index]

+

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))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_LID_UCAST_START

+ +

[top][index]

+

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))
+
+
+
+ +

[Definitions] +IBA Base: Constants/ib_link_states_t

+ +

[top][index]

+

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
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_ATTR_CLASS_PORT_INFO

+ +

[top][index]

+

NAME

+
       IB_MAD_ATTR_CLASS_PORT_INFO
+
+

DESCRIPTION

+
       ClassPortInfo attribute (13.4.8)
+
+

SOURCE

+
#define IB_MAD_ATTR_CLASS_PORT_INFO                     (CL_NTOH16(0x0001))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_ATTR_DIAG_CODE

+ +

[top][index]

+

NAME

+
       IB_MAD_ATTR_DIAG_CODE
+
+

DESCRIPTION

+
       DiagCode attribute (16.3.3)
+
+

SOURCE

+
#define IB_MAD_ATTR_DIAG_CODE                           (CL_NTOH16(0x0024))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_ATTR_DIAGNOSTIC_TIMEOUT

+ +

[top][index]

+

NAME

+
       IB_MAD_ATTR_DIAGNOSTIC_TIMEOUT
+
+

DESCRIPTION

+
       DiagnosticTimeout attribute (16.3.3)
+
+

SOURCE

+
#define IB_MAD_ATTR_DIAGNOSTIC_TIMEOUT          (CL_NTOH16(0x0020))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_ATTR_GUID_INFO

+ +

[top][index]

+

NAME

+
       IB_MAD_ATTR_GUID_INFO
+
+

DESCRIPTION

+
       GUIDInfo attribute (14.2.5)
+
+

SOURCE

+
#define IB_MAD_ATTR_GUID_INFO                           (CL_NTOH16(0x0014))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_ATTR_GUIDINFO_RECORD

+ +

[top][index]

+

NAME

+
       IB_MAD_ATTR_GUIDINFO_RECORD
+
+

DESCRIPTION

+
       GuidInfoRecord attribute (15.2.5)
+
+

SOURCE

+
#define IB_MAD_ATTR_GUIDINFO_RECORD                     (CL_NTOH16(0x0030))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_ATTR_INFORM_INFO

+ +

[top][index]

+

NAME

+
       IB_MAD_ATTR_INFORM_INFO
+
+

DESCRIPTION

+
       InformInfo attribute (13.4.8)
+
+

SOURCE

+
#define IB_MAD_ATTR_INFORM_INFO                         (CL_NTOH16(0x0003))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_ATTR_INFORM_INFO_RECORD

+ +

[top][index]

+

NAME

+
       IB_MAD_ATTR_INFORM_INFO_RECORD
+
+

DESCRIPTION

+
       InformInfo Record attribute (15.2.5)
+
+

SOURCE

+
#define IB_MAD_ATTR_INFORM_INFO_RECORD                  (CL_NTOH16(0x00F3))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_ATTR_IO_CONTROLLER_PROFILE

+ +

[top][index]

+

NAME

+
       IB_MAD_ATTR_IO_CONTROLLER_PROFILE
+
+

DESCRIPTION

+
       IOControllerProfile attribute (16.3.3)
+
+

SOURCE

+
#define IB_MAD_ATTR_IO_CONTROLLER_PROFILE       (CL_NTOH16(0x0011))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_ATTR_IO_UNIT_INFO

+ +

[top][index]

+

NAME

+
       IB_MAD_ATTR_IO_UNIT_INFO
+
+

DESCRIPTION

+
       IOUnitInfo attribute (16.3.3)
+
+

SOURCE

+
#define IB_MAD_ATTR_IO_UNIT_INFO                        (CL_NTOH16(0x0010))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_ATTR_LED_INFO

+ +

[top][index]

+

NAME

+
       IB_MAD_ATTR_LED_INFO
+
+

DESCRIPTION

+
       LedInfo attribute (14.2.5)
+
+

SOURCE

+
#define IB_MAD_ATTR_LED_INFO                            (CL_NTOH16(0x0031))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_ATTR_LFT_RECORD

+ +

[top][index]

+

NAME

+
       IB_MAD_ATTR_LFT_RECORD
+
+

DESCRIPTION

+
       LinearForwardingTableRecord attribute (15.2.5.6)
+
+

SOURCE

+
#define IB_MAD_ATTR_LFT_RECORD                  (CL_NTOH16(0x0015))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_ATTR_LIN_FWD_TBL

+ +

[top][index]

+

NAME

+
       IB_MAD_ATTR_LIN_FWD_TBL
+
+

DESCRIPTION

+
       Switch linear forwarding table
+
+

SOURCE

+
#define IB_MAD_ATTR_LIN_FWD_TBL                         (CL_NTOH16(0x0019))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_ATTR_LINK_RECORD

+ +

[top][index]

+

NAME

+
       IB_MAD_ATTR_LINK_RECORD
+
+

DESCRIPTION

+
       LinkRecord attribute (15.2.5)
+
+

SOURCE

+
#define IB_MAD_ATTR_LINK_RECORD                         (CL_NTOH16(0x0020))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_ATTR_MCAST_FWD_TBL

+ +

[top][index]

+

NAME

+
       IB_MAD_ATTR_MCAST_FWD_TBL
+
+

DESCRIPTION

+
       Switch multicast forwarding table
+
+

SOURCE

+
#define IB_MAD_ATTR_MCAST_FWD_TBL                       (CL_NTOH16(0x001B))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_ATTR_MCMEMBER_RECORD

+ +

[top][index]

+

NAME

+
       IB_MAD_ATTR_MCMEMBER_RECORD
+
+

DESCRIPTION

+
       MCMemberRecord attribute (15.2.5)
+
+

SOURCE

+
#define IB_MAD_ATTR_MCMEMBER_RECORD                     (CL_NTOH16(0x0038))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_ATTR_MULTIPATH_RECORD

+ +

[top][index]

+

NAME

+
       IB_MAD_ATTR_MULTIPATH_RECORD
+
+

DESCRIPTION

+
       MultiPathRecord attribute (15.2.5)
+
+

SOURCE

+
#define IB_MAD_ATTR_MULTIPATH_RECORD                    (CL_NTOH16(0x003A))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_ATTR_NODE_DESC

+ +

[top][index]

+

NAME

+
       IB_MAD_ATTR_NODE_DESC
+
+

DESCRIPTION

+
       NodeDescription attribute (14.2.5)
+
+

SOURCE

+
#define IB_MAD_ATTR_NODE_DESC                           (CL_NTOH16(0x0010))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_ATTR_NODE_INFO

+ +

[top][index]

+

NAME

+
       IB_MAD_ATTR_NODE_INFO
+
+

DESCRIPTION

+
       NodeInfo attribute (14.2.5)
+
+

SOURCE

+
#define IB_MAD_ATTR_NODE_INFO                           (CL_NTOH16(0x0011))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_ATTR_NODE_RECORD

+ +

[top][index]

+

NAME

+
       IB_MAD_ATTR_NODE_RECORD
+
+

DESCRIPTION

+
       NodeRecord attribute (15.2.5)
+
+

SOURCE

+
#define IB_MAD_ATTR_NODE_RECORD                         (CL_NTOH16(0x0011))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_ATTR_NOTICE

+ +

[top][index]

+

NAME

+
       IB_MAD_ATTR_NOTICE
+
+

DESCRIPTION

+
       Notice attribute (13.4.8)
+
+

SOURCE

+
#define IB_MAD_ATTR_NOTICE                                      (CL_NTOH16(0x0002))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_ATTR_P_KEY_TABLE

+ +

[top][index]

+

NAME

+
       IB_MAD_ATTR_P_KEY_TABLE
+
+

DESCRIPTION

+
       PartitionTable attribute (14.2.5)
+
+

SOURCE

+
#define IB_MAD_ATTR_P_KEY_TABLE                         (CL_NTOH16(0x0016))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_ATTR_PATH_RECORD

+ +

[top][index]

+

NAME

+
       IB_MAD_ATTR_PATH_RECORD
+
+

DESCRIPTION

+
       PathRecord attribute (15.2.5)
+
+

SOURCE

+
#define IB_MAD_ATTR_PATH_RECORD                         (CL_NTOH16(0x0035))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_ATTR_PKEYTBL_RECORD

+ +

[top][index]

+

NAME

+
       IB_MAD_ATTR_PKEYTBL_RECORD
+
+

DESCRIPTION

+
       PKEY Table Record attribute (15.2.5)
+
+

SOURCE

+
#define IB_MAD_ATTR_PKEY_TBL_RECORD                     (CL_NTOH16(0x0033))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_ATTR_PORT_CNTRS

+ +

[top][index]

+

NAME

+
       IB_MAD_ATTR_PORT_CNTRS
+
+

DESCRIPTION

+
       SwitchInfo attribute (16.1.2)
+
+

SOURCE

+
#define IB_MAD_ATTR_PORT_CNTRS                          (CL_NTOH16(0x0012))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_ATTR_PORT_INFO

+ +

[top][index]

+

NAME

+
       IB_MAD_ATTR_PORT_INFO
+
+

DESCRIPTION

+
       PortInfo attribute (14.2.5)
+
+

SOURCE

+
#define IB_MAD_ATTR_PORT_INFO                           (CL_NTOH16(0x0015))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_ATTR_PORT_SMPL_CTRL

+ +

[top][index]

+

NAME

+
       IB_MAD_ATTR_PORT_SMPL_CTRL
+
+

DESCRIPTION

+
       NodeDescription attribute (16.1.2)
+
+

SOURCE

+
#define IB_MAD_ATTR_PORT_SMPL_CTRL                      (CL_NTOH16(0x0010))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_ATTR_PORT_SMPL_RSLT

+ +

[top][index]

+

NAME

+
       IB_MAD_ATTR_PORT_SMPL_RSLT
+
+

DESCRIPTION

+
       NodeInfo attribute (16.1.2)
+
+

SOURCE

+
#define IB_MAD_ATTR_PORT_SMPL_RSLT                      (CL_NTOH16(0x0011))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_ATTR_PORTINFO_RECORD

+ +

[top][index]

+

NAME

+
       IB_MAD_ATTR_PORTINFO_RECORD
+
+

DESCRIPTION

+
       PortInfoRecord attribute (15.2.5)
+
+

SOURCE

+
#define IB_MAD_ATTR_PORTINFO_RECORD                     (CL_NTOH16(0x0012))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_ATTR_PREPARE_TO_TEST

+ +

[top][index]

+

NAME

+
       IB_MAD_ATTR_PREPARE_TO_TEST
+
+

DESCRIPTION

+
       PrepareToTest attribute (16.3.3)
+
+

SOURCE

+
#define IB_MAD_ATTR_PREPARE_TO_TEST                     (CL_NTOH16(0x0021))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_ATTR_RND_FWD_TBL

+ +

[top][index]

+

NAME

+
       IB_MAD_ATTR_RND_FWD_TBL
+
+

DESCRIPTION

+
       Switch random forwarding table
+
+

SOURCE

+
#define IB_MAD_ATTR_RND_FWD_TBL                         (CL_NTOH16(0x001A))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_ATTR_SERVICE_ENTRIES

+ +

[top][index]

+

NAME

+
       IB_MAD_ATTR_SERVICE_ENTRIES
+
+

DESCRIPTION

+
       ServiceEntries attribute (16.3.3)
+
+

SOURCE

+
#define IB_MAD_ATTR_SERVICE_ENTRIES                     (CL_NTOH16(0x0012))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_ATTR_SERVICE_RECORD

+ +

[top][index]

+

NAME

+
       IB_MAD_ATTR_SERVICE_RECORD
+
+

DESCRIPTION

+
       ServiceRecord attribute (15.2.5)
+
+

SOURCE

+
#define IB_MAD_ATTR_SERVICE_RECORD                      (CL_NTOH16(0x0031))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_ATTR_SLVL_RECORD

+ +

[top][index]

+

NAME

+
       IB_MAD_ATTR_SLVL_RECORD
+
+

DESCRIPTION

+
       SLtoVL Mapping Table Record attribute (15.2.5)
+
+

SOURCE

+
#define IB_MAD_ATTR_SLVL_RECORD                         (CL_NTOH16(0x0013))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_ATTR_SLVL_TABLE

+ +

[top][index]

+

NAME

+
       IB_MAD_ATTR_SLVL_TABLE
+
+

DESCRIPTION

+
       SL VL Mapping Table attribute (14.2.5)
+
+

SOURCE

+
#define IB_MAD_ATTR_SLVL_TABLE                          (CL_NTOH16(0x0017))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_ATTR_SM_INFO

+ +

[top][index]

+

NAME

+
       IB_MAD_ATTR_SM_INFO
+
+

DESCRIPTION

+
       SMInfo attribute (14.2.5)
+
+

SOURCE

+
#define IB_MAD_ATTR_SM_INFO                                     (CL_NTOH16(0x0020))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_ATTR_SMINFO_RECORD

+ +

[top][index]

+

NAME

+
       IB_MAD_ATTR_SMINFO_RECORD
+
+

DESCRIPTION

+
       SmInfoRecord attribute (15.2.5)
+
+

SOURCE

+
#define IB_MAD_ATTR_SMINFO_RECORD                       (CL_NTOH16(0x0018))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_ATTR_SVC_ASSOCIATION_RECORD

+ +

[top][index]

+

NAME

+
       IB_MAD_ATTR_SVC_ASSOCIATION_RECORD
+
+

DESCRIPTION

+
       Service Association Record attribute (15.2.5)
+
+

SOURCE

+
#define IB_MAD_ATTR_SVC_ASSOCIATION_RECORD              (CL_NTOH16(0x003B))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_ATTR_SWITCH_INFO

+ +

[top][index]

+

NAME

+
       IB_MAD_ATTR_SWITCH_INFO
+
+

DESCRIPTION

+
       SwitchInfo attribute (14.2.5)
+
+

SOURCE

+
#define IB_MAD_ATTR_SWITCH_INFO                         (CL_NTOH16(0x0012))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_ATTR_TEST_DEVICE_LOOP

+ +

[top][index]

+

NAME

+
       IB_MAD_ATTR_TEST_DEVICE_LOOP
+
+

DESCRIPTION

+
       TestDeviceLoop attribute (16.3.3)
+
+

SOURCE

+
#define IB_MAD_ATTR_TEST_DEVICE_LOOP            (CL_NTOH16(0x0023))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_ATTR_TEST_DEVICE_ONCE

+ +

[top][index]

+

NAME

+
       IB_MAD_ATTR_TEST_DEVICE_ONCE
+
+

DESCRIPTION

+
       TestDeviceOnce attribute (16.3.3)
+
+

SOURCE

+
#define IB_MAD_ATTR_TEST_DEVICE_ONCE            (CL_NTOH16(0x0022))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_ATTR_TRACE_RECORD

+ +

[top][index]

+

NAME

+
       IB_MAD_ATTR_MTRACE_RECORD
+
+

DESCRIPTION

+
       TraceRecord attribute (15.2.5)
+
+

SOURCE

+
#define IB_MAD_ATTR_TRACE_RECORD                        (CL_NTOH16(0x0039))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_ATTR_VENDOR_DIAG

+ +

[top][index]

+

NAME

+
       IB_MAD_ATTR_VENDOR_DIAG
+
+

DESCRIPTION

+
       VendorDiag attribute (14.2.5)
+
+

SOURCE

+
#define IB_MAD_ATTR_VENDOR_DIAG                         (CL_NTOH16(0x0030))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_ATTR_VL_ARBITRATION

+ +

[top][index]

+

NAME

+
       IB_MAD_ATTR_VL_ARBITRATION
+
+

DESCRIPTION

+
       VL Arbitration Table attribute (14.2.5)
+
+

SOURCE

+
#define IB_MAD_ATTR_VL_ARBITRATION                      (CL_NTOH16(0x0018))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_ATTR_VLARB_RECORD

+ +

[top][index]

+

NAME

+
       IB_MAD_ATTR_VLARB_RECORD
+
+

DESCRIPTION

+
       VL Arbitration Table Record attribute (15.2.5)
+
+

SOURCE

+
#define IB_MAD_ATTR_VLARB_RECORD                        (CL_NTOH16(0x0036))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_METHOD_GET

+ +

[top][index]

+

NAME

+
       IB_MAD_METHOD_GET
+
+

DESCRIPTION

+
       Get() Method (13.4.5)
+
+

SOURCE

+
#define IB_MAD_METHOD_GET                                       0x01
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_METHOD_GET_RESP

+ +

[top][index]

+

NAME

+
       IB_MAD_METHOD_GET_RESP
+
+

DESCRIPTION

+
       GetResp() Method (13.4.5)
+
+

SOURCE

+
#define IB_MAD_METHOD_GET_RESP                          0x81
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_METHOD_GETTABLE

+ +

[top][index]

+

NAME

+
       IB_MAD_METHOD_GETTABLE
+
+

DESCRIPTION

+
       SubnAdmGetTable() Method (15.2.2)
+
+

SOURCE

+
#define IB_MAD_METHOD_GETTABLE                          0x12
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_METHOD_GETTABLE_RESP

+ +

[top][index]

+

NAME

+
       IB_MAD_METHOD_GETTABLE_RESP
+
+

DESCRIPTION

+
       SubnAdmGetTableResp() Method (15.2.2)
+
+

SOURCE

+
#define IB_MAD_METHOD_GETTABLE_RESP                     0x92
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_METHOD_REPORT

+ +

[top][index]

+

NAME

+
       IB_MAD_METHOD_REPORT
+
+

DESCRIPTION

+
       Report() Method (13.4.5)
+
+

SOURCE

+
#define IB_MAD_METHOD_REPORT                            0x06
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_METHOD_REPORT_RESP

+ +

[top][index]

+

NAME

+
       IB_MAD_METHOD_REPORT_RESP
+
+

DESCRIPTION

+
       ReportResp() Method (13.4.5)
+
+

SOURCE

+
#define IB_MAD_METHOD_REPORT_RESP                       0x86
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_METHOD_RESP_MASK

+ +

[top][index]

+

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
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_METHOD_SEND

+ +

[top][index]

+

NAME

+
       IB_MAD_METHOD_SEND
+
+

DESCRIPTION

+
       Send() Method (13.4.5)
+
+

SOURCE

+
#define IB_MAD_METHOD_SEND                                      0x03
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_METHOD_SET

+ +

[top][index]

+

NAME

+
       IB_MAD_METHOD_SET
+
+

DESCRIPTION

+
       Set() Method (13.4.5)
+
+

SOURCE

+
#define IB_MAD_METHOD_SET                                       0x02
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_METHOD_TRAP

+ +

[top][index]

+

NAME

+
       IB_MAD_METHOD_TRAP
+
+

DESCRIPTION

+
       Trap() Method (13.4.5)
+
+

SOURCE

+
#define IB_MAD_METHOD_TRAP                                      0x05
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_METHOD_TRAP_REPRESS

+ +

[top][index]

+

NAME

+
       IB_MAD_METHOD_TRAP_REPRESS
+
+

DESCRIPTION

+
       TrapRepress() Method (13.4.5)
+
+

SOURCE

+
#define IB_MAD_METHOD_TRAP_REPRESS                      0x07
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_STATUS_BUSY

+ +

[top][index]

+

NAME

+
       IB_MAD_STATUS_BUSY
+
+

DESCRIPTION

+
       Temporarily busy, MAD discarded (13.4.7)
+
+

SOURCE

+
#define IB_MAD_STATUS_BUSY                                      (CL_HTON16(0x0001))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_STATUS_INVALID_FIELD

+ +

[top][index]

+

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))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_STATUS_REDIRECT

+ +

[top][index]

+

NAME

+
       IB_MAD_STATUS_REDIRECT
+
+

DESCRIPTION

+
       QP Redirection required (13.4.7)
+
+

SOURCE

+
#define IB_MAD_STATUS_REDIRECT                          (CL_HTON16(0x0002))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_STATUS_UNSUP_CLASS_VER

+ +

[top][index]

+

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))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_STATUS_UNSUP_METHOD

+ +

[top][index]

+

NAME

+
       IB_MAD_STATUS_UNSUP_METHOD
+
+

DESCRIPTION

+
       Unsupported method (13.4.7)
+
+

SOURCE

+
#define IB_MAD_STATUS_UNSUP_METHOD                      (CL_HTON16(0x0008))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAD_STATUS_UNSUP_METHOD_ATTR

+ +

[top][index]

+

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))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MAX_METHOD

+ +

[top][index]

+

NAME

+
       IB_MAX_METHOD
+
+

DESCRIPTION

+
       Total number of methods available to a class, not including the R-bit.
+
+

SOURCE

+
#define IB_MAX_METHODS                                          128
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MCAST_BLOCK_ID_MASK_HO

+ +

[top][index]

+

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
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MCAST_BLOCK_SIZE

+ +

[top][index]

+

NAME

+
       IB_MCAST_BLOCK_SIZE
+
+

DESCRIPTION

+
       Number of port mask entries in a multicast forwarding table block.
+
+

SOURCE

+
#define IB_MCAST_BLOCK_SIZE                                     32
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MCAST_MASK_SIZE

+ +

[top][index]

+

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
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MCAST_MAX_BLOCK_ID

+ +

[top][index]

+

NAME

+
       IB_MCAST_MAX_BLOCK_ID
+
+

DESCRIPTION

+
       Maximum number of Multicast port mask blocks
+
+

SOURCE

+
#define IB_MCAST_MAX_BLOCK_ID                           511
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MCAST_POSITION_MASK_HO

+ +

[top][index]

+

NAME

+
       IB_MCAST_POSITION_MASK_HO
+
+

DESCRIPTION

+
       Mask (host order) to recover the multicast block position.
+
+

SOURCE

+
#define IB_MCAST_POSITION_MASK_HO                               0xF0000000
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MCAST_POSITION_MAX

+ +

[top][index]

+

NAME

+
       IB_MCAST_POSITION_MAX
+
+

DESCRIPTION

+
       Maximum value for the multicast block position.
+
+

SOURCE

+
#define IB_MCAST_POSITION_MAX                           0xF
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MCAST_POSITION_SHIFT

+ +

[top][index]

+

NAME

+
       IB_MCAST_POSITION_SHIFT
+
+

DESCRIPTION

+
       Shift value to normalize the multicast block position value.
+
+

SOURCE

+
#define IB_MCAST_POSITION_SHIFT                         28
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MCLASS_BIS

+ +

[top][index]

+

NAME

+
       IB_MCLASS_BIS
+
+

DESCRIPTION

+
       Subnet Management Class, BIS
+
+

SOURCE

+
#define IB_MCLASS_BIS 0x12
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MCLASS_BM

+ +

[top][index]

+

NAME

+
       IB_MCLASS_BM
+
+

DESCRIPTION

+
       Subnet Management Class, Baseboard Manager (13.4.4)
+
+

SOURCE

+
#define IB_MCLASS_BM                                            0x05
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MCLASS_COMM_MGMT

+ +

[top][index]

+

NAME

+
       IB_MCLASS_COMM_MGMT
+
+

DESCRIPTION

+
       Subnet Management Class, Communication Management (13.4.4)
+
+

SOURCE

+
#define IB_MCLASS_COMM_MGMT                                     0x07
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MCLASS_DEV_ADM

+ +

[top][index]

+

NAME

+
       IB_MCLASS_DEV_ADM
+
+

DESCRIPTION

+
       Subnet Management Class, Device Administration
+
+

SOURCE

+
#define IB_MCLASS_DEV_ADM 0x10
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MCLASS_DEV_MGMT

+ +

[top][index]

+

NAME

+
       IB_MCLASS_DEV_MGMT
+
+

DESCRIPTION

+
       Subnet Management Class, Device Management (13.4.4)
+
+

SOURCE

+
#define IB_MCLASS_DEV_MGMT                                      0x06
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MCLASS_PERF

+ +

[top][index]

+

NAME

+
       IB_MCLASS_PERF
+
+

DESCRIPTION

+
       Subnet Management Class, Performance Manager (13.4.4)
+
+

SOURCE

+
#define IB_MCLASS_PERF                                          0x04
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MCLASS_SNMP

+ +

[top][index]

+

NAME

+
       IB_MCLASS_SNMP
+
+

DESCRIPTION

+
       Subnet Management Class, SNMP Tunneling (13.4.4)
+
+

SOURCE

+
#define IB_MCLASS_SNMP                                          0x08
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MCLASS_SUBN_ADM

+ +

[top][index]

+

NAME

+
       IB_MCLASS_SUBN_ADM
+
+

DESCRIPTION

+
       Subnet Management Class, Subnet Administration (13.4.4)
+
+

SOURCE

+
#define IB_MCLASS_SUBN_ADM                                      0x03
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MCLASS_SUBN_DIR

+ +

[top][index]

+

NAME

+
       IB_MCLASS_SUBN_DIR
+
+

DESCRIPTION

+
       Subnet Management Class, Subnet Manager directed route (13.4.4)
+
+

SOURCE

+
#define IB_MCLASS_SUBN_DIR                                      0x81
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MCLASS_SUBN_LID

+ +

[top][index]

+

NAME

+
       IB_MCLASS_SUBN_LID
+
+

DESCRIPTION

+
       Subnet Management Class, Subnet Manager LID routed (13.4.4)
+
+

SOURCE

+
#define IB_MCLASS_SUBN_LID                                      0x01
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MCLASS_VENDOR_HIGH_RANGE_MAX

+ +

[top][index]

+

NAME

+
       IB_MCLASS_VENDOR_HIGH_RANGE_MAX
+
+

DESCRIPTION

+
       Subnet Management Class, Vendor Specific High Range End
+
+

SOURCE

+
#define IB_MCLASS_VENDOR_HIGH_RANGE_MAX 0x4f
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MCLASS_VENDOR_HIGH_RANGE_MIN

+ +

[top][index]

+

NAME

+
       IB_MCLASS_VENDOR_HIGH_RANGE_MIN
+
+

DESCRIPTION

+
       Subnet Management Class, Vendor Specific High Range Start
+
+

SOURCE

+
#define IB_MCLASS_VENDOR_HIGH_RANGE_MIN 0x30
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MCLASS_VENDOR_LOW_RANGE_MAX

+ +

[top][index]

+

NAME

+
       IB_MCLASS_VENDOR_LOW_RANGE_MAX
+
+

DESCRIPTION

+
       Subnet Management Class, Vendor Specific Low Range End
+
+

SOURCE

+
#define IB_MCLASS_VENDOR_LOW_RANGE_MAX 0x0f
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MCLASS_VENDOR_LOW_RANGE_MIN

+ +

[top][index]

+

NAME

+
       IB_MCLASS_VENDOR_LOW_RANGE_MIN
+
+

DESCRIPTION

+
       Subnet Management Class, Vendor Specific Low Range Start
+
+

SOURCE

+
#define IB_MCLASS_VENDOR_LOW_RANGE_MIN 0x09
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MTU_LEN_TYPE

+ +

[top][index]

+

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
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_MULTIPATH_REC_BASE_MASK

+ +

[top][index]

+

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
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_NODE_NUM_PORTS_MAX

+ +

[top][index]

+

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
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_NODE_TYPE_CA

+ +

[top][index]

+

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
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_NODE_TYPE_ROUTER

+ +

[top][index]

+

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
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_NODE_TYPE_SWITCH

+ +

[top][index]

+

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
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_NOTICE_NODE_TYPE_CA

+ +

[top][index]

+

NAME

+
       IB_NOTICE_NODE_TYPE_CA
+
+

DESCRIPTION

+
       Encoded generic node type used in MAD attributes (13.4.8.2)
+
+

SOURCE

+
#define IB_NOTICE_NODE_TYPE_CA                          (CL_NTOH32(0x000001))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_NOTICE_NODE_TYPE_ROUTER

+ +

[top][index]

+

NAME

+
       IB_NOTICE_NODE_TYPE_ROUTER
+
+

DESCRIPTION

+
       Encoded generic node type used in MAD attributes (13.4.8.2)
+
+

SOURCE

+
#define IB_NOTICE_NODE_TYPE_ROUTER                      (CL_NTOH32(0x000003))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_NOTICE_NODE_TYPE_SUBN_MGMT

+ +

[top][index]

+

NAME

+
       IB_NOTICE_NODE_TYPE_SUBN_MGMT
+
+

DESCRIPTION

+
       Encoded generic node type used in MAD attributes (13.4.8.2).
+       Note that this value is not defined for the NodeType field
+       of the NodeInfo attribute (14.2.5.3).
+
+

SOURCE

+
#define IB_NOTICE_NODE_TYPE_SUBN_MGMT           (CL_NTOH32(0x000004))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_NOTICE_NODE_TYPE_SWITCH

+ +

[top][index]

+

NAME

+
       IB_NOTICE_NODE_TYPE_SWITCH
+
+

DESCRIPTION

+
       Encoded generic node type used in MAD attributes (13.4.8.2)
+
+

SOURCE

+
#define IB_NOTICE_NODE_TYPE_SWITCH                      (CL_NTOH32(0x000002))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_PATH_REC_BASE_MASK

+ +

[top][index]

+

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
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_PATH_REC_SELECTOR_MASK

+ +

[top][index]

+

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
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_PATH_SELECTOR_TYPE

+ +

[top][index]

+

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
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_PKEY_BASE_MASK

+ +

[top][index]

+

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))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_PKEY_ENTRIES_MAX

+ +

[top][index]

+

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_PKEY_BLOCK_SIZE)
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_PKEY_MAX_BLOCKS

+ +

[top][index]

+

NAME

+
       IB_PKEY_MAX_BLOCKS
+
+

DESCRIPTION

+
       Maximum number of PKEY blocks (14.2.5.7).
+
+

SOURCE

+
#define IB_PKEY_MAX_BLOCKS                                      2048
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_PKEY_TYPE_MASK

+ +

[top][index]

+

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_NTOH16(0x8000))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_QP1_WELL_KNOWN_Q_KEY

+ +

[top][index]

+

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_NTOH32(0x80010000)
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_SMINFO_ATTR_MOD_ACKNOWLEDGE

+ +

[top][index]

+

NAME

+
       IB_SMINFO_ATTR_MOD_ACKNOWLEDGE
+
+

DESCRIPTION

+
       Encoded attribute modifier value used on SubnSet(SMInfo) SMPs.
+
+

SOURCE

+
#define IB_SMINFO_ATTR_MOD_ACKNOWLEDGE          (CL_NTOH32(0x000002))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_SMINFO_ATTR_MOD_DISABLE

+ +

[top][index]

+

NAME

+
       IB_SMINFO_ATTR_MOD_DISABLE
+
+

DESCRIPTION

+
       Encoded attribute modifier value used on SubnSet(SMInfo) SMPs.
+
+

SOURCE

+
#define IB_SMINFO_ATTR_MOD_DISABLE                      (CL_NTOH32(0x000003))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_SMINFO_ATTR_MOD_DISCOVER

+ +

[top][index]

+

NAME

+
       IB_SMINFO_ATTR_MOD_DISCOVER
+
+

DESCRIPTION

+
       Encoded attribute modifier value used on SubnSet(SMInfo) SMPs.
+
+

SOURCE

+
#define IB_SMINFO_ATTR_MOD_DISCOVER                     (CL_NTOH32(0x000005))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_SMINFO_ATTR_MOD_HANDOVER

+ +

[top][index]

+

NAME

+
       IB_SMINFO_ATTR_MOD_HANDOVER
+
+

DESCRIPTION

+
       Encoded attribute modifier value used on SubnSet(SMInfo) SMPs.
+
+

SOURCE

+
#define IB_SMINFO_ATTR_MOD_HANDOVER             (CL_NTOH32(0x000001))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_SMINFO_ATTR_MOD_STANDBY

+ +

[top][index]

+

NAME

+
       IB_SMINFO_ATTR_MOD_STANDBY
+
+

DESCRIPTION

+
       Encoded attribute modifier value used on SubnSet(SMInfo) SMPs.
+
+

SOURCE

+
#define IB_SMINFO_ATTR_MOD_STANDBY                      (CL_NTOH32(0x000004))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_SMINFO_STATE_DISCOVERING

+ +

[top][index]

+

NAME

+
       IB_SMINFO_STATE_DISCOVERING
+
+

DESCRIPTION

+
       Encoded state value used in the SMInfo attribute.
+
+

SOURCE

+
#define IB_SMINFO_STATE_DISCOVERING                     1
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_SMINFO_STATE_INIT

+ +

[top][index]

+

NAME

+
       IB_SMINFO_STATE_INIT
+
+

DESCRIPTION

+
       Encoded state value used in the SMInfo attribute.
+
+

SOURCE

+
#define IB_SMINFO_STATE_INIT                                    4
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_SMINFO_STATE_MASTER

+ +

[top][index]

+

NAME

+
       IB_SMINFO_STATE_MASTER
+
+

DESCRIPTION

+
       Encoded state value used in the SMInfo attribute.
+
+

SOURCE

+
#define IB_SMINFO_STATE_MASTER                          3
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_SMINFO_STATE_NOTACTIVE

+ +

[top][index]

+

NAME

+
       IB_SMINFO_STATE_NOTACTIVE
+
+

DESCRIPTION

+
       Encoded state value used in the SMInfo attribute.
+
+

SOURCE

+
#define IB_SMINFO_STATE_NOTACTIVE                       0
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_SMINFO_STATE_STANDBY

+ +

[top][index]

+

NAME

+
       IB_SMINFO_STATE_STANDBY
+
+

DESCRIPTION

+
       Encoded state value used in the SMInfo attribute.
+
+

SOURCE

+
#define IB_SMINFO_STATE_STANDBY                         2
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_SMP_DIRECTION

+ +

[top][index]

+

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))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_SMP_STATUS_MASK

+ +

[top][index]

+

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))
+
+
+
+ +

[Definitions] +IBA Base: Constants/IB_SUBNET_PATH_HOPS_MAX

+ +

[top][index]

+

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
+
+
+
+ +

[Definitions] +IBA Base: Constants/Join States

+ +

[top][index]

+

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
+
+
+
+ +

[Definitions] +IBA Base: Constants/MAD_BLOCK_GRH_SIZE

+ +

[top][index]

+

NAME

+
       MAD_BLOCK_GRH_SIZE
+
+

DESCRIPTION

+
       Size of a MAD datagram, including the GRH.
+
+

SOURCE

+
#define MAD_BLOCK_GRH_SIZE                                      296
+
+
+
+ +

[Definitions] +IBA Base: Constants/MAD_BLOCK_SIZE

+ +

[top][index]

+

NAME

+
       MAD_BLOCK_SIZE
+
+

DESCRIPTION

+
       Size of a non-RMPP MAD datagram.
+
+

SOURCE

+
#define MAD_BLOCK_SIZE                                          256
+
+
+
+ +

[Definitions] +IBA Base: Constants/MAD_RMPP_DATA_SIZE

+ +

[top][index]

+

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)
+
+
+
+ +

[Definitions] +IBA Base: Constants/MAD_RMPP_HDR_SIZE

+ +

[top][index]

+

NAME

+
       MAD_RMPP_HDR_SIZE
+
+

DESCRIPTION

+
       Size of an RMPP header, including the common MAD header.
+
+

SOURCE

+
#define MAD_RMPP_HDR_SIZE                                       36
+
+
+
+ +

[Definitions] +IBA Base: Types/DM_SVC_NAME

+ +

[top][index]

+

NAME

+
       DM_SVC_NAME
+
+

DESCRIPTION

+
       IBA defined Device Management service name (16.3)
+
+

SYNOPSIS

+
#define DM_SVC_NAME                             "DeviceManager.IBTA"
+
+

SEE ALSO

+ +
+ +

[Functions] +IBA Base: Types/ib_class_is_rmpp

+ +

[top][index]

+

NAME

+
       ib_class_is_rmpp
+
+

DESCRIPTION

+
       Indicates if the Class Code supports RMPP
+
+

SYNOPSIS

+
AL_INLINE boolean_t     AL_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

+
+
+
+
+ +

[Functions] +IBA Base: Types/ib_class_is_vendor_specific

+ +

[top][index]

+

NAME

+
       ib_class_is_vendor_specific
+
+

DESCRIPTION

+
       Indicates if the Class Code if a vendor specific class
+
+

SYNOPSIS

+
static inline boolean_t
+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
+
+
+
+ +

[Functions] +IBA Base: Types/ib_class_is_vendor_specific_high

+ +

[top][index]

+

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
+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
+
+
+
+ +

[Functions] +IBA Base: Types/ib_class_is_vendor_specific_low

+ +

[top][index]

+

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
+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
+
+
+
+ +

[Structures] +IBA Base: Types/ib_class_port_info_t

+ +

[top][index]

+

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                              resp_time_val;
+        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.
+
+       resp_time_value
+               Maximum expected response time.
+
+       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
+
+
+
+ +

[Structures] +IBA Base: Types/ib_dm_mad_t

+ +

[top][index]

+

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                hdr;
+        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

+
       hdr
+               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
+
+
+
+ +

[Structures] +IBA Base: Types/ib_field32_t

+ +

[top][index]

+

NAME

+
       ib_field32_t
+
+

DESCRIPTION

+
       Represents a 32-bit field, and allows access as a 32-bit network byte
+       ordered or a 4-byte array.
+
+

SYNOPSIS

+
#include <complib/cl_packon.h>
+typedef union _ib_field32_t
+{
+        net32_t         val;
+        uint8_t         bytes[4];
+
+}       PACK_SUFFIX ib_field32_t;
+#include <complib/cl_packoff.h>
+
+

FIELDS

+
       val
+               Full field value.
+
+       bytes
+               Byte array representing the field.  The byte array provides identical
+               access independently from CPU byte-ordering.
+
+
+
+ +

[Functions] +IBA Base: Types/ib_get_async_event_str

+ +

[top][index]

+

NAME

+
       ib_get_async_event_str
+
+

DESCRIPTION

+
       Returns a string for the specified asynchronous event.
+
+

SYNOPSIS

+
AL_EXPORT const char* AL_API
+ib_get_async_event_str(
+        IN                              ib_async_event_t                        event );
+
+

PARAMETERS

+
       event
+               [in] event value
+
+ RETURN VALUES
+       Pointer to the asynchronous event description string.
+
+

NOTES

+
+
+

SEE ALSO

+ +
+ +

[Functions] +IBA Base: Types/ib_get_err_str

+ +

[top][index]

+

NAME

+
       ib_get_err_str
+
+

DESCRIPTION

+
       Returns a string for the specified status value.
+
+

SYNOPSIS

+
AL_EXPORT const char* AL_API
+ib_get_err_str(
+        IN                              ib_api_status_t                         status );
+
+

PARAMETERS

+
       status
+               [in] status value
+
+ RETURN VALUES
+       Pointer to the status description string.
+
+

NOTES

+
+
+

SEE ALSO

+ +
+ +

[Functions] +IBA Base: Types/ib_get_node_type_str

+ +

[top][index]

+

NAME

+
       ib_get_node_type_str
+
+

DESCRIPTION

+
       Returns a string for the specified node type.
+
+

SYNOPSIS

+
AL_INLINE const char* AL_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
+
+
+
+ +

[Functions] +IBA Base: Types/ib_get_port_state_from_str

+ +

[top][index]

+

NAME

+
       ib_get_port_state_from_str
+
+

DESCRIPTION

+
       Returns a string for the specified port state.
+
+

SYNOPSIS

+
AL_INLINE const uint8_t AL_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
+
+
+
+ +

[Functions] +IBA Base: Types/ib_get_port_state_str

+ +

[top][index]

+

NAME

+
       ib_get_port_state_str
+
+

DESCRIPTION

+
       Returns a string for the specified port state.
+
+

SYNOPSIS

+
AL_INLINE const char* AL_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
+
+
+
+ +

[Functions] +IBA Base: Types/ib_get_qp_type_str

+ +

[top][index]

+

NAME

+
       ib_get_qp_type_str
+
+

DESCRIPTION

+
       Returns a string for the specified QP type
+
+

SYNOPSIS

+
AL_EXPORT const char* AL_API
+ib_get_qp_type_str(
+        IN                              uint8_t                                         qp_type );
+
+

PARAMETERS

+
       qp_type
+               [in] Encoded QP type as defined in the
+ RETURN VALUES
+       Pointer to the QP type string.
+
+

NOTES

+
+
+

SEE ALSO

+
 ib_qp_type_t
+
+
+
+ +

[Functions] +IBA Base: Types/ib_get_wc_status_str

+ +

[top][index]

+

NAME

+
       ib_get_wc_status_str
+
+

DESCRIPTION

+
       Returns a string for the specified work completion status.
+
+

SYNOPSIS

+
AL_EXPORT const char* AL_API
+ib_get_wc_status_str(
+        IN                              ib_wc_status_t                          wc_status );
+
+

PARAMETERS

+
       wc_status
+               [in] work completion status value
+
+ RETURN VALUES
+       Pointer to the work completion status description string.
+
+

NOTES

+
+
+

SEE ALSO

+ +
+ +

[Functions] +IBA Base: Types/ib_get_wc_type_str

+ +

[top][index]

+

NAME

+
       ib_get_wc_type_str
+
+

DESCRIPTION

+
       Returns a string for the specified work completion type.
+
+

SYNOPSIS

+
AL_EXPORT const char* AL_API
+ib_get_wc_type_str(
+        IN                              ib_wc_type_t                            wc_type );
+
+

PARAMETERS

+
       wc_type
+               [in] work completion type value
+
+ RETURN VALUES
+       Pointer to the work completion type description string.
+
+

NOTES

+
+
+

SEE ALSO

+ +
+ +

[Functions] +IBA Base: Types/ib_get_wr_type_str

+ +

[top][index]

+

NAME

+
       ib_get_wr_type_str
+
+

DESCRIPTION

+
       Returns a string for the specified work request type
+
+

SYNOPSIS

+
AL_EXPORT const char* AL_API
+ib_get_wr_type_str(
+        IN                              uint8_t                                         wr_type );
+
+

PARAMETERS

+
       wr_type
+               [in] Encoded work request type as defined in the
+ RETURN VALUES
+       Pointer to the work request type string.
+
+

NOTES

+
+
+

SEE ALSO

+
 ib_wr_type_t
+
+
+
+ +

[Functions] +IBA Base: Types/ib_gid_get_guid

+ +

[top][index]

+

NAME

+
       ib_gid_get_guid
+
+

DESCRIPTION

+
       Gets the guid from a GID.
+
+

SYNOPSIS

+
AL_INLINE ib_net64_t AL_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
+
+
+
+ +

[Functions] +IBA Base: Types/ib_gid_get_subnet_prefix

+ +

[top][index]

+

NAME

+
       ib_gid_get_subnet_prefix
+
+

DESCRIPTION

+
       Gets the subnet prefix from a GID.
+
+

SYNOPSIS

+
AL_INLINE ib_net64_t AL_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
+
+
+
+ +

[Functions] +IBA Base: Types/ib_gid_is_link_local

+ +

[top][index]

+

NAME

+
       ib_gid_is_link_local
+
+

DESCRIPTION

+
       Returns TRUE if the unicast GID scoping indicates link local,
+       FALSE otherwise.
+
+

SYNOPSIS

+
static inline boolean_t
+ib_gid_is_link_local(
+        IN              const   ib_gid_t* const                         p_gid )
+{
+        return( ib_gid_get_subnet_prefix( p_gid ) == 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
+
+
+
+ +

[Functions] +IBA Base: Types/ib_gid_is_site_local

+ +

[top][index]

+

NAME

+
       ib_gid_is_site_local
+
+

DESCRIPTION

+
       Returns TRUE if the unicast GID scoping indicates site local,
+       FALSE otherwise.
+
+

SYNOPSIS

+
static inline boolean_t
+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 link local,
+       FALSE otherwise.
+
+

NOTES

+
+
+

SEE ALSO

+
       ib_gid_t
+
+
+
+ +

[Definitions] +IBA Base: Types/ib_gid_prefix_t

+ +

[top][index]

+

NAME

+
       ib_gid_prefix_t
+
+

DESCRIPTION

+
+
+

SOURCE

+
typedef ib_net64_t              ib_gid_prefix_t;
+
+
+
+ +

[Functions] +IBA Base: Types/ib_gid_set_default

+ +

[top][index]

+

NAME

+
       ib_gid_set_default
+
+

DESCRIPTION

+
       Sets a GID to the default value.
+
+

SYNOPSIS

+
AL_INLINE void AL_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
+
+
+
+ +

[Definitions] +IBA Base: Types/ib_gid_t

+ +

[top][index]

+

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

+ +
+ +

[Structures] +IBA Base: Types/ib_gmp_t

+ +

[top][index]

+

NAME

+
       ib_gmp_t
+
+

DESCRIPTION

+
       IBA defined GMP MAD format. (16.1.1)
+
+

SYNOPSIS

+
#define IB_GMP_DATA_SIZE 200
+
+#include <complib/cl_packon.h>
+typedef struct _ib_gmp
+{
+        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                                 resv2[40];
+        uint8_t                                 data[IB_GMP_DATA_SIZE];
+
+}       PACK_SUFFIX ib_gmp_t;
+#include <complib/cl_packoff.h>
+
+
+
+ +

[Functions] +IBA Base: Types/ib_grh_get_ver_class_flow

+ +

[top][index]

+

NAME

+
       ib_grh_get_ver_class_flow
+
+

DESCRIPTION

+
       Get encoded version, traffic class and flow label in grh
+
+

SYNOPSIS

+
AL_INLINE void AL_API
+ib_grh_get_ver_class_flow(
+        IN              const   ib_net32_t                                      ver_class_flow,
+                OUT                     uint8_t* const                          p_ver OPTIONAL,
+                OUT                     uint8_t* const                          p_tclass OPTIONAL,
+                OUT                     net32_t* const                          p_flow_lbl OPTIONAL )
+{
+        ib_net32_t tmp_ver_class_flow;
+
+        tmp_ver_class_flow = cl_ntoh32( ver_class_flow );
+
+        if (p_ver)
+                *p_ver = (uint8_t)(tmp_ver_class_flow >> 28);
+
+        if (p_tclass)
+                *p_tclass = (uint8_t)(tmp_ver_class_flow >> 20);
+
+        if (p_flow_lbl)
+                *p_flow_lbl = (ver_class_flow & CL_HTON32( 0x000FFFFF ));
+}
+
+

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
+
+
+
+ +

[Functions] +IBA Base: Types/ib_grh_set_ver_class_flow

+ +

[top][index]

+

NAME

+
       ib_grh_set_ver_class_flow
+
+

DESCRIPTION

+
       Set encoded version, traffic class and flow label in grh
+
+

SYNOPSIS

+
AL_INLINE ib_net32_t AL_API
+ib_grh_set_ver_class_flow(
+        IN              const   uint8_t                                         ver,
+        IN              const   uint8_t                                         tclass,
+        IN              const   net32_t                                         flow_lbl )
+{
+        ib_net32_t              ver_class_flow;
+
+        ver_class_flow = cl_hton32( (ver << 28) | (tclass << 20) );
+        ver_class_flow |= (flow_lbl & CL_HTON32( 0x000FFFFF ));
+        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
+
+
+
+ +

[Structures] +IBA Base: Types/ib_grh_t

+ +

[top][index]

+

NAME

+
       ib_grh_t
+
+

DESCRIPTION

+
       Global route header information received with unreliable datagram messages
+
+

SYNOPSIS

+
#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>
+
+
+
+ +

[Structures] +IBA Base: Types/ib_guid_info_t

+ +

[top][index]

+

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>
+
+
+
+ +

[Functions] +IBA Base: Types/ib_inform_get_dev_id

+ +

[top][index]

+

NAME

+
       ib_inform_get_dev_id
+
+

DESCRIPTION

+
       Retrieves the device ID from a vendor specific inform trap.
+
+

SYNOPSIS

+
AL_INLINE uint16_t AL_API
+ib_inform_get_dev_id(
+        IN              const   ib_inform_info_t* const         p_inform_info )
+{
+        return ib_inform_get_trap_num( p_inform_info );
+}
+
+

PARAMETERS

+
       p_inform_info
+               [in] Pointer to the inform info structure whose
+               device ID to return.
+
+ RETURN VALUES
+       Returns the vendor ID of the inform info, in host byte order.
+
+

SEE ALSO

+
       ib_inform_info_t, ib_inform_set_dev_id
+
+
+
+ +

[Functions] +IBA Base: Types/ib_inform_get_prod_type

+ +

[top][index]

+

NAME

+
       ib_inform_get_prod_type
+
+

DESCRIPTION

+
       Retrieves the producer type from an inform info structure.
+
+

SYNOPSIS

+
AL_INLINE uint32_t AL_API
+ib_inform_get_prod_type(
+        IN              const   ib_inform_info_t* const         p_inform_info )
+{
+        return (cl_ntoh32( p_inform_info->combo3 ) >> 8);
+}
+
+

PARAMETERS

+
       p_inform_info
+               [in] Pointer to the inform info structure whose
+               prducer type to return.
+
+ RETURN VALUES
+       Returns the producer type of the infrom info, in host byte order.
+
+

SEE ALSO

+
       ib_inform_info_t, ib_inform_set_prod_type
+
+
+
+ +

[Functions] +IBA Base: Types/ib_inform_get_qpn

+ +

[top][index]

+

NAME

+
       ib_inform_get_qpn
+
+

DESCRIPTION

+
       Retrieves the QPN from an inform info structure.
+
+

SYNOPSIS

+
AL_INLINE net32_t AL_API
+ib_inform_get_qpn(
+        IN              const   ib_inform_info_t* const         p_inform_info )
+{
+        return (p_inform_info->combo2 & CL_NTOH32( 0x00FFFFFF ));
+}
+
+

PARAMETERS

+
       p_inform_info
+               [in] Pointer to the inform info structure whose
+               QPN to return.
+
+ RETURN VALUES
+       Returns the QPN of the infrom info.
+
+

SEE ALSO

+
       ib_inform_info_t, ib_inform_set_qpn
+
+
+
+ +

[Functions] +IBA Base: Types/ib_inform_get_resp_time_val

+ +

[top][index]

+

NAME

+
       ib_inform_get_resp_time_val
+
+

DESCRIPTION

+
       Retrieves the response time value from an inform info structure.
+
+

SYNOPSIS

+
AL_INLINE uint8_t AL_API
+ib_inform_get_resp_time_val(
+        IN              const   ib_inform_info_t* const         p_inform_info )
+{
+        return (uint8_t)(cl_ntoh32( p_inform_info->combo2 ) >> 27);
+}
+
+

PARAMETERS

+
       p_inform_info
+               [in] Pointer to the inform info structure whose
+               response time value to return.
+
+ RETURN VALUES
+       Returns the response time value of the infrom info.
+
+

SEE ALSO

+
       ib_inform_info_t, ib_inform_set_resp_time_val
+
+
+
+ +

[Functions] +IBA Base: Types/ib_inform_get_trap_num

+ +

[top][index]

+

NAME

+
       ib_inform_get_trap_num
+
+

DESCRIPTION

+
       Retrieves the trap number from an inform info structure.
+
+

SYNOPSIS

+
AL_INLINE uint16_t AL_API
+ib_inform_get_trap_num(
+        IN              const   ib_inform_info_t* const         p_inform_info )
+{
+        return cl_ntoh16( p_inform_info->combo1 );
+}
+
+

PARAMETERS

+
       p_inform_info
+               [in] Pointer to the inform info structure whose
+               trap number to return.
+
+ RETURN VALUES
+       Returns the trap number of the infrom info, in host byte order.
+
+

SEE ALSO

+
       ib_inform_info_t, ib_inform_set_trap_num
+
+
+
+ +

[Functions] +IBA Base: Types/ib_inform_get_vend_id

+ +

[top][index]

+

NAME

+
       ib_inform_get_vend_id
+
+

DESCRIPTION

+
       Retrieves the vendor ID from an inform info structure.
+
+

SYNOPSIS

+
AL_INLINE uint32_t AL_API
+ib_inform_get_vend_id(
+        IN              const   ib_inform_info_t* const         p_inform_info )
+{
+        return ib_inform_get_prod_type( p_inform_info );
+}
+
+

PARAMETERS

+
       p_inform_info
+               [in] Pointer to the inform info structure whose
+               vendor ID to return.
+
+ RETURN VALUES
+       Returns the vendor ID of the infrom info, in host byte order.
+
+

SEE ALSO

+
       ib_inform_info_t, ib_inform_set_vend_id
+
+
+
+ +

[Structures] +IBA Base: Types/ib_inform_info_record_t

+ +

[top][index]

+

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;
+        net16_t                                 subscriber_enum;
+        uint16_t                                reserved[3];
+        ib_inform_info_t                inform_info;
+
+}       PACK_SUFFIX ib_inform_info_record_t;
+#include <complib/cl_packoff.h>
+
+
+
+ +

[Functions] +IBA Base: Types/ib_inform_set_dev_id

+ +

[top][index]

+

NAME

+
       ib_inform_set_dev_id
+
+

DESCRIPTION

+
       Sets the producer type of a vendor specific inform trap.
+
+

SYNOPSIS

+
AL_INLINE void AL_API
+ib_inform_set_dev_id(
+        IN      OUT                     ib_inform_info_t* const         p_inform_info,
+        IN              const   uint16_t                                        dev_id )
+{
+        ib_inform_set_trap_num( p_inform_info, dev_id );
+}
+
+

PARAMETERS

+
       p_inform_info
+               [in/out] Pointer to the inform info structure
+               whose device ID to set.
+
+       dev_id
+               [in] Device ID of inform trap.
+
+ RETURN VALUES
+       This function does not return a value.
+
+

SEE ALSO

+
       ib_inform_info_t, ib_inform_get_dev_id
+
+
+
+ +

[Functions] +IBA Base: Types/ib_inform_set_prod_type

+ +

[top][index]

+

NAME

+
       ib_inform_set_prod_type
+
+

DESCRIPTION

+
       Sets the producer type of an inform info structure.
+
+

SYNOPSIS

+
AL_INLINE void AL_API
+ib_inform_set_prod_type(
+        IN      OUT                     ib_inform_info_t* const         p_inform_info,
+        IN              const   uint32_t                                        prod_type )
+{
+        p_inform_info->combo3 = cl_hton32( prod_type << 8 );
+}
+
+

PARAMETERS

+
       p_inform_info
+               [in/out] Pointer to the inform info structure
+               whose producer type to set.
+
+       prod_type
+               [in] Producer type of inform trap.
+
+ RETURN VALUES
+       This function does not return a value.
+
+

SEE ALSO

+
       ib_inform_info_t, ib_inform_get_prod_type
+
+
+
+ +

[Functions] +IBA Base: Types/ib_inform_set_qpn

+ +

[top][index]

+

NAME

+
       ib_inform_set_qpn
+
+

DESCRIPTION

+
       Sets the QPN of an inform info structure.
+
+

SYNOPSIS

+
AL_INLINE void AL_API
+ib_inform_set_qpn(
+        IN      OUT                     ib_inform_info_t* const         p_inform_info,
+        IN              const   net32_t                                         qpn )
+{
+        p_inform_info->combo2 &= CL_NTOH32( 0xFF000000 );
+        p_inform_info->combo2 |= (qpn & CL_NTOH32( 0x00FFFFFF ));
+}
+
+

PARAMETERS

+
       p_inform_info
+               [in/out] Pointer to the inform info structure
+               whose QPN to set.
+
+       qpn
+               [in] QPN of the inform info.
+
+ RETURN VALUES
+       This function does not return a value.
+
+

SEE ALSO

+
       ib_inform_info_t, ib_inform_get_qpn
+
+
+
+ +

[Functions] +IBA Base: Types/ib_inform_set_resp_time_val

+ +

[top][index]

+

NAME

+
       ib_inform_set_resp_time_val
+
+

DESCRIPTION

+
       Sets the response time value of an inform info structure.
+
+

SYNOPSIS

+
AL_INLINE void AL_API
+ib_inform_set_resp_time_val(
+        IN      OUT                     ib_inform_info_t* const         p_inform_info,
+        IN              const   uint8_t                                         resp_time_val )
+{
+        uint32_t        val;
+
+        val = cl_ntoh32( p_inform_info->combo2 );
+        val &= 0x07FFFFFF;
+        val |= (resp_time_val << 27);
+        p_inform_info->combo2 = cl_hton32( val );
+}
+
+

PARAMETERS

+
       p_inform_info
+               [in/out] Pointer to the inform info structure
+               whose response time value to set.
+
+       resp_time_val
+               [in] Response time value of the inform info.
+
+ RETURN VALUES
+       This function does not return a value.
+
+

SEE ALSO

+
       ib_inform_info_t, ib_inform_get_resp_time_val
+
+
+
+ +

[Functions] +IBA Base: Types/ib_inform_set_trap_num

+ +

[top][index]

+

NAME

+
       ib_inform_set_trap_num
+
+

DESCRIPTION

+
       Sets the trap number of an inform info structure.
+
+

SYNOPSIS

+
AL_INLINE void AL_API
+ib_inform_set_trap_num(
+        IN      OUT                     ib_inform_info_t* const         p_inform_info,
+        IN              const   uint16_t                                        trap_num )
+{
+        p_inform_info->combo1 = cl_hton16( trap_num );
+}
+
+

PARAMETERS

+
       p_inform_info
+               [in/out] Pointer to the inform info structure
+               whose trap number to set.
+
+       trap_num
+               [in] Trap number to set.
+
+ RETURN VALUES
+       This function does not return a value.
+
+

SEE ALSO

+
       ib_inform_info_t, ib_inform_get_trap_num
+
+
+
+ +

[Functions] +IBA Base: Types/ib_inform_set_vend_id

+ +

[top][index]

+

NAME

+
       ib_inform_set_vend_id
+
+

DESCRIPTION

+
       Sets the vendor ID of an inform info structure.
+
+

SYNOPSIS

+
AL_INLINE void AL_API
+ib_inform_set_vend_id(
+        IN      OUT                     ib_inform_info_t* const         p_inform_info,
+        IN              const   uint32_t                                        vend_id )
+{
+        ib_inform_set_prod_type( p_inform_info, vend_id );
+}
+
+

PARAMETERS

+
       p_inform_info
+               [in/out] Pointer to the inform info structure
+               whose vendor ID to set.
+
+       vend_id
+               [in] Vendor ID of inform trap.
+
+ RETURN VALUES
+       This function does not return a value.
+
+

SEE ALSO

+
       ib_mad_inform_info_t, ib_inform_get_vend_id
+
+
+
+ +

[Structures] +IBA Base: Types/ib_ioc_profile_t

+ +

[top][index]

+

NAME

+
       ib_ioc_profile_t
+
+

DESCRIPTION

+
       IBA defined IO Controller profile structure (16.3.3.4)
+
+

SYNOPSIS

+
#include <complib/cl_packon.h>
+typedef __declspec(align(8)) 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
+
+
+
+ +

[Functions] +IBA Base: Types/ib_iou_info_diag_dev_id

+ +

[top][index]

+

NAME

+
       ib_iou_info_diag_dev_id
+
+

DESCRIPTION

+
       Returns the DiagDeviceID.
+
+

SYNOPSIS

+
AL_INLINE uint8_t AL_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
+
+
+
+ +

[Functions] +IBA Base: Types/ib_iou_info_option_rom

+ +

[top][index]

+

NAME

+
       ib_iou_info_option_rom
+
+

DESCRIPTION

+
       Returns the OptionROM.
+
+

SYNOPSIS

+
AL_INLINE uint8_t AL_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
+
+
+
+ +

[Structures] +IBA Base: Types/ib_iou_info_t

+ +

[top][index]

+

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
+#define IB_DM_MAX_CTRL                  0xFF;
+
+        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
+
+
+
+ +

[Structures] +IBA Base: Types/ib_lft_record_t

+ +

[top][index]

+

NAME

+
       ib_lft_record_t
+
+

DESCRIPTION

+
       IBA defined LinearForwardingTable. (14.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>
+
+
+
+ +

[Functions] +IBA Base: Types/ib_mad_init_new

+ +

[top][index]

+

NAME

+
       ib_mad_init_new
+
+

DESCRIPTION

+
       Initializes a MAD common header.
+
+

SYNOPSIS

+
AL_INLINE void AL_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
+
+
+
+ +

[Functions] +IBA Base: Types/ib_mad_init_response

+ +

[top][index]

+

NAME

+
       ib_mad_init_response
+
+

DESCRIPTION

+
       Initializes a MAD common header as a response.
+
+

SYNOPSIS

+
AL_INLINE void AL_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
+
+
+
+ +

[Functions] +IBA Base: Types/ib_mad_is_response

+ +

[top][index]

+

NAME

+
       ib_mad_is_response
+
+

DESCRIPTION

+
       Returns TRUE if the MAD is a response ('R' bit set),
+       FALSE otherwise.
+
+

SYNOPSIS

+
AL_INLINE boolean_t AL_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
+
+
+
+ +

[Structures] +IBA Base: Types/ib_mad_t

+ +

[top][index]

+

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

+ +
+ +

[Functions] +IBA Base: Types/ib_member_get_scope

+ +

[top][index]

+

NAME

+
       ib_member_get_scope
+
+

DESCRIPTION

+
       Get encoded MGID scope
+
+

SYNOPSIS

+
AL_INLINE uint8_t AL_API
+ib_member_get_scope(
+        IN              const   uint8_t                                         scope_state )
+{
+        return (scope_state >> 4);
+}
+
+

PARAMETERS

+
       scope_state
+               [in] the scope and state
+
+ RETURN VALUES
+       Encoded scope.
+
+

SEE ALSO

+
       ib_member_rec_t
+
+
+
+ +

[Functions] +IBA Base: Types/ib_member_get_scope_state

+ +

[top][index]

+

NAME

+
       ib_member_get_scope_state
+
+

DESCRIPTION

+
       Get encoded MGID scope and JoinState
+
+

SYNOPSIS

+
AL_INLINE void AL_API
+ib_member_get_scope_state(
+        IN              const   uint8_t                                         scope_state,
+                OUT                     uint8_t* const                          p_scope,
+                OUT                     uint8_t* const                          p_state )
+{
+        if (p_scope)
+                *p_scope = ib_member_get_scope( scope_state );
+
+        if (p_state)
+                *p_state = ib_member_get_state( scope_state );
+}
+
+

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
+
+
+
+ +

[Functions] +IBA Base: Types/ib_member_get_sl_flow_hop

+ +

[top][index]

+

NAME

+
       ib_member_get_sl_flow_hop
+
+

DESCRIPTION

+
       Get encoded sl flow label and hop limit
+
+

SYNOPSIS

+
AL_INLINE void AL_API
+ib_member_get_sl_flow_hop(
+        IN              const   ib_net32_t                                      sl_flow_hop,
+                OUT                     uint8_t* const                          p_sl OPTIONAL,
+                OUT                     net32_t* const                          p_flow_lbl OPTIONAL,
+                OUT                     uint8_t* const                          p_hop OPTIONAL )
+{
+        ib_net32_t tmp_sl_flow_hop;
+
+        if (p_sl)
+                *p_sl = (uint8_t)(sl_flow_hop & 0x0f);
+
+        tmp_sl_flow_hop = sl_flow_hop >> 4;
+
+        if (p_flow_lbl)
+                *p_flow_lbl = (uint32_t)(tmp_sl_flow_hop & 0xffffff);
+
+        tmp_sl_flow_hop = tmp_sl_flow_hop >> 20;
+
+        if (p_hop)
+                *p_hop = (uint8_t)(tmp_sl_flow_hop & 0xff);
+}
+
+

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
+
+
+
+ +

[Functions] +IBA Base: Types/ib_member_get_state

+ +

[top][index]

+

NAME

+
       ib_member_get_state
+
+

DESCRIPTION

+
       Get encoded MGID JoinState
+
+

SYNOPSIS

+
AL_INLINE uint8_t AL_API
+ib_member_get_state(
+        IN              const   uint8_t                                         scope_state )
+{
+        return (scope_state & 0x0f);
+}
+
+

PARAMETERS

+
       scope_state
+               [in] the scope and state
+
+ RETURN VALUES
+               Encoded JoinState
+
+

SEE ALSO

+
       ib_member_rec_t
+
+
+
+ +

[Structures] +IBA Base: Types/ib_member_rec_t

+ +

[top][index]

+

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;
+        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.
+
+       requestor_gid
+               GID of the endpoint making this request on hehave of port_gid.
+
+       qkey
+               Q_Key to be used 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

+ +
+ +

[Functions] +IBA Base: Types/ib_member_set_join_state

+ +

[top][index]

+

NAME

+
       ib_member_set_join_state
+
+

DESCRIPTION

+
       Set JoinState
+
+

SYNOPSIS

+
AL_INLINE void AL_API
+ib_member_set_join_state(
+        IN      OUT                     ib_member_rec_t                         *p_mc_rec,
+        IN              const   uint8_t                                         state )
+{
+        p_mc_rec->scope_state &= 0xF0;
+        p_mc_rec->scope_state |= (state & 0x0F);
+}
+
+

PARAMETERS

+
       p_mc_rec
+               [in] pointer to the member record
+
+       state
+               [in] the JoinState
+
+ RETURN VALUES
+       NONE
+
+

NOTES

+
+
+

SEE ALSO

+
       ib_member_rec_t
+
+
+
+ +

[Functions] +IBA Base: Types/ib_member_set_scope

+ +

[top][index]

+

NAME

+
       ib_member_set_scope
+
+

DESCRIPTION

+
       Set encoded scope of a MCR.
+
+

SYNOPSIS

+
AL_INLINE void AL_API
+ib_member_set_scope(
+        IN      OUT                     uint8_t* const                          p_scope_state,
+        IN              const   uint8_t                                         scope )
+{
+        CL_ASSERT( scope <= 0x0F );
+        /* Scope is MS 4-bits. */
+        *p_scope_state &= 0xF0;
+        *p_scope_state |= (scope << 4);
+}
+
+

PARAMETERS

+
       scope_state
+               [in/out] Pointer to the MCR scope_state field.
+
+       scope
+               [in] The desired scope.
+
+ RETURN VALUES
+       This function does not return a value.
+
+

SEE ALSO

+
       ib_member_rec_t
+
+
+
+ +

[Functions] +IBA Base: Types/ib_member_set_scope_state

+ +

[top][index]

+

NAME

+
       ib_member_set_scope_state
+
+

DESCRIPTION

+
       Set encoded version, MGID scope and JoinState
+
+

SYNOPSIS

+
AL_INLINE uint8_t AL_API
+ib_member_set_scope_state(
+        IN              const   uint8_t                                         scope,
+        IN              const   uint8_t                                         state )
+{
+        /* Scope is MS 4-bits, state is LS 4-bits */
+        return ((scope << 4) | (state & 0xF));
+}
+
+

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
+
+
+
+ +

[Functions] +IBA Base: Types/ib_member_set_sl_flow_hop

+ +

[top][index]

+

NAME

+
       ib_member_set_sl_flow_hop
+
+

DESCRIPTION

+
       Set encoded version, sl flow and hop
+
+

SYNOPSIS

+
AL_INLINE ib_net32_t AL_API
+ib_member_set_sl_flow_hop(
+        IN              const   uint8_t                                         sl,
+        IN              const   net32_t                                         flow_lbl,
+        IN              const   uint8_t                                         hop_limit )
+{
+        ib_net32_t              sl_flow_hop;
+
+        sl_flow_hop = sl;
+        sl_flow_hop <<= 20;
+        sl_flow_hop |= (cl_ntoh32( flow_lbl ) & 0x000FFFFF);
+        sl_flow_hop <<= 8;
+        sl_flow_hop |= hop_limit;
+        return cl_hton32(sl_flow_hop);
+}
+
+

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 sl flow label and hop limit
+
+

NOTES

+
+
+

SEE ALSO

+
       ib_member_rec_t
+
+
+
+ +

[Functions] +IBA Base: Types/ib_member_set_state

+ +

[top][index]

+

NAME

+
       ib_member_set_state
+
+

DESCRIPTION

+
       Set encoded JoinState of a MCR.
+
+

SYNOPSIS

+
AL_INLINE void AL_API
+ib_member_set_state(
+        IN      OUT                     uint8_t* const                          p_scope_state,
+        IN              const   uint8_t                                         state )
+{
+        CL_ASSERT( state <= 0x0F );
+        /* State is LS 4-bits. */
+        *p_scope_state &= 0x0F;
+        *p_scope_state |= (state & 0x0F);
+}
+
+

PARAMETERS

+
       scope_state
+               [in/out] Pointer to the MCR scope_state field to modify.
+
+       state
+               [in] the JoinState
+
+ RETURN VALUES
+       This function does not return a value.
+
+

SEE ALSO

+
       ib_member_rec_t
+
+
+
+ +

[Definitions] +IBA Base: Types/ib_net16_t

+ +

[top][index]

+

NAME

+
       ib_net16_t
+
+

DESCRIPTION

+
       Defines the network ordered type for 16-bit values.
+
+

SOURCE

+
typedef uint16_t        ib_net16_t;
+
+
+
+ +

[Definitions] +IBA Base: Types/ib_net32_t

+ +

[top][index]

+

NAME

+
       ib_net32_t
+
+

DESCRIPTION

+
       Defines the network ordered type for 32-bit values.
+
+

SOURCE

+
typedef uint32_t        ib_net32_t;
+
+
+
+ +

[Definitions] +IBA Base: Types/ib_net64_t

+ +

[top][index]

+

NAME

+
       ib_net64_t
+
+

DESCRIPTION

+
       Defines the network ordered type for 64-bit values.
+
+

SOURCE

+
typedef uint64_t        ib_net64_t;
+
+
+
+ +

[Functions] +IBA Base: Types/ib_node_info_get_local_port_num

+ +

[top][index]

+

NAME

+
       ib_node_info_get_local_port_num
+
+

DESCRIPTION

+
       Gets a the local port number from the NodeInfo attribute.
+
+

SYNOPSIS

+
AL_INLINE uint8_t AL_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
+
+
+
+ +

[Functions] +IBA Base: Types/ib_node_info_get_vendor_id

+ +

[top][index]

+

NAME

+
       ib_node_info_get_vendor_id
+
+

DESCRIPTION

+
       Gets the VendorID from the NodeInfo attribute.
+
+

SYNOPSIS

+
AL_INLINE ib_net32_t AL_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
+
+
+
+ +

[Structures] +IBA Base: Types/ib_node_info_t

+ +

[top][index]

+

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>
+
+
+
+ +

[Functions] +IBA Base: Types/ib_notice_get_count

+ +

[top][index]

+

NAME

+
       ib_notice_get_count
+
+

DESCRIPTION

+
       Retrieves the notice toggle count from a notice trap.
+
+

SYNOPSIS

+
AL_INLINE boolean_t AL_API
+ib_notice_get_count(
+        IN              const   ib_mad_notice_attr_t* const     p_notice_attr )
+{
+        return ((cl_ntoh16( p_notice_attr->combo3 ) & 0xFFFE) >> 1);
+}
+
+

PARAMETERS

+
       p_notice_attr
+               [in] Pointer to the notice attribute structure whose
+               notice toggle count to return.
+
+ RETURN VALUES
+       Returns the notice toggle count of the notice.
+
+

SEE ALSO

+
       ib_mad_notice_attr_t, ib_notice_set_count
+
+
+
+ +

[Functions] +IBA Base: Types/ib_notice_get_dev_id

+ +

[top][index]

+

NAME

+
       ib_notice_get_dev_id
+
+

DESCRIPTION

+
       Retrieves the device ID from a vendor specific notice trap.
+
+

SYNOPSIS

+
AL_INLINE uint16_t AL_API
+ib_notice_get_dev_id(
+        IN              const   ib_mad_notice_attr_t* const     p_notice_attr )
+{
+        return ib_notice_get_trap_num( p_notice_attr );
+}
+
+

PARAMETERS

+
       p_notice_attr
+               [in] Pointer to the notice attribute structure whose
+               device ID to return.
+
+ RETURN VALUES
+       Returns the vendor ID of the notice, in host byte order.
+
+

SEE ALSO

+
       ib_mad_notice_attr_t, ib_notice_set_dev_id
+
+
+
+ +

[Functions] +IBA Base: Types/ib_notice_get_generic

+ +

[top][index]

+

NAME

+
       ib_notice_get_generic
+
+

DESCRIPTION

+
       Retrieves whether a notice trap is generic.
+
+

SYNOPSIS

+
AL_INLINE boolean_t AL_API
+ib_notice_get_generic(
+        IN              const   ib_mad_notice_attr_t* const     p_notice_attr )
+{
+        if( cl_ntoh32( p_notice_attr->combo1 ) & 0x00000001 )
+                return TRUE;
+        return FALSE;
+}
+
+

PARAMETERS

+
       p_notice_attr
+               [in] Pointer to the notice attribute structure for which to return
+               whether it is generic or not.
+
+ RETURN VALUES
+       Returns TRUE if the notice is generic.
+
+       Returns FALSE if the notice is vendor specific.
+
+

SEE ALSO

+
       ib_mad_notice_attr_t, ib_notice_set_generic
+
+
+
+ +

[Functions] +IBA Base: Types/ib_notice_get_prod_type

+ +

[top][index]

+

NAME

+
       ib_notice_get_prod_type
+
+

DESCRIPTION

+
       Retrieves the producer type from a generic notice trap.
+
+

SYNOPSIS

+
AL_INLINE uint32_t AL_API
+ib_notice_get_prod_type(
+        IN              const   ib_mad_notice_attr_t* const     p_notice_attr )
+{
+        return (cl_ntoh32( p_notice_attr->combo1 ) >> 8);
+}
+
+

PARAMETERS

+
       p_notice_attr
+               [in] Pointer to the notice attribute structure whose
+               prducer type to return.
+
+ RETURN VALUES
+       Returns the producer type of the notice, in host byte order.
+
+

SEE ALSO

+
       ib_mad_notice_attr_t, ib_notice_set_prod_type
+
+
+
+ +

[Functions] +IBA Base: Types/ib_notice_get_toggle

+ +

[top][index]

+

NAME

+
       ib_notice_get_toggle
+
+

DESCRIPTION

+
       Retrieves the notice toggle bit from a notice trap.
+
+

SYNOPSIS

+
AL_INLINE boolean_t AL_API
+ib_notice_get_toggle(
+        IN              const   ib_mad_notice_attr_t* const     p_notice_attr )
+{
+        return (cl_ntoh16( p_notice_attr->combo3 ) & 0x0001);
+}
+
+

PARAMETERS

+
       p_notice_attr
+               [in] Pointer to the notice attribute structure whose
+               notice toggle bit value to return.
+
+ RETURN VALUES
+       Returns TRUE if the notice toggle bit of the notice is set.
+
+       Returns FALSE otherwise.
+
+

SEE ALSO

+
       ib_mad_notice_attr_t, ib_notice_set_toggle
+
+
+
+ +

[Functions] +IBA Base: Types/ib_notice_get_trap_num

+ +

[top][index]

+

NAME

+
       ib_notice_get_trap_num
+
+

DESCRIPTION

+
       Retrieves the trap number from a generic notice trap.
+
+

SYNOPSIS

+
AL_INLINE uint16_t AL_API
+ib_notice_get_trap_num(
+        IN              const   ib_mad_notice_attr_t* const     p_notice_attr )
+{
+        return cl_ntoh16( p_notice_attr->combo2 );
+}
+
+

PARAMETERS

+
       p_notice_attr
+               [in] Pointer to the notice attribute structure whose
+               trap number to return.
+
+ RETURN VALUES
+       Returns the vendor ID of the notice, in host byte order.
+
+

SEE ALSO

+
       ib_mad_notice_attr_t, ib_notice_set_trap_num
+
+
+
+ +

[Functions] +IBA Base: Types/ib_notice_get_type

+ +

[top][index]

+

NAME

+
       ib_notice_get_type
+
+

DESCRIPTION

+
       Retrieves the type of a notice trap.
+
+

SYNOPSIS

+
AL_INLINE uint8_t AL_API
+ib_notice_get_type(
+        IN              const   ib_mad_notice_attr_t* const     p_notice_attr )
+{
+        return (uint8_t)((cl_ntoh32( p_notice_attr->combo1 ) >> 1) & 0x0000007F);
+}
+
+

PARAMETERS

+
       p_notice_attr
+               [in] Pointer to the notice attribute structure whose type to return.
+
+ RETURN VALUES
+       Returns the type of the notice.
+
+

SEE ALSO

+
       ib_mad_notice_attr_t, ib_notice_set_type
+
+
+
+ +

[Functions] +IBA Base: Types/ib_notice_get_vend_id

+ +

[top][index]

+

NAME

+
       ib_notice_get_vend_id
+
+

DESCRIPTION

+
       Retrieves the vendor ID from a vendor specific notice trap.
+
+

SYNOPSIS

+
AL_INLINE uint32_t AL_API
+ib_notice_get_vend_id(
+        IN              const   ib_mad_notice_attr_t* const     p_notice_attr )
+{
+        return ib_notice_get_prod_type( p_notice_attr );
+}
+
+

PARAMETERS

+
       p_notice_attr
+               [in] Pointer to the notice attribute structure whose
+               vendor ID to return.
+
+ RETURN VALUES
+       Returns the vendor ID of the notice, in host byte order.
+
+

SEE ALSO

+
       ib_mad_notice_attr_t, ib_notice_set_vend_id
+
+
+
+ +

[Functions] +IBA Base: Types/ib_notice_set_count

+ +

[top][index]

+

NAME

+
       ib_notice_set_count
+
+

DESCRIPTION

+
       Sets the toggle count of a notice trap.
+
+

SYNOPSIS

+
AL_INLINE void AL_API
+ib_notice_set_count(
+        IN      OUT                     ib_mad_notice_attr_t* const     p_notice_attr,
+        IN              const   uint16_t                                        toggle_cnt )
+{
+        uint16_t        val;
+        val = cl_ntoh16( p_notice_attr->combo3 );
+        val &= 0x0001;
+        val |= (toggle_cnt << 1);
+        p_notice_attr->combo3 = cl_hton16( val );
+}
+
+

PARAMETERS

+
       p_notice_attr
+               [in/out] Pointer to the notice attribute structure
+               whose device ID to set.
+
+       toggle_cnt
+               [in] Toggle count value of the notice.
+
+ RETURN VALUES
+       This function does not return a value.
+
+

SEE ALSO

+
       ib_mad_notice_attr_t, ib_notice_get_count
+
+
+
+ +

[Functions] +IBA Base: Types/ib_notice_set_dev_id

+ +

[top][index]

+

NAME

+
       ib_notice_set_dev_id
+
+

DESCRIPTION

+
       Sets the producer type of a vendor specific notice trap.
+
+

SYNOPSIS

+
AL_INLINE void AL_API
+ib_notice_set_dev_id(
+        IN      OUT                     ib_mad_notice_attr_t* const     p_notice_attr,
+        IN              const   uint16_t                                        dev_id )
+{
+        ib_notice_set_trap_num( p_notice_attr, dev_id );
+}
+
+

PARAMETERS

+
       p_notice_attr
+               [in/out] Pointer to the notice attribute structure
+               whose device ID to set.
+
+       dev_id
+               [in] Device ID of notice trap.
+
+ RETURN VALUES
+       This function does not return a value.
+
+

SEE ALSO

+
       ib_mad_notice_attr_t, ib_notice_get_dev_id
+
+
+
+ +

[Functions] +IBA Base: Types/ib_notice_set_generic

+ +

[top][index]

+

NAME

+
       ib_notice_set_generic
+
+

DESCRIPTION

+
       Sets whether a notice trap is generic.
+
+

SYNOPSIS

+
AL_INLINE void AL_API
+ib_notice_set_generic(
+        IN      OUT                     ib_mad_notice_attr_t* const     p_notice_attr,
+        IN              const   boolean_t                                       is_generic )
+{
+        uint32_t        val;
+
+        val = cl_ntoh32( p_notice_attr->combo1 );
+        if( is_generic )
+                val |= 0x00000001;
+        else
+                val &= 0xFFFFFFFE;
+        p_notice_attr->combo1 = cl_hton32( val );
+}
+
+

PARAMETERS

+
       p_notice_attr
+               [in/out] Pointer to the notice attribute structure for which to set
+               the generic bit.
+
+       is_generic
+               [in] TRUE if the notice is generic, FALSE if vendor specific.
+
+ RETURN VALUES
+       This function does not return a value.
+
+

SEE ALSO

+
       ib_mad_notice_attr_t, ib_notice_get_generic
+
+
+
+ +

[Functions] +IBA Base: Types/ib_notice_set_prod_type

+ +

[top][index]

+

NAME

+
       ib_notice_set_prod_type
+
+

DESCRIPTION

+
       Sets the producer type of a generic notice trap.
+
+

SYNOPSIS

+
AL_INLINE void AL_API
+ib_notice_set_prod_type(
+        IN      OUT                     ib_mad_notice_attr_t* const     p_notice_attr,
+        IN              const   uint32_t                                        prod_type )
+{
+        uint32_t        val;
+
+        val = cl_ntoh32( p_notice_attr->combo1 );
+        /* Clear the type. */
+        val &= 0x000000FF;
+        /* Set new value. */
+        val |= (prod_type << 8);
+        p_notice_attr->combo1 = cl_hton32( val );
+}
+
+

PARAMETERS

+
       p_notice_attr
+               [in/out] Pointer to the notice attribute structure
+               whose producer type to set.
+
+       prod_type
+               [in] Producer type of notice trap.
+
+ RETURN VALUES
+       This function does not return a value.
+
+

SEE ALSO

+
       ib_mad_notice_attr_t, ib_notice_get_prod_type
+
+
+
+ +

[Functions] +IBA Base: Types/ib_notice_set_toggle

+ +

[top][index]

+

NAME

+
       ib_notice_set_toggle
+
+

DESCRIPTION

+
       Sets the notice toggle bit of a notice trap.
+
+

SYNOPSIS

+
AL_INLINE void AL_API
+ib_notice_set_toggle(
+        IN      OUT                     ib_mad_notice_attr_t* const     p_notice_attr,
+        IN              const   boolean_t                                       toggle_val )
+{
+        uint16_t        val;
+        val = cl_ntoh16( p_notice_attr->combo3 );
+        if( toggle_val )
+                val |= 0x0001;
+        else
+                val &= 0xFFFE;
+        p_notice_attr->combo3 = cl_hton16( val );
+}
+
+

PARAMETERS

+
       p_notice_attr
+               [in/out] Pointer to the notice attribute structure
+               whose notice toggle bit to set or clear.
+
+       toggle_val
+               [in] Boolean value indicating whether the toggle bit of the notice
+               should be set or cleared.
+
+ RETURN VALUES
+       This function does not return a value.
+
+

SEE ALSO

+
       ib_mad_notice_attr_t, ib_notice_get_toggle
+
+
+
+ +

[Functions] +IBA Base: Types/ib_notice_set_trap_num

+ +

[top][index]

+

NAME

+
       ib_notice_set_trap_num
+
+

DESCRIPTION

+
       Sets the trap number of a generic notice trap.
+
+

SYNOPSIS

+
AL_INLINE void AL_API
+ib_notice_set_trap_num(
+        IN      OUT                     ib_mad_notice_attr_t* const     p_notice_attr,
+        IN              const   uint16_t                                        trap_num )
+{
+        p_notice_attr->combo2 = cl_hton16( trap_num );
+}
+
+

PARAMETERS

+
       p_notice_attr
+               [in/out] Pointer to the notice attribute structure
+               whose trap number to set.
+
+       trap_num
+               [in] Trap number to set.
+
+ RETURN VALUES
+       This function does not return a value.
+
+

SEE ALSO

+
       ib_mad_notice_attr_t, ib_notice_get_trap_num
+
+
+
+ +

[Functions] +IBA Base: Types/ib_notice_set_type

+ +

[top][index]

+

NAME

+
       ib_notice_set_type
+
+

DESCRIPTION

+
       Sets the type of a notice trap.
+
+

SYNOPSIS

+
AL_INLINE void AL_API
+ib_notice_set_type(
+        IN      OUT                     ib_mad_notice_attr_t* const     p_notice_attr,
+        IN              const   uint8_t                                         type )
+{
+        uint32_t        val;
+
+        val = cl_ntoh32( p_notice_attr->combo1 );
+        /* Clear the type. */
+        val &= 0xFFFFFF01;
+        /* Set new value. */
+        val |= (((uint32_t)(type & 0x7F)) << 1);
+        p_notice_attr->combo1 = cl_hton32( val );
+}
+
+

PARAMETERS

+
       p_notice_attr
+               [in/out] Pointer to the notice attribute structure whose type to set.
+
+       type
+               [in] Type of notice trap.
+
+ RETURN VALUES
+       This function does not return a value.
+
+

SEE ALSO

+
       ib_mad_notice_attr_t, ib_notice_get_type
+
+
+
+ +

[Functions] +IBA Base: Types/ib_notice_set_vend_id

+ +

[top][index]

+

NAME

+
       ib_notice_set_vend_id
+
+

DESCRIPTION

+
       Sets the vendor ID of a vendor specific notice trap.
+
+

SYNOPSIS

+
AL_INLINE void AL_API
+ib_notice_set_vend_id(
+        IN      OUT                     ib_mad_notice_attr_t* const     p_notice_attr,
+        IN              const   uint32_t                                        vend_id )
+{
+        ib_notice_set_prod_type( p_notice_attr, vend_id );
+}
+
+

PARAMETERS

+
       p_notice_attr
+               [in/out] Pointer to the notice attribute structure
+               whose vendor ID to set.
+
+       vend_id
+               [in] Vendor ID of notice trap.
+
+ RETURN VALUES
+       This function does not return a value.
+
+

SEE ALSO

+
       ib_mad_notice_attr_t, ib_notice_get_vend_id
+
+
+
+ +

[Functions] +IBA Base: Types/ib_path_get_ipd

+ +

[top][index]

+

NAME

+
       ib_path_get_ipd
+
+

DESCRIPTION

+
       Returns the encoded value for the inter packet delay.
+
+

SYNOPSIS

+
AL_INLINE uint8_t AL_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

+ +
+ +

[Functions] +IBA Base: Types/ib_path_rec_flow_lbl

+ +

[top][index]

+

NAME

+
       ib_path_rec_flow_lbl
+
+

DESCRIPTION

+
       Get flow label.
+
+

SYNOPSIS

+
AL_INLINE net32_t AL_API
+ib_path_rec_flow_lbl(
+        IN              const   ib_path_rec_t* const            p_rec )
+{
+        return( cl_hton32( (cl_ntoh32(p_rec->hop_flow_raw.val) >> 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
+
+
+
+ +

[Functions] +IBA Base: Types/ib_path_rec_hop_limit

+ +

[top][index]

+

NAME

+
       ib_path_rec_hop_limit
+
+

DESCRIPTION

+
       Get hop limit.
+
+

SYNOPSIS

+
AL_INLINE uint8_t AL_API
+ib_path_rec_hop_limit(
+        IN              const   ib_path_rec_t* const            p_rec )
+{
+        return( p_rec->hop_flow_raw.bytes[3] );
+}
+
+

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
+
+
+
+ +

[Functions] +IBA Base: Types/ib_path_rec_init_local

+ +

[top][index]

+

NAME

+
       ib_path_rec_init_local
+
+

DESCRIPTION

+
       Initializes a subnet local path record.
+
+

SYNOPSIS

+
AL_INLINE void AL_API
+ib_path_rec_init_local(
+        IN                              ib_path_rec_t*  const           p_rec,
+        IN              const   ib_gid_t*               const           p_dgid,
+        IN              const   ib_gid_t*               const           p_sgid,
+        IN              const   ib_net16_t                                      dlid,
+        IN              const   ib_net16_t                                      slid,
+        IN              const   uint8_t                                         num_path,
+        IN              const   ib_net16_t                                      pkey,
+        IN              const   uint8_t                                         sl,
+        IN              const   uint8_t                                         mtu_selector,
+        IN              const   uint8_t                                         mtu,
+        IN              const   uint8_t                                         rate_selector,
+        IN              const   uint8_t                                         rate,
+        IN              const   uint8_t                                         pkt_life_selector,
+        IN              const   uint8_t                                         pkt_life,
+        IN              const   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;
+        /* Lower 4 bits of path rec's SL are reserved. */
+        p_rec->sl = cl_ntoh16( sl );
+        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.val = 0;
+        p_rec->tclass = 0;
+
+        p_rec->resv0 = 0;
+        p_rec->resv1 = 0;
+        p_rec->resv2 = 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] In queries, maximum number of paths to return.
+               In responses, undefined.
+
+       pkey
+               [in] Partition key (P_Key) to use on this path.
+
+       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
+
+
+
+ +

[Functions] +IBA Base: Types/ib_path_rec_mtu

+ +

[top][index]

+

NAME

+
       ib_path_rec_mtu
+
+

DESCRIPTION

+
       Get encoded path MTU.
+
+

SYNOPSIS

+
AL_INLINE uint8_t AL_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
+
+
+
+ +

[Functions] +IBA Base: Types/ib_path_rec_mtu_sel

+ +

[top][index]

+

NAME

+
       ib_path_rec_mtu_sel
+
+

DESCRIPTION

+
       Get encoded path MTU selector.
+
+

SYNOPSIS

+
AL_INLINE uint8_t AL_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
+
+
+
+ +

[Functions] +IBA Base: Types/ib_path_rec_num_path

+ +

[top][index]

+

NAME

+
       ib_path_rec_num_path
+
+

DESCRIPTION

+
       Get max number of paths to return.
+
+

SYNOPSIS

+
static inline uint8_t   
+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
+
+
+
+ +

[Functions] +IBA Base: Types/ib_path_rec_pkt_life

+ +

[top][index]

+

NAME

+
       ib_path_rec_pkt_life
+
+

DESCRIPTION

+
       Get encoded path pkt_life.
+
+

SYNOPSIS

+
AL_INLINE uint8_t AL_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 µsec * 2 ** PacketLifeTime.
+
+

NOTES

+
+
+

SEE ALSO

+
       ib_path_rec_t
+
+
+
+ +

[Functions] +IBA Base: Types/ib_path_rec_pkt_life_sel

+ +

[top][index]

+

NAME

+
       ib_path_rec_pkt_life_sel
+
+

DESCRIPTION

+
       Get encoded path pkt_lifetime selector.
+
+

SYNOPSIS

+
AL_INLINE uint8_t AL_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
+
+
+
+ +

[Functions] +IBA Base: Types/ib_path_rec_rate

+ +

[top][index]

+

NAME

+
       ib_path_rec_rate
+
+

DESCRIPTION

+
       Get encoded path rate.
+
+

SYNOPSIS

+
AL_INLINE uint8_t AL_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
+
+
+
+ +

[Functions] +IBA Base: Types/ib_path_rec_rate_sel

+ +

[top][index]

+

NAME

+
       ib_path_rec_rate_sel
+
+

DESCRIPTION

+
       Get encoded path rate selector.
+
+

SYNOPSIS

+
AL_INLINE uint8_t AL_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
+
+
+
+ +

[Functions] +IBA Base: Types/ib_path_rec_set_hop_flow_raw

+ +

[top][index]

+

NAME

+
       ib_path_rec_set_hop_flow_raw
+
+

DESCRIPTION

+
       Sets the hop limit, flow label, and raw traffic bits of a path record.
+
+

SYNOPSIS

+
AL_INLINE void AL_API
+ib_path_rec_set_hop_flow_raw(
+                OUT                     ib_path_rec_t* const            p_rec,
+        IN              const   uint8_t                                         hop_limit,
+        IN              const   net32_t                                         flow_lbl,
+        IN              const   boolean_t                                       raw )
+{
+        p_rec->hop_flow_raw.val = (cl_ntoh32( flow_lbl ) & 0x000FFFFF) << 8;
+        if( raw )
+                p_rec->hop_flow_raw.val |= 0x80000000;
+        p_rec->hop_flow_raw.val = cl_hton32( p_rec->hop_flow_raw.val );
+        p_rec->hop_flow_raw.bytes[3] = hop_limit;
+}
+
+

PARAMETERS

+
       p_rec
+               Pointer to the path record whose hop limit, flow label, and rab
+               traffic fields to set.
+
+       hop_limit
+               Hop limit to set in the path record.
+
+       flow_lbl
+               Flow label, in network byte order, to set in the path record.
+
+       raw
+               Boolean flag to indicate whether the path record is for raw traffic.
+
+

SEE ALSO

+
       ib_path_rec_t
+
+
+
+ +

[Functions] +IBA Base: Types/ib_path_rec_sl

+ +

[top][index]

+

NAME

+
       ib_path_rec_sl
+
+

DESCRIPTION

+
       Get path service level.
+
+

SYNOPSIS

+
AL_INLINE uint8_t AL_API
+ib_path_rec_sl(
+        IN              const   ib_path_rec_t* const            p_rec )
+{
+        return( (uint8_t)((cl_ntoh16( p_rec->sl )) & 0xF) );
+}
+
+

PARAMETERS

+
       p_rec
+               [in] Pointer to the path record object.
+
+ RETURN VALUES
+       SL.
+
+

NOTES

+
+
+

SEE ALSO

+
       ib_path_rec_t
+
+
+
+ +

[Structures] +IBA Base: Types/ib_path_rec_t

+ +

[top][index]

+

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 __declspec(align(8)) struct _ib_path_rec
+{
+        uint64_t                                resv0;
+        ib_gid_t                                dgid;
+        ib_gid_t                                sgid;
+        ib_net16_t                              dlid;
+        ib_net16_t                              slid;
+        ib_field32_t                    hop_flow_raw;
+        uint8_t                                 tclass;
+        uint8_t                                 num_path;
+        ib_net16_t                              pkey;
+        ib_net16_t                              sl;
+        uint8_t                                 mtu;
+        uint8_t                                 rate;
+        uint8_t                                 pkt_life;
+        uint8_t                                 preference;
+        uint16_t                                resv1;
+        uint32_t                                resv2;
+
+}       PACK_SUFFIX ib_path_rec_t;
+#include <complib/cl_packoff.h>
+
+

FIELDS

+
       resv0
+               Reserved bytes.
+
+       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
+               In queries, maximum number of paths to return.
+               In responses, undefined.
+
+       pkey
+               Partition key (P_Key) to use on this path.
+
+       resv1
+               Reserved byte.
+
+       sl
+               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.
+
+       resv1
+               Reserved bytes.
+
+       resv2
+               Reserved bytes.
+
+

SEE ALSO

+ +
+ +

[Functions] +IBA Base: Types/ib_pkey_get_base

+ +

[top][index]

+

NAME

+
       ib_pkey_get_base
+
+

DESCRIPTION

+
       Returns the base P_Key value with the membership bit stripped.
+
+

SYNOPSIS

+
AL_INLINE ib_net16_t AL_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

+ +
+ +

[Functions] +IBA Base: Types/ib_pkey_is_full_member

+ +

[top][index]

+

NAME

+
       ib_pkey_is_full_member
+
+

DESCRIPTION

+
       Indicates if the port is a full member of the parition.
+
+

SYNOPSIS

+
AL_INLINE boolean_t AL_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
+
+
+
+ +

[Functions] +IBA Base: Types/ib_pkey_is_invalid

+ +

[top][index]

+

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 
+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

+ +
+ +

[Structures] +IBA Base: Types/ib_pkey_table_info_t

+ +

[top][index]

+

NAME

+
       ib_pkey_table_info_t
+
+

DESCRIPTION

+
       IBA defined PKey table. (14.2.5.7)
+
+

SYNOPSIS

+
#define PKEY_TABLE_MAX_ENTRIES          32
+
+#include <complib/cl_packon.h>
+typedef struct _ib_pkey_table_info
+{
+        ib_net16_t                      pkey[PKEY_TABLE_MAX_ENTRIES];
+
+}       PACK_SUFFIX ib_pkey_table_info_t;
+#include <complib/cl_packoff.h>
+
+
+
+ +

[Structures] +IBA Base: Types/ib_port_counters_t

+ +

[top][index]

+

NAME

+
       ib_gmp_t
+
+

DESCRIPTION

+
       IBA defined PortCounters MAD format. (16.1.3.5)
+
+

SYNOPSIS

+
#include <complib/cl_packon.h>
+typedef struct _ib_port_counters
+{
+        uint8_t                 reserved0;
+        uint8_t                 port_select;
+        ib_net16_t              counter_select;
+        ib_net16_t              symbol_error_counter; 
+        uint8_t                 link_error_recovery_counter;
+        uint8_t                 link_down_counter; 
+        ib_net16_t              port_rcv_errors; 
+        ib_net16_t              port_rcv_remote_physical_errors;
+        ib_net16_t              port_rcv_switch_relay_errors; 
+        ib_net16_t              port_xmit_discard; 
+        uint8_t                 port_xmit_constraint_errors;
+        uint8_t                 port_rcv_constraint_errors;
+        uint8_t                 reserved1;
+        /* uint4_t excessive_buffer_overrun_errors;
+        uint4_t local_link_integrity_errors; */
+        uint8_t                 lli_errors_exc_buf_errors;
+        ib_net16_t              reserved2; 
+        ib_net16_t              vl15_dropped;
+        ib_net32_t              port_xmit_data;
+        ib_net32_t              port_rcv_data;
+        ib_net32_t              port_xmit_pkts;
+        ib_net32_t              port_rcv_pkts;
+
+}       PACK_SUFFIX ib_port_counters_t;
+#include <complib/cl_packoff.h>
+
+
+
+ +

[Functions] +IBA Base: Types/ib_port_info_compute_rate

+ +

[top][index]

+

NAME

+
       ib_port_info_compute_rate
+
+

DESCRIPTION

+
       Returns the encoded value for the path rate.
+
+

SYNOPSIS

+
AL_INLINE uint8_t AL_API
+ib_port_info_compute_rate(
+        IN              const   ib_port_info_t* const           p_pi )
+{
+        switch( p_pi->link_width_active * p_pi->link_width_active *
+                ib_port_info_get_link_speed_active( p_pi ) )
+        {
+        case 1:
+                return IB_PATH_RECORD_RATE_2_5_GBS;
+
+        case 2:
+                return IB_PATH_RECORD_RATE_5_GBS;
+
+        case 4:
+                return IB_PATH_RECORD_RATE_10_GBS;
+
+        case 8:
+                return IB_PATH_RECORD_RATE_20_GBS;
+
+        case 16:
+                return IB_PATH_RECORD_RATE_40_GBS;
+
+        case 64:
+                return IB_PATH_RECORD_RATE_30_GBS;
+
+        case 128:
+                return IB_PATH_RECORD_RATE_60_GBS;
+
+        case 256:
+                return IB_PATH_RECORD_RATE_120_GBS;
+
+        default:
+                return IB_PATH_RECORD_RATE_2_5_GBS;
+        }
+}
+
+

PARAMETERS

+
       p_pi
+               [in] Pointer to a PortInfo attribute.
+
+ RETURN VALUES
+       Returns the encoded value for the link speed supported.
+
+

NOTES

+
+
+

SEE ALSO

+ +
+ +

[Functions] +IBA Base: Types/ib_port_info_get_init_type

+ +

[top][index]

+

NAME

+
       ib_port_info_get_init_type
+
+

DESCRIPTION

+
       Gets the init type of a port.
+
+

SYNOPSIS

+
static inline uint8_t   
+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

+ +
+ +

[Functions] +IBA Base: Types/ib_port_info_get_link_speed_active

+ +

[top][index]

+

NAME

+
       ib_port_info_get_link_speed_active
+
+

DESCRIPTION

+
       Returns the Link Speed Active value assigned to this port.
+
+

SYNOPSIS

+
AL_INLINE uint8_t AL_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

+ +
+ +

[Functions] +IBA Base: Types/ib_port_info_get_link_speed_sup

+ +

[top][index]

+

NAME

+
       ib_port_info_get_link_speed_sup
+
+

DESCRIPTION

+
       Returns the encoded value for the link speed supported.
+
+

SYNOPSIS

+
AL_INLINE uint8_t AL_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

+ +
+ +

[Functions] +IBA Base: Types/ib_port_info_get_lmc

+ +

[top][index]

+

NAME

+
       ib_port_info_get_lmc
+
+

DESCRIPTION

+
       Returns the LMC value assigned to this port.
+
+

SYNOPSIS

+
AL_INLINE uint8_t AL_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

+ +
+ +

[Functions] +IBA Base: Types/ib_port_info_get_mpb

+ +

[top][index]

+

NAME

+
       ib_port_info_get_mpb
+
+

DESCRIPTION

+
       Returns the M_Key protect bits assigned to this port.
+
+

SYNOPSIS

+
AL_INLINE uint8_t AL_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

+ +
+ +

[Functions] +IBA Base: Types/ib_port_info_get_mtu_cap

+ +

[top][index]

+

NAME

+
       ib_port_info_get_mtu_cap
+
+

DESCRIPTION

+
       Returns the encoded value for the maximum MTU supported by this port.
+
+

SYNOPSIS

+
AL_INLINE uint8_t AL_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 LMC value assigned to this port.
+
+

NOTES

+
+
+

SEE ALSO

+ +
+ +

[Functions] +IBA Base: Types/ib_port_info_get_neighbor_mtu

+ +

[top][index]

+

NAME

+
       ib_port_info_get_neighbor_mtu
+
+

DESCRIPTION

+
       Returns the encoded value for the neighbor MTU at this port.
+
+

SYNOPSIS

+
AL_INLINE uint8_t AL_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

+ +
+ +

[Functions] +IBA Base: Types/ib_port_info_get_op_vls

+ +

[top][index]

+

NAME

+
       ib_port_info_get_op_vls
+
+

DESCRIPTION

+
       Gets the operational VLs on a port.
+
+

SYNOPSIS

+
AL_INLINE uint8_t AL_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

+ +
+ +

[Functions] +IBA Base: Types/ib_port_info_get_port_state

+ +

[top][index]

+

NAME

+
       ib_port_info_get_port_state
+
+

DESCRIPTION

+
       Returns the port state.
+
+

SYNOPSIS

+
AL_INLINE uint8_t AL_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

+ +
+ +

[Functions] +IBA Base: Types/ib_port_info_get_sm_sl

+ +

[top][index]

+

NAME

+
       ib_port_info_get_sm_sl
+
+

DESCRIPTION

+
       Returns the encoded value for the SM sl at this port.
+
+

SYNOPSIS

+
AL_INLINE uint8_t AL_API
+ib_port_info_get_sm_sl(
+        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 neighbor MTU at this port.
+
+

NOTES

+
+
+

SEE ALSO

+ +
+ +

[Functions] +IBA Base: Types/ib_port_info_get_vl_cap

+ +

[top][index]

+

NAME

+
       ib_port_info_get_vl_cap
+
+

DESCRIPTION

+
       Gets the VL Capability of a port.
+
+

SYNOPSIS

+
AL_INLINE uint8_t AL_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

+ +
+ +

[Functions] +IBA Base: Types/ib_port_info_set_link_speed_sup

+ +

[top][index]

+

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

+
AL_INLINE void AL_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

+ +
+ +

[Functions] +IBA Base: Types/ib_port_info_set_lmc

+ +

[top][index]

+

NAME

+
       ib_port_info_set_lmc
+
+

DESCRIPTION

+
       Sets the LMC value in the PortInfo attribute.
+
+

SYNOPSIS

+
AL_INLINE void AL_API
+ib_port_info_set_lmc(
+        IN                              ib_port_info_t* const           p_pi,
+        IN              const   uint8_t                                         lmc )
+{
+        CL_ASSERT( lmc <= 0x7 );
+        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

+ +
+ +

[Functions] +IBA Base: Types/ib_port_info_set_mpb

+ +

[top][index]

+

NAME

+
       ib_port_info_set_mpb
+
+

DESCRIPTION

+
       Set the M_Key protect bits of this port.
+
+

SYNOPSIS

+
AL_INLINE void AL_API
+ib_port_info_set_mpb(
+        IN                              ib_port_info_t*                         p_pi,
+        IN                              uint8_t                                         mpb )
+{
+        p_pi->mkey_lmc =
+                ((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

+ +
+ +

[Functions] +IBA Base: Types/ib_port_info_set_neighbor_mtu

+ +

[top][index]

+

NAME

+
       ib_port_info_set_neighbor_mtu
+
+

DESCRIPTION

+
       Sets the Neighbor MTU value in the PortInfo attribute.
+
+

SYNOPSIS

+
AL_INLINE void AL_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

+ +
+ +

[Functions] +IBA Base: Types/ib_port_info_set_op_vls

+ +

[top][index]

+

NAME

+
       ib_port_info_set_op_vls
+
+

DESCRIPTION

+
       Sets the operational VLs on a port.
+
+

SYNOPSIS

+
AL_INLINE void AL_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

+ +
+ +

[Functions] +IBA Base: Types/ib_port_info_set_port_state

+ +

[top][index]

+

NAME

+
       ib_port_info_set_port_state
+
+

DESCRIPTION

+
       Sets the port state.
+
+

SYNOPSIS

+
AL_INLINE void AL_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

+ +
+ +

[Functions] +IBA Base: Types/ib_port_info_set_sm_sl

+ +

[top][index]

+

NAME

+
       ib_port_info_set_sm_sl
+
+

DESCRIPTION

+
       Sets the SM sl value in the PortInfo attribute.
+
+

SYNOPSIS

+
AL_INLINE void AL_API
+ib_port_info_set_sm_sl(
+        IN                              ib_port_info_t* const           p_pi,
+        IN              const   uint8_t                                         sm_sl )
+{
+        CL_ASSERT( sm_sl<= 5 );
+        CL_ASSERT( sm_sl != 0 );
+        p_pi->mtu_smsl = (uint8_t)((p_pi->mtu_smsl & 0xF0) | sm_sl );
+}
+
+

PARAMETERS

+
       p_pi
+               [in] Pointer to a PortInfo attribute.
+
+       mtu
+               [in] Encoded SM sl value to set
+
+ RETURN VALUES
+       None.
+
+

NOTES

+
+
+

SEE ALSO

+ +
+ +

[Functions] +IBA Base: Types/ib_port_info_set_state_no_change

+ +

[top][index]

+

NAME

+
       ib_port_info_set_state_no_change
+
+

DESCRIPTION

+
       Sets the port state fields to the value for "no change".
+
+

SYNOPSIS

+
AL_INLINE void AL_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

+ +
+ +

[Functions] +IBA Base: Types/ib_port_info_set_timeout

+ +

[top][index]

+

NAME

+
       ib_port_info_set_timeout
+
+

DESCRIPTION

+
       Sets the encoded subnet timeout value in the PortInfo attribute.
+
+

SYNOPSIS

+
AL_INLINE void AL_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)(timeout & 0x1F);
+}
+
+

PARAMETERS

+
       p_pi
+               [in] Pointer to a PortInfo attribute.
+
+       timeout
+               [in] Encoded timeout value to set
+
+ RETURN VALUES
+       None.
+
+

NOTES

+
+
+

SEE ALSO

+ +
+ +

[Structures] +IBA Base: Types/ib_port_info_t

+ +

[top][index]

+

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>
+
+
+
+ +

[Functions] +IBA Base: Types/ib_rmpp_is_flag_set

+ +

[top][index]

+

NAME

+
       ib_rmpp_is_flag_set
+
+

DESCRIPTION

+
       Returns TRUE if the MAD has the given RMPP flag set.
+
+

SYNOPSIS

+
AL_INLINE boolean_t AL_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
+
+
+
+ +

[Structures] +IBA Base: Types/ib_rmpp_mad_t

+ +

[top][index]

+

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
+
+
+
+ +

[Functions] +IBA Base: Types/ib_sa_mad_get_payload_ptr

+ +

[top][index]

+

NAME

+
       ib_sa_mad_get_payload_ptr
+
+

DESCRIPTION

+
       Gets a pointer to the SA MAD's payload area.
+
+

SYNOPSIS

+
AL_INLINE void* AL_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_smp
+               [in] Pointer to the SA MAD packet.
+
+ RETURN VALUES
+       Pointer to SA MAD payload area.
+
+

NOTES

+
+
+

SEE ALSO

+
       ib_mad_t
+
+
+
+ +

[Structures] +IBA Base: Types/ib_sa_mad_t

+ +

[top][index]

+

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>
+
+
+
+ +

[Functions] +IBA Base: Types/ib_slvl_table_get_vl

+ +

[top][index]

+

NAME

+
       ib_slvl_table_get_vl
+
+

DESCRIPTION

+
       Retrieves the VL for a given SL from an SL to VL mapping table.
+
+

SYNOPSIS

+
AL_INLINE uint8_t AL_API
+ib_slvl_table_get_vl(
+        IN              const   ib_slvl_table_t* const          p_slvl_tbl,
+        IN              const   uint8_t                                         sl )
+{
+        uint8_t vl;
+
+        /* There are two VL's per byte. */
+        vl = p_slvl_tbl->vl_table[sl/2];
+        /* If odd, shift down 4 bits. */
+        if( sl % 2 )
+                vl >>= 4;
+
+        /* Mask off upper bits and return. */
+        return vl & 0x0F;
+}
+
+

PARAMETERS

+
       p_slvl_tbl
+               [in] Pointer to the SL to VL mapping table from which to return the VL.
+
+       sl
+               [in] SL in the table for which to return the VL.
+
+ RETURN VALUES
+       Returns the VL value for the specified SL in the provided table.
+
+

SEE ALSO

+
       ib_slvl_table_t, ib_slvl_table_set_vl
+
+
+
+ +

[Structures] +IBA Base: Types/ib_slvl_table_record_t

+ +

[top][index]

+

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 CA's
+        uint8_t                 out_port_num;   // reserved for CA's
+        uint32_t                resv;
+        ib_slvl_table_t slvl_tbl;
+
+}       PACK_SUFFIX ib_slvl_table_record_t;
+#include <complib/cl_packoff.h>
+
+
+
+ +

[Functions] +IBA Base: Types/ib_slvl_table_set_vl

+ +

[top][index]

+

NAME

+
       ib_slvl_table_set_vl
+
+

DESCRIPTION

+
       Sets the VL for a given SL in an SL to VL mapping table.
+
+

SYNOPSIS

+
AL_INLINE void AL_API
+ib_slvl_table_set_vl(
+        IN      OUT                     ib_slvl_table_t* const          p_slvl_tbl,
+        IN              const   uint8_t                                         sl,
+        IN              const   uint8_t                                         vl )
+{
+        uint8_t entry;
+
+        /* Get the current value for the byte in which the VL is stored. */
+        entry = p_slvl_tbl->vl_table[sl/2];
+
+        /* Clear the appropriate bits and set the new VL value. */
+        if( sl % 2 )
+        {
+                entry &= 0x0F;
+                entry |= ((vl & 0x0F) << 4);
+        }
+        else
+        {
+                entry &= 0xF0;
+                entry |= (vl & 0x0F);
+        }
+        /* Store the updated entry back into the table. */
+        p_slvl_tbl->vl_table[sl/2] = entry;
+}
+
+

PARAMETERS

+
       slvl_tbl
+               [in/out] Pointer to the SL to VL mapping table in which to store the VL.
+
+       sl
+               [in] SL in the table for which to store the VL.
+
+       vl
+               [in] VL to store at the specifed SL.
+
+ RETURN VALUES
+       This function does not return a value.
+
+

SEE ALSO

+
       ib_slvl_table_t, ib_slvl_table_get_vl
+
+
+
+ +

[Structures] +IBA Base: Types/ib_slvl_table_t

+ +

[top][index]

+

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         vl_table[IB_MAX_NUM_VLS/2];
+
+}       PACK_SUFFIX ib_slvl_table_t;
+#include <complib/cl_packoff.h>
+
+
+
+ +

[Structures] +IBA Base: Types/ib_sm_info_t

+ +

[top][index]

+

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

+ +
+ +

[Functions] +IBA Base: Types/ib_sminfo_get_priority

+ +

[top][index]

+

NAME

+
       ib_sminfo_get_priority
+
+

DESCRIPTION

+
       Returns the priority value.
+
+

SYNOPSIS

+
AL_INLINE uint8_t AL_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

+ +
+ +

[Functions] +IBA Base: Types/ib_sminfo_get_state

+ +

[top][index]

+

NAME

+
       ib_sminfo_get_state
+
+

DESCRIPTION

+
       Returns the state value.
+
+

SYNOPSIS

+
AL_INLINE uint8_t AL_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

+ +
+ +

[Functions] +IBA Base: Types/ib_smp_get_payload_ptr

+ +

[top][index]

+

NAME

+
       ib_smp_get_payload_ptr
+
+

DESCRIPTION

+
       Gets a pointer to the SMP payload area.
+
+

SYNOPSIS

+
AL_INLINE void* AL_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
+
+
+
+ +

[Functions] +IBA Base: Types/ib_smp_get_status

+ +

[top][index]

+

NAME

+
       ib_smp_get_status
+
+

DESCRIPTION

+
       Returns the SMP status value in network order.
+
+

SYNOPSIS

+
AL_INLINE ib_net16_t AL_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
+
+
+
+ +

[Functions] +IBA Base: Types/ib_smp_init_new

+ +

[top][index]

+

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

+
AL_INLINE void AL_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;
+
+        cl_memclr( p_smp->resv1,
+                        sizeof(p_smp->resv1) +
+                        sizeof(p_smp->data) +
+                        sizeof(p_smp->initial_path) +
+                        sizeof(p_smp->return_path) );
+
+        /* copy the path */
+        cl_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
+
+
+
+ +

[Functions] +IBA Base: Types/ib_smp_is_d

+ +

[top][index]

+

NAME

+
       ib_smp_is_d
+
+

DESCRIPTION

+
       Returns TRUE if the SMP 'D' (direction) bit is set.
+
+

SYNOPSIS

+
AL_INLINE boolean_t AL_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
+
+
+
+ +

[Functions] +IBA Base: Types/ib_smp_is_response

+ +

[top][index]

+

NAME

+
       ib_smp_is_response
+
+

DESCRIPTION

+
       Returns TRUE if the SMP is a response MAD, FALSE otherwise.
+
+

SYNOPSIS

+
AL_INLINE boolean_t AL_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
+
+
+
+ +

[Structures] +IBA Base: Types/ib_smp_t

+ +

[top][index]

+

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

+ +
+ +

[Structures] +IBA Base: Types/ib_svc_entries_t

+ +

[top][index]

+

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
+
+
+
+ +

[Structures] +IBA Base: Types/ib_svc_entry_t

+ +

[top][index]

+

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
+
+
+
+ +

[Functions] +IBA Base: Types/ib_switch_info_clear_state_change

+ +

[top][index]

+

NAME

+
       ib_switch_info_clear_state_change
+
+

DESCRIPTION

+
       Clears the switch's state change bit.
+
+

SYNOPSIS

+
AL_INLINE void AL_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

+ +
+ +

[Functions] +IBA Base: Types/ib_switch_info_get_state_change

+ +

[top][index]

+

NAME

+
       ib_switch_info_get_state_change
+
+

DESCRIPTION

+
       Returns the value of the state change flag.
+
+

SYNOPSIS

+
AL_INLINE boolean_t AL_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

+ +
+ +

[Structures] +IBA Base: Types/ib_switch_info_t

+ +

[top][index]

+

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>
+
+
+
+ +

[Functions] +IBA Base: Types/ib_vl_arb_element_get_vl

+ +

[top][index]

+

NAME

+
       ib_vl_arb_element_get_vl
+
+

DESCRIPTION

+
       Retrieves the VL from a VL arbitration table element.
+
+

SYNOPSIS

+
AL_INLINE uint8_t AL_API
+ib_vl_arb_element_get_vl(
+        IN              const   ib_vl_arb_element_t                     vl_arb_element )
+{
+        return (vl_arb_element.res_vl >> 4);
+}
+
+

PARAMETERS

+
       vl_arb_element
+               [in] VL arbitration table element from which to return the VL.
+
+ RETURN VALUES
+       Returns the VL value for the specified VL arbitration table element.
+
+

SEE ALSO

+
       vl_arb_element, ib_vl_arb_element_set_vl
+
+
+
+ +

[Functions] +IBA Base: Types/ib_vl_arb_element_set_vl

+ +

[top][index]

+

NAME

+
       ib_vl_arb_element_set_vl
+
+

DESCRIPTION

+
       Retrieves the VL from a VL arbitration table element.
+
+

SYNOPSIS

+
AL_INLINE void AL_API
+ib_vl_arb_element_set_vl(
+        IN      OUT                     ib_vl_arb_element_t* const      p_vl_arb_element,
+        IN              const   uint8_t                                         vl )
+{
+        p_vl_arb_element->res_vl = vl << 4;
+}
+
+

PARAMETERS

+
       vl_arb_element
+               [in/out] VL arbitration table element in which to store the VL.
+
+       vl
+               [in] VL to store in the specified element.
+
+ RETURN VALUES
+       This function does not return a value.
+
+

SEE ALSO

+
       vl_arb_element, ib_vl_arb_element_get_vl
+
+
+
+ +

[Structures] +IBA Base: Types/ib_vl_arb_element_t

+ +

[top][index]

+

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 res_vl;
+        uint8_t weight;
+
+}       PACK_SUFFIX ib_vl_arb_element_t;
+#include <complib/cl_packoff.h>
+
+
+
+ +

[Structures] +IBA Base: Types/ib_vl_arb_table_record_t

+ +

[top][index]

+

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>
+
+
+
+ +

[Structures] +IBA Base: Types/ib_vl_arb_table_t

+ +

[top][index]

+

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>
+
+
+
+ +

[Functions] +IBA Base: Types/ioc_at_slot

+ +

[top][index]

+

NAME

+
       ioc_at_slot
+
+

DESCRIPTION

+
       Returns the IOC value at the specified slot.
+
+

SYNOPSIS

+
AL_INLINE uint8_t AL_API
+ioc_at_slot(
+        IN              const   ib_iou_info_t*  const   p_iou_info,
+        IN                              uint8_t                                 slot )
+{
+        if( !slot )
+                return SLOT_DOES_NOT_EXIST;
+        else if( slot-- & 0x01 )
+                return (p_iou_info->controller_list[slot >> 1] >> 4);
+        else
+                return (p_iou_info->controller_list[slot >> 1] & 0x0F);
+}
+
+

PARAMETERS

+
       p_iou_info
+               [in] Pointer to the IO Unit information structure.
+
+       slot
+               [in] 1-based slot number of the IOC slot to check.
+
+ RETURN VALUES
+       Returns the encoded value for the desired slot.  Possible values are
+       SLOT_DOES_NOT_EXIST, IOC_NOT_INSTALLED, and IOC_INSTALLED.
+
+

NOTES

+
       The input slot number is 1-based, not zero based.
+
+

SEE ALSO

+
       ib_iou_info_t
+
+
+
+ +

[Functions] +IBA Bases: Types/ib_dm_get_slot_lo_hi

+ +

[top][index]

+

DESCRIPTION

+
       Returns the IOC slot number, and the lower and upper bound of the
+       service entries given the attribute modifier of ServiceEntries response.
+
+

SEE ALSO

+
 ib_dm_set_slot_lo_hi
+
+
+
+ +

[Functions] +IBA Bases: Types/ib_dm_set_slot_lo_hi

+ +

[top][index]

+

DESCRIPTION

+
       Joins the IOC slot number, and the lower and upper bound of the service 
+       entries and returns it.
+
+

SEE ALSO

+
 ib_dm_get_slot_lo_hi
+
+
+
+ +

[Definitions] +Verbs/ib_async_event_t

+ +

[top][index]

+

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_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_WQ_REQ_ERROR,
+        IB_AE_WQ_ACCESS_ERROR,
+        IB_AE_PORT_ACTIVE,
+        IB_AE_PORT_DOWN,
+        IB_AE_CLIENT_REREGISTER,
+        IB_AE_SRQ_LIMIT_REACHED,
+        IB_AE_SRQ_CATAS_ERROR,
+        IB_AE_SRQ_QP_LAST_WQE_REACHED,
+        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.
+               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.
+               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_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_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_CLIENT_REREGISTER
+               The SM idicate to client to reregister its SA records.
+
+       IB_AE_SRQ_LIMIT_REACHED
+               Reached SRQ low watermark
+
+       IB_AE_SRQ_CATAS_ERROR
+               An error occurred while processing or accessing the SRQ that prevents
+               dequeuing a WQE from the SRQ and reporting of receive completions.
+
+       IB_AE_SRQ_QP_LAST_WQE_REACHED
+               An event,  issued for a QP, associated with a shared receive queue, when
+                       a CQE is generated for the last WQE, or
+                       the QP gets in the Error State and there are no more WQEs on the RQ.
+
+       IB_AE_UNKNOWN
+               An unknown error occurred which cannot be attributed to any
+               resource; behavior is indeterminate.
+
+
+
+ +

[Structures] +Verbs/ib_event_rec_t

+ +

[top][index]

+

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
+{
+ TO_LONG_PTR(       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;
+
+
+ + diff --git a/branches/WOF2-3/docs/install.txt b/branches/WOF2-3/docs/install.txt new file mode 100644 index 00000000..ee26c0b8 --- /dev/null +++ b/branches/WOF2-3/docs/install.txt @@ -0,0 +1,111 @@ +This document describes installation steps for developers and is +not end users. The process described here is for developers running +on a homogeneous Windows HPC cluster. + +Installation is divided into several phases in order to allow for +quick replacement of specific drivers and/or libraries. Before +starting, the developer should note the following: + +- OS version running on the cluster (2003, 2008) +- Processor architecture of the cluster (x86, x64, ia64) +- Whether they want to install checked or free versions of + drivers and libraries. + + +1. Build the sources. + +Refer to docs\built.txt and bldwo.bat for details on building the +source code. As an example, this will build the sources to install +on a 2008 HPC cluster running on 64-bit processors. + + bldwo chk x32 2008 + bldwo fre x32 2008 + bldwo chk x64 2008 + bldwo fre x64 2008 + +You must build both the checked and free versions of the source to +use this installation process, and include 32-bit binaries when +installing on a 64-bit system. This is because the inf files +reference 32-bit checked and free and 64-bit checked and free +versions of the libraries in the install process. +The correct version (checked or free) of the drivers and executables +will be installed. + +Note: during development, you only need to rebuild the actual +version undergoing testing, as long as the other files are +available. You may also build from a specific directory in +the source tree to only rebuild those files undergoing active +development. + + +2. Create packages. + +Use etc\pkgwo.bat to sort the compiled source code into their +respective packages. The separation of the source code into +packages allows quick rebuilding and replacement of selected +modules. For example, the following creates packages for a +2008 HPC cluster. + + pkgwo fre x64 2008 all + +This creates packages for all the various drivers under +install\2008\x64\fre (ibbus, ipoib, mlx4_bus, winverbs, etc.) + + +3. Deploy the packages to the head node. + +Use etc\depwo.bat to copy the packaged files to the HPC cluster +head node for installation across the cluster. The files are +copied into \winof\install on the head node. For example, the +following deploys the packages to a head node named 'hpc-head'. + + depwo fre x64 2008 hpc-head + + +4. Add a test certificate. + +NOTE: This step only needs to be done once. + +As part of the package deployment, batch files were copied to the +head node. Run \winof\install\addcert.bat on the head node to create +a test certificate (WinOFCert.cer) that can be used to test sign the +drivers. + + cd \winof\install + addcert + +To support test signed drivers, you may need to execute the following +command across the cluster. + + clusrun bcdedit -set testsigning on + clusrun shutdown /r + + +5. Sign the drivers. + +Run \winof\install\signall to create driver catalog files and sign +all drivers, libraries, and executables that were deployed to the +head node. + + cd \winof\install + signall + +You can limit signing to a specific package by changing into that +package's directory and running signwo.bat. + + +6. Install the packages. + +You can install the packages by running dpinst in each package. Packages +should be installed in the following order, depending on your HCA type: + + mlx4_bus -> mlx4_hca -> ipoib + mthca -> ipoib + +Note: The HCA drivers automatically install the ibbus, winverbs, and +winmad packages. Separate installations of those packages are not +necessary. The following provides an installation example: + + clusrun \\hpc-head\c$\winof\install\mlx4_bus\dpinst -f -q -c + clusrun \\hpc-head\c$\winof\install\mlx4_hca\dpinst -f -q -c + clusrun \\hpc-head\c$\winof\install\ipoib\dpinst -f -q -c diff --git a/branches/WOF2-3/docs/interfaces.txt b/branches/WOF2-3/docs/interfaces.txt new file mode 100755 index 00000000..66a80ec8 --- /dev/null +++ b/branches/WOF2-3/docs/interfaces.txt @@ -0,0 +1,40 @@ +WinOF provides several userspace interfaces. The main application +interfaces are given below, along with a brief description of each. + + +libibverbs +OFA interface available on windows and linux + This is the only linux verbs interface, which was ported to + windows to support portability. This sits over winverbs. + It provides low abstraction to the hardware, but does not + expose windows specific features, like overlapped operations + for asynchronous control. This is a good choice for low-level + access, with portability between windows and linux. + +WinVerbs +OFA windows interface + Lowest level windows verbs interface for applications. Most + of the other interfaces sit over this interface. This provides + the lowest abstraction to the hardware, while also exposing + windows specific features. This is a good choice for + low-level access on windows. + +DAPL (Direct Access Programming Library) +Industry standard RDMA interface for multiple OS's + Hardware providers may support this interface, even if not + part of OFA. This sits over libibverbs and ibal. This provides a + higher level of abstraction, but provides the most portability. + +Network Direct (ND) +Microsoft defined interface for windows + Hardware providers may support this interface, even if not + part of OFA. This sits over winverbs and ibal. This provides + a higher level of abstraction, but may provide access to the + most hardware on Windows platforms. + +IBAL (InfiniBand Access Layer) +OFA windows interface + Older windows interface. This is currently a peer to winverbs, + with a longer term goal of moving it over winverbs. The + interface will be supported going forward. This provides low + level abstraction, but does not expose windows specific features. diff --git a/branches/WOF2-3/docs/maintainers.txt b/branches/WOF2-3/docs/maintainers.txt new file mode 100644 index 00000000..91e3b949 --- /dev/null +++ b/branches/WOF2-3/docs/maintainers.txt @@ -0,0 +1,61 @@ +CompLib +Leonid Keller +Tzachi Dar + +DAPL/DAT +NOTE: main source repository is OFA dapl git tree +WinOF mirrors source code +Arlin Davis + +IBBus +Leonid Keller +Tzachi Dar + +Infiniband-diags +NOTE: main source repository is OFA management git tree +WinOF mirrors source code +Sean Hefty + +IPoIB +Tzachi Dar + +mlx4 +Leonid Keller +Tzachi Dar + +mthca +Leonid Keller +Tzachi Dar + +OFED compatibility libraries: +libibverbs, libibmad, libibumad, librdmacm, libibnetdisc +NOTE: +libibverbs, libibumad, and librdmacm are windows implementations +of the OFED interfaces +libibmad and libibnetdisc are WinOF mirrors of code maintained +in the OFA management git tree +Sean Hefty + +OpenSM +Yevgeny Kliteynik + +perftest (tests/perftest) +Sean Hefty + +QlgcVNIC +No current maintainer. + +SRP +Leonid Keller + +WinOF Installer +Stan Smith + +WinMAD +Sean Hefty + +WinVerbs +Sean Hefty + +WSD +Tzachi Dar diff --git a/branches/WOF2-3/docs/masterindex.html b/branches/WOF2-3/docs/masterindex.html new file mode 100644 index 00000000..b0e6139b --- /dev/null +++ b/branches/WOF2-3/docs/masterindex.html @@ -0,0 +1,2741 @@ + + + + +Index + + + + +Generated from ./inc/ with ROBODoc v4.99.17 on Sun Mar 04 2007 18:17:52 +
+

+[Sourcefiles] +[Index] +[Definitions] +[Functions] +[Modules] +[Structures] +

+

Index

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+64-bit Print Format +Access Layer +Asynchronous Processor
+Atomic Operations +ATS +Byte Swapping
+cl_async_proc.h +cl_async_proc_construct +cl_async_proc_destroy
+cl_async_proc_init +cl_async_proc_item_t +cl_async_proc_queue
+cl_async_proc_t +cl_atomic.h +cl_atomic_add
+cl_atomic_comp_xchg +cl_atomic_dec +cl_atomic_inc
+cl_atomic_sub +cl_atomic_xchg +cl_break
+cl_byteswap.h +cl_check_for_read +cl_check_for_write
+cl_comppool.h +cl_copy_from_user +cl_copy_to_user
+cl_cpool_construct +cl_cpool_count +cl_cpool_destroy
+cl_cpool_get +cl_cpool_grow +cl_cpool_init
+cl_cpool_put +cl_cpool_t +cl_dbg_out
+cl_debug.h +cl_destroy_type_t +CL_ENTER
+cl_event.h +cl_event_construct +cl_event_destroy
+cl_event_init +cl_event_reset +cl_event_signal
+cl_event_wait_on +CL_EXIT +cl_fleximap.h
+cl_fmap_apply_func +cl_fmap_count +cl_fmap_delta
+cl_fmap_end +cl_fmap_get +cl_fmap_head
+cl_fmap_init +cl_fmap_insert +cl_fmap_item_t
+cl_fmap_key +cl_fmap_merge +cl_fmap_next
+cl_fmap_prev +cl_fmap_remove +cl_fmap_remove_all
+cl_fmap_remove_item +cl_fmap_t +cl_fmap_tail
+cl_free +cl_get_pagesize +cl_get_physaddr
+cl_get_tick_count +cl_get_tick_freq +cl_get_time_stamp
+cl_get_time_stamp_sec +cl_get_time_stamp_usec +cl_hton16
+CL_HTON16 +CL_HTON32 +cl_hton32
+cl_hton64 +CL_HTON64 +cl_ioctl.h
+cl_ioctl_cmd +cl_ioctl_complete +cl_ioctl_ctl_code
+cl_ioctl_handle_t +cl_ioctl_in_buf +cl_ioctl_in_size
+cl_ioctl_out_buf +cl_ioctl_out_size +cl_ioctl_process
+cl_ioctl_request +cl_ioctl_result +cl_ioctl_type
+cl_irqlock.h +cl_irqlock_acquire +cl_irqlock_construct
+cl_irqlock_destroy +cl_irqlock_init +cl_irqlock_release
+cl_is_blockable +cl_is_cpool_inited +cl_is_fmap_empty
+cl_is_item_in_qlist +cl_is_list_empty +cl_is_list_inited
+cl_is_map_empty +cl_is_map_inited +cl_is_object_in_list
+cl_is_pool_inited +cl_is_qcpool_inited +cl_is_qlist_empty
+cl_is_qmap_empty +cl_is_qpool_inited +cl_is_rbmap_empty
+cl_is_state_valid +cl_is_sys_callback_inited +cl_list.h
+cl_list_apply_func +cl_list_construct +cl_list_count
+cl_list_destroy +cl_list_end +cl_list_find_from_head
+cl_list_find_from_tail +cl_list_head +cl_list_init
+cl_list_insert_array_head +cl_list_insert_array_tail +cl_list_insert_head
+cl_list_insert_next +cl_list_insert_prev +cl_list_insert_tail
+cl_list_item_t +cl_list_iterator_t +cl_list_next
+cl_list_obj +cl_list_obj_t +cl_list_prev
+cl_list_remove_all +cl_list_remove_head +cl_list_remove_item
+cl_list_remove_object +cl_list_remove_tail +cl_list_t
+cl_list_tail +cl_log.h +cl_log_event
+cl_log_type_t +cl_malloc +cl_map.h
+cl_map_construct +cl_map_count +cl_map_delta
+cl_map_destroy +cl_map_end +cl_map_get
+cl_map_head +cl_map_init +cl_map_insert
+cl_map_item_t +cl_map_iterator_t +cl_map_key
+cl_map_merge +cl_map_next +cl_map_obj
+cl_map_obj_t +cl_map_prev +cl_map_remove
+cl_map_remove_all +cl_map_remove_item +cl_map_t
+cl_map_tail +cl_math.h +cl_mem_display
+cl_memclr +cl_memcmp +cl_memcpy
+cl_memory.h +cl_memset +cl_msg_out
+cl_mutex.h +cl_mutex_acquire +cl_mutex_construct
+cl_mutex_destroy +cl_mutex_init +cl_mutex_release
+cl_ntoh +cl_ntoh16 +CL_NTOH16
+CL_NTOH32 +cl_ntoh32 +cl_ntoh64
+CL_NTOH64 +cl_obj.h +cl_obj_construct
+cl_obj_deinit +cl_obj_deref +cl_obj_destroy
+cl_obj_init +cl_obj_insert_rel +cl_obj_insert_rel_parent_locked
+cl_obj_lock +cl_obj_mgr_create +cl_obj_mgr_destroy
+cl_obj_mgr_t +cl_obj_ref +cl_obj_rel_t
+cl_obj_remove_rel +cl_obj_reset +cl_obj_t
+cl_obj_type +cl_obj_unlock +cl_palloc
+cl_panic +cl_passivelock.h +cl_perf.h
+cl_perf_clr +cl_perf_construct +cl_perf_destroy
+cl_perf_display +cl_perf_inc +cl_perf_init
+cl_perf_log +cl_perf_reset +cl_perf_start
+cl_perf_stop +cl_perf_update +cl_perf_update_ctr
+cl_pfn_async_proc_cb_t +cl_pfn_cpool_dtor_t +cl_pfn_cpool_init_t
+cl_pfn_fmap_apply_t +cl_pfn_fmap_cmp_t +cl_pfn_ioctl_handler_t
+cl_pfn_list_apply_t +cl_pfn_list_find_t +cl_pfn_obj_call_t
+cl_pfn_pool_dtor_t +cl_pfn_pool_init_t +cl_pfn_ptr_vec_apply_t
+cl_pfn_ptr_vec_find_t +cl_pfn_qcpool_dtor_t +cl_pfn_qcpool_init_t
+cl_pfn_qlist_apply_t +cl_pfn_qlist_find_t +cl_pfn_qmap_apply_t
+cl_pfn_qpool_dtor_t +cl_pfn_qpool_init_t +cl_pfn_req_cb_t
+cl_pfn_reqmgr_get_count_t +cl_pfn_sys_callback_t +cl_pfn_thread_callback_t
+cl_pfn_timer_callback_t +cl_pfn_vec_apply_t +cl_pfn_vec_dtor_t
+cl_pfn_vec_find_t +cl_pfn_vec_init_t +cl_plock_acquire
+cl_plock_construct +cl_plock_destroy +cl_plock_excl_acquire
+cl_plock_init +cl_plock_release +cl_plock_t
+cl_pool.h +cl_pool_construct +cl_pool_count
+cl_pool_destroy +cl_pool_get +cl_pool_grow
+cl_pool_init +cl_pool_item_t +cl_pool_put
+cl_pool_t +CL_PRINT +cl_proc_count
+cl_ptr_vector.h +cl_ptr_vector_apply_func +cl_ptr_vector_at
+cl_ptr_vector_construct +cl_ptr_vector_destroy +cl_ptr_vector_find_from_end
+cl_ptr_vector_find_from_start +cl_ptr_vector_get +cl_ptr_vector_get_capacity
+cl_ptr_vector_get_size +cl_ptr_vector_init +cl_ptr_vector_insert
+cl_ptr_vector_remove +cl_ptr_vector_set +cl_ptr_vector_set_capacity
+cl_ptr_vector_set_min_size +cl_ptr_vector_set_size +cl_ptr_vector_t
+cl_pzalloc +cl_qcomppool.h +cl_qcpool_construct
+cl_qcpool_count +cl_qcpool_destroy +cl_qcpool_get
+cl_qcpool_grow +cl_qcpool_init +cl_qcpool_put
+cl_qcpool_put_list +cl_qcpool_t +cl_qlist.h
+cl_qlist_apply_func +cl_qlist_count +cl_qlist_end
+cl_qlist_find_from_head +cl_qlist_find_from_tail +cl_qlist_find_next
+cl_qlist_find_prev +cl_qlist_head +cl_qlist_init
+cl_qlist_insert_array_head +cl_qlist_insert_array_tail +cl_qlist_insert_head
+cl_qlist_insert_list_head +cl_qlist_insert_list_tail +cl_qlist_insert_next
+cl_qlist_insert_prev +cl_qlist_insert_tail +cl_qlist_move_items
+cl_qlist_next +cl_qlist_obj +cl_qlist_prev
+cl_qlist_remove_all +cl_qlist_remove_head +cl_qlist_remove_item
+cl_qlist_remove_tail +cl_qlist_set_obj +cl_qlist_t
+cl_qlist_tail +cl_qlock_pool_construct +cl_qlock_pool_destroy
+cl_qlock_pool_get +cl_qlock_pool_init +cl_qlock_pool_put
+cl_qlock_pool_t +cl_qlockpool.h +cl_qmap.h
+cl_qmap_apply_func +cl_qmap_count +cl_qmap_delta
+cl_qmap_end +cl_qmap_get +cl_qmap_head
+cl_qmap_init +cl_qmap_insert +cl_qmap_key
+cl_qmap_merge +cl_qmap_next +cl_qmap_obj
+cl_qmap_prev +cl_qmap_remove +cl_qmap_remove_all
+cl_qmap_remove_item +cl_qmap_set_obj +cl_qmap_t
+cl_qmap_tail +cl_qpool.h +cl_qpool_construct
+cl_qpool_count +cl_qpool_destroy +cl_qpool_get
+cl_qpool_grow +cl_qpool_init +cl_qpool_put
+cl_qpool_put_list +cl_qpool_t +cl_rbmap.h
+cl_rbmap_count +cl_rbmap_end +cl_rbmap_init
+cl_rbmap_insert +cl_rbmap_item_t +cl_rbmap_left
+cl_rbmap_remove_item +cl_rbmap_reset +cl_rbmap_right
+cl_rbmap_root +cl_rbmap_t +cl_rel_alloc
+cl_rel_free +cl_req_mgr_construct +cl_req_mgr_destroy
+cl_req_mgr_get +cl_req_mgr_init +cl_req_mgr_resume
+cl_req_mgr_t +cl_req_type_t +cl_reqmgr.h
+cl_spinlock.h +cl_spinlock_acquire +cl_spinlock_construct
+cl_spinlock_destroy +cl_spinlock_init +cl_spinlock_release
+CL_STATUS_MSG +cl_status_t +cl_sys_callback_get
+cl_sys_callback_put +cl_sys_callback_queue +cl_syscallback.h
+cl_thread.h +cl_thread_pool_construct +cl_thread_pool_destroy
+cl_thread_pool_init +cl_thread_pool_signal +cl_thread_pool_t
+cl_thread_stall +cl_thread_suspend +cl_threadpool.h
+cl_timer.h +cl_timer_construct +cl_timer_destroy
+cl_timer_init +cl_timer_start +cl_timer_stop
+cl_timer_trim +CL_TRACE +CL_TRACE_EXIT
+cl_types.h +cl_vector.h +cl_vector_apply_func
+cl_vector_at +cl_vector_construct +cl_vector_destroy
+cl_vector_find_from_end +cl_vector_find_from_start +cl_vector_get
+cl_vector_get_capacity +cl_vector_get_ptr +cl_vector_get_size
+cl_vector_init +cl_vector_set +cl_vector_set_capacity
+cl_vector_set_min_size +cl_vector_set_size +cl_vector_t
+cl_waitobj.h +cl_waitobj_create +cl_waitobj_deref
+cl_waitobj_destroy +cl_waitobj_handle_t +cl_waitobj_ref
+cl_waitobj_reset +cl_waitobj_signal +cl_waitobj_wait_on
+cl_zalloc +comp_lib.h +Component Library
+Composite Pool +Constants +Data Types
+Debug Levels +Debug Output +DM_SVC_NAME
+Event +Flexi Map +ib_access_t
+ib_add_svc_entry +ib_al.h +ib_al_flags_t
+ib_alloc_pd +ib_api_status_t +ib_apm_state_t
+ib_apr_info_t +ib_apr_pdata_t +ib_apr_status_t
+ib_ari_t +ib_async_event_rec_t +ib_async_event_t
+ib_atomic_t +ib_av_attr_t +ib_bind_mw
+ib_bind_wr_t +ib_ca_attr_t +ib_ca_mod_t
+ib_cancel_mad +ib_cancel_query +ib_cep_listen_t
+ib_ci_call +ib_ci_op_t +IB_CLASS_CAP_GETSET
+IB_CLASS_CAP_TRAP +ib_class_is_rmpp +ib_class_is_vendor_specific
+ib_class_is_vendor_specific_high +ib_class_is_vendor_specific_low +ib_class_port_info_t
+IB_CLASS_RESP_TIME_MASK +ib_close_al +ib_close_ca
+ib_cm_apr +ib_cm_apr_rec_t +ib_cm_apr_t
+ib_cm_cancel +ib_cm_cap_mask_t +ib_cm_drep
+ib_cm_drep_rec_t +ib_cm_drep_t +ib_cm_dreq
+ib_cm_dreq_rec_t +ib_cm_dreq_t +ib_cm_failover_t
+ib_cm_handoff +ib_cm_lap +ib_cm_lap_rec_t
+ib_cm_lap_t +ib_cm_listen +ib_cm_listen_t
+ib_cm_mra +ib_cm_mra_rec_t +ib_cm_mra_t
+ib_cm_rej +ib_cm_rej_rec_t +ib_cm_rej_t
+ib_cm_rep +ib_cm_rep_rec_t +ib_cm_rep_t
+ib_cm_req +ib_cm_req_rec_t +ib_cm_req_t
+ib_cm_rtu +ib_cm_rtu_rec_t +ib_cm_rtu_t
+ib_copy_ca_attr +ib_cq_create_t +ib_create_av
+ib_create_cq +ib_create_ioc +ib_create_mad_pool
+ib_create_mw +ib_create_qp +ib_create_srq
+ib_dealloc_pd +IB_DEFAULT_PARTIAL_PKEY +IB_DEFAULT_PKEY
+IB_DEFAULT_SUBNET_PREFIX +ib_dereg_mad_pool +ib_dereg_mr
+ib_dereg_pnp +ib_dereg_svc +ib_destroy_av
+ib_destroy_cq +ib_destroy_ioc +ib_destroy_mad_pool
+ib_destroy_mw +ib_destroy_qp +ib_destroy_srq
+ib_device_attr_mask_t +ib_dgrm_info_t +ib_dm_get_slot_lo_hi
+ib_dm_mad_t +ib_dm_set_slot_lo_hi +ib_drep_pdata_t
+ib_dreq_pdata_t +ib_event_rec_t +ib_field32_t
+ib_force_apm +ib_get_async_event_str +ib_get_ca_by_gid
+ib_get_ca_guids +ib_get_err_str +ib_get_guid
+ib_get_mad +ib_get_mad_buf +ib_get_node_type_str
+ib_get_port_by_gid +ib_get_port_state_from_str +ib_get_port_state_str
+ib_get_qp_type_str +ib_get_query_node_rec +ib_get_query_path_rec
+ib_get_query_portinfo_rec +ib_get_query_result +ib_get_query_svc_rec
+ib_get_spl_qp +ib_get_wc_status_str +ib_get_wc_type_str
+ib_get_wr_type_str +ib_gid_get_guid +ib_gid_get_subnet_prefix
+ib_gid_is_link_local +ib_gid_is_site_local +ib_gid_pair_t
+ib_gid_prefix_t +ib_gid_set_default +ib_gid_t
+ib_gmp_t +ib_grh_get_ver_class_flow +ib_grh_set_ver_class_flow
+ib_grh_t +ib_guid_info_t +ib_guid_pair_t
+ib_inform_get_dev_id +ib_inform_get_prod_type +ib_inform_get_qpn
+ib_inform_get_resp_time_val +ib_inform_get_trap_num +ib_inform_get_vend_id
+ib_inform_info_record_t +ib_inform_set_dev_id +ib_inform_set_prod_type
+ib_inform_set_qpn +ib_inform_set_resp_time_val +ib_inform_set_trap_num
+ib_inform_set_vend_id +ib_init_dgrm_svc +ib_init_type_t
+IB_INVALID_PORT_NUM +ib_ioc_profile_t +ib_iou_info_diag_dev_id
+ib_iou_info_option_rom +ib_iou_info_t +ib_join_mcast
+ib_lap_pdata_t +ib_leave_mcast +ib_lft_record_t
+IB_LID_MCAST_END +IB_LID_MCAST_START +ib_lid_pair_t
+IB_LID_PERMISSIVE +IB_LID_UCAST_END +IB_LID_UCAST_START
+ib_link_states_t +ib_listen_err_rec_t +ib_listen_info_t
+ib_local_ds_t +ib_local_mad +IB_MAD_ATTR_CLASS_PORT_INFO
+IB_MAD_ATTR_DIAG_CODE +IB_MAD_ATTR_DIAGNOSTIC_TIMEOUT +IB_MAD_ATTR_GUID_INFO
+IB_MAD_ATTR_GUIDINFO_RECORD +IB_MAD_ATTR_INFORM_INFO +IB_MAD_ATTR_INFORM_INFO_RECORD
+IB_MAD_ATTR_IO_CONTROLLER_PROFILE +IB_MAD_ATTR_IO_UNIT_INFO +IB_MAD_ATTR_LED_INFO
+IB_MAD_ATTR_LFT_RECORD +IB_MAD_ATTR_LIN_FWD_TBL +IB_MAD_ATTR_LINK_RECORD
+IB_MAD_ATTR_MCAST_FWD_TBL +IB_MAD_ATTR_MCMEMBER_RECORD +IB_MAD_ATTR_MULTIPATH_RECORD
+IB_MAD_ATTR_NODE_DESC +IB_MAD_ATTR_NODE_INFO +IB_MAD_ATTR_NODE_RECORD
+IB_MAD_ATTR_NOTICE +IB_MAD_ATTR_P_KEY_TABLE +IB_MAD_ATTR_PATH_RECORD
+IB_MAD_ATTR_PKEYTBL_RECORD +IB_MAD_ATTR_PORT_CNTRS +IB_MAD_ATTR_PORT_INFO
+IB_MAD_ATTR_PORT_SMPL_CTRL +IB_MAD_ATTR_PORT_SMPL_RSLT +IB_MAD_ATTR_PORTINFO_RECORD
+IB_MAD_ATTR_PREPARE_TO_TEST +IB_MAD_ATTR_RND_FWD_TBL +IB_MAD_ATTR_SERVICE_ENTRIES
+IB_MAD_ATTR_SERVICE_RECORD +IB_MAD_ATTR_SLVL_RECORD +IB_MAD_ATTR_SLVL_TABLE
+IB_MAD_ATTR_SM_INFO +IB_MAD_ATTR_SMINFO_RECORD +IB_MAD_ATTR_SVC_ASSOCIATION_RECORD
+IB_MAD_ATTR_SWITCH_INFO +IB_MAD_ATTR_TEST_DEVICE_LOOP +IB_MAD_ATTR_TEST_DEVICE_ONCE
+IB_MAD_ATTR_TRACE_RECORD +IB_MAD_ATTR_VENDOR_DIAG +IB_MAD_ATTR_VL_ARBITRATION
+IB_MAD_ATTR_VLARB_RECORD +ib_mad_element_t +ib_mad_init_new
+ib_mad_init_response +ib_mad_is_response +IB_MAD_METHOD_GET
+IB_MAD_METHOD_GET_RESP +IB_MAD_METHOD_GETTABLE +IB_MAD_METHOD_GETTABLE_RESP
+IB_MAD_METHOD_REPORT +IB_MAD_METHOD_REPORT_RESP +IB_MAD_METHOD_RESP_MASK
+IB_MAD_METHOD_SEND +IB_MAD_METHOD_SET +IB_MAD_METHOD_TRAP
+IB_MAD_METHOD_TRAP_REPRESS +IB_MAD_STATUS_BUSY +IB_MAD_STATUS_INVALID_FIELD
+IB_MAD_STATUS_REDIRECT +IB_MAD_STATUS_UNSUP_CLASS_VER +IB_MAD_STATUS_UNSUP_METHOD
+IB_MAD_STATUS_UNSUP_METHOD_ATTR +ib_mad_svc_t +ib_mad_svc_type_t
+ib_mad_t +IB_MAX_METHOD +IB_MCAST_BLOCK_ID_MASK_HO
+IB_MCAST_BLOCK_SIZE +IB_MCAST_MASK_SIZE +IB_MCAST_MAX_BLOCK_ID
+IB_MCAST_POSITION_MASK_HO +IB_MCAST_POSITION_MAX +IB_MCAST_POSITION_SHIFT
+ib_mcast_rec_t +ib_mcast_req_t +IB_MCLASS_BIS
+IB_MCLASS_BM +IB_MCLASS_COMM_MGMT +IB_MCLASS_DEV_ADM
+IB_MCLASS_DEV_MGMT +IB_MCLASS_PERF +IB_MCLASS_SNMP
+IB_MCLASS_SUBN_ADM +IB_MCLASS_SUBN_DIR +IB_MCLASS_SUBN_LID
+IB_MCLASS_VENDOR_HIGH_RANGE_MAX +IB_MCLASS_VENDOR_HIGH_RANGE_MIN +IB_MCLASS_VENDOR_LOW_RANGE_MAX
+IB_MCLASS_VENDOR_LOW_RANGE_MIN +ib_member_get_scope +ib_member_get_scope_state
+ib_member_get_sl_flow_hop +ib_member_get_state +ib_member_rec_t
+ib_member_set_join_state +ib_member_set_scope +ib_member_set_scope_state
+ib_member_set_sl_flow_hop +ib_member_set_state +ib_modify_av
+ib_modify_ca +ib_modify_cq +ib_modify_qp
+ib_modify_srq +ib_mr_attr_t +ib_mr_create_t
+ib_mr_mod_t +ib_mra_pdata_t +IB_MTU_LEN_TYPE
+IB_MULTIPATH_REC_BASE_MASK +ib_net16_t +ib_net32_t
+ib_net64_t +ib_node_info_get_local_port_num +ib_node_info_get_vendor_id
+ib_node_info_t +IB_NODE_NUM_PORTS_MAX +IB_NODE_TYPE_CA
+IB_NODE_TYPE_ROUTER +IB_NODE_TYPE_SWITCH +ib_notice_get_count
+ib_notice_get_dev_id +ib_notice_get_generic +ib_notice_get_prod_type
+ib_notice_get_toggle +ib_notice_get_trap_num +ib_notice_get_type
+ib_notice_get_vend_id +IB_NOTICE_NODE_TYPE_CA +IB_NOTICE_NODE_TYPE_ROUTER
+IB_NOTICE_NODE_TYPE_SUBN_MGMT +IB_NOTICE_NODE_TYPE_SWITCH +ib_notice_set_count
+ib_notice_set_dev_id +ib_notice_set_generic +ib_notice_set_prod_type
+ib_notice_set_toggle +ib_notice_set_trap_num +ib_notice_set_type
+ib_notice_set_vend_id +ib_open_al +ib_open_ca
+ib_path_get_ipd +IB_PATH_REC_BASE_MASK +ib_path_rec_flow_lbl
+ib_path_rec_hop_limit +ib_path_rec_init_local +ib_path_rec_mtu
+ib_path_rec_mtu_sel +ib_path_rec_num_path +ib_path_rec_pkt_life
+ib_path_rec_pkt_life_sel +ib_path_rec_rate +ib_path_rec_rate_sel
+IB_PATH_REC_SELECTOR_MASK +ib_path_rec_set_hop_flow_raw +ib_path_rec_sl
+ib_path_rec_t +IB_PATH_SELECTOR_TYPE +ib_pd_type_t
+ib_peek_cq +ib_pfn_cm_apr_cb_t +ib_pfn_cm_drep_cb_t
+ib_pfn_cm_dreq_cb_t +ib_pfn_cm_lap_cb_t +ib_pfn_cm_mra_cb_t
+ib_pfn_cm_rej_cb_t +ib_pfn_cm_rep_cb_t +ib_pfn_cm_req_cb_t
+ib_pfn_cm_rtu_cb_t +ib_pfn_comp_cb_t +ib_pfn_destroy_cb_t
+ib_pfn_event_cb_t +ib_pfn_listen_err_cb_t +ib_pfn_mad_comp_cb_t
+ib_pfn_mcast_cb_t +ib_pfn_pnp_cb_t +ib_pfn_query_cb_t
+ib_pfn_reg_svc_cb_t +ib_pfn_report_cb_t +ib_pfn_sub_cb_t
+ib_phys_create_t +ib_phys_range_t +IB_PKEY_BASE_MASK
+IB_PKEY_ENTRIES_MAX +ib_pkey_get_base +ib_pkey_is_full_member
+ib_pkey_is_invalid +IB_PKEY_MAX_BLOCKS +ib_pkey_table_info_t
+IB_PKEY_TYPE_MASK +ib_pnp_ca_rec_t +ib_pnp_class_t
+ib_pnp_event_t +ib_pnp_ioc_path_rec_t +ib_pnp_ioc_rec_t
+ib_pnp_iou_rec_t +ib_pnp_port_rec_t +ib_pnp_rec_t
+ib_pnp_req_t +ib_poll_cq +ib_port_attr_mod_t
+ib_port_attr_t +ib_port_cap_t +ib_port_counters_t
+ib_port_info_compute_rate +ib_port_info_get_init_type +ib_port_info_get_link_speed_active
+ib_port_info_get_link_speed_sup +ib_port_info_get_lmc +ib_port_info_get_mpb
+ib_port_info_get_mtu_cap +ib_port_info_get_neighbor_mtu +ib_port_info_get_op_vls
+ib_port_info_get_port_state +ib_port_info_get_sm_sl +ib_port_info_get_vl_cap
+ib_port_info_set_link_speed_sup +ib_port_info_set_lmc +ib_port_info_set_mpb
+ib_port_info_set_neighbor_mtu +ib_port_info_set_op_vls +ib_port_info_set_port_state
+ib_port_info_set_sm_sl +ib_port_info_set_state_no_change +ib_port_info_set_timeout
+ib_port_info_t +ib_post_recv +ib_post_send
+ib_post_srq_recv +ib_put_mad +IB_QP1_WELL_KNOWN_Q_KEY
+ib_qp_attr_t +ib_qp_create_t +ib_qp_mod_t
+ib_qp_opts_t +ib_qp_state_t +ib_qp_type_t
+ib_query +ib_query_av +ib_query_ca
+ib_query_ca_by_guid +ib_query_cq +ib_query_mr
+ib_query_mw +ib_query_qp +ib_query_rec_t
+ib_query_req_t +ib_query_srq +ib_query_type_t
+ib_rearm_cq +ib_rearm_n_cq +ib_recv_opt_t
+ib_recv_wr_t +ib_reg_ioc +ib_reg_mad_pool
+ib_reg_mad_svc +ib_reg_mem +ib_reg_phys
+ib_reg_pnp +ib_reg_shared +ib_reg_shmid
+ib_reg_svc +ib_reg_svc_rec_t +ib_reg_svc_req_t
+ib_rej_pdata_t +ib_rej_status_t +ib_reject_ioc
+ib_remove_svc_entry +ib_rep_pdata_t +ib_report_rec_t
+ib_req_pdata_t +ib_rereg_mem +ib_rereg_phys
+ib_rmpp_is_flag_set +ib_rmpp_mad_t +ib_rtu_pdata_t
+ib_sa_mad_get_payload_ptr +ib_sa_mad_t +ib_send_mad
+ib_send_opt_t +ib_send_wr_t +ib_shmid_t
+ib_sidr_rep_pdata_t +ib_sidr_req_pdata_t +ib_slvl_table_get_vl
+ib_slvl_table_record_t +ib_slvl_table_set_vl +ib_slvl_table_t
+ib_sm_info_t +IB_SMINFO_ATTR_MOD_ACKNOWLEDGE +IB_SMINFO_ATTR_MOD_DISABLE
+IB_SMINFO_ATTR_MOD_DISCOVER +IB_SMINFO_ATTR_MOD_HANDOVER +IB_SMINFO_ATTR_MOD_STANDBY
+ib_sminfo_get_priority +ib_sminfo_get_state +IB_SMINFO_STATE_DISCOVERING
+IB_SMINFO_STATE_INIT +IB_SMINFO_STATE_MASTER +IB_SMINFO_STATE_NOTACTIVE
+IB_SMINFO_STATE_STANDBY +IB_SMP_DIRECTION +ib_smp_get_payload_ptr
+ib_smp_get_status +ib_smp_init_new +ib_smp_is_d
+ib_smp_is_response +IB_SMP_STATUS_MASK +ib_smp_t
+ib_srq_attr_mask_t +ib_srq_attr_t +ib_sub_rec_t
+ib_sub_req_t +IB_SUBNET_PATH_HOPS_MAX +ib_subscribe
+ib_svc_entries_t +ib_svc_entry_t +ib_switch_info_clear_state_change
+ib_switch_info_get_state_change +ib_switch_info_t +ib_sync_destroy
+ib_types.h +ib_unsubscribe +ib_user_query_t
+ib_vl_arb_element_get_vl +ib_vl_arb_element_set_vl +ib_vl_arb_element_t
+ib_vl_arb_table_record_t +ib_vl_arb_table_t +ib_wc_status_t
+ib_wc_t +ib_wc_type_t +ib_wr_type_t
+ioc_at_slot +IOCTL Object +IOCTL_CODE
+Irqlock +Join States +List
+Log Provider +MAD_BLOCK_GRH_SIZE +MAD_BLOCK_SIZE
+MAD_RMPP_DATA_SIZE +MAD_RMPP_HDR_SIZE +Map
+MAX +Memory Management +MIN
+mlnx_create_fmr +mlnx_destroy_fmr +mlnx_fmr_create_t
+mlnx_map_fmr +mlnx_unmap_fmr +Mutex
+Object +Object States +offsetof
+Parameter Keywords +PARENT_STRUCT +Passive Lock
+PERF_DECLARE +PERF_DECLARE_START +Performance Counters
+Pointer Vector +Pool +Quick Composite Pool
+Quick List +Quick Locking Pool +Quick Map
+Quick Pool +RB Map +Request Manager
+ROUNDUP +Spinlock +System Callback
+Thread Pool +Timer +Type Definitions
+UNUSED_PARAM +Vector +Wait Object
+ + diff --git a/branches/WOF2-3/docs/openfabrics.gif b/branches/WOF2-3/docs/openfabrics.gif new file mode 100644 index 0000000000000000000000000000000000000000..148d87752e676f4fe97573730f58cc5e0182878c GIT binary patch literal 3660 zcmWNSdobj zLv27|5LiVtprosaR{)i9%0z;S8WFp}d;>{sqdG}LQ(cR^iJ(g*>u5s^V)Q7w`kN_$ zS**5^&1NG5z%*6Y*dAwm+<1$Tskw=&70cYx+{)V0cAJge_HEnk?T9;b0a~lW4tv14 zLv_c^9shGgJ2fdd-v!(|RNV^*F886Hopfg!&Bc}E`q0JIS<&l(hFcrM-4){3OZ0AY z_3(1{bR+q6Dh1rz?d9pk+zlLjuD$OL5HiN}*#m@*d+%kc1@!>o<9mI56v9XT@$&_u zUl;}5F$(DR^WR5i^%EmT1A_cXkz=U1@t^~NAp50lXfG@Dpjp%)<;WQ6*uSCSArVoB zw2!~odUTK)GY}OWX>n{^|HQwJ@y`rTP8^LpVwU=^!>N}pDZ>eg$KsPt_?&Lpnm(1B zay&4#(f5qhlQ-g+HMuL}^~uvIL22UCsi%T@{i)nD0sIlKyf$ST)NPy(zzPDeKyOcI|?&`ljgW<%&vC!Hs(UHTl)5ij(zo#W%%y)ssba?boWS z1a-31#&>wKJ@nWh@X7!c=GiA;Jbmx{g0mxc1wpl zhCWH8OTE(f&xVKkM#tJmze-+we?B(S^WyW9SN{%lZI3rXEkO z4o!Y}Gc_?RUwJK?o|M0NKJ)#R{M*afuamQL)3dVixu3GxW%=8M*Yn?I-_Fb~yq{eB z@pfTue(~*p3qR)GeUyLrwfKHv=F{5Zr!VtMKi)0>USD6=`2mMufpx$H1pq+!Unc@e>}@BN<4tdx*DUUq$X8xnL1$BDc454ek<#ACGdh)1CQA zc>)GbUN^kFYJ91Qu&2a)p6=N@Q#aI7>~Lmy`xlqeXyT2oKR-hQ=JV{5rx`7c^Zz}( zwMBj7kKQYNz837amj&JWmx@MHu-aM#)9h`V>x>Qz{jTsMN_QMRc9@rv$geb8<2;>Y zYwR~@edv(B%ZbW?s^_1)c|I*)-{<mzSI|t8IZ2+_U`7A+QML3;KyaX+{Z_=K}xh_!$!>#mcV2vqxh<^O#^)IfQ^Ybe#^2C!I>0heR(nPo zZ3e884Q*-PSBH5FvlfoJQ$V2ZvRj%Y+GfqE;-!>WHwPwsdyZ)^mAYpyEbo#jDczQB z35KmEI(?N9N`g!&R#Mq_7gMQKU3_F0@hR2DlP5HHoS(!UndxP?%7K5LL#oPU+g;e3 zeUv;d4zU-L@%G!D8*Mt(vHKZJ>%Q!l-s%x&CaeoAO2eV;u3KRJDb9rwNx7HX^$)w0 zwlAb3169h8HVk$JE)Qw!>%7cUpc!r*A>NBkxVQ2?=2=15)ax>@!jXay-%lx<2DAWv zWP$HXz=VAmqd6fbtmp{!uoIVEEU4V_6%KyhSf;;PZ9h;>fkLQM%mlNoXumiWkg{AZ zAc5D1y5ck~$(XcA`dLr1=i1?m%D9zGd(xm#xA}JYTjOLZ>E3`ISR;LO^mt*Q3Ofo2 z;1q0)&&IY@Cux5f-ZjToV8n)IYFWY`PV9wj-c3=rTAj{F5MxX`J#_USpVw#6ifDEc zZ>Xq~xM>7uVUzp!Zk-$`iA~^e7Y*bR`=}5MGa<*|gN%N`i~_(oG%cmiVcqaJSPa;s zUcM?6XvXLJE$4)tEykVP(si29knFBvt~c44R3#m5?Gb>dmahht8b2{K7FvE! z7pWnK`M9Kw9K?Kx&X;~4UQ!Qsqp{w(Q@R;l^hy+>#*N`5sXGn2pA_B2MwAeVr?oGv&AR#TxjW4xj7(Fq@JRY(y)r8{o^lIJ_QdBbYW z4aXcQL@?&O@#bnNvt)4ey8X%xW?rpt^*wEt#WZ2Su-~ZFI44fgStC#>#sS`hjlxkh z8$iL%fQszaS{{2nif`O%B|OvCqWX%AHk(k-6`?5_^@a?`h(>{nER;MW>(Ozx#HEco zDcLjA)K6Jtas^H(Ul~+cNUcj{L2vt^>y6Cc!4k2vDhzSo&L=u>BVTz-2WgE#;z%&O zQW)AFbW-Dh0&Wxp8(ISeYb9+AbmulGp;x((%s12Ins#!a$EwAsv>FJ;?w6}&Lfqrj zQ72U0DrzS=#@&+~BKSb%;Tlc^P<{_+x-m0oO>DT8fJ>eM=&WA^G`aYrcCavwdZr-V z5nZM1Mm@TPBShV6(2Mw|pKcGg3gL;mQ37(mb^=+L#PK7`sq|X2inJ6J_$EeML)JPs zV61Qk%{66Eo^TY%OeT32>@tBv^C>-T3b7>g##%Bs^Ygm42Rfei6OvA+z*X$q^sG+- zmh4q>`+A#6y_tNHw|^tacit>|-3F(vQKfKh-gWI1p>C=Js?)k&L)S#=@_(&`5&Hi0 znQ%CHX_}pi7y?{*p9z>SFRCo*Z8Aw<)q50=YYEl*59P?QlxDw{Lvzmm+xj7*wZC(y zPLemuLwy!><E2*^n{zwNeWG=ScWi{#%_ z`X+Q&h9TqUAoA|_9VlLC%(*}JJ{|c=t?>Zknt!xfUPq~1Qe^3W3d5WMx5f985p7x& zWoq1xoJ0;fA>9dYZxMY}Z_lBq)iXE$sG&cO;ieM5la}B&=)zB0S!|nbMb~+2j`yFl zJE$Srd!BvWDPDtQ7&SvRUo(5tze;o2&AJ%QR&;dMZiK&Lm6p)F|3OYY?10}H^3)Rd zwry&pVQC;aQwU#<3#0=_f|m}iixBSL@a;?sDi~lGy$r>;(I59Ujc|OEA)7{zrvEzD(E|Y4H;v|r<6PksDchoftmyh!4oB!ct8nl$;Z$T5dttu07|5gb)h0C6;#Fr7bb%? z%xv^94xqwz%98b6p(~=8ATT>k0A|#H)ybd{AOF`_?C*dzleOZQ)H}CW0RJh%uP!N}guz+!9_w+sD-qy;0A3IkfUv{^ z5=E?A7GL0F6$eHG5LG5bPgF>h+7xO=fGidoMT17@gF)0B*yoUS3oIzxh5W3 + + + +Definitions + + + + +Generated from ./inc/ with ROBODoc v4.99.17 on Sun Mar 04 2007 18:17:52 +
+

+[Sourcefiles] +[Index] +[Definitions] +[Functions] +[Modules] +[Structures] +

+

Definitions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+64-bit Print Format +ATS +cl_destroy_type_t
+CL_ENTER +CL_EXIT +CL_HTON16
+CL_HTON32 +CL_HTON64 +cl_ioctl_handle_t
+cl_is_state_valid +cl_list_iterator_t +cl_log_type_t
+cl_map_iterator_t +CL_NTOH16 +CL_NTOH32
+CL_NTOH64 +cl_perf_clr +cl_perf_inc
+cl_perf_log +cl_perf_start +cl_perf_stop
+cl_perf_update +cl_perf_update_ctr +cl_pfn_async_proc_cb_t
+cl_pfn_cpool_dtor_t +cl_pfn_cpool_init_t +cl_pfn_fmap_apply_t
+cl_pfn_fmap_cmp_t +cl_pfn_ioctl_handler_t +cl_pfn_list_apply_t
+cl_pfn_list_find_t +cl_pfn_obj_call_t +cl_pfn_pool_dtor_t
+cl_pfn_pool_init_t +cl_pfn_ptr_vec_apply_t +cl_pfn_ptr_vec_find_t
+cl_pfn_qcpool_dtor_t +cl_pfn_qcpool_init_t +cl_pfn_qlist_apply_t
+cl_pfn_qlist_find_t +cl_pfn_qmap_apply_t +cl_pfn_qpool_dtor_t
+cl_pfn_qpool_init_t +cl_pfn_req_cb_t +cl_pfn_reqmgr_get_count_t
+cl_pfn_sys_callback_t +cl_pfn_thread_callback_t +cl_pfn_timer_callback_t
+cl_pfn_vec_apply_t +cl_pfn_vec_dtor_t +cl_pfn_vec_find_t
+cl_pfn_vec_init_t +CL_PRINT +cl_req_type_t
+CL_STATUS_MSG +cl_status_t +CL_TRACE
+CL_TRACE_EXIT +cl_waitobj_handle_t +Data Types
+Debug Levels +DM_SVC_NAME +ib_access_t
+ib_al_flags_t +ib_api_status_t +ib_apm_state_t
+ib_apr_status_t +ib_async_event_t +ib_atomic_t
+ib_ca_mod_t +ib_cm_cap_mask_t +ib_cm_failover_t
+IB_DEFAULT_PARTIAL_PKEY +IB_DEFAULT_PKEY +IB_DEFAULT_SUBNET_PREFIX
+ib_device_attr_mask_t +ib_gid_prefix_t +ib_gid_t
+ib_init_type_t +IB_INVALID_PORT_NUM +IB_LID_MCAST_END
+IB_LID_MCAST_START +IB_LID_PERMISSIVE +IB_LID_UCAST_END
+IB_LID_UCAST_START +ib_link_states_t +ib_listen_info_t
+IB_MAD_ATTR_CLASS_PORT_INFO +IB_MAD_ATTR_DIAG_CODE +IB_MAD_ATTR_DIAGNOSTIC_TIMEOUT
+IB_MAD_ATTR_GUID_INFO +IB_MAD_ATTR_GUIDINFO_RECORD +IB_MAD_ATTR_INFORM_INFO
+IB_MAD_ATTR_INFORM_INFO_RECORD +IB_MAD_ATTR_IO_CONTROLLER_PROFILE +IB_MAD_ATTR_IO_UNIT_INFO
+IB_MAD_ATTR_LED_INFO +IB_MAD_ATTR_LFT_RECORD +IB_MAD_ATTR_LIN_FWD_TBL
+IB_MAD_ATTR_LINK_RECORD +IB_MAD_ATTR_MCAST_FWD_TBL +IB_MAD_ATTR_MCMEMBER_RECORD
+IB_MAD_ATTR_MULTIPATH_RECORD +IB_MAD_ATTR_NODE_DESC +IB_MAD_ATTR_NODE_INFO
+IB_MAD_ATTR_NODE_RECORD +IB_MAD_ATTR_NOTICE +IB_MAD_ATTR_P_KEY_TABLE
+IB_MAD_ATTR_PATH_RECORD +IB_MAD_ATTR_PKEYTBL_RECORD +IB_MAD_ATTR_PORT_CNTRS
+IB_MAD_ATTR_PORT_INFO +IB_MAD_ATTR_PORT_SMPL_CTRL +IB_MAD_ATTR_PORT_SMPL_RSLT
+IB_MAD_ATTR_PORTINFO_RECORD +IB_MAD_ATTR_PREPARE_TO_TEST +IB_MAD_ATTR_RND_FWD_TBL
+IB_MAD_ATTR_SERVICE_ENTRIES +IB_MAD_ATTR_SERVICE_RECORD +IB_MAD_ATTR_SLVL_RECORD
+IB_MAD_ATTR_SLVL_TABLE +IB_MAD_ATTR_SM_INFO +IB_MAD_ATTR_SMINFO_RECORD
+IB_MAD_ATTR_SVC_ASSOCIATION_RECORD +IB_MAD_ATTR_SWITCH_INFO +IB_MAD_ATTR_TEST_DEVICE_LOOP
+IB_MAD_ATTR_TEST_DEVICE_ONCE +IB_MAD_ATTR_TRACE_RECORD +IB_MAD_ATTR_VENDOR_DIAG
+IB_MAD_ATTR_VL_ARBITRATION +IB_MAD_ATTR_VLARB_RECORD +IB_MAD_METHOD_GET
+IB_MAD_METHOD_GET_RESP +IB_MAD_METHOD_GETTABLE +IB_MAD_METHOD_GETTABLE_RESP
+IB_MAD_METHOD_REPORT +IB_MAD_METHOD_REPORT_RESP +IB_MAD_METHOD_RESP_MASK
+IB_MAD_METHOD_SEND +IB_MAD_METHOD_SET +IB_MAD_METHOD_TRAP
+IB_MAD_METHOD_TRAP_REPRESS +IB_MAD_STATUS_BUSY +IB_MAD_STATUS_INVALID_FIELD
+IB_MAD_STATUS_REDIRECT +IB_MAD_STATUS_UNSUP_CLASS_VER +IB_MAD_STATUS_UNSUP_METHOD
+IB_MAD_STATUS_UNSUP_METHOD_ATTR +ib_mad_svc_type_t +IB_MAX_METHOD
+IB_MCAST_BLOCK_ID_MASK_HO +IB_MCAST_BLOCK_SIZE +IB_MCAST_MASK_SIZE
+IB_MCAST_MAX_BLOCK_ID +IB_MCAST_POSITION_MASK_HO +IB_MCAST_POSITION_MAX
+IB_MCAST_POSITION_SHIFT +IB_MCLASS_BIS +IB_MCLASS_BM
+IB_MCLASS_COMM_MGMT +IB_MCLASS_DEV_ADM +IB_MCLASS_DEV_MGMT
+IB_MCLASS_PERF +IB_MCLASS_SNMP +IB_MCLASS_SUBN_ADM
+IB_MCLASS_SUBN_DIR +IB_MCLASS_SUBN_LID +IB_MCLASS_VENDOR_HIGH_RANGE_MAX
+IB_MCLASS_VENDOR_HIGH_RANGE_MIN +IB_MCLASS_VENDOR_LOW_RANGE_MAX +IB_MCLASS_VENDOR_LOW_RANGE_MIN
+ib_mr_mod_t +IB_MTU_LEN_TYPE +IB_MULTIPATH_REC_BASE_MASK
+ib_net16_t +ib_net32_t +ib_net64_t
+IB_NODE_NUM_PORTS_MAX +IB_NODE_TYPE_CA +IB_NODE_TYPE_ROUTER
+IB_NODE_TYPE_SWITCH +IB_NOTICE_NODE_TYPE_CA +IB_NOTICE_NODE_TYPE_ROUTER
+IB_NOTICE_NODE_TYPE_SUBN_MGMT +IB_NOTICE_NODE_TYPE_SWITCH +IB_PATH_REC_BASE_MASK
+IB_PATH_REC_SELECTOR_MASK +IB_PATH_SELECTOR_TYPE +ib_pd_type_t
+IB_PKEY_BASE_MASK +IB_PKEY_ENTRIES_MAX +IB_PKEY_MAX_BLOCKS
+IB_PKEY_TYPE_MASK +ib_pnp_class_t +ib_pnp_event_t
+IB_QP1_WELL_KNOWN_Q_KEY +ib_qp_opts_t +ib_qp_state_t
+ib_qp_type_t +ib_query_type_t +ib_recv_opt_t
+ib_rej_status_t +ib_send_opt_t +IB_SMINFO_ATTR_MOD_ACKNOWLEDGE
+IB_SMINFO_ATTR_MOD_DISABLE +IB_SMINFO_ATTR_MOD_DISCOVER +IB_SMINFO_ATTR_MOD_HANDOVER
+IB_SMINFO_ATTR_MOD_STANDBY +IB_SMINFO_STATE_DISCOVERING +IB_SMINFO_STATE_INIT
+IB_SMINFO_STATE_MASTER +IB_SMINFO_STATE_NOTACTIVE +IB_SMINFO_STATE_STANDBY
+IB_SMP_DIRECTION +IB_SMP_STATUS_MASK +ib_srq_attr_mask_t
+IB_SUBNET_PATH_HOPS_MAX +ib_wc_status_t +ib_wc_type_t
+ib_wr_type_t +IOCTL_CODE +Join States
+MAD_BLOCK_GRH_SIZE +MAD_BLOCK_SIZE +MAD_RMPP_DATA_SIZE
+MAD_RMPP_HDR_SIZE +MAX +MIN
+Object States +offsetof +Parameter Keywords
+PARENT_STRUCT +PERF_DECLARE +PERF_DECLARE_START
+ROUNDUP +UNUSED_PARAM
+ + diff --git a/branches/WOF2-3/docs/robo_functions.html b/branches/WOF2-3/docs/robo_functions.html new file mode 100644 index 00000000..823659ce --- /dev/null +++ b/branches/WOF2-3/docs/robo_functions.html @@ -0,0 +1,1535 @@ + + + + +Functions + + + + +Generated from ./inc/ with ROBODoc v4.99.17 on Sun Mar 04 2007 18:17:52 +
+

+[Sourcefiles] +[Index] +[Definitions] +[Functions] +[Modules] +[Structures] +

+

Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+cl_async_proc_construct +cl_async_proc_destroy +cl_async_proc_init
+cl_async_proc_queue +cl_atomic_add +cl_atomic_comp_xchg
+cl_atomic_dec +cl_atomic_inc +cl_atomic_sub
+cl_atomic_xchg +cl_break +cl_check_for_read
+cl_check_for_write +cl_copy_from_user +cl_copy_to_user
+cl_cpool_construct +cl_cpool_count +cl_cpool_destroy
+cl_cpool_get +cl_cpool_grow +cl_cpool_init
+cl_cpool_put +cl_dbg_out +cl_event_construct
+cl_event_destroy +cl_event_init +cl_event_reset
+cl_event_signal +cl_event_wait_on +cl_fmap_apply_func
+cl_fmap_count +cl_fmap_delta +cl_fmap_end
+cl_fmap_get +cl_fmap_head +cl_fmap_init
+cl_fmap_insert +cl_fmap_key +cl_fmap_merge
+cl_fmap_next +cl_fmap_prev +cl_fmap_remove
+cl_fmap_remove_all +cl_fmap_remove_item +cl_fmap_tail
+cl_free +cl_get_pagesize +cl_get_physaddr
+cl_get_tick_count +cl_get_tick_freq +cl_get_time_stamp
+cl_get_time_stamp_sec +cl_get_time_stamp_usec +cl_hton16
+cl_hton32 +cl_hton64 +cl_ioctl_cmd
+cl_ioctl_complete +cl_ioctl_ctl_code +cl_ioctl_in_buf
+cl_ioctl_in_size +cl_ioctl_out_buf +cl_ioctl_out_size
+cl_ioctl_process +cl_ioctl_request +cl_ioctl_result
+cl_ioctl_type +cl_irqlock_acquire +cl_irqlock_construct
+cl_irqlock_destroy +cl_irqlock_init +cl_irqlock_release
+cl_is_blockable +cl_is_cpool_inited +cl_is_fmap_empty
+cl_is_item_in_qlist +cl_is_list_empty +cl_is_list_inited
+cl_is_map_empty +cl_is_map_inited +cl_is_object_in_list
+cl_is_pool_inited +cl_is_qcpool_inited +cl_is_qlist_empty
+cl_is_qmap_empty +cl_is_qpool_inited +cl_is_rbmap_empty
+cl_is_sys_callback_inited +cl_list_apply_func +cl_list_construct
+cl_list_count +cl_list_destroy +cl_list_end
+cl_list_find_from_head +cl_list_find_from_tail +cl_list_head
+cl_list_init +cl_list_insert_array_head +cl_list_insert_array_tail
+cl_list_insert_head +cl_list_insert_next +cl_list_insert_prev
+cl_list_insert_tail +cl_list_next +cl_list_obj
+cl_list_prev +cl_list_remove_all +cl_list_remove_head
+cl_list_remove_item +cl_list_remove_object +cl_list_remove_tail
+cl_list_tail +cl_log_event +cl_malloc
+cl_map_construct +cl_map_count +cl_map_delta
+cl_map_destroy +cl_map_end +cl_map_get
+cl_map_head +cl_map_init +cl_map_insert
+cl_map_key +cl_map_merge +cl_map_next
+cl_map_obj +cl_map_prev +cl_map_remove
+cl_map_remove_all +cl_map_remove_item +cl_map_tail
+cl_mem_display +cl_memclr +cl_memcmp
+cl_memcpy +cl_memset +cl_msg_out
+cl_mutex_acquire +cl_mutex_construct +cl_mutex_destroy
+cl_mutex_init +cl_mutex_release +cl_ntoh
+cl_ntoh16 +cl_ntoh32 +cl_ntoh64
+cl_obj_construct +cl_obj_deinit +cl_obj_deref
+cl_obj_destroy +cl_obj_init +cl_obj_insert_rel
+cl_obj_insert_rel_parent_locked +cl_obj_lock +cl_obj_mgr_create
+cl_obj_mgr_destroy +cl_obj_ref +cl_obj_remove_rel
+cl_obj_reset +cl_obj_type +cl_obj_unlock
+cl_palloc +cl_panic +cl_perf_construct
+cl_perf_destroy +cl_perf_display +cl_perf_init
+cl_perf_reset +cl_plock_acquire +cl_plock_construct
+cl_plock_destroy +cl_plock_excl_acquire +cl_plock_init
+cl_plock_release +cl_pool_construct +cl_pool_count
+cl_pool_destroy +cl_pool_get +cl_pool_grow
+cl_pool_init +cl_pool_put +cl_proc_count
+cl_ptr_vector_apply_func +cl_ptr_vector_at +cl_ptr_vector_construct
+cl_ptr_vector_destroy +cl_ptr_vector_find_from_end +cl_ptr_vector_find_from_start
+cl_ptr_vector_get +cl_ptr_vector_get_capacity +cl_ptr_vector_get_size
+cl_ptr_vector_init +cl_ptr_vector_insert +cl_ptr_vector_remove
+cl_ptr_vector_set +cl_ptr_vector_set_capacity +cl_ptr_vector_set_min_size
+cl_ptr_vector_set_size +cl_pzalloc +cl_qcpool_construct
+cl_qcpool_count +cl_qcpool_destroy +cl_qcpool_get
+cl_qcpool_grow +cl_qcpool_init +cl_qcpool_put
+cl_qcpool_put_list +cl_qlist_apply_func +cl_qlist_count
+cl_qlist_end +cl_qlist_find_from_head +cl_qlist_find_from_tail
+cl_qlist_find_next +cl_qlist_find_prev +cl_qlist_head
+cl_qlist_init +cl_qlist_insert_array_head +cl_qlist_insert_array_tail
+cl_qlist_insert_head +cl_qlist_insert_list_head +cl_qlist_insert_list_tail
+cl_qlist_insert_next +cl_qlist_insert_prev +cl_qlist_insert_tail
+cl_qlist_move_items +cl_qlist_next +cl_qlist_obj
+cl_qlist_prev +cl_qlist_remove_all +cl_qlist_remove_head
+cl_qlist_remove_item +cl_qlist_remove_tail +cl_qlist_set_obj
+cl_qlist_tail +cl_qlock_pool_construct +cl_qlock_pool_destroy
+cl_qlock_pool_get +cl_qlock_pool_init +cl_qlock_pool_put
+cl_qmap_apply_func +cl_qmap_count +cl_qmap_delta
+cl_qmap_end +cl_qmap_get +cl_qmap_head
+cl_qmap_init +cl_qmap_insert +cl_qmap_key
+cl_qmap_merge +cl_qmap_next +cl_qmap_obj
+cl_qmap_prev +cl_qmap_remove +cl_qmap_remove_all
+cl_qmap_remove_item +cl_qmap_set_obj +cl_qmap_tail
+cl_qpool_construct +cl_qpool_count +cl_qpool_destroy
+cl_qpool_get +cl_qpool_grow +cl_qpool_init
+cl_qpool_put +cl_qpool_put_list +cl_rbmap_count
+cl_rbmap_end +cl_rbmap_init +cl_rbmap_insert
+cl_rbmap_left +cl_rbmap_remove_item +cl_rbmap_reset
+cl_rbmap_right +cl_rbmap_root +cl_rel_alloc
+cl_rel_free +cl_req_mgr_construct +cl_req_mgr_destroy
+cl_req_mgr_get +cl_req_mgr_init +cl_req_mgr_resume
+cl_spinlock_acquire +cl_spinlock_construct +cl_spinlock_destroy
+cl_spinlock_init +cl_spinlock_release +cl_sys_callback_get
+cl_sys_callback_put +cl_sys_callback_queue +cl_thread_pool_construct
+cl_thread_pool_destroy +cl_thread_pool_init +cl_thread_pool_signal
+cl_thread_stall +cl_thread_suspend +cl_timer_construct
+cl_timer_destroy +cl_timer_init +cl_timer_start
+cl_timer_stop +cl_timer_trim +cl_vector_apply_func
+cl_vector_at +cl_vector_construct +cl_vector_destroy
+cl_vector_find_from_end +cl_vector_find_from_start +cl_vector_get
+cl_vector_get_capacity +cl_vector_get_ptr +cl_vector_get_size
+cl_vector_init +cl_vector_set +cl_vector_set_capacity
+cl_vector_set_min_size +cl_vector_set_size +cl_waitobj_create
+cl_waitobj_deref +cl_waitobj_destroy +cl_waitobj_ref
+cl_waitobj_reset +cl_waitobj_signal +cl_waitobj_wait_on
+cl_zalloc +ib_add_svc_entry +ib_alloc_pd
+ib_bind_mw +ib_cancel_mad +ib_cancel_query
+ib_ci_call +ib_class_is_rmpp +ib_class_is_vendor_specific
+ib_class_is_vendor_specific_high +ib_class_is_vendor_specific_low +ib_close_al
+ib_close_ca +ib_cm_apr +ib_cm_cancel
+ib_cm_drep +ib_cm_dreq +ib_cm_handoff
+ib_cm_lap +ib_cm_listen +ib_cm_mra
+ib_cm_rej +ib_cm_rep +ib_cm_req
+ib_cm_rtu +ib_copy_ca_attr +ib_create_av
+ib_create_cq +ib_create_ioc +ib_create_mad_pool
+ib_create_mw +ib_create_qp +ib_create_srq
+ib_dealloc_pd +ib_dereg_mad_pool +ib_dereg_mr
+ib_dereg_pnp +ib_dereg_svc +ib_destroy_av
+ib_destroy_cq +ib_destroy_ioc +ib_destroy_mad_pool
+ib_destroy_mw +ib_destroy_qp +ib_destroy_srq
+ib_dm_get_slot_lo_hi +ib_dm_set_slot_lo_hi +ib_force_apm
+ib_get_async_event_str +ib_get_ca_by_gid +ib_get_ca_guids
+ib_get_err_str +ib_get_guid +ib_get_mad
+ib_get_mad_buf +ib_get_node_type_str +ib_get_port_by_gid
+ib_get_port_state_from_str +ib_get_port_state_str +ib_get_qp_type_str
+ib_get_query_node_rec +ib_get_query_path_rec +ib_get_query_portinfo_rec
+ib_get_query_result +ib_get_query_svc_rec +ib_get_spl_qp
+ib_get_wc_status_str +ib_get_wc_type_str +ib_get_wr_type_str
+ib_gid_get_guid +ib_gid_get_subnet_prefix +ib_gid_is_link_local
+ib_gid_is_site_local +ib_gid_set_default +ib_grh_get_ver_class_flow
+ib_grh_set_ver_class_flow +ib_inform_get_dev_id +ib_inform_get_prod_type
+ib_inform_get_qpn +ib_inform_get_resp_time_val +ib_inform_get_trap_num
+ib_inform_get_vend_id +ib_inform_set_dev_id +ib_inform_set_prod_type
+ib_inform_set_qpn +ib_inform_set_resp_time_val +ib_inform_set_trap_num
+ib_inform_set_vend_id +ib_init_dgrm_svc +ib_iou_info_diag_dev_id
+ib_iou_info_option_rom +ib_join_mcast +ib_leave_mcast
+ib_local_mad +ib_mad_init_new +ib_mad_init_response
+ib_mad_is_response +ib_member_get_scope +ib_member_get_scope_state
+ib_member_get_sl_flow_hop +ib_member_get_state +ib_member_set_join_state
+ib_member_set_scope +ib_member_set_scope_state +ib_member_set_sl_flow_hop
+ib_member_set_state +ib_modify_av +ib_modify_ca
+ib_modify_cq +ib_modify_qp +ib_modify_srq
+ib_node_info_get_local_port_num +ib_node_info_get_vendor_id +ib_notice_get_count
+ib_notice_get_dev_id +ib_notice_get_generic +ib_notice_get_prod_type
+ib_notice_get_toggle +ib_notice_get_trap_num +ib_notice_get_type
+ib_notice_get_vend_id +ib_notice_set_count +ib_notice_set_dev_id
+ib_notice_set_generic +ib_notice_set_prod_type +ib_notice_set_toggle
+ib_notice_set_trap_num +ib_notice_set_type +ib_notice_set_vend_id
+ib_open_al +ib_open_ca +ib_path_get_ipd
+ib_path_rec_flow_lbl +ib_path_rec_hop_limit +ib_path_rec_init_local
+ib_path_rec_mtu +ib_path_rec_mtu_sel +ib_path_rec_num_path
+ib_path_rec_pkt_life +ib_path_rec_pkt_life_sel +ib_path_rec_rate
+ib_path_rec_rate_sel +ib_path_rec_set_hop_flow_raw +ib_path_rec_sl
+ib_peek_cq +ib_pfn_cm_apr_cb_t +ib_pfn_cm_drep_cb_t
+ib_pfn_cm_dreq_cb_t +ib_pfn_cm_lap_cb_t +ib_pfn_cm_mra_cb_t
+ib_pfn_cm_rej_cb_t +ib_pfn_cm_rep_cb_t +ib_pfn_cm_req_cb_t
+ib_pfn_cm_rtu_cb_t +ib_pfn_comp_cb_t +ib_pfn_destroy_cb_t
+ib_pfn_event_cb_t +ib_pfn_listen_err_cb_t +ib_pfn_mad_comp_cb_t
+ib_pfn_mcast_cb_t +ib_pfn_pnp_cb_t +ib_pfn_query_cb_t
+ib_pfn_reg_svc_cb_t +ib_pfn_report_cb_t +ib_pfn_sub_cb_t
+ib_pkey_get_base +ib_pkey_is_full_member +ib_pkey_is_invalid
+ib_poll_cq +ib_port_info_compute_rate +ib_port_info_get_init_type
+ib_port_info_get_link_speed_active +ib_port_info_get_link_speed_sup +ib_port_info_get_lmc
+ib_port_info_get_mpb +ib_port_info_get_mtu_cap +ib_port_info_get_neighbor_mtu
+ib_port_info_get_op_vls +ib_port_info_get_port_state +ib_port_info_get_sm_sl
+ib_port_info_get_vl_cap +ib_port_info_set_link_speed_sup +ib_port_info_set_lmc
+ib_port_info_set_mpb +ib_port_info_set_neighbor_mtu +ib_port_info_set_op_vls
+ib_port_info_set_port_state +ib_port_info_set_sm_sl +ib_port_info_set_state_no_change
+ib_port_info_set_timeout +ib_post_recv +ib_post_send
+ib_post_srq_recv +ib_put_mad +ib_query
+ib_query_av +ib_query_ca +ib_query_ca_by_guid
+ib_query_cq +ib_query_mr +ib_query_mw
+ib_query_qp +ib_query_srq +ib_rearm_cq
+ib_rearm_n_cq +ib_reg_ioc +ib_reg_mad_pool
+ib_reg_mad_svc +ib_reg_mem +ib_reg_phys
+ib_reg_pnp +ib_reg_shared +ib_reg_shmid
+ib_reg_svc +ib_reject_ioc +ib_remove_svc_entry
+ib_rereg_mem +ib_rereg_phys +ib_rmpp_is_flag_set
+ib_sa_mad_get_payload_ptr +ib_send_mad +ib_slvl_table_get_vl
+ib_slvl_table_set_vl +ib_sminfo_get_priority +ib_sminfo_get_state
+ib_smp_get_payload_ptr +ib_smp_get_status +ib_smp_init_new
+ib_smp_is_d +ib_smp_is_response +ib_subscribe
+ib_switch_info_clear_state_change +ib_switch_info_get_state_change +ib_sync_destroy
+ib_unsubscribe +ib_vl_arb_element_get_vl +ib_vl_arb_element_set_vl
+ioc_at_slot +mlnx_create_fmr +mlnx_destroy_fmr
+mlnx_map_fmr +mlnx_unmap_fmr
+ + diff --git a/branches/WOF2-3/docs/robo_modules.html b/branches/WOF2-3/docs/robo_modules.html new file mode 100644 index 00000000..64e6c96a --- /dev/null +++ b/branches/WOF2-3/docs/robo_modules.html @@ -0,0 +1,116 @@ + + + + +Modules + + + + +Generated from ./inc/ with ROBODoc v4.99.17 on Sun Mar 04 2007 18:17:52 +
+

+[Sourcefiles] +[Index] +[Definitions] +[Functions] +[Modules] +[Structures] +

+

Modules

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+Access Layer +Asynchronous Processor +Atomic Operations +Byte Swapping +Component Library
+Composite Pool +Constants +Debug Output +Event +Flexi Map
+IOCTL Object +Irqlock +List +Log Provider +Map
+Memory Management +Mutex +Object +Passive Lock +Performance Counters
+Pointer Vector +Pool +Quick Composite Pool +Quick List +Quick Locking Pool
+Quick Map +Quick Pool +RB Map +Request Manager +Spinlock
+System Callback +Thread Pool +Timer +Type Definitions +Vector
+Wait Object
+ + diff --git a/branches/WOF2-3/docs/robo_sourcefiles.html b/branches/WOF2-3/docs/robo_sourcefiles.html new file mode 100644 index 00000000..cee58ddf --- /dev/null +++ b/branches/WOF2-3/docs/robo_sourcefiles.html @@ -0,0 +1,149 @@ + + + + +Sourcefiles + + + + +Generated from ./inc/ with ROBODoc v4.99.17 on Sun Mar 04 2007 18:17:52 +
+

+[Sourcefiles] +[Index] +[Definitions] +[Functions] +[Modules] +[Structures] +

+ + + diff --git a/branches/WOF2-3/docs/robo_strutures.html b/branches/WOF2-3/docs/robo_strutures.html new file mode 100644 index 00000000..19552812 --- /dev/null +++ b/branches/WOF2-3/docs/robo_strutures.html @@ -0,0 +1,381 @@ + + + + +Structures + + + + +Generated from ./inc/ with ROBODoc v4.99.17 on Sun Mar 04 2007 18:17:52 +
+

+[Sourcefiles] +[Index] +[Definitions] +[Functions] +[Modules] +[Structures] +

+

Structures

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+cl_async_proc_item_t +cl_async_proc_t +cl_cpool_t +cl_fmap_item_t
+cl_fmap_t +cl_list_item_t +cl_list_obj_t +cl_list_t
+cl_map_item_t +cl_map_obj_t +cl_map_t +cl_obj_mgr_t
+cl_obj_rel_t +cl_obj_t +cl_plock_t +cl_pool_item_t
+cl_pool_t +cl_ptr_vector_t +cl_qcpool_t +cl_qlist_t
+cl_qlock_pool_t +cl_qmap_t +cl_qpool_t +cl_rbmap_item_t
+cl_rbmap_t +cl_req_mgr_t +cl_thread_pool_t +cl_vector_t
+ib_apr_info_t +ib_apr_pdata_t +ib_ari_t +ib_async_event_rec_t
+ib_av_attr_t +ib_bind_wr_t +ib_ca_attr_t +ib_cep_listen_t
+ib_ci_op_t +IB_CLASS_CAP_GETSET +IB_CLASS_CAP_TRAP +ib_class_port_info_t
+IB_CLASS_RESP_TIME_MASK +ib_cm_apr_rec_t +ib_cm_apr_t +ib_cm_drep_rec_t
+ib_cm_drep_t +ib_cm_dreq_rec_t +ib_cm_dreq_t +ib_cm_lap_rec_t
+ib_cm_lap_t +ib_cm_listen_t +ib_cm_mra_rec_t +ib_cm_mra_t
+ib_cm_rej_rec_t +ib_cm_rej_t +ib_cm_rep_rec_t +ib_cm_rep_t
+ib_cm_req_rec_t +ib_cm_req_t +ib_cm_rtu_rec_t +ib_cm_rtu_t
+ib_cq_create_t +ib_dgrm_info_t +ib_dm_mad_t +ib_drep_pdata_t
+ib_dreq_pdata_t +ib_event_rec_t +ib_field32_t +ib_gid_pair_t
+ib_gmp_t +ib_grh_t +ib_guid_info_t +ib_guid_pair_t
+ib_inform_info_record_t +ib_ioc_profile_t +ib_iou_info_t +ib_lap_pdata_t
+ib_lft_record_t +ib_lid_pair_t +ib_listen_err_rec_t +ib_local_ds_t
+ib_mad_element_t +ib_mad_svc_t +ib_mad_t +ib_mcast_rec_t
+ib_mcast_req_t +ib_member_rec_t +ib_mr_attr_t +ib_mr_create_t
+ib_mra_pdata_t +ib_node_info_t +ib_path_rec_t +ib_phys_create_t
+ib_phys_range_t +ib_pkey_table_info_t +ib_pnp_ca_rec_t +ib_pnp_ioc_path_rec_t
+ib_pnp_ioc_rec_t +ib_pnp_iou_rec_t +ib_pnp_port_rec_t +ib_pnp_rec_t
+ib_pnp_req_t +ib_port_attr_mod_t +ib_port_attr_t +ib_port_cap_t
+ib_port_counters_t +ib_port_info_t +ib_qp_attr_t +ib_qp_create_t
+ib_qp_mod_t +ib_query_rec_t +ib_query_req_t +ib_recv_wr_t
+ib_reg_svc_rec_t +ib_reg_svc_req_t +ib_rej_pdata_t +ib_rep_pdata_t
+ib_report_rec_t +ib_req_pdata_t +ib_rmpp_mad_t +ib_rtu_pdata_t
+ib_sa_mad_t +ib_send_wr_t +ib_shmid_t +ib_sidr_rep_pdata_t
+ib_sidr_req_pdata_t +ib_slvl_table_record_t +ib_slvl_table_t +ib_sm_info_t
+ib_smp_t +ib_srq_attr_t +ib_sub_rec_t +ib_sub_req_t
+ib_svc_entries_t +ib_svc_entry_t +ib_switch_info_t +ib_user_query_t
+ib_vl_arb_element_t +ib_vl_arb_table_record_t +ib_vl_arb_table_t +ib_wc_t
+mlnx_fmr_create_t
+ + diff --git a/branches/WOF2-3/docs/robodoc.css b/branches/WOF2-3/docs/robodoc.css new file mode 100644 index 00000000..44ae2c54 --- /dev/null +++ b/branches/WOF2-3/docs/robodoc.css @@ -0,0 +1,36 @@ +body +{ + background-color: #ffffff; + color: #000000; + font-family: 'Lucida Grande', Verdana, + Geneva, Lucida, Arial, + Helvetica, sans-serif; + font-size: 10pt; + margin: 2% 5%; +} +h1, h2, h3, h4, h5, h6, h7 +{ + background-color: #dddddd; + color: #000000; + text-align: right; + font-size: 11pt; +} +td.even, td.uneven +{ + color: #000000; + font-size: 10pt; +} +td.even +{ + background-color: #eeeeee; +} +span.SOURCE +{ + white-space: pre; +} +pre +{ + background-color: #ffffff; + color: #000000; + font-size: 10pt; +} diff --git a/branches/WOF2-3/etc/addcert.bat b/branches/WOF2-3/etc/addcert.bat new file mode 100644 index 00000000..4431a24b --- /dev/null +++ b/branches/WOF2-3/etc/addcert.bat @@ -0,0 +1,3 @@ +makecert -$ individual -r -pe -ss WinOFCertStore -n CN=WinOFCert WinOFCert.cer +clusrun certutil -addstore TrustedPublisher %LOGONSERVER%\c$\winof\install\WinOFCert.cer +clusrun certutil -addstore Root %LOGONSERVER%\c$\winof\install\WinOFCert.cer \ No newline at end of file diff --git a/branches/WOF2-3/etc/bldwo.bat b/branches/WOF2-3/etc/bldwo.bat new file mode 100644 index 00000000..8f8b0295 --- /dev/null +++ b/branches/WOF2-3/etc/bldwo.bat @@ -0,0 +1,104 @@ +@echo off +setlocal + +if "%WDK_PATH%"=="" goto use +if "%OPENIB_REV%"=="" goto use +if "%PLATFORM_SDK_PATH%"=="" goto use + +if "%1"=="chk" ( + set wo_bld=chk + goto set_arch +) +if "%1"=="fre" ( + set wo_bld=fre + goto set_arch +) +goto use + +:set_arch +if "%2"=="x86" ( + set wo_arch=x86 + goto set_os +) +if "%2"=="x32" ( + set wo_arch=x86 + goto set_os +) +if "%2"=="x64" ( + set wo_arch=x64 + goto set_os +) +if "%2"=="ia64" ( + set wo_arch=64 + goto set_os +) +goto use + +:set_os +if "%3"=="win7" ( + set wo_os=win7 + goto set_bld +) +if "%3"=="2003" ( + set wo_os=wnet + goto set_bld +) +if "%3"=="2008" ( + set wo_os=WLH + goto set_bld +) +if "%3"=="xp" ( + if not "%2"=="x86" if not "%2"=="x32" goto use + set wo_os=WXP + set wo_arch= + goto set_bld +) +goto use + +:set_bld +if "%4"=="" set wo_bld_opt=-wg & goto do_build + +:loop +if "%4"=="" goto do_build +set wo_bld_opt=%wo_bld_opt% %4 +shift +goto loop + +:do_build +set DDKBUILDENV= +pushd . +call %WDK_PATH%\bin\setenv.bat %WDK_PATH%\ %wo_bld% %wo_arch% %wo_os% no_oacr +popd +build %wo_bld_opt% +goto end + +:use +echo - +echo bldwo - build winof +echo - +echo Allows building any OS/processor architecture from a single command window. +echo You must customize for your system by setting the following environment +echo variables: +echo - +echo WDK_PATH (example set WDK_PATH=c:\winddk\6001.18001) +echo WINOF_PATH (example set WINOF_PATH=c:\ofw\trunk) +echo OPENIB_REV (example set OPENIB_REV=0) +echo PLATFORM_SDK_PATH (example set PLATFORM_SDK_PATH=c:\progra~1\mi2578~1) +echo - +echo Use: +echo bldwo {chk : fre} {x86 : x64 : ia64} {xp : 2003 : 2008 : win7} [-options] +echo Default build options are 'wg'. +echo xp only supports x86 build +echo - +echo Examples: +echo bldwo chk x86 2003 - builds checked x86 version for 2003 using -wg +echo bldwo chk x64 2003 - builds checked x64 version for 2003 using -wg +echo bldwo fre x64 win7 -wgc - builds free x64 version for Win7 using -wgc +echo bldwo fre x64 2008 -wgc - builds free x64 version for 2008 using -wgc +echo bldwo fre x64 2008 -w -g -c - builds free x64 version for 2008 using -w -g -c +echo - +echo Also see docs\build.txt + +:end +endlocal +@echo on diff --git a/branches/WOF2-3/etc/bldwoall.bat b/branches/WOF2-3/etc/bldwoall.bat new file mode 100644 index 00000000..659755ab --- /dev/null +++ b/branches/WOF2-3/etc/bldwoall.bat @@ -0,0 +1,19 @@ +@echo off +rem +rem Builds the winof stack for all platforms. +rem + +call %~dp0\bldwo chk x86 2003 %* +call %~dp0\bldwo fre x86 2003 %* +call %~dp0\bldwo chk x64 2003 %* +call %~dp0\bldwo fre x64 2003 %* +call %~dp0\bldwo chk ia64 2003 %* +call %~dp0\bldwo fre ia64 2003 %* +call %~dp0\bldwo chk x86 2008 %* +call %~dp0\bldwo fre x86 2008 %* +call %~dp0\bldwo chk x64 2008 %* +call %~dp0\bldwo fre x64 2008 %* +call %~dp0\bldwo chk ia64 2008 %* +call %~dp0\bldwo fre ia64 2008 %* + +@echo on diff --git a/branches/WOF2-3/etc/clean-build.bat b/branches/WOF2-3/etc/clean-build.bat new file mode 100644 index 00000000..b9a8454d --- /dev/null +++ b/branches/WOF2-3/etc/clean-build.bat @@ -0,0 +1,117 @@ +@echo off +setlocal + +rem usage: clean-build {Target-OS} {target-Arch} {scan-only} +rem no args - remove build specific folders and files: +rem *_win7_* *_wxp_* *_wnet_* *_wlh_* +rem arg1 == Target OS name: win7 | wxp | wnet | wlh | all +rem arg2 == Target Arch: x86 | x64 | ia64 | all +rem arg3 != "" - then report matched folders & files - no delete. + +set ALLOS=_win7_ _wlh_ _wnet_ _wxp_ +set ALLARCH=x86 amd64 ia64 + +if "%1" == "/?" ( +:usage + echo usage: + echo clean-build {OS:win7,wlh,wnet,wxp,all} {arch:x86,x64,ia64,all} {scan-only} + echo no args - remove all OS build specific folders and files: *_OS_* + echo otherwise 'win7 x86' only removes files * folders matching '*_win7_x86' + echo arg3 != "" - then report matched folders and files - no delete. + exit /B 0 +) + +if "%1" == "" ( + set TOS=%ALLOS% + goto OK_OS +) +if "%1" == "all" ( + set TOS=%ALLOS% +) else ( + if "%1" == "win7" goto set_OS + if "%1" == "wlh" goto set_OS + if "%1" == "wnet" goto set_OS + if "%1" == "wxp" goto set_OS + echo %0 - BAD OS specification '%1'? + goto usage +rem set Target OS +:set_OS + set TOS=_%1_ +) +:OK_OS + +if "%2" == "" ( +:all_arch + set TARCH= + goto OK_ARCH +) +if "%2" == "all" goto all_arch + +if "%2" == "x64" ( + set TARCH=amd64 + goto OK_ARCH +) +if "%2" == "x86" goto set_ARCH +if "%2" == "ia64" goto set_ARCH +echo %0 - BAD Arch specification '%2'? +goto usage + +rem set Target OS +:set_ARCH + set TARCH=%2 + +:OK_ARCH + +set T=%TEMP%\flist.txt + +rem delete OS flavor {wlh,wxp,wnet} specific build files to ensure a clean build + +rem The story behind the for loop need for the fake 'delims=,' is the need to +rem override the default delimiters of & , anything but +rem or . Problems occur with a folder name like +rem 'c:\svn\trunk\ulp\ipoib - copy(2)\objfre_wlh_x86' as the default delimiters +rem in for loop file read return 'c:\svn\trunk\ulp\ipoib', bad juju. + +rem check/remove directories + +for %%d in ( %TOS% ) do ( + echo Folder Scan for *%%d%TARCH%* + dir /B /S /A:D *%%d%TARCH%* > %T% 2>&1 + if ERRORLEVEL 1 ( + del /Q/F %T% + ) else ( + for /f "delims=," %%f in ( %T% ) do ( + if EXIST "%%f" ( + if "%3" == "" ( + rmdir /S /Q "%%f" 1>nul + ) else ( + echo found "%%f" + ) + ) + ) + del /Q/F %T% + ) +) + +rem check/remove files + +for %%d in ( %TOS% ) do ( + echo File Scan for *%%d%TARCH%* + dir /B /S *%%d%TARCH%* > %T% 2>&1 + if ERRORLEVEL 1 ( + del /Q/F %T% + ) else ( + for /f "delims=," %%f in ( %T% ) do ( + if EXIST "%%f" ( + if "%3" == "" ( + del /F /Q "%%f" 1>nul + ) else ( + echo found %%f + ) + ) + ) + del /Q/F %T% + ) +) +endlocal + diff --git a/branches/WOF2-3/etc/cpinst.bat b/branches/WOF2-3/etc/cpinst.bat new file mode 100644 index 00000000..16904686 --- /dev/null +++ b/branches/WOF2-3/etc/cpinst.bat @@ -0,0 +1,84 @@ +@echo off +setlocal + +if "%WINOF_PATH%"=="" goto use + +if "%1"=="x86" ( + set wo_arch=x86 + set wo_arch_dir=i386 + goto set_os +) +if "%1"=="x64" ( + set wo_arch=amd64 + set wo_arch_dir=amd64 + goto set_os +) +if "%1"=="ia64" ( + set wo_arch=ia64 + set wo_arch_dir=ia64 + goto set_os +) +goto use + +:set_os +if "%2"=="2003" ( + set wo_os=wnet + goto inst +) +if "%2"=="2008" ( + set wo_os=WLH + goto inst +) +if "%2"=="xp" ( + if not "%1"=="x86" goto use + set wo_os=WXP + goto inst +) +goto use + +:inst +pushd %WINOF_PATH% +if not exist install mkdir install +if not exist install\%2 mkdir install\%2 +if not exist install\%2\%1 mkdir install\%2\%1 + +xcopy /D /Y bin\kernel\objfre_%wo_os%_%wo_arch%\%wo_arch_dir% install\%2\%1 +xcopy /D /Y bin\user\objfre_%wo_os%_%wo_arch%\%wo_arch_dir% install\%2\%1 +xcopy /D /Y bin\kernel\objchk_%wo_os%_%wo_arch%\%wo_arch_dir% install\%2\%1 +xcopy /D /Y bin\user\objchk_%wo_os%_%wo_arch%\%wo_arch_dir% install\%2\%1 + +for /f "usebackq" %%i in (`dir /s /b *.inf`) do ( + xcopy /D /Y %%i install\%2\%1 +) + +popd +goto end + +:use +echo - +echo cpinst - copy installation files +echo - +echo Copies drivers, libraries, executables, etc. into an install directory. +echo Files from this directory may be used to install drivers on a given +echo target system. You must customize for your development system by setting +echo the following environment variable: +echo - +echo WINOF_PATH: (example WINOF_PATH=c:\ofw\trunk) +echo - +echo This will create WINOF_PATH\install\OS\ARCH +echo - +echo Use: +echo cpinst {x86 : x64 : ia64} {xp : 2003 : 2008} +echo xp requires x86 build +echo - +echo You must have built both the free and checked versions of the code +echo for the target platform. The files with the most recent date will be kept. +echo - +echo Examples: +echo cpinst x86 2003 - creates WINOF_PATH\install\2003\x86 +echo cpinst x64 2003 - creates WINOF_PATH\install\2003\x64 +echo cpinst x64 2008 - creates WINOF_PATH\install\2008\x64 + +:end +endlocal +@echo on diff --git a/branches/WOF2-3/etc/depwo.bat b/branches/WOF2-3/etc/depwo.bat new file mode 100644 index 00000000..c496e027 --- /dev/null +++ b/branches/WOF2-3/etc/depwo.bat @@ -0,0 +1,115 @@ +@echo off +setlocal + +if "%WDK_PATH%"=="" goto use +if "%OPENIB_REV%"=="" goto use +if "%PLATFORM_SDK_PATH%"=="" goto use + +if "%1"=="chk" ( + set wo_bld=chk + goto set_arch +) +if "%1"=="fre" ( + set wo_bld=fre + goto set_arch +) +goto use + +:set_arch +if "%2"=="x86" ( + set wo_arch=x86 + set wo_arch_dir=i386 + goto set_os +) +if "%2"=="x64" ( + set wo_arch=amd64 + set wo_arch_dir=amd64 + goto set_os +) +if "%2"=="ia64" ( + set wo_arch=ia64 + set wo_arch_dir=ia64 + goto set_os +) +goto use + +:set_os +if "%3"=="win7" ( + set wo_os=win7 + goto deploy +) +if "%3"=="2003" ( + set wo_os=wnet + goto deploy +) +if "%3"=="2008" ( + set wo_os=WLH + goto deploy +) +if "%3"=="xp" ( + if not "%2"=="x86" goto use + set wo_os=WXP + set wo_arch= + goto deploy +) +goto use + +:deploy +if "%4"=="" goto use + +@echo on +pushd %WINOF_PATH% +if not exist \\%4\c$\winof mkdir \\%4\c$\winof +if not exist \\%4\c$\winof\install mkdir \\%4\c$\winof\install + +xcopy /S /D /Y install\%3\%2\%1 \\%4\c$\winof\install + +rem -- HCA drivers automatically install other packages +xcopy /S /D /Y /EXCLUDE:etc\nomerge.txt install\%3\%2\%1\ibbus\*.* \\%4\c$\winof\install\mlx4_hca +xcopy /S /D /Y /EXCLUDE:etc\nomerge.txt install\%3\%2\%1\winmad\*.* \\%4\c$\winof\install\mlx4_hca +xcopy /S /D /Y /EXCLUDE:etc\nomerge.txt install\%3\%2\%1\winverbs\*.* \\%4\c$\winof\install\mlx4_hca +xcopy /S /D /Y /EXCLUDE:etc\nomerge.txt install\%3\%2\%1\ibbus\*.* \\%4\c$\winof\install\mthca +xcopy /S /D /Y /EXCLUDE:etc\nomerge.txt install\%3\%2\%1\winmad\*.* \\%4\c$\winof\install\mthca +xcopy /S /D /Y /EXCLUDE:etc\nomerge.txt install\%3\%2\%1\winverbs\*.* \\%4\c$\winof\install\mthca + +rem -- Copy files to support test signing +xcopy /S /D /Y %WDK_PATH%\tools\devcon\%wo_arch_dir%\devcon.exe \\%4\c$\winof\install +xcopy /S /D /Y etc\addcert.bat \\%4\c$\winof\install +xcopy /S /D /Y etc\sign*.bat \\%4\c$\winof\install +xcopy /D /Y %WDK_PATH%\bin\selfsign\* \\%4\c$\winof\install + +@echo off +popd +goto end + +:use +echo - +echo depwo - deploy winof installation files to cluster head node +echo depwo {chk : fre} {x86 : x64 : ia64} {xp : 2003 : 2008 : win7} headnode +echo - +echo You should run bldwo and pkgwo before running this batch file. +echo You must customize for your system by setting the following environment +echo variables: +echo - +echo WDK_PATH (example set WDK_PATH=c:\winddk\6001.18001) +echo WINOF_PATH (example set WINOF_PATH=c:\ofw\trunk) +echo OPENIB_REV (example set OPENIB_REV=0) +echo PLATFORM_SDK_PATH (example set PLATFORM_SDK_PATH=c:\progra~1\mi2578~1) +echo - +echo Use: +echo depwo {chk : fre} {x86 : x64 : ia64} {xp : 2003 : 2008 : win7} headnode +echo xp only supports x86 build +echo - +echo You must have privileges to copy into \\headnode\c$\winof\install +echo - +echo Examples: +echo depwo chk x64 2008 win08-0 - copies 2008 checked x64 files to win08-0 +echo depwo fre x64 win7 win7-0 - copies windows 7 free x64 files to win7-0 +echo - +echo Files are copied under c:\winof\install on the target system +echo See docs\build.txt for additional information on building the tree. +echo Also see pkgwo and bldwo batch scripts. + +:end +endlocal +@echo on diff --git a/branches/WOF2-3/etc/kernel/index_list.c b/branches/WOF2-3/etc/kernel/index_list.c new file mode 100644 index 00000000..4b3e6491 --- /dev/null +++ b/branches/WOF2-3/etc/kernel/index_list.c @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "index_list.h" + +INDEX_ENTRY EmptyList; + +static BOOLEAN IndexListGrow(INDEX_LIST *pIndexList) +{ + INDEX_ENTRY *array; + SIZE_T size, i; + + size = pIndexList->Size + (PAGE_SIZE / sizeof(INDEX_ENTRY)); + array = ExAllocatePoolWithTag(NonPagedPool, size * sizeof(INDEX_ENTRY), 'xdni'); + if (array == NULL) { + return FALSE; + } + + i = size; + while (i-- > pIndexList->Size) { + array[i].pItem = NULL; + array[i].Next = pIndexList->FreeList; + pIndexList->FreeList = i; + } + + if (pIndexList->pArray != &EmptyList) { + RtlCopyMemory(array, pIndexList->pArray, pIndexList->Size * sizeof(INDEX_ENTRY)); + ExFreePool(pIndexList->pArray); + } else { + array[0].Next = 0; + array[0].Prev = 0; + pIndexList->FreeList = 1; + } + + pIndexList->Size = size; + pIndexList->pArray = array; + return TRUE; +} + +SIZE_T IndexListInsertHead(INDEX_LIST *pIndexList, void *pItem) +{ + INDEX_ENTRY *entry; + SIZE_T index; + + if (pIndexList->FreeList == 0 && !IndexListGrow(pIndexList)) { + return 0; + } + + index = pIndexList->FreeList; + entry = &pIndexList->pArray[index]; + pIndexList->FreeList = entry->Next; + + entry->pItem = pItem; + entry->Next = pIndexList->pArray[0].Next; + pIndexList->pArray[0].Next = index; + entry->Prev = 0; + pIndexList->pArray[entry->Next].Prev = index; + + return index; +} + +void *IndexListRemove(INDEX_LIST *pIndexList, SIZE_T Index) +{ + INDEX_ENTRY *entry; + void *item; + + if (Index >= pIndexList->Size) { + return NULL; + } + + entry = &pIndexList->pArray[Index]; + if (entry->pItem == NULL) { + return NULL; + } + + pIndexList->pArray[entry->Next].Prev = entry->Prev; + pIndexList->pArray[entry->Prev].Next = entry->Next; + + item = entry->pItem; + entry->pItem = NULL; + entry->Next = pIndexList->FreeList; + pIndexList->FreeList = Index; + return item; +} diff --git a/branches/WOF2-3/etc/kernel/work_queue.c b/branches/WOF2-3/etc/kernel/work_queue.c new file mode 100644 index 00000000..f83254a3 --- /dev/null +++ b/branches/WOF2-3/etc/kernel/work_queue.c @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include "work_queue.h" + + +typedef struct _WORK_QUEUE_TASK +{ + WORK_QUEUE *pWorkQueue; + PIO_WORKITEM pWorkItem; + int Next; + int Index; + +} WORK_QUEUE_TASK; + + +#if (WINVER < _WIN32_WINNT_WIN6) +#define KeQueryActiveProcessorCount(x) KeNumberProcessors +#endif + + +NTSTATUS WorkQueueInit(WORK_QUEUE *pWorkQueue, PDEVICE_OBJECT Device, int TaskCount) +{ + WORK_QUEUE_TASK *task; + KAFFINITY procs; + int i; + + if (TaskCount == 0) { + TaskCount = KeQueryActiveProcessorCount(&procs); + } + + KeInitializeSpinLock(&pWorkQueue->Lock); + InitializeListHead(&pWorkQueue->List); + pWorkQueue->TaskCount = TaskCount; + pWorkQueue->TaskArray = ExAllocatePoolWithTag(NonPagedPool, + sizeof(WORK_QUEUE_TASK) * (TaskCount + 1), + 'ktqw'); + if (pWorkQueue->TaskArray == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + for (i = 0; i <= TaskCount; i++) { + task = &pWorkQueue->TaskArray[i]; + task->pWorkQueue = pWorkQueue; + task->Index = i; + task->Next = i + 1; + if (i > 0) { + task->pWorkItem = IoAllocateWorkItem(Device); + if (task->pWorkItem == NULL) { + goto err; + } + } + } + task->Next = 0; + return STATUS_SUCCESS; + +err: + while (--i > 0) { + IoFreeWorkItem(pWorkQueue->TaskArray[i].pWorkItem); + } + ExFreePoolWithTag(pWorkQueue->TaskArray, 'ktqw'); + return STATUS_INSUFFICIENT_RESOURCES; +} + +void WorkQueueDestroy(WORK_QUEUE *pWorkQueue) +{ + while (pWorkQueue->TaskCount > 0) { + IoFreeWorkItem(pWorkQueue->TaskArray[pWorkQueue->TaskCount--].pWorkItem); + } + ExFreePool(pWorkQueue->TaskArray); +} + +static VOID WorkQueueHandler(PDEVICE_OBJECT pDevice, void *Context) +{ + WORK_QUEUE *wq; + WORK_QUEUE_TASK *task = (WORK_QUEUE_TASK *) Context; + WORK_ENTRY *work; + LIST_ENTRY *entry; + KLOCK_QUEUE_HANDLE lockqueue; + UNREFERENCED_PARAMETER(pDevice); + + wq = task->pWorkQueue; + KeAcquireInStackQueuedSpinLock(&wq->Lock, &lockqueue); + + if (!IsListEmpty(&wq->List)) { + entry = RemoveHeadList(&wq->List); + KeReleaseInStackQueuedSpinLock(&lockqueue); + + work = CONTAINING_RECORD(entry, WORK_ENTRY, Entry); + work->WorkHandler(work); + + KeAcquireInStackQueuedSpinLock(&wq->Lock, &lockqueue); + if (!IsListEmpty(&wq->List)) { + KeReleaseInStackQueuedSpinLock(&lockqueue); + IoQueueWorkItem(task->pWorkItem, WorkQueueHandler, DelayedWorkQueue, task); + return; + } + } + + task->Next = wq->TaskArray[0].Next; + wq->TaskArray[0].Next = task->Index; + KeReleaseInStackQueuedSpinLock(&lockqueue); +} + +void WorkQueueInsert(WORK_QUEUE *pWorkQueue, WORK_ENTRY *pWork) +{ + WORK_QUEUE_TASK *task; + KLOCK_QUEUE_HANDLE lockqueue; + + KeAcquireInStackQueuedSpinLock(&pWorkQueue->Lock, &lockqueue); + InsertHeadList(&pWorkQueue->List, &pWork->Entry); + task = &pWorkQueue->TaskArray[pWorkQueue->TaskArray[0].Next]; + pWorkQueue->TaskArray[0].Next = task->Next; + KeReleaseInStackQueuedSpinLock(&lockqueue); + + if (task->Index != 0) { + IoQueueWorkItem(task->pWorkItem, WorkQueueHandler, DelayedWorkQueue, task); + } +} diff --git a/branches/WOF2-3/etc/makebin.bat b/branches/WOF2-3/etc/makebin.bat new file mode 100644 index 00000000..a49fdb02 --- /dev/null +++ b/branches/WOF2-3/etc/makebin.bat @@ -0,0 +1,917 @@ +@echo off +setlocal + +rem usage: +rem makebin src dst OSE Arch DDK_ROOT WdfCoInstaler_Ver +rem +rem src(%1) - OpenIB src path ...\gen1\trunk +rem dst(%2) - full path to where binaries are copied, must exist. +rem OSE(%3) - (Operating System Environment) which windows version +rem {win7,wxp,wlh,wnet} representing {XP, server 2008 & server 2003} +rem Arch(%4) - all, x86, x64, ia64 +rem DDK_ROOT - {blank == assumes %SystemDrive%\WinDDK\7600.16385.0} +rem WdfCoInstall_ver - 5 digit WdfCoInstallerVersion # (blank == 01007} + +rem makebin is designed to take an openIB src tree path and produce a folder +rem (tree) of binaries suitable for input to a WIX builder which procduces +rem an OS/Arch specific .msi installer. +rem Building a OFED release is done is 3 phases, makebin is the 2nd phase. +rem makebin is commonly run from trunk\buildrelease.bat although it can be +rem run standalone. + +echo Starting makebin +echo Src %1 +echo Dst %2 +echo OS %3 +echo Arch %4 + +if "%1"=="" goto usage +if "%2"=="" goto usage + +if "%3"=="" goto usage +if /I "%3"=="win7" goto os_ok +if /I "%3"=="wlh" goto os_ok +if /I "%3"=="wnet" goto os_ok +if /I "%3"=="wxp" goto os_ok +echo %0: Err - Invalid OS type '%3', use [win7, wlh, wnet, wxp] ? +exit /B 1 + +:os_ok + +rem Enable tracing to indicate phase for potiential debug. +set DBG=TRUE + +set OSE=%3 + +if "%4"=="" goto usage + +if /I "%4"=="ia64" ( + set ARCH_MS=%4 + goto arch_ok +) +if /I "%4"=="x86" ( + set ARCH_MS=%4 + goto arch_ok +) +if /I "%4"=="x64" ( + set ARCH_MS=amd64 + goto arch_ok +) +echo %0: Err - Invalid Arch type '%4', use [x86, ia64, x64, all] ? +exit /B 1 + +:arch_ok +set _ARCH=%4 + +if /I "%3"=="wxp" ( + if /I "%4"=="x86" goto os_arch_OK + echo %0: Err - Invalid OS Arch combination '%3 %4', wxp + x86 Only! + exit /B 1 +) + +:os_arch_OK + +rem setup DDK root path +if /I "%5"=="" ( + set _DDK=%systemdrive%\WinDDK\7600.16385.1 +) else ( + set _DDK=%5 +) +if not exist "%_DDK%" ( + echo Missing file %_DDK% ? + exit /B 1 +) + +set WdfCoInstaller=%_DDK%\redist\wdf +set DIFXP=%_DDK%\redist\DIFx\DIFxAPP\WixLib +set DPINST=%_DDK%\redist\DIFx\DPInst\EngMui + +if /I "%6"=="" ( + set CoInstallVer=01009 +) else ( + set CoInstallVer=%6 +) + +if not exist %1 goto usage +if not exist %2 goto usage + +rem verify binaries OK +if /I "%OSE%" == "wxp" goto bin_chk_x86 + +if /I "%_ARCH%"=="x64" ( + if not exist %1\bin\kernel\objfre_%OSE%_amd64\amd64 goto error1 + if not exist %1\bin\user\objfre_%OSE%_amd64\amd64 goto error4 + if not exist %1\bin\user\objchk_%OSE%_amd64\amd64 goto error7 + goto bin_ok +) + +if /I "%_ARCH%"=="ia64" ( + if not exist %1\bin\kernel\objfre_%OSE%_ia64\ia64 goto error2 + if not exist %1\bin\user\objfre_%OSE%_ia64\ia64 goto error5 + if not exist %1\bin\user\objchk_%OSE%_ia64\ia64 goto error8 + goto bin_ok +) + +rem wxp or x86 +:bin_chk_x86 + +if not exist %1\bin\kernel\objfre_%OSE%_x86\i386 goto error3 +if not exist %1\bin\user\objfre_%OSE%_x86\i386 goto error6 +if not exist %1\bin\user\objchk_%OSE%_x86\i386 goto error9 + +:bin_OK + +set CORE_DRV_FRE=ibbus.sys ibbus.pdb ibiou.sys ibiou.pdb ib_iou.inf mthca.sys mthca.inf mthca.pdb mlx4_hca.sys mlx4_hca.pdb mlx4_hca.inf mlx4_bus.sys mlx4_bus.pdb mlx4_bus.inf winverbs.sys winverbs.pdb winmad.sys winmad.pdb + +set CORE_UM_F=ibal.dll ibal.lib ibal.pdb complib.dll complib.lib complib.pdb mthcau.dll mthcau.pdb mlx4u.dll mlx4u.pdb + +set CORE_UM_D=ibald.dll ibald.lib ibald.pdb complibd.dll complibd.lib complibd.pdb mthcaud.dll mthcaud.pdb mlx4ud.dll mlx4ud.pdb + +set WV_CHK=winverbsd.dll winverbsd.lib winverbsd.pdb winmadd.dll winmadd.lib libibverbsd.dll libibverbsd.lib libibverbsd.pdb libibumadd.lib libibumadd.dll libibumadd.pdb libibmadd.lib libibmadd.dll libibmadd.pdb librdmacmd.lib librdmacmd.dll librdmacmd.pdb libibnetdiscd.dll libibnetdiscd.pdb + +set WV_FRE=winverbs.dll winverbs.lib winmad.dll winmad.lib libibverbs.dll libibverbs.lib libibverbs.pdb libibumad.lib libibumad.dll libibumad.pdb libibmad.lib libibmad.dll libibmad.pdb librdmacm.dll librdmacm.lib librdmacm.pdb libibnetdisc.dll libibnetdisc.pdb + +set DAPL2_F=dapl2.dll dapl2.pdb dapl2-ofa-scm.dll dapl2-ofa-scm.pdb dapl2-ofa-cma.dll dapl2-ofa-cma.pdb dapl2-ofa-ucm.dll dapl2-ofa-ucm.pdb dat2.dll dat2.lib dat2.pdb + +set DAPL2_D=dapl2d.dll dapl2d.pdb dapl2-ofa-scmd.dll dapl2-ofa-scmd.pdb dapl2-ofa-cmad.dll dapl2-ofa-cmad.pdb dapl2-ofa-ucmd.dll dapl2-ofa-ucmd.pdb dat2d.dll dat2d.lib dat2d.pdb + +rem +rem KERNEL MODE +rem + +if /I "%OSE%" == "wxp" goto free_wxp_drv +if /I "%_ARCH%" == "x86" goto free_wxp_drv +if /I "%_ARCH%" == "ia64" goto free_ia64_drv + +rem Copy AMD64 Free drivers + +set bin_dir=%1\bin\kernel\objfre_%OSE%_amd64\amd64 +set bin_dir_fre_WOW=%1\bin\user\objfre_%OSE%_x86\i386 +set bin_dir_chk_WOW=%1\bin\user\objchk_%OSE%_x86\i386 + +set dest_dir=%2\HCA\amd64\ + +if "%DBG%" == "TRUE" echo DBG: AMD64 free drivers + +for %%i in ( %CORE_DRV_FRE% ) do ( + xcopy %bin_dir%\%%i %dest_dir% /yq 1> nul + if ERRORLEVEL 1 ( + echo ERR on xcopy %bin_dir%\%%i %dest_dir% /yq + exit /B 1 + ) +) + +xcopy %WdfCoInstaller%\amd64\WdfCoInstaller%CoInstallVer%.dll %dest_dir% /yq + +for %%i in ( ipoib qlgcvnic ) do ( + xcopy %bin_dir%\%%i.sys %2\net\amd64\ /yq 1> nul + if ERRORLEVEL 1 ( + echo ERR xcopy %bin_dir%\%%i.sys %2\net\amd64\ /yq + exit /B 1 + ) + xcopy %bin_dir%\%%i.pdb %2\net\amd64\ /yq 1> nul + if ERRORLEVEL 1 ( + echo ERR xcopy %bin_dir%\%%i.pdb %2\net\amd64\ /yq + exit /B 1 + ) +) + +xcopy %bin_dir%\ibsrp.sys %2\storage\amd64\ /yq +xcopy %bin_dir%\ibsrp.pdb %2\storage\amd64\ /yq + +xcopy %bin_dir%\netipoib.inf %2\net\amd64\ /yq +xcopy %bin_dir%\netvnic.inf %2\net\amd64\ /yq +xcopy %bin_dir%\ib_srp.inf %2\storage\amd64\ /yq +goto free_drv_done + +:free_ia64_drv + +rem Copy IA64 drivers + +set bin_dir=%1\bin\kernel\objfre_%OSE%_ia64\ia64 +set bin_dir_fre_WOW=%1\bin\user\objfre_%OSE%_x86\i386 +set bin_dir_chk_WOW=%1\bin\user\objchk_%OSE%_x86\i386 + +set dest_dir=%2\HCA\ia64\ + +if "%DBG%" == "TRUE" echo DBG: ia64 free drivers + +for %%i in ( %CORE_DRV_FRE% ) do ( + xcopy %bin_dir%\%%i %dest_dir% /yq 1>nul + if ERRORLEVEL 1 ( + echo ERR on xcopy %bin_dir%\%%i %dest_dir% /yq + exit /B 1 + ) +) +xcopy %WdfCoInstaller%\ia64\WdfCoInstaller%CoInstallVer%.dll %dest_dir% /yq + +for %%i in ( ipoib qlgcvnic ) do ( + xcopy %bin_dir%\%%i.sys %2\net\ia64\ /yq 1> nul + if ERRORLEVEL 1 ( + echo ERR xcopy %bin_dir%\%%i.sys %2\net\ia64\ /yq + exit /B 1 + ) + xcopy %bin_dir%\%%i.pdb %2\net\ia64\ /yq 1> nul + if ERRORLEVEL 1 ( + echo ERR xcopy %bin_dir%\%%i.pdb %2\net\ia64\ /yq + exit /B 1 + ) +) + +xcopy %bin_dir%\ibsrp.sys %2\storage\ia64\ /yq +xcopy %bin_dir%\ibsrp.pdb %2\storage\ia64\ /yq + +xcopy %bin_dir%\netipoib.inf %2\net\ia64\ /yq +xcopy %bin_dir%\netvnic.inf %2\net\ia64\ /yq +xcopy %bin_dir%\ib_srp.inf %2\storage\ia64\ /yq + +goto free_drv_done + +rem Copy x86 drivers + +:free_wxp_drv + +if "%DBG%" == "TRUE" echo DBG: x86 free drivers + +set bin_dir=%1\bin\kernel\objfre_%OSE%_x86\i386 +set dest_dir=%2\HCA\x86\ + +for %%i in ( %CORE_DRV_FRE% ) do ( + xcopy %bin_dir%\%%i %dest_dir% /yq 1>nul + if ERRORLEVEL 1 ( + echo ERR on xcopy %bin_dir%\%%i %dest_dir% /yq + exit /B 1 + ) +) +xcopy %WdfCoInstaller%\x86\WdfCoInstaller%CoInstallVer%.dll %dest_dir% /yq + +for %%i in ( ipoib qlgcvnic ) do ( + xcopy %bin_dir%\%%i.sys %2\net\x86\ /yq 1> nul + if ERRORLEVEL 1 ( + echo ERR xcopy %bin_dir%\%%i.sys %2\net\x86\ /yq + exit /B 1 + ) + xcopy %bin_dir%\%%i.pdb %2\net\x86\ /yq 1> nul + if ERRORLEVEL 1 ( + echo ERR xcopy %bin_dir%\%%i.pdb %2\net\x86\ /yq + exit /B 1 + ) +) + +xcopy %bin_dir%\ibsrp.sys %2\storage\x86\ /yq +xcopy %bin_dir%\ibsrp.pdb %2\storage\x86\ /yq + +rem Use netipoib.inf without WSD support for XP32 +if /I "%OSE%" == "wxp" ( + copy /A /Y %1\ulp\ipoib\kernel\netipoib-xp32.inf %2\net\x86\netipoib.inf +) else ( + xcopy %bin_dir%\netipoib.inf %2\net\x86\ /yq +) + +rem allow XP SRP build & sign, WIX skips SRP for XP +rem otherwise there is too much special casing for SRP on XP. +xcopy %bin_dir%\ib_srp.inf %2\storage\x86\ /yq +xcopy %bin_dir%\netvnic.inf %2\net\x86\ /yq +xcopy %bin_dir%\ib_srp.inf %2\storage\x86\ /yq + +:free_drv_done + +rem Checked USER MODE + +if /I "%OSE%" == "wxp" goto wxp_userm +if /I "%_ARCH%" == "x86" goto wxp_userm +if /I "%_ARCH%" == "ia64" goto chk_ia64_um + +if "%DBG%" == "TRUE" echo DBG: amd64 Checked amd64 user-mode + +set bin_dir=%1\bin\user\objchk_%OSE%_amd64\amd64 +set dest_dir=%2\HCA\amd64\ + +for %%i in (%CORE_UM_D%) do ( + xcopy %bin_dir%\%%i %dest_dir% /yq 1>nul + if ERRORLEVEL 1 ( + echo ERR on xcopy %bin_dir%\%%i %dest_dir% /yq + exit /B 1 + ) +) + +echo xcopy winverbs: User checked to HCA\amd64 + +for %%i in ( %WV_CHK% ) do ( + xcopy %bin_dir%\%%i %dest_dir% /yq 1>nul + if ERRORLEVEL 1 ( + echo ERR on xcopy %bin_dir%\%%i %dest_dir% /yq + exit /B 1 + ) +) + +echo xcopy *.exe tools\amd64\debug\ +xcopy %bin_dir%\*.exe %2\tools\amd64\debug\ /yq 1>nul + +for %%i in ( %DAPL2_D% ) do ( + xcopy %bin_dir%\%%i %2\DAPL2\amd64\ /yq 1>nul + if ERRORLEVEL 1 ( + echo ERR on xcopy %bin_dir%\%%i %2\DAPL2\amd64\ /yq + exit /B 1 + ) +) +goto chk_um_dll + +:chk_ia64_um + +rem Copy checked IA64 dlls + +if "%DBG%" == "TRUE" echo DBG: ia64 Checked dlls + +set bin_dir=%1\bin\user\objchk_%OSE%_ia64\ia64 +set dest_dir=%2\HCA\ia64\ + +for %%i in (%CORE_UM_D%) do ( + xcopy %bin_dir%\%%i %dest_dir% /yq 1>nul + if ERRORLEVEL 1 ( + echo ERR on xcopy %bin_dir%\%%i %dest_dir% /yq + exit /B 1 + ) +) + +echo xcopy winverbs: User checked to HCA\ia64 + +for %%i in ( %WV_CHK% ) do ( + xcopy %bin_dir%\%%i %dest_dir% /yq 1>nul + if ERRORLEVEL 1 ( + echo ERR on xcopy %bin_dir%\%%i %dest_dir% /yq + exit /B 1 + ) +) + +echo xcopy *.exe tools\ia64\debug\ +xcopy %bin_dir%\*.exe %2\tools\ia64\debug\ /yq 1>nul + +for %%i in ( %DAPL2_D% ) do ( + xcopy %bin_dir%\%%i %2\DAPL2\ia64\ /yq 1>nul + if ERRORLEVEL 1 ( + echo ERR on xcopy %bin_dir%\%%i %2\DAPL2\ia64\ /yq + exit /B 1 + ) +) +goto chk_um_dll + +rem checked x86 user mode + +:wxp_userm + +if "%DBG%" == "TRUE" echo DBG: x86 Checked user-mode dlls + +set bin_dir=%1\bin\user\objchk_%OSE%_x86\i386 +set dest_dir=%2\HCA\x86\ + +for %%i in (%CORE_UM_D%) do ( + xcopy %bin_dir%\%%i %dest_dir% /yq 1>nul + if ERRORLEVEL 1 ( + echo ERR on xcopy %bin_dir%\%%i %dest_dir% /yq + exit /B 1 + ) +) + +echo xcopy winverbs: User checked to HCA\x86 + +for %%i in ( %WV_CHK% ) do ( + xcopy %bin_dir%\%%i %dest_dir% /yq 1>nul + if ERRORLEVEL 1 ( + echo ERR on xcopy %bin_dir%\%%i %dest_dir% /yq + exit /B 1 + ) +) + +if "%DBG%" == "TRUE" echo DBG: checked *.exe to tools\x86\debug\ +xcopy %bin_dir%\*.exe %2\tools\x86\debug\ /yq 1>nul + +for %%i in ( %DAPL2_D% ) do ( + xcopy %bin_dir%\%%i %2\DAPL2\x86\ /yq 1>nul + if ERRORLEVEL 1 ( + echo ERR on xcopy %bin_dir%\%%i %2\DAPL2\x86\ /yq + exit /B 1 + ) +) +copy /B %bin_dir%\installsp.exe %2\tools\x86\debug\ /y 1>nul + +if /I "%OSE%" == "wxp" goto wxp_free_drv +if /I "%_ARCH%" == "x86" goto wxp_free_drv + +:chk_um_dll + +rem checked x86 DLLs --> WOW64 DLLs + +if "%DBG%" == "TRUE" echo DBG: x86 Checked dlls copy to WOW64 dlls +echo src %bin_dir% +echo dest %2 +echo WOW %bin_dir_chk_WOW% + +if Not Exist "%bin_dir_chk_WOW%\ibald.dll" ( + echo Missing x86 WOW file %bin_dir_chk_WOW%\ibald.dll + exit /B 1 +) + +rem xcopy had problems determining if dest was File | Dir ?? + +if /I "%_ARCH%" == "x64" ( + copy /B %bin_dir_chk_WOW%\ibald.dll %2\HCA\amd64\ibal32d.dll /y + copy /B %bin_dir_chk_WOW%\ibald.lib %2\HCA\amd64\ibal32d.lib /y + copy /B %bin_dir_chk_WOW%\ibald.pdb %2\HCA\amd64\ibal32d.pdb /y + copy /B %bin_dir_chk_WOW%\complibd.dll %2\HCA\amd64\cl32d.dll /y + copy /B %bin_dir_chk_WOW%\complibd.lib %2\HCA\amd64\cl32d.lib /y + copy /B %bin_dir_chk_WOW%\complibd.pdb %2\HCA\amd64\cl32d.pdb /y + copy /B %bin_dir_chk_WOW%\mthcaud.dll %2\HCA\amd64\mthca32d.dll /y + copy /B %bin_dir_chk_WOW%\mlx4ud.dll %2\HCA\amd64\mlx4u32d.dll /y + copy /B %bin_dir_chk_WOW%\dat2d.dll %2\DAPL2\amd64\dat232d.dll /y + copy /B %bin_dir_chk_WOW%\dapl2d.dll %2\DAPL2\amd64\dapl232d.dll /y + copy /B %bin_dir_chk_WOW%\dapl2-ofa-scmd.dll %2\DAPL2\amd64\dapl2-ofa-scmd32.dll /y + copy /B %bin_dir_chk_WOW%\dapl2-ofa-cmad.dll %2\DAPL2\amd64\dapl2-ofa-cmad32.dll /y + copy /B %bin_dir_chk_WOW%\dapl2-ofa-ucmd.dll %2\DAPL2\amd64\dapl2-ofa-ucmd32.dll /y +) else ( + copy /B %bin_dir_chk_WOW%\ibald.dll %2\HCA\ia64\ibal32d.dll /y + copy /B %bin_dir_chk_WOW%\ibald.lib %2\HCA\ia64\ibal32d.lib /y + copy /B %bin_dir_chk_WOW%\ibald.pdb %2\HCA\ia64\ibal32d.pdb /y + copy /B %bin_dir_chk_WOW%\complibd.dll %2\HCA\ia64\cl32d.dll /y + copy /B %bin_dir_chk_WOW%\complibd.lib %2\HCA\ia64\cl32d.lib /y + copy /B %bin_dir_chk_WOW%\complibd.pdb %2\HCA\ia64\cl32d.pdb /y + copy /B %bin_dir_chk_WOW%\mthcaud.dll %2\HCA\ia64\mthca32d.dll /y + copy /B %bin_dir_chk_WOW%\mlx4ud.dll %2\HCA\ia64\mlx4u32d.dll /y + copy /B %bin_dir_chk_WOW%\dat2d.dll %2\DAPL2\ia64\dat232d.dll /y + copy /B %bin_dir_chk_WOW%\dapl2d.dll %2\DAPL2\ia64\dapl232d.dll /y + copy /B %bin_dir_chk_WOW%\dapl2-ofa-scmd.dll %2\DAPL2\ia64\dapl2-ofa-scmd32.dll /y + copy /B %bin_dir_chk_WOW%\dapl2-ofa-cmad.dll %2\DAPL2\ia64\dapl2-ofa-cmad32.dll /y + copy /B %bin_dir_chk_WOW%\dapl2-ofa-ucmd.dll %2\DAPL2\ia64\dapl2-ofa-ucmd32.dll /y + goto ia64_fre_dll +) + +rem Copy Free x64 dll + +set bin_dir=%1\bin\user\objfre_%OSE%_amd64\amd64 +set dest_dir=%2\HCA\amd64\ + +if "%DBG%" == "TRUE" echo DBG: copy amd64 Free dlls + +for %%i in (%CORE_UM_F%) do ( + xcopy %bin_dir%\%%i %dest_dir% /yq 1>nul + if ERRORLEVEL 1 ( + echo ERR on xcopy %bin_dir%\%%i %dest_dir% /y + exit /B 1 + ) +) + +echo xcopy winverbs: User free to HCA\amd64 + +for %%i in ( %WV_FRE% ) do ( + xcopy %bin_dir%\%%i %dest_dir% /yq 1>nul + if ERRORLEVEL 1 ( + echo ERR on xcopy %bin_dir%\%%i %dest_dir% /yq + exit /B 1 + ) +) + +xcopy %bin_dir%\ibwsd.dll %2\net\amd64\ /yq +xcopy %bin_dir%\installsp.exe %2\net\amd64\ /yq +xcopy %bin_dir%\installsp.exe %2\tools\amd64\release\ /yq + +if exist "%bin_dir%\ndinstall.exe" ( + xcopy %bin_dir%\ndinstall.exe %2\net\amd64\ /yq + xcopy %bin_dir%\ndinstall.exe %2\tools\amd64\release\ /yq + xcopy %bin_dir%\ibndprov.dll %2\net\amd64\ /yq + xcopy %bin_dir%\wvndprov.dll %2\net\amd64\ /yq +) else ( + echo %0 - missing x64 Network Direct components [wvndprov.dll ibndprov.dll,ndinstall.exe] +) + +echo xcopy amd64 Free *.exe tools\amd64\release\ +xcopy %bin_dir%\*.exe %2\tools\amd64\release\ /yq 1>nul + +echo xcopy AMD64 [Winverb-apps].pdb tools\amd64\release\ +xcopy %bin_dir%\*.pdb %2\tools\amd64\release\ /yq 1>nul +if ERRORLEVEL 1 ( + echo ERR on xcopy %bin_dir%\*.pdb %2\tools\amd64\release\ /yq + exit /B 1 +) + +for %%i in ( %DAPL2_F% ) do ( + xcopy %bin_dir%\%%i %2\DAPL2\amd64\ /yq 1>nul + if ERRORLEVEL 1 ( + echo ERR on xcopy %bin_dir%\%%i %2\DAPL2\amd64\ /yq + exit /B 1 + ) +) +goto fre_dll_WOW + + +:ia64_fre_dll + +rem Copy Free IA64 dlls + +set bin_dir=%1\bin\user\objfre_%OSE%_ia64\ia64 +set dest_dir=%2\HCA\ia64\ + +if "%DBG%" == "TRUE" echo DBG: copy IA64 Free dlls + +for %%i in (%CORE_UM_F%) do ( + xcopy %bin_dir%\%%i %dest_dir% /yq 1>nul + if ERRORLEVEL 1 ( + echo ERR on xcopy %%i %dest_dir% /yq + exit /B 1 + ) +) + +echo xcopy winverbs: User free to HCA\ia64 + +for %%i in ( %WV_FRE% ) do ( + xcopy %bin_dir%\%%i %dest_dir% /yq 1>nul + if ERRORLEVEL 1 ( + echo ERR on xcopy %bin_dir%\%%i %dest_dir% /yq + exit /B 1 + ) +) + +xcopy %bin_dir%\ibwsd.dll %2\net\ia64\ /yq +xcopy %bin_dir%\installsp.exe %2\net\ia64\ /yq +xcopy %bin_dir%\ndinstall.exe %2\net\ia64\ /yq +xcopy %bin_dir%\wvndprov.dll %2\net\ia64\ /yq + +echo xcopy IA64 Free *.exe tools\ia64\release\ +xcopy %bin_dir%\*.exe %2\tools\ia64\release\ /yq 1>nul + +echo xcopy IA64 [Winverb-apps].pdb tools\ia64\release\ +xcopy %bin_dir%\*.pdb %2\tools\ia64\release\ /yq 1>nul +if ERRORLEVEL 1 ( + echo ERR on xcopy %bin_dir%\*.pdb %2\tools\ia64\release\ /yq + exit /B 1 +) + +for %%i in ( %DAPL2_F% ) do ( + xcopy %bin_dir%\%%i %2\DAPL2\ia64\ /yq 1>nul + if ERRORLEVEL 1 ( + echo ERR on xcopy %bin_dir%\%%i %2\DAPL2\ia64\ /yq + exit /B 1 + ) +) +goto fre_dll_WOW + + +rem Copy Free x86 drivers + +:wxp_free_drv + +set bin_dir=%1\bin\user\objfre_%OSE%_x86\i386 +set dest_dir=%2\HCA\x86\ + +if "%DBG%" == "TRUE" echo DBG: copy x86 Free dlls + +for %%i in (%CORE_UM_F%) do ( + xcopy %bin_dir%\%%i %dest_dir% /yq 1>nul + if ERRORLEVEL 1 ( + echo ERR on xcopy %bin_dir%\%%i %dest_dir% /yq + exit /B 1 + ) +) + +echo xcopy winverbs: User free to HCA\x86 + +for %%i in ( %WV_FRE% ) do ( + xcopy %bin_dir%\%%i %dest_dir% /yq 1>nul + if ERRORLEVEL 1 ( + echo ERR on xcopy %bin_dir%\%%i %dest_dir% /yq + exit /B 1 + ) +) + +echo xcopy x86 free *.exe to tools\x86\release +xcopy %bin_dir%\*.exe %2\tools\x86\release\ /yq 1>nul + +echo xcopy X86 Free [Winverb-apps].pdb tools\x86\release\ +xcopy %bin_dir%\*.pdb %2\tools\x86\release\ /yq 1>nul +if ERRORLEVEL 1 ( + echo ERR on xcopy %bin_dir%\*.pdb %2\tools\x86\release\ /yq + exit /B 1 +) + +for %%i in ( %DAPL2_F% ) do ( + xcopy %bin_dir%\%%i %2\DAPL2\x86\ /yq 1>nul + if ERRORLEVEL 1 ( + echo ERR on xcopy %bin_dir%\%%i %2\DAPL2\x86\ /yq + exit /B 1 + ) +) + +if exist "%bin_dir%\ndinstall.exe" ( + copy %bin_dir%\ndinstall.exe %2\net\x86\ /y + copy %bin_dir%\ndinstall.exe %2\tools\x86\release\ /y + copy %bin_dir%\ibndprov.dll %2\net\x86\ /y + copy %bin_dir%\wvndprov.dll %2\net\x86\ /y +) else ( + echo %0 - missing x86 Network Direct components [ibndprov.dll,ndinstall.exe] +) + +if /I "%OSE%" == "wxp" goto mk_sym_bin + +rem free x86 items + +if "%DBG%" == "TRUE" echo DBG: copy x86 Free WSD + +copy %bin_dir%\ibwsd.dll %2\net\x86\ /y +copy %bin_dir%\installsp.exe %2\net\x86\ /y +copy %bin_dir%\installsp.exe %2\tools\x86\release\ /y + +goto mk_sym_bin + +:fre_dll_WOW + +rem free x86 DLLs --> WOW64 DLLs + +if "%DBG%" == "TRUE" echo DBG: x86 Free dlls to WOW64 + +if /I "%_ARCH%" == "x64" ( + if exist "%bin_dir_fre_WOW%\ibndprov.dll" ( + copy %bin_dir_fre_WOW%\ibndprov.dll %2\net\amd64\ibndprov32.dll /y + copy %bin_dir_fre_WOW%\wvndprov.dll %2\net\amd64\wvndprov32.dll /y + ) + copy /B %bin_dir_fre_WOW%\ibwsd.dll %2\net\amd64\ibwsd32.dll /y + copy /B %bin_dir_fre_WOW%\ibal.dll %2\HCA\amd64\ibal32.dll /y + copy /B %bin_dir_fre_WOW%\ibal.lib %2\HCA\amd64\ibal32.lib /y + copy /B %bin_dir_fre_WOW%\ibal.pdb %2\HCA\amd64\ibal32.pdb /y + copy /B %bin_dir_fre_WOW%\complib.dll %2\HCA\amd64\cl32.dll /y + copy /B %bin_dir_fre_WOW%\complib.lib %2\HCA\amd64\cl32.lib /y + copy /B %bin_dir_fre_WOW%\complib.pdb %2\HCA\amd64\cl32.pdb /y + copy /B %bin_dir_fre_WOW%\winverbs.dll %2\HCA\amd64\winverbs32.dll /y + copy /B %bin_dir_fre_WOW%\winverbs.lib %2\HCA\amd64\winverbs32.lib /y + copy /B %bin_dir_fre_WOW%\winverbs.pdb %2\HCA\amd64\winverbs32.pdb /y + copy /B %bin_dir_fre_WOW%\winmad.dll %2\HCA\amd64\winverbs32.dll /y + copy /B %bin_dir_fre_WOW%\winmad.lib %2\HCA\amd64\winverbs32.lib /y + copy /B %bin_dir_fre_WOW%\winmad.pdb %2\HCA\amd64\winverbs32.pdb /y + copy /B %bin_dir_fre_WOW%\mthcau.dll %2\HCA\amd64\mthca32.dll /y + copy /B %bin_dir_fre_WOW%\mlx4u.dll %2\HCA\amd64\mlx4u32.dll /y + copy /B %bin_dir_fre_WOW%\dat2.dll %2\DAPL2\amd64\dat232.dll /y + copy /B %bin_dir_fre_WOW%\dapl2.dll %2\DAPL2\amd64\dapl232.dll /y + copy /B %bin_dir_fre_WOW%\dapl2-ofa-scm.dll %2\DAPL2\amd64\dapl2-ofa-scm32.dll /y + copy /B %bin_dir_fre_WOW%\dapl2-ofa-cma.dll %2\DAPL2\amd64\dapl2-ofa-cma32.dll /y + copy /B %bin_dir_fre_WOW%\dapl2-ofa-ucm.dll %2\DAPL2\amd64\dapl2-ofa-ucm32.dll /y +) else ( + rem IA64 + if exist "%bin_dir_fre_WOW%\ibndprov.dll" ( + copy %bin_dir_fre_WOW%\ibndprov.dll %2\net\ia64\ibndprov32.dll /y + copy %bin_dir_fre_WOW%\wvndprov.dll %2\net\ia64\wvndprov32.dll /y + ) + copy /B %bin_dir_fre_WOW%\ibwsd.dll %2\net\ia64\ibwsd32.dll /y + copy /B %bin_dir_fre_WOW%\ibal.dll %2\HCA\ia64\ibal32.dll /y + copy /B %bin_dir_fre_WOW%\ibal.lib %2\HCA\ia64\ibal32.lib /y + copy /B %bin_dir_fre_WOW%\ibal.pdb %2\HCA\ia64\ibal32.pdb /y + copy /B %bin_dir_fre_WOW%\complib.dll %2\HCA\ia64\cl32.dll /y + copy /B %bin_dir_fre_WOW%\complib.lib %2\HCA\ia64\cl32.lib /y + copy /B %bin_dir_fre_WOW%\complib.pdb %2\HCA\ia64\cl32.pdb /y + copy /B %bin_dir_fre_WOW%\winverbs.dll %2\HCA\ia64\winverbs32.dll /y + copy /B %bin_dir_fre_WOW%\winverbs.lib %2\HCA\ia64\winverbs32.lib /y + copy /B %bin_dir_fre_WOW%\winverbs.pdb %2\HCA\ia64\winverbs32.pdb /y + copy /B %bin_dir_fre_WOW%\winmad.dll %2\HCA\ia64\winverbs32.dll /y + copy /B %bin_dir_fre_WOW%\winmad.lib %2\HCA\ia64\winverbs32.lib /y + copy /B %bin_dir_fre_WOW%\winmad.pdb %2\HCA\ia64\winverbs32.pdb /y + copy /B %bin_dir_fre_WOW%\mthcau.dll %2\HCA\ia64\mthca32.dll /y + copy /B %bin_dir_fre_WOW%\mlx4u.dll %2\HCA\ia64\mlx4u32.dll /y + copy /B %bin_dir_fre_WOW%\dat2.dll %2\DAPL2\ia64\dat232.dll /y + copy /B %bin_dir_fre_WOW%\dapl2.dll %2\DAPL2\ia64\dapl232.dll /y + copy /B %bin_dir_fre_WOW%\dapl2-ofa-scm.dll %2\DAPL2\ia64\dapl2-ofa-scm32.dll /y + copy /B %bin_dir_fre_WOW%\dapl2-ofa-cma.dll %2\DAPL2\ia64\dapl2-ofa-cma32.dll /y + copy /B %bin_dir_fre_WOW%\dapl2-ofa-ucm.dll %2\DAPL2\ia64\dapl2-ofa-ucm32.dll /y +) + +:mk_sym_bin + +rem bin\bin used to generate a symbol store in build-ofa-dist.bat. + +echo 'Copy bin\obj{chk,fre}_%3_{%ARCH_MS%} to bin' + +if /I "%_ARCH%" == "x64" goto bin_x64 +if /I "%_ARCH%" == "ia64" goto bin_ia64 + +rem x86 +xcopy %1\bin\kernel\objchk_%3_x86 %2\bin\kernel\objchk_%3_x86\ /S /Y /Q +xcopy %1\bin\kernel\objfre_%3_x86 %2\bin\kernel\objfre_%3_x86\ /S /Y /Q + +xcopy %1\bin\user\objchk_%3_x86 %2\bin\user\objchk_%3_x86\ /S /Y /Q +xcopy %1\bin\user\objfre_%3_x86 %2\bin\user\objfre_%3_x86\ /S /Y /Q +goto do_dat + +:bin_x64 +xcopy %1\bin\kernel\objchk_%3_amd64 %2\bin\kernel\objchk_%3_amd64\ /S /Y /Q +xcopy %1\bin\kernel\objfre_%3_amd64 %2\bin\kernel\objfre_%3_amd64\ /S /Y /Q + +xcopy %1\bin\user\objchk_%3_amd64 %2\bin\user\objchk_%3_amd64\ /S /Y /Q +xcopy %1\bin\user\objfre_%3_amd64 %2\bin\user\objfre_%3_amd64\ /S /Y /Q +goto do_dat + +:bin_ia64 +xcopy %1\bin\kernel\objchk_%3_ia64 %2\bin\kernel\objchk_%3_ia64\ /S /Y /Q +xcopy %1\bin\kernel\objfre_%3_ia64 %2\bin\kernel\objfre_%3_ia64\ /S /Y /Q + +xcopy %1\bin\user\objchk_%3_ia64 %2\bin\user\objchk_%3_ia64\ /S /Y /Q +xcopy %1\bin\user\objfre_%3_ia64 %2\bin\user\objfre_%3_ia64\ /S /Y /Q + +:do_dat + +rem Copy DAT v2.0 header files +if "%DBG%" == "TRUE" echo DBG: [%OSE%] DAT v2.0 header files + +if exist %1\ulp\dapl2\dat\include\dat (set DATINC=dat) else (set DATINC=dat2) +pushd %1\ulp\dapl2\dat\include\%DATINC% +if ERRORLEVEL 1 ( + echo %0: ERR - missing DAT files @ %1\ulp\dapl2\dat\include\%DATINC% + exit /B 1 +) +xcopy dat.h %2\DAPL2 /Y/Q +xcopy dat_error.h %2\DAPL2 /Y/Q +xcopy dat_ib_extensions.h %2\DAPL2 /Y/Q +xcopy dat_platform_specific.h %2\DAPL2 /Y/Q +xcopy dat_redirection.h %2\DAPL2 /Y/Q +xcopy dat_registry.h %2\DAPL2 /Y/Q +xcopy dat_vendor_specific.h %2\DAPL2 /Y/Q +xcopy udat.h %2\DAPL2 /Y/Q +xcopy udat_config.h %2\DAPL2 /Y/Q +xcopy udat_redirection.h %2\DAPL2 /Y/Q +xcopy udat_vendor_specific.h %2\DAPL2 /Y/Q +popd + +pushd %1\ulp\dapl2\test\dapltest\scripts +xcopy dt-svr.bat %2\DAPL2 /Y/Q +xcopy dt-cli.bat %2\DAPL2 /Y/Q +popd + +rem Copy IBAL header files +if "%DBG%" == "TRUE" echo DBG: IBAL header files +if exist %1\inc ( + if exist %2\inc rmdir /S/Q %2\inc + mkdir %2\Inc + pushd %1\inc + xcopy oib_ver.h %2\Inc /Y/Q + xcopy mod_ver.def %2\Inc /Y/Q + xcopy openib.def %2\Inc /Y/Q + xcopy user\comp_channel.h %2\Inc /Y/Q + xcopy user\dlist.h %2\Inc /Y/Q + xcopy user\getopt.h %2\Inc /Y/Q + xcopy Complib %2\Inc\Complib /I/S/Y/Q + xcopy Iba %2\Inc\Iba /I/S/Y/Q + xcopy User\Complib %2\Inc\Complib /I/S/Y/Q + xcopy User\Iba %2\Inc\Iba /I/S/Y/Q + xcopy User\linux %2\Inc\linux /I/S/Y/Q + xcopy User\rdma %2\Inc\rdma /I/S/Y/Q + xcopy ..\ulp\libibverbs\include\infiniband %2\Inc\infiniband /I/S/Y/Q + xcopy ..\ulp\librdmacm\include\rdma\rdma_cma.h %2\Inc\rdma /Y/Q + xcopy ..\ulp\librdmacm\include\rdma\rdma_verbs.h %2\Inc\rdma /Y/Q + xcopy ..\etc\user %2\Inc\etc\user /I/S/Y/Q + popd +) + +rem WDK/WIX, Docs & IB SDK items +if "%DBG%" == "TRUE" echo DBG: WDK, WIx, Docs and SDK files + +if exist %2\Misc rmdir /Q/S %2\Misc +mkdir %2\Misc + +copy /Y/A %1\Docs\Manual.htm %2\Misc\Manual.htm +copy /Y/A %1\tests\cmtest\user\cmtest_main.c %2\Misc\cmtest.c + +rem copy 'Driver Install Frameworks for Applications' files so WIX makefiles +rem are not required to know the current WDK version/path. + +for %%i in ( amd64 ia64 x86 ) do ( + mkdir %2\Misc\%%i + if ERRORLEVEL 1 ( + echo ERR on mkdir %2\Misc\DIFxAPP\%%i + exit /B 1 + ) + for %%j in ( DIFxApp.dll DIFxAppA.dll DIFxApp.wixlib ) do ( + copy /B/Y %DIFXP%\%%i\%%j %2\Misc\%%i\%%j + if ERRORLEVEL 1 ( + echo ERR on copy /B/Y %DIFXP%\%%i\%%j %2\Misc\%%i\%%j + exit /B 1 + ) + ) + copy /B/Y %DPINST%\%%i\DPInst.exe %2\Misc\%%i\DPInst.exe + if ERRORLEVEL 1 ( + echo ERR on copy /B/Y %DPINST%\%%i\DPInst.exe %2\Misc\%%i\DPInst.exe + exit /B 1 + ) +) + +rem setup Checked Drivers & Symbols for signing and installation. +if "%DBG%" == "TRUE" echo %3 Checked Drivers+symbols + +if NOT exist %2\Chk ( + mkdir %2\Chk + if ERRORLEVEL 1 ( + echo "failed[%ERRORLEVEL%] mkdir %2\Chk ?" + exit /B 1 + ) +) + +echo "Copy Checked drivers {HCA,net,storage} to %2\Chk" + +rem copy free drivers to get directory structure plus signing files. +rem Overwrite .sys & .pdb files with checked versions. + +for %%i in ( HCA net storage ) do ( + xcopy %2\%%i %2\Chk\%%i\ /S /Y /Q + if ERRORLEVEL 1 ( + echo ERR on xcopy %2\%%i %2\Chk /syq + exit /B 1 + ) +) + +echo "Copy Checked drivers {ibbus,mthca,mlx} to %2\Chk\HCA\%ARCH_MS%" +set B=%2\bin\kernel\objchk_%3 + +for %%i in ( ibbus mthca ibiou mlx4_hca mlx4_bus ) do ( + if exist %B%_amd64\amd64\%%i.sys ( + copy /B/Y %B%_amd64\amd64\%%i.sys %2\Chk\HCA\amd64\%%i.sys + copy /B/Y %B%_amd64\amd64\%%i.pdb %2\Chk\HCA\amd64\%%i.pdb + ) + + if exist %B%_ia64\ia64\%%i.sys ( + copy /B/Y %B%_ia64\ia64\%%i.sys %2\Chk\HCA\ia64\%%i.sys + copy /B/Y %B%_ia64\ia64\%%i.pdb %2\Chk\HCA\ia64\%%i.pdb + ) + if exist %B%_x86\i386\%%i.sys ( + copy /B/Y %B%_x86\i386\%%i.sys %2\Chk\HCA\x86\%%i.sys + copy /B/Y %B%_x86\i386\%%i.pdb %2\Chk\HCA\x86\%%i.pdb + ) +) + +echo "Copy Checked drivers {ipoib,qlgcvnic} to %2\Chk\net\%ARCH_MS%" +for %%i in ( ipoib qlgcvnic ) do ( + if exist %B%_amd64\amd64\%%i.sys ( + copy /B/Y %B%_amd64\amd64\%%i.sys %2\Chk\net\amd64\%%i.sys + copy /B/Y %B%_amd64\amd64\%%i.pdb %2\Chk\net\amd64\%%i.pdb + ) + if exist %B%_ia64\ia64\%%i.sys ( + copy /B/Y %B%_ia64\ia64\%%i.sys %2\Chk\net\ia64\%%i.sys + copy /B/Y %B%_ia64\ia64\%%i.pdb %2\Chk\net\ia64\%%i.pdb + ) + if exist %B%_x86\i386\%%i.sys ( + copy /B/Y %B%_x86\i386\%%i.sys %2\Chk\net\x86\%%i.sys + copy /B/Y %B%_x86\i386\%%i.pdb %2\Chk\net\x86\%%i.pdb + ) +) + +echo "Copy Checked drivers {ibsrp} to %2\Chk\storage\%ARCH_MS%" +for %%i in ( ibsrp ) do ( + if exist %B%_amd64\amd64\%%i.sys ( + copy /B/Y %B%_amd64\amd64\%%i.sys %2\Chk\storage\amd64\%%i.sys + copy /B/Y %B%_amd64\amd64\%%i.pdb %2\Chk\storage\amd64\%%i.pdb + ) + if exist %B%_ia64\ia64\%%i.sys ( + copy /B/Y %B%_ia64\ia64\%%i.sys %2\Chk\storage\ia64\%%i.sys + copy /B/Y %B%_ia64\ia64\%%i.pdb %2\Chk\storage\ia64\%%i.pdb + ) + if exist %B%_x86\i386\%%i.sys ( + copy /B/Y %B%_x86\i386\%%i.sys %2\Chk\storage\x86\%%i.sys + copy /B/Y %B%_x86\i386\%%i.pdb %2\Chk\storage\x86\%%i.pdb + ) +) + +goto end + +:usage +echo makebin src dest os +echo src base directory. +echo dest directory in which to build the installable binary tree. +echo os Windows version [wlh, wnet, wxp] +goto end + +:error1 +echo %1\bin\kernel\objfre_%OSE%_amd64\amd64 missing +goto end +:error2 +echo %1\bin\kernel\objfre_%OSE%_ia64\ia64 missing +goto end +:error3 +echo %1\bin\kernel\objfre_%OSE%_x86\i386 missing +goto end +:error4 +echo %1\bin\user\objfre_%OSE%_amd64\amd64 missing +goto end +:error5 +echo %6\bin\user\objfre_%OSE%_ia64\ia64 missing +goto end +:error6 +echo %1\bin\user\objfre_%OSE%_x86\i386 missing +goto end +:error7 +echo %1\bin\user\objchk_%OSE%_amd64\amd64 missing +goto end +:error8 +echo %1\bin\user\objchk_%OSE%_ia64\ia64 missing +goto end +:error9 +echo %1\bin\user\objchk_%OSE%_x86\i386 missing + +:end +echo. +echo Finished OS %3 +echo. + +endlocal diff --git a/branches/WOF2-3/etc/nomerge.txt b/branches/WOF2-3/etc/nomerge.txt new file mode 100644 index 00000000..d3540e6f --- /dev/null +++ b/branches/WOF2-3/etc/nomerge.txt @@ -0,0 +1 @@ +.inf \ No newline at end of file diff --git a/branches/WOF2-3/etc/pkgwo.bat b/branches/WOF2-3/etc/pkgwo.bat new file mode 100644 index 00000000..062a6ab3 --- /dev/null +++ b/branches/WOF2-3/etc/pkgwo.bat @@ -0,0 +1,206 @@ +@echo off +setlocal +setlocal enabledelayedexpansion + +if "%WDK_PATH%"=="" goto use +if "%OPENIB_REV%"=="" goto use +if "%PLATFORM_SDK_PATH%"=="" goto use + +if "%1"=="chk" ( + set wo_bld=chk + goto set_arch +) +if "%1"=="fre" ( + set wo_bld=fre + goto set_arch +) +goto use + +:set_arch +if "%2"=="x86" ( + set wo_arch=x86 + set wo_arch_dir=i386 + goto set_os +) +if "%2"=="x64" ( + set wo_arch=amd64 + set wo_arch_dir=amd64 + goto set_os +) +if "%2"=="ia64" ( + set wo_arch=ia64 + set wo_arch_dir=ia64 + goto set_os +) +goto use + +:set_os +if "%3"=="win7" ( + set wo_os=win7 + goto set_files +) +if "%3"=="2003" ( + set wo_os=wnet + goto set_files +) +if "%3"=="2008" ( + set wo_os=WLH + goto set_files +) +if "%3"=="xp" ( + if not "%2"=="x86" goto use + set wo_os=WXP + set wo_arch= + goto set_files +) +goto use + +:set_files +if "%4"=="all" ( + for %%i in (dapl, ibacm, ibbus, ipoib, mlx4_bus, mlx4_hca, mthca, winmad, winverbs) do ( + call %~dp0\pkgwo %1 %2 %3 %%i + ) + popd + goto end +) +if "%4"=="dapl" ( + set files=dapl dat dtest + goto package +) +if "%4"=="ibacm" ( + set files=ib_acm libibacm + goto package +) +if "%4"=="ibbus" ( + set files=ib_bus ibbus ibal alts cmtest complib ib_read ib_send ib_write ib_limit + goto package +) +if "%4"=="ipoib" ( + set files=ipoib nd ibwsd netipoib wvnd ibat ibnd + goto package +) +if "%4"=="mlx4_bus" ( + set files=mlx4_bus mlx4_core + goto package +) +if "%4"=="mlx4_hca" ( + set files=mlx4_hca mlx4u mlx4_ib mlx4_net + goto package +) +if "%4"=="mthca" ( + set files=mthca + goto package +) +if "%4"=="winmad" ( + rem -- Includes IB-mgmt libraries + set files=winmad wm ^ + libibumad libibmad libibnet ibaddr iblinkinfo ibnetdiscover ibping ^ + ibportstate ibqueryerror ibroute ibsendtrap ibstat ^ + ibsysstat ibtracert mcm_rereg perfquery saquery sminfo smp vendstat ^ + opensm osmtest ibtrapgen + goto package +) +if "%4"=="winverbs" ( + rem -- Includes OFED verbs and RDMA CM compatability libraries + set files=winverb wv ^ + libibverbs ibv_async ibv_dev ibv_ librdmacm rdma_ + goto package +) +goto use + +:package +pushd %WINOF_PATH% +if not exist install mkdir install +if not exist install\%3 mkdir install\%3 +if not exist install\%3\%2 mkdir install\%3\%2 +if not exist install\%3\%2\%1 mkdir install\%3\%2\%1 +if not exist install\%3\%2\%1\%4 mkdir install\%3\%2\%1\%4 + +for %%i in (%files%) do ( + xcopy /D /Y bin\kernel\obj%wo_bld%_%wo_os%_%wo_arch%\%wo_arch_dir%\%%i* install\%3\%2\%1\%4 + xcopy /D /Y bin\user\obj%wo_bld%_%wo_os%_%wo_arch%\%wo_arch_dir%\%%i* install\%3\%2\%1\%4 + + rem -- Include both free and checked versions of libraries in the package. + rem -- The library names do not overlap. + if "%1"=="chk" ( + xcopy /D /Y bin\user\objfre_%wo_os%_%wo_arch%\%wo_arch_dir%\%%i*.dll install\%3\%2\%1\%4 + xcopy /D /Y bin\user\objfre_%wo_os%_%wo_arch%\%wo_arch_dir%\%%i*.pdb install\%3\%2\%1\%4 + xcopy /D /Y bin\user\objfre_%wo_os%_%wo_arch%\%wo_arch_dir%\%%i*.exp install\%3\%2\%1\%4 + xcopy /D /Y bin\user\objfre_%wo_os%_%wo_arch%\%wo_arch_dir%\%%i*.lib install\%3\%2\%1\%4 + ) + if "%1"=="fre" ( + xcopy /D /Y bin\user\objchk_%wo_os%_%wo_arch%\%wo_arch_dir%\%%i*.dll install\%3\%2\%1\%4 + xcopy /D /Y bin\user\objchk_%wo_os%_%wo_arch%\%wo_arch_dir%\%%i*.pdb install\%3\%2\%1\%4 + xcopy /D /Y bin\user\objchk_%wo_os%_%wo_arch%\%wo_arch_dir%\%%i*.exp install\%3\%2\%1\%4 + xcopy /D /Y bin\user\objchk_%wo_os%_%wo_arch%\%wo_arch_dir%\%%i*.lib install\%3\%2\%1\%4 + ) + + rem -- Include 32-bit libaries with the 64-bit package. Rename the 32-bit + rem -- libraries from lib.dll -> lib32.dll or libd.dll -> lib32d.dll. + rem -- complib, which changes to cl32 + rem -- mthca, which drops the 'u' + if "%2"=="x64" ( + if not exist install\wow64\%3\%2\chk\%4 mkdir install\wow64\%3\%2\chk\%4 + xcopy /D /Y bin\user\objchk_%wo_os%_x86\i386\%%i*.dll install\wow64\%3\%2\chk\%4 + pushd install\wow64\%3\%2\chk\%4 + for /f "usebackq" %%j in (`dir /b *d.dll`) do ( + set dll32_old=%%j + set dll32_new=!dll32_old:~,-5!32d.dll + if "!dll32_old!"=="complibd.dll" set dll32_new=cl32d.dll + if "!dll32_old!"=="mthcaud.dll" set dll32_new=mthca32d.dll + echo F | xcopy /D /Y !dll32_old! %WINOF_PATH%\install\%3\%2\%1\%4\!dll32_new! + ) + popd + + if not exist install\wow64\%3\%2\fre\%4 mkdir install\wow64\%3\%2\fre\%4 + xcopy /D /Y bin\user\objfre_%wo_os%_x86\i386\%%i*.dll install\wow64\%3\%2\fre\%4 + pushd install\wow64\%3\%2\fre\%4 + for /f "usebackq" %%j in (`dir /b *.dll`) do ( + set dll32_old=%%j + set dll32_new=!dll32_old:~,-4!32.dll + if "!dll32_old!"=="complib.dll" set dll32_new=cl32.dll + if "!dll32_old!"=="mthcau.dll" set dll32_new=mthca32.dll + echo F | xcopy /D /Y !dll32_old! %WINOF_PATH%\install\%3\%2\%1\%4\!dll32_new! + ) + popd + ) + + xcopy /D /Y %WDK_PATH%\redist\wdf\%wo_arch_dir%\wdf* install\%3\%2\%1\%4 + xcopy /D /Y %WDK_PATH%\redist\difx\dpinst\multilin\%wo_arch_dir%\dpinst* install\%3\%2\%1\%4 +) + +popd +goto end + +:use +echo - +echo pkgwo - package winof +echo - +echo Separates a built WinOF tree into separate packages for installation. +echo You should build both the free and checked versions of the specified +echo package before running this batch file for the first time. +echo You must customize for your system by setting the following environment +echo variables: +echo - +echo WDK_PATH (example set WDK_PATH=c:\winddk\6001.18001) +echo WINOF_PATH (example set WINOF_PATH=c:\ofw\trunk) +echo OPENIB_REV (example set OPENIB_REV=0) +echo PLATFORM_SDK_PATH (example set PLATFORM_SDK_PATH=c:\progra~1\mi2578~1) +echo - +echo Use: +echo pkgwo {chk : fre} {x86 : x64 : ia64} {xp : 2003 : 2008 : win7} {package} +echo xp only supports x86 build +echo - +echo Valid package names are: +echo all, dapl, ibacm, ibbus, ipoib, mlx4_bus, mlx4_hca, mthca, winmad, winverbs +echo - +echo Examples: +echo pkgwo chk x86 2008 winverbs - packages 2008 checked x86 files for winverbs +echo pkgwo fre x64 win7 mlx4_bus - packages windows 7 free x64 files for mlx4_bus +echo - +echo Packages are created under WINOF_PATH\install. +echo See docs\build.txt for additional information on building the tree. + +:end +endlocal +@echo on diff --git a/branches/WOF2-3/etc/pkgwoall.bat b/branches/WOF2-3/etc/pkgwoall.bat new file mode 100644 index 00000000..615985bd --- /dev/null +++ b/branches/WOF2-3/etc/pkgwoall.bat @@ -0,0 +1,19 @@ +@echo off +rem +rem Packages the winof stack for all platforms. +rem + +call %~dp0\pkgwo chk x86 2003 all +call %~dp0\pkgwo fre x86 2003 all +call %~dp0\pkgwo chk x64 2003 all +call %~dp0\pkgwo fre x64 2003 all +call %~dp0\pkgwo chk ia64 2003 all +call %~dp0\pkgwo fre ia64 2003 all +call %~dp0\pkgwo chk x86 2008 all +call %~dp0\pkgwo fre x86 2008 all +call %~dp0\pkgwo chk x64 2008 all +call %~dp0\pkgwo fre x64 2008 all +call %~dp0\pkgwo chk ia64 2008 all +call %~dp0\pkgwo fre ia64 2008 all + +@echo on diff --git a/branches/WOF2-3/etc/signall.bat b/branches/WOF2-3/etc/signall.bat new file mode 100644 index 00000000..d510edaf --- /dev/null +++ b/branches/WOF2-3/etc/signall.bat @@ -0,0 +1,11 @@ +@echo off +setlocal + +for /f "usebackq" %%i in (`dir /AD /b`) do ( + inf2cat /driver:%%i /os:server2008_x64,server2008r2_x64 + pushd %%i + call signwo + popd +) + +@echo on \ No newline at end of file diff --git a/branches/WOF2-3/etc/signwo.bat b/branches/WOF2-3/etc/signwo.bat new file mode 100644 index 00000000..81bec89f --- /dev/null +++ b/branches/WOF2-3/etc/signwo.bat @@ -0,0 +1,6 @@ +signtool.exe sign /s WinOFCertStore /n WinOFCert /t http://timestamp.verisign.com/scripts/timestamp.dll *.sys +signtool.exe sign /s WinOFCertStore /n WinOFCert /t http://timestamp.verisign.com/scripts/timestamp.dll *.dll +signtool.exe sign /s WinOFCertStore /n WinOFCert /t http://timestamp.verisign.com/scripts/timestamp.dll *.exe +signtool.exe sign /s WinOFCertStore /n WinOFCert /t http://timestamp.verisign.com/scripts/timestamp.dll *.cat + +signtool.exe verify /pa /v *.cat diff --git a/branches/WOF2-3/etc/user/comp_channel.cpp b/branches/WOF2-3/etc/user/comp_channel.cpp new file mode 100644 index 00000000..4f7e9570 --- /dev/null +++ b/branches/WOF2-3/etc/user/comp_channel.cpp @@ -0,0 +1,325 @@ +/* + * Copyright (c) 2008, 2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include + +static void CompChannelQueue(COMP_CHANNEL *pChannel, COMP_ENTRY *pEntry); + + +/* + * Completion manager + */ + +static unsigned __stdcall CompThreadPoll(void *Context) +{ + COMP_MANAGER *mgr = (COMP_MANAGER *) Context; + COMP_ENTRY *entry; + OVERLAPPED *overlap; + DWORD bytes; + ULONG_PTR key; + + while (mgr->Run) { + GetQueuedCompletionStatus(mgr->CompQueue, &bytes, &key, + &overlap, INFINITE); + entry = CONTAINING_RECORD(overlap, COMP_ENTRY, Overlap); + if (entry->Channel != NULL) { + CompChannelQueue(entry->Channel, entry); + } + } + + _endthreadex(0); + return 0; +} + +DWORD CompManagerOpen(COMP_MANAGER *pMgr) +{ + DWORD ret; + + pMgr->CompQueue = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, -1); + if (pMgr->CompQueue == NULL) { + return GetLastError(); + } + + pMgr->Run = TRUE; + pMgr->Thread = (HANDLE) _beginthreadex(NULL, 0, CompThreadPoll, pMgr, 0, NULL); + if (pMgr->Thread == NULL) { + ret = GetLastError(); + goto err; + } + return 0; + +err: + CloseHandle(pMgr->CompQueue); + return ret; +} + +void CompManagerClose(COMP_MANAGER *pMgr) +{ + COMP_CHANNEL *channel; + COMP_ENTRY entry; + + pMgr->Run = FALSE; + CompEntryInit(NULL, &entry); + PostQueuedCompletionStatus(pMgr->CompQueue, 0, (ULONG_PTR) pMgr, &entry.Overlap); + WaitForSingleObject(pMgr->Thread, INFINITE); + CloseHandle(pMgr->Thread); + + CloseHandle(pMgr->CompQueue); +} + +DWORD CompManagerMonitor(COMP_MANAGER *pMgr, HANDLE hFile, ULONG_PTR Key) +{ + HANDLE cq; + + cq = CreateIoCompletionPort(hFile, pMgr->CompQueue, Key, 0); + return (cq == NULL) ? GetLastError() : 0; +} + + +/* + * Completion channel sets + */ + +DWORD CompSetInit(COMP_SET *pSet) +{ + pSet->Head = NULL; + pSet->TailPtr = &pSet->Head; + + pSet->Event = CreateEvent(NULL, TRUE, FALSE, NULL); + if (pSet->Event == NULL) { + return GetLastError(); + } + + return 0; +} + +void CompSetCleanup(COMP_SET *pSet) +{ + CloseHandle(pSet->Event); +} + +void CompSetZero(COMP_SET *pSet) +{ + pSet->Head = NULL; + pSet->TailPtr = &pSet->Head; + ResetEvent(pSet->Event); +} + +void CompSetAdd(COMP_CHANNEL *pChannel, COMP_SET *pSet) +{ + *pSet->TailPtr = pChannel; + pSet->TailPtr = &pChannel->Next; + + EnterCriticalSection(&pChannel->Lock); + pChannel->Set = pSet; + if (pChannel->Head != NULL) { + SetEvent(pSet->Event); + } + LeaveCriticalSection(&pChannel->Lock); +} + +DWORD CompSetPoll(COMP_SET *pSet, DWORD Milliseconds) +{ + DLIST_ENTRY *entry; + COMP_CHANNEL *channel; + DWORD ret, cnt = 0; + + *pSet->TailPtr = NULL; + ret = WaitForSingleObject(pSet->Event, Milliseconds); + if (ret == WAIT_TIMEOUT) { + ret = 0; + } + + for (channel = pSet->Head; channel != NULL; channel = channel->Next) { + EnterCriticalSection(&channel->Lock); + channel->Set = NULL; + cnt += (channel->Head != NULL); + LeaveCriticalSection(&channel->Lock); + } + + return cnt ? cnt : ret; +} + +void CompSetCancel(COMP_SET *pSet) +{ + SetEvent(pSet->Event); +} + + +/* + * Completion channel + */ + +DWORD CompChannelInit(COMP_MANAGER *pMgr, COMP_CHANNEL *pChannel, DWORD Milliseconds) +{ + pChannel->Manager = pMgr; + pChannel->Next = NULL; + pChannel->Set = NULL; + pChannel->Head = NULL; + pChannel->TailPtr = &pChannel->Head; + pChannel->Milliseconds = Milliseconds; + + pChannel->Event = CreateEvent(NULL, TRUE, TRUE, NULL); + if (pChannel->Event == NULL) { + return GetLastError(); + } + + InitializeCriticalSection(&pChannel->Lock); + CompEntryInit(pChannel, &pChannel->Entry); + return 0; +} + +void CompChannelCleanup(COMP_CHANNEL *pChannel) +{ + CloseHandle(pChannel->Event); + DeleteCriticalSection(&pChannel->Lock); +} + +static void CompChannelInsertTail(COMP_CHANNEL *pChannel, COMP_ENTRY *pEntry) +{ + *pChannel->TailPtr = pEntry; + pChannel->TailPtr = &pEntry->Next; + pEntry->Next = NULL; +} + +static COMP_ENTRY *CompChannelRemoveHead(COMP_CHANNEL *pChannel) +{ + COMP_ENTRY *entry; + + entry = pChannel->Head; + pChannel->Head = entry->Next; + if (pChannel->Head == NULL) { + pChannel->TailPtr = &pChannel->Head; + } + return entry; +} + +static COMP_ENTRY *CompChannelFindRemove(COMP_CHANNEL *pChannel, COMP_ENTRY *pEntry) +{ + COMP_ENTRY **entry_ptr, *entry; + + EnterCriticalSection(&pChannel->Lock); + entry_ptr = &pChannel->Head; + while (*entry_ptr && *entry_ptr != pEntry) { + entry_ptr = &(*entry_ptr)->Next; + } + + entry = *entry_ptr; + if (entry != NULL) { + *entry_ptr = pEntry->Next; + if (pChannel->TailPtr == &pEntry->Next) { + pChannel->TailPtr = entry_ptr; + } + InterlockedExchange(&pEntry->Busy, 0); + } + LeaveCriticalSection(&pChannel->Lock); + return entry; +} + +static void CompChannelQueue(COMP_CHANNEL *pChannel, COMP_ENTRY *pEntry) +{ + pEntry->Next = NULL; + EnterCriticalSection(&pChannel->Lock); + CompChannelInsertTail(pChannel, pEntry); + SetEvent(pChannel->Event); + if (pChannel->Set != NULL) { + SetEvent(pChannel->Set->Event); + } + LeaveCriticalSection(&pChannel->Lock); +} + +DWORD CompChannelPoll(COMP_CHANNEL *pChannel, COMP_ENTRY **ppEntry) +{ + COMP_ENTRY *entry; + DWORD ret; + + EnterCriticalSection(&pChannel->Lock); + while (pChannel->Head == NULL) { + ResetEvent(pChannel->Event); + LeaveCriticalSection(&pChannel->Lock); + + ret = WaitForSingleObject(pChannel->Event, pChannel->Milliseconds); + if (ret) { + return ret; + } + + EnterCriticalSection(&pChannel->Lock); + } + entry = CompChannelRemoveHead(pChannel); + LeaveCriticalSection(&pChannel->Lock); + + InterlockedExchange(&entry->Busy, 0); + *ppEntry = entry; + ret = (entry == &pChannel->Entry) ? ERROR_CANCELLED : 0; + + return ret; +} + +void CompChannelCancel(COMP_CHANNEL *pChannel) +{ + if (InterlockedCompareExchange(&pChannel->Entry.Busy, 1, 0) == 0) { + PostQueuedCompletionStatus(pChannel->Manager->CompQueue, 0, + (ULONG_PTR) pChannel, &pChannel->Entry.Overlap); + } +} + + +/* + * Completion entry + */ + +void CompEntryInit(COMP_CHANNEL *pChannel, COMP_ENTRY *pEntry) +{ + RtlZeroMemory(pEntry, sizeof *pEntry); + pEntry->Channel = pChannel; +} + +DWORD CompEntryPost(COMP_ENTRY *pEntry) +{ + if (InterlockedCompareExchange(&pEntry->Busy, 1, 0) == 0) { + if (!PostQueuedCompletionStatus(pEntry->Channel->Manager->CompQueue, + 0, 0, &pEntry->Overlap)) { + InterlockedExchange(&pEntry->Busy, 0); + return GetLastError(); + } + } + return 0; +} + +COMP_ENTRY *CompEntryCancel(COMP_ENTRY *pEntry) +{ + COMP_ENTRY *entry = NULL; + + while (pEntry->Busy) { + Sleep(0); + entry = CompChannelFindRemove(pEntry->Channel, pEntry); + } + return entry; +} diff --git a/branches/WOF2-3/etc/user/getopt.c b/branches/WOF2-3/etc/user/getopt.c new file mode 100644 index 00000000..2718181f --- /dev/null +++ b/branches/WOF2-3/etc/user/getopt.c @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include + +#include "getopt.h" + +char *optarg; +int optind = 1; +int opterr = 1; +int optopt = '?'; + +int getopt(int argc, char * const argv[], char const *opts) +{ + char *loc; + + optarg = NULL; + + if (optind == 0) { + optind = opterr = 1; + optopt = '?'; + } + + if (optind >= argc) { + return EOF; + } + + if (argv[optind][0] != '-' && argv[optind][0] != '/') { + return EOF; + } + + if (!strcmp(argv[optind], "--")) { + optind++; + return '?'; + } + + optopt = argv[optind][1]; + + loc = strchr(opts, optopt); + if (loc == NULL) { + return '?'; + } + + if (loc[1] != ':') { + goto out; + } + + /* process switch argument */ + if (argv[optind][2] != '\0') { + optarg = &argv[optind][2]; + goto out; + } + + /* switch argument is optional (::) - be careful */ + if (loc[2] == ':' ) { + if ((argv[optind+1] == NULL)) { + /* handle EOL without optional arg */ + optarg = NULL; + goto out; + } + if (argv[optind+1] && (argv[optind+1][0] == '-' || argv[optind+1][0] == '/')) + goto out; + } + + optarg = argv[++optind]; + if (!optarg || !(*optarg)) { + return '?'; + } + +out: + optind++; + return optopt; +} + +int getopt_long(int argc, char * const argv[], char const *opts, + const struct option *longopts, int *longindex) +{ + char arg[256]; + char *str; + int i; + + if (optind == 0) { + optarg = NULL; + optind = opterr = 1; + optopt = '?'; + } + + if (optind == argc) { + return EOF; + } + + if (argv[optind][0] != '-' && argv[optind][0] != '/') { + return EOF; + } + + if (!strcmp(argv[optind], "--")) { + optind++; + return '?'; + } + + if (argv[optind][1] != '-') { + return getopt(argc, argv, opts); + } + + strcpy(arg, &argv[optind][2]); + str = strtok(arg, "="); + + for (i = 0; longopts[i].name; i++) { + + if (strcmp(str, longopts[i].name)) { + continue; + } + + if (longindex != NULL) { + *longindex = i; + } + + if (longopts[i].flag != NULL) { + *(longopts[i].flag) = longopts[i].val; + } + + switch (longopts[i].has_arg) { + case required_argument: + optarg = strtok(NULL, "="); + if (optarg != NULL) { + break; + } + + if (++optind == argc || argv[optind][0] == '-') { + return '?'; + } + + optarg = argv[optind]; + break; + case optional_argument: + optarg = strtok(NULL, "="); + if (optarg != NULL) { + break; + } + + if (optind + 1 == argc || argv[optind + 1][0] == '-') { + break; + } + + optarg = argv[++optind]; + break; + default: + break; + } + + optind++; + if (longopts[i].flag == 0) { + return (longopts[i].val); + } else { + return 0; + } + } + return '?'; +} diff --git a/branches/WOF2-3/etc/user/gtod.c b/branches/WOF2-3/etc/user/gtod.c new file mode 100644 index 00000000..b6ea6a92 --- /dev/null +++ b/branches/WOF2-3/etc/user/gtod.c @@ -0,0 +1,138 @@ +/* + * This software is available to you under the OpenFabrics.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION 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 _GTOD_C_ +#define _GTOD_C_ + +/* + * int gettimeofday(struct timeval *ptv, void *ignored) + */ + +#include +#include + + +static __inline +void FileTimeToTimeval(LPFILETIME pft, struct timeval * ptv) +{ /* Note that LONGLONG is a 64-bit value */ + LONGLONG ll; + + if(!pft || !ptv) { + ptv->tv_sec = 0; + ptv->tv_usec = 0; + return; + } + + ll = ((LONGLONG) pft->dwHighDateTime << 32); + ll += (LONGLONG) pft->dwLowDateTime; + ll -= 116444736000000000; + + ptv->tv_sec = (long) (ll / 10000000); + ptv->tv_usec = (long) (ll - ((LONGLONG)(ptv->tv_sec) * 10000000)) / 10; +} + + +// static __inline +int gettimeofday(struct timeval *ptv, void *ignored) +{ + static int QueryCounter = 2; + FILETIME CurrentTime; + UNREFERENCED_PARAMETER(ignored); + + if(!ptv) return -1; + + if(QueryCounter) + { + static LARGE_INTEGER Frequency; + static LARGE_INTEGER Offset; /* counter offset for right time*/ + static LARGE_INTEGER LastCounter; + LARGE_INTEGER Time; + LARGE_INTEGER Counter; + + GetSystemTimeAsFileTime(&CurrentTime); + QueryPerformanceCounter(&Counter); + + if(QueryCounter == 2) + { + QueryCounter = 1; + if(!QueryPerformanceFrequency(&Frequency)) + { + QueryCounter = 0; + Frequency.QuadPart = 10000000; /* prevent division by 0 */ + } + + /* get time as a large integer */ + Counter.HighPart &= 0x7FL; /* Clear high bits to prevent overflow */ + Offset.LowPart = CurrentTime.dwLowDateTime; + Offset.HighPart = (LONG) CurrentTime.dwHighDateTime; + Offset.QuadPart -= Counter.QuadPart * 10000000 / Frequency.QuadPart; + } + + /* Convert counter to a 100 nanoseconds resolution timer value. */ + + Counter.HighPart &= 0x7FL; /* Clear high bits to prevent overflows */ + Counter.QuadPart *= 10000000; /* need time stamp in 100 ns units */ + Counter.QuadPart /= Frequency.QuadPart;/* counter of 0.1 microseconds */ + + if(LastCounter.QuadPart > Counter.QuadPart) + { /* Counter value wrapped */ + Offset.QuadPart += (0x7F00000000*10000000) / Frequency.QuadPart; + } + LastCounter = Counter; + + /* Add the in previous call calculated offset */ + Counter.QuadPart += Offset.QuadPart; + + /* get time as a large integer */ + Time.LowPart = CurrentTime.dwLowDateTime; + Time.HighPart = (LONG) CurrentTime.dwHighDateTime; + + /* keep time difference within an interval of +- 0.1 seconds + relative to the time function by adjusting the counters offset */ + + if( ((Time.QuadPart + 1000000) < Counter.QuadPart) || + ((Time.QuadPart - 1000000) > Counter.QuadPart) ) + { /* Adjust the offset */ + Offset.QuadPart += Time.QuadPart - Counter.QuadPart; + Counter.QuadPart = Time.QuadPart; + } + + /* use the adjusted performance counter time for the time stamp */ + CurrentTime.dwLowDateTime = Counter.LowPart; + CurrentTime.dwHighDateTime = Counter.HighPart; + } + else + { + GetSystemTimeAsFileTime(&CurrentTime); + } + + FileTimeToTimeval(&CurrentTime,ptv); + + return(0); +} + +#endif /* _GTOD_C_ */ diff --git a/branches/WOF2-3/etc/user/inet.c b/branches/WOF2-3/etc/user/inet.c new file mode 100644 index 00000000..28df6a07 --- /dev/null +++ b/branches/WOF2-3/etc/user/inet.c @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2009 Intel Corp., Inc. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#include +#include +#include + +static int inet_pton4(const char *src, struct in_addr *addr) +{ + unsigned long ip; + + ip = inet_addr(src); + if (ip == INADDR_NONE) + return 0; + + addr->S_un.S_addr = ip; + return 1; +} + +enum in6_addr_format_state +{ + in6_fs_num, + in6_fs_colon, + in6_fs_0_colon, + in6_fs_0_num +}; + +static int inet_check_groups(const char *src) +{ + int i; + int digits = 0, groups = 0; + enum in6_addr_format_state state; + + if (src[0] == ':') { + if (src[1] == ':') { + i = 2; + state = in6_fs_0_colon; + } else { + return -1; + } + } else { + i = 0; + state = in6_fs_num; + } + + for (; src[i] != '\0'; i++) { + if (src[i] == ':') { + + switch (state) { + case in6_fs_num: + state = in6_fs_colon; + break; + case in6_fs_colon: + case in6_fs_0_num: + state = in6_fs_0_colon; + break; + default: + return -1; + } + digits = 0; + + } else if (isxdigit(src[i]) && digits++ < 4) { + + switch (state) { + case in6_fs_colon: + state = in6_fs_num; + groups++; + break; + case in6_fs_0_colon: + state = in6_fs_0_num; + groups++; + break; + default: + break; + } + } else { + return -1; + } + } + + if (groups > 8 || state == in6_fs_colon) + return -1; + + return groups; +} + +/* + * We don't handle the format x:x:x:x:x:x:d.d.d.d + */ +static int inet_pton6(const char *src, struct in6_addr *addr) +{ + const char *pos; + int i, skip; + + skip = 8 - inet_check_groups(src); + if (skip > 8) + return -1; + + memset(addr, 0, sizeof(*addr)); + if (src[0] == ':') { + pos = src + 2; + i = skip; + } else { + pos = src; + i = 0; + } + + for (; i < 8; i++) { + addr->u.Word[i] = htons((u_short) strtoul(pos, (char **) &pos, 16)); + pos++; + if (*pos == ':') { + pos++; + i += skip; + } + } + + return 1; +} + +#if WINVER < 0x600 +int inet_pton(int af, const char *src, void *dst) +{ + switch (af) { + case AF_INET: + return inet_pton4(src, (struct in_addr *) dst); + case AF_INET6: + return inet_pton6(src, (struct in6_addr *) dst); + default: + return -1; + } +} +#endif + +static const char *inet_ntop4(const void *src, char *dst, socklen_t cnt) +{ + struct sockaddr_in in; + + in.sin_family = AF_INET; + memcpy(&in.sin_addr, src, 4); + if (getnameinfo((struct sockaddr *) &in, + (socklen_t) sizeof(struct sockaddr_in), + dst, cnt, NULL, 0, NI_NUMERICHOST)) + return NULL; + + return dst; +} + +static const char *inet_ntop6(const void *src, char *dst, socklen_t cnt) +{ + struct sockaddr_in6 in6; + char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"]; + int i, n = 0; + + memset(&in6, 0, sizeof in6); + in6.sin6_family = AF_INET6; + memcpy(&in6.sin6_addr, src, sizeof(struct in_addr6)); + + /* + * If no ipv6 support return simple IPv6 format rule: + * A series of "0's in a 16bit block can be represented by "0" + */ + if (getnameinfo((struct sockaddr *) &in6, (socklen_t) (sizeof in6), + dst, cnt, NULL, 0, NI_NUMERICHOST)) + { + + if (cnt < sizeof(tmp)) + return NULL; + + for (i = 0; i < 8; i++) + n += sprintf(tmp+n, "%s%x", i ? ":" : "", + ntohs(((unsigned short*) src)[i])); + tmp[n] = '\0'; + strcpy(dst, tmp); + } + return dst; +} + +#if WINVER < 0x600 +const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt) +{ + switch (af) { + case AF_INET: + return inet_ntop4(src, dst, cnt); + case AF_INET6: + return inet_ntop6(src, dst, cnt); + default: + return NULL; + } +} +#endif diff --git a/branches/WOF2-3/etc/user/search.c b/branches/WOF2-3/etc/user/search.c new file mode 100644 index 00000000..b2a2098e --- /dev/null +++ b/branches/WOF2-3/etc/user/search.c @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2009 Intel Corp., Inc. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#include +#include + +static int (*compare)(const void *, const void *); + +static intn_t fcompare(const void * const key1, const void * const key2) +{ + return (intn_t) compare((void *) key1, (void *) key2); +} + +void *tsearch(const void *key, void **rootp, + int (*compar)(const void *, const void *)) +{ + cl_fmap_item_t *item, *map_item; + + if (!*rootp) { + *rootp = malloc(sizeof(cl_fmap_t)); + if (!*rootp) + return NULL; + cl_fmap_init((cl_fmap_t *) *rootp, fcompare); + } + + compare = compar; + item = malloc(sizeof(cl_fmap_item_t)); + if (!item) + return NULL; + + map_item = cl_fmap_insert((cl_fmap_t *) *rootp, key, item); + if (map_item != item) + free(item); + + return (void *) &map_item->p_key; +} + +void *tfind(const void *key, void *const *rootp, + int (*compar)(const void *, const void *)) +{ + cl_fmap_item_t *item; + + if (!*rootp) + return NULL; + + compare = compar; + item = cl_fmap_get((cl_fmap_t *) *rootp, key); + if (item == cl_fmap_end((cl_fmap_t *) *rootp)) + return NULL; + + return (void *) &item->p_key; +} + +/* + * Returns NULL if item is not found, or the item itself. This differs + * from the tdelete call by not retuning the parent item, but works if + * the user is only checking against NULL. + */ +void *tdelete(const void *key, void **rootp, + int (*compar)(const void *, const void *)) +{ + cl_fmap_item_t *item; + void *map_key; + + if (!*rootp) + return NULL; + + compare = compar; + item = cl_fmap_remove((cl_fmap_t *) *rootp, key); + if (item == cl_fmap_end((cl_fmap_t *) *rootp)) + return NULL; + + map_key = (void *) item->p_key; + free(item); + return map_key; +} + +//void twalk(const void *root, +// void (*action)(const void *, VISIT, int)) +//{ +//} + +//void tdestroy(void *root, void (*free_node)(void *nodep)) +//{ +//} diff --git a/branches/WOF2-3/etc/wpp/ALTraceRt.cmd b/branches/WOF2-3/etc/wpp/ALTraceRt.cmd new file mode 100644 index 00000000..e3846f2a --- /dev/null +++ b/branches/WOF2-3/etc/wpp/ALTraceRt.cmd @@ -0,0 +1,14 @@ +rem level=32 => Highest 4 = information, 3 = warning + +tracepdb.exe -f ibal.pdb -p tmf +tracepdb.exe -f ibbus.pdb -p tmf + +set TRACE_FORMAT_PREFIX=%%7!08d! %%2!s!: %%8!04x!: + +tracelog -stop ALDetailedRt + +tracelog -start ALDetailedRt -ls -guid #B199CE55-F8BF-4147-B119-DACD1E5987A6 -flag 0x0f00 -level 5 -rt -ft 1 +tracelog -enable ALDetailedRt -guid #99DC84E3-B106-431e-88A6-4DD20C9BBDE3 -flag 0x0f00 -level 5 +tracefmt.exe -rt ALDetailedRt -Displayonly -p tmf -ods + +tracelog -stop ALDetailedRt diff --git a/branches/WOF2-3/etc/wpp/CreateTrace.cmd b/branches/WOF2-3/etc/wpp/CreateTrace.cmd new file mode 100644 index 00000000..91d05373 --- /dev/null +++ b/branches/WOF2-3/etc/wpp/CreateTrace.cmd @@ -0,0 +1,14 @@ +set DDK_HOME=\\tzachid0\c$\Winddk\3790.1830 + +rem if %PROCESSOR_ARCHITECTURE% == x86 (set ARCH_PATH=i386) else set ARCH_PATH=AMD64 +rem use same binaries for 32 and 64 bits +set ARCH_PATH=i386 + +mkdir %SystemDrive%\trace +copy %DDK_HOME%\tools\tracing\%ARCH_PATH%\*.exe %SystemDrive%\trace +copy %DDK_HOME%\tools\tracing\%ARCH_PATH%\*.dll %SystemDrive%\trace + +copy %DDK_HOME%\tools\tracing\i386\tracepdb.exe %SystemDrive%\trace + +copy %DDK_HOME%\bin\x86\mspdb70.dll %SystemDrive%\trace +copy %DDK_HOME%\bin\x86\msvcr70.dll %SystemDrive%\trace \ No newline at end of file diff --git a/branches/WOF2-3/etc/wpp/IPoIBTraceRt.cmd b/branches/WOF2-3/etc/wpp/IPoIBTraceRt.cmd new file mode 100644 index 00000000..b8fb78c8 --- /dev/null +++ b/branches/WOF2-3/etc/wpp/IPoIBTraceRt.cmd @@ -0,0 +1,13 @@ +rem level=32 => Highest 4 = information, 3 = warning + +tracepdb.exe -f ipoib.pdb -p tmf + + +set TRACE_FORMAT_PREFIX=%%7!08d! %%2!s!: %%8!04x!: + +tracelog -stop IPoIBdRt + +tracelog -start IPoIBdRt -ls -guid #3F9BC73D-EB03-453a-B27B-20F9A664211A -flag 0x0fff -level 5 -rt -ft 1 +tracefmt.exe -rt IPoIBdRt -Displayonly -p tmf -ods + +tracelog -stop IPoIBdRt diff --git a/branches/WOF2-3/etc/wpp/MTHCATraceRt.cmd b/branches/WOF2-3/etc/wpp/MTHCATraceRt.cmd new file mode 100644 index 00000000..f2e3fed4 --- /dev/null +++ b/branches/WOF2-3/etc/wpp/MTHCATraceRt.cmd @@ -0,0 +1,14 @@ +rem level=32 => Highest 4 = information, 3 = warning + +tracepdb.exe -f mthca.pdb -p tmf +tracepdb.exe -f mthcau.pdb -p tmf + +set TRACE_FORMAT_PREFIX=%%7!08d! %%2!s!: %%8!04x!: + +tracelog -stop MTHCALogdRt + +tracelog -start MTHCALogdRt -ls -guid #8BF1F640-63FE-4743-B9EF-FA38C695BFDE -flag 0x0f00 -level 5 -rt -ft 1 +tracelog -enable MTHCALogdRt -guid #2C718E52-0D36-4bda-9E58-0FC601818D8F -flag 0x0f00 -level 5 +tracefmt.exe -rt MTHCALogdRt -Displayonly -p tmf -ods + +tracelog -stop MTHCALogdRt diff --git a/branches/WOF2-3/etc/wpp/SDPTraceRt.cmd b/branches/WOF2-3/etc/wpp/SDPTraceRt.cmd new file mode 100644 index 00000000..78249dc9 --- /dev/null +++ b/branches/WOF2-3/etc/wpp/SDPTraceRt.cmd @@ -0,0 +1,10 @@ +rem level=32 => Highest 4 = information, 3 = warning + +tracelog -stop SdpDetailedRt + +tracelog -start SdpDetailedRt -ls -guid #D6FA8A24-9457-455d-9B49-3C1E5D195558 -flag 0xffff -level 4 -rt -ft 1 +tracelog -enable SdpDetailedRt -guid #2D4C03CC-E071-48e2-BDBD-526A0D69D6C9 -flag 0xffff -level 4 +tracefmt.exe -rt SdpDetailedRt -Displayonly -p tmf -ods + +tracelog -stop SdpDetailedRt + diff --git a/branches/WOF2-3/etc/wpp/StartSdpTrace.cmd b/branches/WOF2-3/etc/wpp/StartSdpTrace.cmd new file mode 100644 index 00000000..2f193ded --- /dev/null +++ b/branches/WOF2-3/etc/wpp/StartSdpTrace.cmd @@ -0,0 +1,7 @@ +rem level=32 => Highest 4 = information, 3 = warning + +tracelog -stop SdpDetailedRt + +tracelog -start SdpDetailedRt -ls -UseCPUCycle -guid #D6FA8A24-9457-455d-9B49-3C1E5D195558 -flag 0xffff -level 5 +tracelog -enable SdpDetailedRt -guid #2D4C03CC-E071-48e2-BDBD-526A0D69D6C9 -flag 0xffff -level 5 + diff --git a/branches/WOF2-3/etc/wpp/StartTrace.cmd b/branches/WOF2-3/etc/wpp/StartTrace.cmd new file mode 100644 index 00000000..0617de47 --- /dev/null +++ b/branches/WOF2-3/etc/wpp/StartTrace.cmd @@ -0,0 +1,22 @@ +rem MTHCA +del c:\WinIB1.etl +del c:\WinIB2.etl +tracelog -start MTHCALog -ls -guid #8BF1F640-63FE-4743-B9EF-FA38C695BFDE -flag 0x1 -level 2 -UseCPUCycle -f c:\WInIB1.etl +tracelog -enable MTHCALog -guid #2C718E52-0D36-4bda-9E58-0FC601818D8F -flag 0x1 -level 2 + + + +rem IBAL +tracelog -start IBALLog -ls -guid #B199CE55-F8BF-4147-B119-DACD1E5987A6 -flag 0x1 -level 2 -UseCPUCycle -f c:\WInIB2.etl +tracelog -enable IBALLog -guid #99DC84E3-B106-431e-88A6-4DD20C9BBDE3 -flag 0x1 -level 2 + + + +rem SDP +rem tracelog -start SDPLog -ls -guid #D6FA8A24-9457-455d-9B49-3C1E5D195558 -flag 0xffff -level 32 -UseCPUCycle +rem tracelog -enable SDPLOg -guid #2D4C03CC-E071-48e2-BDBD-526A0D69D6C9 -flag 0xffff -level 32 + +rem SDP +rem tracelog -start SDPLog -ls -guid #D6FA8A24-9457-455d-9B49-3C1E5D195558 -flag 0xffff -level 32 -UseCPUCycle +rem tracelog -enable SDPLOg -guid #2D4C03CC-E071-48e2-BDBD-526A0D69D6C9 -flag 0xffff -level 32 + diff --git a/branches/WOF2-3/etc/wpp/StopSdpTrace.cmd b/branches/WOF2-3/etc/wpp/StopSdpTrace.cmd new file mode 100644 index 00000000..81533e31 --- /dev/null +++ b/branches/WOF2-3/etc/wpp/StopSdpTrace.cmd @@ -0,0 +1,10 @@ +rem level=32 => Highest 4 = information, 3 = warning + +tracelog -stop SdpDetailedRt + +set TRACE_FORMAT_PREFIX=%%7!07d! %%2!s! %%8!04x!.%%3!04x!: %%4!s!: %%!COMPNAME! %%!FUNC! + + +tracefmt.exe -seq -p tmf C:\LogFile.Etl -nosummary -hires -o result.txt + + diff --git a/branches/WOF2-3/etc/wpp/StopTrace.cmd b/branches/WOF2-3/etc/wpp/StopTrace.cmd new file mode 100644 index 00000000..daf7ca5a --- /dev/null +++ b/branches/WOF2-3/etc/wpp/StopTrace.cmd @@ -0,0 +1,8 @@ +tracelog.exe -stop MTHCALog +tracelog.exe -stop IBALLog +rem tracelog.exe -stop SDPLOg + +set TRACE_FORMAT_PREFIX=%%7!08d! %%!LEVEL! %%2!s!: %%8!04x!.%%3!04x!: %%4!s!: %%!FUNC!: + +tracefmt.exe -p tmf -display -v -displayonly -nosummary | sort > aaa +start notepad aaa diff --git a/branches/WOF2-3/hw/dirs b/branches/WOF2-3/hw/dirs new file mode 100644 index 00000000..58242756 --- /dev/null +++ b/branches/WOF2-3/hw/dirs @@ -0,0 +1,3 @@ +DIRS=\ + mthca\ + mlx4 diff --git a/branches/WOF2-3/hw/mlx4/dirs b/branches/WOF2-3/hw/mlx4/dirs new file mode 100644 index 00000000..5927717d --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/dirs @@ -0,0 +1,3 @@ +DIRS= \ + kernel \ + user \ No newline at end of file diff --git a/branches/WOF2-3/hw/mlx4/inc/mx_abi.h b/branches/WOF2-3/hw/mlx4/inc/mx_abi.h new file mode 100644 index 00000000..02ec7b6f --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/inc/mx_abi.h @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Cisco Systems. All rights reserved. + * Copyright (c) 2005 PathScale, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: mx_abi.h 2002 2007-03-26 09:46:23Z sleybo $ + */ + +#ifndef MX_ABI_H +#define MX_ABI_H + +#include +#include "user.h" + +#pragma warning( disable : 4201) + +/* + * Make sure that all structs defined in this file remain laid out so + * that they pack the same way on 32-bit and 64-bit architectures (to + * avoid incompatibility between 32-bit userspace and 64-bit kernels). + * Specifically: + * - Do not use pointer types -- pass pointers in uint64_t instead. + * - Make sure that any structure larger than 4 bytes is padded to a + * multiple of 8 bytes. Otherwise the structure size will be + * different between 32-bit and 64-bit architectures. + */ + +struct ibv_get_context_resp { + + // mmap UAR + uint64_t uar_addr; + + // mmap Blue Flame + uint64_t bf_page; + int bf_buf_size; + int bf_offset; + + // mlx4_query_device result + int max_qp_wr; + int max_sge; + int max_cqe; + + // general parameters + uint32_t vend_id; + uint16_t dev_id; + uint16_t bf_reg_size; + uint16_t bf_regs_per_page; + uint16_t reserved1; + + // ibv_cmd_get_context result + uint32_t qp_tab_size; + + uint32_t reserved2; +}; + +struct ibv_alloc_pd_resp { + uint64_t pd_handle; + uint32_t pdn; + uint32_t reserved; +}; + +struct ibv_reg_mr { + uint64_t start; + uint64_t length; + uint64_t hca_va; + uint32_t access_flags; + uint32_t pdn; + uint64_t pd_handle; +}; + +struct ibv_reg_mr_resp { + uint64_t mr_handle; + uint32_t lkey; + uint32_t rkey; +}; + + +struct ibv_create_cq { + // struct ib_uverbs_create_cq + __declspec(align(8)) uint32_t cqe; + uint32_t reserved; + struct mlx4_ib_create_cq; +}; + +struct ibv_create_cq_resp { + // struct ib_uverbs_create_cq_resp + uint64_t cq_handle; + uint32_t cqe; + struct mlx4_ib_create_cq_resp; +}; + +struct ibv_create_srq { + // struct ib_uverbs_create_srq + uint64_t pd_handle; + uint32_t max_wr; + uint32_t max_sge; + uint32_t srq_limit; + uint32_t reserved; + struct mlx4_ib_create_srq; +}; + +struct ibv_create_srq_resp { + // struct ib_uverbs_create_srq_resp + uint64_t srq_handle; + uint32_t max_wr; + uint32_t max_sge; + struct mlx4_ib_create_srq_resp; +}; + +struct ibv_create_qp { + // struct ib_uverbs_create_qp + uint64_t pd_handle; + uint64_t send_cq_handle; + uint64_t recv_cq_handle; + uint64_t srq_handle; + uint32_t max_send_wr; + uint32_t max_recv_wr; + uint32_t max_send_sge; + uint32_t max_recv_sge; + uint32_t max_inline_data; + uint8_t sq_sig_all; + uint8_t qp_type; + uint8_t is_srq; + uint8_t reserved0; + struct mlx4_ib_create_qp; +}; + +struct ibv_create_qp_resp { + // struct ib_uverbs_create_qp_resp + uint64_t qp_handle; + uint32_t qpn; + uint32_t max_send_wr; + uint32_t max_recv_wr; + uint32_t max_send_sge; + uint32_t max_recv_sge; + uint32_t max_inline_data; +}; + +struct ibv_modify_qp_resp { + enum ibv_qp_attr_mask attr_mask; + uint8_t qp_state; + uint8_t reserved[3]; +}; + +struct ibv_create_ah_resp { + uint64_t start; +}; + +#pragma warning( default : 4201) + +#endif /* MX_ABI_H */ + diff --git a/branches/WOF2-3/hw/mlx4/inc/public.h b/branches/WOF2-3/hw/mlx4/inc/public.h new file mode 100644 index 00000000..a522670c --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/inc/public.h @@ -0,0 +1,139 @@ +/*++ +Copyright (c) 1990-2000 Microsoft Corporation All Rights Reserved + +Module Name: + + public.h + +Abstract: + + This module contains the common declarations shared by driver + and user applications. + +Environment: + + user and kernel + +--*/ + +// +// Define a WMI GUID to get MLX4_HCA info. +// (used in hca\wmi.c) +// + +// {2C4C8445-E4A6-45bc-889B-E5E93551DDAF} +DEFINE_GUID(MLX4_HCA_WMI_STD_DATA_GUID, +0x2c4c8445, 0xe4a6, 0x45bc, 0x88, 0x9b, 0xe5, 0xe9, 0x35, 0x51, 0xdd, 0xaf); + + + +// +// Define a WMI GUID to get MLX4_BUS info. +// (used in bus\wmi.c) +// + +// {3337968C-F117-4289-84C2-04EF74CBAD77} +DEFINE_GUID(MLX4_BUS_WMI_STD_DATA_GUID, +0x3337968c, 0xf117, 0x4289, 0x84, 0xc2, 0x4, 0xef, 0x74, 0xcb, 0xad, 0x77); + + + +// +// Define a GUID for MLX4_BUS upper (IB) interface. +// (used in hca\drv.c) +// + +// {48AC3404-269E-4ab0-B5F3-9EF15AA79D0C} +DEFINE_GUID(MLX4_BUS_IB_INTERFACE_GUID, +0x48ac3404, 0x269e, 0x4ab0, 0xb5, 0xf3, 0x9e, 0xf1, 0x5a, 0xa7, 0x9d, 0xc); + + + +// +// Define the MLX4_BUS type GUID. +// (used in bus\drv.c for responding to the IRP_MN_QUERY_BUS_INFORMATION) +// + +// {CF9E3C49-48D1-45b5-ABD7-CBCA7D954DF4} +DEFINE_GUID(MLX4_BUS_TYPE_GUID, +0xcf9e3c49, 0x48d1, 0x45b5, 0xab, 0xd7, 0xcb, 0xca, 0x7d, 0x95, 0x4d, 0xf4); + + + +// +// Installation Class for MLX4 BUS driver +// (used in bus\mlx4_bus.inf) +// + +// {714995B2-CD65-4a47-BCFE-95AC73A0D780} + + + +// +// Installation Class for MLX4 HCA driver +// (used in hca\mlx4_hca.inf) +// + +// {31B0B28A-26FF-4dca-A6FA-E767C7DFBA20} + + +#if 0 + +// +// Define an Interface Guid for mxe device class. +// This GUID is used to register (IoRegisterDeviceInterface) +// an instance of an interface so that user application +// can control the mxe device. +// + +DEFINE_GUID (GUID_DEVINTERFACE_MXE, + 0x781EF630, 0x72B2, 0x11d2, 0xB8, 0x52, 0x00, 0xC0, 0x4F, 0xAD, 0x51, 0x71); +//{781EF630-72B2-11d2-B852-00C04FAD5171} + +// +// Define a Setup Class GUID for Mxe Class. This is same +// as the TOASTSER CLASS guid in the INF files. +// +//leo +DEFINE_GUID (GUID_DEVCLASS_MXEETHER, + 0x4d36e972, 0xe325, 0x11ce, 0xBF, 0xC1, 0x08, 0x00, 0x2b, 0xE1, 0x03, 0x18); +//{4d36e972-e325-11ce-bfc1-08002be10318} + +// +// Define a WMI GUID to get mxe device info. +// + +DEFINE_GUID (MXE_WMI_STD_DATA_GUID, + 0xBBA21300L, 0x6DD3, 0x11d2, 0xB8, 0x44, 0x00, 0xC0, 0x4F, 0xAD, 0x51, 0x71); + +// +// Define a WMI GUID to represent device arrival notification WMIEvent class. +// + +DEFINE_GUID (MXE_NOTIFY_DEVICE_ARRIVAL_EVENT, + 0x1cdaff1, 0xc901, 0x45b4, 0xb3, 0x59, 0xb5, 0x54, 0x27, 0x25, 0xe2, 0x9c); +// {01CDAFF1-C901-45b4-B359-B5542725E29C} + + +//leo The Guid was taken from devguid.h +//DEFINE_GUID( GUID_DEVCLASS_INFINIBAND, 0x30ef7132L, 0xd858, 0x4a0c, 0xac, 0x24, 0xb9, 0x02, 0x8a, 0x5c, 0xca, 0x3f ); + + +#endif + +// +// GUID definition are required to be outside of header inclusion pragma to avoid +// error during precompiled headers. +// + +#ifndef __PUBLIC_H +#define __PUBLIC_H + +#define BUS_HARDWARE_IDS L"MLX4\\ConnectX_Hca\0" +#define ETH_HARDWARE_IDS L"MLX4\\ConnectX_Eth\0" +#define BUS_HARDWARE_DESCRIPTION L"Mellanox ConnectX Virtual Infiniband Adapter (#%02d)" +#define ETH_HARDWARE_DESCRIPTION L"Mellanox ConnectX Virtual Ethernet Adapter (#%02d)" + +#endif + + diff --git a/branches/WOF2-3/hw/mlx4/inc/user.h b/branches/WOF2-3/hw/mlx4/inc/user.h new file mode 100644 index 00000000..a6220990 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/inc/user.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef MLX4_IB_USER_H +#define MLX4_IB_USER_H + +/* + * Increment this value if any changes that break userspace ABI + * compatibility are made. + */ +#define MLX4_IB_UVERBS_ABI_VERSION 3 + +/* + * Make sure that all structs defined in this file remain laid out so + * that they pack the same way on 32-bit and 64-bit architectures (to + * avoid incompatibility between 32-bit userspace and 64-bit kernels). + * In particular do not use pointer types -- pass pointers in __u64 + * instead. + */ + +struct mlx4_ib_alloc_ucontext_resp { + __u32 qp_tab_size; + __u16 bf_reg_size; + __u16 bf_regs_per_page; +}; + +struct mlx4_ib_alloc_pd_resp { + __u32 pdn; + __u32 reserved; +}; + +struct mlx4_ib_create_cq { + __u64 buf_addr; + __u64 db_addr; + __u64 arm_sn_addr; // Windows specific +}; + +struct mlx4_ib_create_cq_resp { + __u32 cqn; +}; + +struct mlx4_ib_resize_cq { + __u64 buf_addr; +}; + +struct mlx4_ib_create_srq { + __u64 buf_addr; + __u64 db_addr; +}; + +struct mlx4_ib_create_srq_resp { + __u32 srqn; + __u32 reserved; +}; + +struct mlx4_ib_create_qp { + __u64 buf_addr; + __u64 db_addr; + __u8 log_sq_bb_count; + __u8 log_sq_stride; + __u8 sq_no_prefetch; + __u8 reserved[5]; +}; + +#endif /* MLX4_IB_USER_H */ diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/core/SOURCES b/branches/WOF2-3/hw/mlx4/kernel/bus/core/SOURCES new file mode 100644 index 00000000..fe394f67 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/core/SOURCES @@ -0,0 +1,51 @@ +TARGETNAME=mlx4_core +TARGETPATH=..\..\..\..\..\bin\kernel\obj$(BUILD_ALT_DIR) +TARGETTYPE=DRIVER_LIBRARY + + + +!if $(FREEBUILD) +ENABLE_EVENT_TRACING=1 +!else +#ENABLE_EVENT_TRACING=1 +!endif + + +DLLDEF=core.def + +SOURCES= \ + ev_log.mc \ + core.rc \ + cache.c \ + device.c \ + iobuf.c \ + l2w.c \ + l2w_radix.c \ + l2w_debug.c \ + l2w_memory.c \ + l2w_umem.c \ + pa_cash.c \ + packer.c \ + ud_header.c \ + verbs.c \ + +INCLUDES=..;..\inc;..\..\inc;..\net;..\..\..\..\..\inc;..\..\..\..\..\inc\kernel; + +C_DEFINES=$(C_DEFINES) -DDRIVER -DDEPRECATE_DDK_FUNCTIONS -D__LITTLE_ENDIAN -DUSE_WDM_INTERRUPTS + +TARGETLIBS= \ + $(DDK_LIB_PATH)\ntstrsafe.lib \ + $(TARGETPATH)\*\complib.lib \ + $(DDK_LIB_PATH)\iointex.lib + +!IFDEF ENABLE_EVENT_TRACING + +C_DEFINES = $(C_DEFINES) -DEVENT_TRACING + +RUN_WPP = $(SOURCES) -km -ext: .c .h .C .H \ + -scan:..\..\inc\mlx4_debug.h \ + -func:MLX4_PRINT(LEVEL,FLAGS,(MSG,...)) \ + -func:MLX4_PRINT_EXIT(LEVEL,FLAGS,(MSG,...)) +!ENDIF + +MSC_WARNING_LEVEL= /W4 diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/core/cache.c b/branches/WOF2-3/hw/mlx4/kernel/bus/core/cache.c new file mode 100644 index 00000000..382c6589 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/core/cache.c @@ -0,0 +1,449 @@ +/* + * Copyright (c) 2004 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Intel Corporation. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2005 Voltaire, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: cache.c 1349 2004-12-16 21:09:43Z roland $ + */ + +#include "ib\mlx4_ib.h" +#include "ib_cache.h" +#include + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "cache.tmh" +#endif + +#pragma warning( disable : 4200) +struct ib_pkey_cache { + int table_len; + __be16 table[0]; +}; + +struct ib_gid_cache { + int table_len; + union ib_gid table[0]; +}; +#pragma warning( default : 4200) + +struct ib_update_work { + PIO_WORKITEM work_item; + struct ib_device *device; + u8 port_num; +}; + +static inline int start_port(struct ib_device *device) +{ + return (device->node_type == RDMA_NODE_IB_SWITCH) ? 0 : 1; +} + +static inline int end_port(struct ib_device *device) +{ + return (device->node_type == RDMA_NODE_IB_SWITCH) ? + 0 : device->phys_port_cnt; +} + +int ib_get_cached_gid(struct ib_device *device, + u8 port_num, + int index, + union ib_gid *gid) +{ + union ib_gid cgid; + struct ib_gid_cache *cache; + unsigned long flags; + + if (mlx4_is_barred(device->dma_device)) + return -EFAULT; + + if (port_num < start_port(device) || port_num > end_port(device)) + return -EINVAL; + + read_lock_irqsave(&device->cache.lock, &flags); + + cache = device->cache.gid_cache[port_num - start_port(device)]; + + if (index < 0 || index >= cache->table_len) { + read_unlock_irqrestore(&device->cache.lock, flags); + return -EINVAL; + } + + cgid = cache->table[index]; + read_unlock_irqrestore(&device->cache.lock, flags); + *gid = cgid; + + return 0; +} +EXPORT_SYMBOL(ib_get_cached_gid); + +int ib_find_cached_gid(struct ib_device *device, + union ib_gid *gid, + u8 *port_num, + u16 *index) +{ + struct ib_gid_cache *cache; + unsigned long flags; + int p, i; + + if (mlx4_is_barred(device->dma_device)) + return -EFAULT; + + read_lock_irqsave(&device->cache.lock, &flags); + + for (p = 0; p <= end_port(device) - start_port(device); ++p) { + cache = device->cache.gid_cache[p]; + for (i = 0; i < cache->table_len; ++i) { + if (!memcmp(gid, &cache->table[i], sizeof *gid)) { + goto found; + } + } + } + + read_unlock_irqrestore(&device->cache.lock, flags); + *port_num = (u8)-1; + if (index) + *index = (u16)-1; + return -ENOENT; + +found: + read_unlock_irqrestore(&device->cache.lock, flags); + *port_num = (u8)(p + start_port(device)); + if (index) + *index = (u16)i; + + return 0; +} +EXPORT_SYMBOL(ib_find_cached_gid); + +int ib_get_cached_pkey(struct ib_device *device, + u8 port_num, + int index, + __be16 *pkey) +{ + struct ib_pkey_cache *cache; + __be16 cpkey; + unsigned long flags; + + if (mlx4_is_barred(device->dma_device)) + return -EFAULT; + + if (port_num < start_port(device) || port_num > end_port(device)) + return -EINVAL; + + read_lock_irqsave(&device->cache.lock, &flags); + + cache = device->cache.pkey_cache[port_num - start_port(device)]; + + if (index < 0 || index >= cache->table_len) { + read_unlock_irqrestore(&device->cache.lock, flags); + return -EINVAL; + } + + cpkey = cache->table[index]; + read_unlock_irqrestore(&device->cache.lock, flags); + *pkey = cpkey; + + return 0; +} +EXPORT_SYMBOL(ib_get_cached_pkey); + +int ib_find_cached_pkey(struct ib_device *device, + u8 port_num, + __be16 pkey, + u16 *index) +{ + struct ib_pkey_cache *cache; + unsigned long flags; + int i; + + if (mlx4_is_barred(device->dma_device)) + return -EFAULT; + + if (port_num < start_port(device) || port_num > end_port(device)) + return -EINVAL; + + read_lock_irqsave(&device->cache.lock, &flags); + + cache = device->cache.pkey_cache[port_num - start_port(device)]; + + *index = (u16)-1; + + for (i = 0; i < cache->table_len; ++i) + if ((cache->table[i] & 0x7fff) == (pkey & 0x7fff)) { + goto found; + } + + read_unlock_irqrestore(&device->cache.lock, flags); + *index = (u16)-1; + return -ENOENT; + +found: + read_unlock_irqrestore(&device->cache.lock, flags); + *index = (u16)i; + return 0; +} +EXPORT_SYMBOL(ib_find_cached_pkey); + +int ib_get_cached_lmc(struct ib_device *device, + u8 port_num, + u8 *lmc) +{ + unsigned long flags; + u8 clmc; + int ret = 0; + + if (port_num < start_port(device) || port_num > end_port(device)) + return -EINVAL; + + read_lock_irqsave(&device->cache.lock, &flags); + clmc = device->cache.lmc_cache[port_num - start_port(device)]; + read_unlock_irqrestore(&device->cache.lock, flags); + *lmc = clmc; + + return ret; +} +EXPORT_SYMBOL(ib_get_cached_lmc); + +static void ib_cache_update(struct ib_device *device, + u8 port) +{ + struct ib_port_attr *tprops = NULL; + struct ib_pkey_cache *pkey_cache = NULL, *old_pkey_cache; + struct ib_gid_cache *gid_cache = NULL, *old_gid_cache; + int i; + int ret; + + tprops = kmalloc(sizeof *tprops, GFP_KERNEL); + if (!tprops) + return; + + ret = ib_query_port(device, port, tprops); + if (ret) { + printk(KERN_WARNING "ib_query_port failed (%d) for %s. port_num %d (%d,%d)\n", + ret, device->name, (int)port, start_port(device), end_port(device) ); + goto err; + } + + pkey_cache = kmalloc(sizeof *pkey_cache + tprops->pkey_tbl_len * + sizeof *pkey_cache->table, GFP_KERNEL); + if (!pkey_cache) + goto err; + + pkey_cache->table_len = tprops->pkey_tbl_len; + + gid_cache = kmalloc(sizeof *gid_cache + tprops->gid_tbl_len * + sizeof *gid_cache->table, GFP_KERNEL); + if (!gid_cache) + goto err; + + gid_cache->table_len = tprops->gid_tbl_len; + + for (i = 0; i < pkey_cache->table_len; i+=32) { + int size = min(32, pkey_cache->table_len - i); + ret = ib_query_pkey_chunk(device, port, (u16)i, pkey_cache->table + i, size ); + if (ret) { + printk(KERN_WARNING "ib_query_pkey_chunk failed (%d) for %s (index %d)\n", + ret, device->name, i); + goto err; + } + } + + for (i = 0; i < gid_cache->table_len; i+=8) { + int size = min(8, gid_cache->table_len - i); + ret = ib_query_gid_chunk(device, port, i, gid_cache->table + i, size); + if (ret) { + printk(KERN_WARNING "ib_query_gid_chunk failed (%d) for %s (index %d)\n", + ret, device->name, i); + goto err; + } + } + + write_lock_irq(&device->cache.lock); + + old_pkey_cache = device->cache.pkey_cache[port - start_port(device)]; + old_gid_cache = device->cache.gid_cache [port - start_port(device)]; + + device->cache.pkey_cache[port - start_port(device)] = pkey_cache; + device->cache.gid_cache [port - start_port(device)] = gid_cache; + + device->cache.lmc_cache[port - start_port(device)] = tprops->lmc; + + write_unlock_irq(&device->cache.lock); + + kfree(old_pkey_cache); + kfree(old_gid_cache); + kfree(tprops); + return; + +err: + kfree(pkey_cache); + kfree(gid_cache); + kfree(tprops); +} + +static void ib_cache_task(void *work_ptr) +{ + struct ib_update_work *work = work_ptr; + + ib_cache_update(work->device, work->port_num); +} + +static void ib_work_item ( + IN PDEVICE_OBJECT DeviceObject, + IN PVOID Context + ) +{ + struct ib_update_work *work = (struct ib_update_work *)Context; + UNREFERENCED_PARAMETER(DeviceObject); + ib_cache_task(Context); + shutter_loose( &work->device->cache.x.work_thread ); + IoFreeWorkItem(work->work_item); + kfree(Context); +} + +static void ib_cache_event(struct ib_event_handler *handler, + struct ib_event *event) +{ + struct ib_update_work *work; + + if (event->event == IB_EVENT_PORT_ERR || + event->event == IB_EVENT_PORT_ACTIVE || + event->event == IB_EVENT_LID_CHANGE || + event->event == IB_EVENT_PKEY_CHANGE || + event->event == IB_EVENT_SM_CHANGE || + event->event == IB_EVENT_CLIENT_REREGISTER) { + + work = kmalloc(sizeof *work, GFP_ATOMIC); + if (work) { + PDEVICE_OBJECT pdo = to_mdev(handler->device)->dev->pdev->p_self_do; + + // allocate work item + work->work_item = IoAllocateWorkItem(pdo); + if (work->work_item == NULL) { + //TODO: at least - print error. Need to return code, but the function is void + kfree( work ); + return; + } + + // check whether we are in shutdown + if (shutter_use( &event->device->cache.x.work_thread ) <= 0) { + kfree( work ); + return; + } + + // schedule the work + work->device = event->device; + work->port_num = event->element.port_num; + IoQueueWorkItem( work->work_item, ib_work_item, DelayedWorkQueue, work ); + } + } +} + +static void ib_cache_setup_one(struct ib_device *device) +{ + int p; + int port_num; + + shutter_init( &device->cache.x.work_thread ); + rwlock_init(&device->cache.lock); + INIT_IB_EVENT_HANDLER(&device->cache.event_handler, + device, ib_cache_event, NULL, NULL, 0); + ib_register_event_handler(&device->cache.event_handler); + + port_num = end_port(device) - start_port(device) + 1; + if (port_num > 0 ) { + // if port_num ==0 ==> there are no IB ports + device->cache.pkey_cache = + kmalloc(sizeof *device->cache.pkey_cache * port_num, GFP_KERNEL); + device->cache.gid_cache = + kmalloc(sizeof *device->cache.gid_cache * port_num, GFP_KERNEL); + device->cache.lmc_cache = kmalloc(sizeof *device->cache.lmc_cache * + port_num, GFP_KERNEL); + + if (!device->cache.pkey_cache || !device->cache.gid_cache || + !device->cache.lmc_cache) { + printk(KERN_WARNING "Couldn't allocate cache " + "for %s\n", device->name); + goto err; + } + } + + for (p = 0; p < port_num; ++p) { + device->cache.pkey_cache[p] = NULL; + device->cache.gid_cache [p] = NULL; + ib_cache_update(device, (u8)(p + start_port(device))); + } + + return; + +err: + kfree(device->cache.pkey_cache); + kfree(device->cache.gid_cache); + kfree(device->cache.lmc_cache); +} + +// calling sequence: +// EvtReleaseHardware ==> mlx4_ib_cleanup ==> mlx4_unregister_interface ==> +// ==> mlx4_remove_device ==> mlx4_ib_remove ==> ib_unregister_device ==> +// ==> ib_cache_cleanup +static void ib_cache_cleanup_one(struct ib_device *device) +{ + int p; + + ASSERT(device->cache.event_handler.device); + ib_unregister_event_handler(&device->cache.event_handler); + // instead of Linux flush_scheduled_work(): wait for them to quit + shutter_shut( &device->cache.x.work_thread ); + + for (p = 0; p <= end_port(device) - start_port(device); ++p) { + kfree(device->cache.pkey_cache[p]); + kfree(device->cache.gid_cache[p]); + } + + kfree(device->cache.pkey_cache); + kfree(device->cache.gid_cache); + kfree(device->cache.lmc_cache); +} + +static struct ib_client cache_client = { "cache", ib_cache_setup_one, ib_cache_cleanup_one }; + +int __init ib_cache_setup(void) +{ + return ib_register_client(&cache_client); +} + +void __exit ib_cache_cleanup(void) +{ + ib_unregister_client(&cache_client); +} diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/core/core.def b/branches/WOF2-3/hw/mlx4/kernel/bus/core/core.def new file mode 100644 index 00000000..bfbb2f18 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/core/core.def @@ -0,0 +1,64 @@ +LIBRARY mlx4_core.lib + +EXPORTS +; DllInitialize and DllUnload must be exported for the OS reference counting to +; work, and must be private for the compiler to accept them. +DllInitialize private +DllUnload private + +; l2w.c +pci_pool_create +strlcpy +__bitmap_full +__bitmap_empty +core_init +core_cleanup + +; radix.c +radix_tree_create +radix_tree_insert +radix_tree_lookup +radix_tree_delete +radix_tree_destroy + +; cache.c +ib_get_cached_gid +ib_find_cached_gid +ib_get_cached_pkey +ib_find_cached_pkey +ib_get_cached_lmc + +; packer +ib_pack +ib_unpack + +; ud_header +ib_ud_header_init +ib_ud_header_pack +ib_ud_header_unpack + +; device.c +ib_alloc_device +ib_dealloc_device +ib_register_device +ib_unregister_device +ib_register_client +ib_unregister_client +ib_get_client_data +ib_set_client_data +ib_register_event_handler +ib_unregister_event_handler +ib_dispatch_event +ib_query_device +ib_query_port +ib_query_gid +ib_query_pkey +ib_modify_device +ib_modify_port +ib_find_gid +ib_find_pkey + +; verbs.c +ib_modify_qp_is_ok +ib_create_ah +ib_destroy_ah \ No newline at end of file diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/core/core.h b/branches/WOF2-3/hw/mlx4/kernel/bus/core/core.h new file mode 100644 index 00000000..ba5787b3 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/core/core.h @@ -0,0 +1,12 @@ +#pragma once + +int __init ib_cache_setup(void); + +void __exit ib_cache_cleanup(void); + +int __init ib_core_init(void); + +void __exit ib_core_cleanup(void); + +void init_qp_state_tbl(); + diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/core/core.rc b/branches/WOF2-3/hw/mlx4/kernel/bus/core/core.rc new file mode 100644 index 00000000..1d136d44 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/core/core.rc @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: ibal.rc 1611 2006-08-20 14:48:55Z sleybo $ + */ + + +#include + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef _DEBUG_ +#define VER_FILEDESCRIPTION_STR "MLX4 Upper Layer (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "MLX4 Upper Layer" +#endif + +#define VER_INTERNALNAME_STR "mlx4_core.lib" +#define VER_ORIGINALFILENAME_STR "mlx4_core.lib" + +#include + diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/core/device.c b/branches/WOF2-3/hw/mlx4/kernel/bus/core/device.c new file mode 100644 index 00000000..481c5a20 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/core/device.c @@ -0,0 +1,762 @@ +/* + * Copyright (c) 2004 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: device.c 1349 2004-12-16 21:09:43Z roland $ + */ + +#include "l2w.h" +#include "ib_verbs.h" +#include "core.h" +#include + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "device.tmh" +#endif + + +struct ib_client_data { + struct list_head list; + struct ib_client *client; + void * data; +}; + +static LIST_HEAD(device_list); +static LIST_HEAD(client_list); + +/* + * device_mutex protects access to both device_list and client_list. + * There's no real point to using multiple locks or something fancier + * like an rwsem: we always access both lists, and we're always + * modifying one list or the other list. In any case this is not a + * hot path so there's no point in trying to optimize. + */ +static DEFINE_MUTEX(device_mutex); + +static int ib_device_check_mandatory(struct ib_device *device) +{ +#define IB_MANDATORY_FUNC(x) { offsetof(struct ib_device, x), #x } + static const struct { + size_t offset; + char *name; + } mandatory_table[] = { + IB_MANDATORY_FUNC(query_device), + IB_MANDATORY_FUNC(query_port), + IB_MANDATORY_FUNC(query_pkey_chunk), + IB_MANDATORY_FUNC(query_gid_chunk), + IB_MANDATORY_FUNC(alloc_pd), + IB_MANDATORY_FUNC(dealloc_pd), + IB_MANDATORY_FUNC(create_ah), + IB_MANDATORY_FUNC(destroy_ah), + IB_MANDATORY_FUNC(create_qp), + IB_MANDATORY_FUNC(modify_qp), + IB_MANDATORY_FUNC(destroy_qp), + IB_MANDATORY_FUNC(post_send), + IB_MANDATORY_FUNC(post_recv), + IB_MANDATORY_FUNC(create_cq), + IB_MANDATORY_FUNC(destroy_cq), + IB_MANDATORY_FUNC(poll_cq), + IB_MANDATORY_FUNC(req_notify_cq), + IB_MANDATORY_FUNC(get_dma_mr), + IB_MANDATORY_FUNC(dereg_mr) + }; + int i; + + for (i = 0; i < ARRAY_SIZE(mandatory_table); ++i) { + if (!*(void **) ((u8 *) device + mandatory_table[i].offset)) { + printk(KERN_WARNING "Device %s is missing mandatory function %s\n", + device->name, mandatory_table[i].name); + return -EINVAL; + } + } + + return 0; +} + +static struct ib_device *__ib_device_get_by_name(const char *name) +{ + struct ib_device *device; + + list_for_each_entry(device, &device_list, core_list, struct ib_device) + if (!strncmp(name, device->name, IB_DEVICE_NAME_MAX)) + return device; + + return NULL; +} + + +static int alloc_name(char *name) +{ + unsigned long *inuse; + char buf[IB_DEVICE_NAME_MAX]; + struct ib_device *device; + int i; + + inuse = (unsigned long *) get_zeroed_page(GFP_KERNEL); + if (!inuse) + return -ENOMEM; + + list_for_each_entry(device, &device_list, core_list, struct ib_device) { + if (!sscanf(device->name, name, &i)) + continue; + if (i < 0 || i >= PAGE_SIZE * 8) + continue; + if (RtlStringCbPrintfA(buf, sizeof buf, name, i)) + return -EINVAL; + if (!strncmp(buf, device->name, IB_DEVICE_NAME_MAX)) + set_bit(i, inuse); + } + + i = find_first_zero_bit(inuse, PAGE_SIZE * 8); + free_page(inuse); + if (RtlStringCbPrintfA(buf, sizeof buf, name, i)) + return -EINVAL; + + if (__ib_device_get_by_name(buf)) + return -ENFILE; + + strlcpy(name, buf, IB_DEVICE_NAME_MAX); + return 0; +} + +static int start_port(struct ib_device *device) +{ + return (device->node_type == RDMA_NODE_IB_SWITCH) ? 0 : 1; +} + + +static int end_port(struct ib_device *device) +{ + return (device->node_type == RDMA_NODE_IB_SWITCH) ? + 0 : device->phys_port_cnt; +} + +/** + * ib_alloc_device - allocate an IB device struct + * @size:size of structure to allocate + * + * Low-level drivers should use ib_alloc_device() to allocate &struct + * ib_device. @size is the size of the structure to be allocated, + * including any private data used by the low-level driver. + * ib_dealloc_device() must be used to free structures allocated with + * ib_alloc_device(). + */ +struct ib_device *ib_alloc_device(size_t size) +{ + BUG_ON(size < sizeof (struct ib_device)); + + return kzalloc(size, GFP_KERNEL); +} +EXPORT_SYMBOL(ib_alloc_device); + +/** + * ib_dealloc_device - free an IB device struct + * @device:structure to free + * + * Free a structure allocated with ib_alloc_device(). + */ +void ib_dealloc_device(struct ib_device *device) +{ + if (device->reg_state == IB_DEV_UNINITIALIZED) { + kfree(device); + return; + } + + BUG_ON(device->reg_state != IB_DEV_UNREGISTERED); + +} +EXPORT_SYMBOL(ib_dealloc_device); + +static int add_client_context(struct ib_device *device, struct ib_client *client) +{ + struct ib_client_data *context; + unsigned long flags; + + context = kmalloc(sizeof *context, GFP_KERNEL); + if (!context) { + printk(KERN_WARNING "Couldn't allocate client context for %s/%s\n", + device->name, client->name); + return -ENOMEM; + } + + context->client = client; + context->data = NULL; + + spin_lock_irqsave(&device->client_data_lock, &flags); + list_add(&context->list, &device->client_data_list); + spin_unlock_irqrestore(&device->client_data_lock, flags); + + return 0; +} + +static int read_port_table_lengths(struct ib_device *device) +{ + struct ib_port_attr *tprops = NULL; + int num_ports, ret = -ENOMEM; + u8 port_index; + + tprops = kmalloc(sizeof *tprops, GFP_KERNEL); + if (!tprops) + goto out; + + num_ports = end_port(device) - start_port(device) + 1; + if ( num_ports == 0 ){ + //There are no IB ports, no need to update this tables + ret = 0; + goto out; + } + + device->pkey_tbl_len = kmalloc(sizeof *device->pkey_tbl_len * num_ports, + GFP_KERNEL); + device->gid_tbl_len = kmalloc(sizeof *device->gid_tbl_len * num_ports, + GFP_KERNEL); + if (!device->pkey_tbl_len || !device->gid_tbl_len) + goto err; + + for (port_index = 0; port_index < num_ports; ++port_index) { + ret = ib_query_port(device, (u8)(port_index + start_port(device)), + tprops); + if (ret) + goto err; + device->pkey_tbl_len[port_index] = tprops->pkey_tbl_len; + device->gid_tbl_len[port_index] = tprops->gid_tbl_len; + } + + ret = 0; + goto out; + +err: + kfree(device->gid_tbl_len); + kfree(device->pkey_tbl_len); +out: + kfree(tprops); + return ret; +} + +/** + * ib_register_device - Register an IB device with IB core + * @device:Device to register + * + * Low-level drivers use ib_register_device() to register their + * devices with the IB core. All registered clients will receive a + * callback for each device that is added. @device must be allocated + * with ib_alloc_device(). + */ +int ib_register_device(struct ib_device *device) +{ + int ret; + + mutex_lock(&device_mutex); + + if (strchr(device->name, '%')) { + ret = alloc_name(device->name); + if (ret) + goto out; + } + + if (ib_device_check_mandatory(device)) { + ret = -EINVAL; + goto out; + } + + INIT_LIST_HEAD(&device->event_handler_list); + INIT_LIST_HEAD(&device->client_data_list); + spin_lock_init(&device->event_handler_lock); + spin_lock_init(&device->client_data_lock); + + ret = read_port_table_lengths(device); + if (ret) { + printk(KERN_WARNING "Couldn't create table lengths cache for device %s\n", + device->name); + goto out; + } + + { + struct ib_client *client; + + list_for_each_entry(client, &client_list, list, struct ib_client) { + if ( add_client_context(device, client) ) { + printk(KERN_WARNING "add_client_context failed for device %s\n", + device->name); + ret = -EFAULT; + goto out; + } + if (client->add) + client->add(device); + } + } + + list_add_tail(&device->core_list, &device_list); + device->reg_state = IB_DEV_REGISTERED; + + out: + mutex_unlock(&device_mutex); + return ret; +} +EXPORT_SYMBOL(ib_register_device); + +/** + * ib_unregister_device - Unregister an IB device + * @device:Device to unregister + * + * Unregister an IB device. All clients will receive a remove callback. + */ +void ib_unregister_device(struct ib_device *device) +{ + struct ib_client *client; + struct ib_client_data *context, *tmp; + unsigned long flags; + + if(device->reg_state != IB_DEV_REGISTERED) { + ASSERT(device->reg_state == IB_DEV_REGISTERED); + return; + } + + mutex_lock(&device_mutex); + + list_for_each_entry_reverse(client, &client_list, list, struct ib_client) + if (client->remove) + client->remove(device); + + list_del(&device->core_list); + + if (device->gid_tbl_len) { + kfree(device->gid_tbl_len); + device->gid_tbl_len = NULL; + } + if(device->pkey_tbl_len) { + kfree(device->pkey_tbl_len); + device->pkey_tbl_len = NULL; + } + + mutex_unlock(&device_mutex); + + spin_lock_irqsave(&device->client_data_lock, &flags); + list_for_each_entry_safe(context, tmp, &device->client_data_list, list, struct ib_client_data, struct ib_client_data) + kfree(context); + spin_unlock_irqrestore(&device->client_data_lock, flags); + + device->reg_state = IB_DEV_UNREGISTERED; +} +EXPORT_SYMBOL(ib_unregister_device); + +/** + * ib_register_client - Register an IB client + * @client:Client to register + * + * Upper level users of the IB drivers can use ib_register_client() to + * register callbacks for IB device addition and removal. When an IB + * device is added, each registered client's add method will be called + * (in the order the clients were registered), and when a device is + * removed, each client's remove method will be called (in the reverse + * order that clients were registered). In addition, when + * ib_register_client() is called, the client will receive an add + * callback for all devices already registered. + */ +int ib_register_client(struct ib_client *client) +{ + struct ib_device *device; + int ret = 0; + + mutex_lock(&device_mutex); + + list_for_each_entry(device, &device_list, core_list, struct ib_device) { + if ( add_client_context(device, client) ) { + printk(KERN_WARNING "add_client_context failed for device %s\n", + device->name); + ret = -EFAULT; + goto out; + } + if (client->add) + client->add(device); + } + + list_add_tail(&client->list, &client_list); +out: + mutex_unlock(&device_mutex); + return ret; +} +EXPORT_SYMBOL(ib_register_client); + +/** + * ib_unregister_client - Unregister an IB client + * @client:Client to unregister + * + * Upper level users use ib_unregister_client() to remove their client + * registration. When ib_unregister_client() is called, the client + * will receive a remove callback for each IB device still registered. + */ +void ib_unregister_client(struct ib_client *client) +{ + struct ib_client_data *context, *tmp; + struct ib_device *device; + unsigned long flags; + + mutex_lock(&device_mutex); + + list_for_each_entry(device, &device_list, core_list, struct ib_device) { + if (client->remove) + client->remove(device); + + spin_lock_irqsave(&device->client_data_lock, &flags); + list_for_each_entry_safe(context, tmp, &device->client_data_list, list, struct ib_client_data, struct ib_client_data) + if (context->client == client) { + list_del(&context->list); + kfree(context); + } + spin_unlock_irqrestore(&device->client_data_lock, flags); + } + list_del(&client->list); + + mutex_unlock(&device_mutex); +} +EXPORT_SYMBOL(ib_unregister_client); + +/** + * ib_get_client_data - Get IB client context + * @device:Device to get context for + * @client:Client to get context for + * + * ib_get_client_data() returns client context set with + * ib_set_client_data(). + */ +void *ib_get_client_data(struct ib_device *device, struct ib_client *client) +{ + struct ib_client_data *context; + void *ret = NULL; + unsigned long flags; + + spin_lock_irqsave(&device->client_data_lock, &flags); + list_for_each_entry(context, &device->client_data_list, list, struct ib_client_data) + if (context->client == client) { + ret = context->data; + break; + } + spin_unlock_irqrestore(&device->client_data_lock, flags); + + return ret; +} +EXPORT_SYMBOL(ib_get_client_data); + +/** + * ib_set_client_data - Set IB client context + * @device:Device to set context for + * @client:Client to set context for + * @data:Context to set + * + * ib_set_client_data() sets client context that can be retrieved with + * ib_get_client_data(). + */ +void ib_set_client_data(struct ib_device *device, struct ib_client *client, + void *data) +{ + struct ib_client_data *context; + unsigned long flags; + + spin_lock_irqsave(&device->client_data_lock, &flags); + list_for_each_entry(context, &device->client_data_list, list, struct ib_client_data) + if (context->client == client) { + context->data = data; + goto out; + } + + printk(KERN_WARNING "No client context found for %s/%s\n", + device->name, client->name); + +out: + spin_unlock_irqrestore(&device->client_data_lock, flags); +} +EXPORT_SYMBOL(ib_set_client_data); + +/** + * ib_register_event_handler - Register an IB event handler + * @event_handler:Handler to register + * + * ib_register_event_handler() registers an event handler that will be + * called back when asynchronous IB events occur (as defined in + * chapter 11 of the InfiniBand Architecture Specification). This + * callback may occur in interrupt context. + */ +int ib_register_event_handler (struct ib_event_handler *event_handler) +{ + unsigned long flags; + + spin_lock_irqsave(&event_handler->device->event_handler_lock, &flags); + list_add_tail(&event_handler->list, + &event_handler->device->event_handler_list); + spin_unlock_irqrestore(&event_handler->device->event_handler_lock, flags); + + return 0; +} +EXPORT_SYMBOL(ib_register_event_handler); + +/** + * ib_unregister_event_handler - Unregister an event handler + * @event_handler:Handler to unregister + * + * Unregister an event handler registered with + * ib_register_event_handler(). + */ +int ib_unregister_event_handler(struct ib_event_handler *event_handler) +{ + unsigned long flags; + + spin_lock_irqsave(&event_handler->device->event_handler_lock, &flags); + list_del(&event_handler->list); + spin_unlock_irqrestore(&event_handler->device->event_handler_lock, flags); + + return 0; +} +EXPORT_SYMBOL(ib_unregister_event_handler); + +/** + * ib_dispatch_event - Dispatch an asynchronous event + * @event:Event to dispatch + * + * Low-level drivers must call ib_dispatch_event() to dispatch the + * event to all registered event handlers when an asynchronous event + * occurs. + */ +void ib_dispatch_event(struct ib_event *event) +{ + unsigned long flags; + struct ib_event_handler *handler; + + spin_lock_irqsave(&event->device->event_handler_lock, &flags); + + list_for_each_entry(handler, &event->device->event_handler_list, list, struct ib_event_handler) + handler->handler(handler, event); + + spin_unlock_irqrestore(&event->device->event_handler_lock, flags); +} +EXPORT_SYMBOL(ib_dispatch_event); + +/** + * ib_query_device - Query IB device attributes + * @device:Device to query + * @device_attr:Device attributes + * + * ib_query_device() returns the attributes of a device through the + * @device_attr pointer. + */ +int ib_query_device(struct ib_device *device, + struct ib_device_attr *device_attr) +{ + return device->query_device(device, device_attr); +} +EXPORT_SYMBOL(ib_query_device); + +/** + * ib_query_port - Query IB port attributes + * @device:Device to query + * @port_num:Port number to query + * @port_attr:Port attributes + * + * ib_query_port() returns the attributes of a port through the + * @port_attr pointer. + */ +int ib_query_port(struct ib_device *device, + u8 port_num, + struct ib_port_attr *port_attr) +{ + if (port_num < start_port(device) || port_num > end_port(device)) + return -EINVAL; + + return device->query_port(device, port_num, port_attr); +} +EXPORT_SYMBOL(ib_query_port); + +/** + * ib_query_gid_chunk - Get a chunk of GID table entries + * @device:Device to query + * @port_num:Port number to query + * @index:GID table index to query + * @gid:Returned GIDs chunk + * @size: max of elements of chunk to return + * + * ib_query_gid_chunk() fetches the specified GID table enties chunk. + */ +int ib_query_gid_chunk(struct ib_device *device, + u8 port_num, int index, union ib_gid gid[8], int size) +{ + return device->query_gid_chunk(device, port_num, index, gid, size); +} +EXPORT_SYMBOL(ib_query_gid_chunk); + +/** + * ib_query_pkey_chunk - Get a chunk of P_Key table entries + * @device:Device to query + * @port_num:Port number to query + * @index:P_Key table index to query + * @pkey:Returned P_Keys chunk + * @size: max of elements of chunk to return + * + * ib_query_pkey_chunk() fetches the specified P_Key table entries chunk. + */ +int ib_query_pkey_chunk(struct ib_device *device, + u8 port_num, u16 index, __be16 pkey[32], int size) +{ + return device->query_pkey_chunk(device, port_num, index, pkey, size); +} +EXPORT_SYMBOL(ib_query_pkey_chunk); + +/** + * ib_modify_device - Change IB device attributes + * @device:Device to modify + * @device_modify_mask:Mask of attributes to change + * @device_modify:New attribute values + * + * ib_modify_device() changes a device's attributes as specified by + * the @device_modify_mask and @device_modify structure. + */ +int ib_modify_device(struct ib_device *device, + int device_modify_mask, + struct ib_device_modify *device_modify) +{ + return device->modify_device(device, device_modify_mask, + device_modify); +} +EXPORT_SYMBOL(ib_modify_device); + +/** + * ib_modify_port - Modifies the attributes for the specified port. + * @device: The device to modify. + * @port_num: The number of the port to modify. + * @port_modify_mask: Mask used to specify which attributes of the port + * to change. + * @port_modify: New attribute values for the port. + * + * ib_modify_port() changes a port's attributes as specified by the + * @port_modify_mask and @port_modify structure. + */ +int ib_modify_port(struct ib_device *device, + u8 port_num, int port_modify_mask, + struct ib_port_modify *port_modify) +{ + if (port_num < start_port(device) || port_num > end_port(device)) + return -EINVAL; + + return device->modify_port(device, port_num, port_modify_mask, + port_modify); +} +EXPORT_SYMBOL(ib_modify_port); + +/** + * ib_find_gid - Returns the port number and GID table index where + * a specified GID value occurs. + * @device: The device to query. + * @gid: The GID value to search for. + * @port_num: The port number of the device where the GID value was found. + * @index: The index into the GID table where the GID was found. This + * parameter may be NULL. + */ +int ib_find_gid(struct ib_device *device, union ib_gid *gid, + u8 *port_num, u16 *index) +{ + int ret, port, i, j; + union ib_gid tmp_gid[8]; + + for (port = start_port(device); port <= end_port(device); ++port) { + for (i = 0; i < device->gid_tbl_len[port - start_port(device)]; i+=8) { + ret = ib_query_gid_chunk(device, (u8)port, i, tmp_gid, 8); + if (ret) + return ret; + + for (j = 0; j < 8; ++j) { + if (!memcmp(&tmp_gid[j], gid, sizeof *gid)) { + *port_num = (u8)port; + if (index) + *index = (u16)(i+j); + return 0; + } + } + } + } + + return -ENOENT; +} +EXPORT_SYMBOL(ib_find_gid); + +/** + * ib_find_pkey - Returns the PKey table index where a specified + * PKey value occurs. + * @device: The device to query. + * @port_num: The port number of the device to search for the PKey. + * @pkey: The PKey value to search for. + * @index: The index into the PKey table where the PKey was found. + */ +int ib_find_pkey(struct ib_device *device, + u8 port_num, __be16 pkey, u16 *index) +{ + int ret, i, j; + __be16 tmp_pkey[32]; + + for (i = 0; i < device->pkey_tbl_len[port_num - start_port(device)]; i+=32) { + ret = ib_query_pkey_chunk(device, port_num, (u16)i, tmp_pkey, 32); + if (ret) + return ret; + + for (j = 0; j < 32; ++j) { + if ((pkey & 0x7fff) == (tmp_pkey[j] & 0x7fff)) { + *index = (u16)(i+j); + return 0; + } + } + } + + return -ENOENT; +} +EXPORT_SYMBOL(ib_find_pkey); + +int __init ib_core_init(void) +{ + int ret; + + mutex_init(&device_mutex); + ret = ib_cache_setup(); + if (ret) { + printk(KERN_WARNING "Couldn't set up InfiniBand P_Key/GID cache\n"); + } + + return ret; +} + +void __exit ib_core_cleanup(void) +{ + ib_cache_cleanup(); + /* Make sure that any pending umem accounting work is done. */ + // TODO: how to do that ? + // LINUX: flush_scheduled_work(); +} + diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/core/ev_log.mc b/branches/WOF2-3/hw/mlx4/kernel/bus/core/ev_log.mc new file mode 100644 index 00000000..26bfa783 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/core/ev_log.mc @@ -0,0 +1,163 @@ +;/*++ +;============================================================================= +;Copyright (c) 2007 Mellanox Technologies +; +;Module Name: +; +; ev_log.mc +; +;Abstract: +; +; MLX4 Driver event log messages +; +;Authors: +; +; Leonid Keller +; +;Environment: +; +; Kernel Mode . +; +;============================================================================= +;--*/ +; +MessageIdTypedef = NTSTATUS + +SeverityNames = ( + Success = 0x0:STATUS_SEVERITY_SUCCESS + Informational = 0x1:STATUS_SEVERITY_INFORMATIONAL + Warning = 0x2:STATUS_SEVERITY_WARNING + Error = 0x3:STATUS_SEVERITY_ERROR + ) + +FacilityNames = ( + System = 0x0 + RpcRuntime = 0x2:FACILITY_RPC_RUNTIME + RpcStubs = 0x3:FACILITY_RPC_STUBS + Io = 0x4:FACILITY_IO_ERROR_CODE + MLX4 = 0x8:FACILITY_MLX4_ERROR_CODE + ) + + +MessageId=0x0001 Facility=MLX4 Severity=Informational SymbolicName=EVENT_MLX4_ANY_INFO +Language=English +%2 +. + +MessageId=0x0002 Facility=MLX4 Severity=Warning SymbolicName=EVENT_MLX4_ANY_WARN +Language=English +%2 +. +MessageId=0x0003 Facility=MLX4 Severity=Error SymbolicName=EVENT_MLX4_ANY_ERROR +Language=English +%2 +. + +MessageId=0x0004 Facility=MLX4 Severity=Error SymbolicName=EVENT_MLX4_ERROR_LIFEFISH_OK +Language=English +mlx4_bus has started in non-operational mode. +. + +MessageId=0x0005 Facility=MLX4 Severity=Error SymbolicName=EVENT_MLX4_ERROR_LIFEFISH_FAIL +Language=English +mlx4_bus has failed to start even in non-operational mode.%n +Look into the the previous error messages. +. + +MessageId=0x0006 Facility=MLX4 Severity=Informational SymbolicName=EVENT_MLX4_INFO_DEV_STARTED +Language=English +mlx4_bus has been successfully started.%n +The device parameters are:%n + vendor_id %t%2%n + device_id %t%3%n + subvendor_id %t%4%n + subsystem_id %t%5%n + HW revision %t%6%n + FW version %t%7.%8.%9%n + HCA guid %t%10%11%n + HCA location %t'%12'%n + port number %t%13%n + port1 type %t%14%n + port2 type %t%15. +. + +MessageId=0x0007 Facility=MLX4 Severity=Error SymbolicName=EVENT_MLX4_ERROR_MAP_FA +Language=English +MAP_FA command failed with error %2.%n +The adapter card is non-functional.%n +Most likely a FW problem.%n +Please burn the last FW and restart the mlx4_bus driver. +. + +MessageId=0x0008 Facility=MLX4 Severity=Error SymbolicName=EVENT_MLX4_ERROR_RUN_FW +Language=English +RUN_FW command failed with error %2.%n +The adapter card is non-functional.%n +Most likely a FW problem.%n +Please burn the last FW and restart the mlx4_bus driver. +. + +MessageId=0x0009 Facility=MLX4 Severity=Error SymbolicName=EVENT_MLX4_ERROR_QUERY_FW +Language=English +QUERY_FW command failed with error %2.%n +The adapter card is non-functional.%n +Most likely a FW problem.%n +Please burn the last FW and restart the mlx4_bus driver. +. + +MessageId=0x000a Facility=MLX4 Severity=Warning SymbolicName=EVENT_MLX4_WARN_QUERY_FW +Language=English +Function disabled.%n +This device is multi-functional.%n +Please upgrade to a multi-function driver. +. + +MessageId=0x000b Facility=MLX4 Severity=Error SymbolicName=EVENT_MLX4_ERROR_QUERY_DEV_CAP +Language=English +QUERY_DEV_CAP command failed with error %2.%n +The adapter card is non-functional.%n +Most likely a FW problem.%n +Please burn the last FW and restart the mlx4_bus driver. +. + +MessageId=0x000c Facility=MLX4 Severity=Error SymbolicName=EVENT_MLX4_ERROR_QUERY_ADAPTER +Language=English +QUERY_ADAPTER command failed with error %2.%n +The adapter card is non-functional.%n +Most likely a FW problem.%n +Please burn the last FW and restart the mlx4_bus driver. +. + +MessageId=0x000d Facility=MLX4 Severity=Error SymbolicName=EVENT_MLX4_ERROR_NOT_ENOUGH_QPS +Language=English +Too few QPs were requested (requested %2, reserved for FW %3).%n +The adapter card is non-functional.%n +Please increase the Registry LogNumQp parameter under HKLM\System\CurrentControlSet\Services\mlx4_bus\Parameters. +. + +MessageId=0x000e Facility=MLX4 Severity=Informational SymbolicName=EVENT_MLX4_INFO_RESET_START +Language=English +Performing HCA restart ... +. + +MessageId=0x000f Facility=MLX4 Severity=Informational SymbolicName=EVENT_MLX4_INFO_RESET_END +Language=English +HCA restart finished. Notifying the clients ... +. + +MessageId=0x0010 Facility=MLX4 Severity=Warning SymbolicName=EVENT_MLX4_WARN_REG_ACTION +Language=English +%2 failed on %3 with status %4. +. + +MessageId=0x0011 Facility=MLX4 Severity=Warning SymbolicName=EVENT_MLX4_WARN_REG_OPEN_DEV_KEY +Language=English +WdfDeviceOpenRegistryKey failed on opening SW (=driver) key for mlx4_bus with status %2. +. + +MessageId=0x0012 Facility=MLX4 Severity=Warning SymbolicName=EVENT_MLX4_WARN_INVALID_PORT_TYPE_VALUE +Language=English +PortType registry parameter contains invalid value, PortType = %2. +. + + diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/core/iobuf.c b/branches/WOF2-3/hw/mlx4/kernel/bus/core/iobuf.c new file mode 100644 index 00000000..62ce6af8 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/core/iobuf.c @@ -0,0 +1,552 @@ +/* + * Copyright (c) 2004 Topspin Corporation. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: mt_memory.c 2020 2007-05-01 09:29:10Z leonid $ + */ +#include +#include "l2w.h" +#include "pa_cash.h" +#include "ib_verbs.h" + +#if defined (EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "iobuf.tmh" +#endif + + + + +/* +* Function: map user buffer to kernel and lock it +* +* Return: +*/ +int get_user_pages( + IN struct mlx4_dev *dev, /* device */ + IN u64 start, /* address in user space */ + IN int npages, /* size in pages */ + IN int write_access, /* access rights */ + OUT struct scatterlist *sg /* s/g list */ + ) +{ + PMDL mdl_p; + int size = npages << PAGE_SHIFT; + int access = (write_access) ? IoWriteAccess : IoReadAccess; + int err; + void * kva; /* kernel virtual address */ + + UNREFERENCED_PARAMETER(dev); + + MLX4_ENTER(MLX4_DBG_MEMORY); + ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL); + + /* allocate MDL */ + mdl_p = IoAllocateMdl( (PVOID)(ULONG_PTR)start, (ULONG)size, + FALSE, + FALSE, /* not charge quota */ + NULL); + if (mdl_p == NULL) { + err = -ENOMEM; + goto err0; + } + + /* lock memory */ + __try { + MmProbeAndLockPages( mdl_p, UserMode, access ); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + NTSTATUS Status = GetExceptionCode(); + MLX4_PRINT(TRACE_LEVEL_ERROR ,MLX4_DBG_MEMORY ,("Exception 0x%x on MmProbeAndLockPages(), addr 0x%I64x, size %d\n", Status, start, size)); + switch(Status){ + case STATUS_WORKING_SET_QUOTA: + err = -ENOMEM;break; + case STATUS_ACCESS_VIOLATION: + err = -EACCES;break; + default : + err = -EINVAL; + } + + goto err1; + } + + /* map it to kernel */ + kva = MmMapLockedPagesSpecifyCache( mdl_p, + KernelMode, MmNonCached, + NULL, FALSE, NormalPagePriority ); + if (kva == NULL) { + MLX4_PRINT(TRACE_LEVEL_ERROR ,MLX4_DBG_MEMORY ,("MmMapLockedPagesSpecifyCache failed\n")); + err = -EFAULT; + goto err2; + } + + sg->dma_addr.va = kva; + sg->dma_addr.sz = size; + sg->offset = (unsigned int)(start & ~PAGE_MASK); + sg->p_mdl = mdl_p; + // TODO: has to be dma address, not physical one + sg->dma_addr.da = MmGetPhysicalAddress(kva).QuadPart; + return 0; + +err2: + MmUnlockPages(mdl_p); +err1: + IoFreeMdl(mdl_p); +err0: + MLX4_EXIT(MLX4_DBG_MEMORY); + return err; + + } + +void put_page(struct scatterlist *sg) +{ + if (sg->p_mdl) { + MmUnmapLockedPages( sg->dma_addr.va, sg->p_mdl ); + MmUnlockPages(sg->p_mdl); + IoFreeMdl(sg->p_mdl); + } +} + + +typedef struct _iobuf_seg { + LIST_ENTRY link; + PMDL mdl_p; + u64 va; /* virtual address of the buffer */ + u64 size; /* size in bytes of the buffer */ + u32 nr_pages; + int is_user; +} iobuf_seg_t; + +// Returns: 0 on success, -ENOMEM or -EACCESS on error +static int register_segment( + IN u64 va, + IN u64 size, + IN int is_user, + IN enum ib_access_flags acc, + OUT iobuf_seg_t **iobuf_seg) +{ + PMDL mdl_p; + int rc; + KPROCESSOR_MODE mode; + iobuf_seg_t * new_iobuf; + static ULONG cnt=0; + LOCK_OPERATION Operation; + + // set Operation + if (acc & IB_ACCESS_LOCAL_WRITE) + Operation = IoModifyAccess; + else + Operation = IoReadAccess; + + // allocate IOBUF segment object + new_iobuf = (iobuf_seg_t *)kmalloc(sizeof(iobuf_seg_t), GFP_KERNEL ); + if (new_iobuf == NULL) { + rc = -ENOMEM; + goto err_nomem; + } + + // allocate MDL + mdl_p = IoAllocateMdl( (PVOID)(ULONG_PTR)va, (ULONG)size, FALSE,FALSE,NULL); + if (mdl_p == NULL) { + rc = -ENOMEM; + goto err_alloc_mdl; + } + + // make context-dependent things + if (is_user) { + ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL); + mode = UserMode; + } + else { /* Mapping to kernel virtual address */ + // MmBuildMdlForNonPagedPool(mdl_p); // fill MDL ??? - should we do that really ? + mode = KernelMode; + } + + __try { /* try */ + MmProbeAndLockPages( mdl_p, mode, Operation ); /* lock memory */ + } /* try */ + + __except (EXCEPTION_EXECUTE_HANDLER) { + MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_MEMORY, + ("MOSAL_iobuf_register: Exception 0x%x on MmProbeAndLockPages(), va %I64d, sz %I64d\n", + GetExceptionCode(), va, size)); + rc = -EACCES; + goto err_probe; + } + + // fill IOBUF object + new_iobuf->va = va; + new_iobuf->size= size; + new_iobuf->nr_pages = ADDRESS_AND_SIZE_TO_SPAN_PAGES( va, size ); + new_iobuf->mdl_p = mdl_p; + new_iobuf->is_user = is_user; + *iobuf_seg = new_iobuf; + return 0; + +err_probe: + IoFreeMdl(mdl_p); +err_alloc_mdl: + ExFreePool((PVOID)new_iobuf); +err_nomem: + return rc; +} + +void iobuf_init( + IN u64 va, + IN u64 size, + IN int is_user, + IN OUT iobuf_t *iobuf_p) +{ + iobuf_p->va = va; + iobuf_p->size= size; + iobuf_p->is_user = is_user; + InitializeListHead( &iobuf_p->seg_que ); + iobuf_p->seg_num = 0; + iobuf_p->nr_pages = 0; + iobuf_p->is_cashed = 0; +} + +int iobuf_register( + IN u64 va, + IN u64 size, + IN int is_user, + IN enum ib_access_flags acc, + IN OUT iobuf_t *iobuf_p) +{ + int rc=0; + u64 seg_va; // current segment start + u64 seg_size; // current segment size + u64 rdc; // remain data counter - what is rest to lock + u64 delta; // he size of the last not full page of the first segment + iobuf_seg_t * new_iobuf; + unsigned page_size = PAGE_SIZE; + +// 32 - for any case +#define PFNS_IN_PAGE_SIZE_MDL ((PAGE_SIZE - sizeof(struct _MDL) - 32) / sizeof(long)) +#define MIN_IOBUF_SEGMENT_SIZE (PAGE_SIZE * PFNS_IN_PAGE_SIZE_MDL) // 4MB + + ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); + + // we'll try to register all at once. + seg_va = va; + seg_size = rdc = size; + + // allocate segments + while (rdc > 0) { + // map a segment + rc = register_segment(seg_va, seg_size, is_user, acc, &new_iobuf ); + + // success - move to another segment + if (!rc) { + rdc -= seg_size; + seg_va += seg_size; + InsertTailList( &iobuf_p->seg_que, &new_iobuf->link ); + iobuf_p->seg_num++; + // round the segment size to the next page boundary + delta = (seg_va + seg_size) & (page_size - 1); + if (delta) { + seg_size -= delta; + seg_size += page_size; + } + if (seg_size > rdc) + seg_size = rdc; + continue; + } + + // failure - too large a buffer: lessen it and try once more + if (rc == -ENOMEM) { + // no where to lessen - too low memory + if (seg_size <= MIN_IOBUF_SEGMENT_SIZE) + break; + // lessen the size + seg_size >>= 1; + // round the segment size to the next page boundary + delta = (seg_va + seg_size) & (page_size - 1); + if (delta) { + seg_size -= delta; + seg_size += page_size; + } + if (seg_size > rdc) + seg_size = rdc; + continue; + } + + // got unrecoverable error + break; + } + + // SUCCESS + if (rc) + iobuf_deregister( iobuf_p ); + else + iobuf_p->nr_pages += ADDRESS_AND_SIZE_TO_SPAN_PAGES( va, size ); + + return rc; +} + + +static void __iobuf_copy( + IN OUT iobuf_t *dst_iobuf_p, + IN iobuf_t *src_iobuf_p + ) +{ + int i; + iobuf_seg_t *iobuf_seg_p; + + *dst_iobuf_p = *src_iobuf_p; + InitializeListHead( &dst_iobuf_p->seg_que ); + for (i=0; iseg_num; ++i) { + iobuf_seg_p = (iobuf_seg_t *)(PVOID)RemoveHeadList( &src_iobuf_p->seg_que ); + InsertTailList( &dst_iobuf_p->seg_que, &iobuf_seg_p->link ); + } +} + +/* if the buffer to be registered overlaps a buffer, already registered, + a race can happen between HCA, writing to the previously registered + buffer and the probing functions (MmProbeAndLockPages, MmSecureVirtualMemory), + used in the algorithm of memory registration. + To prevent the race we maintain reference counters for the physical pages, being registered, + and register every physical page FOR THE WRITE ACCESS only once.*/ + +int iobuf_register_with_cash( + IN u64 vaddr, + IN u64 size, + IN int is_user, + IN OUT enum ib_access_flags *acc_p, + IN OUT iobuf_t *iobuf_p) +{ + int rc, pa_in; + iobuf_t sec_iobuf; + int i, page_in , page_out, page_in_total; + int nr_pages; + char *subregion_start, *va; + u64 subregion_size; + u64 rdc; // remain data counter - what is rest to lock + u64 delta; // he size of the last not full page of the first segment + enum ib_access_flags acc; + + mutex_lock(&g_pa_mutex); + + // register memory for read access to bring pages into the memory + rc = iobuf_register( vaddr, size, is_user, 0, iobuf_p); + + // on error or read access - exit + if (rc || !(*acc_p & IB_ACCESS_LOCAL_WRITE)) + goto exit; + + // re-register buffer with the correct access rights + iobuf_init( (u64)vaddr, size, is_user, &sec_iobuf ); + nr_pages = ADDRESS_AND_SIZE_TO_SPAN_PAGES( vaddr, size ); + subregion_start = va = (char*)(ULONG_PTR)vaddr; + rdc = size; + pa_in = page_in = page_in_total = page_out = 0; + + for (i=0; i rdc) + subregion_size = rdc; + + // register the subregion + rc = iobuf_register( (ULONG_PTR)subregion_start, subregion_size, is_user, acc, &sec_iobuf); + if (rc) + goto cleanup; + + // prepare to the next loop + rdc -= subregion_size; + subregion_start +=subregion_size; + } + } + + // prepare to registration of the subregion + if (pa_in) { // SUBREGION WITH READ ACCESS + acc = 0; + subregion_size = (u64)page_in * PAGE_SIZE; + } + else { // SUBREGION WITH WRITE ACCESS + acc = IB_ACCESS_LOCAL_WRITE; + subregion_size = (u64)page_out * PAGE_SIZE; + } + + // round the subregion size to the page boundary + delta = (ULONG_PTR)(subregion_start + subregion_size) & (PAGE_SIZE - 1); + subregion_size -= delta; + if (subregion_size > rdc) + subregion_size = rdc; + + // register the subregion + rc = iobuf_register( (ULONG_PTR)subregion_start, subregion_size, is_user, acc, &sec_iobuf); + if (rc) + goto cleanup; + + // cash phys pages + rc = pa_register(iobuf_p); + if (rc) + goto err_pa_reg; + + // replace the iobuf + iobuf_deregister( iobuf_p ); + sec_iobuf.is_cashed = TRUE; + __iobuf_copy( iobuf_p, &sec_iobuf ); + + // buffer is a part of also registered buffer - change the rights + if (page_in_total) + *acc_p &= ~IB_ACCESS_LOCAL_WRITE; + + goto exit; + +err_pa_reg: + iobuf_deregister( &sec_iobuf ); +cleanup: + iobuf_deregister( iobuf_p ); +exit: + mutex_unlock(&g_pa_mutex); + return rc; +} + +static void deregister_segment(iobuf_seg_t * iobuf_seg_p) +{ + MmUnlockPages( iobuf_seg_p->mdl_p ); // unlock the buffer + IoFreeMdl( iobuf_seg_p->mdl_p ); // free MDL + ExFreePool(iobuf_seg_p); +} + +void iobuf_deregister(iobuf_t *iobuf_p) +{ + iobuf_seg_t *iobuf_seg_p; // pointer to current segment object + + ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); + + // release segments + while (!IsListEmpty( &iobuf_p->seg_que )) { + iobuf_seg_p = (iobuf_seg_t *)(PVOID)RemoveTailList( &iobuf_p->seg_que ); + deregister_segment(iobuf_seg_p); + iobuf_p->seg_num--; + } + ASSERT(iobuf_p->seg_num == 0); +} + +void iobuf_deregister_with_cash(iobuf_t *iobuf_p) +{ + ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL); + + mutex_lock(&g_pa_mutex); + if (iobuf_p->is_cashed) + pa_deregister(iobuf_p); + iobuf_deregister(iobuf_p); + mutex_unlock(&g_pa_mutex); +} + +void iobuf_iter_init( + IN iobuf_t *iobuf_p, + IN OUT iobuf_iter_t *iterator_p) +{ + iterator_p->seg_p = iobuf_p->seg_que.Flink; + iterator_p->pfn_ix = 0; +} + +// the function returns phys addresses of the pages, also for the first page +// if one wants to get the phys address of the buffer, one has to +// add the offset from the start of the page to the first phys address +// Returns: the number of entries, filled in page_tbl_p +// Returns 0 while at the end of list. +uint32_t iobuf_get_tpt_seg( + IN iobuf_t *iobuf_p, + IN OUT iobuf_iter_t *iterator_p, + IN uint32_t n_pages_in, + IN OUT uint64_t *page_tbl_p ) +{ + uint32_t i=0; // has to be initialized here for a premature exit + iobuf_seg_t *seg_p; // pointer to current segment object + PPFN_NUMBER pfn_p; + uint32_t pfn_ix; // index of PFN in PFN array of the current segment + uint64_t *pa_buf_p = page_tbl_p; + + // prepare to the loop + seg_p = iterator_p->seg_p; // first segment of the first iobuf + pfn_ix= iterator_p->pfn_ix; + + // check, whether we at the end of the list + if ((PVOID)seg_p == (PVOID)&iobuf_p->seg_que) + goto exit; + pfn_p = MmGetMdlPfnArray( seg_p->mdl_p ) + pfn_ix; + + // pass along all the PFN arrays + for (; i < n_pages_in; i++, pa_buf_p++) { + // convert PFN to the physical address + *pa_buf_p = (uint64_t)*pfn_p++ << PAGE_SHIFT; + + // get to the next PFN + if (++pfn_ix >= seg_p->nr_pages) { + seg_p = (iobuf_seg_t*)seg_p->link.Flink; + pfn_ix = 0; + if ((PVOID)seg_p == (PVOID)&iobuf_p->seg_que) { + i++; + break; + } + pfn_p = MmGetMdlPfnArray( seg_p->mdl_p ); + } + } + +exit: + iterator_p->seg_p = seg_p; + iterator_p->pfn_ix = pfn_ix; + return i; +} + + diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/core/l2w.c b/branches/WOF2-3/hw/mlx4/kernel/bus/core/l2w.c new file mode 100644 index 00000000..4569e816 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/core/l2w.c @@ -0,0 +1,504 @@ +#include "l2w.h" +#include "core.h" +#include "pa_cash.h" +#include "mlx4.h" + +#if defined (EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "l2w.tmh" +#endif + +/* Nth element of the table contains the index of the first set bit of N; 8 - for N=0 */ +char g_set_bit_tbl[256]; + +/* Nth element of the table contains the index of the first 0 bit of N; 8 - for N=255 */ +char g_clr_bit_tbl[256]; + +/* interval for a cmd go-bit waiting */ +// TODO: not clear what is to be this value: +// 1. it has to be enough great, so as the tread will go waiting; +// 2. it has to be enough small, so as there is no too large waiting after first command try; +// 3. it has to be enough great, so as not to cause to intensive rescheduling; +#define CMD_WAIT_USECS 2 +#define CMD_WAIT_INTERVAL ((-10) * CMD_WAIT_USECS) +LARGE_INTEGER g_cmd_interval = { (ULONG)CMD_WAIT_INTERVAL, 0 }; + +//////////////////////////////////////////////////////// +// +// PCI POOL +// +//////////////////////////////////////////////////////// + +pci_pool_t * +pci_pool_create (const char *name, struct pci_dev *pdev, + size_t size, size_t align, size_t allocation) +{ + pci_pool_t *pool; + UNREFERENCED_PARAMETER(align); + UNREFERENCED_PARAMETER(allocation); + + ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); + + // allocation parameter is not handled yet + ASSERT(allocation == 0); + + //TODO: not absolutely correct: Linux's pci_pool_alloc provides contiguous physical memory, + // while default alloc function - ExAllocatePoolWithTag -doesn't. + // But for now it is used for elements of size <= PAGE_SIZE + // Anyway - a sanity check: + ASSERT(size <= PAGE_SIZE); + if (size > PAGE_SIZE) + return NULL; + + // allocate object + pool = (pci_pool_t *)ExAllocatePoolWithTag( NonPagedPool, sizeof(pci_pool_t), MT_TAG_PCIPOOL ); + if (pool == NULL) + return NULL; + + //TODO: not too effective: one can read its own alloc/free functions + ExInitializeNPagedLookasideList( &pool->pool_hdr, NULL, NULL, 0, size, MT_TAG_PCIPOOL, 0 ); + + // fill the object + pool->mdev = pdev->dev; + pool->size = size; + strncpy( pool->name, name, sizeof pool->name ); + + return pool; +} + + +//////////////////////////////////////////////////////// +// +// BIT TECHNIQUES +// +//////////////////////////////////////////////////////// + +void fill_bit_tbls() +{ + unsigned long i; + for (i=0; i<256; ++i) { + g_set_bit_tbl[i] = (char)(_ffs_raw(&i,0) - 1); + g_clr_bit_tbl[i] = (char)(_ffz_raw(&i,0) - 1); + } + g_set_bit_tbl[0] = g_clr_bit_tbl[255] = 8; +} + + +//////////////////////////////////////////////////////// +// +// BIT MAPS +// +//////////////////////////////////////////////////////// + +int __bitmap_full(const unsigned long *bitmap, int bits) +{ + int k, lim = bits/BITS_PER_LONG; + for (k = 0; k < lim; ++k) + if (~bitmap[k]) + return 0; + + if (bits % BITS_PER_LONG) + if (~bitmap[k] & BITMAP_LAST_WORD_MASK(bits)) + return 0; + + return 1; +} + +int __bitmap_empty(const unsigned long *bitmap, int bits) +{ + int k, lim = bits/BITS_PER_LONG; + for (k = 0; k < lim; ++k) + if (bitmap[k]) + return 0; + + if (bits % BITS_PER_LONG) + if (bitmap[k] & BITMAP_LAST_WORD_MASK(bits)) + return 0; + + return 1; +} + + +//////////////////////////////////////////////////////// +// +// DEBUG PRINT +// +//////////////////////////////////////////////////////// + +VOID +WriteEventLogEntry( + PVOID pi_pIoObject, + ULONG pi_ErrorCode, + ULONG pi_UniqueErrorCode, + ULONG pi_FinalStatus, + ULONG pi_nDataItems, + ... + ) +/*++ + +Routine Description: + Writes an event log entry to the event log. + +Arguments: + + pi_pIoObject......... The IO object ( driver object or device object ). + pi_ErrorCode......... The error code. + pi_UniqueErrorCode... A specific error code. + pi_FinalStatus....... The final status. + pi_nDataItems........ Number of data items. + . + . data items values + . + +Return Value: + + None . + +--*/ +{ /* WriteEventLogEntry */ + + /* Variable argument list */ + va_list l_Argptr; + /* Pointer to an error log entry */ + PIO_ERROR_LOG_PACKET l_pErrorLogEntry; + + /* Init the variable argument list */ + va_start(l_Argptr, pi_nDataItems); + + /* Allocate an error log entry */ + l_pErrorLogEntry = + (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry( + pi_pIoObject, + (UCHAR)(sizeof(IO_ERROR_LOG_PACKET)+pi_nDataItems*sizeof(ULONG)) + ); + /* Check allocation */ + if ( l_pErrorLogEntry != NULL) + { /* OK */ + + /* Data item index */ + USHORT l_nDataItem ; + + /* Set the error log entry header */ + l_pErrorLogEntry->ErrorCode = pi_ErrorCode; + l_pErrorLogEntry->DumpDataSize = (USHORT) (pi_nDataItems*sizeof(ULONG)); + l_pErrorLogEntry->SequenceNumber = 0; + l_pErrorLogEntry->MajorFunctionCode = 0; + l_pErrorLogEntry->IoControlCode = 0; + l_pErrorLogEntry->RetryCount = 0; + l_pErrorLogEntry->UniqueErrorValue = pi_UniqueErrorCode; + l_pErrorLogEntry->FinalStatus = pi_FinalStatus; + + /* Insert the data items */ + for (l_nDataItem = 0; l_nDataItem < pi_nDataItems; l_nDataItem++) + { /* Inset a data item */ + + /* Current data item */ + int l_CurDataItem ; + + /* Get next data item */ + l_CurDataItem = va_arg( l_Argptr, int); + + /* Put it into the data array */ + l_pErrorLogEntry->DumpData[l_nDataItem] = l_CurDataItem ; + + } /* Inset a data item */ + + /* Write the packet */ + IoWriteErrorLogEntry(l_pErrorLogEntry); + + } /* OK */ + + /* Term the variable argument list */ + va_end(l_Argptr); + +} /* WriteEventLogEntry */ + + +//////////////////////////////////////////////////////// +// +// GENERAL +// +//////////////////////////////////////////////////////// + +// from lib/string.c +/** +* strlcpy - Copy a %NUL terminated string into a sized buffer +* @dest: Where to copy the string to +* @src: Where to copy the string from +* @size: size of destination buffer +* +* Compatible with *BSD: the result is always a valid +* NUL-terminated string that fits in the buffer (unless, +* of course, the buffer size is zero). It does not pad +* out the result like strncpy() does. +*/ +SIZE_T strlcpy(char *dest, const void *src, SIZE_T size) +{ + SIZE_T ret = strlen(src); + + if (size) { + SIZE_T len = (ret >= size) ? size-1 : ret; + memcpy(dest, src, len); + dest[len] = '\0'; + } + return ret; +} + +int core_init() +{ + int err; + + fill_bit_tbls(); + init_qp_state_tbl(); + err = ib_core_init(); + if (err) + return err; + return pa_cash_init(); +} + +void core_cleanup() +{ + ib_core_cleanup(); + pa_cash_release(); +} + +#ifdef USE_WDM_INTERRUPTS + +void free_irq(struct mlx4_dev *dev) +{ + if (!dev->pdev->int_obj) + return; + +#if (NTDDI_VERSION >= NTDDI_LONGHORN) + // Vista build environment + if (dev->pdev->legacy_connect) + IoDisconnectInterrupt( dev->pdev->int_obj ); + else { + IO_DISCONNECT_INTERRUPT_PARAMETERS ctx; + MLX4_PRINT(TRACE_LEVEL_WARNING, MLX4_DBG_DRV, + ("IoDisconnectInterrupt: Version %d\n", dev->pdev->version)); + ctx.Version = dev->pdev->version; + ctx.ConnectionContext.InterruptObject = dev->pdev->int_obj; + IoDisconnectInterruptEx( &ctx ); + } + +#else + // legacy build environment + IoDisconnectInterrupt( dev->pdev->int_obj ); +#endif + dev->pdev->int_obj = NULL; +} + + +int request_irq( + IN struct mlx4_dev * dev, + IN PKSERVICE_ROUTINE isr, /* Line ISR */ + IN PVOID isr_ctx, /* ISR context */ + IN PKMESSAGE_SERVICE_ROUTINE misr, /* Message ISR */ + OUT PKINTERRUPT * int_obj /* interrupt object */ + ) +{ + NTSTATUS status; + struct pci_dev *pdev = dev->pdev; /* interrupt resources */ + +#if (NTDDI_VERSION >= NTDDI_LONGHORN) + + IO_CONNECT_INTERRUPT_PARAMETERS params; + PIO_INTERRUPT_MESSAGE_INFO p_msi_info; + + KeInitializeSpinLock( &pdev->isr_lock ); + pdev->n_msi_vectors = 0; // not using MSI/MSI-X + + // + // Vista and later platforms build environment + // + + RtlZeroMemory( ¶ms, sizeof(IO_CONNECT_INTERRUPT_PARAMETERS) ); + if ( !(dev->flags & MLX4_FLAG_MSI_X) ) { + params.Version = CONNECT_FULLY_SPECIFIED; + goto get_legacy_int; + } + + // + // try to connect our Interrupt Message Service Rotuine to + // all Message-Signaled Interrupts our device has been granted, + // with automatic fallback to a single line-based interrupt. + // + + params.Version = CONNECT_MESSAGE_BASED; + params.MessageBased.PhysicalDeviceObject = pdev->pdo; + params.MessageBased.ConnectionContext.Generic = &p_msi_info; + params.MessageBased.MessageServiceRoutine = misr; + params.MessageBased.ServiceContext = isr_ctx; + params.MessageBased.SpinLock = NULL; + params.MessageBased.SynchronizeIrql = 0; + params.MessageBased.FloatingSave = FALSE; + // fallback to line-based ISR if there is no MSI support + params.MessageBased.FallBackServiceRoutine = isr; + + status = IoConnectInterruptEx(¶ms); + + pdev->version = params.Version; + *int_obj = (PVOID)p_msi_info; + + if ( NT_SUCCESS(status) ) { + + // + // It worked, so we're running on Vista or later. + // + + if(params.Version == CONNECT_MESSAGE_BASED) { + ULONG i; + + // + // Because we succeeded in connecting to one or more Message-Signaled + // Interrupts, the connection context that was returned was + // a pointer to an IO_INTERRUPT_MESSAGE_INFO structure. + // + pdev->n_msi_vectors = (u8)p_msi_info->MessageCount; // not using MSI/MSI-X + // print it + MLX4_PRINT(TRACE_LEVEL_WARNING, MLX4_DBG_DRV, + ("request_irq: Granted %d MSI vectors ( UnifiedIrql %#x)\n", + p_msi_info->MessageCount, p_msi_info->UnifiedIrql )); + for (i=0; i < p_msi_info->MessageCount; ++i) { + MLX4_PRINT(TRACE_LEVEL_WARNING, MLX4_DBG_DRV, + ("*** Vector %#x, Affinity %#x, Irql %#x, MsgAddr %I64x, MsgData %#x, Mode %d\n", + p_msi_info->MessageInfo[i].Vector, + (ULONG)p_msi_info->MessageInfo[i].TargetProcessorSet, + p_msi_info->MessageInfo[i].Irql, + p_msi_info->MessageInfo[i].MessageAddress.QuadPart, + p_msi_info->MessageInfo[i].MessageData, + p_msi_info->MessageInfo[i].Mode )); + } + + // sanity check + if (pdev->n_msi_vectors_alloc != pdev->n_msi_vectors) { + MLX4_PRINT(TRACE_LEVEL_ERROR ,MLX4_DBG_INIT , + ("Connected to %d interrupts from %d allocated to us !!!\n", + pdev->n_msi_vectors, pdev->n_msi_vectors_alloc )); + ASSERT(pdev->n_msi_vectors_alloc == pdev->n_msi_vectors); + *int_obj = NULL; + return -EFAULT; /* failed to connect interrupt */ + } + + // fill MSI-X map table + for (i=0; i < p_msi_info->MessageCount; ++i) { + pdev->p_msix_map[i].cpu = p_msi_info->MessageInfo[i].TargetProcessorSet; + } + + } else { + // + // We are on Vista, but there is no HW MSI support + // So we are connected to line interrupt + ASSERT(params.Version == CONNECT_LINE_BASED); + } + + + } else { + + // + // We are on a legacy system and maybe can proceed + // + + if (params.Version == CONNECT_FULLY_SPECIFIED) { + + // + // use IoConnectInterruptEx to connect our ISR to a + // line-based interrupt. + // +get_legacy_int: + params.FullySpecified.PhysicalDeviceObject = pdev->pdo; + params.FullySpecified.InterruptObject = int_obj; + params.FullySpecified.ServiceRoutine = isr; + params.FullySpecified.ServiceContext = isr_ctx; + params.FullySpecified.FloatingSave = FALSE; + params.FullySpecified.SpinLock = NULL; + + if (pdev->int_info.Flags & CM_RESOURCE_INTERRUPT_MESSAGE) { + // The resource is for a message-based interrupt. Use the u.MessageInterrupt.Translated member of IntResource. + + params.FullySpecified.Vector = pdev->int_info.u.MessageInterrupt.Translated.Vector; + params.FullySpecified.Irql = (KIRQL)pdev->int_info.u.MessageInterrupt.Translated.Level; + params.FullySpecified.SynchronizeIrql = (KIRQL)pdev->int_info.u.MessageInterrupt.Translated.Level; + params.FullySpecified.ProcessorEnableMask = g.mod_affinity ? + g.mod_affinity : pdev->int_info.u.MessageInterrupt.Translated.Affinity; + } else { + // The resource is for a line-based interrupt. Use the u.Interrupt member of IntResource. + + params.FullySpecified.Vector = pdev->int_info.u.Interrupt.Vector; + params.FullySpecified.Irql = (KIRQL)pdev->int_info.u.Interrupt.Level; + params.FullySpecified.SynchronizeIrql = (KIRQL)pdev->int_info.u.Interrupt.Level; + params.FullySpecified.ProcessorEnableMask = g.mod_affinity ? + g.mod_affinity : pdev->int_info.u.Interrupt.Affinity; + } + + params.FullySpecified.InterruptMode = (pdev->int_info.Flags & CM_RESOURCE_INTERRUPT_LATCHED ? Latched : LevelSensitive); + params.FullySpecified.ShareVector = (BOOLEAN)(pdev->int_info.ShareDisposition == CmResourceShareShared); + + status = IoConnectInterruptEx(¶ms); + pdev->version = params.Version; + } + else { + + // Something wrong with IoConnectInterruptEx. + // Lets try the usual way + status = IoConnectInterrupt( + int_obj, /* InterruptObject */ + isr, /* ISR */ + isr_ctx, /* ISR context */ + &pdev->isr_lock, /* spinlock */ + pdev->int_info.u.Interrupt.Vector, /* interrupt vector */ + (KIRQL)pdev->int_info.u.Interrupt.Level, /* IRQL */ + (KIRQL)pdev->int_info.u.Interrupt.Level, /* Synchronize IRQL */ + (BOOLEAN)((pdev->int_info.Flags == CM_RESOURCE_INTERRUPT_LATCHED) ? + Latched : LevelSensitive), /* interrupt type: LATCHED or LEVEL */ + (BOOLEAN)(pdev->int_info.ShareDisposition == CmResourceShareShared), /* vector shared or not */ + g.mod_affinity ? g.mod_affinity : (KAFFINITY)pdev->int_info.u.Interrupt.Affinity, /* interrupt affinity */ + FALSE /* whether to save Float registers */ + ); + pdev->legacy_connect = TRUE; + } + + } + +#else + + // + // Legacy (before Vista) platform build environment + // + + UNUSED_PARAM(misr); + + KeInitializeSpinLock( &pdev->isr_lock ); + pdev->n_msi_vectors = 0; // not using MSI/MSI-X + + status = IoConnectInterrupt( + int_obj, /* InterruptObject */ + isr, /* ISR */ + isr_ctx, /* ISR context */ + &pdev->isr_lock, /* spinlock */ + pdev->int_info.u.Interrupt.Vector, /* interrupt vector */ + (KIRQL)pdev->int_info.u.Interrupt.Level, /* IRQL */ + (KIRQL)pdev->int_info.u.Interrupt.Level, /* Synchronize IRQL */ + (BOOLEAN)((pdev->int_info.Flags == CM_RESOURCE_INTERRUPT_LATCHED) ? + Latched : LevelSensitive), /* interrupt type: LATCHED or LEVEL */ + (BOOLEAN)(pdev->int_info.ShareDisposition == CmResourceShareShared), /* vector shared or not */ + g.mod_affinity ? g.mod_affinity : (KAFFINITY)pdev->int_info.u.Interrupt.Affinity, /* interrupt affinity */ + FALSE /* whether to save Float registers */ + ); + +#endif + + if (!NT_SUCCESS(status)) { + MLX4_PRINT(TRACE_LEVEL_ERROR ,MLX4_DBG_INIT , + ("Connect interrupt failed with status %#x, affinity %#x )\n", + status, g.mod_affinity ? g.mod_affinity : (unsigned int)pdev->int_info.u.Interrupt.Affinity)); + *int_obj = NULL; + return -EFAULT; /* failed to connect interrupt */ + } + + return 0; +} +#endif diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/core/l2w_debug.c b/branches/WOF2-3/hw/mlx4/kernel/bus/core/l2w_debug.c new file mode 100644 index 00000000..02c66dd0 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/core/l2w_debug.c @@ -0,0 +1,406 @@ +#include "l2w.h" +#include "ev_log.h" + +#define MAX_BUFFER_SIZE 256 + +/* + * This function sends to Event Log messages with one WCHAR string and several binary parameters. + * The string will be inserted instead of %2 parameter of the message. + * Binary parameters will be shown in Dump Area of the message. + * Binary parameters should be of type LONG. + */ +VOID +WriteEventLogEntryStr( + PVOID pi_pIoObject, + ULONG pi_ErrorCode, + ULONG pi_UniqueErrorCode, + ULONG pi_FinalStatus, + PWCHAR pi_InsertionStr, + ULONG pi_nDataItems, + ... + ) +/*++ + +Routine Description: + Writes an event log entry to the event log. + +Arguments: + + pi_pIoObject......... The IO object ( driver object or device object ). + pi_ErrorCode......... The error code. + pi_UniqueErrorCode... A specific error code. + pi_FinalStatus....... The final status. + pi_nDataItems........ Number of data items. + . + . data items values + . + +Return Value: + + None . + +--*/ +{ /* WriteEventLogEntryStr */ + + /* Variable argument list */ + va_list l_Argptr; + /* Pointer to an error log entry */ + PIO_ERROR_LOG_PACKET l_pErrorLogEntry; + /* sizeof insertion string */ + int l_Size = (int)((pi_InsertionStr) ? ((wcslen(pi_InsertionStr) + 1) * sizeof( WCHAR )) : 0); + int l_PktSize =sizeof(IO_ERROR_LOG_PACKET)+pi_nDataItems*sizeof(ULONG); + int l_TotalSize =l_PktSize +l_Size; + + if (pi_pIoObject == NULL) { + ASSERT(pi_pIoObject != NULL); + return; + } + + /* Init the variable argument list */ + va_start(l_Argptr, pi_nDataItems); + + /* Allocate an error log entry */ + if (l_TotalSize >= ERROR_LOG_MAXIMUM_SIZE - 2) + l_TotalSize = ERROR_LOG_MAXIMUM_SIZE - 2; + l_pErrorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry( + pi_pIoObject, (UCHAR)l_TotalSize ); + + /* Check allocation */ + if ( l_pErrorLogEntry != NULL) + { /* OK */ + + /* Data item index */ + USHORT l_nDataItem ; + + /* Set the error log entry header */ + l_pErrorLogEntry->ErrorCode = pi_ErrorCode; + l_pErrorLogEntry->DumpDataSize = (USHORT) (pi_nDataItems*sizeof(ULONG)); + l_pErrorLogEntry->SequenceNumber = 0; + l_pErrorLogEntry->MajorFunctionCode = 0; + l_pErrorLogEntry->IoControlCode = 0; + l_pErrorLogEntry->RetryCount = 0; + l_pErrorLogEntry->UniqueErrorValue = pi_UniqueErrorCode; + l_pErrorLogEntry->FinalStatus = pi_FinalStatus; + + /* Insert the data items */ + for (l_nDataItem = 0; l_nDataItem < pi_nDataItems; l_nDataItem++) + { /* Inset a data item */ + + /* Current data item */ + int l_CurDataItem ; + + /* Get next data item */ + l_CurDataItem = va_arg( l_Argptr, int); + + /* Put it into the data array */ + l_pErrorLogEntry->DumpData[l_nDataItem] = l_CurDataItem ; + + } /* Inset a data item */ + + /* add insertion string */ + if (pi_InsertionStr) { + char *ptr; + int sz = min( l_TotalSize - l_PktSize, l_Size ); + l_pErrorLogEntry->NumberOfStrings = 1; + l_pErrorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET) + l_pErrorLogEntry->DumpDataSize; + ptr = (char*)l_pErrorLogEntry + l_pErrorLogEntry->StringOffset; + memcpy( ptr, pi_InsertionStr, sz ); + *(WCHAR*)&ptr[sz - 2] = (WCHAR)0; + } + + /* Write the packet */ + IoWriteErrorLogEntry(l_pErrorLogEntry); + + } /* OK */ + + /* Term the variable argument list */ + va_end(l_Argptr); + +} /* WriteEventLogEntry */ + +/* + * This function sends to Event Log messages with various parameters. + * Every parameter should be coded as a pair: a format specifier and the value. + * 'pi_nDataItems' presents the number of the pairs. + * + * Here is an example: + * + * To print a message (from MC file) like: + * + * MessageId=0x0006 Facility=MLX4 Severity=Informational SymbolicName=EVENT_MLX4_INFO_TEST + * Language=English + * some_long %2, some_short %3, some_byte %4, some_wide_char_str %5, some_ansii_str %6 + * + * you have to code: + * + * WriteEventLogEntryData( pdev->p_self_do, (ULONG)EVENT_MLX4_INFO_TEST, 0, 0, 5, + * L"%d", long_int, // LONG + * L"%04x", (ULONG)short_int, // SHORT + * L"%02x", (ULONG)byte_int, // CHAR + * L"%s", wide_char_str, // PWCHAR + * L"%S", ansii_str // PCHAR + * ); + */ +VOID +WriteEventLogEntryData( + PVOID pi_pIoObject, + ULONG pi_ErrorCode, + ULONG pi_UniqueErrorCode, + ULONG pi_FinalStatus, + ULONG pi_nDataItems, + ... + ) +/*++ + +Routine Description: + Writes an event log entry to the event log. + +Arguments: + + pi_pIoObject......... The IO object ( driver object or device object ). + pi_ErrorCode......... The error code. + pi_UniqueErrorCode... A specific error code. + pi_FinalStatus....... The final status. + pi_nDataItems........ Number of data items (i.e. pairs of data parameters). + . + . data items values + . + +Return Value: + + None . + +--*/ +{ /* WriteEventLogEntryData */ + + /* Variable argument list */ + va_list l_Argptr; + /* Pointer to an error log entry */ + PIO_ERROR_LOG_PACKET l_pErrorLogEntry; + /* sizeof insertion string */ + int l_Size = 0; + /* temp buffer */ + UCHAR l_Buf[ERROR_LOG_MAXIMUM_SIZE - 2]; + /* position in buffer */ + UCHAR * l_Ptr = l_Buf; + /* Data item index */ + USHORT l_nDataItem ; + /* total packet size */ + int l_TotalSize; + + if (pi_pIoObject == NULL) { + ASSERT(pi_pIoObject != NULL); + return; + } + + /* Init the variable argument list */ + va_start(l_Argptr, pi_nDataItems); + + /* Create the insertion strings Insert the data items */ + memset( l_Buf, 0, sizeof(l_Buf) ); + for (l_nDataItem = 0; l_nDataItem < pi_nDataItems; l_nDataItem++) + { + NTSTATUS status; + /* Current binary data item */ + int l_CurDataItem ; + /* Current pointer data item */ + void* l_CurPtrDataItem ; + /* format specifier */ + WCHAR* l_FormatStr; + /* the rest of the buffer */ + int l_BufSize = (int)(l_Buf + sizeof(l_Buf)- l_Ptr); + /* size of insertion string */ + size_t l_StrSize; + + /* print as much as we can */ + if ( l_BufSize < 4 ) + break; + + /* Get format specifier */ + l_FormatStr = va_arg( l_Argptr, PWCHAR); + + /* Get next data item */ + if ( !wcscmp( l_FormatStr, L"%s" ) || !wcscmp( l_FormatStr, L"%S" ) ) { + l_CurPtrDataItem = va_arg( l_Argptr, PWCHAR); + /* convert to string */ + status = RtlStringCchPrintfW( (NTSTRSAFE_PWSTR)l_Ptr, l_BufSize>>1, l_FormatStr , l_CurPtrDataItem ); + } + else { + l_CurDataItem = va_arg( l_Argptr, int); + /* convert to string */ + status = RtlStringCchPrintfW( (NTSTRSAFE_PWSTR)l_Ptr, l_BufSize>>1, l_FormatStr , l_CurDataItem ); + } + + if (!NT_SUCCESS(status)) + return; + + /* prepare the next loop */ + status = RtlStringCbLengthW( (NTSTRSAFE_PWSTR)l_Ptr, l_BufSize, &l_StrSize ); + if (!NT_SUCCESS(status)) + return; + *(WCHAR*)&l_Ptr[l_StrSize] = (WCHAR)0; + l_StrSize += 2; + l_Size = l_Size + (int)l_StrSize; + l_Ptr = l_Buf + l_Size; + l_BufSize = (int)(l_Buf + sizeof(l_Buf)- l_Ptr); + + } /* Inset a data item */ + + /* Term the variable argument list */ + va_end(l_Argptr); + + /* Allocate an error log entry */ + l_TotalSize =sizeof(IO_ERROR_LOG_PACKET) +l_Size; + if (l_TotalSize >= ERROR_LOG_MAXIMUM_SIZE - 2) { + l_TotalSize = ERROR_LOG_MAXIMUM_SIZE - 2; + l_Size = l_TotalSize - sizeof(IO_ERROR_LOG_PACKET); + } + l_pErrorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry( + pi_pIoObject, (UCHAR)l_TotalSize ); + + /* Check allocation */ + if ( l_pErrorLogEntry != NULL) + { /* OK */ + + /* Set the error log entry header */ + l_pErrorLogEntry->ErrorCode = pi_ErrorCode; + l_pErrorLogEntry->DumpDataSize = 0; + l_pErrorLogEntry->SequenceNumber = 0; + l_pErrorLogEntry->MajorFunctionCode = 0; + l_pErrorLogEntry->IoControlCode = 0; + l_pErrorLogEntry->RetryCount = 0; + l_pErrorLogEntry->UniqueErrorValue = pi_UniqueErrorCode; + l_pErrorLogEntry->FinalStatus = pi_FinalStatus; + l_pErrorLogEntry->NumberOfStrings = l_nDataItem; + l_pErrorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET) + l_pErrorLogEntry->DumpDataSize; + l_Ptr = (UCHAR*)l_pErrorLogEntry + l_pErrorLogEntry->StringOffset; + if ( l_Size ) + memcpy( l_Ptr, l_Buf, l_Size ); + + /* Write the packet */ + IoWriteErrorLogEntry(l_pErrorLogEntry); + + } /* OK */ + +} /* WriteEventLogEntry */ + +// bsize is to be a strlen(src) +// dest has to have enough place, i.e at least (2*strlen(src) + 2) +void __ansi_to_wchar( USHORT *dest, UCHAR *src, int bsize) +{ + int i; + + for (i=0; ipdev->p_self_do, (ULONG)EVENT_MLX4_ANY_ERROR, 0, 0, wbuf, 0, 0 ); +} + +VOID +mlx4_dbg( + IN struct mlx4_dev * mdev, + IN char* format, + ... + ) +{ +#if DBG + va_list list; + UCHAR buf[MAX_BUFFER_SIZE]; + UNUSED_PARAM(mdev); + + // print to Debugger + va_start(list, format); + buf[MAX_BUFFER_SIZE - 1] = '\0'; + RtlStringCbVPrintfA( (char*)buf, sizeof(buf), format, list); + cl_dbg_out( "%s\n", (char*)buf ); + va_end(list); +#else + UNUSED_PARAM(mdev); + UNUSED_PARAM(format); +#endif //DBG +} + +VOID +dev_err( + IN struct mlx4_dev ** mdev, + IN char* format, + ... + ) +{ + va_list list; + UCHAR buf[MAX_BUFFER_SIZE]; + WCHAR wbuf[MAX_BUFFER_SIZE]; + + if (mdev == NULL) { + ASSERT(mdev != NULL); + return; + } + + // print to Debugger + va_start(list, format); + buf[MAX_BUFFER_SIZE - 1] = '\0'; + RtlStringCbVPrintfA( (char*)buf, sizeof(buf), format, list); + cl_dbg_out( "%s\n", (char*)buf ); + va_end(list); + + // print to Event Log + RtlStringCchPrintfW(wbuf, sizeof(wbuf)/sizeof(wbuf[0]), L"%S", buf); + WriteEventLogEntryStr( (*mdev)->pdev->p_self_do, (ULONG)EVENT_MLX4_ANY_ERROR, 0, 0, wbuf, 0, 0 ); +} + +VOID +dev_info( + IN struct mlx4_dev ** p_mdev, + IN char* format, + ... + ) +{ +#if DBG + va_list list; + UCHAR buf[MAX_BUFFER_SIZE]; + UNUSED_PARAM(p_mdev); + + // print to Debugger + va_start(list, format); + buf[MAX_BUFFER_SIZE - 1] = '\0'; + RtlStringCbVPrintfA( (char*)buf, sizeof(buf), format, list); + cl_dbg_out( "%s\n", (char*)buf ); + va_end(list); +#else + UNUSED_PARAM(p_mdev); + UNUSED_PARAM(format); +#endif +} + + + diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/core/l2w_memory.c b/branches/WOF2-3/hw/mlx4/kernel/bus/core/l2w_memory.c new file mode 100644 index 00000000..49b8c92d --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/core/l2w_memory.c @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2004 Topspin Corporation. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: mt_memory.c 2020 2007-05-01 09:29:10Z leonid $ + */ +#include "l2w.h" +#include + +#if defined (EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "l2w_memory.tmh" +#endif + + + +void *alloc_cont_mem( + IN struct pci_dev *pdev, + IN unsigned long size, + OUT dma_addr_t*p_dma_addr) +{ + void *va; + DMA_ADAPTER *p_adapter = pdev->p_dma_adapter; + PHYSICAL_ADDRESS pa = {0}; + + ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); + + memset( p_dma_addr, 0, sizeof(dma_addr_t) ); + + if (!size) + return NULL; + + va = p_adapter->DmaOperations->AllocateCommonBuffer( + p_adapter, (ULONG)size, &pa, FALSE ); + if (va) { + p_dma_addr->da = pa.QuadPart; + p_dma_addr->va = va; + p_dma_addr->sz = (ULONG)size; + } + + return va; +} + +void free_cont_mem( + IN struct pci_dev *pdev, + IN dma_addr_t*p_dma_addr) +{ + PHYSICAL_ADDRESS pa; + DMA_ADAPTER *p_adapter = pdev->p_dma_adapter; + + ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); + + pa.QuadPart = p_dma_addr->da; + p_adapter->DmaOperations->FreeCommonBuffer( + p_adapter, (ULONG)p_dma_addr->sz, pa, p_dma_addr->va, FALSE ); +} + +void * +dma_alloc_coherent( struct mlx4_dev **dev, size_t size, + dma_addr_t *p_dma_addr, gfp_t gfp ) +{ + UNUSED_PARAM(gfp); + + if (!size) + return NULL; + return alloc_cont_mem( (*dev)->pdev, (unsigned long)size, p_dma_addr ); +} + +void +dma_free_coherent( struct mlx4_dev **dev, size_t size, + void *vaddr, dma_addr_t dma_addr) +{ + UNUSED_PARAM(size); + UNUSED_PARAM(vaddr); + ASSERT(size == dma_addr.sz); + ASSERT(vaddr == dma_addr.va); + free_cont_mem( (*dev)->pdev, &dma_addr ); +} + +void +pci_free_consistent( struct pci_dev *pdev, size_t size, + void *vaddr, dma_addr_t dma_addr) +{ + dma_free_coherent( &pdev->dev, size, vaddr, dma_addr ); +} + + + diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/core/l2w_radix.c b/branches/WOF2-3/hw/mlx4/kernel/bus/core/l2w_radix.c new file mode 100644 index 00000000..abea412c --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/core/l2w_radix.c @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: radix.c 1611 2006-08-20 14:48:55Z sleybo $ + */ + +#include "l2w.h" +#include "errno.h" + +int radix_tree_insert(struct radix_tree_root *root, + unsigned long index, void *item) +{ + if ( NULL == cl_map_insert( &root->map, (const uint64_t)index, item ) ) + return -EFAULT; + return 0; +} + +void *radix_tree_lookup(struct radix_tree_root *root, + unsigned long index) +{ + void* item = cl_map_get( &root->map, (const uint64_t)index ); + return item; +} + +void *radix_tree_delete(struct radix_tree_root *root, + unsigned long index) +{ + void* item = cl_map_remove( &root->map, (const uint64_t)index ); + return item; +} + +cl_status_t radix_tree_create(struct radix_tree_root *root, + gfp_t gfp_mask) +{ +#define MIN_ITEMS 32 + cl_status_t cl_status; + UNUSED_PARAM(gfp_mask); + + cl_map_construct( &root->map ); + cl_status = cl_map_init( &root->map, MIN_ITEMS ); + return cl_status; +} + +void radix_tree_destroy(struct radix_tree_root *root ) +{ + cl_map_destroy( &root->map ); +} + diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/core/l2w_umem.c b/branches/WOF2-3/hw/mlx4/kernel/bus/core/l2w_umem.c new file mode 100644 index 00000000..e766b953 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/core/l2w_umem.c @@ -0,0 +1,186 @@ +#include +#include "l2w.h" +#include "ib_verbs.h" + +#if defined (EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "l2w_umem.tmh" +#endif + +/** + * ib_umem_release - release memory pinned with ib_umem_get + * @umem: umem struct to release + */ +void ib_umem_release(struct ib_umem *p_ib_umem) +{ + MLX4_ENTER(MLX4_DBG_MEMORY); + if (p_ib_umem->secure_handle) { + __try { + MmUnsecureVirtualMemory( p_ib_umem->secure_handle ); + p_ib_umem->secure_handle = NULL; + } + __except (EXCEPTION_EXECUTE_HANDLER) { + NTSTATUS Status = GetExceptionCode(); + UNUSED_PARAM_WOWPP(Status); + MLX4_PRINT(TRACE_LEVEL_ERROR ,MLX4_DBG_MEMORY , + ("Exception 0x%x on MmUnsecureVirtualMemory(), addr %I64x, size %I64x, seg_num %d, nr_pages %d\n", + Status, p_ib_umem->iobuf.va, (u64)p_ib_umem->iobuf.size, + p_ib_umem->iobuf.seg_num, p_ib_umem->iobuf.nr_pages )); + } + } + if (p_ib_umem->iobuf_used) + iobuf_deregister_with_cash(&p_ib_umem->iobuf); + kfree(p_ib_umem); + MLX4_EXIT(MLX4_DBG_MEMORY); +} + + +/** + * ib_umem_get - Pin and DMA map userspace memory. + * @context: userspace context to pin memory for + * @addr: userspace virtual address to start at + * @size: length of region to pin + * @access: IB_ACCESS_xxx flags for memory being pinned + */ +struct ib_umem *ib_umem_get(struct ib_ucontext *context, u64 addr, + size_t size, enum ib_access_flags access, boolean_t secure) +{ + int err; + struct ib_umem *p_ib_umem; + + MLX4_ENTER(MLX4_DBG_MEMORY); + + // create the object + p_ib_umem = kzalloc(sizeof *p_ib_umem, GFP_KERNEL); + if (!p_ib_umem) + goto err_nomem; + + p_ib_umem->p_uctx = context; + p_ib_umem->page_size = PAGE_SIZE; + + // register the memory + iobuf_init( addr, (u64)size, !!context, &p_ib_umem->iobuf); + err = iobuf_register_with_cash( addr, (u64)size, !!context, + &access, &p_ib_umem->iobuf ); + if (err) + goto err_reg_mem; + p_ib_umem->iobuf_used = TRUE; + + // TODO: map the memory for DMA + + // secure memory + if (!context || !secure) + goto done; + __try { + p_ib_umem->secure_handle = MmSecureVirtualMemory ( + (PVOID)(ULONG_PTR)addr, size, + (access & IB_ACCESS_LOCAL_WRITE) ? PAGE_READWRITE : PAGE_READONLY ); + if (p_ib_umem->secure_handle == NULL) + goto err_secure; + } + __except (EXCEPTION_EXECUTE_HANDLER) { + NTSTATUS Status = GetExceptionCode(); + UNUSED_PARAM_WOWPP(Status); + MLX4_PRINT(TRACE_LEVEL_ERROR ,MLX4_DBG_MEMORY , + ("Exception 0x%x on MmSecureVirtualMemory(), addr %I64x, size %I64x, access %#x\n", + Status, addr, (u64)size, access )); + goto err_secure; + } + goto done; + +err_secure: + iobuf_deregister(&p_ib_umem->iobuf); + +err_reg_mem: + kfree(p_ib_umem); + +err_nomem: + p_ib_umem = ERR_PTR(-ENOMEM); + +done: + MLX4_EXIT(MLX4_DBG_MEMORY); + return p_ib_umem; +} + +int ib_umem_page_count(struct ib_umem *p_ib_umem) +{ + return (int)p_ib_umem->iobuf.nr_pages; +} + +dma_addr_t ib_umem_get_dma(struct ib_umem *p_ib_umem) +{ + u64 pages[1] = { 0 }; + iobuf_iter_t iobuf_iter; + dma_addr_t dma_addr = { 0, 0 , 0 }; + + iobuf_iter_init( &p_ib_umem->iobuf, &iobuf_iter ); + iobuf_get_tpt_seg( &p_ib_umem->iobuf, &iobuf_iter, 1, pages ); + // TODO: convert phys address to DMA one + dma_addr.da = pages[0]; + + return dma_addr; +} + + +// Returns: 0 on success, -ENOMEM or -EACCESS or -EFAULT on error +int ib_umem_map( + IN u64 va, + IN u64 size, + IN ib_access_t acc, + OUT PMDL *mdl, + OUT void **kva) +{ + PMDL p_mdl; + int rc = 0; + LOCK_OPERATION lock_op = (acc & IB_AC_LOCAL_WRITE) ? IoModifyAccess : IoReadAccess; + + p_mdl = IoAllocateMdl( (PVOID)(ULONG_PTR)va, (ULONG)size, FALSE,FALSE,NULL); + if (p_mdl == NULL) { + rc = -ENOMEM; + goto err_alloc_mdl; + } + + __try { + MmProbeAndLockPages( p_mdl, UserMode, lock_op ); /* lock memory */ + } + __except (EXCEPTION_EXECUTE_HANDLER) { + MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_MEMORY, + ("MOSAL_iobuf_register: Exception 0x%x on MmProbeAndLockPages(), va %I64d, sz %I64d\n", + GetExceptionCode(), va, size)); + rc = -EACCES; + goto err_probe; + } + + *kva = MmMapLockedPagesSpecifyCache( p_mdl, + KernelMode, MmNonCached, NULL, FALSE, NormalPagePriority ); + if (*kva == NULL) { + MLX4_PRINT(TRACE_LEVEL_ERROR ,MLX4_DBG_MEMORY ,("MmMapLockedPagesSpecifyCache failed\n")); + rc = -EFAULT; + goto err_map; + } + + *mdl = p_mdl; + return 0; + +err_map: + MmUnlockPages(p_mdl); +err_probe: + IoFreeMdl(p_mdl); +err_alloc_mdl: + return rc; +} + +void ib_umem_unmap( + IN PMDL p_mdl, + IN void *kva) +{ + if (kva) { + MmUnmapLockedPages( kva, p_mdl ); + MmUnlockPages(p_mdl); + IoFreeMdl(p_mdl); + } +} + + diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/core/makefile b/branches/WOF2-3/hw/mlx4/kernel/bus/core/makefile new file mode 100644 index 00000000..d4938551 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/core/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\..\..\inc\openib.def diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/core/pa_cash.c b/branches/WOF2-3/hw/mlx4/kernel/bus/core/pa_cash.c new file mode 100644 index 00000000..26420c54 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/core/pa_cash.c @@ -0,0 +1,366 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies Ltd. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: mlnx_uvp_cq.c 1611 2006-08-20 14:48:55Z sleybo $ + */ +#include +#include "l2w.h" +#include "pa_cash.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "pa_cash.tmh" +#endif + +/////////////////////////////////////////////////////////////////////////// +// +// RESTRICTIONS +// +/////////////////////////////////////////////////////////////////////////// + +#ifdef _WIN64 +#define MAX_PAGES_SUPPORTED (64 * 1024 * 1024) // 256 GB +#else +#define MAX_PAGES_SUPPORTED (16 * 1024 * 1024) // 64 GB +#endif + +#define FREE_LIST_TRESHOLD 256 // max number of pages in free list + +/////////////////////////////////////////////////////////////////////////// +// +// CONSTANTS +// +/////////////////////////////////////////////////////////////////////////// + +#define PA_TABLE_ENTRY_SIZE sizeof(pa_table_entry_t) +#define PA_TABLE_ENTRY_NUM (PAGE_SIZE / PA_TABLE_ENTRY_SIZE) +#define PA_TABLE_SIZE (PA_TABLE_ENTRY_SIZE * PA_TABLE_ENTRY_NUM) + +#define PA_DIR_ENTRY_SIZE sizeof(pa_dir_entry_t) +#define PA_DIR_ENTRY_NUM (MAX_PAGES_SUPPORTED /PA_TABLE_ENTRY_NUM) +#define PA_DIR_SIZE (PA_DIR_ENTRY_SIZE * PA_DIR_ENTRY_NUM) + + +/////////////////////////////////////////////////////////////////////////// +// +// STRUCTURES +// +/////////////////////////////////////////////////////////////////////////// + +typedef struct { + int ref_cnt; +} pa_table_entry_t; + +typedef struct { + pa_table_entry_t *pa_te; /* pointer to one page of pa_table_entry_t elements */ + int used; /* number of pa_table_entry_t elements, used now. When 0 - the page may be freed */ +} pa_dir_entry_t; + +typedef struct pa_cash_s { + pa_dir_entry_t *pa_dir; + SINGLE_LIST_ENTRY free_list_hdr; + uint32_t free_nr_pages; + uint32_t free_list_threshold; + uint32_t max_nr_pages; + uint32_t cur_nr_pages; +} pa_cash_t; + + + +/////////////////////////////////////////////////////////////////////////// +// +// GLOBALS +// +/////////////////////////////////////////////////////////////////////////// + +DEFINE_MUTEX(g_pa_mutex); +u64 g_pa[1024]; +pa_cash_t g_cash; + + +/////////////////////////////////////////////////////////////////////////// +// +// STATIC FUNCTIONS +// +/////////////////////////////////////////////////////////////////////////// + +static uint32_t pa_calc_threshold() +{ + // threshold expresses the max length of free pages list, which gets released only at driver unload time + // so it can be calculated to be proportional to the system memory size + return FREE_LIST_TRESHOLD; +} + +static pa_table_entry_t *pa_alloc_page() +{ + pa_table_entry_t *pa_te; + + /* take from the list of reserved if it is not empty */ + if (g_cash.free_nr_pages) { + pa_te = (pa_table_entry_t *)PopEntryList( &g_cash.free_list_hdr ); + ((SINGLE_LIST_ENTRY*)pa_te)->Next = NULL; + g_cash.free_nr_pages--; + } + else /* allocate new page */ + pa_te = (pa_table_entry_t *)kzalloc( PA_TABLE_SIZE, GFP_KERNEL ); + + return pa_te; +} + +static void pa_free_page(pa_table_entry_t *pa_te) +{ + if (g_cash.free_nr_pages < g_cash.free_list_threshold) { + PushEntryList( &g_cash.free_list_hdr, (SINGLE_LIST_ENTRY*)pa_te ); + g_cash.free_nr_pages++; + } + else + kfree(pa_te); +} + +static pa_table_entry_t * pa_get_page(uint32_t ix) +{ + pa_table_entry_t *pa_te = g_cash.pa_dir[ix / PA_TABLE_ENTRY_NUM].pa_te; + + /* no this page_table - add a new one */ + if (!pa_te) { + pa_te = pa_alloc_page(); + if (!pa_te) + return NULL; + g_cash.pa_dir[ix / PA_TABLE_ENTRY_NUM].pa_te = pa_te; + g_cash.pa_dir[ix / PA_TABLE_ENTRY_NUM].used = 0; + g_cash.cur_nr_pages++; + } + + return pa_te; +} + +static void pa_put_page(uint32_t ix) +{ + pa_free_page(g_cash.pa_dir[ix / PA_TABLE_ENTRY_NUM].pa_te); + g_cash.pa_dir[ix / PA_TABLE_ENTRY_NUM].pa_te = NULL; + g_cash.cur_nr_pages--; +} + +static int pa_add_pa(uint64_t pa) +{ + uint32_t ix = (uint32_t)(pa >> PAGE_SHIFT); + pa_table_entry_t *pa_te; + + /* or pa is incorrect or memory that big is not supported */ + if (ix > g_cash.max_nr_pages) { + ASSERT(FALSE); + return -EFAULT; + } + + /* get page address */ + pa_te = pa_get_page(ix); + if (!pa_te) + return -ENOMEM; + + /* register page address */ + if (!pa_te[ix % PA_TABLE_ENTRY_NUM].ref_cnt) + ++g_cash.pa_dir[ix / PA_TABLE_ENTRY_NUM].used; + ++pa_te[ix % PA_TABLE_ENTRY_NUM].ref_cnt; + + return 0; +} + + +static int pa_rmv_pa(uint64_t pa) +{ + uint32_t ix = (uint32_t)(pa >> PAGE_SHIFT); + pa_table_entry_t *pa_te; + + /* or pa is incorrect or memory that big is not supported */ + if (ix > g_cash.max_nr_pages) { + ASSERT(FALSE); + return -EFAULT; + } + + pa_te = g_cash.pa_dir[ix / PA_TABLE_ENTRY_NUM].pa_te; + + /* no this page_table - error*/ + if (!pa_te) { + ASSERT(FALSE); + return -EFAULT; + } + + /* deregister page address */ + --pa_te[ix % PA_TABLE_ENTRY_NUM].ref_cnt; + ASSERT(pa_te[ix % PA_TABLE_ENTRY_NUM].ref_cnt >= 0); + + /* release the page on need */ + if (!pa_te[ix % PA_TABLE_ENTRY_NUM].ref_cnt) + --g_cash.pa_dir[ix / PA_TABLE_ENTRY_NUM].used; + if (!g_cash.pa_dir[ix / PA_TABLE_ENTRY_NUM].used) + pa_put_page(ix); + + return 0; +} + + + +/////////////////////////////////////////////////////////////////////////// +// +// PUBLIC FUNCTIONS +// +/////////////////////////////////////////////////////////////////////////// + + +int pa_register(iobuf_t *iobuf_p) +{ + int i,j,n; + iobuf_iter_t iobuf_iter; + + iobuf_iter_init( iobuf_p, &iobuf_iter ); + n = 0; + for (;;) { + i = iobuf_get_tpt_seg( iobuf_p, &iobuf_iter, + sizeof(g_pa) / sizeof (u64), g_pa ); + if (!i) + break; + for (j=0; j> PAGE_SHIFT); + pa_table_entry_t *pa_te; + + /* or pa is incorrect or memory that big is not supported */ + if (ix > g_cash.max_nr_pages) { + ASSERT(FALSE); + return -EFAULT; + } + + pa_te = g_cash.pa_dir[ix / PA_TABLE_ENTRY_NUM].pa_te; + + /* no this page_table */ + if (!pa_te) + return 0; + + return pa_te[ix % PA_TABLE_ENTRY_NUM].ref_cnt; +} + +int pa_cash_init() +{ + void *pa_dir; + pa_dir = kzalloc(PA_DIR_SIZE, GFP_KERNEL); + + if (!pa_dir) + return -ENOMEM; + g_cash.pa_dir = pa_dir; + g_cash.max_nr_pages = PA_TABLE_ENTRY_NUM * PA_DIR_ENTRY_NUM; + g_cash.free_list_hdr.Next = NULL; + g_cash.cur_nr_pages = 0; + g_cash.free_nr_pages = 0; + g_cash.free_list_threshold = pa_calc_threshold(); + mutex_init(&g_pa_mutex); + return 0; +} + diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/core/pa_cash.h b/branches/WOF2-3/hw/mlx4/kernel/bus/core/pa_cash.h new file mode 100644 index 00000000..a231c890 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/core/pa_cash.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies Ltd. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: mlnx_uvp_cq.c 1611 2006-08-20 14:48:55Z sleybo $ + */ + +#include "iobuf.h" + +extern struct mutex g_pa_mutex; + +int pa_cash_init(); + +void pa_cash_release(); + +int pa_is_registered(uint64_t pa); + +int pa_register(iobuf_t *iobuf_p); + +void pa_deregister(iobuf_t *iobuf_p); + +void pa_cash_print(); + diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/core/packer.c b/branches/WOF2-3/hw/mlx4/kernel/bus/core/packer.c new file mode 100644 index 00000000..5b0da952 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/core/packer.c @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2004 Topspin Corporation. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: packer.c 1349 2004-12-16 21:09:43Z roland $ + */ + +#include "l2w.h" +#include "ib_pack.h" + +static u64 value_read(int offset, int size, u8 *structure) +{ + switch (size) { + case 1: return *(u8 *) (structure + offset); + case 2: return be16_to_cpup((__be16 *) (structure + offset)); + case 4: return be32_to_cpup((__be32 *) (structure + offset)); + case 8: return be64_to_cpup((__be64 *) (structure + offset)); + default: + printk(KERN_WARNING "Field size %d bits not handled\n", size * 8); + return 0; + } +} + +/** + * ib_pack - Pack a structure into a buffer + * @desc:Array of structure field descriptions + * @desc_len:Number of entries in @desc + * @structure:Structure to pack from + * @buf:Buffer to pack into + * + * ib_pack() packs a list of structure fields into a buffer, + * controlled by the array of fields in @desc. + */ +void ib_pack(const struct ib_field *desc, + int desc_len, + void *structure, + u8 *buf) +{ + int i; + + for (i = 0; i < desc_len; ++i) { + if (desc[i].size_bits <= 32) { + int shift; + u32 val; + __be32 mask; + __be32 *addr; + + shift = 32 - desc[i].offset_bits - desc[i].size_bits; + if (desc[i].struct_size_bytes) + val = (u32)(value_read((int)desc[i].struct_offset_bytes, + (int)desc[i].struct_size_bytes, + structure) << shift); + else + val = 0; + + mask = cpu_to_be32(((1ull << desc[i].size_bits) - 1) << shift); + addr = (__be32 *) buf + desc[i].offset_words; + *addr = (*addr & ~mask) | (cpu_to_be32(val) & mask); + } else if (desc[i].size_bits <= 64) { + int shift; + u64 val; + __be64 mask; + __be64 *addr; + + shift = 64 - desc[i].offset_bits - desc[i].size_bits; + if (desc[i].struct_size_bytes) + val = value_read((int)desc[i].struct_offset_bytes, + (int)desc[i].struct_size_bytes, + structure) << shift; + else + val = 0; + + mask = cpu_to_be64((~0ull >> (64 - desc[i].size_bits)) << shift); + addr = (__be64 *) ((__be32 *) buf + desc[i].offset_words); + *addr = (*addr & ~mask) | (cpu_to_be64(val) & mask); + } else { + if (desc[i].offset_bits % 8 || + desc[i].size_bits % 8) { + printk(KERN_WARNING "Structure field %s of size %d " + "bits is not byte-aligned\n", + desc[i].field_name, desc[i].size_bits); + } + + if (desc[i].struct_size_bytes) + memcpy(buf + desc[i].offset_words * 4 + + desc[i].offset_bits / 8, + (u8*)structure + desc[i].struct_offset_bytes, + desc[i].size_bits / 8); + else + memset(buf + desc[i].offset_words * 4 + + desc[i].offset_bits / 8, + 0, + desc[i].size_bits / 8); + } + } +} +EXPORT_SYMBOL(ib_pack); + +static void value_write(int offset, int size, u64 val, u8 *structure) +{ + switch (size * 8) { + case 8: *( u8 *) (structure + offset) = (u8)val; break; + case 16: *(__be16 *) (structure + offset) = cpu_to_be16(val); break; + case 32: *(__be32 *) (structure + offset) = cpu_to_be32(val); break; + case 64: *(__be64 *) (structure + offset) = cpu_to_be64(val); break; + default: + printk(KERN_WARNING "Field size %d bits not handled\n", size * 8); + } +} + +/** + * ib_unpack - Unpack a buffer into a structure + * @desc:Array of structure field descriptions + * @desc_len:Number of entries in @desc + * @buf:Buffer to unpack from + * @structure:Structure to unpack into + * + * ib_pack() unpacks a list of structure fields from a buffer, + * controlled by the array of fields in @desc. + */ +void ib_unpack(const struct ib_field *desc, + int desc_len, + void *buf, + void *structure) +{ + int i; + + for (i = 0; i < desc_len; ++i) { + if (!desc[i].struct_size_bytes) + continue; + + if (desc[i].size_bits <= 32) { + int shift; + u32 val; + u32 mask; + __be32 *addr; + + shift = 32 - desc[i].offset_bits - desc[i].size_bits; + mask = ((1ull << desc[i].size_bits) - 1) << shift; + addr = (__be32 *) buf + desc[i].offset_words; + val = (be32_to_cpup(addr) & mask) >> shift; + value_write((int)desc[i].struct_offset_bytes, + (int)desc[i].struct_size_bytes, + val, + structure); + } else if (desc[i].size_bits <= 64) { + int shift; + u64 val; + u64 mask; + __be64 *addr; + + shift = 64 - desc[i].offset_bits - desc[i].size_bits; + mask = (~0ull >> (64 - desc[i].size_bits)) << shift; + addr = (__be64 *) buf + desc[i].offset_words; + val = (be64_to_cpup(addr) & mask) >> shift; + value_write((int)desc[i].struct_offset_bytes, + (int)desc[i].struct_size_bytes, + val, + structure); + } else { + if (desc[i].offset_bits % 8 || + desc[i].size_bits % 8) { + printk(KERN_WARNING "Structure field %s of size %d " + "bits is not byte-aligned\n", + desc[i].field_name, desc[i].size_bits); + } + + memcpy((u8*)structure + desc[i].struct_offset_bytes, + (u8*)buf + desc[i].offset_words * 4 + + desc[i].offset_bits / 8, + desc[i].size_bits / 8); + } + } +} +EXPORT_SYMBOL(ib_unpack); diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/core/ud_header.c b/branches/WOF2-3/hw/mlx4/kernel/bus/core/ud_header.c new file mode 100644 index 00000000..3585fef2 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/core/ud_header.c @@ -0,0 +1,380 @@ +/* + * Copyright (c) 2004 Topspin Corporation. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: ud_header.c 1349 2004-12-16 21:09:43Z roland $ + */ + +#include "l2w.h" +#include "ib_pack.h" + +#define STRUCT_FIELD(header, field) \ + .struct_offset_bytes = offsetof(struct ib_unpacked_ ## header, field), \ + .struct_size_bytes = sizeof ((struct ib_unpacked_ ## header *) 0)->field, \ + .field_name = #header ":" #field + +#define STRUCT_FIELD_INIT(header, field,ow,ob,sb) \ + offsetof(struct ib_unpacked_ ## header, field), \ + sizeof ((struct ib_unpacked_ ## header *) 0)->field, \ + ow,ob,sb, \ + #header ":" #field + +#define STRUCT_FIELD_INITR(ow,ob,sb) \ + 0, 0, ow, ob, sb, "reserved" + +static const struct ib_field lrh_table[] = { + { STRUCT_FIELD_INIT(lrh, virtual_lane, 0, 0, 4) }, + { STRUCT_FIELD_INIT(lrh, link_version, 0, 4, 4) }, + { STRUCT_FIELD_INIT(lrh, service_level, 0, 8, 4) }, + { STRUCT_FIELD_INITR(0,12,2) }, + { STRUCT_FIELD_INIT(lrh, link_next_header, 0, 14, 2) }, + { STRUCT_FIELD_INIT(lrh, destination_lid, 0, 16, 16) }, + { STRUCT_FIELD_INITR(1,0,5) }, + { STRUCT_FIELD_INIT(lrh, packet_length, 1, 5, 11) }, + { STRUCT_FIELD_INIT(lrh, source_lid, 1, 16, 16) } +}; + +static const struct ib_field eth_table[] = { + { STRUCT_FIELD_INIT(eth, dmac_h, 0, 0, 32) }, + { STRUCT_FIELD_INIT(eth, dmac_l, 1, 0, 16) }, + { STRUCT_FIELD_INIT(eth, smac_h, 1, 16,16) }, + { STRUCT_FIELD_INIT(eth, smac_l, 2, 0 ,32) }, + { STRUCT_FIELD_INIT(eth, type, 3, 0, 16)} +}; + + +static const struct ib_field grh_table[] = { + { STRUCT_FIELD_INIT(grh, ip_version, 0, 0, 4) }, + { STRUCT_FIELD_INIT(grh, traffic_class, 0, 4, 8) }, + { STRUCT_FIELD_INIT(grh, flow_label, 0, 12, 20) }, + { STRUCT_FIELD_INIT(grh, payload_length, 1, 0, 16) }, + { STRUCT_FIELD_INIT(grh, next_header, 1, 16, 8) }, + { STRUCT_FIELD_INIT(grh, hop_limit, 1, 24, 8) }, + { STRUCT_FIELD_INIT(grh, source_gid, 2, 0, 128) }, + { STRUCT_FIELD_INIT(grh, destination_gid, 6, 0, 128) } +}; + +static const struct ib_field bth_table[] = { + { STRUCT_FIELD_INIT(bth, opcode, 0, 0, 8) }, + { STRUCT_FIELD_INIT(bth, solicited_event, 0, 8, 1) }, + { STRUCT_FIELD_INIT(bth, mig_req, 0, 9, 1) }, + { STRUCT_FIELD_INIT(bth, pad_count, 0, 10, 2) }, + { STRUCT_FIELD_INIT(bth, transport_header_version, 0, 12, 4) }, + { STRUCT_FIELD_INIT(bth, pkey, 0, 16, 16) }, + { STRUCT_FIELD_INITR(1,0,8) }, + { STRUCT_FIELD_INIT(bth, destination_qpn, 1, 8, 24) }, + { STRUCT_FIELD_INIT(bth, ack_req, 2, 0, 1) }, + { STRUCT_FIELD_INITR(2,1,7) }, + { STRUCT_FIELD_INIT(bth, psn, 2, 8, 24) } +}; + +static const struct ib_field deth_table[] = { + { STRUCT_FIELD_INIT(deth, qkey, 0, 0, 32) }, + { STRUCT_FIELD_INITR(1,0,8) }, + { STRUCT_FIELD_INIT(deth, source_qpn, 1, 8, 24) } +}; + +/** + * ib_ud_header_init - Initialize UD header structure + * @payload_bytes:Length of packet payload + * @grh_present:GRH flag (if non-zero, GRH will be included) + * @header:Structure to initialize + * + * ib_ud_header_init() initializes the lrh.link_version, lrh.link_next_header, + * lrh.packet_length, grh.ip_version, grh.payload_length, + * grh.next_header, bth.opcode, bth.pad_count and + * bth.transport_header_version fields of a &struct ib_ud_header given + * the payload length and whether a GRH will be included. + */ +void ib_ud_header_init(int payload_bytes, + int grh_present, + struct ib_ud_header *header) +{ + int header_len; + u16 packet_length; + + memset(header, 0, sizeof *header); + + header_len = + IB_LRH_BYTES + + IB_BTH_BYTES + + IB_DETH_BYTES; + if (grh_present) { + header_len += IB_GRH_BYTES; + } + + header->lrh.link_version = 0; + header->lrh.link_next_header = + grh_present ? IB_LNH_IBA_GLOBAL : IB_LNH_IBA_LOCAL; + packet_length = (u16)((IB_LRH_BYTES + + IB_BTH_BYTES + + IB_DETH_BYTES + + payload_bytes + + 4 + /* ICRC */ + 3) / 4); /* round up */ + + header->grh_present = grh_present; + if (grh_present) { + packet_length += IB_GRH_BYTES / 4; + header->grh.ip_version = 6; + header->grh.payload_length = + cpu_to_be16((IB_BTH_BYTES + + IB_DETH_BYTES + + payload_bytes + + 4 + /* ICRC */ + 3) & ~3); /* round up */ + header->grh.next_header = 0x1b; + } + + header->lrh.packet_length = cpu_to_be16(packet_length); + + if (header->immediate_present) + header->bth.opcode = IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE; + else + header->bth.opcode = IB_OPCODE_UD_SEND_ONLY; + header->bth.pad_count = (u8)((4 - payload_bytes) & 3); + header->bth.transport_header_version = 0; +} +EXPORT_SYMBOL(ib_ud_header_init); + +/** + * ib_ud_header_pack - Pack UD header struct into wire format + * @header:UD header struct + * @buf:Buffer to pack into + * + * ib_ud_header_pack() packs the UD header structure @header into wire + * format in the buffer @buf. + */ +int ib_ud_header_pack(struct ib_ud_header *header, + u8 *buf) +{ + int len = 0; + + ib_pack(lrh_table, ARRAY_SIZE(lrh_table), + &header->lrh, buf); + len += IB_LRH_BYTES; + + if (header->grh_present) { + ib_pack(grh_table, ARRAY_SIZE(grh_table), + &header->grh, buf + len); + len += IB_GRH_BYTES; + } + + ib_pack(bth_table, ARRAY_SIZE(bth_table), + &header->bth, buf + len); + len += IB_BTH_BYTES; + + ib_pack(deth_table, ARRAY_SIZE(deth_table), + &header->deth, buf + len); + len += IB_DETH_BYTES; + + if (header->immediate_present) { + memcpy(buf + len, &header->immediate_data, sizeof header->immediate_data); + len += sizeof header->immediate_data; + } + + return len; +} +EXPORT_SYMBOL(ib_ud_header_pack); + +/** + * ib_ud_header_unpack - Unpack UD header struct from wire format + * @header:UD header struct + * @buf:Buffer to pack into + * + * ib_ud_header_pack() unpacks the UD header structure @header from wire + * format in the buffer @buf. + */ +int ib_ud_header_unpack(u8 *buf, + struct ib_ud_header *header) +{ + ib_unpack(lrh_table, ARRAY_SIZE(lrh_table), + buf, &header->lrh); + buf += IB_LRH_BYTES; + + if (header->lrh.link_version != 0) { + printk(KERN_WARNING "Invalid LRH.link_version %d\n", + header->lrh.link_version); + return -EINVAL; + } + + switch (header->lrh.link_next_header) { + case IB_LNH_IBA_LOCAL: + header->grh_present = 0; + break; + + case IB_LNH_IBA_GLOBAL: + header->grh_present = 1; + ib_unpack(grh_table, ARRAY_SIZE(grh_table), + buf, &header->grh); + buf += IB_GRH_BYTES; + + if (header->grh.ip_version != 6) { + printk(KERN_WARNING "Invalid GRH.ip_version %d\n", + header->grh.ip_version); + return -EINVAL; + } + if (header->grh.next_header != 0x1b) { + printk(KERN_WARNING "Invalid GRH.next_header 0x%02x\n", + header->grh.next_header); + return -EINVAL; + } + break; + + default: + printk(KERN_WARNING "Invalid LRH.link_next_header %d\n", + header->lrh.link_next_header); + return -EINVAL; + } + + ib_unpack(bth_table, ARRAY_SIZE(bth_table), + buf, &header->bth); + buf += IB_BTH_BYTES; + + switch (header->bth.opcode) { + case IB_OPCODE_UD_SEND_ONLY: + header->immediate_present = 0; + break; + case IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE: + header->immediate_present = 1; + break; + default: + printk(KERN_WARNING "Invalid BTH.opcode 0x%02x\n", + header->bth.opcode); + return -EINVAL; + } + + if (header->bth.transport_header_version != 0) { + printk(KERN_WARNING "Invalid BTH.transport_header_version %d\n", + header->bth.transport_header_version); + return -EINVAL; + } + + ib_unpack(deth_table, ARRAY_SIZE(deth_table), + buf, &header->deth); + buf += IB_DETH_BYTES; + + if (header->immediate_present) + memcpy(&header->immediate_data, buf, sizeof header->immediate_data); + + return 0; +} +EXPORT_SYMBOL(ib_ud_header_unpack); + +/** + * ib_rdmaoe_ud_header_init - Initialize UD header structure + * @payload_bytes:Length of packet payload + * @grh_present:GRH flag (if non-zero, GRH will be included) + * @header:Structure to initialize + * + * ib_rdmaoe_ud_header_init() initializes the grh.ip_version, grh.payload_length, + * grh.next_header, bth.opcode, bth.pad_count and + * bth.transport_header_version fields of a &struct eth_ud_header given + * the payload length and whether a GRH will be included. + */ +void ib_rdmaoe_ud_header_init(int payload_bytes, + int grh_present, + struct eth_ud_header *header) +{ + int header_len; + + memset(header, 0, sizeof *header); + + header_len = + sizeof header->eth + + IB_BTH_BYTES + + IB_DETH_BYTES; + if (grh_present) + header_len += IB_GRH_BYTES; + + header->grh_present = grh_present; + if (grh_present) { + header->grh.ip_version = 6; + header->grh.payload_length = + cpu_to_be16((IB_BTH_BYTES + + IB_DETH_BYTES + + payload_bytes + + 4 + /* ICRC */ + 3) & ~3); /* round up */ + header->grh.next_header = 0x1b; + } + + if (header->immediate_present) + header->bth.opcode = IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE; + else + header->bth.opcode = IB_OPCODE_UD_SEND_ONLY; + header->bth.pad_count =(u8) ((4 - payload_bytes) & 3); + header->bth.transport_header_version = 0; +} + + + +/** + * rdmaoe_ud_header_pack - Pack UD header struct into eth wire format + * @header:UD header struct + * @buf:Buffer to pack into + * + * ib_ud_header_pack() packs the UD header structure @header into wire + * format in the buffer @buf. + */ +int rdmaoe_ud_header_pack(struct eth_ud_header *header, + void *buf) +{ + int len = 0; + + ib_pack(eth_table, ARRAY_SIZE(eth_table), + &header->eth, buf); + len += IB_ETH_BYTES; + + if (header->grh_present) { + ib_pack(grh_table, ARRAY_SIZE(grh_table), + &header->grh, (u8*)buf + len); + len += IB_GRH_BYTES; + } + + ib_pack(bth_table, ARRAY_SIZE(bth_table), + &header->bth, (u8*)buf + len); + len += IB_BTH_BYTES; + + ib_pack(deth_table, ARRAY_SIZE(deth_table), + &header->deth, (u8*)buf + len); + len += IB_DETH_BYTES; + + if (header->immediate_present) { + memcpy((u8*)buf + len, &header->immediate_data, + sizeof header->immediate_data); + len += sizeof header->immediate_data; + } + + return len; +} + + diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/core/verbs.c b/branches/WOF2-3/hw/mlx4/kernel/bus/core/verbs.c new file mode 100644 index 00000000..1f7845bf --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/core/verbs.c @@ -0,0 +1,363 @@ +/* + * Copyright (c) 2004 Mellanox Technologies Ltd. All rights reserved. + * Copyright (c) 2004 Infinicon Corporation. All rights reserved. + * Copyright (c) 2004 Intel Corporation. All rights reserved. + * Copyright (c) 2004 Topspin Corporation. All rights reserved. + * Copyright (c) 2004 Voltaire Corporation. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2005, 2006 Cisco Systems. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: verbs.c 1349 2004-12-16 21:09:43Z roland $ + */ + +#include "l2w.h" +#include "ib_verbs.h" +#include + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "device.tmh" +#endif + + +// qp_state_table +static struct { + int valid; + enum ib_qp_attr_mask req_param[IB_QPT_RAW_ETY + 1]; + enum ib_qp_attr_mask opt_param[IB_QPT_RAW_ETY + 1]; +} qst[XIB_QPS_ERR + 1][XIB_QPS_ERR + 1]; + + +void init_qp_state_tbl() +{ + memset( qst, 0, sizeof(qst) ); + + // + // XIB_QPS_RESET + // + + // XIB_QPS_RESET + qst[XIB_QPS_RESET][XIB_QPS_RESET].valid = 1; + + // XIB_QPS_ERR + qst[XIB_QPS_RESET][XIB_QPS_ERR].valid = 1; + + // XIB_QPS_INIT + + qst[XIB_QPS_RESET][XIB_QPS_INIT].valid = 1; + qst[XIB_QPS_RESET][XIB_QPS_INIT].req_param[IB_QPT_UD] = + (IB_QP_PKEY_INDEX | IB_QP_PORT | IB_QP_QKEY); + qst[XIB_QPS_RESET][XIB_QPS_INIT].req_param[IB_QPT_UC] = + (IB_QP_PKEY_INDEX | IB_QP_PORT | IB_QP_ACCESS_FLAGS); + qst[XIB_QPS_RESET][XIB_QPS_INIT].req_param[IB_QPT_RC] = + (IB_QP_PKEY_INDEX | IB_QP_PORT | IB_QP_ACCESS_FLAGS); + qst[XIB_QPS_RESET][XIB_QPS_INIT].req_param[IB_QPT_SMI] = + (IB_QP_PKEY_INDEX | IB_QP_QKEY); + qst[XIB_QPS_RESET][XIB_QPS_INIT].req_param[IB_QPT_GSI] = + (IB_QP_PKEY_INDEX | IB_QP_QKEY); + + // + // XIB_QPS_INIT + // + + // XIB_QPS_RESET + qst[XIB_QPS_INIT][XIB_QPS_RESET].valid = 1; + + // XIB_QPS_ERR + qst[XIB_QPS_INIT][XIB_QPS_ERR].valid = 1; + + // XIB_QPS_INIT + qst[XIB_QPS_INIT][XIB_QPS_INIT].valid = 1; + + qst[XIB_QPS_INIT][XIB_QPS_INIT].opt_param[IB_QPT_UD] = + (IB_QP_PKEY_INDEX | IB_QP_PORT | IB_QP_QKEY); + qst[XIB_QPS_INIT][XIB_QPS_INIT].opt_param[IB_QPT_UC] = + (IB_QP_PKEY_INDEX | IB_QP_PORT | IB_QP_ACCESS_FLAGS); + qst[XIB_QPS_INIT][XIB_QPS_INIT].opt_param[IB_QPT_RC] = + (IB_QP_PKEY_INDEX | IB_QP_PORT | IB_QP_ACCESS_FLAGS); + qst[XIB_QPS_INIT][XIB_QPS_INIT].opt_param[IB_QPT_SMI] = + (IB_QP_PKEY_INDEX | IB_QP_QKEY); + qst[XIB_QPS_INIT][XIB_QPS_INIT].opt_param[IB_QPT_GSI] = + (IB_QP_PKEY_INDEX | IB_QP_QKEY); + + // XIB_QPS_RTR + qst[XIB_QPS_INIT][XIB_QPS_RTR].valid = 1; + + qst[XIB_QPS_INIT][XIB_QPS_RTR].req_param[IB_QPT_UC] = + (IB_QP_AV | IB_QP_PATH_MTU | IB_QP_DEST_QPN | IB_QP_RQ_PSN); + qst[XIB_QPS_INIT][XIB_QPS_RTR].req_param[IB_QPT_RC] = + (IB_QP_AV | IB_QP_PATH_MTU | IB_QP_DEST_QPN | + IB_QP_RQ_PSN | IB_QP_MAX_DEST_RD_ATOMIC | IB_QP_MIN_RNR_TIMER); + + qst[XIB_QPS_INIT][XIB_QPS_RTR].opt_param[IB_QPT_UD] = + (IB_QP_PKEY_INDEX | IB_QP_QKEY); + qst[XIB_QPS_INIT][XIB_QPS_RTR].opt_param[IB_QPT_UC] = + (IB_QP_ALT_PATH | IB_QP_ACCESS_FLAGS | IB_QP_PKEY_INDEX); + qst[XIB_QPS_INIT][XIB_QPS_RTR].opt_param[IB_QPT_RC] = + (IB_QP_ALT_PATH | IB_QP_ACCESS_FLAGS | IB_QP_PKEY_INDEX); + qst[XIB_QPS_INIT][XIB_QPS_RTR].opt_param[IB_QPT_SMI] = + (IB_QP_PKEY_INDEX | IB_QP_QKEY); + qst[XIB_QPS_INIT][XIB_QPS_RTR].opt_param[IB_QPT_GSI] = + (IB_QP_PKEY_INDEX | IB_QP_QKEY); + + // + // XIB_QPS_RTR + // + + // XIB_QPS_RESET + qst[XIB_QPS_RTR][XIB_QPS_RESET].valid = 1; + + // XIB_QPS_ERR + qst[XIB_QPS_RTR][XIB_QPS_ERR].valid = 1; + + // XIB_QPS_RTS + qst[XIB_QPS_RTR][XIB_QPS_RTS].valid = 1; + + qst[XIB_QPS_RTR][XIB_QPS_RTS].req_param[IB_QPT_UD] = IB_QP_SQ_PSN; + qst[XIB_QPS_RTR][XIB_QPS_RTS].req_param[IB_QPT_UC] = IB_QP_SQ_PSN; + qst[XIB_QPS_RTR][XIB_QPS_RTS].req_param[IB_QPT_RC] = (IB_QP_TIMEOUT | + IB_QP_RETRY_CNT | IB_QP_RNR_RETRY | IB_QP_SQ_PSN | IB_QP_MAX_QP_RD_ATOMIC); + qst[XIB_QPS_RTR][XIB_QPS_RTS].req_param[IB_QPT_SMI] = IB_QP_SQ_PSN; + qst[XIB_QPS_RTR][XIB_QPS_RTS].req_param[IB_QPT_GSI] = IB_QP_SQ_PSN; + + qst[XIB_QPS_RTR][XIB_QPS_RTS].opt_param[IB_QPT_UD] = + (IB_QP_CUR_STATE | IB_QP_QKEY); + qst[XIB_QPS_RTR][XIB_QPS_RTS].opt_param[IB_QPT_UC] = + (IB_QP_CUR_STATE | IB_QP_ALT_PATH | IB_QP_ACCESS_FLAGS | + IB_QP_PATH_MIG_STATE); + qst[XIB_QPS_RTR][XIB_QPS_RTS].opt_param[IB_QPT_RC] = + (IB_QP_CUR_STATE | IB_QP_ALT_PATH | IB_QP_ACCESS_FLAGS | + IB_QP_MIN_RNR_TIMER | IB_QP_PATH_MIG_STATE); + qst[XIB_QPS_RTR][XIB_QPS_RTS].opt_param[IB_QPT_SMI] = + (IB_QP_CUR_STATE | IB_QP_QKEY); + qst[XIB_QPS_RTR][XIB_QPS_RTS].opt_param[IB_QPT_GSI] = + (IB_QP_CUR_STATE | IB_QP_QKEY); + + // + // XIB_QPS_RTS + // + + // XIB_QPS_RESET + qst[XIB_QPS_RTS][XIB_QPS_RESET].valid = 1; + + // XIB_QPS_ERR + qst[XIB_QPS_RTS][XIB_QPS_ERR].valid = 1; + + // XIB_QPS_RTS + qst[XIB_QPS_RTS][XIB_QPS_RTS].valid = 1; + + qst[XIB_QPS_RTS][XIB_QPS_RTS].opt_param[IB_QPT_UD] = + (IB_QP_CUR_STATE | IB_QP_QKEY); + qst[XIB_QPS_RTS][XIB_QPS_RTS].opt_param[IB_QPT_UC] = + (IB_QP_CUR_STATE | IB_QP_ACCESS_FLAGS | IB_QP_ALT_PATH | + IB_QP_PATH_MIG_STATE); + qst[XIB_QPS_RTS][XIB_QPS_RTS].opt_param[IB_QPT_RC] = + (IB_QP_CUR_STATE | IB_QP_ACCESS_FLAGS | IB_QP_ALT_PATH | + IB_QP_PATH_MIG_STATE | IB_QP_MIN_RNR_TIMER); + qst[XIB_QPS_RTS][XIB_QPS_RTS].opt_param[IB_QPT_SMI] = + (IB_QP_CUR_STATE | IB_QP_QKEY); + qst[XIB_QPS_RTS][XIB_QPS_RTS].opt_param[IB_QPT_GSI] = + (IB_QP_CUR_STATE | IB_QP_QKEY); + + // XIB_QPS_SQD + qst[XIB_QPS_RTS][XIB_QPS_SQD].valid = 1; + qst[XIB_QPS_RTS][XIB_QPS_SQD].opt_param[IB_QPT_UD] = IB_QP_EN_SQD_ASYNC_NOTIFY; + qst[XIB_QPS_RTS][XIB_QPS_SQD].opt_param[IB_QPT_UC] = IB_QP_EN_SQD_ASYNC_NOTIFY; + qst[XIB_QPS_RTS][XIB_QPS_SQD].opt_param[IB_QPT_RC] = IB_QP_EN_SQD_ASYNC_NOTIFY; + qst[XIB_QPS_RTS][XIB_QPS_SQD].opt_param[IB_QPT_SMI] = IB_QP_EN_SQD_ASYNC_NOTIFY; + qst[XIB_QPS_RTS][XIB_QPS_SQD].opt_param[IB_QPT_GSI] = IB_QP_EN_SQD_ASYNC_NOTIFY; + + // + // XIB_QPS_SQD + // + + // XIB_QPS_RESET + qst[XIB_QPS_SQD][XIB_QPS_RESET].valid = 1; + + // XIB_QPS_ERR + qst[XIB_QPS_SQD][XIB_QPS_ERR].valid = 1; + + // XIB_QPS_RTS + qst[XIB_QPS_SQD][XIB_QPS_RTS].valid = 1; + + qst[XIB_QPS_SQD][XIB_QPS_RTS].opt_param[IB_QPT_UD] = + (IB_QP_CUR_STATE | IB_QP_QKEY); + qst[XIB_QPS_SQD][XIB_QPS_RTS].opt_param[IB_QPT_UC] = + (IB_QP_CUR_STATE | IB_QP_ALT_PATH | IB_QP_ACCESS_FLAGS | + IB_QP_PATH_MIG_STATE); + qst[XIB_QPS_SQD][XIB_QPS_RTS].opt_param[IB_QPT_RC] = + (IB_QP_CUR_STATE | IB_QP_ALT_PATH | IB_QP_ACCESS_FLAGS | + IB_QP_MIN_RNR_TIMER | IB_QP_PATH_MIG_STATE); + qst[XIB_QPS_SQD][XIB_QPS_RTS].opt_param[IB_QPT_SMI] = + (IB_QP_CUR_STATE | IB_QP_QKEY); + qst[XIB_QPS_SQD][XIB_QPS_RTS].opt_param[IB_QPT_GSI] = + (IB_QP_CUR_STATE | IB_QP_QKEY); + + // XIB_QPS_SQD + qst[XIB_QPS_SQD][XIB_QPS_SQD].valid = 1; + + qst[XIB_QPS_SQD][XIB_QPS_SQD].opt_param[IB_QPT_UD] = + (IB_QP_PKEY_INDEX | IB_QP_QKEY); + qst[XIB_QPS_SQD][XIB_QPS_SQD].opt_param[IB_QPT_UC] = + (IB_QP_AV | IB_QP_ALT_PATH | IB_QP_ACCESS_FLAGS | + IB_QP_PKEY_INDEX | IB_QP_PATH_MIG_STATE); + qst[XIB_QPS_SQD][XIB_QPS_SQD].opt_param[IB_QPT_RC] = + (IB_QP_PORT | IB_QP_AV | IB_QP_TIMEOUT | IB_QP_RETRY_CNT | + IB_QP_RNR_RETRY | IB_QP_MAX_QP_RD_ATOMIC | IB_QP_MAX_DEST_RD_ATOMIC | + IB_QP_ALT_PATH | IB_QP_ACCESS_FLAGS | IB_QP_PKEY_INDEX | + IB_QP_MIN_RNR_TIMER | IB_QP_PATH_MIG_STATE); + qst[XIB_QPS_SQD][XIB_QPS_SQD].opt_param[IB_QPT_SMI] = + (IB_QP_PKEY_INDEX | IB_QP_QKEY); + qst[XIB_QPS_SQD][XIB_QPS_SQD].opt_param[IB_QPT_GSI] = + (IB_QP_PKEY_INDEX | IB_QP_QKEY); + + // + // XIB_QPS_SQE + // + + // XIB_QPS_RESET + qst[XIB_QPS_SQE][XIB_QPS_RESET].valid = 1; + + // XIB_QPS_ERR + qst[XIB_QPS_SQE][XIB_QPS_ERR].valid = 1; + + // XIB_QPS_RTS + qst[XIB_QPS_SQE][XIB_QPS_RTS].valid = 1; + + qst[XIB_QPS_SQE][XIB_QPS_RTS].opt_param[IB_QPT_UD] = + (IB_QP_CUR_STATE | IB_QP_QKEY); + qst[XIB_QPS_SQE][XIB_QPS_RTS].opt_param[IB_QPT_UC] = + (IB_QP_CUR_STATE | IB_QP_ACCESS_FLAGS); + qst[XIB_QPS_SQE][XIB_QPS_RTS].opt_param[IB_QPT_SMI] = + (IB_QP_CUR_STATE | IB_QP_QKEY); + qst[XIB_QPS_SQE][XIB_QPS_RTS].opt_param[IB_QPT_GSI] = + (IB_QP_CUR_STATE | IB_QP_QKEY); + + + // + // XIB_QPS_ERR + // + + // XIB_QPS_RESET + qst[XIB_QPS_ERR][XIB_QPS_RESET].valid = 1; + + // XIB_QPS_ERR + qst[XIB_QPS_ERR][XIB_QPS_ERR].valid = 1; + +} + +int ib_modify_qp_is_ok(enum ib_qp_state cur_state, enum ib_qp_state next_state, + enum ib_qp_type type, enum ib_qp_attr_mask mask) +{ + enum ib_qp_attr_mask req_param, opt_param; + + if (cur_state < 0 || cur_state > XIB_QPS_ERR || + next_state < 0 || next_state > XIB_QPS_ERR) + return 0; + + if (mask & IB_QP_CUR_STATE && + cur_state != XIB_QPS_RTR && cur_state != XIB_QPS_RTS && + cur_state != XIB_QPS_SQD && cur_state != XIB_QPS_SQE) + return 0; + + if (!qst[cur_state][next_state].valid) + return 0; + + req_param = qst[cur_state][next_state].req_param[type]; + opt_param = qst[cur_state][next_state].opt_param[type]; + + if ((mask & req_param) != req_param) + return 0; + + if (mask & ~(req_param | opt_param | IB_QP_STATE)) + return 0; + + return 1; +} +EXPORT_SYMBOL(ib_modify_qp_is_ok); + +struct ib_ah *ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr) +{ + struct ib_ah *ah; + + ah = pd->device->create_ah(pd, ah_attr); + + if (!IS_ERR(ah)) { + ah->device = pd->device; + ah->pd = pd; + ah->p_uctx = NULL; + atomic_inc(&pd->usecnt); + } + + return ah; +} +EXPORT_SYMBOL(ib_create_ah); + +int ib_destroy_ah(struct ib_ah *ah) +{ + int ret; + struct ib_pd *pd = ah->pd; + + ret = ah->device->destroy_ah(ah); + if (!ret) + atomic_dec(&pd->usecnt); + + return ret; +} +EXPORT_SYMBOL(ib_destroy_ah); + +enum rdma_transport_type +rdma_node_get_transport(enum rdma_node_type node_type) +{ + switch (node_type) { + case RDMA_NODE_IB_CA: + case RDMA_NODE_IB_SWITCH: + case RDMA_NODE_IB_ROUTER: + return RDMA_TRANSPORT_IB; + case RDMA_NODE_RNIC: + return RDMA_TRANSPORT_IWARP; + default: + ASSERT(FALSE); + return 0; + } +} + +enum rdma_transport_type rdma_port_get_transport(struct ib_device *device, + u8 port_num) +{ + return device->get_port_transport ? + device->get_port_transport(device, port_num) : + rdma_node_get_transport(device->node_type); +} +EXPORT_SYMBOL(rdma_port_get_transport); + diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/dirs b/branches/WOF2-3/hw/mlx4/kernel/bus/dirs new file mode 100644 index 00000000..b70ba29a --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/dirs @@ -0,0 +1,5 @@ +DIRS=\ + core \ + net \ + ib \ + drv diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/drv/bus.mof b/branches/WOF2-3/hw/mlx4/kernel/bus/drv/bus.mof new file mode 100644 index 00000000..f5b1f1a6 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/drv/bus.mof @@ -0,0 +1,27 @@ +#PRAGMA AUTORECOVER + +[Dynamic, Provider("WMIProv"), + WMI, + Description("Mlx4 Bus driver information"), + guid("{3337968C-F117-4289-84C2-04EF74CBAD77}"), + locale("MS\\0x409")] +class Mlx4BusInformation +{ + [key, read] + string InstanceName; + [read] boolean Active; + + [WmiDataId(1), + read, + Description("The DebugPrintLevel property indicates the debug output level of MLX4_BUS device.")] + uint32 DebugPrintLevel; + + [WmiDataId(2), + read, + write, + Description("The DebugPrintLevel property indicates the debug output flags of MLX4_BUS device.")] + uint32 DebugPrintFlags; + +}; + + diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/drv/bus.rc b/branches/WOF2-3/hw/mlx4/kernel/bus/drv/bus.rc new file mode 100644 index 00000000..58cac5b6 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/drv/bus.rc @@ -0,0 +1,16 @@ +#include + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_UNKNOWN +#ifdef DBG +#define VER_FILEDESCRIPTION_STR "MLX4 Bus Driver (checked)" +#else +#define VER_FILEDESCRIPTION_STR "MLX4 Bus Driver" +#endif +#define VER_INTERNALNAME_STR "mlx4_bus.sys" +#define VER_ORIGINALFILENAME_STR "mlx4_bus.sys" +#include + +#include "ev_log.rc" + + diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/drv/drv.c b/branches/WOF2-3/hw/mlx4/kernel/bus/drv/drv.c new file mode 100644 index 00000000..eebf3cc4 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/drv/drv.c @@ -0,0 +1,1474 @@ +/*++ + +Copyright (c) 2003 Microsoft Corporation All Rights Reserved + +Module Name: + + BUSENUM.C + +Abstract: + + This module contains routines to handle the function driver + aspect of the bus driver. This sample is functionally + equivalent to the WDM mxe bus driver. + +Environment: + + kernel mode only + +--*/ + +#include "precomp.h" +#include +#include + +#if defined (EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "drv.tmh" +#endif + + +#define DRV_VERSION "1.0" +#define DRV_RELDATE "02/01/2008" + +GLOBALS g = {0}; +uint32_t g_mlx4_dbg_flags = 0xffff; +uint32_t g_mlx4_dbg_level = TRACE_LEVEL_INFORMATION; +WCHAR g_wlog_buf[ MAX_LOG_BUF_LEN ]; +UCHAR g_slog_buf[ MAX_LOG_BUF_LEN ]; + +#ifndef USE_WDM_INTERRUPTS + +typedef struct { + int int_num; + PFDO_DEVICE_DATA p_fdo; + struct mlx4_eq * eq; +} INTERRUPT_DATA, *PINTERRUPT_DATA; + +WDF_DECLARE_CONTEXT_TYPE(INTERRUPT_DATA); + +NTSTATUS +EvtEnableInterrupt( + IN WDFINTERRUPT Interrupt, + IN WDFDEVICE AssociatedDevice + ) +{ + UNUSED_PARAM(Interrupt); + UNUSED_PARAM(AssociatedDevice); + MLX4_ENTER(MLX4_DBG_DRV); + MLX4_EXIT( MLX4_DBG_DRV ); + return STATUS_SUCCESS; +} + +NTSTATUS +EvtDisableInterrupt ( + IN WDFINTERRUPT Interrupt, + IN WDFDEVICE AssociatedDevice + ) +{ + UNUSED_PARAM(Interrupt); + UNUSED_PARAM(AssociatedDevice); + MLX4_ENTER(MLX4_DBG_DRV); + MLX4_EXIT( MLX4_DBG_DRV ); + return STATUS_SUCCESS; +} + +BOOLEAN +EvtInterruptIsr( + IN WDFINTERRUPT Interrupt, + IN ULONG MessageID + ) +{ + BOOLEAN isr_handled = FALSE; + PINTERRUPT_DATA p_isr_ctx = WdfObjectGetTypedContext( Interrupt, INTERRUPT_DATA ); + + UNUSED_PARAM(MessageID); + +// MLX4_PRINT(TRACE_LEVEL_VERBOSE, MLX4_DBG_DRV, ("Fdo %p\n", p_isr_ctx->p_fdo)); + if (p_isr_ctx->eq && p_isr_ctx->eq->isr) + isr_handled = p_isr_ctx->eq->isr( p_isr_ctx->eq->eq_ix, p_isr_ctx->eq->ctx ); + + return isr_handled; +} + +#endif + +NTSTATUS +__create_child( + __in WDFDEVICE Device, + __in PWCHAR HardwareIds, + __in PWCHAR DeviceDescription, + __in ULONG SerialNo + ) + +/*++ + +Routine Description: + + The user application has told us that a new device on the bus has arrived. + + We therefore need to create a new PDO, initialize it, add it to the list + of PDOs for this FDO bus, and then tell Plug and Play that all of this + happened so that it will start sending prodding IRPs. + +--*/ + +{ + NTSTATUS status = STATUS_SUCCESS; + BOOLEAN unique = TRUE; + WDFDEVICE hChild; + PPDO_DEVICE_DATA p_pdo; + PFDO_DEVICE_DATA p_fdo; + + PAGED_CODE (); + MLX4_ENTER(MLX4_DBG_DRV); + + // + // First make sure that we don't already have another device with the + // same serial number. + // Framework creates a collection of all the child devices we have + // created so far. So acquire the handle to the collection and lock + // it before walking the item. + // + p_fdo = FdoGetData(Device); + hChild = NULL; + + // + // We need an additional lock to synchronize addition because + // WdfFdoLockStaticChildListForIteration locks against anyone immediately + // updating the static child list (the changes are put on a queue until the + // list has been unlocked). This type of lock does not enforce our concept + // of unique IDs on the bus (ie SerialNo). + // + // Without our additional lock, 2 threads could execute this function, both + // find that the requested SerialNo is not in the list and attempt to add + // it. If that were to occur, 2 PDOs would have the same unique SerialNo, + // which is incorrect. + // + // We must use a passive level lock because you can only call WdfDeviceCreate + // at PASSIVE_LEVEL. + // + WdfWaitLockAcquire(p_fdo->ChildLock, NULL); + WdfFdoLockStaticChildListForIteration(Device); + + while ((hChild = WdfFdoRetrieveNextStaticChild(Device, + hChild, WdfRetrieveAddedChildren)) != NULL) { + // + // WdfFdoRetrieveNextStaticChild returns reported and to be reported + // children (ie children who have been added but not yet reported to PNP). + // + // A surprise removed child will not be returned in this list. + // + p_pdo = PdoGetData(hChild); + p_pdo->PdoDevice = hChild; + p_pdo->p_fdo = p_fdo; + + // + // It's okay to plug in another device with the same serial number + // as long as the previous one is in a surprise-removed state. The + // previous one would be in that state after the device has been + // physically removed, if somebody has an handle open to it. + // + if (SerialNo == p_pdo->SerialNo) { + unique = FALSE; + status = STATUS_INVALID_PARAMETER; + break; + } + } + + if (unique) { + // + // Create a new child device. It is OK to create and add a child while + // the list locked for enumeration. The enumeration lock applies only + // to enumeration, not addition or removal. + // + status = create_pdo(Device, HardwareIds, DeviceDescription, SerialNo, p_fdo->pci_dev.location); + } + + WdfFdoUnlockStaticChildListFromIteration(Device); + WdfWaitLockRelease(p_fdo->ChildLock); + + MLX4_EXIT( MLX4_DBG_DRV ); + return status; +} + +static +NTSTATUS +__do_static_enumeration( + IN WDFDEVICE Device + ) +/*++ +Routine Description: + + The routine enables you to statically enumerate child devices + during start instead of running the enum.exe/notify.exe to + enumerate mxe devices. + + In order to statically enumerate, user must specify the number + of mxes in the Mxe Bus driver's device registry. The + default value is 2. + + You can also configure this value in the Mxe Bus Inf file. + +--*/ + +{ + NTSTATUS status = STATUS_SUCCESS; + int i; + int number_of_ib_ports; + PFDO_DEVICE_DATA p_fdo = FdoGetData(Device); + struct mlx4_dev *mdev = p_fdo->pci_dev.dev; + BOOLEAN ib_created = FALSE; + BOOLEAN eth_created = FALSE; + + MLX4_ENTER(MLX4_DBG_DRV); + + if ( p_fdo->children_created ) + goto end; + + // eventually we'll have all information about children in Registry + // DriverEntry will read it into a Global storage and + // this routine will create all the children on base on this info + number_of_ib_ports = mlx4_count_ib_ports(mdev); + ASSERT(number_of_ib_ports >=0 && number_of_ib_ports <=2); + +#if 0 + //For now we it's either IB or ETH, and we always create LLE if it's ETH + if((number_of_ib_ports > 0) && (mdev->caps.port_type[1] == MLX4_PORT_TYPE_IB) ) { + status = __create_child(Device, BUS_HARDWARE_IDS, BUS_HARDWARE_DESCRIPTION, 0 ); + if (!NT_SUCCESS(status)) { + MLX4_PRINT_EV(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, ("__create_child (ib)failed with 0x%x\n", status)); + } + } +#endif + + for (i = 1; i <= mdev->caps.num_ports; i++) { + if (mlx4_is_enabled_port(mdev, i)) { + if(mlx4_is_eth_port(mdev, i)) { + status = __create_child(Device, ETH_HARDWARE_IDS, ETH_HARDWARE_DESCRIPTION, i); + if (!NT_SUCCESS(status)) { + MLX4_PRINT_EV(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, ("__create_child (eth) failed with 0x%x\n", status)); + break; + } + eth_created = TRUE; + } else { + if (eth_created){ + // + // Illegal configuration the IB should be the first port + // + status = STATUS_INVALID_PARAMETER; + MLX4_PRINT_EV(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, ("__create_child (IB) failed. Invalid configuration, IB should be the first port.")); + break; + } + + if (ib_created){ + continue; + } + + status = __create_child(Device, BUS_HARDWARE_IDS, BUS_HARDWARE_DESCRIPTION, 0 ); + if (!NT_SUCCESS(status)) { + MLX4_PRINT_EV(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, ("__create_child (ib)failed with 0x%x\n", status)); + break; + } + ib_created = TRUE; + } + } + } + + p_fdo->children_created = TRUE; + +end: + MLX4_EXIT( MLX4_DBG_DRV ); + return status; +} + +BOOLEAN __read_setup_params(struct pci_dev *pdev, PUNICODE_STRING puvalue) +{ + NTSTATUS status; + WDFKEY hParamsKey = NULL; + DECLARE_CONST_UNICODE_STRING(KeyName, L"\\Registry\\Machine\\SOFTWARE\\Mellanox"); + DECLARE_CONST_UNICODE_STRING(PortType, L"PortType"); + + status = WdfRegistryOpenKey(NULL, &KeyName, STANDARD_RIGHTS_ALL, WDF_NO_OBJECT_ATTRIBUTES, &hParamsKey); + if( !NT_SUCCESS( status ) ) + { + MLX4_PRINT( TRACE_LEVEL_WARNING ,MLX4_DBG_DEV , + ("WdfRegistryOpenKey(\\Registry\\Machine\\SOFTWARE\\Mellanox) Failed status = 0x%x\n", status)); + WriteEventLogEntryData( pdev->p_self_do, (ULONG)EVENT_MLX4_WARN_REG_ACTION, 0, 0, 3, + L"%s", L"WdfRegistryOpenKey", L"%s", KeyName.Buffer, L"%#x", status ); + return FALSE; + } + + status = WdfRegistryQueryUnicodeString(hParamsKey, &PortType, NULL, puvalue); + if( !NT_SUCCESS( status ) ) + { + MLX4_PRINT( TRACE_LEVEL_ERROR ,MLX4_DBG_DEV , + ("WdfRegistryQueryUnicodeString(PortType) Failed status = 0x%x\n", status)); + WriteEventLogEntryData( pdev->p_self_do, (ULONG)EVENT_MLX4_WARN_REG_ACTION, 0, 0, 3, + L"%s", L"WdfRegistryQueryUnicodeString", L"%s", PortType.Buffer, L"%#x", status ); + WdfRegistryClose(hParamsKey); + return FALSE; + } + + WdfRegistryClose(hParamsKey); + return TRUE; +} + +NTSTATUS +__read_dev_params(IN WDFDEVICE Device, struct mlx4_dev_params *dev_params) +{ + NTSTATUS status = STATUS_SUCCESS; + WDFKEY hKey = NULL; + WDFKEY hParamsKey = NULL; + BOOLEAN bRet = FALSE; + PFDO_DEVICE_DATA p_fdo = FdoGetData(Device); + struct pci_dev *pdev = &p_fdo->pci_dev; + DECLARE_CONST_UNICODE_STRING(Parameters, L"Parameters"); + DECLARE_CONST_UNICODE_STRING(PortType, L"PortType"); + +#define MAX_UVALUE 100 + WCHAR uvalue_data[MAX_UVALUE]={0}; + UNICODE_STRING uvalue; + uvalue.Buffer = uvalue_data; + uvalue.MaximumLength = MAX_UVALUE; + uvalue.Length = 0; + + // default values + dev_params->mod_port_type[0] = MLX4_PORT_TYPE_IB; + dev_params->mod_port_type[1] = MLX4_PORT_TYPE_IB; + + status = WdfDeviceOpenRegistryKey(Device, PLUGPLAY_REGKEY_DRIVER, + STANDARD_RIGHTS_ALL, WDF_NO_OBJECT_ATTRIBUTES, &hKey); + if( !NT_SUCCESS( status ) ) { + MLX4_PRINT( TRACE_LEVEL_ERROR ,MLX4_DBG_DEV , + ("WdfDeviceOpenRegistryKey(\\Registry\\Machine\\Control\\Class\\...) Failed status = 0x%x\n", status)); + WriteEventLogEntryData( pdev->p_self_do, (ULONG)EVENT_MLX4_WARN_REG_OPEN_DEV_KEY, 0, 0, 1, + L"%#x", status ); + goto err; + } + + status = WdfRegistryOpenKey(hKey, &Parameters, STANDARD_RIGHTS_ALL, WDF_NO_OBJECT_ATTRIBUTES, &hParamsKey); + if( !NT_SUCCESS( status ) ) { + MLX4_PRINT( TRACE_LEVEL_ERROR ,MLX4_DBG_DEV ,("WdfRegistryOpenKey(Prameters) Failed status = 0x%x\n", status)); + WriteEventLogEntryData( pdev->p_self_do, (ULONG)EVENT_MLX4_WARN_REG_ACTION, 0, 0, 3, + L"%s", L"WdfRegistryOpenKey", L"%s", Parameters.Buffer, L"%#x", status ); + goto err; + } + + bRet = __read_setup_params(pdev, &uvalue); + if (bRet == TRUE) + { + status = WdfRegistryAssignValue(hParamsKey, &PortType, REG_SZ,uvalue.Length,uvalue.Buffer); + if( !NT_SUCCESS( status ) ) { + MLX4_PRINT( TRACE_LEVEL_ERROR ,MLX4_DBG_DEV ,("WdfRegistryAssignValue(PortType) Failed status = 0x%x\n", status)); + WriteEventLogEntryData( pdev->p_self_do, (ULONG)EVENT_MLX4_WARN_REG_ACTION, 0, 0, 3, + L"%s", L"WdfRegistryAssignValue", L"%s", PortType.Buffer, L"%#x", status ); + goto err; + } + uvalue.Length = 0; + } + + memset(&uvalue_data,0,sizeof(uvalue_data)); + + status = WdfRegistryQueryUnicodeString(hParamsKey, &PortType, NULL, &uvalue); + if (NT_SUCCESS (status)) { + if (!wcscmp(uvalue_data, L"ib,ib")) { + dev_params->mod_port_type[0] = MLX4_PORT_TYPE_IB; + dev_params->mod_port_type[1] = MLX4_PORT_TYPE_IB; + } else + if (!wcscmp(uvalue_data, L"ib,eth")) { + dev_params->mod_port_type[0] = MLX4_PORT_TYPE_IB; + dev_params->mod_port_type[1] = MLX4_PORT_TYPE_ETH; + } else + if (!wcscmp(uvalue_data, L"eth,ib")) { + dev_params->mod_port_type[0] = MLX4_PORT_TYPE_ETH; + dev_params->mod_port_type[1] = MLX4_PORT_TYPE_IB; + } else + if (!wcscmp(uvalue_data, L"eth,eth")) { + dev_params->mod_port_type[0] = MLX4_PORT_TYPE_ETH; + dev_params->mod_port_type[1] = MLX4_PORT_TYPE_ETH; + } else { + MLX4_PRINT( TRACE_LEVEL_ERROR ,MLX4_DBG_DEV ,("Invalid value, PortType = %S\n", uvalue_data)); + WriteEventLogEntryData( pdev->p_self_do, (ULONG)EVENT_MLX4_WARN_INVALID_PORT_TYPE_VALUE, 0, 0, 1, + L"%s",uvalue_data); + } + } + else { + WriteEventLogEntryData( pdev->p_self_do, (ULONG)EVENT_MLX4_WARN_REG_ACTION, 0, 0, 3, + L"%s", L"WdfRegistryQueryUnicodeString", L"%s", PortType.Buffer, L"%#x", status ); + } + +err: + if (hKey != NULL) + WdfRegistryClose(hKey); + + if (hParamsKey != NULL) + WdfRegistryClose(hParamsKey); + + return status; +} + + +static +NTSTATUS +__start_card( + IN WDFDEVICE Device, + IN PFDO_DEVICE_DATA p_fdo + ) +{ +#ifndef USE_WDM_INTERRUPTS + int i; +#endif + int err; + NTSTATUS status = STATUS_SUCCESS; + struct pci_dev *pdev = &p_fdo->pci_dev; + struct mlx4_dev_params dev_params; + + MLX4_ENTER(MLX4_DBG_DRV); + + if ( p_fdo->card_started ) + goto err; + + status = __read_dev_params(Device, &dev_params); + if( !NT_SUCCESS( status ) ) + goto err; + + // enable the card + status = pci_hca_enable( &pdev->bus_pci_ifc, &pdev->pci_cfg_space ); + if( !NT_SUCCESS( status ) ) + goto err; + + // + // init the card + // + +#ifndef USE_WDM_INTERRUPTS + // enable interrupts for start up + for ( i = 0; i < MLX4_MAX_INTERRUPTS; ++i ) + WdfInterruptEnable(p_fdo->interrupt[i].WdfInterrupt); +#endif + + // NET library + err = mlx4_init_one( &p_fdo->pci_dev, &dev_params ); + if (err) { + status = errno_to_ntstatus(err); + goto err; + } + +#ifndef USE_WDM_INTERRUPTS + // + // complete filling interrupt context (for more efficiency) + // + for ( i = 0; i < MLX4_MAX_INTERRUPTS; ++i ) { + struct mlx4_priv *priv = mlx4_priv( p_fdo->pci_dev.dev ); + PINTERRUPT_DATA p_isr_ctx = WdfObjectGetTypedContext( + p_fdo->interrupt[i].WdfInterrupt, INTERRUPT_DATA ); + + p_isr_ctx->eq = &priv->eq_table.eq[i]; + } +#endif + + // + // prepare MLX4 IB interface + // + + // fill the header + p_fdo->bus_ib_ifc.i.Size = sizeof(MLX4_BUS_IB_INTERFACE); + p_fdo->bus_ib_ifc.i.Version = MLX4_BUS_IB_INTERFACE_VERSION; + // Let the framework handle reference counting. + p_fdo->bus_ib_ifc.i.InterfaceReference = WdfDeviceInterfaceReferenceNoOp; + p_fdo->bus_ib_ifc.i.InterfaceDereference = WdfDeviceInterfaceDereferenceNoOp; + + p_fdo->bus_ib_ifc.pdev = &p_fdo->pci_dev; + p_fdo->bus_ib_ifc.p_ibdev = p_fdo->pci_dev.ib_dev; + p_fdo->bus_ib_ifc.is_livefish = mlx4_is_livefish(p_fdo->pci_dev.dev); + if ( p_fdo->bus_ib_ifc.is_livefish == 0 ) { + p_fdo->bus_ib_ifc.pmlx4_dev = to_mdev(p_fdo->pci_dev.ib_dev)->dev; + if ( p_fdo->bus_ib_ifc.pmlx4_dev->flags & MLX4_FLAG_MSI_X ) + p_fdo->bus_ib_ifc.n_msi_vectors = p_fdo->pci_dev.n_msi_vectors - 2; + } + + p_fdo->card_started = TRUE; + +err: + MLX4_EXIT( MLX4_DBG_DRV ); + return status; +} + +static +void +__stop_card( + IN PFDO_DEVICE_DATA p_fdo + ) +{ + if ( p_fdo->card_started ) { + p_fdo->card_started = FALSE; + mlx4_remove_one( &p_fdo->pci_dev, TRUE); + } +} + + +NTSTATUS +EvtDeviceD0Entry( + IN WDFDEVICE Device, + IN WDF_POWER_DEVICE_STATE PreviousState + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PFDO_DEVICE_DATA p_fdo = FdoGetData(Device); + struct pci_dev *pdev = &p_fdo->pci_dev; + struct mlx4_dev *mdev; + struct ib_device_attr props; + struct ib_device *p_ibdev; + + MLX4_ENTER(MLX4_DBG_DRV); + + MLX4_PRINT(TRACE_LEVEL_INFORMATION, MLX4_DBG_DRV, ("PreviousState 0x%x\n", PreviousState)); + + // start card (needed after Hibernation or standby) + if (PreviousState > WdfPowerDeviceD0) + status = __start_card( Device, p_fdo ); + if ( !NT_SUCCESS( status ) ) + goto err; + mdev = pdev->dev; + + // create child device + status = __do_static_enumeration(Device); + if (!NT_SUCCESS(status)) { + MLX4_PRINT_EV(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, ("__do_static_enumeration failed with 0x%x\n", status)); + goto err; + } + + // Log Success Message + MLX4_PRINT(TRACE_LEVEL_INFORMATION ,MLX4_DBG_DRV , + ("Ven %x Dev %d Fw %d.%d.%d, IsBurnDevice %s\n", + (unsigned)pdev->ven_id, (unsigned)pdev->dev_id, + (int) (mdev->caps.fw_ver >> 32), + (int) (mdev->caps.fw_ver >> 16) & 0xffff, + (int) (mdev->caps.fw_ver & 0xffff), + mlx4_is_livefish(mdev) ? "Y" : "N" + )); + if (!mlx4_is_livefish(mdev)) { + memset ( &props, 0, sizeof( props) ); + p_ibdev = pdev->ib_dev; + (p_ibdev->query_device)( p_ibdev, &props ); + WriteEventLogEntryData( pdev->p_self_do, (ULONG)EVENT_MLX4_INFO_DEV_STARTED, 0, 0, 14, + L"%04x", (ULONG)pdev->ven_id, + L"%04x", (ULONG)pdev->dev_id, + L"%04x", (ULONG)pdev->sub_vendor_id, + L"%04x", (ULONG)pdev->sub_system_id, + L"%02x", (ULONG)pdev->revision_id, + L"%d", (int) (mdev->caps.fw_ver >> 32), + L"%d", (int) (mdev->caps.fw_ver >> 16) & 0xffff, + L"%d", (int) (mdev->caps.fw_ver & 0xffff), + L"%08x", *(PULONG)((PUCHAR)&p_ibdev->node_guid + 0), + L"%08x", *(PULONG)((PUCHAR)&p_ibdev->node_guid + 4), + L"%s", pdev->location, + L"%d", mdev->caps.num_ports, + L"%s", mdev->caps.port_type[1] == MLX4_PORT_TYPE_IB ? L"IB" : L"ETH", + L"%s", mdev->caps.port_type[2] == MLX4_PORT_TYPE_IB ? L"IB" : L"ETH" + ); + } + +err: + MLX4_EXIT( MLX4_DBG_DRV ); + return status; +} + +NTSTATUS +EvtDeviceD0Exit( + IN WDFDEVICE Device, + IN WDF_POWER_DEVICE_STATE TargetState + ) +{ + PFDO_DEVICE_DATA p_fdo = FdoGetData(Device); + + MLX4_ENTER(MLX4_DBG_DRV); + MLX4_PRINT(TRACE_LEVEL_INFORMATION, MLX4_DBG_DRV, ("TargetState 0x%x\n", TargetState)); + + if (TargetState > WdfPowerDeviceD0) + __stop_card( p_fdo ); + + st_dev_rmv( p_fdo->pci_dev.p_stat_dev ); + + MLX4_EXIT( MLX4_DBG_DRV ); + return STATUS_SUCCESS; +} + + + +/* Forwards the request to the HCA's PDO. */ +static +void +__put_bus_ifc( + IN BUS_INTERFACE_STANDARD *pBusIfc ) +{ + MLX4_ENTER(MLX4_DBG_DRV); + MLX4_PRINT(TRACE_LEVEL_INFORMATION, MLX4_DBG_DRV, ("pBusIfc=0x%p\n", pBusIfc)); + pBusIfc->InterfaceDereference( pBusIfc->Context ); + MLX4_EXIT( MLX4_DBG_DRV ); +} + +static +NTSTATUS +__get_bus_ifc( + IN PFDO_DEVICE_DATA const p_fdo, + IN const GUID* const pGuid, + OUT BUS_INTERFACE_STANDARD *pBusIfc ) +{ + NTSTATUS status; + WDFDEVICE FdoDevice = p_fdo->FdoDevice; + MLX4_ENTER(MLX4_DBG_DRV); + + status = WdfFdoQueryForInterface( FdoDevice, pGuid, (PINTERFACE)pBusIfc, + sizeof(BUS_INTERFACE_STANDARD), 1, NULL ); + MLX4_EXIT( MLX4_DBG_DRV ); + return status; +} + +static +void +__put_dma_adapter( + IN PFDO_DEVICE_DATA p_fdo, + IN PDMA_ADAPTER p_dma ) +{ + UNUSED_PARAM(p_fdo); + UNUSED_PARAM(p_dma); + MLX4_ENTER(MLX4_DBG_DRV); + MLX4_EXIT( MLX4_DBG_DRV ); +} + + +// this routine releases the resources, taken in __get_resources +static +void +__put_resources( + IN PFDO_DEVICE_DATA p_fdo + ) +{ + struct pci_dev *pdev = &p_fdo->pci_dev; + + MLX4_ENTER(MLX4_DBG_DRV); + + if (pdev->msix_info.valid) + pci_free_msix_info_resources(&pdev->msix_info); + + if (p_fdo->dma_adapter_taken) { + p_fdo->dma_adapter_taken = FALSE; + __put_dma_adapter( p_fdo, pdev->p_dma_adapter ); + } + + if (p_fdo->pci_bus_ifc_taken) { + p_fdo->pci_bus_ifc_taken = FALSE; + __put_bus_ifc(&pdev->bus_pci_ifc); + } + + if (pdev->p_msix_map) + kfree(pdev->p_msix_map); + + + MLX4_EXIT( MLX4_DBG_DRV ); +} + +static +NTSTATUS +__get_dma_adapter( + IN PFDO_DEVICE_DATA p_fdo, + OUT PDMA_ADAPTER * pp_dma ) +{ + NTSTATUS status; + WDF_DMA_ENABLER_CONFIG dmaConfig; + + MLX4_ENTER(MLX4_DBG_DRV); + + WDF_DMA_ENABLER_CONFIG_INIT( &dmaConfig, + WdfDmaProfileScatterGather64, 0x80000000 - 1 ); + + status = WdfDmaEnablerCreate( p_fdo->FdoDevice, + &dmaConfig, WDF_NO_OBJECT_ATTRIBUTES, &p_fdo->dma_enabler ); + if (!NT_SUCCESS (status)) { + return status; + } + + *pp_dma = WdfDmaEnablerWdmGetDmaAdapter( + p_fdo->dma_enabler, WdfDmaDirectionReadFromDevice ); + + MLX4_EXIT( MLX4_DBG_DRV ); + return status; +} + +// this routine fills pci_dev structure, containing all HW +// and some other necessary common resources +static +NTSTATUS +__get_resources( + IN PFDO_DEVICE_DATA p_fdo, + IN WDFCMRESLIST ResourcesRaw, + IN WDFCMRESLIST ResourcesTranslated + ) +{ + NTSTATUS status; + ULONG i, k=0; + PCM_PARTIAL_RESOURCE_DESCRIPTOR desc; + PCM_PARTIAL_RESOURCE_DESCRIPTOR desc_raw; + BUS_INTERFACE_STANDARD bus_pci_ifc; + struct pci_dev *pdev = &p_fdo->pci_dev; + + MLX4_ENTER(MLX4_DBG_DRV); + + // + // Get PCI BUS interface + // + status = __get_bus_ifc( p_fdo, &GUID_BUS_INTERFACE_STANDARD, &bus_pci_ifc ); + if( !NT_SUCCESS( status ) ) { + MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, + ("failed: status=0x%x\n", status)); + return status; + } + RtlCopyMemory( &pdev->bus_pci_ifc, &bus_pci_ifc, sizeof(BUS_INTERFACE_STANDARD) ); + p_fdo->pci_bus_ifc_taken = TRUE; + + // + // get HW resources + // + for (i = 0; i < WdfCmResourceListGetCount(ResourcesTranslated); i++) { + + desc = WdfCmResourceListGetDescriptor( ResourcesTranslated, i ); + desc_raw = WdfCmResourceListGetDescriptor( ResourcesRaw, i ); + + switch (desc->Type) { + + case CmResourceTypeMemory: + MLX4_PRINT(TRACE_LEVEL_VERBOSE, MLX4_DBG_DRV, + ("EvtPrepareHardware(Raw): Desc %d: Memory: Start %#I64x, Length %#x\n", + i, desc_raw->u.Memory.Start.QuadPart, desc_raw->u.Memory.Length )); + MLX4_PRINT(TRACE_LEVEL_VERBOSE, MLX4_DBG_DRV, + ("EvtPrepareHardware: Desc %d: Memory: Start %#I64x, Length %#x\n", + i, desc->u.Memory.Start.QuadPart, desc->u.Memory.Length )); + + if (k < N_BARS) { + pdev->bar[k].phys = desc->u.Memory.Start.QuadPart; + pdev->bar[k].size = (SIZE_T)desc->u.Memory.Length; + } + k++; + break; + +#ifdef USE_WDM_INTERRUPTS + case CmResourceTypeInterrupt: + if (!pdev->n_msi_vectors_alloc) + pdev->int_info = *desc; + if (desc->Flags & CM_RESOURCE_INTERRUPT_MESSAGE) { + pdev->n_msi_vectors_alloc = (u8)(pdev->n_msi_vectors_alloc+desc_raw->u.MessageInterrupt.Raw.MessageCount); + MLX4_PRINT(TRACE_LEVEL_VERBOSE, MLX4_DBG_DRV, + ("EvtPrepareHardware: Desc %d: MsiInterrupt: Share %d, Flags %#x, Level %d, Vector %#x, Affinity %#x\n", + i, desc->ShareDisposition, desc->Flags, + desc->u.MessageInterrupt.Translated.Level, + desc->u.MessageInterrupt.Translated.Vector, + (u32)desc->u.MessageInterrupt.Translated.Affinity )); + MLX4_PRINT(TRACE_LEVEL_VERBOSE, MLX4_DBG_DRV, + ("EvtPrepareHardware: Desc %d: RawMsiInterrupt: Share %d, Flags %#x, MessageCount %#hx, Vector %#x, Affinity %#x\n", + i, desc_raw->ShareDisposition, desc_raw->Flags, + desc_raw->u.MessageInterrupt.Raw.MessageCount, + desc_raw->u.MessageInterrupt.Raw.Vector, + (u32)desc_raw->u.MessageInterrupt.Raw.Affinity )); + } + else { // line-based interrupt + MLX4_PRINT(TRACE_LEVEL_VERBOSE, MLX4_DBG_DRV, + ("EvtPrepareHardware: Desc %d: LineInterrupt: Share %d, Flags %#x, Level %d, Vector %#x, Affinity %#x\n", + i, desc->ShareDisposition, desc->Flags, + desc->u.Interrupt.Level, desc->u.Interrupt.Vector, + (u32)desc->u.Interrupt.Affinity )); + } + break; +#endif + + default: + // + // Ignore all other descriptors. + // + break; + } + } + if (i ==0) { + // This means that no resources are found + MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, ("WdfCmResourceListGetCount: returned 0, quiting\n")); + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // get uplink info. + // + status = pci_save_config( &pdev->bus_pci_ifc, + &pdev->pci_cfg_space ); + if( !NT_SUCCESS( status ) ) + { + MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, + ("Failed to save HCA config: status=0x%x\n", status)); + goto err; + } + pci_get_uplink_info( &pdev->pci_cfg_space, &pdev->uplink_info ); + + // + // allocate DMA adapter + // + status = __get_dma_adapter( p_fdo, &pdev->p_dma_adapter ); + if( !NT_SUCCESS( status ) ) + { + MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, + ("Failed to get DMA adapter: status=0x%x\n", status)); + goto err; + } + p_fdo->dma_adapter_taken = TRUE; + + // + // allocate MSI-X vector map table + // + if ( pdev->n_msi_vectors_alloc ) + { + pdev->p_msix_map = kzalloc(sizeof(struct msix_map) * pdev->n_msi_vectors_alloc, GFP_KERNEL); + if ( !pdev->p_msix_map ) + { + MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, + ("Failed to allocate MSI-X vector map table\n")); + goto err; + } + } + + // + // fill more fields in pci_dev + // + pdev->ven_id = pdev->pci_cfg_space.VendorID; + pdev->dev_id = pdev->pci_cfg_space.DeviceID; + pdev->sub_vendor_id = pdev->pci_cfg_space.u.type0.SubVendorID; + pdev->sub_system_id = pdev->pci_cfg_space.u.type0.SubSystemID; + pdev->revision_id = pdev->pci_cfg_space.RevisionID; + pdev->p_self_do = WdfDeviceWdmGetDeviceObject(p_fdo->FdoDevice); + pdev->pdo = WdfDeviceWdmGetPhysicalDevice(p_fdo->FdoDevice); + + MLX4_EXIT( MLX4_DBG_DRV ); + return STATUS_SUCCESS; +err: + __put_resources(p_fdo); + MLX4_EXIT( MLX4_DBG_DRV ); + return status; +} + +NTSTATUS +EvtPrepareHardware( + IN WDFDEVICE Device, + IN WDFCMRESLIST ResourcesRaw, + IN WDFCMRESLIST ResourcesTranslated + ) +{ + NTSTATUS status; + PFDO_DEVICE_DATA p_fdo = FdoGetData(Device); + struct pci_dev *pdev = &p_fdo->pci_dev; + struct mlx4_dev *mdev; + WDFMEMORY memory; + WDF_OBJECT_ATTRIBUTES attributes; + + MLX4_ENTER(MLX4_DBG_DRV); + + // get resources + status = __get_resources( p_fdo, ResourcesRaw, ResourcesTranslated ); + if( !NT_SUCCESS( status ) ) { + MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, ("__get_resources failed: status=0x%x\n", status)); + goto err; + } + + pdev->p_wdf_device = Device; + pdev->ib_hca_created = 0; + + // start the card + status = __start_card(Device, p_fdo ); + if( !NT_SUCCESS( status ) ) + goto err; + mdev = pdev->dev; + + // get VPD - as far as it just info, we proceed the work in case of error + status = pci_get_vpd( &pdev->bus_pci_ifc, + &pdev->pci_cfg_space, &pdev->vpd, &pdev->vpd_size ); + if( !NT_SUCCESS( status ) ) + { + MLX4_PRINT_EV(TRACE_LEVEL_WARNING, MLX4_DBG_DRV, + ("Failed to read VPD from the card (status=0x%x). Continue the work.\n", status)); + } + + // get card location + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.ParentObject = Device; + status = WdfDeviceAllocAndQueryProperty( Device, + DevicePropertyLocationInformation, NonPagedPool, + &attributes, &memory ); + if( NT_SUCCESS( status ) ) { + UCHAR *ptr; + + // get location + ptr = WdfMemoryGetBuffer(memory, NULL); + status = RtlStringCbCopyW( (LPWSTR)p_fdo->pci_dev.location, + sizeof(p_fdo->pci_dev.location), (LPCWSTR)ptr ); + WdfObjectDelete(memory); + if( !NT_SUCCESS( status ) ) { + MLX4_PRINT_EV(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, + ("Failed to move location string '%S', status=0x%x\n", ptr, status)); + } + } + else { + MLX4_PRINT_EV(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, + ("WdfDeviceAllocAndQueryProperty failed, status=0x%x\n", status)); + } + +err: + MLX4_EXIT( MLX4_DBG_DRV ); + return status; +} + +void fix_bus_ifc(struct pci_dev *pdev) +{ + PFDO_DEVICE_DATA p_fdo; + + p_fdo = CONTAINING_RECORD(pdev, FDO_DEVICE_DATA, pci_dev); + p_fdo->bus_ib_ifc.p_ibdev = p_fdo->pci_dev.ib_dev; + p_fdo->bus_ib_ifc.pmlx4_dev = to_mdev(p_fdo->pci_dev.ib_dev)->dev; + p_fdo->bus_ib_ifc.is_livefish = mlx4_is_livefish(p_fdo->pci_dev.dev); +} + +NTSTATUS +EvtReleaseHardware( + IN WDFDEVICE Device, + IN WDFCMRESLIST ResourcesTranslated + ) +{ + PFDO_DEVICE_DATA p_fdo = FdoGetData(Device); + struct pci_dev *pdev = &p_fdo->pci_dev; + int i; + + UNUSED_PARAM(ResourcesTranslated); + + MLX4_ENTER(MLX4_DBG_DRV); + + if ( pdev->vpd ) { + kfree( pdev->vpd ); + pdev->vpd = NULL; + pdev->vpd_size = 0; + } + __stop_card( p_fdo ); + __put_resources( p_fdo ); + for (i=0; iint_num = int_num; + p_isr_ctx->p_fdo = p_fdo; + p_isr_ctx->eq = NULL; + + // one can call WdfInterruptSetPolicy() to set the policy, affinity etc + + MLX4_EXIT( MLX4_DBG_DRV ); + return Status; +} + +#endif + +inline void InitBusIsr( + struct VipBusIfc* pVipBusIfc + ) +{ + memset(pVipBusIfc, 0, sizeof(struct VipBusIfc)); + KeInitializeEvent(&pVipBusIfc->NicData.ConfigChangeEvent, SynchronizationEvent, TRUE); +} + +NTSTATUS +EvtDriverDeviceAdd( + IN WDFDRIVER Driver, + IN PWDFDEVICE_INIT DeviceInit + ) +/*++ +Routine Description: + + EvtDriverDeviceAdd is called by the framework in response to AddDevice + call from the PnP manager. We create and initialize a device object to + represent a new instance of mxe bus. + +Arguments: + + Driver - Handle to a framework driver object created in DriverEntry + + DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure. + +Return Value: + + NTSTATUS + +--*/ +{ +#ifndef USE_WDM_INTERRUPTS + int i; +#endif + WDF_OBJECT_ATTRIBUTES attributes; + NTSTATUS status; + WDFDEVICE device; + PFDO_DEVICE_DATA p_fdo; + PNP_BUS_INFORMATION busInfo; + WDF_PNPPOWER_EVENT_CALLBACKS Callbacks; + int i; + + UNREFERENCED_PARAMETER(Driver); + + PAGED_CODE (); + MLX4_ENTER(MLX4_DBG_DRV); + + // + // register PnP & Power stuff + // + WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&Callbacks); + Callbacks.EvtDevicePrepareHardware = EvtPrepareHardware; + Callbacks.EvtDeviceReleaseHardware = EvtReleaseHardware; + Callbacks.EvtDeviceD0Entry = EvtDeviceD0Entry; + Callbacks.EvtDeviceD0Exit = EvtDeviceD0Exit; + + WdfDeviceInitSetPnpPowerEventCallbacks( DeviceInit, &Callbacks ); + + // + // Initialize all the properties specific to the device. + // Framework has default values for the one that are not + // set explicitly here. So please read the doc and make sure + // you are okay with the defaults. + // + WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_BUS_EXTENDER); + WdfDeviceInitSetExclusive(DeviceInit, TRUE); + + // + // Initialize attributes structure to specify size and accessor function + // for storing device context. + // + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, FDO_DEVICE_DATA); + + // + // Create a framework device object. In response to this call, framework + // creates a WDM deviceobject. + // + status = WdfDeviceCreate(&DeviceInit, &attributes, &device); + if (!NT_SUCCESS(status)) { + MLX4_PRINT(TRACE_LEVEL_VERBOSE, MLX4_DBG_DRV, + ("WdfDeviceCreate failed with 0x%x\n", status)); + goto end; + } + + // + // Get the device context. + // + p_fdo = FdoGetData(device); + RtlZeroMemory(p_fdo, sizeof(FDO_DEVICE_DATA)); + p_fdo->FdoDevice = device; + for (i=0; imtnic_Ifc); + + // + // Purpose of this lock is documented in PlugInDevice routine below. + // + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.ParentObject = device; + status = WdfWaitLockCreate(&attributes, &p_fdo->ChildLock); + if (!NT_SUCCESS(status)) { + MLX4_PRINT(TRACE_LEVEL_VERBOSE, MLX4_DBG_DRV, + ("WdfWaitLockCreate failed with 0x%x\n", status)); + goto end; + } + + // + // This value is used in responding to the IRP_MN_QUERY_BUS_INFORMATION + // for the child devices. This is an optional information provided to + // uniquely identify the bus the device is connected. + // + busInfo.BusTypeGuid = MLX4_BUS_TYPE_GUID; + busInfo.LegacyBusType = PNPBus; + busInfo.BusNumber = 0; + + WdfDeviceSetBusInformationForChildren(device, &busInfo); + + // + // WMI + // + status = WmiRegistration(device); + if (!NT_SUCCESS(status)) { + MLX4_PRINT(TRACE_LEVEL_VERBOSE, MLX4_DBG_DRV, + ("WmiRegistration failed with 0x%x\n", status)); + goto end; + } + +#ifndef USE_WDM_INTERRUPTS + + // + // create interrupt objects + // + for ( i = 0; i < MLX4_MAX_INTERRUPTS; ++i ) { + status = __create_interrupt( p_fdo->FdoDevice, i, EvtInterruptIsr, + NULL, p_fdo, &p_fdo->interrupt[i].WdfInterrupt ); + if (NT_SUCCESS(status)) + p_fdo->interrupt[i].valid = TRUE; + else { + MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, + ("WdfInterruptCreate failed %#x\n", status )); + goto end; + } + } + +#endif + + // statistics + p_fdo->pci_dev.p_stat_dev = st_dev_add(); + if ( p_fdo->pci_dev.p_stat_dev ) { + p_fdo->pci_dev.p_stat_dev->p_fdo = p_fdo; + p_fdo->pci_dev.p_stat_dev->h_wdf_device = device; + p_fdo->pci_dev.p_stat_dev->flags = g.mod_stat_flags; + } + + status = STATUS_SUCCESS; + +end: + MLX4_EXIT( MLX4_DBG_DRV ); + return status; +} + + + +void +EvtDriverUnload( + IN WDFDRIVER Driver + ) +{ + MLX4_ENTER( MLX4_DBG_DRV ); + + UNUSED_PARAM( Driver ); + + mlx4_ib_cleanup(); + core_cleanup(); + + MLX4_EXIT( MLX4_DBG_DRV ); +#if defined(EVENT_TRACING) + WPP_CLEANUP(WdfDriverWdmGetDriverObject(Driver)); +#endif + +} + +static +NTSTATUS +__read_registry(WDFDRIVER *hDriver) +{ + DECLARE_CONST_UNICODE_STRING(debugLevel, L"DebugLevel"); + DECLARE_CONST_UNICODE_STRING(debugFlags, L"DebugFlags"); + + // "log maximum number of QPs per HCA" + DECLARE_CONST_UNICODE_STRING(numQp, L"LogNumQp"); + + // "log number of RDMARC buffers per QP" + DECLARE_CONST_UNICODE_STRING(numRdmaRc, L"LogNumRdmaRc"); + + // "log maximum number of SRQs per HCA" + DECLARE_CONST_UNICODE_STRING(numSrq, L"LogNumSrq"); + + // "log maximum number of CQs per HCA" + DECLARE_CONST_UNICODE_STRING(numCq, L"LogNumCq"); + + // "log maximum number of multicast groups per HCA" + DECLARE_CONST_UNICODE_STRING(numMcg, L"LogNumMcg"); + + // "log maximum number of memory protection table entries per HCA" + DECLARE_CONST_UNICODE_STRING(numMpt, L"LogNumMpt"); + + // "log maximum number of memory translation table segments per HCA" + DECLARE_CONST_UNICODE_STRING(numMtt, L"LogNumMtt"); + + // "Maximum number of MACs per ETH port (1-127, default 0" + DECLARE_CONST_UNICODE_STRING(numMac, L"NumMac"); + + // "Maximum number of VLANs per ETH port (0-126, default 0)" + DECLARE_CONST_UNICODE_STRING(numVlan, L"NumVlan"); + + // "Enable steering by VLAN priority on ETH ports (0/1, default 0)" + DECLARE_CONST_UNICODE_STRING(usePrio, L"UsePrio"); + + // "max number of FC_EXCH (0-N, default 0)" + DECLARE_CONST_UNICODE_STRING(numFcExch, L"NumFcExch"); + + // "Enable Quality of Service support in the HCA if > 0, (default 1)" + DECLARE_CONST_UNICODE_STRING(enableQoS, L"EnableQoS"); + + // "Block multicast loopback packets if > 0 (default 1)" + DECLARE_CONST_UNICODE_STRING(BlockMcastLB, L"BlockMcastLoopBack"); + + // "Measure the interrupt from the first packet (default 1)" + DECLARE_CONST_UNICODE_STRING(InterruptFromFirstPacket, L"InterruptFromFirstPacket"); + + // "ProcessorAffinity" + DECLARE_CONST_UNICODE_STRING(ProcessorAffinity, L"ProcessorAffinity"); + + // "Stat Flags" + DECLARE_CONST_UNICODE_STRING(StatFlags, L"StatFlags"); + + ULONG value; + WDFKEY hKey = NULL; + NTSTATUS status = STATUS_SUCCESS; + + status = WdfDriverOpenParametersRegistryKey( *hDriver, + STANDARD_RIGHTS_ALL, WDF_NO_OBJECT_ATTRIBUTES, &hKey ); + + if (NT_SUCCESS (status)) { + + // + // Read general values + // + status = WdfRegistryQueryULong(hKey, &debugLevel, &value); + if (NT_SUCCESS (status)) + g_mlx4_dbg_level = g.bwsd.DebugPrintLevel = value; + + status = WdfRegistryQueryULong(hKey, &debugFlags, &value); + if (NT_SUCCESS (status)) + g_mlx4_dbg_flags = g.bwsd.DebugPrintFlags = value; + + status = WdfRegistryQueryULong(hKey, &numQp, &value); + if (NT_SUCCESS (status)) + g.mod_num_qp = value; + + status = WdfRegistryQueryULong(hKey, &numRdmaRc, &value); + if (NT_SUCCESS (status)) + g.mod_rdmarc_per_qp = value; + + status = WdfRegistryQueryULong(hKey, &numSrq, &value); + if (NT_SUCCESS (status)) + g.mod_num_srq = value; + + status = WdfRegistryQueryULong(hKey, &numCq, &value); + if (NT_SUCCESS (status)) + g.mod_num_cq = value; + + status = WdfRegistryQueryULong(hKey, &numMcg, &value); + if (NT_SUCCESS (status)) + g.mod_num_mcg = value; + + status = WdfRegistryQueryULong(hKey, &numMpt, &value); + if (NT_SUCCESS (status)) + g.mod_num_mpt = value; + + status = WdfRegistryQueryULong(hKey, &numMtt, &value); + if (NT_SUCCESS (status)) + g.mod_num_mtt = value; + + status = WdfRegistryQueryULong(hKey, &numMac, &value); + if (NT_SUCCESS (status)) + g.mod_num_mac = value; + else + g.mod_num_mac = 0; + + status = WdfRegistryQueryULong(hKey, &numVlan, &value); + if (NT_SUCCESS (status)) + g.mod_num_vlan= value; + else + g.mod_num_vlan = 0; + + status = WdfRegistryQueryULong(hKey, &usePrio, &value); + if (NT_SUCCESS (status)) + g.mod_use_prio= value; + else + g.mod_use_prio = 0; + + status = WdfRegistryQueryULong(hKey, &numFcExch, &value); + if (NT_SUCCESS (status)) + g.mod_num_fc_exch= value; + else + g.mod_num_fc_exch = 0; + + status = WdfRegistryQueryULong(hKey, &enableQoS, &value); + if (NT_SUCCESS (status)) + g.mod_enable_qos = value; + else + g.mod_enable_qos = 0; + + + status = WdfRegistryQueryULong(hKey, &BlockMcastLB, &value); + if (NT_SUCCESS (status)) + g.mod_mlx4_blck_lb = value; + else + g.mod_mlx4_blck_lb = 1; + + status = WdfRegistryQueryULong(hKey, &InterruptFromFirstPacket, &value); + if (NT_SUCCESS (status)) + g.mod_interrupt_from_first = value; + else + g.mod_interrupt_from_first = 1; + + + status = WdfRegistryQueryULong(hKey, &ProcessorAffinity, &value); + if (NT_SUCCESS (status)) + g.mod_affinity = value; + else + g.mod_affinity = 0; + + status = WdfRegistryQueryULong(hKey, &StatFlags, &value); + if (NT_SUCCESS (status)) + g.mod_stat_flags = value; + else + g.mod_stat_flags = 0; + + + WdfRegistryClose(hKey); + status = STATUS_SUCCESS; + } + + return status; +} + +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath + ) +/*++ +Routine Description: + + Initialize the call backs structure of Driver Framework. + +Arguments: + + DriverObject - pointer to the driver object + + RegistryPath - pointer to a unicode string representing the path, + to driver-specific key in the registry. + +Return Value: + + NT Status Code + +--*/ +{ + int err; + WDF_DRIVER_CONFIG config; + NTSTATUS status; + WDFDRIVER hDriver; + +#if defined(EVENT_TRACING) + WPP_INIT_TRACING(DriverObject, RegistryPath); +#endif + + + // global initializations + RtlZeroMemory( &g, sizeof(g) ); + g_mlx4_dbg_level = g.bwsd.DebugPrintLevel = TRACE_LEVEL_VERBOSE; + g_mlx4_dbg_flags = g.bwsd.DebugPrintFlags = 0xffff; + + MLX4_ENTER(MLX4_DBG_DRV); + MLX4_PRINT(TRACE_LEVEL_INFORMATION, MLX4_DBG_DRV, + ("Built %s %s, Version %s, RelDate %s\n", + __DATE__, __TIME__, DRV_VERSION, DRV_RELDATE)); + + mlx4_net_init(); + err = core_init(); + if (err) { + status = errno_to_ntstatus(err); + goto end; + } + err = mlx4_ib_init(); + if (err) { + status = errno_to_ntstatus(err); + goto end; + } + + // + // Initiialize driver config to control the attributes that + // are global to the driver. Note that framework by default + // provides a driver unload routine. If you create any resources + // in the DriverEntry and want to be cleaned in driver unload, + // you can override that by specifing one in the Config structure. + // + + WDF_DRIVER_CONFIG_INIT( + &config, EvtDriverDeviceAdd ); + config.EvtDriverUnload = EvtDriverUnload; + + // + // Create a framework driver object to represent our driver. + // + status = WdfDriverCreate(DriverObject, + RegistryPath, WDF_NO_OBJECT_ATTRIBUTES, + &config, &hDriver); + + if (!NT_SUCCESS(status)) { + MLX4_PRINT(TRACE_LEVEL_VERBOSE, MLX4_DBG_DRV, ("WdfDriverCreate failed with status 0x%x\n", status)); + goto end; + } + + // + // read registry parameters + // + status = __read_registry(&hDriver); + + // statistics + RtlZeroMemory( &g_stat, sizeof(g_stat) ); + g_stat.drv.p_globals = &g; + g_stat.drv.h_wdf_driver = hDriver; + + // we don't matter the failure in the work with Registry + status = STATUS_SUCCESS; + +end: + MLX4_EXIT( MLX4_DBG_DRV ); + return status; + +} + + + + diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/drv/drv.h b/branches/WOF2-3/hw/mlx4/kernel/bus/drv/drv.h new file mode 100644 index 00000000..1b63fb7a --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/drv/drv.h @@ -0,0 +1,242 @@ +/*++ + +Copyright (c) 2003 Microsoft Corporation All Rights Reserved + +Module Name: + + mxe_drv.h + +Abstract: + + This module contains the common private declarations + for the Mxe Bus enumerator. + +Environment: + + kernel mode only + +--*/ + +#pragma once + +#define BUSENUM_POOL_TAG (ULONG) 'suBT' +#define N_BARS 3 + +#include "net\mlx4.h" +#include "bus_intf.h" + +#if DBG +#define BUS_DEFAULT_DEBUG_OUTPUT_LEVEL 0x000FFFFF + +#else + +#define BUS_DEFAULT_DEBUG_OUTPUT_LEVEL 0x0 + +#endif + +#define BUSRESOURCENAME L"MofResourceName" + +#ifndef min +#define min(_a, _b) (((_a) < (_b)) ? (_a) : (_b)) +#endif + +#ifndef max +#define max(_a, _b) (((_a) > (_b)) ? (_a) : (_b)) +#endif + + +#define MLX4_MAX_INTERRUPTS MLX4_NUM_EQS + +typedef struct { + WDFINTERRUPT WdfInterrupt; + BOOLEAN valid; +} res_interrupt_t; + +// +// The device extension of the bus itself. From whence the PDO's are born. +// + +typedef struct _FDO_DEVICE_DATA +{ + BUS_WMI_STD_DATA WmiData; + WDFWAITLOCK ChildLock; + WDFDEVICE FdoDevice; + struct pci_dev pci_dev; + int card_started; + int pci_bus_ifc_taken; + WDFDMAENABLER dma_enabler; + int dma_adapter_taken; + res_interrupt_t interrupt[MLX4_MAX_INTERRUPTS]; + MLX4_BUS_IB_INTERFACE bus_ib_ifc; + int children_created; + // Data for the Ethernet device + struct VipBusIfc mtnic_Ifc; + +} FDO_DEVICE_DATA, *PFDO_DEVICE_DATA; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(FDO_DEVICE_DATA, FdoGetData) + +// +// The device extension for the PDOs. +// That's of the mxe device which this bus driver enumerates. +// + +typedef struct _PDO_DEVICE_DATA +{ + // Unique serial number of the device on the bus + ULONG SerialNo; + // WDF PDO object + WDFDEVICE PdoDevice; + // FDO context + PFDO_DEVICE_DATA p_fdo; + // MLX4 BUS IB interface + WDF_QUERY_INTERFACE_CONFIG qiMlx4Bus; + WDF_QUERY_INTERFACE_CONFIG qiPciBus; + +} PDO_DEVICE_DATA, *PPDO_DEVICE_DATA; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(PDO_DEVICE_DATA, PdoGetData) + + +typedef struct _QUEUE_DATA +{ + PFDO_DEVICE_DATA FdoData; + +} QUEUE_DATA, *PQUEUE_DATA; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(QUEUE_DATA, QueueGetData) + + // +// wmi.c +// + +NTSTATUS +WmiRegistration( + WDFDEVICE Device +); + +NTSTATUS +EvtStdDataSetItem( + IN WDFWMIINSTANCE WmiInstance, + IN ULONG DataItemId, + IN ULONG InBufferSize, + IN PVOID InBuffer + ); + +NTSTATUS +EvtStdDataSetInstance( + IN WDFWMIINSTANCE WmiInstance, + IN ULONG InBufferSize, + IN PVOID InBuffer + ); + +NTSTATUS +EvtStdDataQueryInstance( + IN WDFWMIINSTANCE WmiInstance, + IN ULONG OutBufferSize, + IN PVOID OutBuffer, + OUT PULONG BufferUsed + ); + + +// +// drv.c +// + +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath + ); + +void +EvtDriverUnload( + IN WDFDRIVER Driver + ); + +NTSTATUS +EvtDriverDeviceAdd( + IN WDFDRIVER Driver, + IN PWDFDEVICE_INIT DeviceInit + ); + +NTSTATUS +EvtPrepareHardware( + IN WDFDEVICE Device, + IN WDFCMRESLIST ResourcesRaw, + IN WDFCMRESLIST ResourcesTranslated + ); + +NTSTATUS +EvtReleaseHardware( + IN WDFDEVICE Device, + IN WDFCMRESLIST ResourcesTranslated + ); + +NTSTATUS +EvtDeviceD0Exit( + IN WDFDEVICE Device, + IN WDF_POWER_DEVICE_STATE TargetState + ); + +NTSTATUS +EvtDeviceD0Entry( + IN WDFDEVICE Device, + IN WDF_POWER_DEVICE_STATE PreviousState + ); + + +// +// pci.c +// + +void +pci_free_msix_info_resources( + IN struct msix_saved_info * pMsixInfo + ); + +NTSTATUS +pci_save_config( + IN BUS_INTERFACE_STANDARD *pBusIfc, + OUT PCI_COMMON_CONFIG* const pConfig + ); + +NTSTATUS pci_get_vpd( + IN BUS_INTERFACE_STANDARD *pBusIfc, + IN PCI_COMMON_CONFIG* const pConfig, + OUT UCHAR* *p_vpd, + IN OUT int* p_vpd_size + ); + +NTSTATUS +pci_hca_reset( + IN struct pci_dev *pdev + ); + +void +pci_get_uplink_info( + IN PCI_COMMON_CONFIG * p_cfg, + OUT uplink_info_t * p_uplink_info + ); + +NTSTATUS +pci_hca_enable( + IN PBUS_INTERFACE_STANDARD p_ifc, + IN PCI_COMMON_CONFIG* p_cfg + ); + +// +// pdo.c +// + +NTSTATUS +create_pdo( + __in WDFDEVICE Device, + __in PWCHAR HardwareIds, + __in PWCHAR DeviceDescription, + __in ULONG SerialNo, + __in PWCHAR Location +); + + + diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/drv/makefile b/branches/WOF2-3/hw/mlx4/kernel/bus/drv/makefile new file mode 100644 index 00000000..a0343a17 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/drv/makefile @@ -0,0 +1,8 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the Windows NT DDK +# +!INCLUDE ..\..\..\..\..\inc\openib.def + + diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/drv/makefile.inc b/branches/WOF2-3/hw/mlx4/kernel/bus/drv/makefile.inc new file mode 100644 index 00000000..b23286df --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/drv/makefile.inc @@ -0,0 +1,24 @@ +mofcomp: mlx4_bus.bmf + +mlx4_bus.bmf: bus.mof + mofcomp -B:$(OBJ_PATH)\$O\mlx4_bus.bmf bus.mof + wmimofck $(OBJ_PATH)\$O\mlx4_bus.bmf + + +# Transform .inx file to .inf file adding date + major,min & svn.version stamp +# Output .inf file is copied to the $(INF_TARGET) folder (commonly where .sys file resides). + +_LNG=$(LANGUAGE) + +!IF !DEFINED(_INX) +_INX=. +!ENDIF + +STAMP=stampinf -a $(_BUILDARCH) -k $(KMDF_VERSION_MAJOR).$(KMDF_VERSION_MINOR) + +!INCLUDE mod_ver.def + +$(INF_TARGET) : $(_INX)\$(INF_NAME).inx + copy $(_INX)\$(@B).inx $@ + $(STAMP) -f $@ -d * -v $(IB_MAJORVERSION).$(IB_MINORVERSION).$(IB_BUILDVERSION).$(OPENIB_REV) + diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/drv/mlx4_bus.cdf b/branches/WOF2-3/hw/mlx4/kernel/bus/drv/mlx4_bus.cdf new file mode 100644 index 00000000..2e0d1430 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/drv/mlx4_bus.cdf @@ -0,0 +1,9 @@ +[CatalogHeader] +Name=mlx4_bus.cat +PublicVersion=0x0000001 +EncodingType=0x00010001 +CATATTR1=0x10010001:OSAttr:2:6.0 +[CatalogFiles] +mlx4_bus.inf=mlx4_bus.inf +mlx4_bus.sys=mlx4_bus.sys +WdfCoInstaller01007.dll=WdfCoInstaller01007.dll diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/drv/mlx4_bus.inx b/branches/WOF2-3/hw/mlx4/kernel/bus/drv/mlx4_bus.inx new file mode 100644 index 00000000..bc0f8413 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/drv/mlx4_bus.inx @@ -0,0 +1,303 @@ +; Mellanox Technologies InfiniBand HCAs. +; Copyright 2008 Mellanox Technologies all Rights Reserved. + +[Version] +Signature="$WINDOWS NT$" +Class=Net +ClassGUID = {4d36e972-e325-11ce-bfc1-08002be10318} + + +Provider=%MTL% +; must be synchronized with bus\drv.c +DriverVer=02/01/2008,1.0.0.0 +CatalogFile=mlx4_bus.cat + + +;***************************************** +; Destination directory section +;***************************************** + +[DestinationDirs] +DefaultDestDir = 12 +Wdf_CoInstaller_CopyFiles = 11 + + +;***************************************** +; Class Install section +;***************************************** + +[ClassInstall32] +AddReg=ClassAddReg + +[ClassAddReg] +HKR,,,,"Mellanox ConnectX Adapters" +HKR,,Icon,,-5 +HKR,,SilentInstall,,1 + + +;***************************************** +; Device Install section +;***************************************** + +[SourceDisksNames.x86] +1=%DiskId%,,,"" + +[SourceDisksNames.amd64] +1=%DiskId%,,,"" + +[SourceDisksNames.ia64] +1=%DiskId%,,,"" + +[SourceDisksFiles.x86] +mlx4_bus.sys = 1,, +wdfcoinstaller$KMDFCOINSTALLERVERSION$.dll = 1,, + +[SourceDisksFiles.amd64] +mlx4_bus.sys = 1,, +wdfcoinstaller$KMDFCOINSTALLERVERSION$.dll = 1,, + +[SourceDisksFiles.ia64] +mlx4_bus.sys = 1,, +wdfcoinstaller$KMDFCOINSTALLERVERSION$.dll = 1,, + +;***************************************** +; Mlx4Bus Install Section +;***************************************** + +[Manufacturer] +%MTL% = MLX4BUS.DeviceSection,ntx86,ntamd64,ntia64 + +[MLX4BUS.DeviceSection] +; empty since we don't support W9x/Me + +[MLX4BUS.DeviceSection.ntx86] +%MT25408.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_6340 +%MT25418.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_634A +%MT25448.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_6368 +%MT25458.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_6372 +%MT26418.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_6732 +%MT26488.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_6778 +%MT26428.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_673c +%MT26438.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_6746 +%MT26448.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_6750 +%MT26458.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_675A +%MT26468.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_6764 +%MT26478.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_676E +%MT00401.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_0191 + +[MLX4BUS.DeviceSection.ntamd64] +%MT25408.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_6340 +%MT25418.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_634A +%MT25448.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_6368 +%MT25458.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_6372 +%MT26418.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_6732 +%MT26488.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_6778 +%MT26428.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_673c +%MT26438.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_6746 +%MT26448.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_6750 +%MT26458.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_675A +%MT26468.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_6764 +%MT26478.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_676E +%MT00401.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_0191 + +[MLX4BUS.DeviceSection.ntia64] +%MT25408.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_6340 +%MT25418.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_634A +%MT25448.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_6368 +%MT25458.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_6372 +%MT26418.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_6732 +%MT26488.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_6778 +%MT26428.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_673c +%MT26438.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_6746 +%MT26448.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_6750 +%MT26458.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_675A +%MT26468.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_6764 +%MT26478.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_676E +%MT00401.DeviceDesc%=MLX4BUS.DDInstall, PCI\VEN_15B3&DEV_0191 + +[MLX4BUS.DDInstall.ntx86.hw] +AddReg = MLX4BUS.HwReg + +[MLX4BUS.DDInstall.ntamd64.hw] +AddReg = MLX4BUS.HwReg + +[MLX4BUS.DDInstall.ntia64.hw] +AddReg = MLX4BUS.HwReg + +[MLX4BUS.HwReg] +HKR,"Interrupt Management",,0x00000010 +HKR,"Interrupt Management\MessageSignaledInterruptProperties",,0x00000010 + +; MSI-X support +HKR,"Interrupt Management\MessageSignaledInterruptProperties",MSISupported,0x00010001,1 +HKR,"Interrupt Management\MessageSignaledInterruptProperties",MessageNumberLimit,0x00010001,18 +HKR,"Interrupt Management\Affinity Policy",,0x00000010 + +; AssignmentSetOverride - processors KAFFINITY mask +HKR,"Interrupt Management\Affinity Policy",AssignmentSetOverride,0x00000001,0x0 + +; IrqPolicyMachineDefault (0) - use default policy for the computer +; IrqPolicyAllCloseProcessors (1) - connect interrupts to all processors of the near NUMA node +; IrqPolicyOneCloseProcessor (2) - connect interrupts to one processor +; IrqPolicyAllProcessorsInMachine (3) - connect interrupts to all processors in the machine +; IrqPolicySpecifiedProcessors (4) - connects interrupts according to AssignmentSetOverride +; IrqPolicySpreadMessagesAcrossAllProcessors (5) - assign different message-based interrupts to different processors +HKR,"Interrupt Management\Affinity Policy",DevicePolicy,0x00010001,0x5 + +; IrqArbPriorityUndefined (0) - no interrupt priority policy. +; IrqArbPriorityLow (1) - device can tolerate low IRQL +; IrqArbPriorityNormal (2) - device expects normal interrupt latencies +; IrqArbPriorityHigh (3) - device requires the lowest possible interrupt latency +HKR,"Interrupt Management\Affinity Policy",DevicePriority,0x00010001,0x3 + +[MLX4BUS.DDInstall.ntx86] +CopyFiles = MLX4BUS.CopyFiles +AddReg = MLX4BUS.SoftwareReg +Characteristics = 0x4 ;NCF_PHYSICAL +BusType = 5; PCIBus + + +[MLX4BUS.DDInstall.ntamd64] +CopyFiles = MLX4BUS.CopyFiles +AddReg = MLX4BUS.SoftwareReg +Characteristics = 0x4 ;NCF_PHYSICAL +BusType = 5; PCIBus + + +[MLX4BUS.DDInstall.ntia64] +CopyFiles = MLX4BUS.CopyFiles +AddReg = MLX4BUS.SoftwareReg +Characteristics = 0x4 ;NCF_PHYSICAL +BusType = 5; PCIBus + + +[MLX4BUS.DDInstall.ntx86.Services] +AddService = mlx4_bus,%SPSVCINST_ASSOCSERVICE%,MLX4BUS.ServiceInstall,MLX4BUS.EventLog + +[MLX4BUS.DDInstall.ntamd64.Services] +AddService = mlx4_bus,%SPSVCINST_ASSOCSERVICE%,MLX4BUS.ServiceInstall,MLX4BUS.EventLog + +[MLX4BUS.DDInstall.ntia64.Services] +AddService = mlx4_bus,%SPSVCINST_ASSOCSERVICE%,MLX4BUS.ServiceInstall,MLX4BUS.EventLog + +[MLX4BUS.CopyFiles] +mlx4_bus.sys + + +;***************************************** +; Service Install section +;***************************************** + +[MLX4BUS.ServiceInstall] +DisplayName = %MLX4BUS.ServiceDesc% +ServiceType = %SERVICE_KERNEL_DRIVER% +StartType = %SERVICE_BOOT_START% +ErrorControl = %SERVICE_ERROR_NORMAL% +ServiceBinary = %12%\mlx4_bus.sys +LoadOrderGroup = NDIS +AddReg = MLX4BUS.ParamsReg + +[MLX4BUS.EventLog] +AddReg = MLX4BUS.AddEventLogReg + +[MLX4BUS.AddEventLogReg] +HKR, , EventMessageFile, 0x00020000, "%%SystemRoot%%\System32\IoLogMsg.dll;%%SystemRoot%%\System32\drivers\mlx4_bus.sys" +HKR, , TypesSupported, 0x00010001, 7 + +[MLX4BUS.SoftwareReg] +HKR,"Parameters","PortType",%REG_SZ%,"ib,ib" + +[MLX4BUS.ParamsReg] +HKR,,DeviceCharacteristics,0x10001,0x0100 ; Use same security checks on relative opens +HKR,,Security,,"D:P(A;;GA;;;BA)(A;;GA;;;SY)" ; Allow generic-all access to Built-in administrators and Local system +HKR,"Parameters","DebugLevel",%REG_DWORD%,0x00000003 +HKR,"Parameters","DebugFlags",%REG_DWORD%,0x0000ffff +HKR,"Parameters","LogNumQp",%REG_DWORD%,0x00000011 +HKR,"Parameters","LogNumRdmaRc",%REG_DWORD%,0x00000004 +HKR,"Parameters","LogNumSrq",%REG_DWORD%,0x00000010 +HKR,"Parameters","LogNumCq",%REG_DWORD%,0x00000010 +HKR,"Parameters","LogNumMcg",%REG_DWORD%,0x0000000D +HKR,"Parameters","LogNumMpt",%REG_DWORD%,0x00000012 +HKR,"Parameters","LogNumMtt",%REG_DWORD%,0x00000014 +HKR,"Parameters","EnableQoS",%REG_DWORD%,0x00000000 +HKR,"Parameters","BlockMcastLoopBack",%REG_DWORD%,0x00000000 +HKR,"Parameters","InterruptFromFirstPacket",%REG_DWORD%,0x00000001 + +HKR,"Parameters","NumMac",%REG_DWORD%,0x00000000 +HKR,"Parameters","NumVlan",%REG_DWORD%,0x00000000 +HKR,"Parameters","UsePrio",%REG_DWORD%,0x00000000 +HKR,"Parameters","NumFcExch",%REG_DWORD%,0x00000000 + + + +HKLM,"System\CurrentControlSet\Control\WMI\GlobalLogger\E51BB6E2-914A-4e21-93C0-192F4801BBFF","Flags",%REG_DWORD%,0xffff +HKLM,"System\CurrentControlSet\Control\WMI\GlobalLogger\E51BB6E2-914A-4e21-93C0-192F4801BBFF","Level",%REG_DWORD%,0x3 + +;***************************************** +; WDF Coinstaller installation section +;***************************************** + +[MLX4BUS.DDInstall.ntx86.CoInstallers] +AddReg=Wdf_CoInstaller_AddReg +CopyFiles=Wdf_CoInstaller_CopyFiles + +[MLX4BUS.DDInstall.ntamd64.CoInstallers] +AddReg=Wdf_CoInstaller_AddReg +CopyFiles=Wdf_CoInstaller_CopyFiles + +[MLX4BUS.DDInstall.ntia64.CoInstallers] +AddReg=Wdf_CoInstaller_AddReg +CopyFiles=Wdf_CoInstaller_CopyFiles + +[Wdf_CoInstaller_AddReg] +HKR,,CoInstallers32,0x00010000, "wdfcoinstaller$KMDFCOINSTALLERVERSION$.dll,WdfCoInstaller" + +[Wdf_CoInstaller_CopyFiles] +wdfcoinstaller$KMDFCOINSTALLERVERSION$.dll + +[MLX4BUS.DDInstall.ntx86.Wdf] +KmdfService = mlx4_bus, mlx4_bus_wdfsect + +[MLX4BUS.DDInstall.ntamd64.Wdf] +KmdfService = mlx4_bus, mlx4_bus_wdfsect + +[MLX4BUS.DDInstall.ntia64.Wdf] +KmdfService = mlx4_bus, mlx4_bus_wdfsect + +[mlx4_bus_wdfsect] +KmdfLibraryVersion = $KMDFVERSION$ + + +;***************************************** +; Strings +;***************************************** + +[Strings] +MTL="Mellanox Technologies Ltd." +MLX4BUS.ServiceDesc = "Mellanox ConnectX Bus Enumerator" +; VPI +MT25408.DeviceDesc="Mellanox ConnectX VPI (MT25408) - PCIe 2.0 2.5GT/s, IB SDR / 10GigE Network Adapter" +MT25418.DeviceDesc="Mellanox ConnectX VPI (MT25418) - PCIe 2.0 2.5GT/s, IB DDR / 10GigE Network Adapter" +MT26418.DeviceDesc="Mellanox ConnectX VPI (MT26418) - PCIe 2.0 5GT/s, IB DDR / 10GigE Network Adapter" +MT26488.DeviceDesc="Mellanox ConnectX VPI (MT26488) - PCIe 2.0 5GT/s, IB DDR / 10GigE Network Adapter" +MT26428.DeviceDesc="Mellanox ConnectX VPI (MT26428) - PCIe 2.0 5GT/s, IB QDR / 10GigE Network Adapter" +MT26438.DeviceDesc="Mellanox ConnectX VPI (MT26438) - PCIe 2.0 5GT/s, IB QDR / 10GigE Network Adapter" +; EN +MT25448.DeviceDesc="Mellanox ConnectX EN (MT25448) - PCIe 2.0 2.5GT/s, 10GigE Ethernet Adapter" +MT25458.DeviceDesc="Mellanox ConnectX EN (MT25458) - PCIe 2.0 2.5GT/s, 10GigE 10GBaseT Ethernet Adapter" +MT26448.DeviceDesc="Mellanox ConnectX EN (MT26448) - PCIe 2.0 5GT/s, 10GigE Ethernet Adapter" +MT26458.DeviceDesc="Mellanox ConnectX EN (MT26458) - PCIe 2.0 5GT/s, 10GigE 10GBaseT Ethernet Adapter" +MT26468.DeviceDesc="Mellanox ConnectX EN (MT26468) - PCIe 2.0 5GT/s, 10GigE Ethernet Adapter" +MT26478.DeviceDesc="Mellanox ConnectX EN (MT26478) - PCIe 2.0 5GT/s, 40GigE Ethernet Adapter" +; Burner +MT00401.DeviceDesc="Mellanox ConnectX (MT00401) - Network Adapter in Flash Recovery Mode" +DiskId = "Mellanox Mlx4 Bus installation disk" +SPSVCINST_NULL = 0x0 +SPSVCINST_ASSOCSERVICE = 0x00000002 +SERVICE_KERNEL_DRIVER = 1 +SERVICE_BOOT_START = 0 +SERVICE_DEMAND_START = 3 +SERVICE_ERROR_NORMAL = 1 +REG_DWORD = 0x00010001 +REG_MULTI_SZ_APPEND = 0x00010008 +REG_SZ = 0x00000000 diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/drv/mlx4_bus32.cdf b/branches/WOF2-3/hw/mlx4/kernel/bus/drv/mlx4_bus32.cdf new file mode 100644 index 00000000..2e0d1430 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/drv/mlx4_bus32.cdf @@ -0,0 +1,9 @@ +[CatalogHeader] +Name=mlx4_bus.cat +PublicVersion=0x0000001 +EncodingType=0x00010001 +CATATTR1=0x10010001:OSAttr:2:6.0 +[CatalogFiles] +mlx4_bus.inf=mlx4_bus.inf +mlx4_bus.sys=mlx4_bus.sys +WdfCoInstaller01007.dll=WdfCoInstaller01007.dll diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/drv/pci.c b/branches/WOF2-3/hw/mlx4/kernel/bus/drv/pci.c new file mode 100644 index 00000000..a036e389 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/drv/pci.c @@ -0,0 +1,942 @@ + +#include "precomp.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "pci.tmh" +#endif + +#include +#include +#include + +#define MLX4_RESET_BASE 0xf0000 +#define MLX4_RESET_SIZE 0x400 +#define MLX4_SEM_OFFSET 0x3fc +#define MLX4_RESET_OFFSET 0x10 +#define MLX4_RESET_VALUE swab32(1) + +#define MLX4_SEM_TIMEOUT_JIFFIES (10 * HZ) +#define MLX4_RESET_TIMEOUT_JIFFIES (2 * HZ) + +//#define PCI_CAPABILITY_ID_VPD 0x03 +//#define PCI_CAPABILITY_ID_PCIX 0x07 +//#define PCI_CAPABILITY_ID_PCI_EXPRESS 0x10 +//#define PCI_CAPABILITY_ID_MSIX 0x11 + +/* + * MSI-X Capability + */ +typedef struct _PCI_MSIX_CAPABILITY { + + PCI_CAPABILITIES_HEADER Header; + + USHORT Flags; + ULONG Table_Offset; + ULONG PBA_Offset; + +} PCI_MSIX_CAPABILITY, *PPCI_MSIX_CAPABILITY; + +#define MSIX_FLAGS_MSIX_ENABLE(flags) (((flags)>>15)&1) /* MSI-X is enabled */ +#define MSIX_FLAGS_MSIX_FUNCTION_MASK(flags) (((flags)>>14)&1) /* all interrupts masked */ +#define MSIX_FLAGS_SUPPORTED(flags) ((flags)&0x07ff) /* vector table size */ +#define MSIX_OFFSET_BIR(offset) ((offset)&7) /* BAR index register */ +#define MSIX_OFFSET_ADDR(offset) ((offset)&0xfffffff8) /* offset */ + +/* this structure describes one MSI-X vector from N */ +typedef struct _PCI_MSIX_VECTOR { + + ULONGLONG Addr; + ULONG Data; + ULONG Flags; + +} PCI_MSIX_VECTOR, *PPCI_MSIX_VECTOR; + +#define MSIX_VECTOR_MASKED(flags) ((flags)&1) /* this vector is masked */ + +/* this structure pending state of 64 MSI-X vectors from N */ +typedef struct _PCI_MSIX_PENDING { + + ULONGLONG Mask; + +} PCI_MSIX_PENDING, *PPCI_MSIX_PENDING; + +/* + * Vital Product Data Capability + */ +typedef struct _PCI_VPD_CAPABILITY { + + PCI_CAPABILITIES_HEADER Header; + + USHORT Flags; + ULONG Data; + +} PCI_VPD_CAPABILITY, *PPCI_VPD_CAPABILITY; + + +/* + * PCI-X Capability + */ +typedef struct _PCI_PCIX_CAPABILITY { + + PCI_CAPABILITIES_HEADER Header; + + USHORT Command; + ULONG Status; + +/* for Command: */ +} PCI_PCIX_CAPABILITY, *PPCI_PCIX_CAPABILITY; + +#define PCI_X_CMD_MAX_READ 0x000c /* Max Memory Read Byte Count */ + +/* + * PCI-Express Capability + */ +typedef struct _PCI_PCIEXP_CAPABILITY { + + PCI_CAPABILITIES_HEADER Header; + + USHORT Flags; + ULONG DevCapabilities; + USHORT DevControl; + USHORT DevStatus; + ULONG LinkCapabilities; + USHORT LinkControl; + USHORT LinkStatus; + ULONG SlotCapabilities; + USHORT SlotControl; + USHORT SlotStatus; + USHORT RootControl; + USHORT RootCapabilities; + USHORT RootStatus; +} PCI_PCIEXP_CAPABILITY, *PPCI_PCIEXP_CAPABILITY; + +/* for DevControl: */ +#define PCI_EXP_DEVCTL_READRQ 0x7000 /* Max_Read_Request_Size */ + +static NTSTATUS +__get_bus_ifc( + IN DEVICE_OBJECT* const pDevObj, + IN const GUID* const pGuid, + OUT BUS_INTERFACE_STANDARD *pBusIfc ); + +static NTSTATUS +__restore_pci_config( + IN BUS_INTERFACE_STANDARD *pBusIfc, + IN PCI_COMMON_CONFIG* const pConfig ); + + +/* + * Returns the offset in configuration space of the PCI-X capabilites. + */ +static ULONG +__find_capability( + IN PCI_COMMON_CONFIG* const pConfig, + IN char cap_id + ) +{ + ULONG offset = 0; + PCI_CAPABILITIES_HEADER *pHdr = NULL; + UCHAR *pBuf = (UCHAR*)pConfig; + + MLX4_ENTER( MLX4_DBG_PNP ); + + if ( pConfig->HeaderType == PCI_DEVICE_TYPE ) { + if( pConfig->u.type0.CapabilitiesPtr ) + { + pHdr = (PCI_CAPABILITIES_HEADER*) + (pBuf + pConfig->u.type0.CapabilitiesPtr); + } + } + + if ( pConfig->HeaderType == PCI_BRIDGE_TYPE ) { + if( pConfig->u.type1.CapabilitiesPtr ) + { + pHdr = (PCI_CAPABILITIES_HEADER*) + (pBuf + pConfig->u.type1.CapabilitiesPtr); + } + } + + /* + * Fix up any fields that might cause changes to the + * device - like writing VPD data. + */ + while( pHdr ) + { + if( pHdr->CapabilityID == cap_id ) + { + offset = (UCHAR)(((ULONG_PTR)pHdr) - ((ULONG_PTR)pConfig)); + break; + } + + if( pHdr->Next ) + pHdr = (PCI_CAPABILITIES_HEADER*)(pBuf + pHdr->Next); + else + pHdr = NULL; + } + + MLX4_EXIT( MLX4_DBG_PNP ); + return offset; +} + + +static NTSTATUS +__pci_restore_msix_info( + IN struct pci_dev *pdev, + struct msix_saved_info * p_info + ) +{ + int i; + int offset; + NTSTATUS status = STATUS_SUCCESS; + PCI_MSIX_CAPABILITY *pPciMsix; + PPCI_MSIX_VECTOR p_cvector, p_svector; + PBUS_INTERFACE_STANDARD p_ifc = &pdev->bus_pci_ifc; + PCI_COMMON_CONFIG* p_cfg = &pdev->pci_cfg_space; + + if ( p_info->valid ) { + + /* restore PBA Table */ + p_info->valid = 0; + memcpy( p_info->mca, p_info->msa, p_info->msz ); + kfree( p_info->msa ); + MmUnmapIoSpace( p_info->mca, p_info->msz ); + + /* restore Vector Table */ + p_svector = p_info->vsa; + p_cvector = p_info->vca; + for (i=0; inum; i++) + p_cvector[i].Flags = p_svector[i].Flags; + kfree( p_info->vsa ); + MmUnmapIoSpace( p_info->vca, p_info->vsz ); + + /* restore MSI-X Capability */ + offset = __find_capability( p_cfg, PCI_CAPABILITY_ID_MSIX ); + pPciMsix = (PCI_MSIX_CAPABILITY*)(((UCHAR*)p_cfg) + offset); + if (offset) { + /* restore MSI-X control register */ + if ( sizeof( pPciMsix->Flags) != p_ifc->SetBusData( + p_ifc->Context, PCI_WHICHSPACE_CONFIG, + &pPciMsix->Flags, offset + + offsetof( PCI_MSIX_CAPABILITY, Flags), + sizeof( pPciMsix->Flags ) )) { + MLX4_PRINT( TRACE_LEVEL_ERROR, MLX4_DBG_PNP, + ("Couldn't restore MSI-X Control register, aborting.\n")); + status = STATUS_UNSUCCESSFUL; + goto end; + } + } + } +end: + return status; +} + +/* + * Restore saved PCI configuration, skipping registers 22 and 23, as well + * as any registers where writing will have side effects such as the flags + * field of the VPD and vendor specific capabilities. The function also delays + * writing the command register, bridge control register (if applicable), and + * PCIX command register (if present). + */ +static NTSTATUS +__restore_pci_config( + IN BUS_INTERFACE_STANDARD *pBusIfc, + IN PCI_COMMON_CONFIG* const pConfig ) +{ + NTSTATUS status = STATUS_SUCCESS; + int i, *pci_hdr = (int*)pConfig; + + MLX4_ENTER( MLX4_DBG_PNP ); + + /* restore capabilities*/ + { + int offset; + PCI_PCIEXP_CAPABILITY *pPciExpCap; + + /* PCI-X */ + offset = __find_capability( pConfig, PCI_CAPABILITY_ID_PCIX ); + if (offset) { + if ( 4 != pBusIfc->SetBusData( pBusIfc->Context, PCI_WHICHSPACE_CONFIG, + &pci_hdr[offset/4], offset, 4) ) { + MLX4_PRINT( TRACE_LEVEL_ERROR, MLX4_DBG_PNP, + ("Couldn't restore HCA PCI-X command register, aborting.\n")); + status = STATUS_UNSUCCESSFUL; + goto out; + } + } + + /* PCI-Express */ + offset = __find_capability( pConfig, PCI_CAPABILITY_ID_PCI_EXPRESS ); + pPciExpCap = (PCI_PCIEXP_CAPABILITY*)(((UCHAR*)pConfig) + offset); + if (offset) { + /* restore HCA PCI Express Device Control register */ + if ( sizeof( pPciExpCap->DevControl ) != pBusIfc->SetBusData( + pBusIfc->Context, PCI_WHICHSPACE_CONFIG, + &pPciExpCap->DevControl, offset + + offsetof( PCI_PCIEXP_CAPABILITY, DevControl), + sizeof( pPciExpCap->DevControl ) )) { + MLX4_PRINT( TRACE_LEVEL_ERROR, MLX4_DBG_PNP, + ("Couldn't restore HCA PCI Express Device Control register, aborting.\n")); + status = STATUS_UNSUCCESSFUL; + goto out; + } + /* restore HCA PCI Express Link Control register */ + if ( sizeof( pPciExpCap->LinkControl ) != pBusIfc->SetBusData( + pBusIfc->Context, PCI_WHICHSPACE_CONFIG, + &pPciExpCap->LinkControl, offset + + offsetof( PCI_PCIEXP_CAPABILITY, LinkControl), + sizeof( pPciExpCap->LinkControl ) )) { + MLX4_PRINT( TRACE_LEVEL_ERROR, MLX4_DBG_PNP, + ("Couldn't restore HCA PCI Express Link Control register, aborting.\n")); + status = STATUS_UNSUCCESSFUL; + goto out; + } + } + } + + /* write basic part */ + for (i = 0; i < 16; ++i) { + if (i == 1) + continue; + + if (4 != pBusIfc->SetBusData( pBusIfc->Context, + PCI_WHICHSPACE_CONFIG, &pci_hdr[i], i * 4, 4 )) { + MLX4_PRINT( TRACE_LEVEL_ERROR ,MLX4_DBG_PNP , + ("Couldn't restore PCI cfg reg %x, aborting.\n", i)); + status = STATUS_DEVICE_NOT_READY; + goto out; + } + } + + /* Write the command register. */ + if (4 != pBusIfc->SetBusData( pBusIfc->Context, + PCI_WHICHSPACE_CONFIG, &pci_hdr[1], 4, 4 )) { + MLX4_PRINT( TRACE_LEVEL_ERROR ,MLX4_DBG_PNP ,("Couldn't restore COMMAND.\n")); + status = STATUS_DEVICE_NOT_READY; + } + +out: + MLX4_EXIT( MLX4_DBG_PNP ); + return status; +} + + +static int +__save_msix_info( + IN PCI_COMMON_CONFIG * p_cfg, + OUT struct msix_saved_info *p_info ) +{ + u64 bar; + int n_supported; + PHYSICAL_ADDRESS pa; + ULONG cap_offset, bir; + PPCI_MSIX_CAPABILITY pPciMsixCap; + + MLX4_ENTER( MLX4_DBG_PNP ); + + /* find capability */ + cap_offset = __find_capability( p_cfg, PCI_CAPABILITY_ID_MSIX ); + if( !cap_offset ) { + p_info->valid = 0; + return 0; + } + pPciMsixCap = (PPCI_MSIX_CAPABILITY)(((UCHAR*)p_cfg) + cap_offset); + n_supported = MSIX_FLAGS_SUPPORTED(pPciMsixCap->Flags) + 1; + p_info->num = n_supported; + + /* map memory for vectors */ + p_info->vsz =(ULONG)(n_supported * sizeof(PCI_MSIX_VECTOR)); + bir = MSIX_OFFSET_BIR(pPciMsixCap->Table_Offset); + bar = *(u64*)&p_cfg->u.type1.BaseAddresses[bir] & ~0x0f; + pa.QuadPart = bar + MSIX_OFFSET_ADDR(pPciMsixCap->Table_Offset); + p_info->vca = MmMapIoSpace( pa, p_info->vsz, MmNonCached ); + if ( p_info->vca == NULL) { + MLX4_PRINT(TRACE_LEVEL_ERROR , MLX4_DBG_PNP, + ("Failed kernel mapping of MSI-X vector table.\n") ); + goto end; + } + + /* alloc memory for vector table */ + p_info->vsa = kmalloc(p_info->vsz, GFP_KERNEL); + if ( !p_info->vsa ) { + MLX4_PRINT(TRACE_LEVEL_ERROR , MLX4_DBG_PNP, + ("Failed allocate memory for MSI-X vector table \n") ); + goto err_alloc_vectors; + } + memcpy( p_info->vsa, p_info->vca, p_info->vsz ); + + /* map memory for mask table */ + bir = MSIX_OFFSET_BIR(pPciMsixCap->PBA_Offset); + bar = *(u64*)&p_cfg->u.type1.BaseAddresses[bir] & ~0x0f; + p_info->msz =(ULONG)(n_supported * sizeof(PCI_MSIX_PENDING) / 64); + pa.QuadPart = bar + MSIX_OFFSET_ADDR(pPciMsixCap->PBA_Offset); + p_info->mca = MmMapIoSpace( pa, p_info->msz, MmNonCached ); + if ( p_info->mca == NULL) { + MLX4_PRINT(TRACE_LEVEL_ERROR , MLX4_DBG_PNP, + ("Failed kernel mapping of MSI-X mask table.\n") ); + goto err_map_masks; + } + + /* alloc memory for mask table */ + p_info->msa = kmalloc(p_info->msz, GFP_KERNEL); + if ( !p_info->msa ) { + MLX4_PRINT(TRACE_LEVEL_ERROR , MLX4_DBG_PNP, + ("Failed allocate memory for MSI-X vector table \n") ); + goto err_alloc_masks; + } + memcpy( p_info->msa, p_info->mca, p_info->msz ); + + p_info->valid = 1; + return 0; + +err_alloc_masks: + MmUnmapIoSpace( p_info->mca, p_info->msz ); + p_info->mca = NULL; + +err_map_masks: + kfree(p_info->vsa); + p_info->vsa = NULL; + +err_alloc_vectors: + MmUnmapIoSpace( p_info->vca, p_info->vsz ); + p_info->vca = NULL; + +end: + MLX4_EXIT( MLX4_DBG_PNP ); + return -EFAULT; +} + +void +pci_free_msix_info_resources( + IN struct msix_saved_info * pMsixInfo + ) +{ + if (pMsixInfo->vca && pMsixInfo->vsz) + MmUnmapIoSpace( pMsixInfo->vca, pMsixInfo->vsz ); + + if (pMsixInfo->mca && pMsixInfo->msz) + MmUnmapIoSpace( pMsixInfo->mca, pMsixInfo->msz ); + + if (pMsixInfo->msa) + kfree(pMsixInfo->msa); + + if (pMsixInfo->vsa) + kfree(pMsixInfo->vsa); + + memset(pMsixInfo,0,sizeof(struct msix_saved_info)); +} + +static NTSTATUS __read_vpd_dword( + IN BUS_INTERFACE_STANDARD *pBusIfc, + IN ULONG cap_offset, + IN ULONG offset, + OUT UCHAR *p_data + ) +{ + #define MAX_TRIES 500 + ULONG len, tries=0; + USHORT addr = (USHORT)offset; + + /* write offset inside VPD data */ + len = pBusIfc->SetBusData( pBusIfc->Context, PCI_WHICHSPACE_CONFIG, &addr, cap_offset+2,2 ); + if ( len != 2 ) + goto err_write; + + /* wait for data to be put in the data register for (MAX_TRIES*2) usecs */ + while ( !(addr & 0x8000) && tries++ < MAX_TRIES ) { + len = pBusIfc->GetBusData( pBusIfc->Context, PCI_WHICHSPACE_CONFIG, &addr, cap_offset+2, 2 ); + if ( len != 2 ) + goto err_read; + cond_resched(); + } + + if ( tries >= MAX_TRIES ) + goto err_to; + + /* get the tag value */ + len = pBusIfc->GetBusData( pBusIfc->Context, PCI_WHICHSPACE_CONFIG, p_data, cap_offset+4, 4 ); + if ( len != 4 ) + goto err_read; + + return STATUS_SUCCESS; + +err_write: + MLX4_PRINT( TRACE_LEVEL_ERROR , MLX4_DBG_PNP , + ("Failed to write HCA config. \n" )); + return STATUS_DEVICE_NOT_READY; + +err_read: + MLX4_PRINT( TRACE_LEVEL_ERROR , MLX4_DBG_PNP , + ("Failed to read HCA config. \n" )); + return STATUS_DEVICE_NOT_READY; + +err_to: + MLX4_PRINT( TRACE_LEVEL_ERROR , MLX4_DBG_PNP , + ("FW hasn't provided VPD data in %d usecs \n", + (g_cmd_interval.u.LowPart / (-10)) * MAX_TRIES )); + return STATUS_DEVICE_NOT_READY; +} + + +#define MAX_VPD_SIZE (1 << 16) + +NTSTATUS pci_get_vpd( + IN BUS_INTERFACE_STANDARD *pBusIfc, + IN PCI_COMMON_CONFIG* const pConfig, + OUT UCHAR* *p_vpd, + IN OUT int* p_vpd_size + ) +{ + PCI_VPD_CAPABILITY *pPciVpdCap; + ULONG cap_offset; + NTSTATUS status = STATUS_SUCCESS; + int vpd_size = 0; + UCHAR *vpd = NULL; + + *p_vpd = NULL; + *p_vpd_size = 0; + + cap_offset = __find_capability( pConfig, PCI_CAPABILITY_ID_VPD ); + if( cap_offset ) { + ULONG offset; + pPciVpdCap = (PCI_VPD_CAPABILITY*)(((UCHAR*)pConfig) + cap_offset); + + /* allocate temp buffer */ + vpd = kmalloc( MAX_VPD_SIZE, GFP_KERNEL); + if ( !vpd ) { + MLX4_PRINT( TRACE_LEVEL_ERROR , MLX4_DBG_PNP , + ("Failed to allocate VPD buffer of size %d.\n", MAX_VPD_SIZE)); + return STATUS_UNSUCCESSFUL; + } + + /* read VPD */ + for ( offset = 0; offset < MAX_VPD_SIZE; offset += 0x4 ) { + status = __read_vpd_dword( pBusIfc, cap_offset, + offset, vpd + offset); + if( !NT_SUCCESS( status ) ) { + kfree( vpd ); + return STATUS_UNSUCCESSFUL; + } + } + /* find the size */ + for ( offset = 0; offset < MAX_VPD_SIZE; ) { + ULONG size; + if ( vpd[offset] == 0x78 ) { + vpd_size = offset + 1; + break; + } + if ( vpd[offset] & 0x80 ) { /* Large Resource Type */ + size = *(PUSHORT)(&vpd[offset+1]); + offset += size + 3; + } + else { /* Small Resource Type */ + size = vpd[offset] & 7; + offset += size + 1; + } + } + /* shorten the VPD array */ + if ( offset >= MAX_VPD_SIZE ) { + /* we didn't found VPD end. We'll keep it all */ + *p_vpd = vpd; + *p_vpd_size = MAX_VPD_SIZE; + } + else { + /* allocate VPD */ + if ( vpd_size ) { + *p_vpd = kmalloc( vpd_size, GFP_KERNEL); + if ( !*p_vpd ) { + *p_vpd = vpd; + *p_vpd_size = MAX_VPD_SIZE; + } + else { + memcpy( *p_vpd, vpd, vpd_size ); + *p_vpd_size = vpd_size; + kfree( vpd ); + } + } + else { + MLX4_PRINT( TRACE_LEVEL_ERROR , MLX4_DBG_PNP , + ("VPD starts from end tag.\n")); + kfree( vpd ); + status = STATUS_UNSUCCESSFUL; + } + } + } + else { + MLX4_PRINT( TRACE_LEVEL_ERROR , MLX4_DBG_PNP ,("Failed to find VPD capability.\n")); + status = STATUS_UNSUCCESSFUL; + } + + return status; +} + +/* + * Reads and saves the PCI configuration of the device accessible + * through the provided bus interface. Does not read registers 22 or 23 + * as directed in Tavor PRM 1.0.1, Appendix A. InfiniHost Software Reset. + */ +NTSTATUS +pci_save_config( + IN BUS_INTERFACE_STANDARD *pBusIfc, + OUT PCI_COMMON_CONFIG* const pConfig ) +{ + ULONG len; + UINT32 *pBuf; + + MLX4_ENTER( MLX4_DBG_PNP ); + + pBuf = (UINT32*)pConfig; + + /* + * Read the lower portion of the configuration, up to but excluding + * register 22. + */ + len = pBusIfc->GetBusData( + pBusIfc->Context, PCI_WHICHSPACE_CONFIG, &pBuf[0], 0, 88 ); + if( len != 88 ) + { + MLX4_PRINT( TRACE_LEVEL_ERROR , MLX4_DBG_PNP ,("Failed to read HCA config.\n")); + return STATUS_DEVICE_NOT_READY; + } + + /* Read the upper portion of the configuration, from register 24. */ + len = pBusIfc->GetBusData( + pBusIfc->Context, PCI_WHICHSPACE_CONFIG, &pBuf[24], 96, 160 ); + if( len != 160 ) + { + MLX4_PRINT( TRACE_LEVEL_ERROR ,MLX4_DBG_PNP ,("Failed to read HCA config.\n")); + return STATUS_DEVICE_NOT_READY; + } + + MLX4_EXIT( MLX4_DBG_PNP ); + return STATUS_SUCCESS; +} + + +/* + * Store Card's PCI Config space and print current MSI-X capabilities + */ +void +pci_get_msi_info( + IN struct pci_dev *pdev, + OUT PCI_COMMON_CONFIG * p_cfg, + OUT uplink_info_t * p_uplink_info ) +{ + ULONG cap_offset; + NTSTATUS status; + BUS_INTERFACE_STANDARD *pBusIfc = &pdev->bus_pci_ifc; + + MLX4_ENTER( MLX4_DBG_PNP ); + + status = pci_save_config( pBusIfc, p_cfg ); + if (!NT_SUCCESS(status)) { + MLX4_PRINT(TRACE_LEVEL_ERROR , MLX4_DBG_PNP, + ("Failed to read PCI configuration of the card.\n") ); + goto end; + } + + // PCI MSI-X Capability + memset( &p_uplink_info->x, 0, sizeof(p_uplink_info->x) ); + cap_offset = __find_capability( p_cfg, PCI_CAPABILITY_ID_MSIX ); + if( cap_offset ) { + PVOID ka; + ULONG sz; + PHYSICAL_ADDRESS pa; + PPCI_MSIX_VECTOR p_vector; + PPCI_MSIX_PENDING p_pend; + ULONG granted_mask = 0; + PPCI_MSIX_CAPABILITY pPciMsixCap = (PPCI_MSIX_CAPABILITY)(((UCHAR*)p_cfg) + cap_offset); + USHORT flags = pPciMsixCap->Flags; + ULONG table_bir = MSIX_OFFSET_BIR(pPciMsixCap->Table_Offset); + ULONG pend_bir = MSIX_OFFSET_BIR(pPciMsixCap->PBA_Offset); + u64 table_bar = *(u64*)&p_cfg->u.type1.BaseAddresses[table_bir] & ~0x0f; + u64 pend_bar = *(u64*)&p_cfg->u.type1.BaseAddresses[pend_bir] & ~0x0f; + int i, n_supported = MSIX_FLAGS_SUPPORTED(flags) + 1; + + /* print capabilities structure */ + MLX4_PRINT( TRACE_LEVEL_WARNING ,MLX4_DBG_PNP , + ("MSI-X Capability: Enabled - %d, Function Masked %d, Vectors Supported %d, Addr_Offset(BIR) %#x(%d), Pend_Offset(BIR) %#x(%d)\n", + MSIX_FLAGS_MSIX_ENABLE(flags), + MSIX_FLAGS_MSIX_FUNCTION_MASK(flags), + n_supported, + MSIX_OFFSET_ADDR(pPciMsixCap->Table_Offset), MSIX_OFFSET_BIR(pPciMsixCap->Table_Offset), + MSIX_OFFSET_ADDR(pPciMsixCap->PBA_Offset), MSIX_OFFSET_BIR(pPciMsixCap->PBA_Offset) )); + + /* fill info */ + p_uplink_info->x.valid = 1; + p_uplink_info->x.enabled= MSIX_FLAGS_MSIX_ENABLE(flags); + p_uplink_info->x.masked = MSIX_FLAGS_MSIX_FUNCTION_MASK(flags); + p_uplink_info->x.requested = n_supported; + + if (pdev->n_msi_vectors_alloc) { + + /* map memory */ + sz =(ULONG)(n_supported * sizeof(PCI_MSIX_VECTOR)); + pa.QuadPart = table_bar + MSIX_OFFSET_ADDR(pPciMsixCap->Table_Offset); + ka = MmMapIoSpace( pa, sz, MmNonCached ); + if ( ka == NULL) { + MLX4_PRINT(TRACE_LEVEL_ERROR , MLX4_DBG_PNP, + ("Failed kernel mapping of MSI-X vector table.\n") ); + goto end; + } + + p_vector = ka; + /* print (allocated+2) vectors */ + for (i=0; in_msi_vectors_alloc+2; i++) { + MLX4_PRINT( TRACE_LEVEL_VERBOSE ,MLX4_DBG_PNP , + ("MSI-X Vectors: Id %d, Masked %d, Addr %#I64x, Data %#x\n", + i, MSIX_VECTOR_MASKED(p_vector[i].Flags), + p_vector[i].Addr, p_vector[i].Data )); + } + + p_uplink_info->x.granted = pdev->n_msi_vectors_alloc; + p_uplink_info->x.granted_mask = granted_mask; + MmUnmapIoSpace( ka, sz ); + + /* map memory */ + sz =(ULONG)(n_supported * sizeof(PCI_MSIX_PENDING) / 64); + pa.QuadPart = pend_bar + MSIX_OFFSET_ADDR(pPciMsixCap->PBA_Offset); + ka = MmMapIoSpace( pa, sz, MmNonCached ); + if ( ka == NULL) { + MLX4_PRINT(TRACE_LEVEL_ERROR , MLX4_DBG_PNP, + ("Failed kernel mapping of MSI-X mask table.\n") ); + goto end; + } + + /* print first pending register (64 vectors) */ + p_pend = ka; + for (i=0; i<1; i++) { + MLX4_PRINT( TRACE_LEVEL_WARNING ,MLX4_DBG_PNP , + ("MSI-X Pending: Id %d, Pend %#I64x\n", i, p_pend[i].Mask )); + } + p_uplink_info->x.pending_mask = *(u32*)&p_pend[0].Mask; + MmUnmapIoSpace( ka, sz ); + } + else { + MLX4_PRINT( TRACE_LEVEL_WARNING ,MLX4_DBG_PNP , + ("MSI-X Vectors: Allocated 0 vectors\n") ); + } + + } + +end: + MLX4_EXIT( MLX4_DBG_PNP ); +} + +NTSTATUS +pci_hca_reset( + IN struct pci_dev *pdev +) +{ + u32 sem; + NTSTATUS status = STATUS_SUCCESS, status1; + PBUS_INTERFACE_STANDARD p_ifc = &pdev->bus_pci_ifc; + PCI_COMMON_CONFIG* p_cfg = &pdev->pci_cfg_space; + struct msix_saved_info msix_info; + ULONG len; + + MLX4_ENTER( MLX4_DBG_PNP ); + + ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); + + /* save Card Config Space including MSI-X capabilities */ + pci_get_msi_info( pdev, p_cfg, &pdev->uplink_info ); + + /* save MSI-X info, if any */ + len = __save_msix_info( p_cfg, &msix_info ); + if (len) { + MLX4_PRINT( TRACE_LEVEL_ERROR ,MLX4_DBG_PNP ,("Failed to save MSI-X config.\n")); + return STATUS_DEVICE_NOT_READY; + } + + /* reset the card */ + MLX4_PRINT( TRACE_LEVEL_WARNING ,MLX4_DBG_PNP , ("\nResetting HCA ... \n\n")); + { + u64 end; + PUCHAR p_reset; + PHYSICAL_ADDRESS pa; + int cnt = 0; + + /* map reset register */ + pa.QuadPart = pdev->bar[HCA_BAR_TYPE_HCR].phys + (uint64_t)MLX4_RESET_BASE; + p_reset = MmMapIoSpace( pa, MLX4_RESET_SIZE, MmNonCached ); + MLX4_PRINT( TRACE_LEVEL_INFORMATION ,MLX4_DBG_PNP , + ("Reset area ia mapped from pa 0x%I64x to va %p, size %#x\n", + pa.QuadPart, p_reset, MLX4_RESET_SIZE)); + if( !p_reset ) { + MLX4_PRINT( TRACE_LEVEL_ERROR ,MLX4_DBG_PNP ,("Failed to map reset register with address 0x%I64x\n", pa.QuadPart)); + status = STATUS_UNSUCCESSFUL; + goto err; + } + + /* grab HW semaphore to lock out flash updates f0014 - dev_id 00a00190 */ + end = jiffies + MLX4_SEM_TIMEOUT_JIFFIES; + MLX4_PRINT( TRACE_LEVEL_INFORMATION ,MLX4_DBG_PNP , + ("Obtaining HW semaphore at %p till %I64d\n", p_reset + MLX4_SEM_OFFSET, end)); + do { + sem = READ_REGISTER_ULONG((void*)(p_reset + MLX4_SEM_OFFSET)); + if (!sem) + break; + + cl_thread_suspend(1); + } while (time_before(jiffies, end) || ++cnt < 100); + + if (sem) { + MLX4_PRINT( TRACE_LEVEL_INFORMATION ,MLX4_DBG_PNP , + ("Failed to obtain HW semaphore in %d attemps till %I64d, aborting\n", + cnt, jiffies)); + status = STATUS_UNSUCCESSFUL; + MmUnmapIoSpace( p_reset, MLX4_RESET_SIZE ); + goto err; + } + + + /* Issue the reset. */ + MLX4_PRINT( TRACE_LEVEL_INFORMATION ,MLX4_DBG_PNP , + ("Resetting the chip at %p with %#x...\n", p_reset + MLX4_RESET_OFFSET, MLX4_RESET_VALUE)); + WRITE_REGISTER_ULONG( (void*)(p_reset + MLX4_RESET_OFFSET), MLX4_RESET_VALUE ); + + /* unmap the reset register */ + MLX4_PRINT( TRACE_LEVEL_INFORMATION ,MLX4_DBG_PNP ,("Unmapping reset register \n")); + MmUnmapIoSpace( p_reset, MLX4_RESET_SIZE ); + + /* Wait a second. */ + cl_thread_suspend( 100 ); + } + + /* Read the configuration register until it doesn't return 0xFFFFFFFF */ + { + ULONG data, i, reset_failed = 1; + MLX4_PRINT( TRACE_LEVEL_INFORMATION ,MLX4_DBG_PNP ,("Read the configuration register \n")); + for( i = 0; i < 500; i++ ) { + if (4 != p_ifc->GetBusData( p_ifc->Context, + PCI_WHICHSPACE_CONFIG, &data, 0, 4)) { + MLX4_PRINT( TRACE_LEVEL_ERROR, MLX4_DBG_PNP, + ("Failed to read device configuration data. Card reset failed !\n")); + status = STATUS_UNSUCCESSFUL; + break; + } + /* See if we got valid data. */ + if( data != 0xFFFFFFFF ) { + reset_failed = 0; + break; + } + + cl_thread_suspend( 10 ); + } + + if (reset_failed) { + MLX4_PRINT( TRACE_LEVEL_ERROR, MLX4_DBG_PNP, + ("Doh! PCI device did not come back after reset!\n")); + status = STATUS_UNSUCCESSFUL; + goto err; + } + } + + /* restore the HCA's PCI configuration headers */ + { + /* Restore the HCA's configuration. */ + MLX4_PRINT( TRACE_LEVEL_INFORMATION ,MLX4_DBG_PNP ,("Restoring HCA PCI configuration \n")); + status = __restore_pci_config( p_ifc, p_cfg ); + if( !NT_SUCCESS( status ) ) { + MLX4_PRINT( TRACE_LEVEL_ERROR, MLX4_DBG_PNP, + ("Failed to restore HCA config. Card reset failed !\n")); + goto err; + } + } + + status = STATUS_SUCCESS; + +err: + /* restore MSI-X info after reset */ + status1 = __pci_restore_msix_info( pdev, &msix_info ); + status = (!status) ? status1 : status; /* return the only or the first error */ + if( NT_SUCCESS( status ) ) { + MLX4_PRINT( TRACE_LEVEL_WARNING ,MLX4_DBG_PNP , ("HCA has been reset ! \n")); + } + + /* check, whether MSI-X capabilities have been restored */ + pci_get_msi_info( pdev, p_cfg, &pdev->uplink_info ); + + if (pdev->msix_info.valid) + pci_free_msix_info_resources(&pdev->msix_info); + MLX4_EXIT( MLX4_DBG_PNP ); + ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); + return status; +} + + +/* + * Tunes PCI configuration as described in 13.3.2 in the Tavor PRM. + */ +void +pci_get_uplink_info( + IN PCI_COMMON_CONFIG * p_cfg, + OUT uplink_info_t * p_uplink_info ) +{ + ULONG cap_offset; + PCI_PCIX_CAPABILITY *pPciXCap; + PCI_PCIEXP_CAPABILITY *pPciExpCap; + + MLX4_ENTER( MLX4_DBG_PNP ); + + // PCIX Capability + cap_offset = __find_capability( p_cfg, PCI_CAPABILITY_ID_PCIX ); + if( cap_offset ) { + pPciXCap = (PCI_PCIX_CAPABILITY*)(((UCHAR*)p_cfg) + cap_offset); + + p_uplink_info->bus_type = UPLINK_BUS_PCIX; + if (pPciXCap->Status & (1 << 17)) + p_uplink_info->u.pci_x.capabilities = UPLINK_BUS_PCIX_133; + + } + + // PCI Express Capability + cap_offset = __find_capability( p_cfg, PCI_CAPABILITY_ID_PCI_EXPRESS ); + if( cap_offset ) { + pPciExpCap = (PCI_PCIEXP_CAPABILITY*)(((UCHAR*)p_cfg) + cap_offset); + + p_uplink_info->bus_type = UPLINK_BUS_PCIE; + if ((pPciExpCap->LinkStatus & 15) == 1) + p_uplink_info->u.pci_e.link_speed = UPLINK_BUS_PCIE_SDR; + if ((pPciExpCap->LinkStatus & 15) == 2) + p_uplink_info->u.pci_e.link_speed = UPLINK_BUS_PCIE_DDR; + p_uplink_info->u.pci_e.link_width = (uint8_t)((pPciExpCap->LinkStatus >> 4) & 0x03f); + p_uplink_info->u.pci_e.capabilities = (uint8_t)((pPciExpCap->LinkCapabilities >> 2) & 0xfc); + p_uplink_info->u.pci_e.capabilities |= pPciExpCap->LinkCapabilities & 3; + } + + MLX4_EXIT( MLX4_DBG_PNP ); +} + + +NTSTATUS +pci_hca_enable( + IN PBUS_INTERFACE_STANDARD p_ifc, + IN PCI_COMMON_CONFIG* p_cfg + ) +{ + NTSTATUS status = STATUS_SUCCESS; + ULONG len; + + MLX4_ENTER( MLX4_DBG_PNP ); + + /* fix command register (set PCI Master bit) */ + // NOTE: we change here the saved value of the command register + if ( (p_cfg->Command & 7) != 7 ) { + p_cfg->Command |= 7; + len = p_ifc->SetBusData( p_ifc->Context, PCI_WHICHSPACE_CONFIG, + (PVOID)&p_cfg->Command , 4, sizeof(ULONG) ); + if( len != sizeof(ULONG) ) { + MLX4_PRINT( TRACE_LEVEL_ERROR ,MLX4_DBG_PNP ,("Failed to write command register.\n")); + status = STATUS_DEVICE_NOT_READY; + } + } + + MLX4_EXIT( MLX4_DBG_PNP ); + return status; +} + + diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/drv/pdo.c b/branches/WOF2-3/hw/mlx4/kernel/bus/drv/pdo.c new file mode 100644 index 00000000..61c2da49 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/drv/pdo.c @@ -0,0 +1,332 @@ +#include "precomp.h" +#include +#include + +#if defined (EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "pdo.tmh" +#endif + +#define MAX_ID_LEN 80 + +NTSTATUS +EvtDeviceProcessQueryInterfaceRequest( + IN WDFDEVICE Device, + IN LPGUID InterfaceType, + IN OUT PINTERFACE ExposedInterface, + IN OUT PVOID ExposedInterfaceSpecificData + ) +{ + PPDO_DEVICE_DATA p_pdo = PdoGetData(Device); + PFDO_DEVICE_DATA p_fdo = p_pdo->p_fdo; + PMLX4_BUS_IB_INTERFACE p_ib_ifc = (PMLX4_BUS_IB_INTERFACE)ExposedInterface; + + UNUSED_PARAM(InterfaceType); + UNUSED_PARAM(ExposedInterfaceSpecificData); + + if (p_fdo->pci_dev.dev) { + p_ib_ifc->p_ibdev = p_fdo->bus_ib_ifc.p_ibdev; + p_ib_ifc->pmlx4_dev = p_fdo->bus_ib_ifc.pmlx4_dev; + p_ib_ifc->is_livefish = p_fdo->bus_ib_ifc.is_livefish; + return STATUS_SUCCESS; + } + else { + p_ib_ifc->p_ibdev = NULL; + p_ib_ifc->pmlx4_dev = NULL; + p_ib_ifc->is_livefish = FALSE; + return STATUS_UNSUCCESSFUL; + } + +} + +NTSTATUS +create_pdo( + __in WDFDEVICE Device, + __in PWCHAR HardwareIds, + __in PWCHAR DeviceDescription, + __in ULONG SerialNo, + __in PWCHAR Location +) +/*++ + +Routine Description: + + This routine creates and initialize a PDO. + +Arguments: + +Return Value: + + NT Status code. + +--*/ +{ + NTSTATUS status; + PWDFDEVICE_INIT pDeviceInit = NULL; + PPDO_DEVICE_DATA p_pdo = NULL; + PFDO_DEVICE_DATA p_fdo; + WDFDEVICE hChild = NULL; + WDF_OBJECT_ATTRIBUTES pdoAttributes; + WDF_DEVICE_PNP_CAPABILITIES pnpCaps; + WDF_DEVICE_POWER_CAPABILITIES powerCaps; + UNICODE_STRING compatId; + UNICODE_STRING deviceId; + DECLARE_UNICODE_STRING_SIZE(buffer, MAX_ID_LEN); + DECLARE_UNICODE_STRING_SIZE(deviceLocation, MAX_ID_LEN); + + MLX4_PRINT(TRACE_LEVEL_INFORMATION, MLX4_DBG_DRV, ("Entered CreatePdo\n")); + + RtlInitUnicodeString(&compatId, HardwareIds); + PAGED_CODE(); + + // + // Allocate a WDFDEVICE_INIT structure and set the properties + // so that we can create a device object for the child. + // + pDeviceInit = WdfPdoInitAllocate(Device); + + if (pDeviceInit == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto Cleanup; + } + + // + // Set DeviceType + // + WdfDeviceInitSetDeviceType(pDeviceInit, FILE_DEVICE_BUS_EXTENDER); + + // + // Provide DeviceID, HardwareIDs, CompatibleIDs and InstanceId + // + RtlInitUnicodeString(&deviceId,HardwareIds); + + status = WdfPdoInitAssignDeviceID(pDeviceInit, &deviceId); + if (!NT_SUCCESS(status)) { + goto Cleanup; + } + + // + // Note same string is used to initialize hardware id too + // + status = WdfPdoInitAddHardwareID(pDeviceInit, &deviceId); + if (!NT_SUCCESS(status)) { + goto Cleanup; + } + + status = WdfPdoInitAddCompatibleID(pDeviceInit, &compatId); + if (!NT_SUCCESS(status)) { + goto Cleanup; + } + + status = RtlUnicodeStringPrintf(&buffer, L"%02d", SerialNo); + if (!NT_SUCCESS(status)) { + goto Cleanup; + } + + status = WdfPdoInitAssignInstanceID(pDeviceInit, &buffer); + if (!NT_SUCCESS(status)) { + goto Cleanup; + } + + // + // Provide a description about the device. This text is usually read from + // the device. In the case of USB device, this text comes from the string + // descriptor. This text is displayed momentarily by the PnP manager while + // it's looking for a matching INF. If it finds one, it uses the Device + // Description from the INF file or the friendly name created by + // coinstallers to display in the device manager. FriendlyName takes + // precedence over the DeviceDesc from the INF file. + // + status = RtlUnicodeStringPrintf(&buffer,DeviceDescription , SerialNo ); + + if (!NT_SUCCESS(status)) { + goto Cleanup; + } + + // + // You can call WdfPdoInitAddDeviceText multiple times, adding device + // text for multiple locales. When the system displays the text, it + // chooses the text that matches the current locale, if available. + // Otherwise it will use the string for the default locale. + // The driver can specify the driver's default locale by calling + // WdfPdoInitSetDefaultLocale. + // + status = RtlUnicodeStringPrintf(&deviceLocation, L"MLX4 %s", Location+4); + if (!NT_SUCCESS(status)) { + goto Cleanup; + } + + status = WdfPdoInitAddDeviceText(pDeviceInit, + &buffer, &deviceLocation, 0x409); + if (!NT_SUCCESS(status)) { + goto Cleanup; + } + + WdfPdoInitSetDefaultLocale(pDeviceInit, 0x409); + + // + // Initialize the attributes to specify the size of PDO device extension. + // All the state information private to the PDO will be tracked here. + // + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&pdoAttributes, PDO_DEVICE_DATA); + + status = WdfDeviceCreate(&pDeviceInit, &pdoAttributes, &hChild); + if (!NT_SUCCESS(status)) { + goto Cleanup; + } + + // + // Once the device is created successfully, framework frees the + // DeviceInit memory and sets the pDeviceInit to NULL. So don't + // call any WdfDeviceInit functions after that. + // + // Get the device context. + // + p_pdo = PdoGetData(hChild); + p_fdo = FdoGetData(Device); + + p_pdo->p_fdo = p_fdo; + p_pdo->SerialNo = SerialNo; + p_pdo->PdoDevice = hChild; + + // + // Set PnP properties for the child device. + // + WDF_DEVICE_PNP_CAPABILITIES_INIT(&pnpCaps); + pnpCaps.Address = SerialNo; + pnpCaps.UINumber = SerialNo; + + WdfDeviceSetPnpCapabilities(hChild, &pnpCaps); + + // + // Set Power properties for the child device + // + WDF_DEVICE_POWER_CAPABILITIES_INIT(&powerCaps); + + powerCaps.DeviceD1 = WdfTrue; + powerCaps.WakeFromD1 = WdfTrue; + powerCaps.DeviceWake = PowerDeviceD1; + + powerCaps.DeviceState[PowerSystemWorking] = PowerDeviceD0; + powerCaps.DeviceState[PowerSystemSleeping1] = PowerDeviceD1; + powerCaps.DeviceState[PowerSystemSleeping2] = PowerDeviceD3; + powerCaps.DeviceState[PowerSystemSleeping3] = PowerDeviceD3; + powerCaps.DeviceState[PowerSystemHibernate] = PowerDeviceD3; + powerCaps.DeviceState[PowerSystemShutdown] = PowerDeviceD3; + + WdfDeviceSetPowerCapabilities(hChild, &powerCaps); + + // + // Set bus IB interface + // + p_fdo->bus_ib_ifc.port_id = (u8) SerialNo; + p_fdo->bus_ib_ifc.pVipBusIfc = &p_fdo->mtnic_Ifc; + p_fdo->bus_ib_ifc.mlx4_interface.mlx4_pd_alloc = mlx4_pd_alloc; + p_fdo->bus_ib_ifc.mlx4_interface.mlx4_pd_free = mlx4_pd_free; + p_fdo->bus_ib_ifc.mlx4_interface.mlx4_uar_alloc = mlx4_uar_alloc; + p_fdo->bus_ib_ifc.mlx4_interface.mlx4_uar_free = mlx4_uar_free; + p_fdo->bus_ib_ifc.mlx4_interface.mlx4_mr_alloc = mlx4_mr_alloc; + p_fdo->bus_ib_ifc.mlx4_interface.mlx4_mr_free = mlx4_mr_free; + p_fdo->bus_ib_ifc.mlx4_interface.mlx4_mr_enable = mlx4_mr_enable; + p_fdo->bus_ib_ifc.mlx4_interface.mlx4_qp_get_region = mlx4_qp_get_region; + p_fdo->bus_ib_ifc.mlx4_interface.mlx4_alloc_hwq_res = mlx4_alloc_hwq_res; + p_fdo->bus_ib_ifc.mlx4_interface.mlx4_free_hwq_res = mlx4_free_hwq_res; + + p_fdo->bus_ib_ifc.mlx4_interface.mlx4_cq_alloc = mlx4_cq_alloc; + p_fdo->bus_ib_ifc.mlx4_interface.mlx4_cq_free = mlx4_cq_free; + p_fdo->bus_ib_ifc.mlx4_interface.mlx4_cq_modify = mlx4_cq_modify; + + p_fdo->bus_ib_ifc.mlx4_interface.mlx4_register_mac = mlx4_register_mac; + p_fdo->bus_ib_ifc.mlx4_interface.mlx4_unregister_mac = mlx4_unregister_mac; + + p_fdo->bus_ib_ifc.mlx4_interface.mlx4_srq_alloc = mlx4_srq_alloc; + p_fdo->bus_ib_ifc.mlx4_interface.mlx4_srq_free = mlx4_srq_free; + p_fdo->bus_ib_ifc.mlx4_interface.mlx4_srq_invalidate = mlx4_srq_invalidate; + p_fdo->bus_ib_ifc.mlx4_interface.mlx4_srq_remove = mlx4_srq_remove; + + p_fdo->bus_ib_ifc.mlx4_interface.mlx4_qp_alloc = mlx4_qp_alloc; + p_fdo->bus_ib_ifc.mlx4_interface.mlx4_qp_free = mlx4_qp_free; + p_fdo->bus_ib_ifc.mlx4_interface.mlx4_qp_remove = mlx4_qp_remove; + p_fdo->bus_ib_ifc.mlx4_interface.mlx4_qp_modify = mlx4_qp_modify; + p_fdo->bus_ib_ifc.mlx4_interface.mlx4_qp_to_ready = mlx4_qp_to_ready; + p_fdo->bus_ib_ifc.mlx4_interface.mlx4_qp_reserve_range = mlx4_qp_reserve_range; + p_fdo->bus_ib_ifc.mlx4_interface.mlx4_qp_release_range = mlx4_qp_release_range; + + p_fdo->bus_ib_ifc.mlx4_interface.mlx4_alloc_cmd_mailbox = mlx4_alloc_cmd_mailbox; + p_fdo->bus_ib_ifc.mlx4_interface.mlx4_free_cmd_mailbox = mlx4_free_cmd_mailbox; + p_fdo->bus_ib_ifc.mlx4_interface.mlx4_cmd = imlx4_cmd; + + p_fdo->bus_ib_ifc.mlx4_interface.mlx4_INIT_PORT = mlx4_INIT_PORT; + p_fdo->bus_ib_ifc.mlx4_interface.mlx4_CLOSE_PORT = mlx4_CLOSE_PORT; + p_fdo->bus_ib_ifc.mlx4_interface.mlx4_add_eq = mlx4_add_eq; + p_fdo->bus_ib_ifc.mlx4_interface.mlx4_remove_eq = mlx4_remove_eq; + p_fdo->bus_ib_ifc.mlx4_interface.mlx4_register_ev_cb = mlx4_reset_cb_register; + p_fdo->bus_ib_ifc.mlx4_interface.mlx4_unregister_ev_cb = mlx4_reset_cb_unregister; + p_fdo->bus_ib_ifc.mlx4_interface.mlx4_reset_request = mlx4_reset_request; + p_fdo->bus_ib_ifc.mlx4_interface.mlx4_reset_execute = mlx4_reset_execute; + p_fdo->bus_ib_ifc.mlx4_interface.mlx4_reset_ready = mlx4_reset_ready; + p_fdo->bus_ib_ifc.mlx4_interface.mlx4_register_vlan = mlx4_register_vlan; + p_fdo->bus_ib_ifc.mlx4_interface.mlx4_unregister_vlan = mlx4_unregister_vlan; + + // + // Create a custom interface so that other drivers can + // query (IRP_MN_QUERY_INTERFACE) and use our callbacks directly. + // + p_fdo->bus_ib_ifc.i.Context = p_pdo; + + WDF_QUERY_INTERFACE_CONFIG_INIT( &p_pdo->qiMlx4Bus, + (PINTERFACE) &p_fdo->bus_ib_ifc, + &MLX4_BUS_IB_INTERFACE_GUID, EvtDeviceProcessQueryInterfaceRequest); + + status = WdfDeviceAddQueryInterface( hChild, &p_pdo->qiMlx4Bus ); + if (!NT_SUCCESS(status)) + goto Cleanup; + + // + // Expose also PCI.SYS interface for MLX4_HCA + // + WDF_QUERY_INTERFACE_CONFIG_INIT( &p_pdo->qiPciBus, + (PINTERFACE) &p_fdo->pci_dev.bus_pci_ifc, + &GUID_BUS_INTERFACE_STANDARD, NULL); + + // TODO: Soft Reset - how tobar getting interface during RESET_IN_PROGRESS + // maybe - using EvtDeviceProcessQueryInterfaceRequest + status = WdfDeviceAddQueryInterface( hChild, &p_pdo->qiPciBus ); + if (!NT_SUCCESS(status)) + goto Cleanup; + + // + // Add this device to the FDO's collection of children. + // After the child device is added to the static collection successfully, + // driver must call WdfPdoMarkMissing to get the device deleted. It + // shouldn't delete the child device directly by calling WdfObjectDelete. + // + status = WdfFdoAddStaticChild(Device, hChild); + if (!NT_SUCCESS(status)) { + goto Cleanup; + } + + return status; + +Cleanup: + KdPrint(("BusEnum: Bus_CreatePdo failed %x\n", status)); + + // + // Call WdfDeviceInitFree if you encounter an error before the + // device is created. Once the device is created, framework + // NULLs the pDeviceInit value. + // + if (pDeviceInit != NULL) { + WdfDeviceInitFree(pDeviceInit); + } + + if(hChild) { + WdfObjectDelete(hChild); + } + + return status; +} + + diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/drv/precomp.h b/branches/WOF2-3/hw/mlx4/kernel/bus/drv/precomp.h new file mode 100644 index 00000000..d105332b --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/drv/precomp.h @@ -0,0 +1,16 @@ +#include +#include +#define NTSTRSAFE_LIB +#include +#include // required for GUID definitions +#include "public.h" +#include "l2w.h" +#include "vip_dev.h" +#include "drv.h" +#include "driver.h" +#include "cmd.h" +#include +#include "ib\mlx4_ib.h" +#include "stat.h" + + diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/drv/sources b/branches/WOF2-3/hw/mlx4/kernel/bus/drv/sources new file mode 100644 index 00000000..16c17f20 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/drv/sources @@ -0,0 +1,61 @@ +TARGETNAME=mlx4_bus +TARGETPATH=..\..\..\..\..\bin\kernel\obj$(BUILD_ALT_DIR) +TARGETTYPE=DRIVER + +# WDK build only - transform .inx --> .inf adding date & version stamp. +# see .\makefile.inc +INF_NAME=$(TARGETNAME) +INF_TARGET=..\..\..\..\..\bin\kernel\$(O)\$(INF_NAME).inf +NTTARGETFILES=$(INF_TARGET) + +!if $(FREEBUILD) +ENABLE_EVENT_TRACING=1 +!else +#ENABLE_EVENT_TRACING=1 +!endif + +SOURCES= \ + bus.rc \ + drv.c \ + pci.c \ + pdo.c \ + wmi.c \ + stat.c + +PRECOMPILED_INCLUDE=precomp.h + +NTTARGETFILE0=mofcomp + +KMDF_VERSION_MAJOR=1 + +C_DEFINES=$(C_DEFINES) -DDRIVER -DDEPRECATE_DDK_FUNCTIONS -D__LITTLE_ENDIAN -DUSE_WDM_INTERRUPTS + +INCLUDES=..;..\inc;..\..\inc;..\core;..\..\..\inc;..\..\..\..\..\inc;..\..\..\..\..\inc\kernel;..\core;..\core\$O + + +TARGETLIBS= $(TARGETLIBS) \ + $(DDK_LIB_PATH)\ntstrsafe.lib \ + $(TARGETPATH)\*\complib.lib \ + $(TARGETPATH)\*\mlx4_core.lib \ + $(TARGETPATH)\*\mlx4_ib.lib \ + $(TARGETPATH)\*\mlx4_net.lib + + + +#LINKER_FLAGS=/MAP + + +!IFDEF ENABLE_EVENT_TRACING + +C_DEFINES = $(C_DEFINES) -DEVENT_TRACING + +RUN_WPP= $(SOURCES) -km -dll -ext: .c .cpp .h .C .CPP .H\ +# -preserveext:.cpp .h\ + -scan:..\..\inc\mlx4_debug.h \ + -func:MLX4_PRINT(LEVEL,FLAGS,(MSG,...)) \ + -func:MLX4_PRINT_EXIT(LEVEL,FLAGS,(MSG,...)) +!ENDIF + +MSC_OPTIMIZATION=/Oi +MSC_WARNING_LEVEL= /W4 + diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/drv/stat.c b/branches/WOF2-3/hw/mlx4/kernel/bus/drv/stat.c new file mode 100644 index 00000000..727bdd23 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/drv/stat.c @@ -0,0 +1,199 @@ +/*++ + +Copyright (c) 2005-2009 Mellanox Technologies. All rights reserved. + +Module Name: + bus_stat.h + +Abstract: + Statistics Collector header file + +Revision History: + +Notes: + +--*/ + +#include "precomp.h" + +MLX4_ST_STAT g_stat; + +static void __print_grh( struct mlx4_dev *mdev, struct ib_unpacked_grh *p) +{ + mlx4_dbg(mdev, "\n\t ========== GRH ==========\n"); + mlx4_dbg(mdev, "\t ip_version %02x", p->ip_version); + mlx4_dbg(mdev, "\t traffic_class %02x", p->traffic_class); + mlx4_dbg(mdev, "\t flow_label %08x", + be32_to_cpu(p->flow_label)); + mlx4_dbg(mdev, "\t payload_length %04x", + be16_to_cpu(p->payload_length)); + mlx4_dbg(mdev, "\t next_header %02x", p->next_header); + mlx4_dbg(mdev, "\t hop_limit %02x", p->hop_limit); + mlx4_dbg(mdev, "\t source_gid %08I64x:%08I64", + be64_to_cpu(p->source_gid.global.subnet_prefix), + be64_to_cpu(p->source_gid.global.interface_id)); + mlx4_dbg(mdev, "\t source_gid %08I64x:%08I64", + be64_to_cpu(p->destination_gid.global.subnet_prefix), + be64_to_cpu(p->destination_gid.global.interface_id)); +} + +static void __print_deth( struct mlx4_dev *mdev, struct ib_unpacked_deth *p) +{ + mlx4_dbg(mdev, "\n\t ========== DETH ==========\n"); + mlx4_dbg(mdev, "\t qkey %08x", + be32_to_cpu(p->qkey)); + mlx4_dbg(mdev, "\t source_qpn %08x", + be32_to_cpu(p->source_qpn)); +} + +static void __print_bth( struct mlx4_dev *mdev, struct ib_unpacked_bth *p) +{ + mlx4_dbg(mdev, "\n\t ========== BTH ==========\n"); + mlx4_dbg(mdev, "\t opcode %02x", p->opcode); + mlx4_dbg(mdev, "\t solicited_event %02x", p->solicited_event); + mlx4_dbg(mdev, "\t mig_req %02x", p->mig_req); + mlx4_dbg(mdev, "\t header_version %02x", p->transport_header_version); + mlx4_dbg(mdev, "\t pkey %04x", + be16_to_cpu(p->pkey)); + mlx4_dbg(mdev, "\t destination_qpn %08x", + be32_to_cpu(p->destination_qpn)); + mlx4_dbg(mdev, "\t ack_req %02x", p->ack_req); + mlx4_dbg(mdev, "\t psn %08x", + be32_to_cpu(p->psn)); +} + +static void __print_lrh( struct mlx4_dev *mdev, struct ib_unpacked_lrh *p) +{ + mlx4_dbg(mdev, "\n\t ========== LRH ==========\n"); + mlx4_dbg(mdev, "\t virtual_lane %02x", p->virtual_lane); + mlx4_dbg(mdev, "\t link_version %02x", p->link_version); + mlx4_dbg(mdev, "\t service_level %02x", p->service_level); + mlx4_dbg(mdev, "\t link_next_header %02x", p->link_next_header); + mlx4_dbg(mdev, "\t destination_lid %04x", + be16_to_cpu(p->destination_lid)); + mlx4_dbg(mdev, "\t packet_length %04x", + be16_to_cpu(p->packet_length)); + mlx4_dbg(mdev, "\t source_lid %04x", + be16_to_cpu(p->source_lid)); +} + +static void __print_ud_header( struct mlx4_dev *mdev, struct ib_ud_header *p) +{ + mlx4_dbg(mdev, "\n\t ========== UD HEADER ==========\n"); + + mlx4_dbg(mdev, "\t grh_present %d, imm_present %d, imm %08x", + p->grh_present, p->immediate_present, be32_to_cpu(p->immediate_data) ); + + if ( mdev->pdev->p_stat_dev->flags & MLX4_MAD_TRACE_LRH ) + __print_lrh( mdev, &p->lrh ); + + if ( mdev->pdev->p_stat_dev->flags & MLX4_MAD_TRACE_BTH ) + __print_bth( mdev, &p->bth ); + + if ( mdev->pdev->p_stat_dev->flags & MLX4_MAD_TRACE_DETH ) + __print_deth( mdev, &p->deth ); + + if ( p->grh_present && (mdev->pdev->p_stat_dev->flags & MLX4_MAD_TRACE_GRH) ) + __print_grh( mdev, &p->grh ); + +} + +static void __print_mlx( struct mlx4_dev *mdev, struct mlx4_wqe_mlx_seg *p) +{ + mlx4_dbg(mdev, "\n\t ========== MLX WQE ==========\n"); + mlx4_dbg(mdev, "\t owner %02x", p->owner); + mlx4_dbg(mdev, "\t opcode %02x", p->opcode); + mlx4_dbg(mdev, "\t size %02x", p->size); + mlx4_dbg(mdev, "\t flags %08x", + be32_to_cpu(p->flags)); + mlx4_dbg(mdev, "\t rlid %04x", + be16_to_cpu(p->rlid)); +} + +void st_print_mlx_header( struct mlx4_dev *mdev, struct mlx4_ib_sqp *sqp, struct mlx4_wqe_mlx_seg *mlx ) +{ + if ( mdev->pdev->p_stat_dev->flags & MLX4_MAD_TRACE_UDH ) + __print_ud_header( mdev, &sqp->hdr.ib ); + if ( mdev->pdev->p_stat_dev->flags & MLX4_MAD_TRACE_WQE ) + __print_mlx( mdev, mlx ); +} + +void st_print_mlx_send(struct mlx4_dev *mdev, struct ib_qp *ibqp, ib_send_wr_t *wr) +{ + struct mlx4_ib_qp *qp = to_mqp(ibqp); + + if ( mdev->pdev->p_stat_dev->flags & MLX4_MAD_TRACE_WR ) { + mlx4_dbg(mdev, "\n\t ========== SEND WR on QP %#x (%#x) ==========\n", + ibqp->qp_num, qp->mqp.qpn ); + mlx4_dbg(mdev, "\t wr_type %d", wr->wr_type); + mlx4_dbg(mdev, "\t wr_id %08I64x", wr->wr_id); + mlx4_dbg(mdev, "\t send_opt %x", wr->send_opt); + mlx4_dbg(mdev, "\t immediate_data %x", be32_to_cpu(wr->immediate_data)); + mlx4_dbg(mdev, "\t num_ds %d", wr->num_ds); + mlx4_dbg(mdev, "\t ds[0].pa %I64x", wr->ds_array[0].vaddr); + mlx4_dbg(mdev, "\t ds[0].length %x", wr->ds_array[0].length); + mlx4_dbg(mdev, "\t ds[0].lkey %x", wr->ds_array[0].lkey); + } +} + +void st_dump_mlx_wqe(struct mlx4_dev *mdev, void *wqe, int size_in_dwords, ib_send_wr_t *wr) +{ + int j; + u32 *ptr = wqe; +#if 0 + int i, size; +#else + UNUSED_PARAM(wr); +#endif + + mlx4_dbg(mdev, "\n\t ========== MLX WQE at %p, size %#x ==========\n", + wqe, size_in_dwords*4 ); + + if ( mdev->pdev->p_stat_dev->flags & MLX4_MAD_TRACE_MLX_WQE_DUMP ) { + for ( j = 0; j < size_in_dwords; ++j ) { + mlx4_warn( mdev, "\t %04x: %08x %08x %08x %08x \n", 16*j, + be32_to_cpu(ptr[4*j]), be32_to_cpu(ptr[4*j + 1]), + be32_to_cpu(ptr[4*j + 2]),be32_to_cpu(ptr[4*j + 3]) ); + } + } + +#if 0 + for ( j = 0; j < (int)wr->num_ds; ++j ) { + mlx4_dbg(mdev, "\n\t ========== SMP %d at pa %I64x, size %#x, lkey %#x ==========\n", + j, wr->ds_array[0].vaddr, wr->ds_array[0].length, wr->ds_array[0].lkey ); + + //TODO: vaddr should be converted to virtual address + ptr = (PVOID)(ULONG_PTR)wr->ds_array[0].vaddr; + size = (wr->ds_array[0].length + 3) >> 2; + for ( i = 0; i < size; ++i ) { + mlx4_warn( mdev, "%04x: %08x %08x %08x %08x \n", 16*i, + be32_to_cpu(ptr[4*i]), be32_to_cpu(ptr[4*i + 1]), + be32_to_cpu(ptr[4*i + 2]),be32_to_cpu(ptr[4*i + 3]) ); + } + } +#endif + +} + + +void st_dev_rmv( PMLX4_ST_DEVICE p_stat ) +{ + if ( p_stat ) + p_stat->valid = FALSE; +} + +PMLX4_ST_DEVICE st_dev_add() +{ + int i; + + for ( i = 0; i < MLX4_ST_MAX_DEVICES; ++i ) { + if ( g_stat.dev[i].valid == FALSE ) { + g_stat.dev[i].valid = TRUE; + return &g_stat.dev[i]; + } + } + + return NULL; +} + + diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/drv/stat.h b/branches/WOF2-3/hw/mlx4/kernel/bus/drv/stat.h new file mode 100644 index 00000000..e0f90df7 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/drv/stat.h @@ -0,0 +1,86 @@ +/*++ + +Copyright (c) 2005-2009 Mellanox Technologies. All rights reserved. + +Module Name: + bus_stat.h + +Abstract: + Statistics Collector header file + +Revision History: + +Notes: + +--*/ + +#include +#include "l2w.h" +#include "ib_pack.h" +#include "qp.h" +#include "device.h" + +// +// restrictions +// + +#define MLX4_ST_MAX_DEVICES 8 + +// +// enums +// + +#define MLX4_MAD_TRACE_LRH (1 << 0) +#define MLX4_MAD_TRACE_BTH (1 << 1) +#define MLX4_MAD_TRACE_DETH (1 << 2) +#define MLX4_MAD_TRACE_GRH (1 << 3) +#define MLX4_MAD_TRACE_WQE (1 << 4) +#define MLX4_MAD_TRACE_UDH (1 << 5) +#define MLX4_MAD_TRACE_WR (1 << 6) +#define MLX4_MAD_TRACE_MLX_WQE_DUMP (1 << 7) + + + +// +// structures +// + +// device + +typedef struct _MLX4_ST_DEVICE +{ + boolean_t valid; + PFDO_DEVICE_DATA p_fdo; + WDFDEVICE h_wdf_device; + ULONG flags; + +} MLX4_ST_DEVICE, *PMLX4_ST_DEVICE; + +// driver +typedef struct _MLX4_ST_DRIVER +{ + GLOBALS *p_globals; + WDFDRIVER h_wdf_driver; + +} MLX4_ST_DRIVER, *PMLX4_ST_DRIVER; + +// driver stack + +typedef struct _MLX4_ST_STAT +{ + MLX4_ST_DRIVER drv; + MLX4_ST_DEVICE dev[MLX4_ST_MAX_DEVICES]; + +} MLX4_ST_STAT, *PMLX4_ST_STAT; + +extern MLX4_ST_STAT g_stat; + +void st_print_mlx_header( struct mlx4_dev *mdev, struct mlx4_ib_sqp *sqp, struct mlx4_wqe_mlx_seg *mlx ); + +void st_print_mlx_send(struct mlx4_dev *mdev, struct ib_qp *ibqp, ib_send_wr_t *wr); + +void st_dev_rmv( PMLX4_ST_DEVICE p_stat ); + +PMLX4_ST_DEVICE st_dev_add(); + +#pragma once diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/drv/wmi.c b/branches/WOF2-3/hw/mlx4/kernel/bus/drv/wmi.c new file mode 100644 index 00000000..97086797 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/drv/wmi.c @@ -0,0 +1,237 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + WMI.C + +Abstract: + + This module handles all the WMI Irps. + +Environment: + + Kernel mode + +--*/ + +#include "precomp.h" + +#if defined (EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "wmi.tmh" +#endif + +NTSTATUS +WmiRegistration( + WDFDEVICE Device + ) +/*++ +Routine Description + + Registers with WMI as a data provider for this + instance of the device + +--*/ +{ + WDF_WMI_PROVIDER_CONFIG providerConfig; + WDF_WMI_INSTANCE_CONFIG instanceConfig; + NTSTATUS status; + DECLARE_CONST_UNICODE_STRING(busRsrcName, BUSRESOURCENAME); + + PAGED_CODE(); + + // + // Register WMI classes. + // First specify the resource name which contain the binary mof resource. + // + status = WdfDeviceAssignMofResourceName(Device, &busRsrcName); + if (!NT_SUCCESS(status)) { + return status; + } + + WDF_WMI_PROVIDER_CONFIG_INIT(&providerConfig, &MLX4_BUS_WMI_STD_DATA_GUID); + providerConfig.MinInstanceBufferSize = sizeof(BUS_WMI_STD_DATA); + + // + // You would want to create a WDFWMIPROVIDER handle separately if you are + // going to dynamically create instances on the provider. Since we are + // statically creating one instance, there is no need to create the provider + // handle. + // + WDF_WMI_INSTANCE_CONFIG_INIT_PROVIDER_CONFIG(&instanceConfig, &providerConfig); + + // + // By setting Register to TRUE, we tell the framework to create a provider + // as part of the Instance creation call. This eliminates the need to + // call WdfWmiProviderRegister. + // + instanceConfig.Register = TRUE; + instanceConfig.EvtWmiInstanceQueryInstance = EvtStdDataQueryInstance; + instanceConfig.EvtWmiInstanceSetInstance = EvtStdDataSetInstance; + instanceConfig.EvtWmiInstanceSetItem = EvtStdDataSetItem; + + status = WdfWmiInstanceCreate( Device, + &instanceConfig, WDF_NO_OBJECT_ATTRIBUTES,WDF_NO_HANDLE ); + + return status; +} + +// +// WMI System Call back functions +// +NTSTATUS +EvtStdDataSetItem( + IN WDFWMIINSTANCE WmiInstance, + IN ULONG DataItemId, + IN ULONG InBufferSize, + IN PVOID InBuffer + ) +/*++ + +Routine Description: + + This routine is a callback into the driver to set for the contents of + an instance. + +Arguments: + + WmiInstance is the instance being set + + DataItemId has the id of the data item being set + + InBufferSize has the size of the data item passed + + InBuffer has the new values for the data item + +Return Value: + + status + +--*/ +{ + PFDO_DEVICE_DATA fdoData; + + PAGED_CODE(); + + fdoData = FdoGetData(WdfWmiInstanceGetDevice(WmiInstance)); + + switch(DataItemId) + { + case 1: + if (InBufferSize < sizeof(ULONG)) { + return STATUS_BUFFER_TOO_SMALL; + } + g_mlx4_dbg_level = fdoData->WmiData.DebugPrintLevel = *((PULONG)InBuffer); + return STATUS_SUCCESS; + + case 2: + if (InBufferSize < sizeof(ULONG)) { + return STATUS_BUFFER_TOO_SMALL; + } + g_mlx4_dbg_flags = fdoData->WmiData.DebugPrintFlags = *((PULONG)InBuffer); + return STATUS_SUCCESS; + + default: + return STATUS_WMI_READ_ONLY; + } +} + +NTSTATUS +EvtStdDataSetInstance( + IN WDFWMIINSTANCE WmiInstance, + IN ULONG InBufferSize, + IN PVOID InBuffer + ) +/*++ + +Routine Description: + + This routine is a callback into the driver to set for the contents of + an instance. + +Arguments: + + WmiInstance is the instance being set + + BufferSize has the size of the data block passed + + Buffer has the new values for the data block + +Return Value: + + status + +--*/ +{ + PFDO_DEVICE_DATA fdoData; + + UNREFERENCED_PARAMETER(InBufferSize); + + PAGED_CODE(); + + fdoData = FdoGetData(WdfWmiInstanceGetDevice(WmiInstance)); + + // + // We will update only writable elements. + // + g_mlx4_dbg_level = fdoData->WmiData.DebugPrintLevel = ((PBUS_WMI_STD_DATA)InBuffer)->DebugPrintLevel; + g_mlx4_dbg_flags = fdoData->WmiData.DebugPrintFlags = ((PBUS_WMI_STD_DATA)InBuffer)->DebugPrintFlags; + + return STATUS_SUCCESS; +} + +NTSTATUS +EvtStdDataQueryInstance( + IN WDFWMIINSTANCE WmiInstance, + IN ULONG OutBufferSize, + IN PVOID OutBuffer, + OUT PULONG BufferUsed + ) +/*++ + +Routine Description: + + This routine is a callback into the driver to set for the contents of + a wmi instance + +Arguments: + + WmiInstance is the instance being set + + OutBufferSize on has the maximum size available to write the data + block. + + OutBuffer on return is filled with the returned data block + + BufferUsed pointer containing how many bytes are required (upon failure) or + how many bytes were used (upon success) + +Return Value: + + status + +--*/ +{ + PFDO_DEVICE_DATA fdoData; + + UNREFERENCED_PARAMETER(OutBufferSize); + + PAGED_CODE(); + + fdoData = FdoGetData(WdfWmiInstanceGetDevice(WmiInstance)); + + *BufferUsed = sizeof (BUS_WMI_STD_DATA); + * (PBUS_WMI_STD_DATA) OutBuffer = fdoData->WmiData; + + return STATUS_SUCCESS; +} + diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/drv/wpptrace.h b/branches/WOF2-3/hw/mlx4/kernel/bus/drv/wpptrace.h new file mode 100644 index 00000000..bef591cb --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/drv/wpptrace.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2005 Mellanox Technologies LTD. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * This source code may incorporate intellectual property owned by + * Microsoft Corporation. Our provision of this source code does not + * include any licenses or any other rights to you under any Microsoft + * intellectual property. If you would like a license from Microsoft + * (e.g., to rebrand, redistribute), you need to contact Microsoft + * directly. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION 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: Uri Habusha + +#pragma once + +#if defined(EVENT_TRACING) + +#define WPP_CONTROL_GUIDS \ + WPP_DEFINE_CONTROL_GUID(EthrnetGuid,(d7221994, d451, 4272, af18, 55df9ca9bfa7), \ + WPP_DEFINE_BIT(BUS_DRIVER) \ + WPP_DEFINE_BIT(BUS_SS) \ + WPP_DEFINE_BIT(BUS_PNP) \ + WPP_DEFINE_BIT(BUS_IOCTL) \ + WPP_DEFINE_BIT(BUS_POWER) \ + WPP_DEFINE_BIT(BUS_WMI)) + + +#define WPP_LEVEL_FLAGS_ENABLED(lvl, flags) (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= lvl) +#define WPP_LEVEL_FLAGS_LOGGER(lvl,flags) WPP_LEVEL_LOGGER(flags) +#define WPP_FLAG_ENABLED(flags)(WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= TRACE_LEVEL_VERBOSE) +#define WPP_FLAG_LOGGER(flags) WPP_LEVEL_LOGGER(flags) + +// begin_wpp config +// TRACE_FUNC_ENTER(FLAG); +// TRACE_FUNC_EXIT(FLAG); +// TRACE_PRINT(LEVEL,FLAGS,MSG,...) +// USESUFFIX(TRACE_FUNC_ENTER, "====>>> %!FUNC! "); +// USESUFFIX(TRACE_FUNC_EXIT, "<<<====== %!FUNC!]"); +// end_wpp + +#else //defined(EVENT_TRACING) + +#include + +// Debug toppics +#define BUS_DRIVER 0x000001 +#define BUS_SS 0x000002 +#define BUS_PNP 0x000004 +#define BUS_IOCTL 0x000008 +#define BUS_POWER 0x000010 +#define BUS_WMI 0x000020 + +#if DBG + +extern const unsigned int g_SdpDbgLevel; +extern const unsigned int g_SdpDbgFlags; + +// +//BUGBUG: need to protect against context switch otherwise there can +// be mismatched of trace messages. We can't use a simple spinlock +// since some of the printing occours in IRQ level and the spinlock +// can be alreardy use. +// +#define TRACE_PRINT(_level_,_flag_,_msg_) \ + if (g_SdpDbgLevel >= (_level_) && (g_SdpDbgFlags & (_flag_))) \ + { \ + if(_level_ == TRACE_LEVEL_ERROR) \ + cl_dbg_out ("***ERROR*** "); \ + cl_dbg_out ("%s(): ",__FUNCTION__); \ + cl_dbg_out _msg_; \ + } + +#else + +#define TRACE_PRINT(lvl ,flags, msg) + +#endif + + + +#define TRACE_FUNC_ENTER(flags)\ + ETH_PRINT(TRACE_LEVEL_VERBOSE, flags,("===>\n")); + +#define TRACE_FUNC_EXIT(flags)\ + ETH_PRINT(TRACE_LEVEL_VERBOSE, flags, ("<===\n" )); + + + +#endif //defined(EVENT_TRACING) + diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/ib/Kconfig b/branches/WOF2-3/hw/mlx4/kernel/bus/ib/Kconfig new file mode 100644 index 00000000..4175a4bd --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/ib/Kconfig @@ -0,0 +1,8 @@ +config MLX4_INFINIBAND + tristate "Mellanox ConnectX HCA support" + select MLX4_CORE + ---help--- + This driver provides low-level InfiniBand support for + Mellanox ConnectX PCI Express host channel adapters (HCAs). + This is required to use InfiniBand protocols such as + IP-over-IB or SRP with these devices. diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/ib/Makefile.lnx b/branches/WOF2-3/hw/mlx4/kernel/bus/ib/Makefile.lnx new file mode 100644 index 00000000..70f09c78 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/ib/Makefile.lnx @@ -0,0 +1,3 @@ +obj-$(CONFIG_MLX4_INFINIBAND) += mlx4_ib.o + +mlx4_ib-y := ah.o cq.o doorbell.o mad.o main.o mr.o qp.o srq.o diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/ib/SOURCES b/branches/WOF2-3/hw/mlx4/kernel/bus/ib/SOURCES new file mode 100644 index 00000000..ef658150 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/ib/SOURCES @@ -0,0 +1,45 @@ +TARGETNAME=mlx4_ib +TARGETPATH=..\..\..\..\..\bin\kernel\obj$(BUILD_ALT_DIR) +TARGETTYPE=DRIVER_LIBRARY + + + +!if $(FREEBUILD) +ENABLE_EVENT_TRACING=1 +!else +#ENABLE_EVENT_TRACING=1 +!endif + + +DLLDEF=ib.def + +SOURCES= ib.rc \ + ah.c \ + cq.c \ + doorbell.c \ + mad.c \ + main.c \ + mr.c \ + qp.c \ + srq.c + +INCLUDES=..;..\inc;..\..\inc;..\core\$O;..\..\..\inc;..\..\..\..\..\inc;..\..\..\..\..\inc\kernel; + +C_DEFINES=$(C_DEFINES) -DDRIVER -DDEPRECATE_DDK_FUNCTIONS -D__LITTLE_ENDIAN + +TARGETLIBS= \ + $(DDK_LIB_PATH)\ntstrsafe.lib \ + $(TARGETPATH)\*\complib.lib \ + $(TARGETPATH)\*\mlx4_core.lib \ + +!IFDEF ENABLE_EVENT_TRACING + +C_DEFINES = $(C_DEFINES) -DEVENT_TRACING + +RUN_WPP = $(SOURCES) -km -ext: .c .h .C .H \ + -scan:..\..\inc\mlx4_debug.h \ + -func:MLX4_PRINT(LEVEL,FLAGS,(MSG,...)) \ + -func:MLX4_PRINT_EXIT(LEVEL,FLAGS,(MSG,...)) +!ENDIF + +MSC_WARNING_LEVEL= /W4 diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/ib/ah.c b/branches/WOF2-3/hw/mlx4/kernel/bus/ib/ah.c new file mode 100644 index 00000000..cffd92cf --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/ib/ah.c @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "mlx4_ib.h" + +static inline int rdma_link_local_addr(struct in6_addr *addr) +{ + if (addr->s6_addr32[0] == cpu_to_be32(0xfe800000) && + addr->s6_addr32[1] == 0) + return 1; + else + return 0; +} + +inline void rdma_get_ll_mac(struct in6_addr *addr, u8 *mac) +{ + memcpy(mac, &addr->s6_addr[8], 3); + memcpy(mac + 3, &addr->s6_addr[13], 3); + mac[0] ^= 2; +} + +static inline int rdma_is_multicast_addr(struct in6_addr *addr) +{ + return addr->s6_addr[0] == 0xff ? 1 : 0; +} + +static inline void rdma_get_mcast_mac(struct in6_addr *addr, u8 *mac) +{ + int i; + + mac[0] = 0x33; + mac[1] = 0x33; + for (i = 2; i < 6; ++i) + mac[i] = addr->s6_addr[i + 10]; + +} + +int mlx4_ib_resolve_grh(struct mlx4_ib_dev *dev, const struct ib_ah_attr *ah_attr, + u8 *mac, int *is_mcast) +{ + int err = 0; + struct sockaddr_in6 dst; + + UNREFERENCED_PARAMETER(dev); + + *is_mcast = 0; + memcpy(dst.sin6_addr.s6_addr, ah_attr->grh.dgid.raw, sizeof(ah_attr->grh.dgid.raw)); + + if (rdma_link_local_addr(&dst.sin6_addr)) + rdma_get_ll_mac(&dst.sin6_addr, mac); + else if (rdma_is_multicast_addr(&dst.sin6_addr)) { + rdma_get_mcast_mac(&dst.sin6_addr, mac); + *is_mcast = 1; + } else { + err = -EINVAL; //jyang:todo + ASSERT(FALSE); + } + return err; +} + +static struct ib_ah *create_ib_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr, + struct mlx4_ib_ah *ah) +{ + struct mlx4_dev *dev = to_mdev(pd->device)->dev; + + if (mlx4_is_barred(pd->device->dma_device)) + return ERR_PTR(-EFAULT); + + + ah->av.ib.port_pd = cpu_to_be32(to_mpd(pd)->pdn | (ah_attr->port_num << 24)); + ah->av.ib.g_slid = ah_attr->src_path_bits; + if (ah_attr->ah_flags & IB_AH_GRH) { + ah->av.ib.g_slid |= 0x80; + ah->av.ib.gid_index = ah_attr->grh.sgid_index; + ah->av.ib.hop_limit = ah_attr->grh.hop_limit; + ah->av.ib.sl_tclass_flowlabel |= + cpu_to_be32((ah_attr->grh.traffic_class << 20) | + ah_attr->grh.flow_label); + memcpy(ah->av.ib.dgid, ah_attr->grh.dgid.raw, 16); + } + + ah->av.ib.dlid = cpu_to_be16(ah_attr->dlid); + if (ah_attr->static_rate) { + ah->av.ib.stat_rate = ah_attr->static_rate + MLX4_STAT_RATE_OFFSET; + while (ah->av.ib.stat_rate > IB_RATE_2_5_GBPS + MLX4_STAT_RATE_OFFSET && + !(1 << ah->av.ib.stat_rate & dev->caps.stat_rate_support)) + --ah->av.ib.stat_rate; + } + ah->av.ib.sl_tclass_flowlabel = cpu_to_be32(ah_attr->sl << 28); + + return &ah->ibah; +} + +struct ib_ah *create_rdmaoe_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr, + struct mlx4_ib_ah *ah) +{ + struct mlx4_ib_dev *ibdev = to_mdev(pd->device); + struct mlx4_dev *dev = ibdev->dev; + u8 mac[6]; + int err; + int is_mcast; + + if (mlx4_is_barred(pd->device->dma_device)) + return ERR_PTR(-EFAULT); + + err = mlx4_ib_resolve_grh(ibdev, ah_attr, mac, &is_mcast); + if (err) + return ERR_PTR(err); + + memcpy(ah->av.eth.mac_0_1, mac, 2); + memcpy(ah->av.eth.mac_2_5, mac + 2, 4); + ah->av.ib.port_pd = cpu_to_be32(to_mpd(pd)->pdn | (ah_attr->port_num << 24)); + ah->av.ib.g_slid = 0x80; + if (ah_attr->static_rate) { + ah->av.ib.stat_rate = ah_attr->static_rate + MLX4_STAT_RATE_OFFSET; + while (ah->av.ib.stat_rate > IB_RATE_2_5_GBPS + MLX4_STAT_RATE_OFFSET && + !(1 << ah->av.ib.stat_rate & dev->caps.stat_rate_support)) + --ah->av.ib.stat_rate; + } + + /* + * HW requires multicast LID so we just choose one. + */ + if (is_mcast) + ah->av.ib.dlid = cpu_to_be16(0xc000); + + memcpy(ah->av.ib.dgid, ah_attr->grh.dgid.raw, 16); + ah->av.ib.sl_tclass_flowlabel = cpu_to_be32(ah_attr->sl << 28); + + return &ah->ibah; +} + + +struct ib_ah *mlx4_ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr) +{ + struct mlx4_ib_ah *ah; + enum rdma_transport_type transport; + + struct ib_ah *ret; + + ah = kzalloc(sizeof *ah, GFP_ATOMIC); + if (!ah) + return ERR_PTR(-ENOMEM); + + transport = rdma_port_get_transport(pd->device, ah_attr->port_num); + if (transport == RDMA_TRANSPORT_RDMAOE) { + if (!(ah_attr->ah_flags & IB_AH_GRH)) { + ret = ERR_PTR(-EINVAL); + goto out; + } else { + /* TBD: need to handle the case when we get called + in an atomic context and there we might sleep. We + don't expect this currently since we're working with + link local addresses which we can translate without + going to sleep */ + ret = create_rdmaoe_ah(pd, ah_attr, ah); + if (IS_ERR(ret)) + goto out; + else + return ret; + } + } else + return create_ib_ah(pd, ah_attr, ah); /* never fails */ + +out: + kfree(ah); + return ret; +} + + +int mlx4_ib_query_ah(struct ib_ah *ibah, struct ib_ah_attr *ah_attr) +{ + struct mlx4_ib_ah *ah = to_mah(ibah); + enum rdma_transport_type transport; + + transport = rdma_port_get_transport(ibah->device, ah_attr->port_num); + + if (mlx4_is_barred(ibah->device->dma_device)) + return -EFAULT; + + memset(ah_attr, 0, sizeof *ah_attr); + ah_attr->dlid = transport == RDMA_TRANSPORT_IB ? be16_to_cpu(ah->av.ib.dlid) : 0; + ah_attr->sl = (u8)(be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) >> 28); + ah_attr->port_num = (u8)(be32_to_cpu(ah->av.ib.port_pd) >> 24); + if (ah->av.ib.stat_rate) + ah_attr->static_rate = ah->av.ib.stat_rate - MLX4_STAT_RATE_OFFSET; + ah_attr->src_path_bits = ah->av.ib.g_slid & 0x7F; + + if (mlx4_ib_ah_grh_present(ah)) { + ah_attr->ah_flags = IB_AH_GRH; + + ah_attr->grh.traffic_class = + (u8)(be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) >> 20); + ah_attr->grh.flow_label = + be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) & 0xfffff; + ah_attr->grh.hop_limit = ah->av.ib.hop_limit; + ah_attr->grh.sgid_index = ah->av.ib.gid_index; + memcpy(ah_attr->grh.dgid.raw, ah->av.ib.dgid, 16); + } + + return 0; +} + +int mlx4_ib_destroy_ah(struct ib_ah *ah) +{ + kfree(to_mah(ah)); + return 0; +} + +// Leo: temporary +int mlx4_ib_modify_ah( struct ib_ah *ibah, struct ib_ah_attr *ah_attr ) +{ + struct mlx4_av *av = &to_mah(ibah)->av.ib; + struct mlx4_dev *dev = to_mdev(ibah->pd->device)->dev; + + if (mlx4_is_barred(dev)) + return -EFAULT; + + // taken from mthca_create_av + av->port_pd = cpu_to_be32(to_mpd(ibah->pd)->pdn | (ah_attr->port_num << 24)); + av->g_slid = ah_attr->src_path_bits; + av->dlid = cpu_to_be16(ah_attr->dlid); + if (ah_attr->static_rate) { + av->stat_rate = ah_attr->static_rate + MLX4_STAT_RATE_OFFSET; + while (av->stat_rate > IB_RATE_2_5_GBPS + MLX4_STAT_RATE_OFFSET && + !(1 << av->stat_rate & dev->caps.stat_rate_support)) + --av->stat_rate; + } + av->sl_tclass_flowlabel = cpu_to_be32(ah_attr->sl << 28); + if (ah_attr->ah_flags & IB_AH_GRH) { + av->g_slid |= 0x80; + av->gid_index = ah_attr->grh.sgid_index; + av->hop_limit = ah_attr->grh.hop_limit; + av->sl_tclass_flowlabel |= + cpu_to_be32((ah_attr->grh.traffic_class << 20) | + ah_attr->grh.flow_label); + memcpy(av->dgid, ah_attr->grh.dgid.raw, 16); + } + return 0; +} + diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/ib/cq.c b/branches/WOF2-3/hw/mlx4/kernel/bus/ib/cq.c new file mode 100644 index 00000000..0ff7e01b --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/ib/cq.c @@ -0,0 +1,651 @@ +/* + * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include +#include "mlx4_ib.h" +#include "cq.h" +#include "qp.h" +#include "user.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "cq.tmh" +#endif + + +static void mlx4_ib_cq_comp(struct mlx4_cq *cq) +{ + struct ib_cq *ibcq = &to_mibcq(cq)->ibcq; + ibcq->comp_handler(ibcq->cq_context); +} + +static void mlx4_ib_cq_event(struct mlx4_cq *cq, enum mlx4_event type) +{ + ib_event_rec_t event; + struct ib_cq *ibcq; + + if (type != MLX4_EVENT_TYPE_CQ_ERROR) { + printk(KERN_WARNING "mlx4_ib: Unexpected event type %d " + "on CQ %06x\n", type, cq->cqn); + return; + } + + ibcq = &to_mibcq(cq)->ibcq; + event.type = IB_EVENT_CQ_ERR; + event.context = ibcq->cq_context; + event.vendor_specific = type; + ibcq->event_handler(&event); +} + +static void *get_cqe_from_buf(struct mlx4_ib_cq_buf *buf, int n) +{ + int offset = n * sizeof (struct mlx4_cqe); + + if (buf->buf.nbufs == 1) + return buf->buf.u.direct.buf + offset; + else + return buf->buf.u.page_list[offset >> PAGE_SHIFT].buf + + (offset & (PAGE_SIZE - 1)); +} + +static void *get_cqe(struct mlx4_ib_cq *cq, int n) +{ + return get_cqe_from_buf(&cq->buf, n); +} + +static void *get_sw_cqe(struct mlx4_ib_cq *cq, int n) +{ + struct mlx4_cqe *cqe = get_cqe(cq, n & cq->ibcq.cqe); + + return (!!(cqe->owner_sr_opcode & MLX4_CQE_OWNER_MASK) ^ + !!(n & (cq->ibcq.cqe + 1))) ? NULL : cqe; +} + +static struct mlx4_cqe *next_cqe_sw(struct mlx4_ib_cq *cq) +{ + return get_sw_cqe(cq, cq->mcq.cons_index); +} + +int mlx4_ib_modify_cq(struct ib_cq *cq, u16 cq_count, u16 cq_period) +{ + struct mlx4_ib_cq *mcq = to_mcq(cq); + struct mlx4_ib_dev *dev = to_mdev(cq->device); + struct mlx4_cq_context *context; + int err; + + if (mlx4_is_barred(dev->dev)) + return -EFAULT; + + context = kzalloc(sizeof *context, GFP_KERNEL); + if (!context) + return -ENOMEM; + + context->cq_period = cpu_to_be16(cq_period); + context->cq_max_count = cpu_to_be16(cq_count); + err = mlx4_cq_modify(dev->dev, &mcq->mcq, context, 1); + + kfree(context); + return err; +} + +struct ib_cq *mlx4_ib_create_cq(struct ib_device *ibdev, int entries, int vector, + struct ib_ucontext *context, + struct ib_udata *udata) +{ + struct mlx4_ib_dev *dev = to_mdev(ibdev); + struct mlx4_ib_cq *cq; + struct mlx4_uar *uar; + int buf_size; + int err; + + if (mlx4_is_barred(ibdev->dma_device)) + return ERR_PTR(-EFAULT); + + if (entries < 1 || entries > dev->dev->caps.max_cqes) + return ERR_PTR(-EINVAL); + + cq = kzalloc(sizeof *cq, GFP_KERNEL); + if (!cq) { + printk(KERN_ERR "mlx4_ib_create_cq: -ENOMEM \n"); + return ERR_PTR(-ENOMEM); + } + + entries = roundup_pow_of_two(entries + 1); + cq->ibcq.cqe = entries - 1; + buf_size = entries * sizeof (struct mlx4_cqe); + spin_lock_init(&cq->lock); + + if (context && udata) { + struct mlx4_ib_create_cq ucmd; + + if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd)) { + err = -EFAULT; + goto err_cq; + } + + cq->umem = ib_umem_get(context, ucmd.buf_addr, buf_size, + IB_ACCESS_LOCAL_WRITE, FALSE); + if (IS_ERR(cq->umem)) { + err = PTR_ERR(cq->umem); + printk(KERN_ERR "mlx4_ib_create_cq: ib_umem_get failed with %d \n", err); + goto err_cq; + } + + err = mlx4_mtt_init(dev->dev, ib_umem_page_count(cq->umem), + ilog2(cq->umem->page_size), &cq->buf.mtt); + if (err) { + printk(KERN_ERR "mlx4_ib_create_cq: mlx4_mtt_init failed with %d \n", err); + goto err_buf; + } + + err = mlx4_ib_umem_write_mtt(dev, &cq->buf.mtt, cq->umem); + if (err) { + printk(KERN_ERR "mlx4_ib_create_cq: mlx4_ib_umem_write_mtt failed with %d \n", err); + goto err_mtt; + } + + err = mlx4_ib_db_map_user(to_mucontext(context), ucmd.db_addr, + &cq->db); + if (err) { + printk(KERN_ERR "mlx4_ib_create_cq: mlx4_ib_db_map_user failed with %d \n", err); + goto err_mtt; + } + + // add mapping to user's arm_sn variable + // we have no way pass the completion event to provider library + // so we'll increment user's arm_sn in kernel + err = ib_umem_map( ucmd.arm_sn_addr, sizeof(int), + IB_ACCESS_LOCAL_WRITE, &cq->mcq.mdl, &cq->mcq.p_u_arm_sn ); + if (err) { + printk(KERN_ERR "mlx4_ib_create_cq: ib_umem_map failed with %d \n", err); + goto err_dbmap; + } + + uar = &to_mucontext(context)->uar; + } else { + err = mlx4_ib_db_alloc(dev, &cq->db, 1); + if (err) { + printk(KERN_ERR "mlx4_ib_create_cq: mlx4_ib_db_alloc failed with %d \n", err); + goto err_cq; + } + + cq->mcq.set_ci_db = cq->db.db; + cq->mcq.arm_db = cq->db.db + 1; + *cq->mcq.set_ci_db = 0; + *cq->mcq.arm_db = 0; + + if (mlx4_buf_alloc(dev->dev, buf_size, PAGE_SIZE * 2, &cq->buf.buf)) { + printk(KERN_ERR "mlx4_ib_create_cq: mlx4_buf_alloc failed for buf_size %d (entries %d) " + "on CQ %06x\n", buf_size, entries, cq->mcq.cqn); + err = -ENOMEM; + goto err_db; + } + + err = mlx4_mtt_init(dev->dev, cq->buf.buf.npages, cq->buf.buf.page_shift, + &cq->buf.mtt); + if (err) { + printk(KERN_ERR "mlx4_ib_create_cq: mlx4_mtt_init failed with %d \n", err); + goto err_buf; + } + + err = mlx4_buf_write_mtt(dev->dev, &cq->buf.mtt, &cq->buf.buf); + if (err) { + printk(KERN_ERR "mlx4_ib_create_cq: mlx4_buf_write_mtt failed with %d \n", err); + goto err_mtt; + } + + cq->mcq.p_u_arm_sn = NULL; + uar = &dev->priv_uar; + } + + err = mlx4_cq_alloc(dev->dev, entries, &cq->buf.mtt, uar, + cq->db.dma.da, &cq->mcq, vector, 0); + if (err) { + printk(KERN_ERR "mlx4_ib_create_cq: mlx4_cq_alloc failed with %d \n", err); + goto err_dbmap; + } + + cq->mcq.comp = mlx4_ib_cq_comp; + cq->mcq.event = mlx4_ib_cq_event; + + if (context) + if (ib_copy_to_udata(udata, &cq->mcq.cqn, sizeof (__u32))) { + err = -EFAULT; + goto err_dbmap; + } + + return &cq->ibcq; + +err_dbmap: + ib_umem_unmap( cq->mcq.mdl, cq->mcq.p_u_arm_sn ); + if (context) + mlx4_ib_db_unmap_user(to_mucontext(context), &cq->db); + +err_mtt: + mlx4_mtt_cleanup(dev->dev, &cq->buf.mtt); + +err_buf: + if (context) + ib_umem_release(cq->umem); + else + mlx4_buf_free(dev->dev, entries * sizeof (struct mlx4_cqe), + &cq->buf.buf); + +err_db: + if (!context) + mlx4_ib_db_free(dev, &cq->db); + +err_cq: + kfree(cq); + + return ERR_PTR(err); +} + +int mlx4_ib_destroy_cq(struct ib_cq *cq) +{ + struct mlx4_ib_dev *dev = to_mdev(cq->device); + struct mlx4_ib_cq *mcq = to_mcq(cq); + + mlx4_cq_free(dev->dev, &mcq->mcq); + mlx4_mtt_cleanup(dev->dev, &mcq->buf.mtt); + + if (cq->p_uctx) { + ib_umem_unmap( mcq->mcq.mdl, mcq->mcq.p_u_arm_sn ); + mlx4_ib_db_unmap_user(to_mucontext(cq->p_uctx), &mcq->db); + ib_umem_release(mcq->umem); + } else { + mlx4_buf_free(dev->dev, (cq->cqe + 1) * sizeof (struct mlx4_cqe), + &mcq->buf.buf); + mlx4_ib_db_free(dev, &mcq->db); + } + + kfree(mcq); + + return 0; +} + +static void dump_cqe(void *cqe) +{ + __be32 *buf = cqe; + + MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, + (KERN_DEBUG "CQE contents %08x %08x %08x %08x %08x %08x %08x %08x\n", + be32_to_cpu(buf[0]), be32_to_cpu(buf[1]), be32_to_cpu(buf[2]), + be32_to_cpu(buf[3]), be32_to_cpu(buf[4]), be32_to_cpu(buf[5]), + be32_to_cpu(buf[6]), be32_to_cpu(buf[7]))); +} + +static void mlx4_ib_handle_error_cqe(struct mlx4_err_cqe *cqe, + ib_wc_t *wc) +{ + if (cqe->syndrome == MLX4_CQE_SYNDROME_LOCAL_QP_OP_ERR) { + printk(KERN_DEBUG "local QP operation err " + "(QPN %06x, WQE index %x, vendor syndrome %02x, " + "opcode = %02x)\n", + be32_to_cpu(cqe->my_qpn), be16_to_cpu(cqe->wqe_index), + cqe->vendor_err_syndrome, + cqe->owner_sr_opcode & ~MLX4_CQE_OWNER_MASK); + dump_cqe(cqe); + } + + switch (cqe->syndrome) { + case MLX4_CQE_SYNDROME_LOCAL_LENGTH_ERR: + wc->status = IB_WCS_LOCAL_LEN_ERR; + break; + case MLX4_CQE_SYNDROME_LOCAL_QP_OP_ERR: + wc->status = IB_WCS_LOCAL_OP_ERR; + break; + case MLX4_CQE_SYNDROME_LOCAL_PROT_ERR: + wc->status = IB_WCS_LOCAL_PROTECTION_ERR; + break; + case MLX4_CQE_SYNDROME_WR_FLUSH_ERR: + wc->status = IB_WCS_WR_FLUSHED_ERR; + break; + case MLX4_CQE_SYNDROME_MW_BIND_ERR: + wc->status = IB_WCS_MEM_WINDOW_BIND_ERR; + break; + case MLX4_CQE_SYNDROME_BAD_RESP_ERR: + wc->status = IB_WCS_BAD_RESP_ERR; + break; + case MLX4_CQE_SYNDROME_LOCAL_ACCESS_ERR: + wc->status = IB_WCS_LOCAL_ACCESS_ERR; + break; + case MLX4_CQE_SYNDROME_REMOTE_INVAL_REQ_ERR: + wc->status = IB_WCS_REM_INVALID_REQ_ERR; + break; + case MLX4_CQE_SYNDROME_REMOTE_ACCESS_ERR: + wc->status = IB_WCS_REM_ACCESS_ERR; + break; + case MLX4_CQE_SYNDROME_REMOTE_OP_ERR: + wc->status = IB_WCS_REM_OP_ERR; + break; + case MLX4_CQE_SYNDROME_TRANSPORT_RETRY_EXC_ERR: + wc->status = IB_WCS_TIMEOUT_RETRY_ERR; + break; + case MLX4_CQE_SYNDROME_RNR_RETRY_EXC_ERR: + wc->status = IB_WCS_RNR_RETRY_ERR; + break; + case MLX4_CQE_SYNDROME_REMOTE_ABORTED_ERR: + wc->status = IB_WCS_REM_ABORT_ERR; + break; + default: + wc->status = IB_WC_GENERAL_ERR; + break; + } + + wc->vendor_specific = cqe->vendor_err_syndrome; +} + +static uint32_t mlx4_ib_ipoib_csum_ok(__be32 status, __be16 checksum) { + + #define CSUM_VALID_NUM 0xffff + uint32_t res = 0; + + // Verify that IP_OK bit is set and the packet is pure IPv4 packet + if ((status & cpu_to_be32(MLX4_CQE_IPOIB_STATUS_IPV4 | + MLX4_CQE_IPOIB_STATUS_IPV4 | + MLX4_CQE_IPOIB_STATUS_IPV4OPT | + MLX4_CQE_IPOIB_STATUS_IPV6 | + MLX4_CQE_IPOIB_STATUS_IPOK)) == + cpu_to_be32(MLX4_CQE_IPOIB_STATUS_IPV4 | + MLX4_CQE_IPOIB_STATUS_IPOK)) + { + // IP checksum calculated by MLX4 matched the checksum in the receive packet's + res |= MLX4_NdisPacketIpChecksumSucceeded; + if (checksum == CSUM_VALID_NUM) { + // TCP or UDP checksum calculated by MLX4 matched the checksum in the receive packet's + res |= (MLX4_NdisPacketUdpChecksumSucceeded | + MLX4_NdisPacketTcpChecksumSucceeded ); + ASSERT( status & cpu_to_be32(MLX4_CQE_IPOIB_STATUS_TCP | MLX4_CQE_IPOIB_STATUS_UDP)); + } + } + return (( res << 8 ) & IB_RECV_OPT_CSUM_MASK ); +} + +static int mlx4_ib_poll_one(struct mlx4_ib_cq *cq, + struct mlx4_ib_qp **cur_qp, + ib_wc_t *wc) +{ + struct mlx4_cqe *cqe; + struct mlx4_qp *mqp; + struct mlx4_ib_wq *wq; + struct mlx4_ib_srq *srq; + int is_send; + int is_error; + u16 wqe_ctr; + + cqe = next_cqe_sw(cq); + if (!cqe) + return -EAGAIN; + + ++cq->mcq.cons_index; + + /* + * Make sure we read CQ entry contents after we've checked the + * ownership bit. + */ + rmb(); + + is_send = cqe->owner_sr_opcode & MLX4_CQE_IS_SEND_MASK; + is_error = (cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) == + MLX4_CQE_OPCODE_ERROR; + + if (!*cur_qp || (be32_to_cpu(cqe->my_qpn) & 0xffffff) != (u32)(*cur_qp)->mqp.qpn) { + /* + * We do not have to take the QP table lock here, + * because CQs will be locked while QPs are removed + * from the table. + */ +#if 1 + // radix_tree_insert in current implementation seems like + // can cause radix_tree_lookup to miss an existing QP + // so we call qp_lookup under the spinlock + mqp = mlx4_qp_lookup_locked( to_mdev(cq->ibcq.device)->dev, be32_to_cpu(cqe->my_qpn)); +#else + mqp = __mlx4_qp_lookup( to_mdev(cq->ibcq.device)->dev, be32_to_cpu(cqe->my_qpn)); +#endif + + if (unlikely(!mqp)) { + printk(KERN_WARNING "CQ %06x with entry for unknown QPN %06x\n", + cq->mcq.cqn, be32_to_cpu(cqe->my_qpn) & 0xffffff); + return -EINVAL; + } + + *cur_qp = to_mibqp(mqp); + } + + if (is_send) { + wq = &(*cur_qp)->sq; + wqe_ctr = be16_to_cpu(cqe->wqe_index); + wq->tail += (u16) (wqe_ctr - (u16) wq->tail); + wc->wr_id = wq->wrid[wq->tail & (wq->wqe_cnt - 1)]; + ++wq->tail; + } else if ((*cur_qp)->ibqp.srq) { + srq = to_msrq((*cur_qp)->ibqp.srq); + wqe_ctr = be16_to_cpu(cqe->wqe_index); + wc->wr_id = srq->wrid[wqe_ctr]; + mlx4_ib_free_srq_wqe(srq, wqe_ctr); + } else { + wq = &(*cur_qp)->rq; + wc->wr_id = wq->wrid[wq->tail & (wq->wqe_cnt - 1)]; + ++wq->tail; + } + + if (is_send) { + wc->recv.ud.recv_opt = 0; + switch (cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) { + case MLX4_OPCODE_RDMA_WRITE_IMM: + wc->recv.ud.recv_opt |= IB_RECV_OPT_IMMEDIATE; + case MLX4_OPCODE_RDMA_WRITE: + wc->wc_type = IB_WC_RDMA_WRITE; + break; + case MLX4_OPCODE_SEND_IMM: + wc->recv.ud.recv_opt |= IB_RECV_OPT_IMMEDIATE; + case MLX4_OPCODE_SEND: + wc->wc_type = IB_WC_SEND; + break; + case MLX4_OPCODE_RDMA_READ: + wc->wc_type = IB_WC_RDMA_READ; + wc->length = be32_to_cpu(cqe->byte_cnt); + break; + case MLX4_OPCODE_ATOMIC_CS: + wc->wc_type = IB_WC_COMPARE_SWAP; + wc->length = 8; + break; + case MLX4_OPCODE_ATOMIC_FA: + wc->wc_type = IB_WC_FETCH_ADD; + wc->length = 8; + break; + case MLX4_OPCODE_BIND_MW: + wc->wc_type = IB_WC_MW_BIND; + break; + case MLX4_OPCODE_LSO: + wc->wc_type = IB_WC_LSO; + break; + default: + wc->wc_type = IB_WC_SEND; + break; + } + } else { + wc->length = be32_to_cpu(cqe->byte_cnt); + + switch (cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) { + case MLX4_RECV_OPCODE_RDMA_WRITE_IMM: + wc->wc_type = IB_WC_RECV_RDMA_WRITE; + wc->recv.ud.recv_opt = IB_RECV_OPT_IMMEDIATE; + wc->recv.ud.immediate_data = cqe->immed_rss_invalid; + break; + case MLX4_RECV_OPCODE_SEND: + wc->wc_type = IB_WC_RECV; + wc->recv.ud.recv_opt = 0; + break; + case MLX4_RECV_OPCODE_SEND_IMM: + wc->wc_type = IB_WC_RECV; + wc->recv.ud.recv_opt = IB_RECV_OPT_IMMEDIATE; + wc->recv.ud.immediate_data = cqe->immed_rss_invalid; + break; + default: + wc->recv.ud.recv_opt = 0; + wc->wc_type = IB_WC_RECV; + break; + } + + wc->recv.ud.remote_lid = cqe->rlid; + wc->recv.ud.remote_sl = cqe->sl >> 4; + wc->recv.ud.remote_qp = cqe->g_mlpath_rqpn & 0xffffff00; + wc->recv.ud.path_bits = (u8)(cqe->g_mlpath_rqpn & 0x7f); + wc->recv.ud.recv_opt |= cqe->g_mlpath_rqpn & 0x080 ? IB_RECV_OPT_GRH_VALID : 0; + wc->recv.ud.pkey_index = (u16)(be32_to_cpu(cqe->immed_rss_invalid) & 0x7f); + wc->recv.ud.recv_opt |= mlx4_ib_ipoib_csum_ok(cqe->ipoib_status,cqe->checksum); + } + if (!is_send && cqe->rlid == 0){ + MLX4_PRINT(TRACE_LEVEL_INFORMATION,MLX4_DBG_CQ,("found rlid == 0 \n ")); + wc->recv.ud.recv_opt |= IB_RECV_OPT_FORWARD; + } + + if (unlikely(is_error)) + mlx4_ib_handle_error_cqe((struct mlx4_err_cqe *) cqe, wc); + else + wc->status = IB_WCS_SUCCESS; + + return 0; +} + +int mlx4_ib_poll_cq( + IN struct ib_cq *ibcq, + IN OUT ib_wc_t** const pp_free_wclist, + OUT ib_wc_t** const pp_done_wclist ) +{ + struct mlx4_ib_cq *cq = to_mcq(ibcq); + struct mlx4_ib_qp *cur_qp = NULL; + unsigned long flags; + int err = 0; + int npolled = 0; + ib_wc_t *wc_p, **next_pp; + + spin_lock_irqsave(&cq->lock, &flags); + + // loop through CQ + next_pp = pp_done_wclist; + wc_p = *pp_free_wclist; + while( wc_p ) { + // poll one CQE + err = mlx4_ib_poll_one(cq, &cur_qp, wc_p); + if (err) + break; + + // prepare for the next loop + *next_pp = wc_p; + next_pp = &wc_p->p_next; + wc_p = wc_p->p_next; + ++npolled; + } + + // prepare the results + *pp_free_wclist = wc_p; /* Set the head of the free list. */ + *next_pp = NULL; /* Clear the tail of the done list. */ + + // update consumer index + if (npolled) + mlx4_cq_set_ci(&cq->mcq); + + spin_unlock_irqrestore(&cq->lock, flags); + return (err == 0 || err == -EAGAIN)? npolled : err; +} + +int mlx4_ib_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags) +{ + if (!mlx4_is_barred(ibcq->device->dma_device)) + mlx4_cq_arm(&to_mcq(ibcq)->mcq, + (flags & IB_CQ_SOLICITED_MASK) == IB_CQ_SOLICITED ? + MLX4_CQ_DB_REQ_NOT_SOL : MLX4_CQ_DB_REQ_NOT, + to_mdev(ibcq->device)->uar_map, + MLX4_GET_DOORBELL_LOCK(&to_mdev(ibcq->device)->uar_lock)); + + return 0; +} + +void __mlx4_ib_cq_clean(struct mlx4_ib_cq *cq, u32 qpn, struct mlx4_ib_srq *srq) +{ + u32 prod_index; + int nfreed = 0; + struct mlx4_cqe *cqe, *dest; + u8 owner_bit; + + /* + * First we need to find the current producer index, so we + * know where to start cleaning from. It doesn't matter if HW + * adds new entries after this loop -- the QP we're worried + * about is already in RESET, so the new entries won't come + * from our QP and therefore don't need to be checked. + */ + for (prod_index = cq->mcq.cons_index; get_sw_cqe(cq, prod_index); ++prod_index) + if (prod_index == cq->mcq.cons_index + cq->ibcq.cqe) + break; + + /* + * Now sweep backwards through the CQ, removing CQ entries + * that match our QP by copying older entries on top of them. + */ + while ((int) --prod_index - (int) cq->mcq.cons_index >= 0) { + cqe = get_cqe(cq, prod_index & cq->ibcq.cqe); + if ((be32_to_cpu(cqe->my_qpn) & 0xffffff) == qpn) { + if (srq && !(cqe->owner_sr_opcode & MLX4_CQE_IS_SEND_MASK)) + mlx4_ib_free_srq_wqe(srq, be16_to_cpu(cqe->wqe_index)); + ++nfreed; + } else if (nfreed) { + dest = get_cqe(cq, (prod_index + nfreed) & cq->ibcq.cqe); + owner_bit = dest->owner_sr_opcode & MLX4_CQE_OWNER_MASK; + memcpy(dest, cqe, sizeof *cqe); + dest->owner_sr_opcode = owner_bit | + (dest->owner_sr_opcode & ~MLX4_CQE_OWNER_MASK); + } + } + + if (nfreed) { + cq->mcq.cons_index += nfreed; + /* + * Make sure update of buffer contents is done before + * updating consumer index. + */ + wmb(); + mlx4_cq_set_ci(&cq->mcq); + } +} + +void mlx4_ib_cq_clean(struct mlx4_ib_cq *cq, u32 qpn, struct mlx4_ib_srq *srq) +{ + spin_lock_irq(&cq->lock); + __mlx4_ib_cq_clean(cq, qpn, srq); + spin_unlock_irq(&cq->lock); +} diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/ib/doorbell.c b/branches/WOF2-3/hw/mlx4/kernel/bus/ib/doorbell.c new file mode 100644 index 00000000..43f26219 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/ib/doorbell.c @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "l2w.h" +#include "mlx4_ib.h" + +struct mlx4_ib_db_pgdir { + struct list_head list; + DECLARE_BITMAP(order0, MLX4_IB_DB_PER_PAGE); + DECLARE_BITMAP(order1, MLX4_IB_DB_PER_PAGE / 2); + unsigned long *bits[2]; + __be32 *db_page; + dma_addr_t db_dma; +}; + +static struct mlx4_ib_db_pgdir *mlx4_ib_alloc_db_pgdir(struct mlx4_ib_dev *dev) +{ + struct mlx4_ib_db_pgdir *pgdir; + + pgdir = kzalloc(sizeof *pgdir, GFP_KERNEL); + if (!pgdir) + return NULL; + + bitmap_fill(pgdir->order1, MLX4_IB_DB_PER_PAGE / 2); + pgdir->bits[0] = pgdir->order0; + pgdir->bits[1] = pgdir->order1; + pgdir->db_page = dma_alloc_coherent(&dev->ib_dev.dma_device, + PAGE_SIZE, &pgdir->db_dma, + GFP_KERNEL); + if (!pgdir->db_page) { + kfree(pgdir); + return NULL; + } + + return pgdir; +} + +static int mlx4_ib_alloc_db_from_pgdir(struct mlx4_ib_db_pgdir *pgdir, + struct mlx4_ib_db *db, int order) +{ + int o; + int i; + + for (o = order; o <= 1; ++o) { + i = find_first_bit(pgdir->bits[o], MLX4_IB_DB_PER_PAGE >> o); + if (i < MLX4_IB_DB_PER_PAGE >> o) + goto found; + } + + return -ENOMEM; + +found: + clear_bit(i, pgdir->bits[o]); + + i <<= o; + + if (o > order) + set_bit(i ^ 1, pgdir->bits[order]); + + db->u.pgdir = pgdir; + db->index = i; + db->db = pgdir->db_page + db->index; + db->dma.da = pgdir->db_dma.da + db->index * 4; + db->order = order; + + return 0; +} + +int mlx4_ib_db_alloc(struct mlx4_ib_dev *dev, struct mlx4_ib_db *db, int order) +{ + struct mlx4_ib_db_pgdir *pgdir; + int ret = 0; + + mutex_lock(&dev->pgdir_mutex); + + list_for_each_entry(pgdir, &dev->pgdir_list, list, struct mlx4_ib_db_pgdir) + if (!mlx4_ib_alloc_db_from_pgdir(pgdir, db, order)) + goto out; + + pgdir = mlx4_ib_alloc_db_pgdir(dev); + if (!pgdir) { + ret = -ENOMEM; + goto out; + } + + list_add(&pgdir->list, &dev->pgdir_list); + + /* This should never fail -- we just allocated an empty page: */ + if (mlx4_ib_alloc_db_from_pgdir(pgdir, db, order)) { + printk(KERN_DEBUG "mlx4_ib_alloc_db_from_pgdir FAILED !\n" ); + } + +out: + + mutex_unlock(&dev->pgdir_mutex); + + return ret; +} + +void mlx4_ib_db_free(struct mlx4_ib_dev *dev, struct mlx4_ib_db *db) +{ + int o; + int i; + + mutex_lock(&dev->pgdir_mutex); + + o = db->order; + i = db->index; + + if (db->order == 0 && test_bit(i ^ 1, db->u.pgdir->order0)) { + clear_bit(i ^ 1, db->u.pgdir->order0); + ++o; + } + + i >>= o; + set_bit(i, db->u.pgdir->bits[o]); + + if (bitmap_full(db->u.pgdir->order1, MLX4_IB_DB_PER_PAGE / 2)) { + dma_free_coherent(&dev->ib_dev.dma_device, PAGE_SIZE, + db->u.pgdir->db_page, db->u.pgdir->db_dma); + list_del(&db->u.pgdir->list); + kfree(db->u.pgdir); + } + + mutex_unlock(&dev->pgdir_mutex); +} + +struct mlx4_ib_user_db_page { + struct list_head list; + struct ib_umem *umem; + u64 user_virt; + int refcnt; +}; + +int mlx4_ib_db_map_user(struct mlx4_ib_ucontext *context, u64 virt, + struct mlx4_ib_db *db) +{ + struct mlx4_ib_user_db_page *page; + int err = 0; + + mutex_lock(&context->db_page_mutex); + + list_for_each_entry(page, &context->db_page_list, list, struct mlx4_ib_user_db_page) + if (page->user_virt == (virt & (u64)PAGE_MASK)) + goto found; + + page = kmalloc(sizeof *page, GFP_KERNEL); + if (!page) { + err = -ENOMEM; + goto out; + } + + page->user_virt = virt & (u64)PAGE_MASK; + page->refcnt = 0; + page->umem = ib_umem_get(&context->ibucontext, virt & (u64)PAGE_MASK, + PAGE_SIZE, 0, FALSE); + if (IS_ERR(page->umem)) { + err = PTR_ERR(page->umem); + kfree(page); + goto out; + } + + list_add(&page->list, &context->db_page_list); + +found: + db->dma = ib_umem_get_dma(page->umem); + db->dma.da += (virt & (u64)(~PAGE_MASK)); + db->u.user_page = page; + ++page->refcnt; + +out: + mutex_unlock(&context->db_page_mutex); + + return err; +} + +void mlx4_ib_db_unmap_user(struct mlx4_ib_ucontext *context, struct mlx4_ib_db *db) +{ + mutex_lock(&context->db_page_mutex); + + if (!--db->u.user_page->refcnt) { + list_del(&db->u.user_page->list); + ib_umem_release(db->u.user_page->umem); + kfree(db->u.user_page); + } + + mutex_unlock(&context->db_page_mutex); +} diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/ib/ib.def b/branches/WOF2-3/hw/mlx4/kernel/bus/ib/ib.def new file mode 100644 index 00000000..a78e9d07 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/ib/ib.def @@ -0,0 +1,11 @@ +LIBRARY mlx4_ib.lib + +EXPORTS +; DllInitialize and DllUnload must be exported for the OS reference counting to +; work, and must be private for the compiler to accept them. +DllInitialize private +DllUnload private + +; main.c +mlx4_ib_init +mlx4_ib_cleanup \ No newline at end of file diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/ib/ib.rc b/branches/WOF2-3/hw/mlx4/kernel/bus/ib/ib.rc new file mode 100644 index 00000000..db7b710d --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/ib/ib.rc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: ibal.rc 1611 2006-08-20 14:48:55Z sleybo $ + */ + + +#include + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef _DEBUG_ +#define VER_FILEDESCRIPTION_STR "MLX4 InfiniBand Specific Services (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "MLX4 InfiniBand Specific Services" +#endif + +#define VER_INTERNALNAME_STR "mlx4_ib.lib" +#define VER_ORIGINALFILENAME_STR "mlx4_ib.lib" + +#include diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/ib/mad.c b/branches/WOF2-3/hw/mlx4/kernel/bus/ib/mad.c new file mode 100644 index 00000000..09f68691 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/ib/mad.c @@ -0,0 +1,267 @@ +/* + * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include "mlx4_ib.h" +#include +#include +#include "cmd.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "mad.tmh" +#endif + + +int mlx4_MAD_IFC(struct mlx4_ib_dev *dev, int ignore_mkey, int ignore_bkey, + int port, ib_wc_t *in_wc, struct ib_grh *in_grh, + void *in_mad, void *response_mad) +{ + struct mlx4_cmd_mailbox *inmailbox, *outmailbox; + u8 *inbox; + int err; + u32 in_modifier = port; + u8 op_modifier = 0; + + inmailbox = mlx4_alloc_cmd_mailbox(dev->dev); + if (IS_ERR(inmailbox)) + return PTR_ERR(inmailbox); + inbox = inmailbox->buf; + + outmailbox = mlx4_alloc_cmd_mailbox(dev->dev); + if (IS_ERR(outmailbox)) { + mlx4_free_cmd_mailbox(dev->dev, inmailbox); + return PTR_ERR(outmailbox); + } + + memcpy(inbox, in_mad, 256); + + /* + * Key check traps can't be generated unless we have in_wc to + * tell us where to send the trap. + */ + if (ignore_mkey || !in_wc) + op_modifier |= 0x1; + if (ignore_bkey || !in_wc) + op_modifier |= 0x2; + + if (in_wc) { + struct { + __be32 my_qpn; + u32 reserved1; + __be32 rqpn; + u8 sl; + u8 g_path; + u16 reserved2[2]; + __be16 pkey; + u32 reserved3[11]; + u8 grh[40]; + } *ext_info; + + memset(inbox + 256, 0, 256); + ext_info = (void*)(inbox + 256); + + ext_info->rqpn = in_wc->recv.ud.remote_qp; + ext_info->sl = in_wc->recv.ud.remote_sl << 4; + ext_info->g_path = in_wc->recv.ud.path_bits | + (in_wc->recv.ud.recv_opt & IB_RECV_OPT_GRH_VALID ? 0x80 : 0); + ext_info->pkey = cpu_to_be16(in_wc->recv.ud.pkey_index); + + if (in_grh) + memcpy(ext_info->grh, in_grh, 40); + + op_modifier |= 0x4; + + in_modifier |= be16_to_cpu(in_wc->recv.ud.remote_lid) << 16; + } + + err = mlx4_cmd_box(dev->dev, inmailbox->dma.da, outmailbox->dma.da, + in_modifier, op_modifier, + MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C); + + if (!err) + memcpy(response_mad, outmailbox->buf, 256); + +// mlx4_dbg( dev->dev, "[MLX4_BUS] mlx4_MAD_IFC : port %d, err %d \n", port, err ); + + mlx4_free_cmd_mailbox(dev->dev, inmailbox); + mlx4_free_cmd_mailbox(dev->dev, outmailbox); + + return err; +} + +static void update_sm_ah(struct mlx4_ib_dev *dev, u8 port_num, u16 lid, u8 sl) +{ + struct ib_ah *new_ah; + struct ib_ah_attr ah_attr; + + if (!dev->send_agent[port_num - 1][0]) + return; + + memset(&ah_attr, 0, sizeof ah_attr); + ah_attr.dlid = lid; + ah_attr.sl = sl; + ah_attr.port_num = port_num; + + new_ah = ib_create_ah(dev->send_agent[port_num - 1][0]->qp->pd, + &ah_attr); + if (IS_ERR(new_ah)) + return; + + spin_lock(&dev->sm_lock); + if (dev->sm_ah[port_num - 1]) + ib_destroy_ah(dev->sm_ah[port_num - 1]); + dev->sm_ah[port_num - 1] = new_ah; + spin_unlock(&dev->sm_lock); +} + +/* + * Snoop SM MADs for port info and P_Key table sets, so we can + * synthesize LID change and P_Key change events. + */ +static void smp_snoop(struct ib_device *ibdev, u8 port_num, struct ib_mad *mad) +{ + struct ib_event event; + + if ((mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED || + mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) && + mad->mad_hdr.method == IB_MGMT_METHOD_SET) { + if (mad->mad_hdr.attr_id == IB_SMP_ATTR_PORT_INFO) { + struct ib_port_info *pinfo = + (struct ib_port_info *) ((struct ib_smp *) mad)->data; + + update_sm_ah(to_mdev(ibdev), port_num, + be16_to_cpu(pinfo->sm_lid), + pinfo->neighbormtu_mastersmsl & 0xf); + + event.device = ibdev; + event.element.port_num = port_num; + + if(pinfo->clientrereg_resv_subnetto & 0x80) + event.event = IB_EVENT_CLIENT_REREGISTER; + else + event.event = IB_EVENT_LID_CHANGE; + + ib_dispatch_event(&event); + } + + if (mad->mad_hdr.attr_id == IB_SMP_ATTR_PKEY_TABLE) { + event.device = ibdev; + event.event = IB_EVENT_PKEY_CHANGE; + event.element.port_num = port_num; + ib_dispatch_event(&event); + } + } +} + +static void node_desc_override(struct ib_device *dev, + struct ib_mad *mad) +{ + if ((mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED || + mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) && + mad->mad_hdr.method == IB_MGMT_METHOD_GET_RESP && + mad->mad_hdr.attr_id == IB_SMP_ATTR_NODE_DESC) { + spin_lock(&to_mdev(dev)->sm_lock); + memcpy(((struct ib_smp *) mad)->data, dev->node_desc, 64); + spin_unlock(&to_mdev(dev)->sm_lock); + } +} + +int mlx4_ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num, + ib_wc_t *in_wc, struct ib_grh *in_grh, + struct ib_mad *in_mad, struct ib_mad *out_mad) +{ + u16 slid; + int err; + + if (mlx4_is_barred(ibdev->dma_device)) + return -EFAULT; + + slid = in_wc ? be16_to_cpu(in_wc->recv.ud.remote_lid) : be16_to_cpu(XIB_LID_PERMISSIVE); + + if (in_mad->mad_hdr.method == IB_MGMT_METHOD_TRAP && slid == 0) { + // we never comes here ! + ASSERT(0); + MLX4_PRINT( TRACE_LEVEL_ERROR ,MLX4_DBG_MAD , + (" Received a trap from HCA, which is unexpected here !\n" )); + // forward_trap(to_mdev(ibdev), port_num, in_mad); + return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED; + } + + if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED || + in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) { + if (in_mad->mad_hdr.method != IB_MGMT_METHOD_GET && + in_mad->mad_hdr.method != IB_MGMT_METHOD_SET && + in_mad->mad_hdr.method != IB_MGMT_METHOD_TRAP_REPRESS) + return IB_MAD_RESULT_SUCCESS; + + /* + * Don't process SMInfo queries or vendor-specific + * MADs -- the SMA can't handle them. + */ + if (in_mad->mad_hdr.attr_id == IB_SMP_ATTR_SM_INFO || + ((in_mad->mad_hdr.attr_id & IB_SMP_ATTR_VENDOR_MASK) == + IB_SMP_ATTR_VENDOR_MASK)) + return IB_MAD_RESULT_SUCCESS; + } else if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_PERF_MGMT || + in_mad->mad_hdr.mgmt_class == IB_MLX_VENDOR_CLASS1 || + in_mad->mad_hdr.mgmt_class == IB_MLX_VENDOR_CLASS2) { + if (in_mad->mad_hdr.method != IB_MGMT_METHOD_GET && + in_mad->mad_hdr.method != IB_MGMT_METHOD_SET) + return IB_MAD_RESULT_SUCCESS; + } else + return IB_MAD_RESULT_SUCCESS; + + err = mlx4_MAD_IFC(to_mdev(ibdev), + mad_flags & IB_MAD_IGNORE_MKEY, + mad_flags & IB_MAD_IGNORE_BKEY, + port_num, in_wc, in_grh, in_mad, out_mad); + if (err) + return IB_MAD_RESULT_FAILURE; + + if (!out_mad->mad_hdr.status) { + smp_snoop(ibdev, port_num, in_mad); + node_desc_override(ibdev, out_mad); + } + + /* set return bit in status of directed route responses */ + if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) + out_mad->mad_hdr.status |= cpu_to_be16(1 << 15); + + if (in_mad->mad_hdr.method == IB_MGMT_METHOD_TRAP_REPRESS) + /* no response for trap repress */ + return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED; + + return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY; +} diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/ib/main.c b/branches/WOF2-3/hw/mlx4/kernel/bus/ib/main.c new file mode 100644 index 00000000..98d38e46 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/ib/main.c @@ -0,0 +1,738 @@ +/* + * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "mlx4_ib.h" +#include "ib_smi.h" +#include "driver.h" +#include "cmd.h" +#include "user.h" +#include "ib_cache.h" +#include "net\mlx4.h" + +#if 1//WORKAROUND_POLL_EQ +void mlx4_poll_eq(struct ib_device *dev, BOOLEAN bStart); +#endif + + +static void init_query_mad(struct ib_smp *mad) +{ + mad->base_version = 1; + mad->mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED; + mad->class_version = 1; + mad->method = IB_MGMT_METHOD_GET; +} + +static int mlx4_ib_query_device(struct ib_device *ibdev, + struct ib_device_attr *props) +{ + struct mlx4_ib_dev *dev = to_mdev(ibdev); + struct ib_smp *in_mad = NULL; + struct ib_smp *out_mad = NULL; + int err = -ENOMEM; + + if (mlx4_is_barred(ibdev->dma_device)) + return -EFAULT; + + in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL); + out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL); + if (!in_mad || !out_mad) + goto out; + + init_query_mad(in_mad); + in_mad->attr_id = IB_SMP_ATTR_NODE_INFO; + + err = mlx4_MAD_IFC(dev, 1, 1, 1, NULL, NULL, in_mad, out_mad); + if (err) + goto out; + + memset(props, 0, sizeof *props); + + props->fw_ver = dev->dev->caps.fw_ver; + props->device_cap_flags = IB_DEVICE_CHANGE_PHY_PORT | + IB_DEVICE_PORT_ACTIVE_EVENT | + IB_DEVICE_SYS_IMAGE_GUID | + IB_DEVICE_RC_RNR_NAK_GEN; + if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_BAD_PKEY_CNTR) + props->device_cap_flags |= IB_DEVICE_BAD_PKEY_CNTR; + if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_BAD_QKEY_CNTR) + props->device_cap_flags |= IB_DEVICE_BAD_QKEY_CNTR; + if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_APM) + props->device_cap_flags |= IB_DEVICE_AUTO_PATH_MIG; + if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_UD_AV_PORT) + props->device_cap_flags |= IB_DEVICE_UD_AV_PORT_ENFORCE; + if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_IPOIB_CSUM) + props->device_cap_flags |= IB_DEVICE_IPOIB_CSUM; + if (dev->dev->caps.max_gso_sz) + props->device_cap_flags |= IB_DEVICE_UD_TSO; + props->vendor_id = be32_to_cpup((__be32 *) (out_mad->data + 36)) & + 0xffffff; + props->vendor_part_id = be16_to_cpup((__be16 *) (out_mad->data + 30)); + props->hw_ver = be32_to_cpup((__be32 *) (out_mad->data + 32)); + memcpy(&props->sys_image_guid, out_mad->data + 4, 8); + + props->max_mr_size = ~0ull; + props->page_size_cap = dev->dev->caps.page_size_cap; + props->max_qp = dev->dev->caps.num_qps - dev->dev->caps.total_reserved_qps; + props->max_qp_wr = dev->dev->caps.max_wqes - MLX4_IB_SQ_MAX_SPARE; + + props->max_sge = min(dev->dev->caps.max_sq_sg, + dev->dev->caps.max_rq_sg); + props->max_cq = dev->dev->caps.num_cqs - dev->dev->caps.reserved_cqs; + props->max_cqe = dev->dev->caps.max_cqes; + props->max_mr = dev->dev->caps.num_mpts - dev->dev->caps.reserved_mrws; + props->max_pd = dev->dev->caps.num_pds - dev->dev->caps.reserved_pds; + props->max_qp_rd_atom = dev->dev->caps.max_qp_dest_rdma; + props->max_qp_init_rd_atom = dev->dev->caps.max_qp_init_rdma; + props->max_res_rd_atom = props->max_qp_rd_atom * props->max_qp; + props->max_srq = dev->dev->caps.num_srqs - dev->dev->caps.reserved_srqs; + props->max_srq_wr = dev->dev->caps.max_srq_wqes - 1; + props->max_srq_sge = dev->dev->caps.max_srq_sge; + props->local_ca_ack_delay = (u8)dev->dev->caps.local_ca_ack_delay; + props->atomic_cap = dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_ATOMIC ? + IB_ATOMIC_HCA : IB_ATOMIC_NON; + props->max_pkeys = (u16)dev->dev->caps.pkey_table_len[1]; + props->max_mcast_grp = dev->dev->caps.num_mgms + dev->dev->caps.num_amgms; + props->max_mcast_qp_attach = dev->dev->caps.num_qp_per_mgm; + props->max_total_mcast_qp_attach = props->max_mcast_qp_attach * + props->max_mcast_grp; + props->max_map_per_fmr = (1 << (32 - ilog2(dev->dev->caps.num_mpts))) - 1; + +out: + kfree(in_mad); + kfree(out_mad); + + return err; +} + + +static enum rdma_transport_type +mlx4_ib_port_get_transport(struct ib_device *device, u8 port_num) +{ + struct mlx4_dev *dev = to_mdev(device)->dev; + + return dev->caps.port_mask & (1 << (port_num - 1)) ? + RDMA_TRANSPORT_IB : RDMA_TRANSPORT_RDMAOE; +} + + +static void ib_link_query_port(struct ib_device *ibdev, u8 port, + struct ib_port_attr *props, + struct ib_smp *out_mad) +{ + props->lid = be16_to_cpup((__be16 *) (out_mad->data + 16)); + props->lmc = out_mad->data[34] & 0x7; + props->sm_lid = be16_to_cpup((__be16 *) (out_mad->data + 18)); + props->sm_sl = out_mad->data[36] & 0xf; + props->state = out_mad->data[32] & 0xf; + props->phys_state = out_mad->data[33] >> 4; + props->port_cap_flags = be32_to_cpup((__be32 *) (out_mad->data + 20)); + props->gid_tbl_len = to_mdev(ibdev)->dev->caps.gid_table_len[port]; + props->max_msg_sz = to_mdev(ibdev)->dev->caps.max_msg_sz; + props->pkey_tbl_len = (u16)to_mdev(ibdev)->dev->caps.pkey_table_len[port]; + props->bad_pkey_cntr = be16_to_cpup((__be16 *) (out_mad->data + 46)); + props->qkey_viol_cntr = be16_to_cpup((__be16 *) (out_mad->data + 48)); + props->active_width = out_mad->data[31] & 0xf; + props->active_speed = out_mad->data[35] >> 4; + props->max_mtu = out_mad->data[41] & 0xf; + props->active_mtu = out_mad->data[36] >> 4; + props->subnet_timeout = out_mad->data[51] & 0x1f; + props->max_vl_num = out_mad->data[37] >> 4; + props->init_type_reply = out_mad->data[41] >> 4; + props->transport= RDMA_TRANSPORT_IB; +} + +static void eth_link_query_port(struct ib_device *ibdev, u8 port, + struct ib_port_attr *props, + struct ib_smp *out_mad) +{ + + props->port_cap_flags = be32_to_cpup((__be32 *) (out_mad->data + 20)); + props->gid_tbl_len = to_mdev(ibdev)->dev->caps.gid_table_len[port]; + props->max_msg_sz = to_mdev(ibdev)->dev->caps.max_msg_sz; + props->pkey_tbl_len = (u16)to_mdev(ibdev)->dev->caps.pkey_table_len[port]; + props->bad_pkey_cntr = be16_to_cpup((__be16 *) (out_mad->data + 46)); + props->qkey_viol_cntr = be16_to_cpup((__be16 *) (out_mad->data + 48)); + props->active_width = out_mad->data[31] & 0xf; + props->active_speed = out_mad->data[35] >> 4; + props->max_mtu = out_mad->data[41] & 0xf; + //props->active_mtu = rdmaoe->mtu[port - 1]; + props->active_mtu = 1500; //jyang:hardcoded + props->subnet_timeout = out_mad->data[51] & 0x1f; + props->max_vl_num = out_mad->data[37] >> 4; + props->init_type_reply = out_mad->data[41] >> 4; + props->transport= RDMA_TRANSPORT_RDMAOE; + + //props->state = netif_running(ndev) && netif_oper_up(ndev) ? + // IB_PORT_ACTIVE : IB_PORT_DOWN; + props->state = IB_PORT_ACTIVE; //jyang: just hardcoded it now + props->phys_state = props->state; +} + + + +static int mlx4_ib_query_port(struct ib_device *ibdev, u8 port, + struct ib_port_attr *props) +{ + struct ib_smp *in_mad = NULL; + struct ib_smp *out_mad = NULL; + int err = -ENOMEM; + + in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL); + out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL); + if (!in_mad || !out_mad) + goto out; + + memset(props, 0, sizeof *props); + + init_query_mad(in_mad); + in_mad->attr_id = IB_SMP_ATTR_PORT_INFO; + in_mad->attr_mod = cpu_to_be32(port); + + err = mlx4_MAD_IFC(to_mdev(ibdev), 1, 1, port, NULL, NULL, in_mad, out_mad); + if (err) + goto out; + + mlx4_ib_port_get_transport(ibdev, port) == RDMA_TRANSPORT_IB ? + ib_link_query_port(ibdev, port, props, out_mad) : + eth_link_query_port(ibdev, port, props, out_mad); + +out: + kfree(in_mad); + kfree(out_mad); + + return err; +} + +static int mlx4_ib_query_gid_chunk(struct ib_device *ibdev, u8 port, int index, + union ib_gid gid[8], int size) +{ + struct ib_smp *in_mad = NULL; + struct ib_smp *out_mad = NULL; + __be64 subnet_prefix; + int err = -ENOMEM; + + if (mlx4_is_barred(ibdev->dma_device)) + return -EFAULT; + + in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL); + out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL); + if (!in_mad || !out_mad) + goto out; + + init_query_mad(in_mad); + in_mad->attr_id = IB_SMP_ATTR_PORT_INFO; + in_mad->attr_mod = cpu_to_be32(port); + + err = mlx4_MAD_IFC(to_mdev(ibdev), 1, 1, port, NULL, NULL, in_mad, out_mad); + if (err) + goto out; + + memcpy(&subnet_prefix, out_mad->data + 8, 8); + + init_query_mad(in_mad); + in_mad->attr_id = IB_SMP_ATTR_GUID_INFO; + in_mad->attr_mod = cpu_to_be32(index / 8); + + err = mlx4_MAD_IFC(to_mdev(ibdev), 1, 1, port, NULL, NULL, in_mad, out_mad); + if (err) + goto out; + + { // copy the results + int i; + __be64 *guid = (__be64 *)out_mad->data; + for (i=0; idma_device)) + return -EFAULT; + + in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL); + out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL); + if (!in_mad || !out_mad) + goto out; + + init_query_mad(in_mad); + in_mad->attr_id = IB_SMP_ATTR_PKEY_TABLE; + in_mad->attr_mod = cpu_to_be32(index / 32); + + err = mlx4_MAD_IFC(to_mdev(ibdev), 1, 1, port, NULL, NULL, in_mad, out_mad); + if (err) + goto out; + + { // copy the results + int i; + __be16 *pkey_chunk = (__be16 *)out_mad->data; + for (i=0; idma_device)) + return -EFAULT; + + if (mask & ~IB_DEVICE_MODIFY_NODE_DESC) + return -EOPNOTSUPP; + + if (mask & IB_DEVICE_MODIFY_NODE_DESC) { + spin_lock(&to_mdev(ibdev)->sm_lock); + memcpy(ibdev->node_desc, props->node_desc, 64); + spin_unlock(&to_mdev(ibdev)->sm_lock); + } + + return 0; +} +static int mlx4_ib_modify_port(struct ib_device *ibdev, u8 port, int mask, + struct ib_port_modify *props) +{ + struct ib_port_attr attr; + u32 cap_mask; + int err; + + if (mlx4_is_barred(ibdev->dma_device)) + return -EFAULT; + + mutex_lock(&to_mdev(ibdev)->cap_mask_mutex); + + err = mlx4_ib_query_port(ibdev, port, &attr); + if (err) + goto out; + + cap_mask = (attr.port_cap_flags | props->set_port_cap_mask) & + ~props->clr_port_cap_mask; + + err = mlx4_SET_PORT(to_mdev(ibdev)->dev, port, + !!(mask & IB_PORT_RESET_QKEY_CNTR), + cap_mask); + +out: + mutex_unlock(&to_mdev(ibdev)->cap_mask_mutex); + return err; +} + +static struct ib_ucontext *mlx4_ib_alloc_ucontext(struct ib_device *ibdev, + struct ib_udata *udata) +{ + struct mlx4_ib_dev *dev = to_mdev(ibdev); + struct mlx4_ib_ucontext *context; + struct mlx4_ib_alloc_ucontext_resp resp; + int err; + + if (mlx4_is_barred(ibdev->dma_device)) + return ERR_PTR(-EFAULT); + + resp.qp_tab_size = dev->dev->caps.num_qps; + resp.bf_reg_size = (__u16)dev->dev->caps.bf_reg_size; + resp.bf_regs_per_page = (__u16)dev->dev->caps.bf_regs_per_page; + + context = kzalloc(sizeof *context, GFP_KERNEL); + if (!context) + return ERR_PTR(-ENOMEM); + + if (mlx4_is_livefish(to_mdev(ibdev)->dev)) + goto done; + + err = mlx4_uar_alloc(to_mdev(ibdev)->dev, &context->uar); + if (err) { + kfree(context); + return ERR_PTR(err); + } + + INIT_LIST_HEAD(&context->db_page_list); + mutex_init(&context->db_page_mutex); + +done: + err = ib_copy_to_udata(udata, &resp, sizeof resp); + if (err) { + mlx4_uar_free(to_mdev(ibdev)->dev, &context->uar); + kfree(context); + return ERR_PTR(-EFAULT); + } + + return &context->ibucontext; +} + +static int mlx4_ib_dealloc_ucontext(struct ib_ucontext *ibcontext) +{ + struct mlx4_ib_ucontext *context = to_mucontext(ibcontext); + + if (!mlx4_is_livefish(to_mdev(ibcontext->device)->dev)) + mlx4_uar_free(to_mdev(ibcontext->device)->dev, &context->uar); + kfree(context); + + return 0; +} + +#if 0 + // TODO: not clear, what is the usage +static int mlx4_ib_mmap(struct ib_ucontext *context, struct vm_area_struct *vma) +{ + struct mlx4_ib_dev *dev = to_mdev(context->device); + + if (vma->vm_end - vma->vm_start != PAGE_SIZE) + return -EINVAL; + + if (vma->vm_pgoff == 0) { + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + + if (io_remap_pfn_range(vma, vma->vm_start, + to_mucontext(context)->uar.pfn, + PAGE_SIZE, vma->vm_page_prot)) + return -EAGAIN; + } else if (vma->vm_pgoff == 1 && dev->dev->caps.bf_reg_size != 0) { + /* FIXME want pgprot_writecombine() for BlueFlame pages */ + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + + if (io_remap_pfn_range(vma, vma->vm_start, + to_mucontext(context)->uar.pfn + + dev->dev->caps.num_uars, + PAGE_SIZE, vma->vm_page_prot)) + return -EAGAIN; + } else + return -EINVAL; + + return 0; +} +#endif + +static struct ib_pd *mlx4_ib_alloc_pd(struct ib_device *ibdev, + struct ib_ucontext *context, + struct ib_udata *udata) +{ + struct mlx4_ib_pd *pd; + int err; + + if (mlx4_is_barred(ibdev->dma_device)) + return ERR_PTR(-EFAULT); + + pd = kmalloc(sizeof *pd, GFP_KERNEL); + if (!pd) + return ERR_PTR(-ENOMEM); + + if (mlx4_is_livefish(to_mdev(ibdev)->dev)) + goto done; + + err = mlx4_pd_alloc(to_mdev(ibdev)->dev, &pd->pdn); + if (err) { + kfree(pd); + return ERR_PTR(err); + } + + if (context) + if (ib_copy_to_udata(udata, &pd->pdn, sizeof (__u32))) { + mlx4_pd_free(to_mdev(ibdev)->dev, pd->pdn); + kfree(pd); + return ERR_PTR(-EFAULT); + } + +done: + return &pd->ibpd; +} + +static int mlx4_ib_dealloc_pd(struct ib_pd *pd) +{ + if (!mlx4_is_livefish(to_mdev(pd->device)->dev)) + mlx4_pd_free(to_mdev(pd->device)->dev, to_mpd(pd)->pdn); + kfree(pd); + + return 0; +} + +static int mlx4_ib_mcg_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) +{ + UNUSED_PARAM(lid); + if (mlx4_is_barred(ibqp->device->dma_device)) + return -EFAULT; + return mlx4_multicast_attach(to_mdev(ibqp->device)->dev, + &to_mqp(ibqp)->mqp, gid->raw); +} + +static int mlx4_ib_mcg_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) +{ + UNUSED_PARAM(lid); + if (mlx4_is_barred(ibqp->device->dma_device)) + return -EFAULT; + return mlx4_multicast_detach(to_mdev(ibqp->device)->dev, + &to_mqp(ibqp)->mqp, gid->raw); +} + +static int init_node_data(struct mlx4_ib_dev *dev) +{ + struct ib_smp *in_mad = NULL; + struct ib_smp *out_mad = NULL; + int err = -ENOMEM; + + in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL); + out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL); + if (!in_mad || !out_mad) + goto out; + + init_query_mad(in_mad); + in_mad->attr_id = IB_SMP_ATTR_NODE_DESC; + + err = mlx4_MAD_IFC(dev, 1, 1, 1, NULL, NULL, in_mad, out_mad); + if (err) + goto out; + + dev->dev->rev_id = be32_to_cpup((__be32 *) (out_mad->data + 32)); + memcpy(dev->ib_dev.node_desc, out_mad->data, 64); + + in_mad->attr_id = IB_SMP_ATTR_NODE_INFO; + + err = mlx4_MAD_IFC(dev, 1, 1, 1, NULL, NULL, in_mad, out_mad); + if (err) + goto out; + + memcpy(&dev->ib_dev.node_guid, out_mad->data + 12, 8); + +out: + kfree(in_mad); + kfree(out_mad); + return err; +} + +static void *mlx4_ib_add(struct mlx4_dev *dev) +{ + struct mlx4_ib_dev *ibdev; + + ibdev = (struct mlx4_ib_dev *) ib_alloc_device(sizeof *ibdev); + if (!ibdev) { + dev_err(&dev->pdev->dev, "Device struct alloc failed\n"); + return NULL; + } + + MLX4_INIT_DOORBELL_LOCK(&ibdev->uar_lock); + + INIT_LIST_HEAD(&ibdev->pgdir_list); + mutex_init(&ibdev->pgdir_mutex); + + ibdev->dev = dev; + + strlcpy(ibdev->ib_dev.name, "mlx4_%d", IB_DEVICE_NAME_MAX); + ibdev->ib_dev.node_type = RDMA_NODE_IB_CA; + ibdev->ib_dev.phys_port_cnt = (u8)mlx4_count_ib_ports(dev); + ibdev->ib_dev.num_comp_vectors = 1; + ibdev->ib_dev.dma_device = dev->pdev->dev; + + ibdev->ib_dev.uverbs_abi_ver = MLX4_IB_UVERBS_ABI_VERSION; + ibdev->ib_dev.query_device = mlx4_ib_query_device; + ibdev->ib_dev.query_port = mlx4_ib_query_port; + ibdev->ib_dev.get_port_transport = mlx4_ib_port_get_transport; + ibdev->ib_dev.query_gid_chunk = mlx4_ib_query_gid_chunk; + ibdev->ib_dev.query_pkey_chunk = mlx4_ib_query_pkey_chunk; + ibdev->ib_dev.modify_device = mlx4_ib_modify_device; + ibdev->ib_dev.modify_port = mlx4_ib_modify_port; + ibdev->ib_dev.alloc_ucontext = mlx4_ib_alloc_ucontext; + ibdev->ib_dev.dealloc_ucontext = mlx4_ib_dealloc_ucontext; + ibdev->ib_dev.mmap = NULL; /* mlx4_ib_mmap; */ + ibdev->ib_dev.alloc_pd = mlx4_ib_alloc_pd; + ibdev->ib_dev.dealloc_pd = mlx4_ib_dealloc_pd; + ibdev->ib_dev.create_ah = mlx4_ib_create_ah; + ibdev->ib_dev.query_ah = mlx4_ib_query_ah; + ibdev->ib_dev.modify_ah = mlx4_ib_modify_ah; + ibdev->ib_dev.destroy_ah = mlx4_ib_destroy_ah; + ibdev->ib_dev.create_srq = mlx4_ib_create_srq; + ibdev->ib_dev.modify_srq = mlx4_ib_modify_srq; + ibdev->ib_dev.query_srq = mlx4_ib_query_srq; + ibdev->ib_dev.destroy_srq = mlx4_ib_destroy_srq; + ibdev->ib_dev.post_srq_recv = mlx4_ib_post_srq_recv; + ibdev->ib_dev.create_qp = mlx4_ib_create_qp; + ibdev->ib_dev.modify_qp = mlx4_ib_modify_qp; + ibdev->ib_dev.query_qp = mlx4_ib_query_qp; + ibdev->ib_dev.destroy_qp = mlx4_ib_destroy_qp; + ibdev->ib_dev.post_send = mlx4_ib_post_send; + ibdev->ib_dev.post_recv = mlx4_ib_post_recv; + ibdev->ib_dev.create_cq = mlx4_ib_create_cq; + ibdev->ib_dev.modify_cq = mlx4_ib_modify_cq; + ibdev->ib_dev.destroy_cq = mlx4_ib_destroy_cq; + ibdev->ib_dev.poll_cq = mlx4_ib_poll_cq; + ibdev->ib_dev.req_notify_cq = mlx4_ib_arm_cq; + ibdev->ib_dev.get_dma_mr = mlx4_ib_get_dma_mr; + ibdev->ib_dev.reg_user_mr = mlx4_ib_reg_user_mr; + ibdev->ib_dev.dereg_mr = mlx4_ib_dereg_mr; + ibdev->ib_dev.attach_mcast = mlx4_ib_mcg_attach; + ibdev->ib_dev.detach_mcast = mlx4_ib_mcg_detach; + ibdev->ib_dev.process_mad = mlx4_ib_process_mad; + + ibdev->ib_dev.alloc_fmr = mlx4_ib_fmr_alloc; + ibdev->ib_dev.map_phys_fmr = mlx4_ib_map_phys_fmr; + ibdev->ib_dev.unmap_fmr = mlx4_ib_unmap_fmr; + ibdev->ib_dev.dealloc_fmr = mlx4_ib_fmr_dealloc; + ibdev->ib_dev.x.find_cached_gid = ib_find_cached_gid; + ibdev->ib_dev.x.find_cached_pkey = ib_find_cached_pkey; + ibdev->ib_dev.x.get_cached_gid = ib_get_cached_gid; + ibdev->ib_dev.x.get_cached_pkey = ib_get_cached_pkey; + ibdev->ib_dev.x.register_ev_cb = mlx4_reset_cb_register; + ibdev->ib_dev.x.unregister_ev_cb = mlx4_reset_cb_unregister; +#if 1//WORKAROUND_POLL_EQ + ibdev->ib_dev.x.poll_eq = mlx4_poll_eq; +#endif + if (mlx4_is_livefish(ibdev->dev)) { + if (ib_register_device(&ibdev->ib_dev)) + goto err_dealloc; + return ibdev; + } + + if (mlx4_pd_alloc(dev, &ibdev->priv_pdn)) + goto err_dealloc; + + if (mlx4_uar_alloc(dev, &ibdev->priv_uar)) + goto err_pd; + + ibdev->uar_map = ioremap((u64)ibdev->priv_uar.pfn << PAGE_SHIFT, PAGE_SIZE); + if (!ibdev->uar_map) + goto err_uar; + + if (init_node_data(ibdev)) + goto err_map; + + spin_lock_init(&ibdev->sm_lock); + mutex_init(&ibdev->cap_mask_mutex); + + if (ib_register_device(&ibdev->ib_dev)) + goto err_map; + + mlx4_dbg(ibdev->dev, "MLX4_BUS: IB interface is ADDED ! \n"); + + return ibdev; + +err_map: + iounmap(ibdev->uar_map, PAGE_SIZE); + +err_uar: + mlx4_uar_free(dev, &ibdev->priv_uar); + +err_pd: + mlx4_pd_free(dev, ibdev->priv_pdn); + +err_dealloc: + ibdev->ib_dev.reg_state = IB_DEV_UNINITIALIZED; + ib_dealloc_device(&ibdev->ib_dev); + + return NULL; +} + +static void mlx4_ib_remove(struct mlx4_dev *dev, void *ibdev_ptr) +{ + struct mlx4_ib_dev *ibdev = ibdev_ptr; + int p; + + if (mlx4_is_livefish(ibdev->dev)) { + ib_unregister_device(&ibdev->ib_dev); + goto dealloc_dev; + } + + ib_unregister_device(&ibdev->ib_dev); + + for (p = 1; p <= dev->caps.num_ports; ++p) + mlx4_CLOSE_PORT(dev, p); + + iounmap(ibdev->uar_map,PAGE_SIZE); + mlx4_uar_free(dev, &ibdev->priv_uar); + mlx4_pd_free(dev, ibdev->priv_pdn); +dealloc_dev: + mlx4_dbg(ibdev->dev, "MLX4_BUS: IB interface is REMOVED ! \n"); + ibdev->ib_dev.reg_state = IB_DEV_UNINITIALIZED; + ib_dealloc_device(&ibdev->ib_dev); +} + +static void mlx4_ib_event(struct mlx4_dev *dev, void *ibdev_ptr, + enum mlx4_dev_event event, int subtype, + int port) +{ + struct ib_event ibev; + + UNUSED_PARAM(dev); + + switch (event) { + case MLX4_EVENT_TYPE_PORT_CHANGE: + ibev.event = subtype == MLX4_PORT_CHANGE_SUBTYPE_ACTIVE ? + IB_EVENT_PORT_ACTIVE : IB_EVENT_PORT_ERR; + break; + + case MLX4_EVENT_TYPE_LOCAL_CATAS_ERROR: + ibev.event = IB_EVENT_DEVICE_FATAL; + break; + + default: + return; + } + + ibev.device = ibdev_ptr; + ibev.element.port_num = (u8)port; + + ib_dispatch_event(&ibev); +} + +static struct mlx4_interface mlx4_ib_interface = { + mlx4_ib_add, /* add */ + mlx4_ib_remove, /* remove */ + mlx4_ib_event, /* event */ + NULL, NULL /* list */ +}; + +int __init mlx4_ib_init(void) +{ + mlx4_ib_qp_init(); + return mlx4_register_interface(&mlx4_ib_interface); +} + +void __exit mlx4_ib_cleanup(void) +{ + mlx4_unregister_interface(&mlx4_ib_interface); +} + + + diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/ib/makefile b/branches/WOF2-3/hw/mlx4/kernel/bus/ib/makefile new file mode 100644 index 00000000..d4938551 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/ib/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\..\..\inc\openib.def diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/ib/mlx4_ib.h b/branches/WOF2-3/hw/mlx4/kernel/bus/ib/mlx4_ib.h new file mode 100644 index 00000000..c2a2cc80 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/ib/mlx4_ib.h @@ -0,0 +1,357 @@ +/* + * Copyright (c) 2006, 2007 Cisco Systems. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef MLX4_IB_H +#define MLX4_IB_H + +#include "l2w.h" + +#include "ib_verbs.h" +// TODO: do we need this file +//#include "ib_umem.h" + +#include "device.h" +#include "doorbell.h" +#include "ib_pack.h" + +enum { + MLX4_IB_DB_PER_PAGE = PAGE_SIZE / 4 +}; + +enum { + MLX4_IB_SQ_MIN_WQE_SHIFT = 6 +}; + +#define MLX4_IB_SQ_HEADROOM(shift) ((2048 >> (shift)) + 1) +#define MLX4_IB_SQ_MAX_SPARE (MLX4_IB_SQ_HEADROOM(MLX4_IB_SQ_MIN_WQE_SHIFT)) + +struct mlx4_ib_db_pgdir; +struct mlx4_ib_user_db_page; + +struct mlx4_ib_db { + __be32 *db; + union { + struct mlx4_ib_db_pgdir *pgdir; + struct mlx4_ib_user_db_page *user_page; + } u; + dma_addr_t dma; + int index; + int order; +}; + +struct mlx4_ib_ucontext { + struct ib_ucontext ibucontext; + struct mlx4_uar uar; + struct list_head db_page_list; + struct mutex db_page_mutex; +}; + +struct mlx4_ib_pd { + struct ib_pd ibpd; + u32 pdn; +}; + +struct mlx4_ib_cq_buf { + struct mlx4_buf buf; + struct mlx4_mtt mtt; +}; + +struct mlx4_ib_cq { + struct ib_cq ibcq; + struct mlx4_cq mcq; + struct mlx4_ib_cq_buf buf; + struct mlx4_ib_db db; + spinlock_t lock; + struct ib_umem *umem; +}; + +struct mlx4_ib_mr { + struct ib_mr ibmr; + struct mlx4_mr mmr; + struct ib_umem *umem; +}; + +struct mlx4_ib_fmr { + struct ib_fmr ibfmr; + struct mlx4_fmr mfmr; +}; + +struct mlx4_ib_wq { + u64 *wrid; + spinlock_t lock; + int wqe_cnt; + int max_post; + int max_gs; + int offset; + int wqe_shift; + unsigned head; + unsigned tail; +}; + +enum mlx4_ib_qp_flags { + MLX4_IB_QP_LSO= 1 << 0 +}; + + +struct mlx4_ib_qp { + struct ib_qp ibqp; + struct mlx4_qp mqp; + struct mlx4_buf buf; + + struct mlx4_ib_db db; + struct mlx4_ib_wq rq; + + u32 doorbell_qpn; + __be32 sq_signal_bits; + int sq_spare_wqes; + struct mlx4_ib_wq sq; + + struct ib_umem *umem; + struct mlx4_mtt mtt; + int buf_size; + struct mutex mutex; + u32 flags; + u8 port; + u8 alt_port; + u8 atomic_rd_en; + u8 resp_depth; + u8 sq_no_prefetch; + u8 state; +}; + +struct mlx4_ib_srq { + struct ib_srq ibsrq; + struct mlx4_srq msrq; + struct mlx4_buf buf; + struct mlx4_ib_db db; + u64 *wrid; + spinlock_t lock; + int head; + int tail; + u16 wqe_ctr; + struct ib_umem *umem; + struct mlx4_mtt mtt; + struct mutex mutex; +}; + +struct mlx4_ib_ah { + struct ib_ah ibah; + union mlx4_ext_av av; +}; + + +enum { + /* + * Largest possible UD header: send with GRH and immediate data. + */ + MLX4_IB_UD_HEADER_SIZE = 76 +}; + +struct mlx4_ib_sqp { + struct mlx4_ib_qp qp; + int pkey_index; + u32 qkey; + u32 send_psn; + union { + struct ib_ud_header ib; + struct eth_ud_header eth; + } hdr; + u8 header_buf[MLX4_IB_UD_HEADER_SIZE]; +}; + +struct mlx4_ib_dev { + struct ib_device ib_dev; + struct mlx4_dev *dev; + void __iomem *uar_map; + + struct list_head pgdir_list; + struct mutex pgdir_mutex; + + struct mlx4_uar priv_uar; + u32 priv_pdn; + + struct ib_mad_agent *send_agent[MLX4_MAX_PORTS][2]; + struct ib_ah *sm_ah[MLX4_MAX_PORTS]; + spinlock_t sm_lock; + + struct mutex cap_mask_mutex; + +#ifndef _WIN64 + spinlock_t uar_lock; +#endif +}; + +static inline struct mlx4_ib_dev *to_mdev(struct ib_device *ibdev) +{ + return container_of(ibdev, struct mlx4_ib_dev, ib_dev); +} + +static inline struct mlx4_ib_ucontext *to_mucontext(struct ib_ucontext *ibucontext) +{ + return container_of(ibucontext, struct mlx4_ib_ucontext, ibucontext); +} + +static inline struct mlx4_ib_pd *to_mpd(struct ib_pd *ibpd) +{ + return container_of(ibpd, struct mlx4_ib_pd, ibpd); +} + +static inline struct mlx4_ib_cq *to_mcq(struct ib_cq *ibcq) +{ + return container_of(ibcq, struct mlx4_ib_cq, ibcq); +} + +static inline struct mlx4_ib_cq *to_mibcq(struct mlx4_cq *mcq) +{ + return container_of(mcq, struct mlx4_ib_cq, mcq); +} + +static inline struct mlx4_ib_mr *to_mmr(struct ib_mr *ibmr) +{ + return container_of(ibmr, struct mlx4_ib_mr, ibmr); +} + +static inline struct mlx4_ib_fmr *to_mfmr(struct ib_fmr *ibfmr) +{ + return container_of(ibfmr, struct mlx4_ib_fmr, ibfmr); +} +static inline struct mlx4_ib_qp *to_mqp(struct ib_qp *ibqp) +{ + return container_of(ibqp, struct mlx4_ib_qp, ibqp); +} + +static inline struct mlx4_ib_qp *to_mibqp(struct mlx4_qp *mqp) +{ + return container_of(mqp, struct mlx4_ib_qp, mqp); +} + +static inline struct mlx4_ib_srq *to_msrq(struct ib_srq *ibsrq) +{ + return container_of(ibsrq, struct mlx4_ib_srq, ibsrq); +} + +static inline struct mlx4_ib_srq *to_mibsrq(struct mlx4_srq *msrq) +{ + return container_of(msrq, struct mlx4_ib_srq, msrq); +} + +static inline struct mlx4_ib_ah *to_mah(struct ib_ah *ibah) +{ + return container_of(ibah, struct mlx4_ib_ah, ibah); +} + +int mlx4_ib_db_alloc(struct mlx4_ib_dev *dev, struct mlx4_ib_db *db, int order); +void mlx4_ib_db_free(struct mlx4_ib_dev *dev, struct mlx4_ib_db *db); +int mlx4_ib_db_map_user(struct mlx4_ib_ucontext *context, u64 virt, + struct mlx4_ib_db *db); +void mlx4_ib_db_unmap_user(struct mlx4_ib_ucontext *context, struct mlx4_ib_db *db); + +struct ib_mr *mlx4_ib_get_dma_mr(struct ib_pd *pd, int acc); +int mlx4_ib_umem_write_mtt(struct mlx4_ib_dev *dev, struct mlx4_mtt *mtt, + struct ib_umem *umem); +struct ib_mr *mlx4_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, + u64 virt_addr, int access_flags, + struct ib_udata *udata); +int mlx4_ib_dereg_mr(struct ib_mr *mr); + +int mlx4_ib_modify_cq(struct ib_cq *cq, u16 cq_count, u16 cq_period); +struct ib_cq *mlx4_ib_create_cq(struct ib_device *ibdev, int entries, int vector, + struct ib_ucontext *context, + struct ib_udata *udata); +int mlx4_ib_destroy_cq(struct ib_cq *cq); +int mlx4_ib_poll_cq(struct ib_cq *ibcq, ib_wc_t** const pp_free_wclist, + ib_wc_t** const pp_done_wclist ); +int mlx4_ib_arm_cq(struct ib_cq *cq, enum ib_cq_notify_flags flags); +void __mlx4_ib_cq_clean(struct mlx4_ib_cq *cq, u32 qpn, struct mlx4_ib_srq *srq); +void mlx4_ib_cq_clean(struct mlx4_ib_cq *cq, u32 qpn, struct mlx4_ib_srq *srq); + +struct ib_ah *mlx4_ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr); +int mlx4_ib_query_ah(struct ib_ah *ibah, struct ib_ah_attr *ah_attr); +int mlx4_ib_modify_ah( struct ib_ah *ibah, struct ib_ah_attr *ah_attr ); +int mlx4_ib_destroy_ah(struct ib_ah *ah); + +struct ib_srq *mlx4_ib_create_srq(struct ib_pd *pd, + struct ib_srq_init_attr *init_attr, + struct ib_udata *udata); +int mlx4_ib_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr, + enum ib_srq_attr_mask attr_mask, struct ib_udata *udata); +int mlx4_ib_query_srq(struct ib_srq *srq, struct ib_srq_attr *srq_attr); +int mlx4_ib_destroy_srq(struct ib_srq *srq); +void mlx4_ib_free_srq_wqe(struct mlx4_ib_srq *srq, int wqe_index); +int mlx4_ib_post_srq_recv(struct ib_srq *ibsrq, ib_recv_wr_t *wr, + ib_recv_wr_t **bad_wr); + +struct ib_qp *mlx4_ib_create_qp(struct ib_pd *pd, + struct ib_qp_init_attr *init_attr, + struct ib_udata *udata); +int mlx4_ib_destroy_qp(struct ib_qp *qp); +int mlx4_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, + int attr_mask, struct ib_udata *udata); +int mlx4_ib_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr_mask, + struct ib_qp_init_attr *qp_init_attr); +int mlx4_ib_post_send(struct ib_qp *ibqp, ib_send_wr_t *wr, + ib_send_wr_t **bad_wr); +int mlx4_ib_post_recv(struct ib_qp *ibqp, ib_recv_wr_t *wr, + ib_recv_wr_t **bad_wr); + +int mlx4_MAD_IFC(struct mlx4_ib_dev *dev, int ignore_mkey, int ignore_bkey, + int port, ib_wc_t *in_wc, struct ib_grh *in_grh, + void *in_mad, void *response_mad); +int mlx4_ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num, + ib_wc_t *in_wc, struct ib_grh *in_grh, + struct ib_mad *in_mad, struct ib_mad *out_mad); +int mlx4_ib_mad_init(struct mlx4_ib_dev *dev); +void mlx4_ib_mad_cleanup(struct mlx4_ib_dev *dev); + +struct ib_fmr *mlx4_ib_fmr_alloc(struct ib_pd *pd, int mr_access_flags, + struct ib_fmr_attr *fmr_attr); +int mlx4_ib_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list, int npages, + u64 iova); +int mlx4_ib_unmap_fmr(struct list_head *fmr_list); +int mlx4_ib_fmr_dealloc(struct ib_fmr *fmr); + +void mlx4_ib_qp_init(); + +int __init mlx4_ib_init(void); +void __exit mlx4_ib_cleanup(void); + +int mlx4_ib_resolve_grh(struct mlx4_ib_dev *dev, const struct ib_ah_attr *ah_attr, + u8 *mac, int *is_mcast); + + +static inline int mlx4_ib_ah_grh_present(struct mlx4_ib_ah *ah) +{ + return !!(ah->av.ib.g_slid & 0x80); + +} + +#endif /* MLX4_IB_H */ diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/ib/mr.c b/branches/WOF2-3/hw/mlx4/kernel/bus/ib/mr.c new file mode 100644 index 00000000..5b63f210 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/ib/mr.c @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "mlx4_ib.h" + +static u32 convert_access(int acc) +{ + return (acc & IB_ACCESS_REMOTE_ATOMIC ? MLX4_PERM_ATOMIC : 0) | + (acc & IB_ACCESS_REMOTE_WRITE ? MLX4_PERM_REMOTE_WRITE : 0) | + (acc & IB_ACCESS_REMOTE_READ ? MLX4_PERM_REMOTE_READ : 0) | + (acc & IB_ACCESS_LOCAL_WRITE ? MLX4_PERM_LOCAL_WRITE : 0) | + MLX4_PERM_LOCAL_READ; +} + +struct ib_mr *mlx4_ib_get_dma_mr(struct ib_pd *pd, int acc) +{ + struct mlx4_ib_mr *mr; + int err; + + if (mlx4_is_barred(pd->device->dma_device)) + return ERR_PTR(-EFAULT); + + mr = kmalloc(sizeof *mr, GFP_KERNEL); + if (!mr) + return ERR_PTR(-ENOMEM); + + err = mlx4_mr_alloc(to_mdev(pd->device)->dev, to_mpd(pd)->pdn, 0, + ~0ull, convert_access(acc), 0, 0, &mr->mmr); + if (err) + goto err_free; + + err = mlx4_mr_enable(to_mdev(pd->device)->dev, &mr->mmr); + if (err) + goto err_mr; + + mr->ibmr.rkey = mr->ibmr.lkey = mr->mmr.key; + mr->umem = NULL; + + return &mr->ibmr; + +err_mr: + mlx4_mr_free(to_mdev(pd->device)->dev, &mr->mmr); + +err_free: + kfree(mr); + + return ERR_PTR(err); +} + +int mlx4_ib_umem_write_mtt(struct mlx4_ib_dev *dev, struct mlx4_mtt *mtt, + struct ib_umem *p_ib_umem) +{ + u64 *pages; + iobuf_iter_t iobuf_iter; + u32 i, n; + int err; + + pages = (u64 *) __get_free_page(GFP_KERNEL); + if (!pages) + return -ENOMEM; + + i = n = err = 0; + + iobuf_iter_init( &p_ib_umem->iobuf, &iobuf_iter ); + for (;;) { + // get up to max_buf_list_size page physical addresses + i = iobuf_get_tpt_seg( &p_ib_umem->iobuf, &iobuf_iter, + PAGE_SIZE / sizeof (u64), pages ); + if (!i) + break; + + // TODO: convert physical adresses to dma one's + + // write 'i' dma addresses + err = mlx4_write_mtt(dev->dev, mtt, n, i, pages); + if (err) + goto out; + n += i; + if (n >= p_ib_umem->iobuf.nr_pages) + break; + } + + CL_ASSERT(n == p_ib_umem->iobuf.nr_pages); + +out: + free_page(pages); + return err; +} + +struct ib_mr *mlx4_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, + u64 virt_addr, int access_flags, + struct ib_udata *udata) +{ + struct mlx4_ib_dev *dev = to_mdev(pd->device); + struct mlx4_ib_mr *mr; + int shift; + int err; + int n; + + UNUSED_PARAM(udata); + + if (mlx4_is_barred(pd->device->dma_device)) + return ERR_PTR(-EFAULT); + + mr = kmalloc(sizeof *mr, GFP_KERNEL); + if (!mr) + return ERR_PTR(-ENOMEM); + + mr->umem = ib_umem_get(pd->p_uctx, start, (size_t)length, access_flags, TRUE); + if (IS_ERR(mr->umem)) { + // there can be also second reason of failue - insufficient memory, + // but we can't get awared of that without changing ib_umem_get prototype + err = -EACCES; + goto err_free; + } + + n = ib_umem_page_count(mr->umem); + shift = ilog2(mr->umem->page_size); + + err = mlx4_mr_alloc(dev->dev, to_mpd(pd)->pdn, virt_addr, length, + convert_access(access_flags), n, shift, &mr->mmr); + if (err) + goto err_umem; + + err = mlx4_ib_umem_write_mtt(dev, &mr->mmr.mtt, mr->umem); + if (err) + goto err_mr; + + err = mlx4_mr_enable(dev->dev, &mr->mmr); + if (err) + goto err_mr; + + mr->ibmr.rkey = mr->ibmr.lkey = mr->mmr.key; + + return &mr->ibmr; + +err_mr: + mlx4_mr_free(to_mdev(pd->device)->dev, &mr->mmr); + +err_umem: + ib_umem_release(mr->umem); + +err_free: + kfree(mr); + + return ERR_PTR(err); +} + +int mlx4_ib_dereg_mr(struct ib_mr *ibmr) +{ + struct mlx4_ib_mr *mr = to_mmr(ibmr); + + mlx4_mr_free(to_mdev(ibmr->device)->dev, &mr->mmr); + if (mr->umem) + ib_umem_release(mr->umem); + kfree(mr); + + return 0; +} + +struct ib_fmr *mlx4_ib_fmr_alloc(struct ib_pd *pd, int acc, + struct ib_fmr_attr *fmr_attr) +{ + struct mlx4_ib_dev *dev = to_mdev(pd->device); + struct mlx4_ib_fmr *fmr; + int err = -ENOMEM; + + if (mlx4_is_barred(pd->device->dma_device)) + return ERR_PTR(-EFAULT); + + fmr = kmalloc(sizeof *fmr, GFP_KERNEL); + if (!fmr) + return ERR_PTR(-ENOMEM); + + err = mlx4_fmr_alloc(dev->dev, to_mpd(pd)->pdn, convert_access(acc), + fmr_attr->max_pages, fmr_attr->max_maps, + fmr_attr->page_shift, &fmr->mfmr); + if (err) + goto err_free; + + err = mlx4_fmr_enable(to_mdev(pd->device)->dev, &fmr->mfmr); + if (err) + goto err_mr; + + fmr->ibfmr.rkey = fmr->ibfmr.lkey = fmr->mfmr.mr.key; + + return &fmr->ibfmr; + +err_mr: + mlx4_mr_free(to_mdev(pd->device)->dev, &fmr->mfmr.mr); + +err_free: + kfree(fmr); + + return ERR_PTR(err); +} + +int mlx4_ib_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list, + int npages, u64 iova) +{ + struct mlx4_ib_fmr *ifmr = to_mfmr(ibfmr); + struct mlx4_ib_dev *dev = to_mdev(ifmr->ibfmr.device); + + if (mlx4_is_barred(ifmr->ibfmr.device->dma_device)) + return -EFAULT; + + return mlx4_map_phys_fmr(dev->dev, &ifmr->mfmr, page_list, npages, iova, + &ifmr->ibfmr.lkey, &ifmr->ibfmr.rkey); +} + +int mlx4_ib_unmap_fmr(struct list_head *fmr_list) +{ + struct ib_fmr *ibfmr; + int err = 0; + struct mlx4_dev *mdev = NULL; + + list_for_each_entry(ibfmr, fmr_list, list, struct ib_fmr) { + if (mdev && to_mdev(ibfmr->device)->dev != mdev) + return -EINVAL; + mdev = to_mdev(ibfmr->device)->dev; + } + + if (!mdev) + return 0; + + list_for_each_entry(ibfmr, fmr_list, list, struct ib_fmr) { + struct mlx4_ib_fmr *ifmr = to_mfmr(ibfmr); + + mlx4_fmr_unmap(mdev, &ifmr->mfmr, &ifmr->ibfmr.lkey, &ifmr->ibfmr.rkey); + } + + /* + * Make sure all MPT status updates are visible before issuing + * SYNC_TPT firmware command. + */ + wmb(); + + if (!mlx4_is_barred(mdev)) + err = mlx4_SYNC_TPT(mdev); + if (err) + printk(KERN_WARNING "mlx4_ib: SYNC_TPT error %d when " + "unmapping FMRs\n", err); + + return 0; +} + +int mlx4_ib_fmr_dealloc(struct ib_fmr *ibfmr) +{ + struct mlx4_ib_fmr *ifmr = to_mfmr(ibfmr); + struct mlx4_ib_dev *dev = to_mdev(ibfmr->device); + int err; + + err = mlx4_fmr_free(dev->dev, &ifmr->mfmr); + + if (!err) + kfree(ifmr); + + return err; +} diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/ib/qp.c b/branches/WOF2-3/hw/mlx4/kernel/bus/ib/qp.c new file mode 100644 index 00000000..263a47ae --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/ib/qp.c @@ -0,0 +1,1978 @@ +/* + * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "mlx4_ib.h" +#include "ib_cache.h" +#include "ib_pack.h" +#include "qp.h" +#include "user.h" + +void st_print_mlx_header( struct mlx4_dev *mdev, struct mlx4_ib_sqp *sqp, struct mlx4_wqe_mlx_seg *mlx ); +void st_print_mlx_send(struct mlx4_dev *mdev, struct ib_qp *ibqp, ib_send_wr_t *wr); +void st_dump_mlx_wqe(struct mlx4_dev *mdev, void *wqe, int size_in_dwords, ib_send_wr_t *wr); + +enum { + MLX4_IB_ACK_REQ_FREQ = 8, +}; + +enum { + MLX4_IB_DEFAULT_SCHED_QUEUE = 0x83, + MLX4_IB_DEFAULT_QP0_SCHED_QUEUE = 0x3f, + MLX4_IB_LINK_TYPE_IB = 0, + MLX4_IB_LINK_TYPE_ETH = 1 +}; + +enum { + MLX4_RDMAOE_ETHERTYPE = 0x8915 +}; + +enum { + MLX4_IB_MIN_SQ_STRIDE = 6 +}; + +static const __be32 mlx4_ib_opcode[] = { + __constant_cpu_to_be32(MLX4_OPCODE_RDMA_WRITE), /* [IB_WR_RDMA_WRITE] */ + __constant_cpu_to_be32(MLX4_OPCODE_RDMA_WRITE_IMM), /* [IB_WR_RDMA_WRITE_WITH_IMM] */ + __constant_cpu_to_be32(MLX4_OPCODE_SEND), /* [IB_WR_SEND] */ + __constant_cpu_to_be32(MLX4_OPCODE_SEND_IMM), /* [IB_WR_SEND_WITH_IMM] */ + __constant_cpu_to_be32(MLX4_OPCODE_RDMA_READ), /* [IB_WR_RDMA_READ] */ + __constant_cpu_to_be32(MLX4_OPCODE_ATOMIC_CS), /* [IB_WR_ATOMIC_CMP_AND_SWP] */ + __constant_cpu_to_be32(MLX4_OPCODE_ATOMIC_FA), /* [IB_WR_ATOMIC_FETCH_AND_ADD]*/ + __constant_cpu_to_be32(MLX4_OPCODE_LSO | (1 << 6)), /* [IB_WR_LSO] */ + + + __constant_cpu_to_be32(MLX4_OPCODE_SEND_INVAL), /* [IB_WR_SEND_WITH_INV] */ + __constant_cpu_to_be32(MLX4_OPCODE_RDMA_READ), /* [IB_WR_RDMA_READ_WITH_INV] */ + __constant_cpu_to_be32(MLX4_OPCODE_LOCAL_INVAL), /* [IB_WR_LOCAL_INV] */ + __constant_cpu_to_be32(MLX4_OPCODE_FMR), /* [IB_WR_FAST_REG_MR] */ + + + + __constant_cpu_to_be32(MLX4_OPCODE_NOP) /* [IB_WR_NOP] */ +}; + + +//????????????????? IB_WR_RDMA_READ_WITH_INV, //??????????????? + +extern inline void rdma_get_ll_mac(struct in6_addr *addr, u8 *mac); + +static struct mlx4_ib_sqp *to_msqp(struct mlx4_ib_qp *mqp) +{ + return container_of(mqp, struct mlx4_ib_sqp, qp); +} + +static int is_sqp(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp) +{ + return qp->mqp.qpn >= dev->dev->caps.sqp_start && + qp->mqp.qpn <= dev->dev->caps.sqp_start + 3; +} + +static int is_qp0(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp) +{ + return qp->mqp.qpn >= dev->dev->caps.sqp_start && + qp->mqp.qpn <= dev->dev->caps.sqp_start + 1; +} + +static void *get_wqe(struct mlx4_ib_qp *qp, int offset) +{ + if (qp->buf.nbufs == 1) + return qp->buf.u.direct.buf + offset; + else + return qp->buf.u.page_list[offset >> PAGE_SHIFT].buf + + (offset & (PAGE_SIZE - 1)); +} + +static void *get_recv_wqe(struct mlx4_ib_qp *qp, int n) +{ + return get_wqe(qp, qp->rq.offset + (n << qp->rq.wqe_shift)); +} + +static void *get_send_wqe(struct mlx4_ib_qp *qp, int n) +{ + return get_wqe(qp, qp->sq.offset + (n << qp->sq.wqe_shift)); +} + +/* + * Stamp a SQ WQE so that it is invalid if prefetched by marking the + * first four bytes of every 64 byte chunk with 0xffffffff, except for + * the very first chunk of the WQE. + */ +static void stamp_send_wqe(struct mlx4_ib_qp *qp, int n) +{ + u32 *wqe = get_send_wqe(qp, n); + int i; + + for (i = 16; i < 1 << (qp->sq.wqe_shift - 2); i += 16) + wqe[i] = 0xffffffff; +} + +static void mlx4_ib_qp_event(struct mlx4_qp *qp, enum mlx4_event type) +{ + ib_event_rec_t event; + struct ib_qp *ibqp = &to_mibqp(qp)->ibqp; + + if (type == MLX4_EVENT_TYPE_PATH_MIG) + to_mibqp(qp)->port = to_mibqp(qp)->alt_port; + + switch (type) { + case MLX4_EVENT_TYPE_PATH_MIG: + event.type = IB_EVENT_PATH_MIG; + break; + case MLX4_EVENT_TYPE_COMM_EST: + event.type = IB_EVENT_COMM_EST; + break; + case MLX4_EVENT_TYPE_SQ_DRAINED: + event.type = IB_EVENT_SQ_DRAINED; + break; + case MLX4_EVENT_TYPE_SRQ_QP_LAST_WQE: + event.type = IB_EVENT_QP_LAST_WQE_REACHED; + break; + case MLX4_EVENT_TYPE_WQ_CATAS_ERROR: + event.type = IB_EVENT_QP_FATAL; + break; + case MLX4_EVENT_TYPE_PATH_MIG_FAILED: + event.type = IB_EVENT_PATH_MIG_ERR; + break; + case MLX4_EVENT_TYPE_WQ_INVAL_REQ_ERROR: + event.type = IB_EVENT_QP_REQ_ERR; + break; + case MLX4_EVENT_TYPE_WQ_ACCESS_ERROR: + event.type = IB_EVENT_QP_ACCESS_ERR; + break; + default: + printk(KERN_WARNING "mlx4_ib: Unexpected event type %d " + "on QP %06x\n", type, qp->qpn); + return; + } + + event.context = ibqp->qp_context; + ibqp->event_handler(&event); +} + +static int send_wqe_overhead(enum ib_qp_type type, u32 flags) +{ + /* + * UD WQEs must have a datagram segment. + * RC and UC WQEs might have a remote address segment. + * MLX WQEs need two extra inline data segments (for the UD + * header and space for the ICRC). + */ + switch (type) { + case IB_QPT_UD: + return sizeof (struct mlx4_wqe_ctrl_seg) + + sizeof (struct mlx4_wqe_datagram_seg) + + ((flags & MLX4_IB_QP_LSO) ? 64 : 0); + case IB_QPT_UC: + return sizeof (struct mlx4_wqe_ctrl_seg) + + sizeof (struct mlx4_wqe_raddr_seg); + case IB_QPT_RC: + return sizeof (struct mlx4_wqe_ctrl_seg) + + sizeof (struct mlx4_wqe_atomic_seg) + + sizeof (struct mlx4_wqe_raddr_seg); + case IB_QPT_SMI: + case IB_QPT_GSI: + return sizeof (struct mlx4_wqe_ctrl_seg) + + ALIGN(MLX4_IB_UD_HEADER_SIZE + + DIV_ROUND_UP(MLX4_IB_UD_HEADER_SIZE, + MLX4_INLINE_ALIGN) * + sizeof (struct mlx4_wqe_inline_seg), + sizeof (struct mlx4_wqe_data_seg)) + + ALIGN(4 + + sizeof (struct mlx4_wqe_inline_seg), + sizeof (struct mlx4_wqe_data_seg)); + default: + return sizeof (struct mlx4_wqe_ctrl_seg); + } +} + +static int set_rq_size(struct mlx4_ib_dev *dev, struct ib_qp_cap *cap, + int is_user, int has_srq, struct mlx4_ib_qp *qp) +{ + /* Sanity check RQ size before proceeding */ + if ((int)cap->max_recv_wr > dev->dev->caps.max_wqes - MLX4_IB_SQ_MAX_SPARE || + (int)cap->max_recv_sge > min(dev->dev->caps.max_sq_sg, dev->dev->caps.max_rq_sg)) + return -EINVAL; + + if (has_srq) { + /* QPs attached to an SRQ should have no RQ */ + if (cap->max_recv_wr) + return -EINVAL; + + qp->rq.wqe_cnt = qp->rq.max_gs = 0; + } else { + /* HW requires >= 1 RQ entry with >= 1 gather entry */ + if (is_user && (!cap->max_recv_wr || !cap->max_recv_sge)) + return -EINVAL; + + qp->rq.wqe_cnt = roundup_pow_of_two(max(1U, cap->max_recv_wr)); + qp->rq.max_gs = roundup_pow_of_two(max(1U, cap->max_recv_sge)); + qp->rq.wqe_shift = ilog2(qp->rq.max_gs * sizeof (struct mlx4_wqe_data_seg)); + } + + /* leave userspace return values as they were, so as not to break ABI */ + if (is_user) { + cap->max_recv_wr = qp->rq.max_post = qp->rq.wqe_cnt; + cap->max_recv_sge = qp->rq.max_gs; + } else { + cap->max_recv_wr = qp->rq.max_post = + min(dev->dev->caps.max_wqes - MLX4_IB_SQ_MAX_SPARE, qp->rq.wqe_cnt); + cap->max_recv_sge = min(qp->rq.max_gs, + min(dev->dev->caps.max_sq_sg, + dev->dev->caps.max_rq_sg)); + } + /* We don't support inline sends for kernel QPs (yet) */ + + return 0; +} + +static int set_kernel_sq_size(struct mlx4_ib_dev *dev, struct ib_qp_cap *cap, + enum ib_qp_type type, struct mlx4_ib_qp *qp) +{ + /* Sanity check SQ size before proceeding */ + if ((int)cap->max_send_wr > dev->dev->caps.max_wqes - MLX4_IB_SQ_MAX_SPARE || + (int)cap->max_send_sge > min(dev->dev->caps.max_sq_sg, dev->dev->caps.max_rq_sg) || + (int)cap->max_inline_data + send_wqe_overhead(type, qp->flags) + + (int)sizeof(struct mlx4_wqe_inline_seg) > dev->dev->caps.max_sq_desc_sz) + return -EINVAL; + + /* + * For MLX transport we need 2 extra S/G entries: + * one for the header and one for the checksum at the end + */ + if ((type == IB_QPT_SMI || type == IB_QPT_GSI) && + (int)cap->max_send_sge + 2 > dev->dev->caps.max_sq_sg) + return -EINVAL; + + qp->sq.wqe_shift = ilog2(roundup_pow_of_two(max(cap->max_send_sge * + sizeof (struct mlx4_wqe_data_seg), + cap->max_inline_data + + sizeof (struct mlx4_wqe_inline_seg)) + + send_wqe_overhead(type,qp->flags))); + qp->sq.wqe_shift = max(MLX4_IB_SQ_MIN_WQE_SHIFT, qp->sq.wqe_shift); + qp->sq.max_gs = ((1 << qp->sq.wqe_shift) - send_wqe_overhead(type,qp->flags)) / + sizeof (struct mlx4_wqe_data_seg); + + /* + * We need to leave 2 KB + 1 WQE of headroom in the SQ to + * allow HW to prefetch. + */ + qp->sq_spare_wqes = MLX4_IB_SQ_HEADROOM(qp->sq.wqe_shift); + qp->sq.wqe_cnt = roundup_pow_of_two(cap->max_send_wr + qp->sq_spare_wqes); + + qp->buf_size = (qp->rq.wqe_cnt << qp->rq.wqe_shift) + + (qp->sq.wqe_cnt << qp->sq.wqe_shift); + if (qp->rq.wqe_shift > qp->sq.wqe_shift) { + qp->rq.offset = 0; + qp->sq.offset = qp->rq.wqe_cnt << qp->rq.wqe_shift; + } else { + qp->rq.offset = qp->sq.wqe_cnt << qp->sq.wqe_shift; + qp->sq.offset = 0; + } + + cap->max_send_wr = qp->sq.max_post = + min(qp->sq.wqe_cnt - qp->sq_spare_wqes, + dev->dev->caps.max_wqes - MLX4_IB_SQ_MAX_SPARE); + cap->max_send_sge = min(qp->sq.max_gs, + min(dev->dev->caps.max_sq_sg, + dev->dev->caps.max_rq_sg)); + /* We don't support inline sends for kernel QPs (yet) */ + cap->max_inline_data = 0; + + return 0; +} + +static int set_user_sq_size(struct mlx4_ib_dev *dev, + struct mlx4_ib_qp *qp, + struct mlx4_ib_create_qp *ucmd) +{ + /* Sanity check SQ size before proceeding */ + if ((1 << ucmd->log_sq_bb_count) > dev->dev->caps.max_wqes || + ucmd->log_sq_stride > + ilog2(roundup_pow_of_two(dev->dev->caps.max_sq_desc_sz)) || + ucmd->log_sq_stride < MLX4_IB_MIN_SQ_STRIDE) + return -EINVAL; + + qp->sq.wqe_cnt = 1 << ucmd->log_sq_bb_count; + qp->sq.wqe_shift = ucmd->log_sq_stride; + + qp->buf_size = (qp->rq.wqe_cnt << qp->rq.wqe_shift) + + (qp->sq.wqe_cnt << qp->sq.wqe_shift); + + return 0; +} + +static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd, + struct ib_qp_init_attr *init_attr, + struct ib_udata *udata, u32 sqpn, struct mlx4_ib_qp *qp) +{ + int err; + BOOLEAN range_allocated = FALSE; + + mutex_init(&qp->mutex); + spin_lock_init(&qp->sq.lock); + spin_lock_init(&qp->rq.lock); + + qp->state = XIB_QPS_RESET; + qp->atomic_rd_en = 0; + qp->resp_depth = 0; + + qp->rq.head = 0; + qp->rq.tail = 0; + qp->sq.head = 0; + qp->sq.tail = 0; + + err = set_rq_size(dev, &init_attr->cap, !!pd->p_uctx, !!init_attr->srq, qp); + if (err) + goto err; + + if (pd->p_uctx) { + struct mlx4_ib_create_qp ucmd; + + if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd)) { + err = -EFAULT; + goto err; + } + + qp->sq_no_prefetch = ucmd.sq_no_prefetch; + + err = set_user_sq_size(dev, qp, &ucmd); + if (err) + goto err; + + qp->umem = ib_umem_get(pd->p_uctx, ucmd.buf_addr, + qp->buf_size, 0, FALSE); + if (IS_ERR(qp->umem)) { + err = PTR_ERR(qp->umem); + goto err; + } + + err = mlx4_mtt_init(dev->dev, ib_umem_page_count(qp->umem), + ilog2(qp->umem->page_size), &qp->mtt); + if (err) + goto err_buf; + + err = mlx4_ib_umem_write_mtt(dev, &qp->mtt, qp->umem); + if (err) + goto err_mtt; + + if (!init_attr->srq) { + err = mlx4_ib_db_map_user(to_mucontext(pd->p_uctx), + ucmd.db_addr, &qp->db); + if (err) + goto err_mtt; + } + } else { + qp->sq_no_prefetch = 0; + + if (init_attr->create_flags & IB_QP_CREATE_IPOIB_UD_LSO) + qp->flags |= MLX4_IB_QP_LSO; + + err = set_kernel_sq_size(dev, &init_attr->cap, init_attr->qp_type, qp); + if (err) + goto err; + + if (!init_attr->srq) { + err = mlx4_ib_db_alloc(dev, &qp->db, 0); + if (err) + goto err; + + *qp->db.db = 0; + } + + if (mlx4_buf_alloc(dev->dev, qp->buf_size, PAGE_SIZE * 2, &qp->buf)) { + err = -ENOMEM; + goto err_db; + } + + err = mlx4_mtt_init(dev->dev, qp->buf.npages, qp->buf.page_shift, + &qp->mtt); + if (err) + goto err_buf; + + err = mlx4_buf_write_mtt(dev->dev, &qp->mtt, &qp->buf); + if (err) + goto err_mtt; + + if (qp->sq.wqe_cnt) { + qp->sq.wrid = kmalloc(qp->sq.wqe_cnt * sizeof (u64), GFP_KERNEL); + if (!qp->sq.wrid) { + err = -ENOMEM; + goto err_wrid; + } + } + + if (qp->rq.wqe_cnt) { + qp->rq.wrid = kmalloc(qp->rq.wqe_cnt * sizeof (u64), GFP_KERNEL); + if (!qp->rq.wrid) { + err = -ENOMEM; + goto err_wrid; + } + } + } + + if (!sqpn) { + err = mlx4_qp_reserve_range(dev->dev, 1, 1, &sqpn); + if (err) + goto err_wrid; + range_allocated = TRUE; + + } + + err = mlx4_qp_alloc(dev->dev, sqpn, &qp->mqp); + if (err) + goto err_range; + + /* + * Hardware wants QPN written in big-endian order (after + * shifting) for send doorbell. Precompute this value to save + * a little bit when posting sends. + */ + qp->doorbell_qpn = swab32(qp->mqp.qpn << 8); + + if (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR) + qp->sq_signal_bits = cpu_to_be32(MLX4_WQE_CTRL_CQ_UPDATE); + else + qp->sq_signal_bits = 0; + + qp->mqp.event = mlx4_ib_qp_event; + + return 0; + +err_range: + if (range_allocated) + mlx4_qp_release_range(dev->dev, sqpn, 1); + +err_wrid: + if (pd->p_uctx) { + if (!init_attr->srq) + mlx4_ib_db_unmap_user(to_mucontext(pd->p_uctx), + &qp->db); + } else { + if (qp->sq.wrid) + kfree(qp->sq.wrid); + if (qp->rq.wrid) + kfree(qp->rq.wrid); + } + +err_mtt: + mlx4_mtt_cleanup(dev->dev, &qp->mtt); + +err_buf: + if (pd->p_uctx) + ib_umem_release(qp->umem); + else + mlx4_buf_free(dev->dev, qp->buf_size, &qp->buf); + +err_db: + if (!pd->p_uctx && !init_attr->srq) + mlx4_ib_db_free(dev, &qp->db); + +err: + return err; +} + +static enum mlx4_qp_state to_mlx4_state(enum ib_qp_state state) +{ + switch (state) { + case XIB_QPS_RESET: return MLX4_QP_STATE_RST; + case XIB_QPS_INIT: return MLX4_QP_STATE_INIT; + case XIB_QPS_RTR: return MLX4_QP_STATE_RTR; + case XIB_QPS_RTS: return MLX4_QP_STATE_RTS; + case XIB_QPS_SQD: return MLX4_QP_STATE_SQD; + case XIB_QPS_SQE: return MLX4_QP_STATE_SQER; + case XIB_QPS_ERR: return MLX4_QP_STATE_ERR; + default: return -1; + } +} + +static void mlx4_ib_lock_cqs(struct mlx4_ib_cq *send_cq, struct mlx4_ib_cq *recv_cq) +{ + if (send_cq == recv_cq) + spin_lock_irq(&send_cq->lock); + else if (send_cq->mcq.cqn < recv_cq->mcq.cqn) { + spin_lock_irq(&send_cq->lock); + spin_lock_nested(&recv_cq->lock, SINGLE_DEPTH_NESTING); + } else { + spin_lock_irq(&recv_cq->lock); + spin_lock_nested(&send_cq->lock, SINGLE_DEPTH_NESTING); + } +} + +static void mlx4_ib_unlock_cqs(struct mlx4_ib_cq *send_cq, struct mlx4_ib_cq *recv_cq) +{ + if (send_cq == recv_cq) + spin_unlock_irq(&send_cq->lock); + else if (send_cq->mcq.cqn < recv_cq->mcq.cqn) { + spin_unlock(&recv_cq->lock); + spin_unlock_irq(&send_cq->lock); + } else { + spin_unlock(&send_cq->lock); + spin_unlock_irq(&recv_cq->lock); + } +} + +static void destroy_qp_common(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp, + int is_user) +{ + struct mlx4_ib_cq *send_cq, *recv_cq; + int zombi = 0; + + if (qp->state != XIB_QPS_RESET) + if (mlx4_qp_modify(dev->dev, NULL, to_mlx4_state(qp->state), + MLX4_QP_STATE_RST, NULL, 0, 0, &qp->mqp)) { + printk(KERN_WARNING "mlx4_ib: modify QP %06x to RESET failed.\n", + qp->mqp.qpn); + zombi = 1; + } + + send_cq = to_mcq(qp->ibqp.send_cq); + recv_cq = to_mcq(qp->ibqp.recv_cq); + + mlx4_ib_lock_cqs(send_cq, recv_cq); + + if (!is_user) { + __mlx4_ib_cq_clean(recv_cq, qp->mqp.qpn, + qp->ibqp.srq ? to_msrq(qp->ibqp.srq): NULL); + if (send_cq != recv_cq) + __mlx4_ib_cq_clean(send_cq, qp->mqp.qpn, NULL); + } + + mlx4_qp_remove(dev->dev, &qp->mqp); + + mlx4_ib_unlock_cqs(send_cq, recv_cq); + + mlx4_qp_free(dev->dev, &qp->mqp); + + if (!is_sqp(dev, qp) && !zombi ) + mlx4_qp_release_range(dev->dev, qp->mqp.qpn, 1); + + mlx4_mtt_cleanup(dev->dev, &qp->mtt); + + if (is_user) { + if (!qp->ibqp.srq) + mlx4_ib_db_unmap_user(to_mucontext(qp->ibqp.p_uctx), + &qp->db); + ib_umem_release(qp->umem); + } else { + kfree(qp->sq.wrid); + kfree(qp->rq.wrid); + mlx4_buf_free(dev->dev, qp->buf_size, &qp->buf); + if (!qp->ibqp.srq) + mlx4_ib_db_free(dev, &qp->db); + } +} + +struct ib_qp *mlx4_ib_create_qp(struct ib_pd *pd, + struct ib_qp_init_attr *init_attr, + struct ib_udata *udata) +{ + struct mlx4_ib_dev *dev = to_mdev(pd->device); + struct mlx4_ib_sqp *sqp; + struct mlx4_ib_qp *qp; + int err; + + /* TODO: suggest to remove :We only support LSO, and only for kernel UD QPs. */ + /*if (init_attr->create_flags & ~IB_QP_CREATE_IPOIB_UD_LSO) + return ERR_PTR(-EINVAL); + if (init_attr->create_flags & IB_QP_CREATE_IPOIB_UD_LSO && + (pd->uobject || init_attr->qp_type != IB_QPT_UD)) + return ERR_PTR(-EINVAL);*/ + + if (mlx4_is_barred(pd->device->dma_device)) + return ERR_PTR(-EFAULT); + + switch (init_attr->qp_type) { + case IB_QPT_RC: + case IB_QPT_UC: + case IB_QPT_UD: + { + qp = kzalloc(sizeof *qp, GFP_KERNEL); + if (!qp) + return ERR_PTR(-ENOMEM); + + err = create_qp_common(dev, pd, init_attr, udata, 0, qp); + if (err) { + kfree(qp); + return ERR_PTR(err); + } + + qp->ibqp.qp_num = qp->mqp.qpn; + + break; + } + case IB_QPT_SMI: + case IB_QPT_GSI: + { + /* Userspace is not allowed to create special QPs: */ + if (pd->p_uctx) + return ERR_PTR(-EINVAL); + + sqp = kzalloc(sizeof *sqp, GFP_KERNEL); + if (!sqp) + return ERR_PTR(-ENOMEM); + + qp = &sqp->qp; + + err = create_qp_common(dev, pd, init_attr, udata, + dev->dev->caps.sqp_start + + (init_attr->qp_type == IB_QPT_SMI ? 0 : 2) + + init_attr->port_num - 1, + qp); + if (err) { + kfree(sqp); + return ERR_PTR(err); + } + + qp->port = init_attr->port_num; + qp->ibqp.qp_num = init_attr->qp_type == IB_QPT_SMI ? 0 : 1; + + break; + } + default: + /* Don't support raw QPs */ + return ERR_PTR(-EINVAL); + } + + return &qp->ibqp; +} + +int mlx4_ib_destroy_qp(struct ib_qp *qp) +{ + struct mlx4_ib_dev *dev = to_mdev(qp->device); + struct mlx4_ib_qp *mqp = to_mqp(qp); + + if (!mlx4_is_barred(dev->dev) && is_qp0(dev, mqp)) + mlx4_CLOSE_PORT(dev->dev, mqp->port); + + destroy_qp_common(dev, mqp, !!qp->pd->p_uctx); + + if (is_sqp(dev, mqp)) + kfree(to_msqp(mqp)); + else + kfree(mqp); + + return 0; +} + +static int to_mlx4_st(enum ib_qp_type type) +{ + switch (type) { + case IB_QPT_RC: return MLX4_QP_ST_RC; + case IB_QPT_UC: return MLX4_QP_ST_UC; + case IB_QPT_UD: return MLX4_QP_ST_UD; + case IB_QPT_SMI: + case IB_QPT_GSI: return MLX4_QP_ST_MLX; + default: return -1; + } +} + +static __be32 to_mlx4_access_flags(struct mlx4_ib_qp *qp, const struct ib_qp_attr *attr, + int attr_mask) +{ + u8 dest_rd_atomic; + u32 access_flags; + u32 hw_access_flags = 0; + + if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) + dest_rd_atomic = attr->max_dest_rd_atomic; + else + dest_rd_atomic = qp->resp_depth; + + if (attr_mask & IB_QP_ACCESS_FLAGS) + access_flags = attr->qp_access_flags; + else + access_flags = qp->atomic_rd_en; + + if (!dest_rd_atomic) + access_flags &= IB_ACCESS_REMOTE_WRITE; + + if (access_flags & IB_ACCESS_REMOTE_READ) + hw_access_flags |= MLX4_QP_BIT_RRE; + if (access_flags & IB_ACCESS_REMOTE_ATOMIC) + hw_access_flags |= MLX4_QP_BIT_RAE; + if (access_flags & IB_ACCESS_REMOTE_WRITE) + hw_access_flags |= MLX4_QP_BIT_RWE; + + return cpu_to_be32(hw_access_flags); +} + +static void store_sqp_attrs(struct mlx4_ib_sqp *sqp, const struct ib_qp_attr *attr, + int attr_mask) +{ + if (attr_mask & IB_QP_PKEY_INDEX) + sqp->pkey_index = attr->pkey_index; + if (attr_mask & IB_QP_QKEY) + sqp->qkey = attr->qkey; + if (attr_mask & IB_QP_SQ_PSN) + sqp->send_psn = attr->sq_psn; +} + +static void mlx4_set_sched(struct mlx4_qp_path *path, u8 port) +{ + path->sched_queue = (path->sched_queue & 0xbf) | ((port - 1) << 6); +} + +static int mlx4_set_path(struct mlx4_ib_dev *dev, const struct ib_ah_attr *ah, + struct mlx4_qp_path *path, u8 port) +{ + int err; + int is_eth = rdma_port_get_transport(&dev->ib_dev, port) == + RDMA_TRANSPORT_RDMAOE ? 1 : 0; + u8 mac[6]; + int is_mcast; + + path->grh_mylmc = ah->src_path_bits & 0x7f; + path->rlid = cpu_to_be16(ah->dlid); + if (ah->static_rate) { + path->static_rate = ah->static_rate + MLX4_STAT_RATE_OFFSET; + while (path->static_rate > IB_RATE_2_5_GBPS + MLX4_STAT_RATE_OFFSET && + !(1 << path->static_rate & dev->dev->caps.stat_rate_support)) + --path->static_rate; + } else + path->static_rate = 0; + path->counter_index = 0xff; + + if (ah->ah_flags & IB_AH_GRH) { + if (ah->grh.sgid_index >= dev->dev->caps.gid_table_len[port]) { + printk(KERN_ERR "sgid_index (%u) too large. max is %d\n", + ah->grh.sgid_index, dev->dev->caps.gid_table_len[port] - 1); + return -1; + } + + path->grh_mylmc |= 1 << 7; + path->mgid_index = ah->grh.sgid_index; + path->hop_limit = ah->grh.hop_limit; + path->tclass_flowlabel = + cpu_to_be32((ah->grh.traffic_class << 20) | + (ah->grh.flow_label)); + memcpy(path->rgid, ah->grh.dgid.raw, 16); + } + + path->sched_queue = MLX4_IB_DEFAULT_SCHED_QUEUE | + ((port - 1) << 6) | ((ah->sl & 0xf) << 2); + + if (is_eth) { + if (!(ah->ah_flags & IB_AH_GRH)) + return -1; + + err = mlx4_ib_resolve_grh(dev, ah, mac, &is_mcast); + if (err) + return err; + + memcpy(path->dmac, mac, 6); + path->ackto = MLX4_IB_LINK_TYPE_ETH; + /* use index 0 into MAC table for RDMAoE */ + path->grh_mylmc &= 0x80; + } + + return 0; +} + +static int __mlx4_ib_modify_qp(struct ib_qp *ibqp, + const struct ib_qp_attr *attr, int attr_mask, + enum ib_qp_state cur_state, enum ib_qp_state new_state) +{ + struct mlx4_ib_dev *dev = to_mdev(ibqp->device); + struct mlx4_ib_qp *qp = to_mqp(ibqp); + struct mlx4_qp_context *context; + enum mlx4_qp_optpar optpar = 0; + int sqd_event; + int err = -EINVAL; + + context = kzalloc(sizeof *context, GFP_KERNEL); + if (!context) + return -ENOMEM; + + context->flags = cpu_to_be32((to_mlx4_state(new_state) << 28) | + (to_mlx4_st(ibqp->qp_type) << 16)); + context->flags |= cpu_to_be32(1 << 8); /* DE? */ + + if (!(attr_mask & IB_QP_PATH_MIG_STATE)) + context->flags |= cpu_to_be32(MLX4_QP_PM_MIGRATED << 11); + else { + optpar |= MLX4_QP_OPTPAR_PM_STATE; + switch (attr->path_mig_state) { + case IB_MIG_MIGRATED: + context->flags |= cpu_to_be32(MLX4_QP_PM_MIGRATED << 11); + break; + case IB_MIG_REARM: + context->flags |= cpu_to_be32(MLX4_QP_PM_REARM << 11); + break; + case IB_MIG_ARMED: + context->flags |= cpu_to_be32(MLX4_QP_PM_ARMED << 11); + break; + } + } + + if (ibqp->qp_type == IB_QPT_GSI || ibqp->qp_type == IB_QPT_SMI ) + context->mtu_msgmax = (IB_MTU_4096 << 5) | 12; + else if (ibqp->qp_type == IB_QPT_UD) { + if (qp->flags & MLX4_IB_QP_LSO) + context->mtu_msgmax = (u8)((IB_MTU_4096 << 5) | + ilog2(dev->dev->caps.max_gso_sz)); + else + context->mtu_msgmax = (IB_MTU_4096 << 5) | 12; + } else if (attr_mask & IB_QP_PATH_MTU) { + if (attr->path_mtu < IB_MTU_256 || attr->path_mtu > IB_MTU_4096) { + printk(KERN_ERR "path MTU (%u) is invalid\n", + attr->path_mtu); + goto out; + } + context->mtu_msgmax = (u8)((attr->path_mtu << 5) | + ilog2(dev->dev->caps.max_msg_sz)); + } + + if (qp->rq.wqe_cnt) + context->rq_size_stride = (u8)(ilog2(qp->rq.wqe_cnt) << 3); + context->rq_size_stride |= qp->rq.wqe_shift - 4; + + if (qp->sq.wqe_cnt) + context->sq_size_stride = (u8)(ilog2(qp->sq.wqe_cnt) << 3); + context->sq_size_stride |= qp->sq.wqe_shift - 4; + + if (cur_state == XIB_QPS_RESET && new_state == XIB_QPS_INIT) + context->sq_size_stride |= !!qp->sq_no_prefetch << 7; + + if (qp->ibqp.p_uctx) + context->usr_page = cpu_to_be32(to_mucontext(ibqp->p_uctx)->uar.index); + else + context->usr_page = cpu_to_be32(dev->priv_uar.index); + + if (attr_mask & IB_QP_DEST_QPN) + context->remote_qpn = cpu_to_be32(attr->dest_qp_num); + + if (attr_mask & IB_QP_PORT) { + if (cur_state == XIB_QPS_SQD && new_state == XIB_QPS_SQD && + !(attr_mask & IB_QP_AV)) { + mlx4_set_sched(&context->pri_path, attr->port_num); + optpar |= MLX4_QP_OPTPAR_SCHED_QUEUE; + } + } + + if (attr_mask & IB_QP_PKEY_INDEX) { + context->pri_path.pkey_index = (u8)attr->pkey_index; + optpar |= MLX4_QP_OPTPAR_PKEY_INDEX; + } + + if (attr_mask & IB_QP_AV) { + if (mlx4_set_path(dev, &attr->ah_attr, &context->pri_path, + attr_mask & IB_QP_PORT ? attr->port_num : qp->port)) + goto out; + + optpar |= (MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH | + MLX4_QP_OPTPAR_SCHED_QUEUE); + } + + if (attr_mask & IB_QP_TIMEOUT) { + context->pri_path.ackto = attr->timeout << 3; + optpar |= MLX4_QP_OPTPAR_ACK_TIMEOUT; + } + + if (attr_mask & IB_QP_ALT_PATH) { + if (attr->alt_port_num == 0 || + attr->alt_port_num > dev->dev->caps.num_ports) + goto out; + + if (attr->alt_pkey_index >= + dev->dev->caps.pkey_table_len[attr->alt_port_num]) + goto out; + + if (mlx4_set_path(dev, &attr->alt_ah_attr, &context->alt_path, + attr->alt_port_num)) + goto out; + + context->alt_path.pkey_index = (u8)attr->alt_pkey_index; + context->alt_path.ackto = attr->alt_timeout << 3; + optpar |= MLX4_QP_OPTPAR_ALT_ADDR_PATH; + } + + context->pd = cpu_to_be32(to_mpd(ibqp->pd)->pdn); + context->params1 = cpu_to_be32(MLX4_IB_ACK_REQ_FREQ << 28); + + if (attr_mask & IB_QP_RNR_RETRY) { + context->params1 |= cpu_to_be32(attr->rnr_retry << 13); + optpar |= MLX4_QP_OPTPAR_RNR_RETRY; + } + + if (attr_mask & IB_QP_RETRY_CNT) { + context->params1 |= cpu_to_be32(attr->retry_cnt << 16); + optpar |= MLX4_QP_OPTPAR_RETRY_COUNT; + } + + if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC) { + if (attr->max_rd_atomic) + context->params1 |= + cpu_to_be32(fls(attr->max_rd_atomic - 1) << 21); + optpar |= MLX4_QP_OPTPAR_SRA_MAX; + } + + if (attr_mask & IB_QP_SQ_PSN) + context->next_send_psn = cpu_to_be32(attr->sq_psn); + + context->cqn_send = cpu_to_be32(to_mcq(ibqp->send_cq)->mcq.cqn); + + if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) { + if (attr->max_dest_rd_atomic) + context->params2 |= + cpu_to_be32(fls(attr->max_dest_rd_atomic - 1) << 21); + optpar |= MLX4_QP_OPTPAR_RRA_MAX; + } + + if (attr_mask & (IB_QP_ACCESS_FLAGS | IB_QP_MAX_DEST_RD_ATOMIC)) { + context->params2 |= to_mlx4_access_flags(qp, attr, attr_mask); + optpar |= MLX4_QP_OPTPAR_RWE | MLX4_QP_OPTPAR_RRE | MLX4_QP_OPTPAR_RAE; + } + + if (ibqp->srq) + context->params2 |= cpu_to_be32(MLX4_QP_BIT_RIC); + + if (attr_mask & IB_QP_MIN_RNR_TIMER) { + context->rnr_nextrecvpsn |= cpu_to_be32(attr->min_rnr_timer << 24); + optpar |= MLX4_QP_OPTPAR_RNR_TIMEOUT; + } + if (attr_mask & IB_QP_RQ_PSN) + context->rnr_nextrecvpsn |= cpu_to_be32(attr->rq_psn); + + context->cqn_recv = cpu_to_be32(to_mcq(ibqp->recv_cq)->mcq.cqn); + + if (attr_mask & IB_QP_QKEY) { + context->qkey = cpu_to_be32(attr->qkey); + optpar |= MLX4_QP_OPTPAR_Q_KEY; + } + + if (ibqp->srq) + context->srqn = cpu_to_be32(1 << 24 | to_msrq(ibqp->srq)->msrq.srqn); + + if (!ibqp->srq && cur_state == XIB_QPS_RESET && new_state == XIB_QPS_INIT) + context->db_rec_addr = cpu_to_be64(qp->db.dma.da); + + if (cur_state == XIB_QPS_INIT && + new_state == XIB_QPS_RTR && + (ibqp->qp_type == IB_QPT_GSI || ibqp->qp_type == IB_QPT_SMI || + ibqp->qp_type == IB_QPT_UD)) { + context->pri_path.sched_queue = (qp->port - 1) << 6; + if (is_qp0(dev, qp)) + context->pri_path.sched_queue |= MLX4_IB_DEFAULT_QP0_SCHED_QUEUE; + else + context->pri_path.sched_queue |= MLX4_IB_DEFAULT_SCHED_QUEUE; + } + + if (cur_state == XIB_QPS_RTS && new_state == XIB_QPS_SQD && + attr_mask & IB_QP_EN_SQD_ASYNC_NOTIFY && attr->en_sqd_async_notify) + sqd_event = 1; + else + sqd_event = 0; + + /* + * Before passing a kernel QP to the HW, make sure that the + * ownership bits of the send queue are set and the SQ + * headroom is stamped so that the hardware doesn't start + * processing stale work requests. + */ + if (!ibqp->p_uctx && cur_state == XIB_QPS_RESET && new_state == XIB_QPS_INIT) { + struct mlx4_wqe_ctrl_seg *ctrl; + int i; + + for (i = 0; i < qp->sq.wqe_cnt; ++i) { + ctrl = get_send_wqe(qp, i); + ctrl->owner_opcode = cpu_to_be32(1 << 31); + + stamp_send_wqe(qp, i); + } + } + + err = mlx4_qp_modify(dev->dev, &qp->mtt, to_mlx4_state(cur_state), + to_mlx4_state(new_state), context, optpar, + sqd_event, &qp->mqp); + if (err) + goto out; + + qp->state = new_state; + + if (attr_mask & IB_QP_ACCESS_FLAGS) + qp->atomic_rd_en = (u8)attr->qp_access_flags; + if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) + qp->resp_depth = attr->max_dest_rd_atomic; + if (attr_mask & IB_QP_PORT) + qp->port = attr->port_num; + if (attr_mask & IB_QP_ALT_PATH) + qp->alt_port = attr->alt_port_num; + + if (is_sqp(dev, qp)) + store_sqp_attrs(to_msqp(qp), attr, attr_mask); + + /* + * If we moved QP0 to RTR, bring the IB link up; if we moved + * QP0 to RESET or ERROR, bring the link back down. + */ + if (is_qp0(dev, qp)) { + if (cur_state != XIB_QPS_RTR && new_state == XIB_QPS_RTR) + if (mlx4_INIT_PORT(dev->dev, qp->port)) + printk(KERN_WARNING "INIT_PORT failed for port %d\n", + qp->port); + + if (cur_state != XIB_QPS_RESET && cur_state != XIB_QPS_ERR && + (new_state == XIB_QPS_RESET || new_state == XIB_QPS_ERR)) + mlx4_CLOSE_PORT(dev->dev, qp->port); + } + + /* + * If we moved a kernel QP to RESET, clean up all old CQ + * entries and reinitialize the QP. + */ + if (new_state == XIB_QPS_RESET && !ibqp->p_uctx) { + mlx4_ib_cq_clean(to_mcq(ibqp->recv_cq), qp->mqp.qpn, + ibqp->srq ? to_msrq(ibqp->srq): NULL); + if (ibqp->send_cq != ibqp->recv_cq) + mlx4_ib_cq_clean(to_mcq(ibqp->send_cq), qp->mqp.qpn, NULL); + + qp->rq.head = 0; + qp->rq.tail = 0; + qp->sq.head = 0; + qp->sq.tail = 0; + if (!ibqp->srq) + *qp->db.db = 0; + } + +out: + kfree(context); + return err; +} + +static struct ib_qp_attr mlx4_ib_qp_attr; +static int mlx4_ib_qp_attr_mask_table[IB_QPT_UD + 1]; + +void mlx4_ib_qp_init() +{ + memset( &mlx4_ib_qp_attr, 0, sizeof(mlx4_ib_qp_attr) ); + mlx4_ib_qp_attr.port_num = 1; + + memset( &mlx4_ib_qp_attr_mask_table, 0, sizeof(mlx4_ib_qp_attr_mask_table) ); + mlx4_ib_qp_attr_mask_table[IB_QPT_UD] = (IB_QP_PKEY_INDEX | + IB_QP_PORT | + IB_QP_QKEY); + mlx4_ib_qp_attr_mask_table[IB_QPT_UC] = (IB_QP_PKEY_INDEX | + IB_QP_PORT | + IB_QP_ACCESS_FLAGS); + mlx4_ib_qp_attr_mask_table[IB_QPT_RC] = (IB_QP_PKEY_INDEX | + IB_QP_PORT | + IB_QP_ACCESS_FLAGS); + mlx4_ib_qp_attr_mask_table[IB_QPT_SMI] = (IB_QP_PKEY_INDEX | + IB_QP_QKEY); + mlx4_ib_qp_attr_mask_table[IB_QPT_GSI] = (IB_QP_PKEY_INDEX | + IB_QP_QKEY); +} + +int mlx4_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, + int attr_mask, struct ib_udata *udata) +{ + struct mlx4_ib_dev *dev = to_mdev(ibqp->device); + struct mlx4_ib_qp *qp = to_mqp(ibqp); + enum ib_qp_state cur_state, new_state; + int err = -EINVAL; + + UNUSED_PARAM(udata); + + if (mlx4_is_barred(dev->dev)) + return -EFAULT; + + mutex_lock(&qp->mutex); + + cur_state = attr_mask & IB_QP_CUR_STATE ? attr->cur_qp_state : qp->state; + new_state = attr_mask & IB_QP_STATE ? attr->qp_state : cur_state; + + if (!ib_modify_qp_is_ok(cur_state, new_state, ibqp->qp_type, attr_mask)) + goto out; + + if ((attr_mask & IB_QP_PORT) && + (attr->port_num == 0 || attr->port_num > dev->dev->caps.num_ports)) { + goto out; + } + + if (attr_mask & IB_QP_PKEY_INDEX) { + int p = attr_mask & IB_QP_PORT ? attr->port_num : qp->port; + if (attr->pkey_index >= dev->dev->caps.pkey_table_len[p]) + goto out; + } + + if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC && + attr->max_rd_atomic > dev->dev->caps.max_qp_init_rdma) { + goto out; + } + + if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC && + attr->max_dest_rd_atomic > dev->dev->caps.max_qp_dest_rdma) { + goto out; + } + + if (cur_state == new_state && cur_state == XIB_QPS_RESET) { + err = 0; + goto out; + } + + if (cur_state == XIB_QPS_RESET && new_state == XIB_QPS_ERR) { + err = __mlx4_ib_modify_qp(ibqp, &mlx4_ib_qp_attr, + mlx4_ib_qp_attr_mask_table[ibqp->qp_type], + XIB_QPS_RESET, XIB_QPS_INIT); + if (err) + goto out; + cur_state = XIB_QPS_INIT; + } + + err = __mlx4_ib_modify_qp(ibqp, attr, attr_mask, cur_state, new_state); + +out: + mutex_unlock(&qp->mutex); + return err; +} + +static enum ib_wr_opcode to_wr_opcode(struct _ib_send_wr *wr) +{ + + enum ib_wr_opcode opcode = -1; //= wr->wr_type; + + switch (wr->wr_type) { + case WR_SEND: + opcode = (wr->send_opt & IB_SEND_OPT_IMMEDIATE) ? IB_WR_SEND_WITH_IMM : IB_WR_SEND; + break; + case WR_LSO: + opcode = IB_WR_LSO; + break; + case WR_RDMA_WRITE: + opcode = (wr->send_opt & IB_SEND_OPT_IMMEDIATE) ? IB_WR_RDMA_WRITE_WITH_IMM : IB_WR_RDMA_WRITE; + break; + case WR_RDMA_READ: + opcode = IB_WR_RDMA_READ; + break; + case WR_COMPARE_SWAP: + opcode = IB_WR_ATOMIC_CMP_AND_SWP; + break; + case WR_FETCH_ADD: + opcode = IB_WR_ATOMIC_FETCH_AND_ADD; + break; + case WR_NOP: + opcode = IB_WR_NOP; + break; + } + return opcode; +} + + + + +static int build_mlx_header(struct mlx4_ib_sqp *sqp, ib_send_wr_t *wr, + void *wqe, unsigned *mlx_seg_len) +{ + enum ib_wr_opcode opcode = to_wr_opcode(wr); + struct ib_device *ib_dev = &to_mdev(sqp->qp.ibqp.device)->ib_dev; + struct mlx4_wqe_mlx_seg *mlx = wqe; + struct mlx4_wqe_inline_seg *inl = (void*)((u8*)wqe + sizeof *mlx); + struct mlx4_ib_ah *ah = to_mah((struct ib_ah *)wr->dgrm.ud.h_av); + u16 pkey; + int send_size; + int header_size; + int spc; + u16 i; + struct ib_ud_header *ib = NULL; + struct eth_ud_header *eth = NULL; + struct ib_unpacked_grh *grh; + struct ib_unpacked_bth *bth; + struct ib_unpacked_deth *deth; + u8 *tmp; + u8 mac[6]; + + send_size = 0; + for (i = 0; i < wr->num_ds; ++i) + send_size += wr->ds_array[i].length; + + if (rdma_port_get_transport(sqp->qp.ibqp.device, sqp->qp.port) == RDMA_TRANSPORT_IB) { + + ib = &sqp->hdr.ib; + grh = &ib->grh; + bth = &ib->bth; + deth = &ib->deth; + ib_ud_header_init(send_size, mlx4_ib_ah_grh_present(ah), ib); + ib->lrh.service_level = + (u8)(be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) >> 28); + ib->lrh.destination_lid = ah->av.ib.dlid; + ib->lrh.source_lid = cpu_to_be16(ah->av.ib.g_slid & 0x7f); + } else { + eth = &sqp->hdr.eth; + grh = ð->grh; + bth = ð->bth; + deth = ð->deth; + ib_rdmaoe_ud_header_init(send_size, mlx4_ib_ah_grh_present(ah), eth); + } + + + if (mlx4_ib_ah_grh_present(ah)) { + grh->traffic_class = + (u8)((be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) >> 20) & 0xff); + grh->flow_label = + ah->av.ib.sl_tclass_flowlabel & cpu_to_be32(0xfffff); + grh->hop_limit = ah->av.ib.hop_limit; + ib_get_cached_gid(ib_dev, (u8)(be32_to_cpu(ah->av.ib.port_pd) >> 24), + ah->av.ib.gid_index, &grh->source_gid); + memcpy(grh->destination_gid.raw, + ah->av.ib.dgid, 16); + } + + mlx->flags &= cpu_to_be32(MLX4_WQE_CTRL_CQ_UPDATE); + + if (ib) { + mlx->flags |= cpu_to_be32((!sqp->qp.ibqp.qp_num ? MLX4_WQE_MLX_VL15 : 0) | + (ib->lrh.destination_lid == + IB_LID_PERMISSIVE ? MLX4_WQE_MLX_SLR : 0) | + (ib->lrh.service_level << 8)); + mlx->rlid = ib->lrh.destination_lid; + + } + + switch (opcode) { + case IB_WR_SEND: + bth->opcode = IB_OPCODE_UD_SEND_ONLY; + if (ib) + ib->immediate_present = 0; + else + eth->immediate_present = 0; + break; + case IB_WR_SEND_WITH_IMM: + bth->opcode = IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE; + if (ib) { + ib->immediate_present = 1; + ib->immediate_data = wr->immediate_data; + } else { + eth->immediate_present = 1; + eth->immediate_data = wr->immediate_data; + } + break; + default: + return -EINVAL; + } + + if (ib) { + ib->lrh.virtual_lane = !sqp->qp.ibqp.qp_num ? 15 : 0; + if (ib->lrh.destination_lid == IB_LID_PERMISSIVE) + ib->lrh.source_lid = IB_LID_PERMISSIVE; + } else { + memcpy(eth->eth.dmac_h, ah->av.eth.mac_0_1, 2); + memcpy(eth->eth.dmac_h + 2, ah->av.eth.mac_2_5, 2); + memcpy(eth->eth.dmac_l, ah->av.eth.mac_2_5 + 2, 2); + rdma_get_ll_mac((struct in6_addr *)&grh->source_gid, mac); + + tmp = mac; + memcpy(eth->eth.smac_h, tmp, 2); + memcpy(eth->eth.smac_l, tmp + 2, 4); + eth->eth.type = cpu_to_be16(MLX4_RDMAOE_ETHERTYPE); + } + + bth->solicited_event = (u8)(!!(wr->send_opt & IB_SEND_SOLICITED)); + + if (!sqp->qp.ibqp.qp_num) + ib_get_cached_pkey(ib_dev, sqp->qp.port, sqp->pkey_index, &pkey); + else + ib_get_cached_pkey(ib_dev, sqp->qp.port, wr->dgrm.ud.pkey_index, &pkey); + bth->pkey = pkey; + bth->destination_qpn = wr->dgrm.ud.remote_qp; + bth->psn = cpu_to_be32((sqp->send_psn++) & ((1 << 24) - 1)); + deth->qkey = wr->dgrm.ud.remote_qkey & 0x80000000 ? + cpu_to_be32(sqp->qkey) : wr->dgrm.ud.remote_qkey; + deth->source_qpn = cpu_to_be32(sqp->qp.ibqp.qp_num); + + if (ib) + header_size = ib_ud_header_pack(ib, sqp->header_buf); + else + header_size = rdmaoe_ud_header_pack(eth, sqp->header_buf); + +#if 0 + { + printk(KERN_ERR "built UD header of size %d:\n", header_size); + for (i = 0; i < header_size / 4; ++i) { + if (i % 8 == 0) + printk(" [%02x] ", i * 4); + printk(" %08x", + be32_to_cpu(((__be32 *) sqp->header_buf)[i])); + if ((i + 1) % 8 == 0) + printk("\n"); + } + printk("\n"); + } +#endif + + /* + * Inline data segments may not cross a 64 byte boundary. If + * our UD header is bigger than the space available up to the + * next 64 byte boundary in the WQE, use two inline data + * segments to hold the UD header. + */ + spc = MLX4_INLINE_ALIGN - + ((u32)(ULONG_PTR)(inl + 1) & (MLX4_INLINE_ALIGN - 1)); + if (header_size <= spc) { + inl->byte_count = cpu_to_be32(1 << 31 | header_size); + memcpy(inl + 1, sqp->header_buf, header_size); + i = 1; + } else { + inl->byte_count = cpu_to_be32(1 << 31 | spc); + memcpy(inl + 1, sqp->header_buf, spc); + + inl = (void*)((u8*)(inl + 1) + spc); + memcpy(inl + 1, sqp->header_buf + spc, header_size - spc); + /* + * Need a barrier here to make sure all the data is + * visible before the byte_count field is set. + * Otherwise the HCA prefetcher could grab the 64-byte + * chunk with this inline segment and get a valid (!= + * 0xffffffff) byte count but stale data, and end up + * generating a packet with bad headers. + * + * The first inline segment's byte_count field doesn't + * need a barrier, because it comes after a + * control/MLX segment and therefore is at an offset + * of 16 mod 64. + */ + wmb(); + inl->byte_count = cpu_to_be32(1 << 31 | (header_size - spc)); + i = 2; + } + + *mlx_seg_len = + ALIGN(i * sizeof (struct mlx4_wqe_inline_seg) + header_size, 16); + return 0; + +} + +static int mlx4_wq_overflow(struct mlx4_ib_wq *wq, int nreq, struct ib_cq *ib_cq) +{ + unsigned cur; + struct mlx4_ib_cq *cq; + + cur = wq->head - wq->tail; + if (likely((int)cur + nreq < wq->max_post)) + return 0; + + cq = to_mcq(ib_cq); + spin_lock(&cq->lock); + cur = wq->head - wq->tail; + spin_unlock(&cq->lock); + + return (int)cur + nreq >= wq->max_post; +} + +static __always_inline void set_raddr_seg(struct mlx4_wqe_raddr_seg *rseg, + u64 remote_addr, __be32 rkey) +{ + rseg->raddr = cpu_to_be64(remote_addr); + rseg->rkey = rkey; + rseg->reserved = 0; +} + +static void set_atomic_seg(struct mlx4_wqe_atomic_seg *aseg, ib_send_wr_t *wr) +{ + if (wr->wr_type == WR_COMPARE_SWAP) { + aseg->swap_add = wr->remote_ops.atomic2; + aseg->compare = wr->remote_ops.atomic1; + } else { + aseg->swap_add = wr->remote_ops.atomic1; + aseg->compare = 0; + } + +} + +static void set_datagram_seg(struct mlx4_wqe_datagram_seg *dseg, + ib_send_wr_t *wr) +{ + + memcpy(dseg->av, &to_mah((struct ib_ah *)wr->dgrm.ud.h_av)->av, sizeof (struct mlx4_av)); + dseg->dqpn = wr->dgrm.ud.remote_qp; + dseg->qkey = wr->dgrm.ud.remote_qkey; + dseg->vlan = to_mah((struct ib_ah *)wr->dgrm.ud.h_av)->av.eth.vlan; + memcpy(dseg->mac_0_1, to_mah((struct ib_ah *)wr->dgrm.ud.h_av)->av.eth.mac_0_1, 6); + +} + +static void set_mlx_icrc_seg(void *dseg) +{ + u32 *t = dseg; + struct mlx4_wqe_inline_seg *iseg = dseg; + + t[1] = 0; + + /* + * Need a barrier here before writing the byte_count field to + * make sure that all the data is visible before the + * byte_count field is set. Otherwise, if the segment begins + * a new cacheline, the HCA prefetcher could grab the 64-byte + * chunk and get a valid (!= * 0xffffffff) byte count but + * stale data, and end up sending the wrong data. + */ + wmb(); + + iseg->byte_count = cpu_to_be32((1 << 31) | 4); +} + +static void set_data_seg(struct mlx4_wqe_data_seg *dseg, ib_local_ds_t *sg) +{ + dseg->lkey = cpu_to_be32(sg->lkey); + dseg->addr = cpu_to_be64(sg->vaddr); + + /* + * Need a barrier here before writing the byte_count field to + * make sure that all the data is visible before the + * byte_count field is set. Otherwise, if the segment begins + * a new cacheline, the HCA prefetcher could grab the 64-byte + * chunk and get a valid (!= * 0xffffffff) byte count but + * stale data, and end up sending the wrong data. + */ + wmb(); + + dseg->byte_count = cpu_to_be32(sg->length); +} + +static void __set_data_seg(struct mlx4_wqe_data_seg *dseg, ib_local_ds_t *sg) +{ + dseg->byte_count = cpu_to_be32(sg->length); + dseg->lkey = cpu_to_be32(sg->lkey); + dseg->addr = cpu_to_be64(sg->vaddr); +} + +static int build_lso_seg(struct mlx4_lso_seg *wqe, ib_send_wr_t *wr, + struct mlx4_ib_qp *qp, unsigned *lso_seg_len) + { + unsigned halign = ALIGN(sizeof *wqe + wr->dgrm.ud.hlen, 16); + void * ds; + /* + * This is a temporary limitation and will be removed in + a forthcoming FW release: + */ + if (unlikely(halign > 64)) + return -EINVAL; + + if (unlikely(!(qp->flags & MLX4_IB_QP_LSO) && + wr->num_ds > qp->sq.max_gs - (halign >> 4))) + return -EINVAL; + *lso_seg_len = halign; + ds = (u8 *) (void *) wqe + halign; + + //TODO: use memcpy from physical/virtual addr we can get directly from the ipoib at first data segmentmemcpy(wqe->header, , ); + memcpy(wqe->header, wr->dgrm.ud.header, wr->dgrm.ud.hlen); + + /* make sure LSO header is written before overwriting stamping */ + wmb(); + + wqe->mss_hdr_size = cpu_to_be32((wr->dgrm.ud.mss - wr->dgrm.ud.hlen) << 16 | + wr->dgrm.ud.hlen); + + return 0; +} + + +int mlx4_ib_post_send(struct ib_qp *ibqp, ib_send_wr_t *wr, + ib_send_wr_t **bad_wr) +{ + enum ib_wr_opcode opcode;// = to_wr_opcode(wr); + struct mlx4_ib_qp *qp = to_mqp(ibqp); + struct mlx4_dev *dev = to_mdev(ibqp->device)->dev; + u8 *wqe /*, *wqe_start*/; + struct mlx4_wqe_ctrl_seg *ctrl; + struct mlx4_wqe_data_seg *dseg; + unsigned long flags; + int nreq; + int err = 0; + int ind; + int size; + unsigned seglen; + int i; + int j = 0; + + if (mlx4_is_barred(ibqp->device->dma_device)) + return -EFAULT; + + spin_lock_irqsave(&qp->sq.lock, &flags); + + ind = qp->sq.head; + + for (nreq = 0; wr; ++nreq, wr = wr->p_next) { + if (mlx4_wq_overflow(&qp->sq, nreq, qp->ibqp.send_cq)) { + err = -ENOMEM; + if (bad_wr) + *bad_wr = wr; + goto out; + } + + if (unlikely(wr->num_ds > (u32)qp->sq.max_gs)) { + err = -EINVAL; + if (bad_wr) + *bad_wr = wr; + goto out; + } + + /*wqe_start = */ + wqe = get_send_wqe(qp, ind & (qp->sq.wqe_cnt - 1)); + ctrl = (void*)wqe; + qp->sq.wrid[ind & (qp->sq.wqe_cnt - 1)] = wr->wr_id; + opcode = to_wr_opcode(wr); + + ctrl->srcrb_flags = + (wr->send_opt & IB_SEND_OPT_SIGNALED ? + cpu_to_be32(MLX4_WQE_CTRL_CQ_UPDATE) : 0) | + (wr->send_opt & IB_SEND_OPT_SOLICITED ? + cpu_to_be32(MLX4_WQE_CTRL_SOLICITED) : 0) | + (wr->send_opt & IB_SEND_OPT_TX_IP_CSUM ? + cpu_to_be32(MLX4_WQE_CTRL_IP_CSUM) : 0) | + (wr->send_opt & IB_SEND_OPT_TX_TCP_UDP_CSUM ? + cpu_to_be32(MLX4_WQE_CTRL_TCP_UDP_CSUM) : 0) | + qp->sq_signal_bits; + + if (opcode == IB_WR_SEND_WITH_IMM || + opcode == IB_WR_RDMA_WRITE_WITH_IMM) + ctrl->imm = wr->immediate_data; + else + ctrl->imm = 0; + + wqe += sizeof *ctrl; + size = sizeof *ctrl / 16; + + switch (ibqp->qp_type) { + case IB_QPT_RC: + case IB_QPT_UC: + switch (opcode) { + case IB_WR_ATOMIC_CMP_AND_SWP: + case IB_WR_ATOMIC_FETCH_AND_ADD: + set_raddr_seg((void*)wqe, wr->remote_ops.vaddr, + wr->remote_ops.rkey); + wqe += sizeof (struct mlx4_wqe_raddr_seg); + + set_atomic_seg((void*)wqe, wr); + wqe += sizeof (struct mlx4_wqe_atomic_seg); + + size += (sizeof (struct mlx4_wqe_raddr_seg) + + sizeof (struct mlx4_wqe_atomic_seg)) / 16; + + break; + + case IB_WR_RDMA_READ: + case IB_WR_RDMA_WRITE: + case IB_WR_RDMA_WRITE_WITH_IMM: + set_raddr_seg((void*)wqe, wr->remote_ops.vaddr, + wr->remote_ops.rkey); + wqe += sizeof (struct mlx4_wqe_raddr_seg); + size += sizeof (struct mlx4_wqe_raddr_seg) / 16; + break; + + default: + /* No extra segments required for sends */ + break; + } + break; + + case IB_QPT_UD: + set_datagram_seg((void*)wqe, wr); + wqe += sizeof (struct mlx4_wqe_datagram_seg); + size += sizeof (struct mlx4_wqe_datagram_seg) / 16; + if (wr->wr_type == WR_LSO) { + err = build_lso_seg((struct mlx4_lso_seg *)(void *)wqe, wr, qp, &seglen); + if (unlikely(err)) { + *bad_wr = wr; + goto out; + } +#define I64_CACHE_LINE 64 +#define OPCODE_INVALID_BIT 6 + // WQE bug treatment for LSO case + // If LSO segment is large enough (exceeds one cache block in size) + // or if it small enough such that S/G element will be placed within the same cache block, + // OPCODE_INVALID_BIT should be on in order to reread this WQE + // More correct solution is + // (unlikely (seglen % I64_CACHE_LINE || seglen % (I64_CACHE_LINE-2) )) + // but it will not be used in order to reduce calculations within Datapath + // If LSO segment consists of 15 DWORDS, S/G elements block will nevertheless start from + // the next cache block + if (unlikely (seglen < I64_CACHE_LINE-4 || seglen > I64_CACHE_LINE )) + ctrl->owner_opcode |= cpu_to_be32 ( 1 << OPCODE_INVALID_BIT); + wqe += seglen; + size += seglen / 16; + j=1; + } + break; + + case IB_QPT_SMI: + case IB_QPT_GSI: + err = build_mlx_header(to_msqp(qp), wr, ctrl, &seglen); + if (err < 0) { + if (bad_wr) + *bad_wr = wr; + goto out; + } + wqe += seglen; + size += seglen / 16; + err = 0; + break; + + default: + break; + } + + /* + * Write data segments in reverse order, so as to + * overwrite cacheline stamp last within each + * cacheline. This avoids issues with WQE + * prefetching. + */ + + dseg = (void*)wqe; + dseg += wr->num_ds - 1; + size += wr->num_ds * (sizeof (struct mlx4_wqe_data_seg) / 16); + + /* Add one more inline data segment for ICRC for MLX sends */ + if (unlikely(qp->ibqp.qp_type == IB_QPT_SMI || + qp->ibqp.qp_type == IB_QPT_GSI)) { + set_mlx_icrc_seg(dseg + 1); + size += sizeof (struct mlx4_wqe_data_seg) / 16; + } + + for (i = wr->num_ds - 1; i >= 0; --i, --dseg) + set_data_seg(dseg, wr->ds_array + i); + + ctrl->fence_size = (u8)((wr->send_opt & IB_SEND_OPT_FENCE ? + MLX4_WQE_CTRL_FENCE : 0) | size); + + /* + * Make sure descriptor is fully written before + * setting ownership bit (because HW can start + * executing as soon as we do). + */ + wmb(); + + if (opcode < 0 || opcode >= ARRAY_SIZE(mlx4_ib_opcode)) { + err = -EINVAL; + goto out; + } + + ctrl->owner_opcode = mlx4_ib_opcode[opcode] | + (ind & qp->sq.wqe_cnt ? cpu_to_be32(1 << 31) : 0); + + // statistics + if ( ibqp->qp_type == IB_QPT_SMI || ibqp->qp_type == IB_QPT_GSI ) { + st_print_mlx_send( dev, ibqp, wr); + st_print_mlx_header( dev, to_msqp(qp), (void*)ctrl ); + st_dump_mlx_wqe( dev, ctrl, size*4, wr); + } + + /* + * We can improve latency by not stamping the last + * send queue WQE until after ringing the doorbell, so + * only stamp here if there are still more WQEs to post. + */ + if (wr->p_next) + stamp_send_wqe(qp, (ind + qp->sq_spare_wqes) & + (qp->sq.wqe_cnt - 1)); + + ++ind; + } + +//printk("ctrl->srcrb_flags & MLX4_WQE_CTRL_TCP_UDP_CSUM =%d \n", ctrl->srcrb_flags & cpu_to_be32(MLX4_WQE_CTRL_TCP_UDP_CSUM )); + +out: +//WQE printout +#if 0 + if (j) { + u32 *ds = (u32 *) wqe_start; + printk("WQE DUMP:\n");cq.c.their + for (j = 0; j < ctrl->fence_size*4; ++j) { + printk("%d %08x\n", j,be32_to_cpu(*ds)); + ++ds; + } + } +#endif + if (likely(nreq)) { + qp->sq.head += nreq; + + /* + * Make sure that descriptors are written before + * doorbell record. + */ + wmb(); + + writel(qp->doorbell_qpn, + (u8*)to_mdev(ibqp->device)->uar_map + MLX4_SEND_DOORBELL); + +#if 0 + if (qp->mqp.qpn == 0x41) + cl_dbg_out( "[MLX4_BUS] mlx4_ib_post_send : qtype %d, qpn %#x, nreq %d, sq.head %#x, wqe_ix %d, db %p \n", + ibqp->qp_type, qp->mqp.qpn, nreq, qp->sq.head, ind, + (u8*)to_mdev(ibqp->device)->uar_map + MLX4_SEND_DOORBELL ); +#endif + /* + * Make sure doorbells don't leak out of SQ spinlock + * and reach the HCA out of order. + */ + mmiowb(); + + stamp_send_wqe(qp, (ind + qp->sq_spare_wqes - 1) & + (qp->sq.wqe_cnt - 1)); + } + + spin_unlock_irqrestore(&qp->sq.lock, flags); + + return err; +} + +int mlx4_ib_post_recv(struct ib_qp *ibqp, ib_recv_wr_t *wr, + ib_recv_wr_t **bad_wr) +{ + struct mlx4_ib_qp *qp = to_mqp(ibqp); + struct mlx4_wqe_data_seg *scat; + unsigned long flags; + int err = 0; + int nreq; + int ind; + int i; + + if (mlx4_is_barred(ibqp->device->dma_device)) + return -EFAULT; + + spin_lock_irqsave(&qp->rq.lock, &flags); + + ind = qp->rq.head & (qp->rq.wqe_cnt - 1); + + for (nreq = 0; wr; ++nreq, wr = wr->p_next) { + if (mlx4_wq_overflow(&qp->rq, nreq, qp->ibqp.send_cq)) { + err = -ENOMEM; + if (bad_wr) + *bad_wr = wr; + goto out; + } + + if (unlikely(wr->num_ds > (u32)qp->rq.max_gs)) { + err = -EINVAL; + if (bad_wr) + *bad_wr = wr; + goto out; + } + + scat = get_recv_wqe(qp, ind); + + for (i = 0; i < (int)wr->num_ds; ++i) + __set_data_seg(scat + i, wr->ds_array + i); + + if (i < qp->rq.max_gs) { + scat[i].byte_count = 0; + scat[i].lkey = cpu_to_be32(MLX4_INVALID_LKEY); + scat[i].addr = 0; + } + + qp->rq.wrid[ind] = wr->wr_id; + + ind = (ind + 1) & (qp->rq.wqe_cnt - 1); + } + +out: + if (likely(nreq)) { + qp->rq.head += nreq; + + /* + * Make sure that descriptors are written before + * doorbell record. + */ + wmb(); + + *qp->db.db = cpu_to_be32(qp->rq.head & 0xffff); + +#if 0 + if (qp->mqp.qpn == 0x41) + cl_dbg_out( "[MLX4_BUS] mlx4_ib_post_recv : qtype %d, qpn %#x, nreq %d, rq.head %#x, wqe_ix %d, db_obj %p, db %p \n", + ibqp->qp_type, qp->mqp.qpn, nreq, qp->rq.head, ind, &qp->db, qp->db.db ); +#endif + } + + spin_unlock_irqrestore(&qp->rq.lock, flags); + + return err; +} + +static inline enum ib_qp_state to_ib_qp_state(enum mlx4_qp_state mlx4_state) +{ + switch (mlx4_state) { + case MLX4_QP_STATE_RST: return XIB_QPS_RESET; + case MLX4_QP_STATE_INIT: return XIB_QPS_INIT; + case MLX4_QP_STATE_RTR: return XIB_QPS_RTR; + case MLX4_QP_STATE_RTS: return XIB_QPS_RTS; + case MLX4_QP_STATE_SQ_DRAINING: + case MLX4_QP_STATE_SQD: return XIB_QPS_SQD; + case MLX4_QP_STATE_SQER: return XIB_QPS_SQE; + case MLX4_QP_STATE_ERR: return XIB_QPS_ERR; + default: return -1; + } +} + +static inline enum ib_mig_state to_ib_mig_state(int mlx4_mig_state) +{ + switch (mlx4_mig_state) { + case MLX4_QP_PM_ARMED: return IB_MIG_ARMED; + case MLX4_QP_PM_REARM: return IB_MIG_REARM; + case MLX4_QP_PM_MIGRATED: return IB_MIG_MIGRATED; + default: return -1; + } +} + +static int to_ib_qp_access_flags(int mlx4_flags) +{ + int ib_flags = 0; + + if (mlx4_flags & MLX4_QP_BIT_RRE) + ib_flags |= IB_ACCESS_REMOTE_READ; + if (mlx4_flags & MLX4_QP_BIT_RWE) + ib_flags |= IB_ACCESS_REMOTE_WRITE; + if (mlx4_flags & MLX4_QP_BIT_RAE) + ib_flags |= IB_ACCESS_REMOTE_ATOMIC; + + return ib_flags; +} + +static void to_ib_ah_attr(struct mlx4_dev *dev, struct ib_ah_attr *ib_ah_attr, + struct mlx4_qp_path *path) +{ + memset(ib_ah_attr, 0, sizeof *ib_ah_attr); + ib_ah_attr->port_num = path->sched_queue & 0x40 ? 2 : 1; + + if (ib_ah_attr->port_num == 0 || ib_ah_attr->port_num > dev->caps.num_ports) + return; + + ib_ah_attr->dlid = be16_to_cpu(path->rlid); + ib_ah_attr->sl = (path->sched_queue >> 2) & 0xf; + ib_ah_attr->src_path_bits = path->grh_mylmc & 0x7f; + ib_ah_attr->static_rate = path->static_rate ? path->static_rate - 5 : 0; + ib_ah_attr->ah_flags = (path->grh_mylmc & (1 << 7)) ? IB_AH_GRH : 0; + if (ib_ah_attr->ah_flags) { + ib_ah_attr->grh.sgid_index = path->mgid_index; + ib_ah_attr->grh.hop_limit = path->hop_limit; + ib_ah_attr->grh.traffic_class = + (u8)((be32_to_cpu(path->tclass_flowlabel) >> 20) & 0xff); + ib_ah_attr->grh.flow_label = + be32_to_cpu(path->tclass_flowlabel) & 0xfffff; + memcpy(ib_ah_attr->grh.dgid.raw, + path->rgid, sizeof ib_ah_attr->grh.dgid.raw); + } +} + +int mlx4_ib_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr_mask, + struct ib_qp_init_attr *qp_init_attr) +{ + struct mlx4_ib_dev *dev = to_mdev(ibqp->device); + struct mlx4_ib_qp *qp = to_mqp(ibqp); + struct mlx4_qp_context context; + int mlx4_state; + int err = 0; + + UNUSED_PARAM(qp_attr_mask); + + if (mlx4_is_barred(dev->dev)) + return -EFAULT; + + mutex_lock(&qp->mutex); + + if (qp->state == XIB_QPS_RESET) { + qp_attr->qp_state = XIB_QPS_RESET; + goto done; + } + + err = mlx4_qp_query(dev->dev, &qp->mqp, &context); + if (err) { + err = -EINVAL; + goto out; + } + + mlx4_state = be32_to_cpu(context.flags) >> 28; + + qp_attr->qp_state = to_ib_qp_state(mlx4_state); + qp_attr->path_mtu = context.mtu_msgmax >> 5; + qp_attr->path_mig_state = + to_ib_mig_state((be32_to_cpu(context.flags) >> 11) & 0x3); + qp_attr->qkey = be32_to_cpu(context.qkey); + qp_attr->rq_psn = be32_to_cpu(context.rnr_nextrecvpsn) & 0xffffff; + qp_attr->sq_psn = be32_to_cpu(context.next_send_psn) & 0xffffff; + qp_attr->dest_qp_num = be32_to_cpu(context.remote_qpn) & 0xffffff; + qp_attr->qp_access_flags = + to_ib_qp_access_flags(be32_to_cpu(context.params2)); + + if (qp->ibqp.qp_type == IB_QPT_RC || qp->ibqp.qp_type == IB_QPT_UC) { + to_ib_ah_attr(dev->dev, &qp_attr->ah_attr, &context.pri_path); + to_ib_ah_attr(dev->dev, &qp_attr->alt_ah_attr, &context.alt_path); + qp_attr->alt_pkey_index = context.alt_path.pkey_index & 0x7f; + qp_attr->alt_port_num = qp_attr->alt_ah_attr.port_num; + } + + qp_attr->pkey_index = context.pri_path.pkey_index & 0x7f; + if (qp_attr->qp_state == XIB_QPS_INIT) + qp_attr->port_num = qp->port; + else + qp_attr->port_num = context.pri_path.sched_queue & 0x40 ? 2 : 1; + + /* qp_attr->en_sqd_async_notify is only applicable in modify qp */ + qp_attr->sq_draining = (u8)(mlx4_state == MLX4_QP_STATE_SQ_DRAINING); + + qp_attr->max_rd_atomic = (u8)(1 << ((be32_to_cpu(context.params1) >> 21) & 0x7)); + + qp_attr->max_dest_rd_atomic = + (u8)(1 << ((be32_to_cpu(context.params2) >> 21) & 0x7)); + qp_attr->min_rnr_timer = + (u8)((be32_to_cpu(context.rnr_nextrecvpsn) >> 24) & 0x1f); + qp_attr->timeout = context.pri_path.ackto >> 3; + qp_attr->retry_cnt = (u8)((be32_to_cpu(context.params1) >> 16) & 0x7); + qp_attr->rnr_retry = (u8)((be32_to_cpu(context.params1) >> 13) & 0x7); + qp_attr->alt_timeout = context.alt_path.ackto >> 3; + +done: + qp_attr->cur_qp_state = qp_attr->qp_state; + qp_attr->cap.max_recv_wr = qp->rq.wqe_cnt; + qp_attr->cap.max_recv_sge = qp->rq.max_gs; + + if (!ibqp->p_uctx) { + qp_attr->cap.max_send_wr = qp->sq.wqe_cnt; + qp_attr->cap.max_send_sge = qp->sq.max_gs; + } else { + qp_attr->cap.max_send_wr = 0; + qp_attr->cap.max_send_sge = 0; + } + + /* + * We don't support inline sends for kernel QPs (yet), and we + * don't know what userspace's value should be. + */ + qp_attr->cap.max_inline_data = 0; + + qp_init_attr->cap = qp_attr->cap; + +out: + mutex_unlock(&qp->mutex); + return err; +} + diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/ib/srq.c b/branches/WOF2-3/hw/mlx4/kernel/bus/ib/srq.c new file mode 100644 index 00000000..9067e1fc --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/ib/srq.c @@ -0,0 +1,373 @@ +/* + * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "mlx4_ib.h" +#include "qp.h" +#include "srq.h" +#include "user.h" + +static void *get_wqe(struct mlx4_ib_srq *srq, int n) +{ + int offset = n << srq->msrq.wqe_shift; + + if (srq->buf.nbufs == 1) + return srq->buf.u.direct.buf + offset; + else + return srq->buf.u.page_list[offset >> PAGE_SHIFT].buf + + (offset & (PAGE_SIZE - 1)); +} + +static void mlx4_ib_srq_event(struct mlx4_srq *srq, enum mlx4_event type) +{ + ib_event_rec_t event; + struct ib_srq *ibsrq = &to_mibsrq(srq)->ibsrq; + + switch (type) { + case MLX4_EVENT_TYPE_SRQ_LIMIT: + event.type = IB_EVENT_SRQ_LIMIT_REACHED; + break; + case MLX4_EVENT_TYPE_SRQ_CATAS_ERROR: + event.type = IB_EVENT_SRQ_ERR; + break; + default: + printk(KERN_WARNING "mlx4_ib: Unexpected event type %d " + "on SRQ %06x\n", type, srq->srqn); + return; + } + + event.context = ibsrq->srq_context; + ibsrq->event_handler(&event); +} + +struct ib_srq *mlx4_ib_create_srq(struct ib_pd *pd, + struct ib_srq_init_attr *init_attr, + struct ib_udata *udata) +{ + struct mlx4_ib_dev *dev = to_mdev(pd->device); + struct mlx4_ib_srq *srq; + struct mlx4_wqe_srq_next_seg *next; + int desc_size; + int buf_size; + int err; + int i; + u32 cqn = 0; + u16 xrcd = 0; + + if (mlx4_is_barred(pd->device->dma_device)) + return ERR_PTR(-EFAULT); + + /* Sanity check SRQ size before proceeding */ + if ((int)init_attr->attr.max_wr >= dev->dev->caps.max_srq_wqes || + (int)init_attr->attr.max_sge > dev->dev->caps.max_srq_sge) + return ERR_PTR(-EINVAL); + + srq = kzalloc(sizeof *srq, GFP_KERNEL); + if (!srq) + return ERR_PTR(-ENOMEM); + + mutex_init(&srq->mutex); + spin_lock_init(&srq->lock); + srq->msrq.max = roundup_pow_of_two(init_attr->attr.max_wr + 1); + srq->msrq.max_gs = init_attr->attr.max_sge; + + desc_size = max(32UL, + roundup_pow_of_two(sizeof (struct mlx4_wqe_srq_next_seg) + + srq->msrq.max_gs * + sizeof (struct mlx4_wqe_data_seg))); + srq->msrq.wqe_shift = ilog2(desc_size); + + buf_size = srq->msrq.max * desc_size; + + if (pd->p_uctx) { + struct mlx4_ib_create_srq ucmd; + + if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd)) { + err = -EFAULT; + goto err_srq; + } + + srq->umem = ib_umem_get(pd->p_uctx, ucmd.buf_addr, + buf_size, 0, FALSE); + if (IS_ERR(srq->umem)) { + err = PTR_ERR(srq->umem); + goto err_srq; + } + + err = mlx4_mtt_init(dev->dev, ib_umem_page_count(srq->umem), + ilog2(srq->umem->page_size), &srq->mtt); + if (err) + goto err_buf; + + err = mlx4_ib_umem_write_mtt(dev, &srq->mtt, srq->umem); + if (err) + goto err_mtt; + + err = mlx4_ib_db_map_user(to_mucontext(pd->p_uctx), + ucmd.db_addr, &srq->db); + if (err) + goto err_mtt; + } else { + err = mlx4_ib_db_alloc(dev, &srq->db, 0); + if (err) + goto err_srq; + + *srq->db.db = 0; + + if (mlx4_buf_alloc(dev->dev, buf_size, PAGE_SIZE * 2, &srq->buf)) { + err = -ENOMEM; + goto err_db; + } + + srq->head = 0; + srq->tail = srq->msrq.max - 1; + srq->wqe_ctr = 0; + + for (i = 0; i < srq->msrq.max; ++i) { + next = get_wqe(srq, i); + next->next_wqe_index = + cpu_to_be16((i + 1) & (srq->msrq.max - 1)); + } + + err = mlx4_mtt_init(dev->dev, srq->buf.npages, srq->buf.page_shift, + &srq->mtt); + if (err) + goto err_buf; + + err = mlx4_buf_write_mtt(dev->dev, &srq->mtt, &srq->buf); + if (err) + goto err_mtt; + + srq->wrid = kmalloc(srq->msrq.max * sizeof (u64), GFP_KERNEL); + if (!srq->wrid) { + err = -ENOMEM; + goto err_mtt; + } + } + err = mlx4_srq_alloc(dev->dev, to_mpd(pd)->pdn, cqn, xrcd, &srq->mtt, + srq->db.dma.da, &srq->msrq); + if (err) + goto err_wrid; + + srq->msrq.event = mlx4_ib_srq_event; + + if (pd->p_uctx) + if (ib_copy_to_udata(udata, &srq->msrq.srqn, sizeof (__u32))) { + err = -EFAULT; + goto err_wrid; + } + + init_attr->attr.max_wr = srq->msrq.max - 1; + + return &srq->ibsrq; + +err_wrid: + if (pd->p_uctx) + mlx4_ib_db_unmap_user(to_mucontext(pd->p_uctx), &srq->db); + else + kfree(srq->wrid); + +err_mtt: + mlx4_mtt_cleanup(dev->dev, &srq->mtt); + +err_buf: + if (pd->p_uctx) + ib_umem_release(srq->umem); + else + mlx4_buf_free(dev->dev, buf_size, &srq->buf); + +err_db: + if (!pd->p_uctx) + mlx4_ib_db_free(dev, &srq->db); + +err_srq: + kfree(srq); + + return ERR_PTR(err); +} + +int mlx4_ib_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr, + enum ib_srq_attr_mask attr_mask, struct ib_udata *udata) +{ + struct mlx4_ib_dev *dev = to_mdev(ibsrq->device); + struct mlx4_ib_srq *srq = to_msrq(ibsrq); + int ret; + + UNUSED_PARAM(udata); + + if (mlx4_is_barred(ibsrq->device->dma_device)) + return -EFAULT; + + /* We don't support resizing SRQs (yet?) */ + if (attr_mask & XIB_SRQ_MAX_WR) + return -ENOSYS; + + if (attr_mask & XIB_SRQ_LIMIT) { + if ((int)attr->srq_limit >= srq->msrq.max) + return -ERANGE; + + mutex_lock(&srq->mutex); + ret = mlx4_srq_arm(dev->dev, &srq->msrq, attr->srq_limit); + mutex_unlock(&srq->mutex); + + if (ret) + return ret; + } + + return 0; +} + +int mlx4_ib_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *srq_attr) +{ + struct mlx4_ib_dev *dev = to_mdev(ibsrq->device); + struct mlx4_ib_srq *srq = to_msrq(ibsrq); + int ret; + int limit_watermark; + + if (mlx4_is_barred(ibsrq->device->dma_device)) + return -EFAULT; + + ret = mlx4_srq_query(dev->dev, &srq->msrq, &limit_watermark); + if (ret) + return ret; + + srq_attr->srq_limit = limit_watermark; + srq_attr->max_wr = srq->msrq.max - 1; + srq_attr->max_sge = srq->msrq.max_gs; + + return 0; +} + +int mlx4_ib_destroy_srq(struct ib_srq *srq) +{ + struct mlx4_ib_dev *dev = to_mdev(srq->device); + struct mlx4_ib_srq *msrq = to_msrq(srq); + + if (!mlx4_is_barred(dev->dev)) + mlx4_srq_invalidate(dev->dev, &msrq->msrq); + mlx4_srq_remove(dev->dev, &msrq->msrq); + + mlx4_srq_free(dev->dev, &msrq->msrq); + mlx4_mtt_cleanup(dev->dev, &msrq->mtt); + + if (srq->p_uctx) { + mlx4_ib_db_unmap_user(to_mucontext(srq->p_uctx), &msrq->db); + ib_umem_release(msrq->umem); + } else { + kfree(msrq->wrid); + mlx4_buf_free(dev->dev, msrq->msrq.max << msrq->msrq.wqe_shift, + &msrq->buf); + mlx4_ib_db_free(dev, &msrq->db); + } + + kfree(msrq); + + return 0; +} + +void mlx4_ib_free_srq_wqe(struct mlx4_ib_srq *srq, int wqe_index) +{ + struct mlx4_wqe_srq_next_seg *next; + + /* always called with interrupts disabled. */ + spin_lock(&srq->lock); + + next = get_wqe(srq, srq->tail); + next->next_wqe_index = cpu_to_be16(wqe_index); + srq->tail = wqe_index; + + spin_unlock(&srq->lock); +} + +int mlx4_ib_post_srq_recv(struct ib_srq *ibsrq, ib_recv_wr_t *wr, + ib_recv_wr_t **bad_wr) +{ + struct mlx4_ib_srq *srq = to_msrq(ibsrq); + struct mlx4_wqe_srq_next_seg *next; + struct mlx4_wqe_data_seg *scat; + unsigned long flags; + int err = 0; + int nreq; + int i; + + if (mlx4_is_barred(ibsrq->device->dma_device)) + return -EFAULT; + + spin_lock_irqsave(&srq->lock, &flags); + + for (nreq = 0; wr; ++nreq, wr = wr->p_next) { + if (unlikely(wr->num_ds > (u32)srq->msrq.max_gs)) { + err = -EINVAL; + *bad_wr = wr; + break; + } + + if (unlikely(srq->head == srq->tail)) { + err = -ENOMEM; + *bad_wr = wr; + break; + } + + srq->wrid[srq->head] = wr->wr_id; + + next = get_wqe(srq, srq->head); + srq->head = be16_to_cpu(next->next_wqe_index); + scat = (struct mlx4_wqe_data_seg *) (next + 1); + + for (i = 0; i < (int)wr->num_ds; ++i) { + scat[i].byte_count = cpu_to_be32(wr->ds_array[i].length); + scat[i].lkey = cpu_to_be32(wr->ds_array[i].lkey); + scat[i].addr = cpu_to_be64(wr->ds_array[i].vaddr); + } + + if (i < srq->msrq.max_gs) { + scat[i].byte_count = 0; + scat[i].lkey = cpu_to_be32(MLX4_INVALID_LKEY); + scat[i].addr = 0; + } + } + + if (likely(nreq)) { + srq->wqe_ctr = (u16)(srq->wqe_ctr + nreq); + + /* + * Make sure that descriptors are written before + * doorbell record. + */ + wmb(); + + *srq->db.db = cpu_to_be32(srq->wqe_ctr); + } + + spin_unlock_irqrestore(&srq->lock, flags); + + return err; +} diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/inc/bus_intf.h b/branches/WOF2-3/hw/mlx4/kernel/bus/inc/bus_intf.h new file mode 100644 index 00000000..89f452ae --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/inc/bus_intf.h @@ -0,0 +1,200 @@ +#pragma once + +#define MLX4_BUS_IB_INTERFACE_VERSION 4 + +#include +// +// Interface for work with MLX4 IB driver +// + +struct mlx4_interface; +struct mlx4_dev; +struct mlx4_cq_context; +enum mlx4_qp_state; +struct mlx4_qp_context; +enum mlx4_qp_optpar; +struct mlx4_eq; + + +typedef int (*MLX4_REGISTER_INTERFACE)(struct mlx4_interface *intf); +typedef VOID (*MLX4_UNREGISTER_INTERFACE)(struct mlx4_interface *intf); + + +int mlx4_pd_alloc(struct mlx4_dev *dev, u32 *pdn); +void mlx4_pd_free(struct mlx4_dev *dev, u32 pdn); + +typedef int (*MLX4_PD_ALLOC) (struct mlx4_dev *dev, u32 *pdn); +typedef void (*MLX4_PD_FREE)(struct mlx4_dev *dev, u32 pdn); + +typedef int (*MLX4_UAR_ALLOC)(struct mlx4_dev *dev, struct mlx4_uar *uar); +typedef void (*MLX4_UAR_FREE)(struct mlx4_dev *dev, struct mlx4_uar *uar); + +typedef int (*MLX4_MR_ALLOC)(struct mlx4_dev *dev, u32 pd, u64 iova, u64 size, u32 access, + int npages, int page_shift, struct mlx4_mr *mr); +typedef void (*MLX4_MR_FREE)(struct mlx4_dev *dev, struct mlx4_mr *mr); +typedef int (*MLX4_MR_ENABLE)(struct mlx4_dev *dev, struct mlx4_mr *mr); + +typedef int (*MLX4_QP_GET_REGION) (struct mlx4_dev *dev, enum qp_region region, int *base_qpn, int *cnt); + +typedef int (*MLX4_ALLOC_HWQ_RES)(struct mlx4_dev *dev, struct mlx4_hwq_resources *wqres, + int size, int max_direct); + +typedef void (*MLX4_FREE_HWQ_RES)(struct mlx4_dev *dev, struct mlx4_hwq_resources *wqres, + int size); + +typedef int (*MLX4_CQ_ALLOC) (struct mlx4_dev *dev, int nent, struct mlx4_mtt *mtt, + struct mlx4_uar *uar, u64 db_rec, struct mlx4_cq *cq, unsigned vector, int collapsed); + +typedef void (*MLX4_CQ_FREE) (struct mlx4_dev *dev, struct mlx4_cq *cq); + +typedef int (*MLX4_CQ_MODIFY) (struct mlx4_dev *dev, struct mlx4_cq *cq, + struct mlx4_cq_context *context, int modify); + +typedef void (*MLX4_CQ_ARM)(struct mlx4_cq *cq, u32 cmd, + void __iomem *uar_page, + spinlock_t *doorbell_lock); + +typedef int (*MLX4_REGISTER_MAC)(struct mlx4_dev *dev, u8 port, u64 mac, int *index); + +typedef void (*MLX4_UNREGISTER_MAC) (struct mlx4_dev *dev, u8 port, int index); + +typedef int (*MLX4_REGISTER_VLAN)(struct mlx4_dev *dev, u8 port, u16 vlan, int *index); + +typedef void (*MLX4_UNREGISTER_VLAN)(struct mlx4_dev *dev, u8 port, int index); + + +typedef int (*MLX4_SRQ_ALLOC) (struct mlx4_dev *dev, u32 pdn, u32 cqn, u16 xrcd, + struct mlx4_mtt *mtt, u64 db_rec, struct mlx4_srq *srq); + +typedef void (*MLX4_SRQ_FREE)(struct mlx4_dev *dev, struct mlx4_srq *srq); + +typedef void (*MLX4_SRQ_INVALIDATE)(struct mlx4_dev *dev, struct mlx4_srq *srq); + +typedef void (*MLX4_SRQ_REMOVE)(struct mlx4_dev *dev, struct mlx4_srq *srq); + +typedef int (*MLX4_QP_ALLOC)(struct mlx4_dev *dev, int qpn, struct mlx4_qp *qp); + +typedef void (*MLX4_QP_FREE)(struct mlx4_dev *dev, struct mlx4_qp *qp); + + +typedef int (*MLX4_QP_RESERVE_RANGE)(struct mlx4_dev *dev, int cnt, int align, u32 *base); + +typedef void (*MLX4_QP_RELEASE_RANGE)(struct mlx4_dev *dev, int base_qpn, int cnt); + + +typedef void (*MLX4_QP_REMOVE)(struct mlx4_dev *dev, struct mlx4_qp *qp); + +typedef int (*MLX4_QP_MODIFY)(struct mlx4_dev *dev, struct mlx4_mtt *mtt, + enum mlx4_qp_state cur_state, enum mlx4_qp_state new_state, + struct mlx4_qp_context *context, enum mlx4_qp_optpar optpar, + int sqd_event, struct mlx4_qp *qp); + +typedef int (*MLX4_QP_TO_READY)(struct mlx4_dev *dev, struct mlx4_mtt *mtt, + struct mlx4_qp_context *context, + struct mlx4_qp *qp, enum mlx4_qp_state *qp_state); + +typedef struct mlx4_cmd_mailbox *(*MLX4_ALLOC_CMD_MAILBOX)(struct mlx4_dev *dev); + +typedef void (*MLX4_FREE_CMD_MAILBOX)(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox); + +typedef int (*MLX4_CMD)(struct mlx4_dev *dev, u64 in_param, u64 *out_param, int out_is_imm, + u32 in_modifier, u8 op_modifier, u16 op, unsigned long timeout); + +typedef int (*MLX4_INIT_PORT)(struct mlx4_dev *dev, int port); +typedef int (*MLX4_CLOSE_PORT)(struct mlx4_dev *dev, int port); + + +typedef +BOOLEAN +(*PISR_FUNC)( + IN PVOID IsrContext + ); + + +typedef int (*MLX4_ADD_EQ) (struct mlx4_dev *dev, int nent, + KAFFINITY cpu, PISR_FUNC func, PVOID func_context , + u8* p_eq_num, struct mlx4_eq ** p_eq); + +typedef void (*MLX4_REMOVE_EQ) (struct mlx4_dev *dev, u8 eq_num); + +typedef int (*MLX4_REGISTER_EVENT_HANDLER) (struct ib_event_handler *event_handler); +typedef int (*MLX4_UNREGISTER_EVENT_HANDLER)(struct ib_event_handler *event_handler); + +typedef int (*MLX4_RESET_REQUEST) (struct ib_event_handler *event_handler); +typedef int (*MLX4_RESET_EXECUTE) (struct ib_event_handler *event_handler); +typedef int (*MLX4_RESET_READY) (struct ib_event_handler *event_handler); + +struct mlx4_interface_ex { + MLX4_PD_ALLOC mlx4_pd_alloc; + MLX4_PD_FREE mlx4_pd_free; + + MLX4_UAR_ALLOC mlx4_uar_alloc; + MLX4_UAR_FREE mlx4_uar_free; + + MLX4_MR_ALLOC mlx4_mr_alloc; + MLX4_MR_FREE mlx4_mr_free; + MLX4_MR_ENABLE mlx4_mr_enable; + MLX4_QP_GET_REGION mlx4_qp_get_region; + MLX4_ALLOC_HWQ_RES mlx4_alloc_hwq_res; + MLX4_FREE_HWQ_RES mlx4_free_hwq_res; + + MLX4_CQ_ALLOC mlx4_cq_alloc; + MLX4_CQ_FREE mlx4_cq_free; + MLX4_CQ_MODIFY mlx4_cq_modify; + +// Not part of the interface since it is an inlie function +// MLX4_CQ_ARM mlx4_cq_arm; + + MLX4_REGISTER_MAC mlx4_register_mac; + MLX4_UNREGISTER_MAC mlx4_unregister_mac; + + MLX4_SRQ_ALLOC mlx4_srq_alloc; + MLX4_SRQ_FREE mlx4_srq_free; + MLX4_SRQ_INVALIDATE mlx4_srq_invalidate; + MLX4_SRQ_REMOVE mlx4_srq_remove; + + MLX4_QP_ALLOC mlx4_qp_alloc; + MLX4_QP_FREE mlx4_qp_free; + MLX4_QP_REMOVE mlx4_qp_remove; + MLX4_QP_MODIFY mlx4_qp_modify; + MLX4_QP_TO_READY mlx4_qp_to_ready; + MLX4_QP_RESERVE_RANGE mlx4_qp_reserve_range; + MLX4_QP_RELEASE_RANGE mlx4_qp_release_range; + + MLX4_ALLOC_CMD_MAILBOX mlx4_alloc_cmd_mailbox; + MLX4_FREE_CMD_MAILBOX mlx4_free_cmd_mailbox; + MLX4_CMD mlx4_cmd; + + MLX4_INIT_PORT mlx4_INIT_PORT; + MLX4_CLOSE_PORT mlx4_CLOSE_PORT; + + MLX4_ADD_EQ mlx4_add_eq; + MLX4_REMOVE_EQ mlx4_remove_eq; + + MLX4_REGISTER_EVENT_HANDLER mlx4_register_ev_cb; + MLX4_UNREGISTER_EVENT_HANDLER mlx4_unregister_ev_cb; + MLX4_RESET_REQUEST mlx4_reset_request; + MLX4_RESET_EXECUTE mlx4_reset_execute; + MLX4_RESET_READY mlx4_reset_ready; + MLX4_REGISTER_VLAN mlx4_register_vlan; + MLX4_UNREGISTER_VLAN mlx4_unregister_vlan; + +}; + + +typedef struct _MLX4_BUS_IB_INTERFACE{ + INTERFACE i; + struct ib_device * p_ibdev; + struct pci_dev * pdev; + struct mlx4_dev * pmlx4_dev; + struct mlx4_interface_ex mlx4_interface; + int is_livefish; + u8 port_id; + struct VipBusIfc *pVipBusIfc; + int n_msi_vectors; + +} MLX4_BUS_IB_INTERFACE, *PMLX4_BUS_IB_INTERFACE; + + + + diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/inc/cmd.h b/branches/WOF2-3/hw/mlx4/kernel/bus/inc/cmd.h new file mode 100644 index 00000000..56e2be53 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/inc/cmd.h @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2006 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef MLX4_CMD_H +#define MLX4_CMD_H + +enum { + /* initialization and general commands */ + MLX4_CMD_SYS_EN = 0x1, + MLX4_CMD_SYS_DIS = 0x2, + MLX4_CMD_MAP_FA = 0xfff, + MLX4_CMD_UNMAP_FA = 0xffe, + MLX4_CMD_RUN_FW = 0xff6, + MLX4_CMD_MOD_STAT_CFG = 0x34, + MLX4_CMD_QUERY_DEV_CAP = 0x3, + MLX4_CMD_QUERY_FW = 0x4, + MLX4_CMD_ENABLE_LAM = 0xff8, + MLX4_CMD_DISABLE_LAM = 0xff7, + MLX4_CMD_QUERY_DDR = 0x5, + MLX4_CMD_QUERY_ADAPTER = 0x6, + MLX4_CMD_INIT_HCA = 0x7, + MLX4_CMD_CLOSE_HCA = 0x8, + MLX4_CMD_INIT_PORT = 0x9, + MLX4_CMD_CLOSE_PORT = 0xa, + MLX4_CMD_QUERY_HCA = 0xb, + MLX4_CMD_QUERY_PORT = 0x43, + MLX4_CMD_SET_PORT = 0xc, + MLX4_CMD_ACCESS_DDR = 0x2e, + MLX4_CMD_MAP_ICM = 0xffa, + MLX4_CMD_UNMAP_ICM = 0xff9, + MLX4_CMD_MAP_ICM_AUX = 0xffc, + MLX4_CMD_UNMAP_ICM_AUX = 0xffb, + MLX4_CMD_SET_ICM_SIZE = 0xffd, + + /* TPT commands */ + MLX4_CMD_SW2HW_MPT = 0xd, + MLX4_CMD_QUERY_MPT = 0xe, + MLX4_CMD_HW2SW_MPT = 0xf, + MLX4_CMD_READ_MTT = 0x10, + MLX4_CMD_WRITE_MTT = 0x11, + MLX4_CMD_SYNC_TPT = 0x2f, + + /* EQ commands */ + MLX4_CMD_MAP_EQ = 0x12, + MLX4_CMD_SW2HW_EQ = 0x13, + MLX4_CMD_HW2SW_EQ = 0x14, + MLX4_CMD_QUERY_EQ = 0x15, + + /* CQ commands */ + MLX4_CMD_SW2HW_CQ = 0x16, + MLX4_CMD_HW2SW_CQ = 0x17, + MLX4_CMD_QUERY_CQ = 0x18, + MLX4_CMD_MODIFY_CQ = 0x2c, + + /* SRQ commands */ + MLX4_CMD_SW2HW_SRQ = 0x35, + MLX4_CMD_HW2SW_SRQ = 0x36, + MLX4_CMD_QUERY_SRQ = 0x37, + MLX4_CMD_ARM_SRQ = 0x40, + + /* QP/EE commands */ + MLX4_CMD_RST2INIT_QP = 0x19, + MLX4_CMD_INIT2RTR_QP = 0x1a, + MLX4_CMD_RTR2RTS_QP = 0x1b, + MLX4_CMD_RTS2RTS_QP = 0x1c, + MLX4_CMD_SQERR2RTS_QP = 0x1d, + MLX4_CMD_2ERR_QP = 0x1e, + MLX4_CMD_RTS2SQD_QP = 0x1f, + MLX4_CMD_SQD2SQD_QP = 0x38, + MLX4_CMD_SQD2RTS_QP = 0x20, + MLX4_CMD_2RST_QP = 0x21, + MLX4_CMD_QUERY_QP = 0x22, + MLX4_CMD_INIT2INIT_QP = 0x2d, + MLX4_CMD_SUSPEND_QP = 0x32, + MLX4_CMD_UNSUSPEND_QP = 0x33, + /* special QP and management commands */ + MLX4_CMD_CONF_SPECIAL_QP = 0x23, + MLX4_CMD_MAD_IFC = 0x24, + + /* multicast commands */ + MLX4_CMD_READ_MCG = 0x25, + MLX4_CMD_WRITE_MCG = 0x26, + MLX4_CMD_MGID_HASH = 0x27, + + /* miscellaneous commands */ + MLX4_CMD_DIAG_RPRT = 0x30, + MLX4_CMD_NOP = 0x31, + MLX4_CMD_QUERY_STAT_CFG = 0x34, + + /* debug commands */ + MLX4_CMD_QUERY_DEBUG_MSG = 0x2a, + MLX4_CMD_SET_DEBUG_MSG = 0x2b, +}; + +enum { + MLX4_CMD_TIME_CLASS_A = 5000, + MLX4_CMD_TIME_CLASS_B = 5000, + MLX4_CMD_TIME_CLASS_C = 5000, +}; + +enum { + MLX4_MAILBOX_SIZE = 4096 +}; + +enum { + /* set port opcode modifiers */ + MLX4_SET_PORT_GENERAL = 0x0, + MLX4_SET_PORT_RQP_CALC = 0x1, + MLX4_SET_PORT_MAC_TABLE = 0x2, + MLX4_SET_PORT_VLAN_TABLE = 0x3, + MLX4_SET_PORT_PRIO_MAP = 0x4, + MLX4_SET_PORT_GID_TABLE = 0x5, +}; + +struct mlx4_dev; + +struct mlx4_cmd_mailbox { + void *buf; + dma_addr_t dma; +}; + +int __mlx4_cmd(struct mlx4_dev *dev, u64 in_param, u64 *out_param, + int out_is_imm, u32 in_modifier, u8 op_modifier, + u16 op, unsigned long timeout); + +/* Invoke a command with no output parameter */ +static inline int mlx4_cmd(struct mlx4_dev *dev, u64 in_param, u32 in_modifier, + u8 op_modifier, u16 op, unsigned long timeout) +{ + return __mlx4_cmd(dev, in_param, NULL, 0, in_modifier, + op_modifier, op, timeout); +} + +/* Invoke a command with an output mailbox */ +static inline int mlx4_cmd_box(struct mlx4_dev *dev, u64 in_param, u64 out_param, + u32 in_modifier, u8 op_modifier, u16 op, + unsigned long timeout) +{ + return __mlx4_cmd(dev, in_param, &out_param, 0, in_modifier, + op_modifier, op, timeout); +} + +/* + * Invoke a command with an immediate output parameter (and copy the + * output into the caller's out_param pointer after the command + * executes). + */ +static inline int mlx4_cmd_imm(struct mlx4_dev *dev, u64 in_param, u64 *out_param, + u32 in_modifier, u8 op_modifier, u16 op, + unsigned long timeout) +{ + return __mlx4_cmd(dev, in_param, out_param, 1, in_modifier, + op_modifier, op, timeout); +} + +struct mlx4_cmd_mailbox *mlx4_alloc_cmd_mailbox(struct mlx4_dev *dev); +void mlx4_free_cmd_mailbox(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox); + +int imlx4_cmd(struct mlx4_dev *dev, u64 in_param, u64 *out_param, int out_is_imm, + u32 in_modifier, u8 op_modifier, u16 op, unsigned long timeout); +#endif /* MLX4_CMD_H */ diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/inc/cq.h b/branches/WOF2-3/hw/mlx4/kernel/bus/inc/cq.h new file mode 100644 index 00000000..93b56ea1 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/inc/cq.h @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef MLX4_CQ_H +#define MLX4_CQ_H + +#include "device.h" +#include "doorbell.h" + +struct mlx4_cq_context { + __be32 flags; + u16 reserved1[3]; + __be16 page_offset; + __be32 logsize_usrpage; + u16 cq_period; + u16 cq_max_count; + u8 reserved4[3]; + u8 comp_eqn; + u8 log_page_size; + u8 reserved5[2]; + u8 mtt_base_addr_h; + __be32 mtt_base_addr_l; + __be32 last_notified_index; + __be32 solicit_producer_index; + __be32 consumer_index; + __be32 producer_index; + u32 reserved6[2]; + __be64 db_rec_addr; +}; + +struct mlx4_cqe { + __be32 my_qpn; + __be32 immed_rss_invalid; + __be32 g_mlpath_rqpn; + u8 sl; + u8 reserved1; + __be16 rlid; + __be32 ipoib_status; + __be32 byte_cnt; + __be16 wqe_index; + __be16 checksum; + u8 reserved2[3]; + u8 owner_sr_opcode; +}; + +struct mlx4_err_cqe { + __be32 my_qpn; + u32 reserved1[5]; + __be16 wqe_index; + u8 vendor_err_syndrome; + u8 syndrome; + u8 reserved2[3]; + u8 owner_sr_opcode; +}; + +enum { + MLX4_CQE_OWNER_MASK = 0x80, + MLX4_CQE_IS_SEND_MASK = 0x40, + MLX4_CQE_OPCODE_MASK = 0x1f +}; + +enum { + MLX4_CQE_SYNDROME_LOCAL_LENGTH_ERR = 0x01, + MLX4_CQE_SYNDROME_LOCAL_QP_OP_ERR = 0x02, + MLX4_CQE_SYNDROME_LOCAL_PROT_ERR = 0x04, + MLX4_CQE_SYNDROME_WR_FLUSH_ERR = 0x05, + MLX4_CQE_SYNDROME_MW_BIND_ERR = 0x06, + MLX4_CQE_SYNDROME_BAD_RESP_ERR = 0x10, + MLX4_CQE_SYNDROME_LOCAL_ACCESS_ERR = 0x11, + MLX4_CQE_SYNDROME_REMOTE_INVAL_REQ_ERR = 0x12, + MLX4_CQE_SYNDROME_REMOTE_ACCESS_ERR = 0x13, + MLX4_CQE_SYNDROME_REMOTE_OP_ERR = 0x14, + MLX4_CQE_SYNDROME_TRANSPORT_RETRY_EXC_ERR = 0x15, + MLX4_CQE_SYNDROME_RNR_RETRY_EXC_ERR = 0x16, + MLX4_CQE_SYNDROME_REMOTE_ABORTED_ERR = 0x22, +}; + +enum { + MLX4_CQE_IPOIB_STATUS_IPV4 = 1 << 22, + MLX4_CQE_IPOIB_STATUS_IPV4F = 1 << 23, + MLX4_CQE_IPOIB_STATUS_IPV6 = 1 << 24, + MLX4_CQE_IPOIB_STATUS_IPV4OPT = 1 << 25, + MLX4_CQE_IPOIB_STATUS_TCP = 1 << 26, + MLX4_CQE_IPOIB_STATUS_UDP = 1 << 27, + MLX4_CQE_IPOIB_STATUS_IPOK = 1 << 28 +}; + +enum { + MLX4_NdisPacketTcpChecksumFailed = 1 << 0, + MLX4_NdisPacketUdpChecksumFailed = 1 << 1, + MLX4_NdisPacketIpChecksumFailed = 1 << 2, + MLX4_NdisPacketTcpChecksumSucceeded = 1 << 3, + MLX4_NdisPacketUdpChecksumSucceeded = 1 << 4, + MLX4_NdisPacketIpChecksumSucceeded = 1 << 5 +}; + +static inline void mlx4_cq_arm(struct mlx4_cq *cq, u32 cmd, + void __iomem *uar_page, + spinlock_t *doorbell_lock) +{ + __be32 doorbell[2]; + u32 sn; + u32 ci; + + sn = cq->arm_sn & 3; + ci = cq->cons_index & 0xffffff; + + *cq->arm_db = cpu_to_be32(sn << 28 | cmd | ci); + + /* + * Make sure that the doorbell record in host memory is + * written before ringing the doorbell via PCI MMIO. + */ + wmb(); + + doorbell[0] = cpu_to_be32(sn << 28 | cmd | cq->cqn); + doorbell[1] = cpu_to_be32(ci); + + mlx4_write64(doorbell, (u8*)uar_page + MLX4_CQ_DOORBELL, doorbell_lock); +} + +static inline void mlx4_cq_set_ci(struct mlx4_cq *cq) +{ + *cq->set_ci_db = cpu_to_be32(cq->cons_index & 0xffffff); +} + +enum { + MLX4_CQ_DB_REQ_NOT_SOL = 1 << 24, + MLX4_CQ_DB_REQ_NOT = 2 << 24 +}; + +int mlx4_cq_modify(struct mlx4_dev *dev, struct mlx4_cq *cq, + struct mlx4_cq_context *context, int resize); + +#endif /* MLX4_CQ_H */ diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/inc/device.h b/branches/WOF2-3/hw/mlx4/kernel/bus/inc/device.h new file mode 100644 index 00000000..daf2bee1 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/inc/device.h @@ -0,0 +1,554 @@ +/* + * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef MLX4_DEVICE_H +#define MLX4_DEVICE_H + +enum { + MLX4_FLAG_MSI_X = 1 << 0, + MLX4_FLAG_OLD_PORT_CMDS = 1 << 1, + MLX4_FLAG_NOT_PRIME = 1 << 2, + MLX4_FLAG_LIVEFISH = 1 << 10, + MLX4_FLAG_RESET_CLIENT = 1 << 11, + MLX4_FLAG_RESET_DRIVER = 1 << 12, + MLX4_FLAG_RESET_STARTED = 1 << 13, + MLX4_FLAG_BUSY_WAIT = 1 << 14 +}; + +enum { + MLX4_MAX_PORTS = 2 +}; + +enum { + MLX4_BOARD_ID_LEN = 64 +}; + +enum { + MLX4_DEV_CAP_FLAG_RC = 1 << 0, + MLX4_DEV_CAP_FLAG_UC = 1 << 1, + MLX4_DEV_CAP_FLAG_UD = 1 << 2, + MLX4_DEV_CAP_FLAG_SRQ = 1 << 6, + MLX4_DEV_CAP_FLAG_IPOIB_CSUM = 1 << 7, + MLX4_DEV_CAP_FLAG_BAD_PKEY_CNTR = 1 << 8, + MLX4_DEV_CAP_FLAG_BAD_QKEY_CNTR = 1 << 9, + MLX4_DEV_CAP_FLAG_DPDP = 1 << 12, + MLX4_DEV_CAP_FLAG_MEM_WINDOW = 1 << 16, + MLX4_DEV_CAP_FLAG_APM = 1 << 17, + MLX4_DEV_CAP_FLAG_ATOMIC = 1 << 18, + MLX4_DEV_CAP_FLAG_RAW_MCAST = 1 << 19, + MLX4_DEV_CAP_FLAG_UD_AV_PORT = 1 << 20, + MLX4_DEV_CAP_FLAG_UD_MCAST = 1 << 21 +}; + +enum mlx4_event { + MLX4_EVENT_TYPE_COMP = 0x00, + MLX4_EVENT_TYPE_PATH_MIG = 0x01, + MLX4_EVENT_TYPE_COMM_EST = 0x02, + MLX4_EVENT_TYPE_SQ_DRAINED = 0x03, + MLX4_EVENT_TYPE_SRQ_QP_LAST_WQE = 0x13, + MLX4_EVENT_TYPE_SRQ_LIMIT = 0x14, + MLX4_EVENT_TYPE_CQ_ERROR = 0x04, + MLX4_EVENT_TYPE_WQ_CATAS_ERROR = 0x05, + MLX4_EVENT_TYPE_EEC_CATAS_ERROR = 0x06, + MLX4_EVENT_TYPE_PATH_MIG_FAILED = 0x07, + MLX4_EVENT_TYPE_WQ_INVAL_REQ_ERROR = 0x10, + MLX4_EVENT_TYPE_WQ_ACCESS_ERROR = 0x11, + MLX4_EVENT_TYPE_SRQ_CATAS_ERROR = 0x12, + MLX4_EVENT_TYPE_LOCAL_CATAS_ERROR = 0x08, + MLX4_EVENT_TYPE_PORT_CHANGE = 0x09, + MLX4_EVENT_TYPE_EQ_OVERFLOW = 0x0f, + MLX4_EVENT_TYPE_ECC_DETECT = 0x0e, + MLX4_EVENT_TYPE_CMD = 0x0a +}; + +enum { + MLX4_PORT_CHANGE_SUBTYPE_DOWN = 1, + MLX4_PORT_CHANGE_SUBTYPE_ACTIVE = 4 +}; + +enum { + MLX4_PERM_LOCAL_READ = 1 << 10, + MLX4_PERM_LOCAL_WRITE = 1 << 11, + MLX4_PERM_REMOTE_READ = 1 << 12, + MLX4_PERM_REMOTE_WRITE = 1 << 13, + MLX4_PERM_ATOMIC = 1 << 14 +}; + +enum { + MLX4_OPCODE_NOP = 0x00, + MLX4_OPCODE_SEND_INVAL = 0x01, + MLX4_OPCODE_RDMA_WRITE = 0x08, + MLX4_OPCODE_RDMA_WRITE_IMM = 0x09, + MLX4_OPCODE_SEND = 0x0a, + MLX4_OPCODE_SEND_IMM = 0x0b, + MLX4_OPCODE_LSO = 0x0e, + MLX4_OPCODE_RDMA_READ = 0x10, + MLX4_OPCODE_ATOMIC_CS = 0x11, + MLX4_OPCODE_ATOMIC_FA = 0x12, + MLX4_OPCODE_ATOMIC_MASK_CS = 0x14, + MLX4_OPCODE_ATOMIC_MASK_FA = 0x15, + MLX4_OPCODE_BIND_MW = 0x18, + MLX4_OPCODE_FMR = 0x19, + MLX4_OPCODE_LOCAL_INVAL = 0x1b, + MLX4_OPCODE_CONFIG_CMD = 0x1f, + + MLX4_RECV_OPCODE_RDMA_WRITE_IMM = 0x00, + MLX4_RECV_OPCODE_SEND = 0x01, + MLX4_RECV_OPCODE_SEND_IMM = 0x02, + MLX4_RECV_OPCODE_SEND_INVAL = 0x03, + + MLX4_CQE_OPCODE_ERROR = 0x1e, + MLX4_CQE_OPCODE_RESIZE = 0x16, +}; + +enum { + MLX4_STAT_RATE_OFFSET = 5 +}; + +enum qp_region { + MLX4_QP_REGION_FW = 0, + MLX4_QP_REGION_ETH_ADDR, + MLX4_QP_REGION_FC_ADDR, + MLX4_QP_REGION_FC_EXCH, + MLX4_QP_REGION_COUNT /* Must be last */ +}; + +#if 0 +// not in use now +// should be set as default to numFcExch +enum { + MLX4_NUM_FEXCH = 64 * 1024, +}; +#endif + + +struct mlx4_caps { + u64 fw_ver; + int num_ports; + int vl_cap[MLX4_MAX_PORTS + 1]; + int ib_mtu_cap[MLX4_MAX_PORTS + 1]; + u64 def_mac[MLX4_MAX_PORTS + 1]; + int eth_mtu_cap[MLX4_MAX_PORTS + 1]; + int gid_table_len[MLX4_MAX_PORTS + 1]; + int pkey_table_len[MLX4_MAX_PORTS + 1]; + int local_ca_ack_delay; + int num_uars; + int bf_reg_size; + int bf_regs_per_page; + int max_sq_sg; + int max_rq_sg; + int num_qps; + int max_wqes; + int max_sq_desc_sz; + int max_rq_desc_sz; + int max_qp_init_rdma; + int max_qp_dest_rdma; + int sqp_start; + int num_srqs; + int max_srq_wqes; + int max_srq_sge; + int reserved_srqs; + int num_cqs; + int max_cqes; + int reserved_cqs; + int num_eqs; + int reserved_eqs; + int num_mpts; + int num_mtt_segs; + int fmr_reserved_mtts; + int reserved_mtts; + int reserved_mrws; + int reserved_uars; + int num_mgms; + int num_amgms; + int reserved_mcgs; + int num_qp_per_mgm; + int num_pds; + int reserved_pds; + int mtt_entry_sz; + u32 max_msg_sz; + u32 page_size_cap; + u32 flags; + u16 stat_rate_support; + u8 port_width_cap[MLX4_MAX_PORTS + 1]; + int max_gso_sz; + int reserved_qps_cnt[MLX4_QP_REGION_COUNT]; + int reserved_qps_base[MLX4_QP_REGION_COUNT]; + int log_num_macs; + int log_num_vlans; + int log_num_prios; + int num_fc_exch; + enum mlx4_port_type port_type[MLX4_MAX_PORTS + 1]; + u32 port_mask; + enum mlx4_port_state port_state[MLX4_MAX_PORTS + 1]; + int reserved_fexch_mpts_base; + int total_reserved_qps; +}; + +struct mlx4_buf_list { + u8 *buf; + dma_addr_t map; +}; +enum { + MLX4_DB_PER_PAGE = PAGE_SIZE / 4 +}; + +struct mlx4_db_pgdir { + struct list_head list; + DECLARE_BITMAP(order0, MLX4_DB_PER_PAGE); + DECLARE_BITMAP(order1, MLX4_DB_PER_PAGE / 2); + unsigned long *bits[2]; + __be32 *db_page; + dma_addr_t db_dma; +}; + +struct mlx4_db { + __be32 *db; + struct mlx4_db_pgdir *pgdir; + dma_addr_t dma; + int index; + int order; +}; + +struct mlx4_mtt { + u32 first_seg; + int order; + int page_shift; +}; + +struct mlx4_buf { + union { + struct mlx4_buf_list direct; + struct mlx4_buf_list *page_list; + } u; + int nbufs; + int npages; + int page_shift; +}; + +struct mlx4_hwq_resources { + struct mlx4_db db; + struct mlx4_mtt mtt; + struct mlx4_buf buf; +}; + +struct mlx4_mr { + struct mlx4_mtt mtt; + u64 iova; + u64 size; + u32 key; + u32 pd; + u32 access; + int enabled; +}; + +struct mlx4_fmr { + struct mlx4_mr mr; + struct mlx4_mpt_entry *mpt; + __be64 *mtts; + dma_addr_t dma_handle; + int max_pages; + int max_maps; + int maps; + u8 page_shift; +}; + +struct mlx4_uar { + unsigned long pfn; + int index; +}; + +struct mlx4_cq { + void (*comp) (struct mlx4_cq *); + void (*event) (struct mlx4_cq *, enum mlx4_event); + + struct mlx4_uar *uar; + + u32 cons_index; + + __be32 *set_ci_db; + __be32 *arm_db; + int arm_sn; + + int cqn; + int comp_eq_idx; + + atomic_t refcount; + struct completion free; + + // Windows specific + int *p_u_arm_sn; + PMDL mdl; +}; + +struct mlx4_qp { + void (*event) (struct mlx4_qp *, enum mlx4_event); + + int qpn; + + atomic_t refcount; + struct completion free; +}; + +struct mlx4_srq { + void (*event) (struct mlx4_srq *, enum mlx4_event); + + int srqn; + int max; + int max_gs; + int wqe_shift; + + atomic_t refcount; + struct completion free; +}; + +struct mlx4_av { + __be32 port_pd; + u8 reserved1; + u8 g_slid; + __be16 dlid; + u8 reserved2; + u8 gid_index; + u8 stat_rate; + u8 hop_limit; + __be32 sl_tclass_flowlabel; + u8 dgid[16]; +}; + +struct mlx4_eth_av { + __be32 port_pd; + u8 reserved1; + u8 smac_idx; + u16 reserved2; + u8 reserved3; + u8 gid_index; + u8 stat_rate; + u8 hop_limit; + __be32 sl_tclass_flowlabel; + u8 dgid[16]; + u32 reserved4[2]; + __be16 vlan; + u8 mac_0_1[2]; + u8 mac_2_5[4]; +}; + +union mlx4_ext_av { + struct mlx4_av ib; + struct mlx4_eth_av eth; +}; + +#define MLX4_DEV_SIGNATURE 0xf1b34a6e + +struct mlx4_dev_params { + enum mlx4_port_type mod_port_type[MLX4_MAX_PORTS]; +} ; + +static inline void mlx4_copy_dev_params( + struct mlx4_dev_params *dst, + struct mlx4_dev_params *src) +{ + *dst = *src; +} + +struct mlx4_dev { + u32 signature; + struct pci_dev *pdev; + unsigned long flags; + LONG reset_pending; + struct mlx4_caps caps; + struct radix_tree_root qp_table_tree; + u32 rev_id; + char board_id[MLX4_BOARD_ID_LEN]; + struct mlx4_dev_params dev_params; +}; + +struct mlx4_init_port_param { + int set_guid0; + int set_node_guid; + int set_si_guid; + u16 mtu; + int port_width_cap; + u16 vl_cap; + u16 max_gid; + u16 max_pkey; + u64 guid0; + u64 node_guid; + u64 si_guid; +}; + +static inline void mlx4_query_steer_cap(struct mlx4_dev *dev, int *log_mac, + int *log_vlan, int *log_prio) +{ + *log_mac = dev->caps.log_num_macs; + *log_vlan = dev->caps.log_num_vlans; + *log_prio = dev->caps.log_num_prios; +} + +static inline u32 mlx4_get_ports_of_type(struct mlx4_dev *dev, + enum mlx4_port_type ptype) +{ + u32 ret = 0; + int i; + + for (i = 1; i <= dev->caps.num_ports; ++i) { + if (dev->caps.port_type[i] == ptype) + ret |= 1 << (i-1); + } + return ret; +} + +#define foreach_port(port, bitmap) \ + for ((port) = 1; (port) <= MLX4_MAX_PORTS; ++(port)) \ + if (bitmap & 1 << ((port)-1)) + +static inline int mlx4_get_fexch_mpts_base(struct mlx4_dev *dev) +{ + return dev->caps.reserved_fexch_mpts_base; +} + +int mlx4_buf_alloc(struct mlx4_dev *dev, int size, int max_direct, + struct mlx4_buf *buf); +void mlx4_buf_free(struct mlx4_dev *dev, int size, struct mlx4_buf *buf); + +int mlx4_db_alloc(struct mlx4_dev *dev, + struct mlx4_db *db, int order); + +void mlx4_db_free(struct mlx4_dev *dev, struct mlx4_db *db); + +int mlx4_pd_alloc(struct mlx4_dev *dev, u32 *pdn); +void mlx4_pd_free(struct mlx4_dev *dev, u32 pdn); + +int mlx4_uar_alloc(struct mlx4_dev *dev, struct mlx4_uar *uar); +void mlx4_uar_free(struct mlx4_dev *dev, struct mlx4_uar *uar); + +int mlx4_mtt_init(struct mlx4_dev *dev, int npages, int page_shift, + struct mlx4_mtt *mtt); +void mlx4_mtt_cleanup(struct mlx4_dev *dev, struct mlx4_mtt *mtt); +u64 mlx4_mtt_addr(struct mlx4_dev *dev, struct mlx4_mtt *mtt); + +int mlx4_mr_alloc_reserved(struct mlx4_dev *dev, u32 mridx, u32 pd, + u64 iova, u64 size, u32 access, int npages, + int page_shift, struct mlx4_mr *mr); +int mlx4_mr_alloc(struct mlx4_dev *dev, u32 pd, u64 iova, u64 size, u32 access, + int npages, int page_shift, struct mlx4_mr *mr); +void mlx4_mr_free(struct mlx4_dev *dev, struct mlx4_mr *mr); +void mlx4_mr_free_reserved(struct mlx4_dev *dev, struct mlx4_mr *mr); +int mlx4_mr_enable(struct mlx4_dev *dev, struct mlx4_mr *mr); +int mlx4_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt, + int start_index, int npages, u64 *page_list); +int mlx4_buf_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt, + struct mlx4_buf *buf); + +struct device; + +int mlx4_alloc_hwq_res(struct mlx4_dev *dev, struct mlx4_hwq_resources *wqres, + int size, int max_direct); +void mlx4_free_hwq_res(struct mlx4_dev *mdev, struct mlx4_hwq_resources *wqres, + int size); + +int mlx4_cq_alloc(struct mlx4_dev *dev, int nent, struct mlx4_mtt *mtt, + struct mlx4_uar *uar, u64 db_rec, struct mlx4_cq *cq, + unsigned vector, int collapsed); +void mlx4_cq_free(struct mlx4_dev *dev, struct mlx4_cq *cq); + +struct mlx4_cq_context; +int mlx4_cq_modify(struct mlx4_dev *dev, struct mlx4_cq *cq, + struct mlx4_cq_context *context, int modify); + +static inline void mlx4_cq_arm(struct mlx4_cq *cq, u32 cmd, + void __iomem *uar_page, + spinlock_t *doorbell_lock); + +enum mlx4_qp_state; +enum mlx4_qp_optpar; +struct mlx4_qp_context; + +int mlx4_qp_reserve_range(struct mlx4_dev *dev, int cnt, int align, u32 *base); +void mlx4_qp_release_range(struct mlx4_dev *dev, int base_qpn, int cnt); +int mlx4_qp_alloc(struct mlx4_dev *dev, int qpn, struct mlx4_qp *qp); +void mlx4_qp_free(struct mlx4_dev *dev, struct mlx4_qp *qp); + +int mlx4_qp_modify(struct mlx4_dev *dev, struct mlx4_mtt *mtt, + enum mlx4_qp_state cur_state, enum mlx4_qp_state new_state, + struct mlx4_qp_context *context, enum mlx4_qp_optpar optpar, + int sqd_event, struct mlx4_qp *qp); + + +int mlx4_qp_to_ready(struct mlx4_dev *dev, struct mlx4_mtt *mtt, + struct mlx4_qp_context *context, + struct mlx4_qp *qp, enum mlx4_qp_state *qp_state); + +void mlx4_qp_remove(struct mlx4_dev *dev, struct mlx4_qp *qp); + + +int mlx4_srq_alloc(struct mlx4_dev *dev, u32 pdn, u32 cqn, u16 xrcd, + struct mlx4_mtt *mtt, u64 db_rec, struct mlx4_srq *srq); +void mlx4_srq_free(struct mlx4_dev *dev, struct mlx4_srq *srq); + +void mlx4_srq_invalidate(struct mlx4_dev *dev, struct mlx4_srq *srq); +void mlx4_srq_remove(struct mlx4_dev *dev, struct mlx4_srq *srq); + +int mlx4_srq_arm(struct mlx4_dev *dev, struct mlx4_srq *srq, int limit_watermark); +int mlx4_srq_query(struct mlx4_dev *dev, struct mlx4_srq *srq, int *limit_watermark); + +int mlx4_INIT_PORT(struct mlx4_dev *dev, int port); +int mlx4_CLOSE_PORT(struct mlx4_dev *dev, int port); + +int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16]); +int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16]); + +int mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *index); +void mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, int index); +int mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index); +void mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, int index); + +int mlx4_map_phys_fmr(struct mlx4_dev *dev, struct mlx4_fmr *fmr, u64 *page_list, + int npages, u64 iova, u32 *lkey, u32 *rkey); +int mlx4_map_phys_fmr_fbo(struct mlx4_dev *dev, struct mlx4_fmr *fmr, + u64 *page_list, int npages, u64 iova, + u32 fbo, u32 len, u32 *lkey, u32 *rkey); +int mlx4_fmr_alloc(struct mlx4_dev *dev, u32 pd, u32 access, int max_pages, + int max_maps, u8 page_shift, struct mlx4_fmr *fmr); +int mlx4_fmr_alloc_reserved(struct mlx4_dev *dev, u32 mridx, u32 pd, + u32 access, int max_pages, int max_maps, + u8 page_shift, struct mlx4_fmr *fmr); +int mlx4_fmr_enable(struct mlx4_dev *dev, struct mlx4_fmr *fmr); +void mlx4_fmr_unmap(struct mlx4_dev *dev, struct mlx4_fmr *fmr, + u32 *lkey, u32 *rkey); +int mlx4_fmr_free(struct mlx4_dev *dev, struct mlx4_fmr *fmr); +int mlx4_fmr_free_reserved(struct mlx4_dev *dev, struct mlx4_fmr *fmr); +int mlx4_SYNC_TPT(struct mlx4_dev *dev); + +int mlx4_SET_PORT(struct mlx4_dev *dev, u8 port, int reset_qkey_viols, + u32 cap_mask); + +#endif /* MLX4_DEVICE_H */ diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/inc/doorbell.h b/branches/WOF2-3/hw/mlx4/kernel/bus/inc/doorbell.h new file mode 100644 index 00000000..0d694cbe --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/inc/doorbell.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2004 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef MLX4_DOORBELL_H +#define MLX4_DOORBELL_H + +#define MLX4_SEND_DOORBELL 0x14 +#define MLX4_CQ_DOORBELL 0x20 + +#if _WIN64 +/* + * Assume that we can just write a 64-bit doorbell atomically. s390 + * actually doesn't have writeq() but S/390 systems don't even have + * PCI so we won't worry about it. + */ + +#define MLX4_DECLARE_DOORBELL_LOCK(name) +#define MLX4_INIT_DOORBELL_LOCK(ptr) +#define MLX4_GET_DOORBELL_LOCK(ptr) (NULL) + +static inline void mlx4_write64(__be32 val[2], void __iomem *dest, + spinlock_t *doorbell_lock) +{ + UNREFERENCED_PARAMETER(doorbell_lock); + *(volatile u64 *)dest = *(volatile u64 *)val; +} + +#else +/* + * Just fall back to a spinlock to protect the doorbell if + * BITS_PER_LONG is 32 -- there's no portable way to do atomic 64-bit + * MMIO writes. + */ + +#define MLX4_DECLARE_DOORBELL_LOCK(name) spinlock_t name +#define MLX4_INIT_DOORBELL_LOCK(ptr) spin_lock_init(ptr) +#define MLX4_GET_DOORBELL_LOCK(ptr) (ptr) + +static inline void mlx4_write64(__be32 val[2], void __iomem *dest, + spinlock_t *doorbell_lock) +{ + unsigned long flags; + + spin_lock_irqsave(doorbell_lock, &flags); + __raw_writel((__force u32) val[0], dest); + __raw_writel((__force u32) val[1], (u8*)dest + 4); + spin_unlock_irqrestore(doorbell_lock, flags); +} + +#endif + +#endif /* MLX4_DOORBELL_H */ diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/inc/driver.h b/branches/WOF2-3/hw/mlx4/kernel/bus/inc/driver.h new file mode 100644 index 00000000..e7962b28 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/inc/driver.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2006 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef MLX4_DRIVER_H +#define MLX4_DRIVER_H + +#include "device.h" + +struct mlx4_dev; + +enum mlx4_dev_event { + MLX4_DEV_EVENT_CATASTROPHIC_ERROR, + MLX4_DEV_EVENT_PORT_UP, + MLX4_DEV_EVENT_PORT_DOWN, + MLX4_DEV_EVENT_PORT_REINIT, +}; + +struct mlx4_interface { + void * (*add) (struct mlx4_dev *dev); + void (*remove)(struct mlx4_dev *dev, void *context); + void (*event) (struct mlx4_dev *dev, void *context, + enum mlx4_dev_event event, int subtype, + int port); + struct list_head list; +}; + +int mlx4_register_interface(struct mlx4_interface *intf); +void mlx4_unregister_interface(struct mlx4_interface *intf); + +#endif /* MLX4_DRIVER_H */ diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/inc/eq.h b/branches/WOF2-3/hw/mlx4/kernel/bus/inc/eq.h new file mode 100644 index 00000000..85c5e07f --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/inc/eq.h @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2008 Mellanox Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: ipoib_port.h 1310 2008-06-30 18:09:25Z ftillier $ + */ + +#ifndef MLX4_EQ_H +#define MLX4_EQ_H + +enum { + MLX4_NUM_ASYNC_EQE = 0x100, + MLX4_NUM_SPARE_EQE = 0x80, + MLX4_EQ_ENTRY_SIZE = 0x20 +}; + +struct mlx4_eq { + struct mlx4_dev *dev; + void __iomem *doorbell; + int eqn; + u32 cons_index; + u16 irq; + u16 have_irq; + int nent; + struct mlx4_buf_list *page_list; + struct mlx4_mtt mtt; + // Windows + KDPC dpc; /* DPC routine */ + spinlock_t lock; /* spinlock for simult DPCs */ + int eq_ix; /* EQ index - 0..MLX4_NUM_EQ */ + BOOLEAN (*isr)(void*); /* isr */ + void * ctx; /* isr ctx */ + USHORT eq_no_progress; /* used to look for stacked card */ + KAFFINITY cpu; /* CPU, this MSI-X vector is connected to */ + int valid; +}; + + + +#pragma pack(push,1) +struct mlx4_eqe { + u8 reserved1; + u8 type; + u8 reserved2; + u8 subtype; + union { + u32 raw[6]; + struct { + __be32 cqn; + } __attribute__((packed)) comp; + struct { + u16 reserved1; + __be16 token; + u32 reserved2; + u8 reserved3[3]; + u8 status; + __be64 out_param; + } __attribute__((packed)) cmd; + struct { + __be32 qpn; + } __attribute__((packed)) qp; + struct { + __be32 srqn; + } __attribute__((packed)) srq; + struct { + __be32 cqn; + u32 reserved1; + u8 reserved2[3]; + u8 syndrome; + } __attribute__((packed)) cq_err; + struct { + u32 reserved1[2]; + __be32 port; + } __attribute__((packed)) port_change; + } event; + u8 reserved3[3]; + u8 owner; +} __attribute__((packed)); +#pragma pack(pop) + +static void eq_set_ci(struct mlx4_eq *eq, int req_not) +{ + __raw_writel((__force u32) cpu_to_be32((eq->cons_index & 0xffffff) | + req_not << 31), + eq->doorbell); + /* We still want ordering, just not swabbing, so add a barrier */ + mb(); +} + +static struct mlx4_eqe *get_eqe(struct mlx4_eq *eq, u32 entry) +{ + unsigned long off = (entry & (eq->nent - 1)) * MLX4_EQ_ENTRY_SIZE; + return (struct mlx4_eqe *)(eq->page_list[off / PAGE_SIZE].buf + off % PAGE_SIZE); +} + +static struct mlx4_eqe *next_eqe_sw(struct mlx4_eq *eq) +{ + struct mlx4_eqe *eqe = get_eqe(eq, eq->cons_index); + return !!(eqe->owner & 0x80) ^ !!(eq->cons_index & eq->nent) ? NULL : eqe; +} + + + +#endif /* MLX4_EQ_H */ + + + diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/inc/ib_cache.h b/branches/WOF2-3/hw/mlx4/kernel/bus/inc/ib_cache.h new file mode 100644 index 00000000..9dda15ad --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/inc/ib_cache.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2004 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Intel Corporation. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: ib_cache.h 1349 2004-12-16 21:09:43Z roland $ + */ + +#pragma once + +#include "ib_verbs.h" + +/** + * ib_get_cached_gid - Returns a cached GID table entry + * @device: The device to query. + * @port_num: The port number of the device to query. + * @index: The index into the cached GID table to query. + * @gid: The GID value found at the specified index. + * + * ib_get_cached_gid() fetches the specified GID table entry stored in + * the local software cache. + */ +int ib_get_cached_gid(struct ib_device *device, + u8 port_num, + int index, + union ib_gid *gid); + +/** + * ib_find_cached_gid - Returns the port number and GID table index where + * a specified GID value occurs. + * @device: The device to query. + * @gid: The GID value to search for. + * @port_num: The port number of the device where the GID value was found. + * @index: The index into the cached GID table where the GID was found. This + * parameter may be NULL. + * + * ib_find_cached_gid() searches for the specified GID value in + * the local software cache. + */ +int ib_find_cached_gid(struct ib_device *device, + union ib_gid *gid, + u8 *port_num, + u16 *index); + +/** + * ib_get_cached_pkey - Returns a cached PKey table entry + * @device: The device to query. + * @port_num: The port number of the device to query. + * @index: The index into the cached PKey table to query. + * @pkey: The PKey value found at the specified index. + * + * ib_get_cached_pkey() fetches the specified PKey table entry stored in + * the local software cache. + */ +int ib_get_cached_pkey(struct ib_device *device_handle, + u8 port_num, + int index, + __be16 *pkey); + +/** + * ib_find_cached_pkey - Returns the PKey table index where a specified + * PKey value occurs. + * @device: The device to query. + * @port_num: The port number of the device to search for the PKey. + * @pkey: The PKey value to search for. + * @index: The index into the cached PKey table where the PKey was found. + * + * ib_find_cached_pkey() searches the specified PKey table in + * the local software cache. + */ +int ib_find_cached_pkey(struct ib_device *device, + u8 port_num, + __be16 pkey, + u16 *index); + +/** + * ib_get_cached_lmc - Returns a cached lmc table entry + * @device: The device to query. + * @port_num: The port number of the device to query. + * @lmc: The lmc value for the specified port for that device. + * + * ib_get_cached_lmc() fetches the specified lmc table entry stored in + * the local software cache. + */ +int ib_get_cached_lmc(struct ib_device *device, + u8 port_num, + u8 *lmc); + diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/inc/ib_mad.h b/branches/WOF2-3/hw/mlx4/kernel/bus/inc/ib_mad.h new file mode 100644 index 00000000..e28a8f32 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/inc/ib_mad.h @@ -0,0 +1,657 @@ +/* + * Copyright (c) 2004 Mellanox Technologies Ltd. All rights reserved. + * Copyright (c) 2004 Infinicon Corporation. All rights reserved. + * Copyright (c) 2004 Intel Corporation. All rights reserved. + * Copyright (c) 2004 Topspin Corporation. All rights reserved. + * Copyright (c) 2004-2006 Voltaire Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: ib_mad.h 5596 2006-03-03 01:00:07Z sean.hefty $ + */ + +#if !defined( IB_MAD_H ) +#define IB_MAD_H + +#include + +/* Management base version */ +#define IB_MGMT_BASE_VERSION 1 + +/* Management classes */ +#define IB_MGMT_CLASS_SUBN_LID_ROUTED 0x01 +#define IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE 0x81 +#define IB_MGMT_CLASS_SUBN_ADM 0x03 +#define IB_MGMT_CLASS_PERF_MGMT 0x04 +#define IB_MGMT_CLASS_BM 0x05 +#define IB_MGMT_CLASS_DEVICE_MGMT 0x06 +#define IB_MGMT_CLASS_CM 0x07 +#define IB_MGMT_CLASS_SNMP 0x08 +#define IB_MGMT_CLASS_DEVICE_ADM 0x10 +#define IB_MGMT_CLASS_BOOT_MGMT 0x11 +#define IB_MGMT_CLASS_BIS 0x12 +#define IB_MGMT_CLASS_CONG_MGMT 0x21 +#define IB_MGMT_CLASS_VENDOR_RANGE2_START 0x30 +#define IB_MGMT_CLASS_VENDOR_RANGE2_END 0x4F + +#define IB_OPENIB_OUI (0x001405) + +/* Management methods */ +#define IB_MGMT_METHOD_GET 0x01 +#define IB_MGMT_METHOD_SET 0x02 +#define IB_MGMT_METHOD_GET_RESP 0x81 +#define IB_MGMT_METHOD_SEND 0x03 +#define IB_MGMT_METHOD_TRAP 0x05 +#define IB_MGMT_METHOD_REPORT 0x06 +#define IB_MGMT_METHOD_REPORT_RESP 0x86 +#define IB_MGMT_METHOD_TRAP_REPRESS 0x07 + +#define IB_MGMT_METHOD_RESP 0x80 +#define IB_BM_ATTR_MOD_RESP cpu_to_be32(1) + +#define IB_MGMT_MAX_METHODS 128 + +/* RMPP information */ +#define IB_MGMT_RMPP_VERSION 1 + +#define IB_MGMT_RMPP_TYPE_DATA 1 +#define IB_MGMT_RMPP_TYPE_ACK 2 +#define IB_MGMT_RMPP_TYPE_STOP 3 +#define IB_MGMT_RMPP_TYPE_ABORT 4 + +#define IB_MGMT_RMPP_FLAG_ACTIVE 1 +#define IB_MGMT_RMPP_FLAG_FIRST (1<<1) +#define IB_MGMT_RMPP_FLAG_LAST (1<<2) + +#define IB_MGMT_RMPP_NO_RESPTIME 0x1F + +#define IB_MGMT_RMPP_STATUS_SUCCESS 0 +#define IB_MGMT_RMPP_STATUS_RESX 1 +#define IB_MGMT_RMPP_STATUS_ABORT_MIN 118 +#define IB_MGMT_RMPP_STATUS_T2L 118 +#define IB_MGMT_RMPP_STATUS_BAD_LEN 119 +#define IB_MGMT_RMPP_STATUS_BAD_SEG 120 +#define IB_MGMT_RMPP_STATUS_BADT 121 +#define IB_MGMT_RMPP_STATUS_W2S 122 +#define IB_MGMT_RMPP_STATUS_S2B 123 +#define IB_MGMT_RMPP_STATUS_BAD_STATUS 124 +#define IB_MGMT_RMPP_STATUS_UNV 125 +#define IB_MGMT_RMPP_STATUS_TMR 126 +#define IB_MGMT_RMPP_STATUS_UNSPEC 127 +#define IB_MGMT_RMPP_STATUS_ABORT_MAX 127 + +#define IB_QP0 0 +#define IB_QP1_QKEY 0x80010000 +#define IB_QP_SET_QKEY 0x80000000 + +#define IB_DEFAULT_PKEY_PARTIAL 0x7FFF +#define IB_DEFAULT_PKEY_FULL 0xFFFF + +enum { + IB_MGMT_MAD_HDR = 24, + IB_MGMT_MAD_DATA = 232, + IB_MGMT_RMPP_HDR = 36, + IB_MGMT_RMPP_DATA = 220, + IB_MGMT_VENDOR_HDR = 40, + IB_MGMT_VENDOR_DATA = 216, + IB_MGMT_SA_HDR = 56, + IB_MGMT_SA_DATA = 200, + IB_MGMT_DEVICE_HDR = 64, + IB_MGMT_DEVICE_DATA = 192, +}; + +struct ib_mad_hdr { + u8 base_version; + u8 mgmt_class; + u8 class_version; + u8 method; + __be16 status; + __be16 class_specific; + __be64 tid; + __be16 attr_id; + __be16 resv; + __be32 attr_mod; +}; + +struct ib_rmpp_hdr { + u8 rmpp_version; + u8 rmpp_type; + u8 rmpp_rtime_flags; + u8 rmpp_status; + __be32 seg_num; + __be32 paylen_newwin; +}; + +typedef u64 __bitwise ib_sa_comp_mask; + +#define IB_SA_COMP_MASK(n) ((__force ib_sa_comp_mask) cpu_to_be64(1ull << n)) + +/* + * ib_sa_hdr and ib_sa_mad structures must be packed because they have + * 64-bit fields that are only 32-bit aligned. 64-bit architectures will + * lay them out wrong otherwise. (And unfortunately they are sent on + * the wire so we can't change the layout) + */ +#pragma pack(push,1) +struct ib_sa_hdr { + __be64 sm_key; + __be16 attr_offset; + __be16 reserved; + ib_sa_comp_mask comp_mask; +} __attribute__ ((packed)); +#pragma pack(pop) + +struct ib_mad { + struct ib_mad_hdr mad_hdr; + u8 data[IB_MGMT_MAD_DATA]; +}; + +struct ib_rmpp_mad { + struct ib_mad_hdr mad_hdr; + struct ib_rmpp_hdr rmpp_hdr; + u8 data[IB_MGMT_RMPP_DATA]; +}; + +#pragma pack(push,1) +struct ib_sa_mad { + struct ib_mad_hdr mad_hdr; + struct ib_rmpp_hdr rmpp_hdr; + struct ib_sa_hdr sa_hdr; + u8 data[IB_MGMT_SA_DATA]; +} __attribute__ ((packed)); +#pragma pack(pop) + +struct ib_vendor_mad { + struct ib_mad_hdr mad_hdr; + struct ib_rmpp_hdr rmpp_hdr; + u8 reserved; + u8 oui[3]; + u8 data[IB_MGMT_VENDOR_DATA]; +}; + +struct ib_class_port_info +{ + u8 base_version; + u8 class_version; + __be16 capability_mask; + u8 reserved[3]; + u8 resp_time_value; + u8 redirect_gid[16]; + __be32 redirect_tcslfl; + __be16 redirect_lid; + __be16 redirect_pkey; + __be32 redirect_qp; + __be32 redirect_qkey; + u8 trap_gid[16]; + __be32 trap_tcslfl; + __be16 trap_lid; + __be16 trap_pkey; + __be32 trap_hlqp; + __be32 trap_qkey; +}; + +/** + * ib_mad_send_buf - MAD data buffer and work request for sends. + * @next: A pointer used to chain together MADs for posting. + * @mad: References an allocated MAD data buffer for MADs that do not have + * RMPP active. For MADs using RMPP, references the common and management + * class specific headers. + * @mad_agent: MAD agent that allocated the buffer. + * @ah: The address handle to use when sending the MAD. + * @context: User-controlled context fields. + * @hdr_len: Indicates the size of the data header of the MAD. This length + * includes the common MAD, RMPP, and class specific headers. + * @data_len: Indicates the total size of user-transferred data. + * @seg_count: The number of RMPP segments allocated for this send. + * @seg_size: Size of each RMPP segment. + * @timeout_ms: Time to wait for a response. + * @retries: Number of times to retry a request for a response. + * + * Users are responsible for initializing the MAD buffer itself, with the + * exception of any RMPP header. Additional segment buffer space allocated + * beyond data_len is padding. + */ +struct ib_mad_send_buf { + struct ib_mad_send_buf *next; + void *mad; + struct ib_mad_agent *mad_agent; + struct ib_ah *ah; + void *context[2]; + int hdr_len; + int data_len; + int seg_count; + int seg_size; + int timeout_ms; + int retries; +}; + +/** + * ib_response_mad - Returns if the specified MAD has been generated in + * response to a sent request or trap. + */ +int ib_response_mad(struct ib_mad *mad); + +/** + * ib_get_rmpp_resptime - Returns the RMPP response time. + * @rmpp_hdr: An RMPP header. + */ +static inline u8 ib_get_rmpp_resptime(struct ib_rmpp_hdr *rmpp_hdr) +{ + return rmpp_hdr->rmpp_rtime_flags >> 3; +} + +/** + * ib_get_rmpp_flags - Returns the RMPP flags. + * @rmpp_hdr: An RMPP header. + */ +static inline u8 ib_get_rmpp_flags(struct ib_rmpp_hdr *rmpp_hdr) +{ + return rmpp_hdr->rmpp_rtime_flags & 0x7; +} + +/** + * ib_set_rmpp_resptime - Sets the response time in an RMPP header. + * @rmpp_hdr: An RMPP header. + * @rtime: The response time to set. + */ +static inline void ib_set_rmpp_resptime(struct ib_rmpp_hdr *rmpp_hdr, u8 rtime) +{ + rmpp_hdr->rmpp_rtime_flags = ib_get_rmpp_flags(rmpp_hdr) | (rtime << 3); +} + +/** + * ib_set_rmpp_flags - Sets the flags in an RMPP header. + * @rmpp_hdr: An RMPP header. + * @flags: The flags to set. + */ +static inline void ib_set_rmpp_flags(struct ib_rmpp_hdr *rmpp_hdr, u8 flags) +{ + rmpp_hdr->rmpp_rtime_flags = (rmpp_hdr->rmpp_rtime_flags & 0xF1) | + (flags & 0x7); +} + +struct ib_mad_agent; +struct ib_mad_send_wc; +struct ib_mad_recv_wc; + +/** + * ib_mad_send_handler - callback handler for a sent MAD. + * @mad_agent: MAD agent that sent the MAD. + * @mad_send_wc: Send work completion information on the sent MAD. + */ +typedef void (*ib_mad_send_handler)(struct ib_mad_agent *mad_agent, + struct ib_mad_send_wc *mad_send_wc); + +/** + * ib_mad_snoop_handler - Callback handler for snooping sent MADs. + * @mad_agent: MAD agent that snooped the MAD. + * @send_wr: Work request information on the sent MAD. + * @mad_send_wc: Work completion information on the sent MAD. Valid + * only for snooping that occurs on a send completion. + * + * Clients snooping MADs should not modify data referenced by the @send_wr + * or @mad_send_wc. + */ +typedef void (*ib_mad_snoop_handler)(struct ib_mad_agent *mad_agent, + struct ib_mad_send_buf *send_buf, + struct ib_mad_send_wc *mad_send_wc); + +/** + * ib_mad_recv_handler - callback handler for a received MAD. + * @mad_agent: MAD agent requesting the received MAD. + * @mad_recv_wc: Received work completion information on the received MAD. + * + * MADs received in response to a send request operation will be handed to + * the user before the send operation completes. All data buffers given + * to registered agents through this routine are owned by the receiving + * client, except for snooping agents. Clients snooping MADs should not + * modify the data referenced by @mad_recv_wc. + */ +typedef void (*ib_mad_recv_handler)(struct ib_mad_agent *mad_agent, + struct ib_mad_recv_wc *mad_recv_wc); + +/** + * ib_mad_agent - Used to track MAD registration with the access layer. + * @device: Reference to device registration is on. + * @qp: Reference to QP used for sending and receiving MADs. + * @mr: Memory region for system memory usable for DMA. + * @recv_handler: Callback handler for a received MAD. + * @send_handler: Callback handler for a sent MAD. + * @snoop_handler: Callback handler for snooped sent MADs. + * @context: User-specified context associated with this registration. + * @hi_tid: Access layer assigned transaction ID for this client. + * Unsolicited MADs sent by this client will have the upper 32-bits + * of their TID set to this value. + * @port_num: Port number on which QP is registered + * @rmpp_version: If set, indicates the RMPP version used by this agent. + */ +struct ib_mad_agent { + struct ib_device *device; + struct ib_qp *qp; + struct ib_mr *mr; + ib_mad_recv_handler recv_handler; + ib_mad_send_handler send_handler; + ib_mad_snoop_handler snoop_handler; + void *context; + u32 hi_tid; + u8 port_num; + u8 rmpp_version; +}; + +/** + * ib_mad_send_wc - MAD send completion information. + * @send_buf: Send MAD data buffer associated with the send MAD request. + * @status: Completion status. + * @vendor_err: Optional vendor error information returned with a failed + * request. + */ +struct ib_mad_send_wc { + struct ib_mad_send_buf *send_buf; + enum ib_wc_status status; + u32 vendor_err; +}; + +/** + * ib_mad_recv_buf - received MAD buffer information. + * @list: Reference to next data buffer for a received RMPP MAD. + * @grh: References a data buffer containing the global route header. + * The data refereced by this buffer is only valid if the GRH is + * valid. + * @mad: References the start of the received MAD. + */ +struct ib_mad_recv_buf { + struct list_head list; + struct ib_grh *grh; + struct ib_mad *mad; +}; + +/** + * ib_mad_recv_wc - received MAD information. + * @wc: Completion information for the received data. + * @recv_buf: Specifies the location of the received data buffer(s). + * @rmpp_list: Specifies a list of RMPP reassembled received MAD buffers. + * @mad_len: The length of the received MAD, without duplicated headers. + * + * For received response, the wr_id contains a pointer to the ib_mad_send_buf + * for the corresponding send request. + */ +struct ib_mad_recv_wc { + ib_wc_t *wc; + struct ib_mad_recv_buf recv_buf; + struct list_head rmpp_list; + int mad_len; +}; + +/** + * ib_mad_reg_req - MAD registration request + * @mgmt_class: Indicates which management class of MADs should be receive + * by the caller. This field is only required if the user wishes to + * receive unsolicited MADs, otherwise it should be 0. + * @mgmt_class_version: Indicates which version of MADs for the given + * management class to receive. + * @oui: Indicates IEEE OUI when mgmt_class is a vendor class + * in the range from 0x30 to 0x4f. Otherwise not used. + * @method_mask: The caller will receive unsolicited MADs for any method + * where @method_mask = 1. + */ +struct ib_mad_reg_req { + u8 mgmt_class; + u8 mgmt_class_version; + u8 oui[3]; + DECLARE_BITMAP(method_mask, IB_MGMT_MAX_METHODS); +}; + +/** + * ib_register_mad_agent - Register to send/receive MADs. + * @device: The device to register with. + * @port_num: The port on the specified device to use. + * @qp_type: Specifies which QP to access. Must be either + * IB_QPT_SMI or IB_QPT_GSI. + * @mad_reg_req: Specifies which unsolicited MADs should be received + * by the caller. This parameter may be NULL if the caller only + * wishes to receive solicited responses. + * @rmpp_version: If set, indicates that the client will send + * and receive MADs that contain the RMPP header for the given version. + * If set to 0, indicates that RMPP is not used by this client. + * @send_handler: The completion callback routine invoked after a send + * request has completed. + * @recv_handler: The completion callback routine invoked for a received + * MAD. + * @context: User specified context associated with the registration. + */ +struct ib_mad_agent *ib_register_mad_agent(struct ib_device *device, + u8 port_num, + enum ib_qp_type qp_type, + struct ib_mad_reg_req *mad_reg_req, + u8 rmpp_version, + ib_mad_send_handler send_handler, + ib_mad_recv_handler recv_handler, + void *context); + +enum ib_mad_snoop_flags { + /*IB_MAD_SNOOP_POSTED_SENDS = 1,*/ + /*IB_MAD_SNOOP_RMPP_SENDS = (1<<1),*/ + IB_MAD_SNOOP_SEND_COMPLETIONS = (1<<2), + /*IB_MAD_SNOOP_RMPP_SEND_COMPLETIONS = (1<<3),*/ + IB_MAD_SNOOP_RECVS = (1<<4) + /*IB_MAD_SNOOP_RMPP_RECVS = (1<<5),*/ + /*IB_MAD_SNOOP_REDIRECTED_QPS = (1<<6)*/ +}; + +/** + * ib_register_mad_snoop - Register to snoop sent and received MADs. + * @device: The device to register with. + * @port_num: The port on the specified device to use. + * @qp_type: Specifies which QP traffic to snoop. Must be either + * IB_QPT_SMI or IB_QPT_GSI. + * @mad_snoop_flags: Specifies information where snooping occurs. + * @send_handler: The callback routine invoked for a snooped send. + * @recv_handler: The callback routine invoked for a snooped receive. + * @context: User specified context associated with the registration. + */ +struct ib_mad_agent *ib_register_mad_snoop(struct ib_device *device, + u8 port_num, + enum ib_qp_type qp_type, + int mad_snoop_flags, + ib_mad_snoop_handler snoop_handler, + ib_mad_recv_handler recv_handler, + void *context); + +/** + * ib_unregister_mad_agent - Unregisters a client from using MAD services. + * @mad_agent: Corresponding MAD registration request to deregister. + * + * After invoking this routine, MAD services are no longer usable by the + * client on the associated QP. + */ +int ib_unregister_mad_agent(struct ib_mad_agent *mad_agent); + +/** + * ib_post_send_mad - Posts MAD(s) to the send queue of the QP associated + * with the registered client. + * @send_buf: Specifies the information needed to send the MAD(s). + * @bad_send_buf: Specifies the MAD on which an error was encountered. This + * parameter is optional if only a single MAD is posted. + * + * Sent MADs are not guaranteed to complete in the order that they were posted. + * + * If the MAD requires RMPP, the data buffer should contain a single copy + * of the common MAD, RMPP, and class specific headers, followed by the class + * defined data. If the class defined data would not divide evenly into + * RMPP segments, then space must be allocated at the end of the referenced + * buffer for any required padding. To indicate the amount of class defined + * data being transferred, the paylen_newwin field in the RMPP header should + * be set to the size of the class specific header plus the amount of class + * defined data being transferred. The paylen_newwin field should be + * specified in network-byte order. + */ +int ib_post_send_mad(struct ib_mad_send_buf *send_buf, + struct ib_mad_send_buf **bad_send_buf); + + +/** + * ib_free_recv_mad - Returns data buffers used to receive a MAD. + * @mad_recv_wc: Work completion information for a received MAD. + * + * Clients receiving MADs through their ib_mad_recv_handler must call this + * routine to return the work completion buffers to the access layer. + */ +void ib_free_recv_mad(struct ib_mad_recv_wc *mad_recv_wc); + +/** + * ib_cancel_mad - Cancels an outstanding send MAD operation. + * @mad_agent: Specifies the registration associated with sent MAD. + * @send_buf: Indicates the MAD to cancel. + * + * MADs will be returned to the user through the corresponding + * ib_mad_send_handler. + */ +void ib_cancel_mad(struct ib_mad_agent *mad_agent, + struct ib_mad_send_buf *send_buf); + +/** + * ib_modify_mad - Modifies an outstanding send MAD operation. + * @mad_agent: Specifies the registration associated with sent MAD. + * @send_buf: Indicates the MAD to modify. + * @timeout_ms: New timeout value for sent MAD. + * + * This call will reset the timeout value for a sent MAD to the specified + * value. + */ +int ib_modify_mad(struct ib_mad_agent *mad_agent, + struct ib_mad_send_buf *send_buf, u32 timeout_ms); + +/** + * ib_redirect_mad_qp - Registers a QP for MAD services. + * @qp: Reference to a QP that requires MAD services. + * @rmpp_version: If set, indicates that the client will send + * and receive MADs that contain the RMPP header for the given version. + * If set to 0, indicates that RMPP is not used by this client. + * @send_handler: The completion callback routine invoked after a send + * request has completed. + * @recv_handler: The completion callback routine invoked for a received + * MAD. + * @context: User specified context associated with the registration. + * + * Use of this call allows clients to use MAD services, such as RMPP, + * on user-owned QPs. After calling this routine, users may send + * MADs on the specified QP by calling ib_mad_post_send. + */ +struct ib_mad_agent *ib_redirect_mad_qp(struct ib_qp *qp, + u8 rmpp_version, + ib_mad_send_handler send_handler, + ib_mad_recv_handler recv_handler, + void *context); + +/** + * ib_process_mad_wc - Processes a work completion associated with a + * MAD sent or received on a redirected QP. + * @mad_agent: Specifies the registered MAD service using the redirected QP. + * @wc: References a work completion associated with a sent or received + * MAD segment. + * + * This routine is used to complete or continue processing on a MAD request. + * If the work completion is associated with a send operation, calling + * this routine is required to continue an RMPP transfer or to wait for a + * corresponding response, if it is a request. If the work completion is + * associated with a receive operation, calling this routine is required to + * process an inbound or outbound RMPP transfer, or to match a response MAD + * with its corresponding request. + */ +int ib_process_mad_wc(struct ib_mad_agent *mad_agent, + ib_wc_t *wc); + +/** + * ib_create_send_mad - Allocate and initialize a data buffer and work request + * for sending a MAD. + * @mad_agent: Specifies the registered MAD service to associate with the MAD. + * @remote_qpn: Specifies the QPN of the receiving node. + * @pkey_index: Specifies which PKey the MAD will be sent using. This field + * is valid only if the remote_qpn is QP 1. + * @rmpp_active: Indicates if the send will enable RMPP. + * @hdr_len: Indicates the size of the data header of the MAD. This length + * should include the common MAD header, RMPP header, plus any class + * specific header. + * @data_len: Indicates the size of any user-transferred data. The call will + * automatically adjust the allocated buffer size to account for any + * additional padding that may be necessary. + * @gfp_mask: GFP mask used for the memory allocation. + * + * This routine allocates a MAD for sending. The returned MAD send buffer + * will reference a data buffer usable for sending a MAD, along + * with an initialized work request structure. Users may modify the returned + * MAD data buffer before posting the send. + * + * The returned MAD header, class specific headers, and any padding will be + * cleared. Users are responsible for initializing the common MAD header, + * any class specific header, and MAD data area. + * If @rmpp_active is set, the RMPP header will be initialized for sending. + */ +struct ib_mad_send_buf * ib_create_send_mad(struct ib_mad_agent *mad_agent, + u32 remote_qpn, u16 pkey_index, + int rmpp_active, + int hdr_len, int data_len, + gfp_t gfp_mask); + +/** + * ib_is_mad_class_rmpp - returns whether given management class + * supports RMPP. + * @mgmt_class: management class + * + * This routine returns whether the management class supports RMPP. + */ +int ib_is_mad_class_rmpp(u8 mgmt_class); + +/** + * ib_get_mad_data_offset - returns the data offset for a given + * management class. + * @mgmt_class: management class + * + * This routine returns the data offset in the MAD for the management + * class requested. + */ +int ib_get_mad_data_offset(u8 mgmt_class); + +/** + * ib_get_rmpp_segment - returns the data buffer for a given RMPP segment. + * @send_buf: Previously allocated send data buffer. + * @seg_num: number of segment to return + * + * This routine returns a pointer to the data buffer of an RMPP MAD. + * Users must provide synchronization to @send_buf around this call. + */ +void *ib_get_rmpp_segment(struct ib_mad_send_buf *send_buf, int seg_num); + +/** + * ib_free_send_mad - Returns data buffers used to send a MAD. + * @send_buf: Previously allocated send data buffer. + */ +void ib_free_send_mad(struct ib_mad_send_buf *send_buf); + +#endif /* IB_MAD_H */ diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/inc/ib_pack.h b/branches/WOF2-3/hw/mlx4/kernel/bus/inc/ib_pack.h new file mode 100644 index 00000000..6c50e11a --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/inc/ib_pack.h @@ -0,0 +1,276 @@ +/* + * Copyright (c) 2004 Topspin Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: ib_pack.h 1349 2004-12-16 21:09:43Z roland $ + */ + +#ifndef IB_PACK_H +#define IB_PACK_H + +#include "ib_verbs.h" + +enum { + IB_LRH_BYTES = 8, + IB_ETH_BYTES = 14, + IB_GRH_BYTES = 40, + IB_BTH_BYTES = 12, + IB_DETH_BYTES = 8 +}; + +struct ib_field { + size_t struct_offset_bytes; + size_t struct_size_bytes; + int offset_words; + int offset_bits; + int size_bits; + char *field_name; +}; + +#define RESERVED \ + .field_name = "reserved" + +/* + * This macro cleans up the definitions of constants for BTH opcodes. + * It is used to define constants such as IB_OPCODE_UD_SEND_ONLY, + * which becomes IB_OPCODE_UD + IB_OPCODE_SEND_ONLY, and this gives + * the correct value. + * + * In short, user code should use the constants defined using the + * macro rather than worrying about adding together other constants. +*/ +#define IB_OPCODE(transport, op) \ + IB_OPCODE_ ## transport ## _ ## op = \ + IB_OPCODE_ ## transport + IB_OPCODE_ ## op + +enum { + /* transport types -- just used to define real constants */ + IB_OPCODE_RC = 0x00, + IB_OPCODE_UC = 0x20, + IB_OPCODE_RD = 0x40, + IB_OPCODE_UD = 0x60, + + /* operations -- just used to define real constants */ + IB_OPCODE_SEND_FIRST = 0x00, + IB_OPCODE_SEND_MIDDLE = 0x01, + IB_OPCODE_SEND_LAST = 0x02, + IB_OPCODE_SEND_LAST_WITH_IMMEDIATE = 0x03, + IB_OPCODE_SEND_ONLY = 0x04, + IB_OPCODE_SEND_ONLY_WITH_IMMEDIATE = 0x05, + IB_OPCODE_RDMA_WRITE_FIRST = 0x06, + IB_OPCODE_RDMA_WRITE_MIDDLE = 0x07, + IB_OPCODE_RDMA_WRITE_LAST = 0x08, + IB_OPCODE_RDMA_WRITE_LAST_WITH_IMMEDIATE = 0x09, + IB_OPCODE_RDMA_WRITE_ONLY = 0x0a, + IB_OPCODE_RDMA_WRITE_ONLY_WITH_IMMEDIATE = 0x0b, + IB_OPCODE_RDMA_READ_REQUEST = 0x0c, + IB_OPCODE_RDMA_READ_RESPONSE_FIRST = 0x0d, + IB_OPCODE_RDMA_READ_RESPONSE_MIDDLE = 0x0e, + IB_OPCODE_RDMA_READ_RESPONSE_LAST = 0x0f, + IB_OPCODE_RDMA_READ_RESPONSE_ONLY = 0x10, + IB_OPCODE_ACKNOWLEDGE = 0x11, + IB_OPCODE_ATOMIC_ACKNOWLEDGE = 0x12, + IB_OPCODE_COMPARE_SWAP = 0x13, + IB_OPCODE_FETCH_ADD = 0x14, + + /* real constants follow -- see comment about above IB_OPCODE() + macro for more details */ + + /* RC */ + IB_OPCODE(RC, SEND_FIRST), + IB_OPCODE(RC, SEND_MIDDLE), + IB_OPCODE(RC, SEND_LAST), + IB_OPCODE(RC, SEND_LAST_WITH_IMMEDIATE), + IB_OPCODE(RC, SEND_ONLY), + IB_OPCODE(RC, SEND_ONLY_WITH_IMMEDIATE), + IB_OPCODE(RC, RDMA_WRITE_FIRST), + IB_OPCODE(RC, RDMA_WRITE_MIDDLE), + IB_OPCODE(RC, RDMA_WRITE_LAST), + IB_OPCODE(RC, RDMA_WRITE_LAST_WITH_IMMEDIATE), + IB_OPCODE(RC, RDMA_WRITE_ONLY), + IB_OPCODE(RC, RDMA_WRITE_ONLY_WITH_IMMEDIATE), + IB_OPCODE(RC, RDMA_READ_REQUEST), + IB_OPCODE(RC, RDMA_READ_RESPONSE_FIRST), + IB_OPCODE(RC, RDMA_READ_RESPONSE_MIDDLE), + IB_OPCODE(RC, RDMA_READ_RESPONSE_LAST), + IB_OPCODE(RC, RDMA_READ_RESPONSE_ONLY), + IB_OPCODE(RC, ACKNOWLEDGE), + IB_OPCODE(RC, ATOMIC_ACKNOWLEDGE), + IB_OPCODE(RC, COMPARE_SWAP), + IB_OPCODE(RC, FETCH_ADD), + + /* UC */ + IB_OPCODE(UC, SEND_FIRST), + IB_OPCODE(UC, SEND_MIDDLE), + IB_OPCODE(UC, SEND_LAST), + IB_OPCODE(UC, SEND_LAST_WITH_IMMEDIATE), + IB_OPCODE(UC, SEND_ONLY), + IB_OPCODE(UC, SEND_ONLY_WITH_IMMEDIATE), + IB_OPCODE(UC, RDMA_WRITE_FIRST), + IB_OPCODE(UC, RDMA_WRITE_MIDDLE), + IB_OPCODE(UC, RDMA_WRITE_LAST), + IB_OPCODE(UC, RDMA_WRITE_LAST_WITH_IMMEDIATE), + IB_OPCODE(UC, RDMA_WRITE_ONLY), + IB_OPCODE(UC, RDMA_WRITE_ONLY_WITH_IMMEDIATE), + + /* RD */ + IB_OPCODE(RD, SEND_FIRST), + IB_OPCODE(RD, SEND_MIDDLE), + IB_OPCODE(RD, SEND_LAST), + IB_OPCODE(RD, SEND_LAST_WITH_IMMEDIATE), + IB_OPCODE(RD, SEND_ONLY), + IB_OPCODE(RD, SEND_ONLY_WITH_IMMEDIATE), + IB_OPCODE(RD, RDMA_WRITE_FIRST), + IB_OPCODE(RD, RDMA_WRITE_MIDDLE), + IB_OPCODE(RD, RDMA_WRITE_LAST), + IB_OPCODE(RD, RDMA_WRITE_LAST_WITH_IMMEDIATE), + IB_OPCODE(RD, RDMA_WRITE_ONLY), + IB_OPCODE(RD, RDMA_WRITE_ONLY_WITH_IMMEDIATE), + IB_OPCODE(RD, RDMA_READ_REQUEST), + IB_OPCODE(RD, RDMA_READ_RESPONSE_FIRST), + IB_OPCODE(RD, RDMA_READ_RESPONSE_MIDDLE), + IB_OPCODE(RD, RDMA_READ_RESPONSE_LAST), + IB_OPCODE(RD, RDMA_READ_RESPONSE_ONLY), + IB_OPCODE(RD, ACKNOWLEDGE), + IB_OPCODE(RD, ATOMIC_ACKNOWLEDGE), + IB_OPCODE(RD, COMPARE_SWAP), + IB_OPCODE(RD, FETCH_ADD), + + /* UD */ + IB_OPCODE(UD, SEND_ONLY), + IB_OPCODE(UD, SEND_ONLY_WITH_IMMEDIATE) +}; + +enum { + IB_LNH_RAW = 0, + IB_LNH_IP = 1, + IB_LNH_IBA_LOCAL = 2, + IB_LNH_IBA_GLOBAL = 3 +}; + +struct ib_unpacked_lrh { + u8 virtual_lane; + u8 link_version; + u8 service_level; + u8 link_next_header; + __be16 destination_lid; + __be16 packet_length; + __be16 source_lid; +}; + +struct ib_unpacked_grh { + u8 ip_version; + u8 traffic_class; + __be32 flow_label; + __be16 payload_length; + u8 next_header; + u8 hop_limit; + union ib_gid source_gid; + union ib_gid destination_gid; +}; + +struct ib_unpacked_bth { + u8 opcode; + u8 solicited_event; + u8 mig_req; + u8 pad_count; + u8 transport_header_version; + __be16 pkey; + __be32 destination_qpn; + u8 ack_req; + __be32 psn; +}; + +struct ib_unpacked_deth { + __be32 qkey; + __be32 source_qpn; +}; + +struct ib_unpacked_eth { + u8 dmac_h[4]; + u8 dmac_l[2]; + u8 smac_h[2]; + u8 smac_l[4]; + __be16 type; +}; + + +struct ib_ud_header { + struct ib_unpacked_lrh lrh; + int grh_present; + struct ib_unpacked_grh grh; + struct ib_unpacked_bth bth; + struct ib_unpacked_deth deth; + int immediate_present; + __be32 immediate_data; +}; + + + +struct eth_ud_header { + struct ib_unpacked_eth eth; + int grh_present; + struct ib_unpacked_grh grh; + struct ib_unpacked_bth bth; + struct ib_unpacked_deth deth; + int immediate_present; + __be32 immediate_data; +}; + + +void ib_pack(const struct ib_field *desc, + int desc_len, + void *structure, + u8 *buf); + +void ib_unpack(const struct ib_field *desc, + int desc_len, + void *buf, + void *structure); + +void ib_ud_header_init(int payload_bytes, + int grh_present, + struct ib_ud_header *header); + +void ib_rdmaoe_ud_header_init(int payload_bytes, + int grh_present, + struct eth_ud_header *header); + +int ib_ud_header_pack(struct ib_ud_header *header, + void *buf); + +int ib_ud_header_unpack(void *buf, + struct ib_ud_header *header); + +int rdmaoe_ud_header_pack(struct eth_ud_header *header, + void *buf); + + +#endif /* IB_PACK_H */ diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/inc/ib_smi.h b/branches/WOF2-3/hw/mlx4/kernel/bus/inc/ib_smi.h new file mode 100644 index 00000000..1f80dab5 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/inc/ib_smi.h @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2004 Mellanox Technologies Ltd. All rights reserved. + * Copyright (c) 2004 Infinicon Corporation. All rights reserved. + * Copyright (c) 2004 Intel Corporation. All rights reserved. + * Copyright (c) 2004 Topspin Corporation. All rights reserved. + * Copyright (c) 2004 Voltaire Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: ib_smi.h 1389 2004-12-27 22:56:47Z roland $ + */ + +#if !defined( IB_SMI_H ) +#define IB_SMI_H + +#include + +#define IB_SMP_DATA_SIZE 64 +#define IB_SMP_MAX_PATH_HOPS 64 + +#pragma pack(push,1) +struct ib_smp { + u8 base_version; + u8 mgmt_class; + u8 class_version; + u8 method; + __be16 status; + u8 hop_ptr; + u8 hop_cnt; + __be64 tid; + __be16 attr_id; + __be16 resv; + __be32 attr_mod; + __be64 mkey; + __be16 dr_slid; + __be16 dr_dlid; + u8 reserved[28]; + u8 data[IB_SMP_DATA_SIZE]; + u8 initial_path[IB_SMP_MAX_PATH_HOPS]; + u8 return_path[IB_SMP_MAX_PATH_HOPS]; +} __attribute__ ((packed)); +#pragma pack(pop) + + +/* Subnet management attributes */ +#define IB_SMP_ATTR_NOTICE __constant_htons(0x0002) +#define IB_SMP_ATTR_NODE_DESC __constant_htons(0x0010) +#define IB_SMP_ATTR_NODE_INFO __constant_htons(0x0011) +#define IB_SMP_ATTR_SWITCH_INFO __constant_htons(0x0012) +#define IB_SMP_ATTR_GUID_INFO __constant_htons(0x0014) +#define IB_SMP_ATTR_PORT_INFO __constant_htons(0x0015) +#define IB_SMP_ATTR_PKEY_TABLE __constant_htons(0x0016) +#define IB_SMP_ATTR_SL_TO_VL_TABLE __constant_htons(0x0017) +#define IB_SMP_ATTR_VL_ARB_TABLE __constant_htons(0x0018) +#define IB_SMP_ATTR_LINEAR_FORWARD_TABLE __constant_htons(0x0019) +#define IB_SMP_ATTR_RANDOM_FORWARD_TABLE __constant_htons(0x001A) +#define IB_SMP_ATTR_MCAST_FORWARD_TABLE __constant_htons(0x001B) +#define IB_SMP_ATTR_SM_INFO __constant_htons(0x0020) +#define IB_SMP_ATTR_VENDOR_DIAG __constant_htons(0x0030) +#define IB_SMP_ATTR_LED_INFO __constant_htons(0x0031) +#define IB_SMP_ATTR_VENDOR_MASK __constant_htons(0xFF00) + +struct ib_port_info { + __be64 mkey; + __be64 gid_prefix; + __be16 lid; + __be16 sm_lid; + __be32 cap_mask; + __be16 diag_code; + __be16 mkey_lease_period; + u8 local_port_num; + u8 link_width_enabled; + u8 link_width_supported; + u8 link_width_active; + u8 linkspeed_portstate; /* 4 bits, 4 bits */ + u8 portphysstate_linkdown; /* 4 bits, 4 bits */ + u8 mkeyprot_resv_lmc; /* 2 bits, 3, 3 */ + u8 linkspeedactive_enabled; /* 4 bits, 4 bits */ + u8 neighbormtu_mastersmsl; /* 4 bits, 4 bits */ + u8 vlcap_inittype; /* 4 bits, 4 bits */ + u8 vl_high_limit; + u8 vl_arb_high_cap; + u8 vl_arb_low_cap; + u8 inittypereply_mtucap; /* 4 bits, 4 bits */ + u8 vlstallcnt_hoqlife; /* 3 bits, 5 bits */ + u8 operationalvl_pei_peo_fpi_fpo; /* 4 bits, 1, 1, 1, 1 */ + __be16 mkey_violations; + __be16 pkey_violations; + __be16 qkey_violations; + u8 guid_cap; + u8 clientrereg_resv_subnetto; /* 1 bit, 2 bits, 5 */ + u8 resv_resptimevalue; /* 3 bits, 5 bits */ + u8 localphyerrors_overrunerrors; /* 4 bits, 4 bits */ + __be16 max_credit_hint; + u8 resv; + u8 link_roundtrip_latency[3]; +}; + +static inline u8 +ib_get_smp_direction(struct ib_smp *smp) +{ + return (u8)((smp->status & IB_SMP_DIRECTION) == IB_SMP_DIRECTION); +} + +#endif /* IB_SMI_H */ diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/inc/ib_verbs.h b/branches/WOF2-3/hw/mlx4/kernel/bus/inc/ib_verbs.h new file mode 100644 index 00000000..44590df5 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/inc/ib_verbs.h @@ -0,0 +1,1913 @@ +/* + * Copyright (c) 2004 Mellanox Technologies Ltd. All rights reserved. + * Copyright (c) 2004 Infinicon Corporation. All rights reserved. + * Copyright (c) 2004 Intel Corporation. All rights reserved. + * Copyright (c) 2004 Topspin Corporation. All rights reserved. + * Copyright (c) 2004 Voltaire Corporation. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2005, 2006, 2007 Cisco Systems. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: ib_verbs.h 1349 2004-12-16 21:09:43Z roland $ + */ + +#if !defined(IB_VERBS_H) +#define IB_VERBS_H + +#include + +union ib_gid { + u8 raw[16]; + struct { + __be64 subnet_prefix; + __be64 interface_id; + } global; +}; + +#include "ib_verbs_ex.h" + +/* + * IPv6 address structure + */ + +struct in6_addr +{ + union + { + __u8 u6_addr8[16]; + __be16 u6_addr16[8]; + __be32 u6_addr32[4]; + } in6_u; +#define s6_addr in6_u.u6_addr8 +#define s6_addr16 in6_u.u6_addr16 +#define s6_addr32 in6_u.u6_addr32 +}; + + +struct sockaddr_in6 { + unsigned short int sin6_family; /* AF_INET6 */ + __be16 sin6_port; /* Transport layer port # */ + __be32 sin6_flowinfo; /* IPv6 flow information */ + struct in6_addr sin6_addr; /* IPv6 address */ + __u32 sin6_scope_id; /* scope id (new in RFC2553) */ +}; + +#define AF_INET6 10 /* IP version 6 */ + +enum rdma_node_type { + /* IB values map to NodeInfo:NodeType. */ + RDMA_NODE_IB_CA = 1, + RDMA_NODE_IB_SWITCH, + RDMA_NODE_IB_ROUTER, + RDMA_NODE_RNIC +}; + +enum rdma_transport_type +rdma_node_get_transport(enum rdma_node_type node_type) __attribute_const__; + +enum ib_device_cap_flags { + IB_DEVICE_RESIZE_MAX_WR = 1, + IB_DEVICE_BAD_PKEY_CNTR = (1<<1), + IB_DEVICE_BAD_QKEY_CNTR = (1<<2), + IB_DEVICE_RAW_MULTI = (1<<3), + IB_DEVICE_AUTO_PATH_MIG = (1<<4), + IB_DEVICE_CHANGE_PHY_PORT = (1<<5), + IB_DEVICE_UD_AV_PORT_ENFORCE = (1<<6), + IB_DEVICE_CURR_QP_STATE_MOD = (1<<7), + IB_DEVICE_SHUTDOWN_PORT = (1<<8), + IB_DEVICE_INIT_TYPE = (1<<9), + IB_DEVICE_PORT_ACTIVE_EVENT = (1<<10), + IB_DEVICE_SYS_IMAGE_GUID = (1<<11), + IB_DEVICE_RC_RNR_NAK_GEN = (1<<12), + IB_DEVICE_SRQ_RESIZE = (1<<13), + IB_DEVICE_N_NOTIFY_CQ = (1<<14), + IB_DEVICE_ZERO_STAG = (1<<15), + IB_DEVICE_SEND_W_INV = (1<<16), + IB_DEVICE_MEM_WINDOW = (1<<17), + IB_DEVICE_IPOIB_CSUM = (1<<18), + IB_DEVICE_UD_TSO = (1<<19) +}; + +enum ib_atomic_cap { + IB_ATOMIC_NON, + IB_ATOMIC_HCA, + IB_ATOMIC_GLOB +}; + +struct ib_device_attr { + u64 fw_ver; + __be64 sys_image_guid; + u64 max_mr_size; + u64 page_size_cap; + u32 vendor_id; + u32 vendor_part_id; + u32 hw_ver; + int max_qp; + int max_qp_wr; + int device_cap_flags; + int max_sge; + int max_sge_rd; + int max_cq; + int max_cqe; + int max_mr; + int max_pd; + int max_qp_rd_atom; + int max_ee_rd_atom; + int max_res_rd_atom; + int max_qp_init_rd_atom; + int max_ee_init_rd_atom; + enum ib_atomic_cap atomic_cap; + int max_ee; + int max_rdd; + int max_mw; + int max_raw_ipv6_qp; + int max_raw_ethy_qp; + int max_mcast_grp; + int max_mcast_qp_attach; + int max_total_mcast_qp_attach; + u64 max_ah; + int max_fmr; + int max_map_per_fmr; + int max_srq; + int max_srq_wr; + int max_srq_sge; + u16 max_pkeys; + u8 local_ca_ack_delay; +}; + +enum ib_mtu { + IB_MTU_256 = 1, + IB_MTU_512 = 2, + IB_MTU_1024 = 3, + IB_MTU_2048 = 4, + IB_MTU_4096 = 5 +}; + +static inline int ib_mtu_enum_to_int(enum ib_mtu mtu) +{ + switch (mtu) { + case IB_MTU_256: return 256; + case IB_MTU_512: return 512; + case IB_MTU_1024: return 1024; + case IB_MTU_2048: return 2048; + case IB_MTU_4096: return 4096; + default: return -1; + } +} + +enum ib_port_state { + IB_PORT_NOP = 0, + IB_PORT_DOWN = 1, + IB_PORT_INIT = 2, + IB_PORT_ARMED = 3, + IB_PORT_ACTIVE = 4, + IB_PORT_ACTIVE_DEFER = 5 +}; + +enum ib_port_cap_flags { + IB_PORT_SM = 1 << 1, + IB_PORT_NOTICE_SUP = 1 << 2, + IB_PORT_TRAP_SUP = 1 << 3, + IB_PORT_OPT_IPD_SUP = 1 << 4, + IB_PORT_AUTO_MIGR_SUP = 1 << 5, + IB_PORT_SL_MAP_SUP = 1 << 6, + IB_PORT_MKEY_NVRAM = 1 << 7, + IB_PORT_PKEY_NVRAM = 1 << 8, + IB_PORT_LED_INFO_SUP = 1 << 9, + IB_PORT_SM_DISABLED = 1 << 10, + IB_PORT_SYS_IMAGE_GUID_SUP = 1 << 11, + IB_PORT_PKEY_SW_EXT_PORT_TRAP_SUP = 1 << 12, + IB_PORT_CM_SUP = 1 << 16, + IB_PORT_SNMP_TUNNEL_SUP = 1 << 17, + IB_PORT_REINIT_SUP = 1 << 18, + IB_PORT_DEVICE_MGMT_SUP = 1 << 19, + IB_PORT_VENDOR_CLASS_SUP = 1 << 20, + IB_PORT_DR_NOTICE_SUP = 1 << 21, + IB_PORT_CAP_MASK_NOTICE_SUP = 1 << 22, + IB_PORT_BOOT_MGMT_SUP = 1 << 23, + IB_PORT_LINK_LATENCY_SUP = 1 << 24, + IB_PORT_CLIENT_REG_SUP = 1 << 25 +}; + +enum ib_port_width { + IB_WIDTH_1X = 1, + IB_WIDTH_4X = 2, + IB_WIDTH_8X = 4, + IB_WIDTH_12X = 8 +}; + +static inline int ib_width_enum_to_int(enum ib_port_width width) +{ + switch (width) { + case IB_WIDTH_1X: return 1; + case IB_WIDTH_4X: return 4; + case IB_WIDTH_8X: return 8; + case IB_WIDTH_12X: return 12; + default: return -1; + } +} + +struct ib_port_attr { + enum ib_port_state state; + enum ib_mtu max_mtu; + enum ib_mtu active_mtu; + int gid_tbl_len; + u32 port_cap_flags; + u32 max_msg_sz; + u32 bad_pkey_cntr; + u32 qkey_viol_cntr; + u16 pkey_tbl_len; + u16 lid; + u16 sm_lid; + u8 lmc; + u8 max_vl_num; + u8 sm_sl; + u8 subnet_timeout; + u8 init_type_reply; + u8 active_width; + u8 active_speed; + u8 phys_state; + enum rdma_transport_type transport; +}; + +enum ib_device_modify_flags { + IB_DEVICE_MODIFY_SYS_IMAGE_GUID = 1 << 0, + IB_DEVICE_MODIFY_NODE_DESC = 1 << 1 +}; + +struct ib_device_modify { + u64 sys_image_guid; + char node_desc[64]; +}; + +enum ib_port_modify_flags { + IB_PORT_SHUTDOWN = 1, + IB_PORT_INIT_TYPE = (1<<2), + IB_PORT_RESET_QKEY_CNTR = (1<<3) +}; + +struct ib_port_modify { + u32 set_port_cap_mask; + u32 clr_port_cap_mask; + u8 init_type; +}; + +enum ib_event_type { + IB_EVENT_CQ_ERR = IB_AE_CQ_ERROR, + IB_EVENT_QP_FATAL = IB_AE_QP_FATAL, + IB_EVENT_QP_REQ_ERR = IB_AE_WQ_REQ_ERROR, + IB_EVENT_QP_ACCESS_ERR = IB_AE_WQ_ACCESS_ERROR, + IB_EVENT_COMM_EST = IB_AE_QP_COMM, + IB_EVENT_SQ_DRAINED = IB_AE_SQ_DRAINED, + IB_EVENT_PATH_MIG = IB_AE_QP_APM, + IB_EVENT_PATH_MIG_ERR = IB_AE_QP_APM_ERROR, + IB_EVENT_DEVICE_FATAL = IB_AE_LOCAL_FATAL, + IB_EVENT_PORT_ACTIVE = IB_AE_PORT_ACTIVE, + IB_EVENT_PORT_ERR = IB_AE_PORT_DOWN, + IB_EVENT_SRQ_LIMIT_REACHED = IB_AE_SRQ_LIMIT_REACHED, + IB_EVENT_SRQ_ERR = IB_AE_SRQ_CATAS_ERROR, + IB_EVENT_QP_LAST_WQE_REACHED = IB_AE_SRQ_QP_LAST_WQE_REACHED, + IB_EVENT_RESET_DRIVER = IB_AE_RESET_DRIVER, // device will be reset upon fatal error + IB_EVENT_RESET_CLIENT = IB_AE_RESET_CLIENT, // device will be reset upon client request + IB_EVENT_RESET_END = IB_AE_RESET_END, // device has been reset + IB_EVENT_RESET_FAILED = IB_AE_RESET_FAILED, // device has been reset + IB_EVENT_LID_CHANGE = IB_AE_LID_CHANGE, + IB_EVENT_CLIENT_REREGISTER = IB_AE_CLIENT_REREGISTER, + IB_EVENT_PKEY_CHANGE = IB_AE_PKEY_CHANGE, + IB_EVENT_SM_CHANGE = IB_AE_SM_CHANGE +}; + +struct ib_event { + struct ib_device *device; + union { + struct ib_cq *cq; + struct ib_qp *qp; + struct ib_srq *srq; + u8 port_num; + } element; + enum ib_event_type event; + struct ib_event_ex x; +}; + +enum ib_event_handler_flags { + IB_IVH_RESET_CB = (1 << 0), // it is handler for soft reset + IB_IVH_NOTIFIED = (1 << 1), // client has been notified about requested reset + IB_IVH_RESET_READY = (1 << 2), // client is ready for HW reset + IB_IVH_RESET_D_PENDING = (1 << 3), // device reset notification is pending + IB_IVH_RESET_C_PENDING = (1 << 4), // client reset notification is pending + IB_IVH_NOTIF_READY = (1 << 5) // client is ready to get reset request notification +}; + +typedef void (*ib_event_handler_t)(struct ib_event_handler *, struct ib_event *); + +struct ib_event_handler { + struct ib_device *device; + ib_event_handler_t handler; + struct list_head list; + void * ctx; + void * rsrv_ptr; + u32 flags; +}; + +#define INIT_IB_EVENT_HANDLER(_ptr, _device, _handler, _ctx, _rptr, _flags) \ + { \ + (_ptr)->device = _device; \ + (_ptr)->handler = _handler; \ + INIT_LIST_HEAD(&(_ptr)->list); \ + (_ptr)->ctx = _ctx; \ + (_ptr)->rsrv_ptr = _rptr; \ + (_ptr)->flags = _flags; \ + } + +struct ib_global_route { + union ib_gid dgid; + u32 flow_label; + u8 sgid_index; + u8 hop_limit; + u8 traffic_class; +}; + +struct ib_grh { + __be32 version_tclass_flow; + __be16 paylen; + u8 next_hdr; + u8 hop_limit; + union ib_gid sgid; + union ib_gid dgid; +}; + +enum { + IB_MULTICAST_QPN = 0xffffff +}; + +#define XIB_LID_PERMISSIVE __constant_htons(0xFFFF) + +enum ib_ah_flags { + IB_AH_GRH = 1 +}; + +enum ib_rate { + IB_RATE_PORT_CURRENT = 0, + IB_RATE_2_5_GBPS = 2, + IB_RATE_5_GBPS = 5, + IB_RATE_10_GBPS = 3, + IB_RATE_20_GBPS = 6, + IB_RATE_30_GBPS = 4, + IB_RATE_40_GBPS = 7, + IB_RATE_60_GBPS = 8, + IB_RATE_80_GBPS = 9, + IB_RATE_120_GBPS = 10 +}; + +/** + * ib_rate_to_mult - Convert the IB rate enum to a multiple of the + * base rate of 2.5 Gbit/sec. For example, IB_RATE_5_GBPS will be + * converted to 2, since 5 Gbit/sec is 2 * 2.5 Gbit/sec. + * @rate: rate to convert. + */ +int ib_rate_to_mult(enum ib_rate rate) __attribute_const__; + +/** + * mult_to_ib_rate - Convert a multiple of 2.5 Gbit/sec to an IB rate + * enum. + * @mult: multiple to convert. + */ +enum ib_rate mult_to_ib_rate(int mult) __attribute_const__; + +struct ib_ah_attr { + struct ib_global_route grh; + u16 dlid; + u8 sl; + u8 src_path_bits; + u8 static_rate; + u8 ah_flags; + u8 port_num; +}; + +enum ib_wc_status { + IB_WC_SUCCESS, + IB_WC_LOC_LEN_ERR, + IB_WC_LOC_QP_OP_ERR, + IB_WC_LOC_EEC_OP_ERR, + IB_WC_LOC_PROT_ERR, + IB_WC_WR_FLUSH_ERR, + IB_WC_MW_BIND_ERR, + IB_WC_BAD_RESP_ERR, + IB_WC_LOC_ACCESS_ERR, + IB_WC_REM_INV_REQ_ERR, + IB_WC_REM_ACCESS_ERR, + IB_WC_REM_OP_ERR, + IB_WC_RETRY_EXC_ERR, + IB_WC_RNR_RETRY_EXC_ERR, + IB_WC_LOC_RDD_VIOL_ERR, + IB_WC_REM_INV_RD_REQ_ERR, + IB_WC_REM_ABORT_ERR, + IB_WC_INV_EECN_ERR, + IB_WC_INV_EEC_STATE_ERR, + IB_WC_FATAL_ERR, + IB_WC_RESP_TIMEOUT_ERR, + IB_WC_GENERAL_ERR +}; + +enum ib_wc_opcode { + XIB_WC_SEND, + XIB_WC_RDMA_WRITE, + XIB_WC_RDMA_READ, + XIB_WC_COMP_SWAP, + XIB_WC_FETCH_ADD, + XIB_WC_BIND_MW, + XIB_WC_LSO, //for Linux compatibility +/* + * Set value of XIB_WC_RECV so consumers can test if a completion is a + * receive by testing (opcode & XIB_WC_RECV). + */ + XIB_WC_RECV = 1 << 7, + XIB_WC_RECV_RDMA_WITH_IMM +}; + +enum ib_wc_flags { + IB_WC_GRH = 1, + IB_WC_WITH_IMM = (1<<1), + IB_WC_FORWARD = (1<<2) +}; + +struct ib_wc { + u64 wr_id; + enum ib_wc_status status; + enum ib_wc_opcode opcode; + u32 vendor_err; + u32 byte_len; + struct ib_qp *qp; + __be32 imm_data; + u32 src_qp; + int wc_flags; + u16 pkey_index; + u16 slid; + u8 sl; + u8 dlid_path_bits; + u8 port_num; /* valid only for DR SMPs on switches */ +}; + +enum ib_cq_notify_flags { + IB_CQ_SOLICITED = 1 << 0, + IB_CQ_NEXT_COMP = 1 << 1, + IB_CQ_SOLICITED_MASK = IB_CQ_SOLICITED | IB_CQ_NEXT_COMP, + IB_CQ_REPORT_MISSED_EVENTS = 1 << 2, +}; + +enum ib_srq_attr_mask { + XIB_SRQ_MAX_WR = 1 << 0, + XIB_SRQ_LIMIT = 1 << 1, +}; + +struct ib_srq_attr { + u32 max_wr; + u32 max_sge; + u32 srq_limit; +}; + +struct ib_srq_init_attr { + void (*event_handler)(ib_event_rec_t *); + void *srq_context; + struct ib_srq_attr attr; +}; + +struct ib_qp_cap { + u32 max_send_wr; + u32 max_recv_wr; + u32 max_send_sge; + u32 max_recv_sge; + u32 max_inline_data; +}; + +enum ib_sig_type { + IB_SIGNAL_ALL_WR, + IB_SIGNAL_REQ_WR +}; + +enum ib_qp_type { + /* + * IB_QPT_SMI and IB_QPT_GSI have to be the first two entries + * here (and in that order) since the MAD layer uses them as + * indices into a 2-entry table. + */ + IB_QPT_SMI, + IB_QPT_GSI, + + IB_QPT_RC, + IB_QPT_UC, + IB_QPT_UD, + IB_QPT_RAW_IP_V6, + IB_QPT_RAW_ETY +}; + +enum ib_qp_create_flags { + IB_QP_CREATE_IPOIB_UD_LSO = 1 << 0, +}; + +struct ib_qp_init_attr { + void (*event_handler)(ib_event_rec_t *); + void *qp_context; + struct ib_cq *send_cq; + struct ib_cq *recv_cq; + struct ib_srq *srq; + struct ib_qp_cap cap; + enum ib_sig_type sq_sig_type; + enum ib_qp_type qp_type; + enum ib_qp_create_flags create_flags; + u8 port_num; /* special QP types only */ +}; + +enum ib_rnr_timeout { + IB_RNR_TIMER_655_36 = 0, + IB_RNR_TIMER_000_01 = 1, + IB_RNR_TIMER_000_02 = 2, + IB_RNR_TIMER_000_03 = 3, + IB_RNR_TIMER_000_04 = 4, + IB_RNR_TIMER_000_06 = 5, + IB_RNR_TIMER_000_08 = 6, + IB_RNR_TIMER_000_12 = 7, + IB_RNR_TIMER_000_16 = 8, + IB_RNR_TIMER_000_24 = 9, + IB_RNR_TIMER_000_32 = 10, + IB_RNR_TIMER_000_48 = 11, + IB_RNR_TIMER_000_64 = 12, + IB_RNR_TIMER_000_96 = 13, + IB_RNR_TIMER_001_28 = 14, + IB_RNR_TIMER_001_92 = 15, + IB_RNR_TIMER_002_56 = 16, + IB_RNR_TIMER_003_84 = 17, + IB_RNR_TIMER_005_12 = 18, + IB_RNR_TIMER_007_68 = 19, + IB_RNR_TIMER_010_24 = 20, + IB_RNR_TIMER_015_36 = 21, + IB_RNR_TIMER_020_48 = 22, + IB_RNR_TIMER_030_72 = 23, + IB_RNR_TIMER_040_96 = 24, + IB_RNR_TIMER_061_44 = 25, + IB_RNR_TIMER_081_92 = 26, + IB_RNR_TIMER_122_88 = 27, + IB_RNR_TIMER_163_84 = 28, + IB_RNR_TIMER_245_76 = 29, + IB_RNR_TIMER_327_68 = 30, + IB_RNR_TIMER_491_52 = 31 +}; + +enum ib_qp_attr_mask { + IB_QP_STATE = 1, + IB_QP_CUR_STATE = (1<<1), + IB_QP_EN_SQD_ASYNC_NOTIFY = (1<<2), + IB_QP_ACCESS_FLAGS = (1<<3), + IB_QP_PKEY_INDEX = (1<<4), + IB_QP_PORT = (1<<5), + IB_QP_QKEY = (1<<6), + IB_QP_AV = (1<<7), + IB_QP_PATH_MTU = (1<<8), + IB_QP_TIMEOUT = (1<<9), + IB_QP_RETRY_CNT = (1<<10), + IB_QP_RNR_RETRY = (1<<11), + IB_QP_RQ_PSN = (1<<12), + IB_QP_MAX_QP_RD_ATOMIC = (1<<13), + IB_QP_ALT_PATH = (1<<14), + IB_QP_MIN_RNR_TIMER = (1<<15), + IB_QP_SQ_PSN = (1<<16), + IB_QP_MAX_DEST_RD_ATOMIC = (1<<17), + IB_QP_PATH_MIG_STATE = (1<<18), + IB_QP_CAP = (1<<19), + IB_QP_DEST_QPN = (1<<20) +}; + +enum ib_qp_state { + XIB_QPS_RESET, + XIB_QPS_INIT, + XIB_QPS_RTR, + XIB_QPS_RTS, + XIB_QPS_SQD, + XIB_QPS_SQE, + XIB_QPS_ERR +}; + +enum ib_mig_state { + IB_MIG_MIGRATED, + IB_MIG_REARM, + IB_MIG_ARMED +}; + +struct ib_qp_attr { + enum ib_qp_state qp_state; + enum ib_qp_state cur_qp_state; + enum ib_mtu path_mtu; + enum ib_mig_state path_mig_state; + u32 qkey; + u32 rq_psn; + u32 sq_psn; + u32 dest_qp_num; + int qp_access_flags; + struct ib_qp_cap cap; + struct ib_ah_attr ah_attr; + struct ib_ah_attr alt_ah_attr; + u16 pkey_index; + u16 alt_pkey_index; + u8 en_sqd_async_notify; + u8 sq_draining; + u8 max_rd_atomic; + u8 max_dest_rd_atomic; + u8 min_rnr_timer; + u8 port_num; + u8 timeout; + u8 retry_cnt; + u8 rnr_retry; + u8 alt_port_num; + u8 alt_timeout; +}; + +enum ib_wr_opcode { + IB_WR_RDMA_WRITE, + IB_WR_RDMA_WRITE_WITH_IMM, + IB_WR_SEND, + IB_WR_SEND_WITH_IMM, + IB_WR_RDMA_READ, + IB_WR_ATOMIC_CMP_AND_SWP, + IB_WR_ATOMIC_FETCH_AND_ADD, + IB_WR_LSO, + IB_WR_SEND_WITH_INV, + IB_WR_RDMA_READ_WITH_INV, + IB_WR_LOCAL_INV, + IB_WR_FAST_REG_MR, + IB_WR_NOP +}; + +enum ib_send_flags { + IB_SEND_FENCE = 1, + IB_SEND_SIGNALED = (1<<1), + IB_SEND_SOLICITED = (1<<2), + IB_SEND_INLINE = (1<<3) +}; + +struct ib_sge { + u64 addr; + u32 length; + u32 lkey; +}; + +struct ib_send_wr { + struct ib_send_wr *next; + u64 wr_id; + struct ib_sge *sg_list; + int num_sge; + enum ib_wr_opcode opcode; + int send_flags; + __be32 imm_data; + union { + struct { + u64 remote_addr; + u32 rkey; + } rdma; + struct { + u64 remote_addr; + u64 compare_add; + u64 swap; + u32 rkey; + } atomic; + struct { + struct ib_ah *ah; + void *header; + int hlen; + int mss; + u32 remote_qpn; + u32 remote_qkey; + u16 pkey_index; /* valid for GSI only */ + u8 port_num; /* valid for DR SMPs on switch only */ + } ud; + } wr; +}; + +struct ib_recv_wr { + struct ib_recv_wr *next; + u64 wr_id; + struct ib_sge *sg_list; + int num_sge; +}; + +enum ib_access_flags { + IB_ACCESS_LOCAL_WRITE = 1, + IB_ACCESS_REMOTE_WRITE = (1<<1), + IB_ACCESS_REMOTE_READ = (1<<2), + IB_ACCESS_REMOTE_ATOMIC = (1<<3), + IB_ACCESS_MW_BIND = (1<<4) +}; + +struct ib_phys_buf { + u64 addr; + u64 size; +}; + +struct ib_mr_attr { + struct ib_pd *pd; + u64 device_virt_addr; + u64 size; + int mr_access_flags; + u32 lkey; + u32 rkey; +}; + +enum ib_mr_rereg_flags { + IB_MR_REREG_TRANS = 1, + IB_MR_REREG_PD = (1<<1), + IB_MR_REREG_ACCESS = (1<<2) +}; + +struct ib_mw_bind { + struct ib_mr *mr; + u64 wr_id; + u64 addr; + u32 length; + int send_flags; + int mw_access_flags; +}; + +struct ib_fmr_attr { + int max_pages; + int max_maps; + u8 page_shift; +}; +struct ib_ucontext { + struct ib_device *device; + int closing; + struct ib_ucontext_ex x; +}; + +struct ib_udata { + void *inbuf; + void *outbuf; + size_t inlen; + size_t outlen; +}; + +#define INIT_UDATA(udata, ibuf, obuf, ilen, olen) \ + { \ + (udata)->inbuf = (void *) (ibuf); \ + (udata)->outbuf = (void *) (obuf); \ + (udata)->inlen = (ilen); \ + (udata)->outlen = (olen); \ + } + +struct ib_pd { + struct ib_device *device; + struct ib_ucontext *p_uctx; + atomic_t usecnt; /* count all resources */ +}; + +struct ib_ah { + struct ib_device *device; + struct ib_pd *pd; + struct ib_ucontext *p_uctx; +}; + +typedef void (*ib_comp_handler)(void *cq_context); + +struct ib_cq { + struct ib_device *device; + struct ib_ucontext *p_uctx; + ib_comp_handler comp_handler; + void (*event_handler)(ib_event_rec_t *); + void * cq_context; + int cqe; + atomic_t usecnt; /* count number of work queues */ +}; + +struct ib_srq { + struct ib_device *device; + struct ib_pd *pd; + struct ib_ucontext *p_uctx; + void (*event_handler)(ib_event_rec_t *); + void *srq_context; + atomic_t usecnt; +}; + +struct ib_qp { + struct ib_device *device; + struct ib_pd *pd; + struct ib_cq *send_cq; + struct ib_cq *recv_cq; + struct ib_srq *srq; + struct ib_ucontext *p_uctx; + void (*event_handler)(ib_event_rec_t *); + void *qp_context; + u32 qp_num; + enum ib_qp_type qp_type; +}; + +struct ib_mr { + struct ib_device *device; + struct ib_pd *pd; + struct ib_ucontext *p_uctx; + u32 lkey; + u32 rkey; + atomic_t usecnt; /* count number of MWs */ +}; + +struct ib_mw { + struct ib_device *device; + struct ib_pd *pd; + struct ib_ucontext *p_uctx; + u32 rkey; +}; + +struct ib_fmr { + struct ib_device *device; + struct ib_pd *pd; + struct list_head list; + u32 lkey; + u32 rkey; +}; + +struct ib_mad; +struct ib_grh; + +enum ib_process_mad_flags { + IB_MAD_IGNORE_MKEY = 1, + IB_MAD_IGNORE_BKEY = 2, + IB_MAD_IGNORE_ALL = IB_MAD_IGNORE_MKEY | IB_MAD_IGNORE_BKEY +}; + +enum ib_mad_result { + IB_MAD_RESULT_FAILURE = 0, /* (!SUCCESS is the important flag) */ + IB_MAD_RESULT_SUCCESS = 1 << 0, /* MAD was successfully processed */ + IB_MAD_RESULT_REPLY = 1 << 1, /* Reply packet needs to be sent */ + IB_MAD_RESULT_CONSUMED = 1 << 2 /* Packet consumed: stop processing */ +}; + +#define IB_DEVICE_NAME_MAX 64 + +struct ib_cache { + rwlock_t lock; + struct ib_event_handler event_handler; + struct ib_pkey_cache **pkey_cache; + struct ib_gid_cache **gid_cache; + u8 *lmc_cache; + struct ib_cache_ex x; +}; + +struct ib_dma_mapping_ops { + int (*mapping_error)(struct ib_device *dev, + u64 dma_addr); + u64 (*map_single)(struct ib_device *dev, + void *ptr, size_t size, + enum dma_data_direction direction); + void (*unmap_single)(struct ib_device *dev, + u64 addr, size_t size, + enum dma_data_direction direction); + u64 (*map_page)(struct ib_device *dev, + dma_addr_t page, unsigned long offset, + size_t size, + enum dma_data_direction direction); + void (*unmap_page)(struct ib_device *dev, + u64 addr, size_t size, + enum dma_data_direction direction); + int (*map_sg)(struct ib_device *dev, + struct scatterlist *sg, int nents, + enum dma_data_direction direction); + void (*unmap_sg)(struct ib_device *dev, + struct scatterlist *sg, int nents, + enum dma_data_direction direction); + u64 (*dma_address)(struct ib_device *dev, + struct scatterlist *sg); + unsigned int (*dma_len)(struct ib_device *dev, + struct scatterlist *sg); + void (*sync_single_for_cpu)(struct ib_device *dev, + u64 dma_handle, + size_t size, + enum dma_data_direction dir); + void (*sync_single_for_device)(struct ib_device *dev, + u64 dma_handle, + size_t size, + enum dma_data_direction dir); + void *(*alloc_coherent)(struct ib_device *dev, + size_t size, + u64 *dma_handle, + gfp_t flag); + void (*free_coherent)(struct ib_device *dev, + size_t size, void *cpu_addr, + u64 dma_handle); +}; + +struct iw_cm_verbs; + +struct ib_device { + struct mlx4_dev *dma_device; + + char name[IB_DEVICE_NAME_MAX]; + + struct list_head event_handler_list; + spinlock_t event_handler_lock; + + struct list_head core_list; + struct list_head client_data_list; + spinlock_t client_data_lock; + + struct ib_cache cache; + int *pkey_tbl_len; + int *gid_tbl_len; + + u32 flags; + + int num_comp_vectors; + + struct iw_cm_verbs *iwcm; + + int (*query_device)(struct ib_device *device, + struct ib_device_attr *device_attr); + int (*query_port)(struct ib_device *device, + u8 port_num, + struct ib_port_attr *port_attr); + enum rdma_transport_type (*get_port_transport)(struct ib_device *device, + u8 port_num); + + int (*query_gid_chunk)(struct ib_device *device, + u8 port_num, int index, + union ib_gid gid[8], int size); + int (*query_pkey_chunk)(struct ib_device *device, + u8 port_num, u16 index, __be16 pkey[32], int size); + int (*modify_device)(struct ib_device *device, + int device_modify_mask, + struct ib_device_modify *device_modify); + int (*modify_port)(struct ib_device *device, + u8 port_num, int port_modify_mask, + struct ib_port_modify *port_modify); + struct ib_ucontext * (*alloc_ucontext)(struct ib_device *device, + struct ib_udata *udata); + int (*dealloc_ucontext)(struct ib_ucontext *context); + int (*mmap)(struct ib_ucontext *context, + struct vm_area_struct *vma); + struct ib_pd * (*alloc_pd)(struct ib_device *device, + struct ib_ucontext *context, + struct ib_udata *udata); + int (*dealloc_pd)(struct ib_pd *pd); + struct ib_ah * (*create_ah)(struct ib_pd *pd, + struct ib_ah_attr *ah_attr); + int (*modify_ah)(struct ib_ah *ah, + struct ib_ah_attr *ah_attr); + int (*query_ah)(struct ib_ah *ah, + struct ib_ah_attr *ah_attr); + int (*destroy_ah)(struct ib_ah *ah); + struct ib_srq * (*create_srq)(struct ib_pd *pd, + struct ib_srq_init_attr *srq_init_attr, + struct ib_udata *udata); + int (*modify_srq)(struct ib_srq *srq, + struct ib_srq_attr *srq_attr, + enum ib_srq_attr_mask srq_attr_mask, + struct ib_udata *udata); + int (*query_srq)(struct ib_srq *srq, + struct ib_srq_attr *srq_attr); + int (*destroy_srq)(struct ib_srq *srq); + int (*post_srq_recv)(struct ib_srq *srq, + ib_recv_wr_t *recv_wr, + ib_recv_wr_t **bad_recv_wr); + struct ib_qp * (*create_qp)(struct ib_pd *pd, + struct ib_qp_init_attr *qp_init_attr, + struct ib_udata *udata); + int (*modify_qp)(struct ib_qp *qp, + struct ib_qp_attr *qp_attr, + int qp_attr_mask, + struct ib_udata *udata); + int (*query_qp)(struct ib_qp *qp, + struct ib_qp_attr *qp_attr, + int qp_attr_mask, + struct ib_qp_init_attr *qp_init_attr); + int (*destroy_qp)(struct ib_qp *qp); + int (*post_send)(struct ib_qp *qp, + ib_send_wr_t *send_wr, + ib_send_wr_t **bad_send_wr); + int (*post_recv)(struct ib_qp *qp, + ib_recv_wr_t *recv_wr, + ib_recv_wr_t **bad_recv_wr); + struct ib_cq * (*create_cq)(struct ib_device *device, int cqe, + int comp_vector, + struct ib_ucontext *context, + struct ib_udata *udata); + int (*modify_cq)(struct ib_cq *cq, u16 cq_count, + u16 cq_period); + int (*destroy_cq)(struct ib_cq *cq); + int (*resize_cq)(struct ib_cq *cq, int cqe, + struct ib_udata *udata); + int (*poll_cq)(struct ib_cq *ibcq, + ib_wc_t** const pp_free_wclist, ib_wc_t** const pp_done_wclist); + int (*peek_cq)(struct ib_cq *cq, int wc_cnt); + int (*req_notify_cq)(struct ib_cq *cq, + enum ib_cq_notify_flags flags); + int (*req_ncomp_notif)(struct ib_cq *cq, + int wc_cnt); + struct ib_mr * (*get_dma_mr)(struct ib_pd *pd, + int mr_access_flags); + struct ib_mr * (*reg_phys_mr)(struct ib_pd *pd, + struct ib_phys_buf *phys_buf_array, + int num_phys_buf, + int mr_access_flags, + u64 *iova_start); + struct ib_mr * (*reg_user_mr)(struct ib_pd *pd, + u64 start, u64 length, + u64 virt_addr, + int mr_access_flags, + struct ib_udata *udata); + int (*query_mr)(struct ib_mr *mr, + struct ib_mr_attr *mr_attr); + int (*dereg_mr)(struct ib_mr *mr); + int (*rereg_phys_mr)(struct ib_mr *mr, + int mr_rereg_mask, + struct ib_pd *pd, + struct ib_phys_buf *phys_buf_array, + int num_phys_buf, + int mr_access_flags, + u64 *iova_start); + struct ib_mw * (*alloc_mw)(struct ib_pd *pd); + int (*bind_mw)(struct ib_qp *qp, + struct ib_mw *mw, + struct ib_mw_bind *mw_bind); + int (*dealloc_mw)(struct ib_mw *mw); + struct ib_fmr * (*alloc_fmr)(struct ib_pd *pd, + int mr_access_flags, + struct ib_fmr_attr *fmr_attr); + int (*map_phys_fmr)(struct ib_fmr *fmr, + u64 *page_list, int list_len, + u64 iova); + int (*unmap_fmr)(struct list_head *fmr_list); + int (*dealloc_fmr)(struct ib_fmr *fmr); + int (*attach_mcast)(struct ib_qp *qp, + union ib_gid *gid, + u16 lid); + int (*detach_mcast)(struct ib_qp *qp, + union ib_gid *gid, + u16 lid); + int (*process_mad)(struct ib_device *device, + int process_mad_flags, + u8 port_num, + ib_wc_t *in_wc, + struct ib_grh *in_grh, + struct ib_mad *in_mad, + struct ib_mad *out_mad); + + struct ib_dma_mapping_ops *dma_ops; + struct list_head port_list; + + enum { + IB_DEV_UNINITIALIZED, + IB_DEV_REGISTERED, + IB_DEV_UNREGISTERED + } reg_state; + + u64 uverbs_cmd_mask; + int uverbs_abi_ver; + + char node_desc[64]; + __be64 node_guid; + u8 node_type; + u8 phys_port_cnt; + struct ib_device_ex x; +}; + +struct ib_client { + char *name; + void (*add) (struct ib_device *); + void (*remove)(struct ib_device *); + + struct list_head list; +}; + +struct ib_device *ib_alloc_device(size_t size); +void ib_dealloc_device(struct ib_device *device); + +int ib_register_device (struct ib_device *device); +void ib_unregister_device(struct ib_device *device); + +int ib_register_client (struct ib_client *client); +void ib_unregister_client(struct ib_client *client); + +void *ib_get_client_data(struct ib_device *device, struct ib_client *client); +void ib_set_client_data(struct ib_device *device, struct ib_client *client, + void *data); + +static inline int ib_copy_from_udata(void *dest, struct ib_udata *udata, size_t len) +{ + if (len > udata->inlen) + return -EFAULT; + memcpy(dest, udata->inbuf, len); + return 0; +} + +static inline int ib_copy_to_udata(struct ib_udata *udata, void *src, size_t len) +{ + if (len > udata->outlen) + return -EFAULT; + memcpy(udata->outbuf, src, len); + return 0; +} + +/** + * ib_modify_qp_is_ok - Check that the supplied attribute mask + * contains all required attributes and no attributes not allowed for + * the given QP state transition. + * @cur_state: Current QP state + * @next_state: Next QP state + * @type: QP type + * @mask: Mask of supplied QP attributes + * + * This function is a helper function that a low-level driver's + * modify_qp method can use to validate the consumer's input. It + * checks that cur_state and next_state are valid QP states, that a + * transition from cur_state to next_state is allowed by the IB spec, + * and that the attribute mask supplied is allowed for the transition. + */ +int ib_modify_qp_is_ok(enum ib_qp_state cur_state, enum ib_qp_state next_state, + enum ib_qp_type type, enum ib_qp_attr_mask mask); + +int ib_register_event_handler (struct ib_event_handler *event_handler); +int ib_unregister_event_handler(struct ib_event_handler *event_handler); +void ib_dispatch_event(struct ib_event *event); + +int ib_query_device(struct ib_device *device, + struct ib_device_attr *device_attr); + +int ib_query_port(struct ib_device *device, + u8 port_num, struct ib_port_attr *port_attr); + +enum rdma_transport_type rdma_port_get_transport(struct ib_device *device, + u8 port_num); +int rdma_is_transport_supported(struct ib_device *device, + enum rdma_transport_type transport); + +int ib_query_gid_chunk(struct ib_device *device, + u8 port_num, int index, union ib_gid gid[8], int size); + +int ib_query_pkey_chunk(struct ib_device *device, + u8 port_num, u16 index, __be16 pkey[32], int size); + +int ib_modify_device(struct ib_device *device, + int device_modify_mask, + struct ib_device_modify *device_modify); + +int ib_modify_port(struct ib_device *device, + u8 port_num, int port_modify_mask, + struct ib_port_modify *port_modify); + +int ib_find_gid(struct ib_device *device, union ib_gid *gid, + u8 *port_num, u16 *index); + +int ib_find_pkey(struct ib_device *device, + u8 port_num, __be16 pkey, u16 *index); + +/** + * ib_alloc_pd - Allocates an unused protection domain. + * @device: The device on which to allocate the protection domain. + * + * A protection domain object provides an association between QPs, shared + * receive queues, address handles, memory regions, and memory windows. + */ +struct ib_pd *ib_alloc_pd(struct ib_device *device); + +/** + * ib_dealloc_pd - Deallocates a protection domain. + * @pd: The protection domain to deallocate. + */ +int ib_dealloc_pd(struct ib_pd *pd); + +/** + * ib_create_ah - Creates an address handle for the given address vector. + * @pd: The protection domain associated with the address handle. + * @ah_attr: The attributes of the address vector. + * + * The address handle is used to reference a local or global destination + * in all UD QP post sends. + */ +struct ib_ah *ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr); + +/** + * ib_init_ah_from_wc - Initializes address handle attributes from a + * work completion. + * @device: Device on which the received message arrived. + * @port_num: Port on which the received message arrived. + * @wc: Work completion associated with the received message. + * @grh: References the received global route header. This parameter is + * ignored unless the work completion indicates that the GRH is valid. + * @ah_attr: Returned attributes that can be used when creating an address + * handle for replying to the message. + */ +int ib_init_ah_from_wc(struct ib_device *device, u8 port_num, ib_wc_t *wc, + struct ib_grh *grh, struct ib_ah_attr *ah_attr); + +/** + * ib_create_ah_from_wc - Creates an address handle associated with the + * sender of the specified work completion. + * @pd: The protection domain associated with the address handle. + * @wc: Work completion information associated with a received message. + * @grh: References the received global route header. This parameter is + * ignored unless the work completion indicates that the GRH is valid. + * @port_num: The outbound port number to associate with the address. + * + * The address handle is used to reference a local or global destination + * in all UD QP post sends. + */ +struct ib_ah *ib_create_ah_from_wc(struct ib_pd *pd, ib_wc_t *wc, + struct ib_grh *grh, u8 port_num); + +/** + * ib_modify_ah - Modifies the address vector associated with an address + * handle. + * @ah: The address handle to modify. + * @ah_attr: The new address vector attributes to associate with the + * address handle. + */ +int ib_modify_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr); + +/** + * ib_query_ah - Queries the address vector associated with an address + * handle. + * @ah: The address handle to query. + * @ah_attr: The address vector attributes associated with the address + * handle. + */ +int ib_query_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr); + +/** + * ib_destroy_ah - Destroys an address handle. + * @ah: The address handle to destroy. + */ +int ib_destroy_ah(struct ib_ah *ah); + +/** + * ib_create_srq - Creates a SRQ associated with the specified protection + * domain. + * @pd: The protection domain associated with the SRQ. + * @srq_init_attr: A list of initial attributes required to create the + * SRQ. If SRQ creation succeeds, then the attributes are updated to + * the actual capabilities of the created SRQ. + * + * srq_attr->max_wr and srq_attr->max_sge are read the determine the + * requested size of the SRQ, and set to the actual values allocated + * on return. If ib_create_srq() succeeds, then max_wr and max_sge + * will always be at least as large as the requested values. + */ +struct ib_srq *ib_create_srq(struct ib_pd *pd, + struct ib_srq_init_attr *srq_init_attr); + +/** + * ib_modify_srq - Modifies the attributes for the specified SRQ. + * @srq: The SRQ to modify. + * @srq_attr: On input, specifies the SRQ attributes to modify. On output, + * the current values of selected SRQ attributes are returned. + * @srq_attr_mask: A bit-mask used to specify which attributes of the SRQ + * are being modified. + * + * The mask may contain XIB_SRQ_MAX_WR to resize the SRQ and/or + * XIB_SRQ_LIMIT to set the SRQ's limit and request notification when + * the number of receives queued drops below the limit. + */ +int ib_modify_srq(struct ib_srq *srq, + struct ib_srq_attr *srq_attr, + enum ib_srq_attr_mask srq_attr_mask); + +/** + * ib_query_srq - Returns the attribute list and current values for the + * specified SRQ. + * @srq: The SRQ to query. + * @srq_attr: The attributes of the specified SRQ. + */ +int ib_query_srq(struct ib_srq *srq, + struct ib_srq_attr *srq_attr); + +/** + * ib_destroy_srq - Destroys the specified SRQ. + * @srq: The SRQ to destroy. + */ +int ib_destroy_srq(struct ib_srq *srq); + +/** + * ib_post_srq_recv - Posts a list of work requests to the specified SRQ. + * @srq: The SRQ to post the work request on. + * @recv_wr: A list of work requests to post on the receive queue. + * @bad_recv_wr: On an immediate failure, this parameter will reference + * the work request that failed to be posted on the QP. + */ +static inline int ib_post_srq_recv(struct ib_srq *srq, + ib_recv_wr_t *recv_wr, + ib_recv_wr_t **bad_recv_wr) +{ + return srq->device->post_srq_recv(srq, recv_wr, bad_recv_wr); +} + +/** + * ib_create_qp - Creates a QP associated with the specified protection + * domain. + * @pd: The protection domain associated with the QP. + * @qp_init_attr: A list of initial attributes required to create the + * QP. If QP creation succeeds, then the attributes are updated to + * the actual capabilities of the created QP. + */ +struct ib_qp *ib_create_qp(struct ib_pd *pd, + struct ib_qp_init_attr *qp_init_attr); + +/** + * ib_modify_qp - Modifies the attributes for the specified QP and then + * transitions the QP to the given state. + * @qp: The QP to modify. + * @qp_attr: On input, specifies the QP attributes to modify. On output, + * the current values of selected QP attributes are returned. + * @qp_attr_mask: A bit-mask used to specify which attributes of the QP + * are being modified. + */ +int ib_modify_qp(struct ib_qp *qp, + struct ib_qp_attr *qp_attr, + int qp_attr_mask); + +/** + * ib_query_qp - Returns the attribute list and current values for the + * specified QP. + * @qp: The QP to query. + * @qp_attr: The attributes of the specified QP. + * @qp_attr_mask: A bit-mask used to select specific attributes to query. + * @qp_init_attr: Additional attributes of the selected QP. + * + * The qp_attr_mask may be used to limit the query to gathering only the + * selected attributes. + */ +int ib_query_qp(struct ib_qp *qp, + struct ib_qp_attr *qp_attr, + int qp_attr_mask, + struct ib_qp_init_attr *qp_init_attr); + +/** + * ib_modify_cq - Modifies moderation params of the CQ + * @cq: The CQ to modify. + * @cq_count: number of CQEs that will tirgger an event + * @cq_period: max period of time beofre triggering an event + * + * Users can examine the cq structure to determine the actual CQ size. + */ +int ib_modify_cq(struct ib_cq *cq, u16 cq_count, u16 cq_period); + +/** + * ib_destroy_qp - Destroys the specified QP. + * @qp: The QP to destroy. + */ +int ib_destroy_qp(struct ib_qp *qp); + +/** + * ib_post_send - Posts a list of work requests to the send queue of + * the specified QP. + * @qp: The QP to post the work request on. + * @send_wr: A list of work requests to post on the send queue. + * @bad_send_wr: On an immediate failure, this parameter will reference + * the work request that failed to be posted on the QP. + */ +static inline int ib_post_send(struct ib_qp *qp, + ib_send_wr_t *send_wr, + ib_send_wr_t **bad_send_wr) +{ + return qp->device->post_send(qp, send_wr, bad_send_wr); +} + +/** + * ib_post_recv - Posts a list of work requests to the receive queue of + * the specified QP. + * @qp: The QP to post the work request on. + * @recv_wr: A list of work requests to post on the receive queue. + * @bad_recv_wr: On an immediate failure, this parameter will reference + * the work request that failed to be posted on the QP. + */ +static inline int ib_post_recv(struct ib_qp *qp, + ib_recv_wr_t *recv_wr, + ib_recv_wr_t **bad_recv_wr) +{ + return qp->device->post_recv(qp, recv_wr, bad_recv_wr); +} + +/** + * ib_create_cq - Creates a CQ on the specified device. + * @device: The device on which to create the CQ. + * @comp_handler: A user-specified callback that is invoked when a + * completion event occurs on the CQ. + * @event_handler: A user-specified callback that is invoked when an + * asynchronous event not associated with a completion occurs on the CQ. + * @cq_context: Context associated with the CQ returned to the user via + * the associated completion and event handlers. + * @cqe: The minimum size of the CQ. + * @comp_vector - Completion vector used to signal completion events. + * Must be >= 0 and < context->num_comp_vectors. + * + * Users can examine the cq structure to determine the actual CQ size. + */ +struct ib_cq *ib_create_cq(struct ib_device *device, + ib_comp_handler comp_handler, + void (*event_handler)(ib_event_rec_t *), + void *cq_context, int cqe, int comp_vector); + +/** + * ib_resize_cq - Modifies the capacity of the CQ. + * @cq: The CQ to resize. + * @cqe: The minimum size of the CQ. + * + * Users can examine the cq structure to determine the actual CQ size. + */ +int ib_resize_cq(struct ib_cq *cq, int cqe); + +/** + * ib_destroy_cq - Destroys the specified CQ. + * @cq: The CQ to destroy. + */ +int ib_destroy_cq(struct ib_cq *cq); + +/** + * ib_poll_cq - poll a CQ for completion(s) + * @cq:the CQ being polled + * @pp_free_wclist: + * On input, a list of work completion structures provided by + * the client. These are used to report completed work requests through + * the pp_done_wclist. + * + * On output, this contains the list of work completions structures for + * which no work completion was found. + * @pp_done_wclist:A list of work completions retrieved from the completion queue. + * + * Poll a CQ for (possibly multiple) completions. If the return value + * is < 0, an error occurred. If the return value is >= 0, it is the + * number of completions returned. If the return value is + * non-negative and < num_entries, then the CQ was emptied. + */ +static inline int ib_poll_cq(struct ib_cq *cq, ib_wc_t** const pp_free_wclist, + ib_wc_t** const pp_done_wclist) +{ + return cq->device->poll_cq(cq, pp_free_wclist, pp_done_wclist); +} + +/** + * ib_peek_cq - Returns the number of unreaped completions currently + * on the specified CQ. + * @cq: The CQ to peek. + * @wc_cnt: A minimum number of unreaped completions to check for. + * + * If the number of unreaped completions is greater than or equal to wc_cnt, + * this function returns wc_cnt, otherwise, it returns the actual number of + * unreaped completions. + */ +int ib_peek_cq(struct ib_cq *cq, int wc_cnt); + +/** + * ib_req_notify_cq - Request completion notification on a CQ. + * @cq: The CQ to generate an event for. + * @flags: + * Must contain exactly one of %IB_CQ_SOLICITED or %IB_CQ_NEXT_COMP + * to request an event on the next solicited event or next work + * completion at any type, respectively. %IB_CQ_REPORT_MISSED_EVENTS + * may also be |ed in to request a hint about missed events, as + * described below. + * + * Return Value: + * < 0 means an error occurred while requesting notification + * == 0 means notification was requested successfully, and if + * IB_CQ_REPORT_MISSED_EVENTS was passed in, then no events + * were missed and it is safe to wait for another event. In + * this case is it guaranteed that any work completions added + * to the CQ since the last CQ poll will trigger a completion + * notification event. + * > 0 is only returned if IB_CQ_REPORT_MISSED_EVENTS was passed + * in. It means that the consumer must poll the CQ again to + * make sure it is empty to avoid missing an event because of a + * race between requesting notification and an entry being + * added to the CQ. This return value means it is possible + * (but not guaranteed) that a work completion has been added + * to the CQ since the last poll without triggering a + * completion notification event. + */ +static inline int ib_req_notify_cq(struct ib_cq *cq, + enum ib_cq_notify_flags flags) +{ + return cq->device->req_notify_cq(cq, flags); +} + +/** + * ib_req_ncomp_notif - Request completion notification when there are + * at least the specified number of unreaped completions on the CQ. + * @cq: The CQ to generate an event for. + * @wc_cnt: The number of unreaped completions that should be on the + * CQ before an event is generated. + */ +static inline int ib_req_ncomp_notif(struct ib_cq *cq, int wc_cnt) +{ + return cq->device->req_ncomp_notif ? + cq->device->req_ncomp_notif(cq, wc_cnt) : + -ENOSYS; +} + +/** + * ib_get_dma_mr - Returns a memory region for system memory that is + * usable for DMA. + * @pd: The protection domain associated with the memory region. + * @mr_access_flags: Specifies the memory access rights. + * + * Note that the ib_dma_*() functions defined below must be used + * to create/destroy addresses used with the Lkey or Rkey returned + * by ib_get_dma_mr(). + */ +struct ib_mr *ib_get_dma_mr(struct ib_pd *pd, int mr_access_flags); + +#if 0 +// TODO: do we need that +/** + * ib_dma_mapping_error - check a DMA addr for error + * @dev: The device for which the dma_addr was created + * @dma_addr: The DMA address to check + */ +static inline int ib_dma_mapping_error(struct ib_device *dev, u64 dma_addr) +{ + if (dev->dma_ops) + return dev->dma_ops->mapping_error(dev, dma_addr); + return dma_mapping_error(dma_addr); +} + +/** + * ib_dma_map_single - Map a kernel virtual address to DMA address + * @dev: The device for which the dma_addr is to be created + * @cpu_addr: The kernel virtual address + * @size: The size of the region in bytes + * @direction: The direction of the DMA + */ +static inline u64 ib_dma_map_single(struct ib_device *dev, + void *cpu_addr, size_t size, + enum dma_data_direction direction) +{ + if (dev->dma_ops) + return dev->dma_ops->map_single(dev, cpu_addr, size, direction); + return dma_map_single(dev->dma_device, cpu_addr, size, direction); +} + +/** + * ib_dma_unmap_single - Destroy a mapping created by ib_dma_map_single() + * @dev: The device for which the DMA address was created + * @addr: The DMA address + * @size: The size of the region in bytes + * @direction: The direction of the DMA + */ +static inline void ib_dma_unmap_single(struct ib_device *dev, + u64 addr, size_t size, + enum dma_data_direction direction) +{ + if (dev->dma_ops) + dev->dma_ops->unmap_single(dev, addr, size, direction); + else + dma_unmap_single(dev->dma_device, addr, size, direction); +} + +/** + * ib_dma_map_page - Map a physical page to DMA address + * @dev: The device for which the dma_addr is to be created + * @page: The page to be mapped + * @offset: The offset within the page + * @size: The size of the region in bytes + * @direction: The direction of the DMA + */ +static inline u64 ib_dma_map_page(struct ib_device *dev, + struct page *page, + unsigned long offset, + size_t size, + enum dma_data_direction direction) +{ + if (dev->dma_ops) + return dev->dma_ops->map_page(dev, page, offset, size, direction); + return dma_map_page(dev->dma_device, page, offset, size, direction); +} + +/** + * ib_dma_unmap_page - Destroy a mapping created by ib_dma_map_page() + * @dev: The device for which the DMA address was created + * @addr: The DMA address + * @size: The size of the region in bytes + * @direction: The direction of the DMA + */ +static inline void ib_dma_unmap_page(struct ib_device *dev, + u64 addr, size_t size, + enum dma_data_direction direction) +{ + if (dev->dma_ops) + dev->dma_ops->unmap_page(dev, addr, size, direction); + else + dma_unmap_page(dev->dma_device, addr, size, direction); +} + +/** + * ib_dma_map_sg - Map a scatter/gather list to DMA addresses + * @dev: The device for which the DMA addresses are to be created + * @sg: The array of scatter/gather entries + * @nents: The number of scatter/gather entries + * @direction: The direction of the DMA + */ +static inline int ib_dma_map_sg(struct ib_device *dev, + struct scatterlist *sg, int nents, + enum dma_data_direction direction) +{ + if (dev->dma_ops) + return dev->dma_ops->map_sg(dev, sg, nents, direction); + return dma_map_sg(dev->dma_device, sg, nents, direction); +} + +/** + * ib_dma_unmap_sg - Unmap a scatter/gather list of DMA addresses + * @dev: The device for which the DMA addresses were created + * @sg: The array of scatter/gather entries + * @nents: The number of scatter/gather entries + * @direction: The direction of the DMA + */ +static inline void ib_dma_unmap_sg(struct ib_device *dev, + struct scatterlist *sg, int nents, + enum dma_data_direction direction) +{ + if (dev->dma_ops) + dev->dma_ops->unmap_sg(dev, sg, nents, direction); + else + dma_unmap_sg(dev->dma_device, sg, nents, direction); +} + +/** + * ib_sg_dma_address - Return the DMA address from a scatter/gather entry + * @dev: The device for which the DMA addresses were created + * @sg: The scatter/gather entry + */ +static inline u64 ib_sg_dma_address(struct ib_device *dev, + struct scatterlist *sg) +{ + if (dev->dma_ops) + return dev->dma_ops->dma_address(dev, sg); + return sg_dma_address(sg); +} + +/** + * ib_sg_dma_len - Return the DMA length from a scatter/gather entry + * @dev: The device for which the DMA addresses were created + * @sg: The scatter/gather entry + */ +static inline unsigned int ib_sg_dma_len(struct ib_device *dev, + struct scatterlist *sg) +{ + if (dev->dma_ops) + return dev->dma_ops->dma_len(dev, sg); + return sg_dma_len(sg); +} + +/** + * ib_dma_sync_single_for_cpu - Prepare DMA region to be accessed by CPU + * @dev: The device for which the DMA address was created + * @addr: The DMA address + * @size: The size of the region in bytes + * @dir: The direction of the DMA + */ +static inline void ib_dma_sync_single_for_cpu(struct ib_device *dev, + u64 addr, + size_t size, + enum dma_data_direction dir) +{ + if (dev->dma_ops) + dev->dma_ops->sync_single_for_cpu(dev, addr, size, dir); + else + dma_sync_single_for_cpu(dev->dma_device, addr, size, dir); +} + +/** + * ib_dma_sync_single_for_device - Prepare DMA region to be accessed by device + * @dev: The device for which the DMA address was created + * @addr: The DMA address + * @size: The size of the region in bytes + * @dir: The direction of the DMA + */ +static inline void ib_dma_sync_single_for_device(struct ib_device *dev, + u64 addr, + size_t size, + enum dma_data_direction dir) +{ + if (dev->dma_ops) + dev->dma_ops->sync_single_for_device(dev, addr, size, dir); + else + dma_sync_single_for_device(dev->dma_device, addr, size, dir); +} + +/** + * ib_dma_alloc_coherent - Allocate memory and map it for DMA + * @dev: The device for which the DMA address is requested + * @size: The size of the region to allocate in bytes + * @dma_handle: A pointer for returning the DMA address of the region + * @flag: memory allocator flags + */ +static inline void *ib_dma_alloc_coherent(struct ib_device *dev, + size_t size, + u64 *dma_handle, + gfp_t flag) +{ + if (dev->dma_ops) + return dev->dma_ops->alloc_coherent(dev, size, dma_handle, flag); + else { + dma_addr_t handle; + void *ret; + + ret = dma_alloc_coherent(dev->dma_device, size, &handle, flag); + *dma_handle = handle; + return ret; + } +} + +/** + * ib_dma_free_coherent - Free memory allocated by ib_dma_alloc_coherent() + * @dev: The device for which the DMA addresses were allocated + * @size: The size of the region + * @cpu_addr: the address returned by ib_dma_alloc_coherent() + * @dma_handle: the DMA address returned by ib_dma_alloc_coherent() + */ +static inline void ib_dma_free_coherent(struct ib_device *dev, + size_t size, void *cpu_addr, + u64 dma_handle) +{ + if (dev->dma_ops) + dev->dma_ops->free_coherent(dev, size, cpu_addr, dma_handle); + else + dma_free_coherent(dev->dma_device, size, cpu_addr, dma_handle); +} + +#endif + +/** + * ib_reg_phys_mr - Prepares a virtually addressed memory region for use + * by an HCA. + * @pd: The protection domain associated assigned to the registered region. + * @phys_buf_array: Specifies a list of physical buffers to use in the + * memory region. + * @num_phys_buf: Specifies the size of the phys_buf_array. + * @mr_access_flags: Specifies the memory access rights. + * @iova_start: The offset of the region's starting I/O virtual address. + */ +struct ib_mr *ib_reg_phys_mr(struct ib_pd *pd, + struct ib_phys_buf *phys_buf_array, + int num_phys_buf, + int mr_access_flags, + u64 *iova_start); + +/** + * ib_rereg_phys_mr - Modifies the attributes of an existing memory region. + * Conceptually, this call performs the functions deregister memory region + * followed by register physical memory region. Where possible, + * resources are reused instead of deallocated and reallocated. + * @mr: The memory region to modify. + * @mr_rereg_mask: A bit-mask used to indicate which of the following + * properties of the memory region are being modified. + * @pd: If %IB_MR_REREG_PD is set in mr_rereg_mask, this field specifies + * the new protection domain to associated with the memory region, + * otherwise, this parameter is ignored. + * @phys_buf_array: If %IB_MR_REREG_TRANS is set in mr_rereg_mask, this + * field specifies a list of physical buffers to use in the new + * translation, otherwise, this parameter is ignored. + * @num_phys_buf: If %IB_MR_REREG_TRANS is set in mr_rereg_mask, this + * field specifies the size of the phys_buf_array, otherwise, this + * parameter is ignored. + * @mr_access_flags: If %IB_MR_REREG_ACCESS is set in mr_rereg_mask, this + * field specifies the new memory access rights, otherwise, this + * parameter is ignored. + * @iova_start: The offset of the region's starting I/O virtual address. + */ +int ib_rereg_phys_mr(struct ib_mr *mr, + int mr_rereg_mask, + struct ib_pd *pd, + struct ib_phys_buf *phys_buf_array, + int num_phys_buf, + int mr_access_flags, + u64 *iova_start); + +/** + * ib_query_mr - Retrieves information about a specific memory region. + * @mr: The memory region to retrieve information about. + * @mr_attr: The attributes of the specified memory region. + */ +int ib_query_mr(struct ib_mr *mr, struct ib_mr_attr *mr_attr); + +/** + * ib_dereg_mr - Deregisters a memory region and removes it from the + * HCA translation table. + * @mr: The memory region to deregister. + */ +int ib_dereg_mr(struct ib_mr *mr); + +/** + * ib_alloc_mw - Allocates a memory window. + * @pd: The protection domain associated with the memory window. + */ +struct ib_mw *ib_alloc_mw(struct ib_pd *pd); + +/** + * ib_bind_mw - Posts a work request to the send queue of the specified + * QP, which binds the memory window to the given address range and + * remote access attributes. + * @qp: QP to post the bind work request on. + * @mw: The memory window to bind. + * @mw_bind: Specifies information about the memory window, including + * its address range, remote access rights, and associated memory region. + */ +static inline int ib_bind_mw(struct ib_qp *qp, + struct ib_mw *mw, + struct ib_mw_bind *mw_bind) +{ + /* XXX reference counting in corresponding MR? */ + return mw->device->bind_mw ? + mw->device->bind_mw(qp, mw, mw_bind) : + -ENOSYS; +} + +/** + * ib_dealloc_mw - Deallocates a memory window. + * @mw: The memory window to deallocate. + */ +int ib_dealloc_mw(struct ib_mw *mw); + +/** + * ib_alloc_fmr - Allocates a unmapped fast memory region. + * @pd: The protection domain associated with the unmapped region. + * @mr_access_flags: Specifies the memory access rights. + * @fmr_attr: Attributes of the unmapped region. + * + * A fast memory region must be mapped before it can be used as part of + * a work request. + */ +struct ib_fmr *ib_alloc_fmr(struct ib_pd *pd, + int mr_access_flags, + struct ib_fmr_attr *fmr_attr); + +/** + * ib_map_phys_fmr - Maps a list of physical pages to a fast memory region. + * @fmr: The fast memory region to associate with the pages. + * @page_list: An array of physical pages to map to the fast memory region. + * @list_len: The number of pages in page_list. + * @iova: The I/O virtual address to use with the mapped region. + */ +static inline int ib_map_phys_fmr(struct ib_fmr *fmr, + u64 *page_list, int list_len, + u64 iova) +{ + return fmr->device->map_phys_fmr(fmr, page_list, list_len, iova); +} + +/** + * ib_unmap_fmr - Removes the mapping from a list of fast memory regions. + * @fmr_list: A linked list of fast memory regions to unmap. + */ +int ib_unmap_fmr(struct list_head *fmr_list); + +/** + * ib_dealloc_fmr - Deallocates a fast memory region. + * @fmr: The fast memory region to deallocate. + */ +int ib_dealloc_fmr(struct ib_fmr *fmr); + +/** + * ib_attach_mcast - Attaches the specified QP to a multicast group. + * @qp: QP to attach to the multicast group. The QP must be type + * IB_QPT_UD. + * @gid: Multicast group GID. + * @lid: Multicast group LID in host byte order. + * + * In order to send and receive multicast packets, subnet + * administration must have created the multicast group and configured + * the fabric appropriately. The port associated with the specified + * QP must also be a member of the multicast group. + */ +int ib_attach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid); + +/** + * ib_detach_mcast - Detaches the specified QP from a multicast group. + * @qp: QP to detach from the multicast group. + * @gid: Multicast group GID. + * @lid: Multicast group LID in host byte order. + */ +int ib_detach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid); + +#endif /* IB_VERBS_H */ diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/inc/ib_verbs_ex.h b/branches/WOF2-3/hw/mlx4/kernel/bus/inc/ib_verbs_ex.h new file mode 100644 index 00000000..6ad4ad7e --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/inc/ib_verbs_ex.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: al.c 1611 2006-08-20 14:48:55Z sleybo $ + */ + +#pragma once + +#include "shutter.h" + +typedef struct _FDO_DEVICE_DATA *PFDO_DEVICE_DATA; +struct ib_cq; +struct ib_event_handler; + +/* extension for ib_device */ +struct ib_device_ex +{ + PFDO_DEVICE_DATA p_fdo; + int (*get_cached_gid)(struct ib_device *device, + u8 port_num, int index, union ib_gid *gid); + int (*find_cached_gid)(struct ib_device *device, + union ib_gid *gid, u8 *port_num, u16 *index); + int (*get_cached_pkey)(struct ib_device *device, + u8 port_num, int index, __be16 *pkey); + int (*find_cached_pkey)(struct ib_device *device, + u8 port_num, __be16 pkey, u16 *index); + int (*register_ev_cb) (struct ib_event_handler *event_handler); + int (*unregister_ev_cb) (struct ib_event_handler *event_handler); +#if 1//WORKAROUND_POLL_EQ + void (*poll_eq)(struct ib_device *device, BOOLEAN bStart); +#endif +}; + + +/* extension for ib_ucontext */ +typedef struct { + PVOID uva; + PMDL mdl; + PVOID kva; + int mapped; +} umap_t; + +struct ib_ucontext_ex +{ + cl_list_item_t list_item; // chain of user contexts + umap_t uar; + umap_t bf; + atomic_t usecnt; /* count all resources */ + // for tools support + struct mutex mutex; + PMDL p_mdl; + PVOID va; + int fw_if_open; +}; + +/* extension for ib_event */ +struct ib_event_ex +{ + uint64_t vendor_specific; +}; + +/* extension for ib_cache */ +struct ib_cache_ex +{ + shutter_t work_thread; +}; + + diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/inc/qp.h b/branches/WOF2-3/hw/mlx4/kernel/bus/inc/qp.h new file mode 100644 index 00000000..a6ba2377 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/inc/qp.h @@ -0,0 +1,312 @@ +/* + * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef MLX4_QP_H +#define MLX4_QP_H + +#include "device.h" + +#define MLX4_INVALID_LKEY 0x100 + +enum mlx4_qp_optpar { + MLX4_QP_OPTPAR_ALT_ADDR_PATH = 1 << 0, + MLX4_QP_OPTPAR_RRE = 1 << 1, + MLX4_QP_OPTPAR_RAE = 1 << 2, + MLX4_QP_OPTPAR_RWE = 1 << 3, + MLX4_QP_OPTPAR_PKEY_INDEX = 1 << 4, + MLX4_QP_OPTPAR_Q_KEY = 1 << 5, + MLX4_QP_OPTPAR_RNR_TIMEOUT = 1 << 6, + MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH = 1 << 7, + MLX4_QP_OPTPAR_SRA_MAX = 1 << 8, + MLX4_QP_OPTPAR_RRA_MAX = 1 << 9, + MLX4_QP_OPTPAR_PM_STATE = 1 << 10, + MLX4_QP_OPTPAR_RETRY_COUNT = 1 << 12, + MLX4_QP_OPTPAR_RNR_RETRY = 1 << 13, + MLX4_QP_OPTPAR_ACK_TIMEOUT = 1 << 14, + MLX4_QP_OPTPAR_SCHED_QUEUE = 1 << 16, + MLX4_QP_OPTPAR_RSS_RCA = 1 << 17, + MLX4_QP_OPTPAR_SRQN = 1 << 18, + MLX4_QP_OPTPAR_CQN_RCV = 1 << 19 +}; + +enum mlx4_qp_state { + MLX4_QP_STATE_RST = 0, + MLX4_QP_STATE_INIT = 1, + MLX4_QP_STATE_RTR = 2, + MLX4_QP_STATE_RTS = 3, + MLX4_QP_STATE_SQER = 4, + MLX4_QP_STATE_SQD = 5, + MLX4_QP_STATE_ERR = 6, + MLX4_QP_STATE_SQ_DRAINING = 7, + MLX4_QP_NUM_STATE +}; + +enum { + MLX4_QP_ST_RC = 0x0, + MLX4_QP_ST_UC = 0x1, + MLX4_QP_ST_RD = 0x2, + MLX4_QP_ST_UD = 0x3, + MLX4_QP_ST_MLX = 0x7 +}; + +enum { + MLX4_QP_PM_MIGRATED = 0x3, + MLX4_QP_PM_ARMED = 0x0, + MLX4_QP_PM_REARM = 0x1 +}; + +enum { + /* params1 */ + MLX4_QP_BIT_SRE = 1 << 15, + MLX4_QP_BIT_SWE = 1 << 14, + MLX4_QP_BIT_SAE = 1 << 13, + /* params2 */ + MLX4_QP_BIT_RRE = 1 << 15, + MLX4_QP_BIT_RWE = 1 << 14, + MLX4_QP_BIT_RAE = 1 << 13, + MLX4_QP_BIT_RIC = 1 << 4, +}; + +struct mlx4_qp_path { + u8 fl; + u8 reserved1[2]; + u8 pkey_index; + u8 reserved2; + u8 grh_mylmc; + __be16 rlid; + u8 ackto; + u8 mgid_index; + u8 static_rate; + u8 hop_limit; + __be32 tclass_flowlabel; + u8 rgid[16]; + u8 sched_queue; + u8 snooper_flags; + u8 reserved3[2]; + u8 counter_index; + u8 reserved4; + u8 dmac[6]; + +}; + +struct mlx4_qp_context { + __be32 flags; + __be32 pd; + u8 mtu_msgmax; + u8 rq_size_stride; + u8 sq_size_stride; + u8 rlkey; + __be32 usr_page; + __be32 local_qpn; + __be32 remote_qpn; + struct mlx4_qp_path pri_path; + struct mlx4_qp_path alt_path; + __be32 params1; + u32 reserved1; + __be32 next_send_psn; + __be32 cqn_send; + u32 reserved2[2]; + __be32 last_acked_psn; + __be32 ssn; + __be32 params2; + __be32 rnr_nextrecvpsn; + __be32 srcd; + __be32 cqn_recv; + __be64 db_rec_addr; + __be32 qkey; + __be32 srqn; + __be32 msn; + __be16 rq_wqe_counter; + __be16 sq_wqe_counter; + u32 reserved3[2]; + __be32 param3; + __be32 nummmcpeers_basemkey; + u8 log_page_size; + u8 reserved4[2]; + u8 mtt_base_addr_h; + __be32 mtt_base_addr_l; + u32 reserved5[10]; +}; + +enum { + MLX4_WQE_CTRL_FENCE = 1 << 6, + MLX4_WQE_CTRL_CQ_UPDATE = 3 << 2, + MLX4_WQE_CTRL_SOLICITED = 1 << 1, + MLX4_WQE_CTRL_IP_CSUM = 1 << 4, + MLX4_WQE_CTRL_TCP_UDP_CSUM = 1 << 5 +}; + +struct mlx4_wqe_ctrl_seg { + __be32 owner_opcode; + u8 reserved2[3]; + u8 fence_size; + /* + * High 24 bits are SRC remote buffer; low 8 bits are flags: + * [7] SO (strong ordering) + * [5] TCP/UDP checksum + * [4] IP checksum + * [3:2] C (generate completion queue entry) + * [1] SE (solicited event) + */ + __be32 srcrb_flags; + /* + * imm is immediate data for send/RDMA write w/ immediate; + * also invalidation key for send with invalidate; input + * modifier for WQEs on CCQs. + */ + __be32 imm; +}; + +enum { + MLX4_WQE_MLX_VL15 = 1 << 17, + MLX4_WQE_MLX_SLR = 1 << 16 +}; + +struct mlx4_wqe_mlx_seg { + u8 owner; + u8 reserved1[2]; + u8 opcode; + u8 reserved2[3]; + u8 size; + /* + * [17] VL15 + * [16] SLR + * [15:12] static rate + * [11:8] SL + * [4] ICRC + * [3:2] C + * [0] FL (force loopback) + */ + __be32 flags; + __be16 rlid; + u16 reserved3; +}; + +struct mlx4_wqe_datagram_seg { + __be32 av[8]; + __be32 dqpn; + __be32 qkey; + __be16 vlan; + u8 mac_0_1[2]; + u8 mac_2_5[4]; +}; + +#pragma warning( disable : 4200) +struct mlx4_lso_seg { +__be32 mss_hdr_size; +__be32 header[0]; +}; +#pragma warning( default : 4200) + + +struct mlx4_wqe_bind_seg { + __be32 flags1; + __be32 flags2; + __be32 new_rkey; + __be32 lkey; + __be64 addr; + __be64 length; +}; + +struct mlx4_wqe_fmr_seg { + __be32 flags; + __be32 mem_key; + __be64 buf_list; + __be64 start_addr; + __be64 reg_len; + __be32 offset; + __be32 page_size; + u32 reserved[2]; +}; + +struct mlx4_wqe_fmr_ext_seg { + u8 flags; + u8 reserved; + __be16 app_mask; + __be16 wire_app_tag; + __be16 mem_app_tag; + __be32 wire_ref_tag_base; + __be32 mem_ref_tag_base; +}; + +struct mlx4_wqe_local_inval_seg { + u8 flags; + u8 reserved1[3]; + __be32 mem_key; + u8 reserved2[3]; + u8 guest_id; + __be64 pa; +}; + +struct mlx4_wqe_raddr_seg { + __be64 raddr; + __be32 rkey; + u32 reserved; +}; + +struct mlx4_wqe_atomic_seg { + __be64 swap_add; + __be64 compare; +}; + +struct mlx4_wqe_data_seg { + __be32 byte_count; + __be32 lkey; + __be64 addr; +}; + +enum { + MLX4_INLINE_ALIGN = 64, +}; + +struct mlx4_wqe_inline_seg { + __be32 byte_count; +}; + +int mlx4_qp_query(struct mlx4_dev *dev, struct mlx4_qp *qp, + struct mlx4_qp_context *context); + + + +int mlx4_qp_get_region(struct mlx4_dev *dev, + enum qp_region region, + int *base_qpn, int *cnt); + +static inline struct mlx4_qp *__mlx4_qp_lookup(struct mlx4_dev *dev, u32 qpn) +{ + return (struct mlx4_qp *)radix_tree_lookup(&dev->qp_table_tree, qpn & (dev->caps.num_qps - 1)); +} + + +struct mlx4_qp *mlx4_qp_lookup_locked(struct mlx4_dev *dev, u32 qpn); + +#endif /* MLX4_QP_H */ diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/inc/srq.h b/branches/WOF2-3/hw/mlx4/kernel/bus/inc/srq.h new file mode 100644 index 00000000..799a0697 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/inc/srq.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef MLX4_SRQ_H +#define MLX4_SRQ_H + +struct mlx4_wqe_srq_next_seg { + u16 reserved1; + __be16 next_wqe_index; + u32 reserved2[3]; +}; + +#endif /* MLX4_SRQ_H */ diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/net/Makefile.lnx b/branches/WOF2-3/hw/mlx4/kernel/bus/net/Makefile.lnx new file mode 100644 index 00000000..0952a652 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/net/Makefile.lnx @@ -0,0 +1,4 @@ +obj-$(CONFIG_MLX4_CORE) += mlx4_core.o + +mlx4_core-y := alloc.o catas.o cmd.o cq.o eq.o fw.o icm.o intf.o main.o mcg.o \ + mr.o pd.o profile.o qp.o reset.o srq.o diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/net/SOURCES b/branches/WOF2-3/hw/mlx4/kernel/bus/net/SOURCES new file mode 100644 index 00000000..e06a1251 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/net/SOURCES @@ -0,0 +1,54 @@ +TARGETNAME=mlx4_net +TARGETPATH=..\..\..\..\..\bin\kernel\obj$(BUILD_ALT_DIR) +TARGETTYPE=DRIVER_LIBRARY + + + +!if $(FREEBUILD) +ENABLE_EVENT_TRACING=1 +!else +#ENABLE_EVENT_TRACING=1 +!endif + + +DLLDEF=net.def + +SOURCES= net.rc \ + alloc.c \ + catas.c \ + cmd.c \ + cq.c \ + eq.c \ + fw.c \ + icm.c \ + intf.c \ + main.c \ + mcg.c \ + mr.c \ + pd.c \ + profile.c \ + qp.c \ + srq.c \ + port.c \ + +INCLUDES=..;..\inc;..\..\inc;..\..\..\inc;..\core\$O;..\..\..\..\..\inc;..\..\..\..\..\inc\kernel; + +C_DEFINES=$(C_DEFINES) -DDRIVER -DDEPRECATE_DDK_FUNCTIONS -D__LITTLE_ENDIAN -DUSE_WDM_INTERRUPTS +#-DFORCE_LIVEFISH + +TARGETLIBS= \ + $(DDK_LIB_PATH)\ntstrsafe.lib \ + $(TARGETPATH)\*\complib.lib \ + $(TARGETPATH)\*\mlx4_core.lib \ + +!IFDEF ENABLE_EVENT_TRACING + +C_DEFINES = $(C_DEFINES) -DEVENT_TRACING + +RUN_WPP = $(SOURCES) -km -ext: .c .h .C .H \ + -scan:..\..\inc\mlx4_debug.h \ + -func:MLX4_PRINT(LEVEL,FLAGS,(MSG,...)) \ + -func:MLX4_PRINT_EXIT(LEVEL,FLAGS,(MSG,...)) +!ENDIF + +MSC_WARNING_LEVEL= /W4 diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/net/alloc.c b/branches/WOF2-3/hw/mlx4/kernel/bus/net/alloc.c new file mode 100644 index 00000000..52d999fe --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/net/alloc.c @@ -0,0 +1,448 @@ +/* + * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "mlx4.h" +#include + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "alloc.tmh" +#endif + + +u32 mlx4_bitmap_alloc(struct mlx4_bitmap *bitmap) +{ + u32 obj; + + spin_lock(&bitmap->lock); + + obj = find_next_zero_bit(bitmap->table, + bitmap->effective_max, + bitmap->last); + if (obj >= bitmap->effective_max) { + bitmap->top = (bitmap->top + bitmap->max) & bitmap->mask; + obj = find_first_zero_bit(bitmap->table, bitmap->effective_max); + } + + if (obj < bitmap->effective_max) { + set_bit(obj, bitmap->table); + bitmap->last = (obj + 1); + if (bitmap->last == bitmap->effective_max) + bitmap->last = 0; + obj |= bitmap->top; + } else + obj = (u32)-1; + + spin_unlock(&bitmap->lock); + + return obj; +} + +void mlx4_bitmap_free(struct mlx4_bitmap *bitmap, u32 obj) +{ + obj &= bitmap->max - 1; + + spin_lock(&bitmap->lock); + clear_bit(obj, bitmap->table); + bitmap->last = min(bitmap->last, obj); + bitmap->top = (bitmap->top + bitmap->max) & bitmap->mask; + spin_unlock(&bitmap->lock); +} + +static unsigned long find_next_zero_string_aligned(unsigned long *bitmap, + u32 start, u32 nbits, + int len, int align) +{ + unsigned long end, i; + +again: + start = ALIGN(start, align); + while ((start < nbits) && test_bit(start, bitmap)) + start += align; + if (start >= nbits) + return ULONG_MAX; + + end = start+len; + if (end > nbits) + return ULONG_MAX; + for (i = start+1; i < end; i++) { + if (test_bit(i, bitmap)) { + start = i+1; + goto again; + } + } + return start; +} + +u32 mlx4_bitmap_alloc_range(struct mlx4_bitmap *bitmap, int cnt, int align) +{ + u32 obj; + int i; + + if (likely(cnt == 1 && align == 1)) + return mlx4_bitmap_alloc(bitmap); + + spin_lock(&bitmap->lock); + + obj = find_next_zero_string_aligned(bitmap->table, bitmap->last, + bitmap->effective_max, cnt, align); + if (obj >= bitmap->effective_max) { + bitmap->top = (bitmap->top + bitmap->max) & bitmap->mask; + obj = find_next_zero_string_aligned(bitmap->table, 0, + bitmap->effective_max, + cnt, align); + } + + if (obj < bitmap->effective_max) { + for (i = 0; i < cnt; i++) + set_bit(obj+i, bitmap->table); + if (obj == bitmap->last) { + bitmap->last = (obj + cnt); + if (bitmap->last >= bitmap->effective_max) + bitmap->last = 0; + } + obj |= bitmap->top; + } else + obj = ULONG_MAX; + + spin_unlock(&bitmap->lock); + + + return obj; +} + +void mlx4_bitmap_free_range(struct mlx4_bitmap *bitmap, u32 obj, int cnt) +{ + int i; + + obj &= bitmap->max - 1; + + spin_lock(&bitmap->lock); + for (i = 0; i < cnt; i++) + clear_bit(obj+i, bitmap->table); + bitmap->last = min(bitmap->last, obj); + bitmap->top = (bitmap->top + bitmap->max) & bitmap->mask; + spin_unlock(&bitmap->lock); +} +int mlx4_bitmap_init_with_effective_max(struct mlx4_bitmap *bitmap, + u32 num, u32 mask, u32 reserved, + u32 effective_max) +{ + int i; + + /* num must be a power of 2 */ + if (num != roundup_pow_of_two(num)) + return -EINVAL; + + bitmap->last = 0; + bitmap->top = 0; + bitmap->max = num; + bitmap->mask = mask; + bitmap->effective_max = effective_max; + spin_lock_init(&bitmap->lock); + bitmap->table = kzalloc(BITS_TO_LONGS(num) * sizeof (long), GFP_KERNEL); + if (!bitmap->table) + return -ENOMEM; + + for (i = 0; i < (int)reserved; ++i) + set_bit(i, bitmap->table); + + return 0; +} + +int mlx4_bitmap_init(struct mlx4_bitmap *bitmap, + u32 num, u32 mask, u32 reserved) +{ + return mlx4_bitmap_init_with_effective_max(bitmap, num, mask, + reserved, num); +} + +void mlx4_bitmap_cleanup(struct mlx4_bitmap *bitmap) +{ + kfree(bitmap->table); +} + +/* + * Handling for queue buffers -- we allocate a bunch of memory and + * register it in a memory region at HCA virtual address 0. If the + * requested size is > max_direct, we split the allocation into + * multiple pages, so we don't require too much contiguous memory. + */ + +int mlx4_buf_alloc(struct mlx4_dev *dev, int size, int max_direct, + struct mlx4_buf *buf) +{ + dma_addr_t t; + + if (size <= max_direct) { + buf->nbufs = 1; + buf->npages = 1; + // TODO: we don't use pages less then PAGE_SIZE + size = max(size, PAGE_SIZE); + buf->page_shift = get_order(size) + PAGE_SHIFT; + buf->u.direct.buf = dma_alloc_coherent(&dev->pdev->dev, + size, &t, GFP_KERNEL); + if (!buf->u.direct.buf) + return -ENOMEM; + + buf->u.direct.map = t; + + while (t.da & ((1 << buf->page_shift) - 1)) { + --buf->page_shift; + buf->npages *= 2; + } + MLX4_PRINT( TRACE_LEVEL_INFORMATION, MLX4_DBG_CQ, + ("size %#x, nbufs %d, pages %d, page_shift %d, kva %p, da %I64x, buf_size %#x\n", + size, buf->nbufs, buf->npages, buf->page_shift, + buf->u.direct.buf, t.da, t.sz )); + memset(buf->u.direct.buf, 0, size); + } else { + int i; + + buf->nbufs = (size + PAGE_SIZE - 1) / PAGE_SIZE; + buf->npages = buf->nbufs; + buf->page_shift = PAGE_SHIFT; + buf->u.page_list = kzalloc(buf->nbufs * sizeof *buf->u.page_list, + GFP_KERNEL); + if (!buf->u.page_list) + return -ENOMEM; + + for (i = 0; i < buf->nbufs; ++i) { + buf->u.page_list[i].buf = + dma_alloc_coherent(&dev->pdev->dev, PAGE_SIZE, + &t, GFP_KERNEL); + if (!buf->u.page_list[i].buf) + goto err_free; + + buf->u.page_list[i].map = t; + + memset(buf->u.page_list[i].buf, 0, PAGE_SIZE); + } + } + + return 0; + +err_free: + mlx4_buf_free(dev, size, buf); + + return -ENOMEM; +} +EXPORT_SYMBOL_GPL(mlx4_buf_alloc); + +void mlx4_buf_free(struct mlx4_dev *dev, int size, struct mlx4_buf *buf) +{ + int i; + + // TODO: we don't use pages less then PAGE_SIZE + size = max(size, PAGE_SIZE); + + if (buf->nbufs == 1) + dma_free_coherent(&dev->pdev->dev, size, buf->u.direct.buf, + buf->u.direct.map); + else { + for (i = 0; i < buf->nbufs; ++i) + if (buf->u.page_list[i].buf) + dma_free_coherent(&dev->pdev->dev, PAGE_SIZE, + buf->u.page_list[i].buf, + buf->u.page_list[i].map); + kfree(buf->u.page_list); + } +} +EXPORT_SYMBOL_GPL(mlx4_buf_free); + +static struct mlx4_db_pgdir *mlx4_alloc_db_pgdir(struct mlx4_dev *dev) +{ + struct mlx4_db_pgdir *pgdir; + + pgdir = kzalloc(sizeof *pgdir, GFP_KERNEL); + if (!pgdir) + return NULL; + + bitmap_fill(pgdir->order1, MLX4_DB_PER_PAGE / 2); + pgdir->bits[0] = pgdir->order0; + pgdir->bits[1] = pgdir->order1; + + + pgdir->db_page = dma_alloc_coherent(&dev->pdev->dev, PAGE_SIZE, + &pgdir->db_dma, GFP_KERNEL); + if (!pgdir->db_page) { + kfree(pgdir); + return NULL; + } + + return pgdir; +} + +static int mlx4_alloc_db_from_pgdir(struct mlx4_db_pgdir *pgdir, + struct mlx4_db *db, int order) +{ + int o; + int i; + + for (o = order; o <= 1; ++o) { + i = find_first_bit(pgdir->bits[o], MLX4_DB_PER_PAGE >> o); + if (i < MLX4_DB_PER_PAGE >> o) + goto found; + } + + return -ENOMEM; + +found: + clear_bit(i, pgdir->bits[o]); + + i <<= o; + + if (o > order) + set_bit(i ^ 1, pgdir->bits[order]); + + db->pgdir = pgdir; + db->index = i; + db->db = pgdir->db_page + db->index; + db->dma.da = pgdir->db_dma.da + db->index * 4; + db->dma.va = (VOID *)(UINT_PTR)-1; + db->dma.sz = ULONG_MAX; + db->order = order; + + return 0; +} + +int mlx4_db_alloc(struct mlx4_dev *dev, + struct mlx4_db *db, int order) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_db_pgdir *pgdir; + int ret = 0; + int ret1 = 0; + + mutex_lock(&priv->pgdir_mutex); + + list_for_each_entry(pgdir, &priv->pgdir_list, list, struct mlx4_db_pgdir) + if (!mlx4_alloc_db_from_pgdir(pgdir, db, order)) + goto out; + + pgdir = mlx4_alloc_db_pgdir(dev); + if (!pgdir) { + ret = -ENOMEM; + goto out; + } + + list_add(&pgdir->list, &priv->pgdir_list); + + /* This should never fail -- we just allocated an empty page: */ + ret1 = mlx4_alloc_db_from_pgdir(pgdir, db, order); + ASSERT(ret1 == 0); + +out: + mutex_unlock(&priv->pgdir_mutex); + + return ret; +} + +void mlx4_db_free(struct mlx4_dev *dev, struct mlx4_db *db) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + int o; + int i; + + mutex_lock(&priv->pgdir_mutex); + + o = db->order; + i = db->index; + + if (db->order == 0 && test_bit(i ^ 1, db->pgdir->order0)) { + clear_bit(i ^ 1, db->pgdir->order0); + ++o; + } + + i >>= o; + set_bit(i, db->pgdir->bits[o]); + + if (bitmap_full(db->pgdir->order1, MLX4_DB_PER_PAGE / 2)) { + + dma_free_coherent(&dev->pdev->dev, PAGE_SIZE, + db->pgdir->db_page, db->pgdir->db_dma); + list_del(&db->pgdir->list); + kfree(db->pgdir); + } + + mutex_unlock(&priv->pgdir_mutex); +} + +int mlx4_alloc_hwq_res(struct mlx4_dev *dev, struct mlx4_hwq_resources *wqres, + int size, int max_direct) +{ + int err; + + if ( mlx4_is_barred(dev) ) + return -EFAULT; + + err = mlx4_db_alloc(dev, &wqres->db, 1); + if (err) + return err; + *wqres->db.db = 0; + + if (mlx4_buf_alloc(dev, size, max_direct, &wqres->buf)) { + err = -ENOMEM; + goto err_db; + } + + err = mlx4_mtt_init(dev, wqres->buf.npages, wqres->buf.page_shift, + &wqres->mtt); + if (err) + goto err_buf; + err = mlx4_buf_write_mtt(dev, &wqres->mtt, &wqres->buf); + if (err) + goto err_mtt; + + return 0; + +err_mtt: + mlx4_mtt_cleanup(dev, &wqres->mtt); +err_buf: + mlx4_buf_free(dev, size, &wqres->buf); +err_db: + mlx4_db_free(dev, &wqres->db); + return err; +} +EXPORT_SYMBOL_GPL(mlx4_alloc_hwq_res); + +void mlx4_free_hwq_res(struct mlx4_dev *dev, struct mlx4_hwq_resources *wqres, + int size) +{ + mlx4_mtt_cleanup(dev, &wqres->mtt); + mlx4_buf_free(dev, size, &wqres->buf); + mlx4_db_free(dev, &wqres->db); +} +EXPORT_SYMBOL_GPL(mlx4_free_hwq_res); + diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/net/catas.c b/branches/WOF2-3/hw/mlx4/kernel/bus/net/catas.c new file mode 100644 index 00000000..29b184c2 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/net/catas.c @@ -0,0 +1,405 @@ +/* + * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "mlx4.h" + +enum { + MLX4_CATAS_POLL_INTERVAL = 5 * HZ, +}; + +static DEFINE_SPINLOCK(catas_lock); +static LIST_HEAD(catas_list); + +void mlx4_dispatch_reset_event(struct ib_device *ibdev, enum ib_event_type type) +{ + unsigned long flags; + struct ib_event event; + struct ib_event_handler *handler; + + event.device = ibdev; + event.event = type; + + spin_lock_irqsave(&ibdev->event_handler_lock, &flags); + + list_for_each_entry(handler, &ibdev->event_handler_list, list, struct ib_event_handler) + { + // notify only soft reset handlers + if ( handler->flags & IB_IVH_RESET_CB ) + // notify only those, that are not yet notified + if ( !(handler->flags & IB_IVH_NOTIFIED) ) { + // notify only those that are ready to get the notification + if ( handler->flags & IB_IVH_NOTIF_READY ) { + // insure not to notify once more + handler->flags |= IB_IVH_NOTIFIED; + handler->flags &= ~(IB_IVH_NOTIF_READY | + IB_IVH_RESET_D_PENDING | IB_IVH_RESET_C_PENDING); + handler->handler(handler, &event); + } + else { + // pend the notification + if (type == IB_EVENT_RESET_DRIVER) + handler->flags |= IB_IVH_RESET_D_PENDING; + else + handler->flags |= IB_IVH_RESET_C_PENDING; + } + } + } + + spin_unlock_irqrestore(&ibdev->event_handler_lock, flags); +} + +/** + * get_event_handlers - return list of handlers of the device + * @device:device + * @tlist:list + * + * get_event_handlers() remove all the device event handlers and put them in 'tlist' + */ +static void get_event_handlers(struct ib_device *device, struct list_head *tlist) +{ + unsigned long flags; + struct ib_event_handler *handler, *thandler; + + spin_lock_irqsave(&device->event_handler_lock, &flags); + + list_for_each_entry_safe(handler, thandler, &device->event_handler_list, + list, struct ib_event_handler, struct ib_event_handler) + { + // take out only reset callbacks + if ( handler->flags & IB_IVH_RESET_CB ) { + list_del( &handler->list ); + list_add_tail( &handler->list, tlist ); + } + } + + spin_unlock_irqrestore(&device->event_handler_lock, flags); +} + + +static void dump_err_buf(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + + u32 i; + + mlx4_err(dev, "Internal error detected:\n"); + for (i = 0; i < priv->fw.catas_size; ++i) + mlx4_warn(dev, " buf[%02x]: %08x\n", + i, swab32(readl(priv->catas_err.map + i))); +} + +static void +catas_reset_wi( + IN DEVICE_OBJECT* p_dev_obj, + IN struct mlx4_dev * dev ) +{ + NTSTATUS status; + long do_reset; + UNUSED_PARAM(p_dev_obj); + + dump_err_buf(dev); + + do_reset = InterlockedCompareExchange(&dev->reset_pending, 1, 0); + if (do_reset == 0) { + status = mlx4_reset(dev); + if ( !NT_SUCCESS( status ) ) { + mlx4_err(dev, "Failed to reset HCA, aborting.(status %#x)\n", status); + } + else + mlx4_err(dev, "catas_reset_wi: HCA has been reset.\n"); + + dev->flags |= MLX4_FLAG_RESET_DRIVER; // bar the device + } + + mlx4_dispatch_event(dev, MLX4_EVENT_TYPE_LOCAL_CATAS_ERROR, 0, 0); + if (dev->pdev->ib_dev) + mlx4_dispatch_reset_event(dev->pdev->ib_dev, IB_EVENT_RESET_DRIVER); +} + +/* polling on DISPATCH_LEVEL */ +static void poll_catas(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + + if (readl(priv->catas_err.map)) { + + mlx4_warn(dev, "Detected catastrophic error on mdev %p\n", dev); + IoQueueWorkItem( priv->catas_err.catas_work, catas_reset_wi, DelayedWorkQueue, dev ); + } else { + spin_lock_dpc(&catas_lock); + if (!priv->catas_err.stop) { + KeSetTimerEx( &priv->catas_err.timer, priv->catas_err.interval, + 0, &priv->catas_err.timer_dpc ); + } + spin_unlock_dpc(&catas_lock); + } +} + +static void timer_dpc( + IN struct _KDPC *Dpc, + IN PVOID DeferredContext, + IN PVOID SystemArgument1, + IN PVOID SystemArgument2 + ) +{ + struct mlx4_dev *dev = (struct mlx4_dev *)DeferredContext; + UNREFERENCED_PARAMETER(Dpc); + UNREFERENCED_PARAMETER(SystemArgument1); + UNREFERENCED_PARAMETER(SystemArgument2); + poll_catas( dev ); +} + +int mlx4_start_catas_poll(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + u64 addr; + int err; + + priv->catas_err.map = NULL; + + addr = pci_resource_start(dev->pdev, priv->fw.catas_bar) + + priv->fw.catas_offset; + + priv->catas_err.map = ioremap(addr, priv->fw.catas_size * 4); + if (!priv->catas_err.map) { + mlx4_warn(dev, "Failed to map internal error buffer at 0x%lx\n", + addr); + err = -ENOMEM; + goto err_map; + } + + priv->catas_err.catas_work = IoAllocateWorkItem( dev->pdev->p_self_do ); + if (!priv->catas_err.catas_work) { + mlx4_warn(dev, "Failed to allocate work item from polling thread\n"); + err = -EFAULT; + goto err_alloc; + } + + priv->catas_err.stop = 0; + spin_lock_init( &catas_lock ); + KeInitializeDpc( &priv->catas_err.timer_dpc, timer_dpc, dev ); + KeInitializeTimer( &priv->catas_err.timer ); + priv->catas_err.interval.QuadPart = (-10)* (__int64)MLX4_CATAS_POLL_INTERVAL; + KeSetTimerEx( &priv->catas_err.timer, priv->catas_err.interval, + 0, &priv->catas_err.timer_dpc ); + return 0; + + +err_alloc: + iounmap(priv->catas_err.map, priv->fw.catas_size * 4); +err_map: + return err; +} + +void mlx4_stop_catas_poll(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + + spin_lock_irq(&catas_lock); + if (priv->catas_err.stop) { + spin_unlock_irq(&catas_lock); + return; + } + priv->catas_err.stop = 1; + spin_unlock_irq(&catas_lock); + + KeCancelTimer(&priv->catas_err.timer); + KeFlushQueuedDpcs(); + if (priv->catas_err.map) + iounmap(priv->catas_err.map, priv->fw.catas_size * 4); + + if (priv->catas_err.catas_work) + IoFreeWorkItem( priv->catas_err.catas_work ); +} + +static int wait4reset(struct ib_event_handler *event_handler) +{ + int n_not_ready = 0; + unsigned long flags; + struct ib_event_handler *handler; + struct ib_device *ibdev = event_handler->device; + + spin_lock_irqsave(&ibdev->event_handler_lock, &flags); + + // mark this handler (=client) reset-ready + event_handler->flags |= IB_IVH_RESET_READY; + + // check the number of still not ready client + + list_for_each_entry(handler, &ibdev->event_handler_list, list, struct ib_event_handler) + if ( handler->flags & IB_IVH_RESET_CB ) + if ( !(handler->flags & IB_IVH_RESET_READY) ) + ++n_not_ready; + + spin_unlock_irqrestore(&ibdev->event_handler_lock, flags); + + return n_not_ready; +} + +int mlx4_reset_ready( struct ib_event_handler *event_handler ) +{ + unsigned long flags; + struct ib_device *ibdev = event_handler->device; + + ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); + + spin_lock_irqsave(&ibdev->event_handler_lock, &flags); + event_handler->flags |= IB_IVH_NOTIF_READY; + spin_unlock_irqrestore(&ibdev->event_handler_lock, flags); + if (event_handler->flags & IB_IVH_RESET_D_PENDING) + mlx4_dispatch_reset_event(ibdev, IB_EVENT_RESET_DRIVER); + else + if (event_handler->flags & IB_IVH_RESET_C_PENDING) + mlx4_dispatch_reset_event(ibdev, IB_EVENT_RESET_CLIENT); + return 0; +} + +int mlx4_reset_execute( struct ib_event_handler *event_handler ) +{ + int err; + struct ib_event event; + struct list_head tlist; + struct ib_event_handler *handler, *thandler; + struct ib_device *ibdev = event_handler->device; + struct pci_dev *pdev = ibdev->dma_device->pdev; + + // mark client as "ready for reset" and check whether we can do reset + if (wait4reset(event_handler)) { + return 0; + } + + // fully bar the device + ibdev->dma_device->flags |= MLX4_FLAG_RESET_STARTED; + + // get old handler list + INIT_LIST_HEAD(&tlist); + get_event_handlers(ibdev, &tlist); + + // restart the device + mlx4_info(pdev->dev, "\n Performing HCA restart ... \n\n"); + WriteEventLogEntryData( pdev->p_self_do, (ULONG)EVENT_MLX4_INFO_RESET_START, 0, 0, 0 ); + err = mlx4_restart_one(pdev); + if (err || mlx4_is_livefish(pdev->dev)) { + event.event = IB_EVENT_RESET_FAILED; + mlx4_err(pdev->dev, "\n HCa restart failed. \n\n"); + } + else { + // recreate interfaces + fix_bus_ifc(pdev); + event.event = IB_EVENT_RESET_END; + mlx4_info(pdev->dev, "\n HCA restart finished. Notifying the clients ... \n\n"); + WriteEventLogEntryData( pdev->p_self_do, (ULONG)EVENT_MLX4_INFO_RESET_END, 0, 0, 0 ); + } + + // notify the clients + list_for_each_entry_safe(handler, thandler, &tlist, + list, struct ib_event_handler, struct ib_event_handler) + { + // because 'handler' will be re-registered during the next call + list_del( &handler->list ); + handler->handler(handler, &event); + } + + return err; +} + +static void +card_reset_wi( + IN DEVICE_OBJECT* p_dev_obj, + IN struct ib_event_handler * event_handler ) +{ + struct ib_device *ibdev = event_handler->device; + + UNUSED_PARAM(p_dev_obj); + IoFreeWorkItem( event_handler->rsrv_ptr ); + + // notify the clients + mlx4_dispatch_reset_event(ibdev, IB_EVENT_RESET_CLIENT); +} + +int mlx4_reset_request( struct ib_event_handler *event_handler ) +{ + struct ib_device *ibdev; + struct mlx4_dev *dev; + + unsigned long flags; + + ibdev = event_handler->device; + if (ibdev == NULL) + return -EFAULT; + + dev = ibdev->dma_device; + if (ibdev == NULL) + return -EFAULT; + + spin_lock_irqsave(&ibdev->event_handler_lock, &flags); + + + // set device to RESET_PENDING mode + if (!(dev->flags & (MLX4_FLAG_RESET_CLIENT | MLX4_FLAG_RESET_DRIVER))) { + PIO_WORKITEM reset_work; + + // bar the device + dev->flags |= MLX4_FLAG_RESET_CLIENT; + + // delay reset to a system thread + // to allow for end of operations that are in progress + reset_work = IoAllocateWorkItem( dev->pdev->p_self_do ); + if (!reset_work) { + spin_unlock_irqrestore(&ibdev->event_handler_lock, flags); + mlx4_err(dev, "mlx4_reset_request IoAllocateWorkItem failed, reset will not be propagated\n"); + return -EFAULT; + } + event_handler->rsrv_ptr = reset_work; + IoQueueWorkItem( reset_work, card_reset_wi, DelayedWorkQueue, event_handler ); + } + + spin_unlock_irqrestore(&ibdev->event_handler_lock, flags); + + + return 0; +} + +int mlx4_reset_cb_register( struct ib_event_handler *event_handler ) +{ + if (mlx4_is_in_reset(event_handler->device->dma_device)) + return -EBUSY; + + return ib_register_event_handler(event_handler); +} + +int mlx4_reset_cb_unregister( struct ib_event_handler *event_handler ) +{ + return ib_unregister_event_handler(event_handler); +} + + diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/net/cmd.c b/branches/WOF2-3/hw/mlx4/kernel/bus/net/cmd.c new file mode 100644 index 00000000..fe9b9807 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/net/cmd.c @@ -0,0 +1,618 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include "mlx4.h" +#include "cmd.h" + +#define CMD_POLL_TOKEN 0xffff + +enum { + /* command completed successfully: */ + CMD_STAT_OK = 0x00, + /* Internal error (such as a bus error) occurred while processing command: */ + CMD_STAT_INTERNAL_ERR = 0x01, + /* Operation/command not supported or opcode modifier not supported: */ + CMD_STAT_BAD_OP = 0x02, + /* Parameter not supported or parameter out of range: */ + CMD_STAT_BAD_PARAM = 0x03, + /* System not enabled or bad system state: */ + CMD_STAT_BAD_SYS_STATE = 0x04, + /* Attempt to access reserved or unallocaterd resource: */ + CMD_STAT_BAD_RESOURCE = 0x05, + /* Requested resource is currently executing a command, or is otherwise busy: */ + CMD_STAT_RESOURCE_BUSY = 0x06, + /* Required capability exceeds device limits: */ + CMD_STAT_EXCEED_LIM = 0x08, + /* Resource is not in the appropriate state or ownership: */ + CMD_STAT_BAD_RES_STATE = 0x09, + /* Index out of range: */ + CMD_STAT_BAD_INDEX = 0x0a, + /* FW image corrupted: */ + CMD_STAT_BAD_NVMEM = 0x0b, + /* Attempt to modify a QP/EE which is not in the presumed state: */ + CMD_STAT_BAD_QP_STATE = 0x10, + /* Bad segment parameters (Address/Size): */ + CMD_STAT_BAD_SEG_PARAM = 0x20, + /* Memory Region has Memory Windows bound to: */ + CMD_STAT_REG_BOUND = 0x21, + /* HCA local attached memory not present: */ + CMD_STAT_LAM_NOT_PRE = 0x22, + /* Bad management packet (silently discarded): */ + CMD_STAT_BAD_PKT = 0x30, + /* More outstanding CQEs in CQ than new CQ size: */ + CMD_STAT_BAD_SIZE = 0x40, + /* Multi Function device support required: */ + CMD_STAT_MULTI_FUNC_REQ = 0x50, + /* must be the last and have max value */ + CMD_STAT_SIZE = CMD_STAT_MULTI_FUNC_REQ + 1 +}; + +enum { + HCR_IN_PARAM_OFFSET = 0x00, + HCR_IN_MODIFIER_OFFSET = 0x08, + HCR_OUT_PARAM_OFFSET = 0x0c, + HCR_TOKEN_OFFSET = 0x14, + HCR_STATUS_OFFSET = 0x18, + + HCR_OPMOD_SHIFT = 12, + HCR_T_BIT = 21, + HCR_E_BIT = 22, + HCR_GO_BIT = 23 +}; + +enum { + GO_BIT_TIMEOUT_MSECS = 10000 +}; + +struct mlx4_cmd_context { + struct completion done; + int result; + int next; + u64 out_param; + u16 token; + u8 status; +}; + +static int mlx4_status_to_errno(u8 status) { + static int trans_table[CMD_STAT_SIZE]; + static int filled = 0; + + if ( !filled ) { + memset( (char*)trans_table, 0, sizeof(trans_table) ); + trans_table[CMD_STAT_INTERNAL_ERR] = -EIO; + trans_table[CMD_STAT_BAD_OP] = -EPERM; + trans_table[CMD_STAT_BAD_PARAM] = -EINVAL; + trans_table[CMD_STAT_BAD_SYS_STATE] = -ENXIO; + trans_table[CMD_STAT_BAD_RESOURCE] = -EBADF; + trans_table[CMD_STAT_RESOURCE_BUSY] = -EBUSY; + trans_table[CMD_STAT_EXCEED_LIM] = -ENOMEM; + trans_table[CMD_STAT_BAD_RES_STATE] = -EBADF; + trans_table[CMD_STAT_BAD_INDEX] = -EBADF; + trans_table[CMD_STAT_BAD_NVMEM] = -EFAULT; + trans_table[CMD_STAT_BAD_QP_STATE] = -EINVAL; + trans_table[CMD_STAT_BAD_SEG_PARAM] = -EFAULT; + trans_table[CMD_STAT_REG_BOUND] = -EBUSY; + trans_table[CMD_STAT_LAM_NOT_PRE] = -EAGAIN; + trans_table[CMD_STAT_BAD_PKT] = -EINVAL; + trans_table[CMD_STAT_BAD_SIZE] = -ENOMEM; + trans_table[CMD_STAT_MULTI_FUNC_REQ] = -EACCES; + filled = 1; + } + + if (status >= ARRAY_SIZE(trans_table) || + (status != CMD_STAT_OK && trans_table[status] == 0)) + return -EIO; + + return trans_table[status]; +} + +static int cmd_pending(struct mlx4_dev *dev, u32 *p_status) +{ + *p_status = readl(mlx4_priv(dev)->cmd.hcr + HCR_STATUS_OFFSET); + + return (*p_status & swab32(1 << HCR_GO_BIT)) || + (mlx4_priv(dev)->cmd.toggle == + !!(*p_status & swab32(1 << HCR_T_BIT))); +} + +static int mlx4_cmd_post(struct mlx4_dev *dev, u64 in_param, u64 out_param, + u32 in_modifier, u8 op_modifier, u16 op, u16 token, + int event) +{ + struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd; + u32 __iomem *hcr = (u32 __iomem *)cmd->hcr; + int ret = -EAGAIN; + u64 end; + u32 hcr_status; + + mutex_lock(&cmd->hcr_mutex); + + end = jiffies; + if (event) + end += msecs_to_jiffies(GO_BIT_TIMEOUT_MSECS); + + while (cmd_pending(dev, &hcr_status)) { + if (time_after_eq(jiffies, end)) { + mlx4_err(dev, "Failed to post command %02x during %d msecs, hcr_status %#x, toggle %#x\n", + op, GO_BIT_TIMEOUT_MSECS, hcr_status, mlx4_priv(dev)->cmd.toggle ); + goto out; + } + cond_resched(); + } + + /* + * We use writel (instead of something like memcpy_toio) + * because writes of less than 32 bits to the HCR don't work + * (and some architectures such as ia64 implement memcpy_toio + * in terms of writeb). + */ + __raw_writel((__force u32) cpu_to_be32(in_param >> 32), hcr + 0); + __raw_writel((__force u32) cpu_to_be32(in_param & 0xfffffffful), hcr + 1); + __raw_writel((__force u32) cpu_to_be32(in_modifier), hcr + 2); + __raw_writel((__force u32) cpu_to_be32(out_param >> 32), hcr + 3); + __raw_writel((__force u32) cpu_to_be32(out_param & 0xfffffffful), hcr + 4); + __raw_writel((__force u32) cpu_to_be32(token << 16), hcr + 5); + + /* __raw_writel may not order writes. */ + wmb(); + + __raw_writel((__force u32) cpu_to_be32((1 << HCR_GO_BIT) | + (cmd->toggle << HCR_T_BIT) | + (event ? (1 << HCR_E_BIT) : 0) | + (op_modifier << HCR_OPMOD_SHIFT) | + op), hcr + 6); + + /* + * Make sure that our HCR writes don't get mixed in with + * writes from another CPU starting a FW command. + */ + mmiowb(); + + cmd->toggle = cmd->toggle ^ 1; + + ret = 0; + +out: + mutex_unlock(&cmd->hcr_mutex); + return ret; +} + +static int mlx4_cmd_poll(struct mlx4_dev *dev, u64 in_param, u64 *out_param, + int out_is_imm, u32 in_modifier, u8 op_modifier, + u16 op, unsigned long timeout) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + u8 __iomem *hcr = priv->cmd.hcr; + int err = 0; + u64 end; + u8 status = 0xff; /* means "unknown" */ + long do_reset; + u32 hcr_status; + + down(&priv->cmd.poll_sem); + + err = mlx4_cmd_post(dev, in_param, out_param ? *out_param : 0, + in_modifier, op_modifier, op, CMD_POLL_TOKEN, 0); + if (err) + goto out; + + end = msecs_to_jiffies(timeout) + jiffies; + while (cmd_pending(dev, &hcr_status) && time_before(jiffies, end)) + cond_resched(); + + if (cmd_pending(dev, &hcr_status)) { + err = -ETIMEDOUT; + mlx4_err(dev, "mlx4_cmd_poll: Command %02x: timeout after %d msecs, hcr_status %#x, toggle %#x \n", + op, timeout, hcr_status, mlx4_priv(dev)->cmd.toggle); + + do_reset = InterlockedCompareExchange(&dev->reset_pending, 1, 0); + if (!do_reset) { + NTSTATUS status1 = mlx4_reset(dev); + if ( !NT_SUCCESS( status1 ) ) { + mlx4_err(dev, "mlx4_cmd_poll: Failed to reset HCA, aborting.(status %#x)\n", status1); + } + else + mlx4_err(dev, "mlx4_cmd_poll: HCA has been reset.\n"); + + dev->flags |= MLX4_FLAG_RESET_DRIVER; // bar the device + } + + if (dev->pdev->ib_dev) + mlx4_dispatch_reset_event(dev->pdev->ib_dev, IB_EVENT_RESET_DRIVER); + + goto out; + } + + if (out_is_imm) + *out_param = + (u64) be32_to_cpu((__force __be32) + __raw_readl(hcr + HCR_OUT_PARAM_OFFSET)) << 32 | + (u64) be32_to_cpu((__force __be32) + __raw_readl(hcr + HCR_OUT_PARAM_OFFSET + 4)); + + status = (u8)(be32_to_cpu((__force __be32)__raw_readl(hcr + HCR_STATUS_OFFSET)) >> 24); + err = mlx4_status_to_errno(status); + +out: + if (status && status != 0x50) { + mlx4_err(dev, "mlx4_cmd_poll: Command failed: op %#hx, status %#02x, errno %d.\n", + op, status, err); + } + up(&priv->cmd.poll_sem); + return err; +} + +void mlx4_cmd_event(struct mlx4_dev *dev, u16 token, u8 status, u64 out_param) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_cmd_context *context = + &priv->cmd.context[token & priv->cmd.token_mask]; + + /* previously timed out command completing at long last */ + if (token != context->token) { + mlx4_err(dev, "mlx4_cmd_event: Command skipped: token %#hx, ctx_token %#hx\n", + token, context->token); + return; + } + + context->result = mlx4_status_to_errno(status); + context->status = status; + context->out_param = out_param; + + complete(&context->done); +} + +static int mlx4_cmd_wait(struct mlx4_dev *dev, u64 in_param, u64 *out_param, + int out_is_imm, u32 in_modifier, u8 op_modifier, + u16 op, unsigned long timeout) +{ + struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd; + struct mlx4_cmd_context *context; + int err = 0; + u64 out_prm = out_param ? *out_param : 0; + long do_reset; + u8 status = 0xff; /* means "unknown" */ + + down(&cmd->event_sem); + if ( dev->flags & MLX4_FLAG_RESET_DRIVER ) { + err = -EBUSY; + mlx4_warn(dev, "mlx4_cmd_wait: Command %02x is skipped because the card is stuck \n", op); + goto exit; + } + spin_lock(&cmd->context_lock); + BUG_ON(cmd->free_head < 0); + context = &cmd->context[cmd->free_head]; + context->token += cmd->token_mask + 1; + cmd->free_head = context->next; + spin_unlock(&cmd->context_lock); + + init_completion(&context->done); + + err = mlx4_cmd_post(dev, in_param, out_prm, + in_modifier, op_modifier, op, context->token, 1); + if (err) + goto out; + + if (wait_for_completion_timeout(&context->done, msecs_to_jiffies(timeout))) { + if (!context->done.done) { + + /* report failure */ + err = -EBUSY; + mlx4_err(dev, "mlx4_cmd_wait: Command %02x completed with timeout after %d msecs \n", + op, timeout); + + /* for enabling busy-wait loop, add MLX4_FLAG_BUSY_WAIT (0x8000) to dev->flags */ + while (dev) { + u32 wait_ms =2000; /* wait interval in msecs */ + if (!(dev->flags & MLX4_FLAG_BUSY_WAIT)) + break; + cl_thread_suspend( wait_ms ); + } + do_reset = InterlockedCompareExchange(&dev->reset_pending, 1, 0); + if (!do_reset) { + NTSTATUS status = mlx4_reset(dev); + if ( !NT_SUCCESS( status ) ) { + mlx4_err(dev, "mlx4_cmd_wait: Failed to reset HCA, aborting.(status %#x)\n", status); + } + else + mlx4_err(dev, "mlx4_cmd_wait: HCA has been reset.\n"); + + dev->flags |= MLX4_FLAG_RESET_DRIVER; // bar the device + } + + /* try to solve the problem */ + if (dev->pdev->ib_dev) + mlx4_dispatch_reset_event(dev->pdev->ib_dev, IB_EVENT_RESET_DRIVER); + } + else { + err = -EFAULT; + mlx4_err(dev, "mlx4_cmd_wait: Unexpected end of waiting for a command \n"); + } + } + else { + err = context->result; + status = context->status; + } + + if (err) + goto out; + + if (out_is_imm) + *out_param = context->out_param; + +out: + spin_lock(&cmd->context_lock); + context->next = cmd->free_head; + cmd->free_head = (int)(context - cmd->context); + spin_unlock(&cmd->context_lock); + if (status && status != 0x50) { + mlx4_err(dev, "mlx4_cmd_wait: Command failed: op %#hx, status %#02x, errno %d, token %#hx.\n", + op, status, err, context->token); + } + +exit: + up(&cmd->event_sem); + return err; +} + +static char *__print_opcode(int opcode) +{ + char *str = NULL; + switch (opcode) { + case MLX4_CMD_SYS_EN : str = "MLX4_CMD_SYS_EN "; break; + case MLX4_CMD_SYS_DIS: str = "MLX4_CMD_SYS_DIS"; break; + case MLX4_CMD_MAP_FA : str = "MLX4_CMD_MAP_FA "; break; + case MLX4_CMD_UNMAP_FA: str = "MLX4_CMD_UNMAP_FA"; break; + case MLX4_CMD_RUN_FW : str = "MLX4_CMD_RUN_FW "; break; + case MLX4_CMD_MOD_STAT_CFG: str = "MLX4_CMD_MOD_STAT_CFG"; break; + case MLX4_CMD_QUERY_DEV_CAP: str = "MLX4_CMD_QUERY_DEV_CAP"; break; + case MLX4_CMD_QUERY_FW: str = "MLX4_CMD_QUERY_FW"; break; + case MLX4_CMD_ENABLE_LAM: str = "MLX4_CMD_ENABLE_LAM"; break; + case MLX4_CMD_DISABLE_LAM: str = "MLX4_CMD_DISABLE_LAM"; break; + case MLX4_CMD_QUERY_DDR: str = "MLX4_CMD_QUERY_DDR"; break; + case MLX4_CMD_QUERY_ADAPTER: str = "MLX4_CMD_QUERY_ADAPTER"; break; + case MLX4_CMD_INIT_HCA: str = "MLX4_CMD_INIT_HCA"; break; + case MLX4_CMD_CLOSE_HCA: str = "MLX4_CMD_CLOSE_HCA"; break; + case MLX4_CMD_INIT_PORT: str = "MLX4_CMD_INIT_PORT"; break; + case MLX4_CMD_CLOSE_PORT: str = "MLX4_CMD_CLOSE_PORT"; break; + case MLX4_CMD_QUERY_HCA: str = "MLX4_CMD_QUERY_HCA"; break; + case MLX4_CMD_QUERY_PORT: str = "MLX4_CMD_QUERY_PORT"; break; + case MLX4_CMD_SET_PORT: str = "MLX4_CMD_SET_PORT"; break; + case MLX4_CMD_ACCESS_DDR: str = "MLX4_CMD_ACCESS_DDR"; break; + case MLX4_CMD_MAP_ICM: str = "MLX4_CMD_MAP_ICM"; break; + case MLX4_CMD_UNMAP_ICM: str = "MLX4_CMD_UNMAP_ICM"; break; + case MLX4_CMD_MAP_ICM_AUX: str = "MLX4_CMD_MAP_ICM_AUX"; break; + case MLX4_CMD_UNMAP_ICM_AUX: str = "MLX4_CMD_UNMAP_ICM_AUX"; break; + case MLX4_CMD_SET_ICM_SIZE: str = "MLX4_CMD_SET_ICM_SIZE"; break; + case MLX4_CMD_SW2HW_MPT: str = "MLX4_CMD_SW2HW_MPT"; break; + case MLX4_CMD_QUERY_MPT: str = "MLX4_CMD_QUERY_MPT"; break; + case MLX4_CMD_HW2SW_MPT: str = "MLX4_CMD_HW2SW_MPT"; break; + case MLX4_CMD_READ_MTT: str = "MLX4_CMD_READ_MTT"; break; + case MLX4_CMD_WRITE_MTT: str = "MLX4_CMD_WRITE_MTT"; break; + case MLX4_CMD_SYNC_TPT: str = "MLX4_CMD_SYNC_TPT"; break; + case MLX4_CMD_MAP_EQ : str = "MLX4_CMD_MAP_EQ "; break; + case MLX4_CMD_SW2HW_EQ: str = "MLX4_CMD_SW2HW_EQ"; break; + case MLX4_CMD_HW2SW_EQ: str = "MLX4_CMD_HW2SW_EQ"; break; + case MLX4_CMD_QUERY_EQ: str = "MLX4_CMD_QUERY_EQ"; break; + case MLX4_CMD_SW2HW_CQ: str = "MLX4_CMD_SW2HW_CQ"; break; + case MLX4_CMD_HW2SW_CQ: str = "MLX4_CMD_HW2SW_CQ"; break; + case MLX4_CMD_QUERY_CQ: str = "MLX4_CMD_QUERY_CQ"; break; + case MLX4_CMD_MODIFY_CQ: str = "MLX4_CMD_MODIFY_CQ"; break; + case MLX4_CMD_SW2HW_SRQ: str = "MLX4_CMD_SW2HW_SRQ"; break; + case MLX4_CMD_HW2SW_SRQ: str = "MLX4_CMD_HW2SW_SRQ"; break; + case MLX4_CMD_QUERY_SRQ: str = "MLX4_CMD_QUERY_SRQ"; break; + case MLX4_CMD_ARM_SRQ: str = "MLX4_CMD_ARM_SRQ"; break; + case MLX4_CMD_RST2INIT_QP: str = "MLX4_CMD_RST2INIT_QP"; break; + case MLX4_CMD_INIT2RTR_QP: str = "MLX4_CMD_INIT2RTR_QP"; break; + case MLX4_CMD_RTR2RTS_QP: str = "MLX4_CMD_RTR2RTS_QP"; break; + case MLX4_CMD_RTS2RTS_QP: str = "MLX4_CMD_RTS2RTS_QP"; break; + case MLX4_CMD_SQERR2RTS_QP: str = "MLX4_CMD_SQERR2RTS_QP"; break; + case MLX4_CMD_2ERR_QP: str = "MLX4_CMD_2ERR_QP"; break; + case MLX4_CMD_RTS2SQD_QP: str = "MLX4_CMD_RTS2SQD_QP"; break; + case MLX4_CMD_SQD2SQD_QP: str = "MLX4_CMD_SQD2SQD_QP"; break; + case MLX4_CMD_SQD2RTS_QP: str = "MLX4_CMD_SQD2RTS_QP"; break; + case MLX4_CMD_2RST_QP: str = "MLX4_CMD_2RST_QP"; break; + case MLX4_CMD_QUERY_QP: str = "MLX4_CMD_QUERY_QP"; break; + case MLX4_CMD_INIT2INIT_QP: str = "MLX4_CMD_INIT2INIT_QP"; break; + case MLX4_CMD_SUSPEND_QP: str = "MLX4_CMD_SUSPEND_QP"; break; + case MLX4_CMD_UNSUSPEND_QP: str = "MLX4_CMD_UNSUSPEND_QP"; break; + case MLX4_CMD_CONF_SPECIAL_QP: str = "MLX4_CMD_CONF_SPECIAL_QP"; break; + case MLX4_CMD_MAD_IFC: str = "MLX4_CMD_MAD_IFC"; break; + case MLX4_CMD_READ_MCG: str = "MLX4_CMD_READ_MCG"; break; + case MLX4_CMD_WRITE_MCG: str = "MLX4_CMD_WRITE_MCG"; break; + case MLX4_CMD_MGID_HASH: str = "MLX4_CMD_MGID_HASH"; break; + case MLX4_CMD_DIAG_RPRT: str = "MLX4_CMD_DIAG_RPRT"; break; + case MLX4_CMD_NOP : str = "MLX4_CMD_NOP "; break; + case MLX4_CMD_QUERY_DEBUG_MSG: str = "MLX4_CMD_QUERY_DEBUG_MSG"; break; + case MLX4_CMD_SET_DEBUG_MSG: str = "MLX4_CMD_SET_DEBUG_MSG"; break; + } + return str; +} + +int __mlx4_cmd(struct mlx4_dev *dev, u64 in_param, u64 *out_param, + int out_is_imm, u32 in_modifier, u8 op_modifier, + u16 op, unsigned long timeout) +{ +#if 0 + mlx4_err(dev, "op %s, ev %d, in_param %#I64x, in_param %#I64x, out_is_imm %d, in_modifier %#x, op_modifier %d\n", + __print_opcode(op), mlx4_priv(dev)->cmd.use_events, in_param, out_param, + out_is_imm, in_modifier, (int)op_modifier); +#endif + + if ( mlx4_is_barred(dev) ) + return -EFAULT; + + if (mlx4_priv(dev)->cmd.use_events) + return mlx4_cmd_wait(dev, in_param, out_param, out_is_imm, + in_modifier, op_modifier, op, timeout); + else + return mlx4_cmd_poll(dev, in_param, out_param, out_is_imm, + in_modifier, op_modifier, op, timeout); +} +EXPORT_SYMBOL_GPL(__mlx4_cmd); + +int mlx4_cmd_init(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + + mutex_init(&priv->cmd.hcr_mutex); + sema_init(&priv->cmd.poll_sem, 1); + priv->cmd.use_events = 0; + priv->cmd.toggle = 1; + + priv->cmd.hcr = ioremap(pci_resource_start(dev->pdev, 0) + MLX4_HCR_BASE, + MLX4_HCR_SIZE); + if (!priv->cmd.hcr) { + mlx4_err(dev, "Couldn't map command register."); + return -ENOMEM; + } + + priv->cmd.pool = pci_pool_create("mlx4_cmd", dev->pdev, + MLX4_MAILBOX_SIZE, + MLX4_MAILBOX_SIZE, 0); + if (!priv->cmd.pool) { + iounmap(priv->cmd.hcr, MLX4_HCR_SIZE); + return -ENOMEM; + } + + return 0; +} + +void mlx4_cmd_cleanup(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + + pci_pool_destroy(priv->cmd.pool); + iounmap(priv->cmd.hcr, MLX4_HCR_SIZE); +} + +/* + * Switch to using events to issue FW commands (can only be called + * after event queue for command events has been initialized). + */ +int mlx4_cmd_use_events(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + int i; + + priv->cmd.context = kmalloc(priv->cmd.max_cmds * + sizeof (struct mlx4_cmd_context), + GFP_KERNEL); + if (!priv->cmd.context) + return -ENOMEM; + + for (i = 0; i < priv->cmd.max_cmds; ++i) { + priv->cmd.context[i].token = (u16)i; + priv->cmd.context[i].next = i + 1; + } + + priv->cmd.context[priv->cmd.max_cmds - 1].next = -1; + priv->cmd.free_head = 0; + + sema_init(&priv->cmd.event_sem, priv->cmd.max_cmds); + spin_lock_init(&priv->cmd.context_lock); + + for (priv->cmd.token_mask = 1; + priv->cmd.token_mask < priv->cmd.max_cmds; + priv->cmd.token_mask <<= 1) + ; /* nothing */ + --priv->cmd.token_mask; + + priv->cmd.use_events = 1; + + down(&priv->cmd.poll_sem); + + return 0; +} + +/* + * Switch back to polling (used when shutting down the device) + */ +void mlx4_cmd_use_polling(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + int i; + + priv->cmd.use_events = 0; + + for (i = 0; i < priv->cmd.max_cmds; ++i) + down(&priv->cmd.event_sem); + + kfree(priv->cmd.context); + + up(&priv->cmd.poll_sem); +} + +struct mlx4_cmd_mailbox *mlx4_alloc_cmd_mailbox(struct mlx4_dev *dev) +{ + struct mlx4_cmd_mailbox *mailbox; + + if ( mlx4_is_barred(dev) ) + return ERR_PTR(-EFAULT); + + mailbox = kmalloc(sizeof *mailbox, GFP_KERNEL); + if (!mailbox) + return ERR_PTR(-ENOMEM); + + mailbox->buf = pci_pool_alloc(mlx4_priv(dev)->cmd.pool, GFP_KERNEL, + &mailbox->dma); + if (!mailbox->buf) { + kfree(mailbox); + return ERR_PTR(-ENOMEM); + } + + return mailbox; +} +EXPORT_SYMBOL_GPL(mlx4_alloc_cmd_mailbox); + +void mlx4_free_cmd_mailbox(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox) +{ + if (!mailbox) + return; + + pci_pool_free(mlx4_priv(dev)->cmd.pool, mailbox->buf, mailbox->dma); + kfree(mailbox); +} +EXPORT_SYMBOL_GPL(mlx4_free_cmd_mailbox); + +// This is the interface version of this function +int imlx4_cmd(struct mlx4_dev *dev, u64 in_param, u64 *out_param, int out_is_imm, + u32 in_modifier, u8 op_modifier, u16 op, unsigned long timeout) +{ + return __mlx4_cmd(dev, in_param, out_param, out_is_imm, in_modifier, + op_modifier, op, timeout); +} + + diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/net/cq.c b/branches/WOF2-3/hw/mlx4/kernel/bus/net/cq.c new file mode 100644 index 00000000..9bec57d8 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/net/cq.c @@ -0,0 +1,289 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * Copyright (c) 2004 Voltaire, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "mlx4.h" +#include "cmd.h" +#include "icm.h" +#include "cq.h" +#include + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "cq.tmh" +#endif + + +#define MLX4_CQ_STATUS_OK ( 0 << 28) +#define MLX4_CQ_STATUS_OVERFLOW ( 9 << 28) +#define MLX4_CQ_STATUS_WRITE_FAIL (10 << 28) +#define MLX4_CQ_FLAG_CC ( 1 << 18) +#define MLX4_CQ_FLAG_OI ( 1 << 17) +#define MLX4_CQ_STATE_ARMED ( 9 << 8) +#define MLX4_CQ_STATE_ARMED_SOL ( 6 << 8) +#define MLX4_EQ_STATE_FIRED (10 << 8) + +void mlx4_cq_completion(struct mlx4_dev *dev, u32 cqn) +{ + struct mlx4_cq *cq; + struct mlx4_cq_table *cq_table = &mlx4_priv(dev)->cq_table; + + spin_lock_dpc(&cq_table->lock); + cq = radix_tree_lookup(&cq_table->tree, cqn & (dev->caps.num_cqs - 1)); + spin_unlock_dpc(&cq_table->lock); + + if (!cq) { + mlx4_warn(dev, "Completion event for bogus CQ %08x\n", cqn); + return; + } + + if (cq->p_u_arm_sn) + ++*cq->p_u_arm_sn; + else + ++cq->arm_sn; + + cq->comp(cq); +} + +void mlx4_cq_event(struct mlx4_dev *dev, u32 cqn, int event_type) +{ + struct mlx4_cq_table *cq_table = &mlx4_priv(dev)->cq_table; + struct mlx4_cq *cq; + + spin_lock_dpc(&cq_table->lock); + + cq = radix_tree_lookup(&cq_table->tree, cqn & (dev->caps.num_cqs - 1)); + if (cq) + atomic_inc(&cq->refcount); + + spin_unlock_dpc(&cq_table->lock); + + if (!cq) { + mlx4_warn(dev, "Async event for bogus CQ %08x\n", cqn); + return; + } + + cq->event(cq, event_type); + + if (atomic_dec_and_test(&cq->refcount)) + complete(&cq->free); +} + +static int mlx4_SW2HW_CQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, + int cq_num) +{ + return mlx4_cmd(dev, mailbox->dma.da, cq_num, 0, MLX4_CMD_SW2HW_CQ, + MLX4_CMD_TIME_CLASS_A); +} + +static int mlx4_MODIFY_CQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, + int cq_num, u32 opmod) +{ + return mlx4_cmd(dev, mailbox->dma.da, cq_num, (u8)opmod, MLX4_CMD_MODIFY_CQ, + MLX4_CMD_TIME_CLASS_A); +} + +static int mlx4_HW2SW_CQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, + int cq_num) +{ + return mlx4_cmd_box(dev, 0, mailbox ? mailbox->dma.da : 0, cq_num, + mailbox ? 0 : 1, MLX4_CMD_HW2SW_CQ, + MLX4_CMD_TIME_CLASS_A); +} + +int mlx4_cq_alloc(struct mlx4_dev *dev, int nent, struct mlx4_mtt *mtt, + struct mlx4_uar *uar, u64 db_rec, struct mlx4_cq *cq, + unsigned vector, int collapsed) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_cq_table *cq_table = &priv->cq_table; + struct mlx4_cmd_mailbox *mailbox; + struct mlx4_cq_context *cq_context; + u64 mtt_addr; + int err; + +#define COLLAPSED_SHIFT 18 +#define ENTRIES_SHIFT 24 + + if ( mlx4_is_barred(dev) ) + return -EFAULT; + + cq->cqn = mlx4_bitmap_alloc(&cq_table->bitmap); + if (cq->cqn == -1) + return -ENOMEM; + + err = mlx4_table_get(dev, &cq_table->table, cq->cqn); + if (err) + goto err_out; + + err = mlx4_table_get(dev, &cq_table->cmpt_table, cq->cqn); + if (err) + goto err_put; + + spin_lock_irq(&cq_table->lock); + err = radix_tree_insert(&cq_table->tree, cq->cqn, cq); + spin_unlock_irq(&cq_table->lock); + if (err) + goto err_cmpt_put; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) { + err = PTR_ERR(mailbox); + goto err_radix; + } + + cq_context = (struct mlx4_cq_context *)mailbox->buf; + memset(cq_context, 0, sizeof *cq_context); + + cq_context->flags = cpu_to_be32(!!collapsed << COLLAPSED_SHIFT); + cq_context->logsize_usrpage = cpu_to_be32( + (ilog2(nent) << ENTRIES_SHIFT) | uar->index); + if (vector == 0) { + cq_context->comp_eqn = (u8)priv->eq_table.eq[MLX4_EQ_COMP].eqn; + } else { + cq_context->comp_eqn = (u8)priv->eq_table.eq[vector].eqn; + } + cq_context->log_page_size = (u8)(mtt->page_shift - MLX4_ICM_PAGE_SHIFT); + + mtt_addr = mlx4_mtt_addr(dev, mtt); + cq_context->mtt_base_addr_h = (u8)(mtt_addr >> 32); + cq_context->mtt_base_addr_l = cpu_to_be32(mtt_addr & 0xffffffff); + cq_context->db_rec_addr = cpu_to_be64(db_rec); + MLX4_PRINT( TRACE_LEVEL_INFORMATION, MLX4_DBG_CQ, + ("CQ: cqn %#x, nent %#x, mtt_base %#I64x, db_rec %#I64x, page_shift %d, log_page_size %#hx, uar_index %#x \n", + cq->cqn, nent, mtt_addr, db_rec, mtt->page_shift, (u16)cq_context->log_page_size, uar->index )); + + err = mlx4_SW2HW_CQ(dev, mailbox, cq->cqn); + mlx4_free_cmd_mailbox(dev, mailbox); + if (err) + goto err_radix; + + cq->cons_index = 0; + cq->arm_sn = 1; + cq->uar = uar; + atomic_set(&cq->refcount, 1); + init_completion(&cq->free); + + return 0; + +err_radix: + spin_lock_irq(&cq_table->lock); + radix_tree_delete(&cq_table->tree, cq->cqn); + spin_unlock_irq(&cq_table->lock); + +err_cmpt_put: + mlx4_table_put(dev, &cq_table->cmpt_table, cq->cqn); + +err_put: + mlx4_table_put(dev, &cq_table->table, cq->cqn); + +err_out: + mlx4_bitmap_free(&cq_table->bitmap, cq->cqn); + + return err; +} +EXPORT_SYMBOL_GPL(mlx4_cq_alloc); + +int mlx4_cq_modify(struct mlx4_dev *dev, struct mlx4_cq *cq, + struct mlx4_cq_context *context, int modify) +{ + struct mlx4_cmd_mailbox *mailbox; + int err; + + if ( mlx4_is_barred(dev) ) + return -EFAULT; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + + memcpy(mailbox->buf, context, sizeof *context); + err = mlx4_MODIFY_CQ(dev, mailbox, cq->cqn, modify); + + mlx4_free_cmd_mailbox(dev, mailbox); + return err; +} +EXPORT_SYMBOL_GPL(mlx4_cq_modify); + +void mlx4_cq_free(struct mlx4_dev *dev, struct mlx4_cq *cq) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_cq_table *cq_table = &priv->cq_table; + int err = 0; + + if (!mlx4_is_barred(dev)) + err = mlx4_HW2SW_CQ(dev, NULL, cq->cqn); + if (err) + mlx4_warn(dev, "HW2SW_CQ failed (%d) for CQN %06x\n", err, cq->cqn); + + synchronize_irq(priv->eq_table.eq[MLX4_EQ_COMP].irq); + + spin_lock_irq(&cq_table->lock); + radix_tree_delete(&cq_table->tree, cq->cqn); + spin_unlock_irq(&cq_table->lock); + + if (atomic_dec_and_test(&cq->refcount)) + complete(&cq->free); + wait_for_completion(&cq->free); + + mlx4_table_put(dev, &cq_table->table, cq->cqn); + mlx4_bitmap_free(&cq_table->bitmap, cq->cqn); +} +EXPORT_SYMBOL_GPL(mlx4_cq_free); + +int mlx4_init_cq_table(struct mlx4_dev *dev) +{ + struct mlx4_cq_table *cq_table = &mlx4_priv(dev)->cq_table; + int err; + + spin_lock_init(&cq_table->lock); + INIT_RADIX_TREE(&cq_table->tree, GFP_ATOMIC); + + err = mlx4_bitmap_init(&cq_table->bitmap, dev->caps.num_cqs, + dev->caps.num_cqs - 1, dev->caps.reserved_cqs); + if (err) + return err; + + return 0; +} + +void mlx4_cleanup_cq_table(struct mlx4_dev *dev) +{ + /* Nothing to do to clean up radix_tree */ + mlx4_bitmap_cleanup(&mlx4_priv(dev)->cq_table.bitmap); + radix_tree_destroy(&mlx4_priv(dev)->cq_table.tree); +} diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/net/eq.c b/branches/WOF2-3/hw/mlx4/kernel/bus/net/eq.c new file mode 100644 index 00000000..89471121 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/net/eq.c @@ -0,0 +1,935 @@ +/* + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "mlx4.h" +#include "cmd.h" +#include "fw.h" +#include "eq.h" + +/* + * Must be packed because start is 64 bits but only aligned to 32 bits. + */ +struct mlx4_eq_context { + __be32 flags; + u16 reserved1[3]; + __be16 page_offset; + u8 log_eq_size; + u8 reserved2[4]; + u8 eq_period; + u8 reserved3; + u8 eq_max_count; + u8 reserved4[3]; + u8 intr; + u8 log_page_size; + u8 reserved5[2]; + u8 mtt_base_addr_h; + __be32 mtt_base_addr_l; + u32 reserved6[2]; + __be32 consumer_index; + __be32 producer_index; + u32 reserved7[4]; +}; + +#define MLX4_EQ_STATUS_OK ( 0 << 28) +#define MLX4_EQ_STATUS_WRITE_FAIL (10 << 28) +#define MLX4_EQ_OWNER_SW ( 0 << 24) +#define MLX4_EQ_OWNER_HW ( 1 << 24) +#define MLX4_EQ_FLAG_EC ( 1 << 18) +#define MLX4_EQ_FLAG_OI ( 1 << 17) +#define MLX4_EQ_STATE_ARMED ( 9 << 8) +#define MLX4_EQ_STATE_FIRED (10 << 8) +#define MLX4_EQ_STATE_ALWAYS_ARMED (11 << 8) + +#define MLX4_ASYNC_EVENT_MASK ((1ull << MLX4_EVENT_TYPE_PATH_MIG) | \ + (1ull << MLX4_EVENT_TYPE_COMM_EST) | \ + (1ull << MLX4_EVENT_TYPE_SQ_DRAINED) | \ + (1ull << MLX4_EVENT_TYPE_CQ_ERROR) | \ + (1ull << MLX4_EVENT_TYPE_WQ_CATAS_ERROR) | \ + (1ull << MLX4_EVENT_TYPE_EEC_CATAS_ERROR) | \ + (1ull << MLX4_EVENT_TYPE_PATH_MIG_FAILED) | \ + (1ull << MLX4_EVENT_TYPE_WQ_INVAL_REQ_ERROR) | \ + (1ull << MLX4_EVENT_TYPE_WQ_ACCESS_ERROR) | \ + (1ull << MLX4_EVENT_TYPE_PORT_CHANGE) | \ + (1ull << MLX4_EVENT_TYPE_ECC_DETECT) | \ + (1ull << MLX4_EVENT_TYPE_SRQ_CATAS_ERROR) | \ + (1ull << MLX4_EVENT_TYPE_SRQ_QP_LAST_WQE) | \ + (1ull << MLX4_EVENT_TYPE_SRQ_LIMIT) | \ + (1ull << MLX4_EVENT_TYPE_CMD)) + +#pragma warning( disable : 4706) +static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq) +{ + struct mlx4_eqe *eqe; + int cqn; + int eqes_found = 0; + int set_ci = 0; + static const uint32_t cDpcMaxTime = 10000; //max time to spend in a while loop + + uint64_t start = cl_get_time_stamp(); + + while ((eqe = next_eqe_sw(eq))) { + /* + * Make sure we read EQ entry contents after we've + * checked the ownership bit. + */ + rmb(); + + switch (eqe->type) { + case MLX4_EVENT_TYPE_COMP: + cqn = be32_to_cpu(eqe->event.comp.cqn) & 0xffffff; + mlx4_cq_completion(dev, cqn); + break; + + case MLX4_EVENT_TYPE_PATH_MIG: + case MLX4_EVENT_TYPE_COMM_EST: + case MLX4_EVENT_TYPE_SQ_DRAINED: + case MLX4_EVENT_TYPE_SRQ_QP_LAST_WQE: + case MLX4_EVENT_TYPE_WQ_CATAS_ERROR: + case MLX4_EVENT_TYPE_PATH_MIG_FAILED: + case MLX4_EVENT_TYPE_WQ_INVAL_REQ_ERROR: + case MLX4_EVENT_TYPE_WQ_ACCESS_ERROR: + mlx4_qp_event(dev, be32_to_cpu(eqe->event.qp.qpn) & 0xffffff, + eqe->type); + break; + + case MLX4_EVENT_TYPE_SRQ_LIMIT: + case MLX4_EVENT_TYPE_SRQ_CATAS_ERROR: + mlx4_srq_event(dev, be32_to_cpu(eqe->event.srq.srqn) & 0xffffff, + eqe->type); + break; + + case MLX4_EVENT_TYPE_CMD: + mlx4_cmd_event(dev, + be16_to_cpu(eqe->event.cmd.token), + eqe->event.cmd.status, + be64_to_cpu(eqe->event.cmd.out_param)); + break; + + case MLX4_EVENT_TYPE_PORT_CHANGE: + mlx4_dispatch_event(dev, eqe->type, eqe->subtype, + be32_to_cpu(eqe->event.port_change.port) >> 28); + break; + + case MLX4_EVENT_TYPE_CQ_ERROR: + mlx4_warn(dev, "CQ %s on CQN %06x\n", + eqe->event.cq_err.syndrome == 1 ? + "overrun" : "access violation", + be32_to_cpu(eqe->event.cq_err.cqn) & 0xffffff); + mlx4_cq_event(dev, be32_to_cpu(eqe->event.cq_err.cqn), + eqe->type); + break; + + case MLX4_EVENT_TYPE_EQ_OVERFLOW: + mlx4_warn(dev, "EQ overrun on EQN %d\n", eq->eqn); + break; + + case MLX4_EVENT_TYPE_EEC_CATAS_ERROR: + case MLX4_EVENT_TYPE_ECC_DETECT: + default: + mlx4_warn(dev, "Unhandled event %02x(%02x) on EQ %d at index %u\n", + eqe->type, eqe->subtype, eq->eqn, eq->cons_index); + + break; + }; + + ++eq->cons_index; + eqes_found = 1; + ++set_ci; + + /* + * The HCA will think the queue has overflowed if we + * don't tell it we've been processing events. We + * create our EQs with MLX4_NUM_SPARE_EQE extra + * entries, so we must update our consumer index at + * least that often. + */ + if (unlikely(set_ci >= MLX4_NUM_SPARE_EQE)) { + /* + * Conditional on hca_type is OK here because + * this is a rare case, not the fast path. + */ + eq_set_ci(eq, 0); + set_ci = 0; + } + + if (cl_get_time_stamp() - start > cDpcMaxTime ) { + break; //allow other DPCs as well + } + } + + eq_set_ci(eq, 1); + + return eqes_found; +} +#pragma warning(disable:4706) + +static void mlx4_dpc( PRKDPC dpc, + PVOID ctx, PVOID arg1, PVOID arg2 ) +{ + struct mlx4_eq *eq = ctx; + + UNREFERENCED_PARAMETER(dpc); + UNREFERENCED_PARAMETER(arg1); + UNREFERENCED_PARAMETER(arg2); + + spin_lock_dpc(&eq->lock); + mlx4_eq_int(eq->dev, eq); + spin_unlock_dpc(&eq->lock); +} + +static BOOLEAN legacy_isr(struct mlx4_dev *dev) +{ + int i; + int work = 0; + struct mlx4_priv *priv = mlx4_priv(dev); + + for (i = 0; i < MLX4_NUM_EQ; ++i) { + if ( next_eqe_sw(&priv->eq_table.eq[i]) ) { + work = 1; + /* another interrupt may happen instantly after writel above. + If it comes to another processor, mlx4_interrupt will be called + and try to schedule the same DPC. So we protect KeInsertQueueDpc + from that race */ + + while(InterlockedCompareExchange(&dev->pdev->dpc_lock, 1, 0)); + + KeInsertQueueDpc(&priv->eq_table.eq[i].dpc, NULL, NULL); + InterlockedCompareExchange(&dev->pdev->dpc_lock, 0, 1); + } else { + /* re-arm the EQ for a case when interrupt comes before EQE + and we didn't scheduled the DPC */ + eq_set_ci(&priv->eq_table.eq[i], 1); + } + } + + for (i = MLX4_NUM_EQ; i <= priv->eq_table.max_extra_eqs; ++i) { + if (priv->eq_table.eq[i].isr) { + int ret = 0; + if ( next_eqe_sw(&priv->eq_table.eq[i]) ) { + ret = priv->eq_table.eq[i].isr(priv->eq_table.eq[i].ctx); + work |= ret; + } else { + eq_set_ci(&priv->eq_table.eq[i], 1); + } + } + } + + return (BOOLEAN)work; +} + +static BOOLEAN mlx4_interrupt( + IN struct _KINTERRUPT *Interrupt, + IN PVOID ServiceContext + ) +{ + struct mlx4_dev *dev = ServiceContext; + struct mlx4_priv *priv = mlx4_priv(dev); + + UNUSED_PARAM(Interrupt); + writel(priv->eq_table.clr_mask, priv->eq_table.clr_int); + return legacy_isr(dev); +} + +static void mlx4_dpc_msix( PRKDPC dpc, + PVOID ctx, PVOID arg1, PVOID arg2 ) +{ + struct mlx4_eq *eq = ctx; + + UNREFERENCED_PARAMETER(dpc); + UNREFERENCED_PARAMETER(arg1); + UNREFERENCED_PARAMETER(arg2); + + mlx4_eq_int(eq->dev, eq); +} + + +#if 1//WORKAROUND_POLL_EQ + +BOOLEAN +IsrSynchronizeRoutine( + IN PVOID SynchronizeContext + ) +{ + struct mlx4_dev *dev = (struct mlx4_dev *)SynchronizeContext; + + mlx4_interrupt(dev->pdev->int_obj,dev); + + return TRUE; +} + + +VOID eq_polling_thread(void *ctx) +{ +#define POLLING_INTERVAL_MS 50 + NTSTATUS status; + struct mlx4_priv *priv = (struct mlx4_priv *)ctx; + PVOID wait_objects[2]; + LARGE_INTEGER wait_time; + + wait_objects[0] = &priv->eq_table.thread_stop_event; + wait_objects[1] = &priv->eq_table.thread_start_event; + + for(;;){ + + /* before start polling */ + for (;;) { + status = KeWaitForMultipleObjects( 2, wait_objects, + WaitAny, Executive, KernelMode, FALSE, NULL, NULL ); + + if ( status == STATUS_WAIT_0 ){/* thread stopped */ + break; + } + + /* start polling */ + if ( status == STATUS_WAIT_1 ){ + break; + } + + } + + if(priv->eq_table.bTerminated) break; + if ( status == STATUS_WAIT_0 ) continue;/* thread stopped, wait for start again */ + + /* polling */ + wait_time.QuadPart = -(int64_t)(((uint64_t)POLLING_INTERVAL_MS) * 10000); + for (;;) { + //mlx4_interrupt( NULL, &priv->dev ); + KeSynchronizeExecution(priv->dev.pdev->int_obj, IsrSynchronizeRoutine, &priv->dev); + + status = KeWaitForSingleObject( &priv->eq_table.thread_stop_event, + Executive, KernelMode, FALSE, &wait_time ); + if ( status == STATUS_SUCCESS ) { + //KeClearEvent(&priv->eq_table.thread_stop_event); + break; /* thread stopped */ + } + } + + if(priv->eq_table.bTerminated) break; + } + + PsTerminateSystemThread(STATUS_SUCCESS); + +} + + +void mlx4_poll_eq(struct ib_device *device, BOOLEAN bStart) +{ + LONG signalled=0; + struct mlx4_priv *priv = mlx4_priv(device->dma_device); + + if(bStart){ + /* signal start of polling */ + signalled = KeSetEvent( + &priv->eq_table.thread_start_event, IO_NO_INCREMENT, FALSE ); + }else{ + /* signal end of polling */ + signalled = KeSetEvent( + &priv->eq_table.thread_stop_event, IO_NO_INCREMENT, FALSE ); + } + +} + +#endif + + +BOOLEAN +mlx4_msi_x_interrupt ( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext, + IN ULONG MessageId + ) +{ + int eq_ix; + struct mlx4_eq *eq; + struct mlx4_priv *priv; + struct mlx4_dev *dev = ServiceContext; + + UNUSED_PARAM(Interrupt); + + // Check, that it is our interrupt + if ( dev->signature != MLX4_DEV_SIGNATURE) + return FALSE; + + if (dev->flags & MLX4_FLAG_MSI_X) { + // MSI-X mode + priv = mlx4_priv(dev); + eq_ix = dev->pdev->p_msix_map[MessageId].eq_ix; + eq = &priv->eq_table.eq[eq_ix]; + if (eq_ix >= MLX4_NUM_EQ) { + if (eq->isr) + eq->isr(eq->ctx); + else + eq_set_ci(eq, 1); + } + else + KeInsertQueueDpc(&eq->dpc, NULL, NULL); + return TRUE; + } + + // legacy mode + return mlx4_interrupt(NULL,dev); +} + +static int mlx4_MAP_EQ(struct mlx4_dev *dev, u64 event_mask, int unmap, + int eq_num) +{ + return mlx4_cmd(dev, event_mask, (unmap << 31) | eq_num, + 0, MLX4_CMD_MAP_EQ, MLX4_CMD_TIME_CLASS_B); +} + +static int mlx4_SW2HW_EQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, + int eq_num) +{ + return mlx4_cmd(dev, mailbox->dma.da, eq_num, 0, MLX4_CMD_SW2HW_EQ, + MLX4_CMD_TIME_CLASS_A); +} + +static int mlx4_HW2SW_EQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, + int eq_num) +{ + return mlx4_cmd_box(dev, 0, mailbox->dma.da, eq_num, 0, MLX4_CMD_HW2SW_EQ, + MLX4_CMD_TIME_CLASS_A); +} + +static void __iomem *mlx4_get_eq_uar(struct mlx4_dev *dev, struct mlx4_eq *eq) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + int index; + + index = eq->eqn / 4 - dev->caps.reserved_eqs / 4; + + if (!priv->eq_table.uar_map[index]) { + priv->eq_table.uar_map[index] = + ioremap(pci_resource_start(dev->pdev, 2) + + ((eq->eqn / 4) << PAGE_SHIFT), + PAGE_SIZE); + if (!priv->eq_table.uar_map[index]) { + mlx4_err(dev, "Couldn't map EQ doorbell for EQN 0x%06x\n", + eq->eqn); + return NULL; + } + } + + return priv->eq_table.uar_map[index] + 0x800 + 8 * (eq->eqn % 4); +} + +/* for legacy interrupts the function returns 0 */ +/* for MSI-X - one vector per EQ */ +/* if cpu=0, it selects the first free vector */ +/* otherwise it returns free vector, allocated to this cpu */ +/* if cpu=0 and all vectors are taken it returns the first vector */ +/* if cpu!=0 and free vector for that cpu was not found - returns MLX4_NUM_UNKNOWN */ +int mlx4_alloc_msi_irqn(struct mlx4_dev *dev, KAFFINITY cpu, int eq_ix ) +{ + int i; + struct pci_dev *pdev = dev->pdev; + + if (!(dev->flags & MLX4_FLAG_MSI_X)) { + if (pdev->p_msix_map) { + pdev->p_msix_map[0].ref_cnt++; + pdev->p_msix_map[0].eq_ix = eq_ix; + } + return 0; + } + + for (i=0; i < pdev->n_msi_vectors_alloc; ++i) { + if (pdev->p_msix_map[i].ref_cnt) + continue; + if (!cpu || (pdev->p_msix_map[i].cpu & cpu)) { + pdev->p_msix_map[i].ref_cnt++; + pdev->p_msix_map[i].eq_ix = eq_ix; + return i; + } + } + + /* all vectors are taken - return error */ + ASSERT(0); + return MLX4_NUM_UNKNOWN; +} + +void mlx4_free_msi_irqn(struct mlx4_dev *dev, int intr) +{ + if (dev->pdev->p_msix_map) { + dev->pdev->p_msix_map[intr].ref_cnt--; + ASSERT(dev->pdev->p_msix_map[intr].ref_cnt>=0); + } +} + +static int mlx4_create_eq(struct mlx4_dev *dev, int nent, + KAFFINITY cpu, int eq_ix, struct mlx4_eq *eq) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_cmd_mailbox *mailbox; + struct mlx4_eq_context *eq_context; + int npages; + u64 *dma_list = NULL; + dma_addr_t t; + u64 mtt_addr; + int err = -ENOMEM; + int i; + int intr; + + eq->valid = 0; + intr = mlx4_alloc_msi_irqn(dev, cpu, eq_ix); + if (intr == MLX4_NUM_UNKNOWN) { + err = -ENOENT; + goto err_out; + } + eq->dev = dev; + eq->irq = (u16)intr; + eq->nent = roundup_pow_of_two(max(nent, 2)); + eq->cpu = cpu; + npages = (int)(NEXT_PAGE_ALIGN(eq->nent * MLX4_EQ_ENTRY_SIZE) / PAGE_SIZE); + + eq->page_list = kmalloc(npages * sizeof *eq->page_list, + GFP_KERNEL); + if (!eq->page_list) + goto err_malloc; + + for (i = 0; i < npages; ++i) + eq->page_list[i].buf = NULL; + + dma_list = kmalloc(npages * sizeof *dma_list, GFP_KERNEL); + if (!dma_list) + goto err_out_free; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + goto err_out_free; + eq_context = (struct mlx4_eq_context *)mailbox->buf; + + for (i = 0; i < npages; ++i) { + eq->page_list[i].buf = dma_alloc_coherent(&dev->pdev->dev, + PAGE_SIZE, &t, GFP_KERNEL); + if (!eq->page_list[i].buf) + goto err_out_free_pages; + + dma_list[i] = t.da; + eq->page_list[i].map = t; + + memset(eq->page_list[i].buf, 0, PAGE_SIZE); + } + + eq->eqn = mlx4_bitmap_alloc(&priv->eq_table.bitmap); + if (eq->eqn == -1) + goto err_out_free_pages; + + eq->doorbell = mlx4_get_eq_uar(dev, eq); + if (!eq->doorbell) { + err = -ENOMEM; + goto err_out_free_eq; + } + + err = mlx4_mtt_init(dev, npages, PAGE_SHIFT, &eq->mtt); + if (err) + goto err_out_free_eq; + + err = mlx4_write_mtt(dev, &eq->mtt, 0, npages, dma_list); + if (err) + goto err_out_free_mtt; + + memset(eq_context, 0, sizeof *eq_context); + eq_context->flags = cpu_to_be32(MLX4_EQ_STATUS_OK | + MLX4_EQ_STATE_ARMED); + eq_context->log_eq_size = (u8)ilog2(eq->nent); + eq_context->intr = (u8)intr; + eq_context->log_page_size = PAGE_SHIFT - MLX4_ICM_PAGE_SHIFT; + + mtt_addr = mlx4_mtt_addr(dev, &eq->mtt); + eq_context->mtt_base_addr_h = (u8)(mtt_addr >> 32); + eq_context->mtt_base_addr_l = cpu_to_be32(mtt_addr & 0xffffffff); + + err = mlx4_SW2HW_EQ(dev, mailbox, eq->eqn); + if (err) { + mlx4_warn(dev, "SW2HW_EQ failed (%d)\n", err); + goto err_out_free_mtt; + } + + mlx4_dbg(dev, "EQ created: EQN %d, size %d(%d), MSI ID %d, CPU %#x\n", + eq->eqn, nent, eq->nent, intr, cpu ); + + kfree(dma_list); + mlx4_free_cmd_mailbox(dev, mailbox); + + eq->cons_index = 0; + eq->valid = 1; + + return 0; + +err_out_free_mtt: + mlx4_mtt_cleanup(dev, &eq->mtt); + +err_out_free_eq: + mlx4_bitmap_free(&priv->eq_table.bitmap, eq->eqn); + +err_out_free_pages: + for (i = 0; i < npages; ++i) + if (eq->page_list[i].buf) + dma_free_coherent(&dev->pdev->dev, PAGE_SIZE, + eq->page_list[i].buf, + eq->page_list[i].map); + + mlx4_free_cmd_mailbox(dev, mailbox); + +err_out_free: + kfree(eq->page_list); + kfree(dma_list); + +err_malloc: + mlx4_free_msi_irqn(dev, eq->irq); + +err_out: + return err; +} + +static void mlx4_free_eq(struct mlx4_dev *dev, + struct mlx4_eq *eq) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_cmd_mailbox *mailbox; + int err; + int npages = (int)(NEXT_PAGE_ALIGN(MLX4_EQ_ENTRY_SIZE * eq->nent) / PAGE_SIZE); + int i; + + if (!eq->valid) + return; + eq->valid = 0; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + mailbox = NULL; + else { + err = mlx4_HW2SW_EQ(dev, mailbox, eq->eqn); + if (err) + mlx4_warn(dev, "HW2SW_EQ failed (%d)\n", err); + } + +#if 0 + { + mlx4_dbg(dev, "Dumping EQ context %02x:\n", eq->eqn); + for (i = 0; i < sizeof (struct mlx4_eq_context) / 4; ++i) { + if (i % 4 == 0) + printk("[%02x] ", i * 4); + printk(" %08x", be32_to_cpup(mailbox->buf + i * 4)); + if ((i + 1) % 4 == 0) + printk("\n"); + } + } +#endif + + mlx4_mtt_cleanup(dev, &eq->mtt); + for (i = 0; i < npages; ++i) + pci_free_consistent(dev->pdev, PAGE_SIZE, + eq->page_list[i].buf, + eq->page_list[i].map); + + kfree(eq->page_list); + mlx4_bitmap_free(&priv->eq_table.bitmap, eq->eqn); + mlx4_free_cmd_mailbox(dev, mailbox); + mlx4_free_msi_irqn(dev, eq->irq); +} + +static void mlx4_free_irqs(struct mlx4_dev *dev) +{ + struct mlx4_eq_table *eq_table = &mlx4_priv(dev)->eq_table; + + if (eq_table->have_irq) + free_irq(dev); +} + +static int mlx4_map_clr_int(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + + priv->clr_base = ioremap(pci_resource_start(dev->pdev, priv->fw.clr_int_bar) + + priv->fw.clr_int_base, MLX4_CLR_INT_SIZE); + if (!priv->clr_base) { + mlx4_err(dev, "Couldn't map interrupt clear register, aborting.\n"); + return -ENOMEM; + } + + return 0; +} + +static void mlx4_unmap_clr_int(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + + if (priv->clr_base) + iounmap(priv->clr_base, MLX4_CLR_INT_SIZE); +} + +int mlx4_init_eq_table(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + int err; + int i; + + err = mlx4_bitmap_init(&priv->eq_table.bitmap, dev->caps.num_eqs, + dev->caps.num_eqs - 1, dev->caps.reserved_eqs); + if (err) + return err; + + for (i = 0; i < ARRAY_SIZE(priv->eq_table.uar_map); ++i) + priv->eq_table.uar_map[i] = NULL; + + err = mlx4_map_clr_int(dev); + if (err) + goto err_out_free; + + priv->eq_table.clr_mask = + swab32(1 << (priv->eq_table.inta_pin & 31)); + priv->eq_table.clr_int = priv->clr_base + + (priv->eq_table.inta_pin < 32 ? 4 : 0); + + /* EQ creation should be in this order because of MSI-X vector allocation way */ + err = mlx4_create_eq(dev, MLX4_NUM_ASYNC_EQE + MLX4_NUM_SPARE_EQE, + 0, MLX4_EQ_ASYNC, &priv->eq_table.eq[MLX4_EQ_ASYNC]); + if (err) + goto err_out_unmap; + + err = mlx4_create_eq(dev, dev->caps.num_cqs + MLX4_NUM_SPARE_EQE, + 0, MLX4_EQ_COMP, &priv->eq_table.eq[MLX4_EQ_COMP]); + if (err) + goto err_out_comp; + + /* init DPC stuff */ + dev->pdev->dpc_lock = 0; + for (i = 0; i < MLX4_NUM_EQS; ++i) { + spin_lock_init( &priv->eq_table.eq[i].lock ); + KeInitializeDpc( &priv->eq_table.eq[i].dpc, + (dev->flags & MLX4_FLAG_MSI_X) ? mlx4_dpc_msix : mlx4_dpc, + &priv->eq_table.eq[i]); + priv->eq_table.eq[i].eq_ix = i; + } + + // connect interrupts +#ifdef USE_WDM_INTERRUPTS + err = request_irq( dev, + mlx4_interrupt, dev, + mlx4_msi_x_interrupt, + &dev->pdev->int_obj ); + if (err) + goto err_out_async; +#else + // not implemented - prevent compilation + #error Interrupts in WDF style are not implemented ! + goto err_out_async; +#endif + priv->eq_table.have_irq = 1; + + err = mlx4_MAP_EQ(dev, MLX4_ASYNC_EVENT_MASK, 0, + priv->eq_table.eq[MLX4_EQ_ASYNC].eqn); + if (err) { + mlx4_warn(dev, "MAP_EQ for async EQ %d failed (%d)\n", + priv->eq_table.eq[MLX4_EQ_ASYNC].eqn, err); + goto err_map_eq; + } + + mlx4_dbg(dev, "Commands and async events are mapped to EQ %d\n", + priv->eq_table.eq[MLX4_EQ_ASYNC].eqn); + + for (i = 0; i < MLX4_NUM_EQ; ++i) + eq_set_ci(&priv->eq_table.eq[i], 1); + +#if 1//WORKAROUND_POLL_EQ + { /* Create a thread for polling EQs in case of missing interrupts from the card */ + NTSTATUS status; + OBJECT_ATTRIBUTES attr; + HANDLE handle; + + KeInitializeEvent(&priv->eq_table.thread_start_event, SynchronizationEvent, FALSE); + KeInitializeEvent(&priv->eq_table.thread_stop_event, SynchronizationEvent, FALSE); + priv->eq_table.bTerminated = FALSE; + priv->eq_table.threadObject = NULL; + InitializeObjectAttributes( &attr, NULL, OBJ_KERNEL_HANDLE, NULL, NULL ); + status = PsCreateSystemThread( &handle, + THREAD_ALL_ACCESS, &attr, NULL, NULL, eq_polling_thread, priv ); + if (NT_SUCCESS(status)) { + status = ObReferenceObjectByHandle( + handle, + THREAD_ALL_ACCESS, + NULL, + KernelMode, + &priv->eq_table.threadObject, + NULL + ); + + ASSERT(status == STATUS_SUCCESS); // + + status = ZwClose(handle); + + ASSERT(NT_SUCCESS(status)); // Should always succeed + + } + } +#endif + + return 0; + +err_map_eq: + mlx4_free_irqs(dev); + +err_out_async: + mlx4_free_eq(dev, &priv->eq_table.eq[MLX4_EQ_COMP]); + +err_out_comp: + mlx4_free_eq(dev, &priv->eq_table.eq[MLX4_EQ_ASYNC]); + +err_out_unmap: + mlx4_unmap_clr_int(dev); + +err_out_free: + mlx4_bitmap_cleanup(&priv->eq_table.bitmap); + return err; +} + +int mlx4_add_eq(struct mlx4_dev *dev, int nent, + KAFFINITY cpu, PISR_FUNC func, PVOID func_context , + u8* p_eq_num, struct mlx4_eq ** p_eq) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + int err; + u8 i, new_eq = 0; + + if ( mlx4_is_barred(dev) ) + return -EFAULT; + + for (i = MLX4_NUM_EQ; i < MLX4_NUM_EQS; i++) { + if(priv->eq_table.eq[i].isr == NULL) { + new_eq = i; + break; + } + } + if (new_eq == 0) + return -ENOMEM; + + err = mlx4_create_eq(dev, nent, + cpu, new_eq, &priv->eq_table.eq[new_eq]); + if (err) { + return err; + } + + *p_eq = &priv->eq_table.eq[new_eq ]; + *p_eq_num = new_eq; + priv->eq_table.eq[new_eq].isr = func; + priv->eq_table.eq[new_eq].ctx = func_context; + priv->eq_table.max_extra_eqs = max(priv->eq_table.max_extra_eqs, new_eq); + return 0; +} + +void mlx4_remove_eq(struct mlx4_dev *dev, u8 eq_num) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_eq_table *eq_table = &mlx4_priv(dev)->eq_table; + + priv->eq_table.eq[eq_num].isr = NULL; + priv->eq_table.eq[eq_num].ctx = NULL; + + if (priv->eq_table.max_extra_eqs == eq_num) + priv->eq_table.max_extra_eqs--; + + mlx4_free_eq(dev, &priv->eq_table.eq[eq_num]); + + + if (eq_table->have_irq) { + int err; + + free_irq(dev); + + #ifdef USE_WDM_INTERRUPTS + err = request_irq( dev, + mlx4_interrupt, dev, + mlx4_msi_x_interrupt, + &dev->pdev->int_obj ); + if (err) { + mlx4_err(dev, "request_irq failed (%d)\n", + err); + ASSERT(0); + } + else + priv->eq_table.have_irq = 1; + #else + // not implemented - prevent compilation + #error Interrupts in WDF style are not implemented ! + #endif + + } +} + +void mlx4_cleanup_eq_table(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + int i; + +#if 1//WORKAROUND_POLL_EQ + /* stop the EQ polling thread */ + if (priv->eq_table.threadObject) { + #define WAIT_TIME_MS 3000 + NTSTATUS status; + LARGE_INTEGER wait_time; + LONG signalled; + + priv->eq_table.bTerminated = TRUE; + + /* signal polling stopped in case it is not */ + signalled = KeSetEvent( + &priv->eq_table.thread_stop_event, IO_NO_INCREMENT, FALSE ); + + /* wait for completion of the thread */ + wait_time.QuadPart = -(int64_t)(((uint64_t)WAIT_TIME_MS) * 10000); + status = KeWaitForSingleObject( priv->eq_table.threadObject, + Executive, KernelMode, FALSE, &wait_time ); + ASSERT(status == STATUS_SUCCESS); + + ObDereferenceObject(priv->eq_table.threadObject); + + /* cleanup */ + priv->eq_table.threadObject = NULL; + } +#endif + + mlx4_MAP_EQ(dev, MLX4_ASYNC_EVENT_MASK, 1, + priv->eq_table.eq[MLX4_EQ_ASYNC].eqn); + + mlx4_free_irqs(dev); + mlx4_free_eq(dev, &priv->eq_table.eq[MLX4_EQ_COMP]); + mlx4_free_eq(dev, &priv->eq_table.eq[MLX4_EQ_ASYNC]); + mlx4_unmap_clr_int(dev); + + for (i = 0; i < ARRAY_SIZE(priv->eq_table.uar_map); ++i) + if (priv->eq_table.uar_map[i]) + iounmap(priv->eq_table.uar_map[i],PAGE_SIZE); + + mlx4_bitmap_cleanup(&priv->eq_table.bitmap); +} diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/net/fw.c b/branches/WOF2-3/hw/mlx4/kernel/bus/net/fw.c new file mode 100644 index 00000000..3f2bfa37 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/net/fw.c @@ -0,0 +1,947 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "fw.h" +#include "cmd.h" +#include "icm.h" + +enum { + MLX4_COMMAND_INTERFACE_MIN_REV = 2, + MLX4_COMMAND_INTERFACE_MAX_REV = 3, + MLX4_COMMAND_INTERFACE_NEW_PORT_CMDS = 3, +}; + +#define FW_MAX_UNSUPPORTED 0x200050000I64 +#define FW_MIN_SUPPORTED 0x200060000I64 + +#define MLX4_GET(dest, source, offset) \ + { \ + void *__p = (char *) (source) + (offset); \ + void *__d = &(dest); \ + switch (sizeof (dest)) { \ + case 1: *(u8 *) __d = *(u8 *) __p; break; \ + case 2: *(__be16 *) __d = be16_to_cpup(__p); break; \ + case 4: *(__be32 *) __d = be32_to_cpup(__p); break; \ + case 8: *(__be64 *) __d = be64_to_cpup(__p); break; \ + default: ASSERTMSG("Incorrect dest field\n", !__p); \ + } \ + } + +#define MLX4_PUT(dest, source, offset) \ + { \ + void *__d = ((char *) (dest) + (offset)); \ + switch (sizeof(source)) { \ + case 1: *(u8 *) __d = (u8)(source); break; \ + case 2: *(__be16 *) __d = cpu_to_be16((u16)(source)); break; \ + case 4: *(__be32 *) __d = cpu_to_be32((u32)(source)); break; \ + case 8: *(__be64 *) __d = cpu_to_be64((u64)(source)); break; \ + default: ASSERTMSG("Incorrect dest field\n", !__d); \ + } \ + } + +static void dump_dev_cap_flags(struct mlx4_dev *dev, u32 flags) +{ + static char *fname[26]; + static int filled = 0; + int i; + + if (!filled) + { + memset( fname, 0, sizeof(fname) ); + fname[0] = "RC transport"; + fname[1] = "UC transport"; + fname[2] = "UD transport"; + fname[3] = "XRC transport"; + fname[4] = "reliable multicast"; + fname[5] = "FCoIB support"; + fname[6] = "SRQ support"; + fname[7] = "IPoIB checksum offload"; + fname[8] = "P_Key violation counter"; + fname[9] = "Q_Key violation counter"; + fname[10] = "VMM"; + fname[11] = "Unknown capability flag (11)"; + fname[12] = "DPDP (different port interfaces)"; + fname[13] = "Unknown capability flag (13)"; + fname[14] = "Unknown capability flag (14)"; + fname[15] = "Unknown capability flag (15)"; + fname[16] = "MW support"; + fname[17] = "APM support"; + fname[18] = "Atomic ops support"; + fname[19] = "Raw multicast support"; + fname[20] = "Address vector port checking support"; + fname[21] = "UD multicast support"; + fname[24] = "Demand paging support"; + fname[25] = "Router support"; + } + + mlx4_dbg(dev, "DEV_CAP flags:\n"); + for (i = 0; i < ARRAY_SIZE(fname); ++i) + if (fname[i] && (flags & (1 << i))) + mlx4_dbg(dev, " %s\n", fname[i]); +} + +int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) +{ + struct mlx4_cmd_mailbox *mailbox; + u32 *outbox; + u8 field; + u16 size; + u16 stat_rate; + int err; + int i; + +#define QUERY_DEV_CAP_OUT_SIZE 0x100 +#define QUERY_DEV_CAP_MAX_SRQ_SZ_OFFSET 0x10 +#define QUERY_DEV_CAP_MAX_QP_SZ_OFFSET 0x11 +#define QUERY_DEV_CAP_RSVD_QP_OFFSET 0x12 +#define QUERY_DEV_CAP_MAX_QP_OFFSET 0x13 +#define QUERY_DEV_CAP_RSVD_SRQ_OFFSET 0x14 +#define QUERY_DEV_CAP_MAX_SRQ_OFFSET 0x15 +#define QUERY_DEV_CAP_RSVD_EEC_OFFSET 0x16 +#define QUERY_DEV_CAP_MAX_EEC_OFFSET 0x17 +#define QUERY_DEV_CAP_MAX_CQ_SZ_OFFSET 0x19 +#define QUERY_DEV_CAP_RSVD_CQ_OFFSET 0x1a +#define QUERY_DEV_CAP_MAX_CQ_OFFSET 0x1b +#define QUERY_DEV_CAP_MAX_MPT_OFFSET 0x1d +#define QUERY_DEV_CAP_RSVD_EQ_OFFSET 0x1e +#define QUERY_DEV_CAP_MAX_EQ_OFFSET 0x1f +#define QUERY_DEV_CAP_RSVD_MTT_OFFSET 0x20 +#define QUERY_DEV_CAP_MAX_MRW_SZ_OFFSET 0x21 +#define QUERY_DEV_CAP_RSVD_MRW_OFFSET 0x22 +#define QUERY_DEV_CAP_MAX_MTT_SEG_OFFSET 0x23 +#define QUERY_DEV_CAP_MAX_AV_OFFSET 0x27 +#define QUERY_DEV_CAP_MAX_REQ_QP_OFFSET 0x29 +#define QUERY_DEV_CAP_MAX_RES_QP_OFFSET 0x2b +#define QUERY_DEV_CAP_MAX_GSO_OFFSET 0x2d +#define QUERY_DEV_CAP_MAX_RDMA_OFFSET 0x2f +#define QUERY_DEV_CAP_RSZ_SRQ_OFFSET 0x33 +#define QUERY_DEV_CAP_ACK_DELAY_OFFSET 0x35 +#define QUERY_DEV_CAP_MTU_WIDTH_OFFSET 0x36 +#define QUERY_DEV_CAP_VL_PORT_OFFSET 0x37 +#define QUERY_DEV_CAP_MAX_MSG_SZ_OFFSET 0x38 +#define QUERY_DEV_CAP_MAX_GID_OFFSET 0x3b +#define QUERY_DEV_CAP_RATE_SUPPORT_OFFSET 0x3c +#define QUERY_DEV_CAP_MAX_PKEY_OFFSET 0x3f +#define QUERY_DEV_CAP_FLAGS_OFFSET 0x44 +#define QUERY_DEV_CAP_RSVD_UAR_OFFSET 0x48 +#define QUERY_DEV_CAP_UAR_SZ_OFFSET 0x49 +#define QUERY_DEV_CAP_PAGE_SZ_OFFSET 0x4b +#define QUERY_DEV_CAP_BF_OFFSET 0x4c +#define QUERY_DEV_CAP_LOG_BF_REG_SZ_OFFSET 0x4d +#define QUERY_DEV_CAP_LOG_MAX_BF_REGS_PER_PAGE_OFFSET 0x4e +#define QUERY_DEV_CAP_LOG_MAX_BF_PAGES_OFFSET 0x4f +#define QUERY_DEV_CAP_MAX_SG_SQ_OFFSET 0x51 +#define QUERY_DEV_CAP_MAX_DESC_SZ_SQ_OFFSET 0x52 +#define QUERY_DEV_CAP_MAX_SG_RQ_OFFSET 0x55 +#define QUERY_DEV_CAP_MAX_DESC_SZ_RQ_OFFSET 0x56 +#define QUERY_DEV_CAP_MAX_QP_MCG_OFFSET 0x61 +#define QUERY_DEV_CAP_RSVD_MCG_OFFSET 0x62 +#define QUERY_DEV_CAP_MAX_MCG_OFFSET 0x63 +#define QUERY_DEV_CAP_RSVD_PD_OFFSET 0x64 +#define QUERY_DEV_CAP_MAX_PD_OFFSET 0x65 +#define QUERY_DEV_CAP_RDMARC_ENTRY_SZ_OFFSET 0x80 +#define QUERY_DEV_CAP_QPC_ENTRY_SZ_OFFSET 0x82 +#define QUERY_DEV_CAP_AUX_ENTRY_SZ_OFFSET 0x84 +#define QUERY_DEV_CAP_ALTC_ENTRY_SZ_OFFSET 0x86 +#define QUERY_DEV_CAP_EQC_ENTRY_SZ_OFFSET 0x88 +#define QUERY_DEV_CAP_CQC_ENTRY_SZ_OFFSET 0x8a +#define QUERY_DEV_CAP_SRQ_ENTRY_SZ_OFFSET 0x8c +#define QUERY_DEV_CAP_C_MPT_ENTRY_SZ_OFFSET 0x8e +#define QUERY_DEV_CAP_MTT_ENTRY_SZ_OFFSET 0x90 +#define QUERY_DEV_CAP_D_MPT_ENTRY_SZ_OFFSET 0x92 +#define QUERY_DEV_CAP_BMME_FLAGS_OFFSET 0x97 +#define QUERY_DEV_CAP_RSVD_LKEY_OFFSET 0x98 +#define QUERY_DEV_CAP_MAX_ICM_SZ_OFFSET 0xa0 + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + outbox = mailbox->buf; + + err = mlx4_cmd_box(dev, 0, mailbox->dma.da, 0, 0, MLX4_CMD_QUERY_DEV_CAP, + MLX4_CMD_TIME_CLASS_A); + if (err) + goto out; + + MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_QP_OFFSET); + dev_cap->reserved_qps = 1 << (field & 0xf); + MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_QP_OFFSET); + dev_cap->max_qps = 1 << (field & 0x1f); + MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_SRQ_OFFSET); + dev_cap->reserved_srqs = 1 << (field >> 4); + MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_SRQ_OFFSET); + dev_cap->max_srqs = 1 << (field & 0x1f); + MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_CQ_SZ_OFFSET); + dev_cap->max_cq_sz = 1 << field; + MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_CQ_OFFSET); + dev_cap->reserved_cqs = 1 << (field & 0xf); + MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_CQ_OFFSET); + dev_cap->max_cqs = 1 << (field & 0x1f); + MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_MPT_OFFSET); + dev_cap->max_mpts = 1 << (field & 0x3f); + MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_EQ_OFFSET); + dev_cap->reserved_eqs = 1 << (field & 0xf); + MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_EQ_OFFSET); + dev_cap->max_eqs = 1 << (field & 0xf); + MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_MTT_OFFSET); + dev_cap->reserved_mtts = 1 << (field >> 4); + MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_MRW_SZ_OFFSET); + dev_cap->max_mrw_sz = 1 << field; + MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_MRW_OFFSET); + dev_cap->reserved_mrws = 1 << (field & 0xf); + MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_MTT_SEG_OFFSET); + dev_cap->max_mtt_seg = 1 << (field & 0x3f); + MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_REQ_QP_OFFSET); + dev_cap->max_requester_per_qp = 1 << (field & 0x3f); + MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_RES_QP_OFFSET); + dev_cap->max_responder_per_qp = 1 << (field & 0x3f); + MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_GSO_OFFSET); + field &= 0x1f; + if (!field) + dev_cap->max_gso_sz = 0; + else + dev_cap->max_gso_sz = 1 << field; + MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_RDMA_OFFSET); + dev_cap->max_rdma_global = 1 << (field & 0x3f); + MLX4_GET(field, outbox, QUERY_DEV_CAP_ACK_DELAY_OFFSET); + dev_cap->local_ca_ack_delay = field & 0x1f; + MLX4_GET(field, outbox, QUERY_DEV_CAP_VL_PORT_OFFSET); + dev_cap->num_ports = field & 0xf; + MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_MSG_SZ_OFFSET); + dev_cap->max_msg_sz = 1 << (field & 0x1f); + MLX4_GET(stat_rate, outbox, QUERY_DEV_CAP_RATE_SUPPORT_OFFSET); + dev_cap->stat_rate_support = stat_rate; + MLX4_GET(dev_cap->flags, outbox, QUERY_DEV_CAP_FLAGS_OFFSET); + MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_UAR_OFFSET); + dev_cap->reserved_uars = field >> 4; + MLX4_GET(field, outbox, QUERY_DEV_CAP_UAR_SZ_OFFSET); + dev_cap->uar_size = 1 << ((field & 0x3f) + 20); + MLX4_GET(field, outbox, QUERY_DEV_CAP_PAGE_SZ_OFFSET); + dev_cap->min_page_sz = 1 << field; + + MLX4_GET(field, outbox, QUERY_DEV_CAP_BF_OFFSET); + if (field & 0x80) { + MLX4_GET(field, outbox, QUERY_DEV_CAP_LOG_BF_REG_SZ_OFFSET); + dev_cap->bf_reg_size = 1 << (field & 0x1f); + MLX4_GET(field, outbox, QUERY_DEV_CAP_LOG_MAX_BF_REGS_PER_PAGE_OFFSET); + dev_cap->bf_regs_per_page = 1 << (field & 0x3f); + mlx4_dbg(dev, "BlueFlame available (reg size %d, regs/page %d)\n", + dev_cap->bf_reg_size, dev_cap->bf_regs_per_page); + } else { + dev_cap->bf_reg_size = 0; + mlx4_dbg(dev, "BlueFlame not available\n"); + } + + MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_SG_SQ_OFFSET); + dev_cap->max_sq_sg = field; + MLX4_GET(size, outbox, QUERY_DEV_CAP_MAX_DESC_SZ_SQ_OFFSET); + dev_cap->max_sq_desc_sz = size; + + MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_QP_MCG_OFFSET); + dev_cap->max_qp_per_mcg = 1 << field; + MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_MCG_OFFSET); + dev_cap->reserved_mgms = field & 0xf; + MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_MCG_OFFSET); + dev_cap->max_mcgs = 1 << field; + MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_PD_OFFSET); + dev_cap->reserved_pds = field >> 4; + MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_PD_OFFSET); + dev_cap->max_pds = 1 << (field & 0x3f); + + MLX4_GET(size, outbox, QUERY_DEV_CAP_RDMARC_ENTRY_SZ_OFFSET); + dev_cap->rdmarc_entry_sz = size; + MLX4_GET(size, outbox, QUERY_DEV_CAP_QPC_ENTRY_SZ_OFFSET); + dev_cap->qpc_entry_sz = size; + MLX4_GET(size, outbox, QUERY_DEV_CAP_AUX_ENTRY_SZ_OFFSET); + dev_cap->aux_entry_sz = size; + MLX4_GET(size, outbox, QUERY_DEV_CAP_ALTC_ENTRY_SZ_OFFSET); + dev_cap->altc_entry_sz = size; + MLX4_GET(size, outbox, QUERY_DEV_CAP_EQC_ENTRY_SZ_OFFSET); + dev_cap->eqc_entry_sz = size; + MLX4_GET(size, outbox, QUERY_DEV_CAP_CQC_ENTRY_SZ_OFFSET); + dev_cap->cqc_entry_sz = size; + MLX4_GET(size, outbox, QUERY_DEV_CAP_SRQ_ENTRY_SZ_OFFSET); + dev_cap->srq_entry_sz = size; + MLX4_GET(size, outbox, QUERY_DEV_CAP_C_MPT_ENTRY_SZ_OFFSET); + dev_cap->cmpt_entry_sz = size; + MLX4_GET(size, outbox, QUERY_DEV_CAP_MTT_ENTRY_SZ_OFFSET); + dev_cap->mtt_entry_sz = size; + MLX4_GET(size, outbox, QUERY_DEV_CAP_D_MPT_ENTRY_SZ_OFFSET); + dev_cap->dmpt_entry_sz = size; + + MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_SRQ_SZ_OFFSET); + dev_cap->max_srq_sz = 1 << field; + MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_QP_SZ_OFFSET); + dev_cap->max_qp_sz = 1 << field; + MLX4_GET(field, outbox, QUERY_DEV_CAP_RSZ_SRQ_OFFSET); + dev_cap->resize_srq = field & 1; + MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_SG_RQ_OFFSET); + dev_cap->max_rq_sg = field; + MLX4_GET(size, outbox, QUERY_DEV_CAP_MAX_DESC_SZ_RQ_OFFSET); + dev_cap->max_rq_desc_sz = size; + + MLX4_GET(dev_cap->bmme_flags, outbox, + QUERY_DEV_CAP_BMME_FLAGS_OFFSET); + MLX4_GET(dev_cap->reserved_lkey, outbox, + QUERY_DEV_CAP_RSVD_LKEY_OFFSET); + MLX4_GET(dev_cap->max_icm_sz, outbox, + QUERY_DEV_CAP_MAX_ICM_SZ_OFFSET); + + if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) { + for (i = 1; i <= dev_cap->num_ports; ++i) { + MLX4_GET(field, outbox, QUERY_DEV_CAP_VL_PORT_OFFSET); + dev_cap->max_vl[i] = field >> 4; + MLX4_GET(field, outbox, QUERY_DEV_CAP_MTU_WIDTH_OFFSET); + dev_cap->ib_mtu[i] = field >> 4; + dev_cap->max_port_width[i] = field & 0xf; + MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_GID_OFFSET); + dev_cap->max_gids[i] = 1 << (field & 0xf); + MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_PKEY_OFFSET); + dev_cap->max_pkeys[i] = 1 << (field & 0xf); + } + } else { +#define QUERY_PORT_SUPPORTED_TYPE_OFFSET 0x00 +#define QUERY_PORT_MTU_OFFSET 0x01 +#define QUERY_PORT_WIDTH_OFFSET 0x06 +#define QUERY_PORT_MAX_GID_PKEY_OFFSET 0x07 +#define QUERY_PORT_MAX_MACVLAN_OFFSET 0x0a +#define QUERY_PORT_MAX_VL_OFFSET 0x0b + + for (i = 1; i <= dev_cap->num_ports; ++i) { + err = mlx4_cmd_box(dev, 0, mailbox->dma.da, i, 0, MLX4_CMD_QUERY_PORT, + MLX4_CMD_TIME_CLASS_B); + if (err) + goto out; + + MLX4_GET(field, outbox, QUERY_PORT_MTU_OFFSET); + dev_cap->ib_mtu[i] = field & 0xf; + MLX4_GET(field, outbox, QUERY_PORT_WIDTH_OFFSET); + dev_cap->max_port_width[i] = field & 0xf; + MLX4_GET(field, outbox, QUERY_PORT_MAX_GID_PKEY_OFFSET); + dev_cap->max_gids[i] = 1 << (field >> 4); + dev_cap->max_pkeys[i] = 1 << (field & 0xf); + MLX4_GET(field, outbox, QUERY_PORT_MAX_VL_OFFSET); + dev_cap->max_vl[i] = field & 0xf; + MLX4_GET(field, outbox, + QUERY_PORT_SUPPORTED_TYPE_OFFSET); + dev_cap->supported_port_types[i] = field & 3; + MLX4_GET(field, outbox, QUERY_PORT_MAX_MACVLAN_OFFSET); + dev_cap->log_max_macs[i] = field & 0xf; + dev_cap->log_max_vlans[i] = field >> 4; + dev_cap->eth_mtu[i] = be16_to_cpu(((u16 *) outbox)[1]); + dev_cap->def_mac[i] = be64_to_cpu(((u64 *) outbox)[2]); + } + } + + if (dev_cap->bmme_flags & 1) + mlx4_dbg(dev, "Base MM extensions: yes " + "(flags %d, rsvd L_Key %08x)\n", + dev_cap->bmme_flags, dev_cap->reserved_lkey); + else + mlx4_dbg(dev, "Base MM extensions: no\n"); + + /* + * Each UAR has 4 EQ doorbells; so if a UAR is reserved, then + * we can't use any EQs whose doorbell falls on that page, + * even if the EQ itself isn't reserved. + */ + dev_cap->reserved_eqs = max(dev_cap->reserved_uars * 4, + dev_cap->reserved_eqs); + + mlx4_dbg(dev, "Max ICM size %lld MB\n", + (unsigned long long) dev_cap->max_icm_sz >> 20); + mlx4_dbg(dev, "Max QPs: %d, reserved QPs: %d, entry size: %d\n", + dev_cap->max_qps, dev_cap->reserved_qps, dev_cap->qpc_entry_sz); + mlx4_dbg(dev, "Max SRQs: %d, reserved SRQs: %d, entry size: %d\n", + dev_cap->max_srqs, dev_cap->reserved_srqs, dev_cap->srq_entry_sz); + mlx4_dbg(dev, "Max CQs: %d, reserved CQs: %d, entry size: %d\n", + dev_cap->max_cqs, dev_cap->reserved_cqs, dev_cap->cqc_entry_sz); + mlx4_dbg(dev, "Max EQs: %d, reserved EQs: %d, entry size: %d\n", + dev_cap->max_eqs, dev_cap->reserved_eqs, dev_cap->eqc_entry_sz); + mlx4_dbg(dev, "reserved MPTs: %d, reserved MTTs: %d\n", + dev_cap->reserved_mrws, dev_cap->reserved_mtts); + mlx4_dbg(dev, "Max PDs: %d, reserved PDs: %d, reserved UARs: %d\n", + dev_cap->max_pds, dev_cap->reserved_pds, dev_cap->reserved_uars); + mlx4_dbg(dev, "Max QP/MCG: %d, reserved MGMs: %d\n", + dev_cap->max_pds, dev_cap->reserved_mgms); + mlx4_dbg(dev, "Max CQEs: %d, max WQEs: %d, max SRQ WQEs: %d\n", + dev_cap->max_cq_sz, dev_cap->max_qp_sz, dev_cap->max_srq_sz); + mlx4_dbg(dev, "Local CA ACK delay: %d, max MTU: %d, port width cap: %d\n", + dev_cap->local_ca_ack_delay, 128 << dev_cap->ib_mtu[1], + dev_cap->max_port_width[1]); + mlx4_dbg(dev, "Max SQ desc size: %d, max SQ S/G: %d\n", + dev_cap->max_sq_desc_sz, dev_cap->max_sq_sg); + mlx4_dbg(dev, "Max RQ desc size: %d, max RQ S/G: %d\n", + dev_cap->max_rq_desc_sz, dev_cap->max_rq_sg); + mlx4_dbg(dev, "Max GSO size: %d\n", dev_cap->max_gso_sz); + + dump_dev_cap_flags(dev, dev_cap->flags); + +out: + mlx4_free_cmd_mailbox(dev, mailbox); + return err; +} + +int mlx4_map_cmd(struct mlx4_dev *dev, u16 op, struct mlx4_icm *icm, u64 virt) +{ + struct mlx4_cmd_mailbox *mailbox; + struct mlx4_icm_iter iter; + __be64 *pages; + int lg; + int nent = 0; + unsigned int i; + int err = 0; + int ts = 0, tc = 0; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + memset(mailbox->buf, 0, MLX4_MAILBOX_SIZE); + pages = mailbox->buf; + + for (mlx4_icm_first(icm, &iter); + !mlx4_icm_last(&iter); + mlx4_icm_next(&iter)) { + /* + * We have to pass pages that are aligned to their + * size, so find the least significant 1 in the + * address or size and use that as our log2 size. + */ + unsigned long end = (unsigned long)(mlx4_icm_addr(&iter).da | mlx4_icm_size(&iter)); + lg = ffs(end) - 1; + if (lg < MLX4_ICM_PAGE_SHIFT) { + mlx4_warn(dev, "Got FW area not aligned to %d (%llx/%lx).\n", + MLX4_ICM_PAGE_SIZE, + (unsigned long long) mlx4_icm_addr(&iter).da, + mlx4_icm_size(&iter)); + err = -EINVAL; + goto out; + } + + for (i = 0; i < mlx4_icm_size(&iter) >> lg; ++i) { + if (virt != -1) { + pages[nent * 2] = cpu_to_be64(virt); + virt += 1I64 << lg; + } + + pages[nent * 2 + 1] = + cpu_to_be64((mlx4_icm_addr(&iter).da + (i << lg)) | + (lg - MLX4_ICM_PAGE_SHIFT)); + ts += 1 << (lg - 10); + ++tc; + + if (++nent == MLX4_MAILBOX_SIZE / 16) { + err = mlx4_cmd(dev, mailbox->dma.da, nent, 0, op, + MLX4_CMD_TIME_CLASS_B); + if (err) + goto out; + nent = 0; + } + } + } + + if (nent) + err = mlx4_cmd(dev, mailbox->dma.da, nent, 0, op, MLX4_CMD_TIME_CLASS_B); + if (err) + goto out; + +#if 0 + switch (op) { + case MLX4_CMD_MAP_FA: + mlx4_dbg(dev, "Mapped %d chunks/%d KB for FW.\n", tc, ts); + break; + case MLX4_CMD_MAP_ICM_AUX: + mlx4_dbg(dev, "Mapped %d chunks/%d KB for ICM aux.\n", tc, ts); + break; + case MLX4_CMD_MAP_ICM: + mlx4_dbg(dev, "Mapped %d chunks/%d KB at %llx for ICM.\n", + tc, ts, (unsigned long long) virt - (ts << 10)); + break; + } +#endif + +out: + mlx4_free_cmd_mailbox(dev, mailbox); + return err; +} + +int mlx4_MAP_FA(struct mlx4_dev *dev, struct mlx4_icm *icm) +{ + return mlx4_map_cmd(dev, MLX4_CMD_MAP_FA, icm, (u64)-1); +} + +int mlx4_UNMAP_FA(struct mlx4_dev *dev) +{ + return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_UNMAP_FA, MLX4_CMD_TIME_CLASS_B); +} + + +int mlx4_RUN_FW(struct mlx4_dev *dev) +{ + return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_RUN_FW, MLX4_CMD_TIME_CLASS_A); +} + +int mlx4_QUERY_FW(struct mlx4_dev *dev) +{ + struct mlx4_fw *fw = &mlx4_priv(dev)->fw; + struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd; + struct mlx4_cmd_mailbox *mailbox; + u32 *outbox; + int err = 0; + u64 fw_ver; + u16 cmd_if_rev; + u8 lg; + +#define QUERY_FW_OUT_SIZE 0x100 +#define QUERY_FW_VER_OFFSET 0x00 +#define QUERY_FW_CMD_IF_REV_OFFSET 0x0a +#define QUERY_FW_MAX_CMD_OFFSET 0x0f +#define QUERY_FW_ERR_START_OFFSET 0x30 +#define QUERY_FW_ERR_SIZE_OFFSET 0x38 +#define QUERY_FW_ERR_BAR_OFFSET 0x3c + +#define QUERY_FW_SIZE_OFFSET 0x00 +#define QUERY_FW_CLR_INT_BASE_OFFSET 0x20 +#define QUERY_FW_CLR_INT_BAR_OFFSET 0x28 + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + outbox = mailbox->buf; + + err = mlx4_cmd_box(dev, 0, mailbox->dma.da, 0, 0, MLX4_CMD_QUERY_FW, + MLX4_CMD_TIME_CLASS_A); + if (err) + goto out; + + MLX4_GET(fw_ver, outbox, QUERY_FW_VER_OFFSET); + /* + * FW subminor version is at more significant bits than minor + * version, so swap here. + */ + dev->caps.fw_ver = (fw_ver & 0xffff00000000ull) | + ((fw_ver & 0xffff0000ull) >> 16) | + ((fw_ver & 0x0000ffffull) << 16); + + MLX4_GET(cmd_if_rev, outbox, QUERY_FW_CMD_IF_REV_OFFSET); + if (cmd_if_rev < MLX4_COMMAND_INTERFACE_MIN_REV || + cmd_if_rev > MLX4_COMMAND_INTERFACE_MAX_REV) { + mlx4_err(dev, "Installed FW has unsupported " + "command interface revision %d.\n", + cmd_if_rev); + mlx4_err(dev, "(Installed FW version is %d.%d.%03d)\n", + (int) (dev->caps.fw_ver >> 32), + (int) (dev->caps.fw_ver >> 16) & 0xffff, + (int) dev->caps.fw_ver & 0xffff); + mlx4_err(dev, "This driver version supports only revisions %d to %d.\n", + MLX4_COMMAND_INTERFACE_MIN_REV, MLX4_COMMAND_INTERFACE_MAX_REV); + err = -ENODEV; + goto out; + } + + if (dev->caps.fw_ver < FW_MAX_UNSUPPORTED) { + mlx4_err(dev, "HCA FW version %d.%d.%d is not supported. Use %d.%d.%d or higher.\n", + (int) (dev->caps.fw_ver >> 32), (int) (dev->caps.fw_ver >> 16) & 0xffff, + (int) (dev->caps.fw_ver & 0xffff), (int) (FW_MAX_UNSUPPORTED >> 32), + (int) (FW_MAX_UNSUPPORTED>> 16) & 0xffff, (int) (FW_MAX_UNSUPPORTED & 0xffff)); + err = -ENODEV; + goto out; + } + else + if (dev->caps.fw_ver < FW_MIN_SUPPORTED) { + mlx4_err(dev, "The HCA FW version is not the latest one. \n" + "If you meet any issues with the HCA please first try to upgrade the FW to version %d.%d.%d or higher.\n", + (int) (FW_MIN_SUPPORTED >> 32), (int) (FW_MIN_SUPPORTED >> 16) & 0xffff, (int) (FW_MIN_SUPPORTED & 0xffff)); + } + + if (cmd_if_rev < MLX4_COMMAND_INTERFACE_NEW_PORT_CMDS) + dev->flags |= MLX4_FLAG_OLD_PORT_CMDS; + + MLX4_GET(lg, outbox, QUERY_FW_MAX_CMD_OFFSET); + cmd->max_cmds = 1 << lg; + + mlx4_dbg(dev, "Current FW version %d.%d.%03d (cmd intf rev %d), max commands %d\n", + (int) (dev->caps.fw_ver >> 32), (int) (dev->caps.fw_ver >> 16) & 0xffff, + (int) dev->caps.fw_ver & 0xffff, cmd_if_rev, cmd->max_cmds); + + MLX4_GET(fw->catas_offset, outbox, QUERY_FW_ERR_START_OFFSET); + MLX4_GET(fw->catas_size, outbox, QUERY_FW_ERR_SIZE_OFFSET); + MLX4_GET(fw->catas_bar, outbox, QUERY_FW_ERR_BAR_OFFSET); + fw->catas_bar = (fw->catas_bar >> 6) * 2; + + mlx4_dbg(dev, "Catastrophic error buffer at 0x%llx, size 0x%x, BAR %d\n", + (unsigned long long) fw->catas_offset, fw->catas_size, fw->catas_bar); + + MLX4_GET(fw->fw_pages, outbox, QUERY_FW_SIZE_OFFSET); + MLX4_GET(fw->clr_int_base, outbox, QUERY_FW_CLR_INT_BASE_OFFSET); + MLX4_GET(fw->clr_int_bar, outbox, QUERY_FW_CLR_INT_BAR_OFFSET); + fw->clr_int_bar = (fw->clr_int_bar >> 6) * 2; + + mlx4_dbg(dev, "FW size %d KB\n", fw->fw_pages >> 2); + + /* + * Round up number of system pages needed in case + * MLX4_ICM_PAGE_SIZE < PAGE_SIZE. + */ + fw->fw_pages = + ALIGN(fw->fw_pages, PAGE_SIZE / MLX4_ICM_PAGE_SIZE) >> + (PAGE_SHIFT - MLX4_ICM_PAGE_SHIFT); + + mlx4_dbg(dev, "Clear int @ %llx, BAR %d\n", + (unsigned long long) fw->clr_int_base, fw->clr_int_bar); + +out: + mlx4_free_cmd_mailbox(dev, mailbox); + return err; +} + + +static int +query_port_state(struct mlx4_dev *dev, u8 port) +{ + int err = 0; + u32 input_modifier = 0; + u64 out_param; + +#define MOD_STAT_OPMOD_QUERY_INLINE 0x3 +#define MOD_STAT_OFFSET_PORT_EN 0x8 + + input_modifier = (1 << 28) | (port << 8) | MOD_STAT_OFFSET_PORT_EN; + + err = mlx4_cmd_imm(dev, 0, &out_param, input_modifier, + MOD_STAT_OPMOD_QUERY_INLINE, + MLX4_CMD_QUERY_STAT_CFG, + MLX4_CMD_TIME_CLASS_A); + if (err) { + return err; + } + + dev->caps.port_state[port] = (((out_param >> 20) & 1) ? MLX4_PORT_ENABLED : MLX4_PORT_DISABLED); + return 0; +} + +int mlx4_port_state(struct mlx4_dev *dev) +{ + u8 i = 0; + int err = 0; + + + for (i = 1; i <= dev->caps.num_ports; ++i) + { + dev->caps.port_state[i] = MLX4_PORT_ENABLED; + } + + for (i = 1; i <= dev->caps.num_ports; ++i) + { + err = query_port_state(dev, i); + if (err) + { + return err; + } + } + + return 0; +} + +static void get_board_id(u8 *vsd, char *board_id) +{ + int i; + +#define VSD_OFFSET_SIG1 0x00 +#define VSD_OFFSET_SIG2 0xde +#define VSD_OFFSET_MLX_BOARD_ID 0xd0 +#define VSD_OFFSET_TS_BOARD_ID 0x20 + +#define VSD_SIGNATURE_TOPSPIN 0x5ad + + memset(board_id, 0, MLX4_BOARD_ID_LEN); + + if (be16_to_cpup(vsd + VSD_OFFSET_SIG1) == VSD_SIGNATURE_TOPSPIN && + be16_to_cpup(vsd + VSD_OFFSET_SIG2) == VSD_SIGNATURE_TOPSPIN) { + strlcpy(board_id, vsd + VSD_OFFSET_TS_BOARD_ID, MLX4_BOARD_ID_LEN); + } else { + /* + * The board ID is a string but the firmware byte + * swaps each 4-byte word before passing it back to + * us. Therefore we need to swab it before printing. + */ + for (i = 0; i < 4; ++i) + ((u32 *) board_id)[i] = + swab32(*(u32 *) (vsd + VSD_OFFSET_MLX_BOARD_ID + i * 4)); + } +} + +int mlx4_QUERY_ADAPTER(struct mlx4_dev *dev, struct mlx4_adapter *adapter) +{ + struct mlx4_cmd_mailbox *mailbox; + u32 *outbox; + int err; + +#define QUERY_ADAPTER_OUT_SIZE 0x100 +#define QUERY_ADAPTER_INTA_PIN_OFFSET 0x10 +#define QUERY_ADAPTER_VSD_OFFSET 0x20 + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + outbox = mailbox->buf; + + err = mlx4_cmd_box(dev, 0, mailbox->dma.da, 0, 0, MLX4_CMD_QUERY_ADAPTER, + MLX4_CMD_TIME_CLASS_A); + if (err) + goto out; + + MLX4_GET(adapter->inta_pin, outbox, QUERY_ADAPTER_INTA_PIN_OFFSET); + + get_board_id((u8*)(outbox + QUERY_ADAPTER_VSD_OFFSET / 4), + adapter->board_id); + +out: + mlx4_free_cmd_mailbox(dev, mailbox); + return err; +} + +int mlx4_INIT_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param) +{ + struct mlx4_cmd_mailbox *mailbox; + __be32 *inbox; + int err; + u8 uar_page_sz = PAGE_SHIFT - 12; + +#define INIT_HCA_IN_SIZE 0x200 +#define INIT_HCA_VERSION_OFFSET 0x000 +#define INIT_HCA_VERSION 2 +#define INIT_HCA_CACHELINE_SZ_OFFSET 0x0e +#define INIT_HCA_X86_64_BYTE_CACHELINE_SZ 0x40 +#define INIT_HCA_FLAGS_OFFSET 0x014 +#define INIT_HCA_QPC_OFFSET 0x020 +#define INIT_HCA_QPC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x10) +#define INIT_HCA_LOG_QP_OFFSET (INIT_HCA_QPC_OFFSET + 0x17) +#define INIT_HCA_SRQC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x28) +#define INIT_HCA_LOG_SRQ_OFFSET (INIT_HCA_QPC_OFFSET + 0x2f) +#define INIT_HCA_CQC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x30) +#define INIT_HCA_LOG_CQ_OFFSET (INIT_HCA_QPC_OFFSET + 0x37) +#define INIT_HCA_ALTC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x40) +#define INIT_HCA_AUXC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x50) +#define INIT_HCA_EQC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x60) +#define INIT_HCA_LOG_EQ_OFFSET (INIT_HCA_QPC_OFFSET + 0x67) +#define INIT_HCA_RDMARC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x70) +#define INIT_HCA_LOG_RD_OFFSET (INIT_HCA_QPC_OFFSET + 0x77) +#define INIT_HCA_MCAST_OFFSET 0x0c0 +#define INIT_HCA_MC_BASE_OFFSET (INIT_HCA_MCAST_OFFSET + 0x00) +#define INIT_HCA_LOG_MC_ENTRY_SZ_OFFSET (INIT_HCA_MCAST_OFFSET + 0x12) +#define INIT_HCA_LOG_MC_HASH_SZ_OFFSET (INIT_HCA_MCAST_OFFSET + 0x16) +#define INIT_HCA_LOG_MC_TABLE_SZ_OFFSET (INIT_HCA_MCAST_OFFSET + 0x1b) +#define INIT_HCA_TPT_OFFSET 0x0f0 +#define INIT_HCA_DMPT_BASE_OFFSET (INIT_HCA_TPT_OFFSET + 0x00) +#define INIT_HCA_LOG_MPT_SZ_OFFSET (INIT_HCA_TPT_OFFSET + 0x0b) +#define INIT_HCA_MTT_BASE_OFFSET (INIT_HCA_TPT_OFFSET + 0x10) +#define INIT_HCA_CMPT_BASE_OFFSET (INIT_HCA_TPT_OFFSET + 0x18) +#define INIT_HCA_UAR_OFFSET 0x120 +#define INIT_HCA_LOG_UAR_SZ_OFFSET (INIT_HCA_UAR_OFFSET + 0x0a) +#define INIT_HCA_UAR_PAGE_SZ_OFFSET (INIT_HCA_UAR_OFFSET + 0x0b) + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + inbox = mailbox->buf; + + memset(inbox, 0, INIT_HCA_IN_SIZE); + + *((u8 *) mailbox->buf + INIT_HCA_VERSION_OFFSET) = INIT_HCA_VERSION; +#if defined(_AMD64_) + *((u8 *) mailbox->buf + INIT_HCA_CACHELINE_SZ_OFFSET) = INIT_HCA_X86_64_BYTE_CACHELINE_SZ; +#endif + +#if defined(__LITTLE_ENDIAN) + *(inbox + INIT_HCA_FLAGS_OFFSET / 4) &= ~cpu_to_be32(1 << 1); +#elif defined(__BIG_ENDIAN) + *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1 << 1); +#else +#error Host endianness not defined +#endif + + if (g.mod_interrupt_from_first) { + // Bit 30,31 tell the moderation method, 0 default, 1 from first packet + *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1 << 30); + } + + /* Check port for UD address vector: */ + *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1); + + /* Enable QoS support if module parameter set */ + if (g.mod_enable_qos) + *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1 << 2); + + /* Enable IPoIB checksumming if we can: */ + if (dev->caps.flags & MLX4_DEV_CAP_FLAG_IPOIB_CSUM) + *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1 << 3); + + /* QPC/EEC/CQC/EQC/RDMARC attributes */ + + MLX4_PUT(inbox, param->qpc_base, INIT_HCA_QPC_BASE_OFFSET); + MLX4_PUT(inbox, param->log_num_qps, INIT_HCA_LOG_QP_OFFSET); + MLX4_PUT(inbox, param->srqc_base, INIT_HCA_SRQC_BASE_OFFSET); + MLX4_PUT(inbox, param->log_num_srqs, INIT_HCA_LOG_SRQ_OFFSET); + MLX4_PUT(inbox, param->cqc_base, INIT_HCA_CQC_BASE_OFFSET); + MLX4_PUT(inbox, param->log_num_cqs, INIT_HCA_LOG_CQ_OFFSET); + MLX4_PUT(inbox, param->altc_base, INIT_HCA_ALTC_BASE_OFFSET); + MLX4_PUT(inbox, param->auxc_base, INIT_HCA_AUXC_BASE_OFFSET); + MLX4_PUT(inbox, param->eqc_base, INIT_HCA_EQC_BASE_OFFSET); + MLX4_PUT(inbox, param->log_num_eqs, INIT_HCA_LOG_EQ_OFFSET); + MLX4_PUT(inbox, param->rdmarc_base, INIT_HCA_RDMARC_BASE_OFFSET); + MLX4_PUT(inbox, param->log_rd_per_qp, INIT_HCA_LOG_RD_OFFSET); + + /* multicast attributes */ + + MLX4_PUT(inbox, param->mc_base, INIT_HCA_MC_BASE_OFFSET); + MLX4_PUT(inbox, param->log_mc_entry_sz, INIT_HCA_LOG_MC_ENTRY_SZ_OFFSET); + MLX4_PUT(inbox, param->log_mc_hash_sz, INIT_HCA_LOG_MC_HASH_SZ_OFFSET); + MLX4_PUT(inbox, param->log_mc_table_sz, INIT_HCA_LOG_MC_TABLE_SZ_OFFSET); + + /* TPT attributes */ + + MLX4_PUT(inbox, param->dmpt_base, INIT_HCA_DMPT_BASE_OFFSET); + MLX4_PUT(inbox, param->log_mpt_sz, INIT_HCA_LOG_MPT_SZ_OFFSET); + MLX4_PUT(inbox, param->mtt_base, INIT_HCA_MTT_BASE_OFFSET); + MLX4_PUT(inbox, param->cmpt_base, INIT_HCA_CMPT_BASE_OFFSET); + + /* UAR attributes */ + + MLX4_PUT(inbox, uar_page_sz, INIT_HCA_UAR_PAGE_SZ_OFFSET); + MLX4_PUT(inbox, param->log_uar_sz, INIT_HCA_LOG_UAR_SZ_OFFSET); + + err = mlx4_cmd(dev, mailbox->dma.da, 0, 0, MLX4_CMD_INIT_HCA, 10000); + + if (err) + mlx4_err(dev, "INIT_HCA returns %d\n", err); + + mlx4_free_cmd_mailbox(dev, mailbox); + return err; +} + +int mlx4_INIT_PORT(struct mlx4_dev *dev, int port) +{ + struct mlx4_cmd_mailbox *mailbox; + u32 *inbox; + int err; + u32 flags; + u16 field; + + if ( mlx4_is_barred(dev) ) + return -EFAULT; + + if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) { +#define INIT_PORT_IN_SIZE 256 +#define INIT_PORT_FLAGS_OFFSET 0x00 +#define INIT_PORT_FLAG_SIG (1 << 18) +#define INIT_PORT_FLAG_NG (1 << 17) +#define INIT_PORT_FLAG_G0 (1 << 16) +#define INIT_PORT_VL_SHIFT 4 +#define INIT_PORT_PORT_WIDTH_SHIFT 8 +#define INIT_PORT_MTU_OFFSET 0x04 +#define INIT_PORT_MAX_GID_OFFSET 0x06 +#define INIT_PORT_MAX_PKEY_OFFSET 0x0a +#define INIT_PORT_GUID0_OFFSET 0x10 +#define INIT_PORT_NODE_GUID_OFFSET 0x18 +#define INIT_PORT_SI_GUID_OFFSET 0x20 + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + inbox = mailbox->buf; + + memset(inbox, 0, INIT_PORT_IN_SIZE); + + flags = 0; + flags |= (dev->caps.vl_cap[port] & 0xf) << INIT_PORT_VL_SHIFT; + flags |= (dev->caps.port_width_cap[port] & 0xf) << INIT_PORT_PORT_WIDTH_SHIFT; + MLX4_PUT(inbox, flags, INIT_PORT_FLAGS_OFFSET); + + field = (u16)(128 << dev->caps.ib_mtu_cap[port]); + MLX4_PUT(inbox, field, INIT_PORT_MTU_OFFSET); + field = (u16)dev->caps.gid_table_len[port]; + MLX4_PUT(inbox, field, INIT_PORT_MAX_GID_OFFSET); + field = (u16)dev->caps.pkey_table_len[port]; + MLX4_PUT(inbox, field, INIT_PORT_MAX_PKEY_OFFSET); + + err = mlx4_cmd(dev, mailbox->dma.da, port, 0, MLX4_CMD_INIT_PORT, + MLX4_CMD_TIME_CLASS_A); + + mlx4_free_cmd_mailbox(dev, mailbox); + } else + err = mlx4_cmd(dev, 0, port, 0, MLX4_CMD_INIT_PORT, + MLX4_CMD_TIME_CLASS_A); + + return err; +} +EXPORT_SYMBOL_GPL(mlx4_INIT_PORT); + +int mlx4_CLOSE_PORT(struct mlx4_dev *dev, int port) +{ + if ( mlx4_is_barred(dev) ) + return -EFAULT; + + return mlx4_cmd(dev, 0, port, 0, MLX4_CMD_CLOSE_PORT, 1000); +} +EXPORT_SYMBOL_GPL(mlx4_CLOSE_PORT); + +int mlx4_CLOSE_HCA(struct mlx4_dev *dev, int panic) +{ + return mlx4_cmd(dev, 0, 0, (u8)panic, MLX4_CMD_CLOSE_HCA, 1000); +} + +int mlx4_SET_ICM_SIZE(struct mlx4_dev *dev, u64 icm_size, u64 *aux_pages) +{ + int ret = mlx4_cmd_imm(dev, icm_size, aux_pages, 0, 0, + MLX4_CMD_SET_ICM_SIZE, + MLX4_CMD_TIME_CLASS_A); + if (ret) + return ret; + + /* + * Round up number of system pages needed in case + * MLX4_ICM_PAGE_SIZE < PAGE_SIZE. + */ + *aux_pages = ALIGN(*aux_pages, PAGE_SIZE / MLX4_ICM_PAGE_SIZE) >> + (PAGE_SHIFT - MLX4_ICM_PAGE_SHIFT); + + return 0; +} + +int mlx4_NOP(struct mlx4_dev *dev) +{ + /* Input modifier of 0x1f means "finish as soon as possible." */ + return mlx4_cmd(dev, 0, 0x1f, 0, MLX4_CMD_NOP, 100); +} diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/net/fw.h b/branches/WOF2-3/hw/mlx4/kernel/bus/net/fw.h new file mode 100644 index 00000000..bd2be130 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/net/fw.h @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * Copyright (c) 2006, 2007 Cisco Systems. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef MLX4_FW_H +#define MLX4_FW_H + +#include "mlx4.h" +#include "icm.h" + +struct mlx4_dev_cap { + int max_srq_sz; + int max_qp_sz; + int reserved_qps; + int max_qps; + int reserved_srqs; + int max_srqs; + int max_cq_sz; + int reserved_cqs; + int max_cqs; + int max_mpts; + int reserved_eqs; + int max_eqs; + int reserved_mtts; + int max_mrw_sz; + int reserved_mrws; + int max_mtt_seg; + int max_requester_per_qp; + int max_responder_per_qp; + int max_rdma_global; + int local_ca_ack_delay; + int num_ports; + u32 max_msg_sz; + int ib_mtu[MLX4_MAX_PORTS + 1]; + int max_port_width[MLX4_MAX_PORTS + 1]; + int max_vl[MLX4_MAX_PORTS + 1]; + int max_gids[MLX4_MAX_PORTS + 1]; + int max_pkeys[MLX4_MAX_PORTS + 1]; + u64 def_mac[MLX4_MAX_PORTS + 1]; + int eth_mtu[MLX4_MAX_PORTS + 1]; + u16 stat_rate_support; + u32 flags; + int reserved_uars; + int uar_size; + int min_page_sz; + int bf_reg_size; + int bf_regs_per_page; + int max_sq_sg; + int max_sq_desc_sz; + int max_rq_sg; + int max_rq_desc_sz; + int max_qp_per_mcg; + int reserved_mgms; + int max_mcgs; + int reserved_pds; + int max_pds; + int qpc_entry_sz; + int rdmarc_entry_sz; + int altc_entry_sz; + int aux_entry_sz; + int srq_entry_sz; + int cqc_entry_sz; + int eqc_entry_sz; + int dmpt_entry_sz; + int cmpt_entry_sz; + int mtt_entry_sz; + int resize_srq; + u8 bmme_flags; + u32 reserved_lkey; + u64 max_icm_sz; + int max_gso_sz; + u8 supported_port_types[MLX4_MAX_PORTS + 1]; + u8 log_max_macs[MLX4_MAX_PORTS + 1]; + u8 log_max_vlans[MLX4_MAX_PORTS + 1]; + +}; + +struct mlx4_adapter { + char board_id[MLX4_BOARD_ID_LEN]; + u8 inta_pin; +}; + +struct mlx4_init_hca_param { + u64 qpc_base; + u64 rdmarc_base; + u64 auxc_base; + u64 altc_base; + u64 srqc_base; + u64 cqc_base; + u64 eqc_base; + u64 mc_base; + u64 dmpt_base; + u64 cmpt_base; + u64 mtt_base; + u16 log_mc_entry_sz; + u16 log_mc_hash_sz; + u8 log_num_qps; + u8 log_num_srqs; + u8 log_num_cqs; + u8 log_num_eqs; + u8 log_rd_per_qp; + u8 log_mc_table_sz; + u8 log_mpt_sz; + u8 log_uar_sz; +}; + +struct mlx4_init_ib_param { + int port_width; + int vl_cap; + int mtu_cap; + u16 gid_cap; + u16 pkey_cap; + int set_guid0; + u64 guid0; + int set_node_guid; + u64 node_guid; + int set_si_guid; + u64 si_guid; +}; + +struct mlx4_set_ib_param { + int set_si_guid; + int reset_qkey_viol; + u64 si_guid; + u32 cap_mask; +}; + +int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap); +int mlx4_MAP_FA(struct mlx4_dev *dev, struct mlx4_icm *icm); +int mlx4_UNMAP_FA(struct mlx4_dev *dev); +int mlx4_RUN_FW(struct mlx4_dev *dev); +int mlx4_QUERY_FW(struct mlx4_dev *dev); +int mlx4_port_state(struct mlx4_dev *dev); +int mlx4_QUERY_ADAPTER(struct mlx4_dev *dev, struct mlx4_adapter *adapter); +int mlx4_INIT_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param); +int mlx4_CLOSE_HCA(struct mlx4_dev *dev, int panic); +int mlx4_map_cmd(struct mlx4_dev *dev, u16 op, struct mlx4_icm *icm, u64 virt); +int mlx4_SET_ICM_SIZE(struct mlx4_dev *dev, u64 icm_size, u64 *aux_pages); +int mlx4_MAP_ICM_AUX(struct mlx4_dev *dev, struct mlx4_icm *icm); +int mlx4_UNMAP_ICM_AUX(struct mlx4_dev *dev); +int mlx4_NOP(struct mlx4_dev *dev); + +#endif /* MLX4_FW_H */ diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/net/icm.c b/branches/WOF2-3/hw/mlx4/kernel/bus/net/icm.c new file mode 100644 index 00000000..d0ba8930 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/net/icm.c @@ -0,0 +1,460 @@ +/* + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "mlx4.h" +#include "cmd.h" +#include "icm.h" +#include "fw.h" + +/* + * We allocate in as big chunks as we can, up to a maximum of 256 KB + * per chunk. + */ +enum { + MLX4_ICM_ALLOC_SIZE = 1 << 18, + MLX4_TABLE_CHUNK_SIZE = 1 << 18 +}; + +static void mlx4_free_icm_pages(struct mlx4_dev *dev, struct mlx4_icm_chunk *chunk) +{ + int i; + + if (chunk->nsg > 0) + pci_unmap_sg(dev->pdev, chunk->mem, chunk->npages, + PCI_DMA_BIDIRECTIONAL); + + for (i = 0; i < chunk->npages; ++i) + __free_pages(dev->pdev, sg_page(&chunk->mem[i]), + get_order(chunk->mem[i].dma_addr.sz)); +} + +static void mlx4_free_icm_coherent(struct mlx4_dev *dev, struct mlx4_icm_chunk *chunk) +{ + int i; + + for (i = 0; i < chunk->npages; ++i) + dma_free_coherent(&dev->pdev->dev, chunk->mem[i].dma_addr.sz, + lowmem_page_address(sg_page(&chunk->mem[i])), + sg_dma_addr(&chunk->mem[i])); +} + +void mlx4_free_icm(struct mlx4_dev *dev, struct mlx4_icm *icm, int coherent) +{ + struct mlx4_icm_chunk *chunk, *tmp; + + if (!icm) + return; + + list_for_each_entry_safe(chunk, tmp, &icm->chunk_list, list, struct mlx4_icm_chunk, struct mlx4_icm_chunk) { + if (coherent) + mlx4_free_icm_coherent(dev, chunk); + else + mlx4_free_icm_pages(dev, chunk); + + kfree(chunk); + } + + kfree(icm); +} + +static int mlx4_alloc_icm_pages(struct pci_dev *pdev, + struct scatterlist *mem, int order, gfp_t gfp_mask) +{ + dma_addr_t page; + + page = alloc_pages(pdev, gfp_mask, order); + if (!page.da) + return -ENOMEM; + + sg_set_page(mem, page, PAGE_SIZE << order, 0); + return 0; +} + +static int mlx4_alloc_icm_coherent(struct mlx4_dev **dev, struct scatterlist *mem, + int order, gfp_t gfp_mask) +{ + void *buf = dma_alloc_coherent(dev, PAGE_SIZE << order, + &sg_dma_addr(mem), gfp_mask); + if (!buf) + return -ENOMEM; + + sg_set_buf(mem, buf, PAGE_SIZE << order); + BUG_ON(mem->offset); + sg_dma_len(mem) = PAGE_SIZE << order; + return 0; +} + +struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages, + gfp_t gfp_mask, int coherent) +{ + struct mlx4_icm *icm; + struct mlx4_icm_chunk *chunk = NULL; + int cur_order; + int ret; + + /* We use sg_set_buf for coherent allocs, which assumes low memory */ + BUG_ON(coherent && (gfp_mask & __GFP_HIGHMEM)); + + icm = kmalloc(sizeof *icm, gfp_mask & ~(__GFP_HIGHMEM | __GFP_NOWARN)); + if (!icm) + return NULL; + + icm->refcount = 0; + INIT_LIST_HEAD(&icm->chunk_list); + + cur_order = get_order(MLX4_ICM_ALLOC_SIZE); + + while (npages > 0) { + if (!chunk) { + chunk = kmalloc(sizeof *chunk, + gfp_mask & ~(__GFP_HIGHMEM | __GFP_NOWARN)); + if (!chunk) + goto fail; + + sg_init_table(chunk->mem, MLX4_ICM_CHUNK_LEN); + chunk->npages = 0; + chunk->nsg = 0; + list_add_tail(&chunk->list, &icm->chunk_list); + } + + while (1 << cur_order > npages) + --cur_order; + + if (coherent) + ret = mlx4_alloc_icm_coherent(&dev->pdev->dev, + &chunk->mem[chunk->npages], + cur_order, gfp_mask); + else + ret = mlx4_alloc_icm_pages(dev->pdev, &chunk->mem[chunk->npages], + cur_order, gfp_mask); + + if (!ret) { + ++chunk->npages; + + if (coherent) + ++chunk->nsg; + else if (chunk->npages == MLX4_ICM_CHUNK_LEN) { + chunk->nsg = pci_map_sg(dev->pdev, chunk->mem, + chunk->npages, + PCI_DMA_BIDIRECTIONAL); + + if (chunk->nsg <= 0) + goto fail; + + chunk = NULL; + } + + npages -= 1 << cur_order; + } else { + --cur_order; + if (cur_order < 0) + goto fail; + } + } + + if (!coherent && chunk) { + chunk->nsg = pci_map_sg(dev->pdev, chunk->mem, + chunk->npages, + PCI_DMA_BIDIRECTIONAL); + + if (chunk->nsg <= 0) + goto fail; + } + + return icm; + +fail: + mlx4_free_icm(dev, icm, coherent); + return NULL; +} + +static int mlx4_MAP_ICM(struct mlx4_dev *dev, struct mlx4_icm *icm, u64 virt) +{ + return mlx4_map_cmd(dev, MLX4_CMD_MAP_ICM, icm, virt); +} + +int mlx4_UNMAP_ICM(struct mlx4_dev *dev, u64 virt, u32 page_count) +{ + return mlx4_cmd(dev, virt, page_count, 0, MLX4_CMD_UNMAP_ICM, + MLX4_CMD_TIME_CLASS_B); +} + +int mlx4_MAP_ICM_page(struct mlx4_dev *dev, u64 dma_addr, u64 virt) +{ + struct mlx4_cmd_mailbox *mailbox; + __be64 *inbox; + int err; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + inbox = mailbox->buf; + + inbox[0] = cpu_to_be64(virt); + inbox[1] = cpu_to_be64(dma_addr); + + err = mlx4_cmd(dev, mailbox->dma.da, 1, 0, MLX4_CMD_MAP_ICM, + MLX4_CMD_TIME_CLASS_B); + + mlx4_free_cmd_mailbox(dev, mailbox); + + if (!err) + mlx4_dbg(dev, "Mapped page at %llx to %llx for ICM.\n", + (unsigned long long) dma_addr, (unsigned long long) virt); + + return err; +} + +int mlx4_MAP_ICM_AUX(struct mlx4_dev *dev, struct mlx4_icm *icm) +{ + return mlx4_map_cmd(dev, MLX4_CMD_MAP_ICM_AUX, icm, (u64)-1); +} + +int mlx4_UNMAP_ICM_AUX(struct mlx4_dev *dev) +{ + return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_UNMAP_ICM_AUX, MLX4_CMD_TIME_CLASS_B); +} + +int mlx4_table_get(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj) +{ + int i = (obj & (table->num_obj - 1)) / (MLX4_TABLE_CHUNK_SIZE / table->obj_size); + int ret = 0; + + mutex_lock(&table->mutex); + + if (table->icm[i]) { + ++table->icm[i]->refcount; + goto out; + } + + table->icm[i] = mlx4_alloc_icm(dev, MLX4_TABLE_CHUNK_SIZE >> PAGE_SHIFT, + (table->lowmem ? GFP_KERNEL : GFP_HIGHUSER) | + __GFP_NOWARN, table->coherent); + if (!table->icm[i]) { + ret = -ENOMEM; + goto out; + } + + if (mlx4_MAP_ICM(dev, table->icm[i], table->virt + + (u64) i * MLX4_TABLE_CHUNK_SIZE)) { + mlx4_free_icm(dev, table->icm[i], table->coherent); + table->icm[i] = NULL; + ret = -ENOMEM; + goto out; + } + + ++table->icm[i]->refcount; + +out: + mutex_unlock(&table->mutex); + return ret; +} + +void mlx4_table_put(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj) +{ + int i; + + i = (obj & (table->num_obj - 1)) / (MLX4_TABLE_CHUNK_SIZE / table->obj_size); + + mutex_lock(&table->mutex); + + if (--table->icm[i]->refcount == 0) { + mlx4_UNMAP_ICM(dev, table->virt + i * MLX4_TABLE_CHUNK_SIZE, + MLX4_TABLE_CHUNK_SIZE / MLX4_ICM_PAGE_SIZE); + mlx4_free_icm(dev, table->icm[i], table->coherent); + table->icm[i] = NULL; + } + + mutex_unlock(&table->mutex); +} + +void *mlx4_table_find(struct mlx4_icm_table *table, int obj, dma_addr_t *dma_handle) +{ + int idx, offset, dma_offset, i; + struct mlx4_icm_chunk *chunk; + struct mlx4_icm *icm; + dma_addr_t page = { 0 } ; + + if (!table->lowmem) + return NULL; + + mutex_lock(&table->mutex); + + idx = (obj & (table->num_obj - 1)) * table->obj_size; + icm = table->icm[idx / MLX4_TABLE_CHUNK_SIZE]; + dma_offset = offset = idx % MLX4_TABLE_CHUNK_SIZE; + + if (!icm) + goto out; + + list_for_each_entry(chunk, &icm->chunk_list, list, struct mlx4_icm_chunk) { + for (i = 0; i < chunk->npages; ++i) { + if (dma_handle && dma_offset >= 0) { + if (sg_dma_len(&chunk->mem[i]) > (unsigned)dma_offset) + { + *dma_handle = sg_dma_addr(&chunk->mem[i]); + sg_dma_address_inc(dma_handle,dma_offset); + } + dma_offset -= sg_dma_len(&chunk->mem[i]); + } + /* + * DMA mapping can merge pages but not split them, + * so if we found the page, dma_handle has already + * been assigned to. + */ + if (chunk->mem[i].dma_addr.sz > (unsigned)offset) { + page = sg_page(&chunk->mem[i]); + goto out; + } + offset -= chunk->mem[i].dma_addr.sz; + } + } + +out: + mutex_unlock(&table->mutex); + return page.da ? (u8*)lowmem_page_address(page) + offset : NULL; +} + +int mlx4_table_get_range(struct mlx4_dev *dev, struct mlx4_icm_table *table, + int start, int end) +{ + int inc = MLX4_TABLE_CHUNK_SIZE / table->obj_size; + int i, err; + + for (i = start; i <= end; i += inc) { + err = mlx4_table_get(dev, table, i); + if (err) + goto fail; + } + + return 0; + +fail: + while (i > start) { + i -= inc; + mlx4_table_put(dev, table, i); + } + + return err; +} + +void mlx4_table_put_range(struct mlx4_dev *dev, struct mlx4_icm_table *table, + int start, int end) +{ + int i; + + for (i = start; i <= end; i += MLX4_TABLE_CHUNK_SIZE / table->obj_size) + mlx4_table_put(dev, table, i); +} + +int mlx4_init_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table, + u64 virt, int obj_size, int nobj, int reserved, + int use_lowmem, int use_coherent) +{ + int obj_per_chunk; + int num_icm; + unsigned chunk_size; + int i; + + obj_per_chunk = MLX4_TABLE_CHUNK_SIZE / obj_size; + num_icm = (nobj + obj_per_chunk - 1) / obj_per_chunk; + + table->icm = kcalloc(num_icm, sizeof *table->icm, GFP_KERNEL); + if (!table->icm) + return -ENOMEM; + table->virt = virt; + table->num_icm = num_icm; + table->num_obj = nobj; + table->obj_size = obj_size; + table->lowmem = use_lowmem; + table->coherent = use_coherent; + mutex_init(&table->mutex); + + for (i = 0; i * MLX4_TABLE_CHUNK_SIZE < reserved * obj_size; ++i) { + chunk_size = MLX4_TABLE_CHUNK_SIZE; + if ((i + 1) * MLX4_TABLE_CHUNK_SIZE > nobj * obj_size) + chunk_size = (unsigned)NEXT_PAGE_ALIGN(nobj * obj_size - i * MLX4_TABLE_CHUNK_SIZE); + + table->icm[i] = mlx4_alloc_icm(dev, chunk_size >> PAGE_SHIFT, + (use_lowmem ? GFP_KERNEL : GFP_HIGHUSER) | + __GFP_NOWARN, use_coherent); + if (!table->icm[i]) + goto err; + if (mlx4_MAP_ICM(dev, table->icm[i], virt + i * MLX4_TABLE_CHUNK_SIZE)) { + mlx4_free_icm(dev, table->icm[i], use_coherent); + table->icm[i] = NULL; + goto err; + } + + /* + * Add a reference to this ICM chunk so that it never + * gets freed (since it contains reserved firmware objects). + */ + ++table->icm[i]->refcount; + } + + return 0; + +err: + for (i = 0; i < num_icm; ++i) { + if (table->icm[i]) { + mlx4_UNMAP_ICM(dev, virt + i * MLX4_TABLE_CHUNK_SIZE, + MLX4_TABLE_CHUNK_SIZE / MLX4_ICM_PAGE_SIZE); + mlx4_free_icm(dev, table->icm[i], use_coherent); + } + } + + kfree(table->icm); + table->icm = NULL; + return -ENOMEM; +} + +void mlx4_cleanup_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table) +{ + int i; + + if (table->icm == NULL) { + return; + } + + for (i = 0; i < table->num_icm; ++i) + if (table->icm[i]) { + mlx4_UNMAP_ICM(dev, table->virt + i * MLX4_TABLE_CHUNK_SIZE, + MLX4_TABLE_CHUNK_SIZE / MLX4_ICM_PAGE_SIZE); + mlx4_free_icm(dev, table->icm[i], table->coherent); + table->icm[i] = NULL; + } + + kfree(table->icm); + table->icm = NULL; +} diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/net/icm.h b/branches/WOF2-3/hw/mlx4/kernel/bus/net/icm.h new file mode 100644 index 00000000..008138fb --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/net/icm.h @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef MLX4_ICM_H +#define MLX4_ICM_H + +#define MLX4_ICM_CHUNK_LEN \ + ((256 - sizeof (struct list_head) - 2 * sizeof (int)) / \ + (sizeof (struct scatterlist))) + +enum { + MLX4_ICM_PAGE_SHIFT = 12, + MLX4_ICM_PAGE_SIZE = 1 << MLX4_ICM_PAGE_SHIFT, +}; + +struct mlx4_icm_chunk { + struct list_head list; + int npages; + int nsg; + struct scatterlist mem[MLX4_ICM_CHUNK_LEN]; +}; + +struct mlx4_icm { + struct list_head chunk_list; + int refcount; +}; + +struct mlx4_icm_iter { + struct mlx4_icm *icm; + struct mlx4_icm_chunk *chunk; + int page_idx; +}; + +struct mlx4_dev; + +struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages, + gfp_t gfp_mask, int coherent); +void mlx4_free_icm(struct mlx4_dev *dev, struct mlx4_icm *icm, int coherent); + +int mlx4_table_get(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj); +void mlx4_table_put(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj); +int mlx4_table_get_range(struct mlx4_dev *dev, struct mlx4_icm_table *table, + int start, int end); +void mlx4_table_put_range(struct mlx4_dev *dev, struct mlx4_icm_table *table, + int start, int end); +int mlx4_init_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table, + u64 virt, int obj_size, int nobj, int reserved, + int use_lowmem, int use_coherent); +void mlx4_cleanup_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table); +int mlx4_table_get(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj); +void mlx4_table_put(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj); +void *mlx4_table_find(struct mlx4_icm_table *table, int obj, dma_addr_t *dma_handle); +int mlx4_table_get_range(struct mlx4_dev *dev, struct mlx4_icm_table *table, + int start, int end); +void mlx4_table_put_range(struct mlx4_dev *dev, struct mlx4_icm_table *table, + int start, int end); + +static inline void mlx4_icm_first(struct mlx4_icm *icm, + struct mlx4_icm_iter *iter) +{ + iter->icm = icm; + iter->chunk = list_empty(&icm->chunk_list) ? + NULL : list_entry(icm->chunk_list.Flink, + struct mlx4_icm_chunk, list); + iter->page_idx = 0; +} + +static inline int mlx4_icm_last(struct mlx4_icm_iter *iter) +{ + return !iter->chunk; +} + +static inline void mlx4_icm_next(struct mlx4_icm_iter *iter) +{ + if (++iter->page_idx >= iter->chunk->nsg) { + if (iter->chunk->list.Flink == &iter->icm->chunk_list) { + iter->chunk = NULL; + return; + } + + iter->chunk = list_entry(iter->chunk->list.Flink, + struct mlx4_icm_chunk, list); + iter->page_idx = 0; + } +} + +static inline dma_addr_t mlx4_icm_addr(struct mlx4_icm_iter *iter) +{ + return sg_dma_addr(&iter->chunk->mem[iter->page_idx]); +} + +static inline unsigned long mlx4_icm_size(struct mlx4_icm_iter *iter) +{ + return sg_dma_len(&iter->chunk->mem[iter->page_idx]); +} + +int mlx4_UNMAP_ICM(struct mlx4_dev *dev, u64 virt, u32 page_count); +int mlx4_MAP_ICM_page(struct mlx4_dev *dev, u64 dma_addr, u64 virt); +int mlx4_MAP_ICM_AUX(struct mlx4_dev *dev, struct mlx4_icm *icm); +int mlx4_UNMAP_ICM_AUX(struct mlx4_dev *dev); + +#endif /* MLX4_ICM_H */ diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/net/intf.c b/branches/WOF2-3/hw/mlx4/kernel/bus/net/intf.c new file mode 100644 index 00000000..1a1b604a --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/net/intf.c @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "mlx4.h" +#include "driver.h" + +struct mlx4_device_context { + struct list_head list; + struct mlx4_interface *intf; + void *context; +}; + +static LIST_HEAD(intf_list); +static LIST_HEAD(dev_list); +static DEFINE_MUTEX(intf_mutex); + +static int mlx4_add_device(struct mlx4_interface *intf, struct mlx4_priv *priv) +{ + struct mlx4_device_context *dev_ctx; + + dev_ctx = kmalloc(sizeof *dev_ctx, GFP_KERNEL); + if (!dev_ctx) + return -EFAULT; + + dev_ctx->intf = intf; + dev_ctx->context = intf->add(&priv->dev); + priv->dev.pdev->ib_dev = dev_ctx->context; + + if (dev_ctx->context) { + spin_lock_irq(&priv->ctx_lock); + list_add_tail(&dev_ctx->list, &priv->ctx_list); + spin_unlock_irq(&priv->ctx_lock); + } else { + kfree(dev_ctx); + return -EFAULT; + } + return 0; +} + +static void mlx4_remove_device(struct mlx4_interface *intf, struct mlx4_priv *priv) +{ + struct mlx4_device_context *dev_ctx; + + list_for_each_entry(dev_ctx, &priv->ctx_list, list, struct mlx4_device_context) + if (dev_ctx->intf == intf) { + spin_lock_irq(&priv->ctx_lock); + list_del(&dev_ctx->list); + spin_unlock_irq(&priv->ctx_lock); + + intf->remove(&priv->dev, dev_ctx->context); + kfree(dev_ctx); + return; + } +} + +int mlx4_register_interface(struct mlx4_interface *intf) +{ + struct mlx4_priv *priv; + int err = 0; + + if (!intf->add || !intf->remove) + return -EINVAL; + + mutex_lock(&intf_mutex); + + list_for_each_entry(priv, &dev_list, dev_list, struct mlx4_priv) { + if (mlx4_add_device(intf, priv)) { + err = -EFAULT; + goto end; + } + } + + list_add_tail(&intf->list, &intf_list); + +end: + mutex_unlock(&intf_mutex); + return err; +} +EXPORT_SYMBOL_GPL(mlx4_register_interface); + +void mlx4_unregister_interface(struct mlx4_interface *intf) +{ + struct mlx4_priv *priv; + + mutex_lock(&intf_mutex); + + list_for_each_entry(priv, &dev_list, dev_list, struct mlx4_priv) + mlx4_remove_device(intf, priv); + + list_del(&intf->list); + + mutex_unlock(&intf_mutex); +} +EXPORT_SYMBOL_GPL(mlx4_unregister_interface); + +void mlx4_dispatch_event(struct mlx4_dev *dev, enum mlx4_event type, + int subtype, int port) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_device_context *dev_ctx; + + spin_lock(&priv->ctx_lock); + + list_for_each_entry(dev_ctx, &priv->ctx_list, list, struct mlx4_device_context) + if (dev_ctx->intf->event) + dev_ctx->intf->event(dev, dev_ctx->context, type, + subtype, port); + + spin_unlock(&priv->ctx_lock); +} + +int mlx4_register_device(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_interface *intf; + int err = 0; + + mutex_lock(&intf_mutex); + + list_for_each_entry(intf, &intf_list, list, struct mlx4_interface) { + if (mlx4_add_device(intf, priv)) { + err = -EFAULT; + goto end; + } + } + + list_add_tail(&priv->dev_list, &dev_list); + +end: + mutex_unlock(&intf_mutex); + if (!err && !mlx4_is_livefish(dev)) + err = mlx4_start_catas_poll(dev); + + return err; +} + +void mlx4_unregister_device(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_interface *intf; + + if (!mlx4_is_livefish(dev)) + mlx4_stop_catas_poll(dev); + mutex_lock(&intf_mutex); + + list_for_each_entry(intf, &intf_list, list, struct mlx4_interface) + mlx4_remove_device(intf, priv); + + list_del(&priv->dev_list); + + mutex_unlock(&intf_mutex); +} + +void mlx4_intf_init() +{ + mutex_init(&intf_mutex); +} diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/net/main.c b/branches/WOF2-3/hw/mlx4/kernel/bus/net/main.c new file mode 100644 index 00000000..54fd42c6 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/net/main.c @@ -0,0 +1,1162 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + +#include "mlx4.h" +#include "fw.h" +#include "icm.h" +#include "device.h" +#include "doorbell.h" +#include "complib\cl_thread.h" +#include + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "main.tmh" +#endif + + +static struct mlx4_profile default_profile = { + 1 << 17, /* num_qp */ + 1 << 4, /* rdmarc_per_qp */ + 1 << 16, /* num_srq */ + 1 << 16, /* num_cq */ + 1 << 13, /* num_mcg */ + 1 << 18, /* num_mpt */ + 1 << 20 /* num_mtt */ +}; + +static void process_mod_param_profile(void) +{ + if (g.mod_num_qp) + default_profile.num_qp = 1 << g.mod_num_qp; + + if (g.mod_rdmarc_per_qp) + default_profile.rdmarc_per_qp = 1 << g.mod_rdmarc_per_qp; + + if (g.mod_num_srq) + default_profile.num_srq = 1 << g.mod_num_srq; + + if (g.mod_num_cq) + default_profile.num_cq = 1 << g.mod_num_cq; + + if (g.mod_num_mcg) + default_profile.num_mcg = 1 << g.mod_num_mcg; + + if (g.mod_num_mpt) + default_profile.num_mpt = 1 << g.mod_num_mpt; + + if (g.mod_num_mtt) + default_profile.num_mtt = 1 << g.mod_num_mtt; +} + +static struct pci_device_id +mlx4_pci_table[] = { + HCA(MELLANOX, SDR, HERMON), + HCA(MELLANOX, DDR, HERMON), + HCA(MELLANOX, DDR_G2, HERMON), + HCA(MELLANOX, DDR_G2_A, HERMON), + HCA(MELLANOX, QDR_G2, HERMON), + HCA(MELLANOX, QDR_G2_A, HERMON), + HCA(MELLANOX, ETH, HERMON), + HCA(MELLANOX, ETH_YATIR, HERMON), + HCA(MELLANOX, ETH_G2, HERMON), + HCA(MELLANOX, ETH_YATIR_G2, HERMON), + HCA(MELLANOX, ETH_B0_G2, HERMON), + HCA(MELLANOX, ETH_B0_40Gb_G2, HERMON), + HCA(MELLANOX, BD, LIVEFISH), +}; +#define MLX4_PCI_TABLE_SIZE (sizeof(mlx4_pci_table)/sizeof(struct pci_device_id)) + + +static int mlx4_check_port_params(struct mlx4_dev *dev, + enum mlx4_port_type *port_type) +{ + if (port_type[0] != port_type[1] && + !(dev->caps.flags & MLX4_DEV_CAP_FLAG_DPDP)) { + mlx4_err(dev, "Only same port types supported " + "on this HCA, aborting.\n"); + return -EINVAL; + } + if ((port_type[0] == MLX4_PORT_TYPE_ETH) && + (port_type[1] == MLX4_PORT_TYPE_IB)) { + mlx4_err(dev, "eth-ib configuration is not supported.\n"); + return -EINVAL; + } + return 0; +} + +static void mlx4_str2port_type(WCHAR **port_str, + enum mlx4_port_type *port_type) +{ + int i; + + for (i = 0; i < MLX4_MAX_PORTS; i++) { + if (!wcscmp(port_str[i], L"eth")) + port_type[i] = MLX4_PORT_TYPE_ETH; + else + port_type[i] = MLX4_PORT_TYPE_IB; + } +} + +int mlx4_count_ib_ports(struct mlx4_dev *dev) +{ + int i; + int count = 0; + + for (i = 0; i < dev->caps.num_ports; i++) { + if (dev->caps.port_type[i+1] == MLX4_PORT_TYPE_IB) { + count++; + } + } + return count; +} + +BOOLEAN mlx4_is_eth_port(struct mlx4_dev *dev, int port_number) +{ + if (dev->caps.port_type[port_number] == MLX4_PORT_TYPE_ETH) { + return TRUE; + } + return FALSE; +} + +BOOLEAN mlx4_is_ib_port(struct mlx4_dev *dev, int port_number) +{ + if (dev->caps.port_type[port_number] == MLX4_PORT_TYPE_IB){ + return TRUE; + } + return FALSE; +} + +BOOLEAN mlx4_is_enabled_port(struct mlx4_dev *dev, int port_number) +{ + if (dev->caps.port_state[port_number] == MLX4_PORT_ENABLED) { + return TRUE; + } + return FALSE; +} + +static void mlx4_set_port_mask(struct mlx4_dev *dev) +{ + int i; + + dev->caps.port_mask = 0; + for (i = 1; i <= dev->caps.num_ports; ++i) + if (dev->caps.port_type[i] == MLX4_PORT_TYPE_IB) + dev->caps.port_mask |= 1 << (i - 1); +} + +static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) +{ + int err; + int i; + int num_eth_ports = 0; + enum mlx4_port_type port_type[MLX4_MAX_PORTS]; + struct mlx4_dev *mdev = dev; + + for (i = 0; i < MLX4_MAX_PORTS; i++) + port_type[i] = dev->dev_params.mod_port_type[i]; + + err = mlx4_QUERY_DEV_CAP(dev, dev_cap); + if (err) { + mlx4_err(dev, "QUERY_DEV_CAP command failed, aborting.\n"); + return err; + } + + if (dev_cap->min_page_sz > PAGE_SIZE) { + mlx4_err(dev, "HCA minimum page size of %d bigger than " + "kernel PAGE_SIZE of %ld, aborting.\n", + dev_cap->min_page_sz, PAGE_SIZE); + return -ENODEV; + } + if (dev_cap->num_ports > MLX4_MAX_PORTS) { + mlx4_err(dev, "HCA has %d ports, but we only support %d, " + "aborting.\n", + dev_cap->num_ports, MLX4_MAX_PORTS); + return -ENODEV; + } + + if (dev_cap->uar_size > (int)pci_resource_len(dev->pdev, 2)) { + mlx4_err(dev, "HCA reported UAR size of 0x%x bigger than " + "PCI resource 2 size of 0x%llx, aborting.\n", + dev_cap->uar_size, + (unsigned long long) pci_resource_len(dev->pdev, 2)); + return -ENODEV; + } + + dev->caps.num_ports = dev_cap->num_ports; + for (i = 1; i <= dev->caps.num_ports; ++i) { + dev->caps.vl_cap[i] = dev_cap->max_vl[i]; + dev->caps.ib_mtu_cap[i] = dev_cap->ib_mtu[i]; + dev->caps.gid_table_len[i] = dev_cap->max_gids[i]; + dev->caps.pkey_table_len[i] = dev_cap->max_pkeys[i]; + dev->caps.port_width_cap[i] = (u8)dev_cap->max_port_width[i]; + dev->caps.eth_mtu_cap[i] = dev_cap->eth_mtu[i]; + dev->caps.def_mac[i] = dev_cap->def_mac[i]; + } + + dev->caps.num_uars = dev_cap->uar_size / PAGE_SIZE; + dev->caps.local_ca_ack_delay = dev_cap->local_ca_ack_delay; + dev->caps.bf_reg_size = dev_cap->bf_reg_size; + dev->caps.bf_regs_per_page = dev_cap->bf_regs_per_page; + dev->caps.max_sq_sg = dev_cap->max_sq_sg; + dev->caps.max_rq_sg = dev_cap->max_rq_sg; + dev->caps.max_wqes = dev_cap->max_qp_sz; + dev->caps.max_qp_init_rdma = dev_cap->max_requester_per_qp; + dev->caps.max_srq_wqes = dev_cap->max_srq_sz; + dev->caps.max_srq_sge = dev_cap->max_rq_sg - 1; + dev->caps.reserved_srqs = dev_cap->reserved_srqs; + dev->caps.max_sq_desc_sz = dev_cap->max_sq_desc_sz; + dev->caps.max_rq_desc_sz = dev_cap->max_rq_desc_sz; + dev->caps.num_qp_per_mgm = MLX4_QP_PER_MGM; + /* + * Subtract 1 from the limit because we need to allocate a + * spare CQE so the HCA HW can tell the difference between an + * empty CQ and a full CQ. + */ + dev->caps.max_cqes = dev_cap->max_cq_sz - 1; + dev->caps.reserved_cqs = dev_cap->reserved_cqs; + dev->caps.reserved_eqs = dev_cap->reserved_eqs; + dev->caps.reserved_mtts = DIV_ROUND_UP(dev_cap->reserved_mtts, + MLX4_MTT_ENTRY_PER_SEG); + dev->caps.reserved_mrws = dev_cap->reserved_mrws; + dev->caps.reserved_uars = dev_cap->reserved_uars; + dev->caps.reserved_pds = dev_cap->reserved_pds; + dev->caps.mtt_entry_sz = MLX4_MTT_ENTRY_PER_SEG * dev_cap->mtt_entry_sz; + dev->caps.max_msg_sz = dev_cap->max_msg_sz; + dev->caps.page_size_cap = ~(u32) (dev_cap->min_page_sz - 1); + dev->caps.flags = dev_cap->flags; + dev->caps.stat_rate_support = dev_cap->stat_rate_support; + dev->caps.max_gso_sz = dev_cap->max_gso_sz; + + dev->caps.log_num_macs = ilog2(roundup_pow_of_two + (g.mod_num_mac + 1)); + dev->caps.log_num_vlans = ilog2(roundup_pow_of_two + (g.mod_num_vlan + 2)); + dev->caps.log_num_prios = (g.mod_use_prio)? 3: 0; + dev->caps.num_fc_exch = g.mod_num_fc_exch; + + err = mlx4_check_port_params(dev, port_type); + if (err) + return err; + + for (i = 1; i <= dev->caps.num_ports; ++i) { + if (!dev_cap->supported_port_types[i]) { + mlx4_warn(dev, "FW doesn't support Multi Protocol, " + "loading IB only\n"); + dev->caps.port_type[i] = MLX4_PORT_TYPE_IB; + continue; + } + if (port_type[i-1] & dev_cap->supported_port_types[i]) + dev->caps.port_type[i] = port_type[i-1]; + else { + if (dev_cap->supported_port_types[i] & MLX4_PORT_TYPE_IB) + dev->caps.port_type[i] = MLX4_PORT_TYPE_IB; + else + dev->caps.port_type[i] = MLX4_PORT_TYPE_ETH; + + MLX4_PRINT_EV(TRACE_LEVEL_WARNING,MLX4_DBG_DRV , + ("Port %d: Unsupported requested port type %#x. We'll use #%x from supported %#x! \n", + i, port_type[i-1], dev->caps.port_type[i], + (int)dev_cap->supported_port_types[i])); + + MLX4_PRINT_EV(TRACE_LEVEL_WARNING ,MLX4_DBG_DRV , + ("Ven %x Dev %d Fw %d.%d.%d, IsBurnDevice %s\n", + (unsigned)dev->pdev->ven_id, (unsigned)dev->pdev->dev_id, + (int) (dev->caps.fw_ver >> 32), + (int) (dev->caps.fw_ver >> 16) & 0xffff, + (int) (dev->caps.fw_ver & 0xffff), + mlx4_is_livefish(dev) ? "Y" : "N" + )); + } + if (dev->caps.log_num_macs > dev_cap->log_max_macs[i]) { + dev->caps.log_num_macs = dev_cap->log_max_macs[i]; + mlx4_warn(dev, "Requested number of MACs is too much " + "for port %d, reducing to %d.\n", + i, 1 << dev->caps.log_num_macs); + } + if (dev->caps.log_num_vlans > dev_cap->log_max_vlans[i]) { + dev->caps.log_num_vlans = dev_cap->log_max_vlans[i]; + mlx4_warn(dev, "Requested number of VLANs is too much " + "for port %d, reducing to %d.\n", + i, 1 << dev->caps.log_num_vlans); + } + if (dev->caps.port_type[i] == MLX4_PORT_TYPE_ETH) + ++num_eth_ports; + } + + mlx4_set_port_mask(dev); + + dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW] = dev_cap->reserved_qps; + dev->caps.reserved_qps_cnt[MLX4_QP_REGION_ETH_ADDR] = + dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FC_ADDR] = + (1 << dev->caps.log_num_macs)* + (1 << dev->caps.log_num_vlans)* + (1 << dev->caps.log_num_prios)* + num_eth_ports; + dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FC_EXCH] = dev->caps.num_fc_exch; + + return 0; +} + +static int __devinit mlx4_load_fw(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + int err; + + priv->fw.fw_icm = mlx4_alloc_icm(dev, priv->fw.fw_pages, + GFP_HIGHUSER | __GFP_NOWARN, 0); + if (!priv->fw.fw_icm) { + mlx4_err(dev, "Couldn't allocate FW area, aborting.\n"); + return -ENOMEM; + } + + err = mlx4_MAP_FA(dev, priv->fw.fw_icm); + if (err) { + mlx4_dbg(dev, "MAP_FA command failed, aborting.\n"); + WriteEventLogEntryData( dev->pdev->p_self_do, (ULONG)EVENT_MLX4_ERROR_MAP_FA, 0, 0, 1, + L"%d", err ); + goto err_free; + } + + err = mlx4_RUN_FW(dev); + if (err) { + mlx4_dbg(dev, "RUN_FW command failed, aborting.\n"); + WriteEventLogEntryData( dev->pdev->p_self_do, (ULONG)EVENT_MLX4_ERROR_RUN_FW, 0, 0, 1, + L"%d", err ); + goto err_unmap_fa; + } + + return 0; + +err_unmap_fa: + mlx4_UNMAP_FA(dev); + +err_free: + mlx4_free_icm(dev, priv->fw.fw_icm, 0); + return err; +} + +static int __devinit mlx4_init_cmpt_table(struct mlx4_dev *dev, u64 cmpt_base, + int cmpt_entry_sz) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + int err; + + err = mlx4_init_icm_table(dev, &priv->qp_table.cmpt_table, + cmpt_base + + ((u64) (MLX4_CMPT_TYPE_QP * + cmpt_entry_sz) << MLX4_CMPT_SHIFT), + cmpt_entry_sz, dev->caps.num_qps, + dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW], + 0, 0); + if (err) + goto err; + + err = mlx4_init_icm_table(dev, &priv->srq_table.cmpt_table, + cmpt_base + + ((u64) (MLX4_CMPT_TYPE_SRQ * + cmpt_entry_sz) << MLX4_CMPT_SHIFT), + cmpt_entry_sz, dev->caps.num_srqs, + dev->caps.reserved_srqs, 0, 0); + if (err) + goto err_qp; + + err = mlx4_init_icm_table(dev, &priv->cq_table.cmpt_table, + cmpt_base + + ((u64) (MLX4_CMPT_TYPE_CQ * + cmpt_entry_sz) << MLX4_CMPT_SHIFT), + cmpt_entry_sz, dev->caps.num_cqs, + dev->caps.reserved_cqs, 0, 0); + if (err) + goto err_srq; + + err = mlx4_init_icm_table(dev, &priv->eq_table.cmpt_table, + cmpt_base + + ((u64) (MLX4_CMPT_TYPE_EQ * + cmpt_entry_sz) << MLX4_CMPT_SHIFT), + cmpt_entry_sz, + roundup_pow_of_two(MLX4_NUM_EQ + + dev->caps.reserved_eqs), + MLX4_NUM_EQ + dev->caps.reserved_eqs, 0, 0); + if (err) + goto err_cq; + + return 0; + +err_cq: + mlx4_cleanup_icm_table(dev, &priv->cq_table.cmpt_table); + +err_srq: + mlx4_cleanup_icm_table(dev, &priv->srq_table.cmpt_table); + +err_qp: + mlx4_cleanup_icm_table(dev, &priv->qp_table.cmpt_table); + +err: + return err; +} + +static int mlx4_init_icm(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap, + struct mlx4_init_hca_param *init_hca, u64 icm_size) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + u64 aux_pages; + int err; + + err = mlx4_SET_ICM_SIZE(dev, icm_size, &aux_pages); + if (err) { + mlx4_err(dev, "SET_ICM_SIZE command failed, aborting.\n"); + return err; + } + + mlx4_dbg(dev, "%lld KB of HCA context requires %lld KB aux memory.\n", + (unsigned long long) icm_size >> 10, + (unsigned long long) aux_pages << 2); + + priv->fw.aux_icm = mlx4_alloc_icm(dev, (int)aux_pages, + GFP_HIGHUSER | __GFP_NOWARN, 0); + if (!priv->fw.aux_icm) { + mlx4_err(dev, "Couldn't allocate aux memory, aborting.\n"); + return -ENOMEM; + } + + err = mlx4_MAP_ICM_AUX(dev, priv->fw.aux_icm); + if (err) { + mlx4_err(dev, "MAP_ICM_AUX command failed, aborting.\n"); + goto err_free_aux; + } + + err = mlx4_init_cmpt_table(dev, init_hca->cmpt_base, dev_cap->cmpt_entry_sz); + if (err) { + mlx4_err(dev, "Failed to map cMPT context memory, aborting.\n"); + goto err_unmap_aux; + } + + err = mlx4_init_icm_table(dev, &priv->eq_table.table, + init_hca->eqc_base, dev_cap->eqc_entry_sz, + dev->caps.num_eqs, dev->caps.num_eqs, 0, 0); + if (err) { + mlx4_err(dev, "Failed to map EQ context memory, aborting.\n"); + goto err_unmap_cmpt; + } + + /* + * Reserved MTT entries must be aligned up to a cacheline + * boundary, since the FW will write to them, while the driver + * writes to all other MTT entries. (The variable + * dev->caps.mtt_entry_sz below is really the MTT segment + * size, not the raw entry size) + */ + dev->caps.reserved_mtts = + ALIGN(dev->caps.reserved_mtts * dev->caps.mtt_entry_sz, + dma_get_cache_alignment()) / dev->caps.mtt_entry_sz; + if ( dev->pdev->p_self_do->AlignmentRequirement + 1 != dma_get_cache_alignment()) { + mlx4_dbg(dev, "Cache-line size %d, recommended value %d.\n", + dev->pdev->p_self_do->AlignmentRequirement + 1, + dma_get_cache_alignment() ); + } + + err = mlx4_init_icm_table(dev, &priv->mr_table.mtt_table, + init_hca->mtt_base, + dev->caps.mtt_entry_sz, + dev->caps.num_mtt_segs, + dev->caps.reserved_mtts, 1, 0); + if (err) { + mlx4_err(dev, "Failed to map MTT context memory, aborting.\n"); + goto err_unmap_eq; + } + + err = mlx4_init_icm_table(dev, &priv->mr_table.dmpt_table, + init_hca->dmpt_base, + dev_cap->dmpt_entry_sz, + dev->caps.num_mpts, + dev->caps.reserved_mrws, 1, 1); + if (err) { + mlx4_err(dev, "Failed to map dMPT context memory, aborting.\n"); + goto err_unmap_mtt; + } + + err = mlx4_init_icm_table(dev, &priv->qp_table.qp_table, + init_hca->qpc_base, + dev_cap->qpc_entry_sz, + dev->caps.num_qps, + dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW], + 0, 0); + if (err) { + mlx4_err(dev, "Failed to map QP context memory, aborting.\n"); + goto err_unmap_dmpt; + } + + err = mlx4_init_icm_table(dev, &priv->qp_table.auxc_table, + init_hca->auxc_base, + dev_cap->aux_entry_sz, + dev->caps.num_qps, + dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW], + 0, 0); + if (err) { + mlx4_err(dev, "Failed to map AUXC context memory, aborting.\n"); + goto err_unmap_qp; + } + + err = mlx4_init_icm_table(dev, &priv->qp_table.altc_table, + init_hca->altc_base, + dev_cap->altc_entry_sz, + dev->caps.num_qps, + dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW], + 0, 0); + if (err) { + mlx4_err(dev, "Failed to map ALTC context memory, aborting.\n"); + goto err_unmap_auxc; + } + + err = mlx4_init_icm_table(dev, &priv->qp_table.rdmarc_table, + init_hca->rdmarc_base, + dev_cap->rdmarc_entry_sz << priv->qp_table.rdmarc_shift, + dev->caps.num_qps, + dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW], + 0, 0); + if (err) { + mlx4_err(dev, "Failed to map RDMARC context memory, aborting\n"); + goto err_unmap_altc; + } + + err = mlx4_init_icm_table(dev, &priv->cq_table.table, + init_hca->cqc_base, + dev_cap->cqc_entry_sz, + dev->caps.num_cqs, + dev->caps.reserved_cqs, 0, 0); + if (err) { + mlx4_err(dev, "Failed to map CQ context memory, aborting.\n"); + goto err_unmap_rdmarc; + } + + err = mlx4_init_icm_table(dev, &priv->srq_table.table, + init_hca->srqc_base, + dev_cap->srq_entry_sz, + dev->caps.num_srqs, + dev->caps.reserved_srqs, 0, 0); + if (err) { + mlx4_err(dev, "Failed to map SRQ context memory, aborting.\n"); + goto err_unmap_cq; + } + + /* + * It's not strictly required, but for simplicity just map the + * whole multicast group table now. The table isn't very big + * and it's a lot easier than trying to track ref counts. + */ + err = mlx4_init_icm_table(dev, &priv->mcg_table.table, + init_hca->mc_base, MLX4_MGM_ENTRY_SIZE, + dev->caps.num_mgms + dev->caps.num_amgms, + dev->caps.num_mgms + dev->caps.num_amgms, + 0, 0); + if (err) { + mlx4_err(dev, "Failed to map MCG context memory, aborting.\n"); + goto err_unmap_srq; + } + + return 0; + +err_unmap_srq: + mlx4_cleanup_icm_table(dev, &priv->srq_table.table); + +err_unmap_cq: + mlx4_cleanup_icm_table(dev, &priv->cq_table.table); + +err_unmap_rdmarc: + mlx4_cleanup_icm_table(dev, &priv->qp_table.rdmarc_table); + +err_unmap_altc: + mlx4_cleanup_icm_table(dev, &priv->qp_table.altc_table); + +err_unmap_auxc: + mlx4_cleanup_icm_table(dev, &priv->qp_table.auxc_table); + +err_unmap_qp: + mlx4_cleanup_icm_table(dev, &priv->qp_table.qp_table); + +err_unmap_dmpt: + mlx4_cleanup_icm_table(dev, &priv->mr_table.dmpt_table); + +err_unmap_mtt: + mlx4_cleanup_icm_table(dev, &priv->mr_table.mtt_table); + +err_unmap_eq: + mlx4_cleanup_icm_table(dev, &priv->eq_table.table); + +err_unmap_cmpt: + mlx4_cleanup_icm_table(dev, &priv->eq_table.cmpt_table); + mlx4_cleanup_icm_table(dev, &priv->cq_table.cmpt_table); + mlx4_cleanup_icm_table(dev, &priv->srq_table.cmpt_table); + mlx4_cleanup_icm_table(dev, &priv->qp_table.cmpt_table); + +err_unmap_aux: + mlx4_UNMAP_ICM_AUX(dev); + +err_free_aux: + mlx4_free_icm(dev, priv->fw.aux_icm, 0); + + return err; +} + +static void mlx4_free_icms(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + + mlx4_cleanup_icm_table(dev, &priv->mcg_table.table); + mlx4_cleanup_icm_table(dev, &priv->srq_table.table); + mlx4_cleanup_icm_table(dev, &priv->cq_table.table); + mlx4_cleanup_icm_table(dev, &priv->qp_table.rdmarc_table); + mlx4_cleanup_icm_table(dev, &priv->qp_table.altc_table); + mlx4_cleanup_icm_table(dev, &priv->qp_table.auxc_table); + mlx4_cleanup_icm_table(dev, &priv->qp_table.qp_table); + mlx4_cleanup_icm_table(dev, &priv->mr_table.dmpt_table); + mlx4_cleanup_icm_table(dev, &priv->mr_table.mtt_table); + mlx4_cleanup_icm_table(dev, &priv->eq_table.table); + mlx4_cleanup_icm_table(dev, &priv->eq_table.cmpt_table); + mlx4_cleanup_icm_table(dev, &priv->cq_table.cmpt_table); + mlx4_cleanup_icm_table(dev, &priv->srq_table.cmpt_table); + mlx4_cleanup_icm_table(dev, &priv->qp_table.cmpt_table); + + mlx4_UNMAP_ICM_AUX(dev); + mlx4_free_icm(dev, priv->fw.aux_icm, 0); + priv->fw.aux_icm = NULL; +} + +static void mlx4_close_hca(struct mlx4_dev *dev) +{ + mlx4_CLOSE_HCA(dev, 0); + mlx4_free_icms(dev); + mlx4_UNMAP_FA(dev); + mlx4_free_icm(dev, mlx4_priv(dev)->fw.fw_icm, 0); +} + +static int mlx4_init_hca(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_adapter adapter; + struct mlx4_dev_cap dev_cap; + struct mlx4_profile profile; + struct mlx4_init_hca_param init_hca; + u64 icm_size; + int err; + + err = mlx4_QUERY_FW(dev); + if (err) { + if (err == -EACCES) { + static int print_it = 1; + if (print_it-- > 0) { + mlx4_info(dev, "Function disabled, please upgrade to multi function driver.\n"); + WriteEventLogEntryData( dev->pdev->p_self_do, (ULONG)EVENT_MLX4_WARN_QUERY_FW, 0, 0, 0 ); + } + } + else { + mlx4_dbg(dev, "QUERY_FW command failed, aborting.\n"); + WriteEventLogEntryData( dev->pdev->p_self_do, (ULONG)EVENT_MLX4_ERROR_QUERY_FW, 0, 0, 1, + L"%d", err ); + } + return err; + } + + err = mlx4_load_fw(dev); + if (err) { + mlx4_dbg(dev, "Failed to start FW, aborting.\n"); + return err; + } + + err = mlx4_dev_cap(dev, &dev_cap); + if (err) { + mlx4_dbg(dev, "QUERY_DEV_CAP command failed, aborting.\n"); + WriteEventLogEntryData( dev->pdev->p_self_do, (ULONG)EVENT_MLX4_ERROR_QUERY_DEV_CAP, 0, 0, 1, + L"%d", err ); + goto err_stop_fw; + } + + // + // Initilize the port state. It's a new command that is supported only in FW 2.6.1280. + //If running on earlier FW version the command can fail. Ignore the error code returned + // + mlx4_port_state(dev); + + process_mod_param_profile(); + profile = default_profile; + + icm_size = mlx4_make_profile(dev, &profile, &dev_cap, &init_hca); + if ((long long) icm_size < 0) { + err = (int)icm_size; + goto err_stop_fw; + } + + init_hca.log_uar_sz = (u8)ilog2(dev->caps.num_uars); + + err = mlx4_init_icm(dev, &dev_cap, &init_hca, icm_size); + if (err) + goto err_stop_fw; + + err = mlx4_INIT_HCA(dev, &init_hca); + if (err) { + mlx4_err(dev, "INIT_HCA command failed, aborting.\n"); + goto err_free_icm; + } + + err = mlx4_QUERY_ADAPTER(dev, &adapter); + if (err) { + mlx4_err(dev, "QUERY_ADAPTER command failed, aborting.\n"); + WriteEventLogEntryData( dev->pdev->p_self_do, (ULONG)EVENT_MLX4_ERROR_QUERY_ADAPTER, 0, 0, 1, + L"%d", err ); + goto err_close; + } + + priv->eq_table.inta_pin = adapter.inta_pin; + memcpy(dev->board_id, adapter.board_id, sizeof dev->board_id); + + return 0; + +err_close: + mlx4_CLOSE_HCA(dev,0); + +err_free_icm: + mlx4_free_icms(dev); + +err_stop_fw: + mlx4_UNMAP_FA(dev); + mlx4_free_icm(dev, priv->fw.fw_icm, 0); + + return err; +} + +static int mlx4_setup_hca(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + int err; + u8 port; + + err = mlx4_init_uar_table(dev); + if (err) { + mlx4_err(dev, "Failed to initialize " + "user access region table, aborting.\n"); + return err; + } + + err = mlx4_uar_alloc(dev, &priv->driver_uar); + if (err) { + mlx4_err(dev, "Failed to allocate driver access region, " + "aborting.\n"); + goto err_uar_table_free; + } + + priv->kar = ioremap((u64)priv->driver_uar.pfn << PAGE_SHIFT, PAGE_SIZE); + if (!priv->kar) { + mlx4_err(dev, "Couldn't map kernel access region, " + "aborting.\n"); + err = -ENOMEM; + goto err_uar_free; + } + + err = mlx4_init_pd_table(dev); + if (err) { + mlx4_err(dev, "Failed to initialize " + "protection domain table, aborting.\n"); + goto err_kar_unmap; + } + + err = mlx4_init_mr_table(dev); + if (err) { + mlx4_err(dev, "Failed to initialize " + "memory region table, aborting.\n"); + goto err_pd_table_free; + } + + + err = mlx4_init_eq_table(dev); + if (err) { + mlx4_err(dev, "Failed to initialize " + "event queue table, aborting.\n"); + goto err_mr_table_free; + } + + err = mlx4_cmd_use_events(dev); + if (err) { + mlx4_err(dev, "Failed to switch to event-driven " + "firmware commands, aborting.\n"); + goto err_eq_table_free; + } + + err = mlx4_NOP(dev); + if (err) { + if (dev->flags & MLX4_FLAG_MSI_X) { + mlx4_warn(dev, "NOP command failed to generate MSI-X " + "interrupt IRQ %d.\n", + priv->eq_table.eq[MLX4_EQ_ASYNC].irq); + mlx4_warn(dev, "Trying again without MSI-X.\n"); + } else { + mlx4_err(dev, "NOP command failed to generate interrupt " + "(IRQ %d), aborting.\n", + priv->eq_table.eq[MLX4_EQ_ASYNC].irq); + mlx4_err(dev, "BIOS or ACPI interrupt routing problem?\n"); + } + + goto err_cmd_poll; + } + + mlx4_dbg(dev, "NOP command IRQ test passed\n"); + + err = mlx4_init_cq_table(dev); + if (err) { + mlx4_err(dev, "Failed to initialize " + "completion queue table, aborting.\n"); + goto err_cmd_poll; + } + + err = mlx4_init_srq_table(dev); + if (err) { + mlx4_err(dev, "Failed to initialize " + "shared receive queue table, aborting.\n"); + goto err_cq_table_free; + } + + err = mlx4_init_qp_table(dev); + if (err) { + mlx4_err(dev, "Failed to initialize " + "queue pair table, aborting.\n"); + goto err_srq_table_free; + } + + err = mlx4_init_mcg_table(dev); + if (err) { + mlx4_err(dev, "Failed to initialize " + "multicast group table, aborting.\n"); + goto err_qp_table_free; + } + for (port = 1; port <= dev->caps.num_ports; port++) { + err = mlx4_SET_PORT(dev, port,0 ,0); + if (err) { + mlx4_err(dev, "Failed to set port %d, aborting\n", + port); + goto err_mcg_table_free; + } + } + + for (port = 0; port < dev->caps.num_ports; port++) { + mlx4_init_mac_table(dev, port); + mlx4_init_vlan_table(dev, port); + } + + return 0; +err_mcg_table_free: + mlx4_cleanup_mcg_table(dev); + +err_qp_table_free: + mlx4_cleanup_qp_table(dev); + +err_srq_table_free: + mlx4_cleanup_srq_table(dev); + +err_cq_table_free: + mlx4_cleanup_cq_table(dev); + +err_cmd_poll: + mlx4_cmd_use_polling(dev); + +err_eq_table_free: + mlx4_cleanup_eq_table(dev); + +err_mr_table_free: + mlx4_cleanup_mr_table(dev); + +err_pd_table_free: + mlx4_cleanup_pd_table(dev); + +err_kar_unmap: + iounmap(priv->kar,PAGE_SIZE); + +err_uar_free: + mlx4_uar_free(dev, &priv->driver_uar); + +err_uar_table_free: + mlx4_cleanup_uar_table(dev); + return err; +} + +static void __devinit mlx4_enable_msi_x(struct mlx4_dev *dev) +{ + int n_cpus = num_possible_cpus(); + + /* decide on the mode */ + if (dev->pdev->n_msi_vectors_alloc >= (n_cpus+2)) + dev->flags |= MLX4_FLAG_MSI_X; + + MLX4_PRINT(TRACE_LEVEL_WARNING ,MLX4_DBG_LOW , + ("Interrupt mode '%s', n_vectors %d, n_cpus %d\n", + (dev->flags & MLX4_FLAG_MSI_X) ? "MSI-X" : "Legacy", + dev->pdev->n_msi_vectors_alloc, n_cpus)); + +} + + +static struct pci_device_id * mlx4_find_pci_dev(USHORT ven_id, USHORT dev_id) +{ + struct pci_device_id *p_id = mlx4_pci_table; + int i; + + // find p_id (appropriate line in mlx4_pci_table) + for (i = 0; i < MLX4_PCI_TABLE_SIZE; ++i, ++p_id) { + if (p_id->device == dev_id && p_id->vendor == ven_id) + return p_id; + } + return NULL; +} + + +int mlx4_init_one(struct pci_dev *pdev, struct mlx4_dev_params *dev_params) +{ + struct pci_device_id *id; + struct mlx4_priv *priv; + struct mlx4_dev *dev; + int err; + NTSTATUS status; + int i; + +#ifdef FORCE_LIVEFISH + if (pdev) + goto err; +#endif + + /* we are going to recreate device anyway */ + pdev->dev = NULL; + pdev->ib_dev = NULL; + + /* find the type of device */ + id = mlx4_find_pci_dev(pdev->ven_id, pdev->dev_id); + if (id == NULL) { + err = -ENOSYS; + goto err; + } + + /* + * Check for BARs. We expect 0: 1MB, 2: 8MB, 4: DDR (may not + * be present) + */ + if (pci_resource_len(pdev, 0) != 1 << 20) { + MLX4_PRINT(TRACE_LEVEL_ERROR ,MLX4_DBG_LOW , + ("Missing DCS, aborting.\n")); + err = -ENODEV; + goto err; + } + if (!pci_resource_len(pdev, 1)) { + MLX4_PRINT(TRACE_LEVEL_ERROR ,MLX4_DBG_LOW , + ("Missing UAR, aborting.\n")); + err = -ENODEV; + goto err; + } + +run_as_livefish: + /* allocate mlx4_priv structure */ + priv = kzalloc(sizeof *priv, GFP_KERNEL); + if (!priv) { + MLX4_PRINT(TRACE_LEVEL_INFORMATION ,MLX4_DBG_LOW , + ("Device struct alloc failed, aborting.\n")); + err = -ENOMEM; + goto end; + } + /* must be here for livefish */ + INIT_LIST_HEAD(&priv->ctx_list); + spin_lock_init(&priv->ctx_lock); + + INIT_LIST_HEAD(&priv->pgdir_list); + mutex_init(&priv->pgdir_mutex); + + /* deal with livefish, if any */ + dev = &priv->dev; + dev->signature = MLX4_DEV_SIGNATURE; + dev->pdev = pdev; + pdev->dev = dev; + if (id->driver_data == LIVEFISH) + dev->flags |= MLX4_FLAG_LIVEFISH; + if (mlx4_is_livefish(dev)) { + err = mlx4_register_device(dev); + if (err) { + MLX4_PRINT(TRACE_LEVEL_INFORMATION ,MLX4_DBG_LOW , + ("mlx4_register_device for livefish failed, return with error.\n")); + WriteEventLogEntryData( pdev->p_self_do, (ULONG)EVENT_MLX4_ERROR_LIFEFISH_FAIL, + 0, errno_to_ntstatus(err), 0 ); + pdev->dev = NULL; + kfree(priv); + } + else { + MLX4_PRINT(TRACE_LEVEL_ERROR ,MLX4_DBG_LOW , + ("MLX4_BUS started in \"livefish\" mode !!!.\n")); + WriteEventLogEntryData( pdev->p_self_do, (ULONG)EVENT_MLX4_ERROR_LIFEFISH_OK, + 0, errno_to_ntstatus(err), 0 ); + } + goto end; + } + + for (i = 0; i < MLX4_MAX_PORTS; i++) + dev->dev_params.mod_port_type[i] = dev_params->mod_port_type[i]; + + /* + * Now reset the HCA before we touch the PCI capabilities or + * attempt a firmware command, since a boot ROM may have left + * the HCA in an undefined state. + */ + status = mlx4_reset(dev); + if ( !NT_SUCCESS( status ) ) { + mlx4_err(dev, "Failed to reset HCA, aborting.(status %#x)\n", status); + err = -EFAULT; + goto err_free_dev; + } + + if (mlx4_cmd_init(dev)) { + mlx4_err(dev, "Failed to init command interface, aborting.\n"); + goto err_free_dev; + } + + err = mlx4_init_hca(dev); + if (err) { + if (err == -EACCES) + dev->flags |= MLX4_FLAG_NOT_PRIME; + goto err_cmd; + } + + mlx4_enable_msi_x(dev); + + err = mlx4_setup_hca(dev); + if (err == -EBUSY && (dev->flags & MLX4_FLAG_MSI_X)) { + dev->flags &= ~MLX4_FLAG_MSI_X; + err = mlx4_setup_hca(dev); + } + + if (err) + goto err_close; + + err = mlx4_register_device(dev); + if (err) + goto err_cleanup; + + mlx4_dbg(dev, "MLX4_BUS: NET device (dev_id=%d) is INITIALIZED ! \n", (int)pdev->dev_id); + return 0; + +err_cleanup: + mlx4_cleanup_mcg_table(dev); + mlx4_cleanup_qp_table(dev); + mlx4_cleanup_srq_table(dev); + mlx4_cleanup_cq_table(dev); + mlx4_cmd_use_polling(dev); + mlx4_cleanup_eq_table(dev); + mlx4_cleanup_mr_table(dev); + mlx4_cleanup_pd_table(dev); + mlx4_cleanup_uar_table(dev); + +err_close: + mlx4_close_hca(dev); + +err_cmd: + mlx4_cmd_cleanup(dev); + +err_free_dev: + pdev->dev = NULL; + kfree(priv); + +err: + /* we failed device initialization - try to simulate "livefish" device to facilitate using FW burning tools */ + id = mlx4_find_pci_dev(pdev->ven_id, DEVID_HERMON_BD); + if (id == NULL) { + err = -ENOSYS; + goto end; + } + goto run_as_livefish; + +end: + return err; +} + +void mlx4_remove_one(struct pci_dev *pdev, int reset) +{ + struct mlx4_dev *dev = pdev->dev; + struct mlx4_priv *priv = mlx4_priv(dev); + int p; + + if (dev) { + mlx4_unregister_device(dev); + if (mlx4_is_livefish(dev)) + goto done; + + for (p = 1; p <= dev->caps.num_ports; ++p) + mlx4_CLOSE_PORT(dev, p); + + mlx4_cleanup_mcg_table(dev); + mlx4_cleanup_qp_table(dev); + mlx4_cleanup_srq_table(dev); + mlx4_cleanup_cq_table(dev); + mlx4_cmd_use_polling(dev); + mlx4_cleanup_eq_table(dev); + mlx4_cleanup_mr_table(dev); + mlx4_cleanup_pd_table(dev); + + iounmap(priv->kar,PAGE_SIZE); + mlx4_uar_free(dev, &priv->driver_uar); + mlx4_cleanup_uar_table(dev); + mlx4_close_hca(dev); + mlx4_cmd_cleanup(dev); + + if (reset && mlx4_reset(dev)) + mlx4_err(dev, "Failed to reset HCA\n"); + mlx4_dbg(dev, "MLX4_BUS: NET device (dev_id=%d) is REMOVED ! \n", (int)pdev->dev_id); + pdev->dev = NULL; +done: + kfree(priv); + } +} + +int mlx4_restart_one(struct pci_dev *pdev) +{ + struct mlx4_dev_params dev_params; + mlx4_copy_dev_params(&dev_params, &pdev->dev->dev_params); + + mlx4_remove_one(pdev, FALSE); + return mlx4_init_one(pdev, &dev_params); +} + +void mlx4_net_init() +{ + mlx4_intf_init(); +} + + + diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/net/makefile b/branches/WOF2-3/hw/mlx4/kernel/bus/net/makefile new file mode 100644 index 00000000..d4938551 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/net/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\..\..\inc\openib.def diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/net/mcg.c b/branches/WOF2-3/hw/mlx4/kernel/bus/net/mcg.c new file mode 100644 index 00000000..2f46cd0f --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/net/mcg.c @@ -0,0 +1,380 @@ +/* + * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + +#include "mlx4.h" +#include "cmd.h" + +struct mlx4_mgm { + __be32 next_gid_index; + __be32 members_count; + u32 reserved[2]; + u8 gid[16]; + __be32 qp[MLX4_QP_PER_MGM]; +}; + +static const u8 zero_gid[16] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + +static int mlx4_READ_MCG(struct mlx4_dev *dev, int index, + struct mlx4_cmd_mailbox *mailbox) +{ + return mlx4_cmd_box(dev, 0, mailbox->dma.da, index, 0, MLX4_CMD_READ_MCG, + MLX4_CMD_TIME_CLASS_A); +} + +static int mlx4_WRITE_MCG(struct mlx4_dev *dev, int index, + struct mlx4_cmd_mailbox *mailbox) +{ + return mlx4_cmd(dev, mailbox->dma.da, index, 0, MLX4_CMD_WRITE_MCG, + MLX4_CMD_TIME_CLASS_A); +} + +static int mlx4_MGID_HASH(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, + u16 *hash) +{ + u64 imm; + int err; + + err = mlx4_cmd_imm(dev, mailbox->dma.da, &imm, 0, 0, MLX4_CMD_MGID_HASH, + MLX4_CMD_TIME_CLASS_A); + + if (!err) + *hash = (u16)imm; + + return err; +} + +/* + * Caller must hold MCG table semaphore. gid and mgm parameters must + * be properly aligned for command interface. + * + * Returns 0 unless a firmware command error occurs. + * + * If GID is found in MGM or MGM is empty, *index = *hash, *prev = -1 + * and *mgm holds MGM entry. + * + * if GID is found in AMGM, *index = index in AMGM, *prev = index of + * previous entry in hash chain and *mgm holds AMGM entry. + * + * If no AMGM exists for given gid, *index = -1, *prev = index of last + * entry in hash chain and *mgm holds end of hash chain. + */ +static int find_mgm(struct mlx4_dev *dev, + u8 *gid, struct mlx4_cmd_mailbox *mgm_mailbox, + u16 *hash, int *prev, int *index) +{ + struct mlx4_cmd_mailbox *mailbox; + struct mlx4_mgm *mgm = mgm_mailbox->buf; + u8 *mgid; + int err; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return -ENOMEM; + mgid = mailbox->buf; + + memcpy(mgid, gid, 16); + + err = mlx4_MGID_HASH(dev, mailbox, hash); + mlx4_free_cmd_mailbox(dev, mailbox); + if (err) + return err; + +#if 0 + mlx4_dbg(dev, "Hash for %04x:%04x:%04x:%04x:" + "%04x:%04x:%04x:%04x is %04x\n", + be16_to_cpu(((__be16 *) gid)[0]), + be16_to_cpu(((__be16 *) gid)[1]), + be16_to_cpu(((__be16 *) gid)[2]), + be16_to_cpu(((__be16 *) gid)[3]), + be16_to_cpu(((__be16 *) gid)[4]), + be16_to_cpu(((__be16 *) gid)[5]), + be16_to_cpu(((__be16 *) gid)[6]), + be16_to_cpu(((__be16 *) gid)[7]), + *hash); +#endif + + *index = *hash; + *prev = -1; + + do { + err = mlx4_READ_MCG(dev, *index, mgm_mailbox); + if (err) + return err; + + if (!memcmp(mgm->gid, zero_gid, 16)) { + if (*index != *hash) { + mlx4_err(dev, "Found zero MGID in AMGM.\n"); + err = -EINVAL; + } + return err; + } + + if (!memcmp(mgm->gid, gid, 16)) + return err; + + *prev = *index; + *index = be32_to_cpu(mgm->next_gid_index) >> 6; + } while (*index); + + *index = -1; + return err; +} + +int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16]) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_cmd_mailbox *mailbox; + struct mlx4_mgm *mgm; + u32 members_count; + u16 hash; + int index, prev; + int link = 0; + unsigned i; + int err; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + mgm = mailbox->buf; + + mutex_lock(&priv->mcg_table.mutex); + + err = find_mgm(dev, gid, mailbox, &hash, &prev, &index); + if (err) + goto out; + + if (index != -1) { + if (!memcmp(mgm->gid, zero_gid, 16)) + memcpy(mgm->gid, gid, 16); + } else { + link = 1; + + index = mlx4_bitmap_alloc(&priv->mcg_table.bitmap); + if (index == -1) { + mlx4_err(dev, "No AMGM entries left\n"); + err = -ENOMEM; + goto out; + } + index += dev->caps.num_mgms; + + err = mlx4_READ_MCG(dev, index, mailbox); + if (err) + goto out; + + memset(mgm, 0, sizeof *mgm); + memcpy(mgm->gid, gid, 16); + } + + members_count = be32_to_cpu(mgm->members_count); + if (members_count == MLX4_QP_PER_MGM) { + mlx4_err(dev, "MGM at index %x is full.\n", index); + err = -ENOMEM; + goto out; + } + + for (i = 0; i < members_count; ++i) + if ((int)(be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qp->qpn) { + mlx4_dbg(dev, "QP %06x already a member of MGM\n", qp->qpn); + err = 0; + goto out; + } + + mgm->qp[members_count++] = cpu_to_be32((qp->qpn & MGM_QPN_MASK) | + (!!g.mod_mlx4_blck_lb << MGM_BLCK_LB_BIT)); + + mgm->members_count = cpu_to_be32(members_count); + + err = mlx4_WRITE_MCG(dev, index, mailbox); + if (err) + goto out; + + if (!link) + goto out; + + err = mlx4_READ_MCG(dev, prev, mailbox); + if (err) + goto out; + + mgm->next_gid_index = cpu_to_be32(index << 6); + + err = mlx4_WRITE_MCG(dev, prev, mailbox); + if (err) + goto out; + +out: + if (err && link && index != -1) { + if (index < dev->caps.num_mgms) + mlx4_warn(dev, "Got AMGM index %d < %d", + index, dev->caps.num_mgms); + else + mlx4_bitmap_free(&priv->mcg_table.bitmap, + index - dev->caps.num_mgms); + } + mutex_unlock(&priv->mcg_table.mutex); + + mlx4_free_cmd_mailbox(dev, mailbox); + return err; +} +EXPORT_SYMBOL_GPL(mlx4_multicast_attach); + +int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16]) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_cmd_mailbox *mailbox; + struct mlx4_mgm *mgm; + u32 members_count; + u16 hash; + int prev, index; + int i, loc; + int err; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + mgm = mailbox->buf; + + mutex_lock(&priv->mcg_table.mutex); + + err = find_mgm(dev, gid, mailbox, &hash, &prev, &index); + if (err) + goto out; + + if (index == -1) { + mlx4_err(dev, "MGID %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x " + "not found\n", + be16_to_cpu(((__be16 *) gid)[0]), + be16_to_cpu(((__be16 *) gid)[1]), + be16_to_cpu(((__be16 *) gid)[2]), + be16_to_cpu(((__be16 *) gid)[3]), + be16_to_cpu(((__be16 *) gid)[4]), + be16_to_cpu(((__be16 *) gid)[5]), + be16_to_cpu(((__be16 *) gid)[6]), + be16_to_cpu(((__be16 *) gid)[7])); + err = -EINVAL; + goto out; + } + + members_count = be32_to_cpu(mgm->members_count); + for (loc = -1, i = 0; i < (int)members_count; ++i) + if ((int)(be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qp->qpn) + loc = i; + + if (loc == -1) { + mlx4_err(dev, "QP %06x not found in MGM\n", qp->qpn); + err = -EINVAL; + goto out; + } + + + mgm->members_count = cpu_to_be32(--members_count); + mgm->qp[loc] = mgm->qp[i - 1]; + mgm->qp[i - 1] = 0; + + err = mlx4_WRITE_MCG(dev, index, mailbox); + if (err) + goto out; + + if (i != 1) + goto out; + + if (prev == -1) { + /* Remove entry from MGM */ + int amgm_index = be32_to_cpu(mgm->next_gid_index) >> 6; + if (amgm_index) { + err = mlx4_READ_MCG(dev, amgm_index, mailbox); + if (err) + goto out; + } else + memset(mgm->gid, 0, 16); + + err = mlx4_WRITE_MCG(dev, index, mailbox); + if (err) + goto out; + + if (amgm_index) { + if (amgm_index < dev->caps.num_mgms) + mlx4_warn(dev, "MGM entry %d had AMGM index %d < %d", + index, amgm_index, dev->caps.num_mgms); + else + mlx4_bitmap_free(&priv->mcg_table.bitmap, + amgm_index - dev->caps.num_mgms); + } + } else { + /* Remove entry from AMGM */ + int cur_next_index = be32_to_cpu(mgm->next_gid_index) >> 6; + err = mlx4_READ_MCG(dev, prev, mailbox); + if (err) + goto out; + + mgm->next_gid_index = cpu_to_be32(cur_next_index << 6); + + err = mlx4_WRITE_MCG(dev, prev, mailbox); + if (err) + goto out; + + if (index < dev->caps.num_mgms) + mlx4_warn(dev, "entry %d had next AMGM index %d < %d", + prev, index, dev->caps.num_mgms); + else + mlx4_bitmap_free(&priv->mcg_table.bitmap, + index - dev->caps.num_mgms); + } + +out: + mutex_unlock(&priv->mcg_table.mutex); + + mlx4_free_cmd_mailbox(dev, mailbox); + return err; +} +EXPORT_SYMBOL_GPL(mlx4_multicast_detach); + +int mlx4_init_mcg_table(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + int err; + + err = mlx4_bitmap_init(&priv->mcg_table.bitmap, + dev->caps.num_amgms, dev->caps.num_amgms - 1, 0); + if (err) + return err; + + mutex_init(&priv->mcg_table.mutex); + + return 0; +} + +void mlx4_cleanup_mcg_table(struct mlx4_dev *dev) +{ + mlx4_bitmap_cleanup(&mlx4_priv(dev)->mcg_table.bitmap); +} diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/net/mlx4.h b/branches/WOF2-3/hw/mlx4/kernel/bus/net/mlx4.h new file mode 100644 index 00000000..90f0722c --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/net/mlx4.h @@ -0,0 +1,455 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2005, 2006, 2007 Cisco Systems. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * Copyright (c) 2004 Voltaire, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef MLX4_H +#define MLX4_H + +#include +#include "l2w.h" +#include "device.h" +#include "doorbell.h" +#include "bus_intf.h" +#include "eq.h" + + +// +// Structure for reporting data to WMI +// + +typedef struct _BUS_WMI_STD_DATA { + UINT32 DebugPrintLevel; + UINT32 DebugPrintFlags; + +} BUS_WMI_STD_DATA, * PBUS_WMI_STD_DATA; + + +// +// Driver global data +// + +enum mlx4_port_type { + MLX4_PORT_TYPE_IB = 1 << 0, + MLX4_PORT_TYPE_ETH = 1 << 1, +}; + +enum mlx4_port_state { + MLX4_PORT_ENABLED = 1 << 0, + MLX4_PORT_DISABLED = 1 << 1, +}; + +#define MAX_HCA_CARDS 8 + +#pragma warning(disable:4201) // nameless struct/union +typedef struct _GLOBALS { + BUS_WMI_STD_DATA bwsd; + + int mod_num_qp; + int mod_rdmarc_per_qp; + int mod_num_srq; + int mod_num_cq; + int mod_num_mcg; + int mod_num_mpt; + int mod_num_mtt; + int mod_num_mac; + int mod_num_vlan; + int mod_use_prio; + int mod_num_fc_exch; + + int mod_enable_qos; + int mod_mlx4_blck_lb; + int mod_interrupt_from_first; + + int mod_affinity; + int mod_stat_flags; + PFDO_DEVICE_DATA p_fdo[MAX_HCA_CARDS]; // for debug purposes +} GLOBALS; +#pragma warning(default:4201) // nameless struct/union + +extern GLOBALS g; + + +enum { + MLX4_HCR_BASE = 0x80680, + MLX4_HCR_SIZE = 0x0001c, + MLX4_CLR_INT_SIZE = 0x00008 +}; + +enum { + MLX4_MGM_ENTRY_SIZE = 0x100, + MLX4_QP_PER_MGM = 4 * (MLX4_MGM_ENTRY_SIZE / 16 - 2), + MLX4_MTT_ENTRY_PER_SEG = 8 +}; + +enum { + MLX4_EQ_ASYNC, + MLX4_EQ_COMP, + MLX4_NUM_EQ +}; +#define MLX4_NUM_UNKNOWN -1 + +#define MLX4_MAX_EXTRA_EQS 16 +#define MLX4_NUM_EQS (MLX4_NUM_EQ + MLX4_MAX_EXTRA_EQS) + +enum { + MLX4_NUM_PDS = 1 << 15 +}; + +enum { + MLX4_CMPT_TYPE_QP = 0, + MLX4_CMPT_TYPE_SRQ = 1, + MLX4_CMPT_TYPE_CQ = 2, + MLX4_CMPT_TYPE_EQ = 3, + MLX4_CMPT_NUM_TYPE +}; + +enum { + MLX4_CMPT_SHIFT = 24, + MLX4_NUM_CMPTS = MLX4_CMPT_NUM_TYPE << MLX4_CMPT_SHIFT +}; + +#define MGM_QPN_MASK 0x00FFFFFF +#define MGM_BLCK_LB_BIT 30 + +struct mlx4_bitmap { + u32 last; + u32 top; + u32 max; + u32 effective_max; + u32 mask; + spinlock_t lock; + unsigned long *table; +}; + +struct mlx4_buddy { + unsigned long **bits; + int max_order; + spinlock_t lock; +}; + +struct mlx4_icm; + +struct mlx4_icm_table { + u64 virt; + int num_icm; + int num_obj; + int obj_size; + int lowmem; + int coherent; + struct mutex mutex; + struct mlx4_icm **icm; +}; + +struct mlx4_profile { + int num_qp; + int rdmarc_per_qp; + int num_srq; + int num_cq; + int num_mcg; + int num_mpt; + int num_mtt; +}; + +struct mlx4_fw { + u64 clr_int_base; + u64 catas_offset; + struct mlx4_icm *fw_icm; + struct mlx4_icm *aux_icm; + u32 catas_size; + u16 fw_pages; + u8 clr_int_bar; + u8 catas_bar; +}; + +struct mlx4_cmd { + struct pci_pool *pool; + u8 __iomem *hcr; + struct mutex hcr_mutex; + struct semaphore poll_sem; + struct semaphore event_sem; + int max_cmds; + spinlock_t context_lock; + int free_head; + struct mlx4_cmd_context *context; + u16 token_mask; + u8 use_events; + u8 toggle; +}; + +struct mlx4_uar_table { + struct mlx4_bitmap bitmap; +}; + +struct mlx4_mr_table { + struct mlx4_bitmap mpt_bitmap; + struct mlx4_buddy mtt_buddy; + u64 mtt_base; + u64 mpt_base; + struct mlx4_icm_table mtt_table; + struct mlx4_icm_table dmpt_table; +}; + +struct mlx4_cq_table { + struct mlx4_bitmap bitmap; + spinlock_t lock; + struct radix_tree_root tree; + struct mlx4_icm_table table; + struct mlx4_icm_table cmpt_table; +}; + +struct mlx4_eq_table { + struct mlx4_bitmap bitmap; + void __iomem *clr_int; + u8 __iomem *uar_map[(MLX4_NUM_EQS + 6) / 4]; + u32 clr_mask; + struct mlx4_eq eq[MLX4_NUM_EQS]; + struct mlx4_icm_table table; + struct mlx4_icm_table cmpt_table; + int have_irq; + u8 inta_pin; + u8 max_extra_eqs; +#if 1//WORKAROUND_POLL_EQ + KEVENT thread_start_event; + KEVENT thread_stop_event; + BOOLEAN bTerminated; + PVOID threadObject; +#endif +}; + +struct mlx4_srq_table { + struct mlx4_bitmap bitmap; + spinlock_t lock; + struct radix_tree_root tree; + struct mlx4_icm_table table; + struct mlx4_icm_table cmpt_table; +}; + +struct mlx4_qp_table { + struct mlx4_bitmap bitmap; + u32 rdmarc_base; + int rdmarc_shift; + spinlock_t lock; + struct mlx4_icm_table qp_table; + struct mlx4_icm_table auxc_table; + struct mlx4_icm_table altc_table; + struct mlx4_icm_table rdmarc_table; + struct mlx4_icm_table cmpt_table; +}; + +struct mlx4_mcg_table { + struct mutex mutex; + struct mlx4_bitmap bitmap; + struct mlx4_icm_table table; +}; + +struct mlx4_catas_err { + u32 __iomem *map; + /* Windows */ + int stop; + KTIMER timer; + KDPC timer_dpc; + LARGE_INTEGER interval; + PIO_WORKITEM catas_work; +}; + +struct mlx4_mac_table { +#define MLX4_MAX_MAC_NUM 128 +#define MLX4_MAC_MASK 0xffffffffffff +#define MLX4_MAC_VALID_SHIFT 63 +#define MLX4_MAC_TABLE_SIZE MLX4_MAX_MAC_NUM << 3 + __be64 entries[MLX4_MAX_MAC_NUM]; + int refs[MLX4_MAX_MAC_NUM]; + struct semaphore mac_sem; + int total; + int max; +}; + +struct mlx4_vlan_table { +#define MLX4_MAX_VLAN_NUM 126 +#define MLX4_VLAN_MASK 0xfff +#define MLX4_VLAN_VALID 1 << 31 +#define MLX4_VLAN_TABLE_SIZE MLX4_MAX_VLAN_NUM << 2 + __be32 entries[MLX4_MAX_VLAN_NUM]; + int refs[MLX4_MAX_VLAN_NUM]; + struct semaphore vlan_sem; + int total; + int max; +}; + +struct mlx4_port_info { + struct mlx4_mac_table mac_table; + struct mlx4_vlan_table vlan_table; +}; + +struct mlx4_priv { + struct mlx4_dev dev; + + struct list_head dev_list; + struct list_head ctx_list; + spinlock_t ctx_lock; + + struct list_head pgdir_list; + struct mutex pgdir_mutex; + + struct mlx4_fw fw; + struct mlx4_cmd cmd; + + struct mlx4_bitmap pd_bitmap; + struct mlx4_uar_table uar_table; + struct mlx4_mr_table mr_table; + struct mlx4_cq_table cq_table; + struct mlx4_eq_table eq_table; + struct mlx4_srq_table srq_table; + struct mlx4_qp_table qp_table; + struct mlx4_mcg_table mcg_table; + + struct mlx4_catas_err catas_err; + + u8 __iomem *clr_base; + + struct mlx4_uar driver_uar; + void __iomem *kar; + struct mlx4_port_info port[MLX4_MAX_PORTS]; +}; + +static inline struct mlx4_priv *mlx4_priv(struct mlx4_dev *dev) +{ + return container_of(dev, struct mlx4_priv, dev); +} + +u32 mlx4_bitmap_alloc(struct mlx4_bitmap *bitmap); +void mlx4_bitmap_free(struct mlx4_bitmap *bitmap, u32 obj); +u32 mlx4_bitmap_alloc_range(struct mlx4_bitmap *bitmap, int cnt, int align); +void mlx4_bitmap_free_range(struct mlx4_bitmap *bitmap, u32 obj, int cnt); +int mlx4_bitmap_init(struct mlx4_bitmap *bitmap, u32 num, u32 mask, u32 reserved); +int mlx4_bitmap_init_with_effective_max(struct mlx4_bitmap *bitmap, + u32 num, u32 mask, u32 reserved, + u32 effective_max); +void mlx4_bitmap_cleanup(struct mlx4_bitmap *bitmap); + +int mlx4_db_alloc(struct mlx4_dev *dev, + struct mlx4_db *db, int order); + +int mlx4_init_pd_table(struct mlx4_dev *dev); +int mlx4_init_uar_table(struct mlx4_dev *dev); +int mlx4_init_mr_table(struct mlx4_dev *dev); +int mlx4_init_eq_table(struct mlx4_dev *dev); +int mlx4_init_cq_table(struct mlx4_dev *dev); +int mlx4_init_qp_table(struct mlx4_dev *dev); +int mlx4_init_srq_table(struct mlx4_dev *dev); +int mlx4_init_mcg_table(struct mlx4_dev *dev); + +void mlx4_cleanup_pd_table(struct mlx4_dev *dev); +void mlx4_cleanup_uar_table(struct mlx4_dev *dev); +void mlx4_cleanup_mr_table(struct mlx4_dev *dev); +void mlx4_cleanup_eq_table(struct mlx4_dev *dev); +void mlx4_cleanup_cq_table(struct mlx4_dev *dev); +void mlx4_cleanup_qp_table(struct mlx4_dev *dev); +void mlx4_cleanup_srq_table(struct mlx4_dev *dev); +void mlx4_cleanup_mcg_table(struct mlx4_dev *dev); + +int mlx4_start_catas_poll(struct mlx4_dev *dev); +void mlx4_stop_catas_poll(struct mlx4_dev *dev); +int mlx4_restart_one(struct pci_dev *pdev); +int mlx4_register_device(struct mlx4_dev *dev); +void mlx4_unregister_device(struct mlx4_dev *dev); +void mlx4_dispatch_event(struct mlx4_dev *dev, enum mlx4_event type, + int subtype, int port); +void mlx4_intf_init(); +void mlx4_net_init(); + +BOOLEAN mlx4_is_eth_port(struct mlx4_dev *dev, int port_number); +BOOLEAN mlx4_is_ib_port(struct mlx4_dev *dev, int port_number); +BOOLEAN mlx4_is_enabled_port(struct mlx4_dev *dev, int port_number); +int mlx4_count_ib_ports(struct mlx4_dev *dev); + +struct mlx4_dev_cap; +struct mlx4_init_hca_param; + +u64 mlx4_make_profile(struct mlx4_dev *dev, + struct mlx4_profile *request, + struct mlx4_dev_cap *dev_cap, + struct mlx4_init_hca_param *init_hca); + +int mlx4_cmd_init(struct mlx4_dev *dev); +void mlx4_cmd_cleanup(struct mlx4_dev *dev); +void mlx4_cmd_event(struct mlx4_dev *dev, u16 token, u8 status, u64 out_param); +int mlx4_cmd_use_events(struct mlx4_dev *dev); +void mlx4_cmd_use_polling(struct mlx4_dev *dev); + +int mlx4_qp_get_region(struct mlx4_dev *dev, + enum qp_region region, + int *base_qpn, int *cnt); + +void mlx4_cq_completion(struct mlx4_dev *dev, u32 cqn); +void mlx4_cq_event(struct mlx4_dev *dev, u32 cqn, int event_type); + +void mlx4_init_mac_table(struct mlx4_dev *dev, u8 port); +void mlx4_init_vlan_table(struct mlx4_dev *dev, u8 port); + +void mlx4_qp_event(struct mlx4_dev *dev, u32 qpn, int event_type); + +void mlx4_srq_event(struct mlx4_dev *dev, u32 srqn, int event_type); + +void mlx4_handle_catas_err(struct mlx4_dev *dev); + +int mlx4_init_one(struct pci_dev *pdev, struct mlx4_dev_params *dev_params); + +void mlx4_remove_one(struct pci_dev *pdev, int reset); + +#define ETH_FCS_LEN 4 /* Frame Check Sequence Length */ +#define ETH_HLEN 14 + +int mlx4_add_eq(struct mlx4_dev *dev, int nent, + KAFFINITY cpu, PISR_FUNC func, PVOID func_context , + u8* p_eq_num, struct mlx4_eq ** p_eq); + +void mlx4_remove_eq(struct mlx4_dev *dev, u8 eq_num); + +int mlx4_reset_ready( struct ib_event_handler *event_handler ); +int mlx4_reset_execute( struct ib_event_handler *event_handler ); + +int mlx4_reset_request( struct ib_event_handler *event_handler ); + +int mlx4_reset_cb_register( struct ib_event_handler *event_handler ); + +int mlx4_reset_cb_unregister( struct ib_event_handler *event_handler ); + +void fix_bus_ifc(struct pci_dev *pdev); + +void mlx4_dispatch_reset_event(struct ib_device *ibdev, enum ib_event_type type); + + +#endif /* MLX4_H */ diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/net/mr.c b/branches/WOF2-3/hw/mlx4/kernel/bus/net/mr.c new file mode 100644 index 00000000..93c13994 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/net/mr.c @@ -0,0 +1,659 @@ +/* + * Copyright (c) 2004 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + +#include "mlx4.h" +#include "cmd.h" +#include "icm.h" + +/* + * Must be packed because mtt_seg is 64 bits but only aligned to 32 bits. + */ +#pragma pack(push,1) +struct mlx4_mpt_entry { + __be32 flags; + __be32 qpn; + __be32 key; + __be32 pd; + __be64 start; + __be64 length; + __be32 lkey; + __be32 win_cnt; + u8 reserved1[3]; + u8 mtt_rep; + __be64 mtt_seg; + __be32 mtt_sz; + __be32 entity_size; + __be32 first_byte_offset; +} __attribute__((packed)); +#pragma pack(pop) + +#define MLX4_MPT_FLAG_SW_OWNS (0xfUL << 28) +#define MLX4_MPT_FLAG_MIO (1 << 17) +#define MLX4_MPT_FLAG_BIND_ENABLE (1 << 15) +#define MLX4_MPT_FLAG_PHYSICAL (1 << 9) +#define MLX4_MPT_FLAG_REGION (1 << 8) + +#define MLX4_MTT_FLAG_PRESENT 1 + +#define MLX4_MPT_STATUS_SW 0xF0 +#define MLX4_MPT_STATUS_HW 0x00 + +static u32 mlx4_buddy_alloc(struct mlx4_buddy *buddy, int order) +{ + int o; + int m; + u32 seg; + + spin_lock(&buddy->lock); + + for (o = order; o <= buddy->max_order; ++o) { + m = 1 << (buddy->max_order - o); + seg = find_first_bit(buddy->bits[o], m); + if (seg < (u32)m) + goto found; + } + + spin_unlock(&buddy->lock); + return (u32)-1; + + found: + clear_bit(seg, buddy->bits[o]); + + while (o > order) { + --o; + seg <<= 1; + set_bit(seg ^ 1, buddy->bits[o]); + } + + spin_unlock(&buddy->lock); + + seg <<= order; + + return seg; +} + +static void mlx4_buddy_free(struct mlx4_buddy *buddy, u32 seg, int order) +{ + seg >>= order; + + spin_lock(&buddy->lock); + + while (test_bit(seg ^ 1, buddy->bits[order])) { + clear_bit(seg ^ 1, buddy->bits[order]); + seg >>= 1; + ++order; + } + + set_bit(seg, buddy->bits[order]); + + spin_unlock(&buddy->lock); +} + +static int __devinit mlx4_buddy_init(struct mlx4_buddy *buddy, int max_order) +{ + int i, s; + + buddy->max_order = max_order; + spin_lock_init(&buddy->lock); + + buddy->bits = kzalloc((buddy->max_order + 1) * sizeof (long *), + GFP_KERNEL); + if (!buddy->bits) + goto err_out; + + for (i = 0; i <= buddy->max_order; ++i) { + s = BITS_TO_LONGS(1 << (buddy->max_order - i)); + buddy->bits[i] = kmalloc(s * sizeof (long), GFP_KERNEL); + if (!buddy->bits[i]) + goto err_out_free; + bitmap_zero(buddy->bits[i], 1 << (buddy->max_order - i)); + } + + set_bit(0, buddy->bits[buddy->max_order]); + + return 0; + +err_out_free: + for (i = 0; i <= buddy->max_order; ++i) + kfree(buddy->bits[i]); + + kfree(buddy->bits); + +err_out: + return -ENOMEM; +} + +static void mlx4_buddy_cleanup(struct mlx4_buddy *buddy) +{ + int i; + + for (i = 0; i <= buddy->max_order; ++i) + kfree(buddy->bits[i]); + + kfree(buddy->bits); +} + +static u32 mlx4_alloc_mtt_range(struct mlx4_dev *dev, int order) +{ + struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table; + u32 seg; + + seg = mlx4_buddy_alloc(&mr_table->mtt_buddy, order); + if (seg == -1) + return (u32)-1; + + if (mlx4_table_get_range(dev, &mr_table->mtt_table, seg, + seg + (1 << order) - 1)) { + mlx4_buddy_free(&mr_table->mtt_buddy, seg, order); + return (u32)-1; + } + + return seg; +} + +int mlx4_mtt_init(struct mlx4_dev *dev, int npages, int page_shift, + struct mlx4_mtt *mtt) +{ + int i; + + if (!npages) { + mtt->order = -1; + mtt->page_shift = MLX4_ICM_PAGE_SHIFT; + return 0; + } else + mtt->page_shift = page_shift; + + for (mtt->order = 0, i = MLX4_MTT_ENTRY_PER_SEG; i < npages; i <<= 1) + ++mtt->order; + + mtt->first_seg = mlx4_alloc_mtt_range(dev, mtt->order); + if (mtt->first_seg == -1) + return -ENOMEM; + + return 0; +} +EXPORT_SYMBOL_GPL(mlx4_mtt_init); + +void mlx4_mtt_cleanup(struct mlx4_dev *dev, struct mlx4_mtt *mtt) +{ + struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table; + + if (mtt->order < 0) + return; + + mlx4_buddy_free(&mr_table->mtt_buddy, mtt->first_seg, mtt->order); + mlx4_table_put_range(dev, &mr_table->mtt_table, mtt->first_seg, + mtt->first_seg + (1 << mtt->order) - 1); +} +EXPORT_SYMBOL_GPL(mlx4_mtt_cleanup); + +u64 mlx4_mtt_addr(struct mlx4_dev *dev, struct mlx4_mtt *mtt) +{ + return (u64) mtt->first_seg * dev->caps.mtt_entry_sz; +} +EXPORT_SYMBOL_GPL(mlx4_mtt_addr); + +static u32 hw_index_to_key(u32 ind) +{ + return (ind >> 24) | (ind << 8); +} + +static u32 key_to_hw_index(u32 key) +{ + return (key << 24) | (key >> 8); +} + +static int mlx4_SW2HW_MPT(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, + int mpt_index) +{ + return mlx4_cmd(dev, mailbox->dma.da, mpt_index, 0, MLX4_CMD_SW2HW_MPT, + MLX4_CMD_TIME_CLASS_B); +} + +static int mlx4_HW2SW_MPT(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, + int mpt_index) +{ + return mlx4_cmd_box(dev, 0, mailbox ? mailbox->dma.da : 0, mpt_index, + (u8)!mailbox, MLX4_CMD_HW2SW_MPT, MLX4_CMD_TIME_CLASS_B); +} + +int mlx4_mr_alloc(struct mlx4_dev *dev, u32 pd, u64 iova, u64 size, u32 access, + int npages, int page_shift, struct mlx4_mr *mr) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + u32 index; + int err; + + if ( mlx4_is_barred(dev) ) + return -EFAULT; + + index = mlx4_bitmap_alloc(&priv->mr_table.mpt_bitmap); + if (index == -1) + return -ENOMEM; + + mr->iova = iova; + mr->size = size; + mr->pd = pd; + mr->access = access; + mr->enabled = 0; + mr->key = hw_index_to_key(index); + + err = mlx4_mtt_init(dev, npages, page_shift, &mr->mtt); + if (err) + mlx4_bitmap_free(&priv->mr_table.mpt_bitmap, index); + + return err; +} +EXPORT_SYMBOL_GPL(mlx4_mr_alloc); + +void mlx4_mr_free(struct mlx4_dev *dev, struct mlx4_mr *mr) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + int err; + + if (!mlx4_is_barred(dev) && mr->enabled) { + err = mlx4_HW2SW_MPT(dev, NULL, + key_to_hw_index(mr->key) & + (dev->caps.num_mpts - 1)); + if (err) + mlx4_warn(dev, "HW2SW_MPT failed (%d)\n", err); + } + + mlx4_mtt_cleanup(dev, &mr->mtt); + mlx4_bitmap_free(&priv->mr_table.mpt_bitmap, key_to_hw_index(mr->key)); +} +EXPORT_SYMBOL_GPL(mlx4_mr_free); + +int mlx4_mr_enable(struct mlx4_dev *dev, struct mlx4_mr *mr) +{ + struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table; + struct mlx4_cmd_mailbox *mailbox; + struct mlx4_mpt_entry *mpt_entry; + int err; + + if ( mlx4_is_barred(dev) ) + return -EFAULT; + + err = mlx4_table_get(dev, &mr_table->dmpt_table, key_to_hw_index(mr->key)); + if (err) + return err; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) { + err = PTR_ERR(mailbox); + goto err_table; + } + mpt_entry = mailbox->buf; + + memset(mpt_entry, 0, sizeof *mpt_entry); + + mpt_entry->flags = cpu_to_be32(MLX4_MPT_FLAG_SW_OWNS | + MLX4_MPT_FLAG_MIO | + MLX4_MPT_FLAG_REGION | + mr->access); + + mpt_entry->key = cpu_to_be32(key_to_hw_index(mr->key)); + mpt_entry->pd = cpu_to_be32(mr->pd); + mpt_entry->start = cpu_to_be64(mr->iova); + mpt_entry->length = cpu_to_be64(mr->size); + mpt_entry->entity_size = cpu_to_be32(mr->mtt.page_shift); + if (mr->mtt.order < 0) { + mpt_entry->flags |= cpu_to_be32(MLX4_MPT_FLAG_PHYSICAL); + mpt_entry->mtt_seg = 0; + } else + mpt_entry->mtt_seg = cpu_to_be64(mlx4_mtt_addr(dev, &mr->mtt)); + + err = mlx4_SW2HW_MPT(dev, mailbox, + key_to_hw_index(mr->key) & (dev->caps.num_mpts - 1)); + if (err) { + mlx4_warn(dev, "SW2HW_MPT failed (%d)\n", err); + goto err_cmd; + } + + mr->enabled = 1; + + mlx4_free_cmd_mailbox(dev, mailbox); + + return 0; + +err_cmd: + mlx4_free_cmd_mailbox(dev, mailbox); + +err_table: + mlx4_table_put(dev, &mr_table->dmpt_table, key_to_hw_index(mr->key)); + return err; +} +EXPORT_SYMBOL_GPL(mlx4_mr_enable); + +static int mlx4_write_mtt_chunk(struct mlx4_dev *dev, struct mlx4_mtt *mtt, + int start_index, int npages, u64 *page_list) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + __be64 *mtts; + dma_addr_t dma_handle; + int i; + int s = start_index * sizeof (u64); + + /* All MTTs must fit in the same page */ + if (start_index / (PAGE_SIZE / sizeof (u64)) != + (start_index + npages - 1) / (PAGE_SIZE / sizeof (u64))) + return -EINVAL; + + if (start_index & (MLX4_MTT_ENTRY_PER_SEG - 1)) + return -EINVAL; + + mtts = mlx4_table_find(&priv->mr_table.mtt_table, mtt->first_seg + + s / dev->caps.mtt_entry_sz, &dma_handle); + if (!mtts) { + printk(KERN_ERR "mlx4_write_mtt_chunk: mlx4_table_find failed with -ENOMEM \n"); + return -ENOMEM; + } + + for (i = 0; i < npages; ++i) + mtts[i] = cpu_to_be64(page_list[i] | MLX4_MTT_FLAG_PRESENT); + + dma_sync_single(&dev->pdev->dev, dma_handle, npages * sizeof (u64), DMA_TO_DEVICE); + + return 0; +} + +int mlx4_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt, + int start_index, int npages, u64 *page_list) +{ + int chunk; + int err; + + if (mtt->order < 0) + return -EINVAL; + + while (npages > 0) { + chunk = min_t(int, PAGE_SIZE / sizeof(u64), npages); + err = mlx4_write_mtt_chunk(dev, mtt, start_index, chunk, page_list); + if (err) + return err; + + npages -= chunk; + start_index += chunk; + page_list += chunk; + } + + return 0; +} +EXPORT_SYMBOL_GPL(mlx4_write_mtt); + +int mlx4_buf_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt, + struct mlx4_buf *buf) +{ + u64 *page_list; + int err; + int i; + + page_list = kmalloc(buf->npages * sizeof *page_list, GFP_KERNEL); + if (!page_list) { + printk(KERN_ERR "mlx4_buf_write_mtt: kmalloc failed with -ENOMEM \n"); + return -ENOMEM; + } + + for (i = 0; i < buf->npages; ++i) + if (buf->nbufs == 1) + page_list[i] = buf->u.direct.map.da + (i << buf->page_shift); + else + page_list[i] = buf->u.page_list[i].map.da; + + err = mlx4_write_mtt(dev, mtt, 0, buf->npages, page_list); + + kfree(page_list); + return err; +} +EXPORT_SYMBOL_GPL(mlx4_buf_write_mtt); + +int mlx4_init_mr_table(struct mlx4_dev *dev) +{ + struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table; + int err; + + if (!is_power_of_2(dev->caps.num_mpts)) + return -EINVAL; + + dev->caps.reserved_fexch_mpts_base = dev->caps.num_mpts - + (2 * dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FC_EXCH]); + err = mlx4_bitmap_init_with_effective_max(&mr_table->mpt_bitmap, + dev->caps.num_mpts, + (u32)~0, dev->caps.reserved_mrws, + dev->caps.reserved_fexch_mpts_base); + + + + if (err) + return err; + + err = mlx4_buddy_init(&mr_table->mtt_buddy, + ilog2(dev->caps.num_mtt_segs)); + if (err) + goto err_buddy; + + if (dev->caps.reserved_mtts) { + if (mlx4_alloc_mtt_range(dev, fls(dev->caps.reserved_mtts - 1)) == -1) { + mlx4_warn(dev, "MTT table of order %d is too small.\n", + mr_table->mtt_buddy.max_order); + err = -ENOMEM; + goto err_reserve_mtts; + } + } + + return 0; + +err_reserve_mtts: + mlx4_buddy_cleanup(&mr_table->mtt_buddy); + +err_buddy: + mlx4_bitmap_cleanup(&mr_table->mpt_bitmap); + + return err; +} + +void mlx4_cleanup_mr_table(struct mlx4_dev *dev) +{ + struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table; + + mlx4_buddy_cleanup(&mr_table->mtt_buddy); + mlx4_bitmap_cleanup(&mr_table->mpt_bitmap); +} + +static inline int mlx4_check_fmr(struct mlx4_fmr *fmr, u64 *page_list, + int npages, u64 iova) +{ + int i, page_mask; + + if (npages > fmr->max_pages) + return -EINVAL; + + page_mask = (1 << fmr->page_shift) - 1; + + /* We are getting page lists, so va must be page aligned. */ + if (iova & page_mask) + return -EINVAL; + + /* Trust the user not to pass misaligned data in page_list */ + if (!fmr) /* instead of 0, that is warned by compiler */ + for (i = 0; i < npages; ++i) { + if (page_list[i] & ~page_mask) + return -EINVAL; + } + + if (fmr->maps >= fmr->max_maps) + return -EINVAL; + + return 0; +} + +int mlx4_map_phys_fmr(struct mlx4_dev *dev, struct mlx4_fmr *fmr, u64 *page_list, + int npages, u64 iova, u32 *lkey, u32 *rkey) +{ + u32 key; + int i, err; + + err = mlx4_check_fmr(fmr, page_list, npages, iova); + if (err) + return err; + + ++fmr->maps; + + key = key_to_hw_index(fmr->mr.key); + key += dev->caps.num_mpts; + *lkey = *rkey = fmr->mr.key = hw_index_to_key(key); + + *(u8 *) fmr->mpt = MLX4_MPT_STATUS_SW; + + /* Make sure MPT status is visible before writing MTT entries */ + wmb(); + + for (i = 0; i < npages; ++i) + fmr->mtts[i] = cpu_to_be64(page_list[i] | MLX4_MTT_FLAG_PRESENT); + + dma_sync_single(&dev->pdev->dev, fmr->dma_handle, + npages * sizeof(u64), DMA_TO_DEVICE); + + fmr->mpt->key = cpu_to_be32(key); + fmr->mpt->lkey = cpu_to_be32(key); + fmr->mpt->length = cpu_to_be64(npages * (1ull << fmr->page_shift)); + fmr->mpt->start = cpu_to_be64(iova); + + /* Make MTT entries are visible before setting MPT status */ + wmb(); + + *(u8 *) fmr->mpt = MLX4_MPT_STATUS_HW; + + /* Make sure MPT status is visible before consumer can use FMR */ + wmb(); + + return 0; +} +EXPORT_SYMBOL_GPL(mlx4_map_phys_fmr); + +int mlx4_fmr_alloc(struct mlx4_dev *dev, u32 pd, u32 access, int max_pages, + int max_maps, u8 page_shift, struct mlx4_fmr *fmr) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + u64 mtt_seg; + int err = -ENOMEM; + + if (page_shift < 12 || page_shift >= 32) + return -EINVAL; + + /* All MTTs must fit in the same page */ + if (max_pages * sizeof *fmr->mtts > PAGE_SIZE) + return -EINVAL; + + fmr->page_shift = page_shift; + fmr->max_pages = max_pages; + fmr->max_maps = max_maps; + fmr->maps = 0; + + err = mlx4_mr_alloc(dev, pd, 0, 0, access, max_pages, + page_shift, &fmr->mr); + if (err) + return err; + + mtt_seg = fmr->mr.mtt.first_seg * dev->caps.mtt_entry_sz; + + fmr->mtts = mlx4_table_find(&priv->mr_table.mtt_table, + fmr->mr.mtt.first_seg, + &fmr->dma_handle); + if (!fmr->mtts) { + err = -ENOMEM; + goto err_free; + } + return 0; + +err_free: + mlx4_mr_free(dev, &fmr->mr); + return err; +} +EXPORT_SYMBOL_GPL(mlx4_fmr_alloc); + +int mlx4_fmr_enable(struct mlx4_dev *dev, struct mlx4_fmr *fmr) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + int err; + + err = mlx4_mr_enable(dev, &fmr->mr); + if (err) + return err; + + fmr->mpt = mlx4_table_find(&priv->mr_table.dmpt_table, + key_to_hw_index(fmr->mr.key), NULL); + if (!fmr->mpt) + return -ENOMEM; + + return 0; +} +EXPORT_SYMBOL_GPL(mlx4_fmr_enable); + +void mlx4_fmr_unmap(struct mlx4_dev *dev, struct mlx4_fmr *fmr, + u32 *lkey, u32 *rkey) +{ + u32 key; + + if (!fmr->maps) + return; + + key = key_to_hw_index(fmr->mr.key); + key &= dev->caps.num_mpts - 1; + *lkey = *rkey = fmr->mr.key = hw_index_to_key(key); + + fmr->maps = 0; + + *(u8 *) fmr->mpt = MLX4_MPT_STATUS_SW; +} +EXPORT_SYMBOL_GPL(mlx4_fmr_unmap); + +int mlx4_fmr_free(struct mlx4_dev *dev, struct mlx4_fmr *fmr) +{ + if (fmr->maps) + return -EBUSY; + + fmr->mr.enabled = 0; + mlx4_mr_free(dev, &fmr->mr); + + return 0; +} +EXPORT_SYMBOL_GPL(mlx4_fmr_free); + +int mlx4_SYNC_TPT(struct mlx4_dev *dev) +{ + return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_SYNC_TPT, 1000); +} +EXPORT_SYMBOL_GPL(mlx4_SYNC_TPT); diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/net/net.def b/branches/WOF2-3/hw/mlx4/kernel/bus/net/net.def new file mode 100644 index 00000000..71305a19 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/net/net.def @@ -0,0 +1,24 @@ +LIBRARY mlx4_net.lib + +EXPORTS +; DllInitialize and DllUnload must be exported for the OS reference counting to +; work, and must be private for the compiler to accept them. +DllInitialize private +DllUnload private + +; main.c +mlx4_init_one +mlx4_remove_one +mlx4_net_init +mlx4_is_eth_port +mlx4_count_ib_ports + +; alloc.c +mlx4_buf_alloc +mlx4_buf_free + +;port.c +mlx4_init_vlan_table +mlx4_init_mac_table +mlx4_SET_PORT + diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/net/net.rc b/branches/WOF2-3/hw/mlx4/kernel/bus/net/net.rc new file mode 100644 index 00000000..61840a0b --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/net/net.rc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: ibal.rc 1611 2006-08-20 14:48:55Z sleybo $ + */ + + +#include + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef _DEBUG_ +#define VER_FILEDESCRIPTION_STR "MLX4 Common HW Services (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "MLX4 Common HW Services" +#endif + +#define VER_INTERNALNAME_STR "mlx4_net.lib" +#define VER_ORIGINALFILENAME_STR "mlx4_net.lib" + +#include diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/net/pd.c b/branches/WOF2-3/hw/mlx4/kernel/bus/net/pd.c new file mode 100644 index 00000000..ed036c9d --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/net/pd.c @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + +#include "mlx4.h" +#include "icm.h" + +int mlx4_pd_alloc(struct mlx4_dev *dev, u32 *pdn) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + + if ( mlx4_is_barred(dev) ) + return -EFAULT; + + *pdn = mlx4_bitmap_alloc(&priv->pd_bitmap); + if (*pdn == -1) + return -ENOMEM; + + return 0; +} +EXPORT_SYMBOL_GPL(mlx4_pd_alloc); + +void mlx4_pd_free(struct mlx4_dev *dev, u32 pdn) +{ + mlx4_bitmap_free(&mlx4_priv(dev)->pd_bitmap, pdn); +} +EXPORT_SYMBOL_GPL(mlx4_pd_free); + +int mlx4_init_pd_table(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + + return mlx4_bitmap_init(&priv->pd_bitmap, dev->caps.num_pds, + (1 << 24) - 1, dev->caps.reserved_pds); +} + +void mlx4_cleanup_pd_table(struct mlx4_dev *dev) +{ + mlx4_bitmap_cleanup(&mlx4_priv(dev)->pd_bitmap); +} + + +int mlx4_uar_alloc(struct mlx4_dev *dev, struct mlx4_uar *uar) +{ + if ( mlx4_is_barred(dev) ) + return -EFAULT; + + uar->index = mlx4_bitmap_alloc(&mlx4_priv(dev)->uar_table.bitmap); + if (uar->index == -1) + return -ENOMEM; + + uar->pfn = (u32)((pci_resource_start(dev->pdev, 2) >> PAGE_SHIFT) + uar->index); + + return 0; +} +EXPORT_SYMBOL_GPL(mlx4_uar_alloc); + +void mlx4_uar_free(struct mlx4_dev *dev, struct mlx4_uar *uar) +{ + mlx4_bitmap_free(&mlx4_priv(dev)->uar_table.bitmap, uar->index); +} +EXPORT_SYMBOL_GPL(mlx4_uar_free); + +int mlx4_init_uar_table(struct mlx4_dev *dev) +{ + return mlx4_bitmap_init(&mlx4_priv(dev)->uar_table.bitmap, + dev->caps.num_uars, dev->caps.num_uars - 1, + max(128, dev->caps.reserved_uars)); +} + +void mlx4_cleanup_uar_table(struct mlx4_dev *dev) +{ + mlx4_bitmap_cleanup(&mlx4_priv(dev)->uar_table.bitmap); +} diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/net/port.c b/branches/WOF2-3/hw/mlx4/kernel/bus/net/port.c new file mode 100644 index 00000000..3bc3b800 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/net/port.c @@ -0,0 +1,365 @@ +/* + * Copyright (c) 2007 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#include "mlx4.h" +#include "cmd.h" +#include "public.h" + +extern NTSTATUS __create_child(); + +void mlx4_init_mac_table(struct mlx4_dev *dev, u8 port) +{ + struct mlx4_mac_table *table = &mlx4_priv(dev)->port[port].mac_table; + int i; + + sema_init(&table->mac_sem, 1); + for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { + table->entries[i] = 0; + table->refs[i] = 0; + } + table->max = 1 << dev->caps.log_num_macs; + table->total = 0; +} + +void mlx4_init_vlan_table(struct mlx4_dev *dev, u8 port) +{ + struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table; + int i; + + sema_init(&table->vlan_sem, 1); + for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) { + table->entries[i] = 0; + table->refs[i] = 0; + } + table->max = 1 << dev->caps.log_num_vlans; + if(table->max > MLX4_MAX_VLAN_NUM) + { + table->max = MLX4_MAX_VLAN_NUM; + } + table->total = 0; +} + +static int mlx4_SET_PORT_mac_table(struct mlx4_dev *dev, u8 port, + __be64 *entries) +{ + struct mlx4_cmd_mailbox *mailbox; + u32 in_mod; + int err; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + + memcpy(mailbox->buf, entries, MLX4_MAC_TABLE_SIZE); + + in_mod = MLX4_SET_PORT_MAC_TABLE << 8 | port; + err = mlx4_cmd(dev, mailbox->dma.da, in_mod, 1, MLX4_CMD_SET_PORT, + MLX4_CMD_TIME_CLASS_B); + + mlx4_free_cmd_mailbox(dev, mailbox); + return err; +} + +static void mlx4_addrconf_ifid_eui48_win(u8 *eui, u64 mac) +{ + u8 *p = (u8*)&mac+2; //mac 6 bytes + memcpy(eui, p, 3); + memcpy(eui + 5, p + 3, 3); + eui[3] = 0xFF; + eui[4] = 0xFE; + eui[0] ^= 2; +} + + +static int update_ipv6_gids_win(struct mlx4_dev *dev, int port, int clear, u64 mac) +{ + struct mlx4_cmd_mailbox *mailbox; + union ib_gid *gids, *tmpgids; + int err; + + tmpgids = kzalloc(128 * sizeof *gids, GFP_ATOMIC); + if (!tmpgids) + return -ENOMEM; + + if (!clear) { + mlx4_addrconf_ifid_eui48_win(&tmpgids[0].raw[8], cpu_to_be64(mac)); + tmpgids[0].global.subnet_prefix = cpu_to_be64(0xfe80000000000000LL); + } + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) { + err = PTR_ERR(mailbox); + goto out; + } + + gids = mailbox->buf; + memcpy(gids, tmpgids, 128 * sizeof *gids); + + err = mlx4_cmd(dev, mailbox->dma.da, MLX4_SET_PORT_GID_TABLE << 8 | port, + 1, MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B); + + mlx4_free_cmd_mailbox(dev, mailbox); + +out: + kfree(tmpgids); + return err; +} + + +int mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *index) +{ + struct mlx4_mac_table *table = + &mlx4_priv(dev)->port[port - 1].mac_table; + int i, err = 0; + int free = -1; + u64 valid = 1; + + if ( mlx4_is_barred(dev) ) + return -EFAULT; + + mlx4_dbg(dev, "Registering mac : 0x%llx\n", mac); + down(&table->mac_sem); + for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { + if (free < 0 && !table->refs[i]) { + free = i; + continue; + } + + if (mac == (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) { + /* Mac already registered, increase refernce count */ + *index = i; + ++table->refs[i]; + goto out; + } + } + mlx4_dbg(dev, "Free mac index is %d\n", free); + + if (table->total == table->max || free < 0) { + /* No free mac entries */ + err = -ENOSPC; + goto out; + } + + /* Register new MAC */ + table->refs[free] = 1; + table->entries[free] = cpu_to_be64(mac | valid << MLX4_MAC_VALID_SHIFT); + + err = mlx4_SET_PORT_mac_table(dev, port, table->entries); + if (unlikely(err)) { + mlx4_err(dev, "Failed adding mac: 0x%llx\n", mac); + table->refs[free] = 0; + table->entries[free] = 0; + goto out; + } + + *index = free; + ++table->total; + + //update port guid with mac address + update_ipv6_gids_win(dev, port, 0, mac); + +#if 0 + +// TODO: Tzachid 9/12/2009 Need to think of a better way of how to create the LLE +// interface + + + if(!InterlockedExchange(&dev->pdev->ib_hca_created, 1)) + { + NTSTATUS status = STATUS_SUCCESS; + status = __create_child(dev->pdev->p_wdf_device, BUS_HARDWARE_IDS, BUS_HARDWARE_DESCRIPTION, 0 ); + if (!NT_SUCCESS(status)) { + mlx4_err(dev, "__create_child (ib)failed with 0x%x\n", status); + dev->pdev->ib_hca_created = FALSE; + } + } +#endif +out: + up(&table->mac_sem); + return err; +} +EXPORT_SYMBOL_GPL(mlx4_register_mac); + +void mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, int index) +{ + struct mlx4_mac_table *table = + &mlx4_priv(dev)->port[port - 1].mac_table; + + down(&table->mac_sem); + if (!table->refs[index]) { + mlx4_warn(dev, "No mac entry for index %d\n", index); + goto out; + } + if (--table->refs[index]) { + mlx4_warn(dev, "Have more references for index %d," + "no need to modify mac table\n", index); + goto out; + } + table->entries[index] = 0; + if ( !mlx4_is_barred(dev) ) + mlx4_SET_PORT_mac_table(dev, port, table->entries); + --table->total; +out: + up(&table->mac_sem); +} +EXPORT_SYMBOL_GPL(mlx4_unregister_mac); + +static int mlx4_SET_PORT_vlan_table(struct mlx4_dev *dev, u8 port, + __be32 *entries) +{ + struct mlx4_cmd_mailbox *mailbox; + u32 in_mod; + int err; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + + memcpy(mailbox->buf, entries, MLX4_VLAN_TABLE_SIZE); + in_mod = MLX4_SET_PORT_VLAN_TABLE << 8 | port; + err = mlx4_cmd(dev, mailbox->dma.da, in_mod, 1, MLX4_CMD_SET_PORT, + MLX4_CMD_TIME_CLASS_B); + + mlx4_free_cmd_mailbox(dev, mailbox); + + return err; +} + +int mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index) +{ + struct mlx4_vlan_table *table = + &mlx4_priv(dev)->port[port - 1].vlan_table; + int i, err = 0; + int free = -1; + + down(&table->vlan_sem); + for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) { + if (free < 0 && (table->refs[i] == 0)) { + free = i; + continue; + } + + if (table->refs[i] && + (vlan == (MLX4_VLAN_MASK & + be32_to_cpu(table->entries[i])))) { + /* Vlan already registered, increase refernce count */ + *index = i; + ++table->refs[i]; + goto out; + } + } + + if (table->total == table->max || free < 0) { + /* No free vlan entries */ + err = -ENOSPC; + goto out; + } + + /* Register new MAC */ + table->refs[free] = 1; + table->entries[free] = cpu_to_be32(vlan | MLX4_VLAN_VALID); + + err = mlx4_SET_PORT_vlan_table(dev, port, table->entries); + if (unlikely(err)) { + mlx4_warn(dev, "Failed adding vlan: %u\n", vlan); + table->refs[free] = 0; + table->entries[free] = 0; + goto out; + } + + *index = free; + ++table->total; +out: + up(&table->vlan_sem); + return err; +} +EXPORT_SYMBOL_GPL(mlx4_register_vlan); + +void mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, int index) +{ + struct mlx4_vlan_table *table = + &mlx4_priv(dev)->port[port - 1].vlan_table; + + down(&table->vlan_sem); + if (!table->refs[index]) { + mlx4_warn(dev, "No vlan entry for index %d\n", index); + goto out; + } + if (--table->refs[index]) { + mlx4_dbg(dev, "Have more references for index %d," + "no need to modify vlan table\n", index); + goto out; + } + table->entries[index] = 0; + mlx4_SET_PORT_vlan_table(dev, port, table->entries); + --table->total; +out: + up(&table->vlan_sem); +} +EXPORT_SYMBOL_GPL(mlx4_unregister_vlan); + +int mlx4_SET_PORT(struct mlx4_dev *dev, u8 port, + int reset_qkey_viols, u32 cap_mask) +{ + struct mlx4_cmd_mailbox *mailbox; + int err; + u8 is_eth = (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH) ? 1 : 0; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + + memset(mailbox->buf, 0, 256); + if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) { + *(u8 *) mailbox->buf = (u8)(!!reset_qkey_viols << 6); + ((__be32 *) mailbox->buf)[2] = cpu_to_be32(cap_mask); + } else { + ((u8 *) mailbox->buf)[3] = (u8)!!reset_qkey_viols; + ((__be32 *) mailbox->buf)[1] = cpu_to_be32(cap_mask); + } + + if (is_eth) { + ((u8 *) mailbox->buf)[3] = 7; + ((__be16 *) mailbox->buf)[3] = + cpu_to_be16(dev->caps.eth_mtu_cap[port] + + ETH_HLEN + ETH_FCS_LEN); + ((__be16 *) mailbox->buf)[4] = cpu_to_be16(1 << 15); + ((__be16 *) mailbox->buf)[6] = cpu_to_be16(1 << 15); + } + err = mlx4_cmd(dev, mailbox->dma.da, port, is_eth, MLX4_CMD_SET_PORT, + MLX4_CMD_TIME_CLASS_B); + + mlx4_free_cmd_mailbox(dev, mailbox); + return err; +} + diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/net/profile.c b/branches/WOF2-3/hw/mlx4/kernel/bus/net/profile.c new file mode 100644 index 00000000..f566081a --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/net/profile.c @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "mlx4.h" +#include "fw.h" + +enum { + MLX4_RES_QP, + MLX4_RES_RDMARC, + MLX4_RES_ALTC, + MLX4_RES_AUXC, + MLX4_RES_SRQ, + MLX4_RES_CQ, + MLX4_RES_EQ, + MLX4_RES_DMPT, + MLX4_RES_CMPT, + MLX4_RES_MTT, + MLX4_RES_MCG, + MLX4_RES_NUM +}; + +static const char *res_name[] = { + "QP", /* [MLX4_RES_QP] */ + "RDMARC", /* [MLX4_RES_RDMARC] */ + "ALTC", /* [MLX4_RES_ALTC] */ + "AUXC", /* [MLX4_RES_AUXC] */ + "SRQ", /* [MLX4_RES_SRQ] */ + "CQ", /* [MLX4_RES_CQ] */ + "EQ", /* [MLX4_RES_EQ] */ + "DMPT", /* [MLX4_RES_DMPT] */ + "CMPT", /* [MLX4_RES_CMPT] */ + "MTT", /* [MLX4_RES_MTT] */ + "MCG" /* [MLX4_RES_MCG] */ +}; + +u64 mlx4_make_profile(struct mlx4_dev *dev, + struct mlx4_profile *request, + struct mlx4_dev_cap *dev_cap, + struct mlx4_init_hca_param *init_hca) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_resource { + u64 size; + u64 start; + int type; + int num; + int log_num; + }; + + u64 total_size = 0; + struct mlx4_resource *profile; + struct mlx4_resource tmp; + int i, j, max_eqs; + + profile = kzalloc(MLX4_RES_NUM * sizeof *profile, GFP_KERNEL); + if (!profile) + return (u64)-ENOMEM; + + profile[MLX4_RES_QP].size = dev_cap->qpc_entry_sz; + profile[MLX4_RES_RDMARC].size = dev_cap->rdmarc_entry_sz; + profile[MLX4_RES_ALTC].size = dev_cap->altc_entry_sz; + profile[MLX4_RES_AUXC].size = dev_cap->aux_entry_sz; + profile[MLX4_RES_SRQ].size = dev_cap->srq_entry_sz; + profile[MLX4_RES_CQ].size = dev_cap->cqc_entry_sz; + profile[MLX4_RES_EQ].size = dev_cap->eqc_entry_sz; + profile[MLX4_RES_DMPT].size = dev_cap->dmpt_entry_sz; + profile[MLX4_RES_CMPT].size = dev_cap->cmpt_entry_sz; + profile[MLX4_RES_MTT].size = MLX4_MTT_ENTRY_PER_SEG * dev_cap->mtt_entry_sz; + profile[MLX4_RES_MCG].size = MLX4_MGM_ENTRY_SIZE; + + profile[MLX4_RES_QP].num = request->num_qp; + profile[MLX4_RES_RDMARC].num = request->num_qp * request->rdmarc_per_qp; + profile[MLX4_RES_ALTC].num = request->num_qp; + profile[MLX4_RES_AUXC].num = request->num_qp; + profile[MLX4_RES_SRQ].num = request->num_srq; + profile[MLX4_RES_CQ].num = request->num_cq; + max_eqs = max( num_possible_cpus()+1, MLX4_NUM_EQS ); + profile[MLX4_RES_EQ].num = + min_t( unsigned, dev_cap->max_eqs, + max_eqs + dev_cap->reserved_eqs ); + profile[MLX4_RES_DMPT].num = request->num_mpt; + profile[MLX4_RES_CMPT].num = MLX4_NUM_CMPTS; + profile[MLX4_RES_MTT].num = request->num_mtt; + profile[MLX4_RES_MCG].num = request->num_mcg; + + for (i = 0; i < MLX4_RES_NUM; ++i) { + profile[i].type = i; + profile[i].num = roundup_pow_of_two(profile[i].num); + profile[i].log_num = ilog2(profile[i].num); + profile[i].size *= profile[i].num; + profile[i].size = max(profile[i].size, (u64) PAGE_SIZE); + } + + /* + * Sort the resources in decreasing order of size. Since they + * all have sizes that are powers of 2, we'll be able to keep + * resources aligned to their size and pack them without gaps + * using the sorted order. + */ + for (i = MLX4_RES_NUM; i > 0; --i) + for (j = 1; j < i; ++j) { + if (profile[j].size > profile[j - 1].size) { + tmp = profile[j]; + profile[j] = profile[j - 1]; + profile[j - 1] = tmp; + } + } + + for (i = 0; i < MLX4_RES_NUM; ++i) { + if (profile[i].size) { + profile[i].start = total_size; + total_size += profile[i].size; + } + + if (total_size > dev_cap->max_icm_sz) { + mlx4_err(dev, "Profile requires 0x%llx bytes; " + "won't fit in 0x%llx bytes of context memory.\n", + (unsigned long long) total_size, + (unsigned long long) dev_cap->max_icm_sz); + kfree(profile); + return (u64)-ENOMEM; + } + + if (profile[i].size) + mlx4_dbg(dev, " profile[%2d] (%6s): 2^%02d entries @ 0x%10llx, " + "size 0x%10llx\n", + i, res_name[profile[i].type], profile[i].log_num, + (unsigned long long) profile[i].start, + (unsigned long long) profile[i].size); + } + + mlx4_dbg(dev, "HCA context memory: reserving %d KB\n", + (int) (total_size >> 10)); + + for (i = 0; i < MLX4_RES_NUM; ++i) { + switch (profile[i].type) { + case MLX4_RES_QP: + dev->caps.num_qps = profile[i].num; + init_hca->qpc_base = profile[i].start; + init_hca->log_num_qps = (u8)profile[i].log_num; + break; + case MLX4_RES_RDMARC: + for (priv->qp_table.rdmarc_shift = 0; + request->num_qp << priv->qp_table.rdmarc_shift < profile[i].num; + ++priv->qp_table.rdmarc_shift) + ; /* nothing */ + dev->caps.max_qp_dest_rdma = 1 << priv->qp_table.rdmarc_shift; + priv->qp_table.rdmarc_base = (u32) profile[i].start; + init_hca->rdmarc_base = profile[i].start; + init_hca->log_rd_per_qp = (u8)priv->qp_table.rdmarc_shift; + break; + case MLX4_RES_ALTC: + init_hca->altc_base = profile[i].start; + break; + case MLX4_RES_AUXC: + init_hca->auxc_base = profile[i].start; + break; + case MLX4_RES_SRQ: + dev->caps.num_srqs = profile[i].num; + init_hca->srqc_base = profile[i].start; + init_hca->log_num_srqs = (u8)profile[i].log_num; + break; + case MLX4_RES_CQ: + dev->caps.num_cqs = profile[i].num; + init_hca->cqc_base = profile[i].start; + init_hca->log_num_cqs = (u8)profile[i].log_num; + break; + case MLX4_RES_EQ: + dev->caps.num_eqs = profile[i].num; + init_hca->eqc_base = profile[i].start; + init_hca->log_num_eqs = (u8)profile[i].log_num; + break; + case MLX4_RES_DMPT: + dev->caps.num_mpts = profile[i].num; + priv->mr_table.mpt_base = profile[i].start; + init_hca->dmpt_base = profile[i].start; + init_hca->log_mpt_sz = (u8)profile[i].log_num; + break; + case MLX4_RES_CMPT: + init_hca->cmpt_base = profile[i].start; + break; + case MLX4_RES_MTT: + dev->caps.num_mtt_segs = profile[i].num; + priv->mr_table.mtt_base = profile[i].start; + init_hca->mtt_base = profile[i].start; + break; + case MLX4_RES_MCG: + dev->caps.num_mgms = profile[i].num >> 1; + dev->caps.num_amgms = profile[i].num >> 1; + init_hca->mc_base = profile[i].start; + init_hca->log_mc_entry_sz = (u16)ilog2(MLX4_MGM_ENTRY_SIZE); + init_hca->log_mc_table_sz = (u8)profile[i].log_num; + init_hca->log_mc_hash_sz = (u16)profile[i].log_num - 1; + break; + default: + break; + } + } + + /* + * PDs don't take any HCA memory, but we assign them as part + * of the HCA profile anyway. + */ + dev->caps.num_pds = MLX4_NUM_PDS; + + kfree(profile); + return total_size; +} diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/net/qp.c b/branches/WOF2-3/hw/mlx4/kernel/bus/net/qp.c new file mode 100644 index 00000000..92138191 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/net/qp.c @@ -0,0 +1,429 @@ +/* + * Copyright (c) 2004 Topspin Communications. All rights reserved. + * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * Copyright (c) 2004 Voltaire, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + +#include "mlx4.h" +#include "icm.h" +#include "cmd.h" +#include "qp.h" + +void mlx4_qp_event(struct mlx4_dev *dev, u32 qpn, int event_type) +{ + struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table; + struct mlx4_qp *qp; + + spin_lock_dpc(&qp_table->lock); + + qp = __mlx4_qp_lookup(dev, qpn); + if (qp) + atomic_inc(&qp->refcount); + + spin_unlock_dpc(&qp_table->lock); + + if (!qp) { + mlx4_dbg(dev, "Async event %d for bogus QP %08x\n", + event_type, qpn); + return; + } + + qp->event(qp, event_type); + + if (atomic_dec_and_test(&qp->refcount)) + complete(&qp->free); +} + +int mlx4_qp_modify(struct mlx4_dev *dev, struct mlx4_mtt *mtt, + enum mlx4_qp_state cur_state, enum mlx4_qp_state new_state, + struct mlx4_qp_context *context, enum mlx4_qp_optpar optpar, + int sqd_event, struct mlx4_qp *qp) +{ + struct mlx4_cmd_mailbox *mailbox; + int ret = 0; + static u16 op[MLX4_QP_NUM_STATE][MLX4_QP_NUM_STATE]; + static int op_inited = 0; + + if ( mlx4_is_barred(dev) ) + return -EFAULT; + + if (!op_inited) { + op[MLX4_QP_STATE_RST][MLX4_QP_STATE_RST] = MLX4_CMD_2RST_QP; + op[MLX4_QP_STATE_RST][MLX4_QP_STATE_ERR] = MLX4_CMD_2ERR_QP; + op[MLX4_QP_STATE_RST][MLX4_QP_STATE_INIT] = MLX4_CMD_RST2INIT_QP; + + op[MLX4_QP_STATE_INIT][MLX4_QP_STATE_RST] = MLX4_CMD_2RST_QP; + op[MLX4_QP_STATE_INIT][MLX4_QP_STATE_ERR] = MLX4_CMD_2ERR_QP; + op[MLX4_QP_STATE_INIT][MLX4_QP_STATE_INIT] = MLX4_CMD_INIT2INIT_QP; + op[MLX4_QP_STATE_INIT][MLX4_QP_STATE_RTR] = MLX4_CMD_INIT2RTR_QP; + + op[MLX4_QP_STATE_RTR][MLX4_QP_STATE_RST] = MLX4_CMD_2RST_QP; + op[MLX4_QP_STATE_RTR][MLX4_QP_STATE_ERR] = MLX4_CMD_2ERR_QP; + op[MLX4_QP_STATE_RTR][MLX4_QP_STATE_RTS] = MLX4_CMD_RTR2RTS_QP; + + op[MLX4_QP_STATE_RTS][MLX4_QP_STATE_RST] = MLX4_CMD_2RST_QP; + op[MLX4_QP_STATE_RTS][MLX4_QP_STATE_ERR] = MLX4_CMD_2ERR_QP; + op[MLX4_QP_STATE_RTS][MLX4_QP_STATE_RTS] = MLX4_CMD_RTS2RTS_QP; + op[MLX4_QP_STATE_RTS][MLX4_QP_STATE_SQD] = MLX4_CMD_RTS2SQD_QP; + + op[MLX4_QP_STATE_SQD][MLX4_QP_STATE_RST] = MLX4_CMD_2RST_QP; + op[MLX4_QP_STATE_SQD][MLX4_QP_STATE_ERR] = MLX4_CMD_2ERR_QP; + op[MLX4_QP_STATE_SQD][MLX4_QP_STATE_RTS] = MLX4_CMD_SQD2RTS_QP; + op[MLX4_QP_STATE_SQD][MLX4_QP_STATE_SQD] = MLX4_CMD_SQD2SQD_QP; + + op[MLX4_QP_STATE_SQER][MLX4_QP_STATE_RST] = MLX4_CMD_2RST_QP; + op[MLX4_QP_STATE_SQER][MLX4_QP_STATE_ERR] = MLX4_CMD_2ERR_QP; + op[MLX4_QP_STATE_SQER][MLX4_QP_STATE_RTS] = MLX4_CMD_SQERR2RTS_QP; + + op[MLX4_QP_STATE_ERR][MLX4_QP_STATE_RST] = MLX4_CMD_2RST_QP; + op[MLX4_QP_STATE_ERR][MLX4_QP_STATE_ERR] = MLX4_CMD_2ERR_QP; + + op_inited = 1; + }; + + if (cur_state >= MLX4_QP_NUM_STATE || new_state >= MLX4_QP_NUM_STATE || + !op[cur_state][new_state]) + return -EINVAL; + + if (op[cur_state][new_state] == MLX4_CMD_2RST_QP) + return mlx4_cmd(dev, 0, qp->qpn, 2, + MLX4_CMD_2RST_QP, MLX4_CMD_TIME_CLASS_A); + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + + if (cur_state == MLX4_QP_STATE_RST && new_state == MLX4_QP_STATE_INIT) { + u64 mtt_addr = mlx4_mtt_addr(dev, mtt); + context->mtt_base_addr_h = (u8)(mtt_addr >> 32); + context->mtt_base_addr_l = cpu_to_be32(mtt_addr & 0xffffffff); + context->log_page_size = (u8)(mtt->page_shift - MLX4_ICM_PAGE_SHIFT); + } + + *(__be32 *) mailbox->buf = cpu_to_be32(optpar); + memcpy((u8*)mailbox->buf + 8, context, sizeof *context); + + ((struct mlx4_qp_context *) ((u8*)mailbox->buf + 8))->local_qpn = + cpu_to_be32(qp->qpn); + + ret = mlx4_cmd(dev, mailbox->dma.da, qp->qpn | (!!sqd_event << 31), + new_state == MLX4_QP_STATE_RST ? 2 : 0, + op[cur_state][new_state], MLX4_CMD_TIME_CLASS_C); + + mlx4_free_cmd_mailbox(dev, mailbox); + return ret; +} +EXPORT_SYMBOL_GPL(mlx4_qp_modify); + +int mlx4_qp_reserve_range(struct mlx4_dev *dev, int cnt, int align, u32 *base) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_qp_table *qp_table = &priv->qp_table; + int qpn; + + qpn = mlx4_bitmap_alloc_range(&qp_table->bitmap, cnt, align); + if (qpn == -1) + return -ENOMEM; + + *base = qpn; + return 0; +} +EXPORT_SYMBOL_GPL(mlx4_qp_reserve_range); + +void mlx4_qp_release_range(struct mlx4_dev *dev, int base_qpn, int cnt) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_qp_table *qp_table = &priv->qp_table; + if (base_qpn < dev->caps.sqp_start + 8) + return; + + mlx4_bitmap_free_range(&qp_table->bitmap, base_qpn, cnt); +} +EXPORT_SYMBOL_GPL(mlx4_qp_release_range); + +int mlx4_qp_alloc(struct mlx4_dev *dev, int qpn, struct mlx4_qp *qp) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_qp_table *qp_table = &priv->qp_table; + int err; + + if ( mlx4_is_barred(dev) ) + return -EFAULT; + + if (!qpn) + return -EINVAL; + + qp->qpn = qpn; + + err = mlx4_table_get(dev, &qp_table->qp_table, qp->qpn); + if (err) + goto err_out; + + err = mlx4_table_get(dev, &qp_table->auxc_table, qp->qpn); + if (err) + goto err_put_qp; + + err = mlx4_table_get(dev, &qp_table->altc_table, qp->qpn); + if (err) + goto err_put_auxc; + + err = mlx4_table_get(dev, &qp_table->rdmarc_table, qp->qpn); + if (err) + goto err_put_altc; + + err = mlx4_table_get(dev, &qp_table->cmpt_table, qp->qpn); + if (err) + goto err_put_rdmarc; + + spin_lock_irq(&qp_table->lock); + err = radix_tree_insert(&dev->qp_table_tree, qp->qpn & (dev->caps.num_qps - 1), qp); + spin_unlock_irq(&qp_table->lock); + if (err) + goto err_put_cmpt; + + atomic_set(&qp->refcount, 1); + init_completion(&qp->free); + + return 0; + +err_put_cmpt: + mlx4_table_put(dev, &qp_table->cmpt_table, qp->qpn); + +err_put_rdmarc: + mlx4_table_put(dev, &qp_table->rdmarc_table, qp->qpn); + +err_put_altc: + mlx4_table_put(dev, &qp_table->altc_table, qp->qpn); + +err_put_auxc: + mlx4_table_put(dev, &qp_table->auxc_table, qp->qpn); + +err_put_qp: + mlx4_table_put(dev, &qp_table->qp_table, qp->qpn); + +err_out: + return err; +} +EXPORT_SYMBOL_GPL(mlx4_qp_alloc); + +void mlx4_qp_remove(struct mlx4_dev *dev, struct mlx4_qp *qp) +{ + struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table; + unsigned long flags; + + spin_lock_irqsave(&qp_table->lock, &flags); + radix_tree_delete(&dev->qp_table_tree, qp->qpn & (dev->caps.num_qps - 1)); + spin_unlock_irqrestore(&qp_table->lock, flags); +} +EXPORT_SYMBOL_GPL(mlx4_qp_remove); + + +struct mlx4_qp *mlx4_qp_lookup_locked(struct mlx4_dev *dev, u32 qpn) +{ + struct mlx4_qp *qp; + struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table; + + spin_lock_irq(&qp_table->lock); + qp = radix_tree_lookup(&dev->qp_table_tree, qpn & (dev->caps.num_qps - 1)); + spin_unlock_irq(&qp_table->lock); + return qp; +} + +void mlx4_qp_free(struct mlx4_dev *dev, struct mlx4_qp *qp) +{ + struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table; + + if (atomic_dec_and_test(&qp->refcount)) + complete(&qp->free); + wait_for_completion(&qp->free); + + mlx4_table_put(dev, &qp_table->cmpt_table, qp->qpn); + mlx4_table_put(dev, &qp_table->rdmarc_table, qp->qpn); + mlx4_table_put(dev, &qp_table->altc_table, qp->qpn); + mlx4_table_put(dev, &qp_table->auxc_table, qp->qpn); + mlx4_table_put(dev, &qp_table->qp_table, qp->qpn); + +} +EXPORT_SYMBOL_GPL(mlx4_qp_free); + +static int mlx4_CONF_SPECIAL_QP(struct mlx4_dev *dev, u32 base_qpn) +{ + return mlx4_cmd(dev, 0, base_qpn, 0, MLX4_CMD_CONF_SPECIAL_QP, + MLX4_CMD_TIME_CLASS_B); +} + +int mlx4_init_qp_table(struct mlx4_dev *dev) +{ + struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table; + int err; + int reserved_from_top = 0; +// hard to believe, that someone will require less ! +#define MIN_QPS_TO_WORK_WITH 16 + + spin_lock_init(&qp_table->lock); + INIT_RADIX_TREE(&dev->qp_table_tree, GFP_ATOMIC); + + /* + * We reserve 2 extra QPs per port for the special QPs. The + * block of special QPs must be aligned to a multiple of 8, so + * round up. + */ + dev->caps.sqp_start = + ALIGN(dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW], 8); + + { + int sort[MLX4_QP_REGION_COUNT]; + int i, j, tmp; + int last_base = dev->caps.num_qps; + + for (i = 1; i < MLX4_QP_REGION_COUNT; ++i) + sort[i] = i; + + for (i = MLX4_QP_REGION_COUNT; i > 0; --i) { + for (j = 2; j < i; ++j) { + if (dev->caps.reserved_qps_cnt[sort[j]] > + dev->caps.reserved_qps_cnt[sort[j - 1]]) { + tmp = sort[j]; + sort[j] = sort[j - 1]; + sort[j - 1] = tmp; + } + } + } + + for (i = 1; i < MLX4_QP_REGION_COUNT; ++i) { + last_base -= dev->caps.reserved_qps_cnt[sort[i]]; + dev->caps.reserved_qps_base[sort[i]] = last_base; + reserved_from_top += + dev->caps.reserved_qps_cnt[sort[i]]; + } + + } + + dev->caps.total_reserved_qps = dev->caps.sqp_start + 8 + reserved_from_top; + if ( dev->caps.total_reserved_qps + MIN_QPS_TO_WORK_WITH > dev->caps.num_qps ) { + err= -EINVAL; + mlx4_dbg(dev, "Not enough QPs to work with. Requested %d, reserved %d\n", + dev->caps.num_qps, dev->caps.total_reserved_qps ); + WriteEventLogEntryData( dev->pdev->p_self_do, (ULONG)EVENT_MLX4_ERROR_NOT_ENOUGH_QPS, 0, 0, 2, + L"%d", dev->caps.num_qps, + L"%d", dev->caps.total_reserved_qps + ); + } + else { + err = mlx4_bitmap_init_with_effective_max(&qp_table->bitmap, + dev->caps.num_qps, + (1 << 23) - 1, + dev->caps.sqp_start + 8, + dev->caps.num_qps - reserved_from_top); + } + + if (err) + return err; + + return mlx4_CONF_SPECIAL_QP(dev, dev->caps.sqp_start); +} + +void mlx4_cleanup_qp_table(struct mlx4_dev *dev) +{ + mlx4_CONF_SPECIAL_QP(dev, 0); + mlx4_bitmap_cleanup(&mlx4_priv(dev)->qp_table.bitmap); + radix_tree_destroy(&dev->qp_table_tree); +} + +int mlx4_qp_get_region(struct mlx4_dev *dev, + enum qp_region region, + int *base_qpn, int *cnt) +{ + if ((region < 0) || (region >= MLX4_QP_REGION_COUNT)) + return -EINVAL; + + *base_qpn = dev->caps.reserved_qps_base[region]; + *cnt = dev->caps.reserved_qps_cnt[region]; + + return 0; +} +EXPORT_SYMBOL_GPL(mlx4_qp_get_region); + + +int mlx4_qp_query(struct mlx4_dev *dev, struct mlx4_qp *qp, + struct mlx4_qp_context *context) +{ + struct mlx4_cmd_mailbox *mailbox; + int err; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + + err = mlx4_cmd_box(dev, 0, mailbox->dma.da, qp->qpn, 0, + MLX4_CMD_QUERY_QP, MLX4_CMD_TIME_CLASS_A); + if (!err) + memcpy(context, (u8*)mailbox->buf + 8, sizeof *context); + + mlx4_free_cmd_mailbox(dev, mailbox); + return err; +} +EXPORT_SYMBOL_GPL(mlx4_qp_query); + +int mlx4_qp_to_ready(struct mlx4_dev *dev, + struct mlx4_mtt *mtt, + struct mlx4_qp_context *context, + struct mlx4_qp *qp, + enum mlx4_qp_state *qp_state) +{ +#define STATE_ARR_SIZE 4 + int err = 0; + int i; + enum mlx4_qp_state states[STATE_ARR_SIZE] = { + MLX4_QP_STATE_RST, + MLX4_QP_STATE_INIT, + MLX4_QP_STATE_RTR, + MLX4_QP_STATE_RTS + }; + + for (i = 0; i < STATE_ARR_SIZE - 1; i++) { + context->flags |= cpu_to_be32(states[i+1] << 28); + err = mlx4_qp_modify(dev, mtt, states[i], + states[i+1], context, 0, 0, qp); + if (err) { + mlx4_err(dev, "Failed to bring qp to state:" + "%d with error: %d\n", + states[i+1], err); + return err; + } + *qp_state = states[i+1]; + } + return 0; +} +EXPORT_SYMBOL_GPL(mlx4_qp_to_ready); + diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/net/reset.c b/branches/WOF2-3/hw/mlx4/kernel/bus/net/reset.c new file mode 100644 index 00000000..e69de29b diff --git a/branches/WOF2-3/hw/mlx4/kernel/bus/net/srq.c b/branches/WOF2-3/hw/mlx4/kernel/bus/net/srq.c new file mode 100644 index 00000000..1d2d1003 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/bus/net/srq.c @@ -0,0 +1,277 @@ +/* + * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + +#include "mlx4.h" +#include "icm.h" +#include "cmd.h" + +struct mlx4_srq_context { + __be32 state_logsize_srqn; + u8 logstride; + u8 reserved1; + __be16 xrc_domain; + __be32 pg_offset_cqn; + u32 reserved2; + u8 log_page_size; + u8 reserved3[2]; + u8 mtt_base_addr_h; + __be32 mtt_base_addr_l; + __be32 pd; + __be16 limit_watermark; + __be16 wqe_cnt; + u16 reserved4; + __be16 wqe_counter; + u32 reserved5; + __be64 db_rec_addr; +}; + +void mlx4_srq_event(struct mlx4_dev *dev, u32 srqn, int event_type) +{ + struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table; + struct mlx4_srq *srq; + + spin_lock_dpc(&srq_table->lock); + + srq = radix_tree_lookup(&srq_table->tree, srqn & (dev->caps.num_srqs - 1)); + if (srq) + atomic_inc(&srq->refcount); + + spin_unlock_dpc(&srq_table->lock); + + if (!srq) { + mlx4_warn(dev, "Async event for bogus SRQ %08x\n", srqn); + return; + } + + srq->event(srq, event_type); + + if (atomic_dec_and_test(&srq->refcount)) + complete(&srq->free); +} + +static int mlx4_SW2HW_SRQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, + int srq_num) +{ + return mlx4_cmd(dev, mailbox->dma.da, srq_num, 0, MLX4_CMD_SW2HW_SRQ, + MLX4_CMD_TIME_CLASS_A); +} + +static int mlx4_HW2SW_SRQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, + int srq_num) +{ + return mlx4_cmd_box(dev, 0, mailbox ? mailbox->dma.da : 0, srq_num, + mailbox ? 0 : 1, MLX4_CMD_HW2SW_SRQ, + MLX4_CMD_TIME_CLASS_A); +} + +static int mlx4_ARM_SRQ(struct mlx4_dev *dev, int srq_num, int limit_watermark) +{ + return mlx4_cmd(dev, limit_watermark, srq_num, 0, MLX4_CMD_ARM_SRQ, + MLX4_CMD_TIME_CLASS_B); +} + +static int mlx4_QUERY_SRQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, + int srq_num) +{ + return mlx4_cmd_box(dev, 0, mailbox->dma.da, srq_num, 0, MLX4_CMD_QUERY_SRQ, + MLX4_CMD_TIME_CLASS_A); +} + +int mlx4_srq_alloc(struct mlx4_dev *dev, u32 pdn, u32 cqn, u16 xrcd, + struct mlx4_mtt *mtt, u64 db_rec, struct mlx4_srq *srq) +{ + struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table; + struct mlx4_cmd_mailbox *mailbox; + struct mlx4_srq_context *srq_context; + u64 mtt_addr; + int err; + UNREFERENCED_PARAMETER(xrcd); + + if ( mlx4_is_barred(dev) ) + return -EFAULT; + + srq->srqn = mlx4_bitmap_alloc(&srq_table->bitmap); + if (srq->srqn == -1) + return -ENOMEM; + + err = mlx4_table_get(dev, &srq_table->table, srq->srqn); + if (err) + goto err_out; + + err = mlx4_table_get(dev, &srq_table->cmpt_table, srq->srqn); + if (err) + goto err_put; + + spin_lock_irq(&srq_table->lock); + err = radix_tree_insert(&srq_table->tree, srq->srqn, srq); + spin_unlock_irq(&srq_table->lock); + if (err) + goto err_cmpt_put; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) { + err = PTR_ERR(mailbox); + goto err_radix; + } + + srq_context = mailbox->buf; + memset(srq_context, 0, sizeof *srq_context); + + srq_context->state_logsize_srqn = cpu_to_be32((ilog2(srq->max) << 24) | + srq->srqn); + srq_context->logstride = (u8)(srq->wqe_shift - 4); + srq_context->pg_offset_cqn = cpu_to_be32(cqn & 0xffffff); + srq_context->log_page_size = (u8)(mtt->page_shift - MLX4_ICM_PAGE_SHIFT); + + mtt_addr = mlx4_mtt_addr(dev, mtt); + srq_context->mtt_base_addr_h = (u8)(mtt_addr >> 32); + srq_context->mtt_base_addr_l = cpu_to_be32(mtt_addr & 0xffffffff); + srq_context->pd = cpu_to_be32(pdn); + srq_context->db_rec_addr = cpu_to_be64(db_rec); + + err = mlx4_SW2HW_SRQ(dev, mailbox, srq->srqn); + mlx4_free_cmd_mailbox(dev, mailbox); + if (err) + goto err_radix; + + atomic_set(&srq->refcount, 1); + init_completion(&srq->free); + + return 0; + +err_radix: + spin_lock_irq(&srq_table->lock); + radix_tree_delete(&srq_table->tree, srq->srqn); + spin_unlock_irq(&srq_table->lock); + +err_cmpt_put: + mlx4_table_put(dev, &srq_table->cmpt_table, srq->srqn); + +err_put: + mlx4_table_put(dev, &srq_table->table, srq->srqn); + +err_out: + mlx4_bitmap_free(&srq_table->bitmap, srq->srqn); + + return err; +} +EXPORT_SYMBOL_GPL(mlx4_srq_alloc); + + + +void mlx4_srq_invalidate(struct mlx4_dev *dev, struct mlx4_srq *srq) +{ + int err; + + if ( mlx4_is_barred(dev) ) + return; + + err = mlx4_HW2SW_SRQ(dev, NULL, srq->srqn); + if (err) + mlx4_warn(dev, "HW2SW_SRQ failed (%d) for SRQN %06x\n", err, srq->srqn); +} +EXPORT_SYMBOL_GPL(mlx4_srq_invalidate); + +void mlx4_srq_remove(struct mlx4_dev *dev, struct mlx4_srq *srq) +{ + struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table; + + spin_lock_irq(&srq_table->lock); + radix_tree_delete(&srq_table->tree, srq->srqn); + spin_unlock_irq(&srq_table->lock); +} +EXPORT_SYMBOL_GPL(mlx4_srq_remove); + +void mlx4_srq_free(struct mlx4_dev *dev, struct mlx4_srq *srq) +{ + struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table; + + if (atomic_dec_and_test(&srq->refcount)) + complete(&srq->free); + wait_for_completion(&srq->free); + + mlx4_table_put(dev, &srq_table->table, srq->srqn); + mlx4_bitmap_free(&srq_table->bitmap, srq->srqn); +} +EXPORT_SYMBOL_GPL(mlx4_srq_free); + +int mlx4_srq_arm(struct mlx4_dev *dev, struct mlx4_srq *srq, int limit_watermark) +{ + return mlx4_ARM_SRQ(dev, srq->srqn, limit_watermark); +} +EXPORT_SYMBOL_GPL(mlx4_srq_arm); + +int mlx4_srq_query(struct mlx4_dev *dev, struct mlx4_srq *srq, int *limit_watermark) +{ + struct mlx4_cmd_mailbox *mailbox; + struct mlx4_srq_context *srq_context; + int err; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + + srq_context = mailbox->buf; + + err = mlx4_QUERY_SRQ(dev, mailbox, srq->srqn); + if (err) + goto err_out; + *limit_watermark = be16_to_cpu(srq_context->limit_watermark); + +err_out: + mlx4_free_cmd_mailbox(dev, mailbox); + return err; +} +EXPORT_SYMBOL_GPL(mlx4_srq_query); + +int mlx4_init_srq_table(struct mlx4_dev *dev) +{ + struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table; + int err; + + spin_lock_init(&srq_table->lock); + INIT_RADIX_TREE(&srq_table->tree, GFP_ATOMIC); + + err = mlx4_bitmap_init(&srq_table->bitmap, dev->caps.num_srqs, + dev->caps.num_srqs - 1, dev->caps.reserved_srqs); + if (err) + return err; + + return 0; +} + +void mlx4_cleanup_srq_table(struct mlx4_dev *dev) +{ + mlx4_bitmap_cleanup(&mlx4_priv(dev)->srq_table.bitmap); + radix_tree_destroy(&mlx4_priv(dev)->srq_table.tree); +} diff --git a/branches/WOF2-3/hw/mlx4/kernel/dirs b/branches/WOF2-3/hw/mlx4/kernel/dirs new file mode 100644 index 00000000..4f2a471f --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/dirs @@ -0,0 +1,3 @@ +DIRS=\ + hca \ + bus diff --git a/branches/WOF2-3/hw/mlx4/kernel/hca/Makefile b/branches/WOF2-3/hw/mlx4/kernel/hca/Makefile new file mode 100644 index 00000000..ddc9da43 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/hca/Makefile @@ -0,0 +1,6 @@ +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the Windows NT DDK +# + +!INCLUDE ..\..\..\..\inc\openib.def diff --git a/branches/WOF2-3/hw/mlx4/kernel/hca/SOURCES b/branches/WOF2-3/hw/mlx4/kernel/hca/SOURCES new file mode 100644 index 00000000..f497a488 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/hca/SOURCES @@ -0,0 +1,63 @@ +TARGETNAME=mlx4_hca +TARGETPATH=..\..\..\..\bin\kernel\obj$(BUILD_ALT_DIR) +TARGETTYPE=DRIVER + +# WDK build only - transform .inx --> .inf adding date & version stamp. +# see .\makefile.inc +INF_NAME=$(TARGETNAME) +INF_TARGET=..\..\..\..\bin\kernel\$(O)\$(INF_NAME).inf +NTTARGETFILES=$(INF_TARGET) + +!if $(FREEBUILD) +ENABLE_EVENT_TRACING=1 +!else +#ENABLE_EVENT_TRACING=1 +!endif + +SOURCES= \ + hca.rc \ + av.c \ + ca.c \ + cq.c \ + data.c \ + direct.c \ + drv.c \ + fw.c \ + mcast.c \ + mr.c \ + pd.c \ + qp.c \ + srq.c \ + hverbs.c \ + vp.c \ + wmi.c \ + +INCLUDES=..;..\inc;..\..\inc;..\bus\inc;..\bus\ib;..\bus\core\$O;..\..\..\..\inc;..\..\..\..\inc\kernel; + +PRECOMPILED_INCLUDE=precomp.h + +NTTARGETFILE0=mofcomp + +KMDF_VERSION_MAJOR=1 + +C_DEFINES=$(C_DEFINES) -DDRIVER -DDEPRECATE_DDK_FUNCTIONS -D__LITTLE_ENDIAN +#-DUSE_WDM_FRAMEWORK + +TARGETLIBS= \ + $(TARGETPATH)\*\complib.lib \ + $(DDK_LIB_PATH)\ntstrsafe.lib \ + +#LINKER_FLAGS=/MAP + +!IFDEF ENABLE_EVENT_TRACING + +C_DEFINES = $(C_DEFINES) -DEVENT_TRACING +RUN_WPP= $(SOURCES) -km -ext: .c .h .C .H \ + -scan:debug.h \ + -func:HCA_PRINT(LEVEL,FLAGS,(MSG,...)) +!ENDIF + +# -func:HCA_PRINT_EV(LEVEL,FLAGS,(MSG,...)) \ + +MSC_OPTIMIZATION=/Oi +MSC_WARNING_LEVEL= /W4 diff --git a/branches/WOF2-3/hw/mlx4/kernel/hca/av.c b/branches/WOF2-3/hw/mlx4/kernel/hca/av.c new file mode 100644 index 00000000..3184874d --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/hca/av.c @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: al.c 1611 2006-08-20 14:48:55Z sleybo $ + */ + +#include "precomp.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "av.tmh" +#endif + +/* +* Address Vector Management Verbs +*/ +ib_api_status_t +mlnx_create_av ( + IN const ib_pd_handle_t h_pd, + IN const ib_av_attr_t *p_ib_av_attr, + OUT ib_av_handle_t *ph_av, + IN OUT ci_umv_buf_t *p_umv_buf ) +{ + int err = 0; + ib_api_status_t status = IB_SUCCESS; + struct ib_pd *p_ib_pd = (struct ib_pd *)h_pd; + struct ib_ah *p_ib_ah; + struct ib_ah_attr ah_attr; + struct ib_ucontext *p_uctx = NULL; + + HCA_ENTER(HCA_DBG_AV); + + if (p_umv_buf && p_umv_buf->command) { + status = IB_UNSUPPORTED; + goto err_nosys; + } + + // fill parameters + err = to_av( p_ib_pd->device, p_ib_av_attr, &ah_attr ); + if (err) { + status = errno_to_iberr(err); + goto err_to_av; + } + + // create AV + p_ib_ah = p_ib_pd->device->create_ah(p_ib_pd, &ah_attr); + if (IS_ERR(p_ib_ah)) { + err = PTR_ERR(p_ib_ah); + status = errno_to_iberr(err); + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_AV ,("create_ah failed (%d)\n", err)); + goto err_create_ah; + } + + // fill results + p_ib_ah->device = p_ib_pd->device; + p_ib_ah->pd = p_ib_pd; + p_ib_ah->p_uctx = p_uctx; + atomic_inc(&p_ib_pd->usecnt); + HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_AV ,("PD%d use cnt %d, pd_handle %p, ctx %p \n", + ((struct mlx4_ib_pd*)p_ib_pd)->pdn, p_ib_pd->usecnt, p_ib_pd, p_ib_pd->p_uctx)); + + // return the result + if (ph_av) *ph_av = (ib_av_handle_t)p_ib_ah; + + status = IB_SUCCESS; + +err_create_ah: +err_to_av: +err_nosys: + if (p_umv_buf && p_umv_buf->command) + p_umv_buf->status = status; + if (status != IB_SUCCESS) + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_AV, + ("completes with ERROR status %x\n", status)); + HCA_EXIT(HCA_DBG_AV); + return status; +} + +ib_api_status_t +mlnx_query_av ( + IN const ib_av_handle_t h_av, + OUT ib_av_attr_t *p_ib_av_attr, + OUT ib_pd_handle_t *ph_pd, + IN OUT ci_umv_buf_t *p_umv_buf ) +{ + int err; + ib_api_status_t status = IB_SUCCESS; + struct ib_ah *p_ib_ah = (struct ib_ah *)h_av; + struct ib_ah_attr ah_attr; + UNUSED_PARAM(p_umv_buf); + + HCA_ENTER(HCA_DBG_AV); + + if (p_umv_buf && p_umv_buf->command) { + status = IB_UNSUPPORTED; + goto err_nosys; + } + + // query AV + err = p_ib_ah->device->query_ah(p_ib_ah, &ah_attr); + if (err) { + status = errno_to_iberr(err); + goto err_query_ah; + } + + // results + if (ph_pd) + *ph_pd = (ib_pd_handle_t)p_ib_ah->pd; + err = from_av( p_ib_ah->device, NULL, &ah_attr, p_ib_av_attr ); + status = errno_to_iberr(err); + +err_query_ah: +err_nosys: + if (p_umv_buf && p_umv_buf->command) + p_umv_buf->status = status; + if (status != IB_SUCCESS) + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_AV, + ("completes with ERROR status %x\n", status)); + HCA_EXIT(HCA_DBG_AV); + return status; +} + +ib_api_status_t +mlnx_modify_av ( + IN const ib_av_handle_t h_av, + IN const ib_av_attr_t *p_ib_av_attr, + IN OUT ci_umv_buf_t *p_umv_buf ) +{ + int err; + struct ib_ah_attr ah_attr; + ib_api_status_t status = IB_SUCCESS; + struct ib_ah *p_ib_ah = (struct ib_ah *)h_av; + UNUSED_PARAM(p_umv_buf); + + HCA_ENTER(HCA_DBG_AV); + + if (p_umv_buf && p_umv_buf->command) { + status = IB_UNSUPPORTED; + goto err_nosys; + } + + // fill parameters + err = to_av( p_ib_ah->device, p_ib_av_attr, &ah_attr ); + if (err) { + status = errno_to_iberr(err); + goto err_to_av; + } + + // modify AV + if (p_ib_ah->device->modify_ah) + err = p_ib_ah->device->modify_ah(p_ib_ah, &ah_attr); + else + err = -ENOSYS; + status = errno_to_iberr(err); + +err_to_av: +err_nosys: + if (p_umv_buf && p_umv_buf->command) + p_umv_buf->status = status; + if (status != IB_SUCCESS) + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_AV, + ("completes with ERROR status %x\n", status)); + HCA_EXIT(HCA_DBG_AV); + return status; +} + +ib_api_status_t +mlnx_destroy_av ( + IN const ib_av_handle_t h_av) +{ + int err; + ib_api_status_t status = IB_SUCCESS; + struct ib_ah *p_ib_ah = (struct ib_ah *)h_av; + struct ib_pd *pd = p_ib_ah->pd; + + HCA_ENTER(HCA_DBG_AV); + + // destroy AV + err = p_ib_ah->device->destroy_ah(p_ib_ah); + if (!err) { + atomic_dec(&pd->usecnt); + HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_MEMORY ,("pdn %d, usecnt %d, pd_handle %p, ctx %p \n", + ((struct mlx4_ib_pd*)pd)->pdn, pd->usecnt, pd, pd->p_uctx)); + } + status = errno_to_iberr(err); + + if (status != IB_SUCCESS) + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_AV, + ("completes with ERROR status %x\n", status)); + HCA_EXIT(HCA_DBG_AV); + return status; +} + + + + +void +mlnx_av_if( + IN OUT ci_interface_t *p_interface ) +{ + p_interface->create_av = mlnx_create_av; + p_interface->query_av = mlnx_query_av; + p_interface->modify_av = mlnx_modify_av; + p_interface->destroy_av = mlnx_destroy_av; +} + diff --git a/branches/WOF2-3/hw/mlx4/kernel/hca/ca.c b/branches/WOF2-3/hw/mlx4/kernel/hca/ca.c new file mode 100644 index 00000000..6a3352f8 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/hca/ca.c @@ -0,0 +1,458 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: al.c 1611 2006-08-20 14:48:55Z sleybo $ + */ + +#include "precomp.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "ca.tmh" +#endif + +ib_api_status_t +mlnx_open_ca ( + IN const ib_net64_t ca_guid, // IN const char * ca_name, + IN const ci_async_event_cb_t pfn_async_event_cb, + IN const void*const ca_context, + OUT ib_ca_handle_t *ph_ca) +{ + mlnx_hca_t *p_hca; + ib_api_status_t status = IB_NOT_FOUND; + struct ib_device *p_ibdev; + + HCA_ENTER(HCA_DBG_SHIM); + HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_SHIM, + ("context 0x%p\n", ca_context)); + + // find CA object + p_hca = mlnx_hca_from_guid( ca_guid ); + if( !p_hca ) { + if (status != IB_SUCCESS) + { + HCA_PRINT(TRACE_LEVEL_ERROR , HCA_DBG_SHIM, + ("completes with ERROR status IB_NOT_FOUND\n")); + } + HCA_EXIT(HCA_DBG_SHIM); + return IB_NOT_FOUND; + } + + p_ibdev = hca2ibdev(p_hca); + + if (hca_is_livefish(hca2fdo(p_hca))) + goto done; + + HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_SHIM, + ("context 0x%p\n", ca_context)); + if (pfn_async_event_cb) { + status = mlnx_set_cb(p_hca, + pfn_async_event_cb, + ca_context); + if (IB_SUCCESS != status) { + goto err_set_cb; + } + } + + + //TODO: do we need something for kernel users ? + + // Return pointer to HCA object +done: + if (ph_ca) *ph_ca = (ib_ca_handle_t)p_hca; + status = IB_SUCCESS; + +//err_mad_cache: +err_set_cb: + if (status != IB_SUCCESS) + { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_SHIM, + ("completes with ERROR status %x\n", status)); + } + HCA_EXIT(HCA_DBG_SHIM); + return status; +} + +static void +mlnx_register_event_handler ( + IN const ib_ca_handle_t h_ca, + IN ci_event_handler_t* p_reg) +{ + mlnx_hca_t *p_hca = (mlnx_hca_t *) h_ca; + KIRQL irql; + + KeAcquireSpinLock(&p_hca->event_list_lock, &irql); + InsertTailList(&p_hca->event_list, &p_reg->entry); + KeReleaseSpinLock(&p_hca->event_list_lock, irql); +} + +static void +mlnx_unregister_event_handler ( + IN const ib_ca_handle_t h_ca, + IN ci_event_handler_t* p_reg) +{ + mlnx_hca_t *p_hca = (mlnx_hca_t *) h_ca; + KIRQL irql; + + KeAcquireSpinLock(&p_hca->event_list_lock, &irql); + RemoveEntryList(&p_reg->entry); + KeReleaseSpinLock(&p_hca->event_list_lock, irql); +} + +ib_api_status_t +mlnx_query_ca ( + IN const ib_ca_handle_t h_ca, + OUT ib_ca_attr_t *p_ca_attr, + IN OUT uint32_t *p_byte_count, + IN OUT ci_umv_buf_t *p_umv_buf ) +{ + int i; + int err; + ib_api_status_t status; + uint32_t size, required_size; + int port_num, num_ports; + uint32_t num_gids, num_pkeys; + uint32_t num_page_sizes = 1; // TBD: what is actually supported + uint8_t *last_p; + struct ib_device_attr props; + struct ib_port_attr *hca_ports = NULL; + mlnx_hca_t *p_hca = (mlnx_hca_t *)h_ca; + struct ib_device *p_ibdev = hca2ibdev(p_hca); + + + HCA_ENTER(HCA_DBG_SHIM); + + // sanity checks + if( p_umv_buf && p_umv_buf->command ) { + HCA_PRINT (TRACE_LEVEL_ERROR, HCA_DBG_SHIM ,("User mode is not supported yet\n")); + p_umv_buf->status = status = IB_UNSUPPORTED; + goto err_user_unsupported; + } + + if( !cl_is_blockable() ) { + status = IB_UNSUPPORTED; + goto err_unsupported; + } + + if (NULL == p_byte_count) { + status = IB_INVALID_PARAMETER; + goto err_byte_count; + } + + // handle "livefish" case + RtlZeroMemory(&props, sizeof(props)); + if ( hca_is_livefish(hca2fdo(p_hca)) ) { + struct pci_dev *pdev = hca2pdev(p_hca); + props.max_pd = 1; + props.vendor_id = pdev->ven_id; + props.vendor_part_id = pdev->dev_id; + num_ports = 0; + goto fill_the_rest; + } + + // query the device + err = p_ibdev->query_device(p_ibdev, &props); + if (err) { + HCA_PRINT (TRACE_LEVEL_ERROR, HCA_DBG_SHIM, + ("ib_query_device failed (%d)\n",err)); + status = errno_to_iberr(err); + goto err_query_device; + } + + // allocate array for port properties + num_ports = p_ibdev->phys_port_cnt; /* Number of physical ports of the HCA */ + if ( num_ports ) + if (NULL == (hca_ports = cl_zalloc( num_ports * sizeof *hca_ports))) { + HCA_PRINT (TRACE_LEVEL_ERROR, HCA_DBG_SHIM, ("Failed to cl_zalloc ports array\n")); + status = IB_INSUFFICIENT_MEMORY; + goto err_alloc_ports; + } + + // start calculation of ib_ca_attr_t full size +fill_the_rest: + num_gids = 0; + num_pkeys = 0; + required_size = PTR_ALIGN(sizeof(ib_ca_attr_t)) + + PTR_ALIGN(sizeof(uint32_t) * num_page_sizes) + + PTR_ALIGN(sizeof(ib_port_attr_t) * num_ports)+ + PTR_ALIGN(MLX4_BOARD_ID_LEN)+ + PTR_ALIGN(sizeof(uplink_info_t)); /* uplink info */ + + // get port properties + for (port_num = 0; port_num < num_ports; ++port_num) { + // request + err = p_ibdev->query_port(p_ibdev, (u8)(port_num + start_port(p_ibdev)), &hca_ports[port_num]); + if (err) { + HCA_PRINT (TRACE_LEVEL_ERROR, HCA_DBG_SHIM, ("ib_query_port failed(%d) for port %d\n",err, port_num)); + status = errno_to_iberr(err); + goto err_query_port; + } + + // calculate GID table size + num_gids = hca_ports[port_num].gid_tbl_len; + size = PTR_ALIGN(sizeof(ib_gid_t) * num_gids); + required_size += size; + + // calculate pkeys table size + num_pkeys = hca_ports[port_num].pkey_tbl_len; + size = PTR_ALIGN(sizeof(uint16_t) * num_pkeys); + required_size += size; + } + + // resource sufficience check + if (NULL == p_ca_attr || *p_byte_count < required_size) { + *p_byte_count = required_size; + status = IB_INSUFFICIENT_MEMORY; + if ( p_ca_attr != NULL) { + HCA_PRINT (TRACE_LEVEL_ERROR,HCA_DBG_SHIM, + ("Failed *p_byte_count (%d) < required_size (%d)\n", *p_byte_count, required_size )); + } + goto err_insuff_mem; + } + RtlZeroMemory(p_ca_attr, required_size); + + // Space is sufficient - setup table pointers + last_p = (uint8_t*)p_ca_attr; + last_p += PTR_ALIGN(sizeof(*p_ca_attr)); + + p_ca_attr->p_page_size = (uint32_t*)last_p; + last_p += PTR_ALIGN(num_page_sizes * sizeof(uint32_t)); + + p_ca_attr->p_port_attr = (ib_port_attr_t *)last_p; + last_p += PTR_ALIGN(num_ports * sizeof(ib_port_attr_t)); + + for (port_num = 0; port_num < num_ports; port_num++) { + p_ca_attr->p_port_attr[port_num].p_gid_table = (ib_gid_t *)last_p; + size = PTR_ALIGN(sizeof(ib_gid_t) * hca_ports[port_num].gid_tbl_len); + last_p += size; + + p_ca_attr->p_port_attr[port_num].p_pkey_table = (uint16_t *)last_p; + size = PTR_ALIGN(sizeof(uint16_t) * hca_ports[port_num].pkey_tbl_len); + last_p += size; + } + + //copy vendor specific data + cl_memcpy(last_p,hca2mdev(p_hca)->board_id, MLX4_BOARD_ID_LEN); + last_p += PTR_ALIGN(MLX4_BOARD_ID_LEN); + *(uplink_info_t*)last_p = hca2pdev(p_hca)->uplink_info; + last_p += PTR_ALIGN(sizeof(uplink_info_t)); /* uplink info */ + + // Separate the loops to ensure that table pointers are always setup + for (port_num = 0; port_num < num_ports; port_num++) { + + // get pkeys, using cache + for (i=0; i < hca_ports[port_num].pkey_tbl_len; ++i) { + err = p_ibdev->x.get_cached_pkey( p_ibdev, (u8)(port_num + start_port(p_ibdev)), i, + &p_ca_attr->p_port_attr[port_num].p_pkey_table[i] ); + if (err) { + status = errno_to_iberr(err); + HCA_PRINT (TRACE_LEVEL_ERROR,HCA_DBG_SHIM, + ("ib_get_cached_pkey failed (%d) for port_num %d, index %d\n", + err, port_num + start_port(p_ibdev), i)); + goto err_get_pkey; + } + } + + // get gids, using cache + for (i=0; i < hca_ports[port_num].gid_tbl_len; ++i) { + union ib_gid * gid = (union ib_gid *)&p_ca_attr->p_port_attr[port_num].p_gid_table[i]; + err = p_ibdev->x.get_cached_gid( p_ibdev, (u8)(port_num + start_port(p_ibdev)), i, (union ib_gid *)gid ); + //TODO: do we need to convert gids to little endian + if (err) { + status = errno_to_iberr(err); + HCA_PRINT (TRACE_LEVEL_ERROR, HCA_DBG_SHIM, + ("ib_get_cached_gid failed (%d) for port_num %d, index %d\n", + err, port_num + start_port(p_ibdev), i)); + goto err_get_gid; + } + } + + HCA_PRINT(TRACE_LEVEL_VERBOSE, HCA_DBG_SHIM,("port %d gid0:\n", port_num)); + HCA_PRINT(TRACE_LEVEL_VERBOSE, HCA_DBG_SHIM, + (" 0x%x%x%x%x%x%x%x%x-0x%x%x%x%x%x%x%x%x\n", + p_ca_attr->p_port_attr[port_num].p_gid_table[0].raw[0], + p_ca_attr->p_port_attr[port_num].p_gid_table[0].raw[1], + p_ca_attr->p_port_attr[port_num].p_gid_table[0].raw[2], + p_ca_attr->p_port_attr[port_num].p_gid_table[0].raw[3], + p_ca_attr->p_port_attr[port_num].p_gid_table[0].raw[4], + p_ca_attr->p_port_attr[port_num].p_gid_table[0].raw[5], + p_ca_attr->p_port_attr[port_num].p_gid_table[0].raw[6], + p_ca_attr->p_port_attr[port_num].p_gid_table[0].raw[7], + p_ca_attr->p_port_attr[port_num].p_gid_table[0].raw[8], + p_ca_attr->p_port_attr[port_num].p_gid_table[0].raw[9], + p_ca_attr->p_port_attr[port_num].p_gid_table[0].raw[10], + p_ca_attr->p_port_attr[port_num].p_gid_table[0].raw[11], + p_ca_attr->p_port_attr[port_num].p_gid_table[0].raw[12], + p_ca_attr->p_port_attr[port_num].p_gid_table[0].raw[13], + p_ca_attr->p_port_attr[port_num].p_gid_table[0].raw[14], + p_ca_attr->p_port_attr[port_num].p_gid_table[0].raw[15])); + } + + // set result size + p_ca_attr->size = required_size; + CL_ASSERT( required_size == (((uintn_t)last_p) - ((uintn_t)p_ca_attr)) ); + HCA_PRINT(TRACE_LEVEL_VERBOSE, HCA_DBG_SHIM , ("Space required %d used %d\n", + required_size, (int)((uintn_t)last_p - (uintn_t)p_ca_attr) )); + + // !!! GID/PKEY tables must be queried before this call !!! + from_hca_cap(p_ibdev, &props, hca_ports, p_ca_attr); + if ( hca_is_livefish(hca2fdo(p_hca)) ) + p_ca_attr->num_ports = 0; + + status = IB_SUCCESS; + +err_get_gid: +err_get_pkey: +err_insuff_mem: +err_query_port: + if (hca_ports) + cl_free(hca_ports); +err_alloc_ports: +err_query_device: +err_byte_count: +err_unsupported: +err_user_unsupported: + if( status != IB_INSUFFICIENT_MEMORY && status != IB_SUCCESS ) + HCA_PRINT(TRACE_LEVEL_ERROR, HCA_DBG_SHIM, + ("completes with ERROR status %x\n", status)); + + HCA_EXIT(HCA_DBG_SHIM); + return status; +} + +ib_api_status_t +mlnx_modify_ca ( + IN const ib_ca_handle_t h_ca, + IN const uint8_t port_num, + IN const ib_ca_mod_t modca_cmd, + IN const ib_port_attr_mod_t *p_port_attr) +{ +#define SET_CAP_MOD(al_mask, al_fld, ib) \ + if (modca_cmd & al_mask) { \ + if (p_port_attr->cap.##al_fld) \ + props.set_port_cap_mask |= ib; \ + else \ + props.clr_port_cap_mask |= ib; \ + } + + ib_api_status_t status; + int err; + struct ib_port_modify props; + int port_modify_mask = 0; + mlnx_hca_t *p_hca = (mlnx_hca_t *)h_ca; + struct ib_device *p_ibdev = hca2ibdev(p_hca); + + HCA_ENTER(HCA_DBG_SHIM); + + //sanity check + if( !cl_is_blockable() ) { + status = IB_UNSUPPORTED; + goto err_unsupported; + } + + if (port_num < start_port(p_ibdev) || port_num > end_port(p_ibdev)) { + status = IB_INVALID_PORT; + goto err_port; + } + + // prepare parameters + RtlZeroMemory(&props, sizeof(props)); + SET_CAP_MOD(IB_CA_MOD_IS_SM, sm, IB_PORT_SM); + SET_CAP_MOD(IB_CA_MOD_IS_SNMP_SUPPORTED, snmp, IB_PORT_SNMP_TUNNEL_SUP); + SET_CAP_MOD(IB_CA_MOD_IS_DEV_MGMT_SUPPORTED, dev_mgmt, IB_PORT_DEVICE_MGMT_SUP); + SET_CAP_MOD(IB_CA_MOD_IS_VEND_SUPPORTED, vend, IB_PORT_VENDOR_CLASS_SUP); + if ((modca_cmd & IB_CA_MOD_QKEY_CTR) && (p_port_attr->qkey_ctr == 0)) + port_modify_mask |= IB_PORT_RESET_QKEY_CNTR; + + // modify port + err = p_ibdev->modify_port(p_ibdev, port_num, port_modify_mask, &props ); + if (err) { + status = errno_to_iberr(err); + HCA_PRINT(TRACE_LEVEL_ERROR , HCA_DBG_SHIM ,("ib_modify_port failed (%d) \n",err)); + goto err_modify_port; + } + + status = IB_SUCCESS; + +err_modify_port: +err_port: +err_unsupported: + if (status != IB_SUCCESS) + { + HCA_PRINT(TRACE_LEVEL_ERROR, HCA_DBG_SHIM, + ("completes with ERROR status %x\n", status)); + } + HCA_EXIT(HCA_DBG_SHIM); + return status; +} + +ib_api_status_t +mlnx_close_ca ( + IN ib_ca_handle_t h_ca) +{ + mlnx_hca_t *p_hca = (mlnx_hca_t *)h_ca; + HCA_ENTER(HCA_DBG_SHIM); + + + if (hca_is_livefish(hca2fdo(p_hca))) + goto done; + + mlnx_reset_cb(p_hca); + +done: + HCA_EXIT(HCA_DBG_SHIM); + + return IB_SUCCESS; +} + + + +void +mlnx_ca_if( + IN OUT ci_interface_t *p_interface ) +{ + p_interface->open_ca = mlnx_open_ca; + p_interface->modify_ca = mlnx_modify_ca; + p_interface->query_ca = mlnx_query_ca; + p_interface->close_ca = mlnx_close_ca; + p_interface->register_event_handler = mlnx_register_event_handler; + p_interface->unregister_event_handler = mlnx_unregister_event_handler; +} + +void +mlnx_ca_if_livefish( + IN OUT ci_interface_t *p_interface ) +{ + p_interface->open_ca = mlnx_open_ca; + p_interface->query_ca = mlnx_query_ca; + p_interface->close_ca = mlnx_close_ca; +} + diff --git a/branches/WOF2-3/hw/mlx4/kernel/hca/cq.c b/branches/WOF2-3/hw/mlx4/kernel/hca/cq.c new file mode 100644 index 00000000..dbd8cfa4 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/hca/cq.c @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: al.c 1611 2006-08-20 14:48:55Z sleybo $ + */ + +#include "precomp.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "cq.tmh" +#endif + +ib_api_status_t +mlnx_create_cq ( + IN const ib_ca_handle_t h_ca, + IN const void *cq_context, + IN ci_async_event_cb_t event_handler, + IN ci_completion_cb_t cq_comp_handler, + IN OUT uint32_t *p_size, + OUT ib_cq_handle_t *ph_cq, + IN OUT ci_umv_buf_t *p_umv_buf ) +{ + int err; + ib_api_status_t status; + struct ib_cq *p_ib_cq; + mlnx_hca_t *p_hca; + struct ib_device *p_ibdev; + struct ib_ucontext *p_uctx; + + HCA_ENTER(HCA_DBG_CQ); + + if( p_umv_buf ) { + + p_uctx = (struct ib_ucontext *)h_ca; + p_ibdev = p_uctx->device; + p_hca = ibdev2hca(p_ibdev); + + if( p_umv_buf && p_umv_buf->command) { + // sanity checks + if (p_umv_buf->input_size < sizeof(struct ibv_create_cq) || + p_umv_buf->output_size < sizeof(struct ibv_create_cq_resp) || + !p_umv_buf->p_inout_buf) { + status = IB_INVALID_PARAMETER; + goto err_inval_params; + } + } + } + else { + p_uctx = NULL; + p_hca = (mlnx_hca_t *)h_ca; + p_ibdev = hca2ibdev(p_hca); + } + + /* sanity check */ + if (!*p_size || *p_size > (uint32_t)hca2mdev(p_hca)->caps.max_cqes) { + status = IB_INVALID_CQ_SIZE; + goto err_cqe; + } + + // allocate cq + p_ib_cq = ibv_create_cq(p_ibdev, + cq_comp_handler, event_handler, + (void*)cq_context, *p_size, p_uctx, p_umv_buf ); + if (IS_ERR(p_ib_cq)) { + err = PTR_ERR(p_ib_cq); + HCA_PRINT (TRACE_LEVEL_ERROR ,HCA_DBG_CQ, ("ibv_create_cq failed (%d)\n", err)); + status = errno_to_iberr(err); + goto err_create_cq; + } + + // return the result + *p_size = p_ib_cq->cqe; + + if (ph_cq) *ph_cq = (ib_cq_handle_t)p_ib_cq; + + status = IB_SUCCESS; + +err_create_cq: +err_inval_params: +err_cqe: + if (p_umv_buf && p_umv_buf->command) + p_umv_buf->status = status; + if (status != IB_SUCCESS) + { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_CQ, + ("completes with ERROR status %x\n", status)); + } + HCA_EXIT(HCA_DBG_CQ); + return status; +} + +ib_api_status_t +mlnx_resize_cq ( + IN const ib_cq_handle_t h_cq, + IN OUT uint32_t *p_size, + IN OUT ci_umv_buf_t *p_umv_buf ) +{ + int err; + ib_api_status_t status = IB_SUCCESS; + struct ib_cq *p_ib_cq = (struct ib_cq *)h_cq; + struct ib_device *p_ibdev = p_ib_cq->device; + + UNUSED_PARAM(p_umv_buf); + + HCA_ENTER(HCA_DBG_CQ); + + if (p_ibdev->resize_cq) { + err = p_ibdev->resize_cq(p_ib_cq, *p_size, NULL); + if (err) { + HCA_PRINT(TRACE_LEVEL_ERROR , HCA_DBG_SHIM, + ("ib_resize_cq failed (%d)\n", err)); + status = errno_to_iberr(err); + } + } + else + status = IB_UNSUPPORTED; + + HCA_EXIT(HCA_DBG_CQ); + return status; +} + +ib_api_status_t +mlnx_query_cq ( + IN const ib_cq_handle_t h_cq, + OUT uint32_t *p_size, + IN OUT ci_umv_buf_t *p_umv_buf ) +{ + UNREFERENCED_PARAMETER(h_cq); + UNREFERENCED_PARAMETER(p_size); + if (p_umv_buf && p_umv_buf->command) { + p_umv_buf->status = IB_UNSUPPORTED; + } + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_CQ,("mlnx_query_cq not supported\n")); + return IB_UNSUPPORTED; +} + +ib_api_status_t +mlnx_destroy_cq ( + IN const ib_cq_handle_t h_cq) +{ + + ib_api_status_t status; + int err; + struct ib_cq *p_ib_cq = (struct ib_cq *)h_cq; + + HCA_ENTER( HCA_DBG_QP); + + HCA_PRINT(TRACE_LEVEL_INFORMATION,HCA_DBG_CQ, + ("cqn %#x, pcs %p\n", ((struct mlx4_ib_cq*)p_ib_cq)->mcq.cqn, PsGetCurrentProcess()) ); + + // destroy CQ + err = ib_destroy_cq( p_ib_cq ); + if (err) { + HCA_PRINT (TRACE_LEVEL_ERROR ,HCA_DBG_SHIM, + ("ibv_destroy_cq failed (%d)\n", err)); + status = errno_to_iberr(err); + goto err_destroy_cq; + } + + status = IB_SUCCESS; + +err_destroy_cq: + if (status != IB_SUCCESS) + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_CQ, + ("completes with ERROR status %x\n", status)); + HCA_EXIT(HCA_DBG_CQ); + return status; +} + + + + +void +mlnx_cq_if( + IN OUT ci_interface_t *p_interface ) +{ + p_interface->create_cq = mlnx_create_cq; + p_interface->resize_cq = mlnx_resize_cq; + p_interface->query_cq = mlnx_query_cq; + p_interface->destroy_cq = mlnx_destroy_cq; +} + diff --git a/branches/WOF2-3/hw/mlx4/kernel/hca/data.c b/branches/WOF2-3/hw/mlx4/kernel/hca/data.c new file mode 100644 index 00000000..52630b7b --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/hca/data.c @@ -0,0 +1,1019 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2004-2005 Mellanox Technologies, Inc. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: data.c 1944 2007-02-12 16:16:00Z sleybo $ + */ + + +#include "precomp.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "data.tmh" +#endif + +static cl_spinlock_t hca_lock; + + + +uint32_t g_mlnx_dpc2thread = 0; + + +cl_qlist_t mlnx_hca_list; + +///////////////////////////////////////////////////////// +// ### HCA +///////////////////////////////////////////////////////// +void +mlnx_hca_insert( + IN mlnx_hca_t *p_hca ) +{ + cl_spinlock_acquire( &hca_lock ); + cl_qlist_insert_tail( &mlnx_hca_list, &p_hca->list_item ); + cl_spinlock_release( &hca_lock ); +} + +void +mlnx_hca_remove( + IN mlnx_hca_t *p_hca ) +{ + cl_spinlock_acquire( &hca_lock ); + cl_qlist_remove_item( &mlnx_hca_list, &p_hca->list_item ); + cl_spinlock_release( &hca_lock ); +} + +mlnx_hca_t* +mlnx_hca_from_guid( + IN ib_net64_t guid ) +{ + cl_list_item_t *p_item; + mlnx_hca_t *p_hca = NULL; + + cl_spinlock_acquire( &hca_lock ); + p_item = cl_qlist_head( &mlnx_hca_list ); + while( p_item != cl_qlist_end( &mlnx_hca_list ) ) + { + p_hca = PARENT_STRUCT( p_item, mlnx_hca_t, list_item ); + if( p_hca->guid == guid ) + break; + p_item = cl_qlist_next( p_item ); + p_hca = NULL; + } + cl_spinlock_release( &hca_lock ); + return p_hca; +} + +///////////////////////////////////////////////////////// +// ### HCA +///////////////////////////////////////////////////////// +cl_status_t +mlnx_hcas_init( void ) +{ + cl_qlist_init( &mlnx_hca_list ); + return cl_spinlock_init( &hca_lock ); +} + + +///////////////////////////////////////////////////////// +///////////////////////////////////////////////////////// + +void ca_event_handler(struct ib_event *ev, void *context) +{ + mlnx_hca_t *p_hca = (mlnx_hca_t *)context; + ib_event_rec_t event_rec; + LIST_ENTRY *entry; + ci_event_handler_t *event_handler; + + // prepare parameters + event_rec.type = ev->event; + event_rec.port_number = ev->element.port_num; + if (event_rec.type > IB_AE_UNKNOWN) { + // CL_ASSERT(0); // This shouldn't happen + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_SHIM,("Unmapped E_EV_CA event of type 0x%x. Replaced by 0x%x (IB_AE_LOCAL_FATAL)\n", + event_rec.type, IB_AE_LOCAL_FATAL)); + event_rec.type = IB_AE_LOCAL_FATAL; + } + + // call the user callback + KeAcquireSpinLockAtDpcLevel(&p_hca->event_list_lock); + for (entry = p_hca->event_list.Flink; entry != &p_hca->event_list; + entry = entry->Flink) { + + event_handler = CONTAINING_RECORD(entry, ci_event_handler_t, entry); + event_rec.context = (void *) event_handler; + event_handler->pfn_async_event_cb(&event_rec); + } + KeReleaseSpinLockFromDpcLevel(&p_hca->event_list_lock); + + if (p_hca && p_hca->async_cb_p) { + event_rec.context = (void *)p_hca->ca_context; + (p_hca->async_cb_p)(&event_rec); + } else { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_SHIM ,("Incorrect context. Async callback was not invoked\n")); + } +} + + +void event_handler( struct ib_event_handler *handler, struct ib_event *event ) +{ + ca_event_handler( event, handler->ctx ); +} + +ib_api_status_t +mlnx_set_cb( + IN mlnx_hca_t * p_hca, + IN ci_async_event_cb_t async_cb_p, + IN const void* const ib_context) +{ + int err; + cl_status_t cl_status; + struct ib_device *ibdev = hca2ibdev(p_hca); + + // Setup the callbacks + if (!p_hca->async_proc_mgr_p) + { + p_hca->async_proc_mgr_p = cl_malloc( sizeof( cl_async_proc_t ) ); + if( !p_hca->async_proc_mgr_p ) + { + return IB_INSUFFICIENT_MEMORY; + } + cl_async_proc_construct( p_hca->async_proc_mgr_p ); + cl_status = cl_async_proc_init( p_hca->async_proc_mgr_p, MLNX_NUM_CB_THR, "CBthread" ); + if( cl_status != CL_SUCCESS ) + { + cl_async_proc_destroy( p_hca->async_proc_mgr_p ); + cl_free(p_hca->async_proc_mgr_p); + p_hca->async_proc_mgr_p = NULL; + return IB_INSUFFICIENT_RESOURCES; + } + } + + p_hca->async_cb_p = async_cb_p; + p_hca->ca_context = ib_context; // This is the context our CB forwards to IBAL + + // register callback with bus driver + INIT_IB_EVENT_HANDLER( &p_hca->ib_event_handler, ibdev, + event_handler, p_hca, NULL, 0 ); + + err = ibdev->x.register_ev_cb(&p_hca->ib_event_handler); + if (err) { + RtlZeroMemory( &p_hca->ib_event_handler, sizeof(p_hca->ib_event_handler) ); + return IB_ERROR; + } + + return IB_SUCCESS; +} + +///////////////////////////////////////////////////////// +///////////////////////////////////////////////////////// +void +mlnx_reset_cb( + IN mlnx_hca_t * p_hca) +{ + cl_async_proc_t *p_async_proc; + struct ib_device *ibdev = hca2ibdev(p_hca); + + cl_spinlock_acquire( &hca_lock ); + + // unregister callback with bus driver + if ( p_hca->ib_event_handler.handler ) + ibdev->x.unregister_ev_cb(&p_hca->ib_event_handler); + + p_async_proc = p_hca->async_proc_mgr_p; + p_hca->async_proc_mgr_p = NULL; + + p_hca->async_cb_p = NULL; + p_hca->ca_context = NULL; + p_hca->cl_device_h = NULL; + + cl_spinlock_release( &hca_lock ); + + if( p_async_proc ) + { + cl_async_proc_destroy( p_async_proc ); + cl_free( p_async_proc ); + } + +} + +///////////////////////////////////////////////////////// +void +from_port_cap( + IN u32 mthca_port_cap, + OUT ib_port_cap_t *ibal_port_cap_p) +{ +#define SET_CAP(flag,cap) if (mthca_port_cap & flag) ibal_port_cap_p->cap = TRUE + + SET_CAP(IB_PORT_CM_SUP,cm); + SET_CAP(IB_PORT_SNMP_TUNNEL_SUP,snmp); + SET_CAP(IB_PORT_DEVICE_MGMT_SUP,dev_mgmt); + SET_CAP(IB_PORT_VENDOR_CLASS_SUP,vend); + SET_CAP(IB_PORT_SM_DISABLED,sm_disable); + SET_CAP(IB_PORT_SM,sm); + SET_CAP(IB_PORT_NOTICE_SUP,notice); + SET_CAP(IB_PORT_TRAP_SUP,trap); + SET_CAP(IB_PORT_AUTO_MIGR_SUP,apm); + SET_CAP(IB_PORT_SL_MAP_SUP,slmap); + SET_CAP(IB_PORT_LED_INFO_SUP,ledinfo); + SET_CAP(IB_PORT_CAP_MASK_NOTICE_SUP,capm_notice); + SET_CAP(IB_PORT_CLIENT_REG_SUP,client_reregister); + SET_CAP(IB_PORT_SYS_IMAGE_GUID_SUP,sysguid); + SET_CAP(IB_PORT_BOOT_MGMT_SUP,boot_mgmt); + SET_CAP(IB_PORT_DR_NOTICE_SUP,dr_notice); + SET_CAP(IB_PORT_PKEY_SW_EXT_PORT_TRAP_SUP,pkey_switch_ext_port); + SET_CAP(IB_PORT_LINK_LATENCY_SUP,link_rtl); + SET_CAP(IB_PORT_REINIT_SUP,reinit); + SET_CAP(IB_PORT_OPT_IPD_SUP,ipd); + SET_CAP(IB_PORT_MKEY_NVRAM,mkey_nvram); + SET_CAP(IB_PORT_PKEY_NVRAM,pkey_nvram); + // there no MTHCA flags for qkey_ctr, pkey_ctr, port_active, bm IBAL capabilities; +} + + +///////////////////////////////////////////////////////// +void +from_hca_cap( + IN struct ib_device *ib_dev, + IN struct ib_device_attr *hca_info_p, + IN struct ib_port_attr *hca_ports, + OUT ib_ca_attr_t *ca_attr_p) +{ + uint8_t port_num; + ib_port_attr_t *ibal_port_p; + struct ib_port_attr *mthca_port_p; + + ca_attr_p->vend_id = hca_info_p->vendor_id; + ca_attr_p->dev_id = (uint16_t)hca_info_p->vendor_part_id; + ca_attr_p->revision = (uint16_t)hca_info_p->hw_ver; + ca_attr_p->fw_ver = hca_info_p->fw_ver; + ca_attr_p->ca_guid = *(UNALIGNED64 uint64_t *)&ib_dev->node_guid; + ca_attr_p->num_ports = ib_dev->phys_port_cnt; + ca_attr_p->max_qps = hca_info_p->max_qp; + ca_attr_p->max_wrs = hca_info_p->max_qp_wr; + ca_attr_p->max_sges = hca_info_p->max_sge; + ca_attr_p->max_rd_sges = hca_info_p->max_sge_rd; + ca_attr_p->max_cqs = hca_info_p->max_cq; + ca_attr_p->max_cqes = hca_info_p->max_cqe; + ca_attr_p->max_pds = hca_info_p->max_pd; + ca_attr_p->init_regions = hca_info_p->max_mr; + ca_attr_p->init_windows = hca_info_p->max_mw; + ca_attr_p->init_region_size = hca_info_p->max_mr_size; + ca_attr_p->max_addr_handles = hca_info_p->max_ah; + ca_attr_p->atomicity = hca_info_p->atomic_cap; + ca_attr_p->max_partitions = hca_info_p->max_pkeys; + ca_attr_p->max_qp_resp_res =(uint8_t) hca_info_p->max_qp_rd_atom; + ca_attr_p->max_resp_res = (uint8_t)hca_info_p->max_res_rd_atom; + ca_attr_p->max_qp_init_depth = (uint8_t)hca_info_p->max_qp_init_rd_atom; + ca_attr_p->max_ipv6_qps = hca_info_p->max_raw_ipv6_qp; + ca_attr_p->max_ether_qps = hca_info_p->max_raw_ethy_qp; + ca_attr_p->max_mcast_grps = hca_info_p->max_mcast_grp; + ca_attr_p->max_mcast_qps = hca_info_p->max_total_mcast_qp_attach; + ca_attr_p->max_qps_per_mcast_grp = hca_info_p->max_mcast_qp_attach; + ca_attr_p->max_fmr = hca_info_p->max_fmr; + ca_attr_p->max_map_per_fmr = hca_info_p->max_map_per_fmr; + ca_attr_p->max_srq = hca_info_p->max_srq; + ca_attr_p->max_srq_wrs = hca_info_p->max_srq_wr; + ca_attr_p->max_srq_sges = hca_info_p->max_srq_sge; + ca_attr_p->system_image_guid = hca_info_p->sys_image_guid; + + ca_attr_p->local_ack_delay = hca_info_p->local_ca_ack_delay; + ca_attr_p->bad_pkey_ctr_support = hca_info_p->device_cap_flags & IB_DEVICE_BAD_PKEY_CNTR; + ca_attr_p->bad_qkey_ctr_support = hca_info_p->device_cap_flags & IB_DEVICE_BAD_QKEY_CNTR; + ca_attr_p->raw_mcast_support = hca_info_p->device_cap_flags & IB_DEVICE_RAW_MULTI; + ca_attr_p->apm_support = hca_info_p->device_cap_flags & IB_DEVICE_AUTO_PATH_MIG; + ca_attr_p->av_port_check = hca_info_p->device_cap_flags & IB_DEVICE_UD_AV_PORT_ENFORCE; + ca_attr_p->change_primary_port = hca_info_p->device_cap_flags & IB_DEVICE_CHANGE_PHY_PORT; + ca_attr_p->modify_wr_depth = hca_info_p->device_cap_flags & IB_DEVICE_RESIZE_MAX_WR; + ca_attr_p->modify_srq_depth = hca_info_p->device_cap_flags & IB_DEVICE_SRQ_RESIZE; + ca_attr_p->system_image_guid_support = hca_info_p->device_cap_flags & IB_DEVICE_SYS_IMAGE_GUID; + ca_attr_p->hw_agents = FALSE; // in the context of IBAL then agent is implemented on the host + ca_attr_p->ipoib_csum = hca_info_p->device_cap_flags & IB_DEVICE_IPOIB_CSUM; + + ca_attr_p->num_page_sizes = 1; + ca_attr_p->p_page_size[0] = PAGE_SIZE; // TBD: extract an array of page sizes from HCA cap + + if ( hca_ports ) + for (port_num = 0; port_num <= (end_port(ib_dev) - start_port(ib_dev)); ++port_num) + { + // Setup port pointers + ibal_port_p = &ca_attr_p->p_port_attr[port_num]; + mthca_port_p = &hca_ports[port_num]; + + // Port Cabapilities + cl_memclr(&ibal_port_p->cap, sizeof(ib_port_cap_t)); + from_port_cap(mthca_port_p->port_cap_flags, &ibal_port_p->cap); + + // Port Atributes + ibal_port_p->port_num = (u8)(port_num + start_port(ib_dev)); + ibal_port_p->port_guid = ibal_port_p->p_gid_table[0].unicast.interface_id; + ibal_port_p->lid = cl_ntoh16(mthca_port_p->lid); + ibal_port_p->lmc = mthca_port_p->lmc; + ibal_port_p->max_vls = mthca_port_p->max_vl_num; + ibal_port_p->sm_lid = cl_ntoh16(mthca_port_p->sm_lid); + ibal_port_p->sm_sl = mthca_port_p->sm_sl; + ibal_port_p->transport = mthca_port_p->transport; + ibal_port_p->link_state = (mthca_port_p->state != 0) ? (uint8_t)mthca_port_p->state : IB_LINK_DOWN; + ibal_port_p->num_gids = (uint16_t)mthca_port_p->gid_tbl_len; + ibal_port_p->num_pkeys = mthca_port_p->pkey_tbl_len; + ibal_port_p->pkey_ctr = (uint16_t)mthca_port_p->bad_pkey_cntr; + ibal_port_p->qkey_ctr = (uint16_t)mthca_port_p->qkey_viol_cntr; + ibal_port_p->max_msg_size = mthca_port_p->max_msg_sz; + ibal_port_p->mtu = (uint8_t)mthca_port_p->max_mtu; + ibal_port_p->active_speed = mthca_port_p->active_speed; + ibal_port_p->active_width = mthca_port_p->active_width; + ibal_port_p->phys_state = mthca_port_p->phys_state; + + ibal_port_p->subnet_timeout = mthca_port_p->subnet_timeout; + // ibal_port_p->local_ack_timeout = 3; // TBD: currently ~32 usec + HCA_PRINT(TRACE_LEVEL_VERBOSE, HCA_DBG_SHIM ,("Port %d port_guid 0x%I64x\n", + ibal_port_p->port_num, cl_ntoh64(ibal_port_p->port_guid))); + } +} + +enum ib_rate to_rate(uint8_t rate) +{ + if (rate == IB_PATH_RECORD_RATE_2_5_GBS) return IB_RATE_2_5_GBPS; + if (rate == IB_PATH_RECORD_RATE_5_GBS) return IB_RATE_5_GBPS; + if (rate == IB_PATH_RECORD_RATE_10_GBS) return IB_RATE_10_GBPS; + if (rate == IB_PATH_RECORD_RATE_20_GBS) return IB_RATE_20_GBPS; + if (rate == IB_PATH_RECORD_RATE_30_GBS) return IB_RATE_30_GBPS; + if (rate == IB_PATH_RECORD_RATE_40_GBS) return IB_RATE_40_GBPS; + if (rate == IB_PATH_RECORD_RATE_60_GBS) return IB_RATE_60_GBPS; + if (rate == IB_PATH_RECORD_RATE_80_GBS) return IB_RATE_80_GBPS; + if (rate == IB_PATH_RECORD_RATE_120_GBS) return IB_RATE_120_GBPS; + return IB_RATE_PORT_CURRENT; +} + +uint8_t from_rate(enum ib_rate ib_rate) +{ + if (ib_rate == IB_RATE_2_5_GBPS) return IB_PATH_RECORD_RATE_2_5_GBS; + if (ib_rate == IB_RATE_5_GBPS) return IB_PATH_RECORD_RATE_5_GBS; + if (ib_rate == IB_RATE_10_GBPS) return IB_PATH_RECORD_RATE_10_GBS; + if (ib_rate == IB_RATE_20_GBPS) return IB_PATH_RECORD_RATE_20_GBS; + if (ib_rate == IB_RATE_30_GBPS) return IB_PATH_RECORD_RATE_30_GBS; + if (ib_rate == IB_RATE_40_GBPS) return IB_PATH_RECORD_RATE_40_GBS; + if (ib_rate == IB_RATE_60_GBPS) return IB_PATH_RECORD_RATE_60_GBS; + if (ib_rate == IB_RATE_80_GBPS) return IB_PATH_RECORD_RATE_80_GBS; + if (ib_rate == IB_RATE_120_GBPS) return IB_PATH_RECORD_RATE_120_GBS; + return 0; +} + +int +to_av( + IN const struct ib_device *p_ib_dev, + IN const ib_av_attr_t *p_ib_av_attr, + OUT struct ib_ah_attr *p_ib_ah_attr) +{ + int err = 0; + u8 port_num; + u16 gid_index; + + p_ib_ah_attr->port_num = p_ib_av_attr->port_num; + p_ib_ah_attr->sl = p_ib_av_attr->sl; + p_ib_ah_attr->dlid = cl_ntoh16(p_ib_av_attr->dlid); + p_ib_ah_attr->static_rate = to_rate(p_ib_av_attr->static_rate); + p_ib_ah_attr->src_path_bits = p_ib_av_attr->path_bits; // PATH: + + /* For global destination or Multicast address:*/ + if (p_ib_av_attr->grh_valid) { + p_ib_ah_attr->ah_flags |= IB_AH_GRH; + p_ib_ah_attr->grh.hop_limit = p_ib_av_attr->grh.hop_limit; + ib_grh_get_ver_class_flow( p_ib_av_attr->grh.ver_class_flow, NULL, + &p_ib_ah_attr->grh.traffic_class, &p_ib_ah_attr->grh.flow_label ); + err = p_ib_dev->x.find_cached_gid((struct ib_device *)p_ib_dev, + (union ib_gid *)p_ib_av_attr->grh.src_gid.raw, &port_num, &gid_index); + if (err) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_SHIM , + ("ib_find_cached_gid failed %d (%#x). Using default: sgid_index = 0\n", err, err)); + gid_index = 0; + } + else if (port_num != p_ib_ah_attr->port_num) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_SHIM , + ("ib_find_cached_gid returned wrong port_num %u (Expected - %u). Using the expected.\n", + (u32)port_num, (u32)p_ib_ah_attr->port_num)); + } + p_ib_ah_attr->grh.sgid_index = (u8)gid_index; + RtlCopyMemory(p_ib_ah_attr->grh.dgid.raw, + p_ib_av_attr->grh.dest_gid.raw, sizeof(p_ib_ah_attr->grh.dgid)); + } + else + p_ib_ah_attr->ah_flags = 0; + + return err; +} + +int from_av( + IN const struct ib_device *p_ib_dev, + IN struct ib_qp_attr *p_ib_qp_attr, + IN struct ib_ah_attr *p_ib_ah_attr, + OUT ib_av_attr_t *p_ib_av_attr) +{ + int err = 0; + + p_ib_av_attr->port_num = p_ib_ah_attr->port_num; + p_ib_av_attr->sl = p_ib_ah_attr->sl; + p_ib_av_attr->dlid = cl_hton16(p_ib_ah_attr->dlid); + p_ib_av_attr->static_rate = from_rate(p_ib_ah_attr->static_rate); + p_ib_av_attr->path_bits = p_ib_ah_attr->src_path_bits; + + if (p_ib_qp_attr) { + p_ib_av_attr->conn.path_mtu = p_ib_qp_attr->path_mtu; // MTU + p_ib_av_attr->conn.local_ack_timeout = p_ib_qp_attr->timeout; // MTU + p_ib_av_attr->conn.seq_err_retry_cnt = p_ib_qp_attr->retry_cnt; // MTU + p_ib_av_attr->conn.rnr_retry_cnt = p_ib_qp_attr->rnr_retry; // MTU + } + + if (p_ib_ah_attr->ah_flags & IB_AH_GRH) { + p_ib_av_attr->grh_valid = TRUE; + p_ib_av_attr->grh.hop_limit = p_ib_ah_attr->grh.hop_limit; + p_ib_av_attr->grh.ver_class_flow = ib_grh_set_ver_class_flow( + 0, p_ib_ah_attr->grh.traffic_class, p_ib_ah_attr->grh.flow_label ); + RtlCopyMemory(p_ib_av_attr->grh.dest_gid.raw, + p_ib_ah_attr->grh.dgid.raw, sizeof(p_ib_av_attr->grh.dest_gid)); + err = p_ib_dev->x.get_cached_gid((struct ib_device *)p_ib_dev, + p_ib_ah_attr->port_num, p_ib_ah_attr->grh.sgid_index, + (union ib_gid*)p_ib_av_attr->grh.src_gid.raw ); + if (err) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_SHIM , + ("ib_get_cached_gid failed %d (%#x). Using default: sgid_index = 0\n", err, err)); + } + } + else + p_ib_av_attr->grh_valid = FALSE; + + + return err; +} + +enum ib_access_flags +to_qp_acl( + IN ib_access_t ibal_acl) +{ +#define IBAL_ACL(ifl,mfl) if (ibal_acl & ifl) acc |= mfl + enum ib_access_flags acc = 0; + + IBAL_ACL(IB_AC_RDMA_READ,IB_ACCESS_REMOTE_READ); + IBAL_ACL(IB_AC_RDMA_WRITE,IB_ACCESS_REMOTE_WRITE); + IBAL_ACL(IB_AC_ATOMIC,IB_ACCESS_REMOTE_ATOMIC); + IBAL_ACL(IB_AC_LOCAL_WRITE,IB_ACCESS_LOCAL_WRITE); + IBAL_ACL(IB_AC_MW_BIND,IB_ACCESS_MW_BIND); + + return acc; +} + +ib_access_t +from_qp_acl( + IN enum ib_access_flags acc) +{ +#define IB_ACL(ifl,mfl) if (acc & ifl) ibal_acl |= mfl + ib_access_t ibal_acl = 0; + + IB_ACL(IB_ACCESS_REMOTE_READ,IB_AC_RDMA_READ); + IB_ACL(IB_ACCESS_REMOTE_WRITE,IB_AC_RDMA_WRITE); + IB_ACL(IB_ACCESS_REMOTE_ATOMIC,IB_AC_ATOMIC); + IB_ACL(IB_ACCESS_LOCAL_WRITE,IB_AC_LOCAL_WRITE); + IB_ACL(IB_ACCESS_MW_BIND,IB_AC_MW_BIND); + + return ibal_acl; +} + +static enum ib_qp_state to_qp_state(ib_qp_state_t ib_qps) +{ +#define MAP_XIB_QPS(val1,val2) case val1: qps = val2; break + enum ib_qp_state qps; + switch (ib_qps) { + MAP_XIB_QPS( IB_QPS_RESET, XIB_QPS_RESET ); + MAP_XIB_QPS( IB_QPS_INIT, XIB_QPS_INIT ); + MAP_XIB_QPS( IB_QPS_RTR, XIB_QPS_RTR ); + MAP_XIB_QPS( IB_QPS_RTS, XIB_QPS_RTS ); + MAP_XIB_QPS( IB_QPS_SQD, XIB_QPS_SQD ); + MAP_XIB_QPS( IB_QPS_SQD_DRAINING, XIB_QPS_SQD ); + MAP_XIB_QPS( IB_QPS_SQD_DRAINED, XIB_QPS_SQD ); + MAP_XIB_QPS( IB_QPS_SQERR, XIB_QPS_SQE ); + MAP_XIB_QPS( IB_QPS_ERROR, XIB_QPS_ERR ); + default: + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_SHIM ,("Unmapped IBAL qp_state %d\n", ib_qps)); + qps = 0xffffffff; + } + return qps; +} + +static ib_qp_state_t from_qp_state(enum ib_qp_state qps, int draining) +{ +#define MAP_IB_QPS(val1,val2) case val1: ib_qps = val2; break + ib_qp_state_t ib_qps; + + if (qps == XIB_QPS_SQD) { + ib_qps = draining ? IB_QPS_SQD_DRAINING : IB_QPS_SQD; + return ib_qps; + } + + switch (qps) { + MAP_IB_QPS( XIB_QPS_RESET, IB_QPS_RESET ); + MAP_IB_QPS( XIB_QPS_INIT, IB_QPS_INIT ); + MAP_IB_QPS( XIB_QPS_RTR, IB_QPS_RTR ); + MAP_IB_QPS( XIB_QPS_RTS, IB_QPS_RTS ); + MAP_IB_QPS( XIB_QPS_SQE, IB_QPS_SQERR ); + MAP_IB_QPS( XIB_QPS_ERR, IB_QPS_ERROR ); + default: + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_SHIM ,("Unmapped IBAL qp_state %d\n", qps)); + ib_qps = 0xffffffff; + } + return ib_qps; +} + +enum ib_mig_state to_apm_state(ib_apm_state_t apm) +{ + if (apm == IB_APM_MIGRATED) return IB_MIG_MIGRATED; + if (apm == IB_APM_REARM) return IB_MIG_REARM; + if (apm == IB_APM_ARMED) return IB_MIG_ARMED; + return 0xffffffff; +} + +ib_api_status_t +to_qp_attr( + IN const struct ib_qp *p_ib_qp, + IN ib_qp_type_t qp_type, + IN const ib_qp_mod_t *p_ib_qp_mod, + OUT struct ib_qp_attr *p_ib_qp_attr, + OUT int *p_qp_attr_mask + ) +{ + int err; + ib_api_status_t status = IB_SUCCESS; + struct mlx4_ib_qp *p_mib_qp = (struct mlx4_ib_qp *)p_ib_qp; + + RtlZeroMemory( p_ib_qp_attr, sizeof *p_ib_qp_attr ); + *p_qp_attr_mask = IB_QP_STATE; + p_ib_qp_attr->qp_state = to_qp_state( p_ib_qp_mod->req_state ); + + // skipped cases + if (p_mib_qp->state == XIB_QPS_RESET && p_ib_qp_mod->req_state != IB_QPS_INIT) + return IB_NOT_DONE; + + switch (p_ib_qp_mod->req_state) { + case IB_QPS_RESET: + case IB_QPS_ERROR: + case IB_QPS_SQERR: + case IB_QPS_TIME_WAIT: + break; + + case IB_QPS_INIT: + + switch (qp_type) { + case IB_QPT_RELIABLE_CONN: + case IB_QPT_UNRELIABLE_CONN: + *p_qp_attr_mask |= IB_QP_PORT | IB_QP_PKEY_INDEX |IB_QP_ACCESS_FLAGS; + p_ib_qp_attr->qp_access_flags = to_qp_acl(p_ib_qp_mod->state.init.access_ctrl); + break; + case IB_QPT_QP0: + case IB_QPT_QP1: + // TODO: these cases had IB_QP_PORT in mthca + // TODO: they do not pass ib_modify_qp_is_ok control here + *p_qp_attr_mask |= IB_QP_QKEY | IB_QP_PKEY_INDEX ; + p_ib_qp_attr->qkey = cl_ntoh32 (p_ib_qp_mod->state.init.qkey); + break; + case IB_QPT_UNRELIABLE_DGRM: + default: + *p_qp_attr_mask |= IB_QP_PORT | IB_QP_QKEY | IB_QP_PKEY_INDEX ; + p_ib_qp_attr->qkey = cl_ntoh32 (p_ib_qp_mod->state.init.qkey); + break; + } + + // IB_QP_PORT + p_ib_qp_attr->port_num = p_ib_qp_mod->state.init.primary_port; + + // IB_QP_PKEY_INDEX + p_ib_qp_attr->pkey_index = p_ib_qp_mod->state.init.pkey_index; + + break; + + case IB_QPS_RTR: + /* modifying the WQE depth is not supported */ + if( p_ib_qp_mod->state.rtr.opts & IB_MOD_QP_SQ_DEPTH || + p_ib_qp_mod->state.rtr.opts & IB_MOD_QP_RQ_DEPTH ) { + status = IB_UNSUPPORTED; + break; + } + + switch (qp_type) { + case IB_QPT_RELIABLE_CONN: + *p_qp_attr_mask |= /* required flags */ + IB_QP_DEST_QPN |IB_QP_RQ_PSN | IB_QP_MAX_DEST_RD_ATOMIC | + IB_QP_AV |IB_QP_PATH_MTU | IB_QP_MIN_RNR_TIMER; + + // IB_QP_DEST_QPN + p_ib_qp_attr->dest_qp_num = cl_ntoh32 (p_ib_qp_mod->state.rtr.dest_qp); + + // IB_QP_RQ_PSN + p_ib_qp_attr->rq_psn = cl_ntoh32 (p_ib_qp_mod->state.rtr.rq_psn); + + // IB_QP_MAX_DEST_RD_ATOMIC + p_ib_qp_attr->max_dest_rd_atomic = p_ib_qp_mod->state.rtr.resp_res; + + // IB_QP_AV, IB_QP_PATH_MTU: Convert primary RC AV (mandatory) + err = to_av(p_ib_qp->device, + &p_ib_qp_mod->state.rtr.primary_av, &p_ib_qp_attr->ah_attr); + if (err) { + status = IB_ERROR; + break; + } + p_ib_qp_attr->path_mtu = p_ib_qp_mod->state.rtr.primary_av.conn.path_mtu; // MTU + p_ib_qp_attr->timeout = p_ib_qp_mod->state.rtr.primary_av.conn.local_ack_timeout; // MTU + p_ib_qp_attr->retry_cnt = p_ib_qp_mod->state.rtr.primary_av.conn.seq_err_retry_cnt; // MTU + p_ib_qp_attr->rnr_retry = p_ib_qp_mod->state.rtr.primary_av.conn.rnr_retry_cnt; // MTU + + // IB_QP_MIN_RNR_TIMER, required in RTR, optional in RTS. + p_ib_qp_attr->min_rnr_timer = p_ib_qp_mod->state.rtr.rnr_nak_timeout; + + // IB_QP_ACCESS_FLAGS: Convert Remote Atomic Flags + if (p_ib_qp_mod->state.rtr.opts & IB_MOD_QP_ACCESS_CTRL) { + *p_qp_attr_mask |= IB_QP_ACCESS_FLAGS; /* optional flag */ + p_ib_qp_attr->qp_access_flags = to_qp_acl(p_ib_qp_mod->state.rtr.access_ctrl); + } + + // IB_QP_ALT_PATH: Convert alternate RC AV + if (p_ib_qp_mod->state.rtr.opts & IB_MOD_QP_ALTERNATE_AV) { + *p_qp_attr_mask |= IB_QP_ALT_PATH; /* required flag */ + err = to_av(p_ib_qp->device, + &p_ib_qp_mod->state.rtr.alternate_av, &p_ib_qp_attr->alt_ah_attr); + if (err) { + status = IB_ERROR; + break; + } + p_ib_qp_attr->alt_timeout = p_ib_qp_mod->state.rtr.alternate_av.conn.local_ack_timeout; // XXX: conv + p_ib_qp_attr->alt_port_num = p_ib_qp_mod->state.rtr.alternate_av.port_num; + } + + // IB_QP_PKEY_INDEX + if (p_ib_qp_mod->state.rtr.opts & IB_MOD_QP_PKEY) { + *p_qp_attr_mask |= IB_QP_PKEY_INDEX; + p_ib_qp_attr->pkey_index = p_ib_qp_mod->state.rtr.pkey_index; + } + break; + + case IB_QPT_UNRELIABLE_CONN: + *p_qp_attr_mask |= /* required flags */ + IB_QP_DEST_QPN |IB_QP_RQ_PSN | IB_QP_AV | IB_QP_PATH_MTU; + + // IB_QP_DEST_QPN + p_ib_qp_attr->dest_qp_num = cl_ntoh32 (p_ib_qp_mod->state.rtr.dest_qp); + + // IB_QP_RQ_PSN + p_ib_qp_attr->rq_psn = cl_ntoh32 (p_ib_qp_mod->state.rtr.rq_psn); + + // IB_QP_PATH_MTU + p_ib_qp_attr->path_mtu = p_ib_qp_mod->state.rtr.primary_av.conn.path_mtu; + + // IB_QP_AV: Convert primary AV (mandatory) + err = to_av(p_ib_qp->device, + &p_ib_qp_mod->state.rtr.primary_av, &p_ib_qp_attr->ah_attr); + if (err) { + status = IB_ERROR; + break; + } + + // IB_QP_ACCESS_FLAGS: Convert Remote Atomic Flags + if (p_ib_qp_mod->state.rtr.opts & IB_MOD_QP_ACCESS_CTRL) { + *p_qp_attr_mask |= IB_QP_ACCESS_FLAGS; /* optional flag */ + p_ib_qp_attr->qp_access_flags = to_qp_acl(p_ib_qp_mod->state.rtr.access_ctrl); + } + + // IB_QP_ALT_PATH: Convert alternate RC AV + if (p_ib_qp_mod->state.rtr.opts & IB_MOD_QP_ALTERNATE_AV) { + *p_qp_attr_mask |= IB_QP_ALT_PATH; /* required flag */ + err = to_av(p_ib_qp->device, + &p_ib_qp_mod->state.rtr.alternate_av, &p_ib_qp_attr->alt_ah_attr); + if (err) { + status = IB_ERROR; + break; + } + p_ib_qp_attr->alt_timeout = p_ib_qp_mod->state.rtr.alternate_av.conn.local_ack_timeout; // XXX: conv + p_ib_qp_attr->alt_port_num = p_ib_qp_mod->state.rtr.alternate_av.port_num; + } + + // IB_QP_PKEY_INDEX + if (p_ib_qp_mod->state.rtr.opts & IB_MOD_QP_PKEY) { + *p_qp_attr_mask |= IB_QP_PKEY_INDEX; + p_ib_qp_attr->pkey_index = p_ib_qp_mod->state.rtr.pkey_index; + } + break; + + case IB_QPT_UNRELIABLE_DGRM: + case IB_QPT_QP0: + case IB_QPT_QP1: + default: + // IB_QP_PKEY_INDEX + if (p_ib_qp_mod->state.rtr.opts & IB_MOD_QP_PKEY) { + *p_qp_attr_mask |= IB_QP_PKEY_INDEX; + p_ib_qp_attr->pkey_index = p_ib_qp_mod->state.rtr.pkey_index; + } + + // IB_QP_QKEY + if (p_ib_qp_mod->state.rtr.opts & IB_MOD_QP_QKEY) { + *p_qp_attr_mask |= IB_QP_QKEY; + p_ib_qp_attr->qkey = cl_ntoh32 (p_ib_qp_mod->state.rtr.qkey); + } + break; + + } + break; + + case IB_QPS_RTS: + /* modifying the WQE depth is not supported */ + if( p_ib_qp_mod->state.rts.opts & IB_MOD_QP_SQ_DEPTH || + p_ib_qp_mod->state.rts.opts & IB_MOD_QP_RQ_DEPTH ) + { + status = IB_UNSUPPORTED; + break; + } + + switch (qp_type) { + case IB_QPT_RELIABLE_CONN: + if (p_mib_qp->state != XIB_QPS_RTS) + *p_qp_attr_mask |= /* required flags */ + IB_QP_SQ_PSN |IB_QP_MAX_QP_RD_ATOMIC | IB_QP_TIMEOUT | + IB_QP_RETRY_CNT |IB_QP_RNR_RETRY; + + // IB_QP_MAX_QP_RD_ATOMIC + p_ib_qp_attr->max_rd_atomic = p_ib_qp_mod->state.rts.init_depth; + + // IB_QP_TIMEOUT + p_ib_qp_attr->timeout = p_ib_qp_mod->state.rts.local_ack_timeout; // XXX: conv + + // IB_QP_RETRY_CNT + p_ib_qp_attr->retry_cnt = p_ib_qp_mod->state.rts.retry_cnt; + + // IB_QP_RNR_RETRY + p_ib_qp_attr->rnr_retry = p_ib_qp_mod->state.rts.rnr_retry_cnt; + + // IB_QP_MAX_DEST_RD_ATOMIC: Update the responder resources for RDMA/ATOMIC (optional for SQD->RTS) + if (p_ib_qp_mod->state.rts.opts & IB_MOD_QP_RESP_RES) { + *p_qp_attr_mask |= IB_QP_MAX_DEST_RD_ATOMIC; + p_ib_qp_attr->max_dest_rd_atomic = p_ib_qp_mod->state.rts.resp_res; + } + +#ifdef WIN_TO_BE_REMOVED + //TODO: do we need that ? + // Linux patch 4793: PKEY_INDEX is not a legal parameter in the RTR->RTS transition. + + // IB_QP_PKEY_INDEX + if (p_ib_qp_mod->state.rts.opts & IB_MOD_QP_PKEY) { + *p_qp_attr_mask |= IB_QP_PKEY_INDEX; + p_ib_qp_attr->pkey_index = p_ib_qp_mod->state.rts.pkey_index; + } +#endif + + // IB_QP_MIN_RNR_TIMER + if (p_ib_qp_mod->state.rts.opts & IB_MOD_QP_RNR_NAK_TIMEOUT) { + *p_qp_attr_mask |= IB_QP_MIN_RNR_TIMER; + p_ib_qp_attr->min_rnr_timer = p_ib_qp_mod->state.rts.rnr_nak_timeout; + } + + // IB_QP_PATH_MIG_STATE + if (p_ib_qp_mod->state.rts.opts & IB_MOD_QP_APM_STATE) { + *p_qp_attr_mask |= IB_QP_PATH_MIG_STATE; + p_ib_qp_attr->path_mig_state = to_apm_state(p_ib_qp_mod->state.rts.apm_state); + } + + // IB_QP_ACCESS_FLAGS + if (p_ib_qp_mod->state.rts.opts & IB_MOD_QP_ACCESS_CTRL) { + *p_qp_attr_mask |= IB_QP_ACCESS_FLAGS; /* optional flags */ + p_ib_qp_attr->qp_access_flags = to_qp_acl(p_ib_qp_mod->state.rts.access_ctrl); + } + + // IB_QP_ALT_PATH: Convert alternate RC AV + if (p_ib_qp_mod->state.rts.opts & IB_MOD_QP_ALTERNATE_AV) { + *p_qp_attr_mask |= IB_QP_ALT_PATH; /* optional flag */ + err = to_av(p_ib_qp->device, + &p_ib_qp_mod->state.rts.alternate_av, &p_ib_qp_attr->alt_ah_attr); + if (err) { + status = IB_ERROR; + break; + } + p_ib_qp_attr->alt_timeout = p_ib_qp_mod->state.rts.alternate_av.conn.local_ack_timeout; // XXX: conv + p_ib_qp_attr->alt_port_num = p_ib_qp_mod->state.rts.alternate_av.port_num; + } + break; + + case IB_QPT_UNRELIABLE_CONN: + if (p_mib_qp->state != XIB_QPS_RTS) + *p_qp_attr_mask |= /* required flags */ + IB_QP_SQ_PSN; + + // IB_QP_MAX_DEST_RD_ATOMIC: Update the responder resources for RDMA/ATOMIC (optional for SQD->RTS) + if (p_ib_qp_mod->state.rts.opts & IB_MOD_QP_RESP_RES) { + *p_qp_attr_mask |= IB_QP_MAX_DEST_RD_ATOMIC; + p_ib_qp_attr->max_dest_rd_atomic = p_ib_qp_mod->state.rts.resp_res; + } + +#ifdef WIN_TO_BE_REMOVED + //TODO: do we need that ? + // Linux patch 4793: PKEY_INDEX is not a legal parameter in the RTR->RTS transition. + + // IB_QP_PKEY_INDEX + if (p_ib_qp_mod->state.rts.opts & IB_MOD_QP_PKEY) { + *p_qp_attr_mask |= IB_QP_PKEY_INDEX; + p_ib_qp_attr->pkey_index = p_ib_qp_mod->state.rts.pkey_index; + } +#endif + + // IB_QP_PATH_MIG_STATE + if (p_ib_qp_mod->state.rts.opts & IB_MOD_QP_APM_STATE) { + *p_qp_attr_mask |= IB_QP_PATH_MIG_STATE; + p_ib_qp_attr->path_mig_state = to_apm_state(p_ib_qp_mod->state.rts.apm_state); + } + + // IB_QP_ACCESS_FLAGS + if (p_ib_qp_mod->state.rts.opts & IB_MOD_QP_ACCESS_CTRL) { + *p_qp_attr_mask |= IB_QP_ACCESS_FLAGS; /* optional flags */ + p_ib_qp_attr->qp_access_flags = to_qp_acl(p_ib_qp_mod->state.rts.access_ctrl); + } + + // IB_QP_ALT_PATH: Convert alternate RC AV + if (p_ib_qp_mod->state.rts.opts & IB_MOD_QP_ALTERNATE_AV) { + *p_qp_attr_mask |= IB_QP_ALT_PATH; /* optional flag */ + err = to_av(p_ib_qp->device, + &p_ib_qp_mod->state.rts.alternate_av, &p_ib_qp_attr->alt_ah_attr); + if (err) { + status = IB_ERROR; + break; + } + p_ib_qp_attr->alt_timeout = p_ib_qp_mod->state.rts.alternate_av.conn.local_ack_timeout; // XXX: conv + p_ib_qp_attr->alt_port_num = p_ib_qp_mod->state.rts.alternate_av.port_num; + } + break; + + case IB_QPT_UNRELIABLE_DGRM: + case IB_QPT_QP0: + case IB_QPT_QP1: + default: + if (p_mib_qp->state != XIB_QPS_RTS) + *p_qp_attr_mask |= /* required flags */ + IB_QP_SQ_PSN; + + // IB_QP_QKEY + if (p_ib_qp_mod->state.rts.opts & IB_MOD_QP_QKEY) { + *p_qp_attr_mask |= IB_QP_QKEY; + p_ib_qp_attr->qkey = cl_ntoh32 (p_ib_qp_mod->state.rts.qkey); + } + break; + + break; + + } + + // IB_QP_SQ_PSN: common for all + p_ib_qp_attr->sq_psn = cl_ntoh32 (p_ib_qp_mod->state.rts.sq_psn); + //NB: IB_QP_CUR_STATE flag is not provisioned by IBAL + break; + + case IB_QPS_SQD: + case IB_QPS_SQD_DRAINING: + case IB_QPS_SQD_DRAINED: + *p_qp_attr_mask |= IB_QP_EN_SQD_ASYNC_NOTIFY; + p_ib_qp_attr->en_sqd_async_notify = (u8)p_ib_qp_mod->state.sqd.sqd_event; + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_SHIM ,("IB_QP_EN_SQD_ASYNC_NOTIFY seems like unsupported\n")); + break; + + default: + //NB: is this an error case and we need this message ? What about returning an error ? + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_SHIM ,("Unmapped qp_state %d\n", p_ib_qp_mod->req_state)); + break; + + } + + return status; +} + +enum ib_qp_type to_qp_type(ib_qp_type_t qp_type) +{ +#define MAP_TYPE(val1,val2) case val1: ib_qp_type = val2; break + enum ib_qp_type ib_qp_type; + + switch (qp_type) { + MAP_TYPE( IB_QPT_RELIABLE_CONN, IB_QPT_RC ); + MAP_TYPE( IB_QPT_UNRELIABLE_CONN, IB_QPT_UC ); + MAP_TYPE( IB_QPT_UNRELIABLE_DGRM, IB_QPT_UD ); + MAP_TYPE( IB_QPT_QP0, IB_QPT_SMI ); + MAP_TYPE( IB_QPT_QP1, IB_QPT_GSI ); + MAP_TYPE( IB_QPT_RAW_IPV6, IB_QPT_RAW_IP_V6 ); + MAP_TYPE( IB_QPT_RAW_ETHER, IB_QPT_RAW_ETY ); + default: + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_SHIM , + ("Unmapped MLX4 ib_wc_type %d\n", qp_type)); + ib_qp_type = 0xffffffff; + } + return ib_qp_type; +} + +ib_qp_type_t from_qp_type(enum ib_qp_type ib_qp_type) +{ +#define MAP_IB_TYPE(val1,val2) case val1: qp_type = val2; break + ib_qp_type_t qp_type; + + switch (ib_qp_type) { + MAP_IB_TYPE( IB_QPT_RC, IB_QPT_RELIABLE_CONN ); + MAP_IB_TYPE( IB_QPT_UC, IB_QPT_UNRELIABLE_CONN ); + MAP_IB_TYPE( IB_QPT_UD, IB_QPT_UNRELIABLE_DGRM ); + MAP_IB_TYPE( IB_QPT_SMI, IB_QPT_QP0 ); + MAP_IB_TYPE( IB_QPT_GSI, IB_QPT_QP1 ); + MAP_IB_TYPE( IB_QPT_RAW_IP_V6, IB_QPT_RAW_IPV6 ); + MAP_IB_TYPE( IB_QPT_RAW_ETY, IB_QPT_RAW_ETHER ); + default: + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_SHIM , + ("Unmapped MLX4 ib_wc_type %d\n", ib_qp_type)); + qp_type = 0xffffffff; + } + return qp_type; +} + +ib_apm_state_t from_apm_state(enum ib_mig_state apm) +{ + if (apm == IB_MIG_MIGRATED) return IB_APM_MIGRATED; + if (apm == IB_MIG_REARM) return IB_APM_REARM; + if (apm == IB_MIG_ARMED) return IB_APM_ARMED; + return 0xffffffff; +} + +ib_api_status_t +from_qp_attr( + IN const struct ib_qp *p_ib_qp, + IN struct ib_qp_attr *p_ib_qp_attr, + OUT ib_qp_attr_t *p_qp_attr + ) +{ + int err; + RtlZeroMemory( p_qp_attr, sizeof *p_qp_attr ); + p_qp_attr->h_pd = (ib_pd_handle_t)p_ib_qp->pd; + p_qp_attr->qp_type = from_qp_type(p_ib_qp->qp_type); + p_qp_attr->access_ctrl = from_qp_acl(p_ib_qp_attr->qp_access_flags); + p_qp_attr->pkey_index = p_ib_qp_attr->pkey_index; + + p_qp_attr->sq_max_inline = p_ib_qp_attr->cap.max_inline_data; + p_qp_attr->sq_depth = p_ib_qp_attr->cap.max_send_wr; + p_qp_attr->rq_depth = p_ib_qp_attr->cap.max_recv_wr; + p_qp_attr->sq_sge = p_ib_qp_attr->cap.max_send_sge; + p_qp_attr->rq_sge = p_ib_qp_attr->cap.max_recv_sge; + p_qp_attr->init_depth = p_ib_qp_attr->max_rd_atomic; + p_qp_attr->resp_res = p_ib_qp_attr->max_dest_rd_atomic; + + p_qp_attr->h_sq_cq = (ib_cq_handle_t)p_ib_qp->send_cq; + p_qp_attr->h_rq_cq = (ib_cq_handle_t)p_ib_qp->recv_cq; + p_qp_attr->h_srq = (ib_srq_handle_t)p_ib_qp->srq; + + p_qp_attr->sq_signaled = !!((struct mlx4_ib_qp *)p_ib_qp)->sq_signal_bits; + + p_qp_attr->state = from_qp_state( p_ib_qp_attr->qp_state, + p_ib_qp_attr->sq_draining); + p_qp_attr->num = cl_hton32(p_ib_qp->qp_num); + p_qp_attr->dest_num = cl_hton32(p_ib_qp_attr->dest_qp_num); + p_qp_attr->qkey = cl_hton32(p_ib_qp_attr->qkey); + + p_qp_attr->sq_psn = cl_hton32(p_ib_qp_attr->sq_psn); + p_qp_attr->rq_psn = cl_hton32(p_ib_qp_attr->rq_psn); + + p_qp_attr->primary_port = p_ib_qp_attr->port_num; + p_qp_attr->alternate_port = p_ib_qp_attr->alt_port_num; + err = from_av( p_ib_qp->device, p_ib_qp_attr, &p_ib_qp_attr->ah_attr, &p_qp_attr->primary_av); + if (err) + goto err_av; + err = from_av( p_ib_qp->device, p_ib_qp_attr, &p_ib_qp_attr->alt_ah_attr, &p_qp_attr->alternate_av); + if (err) + goto err_av; + p_qp_attr->apm_state = from_apm_state(p_ib_qp_attr->path_mig_state); + + return IB_SUCCESS; + +err_av: + return errno_to_iberr(err); +} + diff --git a/branches/WOF2-3/hw/mlx4/kernel/hca/data.h b/branches/WOF2-3/hw/mlx4/kernel/hca/data.h new file mode 100644 index 00000000..f02b1787 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/hca/data.h @@ -0,0 +1,338 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2004-2005 Mellanox Technologies, Inc. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: hca_data.h 2036 2007-07-25 14:27:12Z leonid $ + */ + +#pragma once + +#include +#include + +extern char mlnx_uvp_lib_name[]; + + +#define MLNX_MAX_HCA 4 +#define MLNX_NUM_HOBKL MLNX_MAX_HCA +#define MLNX_NUM_CB_THR 1 +#define MLNX_SIZE_CB_POOL 256 +#define MLNX_UAL_ALLOC_HCA_UL_RES 1 +#define MLNX_UAL_FREE_HCA_UL_RES 2 + + +// Defines for QP ops +#define MLNX_MAX_NUM_SGE 8 +#define MLNX_MAX_WRS_PER_CHAIN 4 + +#define MLNX_NUM_RESERVED_QPS 16 + +/* + * Completion model. + * 0: No DPC processor assignment + * 1: DPCs per-CQ, processor affinity set at CQ initialization time. + * 2: DPCs per-CQ, processor affinity set at runtime. + * 3: DPCs per-CQ, no processor affinity set. + */ +#define MLNX_COMP_MODEL 3 + +#ifdef DBG +#define VALIDATE_INDEX(index, limit, error, label) \ + { \ + if (index >= limit) \ + { \ + status = error; \ + HCA_PRINT(TRACE_LEVEL_ERROR , g_mlnx_dbg_lvl ,("file %s line %d\n", __FILE__, __LINE__)));\ + goto label; \ + } \ + } +#else +#define VALIDATE_INDEX(index, limit, error, label) +#endif + + + +// Typedefs + +typedef enum { + E_EV_CA=1, + E_EV_QP, + E_EV_CQ, + E_EV_LAST +} ENUM_EVENT_CLASS; + +typedef enum { + E_MR_PHYS=1, + E_MR_SHARED, + E_MR_ANY, + E_MR_INVALID +} ENUM_MR_TYPE; + +/* + * Attribute cache for port info saved to expedite local MAD processing. + * Note that the cache accounts for the worst case GID and PKEY table size + * but is allocated from paged pool, so it's nothing to worry about. + */ + +typedef struct _guid_block +{ + boolean_t valid; + ib_guid_info_t tbl; + +} mlnx_guid_block_t; + +typedef struct _port_info_cache +{ + boolean_t valid; + ib_port_info_t info; + +} mlnx_port_info_cache_t; + +typedef struct _pkey_block +{ + boolean_t valid; + ib_pkey_table_t tbl; + +} mlnx_pkey_block_t; + +typedef struct _sl_vl_cache +{ + boolean_t valid; + ib_slvl_table_t tbl; + +} mlnx_sl_vl_cache_t; + +typedef struct _vl_arb_block +{ + boolean_t valid; + ib_vl_arb_table_t tbl; + +} mlnx_vl_arb_block_t; + +typedef struct _attr_cache +{ + mlnx_guid_block_t guid_block[32]; + mlnx_port_info_cache_t port_info; + mlnx_pkey_block_t pkey_tbl[2048]; + mlnx_sl_vl_cache_t sl_vl; + mlnx_vl_arb_block_t vl_arb[4]; + +} mlnx_cache_t; + +typedef struct _ib_mcast { + ib_gid_t mcast_gid; + struct ib_qp *p_ib_qp; + uint16_t mcast_lid; +} mlnx_mcast_t; + +typedef struct _mlnx_hca_t { + cl_list_item_t list_item; // to include in the HCA chain + net64_t guid; // HCA node Guid + uint32_t hw_ver; // HCA HW version + // HOB + KSPIN_LOCK event_list_lock; + LIST_ENTRY event_list; + ci_async_event_cb_t async_cb_p; + const void *ca_context; + void *cl_device_h; + uint32_t index; + cl_async_proc_t *async_proc_mgr_p; + struct ib_event_handler ib_event_handler; +} mlnx_hca_t; + +// Functions +void +setup_ci_interface( + IN const ib_net64_t ca_guid, + IN const int is_livefish, + OUT ci_interface_t *p_interface ); + +void +mlnx_hca_insert( + IN mlnx_hca_t *p_hca ); + +void +mlnx_hca_remove( + IN mlnx_hca_t *p_hca ); + +mlnx_hca_t* +mlnx_hca_from_guid( + IN ib_net64_t guid ); + +/* +void +mlnx_names_from_guid( + IN ib_net64_t guid, + OUT char **hca_name_p, + OUT char **dev_name_p); +*/ + +cl_status_t +mlnx_hcas_init( void ); + +ib_api_status_t +mlnx_set_cb( + IN mlnx_hca_t * p_hca, + IN ci_async_event_cb_t async_cb_p, + IN const void* const ib_context); + +void +mlnx_reset_cb( + IN mlnx_hca_t * p_hca); + +void +from_hca_cap( + IN struct ib_device *ib_dev, + IN struct ib_device_attr *hca_info_p, + IN struct ib_port_attr *hca_ports, + OUT ib_ca_attr_t *ca_attr_p); + +ib_api_status_t +mlnx_local_mad ( + IN const ib_ca_handle_t h_ca, + IN const uint8_t port_num, + IN const ib_av_attr_t *p_src_av_attr, + IN const ib_mad_t *p_mad_in, + OUT ib_mad_t *p_mad_out ); + +ib_api_status_t +fw_access_ctrl( + IN const void* context, + IN const void** const handle_array OPTIONAL, + IN uint32_t num_handles, + IN ib_ci_op_t* const p_ci_op, + IN OUT ci_umv_buf_t *p_umv_buf OPTIONAL); + +void unmap_crspace_for_all( struct ib_ucontext *p_context ); + +void ca_event_handler(struct ib_event *ev, void *context); + +ib_api_status_t +to_qp_attr( + IN const struct ib_qp *ib_qp_p, + IN ib_qp_type_t qp_type, + IN const ib_qp_mod_t *modify_attr_p, + OUT struct ib_qp_attr *qp_attr_p, + OUT int *qp_attr_mask_p + ); + +ib_api_status_t +from_qp_attr( + IN const struct ib_qp *p_ib_qp, + IN struct ib_qp_attr *p_ib_qp_attr, + OUT ib_qp_attr_t *p_qp_attr + ); + +enum ib_qp_type to_qp_type(ib_qp_type_t qp_type); + +ib_qp_type_t from_qp_type(enum ib_qp_type ib_qp_type); + +int +to_av( + IN const struct ib_device *p_ib_dev, + IN const ib_av_attr_t *p_ib_av_attr, + OUT struct ib_ah_attr *p_ib_ah_attr); + +int from_av( + IN const struct ib_device *p_ib_dev, + IN struct ib_qp_attr *p_ib_qp_attr, + IN struct ib_ah_attr *p_ib_ah_attr, + OUT ib_av_attr_t *p_ib_av_attr); + +enum ib_access_flags +to_qp_acl( + IN ib_access_t ibal_acl); + +static inline int from_umv_buf(void *dest, ci_umv_buf_t* const p_umv_buf, size_t len) +{ + RtlCopyMemory(dest, (void*)(ULONG_PTR)p_umv_buf->p_inout_buf, len); + return 0; +} + +static inline int to_umv_buf(ci_umv_buf_t* const p_umv_buf, void *src, size_t len) +{ + if (p_umv_buf->output_size < len) { + p_umv_buf->status = IB_INSUFFICIENT_MEMORY; + p_umv_buf->output_size = 0; + return -EFAULT; + } + RtlCopyMemory( (void*)(ULONG_PTR)p_umv_buf->p_inout_buf, src, len); + p_umv_buf->status = IB_SUCCESS; + p_umv_buf->output_size = (uint32_t)len; + return 0; +} + + +/* interface */ + +void +mlnx_ca_if( + IN OUT ci_interface_t *p_interface ); + +void +mlnx_pd_if( + IN OUT ci_interface_t *p_interface ); + +void +mlnx_av_if( + IN OUT ci_interface_t *p_interface ); + +void +mlnx_cq_if( + IN OUT ci_interface_t *p_interface ); + +void +mlnx_qp_if( + IN OUT ci_interface_t *p_interface ); + +void +mlnx_srq_if( + IN OUT ci_interface_t *p_interface ); + +void +mlnx_mr_if( + IN OUT ci_interface_t *p_interface ); + +void +mlnx_direct_if( + IN OUT ci_interface_t *p_interface ); + +void +mlnx_mcast_if( + IN OUT ci_interface_t *p_interface ); + +void +mlnx_ca_if_livefish( + IN OUT ci_interface_t *p_interface ); + +void +mlnx_mr_if_livefish( + IN OUT ci_interface_t *p_interface ); + + diff --git a/branches/WOF2-3/hw/mlx4/kernel/hca/debug.h b/branches/WOF2-3/hw/mlx4/kernel/hca/debug.h new file mode 100644 index 00000000..a8107981 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/hca/debug.h @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: hca_debug.h 1936 2007-02-06 16:04:33Z sleybo $ + */ + + +#pragma once + +#if defined(EVENT_TRACING) +// +// Software Tracing Definitions +// + +#define WPP_CONTROL_GUIDS \ + WPP_DEFINE_CONTROL_GUID(Mlx4HcaCtlGuid,(F8C96A49,AE22,41e9,8025,D7E416884D89), \ + WPP_DEFINE_BIT( HCA_DBG_DEV) \ + WPP_DEFINE_BIT( HCA_DBG_PNP) \ + WPP_DEFINE_BIT( HCA_DBG_INIT) \ + WPP_DEFINE_BIT( HCA_DBG_MAD) \ + WPP_DEFINE_BIT( HCA_DBG_PO) \ + WPP_DEFINE_BIT( HCA_DBG_PD)\ + WPP_DEFINE_BIT( HCA_DBG_CQ) \ + WPP_DEFINE_BIT( HCA_DBG_QP) \ + WPP_DEFINE_BIT( HCA_DBG_MEMORY) \ + WPP_DEFINE_BIT( HCA_DBG_AV) \ + WPP_DEFINE_BIT( HCA_DBG_SRQ) \ + WPP_DEFINE_BIT( HCA_DBG_MCAST) \ + WPP_DEFINE_BIT( HCA_DBG_LOW) \ + WPP_DEFINE_BIT( HCA_DBG_SHIM)) + + +#define WPP_GLOBALLOGGER + + +#define WPP_LEVEL_FLAGS_ENABLED(lvl, flags) (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= lvl) +#define WPP_LEVEL_FLAGS_LOGGER(lvl,flags) WPP_LEVEL_LOGGER(flags) +#define WPP_FLAG_ENABLED(flags)(WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= TRACE_LEVEL_VERBOSE) +#define WPP_FLAG_LOGGER(flags) WPP_LEVEL_LOGGER(flags) + + +// begin_wpp config +// HCA_ENTER(FLAG); +// HCA_EXIT(FLAG); +// USEPREFIX(HCA_PRINT, "%!STDPREFIX! [MLX4_HCA] :%!FUNC!() :"); +// USESUFFIX(HCA_ENTER, " [MLX4_HCA] :%!FUNC!()["); +// USESUFFIX(HCA_EXIT, " [MLX4_HCA] :%!FUNC!()]"); +// end_wpp + + + +#else + + +#include + +/* + * Debug macros + */ + + +#define HCA_DBG_DEV (1 << 0) +#define HCA_DBG_PNP (1<<1) +#define HCA_DBG_INIT (1 << 2) +#define HCA_DBG_MAD (1 << 3) +#define HCA_DBG_PO (1 << 4) +#define HCA_DBG_PD (1<<5) +#define HCA_DBG_QP (1 << 6) +#define HCA_DBG_CQ (1 << 7) +#define HCA_DBG_MEMORY (1 << 8) +#define HCA_DBG_AV (1<<9) +#define HCA_DBG_SRQ (1 << 10) +#define HCA_DBG_MCAST (1<<11) +#define HCA_DBG_LOW (1 << 12) +#define HCA_DBG_SHIM (1 << 13) + + +#if DBG + +// assignment of _level_ is need to to overcome warning C4127 +#define HCA_PRINT(_level_,_flag_,_msg_) \ + { \ + int __lvl = _level_; \ + if (g.DebugPrintLevel >= (_level_) && \ + (g.DebugPrintFlags & (_flag_))) { \ + cl_dbg_out ("~%d:[MLX4_HCA] %s() :", KeGetCurrentProcessorNumber(), __FUNCTION__); \ + if(__lvl == TRACE_LEVEL_ERROR) cl_dbg_out ("***ERROR*** "); \ + cl_dbg_out _msg_; \ + } \ + } + +#else + +#define HCA_PRINT(lvl ,flags, msg) + +#endif + +#define HCA_ENTER(flags)\ + HCA_PRINT(TRACE_LEVEL_VERBOSE, flags,("[\n")); + +#define HCA_EXIT(flags)\ + HCA_PRINT(TRACE_LEVEL_VERBOSE, flags, ("]\n" )); + + +#endif //EVENT_TRACING + + diff --git a/branches/WOF2-3/hw/mlx4/kernel/hca/direct.c b/branches/WOF2-3/hw/mlx4/kernel/hca/direct.c new file mode 100644 index 00000000..3ac85e58 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/hca/direct.c @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2004-2005 Mellanox Technologies, Inc. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: hca_direct.c 1936 2007-02-06 16:04:33Z sleybo $ + */ + + +#include "precomp.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "direct.tmh" +#endif + + +/* +* Work Request Processing Verbs. +*/ + + +ib_api_status_t +mlnx_post_send ( + IN const ib_qp_handle_t h_qp, + IN ib_send_wr_t *p_send_wr, + OUT ib_send_wr_t **pp_failed ) +{ + int err; + ib_api_status_t status = IB_SUCCESS; + struct ib_qp *p_ib_qp = (struct ib_qp *)h_qp; + + HCA_ENTER(HCA_DBG_QP); + + err = p_ib_qp->device->post_send(p_ib_qp, p_send_wr, pp_failed ); + if (err) { + if (err == -ENOMEM) + status = IB_INSUFFICIENT_RESOURCES; + else + status = errno_to_iberr(err); + } + + if (status != IB_SUCCESS) + HCA_PRINT(TRACE_LEVEL_ERROR , HCA_DBG_QP, + ("post_send failed with status %x\n", status)); + HCA_EXIT(HCA_DBG_QP); + return status; + +} + + +ib_api_status_t +mlnx_post_recv ( + IN const ib_qp_handle_t h_qp, + IN ib_recv_wr_t *p_recv_wr, + OUT ib_recv_wr_t **pp_failed OPTIONAL ) +{ + int err; + ib_api_status_t status = IB_SUCCESS; + struct ib_qp *p_ib_qp = (struct ib_qp *)h_qp; + + HCA_ENTER(HCA_DBG_QP); + + err = p_ib_qp->device->post_recv(p_ib_qp, p_recv_wr, pp_failed ); + if (err) { + if (err == -ENOMEM) + status = IB_INSUFFICIENT_RESOURCES; + else + status = errno_to_iberr(err); + } + + if (status != IB_SUCCESS) + HCA_PRINT(TRACE_LEVEL_ERROR , HCA_DBG_QP, + ("post_recv failed with status %x\n", status)); + HCA_EXIT(HCA_DBG_QP); + return status; + +} + +ib_api_status_t +mlnx_post_srq_recv ( + IN const ib_srq_handle_t h_srq, + IN ib_recv_wr_t *p_recv_wr, + OUT ib_recv_wr_t **pp_failed OPTIONAL ) +{ + int err; + ib_api_status_t status = IB_SUCCESS; + struct ib_srq *p_ib_srq = (struct ib_srq *)h_srq; + + HCA_ENTER(HCA_DBG_SRQ); + + err = p_ib_srq->device->post_srq_recv(p_ib_srq, p_recv_wr, pp_failed ); + if (err) { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_SRQ, + ("post_srq_recv failed (%d)\n", err)); + if (err == -ENOMEM) + status = IB_INSUFFICIENT_RESOURCES; + else + status = errno_to_iberr(err); + } + + if (status != IB_SUCCESS) + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_SRQ, + ("post_srq_recv failed with status %x\n", status)); + HCA_EXIT(HCA_DBG_SRQ); + return status; +} + +/* +* Completion Processing and Completion Notification Request Verbs. +*/ + +ib_api_status_t +mlnx_peek_cq( + IN const ib_cq_handle_t h_cq, + OUT uint32_t* const p_n_cqes ) +{ + int err; + ib_api_status_t status; + struct ib_cq *p_ib_cq = (struct ib_cq *)h_cq; + + HCA_ENTER(HCA_DBG_CQ); + + err = p_ib_cq->device->peek_cq ? + p_ib_cq->device->peek_cq(p_ib_cq, *p_n_cqes) : -ENOSYS; + status = errno_to_iberr(err); + if (status != IB_SUCCESS) + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_CQ, + ("ib_peek_cq failed with status %x\n", status)); + + HCA_EXIT(HCA_DBG_CQ); + return status; +} + +ib_api_status_t +mlnx_poll_cq ( + IN const ib_cq_handle_t h_cq, + IN OUT ib_wc_t** const pp_free_wclist, + OUT ib_wc_t** const pp_done_wclist ) +{ + int err; + ib_api_status_t status = IB_SUCCESS; + struct ib_cq *p_ib_cq = (struct ib_cq *)h_cq; + + HCA_ENTER(HCA_DBG_CQ); + + // sanity checks + if (!pp_free_wclist || !pp_done_wclist || !*pp_free_wclist) { + status = IB_INVALID_PARAMETER; + goto err_invalid_params; + } + + // poll CQ + err = p_ib_cq->device->poll_cq(p_ib_cq, pp_free_wclist, pp_done_wclist); + if (err < 0) + status = errno_to_iberr(err); + else if (!*pp_done_wclist) + status = IB_NOT_FOUND; + +err_invalid_params: + if (status != IB_SUCCESS && status != IB_NOT_FOUND) + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_CQ, + ("mthca_poll_cq_list failed with status %x\n", status)); + HCA_EXIT(HCA_DBG_CQ); + return status; + +} + +ib_api_status_t +mlnx_enable_cq_notify ( + IN const ib_cq_handle_t h_cq, + IN const boolean_t solicited ) +{ + int err; + ib_api_status_t status; + struct ib_cq *p_ib_cq = (struct ib_cq *)h_cq; + + HCA_ENTER(HCA_DBG_CQ); + + err = ib_req_notify_cq(p_ib_cq, + (solicited) ? IB_CQ_SOLICITED : IB_CQ_NEXT_COMP ); + status = errno_to_iberr(err); + if (status != IB_SUCCESS) + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_CQ, + ("ib_req_notify_cq failed with status %x\n", status)); + + HCA_EXIT(HCA_DBG_CQ); + return status; +} + +ib_api_status_t +mlnx_enable_ncomp_cq_notify ( + IN const ib_cq_handle_t h_cq, + IN const uint32_t n_cqes ) +{ + int err; + ib_api_status_t status; + struct ib_cq *p_ib_cq = (struct ib_cq *)h_cq; + + HCA_ENTER(HCA_DBG_CQ); + + err = ib_req_ncomp_notif(p_ib_cq, n_cqes); + status = errno_to_iberr(err); + if (status != IB_SUCCESS) + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_CQ, + ("ib_req_ncomp_notif failed with status %x\n", status)); + + HCA_EXIT(HCA_DBG_CQ); + return status; +} + + +ib_api_status_t +mlnx_bind_mw ( + IN const ib_mw_handle_t h_mw, + IN const ib_qp_handle_t h_qp, + IN ib_bind_wr_t* const p_mw_bind, + OUT net32_t* const p_rkey ) +{ + int err; + ib_api_status_t status; + struct ib_mw *p_ib_mw = (struct ib_mw *)h_mw; + struct ib_qp *p_ib_qp = (struct ib_qp *)h_qp; + struct ib_mw_bind ib_mw_bind; + + UNUSED_PARAM(p_mw_bind); + UNUSED_PARAM(p_rkey); + + HCA_ENTER(HCA_DBG_MEMORY); + + // TODO: convert ib_bind_wr_t to struct ib_mw_bind + + err = p_ib_qp->device->bind_mw ? + p_ib_qp->device->bind_mw(p_ib_qp, p_ib_mw, &ib_mw_bind) : -ENOSYS; + status = errno_to_iberr(err); + + if (status != IB_SUCCESS) + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_CQ, + ("ib_bind_mw failed with status %x\n", status)); + HCA_EXIT(HCA_DBG_MEMORY); + return status; +} + + +void +mlnx_direct_if( + IN OUT ci_interface_t *p_interface ) +{ + p_interface->post_send = mlnx_post_send; + p_interface->post_recv = mlnx_post_recv; + p_interface->post_srq_recv = mlnx_post_srq_recv; + + p_interface->enable_ncomp_cq_notify = mlnx_enable_ncomp_cq_notify; + p_interface->peek_cq = NULL; /* mlnx_peek_cq: Not implemented */ + p_interface->poll_cq = mlnx_poll_cq; + p_interface->enable_cq_notify = mlnx_enable_cq_notify; + + p_interface->bind_mw = mlnx_bind_mw; +} diff --git a/branches/WOF2-3/hw/mlx4/kernel/hca/drv.c b/branches/WOF2-3/hw/mlx4/kernel/hca/drv.c new file mode 100644 index 00000000..9302dd29 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/hca/drv.c @@ -0,0 +1,2015 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: al.c 1611 2006-08-20 14:48:55Z sleybo $ + */ + +#include "precomp.h" +#include +#include +#include + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "drv.tmh" +#endif + +GLOBALS g; + +/* + * UVP name does not include file extension. For debug builds, UAL + * will append "d.dll". For release builds, UAL will append ".dll" + */ +char mlnx_uvp_lib_name[MAX_LIB_NAME] = {"mlx4u"}; + +static int __get_dev_info(PFDO_DEVICE_DATA p_fdo, __be64 *node_guid, u32 *hw_id) +{ + struct ib_device_attr device_attr; + struct ib_device *p_ibdev = p_fdo->bus_ib_ifc.p_ibdev; + int err; + + HCA_ENTER( HCA_DBG_PNP ); + if ( hca_is_livefish(p_fdo) ) { + *node_guid = cl_hton64((uint64_t)(ULONG_PTR)p_ibdev); + p_ibdev->node_guid = *node_guid; + *hw_id = 0; + return 0; + } + + err = (p_ibdev->query_device)( p_ibdev, &device_attr ); + if (err) + return err; + + *node_guid = p_ibdev->node_guid; + *hw_id = device_attr.hw_ver; + HCA_EXIT( HCA_DBG_PNP ); + return 0; +} + +#ifndef USE_WDM_FRAMEWORK + +static ci_interface_t* +__alloc_hca_ifc( + IN PFDO_DEVICE_DATA const p_fdo ) +{ + ci_interface_t *pIfc; + + HCA_ENTER( HCA_DBG_PNP ); + + pIfc = + (ci_interface_t*)ExAllocatePoolWithTag( NonPagedPool, sizeof(ci_interface_t), MT_TAG_KERNEL ); + if( !pIfc ) + { + HCA_PRINT( TRACE_LEVEL_ERROR,HCA_DBG_PNP, + ("Failed to allocate ci_interface_t (%d bytes).\n", + sizeof(ci_interface_t))); + return NULL; + } + + setup_ci_interface( p_fdo->hca.guid, !!hca_is_livefish(p_fdo), pIfc ); + + pIfc->p_hca_obj = &p_fdo->hca; + pIfc->vend_id = (uint32_t)p_fdo->bus_ib_ifc.pdev->ven_id; + pIfc->dev_id = (uint16_t)p_fdo->bus_ib_ifc.pdev->dev_id; + pIfc->dev_revision = (uint16_t)p_fdo->hca.hw_ver; + + HCA_EXIT( HCA_DBG_PNP ); + return pIfc; +} + +static void +__unmap_hca_memory( + IN PFDO_DEVICE_DATA const p_fdo ) +{ + struct pci_dev *pdev = p_fdo->bus_ib_ifc.pdev; + int i; + + HCA_ENTER( HCA_DBG_PNP ); + + for( i = 0; i < HCA_BAR_TYPE_MAX; i++ ) { + if (pdev->bar[i].virt) { + MmUnmapIoSpace( pdev->bar[i].virt, pdev->bar[i].size ); + cl_memclr( &pdev->bar[i], sizeof(hca_bar_t) ); + } + } + + HCA_EXIT( HCA_DBG_PNP ); +} + +/* release the resources, allocated in hca_start */ +static void +__hca_release_resources( + IN WDFDEVICE Device ) +{ + PFDO_DEVICE_DATA p_fdo = FdoGetData(Device); + + HCA_ENTER( HCA_DBG_PNP ); + + switch( p_fdo->state ) + { + case HCA_STARTED: + /* dequeue HCA */ + mlnx_hca_remove( &p_fdo->hca ); + } + + __unmap_hca_memory( p_fdo ); + + p_fdo->state = HCA_ADDED; + + HCA_EXIT( HCA_DBG_PNP ); +} + +static void +__ref_ifc( + IN DEVICE_OBJECT* p_dev_obj ) +{ + PFDO_DEVICE_DATA p_fdo = (PFDO_DEVICE_DATA)p_dev_obj->DeviceExtension; + + HCA_ENTER( HCA_DBG_PNP ); + + cl_atomic_inc( &p_fdo->n_hca_ifc_ref ); + ObReferenceObject( p_dev_obj ); + + HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PNP, + ("MLX4_HCA: CA_guid %I64x, hca_ifc_ref %d\n", + p_fdo->hca.guid, p_fdo->n_hca_ifc_ref) ); + + HCA_EXIT( HCA_DBG_PNP ); +} + +static void +__deref_ifc( + IN DEVICE_OBJECT* p_dev_obj ) +{ + PFDO_DEVICE_DATA p_fdo = (PFDO_DEVICE_DATA)p_dev_obj->DeviceExtension; + + HCA_ENTER( HCA_DBG_PNP ); + + cl_atomic_dec( &p_fdo->n_hca_ifc_ref ); + ObDereferenceObject( p_dev_obj ); + + HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PNP, + ("MLX4_HCA: CA_guid %I64x, hca_ifc_ref %d\n", + p_fdo->hca.guid, p_fdo->n_hca_ifc_ref) ); + + HCA_EXIT( HCA_DBG_PNP ); +} + + + +NTSTATUS +EvtDeviceD0Entry( + IN WDFDEVICE Device, + IN WDF_POWER_DEVICE_STATE PreviousState + ) +{ + NTSTATUS status; + PFDO_DEVICE_DATA p_fdo = FdoGetData(Device); + + HCA_ENTER( HCA_DBG_PNP ); + HCA_PRINT(TRACE_LEVEL_INFORMATION, HCA_DBG_PNP, ("EvtDeviceD0Entry: PreviousState 0x%x\n", PreviousState)); + // start card (needed after Hibernation or standby) + if (PreviousState > WdfPowerDeviceD0) { + /* get MLX4_BUS IB interface */ + if ( !p_fdo->bus_ib_ifc_taken ) { + status = WdfFdoQueryForInterface( Device, &MLX4_BUS_IB_INTERFACE_GUID, + (PINTERFACE)&p_fdo->bus_ib_ifc, sizeof(MLX4_BUS_IB_INTERFACE), MLX4_BUS_IB_INTERFACE_VERSION, NULL ); + if( !NT_SUCCESS( status ) ) { + HCA_PRINT(TRACE_LEVEL_ERROR, HCA_DBG_PNP, ("Getting MLX4 BUS interface failed: status=0x%x\n", status)); + return status; + } + p_fdo->bus_ib_ifc_taken = TRUE; + p_fdo->bus_ib_ifc.p_ibdev->x.p_fdo = p_fdo; + } + } + HCA_EXIT( HCA_DBG_PNP ); + return STATUS_SUCCESS; +} + +NTSTATUS +EvtDeviceD0Exit( + IN WDFDEVICE Device, + IN WDF_POWER_DEVICE_STATE TargetState + ) +{ + NTSTATUS status; + PFDO_DEVICE_DATA p_fdo = FdoGetData(Device); + + HCA_ENTER( HCA_DBG_PNP ); + + HCA_PRINT(TRACE_LEVEL_INFORMATION, HCA_DBG_PNP, ("EvtDeviceD0Exit: TargetState 0x%x\n", TargetState)); + + switch (TargetState) { + case WdfPowerDeviceD1: /* hopefully, it is STANDBY state */ + case WdfPowerDeviceD2: /* hopefully, it is STANDBY state */ + case WdfPowerDeviceD3: /* hopefully, it is STANDBY state */ + case WdfPowerDevicePrepareForHibernation: + if (atomic_read(&p_fdo->usecnt)) { + status = STATUS_UNSUCCESSFUL; + break; + } + /* Fall through. */ + default: + status = STATUS_SUCCESS; + break; + } + + if (TargetState > WdfPowerDeviceD0) { + if(p_fdo->bus_ib_ifc_taken) { + PINTERFACE p_ifc = (PINTERFACE)&p_fdo->bus_ib_ifc; + p_ifc->InterfaceDereference( p_ifc->Context ); + p_fdo->bus_ib_ifc_taken = FALSE; + } + } + + HCA_EXIT( HCA_DBG_PNP ); + return status; +} + +NTSTATUS +EvtDevicePrepareHardware( + IN WDFDEVICE Device, + IN WDFCMRESLIST ResourcesRaw, + IN WDFCMRESLIST ResourcesTranslated + ) +{ + int err; + NTSTATUS status; + PFDO_DEVICE_DATA p_fdo = FdoGetData(Device); + BUS_INTERFACE_STANDARD bus_pci_ifc; + ci_interface_t *p_hca_ifc; + RDMA_INTERFACE_VERBS rdma_ifc, *p_ifc = &rdma_ifc; + WDF_QUERY_INTERFACE_CONFIG qiConfig; + + UNUSED_PARAM(ResourcesRaw); + UNUSED_PARAM(ResourcesTranslated); + + HCA_ENTER( HCA_DBG_PNP ); + + HCA_PRINT(TRACE_LEVEL_INFORMATION, HCA_DBG_PNP, ("EvtPrepareHardware: \n")); + + /* get PCI BUS interface */ + status = WdfFdoQueryForInterface( Device, &GUID_BUS_INTERFACE_STANDARD, + (PINTERFACE)&bus_pci_ifc, sizeof(BUS_INTERFACE_STANDARD), 1, NULL ); + if( !NT_SUCCESS( status ) ) { + HCA_PRINT(TRACE_LEVEL_ERROR, HCA_DBG_PNP, ("Getting PCI BUS interface failed: status=0x%x\n", status)); + return status; + } + RtlCopyMemory( &p_fdo->bus_pci_ifc, &bus_pci_ifc, sizeof(BUS_INTERFACE_STANDARD) ); + p_fdo->bus_pci_ifc_taken = TRUE; + + /* get MLX4_BUS IB interface */ + if ( !p_fdo->bus_ib_ifc_taken ) { + status = WdfFdoQueryForInterface( Device, &MLX4_BUS_IB_INTERFACE_GUID, + (PINTERFACE)&p_fdo->bus_ib_ifc, sizeof(MLX4_BUS_IB_INTERFACE), MLX4_BUS_IB_INTERFACE_VERSION, NULL ); + if( !NT_SUCCESS( status ) ) { + HCA_PRINT(TRACE_LEVEL_ERROR, HCA_DBG_PNP, ("Getting MLX4 BUS interface failed: status=0x%x\n", status)); + return status; + } + p_fdo->bus_ib_ifc_taken = TRUE; + p_fdo->bus_ib_ifc.p_ibdev->x.p_fdo = p_fdo; + } + + InitializeListHead(&p_fdo->hca.event_list); + KeInitializeSpinLock(&p_fdo->hca.event_list_lock); + + /* get node GUID */ + err = __get_dev_info( p_fdo, &p_fdo->hca.guid, &p_fdo->hca.hw_ver ); + if (err) { + + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_LOW , + ("can't get guid - ib_query_device() failed (%08X)\n", err )); + //TODO: no cleanup on error + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* queue HCA */ + mlnx_hca_insert( &p_fdo->hca ); + + /* Allocate and populate our HCA interface structure. */ + p_hca_ifc = __alloc_hca_ifc( p_fdo ); + if( !p_hca_ifc ) { + HCA_PRINT( TRACE_LEVEL_ERROR ,HCA_DBG_PNP ,("__alloc_hca_ifc failed.\n")); + return STATUS_NO_MEMORY; + } + + /* fill interface fields */ + p_ifc->InterfaceHeader.Size = sizeof(RDMA_INTERFACE_VERBS); + p_ifc->InterfaceHeader.Version = VerbsVersion(VERBS_MAJOR_VER, VERBS_MINOR_VER); + p_ifc->InterfaceHeader.Context = p_fdo->p_dev_obj; + p_ifc->InterfaceHeader.InterfaceReference = __ref_ifc; + p_ifc->InterfaceHeader.InterfaceDereference = __deref_ifc; + p_ifc->Verbs = *p_hca_ifc; + ExFreePool( p_hca_ifc ); + + /* create an upper interface */ + WDF_QUERY_INTERFACE_CONFIG_INIT( &qiConfig, (PINTERFACE)p_ifc, + &GUID_RDMA_INTERFACE_VERBS, NULL); + + status = WdfDeviceAddQueryInterface( Device, &qiConfig ); + if (!NT_SUCCESS(status)) { + HCA_PRINT( TRACE_LEVEL_ERROR ,HCA_DBG_PNP ,("WdfDeviceAddQueryInterface failed %#x\n", status)); + return status; + } + + /* + * Change the state since the PnP callback can happen + * before the callback returns. + */ + p_fdo->state = HCA_STARTED; + + HCA_EXIT( HCA_DBG_PNP ); + return STATUS_SUCCESS; +} + + +NTSTATUS +EvtDeviceReleaseHardware( + IN WDFDEVICE Device, + IN WDFCMRESLIST ResourcesTranslated + ) +{ + PFDO_DEVICE_DATA p_fdo = FdoGetData(Device); + + UNUSED_PARAM(ResourcesTranslated); + + HCA_ENTER( HCA_DBG_PNP ); + + HCA_PRINT(TRACE_LEVEL_INFORMATION, HCA_DBG_PNP, ("EvtDeviceReleaseHardware: FdoData=0x%p\n", p_fdo)); + + // release IBBUS resources + __hca_release_resources(Device); + + // release MLX4_BUS resources + if(p_fdo->bus_ib_ifc_taken) { + PINTERFACE p_ifc = (PINTERFACE)&p_fdo->bus_ib_ifc; + p_ifc->InterfaceDereference( p_ifc->Context ); + p_fdo->bus_ib_ifc_taken = FALSE; + } + + // release PCI BUS resources + if(p_fdo->bus_pci_ifc_taken) { + PINTERFACE p_ifc = (PINTERFACE)&p_fdo->bus_pci_ifc; + p_ifc->InterfaceDereference( p_ifc->Context ); + p_fdo->bus_pci_ifc_taken = FALSE; + } + + HCA_EXIT( HCA_DBG_PNP ); + return STATUS_SUCCESS; +} + +NTSTATUS +EvtDeviceQueryRemove( + IN WDFDEVICE Device + ) +{ + PFDO_DEVICE_DATA p_fdo = FdoGetData(Device); + HCA_ENTER( HCA_DBG_PNP ); + if (atomic_read(&p_fdo->usecnt)) { + cl_dbg_out( "MLX4_HCA: Can't get unloaded. %d applications are still in work\n", p_fdo->usecnt); + return STATUS_UNSUCCESSFUL; + } + HCA_EXIT( HCA_DBG_PNP ); + return STATUS_SUCCESS; +} + + +NTSTATUS +EvtDriverDeviceAdd( + IN WDFDRIVER Driver, + IN PWDFDEVICE_INIT DeviceInit + ) +/*++ +Routine Description: + + EvtDriverDeviceAdd is called by the framework in response to AddDevice + call from the PnP manager. We create and initialize a device object to + represent a new instance of mxe bus. + +Arguments: + + Driver - Handle to a framework driver object created in DriverEntry + + DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure. + +Return Value: + + NTSTATUS + +--*/ +{ + WDF_OBJECT_ATTRIBUTES attributes; + NTSTATUS status; + WDFDEVICE device; + PFDO_DEVICE_DATA p_fdo; + WDF_PNPPOWER_EVENT_CALLBACKS Callbacks; + + UNREFERENCED_PARAMETER(Driver); + + PAGED_CODE (); + + HCA_PRINT(TRACE_LEVEL_INFORMATION, HCA_DBG_PNP, ("EvtDriverDeviceAdd: 0x%p\n", Driver)); + // + // register PnP & Power stuff + // + WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&Callbacks); + Callbacks.EvtDevicePrepareHardware = EvtDevicePrepareHardware; + Callbacks.EvtDeviceReleaseHardware = EvtDeviceReleaseHardware; + Callbacks.EvtDeviceQueryRemove = EvtDeviceQueryRemove; + Callbacks.EvtDeviceD0Entry = EvtDeviceD0Entry; + Callbacks.EvtDeviceD0Exit = EvtDeviceD0Exit; + + WdfDeviceInitSetPnpPowerEventCallbacks( DeviceInit, &Callbacks ); + + // + // Initialize all the properties specific to the device. + // Framework has default values for the one that are not + // set explicitly here. So please read the doc and make sure + // you are okay with the defaults. + // + WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_INFINIBAND); + WdfDeviceInitSetExclusive(DeviceInit, FALSE); + + // + // Initialize attributes structure to specify size and accessor function + // for storing device context. + // + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, FDO_DEVICE_DATA); + + // + // Create a framework device object. In response to this call, framework + // creates a WDM deviceobject. + // + status = WdfDeviceCreate(&DeviceInit, &attributes, &device); + if (!NT_SUCCESS(status)) { + HCA_PRINT(TRACE_LEVEL_VERBOSE, HCA_DBG_PNP, ("EvtDriverDeviceAdd: WdfDeviceCreate failed with 0x%x\n", status)); + goto end; + } + + // + // Init device context. + // + p_fdo = FdoGetData(device); + RtlZeroMemory(p_fdo, sizeof(FDO_DEVICE_DATA)); + p_fdo->FdoDevice = device; + p_fdo->p_dev_obj = WdfDeviceWdmGetDeviceObject( device ); + spin_lock_init( &p_fdo->uctx_lock ); + cl_qlist_init( &p_fdo->uctx_list ); + atomic_set(&p_fdo->usecnt, 0); + p_fdo->state = HCA_ADDED; + + // + // WMI + // + status = WmiRegistration(device); + if (!NT_SUCCESS(status)) { + return status; + } + + status = STATUS_SUCCESS; + +end: + HCA_EXIT( HCA_DBG_PNP ); + return status; +} + + +void +EvtDriverUnload( + IN WDFDRIVER Driver + ) +{ + HCA_ENTER( HCA_DBG_PNP ); + + UNUSED_PARAM( Driver ); + + HCA_EXIT( HCA_DBG_PNP ); +#if defined(EVENT_TRACING) + WPP_CLEANUP(WdfDriverWdmGetDriverObject(Driver)); +#endif +} + +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath + ) +/*++ +Routine Description: + + Initialize the call backs structure of Driver Framework. + +Arguments: + + DriverObject - pointer to the driver object + + RegistryPath - pointer to a unicode string representing the path, + to driver-specific key in the registry. + +Return Value: + + NT Status Code + +--*/ +{ + WDF_DRIVER_CONFIG config; + NTSTATUS status; + WDFDRIVER hDriver; + +#if defined(EVENT_TRACING) + WPP_INIT_TRACING(DriverObject, RegistryPath); +#endif + + // global initializations + g.DebugPrintLevel = TRACE_LEVEL_VERBOSE; + g.DebugPrintFlags = 0xffff; + HCA_ENTER( HCA_DBG_PNP ); + + status = mlnx_hcas_init(); + if( status != STATUS_SUCCESS ) { + HCA_PRINT( TRACE_LEVEL_ERROR ,HCA_DBG_PNP , + ("mlnx_hcas_init returned %#x.\n", status)); + goto end; + } + + // + // Initiialize driver config to control the attributes that + // are global to the driver. Note that framework by default + // provides a driver unload routine. If you create any resources + // in the DriverEntry and want to be cleaned in driver unload, + // you can override that by specifing one in the Config structure. + // + + WDF_DRIVER_CONFIG_INIT( + &config, EvtDriverDeviceAdd ); + config.EvtDriverUnload = EvtDriverUnload; + + // + // Create a framework driver object to represent our driver. + // + status = WdfDriverCreate(DriverObject, + RegistryPath, WDF_NO_OBJECT_ATTRIBUTES, + &config, &hDriver); + + if (!NT_SUCCESS(status)) { + HCA_PRINT(TRACE_LEVEL_VERBOSE, HCA_DBG_PNP, ("WdfDriverCreate failed with status 0x%x\n", status)); + goto end; + } + + // + // read registry parameters + // + { + DECLARE_CONST_UNICODE_STRING(valueName0, L"DebugLevel"); + DECLARE_CONST_UNICODE_STRING(valueName1, L"DebugFlags"); + ULONG value; + WDFKEY hKey = NULL; + + status = WdfDriverOpenParametersRegistryKey( hDriver, + STANDARD_RIGHTS_ALL, WDF_NO_OBJECT_ATTRIBUTES, &hKey ); + + if (NT_SUCCESS (status)) { + + status = WdfRegistryQueryULong(hKey, &valueName0, &value); + if (NT_SUCCESS (status)) g.DebugPrintLevel = value; + + status = WdfRegistryQueryULong(hKey, &valueName1, &value); + if (NT_SUCCESS (status)) g.DebugPrintFlags = value; + + WdfRegistryClose(hKey); + } + + // we don't matter the failure in the work with Registry + status = STATUS_SUCCESS; + } + +end: + HCA_PRINT( TRACE_LEVEL_INFORMATION,HCA_DBG_PNP , + ("exit status %#x.\n", status)); + HCA_EXIT( HCA_DBG_PNP ); + return status; + +} + +#else + + +UNICODE_STRING g_param_path; +static cl_vfptr_pnp_po_t vfptrHcaPnp; + +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT p_driver_obj, + IN PUNICODE_STRING p_registry_path ); + +static NTSTATUS +__read_registry( + IN UNICODE_STRING* const p_Param_Path ); + +static void +hca_drv_unload( + IN PDRIVER_OBJECT p_driver_obj ); + +static NTSTATUS +hca_sysctl( + IN PDEVICE_OBJECT p_dev_obj, + IN PIRP p_irp ); + +NTSTATUS +hca_add_device( + IN PDRIVER_OBJECT pDriverObj, + IN PDEVICE_OBJECT pPdo ); + +static NTSTATUS +hca_start( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +hca_query_stop( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +hca_stop( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +hca_cancel_stop( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +hca_query_remove( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static void +hca_release_resources( + IN DEVICE_OBJECT* const p_dev_obj ); + +static NTSTATUS +hca_cancel_remove( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +hca_surprise_remove( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +hca_query_capabilities( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +hca_query_interface( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +hca_query_pnp_state( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +hca_query_bus_relations( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +hca_query_removal_relations( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +hca_query_power( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +hca_set_power( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static ci_interface_t* +__alloc_hca_ifc( + IN FDO_DEVICE_DATA* const p_fdo ); + +static NTSTATUS +__get_ci_interface( + IN DEVICE_OBJECT* const p_dev_obj ); + + + + +NTSTATUS +hca_add_device( + IN PDRIVER_OBJECT pDriverObj, + IN PDEVICE_OBJECT pPdo ) +{ + NTSTATUS status; + DEVICE_OBJECT *p_dev_obj, *pNextDevObj; + PFDO_DEVICE_DATA p_fdo; + + HCA_ENTER(HCA_DBG_PNP); + + /* + * Create the device so that we have a device extension to store stuff in. + */ + status = IoCreateDevice( pDriverObj, sizeof(FDO_DEVICE_DATA), + NULL, FILE_DEVICE_INFINIBAND, FILE_DEVICE_SECURE_OPEN, + FALSE, &p_dev_obj ); + if( !NT_SUCCESS( status ) ) + { + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, + ("IoCreateDevice returned 0x%08X.\n", status)); + return status; + } + + p_fdo = (PFDO_DEVICE_DATA)p_dev_obj->DeviceExtension; + cl_memclr( p_fdo, sizeof(FDO_DEVICE_DATA) ); + cl_spinlock_init( &p_fdo->uctx_lock ); + cl_qlist_init( &p_fdo->uctx_list ); + atomic_set(&p_fdo->usecnt, 0); + + /* Attach to the device stack. */ + pNextDevObj = IoAttachDeviceToDeviceStack( p_dev_obj, pPdo ); + if( !pNextDevObj ) + { + //cl_event_destroy( &p_fdo->mutex ); + IoDeleteDevice( p_dev_obj ); + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, + ("IoAttachDeviceToDeviceStack failed.\n")); + return STATUS_NO_SUCH_DEVICE; + } + + /* Inititalize the complib extension. */ + cl_init_pnp_po_ext( p_dev_obj, pNextDevObj, pPdo, CL_DBG_PNP | CL_DBG_ERROR, + &vfptrHcaPnp, NULL ); + + p_fdo->state = HCA_ADDED; + + HCA_EXIT(HCA_DBG_PNP); + return status; +} + +static void +__put_ifc( + IN PINTERFACE p_ifc ) +{ + HCA_ENTER( HCA_DBG_PNP ); + p_ifc->InterfaceDereference( p_ifc->Context ); + HCA_EXIT( HCA_DBG_PNP ); +} + +/* Forwards the request to the HCA's PDO. */ +static NTSTATUS +__get_ifc( + IN DEVICE_OBJECT* const pDevObj, + IN const GUID* const pGuid, + IN USHORT size, + IN USHORT Version, + IN OUT PVOID InterfaceSpecificData, + OUT PINTERFACE pBusIfc ) +{ + NTSTATUS status; + IRP *pIrp; + IO_STATUS_BLOCK ioStatus; + IO_STACK_LOCATION *pIoStack; + DEVICE_OBJECT *pDev; + KEVENT event; + + HCA_ENTER( HCA_DBG_PNP ); + + CL_ASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL ); + + pDev = IoGetAttachedDeviceReference( pDevObj ); + + KeInitializeEvent( &event, NotificationEvent, FALSE ); + + /* Build the IRP for the HCA. */ + pIrp = IoBuildSynchronousFsdRequest( IRP_MJ_PNP, pDev, + NULL, 0, NULL, &event, &ioStatus ); + if( !pIrp ) + { + ObDereferenceObject( pDev ); + HCA_PRINT( TRACE_LEVEL_ERROR,HCA_DBG_PNP, + ("IoBuildSynchronousFsdRequest failed.\n")); + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* Copy the request query parameters. */ + pIoStack = IoGetNextIrpStackLocation( pIrp ); + pIoStack->MinorFunction = IRP_MN_QUERY_INTERFACE; + pIoStack->Parameters.QueryInterface.Size = size; + pIoStack->Parameters.QueryInterface.Version = Version; + pIoStack->Parameters.QueryInterface.InterfaceType = pGuid; + pIoStack->Parameters.QueryInterface.Interface = (INTERFACE*)pBusIfc; + pIoStack->Parameters.QueryInterface.InterfaceSpecificData = InterfaceSpecificData; + + pIrp->IoStatus.Status = STATUS_NOT_SUPPORTED; + + /* Send the IRP. */ + status = IoCallDriver( pDev, pIrp ); + if( status == STATUS_PENDING ) + { + KeWaitForSingleObject( &event, Executive, KernelMode, + FALSE, NULL ); + + status = ioStatus.Status; + } + ObDereferenceObject( pDev ); + + HCA_EXIT( HCA_DBG_PNP ); + return status; +} + +static ci_interface_t* +__alloc_hca_ifc( + IN PFDO_DEVICE_DATA const p_fdo ) +{ + ci_interface_t *pIfc; + + HCA_ENTER( HCA_DBG_PNP ); + + pIfc = (ci_interface_t*)ExAllocatePoolWithTag( NonPagedPool, + sizeof(ci_interface_t), MT_TAG_KERNEL ); + if( !pIfc ) + { + HCA_PRINT( TRACE_LEVEL_ERROR,HCA_DBG_PNP, + ("Failed to allocate ci_interface_t (%d bytes).\n", + sizeof(ci_interface_t))); + return NULL; + } + + setup_ci_interface( p_fdo->hca.guid, !!hca_is_livefish(p_fdo), pIfc ); + + pIfc->p_hca_obj = &p_fdo->hca; + pIfc->vend_id = (uint32_t)p_fdo->bus_ib_ifc.pdev->ven_id; + pIfc->dev_id = (uint16_t)p_fdo->bus_ib_ifc.pdev->dev_id; + pIfc->dev_revision = (uint16_t)p_fdo->hca.hw_ver; + + HCA_EXIT( HCA_DBG_PNP ); + return pIfc; +} + +static void +__unmap_hca_memory( + IN PFDO_DEVICE_DATA const p_fdo ) +{ + struct pci_dev *pdev = p_fdo->bus_ib_ifc.pdev; + int i; + + HCA_ENTER( HCA_DBG_PNP ); + + if ( pdev ) + for( i = 0; i < HCA_BAR_TYPE_MAX; i++ ) { + if (pdev->bar[i].virt) { + MmUnmapIoSpace( pdev->bar[i].virt, pdev->bar[i].size ); + cl_memclr( &pdev->bar[i], sizeof(hca_bar_t) ); + } + } + + HCA_EXIT( HCA_DBG_PNP ); +} + + +/* release the resources, allocated in hca_start */ +static void +__hca_release_resources( + IN DEVICE_OBJECT* const p_dev_obj ) +{ + PFDO_DEVICE_DATA p_fdo = (PFDO_DEVICE_DATA)p_dev_obj->DeviceExtension; + + HCA_ENTER( HCA_DBG_PNP ); + + switch( p_fdo->state ) + { + case HCA_STARTED: + /* dequeue HCA */ + mlnx_hca_remove( &p_fdo->hca ); + } + + if (p_fdo->al_sym_name.Buffer) { + ExFreePool( p_fdo->al_sym_name.Buffer ); + p_fdo->al_sym_name.Buffer = NULL; + } + + if( p_fdo->pnp_target_entry ) + { + ASSERT( p_fdo->pnp_ifc_entry ); + IoUnregisterPlugPlayNotification( p_fdo->pnp_target_entry ); + p_fdo->pnp_target_entry = NULL; + } + + if( p_fdo->pnp_ifc_entry ) { + IoUnregisterPlugPlayNotification( p_fdo->pnp_ifc_entry ); + p_fdo->pnp_ifc_entry = NULL; + } + + if( p_fdo->p_al_file_obj ) { + ObDereferenceObject( p_fdo->p_al_file_obj ); + p_fdo->p_al_file_obj = NULL; + } + + // release MLX4_BUS resources + if(p_fdo->bus_ib_ifc_taken) { + p_fdo->bus_ib_ifc_taken = FALSE; + __put_ifc( (PINTERFACE)&p_fdo->bus_ib_ifc ); + } + + // release PCI BUS resources + if(p_fdo->bus_pci_ifc_taken) { + p_fdo->bus_pci_ifc_taken = FALSE; + __put_ifc( (PINTERFACE)&p_fdo->bus_pci_ifc ); + } + + __unmap_hca_memory( p_fdo ); + + p_fdo->state = HCA_ADDED; + + HCA_EXIT( HCA_DBG_PNP ); +} + + +static void +hca_release_resources( + IN DEVICE_OBJECT* const p_dev_obj ) +{ + PFDO_DEVICE_DATA p_fdo; + POWER_STATE powerState; + + HCA_ENTER( HCA_DBG_PNP ); + + p_fdo = (PFDO_DEVICE_DATA)p_dev_obj->DeviceExtension; + + /* release all the resources, allocated in hca_start */ + __hca_release_resources(p_dev_obj); + + /* Notify the power manager that the device is powered down. */ + p_fdo->DevicePowerState = PowerDeviceD3; + powerState.DeviceState = PowerDeviceD3; + powerState = PoSetPowerState ( p_fdo->cl_ext.p_self_do, DevicePowerState, powerState ); + + HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PNP, + ("PoSetPowerState: old state %d, new state to %d\n", + powerState.DeviceState, p_fdo->DevicePowerState )); + + /* Clear the PnP state in case we get restarted. */ + p_fdo->pnpState = 0; + + HCA_EXIT( HCA_DBG_PNP ); +} + +static NTSTATUS +hca_start( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + int err; + NTSTATUS status; + PFDO_DEVICE_DATA p_fdo; + IO_STACK_LOCATION *pIoStack; + POWER_STATE powerState; + BUS_INTERFACE_STANDARD bus_pci_ifc; + + HCA_ENTER( HCA_DBG_PNP ); + + p_fdo = (PFDO_DEVICE_DATA)p_dev_obj->DeviceExtension; + + /* Handled on the way up. */ + status = cl_do_sync_pnp( p_dev_obj, p_irp, p_action ); + if( !NT_SUCCESS( status ) ) + { + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, + ("Lower drivers failed IRP_MN_START_DEVICE (%#x).\n", status)); + goto end; + } + + pIoStack = IoGetCurrentIrpStackLocation( p_irp ); + + /* get PCI BUS interface */ + status = __get_ifc( p_dev_obj, &GUID_BUS_INTERFACE_STANDARD, + sizeof(BUS_INTERFACE_STANDARD), 1, NULL, (PINTERFACE)&bus_pci_ifc); + if( !NT_SUCCESS( status ) ) { + HCA_PRINT(TRACE_LEVEL_ERROR, HCA_DBG_PNP, ("Getting PCI BUS interface failed: status=0x%x\n", status)); + goto end; + } + RtlCopyMemory( &p_fdo->bus_pci_ifc, &bus_pci_ifc, sizeof(BUS_INTERFACE_STANDARD) ); + p_fdo->bus_pci_ifc_taken = TRUE; + + /* get MLX4_BUS IB interface */ + status = __get_ifc( p_dev_obj, &MLX4_BUS_IB_INTERFACE_GUID, + sizeof(MLX4_BUS_IB_INTERFACE), MLX4_BUS_IB_INTERFACE_VERSION, NULL, (PINTERFACE)&p_fdo->bus_ib_ifc); + if( !NT_SUCCESS( status ) ) { + HCA_PRINT(TRACE_LEVEL_ERROR, HCA_DBG_PNP, ("Getting MLX4 BUS interface failed: status=0x%x\n", status)); + goto end; + } + p_fdo->bus_ib_ifc_taken = TRUE; + p_fdo->bus_ib_ifc.p_ibdev->x.p_fdo = p_fdo; + + InitializeListHead(&p_fdo->hca.event_list); + KeInitializeSpinLock(&p_fdo->hca.event_list_lock); + + /* get node GUID */ + err = __get_dev_info( p_fdo, &p_fdo->hca.guid, &p_fdo->hca.hw_ver ); + if (err) { + + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_LOW , + ("can't get guid - ib_query_device() failed (%08X)\n", err )); + //TODO: no cleanup on error + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* queue HCA */ + mlnx_hca_insert( &p_fdo->hca ); + + /* + * Change the state since the PnP callback can happen + * before the callback returns. + */ + p_fdo->state = HCA_STARTED; + + /* We get started fully powered. */ + p_fdo->DevicePowerState = PowerDeviceD0; + powerState.DeviceState = PowerDeviceD0; + powerState = PoSetPowerState ( p_fdo->cl_ext.p_self_do, DevicePowerState, powerState ); + HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PNP, + ("PoSetPowerState: old state %d, new state to %d\n", + powerState.DeviceState, p_fdo->DevicePowerState )); + +end: + HCA_EXIT( HCA_DBG_PNP ); + return status; +} + +static NTSTATUS +hca_query_stop( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + /* All kernel clients will get notified through the device hierarchy. */ + + /* TODO: set a flag to fail creation of any new IB resources. */ + return cl_irp_skip( p_dev_obj, p_irp, p_action ); +} + + +static NTSTATUS +hca_stop( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + /* + * Must disable everything. Complib framework will + * call ReleaseResources handler. + */ + return cl_irp_skip( p_dev_obj, p_irp, p_action ); +} + + +static NTSTATUS +hca_cancel_stop( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + /* Handled on the way up. */ + return cl_do_sync_pnp( p_dev_obj, p_irp, p_action ); +} + + +static NTSTATUS +hca_query_remove( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + PFDO_DEVICE_DATA p_fdo = (PFDO_DEVICE_DATA)p_dev_obj->DeviceExtension; + if (atomic_read(&p_fdo->usecnt)) { + cl_dbg_out( "MTHCA: Can't get unloaded. %d applications are still in work\n", p_fdo->usecnt); + p_irp->IoStatus.Status = STATUS_UNSUCCESSFUL; + return cl_irp_complete( p_dev_obj, p_irp, p_action ); + } + /* TODO: set a flag to fail creation of any new IB resources. */ + return cl_irp_skip( p_dev_obj, p_irp, p_action ); +} + + +static NTSTATUS +hca_cancel_remove( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + /* Handled on the way up. */ + return cl_do_sync_pnp( p_dev_obj, p_irp, p_action ); +} + + +static NTSTATUS +hca_surprise_remove( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + /* + * TODO: Set state so that all further requests + * automatically succeed/fail as needed. + */ + return cl_irp_skip( p_dev_obj, p_irp, p_action ); +} + + +static NTSTATUS +hca_query_capabilities( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + NTSTATUS status; + PFDO_DEVICE_DATA p_fdo; + IO_STACK_LOCATION *pIoStack; + DEVICE_CAPABILITIES *pCaps; + + HCA_ENTER( HCA_DBG_PNP ); + + p_fdo = (PFDO_DEVICE_DATA)p_dev_obj->DeviceExtension; + + /* Process on the way up. */ + status = cl_do_sync_pnp( p_dev_obj, p_irp, p_action ); + if( !NT_SUCCESS( status ) ) + { + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, + ("cl_do_sync_pnp returned %08X.\n", status)); + return status; + } + + pIoStack = IoGetCurrentIrpStackLocation( p_irp ); + pCaps = pIoStack->Parameters.DeviceCapabilities.Capabilities; + + /* + * Store the device power mapping into our extension since we're + * the power policy owner. The mapping is used when handling + * IRP_MN_SET_POWER IRPs. + */ + cl_memcpy( + p_fdo->DevicePower, pCaps->DeviceState, sizeof(p_fdo->DevicePower) ); + + if( pCaps->DeviceD1 ) + { + HCA_PRINT( TRACE_LEVEL_WARNING ,HCA_DBG_PNP, + ("WARNING: Device reports support for DeviceD1 power state.\n")); + pCaps->DeviceD1 = FALSE; + } + + if( pCaps->DeviceD2 ) + { + HCA_PRINT( TRACE_LEVEL_WARNING,HCA_DBG_PNP, + ("WARNING: Device reports support for DeviceD2 power state.\n")); + pCaps->DeviceD2 = FALSE; + } + + if( pCaps->SystemWake != PowerSystemUnspecified ) + { + HCA_PRINT( TRACE_LEVEL_WARNING ,HCA_DBG_PNP, + ("WARNING: Device reports support for system wake.\n")); + pCaps->SystemWake = PowerSystemUnspecified; + } + + if( pCaps->DeviceWake != PowerDeviceUnspecified ) + { + HCA_PRINT( TRACE_LEVEL_WARNING, HCA_DBG_PNP, + ("WARNING: Device reports support for device wake.\n")); + pCaps->DeviceWake = PowerDeviceUnspecified; + } + + HCA_EXIT( HCA_DBG_PNP ); + return status; +} + +static void +__ref_ifc( + IN DEVICE_OBJECT* p_dev_obj ) +{ + PFDO_DEVICE_DATA p_fdo = (PFDO_DEVICE_DATA)p_dev_obj->DeviceExtension; + + HCA_ENTER( HCA_DBG_PNP ); + + cl_atomic_inc( &p_fdo->n_hca_ifc_ref ); + ObReferenceObject( p_dev_obj ); + + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, + ("MLX4_HCA: CA_guid %I64x, hca_ifc_ref %d\n", + p_fdo->hca.guid, p_fdo->n_hca_ifc_ref) ); + + HCA_EXIT( HCA_DBG_PNP ); +} + +static void +__deref_ifc( + IN DEVICE_OBJECT* p_dev_obj ) +{ + PFDO_DEVICE_DATA p_fdo = (PFDO_DEVICE_DATA)p_dev_obj->DeviceExtension; + + HCA_ENTER( HCA_DBG_PNP ); + + cl_atomic_dec( &p_fdo->n_hca_ifc_ref ); + ObDereferenceObject( p_dev_obj ); + + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, + ("MLX4_HCA: CA_guid %I64x, hca_ifc_ref %d\n", + p_fdo->hca.guid, p_fdo->n_hca_ifc_ref) ); + + HCA_EXIT( HCA_DBG_PNP ); +} + +static NTSTATUS +__query_ci_ifc( + IN DEVICE_OBJECT* const p_dev_obj, + IN IO_STACK_LOCATION* const p_io_stack ) +{ + RDMA_INTERFACE_VERBS *p_ifc; + PFDO_DEVICE_DATA p_fdo; + ci_interface_t *p_hca_ifc; + NTSTATUS status; + UINT8 version; + + HCA_ENTER( HCA_DBG_PNP ); + + version = VerbsVersionMajor(p_io_stack->Parameters.QueryInterface.Version); + if( version > VERBS_MAJOR_VER ) + { + status = STATUS_NOT_SUPPORTED; + goto exit; + } + + if( p_io_stack->Parameters.QueryInterface.Size < sizeof(RDMA_INTERFACE_VERBS) ) + { + status = STATUS_BUFFER_TOO_SMALL; + goto exit; + } + + p_fdo = (PFDO_DEVICE_DATA)p_dev_obj->DeviceExtension; + p_hca_ifc = __alloc_hca_ifc( p_fdo ); + if( !p_hca_ifc ) + { + status = STATUS_NO_MEMORY; + goto exit; + } + + p_ifc = (RDMA_INTERFACE_VERBS *) p_io_stack->Parameters.QueryInterface.Interface; + + p_ifc->InterfaceHeader.Size = sizeof(RDMA_INTERFACE_VERBS); + p_ifc->InterfaceHeader.Version = VerbsVersion(VERBS_MAJOR_VER, VERBS_MINOR_VER); + p_ifc->InterfaceHeader.Context = p_dev_obj; + p_ifc->InterfaceHeader.InterfaceReference = __ref_ifc; + p_ifc->InterfaceHeader.InterfaceDereference = __deref_ifc; + p_ifc->Verbs = *p_hca_ifc; + + /* take the reference before returning. */ + __ref_ifc( p_dev_obj ); + + ExFreePool( p_hca_ifc ); + status = STATUS_SUCCESS; + +exit: + HCA_EXIT( HCA_DBG_PNP ); + return status; +} + + +static NTSTATUS +hca_query_interface( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + NTSTATUS status; + IO_STACK_LOCATION *p_io_stack; + + HCA_ENTER( HCA_DBG_PNP ); + +#pragma warning( push, 3 ) + PAGED_CODE(); +#pragma warning( pop ) + + p_io_stack = IoGetCurrentIrpStackLocation( p_irp ); + + /* Compare requested GUID with our supported interface GUIDs. */ + if( IsEqualGUID( p_io_stack->Parameters.QueryInterface.InterfaceType, + &GUID_RDMA_INTERFACE_VERBS ) ) + { + status = __query_ci_ifc( p_dev_obj, p_io_stack ); + if( !NT_SUCCESS( status ) ) + { + *p_action = IrpComplete; + } + else + { + *p_action = IrpSkip; + } + } + else + { + status = p_irp->IoStatus.Status; + *p_action = IrpSkip; + } + + HCA_EXIT( HCA_DBG_PNP ); + return status; +} + + +static NTSTATUS +hca_query_pnp_state( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + PFDO_DEVICE_DATA p_fdo; + + HCA_ENTER( HCA_DBG_PNP ); + + p_fdo = (PFDO_DEVICE_DATA)p_dev_obj->DeviceExtension; + + p_irp->IoStatus.Information |= p_fdo->pnpState; + + *p_action = IrpSkip; + + HCA_EXIT( HCA_DBG_PNP ); + return STATUS_SUCCESS;; +} + +static NTSTATUS +hca_query_power( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + NTSTATUS status = STATUS_SUCCESS; + IO_STACK_LOCATION *pIoStack; + + HCA_ENTER(HCA_DBG_PO); + + UNUSED_PARAM( p_dev_obj ); + + pIoStack = IoGetCurrentIrpStackLocation( p_irp ); + + HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PO, + ("QUERY_POWER for FDO %p: type %s, state %d, action %d, IRQL %d, IRP %p\n", + p_dev_obj, + (pIoStack->Parameters.Power.Type) ? "DevicePowerState" : "SystemPowerState", + pIoStack->Parameters.Power.State.DeviceState, + pIoStack->Parameters.Power.ShutdownType, KeGetCurrentIrql(), p_irp )); + + switch( pIoStack->Parameters.Power.Type ) + { + case SystemPowerState: + /* Fail any requests to hibernate or sleep the system. */ + switch( pIoStack->Parameters.Power.State.SystemState ) + { + case PowerSystemSleeping1: // STANDBY support + case PowerSystemSleeping2: // STANDBY support + case PowerSystemSleeping3: // STANDBY support + case PowerSystemHibernate: + { + PFDO_DEVICE_DATA p_fdo = (PFDO_DEVICE_DATA)p_dev_obj->DeviceExtension; + if (atomic_read(&p_fdo->usecnt)) + status = STATUS_UNSUCCESSFUL; + break; + } + + case PowerSystemWorking: + case PowerSystemShutdown: + break; + + default: + status = STATUS_NOT_SUPPORTED; + } + break; + + case DevicePowerState: + /* Fail any query for low power states. */ + switch( pIoStack->Parameters.Power.State.DeviceState ) + { + case PowerDeviceD0: + case PowerDeviceD3: + /* We only support fully powered or off power states. */ + break; + + default: + status = STATUS_NOT_SUPPORTED; + } + break; + } + + if( status == STATUS_SUCCESS ) + *p_action = IrpSkip; + else + *p_action = IrpComplete; + + HCA_EXIT( HCA_DBG_PO ); + return status; +} + + +static void +__RequestPowerCompletion( + IN DEVICE_OBJECT *p_dev_obj, + IN UCHAR minorFunction, + IN POWER_STATE powerState, + IN void *context, + IN IO_STATUS_BLOCK *pIoStatus ) +{ + IRP *p_irp; + cl_pnp_po_ext_t *p_fdo; + + HCA_ENTER( HCA_DBG_PO ); + + UNUSED_PARAM( minorFunction ); + UNUSED_PARAM( powerState ); + + p_irp = (IRP*)context; + p_fdo = (cl_pnp_po_ext_t*)p_dev_obj->DeviceExtension; + + /* Propagate the device IRP status to the system IRP status. */ + p_irp->IoStatus.Status = pIoStatus->Status; + + /* Continue Power IRP processing. */ + PoStartNextPowerIrp( p_irp ); + IoCompleteRequest( p_irp, IO_NO_INCREMENT ); + IoReleaseRemoveLock( &p_fdo->remove_lock, p_irp ); + HCA_EXIT( HCA_DBG_PO ); +} + + +/*NOTE: Completion routines must NEVER be pageable. */ +static NTSTATUS +__SystemPowerCompletion( + IN DEVICE_OBJECT *p_dev_obj, + IN IRP *p_irp, + IN void *context ) +{ + NTSTATUS status; + POWER_STATE state; + PFDO_DEVICE_DATA p_fdo; + IO_STACK_LOCATION *pIoStack; + + HCA_ENTER( HCA_DBG_PO ); + + UNUSED_PARAM( context ); + + p_fdo = (PFDO_DEVICE_DATA)p_dev_obj->DeviceExtension; + pIoStack = IoGetCurrentIrpStackLocation( p_irp ); + + if( !NT_SUCCESS( p_irp->IoStatus.Status ) ) + { + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PO, + ("IRP_MN_SET_POWER for system failed by lower driver with %08x.\n", + p_irp->IoStatus.Status)); + status = STATUS_SUCCESS; + PoStartNextPowerIrp( p_irp ); + goto release; + } + + state.DeviceState = + p_fdo->DevicePower[pIoStack->Parameters.Power.State.SystemState]; + + /* + * Send a device power IRP to our devnode. Using our device object will + * only work on win2k and other NT based systems. + */ + status = PoRequestPowerIrp( p_dev_obj, IRP_MN_SET_POWER, state, + __RequestPowerCompletion, p_irp, NULL ); + + HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PO, + ("PoRequestPowerIrp: SET_POWER 'PowerDeviceD%d', status %#x\n", + state.DeviceState - 1, status )); + + if( status != STATUS_PENDING ) { + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PO, + ("PoRequestPowerIrp returned %08x.\n", status)); + p_irp->IoStatus.Status = status; /* Propagate the failure. */ + PoStartNextPowerIrp( p_irp ); + IoCompleteRequest( p_irp, IO_NO_INCREMENT ); + goto release; + } + + status = STATUS_MORE_PROCESSING_REQUIRED; + goto exit; + +release: + IoReleaseRemoveLock( &p_fdo->cl_ext.remove_lock, p_irp ); +exit: + HCA_EXIT( HCA_DBG_PO ); + return status; +} + + +/* Work item callback to handle DevicePowerD0 IRPs at passive level. */ +static void +__DevicePowerUpCompletionWorkItem( + IN DEVICE_OBJECT* p_dev_obj, + IN void* context ) +{ + int err; + NTSTATUS status; + IO_STACK_LOCATION *pIoStack; + PFDO_DEVICE_DATA p_fdo; + IRP *p_irp; + POWER_STATE powerState; + + HCA_ENTER( HCA_DBG_PO ); + + p_fdo = (PFDO_DEVICE_DATA)p_dev_obj->DeviceExtension; + p_irp = (IRP*)context; + pIoStack = IoGetCurrentIrpStackLocation( p_irp ); + + IoFreeWorkItem( p_fdo->pPoWorkItem ); + p_fdo->pPoWorkItem = NULL; + + /* restart the HCA */ + HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PO, + ("***** Restart the HCA, IRQL %d\n", KeGetCurrentIrql())); + + /* get MLX4_BUS IB interface */ + status = __get_ifc( p_dev_obj, &MLX4_BUS_IB_INTERFACE_GUID, + sizeof(MLX4_BUS_IB_INTERFACE), MLX4_BUS_IB_INTERFACE_VERSION, NULL, (PINTERFACE)&p_fdo->bus_ib_ifc); + if( !NT_SUCCESS( status ) ) { + HCA_PRINT(TRACE_LEVEL_ERROR, HCA_DBG_PNP, ("Getting MLX4 BUS interface failed: status=0x%x\n", status)); + goto err_hca_reg; + } + p_fdo->bus_ib_ifc_taken = TRUE; + p_fdo->bus_ib_ifc.p_ibdev->x.p_fdo = p_fdo; + + /* get node GUID */ + err = __get_dev_info( p_fdo, &p_fdo->hca.guid, &p_fdo->hca.hw_ver ); + if (err) { + + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_LOW , + ("can't get guid - ib_query_device() failed (%08X)\n", err )); + //TODO: no cleanup on error + goto err_hca_reg; + } + + p_fdo->DevicePowerState = pIoStack->Parameters.Power.State.DeviceState; + powerState = PoSetPowerState( p_dev_obj, DevicePowerState, + pIoStack->Parameters.Power.State ); + + HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PO, + ("PoSetPowerState: old state %d, new state to %d\n", + powerState.DeviceState, p_fdo->DevicePowerState )); + + goto exit; + +err_hca_reg: + /* Flag device as having failed. */ + p_fdo->pnpState |= PNP_DEVICE_FAILED; + IoInvalidateDeviceState( p_fdo->cl_ext.p_pdo ); +exit: + PoStartNextPowerIrp( p_irp ); + IoCompleteRequest( p_irp, IO_NO_INCREMENT ); + IoReleaseRemoveLock( &p_fdo->cl_ext.remove_lock, p_irp ); + HCA_EXIT( HCA_DBG_PO ); +} + +/*NOTE: Completion routines must NEVER be pageable. */ +static NTSTATUS +__DevicePowerUpCompletion( + IN DEVICE_OBJECT *p_dev_obj, + IN IRP *p_irp, + IN void *context ) +{ + NTSTATUS status = STATUS_SUCCESS; + PFDO_DEVICE_DATA p_fdo; + IO_STACK_LOCATION *pIoStack; + + HCA_ENTER( HCA_DBG_PO ); + + UNUSED_PARAM( context ); + + p_fdo = (PFDO_DEVICE_DATA)p_dev_obj->DeviceExtension; + pIoStack = IoGetCurrentIrpStackLocation( p_irp ); + + if( !NT_SUCCESS( p_irp->IoStatus.Status ) ) { + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PO, + ("IRP_MN_SET_POWER for device failed by lower driver with %08x.\n", + p_irp->IoStatus.Status)); + status = STATUS_SUCCESS; + PoStartNextPowerIrp( p_irp ); + goto release; + } + + /* Process in a work item - mthca_start blocks. */ + ASSERT( !p_fdo->pPoWorkItem ); + p_fdo->pPoWorkItem = IoAllocateWorkItem( p_dev_obj ); + if( !p_fdo->pPoWorkItem ) { + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PO, + ("Failed to allocate work item.\n" )); + status = STATUS_SUCCESS; + p_fdo->pnpState |= PNP_DEVICE_FAILED; + IoInvalidateDeviceState( p_fdo->cl_ext.p_pdo ); + PoStartNextPowerIrp( p_irp ); + goto release; + } + + /* Process in work item callback. */ + IoMarkIrpPending( p_irp ); + IoQueueWorkItem( p_fdo->pPoWorkItem, + __DevicePowerUpCompletionWorkItem, DelayedWorkQueue, p_irp ); + status = STATUS_MORE_PROCESSING_REQUIRED; + goto exit; + +release: + IoReleaseRemoveLock( &p_fdo->cl_ext.remove_lock, p_irp ); +exit: + HCA_EXIT( HCA_DBG_PO ); + return status; +} + +static NTSTATUS __DevicePowerDownWorkItemCompletion( + IN DEVICE_OBJECT *p_dev_obj, + IN IRP *p_irp, + IN void *context ) +{ + PFDO_DEVICE_DATA p_fdo = (PFDO_DEVICE_DATA)p_dev_obj->DeviceExtension; + UNUSED_PARAM( context ); + + HCA_ENTER( HCA_DBG_PO ); + + PoStartNextPowerIrp( p_irp ); + IoReleaseRemoveLock( &p_fdo->cl_ext.remove_lock, p_irp ); + + HCA_EXIT( HCA_DBG_PO ); + return STATUS_SUCCESS; +} + +/* Work item callback to handle DevicePowerD3 IRPs at passive level. */ +static void +__DevicePowerDownWorkItem( + IN DEVICE_OBJECT* p_dev_obj, + IN void* context ) +{ + IO_STACK_LOCATION *pIoStack; + PFDO_DEVICE_DATA p_fdo; + IRP *p_irp; + POWER_STATE powerState; + + HCA_ENTER( HCA_DBG_PO ); + + p_fdo = (PFDO_DEVICE_DATA)p_dev_obj->DeviceExtension; + p_irp = (IRP*)context; + pIoStack = IoGetCurrentIrpStackLocation( p_irp ); + + IoFreeWorkItem( p_fdo->pPoWorkItem ); + p_fdo->pPoWorkItem = NULL; + + p_fdo->DevicePowerState = pIoStack->Parameters.Power.State.DeviceState; + powerState = PoSetPowerState( p_dev_obj, DevicePowerState, + pIoStack->Parameters.Power.State ); + + HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PO, + ("PoSetPowerState: old state %d, new state to %d, IRQL %d\n", + powerState.DeviceState, p_fdo->DevicePowerState, KeGetCurrentIrql() )); + + HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PO, + ("***** Remove the HCA \n")); + + // release MLX4_BUS resources + if(p_fdo->bus_ib_ifc_taken) { + p_fdo->bus_ib_ifc_taken = FALSE; + __put_ifc( (PINTERFACE)&p_fdo->bus_ib_ifc ); + } + + IoCopyCurrentIrpStackLocationToNext( p_irp ); +#pragma warning( push, 3 ) + IoSetCompletionRoutine( p_irp, __DevicePowerDownWorkItemCompletion, + NULL, TRUE, TRUE, TRUE ); +#pragma warning( pop ) + PoCallDriver( p_fdo->cl_ext.p_next_do, p_irp ); + + HCA_EXIT( HCA_DBG_PO ); +} + + +static NTSTATUS +hca_set_power( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + NTSTATUS status; + IO_STACK_LOCATION *pIoStack; + PFDO_DEVICE_DATA p_fdo; + + HCA_ENTER( HCA_DBG_PO ); + + p_fdo = (PFDO_DEVICE_DATA)p_dev_obj->DeviceExtension; + pIoStack = IoGetCurrentIrpStackLocation( p_irp ); + + HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PO, + ("SET_POWER for FDO %p (ext %p): type %s, state %d, action %d, IRQL %d \n", + p_dev_obj, p_fdo, + (pIoStack->Parameters.Power.Type) ? "DevicePowerState" : "SystemPowerState", + pIoStack->Parameters.Power.State.DeviceState, + pIoStack->Parameters.Power.ShutdownType, KeGetCurrentIrql() )); + + switch( pIoStack->Parameters.Power.Type ) + { + case SystemPowerState: + p_fdo->SystemPowerState = pIoStack->Parameters.Power.State.SystemState; + + /* + * Process on the way up the stack. We cannot block since the + * power dispatch function can be called at elevated IRQL if the + * device is in a paging/hibernation/crash dump path. + */ + IoMarkIrpPending( p_irp ); + IoCopyCurrentIrpStackLocationToNext( p_irp ); +#pragma warning( push, 3 ) + IoSetCompletionRoutine( p_irp, __SystemPowerCompletion, NULL, + TRUE, TRUE, TRUE ); +#pragma warning( pop ) + PoCallDriver( p_fdo->cl_ext.p_next_do, p_irp ); + + *p_action = IrpDoNothing; + status = STATUS_PENDING; + break; + + case DevicePowerState: + IoMarkIrpPending( p_irp ); + if( pIoStack->Parameters.Power.State.DeviceState == PowerDeviceD0 && + p_fdo->SystemPowerState == PowerSystemWorking) + { /* power up */ + /* If we're already powered up, just pass down. */ + if( p_fdo->DevicePowerState == PowerDeviceD0 ) + { + status = STATUS_SUCCESS; + *p_action = IrpIgnore; + break; + } + + /* Process in I/O completion callback. */ + IoCopyCurrentIrpStackLocationToNext( p_irp ); +#pragma warning( push, 3 ) + IoSetCompletionRoutine( p_irp, __DevicePowerUpCompletion, NULL, + TRUE, TRUE, TRUE ); +#pragma warning( pop ) + PoCallDriver( p_fdo->cl_ext.p_next_do, p_irp ); + } + else + { /* power down */ + + /* Process in a work item - deregister_ca and HcaDeinit block. */ + ASSERT( !p_fdo->pPoWorkItem ); + p_fdo->pPoWorkItem = IoAllocateWorkItem( p_dev_obj ); + if( !p_fdo->pPoWorkItem ) + { + status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + + /* Process in work item callback. */ + IoQueueWorkItem( + p_fdo->pPoWorkItem, __DevicePowerDownWorkItem, DelayedWorkQueue, p_irp ); + } + *p_action = IrpDoNothing; + status = STATUS_PENDING; + break; + + default: + /* Pass down and let the PDO driver handle it. */ + *p_action = IrpIgnore; + status = STATUS_SUCCESS; + break; + } + + if( !NT_SUCCESS( status ) ) + *p_action = IrpComplete; + + HCA_EXIT( HCA_DBG_PNP ); + return status; +} + +void +hca_init_vfptr( void ) +{ + vfptrHcaPnp.identity = "MLX4_HCA driver"; + vfptrHcaPnp.pfn_start = hca_start; + vfptrHcaPnp.pfn_query_stop = hca_query_stop; + vfptrHcaPnp.pfn_stop = hca_stop; + vfptrHcaPnp.pfn_cancel_stop = hca_cancel_stop; + vfptrHcaPnp.pfn_query_remove = hca_query_remove; + vfptrHcaPnp.pfn_release_resources = hca_release_resources; + vfptrHcaPnp.pfn_remove = cl_do_remove; + vfptrHcaPnp.pfn_cancel_remove = hca_cancel_remove; + vfptrHcaPnp.pfn_surprise_remove = hca_surprise_remove; + vfptrHcaPnp.pfn_query_capabilities = hca_query_capabilities; + vfptrHcaPnp.pfn_query_pnp_state = hca_query_pnp_state; + vfptrHcaPnp.pfn_filter_res_req = cl_irp_skip; + vfptrHcaPnp.pfn_dev_usage_notification = cl_do_sync_pnp; + vfptrHcaPnp.pfn_query_bus_relations = cl_irp_ignore; + vfptrHcaPnp.pfn_query_ejection_relations = cl_irp_ignore; + vfptrHcaPnp.pfn_query_removal_relations = cl_irp_ignore; + vfptrHcaPnp.pfn_query_target_relations = cl_irp_ignore; + vfptrHcaPnp.pfn_unknown = cl_irp_ignore; + vfptrHcaPnp.pfn_query_resources = cl_irp_ignore; + vfptrHcaPnp.pfn_query_res_req = cl_irp_ignore; + vfptrHcaPnp.pfn_query_bus_info = cl_irp_ignore; + vfptrHcaPnp.pfn_query_interface = hca_query_interface; + vfptrHcaPnp.pfn_read_config = cl_irp_ignore; + vfptrHcaPnp.pfn_write_config = cl_irp_ignore; + vfptrHcaPnp.pfn_eject = cl_irp_ignore; + vfptrHcaPnp.pfn_set_lock = cl_irp_ignore; + vfptrHcaPnp.pfn_query_power = hca_query_power; + vfptrHcaPnp.pfn_set_power = hca_set_power; + vfptrHcaPnp.pfn_power_sequence = cl_irp_ignore; + vfptrHcaPnp.pfn_wait_wake = cl_irp_ignore; +} + +static NTSTATUS +__read_registry( + IN UNICODE_STRING* const p_registry_path ) +{ + NTSTATUS status; + /* Remember the terminating entry in the table below. */ + RTL_QUERY_REGISTRY_TABLE table[3]; + + HCA_ENTER( HCA_DBG_PNP ); + + RtlInitUnicodeString( &g_param_path, NULL ); + g_param_path.MaximumLength = p_registry_path->Length + + sizeof(L"\\Parameters"); + g_param_path.Buffer = cl_zalloc( g_param_path.MaximumLength ); + if( !g_param_path.Buffer ) + { + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, + ("Failed to allocate parameters path buffer.\n")); + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlAppendUnicodeStringToString( &g_param_path, p_registry_path ); + RtlAppendUnicodeToString( &g_param_path, L"\\Parameters" ); + + /* + * Clear the table. This clears all the query callback pointers, + * and sets up the terminating table entry. + */ + cl_memclr( table, sizeof(table) ); + + /* Setup the table entries. */ + table[0].Flags = RTL_QUERY_REGISTRY_DIRECT; + table[0].Name = L"DebugLevel"; + table[0].EntryContext = &g.DebugPrintLevel; + table[0].DefaultType = REG_DWORD; + table[0].DefaultData = &g.DebugPrintLevel; + table[0].DefaultLength = sizeof(ULONG); + + + table[1].Flags = RTL_QUERY_REGISTRY_DIRECT; + table[1].Name = L"DebugFlags"; + table[1].EntryContext = &g.DebugPrintFlags; + table[1].DefaultType = REG_DWORD; + table[1].DefaultData = &g.DebugPrintFlags; + table[1].DefaultLength = sizeof(ULONG); + + + /* Have at it! */ + status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE, + g_param_path.Buffer, table, NULL, NULL ); + + HCA_EXIT( HCA_DBG_PNP ); + return status; +} + +static void +hca_drv_unload( + IN PDRIVER_OBJECT p_driver_obj ) +{ + HCA_ENTER( HCA_DBG_PNP ); + + UNUSED_PARAM( p_driver_obj ); + + cl_free( g_param_path.Buffer ); + + HCA_EXIT( HCA_DBG_PNP ); +#if defined(EVENT_TRACING) + WPP_CLEANUP(p_driver_obj); +#endif + +} + +static NTSTATUS +hca_sysctl( + IN PDEVICE_OBJECT p_dev_obj, + IN PIRP p_irp ) +{ + NTSTATUS status; + PFDO_DEVICE_DATA p_fdo; + + HCA_ENTER( HCA_DBG_PNP ); + + p_fdo = p_dev_obj->DeviceExtension; + + IoSkipCurrentIrpStackLocation( p_irp ); + status = IoCallDriver( p_fdo->cl_ext.p_next_do, p_irp ); + + HCA_EXIT( HCA_DBG_PNP ); + return status; +} + + +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT p_driver_obj, + IN PUNICODE_STRING p_registry_path ) +{ + NTSTATUS status; +#if defined(EVENT_TRACING) + WPP_INIT_TRACING(p_driver_obj ,p_registry_path); +#endif + // global initializations + g.DebugPrintLevel = TRACE_LEVEL_VERBOSE; + g.DebugPrintFlags = 0xffff; + + HCA_ENTER( HCA_DBG_PNP ); + + status = mlnx_hcas_init(); + if( status != STATUS_SUCCESS ) { + HCA_PRINT( TRACE_LEVEL_ERROR ,HCA_DBG_PNP , + ("mlnx_hcas_init returned %#x.\n", status)); + goto end; + } + + status = __read_registry( p_registry_path ); + if( !NT_SUCCESS( status ) ) + { + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, + ("__read_registry_path returned 0x%X.\n", status)); + return status; + } + + /*leo: init function table */ + hca_init_vfptr(); + + p_driver_obj->MajorFunction[IRP_MJ_PNP] = cl_pnp; + p_driver_obj->MajorFunction[IRP_MJ_POWER] = cl_power; + p_driver_obj->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = hca_sysctl; + p_driver_obj->DriverUnload = hca_drv_unload; + p_driver_obj->DriverExtension->AddDevice = hca_add_device; + +end: + HCA_EXIT( HCA_DBG_PNP ); + return STATUS_SUCCESS; +} + +#endif diff --git a/branches/WOF2-3/hw/mlx4/kernel/hca/drv.h b/branches/WOF2-3/hw/mlx4/kernel/hca/drv.h new file mode 100644 index 00000000..732d9fd7 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/hca/drv.h @@ -0,0 +1,372 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: al.c 1611 2006-08-20 14:48:55Z sleybo $ + */ + + +#pragma once + +//////////////////////////////////////////////////////// +// +// INCLUDES +// +//////////////////////////////////////////////////////// + +#ifdef USE_WDM_FRAMEWORK +#include +#endif +#include +#include "data.h" +#include "debug.h" +#include "bus_intf.h" + + +//////////////////////////////////////////////////////// +// +// MACROS +// +//////////////////////////////////////////////////////// + +#if !defined(FILE_DEVICE_INFINIBAND) // Not defined in WXP DDK +#define FILE_DEVICE_INFINIBAND 0x0000003B +#endif + +#define BUSENUM_POOL_TAG (ULONG) 'suBT' + +#define HCARESOURCENAME L"MofResourceName" + +#ifndef min +#define min(_a, _b) (((_a) < (_b)) ? (_a) : (_b)) +#endif + +#ifndef max +#define max(_a, _b) (((_a) > (_b)) ? (_a) : (_b)) +#endif + + +//////////////////////////////////////////////////////// +// +// TYPES +// +//////////////////////////////////////////////////////// + +/****s* HCA/hca_reg_state_t +* NAME +* hca_reg_state_t +* +* DESCRIPTION +* State for tracking registration with AL. This state is independent of the +* device PnP state, and both are used to properly register with AL. +* +* SYNOPSIS +*/ +typedef enum _hca_reg_state +{ + HCA_SHUTDOWN, + HCA_ADDED, + HCA_STARTED + +} hca_reg_state_t; +/* +* VALUES +* HCA_SHUTDOWN +* Cleaning up. +* +* HCA_ADDED +* AddDevice was called and successfully registered for interface +* notifications. +* +* HCA_STARTED +* IRP_MN_START_DEVICE was called. The HCA is fully functional. +* +*********/ + +// +// Structure for reporting data to WMI +// + +typedef struct _HCA_WMI_STD_DATA { + UINT32 DebugPrintLevel; + UINT32 DebugPrintFlags; + +} HCA_WMI_STD_DATA, * PHCA_WMI_STD_DATA; + + +#pragma warning(disable:4201) // nameless struct/union +typedef struct _GLOBALS { + HCA_WMI_STD_DATA; +} GLOBALS; +#pragma warning(default:4201) // nameless struct/union + +extern GLOBALS g; + +// +// The device extension of the bus itself. From whence the PDO's are born. +// + +typedef struct _FDO_DEVICE_DATA +{ +#ifdef USE_WDM_FRAMEWORK + /* ------------------------------------------------- + * PNP and POWER MANAGER DATA + * ------------------------------------------------ */ + cl_pnp_po_ext_t cl_ext; /* COMPLIB PnP object */ + /* Cache of the system to device power states. */ + DEVICE_POWER_STATE DevicePower[PowerSystemMaximum]; + DEVICE_POWER_STATE DevicePowerState; + SYSTEM_POWER_STATE SystemPowerState; + PIO_WORKITEM pPoWorkItem; + +#else + + /* ------------------------------------------------- + * WDF DATA + * ------------------------------------------------ */ + WDFDEVICE FdoDevice; + DEVICE_OBJECT * p_dev_obj; /* WDM dev object */ +#endif + + HCA_WMI_STD_DATA WmiData; + +#ifdef USE_WDM_FRAMEWORK + /* ------------------------------------------------- + * PNP DATA + * ------------------------------------------------ */ + void * pnp_ifc_entry; /* Notification entry for PnP interface events. */ + void * pnp_target_entry; /* Notification entry for PnP target events. */ + PNP_DEVICE_STATE pnpState; /* state for PnP Manager */ +#endif + + /* ------------------------------------------------- + * IBAL DATA + * ------------------------------------------------ */ + /* Number of references on the upper interface. */ + atomic32_t n_hca_ifc_ref; + hca_reg_state_t state; /* State for tracking registration with AL */ +#ifdef USE_WDM_FRAMEWORK + DEVICE_OBJECT * p_al_dev; /* IB_AL FDO */ + FILE_OBJECT * p_al_file_obj; /* IB_AL file object */ + UNICODE_STRING al_sym_name; /* IB_AL symbolic name */ +#endif + + /* ------------------------------------------------- + * SHIM DATA + * ------------------------------------------------ */ + mlnx_hca_t hca; + atomic32_t usecnt; /* the number of working applications*/ + spinlock_t uctx_lock; // spinlock for the below chain + cl_qlist_t uctx_list; // chain of user contexts + int bus_pci_ifc_taken; + BUS_INTERFACE_STANDARD bus_pci_ifc; /* PCI bus interface */ + + /* ------------------------------------------------- + * LOW LEVEL DRIVER' DATA + * ------------------------------------------------ */ + int bus_ib_ifc_taken; + MLX4_BUS_IB_INTERFACE bus_ib_ifc; + + +} FDO_DEVICE_DATA, *PFDO_DEVICE_DATA; + +#ifndef USE_WDM_FRAMEWORK + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(FDO_DEVICE_DATA, FdoGetData) + +typedef struct _QUEUE_DATA +{ + PFDO_DEVICE_DATA FdoData; + +} QUEUE_DATA, *PQUEUE_DATA; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(QUEUE_DATA, QueueGetData) + +#endif + +//////////////////////////////////////////////////////// +// +// FUNCTIONS +// +//////////////////////////////////////////////////////// + +static inline PFDO_DEVICE_DATA hca2fdo(mlnx_hca_t *p_hca) +{ + return CONTAINING_RECORD(p_hca, FDO_DEVICE_DATA, hca); +} + +static inline struct ib_device *hca2ibdev(mlnx_hca_t *p_hca) +{ + return (hca2fdo(p_hca))->bus_ib_ifc.p_ibdev; +} + +static inline mlnx_hca_t *ibdev2hca(struct ib_device *p_ibdev) +{ + return &p_ibdev->x.p_fdo->hca; +} + +static inline struct pci_dev *hca2pdev(mlnx_hca_t *p_hca) +{ + return (hca2fdo(p_hca))->bus_ib_ifc.pdev; +} + +static inline struct mlx4_dev *hca2mdev(mlnx_hca_t *p_hca) +{ + return (hca2fdo(p_hca))->bus_ib_ifc.pdev->dev; +} + +static inline boolean_t hca_is_livefish(PFDO_DEVICE_DATA p_fdo) +{ + if (p_fdo == NULL) { + return TRUE; + } + return p_fdo->bus_ib_ifc.is_livefish; +} + +static inline ib_api_status_t errno_to_iberr(int err) +{ +#define MAP_NT_ERR(err,ibstatus) case err: ib_status = ibstatus; break + ib_api_status_t ib_status; + + if (!err) + return IB_SUCCESS; + + if (err < 0) + err = -err; + switch (err) { + MAP_NT_ERR( ENOENT, IB_NOT_FOUND ); + MAP_NT_ERR( EINTR, IB_INTERRUPTED ); + MAP_NT_ERR( EAGAIN, IB_RESOURCE_BUSY ); + MAP_NT_ERR( ENOMEM, IB_INSUFFICIENT_MEMORY ); + MAP_NT_ERR( EACCES, IB_INVALID_PERMISSION ); + MAP_NT_ERR( EFAULT, IB_ERROR ); + MAP_NT_ERR( EBUSY, IB_RESOURCE_BUSY ); + MAP_NT_ERR( ENODEV, IB_UNSUPPORTED ); + MAP_NT_ERR( EINVAL, IB_INVALID_PARAMETER ); + MAP_NT_ERR( ENOSYS, IB_UNSUPPORTED ); + MAP_NT_ERR( ERANGE, IB_INVALID_SETTING ); + default: + //HCA_PRINT(TRACE_LEVEL_ERROR, HCA_DBG_SHIM, + // "Unmapped errno (%d)\n", err); + ib_status = IB_UNKNOWN_ERROR; + break; + } + return ib_status; +} + +static inline int start_port(struct ib_device *device) +{ + return device->node_type == RDMA_NODE_IB_SWITCH ? 0 : 1; +} + +static inline int end_port(struct ib_device *device) +{ + return device->node_type == RDMA_NODE_IB_SWITCH ? 0 : device->phys_port_cnt; +} + +#ifndef USE_WDM_FRAMEWORK + +//////////////////////////////////////////////////////// +// +// PROTOTYPES +// +//////////////////////////////////////////////////////// + +DRIVER_INITIALIZE DriverEntry; + +void +EvtDriverUnload( + IN WDFDRIVER Driver + ); + +NTSTATUS +EvtDriverDeviceAdd( + IN WDFDRIVER Driver, + IN PWDFDEVICE_INIT Device + ); + +NTSTATUS +EvtDeviceD0Entry( + IN WDFDEVICE Device, + IN WDF_POWER_DEVICE_STATE PreviousState + ); + +NTSTATUS +EvtDeviceD0Exit( + IN WDFDEVICE Device, + IN WDF_POWER_DEVICE_STATE TargetState + ); + +NTSTATUS +EvtPrepareHardware( + IN WDFDEVICE Device, + IN WDFCMRESLIST ResourcesRaw, + IN WDFCMRESLIST ResourcesTranslated + ); + +NTSTATUS +EvtReleaseHardware( + IN WDFDEVICE Device, + IN WDFCMRESLIST ResourcesTranslated + ); + + +// +// Implemented in wmi.c +// + +NTSTATUS +WmiRegistration( + WDFDEVICE Device +); + +NTSTATUS +EvtStdDataSetItem( + IN WDFWMIINSTANCE WmiInstance, + IN ULONG DataItemId, + IN ULONG InBufferSize, + IN PVOID InBuffer + ); + +NTSTATUS +EvtStdDataSetInstance( + IN WDFWMIINSTANCE WmiInstance, + IN ULONG InBufferSize, + IN PVOID InBuffer + ); + +NTSTATUS +EvtStdDataQueryInstance( + IN WDFWMIINSTANCE WmiInstance, + IN ULONG OutBufferSize, + IN PVOID OutBuffer, + OUT PULONG BufferUsed + ); + +#endif + diff --git a/branches/WOF2-3/hw/mlx4/kernel/hca/fw.c b/branches/WOF2-3/hw/mlx4/kernel/hca/fw.c new file mode 100644 index 00000000..678bb5b6 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/hca/fw.c @@ -0,0 +1,494 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: al.c 1611 2006-08-20 14:48:55Z sleybo $ + */ + +#include "precomp.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "fw.tmh" +#endif + + +/*********************************** +Firmware Update definitions +***********************************/ +#define PCI_CONF_ADDR (0x00000058) +#define PCI_CONF_DATA (0x0000005c) +#define FLASH_OFFSET (0x000f01a4) +#define READ_BIT (1<<29) +#define WRITE_BIT (2<<29) +#define ADDR_MSK (0x0007ffff) +#define CMD_MASK (0xe0000000) +#define BANK_SHIFT (19) +#define BANK_MASK (0xfff80000) +#define MAX_FLASH_SIZE (0x80000) // 512K + +#define SEMAP63 (0xf03fc) +#define GPIO_DIR_L (0xf008c) +#define GPIO_POL_L (0xf0094) +#define GPIO_MOD_L (0xf009c) +#define GPIO_DAT_L (0xf0084) +#define GPIO_DATACLEAR_L (0xf00d4) +#define GPIO_DATASET_L (0xf00dc) + +#define CPUMODE (0xf0150) +#define CPUMODE_MSK (0xc0000000UL) +#define CPUMODE_SHIFT (30) + +/* Definitions intended to become shared with UM. Later... */ +#define FW_READ 0x00 +#define FW_WRITE 0x01 +#define FW_READ_CMD 0x08 +#define FW_WRITE_CMD 0x09 +#define FW_OPEN_IF 0xe7 +#define FW_CLOSE_IF 0x7e + +#define FW_SIGNATURE (0x5a445a44) +#define FW_SECT_SIZE (0x10000) + +typedef struct Primary_Sector{ + uint32_t fi_addr; + uint32_t fi_size; + uint32_t signature; + uint32_t fw_reserved[5]; + uint32_t vsd[56]; + uint32_t branch_to; + uint32_t crc016; +} primary_sector_t; + +static uint32_t old_dir; +static uint32_t old_pol; +static uint32_t old_mod; +static uint32_t old_dat; + + +static NTSTATUS +fw_access_pciconf ( + IN BUS_INTERFACE_STANDARD *p_BusInterface, + IN ULONG op_flag, + IN PVOID p_buffer, + IN ULONG offset, + IN ULONG POINTER_ALIGNMENT length ) +{ + + ULONG bytes; + NTSTATUS status = STATUS_SUCCESS; + + PAGED_CODE(); + + if( !p_buffer ) + return STATUS_INVALID_PARAMETER; + + if (p_BusInterface) + { + + bytes = p_BusInterface->SetBusData( + p_BusInterface->Context, + PCI_WHICHSPACE_CONFIG, + (PVOID)&offset, + PCI_CONF_ADDR, + sizeof(ULONG) ); + + if( op_flag == 0 ) + { + if ( bytes ) + bytes = p_BusInterface->GetBusData( + p_BusInterface->Context, + PCI_WHICHSPACE_CONFIG, + p_buffer, + PCI_CONF_DATA, + length ); + if ( !bytes ) + status = STATUS_NOT_SUPPORTED; + } + + else + { + if ( bytes ) + bytes = p_BusInterface->SetBusData( + p_BusInterface->Context, + PCI_WHICHSPACE_CONFIG, + p_buffer, + PCI_CONF_DATA, + length); + + if ( !bytes ) + status = STATUS_NOT_SUPPORTED; + } + } + return status; +} + + +static NTSTATUS +__map_crspace( + IN struct ib_ucontext * p_uctx, + IN PVOID p_buf, + IN ULONG buf_size + ) +{ + NTSTATUS status; + PMDL p_mdl; + PVOID ua, ka; + ULONG sz; + PFDO_DEVICE_DATA p_fdo = p_uctx->device->x.p_fdo; + map_crspace *p_res = (map_crspace *)p_buf; + struct pci_dev *p_pdev = p_fdo->bus_ib_ifc.pdev; + + HCA_ENTER( HCA_DBG_PNP ); + + // sanity checks + if ( buf_size < sizeof *p_res || !p_buf ) { + status = STATUS_INVALID_PARAMETER; + goto err_invalid_params; + } + + // map memory + sz =(ULONG)p_pdev->bar[HCA_BAR_TYPE_HCR].size; + if (!p_pdev->bar[HCA_BAR_TYPE_HCR].virt) { + PHYSICAL_ADDRESS pa; + pa.QuadPart = p_pdev->bar[HCA_BAR_TYPE_HCR].phys; + ka = MmMapIoSpace( pa, sz, MmNonCached ); + if ( ka == NULL) { + HCA_PRINT(TRACE_LEVEL_ERROR , HCA_DBG_SHIM, + ("No kernel mapping of CR space.\n") ); + status = STATUS_INSUFFICIENT_RESOURCES; + goto err_map_to_kernel; + } + p_pdev->bar[HCA_BAR_TYPE_HCR].virt = ka; + } + ka = p_pdev->bar[HCA_BAR_TYPE_HCR].virt; + + // prepare for mapping to user space + p_mdl = IoAllocateMdl( ka, sz, FALSE,FALSE,NULL); + if (p_mdl == NULL) { + HCA_PRINT(TRACE_LEVEL_ERROR , HCA_DBG_SHIM, + ("IoAllocateMdl failed.\n") ); + status = STATUS_INSUFFICIENT_RESOURCES; + goto err_alloc_mdl; + } + + // fill MDL + MmBuildMdlForNonPagedPool(p_mdl); + + // map the buffer into user space + __try + { + ua = MmMapLockedPagesSpecifyCache( p_mdl, UserMode, MmNonCached, + NULL, FALSE, NormalPagePriority ); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + HCA_PRINT(TRACE_LEVEL_ERROR , HCA_DBG_SHIM, + ("MmMapLockedPagesSpecifyCache failed.\n") ); + status = STATUS_INSUFFICIENT_RESOURCES; + goto err_map_to_user; + } + + // fill the results + p_res->va = (uint64_t)(ULONG_PTR)ua; + p_res->size = sz; + + // resource tracking + p_uctx->x.p_mdl = p_mdl; + p_uctx->x.va = ua; + +#if 0 + HCA_PRINT(TRACE_LEVEL_INFORMATION, HCA_DBG_SHIM, + ("MTHCA: __map_crspace succeeded with .ka %I64x, size %I64x va %I64x, size %x, pa %I64x \n", + p_pdev->bar[HCA_BAR_TYPE_HCR].virt, p_pdev->bar[HCA_BAR_TYPE_HCR].size, + p_res->va, p_res->size, p_pdev->bar[HCA_BAR_TYPE_HCR].phys )); +#endif + status = STATUS_SUCCESS; + goto out; + +err_map_to_user: + IoFreeMdl( p_mdl ); +err_alloc_mdl: +err_map_to_kernel: +err_invalid_params: +out: + HCA_EXIT( HCA_DBG_PNP ); + return status; +} + + +static void +__unmap_crspace( + IN struct ib_ucontext * p_uctx + ) +{ + HCA_ENTER( HCA_DBG_PNP ); + + if (p_uctx->x.va && p_uctx->x.p_mdl) { + MmUnmapLockedPages(p_uctx->x.va, p_uctx->x.p_mdl); + IoFreeMdl( p_uctx->x.p_mdl ); + p_uctx->x.va = p_uctx->x.p_mdl = NULL; + //NB: the unmap of IO space is being done in __UnmapHcaMemoryResources + } + + HCA_EXIT( HCA_DBG_PNP ); +} + +static void +__open_fw_access( + IN struct ib_ucontext* p_uctx, + IN PBUS_INTERFACE_STANDARD p_bus_interface ) +{ + if( !p_uctx->x.fw_if_open ) + { + p_bus_interface->InterfaceReference( p_bus_interface->Context ); + p_uctx->x.fw_if_open = TRUE; + } +} + +static void +__close_fw_access( + IN struct ib_ucontext * p_uctx, + IN PBUS_INTERFACE_STANDARD p_bus_interface + ) +{ + if (p_uctx->x.fw_if_open ) { + p_bus_interface->InterfaceDereference((PVOID)p_bus_interface->Context); + p_uctx->x.fw_if_open = FALSE; + } +} + + +void +unmap_crspace_for_all( struct ib_ucontext *p_uctx ) +{ + PFDO_DEVICE_DATA p_fdo = p_uctx->device->x.p_fdo; + PBUS_INTERFACE_STANDARD p_bus_interface = &p_fdo->bus_pci_ifc; + + HCA_ENTER( HCA_DBG_PNP ); + + mutex_lock( &p_uctx->x.mutex ); + __unmap_crspace( p_uctx); + __close_fw_access(p_uctx, p_bus_interface); + mutex_unlock( &p_uctx->x.mutex ); + + HCA_EXIT( HCA_DBG_PNP ); +} + +static NTSTATUS +fw_flash_write_data ( + IN BUS_INTERFACE_STANDARD *p_BusInterface, + IN PVOID p_buffer, + IN ULONG offset, + IN ULONG POINTER_ALIGNMENT length ) +{ + NTSTATUS status; + uint32_t cnt = 0; + uint32_t lcl_data; + + if (!length) + return IB_INVALID_PARAMETER; + + lcl_data = (*((uint32_t*)p_buffer) << 24); + + status = fw_access_pciconf(p_BusInterface, FW_WRITE , &lcl_data, FLASH_OFFSET+4, length ); + if ( status != STATUS_SUCCESS ) + return status; + lcl_data = ( WRITE_BIT | (offset & ADDR_MSK)); + + status = fw_access_pciconf(p_BusInterface, FW_WRITE , &lcl_data, FLASH_OFFSET, 4 ); + if ( status != STATUS_SUCCESS ) + return status; + + lcl_data = 0; + + do + { + if (++cnt > 5000) + { + return STATUS_DEVICE_NOT_READY; + } + + status = fw_access_pciconf(p_BusInterface, FW_READ , &lcl_data, FLASH_OFFSET, 4 ); + if ( status != STATUS_SUCCESS ) + return status; + + } while(lcl_data & CMD_MASK); + + return status; +} + + +static NTSTATUS +fw_flash_read_data ( + IN BUS_INTERFACE_STANDARD *p_BusInterface, + IN PVOID p_buffer, + IN ULONG offset, + IN ULONG POINTER_ALIGNMENT length ) +{ + NTSTATUS status = STATUS_SUCCESS; + uint32_t cnt = 0; + uint32_t lcl_data = ( READ_BIT | (offset & ADDR_MSK)); + + if (!length) + return IB_INVALID_PARAMETER; + + status = fw_access_pciconf(p_BusInterface, FW_WRITE, &lcl_data, FLASH_OFFSET, 4 ); + if ( status != STATUS_SUCCESS ) + return status; + + lcl_data = 0; + do + { + // Timeout checks + if (++cnt > 5000 ) + { + return STATUS_DEVICE_NOT_READY; + } + + status = fw_access_pciconf(p_BusInterface, FW_READ, &lcl_data, FLASH_OFFSET, 4 ); + + if ( status != STATUS_SUCCESS ) + return status; + + } while(lcl_data & CMD_MASK); + + status = fw_access_pciconf(p_BusInterface, FW_READ, p_buffer, FLASH_OFFSET+4, length ); + return status; +} + +ib_api_status_t +fw_access_ctrl( + IN const ib_ca_handle_t h_ca, + IN const void** const handle_array OPTIONAL, + IN uint32_t num_handles, + IN ib_ci_op_t* const p_ci_op, + IN OUT ci_umv_buf_t *p_umv_buf ) +{ + NTSTATUS status = STATUS_SUCCESS; + PVOID p_data; + ULONG offset; + ULONG POINTER_ALIGNMENT length; + struct ib_ucontext *p_uctx = (struct ib_ucontext *)h_ca; + PFDO_DEVICE_DATA p_fdo = p_uctx->device->x.p_fdo; + PBUS_INTERFACE_STANDARD p_bus_interface = &p_fdo->bus_pci_ifc; + + UNREFERENCED_PARAMETER(handle_array); + UNREFERENCED_PARAMETER(num_handles); + + if(!p_umv_buf ) { +#if 1//WORKAROUND_POLL_EQ + if ((p_ci_op->command == FW_POLL_EQ_START) || (p_ci_op->command == FW_POLL_EQ_STOP)){ // poll EQ (in case of missed interrupt) + mlnx_hca_t *p_hca = (mlnx_hca_t *)h_ca; + struct ib_device *p_ibdev = hca2ibdev(p_hca); + if(p_ci_op->command == FW_POLL_EQ_START) + { + p_ibdev->x.poll_eq(p_ibdev,1); + }else + { + p_ibdev->x.poll_eq(p_ibdev,0); + } + return IB_SUCCESS; + } + else +#endif + return IB_UNSUPPORTED; + } + + if ( !p_ci_op ) + return IB_INVALID_PARAMETER; + + length = p_ci_op->buf_size; + offset = p_ci_op->buf_info; + p_data = p_ci_op->p_buf; + + mutex_lock( &p_uctx->x.mutex ); + + switch ( p_ci_op->command ) + { + case FW_MAP_CRSPACE: + status = __map_crspace(p_uctx, p_data, length); + break; + + case FW_UNMAP_CRSPACE: + __unmap_crspace(p_uctx); + break; + + case FW_OPEN_IF: // open BusInterface + if (p_fdo->bus_pci_ifc_taken) + __open_fw_access( p_uctx, p_bus_interface ); + break; + + case FW_READ: // read data from flash + if ( p_uctx->x.fw_if_open ) + status = fw_flash_read_data(p_bus_interface, p_data, offset, length); + break; + + case FW_WRITE: // write data to flash + if ( p_uctx->x.fw_if_open ) + status = fw_flash_write_data(p_bus_interface, p_data, offset, length); + break; + + case FW_READ_CMD: + if ( p_uctx->x.fw_if_open ) + status = fw_access_pciconf(p_bus_interface, 0 , p_data, offset, 4); + break; + + case FW_WRITE_CMD: + if ( p_uctx->x.fw_if_open ) + status = fw_access_pciconf(p_bus_interface, 1 , p_data, offset, 4); + break; + + case FW_CLOSE_IF: // close BusInterface + __close_fw_access(p_uctx, p_bus_interface); + break; + + default: + status = STATUS_INVALID_DEVICE_REQUEST; + } + + if ( status != STATUS_SUCCESS ) { + __close_fw_access(p_uctx, p_bus_interface); + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_INIT, + ("fw_access_ctrl failed, ntstatus: %08x.\n", status)); + } + + mutex_unlock( &p_uctx->x.mutex ); + + switch( status ) { + case STATUS_SUCCESS: return IB_SUCCESS; + case STATUS_INVALID_DEVICE_REQUEST: return IB_UNSUPPORTED; + case STATUS_INSUFFICIENT_RESOURCES: return IB_INSUFFICIENT_RESOURCES; + default: return IB_ERROR; + } +} + + diff --git a/branches/WOF2-3/hw/mlx4/kernel/hca/hca.mof b/branches/WOF2-3/hw/mlx4/kernel/hca/hca.mof new file mode 100644 index 00000000..665df469 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/hca/hca.mof @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: al.c 1611 2006-08-20 14:48:55Z sleybo $ + */ + +#PRAGMA AUTORECOVER + +[Dynamic, Provider("WMIProv"), + WMI, + Description("Mlx4 Hca driver information"), + guid("{2C4C8445-E4A6-45bc-889B-E5E93551DDAF}"), + locale("MS\\0x409")] +class Mlx4HcaInformation +{ + [key, read] + string InstanceName; + [read] boolean Active; + + [WmiDataId(1), + read, + Description("The DebugPrintLevel property indicates the debug output level of MLX4_HCA device.")] + uint32 ErrorCount; + + [WmiDataId(2), + read, + write, + Description("The DebugPrintLevel property indicates the debug output flags of MLX4_HCA device.")] + uint32 DebugPrintLevel; + +}; + + diff --git a/branches/WOF2-3/hw/mlx4/kernel/hca/hca.rc b/branches/WOF2-3/hw/mlx4/kernel/hca/hca.rc new file mode 100644 index 00000000..80d226e6 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/hca/hca.rc @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: hca.rc 1611 2006-08-20 14:48:55Z sleybo $ + */ + + +#include + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_UNKNOWN +#ifdef DBG +#define VER_FILEDESCRIPTION_STR "MLX4 HCA Driver (checked)" +#else +#define VER_FILEDESCRIPTION_STR "MLX4 HCA Driver" +#endif +#define VER_INTERNALNAME_STR "mlx4_hca.sys" +#define VER_ORIGINALFILENAME_STR "mlx4_hca.sys" +#include diff --git a/branches/WOF2-3/hw/mlx4/kernel/hca/hverbs.c b/branches/WOF2-3/hw/mlx4/kernel/hca/hverbs.c new file mode 100644 index 00000000..4fcf5b14 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/hca/hverbs.c @@ -0,0 +1,673 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2004-2005 Mellanox Technologies, Inc. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: hca_verbs.c 2073 2007-11-13 11:38:40Z leonid $ + */ + + +#include "precomp.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "hverbs.tmh" +#endif + + +/* Memory regions */ + +struct ib_mr *ib_get_dma_mr(struct ib_pd *pd, enum ib_access_flags mr_access_flags) +{ + struct ib_mr *mr; + + mr = pd->device->get_dma_mr(pd, mr_access_flags); + + if (!IS_ERR(mr)) { + mr->device = pd->device; + mr->pd = pd; + mr->p_uctx = pd->p_uctx; + atomic_inc(&pd->usecnt); + atomic_set(&mr->usecnt, 0); + HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_MEMORY ,("pdn %d, usecnt %d \n", + ((struct mlx4_ib_pd*)pd)->pdn, pd->usecnt)); + } + + return mr; +} + +struct ib_mr *ib_reg_phys_mr(struct ib_pd *pd, + struct ib_phys_buf *phys_buf_array, + int num_phys_buf, + enum ib_access_flags mr_access_flags, + u64 *iova_start) +{ + struct ib_mr *mr; + + if ( pd->device->reg_phys_mr ) + mr = pd->device->reg_phys_mr(pd, phys_buf_array, num_phys_buf, + mr_access_flags, iova_start); + else + mr = ERR_PTR(-ENOSYS); + + if (!IS_ERR(mr)) { + mr->device = pd->device; + mr->pd = pd; + mr->p_uctx = pd->p_uctx; + atomic_inc(&pd->usecnt); + atomic_set(&mr->usecnt, 0); + HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_MEMORY ,("PD%d use cnt %d \n", + ((struct mlx4_ib_pd*)pd)->pdn, pd->usecnt)); + } + + return mr; +} + + + struct ib_mr *ibv_reg_mr(struct ib_pd *pd, + u64 start, u64 length, + u64 virt_addr, + int mr_access_flags, + ci_umv_buf_t* const p_umv_buf ) +{ + struct ib_mr *ib_mr; + int err; + HCA_ENTER(HCA_DBG_MEMORY); + + if (p_umv_buf && p_umv_buf->command) { + err = -ENOSYS; + goto err_not_supported; + } + + ib_mr = pd->device->reg_user_mr(pd, start, length, virt_addr, mr_access_flags, NULL); + if (IS_ERR(ib_mr)) { + err = PTR_ERR(ib_mr); + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_MEMORY ,("mthca_reg_user_mr failed (%d)\n", err)); + goto err_reg_user_mr; + } + + ib_mr->device = pd->device; + ib_mr->pd = pd; + atomic_inc(&pd->usecnt); + atomic_set(&ib_mr->usecnt, 0); + HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_MEMORY ,("PD%d use cnt %d, pd_handle %p, ctx %p \n", + ((struct mlx4_ib_pd*)pd)->pdn, pd->usecnt, pd, pd->p_uctx)); + HCA_EXIT(HCA_DBG_MEMORY); + return ib_mr; + +err_reg_user_mr: +err_not_supported: + HCA_EXIT(HCA_DBG_MEMORY); + return ERR_PTR(err); +} + +int ib_dereg_mr(struct ib_mr *mr) +{ + int ret; + struct ib_pd *pd; + struct ib_device *p_ibdev; + + if (atomic_read(&mr->usecnt)) + return -EBUSY; + + p_ibdev = mr->device; + pd = mr->pd; + ret = p_ibdev->dereg_mr(mr); + if (!ret) { + atomic_dec(&pd->usecnt); + HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_MEMORY ,("pdn %d, usecnt %d, pd_handle %p, ctx %p \n", + ((struct mlx4_ib_pd*)pd)->pdn, pd->usecnt, pd, pd->p_uctx)); + } + + return ret; +} + +static void release_user_cq_qp_resources( + struct ib_ucontext *p_uctx) +{ + if (p_uctx) { + atomic_dec(&p_uctx->x.usecnt); + if (!atomic_read(&p_uctx->x.usecnt) && p_uctx->closing) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_SHIM ,("User resources are released. Removing context\n")); + ibv_um_close(p_uctx); + } + } +} + +// +// Completion queues +// + +struct ib_cq *ibv_create_cq(struct ib_device *p_ibdev, + ib_comp_handler comp_handler, + void (*event_handler)(ib_event_rec_t *), + void *cq_context, int cqe, + struct ib_ucontext *p_uctx, ci_umv_buf_t* const p_umv_buf) +{ + int err; + struct ib_cq *cq; + struct ib_udata udata, *p_udata = &udata; + struct ibv_create_cq *p_req; + struct ibv_create_cq_resp *p_resp = NULL; + + if ( p_uctx && p_umv_buf && p_umv_buf->p_inout_buf ) { + // prepare user parameters + p_req = (struct ibv_create_cq*)(ULONG_PTR)p_umv_buf->p_inout_buf; + p_resp = (struct ibv_create_cq_resp*)(ULONG_PTR) + p_umv_buf->p_inout_buf; + INIT_UDATA(&udata, &p_req->buf_addr, &p_resp->cqn, + sizeof(struct mlx4_ib_create_cq), sizeof(struct mlx4_ib_create_cq_resp)); + } + else + p_udata = NULL; + + // create cq + cq = p_ibdev->create_cq(p_ibdev, cqe, 0, p_uctx, p_udata); + if (IS_ERR(cq)) { + err = PTR_ERR(cq); + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_CQ ,("create_cq failed (%d)\n", err)); + goto err_create_cq; + } + + cq->device = p_ibdev; + cq->p_uctx = p_uctx; + cq->comp_handler = comp_handler; + cq->event_handler = event_handler; + cq->cq_context = cq_context; + atomic_set(&cq->usecnt, 0); + if (p_uctx) + atomic_inc(&p_uctx->x.usecnt); + + HCA_PRINT(TRACE_LEVEL_INFORMATION, HCA_DBG_CQ , + ("created CQ: cqn %#x:%#x \n", ((struct mlx4_ib_cq*)cq)->mcq.cqn, cq->cqe )); + + // fill results + if (p_umv_buf) { + p_resp->cq_handle = (u64)(ULONG_PTR)cq; + p_resp->cqe = cq->cqe; + p_umv_buf->output_size = sizeof(struct ibv_create_cq_resp); + } + + return cq; + +err_create_cq: + if( p_umv_buf && p_umv_buf->command ) + p_umv_buf->status = IB_ERROR; + return ERR_PTR(err); +} + +int ib_destroy_cq(struct ib_cq *cq) +{ + int ret; + struct ib_ucontext *p_uctx = cq->p_uctx; + + if (atomic_read(&cq->usecnt)) + return -EBUSY; + + HCA_PRINT(TRACE_LEVEL_INFORMATION, HCA_DBG_CQ , + ("destroying CQ: cqn %#x:%#x \n", ((struct mlx4_ib_cq*)cq)->mcq.cqn, cq->cqe )); + + ret = cq->device->destroy_cq(cq); + release_user_cq_qp_resources(p_uctx); + return ret; +} + +// +// Queue pairs +// + +static char *__print_qtype(enum ib_qp_type qtype) +{ + char *str = NULL; + switch (qtype) { + case IB_QPT_SMI: str = "SMI"; break; + case IB_QPT_GSI: str = "GSI"; break; + case IB_QPT_RC: str = "RC"; break; + case IB_QPT_UC: str = "UC"; break; + case IB_QPT_UD: str = "UD"; break; + case IB_QPT_RAW_IP_V6: str = "IP_V6"; break; + case IB_QPT_RAW_ETY: str = "ETY"; break; + default: str = "UKNWN"; break; + } + return str; +} + +struct ib_qp *ibv_create_qp(struct ib_pd *pd, + struct ib_qp_init_attr *qp_init_attr, + struct ib_ucontext *p_uctx, ci_umv_buf_t* const p_umv_buf) +{ + int err; + struct ib_qp *p_ib_qp; + struct ib_udata udata, *p_udata = &udata; + struct ibv_create_qp *p_req = NULL; + struct ibv_create_qp_resp *p_resp= NULL; + + HCA_ENTER(HCA_DBG_QP); + + if ( p_uctx && p_umv_buf && p_umv_buf->command ) { + // prepare user parameters + p_req = (struct ibv_create_qp*)(ULONG_PTR)p_umv_buf->p_inout_buf; + p_resp = (struct ibv_create_qp_resp*)(ULONG_PTR)p_umv_buf->p_inout_buf; + INIT_UDATA(&udata, &p_req->buf_addr, NULL, + sizeof(struct mlx4_ib_create_qp), 0); + } + else + p_udata = NULL; + + p_ib_qp = pd->device->create_qp( pd, qp_init_attr, p_udata ); + + if (IS_ERR(p_ib_qp)) { + err = PTR_ERR(p_ib_qp); + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_QP ,("create_qp failed (%d)\n", err)); + goto err_create_qp; + } + + // fill results + p_ib_qp->device = pd->device; + p_ib_qp->pd = pd; + p_ib_qp->send_cq = qp_init_attr->send_cq; + p_ib_qp->recv_cq = qp_init_attr->recv_cq; + p_ib_qp->srq = qp_init_attr->srq; + p_ib_qp->p_uctx = p_uctx; + p_ib_qp->event_handler = qp_init_attr->event_handler; + p_ib_qp->qp_context = qp_init_attr->qp_context; + p_ib_qp->qp_type = qp_init_attr->qp_type; + atomic_inc(&pd->usecnt); + atomic_inc(&qp_init_attr->send_cq->usecnt); + atomic_inc(&qp_init_attr->recv_cq->usecnt); + if (qp_init_attr->srq) + atomic_inc(&qp_init_attr->srq->usecnt); + if (p_uctx) + atomic_inc(&p_uctx->x.usecnt); + HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_QP ,("pdn %d, usecnt %d, pd_handle %p, ctx %p \n", + ((struct mlx4_ib_pd*)pd)->pdn, pd->usecnt, pd, pd->p_uctx)); + + HCA_PRINT(TRACE_LEVEL_INFORMATION, HCA_DBG_QP , + ("qtype %s (%d), qnum %#x, q_num %#x, ssz %d, rsz %d, scq %#x:%#x, rcq %#x:%#x, port_num %d \n", + __print_qtype(p_ib_qp->qp_type), p_ib_qp->qp_type, + ((struct mlx4_ib_qp*)p_ib_qp)->mqp.qpn, p_ib_qp->qp_num, + qp_init_attr->cap.max_send_wr, qp_init_attr->cap.max_recv_wr, + ((struct mlx4_ib_cq*)p_ib_qp->send_cq)->mcq.cqn, p_ib_qp->send_cq->cqe, + ((struct mlx4_ib_cq*)p_ib_qp->recv_cq)->mcq.cqn, p_ib_qp->recv_cq->cqe, + qp_init_attr->port_num + ) ); + + // fill results for user + if (p_uctx && p_umv_buf && p_umv_buf->p_inout_buf) { + struct mlx4_ib_qp *p_mib_qp = (struct mlx4_ib_qp *)p_ib_qp; + p_resp->qp_handle = (__u64)(ULONG_PTR)p_ib_qp; + p_resp->qpn = p_mib_qp->mqp.qpn; + p_resp->max_send_wr = p_mib_qp->sq.max_post; + p_resp->max_recv_wr = p_mib_qp->rq.max_post; + p_resp->max_send_sge = p_mib_qp->sq.max_gs; + p_resp->max_recv_sge = p_mib_qp->rq.max_gs; + /* + * We don't support inline sends for kernel QPs (yet), and we + * don't know what userspace's value should be. + */ + p_resp->max_inline_data = 0; + p_umv_buf->output_size = sizeof(struct ibv_create_qp_resp); + } + + return p_ib_qp; + +err_create_qp: + if( p_umv_buf && p_umv_buf->command ) + p_umv_buf->status = IB_ERROR; + HCA_EXIT(HCA_DBG_QP); + return ERR_PTR(err); +} + +int ib_destroy_qp(struct ib_qp *qp) +{ + struct ib_pd *p_ib_pd; + struct ib_cq *scq, *rcq; + struct ib_srq *srq; + struct ib_ucontext *p_uctx; + int ret; + + p_ib_pd = qp->pd; + scq = qp->send_cq; + rcq = qp->recv_cq; + srq = qp->srq; + p_uctx = p_ib_pd->p_uctx; + + ret = qp->device->destroy_qp(qp); + if (!ret) { + atomic_dec(&p_ib_pd->usecnt); + atomic_dec(&scq->usecnt); + atomic_dec(&rcq->usecnt); + HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_QP ,("PD%d use cnt %d, pd_handle %p, ctx %p \n", + ((struct mlx4_ib_pd*)p_ib_pd)->pdn, p_ib_pd->usecnt, p_ib_pd, p_ib_pd->p_uctx)); + if (srq) + atomic_dec(&srq->usecnt); + release_user_cq_qp_resources(p_uctx); + } + + return ret; +} + +// +// Shared receive queues +// + + +/* Shared receive queues */ + +struct ib_srq *ibv_create_srq(struct ib_pd *pd, + struct ib_srq_init_attr *srq_init_attr, + struct ib_ucontext *p_uctx, ci_umv_buf_t* const p_umv_buf) +{ + int err; + struct ib_srq *p_ib_srq; + struct ib_udata udata, *p_udata = &udata; + struct ibv_create_srq *p_req = NULL; + struct ibv_create_srq_resp *p_resp= NULL; + + if ( p_uctx && p_umv_buf && p_umv_buf->p_inout_buf) { + // prepare user parameters + p_req = (struct ibv_create_srq*)(ULONG_PTR)p_umv_buf->p_inout_buf; + p_resp = (struct ibv_create_srq_resp*)(ULONG_PTR)p_umv_buf->p_inout_buf; + INIT_UDATA(&udata, &p_req->buf_addr, &p_resp->srqn, + sizeof(struct ibv_create_srq), sizeof(struct ibv_create_srq_resp)); + } + else + p_udata = NULL; + + p_ib_srq = pd->device->create_srq( pd, srq_init_attr, p_udata ); + if (IS_ERR(p_ib_srq)) { + err = PTR_ERR(p_ib_srq); + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_QP ,("create_srq failed (%d)\n", err)); + goto err_create_srq; + } + + // fill results + p_ib_srq->device = pd->device; + p_ib_srq->pd = pd; + p_ib_srq->p_uctx = p_uctx; + p_ib_srq->event_handler = srq_init_attr->event_handler; + p_ib_srq->srq_context = srq_init_attr->srq_context; + atomic_inc(&pd->usecnt); + atomic_set(&p_ib_srq->usecnt, 0); + if (p_uctx) + atomic_inc(&p_uctx->x.usecnt); + HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_QP ,("PD%d use cnt %d, pd_handle %p, ctx %p \n", + ((struct mlx4_ib_pd*)pd)->pdn, pd->usecnt, pd, pd->p_uctx)); + + HCA_PRINT(TRACE_LEVEL_INFORMATION, HCA_DBG_SRQ , + ("uctx %p, qhndl %p, qnum %#x \n", + pd->p_uctx, p_ib_srq, ((struct mlx4_ib_srq*)p_ib_srq)->msrq.srqn ) ); + + // fill results for user + if (p_uctx && p_umv_buf && p_umv_buf->p_inout_buf) { + struct mlx4_ib_srq* p_mib_srq = (struct mlx4_ib_srq*)p_ib_srq; + p_resp->srq_handle = (__u64)(ULONG_PTR)p_ib_srq; + p_resp->max_wr = p_mib_srq->msrq.max - 1; + p_resp->max_sge = p_mib_srq->msrq.max_gs; + p_umv_buf->output_size = sizeof(struct ibv_create_srq_resp); + HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_QP ,("PD%d use cnt %d \n", + ((struct mlx4_ib_pd*)pd)->pdn, pd->usecnt)); + } + + return p_ib_srq; + +err_create_srq: + if( p_umv_buf && p_umv_buf->command ) + p_umv_buf->status = IB_ERROR; + HCA_EXIT(HCA_DBG_QP); + return ERR_PTR(err); +} + +int ib_destroy_srq(struct ib_srq *srq) +{ + int ret; + struct ib_pd *p_ib_pd = srq->pd; + struct ib_ucontext *p_uctx = p_ib_pd->p_uctx; + + ret = srq->device->destroy_srq(srq); + if (!ret) { + atomic_dec(&p_ib_pd->usecnt); + HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_SRQ ,("PD%d use cnt %d, pd_handle %p, ctx %p \n", + ((struct mlx4_ib_pd*)p_ib_pd)->pdn, p_ib_pd->usecnt, p_ib_pd, p_ib_pd->p_uctx)); + release_user_cq_qp_resources(p_uctx); + } + + return ret; +} + +// +// User context +// +static NTSTATUS __map_memory_for_user( + IN io_addr_t addr, + IN SIZE_T size, + IN MEMORY_CACHING_TYPE mem_type, + OUT umap_t * p_map + ) +{ + NTSTATUS status; + + HCA_ENTER(HCA_DBG_SHIM); + + p_map->mapped = 0; + + // map UAR to kernel + p_map->kva = ioremap(addr, size); + if (!p_map->kva) { + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_LOW , + ("Couldn't map kernel access region, aborting.\n") ); + status = IB_INSUFFICIENT_MEMORY; + goto err_ioremap; + } + + // build MDL + p_map->mdl = IoAllocateMdl( p_map->kva, (ULONG)size, + FALSE, TRUE, NULL ); + if( !p_map->mdl ) { + status = IB_INSUFFICIENT_MEMORY; + goto err_alloc_mdl; + } + MmBuildMdlForNonPagedPool( p_map->mdl ); + + /* Map the memory into the calling process's address space. */ + __try { + p_map->uva = MmMapLockedPagesSpecifyCache( p_map->mdl, + UserMode, mem_type, NULL, FALSE, NormalPagePriority ); + } + __except(EXCEPTION_EXECUTE_HANDLER) { + status = IB_INVALID_PERMISSION; + goto err_map; + } + + p_map->mapped = 1; + status = STATUS_SUCCESS; + goto done; + +err_map: + IoFreeMdl(p_map->mdl); + +err_alloc_mdl: + iounmap(p_map->kva, PAGE_SIZE); + +err_ioremap: +done: + HCA_EXIT(HCA_DBG_SHIM); + return status; +} + +static void __unmap_memory_for_user( + IN umap_t * p_map + ) +{ + if (p_map->mapped) { + p_map->mapped = 0; + MmUnmapLockedPages( p_map->uva, p_map->mdl ); + IoFreeMdl(p_map->mdl); + iounmap(p_map->kva, PAGE_SIZE); + } +} + +ib_api_status_t ibv_um_open( + IN struct ib_device * p_ibdev, + IN OUT ci_umv_buf_t* const p_umv_buf, + OUT struct ib_ucontext ** pp_uctx ) +{ + int err; + ib_api_status_t status; + struct mlx4_ib_ucontext *p_muctx; + struct ibv_get_context_resp *p_uresp; + struct mlx4_ib_alloc_ucontext_resp ib_alloc_ucontext_resp; + struct ib_ucontext *p_uctx; + struct ib_udata udata; + + HCA_ENTER(HCA_DBG_SHIM); + + // create user context in kernel + INIT_UDATA(&udata, NULL, &ib_alloc_ucontext_resp, + 0, sizeof(struct mlx4_ib_alloc_ucontext_resp)); + + p_uctx = p_ibdev->alloc_ucontext(p_ibdev, &udata); + if (IS_ERR(p_uctx)) { + err = PTR_ERR(p_uctx); + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_SHIM, + ("mthca_alloc_ucontext failed (%d)\n", err)); + status = errno_to_iberr(err); + goto err_alloc_ucontext; + } + p_muctx = to_mucontext(p_uctx); + p_uresp = (struct ibv_get_context_resp *)(ULONG_PTR)p_umv_buf->p_inout_buf; + + // fill the rest of ib_ucontext fields + p_uctx->device = p_ibdev; + p_uctx->closing = 0; + + // livefish + if (hca_is_livefish(p_ibdev->x.p_fdo)) + goto done; + + // map uar to user space + status = __map_memory_for_user( + (io_addr_t)p_muctx->uar.pfn << PAGE_SHIFT, + PAGE_SIZE, MmNonCached, &p_uctx->x.uar ); + if( !NT_SUCCESS(status) ) { + goto err_map_uar; + } + p_uresp->uar_addr = (u64)(ULONG_PTR)p_uctx->x.uar.uva; + + // map BF to user space + if (ib_alloc_ucontext_resp.bf_reg_size) { + status = __map_memory_for_user( + (io_addr_t)(p_muctx->uar.pfn + + to_mdev(p_ibdev)->dev->caps.num_uars) << PAGE_SHIFT, + PAGE_SIZE, MmWriteCombined, &p_uctx->x.bf ); + if( !NT_SUCCESS(status) ) { + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_SHIM, + ("BlueFlame available, but failed to be mapped (%#x)\n", status)); + p_uresp->bf_page = 0; + p_uresp->bf_buf_size = 0; + } + else { + p_uresp->bf_page = (u64)(ULONG_PTR)p_uctx->x.bf.uva; + p_uresp->bf_buf_size = ib_alloc_ucontext_resp.bf_reg_size / 2; + p_uresp->bf_offset = 0; + } + } + else { + p_uresp->bf_page = 0; + p_uresp->bf_buf_size = 0; + } + +done: + // fill the response + p_uresp->bf_reg_size = ib_alloc_ucontext_resp.bf_reg_size; + p_uresp->bf_regs_per_page = ib_alloc_ucontext_resp.bf_regs_per_page; + p_uresp->qp_tab_size = ib_alloc_ucontext_resp.qp_tab_size; + + *pp_uctx = p_uctx; + status = IB_SUCCESS; + goto end; + +err_map_uar: + p_ibdev->dealloc_ucontext(p_uctx); +err_alloc_ucontext: +end: + HCA_EXIT(HCA_DBG_SHIM); + return status; +} + + +void ibv_um_close( struct ib_ucontext * h_um_ca ) +{ + int err; + ib_api_status_t status; + struct ib_ucontext *p_uctx = (struct ib_ucontext *)h_um_ca; + PFDO_DEVICE_DATA p_fdo = p_uctx->device->x.p_fdo; + + HCA_ENTER(HCA_DBG_SHIM); + + p_uctx->closing = 1; + + if (atomic_read(&p_uctx->x.usecnt)) { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_SHIM, + ("resources are not released (cnt %d)\n", p_uctx->x.usecnt)); + status = IB_RESOURCE_BUSY; + goto err_usage; + } + + if ( !hca_is_livefish(p_fdo)) { + __unmap_memory_for_user( &p_uctx->x.bf ); + __unmap_memory_for_user( &p_uctx->x.uar ); + } + + err = p_fdo->bus_ib_ifc.p_ibdev->dealloc_ucontext(p_uctx); + if (err) { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_SHIM, + ("mthca_dealloc_ucontext failed (%d)\n", err)); + status = errno_to_iberr(err); + goto err_dealloc_ucontext; + } + + HCA_PRINT(TRACE_LEVEL_INFORMATION,HCA_DBG_SHIM, + ("pcs %p\n", PsGetCurrentProcess()) ); + status = IB_SUCCESS; + goto end; + +err_dealloc_ucontext: +err_usage: +end: + if (status != IB_SUCCESS) + { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_SHIM, + ("completes with ERROR status %x\n", status)); + } + HCA_EXIT(HCA_DBG_SHIM); + return; +} + diff --git a/branches/WOF2-3/hw/mlx4/kernel/hca/hverbs.h b/branches/WOF2-3/hw/mlx4/kernel/hca/hverbs.h new file mode 100644 index 00000000..d160159c --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/hca/hverbs.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2004 Mellanox Technologies Ltd. All rights reserved. + * Copyright (c) 2004 Infinicon Corporation. All rights reserved. + * Copyright (c) 2004 Intel Corporation. All rights reserved. + * Copyright (c) 2004 Topspin Corporation. All rights reserved. + * Copyright (c) 2004 Voltaire Corporation. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2005 Cisco Systems. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: ib_verbs.h 1889 2006-12-31 08:33:06Z sleybo $ + */ + +#pragma once + +#include "ib_verbs.h" + +struct ib_mr *ibv_reg_mr(struct ib_pd *pd, + u64 start, u64 length, + u64 virt_addr, + int mr_access_flags, + ci_umv_buf_t* const p_umv_buf ); + +struct ib_cq *ibv_create_cq(struct ib_device *p_ibdev, + ib_comp_handler comp_handler, + void (*event_handler)(ib_event_rec_t *), + void *cq_context, int cqe, + struct ib_ucontext *p_uctx, ci_umv_buf_t* const p_umv_buf); + +struct ib_qp *ibv_create_qp(struct ib_pd *pd, + struct ib_qp_init_attr *qp_init_attr, + struct ib_ucontext *context, ci_umv_buf_t* const p_umv_buf); + +struct ib_srq *ibv_create_srq(struct ib_pd *pd, + struct ib_srq_init_attr *srq_init_attr, + struct ib_ucontext *context, ci_umv_buf_t* const p_umv_buf); + +ib_api_status_t ibv_um_open( + IN struct ib_device * p_ibdev, + IN OUT ci_umv_buf_t* const p_umv_buf, + OUT struct ib_ucontext ** pp_uctx ); + +void ibv_um_close( struct ib_ucontext * h_um_ca ); + + diff --git a/branches/WOF2-3/hw/mlx4/kernel/hca/makefile.inc b/branches/WOF2-3/hw/mlx4/kernel/hca/makefile.inc new file mode 100644 index 00000000..bdf9eb23 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/hca/makefile.inc @@ -0,0 +1,24 @@ +mofcomp: mlx4_hca.bmf + +mlx4_hca.bmf: hca.mof + mofcomp -B:$(OBJ_PATH)\$O\mlx4_hca.bmf hca.mof + wmimofck $(OBJ_PATH)\$O\mlx4_hca.bmf + + +# Transform .inx file to .inf file adding date + major,min & svn.version stamp +# Output .inf file is copied to the $(INF_TARGET) folder (commonly where .sys file resides). + +_LNG=$(LANGUAGE) + +!IF !DEFINED(_INX) +_INX=. +!ENDIF + +STAMP=stampinf -a $(_BUILDARCH) -k $(KMDF_VERSION_MAJOR).$(KMDF_VERSION_MINOR) + +!INCLUDE mod_ver.def + +$(INF_TARGET) : $(_INX)\$(INF_NAME).inx + copy $(_INX)\$(@B).inx $@ + $(STAMP) -f $@ -d * -v $(IB_MAJORVERSION).$(IB_MINORVERSION).$(IB_BUILDVERSION).$(OPENIB_REV) + diff --git a/branches/WOF2-3/hw/mlx4/kernel/hca/mcast.c b/branches/WOF2-3/hw/mlx4/kernel/hca/mcast.c new file mode 100644 index 00000000..7ae1f8ad --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/hca/mcast.c @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2004-2005 Mellanox Technologies, Inc. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: hca_mcast.c 1936 2007-02-06 16:04:33Z sleybo $ + */ + + +#include "precomp.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "mcast.tmh" +#endif + +/* +* Multicast Support Verbs. +*/ +ib_api_status_t +mlnx_attach_mcast ( + IN const ib_qp_handle_t h_qp, + IN const ib_gid_t *p_mcast_gid, + IN const uint16_t mcast_lid, + OUT ib_mcast_handle_t *ph_mcast, + IN OUT ci_umv_buf_t *p_umv_buf ) +{ + int err; + ib_api_status_t status; + struct ib_qp *p_ib_qp = (struct ib_qp *)h_qp; + mlnx_mcast_t *p_mcast; + + HCA_ENTER(HCA_DBG_MCAST); + + // sanity checks + if( p_umv_buf && p_umv_buf->command ) { + HCA_PRINT(TRACE_LEVEL_ERROR , HCA_DBG_MCAST, + ("User mode is not supported yet\n")); + status = IB_UNSUPPORTED; + goto err_nosys; + } + + if( !cl_is_blockable() ) { + status = IB_UNSUPPORTED; + goto err_nosys; + } + + if (!p_mcast_gid || !ph_mcast) { + status = IB_INVALID_PARAMETER; + goto err_invalid_param; + } + + if (p_mcast_gid->raw[0] != 0xff || p_ib_qp->qp_type != IB_QPT_UD) { + status = IB_INVALID_PARAMETER; + goto err_invalid_param; + } + + // allocate structure + p_mcast = (mlnx_mcast_t*)kmalloc(sizeof *p_mcast, GFP_ATOMIC ); + if (p_mcast == NULL) { + status = IB_INSUFFICIENT_MEMORY; + goto err_no_mem; + } + + // attach to mcast group + err = p_ib_qp->device->attach_mcast(p_ib_qp, + (union ib_gid *)p_mcast_gid, mcast_lid); + if (err) { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_MCAST, + ("ibv_attach_mcast failed (%d)\n", err)); + status = errno_to_iberr(err); + goto err_attach; + } + + // fill the structure + p_mcast->p_ib_qp = p_ib_qp; + p_mcast->mcast_lid = mcast_lid; + RtlCopyMemory(p_mcast->mcast_gid.raw, p_mcast_gid->raw, sizeof *p_mcast_gid); + HCA_PRINT(TRACE_LEVEL_INFORMATION,HCA_DBG_MCAST, + ("mcasth %p, qp_p %p, mlid %hx, mgid %I64x`%I64x\n", + p_mcast, p_mcast->p_ib_qp, p_mcast->mcast_lid, + cl_ntoh64(*(uint64_t*)&p_mcast->mcast_gid.raw[0]), + cl_ntoh64(*(uint64_t*)&p_mcast->mcast_gid.raw[8] ))); + + // return the result + if (ph_mcast) *ph_mcast = (ib_mcast_handle_t)p_mcast; + + status = IB_SUCCESS; + goto end; + +err_attach: + kfree(p_mcast); +err_no_mem: +err_invalid_param: +end: +err_nosys: + if (p_umv_buf && p_umv_buf->command) + p_umv_buf->status = status; + if (status != IB_SUCCESS) + HCA_PRINT(TRACE_LEVEL_ERROR, HCA_DBG_MCAST, + ("completes with ERROR status %x\n", status)); + HCA_EXIT(HCA_DBG_MCAST); + return status; +} + +ib_api_status_t +mlnx_detach_mcast ( + IN const ib_mcast_handle_t h_mcast) +{ + int err; + ib_api_status_t status; + mlnx_mcast_t *p_mcast = (mlnx_mcast_t*)h_mcast; + + + HCA_ENTER(HCA_DBG_MCAST); + + // sanity checks + if (!p_mcast || !p_mcast->p_ib_qp) { + HCA_PRINT(TRACE_LEVEL_ERROR , HCA_DBG_MCAST, + ("completes with ERROR status IB_INVALID_PARAMETER\n")); + status = IB_INVALID_PARAMETER; + goto err_invalid_param; + } + + if( !cl_is_blockable() ) { + status = IB_UNSUPPORTED; + goto err_unsupported; + } + + if (p_mcast->mcast_gid.raw[0] != 0xff || p_mcast->p_ib_qp->qp_type != IB_QPT_UD) { + status = IB_INVALID_PARAMETER; + goto err_invalid_param; + } + + HCA_PRINT(TRACE_LEVEL_INFORMATION,HCA_DBG_MCAST, + ("mcasth %p, qp_p %p, mlid %hx, mgid %I64x`%I64x\n", + p_mcast, p_mcast->p_ib_qp, p_mcast->mcast_lid, + *(uint64_t*)&p_mcast->mcast_gid.raw[0], + *(uint64_t*)&p_mcast->mcast_gid.raw[8] )); + + // detach + err = p_mcast->p_ib_qp->device->detach_mcast(p_mcast->p_ib_qp, + (union ib_gid *)&p_mcast->mcast_gid, p_mcast->mcast_lid); + if (err) { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_MCAST, + ("ibv_detach_mcast failed (%d)\n", err)); + status = errno_to_iberr(err); + goto err_detach_mcast; + } + + status = IB_SUCCESS; + +err_detach_mcast: + kfree(p_mcast); +err_unsupported: +err_invalid_param: + if (status != IB_SUCCESS) + HCA_PRINT(TRACE_LEVEL_ERROR, HCA_DBG_MCAST, + ("completes with ERROR status %d\n", status)); + HCA_EXIT(HCA_DBG_MCAST); + return status; +} + + +void +mlnx_mcast_if( + IN OUT ci_interface_t *p_interface ) +{ + p_interface->attach_mcast = mlnx_attach_mcast; + p_interface->detach_mcast = mlnx_detach_mcast; +} diff --git a/branches/WOF2-3/hw/mlx4/kernel/hca/mlx4_hca.cdf b/branches/WOF2-3/hw/mlx4/kernel/hca/mlx4_hca.cdf new file mode 100644 index 00000000..fe3beb7c --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/hca/mlx4_hca.cdf @@ -0,0 +1,28 @@ +[CatalogHeader] +Name=mlx4_hca.cat +PublicVersion=0x0000001 +EncodingType=0x00010001 +CATATTR1=0x10010001:OSAttr:2:6.0 +[CatalogFiles] +mlx4_hca.inf=mlx4_hca.inf +mlx4_hca.sys=mlx4_hca.sys +mlx4u.dll=mlx4u.dll +mlx4ud.dll=mlx4ud.dll +mlx4u32.dll=mlx4u32.dll +mlx4u32d.dll=mlx4u32d.dll +ibal.dll=ibal.dll +ibald.dll=ibald.dll +complib.dll=complib.dll +complibd.dll=complibd.dll +cl32.dll=cl32.dll +cl32d.dll=cl32d.dll +ibal32.dll=ibal32.dll +ibal32d.dll=ibal32d.dll +ibbus.sys=ibbus.sys +winverbs.sys=winverbs.sys +winverbs.dll=winverbs.dll +winverbsd.dll=winverbsd.dll +winmad.sys=winmad.sys +winmad.dll=winmad.dll +winmadd.dll=winmadd.dll +WdfCoInstaller01007.dll=WdfCoInstaller01007.dll diff --git a/branches/WOF2-3/hw/mlx4/kernel/hca/mlx4_hca.inx b/branches/WOF2-3/hw/mlx4/kernel/hca/mlx4_hca.inx new file mode 100644 index 00000000..6db18532 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/hca/mlx4_hca.inx @@ -0,0 +1,470 @@ +; Mellanox Technologies InfiniBand HCAs. +; Copyright 2008 Mellanox Technologies all Rights Reserved. + +[Version] +Signature="$WINDOWS NT$" +Class=InfiniBandController +ClassGUID={58517E00-D3CF-40c9-A679-CEE5752F4491} +Provider=%MTL% +; must be synchronized with hca\drv.c +DriverVer=02/01/2008,1.0.0.0 +CatalogFile=mlx4_hca.cat + + +;***************************************** +; Destination directory section +;***************************************** + +[DestinationDirs] +DefaultDestDir = %DIRID_DRIVERS% +MLX4HCA.UMCopyFiles = %DIRID_SYSTEM% +MLX4HCA.WOW64CopyFiles = %DIRID_SYSTEM_X86% +Wdf_CoInstaller_CopyFiles = %DIRID_SYSTEM% +Ibal.UMCopyFiles = %DIRID_SYSTEM% +Ibal.WOW64CopyFiles = %DIRID_SYSTEM_X86% +WinVerbs.CopySysFiles = %DIRID_DRIVERS% +WinVerbs.CopyDllFiles = %DIRID_SYSTEM% +WinMad.CopySysFiles = %DIRID_DRIVERS% +WinMad.CopyDllFiles = %DIRID_SYSTEM% + + +;***************************************** +; Class Install section +;***************************************** + +[ClassInstall32] +AddReg=ClassAddReg + +[ClassAddReg] +HKR,,,,"InfiniBand Channel Adapters" +HKR,,Icon,,-5 +HKR,,SilentInstall,,1 +HKR,,"UpperFilters",0x00010000,"ibbus" ; enable IBBUS/AL Filter driver loading. +HKR,,"UpperFilters",0x00010008,"WinVerbs" ; enable winverbs Filter driver load. +HKR,,"UpperFilters",0x00010008,"WinMad" + + +;***************************************** +; Device Install section +;***************************************** + +[SourceDisksNames.x86] +1=%DiskId%,,,"" + +[SourceDisksNames.amd64] +1=%DiskId%,,,"" + +[SourceDisksNames.ia64] +1=%DiskId%,,,"" + +[SourceDisksFiles.x86] +mlx4_hca.sys = 1,, +mlx4u.dll = 1,, +mlx4ud.dll = 1,, +WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll = 1,, +ibal.dll=1,, +ibald.dll=1,, +complib.dll=1,, +complibd.dll=1,, +ibbus.sys=1,, +winverbs.sys = 1,, +winverbs.dll = 1,, +winverbsd.dll = 1,, +winmad.sys = 1,, +winmad.dll = 1,, +winmadd.dll = 1,, + +[SourceDisksFiles.amd64] +mlx4_hca.sys = 1,, +mlx4u.dll = 1,, +mlx4ud.dll = 1,, +mlx4u32.dll = 1,, +mlx4u32d.dll = 1,, +WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll = 1,, +ibal.dll=1,, +ibald.dll=1,, +complib.dll=1,, +complibd.dll=1,, +cl32.dll=1,, +cl32d.dll=1,, +ibal32.dll=1,, +ibal32d.dll=1,, +ibbus.sys=1,, +winverbs.sys = 1,, +winverbs.dll = 1,, +winverbsd.dll = 1,, +winmad.sys = 1,, +winmad.dll = 1,, +winmadd.dll = 1,, + +[SourceDisksFiles.ia64] +mlx4_hca.sys = 1,, +mlx4u.dll = 1,, +mlx4ud.dll = 1,, +mlx4u32.dll = 1,, +mlx4u32d.dll = 1,, +WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll = 1,, +ibal.dll=1,, +ibald.dll=1,, +complib.dll=1,, +complibd.dll=1,, +cl32.dll=1,, +cl32d.dll=1,, +ibal32.dll=1,, +ibal32d.dll=1,, +ibbus.sys=1,, +winverbs.sys = 1,, +winverbs.dll = 1,, +winverbsd.dll = 1,, +winmad.sys = 1,, +winmad.dll = 1,, +winmadd.dll = 1,, + + +;***************************************** +; Mlx4HCA Install Section +;***************************************** + +[Manufacturer] +%MTL% = MLX4HCA.DeviceSection,ntx86,ntamd64,ntia64 + +[MLX4HCA.DeviceSection] +; empty since we don't support W9x/Me + +[MLX4HCA.DeviceSection.ntx86] +%Mlx4_Hca.DeviceDesc%=MLX4HCA.DDInstall, MLX4\ConnectX_Hca + +[MLX4HCA.DeviceSection.ntamd64] +%Mlx4_Hca.DeviceDesc%=MLX4HCA.DDInstall, MLX4\ConnectX_Hca + +[MLX4HCA.DeviceSection.ntia64] +%Mlx4_Hca.DeviceDesc%=MLX4HCA.DDInstall, MLX4\ConnectX_Hca + +[MLX4HCA.DDInstall.ntx86] +CopyFiles = MLX4HCA.CopyFiles +CopyFiles = MLX4HCA.UMCopyFiles +CopyFiles = Ibal.UMCopyFiles +CopyFiles = Ibbus.CopyFiles +CopyFiles = WinVerbs.CopySysFiles +CopyFiles = WinVerbs.CopyDllFiles +CopyFiles = WinMad.CopySysFiles +CopyFiles = WinMad.CopyDllFiles + +[MLX4HCA.DDInstall.ntamd64] +CopyFiles = MLX4HCA.CopyFiles +CopyFiles = MLX4HCA.UMCopyFiles +CopyFiles = MLX4HCA.WOW64CopyFiles +CopyFiles = Ibal.UMCopyFiles +CopyFiles = Ibal.WOW64CopyFiles +CopyFiles = Ibbus.CopyFiles +CopyFiles = WinVerbs.CopySysFiles +CopyFiles = WinVerbs.CopyDllFiles +CopyFiles = WinMad.CopySysFiles +CopyFiles = WinMad.CopyDllFiles + +[MLX4HCA.DDInstall.ntia64] +CopyFiles = MLX4HCA.CopyFiles +CopyFiles = MLX4HCA.UMCopyFiles +CopyFiles = MLX4HCA.WOW64CopyFiles +CopyFiles = Ibal.UMCopyFiles +CopyFiles = Ibal.WOW64CopyFiles +CopyFiles = Ibbus.CopyFiles +CopyFiles = WinVerbs.CopySysFiles +CopyFiles = WinVerbs.CopyDllFiles +CopyFiles = WinMad.CopySysFiles +CopyFiles = WinMad.CopyDllFiles + + +[MLX4HCA.DDInstall.ntx86.Services] +AddService = mlx4_hca,%SPSVCINST_ASSOCSERVICE%,MLX4HCA.ServiceInstall,MLX4HCA.EventLog +AddService = ibbus,,Ibbus.ServiceInstall,IBBUS.EventLog +AddService = WinVerbs,,WinVerbs.ServiceInstall +AddService = WinMad,,WinMad.ServiceInstall + +[MLX4HCA.DDInstall.ntamd64.Services] +AddService = mlx4_hca,%SPSVCINST_ASSOCSERVICE%,MLX4HCA.ServiceInstall,MLX4HCA.EventLog +AddService = ibbus,,Ibbus.ServiceInstall,IBBUS.EventLog +AddService = WinVerbs,,WinVerbs.ServiceInstall +AddService = WinMad,,WinMad.ServiceInstall + +[MLX4HCA.DDInstall.ntia64.Services] +AddService = mlx4_hca,%SPSVCINST_ASSOCSERVICE%,MLX4HCA.ServiceInstall,MLX4HCA.EventLog +AddService = ibbus,,Ibbus.ServiceInstall,IBBUS.EventLog +AddService = WinVerbs,,WinVerbs.ServiceInstall +AddService = WinMad,,WinMad.ServiceInstall + + +;***************************************** +; File Copy +;***************************************** + +[MLX4HCA.CopyFiles] +mlx4_hca.sys + +[MLX4HCA.UMCopyFiles] +mlx4u.dll,,,2 +mlx4ud.dll,,,2 + +[MLX4HCA.WOW64CopyFiles] +mlx4u.dll,mlx4u32.dll,,2 +mlx4ud.dll,mlx4u32d.dll,,2 + +[Ibal.UMCopyFiles] +ibal.dll,,,2 +ibald.dll,,,2 +complib.dll,,,2 +complibd.dll,,,2 + +[Ibal.WOW64CopyFiles] +ibal.dll,ibal32.dll,,2 +ibald.dll,ibal32d.dll,,2 +complib.dll,cl32.dll,,2 +complibd.dll,cl32d.dll,,2 + +[Ibbus.CopyFiles] +ibbus.sys + +[WinVerbs.CopySysFiles] +winverbs.sys + +[WinVerbs.CopyDllFiles] +winverbs.dll,,,2 +winverbsd.dll,,,2 + +[WinMad.CopySysFiles] +winmad.sys + +[WinMad.CopyDllFiles] +winmad.dll,,,2 +winmadd.dll,,,2 + + +;***************************************** +; MLX4HCA Service Install section +;***************************************** + +[MLX4HCA.ServiceInstall] +DisplayName = %MLX4HCA.ServiceDesc% +ServiceType = %SERVICE_KERNEL_DRIVER% +StartType = %SERVICE_BOOT_START% +ErrorControl = %SERVICE_ERROR_NORMAL% +ServiceBinary = %12%\mlx4_hca.sys +LoadOrderGroup = extended base +AddReg = MLX4HCA.ParamsReg + +[MLX4HCA.EventLog] +AddReg = MLX4HCA.AddEventLogReg + +[MLX4HCA.AddEventLogReg] +HKR, , EventMessageFile, 0x00020000, "%%SystemRoot%%\System32\IoLogMsg.dll;%%SystemRoot%%\System32\drivers\mlx4_hca.sys" +HKR, , TypesSupported, 0x00010001, 7 + +[MLX4HCA.ParamsReg] +HKR,,DeviceCharacteristics,0x10001,0x0100 ; Use same security checks on relative opens +HKR,,Security,,"D:P(A;;GA;;;BA)(A;;GA;;;SY)" ; Allow generic-all access to Built-in administrators and Local system +HKR,"Parameters","DebugLevel",%REG_DWORD%,0x00000003 +HKR,"Parameters","DebugFlags",%REG_DWORD%,0x0000ffff +HKLM,"System\CurrentControlSet\Control\WMI\GlobalLogger\F8C96A49-AE22-41e9-8025-D7E416884D89","Flags",%REG_DWORD%,0xffff +HKLM,"System\CurrentControlSet\Control\WMI\GlobalLogger\F8C96A49-AE22-41e9-8025-D7E416884D89","Level",%REG_DWORD%,0x3 + + +;***************************************** +; IBBUS Service Install section +;***************************************** + +[Ibbus.ServiceInstall] +DisplayName = %Ibbus.ServiceDesc% +ServiceType = %SERVICE_KERNEL_DRIVER% +StartType = %SERVICE_BOOT_START% +ErrorControl = %SERVICE_ERROR_NORMAL% +ServiceBinary = %12%\ibbus.sys +LoadOrderGroup = PnP Filter +AddReg = Ibbus.ParamsReg +Dependencies = mlx4_hca + +[IBBUS.EventLog] +AddReg = IBBUS.AddEventLogReg + +[IBBUS.AddEventLogReg] +HKR, , EventMessageFile, 0x00020000, "%%SystemRoot%%\System32\IoLogMsg.dll;%%SystemRoot%%\System32\drivers\ibbus.sys" +HKR, , TypesSupported, 0x00010001, 7 + + +[Ibbus.ParamsReg] +HKR,"Parameters","IbalDebugLevel",%REG_DWORD%,2 +HKR,"Parameters","IbalDebugFlags",%REG_DWORD%,0x00ffffff +HKR,"Parameters","SmiPollInterval",%REG_DWORD_NO_CLOBBER%,20000 +HKR,"Parameters","IocQueryTimeout",%REG_DWORD_NO_CLOBBER%,250 +HKR,"Parameters","IocQueryRetries",%REG_DWORD_NO_CLOBBER%,4 +HKR,"Parameters","IocPollInterval",%REG_DWORD_NO_CLOBBER%,30000 +HKR,"Parameters","DebugFlags",%REG_DWORD%,0x80000000 +HKR,"Parameters","ReportPortNIC",%REG_DWORD%,1 + +HKR,"Parameters","StaticChild",%REG_MULTI_SZ_NO_CLOBBER%,IPoIB +;use the following line to add your device +;HKR,"Parameters","StaticChild",%REG_MULTI_SZ_APPEND%,"XsigoBus" + +HKR,"Parameters\IPoIB","DeviceId",%REG_SZ%,"IBA\IPoIB" +HKR,"Parameters\IPoIB","CompatibleId",%REG_MULTI_SZ%,"IBA\SID_1000066a00020000" +HKR,"Parameters\IPoIB","HardwareId",%REG_MULTI_SZ%,"IBA\IPoIB" +HKR,"Parameters\IPoIB","Description",%REG_SZ%,"OpenIB IPoIB Adapter" +HKR,"Parameters\IPoIB","PartitionKey",%REG_SZ%,"FFFF" + +HKR,"Parameters\XsigoBus","DeviceId",%REG_SZ%,"IBA\XsigoBus" +HKR,"Parameters\XsigoBus","CompatibleId",%REG_MULTI_SZ%,"IBA\SID_0000000002139702" +HKR,"Parameters\XsigoBus","HardwareId",%REG_MULTI_SZ%,"IBA\XsigoBus" +HKR,"Parameters\XsigoBus","Description",%REG_SZ%,"Xsigo Virtual Bus" +HKR,"Parameters\XsigoBus","PartitionKey",%REG_SZ%,"FFFF" + +;***************************************** +; WinVerbs Service Install section +;***************************************** + +[WinVerbs.ServiceInstall] +DisplayName = %WinVerbs.ServiceDesc% +ServiceType = %SERVICE_KERNEL_DRIVER% +StartType = %SERVICE_BOOT_START% +ErrorControl = %SERVICE_ERROR_NORMAL% +ServiceBinary = %12%\winverbs.sys +LoadOrderGroup = PNP Filter +Dependencies = ibbus + +;***************************************** +; WinMad Service Install section +;***************************************** + +[WinMad.ServiceInstall] +DisplayName = %WinMad.ServiceDesc% +ServiceType = %SERVICE_KERNEL_DRIVER% +StartType = %SERVICE_BOOT_START% +ErrorControl = %SERVICE_ERROR_NORMAL% +ServiceBinary = %12%\winmad.sys +LoadOrderGroup = PNP Filter +Dependencies = winverbs + + +;***************************************** +; Uninstall section (not used now) +;***************************************** + +[DefaultUninstall.ntx86] +DelFiles = MLX4HCA.CopyFiles +DelFiles = MLX4HCA.UMCopyFiles +DelReg = MLX4HCA.ParamsReg +DelReg = MLX4HCA.AddEventLogReg +DelReg = ClassAddReg +DelFiles = Ibal.UMCopyFiles +DelFiles = Ibbus.CopyFiles +DelReg = Ibbus.ParamsReg +DelFiles = WinVerbs.CopySysFiles +DelFiles = WinVerbs.CopyDllFiles +DelFiles = WinMad.CopySysFiles +DelFiles = WinMad.CopyDllFiles + +[DefaultUninstall.ntamd64] +DelFiles = MLX4HCA.CopyFiles +DelFiles = MLX4HCA.UMCopyFiles +DelFiles = MLX4HCA.WOW64CopyFiles +DelReg = MLX4HCA.ParamsReg +DelReg = MLX4HCA.AddEventLogReg +DelReg = ClassAddReg +DelFiles = Ibal.UMCopyFiles +DelFiles = Ibal.WOW64CopyFiles +DelFiles = Ibbus.CopyFiles +DelReg = Ibbus.ParamsReg +DelFiles = WinVerbs.CopySysFiles +DelFiles = WinVerbs.CopyDllFiles +DelFiles = WinMad.CopySysFiles +DelFiles = WinMad.CopyDllFiles + +[DefaultUninstall.ntia64] +DelFiles = MLX4HCA.CopyFiles +DelFiles = MLX4HCA.UMCopyFiles +DelFiles = MLX4HCA.WOW64CopyFiles +DelReg = MLX4HCA.ParamsReg +DelReg = MLX4HCA.AddEventLogReg +DelReg = ClassAddReg +DelFiles = Ibal.UMCopyFiles +DelFiles = Ibal.WOW64CopyFiles +DelFiles = Ibbus.CopyFiles +DelReg = Ibbus.ParamsReg +DelFiles = WinVerbs.CopySysFiles +DelFiles = WinVerbs.CopyDllFiles +DelFiles = WinMad.CopySysFiles +DelFiles = WinMad.CopyDllFiles + +[DefaultUninstall.Services] +DelService = WinMad,%SPSVCINST_STOPSERVICE% +DelService = WinVerbs,%SPSVCINST_STOPSERVICE% +DelService = Ibbus,%SPSVCINST_STOPSERVICE% +DelService = mlx4_hca,%SPSVCINST_STOPSERVICE% + +;***************************************** +; WDF Coinstaller installation section +;***************************************** + +[MLX4HCA.DDInstall.ntx86.CoInstallers] +AddReg=Wdf_CoInstaller_AddReg +CopyFiles=Wdf_CoInstaller_CopyFiles + +[MLX4HCA.DDInstall.ntamd64.CoInstallers] +AddReg=Wdf_CoInstaller_AddReg +CopyFiles=Wdf_CoInstaller_CopyFiles + +[MLX4HCA.DDInstall.ntia64.CoInstallers] +AddReg=Wdf_CoInstaller_AddReg +CopyFiles=Wdf_CoInstaller_CopyFiles + +[Wdf_CoInstaller_AddReg] +HKR,,CoInstallers32,0x00010000, "WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll,WdfCoInstaller" + +[Wdf_CoInstaller_CopyFiles] +WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll + +[MLX4HCA.DDInstall.ntx86.Wdf] +KmdfService = mlx4_hca,WvWdfSect +KmdfService = WinVerbs,WvWdfSect +KmdfService = WinMad,WvWdfSect + +[MLX4HCA.DDInstall.ntamd64.Wdf] +KmdfService = mlx4_hca,WvWdfSect +KmdfService = WinVerbs,WvWdfSect +KmdfService = WinMad,WvWdfSect + +[MLX4HCA.DDInstall.ntia64.Wdf] +KmdfService = mlx4_hca,WvWdfSect +KmdfService = WinVerbs,WvWdfSect +KmdfService = WinMad,WvWdfSect + +[WvWdfSect] +KmdfLibraryVersion = $KMDFVERSION$ + + +;***************************************** +; Strings +;***************************************** + +[Strings] +Mlx4HcaClassGuid = "{31B0B28A-26FF-4dca-A6FA-E767C7DFBA20}" +MTL="Mellanox Technologies Ltd." +MLX4HCA.ServiceDesc = "Mellanox ConnectX Virtual Infiband Driver" +Ibbus.ServiceDesc = "InfiniBand Bus/AL (Filter Driver)" +WinVerbs.ServiceDesc = "WinVerbs Service" +WinMad.ServiceDesc = "WinMad Service" +Mlx4_Hca.DeviceDesc="Mellanox ConnectX Virtual Channel Adapter" +DiskId = "Mellanox Mlx4 HCA installation disk" +SPSVCINST_NULL = 0x0 +SPSVCINST_ASSOCSERVICE = 0x00000002 +SPSVCINST_STOPSERVICE = 0x00000200 +SERVICE_KERNEL_DRIVER = 1 +SERVICE_BOOT_START = 0 +SERVICE_DEMAND_START = 3 +SERVICE_ERROR_NORMAL = 1 +REG_DWORD = 0x00010001 +REG_DWORD_NO_CLOBBER = 0x00010003 +REG_MULTI_SZ = 0x00010000 +REG_MULTI_SZ_NO_CLOBBER = 0x00010002 +REG_MULTI_SZ_APPEND = 0x00010008 +DIRID_SYSTEM = 11 +DIRID_DRIVERS = 12 +DIRID_SYSTEM_X86 = 16425 diff --git a/branches/WOF2-3/hw/mlx4/kernel/hca/mlx4_hca32.cdf b/branches/WOF2-3/hw/mlx4/kernel/hca/mlx4_hca32.cdf new file mode 100644 index 00000000..bf027678 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/hca/mlx4_hca32.cdf @@ -0,0 +1,22 @@ +[CatalogHeader] +Name=mlx4_hca.cat +PublicVersion=0x0000001 +EncodingType=0x00010001 +CATATTR1=0x10010001:OSAttr:2:6.0 +[CatalogFiles] +mlx4_hca.inf=mlx4_hca.inf +mlx4_hca.sys=mlx4_hca.sys +mlx4u.dll=mlx4u.dll +mlx4ud.dll=mlx4ud.dll +ibal.dll=ibal.dll +ibald.dll=ibald.dll +complib.dll=complib.dll +complibd.dll=complibd.dll +ibbus.sys=ibbus.sys +winverbs.sys=winverbs.sys +winverbs.dll=winverbs.dll +winverbsd.dll=winverbsd.dll +winmad.sys=winmad.sys +winmad.dll=winmad.dll +winmadd.dll=winmadd.dll +WdfCoInstaller01007.dll=WdfCoInstaller01007.dll diff --git a/branches/WOF2-3/hw/mlx4/kernel/hca/mr.c b/branches/WOF2-3/hw/mlx4/kernel/hca/mr.c new file mode 100644 index 00000000..b23b0392 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/hca/mr.c @@ -0,0 +1,588 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2004-2005 Mellanox Technologies, Inc. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: hca_memory.c 2028 2007-07-12 16:00:03Z leonid $ + */ + +#include "precomp.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "mr.tmh" +#endif + +/* + * Memory Management Verbs. + */ + +ib_api_status_t +mlnx_register_mr ( + IN const ib_pd_handle_t h_pd, + IN const ib_mr_create_t *p_mr_create, + OUT net32_t* const p_lkey, + OUT net32_t* const p_rkey, + OUT ib_mr_handle_t *ph_mr, + IN boolean_t um_call ) +{ + ib_api_status_t status; + int err; + struct ib_mr *p_ib_mr; + struct ib_pd *p_ib_pd = (struct ib_pd *)h_pd; + ci_umv_buf_t umv_buf = { 0, 0, 0, 0, 0 }; + + HCA_ENTER(HCA_DBG_MEMORY); + + // sanity checks + if( !cl_is_blockable() ) { + status = IB_UNSUPPORTED; + goto err_unsupported; + } + if (!p_mr_create || 0 == p_mr_create->length) { + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_MEMORY, + ("invalid attributes\n")); + status = IB_INVALID_PARAMETER; + goto err_invalid_parm; + } + /* + * Local write permission is required if remote write or + * remote atomic permission is also requested. + */ + if (p_mr_create->access_ctrl & (IB_AC_RDMA_WRITE | IB_AC_ATOMIC) && + !(p_mr_create->access_ctrl & IB_AC_LOCAL_WRITE)) { + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_MEMORY, + ("invalid access rights\n")); + status = IB_INVALID_PERMISSION; + goto err_invalid_access; + } + + // register mr + p_ib_mr = ibv_reg_mr(p_ib_pd, (ULONG_PTR)p_mr_create->vaddr, + p_mr_create->length, (ULONG_PTR)p_mr_create->vaddr, + to_qp_acl(p_mr_create->access_ctrl), um_call ? &umv_buf : NULL ); + if (IS_ERR(p_ib_mr)) { + err = PTR_ERR(p_ib_mr); + HCA_PRINT(TRACE_LEVEL_ERROR, HCA_DBG_MEMORY, + ("ibv_reg_mr failed (%d)\n", err)); + status = errno_to_iberr(err); + goto err_reg_mr; + } + + // results + *p_lkey = p_ib_mr->lkey; + *p_rkey = cl_hton32( p_ib_mr->rkey ); + if (ph_mr) *ph_mr = (ib_mr_handle_t)p_ib_mr; + status = IB_SUCCESS; + +err_reg_mr: +err_invalid_access: +err_invalid_parm: +err_unsupported: + if (status != IB_SUCCESS) + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_MEMORY, + ("completes with ERROR status %x\n", status)); + HCA_EXIT(HCA_DBG_MEMORY); + return status; +} + +ib_api_status_t +mlnx_register_pmr ( + IN const ib_pd_handle_t h_pd, + IN const ib_phys_create_t* const p_pmr_create, + IN OUT uint64_t* const p_vaddr, + OUT net32_t* const p_lkey, + OUT net32_t* const p_rkey, + OUT ib_mr_handle_t* const ph_mr, + IN boolean_t um_call ) +{ + ib_api_status_t status; + int err; + struct ib_mr *p_ib_mr; + struct ib_phys_buf *buffer_list; + struct ib_pd *p_ib_pd = (struct ib_pd *)h_pd; + + UNUSED_PARAM( um_call ); + + HCA_ENTER(HCA_DBG_MEMORY); + + if (hca_is_livefish(p_ib_pd->device->x.p_fdo)) { + p_ib_mr = kzalloc(sizeof *p_ib_mr, GFP_KERNEL); + if (!p_ib_mr) { + status = IB_INSUFFICIENT_MEMORY; + goto err_mem; + } + p_ib_mr->device = p_ib_pd->device; + p_ib_mr->pd = p_ib_pd; + goto done; + } + + // sanity checks + if( !cl_is_blockable() ) { + status = IB_UNSUPPORTED; + goto err_unsupported; + } + if (!p_vaddr || !p_pmr_create || + 0 == p_pmr_create->length ) { + status = IB_INVALID_PARAMETER; + goto err_invalid_parm; + } + + // prepare parameters + buffer_list = (void*)p_pmr_create->range_array; + //NB: p_pmr_create->buf_offset is not used, i.e. supposed that region is page-aligned + //NB: p_pmr_create->hca_page_size is not used, i.e. supposed it is always the same + + // register pmr + if (p_pmr_create->length == (uint64_t)-1i64) + { + p_ib_mr = ib_get_dma_mr( p_ib_pd, + to_qp_acl(p_pmr_create->access_ctrl) ); + } + else + p_ib_mr = ib_reg_phys_mr(p_ib_pd, buffer_list, p_pmr_create->num_ranges, + to_qp_acl(p_pmr_create->access_ctrl), p_vaddr ); + if (IS_ERR(p_ib_mr)) { + err = PTR_ERR(p_ib_mr); + HCA_PRINT(TRACE_LEVEL_ERROR, HCA_DBG_MEMORY, + ("ib_reg_phys_mr failed (%d)\n", err)); + status = errno_to_iberr(err); + goto err_reg_phys_mr; + } + + // results +done: + if (ph_mr) *ph_mr = (ib_mr_handle_t)p_ib_mr; + *p_lkey = p_ib_mr->lkey; + *p_rkey = cl_hton32( p_ib_mr->rkey ); + //NB: p_vaddr was not changed + status = IB_SUCCESS; + +err_reg_phys_mr: +err_invalid_parm: +err_unsupported: +err_mem: + if (status != IB_SUCCESS) + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_MEMORY, + ("completes with ERROR status %x\n", status)); + + HCA_EXIT(HCA_DBG_MEMORY); + return status; + +} + +ib_api_status_t +mlnx_query_mr ( + IN const ib_mr_handle_t h_mr, + OUT ib_mr_attr_t *p_mr_query ) +{ + int err; + ib_api_status_t status = IB_SUCCESS; + struct ib_mr *p_ib_mr = (struct ib_mr *)h_mr; + struct ib_mr_attr mr_attr; + UNREFERENCED_PARAMETER(p_mr_query); + + HCA_ENTER(HCA_DBG_MEMORY); + + err = p_ib_mr->device->query_mr ? + p_ib_mr->device->query_mr(p_ib_mr, &mr_attr) : -ENOSYS; + status = errno_to_iberr(err); + + if (err) { + // TODO: convert struct ib_mr_attr to ib_mr_attr_t + } + + if (status != IB_SUCCESS) + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_CQ, + ("ib_query_mr failed with status %x\n", status)); + + HCA_EXIT(HCA_DBG_MEMORY); + return status; +} + + +ib_api_status_t +mlnx_modify_mr ( + IN const ib_mr_handle_t h_mr, + IN const ib_mr_mod_t mem_modify_req, + IN const ib_mr_create_t *p_mr_create, + OUT uint32_t *p_lkey, + OUT uint32_t *p_rkey, + IN const ib_pd_handle_t h_pd OPTIONAL, + IN boolean_t um_call ) +{ + UNREFERENCED_PARAMETER(h_mr); + UNREFERENCED_PARAMETER(mem_modify_req); + UNREFERENCED_PARAMETER(p_mr_create); + UNREFERENCED_PARAMETER(p_lkey); + UNREFERENCED_PARAMETER(p_rkey); + UNREFERENCED_PARAMETER(h_pd); + UNREFERENCED_PARAMETER(um_call); + HCA_PRINT(TRACE_LEVEL_ERROR , HCA_DBG_MEMORY ,("mlnx_modify_mr not implemented\n")); + return IB_UNSUPPORTED; +} + + +ib_api_status_t +mlnx_modify_pmr ( + IN const ib_mr_handle_t h_mr, + IN const ib_mr_mod_t mem_modify_req, + IN const ib_phys_create_t* const p_pmr_create, + IN OUT uint64_t* const p_vaddr, + OUT uint32_t* const p_lkey, + OUT uint32_t* const p_rkey, + IN const ib_pd_handle_t h_pd OPTIONAL, + IN boolean_t um_call ) +{ + UNREFERENCED_PARAMETER(h_mr); + UNREFERENCED_PARAMETER(mem_modify_req); + UNREFERENCED_PARAMETER(p_pmr_create); + UNREFERENCED_PARAMETER(p_vaddr); + UNREFERENCED_PARAMETER(p_lkey); + UNREFERENCED_PARAMETER(p_rkey); + UNREFERENCED_PARAMETER(h_pd); + UNREFERENCED_PARAMETER(um_call); + HCA_PRINT(TRACE_LEVEL_ERROR , HCA_DBG_MEMORY ,("mlnx_modify_pmr not implemented\n")); + return IB_UNSUPPORTED; +} + +ib_api_status_t +mlnx_register_smr ( + IN const ib_mr_handle_t h_mr, + IN const ib_pd_handle_t h_pd, + IN const ib_access_t access_ctrl, + IN OUT uint64_t* const p_vaddr, + OUT net32_t* const p_lkey, + OUT net32_t* const p_rkey, + OUT ib_mr_handle_t* const ph_mr, + IN boolean_t um_call ) +{ + UNREFERENCED_PARAMETER(h_mr); + UNREFERENCED_PARAMETER(h_pd); + UNREFERENCED_PARAMETER(access_ctrl); + UNREFERENCED_PARAMETER(p_vaddr); + UNREFERENCED_PARAMETER(p_lkey); + UNREFERENCED_PARAMETER(p_rkey); + UNREFERENCED_PARAMETER(ph_mr); + UNREFERENCED_PARAMETER(um_call); + HCA_PRINT(TRACE_LEVEL_ERROR , HCA_DBG_MEMORY ,("mlnx_register_smr not implemented\n")); + return IB_UNSUPPORTED; +} + +ib_api_status_t +mlnx_deregister_mr ( + IN const ib_mr_handle_t h_mr) +{ + int err; + ib_api_status_t status = IB_SUCCESS; + struct ib_mr *p_ib_mr = (struct ib_mr *)h_mr; + + HCA_ENTER(HCA_DBG_SHIM); + + if (hca_is_livefish(p_ib_mr->device->x.p_fdo)) { + kfree(p_ib_mr); + goto done; + } + + // sanity checks + if( !cl_is_blockable() ) { + status = IB_UNSUPPORTED; + goto err_unsupported; + } + + // deregister + err = ib_dereg_mr(p_ib_mr); + status = errno_to_iberr(err); + +err_unsupported: + if (status != IB_SUCCESS) + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_MEMORY, + ("ib_dereg_mr failed with status %x\n", status)); + +done: + HCA_EXIT(HCA_DBG_MEMORY); + return status; +} + +ib_api_status_t +mlnx_alloc_fmr( + IN const ib_pd_handle_t h_pd, + IN const mlnx_fmr_create_t* const p_fmr_create, + OUT mlnx_fmr_handle_t* const ph_fmr + ) +{ + int err; + ib_api_status_t status = IB_SUCCESS; + struct ib_fmr * p_ib_fmr; + struct ib_pd *p_ib_pd = (struct ib_pd *)h_pd; + struct ib_fmr_attr fmr_attr; + + HCA_ENTER(HCA_DBG_MEMORY); + + // sanity checks + if( !cl_is_blockable() ) { + status = IB_UNSUPPORTED; + goto err_unsupported; + } + if (!p_fmr_create ) { + status = IB_INVALID_PARAMETER; + goto err_invalid_parm; + } + // TODO: check Max remap in AL + + // prepare parameters + RtlZeroMemory(&fmr_attr, sizeof(struct ib_fmr_attr)); + fmr_attr.max_maps = p_fmr_create->max_maps; + fmr_attr.max_pages = p_fmr_create->max_pages; + fmr_attr.page_shift = p_fmr_create->page_size; + + // register mr + p_ib_fmr = p_ib_pd->device->alloc_fmr(p_ib_pd, + to_qp_acl(p_fmr_create->access_ctrl), &fmr_attr); + if (IS_ERR(p_ib_fmr)) { + err = PTR_ERR(p_ib_fmr); + HCA_PRINT(TRACE_LEVEL_ERROR , HCA_DBG_MEMORY , + ("ib_alloc_fmr failed (%d)\n", err)); + status = errno_to_iberr(err); + goto err_alloc_fmr; + } + else { + p_ib_fmr->device = p_ib_pd->device; + p_ib_fmr->pd = p_ib_pd; + atomic_inc(&p_ib_pd->usecnt); + HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_MEMORY ,("PD%d use cnt %d \n", + ((struct mlx4_ib_pd*)p_ib_pd)->pdn, p_ib_pd->usecnt)); + } + + // results + if (ph_fmr) + *ph_fmr = (mlnx_fmr_handle_t)p_ib_fmr; + +err_alloc_fmr: +err_invalid_parm: +err_unsupported: + if (status != IB_SUCCESS) + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_MEMORY, + ("completes with ERROR status %x\n", status)); + + HCA_EXIT(HCA_DBG_MEMORY); + return status; + +} + +ib_api_status_t +mlnx_map_phys_fmr ( + IN const mlnx_fmr_handle_t h_fmr, + IN const uint64_t* const page_list, + IN const int list_len, + IN OUT uint64_t* const p_vaddr, + OUT net32_t* const p_lkey, + OUT net32_t* const p_rkey + ) +{ + int err; + ib_api_status_t status = IB_SUCCESS; + struct ib_fmr *p_ib_fmr = (struct ib_fmr *)h_fmr; + uint64_t vaddr = (*p_vaddr) & ~(PAGE_SIZE - 1); + + HCA_ENTER(HCA_DBG_MEMORY); + + // mapping + err = ib_map_phys_fmr(p_ib_fmr, (u64*)page_list, list_len, (uint64_t)(ULONG_PTR)vaddr); + status = errno_to_iberr(err); + + // return the results + *p_vaddr = vaddr; + *p_lkey = p_ib_fmr->lkey; + *p_rkey = cl_hton32( p_ib_fmr->rkey ); + + if (status != IB_SUCCESS) + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_MEMORY, + ("ibv_map_phys_fmr failed with status %x\n", status)); + + HCA_EXIT(HCA_DBG_MEMORY); + return status; +} + + + +ib_api_status_t +mlnx_unmap_fmr ( + IN const mlnx_fmr_handle_t *ph_fmr) +{ + int err; + struct list_head fmr_list; + ib_api_status_t status = IB_SUCCESS; + struct ib_fmr *p_ib_fmr = (struct ib_fmr *)*ph_fmr; + + HCA_ENTER(HCA_DBG_MEMORY); + + // sanity checks + if( !cl_is_blockable() ) { + status = IB_UNSUPPORTED; + goto err_unsupported; + } + + INIT_LIST_HEAD(&fmr_list); + while(*ph_fmr) { + list_add_tail(&p_ib_fmr->list, &fmr_list); + p_ib_fmr = (struct ib_fmr *)*++ph_fmr; + } + + if (list_empty(&fmr_list)) + goto done; + + p_ib_fmr = list_entry(fmr_list.Flink, struct ib_fmr, list); + err = p_ib_fmr->device->unmap_fmr(&fmr_list); + status = errno_to_iberr(err); + +err_unsupported: + if (status != IB_SUCCESS) + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_MEMORY, + ("ibv_unmap_fmr failed with status %x\n", status)); + +done: + HCA_EXIT(HCA_DBG_MEMORY); + return status; + + +} + + +ib_api_status_t +mlnx_dealloc_fmr ( + IN const mlnx_fmr_handle_t h_fmr + ) +{ + int err; + ib_api_status_t status = IB_SUCCESS; + struct ib_fmr *p_ib_fmr = (struct ib_fmr *)h_fmr; + struct ib_pd *pd = p_ib_fmr->pd; + + HCA_ENTER(HCA_DBG_MEMORY); + + // sanity checks + if( !cl_is_blockable() ) { + status = IB_UNSUPPORTED; + goto err_unsupported; + } + + // deregister + err = p_ib_fmr->device->dealloc_fmr(p_ib_fmr); + if (!err) + atomic_dec(&pd->usecnt); + status = errno_to_iberr(err); + +err_unsupported: + if (status != IB_SUCCESS) + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_MEMORY, + ("ibv_dealloc_fmr failed with status %x\n", status)); + + HCA_EXIT(HCA_DBG_MEMORY); + return status; + +} + + + +/* +* Memory Window Verbs. +*/ + +ib_api_status_t +mlnx_create_mw ( + IN const ib_pd_handle_t h_pd, + OUT net32_t* const p_rkey, + OUT ib_mw_handle_t *ph_mw, + IN OUT ci_umv_buf_t *p_umv_buf ) +{ + UNREFERENCED_PARAMETER(h_pd); + UNREFERENCED_PARAMETER(p_rkey); + UNREFERENCED_PARAMETER(ph_mw); + UNREFERENCED_PARAMETER(p_umv_buf); + HCA_PRINT(TRACE_LEVEL_ERROR , HCA_DBG_MEMORY ,("mlnx_create_mw not implemented\n")); + return IB_UNSUPPORTED; +} + +ib_api_status_t +mlnx_query_mw ( + IN const ib_mw_handle_t h_mw, + OUT ib_pd_handle_t *ph_pd, + OUT net32_t* const p_rkey, + IN OUT ci_umv_buf_t *p_umv_buf ) +{ + UNREFERENCED_PARAMETER(h_mw); + UNREFERENCED_PARAMETER(ph_pd); + UNREFERENCED_PARAMETER(p_rkey); + UNREFERENCED_PARAMETER(p_umv_buf); + HCA_PRINT(TRACE_LEVEL_ERROR , HCA_DBG_MEMORY ,("mlnx_query_mw not implemented\n")); + return IB_UNSUPPORTED; +} + +ib_api_status_t +mlnx_destroy_mw ( + IN const ib_mw_handle_t h_mw) +{ + UNREFERENCED_PARAMETER(h_mw); + HCA_PRINT(TRACE_LEVEL_ERROR , HCA_DBG_MEMORY ,("mlnx_destroy_mw not implemented\n")); + return IB_UNSUPPORTED; +} + + +void +mlnx_mr_if( + IN OUT ci_interface_t *p_interface ) +{ + p_interface->register_mr = mlnx_register_mr; + p_interface->register_pmr = mlnx_register_pmr; + p_interface->query_mr = mlnx_query_mr; + p_interface->modify_mr = mlnx_modify_mr; + p_interface->modify_pmr = mlnx_modify_pmr; + p_interface->register_smr = mlnx_register_smr; + p_interface->deregister_mr = mlnx_deregister_mr; + + p_interface->alloc_mlnx_fmr = mlnx_alloc_fmr; + p_interface->map_phys_mlnx_fmr = mlnx_map_phys_fmr; + p_interface->unmap_mlnx_fmr = mlnx_unmap_fmr; + p_interface->dealloc_mlnx_fmr = mlnx_dealloc_fmr; + + p_interface->create_mw = mlnx_create_mw; + p_interface->query_mw = mlnx_query_mw; + p_interface->destroy_mw = mlnx_destroy_mw; +} + +void +mlnx_mr_if_livefish( + IN OUT ci_interface_t *p_interface ) +{ + p_interface->register_pmr = mlnx_register_pmr; + p_interface->deregister_mr = mlnx_deregister_mr; +} + + diff --git a/branches/WOF2-3/hw/mlx4/kernel/hca/pd.c b/branches/WOF2-3/hw/mlx4/kernel/hca/pd.c new file mode 100644 index 00000000..38d01a36 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/hca/pd.c @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: al.c 1611 2006-08-20 14:48:55Z sleybo $ + */ + +#include "precomp.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "pd.tmh" +#endif + + +/* Protection domains */ + +ib_api_status_t +mlnx_allocate_pd ( + IN const ib_ca_handle_t h_ca, + IN const ib_pd_type_t type, + OUT ib_pd_handle_t *ph_pd, + IN OUT ci_umv_buf_t *p_umv_buf ) +{ + ib_api_status_t status; + struct ib_device *p_ibdev; + struct ib_ucontext *p_uctx; + struct ib_pd *p_ib_pd; + struct ib_udata udata; + struct ibv_alloc_pd_resp *p_resp = NULL; + int err; + + //TODO: how are we to use it ? + UNREFERENCED_PARAMETER(type); + + HCA_ENTER(HCA_DBG_PD); + + if( p_umv_buf ) { + p_uctx = (struct ib_ucontext *)h_ca; + p_ibdev = p_uctx->device; + + if( p_umv_buf->command ) { + // sanity checks + if (p_umv_buf->output_size < sizeof(struct ibv_alloc_pd_resp) || + !p_umv_buf->p_inout_buf) { + status = IB_INVALID_PARAMETER; + goto err_alloc_pd; + } + + // prepare user parameters + p_resp = (struct ibv_alloc_pd_resp*)(ULONG_PTR)p_umv_buf->p_inout_buf; + INIT_UDATA(&udata, NULL, &p_resp->pdn, + 0, sizeof(p_resp->pdn)); + } + else { + u32 pdn; + INIT_UDATA(&udata, NULL, &pdn, + 0, sizeof(pdn)); + } + } + else { + mlnx_hca_t *p_hca = (mlnx_hca_t *)h_ca; + p_ibdev = hca2ibdev(p_hca); + p_uctx = NULL; + } + + // create PD + p_ib_pd = p_ibdev->alloc_pd(p_ibdev, p_uctx, &udata); + + if (IS_ERR(p_ib_pd)){ + err = PTR_ERR(p_ib_pd); + status = errno_to_iberr(err); + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_PD, + ("ibv_alloc_pd failed (%#x)\n", status)); + goto err_alloc_pd; + } + else { + p_ib_pd->device = p_ibdev; + p_ib_pd->p_uctx = p_uctx; + atomic_set(&p_ib_pd->usecnt, 0); + HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_PD ,("pdn %d, usecnt %d, pd_handle %p, ctx %p \n", + ((struct mlx4_ib_pd*)p_ib_pd)->pdn, p_ib_pd->usecnt, p_ib_pd, p_ib_pd->p_uctx)); + } + + // complete user response + if (p_umv_buf && p_umv_buf->command) { + p_resp->pd_handle = (u64)(ULONG_PTR)p_ib_pd; + } + + // return the result + if (ph_pd) *ph_pd = (ib_pd_handle_t)p_ib_pd; + + status = IB_SUCCESS; + +err_alloc_pd: + if (p_umv_buf && p_umv_buf->command) + p_umv_buf->status = status; + HCA_EXIT(HCA_DBG_PD); + return status; +} + +ib_api_status_t +mlnx_deallocate_pd ( + IN ib_pd_handle_t h_pd) +{ + ib_api_status_t status; + int err; + struct ib_pd *p_ib_pd = (struct ib_pd *)h_pd; + + HCA_ENTER( HCA_DBG_PD); + + HCA_PRINT(TRACE_LEVEL_INFORMATION,HCA_DBG_PD, + ("pcs %p\n", PsGetCurrentProcess())); + + if (!hca_is_livefish(p_ib_pd->device->x.p_fdo)) { + if (atomic_read(&p_ib_pd->usecnt)) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_PD, + ("resources are not released (pdn %d, cnt %d)\n", + ((struct mlx4_ib_pd*)p_ib_pd)->pdn, p_ib_pd->usecnt)); + status = IB_RESOURCE_BUSY; + goto err_dealloc_pd; + } + } + + err = p_ib_pd->device->dealloc_pd(p_ib_pd); + if (err) { + status = errno_to_iberr(err); + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_PD + ,("ibv_dealloc_pd failed (%#x)\n", status)); + goto err_dealloc_pd; + } + status = IB_SUCCESS; + +err_dealloc_pd: + HCA_EXIT(HCA_DBG_PD); + return status; +} + + +void +mlnx_pd_if( + IN OUT ci_interface_t *p_interface ) +{ + p_interface->allocate_pd = mlnx_allocate_pd; + p_interface->deallocate_pd = mlnx_deallocate_pd; +} + diff --git a/branches/WOF2-3/hw/mlx4/kernel/hca/precomp.h b/branches/WOF2-3/hw/mlx4/kernel/hca/precomp.h new file mode 100644 index 00000000..1d316185 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/hca/precomp.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: al.c 1611 2006-08-20 14:48:55Z sleybo $ + */ +#pragma once + +#include +#include +#define NTSTRSAFE_LIB +#include +#include // required for GUID definitions +#include "public.h" +#include "debug.h" +#include "l2w.h" +#include "hverbs.h" +#include "mlx4_ib.h" +#include "drv.h" +#include "mx_abi.h" +#include "vc.h" +#include "ib_cache.h" +#include "data.h" diff --git a/branches/WOF2-3/hw/mlx4/kernel/hca/qp.c b/branches/WOF2-3/hw/mlx4/kernel/hca/qp.c new file mode 100644 index 00000000..5da9c0e7 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/hca/qp.c @@ -0,0 +1,398 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: al.c 1611 2006-08-20 14:48:55Z sleybo $ + */ + +#include "precomp.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "qp.tmh" +#endif + + +ib_api_status_t +mlnx_query_qp ( + IN const ib_qp_handle_t h_qp, + OUT ib_qp_attr_t *p_qp_attr, + IN OUT ci_umv_buf_t *p_umv_buf ) +{ + ib_api_status_t status; + struct ib_qp *p_ib_qp = (struct ib_qp *)h_qp; + struct ib_qp_attr qp_attr; + struct ib_qp_init_attr qp_init_attr; + int qp_attr_mask = 0; + int err; + + UNREFERENCED_PARAMETER(p_umv_buf); + + HCA_ENTER( HCA_DBG_QP); + + // sanity checks + if (!p_qp_attr) { + status = IB_INVALID_PARAMETER; + goto err_parm; + } + + // convert structures + memset( &qp_attr, 0, sizeof(struct ib_qp_attr) ); + err = p_ib_qp->device->query_qp( p_ib_qp, &qp_attr, + qp_attr_mask, &qp_init_attr); + if (err){ + status = errno_to_iberr(err); + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_PD, + ("ib_query_qp failed (%#x)\n", status)); + goto err_query_qp; + } + + status = from_qp_attr( p_ib_qp, &qp_attr, p_qp_attr ); + +err_query_qp: +err_parm: + HCA_EXIT(HCA_DBG_QP); + return status; +} + +static ib_api_status_t +__create_qp ( + IN const ib_pd_handle_t h_pd, + IN const uint8_t port_num, + IN const void *qp_uctx, + IN ci_async_event_cb_t event_handler, + IN const ib_qp_create_t *p_create_attr, + OUT ib_qp_attr_t *p_qp_attr, + OUT ib_qp_handle_t *ph_qp, + IN OUT ci_umv_buf_t *p_umv_buf ) +{ + int err; + ib_api_status_t status; + struct ib_qp * p_ib_qp; + struct ib_qp_init_attr qp_init_attr; + struct ib_ucontext *p_uctx = NULL; + struct ib_pd *p_ib_pd = (struct ib_pd *)h_pd; + struct ibv_create_qp *p_req = NULL; + + HCA_ENTER(HCA_DBG_QP); + + if( p_umv_buf && p_umv_buf->command ) { + // sanity checks + if (p_umv_buf->input_size < sizeof(struct ibv_create_qp) || + p_umv_buf->output_size < sizeof(struct ibv_create_qp_resp) || + !p_umv_buf->p_inout_buf) { + status = IB_INVALID_PARAMETER; + goto err_inval_params; + } + p_req = (struct ibv_create_qp*)(ULONG_PTR)p_umv_buf->p_inout_buf; + p_uctx = p_ib_pd->p_uctx; + } + + // prepare the parameters + RtlZeroMemory(&qp_init_attr, sizeof(qp_init_attr)); + qp_init_attr.event_handler = event_handler; + qp_init_attr.qp_context = (void*)qp_uctx; + qp_init_attr.send_cq = (struct ib_cq *)p_create_attr->h_sq_cq; + qp_init_attr.recv_cq = (struct ib_cq *)p_create_attr->h_rq_cq; + qp_init_attr.srq = (struct ib_srq *)p_create_attr->h_srq; + if( p_umv_buf && p_umv_buf->command ) { + qp_init_attr.cap.max_recv_sge = p_req->max_recv_sge; + qp_init_attr.cap.max_send_sge = p_req->max_send_sge; + qp_init_attr.cap.max_recv_wr = p_req->max_recv_wr; + qp_init_attr.cap.max_send_wr = p_req->max_send_wr; + qp_init_attr.cap.max_inline_data = p_req->max_inline_data; + } + else { + qp_init_attr.cap.max_recv_sge = p_create_attr->rq_sge; + qp_init_attr.cap.max_send_sge = p_create_attr->sq_sge; + qp_init_attr.cap.max_recv_wr = p_create_attr->rq_depth; + qp_init_attr.cap.max_send_wr = p_create_attr->sq_depth; + qp_init_attr.cap.max_inline_data = p_create_attr->sq_max_inline; + + } + qp_init_attr.sq_sig_type = (p_create_attr->sq_signaled) ? IB_SIGNAL_ALL_WR : IB_SIGNAL_REQ_WR; + qp_init_attr.qp_type = to_qp_type(p_create_attr->qp_type); + qp_init_attr.port_num = port_num; + qp_init_attr.create_flags |= IB_QP_CREATE_IPOIB_UD_LSO; + + // create qp + p_ib_qp = ibv_create_qp( p_ib_pd, &qp_init_attr, p_uctx, p_umv_buf ); + if (IS_ERR(p_ib_qp)) { + err = PTR_ERR(p_ib_qp); + HCA_PRINT(TRACE_LEVEL_ERROR , HCA_DBG_QP, + ("ibv_create_qp failed (%d)\n", err)); + status = errno_to_iberr(err); + goto err_create_qp; + } + + // Query QP to obtain requested attributes + if (p_qp_attr) { + status = mlnx_query_qp((ib_qp_handle_t)p_ib_qp, p_qp_attr, p_umv_buf); + if (status != IB_SUCCESS) + goto err_query_qp; + } + + // return the results + if (ph_qp) *ph_qp = (ib_qp_handle_t)p_ib_qp; + + status = IB_SUCCESS; + goto end; + +err_query_qp: + ib_destroy_qp( p_ib_qp ); +err_create_qp: +err_inval_params: +end: + if (p_umv_buf && p_umv_buf->command) + p_umv_buf->status = status; + if (status != IB_SUCCESS) + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_QP, + ("completes with ERROR status %x\n", status)); + HCA_EXIT(HCA_DBG_QP); + return status; +} + +ib_api_status_t +mlnx_create_spl_qp ( + IN const ib_pd_handle_t h_pd, + IN const uint8_t port_num, + IN const void *qp_uctx, + IN ci_async_event_cb_t event_handler, + IN const ib_qp_create_t *p_create_attr, + OUT ib_qp_attr_t *p_qp_attr, + OUT ib_qp_handle_t *ph_qp ) +{ + ib_api_status_t status; + + HCA_ENTER(HCA_DBG_SHIM); + + status = __create_qp( h_pd, port_num, + qp_uctx, event_handler, p_create_attr, p_qp_attr, ph_qp, NULL ); + + if (status != IB_SUCCESS) + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_QP, + ("completes with ERROR status %x\n", status)); + HCA_EXIT(HCA_DBG_QP); + return status; +} + +ib_api_status_t +mlnx_create_qp ( + IN const ib_pd_handle_t h_pd, + IN const void *qp_uctx, + IN ci_async_event_cb_t event_handler, + IN const ib_qp_create_t *p_create_attr, + OUT ib_qp_attr_t *p_qp_attr, + OUT ib_qp_handle_t *ph_qp, + IN OUT ci_umv_buf_t *p_umv_buf ) +{ + ib_api_status_t status; + + //NB: algorithm of mthca_alloc_sqp() requires port_num + // PRM states, that special pares are created in couples, so + // looks like we can put here port_num = 1 always + uint8_t port_num = 1; + + HCA_ENTER(HCA_DBG_QP); + + status = __create_qp( h_pd, port_num, + qp_uctx, event_handler, p_create_attr, p_qp_attr, ph_qp, p_umv_buf ); + + if (status != IB_SUCCESS) + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_QP, + ("completes with ERROR status %x\n", status)); + HCA_EXIT(HCA_DBG_QP); + return status; +} + +ib_api_status_t +mlnx_modify_qp ( + IN const ib_qp_handle_t h_qp, + IN const ib_qp_mod_t *p_modify_attr, + OUT ib_qp_attr_t *p_qp_attr OPTIONAL, + IN OUT ci_umv_buf_t *p_umv_buf OPTIONAL ) +{ + int err; + ib_api_status_t status; + struct ib_qp_attr qp_attr; + int qp_attr_mask; + struct ib_qp *p_ib_qp = (struct ib_qp *)h_qp; + + HCA_ENTER(HCA_DBG_QP); + + // sanity checks + if( p_umv_buf && p_umv_buf->command ) { + // sanity checks + if (p_umv_buf->output_size < sizeof(struct ibv_modify_qp_resp) || + !p_umv_buf->p_inout_buf) { + status = IB_INVALID_PARAMETER; + goto err_inval_params; + } + } + + // fill parameters + status = to_qp_attr( p_ib_qp, from_qp_type(p_ib_qp->qp_type), + p_modify_attr, &qp_attr, &qp_attr_mask ); + if (status == IB_NOT_DONE) + goto query_qp; + if (status != IB_SUCCESS ) + goto err_mode_unsupported; + + // modify QP + err = p_ib_qp->device->modify_qp( p_ib_qp, &qp_attr, qp_attr_mask, NULL); + if (err) { + HCA_PRINT(TRACE_LEVEL_ERROR, HCA_DBG_QP, + ("ibv_modify_qp failed (%d)\n", err)); + status = errno_to_iberr(err); + goto err_modify_qp; + } + + // Query QP to obtain requested attributes +query_qp: + if (p_qp_attr) { + status = mlnx_query_qp ((ib_qp_handle_t)p_ib_qp, p_qp_attr, p_umv_buf); + if (status != IB_SUCCESS) + goto err_query_qp; + } + + if( p_umv_buf && p_umv_buf->command ) { + struct ibv_modify_qp_resp resp; + resp.attr_mask = qp_attr_mask; + resp.qp_state = qp_attr.qp_state; + err = to_umv_buf(p_umv_buf, &resp, sizeof(struct ibv_modify_qp_resp)); + if (err) { + HCA_PRINT(TRACE_LEVEL_ERROR , HCA_DBG_SHIM ,("to_umv_buf failed (%d)\n", err)); + status = errno_to_iberr(err); + goto err_copy; + } + } + + status = IB_SUCCESS; + +err_copy: +err_query_qp: +err_modify_qp: +err_mode_unsupported: +err_inval_params: + if (p_umv_buf && p_umv_buf->command) + p_umv_buf->status = status; + if (status != IB_SUCCESS) { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_QP, + ("completes with ERROR status %x\n", status)); + } + HCA_EXIT(HCA_DBG_QP); + return status; +} + +ib_api_status_t +mlnx_ndi_modify_qp ( + IN const ib_qp_handle_t h_qp, + IN const ib_qp_mod_t *p_modify_attr, + OUT ib_qp_attr_t *p_qp_attr OPTIONAL, + IN const uint32_t buf_size, + IN uint8_t* const p_outbuf) +{ + ci_umv_buf_t umv_buf; + ib_api_status_t status; + struct ibv_modify_qp_resp resp; + void *buf = &resp; + + HCA_ENTER(HCA_DBG_QP); + + if (buf_size < sizeof(resp.qp_state)) { + status = IB_INVALID_PARAMETER; + goto out; + } + + /* imitate umv_buf */ + umv_buf.command = TRUE; /* special case for NDI. Usually it's TRUE */ + umv_buf.input_size = 0; + umv_buf.output_size = sizeof(struct ibv_modify_qp_resp); + umv_buf.p_inout_buf = (ULONG_PTR)buf; + + status = mlnx_modify_qp ( h_qp, p_modify_attr, p_qp_attr, &umv_buf ); + + if (status == IB_SUCCESS) { + cl_memclr( p_outbuf, buf_size ); + *p_outbuf = resp.qp_state; + } + +out: + HCA_EXIT(HCA_DBG_QP); + return status; +} + +ib_api_status_t +mlnx_destroy_qp ( + IN const ib_qp_handle_t h_qp, + IN const uint64_t timewait ) +{ + ib_api_status_t status; + int err; + struct ib_qp *p_ib_qp = (struct ib_qp *)h_qp; + + UNUSED_PARAM( timewait ); + + HCA_ENTER( HCA_DBG_QP); + + HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_SHIM , + ("qpnum %#x, pcs %p\n", p_ib_qp->qp_num, PsGetCurrentProcess()) ); + + err = ib_destroy_qp( p_ib_qp ); + if (err) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_QP, + ("ibv_destroy_qp failed (%d)\n", err)); + status = errno_to_iberr(err); + goto err_destroy_qp; + } + + status = IB_SUCCESS; + +err_destroy_qp: + if (status != IB_SUCCESS) + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_QP, + ("completes with ERROR status %x\n", status)); + HCA_EXIT(HCA_DBG_QP); + return status; +} + +void +mlnx_qp_if( + IN OUT ci_interface_t *p_interface ) +{ + p_interface->create_qp = mlnx_create_qp; + p_interface->create_spl_qp = mlnx_create_spl_qp; + p_interface->modify_qp = mlnx_modify_qp; + p_interface->ndi_modify_qp = mlnx_ndi_modify_qp; + p_interface->query_qp = mlnx_query_qp; + p_interface->destroy_qp = mlnx_destroy_qp; +} + diff --git a/branches/WOF2-3/hw/mlx4/kernel/hca/srq.c b/branches/WOF2-3/hw/mlx4/kernel/hca/srq.c new file mode 100644 index 00000000..971b8358 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/hca/srq.c @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: al.c 1611 2006-08-20 14:48:55Z sleybo $ + */ + +#include "precomp.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "srq.tmh" +#endif + + +ib_api_status_t +mlnx_create_srq ( + IN const ib_pd_handle_t h_pd, + IN const void *srq_context, + IN ci_async_event_cb_t event_handler, + IN const ib_srq_attr_t * const p_srq_attr, + OUT ib_srq_handle_t *ph_srq, + IN OUT ci_umv_buf_t *p_umv_buf ) +{ + int err; + ib_api_status_t status; + struct ib_srq *p_ib_srq; + struct ib_srq_init_attr srq_init_attr; + struct ib_ucontext *p_uctx = NULL; + struct ib_pd *p_ib_pd = (struct ib_pd *)h_pd; + + HCA_ENTER(HCA_DBG_SRQ); + + if( p_umv_buf && p_umv_buf->command) { + + // sanity checks + if (p_umv_buf->input_size < sizeof(struct ibv_create_srq) || + p_umv_buf->output_size < sizeof(struct ibv_create_srq_resp) || + !p_umv_buf->p_inout_buf) { + status = IB_INVALID_PARAMETER; + goto err_inval_params; + } + p_uctx = p_ib_pd->p_uctx; + } + + // prepare the parameters + RtlZeroMemory(&srq_init_attr, sizeof(srq_init_attr)); + srq_init_attr.event_handler = event_handler; + srq_init_attr.srq_context = (void*)srq_context; + srq_init_attr.attr.max_wr = p_srq_attr->max_wr; + srq_init_attr.attr.max_sge = p_srq_attr->max_sge; + srq_init_attr.attr.srq_limit = p_srq_attr->srq_limit; + + // allocate srq + p_ib_srq = ibv_create_srq(p_ib_pd, &srq_init_attr, p_uctx, p_umv_buf ); + if (IS_ERR(p_ib_srq)) { + err = PTR_ERR(p_ib_srq); + HCA_PRINT (TRACE_LEVEL_ERROR ,HCA_DBG_SRQ, ("ibv_create_srq failed (%d)\n", err)); + status = errno_to_iberr(err); + goto err_create_srq; + } + + // return the result + if (ph_srq) *ph_srq = (ib_srq_handle_t)p_ib_srq; + + status = IB_SUCCESS; + +err_create_srq: +err_inval_params: + if (p_umv_buf && p_umv_buf->command) + p_umv_buf->status = status; + if (status != IB_SUCCESS) + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_SRQ, + ("completes with ERROR status %x\n", status)); + HCA_EXIT(HCA_DBG_SRQ); + return status; +} + + +ib_api_status_t +mlnx_modify_srq ( + IN const ib_srq_handle_t h_srq, + IN const ib_srq_attr_t* const p_srq_attr, + IN const ib_srq_attr_mask_t srq_attr_mask, + IN OUT ci_umv_buf_t *p_umv_buf OPTIONAL ) +{ + int err; + ib_api_status_t status = IB_SUCCESS; + struct ib_srq *p_ib_srq = (struct ib_srq *)h_srq; + UNUSED_PARAM(p_umv_buf); + + HCA_ENTER(HCA_DBG_SRQ); + + err = p_ib_srq->device->modify_srq(p_ib_srq, (void*)p_srq_attr, srq_attr_mask, NULL); + status = errno_to_iberr(err); + + if (status != IB_SUCCESS) + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_SRQ, + ("completes with ERROR status %x\n", status)); + HCA_EXIT(HCA_DBG_SRQ); + return status; +} + +ib_api_status_t +mlnx_query_srq ( + IN const ib_srq_handle_t h_srq, + OUT ib_srq_attr_t* const p_srq_attr, + IN OUT ci_umv_buf_t *p_umv_buf OPTIONAL ) +{ + int err; + ib_api_status_t status = IB_SUCCESS; + struct ib_srq *p_ib_srq = (struct ib_srq *)h_srq; + UNUSED_PARAM(p_umv_buf); + + HCA_ENTER(HCA_DBG_SRQ); + + err = p_ib_srq->device->query_srq(p_ib_srq, (void*)p_srq_attr); + status = errno_to_iberr(err); + + if (status != IB_SUCCESS) + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_SRQ, + ("completes with ERROR status %x\n", status)); + HCA_EXIT(HCA_DBG_SRQ); + return status; +} + +ib_api_status_t +mlnx_destroy_srq ( + IN const ib_srq_handle_t h_srq ) +{ + int err; + ib_api_status_t status = IB_SUCCESS; + struct ib_srq *p_ib_srq = (struct ib_srq *)h_srq; + + HCA_ENTER(HCA_DBG_SRQ); + + err = ib_destroy_srq(p_ib_srq); + status = errno_to_iberr(err); + + if (status != IB_SUCCESS) + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_SRQ, + ("completes with ERROR status %x\n", status)); + HCA_EXIT(HCA_DBG_SRQ); + return status; +} + +void +mlnx_srq_if( + IN OUT ci_interface_t *p_interface ) +{ + p_interface->create_srq = mlnx_create_srq; + p_interface->modify_srq = mlnx_modify_srq; + p_interface->query_srq = mlnx_query_srq; + p_interface->destroy_srq = mlnx_destroy_srq; +} + diff --git a/branches/WOF2-3/hw/mlx4/kernel/hca/vp.c b/branches/WOF2-3/hw/mlx4/kernel/hca/vp.c new file mode 100644 index 00000000..646d01f2 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/hca/vp.c @@ -0,0 +1,326 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2004-2005 Mellanox Technologies, Inc. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: hca_verbs.c 2073 2007-11-13 11:38:40Z leonid $ + */ + +#include "precomp.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "vp.tmh" +#endif + +static ib_api_status_t +mlnx_um_open( + IN const ib_ca_handle_t h_ca, + IN OUT ci_umv_buf_t* const p_umv_buf, + OUT ib_ca_handle_t* const ph_um_ca ) +{ + ib_api_status_t status; + mlnx_hca_t *p_hca = (mlnx_hca_t *)h_ca; + PFDO_DEVICE_DATA p_fdo = hca2fdo(p_hca); + struct ib_device *p_ibdev = hca2ibdev(p_hca); + struct ib_ucontext *p_uctx; + struct ibv_get_context_resp *p_uresp; + + HCA_ENTER(HCA_DBG_SHIM); + + // sanity check + ASSERT( p_umv_buf ); + if( !p_umv_buf->command ) + { // no User Verb Provider + p_uctx = cl_zalloc( sizeof(struct ib_ucontext) ); + if( !p_uctx ) + { + status = IB_INSUFFICIENT_MEMORY; + goto err_alloc_ucontext; + } + /* Copy the dev info. */ + p_uctx->device = p_ibdev; + p_umv_buf->output_size = 0; + status = IB_SUCCESS; + goto done; + } + + // sanity check + if ( p_umv_buf->output_size < sizeof(struct ibv_get_context_resp) || + !p_umv_buf->p_inout_buf) { + status = IB_INVALID_PARAMETER; + goto err_inval_params; + } + + status = ibv_um_open( p_ibdev, p_umv_buf, &p_uctx ); + if (status != IB_SUCCESS) { + goto end; + } + + // fill more parameters for user (sanity checks are in mthca_alloc_ucontext) + p_uresp = (struct ibv_get_context_resp *)(ULONG_PTR)p_umv_buf->p_inout_buf; + p_uresp->vend_id = (uint32_t)p_fdo->bus_ib_ifc.pdev->ven_id; + p_uresp->dev_id = (uint16_t)p_fdo->bus_ib_ifc.pdev->dev_id; + p_uresp->max_qp_wr = hca2mdev(p_hca)->caps.max_wqes; + p_uresp->max_cqe = hca2mdev(p_hca)->caps.max_cqes; + p_uresp->max_sge = min( hca2mdev(p_hca)->caps.max_sq_sg, + hca2mdev(p_hca)->caps.max_rq_sg ); + +done: + // fill the rest of ib_ucontext_ex fields + atomic_set(&p_uctx->x.usecnt, 0); + p_uctx->x.va = p_uctx->x.p_mdl = NULL; + p_uctx->x.fw_if_open = FALSE; + mutex_init( &p_uctx->x.mutex ); + + // chain user context to the device + spin_lock( &p_fdo->uctx_lock ); + cl_qlist_insert_tail( &p_fdo->uctx_list, &p_uctx->x.list_item ); + cl_atomic_inc(&p_fdo->usecnt); + spin_unlock( &p_fdo->uctx_lock ); + + // return the result + if (ph_um_ca) *ph_um_ca = (ib_ca_handle_t)p_uctx; + + status = IB_SUCCESS; + goto end; + +err_inval_params: +err_alloc_ucontext: +end: + if (p_umv_buf && p_umv_buf->command) + p_umv_buf->status = status; + if (status != IB_SUCCESS) + { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_SHIM, + ("completes with ERROR status %x\n", status)); + } + HCA_EXIT(HCA_DBG_SHIM); + return status; +} + + +static void +mlnx_um_close( + IN ib_ca_handle_t h_ca, + IN ib_ca_handle_t h_um_ca ) +{ + struct ib_ucontext *p_uctx = (struct ib_ucontext *)h_um_ca; + PFDO_DEVICE_DATA p_fdo = p_uctx->device->x.p_fdo; + + UNUSED_PARAM(h_ca); + + if ( !hca_is_livefish(p_fdo)) + unmap_crspace_for_all(p_uctx); + spin_lock( &p_fdo->uctx_lock ); + cl_qlist_remove_item( &p_fdo->uctx_list, &p_uctx->x.list_item ); + cl_atomic_dec(&p_fdo->usecnt); + spin_unlock( &p_fdo->uctx_lock ); + if( !p_uctx->x.uar.kva) + cl_free( h_um_ca ); // no User Verb Provider + else + ibv_um_close(p_uctx); +#if 0 + // TODO: replace where pa_cash.c is found + pa_cash_print(); +#endif + return; +} + + +ib_api_status_t +mlnx_local_mad ( + IN const ib_ca_handle_t h_ca, + IN const uint8_t port_num, + IN const ib_av_attr_t* p_av_attr, + IN const ib_mad_t *p_mad_in, + OUT ib_mad_t *p_mad_out ) +{ + int err; + ib_api_status_t status = IB_SUCCESS; + mlnx_hca_t *p_hca = (mlnx_hca_t *)h_ca; + PFDO_DEVICE_DATA p_fdo = hca2fdo(p_hca); + struct ib_device *p_ibdev = p_fdo->bus_ib_ifc.p_ibdev; + //TODO: do we need use flags (IB_MAD_IGNORE_MKEY, IB_MAD_IGNORE_BKEY) ? + int mad_flags = 0; + //TODO: do we need use grh ? + struct ib_grh *p_grh = NULL; + ib_wc_t *p_wc = NULL; + + HCA_ENTER(HCA_DBG_MAD); + + // sanity checks + if (port_num > 2) { + status = IB_INVALID_PARAMETER; + goto err_port_num; + } + + if (p_av_attr){ + p_wc = cl_zalloc(sizeof(ib_wc_t)); + if(!p_wc){ + status = IB_INSUFFICIENT_MEMORY ; + goto err_wc_alloc; + } + //Copy part of the attributes need to fill the mad extended fields in mellanox devices + p_wc->recv.ud.remote_lid = p_av_attr->dlid; + p_wc->recv.ud.remote_sl = p_av_attr->sl; + p_wc->recv.ud.path_bits = p_av_attr->path_bits; + p_wc->recv.ud.recv_opt = p_av_attr->grh_valid ? IB_RECV_OPT_GRH_VALID : 0; + + if(p_wc->recv.ud.recv_opt & IB_RECV_OPT_GRH_VALID){ + p_grh = cl_zalloc(sizeof(struct _ib_grh)); + if(!p_grh){ + status = IB_INSUFFICIENT_MEMORY ; + goto err_grh_alloc; + } + p_grh->version_tclass_flow = p_av_attr->grh.ver_class_flow; + p_grh->hop_limit = p_av_attr->grh.hop_limit; + cl_memcpy( &p_grh->sgid, &p_av_attr->grh.src_gid, sizeof(p_grh->sgid) ); + cl_memcpy( &p_grh->dgid, &p_av_attr->grh.dest_gid, sizeof(p_grh->dgid) ); + // TODO: no direct analogue in IBAL (seems like it is from rmpp) + p_grh->paylen = 0; + p_grh->next_hdr = 0; + } + + + } + + HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_MAD, + ("MAD: Class %02x, Method %02x, Attr %02x, HopPtr %d, HopCnt %d, \n", + (uint32_t)((ib_smp_t *)p_mad_in)->mgmt_class, + (uint32_t)((ib_smp_t *)p_mad_in)->method, + (uint32_t)((ib_smp_t *)p_mad_in)->attr_id, + (uint32_t)((ib_smp_t *)p_mad_in)->hop_ptr, + (uint32_t)((ib_smp_t *)p_mad_in)->hop_count)); + + // process mad + err = p_ibdev->process_mad( p_ibdev, mad_flags, (uint8_t)port_num, + p_wc, p_grh, (struct ib_mad*)p_mad_in, (struct ib_mad*)p_mad_out); + if (!err) { + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_MAD, + ("MAD failed:\n\tClass 0x%x\n\tMethod 0x%x\n\tAttr 0x%x", + p_mad_in->mgmt_class, p_mad_in->method, p_mad_in->attr_id )); + status = IB_ERROR; + goto err_process_mad; + } + + if( (p_mad_in->mgmt_class == IB_MCLASS_SUBN_DIR || + p_mad_in->mgmt_class == IB_MCLASS_SUBN_LID) && + p_mad_in->attr_id == IB_MAD_ATTR_PORT_INFO ) + { + ib_port_info_t *p_pi_in, *p_pi_out; + + if( p_mad_in->mgmt_class == IB_MCLASS_SUBN_DIR ) + { + p_pi_in = (ib_port_info_t*) + ib_smp_get_payload_ptr( (ib_smp_t*)p_mad_in ); + p_pi_out = (ib_port_info_t*) + ib_smp_get_payload_ptr( (ib_smp_t*)p_mad_out ); + } + else + { + p_pi_in = (ib_port_info_t*)(p_mad_in + 1); + p_pi_out = (ib_port_info_t*)(p_mad_out + 1); + } + + /* Work around FW bug 33958 */ + p_pi_out->subnet_timeout &= 0x7F; + if( p_mad_in->method == IB_MAD_METHOD_SET ) + p_pi_out->subnet_timeout |= (p_pi_in->subnet_timeout & 0x80); + } + + /* Modify direction for Direct MAD */ + if ( p_mad_in->mgmt_class == IB_MCLASS_SUBN_DIR ) + p_mad_out->status |= IB_SMP_DIRECTION; + + +err_process_mad: + if(p_grh) + cl_free(p_grh); +err_grh_alloc: + if(p_wc) + cl_free(p_wc); +err_wc_alloc: +err_port_num: + if (status != IB_SUCCESS) + { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_MAD, + ("completes with ERROR status %x\n", status)); + } + HCA_EXIT(HCA_DBG_MAD); + return status; +} + + +void +setup_ci_interface( + IN const ib_net64_t ca_guid, + IN const int is_livefish, + IN OUT ci_interface_t *p_interface ) +{ + cl_memclr(p_interface, sizeof(*p_interface)); + + /* Guid of the CA. */ + p_interface->guid = ca_guid; + + /* Version of this interface. */ + p_interface->version = VERBS_VERSION; + + /* UVP name */ + cl_memcpy( p_interface->libname, mlnx_uvp_lib_name, MAX_LIB_NAME); + + HCA_PRINT(TRACE_LEVEL_VERBOSE , HCA_DBG_SHIM ,("UVP filename %s\n", p_interface->libname)); + + /* The real interface. */ + mlnx_pd_if(p_interface); + p_interface->um_open_ca = mlnx_um_open; + p_interface->um_close_ca = mlnx_um_close; + p_interface->vendor_call = fw_access_ctrl; + + if (is_livefish) { + mlnx_ca_if_livefish(p_interface); + mlnx_mr_if_livefish(p_interface); + } + else { + mlnx_ca_if(p_interface); + mlnx_av_if(p_interface); + mlnx_srq_if(p_interface); + mlnx_qp_if(p_interface); + mlnx_cq_if(p_interface); + mlnx_mr_if(p_interface); + mlnx_direct_if(p_interface); + mlnx_mcast_if(p_interface); + p_interface->local_mad = mlnx_local_mad; + } + + return; +} + + diff --git a/branches/WOF2-3/hw/mlx4/kernel/hca/wmi.c b/branches/WOF2-3/hw/mlx4/kernel/hca/wmi.c new file mode 100644 index 00000000..64a9708d --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/hca/wmi.c @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: al.c 1611 2006-08-20 14:48:55Z sleybo $ + */ + +#include "precomp.h" + +#ifdef USE_WDM_FRAMEWORK + +#pragma warning( disable : 4206) + +#else + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "wmi.tmh" +#endif + +NTSTATUS +WmiRegistration( + WDFDEVICE Device + ) +/*++ +Routine Description + + Registers with WMI as a data provider for this + instance of the device + +--*/ +{ + WDF_WMI_PROVIDER_CONFIG providerConfig; + WDF_WMI_INSTANCE_CONFIG instanceConfig; + NTSTATUS status; + DECLARE_CONST_UNICODE_STRING(hcaRsrcName, HCARESOURCENAME); + + PAGED_CODE(); + + // + // Register WMI classes. + // First specify the resource name which contain the binary mof resource. + // + status = WdfDeviceAssignMofResourceName(Device, &hcaRsrcName); + if (!NT_SUCCESS(status)) { + return status; + } + + WDF_WMI_PROVIDER_CONFIG_INIT(&providerConfig, &MLX4_HCA_WMI_STD_DATA_GUID); + providerConfig.MinInstanceBufferSize = sizeof(HCA_WMI_STD_DATA); + + // + // You would want to create a WDFWMIPROVIDER handle separately if you are + // going to dynamically create instances on the provider. Since we are + // statically creating one instance, there is no need to create the provider + // handle. + // + WDF_WMI_INSTANCE_CONFIG_INIT_PROVIDER_CONFIG(&instanceConfig, &providerConfig); + + // + // By setting Register to TRUE, we tell the framework to create a provider + // as part of the Instance creation call. This eliminates the need to + // call WdfWmiProviderRegister. + // + instanceConfig.Register = TRUE; + instanceConfig.EvtWmiInstanceQueryInstance = EvtStdDataQueryInstance; + instanceConfig.EvtWmiInstanceSetInstance = EvtStdDataSetInstance; + instanceConfig.EvtWmiInstanceSetItem = EvtStdDataSetItem; + + status = WdfWmiInstanceCreate( Device, + &instanceConfig, WDF_NO_OBJECT_ATTRIBUTES, WDF_NO_HANDLE ); + + return status; +} + +// +// WMI System Call back functions +// +NTSTATUS +EvtStdDataSetItem( + IN WDFWMIINSTANCE WmiInstance, + IN ULONG DataItemId, + IN ULONG InBufferSize, + IN PVOID InBuffer + ) +/*++ + +Routine Description: + + This routine is a callback into the driver to set for the contents of + an instance. + +Arguments: + + WmiInstance is the instance being set + + DataItemId has the id of the data item being set + + InBufferSize has the size of the data item passed + + InBuffer has the new values for the data item + +Return Value: + + status + +--*/ +{ + PFDO_DEVICE_DATA fdoData; + + PAGED_CODE(); + + fdoData = FdoGetData(WdfWmiInstanceGetDevice(WmiInstance)); + + switch(DataItemId) + { + case 1: + if (InBufferSize < sizeof(ULONG)) { + return STATUS_BUFFER_TOO_SMALL; + } + fdoData->WmiData.DebugPrintLevel = *((PULONG)InBuffer); + return STATUS_SUCCESS; + + case 2: + if (InBufferSize < sizeof(ULONG)) { + return STATUS_BUFFER_TOO_SMALL; + } + fdoData->WmiData.DebugPrintFlags = *((PULONG)InBuffer); + return STATUS_SUCCESS; + + default: + return STATUS_WMI_READ_ONLY; + } +} + +NTSTATUS +EvtStdDataSetInstance( + IN WDFWMIINSTANCE WmiInstance, + IN ULONG InBufferSize, + IN PVOID InBuffer + ) +/*++ + +Routine Description: + + This routine is a callback into the driver to set for the contents of + an instance. + +Arguments: + + WmiInstance is the instance being set + + BufferSize has the size of the data block passed + + Buffer has the new values for the data block + +Return Value: + + status + +--*/ +{ + PFDO_DEVICE_DATA fdoData; + + UNREFERENCED_PARAMETER(InBufferSize); + + PAGED_CODE(); + + fdoData = FdoGetData(WdfWmiInstanceGetDevice(WmiInstance)); + + // + // We will update only writable elements. + // + memcpy( &fdoData->WmiData, InBuffer, + min(sizeof(HCA_WMI_STD_DATA), InBufferSize)); + + return STATUS_SUCCESS; +} + +NTSTATUS +EvtStdDataQueryInstance( + IN WDFWMIINSTANCE WmiInstance, + IN ULONG OutBufferSize, + IN PVOID OutBuffer, + OUT PULONG BufferUsed + ) +/*++ + +Routine Description: + + This routine is a callback into the driver to set for the contents of + a wmi instance + +Arguments: + + WmiInstance is the instance being set + + OutBufferSize on has the maximum size available to write the data + block. + + OutBuffer on return is filled with the returned data block + + BufferUsed pointer containing how many bytes are required (upon failure) or + how many bytes were used (upon success) + +Return Value: + + status + +--*/ +{ + PFDO_DEVICE_DATA fdoData; + + UNREFERENCED_PARAMETER(OutBufferSize); + + PAGED_CODE(); + + fdoData = FdoGetData(WdfWmiInstanceGetDevice(WmiInstance)); + + *BufferUsed = sizeof (HCA_WMI_STD_DATA); + * (PHCA_WMI_STD_DATA) OutBuffer = fdoData->WmiData; + + return STATUS_SUCCESS; +} + +#endif + diff --git a/branches/WOF2-3/hw/mlx4/kernel/inc/iobuf.h b/branches/WOF2-3/hw/mlx4/kernel/inc/iobuf.h new file mode 100644 index 00000000..44002497 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/inc/iobuf.h @@ -0,0 +1,53 @@ +#pragma once + +typedef struct { + u64 va; /* virtual address of the buffer */ + u64 size; /* size in bytes of the buffer */ + LIST_ENTRY seg_que; + u32 nr_pages; + int is_user; + int seg_num; + int is_cashed; +} iobuf_t; + +/* iterator for getting segments of tpt */ +typedef struct _iobuf_iter { + void * seg_p; /* the item from where to take the next translations */ + unsigned int pfn_ix; /* index from where to take the next translation */ +} iobuf_iter_t; + +void iobuf_deregister_with_cash(IN iobuf_t *iobuf_p); + +void iobuf_deregister(IN iobuf_t *iobuf_p); + +void iobuf_init( + IN u64 va, + IN u64 size, + IN int is_user, + IN OUT iobuf_t *iobuf_p); + +int iobuf_register_with_cash( + IN u64 vaddr, + IN u64 size, + IN int is_user, + IN OUT enum ib_access_flags *acc_p, + IN OUT iobuf_t *iobuf_p); + +int iobuf_register( + IN u64 va, + IN u64 size, + IN int is_user, + IN ib_access_t acc, + IN OUT iobuf_t *iobuf_p); + +void iobuf_iter_init( + IN iobuf_t *iobuf_p, + IN OUT iobuf_iter_t *iterator_p); + +uint32_t iobuf_get_tpt_seg( + IN iobuf_t *iobuf_p, + IN OUT iobuf_iter_t *iterator_p, + IN uint32_t n_pages_in, + IN OUT uint64_t *page_tbl_p ); + + diff --git a/branches/WOF2-3/hw/mlx4/kernel/inc/l2w.h b/branches/WOF2-3/hw/mlx4/kernel/inc/l2w.h new file mode 100644 index 00000000..a46ea43e --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/inc/l2w.h @@ -0,0 +1,364 @@ +#pragma once + +#ifndef L2W_H +#define L2W_H + +//////////////////////////////////////////////////////// +// +// GENERAL INCLUDES +// +//////////////////////////////////////////////////////// + +// OS +#include +//#include +#include +#include +#include +#include +#define NTSTRSAFE_LIB +#include + +// complib +#include +#include + +// mlx4 +#include "vc.h" + + +//////////////////////////////////////////////////////// +// +// LITERALS +// +//////////////////////////////////////////////////////// + +#define BITS_PER_LONG 32 +#define N_BARS 3 +#define HZ 1000000 /* 1 sec in usecs */ +#define EOPNOTSUPP 95 + + +//////////////////////////////////////////////////////// +// +// SUBSTITUTIONS +// +//////////////////////////////////////////////////////// + +#define BUG_ON(exp) ASSERT(!(exp)) /* in Linux follows here panic() !*/ +#define snprintf _snprintf +#define printk cl_dbg_out +#define KERN_ERR "err:" +#define KERN_WARNING "warn:" +#define KERN_DEBUG "dbg:" + +// memory barriers +#define wmb KeMemoryBarrier +#define rmb KeMemoryBarrier +#define mb KeMemoryBarrier +// TODO: can we make it empty ? I saw in Linux, it is an empty macro for x86 & x64 +#define mmiowb KeMemoryBarrier + +// linker +#define EXPORT_SYMBOL_GPL(a) + +// gcc compiler attributes +#define __devinit +#define __devinitdata +#define __init +#define __exit +#define __force +#define __iomem +#define __attribute_const__ +#define likely(x) (x) +#define unlikely(x) (x) +#define __attribute__(a) +#define __bitwise + +// container_of +#define container_of CONTAINING_RECORD + +// inline +#define inline __inline + +// new Linux event mechanism +#define complete(a) wake_up(a) + +// convert +#define __constant_htons CL_HTON16 +#define __constant_cpu_to_be32 CL_HTON32 + +// various +#define __always_inline inline + +#if (WINVER < _WIN32_WINNT_WIN6) +#define num_possible_cpus() KeNumberProcessors +#else +#define num_possible_cpus() KeQueryMaximumProcessorCount() +#endif + + +//////////////////////////////////////////////////////// +// +// TYPES +// +//////////////////////////////////////////////////////// + +// basic types +typedef unsigned char u8, __u8; +typedef unsigned short int u16, __u16; +typedef unsigned int u32, __u32; +typedef unsigned __int64 u64, __u64; +typedef char s8, __s8; +typedef short int s16, __s16; +typedef int s32, __s32; +typedef __int64 s64, __s64; + +// inherited +typedef u16 __le16; +typedef u16 __be16; +typedef u32 __le32; +typedef u32 __be32; +typedef u64 __le64; +typedef u64 __be64; +typedef u64 io_addr_t; + +// dummy function +typedef void (*MT_EMPTY_FUNC)(); + +// PCI BAR descriptor +typedef enum _hca_bar_type +{ + HCA_BAR_TYPE_HCR, + HCA_BAR_TYPE_UAR, + HCA_BAR_TYPE_DDR, + HCA_BAR_TYPE_MAX + +} hca_bar_type_t; + + +typedef struct _hca_bar +{ + uint64_t phys; + void *virt; + SIZE_T size; + +} hca_bar_t; + +struct msix_saved_info { + PVOID vca; /* MSI-X Vector Table card address */ + PVOID mca; /* MSI-X Mask Table card address */ + PVOID vsa; /* MSI-X Vector Table saved address */ + PVOID msa; /* MSI-X Mask Table saved address */ + ULONG vsz; /* MSI-X Vector Table size */ + ULONG msz; /* MSI-X Mask Table size */ + int num; /* number of supported MSI-X vectors */ + int valid; /* the structure is valid */ +}; + +struct msix_map { + KAFFINITY cpu; /* affinity of this MSI-X vector */ + int eq_ix; /* EQ index in the array of EQs */ + int ref_cnt; /* number of users */ +}; + +typedef struct _MLX4_ST_DEVICE *PMLX4_ST_DEVICE; + +// interface structure between Upper and Low Layers of the driver +struct pci_dev +{ + // driver: OS/platform resources + BUS_INTERFACE_STANDARD bus_pci_ifc; + PCI_COMMON_CONFIG pci_cfg_space; + struct msix_saved_info msix_info; + struct msix_map* p_msix_map; + uplink_info_t uplink_info; + // driver: card resources + hca_bar_t bar[N_BARS]; + CM_PARTIAL_RESOURCE_DESCRIPTOR int_info; /* HCA interrupt resources */ + // driver: various objects and info + USHORT ven_id; + USHORT dev_id; + USHORT sub_vendor_id; + USHORT sub_system_id; + UCHAR revision_id; + DMA_ADAPTER * p_dma_adapter; /* HCA adapter object */ + DEVICE_OBJECT * p_self_do; /* mlx4_bus's FDO */ + DEVICE_OBJECT * pdo; /* mlx4_bus's PDO */ + PVOID p_wdf_device; /* wdf_device */ + LONG ib_hca_created; + // mlx4_ib: various objects and info + struct ib_device * ib_dev; + // mlx4_net: various objects and info + struct mlx4_dev * dev; + volatile long dpc_lock; + PUCHAR vpd; + int vpd_size; + WCHAR location[36]; /* bus+func+dev */ +#ifdef USE_WDM_INTERRUPTS + PKINTERRUPT int_obj; /* HCA interrupt object */ + KSPIN_LOCK isr_lock; /* lock for the ISR */ + // MSI-X interrupts + u8 n_msi_vectors_alloc;/* number of allocated MSI vectors */ + u8 n_msi_vectors; /* number of MSI vectors; 0 - no MSI */ + ULONG version; + int legacy_connect; +#endif + // statistics + PMLX4_ST_DEVICE p_stat_dev; +}; + +/* DPC */ +typedef void (*dpc_t)( struct _KDPC *, PVOID, PVOID, PVOID ); + + +//////////////////////////////////////////////////////// +// +// MACROS +// +//////////////////////////////////////////////////////// + +// conversions +#define swab32(a) _byteswap_ulong((ULONG)(a)) +#define cpu_to_be16(a) _byteswap_ushort((USHORT)(a)) +#define be16_to_cpu(a) _byteswap_ushort((USHORT)(a)) +#define cpu_to_be32(a) _byteswap_ulong((ULONG)(a)) +#define be32_to_cpu(a) _byteswap_ulong((ULONG)(a)) +#define cpu_to_be64(a) _byteswap_uint64((UINT64)(a)) +#define be64_to_cpu(a) _byteswap_uint64((UINT64)(a)) +#define be64_to_cpup(p) _byteswap_uint64(*(PUINT64)(p)) +#define be32_to_cpup(p) _byteswap_ulong(*(PULONG)(p)) +#define be16_to_cpup(p) _byteswap_ushort(*(PUSHORT)(p)) + +// ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +// ALIGN +#define ALIGN(x,a) (((x)+(a)-1)&~((a)-1)) +#define PTR_ALIGN(size) (((size) + sizeof(void*) - 1) & ~(sizeof(void*) - 1)) + +// there is a bug in Microsoft compiler, that when _byteswap_uint64() gets an expression +// it executes the expression but doesn't swap tte dwords +// So, there's a workaround +#ifdef BYTESWAP_UINT64_BUG_FIXED +#define CPU_2_BE64_PREP +#define CPU_2_BE64(x) cl_hton64(x) +#else +#define CPU_2_BE64_PREP unsigned __int64 __tmp__ +#define CPU_2_BE64(x) ( __tmp__ = x, cl_hton64(__tmp__) ) +#endif + +#define ERR_PTR(error) ((void*)(LONG_PTR)(error)) +#define PTR_ERR(ptr) ((long)(LONG_PTR)(void*)(ptr)) +//TODO: there are 2 assumptions here: +// - pointer can't be too big (around -1) +// - error can't be bigger than 1000 +#define IS_ERR(ptr) ((ULONG_PTR)ptr > (ULONG_PTR)-1000L) + +#define BITS_TO_LONGS(bits) \ + (((bits)+BITS_PER_LONG-1)/BITS_PER_LONG) + +#ifndef ETIMEDOUT +#define ETIMEDOUT (110) +#endif + +#ifdef PAGE_ALIGN +#undef PAGE_ALIGN +#define PAGE_ALIGN(Va) ((u64)((ULONG_PTR)(Va) & ~(PAGE_SIZE - 1))) +#endif + +#define NEXT_PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK) + +/* typed minimum */ +#define min_t(type,x,y) ((type)(x) < (type)(y) ? (type)(x) : (type)(y)) + +#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) + +#define EXPORT_SYMBOL(name) +#ifndef USE_WDM_INTERRUPTS +#define free_irq(pdev) +#endif + +static inline NTSTATUS errno_to_ntstatus(int err) +{ +#define MAP_ERR(err,ntstatus) case err: status = ntstatus; break + NTSTATUS status; + + if (!err) + return STATUS_SUCCESS; + + if (err < 0) + err = -err; + switch (err) { + MAP_ERR( ENOENT, STATUS_NOT_FOUND ); + MAP_ERR( EAGAIN, STATUS_DEVICE_BUSY ); + MAP_ERR( ENOMEM, STATUS_NO_MEMORY ); + MAP_ERR( EACCES, STATUS_ACCESS_DENIED ); + MAP_ERR( EFAULT, STATUS_DRIVER_INTERNAL_ERROR ); + MAP_ERR( EBUSY, STATUS_INSUFFICIENT_RESOURCES ); + MAP_ERR( ENODEV, STATUS_NOT_SUPPORTED ); + MAP_ERR( EINVAL, STATUS_INVALID_PARAMETER ); + MAP_ERR( ENOSYS, STATUS_NOT_SUPPORTED ); + default: + status = STATUS_UNSUCCESSFUL; + break; + } + return status; +} + + +//////////////////////////////////////////////////////// +// +// PROTOTYPES +// +//////////////////////////////////////////////////////// + +SIZE_T strlcpy(char *dest, const void *src, SIZE_T size); +int core_init(); +void core_cleanup(); + + +//////////////////////////////////////////////////////// +// +// SPECIFIC INCLUDES +// +//////////////////////////////////////////////////////// + +struct mlx4_dev; +struct mlx4_priv; + +#include +#include +#include +#include "l2w_debug.h" +#include +#include +#include +#include +#include +#include "l2w_radix.h" +#include +#include +#include + +#include "device.h" + +static inline int mlx4_is_livefish(struct mlx4_dev *dev) +{ + if (dev == NULL) { + return TRUE; + } + return !!(dev->flags & MLX4_FLAG_LIVEFISH); +} + +static inline int mlx4_is_barred(struct mlx4_dev *dev) +{ + return dev->flags & MLX4_FLAG_RESET_DRIVER; +} + +static inline int mlx4_is_in_reset(struct mlx4_dev *dev) +{ + return dev->flags & MLX4_FLAG_RESET_STARTED; +} + +#endif diff --git a/branches/WOF2-3/hw/mlx4/kernel/inc/l2w_atomic.h b/branches/WOF2-3/hw/mlx4/kernel/inc/l2w_atomic.h new file mode 100644 index 00000000..51bd7779 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/inc/l2w_atomic.h @@ -0,0 +1,47 @@ +#pragma once + +#include "complib/cl_atomic.h" + +typedef volatile __int32 atomic_t; /* as atomic32_t */ + +#define atomic_inc cl_atomic_inc +#define atomic_dec cl_atomic_dec + +static inline atomic_t atomic_read(atomic_t *pval) +{ + return *pval; +} + +static inline void atomic_set(atomic_t *pval, long val) +{ + *pval = (__int32)val; +} + +/** +* atomic_inc_and_test - decrement and test +* pval: pointer of type atomic_t +* +* Atomically increments pval by 1 and +* returns true if the result is 0, or false for all other +* cases. +*/ +static inline int +atomic_inc_and_test(atomic_t *pval) +{ + return cl_atomic_inc(pval) == 0; +} + +/** +* atomic_dec_and_test - decrement and test +* pval: pointer of type atomic_t +* +* Atomically decrements pval by 1 and +* returns true if the result is 0, or false for all other +* cases. +*/ +static inline int +atomic_dec_and_test(atomic_t *pval) +{ + return cl_atomic_dec(pval) == 0; +} + diff --git a/branches/WOF2-3/hw/mlx4/kernel/inc/l2w_bit.h b/branches/WOF2-3/hw/mlx4/kernel/inc/l2w_bit.h new file mode 100644 index 00000000..3641c516 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/inc/l2w_bit.h @@ -0,0 +1,192 @@ +#pragma once + +// Nth element of the table contains the index of the first set bit of N; 8 - for N=0 +extern char g_set_bit_tbl[256]; +// Nth element of the table contains the index of the first cleared bit of N; 8 - for N=0 +extern char g_clr_bit_tbl[256]; + +static inline int fls(int x) +{ + int r = 32; + + if (!x) + return 0; + if (!(x & 0xffff0000u)) { + x <<= 16; + r -= 16; + } + if (!(x & 0xff000000u)) { + x <<= 8; + r -= 8; + } + if (!(x & 0xf0000000u)) { + x <<= 4; + r -= 4; + } + if (!(x & 0xc0000000u)) { + x <<= 2; + r -= 2; + } + if (!(x & 0x80000000u)) { + x <<= 1; + r -= 1; + } + return r; +} + +/** +* _ffs_raw - find the first one bit in a word +* @addr: The address to start the search at +* @offset: The bitnumber to start searching at +* +* returns: 0 - if not found or N+1, if found Nth bit +*/ +static __inline int _ffs_raw(const unsigned long *addr, int offset) +{ + //TODO: not an effective code - is better in Assembler + int mask; + int rbc; + int ix; + if (!*addr) return 0; + mask = 1 << offset; + rbc = BITS_PER_LONG - offset; + for (ix=0; ix> 5); + + // search in the first word while we are in the middle + if (ix) { + res = _ffz_raw(p, ix); + if (res) + return set + res - 1; + ++p; + set += BITS_PER_LONG; + } + + // search the rest of the bitmap + res = find_first_zero_bit(p, bits_size - (unsigned)(32 * (p - addr))); + return res + set; +} + +/* The functions works only for 32-bit values (not as in Linux ) */ +/* on val=0 will return '-1' */ +static inline int ilog2(u32 val) +{ + ASSERT(val); + return fls(val) - 1; +} + +static inline BOOLEAN is_power_of_2(unsigned long n) +{ + return (!!n & !(n & (n-1))) ? TRUE : FALSE; +} + + diff --git a/branches/WOF2-3/hw/mlx4/kernel/inc/l2w_bitmap.h b/branches/WOF2-3/hw/mlx4/kernel/inc/l2w_bitmap.h new file mode 100644 index 00000000..85ba3608 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/inc/l2w_bitmap.h @@ -0,0 +1,79 @@ +#pragma once + +#define DECLARE_BITMAP(name,bits) \ + unsigned long name[BITS_TO_LONGS(bits)] + +static inline unsigned long atomic_set_bit(int nr, volatile long * addr) +{ + return InterlockedOr( addr, (1 << nr) ); +} + +static inline unsigned long atomic_clear_bit(int nr, volatile long * addr) +{ + return InterlockedAnd( addr, ~(1 << nr) ); +} + +static inline int set_bit(int nr,unsigned long * addr) +{ + addr += nr >> 5; + return atomic_set_bit( nr & 0x1f, (volatile long *)addr ); +} + +static inline int clear_bit(int nr, unsigned long * addr) +{ + addr += nr >> 5; + return atomic_clear_bit( nr & 0x1f, (volatile long *)addr ); +} + +static inline int test_bit(int nr, const unsigned long * addr) +{ + int mask; + + addr += nr >> 5; + mask = 1 << (nr & 0x1f); + return ((mask & *addr) != 0); +} + +static inline void bitmap_zero(unsigned long *dst, int nbits) +{ + if (nbits <= BITS_PER_LONG) + *dst = 0UL; + else { + int len = BITS_TO_LONGS(nbits) * sizeof(unsigned long); + RtlZeroMemory(dst, len); + } +} + +#define BITMAP_LAST_WORD_MASK(nbits) \ + ( ((nbits) % BITS_PER_LONG) ? (1UL<<((nbits) % BITS_PER_LONG))-1 : ~0UL ) + +int __bitmap_full(const unsigned long *bitmap, int bits); + +static inline int bitmap_full(const unsigned long *src, int nbits) +{ + if (nbits <= BITS_PER_LONG) + return ! (~(*src) & BITMAP_LAST_WORD_MASK(nbits)); + else + return __bitmap_full(src, nbits); +} + +int __bitmap_empty(const unsigned long *bitmap, int bits); + +static inline int bitmap_empty(const unsigned long *src, int nbits) +{ + if (nbits <= BITS_PER_LONG) + return ! (*src & BITMAP_LAST_WORD_MASK(nbits)); + else + return __bitmap_empty(src, nbits); +} + +static inline void bitmap_fill(unsigned long *dst, int nbits) +{ + size_t nlongs = BITS_TO_LONGS(nbits); + if (nlongs > 1) { + int len = (int)((nlongs - 1) * sizeof(unsigned long)); + memset(dst, 0xff, len); + } + dst[nlongs - 1] = BITMAP_LAST_WORD_MASK(nbits); +} + diff --git a/branches/WOF2-3/hw/mlx4/kernel/inc/l2w_debug.h b/branches/WOF2-3/hw/mlx4/kernel/inc/l2w_debug.h new file mode 100644 index 00000000..896643ea --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/inc/l2w_debug.h @@ -0,0 +1,55 @@ +#pragma once + +VOID +WriteEventLogEntryStr( + PVOID pi_pIoObject, + ULONG pi_ErrorCode, + ULONG pi_UniqueErrorCode, + ULONG pi_FinalStatus, + PWCHAR pi_InsertionStr, + ULONG pi_nDataItems, + ... + ); + +VOID +WriteEventLogEntryData( + PVOID pi_pIoObject, + ULONG pi_ErrorCode, + ULONG pi_UniqueErrorCode, + ULONG pi_FinalStatus, + ULONG pi_nDataItems, + ... + ); + +void +mlx4_err( + IN struct mlx4_dev * mdev, + IN char* format, + ... + ); + +void +mlx4_dbg( + IN struct mlx4_dev * mdev, + IN char* format, + ... + ); + +VOID +dev_err( + IN struct mlx4_dev ** mdev, + IN char* format, + ... + ); + +VOID +dev_info( + IN struct mlx4_dev ** p_mdev, + IN char* format, + ... + ); + +#define mlx4_warn mlx4_err +#define mlx4_info mlx4_dbg +#define dev_warn dev_err + diff --git a/branches/WOF2-3/hw/mlx4/kernel/inc/l2w_list.h b/branches/WOF2-3/hw/mlx4/kernel/inc/l2w_list.h new file mode 100644 index 00000000..1779a191 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/inc/l2w_list.h @@ -0,0 +1,99 @@ +#pragma once + +//////////////////////////////////////////////////////// +// +// TYPES +// +//////////////////////////////////////////////////////// + +// Use the type, defined in wdm.h +#define list_head _LIST_ENTRY + + +//////////////////////////////////////////////////////// +// +// MACROS +// +//////////////////////////////////////////////////////// + + +// Define and initialize a list header +#define LIST_HEAD(name) \ + struct list_head name = { &(name), &(name) } + +// Initialize a list header +#define INIT_LIST_HEAD(ptr) InitializeListHead(ptr) + +// Get to the beginning of the struct for this list entry +#define list_entry(ptr, type, member) CONTAINING_RECORD(ptr, type, member) + +// Iterate over list of 'list_els' of given 'type' +#define list_for_each_entry(list_el, head, member, type) \ + for ( list_el = list_entry((head)->Flink, type, member); \ + &list_el->member != (head); \ + list_el = list_entry(list_el->member.Flink, type, member)) + +// Iterate backwards over list of 'list_els' of given 'type' +#define list_for_each_entry_reverse(list_el, head, member, type) \ + for (list_el = list_entry((head)->Blink, type, member); \ + &list_el->member != (head); \ + list_el = list_entry(list_el->member.Blink, type, member)) + +// Iterate over list of given type safe against removal of list entry +#define list_for_each_entry_safe(list_el, tmp_list_el, head, member,type, tmp_type) \ + for (list_el = list_entry((head)->Flink, type, member), \ + tmp_list_el = list_entry(list_el->member.Flink, type, member); \ + &list_el->member != (head); \ + list_el = tmp_list_el, \ + tmp_list_el = list_entry(tmp_list_el->member.Flink, tmp_type, member)) + + +//////////////////////////////////////////////////////// +// +// FUNCTIONS +// +//////////////////////////////////////////////////////// + +// Insert a new entry after the specified head. +static inline void list_add(struct list_head *new_entry, struct list_head *head) +{ + InsertHeadList( head, new_entry ); +} + +// Insert a new entry before the specified head. +static inline void list_add_tail(struct list_head *new_entry, struct list_head *head) +{ + InsertTailList( head, new_entry ); +} + +// Deletes entry from list. +static inline void list_del(struct list_head *entry) +{ + RemoveEntryList( entry ); +} + +// Tests whether a list is empty +static inline int list_empty(const struct list_head *head) +{ + return IsListEmpty( head ); +} + +// Insert src_list into dst_list and reinitialise the emptied src_list. +static inline void list_splice_init(struct list_head *src_list, + struct list_head *dst_list) +{ + if (!list_empty(src_list)) { + struct list_head *first = src_list->Flink; + struct list_head *last = src_list->Blink; + struct list_head *at = dst_list->Flink; + + first->Blink = dst_list; + dst_list->Flink = first; + + last->Flink = at; + at->Blink = last; + + INIT_LIST_HEAD(src_list); + } +} + diff --git a/branches/WOF2-3/hw/mlx4/kernel/inc/l2w_memory.h b/branches/WOF2-3/hw/mlx4/kernel/inc/l2w_memory.h new file mode 100644 index 00000000..b10242cb --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/inc/l2w_memory.h @@ -0,0 +1,334 @@ +#pragma once + +#include "iobuf.h" +#include "complib\cl_debug.h" + +//////////////////////////////////////////////////////// +// +// CONSTANTS +// +//////////////////////////////////////////////////////// + +#define MT_TAG_ATOMIC 'MOTA' +#define MT_TAG_KERNEL 'LNRK' +#define MT_TAG_HIGH 'HGIH' +#define MT_TAG_PCIPOOL 'PICP' +#define MT_TAG_IOMAP 'PAMI' + +//////////////////////////////////////////////////////// +// +// SUBSTITUTIONS +// +//////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////// +// +// MACROS +// +//////////////////////////////////////////////////////// + +#define PAGE_MASK (~(PAGE_SIZE-1)) + + + //////////////////////////////////////////////////////// + // + // Helper functions + // + //////////////////////////////////////////////////////// + +// returns log of number of pages, i.e +// for size <= 4096 ==> 0 +// for size <= 8192 ==> 1 +static inline int get_order(unsigned long size) +{ + int order; + + size = (size-1) >> (PAGE_SHIFT-1); + order = -1; + do { + size >>= 1; + order++; + } while (size); + return order; +} + +static inline unsigned long roundup_pow_of_two(unsigned long x) +{ + return (1UL << fls(x - 1)); +} + + + +//////////////////////////////////////////////////////// +// +// SYSTEM MEMORY +// +//////////////////////////////////////////////////////// + +typedef enum _gfp { + __GFP_NOWARN = 0, /* Suppress page allocation failure warning */ + __GFP_HIGHMEM = 0, /* high memory */ + GFP_ATOMIC = 1, /* can't wait (i.e. DPC or higher) */ + GFP_KERNEL = 2, /* can wait (npaged) */ + GFP_HIGHUSER = 4 /* GFP_KERNEL, that can be in HIGH memory */ +} +gfp_t; + +struct vm_area_struct { + void * ptr; +}; + +static inline void * kmalloc( SIZE_T bsize, gfp_t gfp_mask) +{ + void *ptr; + ASSERT( KeGetCurrentIrql() <= DISPATCH_LEVEL); + ASSERT(bsize); + switch (gfp_mask) { + case GFP_ATOMIC: + ptr = ExAllocatePoolWithTag( NonPagedPool, bsize, MT_TAG_ATOMIC ); + break; + case GFP_KERNEL: + ptr = ExAllocatePoolWithTag( NonPagedPool, bsize, MT_TAG_KERNEL ); + break; + case GFP_HIGHUSER: + ptr = ExAllocatePoolWithTag( NonPagedPool, bsize, MT_TAG_HIGH ); + break; + default: + cl_dbg_out("kmalloc: unsupported flag %d\n", gfp_mask); + ptr = NULL; + break; + } + return ptr; +} + +static inline void * kzalloc( SIZE_T bsize, gfp_t gfp_mask) +{ + void* va = kmalloc(bsize, gfp_mask); + if (va) + RtlZeroMemory(va, bsize); + return va; +} + +static inline void *kcalloc(size_t n, size_t size, gfp_t flags) +{ + if (n != 0 && size > ULONG_MAX / n) + return NULL; + return kzalloc(n * size, flags); +} + +static inline void kfree (const void *pobj) +{ + ASSERT( KeGetCurrentIrql() <= DISPATCH_LEVEL ); + if (pobj) + ExFreePool((void *)pobj); +} + +#define get_zeroed_page(mask) kzalloc(PAGE_SIZE, mask) +#define free_page(ptr) kfree(ptr) + + +//////////////////////////////////////////////////////// +// +// IO SPACE <==> SYSTEM MEMORY +// +//////////////////////////////////////////////////////// + +/** +* ioremap - map bus memory into CPU space +* @addr: bus address of the memory +* @size: size of the resource to map +* +* ioremap performs a platform specific sequence of operations to +* make bus memory CPU accessible via the readb/readw/readl/writeb/ +* writew/writel functions and the other mmio helpers. The returned +* address is not guaranteed to be usable directly as a virtual +* address. +*/ +static inline void *ioremap(io_addr_t addr, SIZE_T size) +{ + PHYSICAL_ADDRESS pa; + void *va; + + ASSERT( KeGetCurrentIrql() <= DISPATCH_LEVEL ); + pa.QuadPart = addr; + va = MmMapIoSpace( pa, size, MmNonCached ); + return va; +} + +static inline void iounmap(void *va, SIZE_T size) +{ + MmUnmapIoSpace( va, size ); +} + + +//////////////////////////////////////////////////////// +// +// DMA SUPPORT +// +//////////////////////////////////////////////////////// + +enum dma_data_direction { + PCI_DMA_BIDIRECTIONAL, + PCI_DMA_TODEVICE, + DMA_TO_DEVICE = PCI_DMA_TODEVICE +}; + +#define dma_get_cache_alignment (int)KeGetRecommendedSharedDataAlignment + +// wrapper to DMA address +typedef struct _dma_addr +{ + // TODO: in some cases it is still physical address today + io_addr_t da; /* logical (device) address */ + void * va; /* kernel virtual address */ + unsigned long sz; /* buffer size */ +} dma_addr_t; + +#define lowmem_page_address(dma_addr) ((dma_addr).va) + +struct mlx4_dev; + +void *alloc_cont_mem( + IN struct pci_dev *pdev, + IN unsigned long size, + OUT dma_addr_t*p_dma_addr); + +void free_cont_mem( + IN struct pci_dev *pdev, + IN dma_addr_t*p_dma_addr); + +// TODO: translate to DMA space - for now is not done anything +static inline dma_addr_t pci_map_page(struct pci_dev *pdev, + dma_addr_t dma_addr, unsigned long offset, SIZE_T size, int direction) +{ + UNUSED_PARAM(pdev); + UNUSED_PARAM(offset); + UNUSED_PARAM(size); + UNUSED_PARAM(direction); + + return dma_addr; +} + +static inline dma_addr_t +alloc_pages( struct pci_dev *pdev, gfp_t gfp, int order ) +{ + dma_addr_t dma_addr; + UNUSED_PARAM(gfp); + alloc_cont_mem( pdev, PAGE_SIZE << order, &dma_addr ); + return dma_addr; +} + +#define alloc_page(pdev, mask) alloc_pages(pdev, (mask), 0) +#define __get_free_page(mask) kzalloc(PAGE_SIZE, mask) + +static inline void +__free_pages( struct pci_dev *pdev, dma_addr_t dma_addr, int order ) +{ + UNUSED_PARAM(order); + ASSERT((PAGE_SIZE << order) == (int)dma_addr.sz); + free_cont_mem( pdev, &dma_addr ); +} + +#define __free_page(pdev, dma_addr) __free_pages(pdev, (dma_addr), 0) + + + +static inline int pci_dma_mapping_error(dma_addr_t dma_addr) +{ + return !dma_addr.sz; +} + +static inline void pci_unmap_page(struct pci_dev *pdev, + dma_addr_t dma_addr, SIZE_T size, int direction) +{ + UNUSED_PARAM(pdev); + UNUSED_PARAM(dma_addr); + UNUSED_PARAM(size); + UNUSED_PARAM(direction); +} + +static inline void +dma_sync_single( struct mlx4_dev **dev, dma_addr_t dma_addr, + size_t size, int direction) +{ + UNUSED_PARAM(dev); + UNUSED_PARAM(dma_addr); + UNUSED_PARAM(size); + UNUSED_PARAM(direction); + // TODO: here is to be used FlushAdapterBuffers() +} + +void * +dma_alloc_coherent( struct mlx4_dev **dev, size_t size, + dma_addr_t *p_dma, gfp_t gfp ); + +void dma_free_coherent( struct mlx4_dev **dev, size_t size, + void *vaddr, dma_addr_t dma_handle); + + void pci_free_consistent( struct pci_dev *pdev, size_t size, + void *vaddr, dma_addr_t dma_handle); + + + +//////////////////////////////////////////////////////// +// +// SG lists +// +//////////////////////////////////////////////////////// + +#define sg_dma_addr(sg) ((sg)->dma_addr) +#define sg_dma_address(sg) ((sg)->dma_addr.da) +#define sg_dma_len(sg) ((sg)->dma_addr.sz) +#define sg_dma_address_inc(p_dma,val) (p_dma)->da += val +#define sg_page(sg) ((sg)->dma_addr) + +struct scatterlist { + dma_addr_t dma_addr; /* logical (device) address */ + unsigned int offset; /* offset in the first page */ + PMDL p_mdl; /* MDL, if any (used for user space buffers) */ +}; + +#define offset_in_page(va) ((ULONG)((ULONG_PTR)(va) & ~PAGE_MASK)) + +static inline void sg_init_table(struct scatterlist *sgl, unsigned int nents) +{ + memset(sgl, 0, sizeof(*sgl) * nents); +} + +static inline void sg_set_buf(struct scatterlist *sg, const void *buf, + unsigned int buflen) +{ + UNUSED_PARAM(buflen); + ASSERT(sg->dma_addr.sz == buflen); + sg->offset = offset_in_page(buf); +} + +static inline void sg_set_page(struct scatterlist *sg, + dma_addr_t dma_addr, unsigned int len, unsigned int offset) +{ + UNUSED_PARAM(len); + sg->offset = offset; + sg->dma_addr = dma_addr; +} + +/* Returns: the number of unmapped sg elements */ +static inline int pci_map_sg(struct pci_dev *pdev, + struct scatterlist *sg, int nents, int direction) +{ + UNUSED_PARAM(pdev); + UNUSED_PARAM(sg); + UNUSED_PARAM(direction); + return nents; +} + +/* Returns: the number of unmapped sg elements */ +static inline int pci_unmap_sg(struct pci_dev *pdev, + struct scatterlist *sg, int nents, int direction) +{ + UNUSED_PARAM(pdev); + UNUSED_PARAM(sg); + UNUSED_PARAM(direction); + return nents; +} + diff --git a/branches/WOF2-3/hw/mlx4/kernel/inc/l2w_pci.h b/branches/WOF2-3/hw/mlx4/kernel/inc/l2w_pci.h new file mode 100644 index 00000000..2f4754e6 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/inc/l2w_pci.h @@ -0,0 +1,117 @@ +#pragma once + +// =========================================== +// LITERALS +// =========================================== + +#define DEVID_HERMON_SDR 0x6340 /* 25408 */ +#define DEVID_HERMON_DDR 0x634a /* 25418 */ +#define DEVID_HERMON_DDR_G2 0x6732 /* 26418 */ +#define DEVID_HERMON_DDR_G2_A 0x6778 /* 26488 */ +#define DEVID_HERMON_QDR_G2 0x673c /* 26428 */ +#define DEVID_HERMON_QDR_G2_A 0x6746 /* 26438 */ + +#define DEVID_HERMON_ETH 0x6368 /* 25448 */ +#define DEVID_HERMON_ETH_YATIR 0x6372 /* 25458 */ +#define DEVID_HERMON_ETH_G2 0x6750 /* 26448 */ +#define DEVID_HERMON_ETH_YATIR_G2 0x675A /* 26458 */ +#define DEVID_HERMON_ETH_B0_G2 0x6764 /* 26468 */ +#define DEVID_HERMON_ETH_B0_40Gb_G2 0x676E /* 26478 */ +/* livefish */ +#define DEVID_HERMON_BD 0x0191 /* 401 */ + +/* Types of supported HCA */ +typedef enum __hca_type { + HERMON, /* fully functional HCA */ + LIVEFISH /* a burning device */ +} hca_type_t; + +/* vendors */ +#define PCI_VENDOR_ID_MELLANOX 0x15b3 +#define PCI_VENDOR_ID_TOPSPIN 0x1867 + +#define HCA(v, d, t) \ + { PCI_VENDOR_ID_##v, DEVID_HERMON_##d, t } + +struct pci_device_id { + USHORT vendor; + USHORT device; + hca_type_t driver_data; +}; + + +// =========================================== +// TYPES +// =========================================== + + +// =========================================== +// MACROS/FUNCTIONS +// =========================================== + +NTSTATUS pci_hca_reset( struct pci_dev *pdev); + +/* use shim to implement that */ +#define mlx4_reset(dev) pci_hca_reset(dev->pdev) + +// get bar boundaries +#define pci_resource_start(dev,bar_num) ((dev)->bar[bar_num >> 1].phys) +#define pci_resource_len(dev,bar_num) ((dev)->bar[bar_num >> 1].size) + +// i/o to registers + +static inline u64 readq(const volatile void __iomem *addr) +{ + //TODO: write atomic implementation of _IO_READ_QWORD and change mthca_doorbell.h + u64 val; + READ_REGISTER_BUFFER_ULONG((PULONG)(addr), (PULONG)&val, 2 ); + return val; +} + +static inline u32 readl(const volatile void __iomem *addr) +{ + return READ_REGISTER_ULONG((PULONG)(addr)); +} + +static inline u16 reads(const volatile void __iomem *addr) +{ + return READ_REGISTER_USHORT((PUSHORT)(addr)); +} + +static inline u8 readb(const volatile void __iomem *addr) +{ + return READ_REGISTER_UCHAR((PUCHAR)(addr)); +} + +#define __raw_readq readq +#define __raw_readl readl +#define __raw_reads reads +#define __raw_readb readb + +static inline void writeq(unsigned __int64 val, volatile void __iomem *addr) +{ + //TODO: write atomic implementation of _IO_WRITE_QWORD and change mthca_doorbell.h + WRITE_REGISTER_BUFFER_ULONG( (PULONG)(addr), (PULONG)&val, 2 ); +} + +static inline void writel(unsigned int val, volatile void __iomem *addr) +{ + WRITE_REGISTER_ULONG((PULONG)(addr),val); +} + +static inline void writes(unsigned short val, volatile void __iomem *addr) +{ + WRITE_REGISTER_USHORT((PUSHORT)(addr),val); +} + +static inline void writeb(unsigned char val, volatile void __iomem *addr) +{ + WRITE_REGISTER_UCHAR((PUCHAR)(addr),val); +} + +#define __raw_writeq writeq +#define __raw_writel writel +#define __raw_writes writes +#define __raw_writeb writeb + + diff --git a/branches/WOF2-3/hw/mlx4/kernel/inc/l2w_pcipool.h b/branches/WOF2-3/hw/mlx4/kernel/inc/l2w_pcipool.h new file mode 100644 index 00000000..fd17b8fb --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/inc/l2w_pcipool.h @@ -0,0 +1,102 @@ +#pragma once + +typedef struct pci_pool { + size_t size; + struct mlx4_dev * mdev; + char name [32]; + NPAGED_LOOKASIDE_LIST pool_hdr; +} pci_pool_t; + +// taken from dmapool.c + +/** +* pci_pool_create - Creates a pool of consistent memory blocks, for dma. +* @name: name of pool, for diagnostics +* @mdev: device that will be doing the DMA +* @size: size of the blocks in this pool. +* @align: alignment requirement for blocks; must be a power of two +* @allocation: returned blocks won't cross this boundary (or zero) +* Context: !in_interrupt() +* +* Returns a dma allocation pool with the requested characteristics, or +* null if one can't be created. Given one of these pools, dma_pool_alloc() +* may be used to allocate memory. Such memory will all have "consistent" +* DMA mappings, accessible by the device and its driver without using +* cache flushing primitives. The actual size of blocks allocated may be +* larger than requested because of alignment. +* +* If allocation is nonzero, objects returned from dma_pool_alloc() won't + * cross that size boundary. This is useful for devices which have + * addressing restrictions on individual DMA transfers, such as not crossing + * boundaries of 4KBytes. + */ + +pci_pool_t * +pci_pool_create (const char *name, struct pci_dev *pdev, + size_t size, size_t align, size_t allocation); + +/** + * dma_pool_alloc - get a block of consistent memory + * @pool: dma pool that will produce the block + * @mem_flags: GFP_* bitmask + * @handle: pointer to dma address of block + * + * This returns the kernel virtual address of a currently unused block, + * and reports its dma address through the handle. + * If such a memory block can't be allocated, null is returned. + */ +static inline void * +pci_pool_alloc (pci_pool_t *pool, int mem_flags, dma_addr_t *handle) +{ + PHYSICAL_ADDRESS pa; + void * ptr; + UNREFERENCED_PARAMETER(mem_flags); + + ASSERT( KeGetCurrentIrql() <= DISPATCH_LEVEL ); + + ptr = ExAllocateFromNPagedLookasideList( &pool->pool_hdr ); + if (ptr != NULL) { + pa = MmGetPhysicalAddress( ptr ); + // TODO: convert physical adress to dma one + handle->da = pa.QuadPart; + handle->va = ptr; + handle->sz = 0; /* not known here */ + } + return ptr; +} + + +/** +* dma_pool_free - put block back into dma pool +* @pool: the dma pool holding the block +* @vaddr: virtual address of block +* @dma: dma address of block +* +* Caller promises neither device nor driver will again touch this block +* unless it is first re-allocated. +*/ +static inline void +pci_pool_free (pci_pool_t *pool, void *vaddr, dma_addr_t dma) +{ + UNREFERENCED_PARAMETER(dma); + ASSERT( KeGetCurrentIrql() <= DISPATCH_LEVEL ); + ExFreeToNPagedLookasideList( &pool->pool_hdr, vaddr ); +} + + + +/** + * pci_pool_destroy - destroys a pool of dma memory blocks. + * @pool: dma pool that will be destroyed + * Context: !in_interrupt() + * + * Caller guarantees that no more memory from the pool is in use, + * and that nothing will try to use the pool after this call. + */ +static inline void +pci_pool_destroy (pci_pool_t *pool) +{ + ExDeleteNPagedLookasideList( &pool->pool_hdr ); + ExFreePool( pool); +} + diff --git a/branches/WOF2-3/hw/mlx4/kernel/inc/l2w_radix.h b/branches/WOF2-3/hw/mlx4/kernel/inc/l2w_radix.h new file mode 100644 index 00000000..b12c2d78 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/inc/l2w_radix.h @@ -0,0 +1,25 @@ +#pragma once + +#include + +struct radix_tree_root { + cl_map_t map; +}; + +int radix_tree_insert(struct radix_tree_root *root, + unsigned long index, void *item); + +void *radix_tree_lookup(struct radix_tree_root *root, + unsigned long index); + +void *radix_tree_delete(struct radix_tree_root *root, + unsigned long index); + + +cl_status_t radix_tree_create(struct radix_tree_root *root, + gfp_t gfp_mask); + +void radix_tree_destroy(struct radix_tree_root *root ); + +#define INIT_RADIX_TREE(root, mask) radix_tree_create(root, mask) + diff --git a/branches/WOF2-3/hw/mlx4/kernel/inc/l2w_spinlock.h b/branches/WOF2-3/hw/mlx4/kernel/inc/l2w_spinlock.h new file mode 100644 index 00000000..9e8cb07a --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/inc/l2w_spinlock.h @@ -0,0 +1,148 @@ +#pragma once + +#include + +#if 1 + +typedef cl_spinlock_t spinlock_t; + +static inline void spin_lock_init( + IN spinlock_t* const p_spinlock ) +{ + cl_spinlock_init( p_spinlock ); +} + +#define spin_lock cl_spinlock_acquire +#define spin_unlock cl_spinlock_release + +CL_INLINE void +spin_lock_dpc( + IN cl_spinlock_t* const p_spinlock ) +{ + ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); + KeAcquireSpinLockAtDpcLevel( &p_spinlock->lock ); +} + +CL_INLINE void +spin_unlock_dpc( + IN cl_spinlock_t* const p_spinlock ) +{ + ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); + KeReleaseSpinLockFromDpcLevel( &p_spinlock->lock ); +} + +#else +typedef struct spinlock { + KSPIN_LOCK lock; + KLOCK_QUEUE_HANDLE lockh; + KIRQL irql; +} spinlock_t; + + +static inline void spin_lock_init( + IN spinlock_t* const p_spinlock ) +{ + KeInitializeSpinLock( &p_spinlock->lock ); +} + +static inline void +spin_lock( + IN spinlock_t* const l) +{ + KIRQL irql = KeGetCurrentIrql(); + + ASSERT( l && irql <= DISPATCH_LEVEL ); + + if (irql == DISPATCH_LEVEL) + KeAcquireInStackQueuedSpinLockAtDpcLevel( &l->lock, &l->lockh ); + else + KeAcquireInStackQueuedSpinLock( &l->lock, &l->lockh ); + l->irql = irql; +} + +static inline void +spin_unlock( + IN spinlock_t* const l) +{ + ASSERT( l && KeGetCurrentIrql() == DISPATCH_LEVEL ); + if (l->irql == DISPATCH_LEVEL) + KeReleaseInStackQueuedSpinLockFromDpcLevel( &l->lockh ); + else + KeReleaseInStackQueuedSpinLock( &l->lockh ); +} + +/* to be used only at DPC level */ +static inline void +spin_lock_dpc( + IN spinlock_t* const l) +{ + ASSERT( l && KeGetCurrentIrql() == DISPATCH_LEVEL ); + KeAcquireInStackQueuedSpinLockAtDpcLevel( &l->lock, &l->lockh ); +} + +/* to be used only at DPC level */ +static inline void +spin_unlock_dpc( + IN spinlock_t* const l) +{ + ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); + KeReleaseInStackQueuedSpinLockFromDpcLevel( &l->lockh ); +} + +static inline void +spin_lock_sync( + IN spinlock_t* const l ) +{ + KLOCK_QUEUE_HANDLE lockh; + ASSERT( l && KeGetCurrentIrql() <= DISPATCH_LEVEL ); + KeAcquireInStackQueuedSpinLock ( &l->lock, &lockh ); + KeReleaseInStackQueuedSpinLock( &lockh ); +} + +#endif + +#define DEFINE_SPINLOCK(lock) spinlock_t lock + +static inline void +spin_lock_irqsave( + IN spinlock_t* const l, + IN unsigned long * flags) +{ + UNUSED_PARAM(flags); + spin_lock(l); +} + +static inline void +spin_unlock_irqrestore( + IN spinlock_t* const l, + IN unsigned long flags) +{ + UNUSED_PARAM(flags); + spin_unlock(l); +} + +static inline void +spin_lock_sync( + IN spinlock_t* const l ) +{ + KLOCK_QUEUE_HANDLE lockh; + ASSERT( l && KeGetCurrentIrql() <= DISPATCH_LEVEL ); + KeAcquireInStackQueuedSpinLock ( &l->lock, &lockh ); + KeReleaseInStackQueuedSpinLock( &lockh ); +} + +/* we are working from DPC level, so we can use usual spinlocks */ +#define spin_lock_irq spin_lock +#define spin_unlock_irq spin_unlock +#define spin_lock_nested(a,b) spin_lock(a) + +/* Windows doesn't support such kind of spinlocks so far, but may be tomorrow ... */ +#define rwlock_init spin_lock_init +#define read_lock_irqsave spin_lock_irqsave +#define read_unlock_irqrestore spin_unlock_irqrestore +#define write_lock_irq spin_lock_irq +#define write_unlock_irq spin_unlock_irq + +// rw_lock +typedef spinlock_t rwlock_t; + diff --git a/branches/WOF2-3/hw/mlx4/kernel/inc/l2w_sync.h b/branches/WOF2-3/hw/mlx4/kernel/inc/l2w_sync.h new file mode 100644 index 00000000..779af46b --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/inc/l2w_sync.h @@ -0,0 +1,165 @@ +#pragma once + +// literals +#ifndef LONG_MAX +#define LONG_MAX 2147483647L /* maximum (signed) long value */ +#endif + +#ifndef ULONG_MAX +#define ULONG_MAX 4294967295UL +#endif + +// +// mutex wrapper +// + +struct mutex +{ + KMUTEX m; +}; + +#define DEFINE_MUTEX(a) struct mutex a + +static inline void mutex_init( struct mutex * mutex ) +{ + KeInitializeMutex( &mutex->m, 0 ); +} + +static inline void mutex_lock( struct mutex * mutex ) +{ + NTSTATUS status; + int need_to_wait = 1; + + ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL); + while (need_to_wait) { + status = KeWaitForSingleObject( &mutex->m, Executive, KernelMode, FALSE, NULL ); + if (status == STATUS_SUCCESS) + break; + } +} + +static inline void mutex_unlock( struct mutex * mutex ) +{ + ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); + KeReleaseMutex( &mutex->m, FALSE ); +} + + +// +// semaphore wrapper +// + +struct semaphore +{ + KSEMAPHORE s; +}; + +static inline void sema_init( + IN struct semaphore *sem, + IN LONG cnt) +{ + ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); + KeInitializeSemaphore( &sem->s, cnt, cnt ); +} + +static inline void up( struct semaphore *sem ) +{ + ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); + KeReleaseSemaphore( &sem->s, 0, 1, FALSE ); +} +static inline void down( struct semaphore *sem ) +{ + NTSTATUS status; + int need_to_wait = 1; + + ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL); + while (need_to_wait) { + status = KeWaitForSingleObject( &sem->s, Executive, KernelMode, FALSE, NULL ); + if (status == STATUS_SUCCESS) + break; + } +} + + +// +// completion wrapper +// + +struct completion +{ + KEVENT event; + int done; +}; + +static inline void init_completion( struct completion * compl ) +{ + //TODO: ASSERT is temporary outcommented, because using of fast mutexes in CompLib + // cause working on APC_LEVEL + //ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); + KeInitializeEvent( &compl->event, NotificationEvent , FALSE ); + compl->done = 0; +} + +static inline int wait_for_completion_timeout( struct completion * compl, unsigned long timeout ) +{ + LARGE_INTEGER interval; + ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL); + interval.QuadPart = (-10)* (__int64)timeout; + return (int)KeWaitForSingleObject( &compl->event, Executive, KernelMode, FALSE, &interval ); +} + +static inline void wait_for_completion( struct completion * compl ) +{ + NTSTATUS status; + int need_to_wait = 1; + + ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL); + + while (need_to_wait) { + status = KeWaitForSingleObject( &compl->event, Executive, KernelMode, FALSE, NULL ); + if (status == STATUS_SUCCESS) + break; + } +} + + + +static inline void complete( struct completion * compl ) +{ + ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); + compl->done++; + KeSetEvent( &compl->event, 0, FALSE ); +} + +#ifdef USE_WDM_INTERRUPTS + +// +// IRQ wrapper +// + +void free_irq(struct mlx4_dev *dev); + +int request_irq( + IN struct mlx4_dev * dev, + IN PKSERVICE_ROUTINE isr, /* ISR */ + IN PVOID isr_ctx, /* ISR context */ + IN PKMESSAGE_SERVICE_ROUTINE misr, /* Message ISR */ + OUT PKINTERRUPT * int_obj /* interrupt object */ + ); + +#endif + +// +// various +// + +// TODO: Is it enough to wait at DPC level ? +// Maybe we need to use here KeSynchronizeExecution ? +static inline void synchronize_irq(unsigned int irq) +{ + UNUSED_PARAM(irq); + KeFlushQueuedDpcs(); +} + + + diff --git a/branches/WOF2-3/hw/mlx4/kernel/inc/l2w_time.h b/branches/WOF2-3/hw/mlx4/kernel/inc/l2w_time.h new file mode 100644 index 00000000..672b9547 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/inc/l2w_time.h @@ -0,0 +1,17 @@ +#pragma once + +// returns current time in usecs (u64) +#define jiffies cl_get_time_stamp() + +// jiffies is measured in usecs here! +#define msecs_to_jiffies(msecs) ((msecs)*1000) + +#define time_after(a,b) ((long)(b) - (long)(a) < 0) +#define time_before(a,b) time_after(b,a) + +#define time_after_eq(a,b) ((long)(a) - (long)(b) >= 0) +#define time_before_eq(a,b) time_after_eq(b,a) + +extern LARGE_INTEGER g_cmd_interval; +#define cond_resched() KeDelayExecutionThread( KernelMode, FALSE, &g_cmd_interval ) + diff --git a/branches/WOF2-3/hw/mlx4/kernel/inc/l2w_umem.h b/branches/WOF2-3/hw/mlx4/kernel/inc/l2w_umem.h new file mode 100644 index 00000000..682dcfdd --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/inc/l2w_umem.h @@ -0,0 +1,34 @@ +#pragma once + +#include "l2w_memory.h" +#include "iobuf.h" + +struct ib_umem { + struct ib_ucontext *p_uctx; + int page_size; + iobuf_t iobuf; + int iobuf_used; + void * secure_handle; +}; + + +void ib_umem_release(struct ib_umem *p_ib_umem); + +struct ib_umem *ib_umem_get(struct ib_ucontext *context, u64 addr, + size_t size, enum ib_access_flags access, boolean_t secure); + +int ib_umem_page_count(struct ib_umem *p_ib_umem); + +dma_addr_t ib_umem_get_dma(struct ib_umem *p_ib_umem); + +int ib_umem_map( + IN u64 va, + IN u64 size, + IN ib_access_t acc, + OUT PMDL *mdl, + OUT void **kva); + +void ib_umem_unmap( + IN PMDL p_mdl, + IN void *kva); + diff --git a/branches/WOF2-3/hw/mlx4/kernel/inc/mlx4_debug.h b/branches/WOF2-3/hw/mlx4/kernel/inc/mlx4_debug.h new file mode 100644 index 00000000..051a590c --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/inc/mlx4_debug.h @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: mlx4_debug.h 1936 2007-02-06 16:04:33Z sleybo $ + */ + + +#ifndef _MLX4_DEBUG_H_ +#define _MLX4_DEBUG_H_ + +#include +#define NTSTRSAFE_LIB +#include + + +#include "ev_log.h" + +extern unsigned int g_mlx4_dbg_level; +extern unsigned int g_mlx4_dbg_flags; +#define MAX_LOG_BUF_LEN 512 +extern WCHAR g_wlog_buf[ MAX_LOG_BUF_LEN ]; +extern UCHAR g_slog_buf[ MAX_LOG_BUF_LEN ]; +static void _build_str( const char * format, ... ) +{ + NTSTATUS status; + va_list p_arg; + va_start(p_arg, format); +// vsprintf((char *)g_slog_buf, format , p_arg); +// swprintf(g_wlog_buf, L"%S", g_slog_buf); + status = RtlStringCbVPrintfA((char *)g_slog_buf, sizeof(g_slog_buf), format , p_arg); + if (status) + goto end; + status = RtlStringCchPrintfW(g_wlog_buf, sizeof(g_wlog_buf)/sizeof(g_wlog_buf[0]), L"%S", g_slog_buf); + if (status) + goto end; +// vsnprintf_s((char *)g_slog_buf, sizeof(g_slog_buf), _TRUNCATE, format , p_arg); +// swprintf_s(g_wlog_buf, sizeof(g_wlog_buf), L"%S", g_slog_buf); +end: + va_end(p_arg); +} + +#define MLX4_PRINT_TO_EVENT_LOG(_obj_,_level_,_flag_,_msg_) \ + { \ + NTSTATUS event_id; \ + int __lvl = _level_; \ + switch (__lvl) { \ + case TRACE_LEVEL_FATAL: case TRACE_LEVEL_ERROR: event_id = EVENT_MLX4_ANY_ERROR; break; \ + case TRACE_LEVEL_WARNING: event_id = EVENT_MLX4_ANY_WARN; break; \ + default: event_id = EVENT_MLX4_ANY_INFO; break; \ + } \ + _build_str _msg_; \ + WriteEventLogEntryStr( _obj_, (ULONG)event_id, 0, 0, g_wlog_buf, 0, 0 ); \ + } + +#define MLX4_PRINT_EV_MDEV(_level_,_flag_,_msg_) \ + MLX4_PRINT_TO_EVENT_LOG(mdev->pdev->p_self_do,_level_,_flag_,_msg_) + + +#if defined(EVENT_TRACING) +// +// Software Tracing Definitions +// + +#define WPP_CONTROL_GUIDS \ + WPP_DEFINE_CONTROL_GUID(Mlx4BusCtlGuid,(E51BB6E2,914A,4e21,93C0,192F4801BBFF), \ + WPP_DEFINE_BIT( MLX4_DBG_DEV) \ + WPP_DEFINE_BIT( MLX4_DBG_PNP) \ + WPP_DEFINE_BIT( MLX4_DBG_INIT) \ + WPP_DEFINE_BIT( MLX4_DBG_MAD) \ + WPP_DEFINE_BIT( MLX4_DBG_PO) \ + WPP_DEFINE_BIT( MLX4_DBG_PD) \ + WPP_DEFINE_BIT( MLX4_DBG_CQ) \ + WPP_DEFINE_BIT( MLX4_DBG_QP) \ + WPP_DEFINE_BIT( MLX4_DBG_MEMORY) \ + WPP_DEFINE_BIT( MLX4_DBG_AV) \ + WPP_DEFINE_BIT( MLX4_DBG_SRQ) \ + WPP_DEFINE_BIT( MLX4_DBG_MCAST) \ + WPP_DEFINE_BIT( MLX4_DBG_LOW) \ + WPP_DEFINE_BIT( MLX4_DBG_SHIM) \ + WPP_DEFINE_BIT( MLX4_DBG_DRV) ) + + +#define WPP_GLOBALLOGGER + + +#define WPP_LEVEL_FLAGS_ENABLED(lvl, flags) (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= lvl) +#define WPP_LEVEL_FLAGS_LOGGER(lvl,flags) WPP_LEVEL_LOGGER(flags) +#define WPP_FLAG_ENABLED(flags)(WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= TRACE_LEVEL_VERBOSE) +#define WPP_FLAG_LOGGER(flags) WPP_LEVEL_LOGGER(flags) + + +// begin_wpp config +// MLX4_ENTER(FLAG); +// MLX4_EXIT(FLAG); +// USEPREFIX(MLX4_PRINT, "%!STDPREFIX! [MLX4_BUS] :%!FUNC!() :"); +// USESUFFIX(MLX4_ENTER, " [MLX4_BUS] :%!FUNC!()["); +// USESUFFIX(MLX4_EXIT, " [MLX4_BUS] :%!FUNC!()]"); +// end_wpp + + + +#define MLX4_PRINT_EV(_level_,_flag_,_msg_) \ + { \ + MLX4_PRINT_EV_MDEV(_level_,_flag_,_msg_) \ + } + + +#else + + +#include + +/* + * Debug macros + */ + + +#define MLX4_DBG_DEV (1 << 0) +#define MLX4_DBG_PNP (1<<1) +#define MLX4_DBG_INIT (1 << 2) +#define MLX4_DBG_MAD (1 << 3) +#define MLX4_DBG_PO (1 << 4) +#define MLX4_DBG_PD (1<<5) +#define MLX4_DBG_QP (1 << 6) +#define MLX4_DBG_CQ (1 << 7) +#define MLX4_DBG_MEMORY (1 << 8) +#define MLX4_DBG_AV (1<<9) +#define MLX4_DBG_SRQ (1 << 10) +#define MLX4_DBG_MCAST (1<<11) +#define MLX4_DBG_LOW (1 << 12) +#define MLX4_DBG_SHIM (1 << 13) +#define MLX4_DBG_DRV (1 << 14) + + +#if DBG + +// assignment of _level_ is need to to overcome warning C4127 +#define MLX4_PRINT(_level_,_flag_,_msg_) \ + { \ + uint32_t __lvl = _level_; \ + if (g_mlx4_dbg_level >= (uint32_t)(__lvl) && \ + (g_mlx4_dbg_flags & (_flag_))) { \ + cl_dbg_out ("~%d:[MLX4_BUS] %s() :", KeGetCurrentProcessorNumber(), __FUNCTION__); \ + if(__lvl == TRACE_LEVEL_ERROR) cl_dbg_out ("***ERROR*** "); \ + cl_dbg_out _msg_; \ + } \ + } + +#else + +#define MLX4_PRINT(lvl ,flags, msg) + +#endif + +#define MLX4_PRINT_EV(_level_,_flag_,_msg_) \ + { \ + MLX4_PRINT(_level_,_flag_,_msg_) \ + MLX4_PRINT_EV_MDEV(_level_,_flag_,_msg_) \ + } + +#define MLX4_ENTER(flags)\ + MLX4_PRINT(TRACE_LEVEL_VERBOSE, flags,("[\n")); + +#define MLX4_EXIT(flags)\ + MLX4_PRINT(TRACE_LEVEL_VERBOSE, flags, ("]\n" )); + + +#endif //EVENT_TRACING + + +#endif /*_MLX4_DEBUG_H_ */ + + + + diff --git a/branches/WOF2-3/hw/mlx4/kernel/inc/vc.h b/branches/WOF2-3/hw/mlx4/kernel/inc/vc.h new file mode 100644 index 00000000..bc90e926 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/inc/vc.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2004-2005 Mellanox Technologies, Inc. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: mthca_vc.h 1912 2007-01-17 11:08:02Z leonid $ + */ + +#pragma once + +#include + +typedef +struct _map_crspace { + unsigned __int64 va; /* address of CRSPACE, mapped to user space */ + unsigned long size; /* size of CRSPACE, mapped to user space */ + unsigned long reserved; /* to align on quadword boundary */ +} map_crspace; + +/* Definitions for hca_driver commands*/ +#define FW_READ 0x00 +#define FW_WRITE 0x01 +#define FW_READ_CMD 0x08 +#define FW_WRITE_CMD 0x09 +#define FW_MAP_CRSPACE 0x0A +#define FW_UNMAP_CRSPACE 0x0B +#define FW_OPEN_IF 0xe7 +#define FW_CLOSE_IF 0x7e + +/* MSI-X info */ +struct msix_info { + int valid; + int enabled; + int masked; + int requested; + int granted; + unsigned granted_mask; + unsigned pending_mask; +} ; + +#if 1 //WORKAROUND_POLL_EQ +#define FW_POLL_EQ_START 0x0D +#define FW_POLL_EQ_STOP 0x0E +#endif + +/* uplink info */ +typedef struct { + uint8_t bus_type; /* 1 - PCI, 2 - PCI-X, 3 - PCI_E */ +#define UPLINK_BUS_PCI 1 +#define UPLINK_BUS_PCIX 2 +#define UPLINK_BUS_PCIE 3 + union { + struct { + uint8_t capabilities; +#define UPLINK_BUS_PCIX_133 2 /* 133 MHz capable */ + uint16_t frequency; /* in MHz */ + } pci_x; + struct { + uint8_t capabilities; + uint8_t link_speed; /* 1X link speed */ +#define UPLINK_BUS_PCIE_SDR 1 /* 2.5 Gbps */ +#define UPLINK_BUS_PCIE_DDR 2 /* 5 Gbps */ + uint8_t link_width; /* x1, x2, x4, x8, x12, x16, x32 */ + } pci_e; + } u; + struct msix_info x; +} uplink_info_t; + + + diff --git a/branches/WOF2-3/hw/mlx4/kernel/inc/vip_dev.h b/branches/WOF2-3/hw/mlx4/kernel/inc/vip_dev.h new file mode 100644 index 00000000..c0a45b55 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel/inc/vip_dev.h @@ -0,0 +1,75 @@ +/*++ + +Copyright (c) 1999 Microsoft Corporation + +Module Name: + mtnic_dev.h + +Abstract: + define the essential structure that is common to mxe_bus and the connectx driver + +Revision History: + +Notes: + +--*/ + +#pragma once + +#pragma warning( disable : 4214) +#pragma warning( disable : 4324) +#include +#pragma warning( default : 4214) +#pragma warning( default : 4324) + + +#define MTNIC_MAX_PORTS 2 +#define MAX_MSIX_VECTORES 18 + +#define MXE_INTERFACE_VERSION 2 + +enum mtnic_state { + CARD_DOWN, + CARD_UP, + CARD_GOING_DOWN, + CARD_DISABLED +}; + +struct _MP_PORT; + +struct mlx4_en_eq_info { + struct VipBusIfc * pVipBusIfc; + struct mlx4_eq* eq; + u8 eq_number; + BOOLEAN fUseMsix; +}; + +typedef struct { + enum mtnic_state state; + KEVENT ConfigChangeEvent; + + // Objects that are needed in order to work with the hw + + u32 priv_pdn; + struct mlx4_uar priv_uar; + void __iomem *uar_map; + struct mlx4_mr mr; + spinlock_t* puar_lock; + + BOOLEAN use_msix; + struct mlx4_en_eq_info eq_info[MAX_MSIX_VECTORES]; +} NicData_t; + +struct VipBusIfc +{ + PVOID Context; + LONG NoOfConnectedPorts; + + NicData_t NicData; + + struct _MP_PORT *ports[MTNIC_MAX_PORTS]; + +}; + + + diff --git a/branches/WOF2-3/hw/mlx4/kernel_patches/core_0020_csum.patch b/branches/WOF2-3/hw/mlx4/kernel_patches/core_0020_csum.patch new file mode 100644 index 00000000..9b21e568 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel_patches/core_0020_csum.patch @@ -0,0 +1,51 @@ +From 11d392f57b2199f5c8071360ebf03c2fc6c4afb2 Mon Sep 17 00:00:00 2001 +From: Eli Cohen +Date: Tue, 15 Jan 2008 12:15:59 +0200 +Subject: [PATCH] Add checksum support to ib core + +Signed-off-by: Eli Cohen +--- + include/rdma/ib_verbs.h | 13 +++++++++++-- + 1 files changed, 11 insertions(+), 2 deletions(-) + +diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h +index 11f3960..e35cc29 100644 +--- a/include/rdma/ib_verbs.h ++++ b/include/rdma/ib_verbs.h +@@ -95,7 +95,14 @@ enum ib_device_cap_flags { + IB_DEVICE_N_NOTIFY_CQ = (1<<14), + IB_DEVICE_ZERO_STAG = (1<<15), + IB_DEVICE_SEND_W_INV = (1<<16), +- IB_DEVICE_MEM_WINDOW = (1<<17) ++ IB_DEVICE_MEM_WINDOW = (1<<17), ++ /* ++ * devices which publish this capability must support insertion of UDP ++ * and TCP checksum on outgoing packets and can verify the validity of ++ * checksum for incoming packets. Setting this flag implies the driver ++ * may set NETIF_F_IP_CSUM. ++ */ ++ IB_DEVICE_IP_CSUM = (1<<18), + }; + + enum ib_atomic_cap { +@@ -431,6 +438,7 @@ struct ib_wc { + u8 sl; + u8 dlid_path_bits; + u8 port_num; /* valid only for DR SMPs on switches */ ++ int csum_ok; + }; + + enum ib_cq_notify_flags { +@@ -615,7 +623,8 @@ enum ib_send_flags { + IB_SEND_FENCE = 1, + IB_SEND_SIGNALED = (1<<1), + IB_SEND_SOLICITED = (1<<2), +- IB_SEND_INLINE = (1<<3) ++ IB_SEND_INLINE = (1<<3), ++ IB_SEND_IP_CSUM = (1<<4) + }; + + struct ib_sge { +-- +1.5.3.8 + diff --git a/branches/WOF2-3/hw/mlx4/kernel_patches/core_0025_qp_create_flags.patch b/branches/WOF2-3/hw/mlx4/kernel_patches/core_0025_qp_create_flags.patch new file mode 100644 index 00000000..d5fff8ba --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel_patches/core_0025_qp_create_flags.patch @@ -0,0 +1,53 @@ +From a1d2b448a530a829c2ae3a896c0f2d3adc90a069 Mon Sep 17 00:00:00 2001 +From: Eli Cohen +Date: Tue, 15 Jan 2008 15:42:31 +0200 +Subject: [PATCH] Add creation flags to QPs + +This will allow a kernel verbs consumer to create a QP +and pass special flags to the hw layer. This patch also +defines one such flag for LSO support. + +Signed-off-by: Eli Cohen +--- + drivers/infiniband/core/uverbs_cmd.c | 1 + + include/rdma/ib_verbs.h | 5 +++++ + 2 files changed, 6 insertions(+), 0 deletions(-) + +diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c +index 495c803..9e98cec 100644 +--- a/drivers/infiniband/core/uverbs_cmd.c ++++ b/drivers/infiniband/core/uverbs_cmd.c +@@ -1065,6 +1065,7 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file, + attr.srq = srq; + attr.sq_sig_type = cmd.sq_sig_all ? IB_SIGNAL_ALL_WR : IB_SIGNAL_REQ_WR; + attr.qp_type = cmd.qp_type; ++ attr.create_flags = 0; + + attr.cap.max_send_wr = cmd.max_send_wr; + attr.cap.max_recv_wr = cmd.max_recv_wr; +diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h +index e35cc29..a4f6184 100644 +--- a/include/rdma/ib_verbs.h ++++ b/include/rdma/ib_verbs.h +@@ -494,6 +494,10 @@ enum ib_qp_type { + IB_QPT_RAW_ETY + }; + ++enum qp_create_flags { ++ QP_CREATE_LSO = 1 << 0, ++}; ++ + struct ib_qp_init_attr { + void (*event_handler)(struct ib_event *, void *); + void *qp_context; +@@ -504,6 +508,7 @@ struct ib_qp_init_attr { + enum ib_sig_type sq_sig_type; + enum ib_qp_type qp_type; + u8 port_num; /* special QP types only */ ++ enum qp_create_flags create_flags; + }; + + enum ib_rnr_timeout { +-- +1.5.3.8 + diff --git a/branches/WOF2-3/hw/mlx4/kernel_patches/core_0030_lso.patch b/branches/WOF2-3/hw/mlx4/kernel_patches/core_0030_lso.patch new file mode 100644 index 00000000..16a8e08c --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel_patches/core_0030_lso.patch @@ -0,0 +1,66 @@ +From 86a166b61efd6c040bd6d508a4179e3e15827ac0 Mon Sep 17 00:00:00 2001 +From: Eli Cohen +Date: Tue, 15 Jan 2008 15:48:20 +0200 +Subject: [PATCH] Add core support for LSO + +LSO allows to pass to the network driver SKBs with data larger +than MTU and let the HW fragment the packet to mss quantities. + +Signed-off-by: Eli Cohen +--- + include/rdma/ib_verbs.h | 11 +++++++++-- + 1 files changed, 9 insertions(+), 2 deletions(-) + +diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h +index a4f6184..6ef1729 100644 +--- a/include/rdma/ib_verbs.h ++++ b/include/rdma/ib_verbs.h +@@ -103,6 +103,7 @@ enum ib_device_cap_flags { + * may set NETIF_F_IP_CSUM. + */ + IB_DEVICE_IP_CSUM = (1<<18), ++ IB_DEVICE_TCP_TSO = (1<<19), + }; + + enum ib_atomic_cap { +@@ -410,6 +411,7 @@ enum ib_wc_opcode { + IB_WC_COMP_SWAP, + IB_WC_FETCH_ADD, + IB_WC_BIND_MW, ++ IB_WC_LSO, + /* + * Set value of IB_WC_RECV so consumers can test if a completion is a + * receive by testing (opcode & IB_WC_RECV). +@@ -621,7 +623,8 @@ enum ib_wr_opcode { + IB_WR_SEND_WITH_IMM, + IB_WR_RDMA_READ, + IB_WR_ATOMIC_CMP_AND_SWP, +- IB_WR_ATOMIC_FETCH_AND_ADD ++ IB_WR_ATOMIC_FETCH_AND_ADD, ++ IB_WR_LSO + }; + + enum ib_send_flags { +@@ -629,7 +632,8 @@ enum ib_send_flags { + IB_SEND_SIGNALED = (1<<1), + IB_SEND_SOLICITED = (1<<2), + IB_SEND_INLINE = (1<<3), +- IB_SEND_IP_CSUM = (1<<4) ++ IB_SEND_IP_CSUM = (1<<4), ++ IB_SEND_UDP_LSO = (1<<5) + }; + + struct ib_sge { +@@ -659,6 +663,9 @@ struct ib_send_wr { + } atomic; + struct { + struct ib_ah *ah; ++ void *header; ++ int hlen; ++ int mss; + u32 remote_qpn; + u32 remote_qkey; + u16 pkey_index; /* valid for GSI only */ +-- +1.5.3.8 + diff --git a/branches/WOF2-3/hw/mlx4/kernel_patches/mlx4_0010_add_wc.patch b/branches/WOF2-3/hw/mlx4/kernel_patches/mlx4_0010_add_wc.patch new file mode 100644 index 00000000..767bb269 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel_patches/mlx4_0010_add_wc.patch @@ -0,0 +1,312 @@ +IB/mlx4: set write-combining flag for userspace blueflame pages + +Supported on i386 and x86_64 for now. + +Signed-off-by: Michael S. Tsirkin + +diff --git a/drivers/infiniband/hw/mlx4/Makefile b/drivers/infiniband/hw/mlx4/Makefile +index 70f09c7..ce885a8 100644 +--- a/drivers/infiniband/hw/mlx4/Makefile ++++ b/drivers/infiniband/hw/mlx4/Makefile +@@ -1,3 +1,4 @@ + obj-$(CONFIG_MLX4_INFINIBAND) += mlx4_ib.o + + mlx4_ib-y := ah.o cq.o doorbell.o mad.o main.o mr.o qp.o srq.o ++mlx4_ib-y += wc.o +diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c +index 5128d95..f60a3cd 100644 +--- a/drivers/infiniband/hw/mlx4/main.c ++++ b/drivers/infiniband/hw/mlx4/main.c +@@ -42,6 +42,7 @@ + + #include "mlx4_ib.h" + #include "user.h" ++#include "wc.h" + + #define DRV_NAME "mlx4_ib" + #define DRV_VERSION "0.01" +@@ -375,7 +376,7 @@ static int mlx4_ib_mmap(struct ib_ucontext *context, struct vm_area_struct *vma) + return -EAGAIN; + } else if (vma->vm_pgoff == 1 && dev->dev->caps.bf_reg_size != 0) { + /* FIXME want pgprot_writecombine() for BlueFlame pages */ +- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); ++ vma->vm_page_prot = pgprot_wc(vma->vm_page_prot); + + if (io_remap_pfn_range(vma, vma->vm_start, + to_mucontext(context)->uar.pfn + +@@ -611,12 +612,14 @@ static struct mlx4_interface mlx4_ib_interface = { + + static int __init mlx4_ib_init(void) + { ++ mlx4_enable_wc(); + return mlx4_register_interface(&mlx4_ib_interface); + } + + static void __exit mlx4_ib_cleanup(void) + { + mlx4_unregister_interface(&mlx4_ib_interface); ++ mlx4_disable_wc(); + } + + module_init(mlx4_ib_init); +diff --git a/drivers/infiniband/hw/mlx4/wc.c b/drivers/infiniband/hw/mlx4/wc.c +new file mode 100644 +index 0000000..3747ab1 +--- /dev/null ++++ b/drivers/infiniband/hw/mlx4/wc.c +@@ -0,0 +1,206 @@ ++/* ++ * Copyright (c) 2006-2007 Mellanox Technologies. All rights reserved. ++ * ++ * This software is available to you under a choice of one of two ++ * licenses. You may choose to be licensed under the terms of the GNU ++ * General Public License (GPL) Version 2, available from the file ++ * COPYING in the main directory of this source tree, or the ++ * OpenIB.org BSD license below: ++ * ++ * Redistribution and use in source and binary forms, with or ++ * without modification, are permitted provided that the following ++ * conditions are met: ++ * ++ * - Redistributions of source code must retain the above ++ * copyright notice, this list of conditions and the following ++ * disclaimer. ++ * ++ * - Redistributions in binary form must reproduce the above ++ * copyright notice, this list of conditions and the following ++ * disclaimer in the documentation and/or other materials ++ * provided with the distribution. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS ++ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ++ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN ++ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ++ * SOFTWARE. ++ */ ++ ++#include ++#include "wc.h" ++ ++static u32 old_pat_lo[NR_CPUS] = {0}; ++static u32 old_pat_hi[NR_CPUS] = {0}; ++static unsigned int wc_enabled = 0; ++ ++#define MLX4_PAT_MASK (0xFFFFF8FF) ++#define MLX4_PAT_MOD (0x00000100) ++#define MLX4_WC_FLAGS (_PAGE_PWT) ++ ++#if defined(__i386__) || defined(__x86_64__) ++ ++#define X86_MSR_PAT_OFFSET 0x277 ++ ++/* Returns non-zero if we have a chipset write-combining problem */ ++static int have_wc_errata(void) ++{ ++ struct pci_dev *dev; ++ u8 rev; ++ ++ if ((dev = pci_get_class(PCI_CLASS_BRIDGE_HOST << 8, NULL)) != NULL) { ++ /* ++ * ServerWorks LE chipsets < rev 6 have problems with ++ * write-combining. ++ */ ++ if (dev->vendor == PCI_VENDOR_ID_SERVERWORKS && ++ dev->device == PCI_DEVICE_ID_SERVERWORKS_LE) { ++ pci_read_config_byte(dev, PCI_CLASS_REVISION, &rev); ++ if (rev <= 5) { ++ printk(KERN_INFO "ib_mlx4: Serverworks LE rev < 6" ++ " detected. Write-combining disabled.\n"); ++ pci_dev_put(dev); ++ return -ENOSYS; ++ } ++ } ++ /* Intel 450NX errata # 23. Non ascending cacheline evictions ++ to write combining memory may resulting in data corruption */ ++ if (dev->vendor == PCI_VENDOR_ID_INTEL && ++ dev->device == PCI_DEVICE_ID_INTEL_82451NX) { ++ printk(KERN_INFO "ib_mlx4: Intel 450NX MMC detected." ++ " Write-combining disabled.\n"); ++ pci_dev_put(dev); ++ return -ENOSYS; ++ } ++ pci_dev_put(dev); ++ } ++ return 0; ++} ++ ++static void rd_old_pat(void *err) ++{ ++ *(int *)err |= rdmsr_safe(X86_MSR_PAT_OFFSET, ++ &old_pat_lo[smp_processor_id()], ++ &old_pat_hi[smp_processor_id()]); ++} ++ ++static void wr_new_pat(void *err) ++{ ++ u32 new_pat_lo = (old_pat_lo[smp_processor_id()] & MLX4_PAT_MASK) | ++ MLX4_PAT_MOD; ++ ++ *(int *)err |= wrmsr_safe(X86_MSR_PAT_OFFSET, ++ new_pat_lo, ++ old_pat_hi[smp_processor_id()]); ++} ++ ++static void wr_old_pat(void *err) ++{ ++ *(int *)err |= wrmsr_safe(X86_MSR_PAT_OFFSET, ++ old_pat_lo[smp_processor_id()], ++ old_pat_hi[smp_processor_id()]); ++} ++ ++static int read_and_modify_pat(void) ++{ ++ int ret = 0; ++ ++ preempt_disable(); ++ rd_old_pat(&ret); ++ if (!ret) ++ smp_call_function(rd_old_pat, &ret, 1, 1); ++ if (ret) ++ goto out; ++ ++ wr_new_pat(&ret); ++ if (ret) ++ goto out; ++ ++ smp_call_function(wr_new_pat, &ret, 1, 1); ++ BUG_ON(ret); /* have inconsistent PAT state */ ++out: ++ preempt_enable(); ++ return ret; ++} ++ ++static int restore_pat(void) ++{ ++ int ret = 0; ++ ++ preempt_disable(); ++ wr_old_pat(&ret); ++ if (!ret) { ++ smp_call_function(wr_old_pat, &ret, 1, 1); ++ BUG_ON(ret); /* have inconsistent PAT state */ ++ } ++ ++ preempt_enable(); ++ return ret; ++} ++ ++int mlx4_enable_wc(void) ++{ ++ struct cpuinfo_x86 *c = &cpu_data(0); ++ int ret; ++ ++ if (wc_enabled) ++ return 0; ++ ++ if (!cpu_has(c, X86_FEATURE_MSR) || ++ !cpu_has(c, X86_FEATURE_PAT)) { ++ printk(KERN_INFO "ib_mlx4: WC not available" ++ " on this processor\n"); ++ return -ENOSYS; ++ } ++ ++ if (have_wc_errata()) ++ return -ENOSYS; ++ ++ if (!(ret = read_and_modify_pat())) ++ wc_enabled = 1; ++ else ++ printk(KERN_INFO "ib_mlx4: failed to enable WC\n"); ++ return ret ? -EIO : 0; ++} ++ ++void mlx4_disable_wc(void) ++{ ++ if (wc_enabled) { ++ if (!restore_pat()) ++ wc_enabled = 0; ++ else ++ printk(KERN_INFO "ib_mlx4: failed to disable WC\n"); ++ } ++} ++ ++pgprot_t pgprot_wc(pgprot_t _prot) ++{ ++ return wc_enabled ? __pgprot(pgprot_val(_prot) | MLX4_WC_FLAGS) : ++ pgprot_noncached(_prot); ++} ++ ++int mlx4_wc_enabled(void) ++{ ++ return wc_enabled; ++} ++ ++#else /* !(defined(__i386__) || defined(__x86_64__)) */ ++ ++int mlx4_enable_wc(void){ return 0; } ++void mlx4_disable_wc(void){} ++ ++pgprot_t pgprot_wc(pgprot_t _prot) ++{ ++ return pgprot_noncached(_prot); ++} ++ ++int mlx4_wc_enabled(void) ++{ ++ return 0; ++} ++ ++#endif ++ +diff --git a/drivers/infiniband/hw/mlx4/wc.h b/drivers/infiniband/hw/mlx4/wc.h +new file mode 100644 +index 0000000..70b891d +--- /dev/null ++++ b/drivers/infiniband/hw/mlx4/wc.h +@@ -0,0 +1,43 @@ ++/* ++ * Copyright (c) 2006-2007 Mellanox Technologies. All rights reserved. ++ * ++ * This software is available to you under a choice of one of two ++ * licenses. You may choose to be licensed under the terms of the GNU ++ * General Public License (GPL) Version 2, available from the file ++ * COPYING in the main directory of this source tree, or the ++ * OpenIB.org BSD license below: ++ * ++ * Redistribution and use in source and binary forms, with or ++ * without modification, are permitted provided that the following ++ * conditions are met: ++ * ++ * - Redistributions of source code must retain the above ++ * copyright notice, this list of conditions and the following ++ * disclaimer. ++ * ++ * - Redistributions in binary form must reproduce the above ++ * copyright notice, this list of conditions and the following ++ * disclaimer in the documentation and/or other materials ++ * provided with the distribution. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS ++ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ++ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN ++ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ++ * SOFTWARE. ++ */ ++ ++#ifndef mlx4_WC_H ++#define mlx4_WC_H ++ ++#include ++ ++int mlx4_enable_wc(void); ++void mlx4_disable_wc(void); ++int mlx4_wc_enabled(void); ++pgprot_t pgprot_wc(pgprot_t _prot); ++ ++#endif diff --git a/branches/WOF2-3/hw/mlx4/kernel_patches/mlx4_0030_checksum_offload.patch b/branches/WOF2-3/hw/mlx4/kernel_patches/mlx4_0030_checksum_offload.patch new file mode 100644 index 00000000..2df85b1d --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel_patches/mlx4_0030_checksum_offload.patch @@ -0,0 +1,125 @@ +From cb0f57646824cc986000cc2b8e36cf306f4cda18 Mon Sep 17 00:00:00 2001 +From: Eli Cohen +Date: Tue, 15 Jan 2008 14:47:39 +0200 +Subject: [PATCH] Add checksum offload support to mlx4 + +Signed-off-by: Eli Cohen +Signed-off-by: Ali Ayub +--- + drivers/infiniband/hw/mlx4/cq.c | 2 ++ + drivers/infiniband/hw/mlx4/main.c | 5 +++++ + drivers/infiniband/hw/mlx4/qp.c | 3 +++ + drivers/net/mlx4/fw.c | 3 +++ + include/linux/mlx4/cq.h | 4 ++-- + include/linux/mlx4/qp.h | 2 ++ + 6 files changed, 17 insertions(+), 2 deletions(-) + +Index: ofed_kernel/drivers/infiniband/hw/mlx4/cq.c +=================================================================== +--- ofed_kernel.orig/drivers/infiniband/hw/mlx4/cq.c 2008-01-24 12:01:00.000000000 +0200 ++++ ofed_kernel/drivers/infiniband/hw/mlx4/cq.c 2008-01-24 12:09:24.000000000 +0200 +@@ -314,6 +314,11 @@ static int mlx4_ib_poll_one(struct mlx4_ + int is_send; + int is_error; + u16 wqe_ctr; ++ __be32 status; ++ ++#define CSUM_MASK_BITS cpu_to_be32(0x13c00000) ++#define CSUM_VAL_BITS cpu_to_be32(0x10400000) ++#define CSUM_MASK2_BITS cpu_to_be32(0x0c000000) + + cqe = next_cqe_sw(cq); + if (!cqe) +@@ -431,6 +436,10 @@ static int mlx4_ib_poll_one(struct mlx4_ + wc->wc_flags |= be32_to_cpu(cqe->g_mlpath_rqpn) & 0x80000000 ? + IB_WC_GRH : 0; + wc->pkey_index = be32_to_cpu(cqe->immed_rss_invalid) & 0x7f; ++ status = cqe->ipoib_status; ++ wc->csum_ok = (status & CSUM_MASK_BITS) == CSUM_VAL_BITS && ++ (status & CSUM_MASK2_BITS) && ++ cqe->checksum == 0xffff; + } + + return 0; +Index: ofed_kernel/drivers/infiniband/hw/mlx4/main.c +=================================================================== +--- ofed_kernel.orig/drivers/infiniband/hw/mlx4/main.c 2008-01-24 12:01:17.000000000 +0200 ++++ ofed_kernel/drivers/infiniband/hw/mlx4/main.c 2008-01-24 12:03:18.000000000 +0200 +@@ -100,6 +100,8 @@ static int mlx4_ib_query_device(struct i + props->device_cap_flags |= IB_DEVICE_AUTO_PATH_MIG; + if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_UD_AV_PORT) + props->device_cap_flags |= IB_DEVICE_UD_AV_PORT_ENFORCE; ++ if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_IPOIB_CSUM) ++ props->device_cap_flags |= IB_DEVICE_IP_CSUM; + + props->vendor_id = be32_to_cpup((__be32 *) (out_mad->data + 36)) & + 0xffffff; +@@ -613,6 +615,9 @@ static void *mlx4_ib_add(struct mlx4_dev + ibdev->ib_dev.unmap_fmr = mlx4_ib_unmap_fmr; + ibdev->ib_dev.dealloc_fmr = mlx4_ib_fmr_dealloc; + ++ if (ibdev->dev->caps.flags & MLX4_DEV_CAP_FLAG_IPOIB_CSUM) ++ ibdev->ib_dev.flags |= IB_DEVICE_IP_CSUM; ++ + if (init_node_data(ibdev)) + goto err_map; + +Index: ofed_kernel/drivers/infiniband/hw/mlx4/qp.c +=================================================================== +--- ofed_kernel.orig/drivers/infiniband/hw/mlx4/qp.c 2008-01-24 12:01:00.000000000 +0200 ++++ ofed_kernel/drivers/infiniband/hw/mlx4/qp.c 2008-01-24 12:03:18.000000000 +0200 +@@ -1307,6 +1307,9 @@ int mlx4_ib_post_send(struct ib_qp *ibqp + cpu_to_be32(MLX4_WQE_CTRL_CQ_UPDATE) : 0) | + (wr->send_flags & IB_SEND_SOLICITED ? + cpu_to_be32(MLX4_WQE_CTRL_SOLICITED) : 0) | ++ ((wr->send_flags & IB_SEND_IP_CSUM) ? ++ cpu_to_be32(MLX4_WQE_CTRL_IP_CSUM | ++ MLX4_WQE_CTRL_TCP_UDP_CSUM) : 0) | + qp->sq_signal_bits; + + if (wr->opcode == IB_WR_SEND_WITH_IMM || +Index: ofed_kernel/drivers/net/mlx4/fw.c +=================================================================== +--- ofed_kernel.orig/drivers/net/mlx4/fw.c 2008-01-24 12:01:17.000000000 +0200 ++++ ofed_kernel/drivers/net/mlx4/fw.c 2008-01-24 12:03:18.000000000 +0200 +@@ -741,6 +741,9 @@ int mlx4_INIT_HCA(struct mlx4_dev *dev, + MLX4_PUT(inbox, (u8) (PAGE_SHIFT - 12), INIT_HCA_UAR_PAGE_SZ_OFFSET); + MLX4_PUT(inbox, param->log_uar_sz, INIT_HCA_LOG_UAR_SZ_OFFSET); + ++ if (dev->caps.flags & MLX4_DEV_CAP_FLAG_IPOIB_CSUM) ++ *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1 << 3); ++ + err = mlx4_cmd(dev, mailbox->dma, 0, 0, MLX4_CMD_INIT_HCA, 10000); + + if (err) +Index: ofed_kernel/include/linux/mlx4/cq.h +=================================================================== +--- ofed_kernel.orig/include/linux/mlx4/cq.h 2008-01-24 12:01:00.000000000 +0200 ++++ ofed_kernel/include/linux/mlx4/cq.h 2008-01-24 12:03:18.000000000 +0200 +@@ -45,11 +45,11 @@ struct mlx4_cqe { + u8 sl; + u8 reserved1; + __be16 rlid; +- u32 reserved2; ++ __be32 ipoib_status; + __be32 byte_cnt; + __be16 wqe_index; + __be16 checksum; +- u8 reserved3[3]; ++ u8 reserved2[3]; + u8 owner_sr_opcode; + }; + +Index: ofed_kernel/include/linux/mlx4/qp.h +=================================================================== +--- ofed_kernel.orig/include/linux/mlx4/qp.h 2008-01-24 12:01:00.000000000 +0200 ++++ ofed_kernel/include/linux/mlx4/qp.h 2008-01-24 12:03:18.000000000 +0200 +@@ -158,6 +158,8 @@ enum { + MLX4_WQE_CTRL_FENCE = 1 << 6, + MLX4_WQE_CTRL_CQ_UPDATE = 3 << 2, + MLX4_WQE_CTRL_SOLICITED = 1 << 1, ++ MLX4_WQE_CTRL_IP_CSUM = 1 << 4, ++ MLX4_WQE_CTRL_TCP_UDP_CSUM = 1 << 5, + }; + + struct mlx4_wqe_ctrl_seg { diff --git a/branches/WOF2-3/hw/mlx4/kernel_patches/mlx4_0045_qp_flags.patch b/branches/WOF2-3/hw/mlx4/kernel_patches/mlx4_0045_qp_flags.patch new file mode 100644 index 00000000..835b2911 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel_patches/mlx4_0045_qp_flags.patch @@ -0,0 +1,76 @@ +mlx4: Add creation flags to mlx4 QPs + +The core passes creation flags and mlx4 saves them for later +reference. + +rev 2: +changed flags field to int +moved setting flags to qp_create_common. + +Signed-off-by: Eli Cohen +Signed-off-by: Jack Morgenstein + +--- + +Index: ofed_kernel/drivers/infiniband/hw/mlx4/mlx4_ib.h +=================================================================== +--- ofed_kernel.orig/drivers/infiniband/hw/mlx4/mlx4_ib.h 2008-01-23 13:15:31.282457000 +0200 ++++ ofed_kernel/drivers/infiniband/hw/mlx4/mlx4_ib.h 2008-01-23 15:58:48.546092000 +0200 +@@ -110,6 +110,10 @@ struct mlx4_ib_wq { + unsigned tail; + }; + ++enum qp_flags { ++ MLX4_QP_LSO = 1 << 0 ++}; ++ + struct mlx4_ib_qp { + struct ib_qp ibqp; + struct mlx4_qp mqp; +@@ -133,6 +137,7 @@ struct mlx4_ib_qp { + u8 resp_depth; + u8 sq_no_prefetch; + u8 state; ++ int flags; + }; + + struct mlx4_ib_srq { +Index: ofed_kernel/drivers/infiniband/hw/mlx4/qp.c +=================================================================== +--- ofed_kernel.orig/drivers/infiniband/hw/mlx4/qp.c 2008-01-23 13:15:31.287456000 +0200 ++++ ofed_kernel/drivers/infiniband/hw/mlx4/qp.c 2008-01-23 16:00:38.734097000 +0200 +@@ -238,9 +238,13 @@ static int set_rq_size(struct mlx4_ib_de + return 0; + } + +-static int set_kernel_sq_size(struct mlx4_ib_dev *dev, struct ib_qp_cap *cap, +- enum ib_qp_type type, struct mlx4_ib_qp *qp) ++static int set_kernel_sq_size(struct mlx4_ib_dev *dev, ++ struct ib_qp_init_attr *init_attr, ++ struct mlx4_ib_qp *qp) + { ++ struct ib_qp_cap *cap = &init_attr->cap; ++ enum ib_qp_type type = init_attr->qp_type; ++ + /* Sanity check SQ size before proceeding */ + if (cap->max_send_wr > dev->dev->caps.max_wqes || + cap->max_send_sge > dev->dev->caps.max_sq_sg || +@@ -328,6 +332,9 @@ static int create_qp_common(struct mlx4_ + qp->sq.head = 0; + qp->sq.tail = 0; + ++ if (init_attr->create_flags & QP_CREATE_LSO) ++ qp->flags |= MLX4_QP_LSO; ++ + err = set_rq_size(dev, &init_attr->cap, !!pd->uobject, !!init_attr->srq, qp); + if (err) + goto err; +@@ -371,7 +378,7 @@ static int create_qp_common(struct mlx4_ + } else { + qp->sq_no_prefetch = 0; + +- err = set_kernel_sq_size(dev, &init_attr->cap, init_attr->qp_type, qp); ++ err = set_kernel_sq_size(dev, init_attr, qp); + if (err) + goto err; + diff --git a/branches/WOF2-3/hw/mlx4/kernel_patches/mlx4_0050_lso.patch b/branches/WOF2-3/hw/mlx4/kernel_patches/mlx4_0050_lso.patch new file mode 100644 index 00000000..f84b686d --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel_patches/mlx4_0050_lso.patch @@ -0,0 +1,249 @@ +From 33c5e1a802583cd84b55a4c5270e9d7753ac29bf Mon Sep 17 00:00:00 2001 +From: Eli Cohen +Date: Tue, 15 Jan 2008 18:57:09 +0200 +Subject: [PATCH] Add LSO support to mlx4 + +mlx4: Add LSO support. + +Changes: +Adjusted setting "reserve" value in set_kernel_sq_size to fit changes +in qp_flags patch. + +Signed-off-by: Eli Cohen +Signed-off-by: Jack Morgenstein + +--- + drivers/infiniband/hw/mlx4/cq.c | 3 ++ + drivers/infiniband/hw/mlx4/main.c | 4 +++ + drivers/infiniband/hw/mlx4/qp.c | 52 +++++++++++++++++++++++++++++++++--- + drivers/net/mlx4/fw.c | 9 ++++++ + drivers/net/mlx4/fw.h | 1 + + drivers/net/mlx4/main.c | 1 + + include/linux/mlx4/device.h | 1 + + include/linux/mlx4/qp.h | 5 +++ + 8 files changed, 71 insertions(+), 5 deletions(-) + +Index: ofed_kernel/drivers/infiniband/hw/mlx4/cq.c +=================================================================== +--- ofed_kernel.orig/drivers/infiniband/hw/mlx4/cq.c 2008-01-23 16:01:48.392614000 +0200 ++++ ofed_kernel/drivers/infiniband/hw/mlx4/cq.c 2008-01-23 16:05:20.076983000 +0200 +@@ -408,6 +408,9 @@ static int mlx4_ib_poll_one(struct mlx4_ + case MLX4_OPCODE_BIND_MW: + wc->opcode = IB_WC_BIND_MW; + break; ++ case MLX4_OPCODE_LSO: ++ wc->opcode = IB_WC_LSO; ++ break; + } + } else { + wc->byte_len = be32_to_cpu(cqe->byte_cnt); +Index: ofed_kernel/drivers/infiniband/hw/mlx4/main.c +=================================================================== +--- ofed_kernel.orig/drivers/infiniband/hw/mlx4/main.c 2008-01-23 16:01:48.398613000 +0200 ++++ ofed_kernel/drivers/infiniband/hw/mlx4/main.c 2008-01-23 16:05:20.081982000 +0200 +@@ -102,6 +102,8 @@ static int mlx4_ib_query_device(struct i + props->device_cap_flags |= IB_DEVICE_UD_AV_PORT_ENFORCE; + if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_IPOIB_CSUM) + props->device_cap_flags |= IB_DEVICE_IP_CSUM; ++ if (dev->dev->caps.max_gso_sz) ++ props->device_cap_flags |= IB_DEVICE_TCP_TSO; + + props->vendor_id = be32_to_cpup((__be32 *) (out_mad->data + 36)) & + 0xffffff; +@@ -617,6 +619,8 @@ static void *mlx4_ib_add(struct mlx4_dev + + if (ibdev->dev->caps.flags & MLX4_DEV_CAP_FLAG_IPOIB_CSUM) + ibdev->ib_dev.flags |= IB_DEVICE_IP_CSUM; ++ if (ibdev->dev->caps.max_gso_sz) ++ ibdev->ib_dev.flags |= IB_DEVICE_TCP_TSO; + + if (init_node_data(ibdev)) + goto err_map; +Index: ofed_kernel/drivers/infiniband/hw/mlx4/qp.c +=================================================================== +--- ofed_kernel.orig/drivers/infiniband/hw/mlx4/qp.c 2008-01-23 16:01:51.101506000 +0200 ++++ ofed_kernel/drivers/infiniband/hw/mlx4/qp.c 2008-01-23 16:08:04.078114000 +0200 +@@ -69,6 +69,7 @@ enum { + + static const __be32 mlx4_ib_opcode[] = { + [IB_WR_SEND] = __constant_cpu_to_be32(MLX4_OPCODE_SEND), ++ [IB_WR_LSO] = __constant_cpu_to_be32(MLX4_OPCODE_LSO), + [IB_WR_SEND_WITH_IMM] = __constant_cpu_to_be32(MLX4_OPCODE_SEND_IMM), + [IB_WR_RDMA_WRITE] = __constant_cpu_to_be32(MLX4_OPCODE_RDMA_WRITE), + [IB_WR_RDMA_WRITE_WITH_IMM] = __constant_cpu_to_be32(MLX4_OPCODE_RDMA_WRITE_IMM), +@@ -244,6 +245,7 @@ static int set_kernel_sq_size(struct mlx + { + struct ib_qp_cap *cap = &init_attr->cap; + enum ib_qp_type type = init_attr->qp_type; ++ int reserve = 0; + + /* Sanity check SQ size before proceeding */ + if (cap->max_send_wr > dev->dev->caps.max_wqes || +@@ -260,12 +262,16 @@ static int set_kernel_sq_size(struct mlx + cap->max_send_sge + 2 > dev->dev->caps.max_sq_sg) + return -EINVAL; + ++ if (qp->flags & MLX4_QP_LSO) ++ reserve = 64; ++ + qp->sq.wqe_shift = ilog2(roundup_pow_of_two(max(cap->max_send_sge * +- sizeof (struct mlx4_wqe_data_seg), ++ sizeof (struct mlx4_wqe_data_seg) + ++ reserve, + cap->max_inline_data + + sizeof (struct mlx4_wqe_inline_seg)) + + send_wqe_overhead(type))); +- qp->sq.max_gs = ((1 << qp->sq.wqe_shift) - send_wqe_overhead(type)) / ++ qp->sq.max_gs = ((1 << qp->sq.wqe_shift) -reserve - send_wqe_overhead(type)) / + sizeof (struct mlx4_wqe_data_seg); + + /* +@@ -756,9 +764,11 @@ static int __mlx4_ib_modify_qp(struct ib + } + } + +- if (ibqp->qp_type == IB_QPT_GSI || ibqp->qp_type == IB_QPT_SMI || +- ibqp->qp_type == IB_QPT_UD) ++ if (ibqp->qp_type == IB_QPT_GSI || ibqp->qp_type == IB_QPT_SMI) + context->mtu_msgmax = (IB_MTU_4096 << 5) | 11; ++ else if (ibqp->qp_type == IB_QPT_UD) ++ context->mtu_msgmax = (IB_MTU_4096 << 5) | ++ ilog2(dev->dev->caps.max_gso_sz); + else if (attr_mask & IB_QP_PATH_MTU) { + if (attr->path_mtu < IB_MTU_256 || attr->path_mtu > IB_MTU_4096) { + printk(KERN_ERR "path MTU (%u) is invalid\n", +@@ -1276,6 +1286,28 @@ static void __set_data_seg(struct mlx4_w + dseg->addr = cpu_to_be64(sg->addr); + } + ++static int build_lso_seg(struct mlx4_lso_seg *wqe, struct ib_send_wr *wr, ++ struct mlx4_ib_qp *qp, int *lso_seg_len) ++{ ++ int halign; ++ ++ halign = ALIGN(wr->wr.ud.hlen, 16); ++ if (unlikely(!(qp->flags & MLX4_QP_LSO) && wr->num_sge > qp->sq.max_gs - (halign >> 4))) ++ return -EINVAL; ++ ++ memcpy(wqe->header, wr->wr.ud.header, wr->wr.ud.hlen); ++ ++ /* make sure LSO header is written before ++ overwriting stamping */ ++ wmb(); ++ ++ wqe->mss_hdr_size = cpu_to_be32(((wr->wr.ud.mss - wr->wr.ud.hlen) ++ << 16) | wr->wr.ud.hlen); ++ ++ *lso_seg_len = halign; ++ return 0; ++} ++ + int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, + struct ib_send_wr **bad_wr) + { +@@ -1366,6 +1398,19 @@ int mlx4_ib_post_send(struct ib_qp *ibqp + set_datagram_seg(wqe, wr); + wqe += sizeof (struct mlx4_wqe_datagram_seg); + size += sizeof (struct mlx4_wqe_datagram_seg) / 16; ++ ++ if (wr->opcode == IB_WR_LSO) { ++ int hlen; ++ ++ err = build_lso_seg(wqe, wr, qp, &hlen); ++ if (err) { ++ *bad_wr = wr; ++ goto out; ++ } ++ wqe += hlen; ++ size += hlen >> 4; ++ } ++ + break; + + case IB_QPT_SMI: +Index: ofed_kernel/drivers/net/mlx4/fw.c +=================================================================== +--- ofed_kernel.orig/drivers/net/mlx4/fw.c 2008-01-23 16:01:48.430615000 +0200 ++++ ofed_kernel/drivers/net/mlx4/fw.c 2008-01-23 16:05:20.106981000 +0200 +@@ -133,6 +133,7 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev * + #define QUERY_DEV_CAP_MAX_AV_OFFSET 0x27 + #define QUERY_DEV_CAP_MAX_REQ_QP_OFFSET 0x29 + #define QUERY_DEV_CAP_MAX_RES_QP_OFFSET 0x2b ++#define QUERY_DEV_CAP_MAX_GSO_OFFSET 0x2d + #define QUERY_DEV_CAP_MAX_RDMA_OFFSET 0x2f + #define QUERY_DEV_CAP_RSZ_SRQ_OFFSET 0x33 + #define QUERY_DEV_CAP_ACK_DELAY_OFFSET 0x35 +@@ -215,6 +216,13 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev * + dev_cap->max_requester_per_qp = 1 << (field & 0x3f); + MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_RES_QP_OFFSET); + dev_cap->max_responder_per_qp = 1 << (field & 0x3f); ++ MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_GSO_OFFSET); ++ field &= 0x1f; ++ if (!field) ++ dev_cap->max_gso_sz = 0; ++ else ++ dev_cap->max_gso_sz = 1 << field; ++ + MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_RDMA_OFFSET); + dev_cap->max_rdma_global = 1 << (field & 0x3f); + MLX4_GET(field, outbox, QUERY_DEV_CAP_ACK_DELAY_OFFSET); +@@ -377,6 +385,7 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev * + dev_cap->max_sq_desc_sz, dev_cap->max_sq_sg); + mlx4_dbg(dev, "Max RQ desc size: %d, max RQ S/G: %d\n", + dev_cap->max_rq_desc_sz, dev_cap->max_rq_sg); ++ mlx4_dbg(dev, "Max GSO size: %d\n", dev_cap->max_gso_sz); + + dump_dev_cap_flags(dev, dev_cap->flags); + +Index: ofed_kernel/drivers/net/mlx4/fw.h +=================================================================== +--- ofed_kernel.orig/drivers/net/mlx4/fw.h 2008-01-23 15:58:48.837059000 +0200 ++++ ofed_kernel/drivers/net/mlx4/fw.h 2008-01-23 16:05:20.109984000 +0200 +@@ -96,6 +96,7 @@ struct mlx4_dev_cap { + u8 bmme_flags; + u32 reserved_lkey; + u64 max_icm_sz; ++ int max_gso_sz; + }; + + struct mlx4_adapter { +Index: ofed_kernel/drivers/net/mlx4/main.c +=================================================================== +--- ofed_kernel.orig/drivers/net/mlx4/main.c 2008-01-23 15:58:48.841058000 +0200 ++++ ofed_kernel/drivers/net/mlx4/main.c 2008-01-23 16:05:20.115981000 +0200 +@@ -159,6 +159,7 @@ static int mlx4_dev_cap(struct mlx4_dev + dev->caps.page_size_cap = ~(u32) (dev_cap->min_page_sz - 1); + dev->caps.flags = dev_cap->flags; + dev->caps.stat_rate_support = dev_cap->stat_rate_support; ++ dev->caps.max_gso_sz = dev_cap->max_gso_sz; + + return 0; + } +Index: ofed_kernel/include/linux/mlx4/device.h +=================================================================== +--- ofed_kernel.orig/include/linux/mlx4/device.h 2008-01-23 15:58:48.844060000 +0200 ++++ ofed_kernel/include/linux/mlx4/device.h 2008-01-23 16:05:20.138984000 +0200 +@@ -181,6 +181,7 @@ struct mlx4_caps { + u32 flags; + u16 stat_rate_support; + u8 port_width_cap[MLX4_MAX_PORTS + 1]; ++ int max_gso_sz; + }; + + struct mlx4_buf_list { +Index: ofed_kernel/include/linux/mlx4/qp.h +=================================================================== +--- ofed_kernel.orig/include/linux/mlx4/qp.h 2008-01-23 16:01:48.448613000 +0200 ++++ ofed_kernel/include/linux/mlx4/qp.h 2008-01-23 16:05:20.142981000 +0200 +@@ -215,6 +215,11 @@ struct mlx4_wqe_datagram_seg { + __be32 reservd[2]; + }; + ++struct mlx4_lso_seg { ++ __be32 mss_hdr_size; ++ __be32 header[0]; ++}; ++ + struct mlx4_wqe_bind_seg { + __be32 flags1; + __be32 flags2; diff --git a/branches/WOF2-3/hw/mlx4/kernel_patches/mlx4_0170_shrinking_wqe.patch b/branches/WOF2-3/hw/mlx4/kernel_patches/mlx4_0170_shrinking_wqe.patch new file mode 100644 index 00000000..588881bb --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/kernel_patches/mlx4_0170_shrinking_wqe.patch @@ -0,0 +1,509 @@ +commit 8e6b03bb781ee403e2aa3de9b9576ef42d919ce8 +commit c0aa89f0b295dd0c20b2ff2b1d2eca10cdc84f4b +Author: Michael S. Tsirkin +Date: Thu Aug 30 15:51:40 2007 +0300 + + IB/mlx4: shrinking WQE + + ConnectX supports shrinking wqe, such that a single WR can include + multiple units of wqe_shift. This way, WRs can differ in size, and + do not have to be a power of 2 in size, saving memory and speeding up + send WR posting. Unfortunately, if we do this wqe_index field in CQE + can't be used to look up the WR ID anymore, so do this only if + selective signalling is off. + + Further, on 32-bit platforms, we can't use vmap to make + the QP buffer virtually contigious. Thus we have to use + constant-sized WRs to make sure a WR is always fully within + a single page-sized chunk. + + Finally, we use WR with NOP opcode to avoid wrap-around + in the middle of WR. We set NoErrorCompletion bit to avoid getting + completions with error for NOP WRs. Since NEC is only supported + starting with firmware 2.2.232, we use constant-sized WRs + for older firmware. And, since MLX QPs only support SEND, we use + constant-sized WRs in this case. + + When stamping during NOP posting, do stamping following setting of + the NOP wqe valid bit. + + Signed-off-by: Michael S. Tsirkin + Signed-off-by: Jack Morgenstein + +commit 8e6b03bb781ee403e2aa3de9b9576ef42d919ce8 +commit c0aa89f0b295dd0c20b2ff2b1d2eca10cdc84f4b +Author: Michael S. Tsirkin +Date: Thu Aug 30 15:51:40 2007 +0300 + + IB/mlx4: shrinking WQE + + ConnectX supports shrinking wqe, such that a single WR can include + multiple units of wqe_shift. This way, WRs can differ in size, and + do not have to be a power of 2 in size, saving memory and speeding up + send WR posting. Unfortunately, if we do this wqe_index field in CQE + can't be used to look up the WR ID anymore, so do this only if + selective signalling is off. + + Further, on 32-bit platforms, we can't use vmap to make + the QP buffer virtually contigious. Thus we have to use + constant-sized WRs to make sure a WR is always fully within + a single page-sized chunk. + + Finally, we use WR with NOP opcode to avoid wrap-around + in the middle of WR. We set NoErrorCompletion bit to avoid getting + completions with error for NOP WRs. Since NEC is only supported + starting with firmware 2.2.232, we use constant-sized WRs + for older firmware. And, since MLX QPs only support SEND, we use + constant-sized WRs in this case. + + When stamping during NOP posting, do stamping following setting of + the NOP wqe valid bit. + + Signed-off-by: Michael S. Tsirkin + Signed-off-by: Jack Morgenstein + +Index: ofed_kernel-2.6.16_sles10/drivers/infiniband/hw/mlx4/cq.c +=================================================================== +--- ofed_kernel-2.6.16_sles10.orig/drivers/infiniband/hw/mlx4/cq.c 2008-01-22 13:19:40.000000000 +0200 ++++ ofed_kernel-2.6.16_sles10/drivers/infiniband/hw/mlx4/cq.c 2008-01-22 13:20:13.000000000 +0200 +@@ -353,6 +353,12 @@ static int mlx4_ib_poll_one(struct mlx4_ + is_error = (cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) == + MLX4_CQE_OPCODE_ERROR; + ++ if (unlikely((cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) == MLX4_OPCODE_NOP && ++ is_send)) { ++ printk(KERN_WARNING "Completion for NOP opcode detected!\n"); ++ return -EINVAL; ++ } ++ + if ((be32_to_cpu(cqe->my_qpn) & (1 << 23)) && !is_send) { + /* + * We do not have to take the XRC SRQ table lock here, +@@ -391,8 +397,10 @@ static int mlx4_ib_poll_one(struct mlx4_ + + if (is_send) { + wq = &(*cur_qp)->sq; +- wqe_ctr = be16_to_cpu(cqe->wqe_index); +- wq->tail += (u16) (wqe_ctr - (u16) wq->tail); ++ if (!(*cur_qp)->sq_signal_bits) { ++ wqe_ctr = be16_to_cpu(cqe->wqe_index); ++ wq->tail += (u16) (wqe_ctr - (u16) wq->tail); ++ } + wc->wr_id = wq->wrid[wq->tail & (wq->wqe_cnt - 1)]; + ++wq->tail; + } else if (is_xrc_recv) { +Index: ofed_kernel-2.6.16_sles10/drivers/infiniband/hw/mlx4/mlx4_ib.h +=================================================================== +--- ofed_kernel-2.6.16_sles10.orig/drivers/infiniband/hw/mlx4/mlx4_ib.h 2008-01-22 13:19:40.000000000 +0200 ++++ ofed_kernel-2.6.16_sles10/drivers/infiniband/hw/mlx4/mlx4_ib.h 2008-01-22 13:20:13.000000000 +0200 +@@ -136,6 +136,8 @@ struct mlx4_ib_qp { + + u32 doorbell_qpn; + __be32 sq_signal_bits; ++ unsigned sq_next_wqe; ++ int sq_max_wqes_per_wr; + int sq_spare_wqes; + struct mlx4_ib_wq sq; + +Index: ofed_kernel-2.6.16_sles10/drivers/infiniband/hw/mlx4/qp.c +=================================================================== +--- ofed_kernel-2.6.16_sles10.orig/drivers/infiniband/hw/mlx4/qp.c 2008-01-22 13:19:40.000000000 +0200 ++++ ofed_kernel-2.6.16_sles10/drivers/infiniband/hw/mlx4/qp.c 2008-01-22 13:31:45.000000000 +0200 +@@ -30,6 +30,7 @@ + * SOFTWARE. + */ + ++#include + #include + #include + +@@ -97,7 +98,7 @@ static int is_qp0(struct mlx4_ib_dev *de + + static void *get_wqe(struct mlx4_ib_qp *qp, int offset) + { +- if (qp->buf.nbufs == 1) ++ if (BITS_PER_LONG == 64 || qp->buf.nbufs == 1) + return qp->buf.u.direct.buf + offset; + else + return qp->buf.u.page_list[offset >> PAGE_SHIFT].buf + +@@ -116,16 +117,88 @@ static void *get_send_wqe(struct mlx4_ib + + /* + * Stamp a SQ WQE so that it is invalid if prefetched by marking the +- * first four bytes of every 64 byte chunk with 0xffffffff, except for +- * the very first chunk of the WQE. ++ * first four bytes of every 64 byte chunk with ++ * 0x7FFFFFF | (invalid_ownership_value << 31). ++ * ++ * When max WR is than or equal to the WQE size, ++ * as an optimization, we can stamp WQE with 0xffffffff, ++ * and skip the very first chunk of the WQE. + */ +-static void stamp_send_wqe(struct mlx4_ib_qp *qp, int n) ++static void stamp_send_wqe(struct mlx4_ib_qp *qp, int n, int size) + { +- u32 *wqe = get_send_wqe(qp, n); ++ u32 *wqe; + int i; ++ int s; ++ int ind; ++ void *buf; ++ __be32 stamp; ++ ++ s = roundup(size, 1 << qp->sq.wqe_shift); ++ if (qp->sq_max_wqes_per_wr > 1) { ++ for (i = 0; i < s; i += 64) { ++ ind = (i >> qp->sq.wqe_shift) + n; ++ stamp = ind & qp->sq.wqe_cnt ? cpu_to_be32(0x7fffffff) : ++ cpu_to_be32(0xffffffff); ++ buf = get_send_wqe(qp, ind & (qp->sq.wqe_cnt - 1)); ++ wqe = buf + (i & ((1 << qp->sq.wqe_shift) - 1)); ++ *wqe = stamp; ++ } ++ } else { ++ buf = get_send_wqe(qp, n & (qp->sq.wqe_cnt - 1)); ++ for (i = 64; i < s; i += 64) { ++ wqe = buf + i; ++ *wqe = 0xffffffff; ++ } ++ } ++} ++ ++static void post_nop_wqe(struct mlx4_ib_qp *qp, int n, int size) ++{ ++ struct mlx4_wqe_ctrl_seg *ctrl; ++ struct mlx4_wqe_inline_seg *inl; ++ void *wqe; ++ int s; ++ ++ ctrl = wqe = get_send_wqe(qp, n & (qp->sq.wqe_cnt - 1)); ++ s = sizeof(struct mlx4_wqe_ctrl_seg); ++ ++ if (qp->ibqp.qp_type == IB_QPT_UD) { ++ struct mlx4_wqe_datagram_seg *dgram = wqe + sizeof *ctrl; ++ struct mlx4_av *av = (struct mlx4_av *)dgram->av; ++ memset(dgram, 0, sizeof *dgram); ++ av->port_pd = cpu_to_be32((qp->port << 24) | to_mpd(qp->ibqp.pd)->pdn); ++ s += sizeof(struct mlx4_wqe_datagram_seg); ++ } ++ ++ /* Pad the remainder of the WQE with an inline data segment. */ ++ if (size > s) { ++ inl = wqe + s; ++ inl->byte_count = cpu_to_be32(1 << 31 | (size - s - sizeof *inl)); ++ } ++ ctrl->srcrb_flags = 0; ++ ctrl->fence_size = size / 16; ++ /* ++ * Make sure descriptor is fully written before ++ * setting ownership bit (because HW can start ++ * executing as soon as we do). ++ */ ++ wmb(); + +- for (i = 16; i < 1 << (qp->sq.wqe_shift - 2); i += 16) +- wqe[i] = 0xffffffff; ++ ctrl->owner_opcode = cpu_to_be32(MLX4_OPCODE_NOP | MLX4_WQE_CTRL_NEC) | ++ (n & qp->sq.wqe_cnt ? cpu_to_be32(1 << 31) : 0); ++ ++ stamp_send_wqe(qp, n + qp->sq_spare_wqes, size); ++} ++ ++/* Post NOP WQE to prevent wrap-around in the middle of WR */ ++static inline unsigned pad_wraparound(struct mlx4_ib_qp *qp, int ind) ++{ ++ unsigned s = qp->sq.wqe_cnt - (ind & (qp->sq.wqe_cnt - 1)); ++ if (unlikely(s < qp->sq_max_wqes_per_wr)) { ++ post_nop_wqe(qp, ind, s << qp->sq.wqe_shift); ++ ind += s; ++ } ++ return ind; + } + + static void mlx4_ib_qp_event(struct mlx4_qp *qp, enum mlx4_event type) +@@ -258,6 +331,7 @@ static int set_kernel_sq_size(struct mlx + { + struct ib_qp_cap *cap = &init_attr->cap; + enum ib_qp_type type = init_attr->qp_type; ++ int s; + int reserve = 0; + + /* Sanity check SQ size before proceeding */ +@@ -281,22 +355,69 @@ static int set_kernel_sq_size(struct mlx + reserve = 64; + } + +- qp->sq.wqe_shift = ilog2(roundup_pow_of_two(max(cap->max_send_sge * +- sizeof (struct mlx4_wqe_data_seg) + +- reserve, +- cap->max_inline_data + +- sizeof (struct mlx4_wqe_inline_seg)) + +- send_wqe_overhead(type))); +- qp->sq.wqe_shift = max(MLX4_IB_SQ_MIN_WQE_SHIFT, qp->sq.wqe_shift); +- qp->sq.max_gs = ((1 << qp->sq.wqe_shift) -reserve - send_wqe_overhead(type)) / +- sizeof (struct mlx4_wqe_data_seg); ++ s = max(cap->max_send_sge * sizeof (struct mlx4_wqe_data_seg) + reserve, ++ cap->max_inline_data + sizeof (struct mlx4_wqe_inline_seg)) + ++ send_wqe_overhead(type); + + /* +- * We need to leave 2 KB + 1 WQE of headroom in the SQ to +- * allow HW to prefetch. ++ * Hermon supports shrinking wqe, such that a single WR can include ++ * multiple units of wqe_shift. This way, WRs can differ in size, and ++ * do not have to be a power of 2 in size, saving memory and speeding up ++ * send WR posting. Unfortunately, if we do this wqe_index field in CQE ++ * can't be used to look up the WR ID anymore, so do this only if ++ * selective signalling is off. ++ * ++ * Further, on 32-bit platforms, we can't use vmap to make ++ * the QP buffer virtually contigious. Thus we have to use ++ * constant-sized WRs to make sure a WR is always fully within ++ * a single page-sized chunk. ++ * ++ * Finally, we use NOP opcode to avoid wrap-around in the middle of WR. ++ * We set NEC bit to avoid getting completions with error for NOP WRs. ++ * Since NEC is only supported starting with firmware 2.2.232, ++ * we use constant-sized WRs for older firmware. ++ * ++ * And, since MLX QPs only support SEND, we use constant-sized WRs in this ++ * case. ++ * ++ * We look for the smallest value of wqe_shift such that the resulting ++ * number of wqes does not exceed device capabilities. ++ * ++ * We set WQE size to at least 64 bytes, this way stamping invalidates each WQE. + */ +- qp->sq_spare_wqes = MLX4_IB_SQ_HEADROOM(qp->sq.wqe_shift); +- qp->sq.wqe_cnt = roundup_pow_of_two(cap->max_send_wr + qp->sq_spare_wqes); ++ if (dev->dev->caps.fw_ver >= MLX4_FW_VER_WQE_CTRL_NEC && ++ qp->sq_signal_bits && BITS_PER_LONG == 64 && ++ type != IB_QPT_SMI && type != IB_QPT_GSI) ++ qp->sq.wqe_shift = ilog2(64); ++ else ++ qp->sq.wqe_shift = ilog2(roundup_pow_of_two(s)); ++ ++ for (;;) { ++ if (1 << qp->sq.wqe_shift > dev->dev->caps.max_sq_desc_sz) ++ return -EINVAL; ++ ++ qp->sq_max_wqes_per_wr = DIV_ROUND_UP(s, 1 << qp->sq.wqe_shift); ++ ++ /* ++ * We need to leave 2 KB + 1 WR of headroom in the SQ to ++ * allow HW to prefetch. ++ */ ++ qp->sq_spare_wqes = (2048 >> qp->sq.wqe_shift) + qp->sq_max_wqes_per_wr; ++ qp->sq.wqe_cnt = roundup_pow_of_two(cap->max_send_wr * ++ qp->sq_max_wqes_per_wr + ++ qp->sq_spare_wqes); ++ ++ if (qp->sq.wqe_cnt <= dev->dev->caps.max_wqes) ++ break; ++ ++ if (qp->sq_max_wqes_per_wr <= 1) ++ return -EINVAL; ++ ++ ++qp->sq.wqe_shift; ++ } ++ ++ qp->sq.max_gs = ((qp->sq_max_wqes_per_wr << qp->sq.wqe_shift) - reserve - ++ send_wqe_overhead(type)) / sizeof (struct mlx4_wqe_data_seg); + + qp->buf_size = (qp->rq.wqe_cnt << qp->rq.wqe_shift) + + (qp->sq.wqe_cnt << qp->sq.wqe_shift); +@@ -309,8 +430,7 @@ static int set_kernel_sq_size(struct mlx + } + + cap->max_send_wr = qp->sq.max_post = +- min(qp->sq.wqe_cnt - qp->sq_spare_wqes, +- dev->dev->caps.max_wqes - MLX4_IB_SQ_MAX_SPARE); ++ (qp->sq.wqe_cnt - qp->sq_spare_wqes) / qp->sq_max_wqes_per_wr; + cap->max_send_sge =min(qp->sq.max_gs, + min(dev->dev->caps.max_sq_sg, + dev->dev->caps.max_rq_sg)); +@@ -360,6 +480,12 @@ static int create_qp_common(struct mlx4_ + qp->rq.tail = 0; + qp->sq.head = 0; + qp->sq.tail = 0; ++ qp->sq_next_wqe = 0; ++ ++ if (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR) ++ qp->sq_signal_bits = cpu_to_be32(MLX4_WQE_CTRL_CQ_UPDATE); ++ else ++ qp->sq_signal_bits = 0; + + err = set_rq_size(dev, &init_attr->cap, !!pd->uobject, + !!init_attr->srq || !!init_attr->xrc_domain , qp); +@@ -454,11 +580,6 @@ static int create_qp_common(struct mlx4_ + */ + qp->doorbell_qpn = swab32(qp->mqp.qpn << 8); + +- if (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR) +- qp->sq_signal_bits = cpu_to_be32(MLX4_WQE_CTRL_CQ_UPDATE); +- else +- qp->sq_signal_bits = 0; +- + qp->mqp.event = mlx4_ib_qp_event; + + return 0; +@@ -969,7 +1090,7 @@ static int __mlx4_ib_modify_qp(struct ib + ctrl = get_send_wqe(qp, i); + ctrl->owner_opcode = cpu_to_be32(1 << 31); + +- stamp_send_wqe(qp, i); ++ stamp_send_wqe(qp, i, 1 << qp->sq.wqe_shift); + } + } + +@@ -1022,6 +1143,7 @@ static int __mlx4_ib_modify_qp(struct ib + qp->rq.tail = 0; + qp->sq.head = 0; + qp->sq.tail = 0; ++ qp->sq_next_wqe = 0; + if (!ibqp->srq && ibqp->qp_type != IB_QPT_XRC) + *qp->db.db = 0; + } +@@ -1356,13 +1478,14 @@ int mlx4_ib_post_send(struct ib_qp *ibqp + unsigned long flags; + int nreq; + int err = 0; +- int ind; +- int size; ++ unsigned ind; ++ int uninitialized_var(stamp); ++ int uninitialized_var(size); + int i; + + spin_lock_irqsave(&qp->sq.lock, flags); + +- ind = qp->sq.head; ++ ind = qp->sq_next_wqe; + + for (nreq = 0; wr; ++nreq, wr = wr->next) { + if (mlx4_wq_overflow(&qp->sq, nreq, qp->ibqp.send_cq)) { +@@ -1378,7 +1501,7 @@ int mlx4_ib_post_send(struct ib_qp *ibqp + } + + ctrl = wqe = get_send_wqe(qp, ind & (qp->sq.wqe_cnt - 1)); +- qp->sq.wrid[ind & (qp->sq.wqe_cnt - 1)] = wr->wr_id; ++ qp->sq.wrid[(qp->sq.head + nreq) & (qp->sq.wqe_cnt - 1)] = wr->wr_id; + + ctrl->srcrb_flags = + (wr->send_flags & IB_SEND_SIGNALED ? +@@ -1511,16 +1634,23 @@ int mlx4_ib_post_send(struct ib_qp *ibqp + ctrl->owner_opcode = mlx4_ib_opcode[wr->opcode] | + (ind & qp->sq.wqe_cnt ? cpu_to_be32(1 << 31) : 0); + ++ stamp = ind + qp->sq_spare_wqes; ++ ind += DIV_ROUND_UP(size * 16, 1 << qp->sq.wqe_shift); ++ + /* + * We can improve latency by not stamping the last + * send queue WQE until after ringing the doorbell, so + * only stamp here if there are still more WQEs to post. ++ * ++ * Same optimization applies to padding with NOP wqe ++ * in case of WQE shrinking (used to prevent wrap-around ++ * in the middle of WR). + */ +- if (wr->next) +- stamp_send_wqe(qp, (ind + qp->sq_spare_wqes) & +- (qp->sq.wqe_cnt - 1)); ++ if (wr->next) { ++ stamp_send_wqe(qp, stamp, size * 16); ++ ind = pad_wraparound(qp, ind); ++ } + +- ++ind; + } + + out: +@@ -1542,8 +1672,10 @@ out: + */ + mmiowb(); + +- stamp_send_wqe(qp, (ind + qp->sq_spare_wqes - 1) & +- (qp->sq.wqe_cnt - 1)); ++ stamp_send_wqe(qp, stamp, size * 16); ++ ++ ind = pad_wraparound(qp, ind); ++ qp->sq_next_wqe = ind; + } + + spin_unlock_irqrestore(&qp->sq.lock, flags); +Index: ofed_kernel-2.6.16_sles10/drivers/net/mlx4/alloc.c +=================================================================== +--- ofed_kernel-2.6.16_sles10.orig/drivers/net/mlx4/alloc.c 2008-01-22 13:19:40.000000000 +0200 ++++ ofed_kernel-2.6.16_sles10/drivers/net/mlx4/alloc.c 2008-01-22 13:20:13.000000000 +0200 +@@ -152,6 +152,19 @@ int mlx4_buf_alloc(struct mlx4_dev *dev, + + memset(buf->u.page_list[i].buf, 0, PAGE_SIZE); + } ++ ++ if (BITS_PER_LONG == 64) { ++ struct page **pages; ++ pages = kmalloc(sizeof *pages * buf->nbufs, GFP_KERNEL); ++ if (!pages) ++ goto err_free; ++ for (i = 0; i < buf->nbufs; ++i) ++ pages[i] = virt_to_page(buf->u.page_list[i].buf); ++ buf->u.direct.buf = vmap(pages, buf->nbufs, VM_MAP, PAGE_KERNEL); ++ kfree(pages); ++ if (!buf->u.direct.buf) ++ goto err_free; ++ } + } + + return 0; +@@ -171,6 +184,9 @@ void mlx4_buf_free(struct mlx4_dev *dev, + dma_free_coherent(&dev->pdev->dev, size, buf->u.direct.buf, + buf->u.direct.map); + else { ++ if (BITS_PER_LONG == 64) ++ vunmap(buf->u.direct.buf); ++ + for (i = 0; i < buf->nbufs; ++i) + if (buf->u.page_list[i].buf) + dma_free_coherent(&dev->pdev->dev, PAGE_SIZE, +Index: ofed_kernel-2.6.16_sles10/include/linux/mlx4/device.h +=================================================================== +--- ofed_kernel-2.6.16_sles10.orig/include/linux/mlx4/device.h 2008-01-22 13:19:40.000000000 +0200 ++++ ofed_kernel-2.6.16_sles10/include/linux/mlx4/device.h 2008-01-22 13:20:13.000000000 +0200 +@@ -134,6 +134,11 @@ enum { + MLX4_STAT_RATE_OFFSET = 5 + }; + ++static inline u64 mlx4_fw_ver(u64 major, u64 minor, u64 subminor) ++{ ++ return (major << 32) | (minor << 16) | subminor; ++} ++ + struct mlx4_caps { + u64 fw_ver; + int num_ports; +@@ -193,7 +198,7 @@ struct mlx4_buf_list { + }; + + struct mlx4_buf { +- union { ++ struct { + struct mlx4_buf_list direct; + struct mlx4_buf_list *page_list; + } u; +Index: ofed_kernel-2.6.16_sles10/include/linux/mlx4/qp.h +=================================================================== +--- ofed_kernel-2.6.16_sles10.orig/include/linux/mlx4/qp.h 2008-01-22 13:19:40.000000000 +0200 ++++ ofed_kernel-2.6.16_sles10/include/linux/mlx4/qp.h 2008-01-22 13:20:13.000000000 +0200 +@@ -155,7 +155,11 @@ struct mlx4_qp_context { + u32 reserved5[10]; + }; + ++/* Which firmware version adds support for NEC (NoErrorCompletion) bit */ ++#define MLX4_FW_VER_WQE_CTRL_NEC mlx4_fw_ver(2, 2, 232) ++ + enum { ++ MLX4_WQE_CTRL_NEC = 1 << 29, + MLX4_WQE_CTRL_FENCE = 1 << 6, + MLX4_WQE_CTRL_CQ_UPDATE = 3 << 2, + MLX4_WQE_CTRL_SOLICITED = 1 << 1, diff --git a/branches/WOF2-3/hw/mlx4/todo.txt b/branches/WOF2-3/hw/mlx4/todo.txt new file mode 100644 index 00000000..96870109 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/todo.txt @@ -0,0 +1,116 @@ +CURRENT_PROBLEMS +================ + - qp_test. SEBIT fails + Reproduce (from qp_test, with opensm on sw269): +sw269: objchk_wnet_AMD64\amd64\qp_test.exe --daemon -p=1 --tcp_port=19017 --seed=1353948926 +sw270: objchk_wnet_AMD64\amd64\qp_test.exe --ip=10.4.12.69 -p=1 --ts=RC --tcp_port=19017 --seed=1353948926 --mtu=2048 --qp=5 -i=5 --poll=sebit CLIENT RR 4 7642 + + - srq_test: i've excluded XRC part in poll_one, which is starnge. It seems like unbalanced change with kernel. + For some reson QP is qualified like XRC, which cause poll error. + + - qp_test --ts=UD fails with pkt_size > 1024. Has to work with <=2048 + qp_test.exe --ip=10.4.12.70 --ts=UD --mtu=256 --qp=1 --thread=1 --poll=block --oust=1 -i=2 [--grh] CLIENT SRI 1 1100 + + - qp_test atomic operations fails + qp_test.exe --ip=10.4.12.70 --ts=RC --mtu=256 --qp=1 --thread=1 --poll=block --oust=1 -i=10 CLIENT CS 1 8 + mlx4: local QP operation err (QPN 26004a, WQE index 0, vendor syndrome 70, opcode = 5e) + \data_operation.c , 55 DATA_ERR : thread 0: wr_id: 0x064x + \data_operation.c , 56 DATA_ERR : thread 0: status: IB_WCS_LOCAL_OP_ERR + + - qp_test with several threads fails (not the very simple run) + qp_test.exe --ip=10.4.12.70 --ts=RC --mtu=1024 --qp=5 --thread=5 --poll=block --oust=12 -i=10000 CLIENT SRI 4 32048 SERVER RW 8 + on daemon side: + \data_operation.c , 55 DATA_ERR : thread 3: wr_id: 0x7014064x + \data_operation.c , 56 DATA_ERR : thread 3: status: IB_WCS_WR_FLUSHED_ERR + \data_operation.c , 275 MISC_ERR : thread 3: failed to read completions: IB_ERROR + \qp_test.c , 70 HCA_ERR : Got QP async event. Type: IB_AE_SQ_ERROR(0x1), vendor_specific: 0x064x + + - WSD freezes on long sends (packets lost ???). Do several times. (Tried with free version.) + SdpConnect.exe client 11.4.12.70 2222 0 1 0 2 2 1 40000 2000 + SdpConnect.exe pingpong 11.4.12.70 2223 2000 4 + + - DDR: opensm can't do the work: active side is left in ARMED state, passive - in INITIALIZED. + (maybe, out of debug messages on the passive side) + + - crash on destroy_cq + + mlx4_bus!mlx4_ib_db_free+0xad + mlx4_bus!mlx4_ib_destroy_cq+0x1c2 + mlx4_hca!ib_destroy_cq+0x46 + mlx4_hca!mlnx_destroy_cq+0x1d + ibbus!cleanup_cq+0x1d + ibbus!async_destroy_cb+0xb3 + ibbus!__cl_async_proc_worker+0x61 + ibbus!__cl_thread_pool_routine+0x41 + ibbus!__thread_callback+0x28 + + - Driver unload on the passive side, while opensm is running, gets stuck ! + Seems like because of the not released MADs: + [AL]print_al_obj() !ERROR!: AL object fffffade6c23b900(AL_OBJ_TYPE_H_MAD_SVC), parent: fffffade6cb4bd10 ref_cnt: 8 + Maybe, it is an old problem !! Check with MTHCA. + + - Crash on MAD send completion callback at driver download. + Check it by download driver while mad sending. + + mlxburn -d mt25408_pci_cr0 -fw c:\tmp\mlx4\FW\966\fw-25408-rel.mlx -conf c:\tmp\mlx4\fw\MHGH28-XTC_A1.ini + +Solved Problems: +=============== + - inverted LID in QP1 trafic of IBAL; + - ib_send_bw.exe -a -c UC + Couldn't create QP + - ib_read_bw gets stuck + mlx4: local QP operation err (QPN 0a004a, WQE index 0, vendor syndrome 70, opcode = 5e) + Completion wth error at client: + Failed status 2: wr_id 3 syndrom 0x70 + - crash on query_qp after create qp failed. + Seams like an IBAL problem - it calls mlnx_query_qp with h_qp = 0 + reproduce: + qp_test.exe --daemon + qp_test.exe --ip=10.4.12.70 [--ts=UC] --mtu=256 --qp=1 --thread=1 --poll=block --oust=1 -i=2 [--grh] CLIENT SRI 1 256 + create_qp for some reason failes with invalid_max_sge ??! + +SERIOUS BUGS: +============ +1. ALIGN_PAGE in Linux means aliign to the next page, in Windows - to the previous; +2. IBAL uses modify_av to change SA_SVC AV slid. When not used, it sends SA requests with LID = 1 in host order, as it put it to itself by default. +3. There is no way to convey CQ completion event to user space. So mlx4_cq_event, incrementing arm_sn, can't be called. +One needs to add an arrangement to make kernel code increment this variable. + + +BEFORE DEBUGGING +================ ++0. add support for livefish. +1. review eq.c - all interrupt handling stuff; ++2. remove all //rmv +3. look through all the // TODO +4. Check all the MACROS: whether there are more ones, that have different meaning in Windows and Linux; + +NOT IMPLEMENTED +=============== +0. Add propagation of vendor_specific error code to IBAL callbacks like in MTHCA +1. MSI-X support. +2. Work with DMA addresses and not with physical ones (a very serious change!); + + +KNOWN PROBLEMS +============== +1. Performance + 1.1 Command go-bit timeout is set to CMD_WAIT_USECS. Not clear the influence. + 1.2 Radix tree is implemented via COMPLIB calls, that seems like none used. It can be slow and even buggy. + 1.3 Different things can be done in built_in assempbler (e.g., bit operations like fls()). + +2. WPP support disabled. Problems: + - at compilation phase; + - Linux prints in MLX4_BUS are not supported by WPP (mlx4_err, mlx4_dbg, dev_err, dev_info ...); + - check WPP guids - both in MLX4_BUS and MLX4_HCA - are redefined and not copyed from the previous code. + +3. (General) Several places are marked with '// TODO:'. They have to be reviewed from time to time, especially - upon problems. + +PORTING PROBLEMS: +================ +1. PAGE_ALIGN has different meaning in Linux and Windows; +2. There is no way to convey CQ completion event to user space. So mlx4_cq_event, incrementing arm_sn, can't be called. +One needs to add an arrangement to make kernel code increment this variable. +3. IBAL uses modify_av to change SA_SVC AV slid, set by default to LITTLE_ENDIAN 1. The problem is seen as inverted LID on the sniffer. +The solution - implement modify_av. diff --git a/branches/WOF2-3/hw/mlx4/user/dirs b/branches/WOF2-3/hw/mlx4/user/dirs new file mode 100644 index 00000000..f1a57f04 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/user/dirs @@ -0,0 +1,2 @@ +DIRS=\ + hca diff --git a/branches/WOF2-3/hw/mlx4/user/hca/Makefile b/branches/WOF2-3/hw/mlx4/user/hca/Makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/user/hca/Makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\..\inc\openib.def diff --git a/branches/WOF2-3/hw/mlx4/user/hca/SOURCES b/branches/WOF2-3/hw/mlx4/user/hca/SOURCES new file mode 100644 index 00000000..5e71b11e --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/user/hca/SOURCES @@ -0,0 +1,70 @@ +TRUNK=..\..\..\.. + +!if $(FREEBUILD) +TARGETNAME=mlx4u +!else +TARGETNAME=mlx4ud +!endif + +TARGETPATH=$(TRUNK)\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE=DYNLINK +!if $(_NT_TOOLS_VERSION) == 0x700 +# DDK +DLLDEF=$O\mlx4.def +!else +# WDK +DLLDEF=$(OBJ_PATH)\$O\mlx4.def +!endif +USE_MSVCRT=1 +DLLENTRY=DllMain + +!if $(FREEBUILD) +#ENABLE_EVENT_TRACING=1 +!else +#ENABLE_EVENT_TRACING=1 +!endif + +SOURCES= \ + mlx4u.rc \ + buf.c \ + cq.c \ + dbrec.c \ + mlx4.c \ + mlx4_debug.c \ + qp.c \ + srq.c \ + verbs.c + +INCLUDES= \ + ..\..\inc; \ + $(TRUNK)\inc\user; \ + $(TRUNK)\inc\complib; \ + $(TRUNK)\inc\user\complib; \ + $(TRUNK)\inc; \ + +USER_C_FLAGS=$(USER_C_FLAGS) /DCL_NO_TRACK_MEM + +TARGETLIBS=\ + $(SDK_LIB_PATH)\user32.lib \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\Advapi32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\complib.lib \ +!else + $(TARGETPATH)\*\complibd.lib \ +!endif + +#LINKER_FLAGS=/MAP /MAPINFO:LINES + +!IFDEF ENABLE_EVENT_TRACING + +C_DEFINES = $(C_DEFINES) -DEVENT_TRACING -DWPP_OLDCC + + +RUN_WPP= $(SOURCES) -ext:.c.h -dll\ + -scan:mlx4_debug.h \ + -func:MLX4_PRINT(LEVEL,FLAGS,(MSG,...)) \ + -func:MLX4_PRINT_EXIT(LEVEL,FLAGS,(MSG,...)) +!ENDIF + +MSC_WARNING_LEVEL= /W4 diff --git a/branches/WOF2-3/hw/mlx4/user/hca/buf.c b/branches/WOF2-3/hw/mlx4/user/hca/buf.c new file mode 100644 index 00000000..0f01bd91 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/user/hca/buf.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2006, 2007 Cisco, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "mlx4.h" + +int mlx4_alloc_buf(struct mlx4_buf *buf, int size, int page_size) +{ + int ret; + ret = posix_memalign(&buf->buf, page_size, align(size, page_size)); + if (!ret) + buf->length = size; + return ret; +} + +void mlx4_free_buf(struct mlx4_buf *buf) +{ + posix_memfree(buf->buf); +} diff --git a/branches/WOF2-3/hw/mlx4/user/hca/cq.c b/branches/WOF2-3/hw/mlx4/user/hca/cq.c new file mode 100644 index 00000000..24d2f560 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/user/hca/cq.c @@ -0,0 +1,529 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies Ltd. All rights reserved. + * Copyright (c) 2006, 2007 Cisco Systems. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "mlx4.h" +#include "doorbell.h" +#include "mlx4_debug.h" + +#if defined(EVENT_TRACING) +#include "cq.tmh" +#endif + +enum { + MLX4_CQ_DOORBELL = 0x20 +}; + +enum { + CQ_OK = 0, + CQ_EMPTY = -1, + CQ_POLL_ERR = -2 +}; + +#define MLX4_CQ_DB_REQ_NOT_SOL (1 << 24) +#define MLX4_CQ_DB_REQ_NOT (2 << 24) + +enum { + MLX4_CQE_OWNER_MASK = 0x80, + MLX4_CQE_IS_SEND_MASK = 0x40, + MLX4_CQE_OPCODE_MASK = 0x1f +}; + +enum { + MLX4_CQE_SYNDROME_LOCAL_LENGTH_ERR = 0x01, + MLX4_CQE_SYNDROME_LOCAL_QP_OP_ERR = 0x02, + MLX4_CQE_SYNDROME_LOCAL_PROT_ERR = 0x04, + MLX4_CQE_SYNDROME_WR_FLUSH_ERR = 0x05, + MLX4_CQE_SYNDROME_MW_BIND_ERR = 0x06, + MLX4_CQE_SYNDROME_BAD_RESP_ERR = 0x10, + MLX4_CQE_SYNDROME_LOCAL_ACCESS_ERR = 0x11, + MLX4_CQE_SYNDROME_REMOTE_INVAL_REQ_ERR = 0x12, + MLX4_CQE_SYNDROME_REMOTE_ACCESS_ERR = 0x13, + MLX4_CQE_SYNDROME_REMOTE_OP_ERR = 0x14, + MLX4_CQE_SYNDROME_TRANSPORT_RETRY_EXC_ERR = 0x15, + MLX4_CQE_SYNDROME_RNR_RETRY_EXC_ERR = 0x16, + MLX4_CQE_SYNDROME_REMOTE_ABORTED_ERR = 0x22, +}; + +struct mlx4_cqe { + uint32_t my_qpn; + uint32_t immed_rss_invalid; + uint32_t g_mlpath_rqpn; + uint8_t sl; + uint8_t reserved1; + uint16_t rlid; + uint32_t reserved2; + uint32_t byte_cnt; + uint16_t wqe_index; + uint16_t checksum; + uint8_t reserved3[3]; + uint8_t owner_sr_opcode; +}; + +struct mlx4_err_cqe { + uint32_t my_qpn; + uint32_t reserved1[5]; + uint16_t wqe_index; + uint8_t vendor_err; + uint8_t syndrome; + uint8_t reserved2[3]; + uint8_t owner_sr_opcode; +}; + +static struct mlx4_cqe *get_cqe(struct mlx4_cq *cq, int entry) +{ + return (struct mlx4_cqe *)(cq->buf.buf + entry * MLX4_CQ_ENTRY_SIZE); +} + +static void *get_sw_cqe(struct mlx4_cq *cq, int n) +{ + struct mlx4_cqe *cqe = get_cqe(cq, n & cq->ibv_cq.cqe); + + return (!!(cqe->owner_sr_opcode & MLX4_CQE_OWNER_MASK) ^ + !!(n & (cq->ibv_cq.cqe + 1))) ? NULL : cqe; +} + +static struct mlx4_cqe *next_cqe_sw(struct mlx4_cq *cq) +{ + return get_sw_cqe(cq, cq->cons_index); +} + +static void update_cons_index(struct mlx4_cq *cq) +{ + *cq->set_ci_db = htonl(cq->cons_index & 0xffffff); +} + +static void mlx4_handle_error_cqe(struct mlx4_err_cqe *cqe, ib_wc_t *wc) +{ + if (cqe->syndrome == MLX4_CQE_SYNDROME_LOCAL_QP_OP_ERR) + printf(PFX "local QP operation err " + "(QPN %06x, WQE index %x, vendor syndrome %02x, " + "opcode = %02x)\n", + htonl(cqe->my_qpn), htons(cqe->wqe_index), + cqe->vendor_err, + cqe->owner_sr_opcode & ~MLX4_CQE_OWNER_MASK); + + switch (cqe->syndrome) { + case MLX4_CQE_SYNDROME_LOCAL_LENGTH_ERR: + wc->status = IB_WCS_LOCAL_LEN_ERR; + break; + case MLX4_CQE_SYNDROME_LOCAL_QP_OP_ERR: + wc->status = IB_WCS_LOCAL_OP_ERR; + break; + case MLX4_CQE_SYNDROME_LOCAL_PROT_ERR: + wc->status = IB_WCS_LOCAL_PROTECTION_ERR; + break; + case MLX4_CQE_SYNDROME_WR_FLUSH_ERR: + wc->status = IB_WCS_WR_FLUSHED_ERR; + break; + case MLX4_CQE_SYNDROME_MW_BIND_ERR: + wc->status = IB_WCS_MEM_WINDOW_BIND_ERR; + break; + case MLX4_CQE_SYNDROME_BAD_RESP_ERR: + wc->status = IB_WCS_BAD_RESP_ERR; + break; + case MLX4_CQE_SYNDROME_LOCAL_ACCESS_ERR: + wc->status = IB_WCS_LOCAL_ACCESS_ERR; + break; + case MLX4_CQE_SYNDROME_REMOTE_INVAL_REQ_ERR: + wc->status = IB_WCS_REM_INVALID_REQ_ERR; + break; + case MLX4_CQE_SYNDROME_REMOTE_ACCESS_ERR: + wc->status = IB_WCS_REM_ACCESS_ERR; + break; + case MLX4_CQE_SYNDROME_REMOTE_OP_ERR: + wc->status = IB_WCS_REM_OP_ERR; + break; + case MLX4_CQE_SYNDROME_TRANSPORT_RETRY_EXC_ERR: + wc->status = IB_WCS_TIMEOUT_RETRY_ERR; + break; + case MLX4_CQE_SYNDROME_RNR_RETRY_EXC_ERR: + wc->status = IB_WCS_RNR_RETRY_ERR; + break; + case MLX4_CQE_SYNDROME_REMOTE_ABORTED_ERR: + wc->status = IB_WCS_REM_ABORT_ERR; + break; + } + + wc->vendor_specific = cqe->vendor_err; +} + +static int mlx4_poll_one(struct mlx4_cq *cq, struct mlx4_qp **cur_qp, ib_wc_t *wc) +{ + struct mlx4_wq *wq; + struct mlx4_cqe *cqe; + struct mlx4_srq *srq = NULL; + uint32_t qpn; + uint16_t wqe_index; + int is_error; + int is_send; +#ifdef XRC_SUPPORT + int is_xrc_recv = 0; +#endif + + cqe = next_cqe_sw(cq); + if (!cqe) + return CQ_EMPTY; + + ++cq->cons_index; + + /* + * Make sure we read CQ entry contents after we've checked the + * ownership bit. + */ + rmb(); + + qpn = ntohl(cqe->my_qpn); + + is_send = cqe->owner_sr_opcode & MLX4_CQE_IS_SEND_MASK; + is_error = (cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) == + MLX4_CQE_OPCODE_ERROR; + +#ifdef XRC_SUPPORT + if (qpn & MLX4_XRC_QPN_BIT && !is_send) { + uint32_t srqn = ntohl(cqe->g_mlpath_rqpn) & 0xffffff; + /* + * We do not have to take the XRC SRQ table lock here, + * because CQs will be locked while XRC SRQs are removed + * from the table. + */ + srq = mlx4_find_xrc_srq(to_mctx(cq->ibv_cq.context), srqn); + if (!srq) + return CQ_POLL_ERR; + is_xrc_recv = 1; + } else +#endif + if (!*cur_qp || (qpn & 0xffffff) != (*cur_qp)->ibv_qp.qp_num) { + struct mlx4_qp *tmp_qp; + /* + * We do not have to take the QP table lock here, + * because CQs will be locked while QPs are removed + * from the table. + */ + tmp_qp = mlx4_find_qp(to_mctx(cq->ibv_cq.context), qpn & 0xffffff); + if (!tmp_qp) { + MLX4_PRINT( TRACE_LEVEL_INFORMATION, MLX4_DBG_CQ, ( + "cqe_qpn %#x, wr_id %#I64x, ix %d, cons_index %d, asked_qpn %#x \n", + qpn, wc->wr_id, ntohs(cqe->wqe_index), cq->cons_index - 1, + (*cur_qp) ? (*cur_qp)->ibv_qp.qp_num : 0 )); + return CQ_POLL_ERR; + } + *cur_qp = tmp_qp; + } + + if (is_send) { + wq = &(*cur_qp)->sq; + wqe_index = ntohs(cqe->wqe_index); + wq->tail += (uint16_t) (wqe_index - (uint16_t) wq->tail); + wc->wr_id = wq->wrid[wq->tail & (wq->wqe_cnt - 1)]; + ++wq->tail; + } else +#ifdef XRC_SUPPORT + if (is_xrc_recv) { + wqe_index = htons(cqe->wqe_index); + wc->wr_id = srq->wrid[wqe_index]; + mlx4_free_srq_wqe(srq, wqe_index); + } else +#endif + if ((*cur_qp)->ibv_qp.srq) { + srq = to_msrq((*cur_qp)->ibv_qp.srq); + wqe_index = htons(cqe->wqe_index); + wc->wr_id = srq->wrid[wqe_index]; + mlx4_free_srq_wqe(srq, wqe_index); + } else { + wq = &(*cur_qp)->rq; + wc->wr_id = wq->wrid[wq->tail & (wq->wqe_cnt - 1)]; + ++wq->tail; + } + + if (is_send) { + wc->recv.ud.recv_opt = 0; + switch (cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) { + case MLX4_OPCODE_RDMA_WRITE_IMM: + wc->recv.ud.recv_opt |= IB_RECV_OPT_IMMEDIATE; + case MLX4_OPCODE_RDMA_WRITE: + wc->wc_type = IB_WC_RDMA_WRITE; + break; + case MLX4_OPCODE_SEND_IMM: + wc->recv.ud.recv_opt |= IB_RECV_OPT_IMMEDIATE; + case MLX4_OPCODE_SEND: + wc->wc_type = IB_WC_SEND; + break; + case MLX4_OPCODE_RDMA_READ: + wc->wc_type = IB_WC_RDMA_READ; + wc->length = ntohl(cqe->byte_cnt); + break; + case MLX4_OPCODE_ATOMIC_CS: + wc->wc_type = IB_WC_COMPARE_SWAP; + wc->length = 8; + break; + case MLX4_OPCODE_ATOMIC_FA: + wc->wc_type = IB_WC_FETCH_ADD; + wc->length = 8; + break; + case MLX4_OPCODE_BIND_MW: + wc->wc_type = IB_WC_MW_BIND; + break; + default: + /* assume it's a send completion */ + wc->wc_type = IB_WC_SEND; + break; + } + } else { + wc->length = ntohl(cqe->byte_cnt); + + switch (cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) { + case MLX4_RECV_OPCODE_RDMA_WRITE_IMM: + wc->wc_type = IB_WC_RECV; + wc->recv.ud.recv_opt = IB_RECV_OPT_IMMEDIATE; + wc->recv.ud.immediate_data = cqe->immed_rss_invalid; + break; + case MLX4_RECV_OPCODE_SEND: + wc->wc_type = IB_WC_RECV; + wc->recv.ud.recv_opt = 0; + break; + case MLX4_RECV_OPCODE_SEND_IMM: + wc->wc_type = IB_WC_RECV; + wc->recv.ud.recv_opt = IB_RECV_OPT_IMMEDIATE; + wc->recv.ud.immediate_data = cqe->immed_rss_invalid; + break; + default: + /* assume it's a recv completion */ + wc->recv.ud.recv_opt = 0; + wc->wc_type = IB_WC_RECV; + break; + } + + wc->recv.ud.remote_lid = cqe->rlid; + wc->recv.ud.remote_sl = cqe->sl >> 4; + wc->recv.ud.remote_qp = cqe->g_mlpath_rqpn & 0xffffff00; + wc->recv.ud.path_bits = (uint8_t)(cqe->g_mlpath_rqpn & 0x7f); + wc->recv.ud.recv_opt |= cqe->g_mlpath_rqpn & 0x080 ? IB_RECV_OPT_GRH_VALID : 0; + wc->recv.ud.pkey_index = (uint16_t)(ntohl(cqe->immed_rss_invalid) & 0x7f); + } + + if (is_error) + mlx4_handle_error_cqe((struct mlx4_err_cqe *) cqe, wc); + else + wc->status = IB_WCS_SUCCESS; + + MLX4_PRINT( TRACE_LEVEL_INFORMATION, MLX4_DBG_CQ, ("qpn %#x, wr_id %#I64x, ix %d, cons_index %d, is_error %d \n", + qpn, wc->wr_id, ntohs(cqe->wqe_index), cq->cons_index - 1, is_error )); + + return CQ_OK; +} + +int mlx4_poll_cq_array(const void* h_cq, + const int num_entries, uvp_wc_t* const wc) +{ + struct mlx4_cq *cq = to_mcq((struct ibv_cq *)/*Ptr64ToPtr(*/ h_cq /*)*/); + struct mlx4_qp *qp = NULL; + int ne; + int err = CQ_EMPTY; + + pthread_spin_lock(&cq->lock); + for (ne = 0; ne < num_entries; ne++) { + err = mlx4_poll_one(cq, &qp, (ib_wc_t *) &wc[ne]); + if (err != CQ_OK) + break; + wc[ne].qp_context = qp->ibv_qp.qp_context; + } + + if (ne) + update_cons_index(cq); + pthread_spin_unlock(&cq->lock); + + return (err == CQ_OK || err == CQ_EMPTY) ? ne : err; +} + +ib_api_status_t +mlx4_poll_cq_list( + IN const void* h_cq, + IN OUT ib_wc_t** const pp_free_wclist, + OUT ib_wc_t** const pp_done_wclist) +{ + struct mlx4_cq *cq = to_mcq((struct ibv_cq *)/*Ptr64ToPtr(*/ h_cq /*)*/); + struct mlx4_qp *qp = NULL; + ib_wc_t *wc_p, **next_pp; + int npolled = 0; + int err = CQ_OK; + ib_api_status_t status = IB_SUCCESS; + + pthread_spin_lock(&cq->lock); + + // loop through CQ + next_pp = pp_done_wclist; + wc_p = *pp_free_wclist; + while( wc_p ) { + err = mlx4_poll_one(cq, &qp, wc_p); + if (err != CQ_OK) + break; + + // prepare for the next step + *next_pp = wc_p; + next_pp = &wc_p->p_next; + wc_p = wc_p->p_next; + ++npolled; + } + + // prepare the results + *pp_free_wclist = wc_p; /* Set the head of the free list. */ + *next_pp = NULL; /* Clear the tail of the done list. */ + + if (npolled) + update_cons_index(cq); + + pthread_spin_unlock(&cq->lock); + + if (err == CQ_POLL_ERR) + status = IB_ERROR; + else if (err == CQ_EMPTY && npolled == 0 ) + status = IB_NOT_FOUND; + + return status; +} + +ib_api_status_t +mlx4_arm_cq ( + IN const void* h_cq, + IN const boolean_t solicited) +{ + struct ibv_cq *ibvcq = (struct ibv_cq *)/*Ptr64ToPtr(*/ h_cq /*)*/; + struct mlx4_cq *cq = to_mcq(ibvcq); + uint32_t doorbell[2]; + uint32_t sn; + uint32_t ci; + uint32_t cmd; + + sn = cq->arm_sn & 3; + ci = cq->cons_index & 0xffffff; + cmd = solicited ? MLX4_CQ_DB_REQ_NOT_SOL : MLX4_CQ_DB_REQ_NOT; + + *cq->arm_db = htonl(sn << 28 | cmd | ci); + + /* + * Make sure that the doorbell record in host memory is + * written before ringing the doorbell via PCI MMIO. + */ + wmb(); + + doorbell[0] = htonl(sn << 28 | cmd | cq->cqn); + doorbell[1] = htonl(ci); + + mlx4_write64(doorbell, to_mctx(ibvcq->context), MLX4_CQ_DOORBELL); + + return IB_SUCCESS; +} + +#if 0 +// this function could be called in Windows +// we do it in kernel +void mlx4_cq_event(struct ibv_cq *cq) +{ + to_mcq(cq)->arm_sn++; +} +#endif + +void mlx4_cq_clean(struct mlx4_cq *cq, uint32_t qpn, struct mlx4_srq *srq) +{ + struct mlx4_cqe *cqe, *dest; + uint32_t prod_index; + uint8_t owner_bit; + int nfreed = 0; +#ifdef XRC_SUPPORT + int is_xrc_srq = 0; + + if (srq && srq->ibv_srq.xrc_cq) + is_xrc_srq = 1; +#endif + + pthread_spin_lock(&cq->lock); + + /* + * First we need to find the current producer index, so we + * know where to start cleaning from. It doesn't matter if HW + * adds new entries after this loop -- the QP we're worried + * about is already in RESET, so the new entries won't come + * from our QP and therefore don't need to be checked. + */ + for (prod_index = cq->cons_index; get_sw_cqe(cq, prod_index); ++prod_index) + if (prod_index == cq->cons_index + cq->ibv_cq.cqe) + break; + + /* + * Now sweep backwards through the CQ, removing CQ entries + * that match our QP by copying older entries on top of them. + */ + while ((int) --prod_index - (int) cq->cons_index >= 0) { + cqe = get_cqe(cq, prod_index & cq->ibv_cq.cqe); +#ifdef XRC_SUPPORT + if (is_xrc_srq && + (ntohl(cqe->g_mlpath_rqpn & 0xffffff) == srq->srqn) && + !(cqe->owner_sr_opcode & MLX4_CQE_IS_SEND_MASK)) { + mlx4_free_srq_wqe(srq, ntohs(cqe->wqe_index)); + ++nfreed; + } else +#endif + if ((ntohl(cqe->my_qpn) & 0xffffff) == qpn) { + if (srq && !(cqe->owner_sr_opcode & MLX4_CQE_IS_SEND_MASK)) + mlx4_free_srq_wqe(srq, ntohs(cqe->wqe_index)); + ++nfreed; + } else if (nfreed) { + dest = get_cqe(cq, (prod_index + nfreed) & cq->ibv_cq.cqe); + owner_bit = (uint8_t)(dest->owner_sr_opcode & MLX4_CQE_OWNER_MASK); + memcpy(dest, cqe, sizeof *cqe); + dest->owner_sr_opcode = (uint8_t)(owner_bit | + (dest->owner_sr_opcode & ~MLX4_CQE_OWNER_MASK)); + } + } + + if (nfreed) { + cq->cons_index += nfreed; + /* + * Make sure update of buffer contents is done before + * updating consumer index. + */ + wmb(); + update_cons_index(cq); + } + + pthread_spin_unlock(&cq->lock); +} + +void mlx4_cq_resize_copy_cqes(struct mlx4_cq *cq, void *buf, int old_cqe) +{ + UNREFERENCED_PARAMETER(cq); + UNREFERENCED_PARAMETER(buf); + UNREFERENCED_PARAMETER(old_cqe); +} diff --git a/branches/WOF2-3/hw/mlx4/user/hca/dbrec.c b/branches/WOF2-3/hw/mlx4/user/hca/dbrec.c new file mode 100644 index 00000000..d4ba0659 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/user/hca/dbrec.c @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "mlx4.h" + +#pragma warning( disable:4200 ) +struct mlx4_db_page { + struct mlx4_db_page *prev, *next; + struct mlx4_buf buf; + int num_db; + int use_cnt; + unsigned long free[]; +}; +#pragma warnning( default:4200) + +static const int db_size[] = { + 8, // MLX4_DB_TYPE_CQ + 4, // MLX4_DB_TYPE_RQ +}; + +static struct mlx4_db_page *__add_page(struct mlx4_context *context, + enum mlx4_db_type type) +{ + struct mlx4_db_page *page; + int ps = context->ibv_ctx.page_size; + int pp; + uint32_t i; + + pp = ps / db_size[type]; + + page = malloc(sizeof *page + pp / 8); + if (!page) + return NULL; + + if (mlx4_alloc_buf(&page->buf, ps, ps)) { + free(page); + return NULL; + } + + page->num_db = pp; + page->use_cnt = 0; + for (i = 0; i < pp / (sizeof (long) * 8); ++i) + page->free[i] = (unsigned long)~0; + + page->prev = NULL; + page->next = context->db_list[type]; + context->db_list[type] = page; + if (page->next) + page->next->prev = page; + + return page; +} + +uint32_t *mlx4_alloc_db(struct mlx4_context *context, enum mlx4_db_type type) +{ + struct mlx4_db_page *page; + uint32_t *db = NULL; + int i, j; + + pthread_mutex_lock(&context->db_list_mutex); + + for (page = context->db_list[type]; page; page = page->next) + if (page->use_cnt < page->num_db) + goto found; + + page = __add_page(context, type); + if (!page) + goto out; + +found: + ++page->use_cnt; + + for (i = 0; !page->free[i]; ++i) + /* nothing */; + + j = ffsl(page->free[i]); + page->free[i] &= ~(1UL << (j - 1)); + db = (uint32_t *)(page->buf.buf + (i * 8 * sizeof (long) + (j - 1)) * db_size[type]); + +out: + pthread_mutex_unlock(&context->db_list_mutex); + + return db; +} + +void mlx4_free_db(struct mlx4_context *context, enum mlx4_db_type type, uint32_t *db) +{ + struct mlx4_db_page *page; + int ps = context->ibv_ctx.page_size; + int i; + + pthread_mutex_lock(&context->db_list_mutex); + + for (page = context->db_list[type]; page; page = page->next) + if (((uintptr_t) db & ~(ps - 1)) == (uintptr_t) page->buf.buf) + break; + + if (!page) + goto out; + + i = (int)(((uint8_t *) db - page->buf.buf) / db_size[type]); + page->free[i / (8 * sizeof (long))] |= 1UL << (i % (8 * sizeof (long))); + + if (!--page->use_cnt) { + if (page->prev) + page->prev->next = page->next; + else + context->db_list[type] = page->next; + if (page->next) + page->next->prev = page->prev; + + mlx4_free_buf(&page->buf); + free(page); + } + +out: + pthread_mutex_unlock(&context->db_list_mutex); +} diff --git a/branches/WOF2-3/hw/mlx4/user/hca/doorbell.h b/branches/WOF2-3/hw/mlx4/user/hca/doorbell.h new file mode 100644 index 00000000..ff0c1965 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/user/hca/doorbell.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2007 Cisco, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef DOORBELL_H +#define DOORBELL_H + +#ifdef _WIN64 + +static inline void mlx4_write64(uint32_t val[2], struct mlx4_context *ctx, int offset) +{ + *(volatile uint64_t *) (ctx->uar + offset) = *(volatile uint64_t *)val; +} + +#else + +static inline void mlx4_write64(uint32_t val[2], struct mlx4_context *ctx, int offset) +{ + pthread_spin_lock(&ctx->uar_lock); + *(volatile uint32_t *) (ctx->uar + offset) = val[0]; + *(volatile uint32_t *) (ctx->uar + offset + 4) = val[1]; + pthread_spin_unlock(&ctx->uar_lock); +} + +#endif + +#endif /* DOORBELL_H */ diff --git a/branches/WOF2-3/hw/mlx4/user/hca/l2w.h b/branches/WOF2-3/hw/mlx4/user/hca/l2w.h new file mode 100644 index 00000000..b2fff316 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/user/hca/l2w.h @@ -0,0 +1,183 @@ +#ifndef MLX4_L2W_H +#define MLX4_L2W_H + +// =========================================== +// INCLUDES +// =========================================== + +// OS +#include +#include + +#include + +#include +#include +#include +#include +#include + + +// =========================================== +// SUBSTITUTIONS +// =========================================== + +// Memory +#define memset cl_memset +#define memclr cl_memclr +#define memcpy cl_memcpy +#define malloc cl_malloc +#define calloc(x,y) cl_zalloc((x)*(y)) +#define free cl_free + +// ByteSwap +#define htons cl_hton16 +#define htonl cl_hton32 +#define htonll cl_hton64 + +#define ntohs cl_ntoh16 +#define ntohl cl_ntoh32 +#define ntohll cl_ntoh64 + +// Synchronization +#define pthread_mutex_t HANDLE +#define pthread_spinlock_t cl_spinlock_t + +#define pthread_spin_init(x,y) cl_spinlock_init(x) +#define pthread_spin_lock cl_spinlock_acquire +#define pthread_spin_unlock cl_spinlock_release + + +// =========================================== +// LITERALS +// =========================================== + + +// =========================================== +// TYPES +// =========================================== + +typedef uint8_t __u8; +typedef uint16_t __u16; +typedef uint32_t __u32; +typedef uint64_t __u64; + +typedef int32_t __s32; + + +// =========================================== +// MACROS +// =========================================== + + +// =========================================== +// FUNCTIONS +// =========================================== + +static inline BOOLEAN is_power_of_2(uint32_t n) +{ + return (!!n & !(n & (n-1))) ? TRUE : FALSE; +} + +// Allocated memory is zeroed ! +static inline int posix_memalign(void **memptr, int alignment, int size) +{ + int aligned_size, desc_size = sizeof(int); + char *real_addr, *aligned_addr; + + // sanity check: alignment should a power of 2 and more then 2 + if ( alignment < desc_size || !is_power_of_2((uint32_t)alignment) ) + return -EINVAL; + + // calculate size, needed for aligned allocation + aligned_size = size + alignment + desc_size; + + // allocate + real_addr = cl_zalloc(aligned_size); + if ( real_addr == NULL ) + return -ENOMEM; + + // calculate aligned address + aligned_addr = (char *)(((ULONG_PTR)(real_addr + alignment-1)) & ~(alignment - 1)); + if ( aligned_addr < real_addr + desc_size ) + aligned_addr += alignment; + + // store the descriptor + *(int*)(aligned_addr - desc_size) = (int)(aligned_addr - real_addr); + + *memptr = aligned_addr; + return 0; +} + +// there is no such POSIX function. Called so to be similar to the allocation one. +static inline void posix_memfree(void *memptr) +{ + int *desc_addr = (int*)((char*)memptr - sizeof(int)); + char *real_addr = (char*)memptr - *desc_addr; + cl_free(real_addr); +} + +static inline int ffsl(uint32_t x) +{ + int r = 0; + + if (!x) + return 0; + if (!(x & 0x0000ffffu)) { + x >>= 16; + r += 16; + } + if (!(x & 0x000000ffu)) { + x >>= 8; + r += 8; + } + if (!(x & 0x0000000fu)) { + x >>= 4; + r += 4; + } + if (!(x & 0x000000003u)) { + x >>= 2; + r += 2; + } + if (!(x & 0x00000001u)) { + x >>= 1; + r += 1; + } + return r+1; +} + +static inline void pthread_mutex_lock(HANDLE *mutex) +{ + WaitForSingleObject(*mutex, INFINITE); +} + +static inline void pthread_mutex_unlock(HANDLE *mutex) +{ + ReleaseMutex(*mutex); +} + +// =========================================== +// ARCHITECTURE DEFINITIONS +// =========================================== + +/* + * Architecture-specific defines. Currently, an architecture is + * required to implement the following operations: + * + * mb() - memory barrier. No loads or stores may be reordered across + * this macro by either the compiler or the CPU. + * rmb() - read memory barrier. No loads may be reordered across this + * macro by either the compiler or the CPU. + * wmb() - write memory barrier. No stores may be reordered across + * this macro by either the compiler or the CPU. + * wc_wmb() - flush write combine buffers. No write-combined writes + * will be reordered across this macro by either the compiler or + * the CPU. + */ + +#define mb MemoryBarrier +#define rmb mb +#define wmb mb +#define wc_wmb mb + +#endif diff --git a/branches/WOF2-3/hw/mlx4/user/hca/mlx4.c b/branches/WOF2-3/hw/mlx4/user/hca/mlx4.c new file mode 100644 index 00000000..0f83bd94 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/user/hca/mlx4.c @@ -0,0 +1,329 @@ +/* + * Copyright (c) 2007 Cisco, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + +#include "mlx4.h" +#include "mx_abi.h" + +#ifndef PCI_VENDOR_ID_MELLANOX +#define PCI_VENDOR_ID_MELLANOX 0x15b3 +#endif + +#define HCA(v, d) \ + {PCI_VENDOR_ID_##v, \ + d } + +struct { + unsigned vendor; + unsigned device; +} hca_table[] = { + HCA(MELLANOX, 0x6340), /* MT25408 "Hermon" SDR */ + HCA(MELLANOX, 0x634a), /* MT25418 "Hermon" DDR */ + HCA(MELLANOX, 0x6732), /* MT26418 "Hermon" DDR PCIe gen2 */ + HCA(MELLANOX, 0x6778), /* MT26488 "Hermon" DDR PCIe gen2 */ + HCA(MELLANOX, 0x673C), /* MT26428 "Hermon" QDR PCIe gen2 */ + HCA(MELLANOX, 0x6746), /* MT26438 "Hermon" QDR PCIe gen2 */ + + HCA(MELLANOX, 0x6368), /* MT25448 "Hermon" Ethernet */ + HCA(MELLANOX, 0x6372), /* MT25458 "Hermon" Ethernet Yatir*/ + HCA(MELLANOX, 0x6750), /* MT26448 "Hermon" Ethernet PCIe gen2 */ + HCA(MELLANOX, 0x675A), /* MT26458 "Hermon" Ethernet Yatir PCIe gen2*/ + HCA(MELLANOX, 0x6764), /* MT26468 "Hermon" B0 Ethernet PCIe gen2*/ + HCA(MELLANOX, 0x676E), /* MT26478 "Hermon" B0 40Gb Ethernet PCIe gen2*/ + + HCA(MELLANOX, 0x0191), /* MT25408 "Hermon" livefish mode */ +}; + + +struct ibv_context * mlx4_alloc_context() +{ + struct mlx4_context *context; + + /* allocate context */ + context = cl_zalloc(sizeof *context); + if (!context) + goto end; + + context->qp_table_mutex = CreateMutex(NULL, FALSE, NULL); + if (!context->qp_table_mutex) + goto err_qp_mutex; + +#ifdef XRC_SUPPORT + context->xrc_srq_table_mutex = CreateMutex(NULL, FALSE, NULL); + if (!context->xrc_srq_table_mutex) + goto err_xrc_mutex; +#endif + + context->db_list_mutex = CreateMutex(NULL, FALSE, NULL); + if (!context->db_list_mutex) + goto err_db_mutex; + + if (cl_spinlock_init(&context->uar_lock)) + goto err_uar_spinlock; + + if (cl_spinlock_init(&context->bf_lock)) + goto err_bf_spinlock; + + return &context->ibv_ctx; + +err_bf_spinlock: + cl_spinlock_destroy(&context->uar_lock); +err_uar_spinlock: + CloseHandle(context->db_list_mutex); +err_db_mutex: +#ifdef XRC_SUPPORT + CloseHandle(context->xrc_srq_table_mutex); +err_xrc_mutex: +#endif + CloseHandle(context->qp_table_mutex); +err_qp_mutex: + cl_free(context); +end: + return NULL; + +} + +struct ibv_context * mlx4_fill_context(struct ibv_context *ctx, struct ibv_get_context_resp *p_resp) +{ + struct mlx4_context *context = to_mctx(ctx); + SYSTEM_INFO sys_info; + int i; + + /* check device type */ + for (i = 0; i < sizeof hca_table / sizeof hca_table[0]; ++i) + if (p_resp->vend_id == hca_table[i].vendor && + p_resp->dev_id == hca_table[i].device) + goto found; + goto err_dev_type; + +found: + context->num_qps = p_resp->qp_tab_size; + context->qp_table_shift = ffsl(context->num_qps) - 1 - MLX4_QP_TABLE_BITS; + context->qp_table_mask = (1 << context->qp_table_shift) - 1; + + for (i = 0; i < MLX4_QP_TABLE_SIZE; ++i) + context->qp_table[i].refcnt = 0; + +#ifdef XRC_SUPPORT + context->num_xrc_srqs = p_resp->qp_tab_size; + context->xrc_srq_table_shift = ffsl(context->num_xrc_srqs) - 1 + - MLX4_XRC_SRQ_TABLE_BITS; + context->xrc_srq_table_mask = (1 << context->xrc_srq_table_shift) - 1; + + for (i = 0; i < MLX4_XRC_SRQ_TABLE_SIZE; ++i) + context->xrc_srq_table[i].refcnt = 0; +#endif + + for (i = 0; i < MLX4_NUM_DB_TYPE; ++i) + context->db_list[i] = NULL; + + context->uar = (uint8_t *)(uintptr_t)p_resp->uar_addr; + context->bf_page = (uint8_t *)(uintptr_t)p_resp->bf_page; + context->bf_buf_size = p_resp->bf_buf_size; + context->bf_offset = p_resp->bf_offset; + + context->max_qp_wr = p_resp->max_qp_wr; + context->max_sge = p_resp->max_sge; + context->max_cqe = p_resp->max_cqe; + + GetSystemInfo(&sys_info); + context->ibv_ctx.page_size = sys_info.dwPageSize; + + return &context->ibv_ctx; + +err_dev_type: + mlx4_free_context(&context->ibv_ctx); + return NULL; +} + +void mlx4_free_context(struct ibv_context *ctx) +{ + struct mlx4_context *context = to_mctx(ctx); + + cl_spinlock_destroy(&context->bf_lock); + cl_spinlock_destroy(&context->uar_lock); + CloseHandle(context->db_list_mutex); +#ifdef XRC_SUPPORT + CloseHandle(context->xrc_srq_table_mutex); +#endif + CloseHandle(context->qp_table_mutex); + cl_free(context); +} + +static void __get_uvp_interface(uvp_interface_t *p_uvp) +{ + p_uvp->pre_open_ca = mlx4_pre_open_ca; + p_uvp->post_open_ca = mlx4_post_open_ca; + p_uvp->pre_query_ca = NULL; + p_uvp->post_query_ca = NULL; + p_uvp->pre_modify_ca = NULL; + p_uvp->post_modify_ca = NULL; + p_uvp->pre_close_ca = NULL; + p_uvp->post_close_ca = mlx4_post_close_ca; + + + /* + * Protection Domain + */ + p_uvp->pre_allocate_pd = mlx4_pre_alloc_pd; + p_uvp->post_allocate_pd = mlx4_post_alloc_pd; + p_uvp->pre_deallocate_pd = NULL; + p_uvp->post_deallocate_pd = mlx4_post_free_pd; + + + /* + * SRQ Management Verbs + */ + p_uvp->pre_create_srq = mlx4_pre_create_srq; + p_uvp->post_create_srq = mlx4_post_create_srq; + p_uvp->pre_query_srq = NULL; + p_uvp->post_query_srq = NULL; + p_uvp->pre_modify_srq = NULL; + p_uvp->post_modify_srq = NULL; + p_uvp->pre_destroy_srq = NULL; + p_uvp->post_destroy_srq = mlx4_post_destroy_srq; + + p_uvp->pre_create_qp = mlx4_pre_create_qp; + p_uvp->wv_pre_create_qp = mlx4_wv_pre_create_qp; + p_uvp->post_create_qp = mlx4_post_create_qp; + p_uvp->pre_modify_qp = mlx4_pre_modify_qp; + p_uvp->post_modify_qp = mlx4_post_modify_qp; + p_uvp->pre_query_qp = NULL; + p_uvp->post_query_qp = mlx4_post_query_qp; + p_uvp->pre_destroy_qp = mlx4_pre_destroy_qp; + p_uvp->post_destroy_qp = mlx4_post_destroy_qp; + p_uvp->nd_modify_qp = mlx4_nd_modify_qp; + p_uvp->nd_get_qp_state = mlx4_nd_get_qp_state; + + + /* + * Completion Queue Management Verbs + */ + p_uvp->pre_create_cq = mlx4_pre_create_cq; + p_uvp->post_create_cq = mlx4_post_create_cq; + p_uvp->pre_query_cq = mlx4_pre_query_cq; + p_uvp->post_query_cq = NULL; + p_uvp->pre_resize_cq = NULL; + p_uvp->post_resize_cq = NULL; + p_uvp->pre_destroy_cq = NULL; + p_uvp->post_destroy_cq = mlx4_post_destroy_cq; + + + /* + * AV Management + */ + p_uvp->pre_create_av = mlx4_pre_create_ah; + p_uvp->post_create_av = NULL; + p_uvp->pre_query_av = mlx4_pre_query_ah; + p_uvp->post_query_av = mlx4_post_query_ah; + p_uvp->pre_modify_av = mlx4_pre_modify_ah; + p_uvp->post_modify_av = NULL; + p_uvp->pre_destroy_av = mlx4_pre_destroy_ah; + p_uvp->post_destroy_av = NULL; + + + /* + * Memory Region / Window Management Verbs + */ + p_uvp->pre_create_mw = NULL; + p_uvp->post_create_mw = NULL; + p_uvp->pre_query_mw = NULL; + p_uvp->post_query_mw = NULL; + p_uvp->pre_destroy_mw = NULL; + p_uvp->post_destroy_mw = NULL; + + + /* + * Multicast Support Verbs + */ + p_uvp->pre_attach_mcast = NULL; + p_uvp->post_attach_mcast = NULL; + p_uvp->pre_detach_mcast = NULL; + p_uvp->post_detach_mcast = NULL; + + + /* + * OS bypass (send, receive, poll/notify cq) + */ + p_uvp->post_send = mlx4_post_send; + p_uvp->post_recv = mlx4_post_recv; + p_uvp->post_srq_recv = mlx4_post_srq_recv; + p_uvp->poll_cq = mlx4_poll_cq_list; + p_uvp->poll_cq_array = mlx4_poll_cq_array; + p_uvp->rearm_cq = mlx4_arm_cq; + p_uvp->rearm_n_cq = NULL; + p_uvp->peek_cq = NULL; + p_uvp->bind_mw = NULL; +} + +/* TODO: define and expose XRC through new interface GUID */ +#ifdef XRC_SUPPORT +static void __get_xrc_interface(uvp_xrc_interface_t *p_xrc) +{ + /* + * XRC Management Verbs + */ + p_uvp->pre_create_xrc_srq = mlx4_pre_create_xrc_srq; + p_uvp->post_create_xrc_srq = mlx4_post_create_xrc_srq; + p_uvp->pre_open_xrc_domain = mlx4_pre_open_xrc_domain; + p_uvp->post_open_xrc_domain = mlx4_post_open_xrc_domain; + p_uvp->pre_close_xrc_domain = NULL; + p_uvp->post_close_xrc_domain = mlx4_post_close_xrc_domain; + p_uvp->pre_create_xrc_rcv_qp = NULL; + p_uvp->post_create_xrc_rcv_qp = NULL; + p_uvp->pre_modify_xrc_rcv_qp = NULL; + p_uvp->post_modify_xrc_rcv_qp = NULL; + p_uvp->pre_query_xrc_rcv_qp = NULL; + p_uvp->post_query_xrc_rcv_qp = NULL; + p_uvp->pre_reg_xrc_rcv_qp = NULL; + p_uvp->post_reg_xrc_rcv_qp = NULL; + p_uvp->pre_unreg_xrc_rcv_qp = NULL; + p_uvp->post_unreg_xrc_rcv_qp = NULL; +} +#endif + +__declspec(dllexport) ib_api_status_t +uvp_get_interface (GUID iid, void* pifc) +{ + ib_api_status_t status = IB_SUCCESS; + + if (IsEqualGUID(&iid, &IID_UVP)) + { + __get_uvp_interface((uvp_interface_t *) pifc); + } + else + { + status = IB_UNSUPPORTED; + } + + return status; +} diff --git a/branches/WOF2-3/hw/mlx4/user/hca/mlx4.def b/branches/WOF2-3/hw/mlx4/user/hca/mlx4.def new file mode 100644 index 00000000..07e29ca4 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/user/hca/mlx4.def @@ -0,0 +1,11 @@ +#if DEBUG +LIBRARY mlx4ud.dll +#else +LIBRARY mlx4u.dll +#endif + +#ifndef _WIN64 +EXPORTS +uvp_get_interface +#endif + diff --git a/branches/WOF2-3/hw/mlx4/user/hca/mlx4.h b/branches/WOF2-3/hw/mlx4/user/hca/mlx4.h new file mode 100644 index 00000000..e7f70bb7 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/user/hca/mlx4.h @@ -0,0 +1,350 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005, 2006, 2007 Cisco Systems. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef MLX4_H +#define MLX4_H + + +#include +#include + +#include "verbs.h" +#include "mx_abi.h" + +#include "l2w.h" + +#define PFX "mlx4: " + +#ifndef max +#define max(a,b) \ + ({ typeof (a) _a = (a); \ + typeof (b) _b = (b); \ + _a > _b ? _a : _b; }) +#endif + +#ifndef min +#define min(a,b) \ + ({ typeof (a) _a = (a); \ + typeof (b) _b = (b); \ + _a < _b ? _a : _b; }) +#endif + +enum { + MLX4_CQ_ENTRY_SIZE = 0x20 +}; + +enum { + MLX4_STAT_RATE_OFFSET = 5 +}; + +enum { + MLX4_QP_TABLE_BITS = 8, + MLX4_QP_TABLE_SIZE = 1 << MLX4_QP_TABLE_BITS, + MLX4_QP_TABLE_MASK = MLX4_QP_TABLE_SIZE - 1 +}; + +#ifdef XRC_SUPPORT +enum { + MLX4_XRC_SRQ_TABLE_BITS = 8, + MLX4_XRC_SRQ_TABLE_SIZE = 1 << MLX4_XRC_SRQ_TABLE_BITS, + MLX4_XRC_SRQ_TABLE_MASK = MLX4_XRC_SRQ_TABLE_SIZE - 1 +}; + +enum { + MLX4_XRC_QPN_BIT = (1 << 23) +}; +#endif + +enum mlx4_db_type { + MLX4_DB_TYPE_CQ, + MLX4_DB_TYPE_RQ, + MLX4_NUM_DB_TYPE +}; + +enum mlx4_opcode_type { + MLX4_OPCODE_NOP = 0x00, + MLX4_OPCODE_SEND_INVAL = 0x01, + MLX4_OPCODE_RDMA_WRITE = 0x08, + MLX4_OPCODE_RDMA_WRITE_IMM = 0x09, + MLX4_OPCODE_SEND = 0x0a, + MLX4_OPCODE_SEND_IMM = 0x0b, + MLX4_OPCODE_LSO = 0x0e, + MLX4_OPCODE_RDMA_READ = 0x10, + MLX4_OPCODE_ATOMIC_CS = 0x11, + MLX4_OPCODE_ATOMIC_FA = 0x12, + MLX4_OPCODE_ATOMIC_MASK_CS = 0x14, + MLX4_OPCODE_ATOMIC_MASK_FA = 0x15, + MLX4_OPCODE_BIND_MW = 0x18, + MLX4_OPCODE_FMR = 0x19, + MLX4_OPCODE_LOCAL_INVAL = 0x1b, + MLX4_OPCODE_CONFIG_CMD = 0x1f, + + MLX4_RECV_OPCODE_RDMA_WRITE_IMM = 0x00, + MLX4_RECV_OPCODE_SEND = 0x01, + MLX4_RECV_OPCODE_SEND_IMM = 0x02, + MLX4_RECV_OPCODE_SEND_INVAL = 0x03, + + MLX4_CQE_OPCODE_ERROR = 0x1e, + MLX4_CQE_OPCODE_RESIZE = 0x16, + + MLX4_OPCODE_INVALID = 0xff +}; + +struct mlx4_db_page; + +struct mlx4_context { + struct ibv_context ibv_ctx; + + uint8_t *uar; + pthread_spinlock_t uar_lock; + + uint8_t *bf_page; + int bf_buf_size; + int bf_offset; + pthread_spinlock_t bf_lock; + + struct { + struct mlx4_qp **table; + int refcnt; + } qp_table[MLX4_QP_TABLE_SIZE]; + pthread_mutex_t qp_table_mutex; + int num_qps; + int qp_table_shift; + int qp_table_mask; + int max_qp_wr; + int max_sge; + int max_cqe; + +#ifdef XRC_SUPPORT + struct { + struct mlx4_srq **table; + int refcnt; + } xrc_srq_table[MLX4_XRC_SRQ_TABLE_SIZE]; + pthread_mutex_t xrc_srq_table_mutex; + int num_xrc_srqs; + int xrc_srq_table_shift; + int xrc_srq_table_mask; +#endif + + struct mlx4_db_page *db_list[MLX4_NUM_DB_TYPE]; + pthread_mutex_t db_list_mutex; +}; + +struct mlx4_buf { + uint8_t *buf; + int length; +}; + +struct mlx4_pd { + struct ibv_pd ibv_pd; + uint32_t pdn; +}; + +struct mlx4_cq { + struct ibv_cq ibv_cq; + struct mlx4_buf buf; + pthread_spinlock_t lock; + uint32_t cqn; + uint32_t cons_index; + uint32_t *set_ci_db; + uint32_t *arm_db; + int arm_sn; +}; + +struct mlx4_srq { + struct ibv_srq ibv_srq; + struct mlx4_buf buf; + pthread_spinlock_t lock; + uint64_t *wrid; + uint32_t srqn; + int max; + int max_gs; + int wqe_shift; + int head; + int tail; + uint32_t *db; + uint16_t counter; +}; + +struct mlx4_wq { + uint64_t *wrid; + pthread_spinlock_t lock; + int wqe_cnt; + int max_post; + unsigned head; + unsigned tail; + int max_gs; + int wqe_shift; + int offset; +}; + +struct mlx4_qp { + struct ibv_qp ibv_qp; + struct mlx4_buf buf; + int max_inline_data; + int buf_size; + + uint32_t doorbell_qpn; + uint32_t sq_signal_bits; + int sq_spare_wqes; + struct mlx4_wq sq; + + uint32_t *db; + struct mlx4_wq rq; +}; + +struct mlx4_av { + uint32_t port_pd; + uint8_t reserved1; + uint8_t g_slid; + uint16_t dlid; + uint8_t reserved2; + uint8_t gid_index; + uint8_t stat_rate; + uint8_t hop_limit; + uint32_t sl_tclass_flowlabel; + uint8_t dgid[16]; +}; + +struct mlx4_ah { + struct ibv_ah ibv_ah; + struct mlx4_av av; +}; + +#ifdef XRC_SUPPORT +struct mlx4_xrc_domain { + struct ibv_xrc_domain ibv_xrcd; + uint32_t xrcdn; +}; +#endif + +static inline unsigned long align(unsigned long val, unsigned long align) +{ + return (val + align - 1) & ~(align - 1); +} + +#define to_mxxx(xxx, type) \ + ((struct mlx4_##type *) \ + ((uint8_t *) ib##xxx - offsetof(struct mlx4_##type, ibv_##xxx))) + +static inline struct mlx4_context *to_mctx(struct ibv_context *ibctx) +{ + return to_mxxx(ctx, context); +} + +static inline struct mlx4_pd *to_mpd(struct ibv_pd *ibpd) +{ + return to_mxxx(pd, pd); +} + +static inline struct mlx4_cq *to_mcq(struct ibv_cq *ibcq) +{ + return to_mxxx(cq, cq); +} + +static inline struct mlx4_srq *to_msrq(struct ibv_srq *ibsrq) +{ + return to_mxxx(srq, srq); +} + +static inline struct mlx4_qp *to_mqp(struct ibv_qp *ibqp) +{ + return to_mxxx(qp, qp); +} + +static inline struct mlx4_ah *to_mah(struct ibv_ah *ibah) +{ + return to_mxxx(ah, ah); +} + +#ifdef XRC_SUPPORT +static inline struct mlx4_xrc_domain *to_mxrcd(struct ibv_xrc_domain *ibxrcd) +{ + return to_mxxx(xrcd, xrc_domain); +} +#endif + +struct ibv_context * mlx4_alloc_context(); +struct ibv_context * mlx4_fill_context(struct ibv_context *ctx, + struct ibv_get_context_resp *resp_p); +void mlx4_free_context(struct ibv_context *ctx); + +int mlx4_alloc_buf(struct mlx4_buf *buf, int size, int page_size); +void mlx4_free_buf(struct mlx4_buf *buf); + +uint32_t *mlx4_alloc_db(struct mlx4_context *context, enum mlx4_db_type type); +void mlx4_free_db(struct mlx4_context *context, enum mlx4_db_type type, uint32_t *db); + +int mlx4_poll_cq_array(const void* h_cq, + const int num_entries, uvp_wc_t* const wc); +ib_api_status_t mlx4_poll_cq_list(const void* h_cq, + ib_wc_t** const pp_free_wclist, + ib_wc_t** const pp_done_wclist); +ib_api_status_t mlx4_arm_cq(const void* h_cq, const boolean_t solicited); +void mlx4_cq_event(struct ibv_cq *cq); +void mlx4_cq_clean(struct mlx4_cq *cq, uint32_t qpn, + struct mlx4_srq *srq); +void mlx4_cq_resize_copy_cqes(struct mlx4_cq *cq, void *buf, int new_cqe); + +int mlx4_alloc_srq_buf(struct ibv_pd *pd, struct ibv_srq_attr *attr, + struct mlx4_srq *srq); +void mlx4_free_srq_wqe(struct mlx4_srq *srq, int ind); +ib_api_status_t mlx4_post_srq_recv(const void* h_srq, + ib_recv_wr_t* const wr, + ib_recv_wr_t** bad_wr); + +#ifdef XRC_SUPPORT +struct mlx4_srq *mlx4_find_xrc_srq(struct mlx4_context *ctx, uint32_t xrc_srqn); +int mlx4_store_xrc_srq(struct mlx4_context *ctx, uint32_t xrc_srqn, + struct mlx4_srq *srq); +void mlx4_clear_xrc_srq(struct mlx4_context *ctx, uint32_t xrc_srqn); +#endif + +void mlx4_init_qp_indices(struct mlx4_qp *qp); +void mlx4_qp_init_sq_ownership(struct mlx4_qp *qp); +ib_api_status_t mlx4_post_send(const void* h_qp, + ib_send_wr_t* const wr, + ib_send_wr_t** bad_wr); +ib_api_status_t mlx4_post_recv(const void* h_qp, + ib_recv_wr_t* const wr, + ib_recv_wr_t** bad_wr); + +void mlx4_calc_sq_wqe_size(struct ibv_qp_cap *cap, enum ibv_qp_type type, + struct mlx4_qp *qp); +int mlx4_alloc_qp_buf(struct ibv_pd *pd, struct ibv_qp_cap *cap, + enum ibv_qp_type type, struct mlx4_qp *qp); +void mlx4_set_sq_sizes(struct mlx4_qp *qp, struct ibv_qp_cap *cap, + enum ibv_qp_type type); +struct mlx4_qp *mlx4_find_qp(struct mlx4_context *ctx, uint32_t qpn); +int mlx4_store_qp(struct mlx4_context *ctx, uint32_t qpn, struct mlx4_qp *qp); +void mlx4_clear_qp(struct mlx4_context *ctx, uint32_t qpn); + +#endif /* MLX4_H */ diff --git a/branches/WOF2-3/hw/mlx4/user/hca/mlx4_debug.c b/branches/WOF2-3/hw/mlx4/user/hca/mlx4_debug.c new file mode 100644 index 00000000..38c8a37f --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/user/hca/mlx4_debug.c @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2005 Mellanox Technologies LTD. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +// Author: Yossi Leybovich + +#include "mlx4_debug.h" +#include +#include +#include + +#if !defined(EVENT_TRACING) + + +#if DBG +uint32_t g_mlx4_dbg_level = TRACE_LEVEL_WARNING; +uint32_t g_mlx4_dbg_flags= MLX4_DBG_QP | MLX4_DBG_CQ | MLX4_DBG_MEMORY; +const int MLX4_PRINT_HELPER = 0; +#endif + +VOID +_MLX4_PRINT( + IN char* msg, + ... + ) + + { +#if DBG +#define TEMP_BUFFER_SIZE 1024 + va_list list; + CHAR debugMessageBuffer[TEMP_BUFFER_SIZE]; + HRESULT result; + + va_start(list, msg); + + if (msg) { + + // + // Using new safe string functions instead of _vsnprintf. This function takes + // care of NULL terminating if the message is longer than the buffer. + // + + result = StringCbVPrintfA (debugMessageBuffer, sizeof(debugMessageBuffer), + msg, list); + if(((HRESULT)(result) < 0)) { + + OutputDebugString (": StringCbVPrintfA failed \n"); + return; + } + OutputDebugString ( debugMessageBuffer); + + } + va_end(list); + + return; +#else + UNUSED_PARAM(msg); +#endif //DBG +} + +#endif //EVENT_TRACING + diff --git a/branches/WOF2-3/hw/mlx4/user/hca/mlx4_debug.h b/branches/WOF2-3/hw/mlx4/user/hca/mlx4_debug.h new file mode 100644 index 00000000..0c4ec5a4 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/user/hca/mlx4_debug.h @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + + +#ifndef _MLX4_DEBUG_H_ +#define _MLX4_DEBUG_H_ + +#include + +extern uint32_t g_mlx4_dbg_level; +extern uint32_t g_mlx4_dbg_flags; + + +#if defined(EVENT_TRACING) +// +// Software Tracing Definitions +// +// + +#define WPP_CONTROL_GUIDS \ + WPP_DEFINE_CONTROL_GUID(HCACtlGuid,(1752F07C,7E5C,402c,9C5F,AD21E572F852), \ + WPP_DEFINE_BIT( MLX4_DBG_DEV) \ + WPP_DEFINE_BIT( MLX4_DBG_PNP) \ + WPP_DEFINE_BIT( MLX4_DBG_MAD) \ + WPP_DEFINE_BIT( MLX4_DBG_PO) \ + WPP_DEFINE_BIT( MLX4_DBG_CQ) \ + WPP_DEFINE_BIT( MLX4_DBG_QP) \ + WPP_DEFINE_BIT( MLX4_DBG_MEMORY) \ + WPP_DEFINE_BIT( MLX4_DBG_SRQ) \ + WPP_DEFINE_BIT( MLX4_DBG_AV) \ + WPP_DEFINE_BIT( MLX4_DBG_SEND) \ + WPP_DEFINE_BIT( MLX4_DBG_RECV) \ + WPP_DEFINE_BIT( MLX4_DBG_LOW)) + + +#define WPP_LEVEL_FLAGS_ENABLED(lvl, flags) (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= lvl) +#define WPP_LEVEL_FLAGS_LOGGER(lvl,flags) WPP_LEVEL_LOGGER(flags) +#define WPP_FLAG_ENABLED(flags)(WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= TRACE_LEVEL_VERBOSE) +#define WPP_FLAG_LOGGER(flags) WPP_LEVEL_LOGGER(flags) + + +// begin_wpp config +// MLX4_ENTER(FLAG); +// MLX4_EXIT(FLAG); +// USEPREFIX(MLX4_PRINT, "%!FUNC!() "); +// USESUFFIX(MLX4_ENTER, "%!FUNC!===>"); +// USESUFFIX(MLX4_EXIT, "%!FUNC!<==="); +// end_wpp + + +#else + +#include +#include + +/* + * Debug macros + */ + + +#define MLX4_DBG_DEV (1 << 0) +#define MLX4_DBG_PNP (1 << 1) +#define MLX4_DBG_MAD (1 << 2) +#define MLX4_DBG_PO (1 << 3) +#define MLX4_DBG_QP (1 << 4) +#define MLX4_DBG_CQ (1 << 5) +#define MLX4_DBG_MEMORY (1 << 6) +#define MLX4_DBG_SRQ (1 << 7) +#define MLX4_DBG_AV (1 << 8) +#define MLX4_DBG_SEND (1 << 9) +#define MLX4_DBG_RECV (1 << 10) +#define MLX4_DBG_LOW (1 << 11) + + +VOID + _MLX4_PRINT( + IN char* msg, + ...); + +#if DBG + + +extern const int MLX4_PRINT_HELPER; + +#define MLX4_PRINT(_level_,_flags_,_msg_) \ + if ((_level_) <= g_mlx4_dbg_level && (_flags_) & g_mlx4_dbg_flags) {\ + _MLX4_PRINT("[MLX4] %s():",__FUNCTION__);\ + if((_level_ | MLX4_PRINT_HELPER) == TRACE_LEVEL_ERROR) _MLX4_PRINT ("***ERROR*** ");\ + _MLX4_PRINT _msg_ ; \ + } + + +#else + +#define MLX4_PRINT(lvl ,flags, msg) + +#endif + + +#define MLX4_ENTER(flags)\ + MLX4_PRINT(TRACE_LEVEL_VERBOSE, flags,("===>\n")); + +#define MLX4_EXIT(flags)\ + MLX4_PRINT(TRACE_LEVEL_VERBOSE, flags,("<===\n")); + +#define MLX4_PRINT_EXIT(_level_,_flag_,_msg_) \ + {\ + if (status != IB_SUCCESS) {\ + MLX4_PRINT(_level_,_flag_,_msg_);\ + }\ + MLX4_EXIT(_flag_);\ + } + +#endif //EVENT_TRACING + +#endif /*_MLNX_MLX4_DEBUG_H_ */ + diff --git a/branches/WOF2-3/hw/mlx4/user/hca/mlx4u.rc b/branches/WOF2-3/hw/mlx4/user/hca/mlx4u.rc new file mode 100644 index 00000000..158a0096 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/user/hca/mlx4u.rc @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2009 Mellanox Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: mlx4u.rc 1611 2006-08-20 14:48:55Z reuven $ + */ + + +#include + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef DBG +#define VER_FILEDESCRIPTION_STR "HCA User Mode Verb Provider (Debug)" +#define VER_INTERNALNAME_STR "mlx4ud.dll" +#define VER_ORIGINALFILENAME_STR "mlx4ud.dll" +#else +#define VER_FILEDESCRIPTION_STR "HCA User Mode Verb Provider" +#define VER_INTERNALNAME_STR "mlx4u.dll" +#define VER_ORIGINALFILENAME_STR "mlx4u.dll" +#endif + +#include diff --git a/branches/WOF2-3/hw/mlx4/user/hca/qp.c b/branches/WOF2-3/hw/mlx4/user/hca/qp.c new file mode 100644 index 00000000..12c1ff9f --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/user/hca/qp.c @@ -0,0 +1,780 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies Ltd. All rights reserved. + * Copyright (c) 2007 Cisco, Inc. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "mlx4.h" +#include "doorbell.h" +#include "wqe.h" +#include "mlx4_debug.h" + +#if defined(EVENT_TRACING) +#include "qp.tmh" +#endif + +static enum mlx4_opcode_type __to_opcode(ib_send_wr_t *wr) +{ + + enum mlx4_opcode_type opcode = MLX4_OPCODE_INVALID; + + switch (wr->wr_type) { + case WR_SEND: + opcode = (wr->send_opt & IB_SEND_OPT_IMMEDIATE) ? + MLX4_OPCODE_SEND_IMM : MLX4_OPCODE_SEND; + break; + case WR_RDMA_WRITE: + opcode = (wr->send_opt & IB_SEND_OPT_IMMEDIATE) ? + MLX4_OPCODE_RDMA_WRITE_IMM : MLX4_OPCODE_RDMA_WRITE; + break; + case WR_RDMA_READ: + opcode = MLX4_OPCODE_RDMA_READ; + break; + case WR_COMPARE_SWAP: + opcode = MLX4_OPCODE_ATOMIC_CS; + break; + case WR_FETCH_ADD: + opcode = MLX4_OPCODE_ATOMIC_FA; + break; + default: + opcode = MLX4_OPCODE_INVALID; + break; + } + + return opcode; +} + +static void *get_recv_wqe(struct mlx4_qp *qp, int n) +{ + return qp->buf.buf + qp->rq.offset + (n << qp->rq.wqe_shift); +} + +static void *get_send_wqe(struct mlx4_qp *qp, int n) +{ + return qp->buf.buf + qp->sq.offset + (n << qp->sq.wqe_shift); +} + +/* + * Stamp a SQ WQE so that it is invalid if prefetched by marking the + * first four bytes of every 64 byte chunk with 0xffffffff, except for + * the very first chunk of the WQE. + */ +static void stamp_send_wqe(struct mlx4_qp *qp, int n) +{ + uint32_t *wqe = get_send_wqe(qp, n); + int i; + + for (i = 16; i < 1 << (qp->sq.wqe_shift - 2); i += 16) + wqe[i] = 0xffffffff; +} + +void mlx4_init_qp_indices(struct mlx4_qp *qp) +{ + qp->sq.head = 0; + qp->sq.tail = 0; + qp->rq.head = 0; + qp->rq.tail = 0; +} + +void mlx4_qp_init_sq_ownership(struct mlx4_qp *qp) +{ + struct mlx4_wqe_ctrl_seg *ctrl; + int i; + + for (i = 0; i < qp->sq.wqe_cnt; ++i) { + ctrl = get_send_wqe(qp, i); + ctrl->owner_opcode = htonl((uint32_t)1 << 31); + + stamp_send_wqe(qp, i); + } +} + +static int wq_overflow(struct mlx4_wq *wq, int nreq, struct mlx4_cq *cq) +{ + int cur; + + cur = wq->head - wq->tail; + if (cur + nreq < wq->max_post) + return 0; + + pthread_spin_lock(&cq->lock); + cur = wq->head - wq->tail; + pthread_spin_unlock(&cq->lock); + + return cur + nreq >= wq->max_post; +} + +static inline void set_raddr_seg(struct mlx4_wqe_raddr_seg *rseg, + uint64_t remote_addr, uint32_t rkey) +{ + rseg->raddr = cl_hton64(remote_addr); + rseg->rkey = rkey; + rseg->reserved = 0; +} + +static void set_atomic_seg(struct mlx4_wqe_atomic_seg *aseg, ib_send_wr_t *wr) +{ + if (wr->wr_type == WR_COMPARE_SWAP) { + aseg->swap_add = wr->remote_ops.atomic2; + aseg->compare = wr->remote_ops.atomic1; + } else { + aseg->swap_add = wr->remote_ops.atomic1; + aseg->compare = 0; + } +} + +static void set_datagram_seg(struct mlx4_wqe_datagram_seg *dseg, ib_send_wr_t *wr) +{ + memcpy(dseg->av, &to_mah((struct ibv_ah *)wr->dgrm.ud.h_av)->av, sizeof (struct mlx4_av)); + dseg->dqpn = wr->dgrm.ud.remote_qp; + dseg->qkey = wr->dgrm.ud.remote_qkey; +} + +static void __set_data_seg(struct mlx4_wqe_data_seg *dseg, ib_local_ds_t *ds) +{ + dseg->byte_count = cl_hton32(ds->length); + dseg->lkey = cl_hton32(ds->lkey); + dseg->addr = cl_hton64(ds->vaddr); +} + +static void set_data_seg(struct mlx4_wqe_data_seg *dseg, ib_local_ds_t *ds) +{ + dseg->lkey = cl_hton32(ds->lkey); + dseg->addr = cl_hton64(ds->vaddr); + + /* + * Need a barrier here before writing the byte_count field to + * make sure that all the data is visible before the + * byte_count field is set. Otherwise, if the segment begins + * a new cacheline, the HCA prefetcher could grab the 64-byte + * chunk and get a valid (!= * 0xffffffff) byte count but + * stale data, and end up sending the wrong data. + */ + wmb(); + + dseg->byte_count = cl_hton32(ds->length); +} + +/* + * Avoid using memcpy() to copy to BlueFlame page, since memcpy() + * implementations may use move-string-buffer assembler instructions, + * which do not guarantee order of copying. + */ +static void mlx4_bf_copy(unsigned long *dst, unsigned long *src, unsigned bytecnt) +{ +#ifdef _WIN64 + uint64_t *d = (uint64_t *)dst; + uint64_t *s = (uint64_t *)src; + + while (bytecnt > 0) { + *d++ = *s++; + *d++ = *s++; + bytecnt -= 2 * sizeof (uint64_t); + } +#else + while (bytecnt > 0) { + *dst++ = *src++; + *dst++ = *src++; + bytecnt -= 2 * sizeof (unsigned long); + } +#endif +} + +ib_api_status_t +mlx4_post_send( + IN const void* h_qp, + IN ib_send_wr_t* const p_wr, + OUT ib_send_wr_t** bad_wr) +{ + struct ibv_qp *ibqp = (struct ibv_qp *)/*Ptr64ToPtr(*/h_qp/*)*/; + struct mlx4_qp *qp = to_mqp(ibqp); + struct mlx4_context *ctx; + uint8_t *wqe; + struct mlx4_wqe_ctrl_seg *ctrl = NULL; + enum mlx4_opcode_type opcode; + int ind; + int nreq; + int inl = 0; + ib_api_status_t status = IB_SUCCESS; + ib_send_wr_t *wr = p_wr; + int size = 0; + uint32_t i; + + pthread_spin_lock(&qp->sq.lock); + + /* XXX check that state is OK to post send */ + if(ibqp->state == IBV_QPS_RESET) { + status = IB_INVALID_QP_STATE; + if (bad_wr) + *bad_wr = wr; + goto err_state; + } + + ind = qp->sq.head; + + for (nreq = 0; wr; ++nreq, wr = wr->p_next) { + if (wq_overflow(&qp->sq, nreq, to_mcq(qp->ibv_qp.send_cq))) { + status = IB_INSUFFICIENT_RESOURCES; + if (bad_wr) + *bad_wr = wr; + goto out; + } + + if (wr->num_ds > (uint32_t)qp->sq.max_gs) { + status = IB_INVALID_MAX_SGE; + if (bad_wr) + *bad_wr = wr; + goto out; + } + + opcode = __to_opcode(wr); + if (opcode == MLX4_OPCODE_INVALID) { + status = IB_INVALID_WR_TYPE; + if (bad_wr) + *bad_wr = wr; + goto out; + } + + wqe = get_send_wqe(qp, ind & (qp->sq.wqe_cnt - 1)); + ctrl = (struct mlx4_wqe_ctrl_seg *)wqe; + qp->sq.wrid[ind & (qp->sq.wqe_cnt - 1)] = wr->wr_id; + + ctrl->xrcrb_flags = + (wr->send_opt & IB_SEND_OPT_SIGNALED ? + cl_hton32(MLX4_WQE_CTRL_CQ_UPDATE) : 0) | + (wr->send_opt & IB_SEND_OPT_SOLICITED ? + cl_hton32(MLX4_WQE_CTRL_SOLICIT) : 0) | + qp->sq_signal_bits; + + if (opcode == MLX4_OPCODE_SEND_IMM || + opcode == MLX4_OPCODE_RDMA_WRITE_IMM) + ctrl->imm = wr->immediate_data; + else + ctrl->imm = 0; + + wqe += sizeof *ctrl; + size = sizeof *ctrl / 16; + + switch (ibqp->qp_type) { +#ifdef XRC_SUPPORT + case IBV_QPT_XRC: + // TODO: why is the following line outcommented ? + //ctrl->xrcrb_flags |= cl_hton32(wr->xrc_remote_srq_num << 8); + /* fall thru */ +#endif + case IBV_QPT_RC: + case IBV_QPT_UC: + switch (opcode) { + case MLX4_OPCODE_ATOMIC_CS: + case MLX4_OPCODE_ATOMIC_FA: + set_raddr_seg((struct mlx4_wqe_raddr_seg *)wqe, wr->remote_ops.vaddr, + wr->remote_ops.rkey); + wqe += sizeof (struct mlx4_wqe_raddr_seg); + + set_atomic_seg((struct mlx4_wqe_atomic_seg *)wqe, wr); + wqe += sizeof (struct mlx4_wqe_atomic_seg); + size += (sizeof (struct mlx4_wqe_raddr_seg) + + sizeof (struct mlx4_wqe_atomic_seg)) / 16; + + break; + + case MLX4_OPCODE_RDMA_READ: + inl = 1; + /* fall through */ + case MLX4_OPCODE_RDMA_WRITE: + case MLX4_OPCODE_RDMA_WRITE_IMM: + set_raddr_seg((struct mlx4_wqe_raddr_seg *)wqe, wr->remote_ops.vaddr, + wr->remote_ops.rkey); + wqe += sizeof (struct mlx4_wqe_raddr_seg); + size += sizeof (struct mlx4_wqe_raddr_seg) / 16; + + break; + + default: + /* No extra segments required for sends */ + break; + } + break; + + case IBV_QPT_UD: + set_datagram_seg((struct mlx4_wqe_datagram_seg *)wqe, wr); + wqe += sizeof (struct mlx4_wqe_datagram_seg); + size += sizeof (struct mlx4_wqe_datagram_seg) / 16; + break; + + default: + break; + } + + if (wr->send_opt & IB_SEND_OPT_INLINE && wr->num_ds) { + struct mlx4_wqe_inline_seg *seg; + uint8_t *addr; + int len, seg_len; + int num_seg; + int off, to_copy; + + inl = 0; + + seg = (struct mlx4_wqe_inline_seg *)wqe; + wqe += sizeof *seg; + off = (int)(((uintptr_t) wqe) & (MLX4_INLINE_ALIGN - 1)); + num_seg = 0; + seg_len = 0; + + for (i = 0; i < wr->num_ds; ++i) { + addr = (uint8_t *)(uintptr_t)wr->ds_array[i].vaddr; + len = wr->ds_array[i].length; + inl += len; + + if ((uint32_t)inl > (uint32_t)qp->max_inline_data) { + inl = 0; + status = IB_INVALID_PARAMETER; + *bad_wr = wr; + goto out; + } + + while (len >= MLX4_INLINE_ALIGN - off) { + to_copy = MLX4_INLINE_ALIGN - off; + memcpy(wqe, addr, to_copy); + len -= to_copy; + wqe += to_copy; + addr += to_copy; + seg_len += to_copy; + wmb(); /* see comment below */ + seg->byte_count = htonl(MLX4_INLINE_SEG | seg_len); + seg_len = 0; + seg = (struct mlx4_wqe_inline_seg *)wqe; + wqe += sizeof *seg; + off = sizeof *seg; + ++num_seg; + } + + memcpy(wqe, addr, len); + wqe += len; + seg_len += len; + off += len; + } + + if (seg_len) { + ++num_seg; + /* + * Need a barrier here to make sure + * all the data is visible before the + * byte_count field is set. Otherwise + * the HCA prefetcher could grab the + * 64-byte chunk with this inline + * segment and get a valid (!= + * 0xffffffff) byte count but stale + * data, and end up sending the wrong + * data. + */ + wmb(); + seg->byte_count = htonl(MLX4_INLINE_SEG | seg_len); + } + + size += (inl + num_seg * sizeof * seg + 15) / 16; + } else { + struct mlx4_wqe_data_seg *seg = (struct mlx4_wqe_data_seg *)wqe; + + for (i = wr->num_ds; i > 0; --i) + set_data_seg(seg + i - 1, wr->ds_array + i - 1); + + size += wr->num_ds * (sizeof *seg / 16); + } + + ctrl->fence_size = (uint8_t)((wr->send_opt & IB_SEND_OPT_FENCE ? + MLX4_WQE_CTRL_FENCE : 0) | size); + + /* + * Make sure descriptor is fully written before + * setting ownership bit (because HW can start + * executing as soon as we do). + */ + wmb(); + + ctrl->owner_opcode = htonl(opcode) | + (ind & qp->sq.wqe_cnt ? htonl((uint32_t)1 << 31) : 0); + + /* + * We can improve latency by not stamping the last + * send queue WQE until after ringing the doorbell, so + * only stamp here if there are still more WQEs to post. + */ + if (wr->p_next) + stamp_send_wqe(qp, (ind + qp->sq_spare_wqes) & + (qp->sq.wqe_cnt - 1)); + + ++ind; + + MLX4_PRINT( TRACE_LEVEL_INFORMATION, MLX4_DBG_QP, ("qpn %#x, wr_id %#I64x, ix %d, solicited %d\n", + qp->ibv_qp.qp_num, wr->wr_id, ind - 1, wr->send_opt & IB_SEND_OPT_SOLICITED)); + } + +out: + ctx = to_mctx(ibqp->context); + + if (nreq == 1 && inl && size > 1 && size < ctx->bf_buf_size / 16) { + ctrl->owner_opcode |= htonl((qp->sq.head & 0xffff) << 8); + *(uint32_t *) ctrl->reserved |= qp->doorbell_qpn; + /* + * Make sure that descriptor is written to memory + * before writing to BlueFlame page. + */ + wmb(); + + ++qp->sq.head; + + pthread_spin_lock(&ctx->bf_lock); + + mlx4_bf_copy((unsigned long *) (ctx->bf_page + ctx->bf_offset), + (unsigned long *) ctrl, align(size * 16, 64)); + + wc_wmb(); + + ctx->bf_offset ^= ctx->bf_buf_size; + + pthread_spin_unlock(&ctx->bf_lock); + }else if (nreq) { + qp->sq.head += nreq; + + /* + * Make sure that descriptors are written before + * doorbell record. + */ + wmb(); + + *(uint32_t *) (ctx->uar + MLX4_SEND_DOORBELL) = qp->doorbell_qpn; + } + + if (nreq) + stamp_send_wqe(qp, (ind + qp->sq_spare_wqes - 1) & + (qp->sq.wqe_cnt - 1)); + +err_state: + pthread_spin_unlock(&qp->sq.lock); + + return status; +} + + +ib_api_status_t +mlx4_post_recv( + IN const void* h_qp, + IN ib_recv_wr_t* const p_wr, + OUT ib_recv_wr_t** bad_wr) +{ + struct mlx4_qp *qp = to_mqp((struct ibv_qp *)/*Ptr64ToPtr(*/h_qp/*)*/); + struct mlx4_wqe_data_seg *scat; + ib_api_status_t status = IB_SUCCESS; + ib_recv_wr_t *wr = p_wr; + int nreq; + int ind; + uint32_t i; + + pthread_spin_lock(&qp->rq.lock); + + /* XXX check that state is OK to post receive */ + if(qp->ibv_qp.state == IBV_QPS_RESET) { + status = IB_INVALID_QP_STATE; + if (bad_wr) + *bad_wr = wr; + goto err_state; + } + + ind = qp->rq.head & (qp->rq.wqe_cnt - 1); + + for (nreq = 0; wr; ++nreq, wr = wr->p_next) { + if (wq_overflow(&qp->rq, nreq, to_mcq(qp->ibv_qp.recv_cq))) { + status = IB_INSUFFICIENT_RESOURCES; + if (bad_wr) + *bad_wr = wr; + goto out; + } + + if (wr->num_ds > (uint32_t)qp->rq.max_gs) { + status = IB_INVALID_MAX_SGE; + if (bad_wr) + *bad_wr = wr; + goto out; + } + + scat = get_recv_wqe(qp, ind); + + for (i = 0; i < wr->num_ds; ++i) + __set_data_seg(scat + i, wr->ds_array + i); + + if (i < (uint32_t)qp->rq.max_gs) { + scat[i].byte_count = 0; + scat[i].lkey = htonl(MLX4_INVALID_LKEY); + scat[i].addr = 0; + } + + qp->rq.wrid[ind] = wr->wr_id; + + ind = (ind + 1) & (qp->rq.wqe_cnt - 1); + + MLX4_PRINT( TRACE_LEVEL_INFORMATION, MLX4_DBG_QP, ("qpn %#x, wr_id %#I64x, ix %d, \n", + qp->ibv_qp.qp_num, wr->wr_id, ind - 1)); + } + +out: + if (nreq) { + qp->rq.head += nreq; + + /* + * Make sure that descriptors are written before + * doorbell record. + */ + wmb(); + + *qp->db = htonl(qp->rq.head & 0xffff); + } + +err_state: + pthread_spin_unlock(&qp->rq.lock); + + return status; +} + +static int num_inline_segs(int data, enum ibv_qp_type type) +{ + /* + * Inline data segments are not allowed to cross 64 byte + * boundaries. For UD QPs, the data segments always start + * aligned to 64 bytes (16 byte control segment + 48 byte + * datagram segment); for other QPs, there will be a 16 byte + * control segment and possibly a 16 byte remote address + * segment, so in the worst case there will be only 32 bytes + * available for the first data segment. + */ + if (type == IBV_QPT_UD) + data += (sizeof (struct mlx4_wqe_ctrl_seg) + + sizeof (struct mlx4_wqe_datagram_seg)) % + MLX4_INLINE_ALIGN; + else + data += (sizeof (struct mlx4_wqe_ctrl_seg) + + sizeof (struct mlx4_wqe_raddr_seg)) % + MLX4_INLINE_ALIGN; + + return (int)(data + MLX4_INLINE_ALIGN - sizeof (struct mlx4_wqe_inline_seg) - 1) / + (MLX4_INLINE_ALIGN - sizeof (struct mlx4_wqe_inline_seg)); +} + +void mlx4_calc_sq_wqe_size(struct ibv_qp_cap *cap, enum ibv_qp_type type, + struct mlx4_qp *qp) +{ + int size; + unsigned max_sq_sge; + + max_sq_sge = align(cap->max_inline_data + + num_inline_segs(cap->max_inline_data, type) * + sizeof (struct mlx4_wqe_inline_seg), + sizeof (struct mlx4_wqe_data_seg)) / + sizeof (struct mlx4_wqe_data_seg); + if (max_sq_sge < cap->max_send_sge) + max_sq_sge = cap->max_send_sge; + + size = max_sq_sge * sizeof (struct mlx4_wqe_data_seg); + switch (type) { + case IBV_QPT_UD: + size += sizeof (struct mlx4_wqe_datagram_seg); + break; + + case IBV_QPT_UC: + size += sizeof (struct mlx4_wqe_raddr_seg); + break; + +#ifdef XRC_SUPPORT + case IBV_QPT_XRC: +#endif + case IBV_QPT_RC: + size += sizeof (struct mlx4_wqe_raddr_seg); + /* + * An atomic op will require an atomic segment, a + * remote address segment and one scatter entry. + */ + if (size < (sizeof (struct mlx4_wqe_atomic_seg) + + sizeof (struct mlx4_wqe_raddr_seg) + + sizeof (struct mlx4_wqe_data_seg))) + size = (sizeof (struct mlx4_wqe_atomic_seg) + + sizeof (struct mlx4_wqe_raddr_seg) + + sizeof (struct mlx4_wqe_data_seg)); + break; + + default: + break; + } + + /* Make sure that we have enough space for a bind request */ + if (size < sizeof (struct mlx4_wqe_bind_seg)) + size = sizeof (struct mlx4_wqe_bind_seg); + + size += sizeof (struct mlx4_wqe_ctrl_seg); + + for (qp->sq.wqe_shift = 6; 1 << qp->sq.wqe_shift < size; + qp->sq.wqe_shift++) + ; /* nothing */ +} + +int mlx4_alloc_qp_buf(struct ibv_pd *pd, struct ibv_qp_cap *cap, + enum ibv_qp_type type, struct mlx4_qp *qp) +{ + UNREFERENCED_PARAMETER(type); + + qp->rq.max_gs = cap->max_recv_sge; + + qp->sq.wrid = malloc(qp->sq.wqe_cnt * sizeof (uint64_t)); + if (!qp->sq.wrid) + return -1; + + if (qp->rq.wqe_cnt) { + qp->rq.wrid = malloc(qp->rq.wqe_cnt * sizeof (uint64_t)); + if (!qp->rq.wrid) { + free(qp->sq.wrid); + return -1; + } + } + + for (qp->rq.wqe_shift = 4; + (1 << qp->rq.wqe_shift) < qp->rq.max_gs * (int) sizeof (struct mlx4_wqe_data_seg); + qp->rq.wqe_shift++) + ; /* nothing */ + + qp->buf_size = (qp->rq.wqe_cnt << qp->rq.wqe_shift) + + (qp->sq.wqe_cnt << qp->sq.wqe_shift); + if (qp->rq.wqe_shift > qp->sq.wqe_shift) { + qp->rq.offset = 0; + qp->sq.offset = qp->rq.wqe_cnt << qp->rq.wqe_shift; + } else { + qp->rq.offset = qp->sq.wqe_cnt << qp->sq.wqe_shift; + qp->sq.offset = 0; + } + + if (mlx4_alloc_buf(&qp->buf, qp->buf_size, pd->context->page_size)) { + free(qp->sq.wrid); + if (qp->rq.wqe_cnt) + free(qp->rq.wrid); + return -1; + } + + mlx4_qp_init_sq_ownership(qp); + + return 0; +} + +void mlx4_set_sq_sizes(struct mlx4_qp *qp, struct ibv_qp_cap *cap, + enum ibv_qp_type type) +{ + int wqe_size; + struct mlx4_context *ctx = to_mctx(qp->ibv_qp.context); + + wqe_size = (1 << qp->sq.wqe_shift) - (int) sizeof (struct mlx4_wqe_ctrl_seg); + + switch (type) { + case IBV_QPT_UD: + wqe_size -= sizeof (struct mlx4_wqe_datagram_seg); + break; + + case IBV_QPT_UC: + case IBV_QPT_RC: +#ifdef XRC_SUPPORT + case IBV_QPT_XRC: +#endif + wqe_size -= sizeof (struct mlx4_wqe_raddr_seg); + break; + + default: + break; + } + + qp->sq.max_gs = wqe_size / sizeof (struct mlx4_wqe_data_seg); + cap->max_send_sge = min(ctx->max_sge, qp->sq.max_gs); + qp->sq.max_post = min(ctx->max_qp_wr, + qp->sq.wqe_cnt - qp->sq_spare_wqes); + cap->max_send_wr = qp->sq.max_post; + + /* + * Inline data segments can't cross a 64 byte boundary. So + * subtract off one segment header for each 64-byte chunk, + * taking into account the fact that wqe_size will be 32 mod + * 64 for non-UD QPs. + */ + qp->max_inline_data = wqe_size - + (int) sizeof (struct mlx4_wqe_inline_seg) * + (align(wqe_size, MLX4_INLINE_ALIGN) / MLX4_INLINE_ALIGN); + cap->max_inline_data = qp->max_inline_data; +} + +struct mlx4_qp *mlx4_find_qp(struct mlx4_context *ctx, uint32_t qpn) +{ + int tind = (qpn & (ctx->num_qps - 1)) >> ctx->qp_table_shift; + + if (ctx->qp_table[tind].refcnt) + return ctx->qp_table[tind].table[qpn & ctx->qp_table_mask]; + else + return NULL; +} + +int mlx4_store_qp(struct mlx4_context *ctx, uint32_t qpn, struct mlx4_qp *qp) +{ + int tind = (qpn & (ctx->num_qps - 1)) >> ctx->qp_table_shift; + int ret = 0; + + pthread_mutex_lock(&ctx->qp_table_mutex); + + if (!ctx->qp_table[tind].refcnt) { + ctx->qp_table[tind].table = calloc(ctx->qp_table_mask + 1, + sizeof (struct mlx4_qp *)); + if (!ctx->qp_table[tind].table) { + ret = -1; + goto out; + } + } + + ++ctx->qp_table[tind].refcnt; + ctx->qp_table[tind].table[qpn & ctx->qp_table_mask] = qp; + +out: + pthread_mutex_unlock(&ctx->qp_table_mutex); + return ret; +} + +void mlx4_clear_qp(struct mlx4_context *ctx, uint32_t qpn) +{ + int tind = (qpn & (ctx->num_qps - 1)) >> ctx->qp_table_shift; + + pthread_mutex_lock(&ctx->qp_table_mutex); + + if (!--ctx->qp_table[tind].refcnt) + free(ctx->qp_table[tind].table); + else + ctx->qp_table[tind].table[qpn & ctx->qp_table_mask] = NULL; + + pthread_mutex_unlock(&ctx->qp_table_mutex); +} diff --git a/branches/WOF2-3/hw/mlx4/user/hca/srq.c b/branches/WOF2-3/hw/mlx4/user/hca/srq.c new file mode 100644 index 00000000..c5e9ac89 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/user/hca/srq.c @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2007 Cisco, Inc. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "mlx4.h" +#include "doorbell.h" +#include "wqe.h" + +static void *get_wqe(struct mlx4_srq *srq, int n) +{ + return srq->buf.buf + (n << srq->wqe_shift); +} + +void mlx4_free_srq_wqe(struct mlx4_srq *srq, int ind) +{ + struct mlx4_wqe_srq_next_seg *next; + + pthread_spin_lock(&srq->lock); + + next = get_wqe(srq, srq->tail); + next->next_wqe_index = htons((uint16_t)ind); + srq->tail = ind; + + pthread_spin_unlock(&srq->lock); +} + +ib_api_status_t +mlx4_post_srq_recv( + IN const void* h_srq, + IN ib_recv_wr_t* const p_wr, + OUT ib_recv_wr_t** bad_wr) +{ + struct mlx4_srq *srq = to_msrq((struct ibv_srq *)/*Ptr64ToPtr(*/h_srq/*)*/); + struct mlx4_wqe_srq_next_seg *next; + struct mlx4_wqe_data_seg *scat; + ib_api_status_t status = IB_SUCCESS; + ib_recv_wr_t *wr = p_wr; + uint16_t nreq; + uint32_t i; + + pthread_spin_lock(&srq->lock); + + for (nreq = 0; wr; ++nreq, wr = wr->p_next) { + if (wr->num_ds > (uint32_t)srq->max_gs) { + status = IB_INVALID_MAX_SGE; + *bad_wr = wr; + break; + } + + if (srq->head == srq->tail) { + /* SRQ is full*/ + status = IB_INSUFFICIENT_RESOURCES; + *bad_wr = wr; + break; + } + + srq->wrid[srq->head] = wr->wr_id; + + next = get_wqe(srq, srq->head); + srq->head = ntohs(next->next_wqe_index); + scat = (struct mlx4_wqe_data_seg *) (next + 1); + + for (i = 0; i < wr->num_ds; ++i) { + scat[i].byte_count = htonl(wr->ds_array[i].length); + scat[i].lkey = htonl(wr->ds_array[i].lkey); + scat[i].addr = htonll(wr->ds_array[i].vaddr); + } + + if (i < (uint32_t)srq->max_gs) { + scat[i].byte_count = 0; + scat[i].lkey = htonl(MLX4_INVALID_LKEY); + scat[i].addr = 0; + } + } + + if (nreq) { + srq->counter = srq->counter + nreq; + + /* + * Make sure that descriptors are written before + * we write doorbell record. + */ + wmb(); + + *srq->db = htonl(srq->counter); + } + + pthread_spin_unlock(&srq->lock); + + return status; +} + +int mlx4_alloc_srq_buf(struct ibv_pd *pd, struct ibv_srq_attr *attr, + struct mlx4_srq *srq) +{ + struct mlx4_wqe_srq_next_seg *next; + int size; + int buf_size; + int i; + + UNREFERENCED_PARAMETER(attr); + + srq->wrid = malloc(srq->max * sizeof (uint64_t)); + if (!srq->wrid) + return -1; + + size = sizeof (struct mlx4_wqe_srq_next_seg) + + srq->max_gs * sizeof (struct mlx4_wqe_data_seg); + + for (srq->wqe_shift = 5; 1 << srq->wqe_shift < size; ++srq->wqe_shift) + ; /* nothing */ + + buf_size = srq->max << srq->wqe_shift; + + if (mlx4_alloc_buf(&srq->buf, buf_size, + pd->context->page_size)) { + free(srq->wrid); + return -1; + } + + /* + * Now initialize the SRQ buffer so that all of the WQEs are + * linked into the list of free WQEs. + */ + + for (i = 0; i < srq->max; ++i) { + next = get_wqe(srq, i); + next->next_wqe_index = htons((uint16_t)((i + 1) & (srq->max - 1))); + } + + srq->head = 0; + srq->tail = srq->max - 1; + + return 0; +} + +#ifdef XRC_SUPPORT +struct mlx4_srq *mlx4_find_xrc_srq(struct mlx4_context *ctx, uint32_t xrc_srqn) +{ + int tind = (xrc_srqn & (ctx->num_xrc_srqs - 1)) >> ctx->xrc_srq_table_shift; + + if (ctx->xrc_srq_table[tind].refcnt) + return ctx->xrc_srq_table[tind].table[xrc_srqn & ctx->xrc_srq_table_mask]; + else + return NULL; +} + +int mlx4_store_xrc_srq(struct mlx4_context *ctx, uint32_t xrc_srqn, + struct mlx4_srq *srq) +{ + int tind = (xrc_srqn & (ctx->num_xrc_srqs - 1)) >> ctx->xrc_srq_table_shift; + int ret = 0; + + pthread_mutex_lock(&ctx->xrc_srq_table_mutex); + + if (!ctx->xrc_srq_table[tind].refcnt) { + ctx->xrc_srq_table[tind].table = calloc(ctx->xrc_srq_table_mask + 1, + sizeof (struct mlx4_srq *)); + if (!ctx->xrc_srq_table[tind].table) { + ret = -1; + goto out; + } + } + + ++ctx->xrc_srq_table[tind].refcnt; + ctx->xrc_srq_table[tind].table[xrc_srqn & ctx->xrc_srq_table_mask] = srq; + +out: + pthread_mutex_unlock(&ctx->xrc_srq_table_mutex); + return ret; +} + +void mlx4_clear_xrc_srq(struct mlx4_context *ctx, uint32_t xrc_srqn) +{ + int tind = (xrc_srqn & (ctx->num_xrc_srqs - 1)) >> ctx->xrc_srq_table_shift; + + pthread_mutex_lock(&ctx->xrc_srq_table_mutex); + + if (!--ctx->xrc_srq_table[tind].refcnt) + free(ctx->xrc_srq_table[tind].table); + else + ctx->xrc_srq_table[tind].table[xrc_srqn & ctx->xrc_srq_table_mask] = NULL; + + pthread_mutex_unlock(&ctx->xrc_srq_table_mutex); +} +#endif diff --git a/branches/WOF2-3/hw/mlx4/user/hca/verbs.c b/branches/WOF2-3/hw/mlx4/user/hca/verbs.c new file mode 100644 index 00000000..a39de5a6 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/user/hca/verbs.c @@ -0,0 +1,1470 @@ +/* + * Copyright (c) 2007 Cisco, Inc. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "mlx4.h" +#include "verbs.h" +#include "mx_abi.h" +#include "wqe.h" +#include "mlx4_debug.h" + +#if defined(EVENT_TRACING) +#include "verbs.tmh" +#endif + +ib_api_status_t +mlx4_pre_open_ca ( + IN const ib_net64_t ca_guid, + IN OUT ci_umv_buf_t *p_umv_buf, + OUT ib_ca_handle_t *ph_uvp_ca ) +{ + struct ibv_context *context; + ib_api_status_t status = IB_SUCCESS; + + UNREFERENCED_PARAMETER(ca_guid); + + context = mlx4_alloc_context(); + if (!context) { + status = IB_INSUFFICIENT_MEMORY; + goto end; + } + + if( p_umv_buf ) + { + p_umv_buf->p_inout_buf = (ULONG_PTR)cl_zalloc( sizeof(struct ibv_get_context_resp) ); + if( !p_umv_buf->p_inout_buf ) + { + status = IB_INSUFFICIENT_MEMORY; + goto end; + } + p_umv_buf->input_size = 0; + p_umv_buf->output_size = sizeof(struct ibv_get_context_resp); + p_umv_buf->command = TRUE; + } + + *ph_uvp_ca = (ib_ca_handle_t)context; + +end: + return status; +} + +ib_api_status_t +mlx4_post_open_ca ( + IN const ib_net64_t ca_guid, + IN ib_api_status_t ioctl_status, + IN OUT ib_ca_handle_t *ph_uvp_ca, + IN ci_umv_buf_t *p_umv_buf ) +{ + struct ibv_get_context_resp *p_resp; + struct ibv_context *context = (struct ibv_context *)*ph_uvp_ca; + ib_api_status_t status = IB_SUCCESS; + + UNREFERENCED_PARAMETER(ca_guid); + + CL_ASSERT(p_umv_buf && p_umv_buf->p_inout_buf); + + p_resp = (struct ibv_get_context_resp*)(ULONG_PTR)p_umv_buf->p_inout_buf; + + if (IB_SUCCESS == ioctl_status) + { + if (!mlx4_fill_context(context, p_resp)) + { + status = IB_INSUFFICIENT_RESOURCES; + *ph_uvp_ca = NULL; + goto end; + } + } + +end: + cl_free(p_resp); + return status; +} + +ib_api_status_t +mlx4_post_close_ca ( + IN ib_ca_handle_t h_uvp_ca, + IN ib_api_status_t ioctl_status ) +{ + struct ibv_context *context = (struct ibv_context *)h_uvp_ca; + + CL_ASSERT(context); + + if (IB_SUCCESS == ioctl_status) + + mlx4_free_context(context); + + return IB_SUCCESS; +} + +ib_api_status_t +mlx4_pre_alloc_pd ( + IN const ib_ca_handle_t h_uvp_ca, + IN OUT ci_umv_buf_t *p_umv_buf, + OUT ib_pd_handle_t *ph_uvp_pd ) +{ + struct mlx4_pd *pd; + struct ibv_context *context = (struct ibv_context *)h_uvp_ca; + ib_api_status_t status = IB_SUCCESS; + + CL_ASSERT(context && p_umv_buf); + + p_umv_buf->p_inout_buf = (ULONG_PTR)cl_malloc( sizeof(struct ibv_alloc_pd_resp) ); + if( !p_umv_buf->p_inout_buf ) + { + status = IB_INSUFFICIENT_MEMORY; + goto end; + } + p_umv_buf->input_size = 0; + p_umv_buf->output_size = sizeof(struct ibv_alloc_pd_resp); + p_umv_buf->command = TRUE; + + // Mlx4 code: + + pd = cl_malloc(sizeof *pd); + if (!pd) { + status = IB_INSUFFICIENT_MEMORY; + goto end; + } + + pd->ibv_pd.context = context; + + *ph_uvp_pd = (ib_pd_handle_t)&pd->ibv_pd; + +end: + return status; +} + +void +mlx4_post_alloc_pd ( + IN ib_ca_handle_t h_uvp_ca, + IN ib_api_status_t ioctl_status, + IN OUT ib_pd_handle_t *ph_uvp_pd, + IN ci_umv_buf_t *p_umv_buf ) +{ + struct ibv_pd *pd = (struct ibv_pd *)*ph_uvp_pd; + struct ibv_alloc_pd_resp *p_resp; + + + UNREFERENCED_PARAMETER(h_uvp_ca); + + CL_ASSERT(p_umv_buf && p_umv_buf->p_inout_buf); + + p_resp = (struct ibv_alloc_pd_resp*)(ULONG_PTR)p_umv_buf->p_inout_buf; + + if (IB_SUCCESS == ioctl_status) + { + // Mlx4 code: + + pd->handle = p_resp->pd_handle; + to_mpd(pd)->pdn = p_resp->pdn; + } + else + { + cl_free(to_mpd(pd)); + *ph_uvp_pd = NULL; + } + + cl_free(p_resp); + return; +} + +void +mlx4_post_free_pd ( + IN const ib_pd_handle_t h_uvp_pd, + IN ib_api_status_t ioctl_status ) +{ + struct ibv_pd *pd = (struct ibv_pd *)h_uvp_pd; + + CL_ASSERT(pd); + + if (IB_SUCCESS == ioctl_status) + cl_free(to_mpd(pd)); +} + +static int __align_queue_size(int req) +{ + int nent; + + for (nent = 1; nent < req; nent <<= 1) + ; /* nothing */ + + return nent; +} + +ib_api_status_t +mlx4_pre_create_cq ( + IN const ib_ca_handle_t h_uvp_ca, + IN OUT uint32_t* const p_size, + IN OUT ci_umv_buf_t *p_umv_buf, + OUT ib_cq_handle_t *ph_uvp_cq ) +{ + struct mlx4_cq *cq; + struct ibv_create_cq *p_create_cq; + struct ibv_context *context = (struct ibv_context *)h_uvp_ca; + ib_api_status_t status = IB_SUCCESS; + int size = max( sizeof(struct ibv_create_cq), sizeof(struct ibv_create_cq_resp) ); + + CL_ASSERT(h_uvp_ca && p_umv_buf); + + p_umv_buf->p_inout_buf = (ULONG_PTR)cl_malloc( size ); + if( !p_umv_buf->p_inout_buf ) + { + status = IB_INSUFFICIENT_MEMORY; + goto err_umv_buf; + } + p_umv_buf->input_size = sizeof(struct ibv_create_cq); + p_umv_buf->output_size = sizeof(struct ibv_create_cq_resp); + p_umv_buf->command = TRUE; + + p_create_cq = (struct ibv_create_cq*)(ULONG_PTR)p_umv_buf->p_inout_buf; + + // Mlx4 code: + + /* Sanity check CQ size before proceeding */ + if (*p_size > 0x3fffff) { + status = IB_INVALID_CQ_SIZE; + goto err_cqe_size; + } + + cq = cl_malloc(sizeof *cq); + if (!cq) { + status = IB_INSUFFICIENT_MEMORY; + goto err_cq; + } + + if (cl_spinlock_init(&cq->lock)) { + status = IB_INSUFFICIENT_MEMORY; + goto err_lock; + } + + *p_size = __align_queue_size(*p_size + 1); + + if (mlx4_alloc_buf(&cq->buf, *p_size * MLX4_CQ_ENTRY_SIZE, + context->page_size)) + goto err_alloc_buf; + + cq->ibv_cq.context = context; + cq->cons_index = 0; + + cq->set_ci_db = mlx4_alloc_db(to_mctx(context), MLX4_DB_TYPE_CQ); + if (!cq->set_ci_db) + goto err_alloc_db; + + cq->arm_db = cq->set_ci_db + 1; + *cq->arm_db = 0; + cq->arm_sn = 1; + *cq->set_ci_db = 0; + + p_create_cq->buf_addr = (uintptr_t) cq->buf.buf; + p_create_cq->db_addr = (uintptr_t) cq->set_ci_db; + p_create_cq->arm_sn_addr = (uintptr_t) &cq->arm_sn; + p_create_cq->cqe = --(*p_size); + + *ph_uvp_cq = (ib_cq_handle_t)&cq->ibv_cq; + goto end; + +err_alloc_db: + mlx4_free_buf(&cq->buf); +err_alloc_buf: + cl_spinlock_destroy(&cq->lock); +err_lock: + cl_free(cq); +err_cq: +err_cqe_size: + cl_free( (void*)(ULONG_PTR)p_umv_buf->p_inout_buf ); +err_umv_buf: +end: + return status; +} + +void +mlx4_post_create_cq ( + IN const ib_ca_handle_t h_uvp_ca, + IN ib_api_status_t ioctl_status, + IN const uint32_t size, + IN OUT ib_cq_handle_t *ph_uvp_cq, + IN ci_umv_buf_t *p_umv_buf ) +{ + struct ibv_cq *cq = (struct ibv_cq *)*ph_uvp_cq; + struct ibv_create_cq_resp *p_resp; + + UNREFERENCED_PARAMETER(h_uvp_ca); + UNREFERENCED_PARAMETER(size); + + CL_ASSERT(p_umv_buf && p_umv_buf->p_inout_buf); + + p_resp = (struct ibv_create_cq_resp*)(ULONG_PTR)p_umv_buf->p_inout_buf; + + if (IB_SUCCESS == ioctl_status) + { + // Mlx4 code: + + to_mcq(cq)->cqn = p_resp->cqn; + cq->cqe = p_resp->cqe; + cq->handle = p_resp->cq_handle; + } + else + { + mlx4_post_destroy_cq (*ph_uvp_cq, IB_SUCCESS); + *ph_uvp_cq = NULL; + } + + cl_free(p_resp); + return; +} + +ib_api_status_t +mlx4_pre_query_cq ( + IN const ib_cq_handle_t h_uvp_cq, + OUT uint32_t* const p_size, + IN OUT ci_umv_buf_t *p_umv_buf ) +{ + struct ibv_cq *cq = (struct ibv_cq *)h_uvp_cq; + + UNREFERENCED_PARAMETER(p_umv_buf); + + *p_size = cq->cqe; + + return IB_VERBS_PROCESSING_DONE; +} + +void +mlx4_post_destroy_cq ( + IN const ib_cq_handle_t h_uvp_cq, + IN ib_api_status_t ioctl_status ) +{ + struct ibv_cq *cq = (struct ibv_cq *)h_uvp_cq; + + CL_ASSERT(cq); + + if (IB_SUCCESS == ioctl_status) { + mlx4_free_db(to_mctx(cq->context), MLX4_DB_TYPE_CQ, to_mcq(cq)->set_ci_db); + mlx4_free_buf(&to_mcq(cq)->buf); + + cl_spinlock_destroy(&to_mcq(cq)->lock); + cl_free(to_mcq(cq)); + } +} + +ib_api_status_t +mlx4_pre_create_srq ( + IN const ib_pd_handle_t h_uvp_pd, + IN const ib_srq_attr_t *p_srq_attr, + IN OUT ci_umv_buf_t *p_umv_buf, + OUT ib_srq_handle_t *ph_uvp_srq ) +{ + struct mlx4_srq *srq; + struct ibv_create_srq *p_create_srq; + struct ibv_pd *pd = (struct ibv_pd *)h_uvp_pd; + ib_api_status_t status = IB_SUCCESS; + size_t size = max( sizeof(struct ibv_create_srq), sizeof(struct ibv_create_srq_resp) ); + + CL_ASSERT(p_umv_buf); + + p_umv_buf->p_inout_buf = (ULONG_PTR)cl_malloc( size ); + if( !p_umv_buf->p_inout_buf ) + { + status = IB_INSUFFICIENT_MEMORY; + goto err_memory; + } + p_umv_buf->input_size = sizeof(struct ibv_create_srq); + p_umv_buf->output_size = sizeof(struct ibv_create_srq_resp); + p_umv_buf->command = TRUE; + + p_create_srq = (struct ibv_create_srq*)(ULONG_PTR)p_umv_buf->p_inout_buf; + + // Mlx4 code: + + /* Sanity check SRQ size before proceeding */ + if (p_srq_attr->max_wr > 1 << 16 || p_srq_attr->max_sge > 64) + { + status = IB_INVALID_PARAMETER; + goto err_params; + } + + srq = cl_malloc(sizeof *srq); + if (!srq) { + status = IB_INSUFFICIENT_MEMORY; + goto err_alloc_srq; + } + + if (cl_spinlock_init(&srq->lock)) { + status = IB_INSUFFICIENT_MEMORY; + goto err_lock; + } + + srq->ibv_srq.pd = pd; + srq->ibv_srq.context = pd->context; + + srq->max = __align_queue_size(p_srq_attr->max_wr + 1); + srq->max_gs = p_srq_attr->max_sge; + srq->counter = 0; + + if (mlx4_alloc_srq_buf(pd, (struct ibv_srq_attr *)p_srq_attr, srq)) + { + status = IB_INSUFFICIENT_MEMORY; + goto err_alloc_buf; + } + + srq->db = mlx4_alloc_db(to_mctx(pd->context), MLX4_DB_TYPE_RQ); + if (!srq->db) + goto err_alloc_db; + + *srq->db = 0; + + // fill the parameters for ioctl + p_create_srq->buf_addr = (uintptr_t) srq->buf.buf; + p_create_srq->db_addr = (uintptr_t) srq->db; + p_create_srq->pd_handle = pd->handle; + p_create_srq->max_wr = p_srq_attr->max_wr; + p_create_srq->max_sge = p_srq_attr->max_sge; + p_create_srq->srq_limit = p_srq_attr->srq_limit; + + *ph_uvp_srq = (ib_srq_handle_t)&srq->ibv_srq; + goto end; + +err_alloc_db: + cl_free(srq->wrid); + mlx4_free_buf(&srq->buf); +err_alloc_buf: + cl_spinlock_destroy(&srq->lock); +err_lock: + cl_free(srq); +err_alloc_srq: + cl_free( (void*)(ULONG_PTR)p_umv_buf->p_inout_buf ); +err_params: err_memory: +end: + return status; +} + +void +mlx4_post_create_srq ( + IN const ib_pd_handle_t h_uvp_pd, + IN ib_api_status_t ioctl_status, + IN OUT ib_srq_handle_t *ph_uvp_srq, + IN ci_umv_buf_t *p_umv_buf ) +{ + struct ibv_srq *ibsrq = (struct ibv_srq *)*ph_uvp_srq; + struct mlx4_srq *srq = to_msrq(ibsrq); + struct ibv_create_srq_resp *p_resp; + + UNREFERENCED_PARAMETER(h_uvp_pd); + + CL_ASSERT(p_umv_buf && p_umv_buf->p_inout_buf); + + p_resp = (struct ibv_create_srq_resp*)(ULONG_PTR)p_umv_buf->p_inout_buf; + + if (IB_SUCCESS == ioctl_status) + { + // Mlx4 code: + + srq->srqn = p_resp->srqn; + ibsrq->handle = p_resp->srq_handle; + + srq->max = p_resp->max_wr; + srq->max_gs = p_resp->max_sge; + } + else + { + mlx4_post_destroy_srq (*ph_uvp_srq, IB_SUCCESS); + *ph_uvp_srq = NULL; + } + + cl_free(p_resp); + return; +} + +ib_api_status_t +mlx4_pre_destroy_srq ( + IN const ib_srq_handle_t h_uvp_srq ) +{ +#ifdef XRC_SUPPORT + struct ibv_srq *ibsrq = (struct ibv_srq *)h_uvp_srq; + struct mlx4_srq *srq = to_msrq(ibsrq); + struct mlx4_cq *mcq = NULL; + + if (ibsrq->xrc_cq) + { + /* is an xrc_srq */ + mcq = to_mcq(ibsrq->xrc_cq); + mlx4_cq_clean(mcq, 0, srq); + cl_spinlock_acquire(&mcq->lock); + mlx4_clear_xrc_srq(to_mctx(ibsrq->context), srq->srqn); + cl_spinlock_release(&mcq->lock); + } +#else + UNUSED_PARAM(h_uvp_srq); +#endif + return IB_SUCCESS; +} + +void +mlx4_post_destroy_srq ( + IN const ib_srq_handle_t h_uvp_srq, + IN ib_api_status_t ioctl_status ) +{ + struct ibv_srq *ibsrq = (struct ibv_srq *)h_uvp_srq; + struct mlx4_srq *srq = to_msrq(ibsrq); + + CL_ASSERT(srq); + + if (IB_SUCCESS == ioctl_status) + { + mlx4_free_db(to_mctx(ibsrq->context), MLX4_DB_TYPE_RQ, srq->db); + cl_free(srq->wrid); + mlx4_free_buf(&srq->buf); + cl_spinlock_destroy(&srq->lock); + cl_free(srq); + } + else + { +#ifdef XRC_SUPPORT + if (ibsrq->xrc_cq) { + /* is an xrc_srq */ + struct mlx4_cq *mcq = to_mcq(ibsrq->xrc_cq); + cl_spinlock_acquire(&mcq->lock); + mlx4_store_xrc_srq(to_mctx(ibsrq->context), srq->srqn, srq); + cl_spinlock_release(&mcq->lock); + } +#endif + } +} + +static enum ibv_qp_type +__to_qp_type(ib_qp_type_t type) +{ + switch (type) { + case IB_QPT_RELIABLE_CONN: return IBV_QPT_RC; + case IB_QPT_UNRELIABLE_CONN: return IBV_QPT_UC; + case IB_QPT_UNRELIABLE_DGRM: return IBV_QPT_UD; +#ifdef XRC_SUPPORT + //case IB_QPT_XRC_CONN: return IBV_QPT_XRC; +#endif + default: return IBV_QPT_RC; + } +} + +ib_api_status_t +mlx4_pre_create_qp ( + IN const ib_pd_handle_t h_uvp_pd, + IN const ib_qp_create_t *p_create_attr, + IN OUT ci_umv_buf_t *p_umv_buf, + OUT ib_qp_handle_t *ph_uvp_qp ) +{ + struct ibv_pd *pd = (struct ibv_pd *)h_uvp_pd; + struct mlx4_context *context = to_mctx(pd->context); + struct mlx4_qp *qp; + struct ibv_create_qp *p_create_qp; + struct ibv_qp_init_attr attr; + ib_api_status_t status = IB_SUCCESS; + int size = max( sizeof(struct ibv_create_qp), sizeof(struct ibv_create_qp_resp) ); + + CL_ASSERT(p_umv_buf); + + p_umv_buf->p_inout_buf = (ULONG_PTR)cl_malloc(size); + if( !p_umv_buf->p_inout_buf ) + { + status = IB_INSUFFICIENT_MEMORY; + goto err_memory; + } + p_umv_buf->input_size = sizeof(struct ibv_create_qp); + p_umv_buf->output_size = sizeof(struct ibv_create_qp_resp); + p_umv_buf->command = TRUE; + + p_create_qp = (struct ibv_create_qp*)(ULONG_PTR)p_umv_buf->p_inout_buf; + + /* convert attributes */ + memset( &attr, 0, sizeof(attr) ); + attr.send_cq = (struct ibv_cq *)p_create_attr->h_sq_cq; + attr.recv_cq = (struct ibv_cq *)p_create_attr->h_rq_cq; + attr.srq = (struct ibv_srq*)p_create_attr->h_srq; + attr.cap.max_send_wr = p_create_attr->sq_depth; + attr.cap.max_recv_wr = p_create_attr->rq_depth; + attr.cap.max_send_sge = p_create_attr->sq_sge; + attr.cap.max_recv_sge = p_create_attr->rq_sge; + attr.cap.max_inline_data = p_create_attr->sq_max_inline; + attr.qp_type = __to_qp_type(p_create_attr->qp_type); + attr.sq_sig_all = p_create_attr->sq_signaled; + + // Mlx4 code: + + /* Sanity check QP size before proceeding */ + if (attr.cap.max_send_wr > (uint32_t) context->max_qp_wr || + attr.cap.max_recv_wr > (uint32_t) context->max_qp_wr || + attr.cap.max_send_sge > (uint32_t) context->max_sge || + attr.cap.max_recv_sge > (uint32_t) context->max_sge || + attr.cap.max_inline_data > 1024) + { + status = IB_INVALID_PARAMETER; + goto end; + } + + qp = cl_malloc(sizeof *qp); + if (!qp) { + status = IB_INSUFFICIENT_MEMORY; + goto err_alloc_qp; + } + + mlx4_calc_sq_wqe_size(&attr.cap, attr.qp_type, qp); + + /* + * We need to leave 2 KB + 1 WQE of headroom in the SQ to + * allow HW to prefetch. + */ + qp->sq_spare_wqes = (2048 >> qp->sq.wqe_shift) + 1; + qp->sq.wqe_cnt = __align_queue_size(attr.cap.max_send_wr + qp->sq_spare_wqes); + qp->rq.wqe_cnt = __align_queue_size(attr.cap.max_recv_wr); + + if (attr.srq || attr.qp_type == IBV_QPT_XRC) + attr.cap.max_recv_wr = qp->rq.wqe_cnt = 0; + else + { + if (attr.cap.max_recv_sge < 1) + attr.cap.max_recv_sge = 1; + if (attr.cap.max_recv_wr < 1) + attr.cap.max_recv_wr = 1; + } + + if (mlx4_alloc_qp_buf(pd, &attr.cap, attr.qp_type, qp)) + goto err_alloc_qp_buff; + + mlx4_init_qp_indices(qp); + + if (cl_spinlock_init(&qp->sq.lock)) { + status = IB_INSUFFICIENT_MEMORY; + goto err_spinlock_sq; + } + if (cl_spinlock_init(&qp->rq.lock)) { + status = IB_INSUFFICIENT_MEMORY; + goto err_spinlock_rq; + } + + // fill qp fields + if (!attr.srq && attr.qp_type != IBV_QPT_XRC) { + qp->db = mlx4_alloc_db(context, MLX4_DB_TYPE_RQ); + if (!qp->db) { + status = IB_INSUFFICIENT_MEMORY; + goto err_db; + } + + *qp->db = 0; + } + if (attr.sq_sig_all) + qp->sq_signal_bits = cl_hton32(MLX4_WQE_CTRL_CQ_UPDATE); + else + qp->sq_signal_bits = 0; + + // fill the rest of qp fields + qp->ibv_qp.pd = pd; + qp->ibv_qp.context= pd->context; + qp->ibv_qp.send_cq = attr.send_cq; + qp->ibv_qp.recv_cq = attr.recv_cq; + qp->ibv_qp.srq = attr.srq; + qp->ibv_qp.state = IBV_QPS_RESET; + qp->ibv_qp.qp_type = attr.qp_type; + + // fill request fields + p_create_qp->buf_addr = (uintptr_t) qp->buf.buf; + if (!attr.srq && attr.qp_type != IBV_QPT_XRC) + p_create_qp->db_addr = (uintptr_t) qp->db; + else + p_create_qp->db_addr = 0; + + p_create_qp->pd_handle = pd->handle; + p_create_qp->send_cq_handle = attr.send_cq->handle; + p_create_qp->recv_cq_handle = attr.recv_cq->handle; + p_create_qp->srq_handle = attr.qp_type == IBV_QPT_XRC ? + (attr.xrc_domain ? attr.xrc_domain->handle : 0) : + (attr.srq ? attr.srq->handle : 0); + + p_create_qp->max_send_wr = attr.cap.max_send_wr; + p_create_qp->max_recv_wr = attr.cap.max_recv_wr; + p_create_qp->max_send_sge = attr.cap.max_send_sge; + p_create_qp->max_recv_sge = attr.cap.max_recv_sge; + p_create_qp->max_inline_data = attr.cap.max_inline_data; + p_create_qp->sq_sig_all = (uint8_t)attr.sq_sig_all; + p_create_qp->qp_type = attr.qp_type; + p_create_qp->is_srq = (uint8_t)(attr.qp_type == IBV_QPT_XRC ? + !!attr.xrc_domain : !!attr.srq); + + p_create_qp->log_sq_stride = (uint8_t)qp->sq.wqe_shift; + for (p_create_qp->log_sq_bb_count = 0; + qp->sq.wqe_cnt > 1 << p_create_qp->log_sq_bb_count; + ++p_create_qp->log_sq_bb_count) + ; /* nothing */ + p_create_qp->sq_no_prefetch = 0; + + *ph_uvp_qp = (ib_qp_handle_t)&qp->ibv_qp; + goto end; + +err_db: + cl_spinlock_destroy(&qp->rq.lock); +err_spinlock_rq: + cl_spinlock_destroy(&qp->sq.lock); +err_spinlock_sq: + cl_free(qp->sq.wrid); + if (qp->rq.wqe_cnt) + free(qp->rq.wrid); + mlx4_free_buf(&qp->buf); +err_alloc_qp_buff: + cl_free(qp); +err_alloc_qp: + cl_free( (void*)(ULONG_PTR)p_umv_buf->p_inout_buf ); +err_memory: +end: + return status; +} + +ib_api_status_t +mlx4_wv_pre_create_qp ( + IN const ib_pd_handle_t h_uvp_pd, + IN const uvp_qp_create_t *p_create_attr, + IN OUT ci_umv_buf_t *p_umv_buf, + OUT ib_qp_handle_t *ph_uvp_qp ) +{ + struct mlx4_qp *qp; + ib_api_status_t status; + + status = mlx4_pre_create_qp(h_uvp_pd, &p_create_attr->qp_create, + p_umv_buf, ph_uvp_qp); + if (status == IB_SUCCESS) { + qp = (struct mlx4_qp *) *ph_uvp_qp; + qp->ibv_qp.qp_context = p_create_attr->context; + } + return status; +} + +ib_api_status_t +mlx4_post_create_qp ( + IN const ib_pd_handle_t h_uvp_pd, + IN ib_api_status_t ioctl_status, + IN OUT ib_qp_handle_t *ph_uvp_qp, + IN ci_umv_buf_t *p_umv_buf ) +{ + struct mlx4_qp *qp = (struct mlx4_qp *)*ph_uvp_qp; + struct ibv_pd *pd = (struct ibv_pd *)h_uvp_pd; + struct ibv_context *context = pd->context; + struct ibv_create_qp_resp *p_resp; + ib_api_status_t status = IB_SUCCESS; + + CL_ASSERT(p_umv_buf && p_umv_buf->p_inout_buf); + + p_resp = (struct ibv_create_qp_resp*)(ULONG_PTR)p_umv_buf->p_inout_buf; + + if (IB_SUCCESS == ioctl_status) + { + // Mlx4 code: + + struct ibv_qp_cap cap; + + cap.max_recv_sge = p_resp->max_recv_sge; + cap.max_send_sge = p_resp->max_send_sge; + cap.max_recv_wr = p_resp->max_recv_wr; + cap.max_send_wr = p_resp->max_send_wr; + cap.max_inline_data = p_resp->max_inline_data; + + qp->ibv_qp.handle = p_resp->qp_handle; + qp->ibv_qp.qp_num = p_resp->qpn; + + qp->rq.wqe_cnt = cap.max_recv_wr; + qp->rq.max_gs = cap.max_recv_sge; + + /* adjust rq maxima to not exceed reported device maxima */ + cap.max_recv_wr = min((uint32_t) to_mctx(context)->max_qp_wr, cap.max_recv_wr); + cap.max_recv_sge = min((uint32_t) to_mctx(context)->max_sge, cap.max_recv_sge); + + qp->rq.max_post = cap.max_recv_wr; + //qp->rq.max_gs = cap.max_recv_sge; - RIB : add this ? + mlx4_set_sq_sizes(qp, &cap, qp->ibv_qp.qp_type); + + qp->doorbell_qpn = cl_hton32(qp->ibv_qp.qp_num << 8); + + if (mlx4_store_qp(to_mctx(context), qp->ibv_qp.qp_num, qp)) + { + mlx4_post_destroy_qp(*ph_uvp_qp, IB_SUCCESS); + status = IB_INSUFFICIENT_MEMORY; + } + MLX4_PRINT( TRACE_LEVEL_INFORMATION, MLX4_DBG_QP, + ("qpn %#x, buf %p, db_rec %p, sq %d:%d, rq %d:%d\n", + qp->ibv_qp.qp_num, qp->buf.buf, qp->db, + qp->sq.head, qp->sq.tail, qp->rq.head, qp->rq.tail )); + } + else + { + mlx4_post_destroy_qp(*ph_uvp_qp, IB_SUCCESS); + *ph_uvp_qp = NULL; + } + + cl_free(p_resp); + return status; +} + +ib_api_status_t +mlx4_pre_modify_qp ( + IN const ib_qp_handle_t h_uvp_qp, + IN const ib_qp_mod_t *p_modify_attr, + IN OUT ci_umv_buf_t *p_umv_buf ) +{ + ib_api_status_t status = IB_SUCCESS; + + UNREFERENCED_PARAMETER(h_uvp_qp); + UNREFERENCED_PARAMETER(p_modify_attr); + + CL_ASSERT(p_umv_buf); + + p_umv_buf->p_inout_buf = (ULONG_PTR)cl_malloc(sizeof(struct ibv_modify_qp_resp)); + if( !p_umv_buf->p_inout_buf ) + { + status = IB_INSUFFICIENT_MEMORY; + goto err_memory; + } + p_umv_buf->input_size = 0; + p_umv_buf->output_size = sizeof(struct ibv_modify_qp_resp); + p_umv_buf->command = TRUE; + +err_memory: + return status; +} + +void +mlx4_post_query_qp ( + IN ib_qp_handle_t h_uvp_qp, + IN ib_api_status_t ioctl_status, + IN OUT ib_qp_attr_t *p_query_attr, + IN OUT ci_umv_buf_t *p_umv_buf ) +{ + struct mlx4_qp *qp = (struct mlx4_qp *)h_uvp_qp; + + UNREFERENCED_PARAMETER(p_umv_buf); + + if(IB_SUCCESS == ioctl_status) + { + p_query_attr->sq_max_inline = qp->max_inline_data; + p_query_attr->sq_sge = qp->sq.max_gs; + p_query_attr->sq_depth = qp->sq.max_post; + p_query_attr->rq_sge = qp->rq.max_gs; + p_query_attr->rq_depth = qp->rq.max_post; + } +} + +void +mlx4_post_modify_qp ( + IN const ib_qp_handle_t h_uvp_qp, + IN ib_api_status_t ioctl_status, + IN OUT ci_umv_buf_t *p_umv_buf ) +{ + struct ibv_qp *qp = (struct ibv_qp *)h_uvp_qp; + struct ibv_modify_qp_resp *p_resp; + + CL_ASSERT(p_umv_buf && p_umv_buf->p_inout_buf); + + p_resp = (struct ibv_modify_qp_resp*)(ULONG_PTR)p_umv_buf->p_inout_buf; + + if (IB_SUCCESS == ioctl_status) + { + // Mlx4 code: + + if (qp->state == IBV_QPS_RESET && + p_resp->attr_mask & IBV_QP_STATE && + p_resp->qp_state == IBV_QPS_INIT) + { + mlx4_qp_init_sq_ownership(to_mqp(qp)); + } + + if (p_resp->attr_mask & IBV_QP_STATE) { + qp->state = p_resp->qp_state; + } + + if (p_resp->attr_mask & IBV_QP_STATE && + p_resp->qp_state == IBV_QPS_RESET) + { + mlx4_cq_clean(to_mcq(qp->recv_cq), qp->qp_num, + qp->srq ? to_msrq(qp->srq) : NULL); + if (qp->send_cq != qp->recv_cq) + mlx4_cq_clean(to_mcq(qp->send_cq), qp->qp_num, NULL); + + mlx4_init_qp_indices(to_mqp(qp)); + if (!qp->srq && qp->qp_type != IBV_QPT_XRC) + *to_mqp(qp)->db = 0; + } + } + + cl_free (p_resp); + return; +} + +static void +__mlx4_lock_cqs(struct ibv_qp *qp) +{ + struct mlx4_cq *send_cq = to_mcq(qp->send_cq); + struct mlx4_cq *recv_cq = to_mcq(qp->recv_cq); + + if (send_cq == recv_cq) + cl_spinlock_acquire(&send_cq->lock); + else if (send_cq->cqn < recv_cq->cqn) { + cl_spinlock_acquire(&send_cq->lock); + cl_spinlock_acquire(&recv_cq->lock); + } else { + cl_spinlock_acquire(&recv_cq->lock); + cl_spinlock_acquire(&send_cq->lock); + } +} + +static void +__mlx4_unlock_cqs(struct ibv_qp *qp) +{ + struct mlx4_cq *send_cq = to_mcq(qp->send_cq); + struct mlx4_cq *recv_cq = to_mcq(qp->recv_cq); + + if (send_cq == recv_cq) + cl_spinlock_release(&send_cq->lock); + else if (send_cq->cqn < recv_cq->cqn) { + cl_spinlock_release(&recv_cq->lock); + cl_spinlock_release(&send_cq->lock); + } else { + cl_spinlock_release(&send_cq->lock); + cl_spinlock_release(&recv_cq->lock); + } +} + +ib_api_status_t +mlx4_pre_destroy_qp ( + IN const ib_qp_handle_t h_uvp_qp ) +{ + struct ibv_qp *qp = (struct ibv_qp*)h_uvp_qp; + + mlx4_cq_clean(to_mcq(qp->recv_cq), qp->qp_num, + qp->srq ? to_msrq(qp->srq) : NULL); + if (qp->send_cq != qp->recv_cq) + mlx4_cq_clean(to_mcq(qp->send_cq), qp->qp_num, NULL); + + __mlx4_lock_cqs(qp); + mlx4_clear_qp(to_mctx(qp->context), qp->qp_num); + __mlx4_unlock_cqs(qp); + + return IB_SUCCESS; +} + +void +mlx4_post_destroy_qp ( + IN const ib_qp_handle_t h_uvp_qp, + IN ib_api_status_t ioctl_status ) +{ + struct ibv_qp* ibqp = (struct ibv_qp *)h_uvp_qp; + struct mlx4_qp* qp = to_mqp(ibqp); + + CL_ASSERT(h_uvp_qp); + + if (IB_SUCCESS == ioctl_status) + { + if (!ibqp->srq && ibqp->qp_type != IBV_QPT_XRC) + mlx4_free_db(to_mctx(ibqp->context), MLX4_DB_TYPE_RQ, qp->db); + + cl_spinlock_destroy(&qp->sq.lock); + cl_spinlock_destroy(&qp->rq.lock); + + MLX4_PRINT( TRACE_LEVEL_INFORMATION, MLX4_DBG_QP, + ("qpn %#x, buf %p, sq %d:%d, rq %d:%d\n", qp->ibv_qp.qp_num, qp->buf.buf, + qp->sq.head, qp->sq.tail, qp->rq.head, qp->rq.tail )); + cl_free(qp->sq.wrid); + if (qp->rq.wqe_cnt) + cl_free(qp->rq.wrid); + mlx4_free_buf(&qp->buf); + cl_free(qp); + } + else + { + __mlx4_lock_cqs(ibqp); + mlx4_store_qp(to_mctx(ibqp->context), ibqp->qp_num, qp); + __mlx4_unlock_cqs(ibqp); + } +} + +void +mlx4_nd_modify_qp ( + IN const ib_qp_handle_t h_uvp_qp, + OUT void** pp_outbuf, + OUT DWORD* p_size ) +{ + struct ibv_qp *ibv_qp = (struct ibv_qp *)h_uvp_qp; + + *(uint32_t**)pp_outbuf = (uint32_t*)&ibv_qp->state; + *p_size = sizeof(ibv_qp->state); +} + +static ib_qp_state_t __from_qp_state(enum ibv_qp_state state) +{ + switch (state) { + case IBV_QPS_RESET: return IB_QPS_RESET; + case IBV_QPS_INIT: return IB_QPS_INIT; + case IBV_QPS_RTR: return IB_QPS_RTR; + case IBV_QPS_RTS: return IB_QPS_RTS; + case IBV_QPS_SQD: return IB_QPS_SQD; + case IBV_QPS_SQE: return IB_QPS_SQERR; + case IBV_QPS_ERR: return IB_QPS_ERROR; + default: return IB_QPS_TIME_WAIT; + }; +} + +uint32_t +mlx4_nd_get_qp_state ( + IN const ib_qp_handle_t h_uvp_qp ) +{ + struct ibv_qp *ibv_qp = (struct ibv_qp *)h_uvp_qp; + + return __from_qp_state(ibv_qp->state); +} + +static enum ibv_rate __to_rate(uint8_t rate) +{ + if (rate == IB_PATH_RECORD_RATE_2_5_GBS) return IBV_RATE_2_5_GBPS; + if (rate == IB_PATH_RECORD_RATE_5_GBS) return IBV_RATE_5_GBPS; + if (rate == IB_PATH_RECORD_RATE_10_GBS) return IBV_RATE_10_GBPS; + if (rate == IB_PATH_RECORD_RATE_20_GBS) return IBV_RATE_20_GBPS; + if (rate == IB_PATH_RECORD_RATE_30_GBS) return IBV_RATE_30_GBPS; + if (rate == IB_PATH_RECORD_RATE_40_GBS) return IBV_RATE_40_GBPS; + if (rate == IB_PATH_RECORD_RATE_60_GBS) return IBV_RATE_60_GBPS; + if (rate == IB_PATH_RECORD_RATE_80_GBS) return IBV_RATE_80_GBPS; + if (rate == IB_PATH_RECORD_RATE_120_GBS) return IBV_RATE_120_GBPS; + return IBV_RATE_MAX; +} + +inline void +__grh_get_ver_class_flow( + IN const ib_net32_t ver_class_flow, + OUT uint8_t* const p_ver OPTIONAL, + OUT uint8_t* const p_tclass OPTIONAL, + OUT net32_t* const p_flow_lbl OPTIONAL ) +{ + ib_net32_t tmp_ver_class_flow; + + tmp_ver_class_flow = cl_ntoh32( ver_class_flow ); + + if (p_ver) + *p_ver = (uint8_t)(tmp_ver_class_flow >> 28); + + if (p_tclass) + *p_tclass = (uint8_t)(tmp_ver_class_flow >> 20); + + if (p_flow_lbl) + *p_flow_lbl = (ver_class_flow & CL_HTON32( 0x000FFFFF )); +} + +static ib_api_status_t +__to_ah ( + IN const ib_av_attr_t *p_av_attr, + OUT struct ibv_ah_attr *p_attr ) +{ + p_attr->port_num = p_av_attr->port_num; + p_attr->sl = p_av_attr->sl; + p_attr->dlid = cl_ntoh16 (p_av_attr->dlid); + p_attr->static_rate = __to_rate(p_av_attr->static_rate); + p_attr->src_path_bits = p_av_attr->path_bits; + + /* For global destination or Multicast address:*/ + if (p_av_attr->grh_valid) + { + p_attr->is_global = TRUE; + p_attr->grh.hop_limit = p_av_attr->grh.hop_limit; + __grh_get_ver_class_flow( p_av_attr->grh.ver_class_flow, NULL, + &p_attr->grh.traffic_class, &p_attr->grh.flow_label ); + p_attr->grh.sgid_index = p_av_attr->grh.resv2; + cl_memcpy (p_attr->grh.dgid.raw, p_av_attr->grh.dest_gid.raw, 16); + } + else + { + p_attr->is_global = FALSE; + } + return IB_SUCCESS; +} + +static void +__set_av_params(struct mlx4_ah *ah, struct ibv_pd *pd, struct ibv_ah_attr *attr) +{ + ah->av.port_pd = cl_hton32(to_mpd(pd)->pdn | (attr->port_num << 24)); + ah->av.g_slid = attr->src_path_bits; + ah->av.dlid = cl_hton16(attr->dlid); + if (attr->static_rate) { + ah->av.stat_rate = (uint8_t)(attr->static_rate + MLX4_STAT_RATE_OFFSET); + /* XXX check rate cap? */ + } + ah->av.sl_tclass_flowlabel = cl_hton32(attr->sl << 28); + if (attr->is_global) + { + ah->av.g_slid |= 0x80; + ah->av.gid_index = attr->grh.sgid_index; + ah->av.hop_limit = attr->grh.hop_limit; + ah->av.sl_tclass_flowlabel |= + cl_hton32((attr->grh.traffic_class << 20) | + attr->grh.flow_label); + cl_memcpy(ah->av.dgid, attr->grh.dgid.raw, 16); + } +} + +ib_api_status_t +mlx4_pre_create_ah ( + IN const ib_pd_handle_t h_uvp_pd, + IN const ib_av_attr_t *p_av_attr, + IN OUT ci_umv_buf_t *p_umv_buf, + OUT ib_av_handle_t *ph_uvp_av ) +{ + struct mlx4_ah *ah; + struct ibv_ah_attr attr; + struct ibv_pd *pd = (struct ibv_pd *)h_uvp_pd; + ib_api_status_t status = IB_SUCCESS; + + UNREFERENCED_PARAMETER(p_umv_buf); + + ah = cl_malloc(sizeof *ah); + if (!ah) { + status = IB_INSUFFICIENT_MEMORY; + goto end; + } + + // convert parameters + cl_memset(&attr, 0, sizeof(attr)); + __to_ah(p_av_attr, &attr); + + ah->ibv_ah.pd = pd; + ah->ibv_ah.context = pd->context; + cl_memcpy(&ah->ibv_ah.av_attr, p_av_attr, sizeof (ib_av_attr_t)); + + cl_memset(&ah->av, 0, sizeof ah->av); + __set_av_params(ah, pd, &attr); + + *ph_uvp_av = (ib_av_handle_t)&ah->ibv_ah; + status = IB_VERBS_PROCESSING_DONE; + +end: + return status; +} + +ib_api_status_t +mlx4_pre_query_ah ( + IN const ib_av_handle_t h_uvp_av, + IN OUT ci_umv_buf_t *p_umv_buf ) +{ + UNREFERENCED_PARAMETER(h_uvp_av); + UNREFERENCED_PARAMETER(p_umv_buf); + + return IB_VERBS_PROCESSING_DONE; +} + +void +mlx4_post_query_ah ( + IN const ib_av_handle_t h_uvp_av, + IN ib_api_status_t ioctl_status, + IN OUT ib_av_attr_t *p_addr_vector, + IN OUT ib_pd_handle_t *ph_pd, + IN OUT ci_umv_buf_t *p_umv_buf ) +{ + struct ibv_ah *ah = (struct ibv_ah *)h_uvp_av; + + UNREFERENCED_PARAMETER(p_umv_buf); + + CL_ASSERT(h_uvp_av && p_addr_vector); + + if (ioctl_status == IB_SUCCESS) + { + cl_memcpy(p_addr_vector, &ah->av_attr, sizeof(ib_av_attr_t)); + if (ph_pd) + *ph_pd = (ib_pd_handle_t)ah->pd; + } +} + +ib_api_status_t +mlx4_pre_modify_ah ( + IN const ib_av_handle_t h_uvp_av, + IN const ib_av_attr_t *p_addr_vector, + IN OUT ci_umv_buf_t *p_umv_buf ) +{ + struct ibv_ah *ah = (struct ibv_ah *)h_uvp_av; + struct ibv_ah_attr attr; + ib_api_status_t status; + + UNREFERENCED_PARAMETER(p_umv_buf); + + CL_ASSERT (h_uvp_av); + + status = __to_ah(p_addr_vector, &attr); + if (status) + return status; + + __set_av_params(to_mah(ah), ah->pd, &attr); + cl_memcpy(&ah->av_attr, p_addr_vector, sizeof(ib_av_attr_t)); + + return IB_VERBS_PROCESSING_DONE; +} + +ib_api_status_t +mlx4_pre_destroy_ah ( + IN const ib_av_handle_t h_uvp_av ) +{ + struct ibv_ah *ah = (struct ibv_ah *)h_uvp_av; + + CL_ASSERT(ah); + + cl_free(to_mah(ah)); + + return IB_VERBS_PROCESSING_DONE; +} + +#ifdef XRC_SUPPORT +ib_api_status_t +mlx4_pre_create_xrc_srq ( + IN const ib_pd_handle_t h_uvp_pd, + IN const ib_xrcd_handle_t h_uvp_xrcd, + IN const ib_srq_attr_t *p_srq_attr, + IN OUT ci_umv_buf_t *p_umv_buf, + OUT ib_srq_handle_t *ph_uvp_srq ) +{ + struct mlx4_srq *srq; + struct ibv_create_srq *p_create_srq; + struct ibv_pd *pd = (struct ibv_pd *)h_uvp_pd; + struct ibv_xrc_domain *xrc_domain = (struct ibv_xrc_domain *)h_uvp_xrcd; + ib_api_status_t status = IB_SUCCESS; + size_t size = max( sizeof(struct ibv_create_srq), sizeof(struct ibv_create_srq_resp) ); + + CL_ASSERT(p_umv_buf); + + p_umv_buf->p_inout_buf = cl_malloc( size ); + if( !p_umv_buf->p_inout_buf ) + { + status = IB_INSUFFICIENT_MEMORY; + goto err_memory; + } + p_umv_buf->input_size = sizeof(struct ibv_create_srq); + p_umv_buf->output_size = sizeof(struct ibv_create_srq_resp); + p_umv_buf->command = TRUE; + + p_create_srq = p_umv_buf->p_inout_buf; + + // Mlx4 code: + + /* Sanity check SRQ size before proceeding */ + if (p_srq_attr->max_wr > 1 << 16 || p_srq_attr->max_sge > 64) + { + status = IB_INVALID_PARAMETER; + goto err_params; + } + + srq = cl_malloc(sizeof *srq); + if (!srq) { + status = IB_INSUFFICIENT_MEMORY; + goto err_alloc_srq; + } + + if (cl_spinlock_init(&srq->lock)) { + status = IB_INSUFFICIENT_MEMORY; + goto err_lock; + } + + srq->ibv_srq.pd = pd; + srq->ibv_srq.context = pd->context; + + srq->max = __align_queue_size(p_srq_attr->max_wr + 1); + srq->max_gs = p_srq_attr->max_sge; + srq->counter = 0; + + if (mlx4_alloc_srq_buf(pd, (struct ibv_srq_attr *)p_srq_attr, srq)) + { + status = IB_INSUFFICIENT_MEMORY; + goto err_alloc_buf; + } + + srq->db = mlx4_alloc_db(to_mctx(pd->context), MLX4_DB_TYPE_RQ); + if (!srq->db) + goto err_alloc_db; + + *srq->db = 0; + + // fill the parameters for ioctl + p_create_srq->buf_addr = (uintptr_t) srq->buf.buf; + p_create_srq->db_addr = (uintptr_t) srq->db; + p_create_srq->pd_handle = pd->handle; + p_create_srq->max_wr = p_srq_attr->max_wr; + p_create_srq->max_sge = p_srq_attr->max_sge; + p_create_srq->srq_limit = p_srq_attr->srq_limit; + + *ph_uvp_srq = (ib_srq_handle_t)&srq->ibv_srq; + goto end; + +err_alloc_db: + cl_free(srq->wrid); + mlx4_free_buf(&srq->buf); +err_alloc_buf: + cl_spinlock_destroy(&srq->lock); +err_lock: + cl_free(srq); +err_alloc_srq: + cl_free(p_umv_buf->p_inout_buf); +err_params: err_memory: +end: + return status; +} + +ib_api_status_t +mlx4_post_create_xrc_srq ( + IN const ib_pd_handle_t h_uvp_pd, + IN ib_api_status_t ioctl_status, + IN OUT ib_srq_handle_t *ph_uvp_srq, + IN ci_umv_buf_t *p_umv_buf ) +{ + struct mlx4_srq *srq = (struct mlx4_srq *)*ph_uvp_srq; + struct ibv_create_srq_resp *p_resp; + ib_api_status_t status = IB_SUCCESS; + + UNREFERENCED_PARAMETER(h_uvp_pd); + + CL_ASSERT(p_umv_buf && p_umv_buf->p_inout_buf); + + p_resp = p_umv_buf->p_inout_buf; + + if (IB_SUCCESS == ioctl_status) + { + // Mlx4 code: + + srq->ibv_srq.xrc_srq_num = srq->srqn = p_resp->srqn; + srq->ibv_srq.handle = p_resp->srq_handle; + + srq->max = p_resp->max_wr; + srq->max_gs = p_resp->max_sge; + + if (mlx4_store_xrc_srq(to_mctx(pd->context), srq->ibv_srq.xrc_srq_num, srq)) + { + mlx4_post_destroy_srq(*ph_uvp_srq, IB_SUCCESS); + status = IB_INSUFFICIENT_MEMORY; + } + } + else + { + mlx4_post_destroy_srq (*ph_uvp_srq, IB_SUCCESS); + *ph_uvp_srq = NULL; + } + + cl_free( p_resp ); + return status; +} + +ib_api_status_t +mlx4_pre_open_xrc_domain ( + IN const ib_ca_handle_t h_uvp_ca, + IN const uint32_t oflag, + IN OUT ci_umv_buf_t *p_umv_buf, + OUT ib_xrcd_handle_t *ph_uvp_xrcd ) +{ + struct mlx4_xrc_domain *xrcd; + struct ibv_context * context = (struct ibv_context *)h_uvp_ca; + struct ibv_open_xrc_domain *p_open_xrcd; + ib_api_status_t status = IB_SUCCESS; + int size = max( sizeof(struct ibv_open_xrc_domain), sizeof(struct ibv_open_xrc_domain_resp) ); + + CL_ASSERT(h_uvp_ca && p_umv_buf); + + p_umv_buf->p_inout_buf = cl_malloc( size ); + if( !p_umv_buf->p_inout_buf ) + { + status = IB_INSUFFICIENT_MEMORY; + goto err_umv_buf; + } + p_umv_buf->input_size = sizeof(struct ibv_open_xrc_domain); + p_umv_buf->output_size = sizeof(struct ibv_open_xrc_domain_resp); + p_umv_buf->command = TRUE; + + p_open_xrcd = p_umv_buf->p_inout_buf; + + // Mlx4 code: + + xrcd = cl_malloc(sizeof *xrcd); + if (!xrcd) { + status = IB_INSUFFICIENT_MEMORY; + goto err_xrc; + } + + xrcd->ibv_xrcd.context = context; + + p_open_xrcd->oflags = oflag; + + *ph_uvp_xrcd = (struct ibv_xrc_domain *)&xrcd->ibv_xrcd; + goto end; + +err_xrc: + cl_free(p_umv_buf->p_inout_buf); +err_umv_buf: +end: + return status; +} + +void +mlx4_post_open_xrc_domain ( + IN const ib_ca_handle_t h_uvp_ca, + IN ib_api_status_t ioctl_status, + IN OUT ib_xrcd_handle_t *ph_uvp_xrcd, + IN ci_umv_buf_t *p_umv_buf ) +{ + struct ibv_xrc_domain *xrcd = (struct ibv_xrc_domain *)*ph_uvp_xrcd; + struct ibv_open_xrc_domain_resp *p_resp; + + UNREFERENCED_PARAMETER(h_uvp_ca); + + CL_ASSERT(p_umv_buf && p_umv_buf->p_inout_buf); + + p_resp = p_umv_buf->p_inout_buf; + + if (IB_SUCCESS == ioctl_status) + { + // Mlx4 code: + + xrcd->handle = p_resp->xrcd_handle; + to_mxrcd(xrcd)->xrcdn = p_resp->xrcdn; + } + else + { + cl_free(to_mxrcd(xrcd)); + *ph_uvp_xrcd = NULL; + } + + cl_free(p_resp); + return; +} + +void +mlx4_post_close_xrc_domain ( + IN const ib_xrcd_handle_t h_uvp_xrcd, + IN ib_api_status_t ioctl_status ) +{ + struct ibv_xrc_domain *xrdc = (struct ibv_xrc_domain *)h_uvp_xrcd; + + CL_ASSERT(xrdc); + + if (IB_SUCCESS == ioctl_status) { + cl_free(to_mxrcd(xrdc)); + } +} +#endif diff --git a/branches/WOF2-3/hw/mlx4/user/hca/verbs.h b/branches/WOF2-3/hw/mlx4/user/hca/verbs.h new file mode 100644 index 00000000..9f7f2c14 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/user/hca/verbs.h @@ -0,0 +1,436 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2004 Intel Corporation. All rights reserved. + * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc. All rights reserved. + * Copyright (c) 2005 PathScale, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef INFINIBAND_VERBS_H +#define INFINIBAND_VERBS_H + +#include "l2w.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 + +union ibv_gid { + uint8_t raw[16]; + struct { + uint64_t subnet_prefix; + uint64_t interface_id; + } global; +}; + +enum ibv_rate { + IBV_RATE_MAX = 0, + IBV_RATE_2_5_GBPS = 2, + IBV_RATE_5_GBPS = 5, + IBV_RATE_10_GBPS = 3, + IBV_RATE_20_GBPS = 6, + IBV_RATE_30_GBPS = 4, + IBV_RATE_40_GBPS = 7, + IBV_RATE_60_GBPS = 8, + IBV_RATE_80_GBPS = 9, + IBV_RATE_120_GBPS = 10 +}; + +struct ibv_global_route { + union ibv_gid dgid; + uint32_t flow_label; + uint8_t sgid_index; + uint8_t hop_limit; + uint8_t traffic_class; +}; + +struct ibv_grh { + uint32_t version_tclass_flow; + uint16_t paylen; + uint8_t next_hdr; + uint8_t hop_limit; + union ibv_gid sgid; + union ibv_gid dgid; +}; + +struct ibv_ah_attr { + struct ibv_global_route grh; + uint16_t dlid; + uint8_t sl; + uint8_t src_path_bits; + uint8_t static_rate; + uint8_t is_global; + uint8_t port_num; +}; + +struct ibv_xrc_domain { + struct ibv_context *context; + uint64_t handle; +}; + +struct ibv_srq_attr { + uint32_t max_wr; + uint32_t max_sge; + uint32_t srq_limit; +}; + +enum ibv_qp_type { + IBV_QPT_RC = 2, + IBV_QPT_UC, + IBV_QPT_UD, + IBV_QPT_XRC +}; + +struct ibv_qp_cap { + uint32_t max_send_wr; + uint32_t max_recv_wr; + uint32_t max_send_sge; + uint32_t max_recv_sge; + uint32_t max_inline_data; +}; + +struct ibv_qp_init_attr { + void *qp_context; + struct ibv_cq *send_cq; + struct ibv_cq *recv_cq; + struct ibv_srq *srq; + struct ibv_qp_cap cap; + enum ibv_qp_type qp_type; + int sq_sig_all; + struct ibv_xrc_domain *xrc_domain; +}; + +enum ibv_qp_attr_mask { + IBV_QP_STATE = 1 << 0, + IBV_QP_CUR_STATE = 1 << 1, + IBV_QP_EN_SQD_ASYNC_NOTIFY = 1 << 2, + IBV_QP_ACCESS_FLAGS = 1 << 3, + IBV_QP_PKEY_INDEX = 1 << 4, + IBV_QP_PORT = 1 << 5, + IBV_QP_QKEY = 1 << 6, + IBV_QP_AV = 1 << 7, + IBV_QP_PATH_MTU = 1 << 8, + IBV_QP_TIMEOUT = 1 << 9, + IBV_QP_RETRY_CNT = 1 << 10, + IBV_QP_RNR_RETRY = 1 << 11, + IBV_QP_RQ_PSN = 1 << 12, + IBV_QP_MAX_QP_RD_ATOMIC = 1 << 13, + IBV_QP_ALT_PATH = 1 << 14, + IBV_QP_MIN_RNR_TIMER = 1 << 15, + IBV_QP_SQ_PSN = 1 << 16, + IBV_QP_MAX_DEST_RD_ATOMIC = 1 << 17, + IBV_QP_PATH_MIG_STATE = 1 << 18, + IBV_QP_CAP = 1 << 19, + IBV_QP_DEST_QPN = 1 << 20 +}; + +enum ibv_qp_state { + IBV_QPS_RESET, + IBV_QPS_INIT, + IBV_QPS_RTR, + IBV_QPS_RTS, + IBV_QPS_SQD, + IBV_QPS_SQE, + IBV_QPS_ERR +}; + +struct ibv_pd { + struct ibv_context *context; + uint64_t handle; +}; + +struct ibv_srq { + struct ibv_context *context; + struct ibv_pd *pd; + uint64_t handle; + uint32_t xrc_srq_num; + struct ibv_xrc_domain *xrc_domain; + struct ibv_cq *xrc_cq; +}; + +struct ibv_qp { + struct ibv_context *context; + void *qp_context; + struct ibv_pd *pd; + struct ibv_cq *send_cq; + struct ibv_cq *recv_cq; + struct ibv_srq *srq; + uint64_t handle; + uint32_t qp_num; + enum ibv_qp_state state; + enum ibv_qp_type qp_type; + struct ibv_xrc_domain *xrc_domain; +}; + +struct ibv_cq { + struct ibv_context *context; + uint64_t handle; + int cqe; +}; + +struct ibv_ah { + struct ibv_context *context; + struct ibv_pd *pd; + ib_av_attr_t av_attr; +}; + +struct ibv_context { + int page_size; +}; + + +/************* CA operations *************************/ +ib_api_status_t +mlx4_pre_open_ca ( + IN const ib_net64_t ca_guid, + IN OUT ci_umv_buf_t *p_umv_buf, + OUT ib_ca_handle_t *ph_uvp_ca ); + +ib_api_status_t +mlx4_post_open_ca ( + IN const ib_net64_t ca_guid, + IN ib_api_status_t ioctl_status, + IN OUT ib_ca_handle_t *ph_uvp_ca, + IN ci_umv_buf_t *p_umv_buf ); + +ib_api_status_t +mlx4_post_close_ca ( + IN ib_ca_handle_t h_uvp_ca, + IN ib_api_status_t ioctl_status ); + +/************* PD Management ***********************/ +extern ib_api_status_t +mlx4_pre_alloc_pd ( + IN const ib_ca_handle_t h_uvp_ca, + IN OUT ci_umv_buf_t *p_umv_buf, + OUT ib_pd_handle_t *ph_uvp_pd ); + +void +mlx4_post_alloc_pd ( + IN ib_ca_handle_t h_uvp_ca, + IN ib_api_status_t ioctl_status, + IN OUT ib_pd_handle_t *ph_uvp_pd, + IN ci_umv_buf_t *p_umv_buf ); + +void +mlx4_post_free_pd ( + IN const ib_pd_handle_t h_uvp_pd, + IN ib_api_status_t ioctl_status ); + +/************* CQ Management ***********************/ +ib_api_status_t +mlx4_pre_create_cq ( + IN const ib_ca_handle_t h_uvp_ca, + IN OUT uint32_t* const p_size, + IN OUT ci_umv_buf_t *p_umv_buf, + OUT ib_cq_handle_t *ph_uvp_cq ); + +void +mlx4_post_create_cq ( + IN const ib_ca_handle_t h_uvp_ca, + IN ib_api_status_t ioctl_status, + IN const uint32_t size, + IN OUT ib_cq_handle_t *ph_uvp_cq, + IN ci_umv_buf_t *p_umv_buf ); + +ib_api_status_t +mlx4_pre_query_cq ( + IN const ib_cq_handle_t h_uvp_cq, + OUT uint32_t* const p_size, + IN OUT ci_umv_buf_t *p_umv_buf ); + +void +mlx4_post_destroy_cq ( + IN const ib_cq_handle_t h_uvp_cq, + IN ib_api_status_t ioctl_status ); + +/************* SRQ Management **********************/ +ib_api_status_t +mlx4_pre_create_srq ( + IN const ib_pd_handle_t h_uvp_pd, + IN const ib_srq_attr_t *p_srq_attr, + IN OUT ci_umv_buf_t *p_umv_buf, + OUT ib_srq_handle_t *ph_uvp_srq ); + +void +mlx4_post_create_srq ( + IN const ib_pd_handle_t h_uvp_pd, + IN ib_api_status_t ioctl_status, + IN OUT ib_srq_handle_t *ph_uvp_srq, + IN ci_umv_buf_t *p_umv_buf ); + +ib_api_status_t +mlx4_pre_destroy_srq ( + IN const ib_srq_handle_t h_uvp_srq ); + +void +mlx4_post_destroy_srq ( + IN const ib_srq_handle_t h_uvp_srq, + IN ib_api_status_t ioctl_status ); + +/************* QP Management ***********************/ +ib_api_status_t +mlx4_pre_create_qp ( + IN const ib_pd_handle_t h_uvp_pd, + IN const ib_qp_create_t *p_create_attr, + IN OUT ci_umv_buf_t *p_umv_buf, + OUT ib_qp_handle_t *ph_uvp_qp ); + +ib_api_status_t +mlx4_wv_pre_create_qp ( + IN const ib_pd_handle_t h_uvp_pd, + IN const uvp_qp_create_t *p_create_attr, + IN OUT ci_umv_buf_t *p_umv_buf, + OUT ib_qp_handle_t *ph_uvp_qp ); + +ib_api_status_t +mlx4_post_create_qp ( + IN const ib_pd_handle_t h_uvp_pd, + IN ib_api_status_t ioctl_status, + IN OUT ib_qp_handle_t *ph_uvp_qp, + IN ci_umv_buf_t *p_umv_buf ); + +ib_api_status_t +mlx4_pre_modify_qp ( + IN const ib_qp_handle_t h_uvp_qp, + IN const ib_qp_mod_t *p_modify_attr, + IN OUT ci_umv_buf_t *p_umv_buf ); + +void +mlx4_post_modify_qp ( + IN const ib_qp_handle_t h_uvp_qp, + IN ib_api_status_t ioctl_status, + IN OUT ci_umv_buf_t *p_umv_buf ); + +void +mlx4_post_query_qp ( + IN ib_qp_handle_t h_uvp_qp, + IN ib_api_status_t ioctl_status, + IN OUT ib_qp_attr_t *p_query_attr, + IN OUT ci_umv_buf_t *p_umv_buf ); + +ib_api_status_t +mlx4_pre_destroy_qp ( + IN const ib_qp_handle_t h_uvp_qp ); + +void +mlx4_post_destroy_qp ( + IN const ib_qp_handle_t h_uvp_qp, + IN ib_api_status_t ioctl_status ); + +void +mlx4_nd_modify_qp ( + IN const ib_qp_handle_t h_uvp_qp, + OUT void** pp_outbuf, + OUT DWORD* p_size ); + +uint32_t +mlx4_nd_get_qp_state ( + IN const ib_qp_handle_t h_uvp_qp ); + +/************* AV Management ***********************/ +ib_api_status_t +mlx4_pre_create_ah ( + IN const ib_pd_handle_t h_uvp_pd, + IN const ib_av_attr_t *p_av_attr, + IN OUT ci_umv_buf_t *p_umv_buf, + OUT ib_av_handle_t *ph_uvp_av ); + +ib_api_status_t +mlx4_pre_query_ah ( + IN const ib_av_handle_t h_uvp_av, + IN OUT ci_umv_buf_t *p_umv_buf ); + +void +mlx4_post_query_ah ( + IN const ib_av_handle_t h_uvp_av, + IN ib_api_status_t ioctl_status, + IN OUT ib_av_attr_t *p_addr_vector, + IN OUT ib_pd_handle_t *ph_pd, + IN OUT ci_umv_buf_t *p_umv_buf ); + +ib_api_status_t +mlx4_pre_modify_ah ( + IN const ib_av_handle_t h_uvp_av, + IN const ib_av_attr_t *p_addr_vector, + IN OUT ci_umv_buf_t *p_umv_buf ); + +ib_api_status_t +mlx4_pre_destroy_ah ( + IN const ib_av_handle_t h_uvp_av ); + +#ifdef XRC_SUPPORT +/************* XRC Management **********************/ +ib_api_status_t +mlx4_pre_create_xrc_srq ( + IN const ib_pd_handle_t h_uvp_pd, + IN const ib_xrcd_handle_t h_uvp_xrcd, + IN const ib_srq_attr_t *p_srq_attr, + IN OUT ci_umv_buf_t *p_umv_buf, + OUT ib_srq_handle_t *ph_uvp_srq ); + +ib_api_status_t +mlx4_post_create_xrc_srq ( + IN const ib_pd_handle_t h_uvp_pd, + IN ib_api_status_t ioctl_status, + IN OUT ib_srq_handle_t *ph_uvp_srq, + IN ci_umv_buf_t *p_umv_buf ); + +ib_api_status_t +mlx4_pre_open_xrc_domain ( + IN const ib_ca_handle_t h_uvp_ca, + IN const uint32_t oflag, + IN OUT ci_umv_buf_t *p_umv_buf, + OUT ib_xrcd_handle_t *ph_uvp_xrcd ); + +void +mlx4_post_open_xrc_domain ( + IN const ib_ca_handle_t h_uvp_ca, + IN ib_api_status_t ioctl_status, + IN OUT ib_xrcd_handle_t *ph_uvp_xrcd, + IN ci_umv_buf_t *p_umv_buf ); + +void +mlx4_post_close_xrc_domain ( + IN const ib_xrcd_handle_t h_uvp_xrcd, + IN ib_api_status_t ioctl_status ); + +#endif /* XRC_SUPPORT */ + +END_C_DECLS + +#endif /* INFINIBAND_VERBS_H */ diff --git a/branches/WOF2-3/hw/mlx4/user/hca/wqe.h b/branches/WOF2-3/hw/mlx4/user/hca/wqe.h new file mode 100644 index 00000000..fa2f8ac6 --- /dev/null +++ b/branches/WOF2-3/hw/mlx4/user/hca/wqe.h @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2007 Cisco, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef WQE_H +#define WQE_H + +enum { + MLX4_SEND_DOORBELL = 0x14, +}; + +enum { + MLX4_WQE_CTRL_FENCE = 1 << 6, + MLX4_WQE_CTRL_CQ_UPDATE = 3 << 2, + MLX4_WQE_CTRL_SOLICIT = 1 << 1, +}; + +enum { + MLX4_INLINE_SEG = 1 << 31, + MLX4_INLINE_ALIGN = 64, +}; + +enum { + MLX4_INVALID_LKEY = 0x100, +}; + +struct mlx4_wqe_ctrl_seg { + uint32_t owner_opcode; + uint8_t reserved[3]; + uint8_t fence_size; + /* + * High 24 bits are SRC remote buffer; low 8 bits are flags: + * [7] SO (strong ordering) + * [5] TCP/UDP checksum + * [4] IP checksum + * [3:2] C (generate completion queue entry) + * [1] SE (solicited event) + * [0] FL (force loopback) + */ + uint32_t xrcrb_flags; + /* + * imm is immediate data for send/RDMA write w/ immediate; + * also invalidation key for send with invalidate; input + * modifier for WQEs on CCQs. + */ + uint32_t imm; +}; + +struct mlx4_wqe_datagram_seg { + uint32_t av[8]; + uint32_t dqpn; + uint32_t qkey; + uint32_t reserved[2]; +}; + +struct mlx4_wqe_data_seg { + uint32_t byte_count; + uint32_t lkey; + uint64_t addr; +}; + +struct mlx4_wqe_inline_seg { + uint32_t byte_count; +}; + +struct mlx4_wqe_srq_next_seg { + uint16_t reserved1; + uint16_t next_wqe_index; + uint32_t reserved2[3]; +}; + +struct mlx4_wqe_raddr_seg { + uint64_t raddr; + uint32_t rkey; + uint32_t reserved; +}; + +struct mlx4_wqe_atomic_seg { + uint64_t swap_add; + uint64_t compare; +}; + +struct mlx4_wqe_bind_seg { + uint32_t flags1; + uint32_t flags2; + uint32_t new_rkey; + uint32_t lkey; + uint64_t addr; + uint64_t length; +}; + +#endif /* WQE_H */ diff --git a/branches/WOF2-3/hw/mthca/dirs b/branches/WOF2-3/hw/mthca/dirs new file mode 100644 index 00000000..aa698135 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/dirs @@ -0,0 +1,3 @@ +DIRS=\ + kernel \ + user diff --git a/branches/WOF2-3/hw/mthca/hca_utils.c b/branches/WOF2-3/hw/mthca/hca_utils.c new file mode 100644 index 00000000..a86b5ab5 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/hca_utils.c @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2004-2005 Mellanox Technologies, Inc. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include "mthca_dev.h" + + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "hca_data.tmh" +#endif + + +mthca_qp_access_t +map_qp_ibal_acl( + IN ib_access_t ibal_acl) +{ +#define IBAL_ACL(ifl,mfl) if (ibal_acl & ifl) mthca_acl |= mfl + mthca_qp_access_t mthca_acl = 0; + + IBAL_ACL(IB_AC_RDMA_READ,MTHCA_ACCESS_REMOTE_READ); + IBAL_ACL(IB_AC_RDMA_WRITE,MTHCA_ACCESS_REMOTE_WRITE); + IBAL_ACL(IB_AC_ATOMIC,MTHCA_ACCESS_REMOTE_ATOMIC); + IBAL_ACL(IB_AC_LOCAL_WRITE,MTHCA_ACCESS_LOCAL_WRITE); + IBAL_ACL(IB_AC_MW_BIND,MTHCA_ACCESS_MW_BIND); + + return mthca_acl; +} + +///////////////////////////////////////////////////////// +///////////////////////////////////////////////////////// +ib_access_t +map_qp_mthca_acl( + IN mthca_qp_access_t mthca_acl) +{ +#define ACL_IBAL(mfl,ifl) if (mthca_acl & mfl) ibal_acl |= ifl + ib_access_t ibal_acl = 0; + + ACL_IBAL(MTHCA_ACCESS_REMOTE_READ,IB_AC_RDMA_READ); + ACL_IBAL(MTHCA_ACCESS_REMOTE_WRITE,IB_AC_RDMA_WRITE); + ACL_IBAL(MTHCA_ACCESS_REMOTE_ATOMIC,IB_AC_ATOMIC); + ACL_IBAL(MTHCA_ACCESS_LOCAL_WRITE,IB_AC_LOCAL_WRITE); + ACL_IBAL(MTHCA_ACCESS_MW_BIND,IB_AC_MW_BIND); + + return ibal_acl; +} + + diff --git a/branches/WOF2-3/hw/mthca/hca_utils.h b/branches/WOF2-3/hw/mthca/hca_utils.h new file mode 100644 index 00000000..9b8a5683 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/hca_utils.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2004-2005 Mellanox Technologies, Inc. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#ifndef __HCA_UTILS_H__ +#define __HCA_UTILS_H__ + +#include +#include + +mthca_qp_access_t +map_qp_ibal_acl( + IN ib_access_t ibal_acl) +; + +ib_access_t +map_qp_mthca_acl( + IN mthca_qp_access_t mthca_acl); + +#endif + diff --git a/branches/WOF2-3/hw/mthca/kernel/Makefile b/branches/WOF2-3/hw/mthca/kernel/Makefile new file mode 100644 index 00000000..1c8f2940 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/Makefile @@ -0,0 +1,6 @@ +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the Windows NT DDK +# + +!INCLUDE ..\..\..\inc\openib.def# diff --git a/branches/WOF2-3/hw/mthca/kernel/SOURCES b/branches/WOF2-3/hw/mthca/kernel/SOURCES new file mode 100644 index 00000000..269da791 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/SOURCES @@ -0,0 +1,94 @@ +TRUNK=..\..\.. + +TARGETNAME=mthca +TARGETPATH=$(TRUNK)\bin\kernel\obj$(BUILD_ALT_DIR) +TARGETTYPE=DRIVER + +KMDF_VERSION_MAJOR=1 + +# WDK build only - transform .inx --> .inf adding date & version stamp. +# see .\makefile.inc +INF_NAME=$(TARGETNAME) +INF_TARGET=$(TRUNK)\bin\kernel\$(O)\$(INF_NAME).inf +NTTARGETFILES=$(INF_TARGET) + +!if $(FREEBUILD) +ENABLE_EVENT_TRACING=1 +!else +#ENABLE_EVENT_TRACING=1 +!endif + +SOURCES= \ + mthca_log.mc \ + hca.rc \ + mthca_log.c \ + \ + ..\hca_utils.c \ + ..\mt_utils.c \ + \ + hca_data.c \ + hca_direct.c \ + hca_driver.c \ + hca_mcast.c \ + hca_memory.c \ + hca_pci.c \ + hca_pnp.c \ + hca_verbs.c \ + \ + mt_cache.c \ + mt_device.c \ + mt_l2w.c \ + mt_memory.c \ + mt_packer.c \ + mt_reset_tavor.c \ + mt_ud_header.c \ + mt_uverbs.c \ + mt_verbs.c \ + mt_pa_cash.c \ + \ + mthca_allocator.c \ + mthca_av.c \ + mthca_catas.c \ + mthca_cmd.c \ + mthca_cq.c \ + mthca_eq.c \ + mthca_mad.c \ + mthca_main.c \ + mthca_mcg.c \ + mthca_memfree.c \ + mthca_mr.c \ + mthca_pd.c \ + mthca_profile.c \ + mthca_provider.c \ + mthca_qp.c \ + mthca_srq.c \ + mthca_uar.c \ + + +INCLUDES=\ + ..; \ + $(TRUNK)\inc; \ + $(TRUNK)\inc\kernel; + +C_DEFINES=$(C_DEFINES) -DDRIVER -DDEPRECATE_DDK_FUNCTIONS -D__LITTLE_ENDIAN + +TARGETLIBS= \ + $(DDK_LIB_PATH)\ntstrsafe.lib \ + $(TARGETPATH)\*\complib.lib \ + $(DDK_LIB_PATH)\wdmguid.lib + + +#LINKER_FLAGS=/MAP + +!IFDEF ENABLE_EVENT_TRACING + +C_DEFINES = $(C_DEFINES) -DEVENT_TRACING +RUN_WPP= $(SOURCES) -km -ext: .c .h .C .H \ + -scan:hca_debug.h \ + -func:HCA_PRINT(LEVEL,FLAGS,(MSG,...)) +!ENDIF + +# -func:HCA_PRINT_EV(LEVEL,FLAGS,(MSG,...)) \ + +MSC_OPTIMIZATION=/Oi +MSC_WARNING_LEVEL= /W4 diff --git a/branches/WOF2-3/hw/mthca/kernel/hca.rc b/branches/WOF2-3/hw/mthca/kernel/hca.rc new file mode 100644 index 00000000..2780199f --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/hca.rc @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_UNKNOWN +#ifdef DBG +#define VER_FILEDESCRIPTION_STR "HCA Driver (checked)" +#else +#define VER_FILEDESCRIPTION_STR "HCA Driver" +#endif +#define VER_INTERNALNAME_STR "mthca.sys" +#define VER_ORIGINALFILENAME_STR "mthca.sys" +#include +#include "mthca_log.rc" \ No newline at end of file diff --git a/branches/WOF2-3/hw/mthca/kernel/hca_data.c b/branches/WOF2-3/hw/mthca/kernel/hca_data.c new file mode 100644 index 00000000..80389be1 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/hca_data.c @@ -0,0 +1,973 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2004-2005 Mellanox Technologies, Inc. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include "hca_driver.h" +#include "hca_utils.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "hca_data.tmh" +#endif + +#include "mthca_dev.h" +#include + +static cl_spinlock_t hob_lock; + + + +uint32_t g_mlnx_dpc2thread = 0; + + +cl_qlist_t mlnx_hca_list; + +mlnx_hob_t mlnx_hob_array[MLNX_NUM_HOBKL]; // kernel HOB - one per HCA (cmdif access) +mlnx_hobul_t *mlnx_hobul_array[MLNX_NUM_HOBUL]; // kernel HOBUL - one per HCA (kar access) + +///////////////////////////////////////////////////////// +// ### HCA +///////////////////////////////////////////////////////// +void +mlnx_hca_insert( + IN mlnx_hca_t *p_hca ) +{ + cl_spinlock_acquire( &hob_lock ); + cl_qlist_insert_tail( &mlnx_hca_list, &p_hca->list_item ); + cl_spinlock_release( &hob_lock ); +} + +void +mlnx_hca_remove( + IN mlnx_hca_t *p_hca ) +{ + cl_spinlock_acquire( &hob_lock ); + cl_qlist_remove_item( &mlnx_hca_list, &p_hca->list_item ); + cl_spinlock_release( &hob_lock ); +} + +mlnx_hca_t* +mlnx_hca_from_guid( + IN ib_net64_t guid ) +{ + cl_list_item_t *p_item; + mlnx_hca_t *p_hca = NULL; + + cl_spinlock_acquire( &hob_lock ); + p_item = cl_qlist_head( &mlnx_hca_list ); + while( p_item != cl_qlist_end( &mlnx_hca_list ) ) + { + p_hca = PARENT_STRUCT( p_item, mlnx_hca_t, list_item ); + if( p_hca->guid == guid ) + break; + p_item = cl_qlist_next( p_item ); + p_hca = NULL; + } + cl_spinlock_release( &hob_lock ); + return p_hca; +} + +/* +void +mlnx_names_from_guid( + IN ib_net64_t guid, + OUT char **hca_name_p, + OUT char **dev_name_p) +{ + unsigned int idx; + + if (!hca_name_p) return; + if (!dev_name_p) return; + + for (idx = 0; idx < mlnx_num_hca; idx++) + { + if (mlnx_hca_array[idx].ifx.guid == guid) + { + *hca_name_p = mlnx_hca_array[idx].hca_name_p; + *dev_name_p = mlnx_hca_array[idx].dev_name_p; + } + } +} +*/ + +///////////////////////////////////////////////////////// +// ### HCA +///////////////////////////////////////////////////////// +cl_status_t +mlnx_hcas_init( void ) +{ + cl_qlist_init( &mlnx_hca_list ); + return cl_spinlock_init( &hob_lock ); +} + + +///////////////////////////////////////////////////////// +///////////////////////////////////////////////////////// +ib_api_status_t +mlnx_hobs_set_cb( + IN mlnx_hob_t *hob_p, + IN ci_async_event_cb_t async_cb_p, + IN const void* const ib_context) +{ + cl_status_t cl_status; + + // Setup the callbacks + if (!hob_p->async_proc_mgr_p) + { + hob_p->async_proc_mgr_p = cl_malloc( sizeof( cl_async_proc_t ) ); + if( !hob_p->async_proc_mgr_p ) + { + return IB_INSUFFICIENT_MEMORY; + } + cl_async_proc_construct( hob_p->async_proc_mgr_p ); + cl_status = cl_async_proc_init( hob_p->async_proc_mgr_p, MLNX_NUM_CB_THR, "CBthread" ); + if( cl_status != CL_SUCCESS ) + { + cl_async_proc_destroy( hob_p->async_proc_mgr_p ); + cl_free(hob_p->async_proc_mgr_p); + hob_p->async_proc_mgr_p = NULL; + return IB_INSUFFICIENT_RESOURCES; + } + } + + hob_p->async_cb_p = async_cb_p; + hob_p->ca_context = ib_context; // This is the context our CB forwards to IBAL + HCA_PRINT(TRACE_LEVEL_INFORMATION, HCA_DBG_SHIM,("CL: hca_idx %d context 0x%p\n", (int)(hob_p - mlnx_hob_array), ib_context)); + return IB_SUCCESS; +} + +///////////////////////////////////////////////////////// +///////////////////////////////////////////////////////// +void +mlnx_hobs_remove( + IN mlnx_hob_t *hob_p) +{ + cl_async_proc_t *p_async_proc; + + + cl_spinlock_acquire( &hob_lock ); + + hob_p->mark = E_MARK_INVALID; + + p_async_proc = hob_p->async_proc_mgr_p; + hob_p->async_proc_mgr_p = NULL; + + hob_p->async_cb_p = NULL; + hob_p->ca_context = NULL; + hob_p->cl_device_h = NULL; + + cl_spinlock_release( &hob_lock ); + + if( p_async_proc ) + { + cl_async_proc_destroy( p_async_proc ); + cl_free( p_async_proc ); + } + + + + HCA_PRINT(TRACE_LEVEL_INFORMATION, HCA_DBG_SHIM,("CL: hobs_remove idx %d \n", (int)(hob_p - mlnx_hob_array))); +} + +///////////////////////////////////////////////////////// +///////////////////////////////////////////////////////// +void +mthca_port_cap_to_ibal( + IN u32 mthca_port_cap, + OUT ib_port_cap_t *ibal_port_cap_p) +{ +#define SET_CAP(flag,cap) if (mthca_port_cap & flag) ibal_port_cap_p->cap = TRUE + + SET_CAP(IB_PORT_CM_SUP,cm); + SET_CAP(IB_PORT_SNMP_TUNNEL_SUP,snmp); + SET_CAP(IB_PORT_DEVICE_MGMT_SUP,dev_mgmt); + SET_CAP(IB_PORT_VENDOR_CLASS_SUP,vend); + SET_CAP(IB_PORT_SM_DISABLED,sm_disable); + SET_CAP(IB_PORT_SM,sm); + SET_CAP(IB_PORT_NOTICE_SUP,notice); + SET_CAP(IB_PORT_TRAP_SUP,trap); + SET_CAP(IB_PORT_AUTO_MIGR_SUP,apm); + SET_CAP(IB_PORT_SL_MAP_SUP,slmap); + SET_CAP(IB_PORT_LED_INFO_SUP,ledinfo); + SET_CAP(IB_PORT_CAP_MASK_NOTICE_SUP,capm_notice); + SET_CAP(IB_PORT_CLIENT_REG_SUP,client_reregister); + SET_CAP(IB_PORT_SYS_IMAGE_GUID_SUP,sysguid); + SET_CAP(IB_PORT_BOOT_MGMT_SUP,boot_mgmt); + SET_CAP(IB_PORT_DR_NOTICE_SUP,dr_notice); + SET_CAP(IB_PORT_PKEY_SW_EXT_PORT_TRAP_SUP,pkey_switch_ext_port); + SET_CAP(IB_PORT_LINK_LATENCY_SUP,link_rtl); + SET_CAP(IB_PORT_REINIT_SUP,reinit); + SET_CAP(IB_PORT_OPT_IPD_SUP,ipd); + SET_CAP(IB_PORT_MKEY_NVRAM,mkey_nvram); + SET_CAP(IB_PORT_PKEY_NVRAM,pkey_nvram); + // there no MTHCA flags for qkey_ctr, pkey_ctr, port_active, bm IBAL capabilities; +} + + +///////////////////////////////////////////////////////// +void +mlnx_conv_hca_cap( + IN struct ib_device *ib_dev, + IN struct ib_device_attr *hca_info_p, + IN struct ib_port_attr *hca_ports, + OUT ib_ca_attr_t *ca_attr_p) +{ + uint8_t port_num; + ib_port_attr_t *ibal_port_p; + struct ib_port_attr *mthca_port_p; + + ca_attr_p->vend_id = hca_info_p->vendor_id; + ca_attr_p->dev_id = (uint16_t)hca_info_p->vendor_part_id; + ca_attr_p->revision = (uint16_t)hca_info_p->hw_ver; + ca_attr_p->fw_ver = hca_info_p->fw_ver; + ca_attr_p->ca_guid = *(UNALIGNED64 uint64_t *)&ib_dev->node_guid; + ca_attr_p->num_ports = ib_dev->phys_port_cnt; + ca_attr_p->max_qps = hca_info_p->max_qp; + ca_attr_p->max_wrs = hca_info_p->max_qp_wr; + ca_attr_p->max_sges = hca_info_p->max_sge; + ca_attr_p->max_rd_sges = hca_info_p->max_sge_rd; + ca_attr_p->max_cqs = hca_info_p->max_cq; + ca_attr_p->max_cqes = hca_info_p->max_cqe; + ca_attr_p->max_pds = hca_info_p->max_pd; + ca_attr_p->init_regions = hca_info_p->max_mr; + ca_attr_p->init_windows = hca_info_p->max_mw; + ca_attr_p->init_region_size = hca_info_p->max_mr_size; + ca_attr_p->max_addr_handles = hca_info_p->max_ah; + ca_attr_p->atomicity = hca_info_p->atomic_cap; + ca_attr_p->max_partitions = hca_info_p->max_pkeys; + ca_attr_p->max_qp_resp_res =(uint8_t) hca_info_p->max_qp_rd_atom; + ca_attr_p->max_resp_res = (uint8_t)hca_info_p->max_res_rd_atom; + ca_attr_p->max_qp_init_depth = (uint8_t)hca_info_p->max_qp_init_rd_atom; + ca_attr_p->max_ipv6_qps = hca_info_p->max_raw_ipv6_qp; + ca_attr_p->max_ether_qps = hca_info_p->max_raw_ethy_qp; + ca_attr_p->max_mcast_grps = hca_info_p->max_mcast_grp; + ca_attr_p->max_mcast_qps = hca_info_p->max_total_mcast_qp_attach; + ca_attr_p->max_qps_per_mcast_grp = hca_info_p->max_mcast_qp_attach; + ca_attr_p->max_fmr = hca_info_p->max_fmr; + ca_attr_p->max_map_per_fmr = hca_info_p->max_map_per_fmr; + ca_attr_p->max_srq = hca_info_p->max_srq; + ca_attr_p->max_srq_wrs = hca_info_p->max_srq_wr; + ca_attr_p->max_srq_sges = hca_info_p->max_srq_sge; + ca_attr_p->system_image_guid = hca_info_p->sys_image_guid; + + ca_attr_p->local_ack_delay = hca_info_p->local_ca_ack_delay; + ca_attr_p->bad_pkey_ctr_support = hca_info_p->device_cap_flags & IB_DEVICE_BAD_PKEY_CNTR; + ca_attr_p->bad_qkey_ctr_support = hca_info_p->device_cap_flags & IB_DEVICE_BAD_QKEY_CNTR; + ca_attr_p->raw_mcast_support = hca_info_p->device_cap_flags & IB_DEVICE_RAW_MULTI; + ca_attr_p->apm_support = hca_info_p->device_cap_flags & IB_DEVICE_AUTO_PATH_MIG; + ca_attr_p->av_port_check = hca_info_p->device_cap_flags & IB_DEVICE_UD_AV_PORT_ENFORCE; + ca_attr_p->change_primary_port = hca_info_p->device_cap_flags & IB_DEVICE_CHANGE_PHY_PORT; + ca_attr_p->modify_wr_depth = hca_info_p->device_cap_flags & IB_DEVICE_RESIZE_MAX_WR; + ca_attr_p->modify_srq_depth = hca_info_p->device_cap_flags & IB_DEVICE_SRQ_RESIZE; + ca_attr_p->system_image_guid_support = hca_info_p->device_cap_flags & IB_DEVICE_SYS_IMAGE_GUID; + ca_attr_p->hw_agents = FALSE; // in the context of IBAL then agent is implemented on the host + ca_attr_p->ipoib_csum = hca_info_p->device_cap_flags & IB_DEVICE_IPOIB_CSUM; + + ca_attr_p->num_page_sizes = 1; + ca_attr_p->p_page_size[0] = PAGE_SIZE; // TBD: extract an array of page sizes from HCA cap + + for (port_num = 0; port_num <= end_port(ib_dev) - start_port(ib_dev); ++port_num) + { + // Setup port pointers + ibal_port_p = &ca_attr_p->p_port_attr[port_num]; + mthca_port_p = &hca_ports[port_num]; + + // Port Cabapilities + cl_memclr(&ibal_port_p->cap, sizeof(ib_port_cap_t)); + mthca_port_cap_to_ibal(mthca_port_p->port_cap_flags, &ibal_port_p->cap); + + // Port Atributes + ibal_port_p->port_num = port_num + start_port(ib_dev); + ibal_port_p->port_guid = ibal_port_p->p_gid_table[0].unicast.interface_id; + ibal_port_p->lid = cl_ntoh16(mthca_port_p->lid); + ibal_port_p->lmc = mthca_port_p->lmc; + ibal_port_p->max_vls = mthca_port_p->max_vl_num; + ibal_port_p->sm_lid = cl_ntoh16(mthca_port_p->sm_lid); + ibal_port_p->sm_sl = mthca_port_p->sm_sl; + ibal_port_p->link_state = (mthca_port_p->state != 0) ? (uint8_t)mthca_port_p->state : IB_LINK_DOWN; + ibal_port_p->num_gids = (uint16_t)mthca_port_p->gid_tbl_len; + ibal_port_p->num_pkeys = mthca_port_p->pkey_tbl_len; + ibal_port_p->pkey_ctr = (uint16_t)mthca_port_p->bad_pkey_cntr; + ibal_port_p->qkey_ctr = (uint16_t)mthca_port_p->qkey_viol_cntr; + ibal_port_p->max_msg_size = mthca_port_p->max_msg_sz; + ibal_port_p->mtu = (uint8_t)mthca_port_p->max_mtu; + ibal_port_p->active_speed = mthca_port_p->active_speed; + ibal_port_p->active_width = mthca_port_p->active_width; + ibal_port_p->phys_state = mthca_port_p->phys_state; + + ibal_port_p->subnet_timeout = mthca_port_p->subnet_timeout; + // ibal_port_p->local_ack_timeout = 3; // TBD: currently ~32 usec + HCA_PRINT(TRACE_LEVEL_VERBOSE, HCA_DBG_SHIM ,("Port %d port_guid 0x%I64x\n", + ibal_port_p->port_num, cl_ntoh64(ibal_port_p->port_guid))); + } +} + +void ca_event_handler(struct ib_event *ev, void *context) +{ + mlnx_hob_t *hob_p = (mlnx_hob_t *)context; + ib_event_rec_t event_rec; + LIST_ENTRY *entry; + ci_event_handler_t *event_handler; + + // prepare parameters + event_rec.type = ev->event; + event_rec.port_number = ev->element.port_num; + if (event_rec.type > IB_AE_UNKNOWN) { + // CL_ASSERT(0); // This shouldn't happen + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_SHIM,("Unmapped E_EV_CA event of type 0x%x. Replaced by 0x%x (IB_AE_LOCAL_FATAL)\n", + event_rec.type, IB_AE_LOCAL_FATAL)); + event_rec.type = IB_AE_LOCAL_FATAL; + } + + // call the user callback + KeAcquireSpinLockAtDpcLevel(&hob_p->event_list_lock); + for (entry = hob_p->event_list.Flink; entry != &hob_p->event_list; + entry = entry->Flink) { + + event_handler = CONTAINING_RECORD(entry, ci_event_handler_t, entry); + event_rec.context = (void *) event_handler; + event_handler->pfn_async_event_cb(&event_rec); + } + KeReleaseSpinLockFromDpcLevel(&hob_p->event_list_lock); + + if (hob_p && hob_p->async_cb_p) { + event_rec.context = (void *)hob_p->ca_context; + (hob_p->async_cb_p)(&event_rec); + } else { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_SHIM ,("Incorrect context. Async callback was not invoked\n")); + } +} + +ib_qp_state_t mlnx_qps_to_ibal(enum ib_qp_state qps) +{ +#define MAP_QPS(val1,val2) case val1: ib_qps = val2; break + ib_qp_state_t ib_qps; + switch (qps) { + MAP_QPS( IBQPS_RESET, IB_QPS_RESET ); + MAP_QPS( IBQPS_INIT, IB_QPS_INIT ); + MAP_QPS( IBQPS_RTR, IB_QPS_RTR ); + MAP_QPS( IBQPS_RTS, IB_QPS_RTS ); + MAP_QPS( IBQPS_SQD, IB_QPS_SQD ); + MAP_QPS( IBQPS_SQE, IB_QPS_SQERR ); + MAP_QPS( IBQPS_ERR, IB_QPS_ERROR ); + default: + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_SHIM ,("Unmapped MTHCA qp_state %d\n", qps)); + ib_qps = 0xffffffff; + } + return ib_qps; +} + +enum ib_qp_state mlnx_qps_from_ibal(ib_qp_state_t ib_qps) +{ +#define MAP_IBQPS(val1,val2) case val1: qps = val2; break + enum ib_qp_state qps; + switch (ib_qps) { + MAP_IBQPS( IB_QPS_RESET, IBQPS_RESET ); + MAP_IBQPS( IB_QPS_INIT, IBQPS_INIT ); + MAP_IBQPS( IB_QPS_RTR, IBQPS_RTR ); + MAP_IBQPS( IB_QPS_RTS, IBQPS_RTS ); + MAP_IBQPS( IB_QPS_SQD, IBQPS_SQD ); + MAP_IBQPS( IB_QPS_SQD_DRAINING, IBQPS_SQD ); + MAP_IBQPS( IB_QPS_SQD_DRAINED, IBQPS_SQD ); + MAP_IBQPS( IB_QPS_SQERR, IBQPS_SQE ); + MAP_IBQPS( IB_QPS_ERROR, IBQPS_ERR ); + default: + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_SHIM ,("Unmapped IBAL qp_state %d\n", ib_qps)); + qps = 0xffffffff; + } + return qps; +} + +enum ib_mig_state to_apm_state(ib_apm_state_t apm) +{ + if (apm == IB_APM_MIGRATED) return IB_MIG_MIGRATED; + if (apm == IB_APM_REARM) return IB_MIG_REARM; + if (apm == IB_APM_ARMED) return IB_MIG_ARMED; + return 0xffffffff; +} + +ib_api_status_t +mlnx_conv_qp_modify_attr( + IN const struct ib_qp *ib_qp_p, + IN ib_qp_type_t qp_type, + IN const ib_qp_mod_t *modify_attr_p, + OUT struct ib_qp_attr *qp_attr_p, + OUT int *qp_attr_mask_p + ) +{ + int err; + ib_api_status_t status = IB_SUCCESS; + struct mthca_qp *qp_p = (struct mthca_qp *)ib_qp_p; + + RtlZeroMemory( qp_attr_p, sizeof *qp_attr_p ); + *qp_attr_mask_p = IB_QP_STATE; + qp_attr_p->qp_state = mlnx_qps_from_ibal( modify_attr_p->req_state ); + + // skipped cases + if (qp_p->state == IBQPS_RESET && modify_attr_p->req_state != IB_QPS_INIT) + return IB_NOT_DONE; + + switch (modify_attr_p->req_state) { + case IB_QPS_RESET: + case IB_QPS_ERROR: + case IB_QPS_SQERR: + case IB_QPS_TIME_WAIT: + break; + + case IB_QPS_INIT: + + switch (qp_type) { + case IB_QPT_RELIABLE_CONN: + case IB_QPT_UNRELIABLE_CONN: + *qp_attr_mask_p |= IB_QP_PORT | IB_QP_PKEY_INDEX |IB_QP_ACCESS_FLAGS; + qp_attr_p->qp_access_flags = map_qp_ibal_acl(modify_attr_p->state.init.access_ctrl); + break; + case IB_QPT_UNRELIABLE_DGRM: + case IB_QPT_QP0: + case IB_QPT_QP1: + default: + *qp_attr_mask_p |= IB_QP_PORT | IB_QP_QKEY | IB_QP_PKEY_INDEX ; + qp_attr_p->qkey = cl_ntoh32 (modify_attr_p->state.init.qkey); + break; + } + + // IB_QP_PORT + qp_attr_p->port_num = modify_attr_p->state.init.primary_port; + + // IB_QP_PKEY_INDEX + qp_attr_p->pkey_index = modify_attr_p->state.init.pkey_index; + + break; + + case IB_QPS_RTR: + /* modifying the WQE depth is not supported */ + if( modify_attr_p->state.rtr.opts & IB_MOD_QP_SQ_DEPTH || + modify_attr_p->state.rtr.opts & IB_MOD_QP_RQ_DEPTH ) { + status = IB_UNSUPPORTED; + break; + } + + switch (qp_type) { + case IB_QPT_RELIABLE_CONN: + *qp_attr_mask_p |= /* required flags */ + IB_QP_DEST_QPN |IB_QP_RQ_PSN | IB_QP_MAX_DEST_RD_ATOMIC | + IB_QP_AV |IB_QP_PATH_MTU | IB_QP_MIN_RNR_TIMER; + + // IB_QP_DEST_QPN + qp_attr_p->dest_qp_num = cl_ntoh32 (modify_attr_p->state.rtr.dest_qp); + + // IB_QP_RQ_PSN + qp_attr_p->rq_psn = cl_ntoh32 (modify_attr_p->state.rtr.rq_psn); + + // IB_QP_MAX_DEST_RD_ATOMIC + qp_attr_p->max_dest_rd_atomic = modify_attr_p->state.rtr.resp_res; + + // IB_QP_AV, IB_QP_PATH_MTU: Convert primary RC AV (mandatory) + err = mlnx_conv_ibal_av(ib_qp_p->device, + &modify_attr_p->state.rtr.primary_av, &qp_attr_p->ah_attr); + if (err) { + status = IB_ERROR; + break; + } + qp_attr_p->path_mtu = modify_attr_p->state.rtr.primary_av.conn.path_mtu; // MTU + qp_attr_p->timeout = modify_attr_p->state.rtr.primary_av.conn.local_ack_timeout; // MTU + qp_attr_p->retry_cnt = modify_attr_p->state.rtr.primary_av.conn.seq_err_retry_cnt; // MTU + qp_attr_p->rnr_retry = modify_attr_p->state.rtr.primary_av.conn.rnr_retry_cnt; // MTU + + // IB_QP_MIN_RNR_TIMER, required in RTR, optional in RTS. + qp_attr_p->min_rnr_timer = modify_attr_p->state.rtr.rnr_nak_timeout; + + // IB_QP_ACCESS_FLAGS: Convert Remote Atomic Flags + if (modify_attr_p->state.rtr.opts & IB_MOD_QP_ACCESS_CTRL) { + *qp_attr_mask_p |= IB_QP_ACCESS_FLAGS; /* optional flag */ + qp_attr_p->qp_access_flags = map_qp_ibal_acl(modify_attr_p->state.rtr.access_ctrl); + } + + // IB_QP_ALT_PATH: Convert alternate RC AV + if (modify_attr_p->state.rtr.opts & IB_MOD_QP_ALTERNATE_AV) { + *qp_attr_mask_p |= IB_QP_ALT_PATH; /* required flag */ + err = mlnx_conv_ibal_av(ib_qp_p->device, + &modify_attr_p->state.rtr.alternate_av, &qp_attr_p->alt_ah_attr); + if (err) { + status = IB_ERROR; + break; + } + qp_attr_p->alt_timeout = modify_attr_p->state.rtr.alternate_av.conn.local_ack_timeout; // XXX: conv + } + + // IB_QP_PKEY_INDEX + if (modify_attr_p->state.rtr.opts & IB_MOD_QP_PKEY) { + *qp_attr_mask_p |= IB_QP_PKEY_INDEX; + qp_attr_p->pkey_index = modify_attr_p->state.rtr.pkey_index; + } + break; + + case IB_QPT_UNRELIABLE_CONN: + *qp_attr_mask_p |= /* required flags */ + IB_QP_DEST_QPN |IB_QP_RQ_PSN | IB_QP_AV | IB_QP_PATH_MTU; + + // IB_QP_DEST_QPN + qp_attr_p->dest_qp_num = cl_ntoh32 (modify_attr_p->state.rtr.dest_qp); + + // IB_QP_RQ_PSN + qp_attr_p->rq_psn = cl_ntoh32 (modify_attr_p->state.rtr.rq_psn); + + // IB_QP_PATH_MTU + qp_attr_p->path_mtu = modify_attr_p->state.rtr.primary_av.conn.path_mtu; + + // IB_QP_AV: Convert primary AV (mandatory) + err = mlnx_conv_ibal_av(ib_qp_p->device, + &modify_attr_p->state.rtr.primary_av, &qp_attr_p->ah_attr); + if (err) { + status = IB_ERROR; + break; + } + + // IB_QP_ACCESS_FLAGS: Convert Remote Atomic Flags + if (modify_attr_p->state.rtr.opts & IB_MOD_QP_ACCESS_CTRL) { + *qp_attr_mask_p |= IB_QP_ACCESS_FLAGS; /* optional flag */ + qp_attr_p->qp_access_flags = map_qp_ibal_acl(modify_attr_p->state.rtr.access_ctrl); + } + + // IB_QP_ALT_PATH: Convert alternate RC AV + if (modify_attr_p->state.rtr.opts & IB_MOD_QP_ALTERNATE_AV) { + *qp_attr_mask_p |= IB_QP_ALT_PATH; /* required flag */ + err = mlnx_conv_ibal_av(ib_qp_p->device, + &modify_attr_p->state.rtr.alternate_av, &qp_attr_p->alt_ah_attr); + if (err) { + status = IB_ERROR; + break; + } + } + + // IB_QP_PKEY_INDEX + if (modify_attr_p->state.rtr.opts & IB_MOD_QP_PKEY) { + *qp_attr_mask_p |= IB_QP_PKEY_INDEX; + qp_attr_p->pkey_index = modify_attr_p->state.rtr.pkey_index; + } + break; + + case IB_QPT_UNRELIABLE_DGRM: + case IB_QPT_QP0: + case IB_QPT_QP1: + default: + // IB_QP_PKEY_INDEX + if (modify_attr_p->state.rtr.opts & IB_MOD_QP_PKEY) { + *qp_attr_mask_p |= IB_QP_PKEY_INDEX; + qp_attr_p->pkey_index = modify_attr_p->state.rtr.pkey_index; + } + + // IB_QP_QKEY + if (modify_attr_p->state.rtr.opts & IB_MOD_QP_QKEY) { + *qp_attr_mask_p |= IB_QP_QKEY; + qp_attr_p->qkey = cl_ntoh32 (modify_attr_p->state.rtr.qkey); + } + break; + + } + break; + + case IB_QPS_RTS: + /* modifying the WQE depth is not supported */ + if( modify_attr_p->state.rts.opts & IB_MOD_QP_SQ_DEPTH || + modify_attr_p->state.rts.opts & IB_MOD_QP_RQ_DEPTH ) + { + status = IB_UNSUPPORTED; + break; + } + + switch (qp_type) { + case IB_QPT_RELIABLE_CONN: + if (qp_p->state != IBQPS_RTS) + *qp_attr_mask_p |= /* required flags */ + IB_QP_SQ_PSN |IB_QP_MAX_QP_RD_ATOMIC | IB_QP_TIMEOUT | + IB_QP_RETRY_CNT |IB_QP_RNR_RETRY; + + // IB_QP_MAX_QP_RD_ATOMIC + qp_attr_p->max_rd_atomic = modify_attr_p->state.rts.init_depth; + + // IB_QP_TIMEOUT + qp_attr_p->timeout = modify_attr_p->state.rts.local_ack_timeout; // XXX: conv + + // IB_QP_RETRY_CNT + qp_attr_p->retry_cnt = modify_attr_p->state.rts.retry_cnt; + + // IB_QP_RNR_RETRY + qp_attr_p->rnr_retry = modify_attr_p->state.rts.rnr_retry_cnt; + + // IB_QP_MAX_DEST_RD_ATOMIC: Update the responder resources for RDMA/ATOMIC (optional for SQD->RTS) + if (modify_attr_p->state.rts.opts & IB_MOD_QP_RESP_RES) { + *qp_attr_mask_p |= IB_QP_MAX_DEST_RD_ATOMIC; + qp_attr_p->max_dest_rd_atomic = modify_attr_p->state.rts.resp_res; + } + +#ifdef WIN_TO_BE_REMOVED + //TODO: do we need that ? + // Linux patch 4793: PKEY_INDEX is not a legal parameter in the RTR->RTS transition. + + // IB_QP_PKEY_INDEX + if (modify_attr_p->state.rts.opts & IB_MOD_QP_PKEY) { + *qp_attr_mask_p |= IB_QP_PKEY_INDEX; + qp_attr_p->pkey_index = modify_attr_p->state.rts.pkey_index; + } +#endif + + // IB_QP_MIN_RNR_TIMER + if (modify_attr_p->state.rts.opts & IB_MOD_QP_RNR_NAK_TIMEOUT) { + *qp_attr_mask_p |= IB_QP_MIN_RNR_TIMER; + qp_attr_p->min_rnr_timer = modify_attr_p->state.rts.rnr_nak_timeout; + } + + // IB_QP_PATH_MIG_STATE + if (modify_attr_p->state.rts.opts & IB_MOD_QP_APM_STATE) { + *qp_attr_mask_p |= IB_QP_PATH_MIG_STATE; + qp_attr_p->path_mig_state = to_apm_state(modify_attr_p->state.rts.apm_state); + } + + // IB_QP_ACCESS_FLAGS + if (modify_attr_p->state.rts.opts & IB_MOD_QP_ACCESS_CTRL) { + *qp_attr_mask_p |= IB_QP_ACCESS_FLAGS; /* optional flags */ + qp_attr_p->qp_access_flags = map_qp_ibal_acl(modify_attr_p->state.rts.access_ctrl); + } + + // IB_QP_ALT_PATH: Convert alternate RC AV + if (modify_attr_p->state.rts.opts & IB_MOD_QP_ALTERNATE_AV) { + *qp_attr_mask_p |= IB_QP_ALT_PATH; /* optional flag */ + err = mlnx_conv_ibal_av(ib_qp_p->device, + &modify_attr_p->state.rts.alternate_av, &qp_attr_p->alt_ah_attr); + if (err) { + status = IB_ERROR; + break; + } + qp_attr_p->alt_timeout = modify_attr_p->state.rts.alternate_av.conn.local_ack_timeout; // XXX: conv + } + break; + + case IB_QPT_UNRELIABLE_CONN: + if (qp_p->state != IBQPS_RTS) + *qp_attr_mask_p |= /* required flags */ + IB_QP_SQ_PSN; + + // IB_QP_MAX_DEST_RD_ATOMIC: Update the responder resources for RDMA/ATOMIC (optional for SQD->RTS) + if (modify_attr_p->state.rts.opts & IB_MOD_QP_RESP_RES) { + *qp_attr_mask_p |= IB_QP_MAX_DEST_RD_ATOMIC; + qp_attr_p->max_dest_rd_atomic = modify_attr_p->state.rts.resp_res; + } + +#ifdef WIN_TO_BE_REMOVED + //TODO: do we need that ? + // Linux patch 4793: PKEY_INDEX is not a legal parameter in the RTR->RTS transition. + + // IB_QP_PKEY_INDEX + if (modify_attr_p->state.rts.opts & IB_MOD_QP_PKEY) { + *qp_attr_mask_p |= IB_QP_PKEY_INDEX; + qp_attr_p->pkey_index = modify_attr_p->state.rts.pkey_index; + } +#endif + + // IB_QP_PATH_MIG_STATE + if (modify_attr_p->state.rts.opts & IB_MOD_QP_APM_STATE) { + *qp_attr_mask_p |= IB_QP_PATH_MIG_STATE; + qp_attr_p->path_mig_state = to_apm_state(modify_attr_p->state.rts.apm_state); + } + + // IB_QP_ACCESS_FLAGS + if (modify_attr_p->state.rts.opts & IB_MOD_QP_ACCESS_CTRL) { + *qp_attr_mask_p |= IB_QP_ACCESS_FLAGS; /* optional flags */ + qp_attr_p->qp_access_flags = map_qp_ibal_acl(modify_attr_p->state.rts.access_ctrl); + } + + // IB_QP_ALT_PATH: Convert alternate RC AV + if (modify_attr_p->state.rts.opts & IB_MOD_QP_ALTERNATE_AV) { + *qp_attr_mask_p |= IB_QP_ALT_PATH; /* optional flag */ + err = mlnx_conv_ibal_av(ib_qp_p->device, + &modify_attr_p->state.rts.alternate_av, &qp_attr_p->alt_ah_attr); + if (err) { + status = IB_ERROR; + break; + } + } + break; + + case IB_QPT_UNRELIABLE_DGRM: + case IB_QPT_QP0: + case IB_QPT_QP1: + default: + if (qp_p->state != IBQPS_RTS) + *qp_attr_mask_p |= /* required flags */ + IB_QP_SQ_PSN; + + // IB_QP_QKEY + if (modify_attr_p->state.rts.opts & IB_MOD_QP_QKEY) { + *qp_attr_mask_p |= IB_QP_QKEY; + qp_attr_p->qkey = cl_ntoh32 (modify_attr_p->state.rts.qkey); + } + break; + + break; + + } + + // IB_QP_SQ_PSN: common for all + qp_attr_p->sq_psn = cl_ntoh32 (modify_attr_p->state.rts.sq_psn); + //NB: IB_QP_CUR_STATE flag is not provisioned by IBAL + break; + + case IB_QPS_SQD: + case IB_QPS_SQD_DRAINING: + case IB_QPS_SQD_DRAINED: + *qp_attr_mask_p |= IB_QP_EN_SQD_ASYNC_NOTIFY; + qp_attr_p->en_sqd_async_notify = (u8)modify_attr_p->state.sqd.sqd_event; + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_SHIM ,("IB_QP_EN_SQD_ASYNC_NOTIFY seems like unsupported\n")); + break; + + default: + //NB: is this an error case and we need this message ? What about returning an error ? + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_SHIM ,("Unmapped qp_state %d\n", modify_attr_p->req_state)); + break; + + } + + return status; +} + +int +mlnx_conv_ibal_av( + IN const struct ib_device *ib_dev_p, + IN const ib_av_attr_t *ibal_av_p, + OUT struct ib_ah_attr *ah_attr_p) +{ + int err = 0; + u8 port_num; + u16 gid_index; + + ah_attr_p->port_num = ibal_av_p->port_num; + ah_attr_p->sl = ibal_av_p->sl; + ah_attr_p->dlid = cl_ntoh16(ibal_av_p->dlid); + //TODO: how static_rate is coded ? + ah_attr_p->static_rate = + (ibal_av_p->static_rate == IB_PATH_RECORD_RATE_10_GBS ? 0 : 3); + ah_attr_p->src_path_bits = ibal_av_p->path_bits; // PATH: + + /* For global destination or Multicast address:*/ + if (ibal_av_p->grh_valid) + { + ah_attr_p->ah_flags |= IB_AH_GRH; + ah_attr_p->grh.hop_limit = ibal_av_p->grh.hop_limit; + ib_grh_get_ver_class_flow( ibal_av_p->grh.ver_class_flow, NULL, + &ah_attr_p->grh.traffic_class, &ah_attr_p->grh.flow_label ); + err = ib_find_cached_gid((struct ib_device *)ib_dev_p, + (union ib_gid *)ibal_av_p->grh.src_gid.raw, &port_num, &gid_index); + if (err) { + + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_SHIM ,("ib_find_cached_gid failed %d (%#x). Using default: sgid_index = 0\n", err, err)); + gid_index = 0; + } + else if (port_num != ah_attr_p->port_num) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_SHIM ,("ib_find_cached_gid returned wrong port_num %u (Expected - %u). Using the expected.\n", + (u32)port_num, (u32)ah_attr_p->port_num)); + } + ah_attr_p->grh.sgid_index = (u8)gid_index; + RtlCopyMemory(ah_attr_p->grh.dgid.raw, ibal_av_p->grh.dest_gid.raw, sizeof(ah_attr_p->grh.dgid)); + } + + return err; +} + +int +mlnx_conv_mthca_av( + IN const struct ib_ah *ib_ah_p, + OUT ib_av_attr_t *ibal_av_p) +{ + int err = 0; + struct ib_ud_header header; + struct mthca_ah *ah_p = (struct mthca_ah *)ib_ah_p; + struct ib_device *ib_dev_p = ib_ah_p->pd->device; + struct mthca_dev *dev_p = (struct mthca_dev *)ib_dev_p; + + err = mthca_read_ah( dev_p, ah_p, &header); + if (err) + goto err_read_ah; + + // common part + ibal_av_p->sl = header.lrh.service_level; + mthca_get_av_params(ah_p, &ibal_av_p->port_num, + &ibal_av_p->dlid, &ibal_av_p->static_rate, &ibal_av_p->path_bits ); + + // GRH + ibal_av_p->grh_valid = header.grh_present; + if (ibal_av_p->grh_valid) { + ibal_av_p->grh.ver_class_flow = ib_grh_set_ver_class_flow( + header.grh.ip_version, header.grh.traffic_class, header.grh.flow_label ); + ibal_av_p->grh.hop_limit = header.grh.hop_limit; + RtlCopyMemory(ibal_av_p->grh.src_gid.raw, + header.grh.source_gid.raw, sizeof(ibal_av_p->grh.src_gid)); + RtlCopyMemory(ibal_av_p->grh.src_gid.raw, + header.grh.destination_gid.raw, sizeof(ibal_av_p->grh.dest_gid)); + } + + //TODO: don't know, how to fill conn. Note, that previous version didn't fill it also. + +err_read_ah: + return err; +} + +void +mlnx_modify_ah( + IN const struct ib_ah *ib_ah_p, + IN const struct ib_ah_attr *ah_attr_p) +{ + struct ib_device *ib_dev_p = ib_ah_p->pd->device; + struct mthca_dev *dev_p = (struct mthca_dev *)ib_dev_p; + + mthca_set_av_params(dev_p, (struct mthca_ah *)ib_ah_p, (struct ib_ah_attr *)ah_attr_p ); +} + +uint8_t from_rate(enum ib_rate ib_rate) +{ + if (ib_rate == IB_RATE_2_5_GBPS) return IB_PATH_RECORD_RATE_2_5_GBS; + if (ib_rate == IB_RATE_5_GBPS) return IB_PATH_RECORD_RATE_5_GBS; + if (ib_rate == IB_RATE_10_GBPS) return IB_PATH_RECORD_RATE_10_GBS; + if (ib_rate == IB_RATE_20_GBPS) return IB_PATH_RECORD_RATE_20_GBS; + if (ib_rate == IB_RATE_30_GBPS) return IB_PATH_RECORD_RATE_30_GBS; + if (ib_rate == IB_RATE_40_GBPS) return IB_PATH_RECORD_RATE_40_GBS; + if (ib_rate == IB_RATE_60_GBPS) return IB_PATH_RECORD_RATE_60_GBS; + if (ib_rate == IB_RATE_80_GBPS) return IB_PATH_RECORD_RATE_80_GBS; + if (ib_rate == IB_RATE_120_GBPS) return IB_PATH_RECORD_RATE_120_GBS; + return 0; +} + +int from_av( + IN const struct ib_device *p_ib_dev, + IN struct ib_qp_attr *p_ib_qp_attr, + IN struct ib_ah_attr *p_ib_ah_attr, + OUT ib_av_attr_t *p_ib_av_attr) +{ + int err = 0; + + p_ib_av_attr->port_num = p_ib_ah_attr->port_num; + p_ib_av_attr->sl = p_ib_ah_attr->sl; + p_ib_av_attr->dlid = cl_hton16(p_ib_ah_attr->dlid); + p_ib_av_attr->static_rate = from_rate(p_ib_ah_attr->static_rate); + p_ib_av_attr->path_bits = p_ib_ah_attr->src_path_bits; + + if (p_ib_qp_attr) { + p_ib_av_attr->conn.path_mtu = p_ib_qp_attr->path_mtu; // MTU + p_ib_av_attr->conn.local_ack_timeout = p_ib_qp_attr->timeout; // MTU + p_ib_av_attr->conn.seq_err_retry_cnt = p_ib_qp_attr->retry_cnt; // MTU + p_ib_av_attr->conn.rnr_retry_cnt = p_ib_qp_attr->rnr_retry; // MTU + } + + if (p_ib_ah_attr->ah_flags & IB_AH_GRH) { + p_ib_av_attr->grh_valid = TRUE; + p_ib_av_attr->grh.hop_limit = p_ib_ah_attr->grh.hop_limit; + p_ib_av_attr->grh.ver_class_flow = ib_grh_set_ver_class_flow( + 0, p_ib_ah_attr->grh.traffic_class, p_ib_ah_attr->grh.flow_label ); + RtlCopyMemory(p_ib_av_attr->grh.dest_gid.raw, + p_ib_ah_attr->grh.dgid.raw, sizeof(p_ib_av_attr->grh.dest_gid)); + err = ib_get_cached_gid((struct ib_device *)p_ib_dev, + p_ib_ah_attr->port_num, p_ib_ah_attr->grh.sgid_index, + (union ib_gid*)p_ib_av_attr->grh.src_gid.raw ); + if (err) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_SHIM , + ("ib_get_cached_gid failed %d (%#x). Using default: sgid_index = 0\n", err, err)); + } + } + else + p_ib_av_attr->grh_valid = FALSE; + + + return err; +} + +ib_apm_state_t from_apm_state(enum ib_mig_state apm) +{ + if (apm == IB_MIG_MIGRATED) return IB_APM_MIGRATED; + if (apm == IB_MIG_REARM) return IB_APM_REARM; + if (apm == IB_MIG_ARMED) return IB_APM_ARMED; + return 0xffffffff; +} + +ib_api_status_t +mlnx_conv_qp_attr( + IN const struct ib_qp *p_ib_qp, + IN struct ib_qp_attr *p_ib_qp_attr, + OUT ib_qp_attr_t *p_qp_attr + ) +{ + int err; + RtlZeroMemory( p_qp_attr, sizeof *p_qp_attr ); + p_qp_attr->h_pd = (ib_pd_handle_t)p_ib_qp->pd; + p_qp_attr->qp_type = p_ib_qp->qp_type; + p_qp_attr->access_ctrl = map_qp_mthca_acl(p_ib_qp_attr->qp_access_flags); + p_qp_attr->pkey_index = p_ib_qp_attr->pkey_index; + + p_qp_attr->sq_max_inline = p_ib_qp_attr->cap.max_inline_data; + p_qp_attr->sq_depth = p_ib_qp_attr->cap.max_send_wr; + p_qp_attr->rq_depth = p_ib_qp_attr->cap.max_recv_wr; + p_qp_attr->sq_sge = p_ib_qp_attr->cap.max_send_sge; + p_qp_attr->rq_sge = p_ib_qp_attr->cap.max_recv_sge; + p_qp_attr->init_depth = p_ib_qp_attr->max_rd_atomic; + p_qp_attr->resp_res = p_ib_qp_attr->max_dest_rd_atomic; + + p_qp_attr->h_sq_cq = (ib_cq_handle_t)p_ib_qp->send_cq; + p_qp_attr->h_rq_cq = (ib_cq_handle_t)p_ib_qp->recv_cq; + p_qp_attr->h_srq = (ib_srq_handle_t)p_ib_qp->srq; + + p_qp_attr->sq_signaled = (((struct mthca_qp *)p_ib_qp)->sq_policy == IB_SIGNAL_ALL_WR) ? TRUE : FALSE; + + p_qp_attr->state = mlnx_qps_to_ibal( p_ib_qp_attr->qp_state); + p_qp_attr->num = cl_hton32(p_ib_qp->qp_num); + p_qp_attr->dest_num = cl_hton32(p_ib_qp_attr->dest_qp_num); + p_qp_attr->qkey = cl_hton32(p_ib_qp_attr->qkey); + + p_qp_attr->sq_psn = cl_hton32(p_ib_qp_attr->sq_psn); + p_qp_attr->rq_psn = cl_hton32(p_ib_qp_attr->rq_psn); + + p_qp_attr->primary_port = p_ib_qp_attr->port_num; + p_qp_attr->alternate_port = p_ib_qp_attr->alt_port_num; + err = from_av( p_ib_qp->device, p_ib_qp_attr, &p_ib_qp_attr->ah_attr, &p_qp_attr->primary_av); + if (err) + goto err_av; + err = from_av( p_ib_qp->device, p_ib_qp_attr, &p_ib_qp_attr->alt_ah_attr, &p_qp_attr->alternate_av); + if (err) + goto err_av; + p_qp_attr->apm_state = from_apm_state(p_ib_qp_attr->path_mig_state); + + return IB_SUCCESS; + +err_av: + return errno_to_iberr(err); +} + diff --git a/branches/WOF2-3/hw/mthca/kernel/hca_data.h b/branches/WOF2-3/hw/mthca/kernel/hca_data.h new file mode 100644 index 00000000..f6a15b74 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/hca_data.h @@ -0,0 +1,390 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2004-2005 Mellanox Technologies, Inc. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#ifndef __HCA_DATA_H__ +#define __HCA_DATA_H__ + + +#include +#include +#include +#include + + +extern char mlnx_uvp_lib_name[]; +extern uint32_t g_skip_tavor_reset; +extern uint32_t g_disable_tavor_reset; +extern uint32_t g_tune_pci; +extern uint32_t g_processor_affinity; +extern uint32_t g_max_DPC_time_us; +extern uint32_t g_profile_qp_num; +extern uint32_t g_profile_rd_out; + + +#define MLNX_MAX_HCA 4 +#define MLNX_NUM_HOBKL MLNX_MAX_HCA +#define MLNX_NUM_HOBUL MLNX_MAX_HCA +#define MLNX_NUM_CB_THR 1 +#define MLNX_SIZE_CB_POOL 256 +#define MLNX_UAL_ALLOC_HCA_UL_RES 1 +#define MLNX_UAL_FREE_HCA_UL_RES 2 + + +// Defines for QP ops +#define MLNX_MAX_NUM_SGE 8 +#define MLNX_MAX_WRS_PER_CHAIN 4 + +#define MLNX_NUM_RESERVED_QPS 16 + +/* + * Completion model. + * 0: No DPC processor assignment + * 1: DPCs per-CQ, processor affinity set at CQ initialization time. + * 2: DPCs per-CQ, processor affinity set at runtime. + * 3: DPCs per-CQ, no processor affinity set. + */ +#define MLNX_COMP_MODEL 3 + +#ifdef DBG +#define VALIDATE_INDEX(index, limit, error, label) \ + { \ + if (index >= limit) \ + { \ + status = error; \ + HCA_PRINT(TRACE_LEVEL_ERROR , g_mlnx_dbg_lvl ,("file %s line %d\n", __FILE__, __LINE__)));\ + goto label; \ + } \ + } +#else +#define VALIDATE_INDEX(index, limit, error, label) +#endif + + + +// Typedefs + +typedef enum { + E_EV_CA=1, + E_EV_QP, + E_EV_CQ, + E_EV_LAST +} ENUM_EVENT_CLASS; + +typedef enum { + E_MARK_CA=1, // Channel Adaptor + E_MARK_PD, // Protection Domain + E_MARK_CQ, // Completion Queue + E_MARK_QP, // Queue Pair + E_MARK_AV, // Address Vector (UD) + E_MARK_MG, // Multicast Group + E_MARK_MR, // Memory Region + E_MARK_MW, // Memory Windows + E_MARK_INVALID, +} ENUM_MARK; + +typedef enum { + E_MR_PHYS=1, + E_MR_SHARED, + E_MR_ANY, + E_MR_INVALID +} ENUM_MR_TYPE; + +/* + * Attribute cache for port info saved to expedite local MAD processing. + * Note that the cache accounts for the worst case GID and PKEY table size + * but is allocated from paged pool, so it's nothing to worry about. + */ + +typedef struct _guid_block +{ + boolean_t valid; + ib_guid_info_t tbl; + +} mlnx_guid_block_t; + +typedef struct _port_info_cache +{ + boolean_t valid; + ib_port_info_t info; + +} mlnx_port_info_cache_t; + +typedef struct _pkey_block +{ + boolean_t valid; + ib_pkey_table_t tbl; + +} mlnx_pkey_block_t; + +typedef struct _sl_vl_cache +{ + boolean_t valid; + ib_slvl_table_t tbl; + +} mlnx_sl_vl_cache_t; + +typedef struct _vl_arb_block +{ + boolean_t valid; + ib_vl_arb_table_t tbl; + +} mlnx_vl_arb_block_t; + +typedef struct _attr_cache +{ + mlnx_guid_block_t guid_block[32]; + mlnx_port_info_cache_t port_info; + mlnx_pkey_block_t pkey_tbl[2048]; + mlnx_sl_vl_cache_t sl_vl; + mlnx_vl_arb_block_t vl_arb[4]; + +} mlnx_cache_t; + +typedef struct _ib_ca { + ENUM_MARK mark; + KSPIN_LOCK event_list_lock; + LIST_ENTRY event_list; + ci_async_event_cb_t async_cb_p; + const void *ca_context; + void *cl_device_h; + uint32_t index; + cl_async_proc_t *async_proc_mgr_p; + +} mlnx_hob_t; + +typedef struct HOBUL_t { + int dummy; +#ifdef WIN_TO_BE_REMOVED + pd_info_t *pd_info_tbl; + HH_hca_hndl_t hh_hndl; /* For HH direct access */ + HHUL_hca_hndl_t hhul_hndl; /* user level HCA resources handle for HH */ + uint32_t cq_idx_mask; /* */ + uint32_t qp_idx_mask; /* */ + uint32_t vendor_id; /* \ */ + uint32_t device_id; /* > 3 items needed for initializing user level */ + void *hca_ul_resources_p; /* / */ + MT_size_t cq_ul_resources_sz; /* Needed for allocating user resources for CQs */ + MT_size_t qp_ul_resources_sz; /* Needed for allocating user resources for QPs */ + MT_size_t pd_ul_resources_sz; /* Needed for allocating user resources for PDs */ + uint32_t max_cq; /* Max num. of CQs - size of following table */ + cq_info_t *cq_info_tbl; + uint32_t max_qp; /* Max num. of QPs - size of following table */ + qp_info_t *qp_info_tbl; + uint32_t max_pd; /* Max num. of PDs - size of following table */ + uint32_t log2_mpt_size; + atomic32_t count; +#endif +} mlnx_hobul_t, *mlnx_hobul_hndl_t; + +typedef struct _ib_mcast { + ib_gid_t mcast_gid; + struct ib_qp *ib_qp_p; + uint16_t mcast_lid; +} mlnx_mcast_t; + +typedef struct _mlnx_hca_t { + cl_list_item_t list_item; // to include in the HCA chain + net64_t guid; // HCA node Guid + struct mthca_dev *mdev; // VP Driver device + uint32_t hw_ver; // HCA HW version + mlnx_hob_t hob; // HOB - IBAL-related HCA resources + +#ifdef WIN_TO_BE_REMOVED + // removed as it is found in p_ext->cl_ext.p_pdo + const void* p_dev_obj; // Driver PDO +#endif +} mlnx_hca_t; + + +typedef mlnx_hob_t *mlnx_hca_h; + +// Global Variables +//extern mlnx_hca_t mlnx_hca_array[]; +//extern uint32_t mlnx_num_hca; + +extern mlnx_hob_t mlnx_hob_array[]; +extern mlnx_hobul_t *mlnx_hobul_array[]; + +// Functions +void +setup_ci_interface( + IN const ib_net64_t ca_guid, + OUT ci_interface_t *p_interface ); + +void +mlnx_hca_insert( + IN mlnx_hca_t *p_hca ); + +void +mlnx_hca_remove( + IN mlnx_hca_t *p_hca ); + +mlnx_hca_t* +mlnx_hca_from_guid( + IN ib_net64_t guid ); + +/* +void +mlnx_names_from_guid( + IN ib_net64_t guid, + OUT char **hca_name_p, + OUT char **dev_name_p); +*/ + +cl_status_t +mlnx_hcas_init( void ); + +cl_status_t +mlnx_hobs_init( void ); + +ib_api_status_t +mlnx_hobs_insert( + IN mlnx_hca_t *p_hca, + OUT mlnx_hob_t **hob_p); + + +ib_api_status_t +mlnx_hobs_set_cb( + IN mlnx_hob_t *hob_p, + IN ci_async_event_cb_t async_cb_p, + IN const void* const ib_context); + +ib_api_status_t +mlnx_hobs_get_context( + IN mlnx_hob_t *hob_p, + OUT void **context_p); + +ib_api_status_t +mlnx_hobs_create_device( + IN mlnx_hob_t *hob_p, + OUT char* dev_name); + +void +mlnx_hobs_remove( + IN mlnx_hob_t *hob_p); + +mlnx_hobul_t * +mlnx_hobs_get_hobul( + IN mlnx_hob_t *hob_p); + +void +mlnx_hobul_get( + IN mlnx_hob_t *hob_p, + OUT void **resources_p ); + +void +mlnx_hobul_delete( + IN mlnx_hob_t *hob_p); + +void +mlnx_conv_hca_cap( + IN struct ib_device *ib_dev, + IN struct ib_device_attr *hca_info_p, + IN struct ib_port_attr *hca_ports, + OUT ib_ca_attr_t *ca_attr_p); + +ib_api_status_t +mlnx_local_mad ( + IN const ib_ca_handle_t h_ca, + IN const uint8_t port_num, + IN const ib_av_attr_t *p_src_av_attr, + IN const ib_mad_t *p_mad_in, + OUT ib_mad_t *p_mad_out ); + +void +mlnx_memory_if( + IN OUT ci_interface_t *p_interface ); + +void +mlnx_ecc_if( + IN OUT ci_interface_t *p_interface ); + +void +mlnx_direct_if( + IN OUT ci_interface_t *p_interface ); + +void +mlnx_mcast_if( + IN OUT ci_interface_t *p_interface ); + +ib_api_status_t +fw_access_ctrl( + IN const void* context, + IN const void** const handle_array OPTIONAL, + IN uint32_t num_handles, + IN ib_ci_op_t* const p_ci_op, + IN OUT ci_umv_buf_t *p_umv_buf OPTIONAL); + +void unmap_crspace_for_all( struct ib_ucontext *p_context ); + +void ca_event_handler(struct ib_event *ev, void *context); + +ib_qp_state_t mlnx_qps_to_ibal(enum ib_qp_state qps); + +enum ib_qp_state mlnx_qps_from_ibal(ib_qp_state_t ib_qps); + +ib_api_status_t +mlnx_conv_qp_modify_attr( + IN const struct ib_qp *ib_qp_p, + IN ib_qp_type_t qp_type, + IN const ib_qp_mod_t *modify_attr_p, + OUT struct ib_qp_attr *qp_attr_p, + OUT int *qp_attr_mask_p + ); + +int +mlnx_conv_ibal_av( + IN const struct ib_device *ib_dev_p, + IN const ib_av_attr_t *ibal_av_p, + OUT struct ib_ah_attr *ah_attr_p); + +int +mlnx_conv_mthca_av( + IN const struct ib_ah *ib_ah_p, + OUT ib_av_attr_t *ibal_av_p); + +void +mlnx_modify_ah( + IN const struct ib_ah *ib_ah_p, + IN const struct ib_ah_attr *ah_attr_p); + +void set_skip_tavor_reset(); + +ib_api_status_t +mlnx_conv_qp_attr( + IN const struct ib_qp *p_ib_qp, + IN struct ib_qp_attr *p_ib_qp_attr, + OUT ib_qp_attr_t *p_qp_attr + ); + +#endif diff --git a/branches/WOF2-3/hw/mthca/kernel/hca_debug.h b/branches/WOF2-3/hw/mthca/kernel/hca_debug.h new file mode 100644 index 00000000..62a016cd --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/hca_debug.h @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#ifndef _HCA_DEBUG_H_ +#define _HCA_DEBUG_H_ + +#include + +extern uint32_t g_mthca_dbg_level; +extern uint32_t g_mthca_dbg_flags; +#define MAX_LOG_BUF_LEN 512 +extern WCHAR g_wlog_buf[ MAX_LOG_BUF_LEN ]; +extern UCHAR g_slog_buf[ MAX_LOG_BUF_LEN ]; + +static void _build_str( const char * format, ... ) +{ + NTSTATUS status; + va_list p_arg; + va_start(p_arg, format); + status = RtlStringCbVPrintfA((char *)g_slog_buf, sizeof(g_slog_buf), format , p_arg); + if (status) + goto end; + + status = RtlStringCchPrintfW(g_wlog_buf, sizeof(g_wlog_buf)/sizeof(g_wlog_buf[0]), L"%S", g_slog_buf); + if (status) + goto end; + +end: + va_end(p_arg); +} + +#define HCA_PRINT_TO_EVENT_LOG(_obj_,_level_,_flag_,_msg_) \ + { \ + NTSTATUS event_id; \ + __pragma(warning(suppress:6326)) \ + switch (_level_) { \ + case TRACE_LEVEL_FATAL: case TRACE_LEVEL_ERROR: event_id = EVENT_MTHCA_ANY_ERROR; break; \ + case TRACE_LEVEL_WARNING: event_id = EVENT_MTHCA_ANY_WARN; break; \ + default: event_id = EVENT_MTHCA_ANY_INFO; break; \ + } \ + _build_str _msg_; \ + WriteEventLogEntryStr( _obj_, (ULONG)event_id, 0, 0, g_wlog_buf, 0, 0 ); \ + } + +#define HCA_PRINT_EV_MDEV(_level_,_flag_,_msg_) \ +{\ + if(mdev) {\ + HCA_PRINT_TO_EVENT_LOG(mdev->ext->cl_ext.p_self_do,_level_,_flag_,_msg_)\ + }\ +}\ + + +#if defined(EVENT_TRACING) +// +// Software Tracing Definitions +// + +#define WPP_CONTROL_GUIDS \ + WPP_DEFINE_CONTROL_GUID(HCACtlGuid,(8BF1F640,63FE,4743,B9EF,FA38C695BFDE), \ + WPP_DEFINE_BIT( HCA_DBG_DEV) \ + WPP_DEFINE_BIT( HCA_DBG_PNP) \ + WPP_DEFINE_BIT( HCA_DBG_INIT) \ + WPP_DEFINE_BIT( HCA_DBG_MAD) \ + WPP_DEFINE_BIT( HCA_DBG_PO) \ + WPP_DEFINE_BIT( HCA_DBG_PD)\ + WPP_DEFINE_BIT( HCA_DBG_CQ) \ + WPP_DEFINE_BIT( HCA_DBG_QP) \ + WPP_DEFINE_BIT( HCA_DBG_MEMORY) \ + WPP_DEFINE_BIT( HCA_DBG_AV) \ + WPP_DEFINE_BIT( HCA_DBG_SRQ) \ + WPP_DEFINE_BIT( HCA_DBG_MCAST) \ + WPP_DEFINE_BIT( HCA_DBG_LOW) \ + WPP_DEFINE_BIT( HCA_DBG_SHIM)) + + +#define WPP_GLOBALLOGGER + + +#define WPP_LEVEL_FLAGS_ENABLED(lvl, flags) (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= lvl) +#define WPP_LEVEL_FLAGS_LOGGER(lvl,flags) WPP_LEVEL_LOGGER(flags) +#define WPP_FLAG_ENABLED(flags)(WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= TRACE_LEVEL_VERBOSE) +#define WPP_FLAG_LOGGER(flags) WPP_LEVEL_LOGGER(flags) + + +// begin_wpp config +// HCA_ENTER(FLAG); +// HCA_EXIT(FLAG); +// USEPREFIX(HCA_PRINT, "%!STDPREFIX! [MTHCA] :%!FUNC!() :"); +// USESUFFIX(HCA_ENTER, " [MTHCA] :%!FUNC!()["); +// USESUFFIX(HCA_EXIT, " [MTHCA] :%!FUNC!()]"); +// end_wpp + + + +#define HCA_PRINT_EV(_level_,_flag_,_msg_) \ + { \ + HCA_PRINT_EV_MDEV(_level_,_flag_,_msg_) \ + } + + +#else + + +#include + +/* + * Debug macros + */ + + +#define HCA_DBG_DEV (1 << 0) +#define HCA_DBG_PNP (1<<1) +#define HCA_DBG_INIT (1 << 2) +#define HCA_DBG_MAD (1 << 3) +#define HCA_DBG_PO (1 << 4) +#define HCA_DBG_PD (1<<5) +#define HCA_DBG_QP (1 << 6) +#define HCA_DBG_CQ (1 << 7) +#define HCA_DBG_MEMORY (1 << 8) +#define HCA_DBG_AV (1<<9) +#define HCA_DBG_SRQ (1 << 10) +#define HCA_DBG_MCAST (1<<11) +#define HCA_DBG_LOW (1 << 12) +#define HCA_DBG_SHIM (1 << 13) + + +#if DBG + +// assignment of _level_ is need to to overcome warning C4127 +#define HCA_PRINT(_level_,_flag_,_msg_) \ + { \ + int __lvl = _level_; \ + if (g_mthca_dbg_level >= (_level_) && \ + (g_mthca_dbg_flags & (_flag_))) { \ + cl_dbg_out ("~%d:[MTHCA] %s() :", KeGetCurrentProcessorNumber(), __FUNCTION__); \ + if(__lvl == TRACE_LEVEL_ERROR) cl_dbg_out ("***ERROR*** "); \ + cl_dbg_out _msg_; \ + } \ + } + +#else + +#define HCA_PRINT(lvl ,flags, msg) + +#endif + +#define HCA_PRINT_EV(_level_,_flag_,_msg_) \ + { \ + HCA_PRINT(_level_,_flag_,_msg_) \ + HCA_PRINT_EV_MDEV(_level_,_flag_,_msg_) \ + } + +#define HCA_ENTER(flags)\ + HCA_PRINT(TRACE_LEVEL_VERBOSE, flags,("[\n")); + +#define HCA_EXIT(flags)\ + HCA_PRINT(TRACE_LEVEL_VERBOSE, flags, ("]\n" )); + + +#endif //EVENT_TRACING + + +#endif /*_HCA_DEBUG_H_ */ + + diff --git a/branches/WOF2-3/hw/mthca/kernel/hca_direct.c b/branches/WOF2-3/hw/mthca/kernel/hca_direct.c new file mode 100644 index 00000000..27e044ee --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/hca_direct.c @@ -0,0 +1,308 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2004-2005 Mellanox Technologies, Inc. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include "hca_driver.h" +#include "hca_debug.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "hca_direct.tmh" +#endif +#include "mthca_dev.h" + + +/* Controls whether to use the VAPI entrypoints in THH, or the IBAL native ones. */ +#define MLNX_SEND_NATIVE 1 +#define MLNX_RECV_NATIVE 1 +#define MLNX_POLL_NATIVE 1 + + +/* +* Work Request Processing Verbs. +*/ + + +ib_api_status_t +mlnx_post_send ( + IN const ib_qp_handle_t h_qp, + IN ib_send_wr_t *p_send_wr, + OUT ib_send_wr_t **pp_failed ) +{ + int err; + ib_api_status_t status; + struct ib_qp *ib_qp_p = (struct ib_qp *)h_qp; + struct ib_device *ib_dev = ib_qp_p->device; + + HCA_ENTER(HCA_DBG_QP); + + err = ib_dev->post_send(ib_qp_p, p_send_wr, pp_failed ); + if (err) { + HCA_PRINT(TRACE_LEVEL_ERROR , HCA_DBG_QP, + ("post_send failed (%d)\n", err)); + if (err == -ENOMEM) + status = IB_INSUFFICIENT_RESOURCES; + else + status = errno_to_iberr(err); + goto err_post_send; + } + + status = IB_SUCCESS; + +err_post_send: + if (status != IB_SUCCESS) + { + HCA_PRINT(TRACE_LEVEL_ERROR , HCA_DBG_QP, + ("completes with ERROR status %#x\n", status)); + } + HCA_EXIT(HCA_DBG_QP); + return status; + +} + + +ib_api_status_t +mlnx_post_recv ( + IN const ib_qp_handle_t h_qp, + IN ib_recv_wr_t *p_recv_wr, + OUT ib_recv_wr_t **pp_failed OPTIONAL ) +{ + int err; + ib_api_status_t status; + struct ib_qp *ib_qp_p = (struct ib_qp *)h_qp; + struct ib_device *ib_dev = ib_qp_p->device; + + HCA_ENTER(HCA_DBG_QP); + + err = ib_dev->post_recv(ib_qp_p, p_recv_wr, pp_failed ); + if (err) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_QP, + ("post_recv failed (%d)\n", err)); + if (err == -ENOMEM) + status = IB_INSUFFICIENT_RESOURCES; + else + status = errno_to_iberr(err); + goto err_post_recv; + } + + status = IB_SUCCESS; + +err_post_recv: + if (status != IB_SUCCESS) + { + HCA_PRINT(TRACE_LEVEL_ERROR , HCA_DBG_QP, + ("completes with ERROR status %#x\n", status)); + } + HCA_EXIT(HCA_DBG_QP); + return status; + +} + +ib_api_status_t +mlnx_post_srq_recv ( + IN const ib_srq_handle_t h_srq, + IN ib_recv_wr_t *p_recv_wr, + OUT ib_recv_wr_t **pp_failed OPTIONAL ) +{ + int err; + ib_api_status_t status; + struct ib_srq *ib_srq_p = (struct ib_srq *)h_srq; + struct ib_device *ib_dev = ib_srq_p->device; + + HCA_ENTER(HCA_DBG_SRQ); + + err = ib_dev->post_srq_recv(ib_srq_p, p_recv_wr, pp_failed ); + if (err) { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_SRQ, + ("post_srq_recv failed (%d)\n", err)); + if (err == -ENOMEM) + status = IB_INSUFFICIENT_RESOURCES; + else + status = errno_to_iberr(err); + goto err_post_recv; + } + + status = IB_SUCCESS; + +err_post_recv: + if (status != IB_SUCCESS) + { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_SRQ, + ("completes with ERROR status %#x\n", status)); + } + HCA_EXIT(HCA_DBG_SRQ); + return status; + +} + +/* +* Completion Processing and Completion Notification Request Verbs. +*/ + +ib_api_status_t +mlnx_peek_cq( + IN const ib_cq_handle_t h_cq, + OUT uint32_t* const p_n_cqes ) +{ + UNREFERENCED_PARAMETER(h_cq); + UNREFERENCED_PARAMETER(p_n_cqes); + HCA_PRINT(TRACE_LEVEL_ERROR , HCA_DBG_SHIM ,("mlnx_peek_cq not implemented\n")); + return IB_INVALID_CA_HANDLE; +} + +ib_api_status_t +mlnx_poll_cq ( + IN const ib_cq_handle_t h_cq, + IN OUT ib_wc_t** const pp_free_wclist, + OUT ib_wc_t** const pp_done_wclist ) +{ + int err; + ib_api_status_t status = IB_SUCCESS; + struct ib_cq *ib_cq_p = (struct ib_cq *)h_cq; + + HCA_ENTER(HCA_DBG_CQ); + + // sanity checks + if (!pp_free_wclist || !pp_done_wclist || !*pp_free_wclist) { + status = IB_INVALID_PARAMETER; + goto err_invalid_params; + } + + // poll CQ + err = mthca_poll_cq_list(ib_cq_p, pp_free_wclist, pp_done_wclist ); + if (err) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_CQ, + ("mthca_poll_cq_list failed (%d)\n", err)); + status = errno_to_iberr(err); + }else if (!*pp_done_wclist) + status = IB_NOT_FOUND; + +err_invalid_params: + if (status != IB_SUCCESS && status != IB_NOT_FOUND) + { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_CQ, + ("completes with ERROR status %#x\n", status)); + } + HCA_EXIT(HCA_DBG_CQ); + return status; + +} + +ib_api_status_t +mlnx_enable_cq_notify ( + IN const ib_cq_handle_t h_cq, + IN const boolean_t solicited ) +{ + int err; + ib_api_status_t status = IB_SUCCESS; + struct ib_cq *ib_cq_p = (struct ib_cq *)h_cq; + + HCA_ENTER(HCA_DBG_CQ); + + // REARM CQ + err = ib_req_notify_cq(ib_cq_p, (solicited) ? IB_CQ_SOLICITED : IB_CQ_NEXT_COMP ); + if (err) { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_CQ, + ("ib_req_notify_cq failed (%d)\n", err)); + status = errno_to_iberr(err); + } + + if (status != IB_SUCCESS) + { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_CQ, + ("completes with ERROR status %#x\n", status)); + } + HCA_EXIT(HCA_DBG_CQ); + return status; +} + +ib_api_status_t +mlnx_enable_ncomp_cq_notify ( + IN const ib_cq_handle_t h_cq, + IN const uint32_t n_cqes ) +{ + int err; + ib_api_status_t status = IB_SUCCESS; + struct ib_cq *ib_cq_p = (struct ib_cq *)h_cq; + + HCA_ENTER(HCA_DBG_CQ); + + err = ib_req_ncomp_notif(ib_cq_p, n_cqes ); + if (err) { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_CQ, + ("ib_req_ncomp_notif failed (%d)\n", err)); + status = errno_to_iberr(err); + } + + if (status != IB_SUCCESS) + { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_CQ, + ("completes with ERROR status %#x\n", status)); + } + HCA_EXIT(HCA_DBG_CQ); + return status; +} + +ib_api_status_t +mlnx_bind_mw ( + IN const ib_mw_handle_t h_mw, + IN const ib_qp_handle_t h_qp, + IN ib_bind_wr_t* const p_mw_bind, + OUT net32_t* const p_rkey ) +{ + UNREFERENCED_PARAMETER(h_mw); + UNREFERENCED_PARAMETER(h_qp); + UNREFERENCED_PARAMETER(p_mw_bind); + UNREFERENCED_PARAMETER(p_rkey); + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_SHIM,("mlnx_bind_mw not implemented\n")); + return IB_INVALID_CA_HANDLE; +} + + +void +mlnx_direct_if( + IN OUT ci_interface_t *p_interface ) +{ + p_interface->post_send = mlnx_post_send; + p_interface->post_recv = mlnx_post_recv; + p_interface->post_srq_recv = mlnx_post_srq_recv; + + p_interface->enable_ncomp_cq_notify = mlnx_enable_ncomp_cq_notify; + p_interface->peek_cq = NULL; /* mlnx_peek_cq: Not implemented */ + p_interface->poll_cq = mlnx_poll_cq; + p_interface->enable_cq_notify = mlnx_enable_cq_notify; + + p_interface->bind_mw = mlnx_bind_mw; +} diff --git a/branches/WOF2-3/hw/mthca/kernel/hca_driver.c b/branches/WOF2-3/hw/mthca/kernel/hca_driver.c new file mode 100644 index 00000000..e7dd5eb0 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/hca_driver.c @@ -0,0 +1,1049 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * Provides the driver entry points for the Tavor VPD. + */ + +#include +#include "hca_driver.h" +#include "hca_debug.h" + +#include "mthca_log.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "hca_driver.tmh" +#endif +#include "mthca_dev.h" +#include +#include +#pragma warning( push, 3 ) +//#include "MdCard.h" +#pragma warning( pop ) +#include +#include "mthca/mthca_vc.h" +#include "mt_pa_cash.h" +/* from \inc\platform\evntrace.h +#define TRACE_LEVEL_NONE 0 // Tracing is not on +#define TRACE_LEVEL_FATAL 1 // Abnormal exit or termination +#define TRACE_LEVEL_ERROR 2 // Severe errors that need logging +#define TRACE_LEVEL_WARNING 3 // Warnings such as allocation failure +#define TRACE_LEVEL_INFORMATION 4 // Includes non-error cases(e.g.,Entry-Exit) +#define TRACE_LEVEL_VERBOSE 5 // Detailed traces from intermediate steps +*/ +uint32_t g_mthca_dbg_level = TRACE_LEVEL_INFORMATION; +uint32_t g_mthca_dbg_flags= 0xffff; +WCHAR g_wlog_buf[ MAX_LOG_BUF_LEN ]; +UCHAR g_slog_buf[ MAX_LOG_BUF_LEN ]; +uint32_t g_skip_tavor_reset=0; /* skip reset for Tavor cards */ +uint32_t g_disable_tavor_reset=1; /* disable Tavor reset for the next driver load */ +uint32_t g_tune_pci=0; /* 0 - skip tuning PCI configuration space of HCAs */ +uint32_t g_processor_affinity = 0; +uint32_t g_max_DPC_time_us = 10000; +uint32_t g_profile_qp_num = 0; +uint32_t g_profile_rd_out = 0xffffffff; + +UNICODE_STRING g_param_path; + + +/* + * UVP name does not include file extension. For debug builds, UAL + * will append "d.dll". For release builds, UAL will append ".dll" + */ +char mlnx_uvp_lib_name[MAX_LIB_NAME] = {"mthcau"}; + +void mlnx_poll_eq(struct ib_device *device, BOOLEAN bStart); + + +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT p_driver_obj, + IN PUNICODE_STRING p_registry_path ); + +static NTSTATUS +__read_registry( + IN UNICODE_STRING* const p_Param_Path ); + +static void +hca_drv_unload( + IN PDRIVER_OBJECT p_driver_obj ); + +static NTSTATUS +hca_sysctl( + IN PDEVICE_OBJECT p_dev_obj, + IN PIRP p_irp ); + +static NTSTATUS +__pnp_notify_target( + IN TARGET_DEVICE_REMOVAL_NOTIFICATION *p_notify, + IN void *context ); + +static NTSTATUS +__pnp_notify_ifc( + IN DEVICE_INTERFACE_CHANGE_NOTIFICATION *p_notify, + IN void *context ); + +static NTSTATUS +fw_access_pciconf ( + IN BUS_INTERFACE_STANDARD *p_BusInterface, + IN ULONG op_flag, + IN PVOID p_buffer, + IN ULONG offset, + IN ULONG POINTER_ALIGNMENT length ); + +static NTSTATUS +fw_flash_write_data ( + IN BUS_INTERFACE_STANDARD *p_BusInterface, + IN PVOID p_buffer, + IN ULONG offset, + IN ULONG POINTER_ALIGNMENT length ); + +static NTSTATUS +fw_flash_read_data ( + IN BUS_INTERFACE_STANDARD *p_BusInterface, + IN PVOID p_buffer, + IN ULONG offset, + IN ULONG POINTER_ALIGNMENT length ); + +static NTSTATUS +fw_flash_read4( + IN BUS_INTERFACE_STANDARD *p_BusInterface, + IN uint32_t addr, + IN OUT uint32_t *p_data); + +static NTSTATUS +fw_flash_readbuf( + IN BUS_INTERFACE_STANDARD *p_BusInterface, + IN uint32_t offset, + IN OUT void *p_data, + IN uint32_t len); +static NTSTATUS +fw_set_bank( + IN BUS_INTERFACE_STANDARD *p_BusInterface, + IN uint32_t bank ); + +static NTSTATUS +fw_flash_init( + IN BUS_INTERFACE_STANDARD *p_BusInterface ); + +static NTSTATUS +fw_flash_deinit( + IN BUS_INTERFACE_STANDARD *p_BusInterface ); + + +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT p_driver_obj, + IN PUNICODE_STRING p_registry_path ) +{ + NTSTATUS status; + cl_status_t cl_status; +#if defined(EVENT_TRACING) + WPP_INIT_TRACING(p_driver_obj ,p_registry_path); +#endif + HCA_ENTER( HCA_DBG_DEV ); + + /* init common mechanisms */ + fill_bit_tbls(); + + status = __read_registry( p_registry_path ); + if( !NT_SUCCESS( status ) ) + { + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_INIT, + ("__read_registry_path returned 0x%X.\n", status)); + return status; + } + + /* Initialize Adapter DB */ + cl_status = mlnx_hcas_init(); + if( cl_status != CL_SUCCESS ) + { + HCA_PRINT( TRACE_LEVEL_ERROR ,HCA_DBG_INIT , + ("mlnx_hcas_init returned %#x.\n", cl_status)); + return cl_to_ntstatus( cl_status ); + } +// cl_memclr( mlnx_hca_array, MLNX_MAX_HCA * sizeof(ci_interface_t) ); + + /* init pa cash */ + status = pa_cash_init(); + if (status) + { + HCA_PRINT( TRACE_LEVEL_ERROR ,HCA_DBG_INIT , + ("pa_cash_init failed.\n")); + return status; + } + + /*leo: init function table */ + hca_init_vfptr(); + + p_driver_obj->MajorFunction[IRP_MJ_PNP] = cl_pnp; + p_driver_obj->MajorFunction[IRP_MJ_POWER] = cl_power; + p_driver_obj->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = hca_sysctl; + p_driver_obj->DriverUnload = hca_drv_unload; + p_driver_obj->DriverExtension->AddDevice = hca_add_device; + + /* init core */ + if (ib_core_init()) { + HCA_PRINT( TRACE_LEVEL_ERROR ,HCA_DBG_INIT ,("Failed to init core, aborting.\n")); + return STATUS_UNSUCCESSFUL; + } + + /* init uverbs module */ + if (ib_uverbs_init()) { + HCA_PRINT( TRACE_LEVEL_ERROR ,HCA_DBG_INIT ,("Failed ib_uverbs_init, aborting.\n")); + return STATUS_UNSUCCESSFUL; + } + HCA_EXIT( HCA_DBG_DEV ); + return STATUS_SUCCESS; +} + + +static NTSTATUS +__read_registry( + IN UNICODE_STRING* const p_registry_path ) +{ + NTSTATUS status; + /* Remember the terminating entry in the table below. */ + RTL_QUERY_REGISTRY_TABLE table[10]; + + HCA_ENTER( HCA_DBG_DEV ); + + RtlInitUnicodeString( &g_param_path, NULL ); + g_param_path.MaximumLength = p_registry_path->Length + + sizeof(L"\\Parameters"); + g_param_path.Buffer = cl_zalloc( g_param_path.MaximumLength ); + if( !g_param_path.Buffer ) + { + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_INIT, + ("Failed to allocate parameters path buffer.\n")); + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlAppendUnicodeStringToString( &g_param_path, p_registry_path ); + RtlAppendUnicodeToString( &g_param_path, L"\\Parameters" ); + + /* + * Clear the table. This clears all the query callback pointers, + * and sets up the terminating table entry. + */ + cl_memclr( table, sizeof(table) ); + + /* Setup the table entries. */ + table[0].Flags = RTL_QUERY_REGISTRY_DIRECT; + table[0].Name = L"DebugLevel"; + table[0].EntryContext = &g_mthca_dbg_level; + table[0].DefaultType = REG_DWORD; + table[0].DefaultData = &g_mthca_dbg_level; + table[0].DefaultLength = sizeof(ULONG); + + + table[1].Flags = RTL_QUERY_REGISTRY_DIRECT; + table[1].Name = L"DebugFlags"; + table[1].EntryContext = &g_mthca_dbg_flags; + table[1].DefaultType = REG_DWORD; + table[1].DefaultData = &g_mthca_dbg_flags; + table[1].DefaultLength = sizeof(ULONG); + + table[2].Flags = RTL_QUERY_REGISTRY_DIRECT; + table[2].Name = L"SkipTavorReset"; + table[2].EntryContext = &g_skip_tavor_reset; + table[2].DefaultType = REG_DWORD; + table[2].DefaultData = &g_skip_tavor_reset; + table[2].DefaultLength = sizeof(ULONG); + + table[3].Flags = RTL_QUERY_REGISTRY_DIRECT; + table[3].Name = L"DisableTavorResetOnFailure"; + table[3].EntryContext = &g_disable_tavor_reset; + table[3].DefaultType = REG_DWORD; + table[3].DefaultData = &g_disable_tavor_reset; + table[3].DefaultLength = sizeof(ULONG); + + table[4].Flags = RTL_QUERY_REGISTRY_DIRECT; + table[4].Name = L"TunePci"; + table[4].EntryContext = &g_tune_pci; + table[4].DefaultType = REG_DWORD; + table[4].DefaultData = &g_tune_pci; + table[4].DefaultLength = sizeof(ULONG); + + table[5].Flags = RTL_QUERY_REGISTRY_DIRECT; + table[5].Name = L"ProcessorAffinity"; + table[5].EntryContext = &g_processor_affinity; + table[5].DefaultType = REG_DWORD; + table[5].DefaultData = &g_processor_affinity; + table[5].DefaultLength = sizeof(ULONG); + + table[6].Flags = RTL_QUERY_REGISTRY_DIRECT; + table[6].Name = L"MaxDpcTimeUs"; + table[6].EntryContext = &g_max_DPC_time_us; + table[6].DefaultType = REG_DWORD; + table[6].DefaultData = &g_max_DPC_time_us; + table[6].DefaultLength = sizeof(ULONG); + + table[7].Flags = RTL_QUERY_REGISTRY_DIRECT; + table[7].Name = L"ProfileQpNum"; + table[7].EntryContext = &g_profile_qp_num; + table[7].DefaultType = REG_DWORD; + table[7].DefaultData = &g_profile_qp_num; + table[7].DefaultLength = sizeof(ULONG); + + table[8].Flags = RTL_QUERY_REGISTRY_DIRECT; + table[8].Name = L"ProfileRdOut"; + table[8].EntryContext = &g_profile_rd_out; + table[8].DefaultType = REG_DWORD; + table[8].DefaultData = &g_profile_rd_out; + table[8].DefaultLength = sizeof(ULONG); + + /* Have at it! */ + status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE, + g_param_path.Buffer, table, NULL, NULL ); + + HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_INIT, + ("debug level %d debug flags 0x%.8x SkipTavorReset %d DisableTavorReset %d TunePci %d" + "g_processor_affinity %d g_max_DPC_time_us %d g_profile_qp_num %d g_profile_rd_out %d\n", + g_mthca_dbg_level, g_mthca_dbg_flags, + g_skip_tavor_reset, g_disable_tavor_reset, + g_tune_pci, g_processor_affinity, g_max_DPC_time_us, + g_profile_qp_num, g_profile_rd_out )); + + HCA_EXIT( HCA_DBG_DEV ); + return status; +} + +void set_skip_tavor_reset() +{ + NTSTATUS status; + HANDLE key_handle; + UNICODE_STRING key_name; + ULONG val = 1; + OBJECT_ATTRIBUTES oa; + + HCA_ENTER( HCA_DBG_DEV ); + + InitializeObjectAttributes( &oa, &g_param_path, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL ); + + + status = ZwOpenKey( &key_handle, GENERIC_WRITE, &oa ); + if( !NT_SUCCESS( status ) ) { + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_LOW, + ("ZwOpenKey failed (%#x)\n", status)); + goto err_open_key; + } + + RtlInitUnicodeString( &key_name, L"SkipTavorReset" ); + status = ZwSetValueKey( key_handle, &key_name, 0, + REG_DWORD, &val, sizeof(ULONG) ); + if( !NT_SUCCESS( status ) ) { + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_LOW, + ("ZwSetValueKey failed (%#x)\n", status)); + } + + ZwClose( key_handle ); + +err_open_key: + HCA_EXIT( HCA_DBG_DEV ); +} + +static void +hca_drv_unload( + IN PDRIVER_OBJECT p_driver_obj ) +{ + HCA_ENTER( HCA_DBG_DEV ); + + UNUSED_PARAM( p_driver_obj ); + + pa_cash_release(); + ib_uverbs_cleanup(); + ib_core_cleanup(); + cl_free( g_param_path.Buffer ); + + HCA_EXIT( HCA_DBG_DEV ); +#if defined(EVENT_TRACING) + WPP_CLEANUP(p_driver_obj); +#endif + +} + + +static NTSTATUS +hca_sysctl( + IN PDEVICE_OBJECT p_dev_obj, + IN PIRP p_irp ) +{ + NTSTATUS status; + hca_dev_ext_t *p_ext; + + HCA_ENTER( HCA_DBG_DEV ); + + p_ext = p_dev_obj->DeviceExtension; + + IoSkipCurrentIrpStackLocation( p_irp ); + status = IoCallDriver( p_ext->cl_ext.p_next_do, p_irp ); + + HCA_EXIT( HCA_DBG_DEV ); + return status; +} + +typedef struct Primary_Sector{ + uint32_t fi_addr; + uint32_t fi_size; + uint32_t signature; + uint32_t fw_reserved[5]; + uint32_t vsd[56]; + uint32_t branch_to; + uint32_t crc016; +} primary_sector_t; + +static uint32_t old_dir; +static uint32_t old_pol; +static uint32_t old_mod; +static uint32_t old_dat; + +static NTSTATUS +fw_access_pciconf ( + IN BUS_INTERFACE_STANDARD *p_BusInterface, + IN ULONG op_flag, + IN PVOID p_buffer, + IN ULONG offset, + IN ULONG POINTER_ALIGNMENT length ) +{ + + ULONG bytes; + NTSTATUS status = STATUS_SUCCESS; + + PAGED_CODE(); + + if( !p_buffer ) + return STATUS_INVALID_PARAMETER; + + if (p_BusInterface) + { + + bytes = p_BusInterface->SetBusData( + p_BusInterface->Context, + PCI_WHICHSPACE_CONFIG, + (PVOID)&offset, + PCI_CONF_ADDR, + sizeof(ULONG) ); + + if( op_flag == 0 ) + { + if ( bytes ) + bytes = p_BusInterface->GetBusData( + p_BusInterface->Context, + PCI_WHICHSPACE_CONFIG, + p_buffer, + PCI_CONF_DATA, + length ); + if ( !bytes ) + status = STATUS_NOT_SUPPORTED; + } + + else + { + if ( bytes ) + bytes = p_BusInterface->SetBusData( + p_BusInterface->Context, + PCI_WHICHSPACE_CONFIG, + p_buffer, + PCI_CONF_DATA, + length); + + if ( !bytes ) + status = STATUS_NOT_SUPPORTED; + } + } + return status; +} + + +static NTSTATUS +__map_crspace( + IN struct ib_ucontext * p_context, + IN mlnx_hob_t * p_hob, + IN PVOID p_buf, + IN ULONG buf_size + ) +{ + NTSTATUS status; + PMDL p_mdl; + PVOID ua, ka; + ULONG sz; + hca_dev_ext_t *p_ext = EXT_FROM_HOB(p_hob); + map_crspace *p_res = (map_crspace *)p_buf; + + HCA_ENTER( HCA_DBG_PNP ); + + // sanity checks + if ( buf_size < sizeof *p_res || !p_buf ) { + status = STATUS_INVALID_PARAMETER; + goto err_invalid_params; + } + + // map memory + sz =(ULONG)p_ext->bar[HCA_BAR_TYPE_HCR].size; + if (!p_ext->bar[HCA_BAR_TYPE_HCR].virt) { + PHYSICAL_ADDRESS pa; + pa.QuadPart = p_ext->bar[HCA_BAR_TYPE_HCR].phys; + ka = MmMapIoSpace( pa, sz, MmNonCached ); + if ( ka == NULL) { + HCA_PRINT(TRACE_LEVEL_ERROR , HCA_DBG_SHIM, + ("No kernel mapping of CR space.\n") ); + status = STATUS_INSUFFICIENT_RESOURCES; + goto err_map_to_kernel; + } + p_ext->bar[HCA_BAR_TYPE_HCR].virt = ka; + } + ka = p_ext->bar[HCA_BAR_TYPE_HCR].virt; + + // prepare for mapping to user space + p_mdl = IoAllocateMdl( ka, sz, FALSE,FALSE,NULL); + if (p_mdl == NULL) { + HCA_PRINT(TRACE_LEVEL_ERROR , HCA_DBG_SHIM, + ("IoAllocateMdl failed.\n") ); + status = STATUS_INSUFFICIENT_RESOURCES; + goto err_alloc_mdl; + } + + // fill MDL + MmBuildMdlForNonPagedPool(p_mdl); + + // map the buffer into user space + __try + { + ua = MmMapLockedPagesSpecifyCache( p_mdl, UserMode, MmNonCached, + NULL, FALSE, NormalPagePriority ); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + HCA_PRINT(TRACE_LEVEL_ERROR , HCA_DBG_SHIM, + ("MmMapLockedPagesSpecifyCache failed.\n") ); + status = STATUS_INSUFFICIENT_RESOURCES; + goto err_map_to_user; + } + + // fill the results + p_res->va = (uint64_t)(ULONG_PTR)ua; + p_res->size = sz; + + // resource tracking + p_context->p_mdl = p_mdl; + p_context->va = ua; + +#if 0 + HCA_PRINT(TRACE_LEVEL_INFORMATION, HCA_DBG_SHIM, + ("MTHCA: __map_crspace succeeded with .ka %I64x, size %I64x va %I64x, size %x, pa %I64x \n", + p_ext->bar[HCA_BAR_TYPE_HCR].virt, p_ext->bar[HCA_BAR_TYPE_HCR].size, + p_res->va, p_res->size, p_ext->bar[HCA_BAR_TYPE_HCR].phys )); +#endif + status = STATUS_SUCCESS; + goto out; + +err_map_to_user: + IoFreeMdl( p_mdl ); +err_alloc_mdl: +err_map_to_kernel: +err_invalid_params: +out: + HCA_EXIT( HCA_DBG_PNP ); + return status; +} + + +static void +__unmap_crspace( + IN struct ib_ucontext * p_context + ) +{ + HCA_ENTER( HCA_DBG_PNP ); + + if (p_context->va && p_context->p_mdl) { + MmUnmapLockedPages(p_context->va, p_context->p_mdl); + IoFreeMdl( p_context->p_mdl ); + p_context->va = p_context->p_mdl = NULL; + //NB: the unmap of IO space is being done in __UnmapHcaMemoryResources + } + + HCA_EXIT( HCA_DBG_PNP ); +} + + +static void +__open_fw_access( + IN struct ib_ucontext* p_context, + IN PBUS_INTERFACE_STANDARD p_bus_interface ) +{ + if( !p_context->fw_if_open ) + { + p_bus_interface->InterfaceReference( p_bus_interface->Context ); + p_context->fw_if_open = TRUE; + } +} + + +static void +__close_fw_access( + IN struct ib_ucontext * p_context, + IN PBUS_INTERFACE_STANDARD p_bus_interface + ) +{ + if (p_context->fw_if_open ) { + p_bus_interface->InterfaceDereference((PVOID)p_bus_interface->Context); + p_context->fw_if_open = FALSE; + } +} + + +void +unmap_crspace_for_all( struct ib_ucontext *p_context ) +{ + mlnx_hob_t *p_hob = HOB_FROM_IBDEV( p_context->device ); + hca_dev_ext_t *p_ext = EXT_FROM_HOB(p_hob); + PBUS_INTERFACE_STANDARD p_bus_interface = &p_ext->hcaBusIfc; + + HCA_ENTER( HCA_DBG_PNP ); + + down( &p_context->mutex ); + __unmap_crspace( p_context); + __close_fw_access(p_context, p_bus_interface); + up( &p_context->mutex ); + + HCA_EXIT( HCA_DBG_PNP ); +} + +ib_api_status_t +fw_access_ctrl( + IN const ib_ca_handle_t h_ca, + IN const void** const handle_array OPTIONAL, + IN uint32_t num_handles, + IN ib_ci_op_t* const p_ci_op, + IN OUT ci_umv_buf_t *p_umv_buf ) +{ + DEVICE_OBJECT *p_dev_obj; + PBUS_INTERFACE_STANDARD p_bus_interface; + NTSTATUS status = STATUS_SUCCESS; + PVOID p_data; + ULONG offset; + ULONG POINTER_ALIGNMENT length; + struct ib_ucontext * p_context; + mlnx_hob_t *p_hob; + hca_dev_ext_t *p_ext; + + UNREFERENCED_PARAMETER(handle_array); + UNREFERENCED_PARAMETER(num_handles); + + if( !p_umv_buf ) + { +#if 1//WORKAROUND_POLL_EQ + if ((p_ci_op->command == FW_POLL_EQ_START) || (p_ci_op->command == FW_POLL_EQ_STOP)) + { // poll EQ (in case of missed interrupt) + struct ib_device *ib_dev; + p_hob = (mlnx_hob_t *)h_ca; + ib_dev = IBDEV_FROM_HOB( p_hob ); + + if(p_ci_op->command == FW_POLL_EQ_START) + { + mlnx_poll_eq(ib_dev,1); + }else + { + mlnx_poll_eq(ib_dev,0); + } + return IB_SUCCESS; + } + else +#endif + return IB_UNSUPPORTED; + } + + p_context = (struct ib_ucontext *)h_ca; + p_hob = HOB_FROM_IBDEV( p_context->device ); + p_ext = EXT_FROM_HOB(p_hob); + p_dev_obj = (DEVICE_OBJECT *)p_ext->cl_ext.p_self_do; + p_bus_interface = &p_ext->hcaBusIfc; + + if ( !p_ci_op ) + return IB_INVALID_PARAMETER; + + length = p_ci_op->buf_size; + offset = p_ci_op->buf_info; + p_data = p_ci_op->p_buf; + + down( &p_context->mutex ); + + switch ( p_ci_op->command ) + { + case FW_MAP_CRSPACE: + status = __map_crspace(p_context, p_hob, p_data, length); + break; + + case FW_UNMAP_CRSPACE: + __unmap_crspace(p_context); + break; + + case FW_OPEN_IF: // open BusInterface + __open_fw_access( p_context, p_bus_interface ); + break; + + case FW_READ: // read data from flash + if ( p_context->fw_if_open ) + status = fw_flash_read_data(p_bus_interface, p_data, offset, length); + break; + + case FW_WRITE: // write data to flash + if ( p_context->fw_if_open ) + status = fw_flash_write_data(p_bus_interface, p_data, offset, length); + break; + + case FW_READ_CMD: + if ( p_context->fw_if_open ) + status = fw_access_pciconf(p_bus_interface, 0 , p_data, offset, 4); + break; + + case FW_WRITE_CMD: + if ( p_context->fw_if_open ) + status = fw_access_pciconf(p_bus_interface, 1 , p_data, offset, 4); + break; + + case FW_CLOSE_IF: // close BusInterface + __close_fw_access(p_context, p_bus_interface); + break; + + default: + status = STATUS_INVALID_DEVICE_REQUEST; + } + + if ( status != STATUS_SUCCESS ) { + __close_fw_access(p_context, p_bus_interface); + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_INIT, + ("fw_access_ctrl failed, ntstatus: %08x.\n", status)); + } + + up( &p_context->mutex ); + + switch( status ) { + case STATUS_SUCCESS: return IB_SUCCESS; + case STATUS_INVALID_DEVICE_REQUEST: return IB_UNSUPPORTED; + case STATUS_INSUFFICIENT_RESOURCES: return IB_INSUFFICIENT_RESOURCES; + default: return IB_ERROR; + } +} + +static NTSTATUS +fw_flash_write_data ( + IN BUS_INTERFACE_STANDARD *p_BusInterface, + IN PVOID p_buffer, + IN ULONG offset, + IN ULONG POINTER_ALIGNMENT length ) +{ + NTSTATUS status; + uint32_t cnt = 0; + uint32_t lcl_data; + + if (!length) + return IB_INVALID_PARAMETER; + + lcl_data = (*((uint32_t*)p_buffer) << 24); + + status = fw_access_pciconf(p_BusInterface, FW_WRITE , &lcl_data, FLASH_OFFSET+4, length ); + if ( status != STATUS_SUCCESS ) + return status; + lcl_data = ( WRITE_BIT | (offset & ADDR_MSK)); + + status = fw_access_pciconf(p_BusInterface, FW_WRITE , &lcl_data, FLASH_OFFSET, 4 ); + if ( status != STATUS_SUCCESS ) + return status; + + lcl_data = 0; + + do + { + if (++cnt > 5000) + { + return STATUS_DEVICE_NOT_READY; + } + + status = fw_access_pciconf(p_BusInterface, FW_READ , &lcl_data, FLASH_OFFSET, 4 ); + if ( status != STATUS_SUCCESS ) + return status; + + } while(lcl_data & CMD_MASK); + + return status; +} + +static NTSTATUS +fw_flash_read_data ( + IN BUS_INTERFACE_STANDARD *p_BusInterface, + IN PVOID p_buffer, + IN ULONG offset, + IN ULONG POINTER_ALIGNMENT length ) +{ + NTSTATUS status = STATUS_SUCCESS; + uint32_t cnt = 0; + uint32_t lcl_data = ( READ_BIT | (offset & ADDR_MSK)); + + if (!length) + return IB_INVALID_PARAMETER; + + status = fw_access_pciconf(p_BusInterface, FW_WRITE, &lcl_data, FLASH_OFFSET, 4 ); + if ( status != STATUS_SUCCESS ) + return status; + + lcl_data = 0; + do + { + // Timeout checks + if (++cnt > 5000 ) + { + return STATUS_DEVICE_NOT_READY; + } + + status = fw_access_pciconf(p_BusInterface, FW_READ, &lcl_data, FLASH_OFFSET, 4 ); + + if ( status != STATUS_SUCCESS ) + return status; + + } while(lcl_data & CMD_MASK); + + status = fw_access_pciconf(p_BusInterface, FW_READ, p_buffer, FLASH_OFFSET+4, length ); + return status; +} + +static NTSTATUS +fw_flash_read4( + IN BUS_INTERFACE_STANDARD *p_BusInterface, + IN uint32_t addr, + IN OUT uint32_t *p_data) +{ + NTSTATUS status = STATUS_SUCCESS; + uint32_t lcl_data = 0; + uint32_t bank; + static uint32_t curr_bank = 0xffffffff; + + if (addr & 0x3) + { + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_INIT, + ("Invalid address %08x\n", addr) ); + return STATUS_INVALID_PARAMETER; + } + + bank = addr & BANK_MASK; + if (bank != curr_bank) + { + curr_bank = bank; + if ((status = fw_set_bank(p_BusInterface, bank)) != STATUS_SUCCESS ) + { + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_INIT, + ("fw_set_bank returned %08x\n", status) ); + return STATUS_INVALID_PARAMETER; + } + } + status = fw_flash_read_data(p_BusInterface, &lcl_data, addr, 4); + *p_data = cl_ntoh32(lcl_data); + return STATUS_SUCCESS; +} + +static NTSTATUS +fw_flash_readbuf( + IN BUS_INTERFACE_STANDARD *p_BusInterface, + IN uint32_t offset, + IN OUT void *p_data, + IN uint32_t len) +{ + NTSTATUS status = STATUS_SUCCESS; + uint32_t *p_lcl_data; + uint32_t i; + + if (offset & 0x3) + { + //Address should be 4-bytes aligned + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_INIT, + ("Invalid address %08x\n", offset) ); + return STATUS_INVALID_PARAMETER; + } + if (len & 0x3) + { + //Length should be 4-bytes aligned + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_INIT, + ("Invalid length %d\n", len) ); + return STATUS_INVALID_PARAMETER; + } + p_lcl_data = (uint32_t *)p_data; + + for ( i=0; i < (len >> 2); i++) + { + if ( (status = fw_flash_read_data( p_BusInterface, p_lcl_data, offset, sizeof(uint32_t) )) != STATUS_SUCCESS ) + return status; + offset += 4; + p_lcl_data++; + } + return STATUS_SUCCESS; +} // Flash::flash_read + +static NTSTATUS +fw_flash_writebuf( + IN BUS_INTERFACE_STANDARD *p_BusInterface, + IN PVOID p_buffer, + IN ULONG offset, + IN ULONG POINTER_ALIGNMENT length ) +{ + NTSTATUS status = STATUS_SUCCESS; + uint32_t i; + uint8_t *p_data = (uint8_t *)p_buffer; + + for ( i = 0; i < length; i++ ) + { + status = fw_flash_write_data (p_BusInterface, p_data, offset, 1 ); + if (status != STATUS_SUCCESS ) + return status; + p_data++; + offset++; + } + return status; +} +static NTSTATUS +fw_flash_init( + IN BUS_INTERFACE_STANDARD *p_BusInterface ) +{ + uint32_t dir; + uint32_t pol; + uint32_t mod; + + uint32_t cnt=0; + uint32_t data; + NTSTATUS status = STATUS_SUCCESS; + uint32_t semaphore = 0; + + while ( !semaphore ) + { + status = fw_access_pciconf(p_BusInterface, FW_READ , &data, SEMAP63, 4); + if ( status != STATUS_SUCCESS ) + break; + if( !data ) + { + semaphore = 1; + break; + } + if (++cnt > 5000 ) + { + break; + } + } + + if ( !semaphore ) + { + return STATUS_NOT_SUPPORTED; + } + + // Save old values + + status = fw_access_pciconf(p_BusInterface, FW_READ , &old_dir,GPIO_DIR_L , 4); + if ( status == STATUS_SUCCESS ) + status = fw_access_pciconf(p_BusInterface, FW_READ , &old_pol,GPIO_POL_L , 4); + if ( status == STATUS_SUCCESS ) + status = fw_access_pciconf(p_BusInterface, FW_READ , &old_mod,GPIO_MOD_L , 4); + if ( status == STATUS_SUCCESS ) + status = fw_access_pciconf(p_BusInterface, FW_READ , &old_dat,GPIO_DAT_L , 4); + + // Set Direction=1, Polarity=0, Mode=0 for 3 GPIO lower bits + dir = old_dir | 0x70; + pol = old_pol & ~0x70; + mod = old_mod & ~0x70; + + status = fw_access_pciconf(p_BusInterface, FW_WRITE , &dir,GPIO_DIR_L , 4); + if ( status == STATUS_SUCCESS ) + status = fw_access_pciconf(p_BusInterface, FW_WRITE , &pol,GPIO_POL_L , 4); + if ( status == STATUS_SUCCESS ) + status = fw_access_pciconf(p_BusInterface, FW_WRITE , &mod,GPIO_MOD_L , 4); + if ( status == STATUS_SUCCESS ) + // Set CPUMODE + status = fw_access_pciconf(p_BusInterface, FW_READ , &data, CPUMODE, 4); + if ( status == STATUS_SUCCESS ) + { + data &= ~CPUMODE_MSK; + data |= 1 << CPUMODE_SHIFT; + status = fw_access_pciconf(p_BusInterface, FW_WRITE , &data, CPUMODE, 4); + } + if ( status == STATUS_SUCCESS ) + { + // Reset flash + data = 0xf0; + status = fw_flash_write_data(p_BusInterface, &data, 0x0, 4); + } + return status; +} + +static NTSTATUS +fw_flash_deinit( + IN BUS_INTERFACE_STANDARD *p_BusInterface ) +{ + uint32_t data = 0; + NTSTATUS status = STATUS_SUCCESS; + + status = fw_set_bank(p_BusInterface, 0); + if ( status == STATUS_SUCCESS ) + // Restore origin values + status = fw_access_pciconf(p_BusInterface, FW_WRITE , &old_dir,GPIO_DIR_L , 4); + if ( status == STATUS_SUCCESS ) + status = fw_access_pciconf(p_BusInterface, FW_WRITE , &old_pol,GPIO_POL_L , 4); + if ( status == STATUS_SUCCESS ) + status = fw_access_pciconf(p_BusInterface, FW_WRITE , &old_mod,GPIO_MOD_L , 4); + if ( status == STATUS_SUCCESS ) + status = fw_access_pciconf(p_BusInterface, FW_WRITE , &old_dat,GPIO_DAT_L , 4); + if ( status == STATUS_SUCCESS ) + // Free GPIO Semaphore + status = fw_access_pciconf(p_BusInterface, FW_WRITE , &data, SEMAP63, 4); + return status; +} + +static NTSTATUS +fw_set_bank( + IN BUS_INTERFACE_STANDARD *p_BusInterface, + IN uint32_t bank ) +{ + NTSTATUS status = STATUS_SUCCESS; + uint32_t data = ( (uint32_t)0x70 << 24 ); + uint32_t mask = ((bank >> (BANK_SHIFT-4)) << 24 ); + + status = fw_access_pciconf(p_BusInterface, FW_WRITE , &data, GPIO_DATACLEAR_L, 4); + if (status == STATUS_SUCCESS) + { + // A1 + data &= mask; + //data |= mask; // for A0 + status = fw_access_pciconf(p_BusInterface, FW_WRITE , &data, GPIO_DATASET_L, 4); + } + return status; +} diff --git a/branches/WOF2-3/hw/mthca/kernel/hca_driver.h b/branches/WOF2-3/hw/mthca/kernel/hca_driver.h new file mode 100644 index 00000000..23106121 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/hca_driver.h @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#if !defined( _HCA_DRIVER_H_ ) +#define _HCA_DRIVER_H_ + + +#include +#include +#include +#include +#include "mthca/mthca_vc.h" +#include "hca_data.h" +#include "mt_l2w.h" +#include "hca_debug.h" + + +#include "hca_pnp.h" +#include "hca_pci.h" + +#if !defined(FILE_DEVICE_INFINIBAND) // Not defined in WXP DDK +#define FILE_DEVICE_INFINIBAND 0x0000003B +#endif + +/****s* HCA/hca_reg_state_t +* NAME +* hca_reg_state_t +* +* DESCRIPTION +* State for tracking registration with AL. This state is independent of the +* device PnP state, and both are used to properly register with AL. +* +* SYNOPSIS +*/ +typedef enum _hca_reg_state +{ + HCA_SHUTDOWN, + HCA_ADDED, + HCA_STARTED + +} hca_reg_state_t; +/* +* VALUES +* HCA_SHUTDOWN +* Cleaning up. +* +* HCA_ADDED +* AddDevice was called and successfully registered for interface +* notifications. +* +* HCA_STARTED +* IRP_MN_START_DEVICE was called. The HCA is fully functional. +* +*********/ + + +typedef enum _hca_bar_type +{ + HCA_BAR_TYPE_HCR, + HCA_BAR_TYPE_UAR, + HCA_BAR_TYPE_DDR, + HCA_BAR_TYPE_MAX + +} hca_bar_type_t; + + +typedef struct _hca_bar +{ + uint64_t phys; + void *virt; + SIZE_T size; + +} hca_bar_t; + + +typedef struct _hca_dev_ext +{ + /* ------------------------------------------------- + * PNP DATA + * ------------------------------------------------ */ + cl_pnp_po_ext_t cl_ext; /* COMPLIB PnP object */ + void * pnp_ifc_entry; /* Notification entry for PnP interface events. */ + void * pnp_target_entry; /* Notification entry for PnP target events. */ + PNP_DEVICE_STATE pnpState; /* state for PnP Manager */ + + /* ------------------------------------------------- + * POWER MANAGER DATA + * ------------------------------------------------ */ + /* Cache of the system to device power states. */ + DEVICE_POWER_STATE DevicePower[PowerSystemMaximum]; + DEVICE_POWER_STATE DevicePowerState; + SYSTEM_POWER_STATE SystemPowerState; + PIO_WORKITEM pPoWorkItem; + + /* ------------------------------------------------- + * IB_AL DATA + * ------------------------------------------------ */ + /* Number of references on the upper interface. */ + atomic32_t n_hca_ifc_ref; + hca_reg_state_t state; /* State for tracking registration with AL */ + DEVICE_OBJECT * p_al_dev; /* IB_AL FDO */ + FILE_OBJECT * p_al_file_obj; /* IB_AL file object */ + UNICODE_STRING al_sym_name; /* IB_AL symbolic name */ + + /* ------------------------------------------------- + * LOW LEVEL DRIVER' DATA + * ------------------------------------------------ */ + mlnx_hca_t hca; + atomic32_t usecnt; /* the number of working applications*/ + cl_spinlock_t uctx_lock; // spinlock for the below chain + cl_qlist_t uctx_list; // chain of user contexts + + /* ------------------------------------------------- + * OS DATA + * ------------------------------------------------ */ + hca_bar_t bar[HCA_BAR_TYPE_MAX]; /* HCA memory bars */ + CM_PARTIAL_RESOURCE_DESCRIPTOR interruptInfo; /* HCA interrupt resources */ + PKINTERRUPT int_obj; /* HCA interrupt object */ + spinlock_t isr_lock; /* lock for the ISR */ + ULONG bus_number; /* HCA's bus number */ + BUS_INTERFACE_STANDARD hcaBusIfc; /* PCI bus interface */ + + /* ------------------------------------------------- + * VARIABLES + * ------------------------------------------------ */ + DMA_ADAPTER * p_dma_adapter; /* HCA adapter object */ + ULONG n_map_regs; /* num of allocated adapter map registers */ + PCI_COMMON_CONFIG hcaConfig; /* saved HCA PCI configuration header */ + int hca_hidden; /* flag: when set - no attached DDR memory */ + +} hca_dev_ext_t; + +#define EXT_FROM_HOB(hob_p) (container_of(hob_p, hca_dev_ext_t, hca.hob)) +#define HCA_FROM_HOB(hob_p) (container_of(hob_p, mlnx_hca_t, hob)) +#define MDEV_FROM_HOB(hob_p) (HCA_FROM_HOB(hob_p)->mdev) +#define IBDEV_FROM_HOB(hob_p) (&EXT_FROM_HOB(hob_p)->hca.mdev->ib_dev) +#define HOBUL_FROM_HOB(hob_p) (&EXT_FROM_HOB(hob_p)->hca.hobul) +#define HOB_FROM_IBDEV(dev_p) (mlnx_hob_t *)&dev_p->mdev->ext->hca.hob + + +/*********************************** +Firmware Update definitions +***********************************/ +#define PCI_CONF_ADDR (0x00000058) +#define PCI_CONF_DATA (0x0000005c) +#define FLASH_OFFSET (0x000f01a4) +#define READ_BIT (1<<29) +#define WRITE_BIT (2<<29) +#define ADDR_MSK (0x0007ffff) +#define CMD_MASK (0xe0000000) +#define BANK_SHIFT (19) +#define BANK_MASK (0xfff80000) +#define MAX_FLASH_SIZE (0x80000) // 512K + +#define SEMAP63 (0xf03fc) +#define GPIO_DIR_L (0xf008c) +#define GPIO_POL_L (0xf0094) +#define GPIO_MOD_L (0xf009c) +#define GPIO_DAT_L (0xf0084) +#define GPIO_DATACLEAR_L (0xf00d4) +#define GPIO_DATASET_L (0xf00dc) + +#define CPUMODE (0xf0150) +#define CPUMODE_MSK (0xc0000000UL) +#define CPUMODE_SHIFT (30) + +/* Definitions intended to become shared with UM. Later... */ +#define FW_READ 0x00 +#define FW_WRITE 0x01 +#define FW_READ_CMD 0x08 +#define FW_WRITE_CMD 0x09 +#define FW_OPEN_IF 0xe7 +#define FW_CLOSE_IF 0x7e + +#if 1//WORKAROUND_POLL_EQ +#define FW_POLL_EQ_START 0x0D +#define FW_POLL_EQ_STOP 0x0E +#endif + +#define FW_SIGNATURE (0x5a445a44) +#define FW_SECT_SIZE (0x10000) + +static inline errno_to_iberr(int err) +{ +#define MAP_ERR(err,ibstatus) case err: ib_status = ibstatus; break + ib_api_status_t ib_status = IB_UNKNOWN_ERROR; + if (err < 0) + err = -err; + switch (err) { + MAP_ERR( ENOENT, IB_NOT_FOUND ); + MAP_ERR( EINTR, IB_INTERRUPTED ); + MAP_ERR( EAGAIN, IB_RESOURCE_BUSY ); + MAP_ERR( ENOMEM, IB_INSUFFICIENT_MEMORY ); + MAP_ERR( EACCES, IB_INVALID_PERMISSION ); + MAP_ERR( EFAULT, IB_ERROR ); + MAP_ERR( EBUSY, IB_RESOURCE_BUSY ); + MAP_ERR( ENODEV, IB_UNSUPPORTED ); + MAP_ERR( EINVAL, IB_INVALID_PARAMETER ); + MAP_ERR( ENOSYS, IB_UNSUPPORTED ); + MAP_ERR( ERANGE, IB_INVALID_SETTING ); + default: + //HCA_PRINT(TRACE_LEVEL_ERROR, HCA_DBG_SHIM, + // "Unmapped errno (%d)\n", err); + break; + } + return ib_status; +} + +#endif /* !defined( _HCA_DRIVER_H_ ) */ diff --git a/branches/WOF2-3/hw/mthca/kernel/hca_mcast.c b/branches/WOF2-3/hw/mthca/kernel/hca_mcast.c new file mode 100644 index 00000000..14ce52dd --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/hca_mcast.c @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2004-2005 Mellanox Technologies, Inc. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include +#include + +#include "hca_driver.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "hca_mcast.tmh" +#endif +#include "mthca_dev.h" + +/* +* Multicast Support Verbs. +*/ +ib_api_status_t +mlnx_attach_mcast ( + IN const ib_qp_handle_t h_qp, + IN const ib_gid_t *p_mcast_gid, + IN const uint16_t mcast_lid, + OUT ib_mcast_handle_t *ph_mcast, + IN OUT ci_umv_buf_t *p_umv_buf ) +{ + int err; + ib_api_status_t status; + struct ib_qp *ib_qp_p = (struct ib_qp *)h_qp; + mlnx_mcast_t *mcast_p; + + HCA_ENTER(HCA_DBG_MCAST); + + // sanity checks + if( p_umv_buf && p_umv_buf->command ) { + HCA_PRINT(TRACE_LEVEL_ERROR , HCA_DBG_MCAST, + ("User mode is not supported yet\n")); + status = IB_UNSUPPORTED; + goto err_user_unsupported; + } + + if( !cl_is_blockable() ) { + status = IB_UNSUPPORTED; + goto err_unsupported; + } + + if (!p_mcast_gid || !ph_mcast) { + status = IB_INVALID_PARAMETER; + goto err_invalid_param; + } + + // allocate structure + mcast_p = (mlnx_mcast_t*)kmalloc(sizeof *mcast_p, GFP_ATOMIC ); + if (mcast_p == NULL) { + status = IB_INSUFFICIENT_MEMORY; + goto err_no_mem; + } + + // attach to mcast group + if( p_umv_buf && p_umv_buf->command ) { + //TODO: call uverbs + } + else { + err = ibv_attach_mcast(ib_qp_p, (union ib_gid *)p_mcast_gid, (u16)mcast_lid); + if (err) { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_MCAST, + ("ibv_attach_mcast failed (%d)\n", err)); + status = errno_to_iberr(err); + goto err_attach; + } + } + + // fill the structure + mcast_p->ib_qp_p = ib_qp_p; + mcast_p->mcast_lid = mcast_lid; + RtlCopyMemory(mcast_p->mcast_gid.raw, p_mcast_gid->raw, sizeof *p_mcast_gid); + HCA_PRINT(TRACE_LEVEL_INFORMATION,HCA_DBG_MCAST, + ("mcasth %p, qp_p %p, mlid %hx, mgid %I64x`%I64x\n", + mcast_p, mcast_p->ib_qp_p, mcast_p->mcast_lid, + cl_ntoh64(*(uint64_t*)&mcast_p->mcast_gid.raw[0]), + cl_ntoh64(*(uint64_t*)&mcast_p->mcast_gid.raw[8] ))); + + // return the result + if (ph_mcast) *ph_mcast = (ib_mcast_handle_t)mcast_p; + + status = IB_SUCCESS; + goto end; + +err_attach: + kfree(mcast_p); +err_no_mem: +err_invalid_param: +err_unsupported: +err_user_unsupported: +end: + if (status != IB_SUCCESS) + { + HCA_PRINT(TRACE_LEVEL_ERROR, HCA_DBG_MCAST, + ("completes with ERROR status %#x\n", status)); + } + HCA_EXIT(HCA_DBG_MCAST); + return status; +} + +ib_api_status_t +mlnx_detach_mcast ( + IN const ib_mcast_handle_t h_mcast) +{ + ib_api_status_t status = IB_INVALID_PARAMETER; + int err; + mlnx_mcast_t *mcast_p = (mlnx_mcast_t*)h_mcast; + struct ib_device *ib_dev; + + + HCA_ENTER(HCA_DBG_MCAST); + // sanity check + if (!mcast_p || !mcast_p->ib_qp_p) + { + HCA_PRINT(TRACE_LEVEL_ERROR , HCA_DBG_MCAST, + ("completes with ERROR status IB_INVALID_PARAMETER\n")); + status = IB_INVALID_PARAMETER; + goto err_invalid_param; + } + ib_dev = mcast_p->ib_qp_p->device; + + if( !cl_is_blockable() ) { + status = IB_UNSUPPORTED; + goto err_unsupported; + } + + + HCA_PRINT(TRACE_LEVEL_INFORMATION,HCA_DBG_MCAST, + ("mcasth %p, qp_p %p, mlid %hx, mgid %I64x`%I64x\n", + mcast_p, mcast_p->ib_qp_p, mcast_p->mcast_lid, + *(uint64_t*)&mcast_p->mcast_gid.raw[0], + *(uint64_t*)&mcast_p->mcast_gid.raw[8] )); + + // detach + err = ibv_detach_mcast( mcast_p->ib_qp_p, + (union ib_gid *)&mcast_p->mcast_gid, mcast_p->mcast_lid ); + if (err) { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_MCAST, + ("ibv_detach_mcast failed (%d)\n", err)); + status = errno_to_iberr(err); + goto err_detach_mcast; + } + + status = IB_SUCCESS; + +err_detach_mcast: + kfree(mcast_p); +err_unsupported: +err_invalid_param: + if (status != IB_SUCCESS) + { + HCA_PRINT(TRACE_LEVEL_ERROR, HCA_DBG_MCAST, + ("completes with ERROR status %d\n", status)); + } + HCA_EXIT(HCA_DBG_MCAST); + return status; +} + + +void +mlnx_mcast_if( + IN OUT ci_interface_t *p_interface ) +{ + p_interface->attach_mcast = mlnx_attach_mcast; + p_interface->detach_mcast = mlnx_detach_mcast; +} diff --git a/branches/WOF2-3/hw/mthca/kernel/hca_memory.c b/branches/WOF2-3/hw/mthca/kernel/hca_memory.c new file mode 100644 index 00000000..1e3ef6e2 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/hca_memory.c @@ -0,0 +1,572 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2004-2005 Mellanox Technologies, Inc. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include "hca_utils.h" +#include "mthca_dev.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "hca_memory.tmh" +#endif + +/* + * Memory Management Verbs. + */ + +ib_api_status_t +mlnx_register_mr ( + IN const ib_pd_handle_t h_pd, + IN const ib_mr_create_t *p_mr_create, + OUT net32_t* const p_lkey, + OUT net32_t* const p_rkey, + OUT ib_mr_handle_t *ph_mr, + IN boolean_t um_call ) +{ + ib_api_status_t status; + int err; + struct ib_mr *mr_p; + struct ib_pd *ib_pd_p = (struct ib_pd *)h_pd; + + HCA_ENTER(HCA_DBG_MEMORY); + + // sanity checks + if( !cl_is_blockable() ) { + status = IB_UNSUPPORTED; + goto err_unsupported; + } + if (!p_mr_create || 0 == p_mr_create->length) { + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_MEMORY, + ("invalid attributes\n")); + status = IB_INVALID_PARAMETER; + goto err_invalid_parm; + } + /* + * Local write permission is required if remote write or + * remote atomic permission is also requested. + */ + if (p_mr_create->access_ctrl & (IB_AC_RDMA_WRITE | IB_AC_ATOMIC) && + !(p_mr_create->access_ctrl & IB_AC_LOCAL_WRITE)) { + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_MEMORY, + ("invalid access rights\n")); + status = IB_INVALID_PERMISSION; + goto err_invalid_access; + } + + // register mr + mr_p = ibv_reg_mr(ib_pd_p, map_qp_ibal_acl(p_mr_create->access_ctrl), + p_mr_create->vaddr, p_mr_create->length, + (ULONG_PTR)p_mr_create->vaddr, um_call, TRUE ); + if (IS_ERR(mr_p)) { + err = PTR_ERR(mr_p); + HCA_PRINT(TRACE_LEVEL_ERROR, HCA_DBG_MEMORY, + ("ibv_reg_mr failed (%d)\n", err)); + status = errno_to_iberr(err); + goto err_reg_mr; + } + + // results + *p_lkey = mr_p->lkey; + *p_rkey = cl_hton32( mr_p->rkey ); + if (ph_mr) *ph_mr = (ib_mr_handle_t)mr_p; + status = IB_SUCCESS; + +err_reg_mr: +err_invalid_access: +err_invalid_parm: +err_unsupported: + if (status != IB_SUCCESS) + { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_MEMORY, + ("completes with ERROR status %#x\n", status)); + } + HCA_EXIT(HCA_DBG_MEMORY); + return status; +} + +ib_api_status_t +mlnx_register_pmr ( + IN const ib_pd_handle_t h_pd, + IN const ib_phys_create_t* const p_pmr_create, + IN OUT uint64_t* const p_vaddr, + OUT net32_t* const p_lkey, + OUT net32_t* const p_rkey, + OUT ib_mr_handle_t* const ph_mr, + IN boolean_t um_call ) +{ + ib_api_status_t status; + int err; + struct ib_mr *mr_p; + struct ib_phys_buf *buffer_list; + struct ib_pd *ib_pd_p = (struct ib_pd *)h_pd; + + UNUSED_PARAM( um_call ); + + HCA_ENTER(HCA_DBG_MEMORY); + + // sanity checks + if( !cl_is_blockable() ) { + status = IB_UNSUPPORTED; + goto err_unsupported; + } + if (!p_vaddr || !p_pmr_create || + 0 == p_pmr_create->length ) { + status = IB_INVALID_PARAMETER; + goto err_invalid_parm; + } + + // prepare parameters + buffer_list = (void*)p_pmr_create->range_array; + //NB: p_pmr_create->buf_offset is not used, i.e. supposed that region is page-aligned + //NB: p_pmr_create->hca_page_size is not used, i.e. supposed it is always the same + + // register pmr + if (p_pmr_create->length == (uint64_t)-1i64) + { + mr_p = ibv_get_dma_mr( ib_pd_p, + map_qp_ibal_acl(p_pmr_create->access_ctrl) ); + } + else + mr_p = ibv_reg_phys_mr(ib_pd_p, buffer_list, p_pmr_create->num_ranges, + map_qp_ibal_acl(p_pmr_create->access_ctrl), p_vaddr ); + if (IS_ERR(mr_p)) { + err = PTR_ERR(mr_p); + HCA_PRINT(TRACE_LEVEL_ERROR, HCA_DBG_MEMORY, + ("mthca_reg_phys_mr failed (%d)\n", err)); + status = errno_to_iberr(err); + goto err_reg_phys_mr; + } + + // results + if (ph_mr) *ph_mr = (ib_mr_handle_t)mr_p; + *p_lkey = mr_p->lkey; + *p_rkey = cl_hton32( mr_p->rkey ); + //NB: p_vaddr was not changed + status = IB_SUCCESS; + +err_reg_phys_mr: +err_invalid_parm: +err_unsupported: + if (status != IB_SUCCESS) + { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_MEMORY, + ("completes with ERROR status %#x\n", status)); + } + HCA_EXIT(HCA_DBG_MEMORY); + return status; + +} + +ib_api_status_t +mlnx_query_mr ( + IN const ib_mr_handle_t h_mr, + OUT ib_mr_attr_t *p_mr_query ) +{ + UNREFERENCED_PARAMETER(h_mr); + UNREFERENCED_PARAMETER(p_mr_query); + HCA_PRINT(TRACE_LEVEL_ERROR , HCA_DBG_MEMORY ,("mlnx_query_mr not implemented\n")); + return IB_UNSUPPORTED; +} + + +ib_api_status_t +mlnx_modify_mr ( + IN const ib_mr_handle_t h_mr, + IN const ib_mr_mod_t mem_modify_req, + IN const ib_mr_create_t *p_mr_create, + OUT uint32_t *p_lkey, + OUT uint32_t *p_rkey, + IN const ib_pd_handle_t h_pd OPTIONAL, + IN boolean_t um_call ) +{ + UNREFERENCED_PARAMETER(h_mr); + UNREFERENCED_PARAMETER(mem_modify_req); + UNREFERENCED_PARAMETER(p_mr_create); + UNREFERENCED_PARAMETER(p_lkey); + UNREFERENCED_PARAMETER(p_rkey); + UNREFERENCED_PARAMETER(h_pd); + UNREFERENCED_PARAMETER(um_call); + HCA_PRINT(TRACE_LEVEL_ERROR , HCA_DBG_MEMORY ,("mlnx_modify_mr not implemented\n")); + return IB_UNSUPPORTED; +} + + +ib_api_status_t +mlnx_modify_pmr ( + IN const ib_mr_handle_t h_mr, + IN const ib_mr_mod_t mem_modify_req, + IN const ib_phys_create_t* const p_pmr_create, + IN OUT uint64_t* const p_vaddr, + OUT uint32_t* const p_lkey, + OUT uint32_t* const p_rkey, + IN const ib_pd_handle_t h_pd OPTIONAL, + IN boolean_t um_call ) +{ + UNREFERENCED_PARAMETER(h_mr); + UNREFERENCED_PARAMETER(mem_modify_req); + UNREFERENCED_PARAMETER(p_pmr_create); + UNREFERENCED_PARAMETER(p_vaddr); + UNREFERENCED_PARAMETER(p_lkey); + UNREFERENCED_PARAMETER(p_rkey); + UNREFERENCED_PARAMETER(h_pd); + UNREFERENCED_PARAMETER(um_call); + HCA_PRINT(TRACE_LEVEL_ERROR , HCA_DBG_MEMORY ,("mlnx_modify_pmr not implemented\n")); + return IB_UNSUPPORTED; +} + +ib_api_status_t +mlnx_register_smr ( + IN const ib_mr_handle_t h_mr, + IN const ib_pd_handle_t h_pd, + IN const ib_access_t access_ctrl, + IN OUT uint64_t* const p_vaddr, + OUT net32_t* const p_lkey, + OUT net32_t* const p_rkey, + OUT ib_mr_handle_t* const ph_mr, + IN boolean_t um_call ) +{ + UNREFERENCED_PARAMETER(h_mr); + UNREFERENCED_PARAMETER(h_pd); + UNREFERENCED_PARAMETER(access_ctrl); + UNREFERENCED_PARAMETER(p_vaddr); + UNREFERENCED_PARAMETER(p_lkey); + UNREFERENCED_PARAMETER(p_rkey); + UNREFERENCED_PARAMETER(ph_mr); + UNREFERENCED_PARAMETER(um_call); + HCA_PRINT(TRACE_LEVEL_ERROR , HCA_DBG_MEMORY ,("mlnx_register_smr not implemented\n")); + return IB_UNSUPPORTED; +} + +ib_api_status_t +mlnx_deregister_mr ( + IN const ib_mr_handle_t h_mr) +{ + ib_api_status_t status; + int err; + + HCA_ENTER(HCA_DBG_SHIM); + + // sanity checks + if( !cl_is_blockable() ) { + status = IB_UNSUPPORTED; + goto err_unsupported; + } + + // deregister + err = ibv_dereg_mr((struct ib_mr *)h_mr); + if (err) { + status = errno_to_iberr(err); + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_MEMORY, + ("mthca_dereg_mr failed (%d)", status)); + goto err_dereg_mr; + } + + status = IB_SUCCESS; + +err_dereg_mr: +err_unsupported: + if (status != IB_SUCCESS) + { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_MEMORY, + ("completes with ERROR status %#x\n", status)); + } + HCA_EXIT(HCA_DBG_MEMORY); + return status; + +} + +ib_api_status_t +mlnx_alloc_fmr( + IN const ib_pd_handle_t h_pd, + IN const mlnx_fmr_create_t* const p_fmr_create, + OUT mlnx_fmr_handle_t* const ph_fmr + ) +{ + ib_api_status_t status; + int err; + struct ib_fmr * fmr_p; + struct ib_pd *ib_pd_p = (struct ib_pd *)h_pd; + struct ib_fmr_attr fmr_attr; + + HCA_ENTER(HCA_DBG_MEMORY); + + // sanity checks + if( !cl_is_blockable() ) { + status = IB_UNSUPPORTED; + goto err_unsupported; + } + if (!p_fmr_create ) { + status = IB_INVALID_PARAMETER; + goto err_invalid_parm; + } + // TODO: check Max remap in AL + + // prepare parameters + RtlZeroMemory(&fmr_attr, sizeof(struct ib_fmr_attr)); + fmr_attr.max_maps = p_fmr_create->max_maps; + fmr_attr.max_pages = p_fmr_create->max_pages; + fmr_attr.page_shift = p_fmr_create->page_size; + + // register mr + fmr_p = ibv_alloc_fmr(ib_pd_p, + map_qp_ibal_acl(p_fmr_create->access_ctrl), &fmr_attr); + if (IS_ERR(fmr_p)) { + err = PTR_ERR(fmr_p); + HCA_PRINT(TRACE_LEVEL_ERROR , HCA_DBG_MEMORY , + ("mthca_alloc_fmr failed (%d)\n", err)); + status = errno_to_iberr(err); + goto err_alloc_fmr; + } + + // results + if (ph_fmr) *ph_fmr = (mlnx_fmr_handle_t)fmr_p; + status = IB_SUCCESS; + +err_alloc_fmr: +err_invalid_parm: +err_unsupported: + if (status != IB_SUCCESS) + { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_MEMORY, + ("completes with ERROR status %#x\n", status)); + } + HCA_EXIT(HCA_DBG_MEMORY); + return status; + +} + +ib_api_status_t +mlnx_map_phys_fmr ( + IN const mlnx_fmr_handle_t h_fmr, + IN const uint64_t* const page_list, + IN const int list_len, + IN OUT uint64_t* const p_vaddr, + OUT net32_t* const p_lkey, + OUT net32_t* const p_rkey + ) +{ + int err; + ib_api_status_t status; + struct ib_fmr *ib_fmr = (struct ib_fmr *)h_fmr; + uint64_t vaddr = (*p_vaddr) & ~(PAGE_SIZE - 1); + + HCA_ENTER(HCA_DBG_MEMORY); + + // mapping + err = ibv_map_phys_fmr(ib_fmr, (u64*)page_list, list_len, (uint64_t)(ULONG_PTR)vaddr); + if (err) { + status = errno_to_iberr(err); + HCA_PRINT(TRACE_LEVEL_ERROR , HCA_DBG_MEMORY , + ("ibv_map_phys_fmr failed (%d) for mr %p\n", err, h_fmr)); + goto err_dealloc_fmr; + } + + // return the results + *p_vaddr = vaddr; + *p_lkey = ib_fmr->lkey; + *p_rkey = cl_hton32( ib_fmr->rkey ); + + status = IB_SUCCESS; + +err_dealloc_fmr: + if (status != IB_SUCCESS) + { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_MEMORY, + ("completes with ERROR status %#x\n", status)); + } + HCA_EXIT(HCA_DBG_MEMORY); + return status; +} + + + +ib_api_status_t +mlnx_unmap_fmr ( + IN const mlnx_fmr_handle_t *ph_fmr) +{ + ib_api_status_t status; + int err; + struct ib_fmr *ib_fmr = (struct ib_fmr *)*ph_fmr; + struct list_head fmr_list; + + HCA_ENTER(HCA_DBG_MEMORY); + + // sanity checks + if( !cl_is_blockable() ) { + status = IB_UNSUPPORTED; + goto err_unsupported; + } + + INIT_LIST_HEAD(&fmr_list); + while(*ph_fmr) + { + ib_fmr = (struct ib_fmr*)*ph_fmr; + list_add_tail(&ib_fmr->list, &fmr_list); + ph_fmr ++; + } + + err = ibv_unmap_fmr(&fmr_list); + if (err) { + status = errno_to_iberr(err); + HCA_PRINT(TRACE_LEVEL_ERROR , HCA_DBG_MEMORY , + ("ibv_unmap_fmr failed (%d) \n", err)); + goto err_unmap_fmr; + } + + status = IB_SUCCESS; + +err_unmap_fmr: +err_unsupported: + if (status != IB_SUCCESS) + { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_MEMORY, + ("completes with ERROR status %#x\n", status)); + } + HCA_EXIT(HCA_DBG_MEMORY); + return status; + + +} + + + +ib_api_status_t +mlnx_dealloc_fmr ( + IN const mlnx_fmr_handle_t h_fmr + ) +{ + ib_api_status_t status; + int err; + + HCA_ENTER(HCA_DBG_MEMORY); + + // sanity checks + if( !cl_is_blockable() ) { + status = IB_UNSUPPORTED; + goto err_unsupported; + } + + + // deregister + err = ibv_dealloc_fmr((struct ib_fmr *)h_fmr); + if (err) { + status = errno_to_iberr(err); + HCA_PRINT(TRACE_LEVEL_ERROR, HCA_DBG_MEMORY , + ("ibv_dealloc_fmr failed (%d) for mr %p\n",err, h_fmr)); + goto err_dealloc_fmr; + } + + status = IB_SUCCESS; + +err_dealloc_fmr: +err_unsupported: + if (status != IB_SUCCESS) + { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_MEMORY, + ("completes with ERROR status %#x\n", status)); + } + HCA_EXIT(HCA_DBG_MEMORY); + return status; + +} + + + +/* +* Memory Window Verbs. +*/ + +ib_api_status_t +mlnx_create_mw ( + IN const ib_pd_handle_t h_pd, + OUT net32_t* const p_rkey, + OUT ib_mw_handle_t *ph_mw, + IN OUT ci_umv_buf_t *p_umv_buf ) +{ + UNREFERENCED_PARAMETER(h_pd); + UNREFERENCED_PARAMETER(p_rkey); + UNREFERENCED_PARAMETER(ph_mw); + UNREFERENCED_PARAMETER(p_umv_buf); + HCA_PRINT(TRACE_LEVEL_ERROR , HCA_DBG_MEMORY ,("mlnx_create_mw not implemented\n")); + return IB_UNSUPPORTED; +} + +ib_api_status_t +mlnx_query_mw ( + IN const ib_mw_handle_t h_mw, + OUT ib_pd_handle_t *ph_pd, + OUT net32_t* const p_rkey, + IN OUT ci_umv_buf_t *p_umv_buf ) +{ + UNREFERENCED_PARAMETER(h_mw); + UNREFERENCED_PARAMETER(ph_pd); + UNREFERENCED_PARAMETER(p_rkey); + UNREFERENCED_PARAMETER(p_umv_buf); + HCA_PRINT(TRACE_LEVEL_ERROR , HCA_DBG_MEMORY ,("mlnx_query_mw not implemented\n")); + return IB_UNSUPPORTED; +} + +ib_api_status_t +mlnx_destroy_mw ( + IN const ib_mw_handle_t h_mw) +{ + UNREFERENCED_PARAMETER(h_mw); + HCA_PRINT(TRACE_LEVEL_ERROR , HCA_DBG_MEMORY ,("mlnx_destroy_mw not implemented\n")); + return IB_UNSUPPORTED; +} + + +void +mlnx_memory_if( + IN OUT ci_interface_t *p_interface ) +{ + p_interface->register_mr = mlnx_register_mr; + p_interface->register_pmr = mlnx_register_pmr; + p_interface->query_mr = mlnx_query_mr; + p_interface->modify_mr = mlnx_modify_mr; + p_interface->modify_pmr = mlnx_modify_pmr; + p_interface->register_smr = mlnx_register_smr; + p_interface->deregister_mr = mlnx_deregister_mr; + + p_interface->alloc_mlnx_fmr = mlnx_alloc_fmr; + p_interface->map_phys_mlnx_fmr = mlnx_map_phys_fmr; + p_interface->unmap_mlnx_fmr = mlnx_unmap_fmr; + p_interface->dealloc_mlnx_fmr = mlnx_dealloc_fmr; + + p_interface->create_mw = mlnx_create_mw; + p_interface->query_mw = mlnx_query_mw; + p_interface->destroy_mw = mlnx_destroy_mw; +} + diff --git a/branches/WOF2-3/hw/mthca/kernel/hca_pci.c b/branches/WOF2-3/hw/mthca/kernel/hca_pci.c new file mode 100644 index 00000000..806490d9 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/hca_pci.c @@ -0,0 +1,762 @@ + +#include "hca_driver.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "hca_pci.tmh" +#endif +#include +#include +#include + +#define HCA_RESET_HCR_OFFSET 0x000F0010 +#define HCA_RESET_TOKEN CL_HTON32(0x00000001) + +#define PCI_CAPABILITY_ID_VPD 0x03 +#define PCI_CAPABILITY_ID_PCIX 0x07 +#define PCI_CAPABILITY_ID_PCIEXP 0x10 + +boolean_t +FindBridgeIf( + IN hca_dev_ext_t *pi_ext, + IN PBUS_INTERFACE_STANDARD pi_pInterface + ); + + +/* + * Vital Product Data Capability + */ +typedef struct _PCI_VPD_CAPABILITY { + + PCI_CAPABILITIES_HEADER Header; + + USHORT Flags; + ULONG Data; + +} PCI_VPD_CAPABILITY, *PPCI_VPD_CAPABILITY; + + +/* + * PCI-X Capability + */ +typedef struct _PCI_PCIX_CAPABILITY { + + PCI_CAPABILITIES_HEADER Header; + + USHORT Command; + ULONG Status; + +/* for Command: */ +} PCI_PCIX_CAPABILITY, *PPCI_PCIX_CAPABILITY; + +#define PCI_X_CMD_MAX_READ 0x000c /* Max Memory Read Byte Count */ + +/* + * PCI-Express Capability + */ +typedef struct _PCI_PCIEXP_CAPABILITY { + + PCI_CAPABILITIES_HEADER Header; + + USHORT Flags; + ULONG DevCapabilities; + USHORT DevControl; + USHORT DevStatus; + ULONG LinkCapabilities; + USHORT LinkControl; + USHORT LinkStatus; + ULONG SlotCapabilities; + USHORT SlotControl; + USHORT SlotStatus; + USHORT RootControl; + USHORT RootCapabilities; + USHORT RootStatus; +} PCI_PCIEXP_CAPABILITY, *PPCI_PCIEXP_CAPABILITY; + +/* for DevControl: */ +#define PCI_EXP_DEVCTL_READRQ 0x7000 /* Max_Read_Request_Size */ + +static NTSTATUS +__get_bus_ifc( + IN DEVICE_OBJECT* const pDevObj, + IN const GUID* const pGuid, + OUT BUS_INTERFACE_STANDARD *pBusIfc ); + +static void +__fixup_pci_capabilities( + IN PCI_COMMON_CONFIG* const pConfig ); + +static NTSTATUS +__save_pci_config( + IN BUS_INTERFACE_STANDARD *pBusIfc, + OUT PCI_COMMON_CONFIG* const pConfig ); + +static NTSTATUS +__restore_pci_config( + IN BUS_INTERFACE_STANDARD *pBusIfc, + IN PCI_COMMON_CONFIG* const pConfig, + IN const int is_bridge ); + + +/* + * Returns the offset in configuration space of the PCI-X capabilites. + */ +static ULONG +__FindCapability( + IN PCI_COMMON_CONFIG* const pConfig, + IN char cap_id + ) +{ + ULONG offset = 0; + PCI_CAPABILITIES_HEADER *pHdr = NULL; + UCHAR *pBuf = (UCHAR*)pConfig; + + HCA_ENTER( HCA_DBG_PNP ); + + if ( pConfig->HeaderType == PCI_DEVICE_TYPE ) { + if( pConfig->u.type0.CapabilitiesPtr ) + { + pHdr = (PCI_CAPABILITIES_HEADER*) + (pBuf + pConfig->u.type0.CapabilitiesPtr); + } + } + + if ( pConfig->HeaderType == PCI_BRIDGE_TYPE ) { + if( pConfig->u.type1.CapabilitiesPtr ) + { + pHdr = (PCI_CAPABILITIES_HEADER*) + (pBuf + pConfig->u.type1.CapabilitiesPtr); + } + } + + /* + * Fix up any fields that might cause changes to the + * device - like writing VPD data. + */ + while( pHdr ) + { + if( pHdr->CapabilityID == cap_id ) + { + offset = (UCHAR)(((ULONG_PTR)pHdr) - ((ULONG_PTR)pConfig)); + break; + } + + if( pHdr->Next ) + pHdr = (PCI_CAPABILITIES_HEADER*)(pBuf + pHdr->Next); + else + pHdr = NULL; + } + + HCA_EXIT( HCA_DBG_PNP ); + return offset; +} + +/* Forwards the request to the HCA's PDO. */ +static NTSTATUS +__get_bus_ifc( + IN DEVICE_OBJECT* const pDevObj, + IN const GUID* const pGuid, + OUT BUS_INTERFACE_STANDARD *pBusIfc ) +{ + NTSTATUS status; + IRP *pIrp; + IO_STATUS_BLOCK ioStatus; + IO_STACK_LOCATION *pIoStack; + DEVICE_OBJECT *pDev; + KEVENT event; + + HCA_ENTER( HCA_DBG_PNP ); + + CL_ASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL ); + + pDev = IoGetAttachedDeviceReference( pDevObj ); + + KeInitializeEvent( &event, NotificationEvent, FALSE ); + + /* Build the IRP for the HCA. */ + pIrp = IoBuildSynchronousFsdRequest( IRP_MJ_PNP, pDev, + NULL, 0, NULL, &event, &ioStatus ); + if( !pIrp ) + { + ObDereferenceObject( pDev ); + HCA_PRINT( TRACE_LEVEL_ERROR,HCA_DBG_PNP, + ("IoBuildSynchronousFsdRequest failed.\n")); + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* Copy the request query parameters. */ + pIoStack = IoGetNextIrpStackLocation( pIrp ); + pIoStack->MinorFunction = IRP_MN_QUERY_INTERFACE; + pIoStack->Parameters.QueryInterface.Size = sizeof(BUS_INTERFACE_STANDARD); + pIoStack->Parameters.QueryInterface.Version = 1; + pIoStack->Parameters.QueryInterface.InterfaceType = pGuid; + pIoStack->Parameters.QueryInterface.Interface = (INTERFACE*)pBusIfc; + pIoStack->Parameters.QueryInterface.InterfaceSpecificData = NULL; + + pIrp->IoStatus.Status = STATUS_NOT_SUPPORTED; + + /* Send the IRP. */ + status = IoCallDriver( pDev, pIrp ); + if( status == STATUS_PENDING ) + { + KeWaitForSingleObject( &event, Executive, KernelMode, + FALSE, NULL ); + + status = ioStatus.Status; + } + ObDereferenceObject( pDev ); + + HCA_EXIT( HCA_DBG_PNP ); + return status; +} + + +/* + * Reads and saves the PCI configuration of the device accessible + * through the provided bus interface. Does not read registers 22 or 23 + * as directed in Tavor PRM 1.0.1, Appendix A. InfiniHost Software Reset. + */ +static NTSTATUS +__save_pci_config( + IN BUS_INTERFACE_STANDARD *pBusIfc, + OUT PCI_COMMON_CONFIG* const pConfig ) +{ + ULONG len; + UINT32 *pBuf; + + HCA_ENTER( HCA_DBG_PNP ); + + pBuf = (UINT32*)pConfig; + + /* + * Read the lower portion of the configuration, up to but excluding + * register 22. + */ + len = pBusIfc->GetBusData( + pBusIfc->Context, PCI_WHICHSPACE_CONFIG, &pBuf[0], 0, 88 ); + if( len != 88 ) + { + HCA_PRINT( TRACE_LEVEL_ERROR , HCA_DBG_PNP ,("Failed to read HCA config.\n")); + return STATUS_DEVICE_NOT_READY; + } + + /* Read the upper portion of the configuration, from register 24. */ + len = pBusIfc->GetBusData( + pBusIfc->Context, PCI_WHICHSPACE_CONFIG, &pBuf[24], 96, 160 ); + if( len != 160 ) + { + HCA_PRINT( TRACE_LEVEL_ERROR ,HCA_DBG_PNP ,("Failed to read HCA config.\n")); + return STATUS_DEVICE_NOT_READY; + } + + HCA_EXIT( HCA_DBG_PNP ); + return STATUS_SUCCESS; +} + + +static void +__fixup_pci_capabilities( + IN PCI_COMMON_CONFIG* const pConfig ) +{ + UCHAR *pBuf; + PCI_CAPABILITIES_HEADER *pHdr, *pNextHdr; + + HCA_ENTER( HCA_DBG_PNP ); + + pBuf = (UCHAR*)pConfig; + + if( pConfig->HeaderType == PCI_DEVICE_TYPE ) + { + if( pConfig->u.type0.CapabilitiesPtr ) + { + pNextHdr = (PCI_CAPABILITIES_HEADER*) + (pBuf + pConfig->u.type0.CapabilitiesPtr); + } + else + { + pNextHdr = NULL; + } + } + else + { + ASSERT( pConfig->HeaderType == PCI_BRIDGE_TYPE ); + if( pConfig->u.type1.CapabilitiesPtr ) + { + pNextHdr = (PCI_CAPABILITIES_HEADER*) + (pBuf + pConfig->u.type1.CapabilitiesPtr); + } + else + { + pNextHdr = NULL; + } + } + + /* + * Fix up any fields that might cause changes to the + * device - like writing VPD data. + */ + while( pNextHdr ) + { + pHdr = pNextHdr; + if( pNextHdr->Next ) + pNextHdr = (PCI_CAPABILITIES_HEADER*)(pBuf + pHdr->Next); + else + pNextHdr = NULL; + + switch( pHdr->CapabilityID ) + { + case PCI_CAPABILITY_ID_VPD: + /* Clear the flags field so we don't cause a write. */ + ((PCI_VPD_CAPABILITY*)pHdr)->Flags = 0; + break; + + default: + break; + } + } + + HCA_EXIT( HCA_DBG_PNP ); +} + + +/* + * Restore saved PCI configuration, skipping registers 22 and 23, as well + * as any registers where writing will have side effects such as the flags + * field of the VPD and vendor specific capabilities. The function also delays + * writing the command register, bridge control register (if applicable), and + * PCIX command register (if present). + */ +static NTSTATUS +__restore_pci_config( + IN BUS_INTERFACE_STANDARD *pBusIfc, + IN PCI_COMMON_CONFIG* const pConfig, + IN const int is_bridge ) +{ + NTSTATUS status = STATUS_SUCCESS; + int i, *pci_hdr = (int*)pConfig; + int hca_pcix_cap = 0; + + HCA_ENTER( HCA_DBG_PNP ); + + /* get capabilities */ + hca_pcix_cap = __FindCapability( pConfig, PCI_CAPABILITY_ID_PCIX ); + + /* restore capabilities*/ + if (is_bridge) { + if ( 4 != pBusIfc->SetBusData( pBusIfc->Context, PCI_WHICHSPACE_CONFIG, + &pci_hdr[(hca_pcix_cap + 0x8) / 4], hca_pcix_cap + 0x8, 4) ) { + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, + ("Couldn't restore HCA bridge Upstream split transaction control, aborting.\n")); + status = STATUS_UNSUCCESSFUL; + goto out; + } + if ( 4 != pBusIfc->SetBusData( pBusIfc->Context, PCI_WHICHSPACE_CONFIG, + &pci_hdr[(hca_pcix_cap + 0xc) / 4], hca_pcix_cap + 0xc, 4) ) { + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, + ("Couldn't restore HCA bridge Downstream split transaction control, aborting.\n")); + status = STATUS_UNSUCCESSFUL; + goto out; + } + } + else { + int hca_pcie_cap = __FindCapability( pConfig, PCI_CAPABILITY_ID_PCIEXP ); + PCI_PCIEXP_CAPABILITY *pPciExpCap = (PCI_PCIEXP_CAPABILITY*)(((UCHAR*)pConfig) + hca_pcie_cap); + + if (hca_pcix_cap) { + if ( 4 != pBusIfc->SetBusData( pBusIfc->Context, PCI_WHICHSPACE_CONFIG, + &pci_hdr[hca_pcix_cap/4], hca_pcix_cap, 4) ) { + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, + ("Couldn't restore HCA PCI-X command register, aborting.\n")); + status = STATUS_UNSUCCESSFUL; + goto out; + } + } + + if (hca_pcie_cap) { + /* restore HCA PCI Express Device Control register */ + if ( sizeof( pPciExpCap->DevControl ) != pBusIfc->SetBusData( + pBusIfc->Context, PCI_WHICHSPACE_CONFIG, + &pPciExpCap->DevControl, hca_pcie_cap + + offsetof( PCI_PCIEXP_CAPABILITY, DevControl), + sizeof( pPciExpCap->DevControl ) )) { + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, + ("Couldn't restore HCA PCI Express Device Control register, aborting.\n")); + status = STATUS_UNSUCCESSFUL; + goto out; + } + /* restore HCA PCI Express Link Control register */ + if ( sizeof( pPciExpCap->LinkControl ) != pBusIfc->SetBusData( + pBusIfc->Context, PCI_WHICHSPACE_CONFIG, + &pPciExpCap->LinkControl, hca_pcie_cap + + offsetof( PCI_PCIEXP_CAPABILITY, LinkControl), + sizeof( pPciExpCap->LinkControl ) )) { + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, + ("Couldn't restore HCA PCI Express Link Control register, aborting.\n")); + status = STATUS_UNSUCCESSFUL; + goto out; + } + } + } + + /* write basic part */ + for (i = 0; i < 16; ++i) { + if (i == 1) + continue; + + if (4 != pBusIfc->SetBusData( pBusIfc->Context, + PCI_WHICHSPACE_CONFIG, &pci_hdr[i], i * 4, 4 )) { + HCA_PRINT( TRACE_LEVEL_ERROR ,HCA_DBG_PNP , + ("Couldn't restore PCI cfg reg %x, aborting.\n", i)); + status = STATUS_DEVICE_NOT_READY; + goto out; + } + } + + /* Write the command register. */ + if (4 != pBusIfc->SetBusData( pBusIfc->Context, + PCI_WHICHSPACE_CONFIG, &pci_hdr[1], 4, 4 )) { + HCA_PRINT( TRACE_LEVEL_ERROR ,HCA_DBG_PNP ,("Couldn't restore COMMAND.\n")); + status = STATUS_DEVICE_NOT_READY; + } + +out: + HCA_EXIT( HCA_DBG_PNP ); + return status; +} + +NTSTATUS +hca_reset( DEVICE_OBJECT* const pDevObj, int is_tavor ) +{ + NTSTATUS status = STATUS_SUCCESS; + PCI_COMMON_CONFIG hcaConfig, brConfig; + BUS_INTERFACE_STANDARD hcaBusIfc; + BUS_INTERFACE_STANDARD brBusIfc = {0}; // to bypass C4701 + hca_dev_ext_t *pExt = (hca_dev_ext_t*)pDevObj->DeviceExtension; + + HCA_ENTER( HCA_DBG_PNP ); + + /* sanity check */ + if (is_tavor && g_skip_tavor_reset) { + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_PNP ,("Card reset is skipped, trying to proceed.\n")); + goto resetExit; + } + + /* get the resources */ + { + /* Get the HCA's bus interface. */ + status = __get_bus_ifc( pDevObj, &GUID_BUS_INTERFACE_STANDARD, &hcaBusIfc ); + if( !NT_SUCCESS( status ) ) { + HCA_PRINT( TRACE_LEVEL_ERROR ,HCA_DBG_PNP ,("Failed to get HCA bus interface.\n")); + goto resetErr1; + } + + /* Get the HCA Bridge's bus interface, if any */ + if (is_tavor) { + if (!FindBridgeIf( pExt, &brBusIfc )) + goto resetErr2; + } + } + + /* Save the HCA's PCI configuration headers */ + { + status = __save_pci_config( &hcaBusIfc, &hcaConfig ); + if( !NT_SUCCESS( status ) ) { + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, + ("Failed to save HCA config.\n")); + goto resetErr3; + } + + /* Save the HCA bridge's configuration, if any */ + if (is_tavor) { + int hca_pcix_cap; + status = __save_pci_config( &brBusIfc, &brConfig ); + if( !NT_SUCCESS( status ) ) { + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, + ("Failed to save bridge config.\n")); + goto resetErr3; + } + hca_pcix_cap = __FindCapability( &brConfig, PCI_CAPABILITY_ID_PCIX ); + if (!hca_pcix_cap) { + status = STATUS_UNSUCCESSFUL; + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, + ("Couldn't locate HCA bridge PCI-X capability, aborting.\n")); + goto resetErr3; + } + } + } + + /* reset the card */ + { + PULONG reset_p; + PHYSICAL_ADDRESS pa; + /* map reset register */ + pa.QuadPart = pExt->bar[HCA_BAR_TYPE_HCR].phys + (uint64_t)HCA_RESET_HCR_OFFSET; + HCA_PRINT( TRACE_LEVEL_INFORMATION ,HCA_DBG_PNP ,("Mapping reset register with address 0x%I64x\n", pa.QuadPart)); + reset_p = MmMapIoSpace( pa, 4, MmNonCached ); + if( !reset_p ) { + HCA_PRINT( TRACE_LEVEL_ERROR ,HCA_DBG_PNP ,("Failed to map reset register with address 0x%I64x\n", pa.QuadPart)); + status = STATUS_UNSUCCESSFUL; + goto resetErr3; + } + + /* Issue the reset. */ + HCA_PRINT( TRACE_LEVEL_INFORMATION ,HCA_DBG_PNP ,("Resetting the chip ...\n")); + WRITE_REGISTER_ULONG( reset_p, HCA_RESET_TOKEN ); + + /* unmap the reset register */ + HCA_PRINT( TRACE_LEVEL_INFORMATION ,HCA_DBG_PNP ,("Unmapping reset register \n")); + MmUnmapIoSpace( reset_p, 4 ); + + /* Wait a second. */ + cl_thread_suspend( 1000 ); + } + + /* Read the configuration register until it doesn't return 0xFFFFFFFF */ + { + ULONG data, i, reset_failed = 1; + BUS_INTERFACE_STANDARD *p_ifc = (is_tavor) ? &brBusIfc : &hcaBusIfc; + HCA_PRINT( TRACE_LEVEL_INFORMATION ,HCA_DBG_PNP ,("Read the configuration register \n")); + for( i = 0; i < 100; i++ ) { + if (4 != p_ifc->GetBusData( p_ifc->Context, + PCI_WHICHSPACE_CONFIG, &data, 0, 4)) { + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, + ("Failed to read device configuration data. Card reset failed !\n")); + status = STATUS_UNSUCCESSFUL; + break; + } + /* See if we got valid data. */ + if( data != 0xFFFFFFFF ) { + reset_failed = 0; + break; + } + + cl_thread_suspend( 100 ); + } + + if (reset_failed) { + /* on Tavor reset failure, if configured so, we disable the reset for next time */ + if (is_tavor && g_disable_tavor_reset) + set_skip_tavor_reset(); + + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, + ("Doh! PCI device did not come back after reset!\n")); + status = STATUS_UNSUCCESSFUL; + goto resetErr3; + } + } + + /* restore the HCA's PCI configuration headers */ + { + if (is_tavor) { + /* Restore the HCA's bridge configuration. */ + HCA_PRINT( TRACE_LEVEL_INFORMATION ,HCA_DBG_PNP ,("Restoring bridge PCI configuration \n")); + status = __restore_pci_config( &brBusIfc, &brConfig, TRUE ); + if( !NT_SUCCESS( status ) ) { + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, + ("Failed to restore bridge config. Card reset failed !\n")); + goto resetErr3; + } + } + + /* Restore the HCA's configuration. */ + HCA_PRINT( TRACE_LEVEL_INFORMATION ,HCA_DBG_PNP ,("Restoring HCA PCI configuration \n")); + status = __restore_pci_config( &hcaBusIfc, &hcaConfig, FALSE ); + if( !NT_SUCCESS( status ) ) { + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, + ("Failed to restore HCA config. Card reset failed !\n")); + } + } + +resetErr3: + if (is_tavor) + brBusIfc.InterfaceDereference( brBusIfc.Context ); + +resetErr2: + hcaBusIfc.InterfaceDereference( hcaBusIfc.Context ); + +resetErr1: +resetExit: + HCA_EXIT( HCA_DBG_PNP ); + return status; +} + + +/* + * Tunes PCI configuration as described in 13.3.2 in the Tavor PRM. + */ +NTSTATUS +hca_tune_pci( + IN DEVICE_OBJECT* const pDevObj, + OUT uplink_info_t *p_uplink_info ) +{ + NTSTATUS status; + PCI_COMMON_CONFIG hcaConfig; + BUS_INTERFACE_STANDARD hcaBusIfc; + ULONG len; + ULONG capOffset; + PCI_PCIX_CAPABILITY *pPciXCap; + PCI_PCIEXP_CAPABILITY *pPciExpCap; + + HCA_ENTER( HCA_DBG_PNP ); + + /* Get the HCA's bus interface. */ + status = __get_bus_ifc( pDevObj, &GUID_BUS_INTERFACE_STANDARD, &hcaBusIfc ); + if( !NT_SUCCESS( status ) ) + { + HCA_PRINT( TRACE_LEVEL_ERROR ,HCA_DBG_PNP ,("Failed to get HCA bus interface.\n")); + return status; + } + + /* Save the HCA's configuration. */ + status = __save_pci_config( &hcaBusIfc, &hcaConfig ); + if( !NT_SUCCESS( status ) ) + { + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, + ("Failed to save HCA config.\n")); + status = STATUS_UNSUCCESSFUL; + goto tweakErr; + } + status = 0; + + /* + * PCIX Capability + */ + capOffset = __FindCapability( &hcaConfig, PCI_CAPABILITY_ID_PCIX ); + if( capOffset ) + { + pPciXCap = (PCI_PCIX_CAPABILITY*)(((UCHAR*)&hcaConfig) + capOffset); + + /* fill uplink features */ + p_uplink_info->bus_type = UPLINK_BUS_PCIX; + if (pPciXCap->Status & (1 << 17)) + p_uplink_info->u.pci_x.capabilities = UPLINK_BUS_PCIX_133; + + /* Update the command field to max the read byte count if needed. */ + if ( g_tune_pci && (pPciXCap->Command & 0x000C) != 0x000C ) + { + HCA_PRINT( TRACE_LEVEL_WARNING, HCA_DBG_PNP, + ("Updating max recv byte count of PCI-X capability.\n")); + pPciXCap->Command = (pPciXCap->Command & ~PCI_X_CMD_MAX_READ) | (3 << 2); + len = hcaBusIfc.SetBusData( hcaBusIfc.Context, PCI_WHICHSPACE_CONFIG, + &pPciXCap->Command, + capOffset + offsetof( PCI_PCIX_CAPABILITY, Command), + sizeof( pPciXCap->Command ) ); + if( len != sizeof( pPciXCap->Command ) ) + { + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, + ("Failed to update PCI-X maximum read byte count.\n")); + status = STATUS_UNSUCCESSFUL; + goto tweakErr; + } + } + } + + + /* + * PCI Express Capability + */ + capOffset = __FindCapability( &hcaConfig, PCI_CAPABILITY_ID_PCIEXP ); + if( capOffset ) + { + pPciExpCap = (PCI_PCIEXP_CAPABILITY*)(((UCHAR*)&hcaConfig) + capOffset); + + /* fill uplink features */ + p_uplink_info->bus_type = UPLINK_BUS_PCIE; + if ((pPciExpCap->LinkStatus & 15) == 1) + p_uplink_info->u.pci_e.link_speed = UPLINK_BUS_PCIE_SDR; + if ((pPciExpCap->LinkStatus & 15) == 2) + p_uplink_info->u.pci_e.link_speed = UPLINK_BUS_PCIE_DDR; + p_uplink_info->u.pci_e.link_width = (uint8_t)((pPciExpCap->LinkStatus >> 4) & 0x03f); + p_uplink_info->u.pci_e.capabilities = (uint8_t)((pPciExpCap->LinkCapabilities >> 2) & 0xfc); + p_uplink_info->u.pci_e.capabilities |= pPciExpCap->LinkCapabilities & 3; + + if (g_tune_pci) { + /* Update Max_Read_Request_Size. */ + HCA_PRINT( TRACE_LEVEL_WARNING ,HCA_DBG_PNP, + ("Updating max recv byte count of PCI-Express capability.\n")); + pPciExpCap->DevControl = (pPciExpCap->DevControl & ~PCI_EXP_DEVCTL_READRQ) | (5 << 12); + len = hcaBusIfc.SetBusData( hcaBusIfc.Context, PCI_WHICHSPACE_CONFIG, + &pPciExpCap->DevControl, + capOffset + offsetof( PCI_PCIEXP_CAPABILITY, DevControl), + sizeof( pPciExpCap->DevControl ) ); + if( len != sizeof( pPciExpCap->DevControl ) ) + { + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, + ("Failed to update PCI-Exp maximum read byte count.\n")); + goto tweakErr; + } + } + } + + +tweakErr: + hcaBusIfc.InterfaceDereference( hcaBusIfc.Context ); + + HCA_EXIT( HCA_DBG_PNP ); + return status; +} + + +/* leo */ + +NTSTATUS +hca_enable_pci( + IN DEVICE_OBJECT* const pDevObj, + OUT PBUS_INTERFACE_STANDARD phcaBusIfc, + OUT PCI_COMMON_CONFIG* pHcaConfig + ) +{ + NTSTATUS status; + ULONG len; + + HCA_ENTER( HCA_DBG_PNP ); + + /* Get the HCA's bus interface. */ + status = __get_bus_ifc( pDevObj, &GUID_BUS_INTERFACE_STANDARD, phcaBusIfc ); + if( !NT_SUCCESS( status ) ) + { + HCA_PRINT( TRACE_LEVEL_ERROR , HCA_DBG_PNP ,("Failed to get HCA bus interface.\n")); + return STATUS_DEVICE_NOT_READY; + } + + /* Save the HCA's configuration. */ + status = __save_pci_config( phcaBusIfc, pHcaConfig ); + if( !NT_SUCCESS( status ) ) + { + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, + ("Failed to save HCA config.\n")); + goto pciErr; + } + + /* fix command register (set PCI Master bit) */ + // NOTE: we change here the saved value of the command register + pHcaConfig->Command |= 7; + len = phcaBusIfc->SetBusData( phcaBusIfc->Context, PCI_WHICHSPACE_CONFIG, + (PVOID)&pHcaConfig->Command , 4, sizeof(ULONG) ); + if( len != sizeof(ULONG) ) + { + HCA_PRINT( TRACE_LEVEL_ERROR ,HCA_DBG_PNP ,("Failed to write command register.\n")); + status = STATUS_DEVICE_NOT_READY; + goto pciErr; + } + status = STATUS_SUCCESS; + goto out; + + pciErr: + phcaBusIfc->InterfaceDereference( phcaBusIfc->Context ); + phcaBusIfc->InterfaceDereference = NULL; + out: + HCA_EXIT( HCA_DBG_PNP ); + return status; +} + +void hca_disable_pci(PBUS_INTERFACE_STANDARD phcaBusIfc) +{ + // no need to disable the card, so just release the PCI bus i/f + if (phcaBusIfc->InterfaceDereference) { + phcaBusIfc->InterfaceDereference( phcaBusIfc->Context ); + phcaBusIfc->InterfaceDereference = NULL; + } +} + diff --git a/branches/WOF2-3/hw/mthca/kernel/hca_pci.h b/branches/WOF2-3/hw/mthca/kernel/hca_pci.h new file mode 100644 index 00000000..dd8e9c0e --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/hca_pci.h @@ -0,0 +1,24 @@ +#ifndef HCI_PCI_H +#define HCI_PCI_H + + +NTSTATUS +hca_reset( + IN DEVICE_OBJECT* const pDevObj, int is_tavor ); + +NTSTATUS +hca_enable_pci( + IN DEVICE_OBJECT* const pDevObj, + OUT PBUS_INTERFACE_STANDARD phcaBusIfc, + OUT PCI_COMMON_CONFIG* pHcaConfig + ); + +void hca_disable_pci( + IN PBUS_INTERFACE_STANDARD phcaBusIfc); + +NTSTATUS + hca_tune_pci( + IN DEVICE_OBJECT* const pDevObj, + OUT uplink_info_t *p_uplink_info ); + +#endif diff --git a/branches/WOF2-3/hw/mthca/kernel/hca_pnp.c b/branches/WOF2-3/hw/mthca/kernel/hca_pnp.c new file mode 100644 index 00000000..76978072 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/hca_pnp.c @@ -0,0 +1,1365 @@ +/* BEGIN_ICS_COPYRIGHT **************************************** +** END_ICS_COPYRIGHT ****************************************/ + +/* + $Revision: 1.1 $ +*/ + + +/* + * Provides the driver entry points for the Tavor VPD. + */ + +#include "hca_driver.h" +#include "mthca_dev.h" +#include + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "hca_pnp.tmh" +#endif +#include "mthca.h" +#include +#include + +extern const char *mthca_version; +hca_dev_ext_t *g_ext = NULL; + +static NTSTATUS +hca_start( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +hca_query_stop( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +hca_stop( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +hca_cancel_stop( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +hca_query_remove( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static void +hca_release_resources( + IN DEVICE_OBJECT* const p_dev_obj ); + +static NTSTATUS +hca_cancel_remove( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +hca_surprise_remove( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +hca_query_capabilities( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +hca_query_pnp_state( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +hca_query_bus_relations( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +hca_query_removal_relations( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +hca_query_power( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +hca_set_power( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static ci_interface_t* +__alloc_hca_ifc( + IN hca_dev_ext_t* const p_ext ); + +static NTSTATUS +hca_query_interface( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static NTSTATUS +__get_ci_interface( + IN DEVICE_OBJECT* const p_dev_obj ); + + + +static cl_vfptr_pnp_po_t vfptrHcaPnp; + + +void +hca_init_vfptr( void ) +{ + vfptrHcaPnp.identity = "HCA driver"; + vfptrHcaPnp.pfn_start = hca_start; + vfptrHcaPnp.pfn_query_stop = hca_query_stop; + vfptrHcaPnp.pfn_stop = hca_stop; + vfptrHcaPnp.pfn_cancel_stop = hca_cancel_stop; + vfptrHcaPnp.pfn_query_remove = hca_query_remove; + vfptrHcaPnp.pfn_release_resources = hca_release_resources; + vfptrHcaPnp.pfn_remove = cl_do_remove; + vfptrHcaPnp.pfn_cancel_remove = hca_cancel_remove; + vfptrHcaPnp.pfn_surprise_remove = hca_surprise_remove; + vfptrHcaPnp.pfn_query_capabilities = hca_query_capabilities; + vfptrHcaPnp.pfn_query_pnp_state = hca_query_pnp_state; + vfptrHcaPnp.pfn_filter_res_req = cl_irp_skip; + vfptrHcaPnp.pfn_dev_usage_notification = cl_do_sync_pnp; + vfptrHcaPnp.pfn_query_bus_relations = cl_irp_ignore; + vfptrHcaPnp.pfn_query_ejection_relations = cl_irp_ignore; + vfptrHcaPnp.pfn_query_removal_relations = cl_irp_ignore; + vfptrHcaPnp.pfn_query_target_relations = cl_irp_ignore; + vfptrHcaPnp.pfn_unknown = cl_irp_ignore; + vfptrHcaPnp.pfn_query_resources = cl_irp_ignore; + vfptrHcaPnp.pfn_query_res_req = cl_irp_ignore; + vfptrHcaPnp.pfn_query_bus_info = cl_irp_ignore; + vfptrHcaPnp.pfn_query_interface = hca_query_interface; + vfptrHcaPnp.pfn_read_config = cl_irp_ignore; + vfptrHcaPnp.pfn_write_config = cl_irp_ignore; + vfptrHcaPnp.pfn_eject = cl_irp_ignore; + vfptrHcaPnp.pfn_set_lock = cl_irp_ignore; + vfptrHcaPnp.pfn_query_power = hca_query_power; + vfptrHcaPnp.pfn_set_power = hca_set_power; + vfptrHcaPnp.pfn_power_sequence = cl_irp_ignore; + vfptrHcaPnp.pfn_wait_wake = cl_irp_ignore; +} + + +NTSTATUS +hca_add_device( + IN PDRIVER_OBJECT pDriverObj, + IN PDEVICE_OBJECT pPdo ) +{ + NTSTATUS status; + DEVICE_OBJECT *p_dev_obj, *pNextDevObj; + hca_dev_ext_t *p_ext; + + HCA_ENTER(HCA_DBG_PNP); + + /* + * Create the device so that we have a device extension to store stuff in. + */ + status = IoCreateDevice( pDriverObj, sizeof(hca_dev_ext_t), + NULL, FILE_DEVICE_INFINIBAND, FILE_DEVICE_SECURE_OPEN, + FALSE, &p_dev_obj ); + if( !NT_SUCCESS( status ) ) + { + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, + ("IoCreateDevice returned 0x%08X.\n", status)); + return status; + } + + p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension; + if (!g_ext) + g_ext = p_ext; + cl_memclr( p_ext, sizeof(hca_dev_ext_t) ); + cl_spinlock_init( &p_ext->uctx_lock ); + cl_qlist_init( &p_ext->uctx_list ); + atomic_set(&p_ext->usecnt, 0); + + /* Attach to the device stack. */ + pNextDevObj = IoAttachDeviceToDeviceStack( p_dev_obj, pPdo ); + if( !pNextDevObj ) + { + //cl_event_destroy( &p_ext->mutex ); + IoDeleteDevice( p_dev_obj ); + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, + ("IoAttachDeviceToDeviceStack failed.\n")); + return STATUS_NO_SUCH_DEVICE; + } + + /* Inititalize the complib extension. */ + cl_init_pnp_po_ext( p_dev_obj, pNextDevObj, pPdo, CL_DBG_PNP | CL_DBG_ERROR, + &vfptrHcaPnp, NULL ); + + p_ext->state = HCA_ADDED; + + HCA_EXIT(HCA_DBG_PNP); + return status; +} + + +static ci_interface_t* +__alloc_hca_ifc( + IN hca_dev_ext_t* const p_ext ) +{ + ci_interface_t *pIfc; + + HCA_ENTER( HCA_DBG_PNP ); + + pIfc = (ci_interface_t*)ExAllocatePoolWithTag( NonPagedPool, + sizeof(ci_interface_t), + 'pnpa' ); + if( !pIfc ) + { + HCA_PRINT( TRACE_LEVEL_ERROR,HCA_DBG_PNP, + ("Failed to allocate ci_interface_t (%d bytes).\n", + sizeof(ci_interface_t))); + return NULL; + } + + setup_ci_interface( p_ext->hca.guid, pIfc ); + + pIfc->p_hca_obj = &p_ext->hca.hob; + pIfc->vend_id = (uint32_t)p_ext->hcaConfig.VendorID; + pIfc->dev_id = (uint16_t)p_ext->hcaConfig.DeviceID; + pIfc->dev_revision = (uint16_t)p_ext->hca.hw_ver; + + HCA_EXIT( HCA_DBG_PNP ); + return pIfc; +} + + +/* + * Walk the resource lists and store the information. The write-only + * flag is not set for the UAR region, so it is indistinguishable from the + * DDR region since both are prefetchable. The code here assumes that the + * resources get handed in order - HCR, UAR, DDR. + * - Configuration Space: not prefetchable, read/write + * - UAR space: prefetchable, write only. + * - DDR: prefetchable, read/write. + */ +static NTSTATUS +__SetupHcaResources( + IN DEVICE_OBJECT* const p_dev_obj, + IN CM_RESOURCE_LIST* const pHcaResList, + IN CM_RESOURCE_LIST* const pHostResList ) +{ + NTSTATUS status = STATUS_SUCCESS; + hca_dev_ext_t *p_ext; + USHORT i; + hca_bar_type_t type = HCA_BAR_TYPE_HCR; + + CM_PARTIAL_RESOURCE_DESCRIPTOR *pHcaRes, *pHostRes; + + HCA_ENTER( HCA_DBG_PNP ); + + p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension; + + // store the bus number for reset of Tavor + p_ext->bus_number = pHostResList->List[0].BusNumber; + + for( i = 0; i < pHostResList->List[0].PartialResourceList.Count; i++ ) + { + pHcaRes = + &pHcaResList->List[0].PartialResourceList.PartialDescriptors[i]; + pHostRes = + &pHostResList->List[0].PartialResourceList.PartialDescriptors[i]; + + + /* + * Save the interrupt information so that we can power the device + * up and down. Since the device will lose state when powered down + * we have to fully disable it. Note that we can leave memory mapped + * resources in place when powered down as the resource assignments + * won't change. However, we must disconnect our interrupt, and + * reconnect it when powering up. + */ + if( pHcaRes->Type == CmResourceTypeInterrupt ) + { + p_ext->interruptInfo = *pHostRes; + if ( g_processor_affinity == 0xFFFFFFFF ) + { + /* + * Calculate the mask of the last processor + */ + KAFFINITY n_active_processors_bitmask; + uint32_t last_processor_mask = 0 , tmp_processor_mask = 1; + + n_active_processors_bitmask = KeQueryActiveProcessors(); + while ( tmp_processor_mask & n_active_processors_bitmask ) + { + last_processor_mask = tmp_processor_mask; + tmp_processor_mask = tmp_processor_mask << 1; + } + p_ext->interruptInfo.u.Interrupt.Affinity = last_processor_mask; + } + else if (g_processor_affinity != 0) + { + p_ext->interruptInfo.u.Interrupt.Affinity = g_processor_affinity; + } + HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PNP,("Set Interrupt affinity to : 0x%08X\n", + (int)p_ext->interruptInfo.u.Interrupt.Affinity )); + + continue; + } + + if( pHcaRes->Type != CmResourceTypeMemory ) + continue; + + /* + * Sanity check that our assumption on how resources + * are reported hold. + */ + if( type == HCA_BAR_TYPE_HCR && + (pHcaRes->Flags & CM_RESOURCE_MEMORY_PREFETCHABLE) ) + { + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, + ("First memory resource is prefetchable - expected HCR.\n")); + status = STATUS_UNSUCCESSFUL; + break; + } + + p_ext->bar[type].phys = pHcaRes->u.Memory.Start.QuadPart; + p_ext->bar[type].size = pHcaRes->u.Memory.Length; +#ifdef MAP_ALL_HCA_MEMORY + /*leo: no need to map all the resources */ + p_ext->bar[type].virt = MmMapIoSpace( pHostRes->u.Memory.Start, + pHostRes->u.Memory.Length, MmNonCached ); + if( !p_ext->bar[type].virt ) + { + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, + ("Failed to map memory resource type %d\n", type)); + status = STATUS_UNSUCCESSFUL; + break; + } +#else + p_ext->bar[type].virt = NULL; +#endif + + type++; + } + + if( type == HCA_BAR_TYPE_DDR) + { + p_ext->hca_hidden = 1; + } + else + if( type != HCA_BAR_TYPE_MAX ) + { + HCA_PRINT( TRACE_LEVEL_ERROR ,HCA_DBG_SHIM ,("Failed to map all memory resources.\n")); + status = STATUS_UNSUCCESSFUL; + } + + if( p_ext->interruptInfo.Type != CmResourceTypeInterrupt ) + { + HCA_PRINT( TRACE_LEVEL_ERROR ,HCA_DBG_SHIM ,("No interrupt resource.\n")); + status = STATUS_UNSUCCESSFUL; + } + + HCA_EXIT( HCA_DBG_PNP ); + return status; +} + + +static void +__UnmapHcaMemoryResources( + IN DEVICE_OBJECT* const p_dev_obj ) +{ + hca_dev_ext_t *p_ext; + USHORT i; + + HCA_ENTER( HCA_DBG_PNP ); + + p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension; + + for( i = 0; i < HCA_BAR_TYPE_MAX; i++ ) + { + if( p_ext->bar[i].virt ) + { + MmUnmapIoSpace( p_ext->bar[i].virt, p_ext->bar[i].size ); + cl_memclr( &p_ext->bar[i], sizeof(hca_bar_t) ); + } + } + + HCA_EXIT( HCA_DBG_PNP ); +} + + +static NTSTATUS +hca_start( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + NTSTATUS status; + hca_dev_ext_t *p_ext; + IO_STACK_LOCATION *pIoStack; + POWER_STATE powerState; + DEVICE_DESCRIPTION devDesc; + int err; + + HCA_ENTER( HCA_DBG_PNP ); + + p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension; + + /* Handled on the way up. */ + status = cl_do_sync_pnp( p_dev_obj, p_irp, p_action ); + if( !NT_SUCCESS( status ) ) + { + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, + ("Lower drivers failed IRP_MN_START_DEVICE (%#x).\n", status)); + return status; + } + + pIoStack = IoGetCurrentIrpStackLocation( p_irp ); + + /* + * Walk the resource lists and store the information. The write-only + * flag is not set for the UAR region, so it is indistinguishable from the + * DDR region since both are prefetchable. The code here assumes that the + * resources get handed in order - HCR, UAR, DDR. + * - Configuration Space: not prefetchable, read/write + * - UAR space: prefetchable, write only. + * - DDR: prefetchable, read/write. + */ + status = __SetupHcaResources( p_dev_obj, + pIoStack->Parameters.StartDevice.AllocatedResources, + pIoStack->Parameters.StartDevice.AllocatedResourcesTranslated ); + if( !NT_SUCCESS( status ) ) + { + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, + ("__ProcessResources returned %08X.\n", status)); + return status; + } + + /* save PCI bus i/f, PCI configuration info and enable device */ + hca_enable_pci( p_dev_obj, &p_ext->hcaBusIfc, &p_ext->hcaConfig ); + + /* + * Get the DMA adapter representing the HCA so we can + * allocate common buffers. + */ + RtlZeroMemory( &devDesc, sizeof(devDesc) ); + devDesc.Version = DEVICE_DESCRIPTION_VERSION2; + devDesc.Master = TRUE; + devDesc.ScatterGather = TRUE; + devDesc.Dma32BitAddresses = TRUE; + devDesc.Dma64BitAddresses = TRUE; + devDesc.InterfaceType = PCIBus; + + // get the adapter object + // 0x80000000 is a threshold, that's why - 1 + devDesc.MaximumLength = 0x80000000 - 1; + p_ext->p_dma_adapter = IoGetDmaAdapter( + p_ext->cl_ext.p_pdo, &devDesc, &p_ext->n_map_regs ); + if( !p_ext->p_dma_adapter ) + { + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, + ("Failed to get DMA_ADAPTER for HCA.\n")); + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* Initialize the HCA now. */ + status = mthca_init_one( p_ext ); + if( !NT_SUCCESS( status ) ) + { + //TODO: no cleanup on error + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, + ("mthca_init_one returned %08X\n", status)); + return status; + } + + err = mthca_get_dev_info( p_ext->hca.mdev, &p_ext->hca.guid, &p_ext->hca.hw_ver ); + if (err) { + + //TODO: no cleanup on error + HCA_PRINT( TRACE_LEVEL_ERROR,HCA_DBG_PNP, + ("can't get guid - mthca_query_port()")); + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* queue HCA */ + mlnx_hca_insert( &p_ext->hca ); + + /* + * Change the state since the PnP callback can happen + * before the callback returns. + */ + p_ext->state = HCA_STARTED; + + /* We get started fully powered. */ + p_ext->DevicePowerState = PowerDeviceD0; + powerState.DeviceState = PowerDeviceD0; + powerState = PoSetPowerState ( p_ext->cl_ext.p_self_do, DevicePowerState, powerState ); + HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PNP, + ("PoSetPowerState: old state %d, new state to %d\n", + powerState.DeviceState, p_ext->DevicePowerState )); + + + { + struct mthca_dev *mdev = p_ext->hca.mdev; + HCA_PRINT_EV(TRACE_LEVEL_INFORMATION ,HCA_DBG_LOW , + ("Ven %x Dev %d Hw %x Fw %d.%d.%d Drv %s (%s)", + (unsigned)p_ext->hcaConfig.VendorID, (unsigned)p_ext->hcaConfig.DeviceID, + p_ext->hca.hw_ver, (int) (mdev->fw_ver >> 32), + (int) (mdev->fw_ver >> 16) & 0xffff, (int) (mdev->fw_ver & 0xffff), + DRV_VERSION, DRV_RELDATE + )); + HCA_PRINT_EV(TRACE_LEVEL_INFORMATION ,HCA_DBG_LOW , + ("Flags %s%s%s%s%s%s\n", + (mdev->mthca_flags & MTHCA_FLAG_MEMFREE) ? "MemFree:" : "", + (mdev->mthca_flags & MTHCA_FLAG_NO_LAM) ? "NoLam:" : "", + (mdev->mthca_flags & MTHCA_FLAG_FMR) ? "Fmr:" : "", + (mdev->mthca_flags & MTHCA_FLAG_SRQ) ? "Srq:" : "", + (mdev->mthca_flags & MTHCA_FLAG_DDR_HIDDEN) ? "HideDdr:" : "", + (mdev->mthca_flags & MTHCA_FLAG_PCIE) ? "PciEx:" : "" + )); + } + + HCA_EXIT( HCA_DBG_PNP ); + return status; +} + + +/* release the resources, allocated in hca_start */ +static void +__hca_release_resources( + IN DEVICE_OBJECT* const p_dev_obj ) +{ + hca_dev_ext_t *p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension; + + HCA_ENTER( HCA_DBG_PNP ); + + switch( p_ext->state ) + { + case HCA_STARTED: + /* dequeue HCA */ + mlnx_hca_remove( &p_ext->hca ); + } + + if (p_ext->al_sym_name.Buffer) { + ExFreePool( p_ext->al_sym_name.Buffer ); + p_ext->al_sym_name.Buffer = NULL; + } + + if( p_ext->pnp_target_entry ) + { + ASSERT( p_ext->pnp_ifc_entry ); + IoUnregisterPlugPlayNotification( p_ext->pnp_target_entry ); + p_ext->pnp_target_entry = NULL; + } + + if( p_ext->pnp_ifc_entry ) { + IoUnregisterPlugPlayNotification( p_ext->pnp_ifc_entry ); + p_ext->pnp_ifc_entry = NULL; + } + + if( p_ext->p_al_file_obj ) { + ObDereferenceObject( p_ext->p_al_file_obj ); + p_ext->p_al_file_obj = NULL; + } + + mthca_remove_one( p_ext ); + + if( p_ext->p_dma_adapter ) { + p_ext->p_dma_adapter->DmaOperations->PutDmaAdapter( p_ext->p_dma_adapter ); + p_ext->p_dma_adapter = NULL; + } + + hca_disable_pci( &p_ext->hcaBusIfc ); + + //cl_event_destroy( &p_ext->mutex ); + __UnmapHcaMemoryResources( p_dev_obj ); + + p_ext->state = HCA_ADDED; + + HCA_EXIT( HCA_DBG_PNP ); +} + + +static void +hca_release_resources( + IN DEVICE_OBJECT* const p_dev_obj ) +{ + hca_dev_ext_t *p_ext; + POWER_STATE powerState; + + HCA_ENTER( HCA_DBG_PNP ); + + p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension; + + /* release all the resources, allocated in hca_start */ + __hca_release_resources(p_dev_obj); + + /* Notify the power manager that the device is powered down. */ + p_ext->DevicePowerState = PowerDeviceD3; + powerState.DeviceState = PowerDeviceD3; + powerState = PoSetPowerState ( p_ext->cl_ext.p_self_do, DevicePowerState, powerState ); + + HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PNP, + ("PoSetPowerState: old state %d, new state to %d\n", + powerState.DeviceState, p_ext->DevicePowerState )); + + + /* Clear the PnP state in case we get restarted. */ + p_ext->pnpState = 0; + + HCA_EXIT( HCA_DBG_PNP ); +} + + +static NTSTATUS +hca_query_stop( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + /* All kernel clients will get notified through the device hierarchy. */ + + /* TODO: set a flag to fail creation of any new IB resources. */ + return cl_irp_skip( p_dev_obj, p_irp, p_action ); +} + + +static NTSTATUS +hca_stop( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + /* + * Must disable everything. Complib framework will + * call ReleaseResources handler. + */ + return cl_irp_skip( p_dev_obj, p_irp, p_action ); +} + + +static NTSTATUS +hca_cancel_stop( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + /* Handled on the way up. */ + return cl_do_sync_pnp( p_dev_obj, p_irp, p_action ); +} + + +static NTSTATUS +hca_query_remove( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + hca_dev_ext_t*p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension; + if (atomic_read(&p_ext->usecnt)) { + cl_dbg_out( "MTHCA: Can't get unloaded. %d applications are still in work\n", p_ext->usecnt); + p_irp->IoStatus.Status = STATUS_UNSUCCESSFUL; + return cl_irp_complete( p_dev_obj, p_irp, p_action ); + } + /* TODO: set a flag to fail creation of any new IB resources. */ + return cl_irp_skip( p_dev_obj, p_irp, p_action ); +} + + +static NTSTATUS +hca_cancel_remove( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + /* Handled on the way up. */ + return cl_do_sync_pnp( p_dev_obj, p_irp, p_action ); +} + + +static NTSTATUS +hca_surprise_remove( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + /* + * TODO: Set state so that all further requests + * automatically succeed/fail as needed. + */ + return cl_irp_skip( p_dev_obj, p_irp, p_action ); +} + + +static NTSTATUS +hca_query_capabilities( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + NTSTATUS status; + hca_dev_ext_t *p_ext; + IO_STACK_LOCATION *pIoStack; + DEVICE_CAPABILITIES *pCaps; + + HCA_ENTER( HCA_DBG_PNP ); + + p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension; + + /* Process on the way up. */ + status = cl_do_sync_pnp( p_dev_obj, p_irp, p_action ); + if( !NT_SUCCESS( status ) ) + { + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, + ("cl_do_sync_pnp returned %08X.\n", status)); + return status; + } + + pIoStack = IoGetCurrentIrpStackLocation( p_irp ); + pCaps = pIoStack->Parameters.DeviceCapabilities.Capabilities; + + /* + * Store the device power mapping into our extension since we're + * the power policy owner. The mapping is used when handling + * IRP_MN_SET_POWER IRPs. + */ + cl_memcpy( + p_ext->DevicePower, pCaps->DeviceState, sizeof(p_ext->DevicePower) ); + + if( pCaps->DeviceD1 ) + { + HCA_PRINT( TRACE_LEVEL_WARNING ,HCA_DBG_PNP, + ("WARNING: Device reports support for DeviceD1 power state.\n")); + pCaps->DeviceD1 = FALSE; + } + + if( pCaps->DeviceD2 ) + { + HCA_PRINT( TRACE_LEVEL_WARNING,HCA_DBG_PNP, + ("WARNING: Device reports support for DeviceD2 power state.\n")); + pCaps->DeviceD2 = FALSE; + } + + if( pCaps->SystemWake != PowerSystemUnspecified ) + { + HCA_PRINT( TRACE_LEVEL_WARNING ,HCA_DBG_PNP, + ("WARNING: Device reports support for system wake.\n")); + pCaps->SystemWake = PowerSystemUnspecified; + } + + if( pCaps->DeviceWake != PowerDeviceUnspecified ) + { + HCA_PRINT( TRACE_LEVEL_WARNING, HCA_DBG_PNP, + ("WARNING: Device reports support for device wake.\n")); + pCaps->DeviceWake = PowerDeviceUnspecified; + } + + HCA_EXIT( HCA_DBG_PNP ); + return status; +} + +static void +__ref_ifc( + IN DEVICE_OBJECT* p_dev_obj ) +{ + hca_dev_ext_t *p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension; + + HCA_ENTER( HCA_DBG_PNP ); + + cl_atomic_inc( &p_ext->n_hca_ifc_ref ); + ObReferenceObject( p_dev_obj ); + + HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PNP, + ("MTHCA: CA_guid %I64x, hca_ifc_ref %d\n", + p_ext->hca.guid, p_ext->n_hca_ifc_ref) ); + + HCA_EXIT( HCA_DBG_PNP ); +} + +static void +__deref_ifc( + IN DEVICE_OBJECT* p_dev_obj ) +{ + hca_dev_ext_t *p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension; + + HCA_ENTER( HCA_DBG_PNP ); + + cl_atomic_dec( &p_ext->n_hca_ifc_ref ); + ObDereferenceObject( p_dev_obj ); + + HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PNP, + ("MTHCA: CA_guid %I64x, hca_ifc_ref %d\n", + p_ext->hca.guid, p_ext->n_hca_ifc_ref) ); + + HCA_EXIT( HCA_DBG_PNP ); +} + +static NTSTATUS +__query_ci_ifc( + IN DEVICE_OBJECT* const p_dev_obj, + IN IO_STACK_LOCATION* const p_io_stack ) +{ + RDMA_INTERFACE_VERBS *p_ifc; + hca_dev_ext_t *p_ext; + ci_interface_t *p_hca_ifc; + NTSTATUS status; + UINT8 version; + + HCA_ENTER( HCA_DBG_PNP ); + + version = VerbsVersionMajor(p_io_stack->Parameters.QueryInterface.Version); + if( version > VERBS_MAJOR_VER ) + { + status = STATUS_NOT_SUPPORTED; + goto exit; + } + + if( p_io_stack->Parameters.QueryInterface.Size < sizeof(RDMA_INTERFACE_VERBS) ) + { + status = STATUS_BUFFER_TOO_SMALL; + goto exit; + } + + p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension; + p_hca_ifc = __alloc_hca_ifc( p_ext ); + if( !p_hca_ifc ) + { + status = STATUS_NO_MEMORY; + goto exit; + } + + p_ifc = (RDMA_INTERFACE_VERBS *) p_io_stack->Parameters.QueryInterface.Interface; + + p_ifc->InterfaceHeader.Size = sizeof(RDMA_INTERFACE_VERBS); + p_ifc->InterfaceHeader.Version = VerbsVersion(VERBS_MAJOR_VER, VERBS_MINOR_VER); + p_ifc->InterfaceHeader.Context = p_dev_obj; + p_ifc->InterfaceHeader.InterfaceReference = __ref_ifc; + p_ifc->InterfaceHeader.InterfaceDereference = __deref_ifc; + p_ifc->Verbs = *p_hca_ifc; + + /* take the reference before returning. */ + __ref_ifc( p_dev_obj ); + + ExFreePool( p_hca_ifc ); + status = STATUS_SUCCESS; + +exit: + HCA_EXIT( HCA_DBG_PNP ); + return status; +} + + +static NTSTATUS +hca_query_interface( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + NTSTATUS status; + IO_STACK_LOCATION *p_io_stack; + + HCA_ENTER( HCA_DBG_PNP ); + +#pragma warning( push, 3 ) + PAGED_CODE(); +#pragma warning( pop ) + + p_io_stack = IoGetCurrentIrpStackLocation( p_irp ); + + /* Compare requested GUID with our supported interface GUIDs. */ + if( IsEqualGUID( p_io_stack->Parameters.QueryInterface.InterfaceType, + &GUID_RDMA_INTERFACE_VERBS ) ) + { + status = __query_ci_ifc( p_dev_obj, p_io_stack ); + if( !NT_SUCCESS( status ) ) + { + *p_action = IrpComplete; + } + else + { + *p_action = IrpSkip; + } + } + else + { + status = p_irp->IoStatus.Status; + *p_action = IrpSkip; + } + + HCA_EXIT( HCA_DBG_PNP ); + return status; +} + + +static NTSTATUS +hca_query_pnp_state( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + hca_dev_ext_t *p_ext; + + HCA_ENTER( HCA_DBG_PNP ); + + p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension; + + p_irp->IoStatus.Information |= p_ext->pnpState; + + *p_action = IrpSkip; + + HCA_EXIT( HCA_DBG_PNP ); + return STATUS_SUCCESS;; +} + +static NTSTATUS +hca_query_power( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + NTSTATUS status = STATUS_SUCCESS; + IO_STACK_LOCATION *pIoStack; + + HCA_ENTER(HCA_DBG_PO); + + UNUSED_PARAM( p_dev_obj ); + + pIoStack = IoGetCurrentIrpStackLocation( p_irp ); + + HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PO, + ("QUERY_POWER for FDO %p: type %s, state %d, action %d, IRQL %d, IRP %p\n", + p_dev_obj, + (pIoStack->Parameters.Power.Type) ? "DevicePowerState" : "SystemPowerState", + pIoStack->Parameters.Power.State.DeviceState, + pIoStack->Parameters.Power.ShutdownType, KeGetCurrentIrql(), p_irp )); + + switch( pIoStack->Parameters.Power.Type ) + { + case SystemPowerState: + /* Fail any requests to hibernate or sleep the system. */ + switch( pIoStack->Parameters.Power.State.SystemState ) + { + case PowerSystemSleeping1: // STANDBY support + case PowerSystemSleeping2: // STANDBY support + case PowerSystemSleeping3: // STANDBY support + case PowerSystemHibernate: + { + hca_dev_ext_t*p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension; + if (atomic_read(&p_ext->usecnt)) + status = STATUS_UNSUCCESSFUL; + break; + } + + case PowerSystemWorking: + case PowerSystemShutdown: + break; + + default: + status = STATUS_NOT_SUPPORTED; + } + break; + + case DevicePowerState: + /* Fail any query for low power states. */ + switch( pIoStack->Parameters.Power.State.DeviceState ) + { + case PowerDeviceD0: + case PowerDeviceD3: + /* We only support fully powered or off power states. */ + break; + + default: + status = STATUS_NOT_SUPPORTED; + } + break; + } + + if( status == STATUS_SUCCESS ) + *p_action = IrpSkip; + else + *p_action = IrpComplete; + + HCA_EXIT( HCA_DBG_PO ); + return status; +} + + +static void +__RequestPowerCompletion( + IN DEVICE_OBJECT *p_dev_obj, + IN UCHAR minorFunction, + IN POWER_STATE powerState, + IN void *context, + IN IO_STATUS_BLOCK *pIoStatus ) +{ + IRP *p_irp; + cl_pnp_po_ext_t *p_ext; + + HCA_ENTER( HCA_DBG_PO ); + + UNUSED_PARAM( minorFunction ); + UNUSED_PARAM( powerState ); + + p_irp = (IRP*)context; + p_ext = (cl_pnp_po_ext_t*)p_dev_obj->DeviceExtension; + + /* Propagate the device IRP status to the system IRP status. */ + p_irp->IoStatus.Status = pIoStatus->Status; + + /* Continue Power IRP processing. */ + PoStartNextPowerIrp( p_irp ); + IoCompleteRequest( p_irp, IO_NO_INCREMENT ); + IoReleaseRemoveLock( &p_ext->remove_lock, p_irp ); + HCA_EXIT( HCA_DBG_PO ); +} + + +/*NOTE: Completion routines must NEVER be pageable. */ +static NTSTATUS +__SystemPowerCompletion( + IN DEVICE_OBJECT *p_dev_obj, + IN IRP *p_irp, + IN void *context ) +{ + NTSTATUS status; + POWER_STATE state; + hca_dev_ext_t *p_ext; + IO_STACK_LOCATION *pIoStack; + + HCA_ENTER( HCA_DBG_PO ); + + UNUSED_PARAM( context ); + + p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension; + pIoStack = IoGetCurrentIrpStackLocation( p_irp ); + + if( !NT_SUCCESS( p_irp->IoStatus.Status ) ) + { + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PO, + ("IRP_MN_SET_POWER for system failed by lower driver with %08x.\n", + p_irp->IoStatus.Status)); + status = STATUS_SUCCESS; + PoStartNextPowerIrp( p_irp ); + goto release; + } + + state.DeviceState = + p_ext->DevicePower[pIoStack->Parameters.Power.State.SystemState]; + + /* + * Send a device power IRP to our devnode. Using our device object will + * only work on win2k and other NT based systems. + */ + status = PoRequestPowerIrp( p_dev_obj, IRP_MN_SET_POWER, state, + __RequestPowerCompletion, p_irp, NULL ); + + HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PO, + ("PoRequestPowerIrp: SET_POWER 'PowerDeviceD%d', status %#x\n", + state.DeviceState - 1, status )); + + if( status != STATUS_PENDING ) { + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PO, + ("PoRequestPowerIrp returned %08x.\n", status)); + p_irp->IoStatus.Status = status; /* Propagate the failure. */ + PoStartNextPowerIrp( p_irp ); + IoCompleteRequest( p_irp, IO_NO_INCREMENT ); + goto release; + } + + status = STATUS_MORE_PROCESSING_REQUIRED; + goto exit; + +release: + IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp ); +exit: + HCA_EXIT( HCA_DBG_PO ); + return status; +} + + +/* Work item callback to handle DevicePowerD0 IRPs at passive level. */ +static void +__DevicePowerUpCompletionWorkItem( + IN DEVICE_OBJECT* p_dev_obj, + IN void* context ) +{ + NTSTATUS status; + IO_STACK_LOCATION *pIoStack; + hca_dev_ext_t *p_ext; + IRP *p_irp; + POWER_STATE powerState; + + HCA_ENTER( HCA_DBG_PO ); + + p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension; + p_irp = (IRP*)context; + pIoStack = IoGetCurrentIrpStackLocation( p_irp ); + + IoFreeWorkItem( p_ext->pPoWorkItem ); + p_ext->pPoWorkItem = NULL; + + /* restart the HCA */ + HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PO, + ("***** Restart the HCA, IRQL %d\n", KeGetCurrentIrql())); + + status = mthca_init_one( p_ext ); + if( !NT_SUCCESS( status ) ) { + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PO, + ("!!! mthca_init_one failed (%#x) \n", status)); + goto err_mthca_init; + } + + p_ext->DevicePowerState = pIoStack->Parameters.Power.State.DeviceState; + powerState = PoSetPowerState( p_dev_obj, DevicePowerState, + pIoStack->Parameters.Power.State ); + + HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PO, + ("PoSetPowerState: old state %d, new state to %d\n", + powerState.DeviceState, p_ext->DevicePowerState )); + + goto exit; + +err_mthca_init: + /* Flag device as having failed. */ + p_ext->pnpState |= PNP_DEVICE_FAILED; + IoInvalidateDeviceState( p_ext->cl_ext.p_pdo ); +exit: + PoStartNextPowerIrp( p_irp ); + IoCompleteRequest( p_irp, IO_NO_INCREMENT ); + IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp ); + HCA_EXIT( HCA_DBG_PO ); +} + +/*NOTE: Completion routines must NEVER be pageable. */ +static NTSTATUS +__DevicePowerUpCompletion( + IN DEVICE_OBJECT *p_dev_obj, + IN IRP *p_irp, + IN void *context ) +{ + NTSTATUS status = STATUS_SUCCESS; + hca_dev_ext_t *p_ext; + IO_STACK_LOCATION *pIoStack; + + HCA_ENTER( HCA_DBG_PO ); + + UNUSED_PARAM( context ); + + p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension; + pIoStack = IoGetCurrentIrpStackLocation( p_irp ); + + if( !NT_SUCCESS( p_irp->IoStatus.Status ) ) { + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PO, + ("IRP_MN_SET_POWER for device failed by lower driver with %08x.\n", + p_irp->IoStatus.Status)); + status = STATUS_SUCCESS; + PoStartNextPowerIrp( p_irp ); + goto release; + } + + /* Process in a work item - mthca_start blocks. */ + ASSERT( !p_ext->pPoWorkItem ); + p_ext->pPoWorkItem = IoAllocateWorkItem( p_dev_obj ); + if( !p_ext->pPoWorkItem ) { + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PO, + ("Failed to allocate work item.\n" )); + status = STATUS_SUCCESS; + p_ext->pnpState |= PNP_DEVICE_FAILED; + IoInvalidateDeviceState( p_ext->cl_ext.p_pdo ); + PoStartNextPowerIrp( p_irp ); + goto release; + } + + /* Process in work item callback. */ + IoMarkIrpPending( p_irp ); + IoQueueWorkItem( p_ext->pPoWorkItem, + __DevicePowerUpCompletionWorkItem, DelayedWorkQueue, p_irp ); + status = STATUS_MORE_PROCESSING_REQUIRED; + goto exit; + +release: + IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp ); +exit: + HCA_EXIT( HCA_DBG_PO ); + return status; +} + +static NTSTATUS __DevicePowerDownWorkItemCompletion( + IN DEVICE_OBJECT *p_dev_obj, + IN IRP *p_irp, + IN void *context ) +{ + hca_dev_ext_t *p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension; + UNUSED_PARAM( context ); + + HCA_ENTER( HCA_DBG_PO ); + + PoStartNextPowerIrp( p_irp ); + IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp ); + + HCA_EXIT( HCA_DBG_PO ); + return STATUS_SUCCESS; +} + +/* Work item callback to handle DevicePowerD3 IRPs at passive level. */ +static void +__DevicePowerDownWorkItem( + IN DEVICE_OBJECT* p_dev_obj, + IN void* context ) +{ + IO_STACK_LOCATION *pIoStack; + hca_dev_ext_t *p_ext; + IRP *p_irp; + POWER_STATE powerState; + + HCA_ENTER( HCA_DBG_PO ); + + p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension; + p_irp = (IRP*)context; + pIoStack = IoGetCurrentIrpStackLocation( p_irp ); + + IoFreeWorkItem( p_ext->pPoWorkItem ); + p_ext->pPoWorkItem = NULL; + + p_ext->DevicePowerState = pIoStack->Parameters.Power.State.DeviceState; + powerState = PoSetPowerState( p_dev_obj, DevicePowerState, + pIoStack->Parameters.Power.State ); + + HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PO, + ("PoSetPowerState: old state %d, new state to %d, IRQL %d\n", + powerState.DeviceState, p_ext->DevicePowerState, KeGetCurrentIrql() )); + + HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PO, + ("***** Remove the HCA \n")); + + mthca_remove_one( p_ext ); + + IoCopyCurrentIrpStackLocationToNext( p_irp ); +#pragma warning( push, 3 ) + IoSetCompletionRoutine( p_irp, __DevicePowerDownWorkItemCompletion, + NULL, TRUE, TRUE, TRUE ); +#pragma warning( pop ) + PoCallDriver( p_ext->cl_ext.p_next_do, p_irp ); + + HCA_EXIT( HCA_DBG_PO ); +} + + +static NTSTATUS +hca_set_power( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + NTSTATUS status; + IO_STACK_LOCATION *pIoStack; + hca_dev_ext_t *p_ext; + + HCA_ENTER( HCA_DBG_PO ); + + p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension; + pIoStack = IoGetCurrentIrpStackLocation( p_irp ); + + HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PO, + ("SET_POWER for FDO %p (ext %p): type %s, state %d, action %d, IRQL %d \n", + p_dev_obj, p_ext, + (pIoStack->Parameters.Power.Type) ? "DevicePowerState" : "SystemPowerState", + pIoStack->Parameters.Power.State.DeviceState, + pIoStack->Parameters.Power.ShutdownType, KeGetCurrentIrql() )); + + switch( pIoStack->Parameters.Power.Type ) + { + case SystemPowerState: + p_ext->SystemPowerState = pIoStack->Parameters.Power.State.SystemState; + + /* + * Process on the way up the stack. We cannot block since the + * power dispatch function can be called at elevated IRQL if the + * device is in a paging/hibernation/crash dump path. + */ + IoMarkIrpPending( p_irp ); + IoCopyCurrentIrpStackLocationToNext( p_irp ); +#pragma warning( push, 3 ) + IoSetCompletionRoutine( p_irp, __SystemPowerCompletion, NULL, + TRUE, TRUE, TRUE ); +#pragma warning( pop ) + PoCallDriver( p_ext->cl_ext.p_next_do, p_irp ); + + *p_action = IrpDoNothing; + status = STATUS_PENDING; + break; + + case DevicePowerState: + IoMarkIrpPending( p_irp ); + if( pIoStack->Parameters.Power.State.DeviceState == PowerDeviceD0 && + p_ext->SystemPowerState == PowerSystemWorking) + { /* power up */ + /* If we're already powered up, just pass down. */ + if( p_ext->DevicePowerState == PowerDeviceD0 ) + { + status = STATUS_SUCCESS; + *p_action = IrpIgnore; + break; + } + + /* Process in I/O completion callback. */ + IoCopyCurrentIrpStackLocationToNext( p_irp ); +#pragma warning( push, 3 ) + IoSetCompletionRoutine( p_irp, __DevicePowerUpCompletion, NULL, + TRUE, TRUE, TRUE ); +#pragma warning( pop ) + PoCallDriver( p_ext->cl_ext.p_next_do, p_irp ); + } + else + { /* power down */ + + /* Process in a work item - deregister_ca and HcaDeinit block. */ + ASSERT( !p_ext->pPoWorkItem ); + p_ext->pPoWorkItem = IoAllocateWorkItem( p_dev_obj ); + if( !p_ext->pPoWorkItem ) + { + status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + + /* Process in work item callback. */ + IoQueueWorkItem( + p_ext->pPoWorkItem, __DevicePowerDownWorkItem, DelayedWorkQueue, p_irp ); + } + *p_action = IrpDoNothing; + status = STATUS_PENDING; + break; + + default: + /* Pass down and let the PDO driver handle it. */ + *p_action = IrpIgnore; + status = STATUS_SUCCESS; + break; + } + + if( !NT_SUCCESS( status ) ) + *p_action = IrpComplete; + + HCA_EXIT( HCA_DBG_PNP ); + return status; +} + + diff --git a/branches/WOF2-3/hw/mthca/kernel/hca_pnp.h b/branches/WOF2-3/hw/mthca/kernel/hca_pnp.h new file mode 100644 index 00000000..bc74c8e1 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/hca_pnp.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#ifndef _HCA_PNP_H_ +#define _HCA_PNP_H_ + +void hca_init_vfptr( void ); + +NTSTATUS +hca_add_device( + IN PDRIVER_OBJECT pDriverObj, + IN PDEVICE_OBJECT pPdo ); + + +#endif + + diff --git a/branches/WOF2-3/hw/mthca/kernel/hca_verbs.c b/branches/WOF2-3/hw/mthca/kernel/hca_verbs.c new file mode 100644 index 00000000..4d90cf7e --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/hca_verbs.c @@ -0,0 +1,1698 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2004-2005 Mellanox Technologies, Inc. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include "hca_driver.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "hca_verbs.tmh" +#endif +#include "mthca_dev.h" +#include "ib_cache.h" +#include "mx_abi.h" +#include "mt_pa_cash.h" + + + +// Local declarations +ib_api_status_t +mlnx_query_qp ( + IN const ib_qp_handle_t h_qp, + OUT ib_qp_attr_t *p_qp_attr, + IN OUT ci_umv_buf_t *p_umv_buf ); + +/* +* CA Access Verbs +*/ +ib_api_status_t +mlnx_open_ca ( + IN const ib_net64_t ca_guid, // IN const char * ca_name, + IN const ci_async_event_cb_t pfn_async_event_cb, + IN const void*const ca_context, + OUT ib_ca_handle_t *ph_ca) +{ + mlnx_hca_t *p_hca; + ib_api_status_t status = IB_NOT_FOUND; + struct ib_device *ib_dev; + + HCA_ENTER(HCA_DBG_SHIM); + HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_SHIM, + ("context 0x%p\n", ca_context)); + + // find CA object + p_hca = mlnx_hca_from_guid( ca_guid ); + if( !p_hca ) { + if (status != IB_SUCCESS) + { + HCA_PRINT(TRACE_LEVEL_ERROR , HCA_DBG_SHIM, + ("completes with ERROR status IB_NOT_FOUND\n")); + } + HCA_EXIT(HCA_DBG_SHIM); + return IB_NOT_FOUND; + } + + ib_dev = &p_hca->mdev->ib_dev; + + HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_SHIM, + ("context 0x%p\n", ca_context)); + if (pfn_async_event_cb) { + status = mlnx_hobs_set_cb(&p_hca->hob, + pfn_async_event_cb, + ca_context); + if (IB_SUCCESS != status) { + goto err_set_cb; + } + } + + //TODO: do we need something for kernel users ? + + // Return pointer to HOB object + if (ph_ca) *ph_ca = &p_hca->hob; + status = IB_SUCCESS; + +//err_mad_cache: +err_set_cb: + if (status != IB_SUCCESS) + { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_SHIM, + ("completes with ERROR status %#x\n", status)); + } + HCA_EXIT(HCA_DBG_SHIM); + return status; +} + +static void +mlnx_register_event_handler ( + IN const ib_ca_handle_t h_ca, + IN ci_event_handler_t* p_reg) +{ + mlnx_hob_t *hob_p = (mlnx_hob_t *) h_ca; + KIRQL irql; + + KeAcquireSpinLock(&hob_p->event_list_lock, &irql); + InsertTailList(&hob_p->event_list, &p_reg->entry); + KeReleaseSpinLock(&hob_p->event_list_lock, irql); +} + +static void +mlnx_unregister_event_handler ( + IN const ib_ca_handle_t h_ca, + IN ci_event_handler_t* p_reg) +{ + mlnx_hob_t *hob_p = (mlnx_hob_t *) h_ca; + KIRQL irql; + + KeAcquireSpinLock(&hob_p->event_list_lock, &irql); + RemoveEntryList(&p_reg->entry); + KeReleaseSpinLock(&hob_p->event_list_lock, irql); +} + +ib_api_status_t +mlnx_query_ca ( + IN const ib_ca_handle_t h_ca, + OUT ib_ca_attr_t *p_ca_attr, + IN OUT uint32_t *p_byte_count, + IN OUT ci_umv_buf_t *p_umv_buf ) +{ + ib_api_status_t status; + uint32_t size, required_size; + uint8_t port_num, num_ports; + uint32_t num_gids, num_pkeys; + uint32_t num_page_sizes = 1; // TBD: what is actually supported + uint8_t *last_p; + struct ib_device_attr props; + struct ib_port_attr *hca_ports = NULL; + int i; + + mlnx_hob_t *hob_p = (mlnx_hob_t *)h_ca; + struct ib_device *ib_dev = IBDEV_FROM_HOB( hob_p ); + int err; + + HCA_ENTER(HCA_DBG_SHIM); + + // sanity checks + if( p_umv_buf && p_umv_buf->command ) { + HCA_PRINT (TRACE_LEVEL_ERROR, HCA_DBG_SHIM ,("User mode is not supported yet\n")); + p_umv_buf->status = status = IB_UNSUPPORTED; + goto err_user_unsupported; + } + + if( !cl_is_blockable() ) { + status = IB_UNSUPPORTED; + goto err_unsupported; + } + + if (NULL == p_byte_count) { + status = IB_INVALID_PARAMETER; + goto err_byte_count; + } + + // query the device + err = mthca_query_device(ib_dev, &props ); + if (err) { + HCA_PRINT (TRACE_LEVEL_ERROR, HCA_DBG_SHIM, + ("ib_query_device failed (%d)\n",err)); + status = errno_to_iberr(err); + goto err_query_device; + } + + // alocate arrary for port properties + num_ports = ib_dev->phys_port_cnt; /* Number of physical ports of the HCA */ + if (NULL == (hca_ports = cl_zalloc( num_ports * sizeof *hca_ports))) { + HCA_PRINT (TRACE_LEVEL_ERROR, HCA_DBG_SHIM, ("Failed to cl_zalloc ports array\n")); + status = IB_INSUFFICIENT_MEMORY; + goto err_alloc_ports; + } + + // start calculation of ib_ca_attr_t full size + num_gids = 0; + num_pkeys = 0; + required_size = PTR_ALIGN(sizeof(ib_ca_attr_t)) + + PTR_ALIGN(sizeof(uint32_t) * num_page_sizes) + + PTR_ALIGN(sizeof(ib_port_attr_t) * num_ports)+ + PTR_ALIGN(MTHCA_BOARD_ID_LEN)+ + PTR_ALIGN(sizeof(uplink_info_t)); /* uplink info */ + + // get port properties + for (port_num = 0; port_num <= end_port(ib_dev) - start_port(ib_dev); ++port_num) { + // request + err = mthca_query_port(ib_dev, port_num + start_port(ib_dev), &hca_ports[port_num]); + if (err) { + HCA_PRINT (TRACE_LEVEL_ERROR, HCA_DBG_SHIM, ("ib_query_port failed(%d) for port %d\n",err, port_num)); + status = errno_to_iberr(err); + goto err_query_port; + } + + // calculate GID table size + num_gids = hca_ports[port_num].gid_tbl_len; + size = PTR_ALIGN(sizeof(ib_gid_t) * num_gids); + required_size += size; + + // calculate pkeys table size + num_pkeys = hca_ports[port_num].pkey_tbl_len; + size = PTR_ALIGN(sizeof(uint16_t) * num_pkeys); + required_size += size; + } + + // resource sufficience check + if (NULL == p_ca_attr || *p_byte_count < required_size) { + *p_byte_count = required_size; + status = IB_INSUFFICIENT_MEMORY; + if ( p_ca_attr != NULL) { + HCA_PRINT (TRACE_LEVEL_ERROR,HCA_DBG_SHIM, + ("Failed *p_byte_count (%d) < required_size (%d)\n", *p_byte_count, required_size )); + } + goto err_insuff_mem; + } + RtlZeroMemory(p_ca_attr, required_size); + + // Space is sufficient - setup table pointers + last_p = (uint8_t*)p_ca_attr; + last_p += PTR_ALIGN(sizeof(*p_ca_attr)); + + p_ca_attr->p_page_size = (uint32_t*)last_p; + last_p += PTR_ALIGN(num_page_sizes * sizeof(uint32_t)); + + p_ca_attr->p_port_attr = (ib_port_attr_t *)last_p; + last_p += PTR_ALIGN(num_ports * sizeof(ib_port_attr_t)); + + for (port_num = 0; port_num < num_ports; port_num++) { + p_ca_attr->p_port_attr[port_num].p_gid_table = (ib_gid_t *)last_p; + size = PTR_ALIGN(sizeof(ib_gid_t) * hca_ports[port_num].gid_tbl_len); + last_p += size; + + p_ca_attr->p_port_attr[port_num].p_pkey_table = (uint16_t *)last_p; + size = PTR_ALIGN(sizeof(uint16_t) * hca_ports[port_num].pkey_tbl_len); + last_p += size; + } + + //copy vendor specific data + cl_memcpy(last_p,to_mdev(ib_dev)->board_id, MTHCA_BOARD_ID_LEN); + last_p += PTR_ALIGN(MTHCA_BOARD_ID_LEN); + *(uplink_info_t*)last_p = to_mdev(ib_dev)->uplink_info; + last_p += PTR_ALIGN(sizeof(uplink_info_t)); /* uplink info */ + + // Separate the loops to ensure that table pointers are always setup + for (port_num = 0; port_num < num_ports; port_num++) { + + // get pkeys, using cache + for (i=0; i < hca_ports[port_num].pkey_tbl_len; ++i) { + err = ib_get_cached_pkey( ib_dev, port_num + start_port(ib_dev), i, + &p_ca_attr->p_port_attr[port_num].p_pkey_table[i] ); + if (err) { + status = errno_to_iberr(err); + HCA_PRINT (TRACE_LEVEL_ERROR,HCA_DBG_SHIM, + ("ib_get_cached_pkey failed (%d) for port_num %d, index %d\n", + err, port_num + start_port(ib_dev), i)); + goto err_get_pkey; + } + } + + // get gids, using cache + for (i=0; i < hca_ports[port_num].gid_tbl_len; ++i) { + union ib_gid * gid = (union ib_gid *)&p_ca_attr->p_port_attr[port_num].p_gid_table[i]; + err = ib_get_cached_gid( ib_dev, port_num + start_port(ib_dev), i, (union ib_gid *)gid ); + //TODO: do we need to convert gids to little endian + if (err) { + status = errno_to_iberr(err); + HCA_PRINT (TRACE_LEVEL_ERROR, HCA_DBG_SHIM, + ("ib_get_cached_gid failed (%d) for port_num %d, index %d\n", + err, port_num + start_port(ib_dev), i)); + goto err_get_gid; + } + } + + HCA_PRINT(TRACE_LEVEL_VERBOSE, HCA_DBG_SHIM,("port %d gid0:\n", port_num)); + HCA_PRINT(TRACE_LEVEL_VERBOSE, HCA_DBG_SHIM, + (" 0x%x%x%x%x%x%x%x%x-0x%x%x%x%x%x%x%x%x\n", + p_ca_attr->p_port_attr[port_num].p_gid_table[0].raw[0], + p_ca_attr->p_port_attr[port_num].p_gid_table[0].raw[1], + p_ca_attr->p_port_attr[port_num].p_gid_table[0].raw[2], + p_ca_attr->p_port_attr[port_num].p_gid_table[0].raw[3], + p_ca_attr->p_port_attr[port_num].p_gid_table[0].raw[4], + p_ca_attr->p_port_attr[port_num].p_gid_table[0].raw[5], + p_ca_attr->p_port_attr[port_num].p_gid_table[0].raw[6], + p_ca_attr->p_port_attr[port_num].p_gid_table[0].raw[7], + p_ca_attr->p_port_attr[port_num].p_gid_table[0].raw[8], + p_ca_attr->p_port_attr[port_num].p_gid_table[0].raw[9], + p_ca_attr->p_port_attr[port_num].p_gid_table[0].raw[10], + p_ca_attr->p_port_attr[port_num].p_gid_table[0].raw[11], + p_ca_attr->p_port_attr[port_num].p_gid_table[0].raw[12], + p_ca_attr->p_port_attr[port_num].p_gid_table[0].raw[13], + p_ca_attr->p_port_attr[port_num].p_gid_table[0].raw[14], + p_ca_attr->p_port_attr[port_num].p_gid_table[0].raw[15])); + } + + // set result size + p_ca_attr->size = required_size; + CL_ASSERT( required_size == (((uintn_t)last_p) - ((uintn_t)p_ca_attr)) ); + HCA_PRINT(TRACE_LEVEL_VERBOSE, HCA_DBG_SHIM , ("Space required %d used %d\n", + required_size, (int)((uintn_t)last_p - (uintn_t)p_ca_attr) )); + + // !!! GID/PKEY tables must be queried before this call !!! + mlnx_conv_hca_cap(ib_dev, &props, hca_ports, p_ca_attr); + + status = IB_SUCCESS; + +err_get_gid: +err_get_pkey: +err_insuff_mem: +err_query_port: + cl_free(hca_ports); +err_alloc_ports: +err_query_device: +err_byte_count: +err_unsupported: +err_user_unsupported: + if( status != IB_INSUFFICIENT_MEMORY && status != IB_SUCCESS ) + HCA_PRINT(TRACE_LEVEL_ERROR, HCA_DBG_SHIM, + ("completes with ERROR status %#x\n", status)); + HCA_EXIT(HCA_DBG_SHIM); + return status; +} + +ib_api_status_t +mlnx_modify_ca ( + IN const ib_ca_handle_t h_ca, + IN const uint8_t port_num, + IN const ib_ca_mod_t modca_cmd, + IN const ib_port_attr_mod_t *p_port_attr) +{ +#define SET_CAP_MOD(al_mask, al_fld, ib) \ + if (modca_cmd & al_mask) { \ + if (p_port_attr->cap.##al_fld) \ + props.set_port_cap_mask |= ib; \ + else \ + props.clr_port_cap_mask |= ib; \ + } + + ib_api_status_t status; + int err; + struct ib_port_modify props; + int port_modify_mask = 0; + mlnx_hob_t *hob_p = (mlnx_hob_t *)h_ca; + struct ib_device *ib_dev = IBDEV_FROM_HOB( hob_p ); + + HCA_ENTER(HCA_DBG_SHIM); + + //sanity check + if( !cl_is_blockable() ) { + status = IB_UNSUPPORTED; + goto err_unsupported; + } + + if (port_num < start_port(ib_dev) || port_num > end_port(ib_dev)) { + status = IB_INVALID_PORT; + goto err_port; + } + + // prepare parameters + RtlZeroMemory(&props, sizeof(props)); + SET_CAP_MOD(IB_CA_MOD_IS_SM, sm, IB_PORT_SM); + SET_CAP_MOD(IB_CA_MOD_IS_SNMP_SUPPORTED, snmp, IB_PORT_SNMP_TUNNEL_SUP); + SET_CAP_MOD(IB_CA_MOD_IS_DEV_MGMT_SUPPORTED, dev_mgmt, IB_PORT_DEVICE_MGMT_SUP); + SET_CAP_MOD(IB_CA_MOD_IS_VEND_SUPPORTED, vend, IB_PORT_VENDOR_CLASS_SUP); + if ((modca_cmd & IB_CA_MOD_QKEY_CTR) && (p_port_attr->qkey_ctr == 0)) + port_modify_mask |= IB_PORT_RESET_QKEY_CNTR; + + // modify port + err = mthca_modify_port(ib_dev, port_num, port_modify_mask, &props ); + if (err) { + status = errno_to_iberr(err); + HCA_PRINT(TRACE_LEVEL_ERROR , HCA_DBG_SHIM ,("mthca_modify_port failed (%d) \n",err)); + goto err_modify_port; + } + + status = IB_SUCCESS; + +err_modify_port: +err_port: +err_unsupported: + if (status != IB_SUCCESS) + { + HCA_PRINT(TRACE_LEVEL_ERROR, HCA_DBG_SHIM, + ("completes with ERROR status %#x\n", status)); + } + HCA_EXIT(HCA_DBG_SHIM); + return status; +} + +ib_api_status_t +mlnx_close_ca ( + IN ib_ca_handle_t h_ca) +{ + HCA_ENTER(HCA_DBG_SHIM); + mlnx_hobs_remove(h_ca); + HCA_EXIT(HCA_DBG_SHIM); + return IB_SUCCESS; +} + + +static ib_api_status_t +mlnx_um_open( + IN const ib_ca_handle_t h_ca, + IN OUT ci_umv_buf_t* const p_umv_buf, + OUT ib_ca_handle_t* const ph_um_ca ) +{ + int err; + ib_api_status_t status; + mlnx_hob_t *hob_p = (mlnx_hob_t *)h_ca; + hca_dev_ext_t *ext_p = EXT_FROM_HOB( hob_p ); + struct ib_device *ib_dev = IBDEV_FROM_HOB( hob_p ); + struct ib_ucontext *p_context; + struct ibv_get_context_resp *uresp_p; + struct ibv_alloc_pd_resp resp; + ci_umv_buf_t umv_buf; + + HCA_ENTER(HCA_DBG_SHIM); + + // sanity check + ASSERT( p_umv_buf ); + if( !p_umv_buf->command ) + { + p_context = cl_zalloc( sizeof(struct ib_ucontext) ); + if( !p_context ) + { + status = IB_INSUFFICIENT_MEMORY; + goto err_alloc_ucontext; + } + /* Copy the dev info. */ + p_context->device = ib_dev; + p_umv_buf->output_size = 0; + goto done; + } + + // create user context in kernel + p_context = mthca_alloc_ucontext(ib_dev, p_umv_buf); + if (IS_ERR(p_context)) { + err = PTR_ERR(p_context); + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_SHIM, + ("mthca_alloc_ucontext failed (%d)\n", err)); + status = errno_to_iberr(err); + goto err_alloc_ucontext; + } + + /* allocate pd */ + umv_buf.command = 1; + umv_buf.input_size = umv_buf.status = 0; + umv_buf.output_size = sizeof(struct ibv_alloc_pd_resp); + umv_buf.p_inout_buf = (ULONG_PTR)&resp; + //NB: Pay attention ! Ucontext parameter is important here: + // when it is present (i.e. - for user space) - mthca_alloc_pd won't create MR + p_context->pd = ibv_alloc_pd(ib_dev, p_context, &umv_buf); + if (IS_ERR(p_context->pd)) { + err = PTR_ERR(p_context->pd); + HCA_PRINT(TRACE_LEVEL_ERROR , HCA_DBG_SHIM, + ("ibv_alloc_pd failed (%d)\n", err)); + status = errno_to_iberr(err); + goto err_alloc_pd; + } + + // fill more parameters for user (sanity checks are in mthca_alloc_ucontext) + uresp_p = (struct ibv_get_context_resp *)(ULONG_PTR)p_umv_buf->p_inout_buf; + uresp_p->uar_addr = (uint64_t)(UINT_PTR)p_context->user_uar; + uresp_p->pd_handle = resp.pd_handle; + uresp_p->pdn = resp.pdn; + uresp_p->vend_id = (uint32_t)ext_p->hcaConfig.VendorID; + uresp_p->dev_id = (uint16_t)ext_p->hcaConfig.DeviceID; + +done: + // some more inits + p_context->va = p_context->p_mdl = NULL; + p_context->fw_if_open = FALSE; + KeInitializeMutex( &p_context->mutex, 0 ); + // chain user context to the device + cl_spinlock_acquire( &ext_p->uctx_lock ); + cl_qlist_insert_tail( &ext_p->uctx_list, &p_context->list_item ); + cl_atomic_inc(&ext_p->usecnt); + cl_spinlock_release( &ext_p->uctx_lock ); + + // return the result + if (ph_um_ca) *ph_um_ca = (ib_ca_handle_t)p_context; + + status = IB_SUCCESS; + goto end; + +err_alloc_pd: + mthca_dealloc_ucontext(p_context); +err_alloc_ucontext: +end: + if (p_umv_buf && p_umv_buf->command) + p_umv_buf->status = status; + if (status != IB_SUCCESS) + { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_SHIM, + ("completes with ERROR status %#x\n", status)); + } + HCA_EXIT(HCA_DBG_SHIM); + return status; +} + +static void +mlnx_um_close( + IN ib_ca_handle_t h_ca, + IN ib_ca_handle_t h_um_ca ) +{ + struct ib_ucontext *p_ucontext = (struct ib_ucontext *)h_um_ca; + mlnx_hob_t *hob_p = (mlnx_hob_t *)h_ca; + hca_dev_ext_t *ext_p = EXT_FROM_HOB( hob_p ); + + unmap_crspace_for_all(p_ucontext); + cl_spinlock_acquire( &ext_p->uctx_lock ); + cl_qlist_remove_item( &ext_p->uctx_list, &p_ucontext->list_item ); + cl_atomic_dec(&ext_p->usecnt); + cl_spinlock_release( &ext_p->uctx_lock ); + if( !p_ucontext->pd ) + cl_free( h_um_ca ); + else + ibv_um_close(p_ucontext); + pa_cash_print(); + return; +} + + +/* +* Protection Domain and Reliable Datagram Domain Verbs +*/ + +ib_api_status_t +mlnx_allocate_pd ( + IN const ib_ca_handle_t h_ca, + IN const ib_pd_type_t type, + OUT ib_pd_handle_t *ph_pd, + IN OUT ci_umv_buf_t *p_umv_buf ) +{ + ib_api_status_t status; + struct ib_device *ib_dev; + struct ib_ucontext *p_context; + struct ib_pd *ib_pd_p; + int err; + + //TODO: how are we use it ? + UNREFERENCED_PARAMETER(type); + + HCA_ENTER(HCA_DBG_PD); + + if( p_umv_buf ) { + p_context = (struct ib_ucontext *)h_ca; + ib_dev = p_context->device; + } + else { + mlnx_hob_t *hob_p = (mlnx_hob_t *)h_ca; + p_context = NULL; + ib_dev = IBDEV_FROM_HOB( hob_p ); + } + + // create PD + ib_pd_p = ibv_alloc_pd(ib_dev, p_context, p_umv_buf); + if (IS_ERR(ib_pd_p)) { + err = PTR_ERR(ib_pd_p); + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_PD, + ("ibv_alloc_pd failed (%d)\n", err)); + status = errno_to_iberr(err); + goto err_alloc_pd; + } + + // return the result + if (ph_pd) *ph_pd = (ib_pd_handle_t)ib_pd_p; + + status = IB_SUCCESS; + +err_alloc_pd: + if (p_umv_buf && p_umv_buf->command) + p_umv_buf->status = status; + if (status != IB_SUCCESS) + { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_PD, + ("completes with ERROR status %#x\n", status)); + } + HCA_EXIT(HCA_DBG_PD); + return status; +} + +ib_api_status_t +mlnx_deallocate_pd ( + IN ib_pd_handle_t h_pd) +{ + ib_api_status_t status; + int err; + struct ib_pd *ib_pd_p = (struct ib_pd *)h_pd; + + HCA_ENTER( HCA_DBG_PD); + + HCA_PRINT(TRACE_LEVEL_INFORMATION,HCA_DBG_PD, + ("pcs %p\n", PsGetCurrentProcess())); + + // dealloc pd + err = ibv_dealloc_pd( ib_pd_p ); + if (err) { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_PD + ,("ibv_dealloc_pd failed (%d)\n", err)); + status = errno_to_iberr(err); + goto err_dealloc_pd; + } + status = IB_SUCCESS; + +err_dealloc_pd: + if (status != IB_SUCCESS) + { + HCA_PRINT(TRACE_LEVEL_ERROR, HCA_DBG_PD + ,("completes with ERROR status %#x\n", status)); + } + HCA_EXIT(HCA_DBG_PD); + return status; +} + +/* +* Address Vector Management Verbs +*/ +ib_api_status_t +mlnx_create_av ( + IN const ib_pd_handle_t h_pd, + IN const ib_av_attr_t *p_addr_vector, + OUT ib_av_handle_t *ph_av, + IN OUT ci_umv_buf_t *p_umv_buf ) +{ + int err = 0; + ib_api_status_t status = IB_SUCCESS; + struct ib_pd *ib_pd_p = (struct ib_pd *)h_pd; + struct ib_device *ib_dev = ib_pd_p->device; + struct ib_ah *ib_av_p; + struct ib_ah_attr ah_attr; + struct ib_ucontext *p_context = NULL; + + HCA_ENTER(HCA_DBG_AV); + + if( p_umv_buf && p_umv_buf->command ) { + // sanity checks + if (p_umv_buf->input_size < sizeof(struct ibv_create_ah) || + p_umv_buf->output_size < sizeof(struct ibv_create_ah_resp) || + !p_umv_buf->p_inout_buf) { + status = IB_INVALID_PARAMETER; + goto err_inval_params; + } + p_context = ib_pd_p->ucontext; + } + else + p_context = NULL; + + // fill parameters + RtlZeroMemory(&ah_attr, sizeof(ah_attr)); + mlnx_conv_ibal_av( ib_dev, p_addr_vector, &ah_attr ); + + ib_av_p = ibv_create_ah(ib_pd_p, &ah_attr, p_context, p_umv_buf); + if (IS_ERR(ib_av_p)) { + err = PTR_ERR(ib_av_p); + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_AV, + ("ibv_create_ah failed (%d)\n", err)); + status = errno_to_iberr(err); + goto err_alloc_av; + } + + // return the result + if (ph_av) *ph_av = (ib_av_handle_t)ib_av_p; + + status = IB_SUCCESS; + +err_alloc_av: +err_inval_params: + if (p_umv_buf && p_umv_buf->command) + p_umv_buf->status = status; + if (status != IB_SUCCESS) + { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_AV, + ("completes with ERROR status %#x\n", status)); + } + HCA_EXIT(HCA_DBG_AV); + return status; +} + +ib_api_status_t +mlnx_query_av ( + IN const ib_av_handle_t h_av, + OUT ib_av_attr_t *p_addr_vector, + OUT ib_pd_handle_t *ph_pd, + IN OUT ci_umv_buf_t *p_umv_buf ) +{ + int err; + ib_api_status_t status = IB_SUCCESS; + struct ib_ah *ib_ah_p = (struct ib_ah *)h_av; + + HCA_ENTER(HCA_DBG_AV); + + // sanity checks + if( p_umv_buf && p_umv_buf->command ) { + HCA_PRINT (TRACE_LEVEL_ERROR, HCA_DBG_AV, + ("User mode is not supported yet\n")); + status = IB_UNSUPPORTED; + goto err_user_unsupported; + } + + // query AV +#ifdef WIN_TO_BE_CHANGED + //TODO: not implemented in low-level driver + err = ibv_query_ah(ib_ah_p, &ah_attr) + if (err) { + HCA_PRINT(TRACE_LEVEL_ERROR, HCA_DBG_AV, + ("ibv_query_ah failed (%d)\n", err)); + status = errno_to_iberr(err); + goto err_query_ah; + } + // convert to IBAL structure: something like that + mlnx_conv_mthca_av( p_addr_vector, &ah_attr ); +#else + + err = mlnx_conv_mthca_av( ib_ah_p, p_addr_vector ); + if (err) { + HCA_PRINT (TRACE_LEVEL_ERROR, HCA_DBG_AV, + ("mlnx_conv_mthca_av failed (%d)\n", err)); + status = errno_to_iberr(err); + goto err_conv_mthca_av; + } +#endif + + // results + *ph_pd = (ib_pd_handle_t)ib_ah_p->pd; + +err_conv_mthca_av: +err_user_unsupported: + if (status != IB_SUCCESS) + { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_AV, + ("completes with ERROR status %#x\n", status)); + } + HCA_EXIT(HCA_DBG_AV); + return status; +} + +ib_api_status_t +mlnx_modify_av ( + IN const ib_av_handle_t h_av, + IN const ib_av_attr_t *p_addr_vector, + IN OUT ci_umv_buf_t *p_umv_buf ) +{ + struct ib_ah_attr ah_attr; + ib_api_status_t status = IB_SUCCESS; + struct ib_ah *ib_ah_p = (struct ib_ah *)h_av; + struct ib_device *ib_dev = ib_ah_p->pd->device; + + HCA_ENTER(HCA_DBG_AV); + + // sanity checks + if( p_umv_buf && p_umv_buf->command ) { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_AV, + ("User mode is not supported yet\n")); + status = IB_UNSUPPORTED; + goto err_user_unsupported; + } + + // fill parameters + RtlZeroMemory(&ah_attr, sizeof(ah_attr)); + mlnx_conv_ibal_av( ib_dev, p_addr_vector, &ah_attr ); + + // modify AH +#ifdef WIN_TO_BE_CHANGED + //TODO: not implemented in low-level driver + err = ibv_modify_ah(ib_ah_p, &ah_attr) + if (err) { + HCA_PRINT (TRACE_LEVEL_ERROR,HCA_DBG_AV, + ("ibv_query_ah failed (%d)\n", err)); + status = errno_to_iberr(err); + goto err_query_ah; + } +#else + + mlnx_modify_ah( ib_ah_p, &ah_attr ); +#endif + +err_user_unsupported: + if (status != IB_SUCCESS) + { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_AV, + ("completes with ERROR status %#x\n", status)); + } + HCA_EXIT(HCA_DBG_AV); + return status; +} + +ib_api_status_t +mlnx_destroy_av ( + IN const ib_av_handle_t h_av) +{ + int err; + ib_api_status_t status = IB_SUCCESS; + struct ib_ah *ib_ah_p = (struct ib_ah *)h_av; + + HCA_ENTER(HCA_DBG_AV); + + // destroy AV + err = ibv_destroy_ah( ib_ah_p ); + if (err) { + HCA_PRINT (TRACE_LEVEL_ERROR ,HCA_DBG_AV, + ("ibv_destroy_ah failed (%d)\n", err)); + status = errno_to_iberr(err); + goto err_destroy_ah; + } + +err_destroy_ah: + if (status != IB_SUCCESS) + { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_AV, + ("completes with ERROR status %#x\n", status)); + } + HCA_EXIT(HCA_DBG_AV); + return status; +} + +/* +* Shared Queue Pair Management Verbs +*/ + + +ib_api_status_t +mlnx_create_srq ( + IN const ib_pd_handle_t h_pd, + IN const void *srq_context, + IN ci_async_event_cb_t event_handler, + IN const ib_srq_attr_t * const p_srq_attr, + OUT ib_srq_handle_t *ph_srq, + IN OUT ci_umv_buf_t *p_umv_buf ) +{ + int err; + ib_api_status_t status; + struct ib_srq *ib_srq_p; + struct ib_srq_init_attr srq_init_attr; + struct ib_ucontext *p_context = NULL; + struct ib_pd *ib_pd_p = (struct ib_pd *)h_pd; + + HCA_ENTER(HCA_DBG_SRQ); + + if( p_umv_buf && p_umv_buf->command) { + + // sanity checks + if (p_umv_buf->input_size < sizeof(struct ibv_create_srq) || + p_umv_buf->output_size < sizeof(struct ibv_create_srq_resp) || + !p_umv_buf->p_inout_buf) { + status = IB_INVALID_PARAMETER; + goto err_inval_params; + } + p_context = ib_pd_p->ucontext; + } + + // prepare the parameters + RtlZeroMemory(&srq_init_attr, sizeof(srq_init_attr)); + srq_init_attr.event_handler = event_handler; + srq_init_attr.srq_context = (void*)srq_context; + srq_init_attr.attr = *p_srq_attr; + + // allocate srq + ib_srq_p = ibv_create_srq(ib_pd_p, &srq_init_attr, p_context, p_umv_buf ); + if (IS_ERR(ib_srq_p)) { + err = PTR_ERR(ib_srq_p); + HCA_PRINT (TRACE_LEVEL_ERROR ,HCA_DBG_SRQ, ("ibv_create_srq failed (%d)\n", err)); + status = errno_to_iberr(err); + goto err_create_srq; + } + + // return the result + if (ph_srq) *ph_srq = (ib_srq_handle_t)ib_srq_p; + + status = IB_SUCCESS; + +err_create_srq: +err_inval_params: + if (p_umv_buf && p_umv_buf->command) + p_umv_buf->status = status; + if (status != IB_SUCCESS) + { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_SRQ, + ("completes with ERROR status %#x\n", status)); + } + HCA_EXIT(HCA_DBG_SRQ); + return status; +} + + +ib_api_status_t +mlnx_modify_srq ( + IN const ib_srq_handle_t h_srq, + IN const ib_srq_attr_t* const p_srq_attr, + IN const ib_srq_attr_mask_t srq_attr_mask, + IN OUT ci_umv_buf_t *p_umv_buf OPTIONAL ) +{ + int err; + ib_api_status_t status = IB_SUCCESS; + struct ib_srq *ib_srq = (struct ib_srq *)h_srq; + UNUSED_PARAM(p_umv_buf); + + HCA_ENTER(HCA_DBG_SRQ); + + err = ibv_modify_srq(ib_srq, (void*)p_srq_attr, srq_attr_mask); + if (err) { + HCA_PRINT (TRACE_LEVEL_ERROR, HCA_DBG_AV, + ("ibv_modify_srq failed (%d)\n", err)); + status = errno_to_iberr(err); + } + + if (status != IB_SUCCESS) + { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_SRQ, + ("completes with ERROR status %#x\n", status)); + } + HCA_EXIT(HCA_DBG_SRQ); + return status; +} + +ib_api_status_t +mlnx_query_srq ( + IN const ib_srq_handle_t h_srq, + OUT ib_srq_attr_t* const p_srq_attr, + IN OUT ci_umv_buf_t *p_umv_buf OPTIONAL ) +{ + int err; + ib_api_status_t status = IB_SUCCESS; + struct ib_srq *ib_srq = (struct ib_srq *)h_srq; + UNUSED_PARAM(p_umv_buf); + + HCA_ENTER(HCA_DBG_SRQ); + + err = ibv_query_srq(ib_srq, p_srq_attr); + if (err) { + HCA_PRINT (TRACE_LEVEL_ERROR, HCA_DBG_AV, + ("ibv_query_srq failed (%d)\n", err)); + status = errno_to_iberr(err); + } + + if (status != IB_SUCCESS) + { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_SRQ, + ("completes with ERROR status %#x\n", status)); + } + HCA_EXIT(HCA_DBG_SRQ); + return status; +} + +ib_api_status_t +mlnx_destroy_srq ( + IN const ib_srq_handle_t h_srq ) +{ + int err; + ib_api_status_t status = IB_SUCCESS; + struct ib_srq *ib_srq = (struct ib_srq *)h_srq; + + HCA_ENTER(HCA_DBG_SRQ); + + err = ibv_destroy_srq(ib_srq); + if (err) { + HCA_PRINT (TRACE_LEVEL_ERROR, HCA_DBG_AV, + ("ibv_destroy_srq failed (%d)\n", err)); + status = errno_to_iberr(err); + } + + if (status != IB_SUCCESS) + { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_SRQ, + ("completes with ERROR status %#x\n", status)); + } + HCA_EXIT(HCA_DBG_SRQ); + return status; +} + +/* +* Queue Pair Management Verbs +*/ + + +static ib_api_status_t +_create_qp ( + IN const ib_pd_handle_t h_pd, + IN const uint8_t port_num, + IN const void *qp_context, + IN ci_async_event_cb_t event_handler, + IN const ib_qp_create_t *p_create_attr, + OUT ib_qp_attr_t *p_qp_attr, + OUT ib_qp_handle_t *ph_qp, + IN OUT ci_umv_buf_t *p_umv_buf ) +{ + int err; + ib_api_status_t status; + struct ib_qp * ib_qp_p; + struct mthca_qp *qp_p; + struct ib_qp_init_attr qp_init_attr; + struct ib_ucontext *p_context = NULL; + struct ib_pd *ib_pd_p = (struct ib_pd *)h_pd; + + HCA_ENTER(HCA_DBG_QP); + + if( p_umv_buf && p_umv_buf->command ) { + // sanity checks + if (p_umv_buf->input_size < sizeof(struct ibv_create_qp) || + p_umv_buf->output_size < sizeof(struct ibv_create_qp_resp) || + !p_umv_buf->p_inout_buf) { + status = IB_INVALID_PARAMETER; + goto err_inval_params; + } + p_context = ib_pd_p->ucontext; + } + + // prepare the parameters + RtlZeroMemory(&qp_init_attr, sizeof(qp_init_attr)); + qp_init_attr.qp_type = p_create_attr->qp_type; + qp_init_attr.event_handler = event_handler; + qp_init_attr.qp_context = (void*)qp_context; + qp_init_attr.recv_cq = (struct ib_cq *)p_create_attr->h_rq_cq; + qp_init_attr.send_cq = (struct ib_cq *)p_create_attr->h_sq_cq; + qp_init_attr.srq = (struct ib_srq *)p_create_attr->h_srq; + qp_init_attr.cap.max_inline_data = p_create_attr->sq_max_inline; + qp_init_attr.cap.max_recv_sge = p_create_attr->rq_sge; + qp_init_attr.cap.max_send_sge = p_create_attr->sq_sge; + qp_init_attr.cap.max_recv_wr = p_create_attr->rq_depth; + qp_init_attr.cap.max_send_wr = p_create_attr->sq_depth; + qp_init_attr.sq_sig_type = (p_create_attr->sq_signaled) ? IB_SIGNAL_ALL_WR : IB_SIGNAL_REQ_WR; + qp_init_attr.port_num = port_num; + + + // create qp + ib_qp_p = ibv_create_qp( ib_pd_p, &qp_init_attr, p_context, p_umv_buf ); + if (IS_ERR(ib_qp_p)) { + err = PTR_ERR(ib_qp_p); + HCA_PRINT(TRACE_LEVEL_ERROR , HCA_DBG_QP, + ("ibv_create_qp failed (%d)\n", err)); + status = errno_to_iberr(err); + goto err_create_qp; + } + + // fill the object + qp_p = (struct mthca_qp *)ib_qp_p; + qp_p->qp_init_attr = qp_init_attr; + + // Query QP to obtain requested attributes + if (p_qp_attr) { + status = mlnx_query_qp ((ib_qp_handle_t)ib_qp_p, p_qp_attr, p_umv_buf); + if (status != IB_SUCCESS) + goto err_query_qp; + } + + // return the results + if (ph_qp) *ph_qp = (ib_qp_handle_t)ib_qp_p; + + status = IB_SUCCESS; + goto end; + +err_query_qp: + ibv_destroy_qp( ib_qp_p ); +err_create_qp: +err_inval_params: +end: + if (p_umv_buf && p_umv_buf->command) + p_umv_buf->status = status; + if (status != IB_SUCCESS) + { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_QP, + ("completes with ERROR status %#x\n", status)); + } + HCA_EXIT(HCA_DBG_QP); + return status; +} + +ib_api_status_t +mlnx_create_spl_qp ( + IN const ib_pd_handle_t h_pd, + IN const uint8_t port_num, + IN const void *qp_context, + IN ci_async_event_cb_t event_handler, + IN const ib_qp_create_t *p_create_attr, + OUT ib_qp_attr_t *p_qp_attr, + OUT ib_qp_handle_t *ph_qp ) +{ + ib_api_status_t status; + + HCA_ENTER(HCA_DBG_SHIM); + + status = _create_qp( h_pd, port_num, + qp_context, event_handler, p_create_attr, p_qp_attr, ph_qp, NULL ); + + if (status != IB_SUCCESS) + { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_QP, + ("completes with ERROR status %#x\n", status)); + } + HCA_EXIT(HCA_DBG_QP); + return status; +} + +ib_api_status_t +mlnx_create_qp ( + IN const ib_pd_handle_t h_pd, + IN const void *qp_context, + IN ci_async_event_cb_t event_handler, + IN const ib_qp_create_t *p_create_attr, + OUT ib_qp_attr_t *p_qp_attr, + OUT ib_qp_handle_t *ph_qp, + IN OUT ci_umv_buf_t *p_umv_buf ) +{ + ib_api_status_t status; + + //NB: algorithm of mthca_alloc_sqp() requires port_num + // PRM states, that special pares are created in couples, so + // looks like we can put here port_num = 1 always + uint8_t port_num = 1; + + HCA_ENTER(HCA_DBG_QP); + + status = _create_qp( h_pd, port_num, + qp_context, event_handler, p_create_attr, p_qp_attr, ph_qp, p_umv_buf ); + + if (status != IB_SUCCESS) + { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_QP, + ("completes with ERROR status %#x\n", status)); + } + HCA_EXIT(HCA_DBG_QP); + return status; +} + +ib_api_status_t +mlnx_modify_qp ( + IN const ib_qp_handle_t h_qp, + IN const ib_qp_mod_t *p_modify_attr, + OUT ib_qp_attr_t *p_qp_attr OPTIONAL, + IN OUT ci_umv_buf_t *p_umv_buf OPTIONAL ) +{ + ib_api_status_t status; + int err; + struct ib_qp_attr qp_attr; + int qp_attr_mask; + struct ib_qp *ib_qp_p = (struct ib_qp *)h_qp; + + HCA_ENTER(HCA_DBG_QP); + + // sanity checks + if( p_umv_buf && p_umv_buf->command ) { + // sanity checks + if (p_umv_buf->output_size < sizeof(struct ibv_modify_qp_resp) || + !p_umv_buf->p_inout_buf) { + status = IB_INVALID_PARAMETER; + goto err_inval_params; + } + } + + // fill parameters + status = mlnx_conv_qp_modify_attr( ib_qp_p, ib_qp_p->qp_type, + p_modify_attr, &qp_attr, &qp_attr_mask ); + if (status == IB_NOT_DONE) + goto query_qp; + if (status != IB_SUCCESS ) + goto err_mode_unsupported; + + // modify QP + err = ibv_modify_qp(ib_qp_p, &qp_attr, qp_attr_mask); + if (err) { + HCA_PRINT(TRACE_LEVEL_ERROR, HCA_DBG_QP, + ("ibv_modify_qp failed (%d)\n", err)); + status = errno_to_iberr(err); + goto err_modify_qp; + } + + // Query QP to obtain requested attributes +query_qp: + if (p_qp_attr) { + status = mlnx_query_qp ((ib_qp_handle_t)ib_qp_p, p_qp_attr, p_umv_buf); + if (status != IB_SUCCESS) + goto err_query_qp; + } + + if( p_umv_buf && p_umv_buf->command ) { + struct ibv_modify_qp_resp resp; + resp.attr_mask = qp_attr_mask; + resp.qp_state = qp_attr.qp_state; + err = ib_copy_to_umv_buf(p_umv_buf, &resp, sizeof(struct ibv_modify_qp_resp)); + if (err) { + HCA_PRINT(TRACE_LEVEL_ERROR , HCA_DBG_SHIM ,("ib_copy_to_umv_buf failed (%d)\n", err)); + status = errno_to_iberr(err); + goto err_copy; + } + } + + status = IB_SUCCESS; + +err_copy: +err_query_qp: +err_modify_qp: +err_mode_unsupported: +err_inval_params: + if (p_umv_buf && p_umv_buf->command) + p_umv_buf->status = status; + if (status != IB_SUCCESS) + { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_QP, + ("completes with ERROR status %#x\n", status)); + } + HCA_EXIT(HCA_DBG_QP); + return status; +} + +ib_api_status_t +mlnx_ndi_modify_qp ( + IN const ib_qp_handle_t h_qp, + IN const ib_qp_mod_t *p_modify_attr, + OUT ib_qp_attr_t *p_qp_attr OPTIONAL, + IN const uint32_t buf_size, + IN uint8_t* const p_outbuf) +{ + ci_umv_buf_t umv_buf; + ib_api_status_t status; + struct ibv_modify_qp_resp resp; + void *buf = &resp; + + HCA_ENTER(HCA_DBG_QP); + + if (buf_size < sizeof(resp.qp_state)) { + status = IB_INVALID_PARAMETER; + goto out; + } + + /* imitate umv_buf */ + umv_buf.command = TRUE; /* special case for NDI. Usually it's TRUE */ + umv_buf.input_size = 0; + umv_buf.output_size = sizeof(struct ibv_modify_qp_resp); + umv_buf.p_inout_buf = (ULONG_PTR)buf; + + status = mlnx_modify_qp ( h_qp, p_modify_attr, p_qp_attr, &umv_buf ); + + if (status == IB_SUCCESS) { + cl_memclr( p_outbuf, buf_size ); + *p_outbuf = resp.qp_state; + } + +out: + HCA_EXIT(HCA_DBG_QP); + return status; +} + + + +ib_api_status_t +mlnx_query_qp ( + IN const ib_qp_handle_t h_qp, + OUT ib_qp_attr_t *p_qp_attr, + IN OUT ci_umv_buf_t *p_umv_buf ) +{ + int err; + int qp_attr_mask = 0; + ib_api_status_t status = IB_SUCCESS; + struct ib_qp *ib_qp_p = (struct ib_qp *)h_qp; + struct ib_qp_attr qp_attr; + struct ib_qp_init_attr qp_init_attr; + struct mthca_qp *qp_p = (struct mthca_qp *)ib_qp_p; + + UNREFERENCED_PARAMETER(p_umv_buf); + + HCA_ENTER( HCA_DBG_QP); + + // sanity checks + if (!p_qp_attr) { + status = IB_INVALID_PARAMETER; + goto err_parm; + } + + memset( &qp_attr, 0, sizeof(struct ib_qp_attr) ); + + if (qp_p->state == IBQPS_RESET) { + // the QP doesn't yet exist in HW - fill what we can fill now + p_qp_attr->h_pd = (ib_pd_handle_t)qp_p->ibqp.pd; + p_qp_attr->qp_type = qp_p->ibqp.qp_type; + p_qp_attr->sq_max_inline = qp_p->qp_init_attr.cap.max_inline_data; + p_qp_attr->sq_depth = qp_p->qp_init_attr.cap.max_send_wr; + p_qp_attr->rq_depth = qp_p->qp_init_attr.cap.max_recv_wr; + p_qp_attr->sq_sge = qp_p->qp_init_attr.cap.max_send_sge; + p_qp_attr->rq_sge = qp_p->qp_init_attr.cap.max_recv_sge; + p_qp_attr->resp_res = qp_p->resp_depth; + p_qp_attr->h_sq_cq = (ib_cq_handle_t)qp_p->ibqp.send_cq; + p_qp_attr->h_rq_cq = (ib_cq_handle_t)qp_p->ibqp.recv_cq; + p_qp_attr->sq_signaled = qp_p->sq_policy == IB_SIGNAL_ALL_WR; + p_qp_attr->state = mlnx_qps_to_ibal( qp_p->state ); + p_qp_attr->num = cl_hton32(qp_p->ibqp.qp_num); + p_qp_attr->primary_port = qp_p->qp_init_attr.port_num; + } + else { + //request the info from the card + err = ib_qp_p->device->query_qp( ib_qp_p, &qp_attr, + qp_attr_mask, &qp_init_attr); + if (err){ + status = errno_to_iberr(err); + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_PD, + ("ib_query_qp failed (%#x)\n", status)); + goto err_query_qp; + } + + // convert the results back to IBAL + status = mlnx_conv_qp_attr( ib_qp_p, &qp_attr, p_qp_attr ); + } + +err_query_qp: +err_parm: + HCA_EXIT(HCA_DBG_QP); + return status; +} + +ib_api_status_t +mlnx_destroy_qp ( + IN const ib_qp_handle_t h_qp, + IN const uint64_t timewait ) +{ + ib_api_status_t status; + int err; + struct ib_qp *ib_qp_p = (struct ib_qp *)h_qp; + + UNUSED_PARAM( timewait ); + + HCA_ENTER( HCA_DBG_QP); + + HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_SHIM , + ("qpnum %#x, pcs %p\n", ib_qp_p->qp_num, PsGetCurrentProcess()) ); + + err = ibv_destroy_qp( ib_qp_p ); + if (err) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_QP, + ("ibv_destroy_qp failed (%d)\n", err)); + status = errno_to_iberr(err); + goto err_destroy_qp; + } + + status = IB_SUCCESS; + +err_destroy_qp: + if (status != IB_SUCCESS) + { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_QP, + ("completes with ERROR status %#x\n", status)); + } + HCA_EXIT(HCA_DBG_QP); + return status; +} + +/* +* Completion Queue Managment Verbs. +*/ + +ib_api_status_t +mlnx_create_cq ( + IN const ib_ca_handle_t h_ca, + IN const void *cq_context, + IN ci_async_event_cb_t event_handler, + IN ci_completion_cb_t cq_comp_handler, + IN OUT uint32_t *p_size, + OUT ib_cq_handle_t *ph_cq, + IN OUT ci_umv_buf_t *p_umv_buf ) +{ + int err; + ib_api_status_t status; + struct ib_cq *ib_cq_p; + mlnx_hob_t *hob_p; + struct ib_device *ib_dev; + struct ib_ucontext *p_context; + + HCA_ENTER(HCA_DBG_CQ); + + if( p_umv_buf ) { + + p_context = (struct ib_ucontext *)h_ca; + hob_p = HOB_FROM_IBDEV(p_context->device); + ib_dev = p_context->device; + + // sanity checks + if (p_umv_buf->input_size < sizeof(struct ibv_create_cq) || + p_umv_buf->output_size < sizeof(struct ibv_create_cq_resp) || + !p_umv_buf->p_inout_buf) { + status = IB_INVALID_PARAMETER; + goto err_inval_params; + } + } + else { + hob_p = (mlnx_hob_t *)h_ca; + p_context = NULL; + ib_dev = IBDEV_FROM_HOB( hob_p ); + } + + /* sanity check */ + if (!*p_size || *p_size > (uint32_t)ib_dev->mdev->limits.max_cqes) { + status = IB_INVALID_CQ_SIZE; + goto err_cqe; + } + + // allocate cq + ib_cq_p = ibv_create_cq(ib_dev, + cq_comp_handler, event_handler, + (void*)cq_context, *p_size, p_context, p_umv_buf ); + if (IS_ERR(ib_cq_p)) { + err = PTR_ERR(ib_cq_p); + HCA_PRINT (TRACE_LEVEL_ERROR ,HCA_DBG_CQ, ("ibv_create_cq failed (%d)\n", err)); + status = errno_to_iberr(err); + goto err_create_cq; + } + + // return the result +// *p_size = *p_size; // return the same value + *p_size = ib_cq_p->cqe; + + if (ph_cq) *ph_cq = (ib_cq_handle_t)ib_cq_p; + + status = IB_SUCCESS; + +err_create_cq: +err_inval_params: +err_cqe: + if (p_umv_buf && p_umv_buf->command) + p_umv_buf->status = status; + if (status != IB_SUCCESS) + { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_CQ, + ("completes with ERROR status %#x\n", status)); + } + HCA_EXIT(HCA_DBG_CQ); + return status; +} + +ib_api_status_t +mlnx_resize_cq ( + IN const ib_cq_handle_t h_cq, + IN OUT uint32_t *p_size, + IN OUT ci_umv_buf_t *p_umv_buf ) +{ + UNREFERENCED_PARAMETER(h_cq); + UNREFERENCED_PARAMETER(p_size); + if (p_umv_buf && p_umv_buf->command) { + p_umv_buf->status = IB_UNSUPPORTED; + } + HCA_PRINT(TRACE_LEVEL_ERROR, HCA_DBG_CQ,("mlnx_resize_cq not implemented\n")); + return IB_UNSUPPORTED; +} + +ib_api_status_t +mlnx_query_cq ( + IN const ib_cq_handle_t h_cq, + OUT uint32_t *p_size, + IN OUT ci_umv_buf_t *p_umv_buf ) +{ + UNREFERENCED_PARAMETER(h_cq); + UNREFERENCED_PARAMETER(p_size); + if (p_umv_buf && p_umv_buf->command) { + p_umv_buf->status = IB_UNSUPPORTED; + } + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_CQ,("mlnx_query_cq not implemented\n")); + return IB_UNSUPPORTED; +} + +ib_api_status_t +mlnx_destroy_cq ( + IN const ib_cq_handle_t h_cq) +{ + + ib_api_status_t status; + int err; + struct ib_cq *ib_cq_p = (struct ib_cq *)h_cq; + + HCA_ENTER( HCA_DBG_QP); + + HCA_PRINT(TRACE_LEVEL_INFORMATION,HCA_DBG_CQ, + ("cqn %#x, pcs %p\n", ((struct mthca_cq*)ib_cq_p)->cqn, PsGetCurrentProcess()) ); + + // destroy CQ + err = ibv_destroy_cq( ib_cq_p ); + if (err) { + HCA_PRINT (TRACE_LEVEL_ERROR ,HCA_DBG_SHIM, + ("ibv_destroy_cq failed (%d)\n", err)); + status = errno_to_iberr(err); + goto err_destroy_cq; + } + + status = IB_SUCCESS; + +err_destroy_cq: + if (status != IB_SUCCESS) + { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_CQ, + ("completes with ERROR status %#x\n", status)); + } + HCA_EXIT(HCA_DBG_CQ); + return status; +} + + +ib_api_status_t +mlnx_local_mad ( + IN const ib_ca_handle_t h_ca, + IN const uint8_t port_num, + IN const ib_av_attr_t* p_av_attr, + IN const ib_mad_t *p_mad_in, + OUT ib_mad_t *p_mad_out ) +{ + int err; + ib_api_status_t status = IB_SUCCESS; + mlnx_hob_t *hob_p = (mlnx_hob_t *)h_ca; + struct ib_device *ib_dev = IBDEV_FROM_HOB( hob_p ); + //TODO: do we need use flags (IB_MAD_IGNORE_MKEY, IB_MAD_IGNORE_BKEY) ? + int mad_flags = 0; + struct _ib_wc *wc_p = NULL; + //TODO: do we need use grh ? + struct _ib_grh *grh_p = NULL; + + HCA_ENTER(HCA_DBG_MAD); + + // sanity checks + if (port_num > 2) { + status = IB_INVALID_PARAMETER; + goto err_port_num; + } + + if (p_av_attr){ + wc_p = cl_zalloc(sizeof(struct _ib_wc)); + if(!wc_p){ + status = IB_INSUFFICIENT_MEMORY ; + goto err_wc_alloc; + } + //Copy part of the attributes need to fill the mad extended fields in mellanox devices + wc_p->recv.ud.remote_lid = p_av_attr->dlid; + wc_p->recv.ud.remote_sl = p_av_attr->sl; + wc_p->recv.ud.path_bits = p_av_attr->path_bits; + wc_p->recv.ud.recv_opt = p_av_attr->grh_valid?IB_RECV_OPT_GRH_VALID:0; + + if(wc_p->recv.ud.recv_opt &IB_RECV_OPT_GRH_VALID){ + grh_p = cl_zalloc(sizeof(struct _ib_grh)); + if(!grh_p){ + status = IB_INSUFFICIENT_MEMORY ; + goto err_grh_alloc; + } + cl_memcpy(grh_p, &p_av_attr->grh, sizeof(ib_grh_t)); + } + + + } + + HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_MAD, + ("MAD: Class %02x, Method %02x, Attr %02x, HopPtr %d, HopCnt %d, \n", + (uint32_t)((ib_smp_t *)p_mad_in)->mgmt_class, + (uint32_t)((ib_smp_t *)p_mad_in)->method, + (uint32_t)((ib_smp_t *)p_mad_in)->attr_id, + (uint32_t)((ib_smp_t *)p_mad_in)->hop_ptr, + (uint32_t)((ib_smp_t *)p_mad_in)->hop_count)); + + + // process mad + + err = mthca_process_mad(ib_dev, mad_flags, (uint8_t)port_num, + wc_p, grh_p, (struct ib_mad*)p_mad_in, (struct ib_mad*)p_mad_out); + if (!err) { + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_MAD, + ("MAD failed:\n\tClass 0x%x\n\tMethod 0x%x\n\tAttr 0x%x", + p_mad_in->mgmt_class, p_mad_in->method, p_mad_in->attr_id )); + status = IB_ERROR; + goto err_process_mad; + } + + if( (p_mad_in->mgmt_class == IB_MCLASS_SUBN_DIR || + p_mad_in->mgmt_class == IB_MCLASS_SUBN_LID) && + p_mad_in->attr_id == IB_MAD_ATTR_PORT_INFO ) + { + ib_port_info_t *p_pi_in, *p_pi_out; + + if( p_mad_in->mgmt_class == IB_MCLASS_SUBN_DIR ) + { + p_pi_in = (ib_port_info_t*) + ib_smp_get_payload_ptr( (ib_smp_t*)p_mad_in ); + p_pi_out = (ib_port_info_t*) + ib_smp_get_payload_ptr( (ib_smp_t*)p_mad_out ); + } + else + { + p_pi_in = (ib_port_info_t*)(p_mad_in + 1); + p_pi_out = (ib_port_info_t*)(p_mad_out + 1); + } + + /* Work around FW bug 33958 */ + p_pi_out->subnet_timeout &= 0x7F; + if( p_mad_in->method == IB_MAD_METHOD_SET ) + p_pi_out->subnet_timeout |= (p_pi_in->subnet_timeout & 0x80); + } + + /* Modify direction for Direct MAD */ + if ( p_mad_in->mgmt_class == IB_MCLASS_SUBN_DIR ) + p_mad_out->status |= IB_SMP_DIRECTION; + + +err_process_mad: + if(grh_p) + cl_free(grh_p); +err_grh_alloc: + if(wc_p) + cl_free(wc_p); +err_wc_alloc: +err_port_num: + if (status != IB_SUCCESS) + { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_MAD, + ("completes with ERROR status %#x\n", status)); + } + HCA_EXIT(HCA_DBG_MAD); + return status; +} + + +void +setup_ci_interface( + IN const ib_net64_t ca_guid, + IN OUT ci_interface_t *p_interface ) +{ + cl_memclr(p_interface, sizeof(*p_interface)); + + /* Guid of the CA. */ + p_interface->guid = ca_guid; + + /* Version of this interface. */ + p_interface->version = VERBS_VERSION; + + /* UVP name */ + cl_memcpy( p_interface->libname, mlnx_uvp_lib_name, MAX_LIB_NAME); + + HCA_PRINT(TRACE_LEVEL_VERBOSE , HCA_DBG_SHIM ,("UVP filename %s\n", p_interface->libname)); + + /* The real interface. */ + p_interface->open_ca = mlnx_open_ca; + p_interface->modify_ca = mlnx_modify_ca; + p_interface->query_ca = mlnx_query_ca; + p_interface->close_ca = mlnx_close_ca; + p_interface->um_open_ca = mlnx_um_open; + p_interface->um_close_ca = mlnx_um_close; + p_interface->register_event_handler = mlnx_register_event_handler; + p_interface->unregister_event_handler = mlnx_unregister_event_handler; + + p_interface->allocate_pd = mlnx_allocate_pd; + p_interface->deallocate_pd = mlnx_deallocate_pd; + p_interface->vendor_call = fw_access_ctrl; + + p_interface->create_av = mlnx_create_av; + p_interface->query_av = mlnx_query_av; + p_interface->modify_av = mlnx_modify_av; + p_interface->destroy_av = mlnx_destroy_av; + + p_interface->create_srq = mlnx_create_srq; + p_interface->modify_srq = mlnx_modify_srq; + p_interface->query_srq = mlnx_query_srq; + p_interface->destroy_srq = mlnx_destroy_srq; + + p_interface->create_qp = mlnx_create_qp; + p_interface->create_spl_qp = mlnx_create_spl_qp; + p_interface->modify_qp = mlnx_modify_qp; + p_interface->ndi_modify_qp = mlnx_ndi_modify_qp; + p_interface->query_qp = mlnx_query_qp; + p_interface->destroy_qp = mlnx_destroy_qp; + + p_interface->create_cq = mlnx_create_cq; + p_interface->resize_cq = mlnx_resize_cq; + p_interface->query_cq = mlnx_query_cq; + p_interface->destroy_cq = mlnx_destroy_cq; + + p_interface->local_mad = mlnx_local_mad; + + + mlnx_memory_if(p_interface); + mlnx_direct_if(p_interface); + mlnx_mcast_if(p_interface); + + return; +} + + diff --git a/branches/WOF2-3/hw/mthca/kernel/ib_cache.h b/branches/WOF2-3/hw/mthca/kernel/ib_cache.h new file mode 100644 index 00000000..a1105b8f --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/ib_cache.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2004 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Intel Corporation. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#ifndef _IB_CACHE_H +#define _IB_CACHE_H + +#include + +/** + * ib_get_cached_gid - Returns a cached GID table entry + * @device: The device to query. + * @port_num: The port number of the device to query. + * @index: The index into the cached GID table to query. + * @gid: The GID value found at the specified index. + * + * ib_get_cached_gid() fetches the specified GID table entry stored in + * the local software cache. + */ +int ib_get_cached_gid(struct ib_device *device, + u8 port_num, + int index, + union ib_gid *gid); + +/** + * ib_find_cached_gid - Returns the port number and GID table index where + * a specified GID value occurs. + * @device: The device to query. + * @gid: The GID value to search for. + * @port_num: The port number of the device where the GID value was found. + * @index: The index into the cached GID table where the GID was found. This + * parameter may be NULL. + * + * ib_find_cached_gid() searches for the specified GID value in + * the local software cache. + */ +int ib_find_cached_gid(struct ib_device *device, + union ib_gid *gid, + u8 *port_num, + u16 *index); + +/** + * ib_get_cached_pkey - Returns a cached PKey table entry + * @device: The device to query. + * @port_num: The port number of the device to query. + * @index: The index into the cached PKey table to query. + * @pkey: The PKey value found at the specified index. + * + * ib_get_cached_pkey() fetches the specified PKey table entry stored in + * the local software cache. + */ +int ib_get_cached_pkey(struct ib_device *device_handle, + u8 port_num, + int index, + __be16 *pkey); + +/** + * ib_find_cached_pkey - Returns the PKey table index where a specified + * PKey value occurs. + * @device: The device to query. + * @port_num: The port number of the device to search for the PKey. + * @pkey: The PKey value to search for. + * @index: The index into the cached PKey table where the PKey was found. + * + * ib_find_cached_pkey() searches the specified PKey table in + * the local software cache. + */ +int ib_find_cached_pkey(struct ib_device *device, + u8 port_num, + __be16 pkey, + u16 *index); + + +int ib_cache_setup(void); +void ib_cache_cleanup(void); + +#endif /* _IB_CACHE_H */ diff --git a/branches/WOF2-3/hw/mthca/kernel/ib_mad.h b/branches/WOF2-3/hw/mthca/kernel/ib_mad.h new file mode 100644 index 00000000..e8a80806 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/ib_mad.h @@ -0,0 +1,579 @@ +/* + * Copyright (c) 2004 Mellanox Technologies Ltd. All rights reserved. + * Copyright (c) 2004 Infinicon Corporation. All rights reserved. + * Copyright (c) 2004 Intel Corporation. All rights reserved. + * Copyright (c) 2004 Topspin Corporation. All rights reserved. + * Copyright (c) 2004 Voltaire Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#if !defined( IB_MAD_H ) +#define IB_MAD_H + +#include + +/* Management base version */ +#define IB_MGMT_BASE_VERSION 1 + +/* Management classes */ +#define IB_MGMT_CLASS_SUBN_LID_ROUTED 0x01 +#define IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE 0x81 +#define IB_MGMT_CLASS_SUBN_ADM 0x03 +#define IB_MGMT_CLASS_PERF_MGMT 0x04 +#define IB_MGMT_CLASS_BM 0x05 +#define IB_MGMT_CLASS_DEVICE_MGMT 0x06 +#define IB_MGMT_CLASS_CM 0x07 +#define IB_MGMT_CLASS_SNMP 0x08 +#define IB_MGMT_CLASS_VENDOR_RANGE2_START 0x30 +#define IB_MGMT_CLASS_VENDOR_RANGE2_END 0x4F + +#define IB_OPENIB_OUI (0x001405) + +/* Management methods */ +#define IB_MGMT_METHOD_GET 0x01 +#define IB_MGMT_METHOD_SET 0x02 +#define IB_MGMT_METHOD_GET_RESP 0x81 +#define IB_MGMT_METHOD_SEND 0x03 +#define IB_MGMT_METHOD_TRAP 0x05 +#define IB_MGMT_METHOD_REPORT 0x06 +#define IB_MGMT_METHOD_REPORT_RESP 0x86 +#define IB_MGMT_METHOD_TRAP_REPRESS 0x07 + +#define IB_MGMT_METHOD_RESP 0x80 + +#define IB_MGMT_MAX_METHODS 128 + +/* RMPP information */ +#define IB_MGMT_RMPP_VERSION 1 + +#define IB_MGMT_RMPP_TYPE_DATA 1 +#define IB_MGMT_RMPP_TYPE_ACK 2 +#define IB_MGMT_RMPP_TYPE_STOP 3 +#define IB_MGMT_RMPP_TYPE_ABORT 4 + +#define IB_MGMT_RMPP_FLAG_ACTIVE 1 +#define IB_MGMT_RMPP_FLAG_FIRST (1<<1) +#define IB_MGMT_RMPP_FLAG_LAST (1<<2) + +#define IB_MGMT_RMPP_NO_RESPTIME 0x1F + +#define IB_MGMT_RMPP_STATUS_SUCCESS 0 +#define IB_MGMT_RMPP_STATUS_RESX 1 +#define IB_MGMT_RMPP_STATUS_ABORT_MIN 118 +#define IB_MGMT_RMPP_STATUS_T2L 118 +#define IB_MGMT_RMPP_STATUS_BAD_LEN 119 +#define IB_MGMT_RMPP_STATUS_BAD_SEG 120 +#define IB_MGMT_RMPP_STATUS_BADT 121 +#define IB_MGMT_RMPP_STATUS_W2S 122 +#define IB_MGMT_RMPP_STATUS_S2B 123 +#define IB_MGMT_RMPP_STATUS_BAD_STATUS 124 +#define IB_MGMT_RMPP_STATUS_UNV 125 +#define IB_MGMT_RMPP_STATUS_TMR 126 +#define IB_MGMT_RMPP_STATUS_UNSPEC 127 +#define IB_MGMT_RMPP_STATUS_ABORT_MAX 127 + +#define IB_QP1_QKEY 0x00000180 /* big endian */ +#define IB_QP_SET_QKEY 0x00000080 /* big endian */ + +struct ib_mad_hdr { + u8 base_version; + u8 mgmt_class; + u8 class_version; + u8 method; + __be16 status; + __be16 class_specific; + __be64 tid; + __be16 attr_id; + __be16 resv; + __be32 attr_mod; +}; + +struct ib_rmpp_hdr { + u8 rmpp_version; + u8 rmpp_type; + u8 rmpp_rtime_flags; + u8 rmpp_status; + __be32 seg_num; + __be32 paylen_newwin; +}; + +typedef u64 ib_sa_comp_mask; + +#define IB_SA_COMP_MASK(n) ((ib_sa_comp_mask) cl_hton64(1ull << n)) + +/* + * ib_sa_hdr and ib_sa_mad structures must be packed because they have + * 64-bit fields that are only 32-bit aligned. 64-bit architectures will + * lay them out wrong otherwise. (And unfortunately they are sent on + * the wire so we can't change the layout) + */ +#pragma pack(push,1) +struct ib_sa_hdr { + __be64 sm_key; + __be16 attr_offset; + __be16 reserved; + ib_sa_comp_mask comp_mask; +}; +#pragma pack(pop) + +struct ib_mad { + struct ib_mad_hdr mad_hdr; + u8 data[232]; +}; + +struct ib_rmpp_mad { + struct ib_mad_hdr mad_hdr; + struct ib_rmpp_hdr rmpp_hdr; + u8 data[220]; +}; + +#pragma pack(push,1) +struct ib_sa_mad { + struct ib_mad_hdr mad_hdr; + struct ib_rmpp_hdr rmpp_hdr; + struct ib_sa_hdr sa_hdr; + u8 data[200]; +}; +#pragma pack(pop) + +struct ib_vendor_mad { + struct ib_mad_hdr mad_hdr; + struct ib_rmpp_hdr rmpp_hdr; + u8 reserved; + u8 oui[3]; + u8 data[216]; +}; + +/** + * ib_mad_send_buf - MAD data buffer and work request for sends. + * @mad: References an allocated MAD data buffer. The size of the data + * buffer is specified in the @send_wr.length field. + * @mapping: DMA mapping information. + * @mad_agent: MAD agent that allocated the buffer. + * @context: User-controlled context fields. + * @send_wr: An initialized work request structure used when sending the MAD. + * The wr_id field of the work request is initialized to reference this + * data structure. + * @sge: A scatter-gather list referenced by the work request. + * + * Users are responsible for initializing the MAD buffer itself, with the + * exception of specifying the payload length field in any RMPP MAD. + */ +struct ib_mad_send_buf { + struct ib_mad *mad; + dma_addr_t mapping; + struct ib_mad_agent *mad_agent; + void *context[2]; + struct _ib_send_wr send_wr; + struct ib_sge sge; +}; + +/** + * ib_get_rmpp_resptime - Returns the RMPP response time. + * @rmpp_hdr: An RMPP header. + */ +static inline u8 ib_get_rmpp_resptime(struct ib_rmpp_hdr *rmpp_hdr) +{ + return rmpp_hdr->rmpp_rtime_flags >> 3; +} + +/** + * ib_get_rmpp_flags - Returns the RMPP flags. + * @rmpp_hdr: An RMPP header. + */ +static inline u8 ib_get_rmpp_flags(struct ib_rmpp_hdr *rmpp_hdr) +{ + return rmpp_hdr->rmpp_rtime_flags & 0x7; +} + +/** + * ib_set_rmpp_resptime - Sets the response time in an RMPP header. + * @rmpp_hdr: An RMPP header. + * @rtime: The response time to set. + */ +static inline void ib_set_rmpp_resptime(struct ib_rmpp_hdr *rmpp_hdr, u8 rtime) +{ + rmpp_hdr->rmpp_rtime_flags = ib_get_rmpp_flags(rmpp_hdr) | (rtime << 3); +} + +/** + * ib_set_rmpp_flags - Sets the flags in an RMPP header. + * @rmpp_hdr: An RMPP header. + * @flags: The flags to set. + */ +static inline void ib_set_rmpp_flags(struct ib_rmpp_hdr *rmpp_hdr, u8 flags) +{ + rmpp_hdr->rmpp_rtime_flags = (rmpp_hdr->rmpp_rtime_flags & 0xF1) | + (flags & 0x7); +} + +struct ib_mad_agent; +struct ib_mad_send_wc; +struct ib_mad_recv_wc; + +/** + * ib_mad_send_handler - callback handler for a sent MAD. + * @mad_agent: MAD agent that sent the MAD. + * @mad_send_wc: Send work completion information on the sent MAD. + */ +typedef void (*ib_mad_send_handler)(struct ib_mad_agent *mad_agent, + struct ib_mad_send_wc *mad_send_wc); + +/** + * ib_mad_snoop_handler - Callback handler for snooping sent MADs. + * @mad_agent: MAD agent that snooped the MAD. + * @send_wr: Work request information on the sent MAD. + * @mad_send_wc: Work completion information on the sent MAD. Valid + * only for snooping that occurs on a send completion. + * + * Clients snooping MADs should not modify data referenced by the @send_wr + * or @mad_send_wc. + */ +typedef void (*ib_mad_snoop_handler)(struct ib_mad_agent *mad_agent, + struct _ib_send_wr *send_wr, + struct ib_mad_send_wc *mad_send_wc); + +/** + * ib_mad_recv_handler - callback handler for a received MAD. + * @mad_agent: MAD agent requesting the received MAD. + * @mad_recv_wc: Received work completion information on the received MAD. + * + * MADs received in response to a send request operation will be handed to + * the user after the send operation completes. All data buffers given + * to registered agents through this routine are owned by the receiving + * client, except for snooping agents. Clients snooping MADs should not + * modify the data referenced by @mad_recv_wc. + */ +typedef void (*ib_mad_recv_handler)(struct ib_mad_agent *mad_agent, + struct ib_mad_recv_wc *mad_recv_wc); + +/** + * ib_mad_agent - Used to track MAD registration with the access layer. + * @device: Reference to device registration is on. + * @qp: Reference to QP used for sending and receiving MADs. + * @mr: Memory region for system memory usable for DMA. + * @recv_handler: Callback handler for a received MAD. + * @send_handler: Callback handler for a sent MAD. + * @snoop_handler: Callback handler for snooped sent MADs. + * @context: User-specified context associated with this registration. + * @hi_tid: Access layer assigned transaction ID for this client. + * Unsolicited MADs sent by this client will have the upper 32-bits + * of their TID set to this value. + * @port_num: Port number on which QP is registered + * @rmpp_version: If set, indicates the RMPP version used by this agent. + */ +struct ib_mad_agent { + struct ib_device *device; + struct ib_qp *qp; + struct ib_mr *mr; + ib_mad_recv_handler recv_handler; + ib_mad_send_handler send_handler; + ib_mad_snoop_handler snoop_handler; + void *context; + u32 hi_tid; + u8 port_num; + u8 rmpp_version; +}; + +/** + * ib_mad_send_wc - MAD send completion information. + * @wr_id: Work request identifier associated with the send MAD request. + * @status: Completion status. + * @vendor_err: Optional vendor error information returned with a failed + * request. + */ +struct ib_mad_send_wc { + u64 wr_id; + enum ib_wc_status status; + u32 vendor_err; +}; + +/** + * ib_mad_recv_buf - received MAD buffer information. + * @list: Reference to next data buffer for a received RMPP MAD. + * @grh: References a data buffer containing the global route header. + * The data refereced by this buffer is only valid if the GRH is + * valid. + * @mad: References the start of the received MAD. + */ +struct ib_mad_recv_buf { + struct list_head list; + struct ib_grh *grh; + struct ib_mad *mad; +}; + +/** + * ib_mad_recv_wc - received MAD information. + * @wc: Completion information for the received data. + * @recv_buf: Specifies the location of the received data buffer(s). + * @rmpp_list: Specifies a list of RMPP reassembled received MAD buffers. + * @mad_len: The length of the received MAD, without duplicated headers. + * + * For received response, the wr_id field of the wc is set to the wr_id + * for the corresponding send request. + */ +struct ib_mad_recv_wc { + struct _ib_wc *wc; + struct ib_mad_recv_buf recv_buf; + struct list_head rmpp_list; + int mad_len; +}; + +/** + * ib_mad_reg_req - MAD registration request + * @mgmt_class: Indicates which management class of MADs should be receive + * by the caller. This field is only required if the user wishes to + * receive unsolicited MADs, otherwise it should be 0. + * @mgmt_class_version: Indicates which version of MADs for the given + * management class to receive. + * @oui: Indicates IEEE OUI when mgmt_class is a vendor class + * in the range from 0x30 to 0x4f. Otherwise not used. + * @method_mask: The caller will receive unsolicited MADs for any method + * where @method_mask = 1. + */ +struct ib_mad_reg_req { + u8 mgmt_class; + u8 mgmt_class_version; + u8 oui[3]; + DECLARE_BITMAP(method_mask, IB_MGMT_MAX_METHODS); +}; + +/** + * ib_register_mad_agent - Register to send/receive MADs. + * @device: The device to register with. + * @port_num: The port on the specified device to use. + * @qp_type: Specifies which QP to access. Must be either + * IB_QPT_QP0 or IB_QPT_QP1. + * @mad_reg_req: Specifies which unsolicited MADs should be received + * by the caller. This parameter may be NULL if the caller only + * wishes to receive solicited responses. + * @rmpp_version: If set, indicates that the client will send + * and receive MADs that contain the RMPP header for the given version. + * If set to 0, indicates that RMPP is not used by this client. + * @send_handler: The completion callback routine invoked after a send + * request has completed. + * @recv_handler: The completion callback routine invoked for a received + * MAD. + * @context: User specified context associated with the registration. + */ +struct ib_mad_agent *ib_register_mad_agent(struct ib_device *device, + u8 port_num, + enum ib_qp_type_t qp_type, + struct ib_mad_reg_req *mad_reg_req, + u8 rmpp_version, + ib_mad_send_handler send_handler, + ib_mad_recv_handler recv_handler, + void *context); + +enum ib_mad_snoop_flags { + /*IB_MAD_SNOOP_POSTED_SENDS = 1,*/ + /*IB_MAD_SNOOP_RMPP_SENDS = (1<<1),*/ + IB_MAD_SNOOP_SEND_COMPLETIONS = (1<<2), + /*IB_MAD_SNOOP_RMPP_SEND_COMPLETIONS = (1<<3),*/ + IB_MAD_SNOOP_RECVS = (1<<4) + /*IB_MAD_SNOOP_RMPP_RECVS = (1<<5),*/ + /*IB_MAD_SNOOP_REDIRECTED_QPS = (1<<6)*/ +}; + +/** + * ib_register_mad_snoop - Register to snoop sent and received MADs. + * @device: The device to register with. + * @port_num: The port on the specified device to use. + * @qp_type: Specifies which QP traffic to snoop. Must be either + * IB_QPT_QP0 or IB_QPT_QP1. + * @mad_snoop_flags: Specifies information where snooping occurs. + * @send_handler: The callback routine invoked for a snooped send. + * @recv_handler: The callback routine invoked for a snooped receive. + * @context: User specified context associated with the registration. + */ +struct ib_mad_agent *ib_register_mad_snoop(struct ib_device *device, + u8 port_num, + enum ib_qp_type_t qp_type, + int mad_snoop_flags, + ib_mad_snoop_handler snoop_handler, + ib_mad_recv_handler recv_handler, + void *context); + +/** + * ib_unregister_mad_agent - Unregisters a client from using MAD services. + * @mad_agent: Corresponding MAD registration request to deregister. + * + * After invoking this routine, MAD services are no longer usable by the + * client on the associated QP. + */ +int ib_unregister_mad_agent(struct ib_mad_agent *mad_agent); + +/** + * ib_post_send_mad - Posts MAD(s) to the send queue of the QP associated + * with the registered client. + * @mad_agent: Specifies the associated registration to post the send to. + * @send_wr: Specifies the information needed to send the MAD(s). + * @bad_send_wr: Specifies the MAD on which an error was encountered. + * + * Sent MADs are not guaranteed to complete in the order that they were posted. + * + * If the MAD requires RMPP, the data buffer should contain a single copy + * of the common MAD, RMPP, and class specific headers, followed by the class + * defined data. If the class defined data would not divide evenly into + * RMPP segments, then space must be allocated at the end of the referenced + * buffer for any required padding. To indicate the amount of class defined + * data being transferred, the paylen_newwin field in the RMPP header should + * be set to the size of the class specific header plus the amount of class + * defined data being transferred. The paylen_newwin field should be + * specified in network-byte order. + */ +int ib_post_send_mad(struct ib_mad_agent *mad_agent, + struct _ib_send_wr *send_wr, + struct _ib_send_wr **bad_send_wr); + +/** + * ib_coalesce_recv_mad - Coalesces received MAD data into a single buffer. + * @mad_recv_wc: Work completion information for a received MAD. + * @buf: User-provided data buffer to receive the coalesced buffers. The + * referenced buffer should be at least the size of the mad_len specified + * by @mad_recv_wc. + * + * This call copies a chain of received MAD segments into a single data buffer, + * removing duplicated headers. + */ +void ib_coalesce_recv_mad(struct ib_mad_recv_wc *mad_recv_wc, void *buf); + +/** + * ib_free_recv_mad - Returns data buffers used to receive a MAD. + * @mad_recv_wc: Work completion information for a received MAD. + * + * Clients receiving MADs through their ib_mad_recv_handler must call this + * routine to return the work completion buffers to the access layer. + */ +void ib_free_recv_mad(struct ib_mad_recv_wc *mad_recv_wc); + +/** + * ib_cancel_mad - Cancels an outstanding send MAD operation. + * @mad_agent: Specifies the registration associated with sent MAD. + * @wr_id: Indicates the work request identifier of the MAD to cancel. + * + * MADs will be returned to the user through the corresponding + * ib_mad_send_handler. + */ +void ib_cancel_mad(struct ib_mad_agent *mad_agent, u64 wr_id); + +/** + * ib_modify_mad - Modifies an outstanding send MAD operation. + * @mad_agent: Specifies the registration associated with sent MAD. + * @wr_id: Indicates the work request identifier of the MAD to modify. + * @timeout_ms: New timeout value for sent MAD. + * + * This call will reset the timeout value for a sent MAD to the specified + * value. + */ +int ib_modify_mad(struct ib_mad_agent *mad_agent, u64 wr_id, u32 timeout_ms); + +/** + * ib_redirect_mad_qp - Registers a QP for MAD services. + * @qp: Reference to a QP that requires MAD services. + * @rmpp_version: If set, indicates that the client will send + * and receive MADs that contain the RMPP header for the given version. + * If set to 0, indicates that RMPP is not used by this client. + * @send_handler: The completion callback routine invoked after a send + * request has completed. + * @recv_handler: The completion callback routine invoked for a received + * MAD. + * @context: User specified context associated with the registration. + * + * Use of this call allows clients to use MAD services, such as RMPP, + * on user-owned QPs. After calling this routine, users may send + * MADs on the specified QP by calling ib_mad_post_send. + */ +struct ib_mad_agent *ib_redirect_mad_qp(struct ib_qp *qp, + u8 rmpp_version, + ib_mad_send_handler send_handler, + ib_mad_recv_handler recv_handler, + void *context); + +/** + * ib_process_mad_wc - Processes a work completion associated with a + * MAD sent or received on a redirected QP. + * @mad_agent: Specifies the registered MAD service using the redirected QP. + * @wc: References a work completion associated with a sent or received + * MAD segment. + * + * This routine is used to complete or continue processing on a MAD request. + * If the work completion is associated with a send operation, calling + * this routine is required to continue an RMPP transfer or to wait for a + * corresponding response, if it is a request. If the work completion is + * associated with a receive operation, calling this routine is required to + * process an inbound or outbound RMPP transfer, or to match a response MAD + * with its corresponding request. + */ +int ib_process_mad_wc(struct ib_mad_agent *mad_agent, + struct _ib_wc *wc); + +/** + * ib_create_send_mad - Allocate and initialize a data buffer and work request + * for sending a MAD. + * @mad_agent: Specifies the registered MAD service to associate with the MAD. + * @remote_qpn: Specifies the QPN of the receiving node. + * @pkey_index: Specifies which PKey the MAD will be sent using. This field + * is valid only if the remote_qpn is QP 1. + * @ah: References the address handle used to transfer to the remote node. + * @rmpp_active: Indicates if the send will enable RMPP. + * @hdr_len: Indicates the size of the data header of the MAD. This length + * should include the common MAD header, RMPP header, plus any class + * specific header. + * @data_len: Indicates the size of any user-transferred data. The call will + * automatically adjust the allocated buffer size to account for any + * additional padding that may be necessary. + * @gfp_mask: GFP mask used for the memory allocation. + * + * This is a helper routine that may be used to allocate a MAD. Users are + * not required to allocate outbound MADs using this call. The returned + * MAD send buffer will reference a data buffer usable for sending a MAD, along + * with an initialized work request structure. Users may modify the returned + * MAD data buffer or work request before posting the send. + * + * The returned data buffer will be cleared. Users are responsible for + * initializing the common MAD and any class specific headers. If @rmpp_active + * is set, the RMPP header will be initialized for sending. + */ +struct ib_mad_send_buf * ib_create_send_mad(struct ib_mad_agent *mad_agent, + u32 remote_qpn, u16 pkey_index, + struct ib_ah *ah, int rmpp_active, + int hdr_len, int data_len, + unsigned int gfp_mask); + +/** + * ib_free_send_mad - Returns data buffers used to send a MAD. + * @send_buf: Previously allocated send data buffer. + */ +void ib_free_send_mad(struct ib_mad_send_buf *send_buf); + +#endif /* IB_MAD_H */ diff --git a/branches/WOF2-3/hw/mthca/kernel/ib_pack.h b/branches/WOF2-3/hw/mthca/kernel/ib_pack.h new file mode 100644 index 00000000..deb42e6c --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/ib_pack.h @@ -0,0 +1,245 @@ +/* + * Copyright (c) 2004 Topspin Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#ifndef IB_PACK_H +#define IB_PACK_H + +#include + +enum { + IB_LRH_BYTES = 8, + IB_GRH_BYTES = 40, + IB_BTH_BYTES = 12, + IB_DETH_BYTES = 8 +}; + +struct ib_field { + int struct_offset_bytes; + int struct_size_bytes; + int offset_words; + int offset_bits; + int size_bits; + char *field_name; +}; + +#define RESERVED \ + .field_name = "reserved" + +/* + * This macro cleans up the definitions of constants for BTH opcodes. + * It is used to define constants such as IB_OPCODE_UD_SEND_ONLY, + * which becomes IB_OPCODE_UD + IB_OPCODE_SEND_ONLY, and this gives + * the correct value. + * + * In short, user code should use the constants defined using the + * macro rather than worrying about adding together other constants. +*/ +#define IB_OPCODE(transport, op) \ + IB_OPCODE_ ## transport ## _ ## op = \ + IB_OPCODE_ ## transport + IB_OPCODE_ ## op + +enum { + /* transport types -- just used to define real constants */ + IB_OPCODE_RC = 0x00, + IB_OPCODE_UC = 0x20, + IB_OPCODE_RD = 0x40, + IB_OPCODE_UD = 0x60, + + /* operations -- just used to define real constants */ + IB_OPCODE_SEND_FIRST = 0x00, + IB_OPCODE_SEND_MIDDLE = 0x01, + IB_OPCODE_SEND_LAST = 0x02, + IB_OPCODE_SEND_LAST_WITH_IMMEDIATE = 0x03, + IB_OPCODE_SEND_ONLY = 0x04, + IB_OPCODE_SEND_ONLY_WITH_IMMEDIATE = 0x05, + IB_OPCODE_RDMA_WRITE_FIRST = 0x06, + IB_OPCODE_RDMA_WRITE_MIDDLE = 0x07, + IB_OPCODE_RDMA_WRITE_LAST = 0x08, + IB_OPCODE_RDMA_WRITE_LAST_WITH_IMMEDIATE = 0x09, + IB_OPCODE_RDMA_WRITE_ONLY = 0x0a, + IB_OPCODE_RDMA_WRITE_ONLY_WITH_IMMEDIATE = 0x0b, + IB_OPCODE_RDMA_READ_REQUEST = 0x0c, + IB_OPCODE_RDMA_READ_RESPONSE_FIRST = 0x0d, + IB_OPCODE_RDMA_READ_RESPONSE_MIDDLE = 0x0e, + IB_OPCODE_RDMA_READ_RESPONSE_LAST = 0x0f, + IB_OPCODE_RDMA_READ_RESPONSE_ONLY = 0x10, + IB_OPCODE_ACKNOWLEDGE = 0x11, + IB_OPCODE_ATOMIC_ACKNOWLEDGE = 0x12, + IB_OPCODE_COMPARE_SWAP = 0x13, + IB_OPCODE_FETCH_ADD = 0x14, + + /* real constants follow -- see comment about above IB_OPCODE() + macro for more details */ + + /* RC */ + IB_OPCODE(RC, SEND_FIRST), + IB_OPCODE(RC, SEND_MIDDLE), + IB_OPCODE(RC, SEND_LAST), + IB_OPCODE(RC, SEND_LAST_WITH_IMMEDIATE), + IB_OPCODE(RC, SEND_ONLY), + IB_OPCODE(RC, SEND_ONLY_WITH_IMMEDIATE), + IB_OPCODE(RC, RDMA_WRITE_FIRST), + IB_OPCODE(RC, RDMA_WRITE_MIDDLE), + IB_OPCODE(RC, RDMA_WRITE_LAST), + IB_OPCODE(RC, RDMA_WRITE_LAST_WITH_IMMEDIATE), + IB_OPCODE(RC, RDMA_WRITE_ONLY), + IB_OPCODE(RC, RDMA_WRITE_ONLY_WITH_IMMEDIATE), + IB_OPCODE(RC, RDMA_READ_REQUEST), + IB_OPCODE(RC, RDMA_READ_RESPONSE_FIRST), + IB_OPCODE(RC, RDMA_READ_RESPONSE_MIDDLE), + IB_OPCODE(RC, RDMA_READ_RESPONSE_LAST), + IB_OPCODE(RC, RDMA_READ_RESPONSE_ONLY), + IB_OPCODE(RC, ACKNOWLEDGE), + IB_OPCODE(RC, ATOMIC_ACKNOWLEDGE), + IB_OPCODE(RC, COMPARE_SWAP), + IB_OPCODE(RC, FETCH_ADD), + + /* UC */ + IB_OPCODE(UC, SEND_FIRST), + IB_OPCODE(UC, SEND_MIDDLE), + IB_OPCODE(UC, SEND_LAST), + IB_OPCODE(UC, SEND_LAST_WITH_IMMEDIATE), + IB_OPCODE(UC, SEND_ONLY), + IB_OPCODE(UC, SEND_ONLY_WITH_IMMEDIATE), + IB_OPCODE(UC, RDMA_WRITE_FIRST), + IB_OPCODE(UC, RDMA_WRITE_MIDDLE), + IB_OPCODE(UC, RDMA_WRITE_LAST), + IB_OPCODE(UC, RDMA_WRITE_LAST_WITH_IMMEDIATE), + IB_OPCODE(UC, RDMA_WRITE_ONLY), + IB_OPCODE(UC, RDMA_WRITE_ONLY_WITH_IMMEDIATE), + + /* RD */ + IB_OPCODE(RD, SEND_FIRST), + IB_OPCODE(RD, SEND_MIDDLE), + IB_OPCODE(RD, SEND_LAST), + IB_OPCODE(RD, SEND_LAST_WITH_IMMEDIATE), + IB_OPCODE(RD, SEND_ONLY), + IB_OPCODE(RD, SEND_ONLY_WITH_IMMEDIATE), + IB_OPCODE(RD, RDMA_WRITE_FIRST), + IB_OPCODE(RD, RDMA_WRITE_MIDDLE), + IB_OPCODE(RD, RDMA_WRITE_LAST), + IB_OPCODE(RD, RDMA_WRITE_LAST_WITH_IMMEDIATE), + IB_OPCODE(RD, RDMA_WRITE_ONLY), + IB_OPCODE(RD, RDMA_WRITE_ONLY_WITH_IMMEDIATE), + IB_OPCODE(RD, RDMA_READ_REQUEST), + IB_OPCODE(RD, RDMA_READ_RESPONSE_FIRST), + IB_OPCODE(RD, RDMA_READ_RESPONSE_MIDDLE), + IB_OPCODE(RD, RDMA_READ_RESPONSE_LAST), + IB_OPCODE(RD, RDMA_READ_RESPONSE_ONLY), + IB_OPCODE(RD, ACKNOWLEDGE), + IB_OPCODE(RD, ATOMIC_ACKNOWLEDGE), + IB_OPCODE(RD, COMPARE_SWAP), + IB_OPCODE(RD, FETCH_ADD), + + /* UD */ + IB_OPCODE(UD, SEND_ONLY), + IB_OPCODE(UD, SEND_ONLY_WITH_IMMEDIATE) +}; + +enum { + IB_LNH_RAW = 0, + IB_LNH_IP = 1, + IB_LNH_IBA_LOCAL = 2, + IB_LNH_IBA_GLOBAL = 3 +}; + +struct ib_unpacked_lrh { + u8 virtual_lane; + u8 link_version; + u8 service_level; + u8 link_next_header; + __be16 destination_lid; + __be16 packet_length; + __be16 source_lid; +}; + +struct ib_unpacked_grh { + u8 ip_version; + u8 traffic_class; + __be32 flow_label; + __be16 payload_length; + u8 next_header; + u8 hop_limit; + union ib_gid source_gid; + union ib_gid destination_gid; +}; + +struct ib_unpacked_bth { + u8 opcode; + u8 solicited_event; + u8 mig_req; + u8 pad_count; + u8 transport_header_version; + __be16 pkey; + __be32 destination_qpn; + u8 ack_req; + __be32 psn; +}; + +struct ib_unpacked_deth { + __be32 qkey; + __be32 source_qpn; +}; + +struct ib_ud_header { + struct ib_unpacked_lrh lrh; + int grh_present; + struct ib_unpacked_grh grh; + struct ib_unpacked_bth bth; + struct ib_unpacked_deth deth; + int immediate_present; + __be32 immediate_data; +}; + +void ib_pack(const struct ib_field *desc, + int desc_len, + void *structure, + void *buf); + +void ib_unpack(const struct ib_field *desc, + int desc_len, + void *buf, + void *structure); + +void ib_ud_header_init(int payload_bytes, + int grh_present, + struct ib_ud_header *header); + +int ib_ud_header_pack(struct ib_ud_header *header, + void *buf); + +int ib_ud_header_unpack(void *buf, + struct ib_ud_header *header); + +#endif /* IB_PACK_H */ diff --git a/branches/WOF2-3/hw/mthca/kernel/ib_smi.h b/branches/WOF2-3/hw/mthca/kernel/ib_smi.h new file mode 100644 index 00000000..8cfe1a2a --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/ib_smi.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2004 Mellanox Technologies Ltd. All rights reserved. + * Copyright (c) 2004 Infinicon Corporation. All rights reserved. + * Copyright (c) 2004 Intel Corporation. All rights reserved. + * Copyright (c) 2004 Topspin Corporation. All rights reserved. + * Copyright (c) 2004 Voltaire Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#if !defined( IB_SMI_H ) +#define IB_SMI_H + +#include + +#define IB_SMP_DATA_SIZE 64 +#define IB_SMP_MAX_PATH_HOPS 64 + +#pragma pack(push,1) +struct ib_smp { + u8 base_version; + u8 mgmt_class; + u8 class_version; + u8 method; + __be16 status; + u8 hop_ptr; + u8 hop_cnt; + __be64 tid; + __be16 attr_id; + __be16 resv; + __be32 attr_mod; + __be64 mkey; + __be16 dr_slid; + __be16 dr_dlid; + u8 reserved[28]; + u8 data[IB_SMP_DATA_SIZE]; + u8 initial_path[IB_SMP_MAX_PATH_HOPS]; + u8 return_path[IB_SMP_MAX_PATH_HOPS]; +}; +#pragma pack(pop) + + +/* Subnet management attributes */ +#define IB_SMP_ATTR_NOTICE cl_hton16(0x0002) +#define IB_SMP_ATTR_NODE_DESC cl_hton16(0x0010) +#define IB_SMP_ATTR_NODE_INFO cl_hton16(0x0011) +#define IB_SMP_ATTR_SWITCH_INFO cl_hton16(0x0012) +#define IB_SMP_ATTR_GUID_INFO cl_hton16(0x0014) +#define IB_SMP_ATTR_PORT_INFO cl_hton16(0x0015) +#define IB_SMP_ATTR_PKEY_TABLE cl_hton16(0x0016) +#define IB_SMP_ATTR_SL_TO_VL_TABLE cl_hton16(0x0017) +#define IB_SMP_ATTR_VL_ARB_TABLE cl_hton16(0x0018) +#define IB_SMP_ATTR_LINEAR_FORWARD_TABLE cl_hton16(0x0019) +#define IB_SMP_ATTR_RANDOM_FORWARD_TABLE cl_hton16(0x001A) +#define IB_SMP_ATTR_MCAST_FORWARD_TABLE cl_hton16(0x001B) +#define IB_SMP_ATTR_SM_INFO cl_hton16(0x0020) +#define IB_SMP_ATTR_VENDOR_DIAG cl_hton16(0x0030) +#define IB_SMP_ATTR_LED_INFO cl_hton16(0x0031) +#define IB_SMP_ATTR_VENDOR_MASK cl_hton16(0xFF00) + +static inline u8 +ib_get_smp_direction(struct ib_smp *smp) +{ + return (u8)((smp->status & IB_SMP_DIRECTION) == IB_SMP_DIRECTION); +} + +#endif /* IB_SMI_H */ diff --git a/branches/WOF2-3/hw/mthca/kernel/ib_verbs.h b/branches/WOF2-3/hw/mthca/kernel/ib_verbs.h new file mode 100644 index 00000000..35125ec5 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/ib_verbs.h @@ -0,0 +1,1335 @@ +/* + * Copyright (c) 2004 Mellanox Technologies Ltd. All rights reserved. + * Copyright (c) 2004 Infinicon Corporation. All rights reserved. + * Copyright (c) 2004 Intel Corporation. All rights reserved. + * Copyright (c) 2004 Topspin Corporation. All rights reserved. + * Copyright (c) 2004 Voltaire Corporation. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2005 Cisco Systems. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#if !defined(IB_VERBS_H) +#define IB_VERBS_H + +#include +#include +#include + +union ib_gid { + u8 raw[16]; + struct { + __be64 subnet_prefix; + __be64 interface_id; + } global; +}; + +enum ib_node_type { + IB_NODE_CA = 1, + IB_NODE_SWITCH, + IB_NODE_ROUTER +}; + +enum ib_device_cap_flags { + IB_DEVICE_RESIZE_MAX_WR = 1, + IB_DEVICE_BAD_PKEY_CNTR = (1<<1), + IB_DEVICE_BAD_QKEY_CNTR = (1<<2), + IB_DEVICE_RAW_MULTI = (1<<3), + IB_DEVICE_AUTO_PATH_MIG = (1<<4), + IB_DEVICE_CHANGE_PHY_PORT = (1<<5), + IB_DEVICE_UD_AV_PORT_ENFORCE = (1<<6), + IB_DEVICE_CURR_QP_STATE_MOD = (1<<7), + IB_DEVICE_SHUTDOWN_PORT = (1<<8), + IB_DEVICE_INIT_TYPE = (1<<9), + IB_DEVICE_PORT_ACTIVE_EVENT = (1<<10), + IB_DEVICE_SYS_IMAGE_GUID = (1<<11), + IB_DEVICE_RC_RNR_NAK_GEN = (1<<12), + IB_DEVICE_SRQ_RESIZE = (1<<13), + IB_DEVICE_N_NOTIFY_CQ = (1<<14), + IB_DEVICE_IPOIB_CSUM = (1<<18) +}; + +struct ib_device_attr { + u64 fw_ver; + __be64 sys_image_guid; + u64 max_mr_size; + u64 page_size_cap; + u32 vendor_id; + u32 vendor_part_id; + u32 hw_ver; + int max_qp; + int max_qp_wr; + int device_cap_flags; + int max_sge; + int max_sge_rd; + int max_cq; + int max_cqe; + int max_mr; + int max_pd; + int max_qp_rd_atom; + int max_ee_rd_atom; + int max_res_rd_atom; + int max_qp_init_rd_atom; + int max_ee_init_rd_atom; + enum ib_atomic_cap atomic_cap; + int max_ee; + int max_rdd; + int max_mw; + int max_raw_ipv6_qp; + int max_raw_ethy_qp; + int max_mcast_grp; + int max_mcast_qp_attach; + int max_total_mcast_qp_attach; + u64 max_ah; + int max_fmr; + int max_map_per_fmr; + int max_srq; + int max_srq_wr; + int max_srq_sge; + u16 max_pkeys; + u8 local_ca_ack_delay; +}; + +static inline int ib_mtu_enum_to_int(int mtu) +{ + switch (mtu) { + case IB_MTU_LEN_256: return 256; + case IB_MTU_LEN_512: return 512; + case IB_MTU_LEN_1024: return 1024; + case IB_MTU_LEN_2048: return 2048; + case IB_MTU_LEN_4096: return 4096; + default: return -1; + } +} + +enum ib_port_state { + IB_PORT_NOP = 0, + IB_PORT_DOWN = 1, + IB_PORT_INIT = 2, + IB_PORT_ARMED = 3, + IB_PORT_ACTIVE = 4, + IB_PORT_ACTIVE_DEFER = 5 +}; + +enum ib_port_cap_flags { + IB_PORT_SM = 1 << 1, + IB_PORT_NOTICE_SUP = 1 << 2, + IB_PORT_TRAP_SUP = 1 << 3, + IB_PORT_OPT_IPD_SUP = 1 << 4, + IB_PORT_AUTO_MIGR_SUP = 1 << 5, + IB_PORT_SL_MAP_SUP = 1 << 6, + IB_PORT_MKEY_NVRAM = 1 << 7, + IB_PORT_PKEY_NVRAM = 1 << 8, + IB_PORT_LED_INFO_SUP = 1 << 9, + IB_PORT_SM_DISABLED = 1 << 10, + IB_PORT_SYS_IMAGE_GUID_SUP = 1 << 11, + IB_PORT_PKEY_SW_EXT_PORT_TRAP_SUP = 1 << 12, + IB_PORT_CM_SUP = 1 << 16, + IB_PORT_SNMP_TUNNEL_SUP = 1 << 17, + IB_PORT_REINIT_SUP = 1 << 18, + IB_PORT_DEVICE_MGMT_SUP = 1 << 19, + IB_PORT_VENDOR_CLASS_SUP = 1 << 20, + IB_PORT_DR_NOTICE_SUP = 1 << 21, + IB_PORT_CAP_MASK_NOTICE_SUP = 1 << 22, + IB_PORT_BOOT_MGMT_SUP = 1 << 23, + IB_PORT_LINK_LATENCY_SUP = 1 << 24, + IB_PORT_CLIENT_REG_SUP = 1 << 25 +}; + +enum ib_port_width { + IB_WIDTH_1X = 1, + IB_WIDTH_4X = 2, + IB_WIDTH_8X = 4, + IB_WIDTH_12X = 8 +}; + +enum ib_rate { + IB_RATE_PORT_CURRENT = 0, + IB_RATE_2_5_GBPS = 2, + IB_RATE_5_GBPS = 5, + IB_RATE_10_GBPS = 3, + IB_RATE_20_GBPS = 6, + IB_RATE_30_GBPS = 4, + IB_RATE_40_GBPS = 7, + IB_RATE_60_GBPS = 8, + IB_RATE_80_GBPS = 9, + IB_RATE_120_GBPS = 10 +}; + +static inline int ib_width_enum_to_int(enum ib_port_width width) +{ + switch (width) { + case IB_WIDTH_1X: return 1; + case IB_WIDTH_4X: return 4; + case IB_WIDTH_8X: return 8; + case IB_WIDTH_12X: return 12; + default: return -1; + } +} + +struct ib_port_attr { + enum ib_port_state state; + enum ib_mtu max_mtu; + enum ib_mtu active_mtu; + int gid_tbl_len; + u32 port_cap_flags; + u32 max_msg_sz; + u32 bad_pkey_cntr; + u32 qkey_viol_cntr; + u16 pkey_tbl_len; + u16 lid; + u16 sm_lid; + u8 lmc; + u8 max_vl_num; + u8 sm_sl; + u8 subnet_timeout; + u8 init_type_reply; + u8 active_width; + u8 active_speed; + u8 phys_state; +}; + +enum ib_device_modify_flags { + IB_DEVICE_MODIFY_SYS_IMAGE_GUID = 1 +}; + +struct ib_device_modify { + u64 sys_image_guid; +}; + +enum ib_port_modify_flags { + IB_PORT_SHUTDOWN = 1, + IB_PORT_INIT_TYPE = (1<<2), + IB_PORT_RESET_QKEY_CNTR = (1<<3) +}; + +struct ib_port_modify { + u32 set_port_cap_mask; + u32 clr_port_cap_mask; + u8 init_type; +}; + +enum ib_event_type { + IB_EVENT_CQ_ERR = IB_AE_CQ_ERROR, + IB_EVENT_QP_FATAL = IB_AE_QP_FATAL, + IB_EVENT_QP_REQ_ERR = IB_AE_WQ_REQ_ERROR, + IB_EVENT_QP_ACCESS_ERR = IB_AE_WQ_ACCESS_ERROR, + IB_EVENT_COMM_EST = IB_AE_QP_COMM, + IB_EVENT_SQ_DRAINED = IB_AE_SQ_DRAINED, + IB_EVENT_PATH_MIG = IB_AE_QP_APM, + IB_EVENT_PATH_MIG_ERR = IB_AE_QP_APM_ERROR, + IB_EVENT_DEVICE_FATAL = IB_AE_LOCAL_FATAL, + IB_EVENT_PORT_ACTIVE = IB_AE_PORT_ACTIVE, + IB_EVENT_PORT_ERR = IB_AE_PORT_DOWN, + IB_EVENT_SRQ_LIMIT_REACHED = IB_AE_SRQ_LIMIT_REACHED, + IB_EVENT_SRQ_CATAS_ERROR = IB_AE_SRQ_CATAS_ERROR, + IB_EVENT_SRQ_QP_LAST_WQE_REACHED = IB_AE_SRQ_QP_LAST_WQE_REACHED, + IB_EVENT_LID_CHANGE = IB_AE_LID_CHANGE, + IB_EVENT_CLIENT_REREGISTER = IB_AE_CLIENT_REREGISTER, + IB_EVENT_PKEY_CHANGE = IB_AE_PKEY_CHANGE, + IB_EVENT_SM_CHANGE = IB_AE_SM_CHANGE +}; + +struct ib_event { + struct ib_device *device; + union { + struct ib_cq *cq; + struct ib_qp *qp; + struct ib_srq *srq; + u8 port_num; + } element; + enum ib_event_type event; + uint64_t vendor_specific; +}; + +struct ib_event_handler { + struct ib_device *device; + void (*handler)(struct ib_event_handler *, struct ib_event *); + struct list_head list; +}; + +#define INIT_IB_EVENT_HANDLER(_ptr, _device, _handler) \ + (_ptr)->device = _device; \ + (_ptr)->handler = _handler; \ + INIT_LIST_HEAD(&(_ptr)->list) + +struct ib_global_route { + union ib_gid dgid; + u32 flow_label; + u8 sgid_index; + u8 hop_limit; + u8 traffic_class; +}; + +struct ib_grh { + __be32 version_tclass_flow; + __be16 paylen; + u8 next_hdr; + u8 hop_limit; + union ib_gid sgid; + union ib_gid dgid; +}; + +enum { + IB_MULTICAST_QPN = 0xffffff +}; + +enum ib_ah_flags { + IB_AH_GRH = 1 +}; + +struct ib_ah_attr { + struct ib_global_route grh; + u16 dlid; + u8 sl; + u8 src_path_bits; + u8 static_rate; + u8 ah_flags; + u8 port_num; +}; + +enum ib_cq_notify { + IB_CQ_SOLICITED, + IB_CQ_NEXT_COMP +}; + +struct ib_srq_init_attr { + void (*event_handler)(ib_event_rec_t *); + void *srq_context; + ib_srq_attr_t attr; +}; + +struct ib_qp_cap { + u32 max_send_wr; + u32 max_recv_wr; + u32 max_send_sge; + u32 max_recv_sge; + u32 max_inline_data; +}; + +enum ib_sig_type { + IB_SIGNAL_ALL_WR, + IB_SIGNAL_REQ_WR +}; + +struct ib_qp_init_attr { + void (*event_handler)(ib_event_rec_t *); + void *qp_context; + struct ib_cq *send_cq; + struct ib_cq *recv_cq; + struct ib_srq *srq; + struct ib_qp_cap cap; + enum ib_sig_type sq_sig_type; + enum ib_qp_type_t qp_type; + u8 port_num; /* special QP types only */ +}; + +enum ib_rnr_timeout { + IB_RNR_TIMER_655_36 = 0, + IB_RNR_TIMER_000_01 = 1, + IB_RNR_TIMER_000_02 = 2, + IB_RNR_TIMER_000_03 = 3, + IB_RNR_TIMER_000_04 = 4, + IB_RNR_TIMER_000_06 = 5, + IB_RNR_TIMER_000_08 = 6, + IB_RNR_TIMER_000_12 = 7, + IB_RNR_TIMER_000_16 = 8, + IB_RNR_TIMER_000_24 = 9, + IB_RNR_TIMER_000_32 = 10, + IB_RNR_TIMER_000_48 = 11, + IB_RNR_TIMER_000_64 = 12, + IB_RNR_TIMER_000_96 = 13, + IB_RNR_TIMER_001_28 = 14, + IB_RNR_TIMER_001_92 = 15, + IB_RNR_TIMER_002_56 = 16, + IB_RNR_TIMER_003_84 = 17, + IB_RNR_TIMER_005_12 = 18, + IB_RNR_TIMER_007_68 = 19, + IB_RNR_TIMER_010_24 = 20, + IB_RNR_TIMER_015_36 = 21, + IB_RNR_TIMER_020_48 = 22, + IB_RNR_TIMER_030_72 = 23, + IB_RNR_TIMER_040_96 = 24, + IB_RNR_TIMER_061_44 = 25, + IB_RNR_TIMER_081_92 = 26, + IB_RNR_TIMER_122_88 = 27, + IB_RNR_TIMER_163_84 = 28, + IB_RNR_TIMER_245_76 = 29, + IB_RNR_TIMER_327_68 = 30, + IB_RNR_TIMER_491_52 = 31 +}; + +enum ib_qp_attr_mask { + IB_QP_STATE = 1, + IB_QP_CUR_STATE = (1<<1), + IB_QP_EN_SQD_ASYNC_NOTIFY = (1<<2), + IB_QP_ACCESS_FLAGS = (1<<3), + IB_QP_PKEY_INDEX = (1<<4), + IB_QP_PORT = (1<<5), + IB_QP_QKEY = (1<<6), + IB_QP_AV = (1<<7), + IB_QP_PATH_MTU = (1<<8), + IB_QP_TIMEOUT = (1<<9), + IB_QP_RETRY_CNT = (1<<10), + IB_QP_RNR_RETRY = (1<<11), + IB_QP_RQ_PSN = (1<<12), + IB_QP_MAX_QP_RD_ATOMIC = (1<<13), + IB_QP_ALT_PATH = (1<<14), + IB_QP_MIN_RNR_TIMER = (1<<15), + IB_QP_SQ_PSN = (1<<16), + IB_QP_MAX_DEST_RD_ATOMIC = (1<<17), + IB_QP_PATH_MIG_STATE = (1<<18), + IB_QP_CAP = (1<<19), + IB_QP_DEST_QPN = (1<<20) +}; + +//TODO: these literals are also defined in ib_types.h and have there ANOTHER VALUES !!! +enum ib_qp_state { + IBQPS_RESET, + IBQPS_INIT, + IBQPS_RTR, + IBQPS_RTS, + IBQPS_SQD, + IBQPS_SQE, + IBQPS_ERR +}; + +enum ib_mig_state { + IB_MIG_MIGRATED, + IB_MIG_REARM, + IB_MIG_ARMED +}; + +struct ib_qp_attr { + enum ib_qp_state qp_state; + enum ib_qp_state cur_qp_state; + enum ib_mtu path_mtu; + ib_apm_state_t path_mig_state; + u32 qkey; + u32 rq_psn; + u32 sq_psn; + u32 dest_qp_num; + int qp_access_flags; + struct ib_qp_cap cap; + struct ib_ah_attr ah_attr; + struct ib_ah_attr alt_ah_attr; + u16 pkey_index; + u16 alt_pkey_index; + u8 en_sqd_async_notify; + u8 sq_draining; + u8 max_rd_atomic; + u8 max_dest_rd_atomic; + u8 min_rnr_timer; + u8 port_num; + u8 timeout; + u8 retry_cnt; + u8 rnr_retry; + u8 alt_port_num; + u8 alt_timeout; +}; + +struct ib_sge { + u64 addr; + u32 length; + u32 lkey; +}; + + +typedef enum MTHCA_QP_ACCESS_FLAGS { + MTHCA_ACCESS_LOCAL_WRITE = 1, + MTHCA_ACCESS_REMOTE_WRITE = (1<<1), + MTHCA_ACCESS_REMOTE_READ = (1<<2), + MTHCA_ACCESS_REMOTE_ATOMIC = (1<<3), + MTHCA_ACCESS_MW_BIND = (1<<4) +} mthca_qp_access_t; + +struct ib_phys_buf { + u64 addr; + u64 size; +}; + +struct ib_mr_attr { + struct ib_pd *pd; + u64 device_virt_addr; + u64 size; + mthca_qp_access_t mr_access_flags; + u32 lkey; + u32 rkey; +}; + +enum ib_mr_rereg_flags { + IB_MR_REREG_TRANS = 1, + IB_MR_REREG_PD = (1<<1), + IB_MR_REREG_ACCESS = (1<<2) +}; + +struct ib_mw_bind { + struct ib_mr *mr; + u64 wr_id; + u64 addr; + u32 length; + int send_flags; + int mw_access_flags; +}; + +struct ib_fmr_attr { + int max_pages; + int max_maps; + u8 page_shift; +}; + +struct ib_ucontext { + struct ib_device *device; + PVOID user_uar; + struct ib_pd *pd; + atomic_t usecnt; /* count all resources */ + ULONG is_removing; + cl_list_item_t list_item; // chain of user contexts + // for tools support + KMUTEX mutex; + PMDL p_mdl; + PVOID va; + int fw_if_open; +}; + +struct ib_uobject { + u64 user_handle; /* handle given to us by userspace */ + struct ib_ucontext *context; /* associated user context */ + struct list_head list; /* link to context's list */ + u32 id; /* index into kernel idr */ +}; + +struct ib_umem { + u64 user_base; + u64 virt_base; + u64 length; + int offset; + int page_size; + int writable; + struct list_head chunk_list; +}; + +#pragma warning( disable : 4200 ) +struct ib_umem_chunk { + struct list_head list; + int nents; + int nmap; + struct scatterlist page_list[0]; +}; +#pragma warning( default : 4200 ) + +#define IB_UMEM_MAX_PAGE_CHUNK \ + ((PAGE_SIZE - offsetof(struct ib_umem_chunk, page_list)) / \ + ((char *) &((struct ib_umem_chunk *) 0)->page_list[1] - \ + (char *) &((struct ib_umem_chunk *) 0)->page_list[0])) + +struct ib_pd { + struct list_head list; /* for chaining AV MRs (for user mode only) */ + struct ib_device *device; + struct ib_ucontext *ucontext; + atomic_t usecnt; /* count all resources */ + KMUTEX mutex; /* for chaining AV MRs (for user mode only) */ +}; + +struct ib_ah { + struct ib_device *device; + struct ib_pd *pd; + struct ib_ucontext *ucontext; +}; + +typedef void (*ib_comp_handler)(void *cq_context); + +struct ib_cq { + struct ib_device *device; + struct ib_ucontext *ucontext; + struct ib_mr *ib_mr; + ib_comp_handler comp_handler; + void (*event_handler)(ib_event_rec_t *); + void * cq_context; + int cqe; + atomic_t usecnt; /* count number of work queues */ +}; + +struct ib_srq { + struct ib_device *device; + struct ib_pd *pd; + struct ib_ucontext *ucontext; + struct ib_mr *ib_mr; + void (*event_handler)(ib_event_rec_t *); + void *srq_context; + atomic_t usecnt; /* count number of work queues */ +}; + +struct ib_qp { + struct ib_device *device; + struct ib_pd *pd; + struct ib_cq *send_cq; + struct ib_cq *recv_cq; + struct ib_srq *srq; + struct ib_ucontext *ucontext; + struct ib_mr *ib_mr; + void (*event_handler)(ib_event_rec_t *); + void *qp_context; + u32 qp_num; + enum ib_qp_type_t qp_type; +}; + +struct ib_mr { + struct list_head list; /* for chaining AV MRs (for user mode only) */ + struct ib_device *device; + struct ib_pd *pd; + u32 lkey; + u32 rkey; + atomic_t usecnt; /* count number of MWs */ +}; + +struct ib_mw { + struct ib_device *device; + struct ib_pd *pd; + u32 rkey; +}; + +struct ib_fmr { + struct ib_device *device; + struct ib_pd *pd; + struct list_head list; + u32 lkey; + u32 rkey; +}; + +struct ib_mad; +struct ib_grh; + +enum ib_process_mad_flags { + IB_MAD_IGNORE_MKEY = 1, + IB_MAD_IGNORE_BKEY = 2, + IB_MAD_IGNORE_ALL = IB_MAD_IGNORE_MKEY | IB_MAD_IGNORE_BKEY +}; + +enum ib_mad_result { + IB_MAD_RESULT_FAILURE = 0, /* (!SUCCESS is the important flag) */ + IB_MAD_RESULT_SUCCESS = 1 << 0, /* MAD was successfully processed */ + IB_MAD_RESULT_REPLY = 1 << 1, /* Reply packet needs to be sent */ + IB_MAD_RESULT_CONSUMED = 1 << 2 /* Packet consumed: stop processing */ +}; + +#define IB_DEVICE_NAME_MAX 64 + +struct ib_cache { + rwlock_t lock; + struct ib_event_handler event_handler; + struct ib_pkey_cache **pkey_cache; + struct ib_gid_cache **gid_cache; +}; + +struct mthca_dev; + +struct ib_device { + struct mthca_dev *mdev; + + char name[IB_DEVICE_NAME_MAX]; + + struct list_head event_handler_list; + spinlock_t event_handler_lock; + + struct list_head core_list; + struct list_head client_data_list; + spinlock_t client_data_lock; + + struct ib_cache cache; + + u32 flags; + + int (*query_device)(struct ib_device *device, + struct ib_device_attr *device_attr); + int (*query_port)(struct ib_device *device, + u8 port_num, + struct ib_port_attr *port_attr); + int (*query_gid_chunk)(struct ib_device *device, + u8 port_num, int index, + union ib_gid gid[8]); + int (*query_pkey_chunk)(struct ib_device *device, + u8 port_num, u16 index, __be16 pkey[32]); + int (*modify_device)(struct ib_device *device, + int device_modify_mask, + struct ib_device_modify *device_modify); + int (*modify_port)(struct ib_device *device, + u8 port_num, int port_modify_mask, + struct ib_port_modify *port_modify); + struct ib_ucontext * (*alloc_ucontext)(struct ib_device *device, + ci_umv_buf_t* const p_umv_buf); + int (*dealloc_ucontext)(struct ib_ucontext *context); + struct ib_pd * (*alloc_pd)(struct ib_device *device, + struct ib_ucontext *context, + ci_umv_buf_t* const p_umv_buf); + int (*dealloc_pd)(struct ib_pd *pd); + struct ib_ah * (*create_ah)(struct ib_pd *pd, + struct ib_ah_attr *ah_attr); + int (*modify_ah)(struct ib_ah *ah, + struct ib_ah_attr *ah_attr); + int (*query_ah)(struct ib_ah *ah, + struct ib_ah_attr *ah_attr); + int (*destroy_ah)(struct ib_ah *ah); + struct ib_srq * (*create_srq)(struct ib_pd *pd, + struct ib_srq_init_attr *srq_init_attr, + ci_umv_buf_t* const p_umv_buf); + int (*modify_srq)(struct ib_srq *srq, + ib_srq_attr_t *srq_attr, + ib_srq_attr_mask_t srq_attr_mask); + int (*query_srq)(struct ib_srq *srq, + ib_srq_attr_t *srq_attr); + int (*destroy_srq)(struct ib_srq *srq); + int (*post_srq_recv)(struct ib_srq *srq, + struct _ib_recv_wr *recv_wr, + struct _ib_recv_wr **bad_recv_wr); + struct ib_qp * (*create_qp)(struct ib_pd *pd, + struct ib_qp_init_attr *qp_init_attr, + ci_umv_buf_t* const p_umv_buf); + int (*modify_qp)(struct ib_qp *qp, + struct ib_qp_attr *qp_attr, + int qp_attr_mask); + int (*query_qp)(struct ib_qp *qp, + struct ib_qp_attr *qp_attr, + int qp_attr_mask, + struct ib_qp_init_attr *qp_init_attr); + int (*destroy_qp)(struct ib_qp *qp); + int (*post_send)(struct ib_qp *qp, + struct _ib_send_wr *send_wr, + struct _ib_send_wr **bad_send_wr); + int (*post_recv)(struct ib_qp *qp, + struct _ib_recv_wr *recv_wr, + struct _ib_recv_wr **bad_recv_wr); + struct ib_cq * (*create_cq)(struct ib_device *device, int cqe, + struct ib_ucontext *context, + ci_umv_buf_t* const p_umv_buf); + int (*destroy_cq)(struct ib_cq *cq); + int (*resize_cq)(struct ib_cq *cq, int *cqe); + int (*poll_cq)(struct ib_cq *cq, int num_entries, + struct _ib_wc *wc); + int (*peek_cq)(struct ib_cq *cq, int wc_cnt); + int (*req_notify_cq)(struct ib_cq *cq, + enum ib_cq_notify cq_notify); + int (*req_ncomp_notif)(struct ib_cq *cq, + int wc_cnt); + struct ib_mr * (*get_dma_mr)(struct ib_pd *pd, + mthca_qp_access_t mr_access_flags); + struct ib_mr * (*reg_phys_mr)(struct ib_pd *pd, + struct ib_phys_buf *phys_buf_array, + int num_phys_buf, + mthca_qp_access_t mr_access_flags, + u64 *iova_start); + struct ib_mr * (*reg_virt_mr)(struct ib_pd *pd, + void* vaddr, uint64_t length, uint64_t hca_va, + mthca_qp_access_t acc, boolean_t um_call, boolean_t secure); + int (*query_mr)(struct ib_mr *mr, + struct ib_mr_attr *mr_attr); + int (*dereg_mr)(struct ib_mr *mr); + int (*rereg_phys_mr)(struct ib_mr *mr, + int mr_rereg_mask, + struct ib_pd *pd, + struct ib_phys_buf *phys_buf_array, + int num_phys_buf, + mthca_qp_access_t mr_access_flags, + u64 *iova_start); + struct ib_mw * (*alloc_mw)(struct ib_pd *pd); + int (*bind_mw)(struct ib_qp *qp, + struct ib_mw *mw, + struct ib_mw_bind *mw_bind); + int (*dealloc_mw)(struct ib_mw *mw); + struct ib_fmr * (*alloc_fmr)(struct ib_pd *pd, + mthca_qp_access_t mr_access_flags, + struct ib_fmr_attr *fmr_attr); + int (*map_phys_fmr)(struct ib_fmr *fmr, + u64 *page_list, int list_len, + u64 iova); + int (*unmap_fmr)(struct list_head *fmr_list); + int (*dealloc_fmr)(struct ib_fmr *fmr); + int (*attach_mcast)(struct ib_qp *qp, + union ib_gid *gid, + u16 lid); + int (*detach_mcast)(struct ib_qp *qp, + union ib_gid *gid, + u16 lid); + int (*process_mad)(struct ib_device *device, + int process_mad_flags, + u8 port_num, + struct _ib_wc *in_wc, + struct _ib_grh *in_grh, + struct ib_mad *in_mad, + struct ib_mad *out_mad); + + struct list_head port_list; + + u64 uverbs_cmd_mask; + __be64 node_guid; + u8 node_type; + u8 phys_port_cnt; +}; + +struct ib_client { + char *name; + void (*add) (struct ib_device *); + void (*remove)(struct ib_device *); + + struct list_head list; +}; + +struct ib_device *ib_alloc_device(size_t size); +void ib_dealloc_device(struct ib_device *device); + +int ib_register_device (struct ib_device *device); +void ib_unregister_device(struct ib_device *device); + +int ib_register_client (struct ib_client *client); +void ib_unregister_client(struct ib_client *client); + +void *ib_get_client_data(struct ib_device *device, struct ib_client *client); +void ib_set_client_data(struct ib_device *device, struct ib_client *client, + void *data); + +int ib_core_init(void); + +void ib_core_cleanup(void); + +int ib_register_event_handler (struct ib_event_handler *event_handler); +int ib_unregister_event_handler(struct ib_event_handler *event_handler); +void ib_dispatch_event(struct ib_event *event); + +int ib_query_device(struct ib_device *device, + struct ib_device_attr *device_attr); + +int ib_query_port(struct ib_device *device, + u8 port_num, struct ib_port_attr *port_attr); + +int ib_query_gid_chunk(struct ib_device *device, + u8 port_num, int index, union ib_gid gid[8]); + +int ib_query_pkey_chunk(struct ib_device *device, + u8 port_num, u16 index, __be16 pkey[32]); + +int ib_modify_device(struct ib_device *device, + int device_modify_mask, + struct ib_device_modify *device_modify); + +int ib_modify_port(struct ib_device *device, + u8 port_num, int port_modify_mask, + struct ib_port_modify *port_modify); + +/** + * ibv_alloc_pd - Allocates an unused protection domain. + * @device: The device on which to allocate the protection domain. + * @context: user process context (for application calls only) + * @p_umv_buf: parameters structure (for application calls only) + * + * A protection domain object provides an association between QPs, shared + * receive queues, address handles, memory regions, and memory windows. + */ +struct ib_pd *ibv_alloc_pd(struct ib_device *device, + struct ib_ucontext *context, ci_umv_buf_t* const p_umv_buf); + +/** + * ibv_dealloc_pd - Deallocates a protection domain. + * @pd: The protection domain to deallocate. + */ +int ibv_dealloc_pd(struct ib_pd *pd); + +/** + * ibv_create_ah - Creates an address handle for the given address vector. + * @pd: The protection domain associated with the address handle. + * @ah_attr: The attributes of the address vector. + * @context: user process context (for application calls only) + * @p_umv_buf: parameters structure (for application calls only) + * + * The address handle is used to reference a local or global destination + * in all UD QP post sends. + */ +struct ib_ah *ibv_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr, + struct ib_ucontext *context, ci_umv_buf_t* const p_umv_buf); + +/** + * ibv_create_ah_from_wc - Creates an address handle associated with the + * sender of the specified work completion. + * @pd: The protection domain associated with the address handle. + * @wc: Work completion information associated with a received message. + * @grh: References the received global route header. This parameter is + * ignored unless the work completion indicates that the GRH is valid. + * @port_num: The outbound port number to associate with the address. + * + * The address handle is used to reference a local or global destination + * in all UD QP post sends. + */ +struct ib_ah *ibv_create_ah_from_wc(struct ib_pd *pd, struct _ib_wc *wc, + struct ib_grh *grh, u8 port_num); + +/** + * ibv_modify_ah - Modifies the address vector associated with an address + * handle. + * @ah: The address handle to modify. + * @ah_attr: The new address vector attributes to associate with the + * address handle. + */ +int ibv_modify_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr); + +/** + * ibv_query_ah - Queries the address vector associated with an address + * handle. + * @ah: The address handle to query. + * @ah_attr: The address vector attributes associated with the address + * handle. + */ +int ibv_query_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr); + +/** + * ibv_destroy_ah - Destroys an address handle. + * @ah: The address handle to destroy. + */ +int ibv_destroy_ah(struct ib_ah *ah); + +/** + * ibv_create_srq - Creates a SRQ associated with the specified protection + * domain. + * @pd: The protection domain associated with the SRQ. + * @srq_init_attr: A list of initial attributes required to create the + * SRQ. If SRQ creation succeeds, then the attributes are updated to + * the actual capabilities of the created SRQ. + * @context: user process context (for application calls only) + * @p_umv_buf: parameters structure (for application calls only) + * + * srq_attr->max_wr and srq_attr->max_sge are read the determine the + * requested size of the SRQ, and set to the actual values allocated + * on return. If ibv_create_srq() succeeds, then max_wr and max_sge + * will always be at least as large as the requested values. + */ +struct ib_srq *ibv_create_srq(struct ib_pd *pd, + struct ib_srq_init_attr *srq_init_attr, + struct ib_ucontext *context, ci_umv_buf_t* const p_umv_buf); + + +/** + * ibv_modify_srq - Modifies the attributes for the specified SRQ. + * @srq: The SRQ to modify. + * @srq_attr: On input, specifies the SRQ attributes to modify. On output, + * the current values of selected SRQ attributes are returned. + * @srq_attr_mask: A bit-mask used to specify which attributes of the SRQ + * are being modified. + * + * The mask may contain IB_SRQ_MAX_WR to resize the SRQ and/or + * IB_SRQ_LIMIT to set the SRQ's limit and request notification when + * the number of receives queued drops below the limit. + */ +int ibv_modify_srq(struct ib_srq *srq, + ib_srq_attr_t *srq_attr, + ib_srq_attr_mask_t srq_attr_mask); + +/** + * ibv_query_srq - Returns the attribute list and current values for the + * specified SRQ. + * @srq: The SRQ to query. + * @srq_attr: The attributes of the specified SRQ. + */ +int ibv_query_srq(struct ib_srq *srq, + ib_srq_attr_t *srq_attr); + +/** + * ibv_destroy_srq - Destroys the specified SRQ. + * @srq: The SRQ to destroy. + */ +int ibv_destroy_srq(struct ib_srq *srq); + +/** + * ibv_post_srq_recv - Posts a list of work requests to the specified SRQ. + * @srq: The SRQ to post the work request on. + * @recv_wr: A list of work requests to post on the receive queue. + * @bad_recv_wr: On an immediate failure, this parameter will reference + * the work request that failed to be posted on the QP. + */ +static inline int ibv_post_srq_recv(struct ib_srq *srq, + struct _ib_recv_wr *recv_wr, + struct _ib_recv_wr **bad_recv_wr) +{ + return srq->device->post_srq_recv(srq, recv_wr, bad_recv_wr); +} + +/** + * ibv_create_qp - Creates a QP associated with the specified protection + * domain. + * @pd: The protection domain associated with the QP. + * @qp_init_attr: A list of initial attributes required to create the + * QP. If QP creation succeeds, then the attributes are updated to + * the actual capabilities of the created QP. + * @context: user process context (for application calls only) + * @p_umv_buf: parameters structure (for application calls only) + */ +struct ib_qp *ibv_create_qp(struct ib_pd *pd, + struct ib_qp_init_attr *qp_init_attr, + struct ib_ucontext *context, ci_umv_buf_t* const p_umv_buf); + +/** + * ibv_modify_qp - Modifies the attributes for the specified QP and then + * transitions the QP to the given state. + * @qp: The QP to modify. + * @qp_attr: On input, specifies the QP attributes to modify. On output, + * the current values of selected QP attributes are returned. + * @qp_attr_mask: A bit-mask used to specify which attributes of the QP + * are being modified. + */ +int ibv_modify_qp(struct ib_qp *qp, + struct ib_qp_attr *qp_attr, + int qp_attr_mask); + +/** + * ibv_query_qp - Returns the attribute list and current values for the + * specified QP. + * @qp: The QP to query. + * @qp_attr: The attributes of the specified QP. + * @qp_attr_mask: A bit-mask used to select specific attributes to query. + * @qp_init_attr: Additional attributes of the selected QP. + * + * The qp_attr_mask may be used to limit the query to gathering only the + * selected attributes. + */ +int ibv_query_qp(struct ib_qp *qp, + struct ib_qp_attr *qp_attr, + int qp_attr_mask, + struct ib_qp_init_attr *qp_init_attr); + +/** + * ibv_destroy_qp - Destroys the specified QP. + * @qp: The QP to destroy. + */ +int ibv_destroy_qp(struct ib_qp *qp); + +/** + * ib_post_send - Posts a list of work requests to the send queue of + * the specified QP. + * @qp: The QP to post the work request on. + * @send_wr: A list of work requests to post on the send queue. + * @bad_send_wr: On an immediate failure, this parameter will reference + * the work request that failed to be posted on the QP. + */ +static inline int ib_post_send(struct ib_qp *qp, + struct _ib_send_wr *send_wr, + struct _ib_send_wr **bad_send_wr) +{ + return qp->device->post_send(qp, send_wr, bad_send_wr); +} + +/** + * ib_post_recv - Posts a list of work requests to the receive queue of + * the specified QP. + * @qp: The QP to post the work request on. + * @recv_wr: A list of work requests to post on the receive queue. + * @bad_recv_wr: On an immediate failure, this parameter will reference + * the work request that failed to be posted on the QP. + */ +static inline int ib_post_recv(struct ib_qp *qp, + struct _ib_recv_wr *recv_wr, + struct _ib_recv_wr **bad_recv_wr) +{ + return qp->device->post_recv(qp, recv_wr, bad_recv_wr); +} + +/** + * ibv_create_cq - Creates a CQ on the specified device. + * @device: The device on which to create the CQ. + * @comp_handler: A user-specified callback that is invoked when a + * completion event occurs on the CQ. + * @event_handler: A user-specified callback that is invoked when an + * asynchronous event not associated with a completion occurs on the CQ. + * @cq_context: Context associated with the CQ returned to the user via + * the associated completion and event handlers. + * @cqe: The minimum size of the CQ. + * @context: user process context (for application calls only) + * @p_umv_buf: parameters structure (for application calls only) + * + * Users can examine the cq structure to determine the actual CQ size. + */ +struct ib_cq *ibv_create_cq(struct ib_device *device, + ib_comp_handler comp_handler, + void (*event_handler)(ib_event_rec_t *), + void *cq_context, int cqe, + struct ib_ucontext *context, ci_umv_buf_t* const p_umv_buf); + +/** + * ibv_resize_cq - Modifies the capacity of the CQ. + * @cq: The CQ to resize. + * @cqe: The minimum size of the CQ. + * + * Users can examine the cq structure to determine the actual CQ size. + */ +int ibv_resize_cq(struct ib_cq *cq, int cqe); + +/** + * ibv_destroy_cq - Destroys the specified CQ. + * @cq: The CQ to destroy. + */ +int ibv_destroy_cq(struct ib_cq *cq); + +/** + * ib_poll_cq - poll a CQ for completion(s) + * @cq:the CQ being polled + * @num_entries:maximum number of completions to return + * @wc:array of at least @num_entries &struct _ib_wc where completions + * will be returned + * + * Poll a CQ for (possibly multiple) completions. If the return value + * is < 0, an error occurred. If the return value is >= 0, it is the + * number of completions returned. If the return value is + * non-negative and < num_entries, then the CQ was emptied. + */ +static inline int ib_poll_cq(struct ib_cq *cq, int num_entries, + struct _ib_wc *wc) +{ + return cq->device->poll_cq(cq, num_entries, wc); +} + +/** + * ib_peek_cq - Returns the number of unreaped completions currently + * on the specified CQ. + * @cq: The CQ to peek. + * @wc_cnt: A minimum number of unreaped completions to check for. + * + * If the number of unreaped completions is greater than or equal to wc_cnt, + * this function returns wc_cnt, otherwise, it returns the actual number of + * unreaped completions. + */ +int ib_peek_cq(struct ib_cq *cq, int wc_cnt); + +/** + * ib_req_notify_cq - Request completion notification on a CQ. + * @cq: The CQ to generate an event for. + * @cq_notify: If set to %IB_CQ_SOLICITED, completion notification will + * occur on the next solicited event. If set to %IB_CQ_NEXT_COMP, + * notification will occur on the next completion. + */ +static inline int ib_req_notify_cq(struct ib_cq *cq, + enum ib_cq_notify cq_notify) +{ + return cq->device->req_notify_cq(cq, cq_notify); +} + +/** + * ib_req_ncomp_notif - Request completion notification when there are + * at least the specified number of unreaped completions on the CQ. + * @cq: The CQ to generate an event for. + * @wc_cnt: The number of unreaped completions that should be on the + * CQ before an event is generated. + */ +static inline int ib_req_ncomp_notif(struct ib_cq *cq, int wc_cnt) +{ + return cq->device->req_ncomp_notif ? + cq->device->req_ncomp_notif(cq, wc_cnt) : + -ENOSYS; +} + +/** + * ibv_reg_mr - Prepares a virtually addressed memory region for use + * by an HCA. + * @pd: The protection domain associated assigned to the registered region. + * @vaddr: virtual address of the region + * @length: Specifies the size of the region. + * @hca_va: virtual address in HCA + * @mr_access_flags: Specifies the memory access rights. + * @um_call: call from user, when TRUE. + * @secure: secure the memory from releasing (only for um_call == TRUE) + */ +struct ib_mr *ibv_reg_mr(struct ib_pd *pd, + mthca_qp_access_t mr_access_flags, + void* vaddr, + uint64_t length, + uint64_t hca_va, + boolean_t um_call, + boolean_t secure + ); + +/** + * ibv_get_dma_mr - Returns a memory region for system memory that is + * usable for DMA. + * @pd: The protection domain associated with the memory region. + * @mr_access_flags: Specifies the memory access rights. + */ +struct ib_mr *ibv_get_dma_mr(struct ib_pd *pd, mthca_qp_access_t mr_access_flags); + +/** + * ibv_reg_phys_mr - Prepares a virtually addressed memory region for use + * by an HCA. + * @pd: The protection domain associated assigned to the registered region. + * @phys_buf_array: Specifies a list of physical buffers to use in the + * memory region. + * @num_phys_buf: Specifies the size of the phys_buf_array. + * @mr_access_flags: Specifies the memory access rights. + * @iova_start: The offset of the region's starting I/O virtual address. + */ +struct ib_mr *ibv_reg_phys_mr(struct ib_pd *pd, + struct ib_phys_buf *phys_buf_array, + int num_phys_buf, + mthca_qp_access_t mr_access_flags, + u64 *iova_start); + +/** + * ibv_rereg_phys_mr - Modifies the attributes of an existing memory region. + * Conceptually, this call performs the functions deregister memory region + * followed by register physical memory region. Where possible, + * resources are reused instead of deallocated and reallocated. + * @mr: The memory region to modify. + * @mr_rereg_mask: A bit-mask used to indicate which of the following + * properties of the memory region are being modified. + * @pd: If %IB_MR_REREG_PD is set in mr_rereg_mask, this field specifies + * the new protection domain to associated with the memory region, + * otherwise, this parameter is ignored. + * @phys_buf_array: If %IB_MR_REREG_TRANS is set in mr_rereg_mask, this + * field specifies a list of physical buffers to use in the new + * translation, otherwise, this parameter is ignored. + * @num_phys_buf: If %IB_MR_REREG_TRANS is set in mr_rereg_mask, this + * field specifies the size of the phys_buf_array, otherwise, this + * parameter is ignored. + * @mr_access_flags: If %IB_MR_REREG_ACCESS is set in mr_rereg_mask, this + * field specifies the new memory access rights, otherwise, this + * parameter is ignored. + * @iova_start: The offset of the region's starting I/O virtual address. + */ +int ibv_rereg_phys_mr(struct ib_mr *mr, + int mr_rereg_mask, + struct ib_pd *pd, + struct ib_phys_buf *phys_buf_array, + int num_phys_buf, + mthca_qp_access_t mr_access_flags, + u64 *iova_start); + +/** + * ibv_query_mr - Retrieves information about a specific memory region. + * @mr: The memory region to retrieve information about. + * @mr_attr: The attributes of the specified memory region. + */ +int ibv_query_mr(struct ib_mr *mr, struct ib_mr_attr *mr_attr); + +/** + * ibv_dereg_mr - Deregisters a memory region and removes it from the + * HCA translation table. + * @mr: The memory region to deregister. + */ +int ibv_dereg_mr(struct ib_mr *mr); + +/** + * ibv_alloc_mw - Allocates a memory window. + * @pd: The protection domain associated with the memory window. + */ +struct ib_mw *ibv_alloc_mw(struct ib_pd *pd); + +/** + * ib_bind_mw - Posts a work request to the send queue of the specified + * QP, which binds the memory window to the given address range and + * remote access attributes. + * @qp: QP to post the bind work request on. + * @mw: The memory window to bind. + * @mw_bind: Specifies information about the memory window, including + * its address range, remote access rights, and associated memory region. + */ +static inline int ib_bind_mw(struct ib_qp *qp, + struct ib_mw *mw, + struct ib_mw_bind *mw_bind) +{ + /* XXX reference counting in corresponding MR? */ + return mw->device->bind_mw ? + mw->device->bind_mw(qp, mw, mw_bind) : + -ENOSYS; +} + +/** + * ibv_dealloc_mw - Deallocates a memory window. + * @mw: The memory window to deallocate. + */ +int ibv_dealloc_mw(struct ib_mw *mw); + +/** + * ibv_alloc_fmr - Allocates a unmapped fast memory region. + * @pd: The protection domain associated with the unmapped region. + * @mr_access_flags: Specifies the memory access rights. + * @fmr_attr: Attributes of the unmapped region. + * + * A fast memory region must be mapped before it can be used as part of + * a work request. + */ +struct ib_fmr *ibv_alloc_fmr(struct ib_pd *pd, + mthca_qp_access_t mr_access_flags, + struct ib_fmr_attr *fmr_attr); + +/** + * ib_map_phys_fmr - Maps a list of physical pages to a fast memory region. + * @fmr: The fast memory region to associate with the pages. + * @page_list: An array of physical pages to map to the fast memory region. + * @list_len: The number of pages in page_list. + * @iova: The I/O virtual address to use with the mapped region. + */ +int ibv_map_phys_fmr(struct ib_fmr *fmr, + u64 *page_list, int list_len, + u64 iova); + +/** + * ibv_unmap_fmr - Removes the mapping from a list of fast memory regions. + * @fmr_list: A linked list of fast memory regions to unmap. + */ +int ibv_unmap_fmr(struct list_head *fmr_list); + +/** + * ibv_dealloc_fmr - Deallocates a fast memory region. + * @fmr: The fast memory region to deallocate. + */ +int ibv_dealloc_fmr(struct ib_fmr *fmr); + +/** + * ibv_attach_mcast - Attaches the specified QP to a multicast group. + * @qp: QP to attach to the multicast group. The QP must be type + * IB_QPT_UNRELIABLE_DGRM. + * @gid: Multicast group GID. + * @lid: Multicast group LID in host byte order. + * + * In order to send and receive multicast packets, subnet + * administration must have created the multicast group and configured + * the fabric appropriately. The port associated with the specified + * QP must also be a member of the multicast group. + */ +int ibv_attach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid); + +/** + * ibv_detach_mcast - Detaches the specified QP from a multicast group. + * @qp: QP to detach from the multicast group. + * @gid: Multicast group GID. + * @lid: Multicast group LID in host byte order. + */ +int ibv_detach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid); + +/** + * ibv_um_close - Releases application. + * @h_um_ca: application context + */ +void ibv_um_close(struct ib_ucontext * h_um_ca); + +#endif /* IB_VERBS_H */ diff --git a/branches/WOF2-3/hw/mthca/kernel/makefile.inc b/branches/WOF2-3/hw/mthca/kernel/makefile.inc new file mode 100644 index 00000000..3f3c0013 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/makefile.inc @@ -0,0 +1,17 @@ + +# Transform .inx file to .inf file adding date + major,min & svn.version stamp +# Output .inf file is copied to the $(INF_TARGET) folder (commonly where .sys file resides). + +_LNG=$(LANGUAGE) + +!IF !DEFINED(_INX) +_INX=. +!ENDIF + +STAMP=stampinf -a $(_BUILDARCH) -k $(KMDF_VERSION_MAJOR).$(KMDF_VERSION_MINOR) + +!INCLUDE mod_ver.def + +$(INF_TARGET) : $(_INX)\$(INF_NAME).inx + copy $(_INX)\$(@B).inx $@ + $(STAMP) -f $@ -d * -v $(IB_MAJORVERSION).$(IB_MINORVERSION).$(IB_BUILDVERSION).$(OPENIB_REV) diff --git a/branches/WOF2-3/hw/mthca/kernel/mt_atomic.h b/branches/WOF2-3/hw/mthca/kernel/mt_atomic.h new file mode 100644 index 00000000..c86198cb --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/mt_atomic.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2004-2005 Mellanox Technologies, Inc. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#ifndef MT_ATOMIC_H +#define MT_ATOMIC_H + +#include "complib/cl_atomic.h" + +typedef atomic32_t atomic_t; + +#define atomic_inc cl_atomic_inc +#define atomic_dec cl_atomic_dec + +static inline atomic_t atomic_read(atomic_t *pval) +{ + return *pval; +} + +static inline void atomic_set(atomic_t *pval, long val) +{ + *pval = val; +} + +/** +* atomic_inc_and_test - decrement and test +* pval: pointer of type atomic_t +* +* Atomically increments pval by 1 and +* returns true if the result is 0, or false for all other +* cases. +*/ +static inline int +atomic_inc_and_test(atomic_t *pval) +{ + return cl_atomic_inc(pval) == 0; +} + +/** +* atomic_dec_and_test - decrement and test +* pval: pointer of type atomic_t +* +* Atomically decrements pval by 1 and +* returns true if the result is 0, or false for all other +* cases. +*/ +static inline int +atomic_dec_and_test(atomic_t *pval) +{ + return cl_atomic_dec(pval) == 0; +} + +#endif diff --git a/branches/WOF2-3/hw/mthca/kernel/mt_bitmap.h b/branches/WOF2-3/hw/mthca/kernel/mt_bitmap.h new file mode 100644 index 00000000..85e3a788 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/mt_bitmap.h @@ -0,0 +1,74 @@ +#ifndef MT_BITMAP_H +#define MT_BITMAP_H + +#include + +// DECLARE_BITMAP +#define DECLARE_BITMAP(name,bits) \ + unsigned long name[BITS_TO_LONGS(bits)] + +static inline unsigned long atomic_set_bit(int nr, volatile long * addr) +{ + return InterlockedOr( addr, (1 << nr) ); +} + +static inline unsigned long atomic_clear_bit(int nr, volatile long * addr) +{ + return InterlockedAnd( addr, ~(1 << nr) ); +} + +static inline int set_bit(int nr,long * addr) +{ + addr += nr >> 5; + return atomic_set_bit( nr & 0x1f, (volatile long *)addr ); +} + +static inline int clear_bit(int nr, long * addr) +{ + addr += nr >> 5; + return atomic_clear_bit( nr & 0x1f, (volatile long *)addr ); +} + +static inline int test_bit(int nr, const unsigned long * addr) +{ + int mask; + + addr += nr >> 5; + mask = 1 << (nr & 0x1f); + return ((mask & *addr) != 0); +} + +static inline void bitmap_zero(unsigned long *dst, int nbits) +{ + if (nbits <= BITS_PER_LONG) + *dst = 0UL; + else { + int len = BITS_TO_LONGS(nbits) * sizeof(unsigned long); + RtlZeroMemory(dst, len); + } +} + +#define BITMAP_LAST_WORD_MASK(nbits) \ + ( ((nbits) % BITS_PER_LONG) ? (1UL<<((nbits) % BITS_PER_LONG))-1 : ~0UL ) + +int __bitmap_full(const unsigned long *bitmap, int bits); + +static inline int bitmap_full(const unsigned long *src, int nbits) +{ + if (nbits <= BITS_PER_LONG) + return ! (~(*src) & BITMAP_LAST_WORD_MASK(nbits)); + else + return __bitmap_full(src, nbits); +} + +int __bitmap_empty(const unsigned long *bitmap, int bits); + +static inline int bitmap_empty(const unsigned long *src, int nbits) +{ + if (nbits <= BITS_PER_LONG) + return ! (*src & BITMAP_LAST_WORD_MASK(nbits)); + else + return __bitmap_empty(src, nbits); +} + +#endif diff --git a/branches/WOF2-3/hw/mthca/kernel/mt_cache.c b/branches/WOF2-3/hw/mthca/kernel/mt_cache.c new file mode 100644 index 00000000..97662c3b --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/mt_cache.c @@ -0,0 +1,407 @@ +/* + * Copyright (c) 2004 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Intel Corporation. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2005 Voltaire, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include +#include "mthca_dev.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "mt_cache.tmh" +#endif +#include + +#include "ib_cache.h" + + +#pragma warning( disable : 4200) +struct ib_pkey_cache { + int table_len; + __be16 table[0]; +}; + +struct ib_gid_cache { + int table_len; + union ib_gid table[0]; +}; +#pragma warning( default : 4200) + +struct ib_update_work { + PIO_WORKITEM work_item; + struct ib_device *device; + u8 port_num; +}; + +int ib_get_cached_gid(struct ib_device *device, + u8 port_num, + int index, + union ib_gid *gid) +{ + union ib_gid cgid; + struct ib_gid_cache *cache; + SPIN_LOCK_PREP(lh); + + // sanity checks + if (port_num < start_port(device) || port_num > end_port(device)) + return -EINVAL; + if (!device->cache.gid_cache) + return -EFAULT; + + read_lock_irqsave(&device->cache.lock, &lh); + + cache = device->cache.gid_cache[port_num - start_port(device)]; + + if (index < 0 || index >= cache->table_len) { + read_unlock_irqrestore(&lh); + return -EINVAL; + } + + cgid = cache->table[index]; + read_unlock_irqrestore(&lh); + *gid = cgid; + + return 0; +} + +int ib_find_cached_gid(struct ib_device *device, + union ib_gid *gid, + u8 *port_num, + u16 *index) +{ + struct ib_gid_cache *cache; + int i; + u8 p; + SPIN_LOCK_PREP(lh); + + read_lock_irqsave(&device->cache.lock, &lh); + + for (p = 0; p <= end_port(device) - start_port(device); ++p) { + cache = device->cache.gid_cache[p]; + for (i = 0; i < cache->table_len; ++i) { + if (!memcmp(gid, &cache->table[i], sizeof *gid)) { + goto found; + } + } + } + + read_unlock_irqrestore(&lh); + *port_num = (u8)-1; + if (index) + *index = (u16)-1; + return -ENOENT; + +found: + read_unlock_irqrestore(&lh); + *port_num = p + start_port(device); + if (index) + *index = (u16)i; + + return 0; +} + +int ib_get_cached_pkey(struct ib_device *device, + u8 port_num, + int index, + __be16 *pkey) +{ + struct ib_pkey_cache *cache; + __be16 cpkey; + SPIN_LOCK_PREP(lh); + + // sanity checks + if (port_num < start_port(device) || port_num > end_port(device)) + return -EINVAL; + if (!device->cache.gid_cache) + return -EFAULT; + + read_lock_irqsave(&device->cache.lock, &lh); + + cache = device->cache.pkey_cache[port_num - start_port(device)]; + + if (index < 0 || index >= cache->table_len) { + read_unlock_irqrestore(&lh); + return -EINVAL; + } + + cpkey = cache->table[index]; + read_unlock_irqrestore(&lh); + *pkey = cpkey; + + return 0; +} + +int ib_find_cached_pkey(struct ib_device *device, + u8 port_num, + __be16 pkey, + u16 *index) +{ + struct ib_pkey_cache *cache; + int i; + SPIN_LOCK_PREP(lh); + + if (port_num < start_port(device) || port_num > end_port(device)) + return -EINVAL; + + read_lock_irqsave(&device->cache.lock, &lh); + + cache = device->cache.pkey_cache[port_num - start_port(device)]; + + for (i = 0; i < cache->table_len; ++i) + if ((cache->table[i] & 0x7fff) == (pkey & 0x7fff)) { + goto found; + } + + read_unlock_irqrestore(&lh); + *index = (u16)-1; + return -ENOENT; + +found: + read_unlock_irqrestore(&lh); + *index = (u16)i; + return 0; +} + +static void ib_cache_update(struct ib_device *device, + u8 port) +{ + struct ib_port_attr *tprops = NULL; + struct ib_pkey_cache *pkey_cache = NULL, *old_pkey_cache; + struct ib_gid_cache *gid_cache = NULL, *old_gid_cache; + int i; + int ret; + SPIN_LOCK_PREP(lh); + + tprops = kmalloc(sizeof *tprops, GFP_KERNEL); + if (!tprops) + return; + + ret = ib_query_port(device, port, tprops); + if (ret) { + HCA_PRINT(TRACE_LEVEL_WARNING,HCA_DBG_LOW,("ib_query_port failed (%d) for %s, port %d\n", + ret, device->name, port)); + goto err; + } + + pkey_cache = kmalloc(sizeof *pkey_cache + tprops->pkey_tbl_len * + sizeof *pkey_cache->table, GFP_KERNEL); + if (!pkey_cache) + goto err; + + pkey_cache->table_len = tprops->pkey_tbl_len; + + gid_cache = kmalloc(sizeof *gid_cache + tprops->gid_tbl_len * + sizeof *gid_cache->table, GFP_KERNEL); + if (!gid_cache) + goto err; + + gid_cache->table_len = tprops->gid_tbl_len; + + for (i = 0; i < pkey_cache->table_len; i+=32) { + __be16 pkey_chunk[32]; + int size; + ret = ib_query_pkey_chunk(device, port, (u16)i, pkey_chunk); + if (ret) { + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_LOW,("ib_query_pkey_chunk failed (%d) for %s (index %d)\n", + ret, device->name, i)); + goto err; + } + size = min(32, pkey_cache->table_len - i); + RtlCopyMemory(pkey_cache->table + i, pkey_chunk, size*sizeof(u16)); + } + + for (i = 0; i < gid_cache->table_len; i+=8) { + union ib_gid gid_chunk[8]; + int size; + ret = ib_query_gid_chunk(device, port, i, gid_chunk); + if (ret) { + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_LOW,("ib_query_gid_chunk failed (%d) for %s (index %d)\n", + ret, device->name, i)); + goto err; + } + size = min(8, gid_cache->table_len - i); + RtlCopyMemory(gid_cache->table + i, gid_chunk, size*sizeof(union ib_gid)); + } + + write_lock_irq(&device->cache.lock, &lh); + + old_pkey_cache = device->cache.pkey_cache[port - start_port(device)]; + old_gid_cache = device->cache.gid_cache [port - start_port(device)]; + + device->cache.pkey_cache[port - start_port(device)] = pkey_cache; + device->cache.gid_cache [port - start_port(device)] = gid_cache; + + write_unlock_irq(&lh); + + kfree(old_pkey_cache); + kfree(old_gid_cache); + kfree(tprops); + return; + +err: + kfree(pkey_cache); + kfree(gid_cache); + kfree(tprops); +} + +static void ib_cache_task(void *work_ptr) +{ + struct ib_update_work *work = work_ptr; + + ib_cache_update(work->device, work->port_num); +} + +/* leo: wrapper for Linux work_item callback */ +VOID + ib_work_item ( + IN PDEVICE_OBJECT DeviceObject, + IN PVOID Context + ) +{ + struct ib_update_work *work = (struct ib_update_work *)Context; + UNREFERENCED_PARAMETER(DeviceObject); + ib_cache_task(Context); + IoFreeWorkItem(work->work_item); + kfree(Context); +} + +static void ib_cache_event(struct ib_event_handler *handler, + struct ib_event *event) +{ + struct ib_update_work *work; + + if (event->event == IB_EVENT_PORT_ERR || + event->event == IB_EVENT_PORT_ACTIVE || + event->event == IB_EVENT_LID_CHANGE || + event->event == IB_EVENT_PKEY_CHANGE || + event->event == IB_EVENT_SM_CHANGE) { + work = kmalloc(sizeof *work, GFP_ATOMIC); + //TODO: what will happen on allocation failure ? + if (work) { + work->device = event->device; + work->port_num = event->element.port_num; + + { // schedule a work item to work + // get PDO + PDEVICE_OBJECT pdo = handler->device->mdev->ext->cl_ext.p_self_do; + + // allocate work item + work->work_item = IoAllocateWorkItem(pdo); + if (work->work_item == NULL) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_LOW,("Failed to allocate workitem for cache update.\n")); + } + else { // schedule the work + IoQueueWorkItem( + work->work_item, + ib_work_item, + DelayedWorkQueue, + work + ); + } + } + + } + else + { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_MEMORY,("Failed to memory for workitem.\n")); + } + } +} + +static void ib_cache_setup_one(struct ib_device *device) +{ + u8 p; + + rwlock_init(&device->cache.lock); + INIT_IB_EVENT_HANDLER(&device->cache.event_handler, + device, ib_cache_event); + ib_register_event_handler(&device->cache.event_handler); + + device->cache.pkey_cache = + kmalloc(sizeof *device->cache.pkey_cache * + (end_port(device) - start_port(device) + 1), GFP_KERNEL); + device->cache.gid_cache = + kmalloc(sizeof *device->cache.gid_cache * + (end_port(device) - start_port(device) + 1), GFP_KERNEL); + + if (!device->cache.pkey_cache || !device->cache.gid_cache) { + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_LOW,("Couldn't allocate cache " + "for %s\n", device->name)); + goto err; + } + + for (p = 0; p <= end_port(device) - start_port(device); ++p) { + device->cache.pkey_cache[p] = NULL; + device->cache.gid_cache [p] = NULL; + ib_cache_update(device, p + start_port(device)); + } + + return; + +err: + kfree(device->cache.pkey_cache); + kfree(device->cache.gid_cache); +} + +static void ib_cache_cleanup_one(struct ib_device *device) +{ + int p; + + ib_unregister_event_handler(&device->cache.event_handler); + //TODO: how to do that ? + // LINUX: flush_scheduled_work(); + + for (p = 0; p <= end_port(device) - start_port(device); ++p) { + kfree(device->cache.pkey_cache[p]); + kfree(device->cache.gid_cache[p]); + } + + kfree(device->cache.pkey_cache); + kfree(device->cache.gid_cache); +} + +static struct ib_client cache_client = { "cache", ib_cache_setup_one, ib_cache_cleanup_one }; + +int ib_cache_setup(void) +{ + return ib_register_client(&cache_client); +} + +void ib_cache_cleanup(void) +{ + ib_unregister_client(&cache_client); +} + diff --git a/branches/WOF2-3/hw/mthca/kernel/mt_device.c b/branches/WOF2-3/hw/mthca/kernel/mt_device.c new file mode 100644 index 00000000..883c9868 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/mt_device.c @@ -0,0 +1,569 @@ +/* + * Copyright (c) 2004 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include "hca_driver.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "mt_device.tmh" +#endif +#include "ib_verbs.h" +#include "ib_cache.h" + +struct ib_client_data { + struct list_head list; + struct ib_client *client; + void * data; +}; + +static LIST_HEAD(device_list); +static LIST_HEAD(client_list); + +/* + * device_mutex protects access to both device_list and client_list. + * There's no real point to using multiple locks or something fancier + * like an rwsem: we always access both lists, and we're always + * modifying one list or the other list. In any case this is not a + * hot path so there's no point in trying to optimize. + */ +KMUTEX device_mutex; + +static int ib_device_check_mandatory(struct ib_device *device) +{ +#define IB_MANDATORY_FUNC(x) { offsetof(struct ib_device, x), #x } + static const struct { + size_t offset; + char *name; + } mandatory_table[] = { + IB_MANDATORY_FUNC(query_device), + IB_MANDATORY_FUNC(query_port), + IB_MANDATORY_FUNC(query_pkey_chunk), + IB_MANDATORY_FUNC(query_gid_chunk), + IB_MANDATORY_FUNC(alloc_pd), + IB_MANDATORY_FUNC(dealloc_pd), + IB_MANDATORY_FUNC(create_ah), + IB_MANDATORY_FUNC(destroy_ah), + IB_MANDATORY_FUNC(create_qp), + IB_MANDATORY_FUNC(modify_qp), + IB_MANDATORY_FUNC(destroy_qp), + IB_MANDATORY_FUNC(post_send), + IB_MANDATORY_FUNC(post_recv), + IB_MANDATORY_FUNC(create_cq), + IB_MANDATORY_FUNC(destroy_cq), + IB_MANDATORY_FUNC(poll_cq), + IB_MANDATORY_FUNC(req_notify_cq), + IB_MANDATORY_FUNC(get_dma_mr), + IB_MANDATORY_FUNC(dereg_mr) + }; + int i; + + for (i = 0; i < sizeof mandatory_table / sizeof mandatory_table[0]; ++i) { + if (!*(void **) ((u8 *) device + mandatory_table[i].offset)) { + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_LOW,("Device %s is missing mandatory function %s\n", + device->name, mandatory_table[i].name)); + return -EINVAL; + } + } + + return 0; +} + +static struct ib_device *__ib_device_get_by_name(const char *name) +{ + struct ib_device *device; + + list_for_each_entry(device, &device_list, core_list,struct ib_device) + if (!strncmp(name, device->name, IB_DEVICE_NAME_MAX)) + return device; + + return NULL; +} + +static int __extract_number(char *dest_str, const char *format, int *num) +{ + char *ptr; + UNREFERENCED_PARAMETER(format); + for (ptr = dest_str; *ptr; ptr++) { + if (*ptr >= '0' && *ptr <= '9') { + *num = atoi(ptr); + return 1; + } + } + return 0; +} +static int alloc_name(char *name) +{ + long *inuse; + char buf[IB_DEVICE_NAME_MAX]; + struct ib_device *device; + int i; + + inuse = (long *) get_zeroed_page(GFP_KERNEL); + if (!inuse) + return -ENOMEM; + + list_for_each_entry(device, &device_list, core_list,struct ib_device) { + if (!__extract_number(device->name, name, &i)) + continue; + if (i < 0 || i >= PAGE_SIZE * 8) + continue; + if (RtlStringCbPrintfA(buf, sizeof buf, name, i)) + return -EINVAL; + + if (!strncmp(buf, device->name, IB_DEVICE_NAME_MAX)) + set_bit(i, inuse); + } + + i = find_first_zero_bit((const unsigned long *)inuse, PAGE_SIZE * 8); + free_page(inuse); + if (RtlStringCbPrintfA(buf, sizeof buf, name, i)) + return -EINVAL; + + + if (__ib_device_get_by_name(buf)) + return -ENFILE; + + strlcpy(name, buf, IB_DEVICE_NAME_MAX); + return 0; +} + +static int add_client_context(struct ib_device *device, struct ib_client *client) +{ + struct ib_client_data *context; + SPIN_LOCK_PREP(lh); + + context = kmalloc(sizeof *context, GFP_KERNEL); + if (!context) { + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_LOW,("Couldn't allocate client context for %s/%s\n", + device->name, client->name)); + return -ENOMEM; + } + + context->client = client; + context->data = NULL; + + spin_lock_irqsave(&device->client_data_lock, &lh); + list_add(&context->list, &device->client_data_list); + spin_unlock_irqrestore(&lh); + + return 0; +} + +/** + * ib_register_device - Register an IB device with IB core + * @device:Device to register + * + * Low-level drivers use ib_register_device() to register their + * devices with the IB core. All registered clients will receive a + * callback for each device that is added. @device must be allocated + * with ib_alloc_device(). + */ +int ib_register_device(struct ib_device *device) +{ + int ret = 0; + + down(&device_mutex); + + if (strchr(device->name, '%')) { + ret = alloc_name(device->name); + if (ret) + goto out; + } + + if (ib_device_check_mandatory(device)) { + ret = -EINVAL; + goto out; + } + + INIT_LIST_HEAD(&device->event_handler_list); + INIT_LIST_HEAD(&device->client_data_list); + spin_lock_init(&device->event_handler_lock); + spin_lock_init(&device->client_data_lock); + + list_add_tail(&device->core_list, &device_list); + + { + struct ib_client *client; + + list_for_each_entry(client, &client_list, list,struct ib_client) + if (client->add && !add_client_context(device, client)) + client->add(device); + } + + out: + up(&device_mutex); + return ret; +} + + +/** + * ib_unregister_device - Unregister an IB device + * @device:Device to unregister + * + * Unregister an IB device. All clients will receive a remove callback. + */ +void ib_unregister_device(struct ib_device *device) +{ + struct ib_client *client; + struct ib_client_data *context, *tmp; + SPIN_LOCK_PREP(lh); + + down(&device_mutex); + + list_for_each_entry_reverse(client, &client_list, list,struct ib_client) + if (client->remove) + client->remove(device); + + list_del(&device->core_list); + + up(&device_mutex); + + spin_lock_irqsave(&device->client_data_lock, &lh); + list_for_each_entry_safe(context, tmp, &device->client_data_list, list,struct ib_client_data,struct ib_client_data) + kfree(context); + spin_unlock_irqrestore(&lh); + +} + + +/** + * ib_register_client - Register an IB client + * @client:Client to register + * + * Upper level users of the IB drivers can use ib_register_client() to + * register callbacks for IB device addition and removal. When an IB + * device is added, each registered client's add method will be called + * (in the order the clients were registered), and when a device is + * removed, each client's remove method will be called (in the reverse + * order that clients were registered). In addition, when + * ib_register_client() is called, the client will receive an add + * callback for all devices already registered. + */ +int ib_register_client(struct ib_client *client) +{ + struct ib_device *device; + + down(&device_mutex); + + list_add_tail(&client->list, &client_list); + list_for_each_entry(device, &device_list, core_list,struct ib_device) + if (client->add && !add_client_context(device, client)) + client->add(device); + + up(&device_mutex); + + return 0; +} + + +/** + * ib_unregister_client - Unregister an IB client + * @client:Client to unregister + * + * Upper level users use ib_unregister_client() to remove their client + * registration. When ib_unregister_client() is called, the client + * will receive a remove callback for each IB device still registered. + */ +void ib_unregister_client(struct ib_client *client) +{ + struct ib_client_data *context, *tmp; + struct ib_device *device; + SPIN_LOCK_PREP(lh); + + down(&device_mutex); + + list_for_each_entry(device, &device_list, core_list,struct ib_device) { + if (client->remove) + client->remove(device); + + spin_lock_irqsave(&device->client_data_lock, &lh); + list_for_each_entry_safe(context, tmp, &device->client_data_list, list,struct ib_client_data,struct ib_client_data) + if (context->client == client) { + list_del(&context->list); + kfree(context); + } + spin_unlock_irqrestore(&lh); + } + list_del(&client->list); + + up(&device_mutex); +} + + +/** + * ib_get_client_data - Get IB client context + * @device:Device to get context for + * @client:Client to get context for + * + * ib_get_client_data() returns client context set with + * ib_set_client_data(). + */ +void *ib_get_client_data(struct ib_device *device, struct ib_client *client) +{ + struct ib_client_data *context; + void *ret = NULL; + SPIN_LOCK_PREP(lh); + + spin_lock_irqsave(&device->client_data_lock, &lh); + list_for_each_entry(context, &device->client_data_list, list,struct ib_client_data) + if (context->client == client) { + ret = context->data; + break; + } + spin_unlock_irqrestore(&lh); + + return ret; +} + + +/** + * ib_set_client_data - Get IB client context + * @device:Device to set context for + * @client:Client to set context for + * @data:Context to set + * + * ib_set_client_data() sets client context that can be retrieved with + * ib_get_client_data(). + */ +void ib_set_client_data(struct ib_device *device, struct ib_client *client, + void *data) +{ + struct ib_client_data *context; + SPIN_LOCK_PREP(lh); + + spin_lock_irqsave(&device->client_data_lock, &lh); + list_for_each_entry(context, &device->client_data_list, list,struct ib_client_data) + if (context->client == client) { + context->data = data; + goto out; + } + + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_LOW ,("No client context found for %s/%s\n", + device->name, client->name)); + +out: + spin_unlock_irqrestore(&lh); +} + + +/** + * ib_register_event_handler - Register an IB event handler + * @event_handler:Handler to register + * + * ib_register_event_handler() registers an event handler that will be + * called back when asynchronous IB events occur (as defined in + * chapter 11 of the InfiniBand Architecture Specification). This + * callback may occur in interrupt context. + */ +int ib_register_event_handler (struct ib_event_handler *event_handler) +{ + SPIN_LOCK_PREP(lh); + + spin_lock_irqsave(&event_handler->device->event_handler_lock, &lh); + list_add_tail(&event_handler->list, + &event_handler->device->event_handler_list); + spin_unlock_irqrestore(&lh); + + return 0; +} + + +/** + * ib_unregister_event_handler - Unregister an event handler + * @event_handler:Handler to unregister + * + * Unregister an event handler registered with + * ib_register_event_handler(). + */ +int ib_unregister_event_handler(struct ib_event_handler *event_handler) +{ + SPIN_LOCK_PREP(lh); + spin_lock_irqsave(&event_handler->device->event_handler_lock, &lh); + list_del(&event_handler->list); + spin_unlock_irqrestore(&lh); + + return 0; +} + + +/** + * ib_dispatch_event - Dispatch an asynchronous event + * @event:Event to dispatch + * + * Low-level drivers must call ib_dispatch_event() to dispatch the + * event to all registered event handlers when an asynchronous event + * occurs. + */ +void ib_dispatch_event(struct ib_event *event) +{ + struct ib_event_handler *handler; + SPIN_LOCK_PREP(lh); + + spin_lock_irqsave(&event->device->event_handler_lock, &lh); + + list_for_each_entry(handler, &event->device->event_handler_list, list,struct ib_event_handler) + handler->handler(handler, event); + + spin_unlock_irqrestore(&lh); +} + + +/** + * ib_query_device - Query IB device attributes + * @device:Device to query + * @device_attr:Device attributes + * + * ib_query_device() returns the attributes of a device through the + * @device_attr pointer. + */ +int ib_query_device(struct ib_device *device, + struct ib_device_attr *device_attr) +{ + return device->query_device(device, device_attr); +} + + +/** + * ib_query_port - Query IB port attributes + * @device:Device to query + * @port_num:Port number to query + * @port_attr:Port attributes + * + * ib_query_port() returns the attributes of a port through the + * @port_attr pointer. + */ +int ib_query_port(struct ib_device *device, + u8 port_num, + struct ib_port_attr *port_attr) +{ + if (port_num < start_port(device) || port_num > end_port(device)) + return -EINVAL; + return device->query_port(device, port_num, port_attr); +} + + +/** + * ib_query_gid_chunk - Get a chunk of GID table entries + * @device:Device to query + * @port_num:Port number to query + * @index:GID table index to query + * @gid:Returned GIDs chunk + * + * ib_query_gid_chunk() fetches the specified GID table enties chunk. + */ +int ib_query_gid_chunk(struct ib_device *device, + u8 port_num, int index, union ib_gid gid[8]) +{ + return device->query_gid_chunk(device, port_num, index, gid); +} + + +/** + * ib_query_pkey_chunk - Get a chunk of P_Key table entries + * @device:Device to query + * @port_num:Port number to query + * @index:P_Key table index to query + * @pkey:Returned P_Keys chunk + * + * ib_query_pkey_chunk() fetches the specified P_Key table entries chunk. + */ +int ib_query_pkey_chunk(struct ib_device *device, + u8 port_num, u16 index, __be16 pkey[32]) +{ + return device->query_pkey_chunk(device, port_num, index, pkey); +} + + +/** + * ib_modify_device - Change IB device attributes + * @device:Device to modify + * @device_modify_mask:Mask of attributes to change + * @device_modify:New attribute values + * + * ib_modify_device() changes a device's attributes as specified by + * the @device_modify_mask and @device_modify structure. + */ +int ib_modify_device(struct ib_device *device, + int device_modify_mask, + struct ib_device_modify *device_modify) +{ + return device->modify_device(device, device_modify_mask, + device_modify); +} + + +/** + * ib_modify_port - Modifies the attributes for the specified port. + * @device: The device to modify. + * @port_num: The number of the port to modify. + * @port_modify_mask: Mask used to specify which attributes of the port + * to change. + * @port_modify: New attribute values for the port. + * + * ib_modify_port() changes a port's attributes as specified by the + * @port_modify_mask and @port_modify structure. + */ +int ib_modify_port(struct ib_device *device, + u8 port_num, int port_modify_mask, + struct ib_port_modify *port_modify) +{ + if (port_num < start_port(device) || port_num > end_port(device)) + return -EINVAL; + + return device->modify_port(device, port_num, port_modify_mask, + port_modify); +} + +int ib_core_init(void) +{ + int ret; + + /* leo: added because there is no static init of semaphore in Windows */ + KeInitializeMutex(&device_mutex,0); + + ret = ib_cache_setup(); + if (ret) { + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_LOW ,("Couldn't set up InfiniBand P_Key/GID cache\n")); + } + + return ret; +} + +void ib_core_cleanup(void) +{ + ib_cache_cleanup(); +} + diff --git a/branches/WOF2-3/hw/mthca/kernel/mt_l2w.c b/branches/WOF2-3/hw/mthca/kernel/mt_l2w.c new file mode 100644 index 00000000..0979a74c --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/mt_l2w.c @@ -0,0 +1,133 @@ +#include +#include +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "mt_l2w.tmh" +#endif + +pci_pool_t * +pci_pool_create (const char *name, struct mthca_dev *mdev, + size_t size, size_t align, size_t allocation) +{ + pci_pool_t *pool; + UNREFERENCED_PARAMETER(align); + UNREFERENCED_PARAMETER(allocation); + + MT_ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); + + // allocation parameter is not handled yet + ASSERT(allocation == 0); + + // allocate object + pool = (pci_pool_t *)ExAllocatePoolWithTag( NonPagedPool, sizeof(pci_pool_t), MT_TAG_PCIPOOL ); + if (pool == NULL) + return NULL; + + //TODO: not absolutely correct: Linux's pci_pool_alloc provides contiguous physical memory, + // while default alloc function - ExAllocatePoolWithTag -doesn't. + // But for now it is used for elements of size <= PAGE_SIZE + // Anyway - a sanity check: + ASSERT(size <= PAGE_SIZE); + if (size > PAGE_SIZE) + return NULL; + + //TODO: not too effective: one can read its own alloc/free functions + ExInitializeNPagedLookasideList( &pool->pool_hdr, NULL, NULL, 0, size, MT_TAG_PCIPOOL, 0 ); + + // fill the object + pool->mdev = mdev; + pool->size = size; + strncpy( pool->name, name, sizeof pool->name ); + + return pool; +} + +// from lib/string.c +/** +* strlcpy - Copy a %NUL terminated string into a sized buffer +* @dest: Where to copy the string to +* @src: Where to copy the string from +* @size: size of destination buffer +* +* Compatible with *BSD: the result is always a valid +* NUL-terminated string that fits in the buffer (unless, +* of course, the buffer size is zero). It does not pad +* out the result like strncpy() does. +*/ +SIZE_T strlcpy(char *dest, const char *src, SIZE_T size) +{ + SIZE_T ret = strlen(src); + + if (size) { + SIZE_T len = (ret >= size) ? size-1 : ret; + memcpy(dest, src, len); + dest[len] = '\0'; + } + return ret; +} + + +int __bitmap_full(const unsigned long *bitmap, int bits) +{ + int k, lim = bits/BITS_PER_LONG; + for (k = 0; k < lim; ++k) + if (~bitmap[k]) + return 0; + + if (bits % BITS_PER_LONG) + if (~bitmap[k] & BITMAP_LAST_WORD_MASK(bits)) + return 0; + + return 1; +} + +int __bitmap_empty(const unsigned long *bitmap, int bits) +{ + int k, lim = bits/BITS_PER_LONG; + for (k = 0; k < lim; ++k) + if (bitmap[k]) + return 0; + + if (bits % BITS_PER_LONG) + if (bitmap[k] & BITMAP_LAST_WORD_MASK(bits)) + return 0; + + return 1; +} + +int request_irq( + IN CM_PARTIAL_RESOURCE_DESCRIPTOR *int_info, /* interrupt resources */ + IN KSPIN_LOCK *isr_lock, /* spin lock for ISR */ + IN PKSERVICE_ROUTINE isr, /* ISR */ + IN void *isr_ctx, /* ISR context */ + OUT PKINTERRUPT *int_obj /* interrupt object */ + ) +{ + NTSTATUS status; + + status = IoConnectInterrupt( + int_obj, /* InterruptObject */ + isr, /* ISR */ + isr_ctx, /* ISR context */ + isr_lock, /* spinlock */ + int_info->u.Interrupt.Vector, /* interrupt vector */ + (KIRQL)int_info->u.Interrupt.Level, /* IRQL */ + (KIRQL)int_info->u.Interrupt.Level, /* Synchronize IRQL */ + (BOOLEAN)((int_info->Flags == CM_RESOURCE_INTERRUPT_LATCHED) ? + Latched : LevelSensitive), /* interrupt type: LATCHED or LEVEL */ + (BOOLEAN)(int_info->ShareDisposition == CmResourceShareShared), /* vector shared or not */ + (KAFFINITY)int_info->u.Interrupt.Affinity, /* interrupt affinity */ + FALSE /* whether to save Float registers */ + ); + + if (!NT_SUCCESS(status)) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_INIT ,("IoConnectInterrupt failed status %d (did you change the processor_affinity ? )\n",status)); + return -EFAULT; /* failed to connect interrupt */ + } + else + return 0; +} + + diff --git a/branches/WOF2-3/hw/mthca/kernel/mt_l2w.h b/branches/WOF2-3/hw/mthca/kernel/mt_l2w.h new file mode 100644 index 00000000..faf34055 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/mt_l2w.h @@ -0,0 +1,92 @@ +#ifndef MT_L2W_H +#define MT_L2W_H + +// =========================================== +// INCLUDES +// =========================================== + +// OS +#include +#include +#include +#include + +// ours - the order is important +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include + + +// =========================================== +// SUBSTITUTIONS +// =========================================== + +#define BUG_ON(exp) ASSERT(!(exp)) /* in Linux follows here panic() !*/ +#define WARN_ON(exp) ASSERT(!(exp)) /* in Linux follows here panic() !*/ +#define snprintf _snprintf + +// memory barriers +#define wmb KeMemoryBarrier +#define rmb KeMemoryBarrier +#define mb KeMemoryBarrier + +// =========================================== +// LITERALS +// =========================================== + + + + +// =========================================== +// TYPES +// =========================================== + +// rw_lock +typedef spinlock_t rwlock_t; + +// dummy function +typedef void (*MT_EMPTY_FUNC)(); + +// =========================================== +// MACROS +// =========================================== + +// ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +// ALIGN +#define ALIGN(x,a) (((x)+(a)-1)&~((a)-1)) + +// there is a bug in Microsoft compiler, that when _byteswap_uint64() gets an expression +// it executes the expression but doesn't swap tte dwords +// So, there's a workaround +#ifdef BYTESWAP_UINT64_BUG_FIXED +#define CPU_2_BE64_PREP +#define CPU_2_BE64(x) cl_hton64(x) +#else +#define CPU_2_BE64_PREP unsigned __int64 __tmp__ +#define CPU_2_BE64(x) ( __tmp__ = x, cl_hton64(__tmp__) ) +#endif + + +SIZE_T strlcpy(char *dest, const char *src, SIZE_T size); +void MT_time_calibrate(); + +#define ERR_PTR(error) ((void*)(LONG_PTR)(error)) +#define PTR_ERR(ptr) ((long)(LONG_PTR)(void*)(ptr)) +//TODO: there are 2 assumptions here: +// - pointer can't be too big (around -1) +// - error can't be bigger than 1000 +#define IS_ERR(ptr) ((ULONG_PTR)ptr > (ULONG_PTR)-1000L) + +#endif diff --git a/branches/WOF2-3/hw/mthca/kernel/mt_list.h b/branches/WOF2-3/hw/mthca/kernel/mt_list.h new file mode 100644 index 00000000..092057ee --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/mt_list.h @@ -0,0 +1,63 @@ +#ifndef MT_LIST_H +#define MT_LIST_H + +/* Use the type, defined in wdm.h */ +#define list_head _LIST_ENTRY + +/* Define and initialize a list header */ +#define LIST_HEAD(name) \ + struct list_head name = { &(name), &(name) } + +/* Initialize a list header */ +#define INIT_LIST_HEAD(ptr) InitializeListHead(ptr) + +/* Get to the beginning of the struct for this list entry */ +#define list_entry(ptr, type, member) CONTAINING_RECORD(ptr, type, member) + +/* Iterate over list of 'list_els' of given 'type' */ +#define list_for_each_entry(list_el, head, member, type) \ + for ( list_el = list_entry((head)->Flink, type, member); \ + &list_el->member != (head); \ + list_el = list_entry(list_el->member.Flink, type, member)) + +/* Iterate backwards over list of 'list_els' of given 'type' */ +#define list_for_each_entry_reverse(list_el, head, member, type) \ + for (list_el = list_entry((head)->Blink, type, member); \ + &list_el->member != (head); \ + list_el = list_entry(list_el->member.Blink, type, member)) + +/* Iterate over list of given type safe against removal of list entry */ +#define list_for_each_entry_safe(list_el, tmp_list_el, head, member,type, tmp_type) \ + for (list_el = list_entry((head)->Flink, type, member), \ + tmp_list_el = list_entry(list_el->member.Flink, type, member); \ + &list_el->member != (head); \ + list_el = tmp_list_el, \ + tmp_list_el = list_entry(tmp_list_el->member.Flink, tmp_type, member)) + + +/* Insert a new entry after the specified head. */ +static inline void list_add(struct list_head *new_entry, struct list_head *head) +{ + InsertHeadList( head, new_entry ); +} + +/* Insert a new entry before the specified head. */ +static inline void list_add_tail(struct list_head *new_entry, struct list_head *head) +{ + InsertTailList( head, new_entry ); +} + +/* Deletes entry from list. */ +static inline void list_del(struct list_head *entry) +{ + RemoveEntryList( entry ); +} + +/* Tests whether a list is empty */ +static inline int list_empty(const struct list_head *head) +{ + return IsListEmpty( head ); +} + + +#endif diff --git a/branches/WOF2-3/hw/mthca/kernel/mt_memory.c b/branches/WOF2-3/hw/mthca/kernel/mt_memory.c new file mode 100644 index 00000000..5a8bd1ca --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/mt_memory.c @@ -0,0 +1,762 @@ +/* + * Copyright (c) 2004 Topspin Corporation. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + #include "hca_driver.h" +#include "mthca_dev.h" +#if defined (EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "mt_memory.tmh" +#endif + +#include "mt_pa_cash.h" + + +/* +* Function: map user buffer to kernel and lock it +* +* Return: +*/ +int get_user_pages( + IN struct mthca_dev *dev, /* device */ + IN u64 start, /* address in user space */ + IN int npages, /* size in pages */ + IN int write_access, /* access rights */ + OUT struct scatterlist *sg /* s/g list */ + ) +{ + PMDL mdl_p; + int size = npages << PAGE_SHIFT; + int access = (write_access) ? IoWriteAccess : IoReadAccess; + int err; + void * kva; /* kernel virtual address */ + + UNREFERENCED_PARAMETER(dev); + + HCA_ENTER(HCA_DBG_MEMORY); + ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL); + + /* allocate MDL */ + mdl_p = IoAllocateMdl( (PVOID)(ULONG_PTR)start, (ULONG)size, + FALSE, + FALSE, /* not charge quota */ + NULL); + if (mdl_p == NULL) { + err = -ENOMEM; + goto err0; + } + + /* lock memory */ + __try { + MmProbeAndLockPages( mdl_p, UserMode, access ); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + NTSTATUS Status = GetExceptionCode(); + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_MEMORY ,("Exception 0x%x on MmProbeAndLockPages(), addr 0x%I64x, size %d\n", Status, start, size)); + switch(Status){ + case STATUS_WORKING_SET_QUOTA: + err = -ENOMEM;break; + case STATUS_ACCESS_VIOLATION: + err = -EACCES;break; + default : + err = -EINVAL; + } + + goto err1; + } + + /* map it to kernel */ + kva = MmMapLockedPagesSpecifyCache( mdl_p, + KernelMode, MmNonCached, + NULL, FALSE, NormalPagePriority ); + if (kva == NULL) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_MEMORY ,("MmMapLockedPagesSpecifyCache failed\n")); + err = -EFAULT; + goto err2; + } + + sg->page = kva; + sg->length = size; + sg->offset = (unsigned int)(start & ~PAGE_MASK); + sg->p_mdl = mdl_p; + sg->dma_address = MmGetPhysicalAddress(kva).QuadPart; + return 0; + +err2: + MmUnlockPages(mdl_p); +err1: + IoFreeMdl(mdl_p); +err0: + HCA_EXIT(HCA_DBG_MEMORY); + return err; + + } + +void put_page(struct scatterlist *sg) +{ + if (sg->p_mdl) { + MmUnmapLockedPages( sg->page, sg->p_mdl ); + MmUnlockPages(sg->p_mdl); + IoFreeMdl(sg->p_mdl); + } +} + +VOID + AdapterListControl( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PSCATTER_GATHER_LIST ScatterGather, + IN PVOID Context + ) +{ + struct scatterlist *p_sg = (struct scatterlist *)Context; + + UNREFERENCED_PARAMETER(DeviceObject); + UNREFERENCED_PARAMETER(Irp); + + // sanity checks + if (!ScatterGather || !Context) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("AdapterListControl failed: invalid parameters\n")); + return; + } + if (ScatterGather->NumberOfElements > 1) { + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_LOW ,("AdapterListControl failed: unexpected sg size; %d elements \n", + ScatterGather->NumberOfElements )); + } + if (ScatterGather->Elements[0].Length != p_sg->length) { + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_LOW ,("AdapterListControl failed: unexpected buffer size %#x (expected %#x) \n", + ScatterGather->Elements[0].Length, p_sg->length )); + } + + // results + p_sg->dma_address = ScatterGather->Elements[0].Address.QuadPart; // get logical address + p_sg->p_os_sg = ScatterGather; // store sg list address for releasing + //NB: we do not flush the buffers by FlushAdapterBuffers(), because we don't really transfer data +} + +/* Returns: the number of mapped sg elements */ +int pci_map_sg(struct mthca_dev *dev, + struct scatterlist *sg, int nents, int direction) +{ +#ifndef USE_GET_SG_LIST + + UNREFERENCED_PARAMETER(dev); + UNREFERENCED_PARAMETER(sg); + UNREFERENCED_PARAMETER(direction); + + // mapping was performed in alloc_dma_mem + return nents; + +#else + + int i; + NTSTATUS status; + hca_dev_ext_t *p_ext = dev->ext; + struct scatterlist *p_sg = sg; + KIRQL irql = KeRaiseIrqlToDpcLevel(); + + for (i=0; ip_dma_adapter->DmaOperations->GetScatterGatherList( + p_ext->p_dma_adapter, p_ext->cl_ext.p_self_do, p_sg->p_mdl, p_sg->page, + p_sg->length, AdapterListControl, sg, (BOOLEAN)direction ); + if (!NT_SUCCESS(status)) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("GetScatterGatherList failed %#x\n", status))); + break; + } + } + KeLowerIrql(irql); + return i; /* i.e., we mapped all the entries */ + +#endif +} + +/* Returns: the number of unmapped sg elements */ +int pci_unmap_sg(struct mthca_dev *dev, + struct scatterlist *sg, int nents, int direction) +{ +#ifndef USE_GET_SG_LIST + + UNREFERENCED_PARAMETER(dev); + UNREFERENCED_PARAMETER(sg); + UNREFERENCED_PARAMETER(direction); + // mapping was performed in alloc_dma_mem + return nents; + +#else + + int i; + hca_dev_ext_t *p_ext = dev->ext; + struct scatterlist *p_sg = sg; + KIRQL irql = KeRaiseIrqlToDpcLevel(); + void *p_os_sg = p_sg->p_os_sg; + + for (i=0; ip_os_sg = NULL; + p_ext->p_dma_adapter->DmaOperations->PutScatterGatherList( + p_ext->p_dma_adapter, p_os_sg, (BOOLEAN)direction ); + } + KeLowerIrql(irql); + return i; /* i.e., we mapped all the entries */ + +#endif +} + +/* The function zeroes 'struct scatterlist' and then fills it with values. + On error 'struct scatterlist' is returned zeroed */ +void *alloc_dma_mem( + IN struct mthca_dev *dev, + IN unsigned long size, + OUT struct scatterlist *p_sg) +{ + void *va; + DMA_ADAPTER *p_dma = dev->ext->p_dma_adapter; + +#ifndef USE_GET_SG_LIST + + PHYSICAL_ADDRESS pa = {0}; + ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); + + RtlZeroMemory(p_sg,sizeof *p_sg); + if (!size) + return NULL; + + va = p_dma->DmaOperations->AllocateCommonBuffer( + p_dma, size, &pa, FALSE ); + if (va) { + p_sg->length = size; + p_sg->dma_address = pa.QuadPart; + p_sg->page = va; + } + +#else + + int err; + PHYSICAL_ADDRESS la = {0}, ba = {0}, ha = {(u64)(-1I64)}; + PMDL p_mdl; + + ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); + + RtlZeroMemory(p_sg,sizeof *p_sg); + if (!size) + return NULL; + + // allocate memory + va = MmAllocateContiguousMemorySpecifyCache( + size, la, ha, ba, MmNonCached ); + if (!va) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("MmAllocateContiguousMemorySpecifyCache failed on %#x size\n", size ))); + goto err_alloc; + } + + // allocate MDL + p_mdl = IoAllocateMdl( va, size, FALSE, FALSE, NULL ); + if (!p_mdl) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("MmAllocateContiguousMemorySpecifyCache failed on %#x size\n", size ))); + goto err_mdl; + } + MmBuildMdlForNonPagedPool( p_mdl ); + + p_sg->p_mdl = p_mdl; + p_sg->length = size; + p_sg->page = va; + + goto end; + +err_mdl: + MmFreeContiguousMemory(va); + va = NULL; +err_alloc: +end: + +#endif + + return va; +} + +void free_dma_mem( + IN struct mthca_dev *dev, + IN struct scatterlist *p_sg) +{ +#ifndef USE_GET_SG_LIST + + PHYSICAL_ADDRESS pa; + DMA_ADAPTER *p_dma = dev->ext->p_dma_adapter; + + ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); + + if (p_sg->length) { + pa.QuadPart = p_sg->dma_address; + p_dma->DmaOperations->FreeCommonBuffer( + p_dma, p_sg->length, pa, + p_sg->page, FALSE ); + } + +#else + + PMDL p_mdl = p_sg->p_mdl; + PVOID page = p_sg->page; + + ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); + if (p_mdl) { + p_sg->p_mdl = NULL; + IoFreeMdl( p_mdl ); + } + if (page) { + p_sg->page = NULL; + MmFreeContiguousMemory(page); + } + +#endif +} + + +typedef struct _mt_iobuf_seg { + LIST_ENTRY link; + PMDL mdl_p; + u64 va; /* virtual address of the buffer */ + u64 size; /* size in bytes of the buffer */ + u32 nr_pages; + int is_user; +} mt_iobuf_seg_t; + +// Returns: 0 on success, -ENOMEM or -EACCESS on error +static int register_segment( + IN u64 va, + IN u64 size, + IN int is_user, + IN ib_access_t acc, + OUT mt_iobuf_seg_t **iobuf_seg) +{ + PMDL mdl_p; + int rc; + KPROCESSOR_MODE mode; + mt_iobuf_seg_t * new_iobuf; + static ULONG cnt=0; + LOCK_OPERATION Operation; + + // set Operation + if (acc & IB_AC_LOCAL_WRITE) + Operation = IoModifyAccess; + else + Operation = IoReadAccess; + + // allocate IOBUF segment object + new_iobuf = (mt_iobuf_seg_t *)kmalloc(sizeof(mt_iobuf_seg_t), GFP_KERNEL ); + if (new_iobuf == NULL) { + rc = -ENOMEM; + goto err_nomem; + } + + // allocate MDL + mdl_p = IoAllocateMdl( (PVOID)(ULONG_PTR)va, (ULONG)size, FALSE,FALSE,NULL); + if (mdl_p == NULL) { + rc = -ENOMEM; + goto err_alloc_mdl; + } + + // make context-dependent things + if (is_user) { + ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL); + mode = UserMode; + } + else { /* Mapping to kernel virtual address */ + // MmBuildMdlForNonPagedPool(mdl_p); // fill MDL ??? - should we do that really ? + mode = KernelMode; + } + + __try { /* try */ + MmProbeAndLockPages( mdl_p, mode, Operation ); /* lock memory */ + } /* try */ + + __except (EXCEPTION_EXECUTE_HANDLER) { + HCA_PRINT(TRACE_LEVEL_ERROR, HCA_DBG_MEMORY, + ("MOSAL_iobuf_register: Exception 0x%x on MmProbeAndLockPages(), va %I64d, sz %I64d\n", + GetExceptionCode(), va, size)); + rc = -EACCES; + goto err_probe; + } + + // fill IOBUF object + new_iobuf->va = va; + new_iobuf->size= size; + new_iobuf->nr_pages = ADDRESS_AND_SIZE_TO_SPAN_PAGES( va, size ); + new_iobuf->mdl_p = mdl_p; + new_iobuf->is_user = is_user; + *iobuf_seg = new_iobuf; + return 0; + +err_probe: + IoFreeMdl(mdl_p); +err_alloc_mdl: + ExFreePool((PVOID)new_iobuf); +err_nomem: + return rc; +} + +void iobuf_init( + IN u64 va, + IN u64 size, + IN int is_user, + IN OUT mt_iobuf_t *iobuf_p) +{ + iobuf_p->va = va; + iobuf_p->size= size; + iobuf_p->is_user = is_user; + InitializeListHead( &iobuf_p->seg_que ); + iobuf_p->seg_num = 0; + iobuf_p->nr_pages = 0; + iobuf_p->is_cashed = 0; +} + +int iobuf_register( + IN u64 va, + IN u64 size, + IN int is_user, + IN ib_access_t acc, + IN OUT mt_iobuf_t *iobuf_p) +{ + int rc=0; + u64 seg_va; // current segment start + u64 seg_size; // current segment size + u64 rdc; // remain data counter - what is rest to lock + u64 delta; // he size of the last not full page of the first segment + mt_iobuf_seg_t * new_iobuf; + unsigned page_size = PAGE_SIZE; + +// 32 - for any case +#define PFNS_IN_PAGE_SIZE_MDL ((PAGE_SIZE - sizeof(struct _MDL) - 32) / sizeof(long)) +#define MIN_IOBUF_SEGMENT_SIZE (PAGE_SIZE * PFNS_IN_PAGE_SIZE_MDL) // 4MB + + ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); + + // we'll try to register all at once. + seg_va = va; + seg_size = rdc = size; + + // allocate segments + while (rdc > 0) { + // map a segment + rc = register_segment(seg_va, seg_size, is_user, acc, &new_iobuf ); + + // success - move to another segment + if (!rc) { + rdc -= seg_size; + seg_va += seg_size; + InsertTailList( &iobuf_p->seg_que, &new_iobuf->link ); + iobuf_p->seg_num++; + // round the segment size to the next page boundary + delta = (seg_va + seg_size) & (page_size - 1); + if (delta) { + seg_size -= delta; + seg_size += page_size; + } + if (seg_size > rdc) + seg_size = rdc; + continue; + } + + // failure - too large a buffer: lessen it and try once more + if (rc == -ENOMEM) { + // no where to lessen - too low memory + if (seg_size <= MIN_IOBUF_SEGMENT_SIZE) + break; + // lessen the size + seg_size >>= 1; + // round the segment size to the next page boundary + delta = (seg_va + seg_size) & (page_size - 1); + if (delta) { + seg_size -= delta; + seg_size += page_size; + } + if (seg_size > rdc) + seg_size = rdc; + continue; + } + + // got unrecoverable error + break; + } + + // SUCCESS + if (rc) + iobuf_deregister( iobuf_p ); + else + iobuf_p->nr_pages += ADDRESS_AND_SIZE_TO_SPAN_PAGES( va, size ); + + return rc; +} + + +static void __iobuf_copy( + IN OUT mt_iobuf_t *dst_iobuf_p, + IN mt_iobuf_t *src_iobuf_p + ) +{ + int i; + mt_iobuf_seg_t *iobuf_seg_p; + + *dst_iobuf_p = *src_iobuf_p; + InitializeListHead( &dst_iobuf_p->seg_que ); + for (i=0; iseg_num; ++i) { + iobuf_seg_p = (mt_iobuf_seg_t *)(PVOID)RemoveHeadList( &src_iobuf_p->seg_que ); + InsertTailList( &dst_iobuf_p->seg_que, &iobuf_seg_p->link ); + } +} + +/* if the buffer to be registered overlaps a buffer, already registered, + a race can happen between HCA, writing to the previously registered + buffer and the probing functions (MmProbeAndLockPages, MmSecureVirtualMemory), + used in the algorithm of memory registration. + To prevent the race we maintain reference counters for the physical pages, being registered, + and register every physical page FOR THE WRITE ACCESS only once.*/ + +int iobuf_register_with_cash( + IN u64 vaddr, + IN u64 size, + IN int is_user, + IN OUT ib_access_t *acc_p, + IN OUT mt_iobuf_t *iobuf_p) +{ + int rc, pa_in; + mt_iobuf_t sec_iobuf; + int i, page_in , page_out, page_in_total; + int nr_pages; + char *subregion_start, *va; + u64 subregion_size; + u64 rdc; // remain data counter - what is rest to lock + u64 delta; // he size of the last not full page of the first segment + ib_access_t acc; + + down(&g_pa_mutex); + + // register memory for read access to bring pages into the memory + rc = iobuf_register( vaddr, size, is_user, 0, iobuf_p); + + // on error or read access - exit + if (rc || !(*acc_p & IB_AC_LOCAL_WRITE)) + goto exit; + + // re-register buffer with the correct access rights + iobuf_init( (u64)vaddr, size, is_user, &sec_iobuf ); + nr_pages = ADDRESS_AND_SIZE_TO_SPAN_PAGES( vaddr, size ); + subregion_start = va = (char*)(ULONG_PTR)vaddr; + rdc = size; + pa_in = page_in = page_in_total = page_out = 0; + + for (i=0; i rdc) + subregion_size = rdc; + + // register the subregion + rc = iobuf_register( (ULONG_PTR)subregion_start, subregion_size, is_user, acc, &sec_iobuf); + if (rc) + goto cleanup; + + // prepare to the next loop + rdc -= subregion_size; + subregion_start +=subregion_size; + } + } + + // prepare to registration of the subregion + if (pa_in) { // SUBREGION WITH READ ACCESS + acc = 0; + subregion_size = (u64)page_in * PAGE_SIZE; + } + else { // SUBREGION WITH WRITE ACCESS + acc = IB_AC_LOCAL_WRITE; + subregion_size = (u64)page_out * PAGE_SIZE; + } + + // round the subregion size to the page boundary + delta = (ULONG_PTR)(subregion_start + subregion_size) & (PAGE_SIZE - 1); + subregion_size -= delta; + if (subregion_size > rdc) + subregion_size = rdc; + + // register the subregion + rc = iobuf_register( (ULONG_PTR)subregion_start, subregion_size, is_user, acc, &sec_iobuf); + if (rc) + goto cleanup; + + // cash phys pages + rc = pa_register(iobuf_p); + if (rc) + goto err_pa_reg; + + // replace the iobuf + iobuf_deregister( iobuf_p ); + sec_iobuf.is_cashed = TRUE; + __iobuf_copy( iobuf_p, &sec_iobuf ); + + // buffer is a part of also registered buffer - change the rights + if (page_in_total) + *acc_p = MTHCA_ACCESS_REMOTE_READ; + + goto exit; + +err_pa_reg: + iobuf_deregister( &sec_iobuf ); +cleanup: + iobuf_deregister( iobuf_p ); +exit: + up(&g_pa_mutex); + return rc; +} + +static void deregister_segment(mt_iobuf_seg_t * iobuf_seg_p) +{ + MmUnlockPages( iobuf_seg_p->mdl_p ); // unlock the buffer + IoFreeMdl( iobuf_seg_p->mdl_p ); // free MDL + ExFreePool(iobuf_seg_p); +} + +void iobuf_deregister(mt_iobuf_t *iobuf_p) +{ + mt_iobuf_seg_t *iobuf_seg_p; // pointer to current segment object + + ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); + + // release segments + while (!IsListEmpty( &iobuf_p->seg_que )) { + iobuf_seg_p = (mt_iobuf_seg_t *)(PVOID)RemoveTailList( &iobuf_p->seg_que ); + deregister_segment(iobuf_seg_p); + iobuf_p->seg_num--; + } + ASSERT(iobuf_p->seg_num == 0); +} + +void iobuf_deregister_with_cash(mt_iobuf_t *iobuf_p) +{ + ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL); + + down(&g_pa_mutex); + if (iobuf_p->is_cashed) + pa_deregister(iobuf_p); + iobuf_deregister(iobuf_p); + up(&g_pa_mutex); +} + +void iobuf_iter_init( + IN mt_iobuf_t *iobuf_p, + IN OUT mt_iobuf_iter_t *iterator_p) +{ + iterator_p->seg_p = iobuf_p->seg_que.Flink; + iterator_p->pfn_ix = 0; +} + +// the function returns phys addresses of the pages, also for the first page +// if one wants to get the phys address of the buffer, one has to +// add the offset from the start of the page to the first phys address +// Returns: the number of entries, filled in page_tbl_p +// Returns 0 while at the end of list. +uint32_t iobuf_get_tpt_seg( + IN mt_iobuf_t *iobuf_p, + IN OUT mt_iobuf_iter_t *iterator_p, + IN uint32_t n_pages_in, + IN OUT uint64_t *page_tbl_p ) +{ + uint32_t i=0; // has to be initialized here for a premature exit + mt_iobuf_seg_t *seg_p; // pointer to current segment object + PPFN_NUMBER pfn_p; + uint32_t pfn_ix; // index of PFN in PFN array of the current segment + uint64_t *pa_buf_p = page_tbl_p; + + // prepare to the loop + seg_p = iterator_p->seg_p; // first segment of the first iobuf + pfn_ix= iterator_p->pfn_ix; + + // check, whether we at the end of the list + if ((PVOID)seg_p == (PVOID)&iobuf_p->seg_que) + goto exit; + pfn_p = MmGetMdlPfnArray( seg_p->mdl_p ) + pfn_ix; + + // pass along all the PFN arrays + for (; i < n_pages_in; i++, pa_buf_p++) { + // convert PFN to the physical address + *pa_buf_p = (uint64_t)*pfn_p++ << PAGE_SHIFT; + + // get to the next PFN + if (++pfn_ix >= seg_p->nr_pages) { + seg_p = (mt_iobuf_seg_t*)seg_p->link.Flink; + pfn_ix = 0; + if ((PVOID)seg_p == (PVOID)&iobuf_p->seg_que) { + i++; + break; + } + pfn_p = MmGetMdlPfnArray( seg_p->mdl_p ); + } + } + +exit: + iterator_p->seg_p = seg_p; + iterator_p->pfn_ix = pfn_ix; + return i; +} + + + + diff --git a/branches/WOF2-3/hw/mthca/kernel/mt_memory.h b/branches/WOF2-3/hw/mthca/kernel/mt_memory.h new file mode 100644 index 00000000..fdfcbea7 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/mt_memory.h @@ -0,0 +1,309 @@ +#ifndef MT_MEMORY_H +#define MT_MEMORY_H + +#include "iba/ib_types.h" +#include "complib\cl_debug.h" + +// =========================================== +// CONSTANTS +// =========================================== + +#define MT_TAG_ATOMIC 'MOTA' +#define MT_TAG_KERNEL 'LNRK' +#define MT_TAG_HIGH 'HGIH' +#define MT_TAG_PCIPOOL 'PICP' +#define MT_TAG_IOMAP 'PAMI' + +// =========================================== +// SUBSTITUTIONS +// =========================================== + +#define memcpy_toio memcpy +#define dma_get_cache_alignment (int)KeGetRecommendedSharedDataAlignment + +// =========================================== +// MACROS +// =========================================== + +#define PAGE_MASK (~(PAGE_SIZE-1)) +#define NEXT_PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK) + + +// =========================================== +// SYSTEM MEMORY +// =========================================== + +// memory +#define __GFP_NOWARN 0 /* Suppress page allocation failure warning */ +#define __GFP_HIGHMEM 0 + +#define GFP_ATOMIC 1 /* can't wait (i.e. DPC or higher) */ +#define GFP_KERNEL 2 /* can wait (npaged) */ +#define GFP_HIGHUSER 4 /* GFP_KERNEL, that can be in HIGH memory */ + + +#define SLAB_ATOMIC GFP_ATOMIC +#define SLAB_KERNEL GFP_KERNEL + +#if 1 +static inline void * kmalloc( SIZE_T bsize, unsigned int gfp_mask) +{ + void *ptr; + MT_ASSERT( KeGetCurrentIrql() <= DISPATCH_LEVEL ); + switch (gfp_mask) { + case GFP_ATOMIC: + ptr = ExAllocatePoolWithTag( NonPagedPool, bsize, MT_TAG_ATOMIC ); + break; + case GFP_KERNEL: + ptr = ExAllocatePoolWithTag( NonPagedPool, bsize, MT_TAG_KERNEL ); + break; + case GFP_HIGHUSER: + ptr = ExAllocatePoolWithTag( NonPagedPool, bsize, MT_TAG_HIGH ); + break; + default: + cl_dbg_out("kmalloc: unsupported flag %d\n", gfp_mask); + ptr = NULL; + break; + } + return ptr; +} +#else +#define kmalloc(bsize,flags) ExAllocatePoolWithTag( NonPagedPool, bsize, MT_TAG_KERNEL ) +#endif + +static inline void * kzalloc( SIZE_T bsize, unsigned int gfp_mask) +{ + void* va = kmalloc(bsize, gfp_mask); + if (va) + RtlZeroMemory(va, bsize); + return va; +} + +static inline void kfree (const void *pobj) +{ + MT_ASSERT( KeGetCurrentIrql() <= DISPATCH_LEVEL ); + if (pobj) + ExFreePool((void *)pobj); +} + +#define get_zeroed_page(mask) kzalloc(PAGE_SIZE, mask) +#define free_page(ptr) kfree(ptr) + + +// =========================================== +// IO SPACE <==> SYSTEM MEMORY +// =========================================== + + +/** +* ioremap - map bus memory into CPU space +* @offset: bus address of the memory +* @size: size of the resource to map +* +* ioremap performs a platform specific sequence of operations to +* make bus memory CPU accessible via the readb/readw/readl/writeb/ +* writew/writel functions and the other mmio helpers. The returned +* address is not guaranteed to be usable directly as a virtual +* address. +*/ +static inline void *ioremap(io_addr_t addr, SIZE_T size, SIZE_T* psize) +{ + PHYSICAL_ADDRESS pa; + void *va; + + MT_ASSERT( KeGetCurrentIrql() <= DISPATCH_LEVEL ); + pa.QuadPart = addr; + va = MmMapIoSpace( pa, size, MmNonCached ); + *psize = size; + return va; +} + +static inline void iounmap(void *va, SIZE_T size) +{ + MmUnmapIoSpace( va, size); +} + + // =========================================== + // DMA SUPPORT + // =========================================== + +#define PCI_DMA_BIDIRECTIONAL 0 +#define PCI_DMA_TODEVICE 1 +#define PCI_DMA_FROMDEVICE 2 +#define DMA_TO_DEVICE PCI_DMA_TODEVICE + + struct scatterlist { + dma_addr_t dma_address; /* logical (device) address */ + void * page; /* kernel virtual address */ + PMDL p_mdl; /* MDL, if any (used for user space buffers) */ + PSCATTER_GATHER_LIST p_os_sg; /* adapter scatter-gather list */ + unsigned int offset; /* offset in the first page */ + unsigned int length; /* buffer length */ + }; + + #define sg_dma_address(sg) ((sg)->dma_address) + #define sg_dma_len(sg) ((sg)->length) + + struct mthca_dev; + + int pci_map_sg(struct mthca_dev *dev, + struct scatterlist *sg, int nents, int direction); + + int pci_unmap_sg(struct mthca_dev *dev, + struct scatterlist *sg, int nents, int direction); + + void free_dma_mem( + IN struct mthca_dev *dev, + IN struct scatterlist *p_sg); + + void *alloc_dma_mem( + IN struct mthca_dev *dev, + IN unsigned long size, + OUT struct scatterlist *p_sg); + +static inline void *alloc_dma_zmem( + IN struct mthca_dev *dev, + IN unsigned long size, + OUT struct scatterlist *p_sg) +{ + void *va = alloc_dma_mem( dev, size, p_sg ); + if (va) + RtlZeroMemory(va, size); + return va; +} + +static inline void *alloc_dma_zmem_map( + IN struct mthca_dev *dev, + IN unsigned long size, + IN int direction, + OUT struct scatterlist *p_sg) +{ + void *va = alloc_dma_zmem( dev, size, p_sg ); + if (va) { + if (!pci_map_sg( dev, p_sg, 1, direction )) { + free_dma_mem( dev, p_sg ); + va = NULL; + } + } + return va; +} + +static inline void free_dma_mem_map( + IN struct mthca_dev *dev, + IN struct scatterlist *p_sg, + IN int direction ) +{ + pci_unmap_sg( dev, p_sg, 1, direction ); + free_dma_mem( dev, p_sg ); +} + + static inline dma_addr_t pci_mape_page(struct mthca_dev *dev, + void *va, unsigned long offset, SIZE_T size, int direction) + { + UNREFERENCED_PARAMETER(dev); + UNREFERENCED_PARAMETER(va); + UNREFERENCED_PARAMETER(offset); + UNREFERENCED_PARAMETER(size); + UNREFERENCED_PARAMETER(direction); + /* suppose, that pages where always translated to DMA space */ + return 0; /* i.e., we unmapped all the entries */ + } + + // =========================================== + // HELPERS + // =========================================== + + static inline int get_order(unsigned long size) +{ + int order; + + size = (size-1) >> (PAGE_SHIFT-1); + order = -1; + do { + size >>= 1; + order++; + } while (size); + return order; +} + +static inline int long_log2(unsigned long x) +{ + int r = 0; + for (x >>= 1; x > 0; x >>= 1) + r++; + return r; +} + +static inline unsigned long roundup_pow_of_two(unsigned long x) +{ + return (1UL << fls(x - 1)); +} + +// =========================================== +// PROTOTYPES +// =========================================== + +void put_page(struct scatterlist *sg); +int get_user_pages( + IN struct mthca_dev *dev, /* device */ + IN u64 start, /* address in user space */ + IN int npages, /* size in pages */ + IN int write_access, /* access rights */ + OUT struct scatterlist *sg /* s/g list */ + ); + +typedef struct _mt_iobuf { + u64 va; /* virtual address of the buffer */ + u64 size; /* size in bytes of the buffer */ + LIST_ENTRY seg_que; + u32 nr_pages; + int is_user; + int seg_num; + int is_cashed; +} mt_iobuf_t; + +/* iterator for getting segments of tpt */ +typedef struct _mt_iobuf_iter { + void * seg_p; /* the item from where to take the next translations */ + unsigned int pfn_ix; /* index from where to take the next translation */ +} mt_iobuf_iter_t; + +void iobuf_deregister_with_cash(IN mt_iobuf_t *iobuf_p); + +void iobuf_deregister(IN mt_iobuf_t *iobuf_p); + +void iobuf_init( + IN u64 va, + IN u64 size, + IN int is_user, + IN OUT mt_iobuf_t *iobuf_p); + +int iobuf_register_with_cash( + IN u64 vaddr, + IN u64 size, + IN int is_user, + IN OUT ib_access_t *acc_p, + IN OUT mt_iobuf_t *iobuf_p); + +int iobuf_register( + IN u64 va, + IN u64 size, + IN int is_user, + IN ib_access_t acc, + IN OUT mt_iobuf_t *iobuf_p); + +void iobuf_iter_init( + IN mt_iobuf_t *iobuf_p, + IN OUT mt_iobuf_iter_t *iterator_p); + +uint32_t iobuf_get_tpt_seg( + IN mt_iobuf_t *iobuf_p, + IN OUT mt_iobuf_iter_t *iterator_p, + IN uint32_t n_pages_in, + IN OUT uint64_t *page_tbl_p ); + +unsigned long copy_from_user(void *to, const void *from, unsigned long n); +unsigned long copy_to_user(void *to, const void *from, unsigned long n); + + +#endif diff --git a/branches/WOF2-3/hw/mthca/kernel/mt_pa_cash.c b/branches/WOF2-3/hw/mthca/kernel/mt_pa_cash.c new file mode 100644 index 00000000..7ff2baf6 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/mt_pa_cash.c @@ -0,0 +1,364 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies Ltd. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: mlnx_uvp_cq.c 1611 2006-08-20 14:48:55Z sleybo $ + */ + +#include "mt_pa_cash.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "mt_pa_cash.tmh" +#endif + +/////////////////////////////////////////////////////////////////////////// +// +// RESTRICTIONS +// +/////////////////////////////////////////////////////////////////////////// + +#ifdef _WIN64 +#define MAX_PAGES_SUPPORTED (64 * 1024 * 1024) // 256 GB +#else +#define MAX_PAGES_SUPPORTED (16 * 1024 * 1024) // 64 GB +#endif + +#define FREE_LIST_TRESHOLD 256 // max number of pages in free list + +/////////////////////////////////////////////////////////////////////////// +// +// CONSTANTS +// +/////////////////////////////////////////////////////////////////////////// + +#define PA_TABLE_ENTRY_SIZE sizeof(pa_table_entry_t) +#define PA_TABLE_ENTRY_NUM (PAGE_SIZE / PA_TABLE_ENTRY_SIZE) +#define PA_TABLE_SIZE (PA_TABLE_ENTRY_SIZE * PA_TABLE_ENTRY_NUM) + +#define PA_DIR_ENTRY_SIZE sizeof(pa_dir_entry_t) +#define PA_DIR_ENTRY_NUM (MAX_PAGES_SUPPORTED /PA_TABLE_ENTRY_NUM) +#define PA_DIR_SIZE (PA_DIR_ENTRY_SIZE * PA_DIR_ENTRY_NUM) + + +/////////////////////////////////////////////////////////////////////////// +// +// STRUCTURES +// +/////////////////////////////////////////////////////////////////////////// + +typedef struct { + int ref_cnt; +} pa_table_entry_t; + +typedef struct { + pa_table_entry_t *pa_te; /* pointer to one page of pa_table_entry_t elements */ + int used; /* number of pa_table_entry_t elements, used now. When 0 - the page may be freed */ +} pa_dir_entry_t; + +typedef struct pa_cash_s { + pa_dir_entry_t *pa_dir; + SINGLE_LIST_ENTRY free_list_hdr; + uint32_t free_nr_pages; + uint32_t free_list_threshold; + uint32_t max_nr_pages; + uint32_t cur_nr_pages; +} pa_cash_t; + + + +/////////////////////////////////////////////////////////////////////////// +// +// GLOBALS +// +/////////////////////////////////////////////////////////////////////////// + +KMUTEX g_pa_mutex; +u64 g_pa[1024]; +pa_cash_t g_cash; + + +/////////////////////////////////////////////////////////////////////////// +// +// STATIC FUNCTIONS +// +/////////////////////////////////////////////////////////////////////////// + +static uint32_t __calc_threshold() +{ + // threshold expresses the max length of free pages list, which gets released only at driver unload time + // so it can be calculated to be proportional to the system memory size + return FREE_LIST_TRESHOLD; +} + +static pa_table_entry_t *__alloc_page() +{ + pa_table_entry_t *pa_te; + + /* take from the list of reserved if it is not empty */ + if (g_cash.free_nr_pages) { + pa_te = (pa_table_entry_t *)PopEntryList( &g_cash.free_list_hdr ); + ((SINGLE_LIST_ENTRY*)pa_te)->Next = NULL; + g_cash.free_nr_pages--; + } + else /* allocate new page */ + pa_te = (pa_table_entry_t *)kzalloc( PA_TABLE_SIZE, GFP_KERNEL ); + + return pa_te; +} + +static void __free_page(pa_table_entry_t *pa_te) +{ + if (g_cash.free_nr_pages < g_cash.free_list_threshold) { + PushEntryList( &g_cash.free_list_hdr, (SINGLE_LIST_ENTRY*)pa_te ); + g_cash.free_nr_pages++; + } + else + kfree(pa_te); +} + +static pa_table_entry_t * __get_page(uint32_t ix) +{ + pa_table_entry_t *pa_te = g_cash.pa_dir[ix / PA_TABLE_ENTRY_NUM].pa_te; + + /* no this page_table - add a new one */ + if (!pa_te) { + pa_te = __alloc_page(); + if (!pa_te) + return NULL; + g_cash.pa_dir[ix / PA_TABLE_ENTRY_NUM].pa_te = pa_te; + g_cash.pa_dir[ix / PA_TABLE_ENTRY_NUM].used = 0; + g_cash.cur_nr_pages++; + } + + return pa_te; +} + +static void __put_page(uint32_t ix) +{ + __free_page(g_cash.pa_dir[ix / PA_TABLE_ENTRY_NUM].pa_te); + g_cash.pa_dir[ix / PA_TABLE_ENTRY_NUM].pa_te = NULL; + g_cash.cur_nr_pages--; +} + +static int __add_pa(uint64_t pa) +{ + uint32_t ix = (uint32_t)(pa >> PAGE_SHIFT); + pa_table_entry_t *pa_te; + + /* or pa is incorrect or memory that big is not supported */ + if (ix > g_cash.max_nr_pages) { + ASSERT(FALSE); + return -EFAULT; + } + + /* get page address */ + pa_te = __get_page(ix); + if (!pa_te) + return -ENOMEM; + + /* register page address */ + if (!pa_te[ix % PA_TABLE_ENTRY_NUM].ref_cnt) + ++g_cash.pa_dir[ix / PA_TABLE_ENTRY_NUM].used; + ++pa_te[ix % PA_TABLE_ENTRY_NUM].ref_cnt; + + return 0; +} + + +static int __rmv_pa(uint64_t pa) +{ + uint32_t ix = (uint32_t)(pa >> PAGE_SHIFT); + pa_table_entry_t *pa_te; + + /* or pa is incorrect or memory that big is not supported */ + if (ix > g_cash.max_nr_pages) { + ASSERT(FALSE); + return -EFAULT; + } + + pa_te = g_cash.pa_dir[ix / PA_TABLE_ENTRY_NUM].pa_te; + + /* no this page_table - error*/ + if (!pa_te) { + ASSERT(FALSE); + return -EFAULT; + } + + /* deregister page address */ + --pa_te[ix % PA_TABLE_ENTRY_NUM].ref_cnt; + ASSERT(pa_te[ix % PA_TABLE_ENTRY_NUM].ref_cnt >= 0); + + /* release the page on need */ + if (!pa_te[ix % PA_TABLE_ENTRY_NUM].ref_cnt) + --g_cash.pa_dir[ix / PA_TABLE_ENTRY_NUM].used; + if (!g_cash.pa_dir[ix / PA_TABLE_ENTRY_NUM].used) + __put_page(ix); + + return 0; +} + + + +/////////////////////////////////////////////////////////////////////////// +// +// PUBLIC FUNCTIONS +// +/////////////////////////////////////////////////////////////////////////// + + +int pa_register(mt_iobuf_t *iobuf_p) +{ + int i,j,n; + mt_iobuf_iter_t iobuf_iter; + + iobuf_iter_init( iobuf_p, &iobuf_iter ); + n = 0; + for (;;) { + i = iobuf_get_tpt_seg( iobuf_p, &iobuf_iter, + sizeof(g_pa) / sizeof (u64), g_pa ); + if (!i) + break; + for (j=0; j> PAGE_SHIFT); + pa_table_entry_t *pa_te; + + /* or pa is incorrect or memory that big is not supported */ + if (ix > g_cash.max_nr_pages) { + ASSERT(FALSE); + return -EFAULT; + } + + pa_te = g_cash.pa_dir[ix / PA_TABLE_ENTRY_NUM].pa_te; + + /* no this page_table */ + if (!pa_te) + return 0; + + return pa_te[ix % PA_TABLE_ENTRY_NUM].ref_cnt; +} + +int pa_cash_init() +{ + void *pa_dir; + pa_dir = kzalloc(PA_DIR_SIZE, GFP_KERNEL); + + if (!pa_dir) + return -ENOMEM; + g_cash.pa_dir = pa_dir; + g_cash.max_nr_pages = PA_TABLE_ENTRY_NUM * PA_DIR_ENTRY_NUM; + g_cash.free_list_hdr.Next = NULL; + g_cash.cur_nr_pages = 0; + g_cash.free_nr_pages = 0; + g_cash.free_list_threshold = __calc_threshold(); + KeInitializeMutex(&g_pa_mutex, 0); + return 0; +} + diff --git a/branches/WOF2-3/hw/mthca/kernel/mt_pa_cash.h b/branches/WOF2-3/hw/mthca/kernel/mt_pa_cash.h new file mode 100644 index 00000000..4ca6eb57 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/mt_pa_cash.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies Ltd. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: mlnx_uvp_cq.c 1611 2006-08-20 14:48:55Z sleybo $ + */ + +#include "mthca_dev.h" + +extern KMUTEX g_pa_mutex; + +int pa_cash_init(); + +void pa_cash_release(); + +int pa_is_registered(uint64_t pa); + +int pa_register(mt_iobuf_t *iobuf_p); + +void pa_deregister(mt_iobuf_t *iobuf_p); + +void pa_cash_print(); + diff --git a/branches/WOF2-3/hw/mthca/kernel/mt_packer.c b/branches/WOF2-3/hw/mthca/kernel/mt_packer.c new file mode 100644 index 00000000..a61cece8 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/mt_packer.c @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2004 Topspin Corporation. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "mt_packer.tmh" +#endif + +static u64 value_read(int offset, int size, u8 *structure) +{ + switch (size) { + case 1: return *(u8 *) (structure + offset); + case 2: return cl_ntoh16(*(__be16 *) (structure + offset)); + case 4: return cl_ntoh32(*(__be32 *) (structure + offset)); + case 8: return cl_ntoh64(*(__be64 *) (structure + offset)); + default: + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_LOW ,("Field size %d bits not handled\n", size * 8)); + return 0; + } +} + +/** + * ib_pack - Pack a structure into a buffer + * @desc:Array of structure field descriptions + * @desc_len:Number of entries in @desc + * @structure:Structure to pack from + * @buf:Buffer to pack into + * + * ib_pack() packs a list of structure fields into a buffer, + * controlled by the array of fields in @desc. + */ +void ib_pack(const struct ib_field *desc, + int desc_len, + u8 *structure, + u8 *buf) +{ + int i; + CPU_2_BE64_PREP; + + for (i = 0; i < desc_len; ++i) { + if (desc[i].size_bits <= 32) { + int shift; + u32 val; + __be32 mask; + __be32 *addr; + + shift = 32 - desc[i].offset_bits - desc[i].size_bits; + if (desc[i].struct_size_bytes) + val = (u32)value_read(desc[i].struct_offset_bytes, + desc[i].struct_size_bytes, + structure) << shift; + else + val = 0; + + mask = cl_hton32(((1Ui64 << desc[i].size_bits) - 1) << shift); + addr = (__be32 *) buf + desc[i].offset_words; + *addr = (*addr & ~mask) | (cl_hton32(val) & mask); + } else if (desc[i].size_bits <= 64) { + int shift; + u64 val; + __be64 mask; + __be64 *addr; + + shift = 64 - desc[i].offset_bits - desc[i].size_bits; + if (desc[i].struct_size_bytes) + val = value_read(desc[i].struct_offset_bytes, + desc[i].struct_size_bytes, + structure) << shift; + else + val = 0; + + mask = CPU_2_BE64((~0Ui64 >> (64 - desc[i].size_bits)) << shift); + addr = (__be64 *) ((__be32 *) buf + desc[i].offset_words); + *addr = (*addr & ~mask) | (cl_hton64(val) & mask); + } else { + if (desc[i].offset_bits % 8 || + desc[i].size_bits % 8) { + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_LOW ,("Structure field %s of size %d " + "bits is not byte-aligned\n", + desc[i].field_name, desc[i].size_bits)); + } + + if (desc[i].struct_size_bytes) + memcpy(buf + desc[i].offset_words * 4 + + desc[i].offset_bits / 8, + structure + desc[i].struct_offset_bytes, + desc[i].size_bits / 8); + else + RtlZeroMemory(buf + desc[i].offset_words * 4 + desc[i].offset_bits / 8, + desc[i].size_bits / 8); + } + } +} + +static void value_write(int offset, int size, u64 val, u8 *structure) +{ + switch (size * 8) { + case 8: *( u8 *) (structure + offset) = (u8)val; break; + case 16: *(__be16 *) (structure + offset) = cl_hton16((u16)val); break; + case 32: *(__be32 *) (structure + offset) = cl_hton32((u32)val); break; + case 64: *(__be64 *) (structure + offset) = cl_hton64(val); break; + default: + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_LOW ,("Field size %d bits not handled\n", size * 8)); + } +} + +/** + * ib_unpack - Unpack a buffer into a structure + * @desc:Array of structure field descriptions + * @desc_len:Number of entries in @desc + * @buf:Buffer to unpack from + * @structure:Structure to unpack into + * + * ib_pack() unpacks a list of structure fields from a buffer, + * controlled by the array of fields in @desc. + */ +void ib_unpack(const struct ib_field *desc, + int desc_len, + u8 *buf, + u8 *structure) +{ + int i; + + for (i = 0; i < desc_len; ++i) { + if (!desc[i].struct_size_bytes) + continue; + + if (desc[i].size_bits <= 32) { + int shift; + u32 val; + u32 mask; + __be32 *addr; + + shift = 32 - desc[i].offset_bits - desc[i].size_bits; + mask = ((1Ui64 << desc[i].size_bits) - 1) << shift; + addr = (__be32 *) buf + desc[i].offset_words; + val = (cl_ntoh32(*addr) & mask) >> shift; + value_write(desc[i].struct_offset_bytes, + desc[i].struct_size_bytes, + val, + structure); + } else if (desc[i].size_bits <= 64) { + int shift; + u64 val; + u64 mask; + __be64 *addr; + + shift = 64 - desc[i].offset_bits - desc[i].size_bits; + mask = (~0Ui64 >> (64 - desc[i].size_bits)) << shift; + addr = (__be64 *) buf + desc[i].offset_words; + val = (cl_ntoh64(*addr) & mask) >> shift; + value_write(desc[i].struct_offset_bytes, + desc[i].struct_size_bytes, + val, + structure); + } else { + if (desc[i].offset_bits % 8 || + desc[i].size_bits % 8) { + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_LOW ,("Structure field %s of size %d " + "bits is not byte-aligned\n", + desc[i].field_name, desc[i].size_bits)); + } + + memcpy(structure + desc[i].struct_offset_bytes, + buf + desc[i].offset_words * 4 + + desc[i].offset_bits / 8, + desc[i].size_bits / 8); + } + } +} diff --git a/branches/WOF2-3/hw/mthca/kernel/mt_pci.h b/branches/WOF2-3/hw/mthca/kernel/mt_pci.h new file mode 100644 index 00000000..3f389ca9 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/mt_pci.h @@ -0,0 +1,131 @@ +#ifndef MT_PCI_H +#define MT_PCI_H + +// =========================================== +// LITERALS +// =========================================== + +#ifndef PCI_VENDOR_ID_MELLANOX +#define PCI_VENDOR_ID_MELLANOX 0x15b3 +#endif + +#ifndef PCI_DEVICE_ID_MELLANOX_TAVOR +#define PCI_DEVICE_ID_MELLANOX_TAVOR 0x5a44 +#endif + +#ifndef PCI_DEVICE_ID_MELLANOX_ARBEL_COMPAT +#define PCI_DEVICE_ID_MELLANOX_ARBEL_COMPAT 0x6278 +#endif + +#ifndef PCI_DEVICE_ID_MELLANOX_ARBEL +#define PCI_DEVICE_ID_MELLANOX_ARBEL 0x6282 +#endif + +#ifndef PCI_DEVICE_ID_MELLANOX_SINAI_OLD +#define PCI_DEVICE_ID_MELLANOX_SINAI_OLD 0x5e8c +#endif + +#ifndef PCI_DEVICE_ID_MELLANOX_SINAI +#define PCI_DEVICE_ID_MELLANOX_SINAI 0x6274 +#endif + +#ifndef PCI_VENDOR_ID_TOPSPIN +#define PCI_VENDOR_ID_TOPSPIN 0x1867 +#endif + +/* live fishes */ +#ifndef PCI_DEVICE_ID_MELLANOX_TAVOR_BD +#define PCI_DEVICE_ID_MELLANOX_TAVOR_BD 0x5a45 +#endif + +#ifndef PCI_DEVICE_ID_MELLANOX_ARBEL_BD +#define PCI_DEVICE_ID_MELLANOX_ARBEL_BD 0x6279 +#endif + +#ifndef PCI_DEVICE_ID_MELLANOX_SINAI_OLD_BD +#define PCI_DEVICE_ID_MELLANOX_SINAI_OLD_BD 0x5e8d +#endif + +#ifndef PCI_DEVICE_ID_MELLANOX_SINAI_BD +#define PCI_DEVICE_ID_MELLANOX_SINAI_BD 0x6275 +#endif + +// =========================================== +// TYPES +// =========================================== + + +// =========================================== +// MACROS/FUNCTIONS +// =========================================== + +// get bar boundaries +#if 1 +#define pci_resource_start(dev,bar_num) ((dev)->ext->bar[bar_num].phys) +#define pci_resource_len(dev,bar_num) ((dev)->ext->bar[bar_num].size) +#else +static inline uint64_t pci_resource_start(struct mthca_dev *dev, int bar_num) +{ + return dev->ext->bar[bar_num].phys; +} +#endif + + +// i/o to registers + +static inline u64 readq(const volatile void __iomem *addr) +{ + //TODO: write atomic implementation of _IO_READ_QWORD and change mthca_doorbell.h + u64 val; + READ_REGISTER_BUFFER_ULONG((PULONG)(addr), (PULONG)&val, 2 ); + return val; +} + +static inline u32 readl(const volatile void __iomem *addr) +{ + return READ_REGISTER_ULONG((PULONG)(addr)); +} + +static inline u16 reads(const volatile void __iomem *addr) +{ + return READ_REGISTER_USHORT((PUSHORT)(addr)); +} + +static inline u8 readb(const volatile void __iomem *addr) +{ + return READ_REGISTER_UCHAR((PUCHAR)(addr)); +} + +#define __raw_readq readq +#define __raw_readl readl +#define __raw_reads reads +#define __raw_readb readb + +static inline void writeq(unsigned __int64 val, volatile void __iomem *addr) +{ + //TODO: write atomic implementation of _IO_WRITE_QWORD and change mthca_doorbell.h + WRITE_REGISTER_BUFFER_ULONG( (PULONG)(addr), (PULONG)&val, 2 ); +} + +static inline void writel(unsigned int val, volatile void __iomem *addr) +{ + WRITE_REGISTER_ULONG((PULONG)(addr),val); +} + +static inline void writes(unsigned short val, volatile void __iomem *addr) +{ + WRITE_REGISTER_USHORT((PUSHORT)(addr),val); +} + +static inline void writeb(unsigned char val, volatile void __iomem *addr) +{ + WRITE_REGISTER_UCHAR((PUCHAR)(addr),val); +} + +#define __raw_writeq writeq +#define __raw_writel writel +#define __raw_writes writes +#define __raw_writeb writeb + +#endif + diff --git a/branches/WOF2-3/hw/mthca/kernel/mt_pcipool.h b/branches/WOF2-3/hw/mthca/kernel/mt_pcipool.h new file mode 100644 index 00000000..996cb11d --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/mt_pcipool.h @@ -0,0 +1,103 @@ +#ifndef MT_PCIPOOL_H +#define MT_PCIPOOL_H + +typedef struct pci_pool { + size_t size; + struct mthca_dev *mdev; + char name [32]; + NPAGED_LOOKASIDE_LIST pool_hdr; +} pci_pool_t; + +// taken from dmapool.c + +/** +* pci_pool_create - Creates a pool of consistent memory blocks, for dma. +* @name: name of pool, for diagnostics +* @mdev: device that will be doing the DMA +* @size: size of the blocks in this pool. +* @align: alignment requirement for blocks; must be a power of two +* @allocation: returned blocks won't cross this boundary (or zero) +* Context: !in_interrupt() +* +* Returns a dma allocation pool with the requested characteristics, or +* null if one can't be created. Given one of these pools, dma_pool_alloc() +* may be used to allocate memory. Such memory will all have "consistent" +* DMA mappings, accessible by the device and its driver without using +* cache flushing primitives. The actual size of blocks allocated may be +* larger than requested because of alignment. +* +* If allocation is nonzero, objects returned from dma_pool_alloc() won't + * cross that size boundary. This is useful for devices which have + * addressing restrictions on individual DMA transfers, such as not crossing + * boundaries of 4KBytes. + */ + +pci_pool_t * +pci_pool_create (const char *name, struct mthca_dev *mdev, + size_t size, size_t align, size_t allocation); + +/** + * dma_pool_alloc - get a block of consistent memory + * @pool: dma pool that will produce the block + * @mem_flags: GFP_* bitmask + * @handle: pointer to dma address of block + * + * This returns the kernel virtual address of a currently unused block, + * and reports its dma address through the handle. + * If such a memory block can't be allocated, null is returned. + */ +static inline void * +pci_pool_alloc (pci_pool_t *pool, int mem_flags, dma_addr_t *handle) +{ + PHYSICAL_ADDRESS pa; + void * ptr; + UNREFERENCED_PARAMETER(mem_flags); + + MT_ASSERT( KeGetCurrentIrql() <= DISPATCH_LEVEL ); + + ptr = ExAllocateFromNPagedLookasideList( &pool->pool_hdr ); + if (ptr != NULL) { + pa = MmGetPhysicalAddress( ptr ); + *handle = pa.QuadPart; + } + return ptr; +} + + +/** +* dma_pool_free - put block back into dma pool +* @pool: the dma pool holding the block +* @vaddr: virtual address of block +* @dma: dma address of block +* +* Caller promises neither device nor driver will again touch this block +* unless it is first re-allocated. +*/ +static inline void +pci_pool_free (pci_pool_t *pool, void *vaddr, dma_addr_t dma) +{ + UNREFERENCED_PARAMETER(dma); + MT_ASSERT( KeGetCurrentIrql() <= DISPATCH_LEVEL ); + ExFreeToNPagedLookasideList( &pool->pool_hdr, vaddr ); +} + + + +/** + * pci_pool_destroy - destroys a pool of dma memory blocks. + * @pool: dma pool that will be destroyed + * Context: !in_interrupt() + * + * Caller guarantees that no more memory from the pool is in use, + * and that nothing will try to use the pool after this call. + */ +static inline void +pci_pool_destroy (pci_pool_t *pool) +{ + ExDeleteNPagedLookasideList( &pool->pool_hdr ); + ExFreePool( pool); +} + + + +#endif diff --git a/branches/WOF2-3/hw/mthca/kernel/mt_reset_tavor.c b/branches/WOF2-3/hw/mthca/kernel/mt_reset_tavor.c new file mode 100644 index 00000000..399c2f16 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/mt_reset_tavor.c @@ -0,0 +1,485 @@ +#include +#include +#include "hca_driver.h" +#include "mthca.h" +#include "hca_debug.h" +#include "Mt_l2w.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "mt_reset_tavor.tmh" +#endif + + +#pragma warning(disable : 4996) + +/* limitations */ +#define N_BUSES 16 /* max number of PCI buses */ +#define N_DEVICES 32 /* max number of devices on one bus */ +#define N_FUNCTIONS 8 /* max number of functions on one device */ +#define N_CARDS 8 /* max number of HCA cards */ + +/*----------------------------------------------------------------*/ + +PWCHAR +WcharFindChar( + IN PWCHAR pi_BufStart, + IN PWCHAR pi_BufEnd, + IN WCHAR pi_FromPattern, + IN WCHAR pi_ToPattern + ) +/*++ + +Routine Description: + Converts wide-character string into ASCII + +Arguments: + + pi_BufStart.......... start of the source string + pi_BufEnd............ end of the source string + pi_FromPattern....... start of pattern range to find + pi_ToPattern......... end of pattern range to find + +Return Value: + + pointer to the first pattern found or NULL (when reached the end) + +--*/ +{ /* WcharFindChar */ + + PWCHAR l_pResult = pi_BufStart; + + while (l_pResult < pi_BufEnd ) + { + if (*l_pResult >= pi_FromPattern && *l_pResult <= pi_ToPattern) + return l_pResult; + l_pResult++; + } + + return NULL; + +} /* WcharFindChar */ + + +/*----------------------------------------------------------------*/ + +/* + * Function: MdGetDevLocation + * + * Parameters: + * IN pi_pPdo - PDO of a device in question + * OUT po_pBus - pointer to the bus number of the device in question + * OUT po_pDevFunc - pointer to dev/func of the device, if found + * + * Returns: + * not STATUS_SUCCESS - the device location was not found + * STATUS_SUCCESS - the device location was found and returned in OUT parameters + * + * Description: + * The function uses IoGetDeviceProperty to get the location of a device with given PDO + * + */ +static NTSTATUS +MdGetDevLocation( + IN PDEVICE_OBJECT pi_pPdo, + OUT ULONG * po_pBus, + OUT ULONG * po_pDevFunc + ) +{ + ULONG l_BusNumber, l_DevNumber, l_Function, l_ResultLength = 0; + WCHAR l_Buffer[40], *l_pEnd, *l_pBuf = l_Buffer, *l_pBufEnd = l_Buffer + sizeof(l_Buffer); + NTSTATUS l_Status; + UNICODE_STRING l_UnicodeNumber; + + /* prepare */ + l_ResultLength = 0; + RtlZeroMemory( l_Buffer, sizeof(l_Buffer) ); + + /* Get the device number */ + l_Status = IoGetDeviceProperty(pi_pPdo, + DevicePropertyLocationInformation, sizeof(l_Buffer), l_Buffer, &l_ResultLength); + + /* Verify if the function was successful */ + if ( !NT_SUCCESS(l_Status) || !l_ResultLength ) { + HCA_PRINT( TRACE_LEVEL_ERROR ,HCA_DBG_SHIM ,("(MdGetDevLocation) Unable to get device number: Status 0x%x, ResultSize %d \n", + l_Status, l_ResultLength )); + goto exit; + } + + // ALL THE BELOW CRAP WE DO INSTEAD OF + // sscanf(l_Buffer, "PCI bus %d, device %d, function %d", &l_BusNumber, &l_DevNumber, &l_Function ); + + /* take bus number */ + l_pBuf = WcharFindChar( l_pBuf, l_pBufEnd, L'0', L'9' ); + if (l_pBuf == NULL) goto err; + l_pEnd = WcharFindChar( l_pBuf, l_pBufEnd, L',', L',' ); + if (l_pEnd == NULL) goto err; + l_UnicodeNumber.Length = l_UnicodeNumber.MaximumLength = (USHORT)((PCHAR)l_pEnd - (PCHAR)l_pBuf); + l_UnicodeNumber.Buffer = l_pBuf; l_pBuf = l_pEnd; + RtlUnicodeStringToInteger( &l_UnicodeNumber, 10, &l_BusNumber); + + /* take slot number */ + l_pBuf = WcharFindChar( l_pBuf, l_pBufEnd, L'0', L'9' ); + if (l_pBuf == NULL) goto err; + l_pEnd = WcharFindChar( l_pBuf, l_pBufEnd, L',', L',' ); + if (l_pEnd == NULL) goto err; + l_UnicodeNumber.Length = l_UnicodeNumber.MaximumLength = (USHORT)((PCHAR)l_pEnd - (PCHAR)l_pBuf); + l_UnicodeNumber.Buffer = l_pBuf; l_pBuf = l_pEnd; + RtlUnicodeStringToInteger( &l_UnicodeNumber, 10, &l_DevNumber); + + /* take function number */ + *(l_Buffer + (l_ResultLength>>1)) = 0; /* set end of string */ + l_pBuf = WcharFindChar( l_pBuf, l_pBufEnd, L'0', L'9' ); + if (l_pBuf == NULL) goto err; + l_pEnd = WcharFindChar( l_pBuf, l_pBufEnd, 0, 0 ); + if (l_pEnd == NULL) goto err; + l_UnicodeNumber.Length = l_UnicodeNumber.MaximumLength = (USHORT)((PCHAR)l_pEnd - (PCHAR)l_pBuf); + l_UnicodeNumber.Buffer = l_pBuf; l_pBuf = l_pEnd; + RtlUnicodeStringToInteger( &l_UnicodeNumber, 10, &l_Function); + + /* return the results */ + *po_pBus = l_BusNumber; + *po_pDevFunc = (l_DevNumber & 0x01f) | ((l_Function & 7) << 5); + + goto exit; + +err: + l_Status = STATUS_UNSUCCESSFUL; +exit: + return l_Status; +} + +/*----------------------------------------------------------------*/ + +/* Function: SendAwaitIrpCompletion + * + * Parameters: + * + * Description: + * IRP completion routine + * + * Returns: + * pointer to the entry on SUCCESS + * NULL - otherwise + * +*/ +static +NTSTATUS +SendAwaitIrpCompletion ( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Context + ) +{ + UNREFERENCED_PARAMETER (DeviceObject); + UNREFERENCED_PARAMETER (Irp); + KeSetEvent ((PKEVENT) Context, IO_NO_INCREMENT, FALSE); + return STATUS_MORE_PROCESSING_REQUIRED; // Keep this IRP +} + +/*------------------------------------------------------------------------------------------------------*/ + +/* + * Function: SendAwaitIrp + * + * Description: + * Create and send IRP stack down the stack and wait for the response (Blocking Mode) + * + * Parameters: + * pi_pDeviceExt.......... ointer to USB device extension + * pi_MajorCode........... IRP major code + * pi_MinorCode........... IRP minor code + * pi_pBuffer............. parameter buffer + * pi_nSize............... size of the buffer + * po_pInfo.............. returned field Information from IoStatus block + * + * Returns: + * pointer to the entry on SUCCESS + * NULL - otherwise + * +*/ +static +NTSTATUS +SendAwaitIrp( + IN PDEVICE_OBJECT pi_pFdo, + IN PDEVICE_OBJECT pi_pLdo, + IN ULONG pi_MajorCode, + IN ULONG pi_MinorCode, + IN PVOID pi_pBuffer, + IN int pi_nSize, + OUT PVOID * po_pInfo + ) +/*++ + + Routine Description: + + Create and send IRP stack down the stack and wait for the response ( +Blocking Mode) + + Arguments: + + pi_pFdo................ our device + pi_pLdo................ lower device + pi_MajorCode........... IRP major code + pi_MinorCode........... IRP minor code + pi_pBuffer............. parameter buffer + pi_nSize............... size of the buffer + + Returns: + + standard NTSTATUS return codes. + + Notes: + +--*/ +{ /* SendAwaitIrp */ + // Event + KEVENT l_hEvent; + // Pointer to IRP + PIRP l_pIrp; + // Stack location + PIO_STACK_LOCATION l_pStackLocation; + // Returned status + NTSTATUS l_Status; + // when to invoke + BOOLEAN InvokeAlways = TRUE; + + // call validation + if(KeGetCurrentIrql() != PASSIVE_LEVEL) + return STATUS_SUCCESS; + + // create event + KeInitializeEvent(&l_hEvent, NotificationEvent, FALSE); + + // build IRP request to USBD driver + l_pIrp = IoAllocateIrp( pi_pFdo->StackSize, FALSE ); + + // validate request + if (!l_pIrp) + { + //MdKdPrint( DBGLVL_MAXIMUM, ("(SendAwaitIrp) Unable to allocate IRP !\n")); + return STATUS_INSUFFICIENT_RESOURCES; + } + + // fill IRP + l_pIrp->IoStatus.Status = STATUS_NOT_SUPPORTED; + + // set completion routine + IoSetCompletionRoutine(l_pIrp,SendAwaitIrpCompletion, &l_hEvent, InvokeAlways, InvokeAlways, InvokeAlways); + + // fill stack location + l_pStackLocation = IoGetNextIrpStackLocation(l_pIrp); + l_pStackLocation->MajorFunction= (UCHAR)pi_MajorCode; + l_pStackLocation->MinorFunction= (UCHAR)pi_MinorCode; + RtlCopyMemory( &l_pStackLocation->Parameters, pi_pBuffer, pi_nSize ); + + // Call lower driver perform request + l_Status = IoCallDriver( pi_pLdo, l_pIrp ); + + // if the request not performed --> wait + if (l_Status == STATUS_PENDING) + { + // Wait until the IRP will be complete + KeWaitForSingleObject( + &l_hEvent, // event to wait for + Executive, // thread type (to wait into its context) + KernelMode, // mode of work + FALSE, // alertable + NULL // timeout + ); + l_Status = l_pIrp->IoStatus.Status; + } + + if (po_pInfo) + *po_pInfo = (PVOID)l_pIrp->IoStatus.Information; + + IoFreeIrp(l_pIrp); + return l_Status; + +} /* SendAwaitIrp */ + + +/*------------------------------------------------------------------------------------------------------*/ + +/* + * Function: FindBridgeIf_new + * + * Parameters: + * IN pi_pPdo - PDO of HCA's bus device + * IN pi_Bus, pi_DevFunc - bridge location + * OUT po_pPdo - pointer to PDO of the bridge, when found + * + * Returns: + * FALSE - the bridge was not found + * TRUE - a device was found; *po_pPdo contains its PDO + * + * Description: + * The function finds and opens the bus interface for Tavor HCA + * + * Algorithm: + * 1. find all PDOs of PCI.SYS driver and save it into an array; + * 2. For each PDO open its bus i/f and check whether it is our bridge; + * + * Note: + * 1. It is a "hack" algorithm. It uses some fields of system structures and some + * optimistic assumptions - see more below + * 2. We dangerously assume, that during part to of the algoritm no PDO will removed or added ! + * 3. PCI.SYS gives to its child devices names like \Device\NTPNP_PCI00nn. I tried to get Bridge's + * PDO by calling IoGetDeviceObjectPointer with all such names, but it returns STATUS_NO_SUCH_DEVICE + * for the *right* name of Bridge device !(IoGetDeviceObjectPointer really opens the device. Maybe Bridge is in exclusive use) + */ +int +FindBridgeIf( + IN hca_dev_ext_t *pi_ext, + OUT PBUS_INTERFACE_STANDARD pi_pInterface + ) +{ + NTSTATUS l_Status; + int rc = FALSE; /* result - "not found" by default */ + int n_pdos = 0; /* number of PCI.SYS's PDOs */ + PDEVICE_OBJECT *pdo; /* an array of PCI.SYS's PDOs */ + PDEVICE_OBJECT l_pHcaPdo; + + { // get HCA's bus PDO + IO_STACK_LOCATION l_Iosl; + PDEVICE_RELATIONS l_pDr; + + // find PDO of our bus driver (bypassing possible low filter drivers) + RtlZeroMemory( &l_Iosl, sizeof(l_Iosl) ); + l_Iosl.Parameters.QueryDeviceRelations.Type = TargetDeviceRelation; + l_Status = SendAwaitIrp( + pi_ext->cl_ext.p_self_do, + pi_ext->cl_ext.p_next_do, + IRP_MJ_PNP, + IRP_MN_QUERY_DEVICE_RELATIONS, + &l_Iosl.Parameters, + sizeof(l_Iosl.Parameters.QueryDeviceRelations), + &l_pDr + ); + + if (!NT_SUCCESS (l_Status)) { + HCA_PRINT( TRACE_LEVEL_ERROR ,HCA_DBG_SHIM ,("IRP_MN_QUERY_DEVICE_RELATIONS for TargetDeviceRelation failed (%#x);: Fdo %p, Ldo %p \n", + l_Status, pi_ext->cl_ext.p_self_do, pi_ext->cl_ext.p_next_do )); + goto exit; + } + + HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_SHIM ,("IRP_MN_QUERY_DEVICE_RELATIONS for TargetDeviceRelation for Fdo %p, Ldo %p: num_of_PDOs %d, PDO %p \n", + pi_ext->cl_ext.p_self_do, pi_ext->cl_ext.p_next_do, l_pDr->Count, l_pDr->Objects[0] )); + l_pHcaPdo = l_pDr->Objects[0]; + } + + { // allocate and fill an array with all PCI.SYS PDO devices + // suppose that there is no more than N_PCI_DEVICES, belonging to PCI.SYS + #define N_PCI_DEVICES 256 + KIRQL irql; + PDRIVER_OBJECT l_pDrv; + PDEVICE_OBJECT l_pPdo; + int l_all_pdos = 0; + + pdo = (PDEVICE_OBJECT *)ExAllocatePoolWithTag( + NonPagedPool, + N_PCI_DEVICES * sizeof(PDEVICE_OBJECT), + MT_TAG_KERNEL ); + if (!pdo) + goto exit; + + // suppose, that PDOs are added only at PASSIVE_LEVEL + irql = KeRaiseIrqlToDpcLevel(); + + // get to the PCI.SYS driver + l_pDrv = l_pHcaPdo->DriverObject; + + // find and store all bus PDO s (because the bridge is a bus enumerated device) + for ( l_pPdo = l_pDrv->DeviceObject; l_pPdo; l_pPdo = l_pPdo->NextDevice ) { + l_all_pdos++; + if ( l_pPdo->Flags & DO_BUS_ENUMERATED_DEVICE ) { + pdo[n_pdos] = l_pPdo; + if (++n_pdos >= N_PCI_DEVICES) { + HCA_PRINT( TRACE_LEVEL_ERROR ,HCA_DBG_SHIM , + ("There are more than %d children of PCI.SYS. Skipping the rest \n", N_PCI_DEVICES )); + break; + } + } + } + + // return to previous level + KeLowerIrql(irql); + HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_SHIM ,("Found %d PCI.SYS's PDOs (from %d) \n", n_pdos, l_all_pdos )); + } + + { // Find PDO of the Bridge of our HCA and return open bus interface to it + int i; + ULONG data, l_SecBus; + IO_STACK_LOCATION l_Stack; // parameter buffer for the request + ULONG l_DevId = ((int)(23110) << 16) | PCI_VENDOR_ID_MELLANOX; + + // loop over all the PCI driver devices + for ( i = 0; i < n_pdos; ++i ) { + + // clean interface data + RtlZeroMemory( (PCHAR)pi_pInterface, sizeof(BUS_INTERFACE_STANDARD) ); + + // get Bus Interface for the current PDO + l_Stack.Parameters.QueryInterface.InterfaceType = (LPGUID) &GUID_BUS_INTERFACE_STANDARD; + l_Stack.Parameters.QueryInterface.Size = sizeof(BUS_INTERFACE_STANDARD); + l_Stack.Parameters.QueryInterface.Version = 1; + l_Stack.Parameters.QueryInterface.Interface = (PINTERFACE)pi_pInterface; + l_Stack.Parameters.QueryInterface.InterfaceSpecificData = NULL; + + l_Status =SendAwaitIrp( pi_ext->cl_ext.p_self_do, pdo[i], IRP_MJ_PNP, + IRP_MN_QUERY_INTERFACE, &l_Stack.Parameters, sizeof(l_Stack.Parameters), NULL); + if (!NT_SUCCESS (l_Status)) { + HCA_PRINT( TRACE_LEVEL_WARNING ,HCA_DBG_SHIM , + ("Failed to get bus interface for pdo[%d] %p, error %#x \n", i, pdo[i], l_Status )); + continue; + } + + // Read DevID + data = 0; + if (4 != pi_pInterface->GetBusData( pi_pInterface->Context, + PCI_WHICHSPACE_CONFIG, &data, 0, 4)) { + HCA_PRINT( TRACE_LEVEL_WARNING, HCA_DBG_PNP, + ("Failed to read DevID for pdo[%d] %p, data %#x \n", i, pdo[i], data )); + goto next_loop; + } + + if (data != l_DevId) { + HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PNP, + ("Not Tavor bridge: pdo[%d] %p, data %#x \n", i, pdo[i], data )); + goto next_loop; + } + + // Found Tavor Bridge - read its SecondaryBus + data = 0; + if (4 != pi_pInterface->GetBusData( pi_pInterface->Context, + PCI_WHICHSPACE_CONFIG, &data, 24, 4)) { /* 24 - PrimaryBus, 25 - SecondaryBus, 26 - SubordinateBus */ + HCA_PRINT( TRACE_LEVEL_WARNING, HCA_DBG_PNP, + ("Failed to read SecondaryBus for pdo[%d] %p, data %#x \n", i, pdo[i], data )); + goto next_loop; + } + + l_SecBus = (data >> 16) & 255; + if (l_SecBus != pi_ext->bus_number) { + HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PNP, + ("Wrong bridge for our HCA: pdo[%d] %p, SecBus %d, HcaBus %d \n", i, pdo[i], l_SecBus, pi_ext->bus_number )); + goto next_loop; + } + else { + ULONG l_DevFunc, l_Bus; + l_Status = MdGetDevLocation( pdo[i], &l_Bus, &l_DevFunc ); + HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PNP, + ("Found bridge for our HCA: pdo[%d] %p (bus %d, dev/func %d, HcaPdo %p), SecBus %d, HcaBus %d \n", + i, pdo[i], l_Bus, l_DevFunc, l_pHcaPdo, l_SecBus, pi_ext->bus_number )); + rc = TRUE; + break; + } + next_loop: + pi_pInterface->InterfaceDereference( pi_pInterface->Context ); + } + } + + ExFreePool(pdo); +exit: + return rc; +} diff --git a/branches/WOF2-3/hw/mthca/kernel/mt_spinlock.h b/branches/WOF2-3/hw/mthca/kernel/mt_spinlock.h new file mode 100644 index 00000000..57f3ea5a --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/mt_spinlock.h @@ -0,0 +1,143 @@ +#ifndef MT_SPINLOCK_H +#define MT_SPINLOCK_H + +typedef struct spinlock { + KSPIN_LOCK lock; + +#ifdef SUPPORT_SPINLOCK_ISR + PKINTERRUPT p_int_obj; + KIRQL irql; +#endif +} spinlock_t; + +typedef struct { + KLOCK_QUEUE_HANDLE lockh; + KIRQL irql; +} spinlockh_t; + +#ifdef SUPPORT_SPINLOCK_ISR + +static inline void +spin_lock_setint( + IN spinlock_t* const l, + IN PKINTERRUPT p_int_obj ) +{ + MT_ASSERT( l ); + l->p_int_obj = p_int_obj; +} + +static inline void spin_lock_irq_init( + IN spinlock_t* const l, + IN PKINTERRUPT int_obj + ) +{ + KeInitializeSpinLock( &l->lock ); + l->p_int_obj = int_obj; +} + +static inline unsigned long +spin_lock_irq( + IN spinlock_t* const l) +{ + MT_ASSERT( l ); + MT_ASSERT( l->p_int_obj ); + return (unsigned long)(l->irql = KeAcquireInterruptSpinLock ( l->p_int_obj )); +} + +static inline void +spin_unlock_irq( + IN spinlock_t* const p_spinlock ) +{ + MT_ASSERT( p_spinlock ); + MT_ASSERT( p_spinlock->p_int_obj ); + KeReleaseInterruptSpinLock ( p_spinlock->p_int_obj, p_spinlock->irql ); +} + +#endif + +#define SPIN_LOCK_PREP(lh) spinlockh_t lh + +static inline void spin_lock_init( + IN spinlock_t* const p_spinlock ) +{ + KeInitializeSpinLock( &p_spinlock->lock ); +} + +static inline void +spin_lock( + IN spinlock_t* const l, + IN spinlockh_t * const lh) +{ + KIRQL irql = KeGetCurrentIrql(); + + MT_ASSERT( l || lh ); + ASSERT(irql <= DISPATCH_LEVEL); + + if (irql == DISPATCH_LEVEL) + KeAcquireInStackQueuedSpinLockAtDpcLevel( &l->lock, &lh->lockh ); + else + KeAcquireInStackQueuedSpinLock( &l->lock, &lh->lockh ); + lh->irql = irql; +} + +static inline void +spin_unlock( + IN spinlockh_t * const lh) +{ + MT_ASSERT( lh ); + ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); + if (lh->irql == DISPATCH_LEVEL) + KeReleaseInStackQueuedSpinLockFromDpcLevel( &lh->lockh ); + else + KeReleaseInStackQueuedSpinLock( &lh->lockh ); +} + +static inline void +spin_lock_sync( + IN spinlock_t* const l ) +{ + KLOCK_QUEUE_HANDLE lockh; + MT_ASSERT( l ); + ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); + KeAcquireInStackQueuedSpinLock ( &l->lock, &lockh ); + KeReleaseInStackQueuedSpinLock( &lockh ); +} + +/* to be used only at DPC level */ +static inline void +spin_lock_dpc( + IN spinlock_t* const l, + IN spinlockh_t * const lh) +{ + MT_ASSERT( l || lh ); + ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); + KeAcquireInStackQueuedSpinLockAtDpcLevel( &l->lock, &lh->lockh ); +} + +/* to be used only at DPC level */ +static inline void +spin_unlock_dpc( + IN spinlockh_t * const lh) +{ + ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); + KeReleaseInStackQueuedSpinLockFromDpcLevel( &lh->lockh ); +} + + +/* we are working from DPC level, so we can use usual spinlocks */ +#define spin_lock_irq spin_lock +#define spin_unlock_irq spin_unlock + +/* no diff in Windows */ +#define spin_lock_irqsave spin_lock_irq +#define spin_unlock_irqrestore spin_unlock_irq + +/* Windows doesn't support such kind of spinlocks so far, but may be tomorrow ... */ +#define rwlock_init spin_lock_init +#define read_lock_irqsave spin_lock_irqsave +#define read_unlock_irqrestore spin_unlock_irqrestore +#define write_lock_irq spin_lock_irq +#define write_unlock_irq spin_unlock_irq + +#endif + diff --git a/branches/WOF2-3/hw/mthca/kernel/mt_sync.h b/branches/WOF2-3/hw/mthca/kernel/mt_sync.h new file mode 100644 index 00000000..90d3f38c --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/mt_sync.h @@ -0,0 +1,109 @@ +#ifndef MT_SYNC_H +#define MT_SYNC_H + +// literals +#ifndef LONG_MAX +#define LONG_MAX 2147483647L /* maximum (signed) long value */ +#endif + + +// mutex wrapper + +// suitable both for mutexes and semaphores +static inline void down(PRKMUTEX p_mutex) +{ + NTSTATUS status; + int need_to_wait = 1; + + ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL); + while (need_to_wait) { + status = KeWaitForSingleObject( p_mutex, Executive, KernelMode, FALSE, NULL ); + if (status == STATUS_SUCCESS) + break; + } +} + +// suitable both for mutexes and semaphores +static inline int down_interruptible(PRKMUTEX p_mutex) +{ + NTSTATUS status; + + ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL); + status = KeWaitForSingleObject( p_mutex, Executive, KernelMode, TRUE, NULL ); + if (status == STATUS_SUCCESS) + return 0; + return -EINTR; +} + +#define sem_down(ptr) down((PRKMUTEX)(ptr)) +#define sem_down_interruptible(ptr) down_interruptible((PRKMUTEX)(ptr)) + +static inline void up(PRKMUTEX p_mutex) +{ + ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); + KeReleaseMutex( p_mutex, FALSE ); +} + +static inline void sem_up(PRKSEMAPHORE p_sem) +{ + ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); + KeReleaseSemaphore( p_sem, 0, 1, FALSE ); +} + +static inline void sem_init( + IN PRKSEMAPHORE p_sem, + IN LONG cnt, + IN LONG limit) +{ + ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); + KeInitializeSemaphore( p_sem, cnt, limit ); +} + + +typedef struct wait_queue_head { + KEVENT event; +} wait_queue_head_t; + +static inline void wait_event(wait_queue_head_t *obj_p, int condition) +{ + NTSTATUS status; + int need_to_wait = 1; + MT_ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL); + if (condition) + return; + while (need_to_wait) { + status = KeWaitForSingleObject( &obj_p->event, Executive, KernelMode, FALSE, NULL ); + if (status == STATUS_SUCCESS) + break; + } +} + +static inline void wake_up(wait_queue_head_t *obj_p) +{ + MT_ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); + KeSetEvent( &obj_p->event, 0, FALSE ); +} + +static inline void init_waitqueue_head(wait_queue_head_t *obj_p) +{ + //TODO: ASSERT is temporary outcommented, because using of fast mutexes in CompLib + // cause working on APC_LEVEL + //ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); + KeInitializeEvent( &obj_p->event, NotificationEvent , FALSE ); +} + +static inline void free_irq(PKINTERRUPT int_obj) +{ + IoDisconnectInterrupt( int_obj ); +} + +int request_irq( + IN CM_PARTIAL_RESOURCE_DESCRIPTOR *int_info, /* interrupt resources */ + IN KSPIN_LOCK *isr_lock, /* spin lcok for ISR */ + IN PKSERVICE_ROUTINE isr, /* ISR */ + IN void *isr_ctx, /* ISR context */ + OUT PKINTERRUPT *int_obj /* interrupt object */ + ); + + +#endif diff --git a/branches/WOF2-3/hw/mthca/kernel/mt_types.h b/branches/WOF2-3/hw/mthca/kernel/mt_types.h new file mode 100644 index 00000000..ec8f70e7 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/mt_types.h @@ -0,0 +1,60 @@ +#ifndef MT_TYPES_H +#define MT_TYPES_H + +//#include +#pragma warning( push ) +#include + #include +#pragma warning( pop ) + +// =========================================== +// SUBSTITUTES +// =========================================== + +// gcc compiler attributes +#define __iomem +#define likely(x) (x) +#define unlikely(x) (x) + +// container_of +#define container_of CONTAINING_RECORD + +// inline +#define inline __inline + +// =========================================== +// TYPES +// =========================================== + +// basic types +typedef unsigned char u8, __u8; +typedef unsigned short int u16, __u16; +typedef unsigned int u32, __u32; +typedef unsigned __int64 u64, __u64; +typedef char s8, __s8; +typedef short int s16, __s16; +typedef int s32, __s32; +typedef __int64 s64, __s64; + +// inherited +typedef u16 __le16; +typedef u16 __be16; +typedef u32 __le32; +typedef u32 __be32; +typedef u64 __le64; +typedef u64 __be64; +typedef u64 dma_addr_t; +typedef u64 io_addr_t; + +// =========================================== +// MACROS +// =========================================== + +// assert +#ifdef _DEBUG_ +#define MT_ASSERT( exp ) (void)(!(exp)?cl_dbg_out("Assertion Failed:" #exp "\n"),DbgBreakPoint(),FALSE:TRUE) +#else +#define MT_ASSERT( exp ) +#endif /* _DEBUG_ */ + +#endif diff --git a/branches/WOF2-3/hw/mthca/kernel/mt_ud_header.c b/branches/WOF2-3/hw/mthca/kernel/mt_ud_header.c new file mode 100644 index 00000000..e649c53a --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/mt_ud_header.c @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2004 Topspin Corporation. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "mt_ud_header.tmh" +#endif +#include + +#define STRUCT_FIELD_INIT(header, field,ow,ob,sb) \ + offsetof(struct ib_unpacked_ ## header, field), \ + sizeof ((struct ib_unpacked_ ## header *) 0)->field, \ + ow,ob,sb, \ + #header ":" #field + +#define STRUCT_FIELD_INITR(ow,ob,sb) \ + 0, 0, ow, ob, sb, "reserved" + +static const struct ib_field lrh_table[] = { + { STRUCT_FIELD_INIT(lrh, virtual_lane, 0, 0, 4) }, + { STRUCT_FIELD_INIT(lrh, link_version, 0, 4, 4) }, + { STRUCT_FIELD_INIT(lrh, service_level, 0, 8, 4) }, + { STRUCT_FIELD_INITR(0,12,2) }, + { STRUCT_FIELD_INIT(lrh, link_next_header, 0, 14, 2) }, + { STRUCT_FIELD_INIT(lrh, destination_lid, 0, 16, 16) }, + { STRUCT_FIELD_INITR(1,0,5) }, + { STRUCT_FIELD_INIT(lrh, packet_length, 1, 5, 11) }, + { STRUCT_FIELD_INIT(lrh, source_lid, 1, 16, 16) } +}; + +static const struct ib_field grh_table[] = { + { STRUCT_FIELD_INIT(grh, ip_version, 0, 0, 4) }, + { STRUCT_FIELD_INIT(grh, traffic_class, 0, 4, 8) }, + { STRUCT_FIELD_INIT(grh, flow_label, 0, 12, 20) }, + { STRUCT_FIELD_INIT(grh, payload_length, 1, 0, 16) }, + { STRUCT_FIELD_INIT(grh, next_header, 1, 16, 8) }, + { STRUCT_FIELD_INIT(grh, hop_limit, 1, 24, 8) }, + { STRUCT_FIELD_INIT(grh, source_gid, 2, 0, 128) }, + { STRUCT_FIELD_INIT(grh, destination_gid, 6, 0, 128) } +}; + +static const struct ib_field bth_table[] = { + { STRUCT_FIELD_INIT(bth, opcode, 0, 0, 8) }, + { STRUCT_FIELD_INIT(bth, solicited_event, 0, 8, 1) }, + { STRUCT_FIELD_INIT(bth, mig_req, 0, 9, 1) }, + { STRUCT_FIELD_INIT(bth, pad_count, 0, 10, 2) }, + { STRUCT_FIELD_INIT(bth, transport_header_version, 0, 12, 4) }, + { STRUCT_FIELD_INIT(bth, pkey, 0, 16, 16) }, + { STRUCT_FIELD_INITR(1,0,8) }, + { STRUCT_FIELD_INIT(bth, destination_qpn, 1, 8, 24) }, + { STRUCT_FIELD_INIT(bth, ack_req, 2, 0, 1) }, + { STRUCT_FIELD_INITR(2,1,7) }, + { STRUCT_FIELD_INIT(bth, psn, 2, 8, 24) } +}; + +static const struct ib_field deth_table[] = { + { STRUCT_FIELD_INIT(deth, qkey, 0, 0, 32) }, + { STRUCT_FIELD_INITR(1,0,8) }, + { STRUCT_FIELD_INIT(deth, source_qpn, 1, 8, 24) } +}; + + +/** + * ib_ud_header_init - Initialize UD header structure + * @payload_bytes:Length of packet payload + * @grh_present:GRH flag (if non-zero, GRH will be included) + * @header:Structure to initialize + * + * ib_ud_header_init() initializes the lrh.link_version, lrh.link_next_header, + * lrh.packet_length, grh.ip_version, grh.payload_length, + * grh.next_header, bth.opcode, bth.pad_count and + * bth.transport_header_version fields of a &struct ib_ud_header given + * the payload length and whether a GRH will be included. + */ +void ib_ud_header_init(int payload_bytes, + int grh_present, + struct ib_ud_header *header) +{ + int header_len; + u16 packet_length; + + RtlZeroMemory(header, sizeof *header); + + header_len = + IB_LRH_BYTES + + IB_BTH_BYTES + + IB_DETH_BYTES; + if (grh_present) { + header_len += IB_GRH_BYTES; + } + + header->lrh.link_version = 0; + header->lrh.link_next_header = + (u8)(grh_present ? IB_LNH_IBA_GLOBAL : IB_LNH_IBA_LOCAL); + packet_length = (u16)((IB_LRH_BYTES + + IB_BTH_BYTES + + IB_DETH_BYTES + + payload_bytes + + 4 + /* ICRC */ + 3) / 4); /* round up */ + + header->grh_present = grh_present; + if (grh_present) { + packet_length += IB_GRH_BYTES / 4; + header->grh.ip_version = 6; + header->grh.payload_length = + cl_hton16((u16)((IB_BTH_BYTES + + IB_DETH_BYTES + + payload_bytes + + 4 + /* ICRC */ + 3) & ~3)); /* round up */ + header->grh.next_header = 0x1b; + } + + header->lrh.packet_length = cl_hton16(packet_length); + + if (header->immediate_present) + header->bth.opcode = IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE; + else + header->bth.opcode = IB_OPCODE_UD_SEND_ONLY; + header->bth.pad_count = (u8)((4 - payload_bytes) & 3); + header->bth.transport_header_version = 0; +} + +/** + * ib_ud_header_pack - Pack UD header struct into wire format + * @header:UD header struct + * @buf:Buffer to pack into + * + * ib_ud_header_pack() packs the UD header structure @header into wire + * format in the buffer @buf. + */ +int ib_ud_header_pack(struct ib_ud_header *header, + u8 *buf) +{ + int len = 0; + + ib_pack(lrh_table, ARRAY_SIZE(lrh_table), + &header->lrh, buf); + len += IB_LRH_BYTES; + + if (header->grh_present) { + ib_pack(grh_table, ARRAY_SIZE(grh_table), + &header->grh, buf + len); + len += IB_GRH_BYTES; + } + + ib_pack(bth_table, ARRAY_SIZE(bth_table), + &header->bth, buf + len); + len += IB_BTH_BYTES; + + ib_pack(deth_table, ARRAY_SIZE(deth_table), + &header->deth, buf + len); + len += IB_DETH_BYTES; + + if (header->immediate_present) { + memcpy(buf + len, &header->immediate_data, sizeof header->immediate_data); + len += sizeof header->immediate_data; + } + + return len; +} + +/** + * ib_ud_header_unpack - Unpack UD header struct from wire format + * @header:UD header struct + * @buf:Buffer to pack into + * + * ib_ud_header_pack() unpacks the UD header structure @header from wire + * format in the buffer @buf. + */ +int ib_ud_header_unpack(u8 *buf, + struct ib_ud_header *header) +{ + ib_unpack(lrh_table, ARRAY_SIZE(lrh_table), + buf, &header->lrh); + buf += IB_LRH_BYTES; + + if (header->lrh.link_version != 0) { + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_LOW ,("Invalid LRH.link_version %d\n", + header->lrh.link_version)); + return -EINVAL; + } + + switch (header->lrh.link_next_header) { + case IB_LNH_IBA_LOCAL: + header->grh_present = 0; + break; + + case IB_LNH_IBA_GLOBAL: + header->grh_present = 1; + ib_unpack(grh_table, ARRAY_SIZE(grh_table), + buf, &header->grh); + buf += IB_GRH_BYTES; + + if (header->grh.ip_version != 6) { + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_LOW ,("Invalid GRH.ip_version %d\n", + header->grh.ip_version)); + return -EINVAL; + } + if (header->grh.next_header != 0x1b) { + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_LOW ,("Invalid GRH.next_header 0x%02x\n", + header->grh.next_header)); + return -EINVAL; + } + break; + + default: + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_LOW ,("Invalid LRH.link_next_header %d\n", + header->lrh.link_next_header)); + return -EINVAL; + } + + ib_unpack(bth_table, ARRAY_SIZE(bth_table), + buf, &header->bth); + buf += IB_BTH_BYTES; + + switch (header->bth.opcode) { + case IB_OPCODE_UD_SEND_ONLY: + header->immediate_present = 0; + break; + case IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE: + header->immediate_present = 1; + break; + default: + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_LOW ,("Invalid BTH.opcode 0x%02x\n", + header->bth.opcode)); + return -EINVAL; + } + + if (header->bth.transport_header_version != 0) { + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_LOW ,("Invalid BTH.transport_header_version %d\n", + header->bth.transport_header_version)); + return -EINVAL; + } + + ib_unpack(deth_table, ARRAY_SIZE(deth_table), + buf, &header->deth); + buf += IB_DETH_BYTES; + + if (header->immediate_present) + memcpy(&header->immediate_data, buf, sizeof header->immediate_data); + + return 0; +} diff --git a/branches/WOF2-3/hw/mthca/kernel/mt_uverbs.c b/branches/WOF2-3/hw/mthca/kernel/mt_uverbs.c new file mode 100644 index 00000000..0e4e5674 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/mt_uverbs.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Cisco Systems. All rights reserved. + * Copyright (c) 2005 PathScale, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include +#include + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "mt_uverbs.tmh" +#endif + + +//TODO: all this module is to be eliminated !! + + +static void ib_uverbs_add_one(struct ib_device *device); +static void ib_uverbs_remove_one(struct ib_device *device); + +static struct ib_client uverbs_client = { + "uverbs", + ib_uverbs_add_one, + ib_uverbs_remove_one +}; + +struct ib_uverbs_device { + struct ib_device *ib_dev; +}; + +static void ib_uverbs_add_one(struct ib_device *device) +{ + struct ib_uverbs_device *uverbs_dev; + + if (!device->alloc_ucontext) + return; + + uverbs_dev = kzalloc(sizeof *uverbs_dev, GFP_KERNEL); + if (!uverbs_dev) + return; + + ib_set_client_data(device, &uverbs_client, uverbs_dev); +} + +static void ib_uverbs_remove_one(struct ib_device *device) +{ + struct ib_uverbs_device *uverbs_dev = ib_get_client_data(device, &uverbs_client); + + if (uverbs_dev) + kfree(uverbs_dev); +} + +int ib_uverbs_init(void) +{ + int ret; + + ret = ib_register_client(&uverbs_client); + if (ret) + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("user_verbs: couldn't register client\n")); + + return ret; +} + +void ib_uverbs_cleanup(void) +{ + ib_unregister_client(&uverbs_client); +} + diff --git a/branches/WOF2-3/hw/mthca/kernel/mt_verbs.c b/branches/WOF2-3/hw/mthca/kernel/mt_verbs.c new file mode 100644 index 00000000..3404d4ba --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/mt_verbs.c @@ -0,0 +1,929 @@ +/* + * Copyright (c) 2004 Mellanox Technologies Ltd. All rights reserved. + * Copyright (c) 2004 Infinicon Corporation. All rights reserved. + * Copyright (c) 2004 Intel Corporation. All rights reserved. + * Copyright (c) 2004 Topspin Corporation. All rights reserved. + * Copyright (c) 2004 Voltaire Corporation. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2005 Cisco Systems. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include +#include +#include "mthca_dev.h" +#include "mx_abi.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "mt_verbs.tmh" +#endif + + +void ibv_um_close( struct ib_ucontext * h_um_ca ) +{ + int err; + ib_api_status_t status; + struct ib_ucontext *context_p = (struct ib_ucontext *)h_um_ca; + + HCA_ENTER(HCA_DBG_SHIM); + + context_p->is_removing = TRUE; + + if (atomic_read(&context_p->usecnt)) { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_SHIM, + ("resources are not released (cnt %d)\n", context_p->usecnt)); + status = IB_RESOURCE_BUSY; + goto err_usage; + } + + err = ibv_dealloc_pd( context_p->pd ); + if (err) { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_SHIM, + ("ibv_dealloc_pd failed (%d)\n", err)); + status = errno_to_iberr(err); + } + + err = mthca_dealloc_ucontext(context_p); + if (err) { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_SHIM, + ("mthca_dealloc_ucontext failed (%d)\n", err)); + status = errno_to_iberr(err); + goto err_dealloc_ucontext; + } + + HCA_PRINT(TRACE_LEVEL_INFORMATION,HCA_DBG_SHIM, + ("pcs %p\n", PsGetCurrentProcess()) ); + status = IB_SUCCESS; + goto end; + +err_dealloc_ucontext: +err_usage: +end: + if (status != IB_SUCCESS) + { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_SHIM, + ("completes with ERROR status %x\n", status)); + } + HCA_EXIT(HCA_DBG_SHIM); + return; +} + +/* Protection domains */ + +struct ib_pd *ibv_alloc_pd(struct ib_device *device, + struct ib_ucontext *context, ci_umv_buf_t* const p_umv_buf) +{ + struct ib_pd *pd; + + // direct call is a must, because "lifefish" devices doesn't fill driver i/f table + pd = mthca_alloc_pd(device, context, p_umv_buf); + + if (!IS_ERR(pd)) { + pd->device = device; + pd->ucontext = context; + atomic_set(&pd->usecnt, 0); + KeInitializeMutex( &pd->mutex, 0 ); + INIT_LIST_HEAD( &pd->list ); + HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_CQ ,("PD%d use cnt %d, pd_handle %p, ctx %p \n", + ((struct mthca_pd*)pd)->pd_num, pd->usecnt, pd, pd->ucontext)); + } + + return pd; +} + +int ibv_dealloc_pd(struct ib_pd *pd) +{ + // we need first to release list of AV MRs to decrease pd->usecnt + if (pd->ucontext) { + struct ib_mr *ib_mr, *tmp; + down(&pd->mutex ); + list_for_each_entry_safe(ib_mr, tmp, &pd->list, list,struct ib_mr,struct ib_mr) { + ibv_dereg_mr( ib_mr ); + } + up(&pd->mutex ); + } + + if (atomic_read(&pd->usecnt)) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_CQ,("resources are not released (cnt %d)\n", pd->usecnt)); + return -EBUSY; + } + + HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_CQ ,("PD%d use cnt %d, pd_handle %p, ctx %p \n", + ((struct mthca_pd*)pd)->pd_num, pd->usecnt, pd, pd->ucontext)); + // direct call is a must, because "lifefish" devices doesn't fill driver i/f table + return mthca_dealloc_pd(pd); +} + +/* Address handles */ + +struct ib_ah *ibv_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr, + struct ib_ucontext *context, ci_umv_buf_t* const p_umv_buf) +{ + int err; + struct ib_ah *ah; + struct ib_mr *ib_mr = NULL; + u64 start = 0; + u64 user_handle = 0; + struct ibv_create_ah_resp *create_ah_resp = 0; + + // for user call we need also allocate MR + if (context && p_umv_buf && p_umv_buf->p_inout_buf) { + struct ibv_create_ah *create_ah = (struct ibv_create_ah *)(ULONG_PTR)p_umv_buf->p_inout_buf; + + // create region; destroy will be done on dealloc_pd + ib_mr = ibv_reg_mr( + pd, + create_ah->mr.access_flags, + (void*)(ULONG_PTR)create_ah->mr.start, + create_ah->mr.length, create_ah->mr.hca_va, TRUE, FALSE ); + if (IS_ERR(ib_mr)) { + err = PTR_ERR(ib_mr); + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_AV ,("ibv_reg_mr failed (%d)\n", err)); + goto err_alloc_mr; + } + + start = create_ah->mr.start; + user_handle = create_ah->user_handle; + + // chain this MR to PD list + down(&pd->mutex ); + list_add_tail(&ib_mr->list, &pd->list); + up(&pd->mutex ); + } + + ah = pd->device->create_ah(pd, ah_attr); + + /* fill obligatory fields */ + if (context && p_umv_buf && p_umv_buf->p_inout_buf) { + create_ah_resp = (struct ibv_create_ah_resp *)(ULONG_PTR)p_umv_buf->p_inout_buf; + create_ah_resp->user_handle = user_handle; + } + + if (IS_ERR(ah)) { + err = PTR_ERR(ah); + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_AV ,("create_ah failed (%d)\n", err)); + goto err_create_ah; + } + + // fill results + ah->device = pd->device; + ah->pd = pd; + ah->ucontext = context; + atomic_inc(&pd->usecnt); + HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_AV ,("PD%d use cnt %d, pd_handle %p, ctx %p \n", + ((struct mthca_pd*)pd)->pd_num, pd->usecnt, pd, pd->ucontext)); + + // fill results for user + if (context && p_umv_buf && p_umv_buf->p_inout_buf) { + struct ibv_create_ah_resp *create_ah_resp = (struct ibv_create_ah_resp *)(ULONG_PTR)p_umv_buf->p_inout_buf; + create_ah_resp->start = start; + create_ah_resp->mr.lkey = ib_mr->lkey; + create_ah_resp->mr.rkey = ib_mr->rkey; + create_ah_resp->mr.mr_handle = (u64)(ULONG_PTR)ib_mr; + p_umv_buf->output_size = sizeof(struct ibv_create_ah_resp); + } + + return ah; + +err_create_ah: + if (ib_mr) + ibv_dereg_mr(ib_mr); +err_alloc_mr: + if( p_umv_buf && p_umv_buf->command ) + p_umv_buf->status = IB_ERROR; + return ERR_PTR(ib_mr); +} + +struct ib_ah *ibv_create_ah_from_wc(struct ib_pd *pd, struct _ib_wc *wc, + struct ib_grh *grh, u8 port_num) +{ + struct ib_ah_attr ah_attr; + u32 flow_class; + u16 gid_index; + int ret; + + memset(&ah_attr, 0, sizeof ah_attr); + ah_attr.dlid = wc->recv.ud.remote_lid; + ah_attr.sl = wc->recv.ud.remote_sl; + ah_attr.src_path_bits = wc->recv.ud.path_bits; + ah_attr.port_num = port_num; + + if (wc->recv.ud.recv_opt & IB_RECV_OPT_GRH_VALID) { + ah_attr.ah_flags = IB_AH_GRH; + ah_attr.grh.dgid = grh->dgid; + + ret = ib_find_cached_gid(pd->device, &grh->sgid, &port_num, + &gid_index); + if (ret) + return ERR_PTR(ret); + + ah_attr.grh.sgid_index = (u8) gid_index; + flow_class = cl_ntoh32(grh->version_tclass_flow); + ah_attr.grh.flow_label = flow_class & 0xFFFFF; + ah_attr.grh.traffic_class = (u8)((flow_class >> 20) & 0xFF); + ah_attr.grh.hop_limit = grh->hop_limit; + } + + return ibv_create_ah(pd, &ah_attr, NULL, NULL); +} + +int ibv_modify_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr) +{ + return ah->device->modify_ah ? + ah->device->modify_ah(ah, ah_attr) : + -ENOSYS; +} + +int ibv_query_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr) +{ + return ah->device->query_ah ? + ah->device->query_ah(ah, ah_attr) : + -ENOSYS; +} + + +static void release_user_cq_qp_resources( + struct ib_ucontext *ucontext, + struct ib_mr * ib_mr) +{ + if (ucontext) { + ibv_dereg_mr( ib_mr ); + atomic_dec(&ucontext->usecnt); + if (!atomic_read(&ucontext->usecnt) && ucontext->is_removing) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_SHIM ,("User resources are released. Removing context\n")); + ibv_um_close(ucontext); + } + } +} + +int ibv_destroy_ah(struct ib_ah *ah) +{ + struct ib_pd *pd; + int ret; + + HCA_ENTER(HCA_DBG_AV); + pd = ah->pd; + + ret = ah->device->destroy_ah(ah); + if (!ret) { + atomic_dec(&pd->usecnt); + HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_AV ,("PD%d use cnt %d, pd_handle %p, ctx %p \n", + ((struct mthca_pd*)pd)->pd_num, pd->usecnt, pd, pd->ucontext)); + } + HCA_EXIT(HCA_DBG_AV); + return ret; +} + +/* Shared receive queues */ + +struct ib_srq *ibv_create_srq(struct ib_pd *pd, + struct ib_srq_init_attr *srq_init_attr, + struct ib_ucontext *context, ci_umv_buf_t* const p_umv_buf) +{ + int err; + struct ib_srq *ib_srq; + struct ib_mr *ib_mr = NULL; + u64 user_handle = 0; + struct ibv_create_srq_resp *create_srq_resp = 0; + + // for user call we need also allocate MR + if (context && p_umv_buf && p_umv_buf->p_inout_buf) { + struct ibv_create_srq *create_srp = (struct ibv_create_srq *)(ULONG_PTR)p_umv_buf->p_inout_buf; + + // create region + ib_mr = ibv_reg_mr( + (struct ib_pd *)(ULONG_PTR)create_srp->mr.pd_handle, + create_srp->mr.access_flags, + (void*)(ULONG_PTR)create_srp->mr.start, + create_srp->mr.length, create_srp->mr.hca_va, TRUE, FALSE ); + if (IS_ERR(ib_mr)) { + err = PTR_ERR(ib_mr); + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_QP ,("ibv_reg_mr failed (%d)\n", err)); + goto err_alloc_mr; + } + create_srp->lkey = ib_mr->lkey; + user_handle = create_srp->user_handle; + } + + ib_srq = pd->device->create_srq(pd, srq_init_attr, p_umv_buf); + + /* fill obligatory fields */ + if (context && p_umv_buf && p_umv_buf->p_inout_buf) { + create_srq_resp = (struct ibv_create_srq_resp *)(ULONG_PTR)p_umv_buf->p_inout_buf; + create_srq_resp->user_handle = user_handle; + } + + if (IS_ERR(ib_srq)) { + err = PTR_ERR(ib_srq); + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_QP ,("create_srq failed (%d)\n", err)); + goto err_create_srq; + } + + // fill results + ib_srq->device = pd->device; + ib_srq->pd = pd; + ib_srq->ucontext = context; + ib_srq->event_handler = srq_init_attr->event_handler; + ib_srq->srq_context = srq_init_attr->srq_context; + atomic_inc(&pd->usecnt); + atomic_set(&ib_srq->usecnt, 0); + if (context) + atomic_inc(&context->usecnt); + HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_QP ,("PD%d use cnt %d, pd_handle %p, ctx %p \n", + ((struct mthca_pd*)pd)->pd_num, pd->usecnt, pd, pd->ucontext)); + + HCA_PRINT(TRACE_LEVEL_INFORMATION, HCA_DBG_SRQ , + ("uctx %p, qhndl %p, qnum %#x \n", + pd->ucontext, ib_srq, ((struct mthca_srq*)ib_srq)->srqn ) ); + + // fill results for user + if (context && p_umv_buf && p_umv_buf->p_inout_buf) { + struct mthca_srq *srq = (struct mthca_srq *)ib_srq; + ib_srq->ib_mr = ib_mr; + create_srq_resp->mr.lkey = ib_mr->lkey; + create_srq_resp->mr.rkey = ib_mr->rkey; + create_srq_resp->mr.mr_handle = (u64)(ULONG_PTR)ib_mr; + create_srq_resp->srq_handle = (__u64)(ULONG_PTR)srq; + create_srq_resp->max_wr = (mthca_is_memfree(to_mdev(pd->device))) ? srq->max - 1 : srq->max; + create_srq_resp->max_sge = srq->max_gs; + create_srq_resp->srqn= srq->srqn; + p_umv_buf->output_size = sizeof(struct ibv_create_srq_resp); + HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_QP ,("PD%d use cnt %d \n", + ((struct mthca_pd*)pd)->pd_num, pd->usecnt)); + } + + return ib_srq; + +err_create_srq: + if (ib_mr) + ibv_dereg_mr(ib_mr); +err_alloc_mr: + if( p_umv_buf && p_umv_buf->command ) + p_umv_buf->status = IB_ERROR; + HCA_EXIT(HCA_DBG_QP); + return ERR_PTR(err); +} + +int ibv_modify_srq(struct ib_srq *srq, + ib_srq_attr_t *srq_attr, + ib_srq_attr_mask_t srq_attr_mask) +{ + return srq->device->modify_srq(srq, srq_attr, srq_attr_mask); +} + +int ibv_query_srq(struct ib_srq *srq, + ib_srq_attr_t *srq_attr) +{ + return srq->device->query_srq(srq, srq_attr); +} + +int ibv_destroy_srq(struct ib_srq *srq) +{ + int ret; + struct ib_pd *pd = srq->pd; + struct ib_ucontext *ucontext = pd->ucontext; + struct ib_mr * ib_mr = srq->ib_mr; + + ret = srq->device->destroy_srq(srq); + if (!ret) { + atomic_dec(&pd->usecnt); + HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_SRQ ,("PD%d use cnt %d, pd_handle %p, ctx %p \n", + ((struct mthca_pd*)pd)->pd_num, pd->usecnt, pd, pd->ucontext)); + release_user_cq_qp_resources(ucontext, ib_mr); + } + + return ret; +} + +/* Queue pairs */ + +struct ib_qp *ibv_create_qp(struct ib_pd *pd, + struct ib_qp_init_attr *qp_init_attr, + struct ib_ucontext *context, ci_umv_buf_t* const p_umv_buf) +{ + int err; + struct ib_qp *ib_qp; + struct ib_mr *ib_mr = NULL; + u64 user_handle = 0; + + HCA_ENTER(HCA_DBG_QP); + + // for user call we need also allocate MR + if (context && p_umv_buf && p_umv_buf->p_inout_buf) { + struct ibv_create_qp *create_qp = (struct ibv_create_qp *)(ULONG_PTR)p_umv_buf->p_inout_buf; + + // create region + ib_mr = ibv_reg_mr( + (struct ib_pd *)(ULONG_PTR)create_qp->mr.pd_handle, + create_qp->mr.access_flags, + (void*)(ULONG_PTR)create_qp->mr.start, + create_qp->mr.length, create_qp->mr.hca_va, TRUE, FALSE ); + if (IS_ERR(ib_mr)) { + err = PTR_ERR(ib_mr); + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_QP ,("ibv_reg_mr failed (%d)\n", err)); + goto err_alloc_mr; + } + create_qp->lkey = ib_mr->lkey; + user_handle = create_qp->user_handle; + } + + ib_qp = pd->device->create_qp(pd, qp_init_attr, p_umv_buf); + + if (IS_ERR(ib_qp)) { + err = PTR_ERR(ib_qp); + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_QP ,("create_qp failed (%d)\n", err)); + goto err_create_qp; + } + + // fill results + ib_qp->device = pd->device; + ib_qp->pd = pd; + ib_qp->send_cq = qp_init_attr->send_cq; + ib_qp->recv_cq = qp_init_attr->recv_cq; + ib_qp->srq = qp_init_attr->srq; + ib_qp->ucontext = context; + ib_qp->event_handler = qp_init_attr->event_handler; + ib_qp->qp_context = qp_init_attr->qp_context; + ib_qp->qp_type = qp_init_attr->qp_type; + atomic_inc(&pd->usecnt); + atomic_inc(&qp_init_attr->send_cq->usecnt); + atomic_inc(&qp_init_attr->recv_cq->usecnt); + if (qp_init_attr->srq) + atomic_inc(&qp_init_attr->srq->usecnt); + if (context) + atomic_inc(&context->usecnt); + HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_QP ,("PD%d use cnt %d, pd_handle %p, ctx %p \n", + ((struct mthca_pd*)pd)->pd_num, pd->usecnt, pd, pd->ucontext)); + + HCA_PRINT(TRACE_LEVEL_INFORMATION, HCA_DBG_QP , + ("uctx %p, qhndl %p, qnum %#x, q_num %#x, scq %#x:%#x, rcq %#x:%#x \n", + pd->ucontext, ib_qp, ((struct mthca_qp*)ib_qp)->qpn, ib_qp->qp_num, + ((struct mthca_cq*)ib_qp->send_cq)->cqn, ib_qp->send_cq->cqe, + ((struct mthca_cq*)ib_qp->recv_cq)->cqn, ib_qp->recv_cq->cqe ) ); + + // fill results for user + if (context && p_umv_buf && p_umv_buf->p_inout_buf) { + struct mthca_qp *qp = (struct mthca_qp *)ib_qp; + struct ibv_create_qp_resp *create_qp_resp = (struct ibv_create_qp_resp *)(ULONG_PTR)p_umv_buf->p_inout_buf; + ib_qp->ib_mr = ib_mr; + create_qp_resp->qpn = ib_qp->qp_num; + create_qp_resp->user_handle = user_handle; + create_qp_resp->mr.lkey = ib_mr->lkey; + create_qp_resp->mr.rkey = ib_mr->rkey; + create_qp_resp->mr.mr_handle = (u64)(ULONG_PTR)ib_mr; + create_qp_resp->qp_handle = (__u64)(ULONG_PTR)qp; + create_qp_resp->max_send_wr = qp->sq.max; + create_qp_resp->max_recv_wr = qp->rq.max; + create_qp_resp->max_send_sge = qp->sq.max_gs; + create_qp_resp->max_recv_sge = qp->rq.max_gs; + create_qp_resp->max_inline_data = qp->max_inline_data; + p_umv_buf->output_size = sizeof(struct ibv_create_qp_resp); + } + + return ib_qp; + +err_create_qp: + if (ib_mr) + ibv_dereg_mr(ib_mr); +err_alloc_mr: + if( p_umv_buf && p_umv_buf->command ) + p_umv_buf->status = IB_ERROR; + HCA_EXIT(HCA_DBG_QP); + return ERR_PTR(err); +} + +int ibv_modify_qp(struct ib_qp *qp, + struct ib_qp_attr *qp_attr, + int qp_attr_mask) +{ + return qp->device->modify_qp(qp, qp_attr, qp_attr_mask); +} + +int ibv_query_qp(struct ib_qp *qp, + struct ib_qp_attr *qp_attr, + int qp_attr_mask, + struct ib_qp_init_attr *qp_init_attr) +{ + return qp->device->query_qp ? + qp->device->query_qp(qp, qp_attr, qp_attr_mask, qp_init_attr) : + -ENOSYS; +} + +int ibv_destroy_qp(struct ib_qp *qp) +{ + struct ib_pd *pd; + struct ib_cq *scq, *rcq; + struct ib_srq *srq; + int ret; + struct ib_ucontext *ucontext; + struct ib_mr * ib_mr; + + pd = qp->pd; + scq = qp->send_cq; + rcq = qp->recv_cq; + srq = qp->srq; + ucontext = pd->ucontext; + ib_mr = qp->ib_mr; + + ret = qp->device->destroy_qp(qp); + if (!ret) { + atomic_dec(&pd->usecnt); + atomic_dec(&scq->usecnt); + atomic_dec(&rcq->usecnt); + HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_QP ,("PD%d use cnt %d, pd_handle %p, ctx %p \n", + ((struct mthca_pd*)pd)->pd_num, pd->usecnt, pd, pd->ucontext)); + if (srq) + atomic_dec(&srq->usecnt); + release_user_cq_qp_resources(ucontext, ib_mr); + } + + return ret; +} + +/* Completion queues */ + +struct ib_cq *ibv_create_cq(struct ib_device *device, + ib_comp_handler comp_handler, + void (*event_handler)(ib_event_rec_t *), + void *cq_context, int cqe, + struct ib_ucontext *context, ci_umv_buf_t* const p_umv_buf) +{ + int err; + struct ib_cq *cq; + struct ib_mr *ib_mr = NULL; + u64 user_handle = 0; + + // for user call we need also allocate MR + if (context && p_umv_buf && p_umv_buf->p_inout_buf) { + struct ibv_create_cq *create_cq = (struct ibv_create_cq *)(ULONG_PTR)p_umv_buf->p_inout_buf; + + // create region + ib_mr = ibv_reg_mr( + (struct ib_pd *)(ULONG_PTR)create_cq->mr.pd_handle, + create_cq->mr.access_flags, + (void*)(ULONG_PTR)create_cq->mr.start, + create_cq->mr.length, create_cq->mr.hca_va, TRUE, FALSE ); + if (IS_ERR(ib_mr)) { + err = PTR_ERR(ib_mr); + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_CQ ,("ibv_reg_mr failed (%d)\n", err)); + goto err_alloc_mr; + } + user_handle = create_cq->user_handle; + create_cq->lkey = ib_mr->lkey; + cqe = create_cq->cqe; + } + + // create cq + cq = device->create_cq(device, cqe, context, p_umv_buf); + if (IS_ERR(cq)) { + err = PTR_ERR(cq); + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_CQ ,("create_cq failed (%d)\n", err)); + goto err_create_cq; + } + + cq->device = device; + cq->ucontext = context; + cq->comp_handler = comp_handler; + cq->event_handler = event_handler; + cq->cq_context = cq_context; + atomic_set(&cq->usecnt, 0); + if (context) + atomic_inc(&context->usecnt); + + // fill results + if (context && p_umv_buf && p_umv_buf->p_inout_buf) { + struct ibv_create_cq_resp *create_cq_resp = (struct ibv_create_cq_resp *)(ULONG_PTR)p_umv_buf->p_inout_buf; + cq->ib_mr = ib_mr; + create_cq_resp->user_handle = user_handle; + create_cq_resp->mr.lkey = ib_mr->lkey; + create_cq_resp->mr.rkey = ib_mr->rkey; + create_cq_resp->mr.mr_handle = (u64)(ULONG_PTR)ib_mr; + create_cq_resp->cq_handle = (u64)(ULONG_PTR)cq; + create_cq_resp->cqe = cq->cqe; + p_umv_buf->output_size = sizeof(struct ibv_create_cq_resp); + } + + return cq; + +err_create_cq: + if (ib_mr) + ibv_dereg_mr(ib_mr); +err_alloc_mr: + if( p_umv_buf && p_umv_buf->command ) + p_umv_buf->status = IB_ERROR; + return ERR_PTR(err); +} + +int ibv_destroy_cq(struct ib_cq *cq) +{ + int ret; + struct ib_ucontext *ucontext = cq->ucontext; + struct ib_mr * ib_mr = cq->ib_mr; + + if (atomic_read(&cq->usecnt)) + return -EBUSY; + + ret = cq->device->destroy_cq(cq); + + release_user_cq_qp_resources(ucontext, ib_mr); + + return ret; +} + +int ibv_resize_cq(struct ib_cq *cq, + int cqe) +{ + int ret; + + if (!cq->device->resize_cq) + return -ENOSYS; + + ret = cq->device->resize_cq(cq, &cqe); + if (!ret) + cq->cqe = cqe; + + return ret; +} + +/* Memory regions */ + +struct ib_mr *ibv_reg_mr(struct ib_pd *pd, + mthca_qp_access_t mr_access_flags, + void* vaddr, + uint64_t length, + uint64_t hca_va, + boolean_t um_call, + boolean_t secure + ) +{ + struct ib_mr *ib_mr; + int err; + HCA_ENTER(HCA_DBG_MEMORY); + + ib_mr = pd->device->reg_virt_mr(pd, vaddr, length, hca_va, mr_access_flags, um_call, secure); + if (IS_ERR(ib_mr)) { + err = PTR_ERR(ib_mr); + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_MEMORY ,("mthca_reg_user_mr failed (%d)\n", err)); + goto err_reg_user_mr; + } + + ib_mr->device = pd->device; + ib_mr->pd = pd; + atomic_inc(&pd->usecnt); + atomic_set(&ib_mr->usecnt, 0); + HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_MEMORY ,("PD%d use cnt %d, pd_handle %p, ctx %p \n", + ((struct mthca_pd*)pd)->pd_num, pd->usecnt, pd, pd->ucontext)); + HCA_EXIT(HCA_DBG_MEMORY); + return ib_mr; + +err_reg_user_mr: + HCA_EXIT(HCA_DBG_MEMORY); + return ERR_PTR(err); +} + +struct ib_mr *ibv_get_dma_mr(struct ib_pd *pd, mthca_qp_access_t mr_access_flags) +{ + struct ib_mr *mr; + + // direct call is a must, because "lifefish" devices doesn't fill driver i/f table + mr = mthca_get_dma_mr(pd, mr_access_flags); + + if (!IS_ERR(mr)) { + mr->device = pd->device; + mr->pd = pd; + atomic_inc(&pd->usecnt); + atomic_set(&mr->usecnt, 0); + HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_MEMORY ,("PD%d use cnt %d \n", + ((struct mthca_pd*)pd)->pd_num, pd->usecnt)); + } + + return mr; +} + +struct ib_mr *ibv_reg_phys_mr(struct ib_pd *pd, + struct ib_phys_buf *phys_buf_array, + int num_phys_buf, + mthca_qp_access_t mr_access_flags, + u64 *iova_start) +{ + struct ib_mr *mr; + + mr = pd->device->reg_phys_mr(pd, phys_buf_array, num_phys_buf, + mr_access_flags, iova_start); + + if (!IS_ERR(mr)) { + mr->device = pd->device; + mr->pd = pd; + atomic_inc(&pd->usecnt); + atomic_set(&mr->usecnt, 0); + HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_MEMORY ,("PD%d use cnt %d \n", + ((struct mthca_pd*)pd)->pd_num, pd->usecnt)); + } + + return mr; +} + +int ibv_rereg_phys_mr(struct ib_mr *mr, + int mr_rereg_mask, + struct ib_pd *pd, + struct ib_phys_buf *phys_buf_array, + int num_phys_buf, + mthca_qp_access_t mr_access_flags, + u64 *iova_start) +{ + struct ib_pd *old_pd; + int ret; + + if (!mr->device->rereg_phys_mr) + return -ENOSYS; + + if (atomic_read(&mr->usecnt)) + return -EBUSY; + + old_pd = mr->pd; + + ret = mr->device->rereg_phys_mr(mr, mr_rereg_mask, pd, + phys_buf_array, num_phys_buf, + mr_access_flags, iova_start); + + if (!ret && (mr_rereg_mask & IB_MR_REREG_PD)) { + atomic_dec(&old_pd->usecnt); + atomic_inc(&pd->usecnt); + HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_MEMORY ,("PD%d use cnt %d \n", + ((struct mthca_pd*)pd)->pd_num, pd->usecnt)); + } + + return ret; +} + +int ibv_query_mr(struct ib_mr *mr, struct ib_mr_attr *mr_attr) +{ + return mr->device->query_mr ? + mr->device->query_mr(mr, mr_attr) : -ENOSYS; +} + +int ibv_dereg_mr(struct ib_mr *mr) +{ + int ret; + struct ib_pd *pd; + + if (atomic_read(&mr->usecnt)) + return -EBUSY; + + pd = mr->pd; + // direct call is a must, because "lifefish" devices doesn't fill driver i/f table + ret = mthca_dereg_mr(mr); + if (!ret) { + atomic_dec(&pd->usecnt); + HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_MEMORY ,("PD%d use cnt %d, pd_handle %p, ctx %p \n", + ((struct mthca_pd*)pd)->pd_num, pd->usecnt, pd, pd->ucontext)); + } + + return ret; +} + +/* Memory windows */ + +struct ib_mw *ibv_alloc_mw(struct ib_pd *pd) +{ + struct ib_mw *mw; + + if (!pd->device->alloc_mw) + return ERR_PTR(-ENOSYS); + + mw = pd->device->alloc_mw(pd); + if (!IS_ERR(mw)) { + mw->device = pd->device; + mw->pd = pd; + atomic_inc(&pd->usecnt); + HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_MEMORY ,("PD%d use cnt %d \n", + ((struct mthca_pd*)pd)->pd_num, pd->usecnt)); + } + + return mw; +} + +int ibv_dealloc_mw(struct ib_mw *mw) +{ + struct ib_pd *pd; + int ret; + + pd = mw->pd; + ret = mw->device->dealloc_mw(mw); + if (!ret) { + atomic_dec(&pd->usecnt); + HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_MEMORY ,("PD%d use cnt %d \n", + ((struct mthca_pd*)pd)->pd_num, pd->usecnt)); + } + + return ret; +} + +/* "Fast" memory regions */ + +struct ib_fmr *ibv_alloc_fmr(struct ib_pd *pd, + mthca_qp_access_t mr_access_flags, + struct ib_fmr_attr *fmr_attr) +{ + struct ib_fmr *fmr; + + if (!pd->device->alloc_fmr) + return ERR_PTR(-ENOSYS); + + fmr = pd->device->alloc_fmr(pd, mr_access_flags, fmr_attr); + if (!IS_ERR(fmr)) { + fmr->device = pd->device; + fmr->pd = pd; + atomic_inc(&pd->usecnt); + HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_MEMORY ,("PD%d use cnt %d \n", + ((struct mthca_pd*)pd)->pd_num, pd->usecnt)); + } + + return fmr; +} + +int ibv_map_phys_fmr(struct ib_fmr *fmr, + u64 *page_list, int list_len, + u64 iova) +{ + return fmr->device->map_phys_fmr(fmr, page_list, list_len, iova); +} + +int ibv_unmap_fmr(struct list_head *fmr_list) +{ + struct ib_fmr *fmr; + + if (list_empty(fmr_list)) + return 0; + + fmr = list_entry(fmr_list->Flink, struct ib_fmr, list); + return fmr->device->unmap_fmr(fmr_list); +} + +int ibv_dealloc_fmr(struct ib_fmr *fmr) +{ + struct ib_pd *pd; + int ret; + + pd = fmr->pd; + ret = fmr->device->dealloc_fmr(fmr); + if (!ret) { + atomic_dec(&pd->usecnt); + HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_MEMORY ,("PD%d use cnt %d \n", + ((struct mthca_pd*)pd)->pd_num, pd->usecnt)); + } + + return ret; +} + +/* Multicast groups */ + +int ibv_attach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid) +{ + if (!qp->device->attach_mcast) + return -ENOSYS; + if (gid->raw[0] != 0xff || qp->qp_type != IB_QPT_UNRELIABLE_DGRM) + return -EINVAL; + + return qp->device->attach_mcast(qp, gid, lid); +} + +int ibv_detach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid) +{ + if (!qp->device->detach_mcast) + return -ENOSYS; + if (gid->raw[0] != 0xff || qp->qp_type != IB_QPT_UNRELIABLE_DGRM) + return -EINVAL; + + return qp->device->detach_mcast(qp, gid, lid); +} diff --git a/branches/WOF2-3/hw/mthca/kernel/mthca.cdf b/branches/WOF2-3/hw/mthca/kernel/mthca.cdf new file mode 100644 index 00000000..7a865639 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/mthca.cdf @@ -0,0 +1,29 @@ +[CatalogHeader] +Name=mthca.cat +PublicVersion=0x0000001 +EncodingType=0x00010001 +CATATTR1=0x10010001:OSAttr:2:6.0 +[CatalogFiles] +mthca.inf=mthca.inf +mthca.sys=mthca.sys +mthcau.dll=mthcau.dll +mthcaud.dll=mthcaud.dll +mthca32.dll=mthca32.dll +mthca32d.dll=mthca32d.dll +ibal.dll=ibal.dll +ibald.dll=ibald.dll +complib.dll=complib.dll +complibd.dll=complibd.dll +cl32.dll=cl32.dll +cl32d.dll=cl32d.dll +ibal32.dll=ibal32.dll +ibal32d.dll=ibal32d.dll +ibbus.sys=ibbus.sys +winverbs.sys=winverbs.sys +winverbs.dll=winverbs.dll +winverbsd.dll=winverbsd.dll +winmad.sys=winmad.sys +winmad.dll=winmad.dll +winmadd.dll=winmadd.dll +WdfCoInstaller01007.dll=WdfCoInstaller01007.dll + diff --git a/branches/WOF2-3/hw/mthca/kernel/mthca.h b/branches/WOF2-3/hw/mthca/kernel/mthca.h new file mode 100644 index 00000000..9570421a --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/mthca.h @@ -0,0 +1,9 @@ +#ifndef MTHCA_H +#define MTHCA_H + +NTSTATUS mthca_init_one(hca_dev_ext_t *ext); +void mthca_remove_one(hca_dev_ext_t *ext); +int mthca_get_dev_info(struct mthca_dev *mdev, __be64 *node_guid, u32 *hw_id); + +#endif + diff --git a/branches/WOF2-3/hw/mthca/kernel/mthca.inx b/branches/WOF2-3/hw/mthca/kernel/mthca.inx new file mode 100644 index 00000000..495e0512 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/mthca.inx @@ -0,0 +1,463 @@ +; Mellanox Technologies InfiniBand HCAs. +; Copyright 2005 Mellanox Technologies all Rights Reserved. + +[Version] +Signature="$Windows NT$" +Class=InfiniBandController +ClassGUID={58517E00-D3CF-40c9-A679-CEE5752F4491} +Provider=%OFA% +; must be synchronized with MTHCA_DEV.H +DriverVer=03/08/2006,1.0.0000.614 +CatalogFile=mthca.cat + +; ================= Destination directory section ===================== + +[DestinationDirs] +DefaultDestDir=%DIRID_DRIVERS% +MTHCA.UMCopyFiles=%DIRID_SYSTEM% +MTHCA.WOW64CopyFiles=%DIRID_SYSTEM_X86% +Ibal.UMCopyFiles=%DIRID_SYSTEM% +Ibal.WOW64CopyFiles=%DIRID_SYSTEM_X86% +WinVerbs.CopySysFiles = %DIRID_DRIVERS% +WinVerbs.CopyDllFiles = %DIRID_SYSTEM% +WinMad.CopySysFiles = %DIRID_DRIVERS% +WinMad.CopyDllFiles = %DIRID_SYSTEM% +Wdf_CoInstaller_CopyFiles = %DIRID_SYSTEM% + + +; ================= Class Install section ===================== + +[ClassInstall32] +AddReg=ClassAddReg + +[ClassAddReg] +HKR,,,,"InfiniBand Channel Adapters" +HKR,,Icon,,-5 +HKR,,SilentInstall,,1 +HKR,,"UpperFilters",0x00010000,"ibbus" ; enable IBBUS/AL Filter driver load. +HKR,,"UpperFilters",0x00010008,"WinVerbs" ; enable winverbs Filter driver load. +HKR,,"UpperFilters",0x00010008,"WinMad" + + +; ================= Device Install section ===================== + +[SourceDisksNames.x86] +1=%DiskId%,,,"" + +[SourceDisksNames.amd64] +1=%DiskId%,,,"" + +[SourceDisksNames.ia64] +1=%DiskId%,,,"" + +[SourceDisksFiles] +mthca.sys=1,, +mthcau.dll=1,, +mthcaud.dll=1,, +ibal.dll=1,, +complib.dll=1,, +ibald.dll=1,, +complibd.dll=1,, +ibbus.sys=1,, +winverbs.sys = 1,, +winverbs.dll = 1,, +winverbsd.dll = 1,, +winmad.sys = 1,, +winmad.dll = 1,, +winmadd.dll = 1,, +WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll = 1,, + + +[SourceDisksFiles.amd64] +mthca.sys=1,, +mthcau.dll=1,, +mthcaud.dll=1,, +mthca32.dll=1,, +mthca32d.dll=1,, +ibal.dll=1,, +ibald.dll=1,, +complib.dll=1,, +complibd.dll=1,, +cl32.dll=1,, +cl32d.dll=1,, +ibal32.dll=1,, +ibal32d.dll=1,, +ibbus.sys=1,, +winverbs.sys = 1,, +winverbs.dll = 1,, +winverbsd.dll = 1,, +winmad.sys = 1,, +winmad.dll = 1,, +winmadd.dll = 1,, +WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll = 1,, + +[SourceDisksFiles.ia64] +mthca.sys=1,, +mthcau.dll=1,, +mthcaud.dll=1,, +mthca32.dll=1,, +mthca32d.dll=1,, +ibal.dll=1,, +ibald.dll=1,, +complib.dll=1,, +complibd.dll=1,, +cl32.dll=1,, +cl32d.dll=1,, +ibal32.dll=1,, +ibal32d.dll=1,, +ibbus.sys=1,, +winverbs.sys = 1,, +winverbs.dll = 1,, +winverbsd.dll = 1,, +winmad.sys = 1,, +winmad.dll = 1,, +winmadd.dll = 1,, +WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll = 1,, + +[Manufacturer] +%MTL% = HCA.DeviceSection,ntx86,ntamd64,ntia64 + +[HCA.DeviceSection] +; empty since we don't support W9x/Me + +[HCA.DeviceSection.ntx86] +%MT23108.DeviceDesc%=MTHCA.DDInstall, PCI\VEN_15B3&DEV_5A44 +%MT25208.DeviceDesc%=MTHCA.DDInstall, PCI\VEN_15B3&DEV_6278 +%MT25218.DeviceDesc%=MTHCA.DDInstall, PCI\VEN_15B3&DEV_6282 +%MT24204.DeviceDesc%=MTHCA.DDInstall, PCI\VEN_15B3&DEV_5E8C +%MT25204.DeviceDesc%=MTHCA.DDInstall, PCI\VEN_15B3&DEV_6274 + +[HCA.DeviceSection.ntamd64] +%MT23108.DeviceDesc%=MTHCA.DDInstall, PCI\VEN_15B3&DEV_5A44 +%MT25208.DeviceDesc%=MTHCA.DDInstall, PCI\VEN_15B3&DEV_6278 +%MT25218.DeviceDesc%=MTHCA.DDInstall, PCI\VEN_15B3&DEV_6282 +%MT24204.DeviceDesc%=MTHCA.DDInstall, PCI\VEN_15B3&DEV_5E8C +%MT25204.DeviceDesc%=MTHCA.DDInstall, PCI\VEN_15B3&DEV_6274 + +[HCA.DeviceSection.ntia64] +%MT23108.DeviceDesc%=MTHCA.DDInstall, PCI\VEN_15B3&DEV_5A44 +%MT25208.DeviceDesc%=MTHCA.DDInstall, PCI\VEN_15B3&DEV_6278 +%MT25218.DeviceDesc%=MTHCA.DDInstall, PCI\VEN_15B3&DEV_6282 +%MT24204.DeviceDesc%=MTHCA.DDInstall, PCI\VEN_15B3&DEV_5E8C +%MT25204.DeviceDesc%=MTHCA.DDInstall, PCI\VEN_15B3&DEV_6274 + +[MTHCA.DDInstall.ntx86] +CopyFiles = MTHCA.CopyFiles +CopyFiles = MTHCA.UMCopyFiles +CopyFiles = Ibal.UMCopyFiles +CopyFiles = Ibbus.CopyFiles +CopyFiles = WinVerbs.CopySysFiles +CopyFiles = WinVerbs.CopyDllFiles +CopyFiles = WinMad.CopySysFiles +CopyFiles = WinMad.CopyDllFiles + +[MTHCA.DDInstall.ntamd64] +CopyFiles = MTHCA.CopyFiles +CopyFiles = MTHCA.UMCopyFiles +CopyFiles = MTHCA.WOW64CopyFiles +CopyFiles = Ibal.UMCopyFiles +CopyFiles = Ibal.WOW64CopyFiles +CopyFiles = Ibbus.CopyFiles +CopyFiles = WinVerbs.CopySysFiles +CopyFiles = WinVerbs.CopyDllFiles +CopyFiles = WinMad.CopySysFiles +CopyFiles = WinMad.CopyDllFiles + +[MTHCA.DDInstall.ntia64] +CopyFiles = MTHCA.CopyFiles +CopyFiles = MTHCA.UMCopyFiles +CopyFiles = MTHCA.WOW64CopyFiles +CopyFiles = Ibal.UMCopyFiles +CopyFiles = Ibal.WOW64CopyFiles +CopyFiles = Ibbus.CopyFiles +CopyFiles = WinVerbs.CopySysFiles +CopyFiles = WinVerbs.CopyDllFiles +CopyFiles = WinMad.CopySysFiles +CopyFiles = WinMad.CopyDllFiles + + +; ============== Services ============== + +[MTHCA.DDInstall.ntx86.Services] +AddService = mthca,%SPSVCINST_ASSOCSERVICE%,MTHCA.ServiceInstall,MTHCA.EventLog +AddService = ibbus,,Ibbus.ServiceInstall,Ibbus.EventLog +AddService = WinVerbs,,WinVerbs.ServiceInstall +AddService = WinMad,,WinMad.ServiceInstall + +[MTHCA.DDInstall.ntamd64.Services] +AddService = mthca,%SPSVCINST_ASSOCSERVICE%,MTHCA.ServiceInstall,MTHCA.EventLog +AddService = ibbus,,Ibbus.ServiceInstall,Ibbus.EventLog +AddService = WinVerbs,,WinVerbs.ServiceInstall +AddService = WinMad,,WinMad.ServiceInstall + +[MTHCA.DDInstall.ntia64.Services] +AddService = mthca,%SPSVCINST_ASSOCSERVICE%,MTHCA.ServiceInstall,MTHCA.EventLog +AddService = ibbus,,Ibbus.ServiceInstall,Ibbus.EventLog +AddService = WinVerbs,,WinVerbs.ServiceInstall +AddService = WinMad,,WinMad.ServiceInstall + + +; ============= File Copy ============== + +[MTHCA.CopyFiles] +mthca.sys + +[MTHCA.UMCopyFiles] +mthcau.dll,,,2 +mthcaud.dll,,,2 + +[MTHCA.WOW64CopyFiles] +mthcau.dll,mthca32.dll,,2 +mthcaud.dll,mthca32d.dll,,2 + +[Ibal.UMCopyFiles] +ibal.dll,,,2 +ibald.dll,,,2 +complib.dll,,,2 +complibd.dll,,,2 + +[Ibal.WOW64CopyFiles] +ibal.dll,ibal32.dll,,2 +ibald.dll,ibal32d.dll,,2 +complib.dll,cl32.dll,,2 +complibd.dll,cl32d.dll,,2 + +[Ibbus.CopyFiles] +ibbus.sys + +[WinVerbs.CopySysFiles] +winverbs.sys + +[WinVerbs.CopyDllFiles] +winverbs.dll,,,2 +winverbsd.dll,,,2 + +[WinMad.CopySysFiles] +winmad.sys + +[WinMad.CopyDllFiles] +winmad.dll,,,2 +winmadd.dll,,,2 + +; ============= MTHCA Service Install section ============== + +[MTHCA.ServiceInstall] +DisplayName = %MTHCA.ServiceDesc% +ServiceType = %SERVICE_KERNEL_DRIVER% +StartType = %SERVICE_BOOT_START% +ErrorControl = %SERVICE_ERROR_NORMAL% +ServiceBinary = %12%\mthca.sys +LoadOrderGroup = extended base +AddReg = MTHCA.ParamsReg + + +[MTHCA.EventLog] +AddReg = MTHCA.AddEventLogReg + +[MTHCA.AddEventLogReg] +HKR, , EventMessageFile, 0x00020000, "%%SystemRoot%%\System32\IoLogMsg.dll;%%SystemRoot%%\System32\drivers\mthca.sys" +HKR, , TypesSupported, 0x00010001, 7 + +[MTHCA.ParamsReg] +HKR,"Parameters","DebugLevel",%REG_DWORD%,0x00000003 +HKR,"Parameters","DebugFlags",%REG_DWORD%,0x0000ffff +HKR,"Parameters","SkipTavorReset",%REG_DWORD%,0 +HKR,"Parameters","DisableTavorResetOnFailure",%REG_DWORD%,1 +HKR,"Parameters","TunePci",%REG_DWORD%,0 +HKR,"Parameters","ProcessorAffinity",%REG_DWORD%,0 +HKR,"Parameters","MaxDpcTimeUs",%REG_DWORD%,10000 +HKR,"Parameters","ProfileQpNum",%REG_DWORD%,0 +HKR,"Parameters","ProfileRdOut",%REG_DWORD%,0xffffffff +HKLM,"System\CurrentControlSet\Control\WMI\GlobalLogger\8bf1f640-63fe-4743-b9ef-fa38c695bfde","Flags",%REG_DWORD%,0xffff +HKLM,"System\CurrentControlSet\Control\WMI\GlobalLogger\8bf1f640-63fe-4743-b9ef-fa38c695bfde","Level",%REG_DWORD%,0x3 + + +; ============= IBBUS Service Install section ============== + +[Ibbus.ServiceInstall] +DisplayName = %Ibbus.ServiceDesc% +ServiceType = %SERVICE_KERNEL_DRIVER% +StartType = %SERVICE_BOOT_START% +ErrorControl = %SERVICE_ERROR_NORMAL% +ServiceBinary = %12%\ibbus.sys +LoadOrderGroup = PnP Filter +AddReg = Ibbus.ParamsReg +Dependencies = mthca + +[Ibbus.EventLog] +AddReg = Ibbus.AddEventLogReg + +[Ibbus.AddEventLogReg] +HKR, , EventMessageFile, 0x00020000, "%%SystemRoot%%\System32\IoLogMsg.dll;%%SystemRoot%%\System32\drivers\ibbus.sys" +HKR, , TypesSupported, 0x00010001, 7 + +[Ibbus.ParamsReg] +HKR,"Parameters","IbalDebugLevel",%REG_DWORD%,2 +HKR,"Parameters","IbalDebugFlags",%REG_DWORD%,0x00ffffff +HKR,"Parameters","SmiPollInterval",%REG_DWORD_NO_CLOBBER%,20000 +HKR,"Parameters","IocQueryTimeout",%REG_DWORD_NO_CLOBBER%,250 +HKR,"Parameters","IocQueryRetries",%REG_DWORD_NO_CLOBBER%,4 +HKR,"Parameters","IocPollInterval",%REG_DWORD_NO_CLOBBER%,30000 +HKR,"Parameters","DebugFlags",%REG_DWORD%,0x80000000 +HKR,"Parameters","ReportPortNIC",%REG_DWORD%,1 + +HKR,"Parameters","StaticChild",%REG_MULTI_SZ_NO_CLOBBER%,IPoIB +;use the following line to add your device +;HKR,"Parameters","StaticChild",%REG_MULTI_SZ_APPEND%,"XsigoBus" + +HKR,"Parameters\IPoIB","DeviceId",%REG_SZ%,"IBA\IPoIB" +HKR,"Parameters\IPoIB","CompatibleId",%REG_MULTI_SZ%,"IBA\SID_1000066a00020000" +HKR,"Parameters\IPoIB","HardwareId",%REG_MULTI_SZ%,"IBA\IPoIB" +HKR,"Parameters\IPoIB","Description",%REG_SZ%,"OpenIB IPoIB Adapter" +HKR,"Parameters\IPoIB","PartitionKey",%REG_SZ%,"FFFF" + +HKR,"Parameters\XsigoBus","DeviceId",%REG_SZ%,"IBA\XsigoBus" +HKR,"Parameters\XsigoBus","CompatibleId",%REG_MULTI_SZ%,"IBA\SID_0000000002139702" +HKR,"Parameters\XsigoBus","HardwareId",%REG_MULTI_SZ%,"IBA\XsigoBus" +HKR,"Parameters\XsigoBus","Description",%REG_SZ%,"Xsigo Virtual Bus" +HKR,"Parameters\XsigoBus","PartitionKey",%REG_SZ%,"FFFF" + +; ============= WinVerbs Service Install section ============== + +[WinVerbs.ServiceInstall] +DisplayName = %WinVerbs.ServiceDesc% +ServiceType = %SERVICE_KERNEL_DRIVER% +StartType = %SERVICE_BOOT_START% +ErrorControl = %SERVICE_ERROR_NORMAL% +ServiceBinary = %12%\winverbs.sys +LoadOrderGroup = PNP Filter +Dependencies = ibbus + +; ============= WinMad Service Install section ============== + +[WinMad.ServiceInstall] +DisplayName = %WinMad.ServiceDesc% +ServiceType = %SERVICE_KERNEL_DRIVER% +StartType = %SERVICE_BOOT_START% +ErrorControl = %SERVICE_ERROR_NORMAL% +ServiceBinary = %12%\winmad.sys +LoadOrderGroup = PNP Filter +Dependencies = winverbs + + +; ============= KMDF CoInstaller section ============== + +[MTHCA.DDInstall.ntx86.CoInstallers] +AddReg = Wdf_CoInstaller_AddReg +CopyFiles = Wdf_CoInstaller_CopyFiles + +[MTHCA.DDInstall.ntamd64.CoInstallers] +AddReg = Wdf_CoInstaller_AddReg +CopyFiles = Wdf_CoInstaller_CopyFiles + +[MTHCA.DDInstall.ntia64.CoInstallers] +AddReg = Wdf_CoInstaller_AddReg +CopyFiles = Wdf_CoInstaller_CopyFiles + +[Wdf_CoInstaller_AddReg] +HKR,, CoInstallers32,0x00010000, "WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll,WdfCoInstaller" + +[Wdf_CoInstaller_CopyFiles] +WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll + +[MTHCA.DDInstall.ntx86.Wdf] +KmdfService = WinVerbs, WvWdfSect +KmdfService = WinMad, WvWdfSect + +[MTHCA.DDInstall.ntamd64.Wdf] +KmdfService = WinVerbs, WvWdfSect +KmdfService = WinMad, WvWdfSect + +[MTHCA.DDInstall.ntia64.Wdf] +KmdfService = WinVerbs, WvWdfSect +KmdfService = WinMad, WvWdfSect + +[WvWdfSect] +KmdfLibraryVersion = $KMDFVERSION$ + + +; ============= Uninstall Section ============= + +[DefaultUninstall.ntx86] +DelFiles = MTHCA.CopyFiles +DelFiles = MTHCA.UMCopyFiles +DelReg = MTHCA.ParamsReg +DelReg = MTHCA.AddEventLogReg +DelReg = ClassAddReg +DelFiles = Ibal.UMCopyFiles +DelFiles = Ibbus.CopyFiles +DelReg = Ibbus.ParamsReg +DelFiles = WinVerbs.CopySysFiles +DelFiles = WinVerbs.CopyDllFiles +DelFiles = WinMad.CopySysFiles +DelFiles = WinMad.CopyDllFiles + +[DefaultUninstall.ntamd64] +DelFiles = MTHCA.CopyFiles +DelFiles = MTHCA.UMCopyFiles +DelFiles = MTHCA.WOW64CopyFiles +DelReg = MTHCA.ParamsReg +DelReg = MTHCA.AddEventLogReg +DelReg = ClassAddReg +DelFiles = Ibal.UMCopyFiles +DelFiles = Ibal.WOW64CopyFiles +DelFiles = Ibbus.CopyFiles +DelReg = Ibbus.ParamsReg +DelFiles = WinVerbs.CopySysFiles +DelFiles = WinVerbs.CopyDllFiles +DelFiles = WinMad.CopySysFiles +DelFiles = WinMad.CopyDllFiles + +[DefaultUninstall.ntia64] +DelFiles = MTHCA.CopyFiles +DelFiles = MTHCA.UMCopyFiles +DelFiles = MTHCA.WOW64CopyFiles +DelReg = MTHCA.ParamsReg +DelReg = MTHCA.AddEventLogReg +DelReg = ClassAddReg +DelFiles = Ibal.UMCopyFiles +DelFiles = Ibal.WOW64CopyFiles +DelFiles = Ibbus.CopyFiles +DelReg = Ibbus.ParamsReg +DelFiles = WinVerbs.CopySysFiles +DelFiles = WinVerbs.CopyDllFiles +DelFiles = WinMad.CopySysFiles +DelFiles = WinMad.CopyDllFiles + +[DefaultUninstall.Services] +DelService = WinMad,%SPSVCINST_STOPSERVICE% +DelService = WinVerbs,%SPSVCINST_STOPSERVICE% +DelService = Ibbus,%SPSVCINST_STOPSERVICE% +DelService = mthca,%SPSVCINST_STOPSERVICE% + + +[Strings] +IBClassGuid = "{58517E00-D3CF-40c9-A679-CEE5752F4491}" +OFA = "OpenFabrics Alliance" +MTL="Mellanox Technologies Ltd." +MTHCA.ServiceDesc = "Driver for Mellanox InfiniHost Devices" +MT23108.DeviceDesc="InfiniHost (MT23108) - Mellanox InfiniBand HCA" +MT25208.DeviceDesc="InfiniHost (MT25208) - Mellanox InfiniBand HCA for PCI Express" +MT25218.DeviceDesc="InfiniHost III Ex (MT25218) - Mellanox InfiniBand HCA for PCI Express" +MT24204.DeviceDesc="InfiniHost III Lx (MT24204) - Mellanox InfiniBand HCA for PCI Express" +MT25204.DeviceDesc="InfiniHost III Lx (MT25204) - Mellanox InfiniBand HCA for PCI Express" +DiskId = "Mellanox InfiniBand HCA installation disk" +Ibbus.ServiceDesc = "InfiniBand Bus/AL (Filter Driver)" +WinVerbs.ServiceDesc = "WinVerbs Service" +WinMad.ServiceDesc = "WinMad Service" +SPSVCINST_NULL = 0x0 +SPSVCINST_ASSOCSERVICE = 0x00000002 +SPSVCINST_STOPSERVICE = 0x00000200 +SERVICE_KERNEL_DRIVER = 1 +SERVICE_BOOT_START = 0 +SERVICE_DEMAND_START = 3 +SERVICE_ERROR_NORMAL = 1 +REG_DWORD = 0x00010001 +REG_DWORD_NO_CLOBBER = 0x00010003 +REG_MULTI_SZ = 0x00010000 +REG_MULTI_SZ_NO_CLOBBER = 0x00010002 +REG_MULTI_SZ_APPEND = 0x00010008 +DIRID_SYSTEM = 11 +DIRID_DRIVERS = 12 +DIRID_SYSTEM_X86 = 16425 + diff --git a/branches/WOF2-3/hw/mthca/kernel/mthca32.cdf b/branches/WOF2-3/hw/mthca/kernel/mthca32.cdf new file mode 100644 index 00000000..4fc455ea --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/mthca32.cdf @@ -0,0 +1,22 @@ +[CatalogHeader] +Name=mthca.cat +PublicVersion=0x0000001 +EncodingType=0x00010001 +CATATTR1=0x10010001:OSAttr:2:6.0 +[CatalogFiles] +mthca.inf=mthca.inf +mthca.sys=mthca.sys +mthcau.dll=mthcau.dll +mthcaud.dll=mthcaud.dll +ibal.dll=ibal.dll +ibald.dll=ibald.dll +complib.dll=complib.dll +complibd.dll=complibd.dll +ibbus.sys=ibbus.sys +winverbs.sys=winverbs.sys +winverbs.dll=winverbs.dll +winverbsd.dll=winverbsd.dll +winmad.sys=winmad.sys +winmad.dll=winmad.dll +winmadd.dll=winmadd.dll +WdfCoInstaller01007.dll=WdfCoInstaller01007.dll diff --git a/branches/WOF2-3/hw/mthca/kernel/mthca_allocator.c b/branches/WOF2-3/hw/mthca/kernel/mthca_allocator.c new file mode 100644 index 00000000..28dd974f --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/mthca_allocator.c @@ -0,0 +1,294 @@ +/* + * Copyright (c) 2004 Topspin Communications. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include "mthca_dev.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "mthca_allocator.tmh" +#endif + +/* Trivial bitmap-based allocator */ +u32 mthca_alloc(struct mthca_alloc *alloc) +{ + u32 obj; + SPIN_LOCK_PREP(lh); + + spin_lock(&alloc->lock, &lh); + obj = find_next_zero_bit(alloc->table, alloc->max, alloc->last); + if (obj >= alloc->max) { + alloc->top = (alloc->top + alloc->max) & alloc->mask; + obj = find_first_zero_bit(alloc->table, alloc->max); + } + + if (obj < alloc->max) { + set_bit(obj, (long*)alloc->table); + obj |= alloc->top; + } else + obj = (u32)-1; + + spin_unlock(&lh); + + return obj; +} + +void mthca_free(struct mthca_alloc *alloc, u32 obj) +{ + SPIN_LOCK_PREP(lh); + + obj &= alloc->max - 1; + spin_lock(&alloc->lock, &lh); + clear_bit(obj, (long *)alloc->table); + alloc->last = MIN(alloc->last, obj); + alloc->top = (alloc->top + alloc->max) & alloc->mask; + spin_unlock(&lh); +} + +int mthca_alloc_init(struct mthca_alloc *alloc, u32 num, u32 mask, + u32 reserved) +{ + int i; + HCA_ENTER(HCA_DBG_INIT); + /* num must be a power of 2 */ + if ((int)num != 1 << (ffs(num) - 1)) + return -EINVAL; + + alloc->last = 0; + alloc->top = 0; + alloc->max = num; + alloc->mask = mask; + spin_lock_init(&alloc->lock); + alloc->table = kmalloc(BITS_TO_LONGS(num) * sizeof (long), + GFP_KERNEL); + if (!alloc->table) + return -ENOMEM; + + bitmap_zero(alloc->table, num); + for (i = 0; i < (int)reserved; ++i) + set_bit(i, (long *)alloc->table); + + return 0; +} + +void mthca_alloc_cleanup(struct mthca_alloc *alloc) +{ + kfree(alloc->table); +} + +/* + * Array of pointers with lazy allocation of leaf pages. Callers of + * _get, _set and _clear methods must use a lock or otherwise + * serialize access to the array. + */ + +#define MTHCA_ARRAY_MASK (PAGE_SIZE / sizeof (void *) - 1) + +void *mthca_array_get(struct mthca_array *array, int index) +{ + int p = (index * sizeof (void *)) >> PAGE_SHIFT; + + if (array->page_list[p].page) + return array->page_list[p].page[index & MTHCA_ARRAY_MASK]; + else + return NULL; +} + +int mthca_array_set(struct mthca_array *array, int index, void *value) +{ + int p = (index * sizeof (void *)) >> PAGE_SHIFT; + + /* Allocate with GFP_ATOMIC because we'll be called with locks held. */ + if (!array->page_list[p].page) + array->page_list[p].page = (void **) get_zeroed_page(GFP_ATOMIC); + + if (!array->page_list[p].page) + return -ENOMEM; + + array->page_list[p].page[index & MTHCA_ARRAY_MASK] = value; + ++array->page_list[p].used; + + return 0; +} + +void mthca_array_clear(struct mthca_array *array, int index) +{ + int p = (index * sizeof (void *)) >> PAGE_SHIFT; + + if (array->page_list[p].used <= 0) { + HCA_PRINT(TRACE_LEVEL_INFORMATION, HCA_DBG_LOW,("Array %p index %d page %d with ref count %d < 0\n", + array, index, p, array->page_list[p].used)); + return; + } + + if (--array->page_list[p].used == 0) { + free_page((void*) array->page_list[p].page); + array->page_list[p].page = NULL; + } + else + array->page_list[p].page[index & MTHCA_ARRAY_MASK] = NULL; +} + +int mthca_array_init(struct mthca_array *array, int nent) +{ + int npage = (nent * sizeof (void *) + PAGE_SIZE - 1) / PAGE_SIZE; + int i; + + array->page_list = kmalloc(npage * sizeof *array->page_list, GFP_KERNEL); + if (!array->page_list) + return -ENOMEM; + + for (i = 0; i < npage; ++i) { + array->page_list[i].page = NULL; + array->page_list[i].used = 0; + } + + return 0; +} + +void mthca_array_cleanup(struct mthca_array *array, int nent) +{ + int i; + + for (i = 0; i < (int)((nent * sizeof (void *) + PAGE_SIZE - 1) / PAGE_SIZE); ++i) + free_page((void*) array->page_list[i].page); + + kfree(array->page_list); +} + +/* + * Handling for queue buffers -- we allocate a bunch of memory and + * register it in a memory region at HCA virtual address 0. If the + * requested size is > max_direct, we split the allocation into + * multiple pages, so we don't require too much contiguous memory. + */ + +int mthca_buf_alloc(struct mthca_dev *dev, int size, int max_direct, + union mthca_buf *buf, int *is_direct, struct mthca_pd *pd, + int hca_write, struct mthca_mr *mr) +{ + int err = -ENOMEM; + int npages, shift; + u64 *dma_list = NULL; + dma_addr_t t; + int i; + + HCA_ENTER(HCA_DBG_MEMORY); + if (size <= max_direct) { + *is_direct = 1; + npages = 1; + shift = get_order(size) + PAGE_SHIFT; + + alloc_dma_zmem_map(dev, size, PCI_DMA_BIDIRECTIONAL, &buf->direct); + if (!buf->direct.page) + return -ENOMEM; + t = buf->direct.dma_address; /* shorten the code below */ + + while (t & ((1 << shift) - 1)) { + --shift; + npages *= 2; + } + + dma_list = kmalloc(npages * sizeof *dma_list, GFP_KERNEL); + if (!dma_list) + goto err_free; + + for (i = 0; i < npages; ++i) + dma_list[i] = t + i * (1 << shift); + } else { + *is_direct = 0; + npages = (size + PAGE_SIZE - 1) / PAGE_SIZE; + shift = PAGE_SHIFT; + + dma_list = kmalloc(npages * sizeof *dma_list, GFP_KERNEL); + if (!dma_list) + return -ENOMEM; + + buf->page_list = kmalloc(npages * sizeof *buf->page_list, + GFP_KERNEL); + if (!buf->page_list) + goto err_out; + + for (i = 0; i < npages; ++i) + buf->page_list[i].page = NULL; + + for (i = 0; i < npages; ++i) { + alloc_dma_zmem_map(dev, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL, &buf->page_list[i]); + if (!buf->page_list[i].page) + goto err_free; + dma_list[i] = buf->page_list[i].dma_address; + } + } + + err = mthca_mr_alloc_phys(dev, pd->pd_num, + dma_list, shift, npages, + 0, size, + MTHCA_MPT_FLAG_LOCAL_READ | + (hca_write ? MTHCA_MPT_FLAG_LOCAL_WRITE : 0), + mr); + if (err) + goto err_free; + + kfree(dma_list); + + HCA_EXIT(HCA_DBG_MEMORY); + return 0; + +err_free: + mthca_buf_free(dev, size, buf, *is_direct, NULL); + +err_out: + kfree(dma_list); + + return err; +} + +void mthca_buf_free(struct mthca_dev *dev, int size, union mthca_buf *buf, + int is_direct, struct mthca_mr *mr) +{ + int i; + + if (mr) + mthca_free_mr(dev, mr); + + if (is_direct) { + free_dma_mem_map(dev, &buf->direct, PCI_DMA_BIDIRECTIONAL); + } + else { + for (i = 0; i < (size + PAGE_SIZE - 1) / PAGE_SIZE; ++i) { + free_dma_mem_map(dev, &buf->page_list[i], PCI_DMA_BIDIRECTIONAL); + } + kfree(buf->page_list); + } +} diff --git a/branches/WOF2-3/hw/mthca/kernel/mthca_av.c b/branches/WOF2-3/hw/mthca/kernel/mthca_av.c new file mode 100644 index 00000000..9d266fee --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/mthca_av.c @@ -0,0 +1,293 @@ +/* + * Copyright (c) 2004 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include +#include +#include "mthca_dev.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "mthca_av.tmh" +#endif + + +struct mthca_av { + __be32 port_pd; + u8 reserved1; + u8 g_slid; + __be16 dlid; + u8 reserved2; + u8 gid_index; + u8 msg_sr; + u8 hop_limit; + __be32 sl_tclass_flowlabel; + __be32 dgid[4]; +}; + +int mthca_create_ah(struct mthca_dev *dev, + struct mthca_pd *pd, + struct ib_ah_attr *ah_attr, + struct mthca_ah *ah) +{ + u32 index = (u32)-1; + struct mthca_av *av = NULL; + + ah->type = MTHCA_AH_PCI_POOL; + + if (mthca_is_memfree(dev)) { + ah->av = kmalloc(sizeof *ah->av, GFP_ATOMIC); + if (!ah->av) + return -ENOMEM; + + ah->type = MTHCA_AH_KMALLOC; + av = ah->av; + } else if (!atomic_read(&pd->sqp_count) && + !(dev->mthca_flags & MTHCA_FLAG_DDR_HIDDEN)) { + index = mthca_alloc(&dev->av_table.alloc); + + /* fall back to allocate in host memory */ + if (index == -1) + goto on_hca_fail; + + av = kmalloc(sizeof *av, GFP_ATOMIC); + if (!av) + goto on_hca_fail; + + ah->type = MTHCA_AH_ON_HCA; + ah->avdma = dev->av_table.ddr_av_base + + index * MTHCA_AV_SIZE; + } + +on_hca_fail: + if (ah->type == MTHCA_AH_PCI_POOL) { + ah->av = pci_pool_alloc(dev->av_table.pool, + SLAB_ATOMIC, &ah->avdma); + if (!ah->av) + return -ENOMEM; + + av = ah->av; + } + + ah->key = pd->ntmr.ibmr.lkey; + + RtlZeroMemory(av, MTHCA_AV_SIZE); + + av->port_pd = cl_hton32(pd->pd_num | (ah_attr->port_num << 24)); + av->g_slid = ah_attr->src_path_bits; + av->dlid = cl_hton16(ah_attr->dlid); + av->msg_sr = (3 << 4) | /* 2K message */ + ah_attr->static_rate; + av->sl_tclass_flowlabel = cl_hton32(ah_attr->sl << 28); + if (ah_attr->ah_flags & IB_AH_GRH) { + av->g_slid |= 0x80; + av->gid_index = (u8)((ah_attr->port_num - 1) * dev->limits.gid_table_len + + ah_attr->grh.sgid_index); + av->hop_limit = ah_attr->grh.hop_limit; + av->sl_tclass_flowlabel |= + cl_hton32((ah_attr->grh.traffic_class << 20) | + ah_attr->grh.flow_label); + memcpy(av->dgid, ah_attr->grh.dgid.raw, 16); + } else { + /* Arbel workaround -- low byte of GID must be 2 */ + av->dgid[3] = cl_hton32(2); + } + + { // debug print + int j; + + HCA_PRINT(TRACE_LEVEL_VERBOSE,HCA_DBG_LOW,("Created UDAV at %p/%08lx:\n", + av, (unsigned long) ah->avdma)); + for (j = 0; j < 8; ++j) + HCA_PRINT(TRACE_LEVEL_VERBOSE ,HCA_DBG_AV ,(" [%2x] %08x\n", + j * 4, cl_ntoh32(((__be32 *) av)[j]))); + } + + if (ah->type == MTHCA_AH_ON_HCA) { + memcpy_toio((u8*)dev->av_table.av_map + index * MTHCA_AV_SIZE, + av, MTHCA_AV_SIZE); + ah->av = (struct mthca_av *)( (u8*)( dev->av_table.av_map) + index *MTHCA_AV_SIZE ); + kfree(av); + } + return 0; +} + +int mthca_destroy_ah(struct mthca_dev *dev, struct mthca_ah *ah) +{ + HCA_ENTER(HCA_DBG_AV); + + switch (ah->type) { + case MTHCA_AH_ON_HCA: + mthca_free(&dev->av_table.alloc, + (u32)( (ah->avdma - dev->av_table.ddr_av_base) /MTHCA_AV_SIZE)); + break; + + case MTHCA_AH_PCI_POOL: + pci_pool_free(dev->av_table.pool, ah->av, ah->avdma); + break; + + case MTHCA_AH_KMALLOC: + kfree(ah->av); + break; + } + + HCA_EXIT(HCA_DBG_AV); + return 0; +} + +int mthca_ah_grh_present(struct mthca_ah *ah) +{ + return !!(ah->av->g_slid & 0x80); +} + +int mthca_read_ah(struct mthca_dev *dev, struct mthca_ah *ah, + struct ib_ud_header *header) +{ + if (ah->type == MTHCA_AH_ON_HCA) + return -ENOSYS; + + header->lrh.service_level = (u8)(cl_ntoh32(ah->av->sl_tclass_flowlabel) >> 28); + header->lrh.destination_lid = ah->av->dlid; + header->lrh.source_lid = cl_hton16(ah->av->g_slid & 0x7f); + header->grh_present = mthca_ah_grh_present(ah); + if (header->grh_present) { + header->grh.traffic_class = + (u8)((cl_ntoh32(ah->av->sl_tclass_flowlabel) >> 20) & 0xff); + header->grh.flow_label = + (u8)(ah->av->sl_tclass_flowlabel & cl_hton32(0xfffff)); + ib_get_cached_gid(&dev->ib_dev, + (u8) (cl_ntoh32(ah->av->port_pd) >> 24), + ah->av->gid_index % dev->limits.gid_table_len, + &header->grh.source_gid); + memcpy(header->grh.destination_gid.raw, + ah->av->dgid, 16); + } + + return 0; +} + +int mthca_init_av_table(struct mthca_dev *dev) +{ + int err; + + if (mthca_is_memfree(dev)) + return 0; + + err = mthca_alloc_init(&dev->av_table.alloc, + dev->av_table.num_ddr_avs, + dev->av_table.num_ddr_avs - 1, + 0); + if (err) + return err; + + dev->av_table.pool = pci_pool_create("mthca_av", dev, + MTHCA_AV_SIZE, + MTHCA_AV_SIZE, 0); + if (!dev->av_table.pool) + goto out_free_alloc; + + if (!(dev->mthca_flags & MTHCA_FLAG_DDR_HIDDEN)) { + dev->av_table.av_map = ioremap(pci_resource_start(dev, HCA_BAR_TYPE_DDR) + + dev->av_table.ddr_av_base - + dev->ddr_start, + dev->av_table.num_ddr_avs * + MTHCA_AV_SIZE, + &dev->av_table.av_map_size); + if (!dev->av_table.av_map) + goto out_free_pool; + } else + dev->av_table.av_map = NULL; + + return 0; + + out_free_pool: + pci_pool_destroy(dev->av_table.pool); + + out_free_alloc: + mthca_alloc_cleanup(&dev->av_table.alloc); + return -ENOMEM; +} + +void mthca_cleanup_av_table(struct mthca_dev *dev) +{ + if (mthca_is_memfree(dev)) + return; + + if (dev->av_table.av_map) + iounmap(dev->av_table.av_map, dev->av_table.av_map_size); + pci_pool_destroy(dev->av_table.pool); + mthca_alloc_cleanup(&dev->av_table.alloc); +} + +//NB: temporary, for support of query_qp +void mthca_get_av_params( struct mthca_ah *ah_p, u8 *port_num, __be16 *dlid, u8 *sr, u8 *path_bits ) +{ + struct mthca_av *av_p = ah_p->av; + *port_num = (u8) (cl_ntoh32(av_p->port_pd) >> 24); + *dlid = av_p->dlid; + *sr = av_p->msg_sr & 0x0f; + *path_bits = av_p->g_slid & 0x7f; +} + +//NB: temporary, for support of modify_qp +void mthca_set_av_params( struct mthca_dev *dev, struct mthca_ah *ah_p, struct ib_ah_attr *ah_attr ) +{ + struct mthca_av *av = ah_p->av; + struct ib_ah *ib_ah_p = (struct ib_ah *)ah_p; + struct mthca_pd *pd = (struct mthca_pd *)ib_ah_p->pd; + + // taken from mthca_create_av + av->port_pd = cl_hton32(pd->pd_num | (ah_attr->port_num << 24)); + av->g_slid = ah_attr->src_path_bits; + av->dlid = cl_hton16(ah_attr->dlid); + av->msg_sr = (3 << 4) | /* 2K message */ + ah_attr->static_rate; + av->sl_tclass_flowlabel = cl_hton32(ah_attr->sl << 28); + if (ah_attr->ah_flags & IB_AH_GRH) { + av->g_slid |= 0x80; + av->gid_index = (u8)((ah_attr->port_num - 1) * dev->limits.gid_table_len + + ah_attr->grh.sgid_index); + av->hop_limit = ah_attr->grh.hop_limit; + av->sl_tclass_flowlabel |= + cl_hton32((ah_attr->grh.traffic_class << 20) | + ah_attr->grh.flow_label); + memcpy(av->dgid, ah_attr->grh.dgid.raw, 16); + } else { + /* Arbel workaround -- low byte of GID must be 2 */ + av->dgid[3] = cl_hton32(2); + } +} + + diff --git a/branches/WOF2-3/hw/mthca/kernel/mthca_catas.c b/branches/WOF2-3/hw/mthca/kernel/mthca_catas.c new file mode 100644 index 00000000..0c91518f --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/mthca_catas.c @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2005 Cisco Systems. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include "mthca_dev.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "mthca_catas.tmh" +#endif + +enum { + MTHCA_CATAS_POLL_INTERVAL = 5 * HZ, + + MTHCA_CATAS_TYPE_INTERNAL = 0, + MTHCA_CATAS_TYPE_UPLINK = 3, + MTHCA_CATAS_TYPE_DDR = 4, + MTHCA_CATAS_TYPE_PARITY = 5, +}; + +static spinlock_t catas_lock; + +static void handle_catas(struct mthca_dev *dev) +{ + struct ib_event event; + const char *type; + int i; + + event.device = &dev->ib_dev; + event.event = IB_EVENT_DEVICE_FATAL; + event.element.port_num = 0; + + ib_dispatch_event(&event); + + switch (_byteswap_ulong(readl(dev->catas_err.map)) >> 24) { + case MTHCA_CATAS_TYPE_INTERNAL: + type = "internal error"; + break; + case MTHCA_CATAS_TYPE_UPLINK: + type = "uplink bus error"; + break; + case MTHCA_CATAS_TYPE_DDR: + type = "DDR data error"; + break; + case MTHCA_CATAS_TYPE_PARITY: + type = "internal parity error"; + break; + default: + type = "unknown error"; + break; + } + + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Catastrophic error detected: %s\n", type)); + for (i = 0; i < (int)dev->catas_err.size; ++i) + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_LOW,(" buf[%02x]: %08x\n", + i, _byteswap_ulong(readl(dev->catas_err.map + i)))); +} + +static void poll_catas(struct mthca_dev *dev) +{ + int i; + SPIN_LOCK_PREP(lh); + + for (i = 0; i < (int)dev->catas_err.size; ++i) + if (readl(dev->catas_err.map + i)) { + handle_catas(dev); + return; + } + + spin_lock_dpc(&catas_lock, &lh); + if (!dev->catas_err.stop) { + KeSetTimerEx( &dev->catas_err.timer, dev->catas_err.interval, + 0, &dev->catas_err.timer_dpc ); + } + spin_unlock_dpc(&lh); + + return; +} + +static void timer_dpc( + IN struct _KDPC *Dpc, + IN PVOID DeferredContext, + IN PVOID SystemArgument1, + IN PVOID SystemArgument2 + ) +{ + struct mthca_dev *dev = (struct mthca_dev *)DeferredContext; + UNREFERENCED_PARAMETER(Dpc); + UNREFERENCED_PARAMETER(SystemArgument1); + UNREFERENCED_PARAMETER(SystemArgument2); + poll_catas( dev ); +} + + +void mthca_start_catas_poll(struct mthca_dev *dev) +{ + u64 addr; + + dev->catas_err.stop = 0; + dev->catas_err.map = NULL; + + addr = pci_resource_start(dev, HCA_BAR_TYPE_HCR) + + ((pci_resource_len(dev, HCA_BAR_TYPE_HCR) - 1) & + dev->catas_err.addr); + + dev->catas_err.map = ioremap(addr, dev->catas_err.size * 4, &dev->catas_err.map_size ); + if (!dev->catas_err.map) { + HCA_PRINT(TRACE_LEVEL_WARNING,HCA_DBG_LOW, ("couldn't map catastrophic error region " + "at 0x%I64x/0x%x\n", addr, dev->catas_err.size * 4)); + return; + } + + spin_lock_init( &catas_lock ); + KeInitializeDpc( &dev->catas_err.timer_dpc, timer_dpc, dev ); + KeInitializeTimer( &dev->catas_err.timer ); + dev->catas_err.interval.QuadPart = (-10)* (__int64)MTHCA_CATAS_POLL_INTERVAL; + KeSetTimerEx( &dev->catas_err.timer, dev->catas_err.interval, + 0, &dev->catas_err.timer_dpc ); +} + +void mthca_stop_catas_poll(struct mthca_dev *dev) +{ + SPIN_LOCK_PREP(lh); + + spin_lock_irq(&catas_lock, &lh); + dev->catas_err.stop = 1; + spin_unlock_irq(&lh); + + KeCancelTimer(&dev->catas_err.timer); + KeFlushQueuedDpcs(); + + if (dev->catas_err.map) { + iounmap(dev->catas_err.map, dev->catas_err.map_size); + } +} diff --git a/branches/WOF2-3/hw/mthca/kernel/mthca_cmd.c b/branches/WOF2-3/hw/mthca/kernel/mthca_cmd.c new file mode 100644 index 00000000..e3483f7c --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/mthca_cmd.c @@ -0,0 +1,1844 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include + +#include "mthca_dev.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "mthca_cmd.tmh" +#endif +#include "mthca_config_reg.h" +#include "mthca_cmd.h" +#include "mthca_memfree.h" + +#define CMD_POLL_TOKEN 0xffff + +enum { + HCR_IN_PARAM_OFFSET = 0x00, + HCR_IN_MODIFIER_OFFSET = 0x08, + HCR_OUT_PARAM_OFFSET = 0x0c, + HCR_TOKEN_OFFSET = 0x14, + HCR_STATUS_OFFSET = 0x18, + + HCR_OPMOD_SHIFT = 12, + HCA_E_BIT = 22, + HCR_GO_BIT = 23 +}; + +enum { + /* initialization and general commands */ + CMD_SYS_EN = 0x1, + CMD_SYS_DIS = 0x2, + CMD_MAP_FA = 0xfff, + CMD_UNMAP_FA = 0xffe, + CMD_RUN_FW = 0xff6, + CMD_MOD_STAT_CFG = 0x34, + CMD_QUERY_DEV_LIM = 0x3, + CMD_QUERY_FW = 0x4, + CMD_ENABLE_LAM = 0xff8, + CMD_DISABLE_LAM = 0xff7, + CMD_QUERY_DDR = 0x5, + CMD_QUERY_ADAPTER = 0x6, + CMD_INIT_HCA = 0x7, + CMD_CLOSE_HCA = 0x8, + CMD_INIT_IB = 0x9, + CMD_CLOSE_IB = 0xa, + CMD_QUERY_HCA = 0xb, + CMD_SET_IB = 0xc, + CMD_ACCESS_DDR = 0x2e, + CMD_MAP_ICM = 0xffa, + CMD_UNMAP_ICM = 0xff9, + CMD_MAP_ICM_AUX = 0xffc, + CMD_UNMAP_ICM_AUX = 0xffb, + CMD_SET_ICM_SIZE = 0xffd, + + /* TPT commands */ + CMD_SW2HW_MPT = 0xd, + CMD_QUERY_MPT = 0xe, + CMD_HW2SW_MPT = 0xf, + CMD_READ_MTT = 0x10, + CMD_WRITE_MTT = 0x11, + CMD_SYNC_TPT = 0x2f, + + /* EQ commands */ + CMD_MAP_EQ = 0x12, + CMD_SW2HW_EQ = 0x13, + CMD_HW2SW_EQ = 0x14, + CMD_QUERY_EQ = 0x15, + + /* CQ commands */ + CMD_SW2HW_CQ = 0x16, + CMD_HW2SW_CQ = 0x17, + CMD_QUERY_CQ = 0x18, + CMD_RESIZE_CQ = 0x2c, + + /* SRQ commands */ + CMD_SW2HW_SRQ = 0x35, + CMD_HW2SW_SRQ = 0x36, + CMD_QUERY_SRQ = 0x37, + CMD_ARM_SRQ = 0x40, + + /* QP/EE commands */ + CMD_RST2INIT_QPEE = 0x19, + CMD_INIT2RTR_QPEE = 0x1a, + CMD_RTR2RTS_QPEE = 0x1b, + CMD_RTS2RTS_QPEE = 0x1c, + CMD_SQERR2RTS_QPEE = 0x1d, + CMD_2ERR_QPEE = 0x1e, + CMD_RTS2SQD_QPEE = 0x1f, + CMD_SQD2SQD_QPEE = 0x38, + CMD_SQD2RTS_QPEE = 0x20, + CMD_ERR2RST_QPEE = 0x21, + CMD_QUERY_QPEE = 0x22, + CMD_INIT2INIT_QPEE = 0x2d, + CMD_SUSPEND_QPEE = 0x32, + CMD_UNSUSPEND_QPEE = 0x33, + /* special QPs and management commands */ + CMD_CONF_SPECIAL_QP = 0x23, + CMD_MAD_IFC = 0x24, + + /* multicast commands */ + CMD_READ_MGM = 0x25, + CMD_WRITE_MGM = 0x26, + CMD_MGID_HASH = 0x27, + + /* miscellaneous commands */ + CMD_DIAG_RPRT = 0x30, + CMD_NOP = 0x31, + + /* debug commands */ + CMD_QUERY_DEBUG_MSG = 0x2a, + CMD_SET_DEBUG_MSG = 0x2b, +}; + +/* + * According to Mellanox code, FW may be starved and never complete + * commands. So we can't use strict timeouts described in PRM -- we + * just arbitrarily select 60 seconds for now. + */ +#define CMD_POLL_N_TRIES 60 + +enum { + CMD_TIME_CLASS_A = 60 * HZ, + CMD_TIME_CLASS_B = 60 * HZ, + CMD_TIME_CLASS_C = 60 * HZ +}; + +enum { + GO_BIT_TIMEOUT = 10 * HZ +}; + +#define GO_BIT_N_TRIES 5 +#define GO_BIT_STALL_TIMEOUT ((GO_BIT_TIMEOUT/HZ)/GO_BIT_N_TRIES) /* usecs */ + +struct mthca_cmd_context { + KEVENT event; + int result; + int next; + u64 out_param; + u16 token; + u8 status; +}; + +static inline int go_bit(struct mthca_dev *dev) +{ + return readl(dev->hcr + HCR_STATUS_OFFSET) & + _byteswap_ulong(1 << HCR_GO_BIT); +} + +/* +* Function: performs busy-wait loop, while polling GO bit +* Return: 0 when GO bit was extinguished in time +*/ +static int poll_go_bit(struct mthca_dev *dev) +{ + int i=0; /* init must be here !*/ + + if (!go_bit(dev)) + return 0; + + for (; i= N_POLL_TRIES) { + if ( (__int64)interval.QuadPart > (__int64)MAX_POLL_INTERVAL) + interval.QuadPart += POLL_INTERVAL_DELTA; + i = 0; + } +#endif + } + + if (!go_bit(dev)) return 0; + return 1; +} + + +static int mthca_cmd_post(struct mthca_dev *dev, + u64 in_param, + u64 out_param, + u32 in_modifier, + u8 op_modifier, + u16 op, + u16 token, + int event) +{ + int err = 0; + + down(&dev->cmd.hcr_mutex); + + if (event) + if (wait_go_bit(dev,GO_BIT_TIMEOUT)) { + err = -EAGAIN; + goto out; + } + else + if (go_bit(dev)) { + err = -EAGAIN; + goto out; + } + + /* + * We use writel (instead of something like memcpy_toio) + * because writes of less than 32 bits to the HCR don't work + * (and some architectures such as ia64 implement memcpy_toio + * in terms of writeb). + */ + __raw_writel((u32) cl_hton32((u32)(in_param >> 32)), (u8 *)dev->hcr + 0 * 4); + __raw_writel((u32) cl_hton32((u32)(in_param & 0xfffffffful)), (u8 *) dev->hcr + 1 * 4); + __raw_writel((u32) cl_hton32(in_modifier), (u8 *)dev->hcr + 2 * 4); + __raw_writel((u32) cl_hton32((u32)(out_param >> 32)), (u8 *)dev->hcr + 3 * 4); + __raw_writel((u32) cl_hton32((u32)(out_param & 0xfffffffful)), (u8 *)dev->hcr + 4 * 4); + __raw_writel((u32) cl_hton32(token << 16), (u8 *)dev->hcr + 5 * 4); + + /* __raw_writel may not order writes. */ + wmb(); + + __raw_writel((u32) cl_hton32((1 << HCR_GO_BIT) | + (event ? (1 << HCA_E_BIT) : 0) | + (op_modifier << HCR_OPMOD_SHIFT) | + op), (u8 *)dev->hcr + 6 * 4); + +out: + up(&dev->cmd.hcr_mutex); + return err; +} + + +static int mthca_cmd_poll(struct mthca_dev *dev, + u64 in_param, + u64 *out_param, + int out_is_imm, + u32 in_modifier, + u8 op_modifier, + u16 op, + unsigned long timeout, + u8 *status) +{ + int err = 0; + + sem_down(&dev->cmd.poll_sem); + + err = mthca_cmd_post(dev, in_param, + out_param ? *out_param : 0, + in_modifier, op_modifier, + op, CMD_POLL_TOKEN, 0); + if (err) + goto out; + + if (wait_go_bit(dev,timeout)) { + err = -EBUSY; + goto out; + } + + if (out_is_imm) + *out_param = + (u64) cl_ntoh32((__be32) + __raw_readl(dev->hcr + HCR_OUT_PARAM_OFFSET)) << 32 | + (u64) cl_ntoh32((__be32) + __raw_readl(dev->hcr + HCR_OUT_PARAM_OFFSET + 4)); + + *status = (u8)(cl_ntoh32((__be32) __raw_readl(dev->hcr + HCR_STATUS_OFFSET)) >> 24); + if (*status) + HCA_PRINT(TRACE_LEVEL_VERBOSE,HCA_DBG_LOW,("mthca_cmd_wait: Command %02x completed with status %02x\n", + op, *status)); + +out: + sem_up(&dev->cmd.poll_sem); + return err; +} + +void mthca_cmd_event(struct mthca_dev *dev, + u16 token, + u8 status, + u64 out_param) +{ + struct mthca_cmd_context *context = + &dev->cmd.context[token & dev->cmd.token_mask]; + + /* previously timed out command completing at long last */ + if (token != context->token) + return; + + context->result = 0; + context->status = status; + context->out_param = out_param; + + context->token += dev->cmd.token_mask + 1; + + ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); + KeSetEvent( &context->event, 0, FALSE ); +} + +static int mthca_cmd_wait(struct mthca_dev *dev, + u64 in_param, + u64 *out_param, + int out_is_imm, + u32 in_modifier, + u8 op_modifier, + u16 op, + unsigned long timeout, + u8 *status) +{ + int err = 0; + struct mthca_cmd_context *context; + SPIN_LOCK_PREP(lh); + + sem_down(&dev->cmd.event_sem); + + spin_lock( &dev->cmd.context_lock, &lh ); + BUG_ON(dev->cmd.free_head < 0); + context = &dev->cmd.context[dev->cmd.free_head]; + dev->cmd.free_head = context->next; + spin_unlock( &lh ); + + KeClearEvent( &context->event ); + err = mthca_cmd_post(dev, in_param, + out_param ? *out_param : 0, + in_modifier, op_modifier, + op, context->token, 1); + if (err) { + HCA_PRINT(TRACE_LEVEL_INFORMATION,HCA_DBG_LOW, + ("mthca_cmd_wait: Command %02x completed with err %02x\n", op, err)); + goto out; + } + + { + NTSTATUS res; + LARGE_INTEGER interval; + interval.QuadPart = (-10)* (__int64)timeout; + res = KeWaitForSingleObject( &context->event, Executive, KernelMode, FALSE, &interval ); + if (res != STATUS_SUCCESS) { + err = -EBUSY; + HCA_PRINT(TRACE_LEVEL_INFORMATION,HCA_DBG_LOW, + ("mthca_cmd_wait: Command %02x completed with err %02x\n", op, err)); + goto out; + } + } + + *status = context->status; + if (*status) + HCA_PRINT(TRACE_LEVEL_INFORMATION,HCA_DBG_LOW,("mthca_cmd_wait: Command %02x completed with status %02x\n", + op, *status)); + + if (out_is_imm) + *out_param = context->out_param; + +out: + spin_lock(&dev->cmd.context_lock, &lh); + context->next = dev->cmd.free_head; + dev->cmd.free_head = (int)(context - dev->cmd.context); + spin_unlock(&lh); + + sem_up( &dev->cmd.event_sem ); + + return err; +} + +/* Invoke a command with an output mailbox */ +static int mthca_cmd_box(struct mthca_dev *dev, + u64 in_param, + u64 out_param, + u32 in_modifier, + u8 op_modifier, + u16 op, + unsigned long timeout, + u8 *status) +{ + if (dev->cmd.use_events) + return mthca_cmd_wait(dev, in_param, &out_param, 0, + in_modifier, op_modifier, op, + timeout, status); + else + return mthca_cmd_poll(dev, in_param, &out_param, 0, + in_modifier, op_modifier, op, + timeout, status); +} + +/* Invoke a command with no output parameter */ +static int mthca_cmd(struct mthca_dev *dev, + u64 in_param, + u32 in_modifier, + u8 op_modifier, + u16 op, + unsigned long timeout, + u8 *status) +{ + return mthca_cmd_box(dev, in_param, 0, in_modifier, + op_modifier, op, timeout, status); +} + +/* + * Invoke a command with an immediate output parameter (and copy the + * output into the caller's out_param pointer after the command + * executes). + */ +static int mthca_cmd_imm(struct mthca_dev *dev, + u64 in_param, + u64 *out_param, + u32 in_modifier, + u8 op_modifier, + u16 op, + unsigned long timeout, + u8 *status) +{ + if (dev->cmd.use_events) + return mthca_cmd_wait(dev, in_param, out_param, 1, + in_modifier, op_modifier, op, + timeout, status); + else + return mthca_cmd_poll(dev, in_param, out_param, 1, + in_modifier, op_modifier, op, + timeout, status); +} + +int mthca_cmd_init(struct mthca_dev *dev) +{ + KeInitializeMutex(&dev->cmd.hcr_mutex, 0); + sem_init(&dev->cmd.poll_sem, 1, 1); + dev->cmd.use_events = 0; + + dev->hcr = ioremap(pci_resource_start(dev, HCA_BAR_TYPE_HCR) + MTHCA_HCR_BASE, + MTHCA_HCR_SIZE, &dev->hcr_size); + if (!dev->hcr) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Couldn't map command register.")); + return -ENOMEM; + } + + dev->cmd.pool = pci_pool_create("mthca_cmd", dev, + MTHCA_MAILBOX_SIZE, + MTHCA_MAILBOX_SIZE, 0); + if (!dev->cmd.pool) { + iounmap(dev->hcr, dev->hcr_size); + return -ENOMEM; + } + + return 0; +} + +void mthca_cmd_cleanup(struct mthca_dev *dev) +{ + pci_pool_destroy(dev->cmd.pool); + iounmap(dev->hcr, dev->hcr_size); +} + +/* + * Switch to using events to issue FW commands (should be called after + * event queue to command events has been initialized). + */ +int mthca_cmd_use_events(struct mthca_dev *dev) +{ + int i; + + dev->cmd.context = kmalloc(dev->cmd.max_cmds * + sizeof (struct mthca_cmd_context), + GFP_KERNEL); + if (!dev->cmd.context) + return -ENOMEM; + + for (i = 0; i < dev->cmd.max_cmds; ++i) { + dev->cmd.context[i].token = (u16)i; + dev->cmd.context[i].next = i + 1; + KeInitializeEvent( &dev->cmd.context[i].event, NotificationEvent , FALSE ); + } + + dev->cmd.context[dev->cmd.max_cmds - 1].next = -1; + dev->cmd.free_head = 0; + + sem_init(&dev->cmd.event_sem, dev->cmd.max_cmds, LONG_MAX); + spin_lock_init(&dev->cmd.context_lock); + + for (dev->cmd.token_mask = 1; + dev->cmd.token_mask < dev->cmd.max_cmds; + dev->cmd.token_mask <<= 1) + ; /* nothing */ + --dev->cmd.token_mask; + + dev->cmd.use_events = 1; + sem_down(&dev->cmd.poll_sem); + + return 0; +} + +/* + * Switch back to polling (used when shutting down the device) + */ +void mthca_cmd_use_polling(struct mthca_dev *dev) +{ + int i; + + dev->cmd.use_events = 0; + + for (i = 0; i < dev->cmd.max_cmds; ++i) + sem_down(&dev->cmd.event_sem); + + kfree(dev->cmd.context); + + sem_up(&dev->cmd.poll_sem); +} + +struct mthca_mailbox *mthca_alloc_mailbox(struct mthca_dev *dev, + unsigned int gfp_mask) +{ + struct mthca_mailbox *mailbox; + + mailbox = kmalloc(sizeof *mailbox, gfp_mask); + if (!mailbox) + return ERR_PTR(-ENOMEM); + + mailbox->buf = pci_pool_alloc(dev->cmd.pool, gfp_mask, &mailbox->dma); + if (!mailbox->buf) { + kfree(mailbox); + return ERR_PTR(-ENOMEM); + } + + return mailbox; +} + +void mthca_free_mailbox(struct mthca_dev *dev, struct mthca_mailbox *mailbox) +{ + if (!mailbox) + return; + + pci_pool_free(dev->cmd.pool, mailbox->buf, mailbox->dma); + kfree(mailbox); +} + +int mthca_SYS_EN(struct mthca_dev *dev, u8 *status) +{ + u64 out; + int ret; + + ret = mthca_cmd_imm(dev, 0, &out, 0, 0, CMD_SYS_EN, HZ, status); + + if (*status == MTHCA_CMD_STAT_DDR_MEM_ERR) + HCA_PRINT(TRACE_LEVEL_WARNING,HCA_DBG_LOW,("SYS_EN DDR error: syn=%x, sock=%d, " + "sladdr=%d, SPD source=%s\n", + (int) (out >> 6) & 0xf, (int) (out >> 4) & 3, + (int) (out >> 1) & 7, (int) out & 1 ? "NVMEM" : "DIMM")); + + return ret; +} + +int mthca_SYS_DIS(struct mthca_dev *dev, u8 *status) +{ + return mthca_cmd(dev, 0, 0, 0, CMD_SYS_DIS, HZ, status); +} + +static int mthca_map_cmd(struct mthca_dev *dev, u16 op, struct mthca_icm *icm, + u64 virt, u8 *status) +{ + struct mthca_mailbox *mailbox; + struct mthca_icm_iter iter; + __be64 *pages; + int lg; + int nent = 0; + unsigned long i; + int err = 0; + int ts = 0, tc = 0; + CPU_2_BE64_PREP; + + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + RtlZeroMemory(mailbox->buf, MTHCA_MAILBOX_SIZE); + pages = mailbox->buf; + + for (mthca_icm_first(icm, &iter); + !mthca_icm_last(&iter); + mthca_icm_next(&iter)) { + /* + * We have to pass pages that are aligned to their + * size, so find the least significant 1 in the + * address or size and use that as our log2 size. + */ + i = (u32)mthca_icm_addr(&iter) | mthca_icm_size(&iter); + lg = ffs(i) - 1; + if (lg < 12) { + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_LOW ,("Got FW area not aligned to 4K (%I64x/%lx).\n", + (u64) mthca_icm_addr(&iter), + mthca_icm_size(&iter))); + err = -EINVAL; + goto out; + } + for (i = 0; i < mthca_icm_size(&iter) >> lg; ++i) { + if (virt != -1) { + pages[nent * 2] = cl_hton64(virt); + virt += 1Ui64 << lg; + } + pages[nent * 2 + 1] = CPU_2_BE64((mthca_icm_addr(&iter) + + (i << lg)) | (lg - 12)); + ts += 1 << (lg - 10); + ++tc; + + if (++nent == MTHCA_MAILBOX_SIZE / 16) { + err = mthca_cmd(dev, mailbox->dma, nent, 0, op, + CMD_TIME_CLASS_B, status); + if (err || *status) + goto out; + nent = 0; + } + } + } + + if (nent) + err = mthca_cmd(dev, mailbox->dma, nent, 0, op, + CMD_TIME_CLASS_B, status); + + switch (op) { + case CMD_MAP_FA: + HCA_PRINT(TRACE_LEVEL_VERBOSE ,HCA_DBG_LOW ,("Mapped %d chunks/%d KB for FW.\n", tc, ts)); + break; + case CMD_MAP_ICM_AUX: + HCA_PRINT(TRACE_LEVEL_VERBOSE ,HCA_DBG_LOW ,("Mapped %d chunks/%d KB for ICM aux.\n", tc, ts)); + break; + case CMD_MAP_ICM: + HCA_PRINT(TRACE_LEVEL_VERBOSE,HCA_DBG_LOW,("Mapped %d chunks/%d KB at %I64x for ICM.\n", + tc, ts, (u64) virt - (ts << 10))); + break; + } + +out: + mthca_free_mailbox(dev, mailbox); + return err; +} + +int mthca_MAP_FA(struct mthca_dev *dev, struct mthca_icm *icm, u8 *status) +{ + return mthca_map_cmd(dev, CMD_MAP_FA, icm, (u64)-1, status); +} + +int mthca_UNMAP_FA(struct mthca_dev *dev, u8 *status) +{ + return mthca_cmd(dev, 0, 0, 0, CMD_UNMAP_FA, CMD_TIME_CLASS_B, status); +} + +int mthca_RUN_FW(struct mthca_dev *dev, u8 *status) +{ + return mthca_cmd(dev, 0, 0, 0, CMD_RUN_FW, CMD_TIME_CLASS_A, status); +} + +int mthca_QUERY_FW(struct mthca_dev *dev, u8 *status) +{ + struct mthca_mailbox *mailbox; + u32 *outbox; + int err = 0; + u8 lg; + +#define QUERY_FW_OUT_SIZE 0x100 +#define QUERY_FW_VER_OFFSET 0x00 +#define QUERY_FW_MAX_CMD_OFFSET 0x0f +#define QUERY_FW_ERR_START_OFFSET 0x30 +#define QUERY_FW_ERR_SIZE_OFFSET 0x38 + +#define QUERY_FW_START_OFFSET 0x20 +#define QUERY_FW_END_OFFSET 0x28 + +#define QUERY_FW_SIZE_OFFSET 0x00 +#define QUERY_FW_CLR_INT_BASE_OFFSET 0x20 +#define QUERY_FW_EQ_ARM_BASE_OFFSET 0x40 +#define QUERY_FW_EQ_SET_CI_BASE_OFFSET 0x48 + + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + outbox = mailbox->buf; + + err = mthca_cmd_box(dev, 0, mailbox->dma, 0, 0, CMD_QUERY_FW, + CMD_TIME_CLASS_A, status); + + if (err) + goto out; + + MTHCA_GET(dev->fw_ver, outbox, QUERY_FW_VER_OFFSET); + /* + * FW subSIZE_Tor version is at more signifant bits than minor + * version, so swap here. + */ + dev->fw_ver = (dev->fw_ver & 0xffff00000000Ui64) | + ((dev->fw_ver & 0xffff0000Ui64) >> 16) | + ((dev->fw_ver & 0x0000ffffUi64) << 16); + + MTHCA_GET(lg, outbox, QUERY_FW_MAX_CMD_OFFSET); + dev->cmd.max_cmds = 1 << lg; + MTHCA_GET(dev->catas_err.addr, outbox, QUERY_FW_ERR_START_OFFSET); + MTHCA_GET(dev->catas_err.size, outbox, QUERY_FW_ERR_SIZE_OFFSET); + + HCA_PRINT(TRACE_LEVEL_VERBOSE,HCA_DBG_LOW,("FW version %012I64x, max commands %d\n", + (u64) dev->fw_ver, dev->cmd.max_cmds)); + HCA_PRINT(TRACE_LEVEL_VERBOSE,HCA_DBG_LOW,("Catastrophic error buffer at 0x%I64x, size 0x%x\n", + (u64) dev->catas_err.addr, dev->catas_err.size)); + + + if (mthca_is_memfree(dev)) { + MTHCA_GET(dev->fw.arbel.fw_pages, outbox, QUERY_FW_SIZE_OFFSET); + MTHCA_GET(dev->fw.arbel.clr_int_base, outbox, QUERY_FW_CLR_INT_BASE_OFFSET); + MTHCA_GET(dev->fw.arbel.eq_arm_base, outbox, QUERY_FW_EQ_ARM_BASE_OFFSET); + MTHCA_GET(dev->fw.arbel.eq_set_ci_base, outbox, QUERY_FW_EQ_SET_CI_BASE_OFFSET); + HCA_PRINT(TRACE_LEVEL_VERBOSE ,HCA_DBG_LOW ,("FW size %d KB\n", dev->fw.arbel.fw_pages << 2)); + + /* + * Arbel page size is always 4 KB; round up number of + * system pages needed. + */ + dev->fw.arbel.fw_pages = + ALIGN(dev->fw.arbel.fw_pages, PAGE_SIZE >> 12) >> + (PAGE_SHIFT - 12); + + HCA_PRINT(TRACE_LEVEL_VERBOSE,HCA_DBG_LOW,("Clear int @ %I64x, EQ arm @ %I64x, EQ set CI @ %I64x\n", + (u64) dev->fw.arbel.clr_int_base, + (u64) dev->fw.arbel.eq_arm_base, + (u64) dev->fw.arbel.eq_set_ci_base)); + } else { + MTHCA_GET(dev->fw.tavor.fw_start, outbox, QUERY_FW_START_OFFSET); + MTHCA_GET(dev->fw.tavor.fw_end, outbox, QUERY_FW_END_OFFSET); + + HCA_PRINT(TRACE_LEVEL_VERBOSE,HCA_DBG_LOW,("FW size %d KB (start %I64x, end %I64x)\n", + (int) ((dev->fw.tavor.fw_end - dev->fw.tavor.fw_start) >> 10), + (u64) dev->fw.tavor.fw_start, + (u64) dev->fw.tavor.fw_end)); + } + +out: + mthca_free_mailbox(dev, mailbox); + return err; +} + +int mthca_ENABLE_LAM(struct mthca_dev *dev, u8 *status) +{ + struct mthca_mailbox *mailbox; + u8 info; + u32 *outbox; + int err = 0; + +#define ENABLE_LAM_OUT_SIZE 0x100 +#define ENABLE_LAM_START_OFFSET 0x00 +#define ENABLE_LAM_END_OFFSET 0x08 +#define ENABLE_LAM_INFO_OFFSET 0x13 + +#define ENABLE_LAM_INFO_HIDDEN_FLAG (1 << 4) +#define ENABLE_LAM_INFO_ECC_MASK 0x3 + + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + outbox = mailbox->buf; + + err = mthca_cmd_box(dev, 0, mailbox->dma, 0, 0, CMD_ENABLE_LAM, + CMD_TIME_CLASS_C, status); + + if (err) + goto out; + + if (*status == MTHCA_CMD_STAT_LAM_NOT_PRE) + goto out; + + MTHCA_GET(dev->ddr_start, outbox, ENABLE_LAM_START_OFFSET); + MTHCA_GET(dev->ddr_end, outbox, ENABLE_LAM_END_OFFSET); + MTHCA_GET(info, outbox, ENABLE_LAM_INFO_OFFSET); + + if (!!(info & ENABLE_LAM_INFO_HIDDEN_FLAG) != + !!(dev->mthca_flags & MTHCA_FLAG_DDR_HIDDEN)) { + HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_LOW ,("FW reports that HCA-attached memory " + "is %s hidden; does not match PCI config\n", + (info & ENABLE_LAM_INFO_HIDDEN_FLAG)? + "" : "not")); + } + if (info & ENABLE_LAM_INFO_HIDDEN_FLAG) + HCA_PRINT(TRACE_LEVEL_VERBOSE ,HCA_DBG_LOW ,("HCA-attached memory is hidden.\n")); + + HCA_PRINT(TRACE_LEVEL_VERBOSE,HCA_DBG_LOW,("HCA memory size %d KB (start %I64x, end %I64x)\n", + (int) ((dev->ddr_end - dev->ddr_start) >> 10), + (u64) dev->ddr_start, + (u64) dev->ddr_end)); + +out: + mthca_free_mailbox(dev, mailbox); + return err; +} + +int mthca_DISABLE_LAM(struct mthca_dev *dev, u8 *status) +{ + return mthca_cmd(dev, 0, 0, 0, CMD_SYS_DIS, CMD_TIME_CLASS_C, status); +} + +int mthca_QUERY_DDR(struct mthca_dev *dev, u8 *status) +{ + struct mthca_mailbox *mailbox; + u8 info; + u32 *outbox; + int err = 0; + +#define QUERY_DDR_OUT_SIZE 0x100 +#define QUERY_DDR_START_OFFSET 0x00 +#define QUERY_DDR_END_OFFSET 0x08 +#define QUERY_DDR_INFO_OFFSET 0x13 + +#define QUERY_DDR_INFO_HIDDEN_FLAG (1 << 4) +#define QUERY_DDR_INFO_ECC_MASK 0x3 + + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + outbox = mailbox->buf; + + err = mthca_cmd_box(dev, 0, mailbox->dma, 0, 0, CMD_QUERY_DDR, + CMD_TIME_CLASS_A, status); + + if (err) + goto out; + + MTHCA_GET(dev->ddr_start, outbox, QUERY_DDR_START_OFFSET); + MTHCA_GET(dev->ddr_end, outbox, QUERY_DDR_END_OFFSET); + MTHCA_GET(info, outbox, QUERY_DDR_INFO_OFFSET); + + if (!!(info & QUERY_DDR_INFO_HIDDEN_FLAG) != + !!(dev->mthca_flags & MTHCA_FLAG_DDR_HIDDEN)) { + + HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_LOW ,("FW reports that HCA-attached memory " + "is %s hidden; does not match PCI config\n", + (info & QUERY_DDR_INFO_HIDDEN_FLAG) ? + "" : "not")); + } + if (info & QUERY_DDR_INFO_HIDDEN_FLAG) + HCA_PRINT(TRACE_LEVEL_VERBOSE ,HCA_DBG_LOW ,("HCA-attached memory is hidden.\n")); + + HCA_PRINT(TRACE_LEVEL_VERBOSE,HCA_DBG_LOW,("HCA memory size %d KB (start %I64x, end %I64x)\n", + (int) ((dev->ddr_end - dev->ddr_start) >> 10), + (u64) dev->ddr_start, + (u64) dev->ddr_end)); + +out: + mthca_free_mailbox(dev, mailbox); + return err; +} + +int mthca_QUERY_DEV_LIM(struct mthca_dev *dev, + struct mthca_dev_lim *dev_lim, u8 *status) +{ + struct mthca_mailbox *mailbox; + u32 *outbox; + u8 field; + u16 size; + int err; + +#define QUERY_DEV_LIM_OUT_SIZE 0x100 +#define QUERY_DEV_LIM_MAX_SRQ_SZ_OFFSET 0x10 +#define QUERY_DEV_LIM_MAX_QP_SZ_OFFSET 0x11 +#define QUERY_DEV_LIM_RSVD_QP_OFFSET 0x12 +#define QUERY_DEV_LIM_MAX_QP_OFFSET 0x13 +#define QUERY_DEV_LIM_RSVD_SRQ_OFFSET 0x14 +#define QUERY_DEV_LIM_MAX_SRQ_OFFSET 0x15 +#define QUERY_DEV_LIM_RSVD_EEC_OFFSET 0x16 +#define QUERY_DEV_LIM_MAX_EEC_OFFSET 0x17 +#define QUERY_DEV_LIM_MAX_CQ_SZ_OFFSET 0x19 +#define QUERY_DEV_LIM_RSVD_CQ_OFFSET 0x1a +#define QUERY_DEV_LIM_MAX_CQ_OFFSET 0x1b +#define QUERY_DEV_LIM_MAX_MPT_OFFSET 0x1d +#define QUERY_DEV_LIM_RSVD_EQ_OFFSET 0x1e +#define QUERY_DEV_LIM_MAX_EQ_OFFSET 0x1f +#define QUERY_DEV_LIM_RSVD_MTT_OFFSET 0x20 +#define QUERY_DEV_LIM_MAX_MRW_SZ_OFFSET 0x21 +#define QUERY_DEV_LIM_RSVD_MRW_OFFSET 0x22 +#define QUERY_DEV_LIM_MAX_MTT_SEG_OFFSET 0x23 +#define QUERY_DEV_LIM_MAX_AV_OFFSET 0x27 +#define QUERY_DEV_LIM_MAX_REQ_QP_OFFSET 0x29 +#define QUERY_DEV_LIM_MAX_RES_QP_OFFSET 0x2b +#define QUERY_DEV_LIM_MAX_RDMA_OFFSET 0x2f +#define QUERY_DEV_LIM_RSZ_SRQ_OFFSET 0x33 +#define QUERY_DEV_LIM_ACK_DELAY_OFFSET 0x35 +#define QUERY_DEV_LIM_MTU_WIDTH_OFFSET 0x36 +#define QUERY_DEV_LIM_VL_PORT_OFFSET 0x37 +#define QUERY_DEV_LIM_MAX_GID_OFFSET 0x3b +#define QUERY_DEV_LIM_MAX_PKEY_OFFSET 0x3f +#define QUERY_DEV_LIM_FLAGS_OFFSET 0x44 +#define QUERY_DEV_LIM_RSVD_UAR_OFFSET 0x48 +#define QUERY_DEV_LIM_UAR_SZ_OFFSET 0x49 +#define QUERY_DEV_LIM_PAGE_SZ_OFFSET 0x4b +#define QUERY_DEV_LIM_MAX_SG_OFFSET 0x51 +#define QUERY_DEV_LIM_MAX_DESC_SZ_OFFSET 0x52 +#define QUERY_DEV_LIM_MAX_SG_RQ_OFFSET 0x55 +#define QUERY_DEV_LIM_MAX_DESC_SZ_RQ_OFFSET 0x56 +#define QUERY_DEV_LIM_MAX_QP_MCG_OFFSET 0x61 +#define QUERY_DEV_LIM_RSVD_MCG_OFFSET 0x62 +#define QUERY_DEV_LIM_MAX_MCG_OFFSET 0x63 +#define QUERY_DEV_LIM_RSVD_PD_OFFSET 0x64 +#define QUERY_DEV_LIM_MAX_PD_OFFSET 0x65 +#define QUERY_DEV_LIM_RSVD_RDD_OFFSET 0x66 +#define QUERY_DEV_LIM_MAX_RDD_OFFSET 0x67 +#define QUERY_DEV_LIM_EEC_ENTRY_SZ_OFFSET 0x80 +#define QUERY_DEV_LIM_QPC_ENTRY_SZ_OFFSET 0x82 +#define QUERY_DEV_LIM_EEEC_ENTRY_SZ_OFFSET 0x84 +#define QUERY_DEV_LIM_EQPC_ENTRY_SZ_OFFSET 0x86 +#define QUERY_DEV_LIM_EQC_ENTRY_SZ_OFFSET 0x88 +#define QUERY_DEV_LIM_CQC_ENTRY_SZ_OFFSET 0x8a +#define QUERY_DEV_LIM_SRQ_ENTRY_SZ_OFFSET 0x8c +#define QUERY_DEV_LIM_UAR_ENTRY_SZ_OFFSET 0x8e +#define QUERY_DEV_LIM_MTT_ENTRY_SZ_OFFSET 0x90 +#define QUERY_DEV_LIM_MPT_ENTRY_SZ_OFFSET 0x92 +#define QUERY_DEV_LIM_PBL_SZ_OFFSET 0x96 +#define QUERY_DEV_LIM_BMME_FLAGS_OFFSET 0x97 +#define QUERY_DEV_LIM_RSVD_LKEY_OFFSET 0x98 +#define QUERY_DEV_LIM_LAMR_OFFSET 0x9f +#define QUERY_DEV_LIM_MAX_ICM_SZ_OFFSET 0xa0 + + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + outbox = mailbox->buf; + + err = mthca_cmd_box(dev, 0, mailbox->dma, 0, 0, CMD_QUERY_DEV_LIM, + CMD_TIME_CLASS_A, status); + + if (err) + goto out; + + MTHCA_GET(field, outbox, QUERY_DEV_LIM_RSVD_QP_OFFSET); + dev_lim->reserved_qps = 1 << (field & 0xf); + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_QP_OFFSET); + dev_lim->max_qps = 1 << (field & 0x1f); + MTHCA_GET(field, outbox, QUERY_DEV_LIM_RSVD_SRQ_OFFSET); + dev_lim->reserved_srqs = 1 << (field >> 4); + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_SRQ_OFFSET); + dev_lim->max_srqs = 1 << (field & 0x1f); + MTHCA_GET(field, outbox, QUERY_DEV_LIM_RSVD_EEC_OFFSET); + dev_lim->reserved_eecs = 1 << (field & 0xf); + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_EEC_OFFSET); + dev_lim->max_eecs = 1 << (field & 0x1f); + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_CQ_SZ_OFFSET); + dev_lim->max_cq_sz = 1 << field; + MTHCA_GET(field, outbox, QUERY_DEV_LIM_RSVD_CQ_OFFSET); + dev_lim->reserved_cqs = 1 << (field & 0xf); + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_CQ_OFFSET); + dev_lim->max_cqs = 1 << (field & 0x1f); + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_MPT_OFFSET); + dev_lim->max_mpts = 1 << (field & 0x3f); + MTHCA_GET(field, outbox, QUERY_DEV_LIM_RSVD_EQ_OFFSET); + dev_lim->reserved_eqs = 1 << (field & 0xf); + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_EQ_OFFSET); + dev_lim->max_eqs = 1 << (field & 0x7); + MTHCA_GET(field, outbox, QUERY_DEV_LIM_RSVD_MTT_OFFSET); + if (mthca_is_memfree(dev)) + dev_lim->reserved_mtts = ALIGN((1Ui64 << (field >> 4)) * sizeof(u64), + MTHCA_MTT_SEG_SIZE) / MTHCA_MTT_SEG_SIZE; + else + dev_lim->reserved_mtts = 1 << (field >> 4); + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_MRW_SZ_OFFSET); + dev_lim->max_mrw_sz = 1 << field; + MTHCA_GET(field, outbox, QUERY_DEV_LIM_RSVD_MRW_OFFSET); + dev_lim->reserved_mrws = 1 << (field & 0xf); + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_MTT_SEG_OFFSET); + dev_lim->max_mtt_seg = 1 << (field & 0x3f); + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_REQ_QP_OFFSET); + dev_lim->max_requester_per_qp = 1 << (field & 0x3f); + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_RES_QP_OFFSET); + dev_lim->max_responder_per_qp = 1 << (field & 0x3f); + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_RDMA_OFFSET); + dev_lim->max_rdma_global = 1 << (field & 0x3f); + MTHCA_GET(field, outbox, QUERY_DEV_LIM_ACK_DELAY_OFFSET); + dev_lim->local_ca_ack_delay = field & 0x1f; + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MTU_WIDTH_OFFSET); + dev_lim->max_mtu = field >> 4; + dev_lim->max_port_width = field & 0xf; + MTHCA_GET(field, outbox, QUERY_DEV_LIM_VL_PORT_OFFSET); + dev_lim->max_vl = field >> 4; + dev_lim->num_ports = field & 0xf; + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_GID_OFFSET); + dev_lim->max_gids = 1 << (field & 0xf); + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_PKEY_OFFSET); + dev_lim->max_pkeys = 1 << (field & 0xf); + MTHCA_GET(dev_lim->flags, outbox, QUERY_DEV_LIM_FLAGS_OFFSET); + MTHCA_GET(field, outbox, QUERY_DEV_LIM_RSVD_UAR_OFFSET); + dev_lim->reserved_uars = field >> 4; + MTHCA_GET(field, outbox, QUERY_DEV_LIM_UAR_SZ_OFFSET); + dev_lim->uar_size = 1 << ((field & 0x3f) + 20); + MTHCA_GET(field, outbox, QUERY_DEV_LIM_PAGE_SZ_OFFSET); + dev_lim->min_page_sz = 1 << field; + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_SG_OFFSET); + dev_lim->max_sg = field; + + MTHCA_GET(size, outbox, QUERY_DEV_LIM_MAX_DESC_SZ_OFFSET); + dev_lim->max_desc_sz = size; + + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_QP_MCG_OFFSET); + dev_lim->max_qp_per_mcg = 1 << field; + MTHCA_GET(field, outbox, QUERY_DEV_LIM_RSVD_MCG_OFFSET); + dev_lim->reserved_mgms = field & 0xf; + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_MCG_OFFSET); + dev_lim->max_mcgs = 1 << field; + MTHCA_GET(field, outbox, QUERY_DEV_LIM_RSVD_PD_OFFSET); + dev_lim->reserved_pds = field >> 4; + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_PD_OFFSET); + dev_lim->max_pds = 1 << (field & 0x3f); + MTHCA_GET(field, outbox, QUERY_DEV_LIM_RSVD_RDD_OFFSET); + dev_lim->reserved_rdds = field >> 4; + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_RDD_OFFSET); + dev_lim->max_rdds = 1 << (field & 0x3f); + + MTHCA_GET(size, outbox, QUERY_DEV_LIM_EEC_ENTRY_SZ_OFFSET); + dev_lim->eec_entry_sz = size; + MTHCA_GET(size, outbox, QUERY_DEV_LIM_QPC_ENTRY_SZ_OFFSET); + dev_lim->qpc_entry_sz = size; + MTHCA_GET(size, outbox, QUERY_DEV_LIM_EEEC_ENTRY_SZ_OFFSET); + dev_lim->eeec_entry_sz = size; + MTHCA_GET(size, outbox, QUERY_DEV_LIM_EQPC_ENTRY_SZ_OFFSET); + dev_lim->eqpc_entry_sz = size; + MTHCA_GET(size, outbox, QUERY_DEV_LIM_EQC_ENTRY_SZ_OFFSET); + dev_lim->eqc_entry_sz = size; + MTHCA_GET(size, outbox, QUERY_DEV_LIM_CQC_ENTRY_SZ_OFFSET); + dev_lim->cqc_entry_sz = size; + MTHCA_GET(size, outbox, QUERY_DEV_LIM_SRQ_ENTRY_SZ_OFFSET); + dev_lim->srq_entry_sz = size; + MTHCA_GET(size, outbox, QUERY_DEV_LIM_UAR_ENTRY_SZ_OFFSET); + dev_lim->uar_scratch_entry_sz = size; + + if (mthca_is_memfree(dev)) { + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_SRQ_SZ_OFFSET); + dev_lim->max_srq_sz = 1 << field; + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_QP_SZ_OFFSET); + dev_lim->max_qp_sz = 1 << field; + MTHCA_GET(field, outbox, QUERY_DEV_LIM_RSZ_SRQ_OFFSET); + dev_lim->hca.arbel.resize_srq = field & 1; + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_SG_RQ_OFFSET); + dev_lim->max_sg = min(field, dev_lim->max_sg); + MTHCA_GET(size, outbox, QUERY_DEV_LIM_MAX_DESC_SZ_RQ_OFFSET); + dev_lim->max_desc_sz = min((int)size, dev_lim->max_desc_sz); + MTHCA_GET(size, outbox, QUERY_DEV_LIM_MPT_ENTRY_SZ_OFFSET); + dev_lim->mpt_entry_sz = size; + MTHCA_GET(field, outbox, QUERY_DEV_LIM_PBL_SZ_OFFSET); + dev_lim->hca.arbel.max_pbl_sz = 1 << (field & 0x3f); + MTHCA_GET(dev_lim->hca.arbel.bmme_flags, outbox, + QUERY_DEV_LIM_BMME_FLAGS_OFFSET); + MTHCA_GET(dev_lim->hca.arbel.reserved_lkey, outbox, + QUERY_DEV_LIM_RSVD_LKEY_OFFSET); + MTHCA_GET(field, outbox, QUERY_DEV_LIM_LAMR_OFFSET); + dev_lim->hca.arbel.lam_required = field & 1; + MTHCA_GET(dev_lim->hca.arbel.max_icm_sz, outbox, + QUERY_DEV_LIM_MAX_ICM_SZ_OFFSET); + + if (dev_lim->hca.arbel.bmme_flags & 1){ + HCA_PRINT(TRACE_LEVEL_VERBOSE,HCA_DBG_LOW,("Base MM extensions: yes " + "(flags %d, max PBL %d, rsvd L_Key %08x)\n", + dev_lim->hca.arbel.bmme_flags, + dev_lim->hca.arbel.max_pbl_sz, + dev_lim->hca.arbel.reserved_lkey)); + }else{ + HCA_PRINT(TRACE_LEVEL_VERBOSE ,HCA_DBG_LOW ,("Base MM extensions: no\n")); + } + + HCA_PRINT(TRACE_LEVEL_VERBOSE,HCA_DBG_LOW,("Max ICM size %I64d MB\n", + (u64) dev_lim->hca.arbel.max_icm_sz >> 20)); + } + else { + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_SRQ_SZ_OFFSET); + dev_lim->max_srq_sz = (1 << field) - 1; + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_QP_SZ_OFFSET); + dev_lim->max_qp_sz = (1 << field) - 1; + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_AV_OFFSET); + dev_lim->hca.tavor.max_avs = 1I64 << (field & 0x3f); + dev_lim->mpt_entry_sz = MTHCA_MPT_ENTRY_SIZE; + } + + HCA_PRINT(TRACE_LEVEL_VERBOSE,HCA_DBG_LOW,("Max QPs: %d, reserved QPs: %d, entry size: %d\n", + dev_lim->max_qps, dev_lim->reserved_qps, dev_lim->qpc_entry_sz)); + HCA_PRINT(TRACE_LEVEL_VERBOSE,HCA_DBG_LOW,("Max SRQs: %d, reserved SRQs: %d, entry size: %d\n", + dev_lim->max_srqs, dev_lim->reserved_srqs, dev_lim->srq_entry_sz)); + HCA_PRINT(TRACE_LEVEL_VERBOSE,HCA_DBG_LOW,("Max CQs: %d, reserved CQs: %d, entry size: %d\n", + dev_lim->max_cqs, dev_lim->reserved_cqs, dev_lim->cqc_entry_sz)); + HCA_PRINT(TRACE_LEVEL_VERBOSE,HCA_DBG_LOW,("Max EQs: %d, reserved EQs: %d, entry size: %d\n", + dev_lim->max_eqs, dev_lim->reserved_eqs, dev_lim->eqc_entry_sz)); + HCA_PRINT(TRACE_LEVEL_VERBOSE,HCA_DBG_LOW,("reserved MPTs: %d, reserved MTTs: %d\n", + dev_lim->reserved_mrws, dev_lim->reserved_mtts)); + HCA_PRINT(TRACE_LEVEL_VERBOSE,HCA_DBG_LOW,("Max PDs: %d, reserved PDs: %d, reserved UARs: %d\n", + dev_lim->max_pds, dev_lim->reserved_pds, dev_lim->reserved_uars)); + HCA_PRINT(TRACE_LEVEL_VERBOSE,HCA_DBG_LOW,("Max QP/MCG: %d, reserved MGMs: %d\n", + dev_lim->max_pds, dev_lim->reserved_mgms)); + HCA_PRINT(TRACE_LEVEL_VERBOSE,HCA_DBG_LOW,("Max CQEs: %d, max WQEs: %d, max SRQ WQEs: %d\n", + dev_lim->max_cq_sz, dev_lim->max_qp_sz, dev_lim->max_srq_sz)); + + HCA_PRINT(TRACE_LEVEL_VERBOSE ,HCA_DBG_LOW ,("Flags: %08x\n", dev_lim->flags)); + +out: + mthca_free_mailbox(dev, mailbox); + return err; +} + +static void get_board_id(u8 *vsd, char *board_id) +{ + int i; + +#define VSD_OFFSET_SIG1 0x00 +#define VSD_OFFSET_SIG2 0xde +#define VSD_OFFSET_MLX_BOARD_ID 0xd0 +#define VSD_OFFSET_TS_BOARD_ID 0x20 + +#define VSD_SIGNATURE_TOPSPIN 0x5ad + + RtlZeroMemory(board_id, MTHCA_BOARD_ID_LEN); + + if (cl_ntoh16(*(u16*)(vsd + VSD_OFFSET_SIG1)) == VSD_SIGNATURE_TOPSPIN && + cl_ntoh16(*(u16*)(vsd + VSD_OFFSET_SIG2)) == VSD_SIGNATURE_TOPSPIN) { + strlcpy(board_id, (const char *)(vsd + VSD_OFFSET_TS_BOARD_ID), MTHCA_BOARD_ID_LEN); + } else { + /* + * The board ID is a string but the firmware byte + * swaps each 4-byte word before passing it back to + * us. Therefore we need to swab it before printing. + */ + for (i = 0; i < 4; ++i) + ((u32 *) board_id)[i] = + _byteswap_ulong(*(u32 *) (vsd + VSD_OFFSET_MLX_BOARD_ID + i * 4)); + } +} + +int mthca_QUERY_ADAPTER(struct mthca_dev *dev, + struct mthca_adapter *adapter, u8 *status) +{ + struct mthca_mailbox *mailbox; + u32 *outbox; + int err; + +#define QUERY_ADAPTER_OUT_SIZE 0x100 +#define QUERY_ADAPTER_VENDOR_ID_OFFSET 0x00 +#define QUERY_ADAPTER_DEVICE_ID_OFFSET 0x04 +#define QUERY_ADAPTER_REVISION_ID_OFFSET 0x08 +#define QUERY_ADAPTER_INTA_PIN_OFFSET 0x10 +#define QUERY_ADAPTER_VSD_OFFSET 0x20 + + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + outbox = mailbox->buf; + + err = mthca_cmd_box(dev, 0, mailbox->dma, 0, 0, CMD_QUERY_ADAPTER, + CMD_TIME_CLASS_A, status); + + if (err) + goto out; + + MTHCA_GET(adapter->vendor_id, outbox, QUERY_ADAPTER_VENDOR_ID_OFFSET); + MTHCA_GET(adapter->device_id, outbox, QUERY_ADAPTER_DEVICE_ID_OFFSET); + MTHCA_GET(adapter->revision_id, outbox, QUERY_ADAPTER_REVISION_ID_OFFSET); + MTHCA_GET(adapter->inta_pin, outbox, QUERY_ADAPTER_INTA_PIN_OFFSET); + + get_board_id((u8*)outbox + QUERY_ADAPTER_VSD_OFFSET, + adapter->board_id); + +out: + mthca_free_mailbox(dev, mailbox); + return err; +} + +int mthca_INIT_HCA(struct mthca_dev *dev, + struct mthca_init_hca_param *param, + u8 *status) +{ + struct mthca_mailbox *mailbox; + __be32 *inbox; + int err; + +#define INIT_HCA_IN_SIZE 0x200 +#define INIT_HCA_FLAGS_OFFSET 0x014 +#define INIT_HCA_QPC_OFFSET 0x020 +#define INIT_HCA_QPC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x10) +#define INIT_HCA_LOG_QP_OFFSET (INIT_HCA_QPC_OFFSET + 0x17) +#define INIT_HCA_EEC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x20) +#define INIT_HCA_LOG_EEC_OFFSET (INIT_HCA_QPC_OFFSET + 0x27) +#define INIT_HCA_SRQC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x28) +#define INIT_HCA_LOG_SRQ_OFFSET (INIT_HCA_QPC_OFFSET + 0x2f) +#define INIT_HCA_CQC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x30) +#define INIT_HCA_LOG_CQ_OFFSET (INIT_HCA_QPC_OFFSET + 0x37) +#define INIT_HCA_EQPC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x40) +#define INIT_HCA_EEEC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x50) +#define INIT_HCA_EQC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x60) +#define INIT_HCA_LOG_EQ_OFFSET (INIT_HCA_QPC_OFFSET + 0x67) +#define INIT_HCA_RDB_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x70) +#define INIT_HCA_UDAV_OFFSET 0x0b0 +#define INIT_HCA_UDAV_LKEY_OFFSET (INIT_HCA_UDAV_OFFSET + 0x0) +#define INIT_HCA_UDAV_PD_OFFSET (INIT_HCA_UDAV_OFFSET + 0x4) +#define INIT_HCA_MCAST_OFFSET 0x0c0 +#define INIT_HCA_MC_BASE_OFFSET (INIT_HCA_MCAST_OFFSET + 0x00) +#define INIT_HCA_LOG_MC_ENTRY_SZ_OFFSET (INIT_HCA_MCAST_OFFSET + 0x12) +#define INIT_HCA_MC_HASH_SZ_OFFSET (INIT_HCA_MCAST_OFFSET + 0x16) +#define INIT_HCA_LOG_MC_TABLE_SZ_OFFSET (INIT_HCA_MCAST_OFFSET + 0x1b) +#define INIT_HCA_TPT_OFFSET 0x0f0 +#define INIT_HCA_MPT_BASE_OFFSET (INIT_HCA_TPT_OFFSET + 0x00) +#define INIT_HCA_MTT_SEG_SZ_OFFSET (INIT_HCA_TPT_OFFSET + 0x09) +#define INIT_HCA_LOG_MPT_SZ_OFFSET (INIT_HCA_TPT_OFFSET + 0x0b) +#define INIT_HCA_MTT_BASE_OFFSET (INIT_HCA_TPT_OFFSET + 0x10) +#define INIT_HCA_UAR_OFFSET 0x120 +#define INIT_HCA_UAR_BASE_OFFSET (INIT_HCA_UAR_OFFSET + 0x00) +#define INIT_HCA_UARC_SZ_OFFSET (INIT_HCA_UAR_OFFSET + 0x09) +#define INIT_HCA_LOG_UAR_SZ_OFFSET (INIT_HCA_UAR_OFFSET + 0x0a) +#define INIT_HCA_UAR_PAGE_SZ_OFFSET (INIT_HCA_UAR_OFFSET + 0x0b) +#define INIT_HCA_UAR_SCATCH_BASE_OFFSET (INIT_HCA_UAR_OFFSET + 0x10) +#define INIT_HCA_UAR_CTX_BASE_OFFSET (INIT_HCA_UAR_OFFSET + 0x18) + + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + inbox = mailbox->buf; + + RtlZeroMemory(inbox, INIT_HCA_IN_SIZE); + +#if defined(__LITTLE_ENDIAN) + *(inbox + INIT_HCA_FLAGS_OFFSET / 4) &= ~cl_hton32(1 << 1); +#elif defined(__BIG_ENDIAN) + *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cl_hton32(1 << 1); +#else +#error Host endianness not defined +#endif + /* Check port for UD address vector: */ + *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cl_hton32(1); + + /* Enable IPoIB checksumming if we can: */ + if (dev->device_cap_flags & IB_DEVICE_IPOIB_CSUM) + *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cl_hton32(7 << 3); + + /* We leave wqe_quota, responder_exu, etc as 0 (default) */ + + /* QPC/EEC/CQC/EQC/RDB attributes */ + + MTHCA_PUT(inbox, param->qpc_base, INIT_HCA_QPC_BASE_OFFSET); + MTHCA_PUT(inbox, param->log_num_qps, INIT_HCA_LOG_QP_OFFSET); + MTHCA_PUT(inbox, param->eec_base, INIT_HCA_EEC_BASE_OFFSET); + MTHCA_PUT(inbox, param->log_num_eecs, INIT_HCA_LOG_EEC_OFFSET); + MTHCA_PUT(inbox, param->srqc_base, INIT_HCA_SRQC_BASE_OFFSET); + MTHCA_PUT(inbox, param->log_num_srqs, INIT_HCA_LOG_SRQ_OFFSET); + MTHCA_PUT(inbox, param->cqc_base, INIT_HCA_CQC_BASE_OFFSET); + MTHCA_PUT(inbox, param->log_num_cqs, INIT_HCA_LOG_CQ_OFFSET); + MTHCA_PUT(inbox, param->eqpc_base, INIT_HCA_EQPC_BASE_OFFSET); + MTHCA_PUT(inbox, param->eeec_base, INIT_HCA_EEEC_BASE_OFFSET); + MTHCA_PUT(inbox, param->eqc_base, INIT_HCA_EQC_BASE_OFFSET); + MTHCA_PUT(inbox, param->log_num_eqs, INIT_HCA_LOG_EQ_OFFSET); + MTHCA_PUT(inbox, param->rdb_base, INIT_HCA_RDB_BASE_OFFSET); + + /* UD AV attributes */ + + /* multicast attributes */ + + MTHCA_PUT(inbox, param->mc_base, INIT_HCA_MC_BASE_OFFSET); + MTHCA_PUT(inbox, param->log_mc_entry_sz, INIT_HCA_LOG_MC_ENTRY_SZ_OFFSET); + MTHCA_PUT(inbox, param->mc_hash_sz, INIT_HCA_MC_HASH_SZ_OFFSET); + MTHCA_PUT(inbox, param->log_mc_table_sz, INIT_HCA_LOG_MC_TABLE_SZ_OFFSET); + + /* TPT attributes */ + + MTHCA_PUT(inbox, param->mpt_base, INIT_HCA_MPT_BASE_OFFSET); + if (!mthca_is_memfree(dev)) + MTHCA_PUT(inbox, param->mtt_seg_sz, INIT_HCA_MTT_SEG_SZ_OFFSET); + MTHCA_PUT(inbox, param->log_mpt_sz, INIT_HCA_LOG_MPT_SZ_OFFSET); + MTHCA_PUT(inbox, param->mtt_base, INIT_HCA_MTT_BASE_OFFSET); + + /* UAR attributes */ + { + u8 uar_page_sz = PAGE_SHIFT - 12; + MTHCA_PUT(inbox, uar_page_sz, INIT_HCA_UAR_PAGE_SZ_OFFSET); + } + + MTHCA_PUT(inbox, param->uar_scratch_base, INIT_HCA_UAR_SCATCH_BASE_OFFSET); + + if (mthca_is_memfree(dev)) { + MTHCA_PUT(inbox, param->log_uarc_sz, INIT_HCA_UARC_SZ_OFFSET); + MTHCA_PUT(inbox, param->log_uar_sz, INIT_HCA_LOG_UAR_SZ_OFFSET); + MTHCA_PUT(inbox, param->uarc_base, INIT_HCA_UAR_CTX_BASE_OFFSET); + } + + err = mthca_cmd(dev, mailbox->dma, 0, 0, CMD_INIT_HCA, HZ, status); + + mthca_free_mailbox(dev, mailbox); + return err; +} + +int mthca_INIT_IB(struct mthca_dev *dev, + struct mthca_init_ib_param *param, + int port, u8 *status) +{ + struct mthca_mailbox *mailbox; + u32 *inbox; + int err; + u32 flags; + +#define INIT_IB_IN_SIZE 56 +#define INIT_IB_FLAGS_OFFSET 0x00 +#define INIT_IB_FLAG_SIG (1 << 18) +#define INIT_IB_FLAG_NG (1 << 17) +#define INIT_IB_FLAG_G0 (1 << 16) +#define INIT_IB_VL_SHIFT 4 +#define INIT_IB_PORT_WIDTH_SHIFT 8 +#define INIT_IB_MTU_SHIFT 12 +#define INIT_IB_MAX_GID_OFFSET 0x06 +#define INIT_IB_MAX_PKEY_OFFSET 0x0a +#define INIT_IB_GUID0_OFFSET 0x10 +#define INIT_IB_NODE_GUID_OFFSET 0x18 +#define INIT_IB_SI_GUID_OFFSET 0x20 + + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + inbox = mailbox->buf; + + RtlZeroMemory(inbox, INIT_IB_IN_SIZE); + + flags = 0; + flags |= param->set_guid0 ? INIT_IB_FLAG_G0 : 0; + flags |= param->set_node_guid ? INIT_IB_FLAG_NG : 0; + flags |= param->set_si_guid ? INIT_IB_FLAG_SIG : 0; + flags |= param->vl_cap << INIT_IB_VL_SHIFT; + flags |= param->port_width << INIT_IB_PORT_WIDTH_SHIFT; + flags |= param->mtu_cap << INIT_IB_MTU_SHIFT; + MTHCA_PUT(inbox, flags, INIT_IB_FLAGS_OFFSET); + + MTHCA_PUT(inbox, param->gid_cap, INIT_IB_MAX_GID_OFFSET); + MTHCA_PUT(inbox, param->pkey_cap, INIT_IB_MAX_PKEY_OFFSET); + MTHCA_PUT(inbox, param->guid0, INIT_IB_GUID0_OFFSET); + MTHCA_PUT(inbox, param->node_guid, INIT_IB_NODE_GUID_OFFSET); + MTHCA_PUT(inbox, param->si_guid, INIT_IB_SI_GUID_OFFSET); + + err = mthca_cmd(dev, mailbox->dma, port, 0, CMD_INIT_IB, + CMD_TIME_CLASS_A, status); + + mthca_free_mailbox(dev, mailbox); + return err; +} + +int mthca_CLOSE_IB(struct mthca_dev *dev, int port, u8 *status) +{ + return mthca_cmd(dev, 0, port, 0, CMD_CLOSE_IB, HZ, status); +} + +int mthca_CLOSE_HCA(struct mthca_dev *dev, int panic, u8 *status) +{ + return mthca_cmd(dev, 0, 0, (u8)panic, CMD_CLOSE_HCA, HZ, status); +} + +int mthca_SET_IB(struct mthca_dev *dev, struct mthca_set_ib_param *param, + int port, u8 *status) +{ + struct mthca_mailbox *mailbox; + u32 *inbox; + int err; + u32 flags = 0; + +#define SET_IB_IN_SIZE 0x40 +#define SET_IB_FLAGS_OFFSET 0x00 +#define SET_IB_FLAG_SIG (1 << 18) +#define SET_IB_FLAG_RQK (1 << 0) +#define SET_IB_CAP_MASK_OFFSET 0x04 +#define SET_IB_SI_GUID_OFFSET 0x08 + + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + inbox = mailbox->buf; + + RtlZeroMemory(inbox, SET_IB_IN_SIZE); + + flags |= param->set_si_guid ? SET_IB_FLAG_SIG : 0; + flags |= param->reset_qkey_viol ? SET_IB_FLAG_RQK : 0; + MTHCA_PUT(inbox, flags, SET_IB_FLAGS_OFFSET); + + MTHCA_PUT(inbox, param->cap_mask, SET_IB_CAP_MASK_OFFSET); + MTHCA_PUT(inbox, param->si_guid, SET_IB_SI_GUID_OFFSET); + + err = mthca_cmd(dev, mailbox->dma, port, 0, CMD_SET_IB, + CMD_TIME_CLASS_B, status); + + mthca_free_mailbox(dev, mailbox); + return err; +} + +int mthca_MAP_ICM(struct mthca_dev *dev, struct mthca_icm *icm, u64 virt, u8 *status) +{ + return mthca_map_cmd(dev, CMD_MAP_ICM, icm, virt, status); +} + +int mthca_MAP_ICM_page(struct mthca_dev *dev, u64 dma_addr, u64 virt, u8 *status) +{ + struct mthca_mailbox *mailbox; + __be64 *inbox; + int err; + + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + inbox = mailbox->buf; + + inbox[0] = cl_hton64(virt); + inbox[1] = cl_hton64(dma_addr); + + err = mthca_cmd(dev, mailbox->dma, 1, 0, CMD_MAP_ICM, + CMD_TIME_CLASS_B, status); + + mthca_free_mailbox(dev, mailbox); + + if (!err) + HCA_PRINT(TRACE_LEVEL_VERBOSE,HCA_DBG_LOW,("Mapped page at %I64x to %I64x for ICM.\n", + (u64) dma_addr, (u64) virt)); + + return err; +} + +int mthca_UNMAP_ICM(struct mthca_dev *dev, u64 virt, u32 page_count, u8 *status) +{ + HCA_PRINT(TRACE_LEVEL_VERBOSE,HCA_DBG_LOW,("Unmapping %d pages at %I64x from ICM.\n", + page_count, (u64) virt)); + + return mthca_cmd(dev, virt, page_count, 0, CMD_UNMAP_ICM, CMD_TIME_CLASS_B, status); +} + +int mthca_MAP_ICM_AUX(struct mthca_dev *dev, struct mthca_icm *icm, u8 *status) +{ + return mthca_map_cmd(dev, CMD_MAP_ICM_AUX, icm, (u64)-1, status); +} + +int mthca_UNMAP_ICM_AUX(struct mthca_dev *dev, u8 *status) +{ + return mthca_cmd(dev, 0, 0, 0, CMD_UNMAP_ICM_AUX, CMD_TIME_CLASS_B, status); +} + +int mthca_SET_ICM_SIZE(struct mthca_dev *dev, u64 icm_size, u64 *aux_pages, + u8 *status) +{ + int ret = mthca_cmd_imm(dev, icm_size, aux_pages, 0, 0, CMD_SET_ICM_SIZE, + CMD_TIME_CLASS_A, status); + + if (ret || status) + return ret; + + /* + * Arbel page size is always 4 KB; round up number of system + * pages needed. + */ + *aux_pages = (*aux_pages + (1 << (PAGE_SHIFT - 12)) - 1) >> (PAGE_SHIFT - 12); + *aux_pages = ALIGN(*aux_pages, PAGE_SIZE >> 12) >> (PAGE_SHIFT - 12); + + return 0; +} + +int mthca_SW2HW_MPT(struct mthca_dev *dev, struct mthca_mailbox *mailbox, + int mpt_index, u8 *status) +{ + return mthca_cmd(dev, mailbox->dma, mpt_index, 0, CMD_SW2HW_MPT, + CMD_TIME_CLASS_B, status); +} + +int mthca_HW2SW_MPT(struct mthca_dev *dev, struct mthca_mailbox *mailbox, + int mpt_index, u8 *status) +{ + return mthca_cmd_box(dev, 0, mailbox ? mailbox->dma : 0, mpt_index, + (u8)!mailbox, CMD_HW2SW_MPT, + CMD_TIME_CLASS_B, status); +} + +int mthca_WRITE_MTT(struct mthca_dev *dev, struct mthca_mailbox *mailbox, + int num_mtt, u8 *status) +{ + return mthca_cmd(dev, mailbox->dma, num_mtt, 0, CMD_WRITE_MTT, + CMD_TIME_CLASS_B, status); +} + +int mthca_SYNC_TPT(struct mthca_dev *dev, u8 *status) +{ + return mthca_cmd(dev, 0, 0, 0, CMD_SYNC_TPT, CMD_TIME_CLASS_B, status); +} + +int mthca_MAP_EQ(struct mthca_dev *dev, u64 event_mask, int unmap, + int eq_num, u8 *status) +{ + HCA_PRINT(TRACE_LEVEL_VERBOSE,HCA_DBG_LOW,("%s mask %016I64x for eqn %d\n", + unmap ? "Clearing" : "Setting", + (u64) event_mask, eq_num)); + return mthca_cmd(dev, event_mask, (unmap << 31) | eq_num, + 0, CMD_MAP_EQ, CMD_TIME_CLASS_B, status); +} + +int mthca_SW2HW_EQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox, + int eq_num, u8 *status) +{ + return mthca_cmd(dev, mailbox->dma, eq_num, 0, CMD_SW2HW_EQ, + CMD_TIME_CLASS_A, status); +} + +int mthca_HW2SW_EQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox, + int eq_num, u8 *status) +{ + return mthca_cmd_box(dev, 0, mailbox->dma, eq_num, 0, + CMD_HW2SW_EQ, + CMD_TIME_CLASS_A, status); +} + +int mthca_SW2HW_CQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox, + int cq_num, u8 *status) +{ + return mthca_cmd(dev, mailbox->dma, cq_num, 0, CMD_SW2HW_CQ, + CMD_TIME_CLASS_A, status); +} + +int mthca_HW2SW_CQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox, + int cq_num, u8 *status) +{ + return mthca_cmd_box(dev, 0, mailbox->dma, cq_num, 0, + CMD_HW2SW_CQ, + CMD_TIME_CLASS_A, status); +} + +int mthca_SW2HW_SRQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox, + int srq_num, u8 *status) +{ + return mthca_cmd(dev, mailbox->dma, srq_num, 0, CMD_SW2HW_SRQ, + CMD_TIME_CLASS_A, status); +} + +int mthca_HW2SW_SRQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox, + int srq_num, u8 *status) +{ + return mthca_cmd_box(dev, 0, mailbox->dma, srq_num, 0, + CMD_HW2SW_SRQ, + CMD_TIME_CLASS_A, status); +} + +int mthca_QUERY_SRQ(struct mthca_dev *dev, u32 num, + struct mthca_mailbox *mailbox, u8 *status) +{ + return mthca_cmd_box(dev, 0, mailbox->dma, num, 0, + CMD_QUERY_SRQ, CMD_TIME_CLASS_A, status); +} + +int mthca_ARM_SRQ(struct mthca_dev *dev, int srq_num, int limit, u8 *status) +{ + return mthca_cmd(dev, limit, srq_num, 0, CMD_ARM_SRQ, + CMD_TIME_CLASS_B, status); +} + +int mthca_MODIFY_QP(struct mthca_dev *dev, int trans, u32 num, + int is_ee, struct mthca_mailbox *mailbox, u32 optmask, + u8 *status) +{ + enum { + MTHCA_TRANS_INVALID = 0, + MTHCA_TRANS_RST2INIT, + MTHCA_TRANS_INIT2INIT, + MTHCA_TRANS_INIT2RTR, + MTHCA_TRANS_RTR2RTS, + MTHCA_TRANS_RTS2RTS, + MTHCA_TRANS_SQERR2RTS, + MTHCA_TRANS_ANY2ERR, + MTHCA_TRANS_RTS2SQD, + MTHCA_TRANS_SQD2SQD, + MTHCA_TRANS_SQD2RTS, + MTHCA_TRANS_ANY2RST, + }; + static const u16 op[] = { + 0, /* MTHCA_TRANS_INVALID */ + CMD_RST2INIT_QPEE, /* MTHCA_TRANS_RST2INIT */ + CMD_INIT2INIT_QPEE, /* MTHCA_TRANS_INIT2INIT */ + CMD_INIT2RTR_QPEE, /* MTHCA_TRANS_INIT2RTR */ + CMD_RTR2RTS_QPEE, /* MTHCA_TRANS_RTR2RTS */ + CMD_RTS2RTS_QPEE, /* MTHCA_TRANS_RTS2RTS */ + CMD_SQERR2RTS_QPEE, /* MTHCA_TRANS_SQERR2RTS */ + CMD_2ERR_QPEE, /* MTHCA_TRANS_ANY2ERR */ + CMD_RTS2SQD_QPEE, /* MTHCA_TRANS_RTS2SQD */ + CMD_SQD2SQD_QPEE, /* MTHCA_TRANS_SQD2SQD */ + CMD_SQD2RTS_QPEE, /* MTHCA_TRANS_SQD2RTS */ + CMD_ERR2RST_QPEE /* MTHCA_TRANS_ANY2RST */ + }; + u8 op_mod = 0; + int my_mailbox = 0; + int err; + + UNREFERENCED_PARAMETER(optmask); + + if (trans < 0 || trans >= ARRAY_SIZE(op)) + return -EINVAL; + + if (trans == MTHCA_TRANS_ANY2RST) { + op_mod = 3; /* don't write outbox, any->reset */ + + /* For debugging */ + if (!mailbox) { + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (!IS_ERR(mailbox)) { + my_mailbox = 1; + op_mod = 2; /* write outbox, any->reset */ + } else + mailbox = NULL; + } + } else { + { // debug print + int i; + HCA_PRINT(TRACE_LEVEL_VERBOSE ,HCA_DBG_QP ,("Dumping QP context:\n")); + HCA_PRINT(TRACE_LEVEL_VERBOSE ,HCA_DBG_QP ,(" opt param mask: %08x\n", cl_ntoh32(*(__be32 *)mailbox->buf))); + for (i = 2; i < 0x100 / 4; i=i+4) { + HCA_PRINT(TRACE_LEVEL_VERBOSE ,HCA_DBG_QP ,(" [%02x] %08x %08x %08x %08x\n",i-2, + cl_ntoh32(((__be32 *) mailbox->buf)[i ]), + cl_ntoh32(((__be32 *) mailbox->buf)[i + 1]), + cl_ntoh32(((__be32 *) mailbox->buf)[i + 2]), + cl_ntoh32(((__be32 *) mailbox->buf)[i + 3]))); + } + } + } + + if (trans == MTHCA_TRANS_ANY2RST) { + err = mthca_cmd_box(dev, 0, mailbox ? mailbox->dma : 0, + (!!is_ee << 24) | num, op_mod, + op[trans], CMD_TIME_CLASS_C, status); + + if (mailbox) { // debug print + int i; + HCA_PRINT(TRACE_LEVEL_VERBOSE ,HCA_DBG_QP ,("Dumping QP context:\n")); + for (i = 2; i < 0x100 / 4; i=i+4) { + HCA_PRINT(TRACE_LEVEL_VERBOSE ,HCA_DBG_QP ,(" [%02x] %08x %08x %08x %08x\n",i-2, + cl_ntoh32(((__be32 *) mailbox->buf)[i ]), + cl_ntoh32(((__be32 *) mailbox->buf)[i + 1]), + cl_ntoh32(((__be32 *) mailbox->buf)[i + 2]), + cl_ntoh32(((__be32 *) mailbox->buf)[i + 3]))); + } + } + } else + err = mthca_cmd(dev, mailbox->dma, optmask | (!!is_ee << 24) | num, + op_mod, op[trans], CMD_TIME_CLASS_C, status); + + if (my_mailbox) + mthca_free_mailbox(dev, mailbox); + + return err; +} + +int mthca_QUERY_QP(struct mthca_dev *dev, u32 num, int is_ee, + struct mthca_mailbox *mailbox, u8 *status) +{ + return mthca_cmd_box(dev, 0, mailbox->dma, (!!is_ee << 24) | num, 0, + CMD_QUERY_QPEE, CMD_TIME_CLASS_A, status); +} + +int mthca_CONF_SPECIAL_QP(struct mthca_dev *dev, int type, u32 qpn, + u8 *status) +{ + u8 op_mod; + + switch (type) { + case IB_QPT_QP0: + op_mod = 0; + break; + case IB_QPT_QP1: + op_mod = 1; + break; + case IB_QPT_RAW_IPV6: + op_mod = 2; + break; + case IB_QPT_RAW_ETHER: + op_mod = 3; + break; + default: + return -EINVAL; + } + + return mthca_cmd(dev, 0, qpn, op_mod, CMD_CONF_SPECIAL_QP, + CMD_TIME_CLASS_B, status); +} + +int mthca_MAD_IFC(struct mthca_dev *dev, int ignore_mkey, int ignore_bkey, + int port, struct _ib_wc *in_wc, struct _ib_grh *in_grh, + void *in_mad, void *response_mad, u8 *status) +{ + struct mthca_mailbox *inmailbox, *outmailbox; + u8 *inbox; + int err; + u32 in_modifier = port; + u8 op_modifier = 0; + + +#define MAD_IFC_BOX_SIZE 0x400 +#define MAD_IFC_MY_QPN_OFFSET 0x100 +#define MAD_IFC_RQPN_OFFSET 0x108 +#define MAD_IFC_SL_OFFSET 0x10c +#define MAD_IFC_G_PATH_OFFSET 0x10d +#define MAD_IFC_RLID_OFFSET 0x10e +#define MAD_IFC_PKEY_OFFSET 0x112 +#define MAD_IFC_GRH_OFFSET 0x140 + + inmailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (IS_ERR(inmailbox)) + return PTR_ERR(inmailbox); + inbox = inmailbox->buf; + + outmailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (IS_ERR(outmailbox)) { + mthca_free_mailbox(dev, inmailbox); + return PTR_ERR(outmailbox); + } + + memcpy(inbox, in_mad, 256); + + /* + * Key check traps can't be generated unless we have in_wc to + * tell us where to send the trap. + */ + if (ignore_mkey || !in_wc) + op_modifier |= 0x1; + if (ignore_bkey || !in_wc) + op_modifier |= 0x2; + + if (in_wc) { + u8 val; + + memset(inbox + 256, 0, 256); + + + MTHCA_PUT(inbox, 0, MAD_IFC_MY_QPN_OFFSET); + MTHCA_PUT(inbox, cl_ntoh32(in_wc->recv.ud.remote_qp), MAD_IFC_RQPN_OFFSET); + val = in_wc->recv.ud.remote_sl << 4; + MTHCA_PUT(inbox, val, MAD_IFC_SL_OFFSET); + + val = in_wc->recv.ud.path_bits | + (in_wc->recv.ud.recv_opt & IB_RECV_OPT_GRH_VALID ? 0x80 : 0); + MTHCA_PUT(inbox, val, MAD_IFC_G_PATH_OFFSET) + + MTHCA_PUT(inbox, cl_ntoh16(in_wc->recv.ud.remote_lid), MAD_IFC_RLID_OFFSET); + MTHCA_PUT(inbox, in_wc->recv.ud.pkey_index, MAD_IFC_PKEY_OFFSET); + + if (in_grh) + memcpy(inbox + MAD_IFC_GRH_OFFSET, in_grh, 40); + + op_modifier |= 0x4; + + in_modifier |= cl_ntoh16(in_wc->recv.ud.remote_lid) << 16; + + } + + err = mthca_cmd_box(dev, inmailbox->dma, outmailbox->dma, + in_modifier, op_modifier, + CMD_MAD_IFC, CMD_TIME_CLASS_C, status); + + if (!err && !*status) + memcpy(response_mad, outmailbox->buf, 256); + + mthca_free_mailbox(dev, inmailbox); + mthca_free_mailbox(dev, outmailbox); + return err; +} + +int mthca_READ_MGM(struct mthca_dev *dev, int index, + struct mthca_mailbox *mailbox, u8 *status) +{ + return mthca_cmd_box(dev, 0, mailbox->dma, index, 0, + CMD_READ_MGM, CMD_TIME_CLASS_A, status); +} + +int mthca_WRITE_MGM(struct mthca_dev *dev, int index, + struct mthca_mailbox *mailbox, u8 *status) +{ + return mthca_cmd(dev, mailbox->dma, index, 0, CMD_WRITE_MGM, + CMD_TIME_CLASS_A, status); +} + +int mthca_MGID_HASH(struct mthca_dev *dev, struct mthca_mailbox *mailbox, + u16 *hash, u8 *status) +{ + u64 imm; + int err; + + err = mthca_cmd_imm(dev, mailbox->dma, &imm, 0, 0, CMD_MGID_HASH, + CMD_TIME_CLASS_A, status); + + *hash = (u16)imm; + return err; +} + +int mthca_NOP(struct mthca_dev *dev, u8 *status) +{ + return mthca_cmd(dev, 0, 0x1f, 0, CMD_NOP, 100000, status); /* 100 msecs */ +} diff --git a/branches/WOF2-3/hw/mthca/kernel/mthca_cmd.h b/branches/WOF2-3/hw/mthca/kernel/mthca_cmd.h new file mode 100644 index 00000000..f5bda231 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/mthca_cmd.h @@ -0,0 +1,327 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#ifndef MTHCA_CMD_H +#define MTHCA_CMD_H + +#include + +#define MTHCA_MAILBOX_SIZE 4096 + +enum { + /* command completed successfully: */ + MTHCA_CMD_STAT_OK = 0x00, + /* Internal error (such as a bus error) occurred while processing command: */ + MTHCA_CMD_STAT_INTERNAL_ERR = 0x01, + /* Operation/command not supported or opcode modifier not supported: */ + MTHCA_CMD_STAT_BAD_OP = 0x02, + /* Parameter not supported or parameter out of range: */ + MTHCA_CMD_STAT_BAD_PARAM = 0x03, + /* System not enabled or bad system state: */ + MTHCA_CMD_STAT_BAD_SYS_STATE = 0x04, + /* Attempt to access reserved or unallocaterd resource: */ + MTHCA_CMD_STAT_BAD_RESOURCE = 0x05, + /* Requested resource is currently executing a command, or is otherwise busy: */ + MTHCA_CMD_STAT_RESOURCE_BUSY = 0x06, + /* memory error: */ + MTHCA_CMD_STAT_DDR_MEM_ERR = 0x07, + /* Required capability exceeds device limits: */ + MTHCA_CMD_STAT_EXCEED_LIM = 0x08, + /* Resource is not in the appropriate state or ownership: */ + MTHCA_CMD_STAT_BAD_RES_STATE = 0x09, + /* Index out of range: */ + MTHCA_CMD_STAT_BAD_INDEX = 0x0a, + /* FW image corrupted: */ + MTHCA_CMD_STAT_BAD_NVMEM = 0x0b, + /* Attempt to modify a QP/EE which is not in the presumed state: */ + MTHCA_CMD_STAT_BAD_QPEE_STATE = 0x10, + /* Bad segment parameters (Address/Size): */ + MTHCA_CMD_STAT_BAD_SEG_PARAM = 0x20, + /* Memory Region has Memory Windows bound to: */ + MTHCA_CMD_STAT_REG_BOUND = 0x21, + /* HCA local attached memory not present: */ + MTHCA_CMD_STAT_LAM_NOT_PRE = 0x22, + /* Bad management packet (silently discarded): */ + MTHCA_CMD_STAT_BAD_PKT = 0x30, + /* More outstanding CQEs in CQ than new CQ size: */ + MTHCA_CMD_STAT_BAD_SIZE = 0x40 +}; + +enum { + MTHCA_TRANS_INVALID = 0, + MTHCA_TRANS_RST2INIT, + MTHCA_TRANS_INIT2INIT, + MTHCA_TRANS_INIT2RTR, + MTHCA_TRANS_RTR2RTS, + MTHCA_TRANS_RTS2RTS, + MTHCA_TRANS_SQERR2RTS, + MTHCA_TRANS_ANY2ERR, + MTHCA_TRANS_RTS2SQD, + MTHCA_TRANS_SQD2SQD, + MTHCA_TRANS_SQD2RTS, + MTHCA_TRANS_ANY2RST, +}; + +enum { + DEV_LIM_FLAG_RC = 1 << 0, + DEV_LIM_FLAG_UC = 1 << 1, + DEV_LIM_FLAG_UD = 1 << 2, + DEV_LIM_FLAG_RD = 1 << 3, + DEV_LIM_FLAG_RAW_IPV6 = 1 << 4, + DEV_LIM_FLAG_RAW_ETHER = 1 << 5, + DEV_LIM_FLAG_SRQ = 1 << 6, + DEV_LIM_FLAG_IPOIB_CSUM = 1 << 7, + DEV_LIM_FLAG_BAD_PKEY_CNTR = 1 << 8, + DEV_LIM_FLAG_BAD_QKEY_CNTR = 1 << 9, + DEV_LIM_FLAG_MW = 1 << 16, + DEV_LIM_FLAG_AUTO_PATH_MIG = 1 << 17, + DEV_LIM_FLAG_ATOMIC = 1 << 18, + DEV_LIM_FLAG_RAW_MULTI = 1 << 19, + DEV_LIM_FLAG_UD_AV_PORT_ENFORCE = 1 << 20, + DEV_LIM_FLAG_UD_MULTI = 1 << 21, +}; + +struct mthca_mailbox { + dma_addr_t dma; + void *buf; +}; + +struct mthca_dev_lim { + int max_srq_sz; + int max_qp_sz; + int reserved_qps; + int max_qps; + int reserved_srqs; + int max_srqs; + int reserved_eecs; + int max_eecs; + int max_cq_sz; + int reserved_cqs; + int max_cqs; + int max_mpts; + int reserved_eqs; + int max_eqs; + int reserved_mtts; + int max_mrw_sz; + int reserved_mrws; + int max_mtt_seg; + int max_requester_per_qp; + int max_responder_per_qp; + int max_rdma_global; + int local_ca_ack_delay; + int max_mtu; + int max_port_width; + int max_vl; + int num_ports; + int max_gids; + int max_pkeys; + u32 flags; + int reserved_uars; + int uar_size; + int min_page_sz; + int max_sg; + int max_desc_sz; + int max_qp_per_mcg; + int reserved_mgms; + int max_mcgs; + int reserved_pds; + int max_pds; + int reserved_rdds; + int max_rdds; + int eec_entry_sz; + int qpc_entry_sz; + int eeec_entry_sz; + int eqpc_entry_sz; + int eqc_entry_sz; + int cqc_entry_sz; + int srq_entry_sz; + int uar_scratch_entry_sz; + int mpt_entry_sz; + union { + struct { + u64 max_avs; + } tavor; + struct { + int resize_srq; + int max_pbl_sz; + u8 bmme_flags; + u32 reserved_lkey; + int lam_required; + u64 max_icm_sz; + } arbel; + } hca; +}; + +struct mthca_adapter { + u32 vendor_id; + u32 device_id; + u32 revision_id; + char board_id[MTHCA_BOARD_ID_LEN]; + u8 inta_pin; +}; + +struct mthca_init_hca_param { + u64 qpc_base; + u64 eec_base; + u64 srqc_base; + u64 cqc_base; + u64 eqpc_base; + u64 eeec_base; + u64 eqc_base; + u64 rdb_base; + u64 mc_base; + u64 mpt_base; + u64 mtt_base; + u64 uar_scratch_base; + u64 uarc_base; + u16 log_mc_entry_sz; + u16 mc_hash_sz; + u8 log_num_qps; + u8 log_num_eecs; + u8 log_num_srqs; + u8 log_num_cqs; + u8 log_num_eqs; + u8 log_mc_table_sz; + u8 mtt_seg_sz; + u8 log_mpt_sz; + u8 log_uar_sz; + u8 log_uarc_sz; +}; + +struct mthca_init_ib_param { + int port_width; + int vl_cap; + int mtu_cap; + u16 gid_cap; + u16 pkey_cap; + int set_guid0; + u64 guid0; + int set_node_guid; + u64 node_guid; + int set_si_guid; + u64 si_guid; +}; + +struct mthca_set_ib_param { + int set_si_guid; + int reset_qkey_viol; + u64 si_guid; + u32 cap_mask; +}; + +int mthca_cmd_init(struct mthca_dev *dev); +void mthca_cmd_cleanup(struct mthca_dev *dev); +int mthca_cmd_use_events(struct mthca_dev *dev); +void mthca_cmd_use_polling(struct mthca_dev *dev); +void mthca_cmd_event(struct mthca_dev *dev, u16 token, + u8 status, u64 out_param); + +struct mthca_mailbox *mthca_alloc_mailbox(struct mthca_dev *dev, + unsigned int gfp_mask); +void mthca_free_mailbox(struct mthca_dev *dev, struct mthca_mailbox *mailbox); + +int mthca_SYS_EN(struct mthca_dev *dev, u8 *status); +int mthca_SYS_DIS(struct mthca_dev *dev, u8 *status); +int mthca_MAP_FA(struct mthca_dev *dev, struct mthca_icm *icm, u8 *status); +int mthca_UNMAP_FA(struct mthca_dev *dev, u8 *status); +int mthca_RUN_FW(struct mthca_dev *dev, u8 *status); +int mthca_QUERY_FW(struct mthca_dev *dev, u8 *status); +int mthca_ENABLE_LAM(struct mthca_dev *dev, u8 *status); +int mthca_DISABLE_LAM(struct mthca_dev *dev, u8 *status); +int mthca_QUERY_DDR(struct mthca_dev *dev, u8 *status); +int mthca_QUERY_DEV_LIM(struct mthca_dev *dev, + struct mthca_dev_lim *dev_lim, u8 *status); +int mthca_QUERY_ADAPTER(struct mthca_dev *dev, + struct mthca_adapter *adapter, u8 *status); +int mthca_INIT_HCA(struct mthca_dev *dev, + struct mthca_init_hca_param *param, + u8 *status); +int mthca_INIT_IB(struct mthca_dev *dev, + struct mthca_init_ib_param *param, + int port, u8 *status); +int mthca_CLOSE_IB(struct mthca_dev *dev, int port, u8 *status); +int mthca_CLOSE_HCA(struct mthca_dev *dev, int panic, u8 *status); +int mthca_SET_IB(struct mthca_dev *dev, struct mthca_set_ib_param *param, + int port, u8 *status); +int mthca_MAP_ICM(struct mthca_dev *dev, struct mthca_icm *icm, u64 virt, u8 *status); +int mthca_MAP_ICM_page(struct mthca_dev *dev, u64 dma_addr, u64 virt, u8 *status); +int mthca_UNMAP_ICM(struct mthca_dev *dev, u64 virt, u32 page_count, u8 *status); +int mthca_MAP_ICM_AUX(struct mthca_dev *dev, struct mthca_icm *icm, u8 *status); +int mthca_UNMAP_ICM_AUX(struct mthca_dev *dev, u8 *status); +int mthca_SET_ICM_SIZE(struct mthca_dev *dev, u64 icm_size, u64 *aux_pages, + u8 *status); +int mthca_SW2HW_MPT(struct mthca_dev *dev, struct mthca_mailbox *mailbox, + int mpt_index, u8 *status); +int mthca_HW2SW_MPT(struct mthca_dev *dev, struct mthca_mailbox *mailbox, + int mpt_index, u8 *status); +int mthca_WRITE_MTT(struct mthca_dev *dev, struct mthca_mailbox *mailbox, + int num_mtt, u8 *status); +int mthca_SYNC_TPT(struct mthca_dev *dev, u8 *status); +int mthca_MAP_EQ(struct mthca_dev *dev, u64 event_mask, int unmap, + int eq_num, u8 *status); +int mthca_SW2HW_EQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox, + int eq_num, u8 *status); +int mthca_HW2SW_EQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox, + int eq_num, u8 *status); +int mthca_SW2HW_CQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox, + int cq_num, u8 *status); +int mthca_HW2SW_CQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox, + int cq_num, u8 *status); +int mthca_SW2HW_SRQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox, + int srq_num, u8 *status); +int mthca_HW2SW_SRQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox, + int srq_num, u8 *status); +int mthca_QUERY_SRQ(struct mthca_dev *dev, u32 num, + struct mthca_mailbox *mailbox, u8 *status); +int mthca_ARM_SRQ(struct mthca_dev *dev, int srq_num, int limit, u8 *status); +int mthca_MODIFY_QP(struct mthca_dev *dev, int trans, u32 num, + int is_ee, struct mthca_mailbox *mailbox, u32 optmask, + u8 *status); +int mthca_QUERY_QP(struct mthca_dev *dev, u32 num, int is_ee, + struct mthca_mailbox *mailbox, u8 *status); +int mthca_CONF_SPECIAL_QP(struct mthca_dev *dev, int type, u32 qpn, + u8 *status); +int mthca_MAD_IFC(struct mthca_dev *dev, int ignore_mkey, int ignore_bkey, + int port, struct _ib_wc *in_wc, struct _ib_grh *in_grh, + void *in_mad, void *response_mad, u8 *status); +int mthca_READ_MGM(struct mthca_dev *dev, int index, + struct mthca_mailbox *mailbox, u8 *status); +int mthca_WRITE_MGM(struct mthca_dev *dev, int index, + struct mthca_mailbox *mailbox, u8 *status); +int mthca_MGID_HASH(struct mthca_dev *dev, struct mthca_mailbox *mailbox, + u16 *hash, u8 *status); +int mthca_NOP(struct mthca_dev *dev, u8 *status); + +#endif /* MTHCA_CMD_H */ diff --git a/branches/WOF2-3/hw/mthca/kernel/mthca_config_reg.h b/branches/WOF2-3/hw/mthca/kernel/mthca_config_reg.h new file mode 100644 index 00000000..9ff4a97a --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/mthca_config_reg.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2004 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#ifndef MTHCA_CONFIG_REG_H +#define MTHCA_CONFIG_REG_H + +#define MTHCA_HCR_BASE 0x80680 +#define MTHCA_HCR_SIZE 0x0001c +#define MTHCA_ECR_BASE 0x80700 +#define MTHCA_ECR_SIZE 0x00008 +#define MTHCA_ECR_CLR_BASE 0x80708 +#define MTHCA_ECR_CLR_SIZE 0x00008 +#define MTHCA_MAP_ECR_SIZE (MTHCA_ECR_SIZE + MTHCA_ECR_CLR_SIZE) +#define MTHCA_CLR_INT_BASE 0xf00d8 +#define MTHCA_CLR_INT_SIZE 0x00008 +#define MTHCA_EQ_SET_CI_SIZE (8 * 32) + +#endif /* MTHCA_CONFIG_REG_H */ diff --git a/branches/WOF2-3/hw/mthca/kernel/mthca_cq.c b/branches/WOF2-3/hw/mthca/kernel/mthca_cq.c new file mode 100644 index 00000000..ff9be740 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/mthca_cq.c @@ -0,0 +1,989 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2005 Cisco Systems, Inc. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * Copyright (c) 2004 Voltaire, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include + +#include "mthca_dev.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "mthca_cq.tmh" +#endif +#include "mthca_cmd.h" +#include "mthca_memfree.h" +#include "mthca_wqe.h" + +enum { + MTHCA_MAX_DIRECT_CQ_SIZE = 4 * PAGE_SIZE +}; + +/* + * Must be packed because start is 64 bits but only aligned to 32 bits. + */ +#pragma pack(push,1) +struct mthca_cq_context { + __be32 flags; + __be64 start; + __be32 logsize_usrpage; + __be32 error_eqn; /* Tavor only */ + __be32 comp_eqn; + __be32 pd; + __be32 lkey; + __be32 last_notified_index; + __be32 solicit_producer_index; + __be32 consumer_index; + __be32 producer_index; + __be32 cqn; + __be32 ci_db; /* Arbel only */ + __be32 state_db; /* Arbel only */ + u32 reserved; +}; +#pragma pack(pop) + +#define MTHCA_CQ_STATUS_OK ( 0 << 28) +#define MTHCA_CQ_STATUS_OVERFLOW ( 9 << 28) +#define MTHCA_CQ_STATUS_WRITE_FAIL (10 << 28) +#define MTHCA_CQ_FLAG_TR ( 1 << 18) +#define MTHCA_CQ_FLAG_OI ( 1 << 17) +#define MTHCA_CQ_STATE_DISARMED ( 0 << 8) +#define MTHCA_CQ_STATE_ARMED ( 1 << 8) +#define MTHCA_CQ_STATE_ARMED_SOL ( 4 << 8) +#define MTHCA_EQ_STATE_FIRED (10 << 8) + +enum { + MTHCA_ERROR_CQE_OPCODE_MASK = 0xfe +}; + +enum { + SYNDROME_LOCAL_LENGTH_ERR = 0x01, + SYNDROME_LOCAL_QP_OP_ERR = 0x02, + SYNDROME_LOCAL_EEC_OP_ERR = 0x03, + SYNDROME_LOCAL_PROT_ERR = 0x04, + SYNDROME_WR_FLUSH_ERR = 0x05, + SYNDROME_MW_BIND_ERR = 0x06, + SYNDROME_BAD_RESP_ERR = 0x10, + SYNDROME_LOCAL_ACCESS_ERR = 0x11, + SYNDROME_REMOTE_INVAL_REQ_ERR = 0x12, + SYNDROME_REMOTE_ACCESS_ERR = 0x13, + SYNDROME_REMOTE_OP_ERR = 0x14, + SYNDROME_RETRY_EXC_ERR = 0x15, + SYNDROME_RNR_RETRY_EXC_ERR = 0x16, + SYNDROME_LOCAL_RDD_VIOL_ERR = 0x20, + SYNDROME_REMOTE_INVAL_RD_REQ_ERR = 0x21, + SYNDROME_REMOTE_ABORTED_ERR = 0x22, + SYNDROME_INVAL_EECN_ERR = 0x23, + SYNDROME_INVAL_EEC_STATE_ERR = 0x24 +}; + +enum { + MTHCA_NdisPacketTcpChecksumFailed = 1 << 0, + MTHCA_NdisPacketUdpChecksumFailed = 1 << 1, + MTHCA_NdisPacketIpChecksumFailed = 1 << 2, + MTHCA_NdisPacketTcpChecksumSucceeded = 1 << 3, + MTHCA_NdisPacketUdpChecksumSucceeded = 1 << 4, + MTHCA_NdisPacketIpChecksumSucceeded = 1 << 5 +}; + +struct mthca_cqe { + __be32 my_qpn; + __be32 my_ee; + __be32 rqpn; + u8 sl_ipok; + u8 g_mlpath; + __be16 rlid; + __be32 imm_etype_pkey_eec; + __be32 byte_cnt; + __be32 wqe; + u8 opcode; + u8 is_send; + u8 reserved; + u8 owner; +}; + +struct mthca_err_cqe { + __be32 my_qpn; + u32 reserved1[3]; + u8 syndrome; + u8 vendor_err; + __be16 db_cnt; + u32 reserved2; + __be32 wqe; + u8 opcode; + u8 reserved3[2]; + u8 owner; +}; + +#define MTHCA_CQ_ENTRY_OWNER_SW (0 << 7) +#define MTHCA_CQ_ENTRY_OWNER_HW (1 << 7) + +#define MTHCA_TAVOR_CQ_DB_INC_CI (1 << 24) +#define MTHCA_TAVOR_CQ_DB_REQ_NOT (2 << 24) +#define MTHCA_TAVOR_CQ_DB_REQ_NOT_SOL (3 << 24) +#define MTHCA_TAVOR_CQ_DB_SET_CI (4 << 24) +#define MTHCA_TAVOR_CQ_DB_REQ_NOT_MULT (5 << 24) + +#define MTHCA_ARBEL_CQ_DB_REQ_NOT_SOL (1 << 24) +#define MTHCA_ARBEL_CQ_DB_REQ_NOT (2 << 24) +#define MTHCA_ARBEL_CQ_DB_REQ_NOT_MULT (3 << 24) + +static inline struct mthca_cqe *get_cqe(struct mthca_cq *cq, int entry) +{ + if (cq->is_direct) + return (struct mthca_cqe *)((u8*)cq->queue.direct.page + (entry * MTHCA_CQ_ENTRY_SIZE)); + else + return (struct mthca_cqe *)((u8*)cq->queue.page_list[entry * MTHCA_CQ_ENTRY_SIZE / PAGE_SIZE].page + + (entry * MTHCA_CQ_ENTRY_SIZE) % PAGE_SIZE); +} + +static inline struct mthca_cqe *cqe_sw(struct mthca_cq *cq, int i) +{ + struct mthca_cqe *cqe = get_cqe(cq, i); + return MTHCA_CQ_ENTRY_OWNER_HW & cqe->owner ? NULL : cqe; +} + +static inline struct mthca_cqe *next_cqe_sw(struct mthca_cq *cq) +{ + return cqe_sw(cq, cq->cons_index & cq->ibcq.cqe); +} + +static inline void set_cqe_hw(struct mthca_cqe *cqe) +{ + cqe->owner = MTHCA_CQ_ENTRY_OWNER_HW; +} + +static void dump_cqe(u32 print_lvl, struct mthca_dev *dev, void *cqe_ptr) +{ + __be32 *cqe = cqe_ptr; + UNREFERENCED_PARAMETER(dev); + UNUSED_PARAM_WOWPP(print_lvl); + + (void) cqe; /* avoid warning if mthca_dbg compiled away... */ + HCA_PRINT(print_lvl,HCA_DBG_CQ,("CQE contents \n")); + HCA_PRINT(print_lvl,HCA_DBG_CQ,("\t[%2x] %08x %08x %08x %08x\n",0, + cl_ntoh32(cqe[0]), cl_ntoh32(cqe[1]), cl_ntoh32(cqe[2]), cl_ntoh32(cqe[3]))); + HCA_PRINT(print_lvl,HCA_DBG_CQ,("\t[%2x] %08x %08x %08x %08x \n",16, + cl_ntoh32(cqe[4]), cl_ntoh32(cqe[5]), cl_ntoh32(cqe[6]), cl_ntoh32(cqe[7]))); +} + +/* + * incr is ignored in native Arbel (mem-free) mode, so cq->cons_index + * should be correct before calling update_cons_index(). + */ +static inline void update_cons_index(struct mthca_dev *dev, struct mthca_cq *cq, + int incr) +{ + __be32 doorbell[2]; + + if (mthca_is_memfree(dev)) { + *cq->set_ci_db = cl_hton32(cq->cons_index); + wmb(); + } else { + doorbell[0] = cl_hton32(MTHCA_TAVOR_CQ_DB_INC_CI | cq->cqn); + doorbell[1] = cl_hton32(incr - 1); + + mthca_write64(doorbell, + dev->kar + MTHCA_CQ_DOORBELL, + MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock)); + } +} + +void mthca_cq_completion(struct mthca_dev *dev, u32 cqn) +{ + struct mthca_cq *cq; + + cq = mthca_array_get(&dev->cq_table.cq, cqn & (dev->limits.num_cqs - 1)); + + if (!cq) { + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_LOW ,("Completion event for bogus CQ %08x\n", cqn)); + return; + } + + if (mthca_is_memfree(dev)) { + if (cq->ibcq.ucontext) + ++*cq->p_u_arm_sn; + else + ++cq->arm_sn; + } + + cq->ibcq.comp_handler(cq->ibcq.cq_context); +} + +void mthca_cq_event(struct mthca_dev *dev, u32 cqn, + enum ib_event_type event_type) +{ + struct mthca_cq *cq; + ib_event_rec_t event; + SPIN_LOCK_PREP(lh); + + spin_lock(&dev->cq_table.lock, &lh); + + cq = mthca_array_get(&dev->cq_table.cq, cqn & (dev->limits.num_cqs - 1)); + + if (cq) + atomic_inc(&cq->refcount); + spin_unlock(&lh); + + if (!cq) { + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_LOW ,("Async event for bogus CQ %08x\n", cqn)); + return; + } + + event.type = event_type; + event.context = cq->ibcq.cq_context; + event.vendor_specific = 0; + cq->ibcq.event_handler(&event); + + if (atomic_dec_and_test(&cq->refcount)) + wake_up(&cq->wait); +} + +void mthca_cq_clean(struct mthca_dev *dev, u32 cqn, u32 qpn, + struct mthca_srq *srq) +{ + struct mthca_cq *cq; + struct mthca_cqe *cqe; + u32 prod_index; + int nfreed = 0; + SPIN_LOCK_PREP(lht); + SPIN_LOCK_PREP(lh); + + spin_lock_irq(&dev->cq_table.lock, &lht); + cq = mthca_array_get(&dev->cq_table.cq, cqn & (dev->limits.num_cqs - 1)); + if (cq) + atomic_inc(&cq->refcount); + spin_unlock_irq(&lht); + + if (!cq) + return; + + spin_lock_irq(&cq->lock, &lh); + + /* + * First we need to find the current producer index, so we + * know where to start cleaning from. It doesn't matter if HW + * adds new entries after this loop -- the QP we're worried + * about is already in RESET, so the new entries won't come + * from our QP and therefore don't need to be checked. + */ + for (prod_index = cq->cons_index; + cqe_sw(cq, prod_index & cq->ibcq.cqe); + ++prod_index) { + if (prod_index == cq->cons_index + cq->ibcq.cqe) + break; + } + + HCA_PRINT(TRACE_LEVEL_VERBOSE,HCA_DBG_LOW,("Cleaning QPN %06x from CQN %06x; ci %d, pi %d\n", + qpn, cqn, cq->cons_index, prod_index)); + + /* + * Now sweep backwards through the CQ, removing CQ entries + * that match our QP by copying older entries on top of them. + */ + while ((int) --prod_index - (int) cq->cons_index >= 0) { + cqe = get_cqe(cq, prod_index & cq->ibcq.cqe); + if (cqe->my_qpn == cl_hton32(qpn)) { + if (srq) + mthca_free_srq_wqe(srq, cl_ntoh32(cqe->wqe)); + ++nfreed; + } + else + if (nfreed) { + memcpy(get_cqe(cq, (prod_index + nfreed) & cq->ibcq.cqe), + cqe, MTHCA_CQ_ENTRY_SIZE); + } + } + + if (nfreed) { + wmb(); + cq->cons_index += nfreed; + update_cons_index(dev, cq, nfreed); + } + + spin_unlock_irq(&lh); + if (atomic_dec_and_test(&cq->refcount)) + wake_up(&cq->wait); +} + +static void handle_error_cqe(struct mthca_dev *dev, struct mthca_cq *cq, + struct mthca_qp *qp, int wqe_index, int is_send, + struct mthca_err_cqe *cqe, + struct _ib_wc *entry, int *free_cqe) +{ + int dbd; + __be32 new_wqe; + + UNREFERENCED_PARAMETER(cq); + + if (cqe->syndrome != SYNDROME_WR_FLUSH_ERR) { + HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_CQ ,("Completion with errro " + "(QPN %06x, WQE @ %08x, CQN %06x, index %d)\n", + cl_ntoh32(cqe->my_qpn), cl_ntoh32(cqe->wqe), + cq->cqn, cq->cons_index)); + dump_cqe(TRACE_LEVEL_INFORMATION, dev, cqe); + } + + + /* + * For completions in error, only work request ID, status, vendor error + * (and freed resource count for RD) have to be set. + */ + switch (cqe->syndrome) { + case SYNDROME_LOCAL_LENGTH_ERR: + entry->status = IB_WCS_LOCAL_LEN_ERR; + break; + case SYNDROME_LOCAL_QP_OP_ERR: + entry->status = IB_WCS_LOCAL_OP_ERR; + break; + case SYNDROME_LOCAL_PROT_ERR: + entry->status = IB_WCS_LOCAL_PROTECTION_ERR; + break; + case SYNDROME_WR_FLUSH_ERR: + entry->status = IB_WCS_WR_FLUSHED_ERR; + break; + case SYNDROME_MW_BIND_ERR: + entry->status = IB_WCS_MEM_WINDOW_BIND_ERR; + break; + case SYNDROME_BAD_RESP_ERR: + entry->status = IB_WCS_BAD_RESP_ERR; + break; + case SYNDROME_LOCAL_ACCESS_ERR: + entry->status = IB_WCS_LOCAL_ACCESS_ERR; + break; + case SYNDROME_REMOTE_INVAL_REQ_ERR: + entry->status = IB_WCS_REM_INVALID_REQ_ERR; + break; + case SYNDROME_REMOTE_ACCESS_ERR: + entry->status = IB_WCS_REM_ACCESS_ERR; + break; + case SYNDROME_REMOTE_OP_ERR: + entry->status = IB_WCS_REM_OP_ERR; + break; + case SYNDROME_RETRY_EXC_ERR: + entry->status = IB_WCS_TIMEOUT_RETRY_ERR; + break; + case SYNDROME_RNR_RETRY_EXC_ERR: + entry->status = IB_WCS_RNR_RETRY_ERR; + break; + case SYNDROME_REMOTE_INVAL_RD_REQ_ERR: + entry->status = IB_WCS_REM_INVALID_REQ_ERR; + break; + case SYNDROME_REMOTE_ABORTED_ERR: + case SYNDROME_LOCAL_EEC_OP_ERR: + case SYNDROME_LOCAL_RDD_VIOL_ERR: + case SYNDROME_INVAL_EECN_ERR: + case SYNDROME_INVAL_EEC_STATE_ERR: + default: + entry->status = IB_WCS_GENERAL_ERR; + break; + } + + entry->vendor_specific = cqe->vendor_err; + + /* + * Mem-free HCAs always generate one CQE per WQE, even in the + * error case, so we don't have to check the doorbell count, etc. + */ + if (mthca_is_memfree(dev)) + return; + + mthca_free_err_wqe(dev, qp, is_send, wqe_index, &dbd, &new_wqe); + + /* + * If we're at the end of the WQE chain, or we've used up our + * doorbell count, free the CQE. Otherwise just update it for + * the next poll operation. + */ + if (!(new_wqe & cl_hton32(0x3f)) || (!cqe->db_cnt && dbd)) + return; + + cqe->db_cnt = cl_hton16(cl_ntoh16(cqe->db_cnt) - (u16)dbd); + cqe->wqe = new_wqe; + cqe->syndrome = SYNDROME_WR_FLUSH_ERR; + + *free_cqe = 0; +} + +static inline uint32_t mthca_ib_ipoib_csum_ok(u16 checksum, u8 ip_ok) { + + #define CSUM_VALID_NUM 0xffff + uint32_t res = 0; + + // Verify that IP_OK bit is set and the packet is pure IPv4 packet + if (ip_ok) + { + // IP checksum calculated by MLX4 matched the checksum in the receive packet's + res |= MTHCA_NdisPacketIpChecksumSucceeded; + if (checksum == CSUM_VALID_NUM) { + // TCP or UDP checksum calculated by MTHCA matched the checksum in the receive packet's + res |= (MTHCA_NdisPacketUdpChecksumSucceeded | + MTHCA_NdisPacketTcpChecksumSucceeded ); + } + } + return ( ( res << 8 ) & IB_RECV_OPT_CSUM_MASK ); +} + +static inline int mthca_poll_one(struct mthca_dev *dev, + struct mthca_cq *cq, + struct mthca_qp **cur_qp, + int *freed, + struct _ib_wc *entry) +{ + struct mthca_wq *wq; + struct mthca_cqe *cqe; + unsigned wqe_index; + int is_error; + int is_send; + int free_cqe = 1; + int err = 0; + u16 checksum; + + HCA_ENTER(HCA_DBG_CQ); + cqe = next_cqe_sw(cq); + if (!cqe) + return -EAGAIN; + + /* + * Make sure we read CQ entry contents after we've checked the + * ownership bit. + */ + rmb(); + + { // debug print + HCA_PRINT(TRACE_LEVEL_VERBOSE,HCA_DBG_CQ,("CQ: 0x%06x/%d: CQE -> QPN 0x%06x, WQE @ 0x%08x\n", + cq->cqn, cq->cons_index, cl_ntoh32(cqe->my_qpn), + cl_ntoh32(cqe->wqe))); + dump_cqe(TRACE_LEVEL_VERBOSE, dev, cqe); + } + + is_error = (cqe->opcode & MTHCA_ERROR_CQE_OPCODE_MASK) == + MTHCA_ERROR_CQE_OPCODE_MASK; + is_send = is_error ? cqe->opcode & 0x01 : cqe->is_send & 0x80; + + if (!*cur_qp || cl_ntoh32(cqe->my_qpn) != (*cur_qp)->qpn) { + /* + * We do not have to take the QP table lock here, + * because CQs will be locked while QPs are removed + * from the table. + */ + *cur_qp = mthca_array_get(&dev->qp_table.qp, + cl_ntoh32(cqe->my_qpn) & + (dev->limits.num_qps - 1)); + if (!*cur_qp) { + HCA_PRINT(TRACE_LEVEL_WARNING,HCA_DBG_CQ, ("CQ entry for unknown QP %06x\n", + cl_ntoh32(cqe->my_qpn) & 0xffffff)); + err = -EINVAL; + goto out; + } + } + + if (is_send) { + wq = &(*cur_qp)->sq; + wqe_index = ((cl_ntoh32(cqe->wqe) - (*cur_qp)->send_wqe_offset) + >> wq->wqe_shift); + entry->wr_id = (*cur_qp)->wrid[wqe_index + + (*cur_qp)->rq.max]; + } else if ((*cur_qp)->ibqp.srq) { + struct mthca_srq *srq = to_msrq((*cur_qp)->ibqp.srq); + u32 wqe = cl_ntoh32(cqe->wqe); + wq = NULL; + wqe_index = wqe >> srq->wqe_shift; + entry->wr_id = srq->wrid[wqe_index]; + mthca_free_srq_wqe(srq, wqe); + } else { + wq = &(*cur_qp)->rq; + wqe_index = cl_ntoh32(cqe->wqe) >> wq->wqe_shift; + entry->wr_id = (*cur_qp)->wrid[wqe_index]; + } + + if (wq) { + if (wq->last_comp < wqe_index) + wq->tail += wqe_index - wq->last_comp; + else + wq->tail += wqe_index + wq->max - wq->last_comp; + + wq->last_comp = wqe_index; + } + + if (is_send) { + entry->recv.ud.recv_opt = 0; + switch (cqe->opcode) { + case MTHCA_OPCODE_RDMA_WRITE: + entry->wc_type = IB_WC_RDMA_WRITE; + break; + case MTHCA_OPCODE_RDMA_WRITE_IMM: + entry->wc_type = IB_WC_RDMA_WRITE; + entry->recv.ud.recv_opt |= IB_RECV_OPT_IMMEDIATE; + break; + case MTHCA_OPCODE_SEND: + entry->wc_type = IB_WC_SEND; + break; + case MTHCA_OPCODE_SEND_IMM: + entry->wc_type = IB_WC_SEND; + entry->recv.ud.recv_opt |= IB_RECV_OPT_IMMEDIATE; + break; + case MTHCA_OPCODE_RDMA_READ: + entry->wc_type = IB_WC_RDMA_READ; + entry->length = cl_ntoh32(cqe->byte_cnt); + break; + case MTHCA_OPCODE_ATOMIC_CS: + entry->wc_type = IB_WC_COMPARE_SWAP; + entry->length = MTHCA_BYTES_PER_ATOMIC_COMPL; + break; + case MTHCA_OPCODE_ATOMIC_FA: + entry->wc_type = IB_WC_FETCH_ADD; + entry->length = MTHCA_BYTES_PER_ATOMIC_COMPL; + break; + case MTHCA_OPCODE_BIND_MW: + entry->wc_type = IB_WC_MW_BIND; + break; + default: + entry->wc_type = IB_WC_SEND; + break; + } + } else { + entry->length = cl_ntoh32(cqe->byte_cnt); + switch (cqe->opcode & 0x1f) { + case IB_OPCODE_SEND_LAST_WITH_IMMEDIATE: + case IB_OPCODE_SEND_ONLY_WITH_IMMEDIATE: + entry->recv.ud.recv_opt = IB_RECV_OPT_IMMEDIATE; + entry->recv.ud.immediate_data = cqe->imm_etype_pkey_eec; + entry->wc_type = IB_WC_RECV; + break; + case IB_OPCODE_RDMA_WRITE_LAST_WITH_IMMEDIATE: + case IB_OPCODE_RDMA_WRITE_ONLY_WITH_IMMEDIATE: + entry->recv.ud.recv_opt = IB_RECV_OPT_IMMEDIATE; + entry->recv.ud.immediate_data = cqe->imm_etype_pkey_eec; + entry->wc_type = IB_WC_RECV_RDMA_WRITE; + break; + default: + entry->recv.ud.recv_opt = 0; + entry->wc_type = IB_WC_RECV; + break; + } + entry->recv.ud.remote_lid = cqe->rlid; + entry->recv.ud.remote_qp = cqe->rqpn & 0xffffff00; + entry->recv.ud.pkey_index = (u16)(cl_ntoh32(cqe->imm_etype_pkey_eec) >> 16); + entry->recv.ud.remote_sl = cqe->sl_ipok >> 4; + entry->recv.ud.path_bits = (uint8_t)(cqe->g_mlpath & 0x7f); + entry->recv.ud.recv_opt |= cqe->g_mlpath & 0x80 ? IB_RECV_OPT_GRH_VALID : 0; + checksum = (u16)((cl_ntoh32(cqe->rqpn) >> 24) | + ((cl_ntoh32(cqe->my_ee) >> 16) & 0xff00)); + entry->recv.ud.recv_opt |= mthca_ib_ipoib_csum_ok(checksum, cqe->sl_ipok & 1); + } + if (!is_send && cqe->rlid == 0){ + HCA_PRINT(TRACE_LEVEL_INFORMATION,HCA_DBG_CQ,("found rlid == 0 \n ")); + entry->recv.ud.recv_opt |= IB_RECV_OPT_FORWARD; + + } + if (is_error) { + handle_error_cqe(dev, cq, *cur_qp, wqe_index, is_send, + (struct mthca_err_cqe *) cqe, entry, &free_cqe); + } + else + entry->status = IB_WCS_SUCCESS; + + out: + if (likely(free_cqe)) { + set_cqe_hw(cqe); + ++(*freed); + ++cq->cons_index; + } + HCA_EXIT(HCA_DBG_CQ); + return err; +} + +int mthca_poll_cq(struct ib_cq *ibcq, int num_entries, + struct _ib_wc *entry) +{ + struct mthca_dev *dev = to_mdev(ibcq->device); + struct mthca_cq *cq = to_mcq(ibcq); + struct mthca_qp *qp = NULL; + int err = 0; + int freed = 0; + int npolled; + SPIN_LOCK_PREP(lh); + + spin_lock_irqsave(&cq->lock, &lh); + + for (npolled = 0; npolled < num_entries; ++npolled) { + err = mthca_poll_one(dev, cq, &qp, + &freed, entry + npolled); + if (err) + break; + } + + if (freed) { + wmb(); + update_cons_index(dev, cq, freed); + } + + spin_unlock_irqrestore(&lh); + + return (err == 0 || err == -EAGAIN) ? npolled : err; +} + +int mthca_poll_cq_list( + IN struct ib_cq *ibcq, + IN OUT ib_wc_t** const pp_free_wclist, + OUT ib_wc_t** const pp_done_wclist ) +{ + struct mthca_dev *dev = to_mdev(ibcq->device); + struct mthca_cq *cq = to_mcq(ibcq); + struct mthca_qp *qp = NULL; + int err = 0; + int freed = 0; + ib_wc_t *wc_p, **next_pp; + SPIN_LOCK_PREP(lh); + + HCA_ENTER(HCA_DBG_CQ); + + spin_lock_irqsave(&cq->lock, &lh); + + // loop through CQ + next_pp = pp_done_wclist; + wc_p = *pp_free_wclist; + while( wc_p ) { + // poll one CQE + err = mthca_poll_one(dev, cq, &qp, &freed, wc_p); + if (err) + break; + + // prepare for the next loop + *next_pp = wc_p; + next_pp = &wc_p->p_next; + wc_p = wc_p->p_next; + } + + // prepare the results + *pp_free_wclist = wc_p; /* Set the head of the free list. */ + *next_pp = NULL; /* Clear the tail of the done list. */ + + // update consumer index + if (freed) { + wmb(); + update_cons_index(dev, cq, freed); + } + + spin_unlock_irqrestore(&lh); + HCA_EXIT(HCA_DBG_CQ); + return (err == 0 || err == -EAGAIN)? 0 : err; +} + + +int mthca_tavor_arm_cq(struct ib_cq *cq, enum ib_cq_notify notify) +{ + __be32 doorbell[2]; + + doorbell[0] = cl_hton32((notify == IB_CQ_SOLICITED ? + MTHCA_TAVOR_CQ_DB_REQ_NOT_SOL : + MTHCA_TAVOR_CQ_DB_REQ_NOT) | + to_mcq(cq)->cqn); + doorbell[1] = (__be32) 0xffffffff; + + mthca_write64(doorbell, + to_mdev(cq->device)->kar + MTHCA_CQ_DOORBELL, + MTHCA_GET_DOORBELL_LOCK(&to_mdev(cq->device)->doorbell_lock)); + + return 0; +} + +int mthca_arbel_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify notify) +{ + struct mthca_cq *cq = to_mcq(ibcq); + __be32 doorbell[2]; + u32 sn; + __be32 ci; + + sn = cq->arm_sn & 3; + ci = cl_hton32(cq->cons_index); + + doorbell[0] = ci; + doorbell[1] = cl_hton32((cq->cqn << 8) | (2 << 5) | (sn << 3) | + (notify == IB_CQ_SOLICITED ? 1 : 2)); + + mthca_write_db_rec(doorbell, cq->arm_db); + + /* + * Make sure that the doorbell record in host memory is + * written before ringing the doorbell via PCI MMIO. + */ + wmb(); + + doorbell[0] = cl_hton32((sn << 28) | + (notify == IB_CQ_SOLICITED ? + MTHCA_ARBEL_CQ_DB_REQ_NOT_SOL : + MTHCA_ARBEL_CQ_DB_REQ_NOT) | + cq->cqn); + doorbell[1] = ci; + + mthca_write64(doorbell, + to_mdev(ibcq->device)->kar + MTHCA_CQ_DOORBELL, + MTHCA_GET_DOORBELL_LOCK(&to_mdev(ibcq->device)->doorbell_lock)); + + return 0; +} + +static void mthca_free_cq_buf(struct mthca_dev *dev, struct mthca_cq *cq) +{ + mthca_buf_free(dev, (cq->ibcq.cqe + 1) * MTHCA_CQ_ENTRY_SIZE, + &cq->queue, cq->is_direct, &cq->mr); +} + +int mthca_init_cq(struct mthca_dev *dev, int nent, + struct mthca_ucontext *ctx, u32 pdn, + struct mthca_cq *cq) +{ + int size = NEXT_PAGE_ALIGN(nent * MTHCA_CQ_ENTRY_SIZE ); + struct mthca_mailbox *mailbox; + struct mthca_cq_context *cq_context; + int err = -ENOMEM; + u8 status; + int i; + SPIN_LOCK_PREP(lh); + + cq->ibcq.cqe = nent - 1; + cq->is_kernel = !ctx; + + cq->cqn = mthca_alloc(&dev->cq_table.alloc); + if (cq->cqn == -1) + return -ENOMEM; + + if (mthca_is_memfree(dev)) { + err = mthca_table_get(dev, dev->cq_table.table, cq->cqn); + if (err) + goto err_out; + + if (cq->is_kernel) { + cq->arm_sn = 1; + + err = -ENOMEM; + + cq->set_ci_db_index = mthca_alloc_db(dev, MTHCA_DB_TYPE_CQ_SET_CI, + cq->cqn, &cq->set_ci_db); + if (cq->set_ci_db_index < 0) + goto err_out_icm; + + cq->arm_db_index = mthca_alloc_db(dev, MTHCA_DB_TYPE_CQ_ARM, + cq->cqn, &cq->arm_db); + if (cq->arm_db_index < 0) + goto err_out_ci; + } + } + + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (IS_ERR(mailbox)) + goto err_out_arm; + + cq_context = mailbox->buf; + + if (cq->is_kernel) { + err = mthca_buf_alloc(dev, size, MTHCA_MAX_DIRECT_CQ_SIZE, + &cq->queue, &cq->is_direct, + &dev->driver_pd, 1, &cq->mr); + if (err) + goto err_out_mailbox; + + for (i = 0; i < nent; ++i) + set_cqe_hw(get_cqe(cq, i)); + } + + spin_lock_init(&cq->lock); + atomic_set(&cq->refcount, 1); + init_waitqueue_head(&cq->wait); + KeInitializeMutex(&cq->mutex, 0); + + RtlZeroMemory(cq_context, sizeof *cq_context); + cq_context->flags = cl_hton32(MTHCA_CQ_STATUS_OK | + MTHCA_CQ_STATE_DISARMED | + MTHCA_CQ_FLAG_TR); + cq_context->logsize_usrpage = cl_hton32((ffs(nent) - 1) << 24); + if (ctx) + cq_context->logsize_usrpage |= cl_hton32(ctx->uar.index); + else + cq_context->logsize_usrpage |= cl_hton32(dev->driver_uar.index); + cq_context->error_eqn = cl_hton32(dev->eq_table.eq[MTHCA_EQ_ASYNC].eqn); + cq_context->comp_eqn = cl_hton32(dev->eq_table.eq[MTHCA_EQ_COMP].eqn); + cq_context->pd = cl_hton32(pdn); + cq_context->lkey = cl_hton32(cq->mr.ibmr.lkey); + cq_context->cqn = cl_hton32(cq->cqn); + + if (mthca_is_memfree(dev)) { + cq_context->ci_db = cl_hton32(cq->set_ci_db_index); + cq_context->state_db = cl_hton32(cq->arm_db_index); + } + + err = mthca_SW2HW_CQ(dev, mailbox, cq->cqn, &status); + if (err) { + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_LOW ,("SW2HW_CQ failed (%d)\n", err)); + goto err_out_free_mr; + } + + if (status) { + HCA_PRINT(TRACE_LEVEL_WARNING,HCA_DBG_LOW,("SW2HW_CQ returned status 0x%02x\n", + status)); + err = -EINVAL; + goto err_out_free_mr; + } + + spin_lock_irq(&dev->cq_table.lock, &lh); + if (mthca_array_set(&dev->cq_table.cq, + cq->cqn & (dev->limits.num_cqs - 1), + cq)) { + spin_unlock_irq(&lh); + goto err_out_free_mr; + } + spin_unlock_irq(&lh); + + cq->cons_index = 0; + + mthca_free_mailbox(dev, mailbox); + + return 0; + +err_out_free_mr: + if (cq->is_kernel) + mthca_free_cq_buf(dev, cq); + +err_out_mailbox: + mthca_free_mailbox(dev, mailbox); + +err_out_arm: + if (cq->is_kernel && mthca_is_memfree(dev)) + mthca_free_db(dev, MTHCA_DB_TYPE_CQ_ARM, cq->arm_db_index); + +err_out_ci: + if (cq->is_kernel && mthca_is_memfree(dev)) + mthca_free_db(dev, MTHCA_DB_TYPE_CQ_SET_CI, cq->set_ci_db_index); + +err_out_icm: + mthca_table_put(dev, dev->cq_table.table, cq->cqn); + +err_out: + mthca_free(&dev->cq_table.alloc, cq->cqn); + + return err; +} + +void mthca_free_cq(struct mthca_dev *dev, + struct mthca_cq *cq) +{ + struct mthca_mailbox *mailbox; + int err; + u8 status; + SPIN_LOCK_PREP(lh); + + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (IS_ERR(mailbox)) { + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_LOW ,("No memory for mailbox to free CQ.\n")); + return; + } + + err = mthca_HW2SW_CQ(dev, mailbox, cq->cqn, &status); + if (err){ + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_LOW ,("HW2SW_CQ failed (%d)\n", err)); + } + else if (status){ + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_LOW ,("HW2SW_CQ returned status 0x%02x\n", status)); + } + { // debug print + __be32 *ctx = mailbox->buf; + int j; + UNUSED_PARAM_WOWPP(ctx); + UNUSED_PARAM_WOWPP(j); + + HCA_PRINT(TRACE_LEVEL_VERBOSE ,HCA_DBG_LOW ,("context for CQN %x (cons index %x, next sw %d)\n", + cq->cqn, cq->cons_index, + cq->is_kernel ? !!next_cqe_sw(cq) : 0)); + for (j = 0; j < 16; ++j) + HCA_PRINT(TRACE_LEVEL_VERBOSE ,HCA_DBG_LOW ,("[%2x] %08x\n", j * 4, cl_ntoh32(ctx[j]))); + } + spin_lock_irq(&dev->cq_table.lock, &lh); + mthca_array_clear(&dev->cq_table.cq, + cq->cqn & (dev->limits.num_cqs - 1)); + spin_unlock_irq(&lh); + + /* wait for all RUNNING DPCs on that EQ to complete */ + ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); + KeFlushQueuedDpcs(); + + atomic_dec(&cq->refcount); + wait_event(&cq->wait, !atomic_read(&cq->refcount)); + + if (cq->is_kernel) { + mthca_free_cq_buf(dev, cq); + if (mthca_is_memfree(dev)) { + mthca_free_db(dev, MTHCA_DB_TYPE_CQ_ARM, cq->arm_db_index); + mthca_free_db(dev, MTHCA_DB_TYPE_CQ_SET_CI, cq->set_ci_db_index); + } + } + + mthca_table_put(dev, dev->cq_table.table, cq->cqn); + mthca_free(&dev->cq_table.alloc, cq->cqn); + mthca_free_mailbox(dev, mailbox); +} + +int mthca_init_cq_table(struct mthca_dev *dev) +{ + int err; + + spin_lock_init(&dev->cq_table.lock); + + err = mthca_alloc_init(&dev->cq_table.alloc, + dev->limits.num_cqs, + (1 << 24) - 1, + dev->limits.reserved_cqs); + if (err) + return err; + + err = mthca_array_init(&dev->cq_table.cq, + dev->limits.num_cqs); + if (err) + mthca_alloc_cleanup(&dev->cq_table.alloc); + + return err; +} + +void mthca_cleanup_cq_table(struct mthca_dev *dev) +{ + mthca_array_cleanup(&dev->cq_table.cq, dev->limits.num_cqs); + mthca_alloc_cleanup(&dev->cq_table.alloc); +} + + + diff --git a/branches/WOF2-3/hw/mthca/kernel/mthca_dev.h b/branches/WOF2-3/hw/mthca/kernel/mthca_dev.h new file mode 100644 index 00000000..013b0d63 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/mthca_dev.h @@ -0,0 +1,608 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2005 Cisco Systems. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * Copyright (c) 2004 Voltaire, Inc. All rights reserved. + * Copyright (c) 2006 SilverStorm Technologies, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#ifndef MTHCA_DEV_H +#define MTHCA_DEV_H + +#include "hca_driver.h" +#include "mthca_log.h" +#include "mthca_provider.h" +#include "mthca_doorbell.h" + +// must be synchronized with MTHCA.INF +#define DRV_NAME "mthca" +#define PFX DRV_NAME ": " +//TODO +#define DRV_VERSION "1.0.0000.566" +#define DRV_RELDATE "12/21/2006" + +#define HZ 1000000 /* 1 sec in usecs */ + +enum { + MTHCA_FLAG_DDR_HIDDEN = 1 << 1, + MTHCA_FLAG_SRQ = 1 << 2, + MTHCA_FLAG_MSI = 1 << 3, + MTHCA_FLAG_MSI_X = 1 << 4, + MTHCA_FLAG_NO_LAM = 1 << 5, + MTHCA_FLAG_FMR = 1 << 6, + MTHCA_FLAG_MEMFREE = 1 << 7, + MTHCA_FLAG_PCIE = 1 << 8, + MTHCA_FLAG_SINAI_OPT = 1 << 9, +}; + +enum { + MTHCA_MAX_PORTS = 2 +}; + +enum { + MTHCA_BOARD_ID_LEN = 64 +}; + +enum { + MTHCA_EQ_CONTEXT_SIZE = 0x40, + MTHCA_CQ_CONTEXT_SIZE = 0x40, + MTHCA_QP_CONTEXT_SIZE = 0x200, + MTHCA_RDB_ENTRY_SIZE = 0x20, + MTHCA_AV_SIZE = 0x20, + MTHCA_MGM_ENTRY_SIZE = 0x40, + + /* Arbel FW gives us these, but we need them for Tavor */ + MTHCA_MPT_ENTRY_SIZE = 0x40, + MTHCA_MTT_SEG_SIZE = 0x40, + + MTHCA_QP_PER_MGM = 4 * (MTHCA_MGM_ENTRY_SIZE / 16 - 2) +}; + +enum { + MTHCA_EQ_CMD, + MTHCA_EQ_ASYNC, + MTHCA_EQ_COMP, + MTHCA_NUM_EQ +}; + +enum { + MTHCA_BYTES_PER_ATOMIC_COMPL = 8 +}; + +enum mthca_wr_opcode{ + MTHCA_OPCODE_NOP = 0x00, + MTHCA_OPCODE_RDMA_WRITE = 0x08, + MTHCA_OPCODE_RDMA_WRITE_IMM = 0x09, + MTHCA_OPCODE_SEND = 0x0a, + MTHCA_OPCODE_SEND_IMM = 0x0b, + MTHCA_OPCODE_RDMA_READ = 0x10, + MTHCA_OPCODE_ATOMIC_CS = 0x11, + MTHCA_OPCODE_ATOMIC_FA = 0x12, + MTHCA_OPCODE_BIND_MW = 0x18, + MTHCA_OPCODE_INVALID = 0xff +}; + +struct mthca_cmd { + struct pci_pool *pool; + int use_events; + KMUTEX hcr_mutex; + KSEMAPHORE poll_sem; + KSEMAPHORE event_sem; + int max_cmds; + spinlock_t context_lock; + int free_head; + struct mthca_cmd_context *context; + u16 token_mask; +}; + +struct mthca_limits { + int num_ports; + int vl_cap; + int mtu_cap; + int gid_table_len; + int pkey_table_len; + int local_ca_ack_delay; + int num_uars; + int max_sg; + int num_qps; + int max_wqes; + int max_desc_sz; + int max_qp_init_rdma; + int reserved_qps; + int num_srqs; + int max_srq_wqes; + int max_srq_sge; + int reserved_srqs; + int num_eecs; + int reserved_eecs; + int num_cqs; + int max_cqes; + int reserved_cqs; + int num_eqs; + int reserved_eqs; + int num_mpts; + int num_mtt_segs; + int fmr_reserved_mtts; + int reserved_mtts; + int reserved_mrws; + int reserved_uars; + int num_mgms; + int num_amgms; + int reserved_mcgs; + int num_pds; + int reserved_pds; + u32 page_size_cap; + u32 flags; + u8 port_width_cap; + u64 num_avs; +}; + +struct mthca_alloc { + u32 last; + u32 top; + u32 max; + u32 mask; + spinlock_t lock; + unsigned long *table; +}; + +struct mthca_array { + struct { + void **page; + int used; + } *page_list; +}; + +struct mthca_uar_table { + struct mthca_alloc alloc; + u64 uarc_base; + int uarc_size; +}; + +struct mthca_pd_table { + struct mthca_alloc alloc; +}; + +struct mthca_buddy { + unsigned long **bits; + int max_order; + spinlock_t lock; +}; + +struct mthca_mr_table { + struct mthca_alloc mpt_alloc; + struct mthca_buddy mtt_buddy; + struct mthca_buddy *fmr_mtt_buddy; + u64 mtt_base; + u64 mpt_base; + struct mthca_icm_table *mtt_table; + struct mthca_icm_table *mpt_table; + struct { + void __iomem *mpt_base; + SIZE_T mpt_base_size; + void __iomem *mtt_base; + SIZE_T mtt_base_size; + struct mthca_buddy mtt_buddy; + } tavor_fmr; +}; + +struct mthca_eq_table { + struct mthca_alloc alloc; + void __iomem *clr_int; + u32 clr_mask; + u32 arm_mask; + struct mthca_eq eq[MTHCA_NUM_EQ]; + u64 icm_virt; + struct scatterlist sg; + int have_irq; + u8 inta_pin; + KLOCK_QUEUE_HANDLE lockh; +#if 1//WORKAROUND_POLL_EQ + KEVENT thread_start_event; + KEVENT thread_stop_event; + BOOLEAN bTerminated; + PVOID threadObject; +#endif +}; + +struct mthca_cq_table { + struct mthca_alloc alloc; + spinlock_t lock; + struct mthca_array cq; + struct mthca_icm_table *table; +}; + +struct mthca_srq_table { + struct mthca_alloc alloc; + spinlock_t lock; + struct mthca_array srq; + struct mthca_icm_table *table; +}; + +struct mthca_qp_table { + struct mthca_alloc alloc; + u32 rdb_base; + int rdb_shift; + int sqp_start; + spinlock_t lock; + struct mthca_array qp; + struct mthca_icm_table *qp_table; + struct mthca_icm_table *eqp_table; + struct mthca_icm_table *rdb_table; +}; + +struct mthca_av_table { + struct pci_pool *pool; + int num_ddr_avs; + u64 ddr_av_base; + void __iomem *av_map; + SIZE_T av_map_size; + struct mthca_alloc alloc; +}; + +struct mthca_mcg_table { + KMUTEX mutex; + struct mthca_alloc alloc; + struct mthca_icm_table *table; +}; + +struct mthca_catas_err { + u64 addr; + u32 __iomem *map; + SIZE_T map_size; + unsigned long stop; + u32 size; + KTIMER timer; + KDPC timer_dpc; + LARGE_INTEGER interval; +}; + +struct mthca_dev { + struct ib_device ib_dev; + hca_dev_ext_t *ext; + uplink_info_t uplink_info; + volatile long dpc_lock; + + int hca_type; + unsigned long mthca_flags; + unsigned long device_cap_flags; + + u32 rev_id; + char board_id[MTHCA_BOARD_ID_LEN]; + + /* firmware info */ + u64 fw_ver; + union { + struct { + u64 fw_start; + u64 fw_end; + } tavor; + struct { + u64 clr_int_base; + u64 eq_arm_base; + u64 eq_set_ci_base; + struct mthca_icm *fw_icm; + struct mthca_icm *aux_icm; + u16 fw_pages; + } arbel; + } fw; + + u64 ddr_start; + u64 ddr_end; + + MTHCA_DECLARE_DOORBELL_LOCK(doorbell_lock) + KMUTEX cap_mask_mutex; + + u8 __iomem *hcr; + SIZE_T hcr_size; + u8 __iomem *kar; + SIZE_T kar_size; + u8 __iomem *clr_base; + SIZE_T clr_base_size; + union { + struct { + void __iomem *ecr_base; + SIZE_T ecr_base_size; + } tavor; + struct { + void __iomem *eq_arm; + SIZE_T eq_arm_size; + void __iomem *eq_set_ci_base; + SIZE_T eq_set_ci_base_size; + } arbel; + } eq_regs; + + struct mthca_cmd cmd; + struct mthca_limits limits; + + struct mthca_uar_table uar_table; + struct mthca_pd_table pd_table; + struct mthca_mr_table mr_table; + struct mthca_eq_table eq_table; + struct mthca_cq_table cq_table; + struct mthca_srq_table srq_table; + struct mthca_qp_table qp_table; + struct mthca_av_table av_table; + struct mthca_mcg_table mcg_table; + struct mthca_catas_err catas_err; + struct mthca_uar driver_uar; + struct mthca_db_table *db_tab; + struct mthca_pd driver_pd; + struct mthca_mr driver_mr; + + struct ib_mad_agent *send_agent[MTHCA_MAX_PORTS][2]; + struct ib_ah *sm_ah[MTHCA_MAX_PORTS]; + spinlock_t sm_lock; + u32 state; +}; + +// mthca_dev states +enum { + MTHCA_DEV_UNINITIALIZED, + MTHCA_DEV_INITIALIZED, + MTHCA_DEV_FAILED +}; + +enum { + MTHCA_CQ_ENTRY_SIZE = 0x20 +}; + + + +#define MTHCA_GET(dest, source, offset) \ + { \ + void *__p = (char *) (source) + (offset); \ + void *__q = &(dest); \ + switch (sizeof (dest)) { \ + case 1: *(u8 *)__q = *(u8 *) __p; break; \ + case 2: *(u16 *)__q = (u16)cl_ntoh16(*(u16 *)__p); break; \ + case 4: *(u32 *)__q = (u32)cl_ntoh32(*(u32 *)__p); break; \ + case 8: *(u64 *)__q = (u64)cl_ntoh64(*(u64 *)__p); break; \ + default: ASSERT(0); \ + } \ + } + + +#define MTHCA_PUT(dest, source, offset) \ + { \ + void *__d = ((char *) (dest) + (offset)); \ + switch (sizeof(source)) { \ + case 1: *(u8 *) __d = (u8)(source); break; \ + case 2: *(__be16 *) __d = cl_hton16((u16)source); break; \ + case 4: *(__be32 *) __d = cl_hton32((u32)source); break; \ + case 8: *(__be64 *) __d = cl_hton64((u64)source); break; \ + default: ASSERT(0); \ + } \ + } + +NTSTATUS mthca_reset(struct mthca_dev *mdev); + +u32 mthca_alloc(struct mthca_alloc *alloc); +void mthca_free(struct mthca_alloc *alloc, u32 obj); +int mthca_alloc_init(struct mthca_alloc *alloc, u32 num, u32 mask, + u32 reserved); +void mthca_alloc_cleanup(struct mthca_alloc *alloc); +void *mthca_array_get(struct mthca_array *array, int index); +int mthca_array_set(struct mthca_array *array, int index, void *value); +void mthca_array_clear(struct mthca_array *array, int index); +int mthca_array_init(struct mthca_array *array, int nent); +void mthca_array_cleanup(struct mthca_array *array, int nent); +int mthca_buf_alloc(struct mthca_dev *dev, int size, int max_direct, + union mthca_buf *buf, int *is_direct, struct mthca_pd *pd, + int hca_write, struct mthca_mr *mr); +void mthca_buf_free(struct mthca_dev *dev, int size, union mthca_buf *buf, + int is_direct, struct mthca_mr *mr); + +int mthca_init_uar_table(struct mthca_dev *dev); +int mthca_init_pd_table(struct mthca_dev *dev); +int mthca_init_mr_table(struct mthca_dev *dev); +int mthca_init_eq_table(struct mthca_dev *dev); +int mthca_init_cq_table(struct mthca_dev *dev); +int mthca_init_srq_table(struct mthca_dev *dev); +int mthca_init_qp_table(struct mthca_dev *dev); +int mthca_init_av_table(struct mthca_dev *dev); +int mthca_init_mcg_table(struct mthca_dev *dev); + +void mthca_cleanup_uar_table(struct mthca_dev *dev); +void mthca_cleanup_pd_table(struct mthca_dev *dev); +void mthca_cleanup_mr_table(struct mthca_dev *dev); +void mthca_cleanup_eq_table(struct mthca_dev *dev); +void mthca_cleanup_cq_table(struct mthca_dev *dev); +void mthca_cleanup_srq_table(struct mthca_dev *dev); +void mthca_cleanup_qp_table(struct mthca_dev *dev); +void mthca_cleanup_av_table(struct mthca_dev *dev); +void mthca_cleanup_mcg_table(struct mthca_dev *dev); + +int mthca_register_device(struct mthca_dev *dev); +void mthca_unregister_device(struct mthca_dev *dev); + +void mthca_start_catas_poll(struct mthca_dev *dev); +void mthca_stop_catas_poll(struct mthca_dev *dev); + +int mthca_uar_alloc(struct mthca_dev *dev, struct mthca_uar *uar); +void mthca_uar_free(struct mthca_dev *dev, struct mthca_uar *uar); + +int mthca_pd_alloc(struct mthca_dev *dev, int privileged, struct mthca_pd *pd); +void mthca_pd_free(struct mthca_dev *dev, struct mthca_pd *pd); + +struct mthca_mtt *mthca_alloc_mtt(struct mthca_dev *dev, int size); +void mthca_free_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt); +int mthca_write_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt, + int start_index, u64 *buffer_list, int list_len); +int mthca_mr_alloc(struct mthca_dev *dev, u32 pd, int buffer_size_shift, + u64 iova, u64 total_size, mthca_mpt_access_t access, struct mthca_mr *mr); +int mthca_mr_alloc_notrans(struct mthca_dev *dev, u32 pd, + mthca_mpt_access_t access, struct mthca_mr *mr); +int mthca_mr_alloc_phys(struct mthca_dev *dev, u32 pd, + u64 *buffer_list, int buffer_size_shift, + int list_len, u64 iova, u64 total_size, + mthca_mpt_access_t access, struct mthca_mr *mr); +void mthca_free_mr(struct mthca_dev *dev, struct mthca_mr *mr); + +int mthca_fmr_alloc(struct mthca_dev *dev, u32 pd, + mthca_mpt_access_t access, struct mthca_fmr *fmr); +int mthca_tavor_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list, + int list_len, u64 iova); +void mthca_tavor_fmr_unmap(struct mthca_dev *dev, struct mthca_fmr *fmr); +int mthca_arbel_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list, + int list_len, u64 iova); +void mthca_arbel_fmr_unmap(struct mthca_dev *dev, struct mthca_fmr *fmr); +int mthca_free_fmr(struct mthca_dev *dev, struct mthca_fmr *fmr); + +int mthca_map_eq_icm(struct mthca_dev *dev, u64 icm_virt); +void mthca_unmap_eq_icm(struct mthca_dev *dev); + +int mthca_poll_cq(struct ib_cq *ibcq, int num_entries, + struct _ib_wc *entry); +int mthca_tavor_arm_cq(struct ib_cq *cq, enum ib_cq_notify notify); +int mthca_arbel_arm_cq(struct ib_cq *cq, enum ib_cq_notify notify); +int mthca_init_cq(struct mthca_dev *dev, int nent, + struct mthca_ucontext *ctx, u32 pdn, + struct mthca_cq *cq); +void mthca_free_cq(struct mthca_dev *dev, + struct mthca_cq *cq); +void mthca_cq_completion(struct mthca_dev *dev, u32 cqn); +void mthca_cq_event(struct mthca_dev *dev, u32 cqn, + enum ib_event_type event_type); +void mthca_cq_clean(struct mthca_dev *dev, u32 cqn, u32 qpn, + struct mthca_srq *srq); + +int mthca_alloc_srq(struct mthca_dev *dev, struct mthca_pd *pd, + ib_srq_attr_t *attr, struct mthca_srq *srq); +void mthca_free_srq(struct mthca_dev *dev, struct mthca_srq *srq); +int mthca_modify_srq(struct ib_srq *ibsrq, ib_srq_attr_t *attr, + ib_srq_attr_mask_t attr_mask); +void mthca_srq_event(struct mthca_dev *dev, u32 srqn, + enum ib_event_type event_type, u8 vendor_code); +void mthca_free_srq_wqe(struct mthca_srq *srq, u32 wqe_addr); +int mthca_tavor_post_srq_recv(struct ib_srq *srq, struct _ib_recv_wr *wr, + struct _ib_recv_wr **bad_wr); +int mthca_arbel_post_srq_recv(struct ib_srq *srq, struct _ib_recv_wr *wr, + struct _ib_recv_wr **bad_wr); + +void mthca_qp_event(struct mthca_dev *dev, u32 qpn, + enum ib_event_type event_type, u8 vendor_code); +int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask); +int mthca_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr_mask, + struct ib_qp_init_attr *qp_init_attr); +int mthca_tavor_post_send(struct ib_qp *ibqp, struct _ib_send_wr *wr, + struct _ib_send_wr **bad_wr); +int mthca_tavor_post_recv(struct ib_qp *ibqp, struct _ib_recv_wr *wr, + struct _ib_recv_wr **bad_wr); +int mthca_arbel_post_send(struct ib_qp *ibqp, struct _ib_send_wr *wr, + struct _ib_send_wr **bad_wr); +int mthca_arbel_post_recv(struct ib_qp *ibqp, struct _ib_recv_wr *wr, + struct _ib_recv_wr **bad_wr); +void mthca_free_err_wqe(struct mthca_dev *dev, struct mthca_qp *qp, int is_send, + int index, int *dbd, __be32 *new_wqe); +int mthca_alloc_qp(struct mthca_dev *dev, + struct mthca_pd *pd, + struct mthca_cq *send_cq, + struct mthca_cq *recv_cq, + enum ib_qp_type_t type, + enum ib_sig_type send_policy, + struct ib_qp_cap *cap, + struct mthca_qp *qp); +int mthca_alloc_sqp(struct mthca_dev *dev, + struct mthca_pd *pd, + struct mthca_cq *send_cq, + struct mthca_cq *recv_cq, + enum ib_sig_type send_policy, + struct ib_qp_cap *cap, + int qpn, + int port, + struct mthca_sqp *sqp); +void mthca_free_qp(struct mthca_dev *dev, struct mthca_qp *qp); +int mthca_create_ah(struct mthca_dev *dev, + struct mthca_pd *pd, + struct ib_ah_attr *ah_attr, + struct mthca_ah *ah); +int mthca_destroy_ah(struct mthca_dev *dev, struct mthca_ah *ah); +int mthca_read_ah(struct mthca_dev *dev, struct mthca_ah *ah, + struct ib_ud_header *header); + +int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid); +int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid); + +int mthca_process_mad(struct ib_device *ibdev, + int mad_flags, + u8 port_num, + struct _ib_wc *in_wc, + struct _ib_grh *in_grh, + struct ib_mad *in_mad, + struct ib_mad *out_mad); + +static inline struct mthca_dev *to_mdev(struct ib_device *ibdev) +{ + return container_of(ibdev, struct mthca_dev, ib_dev); +} + +static inline int mthca_is_memfree(struct mthca_dev *dev) +{ + return dev->mthca_flags & MTHCA_FLAG_MEMFREE; +} + +VOID +WriteEventLogEntry( + PVOID pi_pIoObject, + ULONG pi_ErrorCode, + ULONG pi_UniqueErrorCode, + ULONG pi_FinalStatus, + ULONG pi_nDataItems, + ... + ); + +VOID +WriteEventLogEntryStr( + PVOID pi_pIoObject, + ULONG pi_ErrorCode, + ULONG pi_UniqueErrorCode, + ULONG pi_FinalStatus, + PWCHAR pi_InsertionStr, + ULONG pi_nDataItems, + ... + ); + +void mthca_get_av_params( struct mthca_ah *ah_p, u8 *port_num, __be16 *dlid, u8 *sr, u8 *path_bits ); + +void mthca_set_av_params( struct mthca_dev *dev, struct mthca_ah *ah_p, struct ib_ah_attr *ah_attr ); + +int ib_uverbs_init(void); +void ib_uverbs_cleanup(void); +int mthca_ah_grh_present(struct mthca_ah *ah); + +int mthca_max_srq_sge(struct mthca_dev *dev); + + +#endif /* MTHCA_DEV_H */ diff --git a/branches/WOF2-3/hw/mthca/kernel/mthca_doorbell.h b/branches/WOF2-3/hw/mthca/kernel/mthca_doorbell.h new file mode 100644 index 00000000..92cfb3fd --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/mthca_doorbell.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2004 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +enum { + MTHCA_SEND_DOORBELL_FENCE = 1 << 5 +}; + +#ifdef _WIN64 +/* + * Assume that we can just write a 64-bit doorbell atomically. s390 + * actually doesn't have writeq() but S/390 systems don't even have + * PCI so we won't worry about it. + */ + + + +#define MTHCA_DECLARE_DOORBELL_LOCK(name) +#define MTHCA_INIT_DOORBELL_LOCK(ptr) +#define MTHCA_GET_DOORBELL_LOCK(ptr) (NULL) + +static inline void mthca_write64_raw(__be64 val, void __iomem *dest) +{ + __raw_writeq((u64) val, dest); +} + +static inline void mthca_write64(__be32 val[2], void __iomem *dest, + spinlock_t *doorbell_lock) +{ + UNUSED_PARAM(doorbell_lock); + *(volatile u64 *)dest = *(volatile u64 *)val; +} + +static inline void mthca_write_db_rec(__be32 val[2], __be32 *db) +{ + *(volatile u64 *) db = *(volatile u64 *) val; +} + +#else + +/* + * Just fall back to a spinlock to protect the doorbell if + * BITS_PER_LONG is 32 -- there's no portable way to do atomic 64-bit + * MMIO writes. + */ + +#define MTHCA_DECLARE_DOORBELL_LOCK(name) spinlock_t name; +#define MTHCA_INIT_DOORBELL_LOCK(ptr) spin_lock_init(ptr) +#define MTHCA_GET_DOORBELL_LOCK(ptr) (ptr) + +static inline void mthca_write64_raw(__be64 val, void __iomem *dest) +{ + __raw_writel(((u32 *) &val)[0], dest); + __raw_writel(((u32 *) &val)[1], (u8*)dest + 4); +} + +static inline void mthca_write64(__be32 val[2], void __iomem *dest, + spinlock_t *doorbell_lock) +{ + SPIN_LOCK_PREP(lh); + spin_lock_irqsave(doorbell_lock, &lh); + __raw_writel((u32) val[0], dest); + __raw_writel((u32) val[1], (u8*)dest + 4); + spin_unlock_irqrestore(&lh); +} + +static inline void mthca_write_db_rec(__be32 val[2], __be32 *db) +{ + db[0] = val[0]; + wmb(); + db[1] = val[1]; +} + +#endif diff --git a/branches/WOF2-3/hw/mthca/kernel/mthca_eq.c b/branches/WOF2-3/hw/mthca/kernel/mthca_eq.c new file mode 100644 index 00000000..9c47e824 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/mthca_eq.c @@ -0,0 +1,1249 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include "mthca_dev.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "mthca_eq.tmh" +#endif +#include "mthca_cmd.h" +#include "mthca_config_reg.h" +#include "mthca_wqe.h" + +static int mthca_map_reg(struct mthca_dev *dev, + u64 offset, unsigned long size, + void __iomem **map, SIZE_T *map_size); +static int mthca_map_eq_regs(struct mthca_dev *dev); +static void mthca_unmap_eq_regs(struct mthca_dev *dev); +static int mthca_create_eq(struct mthca_dev *dev, + int nent, + u8 intr, + struct mthca_eq *eq); + + +enum { + MTHCA_NUM_ASYNC_EQE = 0x80, + MTHCA_NUM_CMD_EQE = 0x80, + MTHCA_NUM_SPARE_EQE = 0x80, + MTHCA_EQ_ENTRY_SIZE = 0x20 +}; + +/* + * Must be packed because start is 64 bits but only aligned to 32 bits. + */ +#pragma pack(push,1) +struct mthca_eq_context { + __be32 flags; + __be64 start; + __be32 logsize_usrpage; + __be32 tavor_pd; /* reserved for Arbel */ + u8 reserved1[3]; + u8 intr; + __be32 arbel_pd; /* lost_count for Tavor */ + __be32 lkey; + u32 reserved2[2]; + __be32 consumer_index; + __be32 producer_index; + u32 reserved3[4]; +}; +#pragma pack(pop) + +#define MTHCA_EQ_STATUS_OK ( 0 << 28) +#define MTHCA_EQ_STATUS_OVERFLOW ( 9 << 28) +#define MTHCA_EQ_STATUS_WRITE_FAIL (10 << 28) +#define MTHCA_EQ_OWNER_SW ( 0 << 24) +#define MTHCA_EQ_OWNER_HW ( 1 << 24) +#define MTHCA_EQ_FLAG_TR ( 1 << 18) +#define MTHCA_EQ_FLAG_OI ( 1 << 17) +#define MTHCA_EQ_STATE_ARMED ( 1 << 8) +#define MTHCA_EQ_STATE_FIRED ( 2 << 8) +#define MTHCA_EQ_STATE_ALWAYS_ARMED ( 3 << 8) +#define MTHCA_EQ_STATE_ARBEL ( 8 << 8) + +enum { + MTHCA_EVENT_TYPE_COMP = 0x00, + MTHCA_EVENT_TYPE_PATH_MIG = 0x01, + MTHCA_EVENT_TYPE_COMM_EST = 0x02, + MTHCA_EVENT_TYPE_SQ_DRAINED = 0x03, + MTHCA_EVENT_TYPE_CQ_ERROR = 0x04, + MTHCA_EVENT_TYPE_WQ_CATAS_ERROR = 0x05, + MTHCA_EVENT_TYPE_EEC_CATAS_ERROR = 0x06, + MTHCA_EVENT_TYPE_PATH_MIG_FAILED = 0x07, + MTHCA_EVENT_TYPE_LOCAL_CATAS_ERROR = 0x08, + MTHCA_EVENT_TYPE_PORT_CHANGE = 0x09, + MTHCA_EVENT_TYPE_CMD = 0x0a, + MTHCA_EVENT_TYPE_WQ_INVAL_REQ_ERROR = 0x10, + MTHCA_EVENT_TYPE_ECC_DETECT = 0x0e, + MTHCA_EVENT_TYPE_EQ_OVERFLOW = 0x0f, + MTHCA_EVENT_TYPE_WQ_ACCESS_ERROR = 0x11, + MTHCA_EVENT_TYPE_SRQ_CATAS_ERROR = 0x12, + MTHCA_EVENT_TYPE_SRQ_QP_LAST_WQE = 0x13, + MTHCA_EVENT_TYPE_SRQ_LIMIT = 0x14 +}; + +#define MTHCA_ASYNC_EVENT_MASK ((1Ui64 << MTHCA_EVENT_TYPE_PATH_MIG) | \ + (1Ui64 << MTHCA_EVENT_TYPE_COMM_EST) | \ + (1Ui64 << MTHCA_EVENT_TYPE_SQ_DRAINED) | \ + (1Ui64 << MTHCA_EVENT_TYPE_CQ_ERROR) | \ + (1Ui64 << MTHCA_EVENT_TYPE_WQ_CATAS_ERROR) | \ + (1Ui64 << MTHCA_EVENT_TYPE_EEC_CATAS_ERROR) | \ + (1Ui64 << MTHCA_EVENT_TYPE_PATH_MIG_FAILED) | \ + (1Ui64 << MTHCA_EVENT_TYPE_WQ_INVAL_REQ_ERROR) | \ + (1Ui64 << MTHCA_EVENT_TYPE_WQ_ACCESS_ERROR) | \ + (1Ui64 << MTHCA_EVENT_TYPE_LOCAL_CATAS_ERROR) | \ + (1Ui64 << MTHCA_EVENT_TYPE_PORT_CHANGE) | \ + (1Ui64 << MTHCA_EVENT_TYPE_ECC_DETECT)) +#define MTHCA_SRQ_EVENT_MASK ((1Ui64 << MTHCA_EVENT_TYPE_SRQ_CATAS_ERROR) | \ + (1Ui64 << MTHCA_EVENT_TYPE_SRQ_QP_LAST_WQE) | \ + (1Ui64 << MTHCA_EVENT_TYPE_SRQ_LIMIT)) + +#define MTHCA_CMD_EVENT_MASK (1Ui64 << MTHCA_EVENT_TYPE_CMD) + +#define MTHCA_EQ_DB_INC_CI (1 << 24) +#define MTHCA_EQ_DB_REQ_NOT (2 << 24) +#define MTHCA_EQ_DB_DISARM_CQ (3 << 24) +#define MTHCA_EQ_DB_SET_CI (4 << 24) +#define MTHCA_EQ_DB_ALWAYS_ARM (5 << 24) + +#pragma pack(push,1) +struct mthca_eqe { + u8 reserved1; + u8 type; + u8 reserved2; + u8 subtype; + union { + u32 raw[6]; + struct { + __be32 cqn; + } comp; + struct { + u16 reserved1; + __be16 token; + u32 reserved2; + u8 reserved3[3]; + u8 status; + __be64 out_param; + } cmd; + struct { + __be32 qpn; + u32 reserved1; + u32 reserved2; + u8 reserved3[1]; + u8 vendor_code; + u8 reserved4[2]; + } qp; + struct { + __be32 srqn; + u32 reserved1; + u32 reserved2; + u8 reserved3[1]; + u8 vendor_code; + u8 reserved4[2]; + } srq; + struct { + __be32 cqn; + u32 reserved1; + u8 reserved2[3]; + u8 syndrome; + } cq_err; + struct { + u32 reserved1[2]; + __be32 port; + } port_change; + } event; + u8 reserved3[3]; + u8 owner; +} ; +#pragma pack(pop) + +#define MTHCA_EQ_ENTRY_OWNER_SW (0 << 7) +#define MTHCA_EQ_ENTRY_OWNER_HW (1 << 7) + +static inline u64 async_mask(struct mthca_dev *dev) +{ + return dev->mthca_flags & MTHCA_FLAG_SRQ ? + MTHCA_ASYNC_EVENT_MASK | MTHCA_SRQ_EVENT_MASK : + MTHCA_ASYNC_EVENT_MASK; +} + +static inline void tavor_set_eq_ci(struct mthca_dev *dev, struct mthca_eq *eq, u32 ci) +{ + __be32 doorbell[2]; + + doorbell[0] = cl_hton32(MTHCA_EQ_DB_SET_CI | eq->eqn); + doorbell[1] = cl_hton32(ci & (eq->nent - 1)); + + /* + * This barrier makes sure that all updates to ownership bits + * done by set_eqe_hw() hit memory before the consumer index + * is updated. set_eq_ci() allows the HCA to possibly write + * more EQ entries, and we want to avoid the exceedingly + * unlikely possibility of the HCA writing an entry and then + * having set_eqe_hw() overwrite the owner field. + */ + wmb(); + mthca_write64(doorbell, + dev->kar + MTHCA_EQ_DOORBELL, + MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock)); +} + +static inline void arbel_set_eq_ci(struct mthca_dev *dev, struct mthca_eq *eq, u32 ci) +{ + /* See comment in tavor_set_eq_ci() above. */ + wmb(); + __raw_writel((u32) cl_hton32(ci), + (u8*)dev->eq_regs.arbel.eq_set_ci_base + eq->eqn * 8); + /* We still want ordering, just not swabbing, so add a barrier */ + mb(); +} + +static inline void set_eq_ci(struct mthca_dev *dev, struct mthca_eq *eq, u32 ci) +{ + if (mthca_is_memfree(dev)) + arbel_set_eq_ci(dev, eq, ci); + else + tavor_set_eq_ci(dev, eq, ci); +} + +static inline void tavor_eq_req_not(struct mthca_dev *dev, int eqn) +{ + __be32 doorbell[2]; + + doorbell[0] = cl_hton32(MTHCA_EQ_DB_REQ_NOT | eqn); + doorbell[1] = 0; + + mthca_write64(doorbell, + dev->kar + MTHCA_EQ_DOORBELL, + MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock)); +} + +static inline void arbel_eq_req_not(struct mthca_dev *dev, u32 eqn_mask) +{ + writel(eqn_mask, dev->eq_regs.arbel.eq_arm); +} + +static inline void disarm_cq(struct mthca_dev *dev, int eqn, int cqn) +{ + if (!mthca_is_memfree(dev)) { + __be32 doorbell[2]; + + doorbell[0] = cl_hton32(MTHCA_EQ_DB_DISARM_CQ | eqn); + doorbell[1] = cl_hton32(cqn); + + mthca_write64(doorbell, + dev->kar + MTHCA_EQ_DOORBELL, + MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock)); + } +} + +static inline struct mthca_eqe *get_eqe(struct mthca_eq *eq, u32 entry) +{ + unsigned long off = (entry & (eq->nent - 1)) * MTHCA_EQ_ENTRY_SIZE; + return (struct mthca_eqe *)((u8*)eq->page_list[off / PAGE_SIZE].page + off % PAGE_SIZE); +} + +static inline struct mthca_eqe* next_eqe_sw(struct mthca_eq *eq) +{ + struct mthca_eqe* eqe; + eqe = get_eqe(eq, eq->cons_index); + return (MTHCA_EQ_ENTRY_OWNER_HW & eqe->owner) ? NULL : eqe; +} + +static inline void set_eqe_hw(struct mthca_eqe *eqe) +{ + eqe->owner = MTHCA_EQ_ENTRY_OWNER_HW; +} + +static void port_change(struct mthca_dev *dev, int port, int active) +{ + struct ib_event record; + + HCA_PRINT(TRACE_LEVEL_VERBOSE,HCA_DBG_LOW,("Port change to %s for port %d\n", + active ? "active" : "down", port)); + + record.device = &dev->ib_dev; + record.event = active ? IB_EVENT_PORT_ACTIVE : IB_EVENT_PORT_ERR; + record.element.port_num = (u8)port; + // Gen2 ib_core mechanism + ib_dispatch_event(&record); + // our callback + ca_event_handler( &record, &dev->ext->hca.hob ); +} + +static int mthca_eq_int(struct mthca_dev *dev, struct mthca_eq *eq) +{ + int disarm_cqn; + int eqes_found = 0; + int set_ci = 0; + struct mthca_eqe *eqe = next_eqe_sw(eq); + uint64_t start = cl_get_time_stamp(); + int loops = 0; + + while (eqe) { + + /* + * Make sure we read EQ entry contents after we've + * checked the ownership bit. + */ + rmb(); + + switch (eqe->type) { + case MTHCA_EVENT_TYPE_COMP: + disarm_cqn = cl_ntoh32(eqe->event.comp.cqn) & 0xffffff; + disarm_cq(dev, eq->eqn, disarm_cqn); + mthca_cq_completion(dev, disarm_cqn); + break; + + case MTHCA_EVENT_TYPE_PATH_MIG: + mthca_qp_event(dev, cl_ntoh32(eqe->event.qp.qpn) & 0xffffff, + IB_EVENT_PATH_MIG, eqe->event.qp.vendor_code); + break; + + case MTHCA_EVENT_TYPE_COMM_EST: + mthca_qp_event(dev, cl_ntoh32(eqe->event.qp.qpn) & 0xffffff, + IB_EVENT_COMM_EST, eqe->event.qp.vendor_code); + break; + + case MTHCA_EVENT_TYPE_SQ_DRAINED: + mthca_qp_event(dev, cl_ntoh32(eqe->event.qp.qpn) & 0xffffff, + IB_EVENT_SQ_DRAINED, eqe->event.qp.vendor_code); + break; + + case MTHCA_EVENT_TYPE_SRQ_QP_LAST_WQE: + mthca_qp_event(dev, cl_ntoh32(eqe->event.qp.qpn) & 0xffffff, + IB_EVENT_SRQ_QP_LAST_WQE_REACHED, eqe->event.qp.vendor_code); + break; + + case MTHCA_EVENT_TYPE_SRQ_CATAS_ERROR: + mthca_srq_event(dev, cl_ntoh32(eqe->event.srq.srqn) & 0xffffff, + IB_EVENT_SRQ_LIMIT_REACHED, eqe->event.qp.vendor_code); + break; + + case MTHCA_EVENT_TYPE_SRQ_LIMIT: + mthca_srq_event(dev, cl_ntoh32(eqe->event.srq.srqn) & 0xffffff, + IB_EVENT_SRQ_LIMIT_REACHED, eqe->event.qp.vendor_code); + break; + + case MTHCA_EVENT_TYPE_WQ_CATAS_ERROR: + mthca_qp_event(dev, cl_ntoh32(eqe->event.qp.qpn) & 0xffffff, + IB_EVENT_QP_FATAL, eqe->event.qp.vendor_code); + break; + + case MTHCA_EVENT_TYPE_PATH_MIG_FAILED: + mthca_qp_event(dev, cl_ntoh32(eqe->event.qp.qpn) & 0xffffff, + IB_EVENT_PATH_MIG_ERR, eqe->event.qp.vendor_code); + break; + + case MTHCA_EVENT_TYPE_WQ_INVAL_REQ_ERROR: + mthca_qp_event(dev, cl_ntoh32(eqe->event.qp.qpn) & 0xffffff, + IB_EVENT_QP_REQ_ERR, eqe->event.qp.vendor_code); + break; + + case MTHCA_EVENT_TYPE_WQ_ACCESS_ERROR: + mthca_qp_event(dev, cl_ntoh32(eqe->event.qp.qpn) & 0xffffff, + IB_EVENT_QP_ACCESS_ERR, eqe->event.qp.vendor_code); + break; + + case MTHCA_EVENT_TYPE_CMD: + mthca_cmd_event(dev, + cl_ntoh16(eqe->event.cmd.token), + eqe->event.cmd.status, + cl_ntoh64(eqe->event.cmd.out_param)); + break; + + case MTHCA_EVENT_TYPE_PORT_CHANGE: + port_change(dev, + (cl_ntoh32(eqe->event.port_change.port) >> 28) & 3, + eqe->subtype == 0x4); + break; + + case MTHCA_EVENT_TYPE_CQ_ERROR: + HCA_PRINT(TRACE_LEVEL_WARNING,HCA_DBG_LOW, ("CQ %s on CQN %06x (syndrome %d)\n", + eqe->event.cq_err.syndrome == 1 ? + "overrun" : "access violation", + cl_ntoh32(eqe->event.cq_err.cqn) & 0xffffff, eqe->event.cq_err.syndrome)); + mthca_cq_event(dev, cl_ntoh32(eqe->event.cq_err.cqn), + IB_EVENT_CQ_ERR); + break; + + case MTHCA_EVENT_TYPE_EQ_OVERFLOW: + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_LOW ,("EQ overrun on EQN %d\n", eq->eqn)); + break; + + case MTHCA_EVENT_TYPE_EEC_CATAS_ERROR: + case MTHCA_EVENT_TYPE_LOCAL_CATAS_ERROR: + case MTHCA_EVENT_TYPE_ECC_DETECT: + default: + HCA_PRINT(TRACE_LEVEL_WARNING,HCA_DBG_LOW, ("Unhandled event %02x(%02x) on EQ %d\n", + eqe->type, eqe->subtype, eq->eqn)); + break; + }; + + set_eqe_hw(eqe); + ++eq->cons_index; + eqes_found += 1; + ++set_ci; + + /* + * The HCA will think the queue has overflowed if we + * don't tell it we've been processing events. We + * create our EQs with MTHCA_NUM_SPARE_EQE extra + * entries, so we must update our consumer index at + * least that often. + */ + if (unlikely(set_ci >= MTHCA_NUM_SPARE_EQE)) { + /* + * Conditional on hca_type is OK here because + * this is a rare case, not the fast path. + */ + set_eq_ci(dev, eq, eq->cons_index); + set_ci = 0; + } + loops++; + if (cl_get_time_stamp() - start > g_max_DPC_time_us ) { + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_LOW ,("Handling of EQ stopped, and a new DPC is entered after %d loops\n", loops)); + KeInsertQueueDpc(&dev->eq_table.eq[eq->eq_num].dpc, NULL, NULL); + break; + } + eqe = next_eqe_sw(eq); + } + + /* + * Rely on caller to set consumer index so that we don't have + * to test hca_type in our interrupt handling fast path. + */ + return eqes_found; +} + +static void mthca_tavor_dpc( PRKDPC dpc, + PVOID ctx, PVOID arg1, PVOID arg2 ) +{ + struct mthca_eq *eq = ctx; + struct mthca_dev *dev = eq->dev; + SPIN_LOCK_PREP(lh); + + UNREFERENCED_PARAMETER(dpc); + UNREFERENCED_PARAMETER(arg1); + UNREFERENCED_PARAMETER(arg2); + + spin_lock_dpc(&eq->lock, &lh); + + /* we need 'if' in case, when there were scheduled 2 DPC for one EQ */ + if (mthca_eq_int(dev, eq)) { + tavor_set_eq_ci(dev, eq, eq->cons_index); + tavor_eq_req_not(dev, eq->eqn); + } + + spin_unlock_dpc(&lh); +} + +static BOOLEAN mthca_tavor_interrupt( + PKINTERRUPT int_obj, + PVOID ctx + ) +{ + struct mthca_dev *dev = ctx; + u32 ecr; + int i; + + UNREFERENCED_PARAMETER(int_obj); + + if (dev->eq_table.clr_mask) + writel(dev->eq_table.clr_mask, dev->eq_table.clr_int); + + ecr = readl((u8*)dev->eq_regs.tavor.ecr_base + 4); + if (!ecr) + return FALSE; + + writel(ecr, (u8*)dev->eq_regs.tavor.ecr_base + + MTHCA_ECR_CLR_BASE - MTHCA_ECR_BASE + 4); + + for (i = 0; i < MTHCA_NUM_EQ; ++i) { + if (ecr & dev->eq_table.eq[i].eqn_mask && + next_eqe_sw(&dev->eq_table.eq[i])) { + KeInsertQueueDpc(&dev->eq_table.eq[i].dpc, NULL, NULL); + } + } + + return TRUE; +} + +#ifdef MSI_SUPPORT +static irqreturn_t mthca_tavor_msi_x_interrupt(int irq, void *eq_ptr, + struct pt_regs *regs) +{ + struct mthca_eq *eq = eq_ptr; + struct mthca_dev *dev = eq->dev; + + mthca_eq_int(dev, eq); + tavor_set_eq_ci(dev, eq, eq->cons_index); + tavor_eq_req_not(dev, eq->eqn); + + /* MSI-X vectors always belong to us */ + return IRQ_HANDLED; +} +#endif + +static void mthca_arbel_dpc( PRKDPC dpc, + PVOID ctx, PVOID arg1, PVOID arg2 ) +{ + struct mthca_eq *eq = ctx; + struct mthca_dev *dev = eq->dev; + SPIN_LOCK_PREP(lh); + + UNREFERENCED_PARAMETER(dpc); + UNREFERENCED_PARAMETER(arg1); + UNREFERENCED_PARAMETER(arg2); + + spin_lock_dpc(&eq->lock, &lh); + + /* we need 'if' in case, when there were scheduled 2 DPC for one EQ */ + if (mthca_eq_int(dev, eq)) + arbel_set_eq_ci(dev, eq, eq->cons_index); + arbel_eq_req_not(dev, eq->eqn_mask); + + spin_unlock_dpc(&lh); +} + +static BOOLEAN mthca_arbel_interrupt( + PKINTERRUPT int_obj, + PVOID ctx + ) +{ + struct mthca_dev *dev = ctx; + int work = 0; + int i; + + UNREFERENCED_PARAMETER(int_obj); + + if (dev->eq_table.clr_mask) + writel(dev->eq_table.clr_mask, dev->eq_table.clr_int); + + for (i = 0; i < MTHCA_NUM_EQ; ++i) { + if (next_eqe_sw( &dev->eq_table.eq[i]) ) { + work = 1; + while(InterlockedCompareExchange(&dev->dpc_lock, 1, 0)); + + KeInsertQueueDpc(&dev->eq_table.eq[i].dpc, NULL, NULL); + InterlockedCompareExchange(&dev->dpc_lock, 0, 1); + } else { + arbel_eq_req_not(dev, dev->eq_table.eq[i].eqn_mask); + } + } + + return (BOOLEAN)work; +} + +#ifdef MSI_SUPPORT +static irqreturn_t mthca_arbel_msi_x_interrupt(int irq, void *eq_ptr, + struct pt_regs *regs) +{ + struct mthca_eq *eq = eq_ptr; + struct mthca_dev *dev = eq->dev; + + mthca_eq_int(dev, eq); + arbel_set_eq_ci(dev, eq, eq->cons_index); + arbel_eq_req_not(dev, eq->eqn_mask); + + /* MSI-X vectors always belong to us */ + return IRQ_HANDLED; +} +#endif + +#if 1//WORKAROUND_POLL_EQ + +BOOLEAN +IsrSynchronizeRoutine( + IN PVOID SynchronizeContext + ) +{ + struct mthca_dev *dev = (struct mthca_dev *)SynchronizeContext; + + //Is this always correct? + mthca_arbel_interrupt(dev->ext->int_obj,dev); + + return TRUE; +} + + +VOID eq_polling_thread(void *ctx) +{ +#define POLLING_INTERVAL_MS 50 + NTSTATUS status; + struct mthca_dev *dev = (struct mthca_dev *)ctx; + PVOID wait_objects[2]; + LARGE_INTEGER wait_time; + + wait_objects[0] = &dev->eq_table.thread_stop_event; + wait_objects[1] = &dev->eq_table.thread_start_event; + + for(;;){ + + /* before start polling */ + DbgPrint("Before polling.\n"); + for (;;) { + status = KeWaitForMultipleObjects( 2, wait_objects, + WaitAny, Executive, KernelMode, FALSE, NULL, NULL ); + + if ( status == STATUS_WAIT_0 ){/* thread stopped */ + DbgPrint("Signaled to stop polling.\n"); + break; + } + + /* start polling */ + if ( status == STATUS_WAIT_1 ){ + DbgPrint("Signaled to start polling.\n"); + break; + } + + } + + if(dev->eq_table.bTerminated) break; + if ( status == STATUS_WAIT_0 ) continue;/* thread stopped, wait for start again */ + + /* polling */ + DbgPrint("Start polling.\n"); + wait_time.QuadPart = -(int64_t)(((uint64_t)POLLING_INTERVAL_MS) * 10000); + for (;;) { + //mlx4_interrupt( NULL, &priv->dev ); + KeSynchronizeExecution(dev->ext->int_obj, IsrSynchronizeRoutine, dev); + + status = KeWaitForSingleObject( &dev->eq_table.thread_stop_event, + Executive, KernelMode, FALSE, &wait_time ); + if ( status == STATUS_SUCCESS ) { + //KeClearEvent(&priv->eq_table.thread_stop_event); + DbgPrint("Signaled to stop polling while in polling mode.\n"); + break; /* thread stopped */ + } + } + + if(dev->eq_table.bTerminated) break; + } + + DbgPrint("Polling thread terminated.\n"); + PsTerminateSystemThread(STATUS_SUCCESS); + +} + + +void mlnx_poll_eq(struct ib_device *device, BOOLEAN bStart) +{ + LONG signalled=0; + struct mthca_dev *dev = (struct mthca_dev *)(device); + + if(bStart){ + /* signal start of polling */ + signalled = KeSetEvent( + &dev->eq_table.thread_start_event, IO_NO_INCREMENT, FALSE ); + }else{ + /* signal end of polling */ + signalled = KeSetEvent( + &dev->eq_table.thread_stop_event, IO_NO_INCREMENT, FALSE ); + } + +} + +#endif + +static int mthca_create_eq(struct mthca_dev *dev, + int nent, + u8 intr, + struct mthca_eq *eq) +{ + int npages; + u64 *dma_list = NULL; + struct mthca_mailbox *mailbox; + struct mthca_eq_context *eq_context; + int err = -ENOMEM; + int i; + u8 status; + + HCA_ENTER(HCA_DBG_INIT); + eq->dev = dev; + eq->nent = roundup_pow_of_two(max(nent, 2)); + npages = ALIGN(eq->nent * MTHCA_EQ_ENTRY_SIZE, PAGE_SIZE) / PAGE_SIZE; + + eq->page_list = kmalloc(npages * sizeof *eq->page_list, + GFP_KERNEL); + if (!eq->page_list) + goto err_out; + + for (i = 0; i < npages; ++i) + eq->page_list[i].page = NULL; + + dma_list = kmalloc(npages * sizeof *dma_list, GFP_KERNEL); + if (!dma_list) + goto err_out_free; + + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (IS_ERR(mailbox)) + goto err_out_free; + eq_context = mailbox->buf; + + for (i = 0; i < npages; ++i) { + alloc_dma_zmem_map(dev, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL, &eq->page_list[i]); + if (!eq->page_list[i].page) + goto err_out_free_pages; + dma_list[i] = eq->page_list[i].dma_address; + } + + for (i = 0; i < eq->nent; ++i) + set_eqe_hw(get_eqe(eq, i)); + + eq->eqn = mthca_alloc(&dev->eq_table.alloc); + if (eq->eqn == -1) + goto err_out_free_pages; + + err = mthca_mr_alloc_phys(dev, dev->driver_pd.pd_num, + dma_list, PAGE_SHIFT, npages, + 0, npages * PAGE_SIZE, + MTHCA_MPT_FLAG_LOCAL_WRITE | + MTHCA_MPT_FLAG_LOCAL_READ, + &eq->mr); + if (err) + goto err_out_free_eq; + + RtlZeroMemory(eq_context, sizeof *eq_context); + eq_context->flags = cl_hton32(MTHCA_EQ_STATUS_OK | + MTHCA_EQ_OWNER_HW | + MTHCA_EQ_STATE_ARMED | + MTHCA_EQ_FLAG_TR); + if (mthca_is_memfree(dev)) + eq_context->flags |= cl_hton32(MTHCA_EQ_STATE_ARBEL); + + eq_context->logsize_usrpage = cl_hton32((ffs(eq->nent) - 1) << 24); + if (mthca_is_memfree(dev)) { + eq_context->arbel_pd = cl_hton32(dev->driver_pd.pd_num); + } else { + eq_context->logsize_usrpage |= cl_hton32(dev->driver_uar.index); + eq_context->tavor_pd = cl_hton32(dev->driver_pd.pd_num); + } + eq_context->intr = intr; + eq_context->lkey = cl_hton32(eq->mr.ibmr.lkey); + + err = mthca_SW2HW_EQ(dev, mailbox, eq->eqn, &status); + if (err) { + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_LOW ,("SW2HW_EQ failed (%d)\n", err)); + goto err_out_free_mr; + } + if (status) { + HCA_PRINT(TRACE_LEVEL_WARNING,HCA_DBG_LOW,("SW2HW_EQ returned status 0x%02x\n", + status)); + err = -EINVAL; + goto err_out_free_mr; + } + + kfree(dma_list); + mthca_free_mailbox(dev, mailbox); + + eq->eqn_mask = _byteswap_ulong(1 << eq->eqn); + eq->cons_index = 0; + + dev->eq_table.arm_mask |= eq->eqn_mask; + + HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_INIT ,("Allocated EQ %d with %d entries\n", + eq->eqn, eq->nent)); + + HCA_EXIT(HCA_DBG_INIT); + return err; + + err_out_free_mr: + mthca_free_mr(dev, &eq->mr); + + err_out_free_eq: + mthca_free(&dev->eq_table.alloc, eq->eqn); + + err_out_free_pages: + for (i = 0; i < npages; ++i) { + if (eq->page_list[i].page) { + free_dma_mem_map(dev, &eq->page_list[i], PCI_DMA_BIDIRECTIONAL); + } + } + mthca_free_mailbox(dev, mailbox); + + err_out_free: + kfree(eq->page_list); + kfree(dma_list); + + err_out: + HCA_EXIT(HCA_DBG_INIT); + return err; +} + +static void mthca_free_eq(struct mthca_dev *dev, + struct mthca_eq *eq) +{ + struct mthca_mailbox *mailbox; + int err; + u8 status; + int npages = (eq->nent * MTHCA_EQ_ENTRY_SIZE + PAGE_SIZE - 1) / + PAGE_SIZE; + int i; + + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (IS_ERR(mailbox)) + return; + + err = mthca_HW2SW_EQ(dev, mailbox, eq->eqn, &status); + if (err) + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_LOW ,("HW2SW_EQ failed (%d)\n", err)); + if (status) + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_LOW ,("HW2SW_EQ returned status 0x%02x\n", status)); + + dev->eq_table.arm_mask &= ~eq->eqn_mask; + + { // debug print + HCA_PRINT(TRACE_LEVEL_VERBOSE ,HCA_DBG_LOW ,("Dumping EQ context %02x:\n", eq->eqn)); + for (i = 0; i < sizeof (struct mthca_eq_context) / 4; i=i+4) { + HCA_PRINT(TRACE_LEVEL_VERBOSE ,HCA_DBG_LOW ,("[%02x] %08x %08x %08x %08x\n", i, + cl_ntoh32(*(u32*)((u8*)mailbox->buf + i * 4)), + cl_ntoh32(*(u32*)((u8*)mailbox->buf + (i+1)*4)), + cl_ntoh32(*(u32*)((u8*)mailbox->buf + (i+2)*4)), + cl_ntoh32(*(u32*)((u8*)mailbox->buf + (i+1)*4)))); + + } + } + + mthca_free_mr(dev, &eq->mr); + for (i = 0; i < npages; ++i) { + free_dma_mem_map(dev, &eq->page_list[i], PCI_DMA_BIDIRECTIONAL); + } + + kfree(eq->page_list); + mthca_free_mailbox(dev, mailbox); +} + +static void mthca_free_irqs(struct mthca_dev *dev) +{ + if (dev->eq_table.have_irq) + free_irq(dev->ext->int_obj); +#ifdef MSI_SUPPORT + for (i = 0; i < MTHCA_NUM_EQ; ++i) + if (dev->eq_table.eq[i].have_irq) + free_irq(dev->eq_table.eq[i].msi_x_vector, + dev->eq_table.eq + i); +#endif +} + +static int mthca_map_reg(struct mthca_dev *dev, + u64 offset, unsigned long size, + void __iomem **map, SIZE_T *map_size) +{ + u64 base = pci_resource_start(dev, HCA_BAR_TYPE_HCR); + *map = ioremap(base + offset, size, map_size); + if (!*map) + return -ENOMEM; + return 0; +} + +static void mthca_unmap_reg(struct mthca_dev *dev, u64 offset, + unsigned long size, void __iomem *map, SIZE_T map_size) +{ + UNREFERENCED_PARAMETER(dev); + UNREFERENCED_PARAMETER(size); + UNREFERENCED_PARAMETER(offset); + iounmap(map, map_size); +} + +static int mthca_map_eq_regs(struct mthca_dev *dev) +{ + u64 mthca_base; + + mthca_base = pci_resource_start(dev, HCA_BAR_TYPE_HCR); + + if (mthca_is_memfree(dev)) { + /* + * We assume that the EQ arm and EQ set CI registers + * fall within the first BAR. We can't trust the + * values firmware gives us, since those addresses are + * valid on the HCA's side of the PCI bus but not + * necessarily the host side. + */ + if (mthca_map_reg(dev, (pci_resource_len(dev, 0) - 1) & + dev->fw.arbel.clr_int_base, MTHCA_CLR_INT_SIZE, + &dev->clr_base, &dev->clr_base_size)) { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Couldn't map interrupt clear register, " + "aborting.\n")); + return -ENOMEM; + } + + /* + * Add 4 because we limit ourselves to EQs 0 ... 31, + * so we only need the low word of the register. + */ + if (mthca_map_reg(dev, ((pci_resource_len(dev, 0) - 1) & + dev->fw.arbel.eq_arm_base) + 4, 4, + &dev->eq_regs.arbel.eq_arm, &dev->eq_regs.arbel.eq_arm_size)) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Couldn't map EQ arm register, aborting.\n")); + mthca_unmap_reg(dev, (pci_resource_len(dev, 0) - 1) & + dev->fw.arbel.clr_int_base, MTHCA_CLR_INT_SIZE, + dev->clr_base, dev->clr_base_size); + return -ENOMEM; + } + + if (mthca_map_reg(dev, (pci_resource_len(dev, 0) - 1) & + dev->fw.arbel.eq_set_ci_base, + MTHCA_EQ_SET_CI_SIZE, + &dev->eq_regs.arbel.eq_set_ci_base, + &dev->eq_regs.arbel.eq_set_ci_base_size + )) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Couldn't map EQ CI register, aborting.\n")); + mthca_unmap_reg(dev, ((pci_resource_len(dev, 0) - 1) & + dev->fw.arbel.eq_arm_base) + 4, 4, + dev->eq_regs.arbel.eq_arm, dev->eq_regs.arbel.eq_arm_size); + mthca_unmap_reg(dev, (pci_resource_len(dev, 0) - 1) & + dev->fw.arbel.clr_int_base, MTHCA_CLR_INT_SIZE, + dev->clr_base, dev->clr_base_size); + return -ENOMEM; + } + } else { + if (mthca_map_reg(dev, MTHCA_CLR_INT_BASE, MTHCA_CLR_INT_SIZE, + &dev->clr_base, &dev->clr_base_size)) { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Couldn't map interrupt clear register, " + "aborting.\n")); + return -ENOMEM; + } + + if (mthca_map_reg(dev, MTHCA_ECR_BASE, + MTHCA_ECR_SIZE + MTHCA_ECR_CLR_SIZE, + &dev->eq_regs.tavor.ecr_base, &dev->eq_regs.tavor.ecr_base_size)) { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Couldn't map ecr register, " + "aborting.\n")); + mthca_unmap_reg(dev, MTHCA_CLR_INT_BASE, MTHCA_CLR_INT_SIZE, + dev->clr_base, dev->clr_base_size); + return -ENOMEM; + } + } + + return 0; + +} + +static void mthca_unmap_eq_regs(struct mthca_dev *dev) +{ + if (mthca_is_memfree(dev)) { + mthca_unmap_reg(dev, (pci_resource_len(dev, 0) - 1) & + dev->fw.arbel.eq_set_ci_base, + MTHCA_EQ_SET_CI_SIZE, + dev->eq_regs.arbel.eq_set_ci_base, + dev->eq_regs.arbel.eq_set_ci_base_size); + mthca_unmap_reg(dev, ((pci_resource_len(dev, 0) - 1) & + dev->fw.arbel.eq_arm_base) + 4, 4, + dev->eq_regs.arbel.eq_arm, + dev->eq_regs.arbel.eq_arm_size); + mthca_unmap_reg(dev, (pci_resource_len(dev, 0) - 1) & + dev->fw.arbel.clr_int_base, MTHCA_CLR_INT_SIZE, + dev->clr_base, dev->clr_base_size); + } else { + mthca_unmap_reg(dev, MTHCA_ECR_BASE, + MTHCA_ECR_SIZE + MTHCA_ECR_CLR_SIZE, + dev->eq_regs.tavor.ecr_base, + dev->eq_regs.tavor.ecr_base_size); + mthca_unmap_reg(dev, MTHCA_CLR_INT_BASE, MTHCA_CLR_INT_SIZE, + dev->clr_base, dev->clr_base_size); + } +} + +int mthca_map_eq_icm(struct mthca_dev *dev, u64 icm_virt) +{ + int ret; + u8 status; + + /* + * We assume that mapping one page is enough for the whole EQ + * context table. This is fine with all current HCAs, because + * we only use 32 EQs and each EQ uses 32 bytes of context + * memory, or 1 KB total. + */ + dev->eq_table.icm_virt = icm_virt; + alloc_dma_zmem_map(dev,PAGE_SIZE, PCI_DMA_BIDIRECTIONAL, &dev->eq_table.sg); + if (!dev->eq_table.sg.page) + return -ENOMEM; + + ret = mthca_MAP_ICM_page(dev, dev->eq_table.sg.dma_address, icm_virt, &status); + if (!ret && status) + ret = -EINVAL; + if (ret) + free_dma_mem_map(dev, &dev->eq_table.sg, PCI_DMA_BIDIRECTIONAL ); + + return ret; +} + +void mthca_unmap_eq_icm(struct mthca_dev *dev) +{ + u8 status; + + mthca_UNMAP_ICM(dev, dev->eq_table.icm_virt, PAGE_SIZE / 4096, &status); + free_dma_mem_map(dev, &dev->eq_table.sg, PCI_DMA_BIDIRECTIONAL ); +} + +int mthca_init_eq_table(struct mthca_dev *dev) +{ + int err; + u8 status; + u8 intr; + int i; + + HCA_ENTER(HCA_DBG_INIT); + err = mthca_alloc_init(&dev->eq_table.alloc, + dev->limits.num_eqs, + dev->limits.num_eqs - 1, + dev->limits.reserved_eqs); + if (err) + return err; + + err = mthca_map_eq_regs(dev); + if (err) + goto err_out_free; + +#ifdef MSI_SUPPORT + if (dev->mthca_flags & MTHCA_FLAG_MSI || + dev->mthca_flags & MTHCA_FLAG_MSI_X) { + dev->eq_table.clr_mask = 0; + } else +#endif + { + dev->eq_table.clr_mask = + _byteswap_ulong(1 << (dev->eq_table.inta_pin & 31)); + dev->eq_table.clr_int = dev->clr_base + + (dev->eq_table.inta_pin < 32 ? 4 : 0); + } + + dev->eq_table.arm_mask = 0; + + intr = (dev->mthca_flags & MTHCA_FLAG_MSI) ? + 128 : dev->eq_table.inta_pin; + + err = mthca_create_eq(dev, dev->limits.num_cqs + MTHCA_NUM_SPARE_EQE, + (dev->mthca_flags & MTHCA_FLAG_MSI_X) ? 128 : intr, + &dev->eq_table.eq[MTHCA_EQ_COMP]); + if (err) + goto err_out_unmap; + + err = mthca_create_eq(dev, MTHCA_NUM_ASYNC_EQE + MTHCA_NUM_SPARE_EQE, + (dev->mthca_flags & MTHCA_FLAG_MSI_X) ? 129 : intr, + &dev->eq_table.eq[MTHCA_EQ_ASYNC]); + if (err) + goto err_out_comp; + + err = mthca_create_eq(dev, MTHCA_NUM_CMD_EQE + MTHCA_NUM_SPARE_EQE, + (dev->mthca_flags & MTHCA_FLAG_MSI_X) ? 130 : intr, + &dev->eq_table.eq[MTHCA_EQ_CMD]); + if (err) + goto err_out_async; + +#ifdef MSI_SUPPORT + if (dev->mthca_flags & MTHCA_FLAG_MSI_X) { + static const char *eq_name[] = { + [MTHCA_EQ_COMP] = DRV_NAME " (comp)", + [MTHCA_EQ_ASYNC] = DRV_NAME " (async)", + [MTHCA_EQ_CMD] = DRV_NAME " (cmd)" + }; + + for (i = 0; i < MTHCA_NUM_EQ; ++i) { + err = request_irq(dev->eq_table.eq[i].msi_x_vector, + mthca_is_memfree(dev) ? + mthca_arbel_msi_x_interrupt : + mthca_tavor_msi_x_interrupt, + 0, eq_name[i], dev->eq_table.eq + i); + if (err) + goto err_out_cmd; + dev->eq_table.eq[i].have_irq = 1; + /* init DPC stuff something like that */ + spin_lock_init( &dev->eq_table.eq[i].lock ); + dev->dpc_lock = 0; + KeInitializeDpc( + &dev->eq_table.eq[i].dpc, + mthca_is_memfree(dev) ? + mthca_arbel_msi_x_dpc : + mthca_tavor_msi_x_dpc, + dev->eq_table.eq + i); + } + } else +#endif + { + spin_lock_init( &dev->ext->isr_lock ); + err = request_irq( + &dev->ext->interruptInfo, + &dev->ext->isr_lock.lock , + mthca_is_memfree(dev) ? mthca_arbel_interrupt : mthca_tavor_interrupt, + dev, + &dev->ext->int_obj + ); + if (err) + goto err_out_cmd; + dev->eq_table.have_irq = 1; + + /* init DPC stuff */ + for (i = 0; i < MTHCA_NUM_EQ; ++i) { + spin_lock_init( &dev->eq_table.eq[i].lock ); + KeInitializeDpc( + &dev->eq_table.eq[i].dpc, + mthca_is_memfree(dev) ? + mthca_arbel_dpc : + mthca_tavor_dpc, + dev->eq_table.eq + i); + dev->eq_table.eq[i].eq_num = i; + } + } + + err = mthca_MAP_EQ(dev, async_mask(dev), + 0, dev->eq_table.eq[MTHCA_EQ_ASYNC].eqn, &status); + if (err) + HCA_PRINT(TRACE_LEVEL_WARNING,HCA_DBG_INIT,("MAP_EQ for async EQ %d failed (%d)\n", + dev->eq_table.eq[MTHCA_EQ_ASYNC].eqn, err)); + if (status) + HCA_PRINT(TRACE_LEVEL_WARNING,HCA_DBG_INIT, ("MAP_EQ for async EQ %d returned status 0x%02x\n", + dev->eq_table.eq[MTHCA_EQ_ASYNC].eqn, status)); + err = mthca_MAP_EQ(dev, MTHCA_CMD_EVENT_MASK, + 0, dev->eq_table.eq[MTHCA_EQ_CMD].eqn, &status); + if (err) + HCA_PRINT(TRACE_LEVEL_WARNING,HCA_DBG_INIT, ("MAP_EQ for cmd EQ %d failed (%d)\n", + dev->eq_table.eq[MTHCA_EQ_CMD].eqn, err)); + if (status) + HCA_PRINT(TRACE_LEVEL_WARNING,HCA_DBG_INIT,("MAP_EQ for cmd EQ %d returned status 0x%02x\n", + dev->eq_table.eq[MTHCA_EQ_CMD].eqn, status)); + + for (i = 0; i < MTHCA_NUM_EQ; ++i) + if (mthca_is_memfree(dev)) + arbel_eq_req_not(dev, dev->eq_table.eq[i].eqn_mask); + else + tavor_eq_req_not(dev, dev->eq_table.eq[i].eqn); + +#if 1//WORKAROUND_POLL_EQ + { /* Create a thread for polling EQs in case of missing interrupts from the card */ + NTSTATUS status; + OBJECT_ATTRIBUTES attr; + HANDLE handle; + + KeInitializeEvent(&dev->eq_table.thread_start_event, SynchronizationEvent, FALSE); + KeInitializeEvent(&dev->eq_table.thread_stop_event, SynchronizationEvent, FALSE); + dev->eq_table.bTerminated = FALSE; + dev->eq_table.threadObject = NULL; + InitializeObjectAttributes( &attr, NULL, OBJ_KERNEL_HANDLE, NULL, NULL ); + status = PsCreateSystemThread( &handle, + THREAD_ALL_ACCESS, &attr, NULL, NULL, eq_polling_thread, dev ); + if (NT_SUCCESS(status)) { + status = ObReferenceObjectByHandle( + handle, + THREAD_ALL_ACCESS, + NULL, + KernelMode, + &dev->eq_table.threadObject, + NULL + ); + + ASSERT(status == STATUS_SUCCESS); // + + status = ZwClose(handle); + + ASSERT(NT_SUCCESS(status)); // Should always succeed + + } + } +#endif + + return 0; + +err_out_cmd: + mthca_free_eq(dev, &dev->eq_table.eq[MTHCA_EQ_CMD]); + +err_out_async: + mthca_free_eq(dev, &dev->eq_table.eq[MTHCA_EQ_ASYNC]); + +err_out_comp: + mthca_free_eq(dev, &dev->eq_table.eq[MTHCA_EQ_COMP]); + +err_out_unmap: + mthca_unmap_eq_regs(dev); + +err_out_free: + mthca_alloc_cleanup(&dev->eq_table.alloc); + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_INIT ,("mthca_init_eq failed %d\n",err)); + return err; +} + +void mthca_cleanup_eq_table(struct mthca_dev *dev) +{ + u8 status; + int i; + +#if 1//WORKAROUND_POLL_EQ + /* stop the EQ polling thread */ + if (dev->eq_table.threadObject) { + #define WAIT_TIME_MS 3000 + NTSTATUS status; + LARGE_INTEGER wait_time; + LONG signalled; + + dev->eq_table.bTerminated = TRUE; + + /* signal polling stopped in case it is not */ + signalled = KeSetEvent( + &dev->eq_table.thread_stop_event, IO_NO_INCREMENT, FALSE ); + + /* wait for completion of the thread */ + wait_time.QuadPart = -(int64_t)(((uint64_t)WAIT_TIME_MS) * 10000); + status = KeWaitForSingleObject( dev->eq_table.threadObject, + Executive, KernelMode, FALSE, &wait_time ); + ASSERT(status == STATUS_SUCCESS); + + ObDereferenceObject(dev->eq_table.threadObject); + + /* cleanup */ + dev->eq_table.threadObject = NULL; + } +#endif + + mthca_free_irqs(dev); + + mthca_MAP_EQ(dev, async_mask(dev), + 1, dev->eq_table.eq[MTHCA_EQ_ASYNC].eqn, &status); + mthca_MAP_EQ(dev, MTHCA_CMD_EVENT_MASK, + 1, dev->eq_table.eq[MTHCA_EQ_CMD].eqn, &status); + + for (i = 0; i < MTHCA_NUM_EQ; ++i) + mthca_free_eq(dev, &dev->eq_table.eq[i]); + + mthca_unmap_eq_regs(dev); + + mthca_alloc_cleanup(&dev->eq_table.alloc); +} + + + + diff --git a/branches/WOF2-3/hw/mthca/kernel/mthca_log.c b/branches/WOF2-3/hw/mthca/kernel/mthca_log.c new file mode 100644 index 00000000..07bfb6c8 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/mthca_log.c @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2005 Mellanox Technologies LTD. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +// Author: Yossi Leybovich + +#include "hca_driver.h" + + +VOID +WriteEventLogEntry( + PVOID pi_pIoObject, + ULONG pi_ErrorCode, + ULONG pi_UniqueErrorCode, + ULONG pi_FinalStatus, + ULONG pi_nDataItems, + ... + ) +/*++ + +Routine Description: + Writes an event log entry to the event log. + +Arguments: + + pi_pIoObject......... The IO object ( driver object or device object ). + pi_ErrorCode......... The error code. + pi_UniqueErrorCode... A specific error code. + pi_FinalStatus....... The final status. + pi_nDataItems........ Number of data items. + . + . data items values + . + +Return Value: + + None . + +--*/ +{ /* WriteEventLogEntry */ + + /* Variable argument list */ + va_list l_Argptr; + /* Pointer to an error log entry */ + PIO_ERROR_LOG_PACKET l_pErrorLogEntry; + + /* Init the variable argument list */ + va_start(l_Argptr, pi_nDataItems); + + if(pi_pIoObject == NULL) { + return; + } + + /* Allocate an error log entry */ + l_pErrorLogEntry = + (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry( + pi_pIoObject, + (UCHAR)(sizeof(IO_ERROR_LOG_PACKET)+pi_nDataItems*sizeof(ULONG)) + ); + /* Check allocation */ + if ( l_pErrorLogEntry != NULL) + { /* OK */ + + /* Data item index */ + USHORT l_nDataItem ; + + /* Set the error log entry header */ + l_pErrorLogEntry->ErrorCode = pi_ErrorCode; + l_pErrorLogEntry->DumpDataSize = (USHORT) (pi_nDataItems*sizeof(ULONG)); + l_pErrorLogEntry->SequenceNumber = 0; + l_pErrorLogEntry->MajorFunctionCode = 0; + l_pErrorLogEntry->IoControlCode = 0; + l_pErrorLogEntry->RetryCount = 0; + l_pErrorLogEntry->UniqueErrorValue = pi_UniqueErrorCode; + l_pErrorLogEntry->FinalStatus = pi_FinalStatus; + + /* Insert the data items */ + for (l_nDataItem = 0; l_nDataItem < pi_nDataItems; l_nDataItem++) + { /* Inset a data item */ + + /* Current data item */ + int l_CurDataItem ; + + /* Get next data item */ + l_CurDataItem = va_arg( l_Argptr, int); + + /* Put it into the data array */ + l_pErrorLogEntry->DumpData[l_nDataItem] = l_CurDataItem ; + + } /* Inset a data item */ + + /* Write the packet */ + IoWriteErrorLogEntry(l_pErrorLogEntry); + + } /* OK */ + + /* Term the variable argument list */ + va_end(l_Argptr); + +} /* WriteEventLogEntry */ + +/*------------------------------------------------------------------------------------------------------*/ + +VOID +WriteEventLogEntryStr( + PVOID pi_pIoObject, + ULONG pi_ErrorCode, + ULONG pi_UniqueErrorCode, + ULONG pi_FinalStatus, + PWCHAR pi_InsertionStr, + ULONG pi_nDataItems, + ... + ) +/*++ + +Routine Description: + Writes an event log entry to the event log. + +Arguments: + + pi_pIoObject......... The IO object ( driver object or device object ). + pi_ErrorCode......... The error code. + pi_UniqueErrorCode... A specific error code. + pi_FinalStatus....... The final status. + pi_nDataItems........ Number of data items. + . + . data items values + . + +Return Value: + + None . + +--*/ +{ /* WriteEventLogEntryStr */ + + /* Variable argument list */ + va_list l_Argptr; + /* Pointer to an error log entry */ + PIO_ERROR_LOG_PACKET l_pErrorLogEntry; + /* sizeof insertion string */ + int l_Size = (int)((pi_InsertionStr) ? ((wcslen(pi_InsertionStr) + 1) * sizeof( WCHAR )) : 0); + int l_PktSize =sizeof(IO_ERROR_LOG_PACKET)+pi_nDataItems*sizeof(ULONG); + int l_TotalSize =l_PktSize +l_Size; + + if(pi_pIoObject == NULL) { + return; + } + + /* Init the variable argument list */ + va_start(l_Argptr, pi_nDataItems); + + /* Allocate an error log entry */ + if (l_TotalSize >= ERROR_LOG_MAXIMUM_SIZE - 2) + l_TotalSize = ERROR_LOG_MAXIMUM_SIZE - 2; + l_pErrorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry( + pi_pIoObject, (UCHAR)l_TotalSize ); + + /* Check allocation */ + if ( l_pErrorLogEntry != NULL) + { /* OK */ + + /* Data item index */ + USHORT l_nDataItem ; + + /* Set the error log entry header */ + l_pErrorLogEntry->ErrorCode = pi_ErrorCode; + l_pErrorLogEntry->DumpDataSize = (USHORT) (pi_nDataItems*sizeof(ULONG)); + l_pErrorLogEntry->SequenceNumber = 0; + l_pErrorLogEntry->MajorFunctionCode = 0; + l_pErrorLogEntry->IoControlCode = 0; + l_pErrorLogEntry->RetryCount = 0; + l_pErrorLogEntry->UniqueErrorValue = pi_UniqueErrorCode; + l_pErrorLogEntry->FinalStatus = pi_FinalStatus; + + /* Insert the data items */ + for (l_nDataItem = 0; l_nDataItem < pi_nDataItems; l_nDataItem++) + { /* Inset a data item */ + + /* Current data item */ + int l_CurDataItem ; + + /* Get next data item */ + l_CurDataItem = va_arg( l_Argptr, int); + + /* Put it into the data array */ + l_pErrorLogEntry->DumpData[l_nDataItem] = l_CurDataItem ; + + } /* Inset a data item */ + + /* add insertion string */ + if (pi_InsertionStr) { + char *ptr; + int sz = min( l_TotalSize - l_PktSize, l_Size ); + l_pErrorLogEntry->NumberOfStrings = 1; + l_pErrorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET) + l_pErrorLogEntry->DumpDataSize; + ptr = (char*)l_pErrorLogEntry + l_pErrorLogEntry->StringOffset; + memcpy( ptr, pi_InsertionStr, sz ); + *(WCHAR*)&ptr[sz - 2] = (WCHAR)0; + } + + /* Write the packet */ + IoWriteErrorLogEntry(l_pErrorLogEntry); + + } /* OK */ + + /* Term the variable argument list */ + va_end(l_Argptr); + +} /* WriteEventLogEntry */ + + + + + + diff --git a/branches/WOF2-3/hw/mthca/kernel/mthca_log.mc b/branches/WOF2-3/hw/mthca/kernel/mthca_log.mc new file mode 100644 index 00000000..08cbddae --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/mthca_log.mc @@ -0,0 +1,56 @@ +;/*++ +;============================================================================= +;Copyright (c) 2001 Mellanox Technologies +; +;Module Name: +; +; mthcalog.mc +; +;Abstract: +; +; MTHCA Driver event log messages +; +;Authors: +; +; Yossi Leybovich +; +;Environment: +; +; Kernel Mode . +; +;============================================================================= +;--*/ +; +MessageIdTypedef = NTSTATUS + +SeverityNames = ( + Success = 0x0:STATUS_SEVERITY_SUCCESS + Informational = 0x1:STATUS_SEVERITY_INFORMATIONAL + Warning = 0x2:STATUS_SEVERITY_WARNING + Error = 0x3:STATUS_SEVERITY_ERROR + ) + +FacilityNames = ( + System = 0x0 + RpcRuntime = 0x2:FACILITY_RPC_RUNTIME + RpcStubs = 0x3:FACILITY_RPC_STUBS + Io = 0x4:FACILITY_IO_ERROR_CODE + MTHCA = 0x7:FACILITY_MTHCA_ERROR_CODE + ) + + +MessageId=0x0001 Facility=MTHCA Severity=Informational SymbolicName=EVENT_MTHCA_ANY_INFO +Language=English +%2 +. + +MessageId=0x0002 Facility=MTHCA Severity=Warning SymbolicName=EVENT_MTHCA_ANY_WARN +Language=English +%2 +. + +MessageId=0x0003 Facility=MTHCA Severity=Error SymbolicName=EVENT_MTHCA_ANY_ERROR +Language=English +%2 +. + diff --git a/branches/WOF2-3/hw/mthca/kernel/mthca_mad.c b/branches/WOF2-3/hw/mthca/kernel/mthca_mad.c new file mode 100644 index 00000000..6c6c0e6f --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/mthca_mad.c @@ -0,0 +1,286 @@ +/* + * Copyright (c) 2004 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * Copyright (c) 2004 Voltaire, Inc. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include +#include +#include + +#include "mthca_dev.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "mthca_mad.tmh" +#endif +#include "mthca_cmd.h" + +struct mthca_trap_mad { + struct scatterlist sg; +}; + +static void update_sm_ah(struct mthca_dev *dev, + u8 port_num, u16 lid, u8 sl) +{ + struct ib_ah *new_ah; + struct ib_ah_attr ah_attr; + SPIN_LOCK_PREP(lh); + + if (!dev->send_agent[port_num - 1][0]) + return; + + RtlZeroMemory(&ah_attr, sizeof ah_attr); + ah_attr.dlid = lid; + ah_attr.sl = sl; + ah_attr.port_num = port_num; + + new_ah = ibv_create_ah(dev->send_agent[port_num - 1][0]->qp->pd, + &ah_attr, NULL, NULL); + if (IS_ERR(new_ah)) + return; + + spin_lock_irqsave(&dev->sm_lock, &lh); + if (dev->sm_ah[port_num - 1]) { + ibv_destroy_ah(dev->sm_ah[port_num - 1]); + } + dev->sm_ah[port_num - 1] = new_ah; + spin_unlock_irqrestore(&lh); +} + +/* + * Snoop SM MADs for port info and P_Key table sets, so we can + * synthesize LID change and P_Key change events. + */ +static void smp_snoop(struct ib_device *ibdev, + u8 port_num, + struct ib_mad *mad) +{ + struct ib_event event; + + if ((mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED || + mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) && + mad->mad_hdr.method == IB_MGMT_METHOD_SET) { + if (mad->mad_hdr.attr_id == IB_SMP_ATTR_PORT_INFO) { + update_sm_ah(to_mdev(ibdev), port_num, + cl_ntoh16(*(__be16 *) (mad->data + 58)), + (*(u8 *) (mad->data + 76)) & 0xf); + + event.device = ibdev; + event.event = IB_EVENT_LID_CHANGE; + event.element.port_num = port_num; + ib_dispatch_event(&event); + } + + if (mad->mad_hdr.attr_id == IB_SMP_ATTR_PKEY_TABLE) { + event.device = ibdev; + event.event = IB_EVENT_PKEY_CHANGE; + event.element.port_num = port_num; + ib_dispatch_event(&event); + } + } +} + +static void forward_trap(struct mthca_dev *dev, + u8 port_num, + struct ib_mad *mad) +{ + int qpn = mad->mad_hdr.mgmt_class != IB_MGMT_CLASS_SUBN_LID_ROUTED; + struct mthca_trap_mad *tmad; + struct ib_sge gather_list; + struct _ib_send_wr wr; + struct ib_mad_agent *agent = dev->send_agent[port_num - 1][qpn]; + int ret; + SPIN_LOCK_PREP(lh); + + /* fill the template */ + wr.ds_array = (ib_local_ds_t*)(void*)&gather_list; + wr.num_ds = 1; + wr.wr_type = WR_SEND; + wr.send_opt = IB_SEND_OPT_SIGNALED; + wr.dgrm.ud.remote_qp = cl_hton32(qpn); + wr.dgrm.ud.remote_qkey = qpn ? IB_QP1_QKEY : 0; + + if (agent) { + tmad = kmalloc(sizeof *tmad, GFP_KERNEL); + if (!tmad) + return; + + alloc_dma_zmem(dev, sizeof *mad, &tmad->sg); + if (!tmad->sg.page) { + kfree(tmad); + return; + } + + memcpy(tmad->sg.page, mad, sizeof *mad); + + wr.dgrm.ud.rsvd = (void*)&((struct ib_mad *)tmad->sg.page)->mad_hdr; + wr.wr_id = (u64)(ULONG_PTR)tmad; + gather_list.addr = tmad->sg.dma_address; + gather_list.length = tmad->sg.length; + gather_list.lkey = to_mpd(agent->qp->pd)->ntmr.ibmr.lkey; + + /* + * We rely here on the fact that MLX QPs don't use the + * address handle after the send is posted (this is + * wrong following the IB spec strictly, but we know + * it's OK for our devices). + */ + spin_lock_irqsave(&dev->sm_lock, &lh); + wr.dgrm.ud.h_av = (ib_av_handle_t)dev->sm_ah[port_num - 1]; + if (wr.dgrm.ud.h_av) { + HCA_PRINT( TRACE_LEVEL_ERROR ,HCA_DBG_MAD ,(" ib_post_send_mad not ported \n" )); + ret = -EINVAL; + } + else + ret = -EINVAL; + spin_unlock_irqrestore(&lh); + + if (ret) { + free_dma_mem_map(dev, &tmad->sg, PCI_DMA_BIDIRECTIONAL ); + kfree(tmad); + } + } +} + +int mthca_process_mad(struct ib_device *ibdev, + int mad_flags, + u8 port_num, + struct _ib_wc *in_wc, + struct _ib_grh *in_grh, + struct ib_mad *in_mad, + struct ib_mad *out_mad) +{ + int err; + u8 status; + u16 slid = in_wc ? in_wc->recv.ud.remote_lid : cl_ntoh16(IB_LID_PERMISSIVE); + + HCA_PRINT( TRACE_LEVEL_VERBOSE ,HCA_DBG_MAD ,("in: Class %02x, Method %02x, AttrId %x, AttrMod %x, ClSpec %x, Tid %I64x\n", + (u32)in_mad->mad_hdr.mgmt_class, (u32)in_mad->mad_hdr.method, + (u32)in_mad->mad_hdr.attr_id, in_mad->mad_hdr.attr_mod, + (u32)in_mad->mad_hdr.class_specific, in_mad->mad_hdr.tid )); + + /* Forward locally generated traps to the SM */ + if (in_mad->mad_hdr.method == IB_MGMT_METHOD_TRAP && + slid == 0) { + forward_trap(to_mdev(ibdev), port_num, in_mad); + HCA_PRINT( TRACE_LEVEL_VERBOSE ,HCA_DBG_MAD ,("Not sent, but locally forwarded\n")); + return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED; + } + + /* + * Only handle SM gets, sets and trap represses for SM class + * + * Only handle PMA and Mellanox vendor-specific class gets and + * sets for other classes. + */ + if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED || + in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) { + + if (in_mad->mad_hdr.method != IB_MGMT_METHOD_GET && + in_mad->mad_hdr.method != IB_MGMT_METHOD_SET && + in_mad->mad_hdr.method != IB_MGMT_METHOD_TRAP_REPRESS) { + HCA_PRINT( TRACE_LEVEL_VERBOSE,HCA_DBG_MAD,(" Skip some methods. Nothing done !\n")); + return IB_MAD_RESULT_SUCCESS; + } + + /* + * Don't process SMInfo queries or vendor-specific + * MADs -- the SMA can't handle them. + */ + if (in_mad->mad_hdr.attr_id == IB_SMP_ATTR_SM_INFO || + ((in_mad->mad_hdr.attr_id & IB_SMP_ATTR_VENDOR_MASK) == + IB_SMP_ATTR_VENDOR_MASK)) { + HCA_PRINT( TRACE_LEVEL_VERBOSE ,HCA_DBG_MAD ,("Skip SMInfo queries or vendor-specific MADs. Nothing done !\n")); + return IB_MAD_RESULT_SUCCESS; + } + } + else { + if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_PERF_MGMT || + in_mad->mad_hdr.mgmt_class == IB_MLX_VENDOR_CLASS1 || + in_mad->mad_hdr.mgmt_class == IB_MLX_VENDOR_CLASS2) { + + if (in_mad->mad_hdr.method != IB_MGMT_METHOD_GET && + in_mad->mad_hdr.method != IB_MGMT_METHOD_SET) { + HCA_PRINT( TRACE_LEVEL_VERBOSE ,HCA_DBG_MAD ,("Skip some management methods. Nothing done !\n")); + return IB_MAD_RESULT_SUCCESS; + } + } + else { + HCA_PRINT( TRACE_LEVEL_VERBOSE ,HCA_DBG_MAD ,("Skip IB_MGMT_CLASS_PERF_MGMT et al. Nothing done !\n")); + return IB_MAD_RESULT_SUCCESS; + } + } + + // send MAD + err = mthca_MAD_IFC(to_mdev(ibdev), + mad_flags & IB_MAD_IGNORE_MKEY, + mad_flags & IB_MAD_IGNORE_BKEY, + port_num, in_wc, in_grh, in_mad, out_mad, + &status); + if (err) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_MAD ,("MAD_IFC failed\n")); + return IB_MAD_RESULT_FAILURE; + } + if (status == MTHCA_CMD_STAT_BAD_PKT) + return IB_MAD_RESULT_SUCCESS; + if (status) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_MAD ,("MAD_IFC returned status %02x\n", status)); + return IB_MAD_RESULT_FAILURE; + } + + if (!out_mad->mad_hdr.status) + smp_snoop(ibdev, port_num, in_mad); + + HCA_PRINT( TRACE_LEVEL_VERBOSE ,HCA_DBG_MAD,("out: Class %02x, Method %02x, AttrId %x, AttrMod %x, ClSpec %x, Tid %I64x, Status %x\n", + (u32)out_mad->mad_hdr.mgmt_class, (u32)out_mad->mad_hdr.method, + (u32)out_mad->mad_hdr.attr_id, out_mad->mad_hdr.attr_mod, + (u32)out_mad->mad_hdr.class_specific, out_mad->mad_hdr.tid, + (u32)out_mad->mad_hdr.status )); + + if (in_mad->mad_hdr.method == IB_MGMT_METHOD_TRAP_REPRESS) { + /* no response for trap repress */ + return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED; + } + + return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY; +} + +static void send_handler(struct ib_mad_agent *agent, + struct ib_mad_send_wc *mad_send_wc) +{ + struct mthca_trap_mad *tmad = + (void *) (ULONG_PTR) mad_send_wc->wr_id; + + free_dma_mem_map(agent->device->mdev, &tmad->sg, PCI_DMA_BIDIRECTIONAL ); + kfree(tmad); +} diff --git a/branches/WOF2-3/hw/mthca/kernel/mthca_main.c b/branches/WOF2-3/hw/mthca/kernel/mthca_main.c new file mode 100644 index 00000000..85012dcb --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/mthca_main.c @@ -0,0 +1,1095 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include "mthca_dev.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "mthca_main.tmh" +#endif +#include "mthca_config_reg.h" +#include "mthca_cmd.h" +#include "mthca_profile.h" +#include "mthca_memfree.h" + +static const char mthca_version[] = + DRV_NAME ": HCA Driver v" + DRV_VERSION " (" DRV_RELDATE ")"; + +static struct mthca_profile default_profile = { + 1 << 16, // num_qp + 4, // rdb_per_qp + 0, // num_srq + 1 << 16, // num_cq + 1 << 13, // num_mcg + 1 << 17, // num_mpt + 1 << 20, // num_mtt + 1 << 15, // num_udav (Tavor only) + 0, // num_uar + 1 << 18, // uarc_size (Arbel only) + 1 << 18, // fmr_reserved_mtts (Tavor only) +}; + +/* Types of supported HCA */ +enum __hca_type { + TAVOR, /* MT23108 */ + ARBEL_COMPAT, /* MT25208 in Tavor compat mode */ + ARBEL_NATIVE, /* MT25218 with extended features */ + SINAI /* MT25204 */ +}; + +#define MTHCA_FW_VER(major, minor, subminor) \ + (((u64) (major) << 32) | ((u64) (minor) << 16) | (u64) (subminor)) + +static struct { + u64 max_unsupported_fw; + u64 min_supported_fw; + int is_memfree; + int is_pcie; +} mthca_hca_table[] = { + { MTHCA_FW_VER(3, 3, 2), MTHCA_FW_VER(3, 5, 0), 0, 0 }, /* TAVOR */ + { MTHCA_FW_VER(4, 7, 0), MTHCA_FW_VER(4, 8, 200), 0, 1 }, /* ARBEL_COMPAT */ + { MTHCA_FW_VER(5, 1, 0), MTHCA_FW_VER(5, 3, 0), 1, 1 }, /* ARBEL_NATIVE */ + { MTHCA_FW_VER(1, 0, 800), MTHCA_FW_VER(1, 2, 0), 1, 1 } /* SINAI */ +}; + + +#define HCA(v, d, t) \ + { PCI_VENDOR_ID_##v, PCI_DEVICE_ID_MELLANOX_##d, t } + +static struct pci_device_id { + unsigned vendor; + unsigned device; + enum __hca_type driver_data; +} mthca_pci_table[] = { + HCA(MELLANOX, TAVOR, TAVOR), + HCA(MELLANOX, ARBEL_COMPAT, ARBEL_COMPAT), + HCA(MELLANOX, ARBEL, ARBEL_NATIVE), + HCA(MELLANOX, SINAI_OLD, SINAI), + HCA(MELLANOX, SINAI, SINAI), + HCA(TOPSPIN, TAVOR, TAVOR), + HCA(TOPSPIN, ARBEL_COMPAT, TAVOR), + HCA(TOPSPIN, ARBEL, ARBEL_NATIVE), + HCA(TOPSPIN, SINAI_OLD, SINAI), + HCA(TOPSPIN, SINAI, SINAI), +}; +#define MTHCA_PCI_TABLE_SIZE (sizeof(mthca_pci_table)/sizeof(struct pci_device_id)) + +// wrapper to driver's hca_tune_pci +static NTSTATUS mthca_tune_pci(struct mthca_dev *mdev) +{ + PDEVICE_OBJECT pdo = mdev->ext->cl_ext.p_self_do; + return hca_tune_pci(pdo, &mdev->uplink_info); +} + +int mthca_get_dev_info(struct mthca_dev *mdev, __be64 *node_guid, u32 *hw_id) +{ + struct ib_device_attr props; + struct ib_device *ib_dev = &mdev->ib_dev; + int err = (ib_dev->query_device )(ib_dev, &props ); + + if (err) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("can't get guid - mthca_query_port() failed (%08X)\n", err )); + return err; + } + + //TODO: do we need to convert GUID to LE by cl_ntoh64(x) ? + *node_guid = ib_dev->node_guid; + *hw_id = props.hw_ver; + return 0; +} + +static struct pci_device_id * mthca_find_pci_dev(unsigned ven_id, unsigned dev_id) +{ + struct pci_device_id *p_id = mthca_pci_table; + int i; + + // find p_id (appropriate line in mthca_pci_table) + for (i = 0; i < MTHCA_PCI_TABLE_SIZE; ++i, ++p_id) { + if (p_id->device == dev_id && p_id->vendor == ven_id) + return p_id; + } + return NULL; +} + + +static int mthca_dev_lim(struct mthca_dev *mdev, struct mthca_dev_lim *dev_lim) +{ + int err; + u8 status; + + err = mthca_QUERY_DEV_LIM(mdev, dev_lim, &status); + if (err) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("QUERY_DEV_LIM command failed, aborting.\n")); + return err; + } + if (status) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("QUERY_DEV_LIM returned status 0x%02x, " + "aborting.\n", status)); + return -EINVAL; + } + if (dev_lim->min_page_sz > PAGE_SIZE) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("HCA minimum page size of %d bigger than " + "kernel PAGE_SIZE of %ld, aborting.\n", + dev_lim->min_page_sz, PAGE_SIZE)); + return -ENODEV; + } + if (dev_lim->num_ports > MTHCA_MAX_PORTS) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("HCA has %d ports, but we only support %d, " + "aborting.\n", + dev_lim->num_ports, MTHCA_MAX_PORTS)); + return -ENODEV; + } + + if (dev_lim->uar_size > (int)pci_resource_len(mdev, HCA_BAR_TYPE_UAR)) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW , ("HCA reported UAR size of 0x%x bigger than " + "Bar%d size of 0x%lx, aborting.\n", + dev_lim->uar_size, HCA_BAR_TYPE_UAR, + (unsigned long)pci_resource_len(mdev, HCA_BAR_TYPE_UAR))); + return -ENODEV; + } + + + mdev->limits.num_ports = dev_lim->num_ports; + mdev->limits.vl_cap = dev_lim->max_vl; + mdev->limits.mtu_cap = dev_lim->max_mtu; + mdev->limits.gid_table_len = dev_lim->max_gids; + mdev->limits.pkey_table_len = dev_lim->max_pkeys; + mdev->limits.local_ca_ack_delay = dev_lim->local_ca_ack_delay; + mdev->limits.max_sg = dev_lim->max_sg; + mdev->limits.max_wqes = dev_lim->max_qp_sz; + mdev->limits.max_qp_init_rdma = dev_lim->max_requester_per_qp; + mdev->limits.reserved_qps = dev_lim->reserved_qps; + mdev->limits.max_srq_wqes = dev_lim->max_srq_sz; + mdev->limits.reserved_srqs = dev_lim->reserved_srqs; + mdev->limits.reserved_eecs = dev_lim->reserved_eecs; + mdev->limits.max_desc_sz = dev_lim->max_desc_sz; + mdev->limits.max_srq_sge = mthca_max_srq_sge(mdev); + /* + * Subtract 1 from the limit because we need to allocate a + * spare CQE so the HCA HW can tell the difference between an + * empty CQ and a full CQ. + */ + mdev->limits.max_cqes = dev_lim->max_cq_sz - 1; + mdev->limits.reserved_cqs = dev_lim->reserved_cqs; + mdev->limits.reserved_eqs = dev_lim->reserved_eqs; + mdev->limits.reserved_mtts = dev_lim->reserved_mtts; + mdev->limits.reserved_mrws = dev_lim->reserved_mrws; + mdev->limits.reserved_uars = dev_lim->reserved_uars; + mdev->limits.reserved_pds = dev_lim->reserved_pds; + mdev->limits.port_width_cap = (u8)dev_lim->max_port_width; + mdev->limits.page_size_cap = !(u32)(dev_lim->min_page_sz - 1); + mdev->limits.flags = dev_lim->flags; + mdev->limits.num_avs = mthca_is_memfree(mdev) ? 0 : dev_lim->hca.tavor.max_avs; + + /* IB_DEVICE_RESIZE_MAX_WR not supported by driver. + May be doable since hardware supports it for SRQ. + + IB_DEVICE_N_NOTIFY_CQ is supported by hardware but not by driver. + + IB_DEVICE_SRQ_RESIZE is supported by hardware but SRQ is not + supported by driver. */ + mdev->device_cap_flags = IB_DEVICE_CHANGE_PHY_PORT | + IB_DEVICE_PORT_ACTIVE_EVENT | + IB_DEVICE_SYS_IMAGE_GUID | + IB_DEVICE_RC_RNR_NAK_GEN; + + if (dev_lim->flags & DEV_LIM_FLAG_BAD_PKEY_CNTR) + mdev->device_cap_flags |= IB_DEVICE_BAD_PKEY_CNTR; + + if (dev_lim->flags & DEV_LIM_FLAG_BAD_QKEY_CNTR) + mdev->device_cap_flags |= IB_DEVICE_BAD_QKEY_CNTR; + + if (dev_lim->flags & DEV_LIM_FLAG_RAW_MULTI) + mdev->device_cap_flags |= IB_DEVICE_RAW_MULTI; + + if (dev_lim->flags & DEV_LIM_FLAG_AUTO_PATH_MIG) + mdev->device_cap_flags |= IB_DEVICE_AUTO_PATH_MIG; + + if (dev_lim->flags & DEV_LIM_FLAG_UD_AV_PORT_ENFORCE) + mdev->device_cap_flags |= IB_DEVICE_UD_AV_PORT_ENFORCE; + + if (dev_lim->flags & DEV_LIM_FLAG_SRQ) + mdev->mthca_flags |= MTHCA_FLAG_SRQ; + + if (mthca_is_memfree(mdev)) { + if (dev_lim->flags & DEV_LIM_FLAG_IPOIB_CSUM) + mdev->device_cap_flags |= IB_DEVICE_IPOIB_CSUM; //IB_DEVICE_UD_IP_CSUM; + } + + return 0; +} + +static int mthca_init_tavor(struct mthca_dev *mdev) +{ + u8 status; + int err; + struct mthca_dev_lim dev_lim; + struct mthca_profile profile; + struct mthca_init_hca_param init_hca; + + err = mthca_SYS_EN(mdev, &status); + if (err) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("SYS_EN command failed, aborting.\n")); + return err; + } + if (status) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("SYS_EN returned status 0x%02x, " + "aborting.\n", status)); + return -EINVAL; + } + + err = mthca_QUERY_FW(mdev, &status); + if (err) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("QUERY_FW command failed, aborting.\n")); + goto err_disable; + } + if (status) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("QUERY_FW returned status 0x%02x, " + "aborting.\n", status)); + err = -EINVAL; + goto err_disable; + } + err = mthca_QUERY_DDR(mdev, &status); + if (err) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("QUERY_DDR command failed, aborting.\n")); + goto err_disable; + } + if (status) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,( "QUERY_DDR returned status 0x%02x, " + "aborting.\n", status)); + err = -EINVAL; + goto err_disable; + } + + err = mthca_dev_lim(mdev, &dev_lim); + if (err) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,( "QUERY_DEV_LIM command failed, aborting.\n")); + goto err_disable; + } + + profile = default_profile; + profile.num_uar = dev_lim.uar_size / PAGE_SIZE; + profile.uarc_size = 0; + + /* correct default profile */ + if ( g_profile_qp_num != 0 ) + profile.num_qp = g_profile_qp_num; + + if ( g_profile_rd_out != 0xffffffff ) + profile.rdb_per_qp = g_profile_rd_out; + + if (mdev->mthca_flags & MTHCA_FLAG_SRQ) + profile.num_srq = dev_lim.max_srqs; + + err = (int)mthca_make_profile(mdev, &profile, &dev_lim, &init_hca); + if (err < 0) + goto err_disable; + + err = (int)mthca_INIT_HCA(mdev, &init_hca, &status); + if (err) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("INIT_HCA command failed, aborting.\n")); + goto err_disable; + } + if (status) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("INIT_HCA returned status 0x%02x, " + "aborting.\n", status)); + err = -EINVAL; + goto err_disable; + } + + return 0; + +err_disable: + mthca_SYS_DIS(mdev, &status); + + return err; +} + +static int mthca_load_fw(struct mthca_dev *mdev) +{ + u8 status; + int err; + + /* FIXME: use HCA-attached memory for FW if present */ + + mdev->fw.arbel.fw_icm = + mthca_alloc_icm(mdev, mdev->fw.arbel.fw_pages, + GFP_HIGHUSER | __GFP_NOWARN); + if (!mdev->fw.arbel.fw_icm) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Couldn't allocate FW area, aborting.\n")); + return -ENOMEM; + } + + err = mthca_MAP_FA(mdev, mdev->fw.arbel.fw_icm, &status); + if (err) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("MAP_FA command failed, aborting.\n")); + goto err_free; + } + if (status) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("MAP_FA returned status 0x%02x, aborting.\n", status)); + err = -EINVAL; + goto err_free; + } + err = mthca_RUN_FW(mdev, &status); + if (err) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("RUN_FW command failed, aborting.\n")); + goto err_unmap_fa; + } + if (status) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("RUN_FW returned status 0x%02x, aborting.\n", status)); + err = -EINVAL; + goto err_unmap_fa; + } + + return 0; + +err_unmap_fa: + mthca_UNMAP_FA(mdev, &status); + +err_free: + mthca_free_icm(mdev, mdev->fw.arbel.fw_icm); + return err; +} + +static int mthca_init_icm(struct mthca_dev *mdev, + struct mthca_dev_lim *dev_lim, + struct mthca_init_hca_param *init_hca, + u64 icm_size) +{ + u64 aux_pages; + u8 status; + int err; + + err = mthca_SET_ICM_SIZE(mdev, icm_size, &aux_pages, &status); + if (err) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("SET_ICM_SIZE command failed, aborting.\n")); + return err; + } + if (status) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("SET_ICM_SIZE returned status 0x%02x, " + "aborting.\n", status)); + return -EINVAL; + } + + HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_LOW , ("%I64d KB of HCA context requires %I64d KB aux memory.\n", + (u64) icm_size >> 10, + (u64) aux_pages << 2)); + + mdev->fw.arbel.aux_icm = mthca_alloc_icm(mdev, (int)aux_pages, + GFP_HIGHUSER | __GFP_NOWARN); + if (!mdev->fw.arbel.aux_icm) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Couldn't allocate aux memory, aborting.\n")); + return -ENOMEM; + } + + err = mthca_MAP_ICM_AUX(mdev, mdev->fw.arbel.aux_icm, &status); + if (err) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("MAP_ICM_AUX command failed, aborting.\n")); + goto err_free_aux; + } + if (status) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("MAP_ICM_AUX returned status 0x%02x, aborting.\n", status)); + err = -EINVAL; + goto err_free_aux; + } + + err = mthca_map_eq_icm(mdev, init_hca->eqc_base); + if (err) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Failed to map EQ context memory, aborting.\n")); + goto err_unmap_aux; + } + + /* CPU writes to non-reserved MTTs, while HCA might DMA to reserved mtts */ + mdev->limits.reserved_mtts = ALIGN(mdev->limits.reserved_mtts * MTHCA_MTT_SEG_SIZE, + dma_get_cache_alignment()) / MTHCA_MTT_SEG_SIZE; + + mdev->mr_table.mtt_table = mthca_alloc_icm_table(mdev, init_hca->mtt_base, + MTHCA_MTT_SEG_SIZE, + mdev->limits.num_mtt_segs, + mdev->limits.reserved_mtts, 1); + if (!mdev->mr_table.mtt_table) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Failed to map MTT context memory, aborting.\n")); + err = -ENOMEM; + goto err_unmap_eq; + } + + mdev->mr_table.mpt_table = mthca_alloc_icm_table(mdev, init_hca->mpt_base, + dev_lim->mpt_entry_sz, + mdev->limits.num_mpts, + mdev->limits.reserved_mrws, 1); + if (!mdev->mr_table.mpt_table) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Failed to map MPT context memory, aborting.\n")); + err = -ENOMEM; + goto err_unmap_mtt; + } + + mdev->qp_table.qp_table = mthca_alloc_icm_table(mdev, init_hca->qpc_base, + dev_lim->qpc_entry_sz, + mdev->limits.num_qps, + mdev->limits.reserved_qps, 0); + if (!mdev->qp_table.qp_table) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Failed to map QP context memory, aborting.\n")); + err = -ENOMEM; + goto err_unmap_mpt; + } + + mdev->qp_table.eqp_table = mthca_alloc_icm_table(mdev, init_hca->eqpc_base, + dev_lim->eqpc_entry_sz, + mdev->limits.num_qps, + mdev->limits.reserved_qps, 0); + if (!mdev->qp_table.eqp_table) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Failed to map EQP context memory, aborting.\n")); + err = -ENOMEM; + goto err_unmap_qp; + } + + mdev->qp_table.rdb_table = mthca_alloc_icm_table(mdev, init_hca->rdb_base, + MTHCA_RDB_ENTRY_SIZE, + mdev->limits.num_qps << + mdev->qp_table.rdb_shift, + 0, 0); + if (!mdev->qp_table.rdb_table) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Failed to map RDB context memory, aborting\n")); + err = -ENOMEM; + goto err_unmap_eqp; + } + + mdev->cq_table.table = mthca_alloc_icm_table(mdev, init_hca->cqc_base, + dev_lim->cqc_entry_sz, + mdev->limits.num_cqs, + mdev->limits.reserved_cqs, 0); + if (!mdev->cq_table.table) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Failed to map CQ context memory, aborting.\n")); + err = -ENOMEM; + goto err_unmap_rdb; + } + + if (mdev->mthca_flags & MTHCA_FLAG_SRQ) { + mdev->srq_table.table = + mthca_alloc_icm_table(mdev, init_hca->srqc_base, + dev_lim->srq_entry_sz, + mdev->limits.num_srqs, + mdev->limits.reserved_srqs, 0); + if (!mdev->srq_table.table) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Failed to map SRQ context memory, " + "aborting.\n")); + err = -ENOMEM; + goto err_unmap_cq; + } + } + + /* + * It's not strictly required, but for simplicity just map the + * whole multicast group table now. The table isn't very big + * and it's a lot easier than trying to track ref counts. + */ + mdev->mcg_table.table = mthca_alloc_icm_table(mdev, init_hca->mc_base, + MTHCA_MGM_ENTRY_SIZE, + mdev->limits.num_mgms + + mdev->limits.num_amgms, + mdev->limits.num_mgms + + mdev->limits.num_amgms, + 0); + if (!mdev->mcg_table.table) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Failed to map MCG context memory, aborting.\n")); + err = -ENOMEM; + goto err_unmap_srq; + } + + return 0; + +err_unmap_srq: + if (mdev->mthca_flags & MTHCA_FLAG_SRQ) + mthca_free_icm_table(mdev, mdev->srq_table.table); + +err_unmap_cq: + mthca_free_icm_table(mdev, mdev->cq_table.table); + +err_unmap_rdb: + mthca_free_icm_table(mdev, mdev->qp_table.rdb_table); + +err_unmap_eqp: + mthca_free_icm_table(mdev, mdev->qp_table.eqp_table); + +err_unmap_qp: + mthca_free_icm_table(mdev, mdev->qp_table.qp_table); + +err_unmap_mpt: + mthca_free_icm_table(mdev, mdev->mr_table.mpt_table); + +err_unmap_mtt: + mthca_free_icm_table(mdev, mdev->mr_table.mtt_table); + +err_unmap_eq: + mthca_unmap_eq_icm(mdev); + +err_unmap_aux: + mthca_UNMAP_ICM_AUX(mdev, &status); + +err_free_aux: + mthca_free_icm(mdev, mdev->fw.arbel.aux_icm); + + return err; +} + +static int mthca_init_arbel(struct mthca_dev *mdev) +{ + struct mthca_dev_lim dev_lim; + struct mthca_profile profile; + struct mthca_init_hca_param init_hca; + u64 icm_size; + u8 status; + int err; + + err = mthca_QUERY_FW(mdev, &status); + if (err) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("QUERY_FW command failed, aborting.\n")); + return err; + } + if (status) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("QUERY_FW returned status 0x%02x, " + "aborting.\n", status)); + return -EINVAL; + } + + err = mthca_ENABLE_LAM(mdev, &status); + if (err) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("ENABLE_LAM command failed, aborting.\n")); + return err; + } + if (status == MTHCA_CMD_STAT_LAM_NOT_PRE) { + HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_LOW ,("No HCA-attached memory (running in MemFree mode)\n")); + mdev->mthca_flags |= MTHCA_FLAG_NO_LAM; + } else if (status) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("ENABLE_LAM returned status 0x%02x, " + "aborting.\n", status)); + return -EINVAL; + } + + err = mthca_load_fw(mdev); + if (err) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Failed to start FW, aborting.\n")); + goto err_disable; + } + + err = mthca_dev_lim(mdev, &dev_lim); + if (err) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("QUERY_DEV_LIM command failed, aborting.\n")); + goto err_stop_fw; + } + + profile = default_profile; + profile.num_uar = dev_lim.uar_size / PAGE_SIZE; + profile.num_udav = 0; + if (mdev->mthca_flags & MTHCA_FLAG_SRQ) + profile.num_srq = dev_lim.max_srqs; + + /* correct default profile */ + if ( g_profile_qp_num != 0 ) + profile.num_qp = g_profile_qp_num; + + if ( g_profile_rd_out != 0xffffffff ) + profile.rdb_per_qp = g_profile_rd_out; + + RtlZeroMemory( &init_hca, sizeof(init_hca)); + icm_size = mthca_make_profile(mdev, &profile, &dev_lim, &init_hca); + if ((int) icm_size < 0) { + err = (int)icm_size; + goto err_stop_fw; + } + + err = mthca_init_icm(mdev, &dev_lim, &init_hca, icm_size); + if (err) + goto err_stop_fw; + + err = mthca_INIT_HCA(mdev, &init_hca, &status); + if (err) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("INIT_HCA command failed, aborting.\n")); + goto err_free_icm; + } + if (status) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("INIT_HCA returned status 0x%02x, " + "aborting.\n", status)); + err = -EINVAL; + goto err_free_icm; + } + + return 0; + +err_free_icm: + if (mdev->mthca_flags & MTHCA_FLAG_SRQ) + mthca_free_icm_table(mdev, mdev->srq_table.table); + mthca_free_icm_table(mdev, mdev->cq_table.table); + mthca_free_icm_table(mdev, mdev->qp_table.rdb_table); + mthca_free_icm_table(mdev, mdev->qp_table.eqp_table); + mthca_free_icm_table(mdev, mdev->qp_table.qp_table); + mthca_free_icm_table(mdev, mdev->mr_table.mpt_table); + mthca_free_icm_table(mdev, mdev->mr_table.mtt_table); + mthca_unmap_eq_icm(mdev); + + mthca_UNMAP_ICM_AUX(mdev, &status); + mthca_free_icm(mdev, mdev->fw.arbel.aux_icm); + +err_stop_fw: + mthca_UNMAP_FA(mdev, &status); + mthca_free_icm(mdev, mdev->fw.arbel.fw_icm); + +err_disable: + if (!(mdev->mthca_flags & MTHCA_FLAG_NO_LAM)) + mthca_DISABLE_LAM(mdev, &status); + + return err; +} + +static void mthca_close_hca(struct mthca_dev *mdev) +{ + u8 status; + + mthca_CLOSE_HCA(mdev, 0, &status); + + if (mthca_is_memfree(mdev)) { + if (mdev->mthca_flags & MTHCA_FLAG_SRQ) + mthca_free_icm_table(mdev, mdev->srq_table.table); + mthca_free_icm_table(mdev, mdev->cq_table.table); + mthca_free_icm_table(mdev, mdev->qp_table.rdb_table); + mthca_free_icm_table(mdev, mdev->qp_table.eqp_table); + mthca_free_icm_table(mdev, mdev->qp_table.qp_table); + mthca_free_icm_table(mdev, mdev->mr_table.mpt_table); + mthca_free_icm_table(mdev, mdev->mr_table.mtt_table); + mthca_free_icm_table(mdev, mdev->mcg_table.table); + mthca_unmap_eq_icm(mdev); + + mthca_UNMAP_ICM_AUX(mdev, &status); + mthca_free_icm(mdev, mdev->fw.arbel.aux_icm); + + mthca_UNMAP_FA(mdev, &status); + mthca_free_icm(mdev, mdev->fw.arbel.fw_icm); + + if (!(mdev->mthca_flags & MTHCA_FLAG_NO_LAM)) + mthca_DISABLE_LAM(mdev, &status); + } else + mthca_SYS_DIS(mdev, &status); +} + +static int mthca_init_hca(struct mthca_dev *mdev) +{ + u8 status; + int err; + struct mthca_adapter adapter; + + if (mthca_is_memfree(mdev)) + err = mthca_init_arbel(mdev); + else + err = mthca_init_tavor(mdev); + + if (err) + return err; + + err = mthca_QUERY_ADAPTER(mdev, &adapter, &status); + if (err) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("QUERY_ADAPTER command failed, aborting.\n")); + goto err_close; + } + if (status) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("QUERY_ADAPTER returned status 0x%02x, " + "aborting.\n", status)); + err = -EINVAL; + goto err_close; + } + + mdev->eq_table.inta_pin = adapter.inta_pin; + mdev->rev_id = adapter.revision_id; + memcpy(mdev->board_id, adapter.board_id, sizeof mdev->board_id); + + return 0; + +err_close: + mthca_close_hca(mdev); + return err; +} + +static int mthca_setup_hca(struct mthca_dev *mdev) +{ + int err; + u8 status; + + MTHCA_INIT_DOORBELL_LOCK(&mdev->doorbell_lock); + + err = mthca_init_uar_table(mdev); + if (err) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Failed to initialize " + "user access region table, aborting.\n")); + return err; + } + + err = mthca_uar_alloc(mdev, &mdev->driver_uar); + if (err) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Failed to allocate driver access region, " + "aborting.\n")); + goto err_uar_table_free; + } + + mdev->kar = ioremap((io_addr_t)mdev->driver_uar.pfn << PAGE_SHIFT, PAGE_SIZE,&mdev->kar_size); + if (!mdev->kar) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Couldn't map kernel access region, " + "aborting.\n")); + err = -ENOMEM; + goto err_uar_free; + } + + err = mthca_init_pd_table(mdev); + if (err) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Failed to initialize " + "protection domain table, aborting.\n")); + goto err_kar_unmap; + } + + err = mthca_init_mr_table(mdev); + if (err) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Failed to initialize " + "memory region table, aborting.\n")); + goto err_pd_table_free; + } + + err = mthca_pd_alloc(mdev, 1, &mdev->driver_pd); + if (err) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Failed to create driver PD, " + "aborting.\n")); + goto err_mr_table_free; + } + + err = mthca_init_eq_table(mdev); + if (err) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW, ("Failed to initialize " + "event queue table, aborting.\n")); + goto err_pd_free; + } + + err = mthca_cmd_use_events(mdev); + if (err) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Failed to switch to event-driven " + "firmware commands, aborting.\n")); + goto err_eq_table_free; + } + + err = mthca_NOP(mdev, &status); + if (err || status) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("NOP command failed to generate interrupt, aborting.\n")); + if (mdev->mthca_flags & (MTHCA_FLAG_MSI | MTHCA_FLAG_MSI_X)){ + HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Try again with MSI/MSI-X disabled.\n")); + }else{ + HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("BIOS or ACPI interrupt routing problem?\n")); + } + + goto err_cmd_poll; + } + + HCA_PRINT(TRACE_LEVEL_VERBOSE ,HCA_DBG_LOW ,("NOP command IRQ test passed\n")); + + err = mthca_init_cq_table(mdev); + if (err) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Failed to initialize " + "completion queue table, aborting.\n")); + goto err_cmd_poll; + } + + err = mthca_init_srq_table(mdev); + if (err) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Failed to initialize " + "shared receive queue table, aborting.\n")); + goto err_cq_table_free; + } + + err = mthca_init_qp_table(mdev); + if (err) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW, ("Failed to initialize " + "queue pair table, aborting.\n")); + goto err_srq_table_free; + } + + err = mthca_init_av_table(mdev); + if (err) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Failed to initialize " + "address vector table, aborting.\n")); + goto err_qp_table_free; + } + + err = mthca_init_mcg_table(mdev); + if (err) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Failed to initialize " + "multicast group table, aborting.\n")); + goto err_av_table_free; + } + + return 0; + +err_av_table_free: + mthca_cleanup_av_table(mdev); + +err_qp_table_free: + mthca_cleanup_qp_table(mdev); + +err_srq_table_free: + mthca_cleanup_srq_table(mdev); + +err_cq_table_free: + mthca_cleanup_cq_table(mdev); + +err_cmd_poll: + mthca_cmd_use_polling(mdev); + +err_eq_table_free: + mthca_cleanup_eq_table(mdev); + +err_pd_free: + mthca_pd_free(mdev, &mdev->driver_pd); + +err_mr_table_free: + mthca_cleanup_mr_table(mdev); + +err_pd_table_free: + mthca_cleanup_pd_table(mdev); + +err_kar_unmap: + iounmap(mdev->kar, mdev->kar_size); + +err_uar_free: + mthca_uar_free(mdev, &mdev->driver_uar); + +err_uar_table_free: + mthca_cleanup_uar_table(mdev); + return err; +} + + +static int mthca_check_fw(struct mthca_dev *mdev, struct pci_device_id *p_id) +{ + int err = 0; + + if (mdev->fw_ver < mthca_hca_table[p_id->driver_data].max_unsupported_fw) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("HCA FW version %d.%d.%d is not supported. Use %d.%d.%d or higher.\n", + (int) (mdev->fw_ver >> 32), (int) (mdev->fw_ver >> 16) & 0xffff, + (int) (mdev->fw_ver & 0xffff), + (int) (mthca_hca_table[p_id->driver_data].max_unsupported_fw >> 32), + (int) (mthca_hca_table[p_id->driver_data].max_unsupported_fw >> 16) & 0xffff, + (int) (mthca_hca_table[p_id->driver_data].max_unsupported_fw & 0xffff))); + err = -ENODEV; + } + else + if (mdev->fw_ver < mthca_hca_table[p_id->driver_data].min_supported_fw) { + HCA_PRINT_EV(TRACE_LEVEL_WARNING ,HCA_DBG_LOW , + ("The HCA FW version is %d.%d.%d, which is not the latest one. \n" + "If you meet any issues with the HCA please first try to upgrade the FW to version %d.%d.%d or higher.\n", + (int) (mdev->fw_ver >> 32), (int) (mdev->fw_ver >> 16) & 0xffff, + (int) (mdev->fw_ver & 0xffff), + (int) (mthca_hca_table[p_id->driver_data].min_supported_fw >> 32), + (int) (mthca_hca_table[p_id->driver_data].min_supported_fw >> 16) & 0xffff, + (int) (mthca_hca_table[p_id->driver_data].min_supported_fw & 0xffff))); + } + else { + HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_LOW ,("Current HCA FW version is %d.%d.%d. \n", + (int) (mdev->fw_ver >> 32), (int) (mdev->fw_ver >> 16) & 0xffff, + (int) (mdev->fw_ver & 0xffff))); + } + + return err; +} + +NTSTATUS mthca_init_one(hca_dev_ext_t *ext) +{ + static int mthca_version_printed = 0; + int err; + NTSTATUS status; + struct mthca_dev *mdev; + struct pci_device_id *p_id; + + /* print version */ + if (!mthca_version_printed) { + HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_LOW ,("%s\n", mthca_version)); + ++mthca_version_printed; + } + + /* find the type of device */ + p_id = mthca_find_pci_dev( + (unsigned)ext->hcaConfig.VendorID, + (unsigned)ext->hcaConfig.DeviceID); + if (p_id == NULL) { + status = STATUS_NO_SUCH_DEVICE; + goto end; + } + + InitializeListHead(&ext->hca.hob.event_list); + KeInitializeSpinLock(&ext->hca.hob.event_list_lock); + + /* allocate mdev structure */ + mdev = kzalloc(sizeof *mdev, GFP_KERNEL); + if (!mdev) { + // can't use HCA_PRINT_EV here ! + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Device struct alloc failed, " + "aborting.\n")); + status = STATUS_INSUFFICIENT_RESOURCES; + goto end; + } + + /* set some fields */ + mdev->ext = ext; /* pointer to DEVICE OBJECT extension */ + mdev->hca_type = p_id->driver_data; + mdev->ib_dev.mdev = mdev; + if (ext->hca_hidden) + mdev->mthca_flags |= MTHCA_FLAG_DDR_HIDDEN; + if (mthca_hca_table[p_id->driver_data].is_memfree) + mdev->mthca_flags |= MTHCA_FLAG_MEMFREE; + if (mthca_hca_table[p_id->driver_data].is_pcie) + mdev->mthca_flags |= MTHCA_FLAG_PCIE; + +//TODO: after we have a FW, capable of reset, +// write a routine, that only presses the button + + /* + * Now reset the HCA before we touch the PCI capabilities or + * attempt a firmware command, since a boot ROM may have left + * the HCA in an undefined state. + */ + status = hca_reset( mdev->ext->cl_ext.p_self_do, p_id->driver_data == TAVOR ); + if ( !NT_SUCCESS( status ) ) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Failed to reset HCA, aborting.\n")); + goto err_free_dev; + } + + if (mthca_cmd_init(mdev)) { + HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Failed to init command interface, aborting.\n")); + status = STATUS_DEVICE_DATA_ERROR; + goto err_free_dev; + } + + status = mthca_tune_pci(mdev); + if ( !NT_SUCCESS( status ) ) { + goto err_cmd; + } + + err = mthca_init_hca(mdev); + if (err) { + status = STATUS_UNSUCCESSFUL; + goto err_cmd; + } + + err = mthca_check_fw(mdev, p_id); + if (err) { + status = STATUS_UNSUCCESSFUL; + goto err_close; + } + + err = mthca_setup_hca(mdev); + if (err) { + status = STATUS_UNSUCCESSFUL; + goto err_close; + } + + err = mthca_register_device(mdev); + if (err) { + status = STATUS_UNSUCCESSFUL; + goto err_cleanup; + } + + ext->hca.mdev = mdev; + mdev->state = MTHCA_DEV_INITIALIZED; + return 0; + +err_cleanup: + mthca_cleanup_mcg_table(mdev); + mthca_cleanup_av_table(mdev); + mthca_cleanup_qp_table(mdev); + mthca_cleanup_srq_table(mdev); + mthca_cleanup_cq_table(mdev); + mthca_cmd_use_polling(mdev); + mthca_cleanup_eq_table(mdev); + + mthca_pd_free(mdev, &mdev->driver_pd); + + mthca_cleanup_mr_table(mdev); + mthca_cleanup_pd_table(mdev); + mthca_cleanup_uar_table(mdev); + +err_close: + mthca_close_hca(mdev); + +err_cmd: + mthca_cmd_cleanup(mdev); + +err_free_dev: + kfree(mdev); + +end: + return status; +} + +void mthca_remove_one(hca_dev_ext_t *ext) +{ + struct mthca_dev *mdev = ext->hca.mdev; + u8 status; + int p; + + ext->hca.mdev = NULL; + if (mdev) { + mdev->state = MTHCA_DEV_UNINITIALIZED; + mthca_unregister_device(mdev); + + for (p = 1; p <= mdev->limits.num_ports; ++p) + mthca_CLOSE_IB(mdev, p, &status); + + mthca_cleanup_mcg_table(mdev); + mthca_cleanup_av_table(mdev); + mthca_cleanup_qp_table(mdev); + mthca_cleanup_srq_table(mdev); + mthca_cleanup_cq_table(mdev); + mthca_cmd_use_polling(mdev); + mthca_cleanup_eq_table(mdev); + mthca_pd_free(mdev, &mdev->driver_pd); + mthca_cleanup_mr_table(mdev); + mthca_cleanup_pd_table(mdev); + iounmap(mdev->kar, mdev->kar_size); + mthca_uar_free(mdev, &mdev->driver_uar); + mthca_cleanup_uar_table(mdev); + mthca_close_hca(mdev); + mthca_cmd_cleanup(mdev); + kfree(mdev); + } +} + + + diff --git a/branches/WOF2-3/hw/mthca/kernel/mthca_mcg.c b/branches/WOF2-3/hw/mthca/kernel/mthca_mcg.c new file mode 100644 index 00000000..dbf436b4 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/mthca_mcg.c @@ -0,0 +1,403 @@ +/* + * Copyright (c) 2004 Topspin Communications. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include "mthca_dev.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "mthca_mcg.tmh" +#endif +#include "mthca_cmd.h" + + +struct mthca_mgm { + __be32 next_gid_index; + u32 reserved[3]; + u8 gid[16]; + __be32 qp[MTHCA_QP_PER_MGM]; +}; + +static const u8 zero_gid[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + +/* + * Caller must hold MCG table semaphore. gid and mgm parameters must + * be properly aligned for command interface. + * + * Returns 0 unless a firmware command error occurs. + * + * If GID is found in MGM or MGM is empty, *index = *hash, *prev = -1 + * and *mgm holds MGM entry. + * + * if GID is found in AMGM, *index = index in AMGM, *prev = index of + * previous entry in hash chain and *mgm holds AMGM entry. + * + * If no AMGM exists for given gid, *index = -1, *prev = index of last + * entry in hash chain and *mgm holds end of hash chain. + */ +static int find_mgm(struct mthca_dev *dev, + u8 *gid, struct mthca_mailbox *mgm_mailbox, + u16 *hash, int *prev, int *index) +{ + struct mthca_mailbox *mailbox; + struct mthca_mgm *mgm = mgm_mailbox->buf; + u8 *mgid; + int err; + u8 status; + + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (IS_ERR(mailbox)) + return -ENOMEM; + mgid = mailbox->buf; + + memcpy(mgid, gid, 16); + + err = mthca_MGID_HASH(dev, mailbox, hash, &status); + if (err) + goto out; + if (status) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("MGID_HASH returned status %02x\n", status)); + err = -EINVAL; + goto out; + } + + HCA_PRINT(TRACE_LEVEL_VERBOSE,HCA_DBG_LOW,("Hash for %04x:%04x:%04x:%04x:" + "%04x:%04x:%04x:%04x is %04x\n", + cl_ntoh16(((__be16 *) gid)[0]), + cl_ntoh16(((__be16 *) gid)[1]), + cl_ntoh16(((__be16 *) gid)[2]), + cl_ntoh16(((__be16 *) gid)[3]), + cl_ntoh16(((__be16 *) gid)[4]), + cl_ntoh16(((__be16 *) gid)[5]), + cl_ntoh16(((__be16 *) gid)[6]), + cl_ntoh16(((__be16 *) gid)[7]), + *hash)); + + *index = *hash; + *prev = -1; + + do { + err = mthca_READ_MGM(dev, *index, mgm_mailbox, &status); + if (err) + goto out; + if (status) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("READ_MGM returned status %02x\n", status)); + err = -EINVAL; + goto out; + } + + if (!memcmp(mgm->gid, zero_gid, 16)) { + if (*index != *hash) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Found zero MGID in AMGM.\n")); + err = -EINVAL; + } + goto out; + } + + if (!memcmp(mgm->gid, gid, 16)) + goto out; + + *prev = *index; + *index = cl_ntoh32(mgm->next_gid_index) >> 6; + } while (*index); + + *index = -1; + + out: + mthca_free_mailbox(dev, mailbox); + return err; +} + +int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) +{ + struct mthca_dev *dev = to_mdev(ibqp->device); + struct mthca_mailbox *mailbox; + struct mthca_mgm *mgm; + u16 hash; + int index, prev; + int link = 0; + int i; + int err; + u8 status; + + UNREFERENCED_PARAMETER(lid); + + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + mgm = mailbox->buf; + + down(&dev->mcg_table.mutex); + + err = find_mgm(dev, gid->raw, mailbox, &hash, &prev, &index); + if (err) + goto out; + + if (index != -1) { + if (!memcmp(mgm->gid, zero_gid, 16)) + memcpy(mgm->gid, gid->raw, 16); + } else { + link = 1; + + index = mthca_alloc(&dev->mcg_table.alloc); + if (index == -1) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("No AMGM entries left\n")); + err = -ENOMEM; + goto out; + } + + err = mthca_READ_MGM(dev, index, mailbox, &status); + if (err) + goto out; + if (status) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("READ_MGM returned status %02x\n", status)); + err = -EINVAL; + goto out; + } + + memset(mgm, 0, sizeof *mgm); + memcpy(mgm->gid, gid->raw, 16); + mgm->next_gid_index = 0; + } + + for (i = 0; i < MTHCA_QP_PER_MGM; ++i) + if (mgm->qp[i] == cl_hton32(ibqp->qp_num | (1 << 31))) { + HCA_PRINT(TRACE_LEVEL_VERBOSE,HCA_DBG_LOW,("QP %06x already a member of MGM\n", + ibqp->qp_num)); + err = 0; + goto out; + } else if (!(mgm->qp[i] & cl_hton32(1UL << 31))) { + mgm->qp[i] = cl_hton32(ibqp->qp_num | (1 << 31)); + break; + } + + if (i == MTHCA_QP_PER_MGM) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("MGM at index %x is full.\n", index)); + err = -ENOMEM; + goto out; + } + + err = mthca_WRITE_MGM(dev, index, mailbox, &status); + if (err) + goto out; + if (status) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("WRITE_MGM returned status %02x\n", status)); + err = -EINVAL; + goto out; + } + + if (!link) + goto out; + + err = mthca_READ_MGM(dev, prev, mailbox, &status); + if (err) + goto out; + if (status) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("READ_MGM returned status %02x\n", status)); + err = -EINVAL; + goto out; + } + + mgm->next_gid_index = cl_hton32(index << 6); + + err = mthca_WRITE_MGM(dev, prev, mailbox, &status); + if (err) + goto out; + if (status) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("WRITE_MGM returned status %02x\n", status)); + err = -EINVAL; + } + +out: + if (err && link && index != -1) { + BUG_ON(index < dev->limits.num_mgms); + mthca_free(&dev->mcg_table.alloc, index); + } + KeReleaseMutex(&dev->mcg_table.mutex,FALSE); + mthca_free_mailbox(dev, mailbox); + return err; +} + +int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) +{ + struct mthca_dev *dev = to_mdev(ibqp->device); + struct mthca_mailbox *mailbox; + struct mthca_mgm *mgm; + u16 hash; + int prev, index; + int i, loc; + int err; + u8 status; + + UNREFERENCED_PARAMETER(lid); + + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + mgm = mailbox->buf; + + down(&dev->mcg_table.mutex); + + err = find_mgm(dev, gid->raw, mailbox, &hash, &prev, &index); + if (err) + goto out; + + if (index == -1) { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_LOW, ("MGID %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x " + "not found\n", + cl_ntoh16(((__be16 *) gid->raw)[0]), + cl_ntoh16(((__be16 *) gid->raw)[1]), + cl_ntoh16(((__be16 *) gid->raw)[2]), + cl_ntoh16(((__be16 *) gid->raw)[3]), + cl_ntoh16(((__be16 *) gid->raw)[4]), + cl_ntoh16(((__be16 *) gid->raw)[5]), + cl_ntoh16(((__be16 *) gid->raw)[6]), + cl_ntoh16(((__be16 *) gid->raw)[7]))); + err = -EINVAL; + goto out; + } + + for (loc = -1, i = 0; i < MTHCA_QP_PER_MGM; ++i) { + if (mgm->qp[i] == cl_hton32(ibqp->qp_num | (1 << 31))) + loc = i; + if (!(mgm->qp[i] & cl_hton32(1UL << 31))) + break; + } + + if (loc == -1) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("QP %06x not found in MGM\n", ibqp->qp_num)); + err = -EINVAL; + goto out; + } + + mgm->qp[loc] = mgm->qp[i - 1]; + mgm->qp[i - 1] = 0; + + err = mthca_WRITE_MGM(dev, index, mailbox, &status); + if (err) + goto out; + if (status) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("WRITE_MGM returned status %02x\n", status)); + err = -EINVAL; + goto out; + } + + if (i != 1) + goto out; + + if (prev == -1) { + /* Remove entry from MGM */ + int amgm_index_to_free = cl_ntoh32(mgm->next_gid_index) >> 6; + if (amgm_index_to_free) { + err = mthca_READ_MGM(dev, amgm_index_to_free, + mailbox, &status); + if (err) + goto out; + if (status) { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("READ_MGM returned status %02x\n", + status)); + err = -EINVAL; + goto out; + } + } else + RtlZeroMemory(mgm->gid, 16); + + err = mthca_WRITE_MGM(dev, index, mailbox, &status); + if (err) + goto out; + if (status) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("WRITE_MGM returned status %02x\n", status)); + err = -EINVAL; + goto out; + } + if (amgm_index_to_free) { + BUG_ON(amgm_index_to_free < dev->limits.num_mgms); + mthca_free(&dev->mcg_table.alloc, amgm_index_to_free); + } + } else { + /* Remove entry from AMGM */ + int curr_next_index = cl_ntoh32(mgm->next_gid_index) >> 6; + err = mthca_READ_MGM(dev, prev, mailbox, &status); + if (err) + goto out; + if (status) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("READ_MGM returned status %02x\n", status)); + err = -EINVAL; + goto out; + } + + mgm->next_gid_index = cl_hton32(curr_next_index << 6); + + err = mthca_WRITE_MGM(dev, prev, mailbox, &status); + if (err) + goto out; + if (status) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("WRITE_MGM returned status %02x\n", status)); + err = -EINVAL; + goto out; + } + BUG_ON(index < dev->limits.num_mgms); + mthca_free(&dev->mcg_table.alloc, index); + } + + out: + KeReleaseMutex(&dev->mcg_table.mutex, FALSE); + mthca_free_mailbox(dev, mailbox); + return err; +} + +int mthca_init_mcg_table(struct mthca_dev *dev) +{ + int err; + int table_size = dev->limits.num_mgms + dev->limits.num_amgms; + + err = mthca_alloc_init(&dev->mcg_table.alloc, + table_size, + table_size - 1, + dev->limits.num_mgms); + + if (err) + return err; + + KeInitializeMutex(&dev->mcg_table.mutex,0); + + return 0; +} + +void mthca_cleanup_mcg_table(struct mthca_dev *dev) +{ + mthca_alloc_cleanup(&dev->mcg_table.alloc); +} + + diff --git a/branches/WOF2-3/hw/mthca/kernel/mthca_memfree.c b/branches/WOF2-3/hw/mthca/kernel/mthca_memfree.c new file mode 100644 index 00000000..a781f116 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/mthca_memfree.c @@ -0,0 +1,729 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Cisco Systems. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include "hca_driver.h" +#include "mthca_memfree.h" +#include "mthca_dev.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "mthca_memfree.tmh" +#endif +#include "mthca_cmd.h" + +/* + * We allocate in as big chunks as we can, up to a maximum of 256 KB + * per chunk. + */ +enum { + MTHCA_ICM_ALLOC_SIZE = 1 << 18, + MTHCA_TABLE_CHUNK_SIZE = 1 << 18 +}; + +#pragma warning( disable : 4200) +struct mthca_user_db_table { + KMUTEX mutex; + struct { + u64 uvirt; + struct scatterlist mem; + int refcount; + } page[0]; +}; +#pragma warning( default : 4200) + +void mthca_free_icm(struct mthca_dev *dev, struct mthca_icm *icm) +{ + struct mthca_icm_chunk *chunk, *tmp; + int i; + + if (!icm) + return; + + list_for_each_entry_safe(chunk, tmp, &icm->chunk_list, list,struct mthca_icm_chunk,struct mthca_icm_chunk) { + if (chunk->nsg > 0) + pci_unmap_sg(dev, chunk->mem, chunk->npages, + PCI_DMA_BIDIRECTIONAL); + + for (i = 0; i < chunk->npages; ++i) + free_dma_mem_map(dev, &chunk->mem[i], PCI_DMA_BIDIRECTIONAL ); + + kfree(chunk); + } + + kfree(icm); +} + +/* allocate device memory of 'npages' pages as a list of chunks, each containing an array of + continuous buffers. Allocated physical pages, and then they are mapped to bus space !*/ +struct mthca_icm *mthca_alloc_icm(struct mthca_dev *dev, int npages, + unsigned int gfp_mask) +{ + struct mthca_icm *icm; + struct mthca_icm_chunk *chunk = NULL; + int cur_order; + + icm = kmalloc(sizeof *icm, gfp_mask & ~(__GFP_HIGHMEM | __GFP_NOWARN)); + if (!icm) + return icm; + + icm->refcount = 0; + INIT_LIST_HEAD(&icm->chunk_list); + + cur_order = get_order(MTHCA_ICM_ALLOC_SIZE); + + while (npages > 0) { + /* allocate a new chunk */ + if (!chunk) { + chunk = kmalloc(sizeof *chunk, + gfp_mask & ~(__GFP_HIGHMEM | __GFP_NOWARN)); + if (!chunk) + goto fail; + + RtlZeroMemory( chunk, sizeof *chunk ); + list_add_tail(&chunk->list, &icm->chunk_list); + } + + /* fill chunk with allocated consistent areas of integer pages each */ + while (1 << cur_order > npages) + /* try to take a max (required) number of pages */ + --cur_order; + + /* try to allocate a contiguous PHYSICAL buffer */ + alloc_dma_zmem( dev, PAGE_SIZE << cur_order, + &chunk->mem[chunk->npages] ); + + /* if succeded - proceed handling */ + if (chunk->mem[chunk->npages].page) { + + /* check, whether a chunk is full */ + if (++chunk->npages == MTHCA_ICM_CHUNK_LEN) { + /* it's full --> map physical addresses to bus ones */ + chunk->nsg = pci_map_sg(dev, chunk->mem, + chunk->npages, PCI_DMA_BIDIRECTIONAL ); + + if (chunk->nsg <= 0) + goto fail; + + chunk = NULL; + } + + /* calculate the remaining memory to be allocated */ + npages -= 1 << cur_order; + } + /* failed to allocate - lets decrement buffer size and try once more */ + else { + --cur_order; + if (cur_order < 0) + goto fail; + } + } + + /* last, not full chunk: map physical addresses to bus ones */ + if (chunk) { + chunk->nsg = pci_map_sg(dev, chunk->mem, + chunk->npages, + PCI_DMA_BIDIRECTIONAL); + + if (chunk->nsg <= 0) + goto fail; + } + + return icm; + +fail: + mthca_free_icm(dev, icm); + return NULL; +} + +int mthca_table_get(struct mthca_dev *dev, struct mthca_icm_table *table, int obj) +{ + int i = (obj & (table->num_obj - 1)) * table->obj_size / MTHCA_TABLE_CHUNK_SIZE; + int ret = 0; + u8 status; + + down(&table->mutex); + + if (table->icm[i]) { + ++table->icm[i]->refcount; + goto out; + } + + table->icm[i] = mthca_alloc_icm(dev, MTHCA_TABLE_CHUNK_SIZE >> PAGE_SHIFT, + (table->lowmem ? GFP_KERNEL : GFP_HIGHUSER) | + __GFP_NOWARN); + if (!table->icm[i]) { + ret = -ENOMEM; + goto out; + } + + if (mthca_MAP_ICM(dev, table->icm[i], table->virt + i * MTHCA_TABLE_CHUNK_SIZE, + &status) || status) { + mthca_free_icm(dev, table->icm[i]); + table->icm[i] = NULL; + ret = -ENOMEM; + goto out; + } + + ++table->icm[i]->refcount; + +out: + up(&table->mutex); + return ret; +} + +void mthca_table_put(struct mthca_dev *dev, struct mthca_icm_table *table, int obj) +{ + int i; + u8 status; + + if (!mthca_is_memfree(dev)) + return; + + i = (obj & (table->num_obj - 1)) * table->obj_size / MTHCA_TABLE_CHUNK_SIZE; + + down(&table->mutex); + + if (--table->icm[i]->refcount == 0) { + mthca_UNMAP_ICM(dev, table->virt + i * MTHCA_TABLE_CHUNK_SIZE, + MTHCA_TABLE_CHUNK_SIZE >> 12, &status); + mthca_free_icm(dev, table->icm[i]); + table->icm[i] = NULL; + } + + up(&table->mutex); +} + +void *mthca_table_find(struct mthca_icm_table *table, int obj) +{ + int idx, offset, i; + struct mthca_icm_chunk *chunk; + struct mthca_icm *icm; + struct page *page = NULL; + + if (!table->lowmem) + return NULL; + + down(&table->mutex); + + idx = (obj & (table->num_obj - 1)) * table->obj_size; + icm = table->icm[idx / MTHCA_TABLE_CHUNK_SIZE]; + offset = idx % MTHCA_TABLE_CHUNK_SIZE; + + if (!icm) + goto out; + + list_for_each_entry(chunk, &icm->chunk_list, list,struct mthca_icm_chunk) { + for (i = 0; i < chunk->npages; ++i) { + if ((int)chunk->mem[i].length > offset) { + page = chunk->mem[i].page; + goto out; + } + offset -= chunk->mem[i].length; + } + } + +out: + up(&table->mutex); + return page ? (char*)page + offset : NULL; +} + +int mthca_table_get_range(struct mthca_dev *dev, struct mthca_icm_table *table, + int start, int end) +{ + int inc = MTHCA_TABLE_CHUNK_SIZE / table->obj_size; + int i, err; + + for (i = start; i <= end; i += inc) { + err = mthca_table_get(dev, table, i); + if (err) + goto fail; + } + + return 0; + +fail: + while (i > start) { + i -= inc; + mthca_table_put(dev, table, i); + } + + return err; +} + +void mthca_table_put_range(struct mthca_dev *dev, struct mthca_icm_table *table, + int start, int end) +{ + int i; + + if (!mthca_is_memfree(dev)) + return; + + for (i = start; i <= end; i += MTHCA_TABLE_CHUNK_SIZE / table->obj_size) + mthca_table_put(dev, table, i); +} + +struct mthca_icm_table *mthca_alloc_icm_table(struct mthca_dev *dev, + u64 virt, int obj_size, + int nobj, int reserved, + int use_lowmem) +{ + struct mthca_icm_table *table; + int num_icm; + unsigned chunk_size; + int i; + u8 status; + + num_icm = (obj_size * nobj + MTHCA_TABLE_CHUNK_SIZE -1) / MTHCA_TABLE_CHUNK_SIZE; + + table = kmalloc(sizeof *table + num_icm * sizeof *table->icm, GFP_KERNEL); + if (!table) + return NULL; + + table->virt = virt; + table->num_icm = num_icm; + table->num_obj = nobj; + table->obj_size = obj_size; + table->lowmem = use_lowmem; + KeInitializeMutex( &table->mutex, 0 ); + + for (i = 0; i < num_icm; ++i) + table->icm[i] = NULL; + + for (i = 0; i * MTHCA_TABLE_CHUNK_SIZE < reserved * obj_size; ++i) { + chunk_size = MTHCA_TABLE_CHUNK_SIZE; + if ((i + 1) * MTHCA_TABLE_CHUNK_SIZE > nobj * obj_size) + chunk_size = nobj * obj_size - i * MTHCA_TABLE_CHUNK_SIZE; + + table->icm[i] = mthca_alloc_icm(dev, chunk_size >> PAGE_SHIFT, + (use_lowmem ? GFP_KERNEL : GFP_HIGHUSER) | + __GFP_NOWARN); + if (!table->icm[i]) + goto err; + if (mthca_MAP_ICM(dev, table->icm[i], virt + i * MTHCA_TABLE_CHUNK_SIZE, + &status) || status) { + mthca_free_icm(dev, table->icm[i]); + table->icm[i] = NULL; + goto err; + } + + /* + * Add a reference to this ICM chunk so that it never + * gets freed (since it contains reserved firmware objects). + */ + ++table->icm[i]->refcount; + } + + HCA_PRINT(TRACE_LEVEL_VERBOSE,HCA_DBG_LOW, + ("Allocated/max chunks %d:%d, reserved/max objects %#x:%#x, one/total size %#x:%#x at %I64x \n", + i, num_icm, reserved, nobj, obj_size, nobj * obj_size, (u64) virt)); + + return table; + +err: + for (i = 0; i < num_icm; ++i) + if (table->icm[i]) { + mthca_UNMAP_ICM(dev, virt + i * MTHCA_TABLE_CHUNK_SIZE, + MTHCA_TABLE_CHUNK_SIZE >> 12, &status); + mthca_free_icm(dev, table->icm[i]); + } + + kfree(table); + + return NULL; +} + +void mthca_free_icm_table(struct mthca_dev *dev, struct mthca_icm_table *table) +{ + int i; + u8 status; + + for (i = 0; i < table->num_icm; ++i) + if (table->icm[i]) { + mthca_UNMAP_ICM(dev, table->virt + i * MTHCA_TABLE_CHUNK_SIZE, + MTHCA_TABLE_CHUNK_SIZE >> 12, &status); + mthca_free_icm(dev, table->icm[i]); + } + + HCA_PRINT(TRACE_LEVEL_VERBOSE,HCA_DBG_LOW, + ( "Released chunks %d, objects %#x, one/total size %#x:%#x at %I64x \n", + table->num_icm, table->num_obj, table->obj_size, + table->num_obj * table->obj_size, (u64) table->virt)); + kfree(table); +} + +static u64 mthca_uarc_virt(struct mthca_dev *dev, struct mthca_uar *uar, int page) +{ + return dev->uar_table.uarc_base + + uar->index * dev->uar_table.uarc_size + + page * 4096; +} + +int mthca_map_user_db(struct mthca_dev *dev, struct mthca_uar *uar, + struct mthca_user_db_table *db_tab, int index, u64 uaddr, void **kva) +{ + int ret = 0; + u8 status; + int i; + + if (!mthca_is_memfree(dev)) + return 0; + + if (index < 0 || index > dev->uar_table.uarc_size / 8) + return -EINVAL; + + down(&db_tab->mutex); + + i = index / MTHCA_DB_REC_PER_PAGE; + + if ((db_tab->page[i].refcount >= MTHCA_DB_REC_PER_PAGE) || + (db_tab->page[i].uvirt && db_tab->page[i].uvirt != uaddr) || + (uaddr & 4095)) { + ret = -EINVAL; + goto out; + } + + if (db_tab->page[i].refcount) { + ++db_tab->page[i].refcount; + goto done; + } + + ret = get_user_pages(dev, uaddr & PAGE_MASK, 1, 1, + &db_tab->page[i].mem); + if (ret < 0) + goto out; + + db_tab->page[i].mem.length = 4096; + db_tab->page[i].mem.offset = (unsigned)(uaddr & ~PAGE_MASK); + + ret = pci_map_sg(dev, &db_tab->page[i].mem, 1, PCI_DMA_TODEVICE); + if (ret <= 0) { + put_page(&db_tab->page[i].mem); + goto out; + } + + ret = mthca_MAP_ICM_page(dev, sg_dma_address(&db_tab->page[i].mem), + mthca_uarc_virt(dev, uar, i), &status); + if (!ret && status) + ret = -EINVAL; + if (ret) { + pci_unmap_sg(dev, &db_tab->page[i].mem, 1, PCI_DMA_TODEVICE); + put_page(&db_tab->page[i].mem); + goto out; + } + + db_tab->page[i].uvirt = uaddr; + db_tab->page[i].refcount = 1; + +done: + if (kva) + *kva = db_tab->page[i].mem.page; + +out: + up(&db_tab->mutex); + return ret; +} + +void mthca_unmap_user_db(struct mthca_dev *dev, struct mthca_uar *uar, + struct mthca_user_db_table *db_tab, int index) +{ + u8 status; + int ix = index / MTHCA_DB_REC_PER_PAGE; + UNREFERENCED_PARAMETER(uar); + + if (!mthca_is_memfree(dev)) + return; + + /* + * To make our bookkeeping simpler, we don't unmap DB + * pages until we clean up the whole db table. + */ + + down(&db_tab->mutex); + + if (!--db_tab->page[ix].refcount) { + mthca_UNMAP_ICM(dev, mthca_uarc_virt(dev, uar, ix), 1, &status); + pci_unmap_sg(dev, &db_tab->page[ix].mem, 1, PCI_DMA_TODEVICE); + put_page(&db_tab->page[ix].mem); + db_tab->page[ix].uvirt = 0; + } + + up(&db_tab->mutex); +} + +struct mthca_user_db_table *mthca_init_user_db_tab(struct mthca_dev *dev) +{ + struct mthca_user_db_table *db_tab; + int npages; + int i; + + if (!mthca_is_memfree(dev)) + return NULL; + + npages = dev->uar_table.uarc_size / 4096; + db_tab = kmalloc(sizeof *db_tab + npages * sizeof *db_tab->page, GFP_KERNEL); + if (!db_tab) + return ERR_PTR(-ENOMEM); + + KeInitializeMutex(&db_tab->mutex,0); + for (i = 0; i < npages; ++i) { + db_tab->page[i].refcount = 0; + db_tab->page[i].uvirt = 0; + } + + return db_tab; +} + +void mthca_cleanup_user_db_tab(struct mthca_dev *dev, struct mthca_uar *uar, + struct mthca_user_db_table *db_tab) +{ + int i; + u8 status; + + if (!mthca_is_memfree(dev)) + return; + + for (i = 0; i < dev->uar_table.uarc_size / 4096; ++i) { + if (db_tab->page[i].uvirt) { + mthca_UNMAP_ICM(dev, mthca_uarc_virt(dev, uar, i), 1, &status); + pci_unmap_sg(dev, &db_tab->page[i].mem, 1, PCI_DMA_TODEVICE); + put_page(&db_tab->page[i].mem); + } + } + + kfree(db_tab); +} + +int mthca_alloc_db(struct mthca_dev *dev, enum mthca_db_type type, u32 qn, __be32 **db) +{ + int group; + int start, end, dir; + int i, j; + struct mthca_db_page *page; + int ret = 0; + u8 status; + CPU_2_BE64_PREP; + + down(&dev->db_tab->mutex); + switch (type) { + case MTHCA_DB_TYPE_CQ_ARM: + case MTHCA_DB_TYPE_SQ: + group = 0; + start = 0; + end = dev->db_tab->max_group1; + dir = 1; + break; + + case MTHCA_DB_TYPE_CQ_SET_CI: + case MTHCA_DB_TYPE_RQ: + case MTHCA_DB_TYPE_SRQ: + group = 1; + start = dev->db_tab->npages - 1; + end = dev->db_tab->min_group2; + dir = -1; + break; + + default: + ret = -EINVAL; + goto out; + } + + /* try to find an unused index for a new page (in the bitmap) */ + for (i = start; i != end; i += dir) + if (dev->db_tab->page[i].db_rec && + !bitmap_full(dev->db_tab->page[i].used, + MTHCA_DB_REC_PER_PAGE)) { + page = dev->db_tab->page + i; + goto found; + } + + for (i = start; i != end; i += dir) { + if (!dev->db_tab->page[i].db_rec) { + page = dev->db_tab->page + i; + goto alloc; + } + } + + /* if there are no more place for DBs - get out */ + if (dev->db_tab->max_group1 >= dev->db_tab->min_group2 - 1) { + ret = -ENOMEM; + goto out; + } + + /* fix limits indeces */ + if (group == 0) + ++dev->db_tab->max_group1; + else + --dev->db_tab->min_group2; + + /* allocate page */ + page = dev->db_tab->page + end; + +alloc: + alloc_dma_zmem_map(dev, 4096, PCI_DMA_BIDIRECTIONAL, &page->sg); + if (!page->sg.page) { + ret = -ENOMEM; + goto out; + } + page->db_rec = (__be64*)page->sg.page; + + ret = mthca_MAP_ICM_page(dev, page->sg.dma_address, + mthca_uarc_virt(dev, &dev->driver_uar, i), &status); + if (!ret && status) + ret = -EINVAL; + if (ret) { + free_dma_mem_map(dev, &page->sg, PCI_DMA_BIDIRECTIONAL); + goto out; + } + + bitmap_zero(page->used, MTHCA_DB_REC_PER_PAGE); + +found: + j = find_first_zero_bit(page->used, MTHCA_DB_REC_PER_PAGE); + set_bit(j, (long*)page->used); + + if (group == 1) + j = MTHCA_DB_REC_PER_PAGE - 1 - j; + + ret = i * MTHCA_DB_REC_PER_PAGE + j; + + page->db_rec[j] = CPU_2_BE64((((ULONGLONG)qn << 8) | (type << 5))); + + *db = (__be32 *) &page->db_rec[j]; +out: + up(&dev->db_tab->mutex); + + return ret; +} + +void mthca_free_db(struct mthca_dev *dev, int type, int db_index) +{ + int i, j; + struct mthca_db_page *page; + u8 status; + + UNREFERENCED_PARAMETER(type); + + i = db_index / MTHCA_DB_REC_PER_PAGE; + j = db_index % MTHCA_DB_REC_PER_PAGE; + + page = dev->db_tab->page + i; + + down(&dev->db_tab->mutex); + + page->db_rec[j] = 0; + if (i >= dev->db_tab->min_group2) + j = MTHCA_DB_REC_PER_PAGE - 1 - j; + clear_bit(j, (long*)page->used); + + if (bitmap_empty(page->used, MTHCA_DB_REC_PER_PAGE) && + i >= dev->db_tab->max_group1 - 1) { + mthca_UNMAP_ICM(dev, mthca_uarc_virt(dev, &dev->driver_uar, i), 1, &status); + + free_dma_mem_map(dev, &page->sg, PCI_DMA_BIDIRECTIONAL); + page->db_rec = NULL; + + if (i == dev->db_tab->max_group1) { + --dev->db_tab->max_group1; + /* XXX may be able to unmap more pages now */ + } + if (i == dev->db_tab->min_group2) + ++dev->db_tab->min_group2; + } + + up(&dev->db_tab->mutex); +} + +int mthca_init_db_tab(struct mthca_dev *dev) +{ + int i; + + if (!mthca_is_memfree(dev)) + return 0; + + dev->db_tab = kmalloc(sizeof *dev->db_tab, GFP_KERNEL); + if (!dev->db_tab) + return -ENOMEM; + + KeInitializeMutex(&dev->db_tab->mutex, 0); + /* number of pages, needed for UAR context table */ + dev->db_tab->npages = dev->uar_table.uarc_size / 4096; + dev->db_tab->max_group1 = 0; + dev->db_tab->min_group2 = dev->db_tab->npages - 1; + /* allocate array of structures, containing descrpitors of UARC pages */ + dev->db_tab->page = kmalloc(dev->db_tab->npages * + sizeof *dev->db_tab->page, + GFP_KERNEL); + if (!dev->db_tab->page) { + kfree(dev->db_tab); + return -ENOMEM; + } + + for (i = 0; i < dev->db_tab->npages; ++i) + dev->db_tab->page[i].db_rec = NULL; + + return 0; +} + +void mthca_cleanup_db_tab(struct mthca_dev *dev) +{ + int i; + u8 status; + + if (!mthca_is_memfree(dev)) + return; + + /* + * Because we don't always free our UARC pages when they + * become empty to make mthca_free_db() simpler we need to + * make a sweep through the doorbell pages and free any + * leftover pages now. + */ + for (i = 0; i < dev->db_tab->npages; ++i) { + if (!dev->db_tab->page[i].db_rec) + continue; + + if (!bitmap_empty(dev->db_tab->page[i].used, MTHCA_DB_REC_PER_PAGE)) + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_LOW ,("Kernel UARC page %d not empty\n", i)); + + mthca_UNMAP_ICM(dev, mthca_uarc_virt(dev, &dev->driver_uar, i), 1, &status); + + free_dma_mem_map(dev, &dev->db_tab->page[i].sg, PCI_DMA_BIDIRECTIONAL); + } + + kfree(dev->db_tab->page); + kfree(dev->db_tab); +} diff --git a/branches/WOF2-3/hw/mthca/kernel/mthca_memfree.h b/branches/WOF2-3/hw/mthca/kernel/mthca_memfree.h new file mode 100644 index 00000000..97367ce7 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/mthca_memfree.h @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Cisco Systems. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#ifndef MTHCA_MEMFREE_H +#define MTHCA_MEMFREE_H + + +#define MTHCA_ICM_CHUNK_LEN \ + ((256 - sizeof (struct list_head) - 2 * sizeof (int)) / \ + (sizeof (struct scatterlist))) + +struct mthca_icm_chunk { + struct list_head list; + int npages; + int nsg; + struct scatterlist mem[MTHCA_ICM_CHUNK_LEN]; +}; + +struct mthca_icm { + struct list_head chunk_list; + int refcount; +}; + +#pragma warning( disable : 4200) +struct mthca_icm_table { + u64 virt; + int num_icm; + int num_obj; + int obj_size; + int lowmem; + KMUTEX mutex; + struct mthca_icm *icm[0]; +}; +#pragma warning( default : 4200) + +struct mthca_icm_iter { + struct mthca_icm *icm; + struct mthca_icm_chunk *chunk; + int page_idx; +}; + +struct mthca_dev; + +struct mthca_icm *mthca_alloc_icm(struct mthca_dev *dev, int npages, + unsigned int gfp_mask); +void mthca_free_icm(struct mthca_dev *dev, struct mthca_icm *icm); + +struct mthca_icm_table *mthca_alloc_icm_table(struct mthca_dev *dev, + u64 virt, int obj_size, + int nobj, int reserved, + int use_lowmem); +void mthca_free_icm_table(struct mthca_dev *dev, struct mthca_icm_table *table); +int mthca_table_get(struct mthca_dev *dev, struct mthca_icm_table *table, int obj); +void mthca_table_put(struct mthca_dev *dev, struct mthca_icm_table *table, int obj); +void *mthca_table_find(struct mthca_icm_table *table, int obj); +int mthca_table_get_range(struct mthca_dev *dev, struct mthca_icm_table *table, + int start, int end); +void mthca_table_put_range(struct mthca_dev *dev, struct mthca_icm_table *table, + int start, int end); + +static inline void mthca_icm_first(struct mthca_icm *icm, + struct mthca_icm_iter *iter) +{ + iter->icm = icm; + iter->chunk = list_empty(&icm->chunk_list) ? + NULL : list_entry(icm->chunk_list.Flink, + struct mthca_icm_chunk, list); + iter->page_idx = 0; +} + +static inline int mthca_icm_last(struct mthca_icm_iter *iter) +{ + return !iter->chunk; +} + +static inline void mthca_icm_next(struct mthca_icm_iter *iter) +{ + if (++iter->page_idx >= iter->chunk->nsg) { + if (iter->chunk->list.Flink == &iter->icm->chunk_list) { + iter->chunk = NULL; + return; + } + + iter->chunk = list_entry(iter->chunk->list.Flink, + struct mthca_icm_chunk, list); + iter->page_idx = 0; + } +} + +static inline dma_addr_t mthca_icm_addr(struct mthca_icm_iter *iter) +{ + return sg_dma_address(&iter->chunk->mem[iter->page_idx]); +} + +static inline unsigned long mthca_icm_size(struct mthca_icm_iter *iter) +{ + return sg_dma_len(&iter->chunk->mem[iter->page_idx]); +} + +enum { + MTHCA_DB_REC_PER_PAGE = 4096 / 8 +}; + +struct mthca_db_page { + DECLARE_BITMAP(used, MTHCA_DB_REC_PER_PAGE); + __be64 *db_rec; + struct scatterlist sg; +}; + +struct mthca_db_table { + int npages; + int max_group1; + int min_group2; + struct mthca_db_page *page; + KMUTEX mutex; +}; + +enum mthca_db_type { + MTHCA_DB_TYPE_INVALID = 0x0, + MTHCA_DB_TYPE_CQ_SET_CI = 0x1, + MTHCA_DB_TYPE_CQ_ARM = 0x2, + MTHCA_DB_TYPE_SQ = 0x3, + MTHCA_DB_TYPE_RQ = 0x4, + MTHCA_DB_TYPE_SRQ = 0x5, + MTHCA_DB_TYPE_GROUP_SEP = 0x7 +}; + +struct mthca_user_db_table; +struct mthca_uar; + +int mthca_map_user_db(struct mthca_dev *dev, struct mthca_uar *uar, + struct mthca_user_db_table *db_tab, int index, u64 uaddr, void **kva); +void mthca_unmap_user_db(struct mthca_dev *dev, struct mthca_uar *uar, + struct mthca_user_db_table *db_tab, int index); +struct mthca_user_db_table *mthca_init_user_db_tab(struct mthca_dev *dev); +void mthca_cleanup_user_db_tab(struct mthca_dev *dev, struct mthca_uar *uar, + struct mthca_user_db_table *db_tab); + +int mthca_init_db_tab(struct mthca_dev *dev); +void mthca_cleanup_db_tab(struct mthca_dev *dev); +int mthca_alloc_db(struct mthca_dev *dev, enum mthca_db_type type, u32 qn, __be32 **db); +void mthca_free_db(struct mthca_dev *dev, int type, int db_index); + +#endif /* MTHCA_MEMFREE_H */ diff --git a/branches/WOF2-3/hw/mthca/kernel/mthca_mr.c b/branches/WOF2-3/hw/mthca/kernel/mthca_mr.c new file mode 100644 index 00000000..57f6d08f --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/mthca_mr.c @@ -0,0 +1,976 @@ +/* + * Copyright (c) 2004 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include "mthca_dev.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "mthca_mr.tmh" +#endif +#include "mthca_cmd.h" +#include "mthca_memfree.h" + +static int mthca_buddy_init(struct mthca_buddy *buddy, int max_order); +static void mthca_buddy_cleanup(struct mthca_buddy *buddy); + +struct mthca_mtt { + struct mthca_buddy *buddy; + int order; + u32 first_seg; +}; + +/* + * Must be packed because mtt_seg is 64 bits but only aligned to 32 bits. + */ +#pragma pack(push,1) +struct mthca_mpt_entry { + __be32 flags; + __be32 page_size; + __be32 key; + __be32 pd; + __be64 start; + __be64 length; + __be32 lkey; + __be32 window_count; + __be32 window_count_limit; + __be64 mtt_seg; + __be32 mtt_sz; /* Arbel only */ + u32 reserved[2]; +} ; +#pragma pack(pop) + +#define MTHCA_MPT_FLAG_SW_OWNS (0xfUL << 28) +#define MTHCA_MPT_FLAG_MIO (1 << 17) +#define MTHCA_MPT_FLAG_BIND_ENABLE (1 << 15) +#define MTHCA_MPT_FLAG_PHYSICAL (1 << 9) +#define MTHCA_MPT_FLAG_REGION (1 << 8) + +#define MTHCA_MTT_FLAG_PRESENT 1 + +#define MTHCA_MPT_STATUS_SW 0xF0 +#define MTHCA_MPT_STATUS_HW 0x00 + +#define SINAI_FMR_KEY_INC 0x1000000 + +static void dump_mtt(u32 print_lvl, __be64 *mtt_entry ,int list_len) +{ + int i; + UNUSED_PARAM_WOWPP(mtt_entry); // for release version + UNUSED_PARAM_WOWPP(print_lvl); + HCA_PRINT(print_lvl ,HCA_DBG_MEMORY ,("Dumping MTT entry len %d :\n",list_len)); + for (i = 0; i < list_len && i < MTHCA_MAILBOX_SIZE / 8 - 2; i=i+4) { + HCA_PRINT(print_lvl ,HCA_DBG_MEMORY ,("[%02x] %016I64x %016I64x %016I64x %016I64x\n",i, + cl_ntoh64(mtt_entry[i]), + cl_ntoh64(mtt_entry[i+1]), + cl_ntoh64(mtt_entry[i+2]), + cl_ntoh64(mtt_entry[i+3]))); + } +} + + +static void dump_mpt(u32 print_lvl, struct mthca_mpt_entry *mpt_entry ) +{ + int i; + UNUSED_PARAM_WOWPP(mpt_entry); // for release version + UNUSED_PARAM_WOWPP(print_lvl); + HCA_PRINT(print_lvl ,HCA_DBG_MEMORY ,("Dumping MPT entry %08x :\n", mpt_entry->key)); + for (i = 0; i < sizeof (struct mthca_mpt_entry) / 4; i=i+4) { + HCA_PRINT(print_lvl ,HCA_DBG_MEMORY ,("[%02x] %08x %08x %08x %08x \n",i, + cl_ntoh32(((__be32 *) mpt_entry)[i]), + cl_ntoh32(((__be32 *) mpt_entry)[i+1]), + cl_ntoh32(((__be32 *) mpt_entry)[i+2]), + cl_ntoh32(((__be32 *) mpt_entry)[i+3]))); + } +} + + + + + + + + +/* + * Buddy allocator for MTT segments (currently not very efficient + * since it doesn't keep a free list and just searches linearly + * through the bitmaps) + */ + +static u32 mthca_buddy_alloc(struct mthca_buddy *buddy, int order) +{ + int o; + u32 m; + u32 seg; + SPIN_LOCK_PREP(lh); + + spin_lock(&buddy->lock, &lh); + + for (o = order; o <= buddy->max_order; ++o) { + m = 1 << (buddy->max_order - o); + seg = find_first_bit(buddy->bits[o], m); + if (seg < m) + goto found; + } + + spin_unlock(&lh); + return (u32)-1; + + found: + clear_bit(seg, (long*)buddy->bits[o]); + + while (o > order) { + --o; + seg <<= 1; + set_bit(seg ^ 1, (long*)buddy->bits[o]); + } + + spin_unlock(&lh); + + seg <<= order; + + return seg; +} + +static void mthca_buddy_free(struct mthca_buddy *buddy, u32 seg, int order) +{ + SPIN_LOCK_PREP(lh); + + seg >>= order; + + spin_lock(&buddy->lock, &lh); + + while (test_bit(seg ^ 1, buddy->bits[order])) { + clear_bit(seg ^ 1, (long*)buddy->bits[order]); + seg >>= 1; + ++order; + } + + set_bit(seg, (long*)buddy->bits[order]); + + spin_unlock(&lh); +} + +static int mthca_buddy_init(struct mthca_buddy *buddy, int max_order) +{ + int i, s; + + buddy->max_order = max_order; + spin_lock_init(&buddy->lock); + + buddy->bits = kmalloc((buddy->max_order + 1) * sizeof (long *), + GFP_KERNEL); + if (!buddy->bits) + goto err_out; + + RtlZeroMemory(buddy->bits, (buddy->max_order + 1) * sizeof (long *)); + + for (i = 0; i <= buddy->max_order; ++i) { + s = BITS_TO_LONGS(1 << (buddy->max_order - i)); + buddy->bits[i] = kmalloc(s * sizeof (long), GFP_KERNEL); + if (!buddy->bits[i]) + goto err_out_free; + bitmap_zero(buddy->bits[i], + 1 << (buddy->max_order - i)); + } + + set_bit(0, (long*)buddy->bits[buddy->max_order]); + + return 0; + +err_out_free: + for (i = 0; i <= buddy->max_order; ++i) + kfree(buddy->bits[i]); + + kfree(buddy->bits); + +err_out: + return -ENOMEM; +} + +static void mthca_buddy_cleanup(struct mthca_buddy *buddy) +{ + int i; + + for (i = 0; i <= buddy->max_order; ++i) + kfree(buddy->bits[i]); + + kfree(buddy->bits); +} + +static u32 mthca_alloc_mtt_range(struct mthca_dev *dev, int order, + struct mthca_buddy *buddy) +{ + u32 seg = mthca_buddy_alloc(buddy, order); + + if (seg == -1) + return (u32)-1; + + if (mthca_is_memfree(dev)) + if (mthca_table_get_range(dev, dev->mr_table.mtt_table, seg, + seg + (1 << order) - 1)) { + mthca_buddy_free(buddy, seg, order); + seg = (u32)-1; + } + + return seg; +} + +static struct mthca_mtt *__mthca_alloc_mtt(struct mthca_dev *dev, int size, + struct mthca_buddy *buddy) +{ + struct mthca_mtt *mtt; + int i; + HCA_ENTER(HCA_DBG_MEMORY); + if (size <= 0) + return ERR_PTR(-EINVAL); + + mtt = kmalloc(sizeof *mtt, GFP_KERNEL); + if (!mtt) + return ERR_PTR(-ENOMEM); + + mtt->buddy = buddy; + mtt->order = 0; + for (i = MTHCA_MTT_SEG_SIZE / 8; i < size; i <<= 1) + ++mtt->order; + + mtt->first_seg = mthca_alloc_mtt_range(dev, mtt->order, buddy); + if (mtt->first_seg == -1) { + kfree(mtt); + return ERR_PTR(-ENOMEM); + } + HCA_EXIT(HCA_DBG_MEMORY); + return mtt; +} + +struct mthca_mtt *mthca_alloc_mtt(struct mthca_dev *dev, int size) +{ + return __mthca_alloc_mtt(dev, size, &dev->mr_table.mtt_buddy); +} + +void mthca_free_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt) +{ + if (!mtt) + return; + + mthca_buddy_free(mtt->buddy, mtt->first_seg, mtt->order); + + mthca_table_put_range(dev, dev->mr_table.mtt_table, + mtt->first_seg, + mtt->first_seg + (1 << mtt->order) - 1); + + kfree(mtt); +} + +int mthca_write_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt, + int start_index, u64 *buffer_list, int list_len) +{ + struct mthca_mailbox *mailbox; + __be64 *mtt_entry; + int err = 0; + u8 status; + int i; + u64 val = 1; + + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + mtt_entry = mailbox->buf; + + while (list_len > 0) { + val = dev->mr_table.mtt_base + + mtt->first_seg * MTHCA_MTT_SEG_SIZE + start_index * 8; + //TODO: a workaround of bug in _byteswap_uint64 + // in release version optimizer puts the above expression into the function call and generates incorrect code + // so we call the macro to work around that + mtt_entry[0] = CL_HTON64(val); + mtt_entry[1] = 0; + for (i = 0; i < list_len && i < MTHCA_MAILBOX_SIZE / 8 - 2; ++i) { + val = buffer_list[i]; + // BUG in compiler: it can't perform OR on u64 !!! We perform OR on the low dword + *(PULONG)&val |= MTHCA_MTT_FLAG_PRESENT; + mtt_entry[i + 2] = cl_hton64(val); + } + + /* + * If we have an odd number of entries to write, add + * one more dummy entry for firmware efficiency. + */ + if (i & 1) + mtt_entry[i + 2] = 0; + + dump_mtt(TRACE_LEVEL_VERBOSE, mtt_entry ,i); + + err = mthca_WRITE_MTT(dev, mailbox, (i + 1) & ~1, &status); + if (err) { + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_MEMORY ,("WRITE_MTT failed (%d)\n", err)); + goto out; + } + if (status) { + HCA_PRINT(TRACE_LEVEL_WARNING,HCA_DBG_MEMORY,("WRITE_MTT returned status 0x%02x\n", + status)); + err = -EINVAL; + goto out; + } + + list_len -= i; + start_index += i; + buffer_list += i; + } + +out: + mthca_free_mailbox(dev, mailbox); + return err; +} + +static inline u32 tavor_hw_index_to_key(u32 ind) +{ + return ind; +} + +static inline u32 tavor_key_to_hw_index(u32 key) +{ + return key; +} + +static inline u32 arbel_hw_index_to_key(u32 ind) +{ + return (ind >> 24) | (ind << 8); +} + +static inline u32 arbel_key_to_hw_index(u32 key) +{ + return (key << 24) | (key >> 8); +} + +static inline u32 hw_index_to_key(struct mthca_dev *dev, u32 ind) +{ + if (mthca_is_memfree(dev)) + return arbel_hw_index_to_key(ind); + else + return tavor_hw_index_to_key(ind); +} + +static inline u32 key_to_hw_index(struct mthca_dev *dev, u32 key) +{ + if (mthca_is_memfree(dev)) + return arbel_key_to_hw_index(key); + else + return tavor_key_to_hw_index(key); +} + + +static inline u32 adjust_key(struct mthca_dev *dev, u32 key) +{ + if (dev->mthca_flags & MTHCA_FLAG_SINAI_OPT) + return ((key << 20) & 0x800000) | (key & 0x7fffff); + else + return key; +} + +int mthca_mr_alloc(struct mthca_dev *dev, u32 pd, int buffer_size_shift, + u64 iova, u64 total_size, mthca_mpt_access_t access, struct mthca_mr *mr) +{ + struct mthca_mailbox *mailbox; + struct mthca_mpt_entry *mpt_entry; + u32 key; + int err; + u8 status; + CPU_2_BE64_PREP; + + WARN_ON(buffer_size_shift >= 32); + + key = mthca_alloc(&dev->mr_table.mpt_alloc); + if (key == -1) + return -ENOMEM; + mr->ibmr.rkey = mr->ibmr.lkey = hw_index_to_key(dev, key); + + if (mthca_is_memfree(dev)) { + err = mthca_table_get(dev, dev->mr_table.mpt_table, key); + if (err) + goto err_out_mpt_free; + } + + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (IS_ERR(mailbox)) { + err = PTR_ERR(mailbox); + goto err_out_table; + } + mpt_entry = mailbox->buf; + + mpt_entry->flags = cl_hton32(MTHCA_MPT_FLAG_SW_OWNS | + MTHCA_MPT_FLAG_MIO | + MTHCA_MPT_FLAG_REGION | + access); + if (!mr->mtt) + mpt_entry->flags |= cl_hton32(MTHCA_MPT_FLAG_PHYSICAL); + + mpt_entry->page_size = cl_hton32(buffer_size_shift - 12); + mpt_entry->key = cl_hton32(key); + mpt_entry->pd = cl_hton32(pd); + mpt_entry->start = cl_hton64(iova); + mpt_entry->length = cl_hton64(total_size); + + RtlZeroMemory(&mpt_entry->lkey, + sizeof *mpt_entry - offsetof(struct mthca_mpt_entry, lkey)); + + if (mr->mtt) + mpt_entry->mtt_seg = + CPU_2_BE64(dev->mr_table.mtt_base + + mr->mtt->first_seg * MTHCA_MTT_SEG_SIZE); + + { + dump_mpt(TRACE_LEVEL_VERBOSE, mpt_entry); + } + + err = mthca_SW2HW_MPT(dev, mailbox, + key & (dev->limits.num_mpts - 1), + &status); + if (err) { + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_MEMORY ,("SW2HW_MPT failed (%d)\n", err)); + goto err_out_mailbox; + } else if (status) { + HCA_PRINT(TRACE_LEVEL_WARNING,HCA_DBG_MEMORY,("SW2HW_MPT returned status 0x%02x\n", + status)); + err = -EINVAL; + goto err_out_mailbox; + } + + mthca_free_mailbox(dev, mailbox); + return err; + +err_out_mailbox: + mthca_free_mailbox(dev, mailbox); + +err_out_table: + mthca_table_put(dev, dev->mr_table.mpt_table, key); + +err_out_mpt_free: + mthca_free(&dev->mr_table.mpt_alloc, key); + return err; +} + +int mthca_mr_alloc_notrans(struct mthca_dev *dev, u32 pd, + mthca_mpt_access_t access, struct mthca_mr *mr) +{ + mr->mtt = NULL; + return mthca_mr_alloc(dev, pd, 12, 0, ~0Ui64, access, mr); +} + +int mthca_mr_alloc_phys(struct mthca_dev *dev, u32 pd, + u64 *buffer_list, int buffer_size_shift, + int list_len, u64 iova, u64 total_size, + mthca_mpt_access_t access, struct mthca_mr *mr) +{ + int err; + HCA_ENTER(HCA_DBG_MEMORY); + mr->mtt = mthca_alloc_mtt(dev, list_len); + if (IS_ERR(mr->mtt)){ + err= PTR_ERR(mr->mtt); + goto out; + } + + err = mthca_write_mtt(dev, mr->mtt, 0, buffer_list, list_len); + if (err) { + mthca_free_mtt(dev, mr->mtt); + goto out; + } + + err = mthca_mr_alloc(dev, pd, buffer_size_shift, iova, + total_size, access, mr); + if (err) + mthca_free_mtt(dev, mr->mtt); + +out: + HCA_EXIT(HCA_DBG_MEMORY); + return err; +} + +/* Free mr or fmr */ +static void mthca_free_region(struct mthca_dev *dev, u32 lkey) +{ + mthca_table_put(dev, dev->mr_table.mpt_table, key_to_hw_index(dev, lkey)); + mthca_free(&dev->mr_table.mpt_alloc, key_to_hw_index(dev, lkey)); +} + +void mthca_free_mr(struct mthca_dev *dev, struct mthca_mr *mr) +{ + int err; + u8 status; + + err = mthca_HW2SW_MPT(dev, NULL, + key_to_hw_index(dev, mr->ibmr.lkey) & + (dev->limits.num_mpts - 1), + &status); + if (err){ + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_MEMORY ,("HW2SW_MPT failed (%d)\n", err)); + }else if (status){ + HCA_PRINT(TRACE_LEVEL_WARNING,HCA_DBG_MEMORY,("HW2SW_MPT returned status 0x%02x\n", + status)); + } + + mthca_free_region(dev, mr->ibmr.lkey); + mthca_free_mtt(dev, mr->mtt); +} + +int mthca_fmr_alloc(struct mthca_dev *dev, u32 pd, + mthca_mpt_access_t access, struct mthca_fmr *fmr) +{ + struct mthca_mpt_entry *mpt_entry; + struct mthca_mailbox *mailbox; + u64 mtt_seg; + u32 key, idx; + u8 status; + int list_len = fmr->attr.max_pages; + int err = -ENOMEM; + int i; + CPU_2_BE64_PREP; + + if (fmr->attr.page_shift < 12 || fmr->attr.page_shift >= 32) + return -EINVAL; + + /* For Arbel, all MTTs must fit in the same page. */ + if (mthca_is_memfree(dev) && + fmr->attr.max_pages * sizeof *fmr->mem.arbel.mtts > PAGE_SIZE) + return -EINVAL; + + fmr->maps = 0; + + key = mthca_alloc(&dev->mr_table.mpt_alloc); + if (key == -1) + return -ENOMEM; + key = adjust_key(dev, key); + + idx = key & (dev->limits.num_mpts - 1); + fmr->ibfmr.rkey = fmr->ibfmr.lkey = hw_index_to_key(dev, key); + + if (mthca_is_memfree(dev)) { + err = mthca_table_get(dev, dev->mr_table.mpt_table, key); + if (err) + goto err_out_mpt_free; + + fmr->mem.arbel.mpt = mthca_table_find(dev->mr_table.mpt_table, key); + BUG_ON(!fmr->mem.arbel.mpt); + } else + fmr->mem.tavor.mpt = (struct mthca_mpt_entry*)((u8*)dev->mr_table.tavor_fmr.mpt_base + + sizeof *(fmr->mem.tavor.mpt) * idx); + + fmr->mtt = __mthca_alloc_mtt(dev, list_len, dev->mr_table.fmr_mtt_buddy); + if (IS_ERR(fmr->mtt)) + goto err_out_table; + + mtt_seg =fmr->mtt->first_seg * MTHCA_MTT_SEG_SIZE; + + if (mthca_is_memfree(dev)) { + fmr->mem.arbel.mtts = mthca_table_find(dev->mr_table.mtt_table, + fmr->mtt->first_seg); + BUG_ON(!fmr->mem.arbel.mtts); + } else + fmr->mem.tavor.mtts = (u64*)((u8*)dev->mr_table.tavor_fmr.mtt_base + mtt_seg); + + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (IS_ERR(mailbox)) + goto err_out_free_mtt; + + mpt_entry = mailbox->buf; + + mpt_entry->flags = cl_hton32(MTHCA_MPT_FLAG_SW_OWNS | + MTHCA_MPT_FLAG_MIO | + MTHCA_MPT_FLAG_REGION | + access); + + mpt_entry->page_size = cl_hton32(fmr->attr.page_shift - 12); + mpt_entry->key = cl_hton32(key); + mpt_entry->pd = cl_hton32(pd); + RtlZeroMemory(&mpt_entry->start, + sizeof *mpt_entry - offsetof(struct mthca_mpt_entry, start)); + mpt_entry->mtt_seg = CPU_2_BE64(dev->mr_table.mtt_base + mtt_seg); + + { + HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_MEMORY ,("Dumping MPT entry %08x:\n", fmr->ibfmr.lkey)); + for (i = 0; i < sizeof (struct mthca_mpt_entry) / 4; i=i+4) { + HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_MEMORY ,("[%02x] %08x %08x %08x %08x \n",i, + cl_ntoh32(((__be32 *) mpt_entry)[i]), + cl_ntoh32(((__be32 *) mpt_entry)[i+1]), + cl_ntoh32(((__be32 *) mpt_entry)[i+2]), + cl_ntoh32(((__be32 *) mpt_entry)[i+3]))); + } + } + + err = mthca_SW2HW_MPT(dev, mailbox, + key & (dev->limits.num_mpts - 1), + &status); + + if (err) { + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_MEMORY ,("SW2HW_MPT failed (%d)\n", err)); + goto err_out_mailbox_free; + } + if (status) { + HCA_PRINT(TRACE_LEVEL_WARNING,HCA_DBG_MEMORY,("SW2HW_MPT returned status 0x%02x\n", + status)); + err = -EINVAL; + goto err_out_mailbox_free; + } + + mthca_free_mailbox(dev, mailbox); + return 0; + +err_out_mailbox_free: + mthca_free_mailbox(dev, mailbox); + +err_out_free_mtt: + mthca_free_mtt(dev, fmr->mtt); + +err_out_table: + mthca_table_put(dev, dev->mr_table.mpt_table, key); + +err_out_mpt_free: + mthca_free(&dev->mr_table.mpt_alloc, fmr->ibfmr.lkey); + return err; +} + + +int mthca_free_fmr(struct mthca_dev *dev, struct mthca_fmr *fmr) +{ + if (fmr->maps) + return -EBUSY; + + mthca_free_region(dev, fmr->ibfmr.lkey); + mthca_free_mtt(dev, fmr->mtt); + + return 0; +} + + +static inline int mthca_check_fmr(struct mthca_fmr *fmr, u64 *page_list, + int list_len, u64 iova) +{ + int page_mask; + UNREFERENCED_PARAMETER(page_list); + + if (list_len > fmr->attr.max_pages) + return -EINVAL; + + page_mask = (1 << fmr->attr.page_shift) - 1; + + /* We are getting page lists, so va must be page aligned. */ + if (iova & page_mask) + return -EINVAL; + + /* Trust the user not to pass misaligned data in page_list */ + #if 0 + for (i = 0; i < list_len; ++i) { + if (page_list[i] & ~page_mask) + return -EINVAL; + } + #endif + + if (fmr->maps >= fmr->attr.max_maps) + return -EINVAL; + + return 0; +} + + +int mthca_tavor_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list, + int list_len, u64 iova) +{ + struct mthca_fmr *fmr = to_mfmr(ibfmr); + struct mthca_dev *dev = to_mdev(ibfmr->device); + struct mthca_mpt_entry mpt_entry; + u32 key; + int i, err; + CPU_2_BE64_PREP; + + err = mthca_check_fmr(fmr, page_list, list_len, iova); + if (err) + return err; + + ++fmr->maps; + + key = tavor_key_to_hw_index(fmr->ibfmr.lkey); + key += dev->limits.num_mpts; + fmr->ibfmr.lkey = fmr->ibfmr.rkey = tavor_hw_index_to_key(key); + + writeb(MTHCA_MPT_STATUS_SW, fmr->mem.tavor.mpt); + + for (i = 0; i < list_len; ++i) { + __be64 mtt_entry; + u64 val = page_list[i]; + // BUG in compiler: it can't perform OR on u64 !!! We perform OR on the low dword + *(PULONG)&val |= MTHCA_MTT_FLAG_PRESENT; + mtt_entry = cl_hton64(val); + mthca_write64_raw(mtt_entry, fmr->mem.tavor.mtts + i); + } + + mpt_entry.lkey = cl_hton32(key); + mpt_entry.length = CPU_2_BE64(list_len * (1Ui64 << fmr->attr.page_shift)); + mpt_entry.start = cl_hton64(iova); + + __raw_writel((u32) mpt_entry.lkey, &fmr->mem.tavor.mpt->key); + memcpy_toio(&fmr->mem.tavor.mpt->start, &mpt_entry.start, + offsetof(struct mthca_mpt_entry, window_count) - + offsetof(struct mthca_mpt_entry, start)); + + writeb(MTHCA_MPT_STATUS_HW, fmr->mem.tavor.mpt); + + return 0; +} + +int mthca_arbel_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list, + int list_len, u64 iova) +{ + struct mthca_fmr *fmr = to_mfmr(ibfmr); + struct mthca_dev *dev = to_mdev(ibfmr->device); + u32 key; + int i, err; + CPU_2_BE64_PREP; + + err = mthca_check_fmr(fmr, page_list, list_len, iova); + if (err) + return err; + + ++fmr->maps; + + key = arbel_key_to_hw_index(fmr->ibfmr.lkey); + if (dev->mthca_flags & MTHCA_FLAG_SINAI_OPT) + key += SINAI_FMR_KEY_INC; + else + key += dev->limits.num_mpts; + fmr->ibfmr.lkey = fmr->ibfmr.rkey = arbel_hw_index_to_key(key); + + *(u8 *) fmr->mem.arbel.mpt = MTHCA_MPT_STATUS_SW; + + wmb(); + + for (i = 0; i < list_len; ++i) { + // BUG in compiler: it can't perform OR on u64 !!! We perform OR on the low dword + u64 val = page_list[i]; + *(PULONG)&val |= MTHCA_MTT_FLAG_PRESENT; + fmr->mem.arbel.mtts[i] = cl_hton64(val); + } + + fmr->mem.arbel.mpt->key = cl_hton32(key); + fmr->mem.arbel.mpt->lkey = cl_hton32(key); + fmr->mem.arbel.mpt->length = CPU_2_BE64(list_len * (1Ui64 << fmr->attr.page_shift)); + fmr->mem.arbel.mpt->start = cl_hton64(iova); + + wmb(); + + *(u8 *) fmr->mem.arbel.mpt = MTHCA_MPT_STATUS_HW; + + wmb(); + + return 0; +} + + +void mthca_tavor_fmr_unmap(struct mthca_dev *dev, struct mthca_fmr *fmr) +{ + u32 key; + + if (!fmr->maps) + return; + + key = tavor_key_to_hw_index(fmr->ibfmr.lkey); + key &= dev->limits.num_mpts - 1; + fmr->ibfmr.lkey = fmr->ibfmr.rkey = tavor_hw_index_to_key(key); + + fmr->maps = 0; + + writeb(MTHCA_MPT_STATUS_SW, fmr->mem.tavor.mpt); +} + + +void mthca_arbel_fmr_unmap(struct mthca_dev *dev, struct mthca_fmr *fmr) +{ + u32 key; + + if (!fmr->maps) + return; + + key = arbel_key_to_hw_index(fmr->ibfmr.lkey); + key &= dev->limits.num_mpts - 1; + key = adjust_key(dev, key); + fmr->ibfmr.lkey = fmr->ibfmr.rkey = arbel_hw_index_to_key(key); + + fmr->maps = 0; + + *(u8 *) fmr->mem.arbel.mpt = MTHCA_MPT_STATUS_SW; +} + +int mthca_init_mr_table(struct mthca_dev *dev) +{ + int mpts, mtts, err, i; + + err = mthca_alloc_init(&dev->mr_table.mpt_alloc, + (u32)dev->limits.num_mpts, + (u32)~0, (u32)dev->limits.reserved_mrws); + if (err) + return err; + + if (!mthca_is_memfree(dev) && + (dev->mthca_flags & MTHCA_FLAG_DDR_HIDDEN)) + dev->limits.fmr_reserved_mtts = 0; + else + dev->mthca_flags |= MTHCA_FLAG_FMR; + + if (dev->mthca_flags & MTHCA_FLAG_SINAI_OPT) + HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_MEMORY ,("Memory key throughput optimization activated.\n")); + + err = mthca_buddy_init(&dev->mr_table.mtt_buddy, + fls(dev->limits.num_mtt_segs - 1)); + + if (err) + goto err_mtt_buddy; + + dev->mr_table.tavor_fmr.mpt_base = NULL; + dev->mr_table.tavor_fmr.mtt_base = NULL; + + if (dev->limits.fmr_reserved_mtts) { + i = fls(dev->limits.fmr_reserved_mtts - 1); + + if (i >= 31) { + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_MEMORY ,("Unable to reserve 2^31 FMR MTTs.\n")); + err = -EINVAL; + goto err_fmr_mpt; + } + + mpts = mtts = 1 << i; + + } else { + mpts = dev->limits.num_mtt_segs; + mtts = dev->limits.num_mpts; + } + + if (!mthca_is_memfree(dev) && + (dev->mthca_flags & MTHCA_FLAG_FMR)) { + + dev->mr_table.tavor_fmr.mpt_base = + ioremap(dev->mr_table.mpt_base, + mpts * sizeof (struct mthca_mpt_entry), + &dev->mr_table.tavor_fmr.mpt_base_size); + + if (!dev->mr_table.tavor_fmr.mpt_base) { + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_MEMORY ,("MPT ioremap for FMR failed.\n")); + err = -ENOMEM; + goto err_fmr_mpt; + } + + dev->mr_table.tavor_fmr.mtt_base = + ioremap(dev->mr_table.mtt_base, + mtts * MTHCA_MTT_SEG_SIZE, + &dev->mr_table.tavor_fmr.mtt_base_size ); + + if (!dev->mr_table.tavor_fmr.mtt_base) { + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_MEMORY ,("MTT ioremap for FMR failed.\n")); + err = -ENOMEM; + goto err_fmr_mtt; + } + } + + if (dev->limits.fmr_reserved_mtts) { + err = mthca_buddy_init(&dev->mr_table.tavor_fmr.mtt_buddy, fls(mtts - 1)); + if (err) + goto err_fmr_mtt_buddy; + + /* Prevent regular MRs from using FMR keys */ + err = mthca_buddy_alloc(&dev->mr_table.mtt_buddy, fls(mtts - 1)); + if (err) + goto err_reserve_fmr; + + dev->mr_table.fmr_mtt_buddy = + &dev->mr_table.tavor_fmr.mtt_buddy; + } else + dev->mr_table.fmr_mtt_buddy = &dev->mr_table.mtt_buddy; + + /* FMR table is always the first, take reserved MTTs out of there */ + if (dev->limits.reserved_mtts) { + i = fls(dev->limits.reserved_mtts - 1); + + if (mthca_alloc_mtt_range(dev, i, + dev->mr_table.fmr_mtt_buddy) == -1) { + HCA_PRINT(TRACE_LEVEL_WARNING,HCA_DBG_MEMORY,("MTT table of order %d is too small.\n", + dev->mr_table.fmr_mtt_buddy->max_order)); + err = -ENOMEM; + goto err_reserve_mtts; + } + } + + return 0; + +err_reserve_mtts: +err_reserve_fmr: + if (dev->limits.fmr_reserved_mtts) + mthca_buddy_cleanup(&dev->mr_table.tavor_fmr.mtt_buddy); + +err_fmr_mtt_buddy: + if (dev->mr_table.tavor_fmr.mtt_base) + iounmap(dev->mr_table.tavor_fmr.mtt_base, + dev->mr_table.tavor_fmr.mtt_base_size); + +err_fmr_mtt: + if (dev->mr_table.tavor_fmr.mpt_base) + iounmap(dev->mr_table.tavor_fmr.mpt_base, + dev->mr_table.tavor_fmr.mpt_base_size); + +err_fmr_mpt: + mthca_buddy_cleanup(&dev->mr_table.mtt_buddy); + +err_mtt_buddy: + mthca_alloc_cleanup(&dev->mr_table.mpt_alloc); + + return err; +} + +void mthca_cleanup_mr_table(struct mthca_dev *dev) +{ + /* XXX check if any MRs are still allocated? */ + if (dev->limits.fmr_reserved_mtts) + mthca_buddy_cleanup(&dev->mr_table.tavor_fmr.mtt_buddy); + + mthca_buddy_cleanup(&dev->mr_table.mtt_buddy); + + if (dev->mr_table.tavor_fmr.mtt_base) + iounmap(dev->mr_table.tavor_fmr.mtt_base, + dev->mr_table.tavor_fmr.mtt_base_size); + if (dev->mr_table.tavor_fmr.mpt_base) + iounmap(dev->mr_table.tavor_fmr.mpt_base, + dev->mr_table.tavor_fmr.mpt_base_size); + + mthca_alloc_cleanup(&dev->mr_table.mpt_alloc); +} + + diff --git a/branches/WOF2-3/hw/mthca/kernel/mthca_pd.c b/branches/WOF2-3/hw/mthca/kernel/mthca_pd.c new file mode 100644 index 00000000..c2afdd6e --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/mthca_pd.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2004 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Cisco Systems. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include "mthca_dev.h" + + +int mthca_pd_alloc(struct mthca_dev *dev, int privileged, struct mthca_pd *pd) +{ + int err = 0; + + pd->privileged = privileged; + + atomic_set(&pd->sqp_count, 0); + pd->pd_num = mthca_alloc(&dev->pd_table.alloc); + if (pd->pd_num == -1) + return -ENOMEM; + + if (privileged) { + err = mthca_mr_alloc_notrans(dev, pd->pd_num, + MTHCA_MPT_FLAG_LOCAL_READ | + MTHCA_MPT_FLAG_LOCAL_WRITE, + &pd->ntmr); + if (err) + mthca_free(&dev->pd_table.alloc, pd->pd_num); + } + + return err; +} + +void mthca_pd_free(struct mthca_dev *dev, struct mthca_pd *pd) +{ + if (pd->privileged) + mthca_free_mr(dev, &pd->ntmr); + mthca_free(&dev->pd_table.alloc, pd->pd_num); +} + +int mthca_init_pd_table(struct mthca_dev *dev) +{ + return mthca_alloc_init(&dev->pd_table.alloc, + dev->limits.num_pds, + (1 << 24) - 1, + dev->limits.reserved_pds); +} + +void mthca_cleanup_pd_table(struct mthca_dev *dev) +{ + /* XXX check if any PDs are still allocated? */ + mthca_alloc_cleanup(&dev->pd_table.alloc); +} + diff --git a/branches/WOF2-3/hw/mthca/kernel/mthca_profile.c b/branches/WOF2-3/hw/mthca/kernel/mthca_profile.c new file mode 100644 index 00000000..a2aaca20 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/mthca_profile.c @@ -0,0 +1,290 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include "mthca_profile.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "mthca_profile.tmh" +#endif + +enum { + MTHCA_RES_QP, + MTHCA_RES_EEC, + MTHCA_RES_SRQ, + MTHCA_RES_CQ, + MTHCA_RES_EQP, + MTHCA_RES_EEEC, + MTHCA_RES_EQ, + MTHCA_RES_RDB, + MTHCA_RES_MCG, + MTHCA_RES_MPT, + MTHCA_RES_MTT, + MTHCA_RES_UAR, + MTHCA_RES_UDAV, + MTHCA_RES_UARC, + MTHCA_RES_NUM +}; + +enum { + MTHCA_NUM_EQS = 32, + MTHCA_NUM_PDS = 1 << 15 +}; + +u64 mthca_make_profile(struct mthca_dev *dev, + struct mthca_profile *request, + struct mthca_dev_lim *dev_lim, + struct mthca_init_hca_param *init_hca) +{ + struct mthca_resource { + u64 size; + u64 start; + int type; + int num; + int log_num; + }; + + u64 mem_base, mem_avail; + u64 total_size = 0; + struct mthca_resource *profile; + struct mthca_resource tmp; + int i, j; + + profile = kmalloc(MTHCA_RES_NUM * sizeof *profile, GFP_KERNEL); + if (!profile) + return (u64)-ENOMEM; + + RtlZeroMemory(profile, MTHCA_RES_NUM * sizeof *profile); + + profile[MTHCA_RES_QP].size = dev_lim->qpc_entry_sz; + profile[MTHCA_RES_EEC].size = dev_lim->eec_entry_sz; + profile[MTHCA_RES_SRQ].size = dev_lim->srq_entry_sz; + profile[MTHCA_RES_CQ].size = dev_lim->cqc_entry_sz; + profile[MTHCA_RES_EQP].size = dev_lim->eqpc_entry_sz; + profile[MTHCA_RES_EEEC].size = dev_lim->eeec_entry_sz; + profile[MTHCA_RES_EQ].size = dev_lim->eqc_entry_sz; + profile[MTHCA_RES_RDB].size = MTHCA_RDB_ENTRY_SIZE; + profile[MTHCA_RES_MCG].size = MTHCA_MGM_ENTRY_SIZE; + profile[MTHCA_RES_MPT].size = dev_lim->mpt_entry_sz; + profile[MTHCA_RES_MTT].size = MTHCA_MTT_SEG_SIZE; + profile[MTHCA_RES_UAR].size = dev_lim->uar_scratch_entry_sz; + profile[MTHCA_RES_UDAV].size = MTHCA_AV_SIZE; + profile[MTHCA_RES_UARC].size = request->uarc_size; + + profile[MTHCA_RES_QP].num = request->num_qp; + profile[MTHCA_RES_SRQ].num = request->num_srq; + profile[MTHCA_RES_EQP].num = request->num_qp; + profile[MTHCA_RES_RDB].num = request->num_qp * request->rdb_per_qp; + profile[MTHCA_RES_CQ].num = request->num_cq; + profile[MTHCA_RES_EQ].num = MTHCA_NUM_EQS; + profile[MTHCA_RES_MCG].num = request->num_mcg; + profile[MTHCA_RES_MPT].num = request->num_mpt; + profile[MTHCA_RES_MTT].num = request->num_mtt; + profile[MTHCA_RES_UAR].num = request->num_uar; + profile[MTHCA_RES_UARC].num = request->num_uar; + profile[MTHCA_RES_UDAV].num = request->num_udav; + + for (i = 0; i < MTHCA_RES_NUM; ++i) { + profile[i].type = i; + profile[i].log_num = max(ffs(profile[i].num) - 1, 0); + profile[i].size *= profile[i].num; + if (mthca_is_memfree(dev)) + profile[i].size = max(profile[i].size, (u64) PAGE_SIZE); + } + + if (mthca_is_memfree(dev)) { + mem_base = 0; + mem_avail = dev_lim->hca.arbel.max_icm_sz; + } else { + mem_base = dev->ddr_start; + mem_avail = dev->fw.tavor.fw_start - dev->ddr_start; + } + + /* + * Sort the resources in decreasing order of size. Since they + * all have sizes that are powers of 2, we'll be able to keep + * resources aligned to their size and pack them without gaps + * using the sorted order. + */ + for (i = MTHCA_RES_NUM; i > 0; --i) + for (j = 1; j < i; ++j) { + if (profile[j].size > profile[j - 1].size) { + tmp = profile[j]; + profile[j] = profile[j - 1]; + profile[j - 1] = tmp; + } + } + + for (i = 0; i < MTHCA_RES_NUM; ++i) { + if (profile[i].size) { + profile[i].start = mem_base + total_size; + total_size += profile[i].size; + } + if (total_size > mem_avail) { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Profile requires 0x%I64x bytes; " + "won't in 0x%I64x bytes of context memory.\n", + (u64) total_size, + (u64) mem_avail)); + kfree(profile); + return (u64)-ENOMEM; + } + + if (profile[i].size) + HCA_PRINT(TRACE_LEVEL_VERBOSE,HCA_DBG_LOW,("profile[%2d]--%2d/%2d @ 0x%16I64x " + "(size 0x%8I64x)\n", + i, profile[i].type, profile[i].log_num, + (u64) profile[i].start, + (u64) profile[i].size)); + } + + if (mthca_is_memfree(dev)){ + HCA_PRINT(TRACE_LEVEL_VERBOSE,HCA_DBG_LOW,("HCA context memory: reserving %d KB\n", + (int) (total_size >> 10))); + }else{ + HCA_PRINT(TRACE_LEVEL_VERBOSE,HCA_DBG_LOW,("HCA memory: allocated %d KB/%d KB (%d KB free)\n", + (int) (total_size >> 10), (int) (mem_avail >> 10), + (int) ((mem_avail - total_size) >> 10))); + } + for (i = 0; i < MTHCA_RES_NUM; ++i) { + int mc_entry_sz = MTHCA_MGM_ENTRY_SIZE; + int mtt_seg_sz = MTHCA_MTT_SEG_SIZE; + + switch (profile[i].type) { + case MTHCA_RES_QP: + dev->limits.num_qps = profile[i].num; + init_hca->qpc_base = profile[i].start; + init_hca->log_num_qps = (u8)profile[i].log_num; + break; + case MTHCA_RES_EEC: + dev->limits.num_eecs = profile[i].num; + init_hca->eec_base = profile[i].start; + init_hca->log_num_eecs = (u8)profile[i].log_num; + break; + case MTHCA_RES_SRQ: + dev->limits.num_srqs = profile[i].num; + init_hca->srqc_base = profile[i].start; + init_hca->log_num_srqs = (u8)profile[i].log_num; + break; + case MTHCA_RES_CQ: + dev->limits.num_cqs = profile[i].num; + init_hca->cqc_base = profile[i].start; + init_hca->log_num_cqs = (u8)profile[i].log_num; + break; + case MTHCA_RES_EQP: + init_hca->eqpc_base = profile[i].start; + break; + case MTHCA_RES_EEEC: + init_hca->eeec_base = profile[i].start; + break; + case MTHCA_RES_EQ: + dev->limits.num_eqs = profile[i].num; + init_hca->eqc_base = profile[i].start; + init_hca->log_num_eqs = (u8)profile[i].log_num; + break; + case MTHCA_RES_RDB: + for (dev->qp_table.rdb_shift = 0; + request->num_qp << dev->qp_table.rdb_shift < profile[i].num; + ++dev->qp_table.rdb_shift) + ; /* nothing */ + dev->qp_table.rdb_base = (u32) profile[i].start; + init_hca->rdb_base = profile[i].start; + break; + case MTHCA_RES_MCG: + dev->limits.num_mgms = profile[i].num >> 1; + dev->limits.num_amgms = profile[i].num >> 1; + init_hca->mc_base = profile[i].start; + init_hca->log_mc_entry_sz = (u16)(ffs(mc_entry_sz) - 1); + init_hca->log_mc_table_sz = (u8)profile[i].log_num; + init_hca->mc_hash_sz = (u16)(1 << (profile[i].log_num - 1)); + break; + case MTHCA_RES_MPT: + dev->limits.num_mpts = profile[i].num; + dev->mr_table.mpt_base = profile[i].start; + init_hca->mpt_base = profile[i].start; + init_hca->log_mpt_sz = (u8)profile[i].log_num; + break; + case MTHCA_RES_MTT: + dev->limits.num_mtt_segs = profile[i].num; + dev->mr_table.mtt_base = profile[i].start; + init_hca->mtt_base = profile[i].start; + init_hca->mtt_seg_sz = (u8)(ffs(mtt_seg_sz) - 7); + break; + case MTHCA_RES_UAR: + dev->limits.num_uars = profile[i].num; + init_hca->uar_scratch_base = profile[i].start; + break; + case MTHCA_RES_UDAV: + dev->av_table.ddr_av_base = profile[i].start; + dev->av_table.num_ddr_avs = profile[i].num; + break; + case MTHCA_RES_UARC: + dev->uar_table.uarc_size = request->uarc_size; + dev->uar_table.uarc_base = profile[i].start; + init_hca->uarc_base = profile[i].start; + init_hca->log_uarc_sz = (u8)(ffs(request->uarc_size) - 13); + init_hca->log_uar_sz = (u8)(ffs(request->num_uar) - 1); + break; + default: + break; + } + } + + /* + * PDs don't take any HCA memory, but we assign them as part + * of the HCA profile anyway. + */ + dev->limits.num_pds = MTHCA_NUM_PDS; + + /* + * For Tavor, FMRs use ioremapped PCI memory. For 32 bit + * systems it may use too much vmalloc space to map all MTT + * memory, so we reserve some MTTs for FMR access, taking them + * out of the MR pool. They don't use additional memory, but + * we assign them as part of the HCA profile anyway. + */ + if (mthca_is_memfree(dev)) + dev->limits.fmr_reserved_mtts = 0; + else + dev->limits.fmr_reserved_mtts = request->fmr_reserved_mtts; + +#ifdef _WIN64 + dev->limits.fmr_reserved_mtts = 0; +#endif + + kfree(profile); + return total_size; +} diff --git a/branches/WOF2-3/hw/mthca/kernel/mthca_profile.h b/branches/WOF2-3/hw/mthca/kernel/mthca_profile.h new file mode 100644 index 00000000..f1887c58 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/mthca_profile.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#ifndef MTHCA_PROFILE_H +#define MTHCA_PROFILE_H + +#include "mthca_dev.h" +#include "mthca_cmd.h" + +struct mthca_profile { + int num_qp; + int rdb_per_qp; + int num_srq; + int num_cq; + int num_mcg; + int num_mpt; + int num_mtt; + int num_udav; + int num_uar; + int uarc_size; + int fmr_reserved_mtts; +}; + +u64 mthca_make_profile(struct mthca_dev *mdev, + struct mthca_profile *request, + struct mthca_dev_lim *dev_lim, + struct mthca_init_hca_param *init_hca); + +#endif /* MTHCA_PROFILE_H */ diff --git a/branches/WOF2-3/hw/mthca/kernel/mthca_provider.c b/branches/WOF2-3/hw/mthca/kernel/mthca_provider.c new file mode 100644 index 00000000..cb0a01ae --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/mthca_provider.c @@ -0,0 +1,1315 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2005 Cisco Systems. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * Copyright (c) 2004 Voltaire, Inc. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include + +#include "mx_abi.h" +#include "mthca_dev.h" +#include "mt_pa_cash.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "mthca_provider.tmh" +#endif +#include "mthca_cmd.h" +#include "mthca_memfree.h" + +static void init_query_mad(struct ib_smp *mad) +{ + mad->base_version = 1; + mad->mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED; + mad->class_version = 1; + mad->method = IB_MGMT_METHOD_GET; +} + +int mthca_query_device(struct ib_device *ibdev, + struct ib_device_attr *props) +{ + struct ib_smp *in_mad = NULL; + struct ib_smp *out_mad = NULL; + int err = -ENOMEM; + struct mthca_dev* mdev = to_mdev(ibdev); + + u8 status; + + RtlZeroMemory(props, sizeof *props); + + in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL); + out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL); + if (!in_mad || !out_mad) + goto out; + + init_query_mad(in_mad); + in_mad->attr_id = IB_SMP_ATTR_NODE_INFO; + + err = mthca_MAD_IFC(mdev, 1, 1, + 1, NULL, NULL, in_mad, out_mad, &status); + if (err) + goto out; + if (status) { + err = -EINVAL; + goto out; + } + + props->fw_ver = mdev->fw_ver; + props->device_cap_flags = mdev->device_cap_flags; + props->vendor_id = cl_ntoh32(*(__be32 *) (out_mad->data + 36)) & + 0xffffff; + props->vendor_part_id = cl_ntoh16(*(__be16 *) (out_mad->data + 30)); + props->hw_ver = cl_ntoh32(*(__be32 *) (out_mad->data + 32)); + memcpy(&props->sys_image_guid, out_mad->data + 4, 8); + props->max_mr_size = ~0Ui64; + props->page_size_cap = mdev->limits.page_size_cap; + props->max_qp = mdev->limits.num_qps - mdev->limits.reserved_qps; + props->max_qp_wr = mdev->limits.max_wqes; + props->max_sge = mdev->limits.max_sg; + props->max_cq = mdev->limits.num_cqs - mdev->limits.reserved_cqs; + props->max_cqe = mdev->limits.max_cqes; + props->max_mr = mdev->limits.num_mpts - mdev->limits.reserved_mrws; + props->max_pd = mdev->limits.num_pds - mdev->limits.reserved_pds; + props->max_qp_rd_atom = 1 << mdev->qp_table.rdb_shift; + props->max_qp_init_rd_atom = mdev->limits.max_qp_init_rdma; + props->max_res_rd_atom = props->max_qp_rd_atom * props->max_qp; + props->max_srq = mdev->limits.num_srqs - mdev->limits.reserved_srqs; + props->max_srq_wr = mdev->limits.max_srq_wqes; + if (mthca_is_memfree(mdev)) + --props->max_srq_wr; + props->max_srq_sge = mdev->limits.max_srq_sge; + props->local_ca_ack_delay = (u8)mdev->limits.local_ca_ack_delay; + props->atomic_cap = mdev->limits.flags & DEV_LIM_FLAG_ATOMIC ? + IB_ATOMIC_LOCAL : IB_ATOMIC_NONE; + props->max_pkeys = (u16)mdev->limits.pkey_table_len; + props->max_mcast_grp = mdev->limits.num_mgms + mdev->limits.num_amgms; + props->max_mcast_qp_attach = MTHCA_QP_PER_MGM; + props->max_total_mcast_qp_attach = props->max_mcast_qp_attach * + props->max_mcast_grp; + props->max_ah = mdev->limits.num_avs; + + /* + * If Sinai memory key optimization is being used, then only + * the 8-bit key portion will change. For other HCAs, the + * unused index bits will also be used for FMR remapping. + */ + if (mdev->mthca_flags & MTHCA_FLAG_SINAI_OPT) + props->max_map_per_fmr = 255; + else + props->max_map_per_fmr = + (1 << (32 - long_log2(mdev->limits.num_mpts))) - 1; + + err = 0; + out: + kfree(in_mad); + kfree(out_mad); + return err; +} + +int mthca_query_port(struct ib_device *ibdev, + u8 port, struct ib_port_attr *props) +{ + struct ib_smp *in_mad = NULL; + struct ib_smp *out_mad = NULL; + int err = -ENOMEM; + u8 status; + + in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL); + out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL); + if (!in_mad || !out_mad) + goto out; + + init_query_mad(in_mad); + in_mad->attr_id = IB_SMP_ATTR_PORT_INFO; + in_mad->attr_mod = cl_hton32(port); + + err = mthca_MAD_IFC(to_mdev(ibdev), 1, 1, + port, NULL, NULL, in_mad, out_mad, + &status); + if (err) + goto out; + if (status) { + err = -EINVAL; + goto out; + } + + RtlZeroMemory(props, sizeof *props); + props->lid = cl_ntoh16(*(__be16 *) (out_mad->data + 16)); + props->lmc = out_mad->data[34] & 0x7; + props->sm_lid = cl_ntoh16(*(__be16 *) (out_mad->data + 18)); + props->sm_sl = out_mad->data[36] & 0xf; + props->state = out_mad->data[32] & 0xf; + props->phys_state = out_mad->data[33] >> 4; + props->port_cap_flags = cl_ntoh32(*(__be32 *) (out_mad->data + 20)); + props->gid_tbl_len = to_mdev(ibdev)->limits.gid_table_len; + props->max_msg_sz = 0x80000000; + props->pkey_tbl_len = (u16)to_mdev(ibdev)->limits.pkey_table_len; + props->bad_pkey_cntr = cl_ntoh16(*(__be16 *) (out_mad->data + 46)); + props->qkey_viol_cntr = cl_ntoh16(*(__be16 *) (out_mad->data + 48)); + props->active_width = out_mad->data[31] & 0xf; + props->active_speed = out_mad->data[35] >> 4; + props->max_mtu = out_mad->data[41] & 0xf; + props->active_mtu = out_mad->data[36] >> 4; + props->subnet_timeout = out_mad->data[51] & 0x1f; + + out: + kfree(in_mad); + kfree(out_mad); + return err; +} + +int mthca_modify_port(struct ib_device *ibdev, + u8 port, int port_modify_mask, + struct ib_port_modify *props) +{ + struct mthca_set_ib_param set_ib; + struct ib_port_attr attr; + int err; + u8 status; + + if (down_interruptible(&to_mdev(ibdev)->cap_mask_mutex)) + return -EFAULT; + + err = mthca_query_port(ibdev, port, &attr); + if (err) + goto out; + + set_ib.set_si_guid = 0; + set_ib.reset_qkey_viol = !!(port_modify_mask & IB_PORT_RESET_QKEY_CNTR); + + set_ib.cap_mask = (attr.port_cap_flags | props->set_port_cap_mask) & + ~props->clr_port_cap_mask; + + err = mthca_SET_IB(to_mdev(ibdev), &set_ib, port, &status); + if (err) + goto out; + if (status) { + err = -EINVAL; + goto out; + } + +out: + up(&to_mdev(ibdev)->cap_mask_mutex); + return err; +} + +static int mthca_query_pkey_chunk(struct ib_device *ibdev, + u8 port, u16 index, __be16 pkey[32]) +{ + struct ib_smp *in_mad = NULL; + struct ib_smp *out_mad = NULL; + int err = -ENOMEM; + u8 status; + + in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL); + out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL); + if (!in_mad || !out_mad) + goto out; + + init_query_mad(in_mad); + in_mad->attr_id = IB_SMP_ATTR_PKEY_TABLE; + in_mad->attr_mod = cl_hton32(index / 32); + + err = mthca_MAD_IFC(to_mdev(ibdev), 1, 1, + port, NULL, NULL, in_mad, out_mad, + &status); + if (err) + goto out; + if (status) { + err = -EINVAL; + goto out; + } + + { // copy the results + int i; + __be16 *pkey_chunk = (__be16 *)out_mad->data; + for (i=0; i<32; ++i) + pkey[i] = pkey_chunk[i]; + } + + out: + kfree(in_mad); + kfree(out_mad); + return err; +} + +static int mthca_query_gid_chunk(struct ib_device *ibdev, u8 port, + int index, union ib_gid gid[8]) +{ + struct ib_smp *in_mad = NULL; + struct ib_smp *out_mad = NULL; + int err = -ENOMEM; + u8 status; + __be64 subnet_prefix; + + in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL); + out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL); + if (!in_mad || !out_mad) + goto out; + + init_query_mad(in_mad); + in_mad->attr_id = IB_SMP_ATTR_PORT_INFO; + in_mad->attr_mod = cl_hton32(port); + + err = mthca_MAD_IFC(to_mdev(ibdev), 1, 1, + port, NULL, NULL, in_mad, out_mad, + &status); + if (err) + goto out; + if (status) { + err = -EINVAL; + goto out; + } + + memcpy(&subnet_prefix, out_mad->data + 8, 8); + + init_query_mad(in_mad); + in_mad->attr_id = IB_SMP_ATTR_GUID_INFO; + in_mad->attr_mod = cl_hton32(index / 8); + + err = mthca_MAD_IFC(to_mdev(ibdev), 1, 1, + port, NULL, NULL, in_mad, out_mad, + &status); + if (err) + goto out; + if (status) { + err = -EINVAL; + goto out; + } + + { // copy the results + int i; + __be64 *guid = (__be64 *)out_mad->data; + for (i=0; i<8; ++i) { + gid[i].global.subnet_prefix = subnet_prefix; + gid[i].global.interface_id = guid[i]; + } + } + + out: + kfree(in_mad); + kfree(out_mad); + return err; +} + +struct ib_ucontext *mthca_alloc_ucontext(struct ib_device *ibdev, + ci_umv_buf_t* const p_umv_buf) +{ + struct ibv_get_context_resp uresp; + struct mthca_ucontext *context; + int err; + + RtlZeroMemory(&uresp, sizeof uresp); + + uresp.qp_tab_size = to_mdev(ibdev)->limits.num_qps; + if (mthca_is_memfree(to_mdev(ibdev))) + uresp.uarc_size = to_mdev(ibdev)->uar_table.uarc_size; + else + uresp.uarc_size = 0; + + context = kzalloc(sizeof *context, GFP_KERNEL); + if (!context) { + err = -ENOMEM; + goto err_nomem; + } + + err = mthca_uar_alloc(to_mdev(ibdev), &context->uar); + if (err) + goto err_uar_alloc; + + /* + * map uar to user space + */ + + /* map UAR to kernel */ + context->kva = ioremap((io_addr_t)context->uar.pfn << PAGE_SHIFT, PAGE_SIZE,&context->uar_size); + if (!context->kva) { + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_LOW ,("Couldn't map kernel access region, aborting.\n") ); + err = -ENOMEM; + goto err_ioremap; + } + + /* build MDL */ + context->mdl = IoAllocateMdl( context->kva, (ULONG)context->uar_size, + FALSE, TRUE, NULL ); + if( !context->mdl ) { + err = -ENOMEM; + goto err_alloc_mdl; + } + MmBuildMdlForNonPagedPool( context->mdl ); + + /* Map the memory into the calling process's address space. */ + __try { + context->ibucontext.user_uar = MmMapLockedPagesSpecifyCache( context->mdl, + UserMode, MmNonCached, NULL, FALSE, NormalPagePriority ); + } + __except(EXCEPTION_EXECUTE_HANDLER) { + err = -EACCES; + goto err_map; + } + + /* user_db_tab */ + context->db_tab = mthca_init_user_db_tab(to_mdev(ibdev)); + if (IS_ERR(context->db_tab)) { + err = PTR_ERR(context->db_tab); + goto err_init_user; + } + + err = ib_copy_to_umv_buf(p_umv_buf, &uresp, sizeof uresp); + if (err) + goto err_copy_to_umv_buf; + + context->ibucontext.device = ibdev; + + atomic_set(&context->ibucontext.usecnt, 0); + return &context->ibucontext; + +err_copy_to_umv_buf: + mthca_cleanup_user_db_tab(to_mdev(ibdev), &context->uar, + context->db_tab); +err_init_user: + MmUnmapLockedPages( context->ibucontext.user_uar, context->mdl ); +err_map: + IoFreeMdl(context->mdl); +err_alloc_mdl: + iounmap(context->kva, PAGE_SIZE); +err_ioremap: + mthca_uar_free(to_mdev(ibdev), &context->uar); +err_uar_alloc: + kfree(context); +err_nomem: + return ERR_PTR(err); +} + + int mthca_dealloc_ucontext(struct ib_ucontext *context) +{ + struct mthca_ucontext *mucontext = to_mucontext(context); + + mthca_cleanup_user_db_tab(to_mdev(context->device), &mucontext->uar, + mucontext->db_tab); + MmUnmapLockedPages( mucontext->ibucontext.user_uar, mucontext->mdl ); + IoFreeMdl(mucontext->mdl); + iounmap(mucontext->kva, PAGE_SIZE); + mthca_uar_free(to_mdev(context->device), &mucontext->uar); + kfree(mucontext); + + return 0; +} + +struct ib_pd *mthca_alloc_pd(struct ib_device *ibdev, + struct ib_ucontext *context, + ci_umv_buf_t* const p_umv_buf) +{ + int err; + struct mthca_pd *pd; + struct ibv_alloc_pd_resp resp; + + /* sanity check */ + if (p_umv_buf && p_umv_buf->command) { + if (p_umv_buf->output_size < sizeof(struct ibv_alloc_pd_resp)) { + err = -EINVAL; + goto err_param; + } + } + + pd = kmalloc(sizeof *pd, GFP_KERNEL); + if (!pd) { + err = -ENOMEM; + goto err_mem; + } + + err = mthca_pd_alloc(to_mdev(ibdev), !context, pd); + if (err) { + goto err_pd_alloc; + } + + if (p_umv_buf && p_umv_buf->command) { + resp.pd_handle = (u64)(UINT_PTR)pd; + resp.pdn = pd->pd_num; + if (ib_copy_to_umv_buf(p_umv_buf, &resp, sizeof(struct ibv_alloc_pd_resp))) { + err = -EFAULT; + goto err_copy; + } + } + + return &pd->ibpd; + +err_copy: + mthca_pd_free(to_mdev(ibdev), pd); +err_pd_alloc: + kfree(pd); +err_mem: +err_param: + return ERR_PTR(err); +} + +int mthca_dealloc_pd(struct ib_pd *pd) +{ + mthca_pd_free(to_mdev(pd->device), to_mpd(pd)); + kfree(pd); + return 0; +} + +static struct ib_ah *mthca_ah_create(struct ib_pd *pd, + struct ib_ah_attr *ah_attr) +{ + int err; + struct mthca_ah *ah; + + ah = kzalloc(sizeof *ah, GFP_ATOMIC); + if (!ah) + return ERR_PTR(-ENOMEM); + + err = mthca_create_ah(to_mdev(pd->device), to_mpd(pd), ah_attr, ah); + if (err) { + kfree(ah); + return ERR_PTR(err); + } + + return &ah->ibah; +} + +static int mthca_ah_destroy(struct ib_ah *ah) +{ + mthca_destroy_ah(to_mdev(ah->device), to_mah(ah)); + kfree(ah); + + return 0; +} + +static struct ib_srq *mthca_create_srq(struct ib_pd *pd, + struct ib_srq_init_attr *init_attr, + ci_umv_buf_t* const p_umv_buf) +{ + struct ibv_create_srq ucmd = { 0 }; + struct mthca_ucontext *context = NULL; + struct mthca_srq *srq; + int err; + + srq = kzalloc(sizeof *srq, GFP_KERNEL); + if (!srq) + return ERR_PTR(-ENOMEM); + + if (pd->ucontext) { + context = to_mucontext(pd->ucontext); + + if (ib_copy_from_umv_buf(&ucmd, p_umv_buf, sizeof ucmd)) { + err = -EFAULT; + goto err_free; + } + err = mthca_map_user_db(to_mdev(pd->device), &context->uar, + context->db_tab, ucmd.db_index, + ucmd.db_page, NULL); + + if (err) + goto err_free; + + srq->mr.ibmr.lkey = ucmd.lkey; + srq->db_index = ucmd.db_index; + } + + err = mthca_alloc_srq(to_mdev(pd->device), to_mpd(pd), + &init_attr->attr, srq); + + if (err && pd->ucontext) + mthca_unmap_user_db(to_mdev(pd->device), &context->uar, + context->db_tab, ucmd.db_index); + + if (err) + goto err_free; + + if (context && ib_copy_to_umv_buf(p_umv_buf, &srq->srqn, sizeof (u32))) { + mthca_free_srq(to_mdev(pd->device), srq); + err = -EFAULT; + goto err_free; + } + + return &srq->ibsrq; + +err_free: + kfree(srq); + + return ERR_PTR(err); +} + +static int mthca_destroy_srq(struct ib_srq *srq) +{ + struct mthca_ucontext *context; + + if (srq->ucontext) { + context = to_mucontext(srq->ucontext); + + mthca_unmap_user_db(to_mdev(srq->device), &context->uar, + context->db_tab, to_msrq(srq)->db_index); + } + + mthca_free_srq(to_mdev(srq->device), to_msrq(srq)); + kfree(srq); + + return 0; +} + +static struct ib_qp *mthca_create_qp(struct ib_pd *pd, + struct ib_qp_init_attr *init_attr, + ci_umv_buf_t* const p_umv_buf) +{ + struct ibv_create_qp ucmd = {0}; + struct mthca_qp *qp = NULL; + struct mthca_ucontext *context = NULL; + int err; + + switch (init_attr->qp_type) { + case IB_QPT_RELIABLE_CONN: + case IB_QPT_UNRELIABLE_CONN: + case IB_QPT_UNRELIABLE_DGRM: + { + + qp = kmalloc(sizeof *qp, GFP_KERNEL); + if (!qp) { + err = -ENOMEM; + goto err_mem; + } + + if (pd->ucontext) { + context = to_mucontext(pd->ucontext); + + if (ib_copy_from_umv_buf(&ucmd, p_umv_buf, sizeof ucmd)) { + err = -EFAULT; + goto err_copy; + } + + err = mthca_map_user_db(to_mdev(pd->device), &context->uar, + context->db_tab, + ucmd.sq_db_index, ucmd.sq_db_page, NULL); + if (err) + goto err_map1; + + err = mthca_map_user_db(to_mdev(pd->device), &context->uar, + context->db_tab, + ucmd.rq_db_index, ucmd.rq_db_page, NULL); + if (err) + goto err_map2; + + qp->mr.ibmr.lkey = ucmd.lkey; + qp->sq.db_index = ucmd.sq_db_index; + qp->rq.db_index = ucmd.rq_db_index; + } + + err = mthca_alloc_qp(to_mdev(pd->device), to_mpd(pd), + to_mcq(init_attr->send_cq), + to_mcq(init_attr->recv_cq), + init_attr->qp_type, init_attr->sq_sig_type, + &init_attr->cap, qp); + + if (err) + if (pd->ucontext) + goto err_alloc_qp_user; + else + goto err_copy; + + qp->ibqp.qp_num = qp->qpn; + break; + } + case IB_QPT_QP0: + case IB_QPT_QP1: + { + /* Don't allow userspace to create special QPs */ + if (pd->ucontext) { + err = -EINVAL; + goto err_inval; + } + + qp = kmalloc(sizeof (struct mthca_sqp), GFP_KERNEL); + if (!qp) { + err = -ENOMEM; + goto err_mem; + } + + qp->ibqp.qp_num = init_attr->qp_type == IB_QPT_QP0 ? 0 : 1; + + err = mthca_alloc_sqp(to_mdev(pd->device), to_mpd(pd), + to_mcq(init_attr->send_cq), + to_mcq(init_attr->recv_cq), + init_attr->sq_sig_type, &init_attr->cap, + qp->ibqp.qp_num, init_attr->port_num, + to_msqp(qp)); + if (err) + goto err_alloc_sqp; + + break; + } + default: + /* Don't support raw QPs */ + err = -ENOSYS; + goto err_unsupported; + } + + init_attr->cap.max_send_wr = qp->sq.max; + init_attr->cap.max_recv_wr = qp->rq.max; + init_attr->cap.max_send_sge = qp->sq.max_gs; + init_attr->cap.max_recv_sge = qp->rq.max_gs; + init_attr->cap.max_inline_data = qp->max_inline_data; + + return &qp->ibqp; + + +err_alloc_qp_user: + if (pd->ucontext) + mthca_unmap_user_db(to_mdev(pd->device), + &context->uar, context->db_tab, ucmd.rq_db_index); +err_map2: + if (pd->ucontext) + mthca_unmap_user_db(to_mdev(pd->device), + &context->uar, context->db_tab, ucmd.sq_db_index); +err_map1: err_copy: err_alloc_sqp: + if (qp) + kfree(qp); +err_mem: err_inval: err_unsupported: + return ERR_PTR(err); +} + +static int mthca_destroy_qp(struct ib_qp *qp) +{ + if (qp->ucontext) { + mthca_unmap_user_db(to_mdev(qp->device), + &to_mucontext(qp->ucontext)->uar, + to_mucontext(qp->ucontext)->db_tab, + to_mqp(qp)->sq.db_index); + mthca_unmap_user_db(to_mdev(qp->device), + &to_mucontext(qp->ucontext)->uar, + to_mucontext(qp->ucontext)->db_tab, + to_mqp(qp)->rq.db_index); + } + mthca_free_qp(to_mdev(qp->device), to_mqp(qp)); + kfree(qp); + return 0; +} + +static struct ib_cq *mthca_create_cq(struct ib_device *ibdev, int entries, + struct ib_ucontext *context, + ci_umv_buf_t* const p_umv_buf) +{ + struct ibv_create_cq ucmd = {0}; + struct mthca_cq *cq; + int nent; + int err; + void *u_arm_db_page = 0; + + if (entries < 1 || entries > to_mdev(ibdev)->limits.max_cqes) + return ERR_PTR(-EINVAL); + + if (context) { + if (ib_copy_from_umv_buf(&ucmd, p_umv_buf, sizeof ucmd)) + return ERR_PTR(-EFAULT); + + err = mthca_map_user_db(to_mdev(ibdev), &to_mucontext(context)->uar, + to_mucontext(context)->db_tab, + ucmd.set_db_index, ucmd.set_db_page, NULL); + if (err) + return ERR_PTR(err); + + err = mthca_map_user_db(to_mdev(ibdev), &to_mucontext(context)->uar, + to_mucontext(context)->db_tab, + ucmd.arm_db_index, ucmd.arm_db_page, NULL); + if (err) + goto err_unmap_set; + + err = mthca_map_user_db(to_mdev(ibdev), &to_mucontext(context)->uar, + to_mucontext(context)->db_tab, + ucmd.u_arm_db_index, + (u64)(ULONG_PTR)PAGE_ALIGN(ucmd.u_arm_db_page), + &u_arm_db_page); + if (err) + goto err_unmap_arm; + } + + cq = kmalloc(sizeof *cq, GFP_KERNEL); + if (!cq) { + err = -ENOMEM; + goto err_unmap_ev; + } + + if (context) { + cq->mr.ibmr.lkey = ucmd.lkey; + cq->set_ci_db_index = ucmd.set_db_index; + cq->arm_db_index = ucmd.arm_db_index; + cq->u_arm_db_index = ucmd.u_arm_db_index; + cq->p_u_arm_sn = (int*)((char*)u_arm_db_page + BYTE_OFFSET(ucmd.u_arm_db_page)); + } + + for (nent = 1; nent <= entries; nent <<= 1) + ; /* nothing */ + + err = mthca_init_cq(to_mdev(ibdev), nent, + context ? to_mucontext(context) : NULL, + context ? ucmd.mr.pdn : to_mdev(ibdev)->driver_pd.pd_num, + cq); + if (err) + goto err_free; + + if (context) { + struct ibv_create_cq_resp *create_cq_resp = (struct ibv_create_cq_resp *)(ULONG_PTR)p_umv_buf->p_inout_buf; + create_cq_resp->cqn = cq->cqn; + } + + HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_LOW , + ("uctx %p, cq_hndl %p, cq_num %#x, cqe %#x\n", + context, &cq->ibcq, cq->cqn, cq->ibcq.cqe ) ); + + return &cq->ibcq; + +err_free: + kfree(cq); + +err_unmap_ev: + if (context) + mthca_unmap_user_db(to_mdev(ibdev), &to_mucontext(context)->uar, + to_mucontext(context)->db_tab, ucmd.u_arm_db_index); + +err_unmap_arm: + if (context) + mthca_unmap_user_db(to_mdev(ibdev), &to_mucontext(context)->uar, + to_mucontext(context)->db_tab, ucmd.arm_db_index); + +err_unmap_set: + if (context) + mthca_unmap_user_db(to_mdev(ibdev), &to_mucontext(context)->uar, + to_mucontext(context)->db_tab, ucmd.set_db_index); + + return ERR_PTR(err); +} + +static int mthca_destroy_cq(struct ib_cq *cq) +{ + if (cq->ucontext) { + mthca_unmap_user_db(to_mdev(cq->device), + &to_mucontext(cq->ucontext)->uar, + to_mucontext(cq->ucontext)->db_tab, + to_mcq(cq)->u_arm_db_index); + mthca_unmap_user_db(to_mdev(cq->device), + &to_mucontext(cq->ucontext)->uar, + to_mucontext(cq->ucontext)->db_tab, + to_mcq(cq)->arm_db_index); + mthca_unmap_user_db(to_mdev(cq->device), + &to_mucontext(cq->ucontext)->uar, + to_mucontext(cq->ucontext)->db_tab, + to_mcq(cq)->set_ci_db_index); + } + mthca_free_cq(to_mdev(cq->device), to_mcq(cq)); + kfree(cq); + + return 0; +} + +static +mthca_mpt_access_t +map_qp_mpt( + IN mthca_qp_access_t qp_acl) +{ +#define ACL_MTHCA(mfl,ifl) if (qp_acl & mfl) mpt_acl |= ifl + mthca_mpt_access_t mpt_acl = 0; + + ACL_MTHCA(MTHCA_ACCESS_REMOTE_READ,MTHCA_MPT_FLAG_REMOTE_READ); + ACL_MTHCA(MTHCA_ACCESS_REMOTE_WRITE,MTHCA_MPT_FLAG_REMOTE_WRITE); + ACL_MTHCA(MTHCA_ACCESS_REMOTE_ATOMIC,MTHCA_MPT_FLAG_ATOMIC); + ACL_MTHCA(MTHCA_ACCESS_LOCAL_WRITE,MTHCA_MPT_FLAG_LOCAL_WRITE); + + return (mpt_acl | MTHCA_MPT_FLAG_LOCAL_READ); +} + +struct ib_mr *mthca_get_dma_mr(struct ib_pd *pd, mthca_qp_access_t acc) +{ + struct mthca_mr *mr; + int err; + + mr = kzalloc(sizeof *mr, GFP_KERNEL); + if (!mr) + return ERR_PTR(-ENOMEM); + + err = mthca_mr_alloc_notrans(to_mdev(pd->device), + to_mpd(pd)->pd_num, + map_qp_mpt(acc), mr); + + if (err) { + kfree(mr); + return ERR_PTR(err); + } + + return &mr->ibmr; +} + +static struct ib_mr *mthca_reg_phys_mr(struct ib_pd *pd, + struct ib_phys_buf *buffer_list, + int num_phys_buf, + mthca_qp_access_t acc, + u64 *iova_start) +{ + struct mthca_mr *mr; + u64 *page_list; + u64 total_size; + u64 mask; + int shift; + int npages; + int err; + int i, j, n; + + /* First check that we have enough alignment */ + if ((*iova_start & ~PAGE_MASK) != (buffer_list[0].addr & ~PAGE_MASK)) + return ERR_PTR(-EINVAL); + + if (num_phys_buf > 1 && + ((buffer_list[0].addr + buffer_list[0].size) & ~PAGE_MASK)) + return ERR_PTR(-EINVAL); + + mask = 0; + total_size = 0; + for (i = 0; i < num_phys_buf; ++i) { + if (i != 0) + mask |= buffer_list[i].addr; + if (i != num_phys_buf - 1) + mask |= buffer_list[i].addr + buffer_list[i].size; + + total_size += buffer_list[i].size; + } + + if (mask & ~PAGE_MASK) + return ERR_PTR(-EINVAL); + + /* Find largest page shift we can use to cover buffers */ + for (shift = PAGE_SHIFT; shift < 31; ++shift) + if (num_phys_buf > 1) { + if ((1Ui64 << shift) & mask) + break; + } else { + if (1Ui64 << shift >= + buffer_list[0].size + + (buffer_list[0].addr & ((1Ui64 << shift) - 1))) + break; + } + + buffer_list[0].size += buffer_list[0].addr & ((1Ui64 << shift) - 1); + buffer_list[0].addr &= ~0Ui64 << shift; + + mr = kzalloc(sizeof *mr, GFP_KERNEL); + if (!mr) + return ERR_PTR(-ENOMEM); + + npages = 0; + for (i = 0; i < num_phys_buf; ++i) + npages += (int)((buffer_list[i].size + (1Ui64 << shift) - 1) >> shift); + + if (!npages) + return &mr->ibmr; + + page_list = kmalloc(npages * sizeof *page_list, GFP_KERNEL); + if (!page_list) { + kfree(mr); + return ERR_PTR(-ENOMEM); + } + + n = 0; + for (i = 0; i < num_phys_buf; ++i) + for (j = 0; + j < (buffer_list[i].size + (1Ui64 << shift) - 1) >> shift; + ++j) + page_list[n++] = buffer_list[i].addr + ((u64) j << shift); + + HCA_PRINT( TRACE_LEVEL_VERBOSE ,HCA_DBG_LOW ,("Registering memory at %I64x (iova %I64x) " + "in PD %x; shift %d, npages %d.\n", + (u64) buffer_list[0].addr, + (u64) *iova_start, + to_mpd(pd)->pd_num, + shift, npages)); + + err = mthca_mr_alloc_phys(to_mdev(pd->device), + to_mpd(pd)->pd_num, + page_list, shift, npages, + *iova_start, total_size, + map_qp_mpt(acc), mr); + + if (err) { + kfree(page_list); + kfree(mr); + return ERR_PTR(err); + } + + kfree(page_list); + return &mr->ibmr; +} + +static struct ib_mr *mthca_reg_virt_mr(struct ib_pd *pd, + void* vaddr, uint64_t length, uint64_t hca_va, + mthca_qp_access_t acc, boolean_t um_call, boolean_t secure) +{ + struct mthca_dev *dev = to_mdev(pd->device); + struct mthca_mr *mr; + u64 *pages; + int err = 0; + uint32_t i, n; + mt_iobuf_t *iobuf_p; + mt_iobuf_iter_t iobuf_iter; + ib_access_t ib_acc; + + /* + * Be friendly to WRITE_MTT command and leave two + * empty slots for the index and reserved fields of the mailbox. + */ + int max_buf_list_size = PAGE_SIZE / sizeof (u64) - 2; + + HCA_ENTER(HCA_DBG_MEMORY); + + mr = kzalloc(sizeof *mr, GFP_KERNEL); + if (!mr) { + err = -ENOMEM; + goto err_nomem; + } + + /* + * We ask for writable memory if any access flags other than + * "remote read" are set. "Local write" and "remote write" + * obviously require write access. "Remote atomic" can do + * things like fetch and add, which will modify memory, and + * "MW bind" can change permissions by binding a window. + */ + + // try register the buffer + iobuf_p = &mr->iobuf; + iobuf_init( (ULONG_PTR)vaddr, length, um_call, iobuf_p); + ib_acc = (acc & ~MTHCA_ACCESS_REMOTE_READ) ? IB_AC_LOCAL_WRITE : 0; + err = iobuf_register_with_cash( (ULONG_PTR)vaddr, length, um_call, + &ib_acc, iobuf_p ); + if (err) + goto err_reg_mem; + mr->iobuf_used = TRUE; + + // allocate MTT's + mr->mtt = mthca_alloc_mtt(dev, iobuf_p->nr_pages); + if (IS_ERR(mr->mtt)) { + err = PTR_ERR(mr->mtt); + goto err_alloc_mtt; + } + + // allocate buffer_list for writing MTT's + pages = (u64 *) kmalloc(PAGE_SIZE,GFP_KERNEL); + if (!pages) { + err = -ENOMEM; + goto err_pages; + } + + // write MTT's + iobuf_iter_init( iobuf_p, &iobuf_iter ); + n = 0; + for (;;) { + // get up to max_buf_list_size page physical addresses + i = iobuf_get_tpt_seg( iobuf_p, &iobuf_iter, max_buf_list_size, pages ); + if (!i) + break; + + //TODO: convert physical adresses to dma one's + + // write 'i' dma addresses + err = mthca_write_mtt(dev, mr->mtt, n, pages, i); + if (err) + goto err_write_mtt; + n += i; + if (n >= iobuf_p->nr_pages) + break; + } + + CL_ASSERT(n == iobuf_p->nr_pages); + + // write MPT + err = mthca_mr_alloc(dev, to_mpd(pd)->pd_num, PAGE_SHIFT, hca_va, + length, map_qp_mpt(acc), mr); + if (err) + goto err_mt_alloc; + + // secure memory + if (!pd->ucontext || !secure) + goto done; + __try { + mr->secure_handle = MmSecureVirtualMemory ( vaddr, (SIZE_T)length, + (ib_acc & IB_AC_LOCAL_WRITE) ? PAGE_READWRITE : PAGE_READONLY ); + if (mr->secure_handle == NULL) { + err = -EFAULT; + goto err_secure; + } + } + __except (EXCEPTION_EXECUTE_HANDLER) { + NTSTATUS Status = GetExceptionCode(); + UNUSED_PARAM_WOWPP(Status); + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_MEMORY , + ("Exception 0x%x on MmSecureVirtualMemory(), addr %p, size %I64d, access %#x\n", + Status, vaddr, length, acc )); + err = -EFAULT; + goto err_secure; + } + +done: + free_page((void*) pages); + + HCA_EXIT(HCA_DBG_MEMORY); + return &mr->ibmr; + +err_secure: +err_mt_alloc: +err_write_mtt: + free_page((void*) pages); +err_pages: + mthca_free_mtt(dev, mr->mtt); +err_alloc_mtt: + iobuf_deregister(iobuf_p); +err_reg_mem: + kfree(mr); +err_nomem: + + HCA_EXIT(HCA_DBG_MEMORY); + return ERR_PTR(err); +} + +int mthca_dereg_mr(struct ib_mr *mr) +{ + struct mthca_mr *mmr = to_mmr(mr); + struct mthca_dev* dev = to_mdev(mr->device); + + if (mmr->secure_handle) { + __try { + MmUnsecureVirtualMemory( mmr->secure_handle ); + mmr->secure_handle = NULL; + } + __except (EXCEPTION_EXECUTE_HANDLER) { + NTSTATUS Status = GetExceptionCode(); + UNUSED_PARAM_WOWPP(Status); + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_MEMORY , + ("Exception 0x%x on MmUnsecureVirtualMemory(), addr %I64x, size %I64x, seg_num %d, nr_pages %d\n", + Status, mmr->iobuf.va, (u64)mmr->iobuf.size, mmr->iobuf.seg_num, mmr->iobuf.nr_pages )); + } + } + mthca_free_mr(dev, mmr); + if (mmr->iobuf_used) + iobuf_deregister_with_cash(&mmr->iobuf); + kfree(mmr); + return 0; +} + +static struct ib_fmr *mthca_alloc_fmr(struct ib_pd *pd, mthca_qp_access_t acc, + struct ib_fmr_attr *fmr_attr) +{ + struct mthca_fmr *fmr; + int err; + + fmr = kzalloc(sizeof *fmr, GFP_KERNEL); + if (!fmr) + return ERR_PTR(-ENOMEM); + + RtlCopyMemory(&fmr->attr, fmr_attr, sizeof *fmr_attr); + err = mthca_fmr_alloc(to_mdev(pd->device), to_mpd(pd)->pd_num, + map_qp_mpt(acc), fmr); + + if (err) { + kfree(fmr); + return ERR_PTR(err); + } + + return &fmr->ibfmr; +} + +static int mthca_dealloc_fmr(struct ib_fmr *fmr) +{ + struct mthca_fmr *mfmr = to_mfmr(fmr); + int err; + + err = mthca_free_fmr(to_mdev(fmr->device), mfmr); + if (err) + return err; + + kfree(mfmr); + return 0; +} + +static int mthca_unmap_fmr(struct list_head *fmr_list) +{ + struct ib_fmr *fmr; + int err; + u8 status; + struct mthca_dev *mdev = NULL; + + list_for_each_entry(fmr, fmr_list, list,struct ib_fmr) { + if (mdev && to_mdev(fmr->device) != mdev) + return -EINVAL; + mdev = to_mdev(fmr->device); + } + + if (!mdev) + return 0; + + if (mthca_is_memfree(mdev)) { + list_for_each_entry(fmr, fmr_list, list,struct ib_fmr) + mthca_arbel_fmr_unmap(mdev, to_mfmr(fmr)); + + wmb(); + } else + list_for_each_entry(fmr, fmr_list, list,struct ib_fmr) + mthca_tavor_fmr_unmap(mdev, to_mfmr(fmr)); + + err = mthca_SYNC_TPT(mdev, &status); + if (err) + return err; + if (status) + return -EINVAL; + return 0; +} + +static int mthca_init_node_data(struct mthca_dev *dev) +{ + struct ib_smp *in_mad = NULL; + struct ib_smp *out_mad = NULL; + int err = -ENOMEM; + u8 status; + + in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL); + out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL); + if (!in_mad || !out_mad) + goto out; + + init_query_mad(in_mad); + in_mad->attr_id = IB_SMP_ATTR_NODE_INFO; + + err = mthca_MAD_IFC(dev, 1, 1, + 1, NULL, NULL, in_mad, out_mad, + &status); + if (err) + goto out; + if (status) { + err = -EINVAL; + goto out; + } + + memcpy(&dev->ib_dev.node_guid, out_mad->data + 12, 8); + +out: + kfree(in_mad); + kfree(out_mad); + return err; +} + +int mthca_register_device(struct mthca_dev *dev) +{ + int ret; + + ret = mthca_init_node_data(dev); + if (ret) + return ret; + + strlcpy(dev->ib_dev.name, "mthca%d", IB_DEVICE_NAME_MAX); + dev->ib_dev.node_type = IB_NODE_CA; + dev->ib_dev.phys_port_cnt = (u8)dev->limits.num_ports; + dev->ib_dev.mdev = dev; + dev->ib_dev.query_device = mthca_query_device; + dev->ib_dev.query_port = mthca_query_port; + dev->ib_dev.modify_port = mthca_modify_port; + dev->ib_dev.query_pkey_chunk = mthca_query_pkey_chunk; + dev->ib_dev.query_gid_chunk = mthca_query_gid_chunk; + dev->ib_dev.alloc_ucontext = mthca_alloc_ucontext; + dev->ib_dev.dealloc_ucontext = mthca_dealloc_ucontext; + dev->ib_dev.alloc_pd = mthca_alloc_pd; + dev->ib_dev.dealloc_pd = mthca_dealloc_pd; + dev->ib_dev.create_ah = mthca_ah_create; + dev->ib_dev.destroy_ah = mthca_ah_destroy; + + if (dev->mthca_flags & MTHCA_FLAG_SRQ) { + dev->ib_dev.create_srq = mthca_create_srq; + dev->ib_dev.modify_srq = mthca_modify_srq; + dev->ib_dev.query_srq = mthca_query_srq; + dev->ib_dev.destroy_srq = mthca_destroy_srq; + + if (mthca_is_memfree(dev)) + dev->ib_dev.post_srq_recv = mthca_arbel_post_srq_recv; + else + dev->ib_dev.post_srq_recv = mthca_tavor_post_srq_recv; + } + + dev->ib_dev.create_qp = mthca_create_qp; + dev->ib_dev.modify_qp = mthca_modify_qp; + dev->ib_dev.query_qp = mthca_query_qp; + dev->ib_dev.destroy_qp = mthca_destroy_qp; + dev->ib_dev.create_cq = mthca_create_cq; + dev->ib_dev.destroy_cq = mthca_destroy_cq; + dev->ib_dev.poll_cq = mthca_poll_cq; + dev->ib_dev.get_dma_mr = mthca_get_dma_mr; + dev->ib_dev.reg_phys_mr = mthca_reg_phys_mr; + dev->ib_dev.reg_virt_mr = mthca_reg_virt_mr; + dev->ib_dev.dereg_mr = mthca_dereg_mr; + + if (dev->mthca_flags & MTHCA_FLAG_FMR) { + dev->ib_dev.alloc_fmr = mthca_alloc_fmr; + dev->ib_dev.unmap_fmr = mthca_unmap_fmr; + dev->ib_dev.dealloc_fmr = mthca_dealloc_fmr; + if (mthca_is_memfree(dev)) + dev->ib_dev.map_phys_fmr = mthca_arbel_map_phys_fmr; + else + dev->ib_dev.map_phys_fmr = mthca_tavor_map_phys_fmr; + } + + dev->ib_dev.attach_mcast = mthca_multicast_attach; + dev->ib_dev.detach_mcast = mthca_multicast_detach; + dev->ib_dev.process_mad = mthca_process_mad; + + if (mthca_is_memfree(dev)) { + dev->ib_dev.req_notify_cq = mthca_arbel_arm_cq; + dev->ib_dev.post_send = mthca_arbel_post_send; + dev->ib_dev.post_recv = mthca_arbel_post_recv; + } else { + dev->ib_dev.req_notify_cq = mthca_tavor_arm_cq; + dev->ib_dev.post_send = mthca_tavor_post_send; + dev->ib_dev.post_recv = mthca_tavor_post_recv; + } + + KeInitializeMutex(&dev->cap_mask_mutex, 0); + + ret = ib_register_device(&dev->ib_dev); + if (ret) + return ret; + + mthca_start_catas_poll(dev); + + return 0; +} + +void mthca_unregister_device(struct mthca_dev *dev) +{ + mthca_stop_catas_poll(dev); + ib_unregister_device(&dev->ib_dev); +} diff --git a/branches/WOF2-3/hw/mthca/kernel/mthca_provider.h b/branches/WOF2-3/hw/mthca/kernel/mthca_provider.h new file mode 100644 index 00000000..ca5db21f --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/mthca_provider.h @@ -0,0 +1,401 @@ +/* + * Copyright (c) 2004 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Cisco Systems. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#ifndef MTHCA_PROVIDER_H +#define MTHCA_PROVIDER_H + +#include +#include +#include + +typedef uint32_t mthca_mpt_access_t; +#define MTHCA_MPT_FLAG_ATOMIC (1 << 14) +#define MTHCA_MPT_FLAG_REMOTE_WRITE (1 << 13) +#define MTHCA_MPT_FLAG_REMOTE_READ (1 << 12) +#define MTHCA_MPT_FLAG_LOCAL_WRITE (1 << 11) +#define MTHCA_MPT_FLAG_LOCAL_READ (1 << 10) + +union mthca_buf { + struct scatterlist direct; + struct scatterlist *page_list; +}; + +struct mthca_uar { + PFN_NUMBER pfn; + int index; +}; + +struct mthca_user_db_table; + +struct mthca_ucontext { + struct ib_ucontext ibucontext; + struct mthca_uar uar; + struct mthca_user_db_table *db_tab; + // for user UAR + PMDL mdl; + PVOID kva; + SIZE_T uar_size; +}; + +struct mthca_mtt; + +struct mthca_mr { + //NB: the start of this structure is to be equal to mlnx_mro_t ! + //NB: the structure was not inserted here for not to mix driver and provider structures + struct ib_mr ibmr; + struct mthca_mtt *mtt; + int iobuf_used; + mt_iobuf_t iobuf; + void *secure_handle; +}; + +struct mthca_fmr { + struct ib_fmr ibfmr; + struct ib_fmr_attr attr; + struct mthca_mtt *mtt; + int maps; + union { + struct { + struct mthca_mpt_entry __iomem *mpt; + u64 __iomem *mtts; + } tavor; + struct { + struct mthca_mpt_entry *mpt; + __be64 *mtts; + } arbel; + } mem; +}; + +struct mthca_pd { + struct ib_pd ibpd; + u32 pd_num; + atomic_t sqp_count; + struct mthca_mr ntmr; + int privileged; +}; + +struct mthca_eq { + struct mthca_dev *dev; + int eqn; + int eq_num; + u32 eqn_mask; + u32 cons_index; + u16 msi_x_vector; + u16 msi_x_entry; + int have_irq; + int nent; + struct scatterlist *page_list; + struct mthca_mr mr; + KDPC dpc; /* DPC for MSI-X interrupts */ + spinlock_t lock; /* spinlock for simult DPCs */ +}; + +struct mthca_av; + +enum mthca_ah_type { + MTHCA_AH_ON_HCA, + MTHCA_AH_PCI_POOL, + MTHCA_AH_KMALLOC +}; + +struct mthca_ah { + struct ib_ah ibah; + enum mthca_ah_type type; + u32 key; + struct mthca_av *av; + dma_addr_t avdma; +}; + +/* + * Quick description of our CQ/QP locking scheme: + * + * We have one global lock that protects dev->cq/qp_table. Each + * struct mthca_cq/qp also has its own lock. An individual qp lock + * may be taken inside of an individual cq lock. Both cqs attached to + * a qp may be locked, with the send cq locked first. No other + * nesting should be done. + * + * Each struct mthca_cq/qp also has an atomic_t ref count. The + * pointer from the cq/qp_table to the struct counts as one reference. + * This reference also is good for access through the consumer API, so + * modifying the CQ/QP etc doesn't need to take another reference. + * Access because of a completion being polled does need a reference. + * + * Finally, each struct mthca_cq/qp has a wait_queue_head_t for the + * destroy function to sleep on. + * + * This means that access from the consumer API requires nothing but + * taking the struct's lock. + * + * Access because of a completion event should go as follows: + * - lock cq/qp_table and look up struct + * - increment ref count in struct + * - drop cq/qp_table lock + * - lock struct, do your thing, and unlock struct + * - decrement ref count; if zero, wake up waiters + * + * To destroy a CQ/QP, we can do the following: + * - lock cq/qp_table, remove pointer, unlock cq/qp_table lock + * - decrement ref count + * - wait_event until ref count is zero + * + * It is the consumer's responsibilty to make sure that no QP + * operations (WQE posting or state modification) are pending when the + * QP is destroyed. Also, the consumer must make sure that calls to + * qp_modify are serialized. + * + * Possible optimizations (wait for profile data to see if/where we + * have locks bouncing between CPUs): + * - split cq/qp table lock into n separate (cache-aligned) locks, + * indexed (say) by the page in the table + * - split QP struct lock into three (one for common info, one for the + * send queue and one for the receive queue) + */ +//TODO: check correctness of the above requirement: "It is the consumer's responsibilty to make sure that no QP +// operations (WQE posting or state modification) are pending when the QP is destroyed" + +struct mthca_cq { + struct ib_cq ibcq; + spinlock_t lock; + atomic_t refcount; + int cqn; + u32 cons_index; + int is_direct; + int is_kernel; + + /* Next fields are Arbel only */ + int set_ci_db_index; + __be32 *set_ci_db; + int arm_db_index; + __be32 *arm_db; + int arm_sn; + int u_arm_db_index; + int *p_u_arm_sn; + + union mthca_buf queue; + struct mthca_mr mr; + wait_queue_head_t wait; + KMUTEX mutex; +}; + +struct mthca_srq { + struct ib_srq ibsrq; + spinlock_t lock; + atomic_t refcount; + int srqn; + int max; + int max_gs; + int wqe_shift; + int first_free; + int last_free; + u16 counter; /* Arbel only */ + int db_index; /* Arbel only */ + __be32 *db; /* Arbel only */ + void *last; + + int is_direct; + u64 *wrid; + union mthca_buf queue; + struct mthca_mr mr; + + wait_queue_head_t wait; + KMUTEX mutex; +}; + +struct mthca_wq { + spinlock_t lock; + int max; + unsigned next_ind; + unsigned last_comp; + unsigned head; + unsigned tail; + void *last; + int max_gs; + int wqe_shift; + + int db_index; /* Arbel only */ + __be32 *db; +}; + +struct mthca_qp { + struct ib_qp ibqp; + //TODO: added just because absense of ibv_query_qp + // thereafter it may be worth to be replaced by struct ib_qp_attr qp_attr; + struct ib_qp_init_attr qp_init_attr; // leo: for query_qp + atomic_t refcount; + u32 qpn; + int is_direct; + u8 transport; + u8 state; + u8 atomic_rd_en; + u8 resp_depth; + + struct mthca_mr mr; + + struct mthca_wq rq; + struct mthca_wq sq; + enum ib_sig_type sq_policy; + int send_wqe_offset; + int max_inline_data; + + u64 *wrid; + union mthca_buf queue; + + wait_queue_head_t wait; + KMUTEX mutex; +}; + +struct mthca_sqp { + struct mthca_qp qp; + int port; + int pkey_index; + u32 qkey; + u32 send_psn; + struct ib_ud_header ud_header; + struct scatterlist sg; +}; + +static inline struct mthca_ucontext *to_mucontext(struct ib_ucontext *ibucontext) +{ + return container_of(ibucontext, struct mthca_ucontext, ibucontext); +} + +static inline struct mthca_fmr *to_mfmr(struct ib_fmr *ibfmr) +{ + return container_of(ibfmr, struct mthca_fmr, ibfmr); +} + +static inline struct mthca_mr *to_mmr(struct ib_mr *ibmr) +{ + return container_of(ibmr, struct mthca_mr, ibmr); +} + +static inline struct mthca_pd *to_mpd(struct ib_pd *ibpd) +{ + return container_of(ibpd, struct mthca_pd, ibpd); +} + +static inline struct mthca_ah *to_mah(struct ib_ah *ibah) +{ + return container_of(ibah, struct mthca_ah, ibah); +} + +static inline struct mthca_cq *to_mcq(struct ib_cq *ibcq) +{ + return container_of(ibcq, struct mthca_cq, ibcq); +} + +static inline struct mthca_srq *to_msrq(struct ib_srq *ibsrq) +{ + return container_of(ibsrq, struct mthca_srq, ibsrq); +} + +static inline struct mthca_qp *to_mqp(struct ib_qp *ibqp) +{ + return container_of(ibqp, struct mthca_qp, ibqp); +} + +static inline struct mthca_sqp *to_msqp(struct mthca_qp *qp) +{ + return container_of(qp, struct mthca_sqp, qp); +} + +static inline uint8_t start_port(struct ib_device *device) +{ + return device->node_type == IB_NODE_SWITCH ? 0 : 1; +} + +static inline uint8_t end_port(struct ib_device *device) +{ + return device->node_type == IB_NODE_SWITCH ? 0 : device->phys_port_cnt; +} + +static inline int ib_copy_from_umv_buf(void *dest, ci_umv_buf_t* const p_umv_buf, size_t len) +{ + RtlCopyMemory(dest, (void*)(ULONG_PTR)p_umv_buf->p_inout_buf, len); + return 0; +} + +static inline int ib_copy_to_umv_buf(ci_umv_buf_t* const p_umv_buf, void *src, size_t len) +{ + if (p_umv_buf->output_size < len) { + p_umv_buf->status = IB_INSUFFICIENT_MEMORY; + p_umv_buf->output_size = 0; + return -EFAULT; + } + RtlCopyMemory((void*)(ULONG_PTR)p_umv_buf->p_inout_buf, src, len); + p_umv_buf->status = IB_SUCCESS; + p_umv_buf->output_size = (uint32_t)len; + return 0; +} + + + +// API +int mthca_query_device(struct ib_device *ibdev, + struct ib_device_attr *props); + +int mthca_query_port(struct ib_device *ibdev, + u8 port, struct ib_port_attr *props); + +int mthca_modify_port(struct ib_device *ibdev, + u8 port, int port_modify_mask, + struct ib_port_modify *props); + +struct ib_pd *mthca_alloc_pd(struct ib_device *ibdev, + struct ib_ucontext *context, + ci_umv_buf_t* const p_umv_buf); + +int mthca_dealloc_pd(struct ib_pd *pd); + +int mthca_dereg_mr(struct ib_mr *mr); + +int mthca_query_srq(struct ib_srq *ibsrq, ib_srq_attr_t *srq_attr); + +struct ib_ucontext *mthca_alloc_ucontext(struct ib_device *ibdev, + ci_umv_buf_t* const p_umv_buf); + +int mthca_dealloc_ucontext(struct ib_ucontext *context); + +struct ib_mr *mthca_get_dma_mr(struct ib_pd *pd, mthca_qp_access_t acc); + +int mthca_poll_cq_list( + IN struct ib_cq *ibcq, + IN OUT ib_wc_t** const pp_free_wclist, + OUT ib_wc_t** const pp_done_wclist ); + + +#endif /* MTHCA_PROVIDER_H */ diff --git a/branches/WOF2-3/hw/mthca/kernel/mthca_qp.c b/branches/WOF2-3/hw/mthca/kernel/mthca_qp.c new file mode 100644 index 00000000..d64f8071 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/mthca_qp.c @@ -0,0 +1,2542 @@ +/* + * Copyright (c) 2004 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Cisco Systems. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * Copyright (c) 2004 Voltaire, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include +#include +#include + +#include "mthca_dev.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "mthca_qp.tmh" +#endif +#include "mthca_cmd.h" +#include "mthca_memfree.h" +#include "mthca_wqe.h" + + +enum { + MTHCA_MAX_DIRECT_QP_SIZE = 4 * PAGE_SIZE, + MTHCA_ACK_REQ_FREQ = 10, + MTHCA_FLIGHT_LIMIT = 9, + MTHCA_UD_HEADER_SIZE = 72, /* largest UD header possible */ + MTHCA_INLINE_HEADER_SIZE = 4, /* data segment overhead for inline */ + MTHCA_INLINE_CHUNK_SIZE = 16 /* inline data segment chunk */ +}; + +enum { + MTHCA_QP_STATE_RST = 0, + MTHCA_QP_STATE_INIT = 1, + MTHCA_QP_STATE_RTR = 2, + MTHCA_QP_STATE_RTS = 3, + MTHCA_QP_STATE_SQE = 4, + MTHCA_QP_STATE_SQD = 5, + MTHCA_QP_STATE_ERR = 6, + MTHCA_QP_STATE_DRAINING = 7 +}; + +enum { + MTHCA_QP_ST_RC = 0x0, + MTHCA_QP_ST_UC = 0x1, + MTHCA_QP_ST_RD = 0x2, + MTHCA_QP_ST_UD = 0x3, + MTHCA_QP_ST_MLX = 0x7 +}; + +enum { + MTHCA_QP_PM_MIGRATED = 0x3, + MTHCA_QP_PM_ARMED = 0x0, + MTHCA_QP_PM_REARM = 0x1 +}; + +enum { + /* qp_context flags */ + MTHCA_QP_BIT_DE = 1 << 8, + /* params1 */ + MTHCA_QP_BIT_SRE = 1 << 15, + MTHCA_QP_BIT_SWE = 1 << 14, + MTHCA_QP_BIT_SAE = 1 << 13, + MTHCA_QP_BIT_SIC = 1 << 4, + MTHCA_QP_BIT_SSC = 1 << 3, + /* params2 */ + MTHCA_QP_BIT_RRE = 1 << 15, + MTHCA_QP_BIT_RWE = 1 << 14, + MTHCA_QP_BIT_RAE = 1 << 13, + MTHCA_QP_BIT_RIC = 1 << 4, + MTHCA_QP_BIT_RSC = 1 << 3 +}; + +#pragma pack(push,1) +struct mthca_qp_path { + __be32 port_pkey; + u8 rnr_retry; + u8 g_mylmc; + __be16 rlid; + u8 ackto; + u8 mgid_index; + u8 static_rate; + u8 hop_limit; + __be32 sl_tclass_flowlabel; + u8 rgid[16]; +} ; + +struct mthca_qp_context { + __be32 flags; + __be32 tavor_sched_queue; /* Reserved on Arbel */ + u8 mtu_msgmax; + u8 rq_size_stride; /* Reserved on Tavor */ + u8 sq_size_stride; /* Reserved on Tavor */ + u8 rlkey_arbel_sched_queue; /* Reserved on Tavor */ + __be32 usr_page; + __be32 local_qpn; + __be32 remote_qpn; + u32 reserved1[2]; + struct mthca_qp_path pri_path; + struct mthca_qp_path alt_path; + __be32 rdd; + __be32 pd; + __be32 wqe_base; + __be32 wqe_lkey; + __be32 params1; + __be32 reserved2; + __be32 next_send_psn; + __be32 cqn_snd; + __be32 snd_wqe_base_l; /* Next send WQE on Tavor */ + __be32 snd_db_index; /* (debugging only entries) */ + __be32 last_acked_psn; + __be32 ssn; + __be32 params2; + __be32 rnr_nextrecvpsn; + __be32 ra_buff_indx; + __be32 cqn_rcv; + __be32 rcv_wqe_base_l; /* Next recv WQE on Tavor */ + __be32 rcv_db_index; /* (debugging only entries) */ + __be32 qkey; + __be32 srqn; + __be32 rmsn; + __be16 rq_wqe_counter; /* reserved on Tavor */ + __be16 sq_wqe_counter; /* reserved on Tavor */ + u32 reserved3[18]; +} ; + +struct mthca_qp_param { + __be32 opt_param_mask; + u32 reserved1; + struct mthca_qp_context context; + u32 reserved2[62]; +} ; +#pragma pack(pop) + +enum { + MTHCA_QP_OPTPAR_ALT_ADDR_PATH = 1 << 0, + MTHCA_QP_OPTPAR_RRE = 1 << 1, + MTHCA_QP_OPTPAR_RAE = 1 << 2, + MTHCA_QP_OPTPAR_RWE = 1 << 3, + MTHCA_QP_OPTPAR_PKEY_INDEX = 1 << 4, + MTHCA_QP_OPTPAR_Q_KEY = 1 << 5, + MTHCA_QP_OPTPAR_RNR_TIMEOUT = 1 << 6, + MTHCA_QP_OPTPAR_PRIMARY_ADDR_PATH = 1 << 7, + MTHCA_QP_OPTPAR_SRA_MAX = 1 << 8, + MTHCA_QP_OPTPAR_RRA_MAX = 1 << 9, + MTHCA_QP_OPTPAR_PM_STATE = 1 << 10, + MTHCA_QP_OPTPAR_PORT_NUM = 1 << 11, + MTHCA_QP_OPTPAR_RETRY_COUNT = 1 << 12, + MTHCA_QP_OPTPAR_ALT_RNR_RETRY = 1 << 13, + MTHCA_QP_OPTPAR_ACK_TIMEOUT = 1 << 14, + MTHCA_QP_OPTPAR_RNR_RETRY = 1 << 15, + MTHCA_QP_OPTPAR_SCHED_QUEUE = 1 << 16 +}; + +static const u8 mthca_opcode[] = { + MTHCA_OPCODE_RDMA_WRITE, + MTHCA_OPCODE_RDMA_WRITE_IMM, + MTHCA_OPCODE_SEND, + MTHCA_OPCODE_SEND_IMM, + MTHCA_OPCODE_RDMA_READ, + MTHCA_OPCODE_ATOMIC_CS, + MTHCA_OPCODE_ATOMIC_FA +}; + + +enum { RC, UC, UD, RD, RDEE, MLX, NUM_TRANS }; + +static struct _state_table { + int trans; + u32 req_param[NUM_TRANS]; + u32 opt_param[NUM_TRANS]; +} state_table[IBQPS_ERR + 1][IBQPS_ERR + 1]= {0}; + +static void fill_state_table() +{ + struct _state_table *t; + RtlZeroMemory( state_table, sizeof(state_table) ); + + /* IBQPS_RESET */ + t = &state_table[IBQPS_RESET][0]; + t[IBQPS_RESET].trans = MTHCA_TRANS_ANY2RST; + t[IBQPS_ERR].trans = MTHCA_TRANS_ANY2ERR; + + t[IBQPS_INIT].trans = MTHCA_TRANS_RST2INIT; + t[IBQPS_INIT].req_param[UD] = IB_QP_PKEY_INDEX |IB_QP_PORT |IB_QP_QKEY; + t[IBQPS_INIT].req_param[UC] = IB_QP_PKEY_INDEX |IB_QP_PORT |IB_QP_ACCESS_FLAGS; + t[IBQPS_INIT].req_param[RC] = IB_QP_PKEY_INDEX |IB_QP_PORT |IB_QP_ACCESS_FLAGS; + t[IBQPS_INIT].req_param[MLX] = IB_QP_PKEY_INDEX |IB_QP_QKEY; + t[IBQPS_INIT].opt_param[MLX] = IB_QP_PORT; + + /* IBQPS_INIT */ + t = &state_table[IBQPS_INIT][0]; + t[IBQPS_RESET].trans = MTHCA_TRANS_ANY2RST; + t[IBQPS_ERR].trans = MTHCA_TRANS_ANY2ERR; + + t[IBQPS_INIT].trans = MTHCA_TRANS_INIT2INIT; + t[IBQPS_INIT].opt_param[UD] = IB_QP_PKEY_INDEX |IB_QP_PORT |IB_QP_QKEY; + t[IBQPS_INIT].opt_param[UC] = IB_QP_PKEY_INDEX |IB_QP_PORT |IB_QP_ACCESS_FLAGS; + t[IBQPS_INIT].opt_param[RC] = IB_QP_PKEY_INDEX |IB_QP_PORT |IB_QP_ACCESS_FLAGS; + t[IBQPS_INIT].opt_param[MLX] = IB_QP_PKEY_INDEX |IB_QP_QKEY; + + t[IBQPS_RTR].trans = MTHCA_TRANS_INIT2RTR; + t[IBQPS_RTR].req_param[UC] = + IB_QP_AV |IB_QP_PATH_MTU |IB_QP_DEST_QPN |IB_QP_RQ_PSN; + t[IBQPS_RTR].req_param[RC] = + IB_QP_AV |IB_QP_PATH_MTU |IB_QP_DEST_QPN |IB_QP_RQ_PSN |IB_QP_MAX_DEST_RD_ATOMIC |IB_QP_MIN_RNR_TIMER; + t[IBQPS_RTR].opt_param[UD] = IB_QP_PKEY_INDEX |IB_QP_QKEY; + t[IBQPS_RTR].opt_param[UC] = IB_QP_PKEY_INDEX |IB_QP_ALT_PATH |IB_QP_ACCESS_FLAGS; + t[IBQPS_RTR].opt_param[RC] = IB_QP_PKEY_INDEX |IB_QP_ALT_PATH |IB_QP_ACCESS_FLAGS; + t[IBQPS_RTR].opt_param[MLX] = IB_QP_PKEY_INDEX |IB_QP_QKEY; + +/* IBQPS_RTR */ + t = &state_table[IBQPS_RTR][0]; + t[IBQPS_RESET].trans = MTHCA_TRANS_ANY2RST; + t[IBQPS_ERR].trans = MTHCA_TRANS_ANY2ERR; + + t[IBQPS_RTS].trans = MTHCA_TRANS_RTR2RTS; + t[IBQPS_RTS].req_param[UD] = IB_QP_SQ_PSN; + t[IBQPS_RTS].req_param[UC] = IB_QP_SQ_PSN; + t[IBQPS_RTS].req_param[RC] = + IB_QP_TIMEOUT |IB_QP_RETRY_CNT |IB_QP_RNR_RETRY |IB_QP_SQ_PSN |IB_QP_MAX_QP_RD_ATOMIC; + t[IBQPS_RTS].req_param[MLX] = IB_QP_SQ_PSN; + t[IBQPS_RTS].opt_param[UD] = IB_QP_CUR_STATE |IB_QP_QKEY; + t[IBQPS_RTS].opt_param[UC] = + IB_QP_CUR_STATE |IB_QP_ALT_PATH |IB_QP_ACCESS_FLAGS |IB_QP_PATH_MIG_STATE; + t[IBQPS_RTS].opt_param[RC] = IB_QP_CUR_STATE |IB_QP_ALT_PATH | + IB_QP_ACCESS_FLAGS |IB_QP_MIN_RNR_TIMER |IB_QP_PATH_MIG_STATE; + t[IBQPS_RTS].opt_param[MLX] = IB_QP_CUR_STATE |IB_QP_QKEY; + + /* IBQPS_RTS */ + t = &state_table[IBQPS_RTS][0]; + t[IBQPS_RESET].trans = MTHCA_TRANS_ANY2RST; + t[IBQPS_ERR].trans = MTHCA_TRANS_ANY2ERR; + + t[IBQPS_RTS].trans = MTHCA_TRANS_RTS2RTS; + t[IBQPS_RTS].opt_param[UD] = IB_QP_CUR_STATE |IB_QP_QKEY; + t[IBQPS_RTS].opt_param[UC] = IB_QP_ACCESS_FLAGS |IB_QP_ALT_PATH |IB_QP_PATH_MIG_STATE; + t[IBQPS_RTS].opt_param[RC] = IB_QP_ACCESS_FLAGS | + IB_QP_ALT_PATH |IB_QP_PATH_MIG_STATE |IB_QP_MIN_RNR_TIMER; + t[IBQPS_RTS].opt_param[MLX] = IB_QP_CUR_STATE |IB_QP_QKEY; + + t[IBQPS_SQD].trans = MTHCA_TRANS_RTS2SQD; + t[IBQPS_SQD].opt_param[UD] = IB_QP_EN_SQD_ASYNC_NOTIFY; + t[IBQPS_SQD].opt_param[UC] = IB_QP_EN_SQD_ASYNC_NOTIFY; + t[IBQPS_SQD].opt_param[RC] = IB_QP_EN_SQD_ASYNC_NOTIFY; + t[IBQPS_SQD].opt_param[MLX] = IB_QP_EN_SQD_ASYNC_NOTIFY; + + /* IBQPS_SQD */ + t = &state_table[IBQPS_SQD][0]; + t[IBQPS_RESET].trans = MTHCA_TRANS_ANY2RST; + t[IBQPS_ERR].trans = MTHCA_TRANS_ANY2ERR; + + t[IBQPS_RTS].trans = MTHCA_TRANS_SQD2RTS; + t[IBQPS_RTS].opt_param[UD] = IB_QP_CUR_STATE |IB_QP_QKEY; + t[IBQPS_RTS].opt_param[UC] = IB_QP_CUR_STATE | + IB_QP_ALT_PATH |IB_QP_ACCESS_FLAGS |IB_QP_PATH_MIG_STATE; + t[IBQPS_RTS].opt_param[RC] = IB_QP_CUR_STATE |IB_QP_ALT_PATH | + IB_QP_ACCESS_FLAGS |IB_QP_MIN_RNR_TIMER |IB_QP_PATH_MIG_STATE; + t[IBQPS_RTS].opt_param[MLX] = IB_QP_CUR_STATE |IB_QP_QKEY; + + t[IBQPS_SQD].trans = MTHCA_TRANS_SQD2SQD; + t[IBQPS_SQD].opt_param[UD] = IB_QP_PKEY_INDEX |IB_QP_QKEY; + t[IBQPS_SQD].opt_param[UC] = IB_QP_AV | IB_QP_CUR_STATE | + IB_QP_ALT_PATH |IB_QP_ACCESS_FLAGS |IB_QP_PKEY_INDEX |IB_QP_PATH_MIG_STATE; + t[IBQPS_SQD].opt_param[RC] = IB_QP_AV |IB_QP_TIMEOUT |IB_QP_RETRY_CNT |IB_QP_RNR_RETRY | + IB_QP_MAX_QP_RD_ATOMIC |IB_QP_MAX_DEST_RD_ATOMIC |IB_QP_CUR_STATE |IB_QP_ALT_PATH | + IB_QP_ACCESS_FLAGS |IB_QP_PKEY_INDEX |IB_QP_MIN_RNR_TIMER |IB_QP_PATH_MIG_STATE; + t[IBQPS_SQD].opt_param[MLX] = IB_QP_PKEY_INDEX |IB_QP_QKEY; + + /* IBQPS_SQE */ + t = &state_table[IBQPS_SQE][0]; + t[IBQPS_RESET].trans = MTHCA_TRANS_ANY2RST; + t[IBQPS_ERR].trans = MTHCA_TRANS_ANY2ERR; + + t[IBQPS_RTS].trans = MTHCA_TRANS_SQERR2RTS; + t[IBQPS_RTS].opt_param[UD] = IB_QP_CUR_STATE |IB_QP_QKEY; + t[IBQPS_RTS].opt_param[UC] = IB_QP_CUR_STATE | IB_QP_ACCESS_FLAGS; +// t[IBQPS_RTS].opt_param[RC] = IB_QP_CUR_STATE |IB_QP_MIN_RNR_TIMER; + t[IBQPS_RTS].opt_param[MLX] = IB_QP_CUR_STATE |IB_QP_QKEY; + + /* IBQPS_ERR */ + t = &state_table[IBQPS_ERR][0]; + t[IBQPS_RESET].trans = MTHCA_TRANS_ANY2RST; + t[IBQPS_ERR].trans = MTHCA_TRANS_ANY2ERR; + +}; + + +static int is_sqp(struct mthca_dev *dev, struct mthca_qp *qp) +{ + return qp->qpn >= (u32)dev->qp_table.sqp_start && + qp->qpn <= (u32)dev->qp_table.sqp_start + 3; +} + +static int is_qp0(struct mthca_dev *dev, struct mthca_qp *qp) +{ + return qp->qpn >= (u32)dev->qp_table.sqp_start && + qp->qpn <= (u32)(dev->qp_table.sqp_start + 1); +} + + +static void dump_wqe(u32 print_lvl, u32 *wqe_ptr , struct mthca_qp *qp_ptr) +{ + __be32 *wqe = wqe_ptr; + + UNUSED_PARAM_WOWPP(qp_ptr); + UNUSED_PARAM_WOWPP(print_lvl); + + (void) wqe; /* avoid warning if mthca_dbg compiled away... */ + HCA_PRINT(print_lvl,HCA_DBG_QP,("WQE contents QPN 0x%06x \n",qp_ptr->qpn)); + HCA_PRINT(print_lvl,HCA_DBG_QP,("WQE contents [%02x] %08x %08x %08x %08x \n",0 + , cl_ntoh32(wqe[0]), cl_ntoh32(wqe[1]), cl_ntoh32(wqe[2]), cl_ntoh32(wqe[3]))); + HCA_PRINT(print_lvl,HCA_DBG_QP,("WQE contents [%02x] %08x %08x %08x %08x \n",4 + , cl_ntoh32(wqe[4]), cl_ntoh32(wqe[5]), cl_ntoh32(wqe[6]), cl_ntoh32(wqe[7]))); + HCA_PRINT(print_lvl,HCA_DBG_QP,("WQE contents [%02x] %08x %08x %08x %08x \n",8 + , cl_ntoh32(wqe[8]), cl_ntoh32(wqe[9]), cl_ntoh32(wqe[10]), cl_ntoh32(wqe[11]))); + HCA_PRINT(print_lvl,HCA_DBG_QP,("WQE contents [%02x] %08x %08x %08x %08x \n",12 + , cl_ntoh32(wqe[12]), cl_ntoh32(wqe[13]), cl_ntoh32(wqe[14]), cl_ntoh32(wqe[15]))); + +} + + +static void *get_recv_wqe(struct mthca_qp *qp, int n) +{ + if (qp->is_direct) + return (u8*)qp->queue.direct.page + (n << qp->rq.wqe_shift); + else + return (u8*)qp->queue.page_list[(n << qp->rq.wqe_shift) >> PAGE_SHIFT].page + + ((n << qp->rq.wqe_shift) & (PAGE_SIZE - 1)); +} + +static void *get_send_wqe(struct mthca_qp *qp, int n) +{ + if (qp->is_direct) + return (u8*)qp->queue.direct.page + qp->send_wqe_offset + + (n << qp->sq.wqe_shift); + else + return (u8*)qp->queue.page_list[(qp->send_wqe_offset + + (n << qp->sq.wqe_shift)) >> + PAGE_SHIFT].page + + ((qp->send_wqe_offset + (n << qp->sq.wqe_shift)) & + (PAGE_SIZE - 1)); +} + +static void mthca_wq_init(struct mthca_wq *wq) +{ + spin_lock_init(&wq->lock); + wq->next_ind = 0; + wq->last_comp = wq->max - 1; + wq->head = 0; + wq->tail = 0; +} + +void mthca_qp_event(struct mthca_dev *dev, u32 qpn, + enum ib_event_type event_type, u8 vendor_code) +{ + struct mthca_qp *qp; + ib_event_rec_t event; + SPIN_LOCK_PREP(lh); + + spin_lock(&dev->qp_table.lock, &lh); + qp = mthca_array_get(&dev->qp_table.qp, qpn & (dev->limits.num_qps - 1)); + if (qp) + atomic_inc(&qp->refcount); + spin_unlock(&lh); + + if (!qp) { + HCA_PRINT(TRACE_LEVEL_WARNING,HCA_DBG_QP,("QP %06x Async event for bogus \n", qpn)); + return; + } + + event.type = event_type; + event.context = qp->ibqp.qp_context; + event.vendor_specific = vendor_code; + HCA_PRINT(TRACE_LEVEL_WARNING,HCA_DBG_QP,("QP %06x Async event event_type 0x%x vendor_code 0x%x\n", + qpn,event_type,vendor_code)); + qp->ibqp.event_handler(&event); + + if (atomic_dec_and_test(&qp->refcount)) + wake_up(&qp->wait); +} + +static int to_mthca_state(enum ib_qp_state ib_state) +{ + switch (ib_state) { + case IBQPS_RESET: return MTHCA_QP_STATE_RST; + case IBQPS_INIT: return MTHCA_QP_STATE_INIT; + case IBQPS_RTR: return MTHCA_QP_STATE_RTR; + case IBQPS_RTS: return MTHCA_QP_STATE_RTS; + case IBQPS_SQD: return MTHCA_QP_STATE_SQD; + case IBQPS_SQE: return MTHCA_QP_STATE_SQE; + case IBQPS_ERR: return MTHCA_QP_STATE_ERR; + default: return -1; + } +} + +static int to_mthca_st(int transport) +{ + switch (transport) { + case RC: return MTHCA_QP_ST_RC; + case UC: return MTHCA_QP_ST_UC; + case UD: return MTHCA_QP_ST_UD; + case RD: return MTHCA_QP_ST_RD; + case MLX: return MTHCA_QP_ST_MLX; + default: return -1; + } +} + +static inline enum ib_qp_state to_ib_qp_state(int mthca_state) +{ + switch (mthca_state) { + case MTHCA_QP_STATE_RST: return IBQPS_RESET; + case MTHCA_QP_STATE_INIT: return IBQPS_INIT; + case MTHCA_QP_STATE_RTR: return IBQPS_RTR; + case MTHCA_QP_STATE_RTS: return IBQPS_RTS; + case MTHCA_QP_STATE_SQD: return IBQPS_SQD; + case MTHCA_QP_STATE_DRAINING: return IBQPS_SQD; + case MTHCA_QP_STATE_SQE: return IBQPS_SQE; + case MTHCA_QP_STATE_ERR: return IBQPS_ERR; + default: return -1; + } +} + +static inline enum ib_mig_state to_ib_mig_state(int mthca_mig_state) +{ + switch (mthca_mig_state) { + case 0: return IB_MIG_ARMED; + case 1: return IB_MIG_REARM; + case 3: return IB_MIG_MIGRATED; + default: return -1; + } +} + +static int to_ib_qp_access_flags(int mthca_flags) +{ + int ib_flags = 0; + + if (mthca_flags & MTHCA_QP_BIT_RRE) + ib_flags |= MTHCA_ACCESS_REMOTE_READ; + if (mthca_flags & MTHCA_QP_BIT_RWE) + ib_flags |= MTHCA_ACCESS_REMOTE_WRITE; + if (mthca_flags & MTHCA_QP_BIT_RAE) + ib_flags |= MTHCA_ACCESS_REMOTE_ATOMIC; + + return ib_flags; +} + +static void to_ib_ah_attr(struct mthca_dev *dev, struct ib_ah_attr *ib_ah_attr, + struct mthca_qp_path *path) +{ + memset(ib_ah_attr, 0, sizeof *ib_ah_attr); + ib_ah_attr->port_num = (u8)((cl_ntoh32(path->port_pkey) >> 24) & 0x3); + + if (ib_ah_attr->port_num == 0 || ib_ah_attr->port_num > dev->limits.num_ports) + return; + + ib_ah_attr->dlid = cl_ntoh16(path->rlid); + ib_ah_attr->sl = (u8)(cl_ntoh32(path->sl_tclass_flowlabel) >> 28); + ib_ah_attr->src_path_bits = path->g_mylmc & 0x7f; + //TODO: work around: set always full speed - really, it's much more complicate + ib_ah_attr->static_rate = 0; + ib_ah_attr->ah_flags = (path->g_mylmc & (1 << 7)) ? IB_AH_GRH : 0; + if (ib_ah_attr->ah_flags) { + ib_ah_attr->grh.sgid_index = (u8)(path->mgid_index & (dev->limits.gid_table_len - 1)); + ib_ah_attr->grh.hop_limit = path->hop_limit; + ib_ah_attr->grh.traffic_class = + (u8)((cl_ntoh32(path->sl_tclass_flowlabel) >> 20) & 0xff); + ib_ah_attr->grh.flow_label = + cl_ntoh32(path->sl_tclass_flowlabel) & 0xfffff; + memcpy(ib_ah_attr->grh.dgid.raw, + path->rgid, sizeof ib_ah_attr->grh.dgid.raw); + } +} + +int mthca_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr_mask, + struct ib_qp_init_attr *qp_init_attr) +{ + struct mthca_dev *dev = to_mdev(ibqp->device); + struct mthca_qp *qp = to_mqp(ibqp); + int err = 0; + struct mthca_mailbox *mailbox = NULL; + struct mthca_qp_param *qp_param; + struct mthca_qp_context *context; + int mthca_state; + u8 status; + + UNUSED_PARAM(qp_attr_mask); + + down( &qp->mutex ); + + if (qp->state == IBQPS_RESET) { + qp_attr->qp_state = IBQPS_RESET; + goto done; + } + + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (IS_ERR(mailbox)) { + err = PTR_ERR(mailbox); + goto out; + } + + err = mthca_QUERY_QP(dev, qp->qpn, 0, mailbox, &status); + if (err) + goto out_mailbox; + if (status) { + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_QP, + ("QUERY_QP returned status %02x\n", status)); + err = -EINVAL; + goto out_mailbox; + } + + qp_param = mailbox->buf; + context = &qp_param->context; + mthca_state = cl_ntoh32(context->flags) >> 28; + + qp->state = to_ib_qp_state(mthca_state); + qp_attr->qp_state = qp->state; + qp_attr->path_mtu = context->mtu_msgmax >> 5; + qp_attr->path_mig_state = + to_ib_mig_state((cl_ntoh32(context->flags) >> 11) & 0x3); + qp_attr->qkey = cl_ntoh32(context->qkey); + qp_attr->rq_psn = cl_ntoh32(context->rnr_nextrecvpsn) & 0xffffff; + qp_attr->sq_psn = cl_ntoh32(context->next_send_psn) & 0xffffff; + qp_attr->dest_qp_num = cl_ntoh32(context->remote_qpn) & 0xffffff; + qp_attr->qp_access_flags = + to_ib_qp_access_flags(cl_ntoh32(context->params2)); + + if (qp->transport == RC || qp->transport == UC) { + to_ib_ah_attr(dev, &qp_attr->ah_attr, &context->pri_path); + to_ib_ah_attr(dev, &qp_attr->alt_ah_attr, &context->alt_path); + qp_attr->alt_pkey_index = + (u16)(cl_ntoh32(context->alt_path.port_pkey) & 0x7f); + qp_attr->alt_port_num = qp_attr->alt_ah_attr.port_num; + } + + qp_attr->pkey_index = (u16)(cl_ntoh32(context->pri_path.port_pkey) & 0x7f); + qp_attr->port_num = + (u8)((cl_ntoh32(context->pri_path.port_pkey) >> 24) & 0x3); + + /* qp_attr->en_sqd_async_notify is only applicable in modify qp */ + qp_attr->sq_draining = (u8)(mthca_state == MTHCA_QP_STATE_DRAINING); + + qp_attr->max_rd_atomic = (u8)(1 << ((cl_ntoh32(context->params1) >> 21) & 0x7)); + + qp_attr->max_dest_rd_atomic = + (u8)(1 << ((cl_ntoh32(context->params2) >> 21) & 0x7)); + qp_attr->min_rnr_timer = + (u8)((cl_ntoh32(context->rnr_nextrecvpsn) >> 24) & 0x1f); + qp_attr->timeout = context->pri_path.ackto >> 3; + qp_attr->retry_cnt = (u8)((cl_ntoh32(context->params1) >> 16) & 0x7); + qp_attr->rnr_retry = context->pri_path.rnr_retry >> 5; + qp_attr->alt_timeout = context->alt_path.ackto >> 3; + +done: + qp_attr->cur_qp_state = qp_attr->qp_state; + qp_attr->cap.max_send_wr = qp->sq.max; + qp_attr->cap.max_recv_wr = qp->rq.max; + qp_attr->cap.max_send_sge = qp->sq.max_gs; + qp_attr->cap.max_recv_sge = qp->rq.max_gs; + qp_attr->cap.max_inline_data = qp->max_inline_data; + + qp_init_attr->cap = qp_attr->cap; + +out_mailbox: + mthca_free_mailbox(dev, mailbox); + +out: + up(&qp->mutex); + return err; +} + +static void store_attrs(struct mthca_sqp *sqp, struct ib_qp_attr *attr, + int attr_mask) +{ + if (attr_mask & IB_QP_PKEY_INDEX) + sqp->pkey_index = attr->pkey_index; + if (attr_mask & IB_QP_QKEY) + sqp->qkey = attr->qkey; + if (attr_mask & IB_QP_SQ_PSN) + sqp->send_psn = attr->sq_psn; +} + +static void init_port(struct mthca_dev *dev, int port) +{ + int err; + u8 status; + struct mthca_init_ib_param param; + + RtlZeroMemory(¶m, sizeof param); + + param.port_width = dev->limits.port_width_cap; + param.vl_cap = dev->limits.vl_cap; + param.mtu_cap = dev->limits.mtu_cap; + param.gid_cap = (u16)dev->limits.gid_table_len; + param.pkey_cap = (u16)dev->limits.pkey_table_len; + + err = mthca_INIT_IB(dev, ¶m, port, &status); + if (err) + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_QP ,("INIT_IB failed, return code %d.\n", err)); + if (status) + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_QP ,("INIT_IB returned status %02x.\n", status)); +} + + +static __be32 get_hw_access_flags(struct mthca_qp *qp, struct ib_qp_attr *attr, + int attr_mask) +{ + u8 dest_rd_atomic; + u32 access_flags; + u32 hw_access_flags = 0; + + if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) + dest_rd_atomic = attr->max_dest_rd_atomic; + else + dest_rd_atomic = qp->resp_depth; + + if (attr_mask & IB_QP_ACCESS_FLAGS) + access_flags = attr->qp_access_flags; + else + access_flags = qp->atomic_rd_en; + + if (!dest_rd_atomic) + access_flags &= MTHCA_ACCESS_REMOTE_WRITE; + + if (access_flags & MTHCA_ACCESS_REMOTE_READ) + hw_access_flags |= MTHCA_QP_BIT_RRE; + if (access_flags & MTHCA_ACCESS_REMOTE_ATOMIC) + hw_access_flags |= MTHCA_QP_BIT_RAE; + if (access_flags & MTHCA_ACCESS_REMOTE_WRITE) + hw_access_flags |= MTHCA_QP_BIT_RWE; + + return cl_hton32(hw_access_flags); +} + +int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask) +{ + struct mthca_dev *dev = to_mdev(ibqp->device); + struct mthca_qp *qp = to_mqp(ibqp); + enum ib_qp_state cur_state, new_state; + struct mthca_mailbox *mailbox; + struct mthca_qp_param *qp_param; + struct mthca_qp_context *qp_context; + u32 req_param, opt_param; + u32 sqd_event = 0; + u8 status; + int err = -EINVAL; + SPIN_LOCK_PREP(lhs); + SPIN_LOCK_PREP(lhr); + + down( &qp->mutex ); + + if (attr_mask & IB_QP_CUR_STATE) { + if (attr->cur_qp_state != IBQPS_RTR && + attr->cur_qp_state != IBQPS_RTS && + attr->cur_qp_state != IBQPS_SQD && + attr->cur_qp_state != IBQPS_SQE) + goto out; + else + cur_state = attr->cur_qp_state; + } else { + spin_lock_irq(&qp->sq.lock, &lhs); + spin_lock(&qp->rq.lock, &lhr); + cur_state = qp->state; + spin_unlock(&lhr); + spin_unlock_irq(&lhs); + } + + if (attr_mask & IB_QP_STATE) { + if (attr->qp_state < 0 || attr->qp_state > IBQPS_ERR) + goto out; + new_state = attr->qp_state; + } else + new_state = cur_state; + + if (state_table[cur_state][new_state].trans == MTHCA_TRANS_INVALID) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_QP,("Illegal QP transition " + "%d->%d\n", cur_state, new_state)); + goto out; + } + + req_param = state_table[cur_state][new_state].req_param[qp->transport]; + opt_param = state_table[cur_state][new_state].opt_param[qp->transport]; + + if ((req_param & attr_mask) != req_param) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_QP,("QP transition " + "%d->%d missing req attr 0x%08x\n", + cur_state, new_state, + req_param & ~attr_mask)); + //NB: IBAL doesn't use all the fields, so we can miss some mandatory flags + goto out; + } + + if (attr_mask & ~(req_param | opt_param | IB_QP_STATE)) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_QP,("QP transition (transport %d) " + "%d->%d has extra attr 0x%08x\n", + qp->transport, + cur_state, new_state, + attr_mask & ~(req_param | opt_param | + IB_QP_STATE))); + //NB: The old code sometimes uses optional flags that are not so in this code + goto out; + } + + if ((attr_mask & IB_QP_PKEY_INDEX) && + attr->pkey_index >= dev->limits.pkey_table_len) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_QP,("PKey index (%u) too large. max is %d\n", + attr->pkey_index,dev->limits.pkey_table_len-1)); + goto out; + } + + if ((attr_mask & IB_QP_PORT) && + (attr->port_num == 0 || attr->port_num > dev->limits.num_ports)) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_QP,("Port number (%u) is invalid\n", attr->port_num)); + goto out; + } + + if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC && + attr->max_rd_atomic > dev->limits.max_qp_init_rdma) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_QP,("Max rdma_atomic as initiator %u too large (max is %d)\n", + attr->max_rd_atomic, dev->limits.max_qp_init_rdma)); + goto out; + } + + if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC && + attr->max_dest_rd_atomic > 1 << dev->qp_table.rdb_shift) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_QP,("Max rdma_atomic as responder %u too large (max %d)\n", + attr->max_dest_rd_atomic, 1 << dev->qp_table.rdb_shift)); + goto out; + } + + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (IS_ERR(mailbox)) { + err = PTR_ERR(mailbox); + goto out; + } + qp_param = mailbox->buf; + qp_context = &qp_param->context; + RtlZeroMemory(qp_param, sizeof *qp_param); + + qp_context->flags = cl_hton32((to_mthca_state(new_state) << 28) | + (to_mthca_st(qp->transport) << 16)); + qp_context->flags |= cl_hton32(MTHCA_QP_BIT_DE); + if (!(attr_mask & IB_QP_PATH_MIG_STATE)) + qp_context->flags |= cl_hton32(MTHCA_QP_PM_MIGRATED << 11); + else { + qp_param->opt_param_mask |= cl_hton32(MTHCA_QP_OPTPAR_PM_STATE); + switch (attr->path_mig_state) { + case IB_APM_MIGRATED: + qp_context->flags |= cl_hton32(MTHCA_QP_PM_MIGRATED << 11); + break; + case IB_APM_REARM: + qp_context->flags |= cl_hton32(MTHCA_QP_PM_REARM << 11); + break; + case IB_APM_ARMED: + qp_context->flags |= cl_hton32(MTHCA_QP_PM_ARMED << 11); + break; + } + } + + /* leave tavor_sched_queue as 0 */ + + if (qp->transport == MLX || qp->transport == UD) + qp_context->mtu_msgmax = (IB_MTU_LEN_2048 << 5) | 11; + else if (attr_mask & IB_QP_PATH_MTU) { + if (attr->path_mtu < IB_MTU_LEN_256 || attr->path_mtu > IB_MTU_LEN_2048) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_QP, + ("path MTU (%u) is invalid\n", attr->path_mtu)); + goto out_mailbox; + } + qp_context->mtu_msgmax = (u8)((attr->path_mtu << 5) | 31); + } + + if (mthca_is_memfree(dev)) { + if (qp->rq.max) + qp_context->rq_size_stride = (u8)(long_log2(qp->rq.max) << 3); + qp_context->rq_size_stride |= qp->rq.wqe_shift - 4; + + if (qp->sq.max) + qp_context->sq_size_stride = (u8)(long_log2(qp->sq.max) << 3); + qp_context->sq_size_stride |= qp->sq.wqe_shift - 4; + } + + /* leave arbel_sched_queue as 0 */ + + if (qp->ibqp.ucontext) + qp_context->usr_page = + cl_hton32(to_mucontext(qp->ibqp.ucontext)->uar.index); + else + qp_context->usr_page = cl_hton32(dev->driver_uar.index); + qp_context->local_qpn = cl_hton32(qp->qpn); + if (attr_mask & IB_QP_DEST_QPN) { + qp_context->remote_qpn = cl_hton32(attr->dest_qp_num); + } + + if (qp->transport == MLX) + qp_context->pri_path.port_pkey |= + cl_hton32(to_msqp(qp)->port << 24); + else { + if (attr_mask & IB_QP_PORT) { + qp_context->pri_path.port_pkey |= + cl_hton32(attr->port_num << 24); + qp_param->opt_param_mask |= cl_hton32(MTHCA_QP_OPTPAR_PORT_NUM); + } + } + + if (attr_mask & IB_QP_PKEY_INDEX) { + qp_context->pri_path.port_pkey |= + cl_hton32(attr->pkey_index); + qp_param->opt_param_mask |= cl_hton32(MTHCA_QP_OPTPAR_PKEY_INDEX); + } + + if (attr_mask & IB_QP_RNR_RETRY) { + qp_context->pri_path.rnr_retry = attr->rnr_retry << 5; + qp_param->opt_param_mask |= cl_hton32(MTHCA_QP_OPTPAR_RNR_RETRY); + } + + if (attr_mask & IB_QP_AV) { + qp_context->pri_path.g_mylmc = attr->ah_attr.src_path_bits & 0x7f; + qp_context->pri_path.rlid = cl_hton16(attr->ah_attr.dlid); + //TODO: work around: set always full speed - really, it's much more complicate + qp_context->pri_path.static_rate = 0; + if (attr->ah_attr.ah_flags & IB_AH_GRH) { + qp_context->pri_path.g_mylmc |= 1 << 7; + qp_context->pri_path.mgid_index = attr->ah_attr.grh.sgid_index; + qp_context->pri_path.hop_limit = attr->ah_attr.grh.hop_limit; + qp_context->pri_path.sl_tclass_flowlabel = + cl_hton32((attr->ah_attr.sl << 28) | + (attr->ah_attr.grh.traffic_class << 20) | + (attr->ah_attr.grh.flow_label)); + memcpy(qp_context->pri_path.rgid, + attr->ah_attr.grh.dgid.raw, 16); + } else { + qp_context->pri_path.sl_tclass_flowlabel = + cl_hton32(attr->ah_attr.sl << 28); + } + qp_param->opt_param_mask |= cl_hton32(MTHCA_QP_OPTPAR_PRIMARY_ADDR_PATH); + } + + if (attr_mask & IB_QP_TIMEOUT) { + qp_context->pri_path.ackto = attr->timeout << 3; + qp_param->opt_param_mask |= cl_hton32(MTHCA_QP_OPTPAR_ACK_TIMEOUT); + } + + /* XXX alt_path */ + + /* leave rdd as 0 */ + qp_context->pd = cl_hton32(to_mpd(ibqp->pd)->pd_num); + /* leave wqe_base as 0 (we always create an MR based at 0 for WQs) */ + qp_context->wqe_lkey = cl_hton32(qp->mr.ibmr.lkey); + qp_context->params1 = cl_hton32((unsigned long)( + (MTHCA_ACK_REQ_FREQ << 28) | + (MTHCA_FLIGHT_LIMIT << 24) | + MTHCA_QP_BIT_SWE)); + if (qp->sq_policy == IB_SIGNAL_ALL_WR) + qp_context->params1 |= cl_hton32(MTHCA_QP_BIT_SSC); + if (attr_mask & IB_QP_RETRY_CNT) { + qp_context->params1 |= cl_hton32(attr->retry_cnt << 16); + qp_param->opt_param_mask |= cl_hton32(MTHCA_QP_OPTPAR_RETRY_COUNT); + } + + if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC) { + if (attr->max_rd_atomic) { + qp_context->params1 |= + cl_hton32(MTHCA_QP_BIT_SRE | + MTHCA_QP_BIT_SAE); + qp_context->params1 |= + cl_hton32(fls(attr->max_rd_atomic - 1) << 21); + } + qp_param->opt_param_mask |= cl_hton32(MTHCA_QP_OPTPAR_SRA_MAX); + } + + if (attr_mask & IB_QP_SQ_PSN) + qp_context->next_send_psn = cl_hton32(attr->sq_psn); + qp_context->cqn_snd = cl_hton32(to_mcq(ibqp->send_cq)->cqn); + + if (mthca_is_memfree(dev)) { + qp_context->snd_wqe_base_l = cl_hton32(qp->send_wqe_offset); + qp_context->snd_db_index = cl_hton32(qp->sq.db_index); + } + + if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) { + + if (attr->max_dest_rd_atomic) + qp_context->params2 |= + cl_hton32(fls(attr->max_dest_rd_atomic - 1) << 21); + + qp_param->opt_param_mask |= cl_hton32(MTHCA_QP_OPTPAR_RRA_MAX); + + } + + if (attr_mask & (IB_QP_ACCESS_FLAGS | IB_QP_MAX_DEST_RD_ATOMIC)) { + qp_context->params2 |= get_hw_access_flags(qp, attr, attr_mask); + qp_param->opt_param_mask |= cl_hton32(MTHCA_QP_OPTPAR_RWE | + MTHCA_QP_OPTPAR_RRE | + MTHCA_QP_OPTPAR_RAE); + } + + qp_context->params2 |= cl_hton32(MTHCA_QP_BIT_RSC); + + if (ibqp->srq) + qp_context->params2 |= cl_hton32(MTHCA_QP_BIT_RIC); + + if (attr_mask & IB_QP_MIN_RNR_TIMER) { + qp_context->rnr_nextrecvpsn |= cl_hton32(attr->min_rnr_timer << 24); + qp_param->opt_param_mask |= cl_hton32(MTHCA_QP_OPTPAR_RNR_TIMEOUT); + } + if (attr_mask & IB_QP_RQ_PSN) + qp_context->rnr_nextrecvpsn |= cl_hton32(attr->rq_psn); + + qp_context->ra_buff_indx = + cl_hton32(dev->qp_table.rdb_base + + ((qp->qpn & (dev->limits.num_qps - 1)) * MTHCA_RDB_ENTRY_SIZE << + dev->qp_table.rdb_shift)); + + qp_context->cqn_rcv = cl_hton32(to_mcq(ibqp->recv_cq)->cqn); + + if (mthca_is_memfree(dev)) + qp_context->rcv_db_index = cl_hton32(qp->rq.db_index); + + if (attr_mask & IB_QP_QKEY) { + qp_context->qkey = cl_hton32(attr->qkey); + qp_param->opt_param_mask |= cl_hton32(MTHCA_QP_OPTPAR_Q_KEY); + } + + if (ibqp->srq) + qp_context->srqn = cl_hton32(1 << 24 | + to_msrq(ibqp->srq)->srqn); + + if (cur_state == IBQPS_RTS && new_state == IBQPS_SQD && + attr_mask & IB_QP_EN_SQD_ASYNC_NOTIFY && + attr->en_sqd_async_notify) + sqd_event = (u32)(1 << 31); + + err = mthca_MODIFY_QP(dev, state_table[cur_state][new_state].trans, + qp->qpn, 0, mailbox, sqd_event, &status); + if (err) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_QP,("mthca_MODIFY_QP returned error (qp-num = 0x%x) returned status %02x " + "cur_state = %d new_state = %d attr_mask = %d req_param = %d opt_param = %d\n", + ibqp->qp_num, status, cur_state, new_state, + attr_mask, req_param, opt_param)); + goto out_mailbox; + } + if (status) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_QP,("mthca_MODIFY_QP bad status(qp-num = 0x%x) returned status %02x " + "cur_state = %d new_state = %d attr_mask = %d req_param = %d opt_param = %d\n", + ibqp->qp_num, status, cur_state, new_state, + attr_mask, req_param, opt_param)); + err = -EINVAL; + goto out_mailbox; + } + + qp->state = new_state; + if (attr_mask & IB_QP_ACCESS_FLAGS) + qp->atomic_rd_en = (u8)attr->qp_access_flags; + if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) + qp->resp_depth = attr->max_dest_rd_atomic; + + if (is_sqp(dev, qp)) + store_attrs(to_msqp(qp), attr, attr_mask); + + /* + * If we moved QP0 to RTR, bring the IB link up; if we moved + * QP0 to RESET or ERROR, bring the link back down. + */ + if (is_qp0(dev, qp)) { + if (cur_state != IBQPS_RTR && + new_state == IBQPS_RTR) + init_port(dev, to_msqp(qp)->port); + + if (cur_state != IBQPS_RESET && + cur_state != IBQPS_ERR && + (new_state == IBQPS_RESET || + new_state == IBQPS_ERR)) + mthca_CLOSE_IB(dev, to_msqp(qp)->port, &status); + } + + /* + * If we moved a kernel QP to RESET, clean up all old CQ + * entries and reinitialize the QP. + */ + if (new_state == IBQPS_RESET && !qp->ibqp.ucontext) { + mthca_cq_clean(dev, to_mcq(qp->ibqp.send_cq)->cqn, qp->qpn, + qp->ibqp.srq ? to_msrq(qp->ibqp.srq) : NULL); + if (qp->ibqp.send_cq != qp->ibqp.recv_cq) + mthca_cq_clean(dev, to_mcq(qp->ibqp.recv_cq)->cqn, qp->qpn, + qp->ibqp.srq ? to_msrq(qp->ibqp.srq) : NULL); + + mthca_wq_init(&qp->sq); + qp->sq.last = get_send_wqe(qp, qp->sq.max - 1); + mthca_wq_init(&qp->rq); + qp->rq.last = get_recv_wqe(qp, qp->rq.max - 1); + + if (mthca_is_memfree(dev)) { + *qp->sq.db = 0; + *qp->rq.db = 0; + } + } + +out_mailbox: + mthca_free_mailbox(dev, mailbox); + +out: + up( &qp->mutex ); + return err; +} + +static int mthca_max_data_size(struct mthca_dev *dev, struct mthca_qp *qp, int desc_sz) +{ + + /* + * Calculate the maximum size of WQE s/g segments, excluding + * the next segment and other non-data segments. + */ + int max_data_size = desc_sz - sizeof (struct mthca_next_seg); + + switch (qp->transport) { + case MLX: + max_data_size -= 2 * sizeof (struct mthca_data_seg); + break; + + case UD: + if (mthca_is_memfree(dev)) + max_data_size -= sizeof (struct mthca_arbel_ud_seg); + else + max_data_size -= sizeof (struct mthca_tavor_ud_seg); + break; + + default: + max_data_size -= sizeof (struct mthca_raddr_seg); + break; + } + return max_data_size; +} + +static inline int mthca_max_inline_data(int max_data_size) +{ + return max_data_size - MTHCA_INLINE_HEADER_SIZE ; +} + +static void mthca_adjust_qp_caps(struct mthca_dev *dev, + struct mthca_qp *qp) +{ + int max_data_size = mthca_max_data_size(dev, qp, + min(dev->limits.max_desc_sz, 1 << qp->sq.wqe_shift)); + + qp->max_inline_data = mthca_max_inline_data( max_data_size); + + qp->sq.max_gs = min(dev->limits.max_sg, + (int)(max_data_size / sizeof (struct mthca_data_seg))); + qp->rq.max_gs = min(dev->limits.max_sg, + (int)((min(dev->limits.max_desc_sz, 1 << qp->rq.wqe_shift) - + sizeof (struct mthca_next_seg)) / sizeof (struct mthca_data_seg))); +} + +/* + * Allocate and register buffer for WQEs. qp->rq.max, sq.max, + * rq.max_gs and sq.max_gs must all be assigned. + * mthca_alloc_wqe_buf will calculate rq.wqe_shift and + * sq.wqe_shift (as well as send_wqe_offset, is_direct, and + * queue) + */ +static int mthca_alloc_wqe_buf(struct mthca_dev *dev, + struct mthca_pd *pd, + struct mthca_qp *qp) +{ + int size; + int err = -ENOMEM; + + HCA_ENTER(HCA_DBG_QP); + size = sizeof (struct mthca_next_seg) + + qp->rq.max_gs * sizeof (struct mthca_data_seg); + + if (size > dev->limits.max_desc_sz) + return -EINVAL; + + for (qp->rq.wqe_shift = 6; 1 << qp->rq.wqe_shift < size; + qp->rq.wqe_shift++) + ; /* nothing */ + + size = qp->sq.max_gs * sizeof (struct mthca_data_seg); + switch (qp->transport) { + case MLX: + size += 2 * sizeof (struct mthca_data_seg); + break; + + case UD: + size += mthca_is_memfree(dev) ? + sizeof (struct mthca_arbel_ud_seg) : + sizeof (struct mthca_tavor_ud_seg); + break; + + case UC: + size += sizeof (struct mthca_raddr_seg); + break; + + case RC: + size += sizeof (struct mthca_raddr_seg); + /* + * An atomic op will require an atomic segment, a + * remote address segment and one scatter entry. + */ + size = max(size, + sizeof (struct mthca_atomic_seg) + + sizeof (struct mthca_raddr_seg) + + sizeof (struct mthca_data_seg)); + break; + + default: + break; + } + + /* Make sure that we have enough space for a bind request */ + size = max(size, sizeof (struct mthca_bind_seg)); + + size += sizeof (struct mthca_next_seg); + + if (size > dev->limits.max_desc_sz) + return -EINVAL; + + for (qp->sq.wqe_shift = 6; 1 << qp->sq.wqe_shift < size; + qp->sq.wqe_shift++) + ; /* nothing */ + + qp->send_wqe_offset = ALIGN(qp->rq.max << qp->rq.wqe_shift, + 1 << qp->sq.wqe_shift); + + /* + * If this is a userspace QP, we don't actually have to + * allocate anything. All we need is to calculate the WQE + * sizes and the send_wqe_offset, so we're done now. + */ + if (pd->ibpd.ucontext) + return 0; + + size = (int)(LONG_PTR)NEXT_PAGE_ALIGN(qp->send_wqe_offset + + (qp->sq.max << qp->sq.wqe_shift)); + + qp->wrid = kmalloc((qp->rq.max + qp->sq.max) * sizeof (u64), + GFP_KERNEL); + if (!qp->wrid) + goto err_out; + + err = mthca_buf_alloc(dev, size, MTHCA_MAX_DIRECT_QP_SIZE, + &qp->queue, &qp->is_direct, pd, 0, &qp->mr); + if (err) + goto err_out; + + HCA_EXIT(HCA_DBG_QP); + return 0; + +err_out: + kfree(qp->wrid); + return err; +} + +static void mthca_free_wqe_buf(struct mthca_dev *dev, + struct mthca_qp *qp) +{ + mthca_buf_free(dev, (int)(LONG_PTR)NEXT_PAGE_ALIGN(qp->send_wqe_offset + + (qp->sq.max << qp->sq.wqe_shift)), + &qp->queue, qp->is_direct, &qp->mr); + kfree(qp->wrid); +} + +static int mthca_map_memfree(struct mthca_dev *dev, + struct mthca_qp *qp) +{ + int ret; + + if (mthca_is_memfree(dev)) { + ret = mthca_table_get(dev, dev->qp_table.qp_table, qp->qpn); + if (ret) + return ret; + + ret = mthca_table_get(dev, dev->qp_table.eqp_table, qp->qpn); + if (ret) + goto err_qpc; + + ret = mthca_table_get(dev, dev->qp_table.rdb_table, + qp->qpn << dev->qp_table.rdb_shift); + if (ret) + goto err_eqpc; + + } + + return 0; + +err_eqpc: + mthca_table_put(dev, dev->qp_table.eqp_table, qp->qpn); + +err_qpc: + mthca_table_put(dev, dev->qp_table.qp_table, qp->qpn); + + return ret; +} + +static void mthca_unmap_memfree(struct mthca_dev *dev, + struct mthca_qp *qp) +{ + mthca_table_put(dev, dev->qp_table.rdb_table, + qp->qpn << dev->qp_table.rdb_shift); + mthca_table_put(dev, dev->qp_table.eqp_table, qp->qpn); + mthca_table_put(dev, dev->qp_table.qp_table, qp->qpn); +} + +static int mthca_alloc_memfree(struct mthca_dev *dev, + struct mthca_qp *qp) +{ + int ret = 0; + + if (mthca_is_memfree(dev)) { + qp->rq.db_index = mthca_alloc_db(dev, MTHCA_DB_TYPE_RQ, + qp->qpn, &qp->rq.db); + if (qp->rq.db_index < 0) + return qp->rq.db_index; + + qp->sq.db_index = mthca_alloc_db(dev, MTHCA_DB_TYPE_SQ, + qp->qpn, &qp->sq.db); + if (qp->sq.db_index < 0){ + mthca_free_db(dev, MTHCA_DB_TYPE_RQ, qp->rq.db_index); + return qp->sq.db_index; + } + + } + + return ret; +} + +static void mthca_free_memfree(struct mthca_dev *dev, + struct mthca_qp *qp) +{ + if (mthca_is_memfree(dev)) { + mthca_free_db(dev, MTHCA_DB_TYPE_SQ, qp->sq.db_index); + mthca_free_db(dev, MTHCA_DB_TYPE_RQ, qp->rq.db_index); + } +} + +static int mthca_alloc_qp_common(struct mthca_dev *dev, + struct mthca_pd *pd, + struct mthca_cq *send_cq, + struct mthca_cq *recv_cq, + enum ib_sig_type send_policy, + struct mthca_qp *qp) +{ + int ret; + int i; + + atomic_set(&qp->refcount, 1); + init_waitqueue_head(&qp->wait); + KeInitializeMutex(&qp->mutex, 0); + + qp->state = IBQPS_RESET; + qp->atomic_rd_en = 0; + qp->resp_depth = 0; + qp->sq_policy = send_policy; + mthca_wq_init(&qp->sq); + mthca_wq_init(&qp->rq); + + UNREFERENCED_PARAMETER(send_cq); + UNREFERENCED_PARAMETER(recv_cq); + + ret = mthca_map_memfree(dev, qp); + if (ret) + return ret; + + ret = mthca_alloc_wqe_buf(dev, pd, qp); + if (ret) { + mthca_unmap_memfree(dev, qp); + return ret; + } + + mthca_adjust_qp_caps(dev, qp); + + /* + * If this is a userspace QP, we're done now. The doorbells + * will be allocated and buffers will be initialized in + * userspace. + */ + if (pd->ibpd.ucontext) + return 0; + + ret = mthca_alloc_memfree(dev, qp); + if (ret) { + mthca_free_wqe_buf(dev, qp); + mthca_unmap_memfree(dev, qp); + return ret; + } + + if (mthca_is_memfree(dev)) { + struct mthca_next_seg *next; + struct mthca_data_seg *scatter; + int size = (sizeof (struct mthca_next_seg) + + qp->rq.max_gs * sizeof (struct mthca_data_seg)) / 16; + + for (i = 0; i < qp->rq.max; ++i) { + next = get_recv_wqe(qp, i); + next->nda_op = cl_hton32(((i + 1) & (qp->rq.max - 1)) << + qp->rq.wqe_shift); + next->ee_nds = cl_hton32(size); + + for (scatter = (void *) (next + 1); + (void *) scatter < (void *) ((u8*)next + (u32)(1 << qp->rq.wqe_shift)); + ++scatter) + scatter->lkey = cl_hton32(MTHCA_INVAL_LKEY); + } + + for (i = 0; i < qp->sq.max; ++i) { + next = get_send_wqe(qp, i); + next->nda_op = cl_hton32((((i + 1) & (qp->sq.max - 1)) << + qp->sq.wqe_shift) + + qp->send_wqe_offset); + } + } + + qp->sq.last = get_send_wqe(qp, qp->sq.max - 1); + qp->rq.last = get_recv_wqe(qp, qp->rq.max - 1); + + return 0; +} + +static int mthca_set_qp_size(struct mthca_dev *dev, struct ib_qp_cap *cap, + struct mthca_qp *qp) +{ + int max_data_size = mthca_max_data_size(dev, qp, dev->limits.max_desc_sz); + + /* Sanity check QP size before proceeding */ + if (cap->max_send_wr > (u32)dev->limits.max_wqes || + cap->max_recv_wr > (u32)dev->limits.max_wqes || + cap->max_send_sge > (u32)dev->limits.max_sg || + cap->max_recv_sge > (u32)dev->limits.max_sg || + cap->max_inline_data > (u32)mthca_max_inline_data(max_data_size)) + return -EINVAL; + + /* + * For MLX transport we need 2 extra S/G entries: + * one for the header and one for the checksum at the end + */ + if (qp->transport == MLX && cap->max_recv_sge + 2 > (u32)dev->limits.max_sg) + return -EINVAL; + + /* Enable creating zero-sized QPs */ + if (!cap->max_recv_wr) + cap->max_recv_wr = 1; + if (!cap->max_send_wr) + cap->max_send_wr = 1; + + if (mthca_is_memfree(dev)) { + qp->rq.max = cap->max_recv_wr ? + roundup_pow_of_two(cap->max_recv_wr) : 0; + qp->sq.max = cap->max_send_wr ? + roundup_pow_of_two(cap->max_send_wr) : 0; + } else { + qp->rq.max = cap->max_recv_wr; + qp->sq.max = cap->max_send_wr; + } + + qp->rq.max_gs = cap->max_recv_sge; + qp->sq.max_gs = MAX(cap->max_send_sge, + ALIGN(cap->max_inline_data + MTHCA_INLINE_HEADER_SIZE, + MTHCA_INLINE_CHUNK_SIZE) / + (int)sizeof (struct mthca_data_seg)); + + return 0; +} + +int mthca_alloc_qp(struct mthca_dev *dev, + struct mthca_pd *pd, + struct mthca_cq *send_cq, + struct mthca_cq *recv_cq, + enum ib_qp_type_t type, + enum ib_sig_type send_policy, + struct ib_qp_cap *cap, + struct mthca_qp *qp) +{ + int err; + SPIN_LOCK_PREP(lh); + + switch (type) { + case IB_QPT_RELIABLE_CONN: qp->transport = RC; break; + case IB_QPT_UNRELIABLE_CONN: qp->transport = UC; break; + case IB_QPT_UNRELIABLE_DGRM: qp->transport = UD; break; + default: return -EINVAL; + } + + err = mthca_set_qp_size(dev, cap, qp); + if (err) + return err; + + qp->qpn = mthca_alloc(&dev->qp_table.alloc); + if (qp->qpn == -1) + return -ENOMEM; + + err = mthca_alloc_qp_common(dev, pd, send_cq, recv_cq, + send_policy, qp); + if (err) { + mthca_free(&dev->qp_table.alloc, qp->qpn); + return err; + } + + spin_lock_irq(&dev->qp_table.lock, &lh); + mthca_array_set(&dev->qp_table.qp, + qp->qpn & (dev->limits.num_qps - 1), qp); + spin_unlock_irq(&lh); + + return 0; +} + +int mthca_alloc_sqp(struct mthca_dev *dev, + struct mthca_pd *pd, + struct mthca_cq *send_cq, + struct mthca_cq *recv_cq, + enum ib_sig_type send_policy, + struct ib_qp_cap *cap, + int qpn, + int port, + struct mthca_sqp *sqp) +{ + u32 mqpn = qpn * 2 + dev->qp_table.sqp_start + port - 1; + int err; + SPIN_LOCK_PREP(lhs); + SPIN_LOCK_PREP(lhr); + SPIN_LOCK_PREP(lht); + + err = mthca_set_qp_size(dev, cap, &sqp->qp); + if (err) + return err; + + alloc_dma_zmem_map(dev, + sqp->qp.sq.max * MTHCA_UD_HEADER_SIZE, + PCI_DMA_BIDIRECTIONAL, + &sqp->sg); + if (!sqp->sg.page) + return -ENOMEM; + + spin_lock_irq(&dev->qp_table.lock, &lht); + if (mthca_array_get(&dev->qp_table.qp, mqpn)) + err = -EBUSY; + else + mthca_array_set(&dev->qp_table.qp, mqpn, sqp); + spin_unlock_irq(&lht); + + if (err) + goto err_out; + + sqp->port = port; + sqp->qp.qpn = mqpn; + sqp->qp.transport = MLX; + + err = mthca_alloc_qp_common(dev, pd, send_cq, recv_cq, + send_policy, &sqp->qp); + if (err) + goto err_out_free; + + atomic_inc(&pd->sqp_count); + + return 0; + + err_out_free: + /* + * Lock CQs here, so that CQ polling code can do QP lookup + * without taking a lock. + */ + spin_lock_irq(&send_cq->lock, &lhs); + if (send_cq != recv_cq) + spin_lock(&recv_cq->lock, &lhr); + + spin_lock(&dev->qp_table.lock, &lht); + mthca_array_clear(&dev->qp_table.qp, mqpn); + spin_unlock(&lht); + + if (send_cq != recv_cq) + spin_unlock(&lhr); + spin_unlock_irq(&lhs); + + err_out: + free_dma_mem_map(dev, &sqp->sg, PCI_DMA_BIDIRECTIONAL); + + return err; +} + +void mthca_free_qp(struct mthca_dev *dev, + struct mthca_qp *qp) +{ + u8 status; + struct mthca_cq *send_cq; + struct mthca_cq *recv_cq; + int zombi = 0; + SPIN_LOCK_PREP(lhs); + SPIN_LOCK_PREP(lhr); + SPIN_LOCK_PREP(lht); + + send_cq = to_mcq(qp->ibqp.send_cq); + recv_cq = to_mcq(qp->ibqp.recv_cq); + + /* + * Lock CQs here, so that CQ polling code can do QP lookup + * without taking a lock. + */ + spin_lock_irq(&send_cq->lock, &lhs); + if (send_cq != recv_cq) + spin_lock(&recv_cq->lock, &lhr); + + spin_lock(&dev->qp_table.lock, &lht); + mthca_array_clear(&dev->qp_table.qp, + qp->qpn & (dev->limits.num_qps - 1)); + spin_unlock(&lht); + + if (send_cq != recv_cq) + spin_unlock(&lhr); + spin_unlock_irq(&lhs); + + atomic_dec(&qp->refcount); + wait_event(&qp->wait, !atomic_read(&qp->refcount)); + + if (qp->state != IBQPS_RESET) { + if (mthca_MODIFY_QP(dev, MTHCA_TRANS_ANY2RST, qp->qpn, 0, NULL, 0, &status)) { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_QP,("modify QP %06x to RESET failed.\n", + qp->qpn)); + zombi = 1; + } + } + + /* + * If this is a userspace QP, the buffers, MR, CQs and so on + * will be cleaned up in userspace, so all we have to do is + * unref the mem-free tables and free the QPN in our table. + */ + if (!qp->ibqp.ucontext) { + mthca_cq_clean(dev, to_mcq(qp->ibqp.send_cq)->cqn, qp->qpn, + qp->ibqp.srq ? to_msrq(qp->ibqp.srq) : NULL); + if (qp->ibqp.send_cq != qp->ibqp.recv_cq) + mthca_cq_clean(dev, to_mcq(qp->ibqp.recv_cq)->cqn, qp->qpn, + qp->ibqp.srq ? to_msrq(qp->ibqp.srq) : NULL); + + mthca_free_memfree(dev, qp); + mthca_free_wqe_buf(dev, qp); + } + + mthca_unmap_memfree(dev, qp); + + if (is_sqp(dev, qp)) { + atomic_dec(&(to_mpd(qp->ibqp.pd)->sqp_count)); + free_dma_mem_map(dev, &to_msqp(qp)->sg, PCI_DMA_BIDIRECTIONAL); + } else { + if ( !zombi ) + mthca_free(&dev->qp_table.alloc, qp->qpn); + } +} + +static enum mthca_wr_opcode conv_ibal_wr_opcode(struct _ib_send_wr *wr) +{ + + enum mthca_wr_opcode opcode = -1; //= wr->wr_type; + + switch (wr->wr_type) { + case WR_SEND: + opcode = (wr->send_opt & IB_SEND_OPT_IMMEDIATE) ? MTHCA_OPCODE_SEND_IMM : MTHCA_OPCODE_SEND; + break; + case WR_RDMA_WRITE: + opcode = (wr->send_opt & IB_SEND_OPT_IMMEDIATE) ? MTHCA_OPCODE_RDMA_WRITE_IMM : MTHCA_OPCODE_RDMA_WRITE; + break; + case WR_RDMA_READ: opcode = MTHCA_OPCODE_RDMA_READ; break; + case WR_COMPARE_SWAP: opcode = MTHCA_OPCODE_ATOMIC_CS; break; + case WR_FETCH_ADD: opcode = MTHCA_OPCODE_ATOMIC_FA; break; + default: opcode = MTHCA_OPCODE_INVALID;break; + } + return opcode; +} + +/* Create UD header for an MLX send and build a data segment for it */ +static int build_mlx_header(struct mthca_dev *dev, struct mthca_sqp *sqp, + int ind, struct _ib_send_wr *wr, + struct mthca_mlx_seg *mlx, + struct mthca_data_seg *data) +{ + enum ib_wr_opcode opcode = conv_ibal_wr_opcode(wr); + int header_size; + int err; + __be16 pkey; + CPU_2_BE64_PREP; + + if (!wr->dgrm.ud.h_av) { + HCA_PRINT(TRACE_LEVEL_ERROR , HCA_DBG_AV, + ("absent AV in send wr %p\n", wr)); + return -EINVAL; + } + + ib_ud_header_init(256, /* assume a MAD */ + mthca_ah_grh_present(to_mah((struct ib_ah *)wr->dgrm.ud.h_av)), + &sqp->ud_header); + + err = mthca_read_ah(dev, to_mah((struct ib_ah *)wr->dgrm.ud.h_av), &sqp->ud_header); + if (err){ + HCA_PRINT(TRACE_LEVEL_ERROR , HCA_DBG_AV, ("read av error%p\n", + to_mah((struct ib_ah *)wr->dgrm.ud.h_av)->av)); + return err; + } + mlx->flags &= ~cl_hton32(MTHCA_NEXT_SOLICIT | 1); + mlx->flags |= cl_hton32((!sqp->qp.ibqp.qp_num ? MTHCA_MLX_VL15 : 0) | + (sqp->ud_header.lrh.destination_lid == + IB_LID_PERMISSIVE ? MTHCA_MLX_SLR : 0) | + (sqp->ud_header.lrh.service_level << 8)); + mlx->rlid = sqp->ud_header.lrh.destination_lid; + mlx->vcrc = 0; + + switch (opcode) { + case MTHCA_OPCODE_SEND: + sqp->ud_header.bth.opcode = IB_OPCODE_UD_SEND_ONLY; + sqp->ud_header.immediate_present = 0; + break; + case MTHCA_OPCODE_SEND_IMM: + sqp->ud_header.bth.opcode = IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE; + sqp->ud_header.immediate_present = 1; + sqp->ud_header.immediate_data = wr->immediate_data; + break; + default: + return -EINVAL; + } + + sqp->ud_header.lrh.virtual_lane = !sqp->qp.ibqp.qp_num ? 15 : 0; + if (sqp->ud_header.lrh.destination_lid == IB_LID_PERMISSIVE) + sqp->ud_header.lrh.source_lid = IB_LID_PERMISSIVE; + sqp->ud_header.bth.solicited_event = (u8)!!(wr->send_opt & IB_SEND_OPT_SOLICITED); + if (!sqp->qp.ibqp.qp_num) + ib_get_cached_pkey(&dev->ib_dev, (u8)sqp->port, + sqp->pkey_index, &pkey); + else + ib_get_cached_pkey(&dev->ib_dev, (u8)sqp->port, + wr->dgrm.ud.pkey_index, &pkey); + sqp->ud_header.bth.pkey = pkey; + sqp->ud_header.bth.destination_qpn = wr->dgrm.ud.remote_qp; + sqp->ud_header.bth.psn = cl_hton32((sqp->send_psn++) & ((1 << 24) - 1)); + sqp->ud_header.deth.qkey = wr->dgrm.ud.remote_qkey & 0x00000080 ? + cl_hton32(sqp->qkey) : wr->dgrm.ud.remote_qkey; + sqp->ud_header.deth.source_qpn = cl_hton32(sqp->qp.ibqp.qp_num); + + header_size = ib_ud_header_pack(&sqp->ud_header, + (u8*)sqp->sg.page + + ind * MTHCA_UD_HEADER_SIZE); + + data->byte_count = cl_hton32(header_size); + data->lkey = cl_hton32(to_mpd(sqp->qp.ibqp.pd)->ntmr.ibmr.lkey); + data->addr = CPU_2_BE64(sqp->sg.dma_address + + ind * MTHCA_UD_HEADER_SIZE); + + return 0; +} + +static inline int mthca_wq_overflow(struct mthca_wq *wq, int nreq, + struct ib_cq *ib_cq) +{ + unsigned cur; + struct mthca_cq *cq; + SPIN_LOCK_PREP(lh); + + cur = wq->head - wq->tail; + if (likely((int)cur + nreq < wq->max)) + return 0; + + cq = to_mcq(ib_cq); + spin_lock_dpc(&cq->lock, &lh); + cur = wq->head - wq->tail; + spin_unlock_dpc(&lh); + + return (int)cur + nreq >= wq->max; +} + +int mthca_tavor_post_send(struct ib_qp *ibqp, struct _ib_send_wr *wr, + struct _ib_send_wr **bad_wr) +{ + struct mthca_dev *dev = to_mdev(ibqp->device); + struct mthca_qp *qp = to_mqp(ibqp); + u8 *wqe; + u8 *prev_wqe; + int err = 0; + int nreq; + int i; + int size; + int size0 = 0; + u32 f0 = unlikely(wr->send_opt & IB_SEND_OPT_FENCE) ? MTHCA_SEND_DOORBELL_FENCE : 0; + int ind; + u8 op0 = 0; + enum ib_wr_opcode opcode; + SPIN_LOCK_PREP(lh); + + spin_lock_irqsave(&qp->sq.lock, &lh); + + /* XXX check that state is OK to post send */ + + ind = qp->sq.next_ind; + + for (nreq = 0; wr; ++nreq, wr = wr->p_next) { + if (mthca_wq_overflow(&qp->sq, nreq, qp->ibqp.send_cq)) { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_QP,("SQ %06x full (%u head, %u tail," + " %d max, %d nreq)\n", qp->qpn, + qp->sq.head, qp->sq.tail, + qp->sq.max, nreq)); + err = -ENOMEM; + if (bad_wr) + *bad_wr = wr; + goto out; + } + + wqe = get_send_wqe(qp, ind); + prev_wqe = qp->sq.last; + qp->sq.last = wqe; + opcode = conv_ibal_wr_opcode(wr); + + ((struct mthca_next_seg *) wqe)->nda_op = 0; + ((struct mthca_next_seg *) wqe)->ee_nds = 0; + ((struct mthca_next_seg *) wqe)->flags = + ((wr->send_opt & IB_SEND_OPT_SIGNALED) ? + cl_hton32(MTHCA_NEXT_CQ_UPDATE) : 0) | + ((wr->send_opt & IB_SEND_OPT_SOLICITED) ? + cl_hton32(MTHCA_NEXT_SOLICIT) : 0) | + cl_hton32(1); + if (opcode == MTHCA_OPCODE_SEND_IMM|| + opcode == MTHCA_OPCODE_RDMA_WRITE_IMM) + ((struct mthca_next_seg *) wqe)->imm = wr->immediate_data; + + wqe += sizeof (struct mthca_next_seg); + size = sizeof (struct mthca_next_seg) / 16; + + switch (qp->transport) { + case RC: + switch (opcode) { + case MTHCA_OPCODE_ATOMIC_CS: + case MTHCA_OPCODE_ATOMIC_FA: + ((struct mthca_raddr_seg *) wqe)->raddr = + cl_hton64(wr->remote_ops.vaddr); + ((struct mthca_raddr_seg *) wqe)->rkey = + wr->remote_ops.rkey; + ((struct mthca_raddr_seg *) wqe)->reserved = 0; + + wqe += sizeof (struct mthca_raddr_seg); + + if (opcode == MTHCA_OPCODE_ATOMIC_CS) { + ((struct mthca_atomic_seg *) wqe)->swap_add = + (wr->remote_ops.atomic2); + ((struct mthca_atomic_seg *) wqe)->compare = + (wr->remote_ops.atomic1); + } else { + ((struct mthca_atomic_seg *) wqe)->swap_add = + (wr->remote_ops.atomic1); + ((struct mthca_atomic_seg *) wqe)->compare = 0; + } + + wqe += sizeof (struct mthca_atomic_seg); + size += (sizeof (struct mthca_raddr_seg) + + sizeof (struct mthca_atomic_seg)) / 16 ; + break; + + case MTHCA_OPCODE_RDMA_READ: + case MTHCA_OPCODE_RDMA_WRITE: + case MTHCA_OPCODE_RDMA_WRITE_IMM: + ((struct mthca_raddr_seg *) wqe)->raddr = + cl_hton64(wr->remote_ops.vaddr); + ((struct mthca_raddr_seg *) wqe)->rkey = + wr->remote_ops.rkey; + ((struct mthca_raddr_seg *) wqe)->reserved = 0; + wqe += sizeof (struct mthca_raddr_seg); + size += sizeof (struct mthca_raddr_seg) / 16; + break; + + default: + /* No extra segments required for sends */ + break; + } + + break; + + case UC: + switch (opcode) { + case MTHCA_OPCODE_RDMA_WRITE: + case MTHCA_OPCODE_RDMA_WRITE_IMM: + ((struct mthca_raddr_seg *) wqe)->raddr = + cl_hton64(wr->remote_ops.vaddr); + ((struct mthca_raddr_seg *) wqe)->rkey = + wr->remote_ops.rkey; + ((struct mthca_raddr_seg *) wqe)->reserved = 0; + wqe += sizeof (struct mthca_raddr_seg); + size += sizeof (struct mthca_raddr_seg) / 16; + break; + + default: + /* No extra segments required for sends */ + break; + } + + break; + + case UD: + ((struct mthca_tavor_ud_seg *) wqe)->lkey = + cl_hton32(to_mah((struct ib_ah *)wr->dgrm.ud.h_av)->key); + ((struct mthca_tavor_ud_seg *) wqe)->av_addr = + cl_hton64(to_mah((struct ib_ah *)wr->dgrm.ud.h_av)->avdma); + ((struct mthca_tavor_ud_seg *) wqe)->dqpn = wr->dgrm.ud.remote_qp; + ((struct mthca_tavor_ud_seg *) wqe)->qkey = wr->dgrm.ud.remote_qkey; + + wqe += sizeof (struct mthca_tavor_ud_seg); + size += sizeof (struct mthca_tavor_ud_seg) / 16; + break; + + case MLX: + err = build_mlx_header(dev, to_msqp(qp), ind, wr, + (void*)(wqe - sizeof (struct mthca_next_seg)), + (void*)wqe); + if (err) { + if (bad_wr) + *bad_wr = wr; + goto out; + } + wqe += sizeof (struct mthca_data_seg); + size += sizeof (struct mthca_data_seg) / 16; + break; + } + + if ((int)(int)wr->num_ds > qp->sq.max_gs) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_QP ,("SQ %06x too many gathers\n",qp->qpn)); + err = -EINVAL; + if (bad_wr) + *bad_wr = wr; + goto out; + } + if (wr->send_opt & IB_SEND_OPT_INLINE) { + if (wr->num_ds) { + struct mthca_inline_seg *seg = (struct mthca_inline_seg *)wqe; + uint32_t s = 0; + + wqe += sizeof *seg; + for (i = 0; i < (int)wr->num_ds; ++i) { + struct _ib_local_ds *sge = &wr->ds_array[i]; + + s += sge->length; + + if (s > (uint32_t)qp->max_inline_data) { + err = -EINVAL; + if (bad_wr) + *bad_wr = wr; + goto out; + } + + memcpy(wqe, (void *) (ULONG_PTR) sge->vaddr, + sge->length); + wqe += sge->length; + } + + seg->byte_count = cl_hton32(MTHCA_INLINE_SEG | s); + size += align(s + sizeof *seg, 16) / 16; + } + } else { + + for (i = 0; i < (int)wr->num_ds; ++i) { + ((struct mthca_data_seg *) wqe)->byte_count = + cl_hton32(wr->ds_array[i].length); + ((struct mthca_data_seg *) wqe)->lkey = + cl_hton32(wr->ds_array[i].lkey); + ((struct mthca_data_seg *) wqe)->addr = + cl_hton64(wr->ds_array[i].vaddr); + wqe += sizeof (struct mthca_data_seg); + size += sizeof (struct mthca_data_seg) / 16; + HCA_PRINT(TRACE_LEVEL_VERBOSE ,HCA_DBG_QP ,("SQ %06x [%02x] lkey 0x%08x vaddr 0x%I64x 0x%x\n",qp->qpn,i, + (wr->ds_array[i].lkey),(wr->ds_array[i].vaddr),wr->ds_array[i].length)); + } + } + + /* Add one more inline data segment for ICRC */ + if (qp->transport == MLX) { + ((struct mthca_data_seg *) wqe)->byte_count = + cl_hton32((unsigned long)((1 << 31) | 4)); + ((u32 *) wqe)[1] = 0; + wqe += sizeof (struct mthca_data_seg); + size += sizeof (struct mthca_data_seg) / 16; + } + + qp->wrid[ind + qp->rq.max] = wr->wr_id; + + if (opcode == MTHCA_OPCODE_INVALID) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_QP ,("SQ %06x opcode invalid\n",qp->qpn)); + err = -EINVAL; + if (bad_wr) + *bad_wr = wr; + goto out; + } + + ((struct mthca_next_seg *) prev_wqe)->nda_op = + cl_hton32(((ind << qp->sq.wqe_shift) + + qp->send_wqe_offset) |opcode); + wmb(); + ((struct mthca_next_seg *) prev_wqe)->ee_nds = + cl_hton32((size0 ? 0 : MTHCA_NEXT_DBD) | size | + ((wr->send_opt & IB_SEND_OPT_FENCE) ? + MTHCA_NEXT_FENCE : 0)); + + if (!size0) { + size0 = size; + op0 = opcode; + } + + dump_wqe( TRACE_LEVEL_VERBOSE, (u32*)qp->sq.last,qp); + + ++ind; + if (unlikely(ind >= qp->sq.max)) + ind -= qp->sq.max; + } + +out: + if (likely(nreq)) { + __be32 doorbell[2]; + + doorbell[0] = cl_hton32(((qp->sq.next_ind << qp->sq.wqe_shift) + + qp->send_wqe_offset) | f0 | op0); + doorbell[1] = cl_hton32((qp->qpn << 8) | size0); + + wmb(); + + mthca_write64(doorbell, + dev->kar + MTHCA_SEND_DOORBELL, + MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock)); + } + + qp->sq.next_ind = ind; + qp->sq.head += nreq; + + spin_unlock_irqrestore(&lh); + return err; +} + +int mthca_tavor_post_recv(struct ib_qp *ibqp, struct _ib_recv_wr *wr, + struct _ib_recv_wr **bad_wr) +{ + struct mthca_dev *dev = to_mdev(ibqp->device); + struct mthca_qp *qp = to_mqp(ibqp); + __be32 doorbell[2]; + int err = 0; + int nreq; + int i; + int size; + int size0 = 0; + int ind; + u8 *wqe; + u8 *prev_wqe; + SPIN_LOCK_PREP(lh); + + spin_lock_irqsave(&qp->rq.lock, &lh); + + /* XXX check that state is OK to post receive */ + + ind = qp->rq.next_ind; + + for (nreq = 0; wr; ++nreq, wr = wr->p_next) { + if (unlikely(nreq == MTHCA_TAVOR_MAX_WQES_PER_RECV_DB)) { + nreq = 0; + + doorbell[0] = cl_hton32((qp->rq.next_ind << qp->rq.wqe_shift) | size0); + doorbell[1] = cl_hton32(qp->qpn << 8); + + wmb(); + + mthca_write64(doorbell, dev->kar + MTHCA_RECV_DOORBELL, + MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock)); + + qp->rq.head += MTHCA_TAVOR_MAX_WQES_PER_RECV_DB; + size0 = 0; + } + if (mthca_wq_overflow(&qp->rq, nreq, qp->ibqp.recv_cq)) { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_QP,("RQ %06x full (%u head, %u tail," + " %d max, %d nreq)\n", qp->qpn, + qp->rq.head, qp->rq.tail, + qp->rq.max, nreq)); + err = -ENOMEM; + if (bad_wr) + *bad_wr = wr; + goto out; + } + + wqe = get_recv_wqe(qp, ind); + prev_wqe = qp->rq.last; + qp->rq.last = wqe; + + ((struct mthca_next_seg *) wqe)->nda_op = 0; + ((struct mthca_next_seg *) wqe)->ee_nds = + cl_hton32(MTHCA_NEXT_DBD); + ((struct mthca_next_seg *) wqe)->flags = 0; + + wqe += sizeof (struct mthca_next_seg); + size = sizeof (struct mthca_next_seg) / 16; + + if (unlikely((int)wr->num_ds > qp->rq.max_gs)) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_QP ,("RQ %06x too many gathers\n",qp->qpn)); + err = -EINVAL; + if (bad_wr) + *bad_wr = wr; + goto out; + } + + for (i = 0; i < (int)wr->num_ds; ++i) { + ((struct mthca_data_seg *) wqe)->byte_count = + cl_hton32(wr->ds_array[i].length); + ((struct mthca_data_seg *) wqe)->lkey = + cl_hton32(wr->ds_array[i].lkey); + ((struct mthca_data_seg *) wqe)->addr = + cl_hton64(wr->ds_array[i].vaddr); + wqe += sizeof (struct mthca_data_seg); + size += sizeof (struct mthca_data_seg) / 16; +// HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_QP ,("RQ %06x [%02x] lkey 0x%08x vaddr 0x%I64x 0x %x 0x%08x\n",i,qp->qpn, +// (wr->ds_array[i].lkey),(wr->ds_array[i].vaddr),wr->ds_array[i].length, wr->wr_id)); + } + + qp->wrid[ind] = wr->wr_id; + + ((struct mthca_next_seg *) prev_wqe)->nda_op = + cl_hton32((ind << qp->rq.wqe_shift) | 1); + wmb(); + ((struct mthca_next_seg *) prev_wqe)->ee_nds = + cl_hton32(MTHCA_NEXT_DBD | size); + + if (!size0) + size0 = size; + + dump_wqe(TRACE_LEVEL_VERBOSE, (u32*)wqe ,qp); + + ++ind; + if (unlikely(ind >= qp->rq.max)) + ind -= qp->rq.max; + } + +out: + if (likely(nreq)) { + doorbell[0] = cl_hton32((qp->rq.next_ind << qp->rq.wqe_shift) | size0); + doorbell[1] = cl_hton32((qp->qpn << 8) | (nreq & 255)); + + wmb(); + + mthca_write64(doorbell, dev->kar + MTHCA_RECV_DOORBELL, + MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock)); + } + + qp->rq.next_ind = ind; + qp->rq.head += nreq; + + spin_unlock_irqrestore(&lh); + return err; +} + +int mthca_arbel_post_send(struct ib_qp *ibqp, struct _ib_send_wr *wr, + struct _ib_send_wr **bad_wr) +{ + struct mthca_dev *dev = to_mdev(ibqp->device); + struct mthca_qp *qp = to_mqp(ibqp); + __be32 doorbell[2]; + u8 *wqe; + u8 *prev_wqe; + int err = 0; + int nreq; + int i; + int size; + int size0 = 0; + u32 f0 = unlikely(wr->send_opt & IB_SEND_OPT_FENCE) ? MTHCA_SEND_DOORBELL_FENCE : 0; + int ind; + u8 op0 = 0; + enum ib_wr_opcode opcode; + SPIN_LOCK_PREP(lh); + + spin_lock_irqsave(&qp->sq.lock, &lh); + + /* XXX check that state is OK to post send */ + + ind = qp->sq.head & (qp->sq.max - 1); + + for (nreq = 0; wr; ++nreq, wr = wr->p_next) { + if (unlikely(nreq == MTHCA_ARBEL_MAX_WQES_PER_SEND_DB)) { + nreq = 0; + doorbell[0] = cl_hton32((MTHCA_ARBEL_MAX_WQES_PER_SEND_DB << 24) | + ((qp->sq.head & 0xffff) << 8) |f0 | op0); + doorbell[1] = cl_hton32((qp->qpn << 8) | size0); + qp->sq.head += MTHCA_ARBEL_MAX_WQES_PER_SEND_DB; + size0 = 0; + f0 = unlikely(wr->send_opt & IB_SEND_OPT_FENCE) ? MTHCA_SEND_DOORBELL_FENCE : 0; + + /* + * Make sure that descriptors are written before + * doorbell record. + */ + wmb(); + *qp->sq.db = cl_hton32(qp->sq.head & 0xffff); + + /* + * Make sure doorbell record is written before we + * write MMIO send doorbell. + */ + wmb(); + mthca_write64(doorbell, dev->kar + MTHCA_SEND_DOORBELL, + MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock)); + } + + if (mthca_wq_overflow(&qp->sq, nreq, qp->ibqp.send_cq)) { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_QP,("SQ %06x full (%u head, %u tail," + " %d max, %d nreq)\n", qp->qpn, + qp->sq.head, qp->sq.tail, + qp->sq.max, nreq)); + err = -ENOMEM; + if (bad_wr) + *bad_wr = wr; + goto out; + } + + wqe = get_send_wqe(qp, ind); + prev_wqe = qp->sq.last; + qp->sq.last = wqe; + opcode = conv_ibal_wr_opcode(wr); + + ((struct mthca_next_seg *) wqe)->flags = + ((wr->send_opt & IB_SEND_OPT_SIGNALED) ? + cl_hton32(MTHCA_NEXT_CQ_UPDATE) : 0) | + ((wr->send_opt & IB_SEND_OPT_SOLICITED) ? + cl_hton32(MTHCA_NEXT_SOLICIT) : 0) | + ((wr->send_opt & IB_SEND_OPT_TX_IP_CSUM) ? + cl_hton32(MTHCA_NEXT_IP_CSUM) : 0) | + ((wr->send_opt & IB_SEND_OPT_TX_TCP_UDP_CSUM) ? + cl_hton32(MTHCA_NEXT_TCP_UDP_CSUM) : 0) | + cl_hton32(1); + if (opcode == MTHCA_OPCODE_SEND_IMM|| + opcode == MTHCA_OPCODE_RDMA_WRITE_IMM) + ((struct mthca_next_seg *) wqe)->imm = wr->immediate_data; + + wqe += sizeof (struct mthca_next_seg); + size = sizeof (struct mthca_next_seg) / 16; + + switch (qp->transport) { + case RC: + switch (opcode) { + case MTHCA_OPCODE_ATOMIC_CS: + case MTHCA_OPCODE_ATOMIC_FA: + ((struct mthca_raddr_seg *) wqe)->raddr = + cl_hton64(wr->remote_ops.vaddr); + ((struct mthca_raddr_seg *) wqe)->rkey = + wr->remote_ops.rkey; + ((struct mthca_raddr_seg *) wqe)->reserved = 0; + + wqe += sizeof (struct mthca_raddr_seg); + + if (opcode == MTHCA_OPCODE_ATOMIC_CS) { + ((struct mthca_atomic_seg *) wqe)->swap_add = + (wr->remote_ops.atomic2); + ((struct mthca_atomic_seg *) wqe)->compare = + (wr->remote_ops.atomic1); + } else { + ((struct mthca_atomic_seg *) wqe)->swap_add = + (wr->remote_ops.atomic1); + ((struct mthca_atomic_seg *) wqe)->compare = 0; + } + + wqe += sizeof (struct mthca_atomic_seg); + size += (sizeof (struct mthca_raddr_seg) + + sizeof (struct mthca_atomic_seg)) / 16 ; + break; + + case MTHCA_OPCODE_RDMA_READ: + case MTHCA_OPCODE_RDMA_WRITE: + case MTHCA_OPCODE_RDMA_WRITE_IMM: + ((struct mthca_raddr_seg *) wqe)->raddr = + cl_hton64(wr->remote_ops.vaddr); + ((struct mthca_raddr_seg *) wqe)->rkey = + wr->remote_ops.rkey; + ((struct mthca_raddr_seg *) wqe)->reserved = 0; + wqe += sizeof (struct mthca_raddr_seg); + size += sizeof (struct mthca_raddr_seg) / 16; + break; + + default: + /* No extra segments required for sends */ + break; + } + + break; + + case UC: + switch (opcode) { + case MTHCA_OPCODE_RDMA_WRITE: + case MTHCA_OPCODE_RDMA_WRITE_IMM: + ((struct mthca_raddr_seg *) wqe)->raddr = + cl_hton64(wr->remote_ops.vaddr); + ((struct mthca_raddr_seg *) wqe)->rkey = + wr->remote_ops.rkey; + ((struct mthca_raddr_seg *) wqe)->reserved = 0; + wqe += sizeof (struct mthca_raddr_seg); + size += sizeof (struct mthca_raddr_seg) / 16; + break; + + default: + /* No extra segments required for sends */ + break; + } + + break; + + case UD: + memcpy(((struct mthca_arbel_ud_seg *) wqe)->av, + to_mah((struct ib_ah *)wr->dgrm.ud.h_av)->av, MTHCA_AV_SIZE); + ((struct mthca_arbel_ud_seg *) wqe)->dqpn = wr->dgrm.ud.remote_qp; + ((struct mthca_arbel_ud_seg *) wqe)->qkey = wr->dgrm.ud.remote_qkey; + + wqe += sizeof (struct mthca_arbel_ud_seg); + size += sizeof (struct mthca_arbel_ud_seg) / 16; + break; + + case MLX: + err = build_mlx_header(dev, to_msqp(qp), ind, wr, + (void*)(wqe - sizeof (struct mthca_next_seg)), + (void*)wqe); + if (err) { + if (bad_wr) + *bad_wr = wr; + goto out; + } + wqe += sizeof (struct mthca_data_seg); + size += sizeof (struct mthca_data_seg) / 16; + break; + } + + if ((int)wr->num_ds > qp->sq.max_gs) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_QP ,("SQ %06x full too many gathers\n",qp->qpn)); + err = -EINVAL; + if (bad_wr) + *bad_wr = wr; + goto out; + } + if (wr->send_opt & IB_SEND_OPT_INLINE) { + if (wr->num_ds) { + struct mthca_inline_seg *seg = (struct mthca_inline_seg *)wqe; + uint32_t s = 0; + + wqe += sizeof *seg; + for (i = 0; i < (int)wr->num_ds; ++i) { + struct _ib_local_ds *sge = &wr->ds_array[i]; + + s += sge->length; + + if (s > (uint32_t)qp->max_inline_data) { + err = -EINVAL; + if (bad_wr) + *bad_wr = wr; + goto out; + } + + memcpy(wqe, (void *) (uintptr_t) sge->vaddr, + sge->length); + wqe += sge->length; + } + + seg->byte_count = cl_hton32(MTHCA_INLINE_SEG | s); + size += align(s + sizeof *seg, 16) / 16; + } + } else { + for (i = 0; i < (int)wr->num_ds; ++i) { + ((struct mthca_data_seg *) wqe)->byte_count = + cl_hton32(wr->ds_array[i].length); + ((struct mthca_data_seg *) wqe)->lkey = + cl_hton32(wr->ds_array[i].lkey); + ((struct mthca_data_seg *) wqe)->addr = + cl_hton64(wr->ds_array[i].vaddr); + wqe += sizeof (struct mthca_data_seg); + size += sizeof (struct mthca_data_seg) / 16; + } + } + + /* Add one more inline data segment for ICRC */ + if (qp->transport == MLX) { + ((struct mthca_data_seg *) wqe)->byte_count = + cl_hton32((unsigned long)((1 << 31) | 4)); + ((u32 *) wqe)[1] = 0; + wqe += sizeof (struct mthca_data_seg); + size += sizeof (struct mthca_data_seg) / 16; + } + + qp->wrid[ind + qp->rq.max] = wr->wr_id; + + if (opcode == MTHCA_OPCODE_INVALID) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_QP ,("SQ %06x opcode invalid\n",qp->qpn)); + err = -EINVAL; + if (bad_wr) + *bad_wr = wr; + goto out; + } + + ((struct mthca_next_seg *) prev_wqe)->nda_op = + cl_hton32(((ind << qp->sq.wqe_shift) + + qp->send_wqe_offset) |opcode); + wmb(); + ((struct mthca_next_seg *) prev_wqe)->ee_nds = + cl_hton32(MTHCA_NEXT_DBD | size | + ((wr->send_opt & IB_SEND_OPT_FENCE) ? + MTHCA_NEXT_FENCE : 0)); + + if (!size0) { + size0 = size; + op0 = opcode; + } + + ++ind; + if (unlikely(ind >= qp->sq.max)) + ind -= qp->sq.max; + } + +out: + if (likely(nreq)) { + doorbell[0] = cl_hton32((nreq << 24) | + ((qp->sq.head & 0xffff) << 8) |f0 | op0); + doorbell[1] = cl_hton32((qp->qpn << 8) | size0); + qp->sq.head += nreq; + + /* + * Make sure that descriptors are written before + * doorbell record. + */ + wmb(); + *qp->sq.db = cl_hton32(qp->sq.head & 0xffff); + + /* + * Make sure doorbell record is written before we + * write MMIO send doorbell. + */ + wmb(); + mthca_write64(doorbell, + dev->kar + MTHCA_SEND_DOORBELL, + MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock)); + } + + spin_unlock_irqrestore(&lh); + return err; +} + +int mthca_arbel_post_recv(struct ib_qp *ibqp, struct _ib_recv_wr *wr, + struct _ib_recv_wr **bad_wr) +{ + struct mthca_qp *qp = to_mqp(ibqp); + int err = 0; + int nreq; + int ind; + int i; + u8 *wqe; + SPIN_LOCK_PREP(lh); + + spin_lock_irqsave(&qp->rq.lock, &lh); + + /* XXX check that state is OK to post receive */ + + ind = qp->rq.head & (qp->rq.max - 1); + + for (nreq = 0; wr; ++nreq, wr = wr->p_next) { + if (mthca_wq_overflow(&qp->rq, nreq, qp->ibqp.recv_cq)) { + HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_QP,("RQ %06x full (%u head, %u tail," + " %d max, %d nreq)\n", qp->qpn, + qp->rq.head, qp->rq.tail, + qp->rq.max, nreq)); + err = -ENOMEM; + if (bad_wr) + *bad_wr = wr; + goto out; + } + + wqe = get_recv_wqe(qp, ind); + + ((struct mthca_next_seg *) wqe)->flags = 0; + + wqe += sizeof (struct mthca_next_seg); + + if (unlikely((int)wr->num_ds > qp->rq.max_gs)) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_QP ,("RQ %06x full too many scatter\n",qp->qpn)); + err = -EINVAL; + if (bad_wr) + *bad_wr = wr; + goto out; + } + + for (i = 0; i < (int)wr->num_ds; ++i) { + ((struct mthca_data_seg *) wqe)->byte_count = + cl_hton32(wr->ds_array[i].length); + ((struct mthca_data_seg *) wqe)->lkey = + cl_hton32(wr->ds_array[i].lkey); + ((struct mthca_data_seg *) wqe)->addr = + cl_hton64(wr->ds_array[i].vaddr); + wqe += sizeof (struct mthca_data_seg); + } + + if (i < qp->rq.max_gs) { + ((struct mthca_data_seg *) wqe)->byte_count = 0; + ((struct mthca_data_seg *) wqe)->lkey = cl_hton32(MTHCA_INVAL_LKEY); + ((struct mthca_data_seg *) wqe)->addr = 0; + } + + qp->wrid[ind] = wr->wr_id; + + ++ind; + if (unlikely(ind >= qp->rq.max)) + ind -= qp->rq.max; + } +out: + if (likely(nreq)) { + qp->rq.head += nreq; + + /* + * Make sure that descriptors are written before + * doorbell record. + */ + wmb(); + *qp->rq.db = cl_hton32(qp->rq.head & 0xffff); + } + + spin_unlock_irqrestore(&lh); + return err; +} + +void mthca_free_err_wqe(struct mthca_dev *dev, struct mthca_qp *qp, int is_send, + int index, int *dbd, __be32 *new_wqe) +{ + struct mthca_next_seg *next; + + UNREFERENCED_PARAMETER(dev); + + /* + * For SRQs, all WQEs generate a CQE, so we're always at the + * end of the doorbell chain. + */ + if (qp->ibqp.srq) { + *new_wqe = 0; + return; + } + + if (is_send) + next = get_send_wqe(qp, index); + else + next = get_recv_wqe(qp, index); + + *dbd = !!(next->ee_nds & cl_hton32(MTHCA_NEXT_DBD)); + if (next->ee_nds & cl_hton32(0x3f)) + *new_wqe = (next->nda_op & cl_hton32((unsigned long)~0x3f)) | + (next->ee_nds & cl_hton32(0x3f)); + else + *new_wqe = 0; +} + +int mthca_init_qp_table(struct mthca_dev *dev) +{ + int err; + u8 status; + int i; + + spin_lock_init(&dev->qp_table.lock); + fill_state_table(); + + /* + * We reserve 2 extra QPs per port for the special QPs. The + * special QP for port 1 has to be even, so round up. + */ + dev->qp_table.sqp_start = (dev->limits.reserved_qps + 1) & ~1UL; + err = mthca_alloc_init(&dev->qp_table.alloc, + dev->limits.num_qps, + (1 << 24) - 1, + dev->qp_table.sqp_start + + MTHCA_MAX_PORTS * 2); + if (err) + return err; + + err = mthca_array_init(&dev->qp_table.qp, + dev->limits.num_qps); + if (err) { + mthca_alloc_cleanup(&dev->qp_table.alloc); + return err; + } + + for (i = 0; i < 2; ++i) { + err = mthca_CONF_SPECIAL_QP(dev, i ? IB_QPT_QP1 : IB_QPT_QP0, + dev->qp_table.sqp_start + i * 2, + &status); + if (err) + goto err_out; + if (status) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_QP,("CONF_SPECIAL_QP returned " + "status %02x, aborting.\n", + status)); + err = -EINVAL; + goto err_out; + } + } + return 0; + + err_out: + mthca_CONF_SPECIAL_QP(dev, IB_QPT_QP1, 0, &status); + mthca_CONF_SPECIAL_QP(dev, IB_QPT_QP0, 0, &status); + + mthca_array_cleanup(&dev->qp_table.qp, dev->limits.num_qps); + mthca_alloc_cleanup(&dev->qp_table.alloc); + + return err; +} + +void mthca_cleanup_qp_table(struct mthca_dev *dev) +{ + u8 status; + + mthca_CONF_SPECIAL_QP(dev, IB_QPT_QP1, 0, &status); + mthca_CONF_SPECIAL_QP(dev, IB_QPT_QP0, 0, &status); + + mthca_array_cleanup(&dev->qp_table.qp, dev->limits.num_qps); + mthca_alloc_cleanup(&dev->qp_table.alloc); +} + + + diff --git a/branches/WOF2-3/hw/mthca/kernel/mthca_srq.c b/branches/WOF2-3/hw/mthca/kernel/mthca_srq.c new file mode 100644 index 00000000..7c004847 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/mthca_srq.c @@ -0,0 +1,743 @@ +/* + * Copyright (c) 2005 Cisco Systems. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include "mt_l2w.h" +#include "mthca_dev.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "mthca_srq.tmh" +#endif +#include "mthca_cmd.h" +#include "mthca_memfree.h" +#include "mthca_wqe.h" + + +enum { + MTHCA_MAX_DIRECT_SRQ_SIZE = 4 * PAGE_SIZE +}; + +struct mthca_tavor_srq_context { + __be64 wqe_base_ds; /* low 6 bits is descriptor size */ + __be32 state_pd; + __be32 lkey; + __be32 uar; + __be16 limit_watermark; + __be16 wqe_cnt; + u32 reserved[2]; +}; + +struct mthca_arbel_srq_context { + __be32 state_logsize_srqn; + __be32 lkey; + __be32 db_index; + __be32 logstride_usrpage; + __be64 wqe_base; + __be32 eq_pd; + __be16 limit_watermark; + __be16 wqe_cnt; + u16 reserved1; + __be16 wqe_counter; + u32 reserved2[3]; +}; + +static void *get_wqe(struct mthca_srq *srq, int n) +{ + if (srq->is_direct) + return (u8*)srq->queue.direct.page + (n << srq->wqe_shift); + else + return (u8*)srq->queue.page_list[(n << srq->wqe_shift) >> PAGE_SHIFT].page + + ((n << srq->wqe_shift) & (PAGE_SIZE - 1)); +} + +/* + * Return a pointer to the location within a WQE that we're using as a + * link when the WQE is in the free list. We use the imm field + * because in the Tavor case, posting a WQE may overwrite the next + * segment of the previous WQE, but a receive WQE will never touch the + * imm field. This avoids corrupting our free list if the previous + * WQE has already completed and been put on the free list when we + * post the next WQE. + */ +static inline int *wqe_to_link(void *wqe) +{ + return (int *) ((u8*)wqe + offsetof(struct mthca_next_seg, imm)); +} + +static void mthca_tavor_init_srq_context(struct mthca_dev *dev, + struct mthca_pd *pd, + struct mthca_srq *srq, + struct mthca_tavor_srq_context *context) +{ + CPU_2_BE64_PREP; + + RtlZeroMemory(context, sizeof *context); + + context->wqe_base_ds = CPU_2_BE64(1Ui64 << (srq->wqe_shift - 4)); + context->state_pd = cl_hton32(pd->pd_num); + context->lkey = cl_hton32(srq->mr.ibmr.lkey); + + if (pd->ibpd.ucontext) + context->uar = + cl_hton32(to_mucontext(pd->ibpd.ucontext)->uar.index); + else + context->uar = cl_hton32(dev->driver_uar.index); +} + +static void mthca_arbel_init_srq_context(struct mthca_dev *dev, + struct mthca_pd *pd, + struct mthca_srq *srq, + struct mthca_arbel_srq_context *context) +{ + int logsize; + + RtlZeroMemory(context, sizeof *context); + + logsize = long_log2(srq->max); + context->state_logsize_srqn = cl_hton32(logsize << 24 | srq->srqn); + context->lkey = cl_hton32(srq->mr.ibmr.lkey); + context->db_index = cl_hton32(srq->db_index); + context->logstride_usrpage = cl_hton32((srq->wqe_shift - 4) << 29); + if (pd->ibpd.ucontext) + context->logstride_usrpage |= + cl_hton32(to_mucontext(pd->ibpd.ucontext)->uar.index); + else + context->logstride_usrpage |= cl_hton32(dev->driver_uar.index); + context->eq_pd = cl_hton32(MTHCA_EQ_ASYNC << 24 | pd->pd_num); +} + +static void mthca_free_srq_buf(struct mthca_dev *dev, struct mthca_srq *srq) +{ + mthca_buf_free(dev, srq->max << srq->wqe_shift, &srq->queue, + srq->is_direct, &srq->mr); + kfree(srq->wrid); +} + +static int mthca_alloc_srq_buf(struct mthca_dev *dev, struct mthca_pd *pd, + struct mthca_srq *srq) +{ + struct mthca_data_seg *scatter; + u8 *wqe; + int err; + int i; + + if (pd->ibpd.ucontext) + return 0; + + srq->wrid = kmalloc(srq->max * sizeof (u64), GFP_KERNEL); + if (!srq->wrid) + return -ENOMEM; + + err = mthca_buf_alloc(dev, srq->max << srq->wqe_shift, + MTHCA_MAX_DIRECT_SRQ_SIZE, + &srq->queue, &srq->is_direct, pd, 1, &srq->mr); + if (err) { + kfree(srq->wrid); + return err; + } + + /* + * Now initialize the SRQ buffer so that all of the WQEs are + * linked into the list of free WQEs. In addition, set the + * scatter list L_Keys to the sentry value of 0x100. + */ + for (i = 0; i < srq->max; ++i) { + wqe = get_wqe(srq, i); + + *wqe_to_link(wqe) = i < srq->max - 1 ? i + 1 : -1; + + for (scatter = (struct mthca_data_seg *)(wqe + sizeof (struct mthca_next_seg)); + (void *) scatter < (void*)(wqe + (uint32_t)(1 << srq->wqe_shift)); + ++scatter) + scatter->lkey = cl_hton32(MTHCA_INVAL_LKEY); + } + + srq->last = get_wqe(srq, srq->max - 1); + + return 0; +} + +int mthca_alloc_srq(struct mthca_dev *dev, struct mthca_pd *pd, + ib_srq_attr_t *attr, struct mthca_srq *srq) +{ + struct mthca_mailbox *mailbox; + u8 status; + int ds; + int err; + SPIN_LOCK_PREP(lh); + + /* Sanity check SRQ size before proceeding */ + if ((int)attr->max_wr > dev->limits.max_srq_wqes || + (int)attr->max_sge > dev->limits.max_srq_sge) + return -EINVAL; + + srq->max = attr->max_wr; + srq->max_gs = attr->max_sge; + srq->counter = 0; + + if (mthca_is_memfree(dev)) + srq->max = roundup_pow_of_two(srq->max + 1); + + ds = max(64UL, + roundup_pow_of_two(sizeof (struct mthca_next_seg) + + srq->max_gs * sizeof (struct mthca_data_seg))); + + if (!mthca_is_memfree(dev) && (ds > dev->limits.max_desc_sz)) + return -EINVAL; + + srq->wqe_shift = long_log2(ds); + + srq->srqn = mthca_alloc(&dev->srq_table.alloc); + if (srq->srqn == -1) + return -ENOMEM; + + if (mthca_is_memfree(dev)) { + err = mthca_table_get(dev, dev->srq_table.table, srq->srqn); + if (err) + goto err_out; + + if (!pd->ibpd.ucontext) { + srq->db_index = mthca_alloc_db(dev, MTHCA_DB_TYPE_SRQ, + srq->srqn, &srq->db); + if (srq->db_index < 0) { + err = -ENOMEM; + goto err_out_icm; + } + } + } + + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (IS_ERR(mailbox)) { + err = PTR_ERR(mailbox); + goto err_out_db; + } + + err = mthca_alloc_srq_buf(dev, pd, srq); + if (err) + goto err_out_mailbox; + + spin_lock_init(&srq->lock); + atomic_set(&srq->refcount, 1); + init_waitqueue_head(&srq->wait); + KeInitializeMutex(&srq->mutex, 0); + + if (mthca_is_memfree(dev)) + mthca_arbel_init_srq_context(dev, pd, srq, mailbox->buf); + else + mthca_tavor_init_srq_context(dev, pd, srq, mailbox->buf); + + err = mthca_SW2HW_SRQ(dev, mailbox, srq->srqn, &status); + + if (err) { + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_SRQ ,( "SW2HW_SRQ failed (%d)\n", err)); + goto err_out_free_buf; + } + if (status) { + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_SRQ ,( "SW2HW_SRQ returned status 0x%02x\n", + status)); + err = -EINVAL; + goto err_out_free_buf; + } + + spin_lock_irq(&dev->srq_table.lock, &lh); + if (mthca_array_set(&dev->srq_table.srq, + srq->srqn & (dev->limits.num_srqs - 1), + srq)) { + spin_unlock_irq(&lh); + goto err_out_free_srq; + } + spin_unlock_irq(&lh); + + mthca_free_mailbox(dev, mailbox); + + srq->first_free = 0; + srq->last_free = srq->max - 1; + + attr->max_wr = (mthca_is_memfree(dev)) ? srq->max - 1 : srq->max; + attr->max_sge = srq->max_gs; + + return 0; + +err_out_free_srq: + err = mthca_HW2SW_SRQ(dev, mailbox, srq->srqn, &status); + if (err) { + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_SRQ ,( "HW2SW_SRQ failed (%d)\n", err)); + } else if (status) { + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_SRQ ,( "HW2SW_SRQ returned status 0x%02x\n", status)); + } + +err_out_free_buf: + if (!pd->ibpd.ucontext) + mthca_free_srq_buf(dev, srq); + +err_out_mailbox: + mthca_free_mailbox(dev, mailbox); + +err_out_db: + if (!pd->ibpd.ucontext && mthca_is_memfree(dev)) + mthca_free_db(dev, MTHCA_DB_TYPE_SRQ, srq->db_index); + +err_out_icm: + mthca_table_put(dev, dev->srq_table.table, srq->srqn); + +err_out: + mthca_free(&dev->srq_table.alloc, srq->srqn); + + return err; +} + +void mthca_free_srq(struct mthca_dev *dev, struct mthca_srq *srq) +{ + struct mthca_mailbox *mailbox; + int err; + u8 status; + SPIN_LOCK_PREP(lh); + + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (IS_ERR(mailbox)) { + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_SRQ ,( "No memory for mailbox to free SRQ.\n")); + return; + } + + err = mthca_HW2SW_SRQ(dev, mailbox, srq->srqn, &status); + if (err) { + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_SRQ ,( "HW2SW_SRQ failed (%d)\n", err)); + } else if (status) { + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_SRQ ,( "HW2SW_SRQ returned status 0x%02x\n", status)); + } + + spin_lock_irq(&dev->srq_table.lock, &lh); + mthca_array_clear(&dev->srq_table.srq, + srq->srqn & (dev->limits.num_srqs - 1)); + atomic_dec(&srq->refcount); + spin_unlock_irq(&lh); + + wait_event(&srq->wait, !atomic_read(&srq->refcount)); + + if (!srq->ibsrq.ucontext) { + mthca_free_srq_buf(dev, srq); + if (mthca_is_memfree(dev)) + mthca_free_db(dev, MTHCA_DB_TYPE_SRQ, srq->db_index); + } + + mthca_table_put(dev, dev->srq_table.table, srq->srqn); + mthca_free(&dev->srq_table.alloc, srq->srqn); + mthca_free_mailbox(dev, mailbox); +} + +int mthca_modify_srq(struct ib_srq *ibsrq, ib_srq_attr_t *attr, + ib_srq_attr_mask_t attr_mask) +{ + struct mthca_dev *dev = to_mdev(ibsrq->device); + struct mthca_srq *srq = to_msrq(ibsrq); + int ret; + u8 status; + + /* We don't support resizing SRQs (yet?) */ + if (attr_mask & IB_SRQ_MAX_WR) + return -ENOSYS; + + if (attr_mask & IB_SRQ_LIMIT) { + u32 max_wr = mthca_is_memfree(dev) ? srq->max - 1 : srq->max; + if (attr->srq_limit > max_wr) + return -ERANGE; + + down(&srq->mutex); + ret = mthca_ARM_SRQ(dev, srq->srqn, attr->srq_limit, &status); + up(&srq->mutex); + + if (ret) + return ret; + if (status) + return -EINVAL; + } + + return 0; +} + +int mthca_query_srq(struct ib_srq *ibsrq, ib_srq_attr_t *srq_attr) +{ + struct mthca_dev *dev = to_mdev(ibsrq->device); + struct mthca_srq *srq = to_msrq(ibsrq); + struct mthca_mailbox *mailbox; + struct mthca_arbel_srq_context *arbel_ctx; + struct mthca_tavor_srq_context *tavor_ctx; + u8 status; + int err; + + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + + err = mthca_QUERY_SRQ(dev, srq->srqn, mailbox, &status); + if (err) + goto out; + + if (mthca_is_memfree(dev)) { + arbel_ctx = mailbox->buf; + srq_attr->srq_limit = cl_ntoh16(arbel_ctx->limit_watermark); + } else { + tavor_ctx = mailbox->buf; + srq_attr->srq_limit = cl_ntoh16(tavor_ctx->limit_watermark); + } + + srq_attr->max_wr = (mthca_is_memfree(dev)) ? srq->max - 1 : srq->max; + srq_attr->max_sge = srq->max_gs; + +out: + mthca_free_mailbox(dev, mailbox); + + return err; +} + +void mthca_srq_event(struct mthca_dev *dev, u32 srqn, + enum ib_event_type event_type, u8 vendor_code) +{ + struct mthca_srq *srq; + ib_event_rec_t event; + SPIN_LOCK_PREP(lh); + + spin_lock(&dev->srq_table.lock, &lh); + srq = mthca_array_get(&dev->srq_table.srq, srqn & (dev->limits.num_srqs - 1)); + if (srq) + atomic_inc(&srq->refcount); + spin_unlock(&lh); + + if (!srq) { + HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_SRQ ,( "Async event for bogus SRQ %08x\n", srqn)); + return; + } + + if (!srq->ibsrq.event_handler) + goto out; + + event.type = event_type; + event.context = srq->ibsrq.srq_context; + event.vendor_specific = vendor_code; + HCA_PRINT(TRACE_LEVEL_WARNING,HCA_DBG_SRQ, + ("SRQ %06x Async event event_type 0x%x vendor_code 0x%x\n", + srqn,event_type,vendor_code)); + srq->ibsrq.event_handler(&event); + +out: + if (atomic_dec_and_test(&srq->refcount)) + wake_up(&srq->wait); +} + +/* + * This function must be called with IRQs disabled. + */ +void mthca_free_srq_wqe(struct mthca_srq *srq, u32 wqe_addr) +{ + int ind; + SPIN_LOCK_PREP(lh); + + ind = wqe_addr >> srq->wqe_shift; + + spin_lock(&srq->lock, &lh); + + if (likely(srq->first_free >= 0)) + *wqe_to_link(get_wqe(srq, srq->last_free)) = ind; + else + srq->first_free = ind; + + *wqe_to_link(get_wqe(srq, ind)) = -1; + srq->last_free = ind; + + spin_unlock(&lh); +} + +int mthca_tavor_post_srq_recv(struct ib_srq *ibsrq, struct _ib_recv_wr *wr, + struct _ib_recv_wr **bad_wr) +{ + struct mthca_dev *dev = to_mdev(ibsrq->device); + struct mthca_srq *srq = to_msrq(ibsrq); + __be32 doorbell[2]; + int err = 0; + int first_ind; + int ind; + int next_ind; + int nreq; + int i; + u8 *wqe; + u8 *prev_wqe; + CPU_2_BE64_PREP; + SPIN_LOCK_PREP(lh); + + spin_lock_irqsave(&srq->lock, &lh); + + first_ind = srq->first_free; + + for (nreq = 0; wr; wr = wr->p_next) { + ind = srq->first_free; + + if (ind < 0) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_SRQ ,( "SRQ %06x full\n", srq->srqn)); + err = -ENOMEM; + *bad_wr = wr; + break; + } + + wqe = get_wqe(srq, ind); + next_ind = *wqe_to_link(wqe); + + if (next_ind < 0) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_SRQ ,( "SRQ %06x full\n", srq->srqn)); + err = -ENOMEM; + *bad_wr = wr; + break; + } + + prev_wqe = srq->last; + srq->last = wqe; + + ((struct mthca_next_seg *) wqe)->nda_op = 0; + ((struct mthca_next_seg *) wqe)->ee_nds = 0; + /* flags field will always remain 0 */ + + wqe += sizeof (struct mthca_next_seg); + + if (unlikely((int)wr->num_ds > srq->max_gs)) { + err = -EINVAL; + *bad_wr = wr; + srq->last = prev_wqe; + break; + } + + for (i = 0; i < (int)wr->num_ds; ++i) { + ((struct mthca_data_seg *) wqe)->byte_count = + cl_hton32(wr->ds_array[i].length); + ((struct mthca_data_seg *) wqe)->lkey = + cl_hton32(wr->ds_array[i].lkey); + ((struct mthca_data_seg *) wqe)->addr = + CPU_2_BE64(wr->ds_array[i].vaddr); + wqe += sizeof (struct mthca_data_seg); + } + + if (i < srq->max_gs) { + ((struct mthca_data_seg *) wqe)->byte_count = 0; + ((struct mthca_data_seg *) wqe)->lkey = cl_hton32(MTHCA_INVAL_LKEY); + ((struct mthca_data_seg *) wqe)->addr = 0; + } + + ((struct mthca_next_seg *) prev_wqe)->nda_op = + cl_hton32((ind << srq->wqe_shift) | 1); + wmb(); + ((struct mthca_next_seg *) prev_wqe)->ee_nds = + cl_hton32(MTHCA_NEXT_DBD); + + srq->wrid[ind] = wr->wr_id; + srq->first_free = next_ind; + + ++nreq; + if (unlikely(nreq == MTHCA_TAVOR_MAX_WQES_PER_RECV_DB)) { + nreq = 0; + + doorbell[0] = cl_hton32(first_ind << srq->wqe_shift); + doorbell[1] = cl_hton32(srq->srqn << 8); + + /* + * Make sure that descriptors are written + * before doorbell is rung. + */ + wmb(); + + mthca_write64(doorbell, + dev->kar + MTHCA_RECV_DOORBELL, + MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock)); + + first_ind = srq->first_free; + } + } + + if (likely(nreq)) { + doorbell[0] = cl_hton32(first_ind << srq->wqe_shift); + doorbell[1] = cl_hton32((srq->srqn << 8) | nreq); + + /* + * Make sure that descriptors are written before + * doorbell is rung. + */ + wmb(); + + mthca_write64(doorbell, + dev->kar + MTHCA_RECV_DOORBELL, + MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock)); + } + + spin_unlock_irqrestore(&lh); + return err; +} + +int mthca_arbel_post_srq_recv(struct ib_srq *ibsrq, struct _ib_recv_wr *wr, + struct _ib_recv_wr **bad_wr) +{ + struct mthca_srq *srq = to_msrq(ibsrq); + int err = 0; + int ind; + int next_ind; + int nreq; + int i; + u8 *wqe; + CPU_2_BE64_PREP; + SPIN_LOCK_PREP(lh); + + spin_lock_irqsave(&srq->lock, &lh); + + for (nreq = 0; wr; ++nreq, wr = wr->p_next) { + ind = srq->first_free; + + if (ind < 0) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_SRQ ,( "SRQ %06x full\n", srq->srqn)); + err = -ENOMEM; + *bad_wr = wr; + break; + } + + wqe = get_wqe(srq, ind); + next_ind = *wqe_to_link(wqe); + + if (next_ind < 0) { + HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_SRQ ,( "SRQ %06x full\n", srq->srqn)); + err = -ENOMEM; + *bad_wr = wr; + break; + } + + ((struct mthca_next_seg *) wqe)->nda_op = + cl_hton32((next_ind << srq->wqe_shift) | 1); + ((struct mthca_next_seg *) wqe)->ee_nds = 0; + /* flags field will always remain 0 */ + + wqe += sizeof (struct mthca_next_seg); + + if (unlikely((int)wr->num_ds > srq->max_gs)) { + err = -EINVAL; + *bad_wr = wr; + break; + } + + for (i = 0; i < (int)wr->num_ds; ++i) { + ((struct mthca_data_seg *) wqe)->byte_count = + cl_hton32(wr->ds_array[i].length); + ((struct mthca_data_seg *) wqe)->lkey = + cl_hton32(wr->ds_array[i].lkey); + ((struct mthca_data_seg *) wqe)->addr = + CPU_2_BE64(wr->ds_array[i].vaddr); + wqe += sizeof (struct mthca_data_seg); + } + + if (i < srq->max_gs) { + ((struct mthca_data_seg *) wqe)->byte_count = 0; + ((struct mthca_data_seg *) wqe)->lkey = cl_hton32(MTHCA_INVAL_LKEY); + ((struct mthca_data_seg *) wqe)->addr = 0; + } + + srq->wrid[ind] = wr->wr_id; + srq->first_free = next_ind; + } + + if (likely(nreq)) { + srq->counter = (u16)(srq->counter + nreq); + + /* + * Make sure that descriptors are written before + * we write doorbell record. + */ + wmb(); + *srq->db = cl_hton32(srq->counter); + } + + spin_unlock_irqrestore(&lh); + return err; +} + +int mthca_max_srq_sge(struct mthca_dev *dev) +{ + if (mthca_is_memfree(dev)) + return dev->limits.max_sg; + + /* + * SRQ allocations are based on powers of 2 for Tavor, + * (although they only need to be multiples of 16 bytes). + * + * Therefore, we need to base the max number of sg entries on + * the largest power of 2 descriptor size that is <= to the + * actual max WQE descriptor size, rather than return the + * max_sg value given by the firmware (which is based on WQE + * sizes as multiples of 16, not powers of 2). + * + * If SRQ implementation is changed for Tavor to be based on + * multiples of 16, the calculation below can be deleted and + * the FW max_sg value returned. + */ + return min( (uint32_t)dev->limits.max_sg, + ((uint32_t)(1 << (fls(dev->limits.max_desc_sz) - 1)) - + sizeof (struct mthca_next_seg)) / + sizeof (struct mthca_data_seg)); +} + +int mthca_init_srq_table(struct mthca_dev *dev) +{ + int err; + + if (!(dev->mthca_flags & MTHCA_FLAG_SRQ)) + return 0; + + spin_lock_init(&dev->srq_table.lock); + + err = mthca_alloc_init(&dev->srq_table.alloc, + dev->limits.num_srqs, + dev->limits.num_srqs - 1, + dev->limits.reserved_srqs); + if (err) + return err; + + err = mthca_array_init(&dev->srq_table.srq, + dev->limits.num_srqs); + if (err) + mthca_alloc_cleanup(&dev->srq_table.alloc); + + return err; +} + +void mthca_cleanup_srq_table(struct mthca_dev *dev) +{ + if (!(dev->mthca_flags & MTHCA_FLAG_SRQ)) + return; + + mthca_array_cleanup(&dev->srq_table.srq, dev->limits.num_srqs); + mthca_alloc_cleanup(&dev->srq_table.alloc); +} diff --git a/branches/WOF2-3/hw/mthca/kernel/mthca_uar.c b/branches/WOF2-3/hw/mthca/kernel/mthca_uar.c new file mode 100644 index 00000000..b5bb7b3b --- /dev/null +++ b/branches/WOF2-3/hw/mthca/kernel/mthca_uar.c @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include "mthca_dev.h" +#include "mthca_memfree.h" + +int mthca_uar_alloc(struct mthca_dev *dev, struct mthca_uar *uar) +{ + uar->index = mthca_alloc(&dev->uar_table.alloc); + if (uar->index == -1) + return -ENOMEM; + + uar->pfn = (unsigned long)(pci_resource_start(dev, HCA_BAR_TYPE_UAR) >> PAGE_SHIFT) + uar->index; + + return 0; +} + +void mthca_uar_free(struct mthca_dev *dev, struct mthca_uar *uar) +{ + mthca_free(&dev->uar_table.alloc, uar->index); +} + +int mthca_init_uar_table(struct mthca_dev *dev) +{ + int ret; + + ret = mthca_alloc_init(&dev->uar_table.alloc, + dev->limits.num_uars, + dev->limits.num_uars - 1, + dev->limits.reserved_uars); + if (ret) + return ret; + + ret = mthca_init_db_tab(dev); + if (ret) + mthca_alloc_cleanup(&dev->uar_table.alloc); + + return ret; +} + +void mthca_cleanup_uar_table(struct mthca_dev *dev) +{ + mthca_cleanup_db_tab(dev); + + /* XXX check if any UARs are still allocated? */ + mthca_alloc_cleanup(&dev->uar_table.alloc); +} diff --git a/branches/WOF2-3/hw/mthca/mt_utils.c b/branches/WOF2-3/hw/mthca/mt_utils.c new file mode 100644 index 00000000..3d2124a8 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/mt_utils.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include + +/* Nth element of the table contains the index of the first set bit of N; 8 - for N=0 */ +char g_set_bit_tbl[256]; + +/* Nth element of the table contains the index of the first 0 bit of N; 8 - for N=255 */ +char g_clr_bit_tbl[256]; + +void fill_bit_tbls() +{ + unsigned long i; + for (i=0; i<256; ++i) { + g_set_bit_tbl[i] = (char)(_ffs_raw(&i,0) - 1); + g_clr_bit_tbl[i] = (char)(_ffz_raw(&i,0) - 1); + } + g_set_bit_tbl[0] = g_clr_bit_tbl[255] = 8; +} + + diff --git a/branches/WOF2-3/hw/mthca/mt_utils.h b/branches/WOF2-3/hw/mthca/mt_utils.h new file mode 100644 index 00000000..ddbcf389 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/mt_utils.h @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#ifndef MT_UTILS_H +#define MT_UTILS_H + +// Nth element of the table contains the index of the first set bit of N; 8 - for N=0 +extern char g_set_bit_tbl[256]; +// Nth element of the table contains the index of the first cleared bit of N; 8 - for N=0 +extern char g_clr_bit_tbl[256]; + +// DECLARE_BITMAP +#define BITS_PER_LONG 32 +#define BITS_TO_LONGS(bits) \ + (((bits)+BITS_PER_LONG-1)/BITS_PER_LONG) + +/* +* fls: find last bit set. +* returns: 0 - if not found or N+1, if found Nth bit +*/ + +static __inline int fls(int x) +{ + int r = 32; + + if (!x) + return 0; + if (!(x & 0xffff0000u)) { + x <<= 16; + r -= 16; + } + if (!(x & 0xff000000u)) { + x <<= 8; + r -= 8; + } + if (!(x & 0xf0000000u)) { + x <<= 4; + r -= 4; + } + if (!(x & 0xc0000000u)) { + x <<= 2; + r -= 2; + } + if (!(x & 0x80000000u)) { + x <<= 1; + r -= 1; + } + return r; +} + +/** +* _ffs_raw - find the first one bit in a word +* @addr: The address to start the search at +* @offset: The bitnumber to start searching at +* +* returns: 0 - if not found or N+1, if found Nth bit +*/ +static __inline int _ffs_raw(const unsigned long *addr, int offset) +{ + //TODO: not an effective code - is better in Assembler + int mask; + int rbc; + int ix; + if (!*addr) return 0; + mask = 1 << offset; + rbc = BITS_PER_LONG - offset; + for (ix=0; ix + +/* + * Make sure that all structs defined in this file remain laid out so + * that they pack the same way on 32-bit and 64-bit architectures (to + * avoid incompatibility between 32-bit userspace and 64-bit kernels). + * Specifically: + * - Do not use pointer types -- pass pointers in uint64_t instead. + * - Make sure that any structure larger than 4 bytes is padded to a + * multiple of 8 bytes. Otherwise the structure size will be + * different between 32-bit and 64-bit architectures. + */ + +struct ibv_get_context_resp { + uint64_t uar_addr; + uint64_t pd_handle; + uint32_t pdn; + uint32_t qp_tab_size; + uint32_t uarc_size; + uint32_t vend_id; + uint16_t dev_id; + uint16_t reserved[3]; +}; + +struct ibv_alloc_pd_resp { + uint64_t pd_handle; + uint32_t pdn; + uint32_t reserved; +}; + +struct ibv_reg_mr { + uint64_t start; + uint64_t length; + uint64_t hca_va; + uint32_t access_flags; + uint32_t pdn; + uint64_t pd_handle; +}; + +struct ibv_reg_mr_resp { + uint64_t mr_handle; + uint32_t lkey; + uint32_t rkey; +}; + +struct ibv_create_cq { + struct ibv_reg_mr mr; + uint64_t arm_db_page; + uint64_t set_db_page; + uint64_t u_arm_db_page; + uint64_t user_handle; + uint32_t arm_db_index; + uint32_t set_db_index; + uint32_t u_arm_db_index; + uint32_t cqe; + uint32_t lkey; /* used only by kernel */ + uint32_t reserved; +}; + +struct ibv_create_cq_resp { + uint64_t user_handle; + uint64_t cq_handle; + struct ibv_reg_mr_resp mr; + uint32_t cqe; + uint32_t cqn; +}; + +struct ibv_create_srq { + uint64_t user_handle; + struct ibv_reg_mr mr; + uint32_t lkey; /* used only in kernel */ + uint32_t db_index; + uint64_t db_page; +}; + +struct ibv_create_srq_resp { + struct ibv_reg_mr_resp mr; + uint64_t srq_handle; + uint64_t user_handle; + uint32_t max_wr; + uint32_t max_sge; + uint32_t srqn; + uint32_t reserved; +}; + +struct ibv_create_qp { + uint64_t sq_db_page; + uint64_t rq_db_page; + uint32_t sq_db_index; + uint32_t rq_db_index; + struct ibv_reg_mr mr; + uint64_t user_handle; + uint64_t send_cq_handle; + uint64_t recv_cq_handle; + uint64_t srq_handle; + uint32_t max_send_wr; + uint32_t max_recv_wr; + uint32_t max_send_sge; + uint32_t max_recv_sge; + uint32_t max_inline_data; + uint32_t lkey; /* used only in kernel */ + uint8_t sq_sig_all; + uint8_t qp_type; + uint8_t is_srq; + uint8_t reserved[5]; +}; + +struct ibv_create_qp_resp { + struct ibv_reg_mr_resp mr; + uint64_t user_handle; + uint64_t qp_handle; + uint32_t qpn; + uint32_t max_send_wr; + uint32_t max_recv_wr; + uint32_t max_send_sge; + uint32_t max_recv_sge; + uint32_t max_inline_data; +}; + +struct ibv_modify_qp_resp { + enum ibv_qp_attr_mask attr_mask; + uint8_t qp_state; + uint8_t reserved[3]; +}; + +struct ibv_create_ah { + uint64_t user_handle; + struct ibv_reg_mr mr; +}; + +struct ibv_create_ah_resp { + uint64_t user_handle; + uint64_t start; + struct ibv_reg_mr_resp mr; +}; + + +#endif /* MX_ABI_H */ + diff --git a/branches/WOF2-3/hw/mthca/user/Makefile b/branches/WOF2-3/hw/mthca/user/Makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/user/Makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\inc\openib.def diff --git a/branches/WOF2-3/hw/mthca/user/SOURCES b/branches/WOF2-3/hw/mthca/user/SOURCES new file mode 100644 index 00000000..55a9619c --- /dev/null +++ b/branches/WOF2-3/hw/mthca/user/SOURCES @@ -0,0 +1,87 @@ +TRUNK=..\..\.. + +!if $(FREEBUILD) +TARGETNAME=mthcau +!else +TARGETNAME=mthcaud +!endif + +TARGETPATH=$(TRUNK)\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE=DYNLINK +!if $(_NT_TOOLS_VERSION) == 0x700 +# DDK +DLLDEF=$O\mlnx_uvp.def +!else +# WDK +DLLDEF=$(OBJ_PATH)\$O\mlnx_uvp.def +!endif +#USE_NTDLL=1 +USE_MSVCRT=1 +DLLENTRY=DllMain + +!if $(FREEBUILD) +ENABLE_EVENT_TRACING=1 +!else +#ENABLE_EVENT_TRACING=1 +!endif + +SOURCES= \ + \ + ..\mt_utils.c \ + \ + mlnx_uvp.rc \ + mlnx_ual_av.c \ + mlnx_ual_ca.c \ + mlnx_ual_cq.c \ + mlnx_ual_main.c \ + mlnx_ual_mcast.c \ + mlnx_ual_mrw.c \ + mlnx_ual_osbypass.c \ + mlnx_ual_pd.c \ + mlnx_ual_qp.c \ + mlnx_ual_srq.c \ + \ + mlnx_uvp_debug.c \ + mlnx_uvp.c \ + mlnx_uvp_ah.c \ + mlnx_uvp_cq.c \ + mlnx_uvp_memfree.c \ + mlnx_uvp_qp.c \ + mlnx_uvp_srq.c \ + mlnx_uvp_verbs.c + +INCLUDES= \ + ..; \ + $(TRUNK)\inc\user; \ + $(TRUNK)\inc\complib; \ + $(TRUNK)\inc\user\complib; \ + $(TRUNK)\inc; \ + +USER_C_FLAGS=$(USER_C_FLAGS) /DCL_NO_TRACK_MEM + +TARGETLIBS=\ + $(SDK_LIB_PATH)\user32.lib \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\Advapi32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\complib.lib \ + $(TARGETPATH)\*\ibal.lib +!else + $(TARGETPATH)\*\complibd.lib \ + $(TARGETPATH)\*\ibald.lib +!endif + +#LINKER_FLAGS=/MAP /MAPINFO:LINES + +!IFDEF ENABLE_EVENT_TRACING + +C_DEFINES = $(C_DEFINES) -DEVENT_TRACING -DWPP_OLDCC + + +RUN_WPP= $(SOURCES) -ext:.c.h -dll\ + -scan:mlnx_uvp_debug.h \ + -func:UVP_PRINT(LEVEL,FLAGS,(MSG,...)) \ + -func:UVP_PRINT_EXIT(LEVEL,FLAGS,(MSG,...)) +!ENDIF + +MSC_WARNING_LEVEL= /W3 diff --git a/branches/WOF2-3/hw/mthca/user/arch.h b/branches/WOF2-3/hw/mthca/user/arch.h new file mode 100644 index 00000000..9f23be4b --- /dev/null +++ b/branches/WOF2-3/hw/mthca/user/arch.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#ifndef INFINIBAND_ARCH_H +#define INFINIBAND_ARCH_H + +#define htonll cl_hton64 +#define ntohll cl_ntoh64 + +/* + * Architecture-specific defines. Currently, an architecture is + * required to implement the following operations: + * + * mb() - memory barrier. No loads or stores may be reordered across + * this macro by either the compiler or the CPU. + */ + +#define mb MemoryBarrier +#define wmb MemoryBarrier +#define rmb MemoryBarrier + +#endif /* INFINIBAND_ARCH_H */ diff --git a/branches/WOF2-3/hw/mthca/user/mlnx_ual_av.c b/branches/WOF2-3/hw/mthca/user/mlnx_ual_av.c new file mode 100644 index 00000000..17dd8963 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/user/mlnx_ual_av.c @@ -0,0 +1,362 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2004-2005 Mellanox Technologies, Inc. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include "mt_l2w.h" +#include "mlnx_uvp.h" +#include "mx_abi.h" + +#include "mlnx_ual_main.h" +#if defined(EVENT_TRACING) +#include "mlnx_ual_av.tmh" +#endif + +static void +__post_create_av ( + IN const ib_pd_handle_t h_uvp_pd, + IN ib_api_status_t ioctl_status, + IN OUT ib_av_handle_t *ph_uvp_av, + IN OUT ci_umv_buf_t *p_umv_buf); + + +ib_api_status_t +map_itom_av_attr ( + IN const ib_av_attr_t *p_av_attr, + OUT struct ibv_ah_attr *p_attr) +{ + ib_api_status_t status = IB_SUCCESS; + + p_attr->sl = p_av_attr->sl; + p_attr->port_num = p_av_attr->port_num; + p_attr->dlid = CL_NTOH16 (p_av_attr->dlid); + p_attr->src_path_bits = p_av_attr->path_bits; // PATH: + + //TODO: how static_rate is coded ? + p_attr->static_rate = + (p_av_attr->static_rate == IB_PATH_RECORD_RATE_10_GBS ? 0 : 3); + + /* For global destination or Multicast address:*/ + if (p_av_attr->grh_valid) { + p_attr->is_global = TRUE; + p_attr->grh.hop_limit = p_av_attr->grh.hop_limit; + ib_grh_get_ver_class_flow( p_av_attr->grh.ver_class_flow, NULL, + &p_attr->grh.traffic_class, &p_attr->grh.flow_label ); + p_attr->grh.sgid_index = p_av_attr->grh.resv2; + cl_memcpy (p_attr->grh.dgid.raw, p_av_attr->grh.dest_gid.raw, + sizeof (IB_gid_t)); + }else{ + p_attr->is_global = FALSE; + } + + return status; +} + +static ib_api_status_t +__pre_create_av ( + IN const ib_pd_handle_t h_uvp_pd, + IN const ib_av_attr_t *p_av_attr, + IN OUT ci_umv_buf_t *p_umv_buf, + OUT ib_av_handle_t *ph_uvp_av) +{ + int err; + struct mthca_ah *ah; + struct ibv_ah_attr attr; + struct ibv_create_ah *p_create_av; + ib_api_status_t status = IB_SUCCESS; + size_t size = max( sizeof(struct ibv_create_ah), sizeof(struct ibv_create_ah_resp) ); + mlnx_ual_pd_info_t *p_pd = (mlnx_ual_pd_info_t *)h_uvp_pd; + mlnx_ual_hobul_t *p_hobul = p_pd->p_hobul; + + UNREFERENCED_PARAMETER(ph_uvp_av); + + UVP_ENTER(UVP_DBG_AV); + + CL_ASSERT(p_umv_buf); + + // convert parameters + cl_memset( &attr, 0, sizeof(attr)); + status = map_itom_av_attr (p_av_attr, &attr); + if(status != IB_SUCCESS ) + goto end; + + // allocate Ah object + ah = cl_zalloc( sizeof *ah ); + if( !ah ) { + status = IB_INSUFFICIENT_MEMORY; + goto end; + } + + // fill AH partly + ah->h_uvp_pd = h_uvp_pd; + cl_memcpy( &ah->av_attr, p_av_attr, sizeof(ah->av_attr) ); + + // try to create AV + err = mthca_alloc_av(to_mpd(p_pd->ibv_pd), &attr, ah, NULL); + if (err) { + UVP_PRINT(TRACE_LEVEL_ERROR ,UVP_DBG_AV , ("mthca_alloc_av failed (%d)\n", err)); + status = errno_to_iberr(err); + goto err_alloc_av; + } + + // allocate parameters + p_umv_buf->p_inout_buf = (ULONG_PTR)cl_zalloc( size ); + if( !p_umv_buf->p_inout_buf ) + { + status = IB_INSUFFICIENT_MEMORY; + goto err_mem; + } + + // fill the parameters + p_umv_buf->input_size = sizeof(struct ibv_create_ah); + p_umv_buf->output_size = sizeof(struct ibv_create_ah_resp); + p_umv_buf->command = TRUE; + p_create_av = (struct ibv_create_ah *)p_umv_buf->p_inout_buf; + p_create_av->user_handle = (uint64_t)(ULONG_PTR)ah; + if (ah->in_kernel) { + struct mthca_ah_page *page = ah->page; + p_create_av->mr.start = (uint64_t)(ULONG_PTR)page->buf; + p_create_av->mr.length = g_page_size; + p_create_av->mr.hca_va = (uint64_t)(ULONG_PTR)page->buf; + p_create_av->mr.pd_handle = p_pd->ibv_pd->handle; + p_create_av->mr.pdn = to_mpd(p_pd->ibv_pd)->pdn; + p_create_av->mr.access_flags = 0; //local read + status = IB_SUCCESS; + } + else { + __post_create_av(h_uvp_pd, IB_SUCCESS, ph_uvp_av, p_umv_buf); + status = IB_VERBS_PROCESSING_DONE; + } + goto end; + +err_mem: + mthca_free_av(ah); +err_alloc_av: + cl_free(ah); +end: + UVP_EXIT(UVP_DBG_AV); + return status; +} + + +static void +__post_create_av ( + IN const ib_pd_handle_t h_uvp_pd, + IN ib_api_status_t ioctl_status, + IN OUT ib_av_handle_t *ph_uvp_av, + IN OUT ci_umv_buf_t *p_umv_buf) +{ + int err; + struct mthca_ah *ah; + struct mthca_ah_page *page; + struct ibv_create_ah_resp *p_resp; + ib_api_status_t status = IB_SUCCESS; + mlnx_ual_pd_info_t *p_pd = (mlnx_ual_pd_info_t *)h_uvp_pd; + + UVP_ENTER(UVP_DBG_AV); + + CL_ASSERT(p_umv_buf); + + p_resp = (struct ibv_create_ah_resp *)p_umv_buf->p_inout_buf; + ah = (struct mthca_ah *)(ULONG_PTR)p_resp->user_handle; + + if (IB_SUCCESS == ioctl_status) { + + if (!mthca_is_memfree(p_pd->ibv_pd->context)) { + page = ah->page; + if (ah->in_kernel) { + // fill mr parameters + page->mr.handle = p_resp->mr.mr_handle; + page->mr.lkey = p_resp->mr.lkey; + page->mr.rkey = p_resp->mr.rkey; + page->mr.pd = p_pd->ibv_pd; + page->mr.context = p_pd->ibv_pd->context; + } + ah->key = page->mr.lkey; + } + *ph_uvp_av = (ib_av_handle_t)ah; + } + else { + mthca_free_av(ah); + cl_free(ah); + } + goto end; + +end: + if (p_resp) + cl_free( p_resp ); + UVP_EXIT(UVP_DBG_AV); +} + +static ib_api_status_t +__pre_query_av ( + IN const ib_av_handle_t h_uvp_av, + IN OUT ci_umv_buf_t *p_umv_buf ) +{ + UNREFERENCED_PARAMETER(h_uvp_av); + UNREFERENCED_PARAMETER(p_umv_buf); + UVP_ENTER(UVP_DBG_AV); + UVP_EXIT(UVP_DBG_AV); + return IB_VERBS_PROCESSING_DONE; +} + + +static void +__post_query_av ( + IN const ib_av_handle_t h_uvp_av, + IN ib_api_status_t ioctl_status, + IN OUT ib_av_attr_t *p_addr_vector, + IN OUT ib_pd_handle_t *ph_pd, + IN OUT ci_umv_buf_t *p_umv_buf) +{ + struct mthca_ah *ah = (struct mthca_ah *)h_uvp_av; + UNREFERENCED_PARAMETER(p_umv_buf); + + UVP_ENTER(UVP_DBG_AV); + CL_ASSERT(p_umv_buf); + CL_ASSERT(p_addr_vector); + + if (ioctl_status == IB_SUCCESS) + { + cl_memcpy (p_addr_vector, &ah->av_attr, sizeof (ib_av_attr_t)); + if (ph_pd) + *ph_pd = (ib_pd_handle_t)ah->h_uvp_pd; + } + + UVP_EXIT(UVP_DBG_AV); +} + +void mthca_set_av_params( struct mthca_ah *ah_p, struct ibv_ah_attr *ah_attr ); + +static ib_api_status_t +__pre_modify_av ( + IN const ib_av_handle_t h_uvp_av, + IN const ib_av_attr_t *p_addr_vector, + IN OUT ci_umv_buf_t *p_umv_buf) +{ + ib_api_status_t status ; + struct mthca_ah *mthca_ah = (struct mthca_ah *)h_uvp_av; + mlnx_ual_pd_info_t *p_pd_info; + mlnx_ual_hobul_t *p_hobul; + struct ibv_ah_attr attr; + + UNREFERENCED_PARAMETER(p_umv_buf); + + UVP_ENTER(UVP_DBG_AV); + + CL_ASSERT(p_umv_buf); + + p_pd_info = mthca_ah->h_uvp_pd; + CL_ASSERT (p_pd_info); + + p_hobul = p_pd_info->p_hobul; + CL_ASSERT (p_hobul); + + status = map_itom_av_attr (p_addr_vector, &attr); + if(status != IB_SUCCESS) return status; + + mthca_set_av_params( mthca_ah, &attr); + cl_memcpy (&mthca_ah->av_attr, p_addr_vector, sizeof(ib_av_attr_t)); + + UVP_EXIT(UVP_DBG_AV); + + return IB_VERBS_PROCESSING_DONE; +} + +static void +__post_modify_av ( + IN const ib_av_handle_t h_uvp_av, + IN ib_api_status_t ioctl_status, + IN OUT ci_umv_buf_t *p_umv_buf) +{ + UVP_ENTER(UVP_DBG_AV); + UVP_EXIT(UVP_DBG_AV); +} + + +static ib_api_status_t +__pre_destroy_av ( + IN const ib_av_handle_t h_uvp_av) +{ + ib_api_status_t status ; + struct mthca_ah *mthca_ah = (struct mthca_ah *)h_uvp_av; + UVP_ENTER(UVP_DBG_AV); + if (mthca_ah->in_kernel) + status = IB_SUCCESS; + else { + mthca_free_av(mthca_ah); + cl_free(mthca_ah); + status = IB_VERBS_PROCESSING_DONE; + } + UVP_EXIT(UVP_DBG_AV); + return status; +} + +static void +__post_destroy_av ( + IN const ib_av_handle_t h_uvp_av, + IN ib_api_status_t ioctl_status) +{ + struct mthca_ah *mthca_ah = (struct mthca_ah *)h_uvp_av; + + UVP_ENTER(UVP_DBG_AV); + CL_ASSERT (h_uvp_av); + + if (IB_SUCCESS == ioctl_status) { + mthca_free_av(mthca_ah); + cl_free(mthca_ah); + } + + UVP_EXIT(UVP_DBG_AV); + return; +} + +void +mlnx_get_av_interface ( + IN OUT uvp_interface_t *p_uvp ) +{ + + CL_ASSERT(p_uvp); + + /* + * Address Vector Management Verbs + */ + p_uvp->pre_create_av = __pre_create_av; + p_uvp->post_create_av = __post_create_av; + p_uvp->pre_query_av = __pre_query_av; + p_uvp->post_query_av = __post_query_av; + p_uvp->pre_modify_av = __pre_modify_av; + p_uvp->post_modify_av = __post_modify_av; + p_uvp->pre_destroy_av = __pre_destroy_av; + p_uvp->post_destroy_av = __post_destroy_av; + +} + diff --git a/branches/WOF2-3/hw/mthca/user/mlnx_ual_ca.c b/branches/WOF2-3/hw/mthca/user/mlnx_ual_ca.c new file mode 100644 index 00000000..4cea6bd1 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/user/mlnx_ual_ca.c @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2004-2005 Mellanox Technologies, Inc. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include "mlnx_ual_main.h" +#include "mt_l2w.h" +#include "mlnx_uvp.h" +#include "mlnx_uvp_verbs.h" +#include "mx_abi.h" + +#if defined(EVENT_TRACING) +#include "mlnx_ual_ca.tmh" +#endif + +extern uint32_t mlnx_dbg_lvl; + +static ib_api_status_t +__pre_open_ca ( + IN const ib_net64_t ca_guid, + IN OUT ci_umv_buf_t *p_umv_buf, + OUT ib_ca_handle_t *ph_uvp_ca) +{ + ib_api_status_t status = IB_SUCCESS; + + UNREFERENCED_PARAMETER(ph_uvp_ca); + + UVP_ENTER(UVP_DBG_SHIM); + if( p_umv_buf ) + { + p_umv_buf->p_inout_buf = (ULONG_PTR)cl_zalloc( sizeof(struct ibv_get_context_resp) ); + if( !p_umv_buf->p_inout_buf ) + { + status = IB_INSUFFICIENT_MEMORY; + goto err_memory; + } + p_umv_buf->input_size = p_umv_buf->output_size = sizeof(struct ibv_get_context_resp); + p_umv_buf->command = TRUE; + } +err_memory: + UVP_EXIT(UVP_DBG_SHIM); + return IB_SUCCESS; +} + + +static ib_api_status_t +__post_open_ca ( + IN const ib_net64_t ca_guid, + IN ib_api_status_t ioctl_status, + IN OUT ib_ca_handle_t *ph_uvp_ca, + IN ci_umv_buf_t *p_umv_buf ) +{ + ib_api_status_t status = ioctl_status; + mlnx_ual_hobul_t *new_ca; + struct ibv_get_context_resp *p_resp; + struct ibv_context * ibvcontext; + int err; + + UVP_ENTER(UVP_DBG_SHIM); + + p_resp = (struct ibv_get_context_resp *)p_umv_buf->p_inout_buf; + + if (IB_SUCCESS == status) { + /* allocate ibv context */ + ibvcontext = mthca_alloc_context(p_resp); + if (IS_ERR(ibvcontext)) { + err = PTR_ERR(ibvcontext); + UVP_PRINT(TRACE_LEVEL_ERROR ,UVP_DBG_SHIM ,("mthca_alloc_context failed (%d)\n", err)); + status = errno_to_iberr(err); + goto err_alloc_context; + } + + /* allocate mthca context */ + new_ca = (mlnx_ual_hobul_t *)cl_zalloc( sizeof(mlnx_ual_hobul_t) ); + if( !new_ca ) { + status = IB_INSUFFICIENT_MEMORY; + goto err_memory; + } + + /* return results */ + new_ca->ibv_ctx = ibvcontext; + *ph_uvp_ca = (ib_ca_handle_t)new_ca; + } + +err_memory: +err_alloc_context: + if (p_resp) + cl_free( p_resp ); + UVP_EXIT(UVP_DBG_SHIM); + return status; +} + + +static ib_api_status_t +__pre_modify_ca ( + IN ib_ca_handle_t h_uvp_ca, + IN uint8_t port_num, + IN ib_ca_mod_t ca_mod, + IN const ib_port_attr_mod_t* p_port_attr_mod) +{ + UVP_ENTER(UVP_DBG_SHIM); + UVP_EXIT(UVP_DBG_SHIM); + return IB_SUCCESS; +} + + +static void +__post_modify_ca ( + IN ib_ca_handle_t h_uvp_ca, + IN ib_api_status_t ioctl_status) +{ + UVP_ENTER(UVP_DBG_SHIM); + UVP_EXIT(UVP_DBG_SHIM); +} + + +static ib_api_status_t +__pre_close_ca ( + IN ib_ca_handle_t h_uvp_ca) +{ + UVP_ENTER(UVP_DBG_SHIM); + UVP_EXIT(UVP_DBG_SHIM); + return IB_SUCCESS; +} + + +static ib_api_status_t +__post_close_ca ( + IN ib_ca_handle_t h_uvp_ca, + IN ib_api_status_t ioctl_status ) +{ + mlnx_ual_hobul_t *p_hobul = (mlnx_ual_hobul_t *)((void*)h_uvp_ca); + + UVP_ENTER(UVP_DBG_SHIM); + + CL_ASSERT(p_hobul); + + if (IB_SUCCESS == ioctl_status) { + if (p_hobul->ibv_ctx) { + mthca_free_context(p_hobul->ibv_ctx); + p_hobul->ibv_ctx = NULL; + } + + cl_free(p_hobul); + } + + UVP_EXIT(UVP_DBG_SHIM); + return IB_SUCCESS; +} + +void +mlnx_get_ca_interface ( + IN OUT uvp_interface_t *p_uvp ) +{ + CL_ASSERT(p_uvp); + + /* + * HCA Access Verbs + */ + p_uvp->pre_open_ca = __pre_open_ca; + p_uvp->post_open_ca = __post_open_ca; + + + p_uvp->pre_query_ca = NULL; + p_uvp->post_query_ca = NULL; + + p_uvp->pre_modify_ca = NULL; + p_uvp->post_modify_ca = NULL; + + p_uvp->pre_close_ca = __pre_close_ca; + p_uvp->post_close_ca = __post_close_ca; + +} + + diff --git a/branches/WOF2-3/hw/mthca/user/mlnx_ual_cq.c b/branches/WOF2-3/hw/mthca/user/mlnx_ual_cq.c new file mode 100644 index 00000000..28f223dc --- /dev/null +++ b/branches/WOF2-3/hw/mthca/user/mlnx_ual_cq.c @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2004-2005 Mellanox Technologies, Inc. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include "mt_l2w.h" +#include "mlnx_ual_main.h" +#include "mlnx_uvp.h" +#include "mx_abi.h" + +#if defined(EVENT_TRACING) +#include "mlnx_ual_cq.tmh" +#endif + + +extern uint32_t mlnx_dbg_lvl; + +static ib_api_status_t +__pre_create_cq ( + IN const ib_ca_handle_t h_uvp_ca, + IN OUT uint32_t* const p_size, + IN OUT ci_umv_buf_t *p_umv_buf, + OUT ib_cq_handle_t *ph_uvp_cq) +{ + struct ibv_cq *ibv_cq; + ib_api_status_t status = IB_SUCCESS; + size_t size = max( sizeof(struct ibv_create_cq), sizeof(struct ibv_create_cq_resp) ); + mlnx_ual_hobul_t *p_hobul = (mlnx_ual_hobul_t *)((void *)h_uvp_ca); + struct ibv_create_cq *p_create_cq; + int err; + + UVP_ENTER(UVP_DBG_CQ); + + CL_ASSERT(p_umv_buf); + + p_umv_buf->p_inout_buf = (ULONG_PTR)cl_zalloc( size ); + if( !p_umv_buf->p_inout_buf ) + { + status = IB_INSUFFICIENT_MEMORY; + goto err_memory; + } + p_umv_buf->input_size = sizeof(struct ibv_create_cq); + p_umv_buf->output_size = sizeof(struct ibv_create_cq_resp); + p_umv_buf->command = TRUE; + + /* allocate ibv_cq */ + p_create_cq = (struct ibv_create_cq *)p_umv_buf->p_inout_buf; + ibv_cq = p_hobul->ibv_ctx->ops.create_cq_pre(p_hobul->ibv_ctx, p_size, p_create_cq); + if (IS_ERR(ibv_cq)) { + err = PTR_ERR(ibv_cq); + UVP_PRINT(TRACE_LEVEL_ERROR ,UVP_DBG_CQ , ("mthca_alloc_cq_pre failed (%d)\n", err)); + status = (err == -ENOMEM) ? IB_INVALID_CQ_SIZE : errno_to_iberr(err); + goto err_alloc_cq; + } + + *ph_uvp_cq = (ib_cq_handle_t)(ULONG_PTR)p_create_cq->user_handle; + goto end; + +err_alloc_cq: + cl_free((void*)(ULONG_PTR)p_umv_buf->p_inout_buf); +err_memory: +end: + UVP_EXIT(UVP_DBG_CQ); + return status; +} + + +static void +__post_create_cq ( + IN const ib_ca_handle_t h_uvp_ca, + IN ib_api_status_t ioctl_status, + IN const uint32_t size, + IN OUT ib_cq_handle_t *ph_uvp_cq, + IN ci_umv_buf_t *p_umv_buf ) +{ + int err; + ib_api_status_t status = IB_SUCCESS; + struct ibv_create_cq_resp *p_resp; + struct ibv_cq *ibv_cq; + mlnx_ual_hobul_t *p_hobul = (mlnx_ual_hobul_t *)((void *)h_uvp_ca); + + + UVP_ENTER(UVP_DBG_CQ); + + CL_ASSERT(p_hobul); + CL_ASSERT(p_umv_buf); + p_resp = (struct ibv_create_cq_resp *)p_umv_buf->p_inout_buf; + + if (IB_SUCCESS == ioctl_status) { + + /* allocate ibv_cq */ + ibv_cq = p_hobul->ibv_ctx->ops.create_cq_post(p_hobul->ibv_ctx, p_resp); + if (IS_ERR(ibv_cq)) { + err = PTR_ERR(ibv_cq); + UVP_PRINT(TRACE_LEVEL_ERROR ,UVP_DBG_CQ , ("mthca_create_cq failed (%d)\n", err)); + status = errno_to_iberr(err); + goto err_create_cq; + } + + *ph_uvp_cq = (ib_cq_handle_t)ibv_cq; + } + else { + ibv_cq = (struct ibv_cq *)*ph_uvp_cq; + ibv_cq->context = h_uvp_ca->ibv_ctx; + ibv_cq->context->ops.destroy_cq( ibv_cq ); + *ph_uvp_cq = NULL; + } + +err_create_cq: + if (p_resp) + cl_free( p_resp ); + UVP_EXIT(UVP_DBG_CQ); + return; +} + + +static ib_api_status_t +__pre_query_cq ( + IN const ib_cq_handle_t h_uvp_cq, + OUT uint32_t* const p_size, + IN OUT ci_umv_buf_t *p_umv_buf) +{ + struct ibv_cq *ibv_cq = (struct ibv_cq *)h_uvp_cq; + + UVP_ENTER(UVP_DBG_CQ); + + *p_size = ibv_cq->cqe; + + UVP_EXIT(UVP_DBG_CQ); + return IB_VERBS_PROCESSING_DONE; +} + + +static ib_api_status_t +__pre_destroy_cq ( + IN const ib_cq_handle_t h_uvp_cq) +{ + UVP_ENTER(UVP_DBG_CQ); + UVP_EXIT(UVP_DBG_CQ); + return IB_SUCCESS; +} + +static void +__post_destroy_cq ( + IN const ib_cq_handle_t h_uvp_cq, + IN ib_api_status_t ioctl_status) +{ + int err; + struct ibv_cq *ibv_cq = (struct ibv_cq *)h_uvp_cq; + UNREFERENCED_PARAMETER(ioctl_status); + + UVP_ENTER(UVP_DBG_CQ); + + CL_ASSERT(ibv_cq); + + if (IB_SUCCESS == ioctl_status) { + err = ibv_cq->context->ops.destroy_cq( ibv_cq ); + if (err) + UVP_PRINT(TRACE_LEVEL_ERROR ,UVP_DBG_CQ, ("mthca_destroy_cq failed (%d)\n", err)); + //cl_free (p_cq_info); + } + + UVP_EXIT(UVP_DBG_CQ); +} + +void +mlnx_get_cq_interface ( + IN OUT uvp_interface_t *p_uvp ) +{ + UVP_ENTER(UVP_DBG_DEV); + + CL_ASSERT(p_uvp); + + /* + * Completion Queue Management Verbs + */ + p_uvp->pre_create_cq = __pre_create_cq; + p_uvp->post_create_cq = __post_create_cq; + + p_uvp->pre_query_cq = __pre_query_cq; + p_uvp->post_query_cq = NULL; + + p_uvp->pre_resize_cq = NULL; /* __pre_resize_cq: not supported in kernel */ + p_uvp->post_resize_cq = NULL; /* __post_resize_cq:not supported in kernel */ + + p_uvp->pre_destroy_cq = __pre_destroy_cq; + p_uvp->post_destroy_cq = __post_destroy_cq; + + UVP_EXIT(UVP_DBG_DEV); +} + + diff --git a/branches/WOF2-3/hw/mthca/user/mlnx_ual_data.h b/branches/WOF2-3/hw/mthca/user/mlnx_ual_data.h new file mode 100644 index 00000000..d57d4b07 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/user/mlnx_ual_data.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ +#include +#include + +// taken from ib_defs.h +typedef uint32_t IB_wqpn_t; /* Work QP number: Only 24 LSbits */ +typedef uint8_t IB_port_t; +typedef uint8_t IB_gid_t[16]; /* GID (aka IPv6) H-to-L (big) (network) endianess */ +typedef uint32_t IB_ts_t; + +typedef struct _ib_ca +{ + struct ibv_context *ibv_ctx; +} mlnx_ual_hobul_t; + + +typedef struct _ib_pd +{ + struct ibv_pd *ibv_pd; + mlnx_ual_hobul_t *p_hobul; +} mlnx_ual_pd_info_t; + diff --git a/branches/WOF2-3/hw/mthca/user/mlnx_ual_main.c b/branches/WOF2-3/hw/mthca/user/mlnx_ual_main.c new file mode 100644 index 00000000..35a949e0 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/user/mlnx_ual_main.c @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2004-2005 Mellanox Technologies, Inc. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include +#include +#include +#include "mlnx_ual_main.h" + +#if defined(EVENT_TRACING) +#include "mlnx_ual_main.tmh" +#endif + + +uint32_t mlnx_dbg_lvl = 0; // MLNX_TRACE_LVL_8; + +static void uvp_init(); + +extern BOOL APIENTRY +_DllMainCRTStartupForGS( + IN HINSTANCE h_module, + IN DWORD ul_reason_for_call, + IN LPVOID lp_reserved ); + + +BOOL APIENTRY +DllMain( + IN HINSTANCE h_module, + IN DWORD ul_reason_for_call, + IN LPVOID lp_reserved ) +{ + switch( ul_reason_for_call ) + { + case DLL_PROCESS_ATTACH: +#if defined(EVENT_TRACING) +#if DBG + WPP_INIT_TRACING(L"mthcaud.dll"); +#else + WPP_INIT_TRACING(L"mthcau.dll"); +#endif +#endif + if( !_DllMainCRTStartupForGS( + h_module, ul_reason_for_call, lp_reserved ) ) + { + return FALSE; + } + + fill_bit_tbls(); + uvp_init(); + break; + + case DLL_PROCESS_DETACH: + // The calling process is detaching + // the DLL from its address space. + // + // Note that lpvReserved will be NULL if the detach is due to + // a FreeLibrary() call, and non-NULL if the detach is due to + // process cleanup. + // +#if defined(EVENT_TRACING) + WPP_CLEANUP(); +#endif + + default: + return _DllMainCRTStartupForGS( + h_module, ul_reason_for_call, lp_reserved ); + } + return TRUE; +} + + +/* + * UVP Shared Library Init routine +*/ + +static void +uvp_init() +{ + +#if !defined(EVENT_TRACING) +#if DBG +#define ENV_BUFSIZE 16 + TCHAR dbg_lvl_str[ENV_BUFSIZE]; + DWORD i; + + + i = GetEnvironmentVariable( "UVP_DBG_LEVEL", dbg_lvl_str, ENV_BUFSIZE ); + if( i && i <= 16 ) + { + g_mlnx_dbg_level = _tcstoul( dbg_lvl_str, NULL, ENV_BUFSIZE ); + } + + i = GetEnvironmentVariable( "UVP_DBG_FLAGS", dbg_lvl_str, ENV_BUFSIZE ); + if( i && i <= 16 ) + { + g_mlnx_dbg_flags = _tcstoul( dbg_lvl_str, NULL, ENV_BUFSIZE ); + } + + + UVP_PRINT(TRACE_LEVEL_INFORMATION ,UVP_DBG_DEV , + ("Given UVP_DBG debug level:%d debug flags 0x%x\n", + g_mlnx_dbg_level ,g_mlnx_dbg_flags) ); + +#endif +#endif +} + +__declspec(dllexport) ib_api_status_t +uvp_get_interface ( + IN GUID iid, + IN void* pifc) +{ + ib_api_status_t status = IB_SUCCESS; + + UVP_ENTER(UVP_DBG_SHIM); + + if (IsEqualGUID(&iid, &IID_UVP)) + { + mlnx_get_ca_interface((uvp_interface_t *) pifc); + mlnx_get_pd_interface((uvp_interface_t *) pifc); + mlnx_get_srq_interface((uvp_interface_t *) pifc); + mlnx_get_qp_interface((uvp_interface_t *) pifc); + mlnx_get_cq_interface((uvp_interface_t *) pifc); + mlnx_get_av_interface((uvp_interface_t *) pifc); + mlnx_get_mrw_interface((uvp_interface_t *) pifc); + mlnx_get_mcast_interface((uvp_interface_t *) pifc); + mlnx_get_osbypass_interface((uvp_interface_t *) pifc); + } + else + { + status = IB_UNSUPPORTED; + } + + UVP_EXIT(UVP_DBG_SHIM); + return status; +} diff --git a/branches/WOF2-3/hw/mthca/user/mlnx_ual_main.h b/branches/WOF2-3/hw/mthca/user/mlnx_ual_main.h new file mode 100644 index 00000000..9d717d8f --- /dev/null +++ b/branches/WOF2-3/hw/mthca/user/mlnx_ual_main.h @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2004-2005 Mellanox Technologies, Inc. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#ifndef __UAL_MAIN_H__ +#define __UAL_MAIN_H__ + +#include +#include +#include + +//#include +#include "mlnx_ual_data.h" +#include "mlnx_uvp_debug.h" +#include +#include +//#include + + +#define MAX_WRS_PER_CHAIN 16 +#define MAX_NUM_SGE 32 + +#define MLNX_SGE_SIZE 16 +#define MLNX_UAL_ALLOC_HCA_UL_RES 1 +#define MLNX_UAL_FREE_HCA_UL_RES 2 + +typedef unsigned __int3264 cl_dev_handle_t; + +extern uint32_t mlnx_dbg_lvl; +static inline errno_to_iberr(int err) +{ +#define MAP_ERR(err,ibstatus) case err: ib_status = ibstatus; break + ib_api_status_t ib_status = IB_UNKNOWN_ERROR; + if (err < 0) + err = -err; + switch (err) { + MAP_ERR( ENOENT, IB_NOT_FOUND ); + MAP_ERR( EINTR, IB_INTERRUPTED ); + MAP_ERR( EAGAIN, IB_RESOURCE_BUSY ); + MAP_ERR( ENOMEM, IB_INSUFFICIENT_MEMORY ); + MAP_ERR( EACCES, IB_INVALID_PERMISSION ); + MAP_ERR( EFAULT, IB_ERROR ); + MAP_ERR( EBUSY, IB_RESOURCE_BUSY ); + MAP_ERR( ENODEV, IB_UNSUPPORTED ); + MAP_ERR( EINVAL, IB_INVALID_PARAMETER ); + MAP_ERR( ENOSYS, IB_UNSUPPORTED ); + default: + CL_TRACE (CL_DBG_ERROR, mlnx_dbg_lvl, ("Unmapped errno (%d)\n", err)); + break; + } + return ib_status; +} + + + + +/* + * PROTOTYPES + */ + +/************* CA operations *************************/ +void +mlnx_get_ca_interface ( + IN OUT uvp_interface_t *p_uvp ); + +/************* PD Management *************************/ +void +mlnx_get_pd_interface ( + IN OUT uvp_interface_t *p_uvp ); + +/************* AV Management *************************/ +void +mlnx_get_av_interface ( + IN OUT uvp_interface_t *p_uvp ); + +/************* CQ Management *************************/ +void +mlnx_get_cq_interface ( + IN OUT uvp_interface_t *p_uvp ); + +/************* SRQ Management *************************/ +void +mlnx_get_srq_interface ( + IN OUT uvp_interface_t *p_uvp ); + +/************* QP Management *************************/ +void +mlnx_get_qp_interface ( + IN OUT uvp_interface_t *p_uvp ); + +/************* MR/MW Management *************************/ +void +mlnx_get_mrw_interface ( + IN OUT uvp_interface_t *p_uvp ); + +/************* MCAST Management *************************/ +void +mlnx_get_mcast_interface ( + IN OUT uvp_interface_t *p_uvp ); + +/************* OS BYPASS Management *************************/ +void +mlnx_get_osbypass_interface ( + IN OUT uvp_interface_t *p_uvp ); + +#endif diff --git a/branches/WOF2-3/hw/mthca/user/mlnx_ual_mcast.c b/branches/WOF2-3/hw/mthca/user/mlnx_ual_mcast.c new file mode 100644 index 00000000..78c8f0fd --- /dev/null +++ b/branches/WOF2-3/hw/mthca/user/mlnx_ual_mcast.c @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2004-2005 Mellanox Technologies, Inc. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include "mlnx_ual_main.h" + +#if defined(EVENT_TRACING) +#include "mlnx_ual_mcast.tmh" +#endif + +static ib_api_status_t +__pre_attach_mcast ( + IN const ib_qp_handle_t h_uvp_qp, + IN const ib_gid_t *p_mcast_gid, + IN const uint16_t mcast_lid, + IN OUT ci_umv_buf_t *p_umv_buf, + OUT ib_mcast_handle_t *ph_mcast) +{ + UNREFERENCED_PARAMETER(ph_mcast); + + UVP_ENTER(UVP_DBG_SHIM); + CL_ASSERT(p_umv_buf); + p_umv_buf->p_inout_buf = 0;; + p_umv_buf->input_size = 0; + p_umv_buf->output_size = 0; + p_umv_buf->command = TRUE; + + UVP_EXIT(UVP_DBG_SHIM); + return IB_SUCCESS; +} + + + +static void +__post_attach_mcast ( + IN const ib_qp_handle_t h_uvp_qp, + IN ib_api_status_t ioctl_status, + IN OUT ib_mcast_handle_t *ph_mcast, + IN OUT ci_umv_buf_t *p_umv_buf) +{ + UVP_ENTER(UVP_DBG_SHIM); + UVP_EXIT(UVP_DBG_SHIM); +} + + + +static ib_api_status_t +__pre_detach_mcast ( + IN ib_mcast_handle_t h_uvp_mcast, + IN OUT ci_umv_buf_t *p_umv_buf) +{ + UVP_ENTER(UVP_DBG_SHIM); + + CL_ASSERT(p_umv_buf); + p_umv_buf->p_inout_buf = 0; + p_umv_buf->input_size = 0; + p_umv_buf->output_size = 0; + + UVP_EXIT(UVP_DBG_SHIM); + return IB_SUCCESS; +} + + +static void +__post_detach_mcast ( + IN ib_mcast_handle_t h_uvp_mcast, + IN ib_api_status_t ioctl_status, + IN OUT ci_umv_buf_t *p_umv_buf) +{ + UVP_ENTER(UVP_DBG_SHIM); + UVP_EXIT(UVP_DBG_SHIM); +} + +void +mlnx_get_mcast_interface ( + IN OUT uvp_interface_t *p_uvp ) +{ + UVP_ENTER(UVP_DBG_SHIM); + + CL_ASSERT(p_uvp); + + /* + * Multicast Support Verbs + */ + p_uvp->pre_attach_mcast = NULL; + p_uvp->post_attach_mcast = NULL; + p_uvp->pre_detach_mcast = NULL; + p_uvp->post_detach_mcast = NULL; + + UVP_EXIT(UVP_DBG_SHIM); +} + + diff --git a/branches/WOF2-3/hw/mthca/user/mlnx_ual_mrw.c b/branches/WOF2-3/hw/mthca/user/mlnx_ual_mrw.c new file mode 100644 index 00000000..635ff32f --- /dev/null +++ b/branches/WOF2-3/hw/mthca/user/mlnx_ual_mrw.c @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2004-2005 Mellanox Technologies, Inc. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include "mlnx_ual_main.h" +#if defined(EVENT_TRACING) +#include "mlnx_ual_mrw.tmh" +#endif + + + +static ib_api_status_t +__pre_register_mr ( + IN const ib_pd_handle_t h_uvp_pd, + IN const ib_mr_create_t *p_mr_create, + IN OUT ci_umv_buf_t *p_umv_buf, + OUT ib_mr_handle_t *ph_uvp_mr) +{ + UNREFERENCED_PARAMETER(ph_uvp_mr); + + UVP_ENTER(UVP_DBG_SHIM); + CL_ASSERT(p_umv_buf); + p_umv_buf->p_inout_buf = 0; + p_umv_buf->input_size = 0; + p_umv_buf->output_size = 0; + + UVP_EXIT(UVP_DBG_SHIM); + return IB_SUCCESS; +} + + +static void +__post_register_mr ( + IN const ib_pd_handle_t h_uvp_pd, + IN ib_api_status_t ioctl_status, + IN const uint32_t *p_lkey, + IN const uint32_t *p_rkey, + IN OUT const ib_mr_handle_t *ph_uvp_mr, + IN OUT ci_umv_buf_t *p_umv_buf) +{ + UVP_ENTER(UVP_DBG_SHIM); + UVP_EXIT(UVP_DBG_SHIM); + return; +} + + +static ib_api_status_t +__pre_query_mr ( + IN const ib_mr_handle_t h_uvp_mr, + IN OUT ci_umv_buf_t *p_umv_buf) +{ + UVP_ENTER(UVP_DBG_SHIM); + CL_ASSERT(p_umv_buf); + p_umv_buf->p_inout_buf = 0; + p_umv_buf->input_size = 0; + p_umv_buf->output_size = 0; + + UVP_EXIT(UVP_DBG_SHIM); + return IB_SUCCESS; +} + + +static void +__post_query_mr ( + IN const ib_mr_handle_t h_uvp_mr, + IN ib_api_status_t ioctl_status, + IN const ib_mr_attr_t *p_mr_query, + IN OUT ci_umv_buf_t *p_umv_buf) +{ + UVP_ENTER(UVP_DBG_SHIM); + UVP_EXIT(UVP_DBG_SHIM); + return; +} + + +static ib_api_status_t +__pre_modify_mr ( + IN const ib_mr_handle_t h_uvp_mr, + IN const ib_pd_handle_t h_uvp_pd OPTIONAL, + IN const ib_mr_mod_t mr_mod_mask, + IN const ib_mr_create_t *p_mr_create OPTIONAL, + IN OUT ci_umv_buf_t *p_umv_buf) +{ + UVP_ENTER(UVP_DBG_SHIM); + CL_ASSERT(p_umv_buf); + p_umv_buf->p_inout_buf = 0; + p_umv_buf->input_size = 0; + p_umv_buf->output_size = 0; + + UVP_EXIT(UVP_DBG_SHIM); + return IB_SUCCESS; +} + + +static void +__post_modify_mr ( + IN const ib_mr_handle_t h_uvp_mr, + IN const ib_pd_handle_t h_uvp_pd OPTIONAL, + IN ib_api_status_t ioctl_status, + IN const uint32_t *p_lkey, + IN const uint32_t *p_rkey, + IN OUT ci_umv_buf_t *p_umv_buf) +{ + UVP_ENTER(UVP_DBG_SHIM); + UVP_EXIT(UVP_DBG_SHIM); + return; +} + + +static ib_api_status_t +__pre_register_smr ( + IN const ib_pd_handle_t h_uvp_pd, + IN const ib_mr_handle_t h_uvp_mr, + IN const ib_access_t access_ctrl, + IN void *p_vaddr, + IN OUT ci_umv_buf_t *p_umv_buf) +{ + UVP_ENTER(UVP_DBG_SHIM); + CL_ASSERT(p_umv_buf); + p_umv_buf->p_inout_buf = 0; + p_umv_buf->input_size = 0; + p_umv_buf->output_size = 0; + + UVP_EXIT(UVP_DBG_SHIM); + return IB_SUCCESS; +} + + +static void +__post_register_smr ( + IN const ib_pd_handle_t h_uvp_pd, + IN const ib_mr_handle_t h_uvp_mr, + IN ib_api_status_t ioctl_status, + IN const void *p_vaddr, + IN const uint32_t *p_lkey, + IN const uint32_t *p_rkey, + OUT const ib_mr_handle_t *ph_uvp_smr, + IN OUT ci_umv_buf_t *p_umv_buf) +{ + UVP_ENTER(UVP_DBG_SHIM); + UVP_EXIT(UVP_DBG_SHIM); + return; +} + + +static ib_api_status_t +__pre_deregister_mr ( + IN const ib_mr_handle_t h_uvp_mr, + IN OUT ci_umv_buf_t *p_umv_buf) +{ + UVP_ENTER(UVP_DBG_SHIM); + UVP_EXIT(UVP_DBG_SHIM); + return IB_SUCCESS; +} + + +static void +__post_deregister_mr ( + IN const ib_mr_handle_t h_uvp_mr, + IN OUT ci_umv_buf_t *p_umv_buf) +{ + UVP_ENTER(UVP_DBG_SHIM); + UVP_EXIT(UVP_DBG_SHIM); + return; +} + +void +mlnx_get_mrw_interface ( + IN OUT uvp_interface_t *p_uvp ) +{ + UVP_ENTER(UVP_DBG_SHIM); + + CL_ASSERT(p_uvp); + + /* + * Memory Management Verbs + */ +// p_uvp->pre_register_mr = NULL; +// p_uvp->post_register_mr = NULL; +// p_uvp->pre_query_mr = NULL; +// p_uvp->post_query_mr = NULL; +// p_uvp->pre_deregister_mr = NULL; +// p_uvp->post_deregister_mr = NULL; +// p_uvp->pre_modify_mr = NULL; +// p_uvp->post_modify_mr = NULL; +// p_uvp->pre_register_smr = NULL; +// p_uvp->post_register_smr = NULL; + + /* + * Memory Window Verbs + */ + p_uvp->pre_create_mw = NULL; // __pre_create_mw + p_uvp->post_create_mw = NULL; // __post_create_mw + p_uvp->pre_query_mw = NULL; // __pre_query_mw + p_uvp->post_query_mw = NULL; // __post_query_mw + p_uvp->pre_destroy_mw = NULL; // __pre_destroy_mw + p_uvp->post_destroy_mw = NULL; // __post_destroy_mw + + /* register_pmr is not supported in user-mode */ + + UVP_EXIT(UVP_DBG_SHIM); +} + diff --git a/branches/WOF2-3/hw/mthca/user/mlnx_ual_osbypass.c b/branches/WOF2-3/hw/mthca/user/mlnx_ual_osbypass.c new file mode 100644 index 00000000..02a5cad6 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/user/mlnx_ual_osbypass.c @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2004-2005 Mellanox Technologies, Inc. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include "mt_l2w.h" +#include "mlnx_uvp.h" +#include "mx_abi.h" + +#include "mlnx_ual_main.h" +#if defined(EVENT_TRACING) +#include "mlnx_ual_osbypass.tmh" +#endif + +static ib_api_status_t __to_status(int err) +{ + ib_api_status_t status; + + switch (err) { + case -ENOMEM: status = IB_INSUFFICIENT_RESOURCES; break; + case -EINVAL: status = IB_INVALID_WR_TYPE; break; + case -ERANGE: status = IB_INVALID_MAX_SGE; break; + case -EBUSY: status = IB_INVALID_QP_STATE; break; + case -E2BIG: status = IB_INVALID_PARAMETER; break; + default: status = errno_to_iberr(err); + } + return status; +} + +static ib_api_status_t +__post_send ( + IN const void* h_qp, + IN ib_send_wr_t* const p_send_wr, + OUT ib_send_wr_t** pp_send_failure ) +{ + int err; + ib_api_status_t status = IB_SUCCESS; + struct mthca_qp *qp = (struct mthca_qp *) ((void*)h_qp); + + UVP_ENTER(UVP_DBG_QP); + + CL_ASSERT (qp); + + CL_ASSERT( p_send_wr ); + + err = qp->ibv_qp.context->ops.post_send(&qp->ibv_qp, p_send_wr, pp_send_failure ); + + if (err) { + UVP_PRINT(TRACE_LEVEL_ERROR ,UVP_DBG_QP , ("mthca_post_send failed (%d)\n", err)); + status = __to_status(err); + } + + + UVP_EXIT(UVP_DBG_QP); + return status; +} + +static ib_api_status_t +__post_recv ( + IN const void* h_qp, + IN ib_recv_wr_t* const p_recv_wr, + OUT ib_recv_wr_t** pp_recv_failure ) +{ + int err; + ib_api_status_t status = IB_SUCCESS; + struct mthca_qp *qp = (struct mthca_qp *) ((void*)h_qp); + + UVP_ENTER(UVP_DBG_QP); + + CL_ASSERT (qp); + + CL_ASSERT( p_recv_wr ); + + err = qp->ibv_qp.context->ops.post_recv(&qp->ibv_qp, p_recv_wr, pp_recv_failure ); + + if (err) { + UVP_PRINT(TRACE_LEVEL_ERROR ,UVP_DBG_QP, ("mthca_post_recv failed (%d)\n", err)); + status = __to_status(err); + } + + UVP_EXIT(UVP_DBG_QP); + return status; +} + + +static ib_api_status_t +__post_srq_recv ( + IN const void* h_srq, + IN ib_recv_wr_t* const p_recv_wr, + OUT ib_recv_wr_t** pp_recv_failure ) +{ + int err; + ib_api_status_t status = IB_SUCCESS; + struct mthca_srq *srq = (struct mthca_srq *) ((void*)h_srq); + + UVP_ENTER(UVP_DBG_QP); + + CL_ASSERT (srq); + + CL_ASSERT( p_recv_wr ); + + err = srq->ibv_srq.context->ops.post_srq_recv(&srq->ibv_srq, p_recv_wr, pp_recv_failure ); + if (err) { + UVP_PRINT(TRACE_LEVEL_ERROR ,UVP_DBG_QP, ("mthca_post_recv failed (%d)\n", err)); + status = __to_status(err); + } + + UVP_EXIT(UVP_DBG_QP); + return status; +} + + +static ib_api_status_t +__poll_cq ( + IN const void* h_cq, + IN OUT ib_wc_t** const pp_free_wclist, + OUT ib_wc_t** const pp_done_wclist ) +{ + int err; + ib_api_status_t status = IB_SUCCESS; + struct mthca_cq *cq = (struct mthca_cq *) ((void*)h_cq); + + UVP_ENTER(UVP_DBG_CQ); + CL_ASSERT (cq); + + if (!pp_free_wclist || !*pp_free_wclist || !pp_done_wclist) + { + UVP_PRINT(TRACE_LEVEL_ERROR ,UVP_DBG_CQ ,("Passed in bad params\n")); + status = IB_INVALID_PARAMETER; + goto err_invalid_params; + } + + err = cq->ibv_cq.context->ops.poll_cq_list(&cq->ibv_cq, pp_free_wclist, pp_done_wclist ); + if (err) { + UVP_PRINT(TRACE_LEVEL_ERROR ,UVP_DBG_CQ , ("mthca_poll_cq failed (%d)\n", err)); + status = errno_to_iberr(err); + }else if (!*pp_done_wclist) + status = IB_NOT_FOUND; + + +err_invalid_params: + + if (status != IB_NOT_FOUND){ + UVP_PRINT_EXIT(TRACE_LEVEL_ERROR ,UVP_DBG_CQ ,("completes with ERROR status %s\n", ib_get_err_str(status))); + }else + UVP_EXIT(UVP_DBG_CQ); + + return status; +} + + +static int +__poll_cq_array ( + IN const void* h_cq, + IN const int num_entries, + IN OUT uvp_wc_t* const wc ) +{ + int ne; + struct mthca_cq *cq = (struct mthca_cq *) h_cq; + + UVP_ENTER(UVP_DBG_CQ); + CL_ASSERT (cq); + + ne = cq->ibv_cq.context->ops.poll_cq(&cq->ibv_cq, num_entries, wc); + + UVP_EXIT(UVP_DBG_CQ); + return ne; +} + + +static ib_api_status_t +__enable_cq_notify ( + IN const void* h_cq, + IN const boolean_t solicited ) +{ + int err; + ib_api_status_t status = IB_SUCCESS; + struct mthca_cq *cq = (struct mthca_cq *) ((void*)h_cq); + + UVP_ENTER(UVP_DBG_CQ); + CL_ASSERT (cq); + + err = cq->ibv_cq.context->ops.req_notify_cq(&cq->ibv_cq, (solicited) ? IB_CQ_SOLICITED : IB_CQ_NEXT_COMP ); + if (err) { + UVP_PRINT(TRACE_LEVEL_ERROR ,UVP_DBG_SHIM , ("mthca_enable_cq_notify failed (%d)\n", err)); + status = errno_to_iberr(err); + goto exit; + } + +exit: + UVP_EXIT(UVP_DBG_CQ); + return status; +} + + +static ib_api_status_t +__enable_ncomp_cq_notify ( + IN const void* h_cq, + IN const uint32_t n_cqes ) +{ + // Not yet implemented + ib_api_status_t status = IB_UNSUPPORTED; + UVP_ENTER(UVP_DBG_SHIM); + UVP_PRINT(TRACE_LEVEL_ERROR ,UVP_DBG_SHIM , ("__enable_ncomp_cq_notify is not implemented yet\n")); + UVP_EXIT(UVP_DBG_SHIM); + return status; +} + + +void +mlnx_get_osbypass_interface ( + IN OUT uvp_interface_t *p_uvp ) +{ + CL_ASSERT(p_uvp); + + p_uvp->post_send = __post_send; + p_uvp->post_recv = __post_recv; + p_uvp->post_srq_recv = __post_srq_recv; + p_uvp->poll_cq = __poll_cq; + p_uvp->rearm_cq = __enable_cq_notify; + p_uvp->rearm_n_cq = NULL; + p_uvp->peek_cq = NULL; + p_uvp->bind_mw = NULL; + p_uvp->poll_cq_array = __poll_cq_array; +} + diff --git a/branches/WOF2-3/hw/mthca/user/mlnx_ual_pd.c b/branches/WOF2-3/hw/mthca/user/mlnx_ual_pd.c new file mode 100644 index 00000000..2b53f75b --- /dev/null +++ b/branches/WOF2-3/hw/mthca/user/mlnx_ual_pd.c @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2004-2005 Mellanox Technologies, Inc. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include "mt_l2w.h" +#include "mlnx_ual_main.h" +#include "mlnx_uvp.h" +#include "mx_abi.h" + +#if defined(EVENT_TRACING) +#include "mlnx_ual_pd.tmh" +#endif + +static ib_api_status_t +__pre_allocate_pd ( + IN const ib_ca_handle_t h_uvp_ca, + IN OUT ci_umv_buf_t *p_umv_buf, + OUT ib_pd_handle_t *ph_uvp_pd) +{ + ib_api_status_t status = IB_SUCCESS; + + UNREFERENCED_PARAMETER(ph_uvp_pd); + + UVP_ENTER(UVP_DBG_SHIM); + + CL_ASSERT(p_umv_buf); + + p_umv_buf->p_inout_buf = (ULONG_PTR)cl_zalloc( sizeof(struct ibv_alloc_pd_resp) ); + if( !p_umv_buf->p_inout_buf ) + { + status = IB_INSUFFICIENT_MEMORY; + goto err_memory; + } + p_umv_buf->input_size = p_umv_buf->output_size = sizeof(struct ibv_alloc_pd_resp); + p_umv_buf->command = TRUE; + +err_memory: + UVP_EXIT(UVP_DBG_SHIM); + return status; +} + + +static void +__post_allocate_pd ( + IN ib_ca_handle_t h_uvp_ca, + IN ib_api_status_t ioctl_status, + IN OUT ib_pd_handle_t *ph_uvp_pd, + IN ci_umv_buf_t *p_umv_buf ) +{ + int err; + ib_api_status_t status = IB_SUCCESS; + struct ibv_alloc_pd_resp *p_resp; + struct ibv_pd *ibv_pd; + mlnx_ual_hobul_t *p_hobul = (mlnx_ual_hobul_t *)((void *)h_uvp_ca); + mlnx_ual_pd_info_t *p_new_pd; + + UVP_ENTER(UVP_DBG_SHIM); + + CL_ASSERT(p_hobul); + CL_ASSERT(p_umv_buf); + p_resp = (struct ibv_alloc_pd_resp *)p_umv_buf->p_inout_buf; + + if (IB_SUCCESS == ioctl_status) { + + /* allocate ibv_pd */ + ibv_pd = p_hobul->ibv_ctx->ops.alloc_pd(p_hobul->ibv_ctx, p_resp); + if (IS_ERR(ibv_pd)) { + err = PTR_ERR(ibv_pd); + UVP_PRINT(TRACE_LEVEL_ERROR ,UVP_DBG_SHIM , ("mthca_alloc_pd failed (%d)\n", err)); + status = errno_to_iberr(err); + goto err_alloc_pd; + } + + /* allocate pd */ + p_new_pd = (mlnx_ual_pd_info_t *)cl_zalloc( sizeof(mlnx_ual_pd_info_t) ); + if( !p_new_pd ) { + status = IB_INSUFFICIENT_MEMORY; + goto err_memory; + } + + /* return results */ + p_new_pd->ibv_pd = ibv_pd; + p_new_pd->p_hobul = p_hobul; + *ph_uvp_pd = (ib_pd_handle_t)p_new_pd; + } + goto end; + +err_memory: + p_hobul->ibv_ctx->ops.dealloc_pd(ibv_pd); +err_alloc_pd: +end: + if (p_resp) + cl_free( p_resp ); + UVP_EXIT(UVP_DBG_SHIM); + return; +} + + +static ib_api_status_t +__pre_deallocate_pd ( + IN const ib_pd_handle_t h_uvp_pd) +{ + mlnx_ual_pd_info_t *p_pd_info = (mlnx_ual_pd_info_t *)((void *)h_uvp_pd); + UVP_ENTER(UVP_DBG_SHIM); + CL_ASSERT(p_pd_info); + UVP_EXIT(UVP_DBG_SHIM); + return IB_SUCCESS; +} + + +static void +__post_deallocate_pd ( + IN const ib_pd_handle_t h_uvp_pd, + IN ib_api_status_t ioctl_status ) +{ + int err; + mlnx_ual_pd_info_t *p_pd_info = (mlnx_ual_pd_info_t *)((void *)h_uvp_pd); + + UVP_ENTER(UVP_DBG_SHIM); + + CL_ASSERT(p_pd_info || p_pd_info->ibv_pd); + + if (IB_SUCCESS == ioctl_status) { + err = p_pd_info->p_hobul->ibv_ctx->ops.dealloc_pd( p_pd_info->ibv_pd ); + if (err) + UVP_PRINT(TRACE_LEVEL_ERROR ,UVP_DBG_SHIM , ("mthca_alloc_pd failed (%d)\n", err)); + + cl_free (p_pd_info); + } + UVP_EXIT(UVP_DBG_SHIM); +} + +void +mlnx_get_pd_interface ( + IN OUT uvp_interface_t *p_uvp ) +{ + UVP_ENTER(UVP_DBG_SHIM); + + CL_ASSERT(p_uvp); + + /* + * Protection Domain + */ + p_uvp->pre_allocate_pd = __pre_allocate_pd; + p_uvp->post_allocate_pd = __post_allocate_pd; + p_uvp->pre_deallocate_pd = __pre_deallocate_pd; + p_uvp->post_deallocate_pd = __post_deallocate_pd; + + UVP_EXIT(UVP_DBG_SHIM); +} + + diff --git a/branches/WOF2-3/hw/mthca/user/mlnx_ual_qp.c b/branches/WOF2-3/hw/mthca/user/mlnx_ual_qp.c new file mode 100644 index 00000000..53792155 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/user/mlnx_ual_qp.c @@ -0,0 +1,386 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2004-2005 Mellanox Technologies, Inc. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include "mt_l2w.h" +#include "mlnx_uvp.h" +#include "mx_abi.h" + +#include "mlnx_ual_main.h" +#if defined(EVENT_TRACING) +#include "mlnx_ual_qp.tmh" +#endif + +static void +__nd_modify_qp( + IN const ib_qp_handle_t h_uvp_qp, + OUT void** pp_outbuf, + OUT DWORD* p_size + ) +{ + struct ibv_qp *ibv_qp = (struct ibv_qp *)h_uvp_qp; + UVP_ENTER(UVP_DBG_QP); + *(uint32_t**)pp_outbuf = (uint32_t*)&ibv_qp->state; + *p_size = sizeof(ibv_qp->state); + UVP_EXIT(UVP_DBG_QP); +} + +static ib_qp_state_t __qp_state_to_ibal(enum ibv_qp_state state) +{ + switch ( state ) { + case IBV_QPS_RESET: return IB_QPS_RESET; + case IBV_QPS_INIT: return IB_QPS_INIT; + case IBV_QPS_RTR: return IB_QPS_RTR; + case IBV_QPS_RTS: return IB_QPS_RTS; + case IBV_QPS_SQD: return IB_QPS_SQD; + case IBV_QPS_SQE: return IB_QPS_SQERR; + case IBV_QPS_ERR: return IB_QPS_ERROR; + default: return IB_QPS_TIME_WAIT; + }; +} + +static uint32_t +__nd_get_qp_state( + IN const ib_qp_handle_t h_uvp_qp + ) +{ + struct ibv_qp *ibv_qp = (struct ibv_qp *)h_uvp_qp; + UVP_ENTER(UVP_DBG_QP); + return __qp_state_to_ibal( ibv_qp->state ); + UVP_EXIT(UVP_DBG_QP); +} + +static ib_api_status_t +__pre_create_qp ( + IN const ib_pd_handle_t h_uvp_pd, + IN const ib_qp_create_t *p_create_attr, + IN OUT ci_umv_buf_t *p_umv_buf, + OUT ib_qp_handle_t *ph_uvp_qp) +{ + int err; + struct ibv_qp *ibv_qp; + struct ibv_qp_init_attr attr; + struct ibv_create_qp *p_create_qp; + ib_api_status_t status = IB_SUCCESS; + size_t size = max( sizeof(struct ibv_create_qp), sizeof(struct ibv_create_qp_resp) ); + struct ibv_pd *ibv_pd = h_uvp_pd->ibv_pd; + + UVP_ENTER(UVP_DBG_QP); + + CL_ASSERT(p_umv_buf); + + p_umv_buf->p_inout_buf = (ULONG_PTR)cl_zalloc( size ); + if( !p_umv_buf->p_inout_buf ) + { + status = IB_INSUFFICIENT_MEMORY; + goto err_memory; + } + p_umv_buf->input_size = sizeof(struct ibv_create_qp); + p_umv_buf->output_size = sizeof(struct ibv_create_qp_resp); + p_umv_buf->command = TRUE; + + /* convert attributes */ + attr.send_cq = (struct ibv_cq *)p_create_attr->h_sq_cq; + attr.recv_cq = (struct ibv_cq *)p_create_attr->h_rq_cq; + attr.srq = (struct ibv_srq*)p_create_attr->h_srq; + attr.cap.max_send_wr = p_create_attr->sq_depth; + attr.cap.max_recv_wr = p_create_attr->rq_depth; + attr.cap.max_send_sge = p_create_attr->sq_sge; + attr.cap.max_recv_sge = p_create_attr->rq_sge; + attr.cap.max_inline_data = p_create_attr->sq_max_inline; + attr.qp_type = p_create_attr->qp_type; + attr.sq_sig_all = p_create_attr->sq_signaled; + + /* allocate ibv_qp */ + p_create_qp = (struct ibv_create_qp *)p_umv_buf->p_inout_buf; + ibv_qp = ibv_pd->context->ops.create_qp_pre(ibv_pd, &attr, p_create_qp); + if (IS_ERR(ibv_qp)) { + err = PTR_ERR(ibv_qp); + UVP_PRINT(TRACE_LEVEL_ERROR ,UVP_DBG_QP ,("mthca_create_qp_pre failed (%d)\n", err)); + if(err == -ENOMEM && (attr.cap.max_send_sge == 0 ||attr.cap.max_recv_sge == 0|| + attr.cap.max_send_wr == 0 || attr.cap.max_recv_wr == 0)) + status = IB_INVALID_SETTING; + else + status = errno_to_iberr(err); + goto err_alloc_qp; + } + + *ph_uvp_qp = (ib_qp_handle_t) ibv_qp; + goto end; + +err_alloc_qp: + cl_free((void*)(ULONG_PTR)p_umv_buf->p_inout_buf); +err_memory: +end: + UVP_EXIT(UVP_DBG_QP); + return status; +} + +static ib_api_status_t +__wv_pre_create_qp ( + IN const ib_pd_handle_t h_uvp_pd, + IN const uvp_qp_create_t *p_create_attr, + IN OUT ci_umv_buf_t *p_umv_buf, + OUT ib_qp_handle_t *ph_uvp_qp) +{ + struct ibv_qp *qp; + ib_api_status_t status; + + status = __pre_create_qp(h_uvp_pd, &p_create_attr->qp_create, + p_umv_buf, ph_uvp_qp); + if (status == IB_SUCCESS) { + qp = (struct ibv_qp *) *ph_uvp_qp; + qp->qp_context = p_create_attr->context; + } + return status; +} + +static ib_api_status_t +__post_create_qp ( + IN const ib_pd_handle_t h_uvp_pd, + IN ib_api_status_t ioctl_status, + IN OUT ib_qp_handle_t *ph_uvp_qp, + IN ci_umv_buf_t *p_umv_buf ) +{ + int err; + struct ibv_qp *ibv_qp; + struct ibv_create_qp_resp *p_resp; + struct ibv_create_qp *p_create_qp; + ib_api_status_t status = IB_SUCCESS; + struct ibv_pd *ibv_pd = h_uvp_pd->ibv_pd; + + UVP_ENTER(UVP_DBG_QP); + + + CL_ASSERT(p_umv_buf); + p_resp = (struct ibv_create_qp_resp *)p_umv_buf->p_inout_buf; + + if (IB_SUCCESS == ioctl_status) { + + /* allocate ibv_qp */ + ibv_qp = ibv_pd->context->ops.create_qp_post(ibv_pd, p_resp); + if (IS_ERR(ibv_qp)) { + err = PTR_ERR(ibv_qp); + UVP_PRINT(TRACE_LEVEL_ERROR ,UVP_DBG_QP , ("mthca_create_qp_post failed (%d)\n", err)); + status = errno_to_iberr(err); + goto err_create_cq; + } + } + goto end; + + ibv_pd->context->ops.destroy_qp(ibv_qp); +err_create_cq: +end: + if (p_resp) + cl_free( p_resp ); + UVP_EXIT(UVP_DBG_QP); + return status; +} + +static ib_api_status_t +__pre_modify_qp ( + IN const ib_qp_handle_t h_uvp_qp, + IN const ib_qp_mod_t *p_modify_attr, + IN OUT ci_umv_buf_t *p_umv_buf) +{ + ib_api_status_t status = IB_SUCCESS; + UNREFERENCED_PARAMETER(h_uvp_qp); + UNREFERENCED_PARAMETER(p_modify_attr); + + UVP_ENTER(UVP_DBG_SHIM); + + CL_ASSERT(p_umv_buf); + + p_umv_buf->p_inout_buf = (ULONG_PTR)cl_zalloc( sizeof(struct ibv_modify_qp_resp) ); + if( !p_umv_buf->p_inout_buf ) + { + status = IB_INSUFFICIENT_MEMORY; + goto err_memory; + } + p_umv_buf->input_size = 0; + p_umv_buf->output_size = sizeof(struct ibv_modify_qp_resp); + p_umv_buf->command = TRUE; + +err_memory: + UVP_EXIT(UVP_DBG_SHIM); + return status; +} + + +static void +__post_modify_qp ( + IN const ib_qp_handle_t h_uvp_qp, + IN ib_api_status_t ioctl_status, + IN OUT ci_umv_buf_t *p_umv_buf) +{ + int err; + ib_api_status_t status; + struct ibv_modify_qp_resp *p_resp; + struct ibv_qp_attr attr; + struct ibv_qp *ibv_qp = (struct ibv_qp *)h_uvp_qp; + + UVP_ENTER(UVP_DBG_SHIM); + CL_ASSERT(p_umv_buf); + + p_resp = (struct ibv_modify_qp_resp *)p_umv_buf->p_inout_buf; + + if (IB_SUCCESS == ioctl_status) + { + memset( &attr, 0, sizeof(attr)); + attr.qp_state = p_resp->qp_state; + if (ibv_qp) { + err = ibv_qp->context->ops.modify_qp( ibv_qp, + &attr, p_resp->attr_mask); + if (err) { + UVP_PRINT(TRACE_LEVEL_ERROR ,UVP_DBG_SHIM , ("mthca_modify_qp failed (%d)\n", err)); + status = errno_to_iberr(err); + goto err_modify_qp; + } + } + UVP_PRINT(TRACE_LEVEL_INFORMATION ,UVP_DBG_SHIM , + ("Committed to modify QP to state %d\n", p_resp->qp_state)); + } + + +err_modify_qp: + if (p_resp) + cl_free (p_resp); + UVP_EXIT(UVP_DBG_SHIM); + return; + } + + +static ib_api_status_t +__pre_query_qp ( + IN ib_qp_handle_t h_uvp_qp, + IN OUT ci_umv_buf_t *p_umv_buf) +{ + UNREFERENCED_PARAMETER(h_uvp_qp); + UVP_ENTER(UVP_DBG_SHIM); + p_umv_buf->input_size = p_umv_buf->output_size = 0; + p_umv_buf->command = FALSE; + p_umv_buf->status = IB_SUCCESS; + UVP_EXIT(UVP_DBG_SHIM); + return IB_SUCCESS; +} + + +static void +__post_query_qp ( + IN ib_qp_handle_t h_uvp_qp, + IN ib_api_status_t ioctl_status, + IN OUT ib_qp_attr_t *p_query_attr, + IN OUT ci_umv_buf_t *p_umv_buf) +{ + struct mthca_qp *p_mthca_qp = (struct mthca_qp *)h_uvp_qp; + UVP_ENTER(UVP_DBG_SHIM); + + UNREFERENCED_PARAMETER(p_umv_buf); + if(IB_SUCCESS == ioctl_status) + { + p_query_attr->sq_max_inline = p_mthca_qp->max_inline_data; + p_query_attr->sq_sge = p_mthca_qp->sq.max_gs; + p_query_attr->sq_depth = p_mthca_qp->sq.max; + p_query_attr->rq_sge = p_mthca_qp->rq.max_gs; + p_query_attr->rq_depth = p_mthca_qp->rq.max; + } + UVP_EXIT(UVP_DBG_SHIM); +} + + +static ib_api_status_t +__pre_destroy_qp ( + IN const ib_qp_handle_t h_uvp_qp) +{ + int err; + + + UVP_ENTER(UVP_DBG_SHIM); + + mthca_destroy_qp_pre((struct ibv_qp*)h_uvp_qp); + + UVP_EXIT(UVP_DBG_SHIM); + return IB_SUCCESS; +} + +static void +__post_destroy_qp ( + IN const ib_qp_handle_t h_uvp_qp, + IN ib_api_status_t ioctl_status) +{ + int err; + + UVP_ENTER(UVP_DBG_SHIM); + + CL_ASSERT(h_uvp_qp); + + mthca_destroy_qp_post((struct ibv_qp*)h_uvp_qp, (int)ioctl_status); + if (ioctl_status != IB_SUCCESS) + UVP_PRINT(TRACE_LEVEL_ERROR ,UVP_DBG_SHIM , ("mthca_destroy_qp_post failed (%d)\n", ioctl_status)); + + UVP_EXIT(UVP_DBG_SHIM); + return; +} + + +void +mlnx_get_qp_interface ( + IN OUT uvp_interface_t *p_uvp ) +{ + UVP_ENTER(UVP_DBG_SHIM); + + CL_ASSERT(p_uvp); + + /* + * QP Management Verbs + */ + p_uvp->pre_create_qp = __pre_create_qp; + p_uvp->post_create_qp = __post_create_qp; + + // !!! none for create_spl_qp, UAL will return error !!! + + p_uvp->pre_modify_qp = __pre_modify_qp; + p_uvp->post_modify_qp = __post_modify_qp; + p_uvp->pre_query_qp = NULL; + p_uvp->post_query_qp = __post_query_qp; + p_uvp->pre_destroy_qp = __pre_destroy_qp; + p_uvp->post_destroy_qp = __post_destroy_qp; + + p_uvp->nd_modify_qp = __nd_modify_qp; + p_uvp->nd_get_qp_state = __nd_get_qp_state; + p_uvp->wv_pre_create_qp = __wv_pre_create_qp; + + UVP_EXIT(UVP_DBG_SHIM); +} + + + diff --git a/branches/WOF2-3/hw/mthca/user/mlnx_ual_srq.c b/branches/WOF2-3/hw/mthca/user/mlnx_ual_srq.c new file mode 100644 index 00000000..7d5ff1dc --- /dev/null +++ b/branches/WOF2-3/hw/mthca/user/mlnx_ual_srq.c @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2004-2005 Mellanox Technologies, Inc. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: mlnx_ual_srq.c 1611 2006-08-20 14:48:55Z leonid $ + */ + +#include "mt_l2w.h" +#include "mlnx_ual_main.h" +#include "mlnx_uvp.h" +#include "mx_abi.h" + +#if defined(EVENT_TRACING) +#include "mlnx_ual_srq.tmh" +#endif + + +extern uint32_t mlnx_dbg_lvl; + +static void __free_srq(struct mthca_srq *srq) +{ + /* srq may be NULL, when ioctl returned with some kind of error, e.g. IB_INVALID_PARAM */ + if (!srq) + return; + + if (mthca_is_memfree(srq->ibv_srq.context)) { + mthca_free_db(to_mctx(srq->ibv_srq.context)->db_tab, MTHCA_DB_TYPE_SRQ, + srq->db_index); + } + + if (srq->buf) { + posix_memfree(srq->buf); + } + + if (srq->wrid) + cl_free(srq->wrid); + + cl_spinlock_destroy(&srq->lock); + cl_free (srq); +} + +static ib_api_status_t +__pre_create_srq ( + IN const ib_pd_handle_t h_uvp_pd,// Fix me: if needed + IN const ib_srq_attr_t *p_srq_attr, + IN OUT ci_umv_buf_t *p_umv_buf, + OUT ib_srq_handle_t *ph_uvp_srq) +{ + struct mthca_srq *srq; + ib_api_status_t status = IB_SUCCESS; + size_t size = max( sizeof(struct ibv_create_srq), sizeof(struct ibv_create_srq_resp) ); + mlnx_ual_pd_info_t *p_pd = (mlnx_ual_pd_info_t *)h_uvp_pd; + struct ibv_pd *ibv_pd = p_pd->ibv_pd; + struct ibv_create_srq *p_create_srq; + int err; + + UNREFERENCED_PARAMETER(ph_uvp_srq); + + UVP_ENTER(UVP_DBG_SRQ); + + CL_ASSERT(p_umv_buf); + + /* Sanity check SRQ size before proceeding */ + if (p_srq_attr->max_wr > 1 << 16 || p_srq_attr->max_sge > 64) + { + status = IB_INVALID_PARAMETER; + goto err_params; + } + + p_umv_buf->p_inout_buf = (ULONG_PTR)cl_zalloc( size ); + if( !p_umv_buf->p_inout_buf ) + { + status = IB_INSUFFICIENT_MEMORY; + goto err_memory; + } + p_umv_buf->input_size = sizeof(struct ibv_create_srq); + p_umv_buf->output_size = sizeof(struct ibv_create_srq_resp); + p_umv_buf->command = TRUE; + + /* allocate srq */ + srq = cl_zalloc(sizeof *srq); + if (!srq) + { + status = IB_INSUFFICIENT_MEMORY; + goto err_alloc_srq; + } + + /* init fields */ + cl_spinlock_construct(&srq->lock); + if (cl_spinlock_init(&srq->lock)) + goto err_lock; + + srq->ibv_srq.pd = ibv_pd; + srq->ibv_srq.context = ibv_pd->context; + srq->max = align_queue_size(ibv_pd->context, p_srq_attr->max_wr, 1); + srq->max_gs = p_srq_attr->max_sge; + srq->counter = 0; + + if (mthca_alloc_srq_buf(ibv_pd, (void*)p_srq_attr, srq)) + { + status = IB_INSUFFICIENT_MEMORY; + goto err_alloc_buf; + } + + // fill the parameters for ioctl + p_create_srq = (struct ibv_create_srq *)p_umv_buf->p_inout_buf; + p_create_srq->user_handle = (uint64_t)(ULONG_PTR)srq; + p_create_srq->mr.start = (uint64_t)(ULONG_PTR)srq->buf; + p_create_srq->mr.length = srq->buf_size; + p_create_srq->mr.hca_va = 0; + p_create_srq->mr.pd_handle = p_pd->ibv_pd->handle; + p_create_srq->mr.pdn = to_mpd(p_pd->ibv_pd)->pdn; + p_create_srq->mr.access_flags = 0; //local read + + if (mthca_is_memfree(ibv_pd->context)) { + srq->db_index = mthca_alloc_db(to_mctx(ibv_pd->context)->db_tab, + MTHCA_DB_TYPE_SRQ, &srq->db); + if (srq->db_index < 0) + goto err_alloc_db; + + p_create_srq->db_page = db_align(srq->db); + p_create_srq->db_index = srq->db_index; + } + + status = IB_SUCCESS; + goto end; + +err_alloc_db: + posix_memfree(srq->buf); + cl_free(srq->wrid); +err_alloc_buf: + cl_spinlock_destroy(&srq->lock); +err_lock: + cl_free(srq); +err_alloc_srq: + cl_free((void*)(ULONG_PTR)p_umv_buf->p_inout_buf); +err_memory: +err_params: +end: + UVP_EXIT(UVP_DBG_SRQ); + return status; +} + + +static void +__post_create_srq ( + IN const ib_pd_handle_t h_uvp_pd, + IN ib_api_status_t ioctl_status, + IN OUT ib_srq_handle_t *ph_uvp_srq, + IN ci_umv_buf_t *p_umv_buf ) +{ + int err; + struct mthca_srq *srq; + struct ibv_create_srq_resp *p_resp; + mlnx_ual_pd_info_t *p_pd = (mlnx_ual_pd_info_t *)h_uvp_pd; + struct ibv_pd *ibv_pd = p_pd->ibv_pd; + ib_api_status_t status = IB_SUCCESS; + + UVP_ENTER(UVP_DBG_SRQ); + + CL_ASSERT(p_umv_buf); + p_resp = (struct ibv_create_srq_resp *)p_umv_buf->p_inout_buf; + srq = (struct mthca_srq *)(ULONG_PTR)p_resp->user_handle; + + if (IB_SUCCESS == ioctl_status) { + + /* complete filling SRQ object */ + srq->ibv_srq.handle = p_resp->srq_handle; + srq->srqn = p_resp->srqn; + srq->max = p_resp->max_wr; + srq->max_gs = p_resp->max_sge; + srq->mr.handle = p_resp->mr.mr_handle; + srq->mr.lkey = p_resp->mr.lkey; + srq->mr.rkey = p_resp->mr.rkey; + srq->mr.pd = ibv_pd; + srq->mr.context = ibv_pd->context; + + if (mthca_is_memfree(ibv_pd->context)) + mthca_set_db_qn(srq->db, MTHCA_DB_TYPE_SRQ, srq->srqn); + + *ph_uvp_srq = (ib_srq_handle_t)srq; + } + else + __free_srq(srq); + + if (p_resp) + cl_free( p_resp ); + UVP_EXIT(UVP_DBG_SRQ); + return; +} + +static void +__post_destroy_srq ( + IN const ib_srq_handle_t h_uvp_srq, + IN ib_api_status_t ioctl_status) +{ + int err; + struct mthca_srq *srq = (struct mthca_srq *) ((void*)h_uvp_srq); + + UVP_ENTER(UVP_DBG_CQ); + + CL_ASSERT(srq); + + if (IB_SUCCESS == ioctl_status) + __free_srq(srq); + + UVP_EXIT(UVP_DBG_CQ); +} + +void +mlnx_get_srq_interface ( + IN OUT uvp_interface_t *p_uvp ) +{ + UVP_ENTER(UVP_DBG_DEV); + + CL_ASSERT(p_uvp); + + /* + * Completion Queue Management Verbs + */ + p_uvp->pre_create_srq = __pre_create_srq; + p_uvp->post_create_srq = __post_create_srq; + + p_uvp->pre_query_srq = NULL; /* __pre_query_srq; */ + p_uvp->post_query_srq = NULL; /*__post_query_srq;*/ + + p_uvp->pre_modify_srq = NULL; /* __modify_srq;*/ + p_uvp->post_modify_srq = NULL; /*__post_modify_srq;*/ + + p_uvp->pre_destroy_srq = NULL; /* __pre_destroy_srq; */ + p_uvp->post_destroy_srq = __post_destroy_srq; + + UVP_EXIT(UVP_DBG_DEV); +} + + diff --git a/branches/WOF2-3/hw/mthca/user/mlnx_uvp.c b/branches/WOF2-3/hw/mthca/user/mlnx_uvp.c new file mode 100644 index 00000000..c2fcba8f --- /dev/null +++ b/branches/WOF2-3/hw/mthca/user/mlnx_uvp.c @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include "mt_l2w.h" +#include "mlnx_uvp.h" + +#if defined(EVENT_TRACING) +#include "mlnx_uvp.tmh" +#endif + +#include "mx_abi.h" + +size_t g_page_size = 0; + +#ifndef PCI_VENDOR_ID_MELLANOX +#define PCI_VENDOR_ID_MELLANOX 0x15b3 +#endif + +#ifndef PCI_DEVICE_ID_MELLANOX_TAVOR +#define PCI_DEVICE_ID_MELLANOX_TAVOR 0x5a44 +#endif + +#ifndef PCI_DEVICE_ID_MELLANOX_ARBEL_COMPAT +#define PCI_DEVICE_ID_MELLANOX_ARBEL_COMPAT 0x6278 +#endif + +#ifndef PCI_DEVICE_ID_MELLANOX_ARBEL +#define PCI_DEVICE_ID_MELLANOX_ARBEL 0x6282 +#endif + +#ifndef PCI_DEVICE_ID_MELLANOX_SINAI_OLD +#define PCI_DEVICE_ID_MELLANOX_SINAI_OLD 0x5e8c +#endif + +#ifndef PCI_DEVICE_ID_MELLANOX_SINAI +#define PCI_DEVICE_ID_MELLANOX_SINAI 0x6274 +#endif + +#ifndef PCI_VENDOR_ID_TOPSPIN +#define PCI_VENDOR_ID_TOPSPIN 0x1867 +#endif + + +#define HCA(v, d, t) \ + { PCI_VENDOR_ID_##v, PCI_DEVICE_ID_MELLANOX_##d, MTHCA_##t } + +static struct pci_device_id { + unsigned vendor; + unsigned device; + enum mthca_hca_type type; +} mthca_pci_table[] = { + HCA( MELLANOX, TAVOR, TAVOR), + HCA( MELLANOX, ARBEL_COMPAT, TAVOR), + HCA( MELLANOX, ARBEL, ARBEL), + HCA( MELLANOX, SINAI_OLD, ARBEL), + HCA( MELLANOX, SINAI, ARBEL), + HCA( TOPSPIN, TAVOR, TAVOR), + HCA( TOPSPIN, ARBEL_COMPAT, TAVOR), + HCA( TOPSPIN, ARBEL, ARBEL), + HCA( TOPSPIN, SINAI_OLD, ARBEL), + HCA( TOPSPIN, SINAI, ARBEL), +}; + +static struct ibv_context_ops mthca_ctx_ops = { + NULL, // mthca_query_device, + NULL, // mthca_query_port, + mthca_alloc_pd, + mthca_free_pd, + NULL, // mthca_reg_mr, + NULL, // mthca_dereg_mr, + mthca_create_cq_pre, + mthca_create_cq_post, + mthca_poll_cq, + mthca_poll_cq_list, + NULL, /* req_notify_cq */ + mthca_destroy_cq, + NULL, // mthca_create_srq, + NULL, // mthca_modify_srq, + NULL, // mthca_destroy_srq, + NULL, /* post_srq_recv */ + mthca_create_qp_pre, + mthca_create_qp_post, + mthca_modify_qp, + NULL, + NULL, /* post_send */ + NULL, /* post_recv */ + mthca_attach_mcast, + mthca_detach_mcast +}; + +struct ibv_context *mthca_alloc_context(struct ibv_get_context_resp *resp_p) +{ + struct mthca_context * context; + struct ibv_alloc_pd_resp pd_resp; + int i; + + /* allocate context */ + context = cl_zalloc(sizeof *context); + if (!context) + return NULL; + + /* find page size */ + if (!g_page_size) { + SYSTEM_INFO sys_info; + GetSystemInfo(&sys_info); + g_page_size = sys_info.dwPageSize; + } + + /* calculate device type */ + for (i = 0; i < sizeof mthca_pci_table / sizeof mthca_pci_table[0]; ++i) + if (resp_p->vend_id == mthca_pci_table[i].vendor && + resp_p->dev_id == mthca_pci_table[i].device) + goto found; + goto err_dev_type; + +found: + context->hca_type = mthca_pci_table[i].type; + context->uar = (void*)(UINT_PTR)resp_p->uar_addr; + context->num_qps = resp_p->qp_tab_size; + context->qp_table_shift = ffs(context->num_qps) - 1 - MTHCA_QP_TABLE_BITS; + context->qp_table_mask = (1 << context->qp_table_shift) - 1; + + if (mthca_is_memfree(&context->ibv_ctx)) { + context->db_tab = mthca_alloc_db_tab(resp_p->uarc_size); + if (!context->db_tab) + goto err_alloc_db_tab; + } else + context->db_tab = NULL; + + context->qp_table_mutex = CreateMutex( NULL, FALSE, NULL ); + if (!context->qp_table_mutex) + goto err_mutex; + for (i = 0; i < MTHCA_QP_TABLE_SIZE; ++i) + context->qp_table[i].refcnt = 0; + + cl_spinlock_construct(&context->uar_lock); + if (cl_spinlock_init(&context->uar_lock)) + goto err_spinlock; + + pd_resp.pd_handle = resp_p->pd_handle; + pd_resp.pdn = resp_p->pdn; + context->pd = mthca_alloc_pd(&context->ibv_ctx, &pd_resp); + if (!context->pd) + goto err_unmap; + + context->ibv_ctx.ops = mthca_ctx_ops; + + if (mthca_is_memfree(&context->ibv_ctx)) { + context->ibv_ctx.ops.req_notify_cq = mthca_arbel_arm_cq; + context->ibv_ctx.ops.post_send = mthca_arbel_post_send; + context->ibv_ctx.ops.post_recv = mthca_arbel_post_recv; + context->ibv_ctx.ops.post_srq_recv = mthca_arbel_post_srq_recv; + } else { + context->ibv_ctx.ops.req_notify_cq = mthca_tavor_arm_cq; + context->ibv_ctx.ops.post_send = mthca_tavor_post_send; + context->ibv_ctx.ops.post_recv = mthca_tavor_post_recv; + context->ibv_ctx.ops.post_srq_recv = mthca_tavor_post_srq_recv; + } + + return &context->ibv_ctx; + +err_unmap: +err_spinlock: +err_mutex: + mthca_free_db_tab(context->db_tab); + +err_alloc_db_tab: +err_dev_type: + cl_free(context); + return NULL; +} + +void mthca_free_context(struct ibv_context *ibctx) +{ + struct mthca_context *context = to_mctx(ibctx); + + cl_spinlock_destroy(&context->uar_lock); + mthca_free_pd(context->pd); + mthca_free_db_tab(context->db_tab); + cl_free(context); +} diff --git a/branches/WOF2-3/hw/mthca/user/mlnx_uvp.def b/branches/WOF2-3/hw/mthca/user/mlnx_uvp.def new file mode 100644 index 00000000..55f97537 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/user/mlnx_uvp.def @@ -0,0 +1,10 @@ +#if DBG +LIBRARY mthcaud.dll +#else +LIBRARY mthcau.dll +#endif + +#ifndef _WIN64 +EXPORTS +uvp_get_interface +#endif diff --git a/branches/WOF2-3/hw/mthca/user/mlnx_uvp.h b/branches/WOF2-3/hw/mthca/user/mlnx_uvp.h new file mode 100644 index 00000000..cc7cb051 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/user/mlnx_uvp.h @@ -0,0 +1,338 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Cisco Systems. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#ifndef MTHCA_H +#define MTHCA_H + +#include +#include +#include +#include "mlnx_uvp_debug.h" + +#define PFX "mthca: " + +enum mthca_hca_type { + MTHCA_TAVOR, + MTHCA_ARBEL, + MTHCA_LIVEFISH +}; + +enum { + MTHCA_CQ_ENTRY_SIZE = 0x20, + MTHCA_BYTES_PER_ATOMIC_COMPL = 0x8 +}; + +enum { + MTHCA_QP_TABLE_BITS = 8, + MTHCA_QP_TABLE_SIZE = 1 << MTHCA_QP_TABLE_BITS, + MTHCA_QP_TABLE_MASK = MTHCA_QP_TABLE_SIZE - 1 +}; + +enum { + MTHCA_DB_REC_PAGE_SIZE = 4096, + MTHCA_DB_REC_PER_PAGE = MTHCA_DB_REC_PAGE_SIZE / 8 +}; + +enum mthca_db_type { + MTHCA_DB_TYPE_INVALID = 0x0, + MTHCA_DB_TYPE_CQ_SET_CI = 0x1, + MTHCA_DB_TYPE_CQ_ARM = 0x2, + MTHCA_DB_TYPE_SQ = 0x3, + MTHCA_DB_TYPE_RQ = 0x4, + MTHCA_DB_TYPE_SRQ = 0x5, + MTHCA_DB_TYPE_GROUP_SEP = 0x7 +}; + +enum mthca_wr_opcode { + MTHCA_OPCODE_NOP = 0x00, + MTHCA_OPCODE_RDMA_WRITE = 0x08, + MTHCA_OPCODE_RDMA_WRITE_IMM = 0x09, + MTHCA_OPCODE_SEND = 0x0a, + MTHCA_OPCODE_SEND_IMM = 0x0b, + MTHCA_OPCODE_RDMA_READ = 0x10, + MTHCA_OPCODE_ATOMIC_CS = 0x11, + MTHCA_OPCODE_ATOMIC_FA = 0x12, + MTHCA_OPCODE_BIND_MW = 0x18, + MTHCA_OPCODE_INVALID = 0xff +}; + +struct mthca_ah_page; + +struct mthca_db_table; + +struct mthca_context { + struct ibv_context ibv_ctx; + void *uar; + cl_spinlock_t uar_lock; + struct mthca_db_table *db_tab; + struct ibv_pd *pd; + struct { + struct mthca_qp **table; + int refcnt; + } qp_table[MTHCA_QP_TABLE_SIZE]; + HANDLE qp_table_mutex; + int num_qps; + int qp_table_shift; + int qp_table_mask; + enum mthca_hca_type hca_type; +}; + +struct mthca_pd { + struct ibv_pd ibv_pd; + struct mthca_ah_page *ah_list; + HANDLE ah_mutex; + uint32_t pdn; +}; + +struct mthca_cq { + struct ibv_cq ibv_cq; + void *buf; + cl_spinlock_t lock; + struct ibv_mr mr; + uint32_t cqn; + uint32_t cons_index; + + /* Next fields are mem-free only */ + int set_ci_db_index; + uint32_t *set_ci_db; + int arm_db_index; + uint32_t *arm_db; + int u_arm_db_index; + uint32_t *p_u_arm_sn; +}; + +struct mthca_srq { + struct ibv_srq ibv_srq; + void *buf; + void *last; + cl_spinlock_t lock; + struct ibv_mr mr; + uint64_t *wrid; + uint32_t srqn; + int max; + int max_gs; + int wqe_shift; + int first_free; + int last_free; + int buf_size; + + /* Next fields are mem-free only */ + int db_index; + uint32_t *db; + uint16_t counter; +}; + +struct mthca_wq { + cl_spinlock_t lock; + int max; + unsigned next_ind; + unsigned last_comp; + unsigned head; + unsigned tail; + void *last; + int max_gs; + int wqe_shift; + + /* Next fields are mem-free only */ + int db_index; + uint32_t *db; +}; + +struct mthca_qp { + struct ibv_qp ibv_qp; + uint8_t *buf; + uint64_t *wrid; + int send_wqe_offset; + int max_inline_data; + int buf_size; + struct mthca_wq sq; + struct mthca_wq rq; + struct ibv_mr mr; + int sq_sig_all; +}; + +struct mthca_av { + uint32_t port_pd; + uint8_t reserved1; + uint8_t g_slid; + uint16_t dlid; + uint8_t reserved2; + uint8_t gid_index; + uint8_t msg_sr; + uint8_t hop_limit; + uint32_t sl_tclass_flowlabel; + uint32_t dgid[4]; +}; + +struct mthca_ah { + struct mthca_av *av; + ib_av_attr_t av_attr; + ib_pd_handle_t h_uvp_pd; + struct mthca_ah_page *page; + uint32_t key; + int in_kernel; +}; + +#pragma warning( disable : 4200) +struct mthca_ah_page { + struct mthca_ah_page *prev, *next; + void *buf; + struct ibv_mr mr; + int use_cnt; + unsigned free[0]; +}; +#pragma warning( default : 4200) + + +static inline uintptr_t db_align(uint32_t *db) +{ + return (uintptr_t) db & ~((uintptr_t) MTHCA_DB_REC_PAGE_SIZE - 1); +} + +#define to_mxxx(xxx, type) \ + ((struct mthca_##type *) \ + ((uint8_t *) ib##xxx - offsetof(struct mthca_##type, ibv_##xxx))) + +static inline struct mthca_context *to_mctx(struct ibv_context *ibctx) +{ + return to_mxxx(ctx, context); +} + +static inline struct mthca_pd *to_mpd(struct ibv_pd *ibpd) +{ + return to_mxxx(pd, pd); +} + +static inline struct mthca_cq *to_mcq(struct ibv_cq *ibcq) +{ + return to_mxxx(cq, cq); +} + +static inline struct mthca_srq *to_msrq(struct ibv_srq *ibsrq) +{ + return to_mxxx(srq, srq); +} + +static inline struct mthca_qp *to_mqp(struct ibv_qp *ibqp) +{ + return to_mxxx(qp, qp); +} + +static inline int mthca_is_memfree(struct ibv_context *ibctx) +{ + return to_mctx(ibctx)->hca_type == MTHCA_ARBEL; +} + +int mthca_alloc_db(struct mthca_db_table *db_tab, enum mthca_db_type type, + uint32_t **db); +void mthca_set_db_qn(uint32_t *db, enum mthca_db_type type, uint32_t qn); +void mthca_free_db(struct mthca_db_table *db_tab, enum mthca_db_type type, int db_index); +struct mthca_db_table *mthca_alloc_db_tab(int uarc_size); +void mthca_free_db_tab(struct mthca_db_table *db_tab); + +int mthca_query_device(struct ibv_context *context, + struct ibv_device_attr *attr); +int mthca_query_port(struct ibv_context *context, uint8_t port, + struct ibv_port_attr *attr); + + struct ibv_pd *mthca_alloc_pd(struct ibv_context *context, + struct ibv_alloc_pd_resp *resp_p); + +int mthca_free_pd(struct ibv_pd *pd); + +struct ibv_cq *mthca_create_cq_pre(struct ibv_context *context, int *cqe, + struct ibv_create_cq *req); +struct ibv_cq *mthca_create_cq_post(struct ibv_context *context, + struct ibv_create_cq_resp *resp); +int mthca_destroy_cq(struct ibv_cq *cq); +int mthca_poll_cq(struct ibv_cq *cq, int ne, struct _uvp_wc *wc); +int mthca_poll_cq_list(struct ibv_cq *ibcq, + struct _ib_wc** const pp_free_wclist, + struct _ib_wc** const pp_done_wclist ); +int mthca_tavor_arm_cq(struct ibv_cq *cq, int solicited); +int mthca_arbel_arm_cq(struct ibv_cq *cq, int solicited); +void mthca_cq_clean(struct mthca_cq *cq, uint32_t qpn, + struct mthca_srq *srq); +void mthca_init_cq_buf(struct mthca_cq *cq, int nent); + +struct ibv_srq *mthca_create_srq(struct ibv_pd *pd, + struct ibv_srq_init_attr *attr); +int mthca_modify_srq(struct ibv_srq *srq, + struct ibv_srq_attr *attr, + enum ibv_srq_attr_mask mask); +int mthca_destroy_srq(struct ibv_srq *srq); +int mthca_alloc_srq_buf(struct ibv_pd *pd, struct ibv_srq_attr *attr, + struct mthca_srq *srq); +void mthca_free_srq_wqe(struct mthca_srq *srq, int ind); +int mthca_tavor_post_srq_recv(struct ibv_srq *ibsrq, + struct _ib_recv_wr *wr, + struct _ib_recv_wr **bad_wr); +int mthca_arbel_post_srq_recv(struct ibv_srq *ibsrq, + struct _ib_recv_wr *wr, + struct _ib_recv_wr **bad_wr); +struct ibv_qp *mthca_create_qp_pre(struct ibv_pd *pd, + struct ibv_qp_init_attr *attr, struct ibv_create_qp *req); +struct ibv_qp *mthca_create_qp_post(struct ibv_pd *pd, + struct ibv_create_qp_resp *resp); +int mthca_modify_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr, + enum ibv_qp_attr_mask attr_mask); +void mthca_destroy_qp_pre(struct ibv_qp *qp); +void mthca_destroy_qp_post(struct ibv_qp *qp, int ret); +void mthca_init_qp_indices(struct mthca_qp *qp); +int mthca_tavor_post_send(struct ibv_qp *ibqp, struct _ib_send_wr *wr, + struct _ib_send_wr **bad_wr); +int mthca_tavor_post_recv(struct ibv_qp *ibqp, struct _ib_recv_wr *wr, + struct _ib_recv_wr **bad_wr); +int mthca_arbel_post_send(struct ibv_qp *ibqp, struct _ib_send_wr *wr, + struct _ib_send_wr **bad_wr); +int mthca_arbel_post_recv(struct ibv_qp *ibqp, struct _ib_recv_wr *wr, + struct _ib_recv_wr **bad_wr); +int mthca_alloc_qp_buf(struct ibv_pd *pd, struct ibv_qp_cap *cap, + ib_qp_type_t type, struct mthca_qp *qp); +struct mthca_qp *mthca_find_qp(struct mthca_context *ctx, uint32_t qpn); +int mthca_store_qp(struct mthca_context *ctx, uint32_t qpn, struct mthca_qp *qp); +void mthca_clear_qp(struct mthca_context *ctx, uint32_t qpn); +int mthca_free_err_wqe(struct mthca_qp *qp, int is_send, + int index, int *dbd, uint32_t *new_wqe); +int mthca_alloc_av(struct mthca_pd *pd, struct ibv_ah_attr *attr, + struct mthca_ah *ah, struct ibv_create_ah_resp *resp); +void mthca_free_av(struct mthca_ah *ah); +int mthca_attach_mcast(struct ibv_qp *qp, union ibv_gid *gid, uint16_t lid); +int mthca_detach_mcast(struct ibv_qp *qp, union ibv_gid *gid, uint16_t lid); +struct ibv_context *mthca_alloc_context(struct ibv_get_context_resp *resp_p); +void mthca_free_context(struct ibv_context *ibctx); + +#endif /* MTHCA_H */ diff --git a/branches/WOF2-3/hw/mthca/user/mlnx_uvp.rc b/branches/WOF2-3/hw/mthca/user/mlnx_uvp.rc new file mode 100644 index 00000000..f3d2e34a --- /dev/null +++ b/branches/WOF2-3/hw/mthca/user/mlnx_uvp.rc @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef DBG +#define VER_FILEDESCRIPTION_STR "HCA User Mode Verb Provider (checked)" +#define VER_INTERNALNAME_STR "mthcaud.dll" +#define VER_ORIGINALFILENAME_STR "mthcaud.dll" +#else +#define VER_FILEDESCRIPTION_STR "HCA User Mode Verb Provider" +#define VER_INTERNALNAME_STR "mthcau.dll" +#define VER_ORIGINALFILENAME_STR "mthcau.dll" +#endif + +#include diff --git a/branches/WOF2-3/hw/mthca/user/mlnx_uvp_ah.c b/branches/WOF2-3/hw/mthca/user/mlnx_uvp_ah.c new file mode 100644 index 00000000..be1eb898 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/user/mlnx_uvp_ah.c @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include "mt_l2w.h" +#include "mlnx_uvp.h" +#include "mlnx_ual_data.h" +#include "mx_abi.h" + +static struct mthca_ah_page *__add_page( + struct mthca_pd *pd, int page_size, int per_page) +{ + struct mthca_ah_page *page; + int i; + + page = cl_malloc(sizeof *page + per_page * sizeof (int)); + if (!page) + return NULL; + + if (posix_memalign(&page->buf, page_size, page_size)) { + cl_free(page); + return NULL; + } + + page->use_cnt = 0; + for (i = 0; i < per_page; ++i) + page->free[i] = ~0; + + page->prev = NULL; + page->next = pd->ah_list; + pd->ah_list = page; + if (page->next) + page->next->prev = page; + + return page; +} + +int mthca_alloc_av(struct mthca_pd *pd, struct ibv_ah_attr *attr, + struct mthca_ah *ah, struct ibv_create_ah_resp *resp) +{ + if (mthca_is_memfree(pd->ibv_pd.context)) { + ah->av = cl_malloc(sizeof *ah->av); + if (!ah->av) + return -ENOMEM; + } else { + struct mthca_ah_page *page; + int ps; + int pp; + int i, j; + + ps = g_page_size; + pp = ps / (sizeof *ah->av * 8 * sizeof (int)); + + WaitForSingleObject( pd->ah_mutex, INFINITE ); + for (page = pd->ah_list; page; page = page->next) + if (page->use_cnt < ps / (int)(sizeof *ah->av)) + for (i = 0; i < pp; ++i) + if (page->free[i]) + goto found; + + page = __add_page(pd, ps, pp); + if (!page) { + ReleaseMutex( pd->ah_mutex ); + return -ENOMEM; + } + ah->in_kernel = TRUE; + + found: + ++page->use_cnt; + + for (i = 0, j = -1; i < pp; ++i) + if (page->free[i]) { + j = ffs(page->free[i]); + page->free[i] &= ~(1 << (j - 1)); + ah->av = (struct mthca_av *)((uint8_t*)page->buf + + (i * 8 * sizeof (int) + (j - 1)) * sizeof *ah->av); + break; + } + + ah->page = page; + + ReleaseMutex( pd->ah_mutex ); + } + + memset(ah->av, 0, sizeof *ah->av); + + ah->av->port_pd = cl_hton32(pd->pdn | (attr->port_num << 24)); + ah->av->g_slid = attr->src_path_bits; + ah->av->dlid = cl_hton16(attr->dlid); + ah->av->msg_sr = (3 << 4) | /* 2K message */ + attr->static_rate; + ah->av->sl_tclass_flowlabel = cl_hton32(attr->sl << 28); + if (attr->is_global) { + ah->av->g_slid |= 0x80; + /* XXX get gid_table length */ + ah->av->gid_index = (attr->port_num - 1) * 32 + + attr->grh.sgid_index; + ah->av->hop_limit = attr->grh.hop_limit; + ah->av->sl_tclass_flowlabel |= + cl_hton32((attr->grh.traffic_class << 20) | + attr->grh.flow_label); + memcpy(ah->av->dgid, attr->grh.dgid.raw, 16); + } else { + /* Arbel workaround -- low byte of GID must be 2 */ + ah->av->dgid[3] = cl_hton32(2); + } + return 0; +} + +void mthca_free_av(struct mthca_ah *ah) +{ + mlnx_ual_pd_info_t *p_pd = (mlnx_ual_pd_info_t *)ah->h_uvp_pd; + if (mthca_is_memfree(p_pd->ibv_pd->context)) { + cl_free(ah->av); + } else { + struct mthca_pd *pd = to_mpd(p_pd->ibv_pd); + struct mthca_ah_page *page; + int i; + + WaitForSingleObject( pd->ah_mutex, INFINITE ); + page = ah->page; + i = ((uint8_t *)ah->av - (uint8_t *)page->buf) / sizeof *ah->av; + page->free[i / (8 * sizeof (int))] |= 1 << (i % (8 * sizeof (int))); + --page->use_cnt; + ReleaseMutex( pd->ah_mutex ); + } +} + +//NB: temporary, for support of modify_qp +void mthca_set_av_params( struct mthca_ah *ah_p, struct ibv_ah_attr *ah_attr ) +{ + struct mthca_av *av = ah_p->av; + mlnx_ual_pd_info_t *p_pd = (mlnx_ual_pd_info_t *)ah_p->h_uvp_pd; + struct mthca_pd *pd =to_mpd(p_pd->ibv_pd); + + // taken from mthca_alloc_av + //TODO: why cl_hton32 ? + av->port_pd = cl_hton32(pd->pdn | (ah_attr->port_num << 24)); + av->g_slid = ah_attr->src_path_bits; + //TODO: why cl_hton16 ? + av->dlid = cl_hton16(ah_attr->dlid); + av->msg_sr = (3 << 4) | /* 2K message */ + ah_attr->static_rate; + //TODO: why cl_hton32 ? + av->sl_tclass_flowlabel = cl_hton32(ah_attr->sl << 28); + if (ah_attr->is_global) { + av->g_slid |= 0x80; + av->gid_index = (ah_attr->port_num - 1) * 32 + + ah_attr->grh.sgid_index; + av->hop_limit = ah_attr->grh.hop_limit; + av->sl_tclass_flowlabel |= cl_hton32((ah_attr->grh.traffic_class << 20) | + ah_attr->grh.flow_label); + memcpy(av->dgid, ah_attr->grh.dgid.raw, 16); + } else { + /* Arbel workaround -- low byte of GID must be 2 */ + //TODO: why cl_hton32 ? + av->dgid[3] = cl_hton32(2); + } +} + diff --git a/branches/WOF2-3/hw/mthca/user/mlnx_uvp_cq.c b/branches/WOF2-3/hw/mthca/user/mlnx_uvp_cq.c new file mode 100644 index 00000000..bfc0adda --- /dev/null +++ b/branches/WOF2-3/hw/mthca/user/mlnx_uvp_cq.c @@ -0,0 +1,628 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies Ltd. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include +#include +#include "mlnx_uvp.h" +#include "mlnx_uvp_doorbell.h" +#include + +#if defined(EVENT_TRACING) +#include "mlnx_uvp_cq.tmh" +#endif + + +enum { + MTHCA_CQ_DOORBELL = 0x20 +}; + +enum { + CQ_OK = 0, + CQ_EMPTY = -1, + CQ_POLL_ERR = -2 +}; + +#define MTHCA_TAVOR_CQ_DB_INC_CI (1 << 24) +#define MTHCA_TAVOR_CQ_DB_REQ_NOT (2 << 24) +#define MTHCA_TAVOR_CQ_DB_REQ_NOT_SOL (3 << 24) +#define MTHCA_TAVOR_CQ_DB_SET_CI (4 << 24) +#define MTHCA_TAVOR_CQ_DB_REQ_NOT_MULT (5 << 24) + +#define MTHCA_ARBEL_CQ_DB_REQ_NOT_SOL (1 << 24) +#define MTHCA_ARBEL_CQ_DB_REQ_NOT (2 << 24) +#define MTHCA_ARBEL_CQ_DB_REQ_NOT_MULT (3 << 24) + +enum { + MTHCA_CQ_ENTRY_OWNER_SW = 0x00, + MTHCA_CQ_ENTRY_OWNER_HW = 0x80, + MTHCA_ERROR_CQE_OPCODE_MASK = 0xfe +}; + +enum { + SYNDROME_LOCAL_LENGTH_ERR = 0x01, + SYNDROME_LOCAL_QP_OP_ERR = 0x02, + SYNDROME_LOCAL_EEC_OP_ERR = 0x03, + SYNDROME_LOCAL_PROT_ERR = 0x04, + SYNDROME_WR_FLUSH_ERR = 0x05, + SYNDROME_MW_BIND_ERR = 0x06, + SYNDROME_BAD_RESP_ERR = 0x10, + SYNDROME_LOCAL_ACCESS_ERR = 0x11, + SYNDROME_REMOTE_INVAL_REQ_ERR = 0x12, + SYNDROME_REMOTE_ACCESS_ERR = 0x13, + SYNDROME_REMOTE_OP_ERR = 0x14, + SYNDROME_RETRY_EXC_ERR = 0x15, + SYNDROME_RNR_RETRY_EXC_ERR = 0x16, + SYNDROME_LOCAL_RDD_VIOL_ERR = 0x20, + SYNDROME_REMOTE_INVAL_RD_REQ_ERR = 0x21, + SYNDROME_REMOTE_ABORTED_ERR = 0x22, + SYNDROME_INVAL_EECN_ERR = 0x23, + SYNDROME_INVAL_EEC_STATE_ERR = 0x24 +}; + +struct mthca_cqe { + uint32_t my_qpn; + uint32_t my_ee; + uint32_t rqpn; + uint16_t sl_g_mlpath; + uint16_t rlid; + uint32_t imm_etype_pkey_eec; + uint32_t byte_cnt; + uint32_t wqe; + uint8_t opcode; + uint8_t is_send; + uint8_t reserved; + uint8_t owner; +}; + +struct mthca_err_cqe { + uint32_t my_qpn; + uint32_t reserved1[3]; + uint8_t syndrome; + uint8_t vendor_err; + uint16_t db_cnt; + uint32_t reserved2; + uint32_t wqe; + uint8_t opcode; + uint8_t reserved3[2]; + uint8_t owner; +}; + +static inline struct mthca_cqe *get_cqe(struct mthca_cq *cq, int entry) +{ + return (struct mthca_cqe *)((uint8_t*)cq->buf + entry * MTHCA_CQ_ENTRY_SIZE); +} + +static inline struct mthca_cqe *cqe_sw(struct mthca_cq *cq, int i) +{ + struct mthca_cqe *cqe = get_cqe(cq, i); + return MTHCA_CQ_ENTRY_OWNER_HW & cqe->owner ? NULL : cqe; +} + +static inline struct mthca_cqe *next_cqe_sw(struct mthca_cq *cq) +{ + return cqe_sw(cq, cq->cons_index & cq->ibv_cq.cqe); +} + +static inline void set_cqe_hw(struct mthca_cqe *cqe) +{ + cqe->owner = MTHCA_CQ_ENTRY_OWNER_HW; +} + +/* + * incr is ignored in native Arbel (mem-free) mode, so cq->cons_index + * should be correct before calling update_cons_index(). + */ +static inline void update_cons_index(struct mthca_cq *cq, int incr) +{ + uint32_t doorbell[2]; + + if (mthca_is_memfree(cq->ibv_cq.context)) { + *cq->set_ci_db = cl_hton32(cq->cons_index); + mb(); + } else { + doorbell[0] = cl_hton32(MTHCA_TAVOR_CQ_DB_INC_CI | cq->cqn); + doorbell[1] = cl_hton32(incr - 1); + + mthca_write64(doorbell, to_mctx(cq->ibv_cq.context), MTHCA_CQ_DOORBELL); + } +} + + +static void dump_cqe(uint32_t print_lvl, void *cqe_ptr) +{ + uint32_t *cqe = cqe_ptr; + int i; + (void) cqe; /* avoid warning if mthca_dbg compiled away... */ + + UVP_PRINT(print_lvl,UVP_DBG_CQ,("CQE content \n")); + UVP_PRINT(print_lvl,UVP_DBG_CQ,(" [%2x] %08x %08x %08x %08x \n",0 + , cl_ntoh32(cqe[0]), cl_ntoh32(cqe[1]), cl_ntoh32(cqe[2]), cl_ntoh32(cqe[3]))); + UVP_PRINT(print_lvl,UVP_DBG_CQ,(" [%2x] %08x %08x %08x %08x\n",16 + , cl_ntoh32(cqe[4]), cl_ntoh32(cqe[5]), cl_ntoh32(cqe[6]), cl_ntoh32(cqe[7]))); + +} + +static int handle_error_cqe(struct mthca_cq *cq, + struct mthca_qp *qp, int wqe_index, int is_send, + struct mthca_err_cqe *cqe, + struct _ib_wc *entry, int *free_cqe) +{ + int err; + int dbd; + uint32_t new_wqe; + + if (cqe->syndrome == SYNDROME_LOCAL_QP_OP_ERR) { + UVP_PRINT(TRACE_LEVEL_ERROR , UVP_DBG_CQ,("local QP operation err " + "(QPN %06x, WQE @ %08x, CQN %06x, index %d, vendor_err %d)\n", + cl_ntoh32(cqe->my_qpn), cl_ntoh32(cqe->wqe), + cq->cqn, cq->cons_index, cqe->vendor_err)); + dump_cqe(TRACE_LEVEL_VERBOSE, cqe); + } + + /* + * For completions in error, only work request ID, status, vendor error + * (and freed resource count for RD) have to be set. + */ + switch (cqe->syndrome) { + case SYNDROME_LOCAL_LENGTH_ERR: + entry->status = IB_WCS_LOCAL_LEN_ERR; + break; + case SYNDROME_LOCAL_QP_OP_ERR: + entry->status = IB_WCS_LOCAL_OP_ERR; + break; + case SYNDROME_LOCAL_PROT_ERR: + entry->status = IB_WCS_LOCAL_PROTECTION_ERR; + break; + case SYNDROME_WR_FLUSH_ERR: + entry->status = IB_WCS_WR_FLUSHED_ERR; + break; + case SYNDROME_MW_BIND_ERR: + entry->status = IB_WCS_MEM_WINDOW_BIND_ERR; + break; + case SYNDROME_BAD_RESP_ERR: + entry->status = IB_WCS_BAD_RESP_ERR; + break; + case SYNDROME_LOCAL_ACCESS_ERR: + entry->status = IB_WCS_LOCAL_ACCESS_ERR; + break; + case SYNDROME_REMOTE_INVAL_REQ_ERR: + entry->status = IB_WCS_REM_INVALID_REQ_ERR; + break; + case SYNDROME_REMOTE_ACCESS_ERR: + entry->status = IB_WCS_REM_ACCESS_ERR; + break; + case SYNDROME_REMOTE_OP_ERR: + entry->status = IB_WCS_REM_OP_ERR; + break; + case SYNDROME_RETRY_EXC_ERR: + entry->status = IB_WCS_TIMEOUT_RETRY_ERR; + break; + case SYNDROME_RNR_RETRY_EXC_ERR: + entry->status = IB_WCS_RNR_RETRY_ERR; + break; + case SYNDROME_LOCAL_EEC_OP_ERR: + case SYNDROME_LOCAL_RDD_VIOL_ERR: + case SYNDROME_REMOTE_INVAL_RD_REQ_ERR: + case SYNDROME_REMOTE_ABORTED_ERR: + case SYNDROME_INVAL_EECN_ERR: + case SYNDROME_INVAL_EEC_STATE_ERR: + default: + entry->status = IB_WCS_GENERAL_ERR; + break; + } + + entry->vendor_specific = cqe->vendor_err; + + /* + * Mem-free HCAs always generate one CQE per WQE, even in the + * error case, so we don't have to check the doorbell count, etc. + */ + if (mthca_is_memfree(cq->ibv_cq.context)) + return 0; + + err = mthca_free_err_wqe(qp, is_send, wqe_index, &dbd, &new_wqe); + if (err) + return err; + + /* + * If we're at the end of the WQE chain, or we've used up our + * doorbell count, free the CQE. Otherwise just update it for + * the next poll operation. + * + * This doesn't apply to mem-free HCAs, which never use the + * doorbell count field. In that case we always free the CQE. + */ + if (mthca_is_memfree(cq->ibv_cq.context) || + !(new_wqe & cl_hton32(0x3f)) || (!cqe->db_cnt && dbd)) + return 0; + + cqe->db_cnt = cl_hton16(cl_ntoh16(cqe->db_cnt) - dbd); + cqe->wqe = new_wqe; + cqe->syndrome = SYNDROME_WR_FLUSH_ERR; + + *free_cqe = 0; + + return 0; +} + +static inline int mthca_poll_one(struct mthca_cq *cq, + struct mthca_qp **cur_qp, + int *freed, + struct _ib_wc *entry) +{ + struct mthca_wq *wq; + struct mthca_cqe *cqe; + uint32_t qpn; + int wqe_index; + int is_error; + int is_send; + int free_cqe = 1; + int err = 0; + + UVP_ENTER(UVP_DBG_CQ); + + cqe = next_cqe_sw(cq); + if (!cqe) + return -EAGAIN; + + /* + * Make sure we read CQ entry contents after we've checked the + * ownership bit. + */ + rmb(); + + { // debug print + UVP_PRINT(TRACE_LEVEL_VERBOSE,UVP_DBG_CQ,("%x/%d: CQE -> QPN %06x, WQE @ %08x\n", + cq->cqn, cq->cons_index, cl_ntoh32(cqe->my_qpn), + cl_ntoh32(cqe->wqe))); + dump_cqe(TRACE_LEVEL_VERBOSE,cqe); + } + + qpn = cl_ntoh32(cqe->my_qpn); + + is_error = (cqe->opcode & MTHCA_ERROR_CQE_OPCODE_MASK) == + MTHCA_ERROR_CQE_OPCODE_MASK; + is_send = is_error ? cqe->opcode & 0x01 : cqe->is_send & 0x80; + + if (!*cur_qp || cl_ntoh32(cqe->my_qpn) != (*cur_qp)->ibv_qp.qp_num) { + /* + * We do not have to take the QP table lock here, + * because CQs will be locked while QPs are removed + * from the table. + */ + *cur_qp = mthca_find_qp(to_mctx(cq->ibv_cq.context), cl_ntoh32(cqe->my_qpn)); + if (!*cur_qp) { + UVP_PRINT(TRACE_LEVEL_WARNING,UVP_DBG_CQ, ("CQ entry for unknown QP %06x\n", + cl_ntoh32(cqe->my_qpn) & 0xffffff)); + err = -EINVAL; + goto out; + } + } + + if (is_send) { + wq = &(*cur_qp)->sq; + wqe_index = ((cl_ntoh32(cqe->wqe) - (*cur_qp)->send_wqe_offset) >> wq->wqe_shift); + entry->wr_id = (*cur_qp)->wrid[wqe_index + (*cur_qp)->rq.max]; + } else if ((*cur_qp)->ibv_qp.srq) { + struct mthca_srq * srq = to_msrq((*cur_qp)->ibv_qp.srq); + uint32_t wqe = cl_hton32(cqe->wqe); + wq = NULL; + wqe_index = wqe >> srq->wqe_shift; + entry->wr_id = srq->wrid[wqe_index]; + mthca_free_srq_wqe(srq, wqe_index); + } else { + wq = &(*cur_qp)->rq; + wqe_index = cl_ntoh32(cqe->wqe) >> wq->wqe_shift; + entry->wr_id = (*cur_qp)->wrid[wqe_index]; + } + + if (wq) { + if ((int)wq->last_comp < wqe_index) + wq->tail += wqe_index - wq->last_comp; + else + wq->tail += wqe_index + wq->max - wq->last_comp; + + wq->last_comp = wqe_index; + } + + if (is_send) { + entry->recv.ud.recv_opt = 0; + switch (cqe->opcode) { + case MTHCA_OPCODE_RDMA_WRITE: + entry->wc_type = IB_WC_RDMA_WRITE; + break; + case MTHCA_OPCODE_RDMA_WRITE_IMM: + entry->wc_type = IB_WC_RDMA_WRITE; + entry->recv.ud.recv_opt |= IB_RECV_OPT_IMMEDIATE; + break; + case MTHCA_OPCODE_SEND: + entry->wc_type = IB_WC_SEND; + break; + case MTHCA_OPCODE_SEND_IMM: + entry->wc_type = IB_WC_SEND; + entry->recv.ud.recv_opt |= IB_RECV_OPT_IMMEDIATE; + break; + case MTHCA_OPCODE_RDMA_READ: + entry->wc_type = IB_WC_RDMA_READ; + entry->length = cl_ntoh32(cqe->byte_cnt); + break; + case MTHCA_OPCODE_ATOMIC_CS: + entry->wc_type = IB_WC_COMPARE_SWAP; + entry->length = MTHCA_BYTES_PER_ATOMIC_COMPL; + break; + case MTHCA_OPCODE_ATOMIC_FA: + entry->wc_type = IB_WC_FETCH_ADD; + entry->length = MTHCA_BYTES_PER_ATOMIC_COMPL; + break; + case MTHCA_OPCODE_BIND_MW: + entry->wc_type = IB_WC_MW_BIND; + break; + default: + /* assume it's a send completion */ + entry->wc_type = IB_WC_SEND; + break; + } + } else { + entry->length = cl_ntoh32(cqe->byte_cnt); + switch (cqe->opcode & 0x1f) { + case IBV_OPCODE_SEND_LAST_WITH_IMMEDIATE: + case IBV_OPCODE_SEND_ONLY_WITH_IMMEDIATE: + entry->recv.ud.recv_opt = IB_RECV_OPT_IMMEDIATE; + entry->recv.ud.immediate_data = cqe->imm_etype_pkey_eec; + entry->wc_type = IB_WC_RECV; + break; + case IBV_OPCODE_RDMA_WRITE_LAST_WITH_IMMEDIATE: + case IBV_OPCODE_RDMA_WRITE_ONLY_WITH_IMMEDIATE: + entry->recv.ud.recv_opt = IB_RECV_OPT_IMMEDIATE; + entry->recv.ud.immediate_data = cqe->imm_etype_pkey_eec; + entry->wc_type = IB_WC_RECV; + break; + default: + entry->recv.ud.recv_opt = 0; + entry->wc_type = IB_WC_RECV; + break; + } + entry->recv.ud.remote_lid = cqe->rlid; + entry->recv.ud.remote_qp = cqe->rqpn & 0xffffff00; + entry->recv.ud.pkey_index = (uint16_t)(cl_ntoh32(cqe->imm_etype_pkey_eec) >> 16); + entry->recv.ud.remote_sl = cl_ntoh16(cqe->sl_g_mlpath) >> 12; + entry->recv.ud.path_bits = cl_ntoh16(cqe->sl_g_mlpath) & 0x7f; + entry->recv.ud.recv_opt |= cl_ntoh16(cqe->sl_g_mlpath) & 0x80 ? + IB_RECV_OPT_GRH_VALID : 0; + } + + + if (is_error) { + err = handle_error_cqe(cq, *cur_qp, wqe_index, is_send, + (struct mthca_err_cqe *) cqe, + entry, &free_cqe); + } + else + entry->status = IB_WCS_SUCCESS; + +out: + if (likely(free_cqe)) { + set_cqe_hw(cqe); + ++(*freed); + ++cq->cons_index; + } + + UVP_EXIT(UVP_DBG_CQ); + return err; +} + +int mthca_poll_cq(struct ibv_cq *ibcq, int num_entries, struct _uvp_wc *entry) +{ + struct mthca_cq *cq = to_mcq(ibcq); + struct mthca_qp *qp = NULL; + int err = CQ_OK; + int freed = 0; + int npolled; + + cl_spinlock_acquire(&cq->lock); + + for (npolled = 0; npolled < num_entries; ++npolled) { + err = mthca_poll_one(cq, &qp, &freed, (struct _ib_wc *) (entry + npolled)); + if (err) + break; + entry[npolled].qp_context = qp->ibv_qp.qp_context; + } + + if (freed) { + wmb(); + update_cons_index(cq, freed); + } + + cl_spinlock_release(&cq->lock); + + return (err == 0 || err == -EAGAIN) ? npolled : err; +} + +int mthca_poll_cq_list( + IN struct ibv_cq *ibcq, + IN OUT struct _ib_wc** const pp_free_wclist, + OUT struct _ib_wc** const pp_done_wclist ) +{ + struct mthca_cq *cq = to_mcq(ibcq); + struct mthca_qp *qp = NULL; + int err = CQ_OK; + int freed = 0; + ib_wc_t *wc_p, **next_pp; + uint32_t wc_cnt = 0; + + cl_spinlock_acquire(&cq->lock); + + // loop through CQ + next_pp = pp_done_wclist; + wc_p = *pp_free_wclist; + while( wc_p ) { + // poll one CQE + err = mthca_poll_one(cq, &qp, &freed, wc_p); + if (err) + break; + + // prepare for the next loop + *next_pp = wc_p; + next_pp = &wc_p->p_next; + wc_p = wc_p->p_next; + } + + // prepare the results + *pp_free_wclist = wc_p; /* Set the head of the free list. */ + *next_pp = NULL; /* Clear the tail of the done list. */ + + // update consumer index + if (freed) { + wmb(); + update_cons_index(cq, freed); + } + + cl_spinlock_release(&cq->lock); + return (err == 0 || err == -EAGAIN)? 0 : err; +} + +int mthca_tavor_arm_cq(struct ibv_cq *cq, enum ib_cq_notify notify) +{ + uint32_t doorbell[2]; + + doorbell[0] = cl_hton32((notify == IB_CQ_SOLICITED ? + MTHCA_TAVOR_CQ_DB_REQ_NOT_SOL : + MTHCA_TAVOR_CQ_DB_REQ_NOT) | + to_mcq(cq)->cqn); + doorbell[1] = 0xffffffff; + + mthca_write64(doorbell, to_mctx(cq->context), MTHCA_CQ_DOORBELL); + + return 0; +} + +int mthca_arbel_arm_cq(struct ibv_cq *ibvcq, enum ib_cq_notify notify) +{ + struct mthca_cq *cq = to_mcq(ibvcq); + uint32_t doorbell[2]; + uint32_t sn; + uint32_t ci; + + sn = *cq->p_u_arm_sn & 3; + ci = cl_hton32(cq->cons_index); + + doorbell[0] = ci; + doorbell[1] = cl_hton32((cq->cqn << 8) | (2 << 5) | (sn << 3) | + (notify == IB_CQ_SOLICITED ? 1 : 2)); + + mthca_write_db_rec(doorbell, cq->arm_db); + + /* + * Make sure that the doorbell record in host memory is + * written before ringing the doorbell via PCI MMIO. + */ + wmb(); + + doorbell[0] = cl_hton32((sn << 28) | + (notify == IB_CQ_SOLICITED ? + MTHCA_ARBEL_CQ_DB_REQ_NOT_SOL : + MTHCA_ARBEL_CQ_DB_REQ_NOT) | + cq->cqn); + doorbell[1] = ci; + + mthca_write64(doorbell, to_mctx(ibvcq->context), MTHCA_CQ_DOORBELL); + + return 0; +} + +static inline int is_recv_cqe(struct mthca_cqe *cqe) +{ + if ((cqe->opcode & MTHCA_ERROR_CQE_OPCODE_MASK) == + MTHCA_ERROR_CQE_OPCODE_MASK) + return !(cqe->opcode & 0x01); + else + return !(cqe->is_send & 0x80); +} + +void mthca_cq_clean(struct mthca_cq *cq, uint32_t qpn, struct mthca_srq *srq) +{ + struct mthca_cqe *cqe; + uint32_t prod_index; + int nfreed = 0; + + cl_spinlock_acquire(&cq->lock); + + /* + * First we need to find the current producer index, so we + * know where to start cleaning from. It doesn't matter if HW + * adds new entries after this loop -- the QP we're worried + * about is already in RESET, so the new entries won't come + * from our QP and therefore don't need to be checked. + */ + for (prod_index = cq->cons_index; + cqe_sw(cq, prod_index & cq->ibv_cq.cqe); + ++prod_index) + if (prod_index == cq->cons_index + cq->ibv_cq.cqe) + break; + + /* + * Now sweep backwards through the CQ, removing CQ entries + * that match our QP by copying older entries on top of them. + */ + while ((int) --prod_index - (int) cq->cons_index >= 0) { + cqe = get_cqe(cq, prod_index & cq->ibv_cq.cqe); + if (cqe->my_qpn == cl_hton32(qpn)) { + if (srq && is_recv_cqe(cqe)) + mthca_free_srq_wqe(srq, + cl_ntoh32(cqe->wqe) >> srq->wqe_shift); + ++nfreed; + } else if (nfreed) + memcpy(get_cqe(cq, (prod_index + nfreed) & cq->ibv_cq.cqe), + cqe, MTHCA_CQ_ENTRY_SIZE); + } + + if (nfreed) { + mb(); + cq->cons_index += nfreed; + update_cons_index(cq, nfreed); + } + + cl_spinlock_release(&cq->lock); +} + +void mthca_init_cq_buf(struct mthca_cq *cq, int nent) +{ + int i; + + for (i = 0; i < nent; ++i) + set_cqe_hw(get_cqe(cq, i)); + + cq->cons_index = 0; +} diff --git a/branches/WOF2-3/hw/mthca/user/mlnx_uvp_debug.c b/branches/WOF2-3/hw/mthca/user/mlnx_uvp_debug.c new file mode 100644 index 00000000..3fc71134 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/user/mlnx_uvp_debug.c @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2005 Mellanox Technologies LTD. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +// Author: Yossi Leybovich + +#include "mlnx_uvp_debug.h" +#include +#include +#include + +#if !defined(EVENT_TRACING) + + +#if DBG +uint32_t g_mlnx_dbg_level = TRACE_LEVEL_WARNING; +uint32_t g_mlnx_dbg_flags= UVP_DBG_QP | UVP_DBG_CQ|UVP_DBG_MEMORY; +#endif + +VOID +_UVP_PRINT( + IN char* msg, + ... + ) + + { +#if DBG +#define TEMP_BUFFER_SIZE 1024 + va_list list; + UCHAR debugMessageBuffer[TEMP_BUFFER_SIZE]; + HRESULT result; + + va_start(list, msg); + + if (msg) { + + // + // Using new safe string functions instead of _vsnprintf. This function takes + // care of NULL terminating if the message is longer than the buffer. + // + + result = StringCbVPrintfA (debugMessageBuffer, sizeof(debugMessageBuffer), + msg, list); + if(((HRESULT)(result) < 0)) { + + OutputDebugString (": StringCbVPrintfA failed \n"); + return; + } + OutputDebugString ( debugMessageBuffer); + + } + va_end(list); + + return; +#endif //DBG +} + +#endif //EVENT_TRACING + diff --git a/branches/WOF2-3/hw/mthca/user/mlnx_uvp_debug.h b/branches/WOF2-3/hw/mthca/user/mlnx_uvp_debug.h new file mode 100644 index 00000000..2a9cbc5b --- /dev/null +++ b/branches/WOF2-3/hw/mthca/user/mlnx_uvp_debug.h @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#ifndef _MLNX_UVP_DEBUG_H_ +#define _MLNX_UVP_DEBUG_H_ + +#include + +extern uint32_t g_mlnx_dbg_level; +extern uint32_t g_mlnx_dbg_flags; + + +#if defined(EVENT_TRACING) +// +// Software Tracing Definitions +// +// + +#define WPP_CONTROL_GUIDS \ + WPP_DEFINE_CONTROL_GUID(HCACtlGuid,(2C718E52,0D36,4bda,9E58,0FC601818D8F), \ + WPP_DEFINE_BIT( UVP_DBG_DEV) \ + WPP_DEFINE_BIT( UVP_DBG_PNP) \ + WPP_DEFINE_BIT( UVP_DBG_MAD) \ + WPP_DEFINE_BIT( UVP_DBG_PO) \ + WPP_DEFINE_BIT( UVP_DBG_CQ) \ + WPP_DEFINE_BIT( UVP_DBG_QP) \ + WPP_DEFINE_BIT( UVP_DBG_MEMORY) \ + WPP_DEFINE_BIT( UVP_DBG_SRQ) \ + WPP_DEFINE_BIT( UVP_DBG_AV) \ + WPP_DEFINE_BIT( UVP_DBG_SEND) \ + WPP_DEFINE_BIT( UVP_DBG_RECV) \ + WPP_DEFINE_BIT( UVP_DBG_LOW) \ + WPP_DEFINE_BIT( UVP_DBG_SHIM)) + + +#define WPP_LEVEL_FLAGS_ENABLED(lvl, flags) (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= lvl) +#define WPP_LEVEL_FLAGS_LOGGER(lvl,flags) WPP_LEVEL_LOGGER(flags) +#define WPP_FLAG_ENABLED(flags)(WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= TRACE_LEVEL_VERBOSE) +#define WPP_FLAG_LOGGER(flags) WPP_LEVEL_LOGGER(flags) + + +// begin_wpp config +// UVP_ENTER(FLAG); +// UVP_EXIT(FLAG); +// USEPREFIX(UVP_PRINT, "%!FUNC!() "); +// USESUFFIX(UVP_ENTER, "%!FUNC!===>"); +// USESUFFIX(UVP_EXIT, "%!FUNC!<==="); +// end_wpp + + +#else + +#include +#include + +/* + * Debug macros + */ + + +#define UVP_DBG_DEV (1 << 0) +#define UVP_DBG_PNP (1 << 1) +#define UVP_DBG_MAD (1 << 2) +#define UVP_DBG_PO (1 << 3) +#define UVP_DBG_QP (1 << 4) +#define UVP_DBG_CQ (1 << 5) +#define UVP_DBG_MEMORY (1 << 6) +#define UVP_DBG_SRQ (1 << 7) +#define UVP_DBG_AV (1 << 8) +#define UVP_DBG_SEND (1 << 9) +#define UVP_DBG_RECV (1 << 10) +#define UVP_DBG_LOW (1 << 11) +#define UVP_DBG_SHIM (1 << 12) + + +VOID + _UVP_PRINT( + IN char* msg, + ...); + +#if DBG + +#define UVP_PRINT(_level_,_flags_,_msg_) \ + if ((_level_) <= g_mlnx_dbg_level && (_flags_) & g_mlnx_dbg_flags) {\ + _UVP_PRINT("[UVP] %s():",__FUNCTION__);\ + if((_level_) == TRACE_LEVEL_ERROR) _UVP_PRINT ("***ERROR*** ");\ + _UVP_PRINT _msg_ ; \ + } + + +// +#else + +#define UVP_PRINT(lvl ,flags, msg) + +#endif + + +#define UVP_ENTER(flags)\ + UVP_PRINT(TRACE_LEVEL_VERBOSE, flags,("===>\n")); + +#define UVP_EXIT(flags)\ + UVP_PRINT(TRACE_LEVEL_VERBOSE, flags,("<===\n")); + +#define UVP_PRINT_EXIT(_level_,_flag_,_msg_) \ + {\ + if (status != IB_SUCCESS) {\ + UVP_PRINT(_level_,_flag_,_msg_);\ + }\ + UVP_EXIT(_flag_);\ + } + +#endif //EVENT_TRACING + +#endif /*_MLNX_UVP_DEBUG_H_ */ + diff --git a/branches/WOF2-3/hw/mthca/user/mlnx_uvp_doorbell.h b/branches/WOF2-3/hw/mthca/user/mlnx_uvp_doorbell.h new file mode 100644 index 00000000..7928eceb --- /dev/null +++ b/branches/WOF2-3/hw/mthca/user/mlnx_uvp_doorbell.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#ifndef DOORBELL_H +#define DOORBELL_H + +enum { + MTHCA_SEND_DOORBELL_FENCE = 1 << 5 +}; +#if defined _WIN64 + +static inline void mthca_write64(uint32_t val[2], struct mthca_context *ctx, int offset) +{ + *(volatile uint64_t *) ((char *)ctx->uar + offset) = *(volatile uint64_t*)val; +} + +static inline void mthca_write_db_rec(uint32_t val[2], uint32_t *db) +{ + *(volatile uint64_t *) db = *(volatile uint64_t*)val; +} + + +#elif defined(_WIN32) + +static inline void mthca_write64(uint32_t val[2], struct mthca_context *ctx, int offset) +{ + volatile uint64_t *target_p = (volatile uint64_t*)((uint8_t*)ctx->uar + offset); + + cl_spinlock_acquire(&ctx->uar_lock); + *(volatile uint32_t *) ((uint8_t*)ctx->uar + offset) = val[0]; + *(volatile uint32_t *) ((uint8_t*)ctx->uar + offset + 4) = val[1]; + cl_spinlock_release(&ctx->uar_lock); + + //TODO: can we save mm0 and not to use emms, as Linux do ? + //__asm movq mm0,val + //__asm movq target_p,mm0 + //__asm emms +} +static inline void mthca_write_db_rec(uint32_t val[2], uint32_t *db) +{ + db[0] = val[0]; + wmb(); + db[1] = val[1]; +} + + +#endif + +#endif /* MTHCA_H */ diff --git a/branches/WOF2-3/hw/mthca/user/mlnx_uvp_memfree.c b/branches/WOF2-3/hw/mthca/user/mlnx_uvp_memfree.c new file mode 100644 index 00000000..c0b4a925 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/user/mlnx_uvp_memfree.c @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include + +#include "mlnx_uvp.h" + +#define MTHCA_FREE_MAP_SIZE (MTHCA_DB_REC_PER_PAGE / BITS_PER_LONG) + +struct mthca_db_page { + unsigned long free[MTHCA_FREE_MAP_SIZE]; + uint64_t *db_rec; +}; + +struct mthca_db_table { + int npages; + int max_group1; + int min_group2; + HANDLE mutex; + struct mthca_db_page page[]; +}; + +int mthca_alloc_db(struct mthca_db_table *db_tab, enum mthca_db_type type, + uint32_t **db) +{ + int i, j, k; + int group, start, end, dir; + int ret = 0; + + WaitForSingleObject( db_tab->mutex, INFINITE ); + + switch (type) { + case MTHCA_DB_TYPE_CQ_ARM: + case MTHCA_DB_TYPE_SQ: + group = 0; + start = 0; + end = db_tab->max_group1; + dir = 1; + break; + + case MTHCA_DB_TYPE_CQ_SET_CI: + case MTHCA_DB_TYPE_RQ: + case MTHCA_DB_TYPE_SRQ: + group = 1; + start = db_tab->npages - 1; + end = db_tab->min_group2; + dir = -1; + break; + + default: + ret = -1; + goto out; + } + + for (i = start; i != end; i += dir) + if (db_tab->page[i].db_rec) + for (j = 0; j < MTHCA_FREE_MAP_SIZE; ++j) + if (db_tab->page[i].free[j]) + goto found; + + if (db_tab->max_group1 >= db_tab->min_group2 - 1) { + ret = -1; + goto out; + } + + if (posix_memalign((void **) &db_tab->page[i].db_rec, MTHCA_DB_REC_PAGE_SIZE, + MTHCA_DB_REC_PAGE_SIZE)) { + ret = -1; + goto out; + } + + memset(db_tab->page[i].db_rec, 0, MTHCA_DB_REC_PAGE_SIZE); + memset(db_tab->page[i].free, 0xff, sizeof db_tab->page[i].free); + + if (group == 0) + ++db_tab->max_group1; + else + --db_tab->min_group2; + +found: + for (j = 0; j < MTHCA_FREE_MAP_SIZE; ++j) { + k = ffsl(db_tab->page[i].free[j]); + if (k) + break; + } + + if (!k) { + ret = -1; + goto out; + } + + --k; + db_tab->page[i].free[j] &= ~(1UL << k); + + j = j * BITS_PER_LONG + k; + if (group == 1) + j = MTHCA_DB_REC_PER_PAGE - 1 - j; + + ret = i * MTHCA_DB_REC_PER_PAGE + j; + *db = (uint32_t *) &db_tab->page[i].db_rec[j]; + +out: + ReleaseMutex( db_tab->mutex ); + return ret; +} + +void mthca_set_db_qn(uint32_t *db, enum mthca_db_type type, uint32_t qn) +{ + db[1] = cl_hton32((qn << 8) | (type << 5)); +} + +void mthca_free_db(struct mthca_db_table *db_tab, enum mthca_db_type type, int db_index) +{ + int i, j; + struct mthca_db_page *page; + + i = db_index / MTHCA_DB_REC_PER_PAGE; + j = db_index % MTHCA_DB_REC_PER_PAGE; + + page = db_tab->page + i; + + WaitForSingleObject( db_tab->mutex, INFINITE ); + page->db_rec[j] = 0; + + if (i >= db_tab->min_group2) + j = MTHCA_DB_REC_PER_PAGE - 1 - j; + + page->free[j / BITS_PER_LONG] |= 1UL << (j % BITS_PER_LONG); + + ReleaseMutex( db_tab->mutex ); +} + +struct mthca_db_table *mthca_alloc_db_tab(int uarc_size) +{ + struct mthca_db_table *db_tab; + int npages; + int i; + + npages = uarc_size / MTHCA_DB_REC_PAGE_SIZE; + db_tab = cl_malloc(sizeof (struct mthca_db_table) + + npages * sizeof (struct mthca_db_page)); + if (!db_tab) + goto err_malloc; + + db_tab->mutex = CreateMutex( NULL, FALSE, NULL ); + if (!db_tab->mutex) + goto err_mutex; + db_tab->npages = npages; + db_tab->max_group1 = 0; + db_tab->min_group2 = npages - 1; + + for (i = 0; i < npages; ++i) + db_tab->page[i].db_rec = NULL; + + goto end; + +err_mutex: + cl_free(db_tab); +err_malloc: +end: + return db_tab; +} + +void mthca_free_db_tab(struct mthca_db_table *db_tab) +{ + int i; + + if (!db_tab) + return; + + for (i = 0; i < db_tab->npages; ++i) + if (db_tab->page[i].db_rec) + posix_memfree( db_tab->page[i].db_rec); + + cl_free(db_tab); +} diff --git a/branches/WOF2-3/hw/mthca/user/mlnx_uvp_qp.c b/branches/WOF2-3/hw/mthca/user/mlnx_uvp_qp.c new file mode 100644 index 00000000..4fa37679 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/user/mlnx_uvp_qp.c @@ -0,0 +1,1088 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies Ltd. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include +#include "mlnx_uvp.h" +#include "mlnx_uvp_doorbell.h" +#include "mthca_wqe.h" +#include "mlnx_ual_data.h" + +#if defined(EVENT_TRACING) +#include "mlnx_uvp_qp.tmh" +#endif + +static const uint8_t mthca_opcode[] = { + MTHCA_OPCODE_RDMA_WRITE, + MTHCA_OPCODE_RDMA_WRITE_IMM, + MTHCA_OPCODE_SEND, + MTHCA_OPCODE_SEND_IMM, + MTHCA_OPCODE_RDMA_READ, + MTHCA_OPCODE_ATOMIC_CS, + MTHCA_OPCODE_ATOMIC_FA +}; + +static enum mthca_wr_opcode conv_ibal_wr_opcode(struct _ib_send_wr *wr) +{ + enum mthca_wr_opcode opcode = -1; //= wr->wr_type; + + switch (wr->wr_type) { + case WR_SEND: + opcode = (wr->send_opt & IB_SEND_OPT_IMMEDIATE) ? MTHCA_OPCODE_SEND_IMM : MTHCA_OPCODE_SEND; + break; + case WR_RDMA_WRITE: + opcode = (wr->send_opt & IB_SEND_OPT_IMMEDIATE) ? MTHCA_OPCODE_RDMA_WRITE_IMM : MTHCA_OPCODE_RDMA_WRITE; + break; + case WR_RDMA_READ: opcode = MTHCA_OPCODE_RDMA_READ; break; + case WR_COMPARE_SWAP: opcode = MTHCA_OPCODE_ATOMIC_CS; break; + case WR_FETCH_ADD: opcode = MTHCA_OPCODE_ATOMIC_FA; break; + default: opcode = MTHCA_OPCODE_INVALID;break; + } + return opcode; +} + + +static void dump_wqe(uint32_t print_lvl, uint32_t *wqe_ptr , struct mthca_qp *qp_ptr, int size) +{ + net32_t *wqe = wqe_ptr; + int i; + + (void) wqe; /* avoid warning if mthca_dbg compiled away... */ + UVP_PRINT(print_lvl,UVP_DBG_QP,("WQE: QPN 0x%06x, buf %p , buf_sz %d, send_offset %d\n", + qp_ptr->ibv_qp.qp_num, qp_ptr->buf, qp_ptr->buf_size, qp_ptr->send_wqe_offset )); + for (i=0; ibuf + (n << qp->rq.wqe_shift); +} + +static void *get_send_wqe(struct mthca_qp *qp, int n) +{ + void *wqe_addr = qp->buf + qp->send_wqe_offset + (n << qp->sq.wqe_shift); + UVP_PRINT(TRACE_LEVEL_INFORMATION,UVP_DBG_QP, + ("wqe %p, qp_buf %p, offset %#x, index %d, shift %d \n", + wqe_addr, qp->buf, qp->send_wqe_offset, n, + qp->sq.wqe_shift)); + + return wqe_addr; +} + +void mthca_init_qp_indices(struct mthca_qp *qp) +{ + qp->sq.next_ind = 0; + qp->sq.last_comp = qp->sq.max - 1; + qp->sq.head = 0; + qp->sq.tail = 0; + qp->sq.last = get_send_wqe(qp, qp->sq.max - 1); + + qp->rq.next_ind = 0; + qp->rq.last_comp = qp->rq.max - 1; + qp->rq.head = 0; + qp->rq.tail = 0; + qp->rq.last = get_recv_wqe(qp, qp->rq.max - 1); +} + +static inline int mthca_wq_overflow(struct mthca_wq *wq, int nreq, struct mthca_cq *cq) +{ + unsigned cur; + + cur = wq->head - wq->tail; + if ((int)(cur + nreq) < wq->max) + return 0; + + cl_spinlock_acquire(&cq->lock); + cur = wq->head - wq->tail; + cl_spinlock_release(&cq->lock); + + return (int)(cur + nreq) >= wq->max; +} + + +int mthca_tavor_post_send(struct ibv_qp *ibqp, struct _ib_send_wr *wr, + struct _ib_send_wr **bad_wr) +{ + struct mthca_qp *qp = to_mqp(ibqp); + uint8_t *wqe; + uint8_t *prev_wqe; + int ret = 0; + int nreq; + int i; + int size; + int size0 = 0; + uint32_t f0 = unlikely(wr->send_opt & IB_SEND_OPT_FENCE) ? MTHCA_SEND_DOORBELL_FENCE : 0; + int ind; + int op0 = 0; + enum ib_wr_opcode opcode; + + UVP_ENTER(UVP_DBG_QP); + cl_spinlock_acquire(&qp->sq.lock); + + /* XXX check that state is OK to post send */ + + ind = qp->sq.next_ind; + + if(ibqp->state == IBV_QPS_RESET) { + ret = -EBUSY; + if (bad_wr) + *bad_wr = wr; + goto err_busy; + } + + for (nreq = 0; wr; ++nreq, wr = wr->p_next) { + + if (mthca_wq_overflow(&qp->sq, nreq, to_mcq(qp->ibv_qp.send_cq))) { + UVP_PRINT(TRACE_LEVEL_ERROR ,UVP_DBG_QP ,("SQ %06x full (%u head, %u tail," + " %d max, %d nreq)\n", ibqp->qp_num, + qp->sq.head, qp->sq.tail, + qp->sq.max, nreq)); + ret = -ENOMEM; + if (bad_wr) + *bad_wr = wr; + goto out; + } + + wqe = get_send_wqe(qp, ind); + prev_wqe = qp->sq.last; + qp->sq.last = wqe; + opcode = conv_ibal_wr_opcode(wr); + if (opcode == MTHCA_OPCODE_INVALID) { + UVP_PRINT(TRACE_LEVEL_ERROR ,UVP_DBG_QP ,("SQ %06x opcode invalid\n",ibqp->qp_num)); + ret = -EINVAL; + if (bad_wr) + *bad_wr = wr; + goto out; + } + + + ((struct mthca_next_seg *) wqe)->nda_op = 0; + ((struct mthca_next_seg *) wqe)->ee_nds = 0; + ((struct mthca_next_seg *) wqe)->flags = + ((wr->send_opt & IB_SEND_OPT_SIGNALED) ? + cl_hton32(MTHCA_NEXT_CQ_UPDATE) : 0) | + ((wr->send_opt & IB_SEND_OPT_SOLICITED) ? + cl_hton32(MTHCA_NEXT_SOLICIT) : 0) | + cl_hton32(1); + if (opcode == MTHCA_OPCODE_SEND_IMM|| + opcode == MTHCA_OPCODE_RDMA_WRITE_IMM) + ((struct mthca_next_seg *) wqe)->imm = wr->immediate_data; + + wqe += sizeof (struct mthca_next_seg); + size = sizeof (struct mthca_next_seg) / 16; + + + switch (ibqp->qp_type) { + case IB_QPT_RELIABLE_CONN: + switch (opcode) { + case MTHCA_OPCODE_ATOMIC_CS: + case MTHCA_OPCODE_ATOMIC_FA: + ((struct mthca_raddr_seg *) wqe)->raddr = + cl_hton64(wr->remote_ops.vaddr); + ((struct mthca_raddr_seg *) wqe)->rkey = + wr->remote_ops.rkey; + ((struct mthca_raddr_seg *) wqe)->reserved = 0; + + wqe += sizeof (struct mthca_raddr_seg); + + if (opcode == MTHCA_OPCODE_ATOMIC_CS) { + ((struct mthca_atomic_seg *) wqe)->swap_add = + (wr->remote_ops.atomic2); + ((struct mthca_atomic_seg *) wqe)->compare = + (wr->remote_ops.atomic1); + } else { + ((struct mthca_atomic_seg *) wqe)->swap_add = + (wr->remote_ops.atomic1); + ((struct mthca_atomic_seg *) wqe)->compare = 0; + } + + wqe += sizeof (struct mthca_atomic_seg); + size += (sizeof (struct mthca_raddr_seg) + + sizeof (struct mthca_atomic_seg)) / 16; + break; + + case MTHCA_OPCODE_RDMA_WRITE: + case MTHCA_OPCODE_RDMA_WRITE_IMM: + case MTHCA_OPCODE_RDMA_READ: + ((struct mthca_raddr_seg *) wqe)->raddr = + cl_hton64(wr->remote_ops.vaddr); + ((struct mthca_raddr_seg *) wqe)->rkey = + wr->remote_ops.rkey; + ((struct mthca_raddr_seg *) wqe)->reserved = 0; + wqe += sizeof (struct mthca_raddr_seg); + size += sizeof (struct mthca_raddr_seg) / 16; + break; + + default: + /* No extra segments required for sends */ + break; + } + + break; + + case IB_QPT_UNRELIABLE_CONN: + switch (opcode) { + case MTHCA_OPCODE_RDMA_WRITE: + case MTHCA_OPCODE_RDMA_WRITE_IMM: + ((struct mthca_raddr_seg *) wqe)->raddr = + cl_hton64(wr->remote_ops.vaddr); + ((struct mthca_raddr_seg *) wqe)->rkey = + wr->remote_ops.rkey; + ((struct mthca_raddr_seg *) wqe)->reserved = 0; + wqe += sizeof (struct mthca_raddr_seg); + size += sizeof (struct mthca_raddr_seg) / 16; + break; + + default: + /* No extra segments required for sends */ + break; + } + + break; + + case IB_QPT_UNRELIABLE_DGRM: + { + struct mthca_ah *ah = ((struct mthca_ah *)wr->dgrm.ud.h_av); + ((struct mthca_tavor_ud_seg *) wqe)->lkey = + cl_hton32(ah->key); + ((struct mthca_tavor_ud_seg *) wqe)->av_addr = + cl_hton64((ULONG_PTR)ah->av); + ((struct mthca_tavor_ud_seg *) wqe)->dqpn = wr->dgrm.ud.remote_qp; + ((struct mthca_tavor_ud_seg *) wqe)->qkey = wr->dgrm.ud.remote_qkey; + + wqe += sizeof (struct mthca_tavor_ud_seg); + size += sizeof (struct mthca_tavor_ud_seg) / 16; + break; + } + + default: + break; + } + + if ((int)(int)wr->num_ds > qp->sq.max_gs) { + UVP_PRINT(TRACE_LEVEL_ERROR ,UVP_DBG_QP ,("SQ %06x too many gathers\n",ibqp->qp_num)); + ret = -ERANGE; + if (bad_wr) + *bad_wr = wr; + goto out; + } +//TODO sleybo: + if (wr->send_opt & IB_SEND_OPT_INLINE) { + if (wr->num_ds) { + struct mthca_inline_seg *seg = (struct mthca_inline_seg *)wqe; + uint32_t s = 0; + + wqe += sizeof *seg; + for (i = 0; i < (int)wr->num_ds; ++i) { + struct _ib_local_ds *sge = &wr->ds_array[i]; + + s += sge->length; + + if (s > (uint32_t)qp->max_inline_data) { + ret = -E2BIG; + if (bad_wr) + *bad_wr = wr; + goto out; + } + + memcpy(wqe, (void *) (ULONG_PTR) sge->vaddr, + sge->length); + wqe += sge->length; + } + + seg->byte_count = cl_hton32(MTHCA_INLINE_SEG | s); + size += align(s + sizeof *seg, 16) / 16; + } + } else { + for (i = 0; i < (int)wr->num_ds; ++i) { + ((struct mthca_data_seg *) wqe)->byte_count = + cl_hton32(wr->ds_array[i].length); + ((struct mthca_data_seg *) wqe)->lkey = + cl_hton32(wr->ds_array[i].lkey); + ((struct mthca_data_seg *) wqe)->addr = + cl_hton64(wr->ds_array[i].vaddr); + wqe += sizeof (struct mthca_data_seg); + size += sizeof (struct mthca_data_seg) / 16; + } + } + + qp->wrid[ind + qp->rq.max] = wr->wr_id; + + ((struct mthca_next_seg *) prev_wqe)->nda_op = + cl_hton32(((ind << qp->sq.wqe_shift) + + qp->send_wqe_offset) |opcode); + + wmb(); + + ((struct mthca_next_seg *) prev_wqe)->ee_nds = + cl_hton32((size0 ? 0 : MTHCA_NEXT_DBD) | size | + ((wr->send_opt& IB_SEND_OPT_FENCE) ? + MTHCA_NEXT_FENCE : 0)); + + if (!size0) { + size0 = size; + op0 = opcode; + } + + dump_wqe( TRACE_LEVEL_VERBOSE, (uint32_t*)qp->sq.last,qp, size); + + ++ind; + if (unlikely(ind >= qp->sq.max)) + ind -= qp->sq.max; + + } + +out: + if (likely(nreq)) { + uint32_t doorbell[2]; + + doorbell[0] = cl_hton32(((qp->sq.next_ind << qp->sq.wqe_shift) + + qp->send_wqe_offset) | f0 | op0); + doorbell[1] = cl_hton32((ibqp->qp_num << 8) | size0); + + wmb(); + + mthca_write64(doorbell, to_mctx(ibqp->pd->context), MTHCA_SEND_DOORBELL); + } + + qp->sq.next_ind = ind; + qp->sq.head += nreq; + +err_busy: + cl_spinlock_release(&qp->sq.lock); + + UVP_EXIT(UVP_DBG_QP); + return ret; +} + + +int mthca_tavor_post_recv(struct ibv_qp *ibqp, struct _ib_recv_wr *wr, + struct _ib_recv_wr **bad_wr) +{ + struct mthca_qp *qp = to_mqp(ibqp); + uint32_t doorbell[2]; + int ret = 0; + int nreq; + int i; + int size; + int size0 = 0; + int ind; + uint8_t *wqe; + uint8_t *prev_wqe; + + UVP_ENTER(UVP_DBG_QP); + + cl_spinlock_acquire(&qp->rq.lock); + + /* XXX check that state is OK to post receive */ + + ind = qp->rq.next_ind; + if(ibqp->state == IBV_QPS_RESET) { + ret = -EBUSY; + if (bad_wr) + *bad_wr = wr; + goto err_busy; + } + + for (nreq = 0; wr; ++nreq, wr = wr->p_next) { + if (unlikely(nreq == MTHCA_TAVOR_MAX_WQES_PER_RECV_DB)) { + nreq = 0; + + doorbell[0] = cl_hton32((qp->rq.next_ind << qp->rq.wqe_shift) | size0); + doorbell[1] = cl_hton32(ibqp->qp_num << 8); //TODO sleybo: add qpn to qp struct + + /* + * Make sure that descriptors are written + * before doorbell is rung. + */ + mb(); + + mthca_write64(doorbell, to_mctx(ibqp->pd->context), MTHCA_RECV_DOORBELL); + + qp->rq.head += MTHCA_TAVOR_MAX_WQES_PER_RECV_DB; + size0 = 0; + } + + if (mthca_wq_overflow(&qp->rq, nreq, to_mcq(qp->ibv_qp.recv_cq))) { + UVP_PRINT(TRACE_LEVEL_ERROR,UVP_DBG_QP,("RQ %06x full (%u head, %u tail," + " %d max, %d nreq)\n", ibqp->qp_num, + qp->rq.head, qp->rq.tail, + qp->rq.max, nreq)); + ret = -ENOMEM; + if (bad_wr) + *bad_wr = wr; + goto out; + } + + wqe = get_recv_wqe(qp, ind); + prev_wqe = qp->rq.last; + qp->rq.last = wqe; + + ((struct mthca_next_seg *) wqe)->nda_op = 0; + ((struct mthca_next_seg *) wqe)->ee_nds = + cl_hton32(MTHCA_NEXT_DBD); + ((struct mthca_next_seg *) wqe)->flags = + cl_hton32(MTHCA_NEXT_CQ_UPDATE); + + wqe += sizeof (struct mthca_next_seg); + size = sizeof (struct mthca_next_seg) / 16; + + if (unlikely((int)wr->num_ds > qp->rq.max_gs)) { + UVP_PRINT(TRACE_LEVEL_ERROR ,UVP_DBG_QP ,("RQ %06x too many gathers\n",ibqp->qp_num)); + ret = -ERANGE; + if (bad_wr) + *bad_wr = wr; + goto out; + } + + for (i = 0; i < (int)wr->num_ds; ++i) { + ((struct mthca_data_seg *) wqe)->byte_count = + cl_hton32(wr->ds_array[i].length); + ((struct mthca_data_seg *) wqe)->lkey = + cl_hton32(wr->ds_array[i].lkey); + ((struct mthca_data_seg *) wqe)->addr = + cl_hton64(wr->ds_array[i].vaddr); + wqe += sizeof (struct mthca_data_seg); + size += sizeof (struct mthca_data_seg) / 16; + } + + qp->wrid[ind] = wr->wr_id; + + ((struct mthca_next_seg *) prev_wqe)->nda_op = + cl_hton32((ind << qp->rq.wqe_shift) | 1); + wmb(); + ((struct mthca_next_seg *) prev_wqe)->ee_nds = + cl_hton32(MTHCA_NEXT_DBD | size); + + if (!size0) + size0 = size; + + ++ind; + if (unlikely(ind >= qp->rq.max)) + ind -= qp->rq.max; + } + +out: + if (likely(nreq)) { + doorbell[0] = cl_hton32((qp->rq.next_ind << qp->rq.wqe_shift) | size0); + doorbell[1] = cl_hton32((ibqp->qp_num << 8) | (nreq & 255)); + + /* + * Make sure that descriptors are written before + * doorbell is rung. + */ + mb(); + + mthca_write64(doorbell, to_mctx(ibqp->pd->context), MTHCA_RECV_DOORBELL); + } + + qp->rq.next_ind = ind; + qp->rq.head += nreq; + +err_busy: + cl_spinlock_release(&qp->rq.lock); + UVP_EXIT(UVP_DBG_QP); + return ret; +} + +int mthca_arbel_post_send(struct ibv_qp *ibqp, struct _ib_send_wr *wr, + struct _ib_send_wr **bad_wr) +{ + struct mthca_qp *qp = to_mqp(ibqp); + uint32_t doorbell[2]; + uint8_t *wqe; + uint8_t *prev_wqe; + int ret = 0; + int nreq; + int i; + int size; + int size0 = 0; + uint32_t f0 = unlikely(wr->send_opt & IB_SEND_OPT_FENCE) ? MTHCA_SEND_DOORBELL_FENCE : 0; + int ind; + uint8_t op0 = 0; + enum ib_wr_opcode opcode; + + UVP_ENTER(UVP_DBG_QP); + + cl_spinlock_acquire(&qp->sq.lock); + + /* XXX check that state is OK to post send */ + + ind = qp->sq.head & (qp->sq.max - 1); + if(ibqp->state == IBV_QPS_RESET) { + ret = -EBUSY; + if (bad_wr) + *bad_wr = wr; + goto err_busy; + } + + for (nreq = 0; wr; ++nreq, wr = wr->p_next) { + if (unlikely(nreq == MTHCA_ARBEL_MAX_WQES_PER_SEND_DB)) { + nreq = 0; + + doorbell[0] = cl_hton32((MTHCA_ARBEL_MAX_WQES_PER_SEND_DB << 24) | + ((qp->sq.head & 0xffff) << 8) | f0 | op0); + doorbell[1] = cl_hton32((ibqp->qp_num << 8) | size0); + qp->sq.head += MTHCA_ARBEL_MAX_WQES_PER_SEND_DB; + size0 = 0; + f0 = unlikely(wr->send_opt & IB_SEND_OPT_FENCE) ? MTHCA_SEND_DOORBELL_FENCE : 0; + + /* + * Make sure that descriptors are written before + * doorbell record. + */ + wmb(); + *qp->sq.db = cl_hton32(qp->sq.head & 0xffff); + + /* + * Make sure doorbell record is written before we + * write MMIO send doorbell. + */ + wmb(); + mthca_write64(doorbell, to_mctx(ibqp->pd->context), MTHCA_SEND_DOORBELL); + + } + + if (mthca_wq_overflow(&qp->sq, nreq, to_mcq(qp->ibv_qp.send_cq))) { + UVP_PRINT(TRACE_LEVEL_ERROR,UVP_DBG_QP,("SQ %06x full (%u head, %u tail," + " %d max, %d nreq)\n", ibqp->qp_num, + qp->sq.head, qp->sq.tail, + qp->sq.max, nreq)); + ret = -ENOMEM; + if (bad_wr) + *bad_wr = wr; + goto out; + } + + wqe = get_send_wqe(qp, ind); + prev_wqe = qp->sq.last; + qp->sq.last = wqe; + opcode = conv_ibal_wr_opcode(wr); + + ((struct mthca_next_seg *) wqe)->flags = + ((wr->send_opt & IB_SEND_OPT_SIGNALED) ? + cl_hton32(MTHCA_NEXT_CQ_UPDATE) : 0) | + ((wr->send_opt & IB_SEND_OPT_SOLICITED) ? + cl_hton32(MTHCA_NEXT_SOLICIT) : 0) | + cl_hton32(1); + if (opcode == MTHCA_OPCODE_SEND_IMM|| + opcode == MTHCA_OPCODE_RDMA_WRITE_IMM) + ((struct mthca_next_seg *) wqe)->imm = wr->immediate_data; + + wqe += sizeof (struct mthca_next_seg); + size = sizeof (struct mthca_next_seg) / 16; + + switch (ibqp->qp_type) { + case IB_QPT_RELIABLE_CONN: + switch (opcode) { + case MTHCA_OPCODE_ATOMIC_CS: + case MTHCA_OPCODE_ATOMIC_FA: + ((struct mthca_raddr_seg *) wqe)->raddr = + cl_hton64(wr->remote_ops.vaddr); + ((struct mthca_raddr_seg *) wqe)->rkey = + wr->remote_ops.rkey; + ((struct mthca_raddr_seg *) wqe)->reserved = 0; + + wqe += sizeof (struct mthca_raddr_seg); + + if (opcode == MTHCA_OPCODE_ATOMIC_CS) { + ((struct mthca_atomic_seg *) wqe)->swap_add = + (wr->remote_ops.atomic2); + ((struct mthca_atomic_seg *) wqe)->compare = + (wr->remote_ops.atomic1); + } else { + ((struct mthca_atomic_seg *) wqe)->swap_add = + (wr->remote_ops.atomic1); + ((struct mthca_atomic_seg *) wqe)->compare = 0; + } + + wqe += sizeof (struct mthca_atomic_seg); + size += (sizeof (struct mthca_raddr_seg) + + sizeof (struct mthca_atomic_seg)) / 16; + break; + + case MTHCA_OPCODE_RDMA_READ: + case MTHCA_OPCODE_RDMA_WRITE: + case MTHCA_OPCODE_RDMA_WRITE_IMM: + ((struct mthca_raddr_seg *) wqe)->raddr = + cl_hton64(wr->remote_ops.vaddr); + ((struct mthca_raddr_seg *) wqe)->rkey = + wr->remote_ops.rkey; + ((struct mthca_raddr_seg *) wqe)->reserved = 0; + wqe += sizeof (struct mthca_raddr_seg); + size += sizeof (struct mthca_raddr_seg) / 16; + break; + + default: + /* No extra segments required for sends */ + break; + } + + break; + + case IB_QPT_UNRELIABLE_CONN: + switch (opcode) { + case MTHCA_OPCODE_RDMA_WRITE: + case MTHCA_OPCODE_RDMA_WRITE_IMM: + ((struct mthca_raddr_seg *) wqe)->raddr = + cl_hton64(wr->remote_ops.vaddr); + ((struct mthca_raddr_seg *) wqe)->rkey = + wr->remote_ops.rkey; + ((struct mthca_raddr_seg *) wqe)->reserved = 0; + wqe += sizeof (struct mthca_raddr_seg); + size += sizeof (struct mthca_raddr_seg) / 16; + break; + + default: + /* No extra segments required for sends */ + break; + } + + break; + + case IB_QPT_UNRELIABLE_DGRM: + { + struct mthca_ah *ah = ((struct mthca_ah *)wr->dgrm.ud.h_av); + memcpy(((struct mthca_arbel_ud_seg *) wqe)->av, + ah->av, sizeof ( struct mthca_av)); + ((struct mthca_arbel_ud_seg *) wqe)->dqpn = wr->dgrm.ud.remote_qp; + ((struct mthca_arbel_ud_seg *) wqe)->qkey = wr->dgrm.ud.remote_qkey; + + + wqe += sizeof (struct mthca_arbel_ud_seg); + size += sizeof (struct mthca_arbel_ud_seg) / 16; + break; + } + + default: + break; + } + + if ((int)wr->num_ds > qp->sq.max_gs) { + UVP_PRINT(TRACE_LEVEL_ERROR ,UVP_DBG_QP ,("SQ %06x full too many gathers\n",ibqp->qp_num)); + ret = -ERANGE; + if (bad_wr) + *bad_wr = wr; + goto out; + } + + if (wr->send_opt & IB_SEND_OPT_INLINE) { + if (wr->num_ds) { + struct mthca_inline_seg *seg = (struct mthca_inline_seg *)wqe; + uint32_t s = 0; + + wqe += sizeof *seg; + for (i = 0; i < (int)wr->num_ds; ++i) { + struct _ib_local_ds *sge = &wr->ds_array[i]; + + s += sge->length; + + if (s > (uint32_t)qp->max_inline_data) { + ret = -E2BIG; + if (bad_wr) + *bad_wr = wr; + goto out; + } + + memcpy(wqe, (void *) (uintptr_t) sge->vaddr, + sge->length); + wqe += sge->length; + } + + seg->byte_count = cl_hton32(MTHCA_INLINE_SEG | s); + size += align(s + sizeof *seg, 16) / 16; + } + } else { + + for (i = 0; i < (int)wr->num_ds; ++i) { + ((struct mthca_data_seg *) wqe)->byte_count = + cl_hton32(wr->ds_array[i].length); + ((struct mthca_data_seg *) wqe)->lkey = + cl_hton32(wr->ds_array[i].lkey); + ((struct mthca_data_seg *) wqe)->addr = + cl_hton64(wr->ds_array[i].vaddr); + wqe += sizeof (struct mthca_data_seg); + size += sizeof (struct mthca_data_seg) / 16; + } +//TODO do this also in kernel +// size += wr->num_ds * (sizeof *seg / 16); + } + + qp->wrid[ind + qp->rq.max] = wr->wr_id; + + if (opcode == MTHCA_OPCODE_INVALID) { + UVP_PRINT(TRACE_LEVEL_ERROR ,UVP_DBG_QP ,("SQ %06x opcode invalid\n",ibqp->qp_num)); + ret = -EINVAL; + if (bad_wr) + *bad_wr = wr; + goto out; + } + + ((struct mthca_next_seg *) prev_wqe)->nda_op = + cl_hton32(((ind << qp->sq.wqe_shift) + + qp->send_wqe_offset) | + opcode); + wmb(); + ((struct mthca_next_seg *) prev_wqe)->ee_nds = + cl_hton32(MTHCA_NEXT_DBD | size | + ((wr->send_opt & IB_SEND_OPT_FENCE) ? + MTHCA_NEXT_FENCE : 0)); + + if (!size0) { + size0 = size; + op0 = opcode; + } + + dump_wqe( TRACE_LEVEL_VERBOSE, (uint32_t*)qp->sq.last,qp, size); + + ++ind; + if (unlikely(ind >= qp->sq.max)) + ind -= qp->sq.max; + } + +out: + if (likely(nreq)) { + doorbell[0] = cl_hton32((nreq << 24) | + ((qp->sq.head & 0xffff) << 8) | f0 | op0); + doorbell[1] = cl_hton32((ibqp->qp_num << 8) | size0); + + qp->sq.head += nreq; + + /* + * Make sure that descriptors are written before + * doorbell record. + */ + wmb(); + *qp->sq.db = cl_hton32(qp->sq.head & 0xffff); + + /* + * Make sure doorbell record is written before we + * write MMIO send doorbell. + */ + wmb(); + mthca_write64(doorbell, to_mctx(ibqp->pd->context), MTHCA_SEND_DOORBELL); + } + +err_busy: + cl_spinlock_release(&qp->sq.lock); + + UVP_EXIT(UVP_DBG_QP); + + return ret; +} + +int mthca_arbel_post_recv(struct ibv_qp *ibqp, struct _ib_recv_wr *wr, + struct _ib_recv_wr **bad_wr) +{ + struct mthca_qp *qp = to_mqp(ibqp); + int ret = 0; + int nreq; + int ind; + int i; + uint8_t *wqe; + + UVP_ENTER(UVP_DBG_QP); + + cl_spinlock_acquire(&qp->rq.lock); + + /* XXX check that state is OK to post receive */ + + ind = qp->rq.head & (qp->rq.max - 1); + if(ibqp->state == IBV_QPS_RESET) { + ret = -EBUSY; + if (bad_wr) + *bad_wr = wr; + goto err_busy; + } + for (nreq = 0; wr; ++nreq, wr = wr->p_next) { + if (mthca_wq_overflow(&qp->rq, nreq, to_mcq(qp->ibv_qp.recv_cq))) {//TODO sleybo: check the cq + UVP_PRINT(TRACE_LEVEL_ERROR ,UVP_DBG_QP ,("RQ %06x full (%u head, %u tail," + " %d max, %d nreq)\n", ibqp->qp_num, + qp->rq.head, qp->rq.tail, + qp->rq.max, nreq)); + ret = -ENOMEM; + if (bad_wr) + *bad_wr = wr; + goto out; + } + + wqe = get_recv_wqe(qp, ind); + + ((struct mthca_next_seg *) wqe)->flags = 0; + + wqe += sizeof (struct mthca_next_seg); + + if (unlikely((int)wr->num_ds > qp->rq.max_gs)) { + UVP_PRINT(TRACE_LEVEL_ERROR ,UVP_DBG_QP ,("RQ %06x full too many scatter\n",ibqp->qp_num)); + ret = -ERANGE; + if (bad_wr) + *bad_wr = wr; + goto out; + } + + for (i = 0; i < (int)wr->num_ds; ++i) { + ((struct mthca_data_seg *) wqe)->byte_count = + cl_hton32(wr->ds_array[i].length); + ((struct mthca_data_seg *) wqe)->lkey = + cl_hton32(wr->ds_array[i].lkey); + ((struct mthca_data_seg *) wqe)->addr = + cl_hton64(wr->ds_array[i].vaddr); + wqe += sizeof (struct mthca_data_seg); + } + + if (i < qp->rq.max_gs) { + ((struct mthca_data_seg *) wqe)->byte_count = 0; + ((struct mthca_data_seg *) wqe)->lkey = cl_hton32(MTHCA_INVAL_LKEY); + ((struct mthca_data_seg *) wqe)->addr = 0; + } + + qp->wrid[ind] = wr->wr_id; + + ++ind; + if (unlikely(ind >= qp->rq.max)) + ind -= qp->rq.max; + } +out: + if (likely(nreq)) { + qp->rq.head += nreq; + + /* + * Make sure that descriptors are written before + * doorbell record. + */ + mb(); + *qp->rq.db = cl_hton32(qp->rq.head & 0xffff); + } + +err_busy: + cl_spinlock_release(&qp->rq.lock); + + UVP_EXIT(UVP_DBG_QP); + + return ret; +} + +int mthca_alloc_qp_buf(struct ibv_pd *pd, struct ibv_qp_cap *cap, + ib_qp_type_t type, struct mthca_qp *qp) +{ + int size; + int max_sq_sge; + + qp->rq.max_gs = cap->max_recv_sge; + qp->sq.max_gs = cap->max_send_sge; + max_sq_sge = align(cap->max_inline_data + sizeof (struct mthca_inline_seg), + sizeof (struct mthca_data_seg)) / sizeof (struct mthca_data_seg); + if (max_sq_sge < (int)cap->max_send_sge) + max_sq_sge = cap->max_send_sge; + + qp->wrid = cl_malloc((qp->rq.max + qp->sq.max) * sizeof (uint64_t)); + if (!qp->wrid) + return -1; + + size = sizeof (struct mthca_next_seg) + + qp->rq.max_gs * sizeof (struct mthca_data_seg); + + for (qp->rq.wqe_shift = 6; 1 << qp->rq.wqe_shift < size; + qp->rq.wqe_shift++) + ; /* nothing */ + + size = max_sq_sge * sizeof (struct mthca_data_seg); + switch (type) { + case IB_QPT_UNRELIABLE_DGRM: + size += mthca_is_memfree(pd->context) ? + sizeof (struct mthca_arbel_ud_seg) : + sizeof (struct mthca_tavor_ud_seg); + break; + + case IB_QPT_UNRELIABLE_CONN: + size += sizeof (struct mthca_raddr_seg); + break; + + case IB_QPT_RELIABLE_CONN: + size += sizeof (struct mthca_raddr_seg); + /* + * An atomic op will require an atomic segment, a + * remote address segment and one scatter entry. + */ + if (size < (sizeof (struct mthca_atomic_seg) + + sizeof (struct mthca_raddr_seg) + + sizeof (struct mthca_data_seg))) + size = (sizeof (struct mthca_atomic_seg) + + sizeof (struct mthca_raddr_seg) + + sizeof (struct mthca_data_seg)); + break; + + default: + break; + } + + /* Make sure that we have enough space for a bind request */ + if (size < sizeof (struct mthca_bind_seg)) + size = sizeof (struct mthca_bind_seg); + + size += sizeof (struct mthca_next_seg); + + for (qp->sq.wqe_shift = 6; 1 << qp->sq.wqe_shift < size; + qp->sq.wqe_shift++) + ; /* nothing */ + + qp->send_wqe_offset = align(qp->rq.max << qp->rq.wqe_shift, + 1 << qp->sq.wqe_shift); + + qp->buf_size = qp->send_wqe_offset + (qp->sq.max << qp->sq.wqe_shift); + + if (posix_memalign(&qp->buf, g_page_size, + align(qp->buf_size, g_page_size))) { + cl_free(qp->wrid); + return -1; + } + + memset(qp->buf, 0, qp->buf_size); + + if (mthca_is_memfree(pd->context)) { + struct mthca_next_seg *next; + struct mthca_data_seg *scatter; + int i; + uint32_t sz; + + sz = cl_hton32((sizeof (struct mthca_next_seg) + + qp->rq.max_gs * sizeof (struct mthca_data_seg)) / 16); + + for (i = 0; i < qp->rq.max; ++i) { + next = get_recv_wqe(qp, i); + next->nda_op = cl_hton32(((i + 1) & (qp->rq.max - 1)) << + qp->rq.wqe_shift); + next->ee_nds = sz; + + for (scatter = (void *) (next + 1); + (void *) scatter < (void *) ((char *)next + (uint32_t)(1 << qp->rq.wqe_shift)); + ++scatter) + scatter->lkey = cl_hton32(MTHCA_INVAL_LKEY); + } + + for (i = 0; i < qp->sq.max; ++i) { + next = get_send_wqe(qp, i); + next->nda_op = cl_hton32((((i + 1) & (qp->sq.max - 1)) << + qp->sq.wqe_shift) + + qp->send_wqe_offset); + } + } + + qp->sq.last = get_send_wqe(qp, qp->sq.max - 1); + qp->rq.last = get_recv_wqe(qp, qp->rq.max - 1); + + return 0; +} + +struct mthca_qp *mthca_find_qp(struct mthca_context *ctx, uint32_t qpn) +{ + int tind = (qpn & (ctx->num_qps - 1)) >> ctx->qp_table_shift; + + if (ctx->qp_table[tind].refcnt) + return ctx->qp_table[tind].table[qpn & ctx->qp_table_mask]; + else + return NULL; +} + +int mthca_store_qp(struct mthca_context *ctx, uint32_t qpn, struct mthca_qp *qp) +{ + int tind = (qpn & (ctx->num_qps - 1)) >> ctx->qp_table_shift; + int ret = 0; + + WaitForSingleObject( ctx->qp_table_mutex, INFINITE ); + + if (!ctx->qp_table[tind].refcnt) { + ctx->qp_table[tind].table = cl_malloc( + (ctx->qp_table_mask + 1) * sizeof (struct mthca_qp *)); + if (!ctx->qp_table[tind].table) { + ret = -1; + goto out; + } + } + ++ctx->qp_table[tind].refcnt; + ctx->qp_table[tind].table[qpn & ctx->qp_table_mask] = qp; + +out: + ReleaseMutex( ctx->qp_table_mutex ); + return ret; +} + +void mthca_clear_qp(struct mthca_context *ctx, uint32_t qpn) +{ + int tind = (qpn & (ctx->num_qps - 1)) >> ctx->qp_table_shift; + + WaitForSingleObject( ctx->qp_table_mutex, INFINITE ); + + if (!--ctx->qp_table[tind].refcnt) + cl_free(ctx->qp_table[tind].table); + else + ctx->qp_table[tind].table[qpn & ctx->qp_table_mask] = NULL; + + ReleaseMutex( ctx->qp_table_mutex ); +} + +int mthca_free_err_wqe(struct mthca_qp *qp, int is_send, + int index, int *dbd, uint32_t *new_wqe) +{ + struct mthca_next_seg *next; + + /* + * For SRQs, all WQEs generate a CQE, so we're always at the + * end of the doorbell chain. + */ + if (qp->ibv_qp.srq) { + *new_wqe = 0; + return 0; + } + + if (is_send) + next = get_send_wqe(qp, index); + else + next = get_recv_wqe(qp, index); + + *dbd = !!(next->ee_nds & cl_hton32(MTHCA_NEXT_DBD)); + if (next->ee_nds & cl_hton32(0x3f)) + *new_wqe = (next->nda_op & cl_hton32(~0x3f)) | + (next->ee_nds & cl_hton32(0x3f)); + else + *new_wqe = 0; + + return 0; +} + diff --git a/branches/WOF2-3/hw/mthca/user/mlnx_uvp_srq.c b/branches/WOF2-3/hw/mthca/user/mlnx_uvp_srq.c new file mode 100644 index 00000000..061f2d8b --- /dev/null +++ b/branches/WOF2-3/hw/mthca/user/mlnx_uvp_srq.c @@ -0,0 +1,326 @@ +/* + * Copyright (c) 2005 Cisco Systems. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include + +#include "mlnx_uvp.h" +#include "mlnx_uvp_doorbell.h" +#include "mthca_wqe.h" + +#if defined(EVENT_TRACING) +#include "mlnx_uvp_srq.tmh" +#endif + +static void *get_wqe(struct mthca_srq *srq, int n) +{ + return (uint8_t*)srq->buf + (n << srq->wqe_shift); +} + +/* + * Return a pointer to the location within a WQE that we're using as a + * link when the WQE is in the free list. We use the imm field at an + * offset of 12 bytes because in the Tavor case, posting a WQE may + * overwrite the next segment of the previous WQE, but a receive WQE + * will never touch the imm field. This avoids corrupting our free + * list if the previous WQE has already completed and been put on the + * free list when we post the next WQE. + */ +static inline int *wqe_to_link(void *wqe) +{ + return (int *) ((uint8_t*)wqe + 12); +} + +void mthca_free_srq_wqe(struct mthca_srq *srq, int ind) +{ + cl_spinlock_acquire(&srq->lock); + + if (srq->first_free >= 0) + *wqe_to_link(get_wqe(srq, srq->last_free)) = ind; + else + srq->first_free = ind; + + *wqe_to_link(get_wqe(srq, ind)) = -1; + srq->last_free = ind; + + cl_spinlock_release(&srq->lock); +} + +int mthca_tavor_post_srq_recv(struct ibv_srq *ibsrq, + struct _ib_recv_wr *wr, + struct _ib_recv_wr **bad_wr) +{ + struct mthca_srq *srq = to_msrq(ibsrq); + uint32_t doorbell[2]; + int err = 0; + int first_ind; + int ind; + int next_ind; + int nreq; + int i; + uint8_t *wqe; + uint8_t *prev_wqe; + + cl_spinlock_acquire(&srq->lock); + + first_ind = srq->first_free; + + for (nreq = 0; wr; wr = wr->p_next) { + ind = srq->first_free; + + if (ind < 0) { + UVP_PRINT(TRACE_LEVEL_ERROR ,UVP_DBG_QP ,("SRQ %06x full\n", srq->srqn)); + err = -1; + *bad_wr = wr; + break; + } + + wqe = get_wqe(srq, ind); + next_ind = *wqe_to_link(wqe); + + if (next_ind < 0) { + UVP_PRINT(TRACE_LEVEL_ERROR ,UVP_DBG_QP ,("SRQ %06x full\n", srq->srqn)); + err = -ENOMEM; + *bad_wr = wr; + break; + } + + prev_wqe = srq->last; + srq->last = wqe; + + ((struct mthca_next_seg *) wqe)->nda_op = 0; + ((struct mthca_next_seg *) wqe)->ee_nds = 0; + /* flags field will always remain 0 */ + + wqe += sizeof (struct mthca_next_seg); + + if (unlikely((int)wr->num_ds > srq->max_gs)) { + err = -1; + *bad_wr = wr; + srq->last = prev_wqe; + break; + } + + for (i = 0; i < (int)wr->num_ds; ++i) { + ((struct mthca_data_seg *) wqe)->byte_count = + cl_hton32(wr->ds_array[i].length); + ((struct mthca_data_seg *) wqe)->lkey = + cl_hton32(wr->ds_array[i].lkey); + ((struct mthca_data_seg *) wqe)->addr = + htonll(wr->ds_array[i].vaddr); + wqe += sizeof (struct mthca_data_seg); + } + + if (i < srq->max_gs) { + ((struct mthca_data_seg *) wqe)->byte_count = 0; + ((struct mthca_data_seg *) wqe)->lkey = cl_hton32(MTHCA_INVAL_LKEY); + ((struct mthca_data_seg *) wqe)->addr = 0; + } + + ((struct mthca_next_seg *) prev_wqe)->nda_op = + cl_hton32((ind << srq->wqe_shift) | 1); + mb(); + ((struct mthca_next_seg *) prev_wqe)->ee_nds = + cl_hton32(MTHCA_NEXT_DBD); + + srq->wrid[ind] = wr->wr_id; + srq->first_free = next_ind; + + if (++nreq == MTHCA_TAVOR_MAX_WQES_PER_RECV_DB) { + nreq = 0; + + doorbell[0] = cl_hton32(first_ind << srq->wqe_shift); + doorbell[1] = cl_hton32(srq->srqn << 8); + + /* + * Make sure that descriptors are written + * before doorbell is rung. + */ + wmb(); + + mthca_write64(doorbell, to_mctx(ibsrq->context), MTHCA_RECV_DOORBELL); + + first_ind = srq->first_free; + } + } + + if (nreq) { + doorbell[0] = cl_hton32(first_ind << srq->wqe_shift); + doorbell[1] = cl_hton32((srq->srqn << 8) | nreq); + + /* + * Make sure that descriptors are written before + * doorbell is rung. + */ + wmb(); + + mthca_write64(doorbell, to_mctx(ibsrq->context), MTHCA_RECV_DOORBELL); + } + + cl_spinlock_release(&srq->lock); + return err; +} + +int mthca_arbel_post_srq_recv(struct ibv_srq *ibsrq, + struct _ib_recv_wr *wr, + struct _ib_recv_wr **bad_wr) +{ + struct mthca_srq *srq = to_msrq(ibsrq); + int err = 0; + int ind; + int next_ind; + int nreq; + int i; + uint8_t *wqe; + + cl_spinlock_acquire(&srq->lock); + + for (nreq = 0; wr; ++nreq, wr = wr->p_next) { + ind = srq->first_free; + + if (ind < 0) { + UVP_PRINT(TRACE_LEVEL_ERROR ,UVP_DBG_QP ,("SRQ %06x full\n", srq->srqn)); + err = -ENOMEM; + *bad_wr = wr; + break; + } + + wqe = get_wqe(srq, ind); + next_ind = *wqe_to_link(wqe); + + if (next_ind < 0) { + UVP_PRINT(TRACE_LEVEL_ERROR ,UVP_DBG_LOW ,("SRQ %06x full\n", srq->srqn)); + err = -ENOMEM; + *bad_wr = wr; + break; + } + + ((struct mthca_next_seg *) wqe)->nda_op = + cl_hton32((next_ind << srq->wqe_shift) | 1); + ((struct mthca_next_seg *) wqe)->ee_nds = 0; + /* flags field will always remain 0 */ + + wqe += sizeof (struct mthca_next_seg); + + if (unlikely((int)wr->num_ds > srq->max_gs)) { + err = -1; + *bad_wr = wr; + break; + } + + for (i = 0; i < (int)wr->num_ds; ++i) { + ((struct mthca_data_seg *) wqe)->byte_count = + cl_hton32(wr->ds_array[i].length); + ((struct mthca_data_seg *) wqe)->lkey = + cl_hton32(wr->ds_array[i].lkey); + ((struct mthca_data_seg *) wqe)->addr = + htonll(wr->ds_array[i].vaddr); + wqe += sizeof (struct mthca_data_seg); + } + + if (i < srq->max_gs) { + ((struct mthca_data_seg *) wqe)->byte_count = 0; + ((struct mthca_data_seg *) wqe)->lkey = cl_hton32(MTHCA_INVAL_LKEY); + ((struct mthca_data_seg *) wqe)->addr = 0; + } + + srq->wrid[ind] = wr->wr_id; + srq->first_free = next_ind; + } + + if (likely(nreq)) { + srq->counter += (uint16_t)nreq; + + /* + * Make sure that descriptors are written before + * we write doorbell record. + */ + wmb(); + *srq->db = cl_hton32(srq->counter); + } + + cl_spinlock_release(&srq->lock); + return err; +} + +int mthca_alloc_srq_buf(struct ibv_pd *pd, struct ibv_srq_attr *attr, + struct mthca_srq *srq) +{ + struct mthca_data_seg *scatter; + uint8_t *wqe; + int size; + int i; + + srq->wrid = cl_malloc(srq->max * sizeof (uint64_t)); + if (!srq->wrid) + return -1; + + size = sizeof (struct mthca_next_seg) + + srq->max_gs * sizeof (struct mthca_data_seg); + + for (srq->wqe_shift = 6; 1 << srq->wqe_shift < size; ++srq->wqe_shift) + ; /* nothing */ + + srq->buf_size = srq->max << srq->wqe_shift; + + if (posix_memalign(&srq->buf, g_page_size, + align(srq->buf_size, g_page_size))) { + cl_free(srq->wrid); + return -1; + } + + cl_memclr(srq->buf, srq->buf_size); + + /* + * Now initialize the SRQ buffer so that all of the WQEs are + * linked into the list of free WQEs. In addition, set the + * scatter list L_Keys to the sentry value of 0x100. + */ + + for (i = 0; i < srq->max; ++i) { + wqe = get_wqe(srq, i); + + *wqe_to_link(wqe) = i < srq->max - 1 ? i + 1 : -1; + + for (scatter = (struct mthca_data_seg *)(wqe + sizeof (struct mthca_next_seg)); + (void *) scatter < (void*)(wqe + (uint32_t)(1 << srq->wqe_shift)); + ++scatter) + scatter->lkey = cl_hton32(MTHCA_INVAL_LKEY); + } + + srq->first_free = 0; + srq->last_free = srq->max - 1; + srq->last = get_wqe(srq, srq->max - 1); + + return 0; +} diff --git a/branches/WOF2-3/hw/mthca/user/mlnx_uvp_verbs.c b/branches/WOF2-3/hw/mthca/user/mlnx_uvp_verbs.c new file mode 100644 index 00000000..904b71b9 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/user/mlnx_uvp_verbs.c @@ -0,0 +1,512 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Cisco Systems. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include + +#include "mlnx_uvp.h" +#include "mx_abi.h" +#include "mthca_wqe.h" + + +#if defined(EVENT_TRACING) +#include "mlnx_uvp_verbs.tmh" +#endif + +struct ibv_pd *mthca_alloc_pd(struct ibv_context *context, struct ibv_alloc_pd_resp *resp) +{ + struct mthca_pd *pd; + + pd = cl_zalloc(sizeof *pd); + if (!pd) + goto err_malloc; + + if (!mthca_is_memfree(context)) { + pd->ah_list = NULL; + pd->ah_mutex = CreateMutex( NULL, FALSE, NULL ); + if (!pd->ah_mutex) + goto err_mutex; + } + + /* fill response fields */ + pd->ibv_pd.context = context; + pd->ibv_pd.handle = resp->pd_handle; + pd->pdn = resp->pdn; + + return &pd->ibv_pd; + +err_mutex: + cl_free(pd); +err_malloc: + return NULL; +} + +int mthca_free_pd(struct ibv_pd *ibv_pd) +{ + struct mthca_pd *pd = to_mpd(ibv_pd); + if (!mthca_is_memfree(ibv_pd->context)) { + struct mthca_ah_page *page, *next_page; + WaitForSingleObject( pd->ah_mutex, INFINITE ); + for (page = pd->ah_list; page; page = next_page) { + next_page = page->next; + posix_memfree(page->buf); + cl_free(page); + } + ReleaseMutex( pd->ah_mutex ); + CloseHandle(pd->ah_mutex); + } + cl_free(pd); + return 0; +} + +/* allocate create_cq infrastructure and fill it's request parameters structure */ +struct ibv_cq *mthca_create_cq_pre(struct ibv_context *context, int *p_cqe, + struct ibv_create_cq *req) +{ + struct mthca_cq *cq; + int nent; + int ret; + + /* Sanity check CQ size before proceeding */ + if ((unsigned)*p_cqe > 131072) + goto exit; + + cq = cl_zalloc(sizeof *cq); + if (!cq) + goto exit; + + cl_spinlock_construct(&cq->lock); + if (cl_spinlock_init(&cq->lock)) + goto err; + + for (nent = 1; nent <= *p_cqe; nent <<= 1) + ; /* nothing */ + + if (posix_memalign(&cq->buf, g_page_size, + align(nent * MTHCA_CQ_ENTRY_SIZE, g_page_size))) + goto err_memalign; + + mthca_init_cq_buf(cq, nent); + + if (mthca_is_memfree(context)) { + cq->set_ci_db_index = mthca_alloc_db(to_mctx(context)->db_tab, + MTHCA_DB_TYPE_CQ_SET_CI, + &cq->set_ci_db); + if (cq->set_ci_db_index < 0) + goto err_unreg; + + cq->arm_db_index = mthca_alloc_db(to_mctx(context)->db_tab, + MTHCA_DB_TYPE_CQ_ARM, + &cq->arm_db); + if (cq->arm_db_index < 0) + goto err_set_db; + + cq->u_arm_db_index = mthca_alloc_db(to_mctx(context)->db_tab, + MTHCA_DB_TYPE_CQ_ARM, + &cq->p_u_arm_sn); + if (cq->u_arm_db_index < 0) + goto err_arm_db; + + *cq->p_u_arm_sn = 1; + + req->arm_db_page = db_align(cq->arm_db); + req->set_db_page = db_align(cq->set_ci_db); + req->u_arm_db_page = (uint64_t)(ULONG_PTR)cq->p_u_arm_sn; + req->arm_db_index = cq->arm_db_index; + req->set_db_index = cq->set_ci_db_index; + req->u_arm_db_index = cq->u_arm_db_index; + } + + req->mr.start = (uint64_t)(ULONG_PTR)cq->buf; + req->mr.length = nent * MTHCA_CQ_ENTRY_SIZE; + req->mr.hca_va = 0; + req->mr.pd_handle = to_mctx(context)->pd->handle; + req->mr.pdn = to_mpd(to_mctx(context)->pd)->pdn; + req->mr.access_flags = MTHCA_ACCESS_LOCAL_WRITE; + req->user_handle = (uint64_t)(ULONG_PTR)cq; +#if 1 + req->cqe = *p_cqe; + *p_cqe = nent-1; +// *p_cqe = *p_cqe; // return the same value +// cq->ibv_cq.cqe = nent -1; +#else + req->cqe = nent; + *p_cqe = *p_cqe; // return the same value +#endif + return &cq->ibv_cq; + +err_arm_db: + if (mthca_is_memfree(context)) + mthca_free_db(to_mctx(context)->db_tab, MTHCA_DB_TYPE_CQ_SET_CI, + cq->arm_db_index); + +err_set_db: + if (mthca_is_memfree(context)) + mthca_free_db(to_mctx(context)->db_tab, MTHCA_DB_TYPE_CQ_SET_CI, + cq->set_ci_db_index); + +err_unreg: + posix_memfree(cq->buf); + +err_memalign: + cl_spinlock_destroy(&cq->lock); + +err: + cl_free(cq); + +exit: + return ERR_PTR(-ENOMEM); +} + +struct ibv_cq *mthca_create_cq_post(struct ibv_context *context, + struct ibv_create_cq_resp *resp) +{ + struct mthca_cq *cq; + int ret; + + cq = (struct mthca_cq *)(ULONG_PTR)resp->user_handle; + + cq->cqn = resp->cqn; + cq->mr.handle = resp->mr.mr_handle; + cq->mr.lkey = resp->mr.lkey; + cq->mr.rkey = resp->mr.rkey; + cq->mr.pd = to_mctx(context)->pd; + cq->mr.context = context; + cq->ibv_cq.cqe = resp->cqe; + cq->ibv_cq.handle = resp->cq_handle; + cq->ibv_cq.context = context; + + if (mthca_is_memfree(context)) { + mthca_set_db_qn(cq->set_ci_db, MTHCA_DB_TYPE_CQ_SET_CI, cq->cqn); + mthca_set_db_qn(cq->arm_db, MTHCA_DB_TYPE_CQ_ARM, cq->cqn); + } + + return &cq->ibv_cq; + +} + +int mthca_destroy_cq(struct ibv_cq *cq) +{ + int ret; + + if (mthca_is_memfree(cq->context)) { + mthca_free_db(to_mctx(cq->context)->db_tab, MTHCA_DB_TYPE_CQ_SET_CI, + to_mcq(cq)->u_arm_db_index); + mthca_free_db(to_mctx(cq->context)->db_tab, MTHCA_DB_TYPE_CQ_SET_CI, + to_mcq(cq)->set_ci_db_index); + mthca_free_db(to_mctx(cq->context)->db_tab, MTHCA_DB_TYPE_CQ_ARM, + to_mcq(cq)->arm_db_index); + } + + posix_memfree(to_mcq(cq)->buf); + + cl_spinlock_destroy(&((struct mthca_cq *)cq)->lock); + cl_free(to_mcq(cq)); + + return 0; +} + +int align_queue_size(struct ibv_context *context, int size, int spare) +{ + int ret; + + /* Enable creating zero-sized QPs */ + if (!size) + return 1; + + if (mthca_is_memfree(context)) { + for (ret = 1; ret < size + spare; ret <<= 1) + ; /* nothing */ + + return ret; + } else + return size + spare; +} + +struct ibv_qp *mthca_create_qp_pre(struct ibv_pd *pd, + struct ibv_qp_init_attr *attr, struct ibv_create_qp *req) +{ + struct mthca_qp *qp; + struct ibv_context *context = pd->context; + int ret = -ENOMEM; + + UVP_ENTER(UVP_DBG_QP); + /* Sanity check QP size before proceeding */ + if (attr->cap.max_send_wr > 65536 || + attr->cap.max_recv_wr > 65536 || + attr->cap.max_send_sge > 64 || + attr->cap.max_recv_sge > 64 || + attr->cap.max_inline_data > 1024) { + ret = -EINVAL; + UVP_PRINT(TRACE_LEVEL_ERROR ,UVP_DBG_QP ,("sanity checks failed (%d)\n",ret)); + goto exit; + } + + qp = cl_zalloc(sizeof *qp); + if (!qp) { + UVP_PRINT(TRACE_LEVEL_ERROR ,UVP_DBG_QP ,("cl_malloc failed (%d)\n",ret)); + goto err_nomem; + } + + qp->sq.max = align_queue_size(context, attr->cap.max_send_wr, 0); + qp->rq.max = align_queue_size(context, attr->cap.max_recv_wr, 0); + + if (mthca_alloc_qp_buf(pd, &attr->cap, attr->qp_type, qp)) { + UVP_PRINT(TRACE_LEVEL_ERROR ,UVP_DBG_QP ,("mthca_alloc_qp_buf failed (%d)\n",ret)); + goto err_nomem; + } + + mthca_init_qp_indices(qp); + + cl_spinlock_construct(&qp->sq.lock); + if (cl_spinlock_init(&qp->sq.lock)) { + ret = -EFAULT; + UVP_PRINT(TRACE_LEVEL_ERROR ,UVP_DBG_QP ,("cl_spinlock_init failed for sq (%d)\n",ret)); + goto err_spinlock_sq; + } + + cl_spinlock_construct(&qp->rq.lock); + if (cl_spinlock_init(&qp->rq.lock)) { + ret = -EFAULT; + UVP_PRINT(TRACE_LEVEL_ERROR ,UVP_DBG_QP ,("cl_spinlock_init failed for rq (%d)\n",ret)); + goto err_spinlock_rq; + } + + if (mthca_is_memfree(context)) { + qp->sq.db_index = mthca_alloc_db(to_mctx(context)->db_tab, + MTHCA_DB_TYPE_SQ, + &qp->sq.db); + if (qp->sq.db_index < 0) + goto err_sq_db; + + qp->rq.db_index = mthca_alloc_db(to_mctx(context)->db_tab, + MTHCA_DB_TYPE_RQ, + &qp->rq.db); + if (qp->rq.db_index < 0) + goto err_rq_db; + + req->sq_db_page = db_align(qp->sq.db); + req->rq_db_page = db_align(qp->rq.db); + req->sq_db_index = qp->sq.db_index; + req->rq_db_index = qp->rq.db_index; + } + + // fill the rest qp fields + qp->ibv_qp.pd = pd; + qp->ibv_qp.context= pd->context; + qp->ibv_qp.send_cq = attr->send_cq; + qp->ibv_qp.recv_cq = attr->recv_cq; + qp->ibv_qp.srq = attr->srq; + qp->ibv_qp.state = IBV_QPS_RESET; + qp->ibv_qp.qp_type = attr->qp_type; + + // fill the rest request fields + req->mr.start = (uint64_t)(ULONG_PTR)qp->buf; + req->mr.length = qp->buf_size; + req->mr.hca_va = 0; + req->mr.pd_handle = pd->handle; + req->mr.pdn = to_mpd(pd)->pdn; + req->mr.access_flags = 0; //local read + req->user_handle = (uint64_t)(ULONG_PTR)qp; + req->send_cq_handle = attr->send_cq->handle; + req->recv_cq_handle = attr->recv_cq->handle; + req->srq_handle = (attr->srq) ? attr->srq->handle : 0; + req->max_send_wr = attr->cap.max_send_wr; + req->max_recv_wr = attr->cap.max_recv_wr; + req->max_send_sge = attr->cap.max_send_sge; + req->max_recv_sge = attr->cap.max_recv_sge; + req->max_inline_data = attr->cap.max_inline_data; + req->sq_sig_all = (uint8_t)attr->sq_sig_all; + req->qp_type = attr->qp_type; + req->is_srq = !!attr->srq; + + + UVP_EXIT(UVP_DBG_QP); + return &qp->ibv_qp; + +err_rq_db: + if (mthca_is_memfree(context)) + mthca_free_db(to_mctx(context)->db_tab, + MTHCA_DB_TYPE_SQ, qp->sq.db_index); + +err_sq_db: + cl_spinlock_destroy(&qp->rq.lock); + +err_spinlock_rq: + cl_spinlock_destroy(&qp->sq.lock); + +err_spinlock_sq: + cl_free(qp->wrid); + posix_memfree(qp->buf); + +err_nomem: + cl_free(qp); + +exit: + + UVP_EXIT(UVP_DBG_QP); + return ERR_PTR(ret); +} + +struct ibv_qp *mthca_create_qp_post(struct ibv_pd *pd, + struct ibv_create_qp_resp *resp) +{ + struct mthca_qp *qp; + int ret; + UVP_ENTER(UVP_DBG_QP); + qp = (struct mthca_qp *)(ULONG_PTR)resp->user_handle; + + qp->ibv_qp.handle = resp->qp_handle; + qp->ibv_qp.qp_num = resp->qpn; + qp->sq.max = resp->max_send_wr; + qp->rq.max = resp->max_recv_wr; + qp->sq.max_gs = resp->max_send_sge; + qp->rq.max_gs = resp->max_recv_sge; + qp->max_inline_data = resp->max_inline_data; + qp->mr.handle = resp->mr.mr_handle; + qp->mr.lkey = resp->mr.lkey; + qp->mr.rkey = resp->mr.rkey; + qp->mr.pd = pd; + qp->mr.context = pd->context; + + if (mthca_is_memfree(pd->context)) { + mthca_set_db_qn(qp->sq.db, MTHCA_DB_TYPE_SQ, qp->ibv_qp.qp_num); + mthca_set_db_qn(qp->rq.db, MTHCA_DB_TYPE_RQ, qp->ibv_qp.qp_num); + } + + ret = mthca_store_qp(to_mctx(pd->context), qp->ibv_qp.qp_num, qp); + if (ret) + goto err_store_qp; + + UVP_EXIT(UVP_DBG_QP); + return &qp->ibv_qp; + +err_store_qp: + UVP_EXIT(UVP_DBG_QP); + return ERR_PTR(ret); +} + + +int mthca_modify_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr, + enum ibv_qp_attr_mask attr_mask) +{ + int ret = 0; + + if (attr_mask & IBV_QP_STATE) + qp->state = attr->qp_state; + + if ((attr_mask & IBV_QP_STATE) && + (attr->qp_state == IBV_QPS_RESET)) { + mthca_cq_clean(to_mcq(qp->recv_cq), qp->qp_num, + qp->srq ? to_msrq(qp->srq) : NULL); + if (qp->send_cq != qp->recv_cq) + mthca_cq_clean(to_mcq(qp->send_cq), qp->qp_num, NULL); + + mthca_init_qp_indices(to_mqp(qp)); + + if (mthca_is_memfree(qp->pd->context)) { + *to_mqp(qp)->sq.db = 0; + *to_mqp(qp)->rq.db = 0; + } + } + + return ret; +} + + +void mthca_destroy_qp_pre(struct ibv_qp *qp) +{ + int ret; + + mthca_cq_clean(to_mcq(qp->recv_cq), qp->qp_num, + qp->srq ? to_msrq(qp->srq) : NULL); + if (qp->send_cq != qp->recv_cq) + mthca_cq_clean(to_mcq(qp->send_cq), qp->qp_num, NULL); + + cl_spinlock_acquire(&to_mcq(qp->send_cq)->lock); + if (qp->send_cq != qp->recv_cq) + cl_spinlock_acquire(&to_mcq(qp->recv_cq)->lock); + mthca_clear_qp(to_mctx(qp->pd->context), qp->qp_num); + if (qp->send_cq != qp->recv_cq) + cl_spinlock_release(&to_mcq(qp->recv_cq)->lock); + cl_spinlock_release(&to_mcq(qp->send_cq)->lock); +} + +void mthca_destroy_qp_post(struct ibv_qp *qp, int ret) +{ + if (ret) { + cl_spinlock_acquire(&to_mcq(qp->send_cq)->lock); + if (qp->send_cq != qp->recv_cq) + cl_spinlock_acquire(&to_mcq(qp->recv_cq)->lock); + mthca_store_qp(to_mctx(qp->pd->context), qp->qp_num, to_mqp(qp)); + if (qp->send_cq != qp->recv_cq) + cl_spinlock_release(&to_mcq(qp->recv_cq)->lock); + cl_spinlock_release(&to_mcq(qp->send_cq)->lock); + } + else { + if (mthca_is_memfree(qp->pd->context)) { + mthca_free_db(to_mctx(qp->pd->context)->db_tab, MTHCA_DB_TYPE_RQ, + to_mqp(qp)->rq.db_index); + mthca_free_db(to_mctx(qp->pd->context)->db_tab, MTHCA_DB_TYPE_SQ, + to_mqp(qp)->sq.db_index); + } + + cl_spinlock_destroy(&((struct mthca_qp *)qp)->sq.lock); + cl_spinlock_destroy(&((struct mthca_qp *)qp)->rq.lock); + + posix_memfree(to_mqp(qp)->buf); + cl_free(to_mqp(qp)->wrid); + cl_free(to_mqp(qp)); + } + +} + +int mthca_attach_mcast(struct ibv_qp *qp, union ibv_gid *gid, uint16_t lid) +{ +#ifdef WIN_TO_BE_CHANGED + return ibv_cmd_attach_mcast(qp, gid, lid); +#else + return -ENOSYS; +#endif +} + +int mthca_detach_mcast(struct ibv_qp *qp, union ibv_gid *gid, uint16_t lid) +{ +#ifdef WIN_TO_BE_CHANGED + return ibv_cmd_detach_mcast(qp, gid, lid); +#else + return -ENOSYS; +#endif +} + diff --git a/branches/WOF2-3/hw/mthca/user/mlnx_uvp_verbs.h b/branches/WOF2-3/hw/mthca/user/mlnx_uvp_verbs.h new file mode 100644 index 00000000..069271cd --- /dev/null +++ b/branches/WOF2-3/hw/mthca/user/mlnx_uvp_verbs.h @@ -0,0 +1,491 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2004 Intel Corporation. All rights reserved. + * Copyright (c) 2005 Cisco Systems. All rights reserved. + * Copyright (c) 2005 PathScale, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#ifndef MLNX_UVP_VERBS_H +#define MLNX_UVP_VERBS_H + +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS + +union ibv_gid { + uint8_t raw[16]; + struct { + uint64_t subnet_prefix; + uint64_t interface_id; + } global; +}; + +enum ibv_node_type { + IBV_NODE_CA = 1, + IBV_NODE_SWITCH, + IBV_NODE_ROUTER +}; + +enum ibv_device_cap_flags { + IBV_DEVICE_RESIZE_MAX_WR = 1, + IBV_DEVICE_BAD_PKEY_CNTR = 1 << 1, + IBV_DEVICE_BAD_QKEY_CNTR = 1 << 2, + IBV_DEVICE_RAW_MULTI = 1 << 3, + IBV_DEVICE_AUTO_PATH_MIG = 1 << 4, + IBV_DEVICE_CHANGE_PHY_PORT = 1 << 5, + IBV_DEVICE_UD_AV_PORT_ENFORCE = 1 << 6, + IBV_DEVICE_CURR_QP_STATE_MOD = 1 << 7, + IBV_DEVICE_SHUTDOWN_PORT = 1 << 8, + IBV_DEVICE_INIT_TYPE = 1 << 9, + IBV_DEVICE_PORT_ACTIVE_EVENT = 1 << 10, + IBV_DEVICE_SYS_IMAGE_GUID = 1 << 11, + IBV_DEVICE_RC_RNR_NAK_GEN = 1 << 12, + IBV_DEVICE_SRQ_RESIZE = 1 << 13, + IBV_DEVICE_N_NOTIFY_CQ = 1 << 14, +}; + +enum ibv_atomic_cap { + IBV_ATOMIC_NONE, + IBV_ATOMIC_HCA, + IBV_ATOMIC_GLOB +}; + +struct ibv_device_attr { + char fw_ver[64]; + uint64_t node_guid; + uint64_t sys_image_guid; + uint64_t max_mr_size; + uint64_t page_size_cap; + uint32_t vendor_id; + uint32_t vendor_part_id; + uint32_t hw_ver; + int max_qp; + int max_qp_wr; + int device_cap_flags; + int max_sge; + int max_sge_rd; + int max_cq; + int max_cqe; + int max_mr; + int max_pd; + int max_qp_rd_atom; + int max_ee_rd_atom; + int max_res_rd_atom; + int max_qp_init_rd_atom; + int max_ee_init_rd_atom; + enum ibv_atomic_cap atomic_cap; + int max_ee; + int max_rdd; + int max_mw; + int max_raw_ipv6_qp; + int max_raw_ethy_qp; + int max_mcast_grp; + int max_mcast_qp_attach; + int max_total_mcast_qp_attach; + uint64_t max_ah; + int max_fmr; + int max_map_per_fmr; + int max_srq; + int max_srq_wr; + int max_srq_sge; + uint16_t max_pkeys; + uint8_t local_ca_ack_delay; + uint8_t phys_port_cnt; +}; + +enum ibv_mtu { + IBV_MTU_256 = 1, + IBV_MTU_512 = 2, + IBV_MTU_1024 = 3, + IBV_MTU_2048 = 4, + IBV_MTU_4096 = 5 +}; + +enum ibv_port_state { + IBV_PORT_NOP = 0, + IBV_PORT_DOWN = 1, + IBV_PORT_INIT = 2, + IBV_PORT_ARMED = 3, + IBV_PORT_ACTIVE = 4, + IBV_PORT_ACTIVE_DEFER = 5 +}; + +struct ibv_port_attr { + enum ibv_port_state state; + enum ibv_mtu max_mtu; + enum ibv_mtu active_mtu; + int gid_tbl_len; + uint32_t port_cap_flags; + uint32_t max_msg_sz; + uint32_t bad_pkey_cntr; + uint32_t qkey_viol_cntr; + uint16_t pkey_tbl_len; + uint16_t lid; + uint16_t sm_lid; + uint8_t lmc; + uint8_t max_vl_num; + uint8_t sm_sl; + uint8_t subnet_timeout; + uint8_t init_type_reply; + uint8_t active_width; + uint8_t active_speed; + uint8_t phys_state; +}; + +enum ibv_event_type { + IBV_EVENT_CQ_ERR, + IBV_EVENT_QP_FATAL, + IBV_EVENT_QP_REQ_ERR, + IBV_EVENT_QP_ACCESS_ERR, + IBV_EVENT_COMM_EST, + IBV_EVENT_SQ_DRAINED, + IBV_EVENT_PATH_MIG, + IBV_EVENT_PATH_MIG_ERR, + IBV_EVENT_DEVICE_FATAL, + IBV_EVENT_PORT_ACTIVE, + IBV_EVENT_PORT_ERR, + IBV_EVENT_LID_CHANGE, + IBV_EVENT_PKEY_CHANGE, + IBV_EVENT_SM_CHANGE, + IBV_EVENT_SRQ_ERR, + IBV_EVENT_SRQ_LIMIT_REACHED, + IBV_EVENT_QP_LAST_WQE_REACHED +}; + +struct ibv_async_event { + union { + struct ibv_cq *cq; + struct ibv_qp *qp; + struct ibv_srq *srq; + int port_num; + } element; + enum ibv_event_type event_type; +}; + +enum ibv_access_flags { + IBV_ACCESS_LOCAL_WRITE = 1, + IBV_ACCESS_REMOTE_WRITE = (1<<1), + IBV_ACCESS_REMOTE_READ = (1<<2), + IBV_ACCESS_REMOTE_ATOMIC = (1<<3), + IBV_ACCESS_MW_BIND = (1<<4) +}; + +struct ibv_pd { + struct ibv_context *context; + uint64_t handle; +}; + +struct ibv_mr { + struct ibv_context *context; + struct ibv_pd *pd; + uint64_t handle; + uint32_t lkey; + uint32_t rkey; +}; + +struct ibv_global_route { + ib_gid_t dgid; + uint32_t flow_label; + uint8_t sgid_index; + uint8_t hop_limit; + uint8_t traffic_class; +}; + +struct ibv_ah_attr { + struct ibv_global_route grh; + uint16_t dlid; + uint8_t sl; + uint8_t src_path_bits; + uint8_t static_rate; + uint8_t is_global; + uint8_t port_num; +}; + + +enum ib_cq_notify { + IB_CQ_SOLICITED, + IB_CQ_NEXT_COMP +}; + +enum ibv_srq_attr_mask { + IBV_SRQ_MAX_WR = 1 << 0, + IBV_SRQ_LIMIT = 1 << 1, +}; + +struct ibv_srq_attr { + uint32_t max_wr; + uint32_t max_sge; + uint32_t srq_limit; +}; + +struct ibv_srq_init_attr { + void *srq_context; + struct ibv_srq_attr attr; +}; + +struct ibv_qp_cap { + uint32_t max_send_wr; + uint32_t max_recv_wr; + uint32_t max_send_sge; + uint32_t max_recv_sge; + uint32_t max_inline_data; +}; + +struct ibv_qp_init_attr { + void *qp_context; + struct ibv_cq *send_cq; + struct ibv_cq *recv_cq; + struct ibv_srq *srq; + struct ibv_qp_cap cap; + ib_qp_type_t qp_type; + int sq_sig_all; +}; + +enum ibv_qp_attr_mask { + IBV_QP_STATE = 1 << 0, + IBV_QP_CUR_STATE = 1 << 1, + IBV_QP_EN_SQD_ASYNC_NOTIFY = 1 << 2, + IBV_QP_ACCESS_FLAGS = 1 << 3, + IBV_QP_PKEY_INDEX = 1 << 4, + IBV_QP_PORT = 1 << 5, + IBV_QP_QKEY = 1 << 6, + IBV_QP_AV = 1 << 7, + IBV_QP_PATH_MTU = 1 << 8, + IBV_QP_TIMEOUT = 1 << 9, + IBV_QP_RETRY_CNT = 1 << 10, + IBV_QP_RNR_RETRY = 1 << 11, + IBV_QP_RQ_PSN = 1 << 12, + IBV_QP_MAX_QP_RD_ATOMIC = 1 << 13, + IBV_QP_ALT_PATH = 1 << 14, + IBV_QP_MIN_RNR_TIMER = 1 << 15, + IBV_QP_SQ_PSN = 1 << 16, + IBV_QP_MAX_DEST_RD_ATOMIC = 1 << 17, + IBV_QP_PATH_MIG_STATE = 1 << 18, + IBV_QP_CAP = 1 << 19, + IBV_QP_DEST_QPN = 1 << 20 +}; + +enum ibv_qp_state { + IBV_QPS_RESET, + IBV_QPS_INIT, + IBV_QPS_RTR, + IBV_QPS_RTS, + IBV_QPS_SQD, + IBV_QPS_SQE, + IBV_QPS_ERR +}; + +enum ibv_mig_state { + IBV_MIG_MIGRATED, + IBV_MIG_REARM, + IBV_MIG_ARMED +}; + +struct ibv_qp_attr { + enum ibv_qp_state qp_state; + enum ibv_qp_state cur_qp_state; + enum ibv_mtu path_mtu; + enum ibv_mig_state path_mig_state; + uint32_t qkey; + uint32_t rq_psn; + uint32_t sq_psn; + uint32_t dest_qp_num; + int qp_access_flags; + struct ibv_qp_cap cap; + struct ibv_ah_attr ah_attr; + struct ibv_ah_attr alt_ah_attr; + uint16_t pkey_index; + uint16_t alt_pkey_index; + uint8_t en_sqd_async_notify; + uint8_t sq_draining; + uint8_t max_rd_atomic; + uint8_t max_dest_rd_atomic; + uint8_t min_rnr_timer; + uint8_t port_num; + uint8_t timeout; + uint8_t retry_cnt; + uint8_t rnr_retry; + uint8_t alt_port_num; + uint8_t alt_timeout; +}; + + +enum ibv_send_flags { + IBV_SEND_FENCE = 1 << 0, + IBV_SEND_SIGNALED = 1 << 1, + IBV_SEND_SOLICITED = 1 << 2, + IBV_SEND_INLINE = 1 << 3 +}; + +struct ibv_sge { + uint64_t addr; + uint32_t length; + uint32_t lkey; +}; + +struct ibv_send_wr { + struct ibv_send_wr *next; + uint64_t wr_id; + struct ibv_sge *sg_list; + int num_sge; + enum ibv_wr_opcode opcode; + enum ibv_send_flags send_flags; + uint32_t imm_data; /* in network byte order */ + union { + struct { + uint64_t remote_addr; + uint32_t rkey; + } rdma; + struct { + uint64_t remote_addr; + uint64_t compare_add; + uint64_t swap; + uint32_t rkey; + } atomic; + struct { + struct mthca_ah *ah; + uint32_t remote_qpn; + uint32_t remote_qkey; + } ud; + } wr; +}; + +struct ibv_recv_wr { + struct ibv_recv_wr *next; + uint64_t wr_id; + struct ibv_sge *sg_list; + int num_sge; +}; + +typedef enum MTHCA_QP_ACCESS_FLAGS { + MTHCA_ACCESS_LOCAL_WRITE = 1, + MTHCA_ACCESS_REMOTE_WRITE = (1<<1), + MTHCA_ACCESS_REMOTE_READ = (1<<2), + MTHCA_ACCESS_REMOTE_ATOMIC = (1<<3), + MTHCA_ACCESS_MW_BIND = (1<<4) +} mthca_qp_access_t; + + +struct ibv_srq { + struct ibv_pd *pd; + uint64_t handle; + struct ibv_context *context; +}; + +struct ibv_qp { + struct ibv_pd *pd; + struct ibv_cq *send_cq; + struct ibv_cq *recv_cq; + struct ibv_srq *srq; + uint64_t handle; + uint32_t qp_num; + enum ibv_qp_state state; + ib_qp_type_t qp_type; + struct ibv_context *context; + void *qp_context; +}; + +struct ibv_cq { + uint64_t handle; + int cqe; + struct ibv_context *context; +}; + +struct ibv_ah { + struct ibv_pd *pd; +}; + +struct ibv_context_ops { + int (*query_device)(struct ibv_context *context, + struct ibv_device_attr *device_attr); + int (*query_port)(struct ibv_context *context, uint8_t port_num, + struct ibv_port_attr *port_attr); + struct ibv_pd * (*alloc_pd)(struct ibv_context *context, struct ibv_alloc_pd_resp *resp_p); + int (*dealloc_pd)(struct ibv_pd *pd); + struct ibv_mr * (*reg_mr)(struct ibv_pd *pd, void *addr, size_t length, + enum ibv_access_flags access); + int (*dereg_mr)(struct ibv_mr *mr); + struct ibv_cq * (*create_cq_pre)(struct ibv_context *context, int *cqe, + struct ibv_create_cq *req); + struct ibv_cq * (*create_cq_post)(struct ibv_context *context, + struct ibv_create_cq_resp *resp); + int (*poll_cq)(struct ibv_cq *cq, int num_entries, struct _uvp_wc *wc); + int (*poll_cq_list)( struct ibv_cq *ibcq, + struct _ib_wc** const pp_free_wclist, + struct _ib_wc** const pp_done_wclist ); + int (*req_notify_cq)(struct ibv_cq *cq, int solicited_only); + int (*destroy_cq)(struct ibv_cq *cq); + struct ibv_srq * (*create_srq)(struct ibv_pd *pd, + struct ibv_srq_init_attr *srq_init_attr); + int (*modify_srq)(struct ibv_srq *srq, + struct ibv_srq_attr *srq_attr, + enum ibv_srq_attr_mask srq_attr_mask); + int (*destroy_srq)(struct ibv_srq *srq); + int (*post_srq_recv)(struct ibv_srq *srq, + struct _ib_recv_wr *recv_wr, + struct _ib_recv_wr **bad_recv_wr); + struct ibv_qp *(*create_qp_pre)(struct ibv_pd *pd, + struct ibv_qp_init_attr *attr, struct ibv_create_qp *req); + struct ibv_qp *(*create_qp_post)(struct ibv_pd *pd, + struct ibv_create_qp_resp *resp); + int (*modify_qp)(struct ibv_qp *qp, struct ibv_qp_attr *attr, + enum ibv_qp_attr_mask attr_mask); + int (*destroy_qp)(struct ibv_qp *qp); + int (*post_send)(struct ibv_qp *qp, struct _ib_send_wr *wr, + struct _ib_send_wr **bad_wr); + int (*post_recv)(struct ibv_qp *qp, struct _ib_recv_wr *wr, + struct _ib_recv_wr **bad_wr); + int (*attach_mcast)(struct ibv_qp *qp, union ibv_gid *gid, + uint16_t lid); + int (*detach_mcast)(struct ibv_qp *qp, union ibv_gid *gid, + uint16_t lid); +}; + +struct ibv_context { + struct ibv_context_ops ops; + void *abi_compat; +}; + +int align_queue_size(struct ibv_context *context, int size, int spare); + +END_C_DECLS + +#endif /* INFINIBAND_VERBS_H */ diff --git a/branches/WOF2-3/hw/mthca/user/mt_l2w.h b/branches/WOF2-3/hw/mthca/user/mt_l2w.h new file mode 100644 index 00000000..e7bb2ab2 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/user/mt_l2w.h @@ -0,0 +1,104 @@ +#ifndef UMT_L2W_H +#define UMT_L2W_H + +// =========================================== +// INCLUDES +// =========================================== + +// OS +#include +#include +#include +//#include +#include +#include +//#include +#include + + +// =========================================== +// SUBSTITUTIONS +// =========================================== + +#define inline __inline +#define likely(x) (x) +#define unlikely(x) (x) + +// =========================================== +// LITERALS +// =========================================== + + + +// =========================================== +// TYPES +// =========================================== + + +// =========================================== +// MACROS +// =========================================== + +// nullifying macros + +#define ERR_PTR(error) ((void*)(LONG_PTR)(error)) +#define PTR_ERR(ptr) ((long)(LONG_PTR)(void*)(ptr)) +//TODO: there are 2 assumptions here: +// - pointer can't be too big (around -1) +// - error can't be bigger than 1000 +#define IS_ERR(ptr) ((ULONG_PTR)ptr > (ULONG_PTR)-1000L) + +#define ffsl(val) ffs(val) + +extern size_t g_page_size; + +static inline BOOLEAN is_power_of_2(uint32_t n) +{ + return (!!n & !(n & (n-1))) ? TRUE : FALSE; +} + +// Allocated memory is zeroed ! +static inline int posix_memalign(void **memptr, int alignment, int size) +{ + int aligned_size, desc_size = sizeof(int); + char *real_addr, *aligned_addr; + + // sanity check: alignment should a power of 2 and more then 2 + if ( alignment < desc_size || !is_power_of_2((uint32_t)alignment) ) + return -EINVAL; + + // calculate size, needed for aligned allocation + aligned_size = size + alignment + desc_size; + + // allocate + real_addr = cl_zalloc(aligned_size); + if ( real_addr == NULL ) + return -ENOMEM; + + // calculate aligned address + aligned_addr = (char *)(((ULONG_PTR)(real_addr + alignment-1)) & ~(alignment - 1)); + if ( aligned_addr < real_addr + desc_size ) + aligned_addr += alignment; + + // store the descriptor + *(int*)(aligned_addr - desc_size) = (int)(aligned_addr - real_addr); + + *memptr = aligned_addr; + return 0; +} + +// there is no such POSIX function. Called so to be similar to the allocation one. +static inline void posix_memfree(void *memptr) +{ + int *desc_addr = (int*)((char*)memptr - sizeof(int)); + char *real_addr = (char*)memptr - *desc_addr; + cl_free(real_addr); +} + +// =========================================== +// FUNCTIONS +// =========================================== + + +#endif + diff --git a/branches/WOF2-3/hw/mthca/user/opcode.h b/branches/WOF2-3/hw/mthca/user/opcode.h new file mode 100644 index 00000000..cf2598b6 --- /dev/null +++ b/branches/WOF2-3/hw/mthca/user/opcode.h @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#ifndef INFINIBAND_OPCODE_H +#define INFINIBAND_OPCODE_H + +/* + * This macro cleans up the definitions of constants for BTH opcodes. + * It is used to define constants such as IBV_OPCODE_UD_SEND_ONLY, + * which becomes IBV_OPCODE_UD + IBV_OPCODE_SEND_ONLY, and this gives + * the correct value. + * + * In short, user code should use the constants defined using the + * macro rather than worrying about adding together other constants. +*/ +#define IBV_OPCODE(transport, op) \ + IBV_OPCODE_ ## transport ## _ ## op = \ + IBV_OPCODE_ ## transport + IBV_OPCODE_ ## op + +enum { + /* transport types -- just used to define real constants */ + IBV_OPCODE_RC = 0x00, + IBV_OPCODE_UC = 0x20, + IBV_OPCODE_RD = 0x40, + IBV_OPCODE_UD = 0x60, + + /* operations -- just used to define real constants */ + IBV_OPCODE_SEND_FIRST = 0x00, + IBV_OPCODE_SEND_MIDDLE = 0x01, + IBV_OPCODE_SEND_LAST = 0x02, + IBV_OPCODE_SEND_LAST_WITH_IMMEDIATE = 0x03, + IBV_OPCODE_SEND_ONLY = 0x04, + IBV_OPCODE_SEND_ONLY_WITH_IMMEDIATE = 0x05, + IBV_OPCODE_RDMA_WRITE_FIRST = 0x06, + IBV_OPCODE_RDMA_WRITE_MIDDLE = 0x07, + IBV_OPCODE_RDMA_WRITE_LAST = 0x08, + IBV_OPCODE_RDMA_WRITE_LAST_WITH_IMMEDIATE = 0x09, + IBV_OPCODE_RDMA_WRITE_ONLY = 0x0a, + IBV_OPCODE_RDMA_WRITE_ONLY_WITH_IMMEDIATE = 0x0b, + IBV_OPCODE_RDMA_READ_REQUEST = 0x0c, + IBV_OPCODE_RDMA_READ_RESPONSE_FIRST = 0x0d, + IBV_OPCODE_RDMA_READ_RESPONSE_MIDDLE = 0x0e, + IBV_OPCODE_RDMA_READ_RESPONSE_LAST = 0x0f, + IBV_OPCODE_RDMA_READ_RESPONSE_ONLY = 0x10, + IBV_OPCODE_ACKNOWLEDGE = 0x11, + IBV_OPCODE_ATOMIC_ACKNOWLEDGE = 0x12, + IBV_OPCODE_COMPARE_SWAP = 0x13, + IBV_OPCODE_FETCH_ADD = 0x14, + + /* real constants follow -- see comment about above IBV_OPCODE() + macro for more details */ + + /* RC */ + IBV_OPCODE(RC, SEND_FIRST), + IBV_OPCODE(RC, SEND_MIDDLE), + IBV_OPCODE(RC, SEND_LAST), + IBV_OPCODE(RC, SEND_LAST_WITH_IMMEDIATE), + IBV_OPCODE(RC, SEND_ONLY), + IBV_OPCODE(RC, SEND_ONLY_WITH_IMMEDIATE), + IBV_OPCODE(RC, RDMA_WRITE_FIRST), + IBV_OPCODE(RC, RDMA_WRITE_MIDDLE), + IBV_OPCODE(RC, RDMA_WRITE_LAST), + IBV_OPCODE(RC, RDMA_WRITE_LAST_WITH_IMMEDIATE), + IBV_OPCODE(RC, RDMA_WRITE_ONLY), + IBV_OPCODE(RC, RDMA_WRITE_ONLY_WITH_IMMEDIATE), + IBV_OPCODE(RC, RDMA_READ_REQUEST), + IBV_OPCODE(RC, RDMA_READ_RESPONSE_FIRST), + IBV_OPCODE(RC, RDMA_READ_RESPONSE_MIDDLE), + IBV_OPCODE(RC, RDMA_READ_RESPONSE_LAST), + IBV_OPCODE(RC, RDMA_READ_RESPONSE_ONLY), + IBV_OPCODE(RC, ACKNOWLEDGE), + IBV_OPCODE(RC, ATOMIC_ACKNOWLEDGE), + IBV_OPCODE(RC, COMPARE_SWAP), + IBV_OPCODE(RC, FETCH_ADD), + + /* UC */ + IBV_OPCODE(UC, SEND_FIRST), + IBV_OPCODE(UC, SEND_MIDDLE), + IBV_OPCODE(UC, SEND_LAST), + IBV_OPCODE(UC, SEND_LAST_WITH_IMMEDIATE), + IBV_OPCODE(UC, SEND_ONLY), + IBV_OPCODE(UC, SEND_ONLY_WITH_IMMEDIATE), + IBV_OPCODE(UC, RDMA_WRITE_FIRST), + IBV_OPCODE(UC, RDMA_WRITE_MIDDLE), + IBV_OPCODE(UC, RDMA_WRITE_LAST), + IBV_OPCODE(UC, RDMA_WRITE_LAST_WITH_IMMEDIATE), + IBV_OPCODE(UC, RDMA_WRITE_ONLY), + IBV_OPCODE(UC, RDMA_WRITE_ONLY_WITH_IMMEDIATE), + + /* RD */ + IBV_OPCODE(RD, SEND_FIRST), + IBV_OPCODE(RD, SEND_MIDDLE), + IBV_OPCODE(RD, SEND_LAST), + IBV_OPCODE(RD, SEND_LAST_WITH_IMMEDIATE), + IBV_OPCODE(RD, SEND_ONLY), + IBV_OPCODE(RD, SEND_ONLY_WITH_IMMEDIATE), + IBV_OPCODE(RD, RDMA_WRITE_FIRST), + IBV_OPCODE(RD, RDMA_WRITE_MIDDLE), + IBV_OPCODE(RD, RDMA_WRITE_LAST), + IBV_OPCODE(RD, RDMA_WRITE_LAST_WITH_IMMEDIATE), + IBV_OPCODE(RD, RDMA_WRITE_ONLY), + IBV_OPCODE(RD, RDMA_WRITE_ONLY_WITH_IMMEDIATE), + IBV_OPCODE(RD, RDMA_READ_REQUEST), + IBV_OPCODE(RD, RDMA_READ_RESPONSE_FIRST), + IBV_OPCODE(RD, RDMA_READ_RESPONSE_MIDDLE), + IBV_OPCODE(RD, RDMA_READ_RESPONSE_LAST), + IBV_OPCODE(RD, RDMA_READ_RESPONSE_ONLY), + IBV_OPCODE(RD, ACKNOWLEDGE), + IBV_OPCODE(RD, ATOMIC_ACKNOWLEDGE), + IBV_OPCODE(RD, COMPARE_SWAP), + IBV_OPCODE(RD, FETCH_ADD), + + /* UD */ + IBV_OPCODE(UD, SEND_ONLY), + IBV_OPCODE(UD, SEND_ONLY_WITH_IMMEDIATE) +}; + +#endif /* INFINIBAND_OPCODE_H */ diff --git a/branches/WOF2-3/inc/complib/cl_async_proc.h b/branches/WOF2-3/inc/complib/cl_async_proc.h new file mode 100644 index 00000000..083571a4 --- /dev/null +++ b/branches/WOF2-3/inc/complib/cl_async_proc.h @@ -0,0 +1,342 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * Abstract: + * Declaration of the asynchronous processing module. + * + * Environment: + * All + */ + + +#ifndef _CL_ASYNC_PROC_H_ +#define _CL_ASYNC_PROC_H_ + + +#include +#include +#include +#include + + +/****h* Component Library/Asynchronous Processor +* NAME +* Asynchronous Processor +* +* DESCRIPTION +* The asynchronous processor provides threads for executing queued callbacks. +* +* The threads in the asynchronous processor wait for callbacks to be queued. +* +* The asynchronous processor functions operate on a cl_async_proc_t structure +* which should be treated as opaque and manipulated only through the provided +* functions. +* +* SEE ALSO +* Structures: +* cl_async_proc_t, cl_async_proc_item_t +* +* Initialization: +* cl_async_proc_construct, cl_async_proc_init, cl_async_proc_destroy +* +* Manipulation: +* cl_async_proc_queue +*********/ + + +/****s* Component Library: Asynchronous Processor/cl_async_proc_t +* NAME +* cl_async_proc_t +* +* DESCRIPTION +* Asynchronous processor structure. +* +* The cl_async_proc_t structure should be treated as opaque, and should be +* manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _cl_async_proc +{ + cl_thread_pool_t thread_pool; + cl_qlist_t item_queue; + cl_spinlock_t lock; + cl_state_t state; + +} cl_async_proc_t; +/* +* FIELDS +* item_pool +* Pool of items storing the callback function and contexts to be invoked +* by the asynchronous processor's threads. +* +* thread_pool +* Thread pool that will invoke the callbacks. +* +* item_queue +* Queue of items that the threads should process. +* +* lock +* Lock used to synchronize access to the item pool and queue. +* +* SEE ALSO +* Asynchronous Processor +*********/ + + +/* + * Declare the structure so we can reference it in the following function + * prototype. + */ +typedef struct _cl_async_proc_item *__p_cl_async_proc_item_t; + + +/****d* Component Library: Asynchronous Processor/cl_pfn_async_proc_cb_t +* NAME +* cl_pfn_async_proc_cb_t +* +* DESCRIPTION +* The cl_pfn_async_proc_cb_t function type defines the prototype for +* callbacks queued to and invoked by the asynchronous processor. +* +* SYNOPSIS +*/ +typedef void +(CL_API *cl_pfn_async_proc_cb_t)( + IN struct _cl_async_proc_item *p_item ); +/* +* PARAMETERS +* p_item +* Pointer to the cl_async_proc_item_t structure that was queued in +* a call to cl_async_proc_queue. +* +* NOTES +* This function type is provided as function prototype reference for the +* function provided by users as a parameter to the cl_async_proc_queue +* function. +* +* SEE ALSO +* Asynchronous Processor, cl_async_proc_item_t +*********/ + + +/****s* Component Library: Asynchronous Processor/cl_async_proc_item_t +* NAME +* cl_async_proc_item_t +* +* DESCRIPTION +* Asynchronous processor item structure passed to the cl_async_proc_queue +* function to queue a callback for execution. +* +* SYNOPSIS +*/ +typedef struct _cl_async_proc_item +{ + cl_pool_item_t pool_item; + cl_pfn_async_proc_cb_t pfn_callback; + +} cl_async_proc_item_t; +/* +* FIELDS +* pool_item +* Pool item for queuing the item to be invoked by the asynchronous +* processor's threads. This field is defined as a pool item to +* allow items to be managed by a pool. +* +* pfn_callback +* Pointer to a callback function to invoke when the item is dequeued. +* +* SEE ALSO +* Asynchronous Processor, cl_async_proc_queue, cl_pfn_async_proc_cb_t +*********/ + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/****f* Component Library: Asynchronous Processor/cl_async_proc_construct +* NAME +* cl_async_proc_construct +* +* DESCRIPTION +* The cl_async_proc_construct function initializes the state of a +* thread pool. +* +* SYNOPSIS +*/ +CL_EXPORT void CL_API +cl_async_proc_construct( + IN cl_async_proc_t* const p_async_proc ); +/* +* PARAMETERS +* p_async_proc +* [in] Pointer to an asynchronous processor structure. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling cl_async_proc_destroy without first calling +* cl_async_proc_init. +* +* Calling cl_async_proc_construct is a prerequisite to calling any other +* thread pool function except cl_async_proc_init. +* +* SEE ALSO +* Asynchronous Processor, cl_async_proc_init, cl_async_proc_destroy +*********/ + + +/****f* Component Library: Asynchronous Processor/cl_async_proc_init +* NAME +* cl_async_proc_init +* +* DESCRIPTION +* The cl_async_proc_init function initialized an asynchronous processor +* for use. +* +* SYNOPSIS +*/ +CL_EXPORT cl_status_t CL_API +cl_async_proc_init( + IN cl_async_proc_t* const p_async_proc, + IN const uint32_t thread_count, + IN const char* const name ); +/* +* PARAMETERS +* p_async_proc +* [in] Pointer to an asynchronous processor structure to initialize. +* +* thread_count +* [in] Number of threads to be managed by the asynchronous processor. +* +* 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 asynchronous processor have the same name. +* +* RETURN VALUES +* CL_SUCCESS if the asynchronous processor creation succeeded. +* +* CL_INSUFFICIENT_MEMORY if there was not enough memory to inititalize +* the asynchronous processor. +* +* CL_ERROR if the threads could not be created. +* +* NOTES +* cl_async_proc_init creates and starts the specified number of threads. +* If thread_count is zero, the asynchronous processor creates as many +* threads as there are processors in the system. +* +* SEE ALSO +* Asynchronous Processor, cl_async_proc_construct, cl_async_proc_destroy, +* cl_async_proc_queue +*********/ + + +/****f* Component Library: Asynchronous Processor/cl_async_proc_destroy +* NAME +* cl_async_proc_destroy +* +* DESCRIPTION +* The cl_async_proc_destroy function performs any necessary cleanup +* for a thread pool. +* +* SYNOPSIS +*/ +CL_EXPORT void CL_API +cl_async_proc_destroy( + IN cl_async_proc_t* const p_async_proc ); +/* +* PARAMETERS +* p_async_proc +* [in] Pointer to an asynchronous processor 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 asynchronous processor's threads. Because of +* its blocking nature, callers of cl_async_proc_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_async_proc_construct or cl_async_proc_init. +* +* SEE ALSO +* Asynchronous Processor, cl_async_proc_construct, cl_async_proc_init +*********/ + + +/****f* Component Library: Asynchronous Processor/cl_async_proc_queue +* NAME +* cl_async_proc_queue +* +* DESCRIPTION +* The cl_async_proc_queue function queues a callback to an asynchronous +* processor. +* +* SYNOPSIS +*/ +CL_EXPORT void CL_API +cl_async_proc_queue( + IN cl_async_proc_t* const p_async_proc, + IN cl_async_proc_item_t* const p_item ); +/* +* PARAMETERS +* p_async_proc +* [in] Pointer to an asynchronous processor structure to initialize. +* +* p_item +* [in] Pointer to an asynchronous processor item to queue for execution. +* The callback and context fields of the item must be valid. +* +* RETURN VALUES +* This function does not return a value. +* +* SEE ALSO +* Asynchronous Processor, cl_async_proc_init, cl_pfn_async_proc_cb_t +*********/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* !defined(_CL_ASYNC_PROC_H_) */ diff --git a/branches/WOF2-3/inc/complib/cl_atomic.h b/branches/WOF2-3/inc/complib/cl_atomic.h new file mode 100644 index 00000000..11cce604 --- /dev/null +++ b/branches/WOF2-3/inc/complib/cl_atomic.h @@ -0,0 +1,297 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * Abstract: + * Declaration of atomic manipulation functions. + * + * Environment: + * All + */ + + +#ifndef _CL_ATOMIC_H_ +#define _CL_ATOMIC_H_ + + +#include + + +/****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. +*********/ + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/****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 +*/ +CL_EXPORT int32_t CL_API +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 +*/ +CL_EXPORT int32_t CL_API +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 +*/ +CL_EXPORT int32_t CL_API +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 +*/ +CL_EXPORT int32_t CL_API +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 +*********/ + + +/****f* Component Library: Atomic Operations/cl_atomic_xchg +* NAME +* cl_atomic_xchg +* +* DESCRIPTION +* The cl_atomic_xchg function atomically sets a value of a +* 32-bit signed integer and returns the initial value. +* +* SYNOPSIS +*/ +CL_EXPORT int32_t CL_API +cl_atomic_xchg( + IN atomic32_t* const p_value, + IN const int32_t new_value ); +/* +* PARAMETERS +* p_value +* [in] Pointer to a 32-bit integer to exchange with new_value. +* +* new_value +* [in] Value to assign. +* +* RETURN VALUE +* Returns the initial value pointed to by p_value. +* +* NOTES +* The provided value is exchanged with new_value and its initial value +* returned in one atomic operation. +* +* cl_atomic_xchg 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_sub, cl_atomic_comp_xchg +*********/ + + +/****f* Component Library: Atomic Operations/cl_atomic_comp_xchg +* NAME +* cl_atomic_comp_xchg +* +* DESCRIPTION +* The cl_atomic_comp_xchg function atomically compares a 32-bit signed +* integer to a desired value, sets that integer to the +* specified value if equal, and returns the initial value. +* +* SYNOPSIS +*/ +CL_EXPORT int32_t CL_API +cl_atomic_comp_xchg( + IN atomic32_t* const p_value, + IN const int32_t compare, + IN const int32_t new_value ); +/* +* PARAMETERS +* p_value +* [in] Pointer to a 32-bit integer to exchange with new_value. +* +* compare +* [in] Value to compare to the value pointed to by p_value. +* +* new_value +* [in] Value to assign if the value pointed to by p_value is equal to +* the value specified by the compare parameter. +* +* RETURN VALUE +* Returns the initial value of the variable pointed to by p_value. +* +* NOTES +* The value pointed to by p_value is compared to the value specified by the +* compare parameter. If the two values are equal, the p_value variable is +* set to new_value. The initial value pointed to by p_value is returned. +* +* cl_atomic_comp_xchg 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_sub, cl_atomic_xchg +*********/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* _CL_ATOMIC_H_ */ diff --git a/branches/WOF2-3/inc/complib/cl_byteswap.h b/branches/WOF2-3/inc/complib/cl_byteswap.h new file mode 100644 index 00000000..60fd59ae --- /dev/null +++ b/branches/WOF2-3/inc/complib/cl_byteswap.h @@ -0,0 +1,539 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * Abstract: + * provides byteswapping utilities. Basic fuctions are obtained from platform + * specific implementations from ibyteswap_osd.h. + * + * Environment: + * All + */ + + +#ifndef _CL_BYTESWAP_H_ +#define _CL_BYTESWAP_H_ + + +#include +#include + + +/****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 ibyteswap_osd.h provides the following macros. + * __LITTLE_ENDIAN + * __BIG_ENDIAN + * __BYTE_ORDER + * + * If the platform provides byte swapping functions, ibyteswap_osd.h also + * provides the following macros. + * ntoh16, hton16 + * ntoh32, hton32 + * ntoh64, hton64 + */ + +#ifdef __cplusplus +extern "C" +{ +#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) & CL_CONST64(0x00000000000000FF)) << 56) | \ + (((uint64_t)(x) & CL_CONST64(0x000000000000FF00)) << 40) | \ + (((uint64_t)(x) & CL_CONST64(0x0000000000FF0000)) << 24) | \ + (((uint64_t)(x) & CL_CONST64(0x00000000FF000000)) << 8 ) | \ + (((uint64_t)(x) & CL_CONST64(0x000000FF00000000)) >> 8 ) | \ + (((uint64_t)(x) & CL_CONST64(0x0000FF0000000000)) >> 24) | \ + (((uint64_t)(x) & CL_CONST64(0x00FF000000000000)) >> 40) | \ + (((uint64_t)(x) & CL_CONST64(0xFF00000000000000)) >> 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 +*/ +CL_INLINE void CL_API +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 ) + cl_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 +*********/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* _CL_BYTESWAP_H_ */ diff --git a/branches/WOF2-3/inc/complib/cl_comppool.h b/branches/WOF2-3/inc/complib/cl_comppool.h new file mode 100644 index 00000000..19050918 --- /dev/null +++ b/branches/WOF2-3/inc/complib/cl_comppool.h @@ -0,0 +1,619 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * 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. + * + * Environment: + * All + */ + + +#ifndef _CL_COMP_POOL_H_ +#define _CL_COMP_POOL_H_ + + +#include + + +/****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_API *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_API *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 +*********/ + + + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + +/****f* Component Library: Composite Pool/cl_cpool_construct +* NAME +* cl_cpool_construct +* +* DESCRIPTION +* The cl_cpool_construct function constructs a composite pool. +* +* SYNOPSIS +*/ +CL_EXPORT void CL_API +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 +*/ +CL_INLINE boolean_t CL_API +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_EXPORT cl_status_t CL_API +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 +*/ +CL_INLINE void CL_API +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 +*/ +CL_INLINE size_t CL_API +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 +*/ +CL_INLINE void* CL_API +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->list_obj.p_object ); + return( (void*)p_pool_obj->list_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 +*/ +CL_INLINE void CL_API +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->list_obj.p_object == p_object ); + + cl_qcpool_put( &p_pool->qcpool, (cl_pool_item_t*)p_pool_obj ); +} +/* +* 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 +*/ +CL_INLINE cl_status_t CL_API +cl_cpool_grow( + IN cl_cpool_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_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 +*********/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + + +#endif /* _CL_COMP_POOL_H_ */ diff --git a/branches/WOF2-3/inc/complib/cl_debug.h b/branches/WOF2-3/inc/complib/cl_debug.h new file mode 100644 index 00000000..17a8fe7a --- /dev/null +++ b/branches/WOF2-3/inc/complib/cl_debug.h @@ -0,0 +1,599 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * Abstract: + * Declaration of functions for reporting debug output. + * + * Environment: + * All + */ + + +#ifndef _CL_DEBUG_H_ +#define _CL_DEBUG_H_ + + +#include + + +/****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. +*********/ + + +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifndef cl_dbg_out +#if defined( _DEBUG_ ) +/****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 +*/ +CL_EXPORT 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 +*********/ +#else +CL_INLINE void +cl_dbg_out( + IN const char* const debug_message, + IN ... ) +{ + UNUSED_PARAM( debug_message ); +} +#endif /* defined( _DEBUG_ ) */ +#endif /* !defined( cl_dbg_out ) */ + +#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 +*/ +CL_EXPORT 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 + +#ifdef __cplusplus +} /* extern "C" */ +#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 ) \ + do{ \ + if( DBG_LVL & CHK_LVL & CL_DBG_ERROR ) \ + cl_dbg_out STRING; \ + else if( (DBG_LVL & CHK_LVL) == DBG_LVL ) \ + cl_dbg_out STRING; \ + } while(CHK_LVL^CHK_LVL) + + +/****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 ) \ + do{ \ + CL_CHK_STK; \ + CL_PRINT( DBG_LVL, CHK_LVL, _CL_DBG_ENTER ); \ + } while(CHK_LVL^CHK_LVL) + + +/****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 ) \ +__pragma(warning(suppress:6326)) \ +do{ \ +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 ); \ +} while(CHK_LVL^CHK_LVL) + + +/****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 ) \ + __pragma(warning(suppress:6326)) \ + do{ \ + CL_TRACE( DBG_LVL, CHK_LVL, STRING ); \ + CL_EXIT( DBG_LVL, CHK_LVL ); \ + } while(CHK_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. +*********/ + + +#endif /* _CL_DEBUG_H_ */ diff --git a/branches/WOF2-3/inc/complib/cl_event.h b/branches/WOF2-3/inc/complib/cl_event.h new file mode 100644 index 00000000..8fed078f --- /dev/null +++ b/branches/WOF2-3/inc/complib/cl_event.h @@ -0,0 +1,304 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * Abstract: + * Declaration of event abstraction. + * + * Environment: + * All + */ + + +#ifndef _CL_EVENT_H_ +#define _CL_EVENT_H_ + + +/* Indicates that waiting on an event should never timeout */ +#define EVENT_NO_TIMEOUT 0xFFFFFFFF + + +#include + + +/****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 +*********/ + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/****f* Component Library: Event/cl_event_construct +* NAME +* cl_event_construct +* +* DESCRIPTION +* The cl_event_construct function constructs an event. +* +* SYNOPSIS +*/ +CL_EXPORT void CL_API +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_EXPORT cl_status_t CL_API +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 +*/ +CL_EXPORT void CL_API +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 one or more waiting threads. +* +* SYNOPSIS +*/ +CL_EXPORT cl_status_t CL_API +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_EXPORT cl_status_t CL_API +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_EXPORT cl_status_t CL_API +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 in 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 +*********/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* _CL_EVENT_H_ */ diff --git a/branches/WOF2-3/inc/complib/cl_fleximap.h b/branches/WOF2-3/inc/complib/cl_fleximap.h new file mode 100644 index 00000000..ff3dab54 --- /dev/null +++ b/branches/WOF2-3/inc/complib/cl_fleximap.h @@ -0,0 +1,992 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +/* + * Abstract: + * Declaration of flexi map, a binary tree where the caller always provides + * all necessary storage. + */ + +#ifndef _CL_FLEXIMAP_H_ +#define _CL_FLEXIMAP_H_ + +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS + +/****h* Component Library/Flexi Map +* NAME +* Flexi Map +* +* DESCRIPTION +* Flexi map implements a binary tree that stores user provided cl_fmap_item_t +* structures. Each item stored in a flexi map has a unique user defined +* key (duplicates are not allowed). Flexi map provides the ability to +* efficiently search for an item given a key. Flexi map allows user +* defined keys of any size. Storage for keys and a comparison function +* are provided by users to allow flexi map to store items with arbitrary +* key values. +* +* Flexi map does not allocate any memory, and can therefore not fail +* any operations due to insufficient memory. Flexi map can thus be useful +* in minimizing the error paths in code. +* +* Flexi map is not thread safe, and users must provide serialization when +* adding and removing items from the map. +* +* The flexi map functions operate on a cl_fmap_t structure which should +* be treated as opaque and should be manipulated only through the provided +* functions. +* +* SEE ALSO +* Structures: +* cl_fmap_t, cl_fmap_item_t +* +* Callbacks: +* cl_pfn_fmap_apply_t +* +* Item Manipulation: +* cl_fmap_key +* +* Initialization: +* cl_fmap_init +* +* Iteration: +* cl_fmap_end, cl_fmap_head, cl_fmap_tail, cl_fmap_next, cl_fmap_prev +* +* Manipulation: +* cl_fmap_insert, cl_fmap_get, cl_fmap_remove_item, cl_fmap_remove, +* cl_fmap_remove_all, cl_fmap_merge, cl_fmap_delta, cl_fmap_get_next +* +* Search: +* cl_fmap_apply_func +* +* Attributes: +* cl_fmap_count, cl_is_fmap_empty, +*********/ + +/****s* Component Library: Flexi Map/cl_fmap_item_t +* NAME +* cl_fmap_item_t +* +* DESCRIPTION +* The cl_fmap_item_t structure is used by maps to store objects. +* +* The cl_fmap_item_t structure should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _cl_fmap_item +{ + /* Must be first to allow casting. */ + cl_pool_item_t pool_item; + struct _cl_fmap_item *p_left; + struct _cl_fmap_item *p_right; + struct _cl_fmap_item *p_up; + cl_map_color_t color; + const void* p_key; +#ifdef _DEBUG_ + struct _cl_fmap *p_map; +#endif + +} cl_fmap_item_t; +/* +* FIELDS +* pool_item +* Used to store the item in a doubly linked list, allowing more +* efficient map traversal. +* +* p_left +* Pointer to the map item that is a child to the left of the node. +* +* p_right +* Pointer to the map item that is a child to the right of the node. +* +* p_up +* Pointer to the map item that is the parent of the node. +* +* p_nil +* Pointer to the map's NIL item, used as a terminator for leaves. +* The NIL sentinel is in the cl_fmap_t structure. +* +* color +* Indicates whether a node is red or black in the map. +* +* p_key +* Pointer to the value that uniquely represents a node in a map. This +* pointer is set by calling cl_fmap_insert and can be retrieved by +* calling cl_fmap_key. +* +* NOTES +* None of the fields of this structure should be manipulated by users, as +* they are crititcal to the proper operation of the map in which they +* are stored. +* +* To allow storing items in either a quick list, a quick pool, or a flexi +* map, the map implementation guarantees that the map item can be safely +* cast to a pool item used for storing an object in a quick pool, or cast to +* a list item used for storing an object in a quick list. This removes the +* need to embed a flexi map item, a list item, and a pool item in objects +* that need to be stored in a quick list, a quick pool, and a flexi map. +* +* The flexi map item is defined to be identical in layout as a map item. +* +* 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 int +(CL_API *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_API *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 +*/ +CL_INLINE size_t CL_API +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 +*/ +CL_INLINE boolean_t CL_API +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 +*/ +#pragma warning (push) +#pragma warning (disable :4244) +CL_INLINE const void* CL_API +cl_fmap_key( + IN const cl_fmap_item_t* const p_item ) +{ + CL_ASSERT( p_item ); + return( p_item->p_key ); +} +#pragma warning (pop ) +/* +* 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 +*/ +CL_EXPORT void CL_API +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 +*/ +CL_INLINE const cl_fmap_item_t* const CL_API +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 +*/ +CL_INLINE cl_fmap_item_t* CL_API +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 +*/ +CL_INLINE cl_fmap_item_t* CL_API +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 +*/ +CL_INLINE cl_fmap_item_t* CL_API +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 +*/ +CL_INLINE cl_fmap_item_t* CL_API +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_EXPORT cl_fmap_item_t* CL_API +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_match +* NAME +* cl_fmap_match +* +* DESCRIPTION +* The cl_fmap_match function returns the map item matching a key. +* +* SYNOPSIS +*/ +CL_EXPORT cl_fmap_item_t* CL_API +cl_fmap_match( + IN const cl_fmap_t * const p_map, + IN const void *const p_key, + IN cl_pfn_fmap_cmp_t pfn_compare ); +/* +* 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. +* +* pfn_compare +* [in] Pointer to a compare function to invoke to compare the +* keys of items in the map. Passing NULL here makes such call +* to be equivalent to using cl_fmap_get(). +* +* RETURN VALUES +* Pointer to the map item matching the desired key value. +* +* Pointer to the map end if there was no item matching the desired key +* value stored in the flexi map. +* +* SEE ALSO +* Flexi Map, cl_fmap_remove, cl_fmap_get +*********/ + +/****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_EXPORT cl_fmap_item_t* CL_API +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_EXPORT cl_fmap_item_t* CL_API +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 +*/ +CL_EXPORT void CL_API +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 +* is 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_EXPORT cl_fmap_item_t* CL_API +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 +*/ +CL_INLINE void CL_API +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 +*/ +CL_EXPORT void CL_API +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 +*/ +CL_EXPORT void CL_API +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 +*/ +CL_EXPORT void CL_API +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/branches/WOF2-3/inc/complib/cl_ioctl.h b/branches/WOF2-3/inc/complib/cl_ioctl.h new file mode 100644 index 00000000..93998a48 --- /dev/null +++ b/branches/WOF2-3/inc/complib/cl_ioctl.h @@ -0,0 +1,626 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * Abstract: + * Declaration of IOCTL object + * + * Environment: + * All + */ + + +#ifndef _CL_IOCTL_H_ +#define _CL_IOCTL_H_ + + +#include +#include + + +/****h* Component Library/IOCTL Object +* NAME +* IOCTL Object +* +* DESCRIPTION +* The IOCTL object provides functionality for handling IOCTL requests. +* +* The IOCTL object is only available in kernel mode and provides +* functionality for accessing information about IO requests initiated +* by a user-mode application. The IOCTL_CODE macro is used in both +* user and kernel mode to initiate and dispatch IOCTL requests, respectively. +* +* In Linux, in order for the IOCTL object to be used, requests must be +* initiated and handled using the Device Framework abstraction. +* +* SEE ALSO +* Structures: +* cl_ioctl_handle_t +* +* Callbacks: +* cl_pfn_ioctl_handler_t +* +* Control Code Generation +* IOCTL_CODE +* +* Kernel Mode Access +* cl_ioctl_process +* cl_ioctl_complete +* cl_ioctl_type +* cl_ioctl_cmd +* cl_ioctl_ctl_code +* cl_ioctl_in_buf +* cl_ioctl_in_size +* cl_ioctl_out_buf +* cl_ioctl_out_size +* +* User Mode Access +* cl_ioctl_request +* cl_ioctl_result +*********/ + + +/****d* Component Library: IOCTL Object/IOCTL_CODE +* NAME +* IOCTL_CODE +* +* DESCRIPTION +* Macro for defining IO control command codes. +* +* SYNOPSIS +* uint32_t IOCTL_CODE( uint16_t type, uint16_t cmd ) +* +* PARAMETERS +* type +* [in] user-defined type representing the type of command. For Linux, +* the type is truncated to 8-bits. For Windows, the type is a 16-bit +* value, as described in "Specifying Device Types" in the DDK docs. +* +* cmd +* [in] User-defined command. For Linux, the command field is truncated +* to 8-bits. For Windows, the command can be 12-bits, with values +* below 0x800 reserved by Microsoft for system defined commands. +* +* RETURN VALUE +* A 32-bit control code. User-mode clients use the control code to initiate +* requests. Kernel-mode clients use the control code to distinguish between +* different requests. +* +* NOTE +* In Windows, all IOCTL command codes defined with the IOCTL_CODE command +* result in FILE_ANY_ACCESS and METHOD_BUFFERED being specified. +* +* SEE ALSO +* IOCTL Object, cl_dev_ioctl, cl_ioctl_type, cl_ioctl_cmd +*********/ + + +#ifdef CL_KERNEL + +/****d* Component Library: IOCTL Object/cl_ioctl_handle_t +* NAME +* cl_ioctl_handle_t +* +* DESCRIPTION +* Opaque handle representing an IO request. +* +* NOTES +* The cl_ioctl_handle_t type is only available in the kernel. +* The cl_ioctl_handle_t type should be treated as opaque, as it +* varies from environment to environment. +* +* SEE ALSO +* IOCTL Object, cl_ioctl_type, cl_ioctl_cmd, cl_ioctl_in_buf, +* cl_ioctl_in_size, cl_ioctl_out_buf, cl_ioctl_out_size, +* cl_ioctl_set_status, cl_ioctl_set_ret_bytes +*********/ + + +/****d* Component Library: IOCTL Object/cl_pfn_ioctl_handler_t +* NAME +* cl_pfn_ioctl_handler_t +* +* DESCRIPTION +* The cl_pfn_ioctl_handler_t function type defines the prototype for +* IOCTL handlers used when handling IOCTL requests initiated by +* cl_ioctl_request. +* +* SYNOPSIS +*/ +typedef cl_status_t +(CL_API *cl_pfn_ioctl_handler_t)( + IN cl_ioctl_handle_t h_ioctl, + IN void *context_1, + IN void *context_2 ); +/* +* PARAMETERS +* h_ioctl +* [in] Handle to the IOCTL request. +* +* context_1 +* [in] First context parameters, as provided to cl_ioctl_process. +* +* context_2 +* [in] Second context parameters, as provided to cl_ioctl_process. +* +* RETURN VALUES +* CL_SUCCESS if the IOCTL was completed successfully. +* +* CL_PENDING if the IOCTL is being processed asynchronously. +* +* Other return values in case of errors. +* +* NOTES +* It is acceptable to complete the IOCTL successfully to report an error +* status in the output buffer. +* +* SEE ALSO +* IOCTL Object, cl_ioctl_handle_t, cl_ioctl_process +*********/ + + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + +/****f* Component Library: IOCTL Object/cl_ioctl_process +* NAME +* cl_ioctl_process +* +* DESCRIPTION +* The cl_ioctl_process function unpacks information initiated by a call to +* cl_ioctl_request function and invokes a user-supplied callback. +* +* SYNOPSIS +*/ +CL_EXPORT cl_status_t CL_API +cl_ioctl_process( + IN void *p_ioctl, + IN cl_pfn_ioctl_handler_t pfn_ioctl_handler, + IN void *context_1, + IN void *context_2 ); +/* +* PARAMETERS +* p_ioctl +* [in] Pointer to an OS specific IOCTL information. In Linux, +* this parameter depends on whether the IOCTL is handled synchronously +* or asynchronously. See the notes for further detail. +* In Windows, this is a pointer to an IRP. +* +* pfn_ioctl_handler +* [in] Pointer to the callback function to invoke for handling the IOCTL. +* This callback is independent of the IOCTL command. +* +* context_1 +* [in] First of two context parameters to pass to the handler. +* +* context_2 +* [in] Second of two context parameters to pass to the handler. +* +* RETURN VALUES +* CL_SUCCESS if the IOCTL was processed successfully. +* +* Other values to indicate various failures. +* +* NOTES +* Users must call cl_ioctl_complete from within the handler if completing +* the IOCTL request synchronously. If the IOCTL request's control code is +* invalid, the handler should return CL_INVALID_REQUEST. +* +* In Linux, the p_ioctl parameter is a copy of the argp parameter on input, +* and on output points to the IOCTL request object passed to the IOCTL +* handler if and only if the IOCTL handler returned CL_PENDING. +* This allows the user to cancel the request by passing the same +* handle to the cancel routine that was passed to the IOCTL handler. +* If all IOCTLs are handled synchronously, it is acceptable to pass the argp +* parameter of the IOCTL entry point instead of a copy. +* +* SEE ALSO +* IOCTL Object, cl_ioctl_handle_t, cl_pfn_ioctl_handler_t, cl_ioctl_complete +*********/ + + +/****f* Component Library: IOCTL Object/cl_ioctl_complete +* NAME +* cl_ioctl_complete +* +* DESCRIPTION +* Fills in completion information for an IOCTL and releases the IOCTL request +* for completion. +* +* SYNOPSIS +*/ +CL_EXPORT void CL_API +cl_ioctl_complete( + IN cl_ioctl_handle_t h_ioctl, + IN cl_status_t io_status, + IN size_t ret_bytes ); +/* +* PARAMETERS +* h_ioctl +* Handle to the IOCTL being completed. This handle was provided to +* the IOCTL handler. +* +* io_status +* Status of the IOCTL request. +* +* ret_bytes +* Number of bytes written to the output buffer. +* +* RETURN VALUES +* This function does not return a value. +* +* SEE ALSO +* IOCTL Object, cl_ioctl_handle_t, cl_ioctl_process +*********/ + + +/****f* Component Library: IOCTL Object/cl_ioctl_type +* NAME +* cl_ioctl_type +* +* DESCRIPTION +* Returns the type of an IOCTL. +* +* SYNOPSIS +*/ +CL_EXPORT uint16_t CL_API +cl_ioctl_type( + IN cl_ioctl_handle_t h_ioctl ); +/* +* PARAMETERS +* h_ioctl +* [in] Handle to an IOCTL +* +* RETURN VALUE +* Returns the type of the specified IOCTL request, as defined using +* the IOCTL_CMD macro. +* +* NOTES +* The cl_ioctl_type function is only available in the kernel. +* +* SEE ALSO +* IOCTL Object, cl_ioctl_handle_t, cl_ioctl_cmd, cl_ioctl_ctl_code +********/ + + +/****f* Component Library: IOCTL Object/cl_ioctl_cmd +* NAME +* cl_ioctl_cmd +* +* DESCRIPTION +* Returns the command of an IOCTL +* +* SYNOPSIS +*/ +CL_EXPORT uint16_t CL_API +cl_ioctl_cmd( + IN cl_ioctl_handle_t h_ioctl ); +/* +* PARAMETERS +* h_ioctl +* [in] Handle to an IOCTL +* +* RETURN VALUE +* Returns the command of the specified IOCTL request, as defined using +* the IOCTL_CMD macro. +* +* NOTES +* The cl_ioctl_cmd function is only available in the kernel. +* +* SEE ALSO +* IOCTL Object, cl_ioctl_handle_t, cl_ioctl_type, cl_ioctl_ctl_code +********/ + + +/****f* Component Library: IOCTL Object/cl_ioctl_ctl_code +* NAME +* cl_ioctl_ctl_code +* +* DESCRIPTION +* Returns the 32-bit control code of an IOCTL +* +* SYNOPSIS +*/ +CL_EXPORT uint32_t CL_API +cl_ioctl_ctl_code( + IN cl_ioctl_handle_t h_ioctl ); +/* +* PARAMETERS +* h_ioctl +* [in] Handle to an IOCTL +* +* RETURN VALUE +* Returns the 32-bit control code of the specified IOCTL request, +* as defined using the IOCTL_CMD macro. +* +* NOTES +* The cl_ioctl_ctl_code function is only available in the kernel. +* +* SEE ALSO +* IOCTL Object, cl_ioctl_handle_t, cl_ioctl_type, cl_ioctl_cmd +********/ + + +/****f* Component Library: IOCTL Object/cl_ioctl_in_buf +* NAME +* cl_ioctl_in_buf +* +* DESCRIPTION +* Returns a pointer to the input buffer of an IOCTL. +* +* SYNOPSIS +*/ +CL_EXPORT void* CL_API +cl_ioctl_in_buf( + IN cl_ioctl_handle_t h_ioctl ); +/* +* PARAMETERS +* h_ioctl +* [in] Handle to an IOCTL +* +* RETURN VALUE +* Returns the input buffer of the specified IOCTL request. +* +* NOTES +* The cl_ioctl_in_buf function is only available in the kernel. +* +* In Windows, for IOCTL operations defined as METHOD_IN_DIRECT, the +* returned pointer points to the MDL describing the input buffer. +* +* SEE ALSO +* IOCTL Object, cl_ioctl_handle_t, cl_ioctl_in_size, +* cl_ioctl_out_buf, cl_ioctl_out_size +********/ + + +/****f* Component Library: IOCTL Object/cl_ioctl_in_size +* NAME +* cl_ioctl_in_size +* +* DESCRIPTION +* Returns the size of the input buffer of an IOCTL. +* +* SYNOPSIS +*/ +CL_EXPORT ULONG CL_API +cl_ioctl_in_size( + IN cl_ioctl_handle_t h_ioctl ); +/* +* PARAMETERS +* h_ioctl +* [in] Handle to an IOCTL +* +* RETURN VALUE +* Returns the size, in bytes, of the input buffer of the specified +* IOCTL request. +* +* NOTES +* The cl_ioctl_in_size function is only available in the kernel. +* +* SEE ALSO +* IOCTL Object, cl_ioctl_handle_t, cl_ioctl_in_buf, +* cl_ioctl_out_buf, cl_ioctl_out_size +********/ + + +/****f* Component Library: IOCTL Object/cl_ioctl_out_buf +* NAME +* cl_ioctl_out_buf +* +* DESCRIPTION +* Returns a pointer to the output buffer of an IOCTL. +* +* SYNOPSIS +*/ +CL_EXPORT void* CL_API +cl_ioctl_out_buf( + IN cl_ioctl_handle_t h_ioctl ); +/* +* PARAMETERS +* h_ioctl +* [in] Handle to an IOCTL +* +* RETURN VALUE +* Returns a pointer to the output buffer of the specified IOCTL request. +* +* NOTES +* The cl_ioctl_out_buf function is only available in the kernel. +* +* In Windows, for IOCTL operations defined as METHOD_IN_DIRECT or +* METHOD_OUT_DIRECT, the returned pointer points to the MDL describing +* the input buffer. +* +* SEE ALSO +* IOCTL Object, cl_ioctl_handle_t, cl_ioctl_out_size, +* cl_ioctl_in_buf, cl_ioctl_in_size +********/ + + +/****f* Component Library: IOCTL Object/cl_ioctl_out_size +* NAME +* cl_ioctl_out_size +* +* DESCRIPTION +* Returns the size of the output buffer of an IOCTL. +* +* SYNOPSIS +*/ +CL_EXPORT ULONG CL_API +cl_ioctl_out_size( + IN cl_ioctl_handle_t h_ioctl ); +/* +* PARAMETERS +* h_ioctl +* [in] Handle to an IOCTL +* +* RETURN VALUE +* Returns the size, in bytes, of the input buffer of the specified +* IOCTL request. +* +* NOTES +* The cl_ioctl_out_size function is only available in the kernel. +* +* SEE ALSO +* IOCTL Object, cl_ioctl_handle_t, cl_ioctl_out_buf, +* cl_ioctl_in_buf, cl_ioctl_in_size +********/ + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#else /* CL_KERNEL */ + + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + +/****f* Component Library: IOCTL Object/cl_ioctl_request +* NAME +* cl_ioctl_request +* +* DESCRIPTION +* The cl_ioctl_request is used by user-mode clients to initiate IOCTL +* requests to a device. +* +* SYNOPSIS +*/ +CL_EXPORT cl_status_t CL_API +cl_ioctl_request( + IN void *h_dev, + IN uint32_t ioctl_code, + IN void *p_in_buf, + IN size_t in_size, + OUT void *p_out_buf, + IN size_t out_size, + OUT size_t *p_ret_bytes OPTIONAL, + IN void *p_async_info OPTIONAL ); +/* +* PARAMETERS +* h_dev +* [in] Handle to the device to which the IOCTL request is targetted. +* In Linux, this is a file descriptor. In Windows, this is a file +* handle. +* +* ioctl_code +* [in] Control code for the IOCTL request. +* +* p_in_buf +* [in] Pointer to the input buffer. +* +* in_size +* [in] Size, in bytes, of the input buffer. +* +* p_out_buf +* [out] Pointer to the output buffer. +* +* out_size +* [in] Size, in bytes, of the output buffer. +* +* p_ret_bytes +* [out] Number of bytes written to the output buffer. This parameter is +* mutually exclusive of the p_async_info parameter. +* +* p_async_info +* [in] For platforms that support asynchronous I/O, supplies a pointer +* to that platform's async I/O structure, if any. For Windows, this +* is a pointer to an OVERLAPPED structure. This parameter is mutually +* exclusive of the p_ret_bytes parameter. +* +* SEE ALSO +* IOCTL Object, cl_ioctl_result +*********/ + + +/****f* Component Library: IOCTL Object/cl_ioctl_result +* NAME +* cl_ioctl_result +* +* DESCRIPTION +* Checks the status of an asynchronous IOCTL request. +* +* SYNOPSIS +*/ +CL_EXPORT cl_status_t CL_API +cl_ioctl_result( + IN void *h_dev, + IN void *p_async_info, + OUT size_t *p_ret_bytes, + IN boolean_t blocking ); +/* +* PARAMETERS +* h_dev +* [in] Handle to the device to which the IOCTL request is targetted. +* In Linux, this is a file descriptor. In Windows, this is a file +* handle. +* +* p_async_info +* [in] For platforms that support asynchronous I/O, supplies a pointer +* to that platform's async I/O structure, if any. For Windows, this +* is a pointer to an OVERLAPPED structure. This must be the same +* as that provided in the cl_ioctl_request function. +* +* p_ret_bytes +* [out] Number of bytes written to the output buffer. +* +* blocking +* [in] If TRUE, indicates that the call should wait until the +* specified IOCTL request is complete. +* +* RETURN VALUES +* CL_SUCCESS if the IOCTL request was successful. p_ret_bytes contains +* the number bytes written to the output buffer. +* +* CL_PENDING if the IOCTL request is not yet complete. +* +* Other status values to indicate errors. +* +* SEE ALSO +* IOCTL Object, cl_ioctl_request +*********/ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* CL_KERNEL */ + +#endif /* _CL_IOCTL_H_ */ diff --git a/branches/WOF2-3/inc/complib/cl_irqlock.h b/branches/WOF2-3/inc/complib/cl_irqlock.h new file mode 100644 index 00000000..ea139e69 --- /dev/null +++ b/branches/WOF2-3/inc/complib/cl_irqlock.h @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * Abstract: + * Declaration of interrupt level IRQ lock object. + * + * Environment: + * All + */ + + +#ifndef _CL_IRQLOCK_H_ +#define _CL_IRQLOCK_H_ + + +#include + + +/****h* Component Library/Irqlock +* NAME +* Irqlock +* +* DESCRIPTION +* Irqlock provides synchronization at interrupt level between threads for +* exclusive access to a resource. +* +* The irqlock functions manipulate a cl_irqlock_t structure which should +* be treated as opaque and should be manipulated only through the provided +* functions. +* +* SEE ALSO +* Structures: +* cl_irqlock_t +* +* Initialization: +* cl_irqlock_construct, cl_irqlock_init, cl_irqlock_destroy +* +* Manipulation +* cl_irqlock_acquire, cl_irqlock_release +*********/ + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/****f* Component Library: Irqlock/cl_irqlock_construct +* NAME +* cl_irqlock_construct +* +* DESCRIPTION +* The cl_irqlock_construct function initializes the state of a +* IRQ lock. +* +* SYNOPSIS +*/ +CL_EXPORT void CL_API +cl_irqlock_construct( + IN cl_irqlock_t* const p_irqlock ); +/* +* PARAMETERS +* p_irqlock +* [in] Pointer to a IRQ lock structure whose state to initialize. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling cl_irqlock_destroy without first calling +* cl_irqlock_init. +* +* Calling cl_irqlock_construct is a prerequisite to calling any other +* IRQ lock function except cl_irqlock_init. +* +* SEE ALSO +* Irqlock, cl_irqlock_init, cl_irqlock_destroy +*********/ + + +/****f* Component Library: Irqlock/cl_irqlock_init +* NAME +* cl_irqlock_init +* +* DESCRIPTION +* The cl_irqlock_init function initializes a IRQ lock for use. +* +* SYNOPSIS +*/ +CL_EXPORT cl_status_t CL_API +cl_irqlock_init( + IN cl_irqlock_t* const p_irqlock, + IN cl_interrupt_t* const p_interrupt ); +/* +* PARAMETERS +* p_irqlock +* [in] Pointer to a IRQ lock structure to initialize. +* +* p_interrupt +* [in] Platform specific pointer conveying information about the +* interrupt vector and level with which to synchronize. +* +* RETURN VALUES +* CL_SUCCESS if initialization succeeded. +* +* CL_ERROR if initialization failed. Callers should call +* cl_irqlock_destroy to clean up any resources allocated during +* initialization. +* +* NOTES +* Initialize the IRQ lock structure. Allows calling cl_irqlock_aquire +* and cl_irqlock_release. +* +* In Linux, the p_interrupt parameter is currently ignored. +* +* In Windows, the p_interrupt parameter is a pointer to a KINTERRUPT object, +* the value of which is supplied by a call to IoConnectInterrupt. +* +* SEE ALSO +* Irqlock, cl_irqlock_construct, cl_irqlock_destroy, +* cl_irqlock_acquire, cl_irqlock_release +*********/ + + +/****f* Component Library: Irqlock/cl_irqlock_destroy +* NAME +* cl_irqlock_destroy +* +* DESCRIPTION +* The cl_irqlock_destroy function performs all necessary cleanup of a +* IRQ lock. +* +* SYNOPSIS +*/ +CL_EXPORT void CL_API +cl_irqlock_destroy( + IN cl_irqlock_t* const p_irqlock ); +/* +* PARAMETERS +* p_irqlock +* [in] Pointer to a IRQ lock structure to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of a IRQ lock. This function must only +* be called if either cl_irqlock_construct or cl_irqlock_init has been +* called. +* +* SEE ALSO +* Irqlock, cl_irqlock_construct, cl_irqlock_init +*********/ + + +/****f* Component Library: Irqlock/cl_irqlock_acquire +* NAME +* cl_irqlock_acquire +* +* DESCRIPTION +* The cl_irqlock_acquire function acquires a IRQ 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_irqlock_acquire_irq function. +* +* SYNOPSIS +*/ +CL_EXPORT void CL_API +cl_irqlock_acquire( + IN cl_irqlock_t* const p_irqlock ); +/* +* PARAMETERS +* p_irqlock +* [in] Pointer to a IRQ lock structure to acquire. +* +* RETURN VALUE +* This function does not return a value. +* +* SEE ALSO +* Irqlock, cl_irqlock_release +*********/ + + +/****f* Component Library: Irqlock/cl_irqlock_release +* NAME +* cl_irqlock_release +* +* DESCRIPTION +* The cl_irqlock_release function releases a IRQ lock object. +* +* SYNOPSIS +*/ +CL_EXPORT void CL_API +cl_irqlock_release( + IN cl_irqlock_t* const p_irqlock ); +/* +* PARAMETERS +* p_irqlock +* [in] Pointer to a IRQ lock structure to release. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Releases a IRQ lock after a call to cl_irqlock_acquire. +* +* SEE ALSO +* Irqlock, cl_irqlock_acquire +*********/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* _CL_IRQLOCK_H_ */ diff --git a/branches/WOF2-3/inc/complib/cl_list.h b/branches/WOF2-3/inc/complib/cl_list.h new file mode 100644 index 00000000..c05dcdef --- /dev/null +++ b/branches/WOF2-3/inc/complib/cl_list.h @@ -0,0 +1,1364 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * Abstract: + * Declaration of list. + * + * Environment: + * All + */ + + +#ifndef _CL_LIST_H_ +#define _CL_LIST_H_ + + +#include +#include + + +/****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_API *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_API *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 +*********/ + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/****f* Component Library: List/cl_list_construct +* NAME +* cl_list_construct +* +* DESCRIPTION +* The cl_list_construct function constructs a list. +* +* SYNOPSIS +*/ +CL_EXPORT void CL_API +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 +*/ +CL_INLINE boolean_t CL_API +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_EXPORT cl_status_t CL_API +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 +*/ +CL_EXPORT void CL_API +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 +*/ +CL_INLINE boolean_t CL_API +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 +*/ +CL_INLINE cl_status_t CL_API +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->list_obj.p_object = p_object; + cl_qlist_insert_head( &p_list->list, &p_pool_obj->list_obj.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 head of a list. +* +* SYNOPSIS +*/ +CL_INLINE cl_status_t CL_API +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->list_obj.p_object = p_object; + cl_qlist_insert_tail( &p_list->list, &p_pool_obj->list_obj.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_EXPORT cl_status_t CL_API +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_EXPORT cl_status_t CL_API +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 +*/ +CL_INLINE cl_status_t CL_API +cl_list_insert_next( + IN cl_list_t* const p_list, + IN const 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->list_obj.p_object = p_object; + cl_qlist_insert_next( &p_list->list, (cl_list_item_t*)iterator, + &p_pool_obj->list_obj.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 +*/ +CL_INLINE cl_status_t CL_API +cl_list_insert_prev( + IN cl_list_t* const p_list, + IN const 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->list_obj.p_object = p_object; + cl_qlist_insert_prev( &p_list->list, (cl_list_item_t*)iterator, + &p_pool_obj->list_obj.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 +*/ +CL_INLINE void* CL_API +cl_list_remove_head( + 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_head( &p_list->list ); + + /* Place the pool item back into the pool. */ + cl_qpool_put( &p_list->list_item_pool, (cl_pool_item_t*)p_pool_obj ); + + return( (void*)p_pool_obj->list_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 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 +*/ +CL_INLINE void* CL_API +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, (cl_pool_item_t*)p_pool_obj ); + + return( (void*)p_pool_obj->list_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 +*/ +CL_INLINE void CL_API +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_EXPORT cl_status_t CL_API +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 +*/ +CL_INLINE void CL_API +cl_list_remove_item( + IN cl_list_t* const p_list, + IN const 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 +*/ +CL_EXPORT boolean_t CL_API +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 +*/ +CL_INLINE const cl_list_iterator_t CL_API +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 +*/ +CL_INLINE const cl_list_iterator_t CL_API +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 +*/ +CL_INLINE const cl_list_iterator_t CL_API +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 +*/ +CL_INLINE const cl_list_iterator_t CL_API +cl_list_next( + IN const 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 +*/ +CL_INLINE const cl_list_iterator_t CL_API +cl_list_prev( + IN const 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 +*/ +CL_INLINE void* CL_API +cl_list_obj( + IN const cl_list_iterator_t iterator ) +{ + CL_ASSERT( iterator ); + + return( (void*)((cl_pool_obj_t*)iterator)->list_obj.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_EXPORT const cl_list_iterator_t CL_API +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, +* 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_EXPORT const cl_list_iterator_t CL_API +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, +* 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 +*/ +CL_EXPORT void CL_API +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 +*/ +CL_INLINE size_t CL_API +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 +*********/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* _CL_LIST_H_ */ diff --git a/branches/WOF2-3/inc/complib/cl_log.h b/branches/WOF2-3/inc/complib/cl_log.h new file mode 100644 index 00000000..1563cbe7 --- /dev/null +++ b/branches/WOF2-3/inc/complib/cl_log.h @@ -0,0 +1,245 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * Abstract: + * Declaration of logging mechanisms. + * + * Environment: + * All + */ + + +#ifndef _CL_LOG_H_ +#define _CL_LOG_H_ + +#include + + +/****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 +*********/ + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/****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 +*/ +CL_EXPORT void CL_API +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 +*********/ + + +/****f* Component Library: Debug Output/cl_msg_out +* NAME +* cl_event_log_write +* +* DESCRIPTION +* The cl_event_log_write function sends a message to System Event Logger. +* +* SYNOPSIS +*/ +CL_EXPORT void +cl_event_log_write( + PVOID p_io_object, + ULONG p_error_code, + ULONG p_unique_error_code, + ULONG p_final_status, + PWCHAR p_insertion_string, + ULONG p_n_data_items, + ... + ); +/* +* PARAMETERS +* p_io_object +* [in] The IO object ( driver object or device object ). +* +* p_error_code +* [in] The error code. +* +* p_unique_error_code +* [in] A specific error code. +* +* p_final_status +* [in] The final status. +* +* p_insertion_string +* [in] String to print. +* +* p_n_data_items +* [in] Number of data items +* +* ... +* [in] data items values +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* cl_event_log_write is available in both debug and release builds. +* +* The function uses IoAllocateErrorLogEntry and IoWriteErrorLogEntry +* functions to send data to System Event Log. +* +* SEE ALSO +* +*********/ + +#ifdef __cplusplus +} +#endif + +#ifdef CL_KERNEL +#include +#define NTSTRSAFE_LIB +#include + +#define CL_LOG_BUF_LEN 512 +extern WCHAR g_cl_wlog[ CL_LOG_BUF_LEN ]; +extern UCHAR g_cl_slog[ CL_LOG_BUF_LEN ]; + +static void __build_str( const char * format, ... ) +{ + NTSTATUS status; + va_list p_arg; + va_start(p_arg, format); + status = RtlStringCbVPrintfA((char *)g_cl_slog, sizeof(g_cl_slog), format , p_arg); + if (status) + goto end; + status = RtlStringCchPrintfW(g_cl_wlog, sizeof(g_cl_wlog)/sizeof(g_cl_wlog[0]), L"%S", g_cl_slog); + if (status) + goto end; +end: + va_end(p_arg); +} + +#define CL_PRINT_TO_EVENT_LOG(_obj_,_event_id_,_msg_) \ + if (_obj_) \ + { \ + NTSTATUS event_id = _event_id_; \ + __build_str _msg_; \ + cl_event_log_write( _obj_, (ULONG)event_id, 0, 0, g_cl_wlog, 0, 0 ); \ + } +#else + +#define CL_PRINT_TO_EVENT_LOG(_obj_,_event_id_,_msg_) + +#endif + +#endif /* _CL_LOG_H_ */ diff --git a/branches/WOF2-3/inc/complib/cl_map.h b/branches/WOF2-3/inc/complib/cl_map.h new file mode 100644 index 00000000..d7732988 --- /dev/null +++ b/branches/WOF2-3/inc/complib/cl_map.h @@ -0,0 +1,875 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * Abstract: + * Declaration of map, a binary tree. + * + * Environment: + * All + */ + + +#ifndef _CL_MAP_H_ +#define _CL_MAP_H_ + + +#include +#include + + +/****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 +* +* 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 +*********/ + + +#ifdef __cplusplus +extern "C" { +#endif + + +/****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 +*/ +CL_INLINE size_t CL_API +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 +*/ +CL_INLINE boolean_t CL_API +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 +*/ +CL_INLINE uint64_t CL_API +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 +*/ +CL_EXPORT void CL_API +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 +*/ +CL_INLINE boolean_t CL_API +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_EXPORT cl_status_t CL_API +cl_map_init( + IN cl_map_t* const p_map, + IN const size_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 +*/ +CL_EXPORT void CL_API +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 +*/ +CL_INLINE const cl_map_iterator_t CL_API +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 +*/ +CL_INLINE cl_map_iterator_t CL_API +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 +*/ +CL_INLINE cl_map_iterator_t CL_API +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 +*/ +CL_INLINE cl_map_iterator_t CL_API +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 +*/ +CL_INLINE cl_map_iterator_t CL_API +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 +*/ +CL_EXPORT void* CL_API +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 +*/ +CL_EXPORT void* CL_API +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 +*********/ + + +/****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 +*/ +CL_EXPORT void CL_API +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 +*/ +CL_EXPORT void* CL_API +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 +*/ +CL_EXPORT void CL_API +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 +*/ +CL_INLINE void* CL_API +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_EXPORT cl_status_t CL_API +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_EXPORT cl_status_t CL_API +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 usefull 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 +*********/ + + +#ifdef __cplusplus +} +#endif + +#endif /* _CL_MAP_H_ */ diff --git a/branches/WOF2-3/inc/complib/cl_math.h b/branches/WOF2-3/inc/complib/cl_math.h new file mode 100644 index 00000000..8e8af960 --- /dev/null +++ b/branches/WOF2-3/inc/complib/cl_math.h @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * Abstract: + * Defines standard math related macros and functions. + * + * Environment: + * All + */ + + +#ifndef _CL_MATH_H_ +#define _CL_MATH_H_ + + +#include + + +/****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 + + +#endif /* _CL_MATH_H_ */ diff --git a/branches/WOF2-3/inc/complib/cl_memory.h b/branches/WOF2-3/inc/complib/cl_memory.h new file mode 100644 index 00000000..b66f22cc --- /dev/null +++ b/branches/WOF2-3/inc/complib/cl_memory.h @@ -0,0 +1,963 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * Abstract: + * Declaration of generic memory allocation calls. + * + * Environment: + * All + */ + + +#ifndef _CL_MEMORY_H_ +#define _CL_MEMORY_H_ + + +#include +#include + + +/****h* Public/Memory Management +* NAME +* Memory Management +* +* DESCRIPTION +* The memory management functionality provides memory manipulation +* functions as well as powerful debugging tools. +* +* The Allocation Tracking functionality provides a means for tracking memory +* allocations in order to detect memory leaks. +* +* Memory allocation tracking stores the file name and line number where +* allocations occur. Gathering this information does have an adverse impact +* on performance, and memory tracking should therefore not be enabled in +* release builds of software. +* +* Memory tracking is compiled into the debug version of the library, +* and can be enabled for the release version as well. To Enable memory +* tracking in a release build of the public layer, users should define +* the MEM_TRACK_ON keyword for compilation. +*********/ + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/****i* Component Library: Memory Management/__cl_mem_track +* NAME +* __cl_mem_track +* +* DESCRIPTION +* The __cl_mem_track function enables or disables memory allocation tracking. +* +* SYNOPSIS +*/ +CL_EXPORT void CL_API +__cl_mem_track( + IN const boolean_t start ); +/* +* PARAMETERS +* start +* [in] Specifies whether to start or stop memory tracking. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* This function performs all necessary initialization for tracking +* allocations. Users should never call this function, as it is called by +* the component library framework. +* +* If the Start parameter is set to TRUE, the function starts tracking memory +* usage if not already started. When set to FALSE, memory tracking is stoped +* and all remaining allocations are displayed to the applicable debugger, if +* any. +* +* Starting memory tracking when it is already started has no effect. +* Likewise, stoping memory tracking when it is already stopped has no effect. +* +* SEE ALSO +* Memory Management, cl_mem_display +**********/ + + +/****f* Component Library: Memory Management/cl_mem_display +* NAME +* cl_mem_display +* +* DESCRIPTION +* The cl_mem_display function displays all tracked memory allocations to +* the applicable debugger. +* +* SYNOPSIS +*/ +CL_EXPORT void CL_API +cl_mem_display( void ); +/* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Each tracked memory allocation is displayed along with the file name and +* line number that allocated it. +* +* Output is sent to the platform's debugging target, which may be the +* system log file. +* +* SEE ALSO +* Memory Management +**********/ + + +/****i* Component Library: Memory Management/__cl_malloc_trk +* NAME +* __cl_malloc_trk +* +* DESCRIPTION +* The __cl_malloc_trk function allocates and tracks a block of memory. +* +* SYNOPSIS +*/ +CL_EXPORT void* CL_API +__cl_malloc_trk( + IN const char* const p_file_name, + IN const int32_t line_num, + IN const size_t bytes, + IN const boolean_t pageable ); +/* +* PARAMETERS +* p_file_name +* [in] Name of the source file initiating the allocation. +* +* line_num +* [in] Line number in the specified file where the allocation is +* initiated +* +* size +* [in] Size of the requested allocation. +* +* pageable +* [in] On operating systems that support pageable vs. non pageable +* memory in the kernel, set to TRUE to allocate memory from paged pool. +* +* RETURN VALUES +* Pointer to allocated memory if successful. +* +* NULL otherwise. +* +* NOTES +* Allocated memory follows alignment rules specific to the different +* environments. +* This function is should not be called directly. The cl_malloc macro will +* redirect users to this function when memory tracking is enabled. +* +* SEE ALSO +* Memory Management, __cl_malloc_ntrk, __cl_zalloc_trk, __cl_free_trk +**********/ + + +/****i* Component Library: Memory Management/__cl_zalloc_trk +* NAME +* __cl_zalloc_trk +* +* DESCRIPTION +* The __cl_zalloc_trk function allocates and tracks a block of memory +* initialized to zero. +* +* SYNOPSIS +*/ +CL_EXPORT void* CL_API +__cl_zalloc_trk( + IN const char* const p_file_name, + IN const int32_t line_num, + IN const size_t bytes, + IN const boolean_t pageable ); +/* +* PARAMETERS +* p_file_name +* [in] Name of the source file initiating the allocation. +* +* line_num +* [in] Line number in the specified file where the allocation is +* initiated +* +* size +* [in] Size of the requested allocation. +* +* pageable +* [in] On operating systems that support pageable vs. non pageable +* memory in the kernel, set to TRUE to allocate memory from paged pool. +* +* RETURN VALUES +* Pointer to allocated memory if successful. +* +* NULL otherwise. +* +* NOTES +* Allocated memory follows alignment rules specific to the different +* environments. +* This function should not be called directly. The cl_zalloc macro will +* redirect users to this function when memory tracking is enabled. +* +* SEE ALSO +* Memory Management, __cl_zalloc_ntrk, __cl_malloc_trk, __cl_free_trk +**********/ + + +/****i* Component Library: Memory Management/__cl_malloc_ntrk +* NAME +* __cl_malloc_ntrk +* +* DESCRIPTION +* The __cl_malloc_ntrk function allocates a block of memory. +* +* SYNOPSIS +*/ +CL_EXPORT void* CL_API +__cl_malloc_ntrk( + IN const size_t size, + IN const boolean_t pageable ); +/* +* PARAMETERS +* size +* [in] Size of the requested allocation. +* +* pageable +* [in] On operating systems that support pageable vs. non pageable +* memory in the kernel, set to TRUE to allocate memory from paged pool. +* +* RETURN VALUES +* Pointer to allocated memory if successful. +* +* NULL otherwise. +* +* NOTES +* Allocated memory follows alignment rules specific to the different +* environments. +* This function is should not be called directly. The cl_malloc macro will +* redirect users to this function when memory tracking is not enabled. +* +* SEE ALSO +* Memory Management, __cl_malloc_trk, __cl_zalloc_ntrk, __cl_free_ntrk +**********/ + + +/****i* Component Library: Memory Management/__cl_zalloc_ntrk +* NAME +* __cl_zalloc_ntrk +* +* DESCRIPTION +* The __cl_zalloc_ntrk function allocates a block of memory +* initialized to zero. +* +* SYNOPSIS +*/ +CL_EXPORT void* CL_API +__cl_zalloc_ntrk( + IN const size_t bytes, + IN const boolean_t pageable ); +/* +* PARAMETERS +* size +* [in] Size of the requested allocation. +* +* pageable +* [in] On operating systems that support pageable vs. non pageable +* memory in the kernel, set to TRUE to allocate memory from paged pool. +* +* RETURN VALUES +* Pointer to allocated memory if successful. +* +* NULL otherwise. +* +* NOTES +* Allocated memory follows alignment rules specific to the different +* environments. +* This function should not be called directly. The cl_zalloc macro will +* redirect users to this function when memory tracking is not enabled. +* +* SEE ALSO +* Memory Management, __cl_zalloc_trk, __cl_malloc_ntrk, __cl_free_ntrk +**********/ + + +/****i* Component Library: Memory Management/__cl_free_trk +* NAME +* __cl_free_trk +* +* DESCRIPTION +* The __cl_free_trk function deallocates a block of tracked memory. +* +* SYNOPSIS +*/ +CL_EXPORT void CL_API +__cl_free_trk( + IN void* const p_memory ); +/* +* PARAMETERS +* p_memory +* [in] Pointer to a memory block. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* The p_memory parameter is the pointer returned by a previous call to +* __cl_malloc_trk, or __cl_zalloc_trk. +* +* __cl_free_trk has no effect if p_memory is NULL. +* +* This function should not be called directly. The cl_free macro will +* redirect users to this function when memory tracking is enabled. +* +* SEE ALSO +* Memory Management, __cl_free_ntrk, __cl_malloc_trk, __cl_zalloc_trk +**********/ + + +/****i* Component Library: Memory Management/__cl_free_ntrk +* NAME +* __cl_free_ntrk +* +* DESCRIPTION +* The __cl_free_ntrk function deallocates a block of memory. +* +* SYNOPSIS +*/ +CL_EXPORT void CL_API +__cl_free_ntrk( + IN void* const p_memory ); +/* +* PARAMETERS +* p_memory +* [in] Pointer to a memory block. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* The p_memory parameter is the pointer returned by a previous call to +* __cl_malloc_ntrk, or __cl_zalloc_ntrk. +* +* __cl_free_ntrk has no effect if p_memory is NULL. +* +* This function should not be called directly. The cl_free macro will +* redirect users to this function when memory tracking is not enabled. +* +* SEE ALSO +* Memory Management, __cl_free_ntrk, __cl_malloc_trk, __cl_zalloc_trk +**********/ + + +/****f* Component Library: Memory Management/cl_malloc +* NAME +* cl_malloc +* +* DESCRIPTION +* The cl_malloc function allocates a block of memory. +* +* SYNOPSIS +*/ +void* +cl_malloc( + IN const size_t size ); +/* +* PARAMETERS +* size +* [in] Size of the requested allocation. +* +* RETURN VALUES +* Pointer to allocated memory if successful. +* +* NULL otherwise. +* +* NOTES +* Allocated memory follows alignment rules specific to the different +* environments. +* +* SEE ALSO +* Memory Management, cl_free, cl_zalloc, cl_palloc, cl_pzalloc, +* cl_memset, cl_memclr, cl_memcpy, cl_memcmp +**********/ + + +/****f* Component Library: Memory Management/cl_zalloc +* NAME +* cl_zalloc +* +* DESCRIPTION +* The cl_zalloc function allocates a block of memory initialized to zero. +* +* SYNOPSIS +*/ +void* +cl_zalloc( + IN const size_t size ); +/* +* PARAMETERS +* size +* [in] Size of the requested allocation. +* +* RETURN VALUES +* Pointer to allocated memory if successful. +* +* NULL otherwise. +* +* NOTES +* Allocated memory follows alignment rules specific to the different +* environments. +* +* SEE ALSO +* Memory Management, cl_free, cl_malloc, cl_palloc, cl_pzalloc, +* cl_memset, cl_memclr, cl_memcpy, cl_memcmp +**********/ + + +/****f* Component Library: Memory Management/cl_palloc +* NAME +* cl_palloc +* +* DESCRIPTION +* The cl_palloc function allocates a block of memory from paged pool if the +* operating system supports it. If the operating system does not distinguish +* between pool types, cl_palloc is identical to cl_malloc. +* +* SYNOPSIS +*/ +void* +cl_palloc( + IN const size_t size ); +/* +* PARAMETERS +* size +* [in] Size of the requested allocation. +* +* RETURN VALUES +* Pointer to allocated memory if successful. +* +* NULL otherwise. +* +* NOTES +* Allocated memory follows alignment rules specific to the different +* environments. +* +* SEE ALSO +* Memory Management, cl_free, cl_malloc, cl_zalloc, cl_pzalloc, +* cl_memset, cl_memclr, cl_memcpy, cl_memcmp +**********/ + + +/****f* Component Library: Memory Management/cl_pzalloc +* NAME +* cl_pzalloc +* +* DESCRIPTION +* The cl_pzalloc function allocates a block of memory from paged pool if the +* operating system supports it and initializes it to zero. If the operating +* system does not distinguish between pool types, cl_pzalloc is identical +* to cl_zalloc. +* +* SYNOPSIS +*/ +void* +cl_pzalloc( + IN const size_t size ); +/* +* PARAMETERS +* size +* [in] Size of the requested allocation. +* +* RETURN VALUES +* Pointer to allocated memory if successful. +* +* NULL otherwise. +* +* NOTES +* Allocated memory follows alignment rules specific to the different +* environments. +* +* SEE ALSO +* Memory Management, cl_free, cl_malloc, cl_zalloc, cl_palloc, +* cl_memset, cl_memclr, cl_memcpy, cl_memcmp +**********/ + + +/****f* Component Library: Memory Management/cl_free +* NAME +* cl_free +* +* DESCRIPTION +* The cl_free function deallocates a block of memory. +* +* SYNOPSIS +*/ +void +cl_free( + IN void* const p_memory ); +/* +* PARAMETERS +* p_memory +* [in] Pointer to a memory block. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* The p_memory parameter is the pointer returned by a previous call to +* cl_malloc, or cl_zalloc. +* +* cl_free has no effect if p_memory is NULL. +* +* SEE ALSO +* Memory Management, cl_alloc, cl_zalloc +**********/ + + +/****f* Component Library: Memory Management/cl_memset +* NAME +* cl_memset +* +* DESCRIPTION +* The cl_memset function sets every byte in a memory range to a given value. +* +* SYNOPSIS +*/ +CL_EXPORT void CL_API +cl_memset( + IN void* const p_memory, + IN const uint8_t fill, + IN const size_t count ); +/* +* PARAMETERS +* p_memory +* [in] Pointer to a memory block. +* +* fill +* [in] Byte value with which to fill the memory. +* +* count +* [in] Number of bytes to set. +* +* RETURN VALUE +* This function does not return a value. +* +* SEE ALSO +* Memory Management, cl_memclr, cl_memcpy, cl_memcmp +**********/ + + +#ifndef _CL_MEMCLR_DEFINED_ +/****f* Component Library: Memory Management/cl_memclr +* NAME +* cl_memclr +* +* DESCRIPTION +* The cl_memclr function sets every byte in a memory range to zero. +* +* SYNOPSIS +*/ +CL_INLINE void CL_API +cl_memclr( + IN void* const p_memory, + IN const size_t count ) +{ + cl_memset( p_memory, 0, count ); +} +/* +* PARAMETERS +* p_memory +* [in] Pointer to a memory block. +* +* count +* [in] Number of bytes to set. +* +* RETURN VALUE +* This function does not return a value. +* +* SEE ALSO +* Memory Management, cl_memset, cl_memcpy, cl_memcmp +**********/ +#endif + + +/****f* Component Library: Memory Management/cl_memcpy +* NAME +* cl_memcpy +* +* DESCRIPTION +* The cl_memcpy function copies a given number of bytes from +* one buffer to another. +* +* SYNOPSIS +*/ +CL_EXPORT void* CL_API +cl_memcpy( + IN void* const p_dest, + IN const void* const p_src, + IN const size_t count ); +/* +* PARAMETERS +* p_dest +* [in] Pointer to the buffer being copied to. +* +* p_src +* [in] Pointer to the buffer being copied from. +* +* count +* [in] Number of bytes to copy from the source buffer to the +* destination buffer. +* +* RETURN VALUE +* Returns a pointer to the destination buffer. +* +* SEE ALSO +* Memory Management, cl_memset, cl_memclr, cl_memcmp +**********/ + + +/****f* Component Library: Memory Management/cl_memcmp +* NAME +* cl_memcmp +* +* DESCRIPTION +* The cl_memcmp function compares two memory buffers. +* +* SYNOPSIS +*/ +CL_EXPORT int32_t CL_API +cl_memcmp( + IN const void* const p_mem, + IN const void* const p_ref, + IN const size_t count ); +/* +* PARAMETERS +* p_mem +* [in] Pointer to a memory block being compared. +* +* p_ref +* [in] Pointer to the reference memory block to compare against. +* +* count +* [in] Number of bytes to compare. +* +* RETURN VALUES +* Returns less than zero if p_mem is less than p_ref. +* +* Returns greater than zero if p_mem is greater than p_ref. +* +* Returns zero if the two memory regions are the identical. +* +* SEE ALSO +* Memory Management, cl_memset, cl_memclr, cl_memcpy +**********/ + + +#ifdef CL_KERNEL + +/****f* Component Library: Memory Management/cl_get_pagesize +* NAME +* cl_get_pagesize +* +* DESCRIPTION +* Returns the number of bytes in a OS defined page. +* +* SYNOPSIS +*/ +CL_EXPORT uint32_t CL_API +cl_get_pagesize( void ); +/* +* PARAMETERS +* NONE +* +* RETURN VALUES +* Returns the number of bytes in a page as defined by the Operating +* System. +* +* SEE ALSO +* Memory Management +**********/ + + +/****f* Component Library: Memory Management/cl_get_physaddr +* NAME +* cl_get_physaddr +* +* DESCRIPTION +* Returns the Physical address for a kernel virtual address. +* +* SYNOPSIS +*/ +CL_EXPORT uint64_t CL_API +cl_get_physaddr( + IN void *vaddr ); +/* +* PARAMETERS +* p_addr +* [in] Pointer to virtual to which the physical address is required. +* +* RETURN VALUES +* Returns the physical address for a virtual address. +* +* NOTES +* This call is only available in kernel mode. +* +* SEE ALSO +* Memory Management +**********/ + + +/****f* Component Library: Memory Management/cl_check_for_read +* NAME +* cl_check_for_read +* +* DESCRIPTION +* Checks a user-mode virtual address for read access. +* +* SYNOPSIS +*/ +CL_EXPORT cl_status_t CL_API +cl_check_for_read( + IN const void* const vaddr, + IN const size_t count ); +/* +* PARAMETERS +* vaddr +* [in] Virtual address to check for read access. +* +* count +* [in] Number of bytes of the buffer at the specified address +* to validate. +* +* RETURN VALUES +* CL_SUCCESS if the virtual address is valid for a read of the specified +* size. +* +* CL_INVALID_PERMISSION if the virtual address or the size is not valid. +* +* NOTES +* This call is only available in the kernel. The buffer can only be accessed +* in the context of the application thread (i.e. in the path of an IOCTL +* request). Callers cannot be holding a spinlock when calling this function. +* +* SEE ALSO +* Memory Management, cl_check_for_write, cl_copy_to_user, cl_copy_from_user +*********/ + + +/****f* Component Library: Memory Management/cl_check_for_write +* NAME +* cl_check_for_write +* +* DESCRIPTION +* Checks a user-mode virtual address for write access. +* +* SYNOPSIS +*/ +CL_EXPORT cl_status_t CL_API +cl_check_for_write( + IN void* const vaddr, + IN const size_t count ); +/* +* PARAMETERS +* vaddr +* [in] Virtual address to check for write access. +* +* count +* [in] Number of bytes of the buffer at the specified +* address to validate. +* +* RETURN VALUES +* CL_SUCCESS if the virtual address is valid for a write of the specified +* size. +* +* CL_INVALID_PERMISSION if the virtual address or the size is not valid. +* +* NOTES +* This call is only available in the kernel. The buffer can only be accessed +* in the context of the application thread (i.e. in the path of an IOCTL +* request). Callers cannot be holding a spinlock when calling this function. +* +* SEE ALSO +* Memory Management, cl_check_for_read, cl_copy_to_user, cl_copy_from_user +*********/ + + +/****f* Component Library: Memory Management/cl_copy_to_user +* NAME +* cl_copy_to_user +* +* DESCRIPTION +* Copies data into a user-mode buffer, performing access checks. +* +* SYNOPSIS +*/ +CL_EXPORT cl_status_t CL_API +cl_copy_to_user( + IN void* const p_dest, + IN const void* const p_src, + IN const size_t count ); +/* +* PARAMETERS +* p_dest +* [in] User-mode virtual address to which to copy data. +* +* p_src +* [in] Pointer to the buffer being copied from. +* +* count +* [in] Number of bytes to copy from the source buffer to the +* destination buffer. +* +* RETURN VALUES +* CL_SUCCESS if the user-mode buffer virtual address is valid as the +* destination of the copy. +* +* CL_INVALID_PERMISSION if the virtual address or the count is not valid. +* +* NOTES +* This call is only available in the kernel. The buffer can only be accessed +* in the context of the application thread (i.e. in the path of an IOCTL +* request). Callers cannot be holding a spinlock when calling this function. +* +* SEE ALSO +* Memory Management, cl_check_for_read, cl_check_for_write, cl_copy_from_user +*********/ + + +/****f* Component Library: Memory Management/cl_copy_from_user +* NAME +* cl_copy_from_user +* +* DESCRIPTION +* Copies data from a user-mode buffer, performing access checks. +* +* SYNOPSIS +*/ +CL_EXPORT cl_status_t CL_API +cl_copy_from_user( + IN void* const p_dest, + IN const void* const p_src, + IN const size_t count ); +/* +* PARAMETERS +* p_dest +* [in] Pointer to the buffer being copied to. +* +* p_src +* [in] User-mode virtual address from which to copy data. +* +* count +* [in] Number of bytes to copy from the source buffer to the +* destination buffer. +* +* RETURN VALUES +* CL_SUCCESS if the user-mode buffer virtual address is valid as the +* source of the copy. +* +* CL_INVALID_PERMISSION if the virtual address or the count is not valid. +* +* NOTES +* This call is only available in the kernel. The buffer can only be accessed +* in the context of the application thread (i.e. in the path of an IOCTL +* request). Callers cannot be holding a spinlock when calling this function. +* +* SEE ALSO +* Memory Management, cl_check_for_read, cl_check_for_write, cl_copy_to_user +*********/ + +#endif /* CL_KERNEL */ + +#if defined( CL_NO_TRACK_MEM ) && defined( CL_TRACK_MEM ) + #error Conflict: Cannot define both CL_NO_TRACK_MEM and CL_TRACK_MEM. +#endif + +/* + * Turn on memory allocation tracking in debug builds if not explicitly + * disabled or already turned on. + */ +#if defined( _DEBUG_ ) && \ + !defined( CL_NO_TRACK_MEM ) && \ + !defined( CL_TRACK_MEM ) + #define CL_TRACK_MEM +#endif + + +/* + * Define allocation macro. + */ +#if defined( CL_TRACK_MEM ) + +#define cl_malloc( a ) \ + __cl_malloc_trk( __FILE__, __LINE__, a, FALSE ) + +#define cl_zalloc( a ) \ + __cl_zalloc_trk( __FILE__, __LINE__, a, FALSE ) + +#define cl_palloc( a ) \ + __cl_malloc_trk( __FILE__, __LINE__, a, TRUE ) + +#define cl_pzalloc( a ) \ + __cl_zalloc_trk( __FILE__, __LINE__, a, TRUE ) + +#define cl_free( a ) \ + __cl_free_trk( a ) + +#else /* !defined( CL_TRACK_MEM ) */ + +#define cl_malloc( a ) \ + __cl_malloc_ntrk( a, FALSE ) + +#define cl_zalloc( a ) \ + __cl_zalloc_ntrk( a, FALSE ) + +#define cl_palloc( a ) \ + __cl_malloc_ntrk( a, TRUE ) + +#define cl_pzalloc( a ) \ + __cl_zalloc_ntrk( a, TRUE ) + +#define cl_free( a ) \ + __cl_free_ntrk( a ) + +#endif /* defined( CL_TRACK_MEM ) */ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* _CL_MEMORY_H_ */ diff --git a/branches/WOF2-3/inc/complib/cl_mutex.h b/branches/WOF2-3/inc/complib/cl_mutex.h new file mode 100644 index 00000000..2ae4de31 --- /dev/null +++ b/branches/WOF2-3/inc/complib/cl_mutex.h @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * Abstract: + * Declaration of mutex object. + * + * Environment: + * All + */ + + +#ifndef _CL_MUTEX_H_ +#define _CL_MUTEX_H_ + + +#include + + +/****h* complib/Mutex +* NAME +* Mutex +* +* DESCRIPTION +* Mutex provides synchronization between threads for exclusive access to +* a resource. +* +* The Mutex functions manipulate a cl_mutex_t structure which should +* be treated as opaque and should be manipulated only through the provided +* functions. +* +* SEE ALSO +* Structures: +* cl_mutex_t +* +* Initialization: +* cl_mutex_construct, cl_mutex_init, cl_mutex_destroy +* +* Manipulation +* cl_mutex_acquire, cl_mutex_release +*********/ + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/****f* Component Library: Mutex/cl_mutex_construct +* NAME +* cl_mutex_construct +* +* DESCRIPTION +* The cl_mutex_construct function initializes the state of a +* mutex. +* +* SYNOPSIS +*/ +CL_EXPORT void CL_API +cl_mutex_construct( + IN cl_mutex_t* const p_mutex ); +/* +* PARAMETERS +* p_mutex +* [in] Pointer to a mutex structure whose state to initialize. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling cl_semphore_destroy without first calling +* cl_mutex_init. +* +* Calling cl_mutex_construct is a prerequisite to calling any other +* mutex function except cl_mutex_init. +* +* SEE ALSO +* Mutex, cl_semphore_init cl_mutex_destroy +*********/ + + +/****f* Component Library: Mutex/cl_mutex_init +* NAME +* cl_mutex_init +* +* DESCRIPTION +* The cl_mutex_init function initializes a mutex for use. +* +* SYNOPSIS +*/ +CL_EXPORT cl_status_t CL_API +cl_mutex_init( + IN cl_mutex_t* const p_mutex ); +/* +* PARAMETERS +* p_mutex +* [in] Pointer to a mutex structure to initialize. +* +* RETURN VALUES +* CL_SUCCESS if initialization succeeded. +* +* CL_ERROR if initialization failed. Callers should call +* cl_mutex_destroy to clean up any resources allocated during +* initialization. +* +* NOTES +* Initializes the mutex structure. Allows calling cl_mutex_aquire +* and cl_mutex_release. The cl_mutex is always created in the unlocked state. +* +* SEE ALSO +* Mutex, cl_mutex_construct, cl_mutex_destroy, +* cl_mutex_acquire, cl_mutex_release +*********/ + + +/****f* Component Library: Mutex/cl_mutex_destroy +* NAME +* cl_mutex_destroy +* +* DESCRIPTION +* The cl_mutex_destroy function performs all necessary cleanup of a +* mutex. +* +* SYNOPSIS +*/ +CL_EXPORT void CL_API +cl_mutex_destroy( + IN cl_mutex_t* const p_mutex ); +/* +* PARAMETERS +* p_mutex +* [in] Pointer to a mutex structure to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of a mutex. This function must only +* be called if either cl_mutex_construct or cl_mutex_init has been +* called. +* +* SEE ALSO +* Mutex, cl_mutex_construct, cl_mutex_init +*********/ + + +/****f* Component Library: Mutex/cl_mutex_acquire +* NAME +* cl_mutex_acquire +* +* DESCRIPTION +* The cl_mutex_acquire function acquires a mutex. +* +* SYNOPSIS +*/ +CL_EXPORT void CL_API +cl_mutex_acquire( + IN cl_mutex_t* const p_mutex ); +/* +* PARAMETERS +* p_mutex +* [in] Pointer to a mutex structure to acquire. +* +* RETURN VALUE +* This function does not return a value. +* +* SEE ALSO +* Mutex, cl_mutex_release +*********/ + + +/****f* Component Library: Mutex/cl_mutex_release +* NAME +* cl_mutex_release +* +* DESCRIPTION +* The cl_mutex_release function releases a mutex object. +* +* SYNOPSIS +*/ +CL_EXPORT void CL_API +cl_mutex_release( + IN cl_mutex_t* const p_mutex ); +/* +* PARAMETERS +* p_mutex +* [in] Pointer to a mutex structure to release. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Releases a mutex after a call to cl_mutex_acquire. +* +* SEE ALSO +* Mutex, cl_mutex_acquire +*********/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* _CL_MUTEX_H_ */ diff --git a/branches/WOF2-3/inc/complib/cl_nodenamemap.h b/branches/WOF2-3/inc/complib/cl_nodenamemap.h new file mode 100644 index 00000000..e836cf50 --- /dev/null +++ b/branches/WOF2-3/inc/complib/cl_nodenamemap.h @@ -0,0 +1,73 @@ +/* + * 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_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include +#include + +/* NOTE: this may modify the parameter "nodedesc". */ +CL_EXPORT 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. + */ +CL_EXPORT nn_map_t * CL_API open_node_name_map(char *node_name_map); +CL_EXPORT void CL_API close_node_name_map(nn_map_t *map); +CL_EXPORT char * CL_API remap_node_name(nn_map_t *map, uint64_t target_guid, + char *nodedesc); + /* NOTE: parameter "nodedesc" may be modified here. */ +CL_EXPORT int CL_API parse_node_map(const char *file_name, + int (*create)(void *, uint64_t, char *), void *cxt); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* _CL_NODE_NAME_MAP_H_ */ diff --git a/branches/WOF2-3/inc/complib/cl_obj.h b/branches/WOF2-3/inc/complib/cl_obj.h new file mode 100644 index 00000000..e691d101 --- /dev/null +++ b/branches/WOF2-3/inc/complib/cl_obj.h @@ -0,0 +1,998 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * Abstract: + * Declaration of basic objects and relationships. + * + * Environment: + * All + */ + + +#if !defined(__CL_OBJ_H__) +#define __CL_OBJ_H__ + +#include +#include +#include +#include +#include +#include + + +/****h* Component Library/Object +* NAME +* Object +* +* DESCRIPTION +* Object describes a basic class that can be used to track accesses to an +* object and provides automatic cleanup of an object that is dependent +* on another object. +* +* Dependencies between objects are described using a relationship. A +* child object is considered dependent on a parent object. Destruction of +* a parent object automatically results in the destruction of any child +* objects associated with the parent. +* +* The relationship between parent and child objects is many to many. +* Parents can have multiple child objects, and a child can be dependent on +* multiple parent objects. In the latter case, destruction of any parent +* object results in the destruction of the child object. +* +* Other relationships between objects are described using references. An +* object that takes a reference on a second object prevents the second object +* from being deallocated as long as the reference is held. +* +* SEE ALSO +* Types +* cl_destroy_type_t +* +* Structures: +* cl_obj_t, cl_obj_rel_t +* +* Callbacks: +* cl_pfn_obj_call_t +* +* Initialization/Destruction: +* cl_obj_mgr_create, cl_obj_mgr_destroy, +* cl_obj_construct, cl_obj_init, cl_obj_destroy, cl_obj_deinit +* +* Object Relationships: +* cl_obj_ref, cl_obj_deref, +* cl_rel_alloc, cl_rel_free, cl_obj_insert_rel, cl_obj_remove_rel +* +* Object Manipulation: +* cl_obj_reset +*********/ + + + +/* Forward declaration. */ +typedef struct _cl_obj *__p_cl_obj_t; + + + +/****s* Component Library: Object/cl_obj_mgr_t +* NAME +* cl_obj_mgr_t +* +* DESCRIPTION +* The global object manager. +* +* The manager must be created before constructing any other objects, and all +* objects must be destroyed before the object manager is destroyed. +* +* The manager is used to maintain the list of all objects currently active +* in the system. It provides a pool of relationship items used to +* describe parent-child, or dependent, relationships between two objects. +* The manager contains an asynchronous processing thread that is used to +* support asynchronous object destruction. +* +* SYNOPSIS +*/ +typedef struct _cl_obj_mgr +{ + cl_qlist_t obj_list; + cl_spinlock_t lock; + + cl_async_proc_t async_proc_mgr; + + cl_qpool_t rel_pool; + +} cl_obj_mgr_t; +/* +* FIELDS +* obj_list +* List of all object's in the system. Object's are inserted into this +* list when constructed and removed when freed. +* +* lock +* A lock used by the object manager for synchronization to the obj_list. +* +* async_proc_mgr +* An asynchronous processing manager used to process asynchronous +* destruction requests. Users wishing to synchronize the execution of +* specific routines with object destruction may queue work requests to +* this processing manager. +* +* rel_pool +* Pool of items used to describe dependent relationships. Users may +* obtain relationship objects from this pool when forming relationships, +* but are not required to do so. +* +* SEE ALSO +* Object, cl_obj_mgr_create, cl_obj_mgr_destroy, +* cl_obj_construct, cl_obj_deinit, +* cl_qlist_t, cl_spinlock_t, cl_async_proc_t, cl_qpool_t +*********/ + + + +#ifdef __cplusplus +extern "C" { +#endif + + + +/****f* Component Library: Object/cl_obj_mgr_create +* NAME +* cl_obj_mgr_create +* +* DESCRIPTION +* This routine creates an object manager used to track all objects by +* the user. The object manager assists with debugging efforts by identifying +* objects that are not destroyed properly. +* +* SYNOPSIS +*/ +CL_EXPORT cl_status_t CL_API +cl_obj_mgr_create(void); +/* +* PARAMETERS +* None. +* +* RETURN VALUE +* CL_SUCCESS +* The object manager was succesfully created. +* +* CL_INSUFFICIENT_MEMORY +* The object manager could not be allocated. +* +* NOTES +* This call must succeed before invoking any other object-related function. +* +* SEE ALSO +* Object, cl_obj_mgr_destroy +*********/ + + + +/****f* Component Library: Object/cl_obj_mgr_destroy +* NAME +* cl_obj_mgr_destroy +* +* DESCRIPTION +* This routine destroys the object manager created through cl_obj_mgr_create. +* +* SYNOPSIS +*/ +CL_EXPORT void CL_API +cl_obj_mgr_destroy(void); +/* +* PARAMETERS +* None. +* +* RETURN VALUE +* None. +* +* NOTES +* When the object manager is destroyed, it will display information about all +* objects that have not yet been destroyed. +* +* SEE ALSO +* Object, cl_obj_mgr_create +*********/ + + +/****d* Component Library: Object/cl_pfn_obj_call_t +* NAME +* cl_pfn_obj_call_t +* +* DESCRIPTION +* The cl_pfn_obj_call_t function type defines the prototype for functions +* used to return objects to the user. +* +* SYNOPSIS +*/ +typedef void +(CL_API *cl_pfn_obj_call_t)( + IN struct _cl_obj *p_obj ); +/* +* PARAMETERS +* p_obj +* [in] Pointer to a cl_obj_t. This is the object being returned to +* the user. +* +* RETURN VALUES +* None. +* +* NOTES +* This function type is provided as a prototype for functions provided +* by users as parameters to the cl_obj_init function. +* +* SEE ALSO +* Object, cl_obj_init, cl_obj_t +*********/ + + +/****d* Component Library: Object/cl_destroy_type_t +* NAME +* cl_destroy_type_t +* +* DESCRIPTION +* Indicates the type of destruction to perform on an object. +* +* SYNOPSIS +*/ +typedef enum _cl_destroy_type +{ + CL_DESTROY_ASYNC, + CL_DESTROY_SYNC + +} cl_destroy_type_t; +/* +* VALUES +* CL_DESTROY_ASYNC +* Indicates that the object should be destroyed asynchronously. Objects +* destroyed asynchronously complete initial destruction processing, then +* return the calling thread. Once their reference count goes to zero, +* they are queue onto an asynchronous thread to complete destruction +* processing. +* +* CL_DESTROY_SYNC +* Indicates that the object should be destroyed synchronously. Objects +* destroyed synchronously wait (block) until their reference count goes +* to zero. Once their reference count goes to zero, destruction +* processing is completed by the calling thread. +* +* SEE ALSO +* Object, cl_obj_init, cl_obj_destroy, cl_obj_deinit, cl_obj_t +*********/ + + + +/****s* Component Library: Object/cl_obj_t +* NAME +* cl_obj_t +* +* DESCRIPTION +* Object structure. +* +* SYNOPSIS +*/ +typedef struct _cl_obj +{ + cl_pool_item_t pool_item; /* Must be first. */ + uint32_t type; + cl_state_t state; + cl_destroy_type_t destroy_type; + + cl_async_proc_item_t async_item; + cl_event_t event; + + cl_pfn_obj_call_t pfn_destroying; + cl_pfn_obj_call_t pfn_cleanup; + cl_pfn_obj_call_t pfn_free; + + cl_spinlock_t lock; + + cl_qlist_t parent_list; + cl_qlist_t child_list; + + atomic32_t ref_cnt; + +} cl_obj_t; +/* +* FIELDS +* pool_item +* Used to track the object with the global object manager. We use +* a pool item, rather than a list item, to let users store the object +* in a pool. +* +* type +* Stores a user-specified object type. +* +* state +* Records the current state of the object, such as initialized, +* destroying, etc. +* +* destroy_type +* Specifies the type of destruction, synchronous or asynchronous, to +* perform on this object. +* +* async_item +* Asynchronous item used when destroying the object asynchronously. +* This item is queued to an asynchronous thread to complete destruction +* processing. +* +* event +* Event used when destroying the object synchronously. A call to destroy +* the object will wait on this event until the destruction has completed. +* +* pfn_destroying +* User-specified callback invoked to notify a user that an object has +* been marked for destruction. This callback is invoked directly from +* the thread destroying the object and is used to notify a user that +* a parent object has invoked a child object's destructor. +* +* pfn_cleanup +* User-specified callback invoked as an object is undergoing destruction. +* For object's destroyed asynchronously, this callback is invoked from +* the context of the asynchronous destruction thread. Users may block +* in the context of this thread; however, further destruction processing +* will not continue until this callback returns. +* +* pfn_free +* User-specified callback invoked to notify a user that an object has +* been destroyed and is ready for deallocation. Users should either +* call cl_obj_deinit or cl_obj_reset from within this callback. +* +* lock +* A lock provided by the object. +* +* parent_list +* A list of relationships to parent objects that an object is dependent +* on. +* +* child_list +* A list of all child objects that are dependent on this object. +* Destroying this object will result in all related objects maintained +* in the child list also being destroyed. +* +* ref_cnt +* A count of the number of objects still referencing this object. +* +* SEE ALSO +* Object, cl_obj_construct, cl_obj_init, cl_obj_destroy, +* cl_obj_deinit, cl_pfn_obj_call_t, cl_destroy_type_t, +* cl_pool_item_t, cl_state_t, cl_async_proc_item_t, +* cl_event_t, cl_spinlock_t, cl_qlist_t, atomic32_t +*********/ + + + +/****f* Component Library: Object/cl_obj_construct +* NAME +* cl_obj_construct +* +* DESCRIPTION +* This routine prepares an object for use. The object must be successfully +* initialized before being used. +* +* SYNOPSIS +*/ +CL_EXPORT void CL_API +cl_obj_construct( + IN cl_obj_t * const p_obj, + IN const uint32_t obj_type ); +/* +* PARAMETERS +* p_obj +* [in] A pointer to the object to construct. +* +* obj_type +* [in] A user-specified type associated with the object. This type +* is recorded by the object for debugging purposes and may be accessed +* by the user. +* +* RETURN VALUE +* None. +* +* NOTES +* This call must succeed before invoking any other function on an object. +* +* SEE ALSO +* Object, cl_obj_init, cl_obj_destroy, cl_obj_deinit. +*********/ + + +/****f* Component Library: Object/cl_obj_init +* NAME +* cl_obj_init +* +* DESCRIPTION +* This routine initializes an object for use. Upon the successful completion +* of this call, the object is ready for use. +* +* SYNOPSIS +*/ +CL_EXPORT cl_status_t CL_API +cl_obj_init( + IN cl_obj_t * const p_obj, + IN cl_destroy_type_t destroy_type, + IN const cl_pfn_obj_call_t pfn_destroying OPTIONAL, + IN const cl_pfn_obj_call_t pfn_cleanup OPTIONAL, + IN const cl_pfn_obj_call_t pfn_free ); +/* +* PARAMETERS +* p_obj +* [in] A pointer to the object to initialize. +* +* destroy_type +* [in] Specifies the destruction model used by this object. +* +* pfn_destroying +* [in] User-specified callback invoked to notify a user that an object has +* been marked for destruction. This callback is invoked directly from +* the thread destroying the object and is used to notify a user that +* a parent object has invoked a child object's destructor. +* +* pfn_cleanup +* [in] User-specified callback invoked to an object is undergoing +* destruction. For object's destroyed asynchronously, this callback +* is invoked from the context of the asynchronous destruction thread. +* Users may block in the context of this thread; however, further +* destruction processing will not continue until this callback returns. +* +* pfn_free +* [in] User-specified callback invoked to notify a user that an object has +* been destroyed and is ready for deallocation. Users should either +* call cl_obj_deinit or cl_obj_reset from within this callback. +* +* RETURN VALUE +* CL_SUCCESS +* The object was successfully initialized. +* +* CL_INSUFFICIENT_MEMORY +* The object could not allocate the necessary memory resources to +* complete initialization. +* +* NOTES +* The three destruction callbacks are used to notify the user of the progress +* of the destruction, permitting the user to perform an additional processing. +* Pfn_destroying is used to notify the user that the object is being +* destroyed. It is called after an object has removed itself from +* relationships with its parents, but before it destroys any child objects +* that it might have. +* +* Pfn_cleanup is invoked after all child objects have been destroyed, and +* there are no more references on the object itself. For objects destroyed +* asynchronously, pfn_cleanup is invoked from an asynchronous destruction +* thread. +* +* Pfn_free is called to notify the user that the destruction of the object has +* completed. All relationships have been removed, and all child objects have +* been destroyed. Relationship items (cl_obj_rel_t) that were used to +* identify parent objects are returned to the user through the p_parent_list +* field of the cl_obj_t structure. +* +* SEE ALSO +* Object, cl_obj_construct, cl_obj_destroy, cl_obj_deinit, +* cl_obj_t, cl_destroy_type_t, cl_pfn_obj_call_t, +*********/ + + +/****f* Component Library: Object/cl_obj_destroy +* NAME +* cl_obj_destroy +* +* DESCRIPTION +* This routine destroys the specified object. +* +* SYNOPSIS +*/ +CL_EXPORT void CL_API +cl_obj_destroy( + IN cl_obj_t * p_obj ); +/* +* PARAMETERS +* p_obj +* [in] A pointer to the object to destroy. +* +* RETURN VALUE +* None. +* +* NOTES +* This routine starts the destruction process for the specified object. For +* additional information regarding destruction callbacks, see the following +* fields in cl_obj_t and parameters in cl_obj_init: pfn_destroying, +* pfn_cleanup, and pfn_free. +* +* In most cases, after calling this routine, users should call cl_obj_deinit +* from within their pfn_free callback routine. +* +* SEE ALSO +* Object, cl_obj_construct, cl_obj_init, cl_obj_deinit, +* cl_obj_t, cl_destroy_type_t, cl_pfn_obj_call_t +*********/ + + + +/****f* Component Library: Object/cl_obj_deinit +* NAME +* cl_obj_deinit +* +* DESCRIPTION +* Release all resources allocated by an object. This routine should +* typically be called from a user's pfn_free routine. +* +* SYNOPSIS +*/ +CL_EXPORT void CL_API +cl_obj_deinit( + IN cl_obj_t * const p_obj ); +/* +* PARAMETERS +* p_obj +* [in] A pointer to the object to free. +* +* RETURN VALUE +* None. +* +* NOTES +* This call must be invoked to release the object from the global object +* manager. +* +* SEE ALSO +* Object, cl_obj_construct, cl_obj_init, cl_obj_destroy, cl_obj_t +*********/ + + + +/****f* Component Library: Object/cl_obj_reset +* NAME +* cl_obj_reset +* +* DESCRIPTION +* Reset an object's state. This is called after cl_obj_destroy has +* been called on a object, but before cl_obj_deinit has been invoked. +* After an object has been reset, it is ready for re-use. +* +* SYNOPSIS +*/ +CL_EXPORT void CL_API +cl_obj_reset( + IN cl_obj_t * const p_obj ); +/* +* PARAMETERS +* p_obj +* [in] A pointer to the object to reset. +* +* RETURN VALUE +* None. +* +* NOTES +* This routine allows an object to be initialized once, then destroyed +* and re-used multiple times. This permits the user to allocate and +* maintain a pool of objects. The objects may be reset and returned to +* the pool, rather than freed, after being destroyed. The objects would +* not be freed until the pool itself was destroyed. +* +* SEE ALSO +* Object, cl_obj_destroy, cl_obj_free, cl_obj_t +*********/ + + + +/****f* Component Library: Object/cl_obj_ref +* NAME +* cl_obj_ref +* +* DESCRIPTION +* Increments the reference count on an object and returns the updated count. +* This routine is thread safe, but does not result in locking the object. +* +* SYNOPSIS +*/ +CL_EXPORT int32_t CL_API +cl_obj_ref( + IN cl_obj_t * const p_obj ); +/* +* PARAMETERS +* p_obj +* [in] A pointer to the object to reference. +* +* RETURN VALUE +* The updated reference count. +* +* SEE ALSO +* Object, cl_obj_t, cl_obj_deref +*********/ + + + +/****f* Component Library: Object/cl_obj_deref +* NAME +* cl_obj_deref +* +* DESCRIPTION +* Decrements the reference count on an object and returns the updated count. +* This routine is thread safe, but results in locking the object. +* +* SYNOPSIS +*/ +CL_EXPORT int32_t CL_API +cl_obj_deref( + IN cl_obj_t * const p_obj ); +/* +* PARAMETERS +* p_obj +* [in] A pointer to the object to dereference. +* +* RETURN VALUE +* The updated reference count. +* +* SEE ALSO +* Object, cl_obj_t, cl_obj_ref +*********/ + + +/****f* Component Library: Object/cl_obj_type +* NAME +* cl_obj_type +* +* DESCRIPTION +* Returns the type of an object. +* +* SYNOPSIS +*/ +CL_INLINE uint32_t CL_API +cl_obj_type( + IN cl_obj_t * const p_obj ) +{ + return p_obj->type; +} +/* +* PARAMETERS +* p_obj +* [in] A pointer to the object whose type to return. +* +* RETURN VALUE +* The type of the object, as specified in the call to cl_obj_init. +* +* SEE ALSO +* Object, cl_obj_t, cl_obj_init +*********/ + + +/****f* Component Library: Object/cl_obj_lock +* NAME +* cl_obj_lock +* +* DESCRIPTION +* Acquires an object's lock. +* +* SYNOPSIS +*/ +CL_INLINE void CL_API +cl_obj_lock( + IN cl_obj_t * const p_obj ) +{ + CL_ASSERT( p_obj->state == CL_INITIALIZED || + p_obj->state == CL_DESTROYING ); + cl_spinlock_acquire( &p_obj->lock ); +} +/* +* PARAMETERS +* p_obj +* [in] A pointer to the object whose lock to acquire. +* +* RETURN VALUE +* This function does not return a value. +* +* SEE ALSO +* Object, cl_obj_t, cl_obj_unlock +*********/ + + +/****f* Component Library: Object/cl_obj_unlock +* NAME +* cl_obj_unlock +* +* DESCRIPTION +* Releases an object's lock previously acquired by a call to cl_obj_lock. +* +* SYNOPSIS +*/ +CL_INLINE void CL_API +cl_obj_unlock( + IN cl_obj_t * const p_obj ) +{ + CL_ASSERT( p_obj->state == CL_INITIALIZED || + p_obj->state == CL_DESTROYING ); + cl_spinlock_release( &p_obj->lock ); +} +/* +* PARAMETERS +* p_obj +* [in] A pointer to the object whose lock to release. +* +* RETURN VALUE +* This function does not return a value. +* +* SEE ALSO +* Object, cl_obj_t, cl_obj_lock +*********/ + + +/****s* Component Library: Object/cl_obj_rel_t +* NAME +* cl_obj_rel_t +* +* DESCRIPTION +* Identifies a dependent relationship between two objects. +* +* SYNOPSIS +*/ +typedef struct _cl_obj_rel +{ + cl_pool_item_t pool_item; /* Must be first. */ + struct _cl_obj *p_parent_obj; + + cl_list_item_t list_item; + struct _cl_obj *p_child_obj; + +} cl_obj_rel_t; +/* +* FIELDS +* pool_item +* An item used to store the relationship in a free pool maintained +* by the object manager. This field is also used by the parent object +* to store the relationship in its child_list. +* +* p_parent_obj +* A reference to the parent object for the relationship. +* +* list_item +* This field is used by the child object to store the relationship in +* its parent_list. +* +* p_child_obj +* A reference to the child object for the relationship. +* +* NOTES +* This structure is used to define all dependent relationships. Dependent +* relationships are those where the destruction of a parent object result in +* the destruction of child objects. For other types of relationships, simple +* references between objects may be used. +* +* Relationship items are stored in lists maintained by both the parent +* and child objects. References to both objects exist while the +* relationship is maintained. Typically, relationships are defined by +* the user by calling cl_obj_insert_rel, but are destroyed automatically +* via an object's destruction process. +* +* SEE ALSO +* Object, cl_rel_alloc, cl_rel_free, cl_obj_insert_rel, cl_obj_remove_rel, +* cl_obj_destroy +*********/ + + + +/****f* Component Library: Object/cl_rel_alloc +* NAME +* cl_rel_alloc +* +* DESCRIPTION +* Retrieves an object relationship item from the object manager. +* +* SYNOPSIS +*/ +CL_EXPORT cl_obj_rel_t* CL_API +cl_rel_alloc(void); +/* +* PARAMETERS +* None. +* +* RETURN VALUE +* A reference to an allocated relationship object, or NULL if no relationship +* object could be allocated. +* +* NOTES +* This routine retrieves a cl_obj_rel_t structure from a pool maintained +* by the object manager. The pool automatically grows as needed. +* +* Relationship items are used to describe a dependent relationship between +* a parent and child object. In cases where a child has a fixed number of +* relationships, the user may be able to allocate and manage the cl_obj_rel_t +* structures more efficiently than obtaining the structures through this call. +* +* SEE ALSO +* Object, cl_rel_free, cl_obj_insert_rel, cl_obj_remove_rel, cl_obj_destroy +*********/ + + + +/****f* Component Library: Object/cl_rel_free +* NAME +* cl_rel_free +* +* DESCRIPTION +* Return a relationship object to the global object manager. +* +* SYNOPSIS +*/ +CL_EXPORT void CL_API +cl_rel_free( + IN cl_obj_rel_t * const p_rel ); +/* +* PARAMETERS +* p_rel +* [in] A reference to the relationship item to free. +* +* RETURN VALUE +* None. +* +* NOTES +* Relationship items must not be freed until both the parent and child +* object have removed their references to one another. Relationship items +* may be freed after calling cl_obj_remove_rel or after the associated +* child object's free callback has been invoked. In the latter case, the +* invalid relationship items are referenced by the child object's parent_list. +* +* SEE ALSO +* Object, cl_rel_alloc, cl_obj_insert_rel, cl_obj_remove_rel, cl_obj_destroy +*********/ + + + +/****f* Component Library: Object/cl_obj_insert_rel +* NAME +* cl_obj_insert_rel +* +* DESCRIPTION +* Forms a relationship between two objects, with the existence of the child +* object dependent on the parent. +* +* SYNOPSIS +*/ +CL_EXPORT cl_status_t CL_API +cl_obj_insert_rel( + IN cl_obj_rel_t * const p_rel, + IN cl_obj_t * const p_parent_obj, + IN cl_obj_t * const p_child_obj ); +/* +* PARAMETERS +* p_rel +* [in] A reference to an unused relationship item. +* +* p_parent_obj +* [in] A reference to the parent object. +* +* p_child_obj +* [in] A reference to the child object. +* +* RETURN VALUE +* None. +* +* NOTES +* This call inserts a relationship between the parent and child object. +* The relationship allows for the automatic destruction of the child object +* if the parent is destroyed. +* +* A given object can have multiple parent and child objects, but the +* relationships must form into an object tree. That is, there cannot be any +* cycles formed through the parent-child relationships. (For example, an +* object cannot be both the parent and a child of a second object.) +* +* SEE ALSO +* Object, cl_rel_alloc, cl_rel_free, cl_obj_remove_rel, cl_obj_destroy +*********/ + + + +/****f* Component Library: Object/cl_obj_insert_rel_parent_locked +* NAME +* cl_obj_insert_rel_parent_locked +* +* DESCRIPTION +* Forms a relationship between two objects, with the existence of the child +* object dependent on the parent. The parent's object lock is held. +* +* SYNOPSIS +*/ +CL_EXPORT cl_status_t CL_API +cl_obj_insert_rel_parent_locked( + IN cl_obj_rel_t * const p_rel, + IN cl_obj_t * const p_parent_obj, + IN cl_obj_t * const p_child_obj ); +/* +* PARAMETERS +* p_rel +* [in] A reference to an unused relationship item. +* +* p_parent_obj +* [in] A reference to the parent object. +* +* p_child_obj +* [in] A reference to the child object. +* +* RETURN VALUE +* None. +* +* NOTES +* This call inserts a relationship between the parent and child object. +* The relationship allows for the automatic destruction of the child object +* if the parent is destroyed. +* +* A given object can have multiple parent and child objects, but the +* relationships must form into an object tree. That is, there cannot be any +* cycles formed through the parent-child relationships. (For example, an +* object cannot be both the parent and a child of a second object.) +* +* This call requires the caller to already hold the parent object's lock. +* +* SEE ALSO +* Object, cl_rel_alloc, cl_rel_free, cl_obj_remove_rel, cl_obj_destroy +*********/ + + + +/****f* Component Library: Object/cl_obj_remove_rel +* NAME +* cl_obj_remove_rel +* +* DESCRIPTION +* Manually removes a relationship between two objects. +* +* SYNOPSIS +*/ +CL_EXPORT void CL_API +cl_obj_remove_rel( + IN cl_obj_rel_t * const p_rel ); +/* +* PARAMETERS +* p_rel +* [in] A reference to the relationship to remove. +* +* RETURN VALUE +* None. +* +* NOTES +* This routine permits a user to manually remove a dependent relationship +* between two objects. When removing a relationship using this call, the +* user must ensure that objects referenced by the relationship are not +* destroyed, either directly or indirectly via a parent. +* +* SEE ALSO +* Object, cl_rel_alloc, cl_rel_free, cl_obj_insert_rel, cl_obj_destroy +*********/ + + +#ifdef __cplusplus +} +#endif + + +#endif /* __CL_OBJ_H__ */ diff --git a/branches/WOF2-3/inc/complib/cl_passivelock.h b/branches/WOF2-3/inc/complib/cl_passivelock.h new file mode 100644 index 00000000..a1a5d117 --- /dev/null +++ b/branches/WOF2-3/inc/complib/cl_passivelock.h @@ -0,0 +1,433 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * 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 writting. It is similar + * in behavior to the passive lock, but works at passive only. + * + * Environment: + * All + */ + + +#ifndef _CL_PASSIVE_LOCK_H_ +#define _CL_PASSIVE_LOCK_H_ + + +#include +#include + + +/****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 +{ + cl_event_t reader_event; + cl_event_t writer_event; + atomic32_t reader_count; + +} cl_plock_t; +/* +* FIELDS +* reader_event +* Event used to synchronize shared access to the lock. +* +* writer_event +* Event used to synchronize exclusive access to the lock. +* +* reader_count +* Number of threads holding the lock for shared access. +* +* 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 +*/ +CL_INLINE void CL_API +cl_plock_construct( + IN cl_plock_t* const p_lock ) +{ + CL_ASSERT( p_lock ); + + p_lock->reader_count = 0; + cl_event_construct( &p_lock->reader_event ); + cl_event_construct( &p_lock->writer_event ); +} +/* +* 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 +*/ +CL_INLINE void CL_API +cl_plock_destroy( + IN cl_plock_t* const p_lock ) +{ + CL_ASSERT( p_lock ); + CL_ASSERT( p_lock->reader_count == 0 ); + + cl_event_destroy( &p_lock->writer_event ); + cl_event_destroy( &p_lock->reader_event ); +} +/* +* 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 +*/ +CL_INLINE cl_status_t CL_API +cl_plock_init( + IN cl_plock_t* const p_lock ) +{ + cl_status_t status; + + CL_ASSERT( p_lock ); + + cl_plock_construct( p_lock ); + + status = cl_event_init( &p_lock->writer_event, FALSE ); + if( status != CL_SUCCESS ) + { + cl_plock_destroy( p_lock ); + return( status ); + } + + status = cl_event_init( &p_lock->reader_event, FALSE ); + if( status != CL_SUCCESS ) + { + cl_plock_destroy( p_lock ); + return( status ); + } + + /* + * Set the writer event to signalled so that the first + * wait operation succeeds. + */ + status = cl_event_signal( &p_lock->writer_event ); + if( status != CL_SUCCESS ) + { + cl_plock_destroy( p_lock ); + return( status ); + } + + /* + * Set the reader event to signalled so that the first + * wait operation succeeds. + */ + status = cl_event_signal( &p_lock->reader_event ); + if( status != CL_SUCCESS ) + { + cl_plock_destroy( p_lock ); + return( status ); + } + + 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, and cl_plock_excl_release. +* +* SEE ALSO +* Passive Lock, cl_plock_construct, cl_plock_destroy, +* cl_plock_excl_acquire, cl_plock_excl_release, +* 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 +*/ +CL_INLINE void CL_API +cl_plock_acquire( + IN cl_plock_t* const p_lock ) +{ + cl_status_t status; + + CL_ASSERT( p_lock ); + + status = + cl_event_wait_on( &p_lock->reader_event, EVENT_NO_TIMEOUT, FALSE ); + CL_ASSERT( status == CL_SUCCESS ); + + /* + * Increment the reader count to block a thread trying for exclusive + * access. + */ + cl_atomic_inc( &p_lock->reader_count ); +#ifdef DBG_PASSIVE_LOCKS + cl_dbg_out( "cl_plock_acquire: ReaderCount = %u\n", + p_lock->reader_count ); +#endif + /* + * Release the reader event to satisfy the wait of another reader + * or a writer. + */ + cl_event_signal( &p_lock->reader_event ); +} +/* +* 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 +*/ +CL_INLINE void CL_API +cl_plock_excl_acquire( + IN cl_plock_t* const p_lock ) +{ + cl_status_t status; + + CL_ASSERT( p_lock ); + + /* Acquire the reader event. This will block new readers. */ + status = + cl_event_wait_on( &p_lock->reader_event, EVENT_NO_TIMEOUT, FALSE ); + CL_ASSERT( status == CL_SUCCESS ); + + /* Wait for the writer event until all readers have exited. */ + while( p_lock->reader_count ) + { +#ifdef DBG_PASSIVE_LOCKS + cl_dbg_out( "cl_plock_excl_acquire: ReaderCount = %u\n", + p_lock->reader_count ); +#endif + status = + cl_event_wait_on( &p_lock->writer_event, EVENT_NO_TIMEOUT, FALSE ); + CL_ASSERT( status == CL_SUCCESS ); + } + +#ifdef DBG_PASSIVE_LOCKS + cl_dbg_out( "cl_plock_excl_acquire: Exit\n" ); +#endif +} +/* +* 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 +*/ +CL_INLINE void CL_API +cl_plock_release( + IN cl_plock_t* const p_lock ) +{ + CL_ASSERT( p_lock ); + + if( p_lock->reader_count ) + { + + /* + * Decrement the count to allow a thread waiting for exclusive + * access to continue. + */ + cl_atomic_dec( &p_lock->reader_count ); + + #ifdef DBG_PASSIVE_LOCKS + cl_dbg_out( "cl_plock_release: ReaderCount = %u\n", + p_lock->reader_count ); + #endif + + /* Release a writer, if any. */ + cl_event_signal( &p_lock->writer_event ); + } + else + { + /* Release threads waiting to acquire the lock. */ + cl_event_signal( &p_lock->reader_event ); + cl_event_signal( &p_lock->writer_event ); + + #ifdef DBG_PASSIVE_LOCKS + cl_dbg_out( "cl_plock_release: Exit\n" ); + #endif + } +} +/* +* 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 +*********/ + + +#endif /* _CL_PASSIVE_LOCK_H_ */ diff --git a/branches/WOF2-3/inc/complib/cl_perf.h b/branches/WOF2-3/inc/complib/cl_perf.h new file mode 100644 index 00000000..58c4d634 --- /dev/null +++ b/branches/WOF2-3/inc/complib/cl_perf.h @@ -0,0 +1,807 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * Abstract: + * Declaration of performance tracking. + * + * Environment: + * All + */ + + +#ifndef _CL_PERF_H_ +#define _CL_PERF_H_ + + +#include +#include +#include + + +/****h* Component Library/Performance Counters +* NAME +* Performance Counters +* +* DESCRIPTION +* The performance counters allows timing operations to benchmark +* software performance and help identify potential bottlenecks. +* +* All performance counters are NULL macros when disabled, preventing them +* from adversly affecting performance in builds where the counters are not +* used. +* +* Each counter records elapsed time in micro-seconds, minimum time elapsed, +* and total number of samples. +* +* Each counter is independently protected by a spinlock, allowing use of +* the counters in multi-processor environments. +* +* The impact of serializing access to performance counters is measured, +* allowing measurements to be corrected as necessary. +* +* NOTES +* Performance counters do impact performance, and should only be enabled +* when gathering data. Counters can be enabled or disabled on a per-user +* basis at compile time. To enable the counters, users should define +* the PERF_TRACK_ON keyword before including the cl_perf.h file. +* Undefining the PERF_TRACK_ON keyword disables the performance counters. +* When disabled, all performance tracking calls resolve to no-ops. +* +* When using performance counters, it is the user's responsibility to +* maintain the counter indexes. It is recomended that users define an +* enumerated type to use for counter indexes. It improves readability +* and simplifies maintenance by reducing the work necessary in managing +* the counter indexes. +* +* SEE ALSO +* Structures: +* cl_perf_t +* +* Initialization: +* cl_perf_construct, cl_perf_init, cl_perf_destroy +* +* Manipulation +* cl_perf_reset, cl_perf_display, cl_perf_start, cl_perf_update, +* cl_perf_log, cl_perf_stop +* +* Macros: +* PERF_DECLARE, PERF_DECLARE_START +*********/ + + +/* + * Number of times the counter calibration test is executed. This is used + * to determine the average time to use a performance counter. + */ +#define PERF_CALIBRATION_TESTS 100000 + + +/****i* Component Library: Performance Counters/cl_perf_data_t +* NAME +* cl_perf_data_t +* +* DESCRIPTION +* The cl_perf_data_t structure is used to tracking information +* for a single counter. +* +* SYNOPSIS +*/ +typedef struct _cl_perf_data +{ + uint64_t count; + uint64_t total_time; + uint64_t min_time; + cl_spinlock_t lock; + +} cl_perf_data_t; +/* +* FIELDS +* count +* Number of samples in the counter. +* +* total_time +* Total time for all samples, in microseconds. +* +* min_time +* Minimum time for any sample in the counter, in microseconds. +* +* lock +* Spinlock to serialize counter updates. +* +* SEE ALSO +* Performance Counters +*********/ + + +/****i* Component Library: Performance Counters/cl_perf_t +* NAME +* cl_perf_t +* +* DESCRIPTION +* The cl_perf_t structure serves as a container for a group of performance +* counters and related calibration data. +* +* This structure should be treated as opaque and be manipulated only through +* the provided functions. +* +* SYNOPSIS +*/ +typedef struct _cl_perf +{ + cl_perf_data_t *data_array; + uintn_t size; + uint64_t locked_calibration_time; + uint64_t normal_calibration_time; + cl_state_t state; + +} cl_perf_t; +/* +* FIELDS +* data_array +* Pointer to the array of performance counters. +* +* size +* Number of counters in the counter array. +* +* locked_calibration_time +* Time needed to update counters while holding a spinlock. +* +* normal_calibration_time +* Time needed to update counters while not holding a spinlock. +* +* state +* State of the performance counter provider. +* +* SEE ALSO +* Performance Counters, cl_perf_data_t +*********/ + + +/****f* Component Library: Performance Counters/cl_perf_construct +* NAME +* cl_perf_construct +* +* DESCRIPTION +* The cl_perf_construct macro constructs a performance +* tracking container. +* +* SYNOPSIS +*/ +void +cl_perf_construct( + IN cl_perf_t* const p_perf ); +/* +* PARAMETERS +* p_perf +* [in] Pointer to a performance counter container to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* cl_perf_construct allows calling cl_perf_destroy without first calling +* cl_perf_init. +* +* Calling cl_perf_construct is a prerequisite to calling any other +* perfromance counter function except cl_perf_init. +* +* This function is implemented as a macro and has no effect when +* performance counters are disabled. +* +* SEE ALSO +* Performance Counters, cl_perf_init, cl_perf_destroy +*********/ + + +/****f* Component Library: Performance Counters/cl_perf_init +* NAME +* cl_perf_init +* +* DESCRIPTION +* The cl_perf_init function initializes a performance counter container +* for use. +* +* SYNOPSIS +*/ +cl_status_t +cl_perf_init( + IN cl_perf_t* const p_perf, + IN const uintn_t num_counters ); +/* +* PARAMETERS +* p_perf +* [in] Pointer to a performance counter container to initalize. +* +* num_cntrs +* [in] Number of counters to allocate in the container. +* +* RETURN VALUES +* CL_SUCCESS if initialization was successful. +* +* CL_INSUFFICIENT_MEMORY if there was not enough memory to initialize +* the container. +* +* CL_ERROR if an error was encountered initializing the locks for the +* performance counters. +* +* NOTES +* This function allocates all memory required for the requested number of +* counters and initializes all locks protecting those counters. After a +* successful initialization, cl_perf_init calibrates the counters and +* resets their value. +* +* This function is implemented as a macro and has no effect when +* performance counters are disabled. +* +* SEE ALSO +* Performance Counters, cl_perf_construct, cl_perf_destroy, cl_perf_display +*********/ + + +/****f* Component Library: Performance Counters/cl_perf_destroy +* NAME +* cl_perf_destroy +* +* DESCRIPTION +* The cl_perf_destroy function destroys a performance tracking container. +* +* SYNOPSIS +*/ +void +cl_perf_destroy( + IN cl_perf_t* const p_perf, + IN const boolean_t display ); +/* +* PARAMETERS +* p_perf +* [in] Pointer to a performance counter container to destroy. +* +* display +* [in] If TRUE, causes the performance counters to be displayed. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* cl_perf_destroy frees all resources allocated in a call to cl_perf_init. +* If the display parameter is set to TRUE, displays all counter values +* before deallocating resources. +* +* This function should only be called after a call to cl_perf_construct +* or cl_perf_init. +* +* This function is implemented as a macro and has no effect when +* performance counters are disabled. +* +* SEE ALSO +* Performance Counters, cl_perf_construct, cl_perf_init +*********/ + + +/****f* Component Library: Performance Counters/cl_perf_reset +* NAME +* cl_perf_reset +* +* DESCRIPTION +* The cl_perf_reset function resets the counters contained in +* a performance tracking container. +* +* SYNOPSIS +*/ +void +cl_perf_reset( + IN cl_perf_t* const p_perf ); +/* +* PARAMETERS +* p_perf +* [in] Pointer to a performance counter container whose counters +* to reset. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* This function is implemented as a macro and has no effect when +* performance counters are disabled. +* +* SEE ALSO +* Performance Counters +*********/ + + +/****f* Component Library: Performance Counters/cl_perf_display +* NAME +* cl_perf_display +* +* DESCRIPTION +* The cl_perf_display function displays the current performance +* counter values. +* +* SYNOPSIS +*/ +void +cl_perf_display( + IN const cl_perf_t* const p_perf ); +/* +* PARAMETERS +* p_perf +* [in] Pointer to a performance counter container whose counter +* values to display. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* This function is implemented as a macro and has no effect when +* performance counters are disabled. +* +* SEE ALSO +* Performance Counters, cl_perf_init +*********/ + + +/****d* Component Library: Performance Counters/PERF_DECLARE +* NAME +* PERF_DECLARE +* +* DESCRIPTION +* The PERF_DECLARE macro declares a performance counter variable used +* to store the starting time of a timing sequence. +* +* SYNOPSIS +* PERF_DECLARE( index ) +* +* PARAMETERS +* index +* [in] Index of the performance counter for which to use this +* variable. +* +* NOTES +* Variables should generally be declared on the stack to support +* multi-threading. In cases where a counter needs to be used to +* time operations accross multiple functions, care must be taken to +* ensure that the start time stored in this variable is not overwritten +* before the related performance counter has been updated. +* +* This macro has no effect when performance counters are disabled. +* +* SEE ALSO +* Performance Counters, PERF_DECLARE_START, cl_perf_start, cl_perf_log, +* cl_perf_stop +*********/ + + +/****d* Component Library: Performance Counters/PERF_DECLARE_START +* NAME +* PERF_DECLARE_START +* +* DESCRIPTION +* The PERF_DECLARE_START macro declares a performance counter variable +* and sets it to the starting time of a timed sequence. +* +* SYNOPSIS +* PERF_DECLARE_START( index ) +* +* PARAMETERS +* index +* [in] Index of the performance counter for which to use this +* variable. +* +* NOTES +* Variables should generally be declared on the stack to support +* multi-threading. +* +* This macro has no effect when performance counters are disabled. +* +* SEE ALSO +* Performance Counters, PERF_DECLARE, cl_perf_start, cl_perf_log, +* cl_perf_stop +*********/ + + +/****d* Component Library: Performance Counters/cl_perf_start +* NAME +* cl_perf_start +* +* DESCRIPTION +* The cl_perf_start macro sets the starting value of a timed sequence. +* +* SYNOPSIS +*/ +void +cl_perf_start( + IN const uintn_t index ); +/* +* PARAMETERS +* index +* [in] Index of the performance counter to set. +* +* NOTES +* This macro has no effect when performance counters are disabled. +* +* SEE ALSO +* Performance Counters, PERF_DECLARE, PERF_DECLARE_START, cl_perf_log, +* cl_perf_update, cl_perf_stop +*********/ + + +/****d* Component Library: Performance Counters/cl_perf_clr +* NAME +* cl_perf_clr +* +* DESCRIPTION +* The cl_perf_clr macro clears a counter variable. +* +* SYNOPSIS +*/ +void +cl_perf_inc( + IN const uintn_t index ); +/* +* PARAMETERS +* index +* [in] Index of the performance counter to set. +* +* NOTES +* This macro has no effect when performance counters are disabled. +* +* SEE ALSO +* Performance Counters, PERF_DECLARE, PERF_DECLARE_START, cl_perf_log, +* cl_perf_update, cl_perf_stop +*********/ + + +/****d* Component Library: Performance Counters/cl_perf_inc +* NAME +* cl_perf_inc +* +* DESCRIPTION +* The cl_perf_inc macro increments a counter variable by one. +* +* SYNOPSIS +*/ +void +cl_perf_inc( + IN const uintn_t index ); +/* +* PARAMETERS +* index +* [in] Index of the performance counter to set. +* +* NOTES +* This macro has no effect when performance counters are disabled. +* +* SEE ALSO +* Performance Counters, PERF_DECLARE, PERF_DECLARE_START, cl_perf_log, +* cl_perf_update, cl_perf_stop +*********/ + + +/****d* Component Library: Performance Counters/cl_perf_update +* NAME +* cl_perf_update +* +* DESCRIPTION +* The cl_perf_update macro adds a timing sample based on a provided start +* time to a counter in a performance counter container. +* +* SYNOPSIS +*/ +void +cl_perf_update( + IN cl_perf_t* const p_perf, + IN const uintn_t index, + IN const uint64_t start_time ); +/* +* PARAMETERS +* p_perf +* [in] Pointer to a performance counter container to whose counter +* the sample should be added. +* +* index +* [in] Number of the performance counter to update with a new sample. +* +* start_time +* [in] Timestamp to use as the start time for the timing sample. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* This macro has no effect when performance counters are disabled. +* +* SEE ALSO +* Performance Counters, PERF_DECLARE, PERF_DECLARE_START, cl_perf_start, +* cl_perf_lob, cl_perf_stop +*********/ + + +/****d* Component Library: Performance Counters/cl_perf_update_ctr +* NAME +* cl_perf_update_ctr +* +* DESCRIPTION +* The cl_perf_update_ctr macro updates a counter in a performance +* counter container. +* +* SYNOPSIS +*/ +void +cl_perf_update_ctr( + IN cl_perf_t* const p_perf, + IN const uintn_t index ); +/* +* PARAMETERS +* p_perf +* [in] Pointer to a performance counter container to whose counter +* the sample should be added. +* +* index +* [in] Number of the performance counter to update with a new sample. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* This macro has no effect when performance counters are disabled. +* +* SEE ALSO +* Performance Counters, PERF_DECLARE, PERF_DECLARE_START, cl_perf_start, +* cl_perf_lob, cl_perf_stop +*********/ + + +/****d* Component Library: Performance Counters/cl_perf_log +* NAME +* cl_perf_log +* +* DESCRIPTION +* The cl_perf_log macro adds a given timing sample to a +* counter in a performance counter container. +* +* SYNOPSIS +*/ +void +cl_perf_log( + IN cl_perf_t* const p_perf, + IN const uintn_t index, + IN const uint64_t pc_total_time ); +/* +* PARAMETERS +* p_perf +* [in] Pointer to a performance counter container to whose counter +* the sample should be added. +* +* index +* [in] Number of the performance counter to update with a new sample. +* +* pc_total_time +* [in] Total elapsed time for the sample being added. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* This macro has no effect when performance counters are disabled. +* +* SEE ALSO +* Performance Counters, PERF_DECLARE, PERF_DECLARE_START, cl_perf_start, +* cl_perf_update, cl_perf_stop +*********/ + + +/****d* Component Library: Performance Counters/cl_perf_stop +* NAME +* cl_perf_stop +* +* DESCRIPTION +* The cl_perf_log macro updates a counter in a performance counter +* container with a new timing sample. +* +* SYNOPSIS +*/ +void +cl_perf_stop( + IN cl_perf_t* const p_perf, + IN const uintn_t index ); +/* +* PARAMETERS +* p_perf +* [in] Pointer to a performance counter container to whose counter +* a sample should be added. +* +* index +* [in] Number of the performance counter to update with a new sample. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* The ending time stamp is taken and elapsed time calculated before updating +* the specified counter. +* +* This macro has no effect when performance counters are disabled. +* +* SEE ALSO +* Performance Counters, PERF_DECLARE, PERF_DECLARE_START, cl_perf_start, +* cl_perf_log +*********/ + + +/* + * PERF_TRACK_ON must be defined by the user before including this file to + * enable performance tracking. To disable tracking, users should undefine + * PERF_TRACK_ON. + */ +#if defined( PERF_TRACK_ON ) +/* + * Enable performance tracking. + */ + +#define cl_perf_construct( p_perf ) \ + __cl_perf_construct( p_perf ) +#define cl_perf_init( p_perf, num_counters ) \ + __cl_perf_init( p_perf, num_counters ) +#define cl_perf_destroy( p_perf, display ) \ + __cl_perf_destroy( p_perf, display ) +#define cl_perf_reset( p_perf ) \ + __cl_perf_reset( p_perf ) +#define cl_perf_display( p_perf ) \ + __cl_perf_display( p_perf ) +#define PERF_DECLARE( index ) \ + uint64_t Pc##index +#define PERF_DECLARE_START( index ) \ + uint64 Pc##index = cl_get_time_stamp() +#define cl_perf_start( index ) \ + (Pc##index = cl_get_time_stamp()) +#define cl_perf_clr( index ) \ + (Pc##index = 0) +#define cl_perf_inc( index ) \ + (Pc##index++) +#define cl_perf_log( p_perf, index, pc_total_time ) \ +{\ + /* Update the performance data. This requires synchronization. */ \ + cl_spinlock_acquire( &((cl_perf_t*)p_perf)->data_array[index].lock ); \ + \ + ((cl_perf_t*)p_perf)->data_array[index].total_time += pc_total_time; \ + ((cl_perf_t*)p_perf)->data_array[index].count++; \ + if( pc_total_time < ((cl_perf_t*)p_perf)->data_array[index].min_time ) \ + ((cl_perf_t*)p_perf)->data_array[index].min_time = pc_total_time; \ + \ + cl_spinlock_release( &((cl_perf_t*)p_perf)->data_array[index].lock ); \ +} +#define cl_perf_update( p_perf, index, start_time ) \ +{\ + /* Get the ending time stamp, and calculate the total time. */ \ + uint64_t pc_total_time = cl_get_time_stamp() - start_time;\ + /* Using stack variable for start time, stop and log */ \ + cl_perf_log( p_perf, index, pc_total_time ); \ +} +#define cl_perf_update_ctr( p_perf, index ) \ + cl_perf_log( p_perf, index, Pc##index ) +#define cl_perf_stop( p_perf, index ) \ +{\ + cl_perf_update( p_perf, index, Pc##index );\ +} + +#define cl_get_perf_values( p_perf, index, p_total, p_min, p_count ) \ +{\ + *p_total = p_perf->data_array[index].total_time; \ + *p_min = p_perf->data_array[index].min_time; \ + *p_count = p_perf->data_array[index].count; \ +} + +#define cl_get_perf_calibration( p_perf, p_locked_time, p_normal_time ) \ +{\ + *p_locked_time = p_perf->locked_calibration_time; \ + *p_normal_time = p_perf->normal_calibration_time; \ +} + +#define cl_get_perf_string( p_perf, i ) \ +"CL Perf:\t%lu\t%"PRIu64"\t%"PRIu64"\t%"PRIu64"\n", \ + i, p_perf->data_array[i].total_time, \ + p_perf->data_array[i].min_time, p_perf->data_array[i].count + +#else /* PERF_TRACK_ON */ +/* + * Disable performance tracking. + */ + +#define cl_perf_construct( p_perf ) +#define cl_perf_init( p_perf, num_cntrs ) CL_SUCCESS +#define cl_perf_destroy( p_perf, display ) +#define cl_perf_reset( p_perf ) +#define cl_perf_display( p_perf ) +#define PERF_DECLARE( index ) +#define PERF_DECLARE_START( index ) +#define cl_perf_start( index ) +#define cl_perf_clr( index ) +#define cl_perf_inc( index ) +#define cl_perf_log( p_perf, index, pc_total_time ) +#define cl_perf_update( p_perf, index, start_time ) +#define cl_perf_update_ctr( p_perf, index ) +#define cl_perf_stop( p_perf, index ) +#define cl_get_perf_values( p_perf, index, p_total, p_min, p_count ) +#define cl_get_perf_calibration( p_perf, p_locked_time, p_normal_time ) +#endif /* PERF_TRACK_ON */ + + +/* + * Internal performance tracking functions. Users should never call these + * functions directly. Instead, use the macros defined above to resolve + * to these functions when PERF_TRACK_ON is defined, which allows disabling + * performance tracking. + */ + + +/* + * Initialize the state of the performance tracking structure. + */ +CL_EXPORT void CL_API +__cl_perf_construct( + IN cl_perf_t* const p_perf ); + +/* + * Size the performance tracking information and initialize all + * related structures. + */ +CL_EXPORT cl_status_t CL_API +__cl_perf_init( + IN cl_perf_t* const p_perf, + IN const uintn_t num_counters ); + +/* + * Destroy the performance tracking data. + */ +CL_EXPORT void CL_API +__cl_perf_destroy( + IN cl_perf_t* const p_perf, + IN const boolean_t display ); + +/* + * Reset the performance tracking data. + */ +CL_EXPORT void CL_API +__cl_perf_reset( + IN cl_perf_t* const p_perf ); + +/* + * Display the current performance tracking data. + */ +CL_EXPORT void CL_API +__cl_perf_display( + IN const cl_perf_t* const p_perf ); + + +#endif /* _CL_PERF_H_ */ diff --git a/branches/WOF2-3/inc/complib/cl_pool.h b/branches/WOF2-3/inc/complib/cl_pool.h new file mode 100644 index 00000000..df09b500 --- /dev/null +++ b/branches/WOF2-3/inc/complib/cl_pool.h @@ -0,0 +1,594 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * Abstract: + * Declaration of the pool. + * The pool manages a pool of objects. + * The pool can grow to meet demand, limited only by system memory. + * + * Environment: + * All + */ + + +#ifndef _CL_POOL_H_ +#define _CL_POOL_H_ + + +#include + + +/****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_API *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_API *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 +*********/ + + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + +/****f* Component Library: Pool/cl_pool_construct +* NAME +* cl_pool_construct +* +* DESCRIPTION +* The cl_pool_construct function constructs a pool. +* +* SYNOPSIS +*/ +CL_EXPORT void CL_API +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 +*/ +CL_INLINE uint32_t CL_API +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_EXPORT cl_status_t CL_API +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 +*/ +CL_INLINE void CL_API +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 +*/ +CL_INLINE size_t CL_API +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 +*/ +CL_INLINE void* CL_API +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->list_obj.p_object ); + return( (void*)p_pool_obj->list_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 +*/ +CL_INLINE void CL_API +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->list_obj.p_object == p_object ); + + cl_qcpool_put( &p_pool->qcpool, (cl_pool_item_t*)p_pool_obj ); +} +/* +* 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 +*/ +CL_INLINE cl_status_t CL_API +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 +*********/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + + +#endif /* _CL_POOL_H_ */ diff --git a/branches/WOF2-3/inc/complib/cl_ptr_vector.h b/branches/WOF2-3/inc/complib/cl_ptr_vector.h new file mode 100644 index 00000000..bfba4f73 --- /dev/null +++ b/branches/WOF2-3/inc/complib/cl_ptr_vector.h @@ -0,0 +1,878 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * Abstract: + * This file contains pointer vector definitions. Pointer Vector provides + * dynmically resizable array functionality. + * + * Environment: + * All + */ + + +#ifndef _CL_PTR_VECTOR_H_ +#define _CL_PTR_VECTOR_H_ + + +#include + + +/****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_obj, 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_API *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_API *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 +*********/ + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/****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 +*/ +CL_EXPORT void CL_API +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_EXPORT cl_status_t CL_API +cl_ptr_vector_init( + IN cl_ptr_vector_t* const p_vector, + IN const size_t min_cap, + IN const size_t grow_size ); +/* +* PARAMETERS +* p_vector +* [in] Pointer to a cl_ptr_vector_t structure to inititalize. +* +* min_cap +* [in] Initial number of elements the vector will support. +* The vector is always initialized with a size of zero. +* +* 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 +*/ +CL_EXPORT void CL_API +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 +*/ +CL_INLINE size_t CL_API +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 +*/ +CL_INLINE size_t CL_API +cl_ptr_vector_get_size( + IN const cl_ptr_vector_t* const p_vector ) +{ + CL_ASSERT( p_vector ); + CL_ASSERT( p_vector->state == CL_UNINITIALIZED || + p_vector->state == CL_INITIALIZED ); + + return( 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 +*/ +CL_INLINE void* CL_API +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_EXPORT cl_status_t CL_API +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_EXPORT cl_status_t CL_API +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 +*/ +CL_INLINE cl_status_t CL_API +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 +*/ +CL_EXPORT void* CL_API +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_EXPORT cl_status_t CL_API +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_EXPORT cl_status_t CL_API +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_EXPORT cl_status_t CL_API +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 +*/ +CL_EXPORT void CL_API +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 +*/ +CL_EXPORT size_t CL_API +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 +*/ +CL_EXPORT size_t CL_API +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 +*********/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* _CL_PTR_VECTOR_H_ */ diff --git a/branches/WOF2-3/inc/complib/cl_qcomppool.h b/branches/WOF2-3/inc/complib/cl_qcomppool.h new file mode 100644 index 00000000..8cdbb55f --- /dev/null +++ b/branches/WOF2-3/inc/complib/cl_qcomppool.h @@ -0,0 +1,785 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * 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. + * + * Environment: + * All + */ + + +#ifndef _CL_QUICK_COMPOSITE_POOL_H_ +#define _CL_QUICK_COMPOSITE_POOL_H_ + + +#include +#include + + +/****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_ + /* Pad to make the cl_pool_obj structure line up properly */ + void *pad; + /* 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_list_obj_t list_obj; +#ifdef _DEBUG_ + /* Pointer to the owner pool used for sanity checks. */ + struct _cl_qcpool *p_pool; +#endif + +} 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_API *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_API *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 +*********/ + + + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + +/****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 +*/ +CL_EXPORT void CL_API +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 +*/ +CL_INLINE uint32_t CL_API +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_EXPORT cl_status_t CL_API +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 +*/ +CL_EXPORT void CL_API +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 +*/ +CL_INLINE size_t CL_API +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_EXPORT cl_pool_item_t* CL_API +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 +*/ +CL_INLINE void CL_API +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 +*/ +CL_INLINE void CL_API +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_EXPORT cl_status_t CL_API +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 +*********/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + + +#endif /* _CL_QUICK_COMPOSITE_POOL_H_ */ diff --git a/branches/WOF2-3/inc/complib/cl_qlist.h b/branches/WOF2-3/inc/complib/cl_qlist.h new file mode 100644 index 00000000..4c411f6e --- /dev/null +++ b/branches/WOF2-3/inc/complib/cl_qlist.h @@ -0,0 +1,1756 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * Abstract: + * Declaration of quick list. + * + * Environment: + * All + */ + + +#ifndef _CL_QUICK_LIST_H_ +#define _CL_QUICK_LIST_H_ + + +#include + + +/****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 +*********/ + + +/****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_API *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_API *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 +*********/ + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/****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 +*/ +CL_INLINE void CL_API +__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 +*/ +CL_INLINE void CL_API +__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 ); + CL_ASSERT( p_list_item->p_next ); + CL_ASSERT( p_list_item->p_prev ); + + /* 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; + p_list_item->p_list = 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 +*/ +CL_INLINE void CL_API +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 +*/ +CL_INLINE void* CL_API +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 +*********/ + + +CL_INLINE void CL_API +__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 +*/ +CL_INLINE void CL_API +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 +*/ +CL_INLINE size_t CL_API +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( 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 +*/ +CL_INLINE boolean_t CL_API +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 +*/ +CL_INLINE cl_list_item_t* CL_API +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 ); + + /* 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 +*/ +CL_INLINE cl_list_item_t* CL_API +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 ); + + /* 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 +*/ +CL_INLINE cl_list_item_t* CL_API +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 +*/ +CL_INLINE cl_list_item_t* CL_API +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 +*/ +CL_INLINE const cl_list_item_t* const CL_API +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 +*/ +CL_INLINE void CL_API +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 +*/ +CL_INLINE void CL_API +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 +*/ +CL_EXPORT void CL_API +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 +*/ +CL_EXPORT void CL_API +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 +*/ +CL_EXPORT void CL_API +cl_qlist_insert_array_head( + IN cl_qlist_t* const p_list, + IN cl_list_item_t* const p_array, + IN size_t item_count, + IN const size_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 +*/ +CL_EXPORT void CL_API +cl_qlist_insert_array_tail( + IN cl_qlist_t* const p_list, + IN cl_list_item_t* const p_array, + IN size_t item_count, + IN const size_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 +*/ +CL_INLINE void CL_API +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 +*/ +CL_INLINE void CL_API +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 +*/ +CL_INLINE cl_list_item_t* CL_API +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 ); + + __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 +*/ +CL_INLINE cl_list_item_t* CL_API +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 ); + + __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 +*/ +CL_INLINE void CL_API +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; + + __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 +*/ +CL_INLINE void CL_API +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 +*/ +CL_EXPORT boolean_t CL_API +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_EXPORT cl_list_item_t* CL_API +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_EXPORT cl_list_item_t* CL_API +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 +*/ +CL_INLINE cl_list_item_t* CL_API +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 +*/ +CL_INLINE cl_list_item_t* CL_API +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 +*/ +CL_EXPORT void CL_API +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 +*/ +CL_EXPORT void CL_API +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 +*********/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* _CL_QUICK_LIST_H_ */ diff --git a/branches/WOF2-3/inc/complib/cl_qlockpool.h b/branches/WOF2-3/inc/complib/cl_qlockpool.h new file mode 100644 index 00000000..3187dcb6 --- /dev/null +++ b/branches/WOF2-3/inc/complib/cl_qlockpool.h @@ -0,0 +1,369 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * Abstract: + * Declaration of cl_qlock_pool_t. + * This object represents a threadsafe quick-pool of objects. + * + * Environment: + * All + */ + +#ifndef _CL_QLOCKPOOL_H_ +#define _CL_QLOCKPOOL_H_ + + +#include +#include + + +/****h* Component Library/Quick Locking Pool +* NAME +* Quick Locking Pool +* +* DESCRIPTION +* The Quick Locking Pool represents a thread-safe quick pool. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* SEE ALSO +* Structures: +* cl_qlock_pool_t +* +* Initialization: +* cl_qlock_pool_construct, cl_qlock_pool_init, cl_qlock_pool_destroy +* +* Manipulation +* cl_qlock_pool_get, cl_qlock_pool_put +*********/ + + +/****s* Component Library: Quick Locking Pool/cl_qlock_pool_t +* NAME +* cl_qlock_pool_t +* +* DESCRIPTION +* Quick Locking Pool structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _cl_qlock_pool +{ + cl_spinlock_t lock; + cl_qpool_t pool; + +} cl_qlock_pool_t; +/* +* FIELDS +* lock +* Spinlock guarding the pool. +* +* pool +* quick_pool of user objects. +* +* SEE ALSO +* Quick Locking Pool +*********/ + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/****f* Component Library: Quick Locking Pool/cl_qlock_pool_construct +* NAME +* cl_qlock_pool_construct +* +* DESCRIPTION +* This function constructs a Quick Locking Pool. +* +* SYNOPSIS +*/ +static inline void +cl_qlock_pool_construct( + IN cl_qlock_pool_t* const p_pool ) +{ + cl_qpool_construct( &p_pool->pool ); + cl_spinlock_construct( &p_pool->lock ); +} + +/* +* PARAMETERS +* p_pool +* [in] Pointer to a Quick Locking Pool to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling cl_qlock_pool_init, cl_qlock_pool_destroy +* +* Calling cl_qlock_pool_construct is a prerequisite to calling any other +* method except cl_qlock_pool_init. +* +* SEE ALSO +* Quick Locking Pool, cl_qlock_pool_init, cl_qlock_pool_destroy +*********/ + + +/****f* Component Library: Quick Locking Pool/cl_qlock_pool_destroy +* NAME +* cl_qlock_pool_destroy +* +* DESCRIPTION +* The cl_qlock_pool_destroy function destroys a node, releasing +* all resources. +* +* SYNOPSIS +*/ +static inline void +cl_qlock_pool_destroy( + IN cl_qlock_pool_t* const p_pool ) +{ + /* + If the pool has already been put into use, grab the lock + to sync with other threads before we blow everything away. + */ + if( cl_is_qpool_inited( &p_pool->pool ) ) + { + cl_spinlock_acquire( &p_pool->lock ); + cl_qpool_destroy( &p_pool->pool ); + cl_spinlock_release( &p_pool->lock ); + } + else + cl_qpool_destroy( &p_pool->pool ); + + cl_spinlock_destroy( &p_pool->lock ); +} +/* +* PARAMETERS +* p_pool +* [in] Pointer to a Quick Locking Pool to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified Quick Locking Pool. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* cl_qlock_pool_construct or cl_qlock_pool_init. +* +* SEE ALSO +* Quick Locking Pool, cl_qlock_pool_construct, cl_qlock_pool_init +*********/ + + +/****f* Component Library: Quick Locking Pool/cl_qlock_pool_init +* NAME +* cl_qlock_pool_init +* +* DESCRIPTION +* The cl_qlock_pool_init function initializes a Quick Locking Pool for use. +* +* SYNOPSIS +*/ +static inline cl_status_t +cl_qlock_pool_init( + IN cl_qlock_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_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_qlock_pool_construct( p_pool ); + + status = cl_spinlock_init( &p_pool->lock ); + if( status ) + return( status ); + + status = cl_qpool_init( &p_pool->pool, min_size, max_size, grow_size, + object_size, pfn_initializer, pfn_destructor, context ); + + return( status ); +} +/* +* PARAMETERS +* p_pool +* [in] Pointer to an cl_qlock_pool_t object 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 +* Allows calling other Quick Locking Pool methods. +* +* SEE ALSO +* Quick Locking Pool, cl_qlock_pool_construct, cl_qlock_pool_destroy +*********/ + + +/****f* Component Library: Quick Locking Pool/cl_qlock_pool_get +* NAME +* cl_qlock_pool_get +* +* DESCRIPTION +* Gets an object wrapper and wire MAD from the pool. +* +* SYNOPSIS +*/ +static inline cl_pool_item_t* +cl_qlock_pool_get( + IN cl_qlock_pool_t* const p_pool ) +{ + cl_pool_item_t* p_item; + cl_spinlock_acquire( &p_pool->lock ); + p_item = cl_qpool_get( &p_pool->pool ); + cl_spinlock_release( &p_pool->lock ); + return( p_item ); +} + +/* +* PARAMETERS +* p_pool +* [in] Pointer to an cl_qlock_pool_t object. +* +* RETURN VALUES +* Returns a pointer to a cl_pool_item_t contained in the user object. +* +* NOTES +* The object must eventually be returned to the pool with a call to +* cl_qlock_pool_put. +* +* The cl_qlock_pool_construct or cl_qlock_pool_init must be called before +* using this function. +* +* SEE ALSO +* Quick Locking Pool, cl_qlock_pool_put +*********/ + + +/****f* Component Library: Quick Locking Pool/cl_qlock_pool_put +* NAME +* cl_qlock_pool_put +* +* DESCRIPTION +* Returns an object to the pool. +* +* SYNOPSIS +*/ +static inline void +cl_qlock_pool_put( + IN cl_qlock_pool_t* const p_pool, + IN cl_pool_item_t* const p_item ) +{ + cl_spinlock_acquire( &p_pool->lock ); + cl_qpool_put( &p_pool->pool, p_item ); + cl_spinlock_release( &p_pool->lock ); +} +/* +* PARAMETERS +* p_pool +* [in] Pointer to an cl_qlock_pool_t object. +* +* p_item +* [in] Pointer to the cl_pool_item_t in an object that was previously +* retrieved from the pool. +* +* RETURN VALUES +* This function does not return a value. +* +* NOTES +* The cl_qlock_pool_construct or cl_qlock_pool_init must be called before +* using this function. +* +* SEE ALSO +* Quick Locking Pool, cl_qlock_pool_get +*********/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* _CL_QLOCKPOOL_H_ */ diff --git a/branches/WOF2-3/inc/complib/cl_qmap.h b/branches/WOF2-3/inc/complib/cl_qmap.h new file mode 100644 index 00000000..4981b4e9 --- /dev/null +++ b/branches/WOF2-3/inc/complib/cl_qmap.h @@ -0,0 +1,973 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * Abstract: + * Declaration of quick map, a binary tree where the caller always provides + * all necessary storage. + * + * Environment: + * All + */ + + +#ifndef _CL_QMAP_H_ +#define _CL_QMAP_H_ + + +#include +#include + + +/****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 +* +* Search: +* cl_qmap_apply_func +* +* Attributes: +* cl_qmap_count, cl_is_qmap_empty, +*********/ + + +/****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_API *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 +*********/ + + +#ifdef __cplusplus +extern "C" { +#endif + + +/****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 +*/ +CL_INLINE size_t CL_API +cl_qmap_count( + IN const cl_qmap_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_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 +*/ +CL_INLINE boolean_t CL_API +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 +*/ +CL_INLINE void CL_API +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 +*/ +CL_INLINE void* CL_API +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 +*/ +CL_INLINE uint64_t CL_API +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 +*/ +CL_EXPORT void CL_API +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 +*/ +CL_INLINE const cl_map_item_t* const CL_API +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 +*/ +CL_INLINE cl_map_item_t* CL_API +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 +*/ +CL_INLINE cl_map_item_t* CL_API +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 +*/ +CL_INLINE cl_map_item_t* CL_API +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 +*/ +CL_INLINE cl_map_item_t* CL_API +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. +* +* SYNOPSIS +*/ +CL_EXPORT cl_map_item_t* CL_API +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. +* +* 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_EXPORT cl_map_item_t* CL_API +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_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 +*/ +CL_EXPORT void CL_API +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_EXPORT cl_map_item_t* CL_API +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 +*/ +CL_INLINE void CL_API +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 +*/ +CL_EXPORT void CL_API +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 +*/ +CL_EXPORT void CL_API +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 usefull 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 +*/ +CL_EXPORT void CL_API +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 +*********/ + +#ifdef __cplusplus +} +#endif + + +#endif /* _CL_QMAP_H_ */ diff --git a/branches/WOF2-3/inc/complib/cl_qpool.h b/branches/WOF2-3/inc/complib/cl_qpool.h new file mode 100644 index 00000000..03b27376 --- /dev/null +++ b/branches/WOF2-3/inc/complib/cl_qpool.h @@ -0,0 +1,639 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * 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. + * + * Environment: + * All + */ + + +#ifndef _CL_QUICK_POOL_H_ +#define _CL_QUICK_POOL_H_ + + +#include + + +/****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_API *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_API *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 +*********/ + + + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + +/****f* Component Library: Quick Pool/cl_qpool_construct +* NAME +* cl_qpool_construct +* +* DESCRIPTION +* The cl_qpool_construct function constructs a quick pool. +* +* SYNOPSIS +*/ +CL_EXPORT void CL_API +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 +*/ +CL_INLINE uint32_t CL_API +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_EXPORT cl_status_t CL_API +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 +*/ +CL_INLINE void CL_API +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 +*/ +CL_INLINE size_t CL_API +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 +*/ +CL_INLINE cl_pool_item_t* CL_API +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 +*/ +CL_INLINE void CL_API +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 +*/ +CL_INLINE void CL_API +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 +*/ +CL_INLINE cl_status_t CL_API +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 +*********/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + + +#endif /* _CL_QUICK_POOL_H_ */ diff --git a/branches/WOF2-3/inc/complib/cl_rbmap.h b/branches/WOF2-3/inc/complib/cl_rbmap.h new file mode 100644 index 00000000..7e73fb42 --- /dev/null +++ b/branches/WOF2-3/inc/complib/cl_rbmap.h @@ -0,0 +1,593 @@ +/*++ +Copyright © InfiniCon Systems, Inc. All rights reserved. + +THIS SOFTWARE IS PROVIDED BY INFINICON SYSTEMS, INC. ("INFINICON") TO EACH +PERSON OR COMPANY ("RECIPIENT") ON AN "AS IS" BASIS. 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 INFINICON 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 OR 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. + +Any agreements between InfiniCon and the Recipient shall apply to Recipient's +use of the Software. +--*/ + + +/* + * Abstract: + * Declaration of primitive red/black map, a red/black tree where the caller + * always provides all necessary storage. + * + * This tree implementation exposes functions required for the client to + * manually walk the map, allowing clients to implement various methods + * of comparisson. + * + * Environment: + * All + * + * $Revision$ + */ + + +#ifndef _CL_RBMAP_H_ +#define _CL_RBMAP_H_ + + +#include + + +/****h* Component Library/RB Map +* NAME +* RB Map +* +* DESCRIPTION +* RB map implements a binary tree that stores user provided cl_rbmap_item_t +* structures. Each item stored in a RB map has a unique key +* (duplicates are not allowed). RB map provides the ability to +* efficiently search for an item given a key. +* +* RB map does not allocate any memory, and can therefore not fail +* any operations due to insufficient memory. RB map can thus be useful +* in minimizing the error paths in code. +* +* RB map is not thread safe, and users must provide serialization when +* adding and removing items from the map. +* +* The RB map functions operate on a cl_rbmap_t structure which should be +* treated as opaque and should be manipulated only through the provided +* functions. +* +* SEE ALSO +* Structures: +* cl_rbmap_t, cl_rbmap_item_t +* +* Initialization: +* cl_rbmap_init +* +* Iteration: +* cl_rbmap_root, cl_rbmap_end, cl_rbmap_left, cl_rbmap_right, cl_rbmap_up +* +* Manipulation: +* cl_rbmap_insert, cl_rbmap_get, cl_rbmap_remove_item, cl_rbmap_remove, +* cl_rbmap_reset, cl_rbmap_merge, cl_rbmap_delta +* +* Search: +* cl_rbmap_apply_func +* +* Attributes: +* cl_rbmap_count, cl_is_rbmap_empty, +*********/ + + +/****i* Component Library: RB 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 +* RB Map, cl_rbmap_item_t +*********/ + + +/****s* Component Library: RB Map/cl_rbmap_item_t +* NAME +* cl_rbmap_item_t +* +* DESCRIPTION +* The cl_rbmap_item_t structure is used by maps to store objects. +* +* The cl_rbmap_item_t structure should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _cl_rbmap_item +{ + struct _cl_rbmap_item *p_left; + struct _cl_rbmap_item *p_right; + struct _cl_rbmap_item *p_up; + cl_map_color_t color; +#ifdef _DEBUG_ + struct _cl_rbmap *p_map; +#endif + +} cl_rbmap_item_t; +/* +* FIELDS +* 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. +* +* color +* Indicates whether a node is red or black in the map. +* +* 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 RB map. +* +* SEE ALSO +* RB Map, cl_rbmap_insert, cl_rbmap_key, cl_pool_item_t, cl_list_item_t +*********/ + + +/****s* Component Library: RB Map/cl_rbmap_t +* NAME +* cl_rbmap_t +* +* DESCRIPTION +* Quick map structure. +* +* The cl_rbmap_t structure should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _cl_rbmap +{ + cl_rbmap_item_t root; + cl_rbmap_item_t nil; + cl_state_t state; + size_t count; + +} cl_rbmap_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 +* RB Map +*********/ + + +#ifdef __cplusplus +extern "C" { +#endif + + +/****f* Component Library: RB Map/cl_rbmap_count +* NAME +* cl_rbmap_count +* +* DESCRIPTION +* The cl_rbmap_count function returns the number of items stored +* in a RB map. +* +* SYNOPSIS +*/ +CL_INLINE size_t CL_API +cl_rbmap_count( + IN const cl_rbmap_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_rbmap_t structure whose item count to return. +* +* RETURN VALUE +* Returns the number of items stored in the map. +* +* SEE ALSO +* RB Map, cl_is_rbmap_empty +*********/ + + +/****f* Component Library: RB Map/cl_is_rbmap_empty +* NAME +* cl_is_rbmap_empty +* +* DESCRIPTION +* The cl_is_rbmap_empty function returns whether a RB map is empty. +* +* SYNOPSIS +*/ +CL_INLINE boolean_t CL_API +cl_is_rbmap_empty( + IN const cl_rbmap_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_rbmap_t structure to test for emptiness. +* +* RETURN VALUES +* TRUE if the RB map is empty. +* +* FALSE otherwise. +* +* SEE ALSO +* RB Map, cl_rbmap_count, cl_rbmap_reset +*********/ + + +/****f* Component Library: RB Map/cl_rbmap_reset +* NAME +* cl_rbmap_reset +* +* DESCRIPTION +* The cl_rbmap_reset function removes all items in a RB map, +* leaving it empty. +* +* SYNOPSIS +*/ +CL_INLINE void CL_API +cl_rbmap_reset( + IN cl_rbmap_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->count = 0; +} +/* +* PARAMETERS +* p_map +* [in] Pointer to a cl_rbmap_t structure to empty. +* +* RETURN VALUES +* This function does not return a value. +* +* SEE ALSO +* RB Map, cl_rbmap_remove, cl_rbmap_remove_item +*********/ + + +/****f* Component Library: RB Map/cl_rbmap_init +* NAME +* cl_rbmap_init +* +* DESCRIPTION +* The cl_rbmap_init function initialized a RB map for use. +* +* SYNOPSIS +*/ +CL_INLINE void CL_API +cl_rbmap_init( + IN cl_rbmap_t* const p_map ) +{ + CL_ASSERT( p_map ); + + /* special setup for the root node */ + p_map->root.p_left = &p_map->nil; + p_map->root.p_right = &p_map->nil; + p_map->root.p_up = &p_map->root; + p_map->root.color = CL_MAP_BLACK; + + /* Setup the node used as terminator for all leaves. */ + p_map->nil.p_left = &p_map->nil; + p_map->nil.p_right = &p_map->nil; + p_map->nil.p_up = &p_map->nil; + p_map->nil.color = CL_MAP_BLACK; + +#ifdef _DEBUG_ + p_map->root.p_map = p_map; + p_map->nil.p_map = p_map; +#endif + + p_map->state = CL_INITIALIZED; + + p_map->count = 0; +} +/* +* PARAMETERS +* p_map +* [in] Pointer to a cl_rbmap_t structure to initialize. +* +* RETURN VALUES +* This function does not return a value. +* +* NOTES +* Allows calling RB map manipulation functions. +* +* SEE ALSO +* RB Map, cl_rbmap_insert, cl_rbmap_remove +*********/ + + +/****f* Component Library: RB Map/cl_rbmap_root +* NAME +* cl_rbmap_root +* +* DESCRIPTION +* The cl_rbmap_root function returns the root of a RB map. +* +* SYNOPSIS +*/ +CL_INLINE cl_rbmap_item_t* const CL_API +cl_rbmap_root( + IN const cl_rbmap_t* const p_map ) +{ + CL_ASSERT( p_map ); + return( p_map->root.p_left ); +} +/* +* PARAMETERS +* p_map +* [in] Pointer to a cl_rbmap_t structure whose root to return. +* +* RETURN VALUE +* Pointer to the end of the map. +* +* NOTES +* cl_rbmap_end is useful for determining the validity of map items returned +* by cl_rbmap_head, cl_rbmap_tail, cl_rbmap_next, or cl_rbmap_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_rbmap_head or cl_rbmap_tail, this condition indicates that +* the map is empty. +* +* SEE ALSO +* RB Map, cl_rbmap_head, cl_rbmap_tail, cl_rbmap_next, cl_rbmap_prev, +* cl_rbmap_end, cl_rbmap_left, cl_rbmap_right, cl_rbmap_up +*********/ + + +/****f* Component Library: RB Map/cl_rbmap_end +* NAME +* cl_rbmap_end +* +* DESCRIPTION +* The cl_rbmap_end function returns the end of a RB map. +* +* SYNOPSIS +*/ +CL_INLINE const cl_rbmap_item_t* const CL_API +cl_rbmap_end( + IN const cl_rbmap_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_rbmap_t structure whose end to return. +* +* RETURN VALUE +* Pointer to the end of the map. +* +* NOTES +* cl_rbmap_end is useful for determining the validity of map items returned +* by cl_rbmap_head, cl_rbmap_tail, cl_rbmap_next, or cl_rbmap_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_rbmap_head or cl_rbmap_tail, this condition indicates that +* the map is empty. +* +* SEE ALSO +* RB Map, cl_rbmap_head, cl_rbmap_tail, cl_rbmap_next, cl_rbmap_prev +* cl_rbmap_root, cl_rbmap_left, cl_rbmap_right, cl_rbmap_up +*********/ + + +/****f* Component Library: RB Map/cl_rbmap_left +* NAME +* cl_rbmap_left +* +* DESCRIPTION +* The cl_rbmap_left function returns the map item to the left +* of the specified map item. +* +* SYNOPSIS +*/ +CL_INLINE cl_rbmap_item_t* CL_API +cl_rbmap_left( + IN const cl_rbmap_item_t* const p_item ) +{ + CL_ASSERT( p_item ); + return( (cl_rbmap_item_t*)p_item->p_left ); +} +/* +* PARAMETERS +* p_item +* [in] Pointer to a map item whose predecessor to return. +* +* RETURN VALUES +* Pointer to the map item to the left in a RB map. +* +* Pointer to the map end if no item is to the left. +* +* SEE ALSO +* RB Map, cl_rbmap_head, cl_rbmap_tail, cl_rbmap_next, cl_rbmap_end, +* cl_rbmap_item_t +*********/ + + +/****f* Component Library: RB Map/cl_rbmap_right +* NAME +* cl_rbmap_right +* +* DESCRIPTION +* The cl_rbmap_right function returns the map item to the right +* of the specified map item. +* +* SYNOPSIS +*/ +CL_INLINE cl_rbmap_item_t* CL_API +cl_rbmap_right( + IN const cl_rbmap_item_t* const p_item ) +{ + CL_ASSERT( p_item ); + return( (cl_rbmap_item_t*)p_item->p_right ); +} +/* +* PARAMETERS +* p_item +* [in] Pointer to a map item whose predecessor to return. +* +* RETURN VALUES +* Pointer to the map item to the right in a RB map. +* +* Pointer to the map end if no item is to the right. +* +* SEE ALSO +* RB Map, cl_rbmap_head, cl_rbmap_tail, cl_rbmap_next, cl_rbmap_end, +* cl_rbmap_item_t +*********/ + + +/****f* Component Library: RB Map/cl_rbmap_insert +* NAME +* cl_rbmap_insert +* +* DESCRIPTION +* The cl_rbmap_insert function inserts a map item into a RB map. +* +* SYNOPSIS +*/ +CL_EXPORT void CL_API +cl_rbmap_insert( + IN cl_rbmap_t* const p_map, + IN cl_rbmap_item_t* const p_insert_at, + IN cl_rbmap_item_t* const p_item, + IN boolean_t left ); +/* +* PARAMETERS +* p_map +* [in] Pointer to a cl_rbmap_t structure into which to add the item. +* +* p_insert_at +* [in] Pointer to a cl_rbmap_item_t structure to serve as parent +* to p_item. +* +* p_item +* [in] Pointer to a cl_rbmap_item_t stucture to insert into the RB map. +* +* left +* [in] Indicates that p_item should be inserted to the left of p_insert_at. +* +* 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 RB map to rebalance. +* +* SEE ALSO +* RB Map, cl_rbmap_remove, cl_rbmap_item_t +*********/ + + +/****f* Component Library: RB Map/cl_rbmap_remove_item +* NAME +* cl_rbmap_remove_item +* +* DESCRIPTION +* The cl_rbmap_remove_item function removes the specified map item +* from a RB map. +* +* SYNOPSIS +*/ +CL_EXPORT void CL_API +cl_rbmap_remove_item( + IN cl_rbmap_t* const p_map, + IN cl_rbmap_item_t* const p_item ); +/* +* PARAMETERS +* p_item +* [in] Pointer to a map item to remove from its RB map. +* +* RETURN VALUES +* This function does not return a value. +* +* In a debug build, cl_rbmap_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 RB map. +* +* SEE ALSO +* RB Map, cl_rbmap_remove, cl_rbmap_reset, cl_rbmap_insert +*********/ + + +#ifdef __cplusplus +} +#endif + + +#endif /* _CL_RBMAP_H_ */ diff --git a/branches/WOF2-3/inc/complib/cl_reqmgr.h b/branches/WOF2-3/inc/complib/cl_reqmgr.h new file mode 100644 index 00000000..7077e13b --- /dev/null +++ b/branches/WOF2-3/inc/complib/cl_reqmgr.h @@ -0,0 +1,481 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * Abstract: + * Declaration of asynchronous request manager. The request manager does + * not return resources, only notifies the user when resources are available. + * + * Environment: + * All + */ + + +#ifndef _CL_REQ_MGR_H_ +#define _CL_REQ_MGR_H_ + + +#include + + +/****h* Component Library/Request Manager +* NAME +* Request Manager +* +* DESCRIPTION +* The Request Manager manages synchronous as well as asynchronous +* requests for objects. +* +* Request manager does not supply the objects, but merely returns whether +* objects are available to satisfy requests. This allows users to use +* various sources for objects. +* +* While the request manager manages synchronous and asynchronous requests +* for objects, it does not itself operate asynchronously. Instead, the +* cl_req_mgr_resume function returns information for resuming asynchronous +* requests. If a call to cl_req_mgr_resume returns CL_SUCCESS, additional +* requests may be able to resume. It is recommended that users flush +* pending requests by calling cl_req_mgr_resume while CL_SUCCESS is returned. +* +* The request manager functions operates on a cl_req_mgr_t structure which +* should be treated as opaque and should be manipulated only through the +* provided functions. +* +* SEE ALSO +* Types: +* cl_req_type_t +* +* Structures: +* cl_req_mgr_t +* +* Callbacks: +* cl_pfn_req_cb_t, cl_pfn_reqmgr_get_count_t +* +* Initialization/Destruction: +* cl_req_mgr_construct, cl_req_mgr_init, cl_req_mgr_destroy +* +* Manipulation: +* cl_req_mgr_get, cl_req_mgr_resume +* +* Attributes: +* cl_is_req_mgr_inited, cl_req_mgr_count +*********/ + + +/****d* Component Library: Request Manager/cl_pfn_req_cb_t +* NAME +* cl_pfn_req_cb_t +* +* DESCRIPTION +* The cl_pfn_req_cb_t function type defines the prototype for functions +* used to store a function pointer to a user defined function. +* +* SYNOPSIS +*/ +typedef void +(CL_API *cl_pfn_req_cb_t)( void ); +/* +* PARAMETERS +* This function does not take parameters. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Function pointers specified by this parameter do not have to match the +* defined syntax, as these callbacks are never invoked directly by the +* request manager. When specifying a function with a different prototype, +* cast the function pointer to this type. +* +* SEE ALSO +* Request Manager, cl_req_mgr_get, cl_req_mgr_resume +*********/ + + +/****d* Component Library: Request Manager/cl_req_type_t +* NAME +* cl_req_type_t +* +* DESCRIPTION +* The cl_req_type_t enumerated type describes the type of request. +* +* SYNOPSIS +*/ +typedef enum _cl_req_type +{ + REQ_GET_SYNC, + REQ_GET_ASYNC, + REQ_GET_PARTIAL_OK + +} cl_req_type_t; +/* +* VALUES +* REQ_GET_SYNC +* Synchronous request. +* +* REQ_GET_ASYNC +* Asynchronous requests for which all objects are required at once. +* +* REQ_GET_PARTIAL_OK +* Asynchronous requests that may be broken into multiple smaller requests. +* +* SEE ALSO +* Request Manager, cl_req_mgr_get +*********/ + + +/****d* Component Library: Request Manager/cl_pfn_reqmgr_get_count_t +* NAME +* cl_pfn_reqmgr_get_count_t +* +* DESCRIPTION +* The cl_pfn_reqmgr_get_count_t function type defines the prototype for +* functions used to retrieve the number of available objects in a pool. +* +* SYNOPSIS +*/ +typedef size_t +(CL_API *cl_pfn_reqmgr_get_count_t)( + IN void* context ); +/* +* PARAMETERS +* Context +* [in] Context provided in a call to cl_req_mgr_init by +* the get_context parameter. +* +* RETURN VALUE +* Returns the number of objects available in an object pool for which +* requests are managed by a request manager. +* +* NOTES +* This function type is provided as function prototype reference for the +* function passed into cl_req_mgr_init. This function is invoked by the +* request manager when trying to fulfill requests for resources, either +* through a call to cl_req_mgr_get or cl_req_mgr_resume. +* +* SEE ALSO +* Request Manager, cl_req_mgr_init, cl_req_mgr_get, cl_req_mgr_resume +*********/ + + +/****s* Component Library: Request Manager/cl_req_mgr_t +* NAME +* cl_req_mgr_t +* +* DESCRIPTION +* Quick composite pool structure. +* +* The cl_req_mgr_t structure should be treated as opaque and should be +* manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _cl_req_mgr +{ + cl_pfn_reqmgr_get_count_t pfn_get_count; + const void *get_context; + cl_qlist_t request_queue; + cl_qpool_t request_pool; + +} cl_req_mgr_t; +/* +* FIELDS +* pfn_get_count +* Pointer to the count callback function. +* +* get_context +* Context to pass as single parameter to count callback. +* +* request_queue +* Pending requests for elements. +* +* request_pool +* Pool of request structures for storing requests in the request queue. +* +* SEE ALSO +* Request Manager +*********/ + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/****f* Component Library: Request Manager/cl_req_mgr_construct +* NAME +* cl_req_mgr_construct +* +* DESCRIPTION +* The cl_req_mgr_construct function constructs a request manager. +* +* SYNOPSIS +*/ +CL_EXPORT void CL_API +cl_req_mgr_construct( + IN cl_req_mgr_t* const p_req_mgr ); +/* +* PARAMETERS +* p_req_mgr +* [in] Pointer to a cl_req_mgr_t structure to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* cl_req_mgr_construct allows calling cl_req_mgr_destroy without first +* calling cl_req_mgr_init. +* +* Calling cl_req_mgr_construct is a prerequisite to calling any other +* request manager function except cl_req_mgr_init. +* +* SEE ALSO +* Request Manager, cl_req_mgr_init, cl_req_mgr_destroy +*********/ + + +/****f* Component Library: Request Manager/cl_req_mgr_init +* NAME +* cl_req_mgr_init +* +* DESCRIPTION +* The cl_req_mgr_init function initializes a request manager for use. +* +* SYNOPSIS +*/ +CL_EXPORT cl_status_t CL_API +cl_req_mgr_init( + IN cl_req_mgr_t* const p_req_mgr, + IN cl_pfn_reqmgr_get_count_t pfn_get_count, + IN const void* const get_context ); +/* +* PARAMETERS +* p_req_mgr +* [in] Pointer to a cl_req_mgr_t structure to initialize. +* +* pfn_get_count +* [in] Callback function invoked by the request manager to get the +* number of objects available in a pool of objects for which the +* request manager is managing requests. +* See the cl_pfn_req_mgr_get_count_t function type declaration for +* details about the callback function. +* +* get_context +* [in] Context to pass into the function specified by the +* pfn_get_count parameter. +* +* RETURN VALUES +* CL_SUCCESS if the request manager was successfully initialized. +* +* CL_INSUFFICIENT_MEMORY if there was not enough memory to initialize +* the request manager. +* +* SEE ALSO +* Request Manager, cl_req_mgr_construct, cl_req_mgr_destroy, cl_req_mgr_get, +* cl_req_mgr_resume, cl_pfn_req_mgr_get_count_t +*********/ + + +/****f* Component Library: Request Manager/cl_req_mgr_destroy +* NAME +* cl_req_mgr_destroy +* +* DESCRIPTION +* The cl_req_mgr_destroy function destroys a request manager. +* +* SYNOPSIS +*/ +CL_EXPORT void CL_API +cl_req_mgr_destroy( + IN cl_req_mgr_t* const p_req_mgr ); +/* +* PARAMETERS +* p_req_mgr +* [in] Pointer to a cl_req_mgr_t structure to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* cl_req_mgr_destroy frees all memory allocated by the request manager. +* Further operations on the request manager should not be attempted. +* +* This function should only be called after a call to cl_req_mgr_construct +* or cl_req_mgr_init. +* +* SEE ALSO +* Request Manager, cl_req_mgr_construct, cl_req_mgr_init +*********/ + + +/****f* Component Library: Request Manager/cl_req_mgr_get +* NAME +* cl_req_mgr_get +* +* DESCRIPTION +* The cl_req_mgr_get function handles synchronous and asynchronous +* requests for objects. +* +* SYNOPSIS +*/ +CL_EXPORT cl_status_t CL_API +cl_req_mgr_get( + IN cl_req_mgr_t* const p_req_mgr, + IN OUT size_t* const p_count, + IN const cl_req_type_t req_type, + IN cl_pfn_req_cb_t pfn_callback, + IN const void* const context1, + IN const void* const context2 ); +/* +* PARAMETERS +* p_req_mgr +* [in] Pointer to a cl_req_mgr_t structure from which to check +* for resources. +* +* p_count +* [in/out] On input, contains the number of objects requested. +* On output, contains the number of objects available. +* +* req_type +* [in] Enumerated type describing the type of request. Valid values are: +* ReqGetSync +* Synchronous request. +* ReqGetAsync +* Asynchronous requests for which all objects are required at +* once. +* ReqGetAsyncPartialOk +* Asynchronous requests that may be broken into multiple smaller +* requests. +* +* pfn_callback +* [in] Pointer to a callback function for use by the caller. This +* callback function is never invoked by the request manager. +* +* context1 +* [in] First of two contexts for a resource request. +* +* context2 +* [in] Second of two contexts for a resource request. +* +* RETURN VALUES +* CL_SUCCESS if all objects requested are available. +* +* CL_PENDING if the request could not be completed in its entirety. +* The p_count parameter contains the number of objects immediately available. +* +* CL_INSUFFICIENT_RESOURCES if the request could not be completed due to +* insufficient objects being available. +* +* CL_INSUFFICIENT_MEMORY if the request failed due to a lack of system memory. +* +* NOTES +* Upon successful completion of this function, the p_count parameter contains +* the number of objects available. +* +* Synchronous requests fail if there are any asynchronous requests pending, +* or if there are not enough resources to immediately satisfy the request in +* its entirety . +* +* Asynchronous requests fail if there is insufficient system memory to +* queue them. +* +* Once an asynchronous request is queued, use cl_req_mgr_resume to retrieve +* information for resuming queued requests. +* +* SEE ALSO +* Request Manager, cl_req_mgr_resume +*********/ + + +/****f* Component Library: Request Manager/cl_req_mgr_resume +* NAME +* cl_req_mgr_resume +* +* DESCRIPTION +* The cl_req_mgr_resume function attempts to resume queued requests. +* +* SYNOPSIS +*/ +CL_EXPORT cl_status_t CL_API +cl_req_mgr_resume( + IN cl_req_mgr_t* const p_req_mgr, + OUT size_t* const p_count, + OUT cl_pfn_req_cb_t* const ppfn_callback, + OUT const void** const p_context1, + OUT const void** const p_context2 ); +/* +* PARAMETERS +* p_req_mgr +* [in] Pointer to a cl_req_mgr_t structure from which to resume requests. +* +* p_count +* [out] Contains the number of objects available for a resuming request. +* +* ppfn_callback +* [out] Contains the pfn_callback value for the resuming request, as +* provided to the call to the cl_req_mgr_get function. +* +* p_context1 +* [out] Contains the context1 value for the resuming request, as provided +* to the call to the cl_req_mgr_get function. +* +* p_context2 +* [out] Contains the context2 value for the resuming request, as provided +* to the call to the cl_req_mgr_get function. +* +* RETURN VALUES +* CL_SUCCESS if a request was completed. +* +* CL_PENDING if a request was continued, but not completed. +* +* CL_INSUFFICIENT_RESOURCES if a request could not be continued due to +* a lack of resources. +* +* CL_NOT_DONE if there were no pending requests. +* +* NOTES +* cl_req_mgr_resume resumes at most one request. Further requests may be +* able to be resumed if this call returns CL_SUCCESS. +* +* SEE ALSO +* Request Manager, cl_req_mgr_get +*********/ + + +#ifdef __cplusplus +} +#endif + + +#endif /* _CL_REQ_MGR_H_ */ diff --git a/branches/WOF2-3/inc/complib/cl_spinlock.h b/branches/WOF2-3/inc/complib/cl_spinlock.h new file mode 100644 index 00000000..8dd45e1e --- /dev/null +++ b/branches/WOF2-3/inc/complib/cl_spinlock.h @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * Abstract: + * Declaration of spin lock object. + * + * Environment: + * All + */ + + +#ifndef _CL_SPINLOCK_H_ +#define _CL_SPINLOCK_H_ + + +#include + + +/****h* Component Library/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 +*********/ + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/****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 +*/ +CL_EXPORT void CL_API +cl_spinlock_construct( + IN cl_spinlock_t* const p_spinlock ); +/* +* PARAMETERS +* p_spinlock +* [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_EXPORT cl_status_t CL_API +cl_spinlock_init( + IN cl_spinlock_t* const p_spinlock ); +/* +* PARAMETERS +* p_spinlock +* [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_release +*********/ + + +/****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 +*/ +CL_EXPORT void CL_API +cl_spinlock_destroy( + IN cl_spinlock_t* const p_spinlock ); +/* +* PARAMETERS +* p_spinlock +* [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. +* +* SYNOPSIS +*/ +CL_EXPORT void CL_API +cl_spinlock_acquire( + IN cl_spinlock_t* const p_spinlock ); +/* +* PARAMETERS +* p_spinlock +* [in] Pointer to a spin lock structure to acquire. +* +* RETURN VALUE +* This function does not return a value. +* +* SEE ALSO +* Spinlock, cl_spinlock_release +*********/ + + +/****f* Component Library: Spinlock/cl_spinlock_release +* NAME +* cl_spinlock_release +* +* DESCRIPTION +* The cl_spinlock_release function releases a spin lock object. +* +* SYNOPSIS +*/ +CL_EXPORT void CL_API +cl_spinlock_release( + IN cl_spinlock_t* const p_spinlock ); +/* +* PARAMETERS +* p_spinlock +* [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 +*********/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* _CL_SPINLOCK_H_ */ diff --git a/branches/WOF2-3/inc/complib/cl_syscallback.h b/branches/WOF2-3/inc/complib/cl_syscallback.h new file mode 100644 index 00000000..09678969 --- /dev/null +++ b/branches/WOF2-3/inc/complib/cl_syscallback.h @@ -0,0 +1,368 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * Abstract: + * System Callback abstractions. + * + * Environment: + * All + */ + + +#ifndef _CL_SYS_CALLBACK_H_ +#define _CL_SYS_CALLBACK_H_ + + +#include + +/****h* Component Library/System Callback +* NAME +* System Callback +* +* DESCRIPTION +* The System Callback provider uses threads from a system thread-pool to +* invoke specified callback functions. +* +* Callbacks can be queued in a low- or high-priority queue for processing. +* +* cl_thread_suspend and cl_thread_stall can be used to delay or stall the +* callback thread. +* +* Environments that do not have a native system thread-pool emulate this +* functionality to provide cross-environment support. +* +* The cl_sys_callback_item_t structure should be treated as opaque and be +* manipulated only through the provided functions. +*********/ + + +/****d* Component Library: System Callback/cl_pfn_sys_callback_t +* NAME +* cl_pfn_sys_callback_t +* +* DESCRIPTION +* The cl_pfn_sys_callback_t function type defines the prototype for +* functions invoked by the system callback provider. +* +* SYNOPSIS +*/ +typedef void +(CL_API *cl_pfn_sys_callback_t)( + IN void* get_context, + IN void* queue_context ); +/* +* PARAMETERS +* get_context +* [in] Value of the get_context parameter specified in a call +* to cl_sys_callback_get. +* +* queue_context +* [in] Value of the queue_context parameter specified in a call +* to cl_sys_callback_queue. +* +* 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_sys_callback_queue function. +* +* SEE ALSO +* System Callback, cl_sys_callback_queue +*********/ + + +/* Include platform specific system callback support. */ +#include + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/****i* Component Library: System Callback/cl_sys_callback_construct +* NAME +* cl_sys_callback_construct +* +* DESCRIPTION +* The cl_sys_callback_construct function is called to initialize the state +* of the system callback provider. +* +* SYNOPSIS +*/ +void +__cl_sys_callback_construct( void ); +/* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* This function is called internally when initializing the component +* library for use. Users should never call this function directly. +* +* Calling cl_sys_callback_construct is a prerequisite to calling any other +* system callback function. +* +* Allows calling cl_sys_callback_init, cl_sys_callback_destroy, and +* cl_is_sys_callback_inited. +* +* SEE ALSO +* System Callback, cl_sys_callback_init, cl_sys_callback_destroy, +* cl_is_sys_callback_inited +*********/ + + +/****f* Component Library: System Callback/cl_is_sys_callback_inited +* NAME +* cl_is_sys_callback_inited +* +* DESCRIPTION +* The cl_is_sys_callback_inited function returns whether the system +* callback provider was initialized successfully +* +* SYNOPSIS +*/ +boolean_t +__cl_is_sys_callback_inited( void ); +/* +* RETURN VALUES +* TRUE if the system callback provider was initialized successfully. +* +* FALSE otherwise. +* +* NOTES +* Allows checking the state of the system callback provider to determine +* if invoking member functions is appropriate. +* +* SEE ALSO +* System Callback +*********/ + + +/****i* Component Library: System Callback/cl_sys_callback_init +* NAME +* cl_sys_callback_init +* +* DESCRIPTION +* The cl_sys_callback_init function is called to initialize the system +* callback provider. +* +* SYNOPSIS +*/ +cl_status_t +__cl_sys_callback_init( void ); +/* +* RETURN VALUES +* CL_SUCCESS if the system callback provider was initialized successfully. +* +* CL_INSUFFICIENT_MEMORY if there was not enough memory to inititalize +* the system callback provider. +* +* CL_ERROR if the system callback provider's threads could not be created. +* +* NOTES +* This function is called internally when initializing the component +* library for use. Users should never call this function directly. +* +* SEE ALSO +* System Callback, cl_sys_callback_construct, cl_sys_callback_destroy +*********/ + + +/****i* Component Library: System Callback/cl_sys_callback_destroy +* NAME +* cl_sys_callback_destroy +* +* DESCRIPTION +* The cl_sys_callback_destroy function is called to destroy the system +* callback provider. +* +* SYNOPSIS +*/ +void +__cl_sys_callback_destroy( void ); +/* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* This function is called internally when destroying the component +* library after use. Users should never call this function directly. +* +* All threads and resources allocated by the system callback provider +* are freed. +* +* This function should only be called after calling either +* cl_sys_callback_construct or cl_sys_callback_construct. +* +* SEE ALSO +* System Callback, cl_sys_callback_construct, cl_sys_callback_construct +*********/ + + +/****f* Component Library: System Callback/cl_sys_callback_get +* NAME +* cl_sys_callback_get +* +* DESCRIPTION +* The cl_sys_callback_get function retrieves a system callback item. +* +* SYNOPSIS +*/ +CL_EXPORT cl_sys_callback_item_t* CL_API +cl_sys_callback_get( + IN const void* const get_context ); +/* +* PARAMETERS +* get_context +* [in] Context value to pass into the callback function. +* +* RETURN VALUES +* Returns a pointer to a system callback item if successful. +* +* Returns NULL if the call fails. +* +* NOTES +* A system callback item must be released with a call to cl_sys_callback_put. +* +* Care must be taken to prevent a system callback item from being returned +* to the pool while it is queued. Callers of cl_sys_callback_queue must not +* return the system callback item to the pool until their callback has been +* invoked. +* +* In Windows 2000 Kernel Mode, the get_context is a pointer to the device +* object for which the system callback is being used. +* +* SEE ALSO +* System Callback, SysCallbackPut, SysCallbackQueue +*********/ + + +/****f* Component Library: System Callback/cl_sys_callback_put +* NAME +* cl_sys_callback_put +* +* DESCRIPTION +* The cl_sys_callback_put function releases the specified +* system callback item. +* +* SYNOPSIS +*/ +CL_EXPORT void CL_API +cl_sys_callback_put( + IN cl_sys_callback_item_t* const p_item ); +/* +* PARAMETERS +* p_item +* [in] Pointer to a system callback item to release. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* The p_item parameter points to a system callback item returned by +* a previous call to cl_sys_callback_get. +* +* The specified system callback item must not be queued when making +* a call to this function. This function can, however, be called +* from the callback function. +* +* SEE ALSO +* System Callback, cl_sys_callback_get, cl_sys_callback_queue +*********/ + + +/****f* Component Library: System Callback/cl_sys_callback_queue +* NAME +* cl_sys_callback_queue +* +* DESCRIPTION +* The cl_sys_callback_queue function queues the specified system callback item +* for execution. +* +* SYNOPSIS +*/ +CL_EXPORT cl_status_t CL_API +cl_sys_callback_queue( + IN cl_sys_callback_item_t* const p_item, + IN cl_pfn_sys_callback_t pfn_callback, + IN const void* const queue_context, + IN const boolean_t high_priority ); +/* +* PARAMETERS +* p_item +* [in] Pointer to a system callback item. +* +* pfn_callback +* [in] Pointer to a function to be invoked by the system callback module. +* See the cl_pfn_sys_callback_t function type definition for details +* about the callback function. +* +* queue_context +* [in] Value passed to the system callback function. +* +* high_priority +* [in] Specifies whether the request should be queued in the high- or +* low-priority queue. +* +* RETURN VALUES +* CL_SUCCESS if the system callback item was successfully queued. +* +* CL_ERROR otherwise. +* +* NOTES +* A thread from the system thread pool will invoke the specified callback +* function with the get_context value specified in the call to +* cl_sys_callback_get and the specified context as parameters. +* +* The high priority queue is processed before the low priority queue. There +* is no fairness algorithm implemented for removing items from the queues. +* +* Care should be taken to only queue a given system callback item once +* at a time. +* +* SEE ALSO +* System Callback, cl_sys_callback_get, cl_pfn_sys_callback_t +*********/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* _CL_SYS_CALLBACK_H_ */ diff --git a/branches/WOF2-3/inc/complib/cl_thread.h b/branches/WOF2-3/inc/complib/cl_thread.h new file mode 100644 index 00000000..aef5c9c6 --- /dev/null +++ b/branches/WOF2-3/inc/complib/cl_thread.h @@ -0,0 +1,396 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * Abstract: + * Declaration of thread abstraction and thread related operations. + * + * Environment: + * All + */ + + +#ifndef _CL_THREAD_H_ +#define _CL_THREAD_H_ + + +#include + + +/****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_API *cl_pfn_thread_callback_t)( + IN void* context ); +/* +* PARAMETERS +* context +* [in] Value specified in a call to cl_thread_init or +* cl_thread_pool_create. +* +* 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_thread_init +* and cl_thread_pool_create functions. +* +* 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 +*********/ + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/****i* Component Library: Thread/cl_thread_construct +* NAME +* cl_thread_construct +* +* DESCRIPTION +* The cl_thread_construct function initializes the state of a thread. +* +* SYNOPSIS +*/ +CL_EXPORT void CL_API +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_EXPORT cl_status_t CL_API +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 +*/ +CL_EXPORT void CL_API +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 +*/ +CL_EXPORT void CL_API +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 +*/ +CL_EXPORT void CL_API +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 +*/ +CL_EXPORT uint32_t CL_API +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 +*/ +CL_EXPORT boolean_t CL_API +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 +*/ +CL_EXPORT boolean_t CL_API +cl_is_blockable( void ); +/* +* RETURN VALUE +* TRUE if the caller's thread context can be blocked, i.e it is safe +* to perform a sleep, or call a down operation on a semaphore. +* +* FALSE otherwise +* +* SEE ALSO +* Thread +*********/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* _CL_THREAD_H_ */ diff --git a/branches/WOF2-3/inc/complib/cl_threadpool.h b/branches/WOF2-3/inc/complib/cl_threadpool.h new file mode 100644 index 00000000..d84fe1c0 --- /dev/null +++ b/branches/WOF2-3/inc/complib/cl_threadpool.h @@ -0,0 +1,306 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * Abstract: + * Declaration of thread pool. + * + * Environment: + * All + */ + + +#ifndef _CL_THREAD_POOL_H_ +#define _CL_THREAD_POOL_H_ + + +#include +#include +#include + + +/****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 +{ + cl_pfn_thread_callback_t pfn_callback; + const void *context; + cl_list_t thread_list; + cl_event_t wakeup_event; + cl_event_t destroy_event; + boolean_t exit; + cl_state_t state; + atomic32_t running_count; + // for debug + cl_thread_t *p_thread[8]; + +} cl_thread_pool_t; +/* +* FIELDS +* pfn_callback +* Callback function for the thread to invoke. +* +* context +* Context to pass to the thread callback function. +* +* thread_list +* List of threads managed by the thread pool. +* +* event +* Event used to signal threads to wake up and do work. +* +* destroy_event +* Event used to signal threads to exit. +* +* exit +* Flag used to indicates threads to exit. +* +* state +* State of the thread pool. +* +* running_count +* Number of threads running. +* +* SEE ALSO +* Thread Pool +*********/ + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/****f* Component Library: Thread Pool/cl_thread_pool_construct +* NAME +* cl_thread_pool_construct +* +* DESCRIPTION +* The cl_thread_pool_construct function initializes the state of a +* thread pool. +* +* SYNOPSIS +*/ +CL_EXPORT void CL_API +cl_thread_pool_construct( + IN cl_thread_pool_t* const p_thread_pool ); +/* +* PARAMETERS +* p_thread_pool +* [in] Pointer to a thread pool structure. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling cl_thread_pool_destroy without first calling +* cl_thread_pool_init. +* +* Calling cl_thread_pool_construct is a prerequisite to calling any other +* thread pool function except cl_thread_pool_init. +* +* SEE ALSO +* Thread Pool, cl_thread_pool_init, cl_thread_pool_destroy +*********/ + + +/****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_EXPORT cl_status_t CL_API +cl_thread_pool_init( + IN cl_thread_pool_t* const p_thread_pool, + IN uint32_t thread_count, + IN cl_pfn_thread_callback_t pfn_callback, + IN const void* const 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 +*/ +CL_EXPORT void CL_API +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_EXPORT cl_status_t CL_API +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 +*********/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* _CL_THREAD_POOL_H_ */ diff --git a/branches/WOF2-3/inc/complib/cl_timer.h b/branches/WOF2-3/inc/complib/cl_timer.h new file mode 100644 index 00000000..8df14d8b --- /dev/null +++ b/branches/WOF2-3/inc/complib/cl_timer.h @@ -0,0 +1,446 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * Abstract: + * Declaration of timer abstraction. + * + * Environment: + * All + */ + + +#ifndef _CL_TIMER_H_ +#define _CL_TIMER_H_ + + +#include + + +/****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_API *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 + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/****f* Component Library: Timer/cl_timer_construct +* NAME +* cl_timer_construct +* +* DESCRIPTION +* The cl_timer_construct function initializes the state of a timer. +* +* SYNOPSIS +*/ +CL_EXPORT void CL_API +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_EXPORT cl_status_t CL_API +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 +*/ +CL_EXPORT void CL_API +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_EXPORT cl_status_t CL_API +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 +*/ +CL_EXPORT void CL_API +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_EXPORT cl_status_t CL_API +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 reseting 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 +*/ +CL_EXPORT uint64_t CL_API +cl_get_time_stamp( void ); +/* +* RETURN VALUE +* Time elapsed, in microseconds, since the system was booted. +* +* SEE ALSO +* Timer, cl_get_time_stamp_usec, cl_get_time_stamp_sec +*********/ + + +/****f* Component Library: Time Stamp/cl_get_time_stamp_usec +* NAME +* cl_get_time_stamp_usec +* +* DESCRIPTION +* The cl_get_time_stamp_usec function returns the current time stamp in +* microseconds since the system was booted. +* +* SYNOPSIS +*/ +CL_INLINE uint64_t CL_API +cl_get_time_stamp_usec( void ) +{ + return cl_get_time_stamp(); +} +/* +* RETURN VALUE +* Time elapsed, in microseconds, since the system was booted. +* +* SEE ALSO +* Timer, cl_get_time_stamp, 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 +*/ +CL_EXPORT uint32_t CL_API +cl_get_time_stamp_sec( void ); +/* +* RETURN VALUE +* Time elapsed, in seconds, since the system was booted. +* +* SEE ALSO +* Timer, cl_get_time_stamp +*********/ + + +/****f* Component Library: Time Stamp/cl_get_tick_count +* NAME +* cl_get_tick_count +* +* DESCRIPTION +* The cl_get_tick_count function returns the raw high-resolution +* performance counter value. +* +* SYNOPSIS +*/ +CL_EXPORT uint64_t CL_API +cl_get_tick_count( void ); +/* +* RETURN VALUE +* Value of the high-resolution performance counter. +* +* SEE ALSO +* Timer, cl_get_time_stamp, cl_get_tick_freq +*********/ + + +/****f* Component Library: Time Stamp/cl_get_tick_freq +* NAME +* cl_get_tick_freq +* +* DESCRIPTION +* The cl_get_tick_freq function returns the frequency of the +* high-resolution performance counter. +* +* SYNOPSIS +*/ +CL_EXPORT uint64_t CL_API +cl_get_tick_freq( void ); +/* +* RETURN VALUE +* The frequency of the high-resolution performance counter. +* +* SEE ALSO +* Timer, cl_get_time_stamp, cl_get_tick_count +*********/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* _CL_TIMER_H_ */ diff --git a/branches/WOF2-3/inc/complib/cl_types.h b/branches/WOF2-3/inc/complib/cl_types.h new file mode 100644 index 00000000..2773707f --- /dev/null +++ b/branches/WOF2-3/inc/complib/cl_types.h @@ -0,0 +1,509 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * Abstract: + * Defines standard return codes, keywords, macros, and debug levels. + * + * Environment: + * All supported platforms + */ + + +#ifndef _CL_TYPES_H_ +#define _CL_TYPES_H_ + + +#include + + +typedef uint16_t net16_t; +typedef uint32_t net32_t; +typedef uint64_t net64_t; + + + +/****d* Component Library: Pointer Manipulation/offsetof +* NAME +* offsetof +* +* DESCRIPTION +* The offsetof macro returns the offset of a member within a structure. +* +* SYNOPSIS +* uintptr_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) ((uintptr_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 +*********/ +#ifndef PARENT_STRUCT +#define PARENT_STRUCT(p_member, PARENT_TYPE, MEMBER_NAME) \ + ((PARENT_TYPE*)((uint8_t*)(p_member) - offsetof(PARENT_TYPE, MEMBER_NAME))) +#endif + +/****d* Component Library/Parameter Keywords +* NAME +* Parameter Keywords +* +* DESCRIPTION +* The Parameter Keywords can be used to clarify the usage of function +* parameters to users. +* +* VALUES +* IN +* Designates that the parameter is used as input to a function. +* +* OUT +* Designates that the parameter's value will be set by the function. +* +* OPTIONAL +* Designates that the parameter is optional, and may be NULL. +* The OPTIONAL keyword, if used, follows the parameter name. +* +* EXAMPLE +* // Function declaration. +* void* +* my_func( +* IN void* const p_param1, +* OUT void** const p_handle OPTIONAL ); +* +* NOTES +* Multiple keywords can apply to a single parameter. The IN and OUT +* keywords precede the parameter type. The OPTIONAL +* keyword, if used, follows the parameter name. +*********/ +#ifndef IN +#define IN /* Function input parameter */ +#endif +#ifndef OUT +#define OUT /* Function output parameter */ +#endif +#ifndef OPTIONAL +#define OPTIONAL /* Optional function parameter - NULL if not used */ +#endif + + +/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Function Returns And Completion Codes %% +%% %% +%% The text for any addition to this enumerated type must be added to the %% +%% string array defined in . %% +%% %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ + + +/****d* Component Library/Data Types +* NAME +* Data Types +* +* DESCRIPTION +* The component library provides and uses explicitly sized types. +* +* VALUES +* char +* 8-bit, defined by compiler. +* +* void +* 0-bit, defined by compiler. +* +* int8_t +* 8-bit signed integer. +* +* uint8_t +* 8-bit unsigned integer. +* +* int16_t +* 16-bit signed integer. +* +* uint16_t +* 16-bit unsigned integer. +* +* net16_t +* 16-bit network byte order value. +* +* int32_t +* 32-bit signed integer. +* +* uint32_t +* 32-bit unsigned integer. +* +* net32_t +* 32-bit network byte order value. +* +* int64_t +* 64-bit signed integer. +* +* uint64_t +* 64-bit unsigned integer. +* +* net64_t +* 64-bit network byte order value. +* +* intn_t +* Signed natural sized integer. 32-bit on a 32-bit platform, 64-bit on +* a 64-bit platform. +* +* uintn_t +* Unsigned natural sized integer. 32-bit on a 32-bit platform, 64-bit on +* a 64-bit platform. +* +* boolean_t +* integral sized. Set to TRUE or FALSE and used in logical expressions. +* +* NOTES +* Pointer types are not defined as these provide no value and can potentially +* lead to naming confusion. +*********/ + + +/****d* Component Library: Data Types/cl_status_t +* NAME +* cl_status_t +* +* DESCRIPTION +* The cl_status_t return types are used by the component library to +* provide detailed function return values. +* +* SYNOPSIS +*/ +#ifdef CL_KERNEL + +typedef enum _cl_status +{ + CL_SUCCESS = STATUS_SUCCESS, + CL_ERROR = STATUS_DRIVER_INTERNAL_ERROR, + CL_INVALID_STATE = STATUS_INVALID_DEVICE_STATE, + CL_INVALID_OPERATION = STATUS_NOT_SUPPORTED, + CL_INVALID_SETTING = STATUS_INVALID_PARAMETER_MIX, + CL_INVALID_PARAMETER = STATUS_INVALID_PARAMETER, + CL_INSUFFICIENT_RESOURCES = STATUS_INSUFFICIENT_RESOURCES, + CL_INSUFFICIENT_MEMORY = STATUS_NO_MEMORY, + CL_INVALID_PERMISSION = STATUS_ACCESS_DENIED, + CL_COMPLETED = STATUS_EVENT_DONE, + CL_NOT_DONE = STATUS_ABANDONED, + CL_PENDING = STATUS_PENDING, + CL_TIMEOUT = STATUS_TIMEOUT, + CL_CANCELED = STATUS_CANCELLED, + CL_REJECT = STATUS_REQUEST_NOT_ACCEPTED, + CL_OVERRUN = STATUS_DATA_OVERRUN, + CL_NOT_FOUND = STATUS_NOT_FOUND, + CL_UNAVAILABLE = STATUS_DEVICE_NOT_READY, + CL_BUSY = STATUS_DEVICE_BUSY, + CL_DISCONNECT = STATUS_LOCAL_DISCONNECT, + CL_DUPLICATE = STATUS_DUPLICATE_NAME, + CL_INVALID_REQUEST = STATUS_INVALID_DEVICE_REQUEST, + CL_INVALID_HANDLE = STATUS_INVALID_HANDLE, + CL_CONNECTION_INVALID = STATUS_CONNECTION_INVALID + +} cl_status_t; + +#else + +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_INVALID_REQUEST, + + CL_STATUS_COUNT /* should be the last value */ + +} cl_status_t; + +#endif + +/* +* SEE ALSO +* Data Types, CL_STATUS_MSG +*********/ + + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + +#ifndef CL_KERNEL +/* Status values above converted to text for easier printing. */ +CL_EXPORT const char* cl_status_text[CL_STATUS_COUNT]; +#endif + +#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 +*/ +CL_EXPORT void CL_API +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 +*********/ +#ifndef CL_KERNEL +#define CL_STATUS_MSG( errcode ) \ + ((errcode < CL_STATUS_COUNT)?cl_status_text[errcode]:"invalid status code") +#endif + + +#if !defined( FALSE ) +#define FALSE 0 +#endif /* !defined( TRUE ) */ + + +#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 +*/ +CL_INLINE boolean_t CL_API +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 +*********/ + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* _DATA_TYPES_H_ */ diff --git a/branches/WOF2-3/inc/complib/cl_vector.h b/branches/WOF2-3/inc/complib/cl_vector.h new file mode 100644 index 00000000..86dad3f2 --- /dev/null +++ b/branches/WOF2-3/inc/complib/cl_vector.h @@ -0,0 +1,1004 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * Abstract: + * This file contains vector definitions. Vector provides dynmically + * resizable array functionality. Objects in a Vector are not relocated + * when the array is resized. + * + * Environment: + * All + */ + + +#ifndef _CL_VECTOR_H_ +#define _CL_VECTOR_H_ + + +#include + + +/****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_API *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_API *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_API *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_API *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_API *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 +*********/ + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/****f* Component Library: Vector/cl_vector_construct +* NAME +* cl_vector_construct +* +* DESCRIPTION +* The cl_vector_construct function constructs a vector. +* +* SYNOPSIS +*/ +CL_EXPORT void CL_API +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_EXPORT cl_status_t CL_API +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 +*/ +CL_EXPORT void CL_API +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 +*/ +CL_INLINE size_t CL_API +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 +*/ +CL_INLINE size_t CL_API +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 +*/ +CL_INLINE void* CL_API +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 +*/ +CL_INLINE void CL_API +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_element, p_src, 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_EXPORT cl_status_t CL_API +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_EXPORT cl_status_t CL_API +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_EXPORT cl_status_t CL_API +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_EXPORT cl_status_t CL_API +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_EXPORT cl_status_t CL_API +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 +*/ +CL_EXPORT void CL_API +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 +*/ +CL_EXPORT size_t CL_API +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 +*/ +CL_EXPORT size_t CL_API +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 +*********/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* _CL_VECTOR_H_ */ diff --git a/branches/WOF2-3/inc/complib/cl_waitobj.h b/branches/WOF2-3/inc/complib/cl_waitobj.h new file mode 100644 index 00000000..7138b1bb --- /dev/null +++ b/branches/WOF2-3/inc/complib/cl_waitobj.h @@ -0,0 +1,377 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * Abstract: + * Declaration of wait object. + * + * Environment: + * All + */ + + +#ifndef _CL_WAITOBJ_H_ +#define _CL_WAITOBJ_H_ + + +#include + + +/****h* Component Library/Wait Object +* NAME +* Wait Object +* +* DESCRIPTION +* The Wait Object provides the capability for a user mode process to +* create and manipulate a wait object that can also be manipulated from +* kernel mode. +* +* SEE ALSO +* Structures: +* cl_waitobj_handle_t +* +* User Mode Initialization/Destruction: +* cl_waitobj_create +* cl_waitobj_destroy +* +* Kernel Mode Access: +* cl_waitobj_ref +* cl_waitobj_deref +* +* Manipulation: +* cl_waitobj_signal +* cl_waitobj_reset +* cl_waitobj_wait_on +******/ + + +/****d* Component Library: Wait Object/cl_waitobj_handle_t +* NAME +* cl_waitobj_handle_t +* +* DESCRIPTION +* Defines the handle for an OS wait object. +* +* NOTES +* The wait object handle should be treated as opaque and is defined +* differently depending on the target environment. +* +* SEE ALSO +* Wait Object, cl_waitobj_create, cl_waitobj_destroy, +* cl_waitobj_ref, cl_waitobj_deref, cl_waitobj_signal, +* cl_waitobj_reset, cl_waitobj_wait_on +******/ + + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + +#if defined(CL_KERNEL) + +/****f* Component Library: Wait Object/cl_waitobj_ref +* NAME +* cl_waitobj_ref +* +* DESCRIPTION +* The cl_waitobj_ref function validates a user mode wait object handle +* and returns a kernel mode wait object handle. A reference is taken +* on the object to prevent its destruction even if the user mode +* application destroys it. +* +* SYNOPSIS +*/ +CL_EXPORT cl_waitobj_handle_t CL_API +cl_waitobj_ref( + IN void *h_user_wait_obj ); +/* +* PARAMETERS +* h_user_wait_obj +* [in] A wait object handle passed from user mode. +* +* RETURN VALUES +* Returns a kernel wait object handle upon success. The returned handle +* should only be used as parameters to kernel mode calls. +* +* Returns NULL in case of failure. +* +* NOTES +* This function is only available in kernel mode. +* +* SEE ALSO +* Wait Object, cl_waitobj_handle_t, cl_waitobj_deref, +* cl_waitobj_signal, cl_waitobj_reset, cl_waitobj_wait_on +******/ + + +/****f* Component Library: Wait Object/cl_waitobj_deref +* NAME +* cl_waitobj_deref +* +* DESCRIPTION +* The cl_waitobj_deref function release a reference on a kernel mode +* wait object handle and allows the wait object to be destroyed. +* +* SYNOPSIS +*/ +CL_EXPORT void CL_API +cl_waitobj_deref( + IN cl_waitobj_handle_t h_kernel_wait_obj ); +/* +* PARAMETERS +* h_kernel_wait_obj +* [in] A wait object handle returned by a previous call to cl_waitobj_ref. +* +* RETURN VALUES +* This function does not return a value. +* +* NOTES +* This function is only available in kernel mode. +* +* SEE ALSO +* Wait Object, cl_waitobj_handle_t, cl_waitobj_ref, +* cl_waitobj_signal, cl_waitobj_reset, cl_waitobj_wait_on +******/ + +#else /* CL_KERNEL */ + +/****f* Component Library: Wait Object/cl_waitobj_create +* NAME +* cl_waitobj_create +* +* DESCRIPTION +* The cl_waitobj_create function creates a wait object. +* +* SYNOPSIS +*/ +CL_EXPORT cl_status_t CL_API +cl_waitobj_create( + IN const boolean_t manual_reset, + OUT cl_waitobj_handle_t* const ph_wait_obj ); +/* +* PARAMETERS +* 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. +* +* ph_wait_obj +* [out] Pointer to a wait object handle set upon successful creation. +* +* RETURN VALUES +* CL_SUCCESS if the wait object was created successfully. +* +* CL_ERROR if the wait object creation failed. +* +* NOTES +* This function is only available in user mode. +* +* SEE ALSO +* Wait Object, cl_waitobj_handle_t, cl_waitobj_destroy, +* cl_waitobj_signal, cl_waitobj_reset, cl_waitobj_wait_on +******/ + + +/****f* Component Library: Wait Object/cl_waitobj_destroy +* NAME +* cl_waitobj_destroy +* +* DESCRIPTION +* The cl_waitobj_destroy function destroys a wait object. +* +* SYNOPSIS +*/ +CL_EXPORT cl_status_t CL_API +cl_waitobj_destroy( + IN cl_waitobj_handle_t h_wait_obj ); +/* +* PARAMETERS +* h_wait_obj +* [in] A handle to the wait object to destroy, obtained by a pervious +* call to cl_waitobj_create. +* +* RETURN VALUES +* CL_SUCCESS if the wait object handle is destroyed. +* +* CL_INVALID_PARAMETER if the wait object handle is invalid. +* +* NOTES +* This function is only available in user mode. +* +* SEE ALSO +* Wait Object, cl_waitobj_handle_t, cl_waitobj_create, +* cl_waitobj_signal, cl_waitobj_reset, cl_waitobj_wait_on +*********/ + +#endif /* CL_KERNEL */ + +/****f* Component Library: Wait Object/cl_waitobj_signal +* NAME +* cl_waitobj_signal +* +* DESCRIPTION +* The cl_waitobj_signal function sets a wait object to the signalled +* state and releases one or more waiting threads. +* +* SYNOPSIS +*/ +CL_EXPORT cl_status_t CL_API +cl_waitobj_signal( + IN cl_waitobj_handle_t h_wait_obj ); +/* +* PARAMETERS +* h_wait_obj +* [in] A handle to the wait object that needs to be signaled. +* +* RETURN VALUES +* CL_SUCCESS if the event was successfully signalled. +* +* CL_ERROR otherwise. +* +* NOTES +* For auto-reset wait objects, the wait object is reset automatically once +* a wait operation is satisfied. +* +* Triggering the wait object multiple times does not guarantee that the same +* number of wait operations are satisfied. This is because wait objects are +* either in a signalled on non-signalled state, and triggering a wait object +* that is already in the signalled state has no effect. +* +* In kernel mode, a pointer to a cl_event_t can safely be used instead of +* a wait object handle. +* +* SEE ALSO +* Wait Object, cl_waitobj_create, cl_waitobj_destroy, +* cl_waitobj_ref, cl_waitobj_deref, +* cl_waitobj_reset, cl_waitobj_wait_on +*********/ + + +/****f* Component Library: Wait Object/cl_waitobj_reset +* NAME +* cl_waitobj_reset +* +* DESCRIPTION +* The cl_waitobj_reset function sets an wait object to the non-signalled state. +* +* SYNOPSIS +*/ +CL_EXPORT cl_status_t CL_API +cl_waitobj_reset( + IN cl_waitobj_handle_t h_wait_obj ); +/* +* PARAMETERS +* h_wait_obj +* [in] A handle to the wait object that needs to reset. +* +* RETURN VALUES +* CL_SUCCESS if the wait object was successfully reset. +* +* CL_ERROR otherwise. +* +* NOTES +* In kernel mode, a pointer to a cl_event_t can safely be used instead of +* a wait object handle. +* +* SEE ALSO +* Wait Object, cl_waitobj_create, cl_waitobj_destroy, +* cl_waitobj_ref, cl_waitobj_deref, +* cl_waitobj_signal, cl_waitobj_wait_on +*********/ + + +/****f* Component Library: Wait Object/cl_waitobj_wait_on +* NAME +* cl_waitobj_wait_on +* +* DESCRIPTION +* The cl_waitobj_wait_on function waits for the specified wait object to be +* triggered for a minimum amount of time. +* +* SYNOPSIS +*/ +CL_EXPORT cl_status_t CL_API +cl_waitobj_wait_on( + IN cl_waitobj_handle_t h_wait_obj, + IN const uint32_t wait_us, + IN const boolean_t interruptible ); +/* +* PARAMETERS +* h_wait_obj +* [in] A handle to the wait object 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 wait object +* 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 +* wait object is triggered and never timeout. +* +* If the timeout value is zero, this function simply tests the state of +* the wait object. +* +* If the wait object is already in the signalled state at the time of the call +* to cl_waitobj_wait_on, the call completes immediately with CL_SUCCESS. +* +* In kernel mode, a pointer to a cl_event_t can safely be used instead of +* a wait object handle. +* +* SEE ALSO +* Wait Object, cl_waitobj_create, cl_waitobj_destroy, +* cl_waitobj_ref, cl_waitobj_deref, +* cl_waitobj_signal, cl_waitobj_reset +*********/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + + +#endif /* _CL_WAITOBJ_H_ */ diff --git a/branches/WOF2-3/inc/complib/comp_lib.h b/branches/WOF2-3/inc/complib/comp_lib.h new file mode 100644 index 00000000..39f5e0cb --- /dev/null +++ b/branches/WOF2-3/inc/complib/comp_lib.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * Abstract: + * One stop shopping for component library headers. + * + * Environment: + * All + */ + + +#ifndef _CL_LIB_H_ +#define _CL_LIB_H_ + + +/****h* Component Library/Component Library +* NAME +* component library +* +* DESCRIPTION +* The component library is a collection of components that can be used to +* create complex projects quickly and reliably. +* +* The component library simplifies development by eliminating the need to +* re-implement existing functionality. This contributes to shorter +* development cycles as well as smaller code bases, helping reduce the +* number of bugs by leveraging tried and tested code. +* +* The component library also provides the same interface in multiple +* environments, such as kernel mode and user mode, allowing code to be used +* in both, again reducing code duplication and development life cycles. +* +* Components of the library all follow the same usage model, as follows: +* - The constructor for all components should be called before any other +* function for that component. It is acceptable to call the initializer +* without first calling the constructor. +* +* - The initializer for all components must be called successfully +* before any function manipulating that component is called. +* +* - The destructor for all components must be called if the initializer +* was called. +* +* In a debug build, the components assert that the proper sequence is +* followed. +*********/ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#endif /* _CL_LIB_H_ */ diff --git a/branches/WOF2-3/inc/iba/ib_al.h b/branches/WOF2-3/inc/iba/ib_al.h new file mode 100644 index 00000000..ba30e9be --- /dev/null +++ b/branches/WOF2-3/inc/iba/ib_al.h @@ -0,0 +1,10095 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#if !defined(__IB_AL_H__) +#define __IB_AL_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/****h* IB Access Layer API/Access Layer +* NAME +* InfiniBand Access Layer +* COPYRIGHT +* Copyright (c) 2003 Intel Corporation - All Rights Reserved. +* DESCRIPTION +* The access layer provides transport level access to an InfiniBand fabric. +* It supplies a foundation upon which a channel driver may be built. The +* access layer exposes the capabilities of the InfiniBand architecture and +* adds support for higher-level functionality required by most users of an +* InfiniBand fabric. Users define the protocols and policies used by the +* access layer, and the access layer implements them under the direction +* of a user. +****/ + +typedef struct _ib_al* ib_al_handle_t; +typedef struct _al_pnp* ib_pnp_handle_t; +typedef struct _al_reg_svc* ib_reg_svc_handle_t; +typedef struct _al_mad_send* ib_mad_send_handle_t; +typedef struct _al_mad_svc* ib_mad_svc_handle_t; +typedef struct _al_query* ib_query_handle_t; +typedef struct _al_sub* ib_sub_handle_t; +typedef struct _al_listen* ib_listen_handle_t; +typedef struct _al_ioc* ib_ioc_handle_t; +typedef struct _al_svc_entry* ib_svc_handle_t; +typedef struct _al_pool_key* ib_pool_key_t; +typedef struct _al_pool* ib_pool_handle_t; +typedef struct _mlnx_fmr_pool_element* mlnx_fmr_pool_el_t; + + +typedef struct _ib_cm_handle +{ + ib_al_handle_t h_al; + ib_qp_handle_t h_qp; + net32_t cid; + +} ib_cm_handle_t; + + +/****s* Access Layer/ib_shmid_t +* NAME +* ib_shmid_t +* +* DESCRIPTION +* Shared Memory Identifier, used to uniquely identify a shared memory region. +* +* SYNOPSIS +*/ +typedef uint8_t ib_shmid_t[64]; +/* +* SEE ALSO +* ib_reg_shmid +*********/ + + +/****d* Access Layer/ATS +* NAME +* DAPL Address Translation Service +* +* DESCRIPTION +* ATS service ID, service name, and IPv4 offset for DAPL-compliant +* ATS service records. +*/ +#define ATS_SERVICE_ID CL_NTOH64( 0x10000CE100415453 ) +#define ATS_NAME "DAPL Address Translation Service" +#define ATS_IPV4_OFFSET 12 +/**********/ + + +/****s* Access Layer/ib_mad_element_t +* NAME +* ib_mad_element_t +* +* DESCRIPTION +* Information used to submit a work request to a management datagram (MAD) +* queue pair. +* +* SYNOPSIS +*/ +typedef struct _ib_mad_element +{ + TO_LONG_PTR(struct _ib_mad_element*, p_next); + TO_LONG_PTR(const void*, context1); + TO_LONG_PTR(const void*, context2); + + /* Request/completion data. */ + TO_LONG_PTR(ib_mad_t*, p_mad_buf); + uint32_t size; + uint32_t immediate_data; + ib_net32_t remote_qp; + + /* Send request information. */ + TO_LONG_PTR(ib_av_handle_t, h_av); + ib_send_opt_t send_opt; + ib_net32_t remote_qkey; + boolean_t resp_expected; + uint32_t timeout_ms; + uint32_t retry_cnt; + uint8_t rmpp_version; + + /* Completion information. */ + ib_wc_status_t status; + boolean_t grh_valid; + TO_LONG_PTR(ib_grh_t*, p_grh); + + /* Completed receive data or send request information if h_av is NULL. */ + uint32_t recv_opt; + ib_net16_t remote_lid; + uint8_t remote_sl; + uint16_t pkey_index; + uint8_t path_bits; + + /* Transaction completion data. */ + TO_LONG_PTR(void*, send_context1); + TO_LONG_PTR(void*, send_context2); + +} ib_mad_element_t; +/* +* FIELDS +* p_next +* A pointer used to chain MAD elements together. This value is +* set to NULL to mark the end of the chain. +* +* context1 +* User-defined context information associated with the datagram. +* +* context2 +* User-defined context information associated with the datagram. +* +* p_buffer +* The local data buffer contain the MAD. +* +* size +* The size of the MAD referenced by p_buffer. +* +* immediate_data +* 32-bit field sent or received as part of a datagram message. +* This field is valid for send operations if the send_opt +* IB_SEND_OPT_IMMEDIATE flag has been set. This field is valid +* on received datagram completions if the recv_opt +* IB_RECV_OPT_IMMEDIATE flag is set. +* +* remote_qp +* Identifies the destination queue pair of a datagram send operation or +* the source queue pair of a received datagram. +* +* h_av +* An address vector that specifies the path information used to route +* the outbound datagram to the destination queue pair. This handle may +* be NULL when sending a directed route SMP or if the access layer +* should create the address vector for the user. +* +* send_opt +* Optional send control parameters. The following options are valid: +* IB_SEND_OPT_IMMEDIATE and IB_SEND_OPT_SOLICITED. IB_SEND_OPT_FENCE +* is only valid on MAD QPs. +* +* remote_qkey +* The qkey for the destination queue pair. +* +* resp_expected +* This field is used to indicate that the submitted operation expects +* a response. When set, the access layer will retry this send operation +* until the corresponding response is successfully received, or the +* request times out. Send operations for which a response is expected +* will always be completed by the access layer before the corresponding +* received response. +* +* timeout_ms +* Specifies the number of milliseconds to wait for a response to +* a request until retrying or timing out the request. This field is +* ignored if resp_expected is set to FALSE. +* +* retry_cnt +* Specifies the number of times that the request will be retried +* before failing the request. This field is ignored if resp_expected +* is set to FALSE. +* +* rmpp_version +* Indicates the version of the RMPP protocol to use when sending this +* MAD. For MADs posted to MAD services of type IB_MAD_SVC_DEFAULT, +* setting this field to 0 disables RMPP on user-defined management +* classes or invokes the default RMPP version for well-defined management +* classes, if appropriate. For MADs posted to MAD services of type +* IB_MAD_SVC_RMPP, setting this field to 0 disables RMPP on the sent +* MAD. Note that if the RMPP header exists, but the RMPP protocol is +* not activated for this MAD, the user must ensure that the RMPP header +* has been zeroed. This field is intended to help support backwards +* compatibility. +* +* status +* The result of the MAD work request. +* +* grh_valid +* A flag indicating whether the p_grh reference is valid. +* +* p_grh +* A reference to the global route header information. +* +* recv_opt +* Indicates optional fields valid as part of a work request that +* completed on an unreliable datagram queue pair. +* +* remote_lid +* The source LID of the received datagram. +* +* remote_sl +* The service level used by the source of the received datagram. +* +* pkey_index +* This is valid only for IB_QPT_QP1 and IB_QPT_QP1_ALIAS QP types. +* For received datagrams, this field contains the pkey index for +* the source queue pair. For send operations, this field contains +* the pkey index to use when posting the send work request. +* +* path_bits +* The portion of the remote_lid that may be changed to vary the path +* through the subnet to the remote port. +* +* send_context1 +* If this datagram was received as a response to a sent datagram, this +* field contains the context1 value of the send operation. If this is +* an unsolicited receive, this field will be 0. +* +* send_context2 +* If this datagram was received as a response to a sent datagram, this +* field contains the context2 value of the send operation. If this is +* an unsolicited receive, this field will be 0. +* +* remote_qp +* Identifies the source queue pair of a received datagram. +* +* NOTES +* The format of data sent over the fabric is expected to be in the form +* of a MAD. MADs are expected to match the format defined by the +* Infiniband specification and must be in network-byte order when posted +* to a MAD service. +* +* This structure is received to notify a user that a datagram has been +* received for a registered management class. Information of the source +* of the data is provided, along with the data buffer. +* +* The MAD element structure is defined such that a received MAD element +* may be re-used as a sent response. In such cases, the h_av field may be +* NULL. The address vector will be created and destroyed by the access +* layer. +* +* SEE ALSO +* ib_get_mad, ib_put_mad, ib_send_mad, ib_local_ds_t, ib_send_opt_t, +* ib_pfn_mad_recv_cb_t, ib_get_mad_buf +*****/ + + +/****f* Access Layer/ib_get_mad_buf +* NAME +* ib_get_mad_buf +* +* DESCRIPTION +* Returns a pointer to the MAD buffer associated with a MAD element. +* +* SYNOPSIS +*/ +#pragma warning(push) +#pragma warning(disable: 4244 ) +AL_INLINE void* AL_API +ib_get_mad_buf( + IN const ib_mad_element_t* const p_mad_element ) +{ + CL_ASSERT( p_mad_element ); + return( p_mad_element->p_mad_buf ); +} +#pragma warning (pop) +/* +* PARAMETERS +* p_mad_element +* [in] A pointer to a MAD element. +* +* NOTES +* Returns a pointer to the MAD buffer associated with a MAD element. +* +* SEE ALSO +* ib_mad_element_t +*****/ + + +/****f* Access Layer/ib_pfn_comp_cb_t +* NAME +* ib_pfn_comp_cb_t +* +* DESCRIPTION +* Completion callback provided by a client. +* +* SYNOPSIS +*/ +typedef void +(AL_API *ib_pfn_comp_cb_t)( + IN const ib_cq_handle_t h_cq, + IN void *cq_context ); +/* +* PARAMETERS +* h_cq +* [in] Handle for the completion queue on which the completion occurred. +* +* cq_context +* [in] User-specified context for the completion queue on which the +* completion occurred. +* +* NOTES +* This function is invoked upon completion of a work request on a queue pair +* associated with the completion queue. The context associated with the +* completion queue on which the completion occurred is return to the client +* through the callback. +* +* In the kernel, this callback is usually invoked using a tasklet, dependent +* on the implementation of the underlying verbs provider driver. +*****/ + + +/****d* Access Layer/ib_al_flags_t +* NAME +* ib_al_flags_t +* +* DESCRIPTION +* Access layer flags used to direct the operation of various calls. +* +* SYNOPSIS +*/ +typedef uint32_t ib_al_flags_t; +#define IB_FLAGS_SYNC 0x00000001 +/* +* VALUES +* IB_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 +* ib_cm_req_t, ib_cm_rep_t, ib_cm_dreq_t, ib_cm_lap_t, +* ib_reg_svc_req_t, ib_mcast_req_t, ib_query_req_t, ib_sub_req_t +*****/ + + +/****f* Access Layer/ib_pfn_destroy_cb_t +* NAME +* ib_pfn_destroy_cb_t +* +* DESCRIPTION +* Asynchronous callback invoked after a resource has been successfully +* destroyed. +* +* SYNOPSIS +*/ +typedef void +(AL_API *ib_pfn_destroy_cb_t)( + IN void *context ); +/* +* PARAMETERS +* context +* [in] User-specified context associated with the resource being +* destroyed. The context for the resource is usually set during the +* object's creation. +* +* NOTES +* This callback notifies a client that a resource has been successfully +* destroyed. It is used to indicate that all pending callbacks associated +* with the resource have completed, and no additional events will be +* generated for that resource. +* +* This callback is invoked within a system thread context in the kernel. +* +* If the user specifies ib_sync_destroy as the asynchronous callback, then +* the object being destroyed will be destroyed synchronously. This may +* result in the calling thread blocking while outstanding callbacks complete. +* +* SEE ALSO +* ib_sync_destroy +*****/ + + + +/****f* Access Layer/ib_sync_destroy +* NAME +* ib_sync_destroy +* +* DESCRIPTION +* Access layer routine used to indicate synchronous destruction of an +* object. +* +* SYNOPSIS +*/ +static const ib_pfn_destroy_cb_t ib_sync_destroy = (ib_pfn_destroy_cb_t)(LONG_PTR)-1; +/* +* PARAMETERS +* Not Applicable. +* +* NOTES +* Users specify ib_sync_destroy as the ib_pfn_destroy_cb_t callback in order +* to force synchronous object destruction. This may result in the calling +* thread blocking while outstanding callbacks complete. +* +* SEE ALSO +* ib_pfn_destroy_cb_t +*****/ + + +/****s* Access Layer/ib_async_event_rec_t +* NAME +* ib_async_event_rec_t +* +* DESCRIPTION +* Information returned when an asynchronous event occurs on an allocated +* resource. +* +* SYNOPSIS +*/ +typedef struct _ib_async_event_rec +{ + ib_async_event_t code; + uint64_t vendor_specific; + + TO_LONG_PTR(void*, context); + union _handle_t + { + TO_LONG_PTR(ib_ca_handle_t, h_ca); + TO_LONG_PTR(ib_cq_handle_t, h_cq); + TO_LONG_PTR(ib_qp_handle_t, h_qp); + TO_LONG_PTR(struct _ib_srq*, h_srq); + + } handle; + + uint8_t port_number; + +} ib_async_event_rec_t; +/* +* FIELDS +* code +* A code that identifies the type of event being reported. +* +* vendor_specific +* A field containing optional vendor specific information. +* +* context +* User-defined context information associated with the resource on +* which the error occurred. +* +* handle +* A handle to the resource for which this event record was generated. +* This handle will match the handle returned during the creation of +* resource. It is provided in case an event occurs before a client's +* call to create a resource can return. +* +* SEE ALSO +* ib_async_event_t, ib_pfn_event_cb_t +*****/ + + +/****f* Access Layer/ib_pfn_event_cb_t +* NAME +* ib_pfn_event_cb_t +* +* DESCRIPTION +* A user-specified callback that is invoked after an asynchronous event +* has occurred on an allocated resource. +* +* SYNOPSIS +*/ +typedef void +(AL_API *ib_pfn_event_cb_t)( + IN ib_async_event_rec_t *p_event_rec ); +/* +* PARAMETERS +* p_event_rec +* [in] Information returned to the user, indicating the type of +* event and the associated user context. +* +* NOTES +* This callback is invoked within a system thread context in the kernel. +* +* SEE ALSO +* ib_async_event_rec_t +*****/ + + +/****f* Access Layer/ib_open_ca +* NAME +* ib_open_ca +* +* DESCRIPTION +* Opens a channel adapter for additional access. A channel adapter must +* be opened before consuming resources on that adapter. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_open_ca( + IN const ib_al_handle_t h_al, + IN const ib_net64_t ca_guid, + IN const ib_pfn_event_cb_t pfn_ca_event_cb OPTIONAL, + IN const void* const ca_context, + OUT ib_ca_handle_t* const ph_ca ); +/* +* PARAMETERS +* h_al +* [in] The handle to an open instance of AL. +* +* ca_guid +* [in] The GUID of the channel adapter to open. +* +* pfn_ca_event_cb +* [in] A user-specified callback that is invoked after an +* asynchronous event has occurred on the channel adapter. +* +* ca_context +* [in] A client-specified context to associate with this opened instance +* of the channel adapter. This context is returned to the user when +* invoking asynchronous callbacks referencing this channel adapter. +* +* ph_ca +* [out] Upon successful completion of this call, this references a +* handle to the opened channel adapter. +* +* RETURN VALUES +* IB_SUCCESS +* The operation was successful. +* +* IB_INVALID_AL_HANDLE +* The access layer handle was invalid. +* +* IB_INVALID_GUID +* No channel adapter in the system was found for the specified ca_guid. +* +* IB_INVALID_PARAMETER +* A reference to the CA handle was not provided. +* +* IB_INSUFFICIENT_MEMORY +* There was insufficient memory to open the channel adapter. +* +* NOTES +* When successful, this routine returns a handle to an open instance of a CA. +* +* SEE ALSO +* ib_query_ca, ib_modify_ca, ib_close_ca, ib_pfn_event_cb_t +*****/ + + +/****f* Access Layer/ib_query_ca +* NAME +* ib_query_ca +* +* DESCRIPTION +* Queries the attributes of an opened channel adapter. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_query_ca( + IN const ib_ca_handle_t h_ca, + OUT ib_ca_attr_t* const p_ca_attr OPTIONAL, + IN OUT uint32_t* const p_size ); +/* +* PARAMETERS +* h_ca +* [in] The handle to an open channel adapter. +* +* p_ca_attr +* [out] A reference to a buffer where the channel adapter attributes, +* including port attribute information will be copied. If this parameter +* is NULL, then the required buffer size needed to return all of the CA +* attribute information is returned through the p_size parameter. The +* ib_ca_attr_t structure for the specified channel adapter is stored +* at the top of the buffer. +* +* p_size +* [in/out] On input, this references the size of the data buffer +* referenced by the p_ca_attr parameter. +* +* On output, the number of bytes used or needed to copy all CA +* attribute information. +* +* RETURN VALUES +* IB_SUCCESS +* The attributes were returned successfully. +* +* IB_INVALID_CA_HANDLE +* The channel adapter handle was invalid. +* +* IB_INSUFFICIENT_MEMORY +* The size of the p_ca_attr buffer, specified through p_size, is +* insufficient to store all of the CA attribute information. +* +* IB_INVALID_PARAMETER +* A reference to the size was not provided. +* +* NOTES +* This routine returns information about the specified channel adapter, +* including port attributes. The amount of information returned through +* this call is variable sized. Users may obtain the size of the data +* buffer required to obtain the CA attributes by calling this function +* with p_ca_attr set to NULL. The access layer will then return the +* necessary size in the variable referenced by the p_size parameter. +* +* SEE ALSO +* ib_open_ca, ib_query_ca_by_guid, ib_modify_ca, ib_close_ca, ib_ca_attr_t +*****/ + + +/****f* Access Layer/ib_query_ca_by_guid +* NAME +* ib_query_ca_by_guid +* +* DESCRIPTION +* Queries the attributes of an opened channel adapter. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_query_ca_by_guid( + IN const ib_al_handle_t h_al, + IN const ib_net64_t ca_guid, + OUT ib_ca_attr_t* const p_ca_attr OPTIONAL, + IN OUT uint32_t* const p_size ); +/* +* PARAMETERS +* h_al +* [in] The handle to an open instance of AL. +* +* ca_guid +* [in] The GUID of the channel adapter to query. +* +* p_ca_attr +* [out] A reference to a buffer where the channel adapter attributes, +* including port attribute information will be copied. If this parameter +* is NULL, then the required buffer size needed to return all of the CA +* attribute information is returned through the p_size parameter. The +* ib_ca_attr_t structure for the specified channel adapter is stored +* at the top of the buffer. +* +* p_size +* [in/out] On input, this references the size of the data buffer +* referenced by the p_ca_attr parameter. +* +* On output, the number of bytes used or needed to copy all CA +* attribute information. +* +* RETURN VALUES +* IB_SUCCESS +* The attributes were returned successfully. +* +* IB_INVALID_AL_HANDLE +* The access layer handle was invalid. +* +* IB_INVALID_GUID +* No channel adapter in the system was found for the specified ca_guid. +* +* IB_INSUFFICIENT_MEMORY +* The size of the p_ca_attr buffer, specified through p_size, is +* insufficient to store all of the CA attribute information. +* +* IB_INVALID_PARAMETER +* A reference to the size was not provided. +* +* NOTES +* This routine returns information about the specified channel adapter, +* including port attributes. The amount of information returned through +* this call is variable sized. Users may obtain the size of the data +* buffer required to obtain the CA attributes by calling this function +* with p_ca_attr set to NULL. The access layer will then return the +* necessary size in the variable referenced by the p_size parameter. +* +* SEE ALSO +* ib_open_ca, ib_query_ca, ib_modify_ca, ib_close_ca, ib_ca_attr_t +*****/ + + +/****f* Access Layer/ib_modify_ca +* NAME +* ib_modify_ca +* +* DESCRIPTION +* Modifies the attributes and violation counters associated with a port. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_modify_ca( + IN const ib_ca_handle_t h_ca, + IN const uint8_t port_num, + IN const ib_ca_mod_t ca_mod, + IN const ib_port_attr_mod_t* const p_port_attr_mod ); +/* +* PARAMETERS +* h_ca +* [in] A handle to an opened channel adapter. +* +* port_num +* [in] An index to the port that is being modified. The port_num matches +* the index of the port as returned through the ib_query_ca call. +* +* ca_mod +* [in] A mask of the attributes and counters to modify. +* +* p_port_attr_mod +* [in] A list of the specific port attribute information to modify. For +* the access layer to modify an attribute, its corresponding bit must be +* set in the ca_mod parameter. +* +* RETURN VALUES +* IB_SUCCESS +* The attributes were successfully modified. +* +* IB_INVALID_CA_HANDLE +* The channel adapter handle was invalid. +* +* IB_INVALID_PORT +* The port number supplied was invalid for the given channel adapter. +* +* IB_INVALID_PARAMETER +* The supplied ca_mod mask is invalid or a reference to the port +* attribute information was not provided. +* +* IB_UNSUPPORTED +* The optional qkey and pkey violation counters are not supported by +* this channel adapter, but an attempt was made to modify them. +* +* NOTES +* This call sets the attributes for a port in its associated PORT_INFO +* structure. It will also reset pkey and qkey violation counters. +* +* SEE ALSO +* ib_open_ca, ib_query_ca, ib_close_ca, ib_ca_mod_t, ib_port_attr_mod_t +*****/ + + +/****f* Access Layer/ib_close_ca +* NAME +* ib_close_ca +* +* DESCRIPTION +* Closes an opened channel adapter. Once closed, no further access to this +* channel adapter is possible. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_close_ca( + IN const ib_ca_handle_t h_ca, + IN const ib_pfn_destroy_cb_t pfn_destroy_cb OPTIONAL ); +/* +* PARAMETERS +* h_ca +* [in] A handle to an opened channel adapter. +* +* pfn_destroy_cb +* [in] A user-specified callback that is invoked after the channel +* adapter has been successfully destroyed. +* +* RETURN VALUES +* IB_SUCCESS +* The close request was registered. +* +* IB_INVALID_CA_HANDLE +* The channel adapter handle was invalid. +* +* NOTES +* This call closes the opened channel adapter and frees all associated +* resources, such as queue pairs, protection domains, and completion +* queues. Since callbacks may be outstanding against the channel adapter +* or one of its resources at the time the close operation is invoked, this +* call operates asynchronously. The user will be notified through a callback +* once the close operation completes, indicating that no additional callbacks +* will be invoked for the specified channel adapter or a related resource. +* +* SEE ALSO +* ib_open_ca +*****/ + + +/****f* Access Layer/ib_alloc_pd +* NAME +* ib_alloc_pd +* +* DESCRIPTION +* Allocates a protection domain on the specified channel adapter. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_alloc_pd( + IN const ib_ca_handle_t h_ca, + IN const ib_pd_type_t pd_type, + IN const void* const pd_context, + OUT ib_pd_handle_t* const ph_pd ); +/* +* PARAMETERS +* h_ca +* [in] A handle to an opened channel adapter. +* +* pd_type +* [in] Indicates the type of protection domain being created. +* +* pd_context +* [in] A client-specified context to associate with this allocated +* protection domain. This context is returned to the user when +* invoking asynchronous callbacks referencing this protection domain. +* +* ph_pd +* [out] Upon successful completion of this call, this references a +* handle to the allocated protection domain. +* +* RETURN VALUES +* IB_SUCCESS +* The operation was successful. +* +* IB_INVALID_CA_HANDLE +* The channel adapter handle was invalid. +* +* IB_INVALID_PARAMETER +* The supplied pd_type value is invalid or a reference to the protection +* domain handle was not provided. +* +* IB_INSUFFICIENT_MEMORY +* There was insufficient memory to allocate the protection domain. +* +* IB_INSUFFICIENT_RESOURCES +* There were insufficient resources currently available on the channel +* adapter to create the protection domain. +* +* NOTES +* When successful, this routine returns a handle to a newly allocated +* protection domain. +* +* SEE ALSO +* ib_dealloc_pd, ib_pd_type_t +*****/ + + +/****f* Access Layer/ib_dealloc_pd +* NAME +* ib_dealloc_pd +* +* DESCRIPTION +* Deallocates a protection domain. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_dealloc_pd( + IN const ib_pd_handle_t h_pd, + IN const ib_pfn_destroy_cb_t pfn_destroy_cb OPTIONAL ); +/* +* PARAMETERS +* h_pd +* [in] A handle to an allocated protection domain. +* +* pfn_destroy_cb +* [in] A user-specified callback that is invoked after the protection +* domain has been successfully destroyed. +* +* RETURN VALUES +* IB_SUCCESS +* The operation was successful. +* +* IB_INVALID_PD_HANDLE +* The protection domain handle was invalid. +* +* NOTES +* This call deallocates a protection domain and releases all associated +* resources, including queue pairs and registered memory regions. Since +* callbacks may be outstanding against one of protection domain's related +* resources at the time the deallocation call is invoked, this call operates +* asynchronously. The user will be notified through a callback once the +* deallocation call completes, indicating that no additional callbacks +* will be invoked for a related resource. +* +* SEE ALSO +* ib_alloc_pd +*****/ + + +/****f* Access Layer/ib_create_av +* NAME +* ib_create_av +* +* DESCRIPTION +* Creates an address vector. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_create_av( + IN const ib_pd_handle_t h_pd, + IN const ib_av_attr_t* const p_av_attr, + OUT ib_av_handle_t* const ph_av ); +/* +* PARAMETERS +* h_pd +* [in] A handle to an allocated protection domain that the address +* vector will be associated with. +* +* p_av_attr +* [in] Attributes for the newly created address vector. +* +* ph_av +* [out] Upon successful completion of this call, this references a +* handle to the newly created address vector. +* +* RETURN VALUES +* IB_SUCCESS +* The operation was successful. +* +* IB_INVALID_PD_HANDLE +* The protection domain handle was invalid. +* +* IB_INVALID_PARAMETER +* A reference to the address vector attributes or handle was not +* provided. +* +* IB_INSUFFICIENT_MEMORY +* There was insufficient memory to create the address vector. +* +* IB_INVALID_PORT +* The port number supplied, through the address vector attributes, +* was invalid for the given channel adapter. +* +* IB_INSUFFICIENT_RESOURCES +* There were insufficient resources currently available on the channel +* adapter to create the address vector. +* +* NOTES +* This routine creates an address vector. Clients specify the attributes +* of the address vector through the p_av_attr parameter. +* +* SEE ALSO +* ib_query_av, ib_modify_av, ib_destroy_av +*****/ + + +/****f* Access Layer/ib_query_av +* NAME +* ib_query_av +* +* DESCRIPTION +* Returns the attributes of an address vector. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_query_av( + IN const ib_av_handle_t h_av, + OUT ib_av_attr_t* const p_av_attr, + OUT ib_pd_handle_t* const ph_pd ); +/* +* PARAMETERS +* h_av +* [in] A handle to an existing address vector. +* +* p_av_attr +* [out] Upon successful completion, the structure referenced by this +* parameter contains the attributes of the specified address vector. +* +* ph_pd +* [out] Upon successful completion, this references a handle to the +* protection domain associated with the address vector. +* +* RETURN VALUES +* IB_SUCCESS +* The attributes were returned successfully. +* +* IB_INVALID_AV_HANDLE +* The address vector handle was invalid. +* +* IB_INVALID_PARAMETER +* A reference to the address vector attributes structure or protection +* domain handle was not provided. +* +* SEE ALSO +* ib_create_av, ib_modify_av, ib_destroy_av, ib_av_attr_t +*****/ + + +/****f* Access Layer/ib_modify_av +* NAME +* ib_modify_av +* +* DESCRIPTION +* Modifies the attributes of an existing address vector. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_modify_av( + IN const ib_av_handle_t h_av, + IN const ib_av_attr_t* const p_av_attr ); +/* +* PARAMETERS +* h_av +* [in] A handle to an existing address vector. +* +* p_av_attr +* [in] The new attributes to use when modifying the address vector. +* +* RETURN VALUES +* IB_SUCCESS +* The address vector was successfully modified. +* +* IB_INVALID_AV_HANDLE +* The address vector handle was invalid. +* +* IB_INVALID_PARAMETER +* A reference to the address vector attributes structure was not +* provided. +* +* IB_INVALID_PORT +* The port number supplied, through the address vector attributes, +* was invalid for the given channel adapter. +* +* NOTES +* This routine modifies the attributes of an existing address vector. +* The new attributes are specified through the p_av_attr parameter. +* +* SEE ALSO +* ib_create_av, ib_destroy_av +*****/ + + +/****f* Access Layer/ib_destroy_av +* NAME +* ib_destroy_av +* +* DESCRIPTION +* Destroys an existing address vector. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_destroy_av( + IN const ib_av_handle_t h_av ); +/* +* PARAMETERS +* h_av +* [in] A handle to an existing address vector. +* +* RETURN VALUES +* IB_SUCCESS +* The address vector was successfully destroyed. +* +* IB_INVALID_AV_HANDLE +* The address vector handle was invalid. +* +* NOTES +* This routine destroys an existing address vector. +* +* SEE ALSO +* ib_create_av +*****/ + + +/****f* Access Layer/ib_create_srq +* NAME +* ib_create_srq +* +* DESCRIPTION +* Creates a shared receive queue and returns its handle to the user. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_create_srq( + IN const ib_pd_handle_t h_pd, + IN const ib_srq_attr_t* const p_srq_attr, + IN const void* const srq_context, + IN const ib_pfn_event_cb_t pfn_srq_event_cb OPTIONAL, + OUT ib_srq_handle_t* const ph_srq ); +/* +* PARAMETERS +* h_pd +* [in] This is a handle to a protection domain associated with the shared queue +* pair. +* +* p_srq_attr +* [in] Attributes necessary to allocate and initialize a shared receive queue. +* +* srq_context +* [in] A user-specified context information associated with the shared +* receive queue. +* +* pfn_qp_event_cb +* [in] User-specified error callback routine invoked after an +* asynchronous event has occurred on the shared receive queue. +* +* ph_srq +* [out] Upon successful completion of this call, this references a +* handle to the newly created shared receive queue. +* +* RETURN VALUES +* IB_SUCCESS +* The receive queue was successfully created. +* +* IB_INVALID_PD_HANDLE +* The protection domain to associate with the shared receive queue was invalid. +* +* IB_INVALID_PARAMETER +* A reference to the shared receive queue attributes or handle was not provided. +* +* IB_INSUFFICIENT_MEMORY +* There was insufficient memory to create the shared receive queue. +* +* IB_INSUFFICIENT_RESOURCES +* There were insufficient resources currently available on the channel +* adapter to create the shared receive queue. +* +* IB_INVALID_SETTING +* The specified shared receive queue creation attributes are invalid. +* +* IB_INVALID_MAX_WRS +* The requested maximum send or receive work request depth could not be +* supported. +* +* IB_INVALID_MAX_SGE +* The requested maximum number of scatter-gather entries for the send or +* receive queue could not be supported. +* +* NOTES +* This routine allocates a shared receive queue with the specified attributes. If +* the shared receive queue cannot be allocated, an error is returned. When creating +* the shared receive queue, users associate a context with the shared receive queue. This +* context is returned to the user through the asynchronous event callback +* if an event occurs. +* +* This routine is used to create receive queues, which work with QPs of type: +* +* IB_QPT_RELIABLE_CONN +* IB_QPT_UNRELIABLE_CONN +* IB_QPT_UNRELIABLE_DGRM +* +* SEE ALSO +* ib_query_srq, ib_modify_srq, ib_destroy_srq, ib_srq_attr_t, +* ib_srq_attr_mask_t, ib_pfn_event_cb_t, ib_qp_attr_t +*****/ + + +/****f* Access Layer/ib_query_srq +* NAME +* ib_query_srq +* +* DESCRIPTION +* Query the current attributes of the shared receive queue. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_query_srq( + IN const ib_srq_handle_t h_srq, + OUT ib_srq_attr_t* const p_srq_attr ); +/* +* PARAMETERS +* h_srq +* [in] A handle to an existing shared receive queue. +* +* p_srq_attr +* [out] Upon successful completion of this call, the structure +* referenced by this parameter contains the attributes of the specified +* quere pair. +* +* RETURN VALUES +* IB_SUCCESS +* The shared receive queue attributes were returned successfully. +* +* IB_INVALID_SRQ_HANDLE +* The shared receive queue handle was invalid. +* +* IB_INVALID_PARAMETER +* A reference to the shared receive queue attributes structure was not provided. +* +* NOTES +* This routine returns information about the specified shared receive queue. +* +* SEE ALSO +* ib_query_srq, ib_modify_srq, ib_destroy_srq, ib_srq_attr_t, +* ib_srq_attr_mask_t, ib_pfn_event_cb_t, ib_qp_attr_t +*****/ + + +/****f* Access Layer/ib_modify_srq +* NAME +* ib_modify_srq +* +* DESCRIPTION +* Modifies the attributes of an existing shared receive queue. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_modify_srq( + IN const ib_srq_handle_t h_srq, + IN const ib_srq_attr_t* const p_srq_attr, + IN const ib_srq_attr_mask_t srq_attr_mask ); +/* +* PARAMETERS +* h_srq +* [in] A handle to an existing shared receive queue. +* +* p_srq_attr +* [in] Attributes necessary to allocate and initialize a shared receive queue. +* +* srq_attr_mask +* [in] Flags, indicating which fields in the previous structure are valid. +* +* RETURN VALUES +* IB_SUCCESS +* The shared receive queue was successfully modified. +* +* IB_INVALID_SRQ_HANDLE +* The shared receive queue handle was invalid. +* +* IB_INVALID_PARAMETER +* A reference to the shared receive queue attributes was not provided. +* +* IB_INVALID_SETTING +* The specified shared receive queue attributes were invalid. +* +* IB_UNSUPPORTED +* The required action is not supported yet. +* +* IB_INSUFFICIENT_RESOURCES +* There were insufficient resources currently available on the channel +* adapter to register the modify the shared receive queue. +* +* NOTES +* This routine modifies the attributes of an existing shared receive queue and +* transitions it to a new state. The new state and attributes are +* specified through the p_qp_mod parameter. Upon successful completion, +* the shared receive queue is in the requested state. +* +* SEE ALSO +* ib_query_srq, ib_modify_srq, ib_destroy_srq, ib_srq_attr_t, +* ib_srq_attr_mask_t, ib_pfn_event_cb_t, ib_qp_attr_t +*****/ + + +/****f* Access Layer/ib_destroy_srq +* NAME +* ib_destroy_srq +* +* DESCRIPTION +* Release a shared receive queue. Once destroyed, no further access to this +* shared receive queue is possible. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_destroy_srq( + IN const ib_srq_handle_t h_srq, + IN const ib_pfn_destroy_cb_t pfn_destroy_cb OPTIONAL ); +/* +* PARAMETERS +* h_srq +* [in] A handle to an existing shared shared receive queue. +* +* pfn_destroy_cb +* [in] A user-specified callback that is invoked after the shared receive queue +* has been successfully destroyed. +* +* RETURN VALUES +* IB_SUCCESS +* The destroy request was registered. +* +* IB_INVALID_SRQ_HANDLE +* The shared receive queue handle was invalid. +* +* IB_RESOURCE_BUSY +* There are QPs, bound to the shared receive queue +* +* NOTES +* This call destroys an existing shared receive queue. Since callbacks may be +* outstanding against the shared receive queue at the time the destroy operation is +* invoked, then this call operates asynchronously. The user will be notified +* through a callback once the destroy operation completes, indicating that +* no additional callbacks will be invoked for the specified shared receive queue. +* +* SEE ALSO +* ib_query_srq, ib_modify_srq, ib_destroy_srq, ib_srq_attr_t, +* ib_srq_attr_mask_t, ib_pfn_event_cb_t, ib_qp_attr_t +*****/ + + +/****f* Access Layer/ib_post_srq_recv +* NAME +* ib_post_srq_recv +* +* DESCRIPTION +* This routine posts a work request to the shared receive queue of a shared receive queue. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_post_srq_recv( + IN const ib_srq_handle_t h_srq, + IN ib_recv_wr_t* const p_recv_wr, + OUT ib_recv_wr_t **pp_recv_failure OPTIONAL ); +/* +* PARAMETERS +* h_srq +* [in] The shared receive queue to which this work request is being submitted. +* +* p_recv_wr +* [in] A reference to the head of the work request list. +* +* pp_recv_failure +* [out] If the post receive operation failed, this references the work +* request in the p_recv_wr list where the first failure occurred. +* This parameter may be NULL if only a single work request is being +* posted to the QP. +* +* RETURN VALUES +* IB_SUCCESS +* All work requests were successfully posted. +* +* IB_INVALID_QP_HANDLE +* The shared receive queue handle was invalid. +* +* IB_INVALID_PARAMETER +* A reference to the receive work request list was not provided. +* +* IB_INSUFFICIENT_RESOURCES +* The number of posted work requests exceed the current depth available +* on the receive queue. +* +* IB_INVALID_WR_TYPE +* The work request type was invalid. +* +* IB_INVALID_QP_STATE +* The current shared receive queue state does not allow posting receives. +* +* NOTES +* This routine posts a work request to the shared receive queue. +* The type of work to perform is defined by the p_recv_wr parameter. This +* call is used to post data buffers to receive incoming message sends. +* +* SEE ALSO +* ib_recv_wr_t +*****/ + + +/****f* Access Layer/ib_create_qp +* NAME +* ib_create_qp +* +* DESCRIPTION +* Creates a queue pair and returns its handle to the user. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_create_qp( + IN const ib_pd_handle_t h_pd, + IN const ib_qp_create_t* const p_qp_create, + IN const void* const qp_context, + IN const ib_pfn_event_cb_t pfn_qp_event_cb OPTIONAL, + OUT ib_qp_handle_t* const ph_qp ); +/* +* PARAMETERS +* h_pd +* [in] This is a handle to a protection domain associated with the queue +* pair. +* +* p_qp_create +* [in] Attributes necessary to allocate and initialize the queue pair. +* +* qp_context +* [in] A user-specified context information associated with the +* queue pair. +* +* pfn_qp_event_cb +* [in] User-specified error callback routine invoked after an +* asynchronous event has occurred on the queue pair. +* +* ph_qp +* [out] Upon successful completion of this call, this references a +* handle to the newly created queue pair. +* +* RETURN VALUES +* IB_SUCCESS +* The queue pair was successfully created. +* +* IB_INVALID_PD_HANDLE +* The protection domain to associate with the queue pair was invalid. +* +* IB_INVALID_PARAMETER +* A reference to the queue pair attributes or handle was not provided. +* +* IB_INSUFFICIENT_MEMORY +* There was insufficient memory to create the queue pair. +* +* IB_INSUFFICIENT_RESOURCES +* There were insufficient resources currently available on the channel +* adapter to create the queue pair. +* +* IB_INVALID_CQ_HANDLE +* The send or receive completion queue to associate with the queue pair +* was invalid. +* +* IB_INVALID_SRQ_HANDLE +* The shared receive queue to be associated with the queue pair +* was invalid. +* +* IB_INVALID_SETTING +* The specified queue pair creation attributes are invalid. +* +* IB_UNSUPPORTED +* The specified queue pair type was not supported by the channel adapter. +* +* IB_INVALID_MAX_WRS +* The requested maximum send or receive work request depth could not be +* supported. +* +* IB_INVALID_MAX_SGE +* The requested maximum number of scatter-gather entries for the send or +* receive queue could not be supported. +* +* NOTES +* 1. This routine allocates a queue pair with the specified attributes. If +* the queue pair cannot be allocated, an error is returned. When creating +* the queue pair, users associate a context with the queue pair. This +* context is returned to the user through the asynchronous event callback +* if an event occurs. +* +* 2. For QPs that are associated with an SRQ, the Consumer should take +* the QP through the Error State before invoking a Destroy QP or a Modify +* QP to the Reset State. The Consumer may invoke the Destroy QP without +* first performing a Modify QP to the Error State and waiting for the Affiliated +* Asynchronous Last WQE Reached Event. However, if the Consumer +* does not wait for the Affiliated Asynchronous Last WQE Reached Event, +* then WQE and Data Segment leakage may occur. +* +* 3. This routine is used to create queue pairs of type: +* IB_QPT_RELIABLE_CONN +* IB_QPT_UNRELIABLE_CONN +* IB_QPT_UNRELIABLE_DGRM +* IB_QPT_MAD +* +* 4. Callers of ib_create_qp should call ib_init_dgrm_svc if the queue pair +* is of type IB_QPT_UNRELIABLE_DGRM or IB_QPT_MAD before sending or +* receiving data. IB_QPT_RELIABLE_CONN, IB_QPT_UNRELIABLE_CONN type +* queue pairs should be used by the connection establishment process +* before data may be sent or received on the QP. +* +* This call does not return the QP attributes as MAD QPs do not support +* such an operation. This is a minor specification deviation. +* +* SEE ALSO +* ib_query_qp, ib_modify_qp, ib_destroy_qp, ib_cm_req, ib_cm_rep, ib_cm_rtu +* ib_init_dgrm_svc, ib_qp_create_t, ib_pfn_event_cb_t, ib_qp_attr_t +*****/ + + +/****f* Access Layer/ib_get_spl_qp +* NAME +* ib_get_spl_qp +* +* DESCRIPTION +* Create a special QP or QP alias. This call provides access to queue +* pairs 0 and 1, and the raw queue pair types. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_get_spl_qp( + IN const ib_pd_handle_t h_pd, + IN const ib_net64_t port_guid, + IN const ib_qp_create_t* const p_qp_create, + IN const void* const qp_context, + IN const ib_pfn_event_cb_t pfn_qp_event_cb OPTIONAL, + OUT ib_pool_key_t* const p_pool_key OPTIONAL, + OUT ib_qp_handle_t* const ph_qp ); +/* +* PARAMETERS +* h_pd +* [in] This is a handle to a protection domain associated with the queue +* pair. This must be a protection domain alias for aliased QP types. +* +* port_guid +* [in] The port GUID that the special QP will be associated with. +* +* p_qp_create +* [in] Attributes necessary to allocate and initialize the queue pair. +* +* qp_context +* [in] A user-specified context information associated with the +* queue pair. +* +* pfn_qp_ervent_cb +* [in] User-specified error callback routine invoked after an +* asynchronous event has occurred on the queue pair. +* +* p_pool_key +* [in] A key to a pool of MAD elements that are used to send MADs. +* This key is only valid for aliased QP types. +* +* ph_qp +* [out] Upon successful completion of this call, this references a +* handle to the newly created queue pair. +* +* RETURN VALUES +* IB_SUCCESS +* The queue pair was successfully created. +* +* IB_INVALID_PD_HANDLE +* The protection domain to associate with the queue pair was invalid. +* +* IB_INVALID_PORT +* The port number supplied was invalid for the given channel adapter. +* +* IB_INVALID_PARAMETER +* A reference to the queue pair attributes or handle was not provided. +* +* IB_INVALID_PERMISSION +* The calling process does not have sufficient privilege to create the +* requested queue pair type. +* +* IB_INSUFFICIENT_MEMORY +* There was insufficient memory to create the queue pair. +* +* IB_INSUFFICIENT_RESOURCES +* There were insufficient resources currently available on the channel +* adapter to create the queue pair. +* +* IB_INVALID_CQ_HANDLE +* The send or receive completion queue to associate with the queue pair +* was invalid. +* +* IB_INVALID_SETTING +* The specified queue pair type was invalid. +* +* IB_UNSUPPORTED +* The specified queue pair type was not supported by the channel adapter. +* +* IB_INVALID_MAX_WRS +* The requested maximum send or receive work request depth could not be +* supported. +* +* IB_INVALID_MAX_SGE +* The requested maximum number of scatter-gather entries for the send or +* receive queue could not be supported. +* +* NOTES +* This routine allocates a queue pair with the specified attributes. If +* the queue pair cannot be allocated, an error is returned. When creating +* the queue pair, users associate a context with the queue pair. This +* context is returned to the user through the asynchronous event callback +* if an event occurs. +* +* This routine is used to create queue pairs of type: +* +* IB_QPT_QP0 +* IB_QPT_QP1 +* IB_QPT_RAW_IPV6 +* IB_QPT_RAW_ETHER +* IB_QPT_QP0_ALIAS +* IB_QPT_QP1_ALIAS +* +* Callers of ib_get_spl_qp should call ib_init_dgrm_svc if the queue pair is +* of type IB_QPT_QP0, IB_QPT_QP1, IB_QPT_RAW_IPV6, IB_QPT_RAW_ETHER before +* sending or receiving data. MADs may be sent on aliased QPs on the +* successful return of this routine. +* +* SEE ALSO +* ib_query_qp, ib_modify_qp, ib_destroy_qp, ib_get_mad +* ib_init_dgrm_svc, ib_qp_create_t, ib_pfn_event_cb_t, ib_qp_attr_t +*****/ + + +/****f* Access Layer/ib_query_qp +* NAME +* ib_query_qp +* +* DESCRIPTION +* Query the current attributes of the queue pair. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_query_qp( + IN const ib_qp_handle_t h_qp, + OUT ib_qp_attr_t* const p_qp_attr ); +/* +* PARAMETERS +* h_qp +* [in] A handle to an existing queue pair. +* +* p_qp_attr +* [out] Upon successful completion of this call, the structure +* referenced by this parameter contains the attributes of the specified +* quere pair. +* +* RETURN VALUES +* IB_SUCCESS +* The queue pair attributes were returned successfully. +* +* IB_INVALID_QP_HANDLE +* The queue pair handle was invalid. +* +* IB_INVALID_PARAMETER +* A reference to the queue pair attributes structure was not provided. +* +* NOTES +* This routine returns information about the specified queue pair. +* +* SEE ALSO +* ib_create_qp, ib_modify_qp, ib_qp_attr_t +*****/ + + +/****f* Access Layer/ib_modify_qp +* NAME +* ib_modify_qp +* +* DESCRIPTION +* Modifies the attributes of an existing queue pair. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_modify_qp( + IN const ib_qp_handle_t h_qp, + IN const ib_qp_mod_t* const p_qp_mod ); +/* +* PARAMETERS +* h_qp +* [in] A handle to an existing queue pair. +* +* p_qp_mod +* [in] The new attributes to use when modifying the queue pair. +* +* RETURN VALUES +* IB_SUCCESS +* The queue pair was successfully modified. +* +* IB_INVALID_QP_HANDLE +* The queue pair handle was invalid. +* +* IB_INVALID_PARAMETER +* A reference to the queue pair attributes was not provided. +* +* IB_INVALID_SETTING +* The specified queue pair attributes were invalid. +* +* IB_INSUFFICIENT_RESOURCES +* There were insufficient resources currently available on the channel +* adapter to register the modify the queue pair. +* +* IB_UNSUPPORTED +* The requested modification was not supported. +* +* IB_INVALID_QP_STATE +* The queue pair was in an invalid state for the requested operation. +* +* IB_INVALID_PKEY +* The specified pkey was not valid. +* +* IB_INVALID_APM_STATE +* The specified automatic path migration state was not valid. +* +* NOTES +* This routine modifies the attributes of an existing queue pair and +* transitions it to a new state. The new state and attributes are +* specified through the p_qp_mod parameter. Upon successful completion, +* the queue pair is in the requested state. +* +* SEE ALSO +* ib_create_qp, ib_destroy_qp, ib_qp_mod_t +*****/ + + +/****f* Access Layer/ib_destroy_qp +* NAME +* ib_destroy_qp +* +* DESCRIPTION +* Release a queue pair. Once destroyed, no further access to this +* queue pair is possible. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_destroy_qp( + IN const ib_qp_handle_t h_qp, + IN const ib_pfn_destroy_cb_t pfn_destroy_cb OPTIONAL ); +/* +* PARAMETERS +* h_qp +* [in] A handle to an existing queue pair. +* +* pfn_destroy_cb +* [in] A user-specified callback that is invoked after the queue pair +* has been successfully destroyed. +* +* RETURN VALUES +* IB_SUCCESS +* The destroy request was registered. +* +* IB_INVALID_QP_HANDLE +* The queue pair handle was invalid. +* +* NOTES +* This call destroys an existing queue pair. Since callbacks may be +* outstanding against the queue pair at the time the destroy operation is +* invoked, the this call operates asynchronously. The user will be notified +* through a callback once the destroy operation completes, indicating that +* no additional callbacks will be invoked for the specified queue pair. +* +* SEE ALSO +* ib_create_qp +*****/ + + +/****s* Access Layer/ib_cq_create_t +* NAME +* ib_cq_create_t +* +* DESCRIPTION +* Attributes used to initialize a completion queue at creation time. +* +* SYNOPSIS +*/ +typedef struct _ib_cq_create +{ + uint32_t size; + ib_pfn_comp_cb_t pfn_comp_cb; + cl_waitobj_handle_t h_wait_obj; + +} ib_cq_create_t; +/* +* FIELDS +* size +* Specifies the maximum number of work completions that may be on the +* completion queue. If the creation call is successful, the actual +* size of the completion queue will be returned. The actual size of +* the CQ will be greater than or equal to the requested size. +* +* pfn_comp_cb +* A callback that is invoked whenever a signaled completion occurs on +* the completion queue. This field is mutually exclusive with the +* p_event field. +* +* h_wait_obj +* A wait object that is triggered whenever a signaled completion occurs +* on the completion queue. This field is mutually exclusive with the +* pfn_comp_cb field and is only valid for user-mode clients. The wait +* object must be ready for use when the call to ib_create_cq is invoked. +* +* NOTES +* Clients must specify either an event or a callback when creating a +* completion queue. When a signaled completion occurs on the completion +* queue, the client will be notified through the callback or by +* signaling the specified event. +* +* SEE ALSO +* ib_create_cq, ib_pfn_comp_cb_t +*****/ + + +/****f* Access Layer/ib_create_cq +* NAME +* ib_create_cq +* +* DESCRIPTION +* Creates a completion queue and returns its handle to the user. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_create_cq( + IN const ib_ca_handle_t h_ca, + IN OUT ib_cq_create_t* const p_cq_create, + IN const void* const cq_context, + IN const ib_pfn_event_cb_t pfn_cq_event_cb OPTIONAL, + OUT ib_cq_handle_t* const ph_cq ); +/* +* PARAMETERS +* h_ca +* [in] A handle to an open channel adapter. +* +* p_cq_create +* [in] Attributes necessary to allocate and initialize the +* completion queue. +* +* cq_context +* [in] A user-specified context associated with the completion queue. +* +* pfn_cq_event_cb +* [in] User-specified error callback routine invoked after an +* asynchronous event has occurred on the completion queue. +* +* ph_cq +* [out] Upon successful completion of this call, this references a +* handle to the newly created completion queue. +* +* RETURN VALUES +* IB_SUCCESS +* The completion queue was successfully created. +* +* IB_INVALID_CA_HANDLE +* The channel adapter handle was invalid. +* +* IB_INVALID_PARAMETER +* A reference to the completion queue attributes or handle was not +* provided. +* +* IB_INVALID_SETTING +* The specified attributes that should be used to create the completion +* queue are invalid. Both completion callback and wait object +* information were supplied or are missing. +* +* IB_INSUFFICIENT_MEMORY +* There was insufficient memory to create the completion queue. +* +* IB_INSUFFICIENT_RESOURCES +* There were insufficient resources currently available on the channel +* adapter to create the completion queue. +* +* IB_INVALID_CQ_SIZE +* The requested size of the completion queue was larger than the +* maximum supported by the associated channel adapter. +* +* NOTES +* This routine allocates a completion queue on the specified channel +* adapter. If the completion queue cannot be allocated, an error is +* returned. When creating the completion queue, users associate a context +* with the completion queue. This context is returned to the user through +* the completion and asynchronous event callbacks. +* +* SEE ALSO +* ib_query_cq, ib_modify_cq, ib_destroy_cq, ib_cq_create_t, ib_pfn_event_cb_t +*****/ + + +/****f* Access Layer/ib_modify_cq +* NAME +* ib_modify_cq +* +* DESCRIPTION +* Modifies the attributes associated with a completion queue, allowing the +* completion queue to be resized. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_modify_cq( + IN const ib_cq_handle_t h_cq, + IN OUT uint32_t* const p_size ); +/* +* PARAMETERS +* h_cq +* [in] A handle to an existing completion queue. +* +* p_size +* [in/out] Specifies the new size of the completion queue. If the +* modify call is successful, the actual size of the completion queue +* will be returned. The actual size of the CQ will be greater than or +* equal to the requested size. +* +* RETURN VALUES +* IB_SUCCESS +* The completion queue was successfully modified. +* +* IB_INVALID_CQ_HANDLE +* The completion queue handle was invalid. +* +* IB_INVALID_PARAMETER +* A reference to the completion queue size was not provided. +* +* IB_INVALID_CQ_SIZE +* The requested size of the completion queue was larger than the +* maximum supported by the associated channel adapter. +* +* IB_OVERFLOW +* The specified size of the completion queue is smaller than the number +* of work completions currently on the completion queue. +* +* IB_INSUFFICIENT_MEMORY +* There was insufficient memory to modify the completion queue. +* +* NOTES +* This routine allows a client to modify the size of a completion queue. +* If the new size is larger than what the associated channel adapter can +* support, an error is returned. If the completion queue has valid +* completion entries on it and the requested size is smaller than the +* number of entries, an overflow error is returned and the modify +* operation is aborted. +* +* SEE ALSO +* ib_create_cq +*****/ + + +/****f* Access Layer/ib_query_cq +* NAME +* ib_query_cq +* +* DESCRIPTION +* Returns information about the specified completion queue. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_query_cq( + IN const ib_cq_handle_t h_cq, + OUT uint32_t* const p_size ); +/* +* PARAMETERS +* h_cq +* [in] A handle to an existing completion queue. +* +* p_size +* [out] Upon successful completion of this call, contains the actual +* size of the completion queue. +* +* RETURN VALUES +* IB_SUCCESS +* The completion queue was successfully queried. +* +* IB_INVALID_CQ_HANDLE +* The completion queue handle was invalid. +* +* IB_INVALID_PARAMETER +* A reference to the completion queue size was not provided. +* +* SEE ALSO +* ib_create_cq +*****/ + + +/****f* Access Layer/ib_destroy_cq +* NAME +* ib_destroy_cq +* +* DESCRIPTION +* Destroys a completion queue. Once destroyed, no further access to the +* completion queue is possible. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_destroy_cq( + IN const ib_cq_handle_t h_cq, + IN const ib_pfn_destroy_cb_t pfn_destroy_cb OPTIONAL ); +/* +* PARAMETERS +* h_qp +* [in] A handle to an existing completion queue. +* +* pfn_destroy_cb +* [in] A user-provided callback that is invoked after the +* completion queue has been successfully destroyed. +* +* RETURN VALUES +* IB_SUCCESS +* The destroy request was registered. +* +* IB_INVALID_CQ_HANDLE +* The completion queue handle was invalid. +* +* NOTES +* This call destroys an existing completion queue. Since callbacks may be +* outstanding against the completion queue at the time the destroy operation +* is invoked, the this call operates asynchronously. The user will be +* notified through a callback once the destroy operation completes, +* indicating that no additional callbacks will be invoked for the specified +* completion queue. +* +* If there are still queue pairs associated with the completion queue when +* this function is invoked, the destroy operation will fail with status +* IB_RESOURCE_BUSY. +* +* SEE ALSO +* ib_create_cq, ib_pfn_destroy_cb_t +*****/ + + +/****f* Access Layer/ib_reg_mem +* NAME +* ib_reg_mem +* +* DESCRIPTION +* Registers a virtual memory region with a channel adapter. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_reg_mem( + IN const ib_pd_handle_t h_pd, + IN const ib_mr_create_t* const p_mr_create, + OUT net32_t* const p_lkey, + OUT net32_t* const p_rkey, + OUT ib_mr_handle_t* const ph_mr ); +/* +* PARAMETERS +* h_pd +* [in] A handle to an existing protection domain that the memory +* should be registered with. +* +* p_mr_create +* [in] Information describing the memory region to register. +* +* p_lkey +* [out] The local access key associated with this registered memory +* region. +* +* p_rkey +* [out] A key that may be used by a remote end-point when performing +* RDMA or atomic operations to this registered memory region. +* +* ph_mr +* [out] Upon successful completion of this call, this references a +* handle to the registered memory region. This handle is used when +* performing data transfers and to deregister the memory. +* +* RETURN VALUES +* IB_SUCCESS +* The memory region was successfully registered. +* +* IB_INVALID_PD_HANDLE +* The protection domain to associate with the memory region was invalid. +* +* IB_INVALID_PARAMETER +* A reference to the memory region information, lkey, rkey, or handle +* was not provided. +* +* IB_INSUFFICIENT_MEMORY +* There was insufficient memory to register the memory region. +* +* IB_INSUFFICIENT_RESOURCES +* There were insufficient resources currently available on the channel +* adapter to register the memory region. +* +* IB_UNSUPPORTED +* The requested access rights are not supported by the channel adapter. +* +* IB_INVALID_PERMISSION +* The requested access rights are invalid. +* +* NOTES +* This routine registers a virtual memory region with a channel adapter. +* Memory must be registered before being used in a data transfer operation. +* +* SEE ALSO +* ib_dereg_mr, ib_reg_phys, ib_reg_shared, ib_mr_create_t +*****/ + + +/****f* Access Layer/ib_reg_phys +* NAME +* ib_reg_phys +* +* DESCRIPTION +* Registers a physical memory region with a channel adapter. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_reg_phys( + IN const ib_pd_handle_t h_pd, + IN const ib_phys_create_t* const p_phys_create, + IN OUT uint64_t* const p_vaddr, + OUT net32_t* const p_lkey, + OUT net32_t* const p_rkey, + OUT ib_mr_handle_t* const ph_mr ); +/* +* PARAMETERS +* h_pd +* [in] A handle to an existing protection domain that the memory +* should be registered with. +* +* p_phys_create +* [in] Information describing the memory region to register. +* +* p_vaddr +* [in/out] On input, references the requested virtual address for the +* start of the physical region. On output, references the actual +* virtual address assigned to the registered region. +* +* p_lkey +* [out] The local access key associated with this registered memory +* region. +* +* p_rkey +* [out] A key that may be used by a remote end-point when performing +* RDMA or atomic operations to this registered memory region. +* +* ph_mr +* [out] Upon successful completion of this call, this references a +* handle to the registered memory region. This handle is used when +* performing data transfers and to deregister the memory. +* +* RETURN VALUES +* IB_SUCCESS +* The physical memory region was successfully registered. +* +* IB_INVALID_PD_HANDLE +* The protection domain to associate with the physical memory region +* was invalid. +* +* IB_INVALID_PARAMETER +* A reference to the physical memory region information, virtual address, +* lkey, rkey, or handle was not provided. +* +* IB_INSUFFICIENT_MEMORY +* There was insufficient memory to register the physical memory region. +* +* IB_INSUFFICIENT_RESOURCES +* There were insufficient resources currently available on the channel +* adapter to register the physical memory region. +* +* IB_UNSUPPORTED +* The requested access rights are not supported by the channel adapter. +* +* IB_INVALID_PERMISSION +* The requested access rights are invalid. +* +* NOTES +* This routine registers an array of physical pages as a single virtually +* contiguous region with a channel adapter. Memory must be registered +* before being used in a data transfer operation. +* +* SEE ALSO +* ib_dereg_mr, ib_reg_mem, ib_reg_shared, ib_phys_create_t +*****/ + + +/****f* Access Layer/ib_query_mr +* NAME +* ib_query_mr +* +* DESCRIPTION +* Query the current attributes of a memory region. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_query_mr( + IN const ib_mr_handle_t h_mr, + OUT ib_mr_attr_t* const p_mr_attr ); +/* +* PARAMETERS +* h_mr +* [in] A handle to a registered memory region. +* +* p_mr_attr +* [out] A reference to a structure where the registered memory attributes +* will be copied. +* +* RETURN VALUES +* IB_SUCCESS +* The memory region attributes were returned successfully. +* +* IB_INVALID_MR_HANDLE +* The memory region handle was invalid. +* +* IB_INVALID_PARAMETER +* A reference to the memory region attributes was not provided. +* +* NOTES +* This routine returns information about the specified registered memory +* region. +* +* SEE ALSO +* ib_dereg_mr, ib_reg_mem, ib_reg_shared, ib_mr_attr_t +*****/ + + +/****f* Access Layer/ib_rereg_mem +* NAME +* ib_rereg_mem +* +* DESCRIPTION +* Modifies the attributes of an existing memory region. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_rereg_mem( + IN const ib_mr_handle_t h_mr, + IN const ib_mr_mod_t mr_mod_mask, + IN const ib_mr_create_t* const p_mr_create OPTIONAL, + OUT net32_t* const p_lkey, + OUT net32_t* const p_rkey, + IN const ib_pd_handle_t h_pd OPTIONAL ); +/* +* PARAMETERS +* h_mr +* [in] A handle to the registered memory region being modified. +* +* mr_mod_mask +* [in] A mask used to specify which attributes of the memory region are +* being modified. +* +* p_mr_create +* [in] This references information needed to perform the modification on +* the registered memory region. This parameter may be NULL if only the +* protection domain will be modified. +* +* p_lkey +* [out] The local access key associated with this registered memory +* region. +* +* p_rkey +* [out] A key that may be used by a remote end-point when performing RDMA +* or atomic operations to this registered memory region. +* +* h_pd +* [in] An optionally provided parameter used to modify the protection +* domain of a registered region. +* +* RETURN VALUES +* IB_SUCCESS +* The memory region attributes were modified successfully. +* +* IB_INVALID_MR_HANDLE +* The memory region handle was invalid. +* +* IB_INVALID_PARAMETER +* A reference to the lkey or rkey was not provided or the specified +* modify mask is invalid. +* +* IB_INVALID_SETTING +* The specified memory region attributes are invalid. +* +* IB_INVALID_PD_HANDLE +* The protection domain handle was invalid. +* +* IB_INSUFFICIENT_RESOURCES +* There were insufficient resources currently available on the channel +* adapter to modify the memory region. +* +* IB_UNSUPPORTED +* The requested access rights are not supported by the channel adapter. +* +* IB_INVALID_PERMISSION +* The requested access rights are invalid. +* +* IB_RESOURCE_BUSY +* The memory region has windows bound to it. +* +* NOTES +* This routine modifies the attributes of the specified memory region. +* The memory being modified may have been registered using either virtual +* or physical registration. Conceptually, this routine is equivalent to +* to calling ib_dereg_mr, followed by ib_reg_mem, but may be higher +* performing. +* +* SEE ALSO +* ib_reg_mem, ib_reg_phys, ib_dereg_mr, ib_mr_mod_t, ib_mr_create_t +*****/ + + +/****f* Access Layer/ib_rereg_phys +* NAME +* ib_rereg_phys +* +* DESCRIPTION +* Modifies the attributes of an existing memory region. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_rereg_phys( + IN const ib_mr_handle_t h_mr, + IN const ib_mr_mod_t mr_mod_mask, + IN const ib_phys_create_t* const p_phys_create OPTIONAL, + IN OUT uint64_t* const p_vaddr, + OUT net32_t* const p_lkey, + OUT net32_t* const p_rkey, + IN const ib_pd_handle_t h_pd OPTIONAL ); +/* +* PARAMETERS +* h_mr +* [in] A handle to the registered memory region being modified. +* +* mr_mod_mask +* [in] A mask used to specify which attributes of the memory region are +* being modified. +* +* p_phys_create +* [in] This references information needed to perform the modification on +* the registered memory region. This parameter may be NULL if +* only the protection domain will be modified. +* +* p_vaddr +* [in/out] On input, this specifies the requested virtual address for the +* start of the physical region. On output, this references the actual +* virtual address assigned to the registered region. +* +* p_lkey +* [out] The local access key associated with this registered memory +* region. +* +* p_rkey +* [out] A key that may be used by a remote end-point when performing RDMA +* or atomic operations to this registered memory region. +* +* h_pd +* [in] An optionally provided parameter used to modify the protection +* domain of a registered region. +* +* RETURN VALUES +* IB_SUCCESS +* The memory region attributes were modified successfully. +* +* IB_INVALID_MR_HANDLE +* The memory region handle was invalid. +* +* IB_INVALID_PARAMETER +* A reference to the virtual address, lkey, rkey was not provided or +* the specified modify mask is invalid. +* +* IB_INVALID_SETTING +* The specified memory region attributes are invalid. +* +* IB_INVALID_PD_HANDLE +* The protection domain handle was invalid. +* +* IB_INSUFFICIENT_RESOURCES +* There were insufficient resources currently available on the channel +* adapter to modify the memory region. +* +* IB_UNSUPPORTED +* The requested access rights are not supported by the channel adapter. +* +* IB_INVALID_PERMISSION +* The requested access rights are invalid. +* +* IB_RESOURCE_BUSY +* The memory region has windows bound to it. +* +* NOTES +* This routine modifies the attributes of the specified memory region. +* The memory being modified may have been registered using either virtual +* or physical registration. Conceptually, this routine is equivalent to +* to calling ib_dereg_mr, followed by ib_reg_phys, but may be higher +* performing. +* +* SEE ALSO +* ib_reg_mem, ib_reg_phys, ib_dereg_mr, ib_mr_mod_t, ib_mr_create_t +*****/ + + +/****f* Access Layer/ib_reg_shared +* NAME +* ib_reg_shared +* +* DESCRIPTION +* Registers a memory region that has the same physical pages as an +* existing registered memory region. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_reg_shared( + IN const ib_mr_handle_t h_mr, + IN const ib_pd_handle_t h_pd, + IN const ib_access_t access_ctrl, + IN OUT uint64_t* const p_vaddr, + OUT net32_t* const p_lkey, + OUT net32_t* const p_rkey, + OUT ib_mr_handle_t* const ph_mr ); +/* +* PARAMETERS +* h_mr +* [in] A handle to an existing registered memory region that this +* registration should share physical pages with. +* +* h_pd +* [in] Handle to the PD on which memory is being registered +* +* access_ctrl +* [in] Access rights of the registered region. +* +* p_vaddr +* [in/out] On input, this specifies the requested virtual address for the +* start of the physical region. On output, this references the actual +* virtual address assigned to the registered region. This is always a +* 64-bit quantity to support registering more than 4GB of memory on +* 32-bit systems with PAE. +* +* p_lkey +* [out] The local access key associated with this registered memory +* region. +* +* p_rkey +* [out] A key that may be used by a remote end-point when performing RDMA +* or atomic operations to this registered memory region. +* +* ph_mr +* [out] Upon successful completion of this call, this references a handle +* to the registered memory region. This handle is used when performing +* data transfers and to deregister the memory. +* +* RETURN VALUES +* IB_SUCCESS +* The shared memory region was successfully registered. +* +* IB_INVALID_MR_HANDLE +* The memory region handle was invalid. +* +* IB_INVALID_PD_HANDLE +* The protection domain handle was invalid. +* +* IB_INVALID_PARAMETER +* A reference to the virtual address, lkey, rkey, or handle was not +* provided. +* +* IB_INSUFFICIENT_MEMORY +* There was insufficient memory to register the shared memory region. +* +* IB_INSUFFICIENT_RESOURCES +* There were insufficient resources currently available on the channel +* adapter to register the shared memory region. +* +* IB_UNSUPPORTED +* The requested access rights are not supported by the channel adapter. +* +* IB_INVALID_PERMISSION +* The requested access rights are invalid. +* +* NOTES +* This routine registers a memory region that shares the same set of +* physical pages associated with an existing registered memory region. +* +* SEE ALSO +* ib_dereg_mr, ib_reg_mem, ib_reg_phys, ib_reg_shared, ib_mr_create_t +*****/ + + +/****f* Access Layer/ib_reg_shmid +* NAME +* ib_reg_shmid +* +* DESCRIPTION +* Registers a memory region to be shared across multiple processes. +* The memory is referenced by a shared memory identifier. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_reg_shmid( + IN const ib_pd_handle_t h_pd, + IN const ib_shmid_t shmid, + IN const ib_mr_create_t* const p_mr_create, + OUT uint64_t* const p_vaddr, + OUT net32_t* const p_lkey, + OUT net32_t* const p_rkey, + OUT ib_mr_handle_t* const ph_mr ); +/* +* PARAMETERS +* h_pd +* [in] A handle to an existing protection domain that the memory +* should be registered with. +* +* shmid +* [in] An identifier for the shared memory region. +* +* p_mr_create +* [in] Information describing the attributes of the memory region to +* register. +* +* p_vaddr, +* [out] The HCA assigned, HCA relative virtual address for the +* memory region. +* +* p_lkey +* [out] The local access key associated with this registered memory +* region. +* +* p_rkey +* [out] A key that may be used by a remote end-point when performing RDMA +* or atomic operations to this registered memory region. +* +* ph_mr +* [out] Upon successful completion of this call, this references a handle +* to the registered memory region. This handle is used when performing +* data transfers and to deregister the memory. +* +* RETURN VALUES +* IB_SUCCESS +* The shared memory region was successfully registered. +* +* IB_INVALID_PD_HANDLE +* The protection domain handle was invalid. +* +* IB_INVALID_PARAMETER +* A reference to the memory region information, lkey, rkey, or handle +* was not provided. +* +* IB_INVALID_SETTING +* The length and page mapping for the memory region do not match those +* of the region identified by the provided SHMID. +* +* IB_INSUFFICIENT_MEMORY +* There was insufficient memory to register the shared memory region. +* +* IB_INSUFFICIENT_RESOURCES +* There were insufficient resources currently available on the channel +* adapter to register the shared memory region. +* +* IB_UNSUPPORTED +* The requested access rights are not supported by the channel adapter. +* +* IB_INVALID_PERMISSION +* The requested access rights are invalid. +* +* NOTES +* This routine registers a memory region that is shared between processes. +* The region being registered is identified through a shared memory +* identifier. The registered region shares hardware resources as much +* as possible. +* +* SEE ALSO +* ib_dereg_mr, ib_reg_mem, ib_reg_shared, ib_mr_create_t +*****/ + + +/****f* Access Layer/ib_dereg_mr +* NAME +* ib_dereg_mr +* +* DESCRIPTION +* Deregisters a registered memory region. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_dereg_mr( + IN const ib_mr_handle_t h_mr ); +/* +* PARAMETERS +* h_mr +* [in] A handle to a registered memory region that will be unregistered. +* +* RETURN VALUES +* IB_SUCCESS +* The memory region was successfully deregistered. +* +* IB_INVALID_MR_HANDLE +* The memory region handle was invalid. +* +* IB_RESOURCE_BUSY +* The memory region has memory windows bound to it. +* +* NOTES +* This routine deregisters a memory region with a channel adapter. The +* region may be deregistered only if there are no memory windows or +* existing shared memory regions currently bound to the region. Work +* requests referencing this region when it is deregistered will fail +* with a WRS_LOCAL_PROTECTION_ERR error. +* +* SEE ALSO +* ib_reg_mem, ib_reg_phys, ib_reg_shared +*****/ + + +#ifdef CL_KERNEL + +/****f* Access Layer/mlnx_create_fmr +* NAME +* mlnx_create_fmr +* +* DESCRIPTION +* Creates a Mellanox fast memory region. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +mlnx_create_fmr( + IN const ib_pd_handle_t h_pd, + IN const mlnx_fmr_create_t* const p_fmr_create, + OUT mlnx_fmr_handle_t* const ph_fmr ); +/* +* PARAMETERS +* h_pd +* [in] An optionally provided parameter used to modify the protection +* domain of a registered region. +* p_fmr_create +* [in] This references information needed to perform the modification on +* the registered memory region. This parameter may be NULL if only the +* protection domain will be modified. +* ph_fmr +* [out] A handle to the registered memory region being modified. +* +* RETURN VALUES +* IB_SUCCESS +* The memory region attributes were modified successfully. +* +* IB_INVALID_MR_HANDLE +* The memory region handle was invalid. +* +* IB_INVALID_PARAMETER +* A reference to the lkey or rkey was not provided or the specified +* modify mask is invalid. +* +* IB_INVALID_SETTING +* The specified memory region attributes are invalid. +* +* IB_INVALID_PD_HANDLE +* The protection domain handle was invalid. +* +* IB_INSUFFICIENT_RESOURCES +* There were insufficient resources currently available on the channel +* adapter to modify the memory region. +* +* IB_UNSUPPORTED +* The requested access rights are not supported by the channel adapter. +* +* IB_INVALID_PERMISSION +* The requested access rights are invalid. +* +* IB_RESOURCE_BUSY +* The memory region has windows bound to it. +* +* NOTES +* This is a Mellanox specific extension to verbs. +* +* SEE ALSO +* mlnx_destroy_fmr, mlnx_fmr_create_t +*****/ + + +/****f* Access Layer/mlnx_map_fmr +* NAME +* mlnx_map_fmr +* +* DESCRIPTION +* //TODO +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +mlnx_map_phys_fmr( + IN const mlnx_fmr_handle_t h_fmr, + IN const uint64_t* const paddr_list, + IN const int list_len, + IN OUT uint64_t* const p_vaddr, + OUT net32_t* const p_lkey, + OUT net32_t* const p_rkey ); +/* +* PARAMETERS +* h_fmr +* [in] Handle to the fast memory region that these pages map to +* page_list +* [in] array of phys address +* list_len +* [in] number of pages in the list +* p_vaddr +* [in/out] On input, references the requested virtual address for the +* start of the FMR. On output, references the actual +* virtual address assigned to the FMR. +* p_lkey +* [out] The local access key associated with this registered memory +* region. +* p_rkey +* [out] A key that may be used by a remote end-point when performing +* RDMA or atomic operations to this registered memory region. +* +* RETURN VALUES +* IB_SUCCESS +* The memory region attributes were modified successfully. +* +* IB_INVALID_MR_HANDLE +* The memory region handle was invalid. +* +* IB_INVALID_PARAMETER +* A reference to the lkey or rkey was not provided or the specified +* modify mask is invalid. +* +* IB_INVALID_SETTING +* The specified memory region attributes are invalid. +* +* IB_INVALID_PD_HANDLE +* The protection domain handle was invalid. +* +* IB_INSUFFICIENT_RESOURCES +* There were insufficient resources currently available on the channel +* adapter to modify the memory region. +* +* IB_UNSUPPORTED +* The requested access rights are not supported by the channel adapter. +* +* IB_INVALID_PERMISSION +* The requested access rights are invalid. +* +* IB_RESOURCE_BUSY +* The memory region has windows bound to it. +* +* NOTES +* This is a Mellanox specific extension to verbs. +* +* SEE ALSO +* mlnx_destroy_fmr, mlnx_fmr_create_t +*****/ + + +/****f* Access Layer/mlnx_unmap_fmr +* NAME +* mlnx_unmap_fmr +* +* DESCRIPTION +* //TODO +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +mlnx_unmap_fmr( + IN const mlnx_fmr_handle_t h_fmr ); +/* +* PARAMETERS +* h_fmr +* +* RETURN VALUES +* IB_SUCCESS +* The memory region attributes were modified successfully. +* +* IB_INVALID_MR_HANDLE +* The memory region handle was invalid. +* +* IB_INVALID_PARAMETER +* A reference to the lkey or rkey was not provided or the specified +* modify mask is invalid. +* +* IB_INVALID_SETTING +* The specified memory region attributes are invalid. +* +* IB_INVALID_PD_HANDLE +* The protection domain handle was invalid. +* +* IB_INSUFFICIENT_RESOURCES +* There were insufficient resources currently available on the channel +* adapter to modify the memory region. +* +* IB_UNSUPPORTED +* The requested access rights are not supported by the channel adapter. +* +* IB_INVALID_PERMISSION +* The requested access rights are invalid. +* +* IB_RESOURCE_BUSY +* The memory region has windows bound to it. +* +* NOTES +* This is a Mellanox specific extension to verbs. +* +* SEE ALSO +* mlnx_destroy_fmr, mlnx_fmr_create_t +*****/ + + +/****f* Access Layer/mlnx_destroy_fmr +* NAME +* mlnx_destroy_fmr +* +* DESCRIPTION +* Destroys an existing Mellanox fast memory region. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +mlnx_destroy_fmr( + IN const mlnx_fmr_handle_t h_fmr ); +/* +* PARAMETERS +* h_fmr +* [in] A handle to the registered memory region being modified. +* +* RETURN VALUES +* IB_SUCCESS +* The memory region attributes were modified successfully. +* +* IB_INVALID_MR_HANDLE +* The memory region handle was invalid. +* +* IB_INVALID_PARAMETER +* A reference to the lkey or rkey was not provided or the specified +* modify mask is invalid. +* +* IB_INVALID_SETTING +* The specified memory region attributes are invalid. +* +* IB_INVALID_PD_HANDLE +* The protection domain handle was invalid. +* +* IB_INSUFFICIENT_RESOURCES +* There were insufficient resources currently available on the channel +* adapter to modify the memory region. +* +* IB_UNSUPPORTED +* The requested access rights are not supported by the channel adapter. +* +* IB_INVALID_PERMISSION +* The requested access rights are invalid. +* +* IB_RESOURCE_BUSY +* The memory region has windows bound to it. +* +* NOTES +* This is a Mellanox specific extension to verbs. +* +* SEE ALSO +* mlnx_destroy_fmr, mlnx_fmr_create_t +*****/ + + +/****f* Access Layer/ib_create_fmr_pool +* NAME +* ib_create_fmr_pool +* +* DESCRIPTION +* Creates a pool of FMR elements for use +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +mlnx_create_fmr_pool( + IN const ib_pd_handle_t h_pd, + IN const mlnx_fmr_pool_create_t *p_fmr_pool_attr, + OUT mlnx_fmr_pool_handle_t* const ph_pool ); +/* +* PARAMETERS +TODO +* +* RETURN VALUES +TODO +* +* NOTES +TODO +* +* SEE ALSO +TOD +*****/ + + +/****f* Access Layer/ib_destroy_fmr_pool +* NAME +* ib_destroy_fmr_pool +* +* DESCRIPTION +* Destroys a MAD pool and all associated resources. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +mlnx_destroy_fmr_pool( + IN const mlnx_fmr_pool_handle_t h_pool ); +/* +* PARAMETERS +TODO +* +* RETURN VALUES +TODO +* +* NOTES +TODO +* +* SEE ALSO +TODO +*****/ + + + + + + + +/****f* Access Layer/ib_fmr_pool_map_phys +* NAME +* ib_destroy_fmr_pool +* +* DESCRIPTION +* Destroys a MAD pool and all associated resources. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +mlnx_map_phys_fmr_pool( + IN const mlnx_fmr_pool_handle_t h_pool , + IN const uint64_t* const paddr_list, + IN const int list_len, + IN OUT uint64_t* const p_vaddr, + OUT net32_t* const p_lkey, + OUT net32_t* const p_rkey, + OUT mlnx_fmr_pool_el_t *pp_fmr_el); +/* +* PARAMETERS +TODO +* +* RETURN VALUES +TODO +* +* NOTES +TODO +* +* SEE ALSO +TODO +*****/ + + + + + +/****f* Access Layer/ib_destroy_fmr_pool +* NAME +* ib_destroy_fmr_pool +* +* DESCRIPTION +* Destroys a MAD pool and all associated resources. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +mlnx_unmap_fmr_pool( + IN mlnx_fmr_pool_el_t p_fmr_el ); +/* +* PARAMETERS +TODO +* +* RETURN VALUES +TODO +* +* NOTES +TODO +* +* SEE ALSO +TODO +*****/ + + +/****f* Access Layer/ib_flush_fmr_pool +* NAME +* ib_flush_fmr_pool +* +* DESCRIPTION +* Destroys a MAD pool and all associated resources. +* +* SYNOPSIS +*/ +ib_api_status_t +mlnx_flush_fmr_pool(mlnx_fmr_pool_handle_t h_pool); +/* +* PARAMETERS +TODO +* +* RETURN VALUES +TODO +* +* NOTES +TODO +* +* SEE ALSO +TODO +*****/ +#endif /* CL_KERNEL */ + +/****f* Access Layer/ib_create_mw +* NAME +* ib_create_mw +* +* DESCRIPTION +* Creates a memory window associated with the specified protection domain. +* Newly created windows are not bound to any specific memory region. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_create_mw( + IN const ib_pd_handle_t h_pd, + OUT net32_t* const p_rkey, + OUT ib_mw_handle_t* const ph_mw ); +/* +* PARAMETERS +* h_pd +* [in] A handle to an existing protection domain that the memory window +* should be created within. +* +* p_rkey +* [out] The current rkey associated with the memory window. This key is +* used to bind the window to a registered memory region. +* +* ph_mw +* [out] Upon successful completion of this call, this references a handle +* to the memory window. This handle is used to bind and destroy +* the window. +* +* RETURN VALUES +* IB_SUCCESS +* The memory window was successfully created. +* +* IB_INVALID_PD_HANDLE +* The protection domain handle was invalid. +* +* IB_INVALID_PARAMETER +* A reference to the memory window rkey or handle was not provided. +* +* IB_INSUFFICIENT_MEMORY +* There was insufficient memory to create the memory window. +* +* IB_INSUFFICIENT_RESOURCES +* There were insufficient resources currently available on the channel +* adapter to create the memory window. +* +* NOTES +* This routine creates an unbound memory window associated with a specified +* protection domain. The memory window cannot be used for data transfer +* operations until being bound to a registered memory region. +* +* SEE ALSO +* ib_destroy_mw, ib_query_mw, ib_bind_mw +*****/ + + +/****f* Access Layer/ib_query_mw +* NAME +* ib_query_mw +* +* DESCRIPTION +* Query the current attributes of a memory window. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_query_mw( + IN const ib_mw_handle_t h_mw, + OUT ib_pd_handle_t* const ph_pd, + OUT net32_t* const p_rkey ); +/* +* PARAMETERS +* h_mw +* [in] A handle to an existing memory window. +* +* ph_pd +* [out] Upon successful completion of this call, this will reference +* the protection domain associated with this memory window. +* +* p_rkey +* [out] Upon successful completion of this call, this will reference +* the current rkey associated with this memory window. +* +* RETURN VALUES +* IB_SUCCESS +* The memory window attributes were returned successfully. +* +* IB_INVALID_MW_HANDLE +* The memory window handle was invalid. +* +* IB_INVALID_PARAMETER +* A reference to the protection domain handle or rkey was not provided. +* +* NOTES +* This routine returns information about the specified memory window. +* +* SEE ALSO +* ib_create_mw +*****/ + + +/****f* Access Layer/ib_bind_mw +* NAME +* ib_bind_mw +* +* DESCRIPTION +* Binds a memory window to a registered memory region. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_bind_mw( + IN const ib_mw_handle_t h_mw, + IN const ib_qp_handle_t h_qp, + IN ib_bind_wr_t* const p_mw_bind, + OUT net32_t* const p_rkey ); +/* +* PARAMETERS +* h_mw +* [in] A handle to an existing memory window. +* +* h_qp +* [in] A handle to a queue pair that the bind request will be posted to. +* +* p_mw_bind +* [in] Describes the memory window bind request. +* +* p_rkey +* [out] The new rkey for the memory window that may be used by a remote +* end-point when performing RDMA or atomic operations to this memory +* region. +* +* RETURN VALUES +* IB_SUCCESS +* The memory window bind operation was successfully posted. +* +* IB_INVALID_MW_HANDLE +* The memory window handle was invalid. +* +* IB_INVALID_QP_HANDLE +* The queue pair handle was invalid. +* +* IB_INVALID_PARAMETER +* A reference to the memory window bind work request or rkey was not +* provided. +* +* IB_INVALID_SERVICE_TYPE +* The queue pair configuration does not support this type of service. +* +* IB_INVALID_MR_HANDLE +* The memory region handle was invalid. +* +* IB_INVALID_RKEY +* The rkey is invalid for the memory region being bound. +* +* IB_UNSUPPORTED +* The requested access rights are not supported by the channel adapter. +* +* IB_INVALID_PERMISSION +* The requested access rights are invalid. +* +* IB_INSUFFICIENT_RESOURCES +* There were insufficient resources currently available on the channel +* adapter to bind the memory window. +* +* NOTES +* This routine posts a request to bind a memory window to a registered +* memory region. The bind operation occurs on the specified queue pair, +* but the bound region is usable across all queue pairs within the same +* protection domain. +* +* SEE ALSO +* ib_create_mw, ib_bind_wr_t +*****/ + + +/****f* Access Layer/ib_destroy_mw +* NAME +* ib_destroy_mw +* +* DESCRIPTION +* Destroys a memory window. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_destroy_mw( + IN const ib_mw_handle_t h_mw ); +/* +* PARAMETERS +* h_mw +* [in] A handle to an existing memory window. +* +* RETURN VALUES +* IB_SUCCESS +* The memory window was successfully destroyed. +* +* IB_INVALID_MW_HANDLE +* The memory window handle was invalid. +* +* NOTES +* This routine deallocates a window entry created via a ib_create_mw. +* Once this operation is complete, future accesses to the window will fail. +* +* SEE ALSO +* ib_create_mw +*****/ + + +/****f* Access Layer/ib_post_send +* NAME +* ib_post_send +* +* DESCRIPTION +* This routine posts a work request to the send queue of a queue pair. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_post_send( + IN const ib_qp_handle_t h_qp, + IN ib_send_wr_t* const p_send_wr, + OUT ib_send_wr_t **pp_send_failure OPTIONAL ); +/* +* PARAMETERS +* h_qp +* [in] The queue pair to which this work request is being submitted. +* +* p_send_wr +* [in] A reference to the head of the work request list. +* +* pp_send_failure +* [out] If the post send operation failed, this references the work +* request in the p_send_wr list where the first failure occurred. +* This parameter may be NULL if only a single work request is being +* posted to the QP. +* +* RETURN VALUES +* IB_SUCCESS +* All work requests were successfully posted. +* +* IB_INVALID_QP_HANDLE +* The queue pair handle was invalid. +* +* IB_INVALID_PARAMETER +* A reference to the send work request list was not provided. +* +* IB_INSUFFICIENT_RESOURCES +* The number of posted work requests exceed the current depth available +* on the send queue. +* +* IB_INVALID_WR_TYPE +* The work request type was invalid. +* +* IB_INVALID_QP_STATE +* The current queue pair state does not allow posting sends. +* +* IB_INVALID_MAX_SGE +* The number of work request scatter gather elements exceed the queue +* pair configuration. +* +* IB_UNSUPPORTED +* The requested operation is not supported by the channel adapter. +* +* NOTES +* This routine posts a work request to the send queue of a queue pair. +* The type of work to perform is defined by the p_send_wr parameter. +* +* SEE ALSO +* ib_send_wr_t +*****/ + + +/****f* Access Layer/ib_post_recv +* NAME +* ib_post_recv +* +* DESCRIPTION +* This routine posts a work request to the receive queue of a queue pair. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_post_recv( + IN const ib_qp_handle_t h_qp, + IN ib_recv_wr_t* const p_recv_wr, + OUT ib_recv_wr_t **pp_recv_failure OPTIONAL ); +/* +* PARAMETERS +* h_qp +* [in] The queue pair to which this work request is being submitted. +* +* p_recv_wr +* [in] A reference to the head of the work request list. +* +* pp_recv_failure +* [out] If the post receive operation failed, this references the work +* request in the p_recv_wr list where the first failure occurred. +* This parameter may be NULL if only a single work request is being +* posted to the QP. +* +* RETURN VALUES +* IB_SUCCESS +* All work requests were successfully posted. +* +* IB_INVALID_QP_HANDLE +* The queue pair handle was invalid. +* +* IB_INVALID_PARAMETER +* A reference to the receive work request list was not provided. +* +* IB_INSUFFICIENT_RESOURCES +* The number of posted work requests exceed the current depth available +* on the receive queue. +* +* IB_INVALID_WR_TYPE +* The work request type was invalid. +* +* IB_INVALID_QP_STATE +* The current queue pair state does not allow posting receives. +* +* NOTES +* This routine posts a work request to the receive queue of a queue pair. +* The type of work to perform is defined by the p_recv_wr parameter. This +* call is used to post data buffers to receive incoming message sends. +* +* SEE ALSO +* ib_recv_wr_t +*****/ + + +/****f* Access Layer/ib_send_mad +* NAME +* ib_send_mad +* +* DESCRIPTION +* This routine posts a work request to the send queue of a queue pair. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_send_mad( + IN const ib_mad_svc_handle_t h_mad_svc, + IN ib_mad_element_t* const p_mad_element_list, + OUT ib_mad_element_t **pp_mad_failure OPTIONAL ); +/* +* PARAMETERS +* h_mad_svc +* [in] The MAD service to which this work request is being submitted. +* +* p_mad_element_list +* [in] A list of MAD elements that will be posted to the send queue. +* +* pp_mad_failure +* [out] If the send MAD operation failed, this references the MAD +* element in the p_mad_element_list where the first failure occurred. +* This parameter is optional if p_mad_element_list contains a single +* MAD. +* +* RETURN VALUES +* IB_SUCCESS +* The MAD element list was successfully posted. +* +* IB_INVALID_HANDLE +* The MAD service handle was invalid. +* +* IB_INVALID_PARAMETER +* A reference to the MAD element list was not provided. +* +* IB_INSUFFICIENT_RESOURCES +* There were insufficient resources currently available to complete +* the request. +* +* IB_INVALID_SETTING +* The MAD element RMPP version is not supported by the access layer. +* +* IB_INSUFFICIENT_MEMORY +* There was insufficient memory to complete the request. +* +* NOTES +* This routine posts a work request to send a MAD on a MAD service. All +* MAD elements successfully posted by this call are under the control of +* the access layer and should not be accessed until the send operation +* completes. +* +* In order to guarantee that MADs sent by separate clients do not use the +* same transaction ID, the access layer reserves the upper 32-bits of the +* TID on all unsolicited MADs. MADs sent with the response bit set will +* not have their transaction ID's modified. Unsolicited MADs will have the +* upper 32-bits of their TID set to an access layer generated client ID. +* +* SEE ALSO +* ib_mad_element_t, ib_cancel_mad +*****/ + + +/****f* Access Layer/ib_cancel_mad +* NAME +* ib_cancel_mad +* +* DESCRIPTION +* This routine cancels a pending send transaction to a MAD service. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_cancel_mad( + IN const ib_mad_svc_handle_t h_mad_svc, + IN ib_mad_element_t* const p_mad_element ); +/* +* PARAMETERS +* h_mad_svc +* [in] The MAD service to which the send operation was directed. +* +* p_mad_element +* [in] A handle to a sent MAD element. +* +* RETURN VALUES +* IB_SUCCESS +* The requested MAD transaction was located and canceled. +* +* IB_INVALID_PARAMETER +* A reference to the MAD element list was not provided. +* +* IB_NOT_FOUND +* The requested transaction was not located or had already completed. +* +* NOTES +* This routine cancels a pending send transaction to a MAD service. If +* the request is successfully located and has not yet completed, it will +* be completed with its status set to IB_CANCELED. The canceled operation +* will be returned to the user through the normal MAD completion callback. +* If the send transaction has already completed, this call will return +* IB_NOT_FOUND. +* +* SEE ALSO +* ib_send_mad +*****/ + + +/****f* Access Layer/ib_peek_cq +* NAME +* ib_peek_cq +* +* DESCRIPTION +* Returns the number of entries currently on the completion queue. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_peek_cq( + IN const ib_cq_handle_t h_cq, + OUT uint32_t* const p_n_cqes ); +/* +* PARAMETERS +* h_cq +* [in] Handle to the completion queue to peek. +* +* p_n_cqes +* [out] Upon successful completion of this call, contains the number +* of completion queue entries currently on the completion queue. +* +* RETURN VALUES +* IB_SUCCESS +* The peek operation completed successfully. +* +* IB_INVALID_CQ_HANDLE +* The completion queue handle was invalid. +* +* IB_INVALID_PARAMETER +* A reference to the completion queue entry count was not provided. +* +* IB_UNSUPPORTED +* This operation is not supported by the channel adapter. +* +* NOTES +* The value returned is a snapshot of the number of compleiton queue +* entries curently on the completion queue. Support for this operation +* is optional by a channel adapter vendor. +* +* SEE ALSO +* ib_create_cq, ib_poll_cq, ib_rearm_cq, ib_rearm_n_cq +*****/ + + +/****f* Access Layer/ib_poll_cq +* NAME +* ib_poll_cq +* +* DESCRIPTION +* Checks a completion queue for completed work requests. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_poll_cq( + IN const ib_cq_handle_t h_cq, + IN OUT ib_wc_t** const pp_free_wclist, + OUT ib_wc_t** const pp_done_wclist ); +/* +* PARAMETERS +* h_cq +* [in] A handle to a completion queue to check for completions on. +* +* pp_free_wclist +* [in/out] On input, a list of work completion structures provided by +* the client. These are used to report completed work requests through +* the pp_done_wclist. +* +* On output, this contains the list of work completions structures for +* which no work completion was found. +* +* pp_done_wclist +* [out] A list of work completions retrieved from the completion queue. +* +* RETURN VALUES +* IB_SUCCESS +* The poll operation completed successfully. If the work completion +* structures referenced by the pp_free_wclist list is empty there are +* potentially more completions available to retrieve. +* +* IB_INVALID_PARAMETER +* A reference to the free or done work completion list was not provided. +* +* IB_INVALID_CQ_HANDLE +* The completion queue handle was invalid. +* +* IB_NOT_FOUND +* No completed work requests were removed from the completion queue. +* +* NOTES +* This routine retrieves completed work requests from the specified +* completion queue. This call will retrieve all completed requests, +* up to to the number of work completion structures referenced by the +* pp_free_wclist. Completed requests will be returned through the +* pp_done_wclist parameter. +* +* SEE ALSO +* ib_create_cq, ib_post_send, ib_post_recv, ib_bind_mw, ib_wc_t +*****/ + + +/****f* Access Layer/ib_rearm_cq +* NAME +* ib_rearm_cq +* +* DESCRIPTION +* This indicates that the completion queue should notify the client when +* the next completion is added. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_rearm_cq( + IN const ib_cq_handle_t h_cq, + IN const boolean_t solicited ); +/* +* PARAMETERS +* h_cq +* [in] Handle to the completion queue to rearm. +* +* solicited +* [in] A flag indicating whether the request is to generate a +* notification on the next entry, if set to FALSE, or on the next +* solicited entry being added to the completion queue, if set to TRUE. +* +* RETURN VALUES +* IB_SUCCESS +* The completion queue rearm request was registered successfully. +* +* IB_INVALID_CQ_HANDLE +* The completion queue handle was invalid. +* +* NOTES +* This routine instructs the channel interface to invoke the completion +* handler when the next completion queue entry is added to this CQ. +* +* SEE ALSO +* ib_create_cq, ib_peek_cq, ib_poll_cq, ib_rearm_n_cq +*****/ + + +/****f* Access Layer/ib_rearm_n_cq +* NAME +* ib_rearm_n_cq +* +* DESCRIPTION +* This indicates that the completion queue should notify the client when +* the next N completions have been added to this CQ. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_rearm_n_cq( + IN const ib_cq_handle_t h_cq, + IN const uint32_t n_cqes ); +/* +* PARAMETERS +* h_cq +* [in] Handle to the completion queue to rearm. +* +* n_cqes +* [in] The number of completion queue entries to be added to the +* completion queue before notifying the client. This value must +* greater than or equal to one and less than or equal to the size +* of the completion queue. +* +* RETURN VALUES +* IB_SUCCESS +* The completion queue rearm request was registered successfully. +* +* IB_INVALID_CQ_HANDLE +* The completion queue handle was invalid. +* +* IB_INVALID_PARAMETER +* The requested number of completion queue entries was invalid. +* +* IB_UNSUPPORTED +* This operation is not supported by the channel adapter. +* +* NOTES +* This routine instructs the channel interface to invoke the completion +* handler when the next N completions have been added to this CQ regardless +* of the completion type (solicited or unsolicited). Any CQ entries that +* existed before the rearm is enabled will not result in a call to the +* handler. Support for this operation is optional by a channel adapter +* vendor. +* +* SEE ALSO +* ib_create_cq, ib_peek_cq, ib_poll_cq, ib_rearm_cq +*****/ + + +/****s* Access Layer/ib_mcast_rec_t +* NAME +* ib_mcast_rec_t +* +* DESCRIPTION +* Information returned as a result of joining a multicast group. +* +* SYNOPSIS +*/ +typedef struct _ib_mcast_rec +{ + TO_LONG_PTR(const void*, mcast_context); + ib_api_status_t status; + ib_net16_t error_status; + + TO_LONG_PTR(ib_mcast_handle_t, h_mcast); + TO_LONG_PTR(ib_member_rec_t*, p_member_rec); + +} ib_mcast_rec_t; +/* +* FIELDS +* mcast_context +* User-defined context information associated with the multicast join +* request. +* +* status +* Indicates the success of the multicast group join operation. +* +* error_status +* Provide additional error information that was provided by the SA. +* This field is only valid if status is set to IB_REMOTE_ERROR. +* +* h_mcast +* Upon successful completion of a multicast join, this references a +* handle to the multicast group. This handle is used to leave the +* multicast group. +* +* p_member_rec +* References a member record that provides information about the +* multicast group. +* +* NOTES +* This structure is returned to a client through a callback to notify them +* of the result of a multicast join operation. +* +* SEE ALSO +* ib_join_mcast, ib_pfn_mcast_cb_t, ib_leave_mcast +*****/ + + +/****f* Access Layer/ib_pfn_mcast_cb_t +* NAME +* ib_pfn_mcast_cb_t +* +* DESCRIPTION +* User-defined callback invoked on completion of a multicast join request. +* +* SYNOPSIS +*/ +typedef void +(AL_API *ib_pfn_mcast_cb_t)( + IN ib_mcast_rec_t *p_mcast_rec ); +/* +* PARAMETERS +* p_mcast_rec +* [in] References the result of the join operation. +* +* NOTES +* The callback is used to notify a client of the result of a multicast +* join request. +* +* This callback is invoked within a system thread context in the kernel. +* +* SEE ALSO +* ib_join_mcast, ib_mcast_rec_t +*****/ + + +/****s* Access Layer/ib_mcast_req_t +* NAME +* ib_mcast_req_t +* +* DESCRIPTION +* Information used to join a multicast group. +* +* SYNOPSIS +*/ +typedef struct _ib_mcast_req +{ + boolean_t create; + ib_member_rec_t member_rec; + + const void* mcast_context; + ib_pfn_mcast_cb_t pfn_mcast_cb; + + uint32_t timeout_ms; + uint32_t retry_cnt; + ib_al_flags_t flags; + + ib_net64_t port_guid; + uint16_t pkey_index; + +} ib_mcast_req_t; +/* +* FIELDS +* create +* Indicates that the multicast group should be created if it does not +* already exist. +* +* member_rec +* Specifies the membership information of the multicast group to join +* or create. The mgid and join state (scope_state) fields of the +* member record must be set. In addition, if create is set to TRUE, +* the following fields must also be set: qkey, tclass, service level +* and flow label (sl_flow_hop), and pkey. All other fields are ignored +* by the access layer. +* +* mcast_context +* User-defined context information associated with the join request. +* This context is returned to the user through the function specified +* by the pfn_mcast_cb field. +* +* pfn_mcast_cb +* A user-defined callback that is invoked upon completion of the +* join request. +* +* timeout_ms +* Specifies the number of milliseconds to wait for a response for +* the join request until retrying or timing out the request. +* +* retry_cnt +* Specifies the number of times that the join request 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. +* +* port_guid +* Indicates the port that will join the multicast group. The QP +* specified as part of the ib_join_mast call will bind to this port. +* +* pkey_index +* Specifies the pkey associated with this queue pair. +* +* NOTES +* This structure is used when joining an existing multicast group or +* creating a new multicast group. +* +* SEE ALSO +* ib_join_mcast, ib_pfn_mcast_cb_t, ib_gid_t +*****/ + + +/****f* Access Layer/ib_join_mcast +* NAME +* ib_join_mcast +* +* DESCRIPTION +* Attaches a queue pair to a multicast group. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_join_mcast( + IN const ib_qp_handle_t h_qp, + IN const ib_mcast_req_t* const p_mcast_req ); +/* +* PARAMETERS +* h_qp +* [in] A handle to an unreliable datagram queue pair that will join the +* multicast group. +* +* p_mcast_req +* [in] Specifies the multicast group to join. +* +* RETURN VALUES +* IB_SUCCESS +* The join multicast group request has been initiated. +* +* IB_INVALID_QP_HANDLE +* The queue pair handle was invalid. +* +* IB_INVALID_PARAMETER +* A reference to the multicast group request information was not +* provided. +* +* IB_INVALID_SERVICE_TYPE +* The queue pair configuration does not support this type of service. +* +* IB_INSUFFICIENT_MEMORY +* There was insufficient memory to join the multicast group. +* +* IB_INVALID_GUID +* No port was found for the port_guid specified in the request. +* +* IB_INSUFFICIENT_RESOURCES +* There were insufficient resources currently available on the channel +* adapter to perform the operation. +* +* IB_INVALID_PKEY +* The pkey specified in the multicast join request does not match the +* pkey of the queue pair. +* +* IB_INVALID_PORT +* The port GUID specified in the multicast join request does not match +* the port of the queue pair. +* +* IB_ERROR +* An error occurred while performing the multicast group join operation. +* +* IB_INSUFFICIENT_RESOURCES +* There were insufficient resources currently available to complete +* the request. +* +* IB_INSUFFICIENT_MEMORY +* There was insufficient memory to complete the request. +* +* NOTES +* This routine results in the specified queue pair joining a multicast +* group. If the multicast group does not already exist, it will be created +* at the user's option. Information about the multicast group is returned +* to the user through a callback specified through the p_mcast_req +* parameter. +* +* If the specified queue pair is already a member of a multicast group when +* this call is invoked, an error will occur if there are conflicting +* membership requirements. The QP is restricted to being bound to a single +* port_guid and using a single pkey. +* +* SEE ALSO +* ib_leave_mcast, ib_mcast_req_t, ib_create_qp, ib_init_dgrm_svc +*****/ + + +/****f* Access Layer/ib_leave_mcast +* NAME +* ib_leave_mcast +* +* DESCRIPTION +* Removes a queue pair from a multicast group. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_leave_mcast( + IN const ib_mcast_handle_t h_mcast, + IN const ib_pfn_destroy_cb_t pfn_destroy_cb OPTIONAL ); +/* +* PARAMETERS +* h_mcast +* [in] A handle to a joined multicast group. +* +* pfn_destroy_cb +* [in] An optional user-specified callback that is invoked after the +* leave request has completed. +* +* RETURN VALUES +* IB_SUCCESS +* The leave multicast group request has been initiated. +* +* IB_INVALID_MCAST_HANDLE +* The multicast group handle was invalid. +* +* IB_ERROR +* An error occurred while performing the multicast group leave operation. +* +* IB_INSUFFICIENT_RESOURCES +* There were insufficient resources currently available on the channel +* adapter to perform the operation. +* +* NOTES +* This routine detaches a queue pair from a multicast group and removes +* it as a member of the group with the subnet administrator. +* +* SEE ALSO +* ib_join_mcast, ib_pfn_destroy_cb_t +*****/ + + +/****f* Access Layer/ib_local_mad +* NAME +* ib_local_mad +* +* DESCRIPTION +* Request that a locally received MAD be processed by the channel adapter +* on which it was received. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_local_mad( + IN const ib_ca_handle_t h_ca, + IN const uint8_t port_num, + IN const void* const p_mad_in, + OUT void* p_mad_out ); +/* +* PARAMETERS +* h_ca +* [in] A handle to the channel adapter that should process the MAD. +* This must be the same adapter that the MAD was received on. +* +* port_num +* [in] The port number to which this request is directed. +* +* p_mad_in +* [in] Pointer to a management datagram (MAD) structure containing +* the command to be processed. +* +* p_mad_out +* [out] References a MAD that should contain the response to the +* received input MAD specified through the p_mad_in parameter. +* +* RETURN VALUES +* IB_SUCCESS +* The local MAD was processed successfully. +* +* IB_INVALID_CA_HANDLE +* The channel adapter handle was invalid. +* +* IB_INVALID_PORT +* The port number was invalid. +* +* IB_INVALID_PARAMETER +* A reference to the MAD input or MAD output buffer was not provided. +* +* NOTES +* This call is provided to support SMA and GSA implementations above the +* verbs interface on ports that the access layer has disabled. This routine +* is used to perform local operations by the channel adapter. On successful +* return, the provide output MAD should be used when sending a response. +* +* SEE ALSO +* ib_query_ca, ib_ca_attr_t +*****/ + + +/****s* Access Layer/ib_req_pdata_t +* NAME +* ib_req_pdata_t +* +* DESCRIPTION +* User data sent as part of a request for communication. +* +* SYNOPSIS +*/ +typedef union _ib_req_pdata +{ + uint8_t data[IB_REQ_PDATA_SIZE]; + +} ib_req_pdata_t; +/* +* SEE ALSO +* ib_cm_data_sizes_t +*****/ + + +/****s* Access Layer/ib_rep_pdata_t +* NAME +* ib_rep_pdata_t +* +* DESCRIPTION +* User data sent as part of a reply to a request for communication. +* +* SYNOPSIS +*/ +typedef union _ib_rep_pdata +{ + uint8_t data[IB_REP_PDATA_SIZE]; + +} ib_rep_pdata_t; +/* +* SEE ALSO +* ib_cm_data_sizes_t +*****/ + + +/****s* Access Layer/ib_rtu_pdata_t +* NAME +* ib_rtu_pdata_t +* +* DESCRIPTION +* User data sent as part of a ready to use message. +* +* SYNOPSIS +*/ +typedef union _ib_rtu_pdata +{ + uint8_t data[IB_RTU_PDATA_SIZE]; + +} ib_rtu_pdata_t; +/* +* SEE ALSO +* ib_cm_data_sizes_t +*****/ + + +/****s* Access Layer/ib_rej_pdata_t +* NAME +* ib_rej_pdata_t +* +* DESCRIPTION +* User data sent as part of a connection reject message. +* +* SYNOPSIS +*/ +typedef union _ib_rej_pdata +{ + uint8_t data[IB_REJ_PDATA_SIZE]; + +} ib_rej_pdata_t; +/* +* SEE ALSO +* ib_cm_data_sizes_t +*****/ + + +/****s* Access Layer/ib_mra_pdata_t +* NAME +* ib_mra_pdata_t +* +* DESCRIPTION +* User data sent as part of a message receipt acknowledgement. +* +* SYNOPSIS +*/ +typedef union _ib_mra_pdata +{ + uint8_t data[IB_MRA_PDATA_SIZE]; + +} ib_mra_pdata_t; +/* +* SEE ALSO +* ib_cm_data_sizes_t +*****/ + + +/****s* Access Layer/ib_lap_pdata_t +* NAME +* ib_lap_pdata_t +* +* DESCRIPTION +* User data sent as part of a load alternate path message. +* +* SYNOPSIS +*/ +typedef union _ib_lap_pdata +{ + uint8_t data[IB_LAP_PDATA_SIZE]; + +} ib_lap_pdata_t; +/* +* SEE ALSO +* ib_cm_data_sizes_t +*****/ + + +/****s* Access Layer/ib_apr_pdata_t +* NAME +* ib_apr_pdata_t +* +* DESCRIPTION +* User data sent as part of an alternate path response. +* +* SYNOPSIS +*/ +typedef union _ib_apr_pdata +{ + uint8_t data[IB_APR_PDATA_SIZE]; + +} ib_apr_pdata_t; +/* +* SEE ALSO +* ib_cm_data_sizes_t +*****/ + + +/****s* Access Layer/ib_dreq_pdata_t +* NAME +* ib_dreq_pdata_t +* +* DESCRIPTION +* User data sent as part of a disconnection request. +* +* SYNOPSIS +*/ +typedef union _ib_dreq_pdata +{ + uint8_t data[IB_DREQ_PDATA_SIZE]; + +} ib_dreq_pdata_t; +/* +* SEE ALSO +* ib_cm_data_sizes_t +*****/ + + +/****s* Access Layer/ib_drep_pdata_t +* NAME +* ib_drep_pdata_t +* +* DESCRIPTION +* User data sent as part of a reply to a disconnection request. +* +* SYNOPSIS +*/ +typedef union _ib_drep_pdata +{ + uint8_t data[IB_DREP_PDATA_SIZE]; + +} ib_drep_pdata_t; +/* +* SEE ALSO +* ib_cm_data_sizes_t +*****/ + + +/****s* Access Layer/ib_sidr_req_pdata_t +* NAME +* ib_sidr_req_pdata_t +* +* DESCRIPTION +* User data sent as part of a service ID resolution request. +* +* SYNOPSIS +*/ +typedef union _ib_sidr_req_pdata +{ + uint8_t data[IB_SIDR_REQ_PDATA_SIZE]; + +} ib_sidr_req_pdata_t; +/* +* SEE ALSO +* ib_cm_data_sizes_t +*****/ + + +/****s* Access Layer/ib_sidr_rep_pdata_t +* NAME +* ib_sidr_rep_pdata_t +* +* DESCRIPTION +* User data sent as part of a service ID resolution reply. +* +* SYNOPSIS +*/ +typedef union _ib_sidr_rep_pdata +{ + uint8_t data[IB_SIDR_REP_PDATA_SIZE]; + +} ib_sidr_rep_pdata_t; +/* +* SEE ALSO +* ib_cm_data_sizes_t +*****/ + + +/****s* Access Layer/ib_ari_t +* NAME +* ib_ari_t +* +* DESCRIPTION +* Infiniband-defined additional rejection information. +* +* SYNOPSIS +*/ +typedef struct _ib_ari +{ + uint8_t data[IB_ARI_SIZE]; + +} ib_ari_t; +/* +* SEE ALSO +* ib_cm_data_sizes_t +*****/ + + +/****s* Access Layer/ib_apr_info_t +* NAME +* ib_apr_info_t +* +* DESCRIPTION +* Infiniband-defined additional rejection information. +* +* SYNOPSIS +*/ +typedef struct _ib_apr_info +{ + uint8_t data[IB_APR_INFO_SIZE]; + +} ib_apr_info_t; +/* +* SEE ALSO +* ib_cm_data_sizes_t +*****/ + + +/****s* Access Layer/ib_cm_req_rec_t +* NAME +* ib_cm_req_rec_t +* +* DESCRIPTION +* Connection request information returned to the user through their +* connection request callback. +* +* SYNOPSIS +*/ + +#pragma warning(disable:4324) +typedef struct _ib_cm_req_rec +{ + const void* context; + ib_cm_handle_t h_cm_req; + ib_listen_handle_t h_cm_listen; + + const uint8_t* p_req_pdata; + + ib_qp_type_t qp_type; + + /* valid for rc, uc & rd qp_type only */ + uint8_t resp_res; + boolean_t flow_ctrl; + uint8_t rnr_retry_cnt; + ib_path_rec_t primary_path; + ib_path_rec_t alt_path; + + /* valid for ud qp_type only */ + ib_net16_t pkey; + const void* sidr_context; + +} ib_cm_req_rec_t; +#pragma warning(default:4324) +/* +* FIELDS +* context +* For peer-to-peer connections, this is the queue pair context associated +* with a connection request. For listens, this is the listen context +* specified through the ib_cm_listen routine. +* +* h_cm_req +* The handle to the communication manager request. This handle is used +* to reply to the or reject the connection. +* +* h_cm_listen +* For connection request callbacks initiated in response to an +* ib_cm_listen call, this is a handle to the listen request. This +* handle is provided to the user to avoid a race condition between +* the return of the ib_cm_listen routine and the notification of a +* connection request. +* +* p_req_pdata +* A reference to user-defined private data sent as part of the connection +* request. +* +* qp_type +* Indicates the CM service type. +* +* resp_res +* The maximum number of RDMA read/atomic operations from the recipient +* that the requestor supports on the connection. The init_depth +* specified in the call to ib_cm_rep must be less than or equal to +* this value. +* +* flow_ctrl +* Indicates if the remote CA implements hardware end-to-end flow control. +* +* rnr_retry_cnt +* Requested number of RNR NAK retries to perform before generating a +* local error. +* +* primary_path +* The path record to use for the primary connection. +* +* alt_path +* The path record to use for the alternate connection. +* +* pkey +* The pkey used in the user's request. +* +* sidr_context +* The sidr_context used in ib_cm_listen. +* +* SEE ALSO +* ib_cm_req, ib_cm_listen, ib_pfn_cm_req_cb_t, +* ib_access_t, ib_path_rec_t, ib_req_pdata_t, ib_qp_type_t +*****/ + + +/****s* Access Layer/ib_cm_rep_rec_t +* NAME +* ib_cm_rep_rec_t +* +* DESCRIPTION +* Connection request reply information returned to the user through their +* connection reply callback. +* +* SYNOPSIS +*/ +typedef struct _ib_cm_rep_rec +{ + const uint8_t* p_rep_pdata; + + ib_qp_type_t qp_type; + + ib_cm_handle_t h_cm_rep; + /* valid for rc, uc & rd qp_type only */ + const void* qp_context; + uint8_t resp_res; + boolean_t flow_ctrl; + ib_apr_status_t apr_status; + + /* valid for ud qp_type only */ + const void* sidr_context; + ib_sidr_status_t status; + ib_net32_t remote_qp; + ib_net32_t remote_qkey; + ib_class_port_info_t class_info; + +} ib_cm_rep_rec_t; +/* +* FIELDS +* p_rep_pdata +* A reference to user-defined private data sent as part of the connection +* request reply. +* +* qp_type +* Indicates the CM service type. +* +* h_cm_rep +* The handle to the communication manager reply. This handle is used +* to issue a ready to use message or to reject the connection. +* +* h_qp +* The handle to the queue pair associated with a connection request. +* +* qp_context +* The queue pair context associated with a connection request. +* +* resp_res +* The maximum number of RDMA read/atomic operations from the recipient +* that the requestor supports on the connection. This may be less than +* the init_depth specified in the call to ib_cm_req. The local queue +* pair will be configured with this value unless the connection is +* rejected. +* +* flow_ctrl +* Indicates if the remote CA implements hardware end-to-end flow control. +* +* apr_status +* Indicates whether the alternate path information was accepted. +* +* h_al +* The AL handle on which the SIDR request was issued. +* +* sidr_context +* The sidr_context used in ib_cm_req. +* +* status +* Status of the request made previously using ib_cm_req. +* +* remote_qp +* Identifies the destination queue pair number. +* +* remote_qkey +* Identifies the destination qkey. +* +* class_info +* Identifies the class_port_info returned if status was not successful. +* This field has no value if status is successful. +* +* SEE ALSO +* ib_cm_req, ib_cm_rep, ib_pfn_cm_rep_cb_t, ib_cm_status_t, ib_rep_pdata_t +* ib_qp_type_t, ib_sidr_status_t +*****/ + + +/****s* Access Layer/ib_cm_rtu_rec_t +* NAME +* ib_cm_rtu_rec_t +* +* DESCRIPTION +* Connection ready to use message information returned to the user through +* their ready to use callback. +* +* SYNOPSIS +*/ +typedef struct _ib_cm_rtu_rec +{ + const uint8_t* p_rtu_pdata; + + ib_qp_handle_t h_qp; + const void* qp_context; + +} ib_cm_rtu_rec_t; +/* +* FIELDS +* p_rtu_pdata +* A reference to user-defined private data sent as part of the ready +* to use message. +* +* h_qp +* The queue pair handle associated with the connection request. +* +* qp_context +* The queue pair context associated with the connection request. +* +* SEE ALSO +* ib_cm_rtu, ib_pfn_cm_rtu_cb_t, ib_cm_status_t, ib_rtu_pdata_t, +* ib_qp_type_t +*****/ + + +/****s* Access Layer/ib_cm_rej_rec_t +* NAME +* ib_cm_rej_rec_t +* +* DESCRIPTION +* Connection rejection information returned to the user through their +* rejection callback. +* +* SYNOPSIS +*/ +typedef struct _ib_cm_rej_rec +{ + ib_rej_status_t rej_status; + const uint8_t* p_ari; + uint8_t ari_length; + + const uint8_t* p_rej_pdata; + + ib_qp_handle_t h_qp; + const void* qp_context; + +} ib_cm_rej_rec_t; +/* +* FIELDS +* rej_status +* The reason for the connection rejection. +* +* p_ari +* Additional rejection information. The data referenced by this field +* is dependent on the rej_status and is defined by the Infiniband +* specification. +* +* ari_length +* Length of valid data provided in the p_ari buffer. +* +* p_rej_pdata +* A reference to user-defined private data sent as part of the connection +* request reply. +* +* h_qp +* The queue pair handle associated with a connection request. +* +* qp_context +* The queue pair context associated with a connection request. +* +* SEE ALSO +* ib_cm_rej, ib_pfn_cm_rej_cb_t, ib_rej_status_t, ib_ari_t, ib_rej_pdata_t, +* ib_qp_type_t +*****/ + + +/****s* Access Layer/ib_cm_mra_rec_t +* NAME +* ib_cm_mra_rec_t +* +* DESCRIPTION +* Message received acknowledgement information returned to the user through +* a callback. +* +* SYNOPSIS +*/ +typedef struct _ib_cm_mra_rec +{ + const uint8_t* p_mra_pdata; + + ib_qp_handle_t h_qp; + const void* qp_context; + +} ib_cm_mra_rec_t; +/* +* FIELDS +* p_mra_pdata +* A reference to user-defined private data sent as part of the MRA. +* +* h_qp +* The queue pair handle associated with a connection request. +* +* qp_context +* The queue pair context associated with a connection request. +* +* SEE ALSO +* ib_cm_req, ib_cm_mra, ib_pfn_cm_mra_cb_t, ib_mra_pdata_t, ib_qp_type_t +*****/ + + +/****s* Access Layer/ib_cm_lap_rec_t +* NAME +* ib_cm_lap_rec_t +* +* DESCRIPTION +* Load alternate path request information returned to the user through +* a callback. +* +* SYNOPSIS +*/ +#pragma warning(disable:4324) +typedef struct _ib_cm_lap_rec +{ + ib_cm_handle_t h_cm_lap; + ib_path_rec_t alt_path; + + const uint8_t* p_lap_pdata; + + const void* qp_context; + +} ib_cm_lap_rec_t; +#pragma warning(default:4324) +/* +* FIELDS +* p_lap_pdata +* A reference to user-defined private data sent as part of the load +* alternate path request. +* +* qp_context +* The queue pair context associated with a connection request. +* +* h_cm_lap +* A handle to the load alternate path request. This handle is used +* to reply to the load request. +* +* alt_path +* Requested alternate path. Users must accept or reject the path by +* calling ib_cm_apr. +* +* SEE ALSO +* ib_cm_lap, ib_pfn_cm_lap_cb_t, ib_lap_pdata_t, ib_qp_type_t +*****/ + + +/****s* Access Layer/ib_cm_apr_rec_t +* NAME +* ib_cm_apr_rec_t +* +* DESCRIPTION +* Load alternate path response information returned to the user through +* a callback. +* +* SYNOPSIS +*/ +typedef struct _ib_cm_apr_rec +{ + ib_api_status_t cm_status; + ib_apr_status_t apr_status; + + const uint8_t* p_info; + uint8_t info_length; + + const uint8_t* p_apr_pdata; + + ib_qp_handle_t h_qp; + const void* qp_context; + +} ib_cm_apr_rec_t; +/* +* FIELDS +* cm_status +* The status of the alternate path response. IB_SUCCESS indicates that +* the alternate path was loaded successfully. IB_TIMEOUT indicates that +* a reply was not received within the specified timeout and retry count. +* Other error values indicates that the alternate path was not loaded. +* if the apr_status is IB_AP_SUCCESS, the QP failed to load the path. +* Other apr_status values indicate that the request was rejected for some +* reason. +* +* apr_status +* The alternate path response status. This indicates additional failure +* information to a load alternate path request and is defined by the +* InfiniBand specification. +* +* info_length +* Length of valid data in the APR additional information buffer. +* +* p_info +* APR additional information. +* +* p_apr_pdata +* A reference to user-defined private data sent as part of the alternate +* path response. +* +* h_qp +* The queue pair handle associated with the alternate path response. +* +* qp_context +* The queue pair context associated with the alternate path response. +* +* SEE ALSO +* ib_cm_lap, ib_pfn_cm_apr_cb_t, ib_apr_status_t, ib_apr_info_t +* ib_apr_pdata_t, ib_qp_type_t +*****/ + + +/****s* Access Layer/ib_cm_dreq_rec_t +* NAME +* ib_cm_dreq_rec_t +* +* DESCRIPTION +* Disconnection request information returned to the user through their +* disconnection callback. +* +* SYNOPSIS +*/ +typedef struct _ib_cm_dreq_rec +{ + ib_cm_handle_t h_cm_dreq; + + const uint8_t* p_dreq_pdata; + + const void* qp_context; + +} ib_cm_dreq_rec_t; +/* +* FIELDS +* h_cm_dreq +* A handle to the disconnection request. This handle is used to reply +* to the disconnection request. +* +* p_dreq_pdata +* A reference to user-defined private data sent as part of the +* disconnect request. +* +* qp_context +* The queue pair context associated with the disconnect request. +* +* SEE ALSO +* ib_cm_dreq, ib_pfn_cm_dreq_cb_t, ib_dreq_pdata_t, ib_qp_type_t +*****/ + + +/****s* Access Layer/ib_cm_drep_rec_t +* NAME +* ib_cm_drep_rec_t +* +* DESCRIPTION +* Disconnection reply information returned to the user through their +* disconnect reply callback. +* +* SYNOPSIS +*/ +typedef struct _ib_cm_drep_rec +{ + ib_api_status_t cm_status; + + const uint8_t* p_drep_pdata; + + ib_qp_handle_t h_qp; + const void* qp_context; + +} ib_cm_drep_rec_t; +/* +* FIELDS +* cm_status +* The status of the disconnect request. Valid values are IB_SUCCESS +* and IB_TIMEOUT. IB_TIMEOUT indicates that a reply was not received +* within the specified timeout and retry count. +* +* p_drep_pdata +* A reference to user-defined private data sent as part of the +* disconnect reply. +* +* h_qp +* The queue pair handle associated with the disconnect reply. +* +* qp_context +* The queue pair context associated with the disconnect reply. +* +* SEE ALSO +* ib_cm_drep, ib_pfn_cm_drep_cb_t, ib_drep_pdata_t, ib_qp_type_t +*****/ + + +/****f* Access Layer/ib_pfn_cm_req_cb_t +* NAME +* ib_pfn_cm_req_cb_t +* +* DESCRIPTION +* A user-specified callback that is invoked after receiving a connection +* request message. +* +* SYNOPSIS +*/ +typedef void +(AL_API *ib_pfn_cm_req_cb_t)( + IN ib_cm_req_rec_t *p_cm_req_rec ); +/* +* PARAMETERS +* p_cm_req_rec +* [in] Connection request information returned to the user, indicating +* the parameters for the connection. +* +* NOTES +* This callback is invoked to notify the user of a connection request. This +* routine is invoked for peer to peer connection request calls to ib_cm_req +* and for calls to ib_cm_listen. Users must call ib_cm_rep to accept the +* connection or ib_cm_rej to reject the connection from the callback. +* +* Users may also call ib_cm_mra to acknowledge the connection request and +* prevent the remote side from timing out the connection request. The +* ib_cm_mra routine should be invoked if the user requires substantial +* processing time to process the connection request. +* +* In the kernel, this callback is typically invoked from within a tasklet, +* depending on the implementation of the verbs provider driver. +* +* SEE ALSO +* ib_cm_req, ib_cm_listen, ib_cm_rep, ib_cm_mra, ib_cm_rej, ib_cm_req_rec_t +*****/ + + +/****f* Access Layer/ib_pfn_cm_rep_cb_t +* NAME +* ib_pfn_cm_rep_cb_t +* +* DESCRIPTION +* A user-specified callback that is invoked after receiving a connection +* request reply message. +* +* SYNOPSIS +*/ +typedef void +(AL_API *ib_pfn_cm_rep_cb_t)( + IN ib_cm_rep_rec_t *p_cm_rep_rec ); +/* +* PARAMETERS +* p_cm_rep_rec +* [in] Connection request reply information returned to the user, +* indicating the remote connection data. +* +* NOTES +* This callback is invoked to notify the user of a connection request reply. +* This routine is invoked after calling ib_cm_req. Users must call +* ib_cm_rtu to accept the connection or ib_cm_rej to reject the connection +* from the callback. +* +* Users may also call ib_cm_mra to acknowledge the connection request reply +* and prevent the remote side from timing out the connection request. The +* ib_cm_mra routine should be invoked if the user requires substantial +* processing time to process the connection request reply. +* +* If a reply is not received within the specified timeout period, +* this callback will be invoked with the status set to IB_CM_TIMEOUT. Users +* may call ib_cm_rej to notify the remote side that the connection request +* is being rejected due to a timeout. +* +* In the kernel, this callback is typically invoked from within a tasklet, +* depending on the implementation of the verbs provider driver. +* +* SEE ALSO +* ib_cm_req, ib_cm_listen, ib_cm_rep, ib_cm_rej, ib_cm_mra, ib_cm_rej, +* ib_cm_rep_rec_t +*****/ + + +/****f* Access Layer/ib_pfn_cm_rtu_cb_t +* NAME +* ib_pfn_cm_rtu_cb_t +* +* DESCRIPTION +* A user-specified callback that is invoked after receiving a connection +* ready to use message. +* +* SYNOPSIS +*/ +typedef void +(AL_API *ib_pfn_cm_rtu_cb_t)( + IN ib_cm_rtu_rec_t *p_cm_rtu_rec ); +/* +* PARAMETERS +* p_cm_rtu_rec +* [in] Connection ready to use information returned to the user. +* +* NOTES +* This callback is invoked to notify the user that a connection is ready +* to use. This routine is invoked after calling ib_cm_rep. If a ready to +* use message is not received within the specified timeout period, this +* callback will be invoked with the status set to IB_CM_TIMEOUT. +* +* This callback will be invoked before a user is notified of any completions +* that has occurred on the associated queue pair. +* +* In the kernel, this callback is typically invoked from within a tasklet, +* depending on the implementation of the verbs provider driver. +* +* SEE ALSO +* ib_cm_rep, ib_cm_rtu_rec_t +*****/ + + +/****f* Access Layer/ib_pfn_cm_rej_cb_t +* NAME +* ib_pfn_cm_rej_cb_t +* +* DESCRIPTION +* A user-specified callback that is invoked after receiving a connection +* rejection message. +* +* SYNOPSIS +*/ +typedef void +(AL_API *ib_pfn_cm_rej_cb_t)( + IN ib_cm_rej_rec_t *p_cm_rej_rec ); +/* +* PARAMETERS +* p_cm_rej_rec +* [in] Connection rejection information returned to the user. +* +* NOTES +* This callback is invoked to notify the user that a connection has been +* rejected. This routine may be invoked after calling ib_cm_req or +* ib_cm_rep. +* +* In the kernel, this callback is typically invoked from within a tasklet, +* depending on the implementation of the verbs provider driver. +* +* SEE ALSO +* ib_cm_req, ib_cm_rep, ib_cm_rtu, ib_cm_rej, ib_cm_rej_rec_t +*****/ + + +/****f* Access Layer/ib_pfn_cm_mra_cb_t +* NAME +* ib_pfn_cm_mra_cb_t +* +* DESCRIPTION +* A user-specified callback that is invoked after receiving a message +* received acknowledgement. +* +* SYNOPSIS +*/ +typedef void +(AL_API *ib_pfn_cm_mra_cb_t)( + IN ib_cm_mra_rec_t *p_cm_mra_rec ); + +/* +* PARAMETERS +* p_cm_mra_rec +* [in] Message received acknowledgement information received from the +* remote side. +* +* NOTES +* This callback is invoked to notify the user that their request was +* successfully received, but additional processing is required. This +* callback may be invoked after calling ib_cm_req or ib_cm_rep +* +* In the kernel, this callback is typically invoked from within a tasklet, +* depending on the implementation of the verbs provider driver. +* +* SEE ALSO +* ib_cm_req, ib_cm_rep, ib_cm_mra_rec_t +*****/ + + +/****f* Access Layer/ib_pfn_cm_lap_cb_t +* NAME +* ib_pfn_cm_lap_cb_t +* +* DESCRIPTION +* A user-specified callback that is invoked after receiving a load +* alternate path message. +* +* SYNOPSIS +*/ +typedef void +(AL_API *ib_pfn_cm_lap_cb_t)( + IN ib_cm_lap_rec_t *p_cm_lap_rec ); +/* +* PARAMETERS +* p_cm_lap_rec +* [in] Load alternate path information sent by the remote side. +* +* NOTES +* This callback is invoked to notify the user of a load alternate path +* request. Users must call ib_cm_apr to respond to the load alternate +* path request from within this callback. The ib_cm_apr call is used +* to accept or reject the load alternate path request. +* +* In the kernel, this callback is typically invoked from within a +* tasklet, depending on the implementation of the verbs provider driver. +* +* SEE ALSO +* ib_cm_lap, ib_cm_apr, ib_cm_lap_rec_t +*****/ + + +/****f* Access Layer/ib_pfn_cm_apr_cb_t +* NAME +* ib_pfn_cm_apr_cb_t +* +* DESCRIPTION +* A user-specified callback that is invoked after receiving a load +* alternate path response message. +* +* SYNOPSIS +*/ +typedef void +(AL_API *ib_pfn_cm_apr_cb_t)( + IN ib_cm_apr_rec_t *p_cm_apr_rec ); +/* +* PARAMETERS +* p_cm_apr_rec +* [in] Load alternate path response information sent by the remote side. +* +* NOTES +* This callback is invoked to notify the user of a load alternate path +* response. If a response is not received within the specified timeout +* period, this callback will be invoked with the status set to IB_CM_TIMEOUT. +* +* In the kernel, this callback is typically invoked from within a tasklet, +* depending on the implementation of the verbs provider driver. +* +* SEE ALSO +* ib_cm_lap, ib_cm_apr, ib_cm_apr_rec_t +*****/ + + +/****f* Access Layer/ib_pfn_cm_dreq_cb_t +* NAME +* ib_pfn_cm_dreq_cb_t +* +* DESCRIPTION +* A user-specified callback that is invoked after receiving a disconnect +* request message. +* +* SYNOPSIS +*/ +typedef void +(AL_API *ib_pfn_cm_dreq_cb_t)( + IN ib_cm_dreq_rec_t *p_cm_dreq_rec ); +/* +* PARAMETERS +* p_cm_dreq_rec +* [in] Disconnect request information returned to the user. +* +* NOTES +* This callback is invoked to notify the user of a disconnect request. +* Users must call ib_cm_drep to respond to the disconnect request. After +* this callback returns, the queue pair associated with the connection is +* transitioned to the time-wait state and is no longer usable for sending +* and receiving data. +* +* In the kernel, this callback is typically invoked from within a tasklet, +* depending on the implementation of the verbs provider driver. +* +* SEE ALSO +* ib_cm_req, ib_cm_listen, ib_cm_drep, ib_cm_dreq_rec_t +*****/ + + +/****f* Access Layer/ib_pfn_cm_drep_cb_t +* NAME +* ib_pfn_cm_drep_cb_t +* +* DESCRIPTION +* A user-specified callback that is invoked after receiving a disconnect +* reply message. +* +* SYNOPSIS +*/ +typedef void +(AL_API *ib_pfn_cm_drep_cb_t)( + IN ib_cm_drep_rec_t *p_cm_drep_rec ); +/* +* PARAMETERS +* p_cm_drep_rec +* [in] Disconnect reply information returned to the user. +* +* NOTES +* This callback is invoked to notify the user of a disconnect reply. If +* no reply was received within the specified timeout period, this callback +* will be invoked with the status set to IB_CM_TIMEOUT. +* +* In the kernel, this callback is typically invoked from within a +* tasklet, depending on the implementation of the verbs provider driver. +* +* SEE ALSO +* ib_cm_dreq, ib_cm_drep, ib_cm_drep_rec_t +*****/ + + +/****d* Access Layer/ib_listen_info_t +* NAME +* ib_listen_info_t +* +* DESCRIPTION +* Constants used to specify directed listen requests. +* +* SYNOPSIS +*/ +#define IB_ALL_CAS 0 +#define IB_ALL_PORTS 0 +#define IB_ALL_LIDS 0 +#define IB_ALL_PKEYS 0 +/* +* SEE ALSO +* ib_cm_listen, ib_cm_listen_t +*****/ + + +/****s* Access Layer/ib_cm_listen_t +* NAME +* ib_cm_listen_t +* +* DESCRIPTION +* Request to listen for incoming connection attempts. +* +* SYNOPSIS +*/ +typedef struct _ib_cm_listen +{ + ib_net64_t svc_id; + + ib_net64_t ca_guid; + ib_net64_t port_guid; + ib_net16_t lid; + ib_net16_t pkey; + + uint8_t* p_compare_buffer; + uint8_t compare_offset; + uint8_t compare_length; + + ib_pfn_cm_req_cb_t pfn_cm_req_cb; + + ib_qp_type_t qp_type; + + /* valid for ud qp_type only */ + const void* sidr_context; + +} ib_cm_listen_t; +/* +* FIELDS +* svc_id +* The identifier of the service to register for incoming connection +* requests. +* +* ca_guid +* Directs the communication manager to register the listen only +* with the specified channel adapter. This should be set to IB_ALL_CAS +* if the listen is not directed to a particular channel adapter. +* +* port_guid +* Directs the communication manager to register the listen only +* with the specified port. This should be set to IB_ALL_PORTS +* if the listen is not directed to a particular port. +* +* lid +* Directs the communication manager to register the listen only +* with the specified LID. This should be set to IB_ALL_LIDS +* if the listen is not directed to a particular LID. +* +* pkey +* Directs the communication manager to register the listen only with +* the specified pkey value. This should be set to IB_ALL_PKEYS +* iv the listen is not directed to a particular partition. +* +* p_compare_buffer +* An optionally provided buffer that will be used to match incoming +* connection requests with a registered service. Use of this buffer +* permits multiple services to listen on the same service ID as long as +* they provide different compare buffers. Incoming requests will +* be matched against the compare buffer. +* +* compare_offset +* An offset into the user-defined data area of a connection request +* which contains the start of the data that will be compared against. +* The offset must be the same for all requests using the same service ID. +* +* compare_length +* Specifies the size of the compare buffer in bytes. The length must +* be the same for all requests using the same service ID. +* +* pfn_cm_req_cb +* References a user-provided callback that will be invoked whenever a +* connection request is received. +* +* qp_type +* Indicates the CM service type. +* +* pfn_cm_mra_cb +* References a user-provided callback that will be invoked when +* a message received acknowledgement is received. +* +* pfn_cm_rej_cb +* References a user-provided callback that will be invoked if the +* connection is rejected by the remote end-point. +* +* sidr_context +* sidr specific context for listens. This context is passed back in +* the ib_pfn_cm_req_cb_t callback. +* +* NOTES +* Users fill out this structure when listening on a service ID with the +* local communication manager. The communication manager will use the given +* service ID and compare buffer to route connection requests to the +* appropriate client. Users may direct listens requests on a particular +* channel adapter, port, or LID. +* +* Message received acknowledgement (MRA) callbacks will not be invoked +* until a connection request has been replied to. +* +* SEE ALSO +* ib_listen_info_t, ib_pfn_cm_req_cb_t, ib_pfn_cm_mra_cb_t, +* ib_qp_type_t +*****/ + + +/****s* Access Layer/ib_cm_req_t +* NAME +* ib_cm_req_t +* +* DESCRIPTION +* Connection request information used to establish a new connection. +* +* SYNOPSIS +*/ +typedef struct _ib_cm_req +{ + ib_net64_t svc_id; + + ib_al_flags_t flags; + uint8_t max_cm_retries; + TO_LONG_PTR(ib_path_rec_t*, p_primary_path); + + TO_LONG_PTR(ib_pfn_cm_rep_cb_t, pfn_cm_rep_cb); + + TO_LONG_PTR(const uint8_t*, p_req_pdata); + uint8_t req_length; + + ib_qp_type_t qp_type; + + /* valid for rc, uc & rd qp_type only */ + TO_LONG_PTR(ib_qp_handle_t, h_qp); + + TO_LONG_PTR(uint8_t*, p_compare_buffer); + uint8_t compare_offset; + uint8_t compare_length; + + uint8_t resp_res; + uint8_t init_depth; + uint8_t remote_resp_timeout; + boolean_t flow_ctrl; + uint8_t local_resp_timeout; + uint8_t rnr_nak_timeout; + uint8_t rnr_retry_cnt; + uint8_t retry_cnt; + + TO_LONG_PTR(ib_path_rec_t*, p_alt_path OPTIONAL); + + TO_LONG_PTR(ib_pfn_cm_req_cb_t, pfn_cm_req_cb); + TO_LONG_PTR(ib_pfn_cm_mra_cb_t, pfn_cm_mra_cb); + TO_LONG_PTR(ib_pfn_cm_rej_cb_t, pfn_cm_rej_cb); + + /* valid for ud qp_type only */ + TO_LONG_PTR(ib_al_handle_t, h_al); + TO_LONG_PTR(const void*, sidr_context); + uint32_t timeout_ms; + ib_net16_t pkey; + +} ib_cm_req_t; +/* +* FIELDS +* svc_id +* The ID of the remote service to which the connection request is +* being made. +* +* flags +* Used to describe the mode of operation. Set to IB_FLAGS_SYNC to +* process the called routine synchronously. +* +* max_cm_retries +* The maximum number of times that either CM should resend a connection +* establishment message. +* +* p_primary_path +* Path information over which to establish the primary connection. +* +* pfn_cm_rep_cb +* References a user-provided callback that will be invoked when +* a reply to the connection request is received. +* +* p_req_pdata +* Optional user-defined private data sent as part of the connection +* request. +* +* req_length +* Defines the size of the user-defined private data. +* +* qp_type +* Indicates the CM service type. +* +* h_qp +* A handle to the queue pair to use in the connection. +* +* p_compare_buffer +* An optionally provided buffer that will be used to match incoming +* connection requests with a registered service. Use of this buffer +* permits multiple services to connect using the same service ID as +* long as they provide different compare buffers. Incoming requests +* will be matched against the compare buffer. Valid for peer-to-peer +* connection requests only. +* +* compare_offset +* An offset into the user-defined data area of a connection request +* which contains the start of the data that will be compared against. +* The offset must be the same for all requests using the same service ID. +* Valid for peer-to-peer connection requests only. +* +* compare_length +* Specifies the size of the compare buffer in bytes. The length must +* be the same for all requests using the same service ID. Valid for +* peer-to-peer connection requests only. +* +* resp_res +* The maximum number of outstanding RDMA read/atomic operations the +* requestor supports from the remote QP. +* +* init_depth +* The maximum number of outstanding RDMA read/atomic operations the +* requestor will have outstanding to the remote QP. +* +* remote_resp_timeout +* The time within which the remote CM should transmit a response to +* the sender. This value is expressed as +* 4.096 * (2 ^ local_resp_timeout) microseconds. +* +* flow_ctrl +* Indicates whether the local CA supports end-to-end flow control. +* +* local_resp_timeout +* The time that the remote CM should wait to receive a response from +* the local CM. This value is expressed as +* 4.096 * (2 ^ local_resp_timeout) microseconds. +* +* rnr_nak_timeout +* The time to wait before retrying a packet after receiving a RNR NAK. +* This value is defined in section 9.7.5.2.8 of the IB Spec, table 45. +* +* rnr_retry_cnt +* The number of times that the local QP should retry a send operation +* after receiving an RNR NACK before reporting an error. +* +* retry_cnt +* The number of times that a QP should retry a send operation before +* reporting an error. +* +* p_alt_path +* Optional path information that will be used as the alternate +* connection path in the case of failure. +* +* pfn_cm_req_cb +* References a user-provided callback that will be invoked when +* a request for a connection is received. This is required for peer-to +* peer connection requests, and must be NULL for client/server +* connection requests. +* +* pfn_cm_mra_cb +* References a user-provided callback that will be invoked when +* a message received acknowledgement is received. +* +* pfn_cm_rej_cb +* References a user-provided callback that will be invoked if the +* connection is rejected by the remote end-point. +* +* sidr_context +* The user-defined sidr context information that will be passed back in a +* ib_cm_req callback. +* +* timeout_ms +* Timeout value in milli-seconds for the REQ to expire. The CM will add +* twice packet lifetime to this value to determine the actual timeout +* value used. +* +* pkey +* pkey to be used as part of the request. This field is only valid for +* IB_MCLASS_CM_VER_2 clients. +* +* SEE ALSO +* ib_cm_req, ib_pfn_cm_req_cb_t, ib_pfn_cm_rep_cb_t, ib_pfn_cm_mra_cb_t, +* ib_pfn_cm_rej_cb_t, ib_path_rec_t, ib_req_pdata_t, ib_qp_type_t +*****/ + + +/****d* Access Layer/ib_cm_failover_t +* NAME +* ib_cm_failover_t +* +* DESCRIPTION +* Fail over acceptance status returned as part of a connection reply. +* +* SYNOPSIS +*/ +typedef uint8_t ib_cm_failover_t; +#define IB_FAILOVER_ACCEPT_SUCCESS 0 +#define IB_FAILOVER_ACCEPT_UNSUPPORTED 1 +#define IB_FAILOVER_ACCEPT_ERROR 2 +/* +* NOTES +* These values and their use are defined the Infiniband specification. +* +* SEE ALSO +* ib_cm_rep, ib_cm_rep_t +*****/ + + +/****s* Access Layer/ib_cm_rep_t +* NAME +* ib_cm_rep_t +* +* DESCRIPTION +* Connection reply information used when establishing a connection. +* +* SYNOPSIS +*/ +typedef struct _ib_cm_rep +{ + ib_al_flags_t flags; + + TO_LONG_PTR(const uint8_t*, p_rep_pdata); + uint8_t rep_length; + + TO_LONG_PTR(ib_qp_handle_t, h_qp); + ib_qp_type_t qp_type; + + /* valid for rc, uc & rd qp_type only */ + ib_access_t access_ctrl; + uint32_t sq_depth; + uint32_t rq_depth; + + uint8_t init_depth; + uint8_t target_ack_delay; + ib_cm_failover_t failover_accepted; + boolean_t flow_ctrl; + uint8_t rnr_nak_timeout; + uint8_t rnr_retry_cnt; + + TO_LONG_PTR(ib_pfn_cm_rej_cb_t, pfn_cm_rej_cb); + TO_LONG_PTR(ib_pfn_cm_mra_cb_t, pfn_cm_mra_cb); + TO_LONG_PTR(ib_pfn_cm_rtu_cb_t, pfn_cm_rtu_cb); + TO_LONG_PTR(ib_pfn_cm_lap_cb_t, pfn_cm_lap_cb); + TO_LONG_PTR(ib_pfn_cm_dreq_cb_t, pfn_cm_dreq_cb); + + TO_LONG_PTR(ib_recv_wr_t*, p_recv_wr); + TO_LONG_PTR(ib_recv_wr_t**, pp_recv_failure); + + /*valid for ud qp_type only */ + ib_sidr_status_t status; + ib_class_port_info_t class_info; + +} ib_cm_rep_t; +/* +* FIELDS +* flags +* Used to describe the mode of operation. Set to IB_FLAGS_SYNC to +* process the called routine synchronously. +* +* p_rep_pdata +* Optional user-defined private data sent as part of the connection +* reply. +* +* rep_length +* Defines the size of the user-defined private data. +* +* qp_type +* Indicates the CM service type. +* +* h_qp +* A handle to the queue pair to use in the connection. For SIDR, h_qp +* is valid only if sidr status is IB_SIDR_SUCCESS. +* +* access_ctrl +* Indicates the type of access permitted on the local QP. +* +* sq_depth +* The maximum number of outstanding send operations that the local +* QP needs to support. +* +* rq_depth +* The maximum number of outstanding receive operations that the local +* QP needs to support. +* +* init_depth +* The maximum number of outstanding RDMA read/atomic operations the +* sender of the reply will have outstanding to the remote QP. +* +* target_ack_delay +* The time that the remote QP should wait to receive an ACK from the +* local QP. +* +* failover_accepted +* Status indicating if the fail over path was accepted by the sender +* of the reply. +* +* flow_ctrl +* Indicates whether the local CA supports end-to-end flow control. +* +* rnr_nak_timeout +* The time to wait before retrying a packet after receiving a RNR NAK. +* +* rnr_retry_cnt +* The number of times that the local QP should retry a send operation +* after receiving an RNR NACK before reporting an error. +* +* pfn_cm_rtu_cb +* References a user-defined callback that will be invoked when +* a connection is ready to use for send operations. +* +* pfn_cm_lap_cb +* References a user-defined callback that will be invoked when +* a load alternate path request is received for the connecting +* queue pair or end-to-end context. +* +* pfn_cm_dreq_cb +* References a user-defined callback that will be invoked when +* a disconnect request is received is for the connecting +* queue pair or end-to-end context. +* +* p_recv_wr +* A reference to the head of the work request list to be initially +* posted to the receive queue. Providing this list closes a potential +* race condition between sending a CM REP message and posting receives. +* Use of this field is optional. +* +* pp_recv_failure +* If the post receive operation failed, this references the work +* request in the p_recv_wr list where the first failure occurred. +* This field is required only if p_recv_wr is used. +* +* status +* sidr status value returned back to a previously received REQ. +* +* class_info +* The contents of this field are valid only if status is IB_SIDR_REDIRECT. +* +* SEE ALSO +* ib_cm_rep, ib_access_t, ib_cm_failover_t, ib_rep_pdata_t +* ib_pfn_cm_rtu_cb_t, ib_pfn_cm_lap_cb_t, ib_pfn_cm_dreq_cb_t, +* ib_qp_type_t +*****/ + + +/****s* Access Layer/ib_cm_rtu_t +* NAME +* ib_cm_rtu_t +* +* DESCRIPTION +* Connection ready to use information used when establishing a connection. +* +* SYNOPSIS +*/ +typedef struct _ib_cm_rtu +{ + ib_access_t access_ctrl; + uint32_t sq_depth; + uint32_t rq_depth; + + const uint8_t* p_rtu_pdata; + uint8_t rtu_length; + + ib_pfn_cm_apr_cb_t pfn_cm_apr_cb; + ib_pfn_cm_dreq_cb_t pfn_cm_dreq_cb; + +} ib_cm_rtu_t; +/* +* FIELDS +* access_ctrl +* Indicates the type of access permitted on the local QP. +* +* sq_depth +* The maximum number of outstanding send operations that the local +* QP needs to support. This field should be set to zero if the CA +* does not support changing the work request depth after the QP is +* created. +* +* rq_depth +* The maximum number of outstanding receive operations that the local +* QP needs to support. This field should be set to zero if the CA +* does not support changing the work request depth after the QP is +* created. +* +* p_rtu_pdata +* Optional user-defined private data sent as part of the connection +* ready to use message. +* +* rtu_length +* Defines the size of the user-defined private data. +* +* pfn_cm_apr_cb +* References a user-defined callback that will be invoked when an +* alternate path response is received for the connecting queue pair +* or end-to-end context. +* +* pfn_cm_dreq_cb +* References a user-defined callback that will be invoked when a +* disconnect request is received is for the connecting queue pair +* or end-to-end context. +* +* SEE ALSO +* ib_cm_rtu, ib_access_t, ib_rtu_pdata_t +*****/ + + +/****s* Access Layer/ib_cm_rej_t +* NAME +* ib_cm_rej_t +* +* DESCRIPTION +* Information used to reject a connection request. +* +* SYNOPSIS +*/ +typedef struct _ib_cm_rej +{ + ib_rej_status_t rej_status; + + ib_ari_t* p_ari; + uint8_t ari_length; + const uint8_t* p_rej_pdata; + uint8_t rej_length; + +} ib_cm_rej_t; +/* +* FIELDS +* rej_status +* The reason for the connection rejection. +* +* p_ari +* Additional rejection information. The data referenced by this field +* is dependent on the rej_status and is defined by the Infiniband +* specification. +* +* ari_length +* Length of valid data provided in the p_ari buffer. +* +* p_rej_pdata +* A reference to user-defined private data sent as part of the +* reject message. +* +* rej_length +* Defines the size of the user-defined private data. +* +* SEE ALSO +* ib_cm_rej, ib_pfn_cm_rej_cb_t, ib_rej_status_t, ib_ari_t, ib_rej_pdata_t +*****/ + + +/****s* Access Layer/ib_cm_mra_t +* NAME +* ib_cm_mra_t +* +* DESCRIPTION +* Connection message received acknowledgement information used to +* indicate that a connection request, reply, or load alternate path +* has been received. +* +* SYNOPSIS +*/ +typedef struct _ib_cm_mra +{ + uint8_t svc_timeout; + + TO_LONG_PTR(const uint8_t*, p_mra_pdata); + uint8_t mra_length; + +} ib_cm_mra_t; +/* +* FIELDS +* svc_timeout +* Indicates the amount of time that the local service requires to +* complete processing of the previously received message. +* +* p_mra_pdata +* Optional user-defined private data sent as part of the message +* received acknowledgement. +* +* mra_length +* Defines the size of the user-defined private data. +* +* SEE ALSO +* ib_cm_mra, ib_pfn_cm_req_cb_t, ib_pfn_cm_rep_cb_t, ib_pfn_cm_lap_cb_t, +* ib_mra_pdata_t +*****/ + + +/****s* Access Layer/ib_cm_lap_t +* NAME +* ib_cm_lap_t +* +* DESCRIPTION +* Load alternate path information used to configure a queue pair with an +* alternate path. +* +* SYNOPSIS +*/ +typedef struct _ib_cm_lap +{ + ib_al_flags_t flags; + + TO_LONG_PTR(const uint8_t*, p_lap_pdata); + uint8_t lap_length; + + ib_qp_type_t qp_type; + + /* valid for rc, uc & rd qp_type only */ + TO_LONG_PTR(ib_qp_handle_t, h_qp); + + uint8_t remote_resp_timeout; + TO_LONG_PTR(ib_path_rec_t*, p_alt_path); + ib_pfn_cm_apr_cb_t pfn_cm_apr_cb; + +} ib_cm_lap_t; +/* +* FIELDS +* flags +* Used to describe the mode of operation. Set to IB_FLAGS_SYNC to +* process the called routine synchronously. +* +* p_lap_pdata +* Optional user-defined private data sent as part of the load alternate +* path message. +* +* lap_length +* Defines the size of the user-defined private data. +* +* qp_type +* Indicates the CM service type. +* +* h_qp +* A handle to the queue pair that should receive the alternate path. +* +* remote_resp_timeout +* The time within which the remote CM should transmit a response to +* the sender. This value is expressed as +* 4.096 * (2 ^ local_resp_timeout) microseconds. +* +* p_alt_path +* The path record to use for the alternate connection. +* +* pfn_cm_apr_cb +* References a user-defined callback that will be invoked when the +* response to the load request is received. +* +* SEE ALSO +* ib_cm_lap, ib_pfn_cm_lap_cb_t, ib_pfn_cm_apr_cb_t, ib_path_rec_t, +* ib_pfn_lap_pdata_t, ib_qp_type_t +*****/ + + +/****s* Access Layer/ib_cm_apr_t +* NAME +* ib_cm_apr_t +* +* DESCRIPTION +* Load alternate path information used to configure a queue pair with an +* alternate path. +* +* SYNOPSIS +*/ +typedef struct _ib_cm_apr +{ + TO_LONG_PTR(const uint8_t*, p_apr_pdata); + uint8_t apr_length; + + ib_qp_type_t qp_type; + + /* valid for rc, uc & rd qp_type only */ + TO_LONG_PTR(ib_qp_handle_t, h_qp); + + ib_apr_status_t apr_status; + uint8_t info_length; + TO_LONG_PTR(const ib_apr_info_t*, p_info); + +} ib_cm_apr_t; +/* +* FIELDS +* p_apr_pdata +* Optional user-defined private data sent as part of the alternate +* path response message. +* +* apr_length +* Defines the size of the user-defined private data. +* +* qp_type +* Indicates the CM service type. +* +* h_qp +* A handle to the queue pair that should receive the alternate path. +* +* apr_status +* The alternate path response status. This indicates additional failure +* information to a load alternate path request and is defined by the +* Infiniband specification. +* +* info_length +* Length of valid data in the APR additional information buffer. +* +* p_info +* APR additional information. +* +* SEE ALSO +* ib_cm_apr, ib_pfn_cm_apr_cb_t, ib_lap_pdata_t, ib_qp_type_t +*****/ + + +/****s* Access Layer/ib_cm_dreq_t +* NAME +* ib_cm_dreq_t +* +* DESCRIPTION +* Disconnection request information used to tear down a connection. +* +* SYNOPSIS +*/ +typedef struct _ib_cm_dreq +{ + ib_al_flags_t flags; + + uint8_t* p_dreq_pdata; + uint8_t dreq_length; + + ib_qp_type_t qp_type; + + /* valid for rc, uc & rd qp_type only */ + ib_qp_handle_t h_qp; + ib_pfn_cm_drep_cb_t pfn_cm_drep_cb; + +} ib_cm_dreq_t; +/* +* FIELDS +* flags +* Used to describe the mode of operation. Set to IB_FLAGS_SYNC to +* process the called routine synchronously. +* +* p_dreq_pdata +* A reference to user-defined private data sent as part of the +* disconnection request. +* +* dreq_length +* Defines the size of the user-defined private data. +* +* qp_type +* Indicates the CM service type. +* +* h_qp +* A handle to the queue pair to disconnect. +* +* pfn_cm_drep_cb +* References a user-defined callback that will be invoked when +* the reply to the disconnect is received. +* +* NOTES +* Users submit this structure to disconnect a queue pair or end-to-end +* context. A single disconnect call disconnects either a queue pair or +* an end-to-end context, but not both. +* +* SEE ALSO +* ib_cm_dreq, ib_cm_drep, ib_dreq_pdata_t, ib_al_flags_t, +* ib_qp_type_t +*****/ + + +/****s* Access Layer/ib_cm_drep_t +* NAME +* ib_cm_drep_t +* +* DESCRIPTION +* Disconnection reply information used when tearing down a connection. +* +* SYNOPSIS +*/ +typedef struct _ib_cm_drep +{ + uint8_t* p_drep_pdata; + uint8_t drep_length; + +} ib_cm_drep_t; +/* +* FIELDS +* p_drep_pdata +* A reference to user-defined private data sent as part of the +* disconnection reply. +* +* drep_length +* Defines the size of the user-defined private data. +* +* SEE ALSO +* ib_cm_drep, ib_drep_pdata_t +*****/ + + +/****f* Access Layer/ib_cm_listen +* NAME +* ib_cm_listen +* +* DESCRIPTION +* Issues a request to the local communication manager to listen for +* incoming connection requests. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_cm_listen( + IN const ib_al_handle_t h_al, + IN const ib_cm_listen_t* const p_cm_listen, + IN const void* const listen_context, + OUT ib_listen_handle_t* const ph_cm_listen ); +/* +* PARAMETERS +* h_al +* [in] A handle to an opened instance of the access layer. +* +* p_cm_listen +* [in] Information used to direct the listen request to match incoming +* connection requests. +* +* listen_context +* User-specified context information that is returned as a part of all +* connection requests through the pfn_cm_req_cb routine. The context is +* also returned through the error and destroy callbacks. +* +* ph_cm_listen +* [out] Upon successful completion of this call, this references a handle +* to the listen request. This handle may be used to cancel the listen +* operation. +* +* RETURN VALUES +* IB_SUCCESS +* The listen request was successfully registered with the connection +* manager. +* +* IB_INVALID_AL_HANDLE +* The access layer handle was invalid. +* +* IB_INVALID_PARAMETER +* A reference to the listen request information, error callback function, +* or listen handle was not provided. +* +* IB_INVALID_SETTING +* The class version specified in the listen request is not supported by +* connection manager or the listen request is not unique. +* +* IB_INSUFFICIENT_MEMORY +* There was insufficient memory to register the listen request. +* +* IB_INVALID_GUID +* A channel adapter or port GUID is not wildcarded and no channel adapter +* or port in the system was found for the specified GUID. +* +* IB_INVALID_LID +* The lid is not wildcarded and is not within the lid range for the port +* specified in the listen request information. +* +* IB_INVALID_PKEY +* The pkey is not wildcarded and is not a valid pkey for the port +* specified in the listen request information. +* +* NOTES +* This routine directs the access layer to route connection requests +* matching the specified connection parameters to the client. Clients +* listen for connections matching a particular service ID, and may optionally +* direct their listen request towards a specific channel adapter, port, or +* LID. +* +* If local configuration changes occur that invalidate a listen request, the +* specified error callback will be invoked. Invalidated listen requests +* should be canceled by the user. An example of a configuration change that +* invalidates listen requests is a LID change for directed listens. The +* listen error callback will be invoked within the context of a system +* thread. +* +* SEE ALSO +* ib_cm_listen_t +*****/ + + +/****f* Access Layer/ib_cm_cancel +* NAME +* ib_cm_cancel +* +* DESCRIPTION +* Routine used to cancel listening for connection requests. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_cm_cancel( + IN const ib_listen_handle_t h_cm_listen, + IN const ib_pfn_destroy_cb_t pfn_destroy_cb OPTIONAL ); +/* +* PARAMETERS +* h_cm_listen +* [in] A handle to an existing listen request. +* +* pfn_destroy_cb +* [in] A user-specified callback that is invoked after the listen +* request has been successfully canceled. +* +* RETURN VALUES +* IB_SUCCESS +* The cancel listen operation was initiated. +* +* IB_INVALID_HANDLE +* The connection manager handle was invalid. +* +* NOTES +* This routine cancels a listen request. To avoid a race condition +* canceling a request at the same time a connection callback is in +* progress, the cancel operation operates asynchronously. For +* additional details see ib_pfn_destroy_cb_t. +* +* SEE ALSO +* ib_cm_listen, ib_pfn_destroy_cb_t +*****/ + + +/****f* Access Layer/ib_cm_req +* NAME +* ib_cm_req +* +* DESCRIPTION +* Issues a connection request to a specified end-point. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_cm_req( + IN const ib_cm_req_t* const p_cm_req ); +/* +* PARAMETERS +* p_cm_req +* [in] Information describing the type of connection and the remote +* endpoint for the connection. +* +* RETURN VALUES +* IB_SUCCESS +* The connection request was initiated. +* +* IB_INVALID_PARAMETER +* A reference to the connect request information was not provided. +* +* IB_INVALID_SETTING +* The connect request information contains one or more of the following +* errors: +* - The class version, queue pair type, or path is not supported by +* connection manager. +* - The private data length exceeds the value allowed by the specified +* connection class version. +* - The primary path is not on the same channel adapter as the queue +* pair. +* - The primary and alternate paths are on different channel adapters. +* - The primary and alternate paths specify different MTUs. +* - A primary or alternate path record packet lifetime is out of range. +* - A primary or alternate path record pkey is out of range. +* +* IB_INVALID_QP_HANDLE +* The queue pair handle specified in the connect request was invalid. +* +* IB_INVALID_AL_HANDLE +* The access layer handle was invalid. +* +* IB_INVALID_STATE +* The queue pair or end-to-end context is already connected. +* +* IB_INVALID_QP_STATE +* The queue pair was in an invalid state to perform the operation. +* +* IB_INSUFFICIENT_MEMORY +* There was insufficient memory to initiate the connect request. +* +* NOTES +* This routine issues a connection request through the communication +* manager to a specified end-point. The p_cm_req parameter contains +* details needed to form the connection. The connection request will +* match with a remote ib_cm_listen or ib_cm_req connection request. +* +* SEE ALSO +* ib_cm_req_t, ib_cm_listen, ib_pfn_cm_req_cb_t +*****/ + + +/****f* Access Layer/ib_cm_rep +* NAME +* ib_cm_rep +* +* DESCRIPTION +* Sends a reply to a connection request, indicating that the connection +* has been accepted. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_cm_rep( + IN const ib_cm_handle_t h_cm_req, + IN const ib_cm_rep_t* const p_cm_rep ); +/* +* PARAMETERS +* h_cm_req +* [in] A handle to the connection request being replied to. This handle +* is provided by the access layer through the ib_pfn_cm_req_cb_t +* callback. +* +* p_cm_rep +* [in] Contains reply information to return to the initiator of the +* connection request. +* +* RETURN VALUES +* IB_SUCCESS +* The connection reply was initiated. +* +* IB_INVALID_HANDLE +* The connection manager request handle was invalid. +* +* IB_INVALID_PARAMETER +* A reference to the reply information was not provided. +* +* IB_INVALID_STATE +* The current connection state does not allow sending this message. +* +* IB_INVALID_SETTING +* The connect reply information contains one or more of the following +* errors: +* - The class version, queue pair type, or path is not supported by +* connection manager. +* - The private data length exceeds the value allowed by the connection +* class version. +* - The primary path is not on the same channel adapter as the queue +* pair. +* - The primary and alternate paths are on different channel adapters. +* - The primary and alternate paths specify different MTUs. +* - A primary or alternate path record packet lifetime is out of range. +* - A primary or alternate path record pkey is out of range. +* - The specified private data length is invalid. +* +* IB_INVALID_QP_HANDLE +* The queue pair handle specified in the reply was invalid. +* +* IB_INVALID_QP_STATE +* The queue pair was in an invalid state to perform the operation. +* +* IB_INSUFFICIENT_MEMORY +* There was insufficient memory to send the connect reply. +* +* NOTES +* This routine results in the access layer replying to a connection +* request from a remote node. This call results in sending a response +* to the requesting node that the request has been accepted. +* +* SEE ALSO +* ib_cm_rep_t, ib_pfn_cm_req_cb_t, ib_pfn_cm_rep_cb_t +*****/ + + +/****f* Access Layer/ib_cm_rtu +* NAME +* ib_cm_rtu +* +* DESCRIPTION +* Sends a ready to use message for a connection request, indicating that +* the connection has been accepted and is ready for use. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_cm_rtu( + IN const ib_cm_handle_t h_cm_rep, + IN const ib_cm_rtu_t* const p_cm_rtu ); +/* +* PARAMETERS +* h_cm_rep +* [in] A handle to the connection reply being responded to. This handle +* is provided by the access layer through the ib_pfn_cm_rep_cb_t +* callback. +* +* p_cm_rtu +* [in] Contains ready to use information to return to the sender of the +* connection reply. +* +* RETURN VALUES +* IB_SUCCESS +* The connection ready to use was initiated. +* +* IB_INVALID_HANDLE +* The connection manager reply handle was invalid. +* +* IB_INVALID_PARAMETER +* A reference to the ready to use information was not provided. +* +* IB_INVALID_STATE +* The current connection state does not allow sending this message. +* +* IB_INVALID_SETTING +* The specified queue pair attributes were invalid or the private data +* length exceeds the value allowed by the specified connection class +* version. +* +* IB_UNSUPPORTED +* The specified queue pair access control was not supported. +* +* IB_INSUFFICIENT_MEMORY +* There was insufficient memory to send the ready to use response. +* +* NOTES +* This routine results in the access layer marking a connection as ready +* to use and notifying the remote end-point. +* +* SEE ALSO +* ib_cm_rep_t, ib_pfn_cm_rep_cb_t, ib_cm_rtu_t +*****/ + + +/****f* Access Layer/ib_cm_rej +* NAME +* ib_cm_rej +* +* DESCRIPTION +* Rejects a connection request from a remote end-point. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_cm_rej( + IN const ib_cm_handle_t h_cm, + IN const ib_cm_rej_t* const p_cm_rej ); +/* +* PARAMETERS +* h_cm +* [in] A handle to the connection request or reply being rejected. +* This is the h_cm_req or h_cm_rep handle provided through the +* ib_pfn_cm_req_cb_t or ib_pfn_cm_rep_cb_t callback, respectively. +* +* p_cm_rej +* [in] Contains the connection rejection information to return to the +* connecting end-point. +* +* RETURN VALUES +* IB_SUCCESS +* The connection reject was initiated. +* +* IB_INVALID_HANDLE +* The connection manager handle was invalid. +* +* IB_INVALID_PARAMETER +* A reference to the reject information was not provided. +* +* NOTES +* This routine results in the access layer rejecting a connection +* and notifying the remote end-point. +* +* SEE ALSO +* ib_pfn_cm_req_cb_t, ib_pfn_cm_rep_cb_t, ib_cm_rej_t +*****/ + + +/****f* Access Layer/ib_cm_mra +* NAME +* ib_cm_mra +* +* DESCRIPTION +* Notifies the remote end-point of a connection or load alternate path +* request that the request message has been received, but additional +* processing is required. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_cm_mra( + IN const ib_cm_handle_t h_cm, + IN const ib_cm_mra_t* const p_cm_mra ); +/* +* PARAMETERS +* h_cm +* [in] A handle to the connection request, connection reply, or load +* alternate path request that should receive the message received +* acknowledgement message. This is the h_cm_req, h_cm_rep, or +* h_cm_lap handle provided through the ib_pfn_cm_req_cb_t, +* ib_pfn_cm_rep_cb_t, or ib_pfn_cm_lap_cb_t callback, respectively. +* +* p_cm_mra +* [in] Contains the message received acknowledgement data to return to +* the requesting end-point. +* +* RETURN VALUES +* IB_SUCCESS +* The message receive acknowledge was sent successfully. +* +* IB_INVALID_HANDLE +* The connection manager reply handle was invalid. +* +* IB_INVALID_PARAMETER +* A reference to the message receive acknowledge information was not +* provided. +* +* IB_INVALID_STATE +* The current connection state does not allow sending this message. +* +* IB_INVALID_SETTING +* The class version is not supported by connection manager or the +* specified private data length is invalid. +* +* IB_INSUFFICIENT_MEMORY +* There was insufficient memory to send the message receive acknowledge. +* +* NOTES +* This routine results in the access layer acknowledging a connection or +* load alternate path message. It should be invoked by a client if the +* client is unable to respond to a request within a specified timeout, +* in order to prevent the remote end-point from timing out. +* +* SEE ALSO +* ib_pfn_cm_req_cb_t, ib_pfn_cm_rep_cb_t, ib_pfn_cm_lap_cb_t, ib_cm_mra_t +*****/ + + +/****f* Access Layer/ib_cm_lap +* NAME +* ib_cm_lap +* +* DESCRIPTION +* Issues a load alternate path request to a specified end-point. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_cm_lap( + IN const ib_cm_lap_t* const p_cm_lap ); +/* +* PARAMETERS +* p_cm_lap +* [in] Information describing the alternate path to load and the remote +* endpoint for the connection. +* +* RETURN VALUES +* IB_SUCCESS +* The load alternate path request was sent successfully. +* +* IB_INVALID_PARAMETER +* A reference to the load alternate path information was not provided. +* +* IB_UNSUPPORTED +* The passive side of the connection attempted to load an alternate path. +* +* IB_INVALID_STATE +* The current connection state does not allow sending this message. +* +* IB_INVALID_SETTING +* The load alternate path information contains one or more of the +* following errors: +* - The class version, queue pair type, or path is not supported by +* connection manager. +* - The primary path is not on the same channel adapter as the queue +* pair. +* - The primary and alternate paths are on different channel adapters. +* - The primary and alternate paths specify different MTUs. +* - The alternate path record packet lifetime is out of range. +* - The alternate path record pkey is out of range. +* - The specified private data length is invalid. +* +* IB_INVALID_QP_HANDLE +* The queue pair handle specified in the load alternate path information +* was invalid. +* +* IB_INSUFFICIENT_MEMORY +* There was insufficient memory to send the load alternate path request. +* +* NOTES +* This routine issues initiates loading an alternate path on an existing +* connected queue pair or end-to-end context. If the request is successful, +* the alternate path will be loaded and armed for path migration. +* +* The p_cm_lap parameter describes the alternate path to load and indicates +* the remote endpoint of an existing connection that will receive the load +* request. +* +* SEE ALSO +* ib_cm_apr, ib_cm_lap_t, ib_pfn_cm_lap_cb_t, ib_pfn_cm_apr_cb_t +*****/ + + +/****f* Access Layer/ib_cm_apr +* NAME +* ib_cm_apr +* +* DESCRIPTION +* Responds to a load alternate path request, to accept or reject the +* proposed alternate path. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_cm_apr( + IN const ib_cm_handle_t h_cm_lap, + IN const ib_cm_apr_t* const p_cm_apr ); +/* +* PARAMETERS +* h_cm_lap +* [in] A handle to a load alternate path request corresponding to the +* response. This handle is provided through the ib_pfn_cm_lap_cb_t. +* +* p_cm_apr +* [in] Information describing the alternate path response. The response +* will accept or reject the load request. If the request is rejected +* this parameter will reference additional rejection information. +* +* RETURN VALUES +* IB_SUCCESS +* The load alternate path response was sent successfully. +* +* IB_INVALID_HANDLE +* The connection manager load alternate path handle was invalid. +* +* IB_INVALID_PARAMETER +* A reference to the alternate path information was not provided. +* +* IB_INVALID_STATE +* The current connection state does not allow sending this message. +* +* IB_INVALID_SETTING +* The private data length specified in alternate path information is +* invalid. +* +* IB_INVALID_QP_HANDLE +* The queue pair handle specified in the alternate path information +* was invalid. +* +* IB_INSUFFICIENT_MEMORY +* There was insufficient memory to send the alternate path response. +* +* NOTES +* This routine responds to a load alternate path request. +* +* SEE ALSO +* ib_cm_lap, ib_cm_apr_t, ib_pfn_cm_lap_cb_t, ib_pfn_cm_apr_cb_t +*****/ + + +/****f* Access Layer/ib_force_apm +* NAME +* ib_force_apm +* +* DESCRIPTION +* This routine indicates that a queue pair should immediately migrate to its +* alternate path. All future data transfers will occur over the new path. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_force_apm( + IN const ib_qp_handle_t h_qp ); +/* +* PARAMETERS +* h_qp +* [in] A handle to the queue pair to migrate. +* +* RETURN VALUES +* IB_SUCCESS +* The queue pair or end-to-end context was successfully modified. +* +* IB_INVALID_PARAMETER +* Neither or both of the queue pair or the end-to-end context handles +* were valid. +* +* IB_INVALID_QP_HANDLE +* The queue pair handle was invalid. +* +* IB_INSUFFICIENT_RESOURCES +* There were insufficient resources currently available on the channel +* adapter to register the modify the queue pair or end-to-end context. +* +* IB_UNSUPPORTED +* The requested modification was not supported. +* +* IB_INVALID_QP_STATE +* The queue pair was in an invalid state for the requested operation. +* +* NOTES +* For this routine to operate correctly, the specified queue pair must have +* an existing alternate path loaded. If an alternate path is not loaded, or +* has not yet been armed, this call will fail. +* +* Use of this call results in additional data transfers that occur on the +* given queue pair using the alternate path. Once this call completes, a +* new alternate path may be loaded using the ib_cm_lap call. +* +* SEE ALSO +* ib_cm_lap +*****/ + + +/****f* Access Layer/ib_cm_dreq +* NAME +* ib_cm_dreq +* +* DESCRIPTION +* This routine disconnects a queue pair or end-to-end context. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_cm_dreq( + IN const ib_cm_dreq_t* const p_cm_dreq ); +/* +* PARAMETERS +* p_cm_dreq +* [in] Information that describes the connection being disconnected. +* +* RETURN VALUES +* IB_SUCCESS +* The disconnect request was sent successfully. +* +* IB_INVALID_PARAMETER +* A reference to the disconnect request information was not provided. +* +* IB_INVALID_STATE +* The current connection state does not allow sending this message. +* +* IB_INVALID_SETTING +* The private data length specified in disconnect request information is +* invalid. +* +* IB_INVALID_QP_HANDLE +* The queue pair handle specified in the disconnect request information +* was invalid. +* +* IB_INSUFFICIENT_MEMORY +* There was insufficient memory to send the disconnect request. +* +* NOTES +* This function will disconnect a queue pair or end-to-end context. +* It results in sending a disconnection request message to the remote +* end-point. After calling this routine, data transfers on the specified +* queue pair or end-to-end context will fail. +* +* SEE ALSO +* ib_cm_drep, ib_pfn_cm_dreq_cb_t, ib_cm_dreq_t +*****/ + + +/****f* Access Layer/ib_cm_drep +* NAME +* ib_cm_drep +* +* DESCRIPTION +* This routine replies to a disconnection request and disconnects +* a queue pair or end-to-end context. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_cm_drep( + IN const ib_cm_handle_t h_cm_dreq, + IN const ib_cm_drep_t* const p_cm_drep ); +/* +* PARAMETERS +* h_cm_dreq +* [in] A handle to a disconnection request being replied to. This +* handle is provided through the ib_pfn_cm_dreq_cb_t callback. +* +* p_cm_drep +* [in] Reply information used to respond to the disconnection request. +* +* RETURN VALUES +* IB_SUCCESS +* The disconnect request was sent successfully. +* +* IB_INVALID_HANDLE +* The connection manager disconnect request handle was invalid. +* +* IB_INVALID_PARAMETER +* A reference to the disconnect repy information was not provided. +* +* IB_INVALID_STATE +* The current connection state does not allow sending this message. +* +* IB_INVALID_SETTING +* The private data length specified in disconnect reply information is +* invalid. +* +* IB_INSUFFICIENT_MEMORY +* There was insufficient memory to send the disconnect reply. +* +* NOTES +* This function will disconnect a queue pair or end-to-end context. It +* results in sending a disconnection reply message to the remote end-point. +* After calling this routine, data transfers on the specified queue pair or +* end-to-end context will fail. +* +* SEE ALSO +* ib_cm_dreq, ib_pfn_cm_dreq_cb_t, ib_cm_drep_t +*****/ + + +/****f* Access Layer/ib_cm_handoff +* NAME +* ib_cm_handoff +* +* DESCRIPTION +* Hands off the received REQ information to svc_id. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_cm_handoff( + IN const ib_cm_handle_t h_cm_req, + IN const ib_net64_t svc_id ); +/* +* PARAMETERS +* h_cm_req +* [in] A handle to the connection request being handed off. +* This is the h_cm_req handle provided through the ib_pfn_cm_req_cb_t +* callback. +* +* svc_id +* [in] The service id to which this connection request is handed off. +* +* RETURN VALUES +* IB_SUCCESS +* The handoff was initiated. +* +* IB_INVALID_HANDLE +* The connection manager handle was invalid. +* +* IB_INVALID_PARAMETER +* A valid service id was not provided. +* +* IB_INVALID_STATE +* The current connection state does not allow this transfer. +* +* IB_INSUFFICIENT_MEMORY +* There was insufficient memory to complete the request. +* +* NOTES +* This routine results in the access layer handing off the connection +* to the service id as a new incoming connection. +* +* SEE ALSO +* ib_pfn_cm_req_cb_t, ib_cm_rej_t, ib_cm_listen +*****/ + + +/****s* Access Layer/ib_cep_listen_t +* NAME +* ib_cep_listen_t +* +* DESCRIPTION +* Request to listen for incoming connection attempts. +* +* SYNOPSIS +*/ +typedef struct _ib_cep_listen +{ + net64_t svc_id; + + net64_t port_guid; + + TO_LONG_PTR(uint8_t*, p_cmp_buf); + uint8_t cmp_len; + uint8_t cmp_offset; + +} ib_cep_listen_t; +/* +* FIELDS +* svc_id +* The identifier of the service to register for incoming connection +* requests. +* +* port_guid +* Directs the communication manager to register the listen only +* with the specified port. This should be set to IB_ALL_PORTS +* if the listen is not directed to a particular port. +* +* p_cmp_buf +* An optionally provided buffer that will be used to match incoming +* connection requests with a registered service. Use of this buffer +* permits multiple services to listen on the same service ID as long as +* they provide different compare buffers. Incoming requests will +* be matched against the compare buffer. +* +* cmp_len +* Specifies the size of the compare buffer in bytes. The length must +* be the same for all requests using the same service ID. +* +* cmp_offset +* An offset into the user-defined data area of a connection request +* which contains the start of the data that will be compared against. +* The offset must be the same for all requests using the same service ID. +* +* NOTES +* Users fill out this structure when listening on a service ID with the +* local communication manager. The communication manager will use the given +* service ID and compare buffer to route connection requests to the +* appropriate client. Users may direct listens requests on a particular +* channel adapter, port, or LID. +*****/ + + +/****f* Access Layer/ib_create_ioc +* NAME +* ib_create_ioc +* +* DESCRIPTION +* Creates an instance of an I/O controller. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_create_ioc( + IN const ib_ca_handle_t h_ca, + IN const ib_ioc_profile_t* const p_ioc_profile, + OUT ib_ioc_handle_t* const ph_ioc ); +/* +* PARAMETERS +* h_ca +* [in] A handle to an opened channel adapter. The controller will be +* created to be exposed through the given adapter. +* +* p_ioc_profile +* [in] I/O controller profile information. +* +* ph_ioc +* [out] Upon successful completion of this call, this references a +* handle to the created I/O controller. This handle may be used to +* add service entries to the controller and register it. +* +* RETURN VALUES +* IB_SUCCESS +* The I/O controller was successfully created. +* +* IB_INVALID_CA_HANDLE +* The channel adapter handle was invalid. +* +* IB_INVALID_PARAMETER +* A reference to the I/O controller profile information or handle +* was not provided. +* +* IB_INSUFFICIENT_MEMORY +* There was insufficient memory to create the I/O controller. +* +* NOTES +* This routine creates an I/O controller. Once created, services may be +* added to the controller before being registered with the local device +* manager. +* +* SEE ALSO +* ib_destroy_ioc, ib_add_svc_entry, ib_reg_ioc, ib_ioc_profile_t +*****/ + + +/****f* Access Layer/ib_destroy_ioc +* NAME +* ib_destroy_ioc +* +* DESCRIPTION +* Destroys an instance of an I/O controller. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_destroy_ioc( + IN const ib_ioc_handle_t h_ioc ); +/* +* PARAMETERS +* h_ioc +* [in] A handle to an existing I/O controller. +* +* RETURN VALUES +* IB_SUCCESS +* The I/O controller was successfully destroyed. +* +* IB_INVALID_HANDLE +* The I/O controller handle was invalid. +* +* NOTES +* Once an I/O controller is destroyed, it is no longer reported by the +* local device manager as an exported device. This routine automatically +* removes all services associated with the controller. +* +* SEE ALSO +* ib_create_ioc +*****/ + + +/****f* Access Layer/ib_reg_ioc +* NAME +* ib_reg_ioc +* +* DESCRIPTION +* Registers an I/O controller with the local device manager, which will +* export the controller to the fabric. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_reg_ioc( + IN const ib_ioc_handle_t h_ioc ); +/* +* PARAMETERS +* h_ioc +* [in] A handle to the controller being registered. +* +* RETURN VALUES +* IB_SUCCESS +* The I/O controller was successfully registered. +* +* IB_INSUFFICIENT_MEMORY +* There was insufficient memory to register the I/O controller. +* +* IB_INSUFFICIENT_RESOURCES +* There were insufficient resources currently available on the I/O +* unit to register the I/O controller. +* +* IB_INVALID_HANDLE +* The I/O controller handle was invalid. +* +* NOTES +* This routine registers an I/O controller with the local device manager. +* The device manager exports the controller to the fabric as part of an +* I/O unit. Typically, clients will call ib_add_svc_entry to add services +* to the controller before registering it with the device manager. +* +* SEE ALSO +* ib_create_ioc, ib_destroy_ioc, ib_add_svc_entry +*****/ + + +/****f* Access Layer/ib_add_svc_entry +* NAME +* ib_add_svc_entry +* +* DESCRIPTION +* Adds a new service entry to an existing I/O controller. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_add_svc_entry( + IN const ib_ioc_handle_t h_ioc, + IN const ib_svc_entry_t* const p_svc_entry, + OUT ib_svc_handle_t* const ph_svc ); +/* +* PARAMETERS +* h_ioc +* [in] A handle to an existing I/O controller that will support the +* added service. +* +* p_svc_entry +* [in] Service entry information that will be reported as part of the +* controller's service profile. +* +* ph_svc +* [out] Upon successful completion of this call, this references a handle +* to the added service. This handle may be used to remove the service +* entry. +* +* RETURN VALUES +* IB_SUCCESS +* The service entry was successfully added. +* +* IB_INVALID_HANDLE +* The I/O controller handle was invalid. +* +* IB_INVALID_PARAMETER +* A reference to the service entry information or handle was not +* provided. +* +* IB_INSUFFICIENT_MEMORY +* There was insufficient memory to register the service entry. +* +* IB_INSUFFICIENT_RESOURCES +* There were insufficient resources currently available on the I/O +* controller to register the service entry. +* +* NOTES +* This routine adds a new service to an I/O controller. Once added, the +* service will be reported with the controller profile, provided that the +* controller is registered with the local device manager. +* +* SEE ALSO +* ib_create_ioc, ib_remove_svc_entry, ib_reg_ioc, ib_svc_entry_t +*****/ + + +/****f* Access Layer/ib_remove_svc_entry +* NAME +* ib_remove_svc_entry +* +* DESCRIPTION +* This removes a service entry from an I/O controller. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_remove_svc_entry( + IN const ib_svc_handle_t h_svc ); +/* +* PARAMETERS +* h_svc +* [in] A handle to an existing service entry. +* +* RETURN VALUES +* IB_SUCCESS +* The service entry was successfully removed. +* +* IB_INVALID_HANDLE +* The service entry handle was invalid. +* +* NOTES +* This routine removes the specified service from its associated I/O +* controller. Once removed, the service information will no longer be +* exported along with the controller. +* +* SEE ALSO +* ib_add_svc_entry +*****/ + + +/****f* Access Layer/ib_get_ca_guids +* NAME +* ib_get_ca_guids +* +* DESCRIPTION +* Returns a list of GUIDS for all channel adapter currently available in +* the system. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_get_ca_guids( + IN ib_al_handle_t h_al, + OUT ib_net64_t* const p_guid_array OPTIONAL, + IN OUT size_t* const p_guid_cnt ); +/* +* PARAMETERS +* h_al +* [in] A handle to an opened instance of the access layer. +* +* p_guid_array +* [out] An array of GUIDs provided by the user and filled out by the +* access layer. If this parameter is NULL, the access layer will return +* the number of entries in the array necessary to retrieve the GUID list. +* +* p_guid_cnt +* [in/out] On input, this specifies the number of entries in the +* GUID array. +* +* On output, the access layer will set this to the number of valid +* entries in the p_guid_array or the minimum number of entries needed +* in the GUID array in order to return all channel adapter GUIDs. +* +* RETURN VALUES +* IB_SUCCESS +* The operation was successful. +* +* IB_INVALID_AL_HANDLE +* The access layer handle was invalid. +* +* IB_INVALID_PARAMETER +* A reference to the GUID count was not provided. +* +* IB_INSUFFICIENT_MEMORY +* There was insufficient memory to perform the operation. +* +* NOTES +* This routine returns a list of GUIDs for all available channel adapters. +* When called, the access layer will examine p_guid_cnt to determine the +* number of entries available in the p_guid_array. If the count is too +* small, the function will return IB_INSUFFICIENT_MEMORY, and set p_guid_cnt +* to the number of needed entries. +* +* SEE ALSO +* ib_open_al, ib_open_ca +*****/ + + +/****f* Access Layer/ib_get_ca_by_gid +* NAME +* ib_get_ca_by_gid +* +* DESCRIPTION +* Returns the GUID of a channel adapter contain the given port GID. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_get_ca_by_gid( + IN ib_al_handle_t h_al, + IN const ib_gid_t* const p_gid, + OUT ib_net64_t* const p_ca_guid ); +/* +* PARAMETERS +* h_al +* [in] A handle to an opened instance of the access layer. +* +* p_gid +* [in] A port GID. +* +* p_ca_guid +* [out] A GUID to the CA that contains the port matching the user- +* specified GID. +* +* RETURN VALUES +* IB_SUCCESS +* The operation was successful. +* +* IB_INVALID_AL_HANDLE +* The access layer handle was invalid. +* +* IB_INVALID_PARAMETER +* A reference to the port GID or CA GUID was not provided. +* +* IB_INSUFFICIENT_MEMORY +* There was insufficient memory to perform the operation. +* +* IB_NOT_FOUND +* No channel adapters in the system contain the specifed port GID. +* +* NOTES +* This routine returns a CA GUID that contains the user-specified port GID. +* If no channel adapters in the system contain the port GID, the call will +* return IB_NOT_FOUND. +* +* SEE ALSO +* ib_open_al, ib_open_ca, ib_get_ca_guids +*****/ + + +/****f* Access Layer/ib_get_port_by_gid +* NAME +* ib_get_port_by_gid +* +* DESCRIPTION +* Returns the GUID of a port that contains the given port GID. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_get_port_by_gid( + IN ib_al_handle_t h_al, + IN const ib_gid_t* const p_gid, + OUT ib_net64_t* const p_port_guid ); +/* +* PARAMETERS +* h_al +* [in] A handle to an opened instance of the access layer. +* +* p_gid +* [in] A port GID. +* +* p_port_guid +* [out] A GUID to the port that contains the matching user- +* specified GID. +* +* RETURN VALUES +* IB_SUCCESS +* The operation was successful. +* +* IB_INVALID_AL_HANDLE +* The access layer handle was invalid. +* +* IB_INVALID_PARAMETER +* A reference to the port GID or port GUID was not provided. +* +* IB_INSUFFICIENT_MEMORY +* There was insufficient memory to perform the operation. +* +* IB_NOT_FOUND +* No channel adapters in the system contain the specifed port GID. +* +* NOTES +* This routine returns a port GUID that contains the user-specified port GID. +* If no channel adapters in the system contain the port GID, the call will +* return IB_NOT_FOUND. +* +* SEE ALSO +* ib_open_al, ib_open_ca, ib_get_ca_guids +*****/ + + +/****f* Access Layer/ib_pfn_mad_comp_cb_t +* NAME +* ib_pfn_mad_comp_cb_t +* +* DESCRIPTION +* User-defined callback used to notify the user of a completion for a +* sent or received datagram. +* +* SYNOPSIS +*/ +typedef void +(AL_API *ib_pfn_mad_comp_cb_t)( + IN const ib_mad_svc_handle_t h_mad_svc, + IN void *mad_svc_context, + IN ib_mad_element_t *p_mad_element ); +/* +* PARAMETERS +* h_mad_svc +* [in] Handle to the MAD service on which the completion occured. +* +* mad_svc_context +* [in] User-defined context information associated with the MAD service +* on which the completion occurred. +* +* p_mad_element +* [in] References information on the completed MAD request. +* +* NOTES +* This function is invoked upon completion of a sent or receive MAD. +* It is separate from the normal completion callbacks in order to allow +* the access layer to perform post processing on the MAD, such as +* segmentation and reassembly, and retransmissions if a response was +* expected. +* +* The mad element returned through this call should be returned to its MAD +* pool after completion processing on the MAD has concluded. Completed +* receive MAD elements should not be reposted to the receive queue of a +* MAD QP. +* +* In the kernel, this callback is typically invoked from within a +* tasklet, depending on the implementation of the verbs provider driver. +* +* SEE ALSO +* ib_send_mad, ib_reg_mad_svc +*****/ + + +/****f* Access Layer/ib_create_mad_pool +* NAME +* ib_create_mad_pool +* +* DESCRIPTION +* Creates a pool of MAD elements for use sending and receive management +* datagrams. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_create_mad_pool( + IN const ib_al_handle_t h_al, + IN const size_t min, + IN const size_t max, + IN const size_t grow_size, + OUT ib_pool_handle_t* const ph_pool ); +/* +* PARAMETERS +* h_al +* [in] A handle to an open instance of the access layer. +* +* min +* [in] The minimum number of MAD elements to create in the pool. +* +* max +* [in] The maximum number of MAD elements that will be created by the +* pool. If max is set to 0, the pool will continue to grow as long +* as system resources are available. +* +* grow_size +* [in] The number of MAD elements to add to the pool when growing it. +* If set to 0, the pool will not grow beyond the number specified +* at creation. This value must be greater than 0, if min is set to 0. +* +* ph_pool +* [out] On successful completion of this call, this returns a handle to +* the newly created pool. +* +* RETURN VALUES +* IB_SUCCESS +* The MAD pool was created successfully. +* +* IB_INVALID_AL_HANDLE +* The access layer handle was invalid. +* +* IB_INVALID_PARAMETER +* A reference to the pool handle was not provided. +* +* IB_INVALID_SETTING +* The maximum number of MAD elements was non-zero and less than the +* minimum number of MAD elements. +* +* IB_INSUFFICIENT_MEMORY +* There was insufficient memory to create the MAD pool. +* +* NOTES +* This routine creates a pool of MAD elements. The elements may be used +* to send and receive MADs on alias and MAD type QPs. +* +* SEE ALSO +* ib_destroy_mad_pool, ib_get_mad, ib_put_mad, ib_reg_mad_pool, +* ib_dereg_mad_pool +*****/ + + +/****f* Access Layer/ib_destroy_mad_pool +* NAME +* ib_destroy_mad_pool +* +* DESCRIPTION +* Destroys a MAD pool and all associated resources. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_destroy_mad_pool( + IN const ib_pool_handle_t h_pool ); +/* +* PARAMETERS +* h_pool +* [in] A handle to a MAD pool allocated through the ib_create_mad_pool +* routine. +* +* RETURN VALUES +* IB_SUCCESS +* The MAD pool was successfully destroyed. +* +* IB_INVALID_HANDLE +* The MAD pool handle was invalid. +* +* IB_RESOURCE_BUSY +* One or more MAD elements have not been returned to the MAD pool. +* +* NOTES +* This call destroys a MAD pool and all resources allocated by the pool. +* +* SEE ALSO +* ib_create_mad_pool, ib_get_mad, ib_put_mad +*****/ + + +/****f* Access Layer/ib_reg_mad_pool +* NAME +* ib_reg_mad_pool +* +* DESCRIPTION +* Registers a MAD pool for use with a protection domain. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_reg_mad_pool( + IN const ib_pool_handle_t h_pool, + IN const ib_pd_handle_t h_pd, + OUT ib_pool_key_t* const p_pool_key ); +/* +* PARAMETERS +* h_pool +* [in] A handle to a MAD pool. +* +* h_pd +* [in] A handle to a protection domain. +* +* p_pool_key +* [out] A key associated with registering the MAD pool with the +* protection domain. This key is returned to the user and is used +* when retrieving MADs from the pool. +* +* RETURN VALUES +* IB_SUCCESS +* The MAD pool was successfully registered with the protection domain. +* +* IB_INVALID_HANDLE +* The MAD pool handle was invalid. +* +* IB_INVALID_PD_HANDLE +* The protection domain handle was invalid. +* +* IB_INVALID_PARAMETER +* A reference to the pool key was not provided. +* +* IB_INSUFFICIENT_MEMORY +* There was insufficient memory to register the MAD pool. +* +* IB_INSUFFICIENT_RESOURCES +* There were insufficient resources currently available on the channel +* adapter to register the MAD pool. +* +* NOTES +* This function registers a MAD pool with a protection domain. After +* successful completion of this call, the MAD elements of the associated +* pool are usable on any queue pairs associated with the given protection +* domain. +* +* SEE ALSO +* ib_create_mad_pool, ib_destroy_mad_pool, ib_dereg_mad_pool, ib_get_mad +*****/ + + +/****f* Access Layer/ib_dereg_mad_pool +* NAME +* ib_dereg_mad_pool +* +* DESCRIPTION +* Deregisters a MAD pool from a protection domain. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_dereg_mad_pool( + IN const ib_pool_key_t pool_key ); +/* +* PARAMETERS +* pool_key +* [in] Key to the MAD pool to deregister. The specified pool must +* have been registered with a protection domain through a call to +* ib_reg_mad_pool. +* +* RETURN VALUES +* IB_SUCCESS +* The MAD pool was successfully deregistered from the protection domain. +* +* IB_INVALID_PARAMETER +* The MAD pool key was invalid. +* +* IB_RESOURCE_BUSY +* One or more MAD elements were removed from the MAD pool using the +* specified pool key, and were not returned. +* +* NOTES +* This function deregisters a MAD pool with a protection domain. After +* successful completion of this call, the MAD elements of the associated +* pool are no longer usable on the protection domain. +* +* SEE ALSO +* ib_create_mad_pool, ib_destroy_mad_pool, ib_reg_mad_pool +*****/ + + +/****f* Access Layer/ib_get_mad +* NAME +* ib_get_mad +* +* DESCRIPTION +* Obtains a MAD element from the pool. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_get_mad( + IN const ib_pool_key_t pool_key, + IN const size_t buf_size, + OUT ib_mad_element_t **pp_mad_element ); +/* +* PARAMETERS +* pool_key +* [in] Key for the pool to obtain a MAD element for the desired +* protection domain. +* +* buf_size +* [in] The size of the buffer referenced by the MAD element. +* +* pp_mad_element +* [out] Upon successful completion of this call, this references +* the returned MAD element. +* +* RETURN VALUES +* IB_SUCCESS +* The MAD element was successfully retrieved from the MAD pool. +* +* IB_INVALID_PARAMETER +* The MAD pool key was invalid or a reference to the MAD element +* pointer was not provided. +* +* IB_INSUFFICIENT_MEMORY +* There was insufficient memory to obtain the MAD element. +* +* IB_INSUFFICIENT_RESOURCES +* There were insufficient resources currently available on the channel +* adapter to grow and register the MAD pool. +* +* NOTES +* This function obtains a MAD element containing a data segment +* that references a data buffer for the given pool key. The data buffer +* referenced by the MAD element is zeroed before being returned to the +* user. +* +* It is recommended that elements retrieved from a MAD pool for use on +* the receive queue of a MAD QP have a buffer size of 256 bytes. +* +* For MADs being sent, buf_size should be set to the size of the relevant +* data sent as part of the MAD, and should not include any padding needed +* to make the MAD size a multiple of 256 bytes. For most MADs, buf_size +* may be set equal to the size of the MAD header plus the amount of user +* data transfered as part of the MAD. +* +* SEE ALSO +* ib_put_mad, ib_send_mad, ib_mad_element_t +*****/ + + +/****f* Access Layer/ib_put_mad +* NAME +* ib_put_mad +* +* DESCRIPTION +* Returns a list of MAD elements to the pool. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_put_mad( + IN const ib_mad_element_t* p_mad_element_list ); +/* +* PARAMETERS +* p_mad_element_list +* [in] A pointer to a list of MAD elements. +* +* RETURN VALUES +* IB_SUCCESS +* The list of MAD elements was successfully returned to the MAD pool. +* +* IB_INVALID_PARAMETER +* A reference to the MAD element list was not provided. +* +* NOTES +* This function returns a list of MAD elements to the pool. +* +* SEE ALSO +* ib_get_mad, ib_mad_element_t +*****/ + + +/****s* Access Layer/ib_dgrm_info_t +* NAME +* ib_dgrm_info_t +* +* DESCRIPTION +* Information specified when initializing a datagram queue pair before its +* first use. +* +* SYNOPSIS +*/ +typedef struct _ib_dgrm_info +{ + ib_net64_t port_guid; + uint32_t qkey; + uint16_t pkey_index; + +} ib_dgrm_info_t; +/* +* FIELDS +* port_guid +* Specifies the port that the datagram service will use. This field +* applies only to IB_QPT_UNRELIABLE_DGRM and IB_QPT_MAD QP types. +* +* qkey +* Specifies the qkey that the queue pair will use. Incoming messages +* must have a matching qkey for the message to be accepted by the +* receiving QP. +* +* pkey_index +* Specifies the pkey associated with this queue pair. +* +* SEE ALSO +* ib_init_dgrm_svc +*****/ + + +/****f* Access Layer/ib_init_dgrm_svc +* NAME +* ib_init_dgrm_svc +* +* DESCRIPTION +* Initializes a datagram queue pair for use. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_init_dgrm_svc( + IN const ib_qp_handle_t h_qp, + IN const ib_dgrm_info_t* const p_dgrm_info OPTIONAL ); +/* +* PARAMETERS +* h_qp +* [in] A handle to an existing queue pair. +* +* p_dgrm_info +* [in] References information needed to configure the queue pair for +* use sending and receiving datagrams. This field is optional for +* IB_QPT_QP0, IB_QPT_QP1 queue pair types and is not used for +* IB_QPT_RAW_IPV6, and IB_QPT_RAW_ETHER queue pair types. +* +* RETURN VALUES +* IB_SUCCESS +* The datagram queue pair was initialized successfully. +* +* IB_INVALID_QP_HANDLE +* The datagram queue pair handle was invalid. +* +* IB_INVALID_PARAMETER +* The queue pair handle was not created as a datagram queue pair type +* or a reference to the datagram service information was not provided. +* +* IB_INVALID_QP_STATE +* The queue pair was in an invalid state for the requested operation. +* +* IB_INSUFFICIENT_MEMORY +* There was insufficient memory to initialize the datagram queue pair. +* +* NOTES +* This call binds the queue pair to a given port and transitions its state +* to ready to send and receive data. A queue pair must be initialized +* before it can be used to send and receive datagrams. +* +* This routine is used to initialize queue pairs of type: +* +* IB_QPT_QP0 +* IB_QPT_QP1 +* IB_QPT_MAD +* IB_QPT_RAW_IPV6 +* IB_QPT_RAW_ETHER +* IB_QPT_UNRELIABLE_DGRM +* +* For IB_QPT_MAD type queue pairs, receive buffers are automatically posted +* by the access layer, however, users must call ib_reg_mad_svc to receive +* MADs. Received MAD elements must be returned to the access layer through +* the ib_put_mad() call. +* +* SEE ALSO +* ib_create_qp, ib_get_spl_qp, ib_dgrm_info_t, ib_reg_mad_svc +*****/ + + +/****d* Access Layer/ib_mad_svc_type_t +* NAME +* ib_mad_svc_type_t +* +* DESCRIPTION +* Indicates the type of services provided by a MAD service. +* +* SYNOPSIS +*/ +typedef enum _ib_mad_svc_type +{ + IB_MAD_SVC_DEFAULT = 0, + IB_MAD_SVC_RMPP, + IB_MAD_SVC_RAW + +} ib_mad_svc_type_t; +/* +* VALUES +* IB_MAD_SVC_DEFAULT +* Indicates that the access layer will provide all necessary services, +* including retransmissions and RMPP for well-defined management classes. +* +* IB_MAD_SVC_RMPP +* Indicates that the MAD service requires retransmissions and the RMPP +* header is available on all MADs. (The RMPP protocol will be activated +* on a per send basis.) This service type should be used for +* user-defined management classes requiring RMPP. +* +* IB_MAD_SVC_RAW +* Specifies that the MAD service will not perform retransmissions or +* perform RMPP. All MADs received or sent on a MAD service of this type +* +* NOTES +* This enum is used to define the types of MAD services available to users. +* +* SEE ALSO +* ib_mad_svc_t, ib_reg_mad_svc +*****/ + + + +/****s* Access Layer/ib_mad_svc_t +* NAME +* ib_mad_svc_t +* +* DESCRIPTION +* Information used to request management datagram support with a queue pair. +* +* SYNOPSIS +*/ +typedef struct _ib_mad_svc +{ + TO_LONG_PTR(void, *mad_svc_context); + TO_LONG_PTR(ib_pfn_mad_comp_cb_t, pfn_mad_send_cb); + TO_LONG_PTR(ib_pfn_mad_comp_cb_t, pfn_mad_recv_cb); + + boolean_t support_unsol; + uint8_t mgmt_class; + uint8_t mgmt_version; + boolean_t method_array[IB_MAX_METHODS]; + + ib_mad_svc_type_t svc_type; + +} ib_mad_svc_t; +/* +* FIELDS +* mad_svc_context +* User-defined context that is returned by the access layer through +* the pfn_mad_send_cb and pfn_mad_recv_cb. +* +* pfn_mad_send_cb +* A send callback that is invoked to notify the user that a send +* operation has completed for a sent MAD. +* +* pfn_mad_recv_cb +* A receive callback that is invoked to notify the user that a MAD +* has been received. +* +* support_unsol +* If set to TRUE, this field indicates that the registering client +* supports processing unsolicited MADs. Unsolicited MADs are +* received MADs that do not have the response bit set. If set to TRUE, +* the following fields are required (must be non-zero): mgmt_class, +* mgmt_version, and method_array. +* +* mgmt_version +* Indicates which version of a management class the client requires +* support for. The access layer distinguishes between clients +* requiring different versions of the same management class. +* This field is ignored if the support_unsol field is set to FALSE. +* +* mgmt_class +* Indicates the management class that should be supported by the +* access layer. This field is ignored if the support_unsol field is +* set to FALSE. +* +* method_array +* An array of 127 entries specifying which methods are supported by +* a client when receiving unsolicited MADs. Each index corresponds to +* a single method, and each entry in the array indicates if the method +* is supported by the client. This field is ignored if the +* support_unsol field is set to FALSE. +* +* svc_type +* Indicates the type of services that should be provided by the MAD +* service. +* +* NOTES +* Clients use this structure to define which management datagram methods +* they support, and the type of support required for each. A received MAD +* is distinguished by the access layer based on the following three fields: +* management class, management version, and method. +* +* Specific combinations of class, version, and method may be registered +* for unsolicited MADs only once. The access layer supports multiple +* clients registering for unsolicited MADs as long as they do not share the +* same methods, class, or version. +* +* The svc_type field can be set by a client to indicate that the access +* layer should invoke RMPP for the specified management class of MADs. If +* set to IB_MAD_SVC_DEFAULT, the access layer will automatically invoke RMPP +* for well known MAD classes (those defined by the 1.1 version of the +* InfiniBand specification). The svc_type field is intended to be used by +* clients sending and receiving vendor specific management class requiring +* RMPP and clients providing their own MAD services. +* +* SEE ALSO +* ib_reg_mad_svc, ib_pfn_mad_send_cb_t, ib_pfn_mad_recv_cb_t, +* ib_mad_svc_type_t +*****/ + + +/****f* Access Layer/ib_reg_mad_svc +* NAME +* ib_reg_mad_svc +* +* DESCRIPTION +* Requests management datagram support for a specified class with a +* queue pair. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_reg_mad_svc( + IN const ib_qp_handle_t h_qp, + IN const ib_mad_svc_t* const p_mad_svc, + OUT ib_mad_svc_handle_t* const ph_mad_svc ); +/* +* PARAMETERS +* h_qp +* [in] A handle to queue pair. The queue pair must have been created +* as one of the following types: IB_QPT_QP0, IB_QPT_QP0_ALIAS, +* IB_QPT_QP1, IB_QPT_QP1_ALIAS, or IB_QPT_MAD. +* +* p_mad_svc +* [in] A reference to the management class and methods supported by +* this queue pair. +* +* ph_mad_svc +* [out] On successful completion of this call, this references a +* handle to the newly created MAD service. +* +* RETURN VALUES +* IB_SUCCESS +* The queue pair was registered successfully. +* +* IB_INVALID_QP_HANDLE +* The queue pair handle was invalid. +* +* IB_INVALID_PARAMETER +* The queue pair handle was not created with the proper queue pair +* type or a reference to the MAD service information or handle was +* not provided. +* +* IB_INSUFFICIENT_MEMORY +* There was insufficient memory to register the queue pair. +* +* NOTES +* This routine registers a queue pair as using a particular management +* class. This indicates that the access layer should perform additional +* processing on MADs sent and received by this queue pair. Queue pairs +* registered for MAD support receive access layer SAR and retransmissions +* services. A queue pair may be registered for multiple management classes. +* +* SEE ALSO +* ib_create_qp, ib_mad_svc_t +*****/ + +/****s* Access Layer/ib_reg_svc_rec_t +* NAME +* _ib_reg_svc_rec_t +* +* DESCRIPTION +* Information returned as a result of registering a service with the subnet +* administrator. This includes name service registration. +* +* SYNOPSIS +*/ +typedef struct _ib_reg_svc_rec +{ + const void* svc_context; + ib_reg_svc_handle_t h_reg_svc; + ib_api_status_t req_status; + ib_net16_t resp_status; + ib_service_record_t svc_rec; + +} ib_reg_svc_rec_t; +/* +* FIELDS +* svc_context +* User-defined context information associated with the registration +* through the ib_reg_svc call. +* +* req_status +* Indicates the success of the registration operation. +* +* resp_status +* Indicates the status of the response from the SA +* +* h_reg_svc +* For successful queries, this references the first record of +* information returned by the subnet administrator. If multiple +* records of information were returned, the ib_reg_svc_rec_t will +* be chained together. +* +* svc_rec +* The service record returned by the SA for the registered service. +* +* NOTES +* A query result structure is returned to a client through their +* ib_pfn_query_cb_t routine to notify them of the results of a subnet +* administration query. +* +* SEE ALSO +* ib_reg_svc, ib_pfn_reg_svc_cb_t, ib_reg_svc_status_t +*****/ + + +/****f* Access Layer/ib_pfn_reg_svc_cb_t +* NAME +* ib_pfn_reg_svc_cb_t +* +* DESCRIPTION +* User-defined callback that is invoked to notify a client of the result +* of a service registration attempt. +* +* SYNOPSIS +*/ +typedef void +(AL_API *ib_pfn_reg_svc_cb_t)( + IN ib_reg_svc_rec_t *p_reg_svc_rec ); +/* +* PARAMETERS +* p_reg_svc_rec +* [in] References the result of the service registration attempt. +* +* NOTES +* The callback is used to notify a client of the result of a service +* registration attempt with the subnet administrator. +* +* In the kernel, this callback is usually invoked using a tasklet, dependent +* on the implementation of the underlying verbs provider driver. +* +* SEE ALSO +* ib_reg_svc, ib_reg_svc_rec_t +*****/ + + +/****s* Access Layer/ib_reg_svc_req_t +* NAME +* ib_reg_svc_req_t +* +* DESCRIPTION +* Information used to request that a service be registered with the subnet +* administrator. +* +* SYNOPSIS +*/ +typedef struct _ib_reg_svc_req +{ + ib_service_record_t svc_rec; + ib_net64_t port_guid; + + uint32_t timeout_ms; + uint32_t retry_cnt; + ib_al_flags_t flags; + + const void *svc_context; + ib_net64_t svc_data_mask; + + ib_pfn_reg_svc_cb_t pfn_reg_svc_cb; + +} ib_reg_svc_req_t; +/* +* FIELDS +* svc_rec +* Service record that describes the service being registered. +* +* port_guid +* Directs the registration to use the specified port. The request will +* contact the management entity reachable through the given port. +* +* timeout_ms +* Specifies the number of milliseconds to wait for a response for +* the registration until retrying or timing out the request. +* +* retry_cnt +* Specifies the number of times that the registration 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. +* +* svc_context +* User-defined context information associated with this registration +* request. This context is returned to the user through the function +* specified by the pfn_reg_svc_cb field. +* +* svc_data_mask +* User-defined component mask indicating which parts of the private +* data is populated. This is used as an extension to the svc_id +* for data compare. Also used as a cheap way to communicate data +* to all clients for this service. +* +* pfn_reg_svc_cb +* A user-defined callback that is invoked upon completion of the +* registration request. +* +* NOTES +* This structure is used to register a service with the subnet administrator. +* The registration call operates asynchronously unless the flags field is +* set to IB_FLAGS_SYNC. If synchronous operation is indicated, the client +* will receive a callback with the results of the registration attempt +* before the ib_reg_svc call returns. Synchronous operation results in +* the calling thread blocking. +* +* SEE ALSO +* ib_reg_svc, ib_svc_rec_t, ib_pfn_reg_svc_cb_t +*****/ + + +/****f* Access Layer/ib_reg_svc +* NAME +* ib_reg_svc +* +* DESCRIPTION +* Routine used to register for a service with the subnet administrator. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_reg_svc( + IN const ib_al_handle_t h_al, + IN const ib_reg_svc_req_t* const p_reg_svc_req, + OUT ib_reg_svc_handle_t* const ph_reg_svc ); +/* +* PARAMETERS +* h_al +* [in] A handle to an open instance of the access layer. +* +* p_reg_svc_req +* [in] Describes the service to register with the subnet administrator. +* +* ph_reg_svc +* [out] Pointer to a service registration handle, used to deregister +* the service. Set upon successful completion of the function. +* +* RETURN VALUES +* IB_SUCCESS +* The service registration was initiated. +* +* IB_INVALID_AL_HANDLE +* The access layer handle was invalid. +* +* IB_INVALID_PARAMETER +* A reference to the service registration request was not provided. +* +* IB_INSUFFICIENT_MEMORY +* There was insufficient memory to perform the operation. +* +* IB_NOT_FOUND +* No channel adapters in the system contain the GID specified in the +* service record. +* +* IB_INVALID_GID +* No port was found matching the GID specified in the service record. +* +* IB_INSUFFICIENT_RESOURCES +* There were insufficient resources currently available on the channel +* adapter to perform the operation. +* +* NOTES +* This routine registers a service with the subnet administrator. Registered +* services are reported by the subnet administrator to clients querying the +* subnet administrator for service information. +* +* Once registered, a client will receive notification, via a callback, +* that a service has been successfully registered. +* +* SEE ALSO +* ib_dereg_svc, ib_reg_svc_req_t +*****/ + + +/****f* Access Layer/ib_dereg_svc +* NAME +* ib_dereg_svc +* +* DESCRIPTION +* Remove a service as being registered with the subnet administrator. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_dereg_svc( + IN const ib_reg_svc_handle_t h_reg_svc, + IN const ib_pfn_destroy_cb_t pfn_destroy_cb OPTIONAL ); +/* +* PARAMETERS +* h_reg_svc +* [in] A handle to a registered service. +* +* pfn_destroy_cb +* [in] A user-specified callback that is invoked after the service +* has been deregistered. +* +* RETURN VALUES +* IB_SUCCESS +* The service deregistration was initiated. +* +* IB_INVALID_HANDLE +* The registered service handle was invalid. +* +* IB_INSUFFICIENT_MEMORY +* There was insufficient memory to perform the operation. +* +* IB_INSUFFICIENT_RESOURCES +* There were insufficient resources currently available on the channel +* adapter to perform the operation. +* +* NOTES +* This routine deregisters a service with the subnet administrator. +* To avoid a race condition deregistering a service at the same time +* the registration completion callback is in progress, the deregister +* operation operates asynchronously. For additional details see +* ib_pfn_destroy_cb_t. +* +* SEE ALSO +* ib_reg_svc, ib_pfn_destroy_cb_t +*****/ + + +/****d* Access Layer/ib_query_type_t +* NAME +* ib_query_type_t +* +* DESCRIPTION +* Abstracted queries supported by the access layer. +* +* SYNOPSIS +*/ +typedef enum _ib_query_type +{ + IB_QUERY_USER_DEFINED, + + IB_QUERY_ALL_SVC_RECS, + IB_QUERY_SVC_REC_BY_NAME, + IB_QUERY_SVC_REC_BY_ID, + + IB_QUERY_CLASS_PORT_INFO, + + IB_QUERY_NODE_REC_BY_NODE_GUID, + IB_QUERY_PORT_REC_BY_LID, + + IB_QUERY_VLARB_BY_LID_PORT_BLOCK, + IB_QUERY_SLVL_BY_LID_AND_PORTS, + + IB_QUERY_PATH_REC_BY_PORT_GUIDS, + IB_QUERY_PATH_REC_BY_GIDS, + IB_QUERY_PATH_REC_BY_LIDS, + +} ib_query_type_t; +/* +* VALUES +* IB_QUERY_USER_DEFINED +* Query the SA based on user-defined input. Queries of this type +* should reference an ib_user_query_t structure as input into the +* query. +* +* IB_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 +* into the query. +* +* IB_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. +* +* IB_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. +* +* IB_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. +* +* IB_QUERY_PATH_REC_BY_PORT_GUIDS +* Query for path records between the specified pair of port GUIDs. +* Queries of this type should reference an ib_guid_pair_t structure +* that indicates the GUIDs of the path being requested. +* +* IB_QUERY_PATH_REC_BY_GIDS +* Query for path records between the specified pair of port GIDs. +* Queries of this type should reference an ib_gid_pair_t structure +* that indicates the GIDs of the path being requested. +* +* IB_QUERY_PATH_REC_BY_LIDS +* Query for path records between the specified pair of port LIDs. +* Queries of this type should reference an ib_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 the subnet administrator or a class manager. These queries are +* intended to represent those most often used by clients. +* +* SEE ALSO +* ib_query, ib_query_req_t, ib_user_query_t, ib_gid_pair_t, ib_lid_pair_t +* ib_guid_pair_t +*****/ + + +/****s* Access Layer/ib_user_query_t +* NAME +* ib_user_query_t +* +* DESCRIPTION +* User-defined query information. +* +* SYNOPSIS +*/ +typedef struct _ib_user_query +{ + uint8_t method; + ib_net16_t attr_id; + uint32_t attr_size; + ib_net64_t comp_mask; + TO_LONG_PTR(void*, p_attr); + +} ib_user_query_t; +/* +* FIELDS +* +* method +* Method to be run +* +* attr_id +* Attribute identifier of query data. +* +* attr_size +* Size of the query attribute in bytes. This is translated into the +* attr_offset field of the SA MAD by the ib_query call. +* +* 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 +* ib_query_type_t, ib_query, ib_get_attr_offset, ib_get_attr_size +*****/ + + +/****s* Access Layer/ib_gid_pair_t +* NAME +* ib_gid_pair_t +* +* DESCRIPTION +* Source and destination GIDs. +* +* SYNOPSIS +*/ +typedef struct _ib_gid_pair +{ + ib_gid_t src_gid; + ib_gid_t dest_gid; + +} ib_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* Access Layer/ib_lid_pair_t +* NAME +* ib_lid_pair_t +* +* DESCRIPTION +* Source and destination LIDs. +* +* SYNOPSIS +*/ +typedef struct _ib_lid_pair +{ + ib_net16_t src_lid; + ib_net16_t dest_lid; + +} ib_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* Access Layer/ib_guid_pair_t +* NAME +* ib_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 _ib_guid_pair +{ + ib_net64_t src_guid; + ib_net64_t dest_guid; + +} ib_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* Access Layer/ib_query_rec_t +* NAME +* ib_query_rec_t +* +* DESCRIPTION +* Contains the results of a subnet administration query. +* +* SYNOPSIS +*/ +typedef struct _ib_query_rec +{ + const void* query_context; + ib_api_status_t status; + + ib_query_type_t query_type; + uint32_t result_cnt; + ib_mad_element_t* p_result_mad; + +} ib_query_rec_t; +/* +* FIELDS +* query_context +* User-defined context information associated with the query through +* the ib_reg_query 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 ib_reg_query call. +* +* result_cnt +* The number of result structures that were returned by the query. +* +* p_result_mad +* For queries returning IB_SUCCESS or IB_REMOTE_ERROR, this references +* the MAD returned by the subnet administrator containing the list +* of results or the returned error code. +* +* NOTES +* A query result structure is returned to a client through their +* ib_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 the subnet administrator, p_result_mad will reference a MAD element +* containing the results. The MAD referenced by p_result_mad is owned by +* the user and remains available even after their callback returns. Users +* must call ib_put_mad() to return the MAD element back to the access layer +* when they are done accessing the results. +* +* To retrieve individual result structures from the p_result_mad, users +* may call ib_get_query_result(). +* +* SEE ALSO +* ib_query, ib_pfn_query_cb_t, ib_api_status_t, ib_put_mad, ib_mad_element_t +* ib_query_status_t, ib_query_type_t, ib_get_query_result +*****/ + + +/****f* Access Layer/ib_get_query_result +* NAME +* ib_get_query_result +* +* DESCRIPTION +* Retrieves a result structure from a MAD returned by a call to ib_query(). +* +* SYNOPSIS +*/ +AL_INLINE void* AL_API +ib_get_query_result( + IN ib_mad_element_t *p_result_mad, + IN uint32_t result_index ) +{ + ib_sa_mad_t *p_sa_mad; + + CL_ASSERT( p_result_mad ); + p_sa_mad = (ib_sa_mad_t*)ib_get_mad_buf( p_result_mad ); + 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_mad->size ); + + return( p_sa_mad->data + + (ib_get_attr_size( p_sa_mad->attr_offset ) * result_index) ); +} +/* +* PARAMETERS +* p_result_mad +* [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 ib_query(). 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 ib_query_rec_t structure. +* +* SEE ALSO +* ib_query_rec_t, ib_mad_element_t +*****/ + + +/****f* Access Layer/ib_get_query_path_rec +* NAME +* ib_get_query_path_rec +* +* DESCRIPTION +* Retrieves a path record result from a MAD returned by a call to +* ib_query(). +* +* SYNOPSIS +*/ +AL_INLINE ib_path_rec_t* AL_API +ib_get_query_path_rec( + IN ib_mad_element_t *p_result_mad, + IN uint32_t result_index ) +{ + ib_sa_mad_t *p_sa_mad; + + CL_ASSERT( p_result_mad ); + p_sa_mad = (ib_sa_mad_t*)ib_get_mad_buf( p_result_mad ); + CL_ASSERT( p_sa_mad && p_sa_mad->attr_id == IB_MAD_ATTR_PATH_RECORD ); + + return( (ib_path_rec_t*)ib_get_query_result( p_result_mad, result_index ) ); +} +/* +* PARAMETERS +* p_result_mad +* [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 ib_query(). +* +* SEE ALSO +* ib_query_rec_t, ib_mad_element_t, ib_get_query_result, ib_path_rec_t +*****/ + + +/****f* Access Layer/ib_get_query_portinfo_rec +* NAME +* ib_get_query_portinfo_rec +* +* DESCRIPTION +* Retrieves a port info record result from a MAD returned by a call to +* ib_query(). +* +* SYNOPSIS +*/ +AL_INLINE ib_portinfo_record_t* AL_API +ib_get_query_portinfo_rec( + IN ib_mad_element_t *p_result_mad, + IN uint32_t result_index ) +{ + ib_sa_mad_t *p_sa_mad; + + CL_ASSERT( p_result_mad ); + p_sa_mad = (ib_sa_mad_t*)ib_get_mad_buf( p_result_mad ); + CL_ASSERT( p_sa_mad && p_sa_mad->attr_id == IB_MAD_ATTR_PORTINFO_RECORD ); + + return( (ib_portinfo_record_t*)ib_get_query_result( p_result_mad, + result_index ) ); +} +/* +* PARAMETERS +* p_result_mad +* [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 ib_query(). +* +* SEE ALSO +* ib_query_rec_t, ib_mad_element_t, ib_get_query_result, ib_portinfo_record_t +*****/ + + +/****f* Access Layer/ib_get_query_node_rec +* NAME +* ib_get_query_node_rec +* +* DESCRIPTION +* Retrieves a node record result from a MAD returned by a call to +* ib_query(). +* +* SYNOPSIS +*/ +AL_INLINE ib_node_record_t* AL_API +ib_get_query_node_rec( + IN ib_mad_element_t *p_result_mad, + IN uint32_t result_index ) +{ + ib_sa_mad_t *p_sa_mad; + + CL_ASSERT( p_result_mad ); + p_sa_mad = (ib_sa_mad_t*)ib_get_mad_buf( p_result_mad ); + CL_ASSERT( p_sa_mad && p_sa_mad->attr_id == IB_MAD_ATTR_NODE_RECORD ); + + return( (ib_node_record_t*)ib_get_query_result( p_result_mad, + result_index ) ); +} +/* +* PARAMETERS +* p_result_mad +* [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 ib_query(). +* +* SEE ALSO +* ib_query_rec_t, ib_mad_element_t, ib_get_query_result, ib_node_record_t +*****/ + + +/****f* Access Layer/ib_get_query_svc_rec +* NAME +* ib_get_query_svc_rec +* +* DESCRIPTION +* Retrieves a service record result from a MAD returned by a call to +* ib_query(). +* +* SYNOPSIS +*/ +AL_INLINE ib_service_record_t* AL_API +ib_get_query_svc_rec( + IN ib_mad_element_t *p_result_mad, + IN uint32_t result_index ) +{ + ib_sa_mad_t *p_sa_mad; + + CL_ASSERT( p_result_mad ); + p_sa_mad = (ib_sa_mad_t*)ib_get_mad_buf( p_result_mad ); + CL_ASSERT( p_sa_mad && p_sa_mad->attr_id == IB_MAD_ATTR_SERVICE_RECORD ); + + return( (ib_service_record_t*)ib_get_query_result( p_result_mad, + result_index ) ); +} +/* +* PARAMETERS +* p_result_mad +* [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 ib_query(). +* +* SEE ALSO +* ib_query_rec_t, ib_mad_element_t, ib_get_query_result, ib_service_record_t +*****/ + + +/****f* Access Layer/ib_pfn_query_cb_t +* NAME +* ib_pfn_query_cb_t +* +* DESCRIPTION +* User-defined callback invoked on completion of a subnet administrator +* query. +* +* SYNOPSIS +*/ +typedef void +(AL_API *ib_pfn_query_cb_t)( + IN ib_query_rec_t *p_query_rec ); +/* +* PARAMETERS +* p_query_rec +* [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 the subnet administrator. +* +* In the kernel, this callback is usually invoked using a tasklet, dependent +* on the implementation of the underlying verbs provider driver. +* +* SEE ALSO +* ib_query_rec_t +*****/ + + +/****s* Access Layer/ib_query_req_t +* NAME +* ib_query_req_t +* +* DESCRIPTION +* Information used to request an access layer provided query of the subnet +* administrator. +* +* SYNOPSIS +*/ +typedef struct _ib_query_req +{ + ib_query_type_t query_type; + const void* p_query_input; + ib_net64_t port_guid; + + uint32_t timeout_ms; + uint32_t retry_cnt; + ib_al_flags_t flags; + + const void* query_context; + ib_pfn_query_cb_t pfn_query_cb; + +} ib_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. +* +* port_guid +* Directs the query to use the specified port. The request will +* contact the management entity reachable through the given port. +* +* 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 access layer provided query +* of the subnet administrator. 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 ib_guid_pair_t structure +* -- a pair of GIDs specified through an ib_gid_pair_t structure +* +* SEE ALSO +* ib_query_type_t, ib_pfn_query_cb_t, ib_guid_pair_t, +* ib_gid_pair_t +*****/ + + +/****f* Access Layer/ib_query +* NAME +* ib_query +* +* DESCRIPTION +* Routine used to request an access layer provided query of the subnet +* administrator. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_query( + IN const ib_al_handle_t h_al, + IN const ib_query_req_t* const p_query_req, + OUT ib_query_handle_t* const ph_query OPTIONAL ); +/* +* PARAMETERS +* h_al +* [in] A handle to an open instance of the access layer. +* +* p_query_req +* [in] Specifies the type of query that the access layer should perform, +* along with information needed to process the completed query. +* +* ph_query +* [out] Pointer to a query handle that can be used to cancel the query. +* +* RETURN VALUES +* IB_SUCCESS +* The subnet administrator query was initiated. +* +* IB_INVALID_AL_HANDLE +* The access layer handle was invalid. +* +* IB_INVALID_PARAMETER +* A reference to the query request was not provided. +* +* IB_INSUFFICIENT_MEMORY +* There was insufficient memory to perform the operation. +* +* IB_INVALID_GUID +* No port was found for the port_guid specified in the request. +* +* IB_ERROR +* An invalid query_type was specified in the request. +* +* IB_INSUFFICIENT_RESOURCES +* There were insufficient resources currently available on the channel +* adapter to perform the operation. +* +* NOTES +* This routine directs the access layer to initiate a query to the subnet +* administrator for desired information. The access layer will issue the +* query, collect the results, and report them to the client through a user- +* specified callback. The access layer is responsible for retrying the +* operation as directed by the client. +* +* SEE ALSO +* ib_cancel_query, ib_query_req_t +*****/ + + +/****f* Access Layer/ib_cancel_query +* NAME +* ib_cancel_query +* +* DESCRIPTION +* Routine used to cancel a query of the subnet administrator. +* +* SYNOPSIS +*/ +AL_EXPORT void AL_API +ib_cancel_query( + IN const ib_al_handle_t h_al, + IN const ib_query_handle_t h_query ); +/* +* PARAMETERS +* h_al +* [in] A handle to an open instance of the access layer. +* +* h_query +* [in] Query handle returned by a previous call to ib_query(). +* +* RETURN VALUES +* This function does not return a value. +* +* NOTES +* This routine directs the access layer to cancel a query to the subnet +* administrator. The access layer will issue notify the user with the +* final status of the query through the query callback specified in the +* call to ib_query(). +* +* SEE ALSO +* ib_query +*****/ + + +/****d* Access Layer/ib_pnp_class_t +* NAME +* ib_pnp_class_t +* +* DESCRIPTION +* Specifies the class of plug and play events that are being subscribed for. +* +* SYNOPSIS +*/ +#define IB_PNP_CA 0x00000001 +#define IB_PNP_PORT 0x00000002 +#define IB_PNP_IOU 0x00000004 +#define IB_PNP_IOC 0x00000008 + +#define IB_PNP_FLAG_REG_SYNC 0x40000000 +#define IB_PNP_FLAG_REG_COMPLETE 0x80000000 +#define IB_PNP_FLAG_MASK 0xF0000000 +#define IB_PNP_CLASS_MASK 0x000000FF + +typedef uint32_t ib_pnp_class_t; +/* +* VALUES +* IB_PNP_CA +* Value used to register for local channel adapter events. These +* events include the addition or removal of a local channel adapter. +* +* IB_PNP_PORT +* Value used to register for local port events. These events include +* local port up or down events and port LID or Pkey changes. +* +* IB_PNP_IOU +* Value used to register for I/O unit PnP events. I/O unit events +* include notifications of I/O unit assignment to and dissociation from +* the local host. +* +* IB_PNP_IOC +* Value used to register for an I/O controller PnP event. I/O controller +* events include notification of an I/O controller assignment to a local +* port and indication that an I/O controller dissociation has occurred. +* +* IB_PNP_FLAG_REG_SYNC +* Flag that is ORed with the PnP Class to control behavior of the +* ib_pnp_reg call. When set, ib_pnp_reg returns after client has +* received all events for the current state of the system. +* +* IB_PNP_FLAG_REG_COMPLETE +* Flag that is ORed with the PnP Class to control whether an event +* is generated to indicate that a client has received all events for the +* current state of the system. +* +* NOTES +* When registering for PnP notification, a client specifies the class of +* local events that the client wishes to be notified of. For example to +* request notification of events on a port, a client would use IB_PNP_PORT. +* To be notified of the assignment of an I/O controller, a client would use +* IB_PNP_IOC. +* +* The PnP APIs do not support registration for multiple event classes at +* a time. +* +* SEE ALSO +* ib_pfn_pnp_cb_t, ib_pfn_report_cb_t, ib_pnp_rec_t, ib_pnp_event_t +*****/ + + +/****d* Access Layer/ib_pnp_event_t +* NAME +* ib_pnp_event_t +* +* DESCRIPTION +* Indicates the type of plug and play event that has occurred. +* +* SYNOPSIS +*/ +#define IB_PNP_EVENT_PATH 0x00000800 +#define IB_PNP_EVENT_ADD 0x00001000 +#define IB_PNP_EVENT_REMOVE 0x00002000 +#define IB_PNP_EVENT_CHANGE 0x00004000 +#define IB_PNP_EVENT_INIT 0x00008000 +#define IB_PNP_EVENT_ARMED 0x00010000 +#define IB_PNP_EVENT_ACTIVE 0x00020000 +#define IB_PNP_EVENT_DOWN 0x00040000 +#define IB_PNP_EVENT_PKEY 0x00080000 +#define IB_PNP_EVENT_SM 0x00100000 +#define IB_PNP_EVENT_GID 0x00200000 +#define IB_PNP_EVENT_LID 0x00400000 +#define IB_PNP_EVENT_SUBNET 0x00800000 + +#define IB_PNP_CA_ADD (IB_PNP_CA | IB_PNP_EVENT_ADD) +#define IB_PNP_CA_REMOVE (IB_PNP_CA | IB_PNP_EVENT_REMOVE) + +#define IB_PNP_PORT_ADD (IB_PNP_PORT | IB_PNP_EVENT_ADD) +#define IB_PNP_PORT_REMOVE (IB_PNP_PORT | IB_PNP_EVENT_REMOVE) +#define IB_PNP_PORT_INIT (IB_PNP_PORT | IB_PNP_EVENT_INIT) +#define IB_PNP_PORT_ARMED (IB_PNP_PORT | IB_PNP_EVENT_ARMED) +#define IB_PNP_PORT_ACTIVE (IB_PNP_PORT | IB_PNP_EVENT_ACTIVE) +#define IB_PNP_PORT_DOWN (IB_PNP_PORT | IB_PNP_EVENT_DOWN) +#define IB_PNP_PKEY_CHANGE (IB_PNP_PORT | IB_PNP_EVENT_PKEY) +#define IB_PNP_SM_CHANGE (IB_PNP_PORT | IB_PNP_EVENT_SM) +#define IB_PNP_GID_CHANGE (IB_PNP_PORT | IB_PNP_EVENT_GID) +#define IB_PNP_LID_CHANGE (IB_PNP_PORT | IB_PNP_EVENT_LID) +#define IB_PNP_SUBNET_TIMEOUT_CHANGE (IB_PNP_PORT | IB_PNP_EVENT_SUBNET) + +#define IB_PNP_IOU_ADD (IB_PNP_IOU | IB_PNP_EVENT_ADD) +#define IB_PNP_IOU_REMOVE (IB_PNP_IOU | IB_PNP_EVENT_REMOVE) +#define IB_PNP_IOC_ADD (IB_PNP_IOC | IB_PNP_EVENT_ADD) +#define IB_PNP_IOC_REMOVE (IB_PNP_IOC | IB_PNP_EVENT_REMOVE) +#define IB_PNP_IOC_PATH_ADD (IB_PNP_IOC | IB_PNP_EVENT_PATH | \ + IB_PNP_EVENT_ADD) +#define IB_PNP_IOC_PATH_REMOVE (IB_PNP_IOC | IB_PNP_EVENT_PATH | \ + IB_PNP_EVENT_REMOVE) + +#define IB_PNP_REG_COMPLETE IB_PNP_FLAG_REG_COMPLETE + +typedef uint32_t ib_pnp_event_t; +/* +* VALUES +* IB_PNP_CA_ADD +* Indicates that a new channel adapter has been added. +* +* IB_PNP_CA_REMOVE +* Indicates that a channel adapter has been removed. +* +* IB_PNP_PORT_ADD +* Indicates that a new port has been added. This callback will always +* be followed by a callback to indicate the actual port state to allow +* clients to use the PnP callbacks to drive their state machine. +* +* IB_PNP_PORT_REMOVE +* Indicates that a port has been removed. +* A CA remove event will trigger this event first. +* +* IB_PNP_PORT_INIT +* Indicates that a port is in the IB_LINK_INIT state. +* +* IB_PNP_PORT_ARMED +* Indicates that a port is in the IB_LINK_ARMED state. +* +* IB_PNP_PORT_ACTIVE +* Indicates that a port is in the IB_LINK_ACTIVE state. +* +* IB_PNP_PORT_DOWN +* Indicates that a port down event has occurred. +* +* IB_PNP_PKEY_CHANGE +* Indicates that port Pkey change has ocurred. +* +* IB_PNP_SM_CHANGE +* Indicates that the SM assignment for a port has changed. +* +* IB_PNP_GID_CHANGE +* Indicates that the GID assignment for a port has changed. +* +* IB_PNP_LID_CHANGE +* Indicates that the LID or LMC assignment for a port has changed. +* +* IB_PNP_SUBNET_TIMEOUT_CHANGE +* Indicates that the subnet timeout assignment for a port has changed. +* +* IB_PNP_IOU_ADD +* Indicates that an I/O unit assignment has occured. +* +* IB_PNP_IOU_REMOVE +* Indicates that an I/O unit disassociation has occured. +* +* IB_PNP_IOC_ADD +* Indicates that an I/O controller assignment has occurred. +* +* IB_PNP_IOC_REMOVE +* Indicates that an I/O controller dissociation has occurred. +* A port down event will trigger this event first. +* +* IB_PNP_IOC_PATH_ADD +* Indicates that a new path to an I/O controller is available. +* +* IB_PNP_IOC_PATH_REMOVE +* Indiactes that a path to an I/O controller is no longer avaialble. +* +* IB_PNP_REG_COMPLETE +* Indicates that all events associated with a ib_reg_pnp call have been +* reported to the user. The user's state of the system is now in +* sync with that of the access layer. +* +* NOTES +* The Access Layer maintains a queue of client PnP registrations. +* Using this queue, PnP events are reported to clients in a specific +* order. CA add, port add, and IOC add events are reported from the +* head of the queue, while CA remove, port remove, and IOC remove events +* are reported from the tail. Clients are responsible for performing +* registrations in the proper sequence to ensure that PnP event +* notifiations occur in the desired order. +* +* SEE ALSO +* ib_pfn_pnp_cb_t, ib_pfn_report_cb_t, ib_pnp_rec_t, ib_pnp_class_t +*****/ + + +AL_INLINE const char* AL_API +ib_get_pnp_event_str( + IN ib_pnp_event_t event ) +{ + switch( event ) + { + case IB_PNP_CA_ADD : return "IB_PNP_CA_ADD"; + case IB_PNP_CA_REMOVE : return "IB_PNP_CA_REMOVE"; + case IB_PNP_PORT_ADD : return "IB_PNP_PORT_ADD"; + case IB_PNP_PORT_REMOVE : return "IB_PNP_PORT_REMOVE"; + case IB_PNP_PORT_INIT : return "IB_PNP_PORT_INIT"; + case IB_PNP_PORT_ARMED : return "IB_PNP_PORT_ARMED"; + case IB_PNP_PORT_ACTIVE : return "IB_PNP_PORT_ACTIVE"; + case IB_PNP_PORT_DOWN : return "IB_PNP_PORT_DOWN"; + case IB_PNP_PKEY_CHANGE : return "IB_PNP_PKEY_CHANGE"; + case IB_PNP_SM_CHANGE : return "IB_PNP_SM_CHANGE"; + case IB_PNP_GID_CHANGE : return "IB_PNP_GID_CHANGE"; + case IB_PNP_LID_CHANGE : return "IB_PNP_LID_CHANGE"; + case IB_PNP_SUBNET_TIMEOUT_CHANGE : return "IB_PNP_SUBNET_TIMEOUT_CHANGE"; + case IB_PNP_IOU_ADD : return "IB_PNP_IOU_ADD"; + case IB_PNP_IOU_REMOVE : return "IB_PNP_IOU_REMOVE"; + case IB_PNP_IOC_ADD : return "IB_PNP_IOC_ADD"; + case IB_PNP_IOC_REMOVE : return "IB_PNP_IOC_REMOVE"; + case IB_PNP_IOC_PATH_ADD : return "IB_PNP_IOC_PATH_ADD"; + case IB_PNP_IOC_PATH_REMOVE : return "IB_PNP_IOC_PATH_REMOVE"; + case IB_PNP_REG_COMPLETE : return "IB_PNP_REG_COMPLETE"; + } + return "Unknown"; +} + + +/****s* Access Layer/ib_pnp_rec_t +* NAME +* ib_pnp_rec_t +* +* DESCRIPTION +* Notification information used to describe local channel adapter, port, +* and I/O controller events. +* +* SYNOPSIS +*/ +typedef struct _ib_pnp_rec +{ + ib_pnp_event_t pnp_event; + + TO_LONG_PTR(struct _al_pnp *, h_pnp); + TO_LONG_PTR(struct _al_pnp *, h_ioc_event); + + TO_LONG_PTR(void*, pnp_context); + TO_LONG_PTR(void*, context); + //NOTE: + //guid and ca_guid use as key to flexi map need to keep these field together + ib_net64_t guid; + ib_net64_t ca_guid; + +} ib_pnp_rec_t; +/* +* FIELDS +* pnp_event +* Describes the type of plug and play event that is being reported. +* +* h_pnp +* A handle to the notification registration for which this PnP record +* was generated. This handle will match the handle returned through +* an ib_reg_pnp call. It is provided in case a PnP notification event +* occurs before a client's call to ib_reg_pnp can return. This handle +* may be used to cancel further notification of PnP events. +* +* h_ioc_event +* A handle that is unique to an I/O controller assignment event. +* This handle is used to reject the assignment of an I/O controller +* from within the ib_pfn_pnp_cb_t callback. Valid for IB_PNP_IOC_ADD +* events only. +* +* pnp_context +* User-defined context information specified when registering for +* notification of the event. See the notes section below for +* more details. +* +* context +* This field references a user-specified context on which the event +* occurred. See the notes section below for more details. +* +* guid +* The GUID of the adapter, port, IOU, or IOC for which +* the PnP event occurred. +* +* ca_guid +* The GUID of the HCA +* +* NOTES +* This structure is returned to the user to notify them of: the addition +* of a channel adapter, the removal of a channel adapter, a port up or down +* event, a port pkey change, and I/O controller addition and removal events. +* +* The context field is NULL unless a context value has already been set +* by the user. +* +* The context value can be changed by updating its field +* and will take effect once the notification callback returns. +* +* Once a device has been removed, all context associated with that device +* is lost. Context is maintained between port down and subsequent port up +* events provided that the channel adapter is not removed. +* +* I/O controller path notifications are only delivered with respect to a +* previously reported I/O controller. +* +* SEE ALSO +* ib_open_al, ib_ca_attr_t, ib_reg_pnp, ib_dereg_pnp, ib_pfn_pnp_cb_t, +* ib_ioc_info_t, ib_reject_ioc, ib_pnp_event_t +*****/ + + +/****s* Access Layer/ib_pnp_ca_rec_t +* NAME +* ib_pnp_ca_rec_t +* +* DESCRIPTION +* Notification information used to describe local channel adapter events. +* +* SYNOPSIS +*/ +typedef struct _ib_pnp_ca_rec +{ + ib_pnp_rec_t pnp_rec; + TO_LONG_PTR(ib_ca_attr_t*, p_ca_attr); + +} ib_pnp_ca_rec_t; +/* +* FIELDS +* pnp_rec +* Structure describing the plug and play event being reported. +* +* p_ca_attr +* Attributes of the channel adapter that has experienced the event. +* NULL for IB_PNP_CA_REMOVE, IB_PNP_PORT_REMOVE, and IB_PNP_IOC_REMOVE +* events. +* +* NOTES +* This structure is returned to the user to notify them of the addition +* or the removal of a channel adapter. +* +* The context field is NULL unless a context value has already been set +* by the user. +* +* Context values can be changed by updating the appropriate field +* and will be take effect once the notification callback returns. +* +* Once a device has been removed, all context associated with that device +* is lost. +* +* Recipients of CA-related PnP events should cast the ib_pnp_rec_t structure +* returned in the PnP callback to this type to access CA-specific information. +* +* SEE ALSO +* ib_open_al, ib_ca_attr_t, ib_reg_pnp, ib_dereg_pnp, ib_pfn_pnp_cb_t, +* ib_ioc_info_t, ib_reject_ioc, ib_pnp_event_t +*****/ + + +/****s* Access Layer/ib_pnp_port_rec_t +* NAME +* ib_pnp_port_rec_t +* +* DESCRIPTION +* Notification information used to describe local port events. +* +* SYNOPSIS +*/ +typedef struct _ib_pnp_port_rec +{ + ib_pnp_rec_t pnp_rec; + TO_LONG_PTR(ib_ca_attr_t*, p_ca_attr); + TO_LONG_PTR(ib_port_attr_t*,p_port_attr); + +} ib_pnp_port_rec_t; +/* +* FIELDS +* pnp_rec +* Structure describing the plug and play event being reported. +* +* p_ca_attr +* Attributes of the channel adapter that has experienced the event. +* NULL for IB_PNP_CA_REMOVE, IB_PNP_PORT_REMOVE, and IB_PNP_IOC_REMOVE +* events. +* +* p_port_attr +* Attributes of the port that has experienced the event. Valid only +* for IB_PNP_PORT_UP, IB_PNP_PORT_DOWN, IB_PNP_PKEY_CHANGE, and +* IB_PNP_IOC_ADD events. +* +* NOTES +* This structure is returned to the user to notify them of port events. +* +* The context field is NULL unless a context value has already been set +* by the user. +* +* Context values can be changed by updating the appropriate field +* and will be take effect once the notification callback returns. +* +* Once a device has been removed, all context associated with that device +* is lost. Context is maintained between port down and subsequent port up +* events provided that the channel adapter is not removed. +* +* Recipients of port related PnP events should cast the ib_pnp_rec_t structure +* returned in the PnP callback to this type to access port specific information. +* +* SEE ALSO +* ib_open_al, ib_ca_attr_t, ib_reg_pnp, ib_dereg_pnp, ib_pfn_pnp_cb_t, +* ib_ioc_info_t, ib_reject_ioc, ib_pnp_event_t +*****/ + + +/****s* Access Layer/ib_pnp_iou_rec_t +* NAME +* ib_pnp_iou_rec_t +* +* DESCRIPTION +* Notification information used to describe local I/O unit events. +* +* SYNOPSIS +*/ +typedef struct _ib_pnp_iou_rec +{ + ib_pnp_rec_t pnp_rec; + net64_t guid; + net64_t ca_guid; + net64_t chassis_guid; + uint8_t slot; + net32_t vend_id; + net16_t dev_id; + net32_t revision; + char desc[IB_NODE_DESCRIPTION_SIZE + 1]; + +} ib_pnp_iou_rec_t; +/* +* FIELDS +* pnp_rec +* Structure describing the plug and play event being reported. +* +* ca_guid +* GUID of the local HCA through which the I/O unit is accessible. Valid +* only for IB_PNP_IOU_ADD events. +* +* chassis guid +* GUID of the chassis in which an I/O unit is installed. Valid only for +* IB_PNP_IOU_ADD events. +* +* slot +* Chassis slot number in which an I/O unit is installed. Valid only for +* IB_PNP_IOU_ADD events. +* +* guid +* GUID of an I/O unit from which one or more I/O controllers are assigned +* to this host. Valid only for IB_PNP_IOU_ADD events. +* +* vend_id +* Vendor ID of an I/O unit from which one or more I/O controllers are +* assigned to this host. Valid only for IB_PNP_IOU_ADD events. +* +* dev_id +* Device ID of an I/O unit from which one or more I/O controllers are +* assigned to this host. Valid only for IB_PNP_IOU_ADD events. +* +* revision +* Revision of an I/O unit from which one or more I/O controllers are +* assigned to this host. Valid only for IB_PNP_IOU_ADD events. +* +* desc +* Node description string for an I/O unit from which one or more I/O +* controllers are assigned to this host. Valid only for IB_PNP_IOU_ADD +* events. +* +* NOTES +* This structure is returned to the user to notify them of the addition +* and removal of an I/O Unit. +* +* The context field is NULL unless a context value has already been set +* by the user. +* +* Context values can be changed by updating the appropriate field +* and will be take effect once the notification callback returns. +* +* Once a device has been removed, all context associated with that device +* is lost. Context is maintained between port down and subsequent port up +* events provided that the channel adapter is not removed. +* +* SEE ALSO +* ib_open_al, ib_ca_attr_t, ib_reg_pnp, ib_dereg_pnp, ib_pfn_pnp_cb_t, +* ib_ioc_info_t, ib_reject_ioc, ib_pnp_event_t +*****/ + + +/****s* Access Layer/ib_pnp_ioc_rec_t +* NAME +* ib_pnp_ioc_rec_t +* +* DESCRIPTION +* Notification information used to describe local channel adapter, port, +* and I/O controller events. +* +* SYNOPSIS +*/ +typedef struct _ib_pnp_ioc_rec +{ + ib_pnp_rec_t pnp_rec; + net64_t ca_guid; + ib_ioc_info_t info; + ib_svc_entry_t svc_entry_array[1]; + +} ib_pnp_ioc_rec_t; +/* +* FIELDS +* pnp_rec +* Structure describing the plug and play event being reported. +* +* ca_guid +* GUID of the local HCA through which the I/O controller is accessible. +* Valid only for IB_PNP_IOC_ADD events. +* +* p_ioc_info +* The I/O controller information for an assigned controller, including +* information for the I/O unit. Valid only for IB_PNP_IOC_ADD events. +* +* svc_entry_array +* If an I/O controller is being reported, this will reference an array +* of service entries associated with the I/O controller. The actual +* number of entries in the array may be determined by examining the +* svc_entries field in the I/O controller profile. Valid only for +* IB_PNP_IOC_ADD events. +* +* NOTES +* This structure is returned to the user to notify them of the addition +* and removal of an I/O controller. +* +* The context field is NULL unless a context value has already been set +* by the user. +* +* Context values can be changed by updating the appropriate field +* and will be take effect once the notification callback returns. +* +* Once a device has been removed, all context associated with that device +* is lost. Context is maintained between port down and subsequent port up +* events provided that the channel adapter is not removed. +* +* SEE ALSO +* ib_open_al, ib_ca_attr_t, ib_reg_pnp, ib_dereg_pnp, ib_pfn_pnp_cb_t, +* ib_ioc_info_t, ib_reject_ioc, ib_pnp_event_t +*****/ + + +/****s* Access Layer/ib_pnp_ioc_path_rec_t +* NAME +* ib_pnp_ioc_path_rec_t +* +* DESCRIPTION +* Notification information used to describe local channel adapter, port, +* and I/O controller events. +* +* SYNOPSIS +*/ +typedef struct _ib_pnp_ioc_path_rec +{ + ib_pnp_rec_t pnp_rec; + net64_t ca_guid; + net64_t port_guid; + ib_path_rec_t path; + +} ib_pnp_ioc_path_rec_t; +/* +* FIELDS +* pnp_rec +* Structure describing the plug and play event being reported. +* +* ca_guid +* GUID of the local HCA through which the I/O controller is accessible. +* Valid only for IB_PNP_IOC_PATH_ADD and IB_PNP_IOC_PATH_REMOVE events. +* +* port_guid +* GUID of the local HCA port through which the I/O controller is +* accessible. Valid only for IB_PNP_IOC_PATH_ADD and +* IB_PNP_IOC_PATH_REMOVE events. +* +* p_path +* Path record that provides connectivity with a given I/O controller. +* Valid only for IB_PNP_IOC_PATH_ADD and IB_PNP_IOC_PATH_REMOVE events. +* +* NOTES +* This structure is returned to the user to notify them of the addition +* and removal of a path to an I/O controller. I/O controller path +* notifications are only delivered with respect to a previously reported +* I/O controller. +* +* The context field is NULL unless a context value has already been set +* by the user. +* +* Context values can be changed by updating the appropriate field +* and will be take effect once the notification callback returns. +* +* Once a device has been removed, all context associated with that device +* is lost. Context is maintained between port down and subsequent port up +* events provided that the channel adapter is not removed. +* +* SEE ALSO +* ib_open_al, ib_ca_attr_t, ib_reg_pnp, ib_dereg_pnp, ib_pfn_pnp_cb_t, +* ib_ioc_info_t, ib_reject_ioc, ib_pnp_event_t +*****/ + + +/****f* Access Layer/ib_pfn_pnp_cb_t +* NAME +* ib_pfn_pnp_cb_t +* +* DESCRIPTION +* User-defined callback that is invoked to notify a client of the addition +* or removal of a channel adapter, a port up or down event, port changes, +* and the assignment of an I/O controller to a local port. +* +* SYNOPSIS +*/ +typedef ib_api_status_t +(AL_API *ib_pfn_pnp_cb_t)( + IN ib_pnp_rec_t *p_pnp_rec ); +/* +* PARAMETERS +* p_pnp_rec +* [in] A reference to a plug and play record. The plug and play +* record contains details about the type of local event that has +* occurred, along with the relevant device information. +* +* RETURN VALUES +* IB_SUCCESS +* Indicates to the PnP manager that the callback client requires it +* to maintain a context for this event. +* +* Other +* Indicates to the PnP manager that the callback client does not need +* a context for this event. +* +* NOTES +* The callback is used to notify users of local events that have occurred +* on a given channel adapter. Information about the type of event that +* occurred along with the associated device is returned to the user through +* the p_pnp_rec parameter. +* +* Users register for plug and play changes by requesting notification from +* the access layer. Users may register for notifications either by directly +* invoking the appropriate function in the access layer, or indirectly by +* adding the necessary registration data to the access layer device file. +* +* This callback is invoked from within a system thread context. +* +* If the callback returns a status other than IB_SUCCESS, no further +* callback for related events will be delivered. +* +* SEE ALSO +* ib_pnp_rec_t, ib_reg_pnp, ib_dereg_pnp, ib_reject_ioc +*****/ + + +/****s* Access Layer/ib_pnp_req_t +* NAME +* ib_pnp_req_t +* +* DESCRIPTION +* Information used to register for notification of local and I/O +* controller assignment events. +* +* SYNOPSIS +*/ +typedef struct _ib_pnp_req +{ + ib_pnp_class_t pnp_class; + const void *pnp_context; + ib_pfn_pnp_cb_t pfn_pnp_cb; + +} ib_pnp_req_t; +/* +* FIELDS +* pnp_class +* Specifies the class of PnP events that the client wishes to be +* notified of. +* +* pnp_context +* User-defined context information associated with this notification. +* The context data is returned to the user as a part of their PnP +* notification callback. +* +* pfn_pnp_cb +* User-defined callback function that is invoked to notify the user of +* the occurrance of a plug and play event. +* +* NOTES +* This structure is used when requesting notification of local events from +* the access layer. The class of PnP events which to be notified of is +* specified through the pnp_class field. +* +* SEE ALSO +* ib_pnp_class_t, ib_pfn_pnp_cb_t, ib_reg_pnp, ib_pnp_rec_t +*****/ + + +/****f* Access Layer/ib_reg_pnp +* NAME +* ib_reg_pnp +* +* DESCRIPTION +* Routine used to register for notification of local and I/O controller +* assignment events. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_reg_pnp( + IN const ib_al_handle_t h_al, + IN const ib_pnp_req_t* const p_pnp_req, + OUT ib_pnp_handle_t* const ph_pnp ); +/* +* PARAMETERS +* h_al +* [in] A handle to an open instance of the access layer. +* +* p_pnp_req +* [in] Specifies the type of events that the user wishes to be notified +* of, along with information needed to process the completed query. +* +* ph_pnp +* [out] Upon successful completion of this call, this references a handle +* to the PnP notification request. This handle may be used to cancel the +* notification registration. +* +* RETURN VALUES +* IB_SUCCESS +* The PnP registration was successful. +* +* IB_INVALID_AL_HANDLE +* The access layer handle was invalid. +* +* IB_INVALID_PARAMETER +* A reference to the PnP request information or handle was not provided. +* +* IB_INSUFFICIENT_MEMORY +* There was insufficient memory to register for PnP notification. +* +* NOTES +* This routine registers the calling client with the access layer for +* notification of locally occurring events, or the assignment of I/O +* controllers to a local device. Once registered, a client will receive +* notification, via a callback, that a given event has occurred on a +* local device. Clients may restrict the types of events and devices +* that are reported. The p_pnp_req parameter is used to indicate which +* device events to report to the user. +* +* Upon invoking this routine, the client may receive a callback through +* the ib_pfn_pnp_cb_t routine to notify them of the current system state. +* For example, if a client registers for notification of port up events, +* then the access layer will notify the client of all available ports when +* this routine is first invoked. +* +* SEE ALSO +* ib_dereg_pnp, ib_pnp_req_t, ib_pnp_rec_t, ib_pfn_pnp_cb_t +*****/ + + +/****f* Access Layer/ib_dereg_pnp +* NAME +* ib_dereg_pnp +* +* DESCRIPTION +* Routine used to cancel notification of local events or I/O controller +* assignments. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_dereg_pnp( + IN const ib_pnp_handle_t h_pnp, + IN const ib_pfn_destroy_cb_t pfn_destroy_cb OPTIONAL ); +/* +* PARAMETERS +* h_pnp +* [in] A handle returned as a result of an ib_reg_pnp operation. +* +* pfn_destroy_cb +* [in] A user-specified callback that is invoked after the PnP +* registration has been successfully deregistered. +* +* NOTES +* This routine cancels a pending PnP operation. To avoid a race condition +* canceling a request at the same time a notification callback is in +* progress, the cancel operation operates asynchronously. For additional +* details see ib_pfn_destroy_cb_t. +* +* RETURN VALUES +* IB_SUCCESS +* The PnP deregistration was initiated. +* +* IB_INVALID_HANDLE +* The PnP handle was invalid. +* +* SEE ALSO +* ib_reg_pnp, ib_pfn_destroy_cb_t +*****/ + + +/****s* Access Layer/ib_sub_rec_t +* NAME +* ib_sub_rec_t +* +* DESCRIPTION +* Information returned to a user that indicates the result of a subscription +* request. +* +* SYNOPSIS +*/ +typedef struct _ib_sub_rec +{ + const void* sub_context; + ib_api_status_t status; + ib_sub_handle_t h_sub; + +} ib_sub_rec_t; +/* +* FIELDS +* sub_context +* References user-defined context information associated with the +* subscription request. This field is set by the user through the +* ib_subscribe routine. +* +* status +* Indicates the success of the subscription request. +* +* h_sub +* The handle to the subscription request that was returned to the user +* from the ib_subscribe call. This handle is provided to the user to +* avoid a race condition between the return of the ib_subscribe routine +* and the notification of an event. +* +* NOTES +* This structure is returned to the user to notify them of the results +* of a subscription request. After successfully subscribing with a +* class manager for an event, this structure will be returned to the user +* with the status set to IB_SUCCESS. The sub_context field will be set +* to the context specified through the p_sub_req parameter in the +* ib_subscribe routine. +* +* SEE ALSO +* ib_subscribe +*****/ + + +/****f* Access Layer/ib_pfn_sub_cb_t +* NAME +* ib_pfn_sub_cb_t +* +* DESCRIPTION +* User-defined callback invoked on completion of a subscription request. +* +* SYNOPSIS +*/ +typedef void +(AL_API *ib_pfn_sub_cb_t)( + IN ib_sub_rec_t *p_sub_rec ); +/* +* PARAMETERS +* p_sub_rec +* [in] This is a reference to a structure containing the result of the +* subscription request. +* +* NOTES +* This routine is invoked to notify a client of the result of a +* subscription request with a class manager. If the subscription request +* was successful, the client will receive future notifications of the +* subscribed event from the class manager. +* +* This callback will always be invoked before a client receives information +* reported on a subscribed event that has occurred. +* +* In the kernel, this callback is usually invoked using a tasklet, dependent +* on the implementation of the underlying verbs provider driver. +* +* SEE ALSO +* ib_subscribe, ib_sub_rec_t +*****/ + + +/****s* Access Layer/ib_report_rec_t +* NAME +* ib_report_rec_t +* +* DESCRIPTION +* Reported event information returned to the user when a subscribed for +* event occurs. +* +* SYNOPSIS +*/ +typedef struct _ib_report_rec +{ + const void* report_context; + ib_mad_notice_attr_t* p_notice; + +} ib_report_rec_t; +/* +* FIELDS +* report_context +* Client-defined context information specified when registering for +* the report. +* +* p_notice +* Reported information that describes the event that has occurred. +* +* NOTES +* Subscription for reported events is done through a class manager. When +* a class manager detects that such an event occurs, it will generate a +* report to the subscribed client. The reported information is referenced +* through the p_notice field. +* +* SEE ALSO +* ib_mad_notice_attr_t +*****/ + + +/****f* Access Layer/ib_pfn_report_cb_t +* NAME +* ib_pfn_report_cb_t +* +* DESCRIPTION +* User-defined callback that is invoked to notify a client of an event +* that has occurred on the fabric. +* +* SYNOPSIS +*/ +typedef void +(AL_API *ib_pfn_report_cb_t)( + IN ib_report_rec_t *p_report_rec ); +/* +* PARAMETERS +* p_report_rec +* [in] A reference to an event report. The report contains +* details about the type of event that has occurred, along with the +* relevant device information. +* +* NOTES +* The callback is used to notify users of remote events that have been seen +* by a specified class manager. Information about the type of event that +* occurred along with the associated device is returned to the user through +* the p_report_rec parameter. +* +* Users register for device changes by subscribing with a class manager. +* Users may subscribe for events either by directly invoking the +* appropriate function in the access layer, or indirectly by adding the +* necessary registration data to the access layer device file. +* +* This callback is invoked from within a system thread context. +* +* SEE ALSO +* ib_report_rec_t, ib_subscribe, ib_unsubscribe +*****/ + + +/****s* Access Layer/ib_sub_req_t +* NAME +* ib_sub_req_t +* +* DESCRIPTION +* Information used to subscribed for event notification from a class +* manager. +* +* SYNOPSIS +*/ +typedef struct _ib_sub_req +{ + ib_svc_name_t* p_class_mgr_name; + ib_inform_info_t* p_inform_info; + ib_net64_t port_guid; + + uint32_t timeout_ms; + uint32_t retry_cnt; + ib_al_flags_t flags; + + const void* sub_context; + ib_pfn_sub_cb_t pfn_sub_cb; + + const void* report_context; + ib_pfn_report_cb_t pfn_report_cb; + +} ib_sub_req_t; +/* +* FIELDS +* p_class_mgr_name +* The service name of the class manager to subscribe for events with. +* +* p_inform_info +* Information describing the type of event being subscribed to. +* +* port_guid +* Directs the subscription request to use the specified port. The +* request will contact the subnet administrator reachable through the +* given port. +* +* timeout_ms +* Specifies the number of milliseconds to wait for a response for +* this subscription 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. +* +* sub_context +* User-defined context information associated with this subscription +* request. This context is returned to the user through the function +* specified by the pfn_sub_cb field. +* +* pfn_sub_cb +* A user-defined callback that is invoked upon completion of the +* subscription request. This is used to notify a client that of the +* result of their subscription request. +* +* report_context +* User-defined context information associated with this subscription. +* This context is returned to the user through the client's +* ib_pfn_report_cb_t callback routine specified in ib_open_al. +* +* pfn_report_cb +* A user-defined callback that is invoked to notify the user that an +* event report has been received. +* +* NOTES +* This structure is used to subscribe for events with a class manager. Both +* the subscription request and any corresponding event notifications operate +* asynchronously. Clients will be notified of the result of their +* subscription request before receiving notification of associated events. +* +* SEE ALSO +* ib_subscribe, ib_svc_name_t, ib_inform_info_t, ib_pfn_sub_cb_t, +* ib_pfn_report_cb_t, ib_open_al +*****/ + + +/****f* Access Layer/ib_subscribe +* NAME +* ib_subscribe +* +* DESCRIPTION +* Subscribe with a class manager for event notification. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_subscribe( + IN const ib_al_handle_t h_al, + IN const ib_sub_req_t* const p_sub_req, + OUT ib_sub_handle_t* const ph_sub ); +/* +* PARAMETERS +* h_al +* [in] A handle to an open instance of the access layer. +* +* p_sub_req +* [in] Specifies the type of events that the user wishes to be +* notified of, along with information needed to process the completed +* subscription. +* +* ph_sub +* [out] Upon successful completion of this call, this references a handle +* to the subscription request. This handle may be used to unsubscribe +* from the events. +* +* RETURN VALUES +* IB_SUCCESS +* The subscription request was initiated. +* +* IB_INVALID_AL_HANDLE +* The access layer handle was invalid. +* +* IB_INVALID_PARAMETER +* A reference to the subscription request or handle was not provided. +* +* IB_INSUFFICIENT_MEMORY +* There was insufficient memory to perform the operation. +* +* IB_INVALID_GUID +* No port was found for the port_guid specified in the request. +* +* IB_INSUFFICIENT_RESOURCES +* There were insufficient resources currently available on the channel +* adapter to perform the operation. +* +* NOTES +* This routine registers the calling client with a class manager for +* notification of events. Once registered, a client will receive +* notification, via a callback, that a given event has occurred on +* a device managed by the class manager. +* +* SEE ALSO +* ib_unsubscribe, ib_sub_req_t, ib_pfn_sub_cb_t, ib_pfn_report_cb_t +*****/ + + +/****f* Access Layer/ib_unsubscribe +* NAME +* ib_unsubscribe +* +* DESCRIPTION +* Unsubscribe with a class manager for event notification. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_unsubscribe( + IN const ib_sub_handle_t h_sub, + IN const ib_pfn_destroy_cb_t pfn_destroy_cb OPTIONAL ); +/* +* PARAMETERS +* h_al +* [in] A handle to an open instance of the access layer. +* +* h_sub +* [in] A handle to a subscribed event. +* +* pfn_destroy_cb +* [in] A user-specified callback that is invoked after the subscription +* request has been successfully canceled. +* +* RETURN VALUES +* IB_SUCCESS +* The unsubscribe request was initiated. +* +* IB_INVALID_HANDLE +* The subscription handle was invalid. +* +* IB_INVALID_PARAMETER +* A reference to the subscription request or handle was not provided. +* +* IB_INSUFFICIENT_MEMORY +* There was insufficient memory to perform the operation. +* +* IB_INSUFFICIENT_RESOURCES +* There were insufficient resources currently available on the channel +* adapter to perform the operation. +* +* NOTES +* This routine cancels an active or pending event subscription with a class +* manager. To avoid a race condition canceling a subscription at the same +* time an event notification callback is in progress, the unsubscribe +* operation operates asynchronously. For additional details see +* ib_pfn_destroy_cb_t. +* +* SEE ALSO +* ib_subscribe, ib_pfn_destroy_cb_t +*****/ + + +/****f* Access Layer/ib_reject_ioc +* NAME +* ib_reject_ioc +* +* DESCRIPTION +* Rejects an I/O controller assignment to a host. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_reject_ioc( + IN const ib_al_handle_t h_al, + IN const ib_pnp_handle_t h_ioc_event ); +/* +* PARAMETERS +* h_al +* [in] A handle to an open instance of the access layer. +* +* h_ioc_event +* [in] A handle provided as part of the notification of an I/O controller +* being assigned. This handle is obtained through the ib_pnp_rec_t +* structure given to a client through their ib_pfn_pnp_cb_t callback. +* +* RETURN VALUES +* IB_SUCCESS +* The I/O controller reject request was initiated. +* +* IB_INVALID_AL_HANDLE +* The access layer handle was invalid. +* +* IB_INVALID_HANDLE +* The I/O controller handle was invalid. +* +* IB_INSUFFICIENT_MEMORY +* There was insufficient memory to perform the operation. +* +* IB_INSUFFICIENT_RESOURCES +* There were insufficient resources currently available on the channel +* adapter to perform the operation. +* +* NOTES +* This routine rejects an I/O controller assigned by the configuration +* manager to the local host. The access layer sends a rejection notification +* to the configuration manager and disable access to the controller from +* the local host. This routine must be called from a client's +* ib_pfn_pnp_cb_t callback to reject a newly assigned I/O controller. +* +* SEE ALSO +* ib_pfn_pnp_cb_t, ib_pnp_rec_t +*****/ + + +#define IB_ANY_INDEX -1 +/****d* Access Layer/ib_device_attr_mask_t +* NAME +* ib_device_attr_mask_t +* +* DESCRIPTION +* Used to specify desired attributes of a device or port. +* +* SYNOPSIS +*/ +#define IB_DEV_PORT_ACTIVE 0x1 +/* +* VALUES +* IB_DEV_PORT_ACTIVE +* Specifies that a port state should be active. Applies only to port +* GUIDs. +* +* SEE ALSO +* ib_get_guid +*****/ + + +/****f* Access Layer/ib_get_guid +* NAME +* ib_get_guid +* +* DESCRIPTION +* Returns a GUID for a device or port that matches the user-specified +* attributes. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_get_guid( + IN ib_al_handle_t h_al, + IN const uint32_t index, + IN const ib_pnp_class_t device_type, + IN const uint64_t attr_mask, + OUT ib_net64_t* const p_guid ); +/* +* PARAMETERS +* h_al +* [in] A handle to an opened instance of the access layer. +* +* index +* [in] Specifies the location of the device or port. Users specify this +* value to iterate through all devices or ports on the system. If set +* to IB_ANY_INDEX, then the first device or port matching the given +* attributes will be returned. +* +* device_type +* [in] Indicates the type of device to retrieve the GUID for. +* +* attr_mask +* [in] Specifies a set of attributes that the given device or port +* must have for a successful match to occur. +* +* p_guid +* [out] On successful return, this parameter will reference the GUID +* of the device or port that contains the specified attributes. +* +* RETURN VALUES +* IB_SUCCESS +* The operation was successful. +* +* IB_INVALID_AL_HANDLE +* The access layer handle was invalid. +* +* IB_INVALID_SETTING +* The specified device type is invalid. +* +* IB_INVALID_PARAMETER +* No p_guid parameter was specified. +* +* IB_NO_MATCH +* The device or port at the specified index does not have the given +* attributes. +* +* IB_INVALID_INDEX +* No device or port exists for the specified index. +* +* NOTES +* This routine returns a GUID for a device or port that matches the +* user-specified attributes. If index is IB_ANY_INDEX, then the first +* device or port matching the given attributes is returned if a match is +* found. If no match is found, the call will return IB_NO_MATCH. If a +* valid index is specified, then the device or port located at that index +* will be examined to see if it has the given attributes. If the device +* or port with those attributes is found, its GUID is returned. +* +* This routine may be used to locate a device or port with a given set +* of attributes, or iterate through all devices or ports on the system. +* The specified index values are set by the access layer, but the index +* associated with a GUID may change if devices are removed from the system. +* +* SEE ALSO +* ib_open_al, ib_pnp_class_t, ib_get_ca_guids, ib_query_ca_by_guid +*****/ + + +/****f* Access Layer/ib_ci_call +* NAME +* ib_ci_call +* +* DESCRIPTION +* Performs a vendor specific CA interface function call. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_ci_call( + IN ib_ca_handle_t h_ca, + IN const void** const handle_array OPTIONAL, + IN uint32_t num_handles, + IN ib_ci_op_t* const p_ci_op ); +/* +* PARAMETERS +* h_ca +* [in] An opened instance of a channel adapter. +* +* handle_array +* [in] This parameter references an array containing handles of +* existing CA resources. This array should contain all of the +* handles specified in the vendor specific data provided with this +* call. All handles specified through this array are validated by +* the access layer as existing and belonging to the calling process. +* The verbs provider driver is responsible for verifying that the +* number and type of handles are correct for the requested operation. +* +* num_handles +* [in] The number of the handles in handle array. This count is +* verified by the access layer. +* +* p_ci_op +* [in] A reference to the vendor specific CA interface data +* structure containing the operation parameters. +* +* RETURN VALUES +* IB_SUCCESS +* The operation was successful. +* +* IB_INVALID_CA_HANDLE +* The specified CA handle was invalid. +* +* IB_INVALID_PARAMETER +* A reference to the vendor specific data was not provided. +* +* IB_INVALID_HANDLE +* A handle specified in the handle array was invalid. +* +* IB_INSUFFICIENT_MEMORY +* There was insufficient memory to perform the operation. +* +* IB_ERROR +* An error occurred while processing the command. Additional +* error information is provided in the p_ci_op status field. +* +* NOTES +* This routine performs a vendor specific CA interface function call. +* The optional p_ci_op structure provides a means to pass vendor +* specific parameters and data to the verbs provider driver. If the +* vendor specific data contains handles, the client should provide the +* optional handle array that lists all of the handles specified in the +* vendor specific data. The handles in the handle array are restricted +* to the following types: ib_pd_handle_t, ib_cq_handle_t, +* ib_av_handle_t, ib_qp_handle_t, ib_mr_handle_t, or ib_mw_handle_t. +* The contents of the handle array are verified by the access layer and +* the verbs provider driver. This call cannot be used to allocate private +* handles that are passed as parameters in access layer calls. +* +* SEE ALSO +* ib_open_ca, ib_alloc_pd, ib_create_av, ib_create_cq, +* ib_create_qp, ib_reg_mr, ib_reg_phys, ib_reg_shared, +* ib_create_mw, ib_ci_op_t +*****/ + + +/****f* Access Layer/ib_open_al +* NAME +* ib_open_al +* +* DESCRIPTION +* This routine opens an instance of the access layer for the user and +* returns its handle. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_open_al( + OUT ib_al_handle_t* const ph_al ); +/* +* PARAMETERS +* ph_al +* [in] Upon successful completion of this call, this parameter will +* reference a handle to the access layer. +* +* RETURN VALUES +* IB_SUCCESS +* The access layer was opened successfully. +* +* IB_INVALID_PARAMETER +* A reference to the access layer handle was not provided. +* +* IB_INSUFFICIENT_MEMORY +* There was insufficient memory to perform the operation. +* +* NOTES +* This function opens an instance of the access layer. An instance of the +* access layer is required before allocating additional resources from the +* access layer or a channel adapter. If successful, a handle to the access +* layer is returned. User-mode clients should not call ib_open_al from the +* module initialization routine. +* +* SEE ALSO +* ib_close_al +*****/ + + +/****f* Access Layer/ib_close_al +* NAME +* ib_close_al +* +* DESCRIPTION +* Deregisters a channel driver with the access layer and releases all +* associated resources, including queue pairs, connection requests, +* and completion queues. +* +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t AL_API +ib_close_al( + IN const ib_al_handle_t h_al ); +/* +* PARAMETERS +* h_al +* [in] A handle to an instance of the access layer. +* +* RETURN VALUES +* IB_SUCCESS +* The access layer was closed successfully. +* +* IB_INVALID_AL_HANDLE +* The access layer handle was invalid. +* +* NOTES +* This call destroys an existing instance of the access layer. Since +* callbacks may be outstanding against the resources managed by this +* access layer instance when the destroy operation is invoked, this +* call may block until all outstanding callbacks complete. This +* routine may not be called from a callback invoked by the access layer. +* +* SEE ALSO +* ib_open_al +*****/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + + +#endif /* __IB_AL_H__ */ diff --git a/branches/WOF2-3/inc/iba/ib_al_ioctl.h b/branches/WOF2-3/inc/iba/ib_al_ioctl.h new file mode 100644 index 00000000..f37f8f64 --- /dev/null +++ b/branches/WOF2-3/inc/iba/ib_al_ioctl.h @@ -0,0 +1,3636 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + +#ifndef __IB_UAL_IOCTL_H__ +#define __IB_UAL_IOCTL_H__ + +#include +#include +#include +#include + + +/* +* Typedefs +* +*/ +/* +* ual_close_ca_ioctl: +* NOTES: +* It is sufficient to pass the ca handle to the kernel proxy on close_ca +* The UAL context for this CA instance maintains the application callback +* So, when the proxy notifies for a close_ca_callback, we know which +* app callback to call +* +*/ + + +/****s* User-mode Access Layer/ual_bind_file_ioctl_t +* NAME +* ual_bind_file_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* binding a file handle to an existing proxy context. +* +* SYNOPSIS +*/ +typedef struct _ual_bind_file_ioctl +{ + void* __ptr64 h_file; /* __ptr64 is correct for HANDLE types. */ + +} ual_bind_file_ioctl_t; +/* +* FIELDS +* h_file +* File handle from the user-mode process intended for asynchronous requests. +* The IOCTL code will specify the type of asynchronous requests to be +* performed on this file handle. +* +* SEE ALSO +* +* NOTES +*****/ + + +/****s* User-mode Access Layer/ual_get_uvp_name_t +* NAME +* ual_get_uvp_name_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* getting the user library information. +* +* SYNOPSIS +*/ +typedef union _ual_get_uvp_name +{ + struct _ual_get_uvp_name_in + { + ib_net64_t ca_guid; + + } in; + struct _ual_get_uvp_name_out + { + ib_api_status_t status; + char uvp_lib_name[MAX_LIB_NAME]; + + } out; + +} ual_get_uvp_name_ioctl_t; +/* +* FIELDS +* in.ca_guid +* The GUID of the channel adapter +* +* out.status +* Status of the operation +* +* out.uvp_lib_name +* The vendor's library name associated with the CA +* +* SEE ALSO +* +* +* NOTES +*****/ + + + +/****s* User-mode Access Layer/ual_open_ca_ioctl_t +* NAME +* ual_open_ca_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* ib_open_ca +* +* SYNOPSIS +*/ +typedef union _ual_open_ca_ioctl +{ + struct _ual_open_ca_ioctl_in + { + ci_umv_buf_t umv_buf; + ib_net64_t guid; + uint64_t context; + + } in; + + struct _ual_open_ca_ioctl_out + { + ci_umv_buf_t umv_buf; + ib_api_status_t status; + uint64_t h_ca; + + } out; + +} ual_open_ca_ioctl_t; +/* +* FIELDS +* in.umv_buf +* Opaque to IBAL buffer descriptor to allow the user-mode HCA library to +* exchange private information with the kernel-mode HCA driver. +* +* in.guid +* The GUID of the channel adapter to open. +* +* in.context +* A caller-specified context to associate with this opened instance +* of the channel adapter. This context is returned to the user when +* invoking asynchronous callbacks referencing this channel adapter. +* +* out.umv_buf +* Returns the status from the HCA driver to the user-mode HCA library, +* along with any vendor specific output information. +* +* out.status +* Status of the operation +* +* out.h_ca +* On return from IOCTL, contains the CA Handle from AL. +*****/ + + + +/****s* User-mode Access Layer/ual_query_ca_ioctl_t +* NAME +* ual_query_ca_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* ib_query_ca +* +* SYNOPSIS +*/ +typedef union _ual_query_ca_ioctl +{ + struct _ual_query_ca_ioctl_in + { + ci_umv_buf_t umv_buf; + uint64_t h_ca; + uint32_t byte_cnt; + uint64_t p_ca_attr; + + } in; + struct _ual_query_ca_ioctl_out + { + ci_umv_buf_t umv_buf; + ib_api_status_t status; + uint32_t byte_cnt; + + } out; + +} ual_query_ca_ioctl_t; +/* +* FIELDS +* in.umv_buf +* Opaque to IBAL buffer descriptor to allow the user-mode HCA library to +* exchange private information with the kernel-mode HCA driver. +* +* in.h_ca +* The handle to an open instance of CA returned via a +* ual_open_ca_ioctl structure. +* +* in.byte_cnt +* Specifies the size of the data buffer referenced by the p_ca_attr +* parameter. +* +* p_ca_attr +* A reference to a buffer where the channel adapter attributes, +* including port attribute information will be copied. If this parameter +* is NULL, then the required buffer size needed to return all of the CA +* attribute information is returned through the out.byte_cnt parameter. +* The ib_ca_attr_t structure for the specified channel adapter is stored +* at the top of this buffer. +* +* out.umv_buf +* Returns the status from the HCA driver to the user-mode HCA library, +* along with any vendor specific output information. +* +* out.status +* Status of the operation +* +* out.byte_cnt +* Contains the number of bytes used or needed to copy all CA attributes. +*****/ + + + +/****s* User-mode Access Layer/ual_modify_ca_ioctl_t +* NAME +* ual_modify_ca_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* ib_modify_ca +* +* SYNOPSIS +*/ +typedef union _ual_modify_ca_ioctl +{ + struct _ual_modify_ca_ioctl_in + { + uint64_t h_ca; + uint8_t port_num; + ib_ca_mod_t ca_mod; + ib_port_attr_mod_t port_attr_mod; + + } in; + struct _ual_modify_ca_ioclt_out + { + ib_api_status_t status; + + } out; + + +} ual_modify_ca_ioctl_t; +/* +* FIELDS +* in.h_ca +* The handle to an open instance of CA (in KAL space). +* +* in.port_num +* An index of the port that is being modified. +* +* in.ca_mod +* The mask of the attributes and counters to modify. +* +* in.port_attr_mod +* List of port attribute information to modify. +* +* out.status +* Status of the operation +*****/ + + + +/****s* User-mode Access Layer/ual_close_ca_ioctl_t +* NAME +* ual_close_ca_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* ib_close_ca +* +* SYNOPSIS +*/ +typedef union _ual_close_ca_ioctl +{ + struct _ual_close_ca_ioctl_in + { + uint64_t h_ca; + + } in; + struct _ual_close_ca_ioctl_out + { + ib_api_status_t status; + + } out; + +} ual_close_ca_ioctl_t; +/* +* FIELDS +* in.h_ca +* The handle to an open instance of CA (in KAL space). +* +* out.status +* Status of the operation +*****/ + +/****s* User-mode Access Layer/ual_ci_call_ioctl_t +* NAME +* ual_ci_call_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* ib_ci_call +* +* SYNOPSIS +*/ +typedef union _ual_ci_call_ioctl +{ + struct _ual_ci_call_ioctl_in + { + ci_umv_buf_t umv_buf; + ib_ci_op_t ci_op; + uint64_t h_ca; + uint32_t num_handles; + uint64_t handle_array[1]; + + } in; + struct _ual_ci_call_ioctl_out + { + ci_umv_buf_t umv_buf; + ib_ci_op_t ci_op; + ib_api_status_t status; + + } out; + +} ual_ci_call_ioctl_t; +/* +* FIELDS +* in.umv_buf +* Opaque to IBAL buffer descriptor to allow the user-mode HCA library to +* exchange private information with the kernel-mode HCA driver. +* +* in.ci_op +* Contains information on the operation that needs to be performed +* by the verbs provider. The proxy marshals the data buffer between +* user mode and kernel space. +* +* in.h_ca +* The handle to an open instance of CA returned by a ual_open_ca_ioctl. +* +* in.num_handles +* The number of handles in the array at in.p_handle_array. +* +* in.handle_array +* First entry in an array of handles used for this operation. Ignored if +* in.num_handles is zero. +* +* out.umv_buf +* Returns the status from the HCA driver to the user-mode HCA library, +* along with any vendor specific output information. +* +* out.status +* Status of the operation +* +* out.ci_op +* Contains information on the operation that needs to be performed +* by the verbs provider. The proxy marshals the data buffer between +* user mode and kernel space. +*****/ + + + +/****s* User-mode Access Layer/ual_alloc_pd_ioctl_t +* NAME +* ual_alloc_pd_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* ib_alloc_pd +* +* SYNOPSIS +*/ +typedef union _ual_alloc_pd_ioctl +{ + struct _ual_alloc_pd_ioctl_in + { + ci_umv_buf_t umv_buf; + uint64_t h_ca; + ib_pd_type_t type; + uint64_t context; + + } in; + struct _ual_alloc_pd_ioctl_out + { + ci_umv_buf_t umv_buf; + ib_api_status_t status; + uint64_t h_pd; + + } out; + +} ual_alloc_pd_ioctl_t; +/* +* FIELDS +* in.umv_buf +* Opaque to IBAL buffer descriptor to allow the user-mode HCA library to +* exchange private information with the kernel-mode HCA driver. +* +* in.h_ca +* The handle to an open instance of CA returned in a ual_open_ca_ioctl. +* +* in.context +* UAL's pd context. This context will be provided on destroy callback. +* +* out.umv_buf +* Returns the status from the HCA driver to the user-mode HCA library, +* along with any vendor specific output information. +* +* out.status +* Status of the operation +* +* out.h_pd +* The handle to the PD to use in further PD-related IOCTLs. +*****/ + + + +/****s* User-mode Access Layer/ual_dealloc_pd_ioctl_t +* NAME +* ual_dealloc_pd_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* ib_dealloc_pd +* +* SYNOPSIS +*/ +typedef union _ual_dealloc_pd_ioctl +{ + struct _ual_dealloc_pd_ioctl_in + { + uint64_t h_pd; + + } in; + struct _ual_dealloc_pd_ioctl_out + { + ib_api_status_t status; + + } out; + +} ual_dealloc_pd_ioctl_t; +/* +* FIELDS +* in.h_pd +* The handle of the PD that is going to be deallocated. +* +* out.status +* Status of the operation +*****/ + + + +/****s* User-mode Access Layer/ual_create_av_ioctl_t +* NAME +* ual_create_av_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* ib_create_av +* +* SYNOPSIS +*/ +typedef union _ual_create_av_ioctl +{ + struct _ual_create_av_ioctl_in + { + ci_umv_buf_t umv_buf; + uint64_t h_pd; + ib_av_attr_t attr; + + } in; + struct _ual_create_av_ioctl_out + { + ci_umv_buf_t umv_buf; + ib_api_status_t status; + uint64_t h_av; + + } out; + +} ual_create_av_ioctl_t; +/* +* FIELDS +* in.umv_buf +* Opaque to IBAL buffer descriptor to allow the user-mode HCA library to +* exchange private information with the kernel-mode HCA driver. +* +* in.h_pd +* The handle to an already allocated PD (in KAL space). +* +* in.attr +* Attributes of the address vector that needs to be created. +* +* out.umv_buf +* Returns the status from the HCA driver to the user-mode HCA library, +* along with any vendor specific output information. +* +* out.status +* Status of the operation. +* +* out.h_av +* Handle to the newly created address vector. +*****/ + + + +/****s* User-mode Access Layer/ual_query_av_ioctl_t +* NAME +* ual_query_av_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* ib_query_av +* +* SYNOPSIS +*/ +typedef union _ual_query_av_ioctl +{ + struct _ual_query_av_ioctl_in + { + ci_umv_buf_t umv_buf; + uint64_t h_av; + + } in; + struct _ual_query_av_ioctl_out + { + ci_umv_buf_t umv_buf; + ib_api_status_t status; + ib_av_attr_t attr; + + } out; + +} ual_query_av_ioctl_t; +/* +* FIELDS +* in.umv_buf +* Opaque to IBAL buffer descriptor to allow the user-mode HCA library to +* exchange private information with the kernel-mode HCA driver. +* +* in.h_av +* A handle to an existing address vector. +* +* out.umv_buf +* Returns the status from the HCA driver to the user-mode HCA library, +* along with any vendor specific output information. +* +* out.status +* Status of the operation. +* +* out.attr +* Attributes of the address vector. +*****/ + + + +/****s* User-mode Access Layer/ual_modify_av_ioctl_t +* NAME +* ual_modify_av_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* ib_modify_av +* +* SYNOPSIS +*/ +typedef union _ual_modify_av_ioctl +{ + struct _ual_modify_av_ioctl_in + { + ci_umv_buf_t umv_buf; + uint64_t h_av; + ib_av_attr_t attr; + + } in; + struct _ual_modify_av_ioctl_out + { + ci_umv_buf_t umv_buf; + ib_api_status_t status; + + } out; + +} ual_modify_av_ioctl_t; +/* +* FIELDS +* in.umv_buf +* Opaque to IBAL buffer descriptor to allow the user-mode HCA library to +* exchange private information with the kernel-mode HCA driver. +* +* in.h_av +* A handle to an existing address vector. +* +* in.attr +* The requested attributes to be used for modifying the address vector. +* +* out.umv_buf +* Returns the status from the HCA driver to the user-mode HCA library, +* along with any vendor specific output information. +* +* out.status +* Status of the operation +*****/ + + + +/****s* User-mode Access Layer/ual_destroy_av_ioctl_t +* NAME +* ual_destroy_av_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* ib_destroy_av +* +* SYNOPSIS +*/ +typedef union _ual_destroy_av_ioctl +{ + struct _ual_destroy_av_ioctl_in + { + uint64_t h_av; + + } in; + struct _ual_destroy_av_ioctl_out + { + ib_api_status_t status; + + } out; + +} ual_destroy_av_ioctl_t; +/* +* FIELDS +* in.h_av +* A handle to an existing address vector. +* +* out.status +* Status of the operation. +*****/ + +/****s* User-mode Access Layer/ual_create_srq_ioctl_t +* NAME +* ual_create_srq_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* ib_create_srq +* +* SYNOPSIS +*/ +typedef union _ual_create_srq_ioctl +{ + struct _ual_create_srq_ioctl_in + { + ci_umv_buf_t umv_buf; + uint64_t h_pd; + ib_srq_attr_t srq_attr; + uint64_t context; + boolean_t ev_notify; + + } in; + struct _ual_create_srq_ioctl_out + { + ci_umv_buf_t umv_buf; + ib_api_status_t status; + uint64_t h_srq; + + } out; + +} ual_create_srq_ioctl_t; +/* +* FIELDS +* in.umv_buf +* Opaque to IBAL buffer descriptor to allow the user-mode HCA library to +* exchange private information with the kernel-mode HCA driver. +* +* in.h_pd +* Protection domain on which to create the srq. +* +* in.srq_attr +* Attributes necessary for creating the srq. +* +* in.context +* UAL's srq context that needs to be returned on a callback. +* +* in.ev_notify +* Boolean indicating whether asynchronous events should be +* forwarded to user-mode. +* +* out.umv_buf +* Returns the status from the HCA driver to the user-mode HCA library, +* along with any vendor specific output information. +* +* out.status +* Status of the operation. +* +* out.h_srq +* Handle for the newly created srq. +*****/ + + +/****s* User-mode Access Layer/ual_modify_srq_ioctl_t +* NAME +* ual_modify_srq_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* ib_modify_srq +* +* SYNOPSIS +*/ +typedef union _ual_modify_srq_ioctl +{ + struct _ual_modify_srq_ioctl_in + { + ci_umv_buf_t umv_buf; + uint64_t h_srq; + ib_srq_attr_mask_t srq_attr_mask; + ib_srq_attr_t srq_attr; + + } in; + struct _ual_modify_srq_ioctl_out + { + ci_umv_buf_t umv_buf; + ib_api_status_t status; + + } out; + +} ual_modify_srq_ioctl_t; +/* +* FIELDS +* in.umv_buf +* Opaque to IBAL buffer descriptor to allow the user-mode HCA library to +* exchange private information with the kernel-mode HCA driver. +* +* in.h_srq +* A handle to an existing Queue Pair. +* +* in.modify_attr +* Attributes used for modifying the srq. +* +* out.umv_buf +* Returns the status from the HCA driver to the user-mode HCA library, +* along with any vendor specific output information. +* +* out.status +* Status of the operation. +* +*****/ + + + +/****s* User-mode Access Layer/ual_query_srq_ioctl_t +* NAME +* ual_query_srq_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* ib_query_srq +* +* SYNOPSIS +*/ +typedef union _ual_query_srq_ioctl +{ + struct _ual_query_srq_ioctl_in + { + ci_umv_buf_t umv_buf; + uint64_t h_srq; + + } in; + struct _ual_query_srq_ioctl_out + { + ci_umv_buf_t umv_buf; + ib_api_status_t status; + ib_srq_attr_t srq_attr; + + } out; + +} ual_query_srq_ioctl_t; +/* +* FIELDS +* in.umv_buf +* Opaque to IBAL buffer descriptor to allow the user-mode HCA library to +* exchange private information with the kernel-mode HCA driver. +* +* h_srq +* Handle to the srq whose attributes to query. +* +* out.umv_buf +* Returns the status from the HCA driver to the user-mode HCA library, +* along with any vendor specific output information. +* +* out.status +* Status of the operation. +* +* out.srq_attr +* Attributes of the srq. +*****/ + + + +/****s* User-mode Access Layer/ual_destroy_srq_ioctl_t +* NAME +* ual_destroy_srq_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* ib_destroy_srq +* +* SYNOPSIS +*/ +typedef union _ual_destroy_srq_ioctl +{ + struct _ual_destroy_srq_ioctl_in + { + uint64_t h_srq; + + } in; + struct _ual_destroy_srq_ioctl_out + { + ib_api_status_t status; + + } out; + +} ual_destroy_srq_ioctl_t; +/* +* FIELDS +* in.h_srq +* Handle of the srq that needs to be destroyed. +* +* out.status +* Status of the operation. +*****/ + + + +/****s* User-mode Access Layer/ual_create_qp_ioctl_t +* NAME +* ual_create_qp_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* ib_create_qp +* +* SYNOPSIS +*/ +typedef union _ual_create_qp_ioctl +{ + struct _ual_create_qp_ioctl_in + { + ci_umv_buf_t umv_buf; + uint64_t h_pd; + ib_qp_create_t qp_create; + uint64_t context; + boolean_t ev_notify; + + } in; + struct _ual_create_qp_ioctl_out + { + ci_umv_buf_t umv_buf; + ib_api_status_t status; + ib_qp_attr_t attr; + uint64_t h_qp; + + } out; + +} ual_create_qp_ioctl_t; +/* +* FIELDS +* in.umv_buf +* Opaque to IBAL buffer descriptor to allow the user-mode HCA library to +* exchange private information with the kernel-mode HCA driver. +* +* in.h_pd +* Protection domain on which to create the QP. +* +* in.qp_create +* Attributes necessary for creating the QP. +* +* in.context +* UAL's qp context that needs to be returned on a callback. +* +* in.ev_notify +* Boolean indicating whether asynchronous events should be +* forwarded to user-mode. +* +* out.umv_buf +* Returns the status from the HCA driver to the user-mode HCA library, +* along with any vendor specific output information. +* +* out.status +* Status of the operation. +* +* out.attr +* Actual attributes of the newly created QP. +* +* out.h_qp +* Handle for the newly created QP. +*****/ + + + +/****s* User-mode Access Layer/ual_modify_qp_ioctl_t +* NAME +* ual_modify_qp_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* ib_modify_qp +* +* SYNOPSIS +*/ +typedef union _ual_modify_qp_ioctl +{ + struct _ual_modify_qp_ioctl_in + { + ci_umv_buf_t umv_buf; + uint64_t h_qp; + ib_qp_mod_t modify_attr; + + } in; + struct _ual_modify_qp_ioctl_out + { + ci_umv_buf_t umv_buf; + ib_api_status_t status; + //ib_qp_query_t query_attr; // Not returned by AL + + } out; + +} ual_modify_qp_ioctl_t; +/* +* FIELDS +* in.umv_buf +* Opaque to IBAL buffer descriptor to allow the user-mode HCA library to +* exchange private information with the kernel-mode HCA driver. +* +* in.h_qp +* A handle to an existing Queue Pair. +* +* in.modify_attr +* Attributes used for modifying the QP. +* +* out.umv_buf +* Returns the status from the HCA driver to the user-mode HCA library, +* along with any vendor specific output information. +* +* out.status +* Status of the operation. +* +* out.query_attr +* On return from the ioctl, contains the actual attributes of +* the QP just modified. +*****/ + + + +/****s* User-mode Access Layer/ual_query_qp_ioctl_t +* NAME +* ual_query_qp_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* ib_query_qp +* +* SYNOPSIS +*/ +typedef union _ual_query_qp_ioctl +{ + struct _ual_query_qp_ioctl_in + { + ci_umv_buf_t umv_buf; + uint64_t h_qp; + + } in; + struct _ual_query_qp_ioctl_out + { + ci_umv_buf_t umv_buf; + ib_api_status_t status; + ib_qp_attr_t attr; + + } out; + +} ual_query_qp_ioctl_t; +/* +* FIELDS +* in.umv_buf +* Opaque to IBAL buffer descriptor to allow the user-mode HCA library to +* exchange private information with the kernel-mode HCA driver. +* +* h_qp +* Handle to the QP whose attributes to query. +* +* out.umv_buf +* Returns the status from the HCA driver to the user-mode HCA library, +* along with any vendor specific output information. +* +* out.status +* Status of the operation. +* +* out.attr +* Attributes of the QP. +*****/ + + + +/****s* User-mode Access Layer/ual_destroy_qp_ioctl_t +* NAME +* ual_destroy_qp_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* ib_destroy_qp +* +* SYNOPSIS +*/ +typedef union _ual_destroy_qp_ioctl +{ + struct _ual_destroy_qp_ioctl_in + { + uint64_t h_qp; + + } in; + struct _ual_destroy_qp_ioctl_out + { + ib_api_status_t status; + + } out; + +} ual_destroy_qp_ioctl_t; +/* +* FIELDS +* in.h_qp +* Handle of the QP that needs to be destroyed. +* +* out.status +* Status of the operation. +*****/ + + + +/****s* User-mode Access Layer/ual_create_cq_ioctl_t +* NAME +* ual_create_cq_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* ib_create_cq +* +* SYNOPSIS +*/ +typedef union _ual_create_cq_ioctl +{ + struct _ual_create_cq_ioctl_in + { + ci_umv_buf_t umv_buf; + uint64_t h_ca; + void* __ptr64 h_wait_obj; /* __ptr64 is correct for HANDLE types. */ + uint64_t context; + uint32_t size; + boolean_t ev_notify; + + } in; + struct _ual_create_cq_ioctl_out + { + ci_umv_buf_t umv_buf; + ib_api_status_t status; + uint64_t h_cq; + uint32_t size; + + } out; + +} ual_create_cq_ioctl_t; +/* +* FIELDS +* in.umv_buf +* Opaque to IBAL buffer descriptor to allow the user-mode HCA library to +* exchange private information with the kernel-mode HCA driver. +* +* in.h_ca +* CA handle on which to create the CQ. +* +* in.cq_create +* Attributes necessary for creating the cq. +* +* in.cq_context +* UAL's cq context that needs to be returned on a callback. +* +* in.ev_notify +* Boolean indicating whether asynchronous events should be +* forwared to user-mode. +* +* out.umv_buf +* Returns the status from the HCA driver to the user-mode HCA library, +* along with any vendor specific output information. +* +* out.status +* Status of the operation. +* +* h_cq +* Handle to the newly created CQ. +* +* size +* Actual size of the newly created CQ. +*****/ + + + +/****s* User-mode Access Layer/ual_modify_cq_ioctl_t +* NAME +* ual_modify_cq_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* ib_modify_cq +* +* SYNOPSIS +*/ +typedef union _ual_modify_cq_ioctl +{ + struct _ual_modify_cq_ioctl_in + { + ci_umv_buf_t umv_buf; + uint64_t h_cq; + uint32_t size; + + } in; + struct _ual_modify_cq_ioctl_out + { + ci_umv_buf_t umv_buf; + ib_api_status_t status; + uint32_t size; + + } out; + +} ual_modify_cq_ioctl_t; +/* +* FIELDS +* in.umv_buf +* Opaque to IBAL buffer descriptor to allow the user-mode HCA library to +* exchange private information with the kernel-mode HCA driver. +* +* in.h_cq +* A handle to the CQ to modify. +* +* in.size +* The requested new size of the CQ. +* +* out.umv_buf +* Returns the status from the HCA driver to the user-mode HCA library, +* along with any vendor specific output information. +* +* out.status +* Status of the operation. +* +* out.size +* The actual size of the CQ. +*****/ + + + +/****s* User-mode Access Layer/ual_query_cq_ioctl_t +* NAME +* ual_query_cq_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* ib_query_cq +* +* SYNOPSIS +*/ +typedef union _ual_query_cq_ioctl +{ + struct _ual_query_cq_ioctl_in + { + ci_umv_buf_t umv_buf; + uint64_t h_cq; + + } in; + struct _ual_query_cq_ioctl_out + { + ci_umv_buf_t umv_buf; + ib_api_status_t status; + uint32_t size; + + } out; + +} ual_query_cq_ioctl_t; +/* +* FIELDS +* in.umv_buf +* Opaque to IBAL buffer descriptor to allow the user-mode HCA library to +* exchange private information with the kernel-mode HCA driver. +* +* in.h_cq +* A handle to an existing CQ. +* +* out.umv_buf +* Returns the status from the HCA driver to the user-mode HCA library, +* along with any vendor specific output information. +* +* out.status +* Status of the operation. +* +* out.size +* The size of the CQ. +*****/ + + + +/****s* User-mode Access Layer/ual_destroy_cq_ioctl_t +* NAME +* ual_destroy_cq_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* ib_destroy_cq +* +* SYNOPSIS +*/ +typedef union _ual_destroy_cq_ioctl +{ + struct _ual_destroy_cq_ioctl_in + { + uint64_t h_cq; + + } in; + struct _ual_destroy_cq_ioctl_out + { + ib_api_status_t status; + + } out; + +} ual_destroy_cq_ioctl_t; +/* +* FIELDS +* in.h_cq +* Handle of the cq that needs to be destroyed. +* +* out.status +* Status of the operation. +*****/ + + + +/****s* User-mode Access Layer/ual_reg_mem_ioctl_t +* NAME +* ual_reg_mem_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* ib_reg_mem +* +* SYNOPSIS +*/ +typedef union _ual_reg_mem_ioctl +{ + struct _ual_reg_mem_ioctl_in + { + uint64_t h_pd; + ib_mr_create_t mem_create; + + } in; + struct _ual_reg_mem_ioctl_out + { + ib_api_status_t status; + net32_t lkey; + net32_t rkey; + uint64_t h_mr; + + } out; + +} ual_reg_mem_ioctl_t; +/* +* FIELDS +* in.h_pd +* Handle to the protection domain on which to register the memory. +* +* in.mem_create +* Information for registering the memory region. +* +* out.status +* Status of the operation. +* +* out.lkey +* LKey value returned by verb. +* +* out.rkey +* RKey value returned by verb. +* +* h_mr +* Handle to the registered memory region. +*****/ + + + +/****s* User-mode Access Layer/ual_query_mr_ioctl_t +* NAME +* ual_query_mr_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* ib_query_mr +* +* SYNOPSIS +*/ +typedef union _ual_query_mr_ioctl +{ + struct _ual_query_mr_ioctl_in + { + uint64_t h_mr; + + } in; + struct _ual_query_mr_ioctl_out + { + ib_api_status_t status; + ib_mr_attr_t attr; + + } out; + +} ual_query_mr_ioctl_t; +/* +* FIELDS +* in.h_mr +* A handle to a registered memory region. +* +* out.status +* Status of the operation. +* +* out.attr +* Attributes of the registered memory region. +*****/ + + + +/****s* User-mode Access Layer/ual_rereg_mem_ioctl_t +* NAME +* ual_rereg_mem_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* ib_modify_mr +* +* SYNOPSIS +*/ +typedef union _ual_rereg_mem_ioctl +{ + struct _ual_rereg_mem_ioctl_in + { + uint64_t h_mr; + ib_mr_mod_t mem_mod_mask; + ib_mr_create_t mem_create; + uint64_t h_pd; + + } in; + struct _ual_rereg_mem_ioctl_out + { + ib_api_status_t status; + net32_t lkey; + net32_t rkey; + + } out; + +} ual_rereg_mem_ioctl_t; +/* +* FIELDS +* in.h_mr +* A handle to a registered memory region that is being modified. +* +* in.mem_mod_mask +* The attributes to use when modifying the memory region. +* +* in.mem_create +* Information to use for modifying the memory region. Required only +* for changes other than the PD. +* +* in.h_pd +* PD Handle for changing protection domains. +* +* out.status +* Status of the operation. +* +* out.l_key +* LKey of the memory region. +* +* out.rkey +* RKey of the memory region. +*****/ + + + +/****s* User-mode Access Layer/ual_reg_shared_ioctl_t +* NAME +* ual_reg_shared_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* ib_reg_shared +* +* SYNOPSIS +*/ +typedef union _ual_reg_shared_ioctl +{ + struct _ual_reg_shared_ioctl_in + { + uint64_t h_mr; + uint64_t h_pd; + ib_access_t access_ctrl; + uint64_t vaddr; + + } in; + struct _ual_reg_shared_ioctl_out + { + ib_api_status_t status; + uint64_t vaddr; + net32_t lkey; + net32_t rkey; + uint64_t h_new_mr; + + } out; + +} ual_reg_shared_ioctl_t; +/* +* FIELDS +* in.h_mr +* A handle to the existing registered memory region. +* +* in.h_pd +* A handle to the PD on which memory is being registered. +* +* in.access_ctrl +* Access control for the new memory region. +* +* in.vaddr +* Requested virtual address. +* +* out.status +* Status of the operation. +* +* out.vaddr +* Actual virtual address of the registered region. +* +* out.l_key +* LKey of the memory region. +* +* out.rkey +* RKey of the memory region. +* +* h_new_mr +* Handle to the registered memory region. +*****/ + + + +/****s* User-mode Access Layer/ual_dereg_mr_ioctl_t +* NAME +* ual_dereg_mr_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* ib_dereg_mr +* +* SYNOPSIS +*/ +typedef union _ual_dereg_mr_ioctl +{ + struct _ual_dereg_mr_ioctl_in + { + uint64_t h_mr; + + } in; + struct _ual_dereg_mr_ioctl_out + { + ib_api_status_t status; + + } out; + +} ual_dereg_mr_ioctl_t; +/* +* FIELDS +* in.h_mr +* A handle to a registered memory region. +* +* out.status +* Status of the operation. +*****/ + + + +/****s* User-mode Access Layer/ual_create_mw_ioctl_t +* NAME +* ual_create_mw_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* ib_create_mw +* +* SYNOPSIS +*/ +typedef union _ual_create_mw_ioctl +{ + struct _ual_create_mw_ioctl_in + { + ci_umv_buf_t umv_buf; + uint64_t h_pd; + + } in; + struct _ual_create_mw_ioctl_out + { + ci_umv_buf_t umv_buf; + ib_api_status_t status; + net32_t rkey; + uint64_t h_mw; + + } out; + +} ual_create_mw_ioctl_t; +/* +* FIELDS +* in.umv_buf +* Opaque to IBAL buffer descriptor to allow the user-mode HCA library to +* exchange private information with the kernel-mode HCA driver. +* +* in.h_pd +* A handle to the protection domain on which the memory window should +* be created. +* +* out.umv_buf +* Returns the status from the HCA driver to the user-mode HCA library, +* along with any vendor specific output information. +* +* out.status +* Status of the operation. +* +* out.rkey +* RKey associated with the memory window. +* +* h_mw +* Handle to the newly created MW. +*****/ + + + +/****s* User-mode Access Layer/ual_query_mw_ioctl_t +* NAME +* ual_query_mw_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* ib_query_mw +* +* SYNOPSIS +*/ +typedef union _ual_query_mw_ioctl +{ + struct _ual_query_mw_ioctl_in + { + ci_umv_buf_t umv_buf; + uint64_t h_mw; + + } in; + struct _ual_query_mw_ioctl_out + { + ci_umv_buf_t umv_buf; + ib_api_status_t status; + net32_t rkey; + + } out; + +} ual_query_mw_ioctl_t; +/* +* FIELDS +* in.umv_buf +* Opaque to IBAL buffer descriptor to allow the user-mode HCA library to +* exchange private information with the kernel-mode HCA driver. +* +* in.h_mw +* A handle to an existing memory window. +* +* out.umv_buf +* Returns the status from the HCA driver to the user-mode HCA library, +* along with any vendor specific output information. +* +* out.status +* Status of the operation. +* +* rkey +* RKey associated with the memory window. +*****/ + + + +/****s* User-mode Access Layer/ual_bind_mw_ioctl_t +* NAME +* ual_bind_mw_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* ib_bind_mw +* +* SYNOPSIS +*/ +typedef union _ual_bind_mw_ioctl +{ + struct _ual_bind_mw_ioctl_in + { + uint64_t h_mw; + uint64_t h_qp; + ib_bind_wr_t mw_bind; + + } in; + struct _ual_bind_mw_ioctl_out + { + ib_api_status_t status; + uint32_t r_key; + + } out; + +} ual_bind_mw_ioctl_t; +/* +* FIELDS +* in.h_mw +* A handle to an existing memory window. +* +* in.h_qp +* The qp handle to post the bind request. +* +* in.mw_bind +* Bind request. +* +* out.status +* Status of the operation. +* +* out.rkey +* RKey for the memory window. +*****/ + + + +/****s* User-mode Access Layer/ual_destroy_mw_ioctl_t +* NAME +* ual_destroy_mw_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* ib_destroy_mw +* +* SYNOPSIS +*/ +typedef union _ual_destroy_mw_ioctl +{ + struct _ual_destroy_mw_ioctl_in + { + uint64_t h_mw; + + } in; + struct _ual_destroy_mw_ioctl_out + { + ib_api_status_t status; + + } out; + +} ual_destroy_mw_ioctl_t; +/* +* FIELDS +* in.h_mw +* A handle to an existing memory window. +* +* out.status +* Status of the operation +*****/ + + + +/****s* User-mode Access Layer/ual_post_send_ioctl_t +* NAME +* ual_post_send_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* ib_post_send +* +* SYNOPSIS +*/ +typedef union _ual_post_send_ioctl +{ + struct _ual_post_send_ioctl_in + { + uint64_t h_qp; + uint32_t num_wr; + uint32_t num_ds; + ib_send_wr_t send_wr[1]; + /* Additional work requests follow, followed by data segments. */ + + } in; + struct _ual_post_send_ioctl_out + { + ib_api_status_t status; + uint32_t failed_cnt; + + } out; + +} ual_post_send_ioctl_t; +/* +* FIELDS +* in.h_qp +* A handle to QP where the work request is being posted. +* +* in.num_wr +* Number of work request items in the array of work requests. +* +* in.num_ds +* Number of data segments following the array of work requests. +* +* in.send_wr +* First work request in the array of work requests being posted. +* +* out.status +* Status of the operation. +* +* out.failed_cnt +* Number of work request that failed. +*****/ + + +/****s* User-mode Access Layer/ual_post_srq_recv_ioctl_t +* NAME +* ual_post_srq_recv_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* ib_post_srq_recv +* +* SYNOPSIS +*/ +typedef union _ual_post_srq_recv_ioctl +{ + struct _ual_post_srq_recv_ioctl_in + { + uint64_t h_srq; + uint32_t num_wr; + uint32_t num_ds; + ib_recv_wr_t recv_wr[1]; + /* Additional work requests follow, followed by data segments. */ + + } in; + struct _ual_post_srq_recv_ioctl_out + { + ib_api_status_t status; + uint32_t failed_cnt; + + } out; + +} ual_post_srq_recv_ioctl_t; +/* +* FIELDS +* in.h_srq +* A handle to SRQ where the work request is being posted. +* +* in.num_wr +* Number of work request items in the array of work requests. +* +* in.num_ds +* Number of data segments following the array of work requests. +* +* in.recv_wr +* First work request in the array of work requests being posted. +* +* out.status +* Status of the operation. +* +* failed_cnt +* Number of work request that failed. +*****/ + + + +/****s* User-mode Access Layer/ual_post_recv_ioctl_t +* NAME +* ual_post_recv_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* ib_post_recv +* +* SYNOPSIS +*/ +typedef union _ual_post_recv_ioctl +{ + struct _ual_post_recv_ioctl_in + { + uint64_t h_qp; + uint32_t num_wr; + uint32_t num_ds; + ib_recv_wr_t recv_wr[1]; + /* Additional work requests follow, followed by data segments. */ + + } in; + struct _ual_post_recv_ioctl_out + { + ib_api_status_t status; + uint32_t failed_cnt; + + } out; + +} ual_post_recv_ioctl_t; +/* +* FIELDS +* in.h_qp +* A handle to QP where the work request is being posted. +* +* in.num_wr +* Number of work request items in the array of work requests. +* +* in.num_ds +* Number of data segments following the array of work requests. +* +* in.recv_wr +* First work request in the array of work requests being posted. +* +* out.status +* Status of the operation. +* +* failed_cnt +* Number of work request that failed. +*****/ + + + +/****s* User-mode Access Layer/ual_peek_cq_ioctl_t +* NAME +* ual_peek_cq_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* ib_peek_cq +* +* SYNOPSIS +*/ +typedef union _ual_peek_cq_ioctl +{ + struct _ual_peek_cq_ioctl_in + { + uint64_t h_cq; + + } in; + struct _ual_peek_cq_ioctl_out + { + ib_api_status_t status; + uint32_t n_cqes; + + } out; + +} ual_peek_cq_ioctl_t; +/* +* FIELDS +* in.h_cq +* A handle to a CQ. +* +* out.status +* Status of the operation. +* +* out.n_cqes +* The number of completion queue entries currently on the CQ. +*****/ + + + +/****s* User-mode Access Layer/ual_poll_cq_ioctl_t +* NAME +* ual_poll_cq_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* ib_poll_cq +* +* SYNOPSIS +*/ +typedef union _ual_poll_cq_ioctl +{ + struct _ual_poll_cq_ioctl_in + { + uint64_t h_cq; + uint32_t num_wc; + + } in; + struct _ual_poll_cq_ioctl_out + { + ib_api_status_t status; + uint32_t num_wc; + ib_wc_t wc[1]; + /* Additional WC's follow. */ + } out; + +} ual_poll_cq_ioctl_t; +/* +* FIELDS +* in.h_cq +* A handle to cq that is going to be polled for completions. +* +* in.num_wc +* Number of work completions in the output array. +* +* out.status +* Status of the operation. +* +* out.num_wc +* Number of work completions polled. +* +* out.wc +* First work completion in the array to use for polling. +*****/ + + + +/****s* User-mode Access Layer/ual_rearm_cq_ioctl_t +* NAME +* ual_rearm_cq_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* ib_rearm_cq +* +* SYNOPSIS +*/ +typedef union _ual_rearm_cq_ioctl +{ + struct _ual_rearm_cq_ioctl_in + { + uint64_t h_cq; + boolean_t solicited; + + } in; + struct _ual_rearm_cq_ioctl_out + { + ib_api_status_t status; + + } out; + +} ual_rearm_cq_ioctl_t; +/* +* FIELDS +* in.h_cq +* A handle to a CQ. +* +* in.solicited +* Flag for rearm CQ. +* +* out.status +* Status of the operation. +*****/ + + + +/****s* User-mode Access Layer/ual_rearm_n_cq_ioctl_t +* NAME +* ual_rearm_n_cq_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* ib_rearm_n_cq +* +* SYNOPSIS +*/ +typedef union _ual_rearm_n_cq_ioctl +{ + struct _ual_rearm_n_cq_ioctl_in + { + uint64_t h_cq; + uint32_t n_cqes; + + } in; + struct _ual_rearm_n_cq_ioctl_out + { + ib_api_status_t status; + + } out; + +} ual_rearm_n_cq_ioctl_t; +/* +* FIELDS +* in.h_cq +* A handle to a CQ. +* +* in.n_cqes +* Rearm the CQ to signal when the next N completions are added. +* +* in.status +* Status of the operation. +*****/ + + + +/****s* User-mode Access Layer/ual_attach_mcast_ioctl_t +* NAME +* ual_attach_mcast_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* verbs attach multicast call. +* +* SYNOPSIS +*/ +typedef union _ual_attach_mcast_ioctl +{ + struct _ual_attach_mcast_ioctl_in + { + ci_umv_buf_t umv_buf; + uint64_t h_qp; + ib_gid_t mgid; + ib_net16_t mlid; + + } in; + struct _ual_attach_mcast_ioctl_out + { + ci_umv_buf_t umv_buf; + ib_api_status_t status; + uint64_t h_attach; + + } out; + +} ual_attach_mcast_ioctl_t; +/* +* FIELDS +* in.umv_buf +* Opaque to IBAL buffer descriptor to allow the user-mode HCA library to +* exchange private information with the kernel-mode HCA driver. +* +* in.h_qp +* Handle to the QP that is joining the multicast group. +* +* in.mgid +* Multicast GID address for this multicast group. +* +* in.mlid +* Multicast LID for this multicast group. +* +* out.umv_buf +* Returns the status from the HCA driver to the user-mode HCA library, +* along with any vendor specific output information. +* +* out.status +* Status of the operation. +* +* h_attach +* Multicast group handle. +*****/ + + + +/****s* User-mode Access Layer/ual_detach_mcast_ioctl_t +* NAME +* ual_detach_mcast_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* verbs detach call. +* +* SYNOPSIS +*/ +typedef union _ual_detach_mcast_ioctl +{ + struct _ual_detach_mcast_ioctl_in + { + uint64_t h_attach; + + } in; + struct _ual_detach_mcast_ioctl_out + { + ib_api_status_t status; + + } out; + +} ual_detach_mcast_ioctl_t; +/* +* FIELDS +* in.h_attach +* A handle to the multicast group. +* +* out.status +* Status of the operation. +*****/ + + + +/****s* User-mode Access Layer/ual_reg_mad_svc_ioctl_t +* NAME +* ual_reg_mad_svc_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* ib_reg_mad_svc +* +* SYNOPSIS +*/ +typedef union _ual_reg_mad_svc_ioctl +{ + struct _ual_reg_mad_svc_ioctl_in + { + uint64_t h_qp; + ib_mad_svc_t mad_svc; + + } in; + struct _ual_reg_mad_svc_ioctl_out + { + ib_api_status_t status; + uint64_t h_mad_svc; + + } out; + +} ual_reg_mad_svc_ioctl_t; +/* +* FIELDS +* in.h_qp +* Handle to the special QP or MAD QP. +* +* in.mad_svc +* Mad service definition. +* +* out.status +* Status of the operation. +* +* out.h_mad_svc +* Handle to the mad service. +*****/ + + + +/****s* User-mode Access Layer/ual_dereg_mad_svc_ioctl_t +* NAME +* ual_dereg_mad_svc_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* ib_dereg_mad_svc +* +* SYNOPSIS +*/ +typedef union _ual_dereg_mad_svc_ioctl +{ + struct _ual_dereg_mad_svc_ioctl_in + { + uint64_t h_mad_svc; + + } in; + struct _ual_dereg_mad_svc_ioctl_out + { + ib_api_status_t status; + + } out; + +} ual_dereg_mad_svc_ioctl_t; +/* +* FIELDS +* in.h_mad_svc +* Handle to the mad service. +* +* out.status +* Status of the operation. +*****/ + + + +/****s* User-mode Access Layer/ual_reg_mad_pool_ioctl_t +* NAME +* ual_reg_mad_pool_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* registering a mad pool to be used with special qp. This ioctl +* will result in user-mode pool registered. Additionally, +* the kernel proxy will allocate a kernel mad pool and register it +* so that later mad_sends will have the appropriate pool in kernel. +* +* SYNOPSIS +*/ +typedef union _ual_reg_mad_pool_ioctl +{ + struct _ual_reg_mad_pool_ioctl_in + { + uint64_t h_pd; + + } in; + struct _ual_reg_mad_pool_ioctl_out + { + ib_api_status_t status; + uint64_t pool_key; + + } out; + +} ual_reg_mad_pool_ioctl_t; +/* +* FIELDS +* in.h_pd +* PD associated with the pool +* +* out.status +* Status of the operation. +* +* out.pool_key +* Pool key to the mad pool in kernel space +*****/ + + + +/****s* User-mode Access Layer/ual_dereg_mad_pool_ioctl_t +* NAME +* ual_dereg_mad_pool_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* deregistering a mad pool to be used with special qp. +* The kernel proxy will deregister and destroy the mad pool +* created on behalf of the user process. +* +* SYNOPSIS +*/ +typedef union _ual_dereg_mad_pool_ioctl +{ + struct _ual_dereg_mad_pool_ioctl_in + { + uint64_t pool_key; + + } in; + struct _ual_dereg_mad_pool_ioctl_out + { + ib_api_status_t status; + + } out; + +} ual_dereg_mad_pool_ioctl_t; +/* +* FIELDS +* in.pool_key +* Pool key to the mad pool in kernel space. +* +* out.status +* Status of the operation +*****/ + + + +/****s* User-mode Access Layer/ual_send_mad_ioctl_t +* NAME +* ual_send_mad_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* ib_send_mad +* +* SYNOPSIS +*/ +typedef union _ual_send_mad_ioctl +{ + struct _ual_send_mad_ioctl_in + { + uint64_t h_mad_svc; + uint64_t pool_key; + uint64_t h_av; + uint64_t p_mad_element; + uint32_t size; + uint64_t ph_proxy; + + } in; + struct _ual_send_mad_ioctl_out + { + ib_api_status_t status; + + } out; + +} ual_send_mad_ioctl_t; +/* +* FIELDS +* in.h_mad_svc +* Handle to the mad service. +* +* in.pool_key +* Pool key associated with the pool in kernel space. +* +* in.h_av +* handle to address vector of MAD. +* +* in.p_mad_element +* Pointer to the user-mode MAD element. The proxy marshals this data. +* +* in.size +* size of MAD buffer to send. +* +* in.ph_proxy +* Location to which to write the context used to cancel the MAD. +* +* out.status +* Status of the operation. +*****/ + + + +/****s* User-mode Access Layer/ual_cancel_mad_ioctl_t +* NAME +* ual_cancel_mad_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* ib_cancel_mad +* +* SYNOPSIS +*/ +typedef union _ual_cancel_mad_ioctl +{ + struct _ual_cancel_mad_ioctl_in + { + uint64_t h_mad_svc; + uint64_t h_proxy_element; + + } in; + struct _ual_cancel_mad_ioctl_out + { + ib_api_status_t status; + + } out; + +} ual_cancel_mad_ioctl_t; +/* +* FIELDS +* in.h_mad_svc +* contains the handle to the mad service +* +* in.h_mad_send +* this references the handle to the sent MAD operation. +* +* out.status +* Status of the operation. +*****/ + + + +/****s* User-mode Access Layer/ual_spl_qp_ioctl_t +* NAME +* ual_spl_qp_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters to get +* the alias qp from KAL. +* +* SYNOPSIS +*/ +typedef union _ual_spl_qp_ioctl +{ + struct _ual_spl_qp_ioctl_in + { + ci_umv_buf_t umv_buf; + uint64_t h_pd; + ib_net64_t port_guid; + ib_qp_create_t qp_create; + uint64_t context; + + } in; + struct _ual_spl_qp_ioctl_out + { + ci_umv_buf_t umv_buf; + ib_api_status_t status; + uint64_t h_qp; + + } out; + +} ual_spl_qp_ioctl_t; +/* +* FIELDS +* in.h_pd +* Protection domain for the special qp. +* +* in.port_guid +* Port GUID on which to allocate the special QP. +* +* in.qp_create +* Special QP creation parameters. +* +* in.qp_context +* Context to associate with the QP, to be used in any notifications. +* +* out.status +* Status of the operation. +* +* out.h_qp +* Handle to the special QP. +*****/ + + + +/****s* User-mode Access Layer/ual_mad_recv_ioctl_t +* NAME +* ual_mad_recv_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters to get +* the mad_element information upon receiving MAD. +* +* SYNOPSIS +*/ +typedef union _ual_mad_recv_ioctl +{ + struct _ual_mad_recv_comp_ioctl_in + { + uint64_t h_mad; + uint64_t p_user_mad; + uint64_t p_mad_buf; + uint64_t p_grh; + + } in; + struct _ual_mad_recv_comp_ioctl_out + { + ib_api_status_t status; + + } out; + +} ual_mad_recv_ioctl_t; +/* +* FIELDS +* in.h_mad +* Received MAD handle handed to usermode in the MAD recv notification. +* +* in.p_user_mad +* Pointer to a user-mode mad element. +* +* in.p_mad_buf +* Pointer to the MAD element's user-mode buffer. +* +* in.p_grh +* Ponter to the MAD element's user-mode GRH buffer. +* +* out.status +* Status of the operation. +*****/ + + + +/****s* User-mode Access Layer/ual_local_mad_ioctl_t +* NAME +* ual_local_mad_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* ib_local_mad +* +* SYNOPSIS +*/ +typedef union _ual_local_mad_ioctl +{ + struct _ual_local_mad_ioctl_in + { + uint64_t h_ca; + __declspec(align(8)) uint8_t mad_in[MAD_BLOCK_SIZE]; + uint8_t port_num; + + + } in; + struct _ual_local_mad_ioctl_out + { + ib_api_status_t status; + uint32_t _pad; /* 8-byte alignment needed for ia64 */ + __declspec(align(8)) uint8_t mad_out[MAD_BLOCK_SIZE]; + + } out; + +} ual_local_mad_ioctl_t; +/* +** FIELDS +* in.h_ca +* The handle to an open instance of CA returned via a +* ual_open_ca_ioctl structure. +* in.port_num +* Port number this MAD refere to. +* in.mad_in +* Mad structure from user mode to forward to local HCA. +* +** out.status +* Status of the operation. +* out.mad_out +* Mad structure answer from local HCA for user mode. +*****/ + + + +/****s* User-mode Access Layer/ual_create_cep_ioctl_t +* NAME +* ual_create_cep_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the output parameters to +* create a CEP. +* +* SYNOPSIS +*/ +typedef struct _ual_create_cep_ioctl +{ + ib_api_status_t status; + net32_t cid; + +} ual_create_cep_ioctl_t; +/* +* FIELDS +* status +* Status of the operation. +* +* cid +* CID of the created CEP. +*****/ + + +/****s* User-mode Access Layer/ual_cep_listen_ioctl_t +* NAME +* ual_cep_listen_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input parameters to +* perform a CM listen request. +* +* SYNOPSIS +*/ +typedef struct _ual_cep_listen_ioctl +{ + net32_t cid; + ib_cep_listen_t cep_listen; + uint8_t compare[IB_REQ_PDATA_SIZE]; + +} ual_cep_listen_ioctl_t; +/* +* FIELDS +* in.cid +* CID of an existing CEP. +* +* in.cep_listen +* Information used to direct the listen request to match incoming +* connection requests. +*****/ + + + +/****s* User-mode Access Layer/ual_cm_req_ioctl_t +* NAME +* ual_cm_req_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* al_cep_pre_req call. +* +* SYNOPSIS +*/ +typedef union _ual_cep_req_ioctl +{ + struct _ual_cep_req_ioctl_in + { + net32_t cid; + ib_cm_req_t cm_req; + ib_path_rec_t paths[2]; + uint8_t pdata[IB_REQ_PDATA_SIZE]; + uint8_t compare[IB_REQ_PDATA_SIZE]; + + } in; + struct _ual_cep_req_ioctl_out + { + ib_api_status_t status; + ib_qp_mod_t init; + + } out; + +} ual_cep_req_ioctl_t; +/* +* FIELDS +* in.cid +* CID of the target CEP. +* +* in.cm_req +* CM REQ parameters. +* +* in.paths +* Array of paths, the first being the primary path to use for the REQ. +* +* out.status +* Status of the operation +* +* out.init +* QP modify paramters for INIT state transition. +*****/ + + + +/****s* User-mode Access Layer/ual_cep_rep_ioctl_t +* NAME +* ual_cep_rep_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* al_cep_pre_rep call. +* +* SYNOPSIS +*/ +typedef union _ual_cep_rep_ioctl +{ + struct _ual_cep_rep_ioctl_in + { + uint64_t context; + net32_t cid; + ib_cm_rep_t cm_rep; + uint8_t pdata[IB_REP_PDATA_SIZE]; + + } in; + struct _ual_cep_rep_ioctl_out + { + ib_api_status_t status; + ib_qp_mod_t init; + + } out; + +} ual_cep_rep_ioctl_t; +/* +* FIELDS +* in.h_cm_req +* The cm_req connection handle got on the callback. +* +* in.cm_rep +* CM REP parameters. +* +* out.status +* Status of the operation. +* +* out.init +* QP modify paramters for INIT state transition. +*****/ + + + +/****s* User-mode Access Layer/ual_cep_get_rtr_ioctl_t +* NAME +* ual_cep_get_rtr_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the output parameters for +* al_cep_get_rtr_attr call. +* +* SYNOPSIS +*/ +typedef struct _ual_cep_get_rtr_ioctl +{ + ib_api_status_t status; + ib_qp_mod_t rtr; + +} ual_cep_get_rtr_ioctl_t; +/* +* FIELDS +* out.status +* Status of the operation. +* +* out.rtr +* QP modify paramters for RTR state transition. +*****/ + + + +/****s* User-mode Access Layer/ual_cep_get_rts_ioctl_t +* NAME +* ual_cep_get_rts_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the output parameters for +* al_cep_get_rts_attr call. +* +* SYNOPSIS +*/ +typedef struct _ual_cep_get_rts_ioctl +{ + ib_api_status_t status; + ib_qp_mod_t rts; + +} ual_cep_get_rts_ioctl_t; +/* +* FIELDS +* out.status +* Status of the operation. +* +* out.rts +* QP modify paramters for RTS state transition. +*****/ + + + +/****s* User-mode Access Layer/ual_cep_rtu_ioctl_t +* NAME +* ual_cep_rtu_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input parameters for +* al_cep_rtu call. +* +* SYNOPSIS +*/ +typedef struct _ual_cep_rtu_ioctl +{ + net32_t cid; + uint8_t pdata_len; + uint8_t pdata[IB_RTU_PDATA_SIZE]; + +} ual_cep_rtu_ioctl_t; +/* +* FIELDS +* in.cid +* The cm_rep connection handle got on the callback. +* +* in.pdata_len +* Length of private data. +* +* in.pdata +* Private data. +*****/ + + + +/****s* User-mode Access Layer/ual_cep_rej_ioctl_t +* NAME +* ual_cep_rej_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input parameters for +* al_cep_rej +* +* SYNOPSIS +*/ +typedef struct _ual_cep_rej_ioctl +{ + net32_t cid; + + ib_rej_status_t rej_status; + uint8_t ari_len; + uint8_t pdata_len; + uint8_t ari[IB_ARI_SIZE]; + uint8_t pdata[IB_REJ_PDATA_SIZE]; + +} ual_cep_rej_ioctl_t; +/* +* FIELDS +* in.cid +* The CID of the target CEP. +* +* in.rej_status +* Rejection status as defined in IB spec. +* +* in.ari_len +* Length of the ARI data. +* +* in.pdata_len +* Length of the private data. +* +* in.ari +* ARI data. +* +* in.pdata +* Private data. +*****/ + + + +/****s* User-mode Access Layer/ual_cep_handoff_ioctl_t +* NAME +* ual_cep_handoff_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* ib_cm_handoff +* +* SYNOPSIS +*/ +typedef union _ual_cep_handoff_ioctl +{ + struct _ual_cep_handoff_ioctl_in + { + uint64_t h_cm; + net64_t sid; + + } in; + struct _ual_cep_handoff_ioctl_out + { + ib_api_status_t status; + + } out; + +} ual_cep_handoff_ioctl_t; +/* +* FIELDS +* in.h_cm +* The connection handle got on the callback. +* +* in.sid +* Service ID to which to handoff the listen. +* +* out.status +* Status of the operation +*****/ + + + +/****s* User-mode Access Layer/ual_cep_mra_ioctl_t +* NAME +* ual_cep_mra_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input parameters for +* ib_cm_mra +* +* SYNOPSIS +*/ +typedef struct _ual_cep_mra_ioctl +{ + net32_t cid; + ib_cm_mra_t cm_mra; + uint8_t pdata[IB_MRA_PDATA_SIZE]; + +} ual_cep_mra_ioctl_t; +/* +* FIELDS +* in.cid +* The CID for the target CEP. +* +* in.cm_mra +* CM MRA parameters. +*****/ + + + +/****s* User-mode Access Layer/ual_cep_lap_ioctl_t +* NAME +* ual_cep_lap_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input parameters for +* ib_cm_lap +* +* SYNOPSIS +*/ +typedef struct _ual_cep_lap_ioctl +{ + net32_t cid; + ib_cm_lap_t cm_lap; + ib_path_rec_t alt_path; + uint8_t pdata[IB_LAP_PDATA_SIZE]; + +} ual_cep_lap_ioctl_t; +/* +* FIELDS +* in.cm_lap +* CM LAP parameters +* +* in.alt_path +* Alternate path information. +*****/ + + + +/****s* User-mode Access Layer/ual_cep_apr_ioctl_t +* NAME +* ual_cep_apr_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input parameters for +* ib_cep_apr +* +* SYNOPSIS +*/ +typedef union _ual_cep_apr_ioctl +{ + struct _ual_cep_apr_ioctl_in + { + net32_t cid; + ib_cm_apr_t cm_apr; + uint8_t apr_info[IB_APR_INFO_SIZE]; + uint8_t pdata[IB_APR_PDATA_SIZE]; + + } in; + + struct _ual_cep_apr_ioctl_out + { + ib_api_status_t status; + ib_qp_mod_t apr; + + } out; + +} ual_cep_apr_ioctl_t; +/* +* FIELDS +* in.h_cm_lap +* The cm_lap connection handle got on the LAP callback. +* +* in.cm_apr +* CM APR parameters. +*****/ + + + +/****s* User-mode Access Layer/ual_force_apm_ioctl_t +* NAME +* ual_force_apm_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* ib_force_apm +* +* SYNOPSIS +*/ +typedef union _ual_force_apm_ioctl +{ + union _ual_force_apm_ioctl_in + { + uint64_t h_qp; + + } in; + struct _ual_force_apm_ioctl_out + { + ib_api_status_t status; + + } out; + +} ual_force_apm_ioctl_t; +/* +* FIELDS +* in.h_qp +* A handle to the QP to migrate. +* +* out.status +* Status of the operation +*****/ + + + +/****s* User-mode Access Layer/ual_cep_dreq_ioctl_t +* NAME +* ual_cep_dreq_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input parameters for +* ib_cm_dreq +* +* SYNOPSIS +*/ +typedef struct _ual_cep_dreq_ioctl +{ + net32_t cid; + uint8_t pdata_len; + uint8_t pdata[IB_DREQ_PDATA_SIZE]; + +} ual_cep_dreq_ioctl_t; +/* +* FIELDS +* cm_dreq +* CM DREQ parameters. +*****/ + + + +/****s* User-mode Access Layer/ual_cep_drep_ioctl_t +* NAME +* ual_cep_drep_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* ib_cm_drep +* +* SYNOPSIS +*/ +typedef struct _ual_cep_drep_ioctl +{ + net32_t cid; + uint8_t pdata_len; + uint8_t pdata[IB_DREP_PDATA_SIZE]; + +} ual_cep_drep_ioctl_t; +/* +* FIELDS +* in.h_cm_dreq +* The cm_dreq connection handle got on the callback. +* +* in.cm_drep +* CM DREP parameters. +*****/ + + + +/****s* User-mode Access Layer/ual_cep_get_timewait_ioctl_t +* NAME +* ual_cep_get_timewait_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the output parameters for +* ib_cep_get_timewait +* +* SYNOPSIS +*/ +typedef struct _ual_cep_get_timewait_ioctl +{ + ib_api_status_t status; + uint64_t timewait_us; + +} ual_cep_get_timewait_ioctl_t; +/* +* FIELDS +* in.status +* Status of the request. +* +* in.timewait_us +* Timewait value, in microseconds. +*****/ + + + +/****s* User-mode Access Layer/ual_cep_poll_ioctl_t +* NAME +* ual_cep_poll_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the output parameters to +* poll for incoming events on a CEP. The input parameter is the CID. +* +* SYNOPSIS +*/ +typedef struct _ual_cep_poll_ioctl +{ + ib_api_status_t status; + net32_t new_cid; + ib_mad_element_t element; + ib_grh_t grh; + uint8_t mad_buf[MAD_BLOCK_SIZE]; + +} ual_cep_poll_ioctl_t; +/* +* FIELDS +* status +* Status of the operation. +* +* new_cep +* For listen requests, CEP information of CEPs created in response +* to incoming REQs. +* +* mad_buf +* Payload of a received MAD (or failed send) +*****/ + + + +/****s* User-mode Access Layer/ual_cep_get_pdata_t +* NAME +* ual_cep_get_pdata_t +* +* DESCRIPTION +* IOCTL structure containing the input parameters for +* getting private data of CM RDMA request +* +* SYNOPSIS +*/ +typedef union _ual_cep_get_pdata_ioctl +{ + struct _ual_cep_get_pdata_ioctl_in + { + net32_t cid; + + } in; + + struct _ual_cep_get_pdata_ioctl_out + { + uint32_t pdata_len; + uint8_t pdata[IB_REJ_PDATA_SIZE]; + uint8_t resp_res; + uint8_t init_depth; + + } out; + +} ual_cep_get_pdata_ioctl_t; +/* +* FIELDS +* in.cid +* The CID for the target CEP. +* +* out.pdata_len +* The size of the private data +* +* out.pdata +* The private data. +*****/ + + + +/****s* User-mode Access Layer/ual_reg_shmid_ioctl_t +* NAME +* ual_reg_shmid_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* ib_create_shmid +* +* SYNOPSIS +*/ +typedef union _ual_reg_shmid_ioctl +{ + struct _ual_reg_shmid_ioctl_in + { + uint64_t h_pd; + ib_shmid_t shmid; + ib_mr_create_t mr_create; + + } in; + struct _ual_reg_shmid_ioctl_out + { + ib_api_status_t status; + uint64_t vaddr; + net32_t lkey; + net32_t rkey; + uint64_t h_mr; + + } out; + +} ual_reg_shmid_ioctl_t; +/* +* PARAMETERS +* in.h_pd +* A handle to an existing protection domain that the memory +* should be registered with. +* +* in.shmid +* An identifier to the shared memory region. +* +* in.mr_create +* Information describing the attributes of the memory region to +* register. +* +* out.status +* Status of the operation. +* +* out.vaddr +* Assigned I/O virtual address for the memory region. +* +* out.lkey +* The local access key associated with this registered memory +* region. +* +* out.rkey +* A key that may be used by a remote end-point when performing RDMA +* or atomic operations to this registered memory region. +* +* out.h_mr +* Upon successful completion of this call, this references a handle +* to the registered memory region. This handle is used when performing +* data transfers and to deregister the memory. +*****/ + + + +/****s* User-mode Access Layer/ual_send_sa_req_t +* NAME +* ual_send_sa_req_t +* +* DESCRIPTION +* IOCTL structure containing the input and output parameters for +* ib_create_shmid +* +* SYNOPSIS +*/ +typedef union _ual_send_sa_req_ioctl +{ + struct _ual_send_sa_req_ioctl_in + { + net64_t port_guid; + uint32_t timeout_ms; + uint32_t retry_cnt; + ib_user_query_t sa_req; + uint8_t attr[IB_SA_DATA_SIZE]; + uint64_t ph_sa_req; + uint64_t p_status; + + } in; + struct _ual_send_sa_req_ioctl_out + { + ib_api_status_t status; + uint64_t h_resp; + uint32_t resp_size; + + } out; + +} ual_send_sa_req_ioctl_t; +/* +* PARAMETERS +* in.sa_mad_data +* The SA request to send. +* +* in.attr +* The SA attribute data to send. +* +* in.ph_sa_req +* Pointer to UAL's query handle. The proxy fills this in +* before returning from the IOCTL handler to allow cancelation. +* +* in.p_status +* Pointer to status of the query. +* +* out.status +* Status of the query if it was initiated successfully. +* +* out.h_resp +* Handle to a response MAD. +* +* out.resp_size +* Size, in bytes, of the response MAD's buffer. +*****/ + + + +/****s* User-mode Access Layer/ual_cancel_sa_req_ioctl_t +* NAME +* ual_cancel_sa_req_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input parameters for cancelling an +* SA request. +* +* SYNOPSIS +*/ +typedef struct _ual_cancel_sa_req_ioctl +{ + uint64_t h_sa_req; + +} ual_cancel_sa_req_ioctl_t; +/* +* PARAMETERS +* h_sa_req +* Handle to the query to cancel. +*****/ + + + +/****s* User-mode Access Layer/ual_reg_pnp_ioctl_in_t +* NAME +* ual_reg_pnp_ioctl_in_t +* +* DESCRIPTION +* IOCTL structure containing the input parameters for registering +* for PnP events. +* +* SYNOPSIS +*/ +typedef struct _ual_reg_pnp_ioctl_in +{ + ib_pnp_class_t pnp_class; + void* __ptr64 sync_event; /* __ptr64 is correct for HANDLE types. */ + uint64_t p_status; + uint64_t p_hdl; + +} ual_reg_pnp_ioctl_in_t; +/* +* NOTES +* This is an asynchronous IOCTL. +* +* The output parameters are a ual_rearm_pnp_ioctl_out_t. +* +* PARAMETERS +* pnp_class +* Class of PnP events for which to register. +* +* p_status +* Pointer to user-mode status variable to set in failure case. +* +* p_hdl +* Pointer to user-mode handle variable to set in success case. +*****/ + + + +/****s* User-mode Access Layer/ual_poll_pnp_ioctl_t +* NAME +* ual_poll_pnp_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the parameters for retriveing data for +* a PnP event. +* +* SYNOPSIS +*/ +typedef union _ual_poll_pnp_ioctl +{ + struct _ual_poll_pnp_ioctl_in + { + uint64_t evt_hdl; + + } in; + struct _ual_poll_pnp_ioctl_out + { + ib_pnp_rec_t pnp_rec; + + } out; + +} ual_poll_pnp_ioctl_t; +/* +* NOTES +* This is a synchronous IOCTL. +* +* PARAMETERS +* in.evt_hdl +* Handle to a new PnP event. +* +* out.pnp_rec +* Buffer for the new PnP event. +*****/ + + + +/****s* User-mode Access Layer/ual_rearm_pnp_ioctl_in_t +* NAME +* ual_rearm_pnp_ioctl_in_t +* +* DESCRIPTION +* IOCTL structure containing the input parameters for requesting +* notification of the next PnP event. +* +* SYNOPSIS +*/ +typedef struct _ual_rearm_pnp_ioctl_in +{ + uint64_t pnp_hdl; + uint64_t last_evt_hdl; + uint64_t last_evt_context; + ib_api_status_t last_evt_status; + +} ual_rearm_pnp_ioctl_in_t; +/* +* NOTES +* This is an asynchronous IOCTL. +* +* The output parameters are a ual_rearm_pnp_ioctl_out_t. +* +* PARAMETERS +* pnp_hdl +* Handle to the PnP registration to rearm. +* +* last_evt_hdl +* Handle to the last PnP event processed. +* +* last_evt_context +* Context value to set for the last reported PnP event. +* +* last_evt_status +* Status value to return for the last reported PnP event. +*****/ + + + +/****s* User-mode Access Layer/ual_rearm_pnp_ioctl_out_t +* NAME +* ual_rearm_pnp_ioctl_out_t +* +* DESCRIPTION +* IOCTL structure containing the output parameters for a PnP event. +* +* SYNOPSIS +*/ +typedef struct _ual_rearm_pnp_ioctl_out +{ + uint64_t evt_hdl; + uint32_t evt_size; + +} ual_rearm_pnp_ioctl_out_t; +/* +* NOTES +* This is an asynchronous IOCTL. +* +* The output parameters are identical to that of ual_reg_pnp_ioctl_t. +* +* PARAMETERS +* evt_hdl +* Handle to a new PnP event. +* +* evt_size +* Buffer size needed to poll the new PnP event. +*****/ + + + +/****s* User-mode Access Layer/ual_dereg_pnp_ioctl_t +* NAME +* ual_dereg_pnp_ioctl_t +* +* DESCRIPTION +* IOCTL structure containing the input parameters for cancelling an +* SA request. +* +* SYNOPSIS +*/ +typedef struct _ual_dereg_pnp_ioctl +{ + uint64_t h_pnp; + +} ual_dereg_pnp_ioctl_t; +/* +* NOTES +* This is an asynchronous IOCTL. +* +* PARAMETERS +* h_pnp +* Handle to the PnP registration to deregister. +*****/ + +/****s* User-mode Access Layer/ual_ndi_notify_cq_ioctl_in_t +* NAME +* ual_ndi_notify_cq_ioctl_in_t +* +* DESCRIPTION +* IOCTL structure containing the input parameters for requesting +* notification of the next event on NDI CQ. +* +* SYNOPSIS +*/ +typedef struct _ual_ndi_notify_cq_ioctl_in +{ + uint64_t h_cq; + boolean_t notify_comps; + +} ual_ndi_notify_cq_ioctl_in_t; +/* +* NOTES +* This is an asynchronous IOCTL. +* +* FIELDS +* h_cq +* A handle to the CQ to modify. +* +* notify_comps +* Type of notification, requested. If TRUE - completion events, +* otherwise - errors. +* +*****/ + +/****s* User-mode Access Layer/ual_ndi_req_cm_ioctl_in_t +* NAME +* ual_ndi_req_cm_ioctl_in_t +* +* DESCRIPTION +* IOCTL structure containing the input parameters +* sending CM REQ . +* +* SYNOPSIS +*/ +typedef struct _ual_ndi_req_cm_ioctl_in +{ + ib_path_rec_t path; + uint64_t h_qp; + net64_t guid; + net32_t cid; + uint16_t dst_port; + uint8_t resp_res; + uint8_t init_depth; + uint8_t prot; + uint8_t pdata_size; + ib_cm_rdma_req_t pdata; + +} ual_ndi_req_cm_ioctl_in_t; +/* +* NOTES +* There is no output parameter. +* +* FIELDS +* h_qp +* A handle to the QP to modify. +* +* guid +* Local port GUID to which to bind to. +* +* cid +* CID of the CEP to use for the connection request. +* +* dst_port +* Destination port number. +* +* path +* Path record for the connection. +* +* resp_res +* Responder resources for the QP. +* +* init_depth +* Initiator depth for the QP. +* +* prot +* Protocol. +* +* pdata_size +* The size of following private RDMA CM data +* +* pdata +* Private data in format RDMA CM +* +*****/ + +/****s* User-mode Access Layer/ual_ndi_rep_cm_ioctl_in_t +* NAME +* ual_ndi_rep_cm_ioctl_in_t +* +* DESCRIPTION +* IOCTL structure containing the input parameters +* sending CM REP response . +* +* SYNOPSIS +*/ +typedef struct _ual_ndi_rep_cm_ioctl_in +{ + uint64_t h_qp; + net32_t cid; + uint8_t init_depth; + uint8_t resp_res; + uint8_t pdata_size; + uint8_t pdata[IB_REJ_PDATA_SIZE]; + +} ual_ndi_rep_cm_ioctl_in_t; +/* +* NOTES +* The output parameter is the new QP state (RTS). +* +* FIELDS +* h_qp +* A handle to the QP to modify. +* +* cid +* Connection ID. +* +* init_depth +* The maximum number of outstanding RDMA read/atomic operations. +* +* resp_res +* The maximum number of RDMA read/atomic operations from the recipient. +* +* pdata_size +* The size of following private data +* +* pdata +* Private data in format RDMA CM +* +*****/ + +/****s* User-mode Access Layer/ual_ndi_rej_cm_ioctl_in_t +* NAME +* ual_ndi_rej_cm_ioctl_in_t +* +* DESCRIPTION +* IOCTL structure containing the input parameters +* sending CM REJ response . +* +* SYNOPSIS +*/ +typedef struct _ual_ndi_rej_cm_ioctl_in +{ + net32_t cid; + uint8_t pdata_size; + uint8_t pdata[IB_REJ_PDATA_SIZE]; + +} ual_ndi_rej_cm_ioctl_in_t; +/* +* NOTES +* The output parameter is the new QP state (RTS). +* +* FIELDS +* cid +* Connection ID. +* +* pdata_size +* The size of following private data +* +* pdata +* Private data in format RDMA CM +* +*****/ + +/****s* User-mode Access Layer/ual_ndi_modify_qp_ioctl_in_t +* NAME +* ual_ndi_modify_qp_ioctl_in_t +* +* DESCRIPTION +* IOCTL structure containing the input parameters +* for MODIFY_QP . +* +* SYNOPSIS +*/ +typedef struct _ual_ndi_modify_qp_ioctl_in +{ + uint64_t h_qp; + ib_qp_mod_t qp_mod; + +} ual_ndi_modify_qp_ioctl_in_t; +/* +* NOTES +* The output parameter is the new QP state. +* +* FIELDS +* h_qp +* A handle to the QP to modify. +* +* qp_mod +* Attributes used for modifying the QP. +* +*****/ + + + +#endif /* __IB_UAL_IOCTL_H__ */ diff --git a/branches/WOF2-3/inc/iba/ib_at_ioctl.h b/branches/WOF2-3/inc/iba/ib_at_ioctl.h new file mode 100644 index 00000000..70b899e7 --- /dev/null +++ b/branches/WOF2-3/inc/iba/ib_at_ioctl.h @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +/* This file is shared between user- and kernel-mode */ + + +#ifndef _IB_AT_IOCTL_H_ +#define _IB_AT_IOCTL_H_ + +#include + + +#define IBAT_IOCTL_VERSION 5 + +#define IBAT_MAC_LEN 6 + + +#define IOCTL_IBAT( n ) \ + CTL_CODE( FILE_DEVICE_UNKNOWN, (0x800 + n), \ + METHOD_BUFFERED, FILE_ANY_ACCESS ) + +/** This IRP is used to return all available CAs ports number + * and port guid */ +#define IOCTL_IBAT_PORTS IOCTL_IBAT( 1 ) + +typedef struct _IBAT_PORT_RECORD +{ + UINT64 CaGuid; + UINT64 PortGuid; + UINT16 PKey; + UINT8 PortNum; + +} IBAT_PORT_RECORD; + +typedef struct _IOCTL_IBAT_PORTS_IN +{ + ULONG Version; + +} IOCTL_IBAT_PORTS_IN; + +typedef struct _IOCTL_IBAT_PORTS_OUT +{ + /** Total size, of the output buffer needed if the + * suplied buffer wasn't enough */ + ULONG Size; + LONG NumPorts; + IBAT_PORT_RECORD Ports[1]; + +} IOCTL_IBAT_PORTS_OUT; + + +/** This IRP is used to return all the ip addresses that + * are assigned to a port */ +#define IOCTL_IBAT_IP_ADDRESSES IOCTL_IBAT( 2 ) + +typedef struct _IOCTL_IBAT_IP_ADDRESSES_IN +{ + ULONG Version; + /** The guid of the port that we are querying for. May be + * zero if querying for IP addresses of all ports. */ + UINT64 PortGuid; + +} IOCTL_IBAT_IP_ADDRESSES_IN; + +typedef struct _IP_ADDRESS +{ + /** Might only be 4 or 6 */ + CHAR IpVersion; + /** Sized to support both IPv4 and IPv6 */ + UCHAR Address[16]; + +} IP_ADDRESS; + +typedef struct _IOCTL_IBAT_IP_ADDRESSES_OUT +{ + /** Total size of the output buffer needed if the + * suplied buffer wasn't enough */ + ULONG Size; + LONG AddressCount; + IP_ADDRESS Address[1]; + +} IOCTL_IBAT_IP_ADDRESSES_OUT; + + +/** This IRP is used to convert a remote MAC addresses to a remote GID */ +#define IOCTL_IBAT_MAC_TO_GID IOCTL_IBAT( 3 ) + +typedef struct _IOCTL_IBAT_MAC_TO_GID_IN +{ + ULONG Version; + UINT64 PortGuid; + UCHAR DestMac[IBAT_MAC_LEN]; + +} IOCTL_IBAT_MAC_TO_GID_IN; + +typedef struct _IOCTL_IBAT_MAC_TO_GID_OUT +{ + ib_gid_t DestGid; + +} IOCTL_IBAT_MAC_TO_GID_OUT; + +/** This IRP is used to get port record, corresponding to its (loca) IP address */ +#define IOCTL_IBAT_IP_TO_PORT IOCTL_IBAT( 4 ) + +typedef struct _IOCTL_IBAT_IP_TO_PORT_IN +{ + ULONG Version; + IP_ADDRESS Address; + +} IOCTL_IBAT_IP_TO_PORT_IN; + +typedef struct _IOCTL_IBAT_IP_TO_PORT_OUT +{ + IBAT_PORT_RECORD Port; + +} IOCTL_IBAT_IP_TO_PORT_OUT; + + +/** This IRP is used to convert a remote MAC addresses to a remote GID */ +#define IOCTL_IBAT_MAC_TO_PATH IOCTL_IBAT( 5 ) + +typedef struct _IOCTL_IBAT_MAC_TO_PATH_IN +{ + ULONG Version; + UINT64 PortGuid; + UCHAR DestMac[IBAT_MAC_LEN]; + +} IOCTL_IBAT_MAC_TO_PATH_IN; + +typedef struct _IOCTL_IBAT_MAC_TO_PATH_OUT +{ + ib_path_rec_t Path; + +} IOCTL_IBAT_MAC_TO_PATH_OUT; + + +#define IBAT_DEV_NAME L"\\Device\\ibat" +#define IBAT_DOS_DEV_NAME L"\\DosDevices\\Global\\ibat" +#define IBAT_WIN32_NAME L"\\\\.\\ibat" + +#endif /* _IB_AT_IOCTL_H_ */ diff --git a/branches/WOF2-3/inc/iba/ib_ci.h b/branches/WOF2-3/inc/iba/ib_ci.h new file mode 100644 index 00000000..89ec8816 --- /dev/null +++ b/branches/WOF2-3/inc/iba/ib_ci.h @@ -0,0 +1,3023 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#if !defined(__IB_CI_H__) +#define __IB_CI_H__ + +#include + + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + +/****h* IB_API/Verbs +* NAME +* Verbs -- Verbs implements the hardware and software glue to the OS layer. +* COPYRIGHT +* Copyright© 2001 Intel Corporation - All Rights Reserved. +* DESCRIPTION +* The Verbs API definition defines the interface mechanism between an IHV +* supplied driver component. It implements verbs functionality as defined +* Volume 1, of the InfiniBand(tm) specifications. +* AUTHOR +* Intel Corporation +* CREATION DATE +* XX.XX.XX +* NOTES +* Evolving Spec!! +* Invalid Handle checks are a mere signature checks in kernel mode. Hence +* passing invalid pointer would lead to panics in the kernel. For user mode +* These are verified for most verbs that need to take a kernel transition. +* Verbs those are entirely done in user mode that would affect speed path +* do not perform consistency checks. So invalid pointers would lead to +* application crash with core dumps. +*********** +*/ + + +/* + * Version that identifies this version of the header file for interface + * definition. + */ +#define VERBS_MAJOR_VER (0x0002) +#define VERBS_MINOR_VER (0x0000) + +#define VERBS_VERSION (((VERBS_MAJOR_VER) << 16) | (VERBS_MINOR_VER)) +#define MK_VERBS_VERSION(maj,min) ((((maj) & 0xFFFF) << 16) | \ + ((min) & 0xFFFF)) + +/* + * TODO: The in and out buffers should be separated (usage can still make + * both point to the same actual memory region. + */ +/****s* Verbs/ci_umv_buf_t +* NAME +* ci_umv_buf_t -- Vendor specific structure to facilitate user mode IO +* DESCRIPTION +* This structure is provided to assist the vendor specific user mode +* library to exchange information with its kernel mode driver. The +* user mode InfiniBand(tm) Access Layer will call the vendor specific +* module before a call is made to the kernel mode driver. The kernel mode +* driver is expected to know the format and data in the p_inout_buf, +* and copy any necessary data that must be handed to the user mode +* vendor library. +* PURPOSE +* command +* A command code that is understood by the vendor specific kernel +* mode driver. +* p_inout_buf +* The user mode component of the vendor specific library allocates +* this memory and passes information in this buffer. vendor is expected +* to set both the input and output buffer sizes appropriately. +* This information is required since the kernel mode proxy that passes +* this buffer to the kernel mode vendor specific library will copy the +* content of this buffer to a kernel mode buffer. The kernel mode +* vendor specific driver would copy the data that needs to be returned +* to the user mode component, and set the output size appropriately +* so that the proxy can now copy the data back to user mode buffer. +* +* In the Infiniband Access Layer, it is important to know the +* usage of umv_buf and whether the contents of the p_inout_buf +* can have embedded user-mode pointers. When invoked from an +* arbitrary thread context, Vendor driver can NOT access user-mode +* pointers of a user-process. +* input_size +* Size of the input buffer, must be set by the user mode vendor +* specific library. +* output_size +* Size of the output buffer. Must be set by the user mode component +* to specify the maximum size of the data expected from its kernel +* mode driver. The kernel mode driver would set the size to the exact +* size that needs to be returned to its user mode counterpart. +* status +* Indicates the status of the operation from the kernel mode vendor +* specific driver. The caller is supposed to initialize it appropriately +* to identify if an operation succeded, or failed. For e.g. when +* the user mode library is called after a resource creation, the user +* mode vendor specific code must be able to identify if there is +* post processing required, or if any resource allocation failed. +* SOURCE +*/ +typedef struct _umv_buf +{ + uint32_t command; + uint32_t status; + uint32_t input_size; + uint32_t output_size; + uint64_t p_inout_buf; +} ci_umv_buf_t; +/******/ + +/****f* Verbs/ci_completion_cb_t +* NAME +* ci_completion_cb_t -- Completion Notification callback. +* SYNOPSIS +*/ + +typedef void +(*ci_completion_cb_t)( + IN void *cq_context ); + +/* +* DESCRIPTION +* This function prototype indicates the parameter passed to ci_open_ca() +* to receive completion callbacks. +* PARAMETERS +* cq_context +* [in] Completion queue context passed during the ci_create_cq +* RETURN VALUE +* None +* NOTES +* The consumer only gets the cq_context. It is the client +* responsibility to store the cq_handle in the context after the creation +* time. So it can call ci_poll_cq() after the arrival of the notification. +* SEE ALSO +* ci_create_cq +****** +*/ + + +/****f* Verbs/ci_async_event_cb_t +* NAME +* ci_async_event_cb_t +* +* DESCRIPTION +* Asynchronous event notification routine. +* +* SYNOPSIS +*/ +typedef void +(*ci_async_event_cb_t)( + IN ib_event_rec_t* p_event_record ); +/* +* PARAMETERS +* p_event_record +* [in] Information describing the type of event that has occurred. +* +* NOTES +* This routine is called when an asynchronous event is generated by a +* channel adapter. The event notification record passed has relevant +* information on the type of the event, the source that caused the event, +* and the context associated. +* +* This routine is called at DISPATCH. +*****/ + + +/****f* Verbs/ci_open_ca +* NAME +* ci_open_ca -- open and possibly obtain a handle to access the HCA. +* SYNOPSIS +*/ + +typedef ib_api_status_t +(*ci_open_ca) ( + IN const ib_net64_t ca_guid, + IN const ci_async_event_cb_t pfn_async_event_cb, + IN const void* const ca_context, + OUT ib_ca_handle_t *ph_ca ); +/* +* DESCRIPTION +* This routine returns a handle to an open instance of a HCA. Client can call +* this routine to retrieve a new open instance. Only one instance of the +* open call is active at any time. If a duplicate open is called by the +* consumer or any other consumer, it IB_RESOURCE_BUSY error status is +* returned. +* PARAMETERS +* ca_guid +* [in] The HCA adapter's EUI64 identifier. Clients would use other +* enumeration API's to locate all available adapters and their +* guids in a system, e.g. GetCaGuids(), maintained by the IB +* Access Layer. User mode consumers also have the same mechanism +* to retrieve this information. +* pfn_async_event_cb +* [in] Asynchronous event handler, one per open instance. +* ca_context +* [in] Verbs consumer supplied value, which is returned on calls to +* handlers which in turn is used by clients to identify the +* open instance. +* ph_ca +* [out] Pointer to a handle to the newly open instance of the CA returned +* by the Verbs Provider. +* +* RETURN VALUE +* IB_SUCCESS +* The HCA is successfully opened and returned handle is valid. +* IB_INSUFFICIENT_RESOURCES +* Insufficient resources to satisfy request. +* IB_INVALID_PARAMETER +* Callback routine are not provided, GUID value is zero, or ph_ca is NULL +* IB_RESOURCE_BUSY +* The interface is already open by another consumer. +* IB_NOT_FOUND +* ca_guid passed is not valid +* +* SEE ALSO +* ci_query_ca, ci_modify_ca, ci_close_ca +*********/ + + +/* + * Structure is provided by caller, and must be valid while registered. + * Callback context for CA events references structure. + */ +typedef struct _ci_event_handler +{ + LIST_ENTRY entry; + ci_async_event_cb_t pfn_async_event_cb; + +} ci_event_handler_t; + +typedef void +(*ci_register_event_handler_t) ( + IN const ib_ca_handle_t h_ca, + IN ci_event_handler_t* p_reg); + +typedef void +(*ci_unregister_event_handler_t) ( + IN const ib_ca_handle_t h_ca, + IN ci_event_handler_t* p_reg); + + +/****f* Verbs/ci_um_open_ca +* NAME +* ci_um_open_ca -- Create a CA context for use by user-mode processes. +* SYNOPSIS +*/ +typedef ib_api_status_t +(*ci_um_open_ca_t) ( + IN const ib_ca_handle_t h_ca, + IN OUT ci_umv_buf_t* const p_umv_buf, + OUT ib_ca_handle_t* const ph_um_ca ); +/* +* DESCRIPTION +* This routine is used called on behalf of a user-mode application to +* establish a per-CA context in user-mode. +* +* PARAMETERS +* h_ca +* [in] Handle returned by an earlier call to ci_open_ca() +* p_umv_buf +* [in/out] Vendor specific parameter to support user mode IO. +* ph_um_ca +* [out] Handle to pass into ci_um_close_ca call to free any kernel +* resources allocated for the user-mode appliation. +* +* RETURN VALUE +* IB_SUCCESS +* The user-mode context information is returned successfully. +* IB_INSUFFICIENT_MEMORY +* The size of the p_ca_attr buffer, specified through p_size, is +* insufficient to store all of the CA attribute information. +* IB_INVALID_CA_HANDLE +* h_ca is invalid +* IB_INVALID_PARAMETER +* The p_umv_buf parameters are insufficient to complete the request. +* +* SEE ALSO +* ci_query_ca, ci_modify_ca, ci_close_ca +*********/ + + +/****f* Verbs/ci_query_ca +* NAME +* ci_query_ca -- Query the attributes of the HCA +* SYNOPSIS +*/ + +typedef ib_api_status_t +(*ci_query_ca) ( + IN const ib_ca_handle_t h_ca, + OUT ib_ca_attr_t *p_ca_attr OPTIONAL, + IN OUT uint32_t *p_size, + IN OUT ci_umv_buf_t *p_umv_buf OPTIONAL ); +/* +* DESCRIPTION +* This routine retrieves vital information about this hca. It returns +* necessary information about HCA guid, port guids, LID's assigned by +* the master SM. Clients can use this information to communicate with the +* Master SM node to perform path queries etc. +* PARAMETERS +* h_ca +* [in] Handle returned by an earlier call to ci_open_ca() +* p_ca_attr +* [out] CA attribute of this Host Channel adapter +* p_size +* [in/out] On input, this references the size of the data buffer +* referenced by the p_ca_attr parameter. +* On output, the number of bytes used or needed to copy all CA +* attribute information. +* p_umv_buf +* [in out] Vendor specific parameter to support user mode IO. +* RETURN VALUE +* IB_SUCCESS +* The attribute structure is returned completely. +* IB_INSUFFICIENT_MEMORY +* The size of the p_ca_attr buffer, specified through p_size, is +* insufficient to store all of the CA attribute information. +* IB_INVALID_CA_HANDLE +* h_ca is invalid +* IB_INVALID_PARAMETER +* p_size is NULL. +* NOTES +* Users may obtain the size of the data buffer required to obtain the +* CA attributes by calling this function with p_ca_attr set to NULL. +* The channel interface will then return the necessary size in the +* variable referenced by the p_size parameter. The caller can then allocate +* exact size and call this routine again. No partial information is returned +* if the size is not sufficient. +* SEE ALSO +* ci_open_ca, ci_modify_ca +********/ + +/****f* Verbs/ci_modify_ca +* NAME +* ci_modify_ca -- Modify port attributes and error counters +* SYNOPSIS +*/ + +typedef ib_api_status_t +(*ci_modify_ca) ( + IN const ib_ca_handle_t h_ca, + IN const uint8_t port_num, + IN const ib_ca_mod_t ca_mod, + IN const ib_port_attr_mod_t *p_port_attr_mod ); +/* +* DESCRIPTION +* Modifies either the P_KEY/Q_KEY violation counters, or sets the capability +* mask in the port attributes. This is effectively translated to PORTINFO +* values responded later when a MAD from SM or another node arrives to +* retrieve port related attributes. +* +* PARAMETERS +* h_ca +* [in] Handle returned by previous call to ci_open_ca() +* port_num +* [in] Port number, which needs to be modified. +* ca_mod +* [in] Command mask to perform operations on. +* p_port_attr_mod +* [in] port attribute which needs this change to be performed. +* if the capability bit is set, then that corresponding +* port capability is turned on. +* RETURN VALUE +* IB_SUCCESS +* Modify port attributes was performed +* IB_INVALID_PORT +* Invalid port number supplied in port_att. +* IB_INVALID_PARAMETER +* Unknown Command supplied in port_attr. +* IB_UNSUPPORTED +* Optional Q_KEY and P_KEY violation counters are not supported. +* IB_INVALID_CA_HANDLE +* h_ca is invalid +* NOTES +* No ownership checks are performed in the Verbs Provider Driver. +* All such permission checks are to be performed by the IB access layer +* before passing requests down to the HCA driver. These operations can be +* performed only by the special QP owner. Either the QP0 or QP1. Since port +* attributes is really maintained by the QP0 for SMA to respond with correct +* values, but the agent capability is really a QP1 functionality. +* SEE ALSO +* ci_open_ca, ci_query_ca, ci_close_ca +*/ +/********/ + +/****f* Verbs/ci_close_ca +* NAME +* ci_close_ca -- Close access to adapter via this h_ca +* SYNOPSIS +*/ + +typedef ib_api_status_t +(*ci_close_ca) ( + IN ib_ca_handle_t h_ca ); +/* +* DESCRIPTION +* This routine is called when the client no longer wishes to use HCA +* resources obtained via this h_ca. All resources allocated as part +* this handle during the ci_open_ca are destroyed. +* PARAMETERS +* h_ca +* [in] CA handle returned via the ci_open_ca() call. +* RETURN VALUE +* IB_SUCCESS +* The intend to destroy is registered. No further calls for +* completion or async event will be sent to this instance. When it is +* appropriate to destroy this instance, the event h_kevent is signaled. +* IB_RESOURCE_BUSY +* Some resource allocated via this handle is not freed. +* IB_INVALID_CA_HANDLE +* h_ca is invalid +* NOTES +* This call cannot be called from any of the notification functions invoked +* by the Verbs driver. For e.g. the completion handler or the async error +* callback provided during the ci_open_ca() call. The call will block until +* all references to this adapter object is closed which includes all the +* pending callbacks returning back to the verbs provider driver. +* +* Resources allocated during the ci_open_ca() is deallocated. Other resource +* cleanup are responsibility of the consumer . +* SEE ALSO +* ci_open_ca +********/ + +/****f* Verbs/ci_um_close_ca_t +* NAME +* ci_um_close_ca_t -- Close user-mode access to adapter via this h_ca +* SYNOPSIS +*/ +typedef void +(*ci_um_close_ca_t) ( + IN ib_ca_handle_t h_ca, + IN ib_ca_handle_t h_um_ca ); +/* +* DESCRIPTION +* This routine is called when the client no longer wishes to use HCA +* resources obtained via this h_ca. All resources allocated as part +* this handle during the ci_um_open_ca are destroyed. +* PARAMETERS +* h_ca +* [in] CA handle returned via the ci_open_ca() call. +* h_um_ca +* [in] CA handle returned via the ci_um_open_ca() call. +* +* RETURN VALUE +* This funtion does not return a value. +* NOTES +* This call is invoked from the context of a UM application when such an +* appliation closes the HCA in user-mode. +* +* Resources allocated during the ci_um_open_ca() are deallocated. +* +* SEE ALSO +* ci_um_open_ca +********/ + +/****f* Verbs/ci_allocate_pd +* NAME +* ci_allocate_pd -- Allocate a protection domain for this adapter. +* SYNOPSIS +*/ + +typedef ib_api_status_t +(*ci_allocate_pd) ( + IN const ib_ca_handle_t h_ca, + IN const ib_pd_type_t type, + OUT ib_pd_handle_t *ph_pd, + IN OUT ci_umv_buf_t *p_umv_buf OPTIONAL ); +/* +* DESCRIPTION +* This routine allocates a protection domain handle, which is later +* used to create QP's, Register Memory Regions, Bind Memory Windows +* and address vectors. Protection domain has no InfiniBand architectural +* attributes but the OS implements policy on its usage and allocation. +* PARAMETERS +* h_ca +* [in] Handle returned by ci_open_ca() +* +* type +* [in] Type of the protection domain. CA vendors may use this +* information to optimize how the PD is allocated. +* +* ph_pd +* [out] The handle to the newly created protection domain +* +* p_umv_buf +* [in/out] Vendor specific parameter to support user mode IO. +* +* RETURN VALUE +* IB_SUCCESS +* PD is successfully allocated and the ph_pd is valid. +* +* IB_INSUFFICIENT_RESOURCES +* No more PD's available for this adapter. +* +* IB_INVALID_CA_HANDLE +* HCA handle is not valid +* +* SEE ALSO +* ci_deallocate_pd +*******/ + +/****f* Verbs/ci_deallocate_pd +* NAME +* ci_deallocate_pd -- Deallocate a protection domain object. +* SYNOPSIS +*/ + +typedef ib_api_status_t +(*ci_deallocate_pd) ( + IN ib_pd_handle_t h_pd ); + +/* +* DESCRIPTION +* This routine deallocates a pd that is allocated via the ci_allocate_pd() +* call. The PD cannot be deallocated if it is still bound to a QP, any memory +* region, memory window or address vector. +* PARAMETERS +* h_pd +* [in] Handle allocated via the ci_allocate_pd() +* RETURN VALUE +* IB_SUCCESS +* PD is freed successfully +* IB_INVALID_PD_HANDLE +* pd_handle is invalid +* IB_RESOURCE_BUSY +* PD is probably still bound to some resource +* SEE ALSO +* ci_allocate_pd +******* +*/ + + +/****f* Verbs/ci_create_av +* NAME +* ci_create_av -- Create an address vector for use in UD. +* SYNOPSIS +*/ + +typedef ib_api_status_t +(*ci_create_av) ( + IN const ib_pd_handle_t h_pd, + IN const ib_av_attr_t *p_av_attr, + OUT ib_av_handle_t *ph_av, + IN OUT ci_umv_buf_t *p_umv_buf OPTIONAL ); + +/* +* DESCRIPTION +* This routine creates an address vector for use in unreliable datagram +* queue pairs. The information necessary to create the address vector +* handle is supplied in the ib_av_attr_t parameter. +* PARAMETERS +* h_pd +* [in] Protection domain to which this av is associated. +* p_av_attr +* [in] Parameters to create the address vector handle +* ph_av +* [out] Handle to use for datagram sends. +* p_umv_buf +* [in out] Vendor specific parameter to support user mode IO. +* RETURN VALUE +* IB_SUCCESS +* The create operation was successful +* IB_INSUFFICIENT_RESOURCES +* No more address handles are available +* IB_INVALID_PD_HANDLE +* The specified protection domain handle is invalid +* IB_INVALID_PORT +* Invalid port number supplied. +* IB_INVALID_PARAMETER +* One of the p_av_attr or p_av_attr was NULL. +* NOTES +* The values in the p_av_attr is not validated for correctness. The values +* in the attribute such as port number, protection domain etc are also +* validated during processing by the channel adapter. If the attribute +* validation fails a processing error IB_WCS_LOCAL_OP_ERR. +* SEE ALSO +* ci_allocate_pd +********/ + +/****f* Verbs/ci_query_av +* NAME +* ci_query_av -- Obtain the address vector associated with the handle +* SYNOPSIS +*/ + +typedef ib_api_status_t +(*ci_query_av) ( + IN const ib_av_handle_t h_av, + OUT ib_av_attr_t *p_av_attr, + OUT ib_pd_handle_t *ph_pd, + IN OUT ci_umv_buf_t *p_umv_buf OPTIONAL ); + +/* +* DESCRIPTION +* This routine returns the address vector and pd_handle associated with the +* av_handle. +* PARAMETERS +* h_av +* [in] Handle to the address vector +* p_av_attr +* [out] address vector data referred by the av_handle +* ph_pd +* [out] pd handle associated with the av_handle +* p_umv_buf +* [in out] Vendor specific parameter to support user mode IO. +* RETURN VALUE +* IB_SUCCESS +* returned values are valid +* IB_INVALID_AV_HANDLE +* The address vector handle was invalid +* IB_INVALID_PARAMETER +* One of the p_av_attr or ph_pd parameters was NULL. +* IB_INVALID_PORT +* Invalid port number passed in the Address Vector. +* SEE ALSO +* ci_create_av, ci_modify_av +******* +*/ + +/****f* Verbs/ci_modify_av +* NAME +* ci_modify_av -- Change the address vector referred by the av_handle +* SYNOPSIS +*/ + +typedef ib_api_status_t +(*ci_modify_av) ( + IN const ib_av_handle_t h_av, + IN const ib_av_attr_t *p_av_attr, + IN OUT ci_umv_buf_t *p_umv_buf OPTIONAL ); +/* +* DESCRIPTION +* This routine allows a consumer to modify the address information +* passed. +* PARAMETERS +* h_av +* [in] Address handle that needs to be updated with new info. +* p_av_attr +* [in] New address vector to associate with the addr_handle. +* p_umv_buf +* [in out] Vendor specific parameter to support user mode IO. +* RETURN VALUE +* IB_SUCCESS +* Operation was successful +* IB_INVALID_AV_HANDLE +* The address vector handle was invalid +* IB_INVALID_PORT +* Invalid port number passed in the Address Vector. +* IB_INVALID_PARAMETER +* The parameter p_av_attr is not valid. +* NOTES +* The values in the p_av_attr is not validated for correctness. The values +* in the attribute such as port number, protection domain etc are validated +* during processing by the channel adapter. If the attribute validation fails +* a processing error IB_WCS_LOCAL_OP_ERR. +* SEE ALSO +* ci_create_av, ci_query_av +********* +*/ + +/****f* Verbs/ci_destroy_av +* NAME +* ci_destroy_av -- Destroy the address vector +* SYNOPSIS +*/ + +typedef ib_api_status_t +(*ci_destroy_av) ( + IN const ib_av_handle_t h_av ); +/* +* DESCRIPTION +* This routine destroys the specified address handle. After the routine +* returns, this address handle cannot be used to reference the destination. +* PARAMETERS +* h_av +* [in] Handle that needs to be destroyed. +* RETURN VALUE +* IB_SUCCESS +* Operation was successful. +* IB_INVALID_AV_HANDLE +* The address vector handle was invalid +* SEE ALSO +* ci_create_av +********* +*/ + +/****f* Verbs/ci_create_srq +* NAME +* ci_create_srq -- Create a Shared Queue Pair for the specified HCA +* SYNOPSIS +*/ + +typedef ib_api_status_t +(*ci_create_srq) ( + IN const ib_pd_handle_t h_pd, + IN const void *srq_context, + IN const ci_async_event_cb_t pfn_async_event_cb, + IN const ib_srq_attr_t * const p_srq_attr, + OUT ib_srq_handle_t *ph_srq, + IN OUT ci_umv_buf_t *p_umv_buf OPTIONAL ); +/* +* DESCRIPTION +* A new shared queue pair is created on the specified HCA. The initial set of +* parameters is provided by the srq_attr_mask/p_srq_attr parameters. The newly created +* queue pair with its attributes is returned in the srq_query_attr structure. +* PARAMETERS +* h_pd +* [in] Handle to Protection Domain +* srq_context +* [in] A user specified context passed in a asynchronous error callback. +* pfn_async_event_cb +* [in] Asynchronous event handler. +* p_srq_attr +* [in out] Initial attributes with which the srq must be created. +* ph_srq +* [out] Handle to the queue pair newly created. +* p_umv_buf +* [in out] Vendor specific parameter to support user mode IO. +* RETURN VALUE +* IB_SUCCESS +* The queue pair is successfully created with the provided initial +* attributes. +* IB_INSUFFICIENT_RESOURCES +* Insufficient resources to complete request. +* IB_INVALID_PD_HANDLE +* pd_handle supplied in the qp_create_attr is invalid +* IB_INVALID_SERVICE_TYPE +* Invalid service type. +* IB_INVALID_MAX_WRS +* Max WRS capacity exceeded +* IB_INVALID_MAX_SGE +* Max Scatter gather element request exceeds HCA capability +* IB_UNSUPPORTED +* Unreliable datagram not supported +* IB_INVALID_PARAMETER +* The parameter p_create_attr is invalid. +* NOTES +* If any of the initial parameters is not valid, the queue pair is not +* created. If the routine call is not successful then the contents of +* qp_query_attr and qp_handle is undefined. +* SEE ALSO +* ci_query_qp, ci_modify_qp, ci_destroy_qp +****** +*/ + + +/****f* Verbs/ci_modify_srq +* NAME +* ci_modify_srq -- Modify attributes of the specified SRQ. +* SYNOPSIS +*/ + +typedef ib_api_status_t +(*ci_modify_srq) ( + IN const ib_srq_handle_t h_srq, + IN const ib_srq_attr_t* const p_srq_attr, + IN const ib_srq_attr_mask_t srq_attr_mask, + IN OUT ci_umv_buf_t *p_umv_buf OPTIONAL ); +/* +* DESCRIPTION +* This routine is used to modify the srq states or other attributes of the +* srq. On successful completion, the requested state transition is performed +* and the srq is transitioned to the required state. +* PARAMETERS +* h_srq +* [in] Handle to the queue pair whose state is to be modified. +* p_srq_attr +* [in] Initial attributes with which the srq must be created. +* srq_attr_mask +* [in] Flags, specifying valid fields in ib_srq_attr_t structure. +* p_umv_buf +* [in out] Vendor specific parameter to support user mode IO. +* RETURN VALUE +* IB_SUCCESS +* The operation was successful and the QP attributes are modified +* to the requested state. +* IB_INSUFFICIENT_RESOURCES +* Insufficient resources to complete the requested operation. +* IB_INVALID_QP_HANDLE +* Invalid QP handle was passed. +* IB_UNSUPPORTED +* Requested operation is not supported, for e.g. Atomic operations. +* IB_QP_INVALID_STATE +* Invalid state transition request. Current QP state not in allowable +* state. +* IB_INVALID_PARAMETER +* The parameter p_modify_attr is not valid. +* SEE ALSO +* ci_create_qp, ci_destroy_qp, ci_query_qp +****** +*/ + + +/****f* Verbs/ci_query_srq +* NAME +* ci_query_srq -- Query the current SRQ attributes +* SYNOPSIS +*/ + +typedef ib_api_status_t +(*ci_query_srq) ( + IN const ib_srq_handle_t h_srq, + OUT ib_srq_attr_t* const p_srq_attr, + IN OUT ci_umv_buf_t *p_umv_buf OPTIONAL ); +/* +* DESCRIPTION +* This routine queries the current attributes for the srq +* corresponding to h_srq. The attributes are returned in p_query_attr. +* Depending on the current state of the srq, some of the fields in the +* attribute structure may not be valid. +* PARAMETERS +* h_srq +* [in] Handle to the srq for which the attributes are being retrieved +* p_srq_attr +* [out] Pointer to the ib_srq_query_t structure where the current +* attributes of the srq is returned. +* p_umv_buf +* [in out] Vendor specific parameter to support user mode IO. +* RETURN VALUE +* IB_SUCCESS +* The values returned in p_qp_attr are valid. +* IB_INVALID_QP_HANDLE +* The h_qp supplied is not a valid handle. +* IB_INVALID_PARAMETER +* Parameter p_qp_attr is not valid. +* SEE ALSO +* ci_create_qp, ci_destroy_qp, ci_modify_srq +***** +*/ + + +/****f* Verbs/ci_destroy_srq +* NAME +* ci_destroy_srq -- Destroy the specified Shared Queue Pair. +* SYNOPSIS +*/ + +typedef ib_api_status_t +(*ci_destroy_srq) ( + IN const ib_srq_handle_t h_srq ); +/* +* DESCRIPTION +* Destroys the associated srq. The srq could have outstanding work requests +* when this call is made. Any outstanding work requests *SHALL NOT* be +* completed after this routine returns. +* PARAMETERS +* h_srq +* [in] Handle to the srq that needs to be destroyed. +* RETURN VALUE +* IB_SUCCESS +* The intend to destroy this queue pair is registered and no further +* work requests will be processed. When no pending callbacks are in +* progress, the destroy_callback function is invoked which marks the +* destruction of the resource. The consumer can be guaranteed that +* no future callbacks will be propagated on behalf of this resource. +* IB_INVALID_QP_HANDLE +* The handle passed is invalid. +* IB_RESOURCE_BUSY +* If the queue pair is a unreliable datagram service type, and +* is still bound to a multicast group. +* NOTES +* This call cannot be called from any of the notification functions invoked +* by the Verbs driver. For e.g. the completion handler or the async error +* callback provided during the ci_open_ca() call. The call will block until +* all references to this adapter object is closed which includes all the +* pending callbacks returning back to the verbs provider driver. +* SEE ALSO +* ci_cquery_qp, ci_destroy_qp, ci_modify_srq +****** +*/ + + +/****f* Verbs/ci_create_qp +* NAME +* ci_create_qp -- Create a Queue Pair for the specified HCA +* SYNOPSIS +*/ + +typedef ib_api_status_t +(*ci_create_qp) ( + IN const ib_pd_handle_t h_pd, + IN const void *qp_context, + IN const ci_async_event_cb_t pfn_async_event_cb, + IN const ib_qp_create_t *p_create_attr, + OUT ib_qp_attr_t *p_qp_attr, + OUT ib_qp_handle_t *ph_qp, + IN OUT ci_umv_buf_t *p_umv_buf OPTIONAL ); +/* +* DESCRIPTION +* A new queue pair is created on the specified HCA. The initial set of +* parameters is provided by the qp_create_attr parameter. The newly created +* queue pair, with its attributes such as the qp number is returned +* in the qp_query_attr structure. +* PARAMETERS +* h_pd +* [in] Handle to Protection Domain +* qp_context +* [in] A user specified context passed in a asynchronous error callback. +* pfn_async_event_cb +* [in] Asynchronous event handler. +* p_create_attr +* [in] Initial attributes with which the qp must be created. +* p_qp_attr +* [out] Attributes of the newly created queue pair. +* ph_qp +* [out] Handle to the queue pair newly created. +* p_umv_buf +* [in out] Vendor specific parameter to support user mode IO. +* RETURN VALUE +* IB_SUCCESS +* The queue pair is successfully created with the provided initial +* attributes. +* IB_INSUFFICIENT_RESOURCES +* Insufficient resources to complete request. +* IB_INVALID_PD_HANDLE +* pd_handle supplied in the qp_create_attr is invalid +* IB_INVALID_CQ_HANDLE +* cq_handle supplied for send/receive is invalid. +* IB_INVALID_SERVICE_TYPE +* Invalid service type. +* IB_INVALID_MAX_WRS +* Max WRS capacity exceeded +* IB_INVALID_MAX_SGE +* Max Scatter gather element request exceeds HCA capability +* IB_UNSUPPORTED +* Unreliable datagram not supported +* IB_INVALID_PARAMETER +* The parameter p_create_attr is invalid. +* NOTES +* If any of the initial parameters is not valid, the queue pair is not +* created. If the routine call is not successful then the contents of +* qp_query_attr and qp_handle is undefined. +* SEE ALSO +* ci_create_spl_qp, ci_query_qp, ci_modify_qp, ci_destroy_qp +****** +*/ + +/****f* Verbs/ci_create_spl_qp +* NAME +* ci_create_spl_qp -- Create a special queue pair. +* SYNOPSIS +*/ + +typedef ib_api_status_t +(*ci_create_spl_qp) ( + IN const ib_pd_handle_t h_pd, + IN const uint8_t port_num, + IN const void *qp_context, + IN const ci_async_event_cb_t pfn_async_event_cb, + IN const ib_qp_create_t *p_create_attr, + OUT ib_qp_attr_t *p_qp_attr, + OUT ib_qp_handle_t *ph_qp ); +/* +* DESCRIPTION +* Create and return a handle to for the indicated service type on the +* specified port. QP service types can be one of SMI, GSI, Raw IPv6 or +* Raw ether type as specified in qp_type_t. +* PARAMETERS +* h_pd +* [in] Handle to the PD on which the special queue pair is to be created. +* port_num +* [in] Port number for which this special queue pair is created. +* qp_context +* [in] User specified context passed during the async error callback +* routine. +* pfn_async_event_cb +* [in] Asynchronous event handler. +* p_create_attr +* [in] Initial set of attributes with which the queue pair is to be +* created. +* p_qp_attr +* [out] QP attributes after the qp is successfully created. +* +* ph_qp +* [out] Handle to the special qp after its creation. +* RETURN VALUE +* IB_SUCCESS +* The special queue pair of the requested service type is created. +* IB_INSUFFICIENT_RESOURCES +* Insufficient resources to satisfy the request. +* IB_NOT_FOUND +* Indicated port guid is not found on this HCA. +* IB_INVALID_CQ_HANDLE +* Invalid cq handle passed to send/receive side. +* IB_INVALID_MAX_WRS +* Max WRS capacity exceeded +* IB_INVALID_MAX_SGE +* Max Scatter gather element request exceeds HCA capability +* IB_RESOURCE_BUSY +* Applicable to SMI/GSI qp's. This return code means that the SMI/GSI +* QP is already allocated. +* IB_INVALID_PD +* Invalid protection domain supplied. +* IB_INVALID_PORT +* Invalid port number supplied. +* IB_UNSUPPORTED +* Raw datagram unsupported. +* IB_INVALID_PARAMETER +* The parameter p_create_attr is not valid. +* NOTES +* This verb is privileged and only available in kernel mode. The User mode +* clients that need access to SMI/GSI qp's is recommended to do this via +* a higher level of abstraction. +* SEE ALSO +* ci_create_qp, ci_query_qp, ci_modify_qp, ci_destroy_qp +****** +*/ + +/****f* Verbs/ci_modify_qp +* NAME +* ci_modify_qp -- Modify attributes of the specified QP. +* SYNOPSIS +*/ + +typedef ib_api_status_t +(*ci_modify_qp) ( + IN const ib_qp_handle_t h_qp, + IN const ib_qp_mod_t *p_modify_attr, + OUT ib_qp_attr_t *p_qp_attr OPTIONAL, + IN OUT ci_umv_buf_t *p_umv_buf OPTIONAL ); +/* +* DESCRIPTION +* This routine is used to modify the qp states or other attributes of the +* QP. On successful completion, the requested state transition is performed +* and the QP is transitioned to the required state. +* PARAMETERS +* h_qp +* [in] Handle to the queue pair whose state is to be modified. +* p_modify_attr +* [in] Specifies what attributes need to be modified in the qp. +* p_qp_attr +* [out] QP attributes after the qp is successfully created. +* p_umv_buf +* [in out] Vendor specific parameter to support user mode IO. +* RETURN VALUE +* IB_SUCCESS +* The operation was successful and the QP attributes are modified +* to the requested state. +* IB_INSUFFICIENT_RESOURCES +* Insufficient resources to complete the requested operation. +* IB_INVALID_QP_HANDLE +* Invalid QP handle was passed. +* IB_UNSUPPORTED +* Requested operation is not supported, for e.g. Atomic operations. +* IB_QP_INVALID_STATE +* Invalid state transition request. Current QP state not in allowable +* state. +* IB_INVALID_PKEY +* Pkey specified in modify request not valid entry in P_KEY table. Or +* index is out of range. +* IB_INVALID_APM_STATE +* Invalid automatic path migration state specified in the request. +* IB_INVALID_PARAMETER +* The parameter p_modify_attr is not valid. +* NOTES +* Refer to Table 79 in chapter 11, Volume 1 of the InfiniBand Specifications. +* SEE ALSO +* ci_create_qp, ci_create_spl_qp, ci_query_qp +****** +*/ + +/****f* Verbs/ci_ndi_modify_qp +* NAME +* ci_ndi_modify_qp -- Modify attributes of the specified QP. +* SYNOPSIS +*/ + +typedef ib_api_status_t +(*ci_ndi_modify_qp) ( + IN const ib_qp_handle_t h_qp, + IN const ib_qp_mod_t *p_modify_attr, + OUT ib_qp_attr_t *p_qp_attr OPTIONAL, + IN const uint32_t buf_size, + IN OUT uint8_t* const p_outbuf); +/* +* DESCRIPTION +* This routine is used to modify the qp states or other attributes of the +* QP. On successful completion, the requested state transition is performed +* and the QP is transitioned to the required state. +* PARAMETERS +* h_qp +* [in] Handle to the queue pair whose state is to be modified. +* p_modify_attr +* [in] Specifies what attributes need to be modified in the qp. +* p_qp_attr +* [out] QP attributes after the qp is successfully created. +* buf_size +* [in] Size of the output buffer +* p_outbuf +* [in out] Output buffer +* +* RETURN VALUE +* IB_SUCCESS +* The operation was successful and the QP attributes are modified +* to the requested state. +* IB_INSUFFICIENT_RESOURCES +* Insufficient resources to complete the requested operation. +* IB_INVALID_QP_HANDLE +* Invalid QP handle was passed. +* IB_UNSUPPORTED +* Requested operation is not supported, for e.g. Atomic operations. +* IB_QP_INVALID_STATE +* Invalid state transition request. Current QP state not in allowable +* state. +* IB_INVALID_PKEY +* Pkey specified in modify request not valid entry in P_KEY table. Or +* index is out of range. +* IB_INVALID_APM_STATE +* Invalid automatic path migration state specified in the request. +* IB_INVALID_PARAMETER +* The parameter p_modify_attr is not valid. +* NOTES +* Refer to Table 79 in chapter 11, Volume 1 of the InfiniBand Specifications. +* SEE ALSO +* ci_create_qp, ci_create_spl_qp, ci_query_qp +****** +*/ + +/****f* Verbs/ci_query_qp +* NAME +* ci_query_qp -- Query the current QP attributes +* SYNOPSIS +*/ + +typedef ib_api_status_t +(*ci_query_qp) ( + IN const ib_qp_handle_t h_qp, + OUT ib_qp_attr_t* const p_qp_attr, + IN OUT ci_umv_buf_t *p_umv_buf OPTIONAL ); +/* +* DESCRIPTION +* This routine queries the current attributes for the QP +* corresponding to h_qp. The attributes are returned in p_query_attr. +* Depending on the current state of the QP, some of the fields in the +* attribute structure may not be valid. +* PARAMETERS +* h_qp +* [in] Handle to the QP for which the attributes are being retrieved +* p_qp_attr +* [out] Pointer to the ib_qp_query_t structure where the current +* attributes of the QP is returned. +* p_umv_buf +* [in out] Vendor specific parameter to support user mode IO. +* RETURN VALUE +* IB_SUCCESS +* The values returned in p_qp_attr are valid. +* IB_INVALID_QP_HANDLE +* The h_qp supplied is not a valid handle. +* IB_INVALID_PARAMETER +* Parameter p_qp_attr is not valid. +* SEE ALSO +* ci_create_qp +***** +*/ + +/****f* Verbs/ci_destroy_qp +* NAME +* ci_destroy_qp -- Destroy the specified Queue Pair. +* SYNOPSIS +*/ + +typedef ib_api_status_t +(*ci_destroy_qp) ( + IN const ib_qp_handle_t h_qp, + IN const uint64_t timewait ); +/* +* DESCRIPTION +* Destroys the associated QP. The QP could have outstanding work requests +* when this call is made. Any outstanding work requests *SHALL NOT* be +* completed after this routine returns. +* PARAMETERS +* h_qp +* [in] Handle to the qp that needs to be destroyed. +* timewait +* [in] Time (in microseconds) at which the QP should leave +* the timewait state and can be reused. +* +* RETURN VALUE +* IB_SUCCESS +* The intend to destroy this queue pair is registered and no further +* work requests will be processed. When no pending callbacks are in +* progress, the destroy_callback function is invoked which marks the +* destruction of the resource. The consumer can be guaranteed that +* no future callbacks will be propagated on behalf of this resource. +* IB_INVALID_QP_HANDLE +* The handle passed is invalid. +* IB_RESOURCE_BUSY +* If the queue pair is a unreliable datagram service type, and +* is still bound to a multicast group. +* NOTES +* This call cannot be called from any of the notification functions invoked +* by the Verbs driver. For e.g. the completion handler or the async error +* callback provided during the ci_open_ca() call. The call will block until +* all references to this adapter object is closed which includes all the +* pending callbacks returning back to the verbs provider driver. +* +* If the CQ associated with this QP is still not destroyed, the completions +* on behalf of this QP can still be pulled via the ci_poll_cq() call. Any +* resources allocated by the Channel Interface must be deallocated as part +* of this call. +* SEE ALSO +* ci_create_qp, ci_create_spl_qp +****** +*/ + +/****f* Verbs/ci_create_cq +* NAME +* ci_create_cq -- Create a completion queue (CQ) on the specified HCA. +* SYNOPSIS +*/ + +typedef ib_api_status_t +(*ci_create_cq) ( + IN const ib_ca_handle_t h_ca, + IN const void *cq_context, + IN const ci_async_event_cb_t pfn_async_event_cb, + IN ci_completion_cb_t completion_cb, + IN OUT uint32_t* const p_size, + OUT ib_cq_handle_t *ph_cq, + IN OUT ci_umv_buf_t *p_umv_buf OPTIONAL ); +/* +* DESCRIPTION +* The consumer must specify the minimum number of entries in the CQ. The +* exact number of entries the Channel Interface created is returned to the +* client. If the requested number of entries is larger than what this +* HCA can support, an error is returned. +* PARAMETERS +* h_ca +* [in] A handle to the open HCA +* cq_context +* [in] The context that is passed during the completion callbacks. +* pfn_async_event_cb +* [in] Asynchronous event handler. +* completion_cb +* [in] Callback for completion events +* p_size +* [in out] Points to a variable containing the number of CQ entries +* requested by the consumer. On completion points to the size of the +* CQ that was created by the provider. +* ph_cq +* [out] Handle to the newly created CQ on successful creation. +* p_umv_buf +* [in out] Vendor specific parameter to support user mode IO. +* RETURN VALUE +* IB_SUCCESS +* The operation was successful. +* IB_INVALID_CA_HANDLE +* The h_ca passed is invalid. +* IB_INSUFFICIENT_RESOURCES +* Insufficient resources to complete request. +* IB_INVALID_CQ_SIZE +* Requested CQ Size is not supported. +* IB_INVALID_PARAMETER +* one of the parameters was NULL. +* NOTES +* The consumer would need a way to retrieve the cq_handle associated with +* context being returned, so it can perform ci_poll_cq() to retrieve +* completion queue entries. The handle as such is not being passed, since +* there is no information in the handle that is visible to the consumer. +* Passing a context directly would help avoid any reverse lookup that the +* consumer would need to perform in order to identify it's own internal +* data-structures needed to process this completion completely. +* SEE ALSO +* ci_destroy_cq, ci_query_cq, ci_resize_cq +****** +*/ + +/****f* Verbs/ci_resize_cq +* NAME +* ci_resize_cq -- Modify the maximum number of entries the CQ could hold. +* SYNOPSIS +*/ + +typedef ib_api_status_t +(*ci_resize_cq) ( + IN const ib_cq_handle_t h_cq, + IN OUT uint32_t* const p_size, + IN OUT ci_umv_buf_t *p_umv_buf OPTIONAL ); +/* +* DESCRIPTION +* This routine allows the caller to modify the maximum number of entries +* the CQ could hold. It is possible to resize the CQ while there are +* entries in the CQ, and with outstanding work requests that will generate +* completions. If the entries in the CQ are more than the new size which is +* being created, an error is returned. +* PARAMETERS +* h_cq +* [in] Completion Queue handle +* p_size +* [in out] This parameter indicates the requested size of the CQ. On +* successful completion, the current size allocated is returned in +* this same parameter. +* p_umv_buf +* [in out] Vendor specific parameter to support user mode IO. +* RETURN VALUE +* IB_SUCCESS +* The resize operation was successful. +* IB_INVALID_CQ_HANDLE +* The CQ handle is invalid. +* IB_INSUFFICIENT_RESOURCES +* Insufficient resources to complete request. +* IB_INVALID_PARAMETER +* one of the parameters was NULL. +* IB_INVALID_CQ_SIZE +* Requested CQ Size is not supported. +* IB_OVERFLOW +* The CQ has more entries than the resize request. The CQ is not +* modified, and old entries still exist. +* NOTES +* If the consumer wishes to resize the CQ smaller than originally created, +* it is recommended to retrieve all entries before performing a CQ resize +* operation. It is left to the verb implementer on resize operations, to +* actually reduce the entries, or leave it as it. The consumer must make no +* assumptions on the successful completion, and should only rely on the +* size returned in p_size. +* SEE ALSO +* ci_create_cq +****** +*/ + +/****f* Verbs/ci_query_cq +* NAME +* ci_query_cq -- Query the number of entries configured for the CQ. +* SYNOPSIS +*/ + +typedef ib_api_status_t +(*ci_query_cq) ( + IN const ib_cq_handle_t h_cq, + OUT uint32_t *p_size, + IN OUT ci_umv_buf_t *p_umv_buf OPTIONAL ); +/* +* DESCRIPTION +* This routine returns the maximum number of entries this completion +* queue is configured. +* PARAMETERS +* h_cq +* [in] Handle to the completion queue +* p_size +* [out] The number of entries the completion queue is configured to hold +* p_umv_buf +* [in out] Vendor specific parameter to support user mode IO. +* RETURN VALUE +* IB_SUCCESS +* The call completed successfully, and the returned values are valid +* IB_INVALID_CQ_HANDLE +* The cq_handle passed is invalid. +* IB_INVALID_PARAMETER +* one of the parameters was NULL. +* SEE ALSO +* ci_create_cq, ci_resize_cq +****** +*/ + +/****f* Verbs/ci_destroy_cq +* NAME +* ci_destroy_cq -- Destroy a completion queue. +* SYNOPSIS +*/ + +typedef ib_api_status_t +(*ci_destroy_cq) ( + IN const ib_cq_handle_t h_cq ); +/* +* DESCRIPTION +* Destroys a completion queue. If any queue pairs are still bound +* to this CQ, the attempt to destroy will fail, and the CQ and associated +* resources are *NOT* destroyed. +* PARAMETERS +* cq_handle +* [in] Handle to the cq that is to be destroyed. +* RETURN VALUE +* IB_SUCCESS +* The intend to destroy the completion queue is registered successfully. +* The destroy_callback function will be invoked when it is safe and +* guarantees that no more completion callbacks will be invoked for +* this CQ. Any pending CQ notifications are discarded. +* IB_INVALID_CQ_HANDLE +* The CQ handle is invalid. +* IB_RESOURCE_BUSY +* Queue pairs may still be bound to this completion queue. +* IB_INVALID_PARAMETER +* one of the parameters was NULL. +* SEE ALSO +* ci_create_cq +* NOTES +* This call cannot be called from any of the notification functions invoked +* by the Verbs driver. For e.g. the completion handler or the async error +* callback provided during the ci_open_ca() call. The call will block until +* all references to this adapter object is closed which includes all the +* pending callbacks returning back to the verbs provider driver. +****** +*/ + + + +/****f* Verbs/ci_register_mr +* NAME +* ci_register_mr -- Register a memory region with the HCA. +* SYNOPSIS +*/ + +typedef ib_api_status_t +(*ci_register_mr) ( + IN const ib_pd_handle_t h_pd, + IN const ib_mr_create_t* const p_mr_create, + OUT net32_t* const p_lkey, + OUT net32_t* const p_rkey, + OUT ib_mr_handle_t * const ph_mr, + IN boolean_t um_call ); +/* +* DESCRIPTION +* This routine registers a virtually contiguous region of memory with the +* HCA. All memory regions that need to be used by the HCA must be registered +* prior to use in data transfer operations. On successful completion +* the region handle, lkey are returned. If remote access rights are specified +* then the rkey is also returned. +* PARAMETERS +* h_pd +* [in] Handle to the PD on which memory is being registered +* p_mr_create +* [in] Holds attributes for the region being registered. Look at +* ib_mr_create_t for more details. +* p_lkey +* [out] Local Key Attributes of the registered memory region +* p_rkey +* [out] Remote key of the registered memory region. The verbs provider +* is required to give this in the expected ordering on the wire. When +* rkey's are exchanged between remote nodes, no swapping of this data +* will be performed. +* ph_mr +* [out] Handle to the registered memory region. This handle is used when +* submitting work requests to refer to this region of memory. +* um_call +* [in] Boolean indicating whether the registration originated in user-mode. +* RETURN VALUE +* IB_SUCCESS +* Registration with the adapter was successful. +* IB_INSUFFICIENT_RESOURCES +* Insufficient resources to satisfy request. +* IB_INVALID_PARAMETER +* One of the input pointers was NULL. +* IB_INVALID_PD_HANDLE +* Invalid mr_pdhandle +* IB_INVALID_PERMISSION +* Invalid access rights. +* NOTES +* In addition to registration, the routine also pins memory, so that the +* physical page associated with the virtual address does not get swapped +* out during the time the HCA is attempting to transfer data to this +* address. If the memory is not pinned, this could lead to data-corruption +* and unpredictable behavior by the operating environment. +* +* SEE ALSO +* ci_deregister_mr, ci_query_mr, ci_register_pmr, ci_modify_mr, +* ci_register_smr +****** +*/ + +/****f* Verbs/ci_register_pmr +* NAME +* ci_register_pmr -- Register a physical memory region with the HCA. +* SYNOPSIS +*/ + +typedef ib_api_status_t +(*ci_register_pmr) ( + IN const ib_pd_handle_t h_pd, + IN const ib_phys_create_t*const p_pmr_create, + IN OUT uint64_t* const p_vaddr, + OUT net32_t* const p_lkey, + OUT net32_t* const p_rkey, + OUT ib_mr_handle_t* const ph_mr, + IN boolean_t um_call ); +/* +* DESCRIPTION +* This routine registers an array of physical pages as a single virtually +* contiguous region with the HCA. All memory regions that need to be used by +* the HCA must be registered prior to use in data transfer operations. +* On successful completion the region handle, lkey and rkey used for +* local and remote access authentication are returned. +* PARAMETERS +* h_pd +* [in] Handle to the PD on which memory is being registered +* p_pmr_create +* [in] Holds attributes for the region being registered. +* p_vaddr +* [in/out] On input, references the requested virtual address for the +* start of the physical region. On output, references the actual +* virtual address assigned to the registered region. +* p_lkey +* [out] Local key of the registered memory region +* p_rkey +* [out] Remote key of the registered memory region.The verbs provider +* is required to give this in the expected ordering on the wire. When +* rkey's are exchanged between remote nodes, no swapping of this data +* will be performed. +* ph_mr +* [out] Handle to the registered memory region. This handle is used when +* submitting work requests to refer to this region of memory. +* um_call +* [in] Boolean indicating whether the registration originated in user-mode. +* RETURN VALUE +* IB_SUCCESS +* Registration with the adapter was successful. +* IB_INSUFFICIENT_RESOURCES +* Insufficient resources to satisfy request. +* IB_INVALID_PARAMETER +* Invalid length or address in p_mr_create. Also returned if the page_size +* passed is not one of supported page sizes by the HCA. +* IB_INVALID_PD_HANDLE +* Invalid mr_pdhandle +* IB_INVALID_PERMISSION +* Invalid access rights. +* PORTABILITY +* Kernel Mode only +* NOTES +* Remote and Atomic access settings in ib_access_ctrl_t, requires local +* write access to be enabled, otherwise IB_INVALID_PERMISSION is returned. +* The p_vaddr returned could be different from the vaddr specified in +* p_pmr_create. If the requested virtual addr offset in a page does not +* match, the channel interface is free to pick and assign a pseudo virtual +* address. The address constructed is not a system virtual address, and only +* meaningful to the adapter to which this registration is targeted. +* SEE ALSO +* ci_deregister_mr, ci_query_mr, ci_register_mr, ci_modify_mr, +* ci_register_smr +****** +*/ + +/****f* Verbs/ci_query_mr +* NAME +* ci_query_mr -- Query attributes of a registered memory region +* SYNOPSIS +*/ + +typedef ib_api_status_t +(*ci_query_mr) ( + IN const ib_mr_handle_t h_mr, + OUT ib_mr_attr_t* const p_mr_query ); +/* +* DESCRIPTION +* This routine retrieves the memory region attributed of a +* registered memory region. The memory handle could have been +* obtained via ci_register_mr or ci_register_pmr. +* PARAMETERS +* h_mr +* [in] Memory handle for which the attributes need to be retrieved. +* p_mr_query +* [out] Attributes of the memory region associated with memory handle. +* RETURN VALUE +* IB_SUCCESS +* The routine completed successfully and attributes returned +* are valid. +* IB_INVALID_MR_HANDLE +* The memory handle is not valid. +* IB_INVALID_PARAMETER +* One of the input pointers was NULL. +* NOTES +* Invalid handle checks are a mere signature checks in kernel mode. +* Drivers in kernel are expected to be good corporate citizens. +* In user mode, proper ownership is determined before passing handles +* down to kernel to protect from rogue applications. +* SEE ALSO +* ci_register_mr, ci_register_pmr +****** +*/ + +/****f* Verbs/ci_modify_mr +* NAME +* ci_modify_mr -- Modify some or all parameters of a memory region. +* SYNOPSIS +*/ + +typedef ib_api_status_t +(*ci_modify_mr) ( + IN const ib_mr_handle_t h_mr, + IN const ib_mr_mod_t mr_modify_mask, + IN const ib_mr_create_t* const p_mr_create OPTIONAL, + OUT net32_t* const p_lkey, + OUT net32_t* const p_rkey, + IN const ib_pd_handle_t h_pd OPTIONAL, + IN boolean_t um_call ); +/* +* DESCRIPTION +* This routine modifies attributes of the specified memory region +* irrespective of whether the handle was obtained via ci_register_mr +* or ci_register_pmr. This verb conceptually performs a de-registration +* followed by a ci_register_mr. +* PARAMETERS +* h_mr +* [in] Handle to the memory region whose attributes are to be modified. +* mr_modify_mask +* [in] Command specifying which parts of the mem_region is valid. The +* command is specified as a bit mask. +* p_mr_create +* [in] Desired attributes that need to be modified for mem_handle. +* This is an optional parameter which can be NULL if mr_modify_mask +* is set to IB_MR_MOD_PD. +* p_lkey +* [out] The new l_key for this newly registered memory region. +* p_rkey +* [out] The new r_key for this newly registered memory region. +* The verbs provider is required to give this in the expected ordering +* on the wire. When rkey's are exchanged between remote nodes, no +* swapping of this data will be performed. +* h_pd +* [in] This parameter is valid only if the IB_MR_MOD_PD flag is set +* in the mr_modify_req parameter. This field supplies the new +* protection domain to which the modified region should be +* associated with. +* um_call +* [in] Boolean indicating whether the registration originated in user-mode. +* RETURN VALUE +* IB_SUCCESS +* The modify memory region request completed successfully. +* IB_RESOURCE_BUSY +* The memory region has windows bound to it. +* IB_INSUFFICIENT_RESOURCES +* Insufficient resources to complete the request. +* IB_INVALID_MR_HANDLE +* The memory handle supplied is not a valid memory region handle. +* IB_INVALID_PERMISSION +* Invalid access rights specified. +* IB_INVALID_PARAMETER +* A reference to the lkey or rkey was not provided or the specified +* modify mask is invalid. +* IB_INVALID_SETTING +* The specified memory region attributes are invalid. +* IB_INVALID_PD_HANDLE +* Protection domain handle supplied is not valid. +* NOTES +* Remote and Atomic access settings in ib_access_ctrl_t, requires local +* write access to be enabled. +* TBD: How to handle shared memory region being passed to modify_mem? +* SEE ALSO +* ci_register_mr, ci_register_pmr, ci_register_smr +******* +*/ + +/****f* Verbs/ci_modify_pmr +* NAME +* ci_modify_pmr -- Modify some or all parameters of a memory region. +* SYNOPSIS +*/ + +typedef ib_api_status_t +(*ci_modify_pmr) ( + IN const ib_mr_handle_t h_mr, + IN const ib_mr_mod_t mr_modify_mask, + IN const ib_phys_create_t* const p_pmr_create, + IN OUT uint64_t* const p_vaddr, + OUT net32_t* const p_lkey, + OUT net32_t* const p_rkey, + IN const ib_pd_handle_t h_pd OPTIONAL, + IN boolean_t um_call ); +/* +* DESCRIPTION +* This routine modifies attributes of the specified memory region +* irrespective of whether the handle was obtained via ci_register_mr +* or ci_register_pmr. This verb conceptually performs a de-registration +* followed by a ci_register_pmr. +* PARAMETERS +* h_mr +* [in] Handle to the memory region whose attributes are to be modified. +* mr_modify_mask +* [in] Command specifying which parts of the mem_region is valid. The +* command is specified as a bit mask. +* p_pmr_create +* [in] Desired attributes that need to be modified for mem_handle. +* p_vaddr +* [in/out] On input, references the requested virtual address for the +* start of the physical region. On output, references the actual +* virtual address assigned to the registered region. +* p_lkey +* [out] The new l_key for this newly registered physical memory region. +* p_rkey +* [out] The new r_key for this newly registered physical memory region. +* VPD is required to give this in the expected ordering on the wire. When +* rkey's are exchanged between remote nodes, no swapping of this data +* will be performed. +* h_pd +* [in] This parameter is valid only if the IB_MR_MOD_PD flag is set +* in the mr_modify_req parameter. This field supplies the new +* protection domain to which the modified region should be +* associated with. +* um_call +* [in] Boolean indicating whether the registration originated in user-mode. +* RETURN VALUE +* IB_SUCCESS +* The modify memory region request completed successfully. +* IB_RESOURCE_BUSY +* The memory region has windows bound to it. +* IB_INSUFFICIENT_RESOURCES +* Insufficient resources to complete the request. +* IB_INVALID_MR_HANDLE +* The memory handle supplied is not a valid memory region handle. +* IB_INVALID_PERMISSION +* Invalid access rights specified. +* IB_INVALID_PARAMETER +* A reference to the virtual address, lkey, rkey was not provided or +* the specified modify mask is invalid. +* IB_INVALID_SETTING +* The specified memory region attributes are invalid. +* PORTABILITY +* Kernel Mode only +* NOTES +* Remote and Atomic access settings in ib_access_ctrl_t, requires local +* write access to be enabled. +* SEE ALSO +* ci_register_mr, ci_register_pmr, ci_register_smr +********* +*/ + +/****f* Verbs/ci_register_smr +* NAME +* ci_register_smr -- Register a memory region using same physical pages as +* an existing memory region. +* SYNOPSIS +*/ + +typedef ib_api_status_t +(*ci_register_smr) ( + IN const ib_mr_handle_t h_mr, + IN const ib_pd_handle_t h_pd, + IN const ib_access_t access_ctrl, + IN OUT uint64_t* const p_vaddr, + OUT net32_t* const p_lkey, + OUT net32_t* const p_rkey, + OUT ib_mr_handle_t* const ph_mr, + IN boolean_t um_call ); +/* +* DESCRIPTION +* This routine registers a new memory region but shares the same set of +* physical pages associated with memory handle. For user mode applications +* the process *must* be owning memory handle for this call to be successful. +* PARAMETERS +* h_mr +* [in] Handle to memory region whose physical pages are being registered +* by this shared registration. +* h_pd +* [in] Handle to the PD on which memory is being registered +* access_ctrl +* [in] Memory access restrictions on the registered memory. +* p_vaddr +* [in/out] On input, references the requested virtual address for the +* start of the physical region. On output, references the actual +* virtual address assigned to the registered region. +* p_lkey +* [out] L_KEY for this memory region. +* p_rkey +* [out] R_KEY for this memory region. This is valid only when remote +* access is enabled for this region. The verbs provider +* is required to give this in the expected ordering on the wire. When +* rkey's are exchanged between remote nodes, no swapping of this data +* will be performed. +* ph_mr +* [out] Handle to the registered memory region. This handle is used when +* submitting work requests to refer to this region of memory. +* um_call +* [in] Boolean indicating whether the registration originated in user-mode. +* RETURN VALUE +* IB_SUCCESS +* The call is successful and a new region handle returned is valid. +* IB_INVALID_MR_HANDLE +* mr_handle is invalid. +* IB_INVALID_PD_HANDLE +* mr_pdhandle supplied is invalid. +* IB_INVALID_PERMISSION +* Invalid access rights passed in mr_access. +* NOTES +* ISSUE: how to deal with ci_deregister_mr, ci_modify_mr, ci_modify_pmr +* should we treat them as memory windows and fail those if a shared region +* was registered? +* SEE ALSO +* ci_register_mr, ci_register_pmr, ci_modify_mr, ci_modify_pmr +****** +*/ + +/****f* Verbs/ci_deregister_mr +* NAME +* ci_deregister_mr -- Deregister a memory region +* SYNOPSIS +*/ + +typedef ib_api_status_t +(*ci_deregister_mr) ( + IN const ib_mr_handle_t h_mr ); +/* +* DESCRIPTION +* This routine deregisters a memory region from the HCA. The region can +* de-registered only if there are no existing memory windows bound to +* this region, and if no existing shared memory regions were registered +* that refers to the same set of physical pages associated with the memory +* handle. If there are outstanding work requests referring to this memory +* region, then after this call is successful, those work requests will +* complete with WRS_LOCAL_PROTECTION_ERR. +* PARAMETERS +* h_mr +* [in] Memory handle that is being de-registered. +* RETURN VALUE +* IB_SUCCESS +* The memory de-registration was successful +* IB_INVALID_MR_HANDLE +* The memory handle supplied is not a valid memory handle. +* IB_RESOURCE_BUSY +* The memory region has active windows bound. +* NOTES +* SEE ALSO +* ci_register_mr, ci_register_pmr, ci_register_smr +****** +*/ + + +#ifdef CL_KERNEL +/****f* Verbs/ci_alloc_mlnx_fmr +* NAME +* ci_alloc_mlnx_fmr -- Allocate a Mellanox fast memory region with the HCA. +* SYNOPSIS +*/ +typedef ib_api_status_t +(*ci_alloc_mlnx_fmr) ( + IN const ib_pd_handle_t h_pd, + IN mlnx_fmr_create_t const *p_fmr_ctreate, + OUT mlnx_fmr_handle_t* const ph_fmr); +/* +* DESCRIPTION +* //TODO +* PARAMETERS +* h_pd +* [in] Handle to the PD on which fast memory is being registered +* mr_access_flags +* [in] mask of the access rights to the memory region +* p_fmr_attr +* [in] attribute of this fmr +* ph_fmr +* [out] Handle to the fast memory region. This handle is used when +* mapin/unmaping fmr +* +* RETURN VALUE +* IB_SUCCESS +* Registration with the adapter was successful. +* IB_INSUFFICIENT_RESOURCES +* Insufficient resources to satisfy request. +* IB_INVALID_PARAMETER +* One of the input pointers was NULL. +* IB_INVALID_PD_HANDLE +* Invalid pd handle +* IB_INVALID_PERMISSION +* Invalid access rights. +* +* NOTES +* The Alloc operation does not map nor pinned any memory. +* In order to use the FMR the user need to call map +* +* This is a Mellanox specific extension to verbs. +* +* SEE ALSO +* ci_dealloc_mlnx_fmr, ci_map_phys_mlnx_fmr, ci_unmap_mlnx_fmr +****** +*/ + + +/****f* Verbs/ci_map_phys_mlnx_fmr +* NAME +* ci_map_phys_mlnx_fmr -- Map a Mellanox fast memory region with a +* given page list. +* +* SYNOPSIS +*/ +typedef ib_api_status_t +(*ci_map_phys_mlnx_fmr) ( + IN const mlnx_fmr_handle_t h_fmr, + IN const uint64_t* const paddr_list, + IN const int list_len, + IN OUT uint64_t* const p_vaddr, + OUT net32_t* const p_lkey, + OUT net32_t* const p_rkey); +/* +* DESCRIPTION +* //TODO +* +* PARAMETERS +* h_fmr +* [in] Handle to the fast memory region that these pages map to +* page_list +* [in] array of phys address +* list_len +* [in] number of pages in the list +* p_vaddr +* [in/out] On input, references the requested virtual address for the +* start of the FMR. On output, references the actual +* virtual address assigned to the FMR. +* p_lkey +* [out] The local access key associated with this registered memory +* region. +* p_rkey +* [out] A key that may be used by a remote end-point when performing +* RDMA or atomic operations to this registered memory region. +* +* RETURN VALUE +* IB_SUCCESS +* Registration with the adapter was successful. +* IB_INSUFFICIENT_RESOURCES +* Insufficient resources to satisfy request. +* IB_INVALID_PARAMETER +* One of the input pointers was NULL. +* IB_INVALID_PD_HANDLE +* Invalid pd handle +* IB_INVALID_PERMISSION +* Invalid access rights. +* +* NOTES +* The Alloc operation does not map nor pinned any memory. +* In order to use the FMR the user need to call map +* +* This is a Mellanox specific extension to verbs. +* +* SEE ALSO +* ci_dealloc_mlnx_fmr, ci_alloc_mlnx_fmr, ci_unmap_mlnx_fmr +****** +*/ + + +/****f* Verbs/ci_unmap_mlnx_fmr +* NAME +* ci_unmap_mlnx_fmr -- UnMap a Mellanox fast memory region. +* SYNOPSIS +*/ +typedef ib_api_status_t +(*ci_unmap_mlnx_fmr) ( + IN const mlnx_fmr_handle_t *ph_fmr); +/* +* DESCRIPTION +* //TODO +* +* PARAMETERS +* h_fmr +* [in] Handle to the fast memory region that these pages map to +* +* RETURN VALUE +* IB_SUCCESS +* Registration with the adapter was successful. +* IB_INSUFFICIENT_RESOURCES +* Insufficient resources to satisfy request. +* IB_INVALID_PARAMETER +* One of the input pointers was NULL. +* IB_INVALID_PD_HANDLE +* Invalid pd handle +* IB_INVALID_PERMISSION +* Invalid access rights. +* +* NOTES +* The Alloc operation does not map nor pinned any memory. +* In order to use the FMR the user need to call map +* +* This is a Mellanox specific extension to verbs. +* +* SEE ALSO +* ci_dealloc_mlnx_fmr, ci_alloc_mlnx_fmr, ci_map_phy_mlnx_fmr +****** +*/ + + +/****f* Verbs/ci_dealloc_mlnx_fmr +* NAME +* ci_dealloc_mlnx_fmr -- Deallocate a Mellanox fast memory region. +* +* SYNOPSIS +*/ +typedef ib_api_status_t +(*ci_dealloc_mlnx_fmr) ( + IN mlnx_fmr_handle_t const h_fmr); +/* +* DESCRIPTION +* //TODO +* +* PARAMETERS +* h_fmr +* [in] Handle to the fast memory region. This handle is used when +* mapin/unmaping fmr +* +* RETURN VALUE +* IB_SUCCESS +* Registration with the adapter was successful. +* IB_INSUFFICIENT_RESOURCES +* Insufficient resources to satisfy request. +* IB_INVALID_PARAMETER +* One of the input pointers was NULL. +* IB_INVALID_PD_HANDLE +* Invalid pd handle +* IB_INVALID_PERMISSION +* Invalid access rights. +* +* NOTES +* This is a Mellanox specific extension to verbs. +* +* SEE ALSO +* ci_dealloc_mlnx_fmr, ci_map_phys_mlnx_fmr, ci_unmap_mlnx_fmr +****** +*/ +#endif + + +/****f* Verbs/ci_create_mw +* NAME +* ci_create_mw -- Create a memory window entry for later use +* SYNOPSIS +*/ + +typedef ib_api_status_t +(*ci_create_mw) ( + IN const ib_pd_handle_t h_pd, + OUT net32_t* const p_rkey, + OUT ib_mw_handle_t *ph_mw, + IN OUT ci_umv_buf_t *p_umv_buf OPTIONAL ); +/* +* DESCRIPTION +* This routine allocates a memory window. This window entry cannot be used +* for remote access unless this window is bound to a memory region +* via the ci_bind_mw call. +* PARAMETERS +* h_pd +* [in] Protection domain handle to use for this memory window +* p_rkey +* [out] Remote access key that can be exchanged with a remote node to +* perform RDMA transactions on this memory window. This R_KEY is still not +* bound to any memory regions, until a successful call to ci_bind_mw. +* VPD is required to give this in the expected ordering on the wire. When +* rkey's are exchanged between remote nodes, no swapping of this data +* will be performed. +* ph_mw +* [out] Handle to the newly created memory window. +* p_umv_buf +* [in out] Vendor specific parameter to support user mode IO. +* RETURN VALUE +* IB_SUCCESS +* The memory window allocation completed successfully. +* IB_INSUFFICIENT_RESOURCES +* Not enough resources to complete the request. +* IB_INVALID_PD_HANDLE +* pd_handle supplied is invalid. +* IB_INVALID_PARAMETER +* One of the pointers was not valid. +* SEE ALSO +* ci_destroy_mw, ci_query_mw, ci_bind_mw +****** +*/ + +/****f* Verbs/ci_query_mw +* NAME +* ci_query_mw -- Query memory window attributes for memory window handle +* SYNOPSIS +*/ + +typedef ib_api_status_t +(*ci_query_mw) ( + IN const ib_mw_handle_t h_mw, + OUT ib_pd_handle_t *ph_pd, + OUT net32_t* const p_rkey, + IN OUT ci_umv_buf_t *p_umv_buf OPTIONAL ); +/* +* DESCRIPTION +* This routine retrieves the current R_KEY and protection domain +* handle associated with this mw_handle. +* PARAMETERS +* h_mw +* [in] Memory window handle whose attributes are being retrieved. +* ph_pd +* [out] Protection domain handle associated with this mw_handle +* p_rkey +* [out] Current R_KEY associated with this mw_handle.The verbs provider +* is required to give this in the expected ordering on the wire. When +* rkey's are exchanged between remote nodes, no swapping of this data +* will be performed. +* p_umv_buf +* [in out] Vendor specific parameter to support user mode IO. +* RETURN VALUE +* IB_SUCCESS +* The query operation completed successfully. +* IB_INVALID_MW_HANDLE +* mw_handle supplied is an invalid handle +* IB_INVALID_PARAMETER +* One of the pointers was not valid. +* SEE ALSO +* ci_create_mw, ci_bind_mw +****** +*/ + +/****f* Verbs/ci_bind_mw +* NAME +* ci_bind_mw -- Bind a memory window to a memory region. +* SYNOPSIS +*/ + +typedef ib_api_status_t +(*ci_bind_mw) ( + IN const ib_mw_handle_t h_mw, + IN const ib_qp_handle_t h_qp, + IN ib_bind_wr_t* const p_mw_bind, + OUT net32_t* const p_rkey ); +/* +* DESCRIPTION +* This routine posts a request to bind a memory window to a registered +* memory region. If the queue pair was created with selectable signaling, +* once the operation is completed successfully then a completion queue entry +* is generated indicating the bind operation has completed. The IB_POST_FENCE +* option could be specified to cause the requestor to wait until outstanding +* RDMA operations can be completed. +* PARAMETERS +* h_mw +* [in] Handle to memory window that needs to be bound to a memory region. +* h_qp +* [in] Queue Pair to which this bind request is to be posted. +* p_mw_bind +* [in] Input parameters for this bind request, consisting of virtual +* addr range of bind request etc. +* p_rkey +* [out] On successful completion, the new R_KEY is returned. +* VPD is required to give this in the expected ordering on the wire. When +* rkey's are exchanged between remote nodes, no swapping of this data +* will be performed. +* RETURN VALUE +* IB_SUCCESS +* The memory bind operation was posted successfully. +* IB_INSUFFICIENT_RESOURCES +* Insufficient resources to complete the request. +* No more WQE's to post this request +* No more free WQE's to post this request +* IB_INVALID_MW_HANDLE +* memw_handle supplied is an invalid memory window handle. +* IB_INVALID_PERMISSION +* Invalid access rights specified in request +* IB_INVALID_SERVICE_TYPE +* Invalid service type for this qp_handle. +* IB_INVALID_PARAMETER +* One of the pointers was not valid. +* IB_INVALID_RKEY +* R_KEY specified is invalid for the memory region being bound. +* IB_INVALID_QP_HANDLE +* h_qp supplied was an invalid QP handle. +* NOTES +* - A previously bound memory window can be bound to the same or different +* memory region. +* +* - A bind operation with length of 0, invalidates any previous binding +* and returns an R_KEY in the unbound state. +* SEE ALSO +* ci_create_mw +****** +*/ + +/****f* Verbs/ci_destroy_mw +* NAME +* ci_destroy_mw -- Destroy a memory window. +* SYNOPSIS +*/ + +typedef ib_api_status_t +(*ci_destroy_mw) ( + IN const ib_mw_handle_t h_mw ); +/* +* DESCRIPTION +* This routine deallocates a window entry created via a ci_create_mw. +* Once this operation is complete, the channel interface guarantees that +* no future remote accesses will be permitted to this window entry. +* PARAMETERS +* h_mw +* [in] Handle to the memory window that is being destroyed. +* RETURN VALUE +* IB_SUCCESS +* The destroy window request completed successfully. +* IB_INVALID_MW_HANDLE +* memw_handle supplied is invalid. +* NOTES +* Deallocate memory window implicitly means the window is also unbound +* once the call completes successfully. Any future remote access with +* the same R_KEY should fail with protection violation. +* SEE ALSO +* ci_create_mw +****** +*/ + +/****f* Verbs/ci_post_send +* NAME +* ci_post_send -- Post a work request to the send side of a queue pair. +* SYNOPSIS +*/ + +typedef ib_api_status_t +(*ci_post_send) ( + IN const ib_qp_handle_t h_qp, + IN ib_send_wr_t* const p_send_wr, + OUT ib_send_wr_t **pp_failed ); +/* +* DESCRIPTION +* This routine posts a work request to the send side of the queue pair. +* The different types of work request that can be posted are explained in +* the ib_wr_t structure. For exact details on ordering rules please consult +* the Volume 1, of the InfiniBand Specifications. If there is more +* outstanding requests posted that what the queue is configured for, an +* immediate error is returned. +* PARAMETERS +* h_qp +* [in] The queue pair to which this work request is being submitted. +* p_send_wr +* [in] A pointer to the head of the list that must be posted to the +* Send Queue. +* pp_failed +* [out] A pointer to the head of the list that holds the failed WRs. +* If all the entries provided are posted with the CI, then this parameter +* would be set to NULL. +* RETURN VALUE +* Any unsuccessful status indicates the status of the first failed request. +* +* IB_SUCCESS +* All the work requests are completed successfully +* IB_INVALID_QP_HANDLE +* The qp_handle supplied is invalid. +* IB_INSUFFICIENT_RESOURCES +* Insufficient resources to complete the request. +* There are no more work elements in the channel interface to +* process this request, and the total outstanding work request has +* been exceeded. +* IB_INVALID_WR_TYPE +* The work request type was not valid. +* IB_INVALID_QP_STATE +* The queue pair is either in Reset, Init, RTR or Error state. +* IB_INVALID_MAX_SGE +* The work request has too many scatter gather elements than what the +* QP is configured. +* IB_UNSUPPORTED +* Atomics or Reliable datagram request is not supported by this HCA. +* IB_INVALID_ADDR_HANDLE +* Address handle supplied in the work request is invalid. +* NOTES +* Please refer to Table 81 and Table 82 for allowed operation types +* on different types of queue pairs, and the different modifiers +* acceptable for the work request for different QP service types. +* SEE ALSO +* ci_post_recv, ci_poll_cq +****** +*/ + +/****f* Verbs/ci_post_srq_recv +* NAME +* ci_post_srq_recv -- Post a work request to the receive queue of a queue pair. +* SYNOPSIS +*/ + +typedef ib_api_status_t +(*ci_post_srq_recv) ( + IN const ib_srq_handle_t h_srq, + IN ib_recv_wr_t* const p_recv_wr, + OUT ib_recv_wr_t **pp_failed ); +/* +* DESCRIPTION +* This routine allows to queue a work request to the receive side of a +* shared queue pair. The work_req holds necessary data to satisfy an incoming +* receive message. If an attempt is made to queue more work requests than +* what is available, an error is returned. +* PARAMETERS +* h_srq +* [in] Handle to the queue pair to which the receive work request is being +* posted. +* p_recv_wr +* [in] Holds the WRs to be posted to the receive queue. +* pp_failed +* [out] If any entry could not be posted with the CI, then this points +* to the first WR that completed unsuccessfully. If all entries are +* posted, then this field is set to NULL on successful exit. +* RETURN VALUE +* Any unsuccessful status indicates the status of the first failed request. +* +* IB_SUCCESS +* The work request was successfully queued to the receive side of the QP. +* IB_INVALID_SRQ_HANDLE +* srq_handle supplied is not valid. +* IB_INSUFFICIENT_RESOURCES +* The qp has exceeded its receive queue depth than what is has been +* configured. +* IB_INVALID_WR_TYPE +* Invalid work request type found in the request. +* SEE ALSO +****** +*/ + + + +/****f* Verbs/ci_post_recv +* NAME +* ci_post_recv -- Post a work request to the receive queue of a queue pair. +* SYNOPSIS +*/ + +typedef ib_api_status_t +(*ci_post_recv) ( + IN const ib_qp_handle_t h_qp, + IN ib_recv_wr_t* const p_recv_wr, + OUT ib_recv_wr_t **pp_failed ); +/* +* DESCRIPTION +* This routine allows to queue a work request to the receive side of a +* queue pair. The work_req holds necessary data to satisfy an incoming +* receive message. If an attempt is made to queue more work requests than +* what is available, an error is returned. +* PARAMETERS +* h_qp +* [in] Handle to the queue pair to which the receive work request is being +* posted. +* p_recv_wr +* [in] Holds the WRs to be posted to the receive queue. +* pp_failed +* [out] If any entry could not be posted with the CI, then this points +* to the first WR that completed unsuccessfully. If all entries are +* posted, then this field is set to NULL on successful exit. +* RETURN VALUE +* Any unsuccessful status indicates the status of the first failed request. +* +* IB_SUCCESS +* The work request was successfully queued to the receive side of the QP. +* IB_INVALID_QP_HANDLE +* qp_handle supplied is not valid. +* IB_INSUFFICIENT_RESOURCES +* The qp has exceeded its receive queue depth than what is has been +* configured. +* IB_INVALID_WR_TYPE +* Invalid work request type found in the request. +* IB_INVALID_QP_STATE +* QP was in reset or init state. +* (TBD: there may be an errata that allows posting in init state) +* SEE ALSO +* ci_post_send, ci_poll_cq. +****** +*/ + +/****f* Verbs/ci_peek_cq +* NAME +* ci_peek_cq +* +* DESCRIPTION +* Returns the number of entries currently on the completion queue. +* +* SYNOPSIS +*/ +typedef ib_api_status_t +(*ci_peek_cq) ( + IN const ib_cq_handle_t h_cq, + OUT uint32_t* const p_n_cqes ); +/* +* PARAMETERS +* h_cq +* [in] Handle to the completion queue to peek. +* +* p_n_cqes +* [out] The number of completion entries on the CQ. +* +* RETURN VALUES +* IB_SUCCESS +* The peek operation completed successfully. +* IB_INVALID_CQ_HANDLE +* The completion queue handle was invalid. +* IB_INVALID_PARAMETER +* A reference to the completion queue entry count was not provided. +* IB_UNSUPPORTED +* This operation is not supported by the channel adapter. +* +* NOTES +* The value returned is a snapshot of the number of compleiton queue +* entries curently on the completion queue. Support for this operation +* is optional by a channel adapter vendor. +* +* SEE ALSO +* ci_create_cq, ci_poll_cq, ci_enable_cq_notify, ci_enable_ncomp_cq_notify +*****/ + +/****f* Verbs/ci_poll_cq +* NAME +* ci_poll_cq -- Retrieve a work completion record from a completion queue +* SYNOPSIS +*/ + +typedef ib_api_status_t +(*ci_poll_cq) ( + IN const ib_cq_handle_t h_cq, + IN OUT ib_wc_t** const pp_free_wclist, + OUT ib_wc_t** const pp_done_wclist ); +/* +* DESCRIPTION +* This routine retrieves a work completion entry from the specified +* completion queue. The contents of the data returned in a work completion +* is specified in ib_wc_t. +* PARAMETERS +* h_cq +* [in] Handle to the completion queue being polled. +* pp_free_wclist +* [in out] A list of work request structures provided by the consumer +* for the channel interface to return completed Completion Queue +* entries. If not all the entries are consumed, this list holds the +* list of un-utilized completion entries provided back to the consumer. +* pp_done_wclist +* [out] A list of work completions retrieved from the completion queue +* and successfully processed. +* RETURN VALUE +* IB_SUCCESS +* Poll completed successfully and found one or more entries. If on +* completion the pp_free_wclist is empty, then there are potentially more +* entries and the consumer must continue to retrieve entries. +* IB_INVALID_CQ_HANDLE +* The cq_handle supplied is not valid. +* IB_NOT_FOUND +* There were no completion entries found in the specified CQ. +* SEE ALSO +* ci_create_cq, ci_post_send, ci_post_recv, ci_bind_mw +****** +*/ + +/****f* Verbs/ci_enable_cq_notify +* NAME +* ci_enable_cq_notify -- Invoke the Completion handler, on next entry added. +* SYNOPSIS +*/ + +typedef ib_api_status_t +(*ci_enable_cq_notify) ( + IN const ib_cq_handle_t h_cq, + IN const boolean_t solicited ); +/* +* DESCRIPTION +* This routine instructs the channel interface to invoke the completion +* handler when the next completion queue entry is added to this CQ. +* Please refer to Volume 1, of the InfiniBand specification for a complete +* description. +* PARAMETERS +* h_cq +* [in] Handle to the CQ on which the notification is being enabled. +* solicited +* [in] A boolean flag indicating whether the request is to generate a +* notification on the next entry or on the next solicited entry +* being added to the completion queue. +* RETURN VALUE +* IB_SUCCESS +* The notification request was registered successfully. +* IB_INVALID_CQ_HANDLE +* cq_handle supplied is not a valid handle. +* NOTES +* The consumer cannot call a request for notification without emptying +* entries from the CQ. i.e if a consumer registers for a notification +* request in the completion callback before pulling entries from the +* CQ via ci_poll_cq, the notification is not generated for completions +* already in the CQ. For e.g. in the example below, if there are no calls +* to ci_poll_cq() after the ci_enable_cq_notify(). For any CQ entries added +* before calling this ci_enable_cq_notify() call, the consumer does not +* get a completion notification callback. In order to comply with the verb +* spec, consumer is supposed to perform a ci_poll_cq() after the +* ci_enable_cq_notify() is made to retrive any entries that might have +* been added to the CQ before the CI registers the notification enable. +* +* while ((ret_val = ci_poll_cq(cq_handle, &free_list, &done_list) +* == FSUCCESS)) +* { +* process entries; +* } +* if (ret_val == IB_NOT_FOUND) +* ci_enable_cq_notify(cq_handle); +* // Need to perform a ci_poll_cq() +* // after the enable. +* SEE ALSO +* ci_create_cq, ci_peek_cq, ci_poll_cq, ci_enable_ncomp_cq_notify +****** +*/ + +/****f* Verbs/ci_enable_ncomp_cq_notify +* NAME +* ci_enable_ncomp_cq_notify -- Invoke the Completion handler when the next +* N completions are added. +* SYNOPSIS +*/ + +typedef ib_api_status_t +(*ci_enable_ncomp_cq_notify) ( + IN const ib_cq_handle_t h_cq, + IN const uint32_t n_cqes ); +/* +* DESCRIPTION +* This routine instructs the channel interface to invoke the completion +* handler when the next N completions have been added to this CQ. +* PARAMETERS +* h_cq +* [in] Handle to the CQ on which the notification is being enabled. +* n_cqes +* [in] The number of completion queue entries to be added to the +* completion queue before notifying the client. This value must +* greater than or equal to one and less than or equal to the size +* of the completion queue. +* +* RETURN VALUE +* IB_SUCCESS +* The notification request was registered successfully. +* IB_INVALID_CQ_HANDLE +* cq_handle supplied is not a valid handle. +* IB_INVALID_PARAMETER +* The requested number of completion queue entries was invalid. +* IB_UNSUPPORTED +* This operation is not supported by the channel adapter. +* +* NOTES +* This routine instructs the channel interface to invoke the completion +* handler when the next N completions have been added to this CQ regardless +* of the completion type (solicited or unsolicited). Any CQ entries that +* existed before the rearm is enabled will not result in a call to the +* handler. Support for this operation is optional by a channel adapter +* vendor. +* +* SEE ALSO +* ci_create_cq, ci_peek_cq, ci_poll_cq, ci_enable_cq_notify +****** +*/ + +/****f* Verbs/ci_attach_mcast +* NAME +* ci_attach_mcast -- Attach a queue pair to a multicast group +* SYNOPSIS +*/ + +typedef ib_api_status_t +(*ci_attach_mcast) ( + IN const ib_qp_handle_t h_qp, + IN const ib_gid_t *p_mcast_gid, + IN const ib_net16_t mcast_lid, + OUT ib_mcast_handle_t *ph_mcast, + IN OUT ci_umv_buf_t *p_umv_buf OPTIONAL ); +/* +* DESCRIPTION +* This routine attaches the given qp_handle to a multicast gid as specified +* by mcast_gid parameter. +* PARAMETERS +* h_qp +* [in] Queue pair handle which needs to be added to the multicast group +* on the adapter. +* mcast_lid +* [in] The multicast group LID value. +* p_mcast_gid +* [in] IPv6 address associated with this multicast group. +* ph_mcast +* [out] Multicast handle holding the association of this queue pair +* to the multicast group. +* p_umv_buf +* [in out] Vendor specific parameter to support user mode IO. +* RETURN VALUE +* IB_SUCCESS +* The queue pair handle was successfully added to the multicast +* group. +* IB_INVALID_QP_HANDLE +* qp_handle supplied is invalid. +* IB_INVALID_SERVICE_TYPE +* Queue pair handle supplied is not of unreliable datagram type. +* IB_INVALID_GID +* The supplied addr is not a valid multicast ipv6 address. +* IB_INVALID_LID +* The supplied lid is not a valid multicast lid. +* IB_UNSUPPORTED +* Multicast is not supported by this HCA. +* IB_INSUFFICIENT_RESOURCES +* Insufficient resources to complete request. +* IB_INVALID_PARAMETER +* One of the parameters was NULL. +* SEE ALSO +* ci_create_qp, ci_detach_mcast +****** +*/ + + +/****f* Verbs/ci_detach_mcast +* NAME +* ci_detach_mcast -- Detach a queue pair from a multicast group +* SYNOPSIS +*/ + +typedef ib_api_status_t +(*ci_detach_mcast) ( + IN const ib_mcast_handle_t h_mcast ); +/* +* DESCRIPTION +* This routine detaches a queue pair from its previously associated multicast +* group. +* PARAMETERS +* h_mcast +* [in] The multicast handle passed back to consumer after the +* ci_mcast_attach call. +* RETURN VALUE +* IB_SUCCESS +* The qp was successfully detached from the multicast group. +* IB_INVALID_MCAST_HANDLE +* mcast_handle supplied is an invalid handle +* IB_INVALID_PARAMETER +* One of the parameters was NULL. +* SEE ALSO +* ci_attach_mcast +****** +*/ + +/****f* Verbs/ci_local_mad +* NAME +* ci_local_mad -- Request a mad to be processed by the local adapter. +* SYNOPSIS +*/ + +typedef ib_api_status_t +(*ci_local_mad) ( + IN const ib_ca_handle_t h_ca, + IN const uint8_t port_num, + IN const ib_av_attr_t *p_src_av_attr, + IN const ib_mad_t *p_mad_in, + OUT ib_mad_t *p_mad_out ); +/* +* DESCRIPTION +* This routine is OPTIONAL for the channel interface. This is required +* for adapters which do not have the agents such as Subnet Management +* agent (SMA) Or the GSA in the Verbs Provider driver. +* hardware, for all such adapters the exact queue pair management of +* special queue pairs happen above the channel interface. This routine +* is used to perform local operations, since there is no agent below the +* channel interface. For e.g: If a Subnet Management packet (SMP) to +* set PORT_STATE is received, this reception is processed above the channel +* interface, then this call is done to set the port state on the local +* adapter. On successful return, the response is generated and sent to the +* Subnet Manager. +* PARAMETERS +* h_ca +* [in] A handle to the channel adapter that should process the MAD. +* This must be the same adapter that the MAD was received on. +* port_num +* [in] port number to which this request is directed is to be sent. +* p_mad_in +* [in] pointer to a management datagram (MAD) structure containing +* the command to be processed. +* p_mad_out +* [out] Response packet after processing the command. The storage to this +* must be allocated by the consumer. +* RETURN VALUE +* IB_SUCCESS +* Command processed successfully. +* IB_INVALID_CA_HANDLE +* The HCA handle supplied is not valid. +* IB_INVALID_PORT +* The port number supplied is invalid. +* PORTABILITY +* Kernel Mode only +* NOTES +* This call is provided to aid adapters that don't have a agent functionality +* built in the channel interface. Some adapters do have a local processor +* to process these packets, hence even for local port management, we can +* use the same mechanism we use to configure external nodes by using a +* hop counter = 1 in the MAD packets. If the SMA indicates it has a local +* sma in the ib_ca_attr_t, then the packets are posted to the adapter +* instead of making a private call to the adapter. +* SEE ALSO +* ci_query_ca, ci_ca_attr_t +****** +*/ + + +/****f* Verbs/ci_vendor_call +* NAME +* ci_vendor_call +* +* DESCRIPTION +* Performs a vendor specific CA interface function call. +* +* SYNOPSIS +*/ +typedef ib_api_status_t +(*ci_vendor_call)( + IN const ib_ca_handle_t h_ca, + IN const void** const handle_array OPTIONAL, + IN uint32_t num_handles, + IN ib_ci_op_t* const p_ci_op, + IN OUT ci_umv_buf_t *p_umv_buf OPTIONAL ); +/* +* PARAMETERS +* h_ca +* [in] A handle to an opened CA. +* +* handle_array +* [in] This parameter references an array containing handles of +* existing CA resources. This array should contain all of the +* handles specified in the vendor specific data provided with this +* call. All handles specified through this array are validated by +* the verbs provider driver to ensure that the number and type of +* handles are correct for the requested operation. +* +* num_handles +* [in] The number of the handles in handle array. This count is +* verified by the access layer. +* +* p_ci_op +* [in] A reference to the vendor specific CA interface data +* structure containing the operation parameters. +* +* p_umv_buf +* [in out] Vendor specific parameter to support user mode IO. +* +* RETURN VALUES +* IB_SUCCESS +* The operation was successful. +* +* IB_INVALID_CA_HANDLE +* The CA handle was invalid. +* +* IB_INVALID_PARAMETER +* A reference to the vendor specific data was not provided. +* +* IB_INVALID_HANDLE +* A handle specified in the handle array was invalid. +* +* IB_INSUFFICIENT_MEMORY +* There was insufficient memory to perform the operation. +* +* IB_ERROR +* An error occurred while processing the command. Additional +* error information is provided in the p_ci_op status field. +* +* NOTES +* This routine performs a vendor specific CA interface function call. +* The p_ci_op structure provides a means to pass vendor specific data to +* the verbs provider driver. If the vendor specific data contains handles, +* the client should provide the optional handle array that lists all of +* all of the handles specified in the vendor specific data. The handles +* in the handle array are restricted to the following types: ib_ca_handle_t, +* ib_pd_handle_t, ib_cq_handle_t, ib_av_handle_t, ib_qp_handle_t, +* ib_mr_handle_t, or ib_mw_handle_t +* The contents of the handle array are verified by the +* access layer and the verbs provider driver. +* +* SEE ALSO +* ci_open_ca, ci_allocate_pd, ci_create_av, ci_create_cq, +* ci_create_qp, ci_register_mr, ci_register_pmr, +* ci_register_smr, ci_create_mw, ib_ci_op_t +*****/ + + +#define MAX_LIB_NAME 32 + +#ifdef CL_KERNEL + +/****s* Verbs/ci_interface_t +* NAME +* ci_interface_t -- Interface holding Channel Interface API's +* PURPOSE +* The following structure is supplied by a Channel Interface +* providing verbs functionality. +* SOURCE +*/ + +typedef struct _ci_interface +{ + net64_t guid; + + /* + * Handle, returned by open_ca function of HCA upper interface (ci_interface_t) + * It has ib_ca_handle_t type + */ + void *p_hca_obj; + + /* + * Vendor ID, Device ID, Device Revision of the HCA + * libname refers to the user mode library to load + * to support direct user mode IO. If vendor does not support one + * then the fields must be initialized to all zero's. + */ + uint32_t vend_id; + uint16_t dev_id; + uint16_t dev_revision; + char libname[MAX_LIB_NAME]; + /* + * Version of the header file this interface export can handle + */ + uint32_t version; + + /* + * HCA Access Verbs + */ + ci_open_ca open_ca; + ci_um_open_ca_t um_open_ca; + ci_query_ca query_ca; + ci_modify_ca modify_ca; + ci_close_ca close_ca; + ci_um_close_ca_t um_close_ca; + ci_register_event_handler_t register_event_handler; + ci_unregister_event_handler_t unregister_event_handler; + + + ci_vendor_call vendor_call; + + /* + * Protection Domain + */ + ci_allocate_pd allocate_pd; + ci_deallocate_pd deallocate_pd; + + /* + * Address Vector Management Verbs + */ + + ci_create_av create_av; + ci_query_av query_av; + ci_modify_av modify_av; + ci_destroy_av destroy_av; + + /* + * SRQ Management Verbs + */ + ci_create_srq create_srq; + ci_modify_srq modify_srq; + ci_query_srq query_srq; + ci_destroy_srq destroy_srq; + + /* + * QP Management Verbs + */ + ci_create_qp create_qp; + ci_create_spl_qp create_spl_qp; + ci_modify_qp modify_qp; + ci_query_qp query_qp; + ci_destroy_qp destroy_qp; + ci_ndi_modify_qp ndi_modify_qp; + + /* + * Completion Queue Management Verbs + */ + ci_create_cq create_cq; + ci_resize_cq resize_cq; + ci_query_cq query_cq; + ci_destroy_cq destroy_cq; + + /* + * Memory Management Verbs + */ + ci_register_mr register_mr; + ci_register_pmr register_pmr; + ci_query_mr query_mr; + ci_modify_mr modify_mr; + ci_modify_pmr modify_pmr; + ci_register_smr register_smr; + ci_deregister_mr deregister_mr; + + /* + * Mellanox Fast Memory Management Verbs + */ + ci_alloc_mlnx_fmr alloc_mlnx_fmr; + ci_map_phys_mlnx_fmr map_phys_mlnx_fmr; + ci_unmap_mlnx_fmr unmap_mlnx_fmr; + ci_dealloc_mlnx_fmr dealloc_mlnx_fmr; + + + /* + * Memory Window Verbs + */ + ci_create_mw create_mw; + ci_query_mw query_mw; + ci_bind_mw bind_mw; + ci_destroy_mw destroy_mw; + + /* + * Work Request Processing Verbs + */ + ci_post_send post_send; + ci_post_recv post_recv; + ci_post_srq_recv post_srq_recv; + + /* + * Completion Processing and + * Completion Notification Request Verbs. + */ + ci_peek_cq peek_cq; /* Optional */ + ci_poll_cq poll_cq; + ci_enable_cq_notify enable_cq_notify; + ci_enable_ncomp_cq_notify enable_ncomp_cq_notify; /* Optional */ + + /* + * Multicast Support Verbs + */ + ci_attach_mcast attach_mcast; + ci_detach_mcast detach_mcast; + + /* + * Local MAD support, for HCA's that do not support + * Agents in the HW. + */ + ci_local_mad local_mad; + +} ci_interface_t; +/********/ + + +/****f* Verbs/ib_register_ca +* NAME +* ib_register_ca -- Inform the IB Access Layer about a new HCA +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t +ib_register_ca ( + IN const ci_interface_t* p_ci, + IN const PDEVICE_OBJECT p_hca_dev, + IN const PDEVICE_OBJECT p_fdo + ); +/* +* DESCRIPTION +* This routine is called by a HCA kernel mode driver to inform the +* IB Access Layer about a new HCA that is ready for use. It is expected +* that the Access Layer could immediatly turn around and call for services +* even before the call returns back the HCA driver code. The HCA driver +* must initialize all resources and be ready to service any calls before adding +* its services to the IB Access Layer. +* +* PARAMETERS +* p_ci +* [in] Pointer to the ci_interface_t structure that has the function +* vector to support verbs functionality. +* p_hca_dev +* PDO of HCA device +* p_fdo +* FDO of IBBUS device +* +* RETURN VALUE +* IB_SUCCESS +* The registration is successful. +* +* IB_INVALID_PARAMETER +* A reference to the CI interface structure was not provided. +* +* IB_INSUFFICIENT_RESOURCES +* Insufficient memory to satisfy resource requirements. +* +* IB_DUPLICATE_CA +* HCA GUID is already registered with the IB Access Layer +* +* PORTABILITY +* Kernel Mode only +* +* SEE ALSO +* ib_deregister_ca, ci_interface_t +*******/ + +/****f* Verbs/ib_deregister_ca +* NAME +* ib_deregister_ca -- Inform the IB Access Layer that this HCA is no longer available +* SYNOPSIS +*/ +AL_EXPORT ib_api_status_t +ib_deregister_ca ( + IN const net64_t ca_guid ); +/* +* DESCRIPTION +* This routine is called by the HCA driver when this HCA would no longer be +* available for services. The access layer is expected to return all resources +* back to the HCA driver, and perform a ci_close_ca on this interface. +* +* PARAMETERS +* ca_guid +* [in] GUID of the HCA that is being removed. +* +* RETURN VALUE +* IB_SUCCESS +* The deregistration is successful. +* +* IB_NOT_FOUND +* No HCA with the specified GUID is registered. +* +* IB_BUSY +* The HCA is still in use and cannot be released. +* +* PORTABILITY +* Kernel Mode only +* +* SEE ALSO +* ib_register_ca, ci_interface_t +*******/ + +#endif /* CL_KERNEL */ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif // __IB_CI_H__ diff --git a/branches/WOF2-3/inc/iba/ib_types.h b/branches/WOF2-3/inc/iba/ib_types.h new file mode 100644 index 00000000..43bad3e5 --- /dev/null +++ b/branches/WOF2-3/inc/iba/ib_types.h @@ -0,0 +1,12533 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * 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. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#if !defined(__IB_TYPES_H__) +#define __IB_TYPES_H__ + +#include +#include + + +#pragma warning( disable : 4201) //nameless union/structure + + +#define IB_CONCAT(str1, str2) str1##str2 + +#define TO_LONG_PTR(type,member_name) \ + union { type member_name; uint64_t IB_CONCAT(member_name,_padding); } + + +#ifdef CL_KERNEL + #define AL_EXPORT + #define AL_API + #define AL_INLINE static inline +#else + #if defined( EXPORT_AL_SYMBOLS ) + #define AL_EXPORT __declspec(dllexport) + #else + #define AL_EXPORT __declspec(dllimport) + #endif + #define AL_API __stdcall + #define AL_INLINE AL_EXPORT inline +#endif /* CL_KERNEL */ + + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + +/****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_NTOH32(0x80010000) +/*********/ + +#define IB_QP0 0 +#define IB_QP1 CL_NTOH32(1) + +#define IB_QP_PRIVILEGED_Q_KEY CL_NTOH32(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.1 (Table 3 p. 148) +*/ +#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_PKEY_BLOCK_SIZE) +/*********/ + +/****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_NTOH16(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 +* Subnet 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 +* Subnet Management Class, Performance Manager (13.4.4) +* +* SOURCE +*/ +#define IB_MCLASS_PERF 0x04 +/**********/ + +/****d* IBA Base: Constants/IB_MCLASS_BM +* NAME +* IB_MCLASS_BM +* +* DESCRIPTION +* Subnet Management Class, Baseboard Manager (13.4.4) +* +* SOURCE +*/ +#define IB_MCLASS_BM 0x05 +/**********/ + +/****d* IBA Base: Constants/IB_MCLASS_DEV_MGMT +* NAME +* IB_MCLASS_DEV_MGMT +* +* DESCRIPTION +* Subnet 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 +* Subnet 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 +* Subnet 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 +* Subnet 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 +* Subnet Management Class, Vendor Specific Low Range End +* +* SOURCE +*/ +#define IB_MCLASS_VENDOR_LOW_RANGE_MAX 0x0f +/**********/ + +#define IB_MLX_VENDOR_CLASS1 0x9 +#define IB_MLX_VENDOR_CLASS2 0xA + +/****d* IBA Base: Constants/IB_MCLASS_DEV_ADM +* NAME +* IB_MCLASS_DEV_ADM +* +* DESCRIPTION +* Subnet Management Class, Device Administration +* +* SOURCE +*/ +#define IB_MCLASS_DEV_ADM 0x10 +/**********/ + +/****d* IBA Base: Constants/IB_MCLASS_BIS +* NAME +* IB_MCLASS_BIS +* +* DESCRIPTION +* Subnet Management Class, BIS +* +* SOURCE +*/ +#define IB_MCLASS_BIS 0x12 +/**********/ + +/****d* IBA Base: Constants/IB_MCLASS_CC +* NAME +* IB_MCLASS_CC +* +* DESCRIPTION +* Management Class, Congestion Control (A10.4.1) +* +* SOURCE +*/ +#define IB_MCLASS_CC 0x21 +/**********/ + +/****d* IBA Base: Constants/IB_MCLASS_VENDOR_HIGH_RANGE_MIN +* NAME +* IB_MCLASS_VENDOR_HIGH_RANGE_MIN +* +* DESCRIPTION +* Subnet 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 +* Subnet 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 +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 +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 +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 +*/ +AL_INLINE boolean_t AL_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_NTOH16(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_NTOH16(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_NTOH16(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_NTOH16(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_NTOH16(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_NTOH16(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_NTOH16(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_NTOH16(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_NTOH16(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_NTOH16(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_NTOH16(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_NTOH16(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_NTOH16(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_NTOH16(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_NTOH16(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_NTOH16(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_NTOH16(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_NTOH16(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_NTOH16(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_NTOH16(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_NTOH16(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_NTOH16(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_NTOH16(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_NTOH16(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_NTOH16(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_NTOH16(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_NTOH16(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_NTOH16(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_NTOH16(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_NTOH16(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_NTOH16(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_NTOH16(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_NTOH16(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_NTOH16(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_NTOH16(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_NTOH16(0x003A)) +/**********/ + +/****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_NTOH16(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_NTOH16(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_NTOH16(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_NTOH16(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_NTOH16(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_NTOH16(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_NTOH16(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_NTOH16(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_NTOH16(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_MAD_ATTR_CONG_INFO +* NAME +* IB_MAD_ATTR_CONG_INFO +* +* DESCRIPTION +* CongestionInfo attribute (A10.4.3) +* +* SOURCE +*/ +#define IB_MAD_ATTR_CONG_INFO (CL_HTON16(0x0011)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_ATTR_CONG_KEY_INFO +* NAME +* IB_MAD_ATTR_CONG_KEY_INFO +* +* DESCRIPTION +* CongestionKeyInfo attribute (A10.4.3) +* +* SOURCE +*/ +#define IB_MAD_ATTR_CONG_KEY_INFO (CL_HTON16(0x0012)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_ATTR_CONG_LOG +* NAME +* IB_MAD_ATTR_CONG_LOG +* +* DESCRIPTION +* CongestionLog attribute (A10.4.3) +* +* SOURCE +*/ +#define IB_MAD_ATTR_CONG_LOG (CL_HTON16(0x0013)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_ATTR_SW_CONG_SETTING +* NAME +* IB_MAD_ATTR_SW_CONG_SETTING +* +* DESCRIPTION +* SwitchCongestionSetting attribute (A10.4.3) +* +* SOURCE +*/ +#define IB_MAD_ATTR_SW_CONG_SETTING (CL_HTON16(0x0014)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_ATTR_SW_PORT_CONG_SETTING +* NAME +* IB_MAD_ATTR_SW_PORT_CONG_SETTING +* +* DESCRIPTION +* SwitchPortCongestionSetting attribute (A10.4.3) +* +* SOURCE +*/ +#define IB_MAD_ATTR_SW_PORT_CONG_SETTING (CL_HTON16(0x0015)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_ATTR_CA_CONG_SETTING +* NAME +* IB_MAD_ATTR_CA_CONG_SETTING +* +* DESCRIPTION +* CACongestionSetting attribute (A10.4.3) +* +* SOURCE +*/ +#define IB_MAD_ATTR_CA_CONG_SETTING (CL_HTON16(0x0016)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_ATTR_CC_TBL +* NAME +* IB_MAD_ATTR_CC_TBL +* +* DESCRIPTION +* CongestionControlTable attribute (A10.4.3) +* +* SOURCE +*/ +#define IB_MAD_ATTR_CC_TBL (CL_HTON16(0x0017)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_ATTR_TIME_STAMP +* NAME +* IB_MAD_ATTR_TIME_STAMP +* +* DESCRIPTION +* TimeStamp attribute (A10.4.3) +* +* SOURCE +*/ +#define IB_MAD_ATTR_TIME_STAMP (CL_HTON16(0x0018)) +/**********/ + +/****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_NOTICE_NODE_TYPE_SUBN_MGMT +* NAME +* IB_NOTICE_NODE_TYPE_SUBN_MGMT +* +* DESCRIPTION +* Encoded generic node type used in MAD attributes (13.4.8.2). +* Note that this value is not defined for the NodeType field +* of the NodeInfo attribute (14.2.5.3). +* +* SOURCE +*/ +#define IB_NOTICE_NODE_TYPE_SUBN_MGMT (CL_NTOH32(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", + "Subnet Management" +}; + +/****f* IBA Base: Types/ib_get_node_type_str +* NAME +* ib_get_node_type_str +* +* DESCRIPTION +* Returns a string for the specified node type. +* +* SYNOPSIS +*/ +AL_INLINE const char* AL_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 *AL_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 +*/ +AL_INLINE const char* AL_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 +*/ +AL_INLINE const uint8_t AL_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 +*/ +AL_INLINE ib_net16_t AL_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 +*/ +AL_INLINE boolean_t AL_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 +ib_pkey_is_invalid( + IN const ib_net16_t pkey ) +{ + if (ib_pkey_get_base(pkey) == 0x0000) + return TRUE; + + return FALSE; +} +/* +* PARAMETERS +* pkey +* [in] P_Key value +* +* RETURN VALUE +* Returns the base P_Key value with the membership bit stripped. +* +* NOTES +* +* SEE ALSO +*********/ + +/****d* IBA Base: Types/ib_gid_t +* NAME +* ib_gid_t +* +* DESCRIPTION +* +* SYNOPSIS +*/ +#include +typedef union _ib_gid +{ + uint8_t raw[16]; + struct _ib_gid_unicast + { + ib_gid_prefix_t prefix; + ib_net64_t interface_id; + + } PACK_SUFFIX unicast; + + struct _ib_gid_multicast + { + uint8_t header[2]; + uint8_t raw_group_id[14]; + + } PACK_SUFFIX multicast; + +} PACK_SUFFIX ib_gid_t; +#include +/* +* FIELDS +* raw +* GID represented as an unformated byte array. +* +* unicast +* Typical unicast representation with subnet prefix and +* port GUID. +* +* multicast +* Representation for multicast use. +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_gid_is_multicast +* NAME +* ib_gid_is_multicast +* +* DESCRIPTION +* Returns a boolean indicating whether a GID is a multicast GID. +* +* SYNOPSIS +*/ +AL_INLINE boolean_t AL_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 +*/ +AL_INLINE uint8_t AL_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 +*/ +AL_INLINE void AL_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 +*/ +AL_INLINE void AL_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 +*/ +AL_INLINE ib_net64_t AL_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 +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 +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 +*/ +AL_INLINE ib_net64_t AL_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_field32_t +* NAME +* ib_field32_t +* +* DESCRIPTION +* Represents a 32-bit field, and allows access as a 32-bit network byte +* ordered or a 4-byte array. +* +* SYNOPSIS +*/ +#include +typedef union _ib_field32_t +{ + net32_t val; + uint8_t bytes[4]; + +} PACK_SUFFIX ib_field32_t; +#include +/* +* FIELDS +* val +* Full field value. +* +* bytes +* Byte array representing the field. The byte array provides identical +* access independently from CPU byte-ordering. +*********/ + +/****s* IBA Base: Types/ib_path_rec_t +* NAME +* ib_path_rec_t +* +* DESCRIPTION +* Path records encapsulate the properties of a given +* route between two end-points on a subnet. +* +* SYNOPSIS +*/ +#include +typedef __declspec(align(8)) struct _ib_path_rec +{ + ib_net64_t service_id; + ib_gid_t dgid; + ib_gid_t sgid; + ib_net16_t dlid; + ib_net16_t slid; + ib_net32_t hop_flow_raw; + uint8_t tclass; + uint8_t num_path; + ib_net16_t pkey; + ib_net16_t qos_class_sl; + uint8_t mtu; + uint8_t rate; + uint8_t pkt_life; + uint8_t preference; + uint8_t resv2[6]; + +} PACK_SUFFIX ib_path_rec_t; +#include +/* +* FIELDS +* service_id +* Service ID for QoS. +* +* dgid +* GID of destination port. +* +* sgid +* GID of source port. +* +* dlid +* LID of destination port. +* +* slid +* LID of source port. +* +* hop_flow_raw +* Global routing parameters: hop count, flow label and raw bit. +* +* tclass +* Another global routing parameter. +* +* num_path +* Reversible path - 1 bit to say if path is reversible. +* num_path [6:0] In queries, maximum number of paths to return. +* In responses, undefined. +* +* pkey +* Partition key (P_Key) to use on this path. +* +* qos_class_sl +* QoS class and service level to use on this path. +* +* mtu +* MTU and MTU selector fields to use on this path +* +* rate +* Rate and rate selector fields to use on this path. +* +* pkt_life +* Packet lifetime +* +* preference +* Indicates the relative merit of this path versus other path +* records returned from the SA. Lower numbers are better. +* +* resv2 +* Reserved bytes. +* SEE ALSO +*********/ + +/* Path Record Component Masks */ +#define IB_PR_COMPMASK_SERVICEID_MSB (CL_HTON64(((uint64_t)1)<<0)) +#define IB_PR_COMPMASK_SERVICEID_LSB (CL_HTON64(((uint64_t)1)<<1)) +#define IB_PR_COMPMASK_DGID (CL_HTON64(((uint64_t)1)<<2)) +#define IB_PR_COMPMASK_SGID (CL_HTON64(((uint64_t)1)<<3)) +#define IB_PR_COMPMASK_DLID (CL_HTON64(((uint64_t)1)<<4)) +#define IB_PR_COMPMASK_SLID (CL_HTON64(((uint64_t)1)<<5)) +#define IB_PR_COMPMASK_RAWTRAFFIC (CL_HTON64(((uint64_t)1)<<6)) +#define IB_PR_COMPMASK_RESV0 (CL_HTON64(((uint64_t)1)<<7)) +#define IB_PR_COMPMASK_FLOWLABEL (CL_HTON64(((uint64_t)1)<<8)) +#define IB_PR_COMPMASK_HOPLIMIT (CL_HTON64(((uint64_t)1)<<9)) +#define IB_PR_COMPMASK_TCLASS (CL_HTON64(((uint64_t)1)<<10)) +#define IB_PR_COMPMASK_REVERSIBLE (CL_HTON64(((uint64_t)1)<<11)) +#define IB_PR_COMPMASK_NUMBPATH (CL_HTON64(((uint64_t)1)<<12)) +#define IB_PR_COMPMASK_PKEY (CL_HTON64(((uint64_t)1)<<13)) +#define IB_PR_COMPMASK_QOS_CLASS (CL_HTON64(((uint64_t)1)<<14)) +#define IB_PR_COMPMASK_SL (CL_HTON64(((uint64_t)1)<<15)) +#define IB_PR_COMPMASK_MTUSELEC (CL_HTON64(((uint64_t)1)<<16)) +#define IB_PR_COMPMASK_MTU (CL_HTON64(((uint64_t)1)<<17)) +#define IB_PR_COMPMASK_RATESELEC (CL_HTON64(((uint64_t)1)<<18)) +#define IB_PR_COMPMASK_RATE (CL_HTON64(((uint64_t)1)<<19)) +#define IB_PR_COMPMASK_PKTLIFETIMESELEC (CL_HTON64(((uint64_t)1)<<20)) +#define IB_PR_COMPMASK_PKTLIFETIME (CL_HTON64(((uint64_t)1)<<21)) + +/* Link Record Component Masks */ +#define IB_LR_COMPMASK_FROM_LID (CL_HTON64(((uint64_t)1)<<0)) +#define IB_LR_COMPMASK_FROM_PORT (CL_HTON64(((uint64_t)1)<<1)) +#define IB_LR_COMPMASK_TO_PORT (CL_HTON64(((uint64_t)1)<<2)) +#define IB_LR_COMPMASK_TO_LID (CL_HTON64(((uint64_t)1)<<3)) + +/* VL Arbitration Record Masks */ +#define IB_VLA_COMPMASK_LID (CL_HTON64(((uint64_t)1)<<0)) +#define IB_VLA_COMPMASK_OUT_PORT (CL_HTON64(((uint64_t)1)<<1)) +#define IB_VLA_COMPMASK_BLOCK (CL_HTON64(((uint64_t)1)<<2)) + +/* SLtoVL Mapping Record Masks */ +#define IB_SLVL_COMPMASK_LID (CL_HTON64(((uint64_t)1)<<0)) +#define IB_SLVL_COMPMASK_IN_PORT (CL_HTON64(((uint64_t)1)<<1)) +#define IB_SLVL_COMPMASK_OUT_PORT (CL_HTON64(((uint64_t)1)<<2)) + +/* P_Key Table Record Masks */ +#define IB_PKEY_COMPMASK_LID (CL_HTON64(((uint64_t)1)<<0)) +#define IB_PKEY_COMPMASK_BLOCK (CL_HTON64(((uint64_t)1)<<1)) +#define IB_PKEY_COMPMASK_PORT (CL_HTON64(((uint64_t)1)<<2)) + +/* Switch Info Record Masks */ +#define IB_SWIR_COMPMASK_LID (CL_HTON64(((uint64_t)1)<<0)) +#define IB_SWIR_COMPMASK_RESERVED1 (CL_HTON64(((uint64_t)1)<<1)) + +/* LFT Record Masks */ +#define IB_LFTR_COMPMASK_LID (CL_HTON64(((uint64_t)1)<<0)) +#define IB_LFTR_COMPMASK_BLOCK (CL_HTON64(((uint64_t)1)<<1)) + +/* MFT Record Masks */ +#define IB_MFTR_COMPMASK_LID (CL_HTON64(((uint64_t)1)<<0)) +#define IB_MFTR_COMPMASK_POSITION (CL_HTON64(((uint64_t)1)<<1)) +#define IB_MFTR_COMPMASK_RESERVED1 (CL_HTON64(((uint64_t)1)<<2)) +#define IB_MFTR_COMPMASK_BLOCK (CL_HTON64(((uint64_t)1)<<3)) +#define IB_MFTR_COMPMASK_RESERVED2 (CL_HTON64(((uint64_t)1)<<4)) + +/* NodeInfo Record Masks */ +#define IB_NR_COMPMASK_LID (CL_HTON64(((uint64_t)1)<<0)) +#define IB_NR_COMPMASK_RESERVED1 (CL_HTON64(((uint64_t)1)<<1)) +#define IB_NR_COMPMASK_BASEVERSION (CL_HTON64(((uint64_t)1)<<2)) +#define IB_NR_COMPMASK_CLASSVERSION (CL_HTON64(((uint64_t)1)<<3)) +#define IB_NR_COMPMASK_NODETYPE (CL_HTON64(((uint64_t)1)<<4)) +#define IB_NR_COMPMASK_NUMPORTS (CL_HTON64(((uint64_t)1)<<5)) +#define IB_NR_COMPMASK_SYSIMAGEGUID (CL_HTON64(((uint64_t)1)<<6)) +#define IB_NR_COMPMASK_NODEGUID (CL_HTON64(((uint64_t)1)<<7)) +#define IB_NR_COMPMASK_PORTGUID (CL_HTON64(((uint64_t)1)<<8)) +#define IB_NR_COMPMASK_PARTCAP (CL_HTON64(((uint64_t)1)<<9)) +#define IB_NR_COMPMASK_DEVID (CL_HTON64(((uint64_t)1)<<10)) +#define IB_NR_COMPMASK_REV (CL_HTON64(((uint64_t)1)<<11)) +#define IB_NR_COMPMASK_PORTNUM (CL_HTON64(((uint64_t)1)<<12)) +#define IB_NR_COMPMASK_VENDID (CL_HTON64(((uint64_t)1)<<13)) +#define IB_NR_COMPMASK_NODEDESC (CL_HTON64(((uint64_t)1)<<14)) + +/* Service Record Component Masks Sec 15.2.5.14 Ver 1.1*/ +#define IB_SR_COMPMASK_SID (CL_HTON64(((uint64_t)1)<<0)) +#define IB_SR_COMPMASK_SGID (CL_HTON64(((uint64_t)1)<<1)) +#define IB_SR_COMPMASK_SPKEY (CL_HTON64(((uint64_t)1)<<2)) +#define IB_SR_COMPMASK_RES1 (CL_HTON64(((uint64_t)1)<<3)) +#define IB_SR_COMPMASK_SLEASE (CL_HTON64(((uint64_t)1)<<4)) +#define IB_SR_COMPMASK_SKEY (CL_HTON64(((uint64_t)1)<<5)) +#define IB_SR_COMPMASK_SNAME (CL_HTON64(((uint64_t)1)<<6)) +#define IB_SR_COMPMASK_SDATA8_0 (CL_HTON64(((uint64_t)1)<<7)) +#define IB_SR_COMPMASK_SDATA8_1 (CL_HTON64(((uint64_t)1)<<8)) +#define IB_SR_COMPMASK_SDATA8_2 (CL_HTON64(((uint64_t)1)<<9)) +#define IB_SR_COMPMASK_SDATA8_3 (CL_HTON64(((uint64_t)1)<<10)) +#define IB_SR_COMPMASK_SDATA8_4 (CL_HTON64(((uint64_t)1)<<11)) +#define IB_SR_COMPMASK_SDATA8_5 (CL_HTON64(((uint64_t)1)<<12)) +#define IB_SR_COMPMASK_SDATA8_6 (CL_HTON64(((uint64_t)1)<<13)) +#define IB_SR_COMPMASK_SDATA8_7 (CL_HTON64(((uint64_t)1)<<14)) +#define IB_SR_COMPMASK_SDATA8_8 (CL_HTON64(((uint64_t)1)<<15)) +#define IB_SR_COMPMASK_SDATA8_9 (CL_HTON64(((uint64_t)1)<<16)) +#define IB_SR_COMPMASK_SDATA8_10 (CL_HTON64(((uint64_t)1)<<17)) +#define IB_SR_COMPMASK_SDATA8_11 (CL_HTON64(((uint64_t)1)<<18)) +#define IB_SR_COMPMASK_SDATA8_12 (CL_HTON64(((uint64_t)1)<<19)) +#define IB_SR_COMPMASK_SDATA8_13 (CL_HTON64(((uint64_t)1)<<20)) +#define IB_SR_COMPMASK_SDATA8_14 (CL_HTON64(((uint64_t)1)<<21)) +#define IB_SR_COMPMASK_SDATA8_15 (CL_HTON64(((uint64_t)1)<<22)) +#define IB_SR_COMPMASK_SDATA16_0 (CL_HTON64(((uint64_t)1)<<23)) +#define IB_SR_COMPMASK_SDATA16_1 (CL_HTON64(((uint64_t)1)<<24)) +#define IB_SR_COMPMASK_SDATA16_2 (CL_HTON64(((uint64_t)1)<<25)) +#define IB_SR_COMPMASK_SDATA16_3 (CL_HTON64(((uint64_t)1)<<26)) +#define IB_SR_COMPMASK_SDATA16_4 (CL_HTON64(((uint64_t)1)<<27)) +#define IB_SR_COMPMASK_SDATA16_5 (CL_HTON64(((uint64_t)1)<<28)) +#define IB_SR_COMPMASK_SDATA16_6 (CL_HTON64(((uint64_t)1)<<29)) +#define IB_SR_COMPMASK_SDATA16_7 (CL_HTON64(((uint64_t)1)<<30)) +#define IB_SR_COMPMASK_SDATA32_0 (CL_HTON64(((uint64_t)1)<<31)) +#define IB_SR_COMPMASK_SDATA32_1 (CL_HTON64(((uint64_t)1)<<32)) +#define IB_SR_COMPMASK_SDATA32_2 (CL_HTON64(((uint64_t)1)<<33)) +#define IB_SR_COMPMASK_SDATA32_3 (CL_HTON64(((uint64_t)1)<<34)) +#define IB_SR_COMPMASK_SDATA64_0 (CL_HTON64(((uint64_t)1)<<35)) +#define IB_SR_COMPMASK_SDATA64_1 (CL_HTON64(((uint64_t)1)<<36)) + +/* Port Info Record Component Masks */ +#define IB_PIR_COMPMASK_LID (CL_HTON64(((uint64_t)1)<<0)) +#define IB_PIR_COMPMASK_PORTNUM (CL_HTON64(((uint64_t)1)<<1)) +#define IB_PIR_COMPMASK_RESV1 (CL_HTON64(((uint64_t)1)<<2)) +#define IB_PIR_COMPMASK_MKEY (CL_HTON64(((uint64_t)1)<<3)) +#define IB_PIR_COMPMASK_GIDPRE (CL_HTON64(((uint64_t)1)<<4)) +#define IB_PIR_COMPMASK_BASELID (CL_HTON64(((uint64_t)1)<<5)) +#define IB_PIR_COMPMASK_SMLID (CL_HTON64(((uint64_t)1)<<6)) +#define IB_PIR_COMPMASK_CAPMASK (CL_HTON64(((uint64_t)1)<<7)) +#define IB_PIR_COMPMASK_DIAGCODE (CL_HTON64(((uint64_t)1)<<8)) +#define IB_PIR_COMPMASK_MKEYLEASEPRD (CL_HTON64(((uint64_t)1)<<9)) +#define IB_PIR_COMPMASK_LOCALPORTNUM (CL_HTON64(((uint64_t)1)<<10)) +#define IB_PIR_COMPMASK_LINKWIDTHENABLED (CL_HTON64(((uint64_t)1)<<11)) +#define IB_PIR_COMPMASK_LNKWIDTHSUPPORT (CL_HTON64(((uint64_t)1)<<12)) +#define IB_PIR_COMPMASK_LNKWIDTHACTIVE (CL_HTON64(((uint64_t)1)<<13)) +#define IB_PIR_COMPMASK_LNKSPEEDSUPPORT (CL_HTON64(((uint64_t)1)<<14)) +#define IB_PIR_COMPMASK_PORTSTATE (CL_HTON64(((uint64_t)1)<<15)) +#define IB_PIR_COMPMASK_PORTPHYSTATE (CL_HTON64(((uint64_t)1)<<16)) +#define IB_PIR_COMPMASK_LINKDWNDFLTSTATE (CL_HTON64(((uint64_t)1)<<17)) +#define IB_PIR_COMPMASK_MKEYPROTBITS (CL_HTON64(((uint64_t)1)<<18)) +#define IB_PIR_COMPMASK_RESV2 (CL_HTON64(((uint64_t)1)<<19)) +#define IB_PIR_COMPMASK_LMC (CL_HTON64(((uint64_t)1)<<20)) +#define IB_PIR_COMPMASK_LINKSPEEDACTIVE (CL_HTON64(((uint64_t)1)<<21)) +#define IB_PIR_COMPMASK_LINKSPEEDENABLE (CL_HTON64(((uint64_t)1)<<22)) +#define IB_PIR_COMPMASK_NEIGHBORMTU (CL_HTON64(((uint64_t)1)<<23)) +#define IB_PIR_COMPMASK_MASTERSMSL (CL_HTON64(((uint64_t)1)<<24)) +#define IB_PIR_COMPMASK_VLCAP (CL_HTON64(((uint64_t)1)<<25)) +#define IB_PIR_COMPMASK_INITTYPE (CL_HTON64(((uint64_t)1)<<26)) +#define IB_PIR_COMPMASK_VLHIGHLIMIT (CL_HTON64(((uint64_t)1)<<27)) +#define IB_PIR_COMPMASK_VLARBHIGHCAP (CL_HTON64(((uint64_t)1)<<28)) +#define IB_PIR_COMPMASK_VLARBLOWCAP (CL_HTON64(((uint64_t)1)<<29)) +#define IB_PIR_COMPMASK_INITTYPEREPLY (CL_HTON64(((uint64_t)1)<<30)) +#define IB_PIR_COMPMASK_MTUCAP (CL_HTON64(((uint64_t)1)<<31)) +#define IB_PIR_COMPMASK_VLSTALLCNT (CL_HTON64(((uint64_t)1)<<32)) +#define IB_PIR_COMPMASK_HOQLIFE (CL_HTON64(((uint64_t)1)<<33)) +#define IB_PIR_COMPMASK_OPVLS (CL_HTON64(((uint64_t)1)<<34)) +#define IB_PIR_COMPMASK_PARENFIN (CL_HTON64(((uint64_t)1)<<35)) +#define IB_PIR_COMPMASK_PARENFOUT (CL_HTON64(((uint64_t)1)<<36)) +#define IB_PIR_COMPMASK_FILTERRAWIN (CL_HTON64(((uint64_t)1)<<37)) +#define IB_PIR_COMPMASK_FILTERRAWOUT (CL_HTON64(((uint64_t)1)<<38)) +#define IB_PIR_COMPMASK_MKEYVIO (CL_HTON64(((uint64_t)1)<<39)) +#define IB_PIR_COMPMASK_PKEYVIO (CL_HTON64(((uint64_t)1)<<40)) +#define IB_PIR_COMPMASK_QKEYVIO (CL_HTON64(((uint64_t)1)<<41)) +#define IB_PIR_COMPMASK_GUIDCAP (CL_HTON64(((uint64_t)1)<<42)) +#define IB_PIR_COMPMASK_RESV3 (CL_HTON64(((uint64_t)1)<<43)) +#define IB_PIR_COMPMASK_SUBNTO (CL_HTON64(((uint64_t)1)<<44)) +#define IB_PIR_COMPMASK_RESV4 (CL_HTON64(((uint64_t)1)<<45)) +#define IB_PIR_COMPMASK_RESPTIME (CL_HTON64(((uint64_t)1)<<46)) +#define IB_PIR_COMPMASK_LOCALPHYERR (CL_HTON64(((uint64_t)1)<<47)) +#define IB_PIR_COMPMASK_OVERRUNERR (CL_HTON64(((uint64_t)1)<<48)) + +/* Multicast Member Record Component Masks */ +#define IB_MCR_COMPMASK_GID (CL_HTON64(((uint64_t)1)<<0)) +#define IB_MCR_COMPMASK_MGID (CL_HTON64(((uint64_t)1)<<0)) +#define IB_MCR_COMPMASK_PORT_GID (CL_HTON64(((uint64_t)1)<<1)) +#define IB_MCR_COMPMASK_QKEY (CL_HTON64(((uint64_t)1)<<2)) +#define IB_MCR_COMPMASK_MLID (CL_HTON64(((uint64_t)1)<<3)) +#define IB_MCR_COMPMASK_MTU_SEL (CL_HTON64(((uint64_t)1)<<4)) +#define IB_MCR_COMPMASK_MTU (CL_HTON64(((uint64_t)1)<<5)) +#define IB_MCR_COMPMASK_TCLASS (CL_HTON64(((uint64_t)1)<<6)) +#define IB_MCR_COMPMASK_PKEY (CL_HTON64(((uint64_t)1)<<7)) +#define IB_MCR_COMPMASK_RATE_SEL (CL_HTON64(((uint64_t)1)<<8)) +#define IB_MCR_COMPMASK_RATE (CL_HTON64(((uint64_t)1)<<9)) +#define IB_MCR_COMPMASK_LIFE_SEL (CL_HTON64(((uint64_t)1)<<10)) +#define IB_MCR_COMPMASK_LIFE (CL_HTON64(((uint64_t)1)<<11)) +#define IB_MCR_COMPMASK_SL (CL_HTON64(((uint64_t)1)<<12)) +#define IB_MCR_COMPMASK_FLOW (CL_HTON64(((uint64_t)1)<<13)) +#define IB_MCR_COMPMASK_HOP (CL_HTON64(((uint64_t)1)<<14)) +#define IB_MCR_COMPMASK_SCOPE (CL_HTON64(((uint64_t)1)<<15)) +#define IB_MCR_COMPMASK_JOIN_STATE (CL_HTON64(((uint64_t)1)<<16)) +#define IB_MCR_COMPMASK_PROXY (CL_HTON64(((uint64_t)1)<<17)) + +/* GUID Info Record Component Masks */ +#define IB_GIR_COMPMASK_LID (CL_HTON64(((uint64_t)1)<<0)) +#define IB_GIR_COMPMASK_BLOCKNUM (CL_HTON64(((uint64_t)1)<<1)) +#define IB_GIR_COMPMASK_RESV1 (CL_HTON64(((uint64_t)1)<<2)) +#define IB_GIR_COMPMASK_RESV2 (CL_HTON64(((uint64_t)1)<<3)) +#define IB_GIR_COMPMASK_GID0 (CL_HTON64(((uint64_t)1)<<4)) +#define IB_GIR_COMPMASK_GID1 (CL_HTON64(((uint64_t)1)<<5)) +#define IB_GIR_COMPMASK_GID2 (CL_HTON64(((uint64_t)1)<<6)) +#define IB_GIR_COMPMASK_GID3 (CL_HTON64(((uint64_t)1)<<7)) +#define IB_GIR_COMPMASK_GID4 (CL_HTON64(((uint64_t)1)<<8)) +#define IB_GIR_COMPMASK_GID5 (CL_HTON64(((uint64_t)1)<<9)) +#define IB_GIR_COMPMASK_GID6 (CL_HTON64(((uint64_t)1)<<10)) +#define IB_GIR_COMPMASK_GID7 (CL_HTON64(((uint64_t)1)<<11)) + +/* MultiPath Record Component Masks */ +#define IB_MPR_COMPMASK_RAWTRAFFIC (CL_HTON64(((uint64_t)1)<<0)) +#define IB_MPR_COMPMASK_RESV0 (CL_HTON64(((uint64_t)1)<<1)) +#define IB_MPR_COMPMASK_FLOWLABEL (CL_HTON64(((uint64_t)1)<<2)) +#define IB_MPR_COMPMASK_HOPLIMIT (CL_HTON64(((uint64_t)1)<<3)) +#define IB_MPR_COMPMASK_TCLASS (CL_HTON64(((uint64_t)1)<<4)) +#define IB_MPR_COMPMASK_REVERSIBLE (CL_HTON64(((uint64_t)1)<<5)) +#define IB_MPR_COMPMASK_NUMBPATH (CL_HTON64(((uint64_t)1)<<6)) +#define IB_MPR_COMPMASK_PKEY (CL_HTON64(((uint64_t)1)<<7)) +#define IB_MPR_COMPMASK_QOS_CLASS (CL_HTON64(((uint64_t)1)<<8)) +#define IB_MPR_COMPMASK_SL (CL_HTON64(((uint64_t)1)<<9)) +#define IB_MPR_COMPMASK_MTUSELEC (CL_HTON64(((uint64_t)1)<<10)) +#define IB_MPR_COMPMASK_MTU (CL_HTON64(((uint64_t)1)<<11)) +#define IB_MPR_COMPMASK_RATESELEC (CL_HTON64(((uint64_t)1)<<12)) +#define IB_MPR_COMPMASK_RATE (CL_HTON64(((uint64_t)1)<<13)) +#define IB_MPR_COMPMASK_PKTLIFETIMESELEC (CL_HTON64(((uint64_t)1)<<14)) +#define IB_MPR_COMPMASK_PKTLIFETIME (CL_HTON64(((uint64_t)1)<<15)) +#define IB_MPR_COMPMASK_SERVICEID_MSB (CL_HTON64(((uint64_t)1)<<16)) +#define IB_MPR_COMPMASK_INDEPSELEC (CL_HTON64(((uint64_t)1)<<17)) +#define IB_MPR_COMPMASK_RESV3 (CL_HTON64(((uint64_t)1)<<18)) +#define IB_MPR_COMPMASK_SGIDCOUNT (CL_HTON64(((uint64_t)1)<<19)) +#define IB_MPR_COMPMASK_DGIDCOUNT (CL_HTON64(((uint64_t)1)<<20)) +#define IB_MPR_COMPMASK_SERVICEID_LSB (CL_HTON64(((uint64_t)1)<<21)) + +/* SMInfo Record Component Masks */ +#define IB_SMIR_COMPMASK_LID (CL_HTON64(((uint64_t)1)<<0)) +#define IB_SMIR_COMPMASK_RESV0 (CL_HTON64(((uint64_t)1)<<1)) +#define IB_SMIR_COMPMASK_GUID (CL_HTON64(((uint64_t)1)<<2)) +#define IB_SMIR_COMPMASK_SMKEY (CL_HTON64(((uint64_t)1)<<3)) +#define IB_SMIR_COMPMASK_ACTCOUNT (CL_HTON64(((uint64_t)1)<<4)) +#define IB_SMIR_COMPMASK_PRIORITY (CL_HTON64(((uint64_t)1)<<5)) +#define IB_SMIR_COMPMASK_SMSTATE (CL_HTON64(((uint64_t)1)<<6)) + +/* InformInfo Record Component Masks */ +#define IB_IIR_COMPMASK_SUBSCRIBERGID (CL_HTON64(((uint64_t)1)<<0)) +#define IB_IIR_COMPMASK_ENUM (CL_HTON64(((uint64_t)1)<<1)) +#define IB_IIR_COMPMASK_RESV0 (CL_HTON64(((uint64_t)1)<<2)) +#define IB_IIR_COMPMASK_GID (CL_HTON64(((uint64_t)1)<<3)) +#define IB_IIR_COMPMASK_LIDRANGEBEGIN (CL_HTON64(((uint64_t)1)<<4)) +#define IB_IIR_COMPMASK_LIDRANGEEND (CL_HTON64(((uint64_t)1)<<5)) +#define IB_IIR_COMPMASK_RESV1 (CL_HTON64(((uint64_t)1)<<6)) +#define IB_IIR_COMPMASK_ISGENERIC (CL_HTON64(((uint64_t)1)<<7)) +#define IB_IIR_COMPMASK_SUBSCRIBE (CL_HTON64(((uint64_t)1)<<8)) +#define IB_IIR_COMPMASK_TYPE (CL_HTON64(((uint64_t)1)<<9)) +#define IB_IIR_COMPMASK_TRAPNUMB (CL_HTON64(((uint64_t)1)<<10)) +#define IB_IIR_COMPMASK_DEVICEID (CL_HTON64(((uint64_t)1)<<10)) +#define IB_IIR_COMPMASK_QPN (CL_HTON64(((uint64_t)1)<<11)) +#define IB_IIR_COMPMASK_RESV2 (CL_HTON64(((uint64_t)1)<<12)) +#define IB_IIR_COMPMASK_RESPTIME (CL_HTON64(((uint64_t)1)<<13)) +#define IB_IIR_COMPMASK_RESV3 (CL_HTON64(((uint64_t)1)<<14)) +#define IB_IIR_COMPMASK_PRODTYPE (CL_HTON64(((uint64_t)1)<<15)) +#define IB_IIR_COMPMASK_VENDID (CL_HTON64(((uint64_t)1)<<15)) + +/****f* IBA Base: Types/ib_path_rec_init_local +* NAME +* ib_path_rec_init_local +* +* DESCRIPTION +* Initializes a subnet local path record. +* +* SYNOPSIS +*/ +AL_INLINE void AL_API +ib_path_rec_init_local( + IN ib_path_rec_t* const p_rec, + IN const ib_gid_t* const p_dgid, + IN const ib_gid_t* const p_sgid, + IN const ib_net16_t dlid, + IN const ib_net16_t slid, + IN const uint8_t num_path, + IN const ib_net16_t pkey, + IN const uint8_t sl, + IN const uint16_t qos_class, + IN const uint8_t mtu_selector, + IN const uint8_t mtu, + IN const uint8_t rate_selector, + IN const uint8_t rate, + IN const uint8_t pkt_life_selector, + IN const uint8_t pkt_life, + IN const 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; + + memset(p_rec->resv2, 0, sizeof(p_rec->resv2)); +} +/* +* 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 +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 +*/ +AL_INLINE void AL_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 +*/ +AL_INLINE uint8_t AL_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 +*/ +AL_INLINE void AL_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 +*/ +AL_INLINE uint16_t AL_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 +*/ +AL_INLINE uint8_t AL_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 +*/ +AL_INLINE uint8_t AL_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 +*/ +AL_INLINE uint8_t AL_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 +*/ +AL_INLINE uint8_t AL_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 +*/ +AL_INLINE uint8_t AL_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 µsec * 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 +*/ +AL_INLINE uint8_t AL_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 +*/ +AL_INLINE net32_t AL_API +ib_path_rec_flow_lbl( + IN const ib_path_rec_t* const p_rec ) +{ + return( cl_hton32( (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 +*/ +AL_INLINE uint8_t AL_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 +*********/ + +/****f* IBA Base: Types/ib_path_rec_set_hop_flow_raw +* NAME +* ib_path_rec_set_hop_flow_raw +* +* DESCRIPTION +* Sets the hop limit, flow label, and raw traffic bits of a path record. +* +* SYNOPSIS +*/ +AL_INLINE void AL_API +ib_path_rec_set_hop_flow_raw( + OUT ib_path_rec_t* const p_rec, + IN const uint8_t hop_limit, + IN const net32_t flow_lbl, + IN const boolean_t raw ) +{ + p_rec->hop_flow_raw = raw ? 0x80000000 : 0; + p_rec->hop_flow_raw |= (cl_ntoh32( flow_lbl ) & 0x000FFFFF) << 8; + p_rec->hop_flow_raw |= hop_limit; + p_rec->hop_flow_raw = cl_hton32( p_rec->hop_flow_raw ); +} +/* +* PARAMETERS +* p_rec +* Pointer to the path record whose hop limit, flow label, and rab +* traffic fields to set. +* +* hop_limit +* Hop limit to set in the path record. +* +* flow_lbl +* Flow label, in network byte order, to set in the path record. +* +* raw +* Boolean flag to indicate whether the path record is for raw traffic. +* +* 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_ENH_PORT0_CC_MASK +* NAME +* IB_CLASS_ENH_PORT0_CC_MASK +* +* DESCRIPTION +* ClassPortInfo CapabilityMask bits. +* Switch only: This bit will be set if the EnhacedPort0 +* supports CA Congestion Control (A10.4.3.1). +* +* SEE ALSO +* ib_class_port_info_t +* +* SOURCE +*/ +#define IB_CLASS_ENH_PORT0_CC_MASK 0x0100 +/*********/ + +/****s* IBA Base: Constants/IB_CLASS_RESP_TIME_MASK +* NAME +* IB_CLASS_RESP_TIME_MASK +* +* DESCRIPTION +* Mask bits to extract the reponse time value from the +* resp_time_val field of ib_class_port_info_t. +* +* SEE ALSO +* ib_class_port_info_t +* +* SOURCE +*/ +#define IB_CLASS_RESP_TIME_MASK 0x1F +/*********/ +/****s* IBA Base: Types/ib_class_port_info_t +* NAME +* ib_class_port_info_t +* +* DESCRIPTION +* IBA defined ClassPortInfo attribute (13.4.8.1) +* route between two end-points on a subnet. +* +* SYNOPSIS +*/ +#include +typedef struct _ib_class_port_info +{ + uint8_t base_ver; + uint8_t class_ver; + ib_net16_t cap_mask; + ib_net32_t cap_mask2_resp_time; + ib_gid_t redir_gid; + ib_net32_t redir_tc_sl_fl; + ib_net16_t redir_lid; + ib_net16_t redir_pkey; + ib_net32_t redir_qp; + ib_net32_t redir_qkey; + ib_gid_t trap_gid; + ib_net32_t trap_tc_sl_fl; + ib_net16_t trap_lid; + ib_net16_t trap_pkey; + ib_net32_t trap_hop_qp; + ib_net32_t trap_qkey; + +} PACK_SUFFIX ib_class_port_info_t; +#include +/* +* FIELDS +* base_ver +* Maximum supported MAD Base Version. +* +* class_ver +* Maximum supported management class version. +* +* cap_mask +* Supported capabilities of this management class. +* +* cap_mask2_resp_time +* Maximum expected response time and additional +* supported capabilities of this management class. +* +* redir_gid +* GID to use for redirection, or zero +* +* redir_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 +* +*********/ + +#define IB_PM_ALL_PORT_SELECT (CL_HTON16(((uint16_t)1)<<8)) +#define IB_PM_EXT_WIDTH_SUPPORTED (CL_HTON16(((uint16_t)1)<<9)) +#define IB_PM_EXT_WIDTH_NOIETF_SUP (CL_HTON16(((uint16_t)1)<<10)) + +/****f* IBA Base: Types/ib_class_set_resp_time_val +* NAME +* ib_class_set_resp_time_val +* +* DESCRIPTION +* Set maximum expected response time. +* +* SYNOPSIS +*/ +AL_INLINE void AL_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 +*/ +AL_INLINE uint8_t AL_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 +*/ +AL_INLINE void AL_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 +*/ +AL_INLINE uint32_t AL_API +ib_class_cap_mask2(IN const ib_class_port_info_t * const p_cpi) +{ + return (cl_ntoh32(p_cpi->cap_mask2_resp_time) >> 5); +} + +/* +* PARAMETERS +* p_cpi +* [in] Pointer to the class port info object. +* +* RETURN VALUES +* CapabilityMask2 of the ClassPortInfo. +* +* NOTES +* +* SEE ALSO +* ib_class_port_info_t +*********/ + +/****s* IBA Base: Types/ib_sm_info_t +* NAME +* ib_sm_info_t +* +* DESCRIPTION +* SMInfo structure (14.2.5.13). +* +* SYNOPSIS +*/ +#include +typedef struct _ib_sm_info +{ + ib_net64_t guid; + ib_net64_t sm_key; + ib_net32_t act_count; + uint8_t pri_state; + +} PACK_SUFFIX ib_sm_info_t; +#include +/* +* FIELDS +* guid +* Port GUID for this SM. +* +* sm_key +* SM_Key of this SM. +* +* act_count +* Activity counter used as a heartbeat. +* +* pri_state +* Priority and State information +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_sminfo_get_priority +* NAME +* ib_sminfo_get_priority +* +* DESCRIPTION +* Returns the priority value. +* +* SYNOPSIS +*/ +AL_INLINE uint8_t AL_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 +*/ +AL_INLINE uint8_t AL_API +ib_sminfo_get_state( + IN const ib_sm_info_t* const p_smi ) +{ + return( (uint8_t)(p_smi->pri_state & 0x0F) ); +} +/* +* PARAMETERS +* p_smi +* [in] Pointer to the SMInfo Attribute. +* +* RETURN VALUES +* Returns the state value. +* +* NOTES +* +* SEE ALSO +*********/ + +/****s* IBA Base: Types/ib_mad_t +* NAME +* ib_mad_t +* +* DESCRIPTION +* IBA defined MAD header (13.4.3) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_mad +{ + uint8_t base_ver; + uint8_t mgmt_class; + uint8_t class_ver; + uint8_t method; + ib_net16_t status; + ib_net16_t class_spec; + ib_net64_t trans_id; + ib_net16_t attr_id; + ib_net16_t resv; + ib_net32_t attr_mod; +} PACK_SUFFIX ib_mad_t; +#include +/* +* FIELDS +* base_ver +* MAD base format. +* +* mgmt_class +* Class of operation. +* +* class_ver +* Version of MAD class-specific format. +* +* method +* Method to perform, including 'R' bit. +* +* status +* Status of operation. +* +* class_spec +* Reserved for subnet management. +* +* trans_id +* Transaction ID. +* +* attr_id +* Attribute ID. +* +* resv +* Reserved field. +* +* attr_mod +* Attribute modifier. +* +* SEE ALSO +*********/ + + +/****s* IBA Base: Types/ib_rmpp_mad_t +* NAME +* ib_rmpp_mad_t +* +* DESCRIPTION +* IBA defined MAD RMPP header (13.6.2.1) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_rmpp_mad +{ + ib_mad_t common_hdr; + + uint8_t rmpp_version; + uint8_t rmpp_type; + uint8_t rmpp_flags; + uint8_t rmpp_status; + + ib_net32_t seg_num; + ib_net32_t paylen_newwin; + +} PACK_SUFFIX ib_rmpp_mad_t; +#include +/* +* SEE ALSO +* ib_mad_t +*********/ + + +/****f* IBA Base: Types/ib_mad_init_new +* NAME +* ib_mad_init_new +* +* DESCRIPTION +* Initializes a MAD common header. +* +* SYNOPSIS +*/ +AL_INLINE void AL_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 +*/ +AL_INLINE void AL_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) +* or if the MAD is a TRAP REPRESS, +* FALSE otherwise. +* +* SYNOPSIS +*/ +AL_INLINE boolean_t AL_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) || + (p_mad->method == IB_MAD_METHOD_TRAP_REPRESS)); +} +/* +* 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 +*/ +AL_INLINE boolean_t AL_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 +*********/ + +AL_INLINE void AL_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); +} + + +AL_INLINE uint8_t AL_API +ib_rmpp_get_resp_time( + IN const ib_rmpp_mad_t* const p_rmpp_mad ) +{ + CL_ASSERT( p_rmpp_mad ); + return( (uint8_t)(p_rmpp_mad->rmpp_flags >> 3) ); +} + +/****d* IBA Base: Constants/IB_SMP_DIRECTION +* NAME +* IB_SMP_DIRECTION +* +* DESCRIPTION +* The Direction bit for directed route SMPs. +* +* SOURCE +*/ +#define IB_SMP_DIRECTION_HO 0x8000 +#define IB_SMP_DIRECTION (CL_HTON16(IB_SMP_DIRECTION_HO)) +/**********/ + +/****d* IBA Base: Constants/IB_SMP_STATUS_MASK +* NAME +* IB_SMP_STATUS_MASK +* +* DESCRIPTION +* Mask value for extracting status from a directed route SMP. +* +* SOURCE +*/ +#define IB_SMP_STATUS_MASK_HO 0x7FFF +#define IB_SMP_STATUS_MASK (CL_HTON16(IB_SMP_STATUS_MASK_HO)) +/**********/ + +/****s* IBA Base: Types/ib_smp_t +* NAME +* ib_smp_t +* +* DESCRIPTION +* IBA defined SMP. (14.2.1.2) +* +* SYNOPSIS +*/ +#define IB_SMP_DATA_SIZE 64 +#include +typedef struct _ib_smp +{ + uint8_t base_ver; + uint8_t mgmt_class; + uint8_t class_ver; + uint8_t method; + ib_net16_t status; + uint8_t hop_ptr; + uint8_t hop_count; + ib_net64_t trans_id; + ib_net16_t attr_id; + ib_net16_t resv; + ib_net32_t attr_mod; + ib_net64_t m_key; + ib_net16_t dr_slid; + ib_net16_t dr_dlid; + uint32_t resv1[7]; + uint8_t data[IB_SMP_DATA_SIZE]; + uint8_t initial_path[IB_SUBNET_PATH_HOPS_MAX]; + uint8_t return_path[IB_SUBNET_PATH_HOPS_MAX]; + +} PACK_SUFFIX ib_smp_t; +#include +/* +* FIELDS +* base_ver +* MAD base format. +* +* mgmt_class +* Class of operation. +* +* class_ver +* Version of MAD class-specific format. +* +* method +* Method to perform, including 'R' bit. +* +* status +* Status of operation. +* +* hop_ptr +* Hop pointer for directed route MADs. +* +* hop_count +* Hop count for directed route MADs. +* +* trans_Id +* Transaction ID. +* +* attr_id +* Attribute ID. +* +* resv +* Reserved field. +* +* attr_mod +* Attribute modifier. +* +* m_key +* Management key value. +* +* dr_slid +* Directed route source LID. +* +* dr_dlid +* Directed route destination LID. +* +* resv0 +* Reserved for 64 byte alignment. +* +* data +* MAD data payload. +* +* initial_path +* Outbound port list. +* +* return_path +* Inbound port list. +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_smp_get_status +* NAME +* ib_smp_get_status +* +* DESCRIPTION +* Returns the SMP status value in network order. +* +* SYNOPSIS +*/ +AL_INLINE ib_net16_t AL_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 +*/ +AL_INLINE boolean_t AL_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 +*/ +AL_INLINE boolean_t AL_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 convenient spot. +* +* SYNOPSIS +*/ +AL_INLINE void AL_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; + + cl_memclr( p_smp->resv1, + sizeof(p_smp->resv1) + + sizeof(p_smp->data) + + sizeof(p_smp->initial_path) + + sizeof(p_smp->return_path) ); + + /* copy the path */ + cl_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 +*/ +AL_INLINE void* AL_API +ib_smp_get_payload_ptr( + IN const ib_smp_t* const p_smp ) +{ + return( (void*)p_smp->data ); +} +/* +* PARAMETERS +* p_smp +* [in] Pointer to the SMP packet. +* +* RETURN VALUES +* Pointer to SMP payload area. +* +* NOTES +* +* SEE ALSO +* ib_mad_t +*********/ + +/****s* IBA Base: Types/ib_node_info_t +* NAME +* ib_node_info_t +* +* DESCRIPTION +* IBA defined NodeInfo. (14.2.5.3) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_node_info +{ + uint8_t base_version; + uint8_t class_version; + uint8_t node_type; + uint8_t num_ports; + ib_net64_t sys_guid; + ib_net64_t node_guid; + ib_net64_t port_guid; + ib_net16_t partition_cap; + ib_net16_t device_id; + ib_net32_t revision; + ib_net32_t port_num_vendor_id; + +} PACK_SUFFIX ib_node_info_t; +#include +/************/ + +/****s* IBA Base: Types/ib_sa_mad_t +* NAME +* ib_sa_mad_t +* +* DESCRIPTION +* IBA defined SA MAD format. (15.2.1) +* +* SYNOPSIS +*/ +#define IB_SA_DATA_SIZE 200 + +#include +typedef struct _ib_sa_mad +{ + uint8_t base_ver; + uint8_t mgmt_class; + uint8_t class_ver; + uint8_t method; + ib_net16_t status; + ib_net16_t resv; + ib_net64_t trans_id; + ib_net16_t attr_id; + ib_net16_t resv1; + ib_net32_t attr_mod; + + uint8_t rmpp_version; + uint8_t rmpp_type; + uint8_t rmpp_flags; + uint8_t rmpp_status; + + ib_net32_t seg_num; + ib_net32_t paylen_newwin; + + ib_net64_t sm_key; + + ib_net16_t attr_offset; + ib_net16_t resv3; + + ib_net64_t comp_mask; + + uint8_t data[IB_SA_DATA_SIZE]; +} PACK_SUFFIX ib_sa_mad_t; +#include +/**********/ +#define IB_SA_MAD_HDR_SIZE (sizeof(ib_sa_mad_t) - IB_SA_DATA_SIZE) + + + +AL_INLINE uint32_t AL_API +ib_get_attr_size( + IN const ib_net16_t attr_offset ) +{ + return( ((uint32_t)cl_ntoh16( attr_offset )) << 3 ); +} + +AL_INLINE ib_net16_t AL_API +ib_get_attr_offset( + IN const uint32_t attr_size ) +{ + CL_ASSERT((attr_size & 0x07) == 0); + 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 +*/ +AL_INLINE void* AL_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_NTOH32(0xFF000000)) +#define IB_NODE_INFO_VEND_ID_MASK (CL_NTOH32(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 +* Get the local port number from the NodeInfo attribute. +* +* SYNOPSIS +*/ +AL_INLINE uint8_t AL_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 +*/ +AL_INLINE ib_net32_t AL_API +ib_node_info_get_vendor_id( + IN const ib_node_info_t* const p_ni ) +{ + return( (ib_net32_t)( p_ni->port_num_vendor_id & + IB_NODE_INFO_VEND_ID_MASK ) ); +} +/* +* PARAMETERS +* p_ni +* [in] Pointer to a NodeInfo attribute. +* +* RETURN VALUES +* VendorID that returned the attribute. +* +* NOTES +* +* SEE ALSO +* ib_node_info_t +*********/ + +#define IB_NODE_DESCRIPTION_SIZE 64 + +#include +typedef struct _ib_node_desc +{ + // Node String is an array of UTF-8 character that + // describes the node in text format + // Note that this string is NOT NULL TERMINATED! + uint8_t description[IB_NODE_DESCRIPTION_SIZE]; + +} PACK_SUFFIX ib_node_desc_t; +#include + +#include +typedef struct _ib_node_record_t +{ + ib_net16_t lid; + ib_net16_t resv; + ib_node_info_t node_info; + ib_node_desc_t node_desc; + uint8_t pad[4]; + +} PACK_SUFFIX ib_node_record_t; +#include + +/****s* IBA Base: Types/ib_port_info_t +* NAME +* ib_port_info_t +* +* DESCRIPTION +* IBA defined PortInfo. (14.2.5.6) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_port_info +{ + ib_net64_t m_key; + ib_net64_t subnet_prefix; + ib_net16_t base_lid; + ib_net16_t master_sm_base_lid; + ib_net32_t capability_mask; + ib_net16_t diag_code; + ib_net16_t m_key_lease_period; + uint8_t local_port_num; + uint8_t link_width_enabled; + uint8_t link_width_supported; + uint8_t link_width_active; + uint8_t state_info1; /* LinkSpeedSupported and PortState */ + uint8_t state_info2; /* PortPhysState and LinkDownDefaultState */ + uint8_t mkey_lmc; + uint8_t link_speed; /* LinkSpeedEnabled and LinkSpeedActive */ + uint8_t mtu_smsl; + uint8_t vl_cap; /* VLCap and InitType */ + uint8_t vl_high_limit; + uint8_t vl_arb_high_cap; + uint8_t vl_arb_low_cap; + uint8_t mtu_cap; + uint8_t vl_stall_life; + uint8_t vl_enforce; + ib_net16_t m_key_violations; + ib_net16_t p_key_violations; + ib_net16_t q_key_violations; + uint8_t guid_cap; + uint8_t subnet_timeout; /* cli_rereg(1b), mcast_pkey_trap_suppr(1b), resrv(1b), timeout(5b) */ + uint8_t resp_time_value; + uint8_t error_threshold; + ib_net16_t max_credit_hint; + ib_net32_t link_rt_latency; /* reserv(8b), link round trip lat(24b) */ + +} PACK_SUFFIX ib_port_info_t; +#include +/************/ + +#define IB_PORT_STATE_MASK 0x0F +#define IB_PORT_LMC_MASK 0x07 +#define IB_PORT_LMC_MAX 0x07 +#define IB_PORT_MPB_MASK 0xC0 +#define IB_PORT_MPB_SHIFT 6 +#define IB_PORT_LINK_SPEED_SHIFT 4 +#define IB_PORT_LINK_SPEED_SUPPORTED_MASK 0xF0 +#define IB_PORT_LINK_SPEED_ACTIVE_MASK 0xF0 +#define IB_PORT_LINK_SPEED_ENABLED_MASK 0x0F +#define IB_PORT_PHYS_STATE_MASK 0xF0 +#define IB_PORT_PHYS_STATE_SHIFT 4 +#define IB_PORT_PHYS_STATE_NO_CHANGE 0 +#define IB_PORT_PHYS_STATE_SLEEP 1 +#define IB_PORT_PHYS_STATE_POLLING 2 +#define IB_PORT_PHYS_STATE_DISABLED 3 +#define IB_PORT_PHYS_STATE_PORTCONFTRAIN 4 +#define IB_PORT_PHYS_STATE_LINKUP 5 +#define IB_PORT_PHYS_STATE_LINKERRRECOVER 6 +#define IB_PORT_PHYS_STATE_PHYTEST 7 +#define IB_PORT_LNKDWNDFTSTATE_MASK 0x0F + +#define IB_PORT_CAP_RESV0 (CL_NTOH32(0x00000001)) +#define IB_PORT_CAP_IS_SM (CL_NTOH32(0x00000002)) +#define IB_PORT_CAP_HAS_NOTICE (CL_NTOH32(0x00000004)) +#define IB_PORT_CAP_HAS_TRAP (CL_NTOH32(0x00000008)) +#define IB_PORT_CAP_HAS_IPD (CL_NTOH32(0x00000010)) +#define IB_PORT_CAP_HAS_AUTO_MIG (CL_NTOH32(0x00000020)) +#define IB_PORT_CAP_HAS_SL_MAP (CL_NTOH32(0x00000040)) +#define IB_PORT_CAP_HAS_NV_MKEY (CL_NTOH32(0x00000080)) +#define IB_PORT_CAP_HAS_NV_PKEY (CL_NTOH32(0x00000100)) +#define IB_PORT_CAP_HAS_LED_INFO (CL_NTOH32(0x00000200)) +#define IB_PORT_CAP_SM_DISAB (CL_NTOH32(0x00000400)) +#define IB_PORT_CAP_HAS_SYS_IMG_GUID (CL_NTOH32(0x00000800)) +#define IB_PORT_CAP_HAS_PKEY_SW_EXT_PORT_TRAP (CL_NTOH32(0x00001000)) +#define IB_PORT_CAP_RESV13 (CL_NTOH32(0x00002000)) +#define IB_PORT_CAP_RESV14 (CL_NTOH32(0x00004000)) +#define IB_PORT_CAP_RESV15 (CL_NTOH32(0x00008000)) +#define IB_PORT_CAP_HAS_COM_MGT (CL_NTOH32(0x00010000)) +#define IB_PORT_CAP_HAS_SNMP (CL_NTOH32(0x00020000)) +#define IB_PORT_CAP_REINIT (CL_NTOH32(0x00040000)) +#define IB_PORT_CAP_HAS_DEV_MGT (CL_NTOH32(0x00080000)) +#define IB_PORT_CAP_HAS_VEND_CLS (CL_NTOH32(0x00100000)) +#define IB_PORT_CAP_HAS_DR_NTC (CL_NTOH32(0x00200000)) +#define IB_PORT_CAP_HAS_CAP_NTC (CL_NTOH32(0x00400000)) +#define IB_PORT_CAP_HAS_BM (CL_NTOH32(0x00800000)) +#define IB_PORT_CAP_HAS_LINK_RT_LATENCY (CL_NTOH32(0x01000000)) +#define IB_PORT_CAP_HAS_CLIENT_REREG (CL_NTOH32(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_HAS_VEND_MADS (CL_HTON32(0x10000000)) +#define IB_PORT_CAP_HAS_MCAST_PKEY_TRAP_SUPPRESS (CL_HTON32(0x20000000)) +#define IB_PORT_CAP_HAS_MCAST_FDB_TOP (CL_HTON32(0x40000000)) +#define IB_PORT_CAP_HAS_HIER_INFO (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 +*/ +AL_INLINE uint8_t AL_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 +*/ +AL_INLINE void AL_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 +*/ +AL_INLINE uint8_t AL_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 +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 +*/ +AL_INLINE uint8_t AL_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 +*/ +AL_INLINE void AL_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 +*/ +AL_INLINE void AL_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 +*/ +AL_INLINE uint8_t AL_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 +*/ +AL_INLINE void AL_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 +*/ +AL_INLINE uint8_t AL_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 +*/ +AL_INLINE void AL_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 +*/ +AL_INLINE uint8_t AL_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 +*/ +AL_INLINE void AL_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 +*/ +AL_INLINE uint8_t AL_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 +*/ +AL_INLINE uint8_t AL_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_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_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 +*/ +AL_INLINE uint8_t AL_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 +*/ +AL_INLINE uint8_t AL_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 encoded 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 at this port. +* +* SYNOPSIS +*/ +AL_INLINE uint8_t AL_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 +*/ +AL_INLINE void AL_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 AL_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 AL_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_get_sm_sl +* NAME +* ib_port_info_get_sm_sl +* +* DESCRIPTION +* Returns the encoded value for the SM sl at this port. +* +* SYNOPSIS +*/ +AL_INLINE uint8_t AL_API +ib_port_info_get_sm_sl( + 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 neighbor MTU at this port. +* +* NOTES +* +* SEE ALSO +*********/ +/****f* IBA Base: Types/ib_port_info_set_sm_sl +* NAME +* ib_port_info_set_sm_sl +* +* DESCRIPTION +* Sets the SM sl value in the PortInfo attribute. +* +* SYNOPSIS +*/ +AL_INLINE void AL_API +ib_port_info_set_sm_sl( + IN ib_port_info_t* const p_pi, + IN const uint8_t sm_sl ) +{ + CL_ASSERT( sm_sl<= 5 ); + CL_ASSERT( sm_sl != 0 ); + p_pi->mtu_smsl = (uint8_t)((p_pi->mtu_smsl & 0xF0) | sm_sl ); +} +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* mtu +* [in] Encoded SM sl 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 +*/ +AL_INLINE void AL_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 & 0xE0) | (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 +*/ +AL_INLINE void AL_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 & 0x7F) | (client_rereg << 7)); +} +/* +* 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_mcast_pkey_trap_suppress +* NAME +* ib_port_info_get_mcast_pkey_trap_suppress +* +* DESCRIPTION +* Gets the encoded multicast pkey trap suppresion enabled bit value +* in the PortInfo attribute. +* +* SYNOPSIS +*/ +static inline uint8_t AL_API +ib_port_info_get_mcast_pkey_trap_suppress(IN ib_port_info_t const *p_pi) +{ + return ((p_pi->subnet_timeout & 0x40) >> 6); +} + +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* RETURN VALUES +* Multicast PKey trap suppression enabled value (either 1 or 0). +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_set_mcast_pkey_trap_suppress +* NAME +* ib_port_info_set_mcast_pkey_trap_suppress +* +* DESCRIPTION +* Sets the encoded multicast pkey trap suppresion enabled bit value +* in the PortInfo attribute. +* +* SYNOPSIS +*/ +static inline void AL_API +ib_port_info_set_mcast_pkey_trap_suppress(IN ib_port_info_t * const p_pi, + IN const uint8_t trap_suppress) +{ + CL_ASSERT(trap_suppress <= 0x1); + p_pi->subnet_timeout = + (uint8_t) ((p_pi->subnet_timeout & 0xBF) | (trap_suppress << 6)); +} + +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* trap_suppress +* [in] Multicast pkey trap suppresion enabled 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 +*/ +AL_INLINE uint8_t AL_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 +*/ +AL_INLINE uint8_t AL_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 +*/ +AL_INLINE void AL_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 +*/ +AL_INLINE uint8_t AL_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 +*/ +AL_INLINE void AL_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 +*/ +AL_INLINE uint8_t AL_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 +*/ +AL_INLINE uint8_t AL_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 +*/ +AL_INLINE void AL_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 +*/ +AL_INLINE uint8_t AL_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 +*/ +AL_INLINE void AL_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 +*/ +AL_INLINE uint8_t AL_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 +*/ +AL_INLINE void AL_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 +*/ +AL_INLINE uint8_t AL_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 +*/ +AL_INLINE uint8_t AL_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 +*/ +AL_INLINE void AL_API +ib_port_info_set_phy_and_overrun_err_thd( + IN ib_port_info_t* const p_pi, + IN uint8_t phy_threshold, + IN uint8_t overrun_threshold ) +{ + p_pi->error_threshold = + (uint8_t)( ((phy_threshold & 0x0F) << 4) | (overrun_threshold & 0x0F) ); +} +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* phy_threshold +* [in] Physical Link Errors Threshold above which Trap 129 is generated +* +* overrun_threshold +* [in] Credits overrun Errors Threshold above which Trap 129 is generated +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +typedef uint8_t ib_svc_name_t[64]; + +#include +typedef struct _ib_service_record +{ + ib_net64_t service_id; + ib_gid_t service_gid; + ib_net16_t service_pkey; + ib_net16_t resv; + ib_net32_t service_lease; + uint8_t service_key[16]; + ib_svc_name_t service_name; + uint8_t service_data8[16]; + ib_net16_t service_data16[8]; + ib_net32_t service_data32[4]; + ib_net64_t service_data64[2]; + +} PACK_SUFFIX ib_service_record_t; +#include + +#include +typedef struct _ib_portinfo_record +{ + ib_net16_t lid; + uint8_t port_num; + uint8_t resv; + ib_port_info_t port_info; + +} PACK_SUFFIX ib_portinfo_record_t; +#include + +#include +typedef struct _ib_link_record +{ + ib_net16_t from_lid; + uint8_t from_port_num; + uint8_t to_port_num; + ib_net16_t to_lid; + uint8_t pad[2]; + +} PACK_SUFFIX ib_link_record_t; +#include + +#include +typedef struct _ib_sminfo_record +{ + ib_net16_t lid; + uint16_t resv0; + ib_sm_info_t sm_info; + uint8_t pad[7]; + +} PACK_SUFFIX ib_sminfo_record_t; +#include + +/****s* IBA Base: Types/ib_lft_record_t +* NAME +* ib_lft_record_t +* +* DESCRIPTION +* IBA defined LinearForwardingTableRecord (15.2.5.6) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_lft_record +{ + ib_net16_t lid; + ib_net16_t block_num; + uint32_t resv0; + uint8_t lft[64]; +} PACK_SUFFIX ib_lft_record_t; +#include +/************/ + +/****s* IBA Base: Types/ib_mft_record_t +* NAME +* ib_mft_record_t +* +* DESCRIPTION +* IBA defined MulticastForwardingTableRecord (15.2.5.8) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_mft_record +{ + ib_net16_t lid; + ib_net16_t position_block_num; + uint32_t resv0; + ib_net16_t mft[IB_MCAST_BLOCK_SIZE]; +} PACK_SUFFIX ib_mft_record_t; +#include +/************/ + +/****s* IBA Base: Types/ib_switch_info_t +* NAME +* ib_switch_info_t +* +* DESCRIPTION +* IBA defined SwitchInfo. (14.2.5.4) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_switch_info +{ + ib_net16_t lin_cap; + ib_net16_t rand_cap; + ib_net16_t mcast_cap; + ib_net16_t lin_top; + uint8_t def_port; + uint8_t def_mcast_pri_port; + uint8_t def_mcast_not_port; + uint8_t life_state; + ib_net16_t lids_per_port; + ib_net16_t enforce_cap; + uint8_t flags; + uint8_t resvd; + ib_net16_t mcast_top; + +} PACK_SUFFIX ib_switch_info_t; +#include +/************/ + +#include +typedef struct _ib_switch_info_record +{ + ib_net16_t lid; + uint16_t resv0; + ib_switch_info_t switch_info; + +} PACK_SUFFIX ib_switch_info_record_t; +#include + +#define IB_SWITCH_PSC 0x04 + +/****f* IBA Base: Types/ib_switch_info_get_state_change +* NAME +* ib_switch_info_get_state_change +* +* DESCRIPTION +* Returns the value of the state change flag. +* +* SYNOPSIS +*/ +AL_INLINE boolean_t AL_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 +*/ +AL_INLINE void AL_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_si +* [in] Pointer to a SwitchInfo attribute. +* +* RETURN VALUES +* None +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_switch_info_get_opt_sl2vlmapping +* NAME +* ib_switch_info_get_state_opt_sl2vlmapping +* +* DESCRIPTION +* Returns the value of the optimized SLtoVLMapping programming flag. +* +* SYNOPSIS +*/ +static inline boolean_t AL_API +ib_switch_info_get_opt_sl2vlmapping(IN const ib_switch_info_t * const p_si) +{ + return ((p_si->life_state & 0x01) == 0x01); +} + +/* +* PARAMETERS +* p_si +* [in] Pointer to a SwitchInfo attribute. +* +* RETURN VALUES +* Returns the value of the optimized SLtoVLMapping programming flag. +* +* 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 +*/ +AL_INLINE boolean_t AL_API +ib_switch_info_is_enhanced_port0( + IN const ib_switch_info_t* const p_si ) +{ + return( (p_si->flags & 0x08) == 0x08 ); +} +/* +* PARAMETERS +* p_si +* [in] Pointer to a SwitchInfo attribute. +* +* RETURN VALUES +* Returns TRUE if the switch supports enhanced port 0. FALSE otherwise. +* +* NOTES +* +* SEE ALSO +*********/ + +/****s* IBA Base: Types/ib_guid_info_t +* NAME +* ib_guid_info_t +* +* DESCRIPTION +* IBA defined GuidInfo. (14.2.5.5) +* +* SYNOPSIS +*/ +#define GUID_TABLE_MAX_ENTRIES 8 + +#include +typedef struct _ib_guid_info +{ + ib_net64_t guid[GUID_TABLE_MAX_ENTRIES]; + +} PACK_SUFFIX ib_guid_info_t; +#include +/************/ + +#include +typedef struct _ib_guidinfo_record +{ + ib_net16_t lid; + uint8_t block_num; + uint8_t resv; + uint32_t reserved; + ib_guid_info_t guid_info; +} PACK_SUFFIX ib_guidinfo_record_t; +#include + +#define IB_MULTIPATH_MAX_GIDS 11 /* Support max that can fit into first MAD (for now) */ + +#include +typedef struct _ib_multipath_rec_t +{ + ib_net32_t hop_flow_raw; + uint8_t tclass; + uint8_t num_path; + ib_net16_t pkey; + ib_net16_t qos_class_sl; + uint8_t mtu; + uint8_t rate; + uint8_t pkt_life; + uint8_t service_id_8msb; + uint8_t independence; /* formerly resv2 */ + uint8_t sgid_count; + uint8_t dgid_count; + uint8_t service_id_56lsb[7]; + ib_gid_t gids[IB_MULTIPATH_MAX_GIDS]; +} PACK_SUFFIX ib_multipath_rec_t; +#include +/* +* FIELDS +* hop_flow_raw +* Global routing parameters: hop count, flow label and raw bit. +* +* tclass +* Another global routing parameter. +* +* num_path +* Reversible path - 1 bit to say if path is reversible. +* num_path [6:0] In queries, maximum number of paths to return. +* In responses, undefined. +* +* pkey +* Partition key (P_Key) to use on this path. +* +* qos_class_sl +* QoS class and service level to use on this path. +* +* mtu +* MTU and MTU selector fields to use on this path +* rate +* Rate and rate selector fields to use on this path. +* +* pkt_life +* Packet lifetime +* +* service_id_8msb +* 8 most significant bits of Service ID +* +* service_id_56lsb +* 56 least significant bits of Service ID +* +* preference +* Indicates the relative merit of this path versus other path +* records returned from the SA. Lower numbers are better. +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_multipath_rec_num_path +* NAME +* ib_multipath_rec_num_path +* +* DESCRIPTION +* Get max number of paths to return. +* +* SYNOPSIS +*/ +AL_INLINE uint8_t AL_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 AL_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 +*/ +AL_INLINE uint8_t AL_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 AL_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 AL_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 +*/ +AL_INLINE uint8_t AL_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 +*/ +AL_INLINE uint8_t AL_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 +*/ +AL_INLINE uint8_t AL_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 +*/ +AL_INLINE uint8_t AL_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 +*/ +AL_INLINE uint8_t AL_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 µsec * 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 +*/ +AL_INLINE uint8_t AL_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 AL_API +ib_multipath_rec_service_id(IN const ib_multipath_rec_t * const p_rec) +{ + union { + ib_net64_t sid; + uint8_t sid_arr[8]; + } sid_union; + sid_union.sid_arr[0] = p_rec->service_id_8msb; + memcpy(&sid_union.sid_arr[1], p_rec->service_id_56lsb, 7); + return sid_union.sid; +} + +/* +* PARAMETERS +* p_rec +* [in] Pointer to the multipath record object. +* +* RETURN VALUES +* Service ID +* +* NOTES +* +* SEE ALSO +* ib_multipath_rec_t +*********/ + +#define IB_NUM_PKEY_ELEMENTS_IN_BLOCK 32 +/****s* IBA Base: Types/ib_pkey_table_t +* NAME +* ib_pkey_table_t +* +* DESCRIPTION +* IBA defined PKey table. (14.2.5.7) +* +* SYNOPSIS +*/ + +#include +typedef struct _ib_pkey_table +{ + ib_net16_t pkey_entry[IB_NUM_PKEY_ELEMENTS_IN_BLOCK]; + +} PACK_SUFFIX ib_pkey_table_t; +#include +/************/ + +/****s* IBA Base: Types/ib_pkey_table_record_t +* NAME +* ib_pkey_table_record_t +* +* DESCRIPTION +* IBA defined P_Key Table Record for SA Query. (15.2.5.11) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_pkey_table_record +{ + ib_net16_t lid; // for CA: lid of port, for switch lid of port 0 + uint16_t block_num; + uint8_t port_num; // for switch: port number, for CA: reserved + uint8_t reserved1; + uint16_t reserved2; + ib_pkey_table_t pkey_tbl; + +} PACK_SUFFIX ib_pkey_table_record_t; +#include +/************/ + +#define IB_DROP_VL 15 +#define IB_MAX_NUM_VLS 16 +/****s* IBA Base: Types/ib_slvl_table_t +* NAME +* ib_slvl_table_t +* +* DESCRIPTION +* IBA defined SL2VL Mapping Table Attribute. (14.2.5.8) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_slvl_table +{ + uint8_t raw_vl_by_sl[IB_MAX_NUM_VLS/2]; + +} PACK_SUFFIX ib_slvl_table_t; +#include +/************/ + +/****s* IBA Base: Types/ib_slvl_table_record_t +* NAME +* ib_slvl_table_record_t +* +* DESCRIPTION +* IBA defined SL to VL Mapping Table Record for SA Query. (15.2.5.4) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_slvl_table_record +{ + ib_net16_t lid; // for CA: lid of port, for switch lid of port 0 + uint8_t in_port_num; // reserved for CAs + uint8_t out_port_num; // reserved for CAs + uint32_t resv; + ib_slvl_table_t slvl_tbl; + +} PACK_SUFFIX ib_slvl_table_record_t; +#include +/************/ + +/****f* IBA Base: Types/ib_slvl_table_set +* NAME +* ib_slvl_table_set +* +* DESCRIPTION +* Set slvl table entry. +* +* SYNOPSIS +*/ +AL_INLINE void AL_API +ib_slvl_table_set( + IN ib_slvl_table_t* p_slvl_tbl, + IN const uint8_t sl_index, + IN const 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 +*/ +AL_INLINE uint8_t AL_API +ib_slvl_table_get( +IN const ib_slvl_table_t* p_slvl_tbl, +IN const uint8_t sl_index ) +{ + uint8_t idx = sl_index/2; + CL_ASSERT(sl_index <= 15); + + if (sl_index % 2) + { + /* this is an odd sl. Need to return the ls bits. */ + return ( p_slvl_tbl->raw_vl_by_sl[idx] & 0x0F ); + } + else + { + /* this is an even sl. Need to return the ms bits. */ + return ( (p_slvl_tbl->raw_vl_by_sl[idx] & 0xF0) >> 4 ); + } +} +/* +* PARAMETERS +* p_slvl_tbl +* [in] pointer to ib_slvl_table_t object. +* +* sl_index +* [in] the sl index in the table whose value should be returned. +* +* RETURN VALUES +* vl for the requested sl_index. +* +* NOTES +* +* SEE ALSO +* ib_slvl_table_t +*********/ + +/****s* IBA Base: Types/ib_vl_arb_element_t +* NAME +* ib_vl_arb_element_t +* +* DESCRIPTION +* IBA defined VL Arbitration Table Element. (14.2.5.9) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_vl_arb_element +{ + uint8_t vl; + uint8_t weight; +} PACK_SUFFIX ib_vl_arb_element_t; +#include +/************/ + +/****f* IBA Base: Types/ib_vl_arb_element_get_vl +* NAME +* ib_vl_arb_element_get_vl +* +* DESCRIPTION +* Retrieves the VL from a VL arbitration table element. +* +* SYNOPSIS +*/ +AL_INLINE uint8_t AL_API +ib_vl_arb_element_get_vl( + IN const ib_vl_arb_element_t vl_arb_element ) +{ + return (vl_arb_element.vl >> 4); +} +/* +* PARAMETERS +* vl_arb_element +* [in] VL arbitration table element from which to return the VL. +* +* RETURN VALUES +* Returns the VL value for the specified VL arbitration table element. +* +* SEE ALSO +* vl_arb_element, ib_vl_arb_element_set_vl +*********/ + +/****f* IBA Base: Types/ib_vl_arb_element_set_vl +* NAME +* ib_vl_arb_element_set_vl +* +* DESCRIPTION +* Retrieves the VL from a VL arbitration table element. +* +* SYNOPSIS +*/ +AL_INLINE void AL_API +ib_vl_arb_element_set_vl( + IN OUT ib_vl_arb_element_t* const p_vl_arb_element, + IN const uint8_t vl ) +{ + p_vl_arb_element->vl = vl << 4; +} +/* +* PARAMETERS +* vl_arb_element +* [in/out] VL arbitration table element in which to store the VL. +* +* vl +* [in] VL to store in the specified element. +* +* RETURN VALUES +* This function does not return a value. +* +* SEE ALSO +* vl_arb_element, ib_vl_arb_element_get_vl +*********/ + +#define IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK 32 + +/****s* IBA Base: Types/ib_vl_arb_table_t +* NAME +* ib_vl_arb_table_t +* +* DESCRIPTION +* IBA defined VL Arbitration Table. (14.2.5.9) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_vl_arb_table +{ + ib_vl_arb_element_t vl_entry[IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK]; +} PACK_SUFFIX ib_vl_arb_table_t; +#include +/************/ + +/****s* IBA Base: Types/ib_vl_arb_table_record_t +* NAME +* ib_vl_arb_table_record_t +* +* DESCRIPTION +* IBA defined VL Arbitration Table Record for SA Query. (15.2.5.9) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_vl_arb_table_record +{ + ib_net16_t lid; // for CA: lid of port, for switch lid of port 0 + uint8_t port_num; + uint8_t block_num; + uint32_t reserved; + ib_vl_arb_table_t vl_arb_tbl; +} PACK_SUFFIX ib_vl_arb_table_record_t; +#include +/************/ + +/****s* IBA Base: Types/ib_grh_t +* NAME +* ib_grh_t +* +* DESCRIPTION +* Global route header information received with unreliable datagram messages +* +* SYNOPSIS +*/ +#include +typedef struct _ib_grh +{ + ib_net32_t ver_class_flow; + uint16_t resv1; + uint8_t resv2; + uint8_t hop_limit; + ib_gid_t src_gid; + ib_gid_t dest_gid; +} PACK_SUFFIX ib_grh_t; +#include +/************/ + +/****f* IBA Base: Types/ib_grh_get_ver_class_flow +* NAME +* ib_grh_get_ver_class_flow +* +* DESCRIPTION +* Get encoded version, traffic class and flow label in grh +* +* SYNOPSIS +*/ +AL_INLINE void AL_API +ib_grh_get_ver_class_flow( + IN const ib_net32_t ver_class_flow, + OUT uint8_t* const p_ver OPTIONAL, + OUT uint8_t* const p_tclass OPTIONAL, + OUT net32_t* const p_flow_lbl OPTIONAL ) +{ + ib_net32_t tmp_ver_class_flow; + + tmp_ver_class_flow = cl_ntoh32( ver_class_flow ); + + if (p_ver) + *p_ver = (uint8_t)(tmp_ver_class_flow >> 28); + + if (p_tclass) + *p_tclass = (uint8_t)(tmp_ver_class_flow >> 20); + + if (p_flow_lbl) + *p_flow_lbl = (ver_class_flow & CL_HTON32( 0x000FFFFF )); +} +/* +* 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 +*/ +AL_INLINE ib_net32_t AL_API +ib_grh_set_ver_class_flow( + IN const uint8_t ver, + IN const uint8_t tclass, + IN const net32_t flow_lbl ) +{ + ib_net32_t ver_class_flow; + + ver_class_flow = cl_hton32( (ver << 28) | (tclass << 20) ); + ver_class_flow |= (flow_lbl & CL_HTON32( 0x000FFFFF )); + return (ver_class_flow); +} +/* +* PARAMETERS +* ver +* [in] the version info. +* +* tclass +* [in] the traffic class info. +* +* flow_lbl +* [in] the flow label info +* +* RETURN VALUES +* ver_class_flow +* [out] the version, traffic class and flow label info. +* +* NOTES +* +* SEE ALSO +* ib_grh_t +*********/ + +/****s* IBA Base: Types/ib_member_rec_t +* NAME +* ib_member_rec_t +* +* DESCRIPTION +* Multicast member record, used to create, join, and leave multicast +* groups. +* +* SYNOPSIS +*/ +#include +typedef struct _ib_member_rec +{ + ib_gid_t mgid; + ib_gid_t port_gid; + ib_net32_t qkey; + ib_net16_t mlid; + uint8_t mtu; + uint8_t tclass; + ib_net16_t pkey; + uint8_t rate; + uint8_t pkt_life; + ib_net32_t sl_flow_hop; + uint8_t scope_state; + uint8_t proxy_join; + uint8_t reserved[2]; + uint8_t pad[4]; + +} PACK_SUFFIX ib_member_rec_t; +#include +/* +* FIELDS +* mgid +* Multicast GID address for this multicast group. +* +* port_gid +* Valid GID of the endpoint joining this multicast group. +* +* qkey +* Q_Key to be used 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 +*/ +AL_INLINE void AL_API +ib_member_get_sl_flow_hop( + IN const ib_net32_t sl_flow_hop, + OUT uint8_t* const p_sl OPTIONAL, + OUT net32_t* const p_flow_lbl OPTIONAL, + OUT uint8_t* const p_hop OPTIONAL ) +{ + ib_net32_t tmp_sl_flow_hop; + + if (p_sl) + *p_sl = (uint8_t)(sl_flow_hop & 0x0f); + + tmp_sl_flow_hop = sl_flow_hop >> 4; + + if (p_flow_lbl) + *p_flow_lbl = (uint32_t)(tmp_sl_flow_hop & 0xffffff); + + tmp_sl_flow_hop = tmp_sl_flow_hop >> 20; + + if (p_hop) + *p_hop = (uint8_t)(tmp_sl_flow_hop & 0xff); +} +/* +* 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 +*/ +AL_INLINE ib_net32_t AL_API +ib_member_set_sl_flow_hop( + IN const uint8_t sl, + IN const net32_t flow_lbl, + IN const uint8_t hop_limit ) +{ + ib_net32_t sl_flow_hop; + + sl_flow_hop = sl; + sl_flow_hop <<= 20; + sl_flow_hop |= (cl_ntoh32( flow_lbl ) & 0x000FFFFF); + sl_flow_hop <<= 8; + sl_flow_hop |= hop_limit; + return cl_hton32(sl_flow_hop); +} +/* +* 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 +* NAME +* ib_member_get_scope +* +* DESCRIPTION +* Get encoded MGID scope +* +* SYNOPSIS +*/ +AL_INLINE uint8_t AL_API +ib_member_get_scope( + IN const uint8_t scope_state ) +{ + return (scope_state >> 4); +} +/* +* PARAMETERS +* scope_state +* [in] the scope and state +* +* RETURN VALUES +* Encoded scope. +* +* SEE ALSO +* ib_member_rec_t +*********/ + +/****f* IBA Base: Types/ib_member_get_state +* NAME +* ib_member_get_state +* +* DESCRIPTION +* Get encoded MGID JoinState +* +* SYNOPSIS +*/ +AL_INLINE uint8_t AL_API +ib_member_get_state( + IN const uint8_t scope_state ) +{ + return (scope_state & 0x0f); +} +/* +* PARAMETERS +* scope_state +* [in] the scope and state +* +* RETURN VALUES +* Encoded JoinState +* +* 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 +*/ +AL_INLINE void AL_API +ib_member_get_scope_state( + IN const uint8_t scope_state, + OUT uint8_t* const p_scope, + OUT uint8_t* const p_state ) +{ + if (p_scope) + *p_scope = ib_member_get_scope( scope_state ); + + if (p_state) + *p_state = ib_member_get_state( scope_state ); +} +/* +* 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 +* NAME +* ib_member_set_scope +* +* DESCRIPTION +* Set encoded scope of a MCR. +* +* SYNOPSIS +*/ +AL_INLINE void AL_API +ib_member_set_scope( + IN OUT uint8_t* const p_scope_state, + IN const uint8_t scope ) +{ + CL_ASSERT( scope <= 0x0F ); + /* Scope is MS 4-bits. */ + *p_scope_state &= 0xF0; + *p_scope_state |= (scope << 4); +} +/* +* PARAMETERS +* scope_state +* [in/out] Pointer to the MCR scope_state field. +* +* scope +* [in] The desired scope. +* +* RETURN VALUES +* This function does not return a value. +* +* SEE ALSO +* ib_member_rec_t +*********/ + +/****f* IBA Base: Types/ib_member_set_state +* NAME +* ib_member_set_state +* +* DESCRIPTION +* Set encoded JoinState of a MCR. +* +* SYNOPSIS +*/ +AL_INLINE void AL_API +ib_member_set_state( + IN OUT uint8_t* const p_scope_state, + IN const uint8_t state ) +{ + CL_ASSERT( state <= 0x0F ); + /* State is LS 4-bits. */ + *p_scope_state &= 0x0F; + *p_scope_state |= (state & 0x0F); +} +/* +* PARAMETERS +* scope_state +* [in/out] Pointer to the MCR scope_state field to modify. +* +* state +* [in] the JoinState +* +* RETURN VALUES +* This function does not return a value. +* +* 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 +*/ +AL_INLINE uint8_t AL_API +ib_member_set_scope_state( + IN const uint8_t scope, + IN const uint8_t state ) +{ + /* Scope is MS 4-bits, state is LS 4-bits */ + return ((scope << 4) | (state & 0xF)); +} +/* +* 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 +*/ +AL_INLINE void AL_API +ib_member_set_join_state( + IN OUT ib_member_rec_t *p_mc_rec, + IN const uint8_t state ) +{ + p_mc_rec->scope_state &= 0xF0; + p_mc_rec->scope_state |= (state & 0x0F); +} +/* +* 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_MEMBER 0x04 + +/* + * Generic MAD notice types + */ +#define IB_NOTICE_TYPE_FATAL 0x00 +#define IB_NOTICE_TYPE_URGENT 0x01 +#define IB_NOTICE_TYPE_SECURITY 0x02 +#define IB_NOTICE_TYPE_SUBN_MGMT 0x03 +#define IB_NOTICE_TYPE_INFO 0x04 +#define IB_NOTICE_TYPE_EMPTY 0x7F + +#include +typedef struct _ib_mad_notice_attr // Total Size calc Accumulated +{ + uint8_t generic_type; // 1 1 + + union _notice_g_or_v + { + struct _notice_generic // 5 6 + { + uint8_t prod_type_msb; + ib_net16_t prod_type_lsb; + ib_net16_t trap_num; + } PACK_SUFFIX generic; + + struct _notice_vend + { + uint8_t vend_id_msb; + ib_net16_t vend_id_lsb; + ib_net16_t dev_id; + } PACK_SUFFIX vend; + } g_or_v; + + ib_net16_t issuer_lid; // 2 8 + ib_net16_t toggle_count; // 2 10 + + union _data_details // 54 64 + { + struct _raw_data + { + uint8_t details[54]; + } PACK_SUFFIX raw_data; + + struct _ntc_64_67 + { + uint8_t res[6]; + ib_gid_t gid; // the Node or Multicast Group that came in/out + } PACK_SUFFIX ntc_64_67; + + struct _ntc_128 { + ib_net16_t sw_lid; // the sw lid of which link state changed + } PACK_SUFFIX ntc_128; + + struct _ntc_129_131 { + ib_net16_t pad; + ib_net16_t lid; // lid and port number of the violation + uint8_t port_num; + } PACK_SUFFIX ntc_129_131; + + struct _ntc_144 { + ib_net16_t pad1; + ib_net16_t lid; // lid where capability mask changed + uint8_t pad2; + uint8_t local_changes; + ib_net32_t new_cap_mask; // new capability mask + ib_net16_t change_flgs; + } 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 pad2; // 2 + uint8_t method; // 1 + uint8_t pad3; // 1 + ib_net16_t attr_id; // 2 + ib_net32_t attr_mod; // 4 + ib_net64_t mkey; // 8 + uint8_t dr_slid; // 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 // p/q_key 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; + + struct _ntc_bkey_259 // bkey violation + { + ib_net16_t lidaddr; + uint8_t method; + uint8_t reserved; + ib_net16_t attribute_id; + ib_net32_t attribute_modifier; + ib_net32_t qp; // qp is low 24 bits + ib_net64_t bkey; + ib_gid_t gid; + } PACK_SUFFIX ntc_bkey_259; + + struct _ntc_cckey_0 // CC key violation + { + ib_net16_t slid; // source LID from offending packet LRH + uint8_t method; // method, from common MAD header + uint8_t resv0; + ib_net16_t attribute_id; // Attribute ID, from common MAD header + ib_net16_t resv1; + ib_net32_t attribute_modifier;// Attribute Modif, from common MAD header + ib_net32_t qp; // 8b pad, 24b dest QP from BTH + ib_net64_t cc_key; // CC key of the offending packet + ib_gid_t source_gid; // GID from GRH of the offending packet + uint8_t padding[14]; // Padding - ignored on read + } PACK_SUFFIX ntc_cckey_0; + + } data_details; + + ib_gid_t issuer_gid; // 16 80 + +} PACK_SUFFIX ib_mad_notice_attr_t; +#include + +/** + * Trap 259 masks + */ +#define TRAP_259_MASK_SL (CL_HTON32(0xF0000000)) +#define TRAP_259_MASK_QP (CL_HTON32(0x00FFFFFF)) + +/** + * Trap 144 masks + */ +#define TRAP_144_MASK_OTHER_LOCAL_CHANGES 0x01 +#define TRAP_144_MASK_SM_PRIORITY_CHANGE (CL_HTON16(0x0008)) +#define TRAP_144_MASK_LINK_SPEED_ENABLE_CHANGE (CL_HTON16(0x0004)) +#define TRAP_144_MASK_LINK_WIDTH_ENABLE_CHANGE (CL_HTON16(0x0002)) +#define TRAP_144_MASK_NODE_DESCRIPTION_CHANGE (CL_HTON16(0x0001)) + +/****f* IBA Base: Types/ib_notice_is_generic +* NAME +* ib_notice_is_generic +* +* DESCRIPTION +* Check if the notice is generic +* +* SYNOPSIS +*/ +static inline boolean_t AL_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 AL_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 AL_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 AL_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 AL_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 AL_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 AL_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 AL_API +ib_notice_set_vend_id_ho(IN ib_mad_notice_attr_t * p_ntc, + IN uint32_t vend_id_ho) +{ + p_ntc->g_or_v.vend.vend_id_lsb = + cl_hton16((uint16_t) (vend_id_ho & 0x0000ffff)); + p_ntc->g_or_v.vend.vend_id_msb = + (uint8_t) ((vend_id_ho & 0x00ff0000) >> 16); +} + +/* +* PARAMETERS +* p_ntc +* [in] Pointer to the notice MAD attribute +* +* vend_id_ho +* [in] The producer Type code in host order +* +* RETURN VALUES +* None +* +* SEE ALSO +* ib_mad_notice_attr_t +*********/ + +#include +typedef struct _ib_inform_info +{ + ib_gid_t gid; + ib_net16_t lid_range_begin; + ib_net16_t lid_range_end; + ib_net16_t reserved1; + uint8_t is_generic; + uint8_t subscribe; + ib_net16_t trap_type; + union _inform_g_or_v { + struct _inform_generic { + ib_net16_t trap_num; + ib_net32_t qpn_resp_time_val; + uint8_t reserved2; + uint8_t node_type_msb; + ib_net16_t node_type_lsb; + } PACK_SUFFIX generic; + struct _inform_vend { + ib_net16_t dev_id; + ib_net32_t qpn_resp_time_val; + uint8_t reserved2; + uint8_t vendor_id_msb; + ib_net16_t vendor_id_lsb; + } PACK_SUFFIX vend; + } PACK_SUFFIX g_or_v; +} PACK_SUFFIX ib_inform_info_t; +#include + +/****f* IBA Base: Types/ib_inform_info_get_qpn_resp_time +* NAME +* ib_inform_info_get_qpn_resp_time +* +* DESCRIPTION +* Get QPN of the inform info +* +* SYNOPSIS +*/ +AL_INLINE void AL_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 +*/ +AL_INLINE void AL_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 +*/ +AL_INLINE ib_net32_t AL_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 +*/ +AL_INLINE ib_net32_t AL_API +ib_inform_info_get_vend_id(IN const ib_inform_info_t * p_inf) +{ + uint32_t vi; + + vi = cl_ntoh16(p_inf->g_or_v.vend.vendor_id_lsb) | + (p_inf->g_or_v.vend.vendor_id_msb << 16); + return cl_hton32(vi); +} + +/* +* PARAMETERS +* p_inf +* [in] pointer to an inform info +* +* RETURN VALUES +* The node type +* +* NOTES +* +* SEE ALSO +* ib_inform_info_t +*********/ + +/****s* IBA Base: Types/ib_inform_info_record_t +* NAME +* ib_inform_info_record_t +* +* DESCRIPTION +* IBA defined InformInfo Record. (15.2.5.12) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_inform_info_record +{ + ib_gid_t subscriber_gid; + net16_t subscriber_enum; + uint8_t reserved[6]; + ib_inform_info_t inform_info; + uint8_t pad[4]; + +} PACK_SUFFIX ib_inform_info_record_t; +#include +/********/ + +/****s* IBA Base: Types/ib_perfmgt_mad_t +* NAME +* ib_perfmgt_mad_t +* +* DESCRIPTION +* IBA defined Perf Management MAD (16.3.1) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_perfmgt_mad { + ib_mad_t header; + uint8_t resv[40]; +#define IB_PM_DATA_SIZE 192 + uint8_t data[IB_PM_DATA_SIZE]; +} PACK_SUFFIX ib_perfmgt_mad_t; +#include +/* +* FIELDS +* header +* Common MAD header. +* +* resv +* Reserved. +* +* data +* Performance Management payload. The structure and content of this field +* depends upon the method, attr_id, and attr_mod fields in the header. +* +* SEE ALSO +* ib_mad_t +*********/ + +/****s* IBA Base: Types/ib_port_rcv_data_sl +* NAME +* ib_port_rcv_data_sl_t +* +* DESCRIPTION +* IBA defined PortRcvDataSL Attribute. (A13.6.4) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_port_rcv_data_sl { + uint8_t reserved; + uint8_t port_select; + ib_net16_t counter_select; + ib_net32_t port_rcv_data_sl[16]; + uint8_t resv[124]; +} PACK_SUFFIX ib_port_rcv_data_sl_t; +#include + +/****d* IBA Base: Types/DM_SVC_NAME +* NAME +* DM_SVC_NAME +* +* DESCRIPTION +* IBA defined Device Management service name (16.3) +* +* SYNOPSIS +*/ +#define DM_SVC_NAME "DeviceManager.IBTA" +/* +* SEE ALSO +*********/ + +/****s* IBA Base: Types/ib_dm_mad_t +* NAME +* ib_dm_mad_t +* +* DESCRIPTION +* IBA defined Device Management MAD (16.3.1) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_dm_mad +{ + ib_mad_t hdr; + uint8_t resv[40]; + +#define IB_DM_DATA_SIZE 192 + uint8_t data[IB_DM_DATA_SIZE]; + +} PACK_SUFFIX ib_dm_mad_t; +#include +/* +* FIELDS +* hdr +* Common MAD header. +* +* resv +* Reserved. +* +* data +* Device Management payload. The structure and content of this field +* depend upon the method, attr_id, and attr_mod fields in the header. +* +* SEE ALSO +* ib_mad_t +*********/ + +/****s* IBA Base: Types/ib_iou_info_t +* NAME +* ib_iou_info_t +* +* DESCRIPTION +* IBA defined IO Unit information structure (16.3.3.3) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_iou_info +{ + ib_net16_t change_id; + uint8_t max_controllers; + uint8_t diag_rom; + +#define IB_DM_CTRL_LIST_SIZE 128 +#define IB_DM_MAX_CTRL 0xFF; + + uint8_t controller_list[IB_DM_CTRL_LIST_SIZE]; +#define IOC_NOT_INSTALLED 0x0 +#define IOC_INSTALLED 0x1 +// Reserved values 0x02-0xE +#define SLOT_DOES_NOT_EXIST 0xF + +} PACK_SUFFIX ib_iou_info_t; +#include +/* +* FIELDS +* change_id +* Value incremented, with rollover, by any change to the controller_list. +* +* max_controllers +* Number of slots in controller_list. +* +* diag_rom +* A byte containing two fields: DiagDeviceID and OptionROM. +* These fields may be read using the ib_iou_info_diag_dev_id +* and ib_iou_info_option_rom functions. +* +* controller_list +* A series of 4-bit nibbles, with each nibble representing a slot +* in the IO Unit. Individual nibbles may be read using the +* ioc_at_slot function. +* +* SEE ALSO +* ib_dm_mad_t, ib_iou_info_diag_dev_id, ib_iou_info_option_rom, ioc_at_slot +*********/ + +/****f* IBA Base: Types/ib_iou_info_diag_dev_id +* NAME +* ib_iou_info_diag_dev_id +* +* DESCRIPTION +* Returns the DiagDeviceID. +* +* SYNOPSIS +*/ +AL_INLINE uint8_t AL_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 +*/ +AL_INLINE uint8_t AL_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 +*/ +AL_INLINE uint8_t AL_API +ioc_at_slot( + IN const ib_iou_info_t* const p_iou_info, + IN uint8_t slot ) +{ + if( !slot ) + return SLOT_DOES_NOT_EXIST; + else if( slot-- & 0x01 ) + return (p_iou_info->controller_list[slot >> 1] >> 4); + else + return (p_iou_info->controller_list[slot >> 1] & 0x0F); +} +/* +* PARAMETERS +* p_iou_info +* [in] Pointer to the IO Unit information structure. +* +* slot +* [in] 1-based slot number of the IOC slot to check. +* +* RETURN VALUES +* Returns the encoded value for the desired slot. Possible values are +* SLOT_DOES_NOT_EXIST, IOC_NOT_INSTALLED, and IOC_INSTALLED. +* +* NOTES +* The input slot number is 1-based, not zero based. +* +* SEE ALSO +* ib_iou_info_t +*********/ + +/****s* IBA Base: Types/ib_ioc_profile_t +* NAME +* ib_ioc_profile_t +* +* DESCRIPTION +* IBA defined IO Controller profile structure (16.3.3.4) +* +* SYNOPSIS +*/ +#include +typedef __declspec(align(8)) struct _ib_ioc_profile +{ + ib_net64_t ioc_guid; + + ib_net32_t vend_id; + + ib_net32_t dev_id; + ib_net16_t dev_ver; + ib_net16_t resv2; + + ib_net32_t subsys_vend_id; + ib_net32_t subsys_id; + + ib_net16_t io_class; + ib_net16_t io_subclass; + ib_net16_t protocol; + ib_net16_t protocol_ver; + + ib_net32_t resv3; + ib_net16_t send_msg_depth; + uint8_t resv4; + uint8_t rdma_read_depth; + ib_net32_t send_msg_size; + ib_net32_t rdma_size; + + uint8_t ctrl_ops_cap; +#define CTRL_OPS_CAP_ST 0x01 +#define CTRL_OPS_CAP_SF 0x02 +#define CTRL_OPS_CAP_RT 0x04 +#define CTRL_OPS_CAP_RF 0x08 +#define CTRL_OPS_CAP_WT 0x10 +#define CTRL_OPS_CAP_WF 0x20 +#define CTRL_OPS_CAP_AT 0x40 +#define CTRL_OPS_CAP_AF 0x80 + + uint8_t resv5; + + uint8_t num_svc_entries; +#define MAX_NUM_SVC_ENTRIES 0xff + + uint8_t resv6[9]; + +#define CTRL_ID_STRING_LEN 64 + char id_string[CTRL_ID_STRING_LEN]; + +} PACK_SUFFIX ib_ioc_profile_t; +#include +/* +* FIELDS +* ioc_guid +* An EUI-64 GUID used to uniquely identify the IO controller. +* +* vend_id +* IO controller vendor ID, IEEE format. +* +* dev_id +* A number assigned by the vendor to identify the type of controller. +* +* dev_ver +* A number assigned by the vendor to identify the divice version. +* +* subsys_vend_id +* ID of the vendor of the enclosure, if any, in which the IO controller +* resides in IEEE format; otherwise zero. +* +* subsys_id +* A number identifying the subsystem where the controller resides. +* +* io_class +* 0x0000 - 0xfffe = reserved for IO classes encompased by InfiniBand +* Architecture. 0xffff = Vendor specific. +* +* io_subclass +* 0x0000 - 0xfffe = reserved for IO subclasses encompased by InfiniBand +* Architecture. 0xffff = Vendor specific. This shall be set to 0xfff +* if the io_class component is 0xffff. +* +* protocol +* 0x0000 - 0xfffe = reserved for IO subclasses encompased by InfiniBand +* Architecture. 0xffff = Vendor specific. This shall be set to 0xfff +* if the io_class component is 0xffff. +* +* protocol_ver +* Protocol specific. +* +* send_msg_depth +* Maximum depth of the send message queue. +* +* rdma_read_depth +* Maximum depth of the per-channel RDMA read queue. +* +* send_msg_size +* Maximum size of send messages. +* +* ctrl_ops_cap +* Supported operation types of this IO controller. A bit set to one +* for affirmation of supported capability. +* +* num_svc_entries +* Number of entries in the service entries table. +* +* id_string +* UTF-8 encoded string for identifying the controller to an operator. +* +* SEE ALSO +* ib_dm_mad_t +*********/ + + +AL_INLINE uint32_t AL_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 ); +} + + +AL_INLINE void AL_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); +} + + +AL_INLINE uint32_t AL_API +ib_ioc_profile_get_subsys_vend_id( + IN const ib_ioc_profile_t* const p_ioc_profile ) +{ + return( cl_ntoh32(p_ioc_profile->subsys_vend_id) >> 8 ); +} + + +AL_INLINE void AL_API +ib_ioc_profile_set_subsys_vend_id( + IN ib_ioc_profile_t* const p_ioc_profile, + IN const uint32_t subsys_vend_id ) +{ + p_ioc_profile->subsys_id = (cl_hton32(subsys_vend_id) << 8); +} + +/****s* IBA Base: Types/ib_svc_entry_t +* NAME +* ib_svc_entry_t +* +* DESCRIPTION +* IBA defined IO Controller service entry structure (16.3.3.5) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_svc_entry +{ +#define MAX_SVC_ENTRY_NAME_LEN 40 + char name[MAX_SVC_ENTRY_NAME_LEN]; + + ib_net64_t id; + +} PACK_SUFFIX ib_svc_entry_t; +#include +/* +* FIELDS +* name +* UTF-8 encoded, null-terminated name of the service. +* +* id +* An identifier of the associated Service. +* +* SEE ALSO +* ib_svc_entries_t +*********/ + +/****s* IBA Base: Types/ib_svc_entries_t +* NAME +* ib_svc_entries_t +* +* DESCRIPTION +* IBA defined IO Controller service entry array (16.3.3.5) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_svc_entries +{ +#define SVC_ENTRY_COUNT 4 + ib_svc_entry_t service_entry[SVC_ENTRY_COUNT]; + +} PACK_SUFFIX ib_svc_entries_t; +#include +/* +* FIELDS +* service_entry +* An array of IO controller service entries. +* +* SEE ALSO +* ib_dm_mad_t, ib_svc_entry_t +*********/ + + +/****f* IBA Bases: Types/ib_dm_get_slot_lo_hi +* DESCRIPTION +* Returns the IOC slot number, and the lower and upper bound of the +* service entries given the attribute modifier of ServiceEntries response. +*/ +AL_INLINE void AL_API +ib_dm_get_slot_lo_hi( + IN const ib_net32_t slot_lo_hi, + OUT uint8_t *const p_slot OPTIONAL, + OUT uint8_t *const p_lo OPTIONAL, + OUT uint8_t *const p_hi OPTIONAL ) +{ + ib_net32_t tmp_slot_lo_hi = CL_NTOH32( slot_lo_hi ); + + if( p_slot ) + *p_slot = (uint8_t)( ( tmp_slot_lo_hi >> 16 ) ); + + if( p_hi ) + *p_hi = (uint8_t)( ( tmp_slot_lo_hi >> 8 ) ); + + if( p_lo ) + *p_lo = (uint8_t)( ( tmp_slot_lo_hi >> 0 ) ); +} +/* SEE ALSO +* ib_dm_set_slot_lo_hi +********/ + +/****f* IBA Bases: Types/ib_dm_set_slot_lo_hi +* DESCRIPTION +* Joins the IOC slot number, and the lower and upper bound of the service +* entries and returns it. +*/ +AL_INLINE net32_t AL_API +ib_dm_set_slot_lo_hi( + IN const uint8_t slot, + IN const uint8_t lo, + IN const uint8_t hi ) +{ + uint32_t tmp; + + tmp = slot << 16; + tmp |= hi << 8; + tmp |= lo; + return cl_hton32( tmp ); +} +/* SEE ALSO +* ib_dm_get_slot_lo_hi +********/ + +/* + * Information describing an I/O controller + */ +#pragma warning(disable:4324) +typedef struct _ib_ioc_info +{ + net64_t chassis_guid; + uint8_t chassis_slot; + net64_t iou_guid; + uint8_t iou_slot; + ib_ioc_profile_t profile; + +} ib_ioc_info_t; +#pragma warning(default:4324) + + +/* + * 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 92 +#define IB_MRA_PDATA_SIZE 222 +#define IB_REJ_PDATA_SIZE 148 +#define IB_REP_PDATA_SIZE 196 +#define IB_RTU_PDATA_SIZE 224 +#define IB_LAP_PDATA_SIZE 168 +#define IB_APR_PDATA_SIZE 148 +#define IB_DREQ_PDATA_SIZE 220 +#define IB_DREP_PDATA_SIZE 224 +#define IB_SIDR_REQ_PDATA_SIZE 216 +#define IB_SIDR_REP_PDATA_SIZE 136 + +#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 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 uint8_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 + + +/************/ +/****s* IBA Base: Types/ib_gmp_t +* NAME +* ib_gmp_t +* +* DESCRIPTION +* IBA defined GMP MAD format. (16.1.1) +* +* SYNOPSIS +*/ +#define IB_GMP_DATA_SIZE 200 + +#include +typedef struct _ib_gmp +{ + 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 resv2[40]; + uint8_t data[IB_GMP_DATA_SIZE]; + +} PACK_SUFFIX ib_gmp_t; +#include +/**********/ +#define IB_GMP_MAD_HDR_SIZE (sizeof(ib_gmp_t) - IB_GMP_DATA_SIZE) + + + +/************/ +/****s* IBA Base: Types/ib_port_counters_t +* NAME +* ib_gmp_t +* +* DESCRIPTION +* IBA defined PortCounters MAD format. (16.1.3.5) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_port_counters +{ + uint8_t reserved0; + uint8_t port_select; + ib_net16_t counter_select; + ib_net16_t symbol_error_counter; + uint8_t link_error_recovery_counter; + uint8_t link_down_counter; + ib_net16_t port_rcv_errors; + ib_net16_t port_rcv_remote_physical_errors; + ib_net16_t port_rcv_switch_relay_errors; + ib_net16_t port_xmit_discard; + uint8_t port_xmit_constraint_errors; + uint8_t port_rcv_constraint_errors; + uint8_t reserved1; + /* uint4_t excessive_buffer_overrun_errors; + uint4_t local_link_integrity_errors; */ + uint8_t lli_errors_exc_buf_errors; + ib_net16_t reserved2; + ib_net16_t vl15_dropped; + ib_net32_t port_xmit_data; + ib_net32_t port_rcv_data; + ib_net32_t port_xmit_pkts; + ib_net32_t port_rcv_pkts; + +} PACK_SUFFIX ib_port_counters_t; +#include +/**********/ + +#define IB_COUNTER_SYMBOL_ERROR CL_NTOH16(1<<0) +#define IB_COUNTER_LINK_RECOVERY_ERROR CL_NTOH16(1<<1) +#define IB_COUNTER_LINK_DOWN CL_NTOH16(1<<2) +#define IB_COUNTER_RCV_ERROR CL_NTOH16(1<<3) +#define IB_COUNTERT_RCV_RMT_PHY_ERROR CL_NTOH16(1<<4) +#define IB_COUNTER_RCV_SWITCH_RELAY_ERROR CL_NTOH16(1<<5) +#define IB_COUNTER_XMIT_DISCARD CL_NTOH16(1<<6) +#define IB_COUNTER_XMIT_CONSTRAIN CL_NTOH16(1<<7) +#define IB_COUNTER_RCV_CONSTRAIN CL_NTOH16(1<<8) +#define IB_COUNTER_LINK_INTEG_ERROR CL_NTOH16(1<<9) +#define IB_COUNTER_EXECE_BUF_ERROR CL_NTOH16(1<<10) +#define IB_COUNTER_VL15_DROP CL_NTOH16(1<<11) +#define IB_COUNTER_XMIT_DATA CL_NTOH16(1<<12) +#define IB_COUNTER_XMIT_PKT CL_NTOH16(1<<13) +#define IB_COUNTER_RCV_DATA CL_NTOH16(1<<14) +#define IB_COUNTER_RCV_PKT CL_NTOH16(1<<15) +#define IB_COUNTER_ALL 0xff + + +/* + * The following definitions are shared between the Access Layer and VPD + */ + + +typedef struct _ib_ca* ib_ca_handle_t; +typedef struct _ib_pd* ib_pd_handle_t; +typedef struct _ib_mr* ib_mr_handle_t; +typedef struct _ib_mw* ib_mw_handle_t; +typedef struct _ib_qp* ib_qp_handle_t; +typedef struct _ib_srq* ib_srq_handle_t; +typedef struct _ib_cq* ib_cq_handle_t; +typedef struct _ib_av* ib_av_handle_t; +typedef struct _ib_mcast* ib_mcast_handle_t; +typedef struct _mlnx_fmr* mlnx_fmr_handle_t; +typedef struct _mlnx_fmr_pool* mlnx_fmr_pool_handle_t; + + +/****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_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_SRQ_SIZE, + IB_INVALID_SERVICE_TYPE, + IB_INVALID_GID, + IB_INVALID_LID, + IB_INVALID_GUID, + IB_INVALID_GUID_MASK, + IB_INVALID_CA_HANDLE, + IB_INVALID_AV_HANDLE, + IB_INVALID_CQ_HANDLE, + IB_INVALID_QP_HANDLE, + IB_INVALID_SRQ_HANDLE, + IB_INVALID_PD_HANDLE, + IB_INVALID_MR_HANDLE, + IB_INVALID_FMR_HANDLE, + IB_INVALID_MW_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_INVALID_INDEX, + IB_NO_MATCH, + IB_PENDING, + IB_UNKNOWN_ERROR /* ALWAYS LAST ENUM VALUE! */ + +} ib_api_status_t; +/*****/ + + + +/****f* IBA Base: Types/ib_get_err_str +* NAME +* ib_get_err_str +* +* DESCRIPTION +* Returns a string for the specified status value. +* +* SYNOPSIS +*/ +AL_EXPORT const char* AL_API +ib_get_err_str( + IN ib_api_status_t 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_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_WQ_REQ_ERROR, + IB_AE_WQ_ACCESS_ERROR, + IB_AE_PORT_ACTIVE, + IB_AE_PORT_DOWN, + IB_AE_CLIENT_REREGISTER, + IB_AE_SRQ_LIMIT_REACHED, + IB_AE_SRQ_CATAS_ERROR, + IB_AE_SRQ_QP_LAST_WQE_REACHED, + IB_AE_RESET_DRIVER, + IB_AE_RESET_CLIENT, + IB_AE_RESET_END, + IB_AE_RESET_FAILED, + IB_AE_LID_CHANGE, + IB_AE_PKEY_CHANGE, + IB_AE_SM_CHANGE, + IB_AE_GID_CHANGE, + IB_AE_RESET_4_RMV, + 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_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_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_CLIENT_REREGISTER +* The SM idicate to client to reregister its SA records. +* +* IB_AE_SRQ_LIMIT_REACHED +* Reached SRQ low watermark +* +* IB_AE_SRQ_CATAS_ERROR +* An error occurred while processing or accessing the SRQ that prevents +* dequeuing a WQE from the SRQ and reporting of receive completions. +* +* IB_AE_SRQ_QP_LAST_WQE_REACHED +* An event, issued for a QP, associated with a shared receive queue, when +* a CQE is generated for the last WQE, or +* the QP gets in the Error State and there are no more WQEs on the RQ. +* +* IB_AE_RESET_DRIVER +* Device will be reset upon fatal error. +* +* IB_AE_RESET_CLIENT +* Device will be reset upon client request. +* +* IB_AE_RESET_END +* Device has been reset. +* +* IB_AE_RESET_FAILED +* Device reset failed. The Low Level Driver is inoperational. +* +* IB_AE_UNKNOWN +* An unknown error occurred which cannot be attributed to any +* resource; behavior is indeterminate. +* +*****/ + + +/****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 +*/ +AL_EXPORT const char* AL_API +ib_get_async_event_str( + IN ib_async_event_t 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 +{ + TO_LONG_PTR(void*, context); + ib_async_event_t type; + + /* HCA vendor specific event information. */ + uint64_t vendor_specific; + uint8_t port_number; + +} 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; + boolean_t ipd; + boolean_t pkey_switch_ext_port; + boolean_t bm; + boolean_t link_rtl; + boolean_t client_reregister; + +} 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 +*****/ + +enum rdma_transport_type { + RDMA_TRANSPORT_IB, + RDMA_TRANSPORT_IWARP, + RDMA_TRANSPORT_RDMAOE +}; + +/****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; + enum rdma_transport_type transport; + uint64_t max_msg_size; + ib_net16_t lid; + uint8_t lmc; + + uint8_t active_width; + + 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; + uint8_t active_speed; + uint8_t phys_state; + + 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. + */ + TO_LONG_PTR(ib_gid_t*, p_gid_table); + TO_LONG_PTR(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; + uint64_t max_addr_handles; + + uint32_t max_partitions; + + ib_atomic_t atomicity; + + uint8_t max_qp_resp_res; + uint8_t max_resp_res; + + uint8_t max_qp_init_depth; + + 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; + uint32_t max_srq; + uint32_t max_srq_wrs; + uint32_t max_srq_sges; + + /* + * 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 modify_srq_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; + boolean_t ipoib_csum; + + ib_net64_t system_image_guid; + + uint32_t num_page_sizes; + uint8_t num_ports; + + TO_LONG_PTR(uint32_t*, p_page_size); + TO_LONG_PTR(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 +* Maximum limit on number of responder resources for incomming RDMA +* operations on QPs. +* +* max_fmr +* Maximum number of Fast Memory Regions supported. +* +* max_map_per_fmr +* Maximum number of mappings, supported by a Fast Memory Region. +* +* max_srq +* Maximum number of Shared Receive Queues supported. +* +* max_srq_wrs +* Maximum number of work requests supported by this SRQ. +* +* max_srq_sges +* Maximum number of scatter gather elements supported per work request on SRQ. +* +* max_resp_res +* Maximum number of responder resources per HCA, with this HCA used as +* the target. +* +* max_qp_init_depth +* Maximimum initiator depth per QP for initiating RDMA reads and +* atomic operations. +* +* 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. +* +* modify_srq_depth +* Indicates ability to modify SRQ depth during a modify SRQ 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 +*/ +AL_EXPORT ib_ca_attr_t* AL_API +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 +*****/ + + +/****d* Access Layer/ib_pd_type_t +* NAME +* ib_pd_type_t +* +* DESCRIPTION +* Indicates the type of protection domain being allocated. +* +* SYNOPSIS +*/ +typedef enum _ib_pd_type +{ + IB_PDT_NORMAL, + IB_PDT_ALIAS, + IB_PDT_SQP, + IB_PDT_UD + +} ib_pd_type_t; +/* +* VALUES +* IB_PDT_NORMAL +* Protection domain for all non-aliased QPs. +* +* IB_PDT_ALIAS +* Protection domain for IB_QPT_QP0_ALIAS and IB_QPT_QP1_ALIAS QPs. +* +* IB_PDT_SQP +* Protection domain for special queue pair usage. +* +* IB_PDT_UD +* Protection domain for UD queue pair usage. +*****/ + + +/****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_QPT_UNKNOWN +} 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. +*****/ + + +/****f* IBA Base: Types/ib_get_qp_type_str +* NAME +* ib_get_qp_type_str +* +* DESCRIPTION +* Returns a string for the specified QP type +* +* SYNOPSIS +*/ +AL_EXPORT const char* AL_API +ib_get_qp_type_str( + IN uint8_t qp_type ); + +/* +* PARAMETERS +* qp_type +* [in] Encoded QP type as defined in the +QP attribute. + +* RETURN VALUES +* Pointer to the QP type string. +* +* NOTES +* +* SEE ALSO +* ib_qp_type_t +*********/ + +/****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; +/*****/ + +/****d* Access Layer/ib_srq_attr_mask_t +* NAME +* ib_srq_attr_mask_t +* +* DESCRIPTION +* Indicates valid fields in ib_srq_attr_t structure +* +* SYNOPSIS +*/ +typedef enum _ib_srq_attr_mask { + IB_SRQ_MAX_WR = 1 << 0, + IB_SRQ_LIMIT = 1 << 1, +} ib_srq_attr_mask_t; +/*****/ + + +/****s* Access Layer/ib_srq_attr_t +* NAME +* ib_srq_attr_t +* +* DESCRIPTION +* Attributes used to initialize a shared queue pair at creation time. +* +* SYNOPSIS +*/ +typedef struct _ib_srq_attr { + uint32_t max_wr; + uint32_t max_sge; + uint32_t srq_limit; +} ib_srq_attr_t; +/* +* FIELDS +* max_wr +* Specifies the max number of work request on SRQ. +* +* max_sge +* Specifies the max number of scatter/gather elements in one work request. +* +* srq_limit +* Specifies the low water mark for SRQ. +* +* SEE ALSO +* ib_qp_type_t, ib_srq_attr_mask_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; + + uint32_t sq_max_inline; + uint32_t sq_depth; + uint32_t rq_depth; + uint32_t sq_sge; + uint32_t rq_sge; + + TO_LONG_PTR(ib_cq_handle_t, h_sq_cq); + TO_LONG_PTR(ib_cq_handle_t, h_rq_cq); + TO_LONG_PTR(ib_srq_handle_t, h_srq); + + boolean_t sq_signaled; + +} ib_qp_create_t; +/* +* FIELDS +* type +* Specifies the type of queue pair to create. +* +* sq_max_inline +* Maximum payload that can be inlined directly in a WQE, eliminating +* protection checks and additional DMA operations. +* +* 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. +* +* h_srq +* A handle to an SRQ to get receive completions via. Must be coded NULL +* when QP is not associated with SRQ +* +* 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 +{ + TO_LONG_PTR(ib_pd_handle_t, h_pd); + ib_qp_type_t qp_type; + ib_access_t access_ctrl; + uint16_t pkey_index; + + uint32_t sq_max_inline; + uint32_t sq_depth; + uint32_t rq_depth; + uint32_t sq_sge; + uint32_t rq_sge; + uint8_t init_depth; + uint8_t resp_res; + + TO_LONG_PTR(ib_cq_handle_t, h_sq_cq); + TO_LONG_PTR(ib_cq_handle_t, h_rq_cq); + TO_LONG_PTR(ib_srq_handle_t,h_srq); + + 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 QP. +* +* sq_max_inline +* Maximum payload that can be inlined directly in a WQE, eliminating +* protection checks and additional DMA operations. +* +* 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_init + { + 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; + uint8_t rnr_nak_timeout; + + 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; + + } rtr; + + struct _qp_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_qp_opts_t opts; + uint8_t rnr_nak_timeout; + 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 +*****/ + + +/****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, + WR_RDMA_WRITE, + WR_RDMA_READ, + WR_COMPARE_SWAP, + WR_FETCH_ADD, + WR_LSO, + WR_NOP, + WR_UNKNOWN + +} ib_wr_type_t; +/*****/ + + +/****f* IBA Base: Types/ib_get_wr_type_str +* NAME +* ib_get_wr_type_str +* +* DESCRIPTION +* Returns a string for the specified work request type +* +* SYNOPSIS +*/ +AL_EXPORT const char* AL_API +ib_get_wr_type_str( + IN uint8_t wr_type ); + +/* +* PARAMETERS +* wr_type +* [in] Encoded work request type as defined in the +work request attribute. + +* RETURN VALUES +* Pointer to the work request type string. +* +* NOTES +* +* SEE ALSO +* 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 +{ + uint64_t 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_TX_IP_CSUM 0x00000040 +#define IB_SEND_OPT_TX_TCP_UDP_CSUM 0x00000080 + +#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 +{ + uint64_t wr_id; + struct _ib_send_wr* p_next; + ib_local_ds_t* ds_array; + uint32_t num_ds; + ib_wr_type_t wr_type; + ib_send_opt_t send_opt; + ib_net32_t immediate_data; + + union + { + union _send_dgrm + { + struct _send_ud + { + ib_av_handle_t h_av; + ib_net32_t remote_qp; + ib_net32_t remote_qkey; + void* rsvd; + uint16_t pkey_index; + void* header; + int hlen; + int mss; + } 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; + net32_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.ud.pkey_index +* The pkey index for this send work request. This is valid only +* for IB_QPT_QP1 and IB_QPT_QP1_ALIAS QP types. The work request +* is posted to using this pkey index build the GMP's BTH instead +* of the QP's pkey. +* +* dgrm.ud.rsvd +* Reserved for use by the Access Layer. +* +* 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 +{ + TO_LONG_PTR(struct _ib_recv_wr*, p_next); + uint64_t wr_id; + uint32_t num_ds; + TO_LONG_PTR(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; + + TO_LONG_PTR(ib_mr_handle_t, h_mr); + ib_access_t access_ctrl; + net32_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_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_BAD_RESP_ERR, + IB_WCS_LOCAL_ACCESS_ERR, + IB_WCS_GENERAL_ERR, + IB_WCS_UNMATCHED_RESPONSE, /* InfiniBand Access Layer */ + IB_WCS_CANCELED, /* InfiniBand Access Layer */ + IB_WCS_REM_ABORT_ERR, + 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_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_BAD_RESP_ERR, +* An unexpected transport layer opcode was returned +* by the responder. +* +* IB_WCS_LOCAL_ACCESS_ERR, +* A protection error occurred on a local data buffer +* during the processing of a RDMA Write with Immediate Data +* operation sent from the remote node. +* +* IB_WCS_REM_ABORT_ERR, +* The operation was aborted (e.g., For UD QPs associated with an SRQ, +* the responder aborted the operation). +* +* IB_WCS_REM_ABORT_ERR, +* The operation was aborted (e.g., For UD QPs associated with an SRQ, +* the responder aborted the operation). +* +* 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. + * + * IB_WCS_GENERAL_ERR, + * Any other error + * +*****/ + + + +/****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 +*/ +AL_EXPORT const char* AL_API +ib_get_wc_status_str( + IN ib_wc_status_t 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_RDMA_READ, + IB_WC_COMPARE_SWAP, + IB_WC_FETCH_ADD, + IB_WC_MW_BIND, + IB_WC_UNKNOWN1, + IB_WC_RECV = (1 << 7), + IB_WC_RECV_RDMA_WRITE, + IB_WC_LSO, + IB_WC_LOCAL_INV, + IB_WC_FAST_REG_MR, + IB_WC_UNKNOWN2 + +} ib_wc_type_t; +/*****/ + + +/****f* IBA Base: Types/ib_get_wc_type_str +* NAME +* ib_get_wc_type_str +* +* DESCRIPTION +* Returns a string for the specified work completion type. +* +* SYNOPSIS +*/ +AL_EXPORT const char* AL_API +ib_get_wc_type_str( + IN ib_wc_type_t wc_type ); +/* +* PARAMETERS +* wc_type +* [in] work completion type value +* +* RETURN VALUES +* Pointer to the work completion type description string. +* +* NOTES +* +* SEE ALSO +*********/ + + +/****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_INVALIDATE 0x00000008 +#define IB_RECV_OPT_VEND_MASK 0xFFFF0000 +#define IB_RECV_OPT_CSUM_MASK 0x0000FF00 +/* +* 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 +{ + TO_LONG_PTR(struct _ib_wc*, p_next); + uint64_t wr_id; + ib_wc_type_t wc_type; + + uint32_t length; + uint64_t vendor_specific; + ib_wc_status_t status; + + 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 +{ + TO_LONG_PTR(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 +*****/ + +#ifdef CL_KERNEL + +/****s* Access Layer/mlnx_fmr_create_t +* NAME +* mlnx_fmr_create_t +* +* DESCRIPTION +* Information required to create a Mellanox fast memory region. +* +* SYNOPSIS +*/ +typedef struct _mlnx_fmr_create +{ + int max_pages; + int max_maps; + uint8_t page_size; + ib_access_t access_ctrl; + +} mlnx_fmr_create_t; +/* +* FIELDS +* max_pages +* max pages in the region. +* +* max_maps +* max times, the region can be mapped before remapping. +* +* page_size +* log2 of the page size (e.g. 12 for 4KB). +* +* access_ctrl +* Access rights of the registered region. +* +* NOTES +* This is a Mellanox specific extension to verbs. +* +* SEE ALSO +* ib_access_t +*****/ + + +/****s* Access Layer/mlnx_fmr_pool_create_t +* NAME +* mlnx_fmr_pool_create_t +* +* DESCRIPTION +* Information required to create a Mellanox fast memory region pool. +* +* SYNOPSIS +*/ +typedef struct _mlnx_fmr_pool_create +{ + int max_pages_per_fmr; + uint8_t page_size; /* really - page_shift, log2 of page_size */ + enum ib_access_flags access_ctrl; + int pool_size; + int dirty_watermark; + void (*flush_function)(mlnx_fmr_pool_handle_t h_pool, void *arg); + void *flush_arg; + boolean_t cache; +} mlnx_fmr_pool_create_t; +/* +* FIELDS +* max_pages +* max pages in the region. +* +* max_maps +* max times, the region can be mapped before remapping. +* +* page_size +* log2 of the page size (e.g. 12 for 4KB). +* +* access_ctrl +* Access rights of the registered region. +* +* NOTES +* This is a Mellanox specific extension to verbs. +* +* SEE ALSO +* ib_access_t +*****/ +#endif + +/****s* Access Layer/ib_phys_range_t +* NAME +* ib_phys_range_t +* +* DESCRIPTION +* Information describing a physical memory range. +* +* SYNOPSIS +*/ +typedef struct _ib_phys_range +{ + uint64_t base_addr; + uint64_t size; + +} ib_phys_range_t; +/* +* FIELDS +* base_addr +* Physical address of the base of the memory range. +* +* size +* size, in bytes, of the memory range. +* +* NOTES +* The base address must be start and end on an HCA-supported page boundary. +* +* SEE ALSO +* ib_phys_create_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_ranges; + ib_phys_range_t* range_array; + uint32_t buf_offset; + uint32_t hca_page_size; + ib_access_t access_ctrl; +} ib_phys_create_t; +/* +* FIELDS +* length +* The length of the memory region in bytes. +* +* num_ranges +* Number of ib_phys_range structures listed in the specified range array. +* +* range_array +* An array of ib_phys_range structures to be registered as a single memory +* region. +* +* buf_offset +* The offset into the first physical memory range of the specified memory +* region on which to start the virtual address. +* +* hca_page_size +* The HCA page size to use to register the memory. +* +* 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 +{ + TO_LONG_PTR(ib_pd_handle_t, h_pd); + uint64_t local_lb; + uint64_t local_ub; + uint64_t remote_lb; + uint64_t remote_ub; + ib_access_t access_ctrl; + net32_t lkey; + net32_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. This is always a 64-bit quantity to support registering +* more than 4GB of memory on 32-bit systems with PAE. +* +* local_ub +* The virtual address of the upper bound of protection for local +* memory access. This is always a 64-bit quantity to support registering +* more than 4GB of memory on 32-bit systems with PAE. +* +* remote_lb +* The virtual address of the lower bound of protection for remote +* memory access. This is always a 64-bit quantity to support registering +* more than 4GB of memory on 32-bit systems with PAE. +* +* remote_ub +* The virtual address of the upper bound of protection for remote +* memory access. This is always a 64-bit quantity to support registering +* more than 4GB of memory on 32-bit systems with PAE. +* +* 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 +#define IB_CA_MOD_IS_CLIENT_REREGISTER_SUPPORTED 0x00800000 +#define IB_CA_MOD_RESERVED_MASK 0xFF000000 +/* +* 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. +* +* IB_CA_MOD_IS_CLIENT_REREGISTER_SUPPORTED +* Used to modify the system image GUID for the port. +* +* IB_CA_MOD_RESERVED_MASK +* Mask of all the reserved bits. If any of these bits are set +* ib_modify_ca will return IB_INVALID_PARAMETER. +*****/ + +/****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_STATE_INIT +* NAME +* IB_SMINFO_STATE_INIT +* +* DESCRIPTION +* Encoded state value used in the SMInfo attribute. +* +* SOURCE +*/ +#define IB_SMINFO_STATE_INIT 4 +/**********/ + +/****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_NTOH32(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_NTOH32(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_NTOH32(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_NTOH32(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_NTOH32(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 uint32_t buf_size; + IN uint32_t buf_info; + IN OUT int32_t status; + IN OUT TO_LONG_PTR(void*, p_buf) OPTIONAL; // Do not put it last in the structure, because of memory alignment + OUT uint32_t num_bytes_ret; + +} ib_ci_op_t; +/* +* FIELDS +* command +* A command code that is understood by the verbs provider. +* +* 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. +* +* buf_size +* The size of the buffer in bytes. +* +* buf_info +* Additional buffer information +* +* 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. +* +* 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. +* +* 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. +*****/ + +/****s* IBA Base: Types/ib_cc_mad_t +* NAME +* ib_cc_mad_t +* +* DESCRIPTION +* IBA defined Congestion Control MAD format. (A10.4.1) +* +* SYNOPSIS +*/ +#define IB_CC_LOG_DATA_SIZE 32 +#define IB_CC_MGT_DATA_SIZE 192 +#define IB_CC_MAD_HDR_SIZE (sizeof(ib_sa_mad_t) - IB_CC_LOG_DATA_SIZE \ + - IB_CC_MGT_DATA_SIZE) + +#include +typedef struct _ib_cc_mad { + ib_mad_t header; + ib_net64_t cc_key; + uint8_t log_data[IB_CC_LOG_DATA_SIZE]; + uint8_t mgt_data[IB_CC_MGT_DATA_SIZE]; +} PACK_SUFFIX ib_cc_mad_t; +#include +/* +* FIELDS +* header +* Common MAD header. +* +* cc_key +* CC_Key of the Congestion Control MAD. +* +* log_data +* Congestion Control log data of the CC MAD. +* +* mgt_data +* Congestion Control management data of the CC MAD. +* +* SEE ALSO +* ib_mad_t +*********/ + +/****f* IBA Base: Types/ib_cc_mad_get_cc_key +* NAME +* ib_cc_mad_get_cc_key +* +* DESCRIPTION +* Gets a CC_Key of the CC MAD. +* +* SYNOPSIS +*/ +static inline ib_net64_t AL_API +ib_cc_mad_get_cc_key(IN const ib_cc_mad_t * const p_cc_mad) +{ + return p_cc_mad->cc_key; +} +/* +* PARAMETERS +* p_cc_mad +* [in] Pointer to the CC MAD packet. +* +* RETURN VALUES +* CC_Key of the provided CC MAD packet. +* +* NOTES +* +* SEE ALSO +* ib_cc_mad_t +*********/ + +/****f* IBA Base: Types/ib_cc_mad_get_log_data_ptr +* NAME +* ib_cc_mad_get_mgt_data_ptr +* +* DESCRIPTION +* Gets a pointer to the CC MAD's log data area. +* +* SYNOPSIS +*/ +static inline void * AL_API +ib_cc_mad_get_log_data_ptr(IN const ib_cc_mad_t * const p_cc_mad) +{ + return ((void *)p_cc_mad->log_data); +} +/* +* PARAMETERS +* p_cc_mad +* [in] Pointer to the CC MAD packet. +* +* RETURN VALUES +* Pointer to CC MAD log data area. +* +* NOTES +* +* SEE ALSO +* ib_cc_mad_t +*********/ + +/****f* IBA Base: Types/ib_cc_mad_get_mgt_data_ptr +* NAME +* ib_cc_mad_get_mgt_data_ptr +* +* DESCRIPTION +* Gets a pointer to the CC MAD's management data area. +* +* SYNOPSIS +*/ +static inline void * AL_API +ib_cc_mad_get_mgt_data_ptr(IN const ib_cc_mad_t * const p_cc_mad) +{ + return ((void *)p_cc_mad->mgt_data); +} +/* +* PARAMETERS +* p_cc_mad +* [in] Pointer to the CC MAD packet. +* +* RETURN VALUES +* Pointer to CC MAD management data area. +* +* NOTES +* +* SEE ALSO +* ib_cc_mad_t +*********/ + +/****s* IBA Base: Types/ib_cong_info_t +* NAME +* ib_cong_info_t +* +* DESCRIPTION +* IBA defined CongestionInfo attribute (A10.4.3.3) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_cong_info { + uint8_t cong_info; + uint8_t resv; + uint8_t ctrl_table_cap; +} PACK_SUFFIX ib_cong_info_t; +#include +/* +* FIELDS +* cong_info +* Congestion control capabilities of the node. +* +* ctrl_table_cap +* Number of 64 entry blocks in the CongestionControlTable. +* +* SEE ALSO +* ib_cc_mad_t +*********/ + +/****s* IBA Base: Types/ib_cong_key_info_t +* NAME +* ib_cong_key_info_t +* +* DESCRIPTION +* IBA defined CongestionKeyInfo attribute (A10.4.3.4) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_cong_key_info { + ib_net64_t cc_key; + ib_net16_t protect_bit; + ib_net16_t lease_period; + ib_net16_t violations; +} PACK_SUFFIX ib_cong_key_info_t; +#include +/* +* FIELDS +* cc_key +* 8-byte CC Key. +* +* protect_bit +* Bit 0 is a CC Key Protect Bit, other 15 bits are reserved. +* +* lease_period +* How long the CC Key protect bit is to remain non-zero. +* +* violations +* Number of received MADs that violated CC Key. +* +* SEE ALSO +* ib_cc_mad_t +*********/ + +/****s* IBA Base: Types/ib_cong_log_event_sw_t +* NAME +* ib_cong_log_event_sw_t +* +* DESCRIPTION +* IBA defined CongestionLogEvent (SW) entry (A10.4.3.5) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_cong_log_event_sw { + ib_net16_t slid; + ib_net16_t dlid; + ib_net32_t sl; + ib_net32_t time_stamp; +} PACK_SUFFIX ib_cong_log_event_sw_t; +#include +/* +* FIELDS +* slid +* Source LID of congestion event. +* +* dlid +* Destination LID of congestion event. +* +* sl +* 4 bits - SL of congestion event. +* rest of the bits are reserved. +* +* time_stamp +* Timestamp of congestion event. +* +* SEE ALSO +* ib_cc_mad_t, ib_cong_log_t +*********/ + +/****s* IBA Base: Types/ib_cong_log_event_ca_t +* NAME +* ib_cong_log_event_ca_t +* +* DESCRIPTION +* IBA defined CongestionLogEvent (CA) entry (A10.4.3.5) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_cong_log_event_ca { + ib_net32_t local_qp_resv0; + ib_net32_t remote_qp_sl_service_type; + ib_net16_t remote_lid; + ib_net16_t resv1; + ib_net32_t time_stamp; +} PACK_SUFFIX ib_cong_log_event_ca_t; +#include +/* +* FIELDS +* resv0_local_qp +* bits [31:8] local QP that reached CN threshold. +* bits [7:0] reserved. +* +* remote_qp_sl_service_type +* bits [31:8] remote QP that is connected to local QP. +* bits [7:4] SL of the local QP. +* bits [3:0] Service Type of the local QP. +* +* remote_lid +* LID of the remote port that is connected to local QP. +* +* time_stamp +* Timestamp when threshold reached. +* +* SEE ALSO +* ib_cc_mad_t, ib_cong_log_t +*********/ + +/****s* IBA Base: Types/ib_cong_log_t +* NAME +* ib_cong_log_t +* +* DESCRIPTION +* IBA defined CongestionLog attribute (A10.4.3.5) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_cong_log { + uint8_t log_type; + union _log_details + { + struct _log_sw { + uint8_t cong_flags; + ib_net16_t event_counter; + ib_net32_t time_stamp; + uint8_t port_map[32]; + ib_cong_log_event_sw_t entry_list[15]; + } PACK_SUFFIX log_sw; + + struct _log_ca { + uint8_t cong_flags; + ib_net16_t event_counter; + ib_net16_t event_map; + ib_net16_t resv; + ib_net32_t time_stamp; + ib_cong_log_event_ca_t log_event[13]; + } PACK_SUFFIX log_ca; + + } log_details; +} PACK_SUFFIX ib_cong_log_t; +#include +/* +* FIELDS +* +* log_{sw,ca}.log_type +* Log type: 0x1 is for Switch, 0x2 is for CA +* +* log_{sw,ca}.cong_flags +* Congestion Flags. +* +* log_{sw,ca}.event_counter +* Number of events since log last sent. +* +* log_{sw,ca}.time_stamp +* Timestamp when log sent. +* +* log_sw.port_map +* If a bit set to 1, then the corresponding port +* has marked packets with a FECN. +* bits 0 and 255 - reserved +* bits [254..1] - ports [254..1]. +* +* log_sw.entry_list +* Array of 13 most recent congestion log events. +* +* log_ca.event_map +* array 16 bits, one for each SL. +* +* log_ca.log_event +* Array of 13 most recent congestion log events. +* +* SEE ALSO +* ib_cc_mad_t, ib_cong_log_event_sw_t, ib_cong_log_event_ca_t +*********/ + +/****s* IBA Base: Types/ib_sw_cong_setting_t +* NAME +* ib_sw_cong_setting_t +* +* DESCRIPTION +* IBA defined SwitchCongestionSetting attribute (A10.4.3.6) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_sw_cong_setting { + ib_net32_t control_map; + uint8_t victim_mask[32]; + uint8_t credit_mask[32]; + uint8_t threshold_resv; + uint8_t packet_size; + ib_net16_t cs_threshold_resv; + ib_net16_t cs_return_delay; + ib_net16_t marking_rate; +} PACK_SUFFIX ib_sw_cong_setting_t; +#include +/* +* FIELDS +* +* control_map +* Indicates which components of this attribute are valid +* +* victim_mask +* If the bit set to 1, then the port corresponding to +* that bit shall mark packets that encounter congestion +* with a FECN, whether they are the source or victim +* of congestion. (See A10.2.1.1.1) +* bit 0: port 0 (enhanced port 0 only) +* bits [254..1]: ports [254..1] +* bit 255: reserved +* +* credit_mask +* If the bit set to 1, then the port corresponding +* to that bit shall apply Credit Starvation. +* bit 0: port 0 (enhanced port 0 only) +* bits [254..1]: ports [254..1] +* bit 255: reserved +* +* threshold +* bits [15..12] Indicates how agressive cong. marking should be +* bits [11..0] Reserved +* +* packet_size +* Any packet less than this size won't be marked with FECN +* +* cs_threshold +* bits [7..4] How agressive Credit Starvation should be +* bits [3..0] Reserved +* +* cs_return_delay +* Value that controls credit return rate. +* +* marking_rate +* The value that provides the mean number of packets +* between marking eligible packets with FECN. +* +* SEE ALSO +* ib_cc_mad_t +*********/ + +/****s* IBA Base: Types/ib_sw_port_cong_setting_element_t +* NAME +* ib_sw_port_cong_setting_element_t +* +* DESCRIPTION +* IBA defined SwitchPortCongestionSettingElement (A10.4.3.7) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_sw_port_cong_setting_element { + uint8_t valid_ctrl_type_res_threshold; + uint8_t packet_size; + ib_net16_t cong_param; +} PACK_SUFFIX ib_sw_port_cong_setting_element_t; +#include +/* +* FIELDS +* +* valid_ctrl_type_res_threshold +* bit 7: "Valid" +* when set to 1, indicates this switch +* port congestion setting element is valid. +* bit 6: "Control Type" +* Indicates which type of attribute is being set: +* 0b = Congestion Control parameters are being set. +* 1b = Credit Starvation parameters are being set. +* bits [5..4]: reserved +* bits [3..0]: "Threshold" +* When Control Type is 0, contains the congestion +* threshold value (Threshold) for this port. +* When Control Type is 1, contains the credit +* starvation threshold (CS_Threshold) value for +* this port. +* +* packet_size +* When Control Type is 0, this field contains the minimum +* size of packets that may be marked with a FECN. +* When Control Type is 1, this field is reserved. +* +* cong_parm +* When Control Type is 0, this field contains the port +* marking_rate. +* When Control Type is 1, this field is reserved. +* +* SEE ALSO +* ib_cc_mad_t, ib_sw_port_cong_setting_t +*********/ + +/****d* IBA Base: Types/ib_sw_port_cong_setting_block_t +* NAME +* ib_sw_port_cong_setting_block_t +* +* DESCRIPTION +* Defines the SwitchPortCongestionSetting Block (A10.4.3.7). +* +* SOURCE +*/ +typedef ib_sw_port_cong_setting_element_t ib_sw_port_cong_setting_block_t[32]; +/**********/ + +/****s* IBA Base: Types/ib_sw_port_cong_setting_t +* NAME +* ib_sw_port_cong_setting_t +* +* DESCRIPTION +* IBA defined SwitchPortCongestionSetting attribute (A10.4.3.7) +* +* SYNOPSIS +*/ + +#include +typedef struct _ib_sw_port_cong_setting { + ib_sw_port_cong_setting_block_t block; +} PACK_SUFFIX ib_sw_port_cong_setting_t; +#include +/* +* FIELDS +* +* block +* SwitchPortCongestionSetting block. +* +* SEE ALSO +* ib_cc_mad_t, ib_sw_port_cong_setting_element_t +*********/ + +/****s* IBA Base: Types/ib_ca_cong_entry_t +* NAME +* ib_ca_cong_entry_t +* +* DESCRIPTION +* IBA defined CACongestionEntry (A10.4.3.8) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_ca_cong_entry { + ib_net16_t ccti_timer; + uint8_t ccti_increase; + uint8_t trigger_threshold; + uint8_t ccti_min; + uint8_t resv0; + ib_net16_t resv1; +} PACK_SUFFIX ib_ca_cong_entry_t; +#include +/* +* FIELDS +* +* ccti_timer +* When the timer expires it will be reset to its specified +* value, and 1 will be decremented from the CCTI. +* +* ccti_increase +* The number to be added to the table Index (CCTI) +* on the receipt of a BECN. +* +* trigger_threshold +* When the CCTI is equal to this value, an event +* is logged in the CAs cyclic event log. +* +* ccti_min +* The minimum value permitted for the CCTI. +* +* SEE ALSO +* ib_cc_mad_t +*********/ + +/****s* IBA Base: Types/ib_ca_cong_setting_t +* NAME +* ib_ca_cong_setting_t +* +* DESCRIPTION +* IBA defined CACongestionSetting attribute (A10.4.3.8) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_ca_cong_setting { + ib_net16_t port_control; + ib_net16_t control_map; + ib_ca_cong_entry_t entry_list[16]; +} PACK_SUFFIX ib_ca_cong_setting_t; +#include +/* +* FIELDS +* +* port_control +* Congestion attributes for this port: +* bit0 = 0: QP based CC +* bit0 = 1: SL/Port based CC +* All other bits are reserved +* +* control_map +* An array of sixteen bits, one for each SL. Each bit indicates +* whether or not the corresponding entry is to be modified. +* +* entry_list +* List of 16 CACongestionEntries, one per SL. +* +* SEE ALSO +* ib_cc_mad_t +*********/ + +/****s* IBA Base: Types/ib_cc_tbl_entry_t +* NAME +* ib_cc_tbl_entry_t +* +* DESCRIPTION +* IBA defined CongestionControlTableEntry (A10.4.3.9) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_cc_tbl_entry { + ib_net16_t shift_multiplier; +} PACK_SUFFIX ib_cc_tbl_entry_t; +#include +/* +* FIELDS +* +* shift_multiplier +* bits [15..14] - CCT Shift +* used when calculating the injection rate delay +* bits [13..0] - CCT Multiplier +* used when calculating the injection rate delay +* +* SEE ALSO +* ib_cc_mad_t +*********/ + +/****s* IBA Base: Types/ib_cc_tbl_t +* NAME +* ib_cc_tbl_t +* +* DESCRIPTION +* IBA defined CongestionControlTable attribute (A10.4.3.9) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_cc_tbl { + ib_net16_t ccti_limit; + ib_net16_t resv; + ib_cc_tbl_entry_t entry_list[64]; +} PACK_SUFFIX ib_cc_tbl_t; +#include +/* +* FIELDS +* +* ccti_limit +* Maximum valid CCTI for this table. +* +* entry_list +* List of up to 64 CongestionControlTableEntries. +* +* SEE ALSO +* ib_cc_mad_t +*********/ + +/****s* IBA Base: Types/ib_time_stamp_t +* NAME +* ib_time_stamp_t +* +* DESCRIPTION +* IBA defined TimeStamp attribute (A10.4.3.10) +* +* SOURCE +*/ +#include +typedef struct _ib_time_stamp { + ib_net32_t value; +} PACK_SUFFIX ib_time_stamp_t; +#include +/* +* FIELDS +* +* value +* Free running clock that provides relative time info +* for a device. Time is kept in 1.024 usec units. +* +* SEE ALSO +* ib_cc_mad_t +*********/ + +#define IB_REQ_CM_RDMA_SID_PREFIX 0x0000000001000000 +#define IB_REQ_CM_RDMA_PDATA_SIZE 56 +#define IB_REQ_CM_RDMA_MAJOR_VERSION 0 +#define IB_REQ_CM_RDMA_MINOR_VERSION 0 + + +/****s* Access Layer/ib_cm_rep_t +* NAME +* ib_cm_rdma_req_t +* +* DESCRIPTION +* Connection reply information used when establishing a connection. +* +* SYNOPSIS +*/ +typedef struct _ib_cm_rdma_req +{ + uint8_t maj_min_ver; /* min_ver: bits 0-3, maj_ver: bits 4-7 */ + uint8_t ipv; /* resides in bits 4-7 */ + net16_t src_port; + net32_t src_ip_addr[4]; + net32_t dst_ip_addr[4]; + uint8_t pdata[IB_REQ_CM_RDMA_PDATA_SIZE]; + +} PACK_SUFFIX ib_cm_rdma_req_t; +/* +* FIELDS +* maj_min_ver +* Defines the major and minor versions of RDMA IP CM Service protocol, supported +* +* ipv +* Defines IP protocol version (4 or 6). +* +* src_port +* Defines the local IP protocol port number of the client. +* +* src_ip_addr +* Contains the source IP address. +* +* dst_ip_addr +* Contains the destination IP address. +* +* pdata +* Contains Consumer Private Data. +* +*****/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + + +#endif /* __IB_TYPES_H__ */ + + + + + diff --git a/branches/WOF2-3/inc/kernel/complib/cl_atomic_osd.h b/branches/WOF2-3/inc/kernel/complib/cl_atomic_osd.h new file mode 100644 index 00000000..90289d59 --- /dev/null +++ b/branches/WOF2-3/inc/kernel/complib/cl_atomic_osd.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + + +#ifndef _CL_ATOMIC_OSD_H_ +#define _CL_ATOMIC_OSD_H_ + + +#include "complib/cl_types.h" + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +CL_INLINE int32_t +cl_atomic_inc( + IN atomic32_t* const p_value ) +{ + return( InterlockedIncrement( (LONG*)p_value ) ); +} + + +CL_INLINE int32_t +cl_atomic_dec( + IN atomic32_t* const p_value ) +{ + return( InterlockedDecrement( (LONG*)p_value ) ); +} + + +CL_INLINE int32_t +cl_atomic_add( + IN atomic32_t* const p_value, + IN const int32_t increment ) +{ + /* Return the incremented value. */ + return( InterlockedExchangeAdd( (long*)p_value, increment ) + increment ); +} + + +CL_INLINE int32_t +cl_atomic_sub( + IN atomic32_t* const p_value, + IN const int32_t decrement ) +{ + /* Return the decremented value. */ + return( InterlockedExchangeAdd( (long*)p_value, -decrement ) - decrement ); +} + + +CL_INLINE int32_t +cl_atomic_xchg( + IN atomic32_t* const p_value, + IN const int32_t new_value ) +{ + return( InterlockedExchange( (long*)p_value, new_value ) ); +} + + +CL_INLINE int32_t +cl_atomic_comp_xchg( + IN atomic32_t* const p_value, + IN const int32_t compare, + IN const int32_t new_value ) +{ + return( InterlockedCompareExchange( (long*)p_value, new_value, compare ) ); +} + + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _CL_ATOMIC_OSD_H_ diff --git a/branches/WOF2-3/inc/kernel/complib/cl_bus_ifc.h b/branches/WOF2-3/inc/kernel/complib/cl_bus_ifc.h new file mode 100644 index 00000000..9ec8e1b3 --- /dev/null +++ b/branches/WOF2-3/inc/kernel/complib/cl_bus_ifc.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + + +#ifndef _CL_BUS_IFC_H_ +#define _CL_BUS_IFC_H_ + + +#include + + +/****f* Component Library: Plug and Play/cl_fwd_query_ifc +* NAME +* cl_fwd_query_ifc +* +* DESCRIPTION +* Forwards a IRP_MN_QUERY_INTERFACE request to the device stack +* represented by the input device object. +* +* SYNOPSIS +*/ +CL_EXPORT NTSTATUS +cl_fwd_query_ifc( + IN DEVICE_OBJECT* const p_dev_obj, + IN IO_STACK_LOCATION* const p_io_stack ); +/* +* PARAMETERS +* p_dev_obj +* Pointer to the device object that is the IRP target. +* +* p_io_stack +* Pointer to the original IRP's I/O stack location, used to format +* the forwarded IRP. +* +* RETURN VALUES +* IRP status value. +* +* NOTES +* The IRP forwarded is synchronous, so this call must be invoked at PASSIVE. +* +* SEE ALSO +* Plug and Play +*********/ + +#endif /* _CL_BUS_IFC_H_ */ \ No newline at end of file diff --git a/branches/WOF2-3/inc/kernel/complib/cl_byteswap_osd.h b/branches/WOF2-3/inc/kernel/complib/cl_byteswap_osd.h new file mode 100644 index 00000000..dfa29043 --- /dev/null +++ b/branches/WOF2-3/inc/kernel/complib/cl_byteswap_osd.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + +#ifndef _CL_BYTESWAP_OSD_H_ +#define _CL_BYTESWAP_OSD_H_ + + +#include "complib/cl_types.h" + + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define CPU_LE 1 +#define CPU_BE 0 + +#define cl_ntoh16 _byteswap_ushort +#define cl_hton16 _byteswap_ushort + +#define cl_ntoh32 _byteswap_ulong +#define cl_hton32 _byteswap_ulong + +#define cl_ntoh64 _byteswap_uint64 +#define cl_hton64 _byteswap_uint64 + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _CL_BYTESWAP_OSD_H_ + + + + + diff --git a/branches/WOF2-3/inc/kernel/complib/cl_debug_osd.h b/branches/WOF2-3/inc/kernel/complib/cl_debug_osd.h new file mode 100644 index 00000000..f72585a1 --- /dev/null +++ b/branches/WOF2-3/inc/kernel/complib/cl_debug_osd.h @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + + +#ifndef _CL_DEBUG_OSD_H_ +#define _CL_DEBUG_OSD_H_ + + +#include "complib/cl_types.h" + + +#if !defined(__MODULE__) +#define __MODULE__ "" +#define __MOD_DELIMITER__ "" +#else /* !defined(__MODULE__) */ +#define __MOD_DELIMITER__ ":" +#endif /* !defined(__MODULE__) */ + + +#if defined( _WIN64 ) +#define PRIdSIZE_T "I64d" +#else +#define PRIdSIZE_T "d" +#endif +#define PRId64 "I64d" +#define PRIx64 "I64x" +#define PRIo64 "I64o" +#define PRIu64 "I64u" + + +#if defined( _DEBUG_ ) + +#ifdef __cplusplus +extern "C" +{ +#endif + +VOID cl_dbg_out( IN const char * const Format, ...); +#ifdef __cplusplus +} +#endif + +#else +#define cl_dbg_out __noop +#endif /* defined( _DEBUG_ ) */ + +#define cl_msg_out DbgPrint + + +/* + * The following macros are used internally by the CL_ENTER, CL_TRACE, + * CL_TRACE_EXIT, and CL_EXIT macros. + */ +#if defined( _WDMDDK_ ) +/* wdm.h does not provide for a way to get the current processor number. */ +#define _CL_DBG_ENTER \ + ("%s%s%s() [\n", __MODULE__, __MOD_DELIMITER__, __FUNCTION__) + +#define _CL_DBG_EXIT \ + ("%s%s%s() ]\n", __MODULE__, __MOD_DELIMITER__, __FUNCTION__) + +#define _CL_DBG_INFO \ + ("%s%s%s(): ", __MODULE__, __MOD_DELIMITER__, __FUNCTION__) + +#define _CL_DBG_ERROR \ + ("%s%s%s() !ERROR!: ", __MODULE__, __MOD_DELIMITER__, __FUNCTION__) + +#else // !defined( _WDMDDK_ ) + +#define _CL_DBG_ENTER \ + ("~%d:(%x)%s%s%s() [\n", KeGetCurrentProcessorNumber(), PsGetCurrentThread(), __MODULE__, \ + __MOD_DELIMITER__, __FUNCTION__) + +#define _CL_DBG_EXIT \ + ("~%d:%s%s%s() ]\n", KeGetCurrentProcessorNumber(), __MODULE__, \ + __MOD_DELIMITER__, __FUNCTION__) + +#define _CL_DBG_INFO \ + ("~%d:%s%s%s(): ", KeGetCurrentProcessorNumber(), __MODULE__, \ + __MOD_DELIMITER__, __FUNCTION__) + +#define _CL_DBG_ERROR \ + ("~%d:%s%s%s() !ERROR!: ", KeGetCurrentProcessorNumber(), __MODULE__, \ + __MOD_DELIMITER__, __FUNCTION__) + +#endif // !defined( _WDMDDK_ ) + +#define CL_CHK_STK + + +#endif /* _CL_DEBUG_OSD_H_ */ + diff --git a/branches/WOF2-3/inc/kernel/complib/cl_event_osd.h b/branches/WOF2-3/inc/kernel/complib/cl_event_osd.h new file mode 100644 index 00000000..9e5ea3f9 --- /dev/null +++ b/branches/WOF2-3/inc/kernel/complib/cl_event_osd.h @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + + +#ifndef _CL_EVENT_OSD_H_ +#define _CL_EVENT_OSD_H_ + + +#include "complib/cl_types.h" +#include "complib/cl_memory.h" + + +/* Simple definition, eh? */ +typedef KEVENT cl_event_t; + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +CL_INLINE void +cl_event_construct( + IN cl_event_t* const p_event ) +{ + CL_ASSERT( p_event ); + + cl_memclr( p_event, sizeof(cl_event_t) ); +} + + +CL_INLINE 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 ); + + if( manual_reset ) + KeInitializeEvent( p_event, NotificationEvent, FALSE ); + else + KeInitializeEvent( p_event, SynchronizationEvent, FALSE ); + + return( CL_SUCCESS ); +} + + +CL_INLINE void +cl_event_destroy( + IN cl_event_t* const p_event ) +{ + UNUSED_PARAM( p_event ); +} + + +CL_INLINE cl_status_t +cl_event_signal( + IN cl_event_t* const p_event ) +{ + CL_ASSERT( p_event ); + CL_ASSERT( KeGetCurrentIrql() <= DISPATCH_LEVEL ); + + KeSetEvent( p_event, 0, FALSE ); + + return( CL_SUCCESS ); +} + + +CL_INLINE cl_status_t +cl_event_reset( + IN cl_event_t* const p_event ) +{ + CL_ASSERT( p_event ); + CL_ASSERT( KeGetCurrentIrql() <= DISPATCH_LEVEL ); + + KeClearEvent( p_event ); + + return( CL_SUCCESS ); +} + + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _CL_EVENT_OSD_H_ \ No newline at end of file diff --git a/branches/WOF2-3/inc/kernel/complib/cl_init.h b/branches/WOF2-3/inc/kernel/complib/cl_init.h new file mode 100644 index 00000000..206e6308 --- /dev/null +++ b/branches/WOF2-3/inc/kernel/complib/cl_init.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#ifndef _CL_INIT_H_ +#define _CL_INIT_H_ + + +#include +#include + + +#ifdef CL_TRACK_MEM +#ifdef NEED_CL_OBJ +#define CL_INIT (__cl_mem_track( TRUE ), cl_obj_mgr_create()) +#define CL_DEINIT (cl_obj_mgr_destroy(), __cl_mem_track( FALSE )) +#else /* NEED_CL_OBJ */ +#define CL_INIT (__cl_mem_track( TRUE ), STATUS_SUCCESS) +#define CL_DEINIT (__cl_mem_track( FALSE )) +#endif /* NEED_CL_OBJ */ +#else /* CL_TRACK_MEM */ +#ifdef NEED_CL_OBJ +#define CL_INIT cl_obj_mgr_create() +#define CL_DEINIT cl_obj_mgr_destroy() +#else /* NEED_CL_OBJ */ +#define CL_INIT STATUS_SUCCESS +#define CL_DEINIT +#endif /* NEED_CL_OBJ */ +#endif /* CL_TRACK_MEM */ + +#endif // _CL_INIT_H_ diff --git a/branches/WOF2-3/inc/kernel/complib/cl_ioctl_osd.h b/branches/WOF2-3/inc/kernel/complib/cl_ioctl_osd.h new file mode 100644 index 00000000..450f3ef9 --- /dev/null +++ b/branches/WOF2-3/inc/kernel/complib/cl_ioctl_osd.h @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * Abstract: + * Declaration of IOCTL object + * + * Environment: + * Windows Kernel Mode + */ + + +#ifndef _CL_IOCTL_OSD_H_ +#define _CL_IOCTL_OSD_H_ + + +#include + + +#define IOCTL_CODE( type, cmd ) \ + CTL_CODE( type, (cmd & 0x0FFF), METHOD_BUFFERED, FILE_ANY_ACCESS) + + +typedef PIRP cl_ioctl_handle_t; + + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + +CL_INLINE cl_status_t +cl_ioctl_process( + IN void *p_ioctl, + IN cl_status_t (pfn_ioctl_handler( cl_ioctl_handle_t, void*, void* ) ), + IN void *context_1, + IN void *context_2 ) +{ + return pfn_ioctl_handler( ((PIRP)p_ioctl), context_1, context_2 ); +} + + +CL_INLINE uint16_t +cl_ioctl_type( + IN cl_ioctl_handle_t h_ioctl ) +{ + IO_STACK_LOCATION *p_io_stack; + + p_io_stack = IoGetCurrentIrpStackLocation( h_ioctl ); + return (uint16_t)DEVICE_TYPE_FROM_CTL_CODE( + p_io_stack->Parameters.DeviceIoControl.IoControlCode ); +} + + +CL_INLINE uint16_t +cl_ioctl_cmd( + IN cl_ioctl_handle_t h_ioctl ) +{ + IO_STACK_LOCATION *p_io_stack; + + p_io_stack = IoGetCurrentIrpStackLocation( h_ioctl ); + return (uint16_t) + ((p_io_stack->Parameters.DeviceIoControl.IoControlCode >> 2) & 0x0FFF); +} + + +CL_INLINE uint32_t +cl_ioctl_ctl_code( + IN cl_ioctl_handle_t h_ioctl ) +{ + IO_STACK_LOCATION *p_io_stack; + + p_io_stack = IoGetCurrentIrpStackLocation( h_ioctl ); + return p_io_stack->Parameters.DeviceIoControl.IoControlCode; +} + + +CL_INLINE void* +cl_ioctl_in_buf( + IN cl_ioctl_handle_t h_ioctl ) +{ + IO_STACK_LOCATION *p_io_stack; + + p_io_stack = IoGetCurrentIrpStackLocation( h_ioctl ); + switch( p_io_stack->Parameters.DeviceIoControl.IoControlCode & 0x03 ) + { + case METHOD_BUFFERED: + case METHOD_OUT_DIRECT: + return (h_ioctl)->AssociatedIrp.SystemBuffer; + + case METHOD_IN_DIRECT: + return (h_ioctl)->MdlAddress; + + case METHOD_NEITHER: + return p_io_stack->Parameters.DeviceIoControl.Type3InputBuffer; + } + return NULL; +} + + +CL_INLINE ULONG +cl_ioctl_in_size( + IN cl_ioctl_handle_t h_ioctl ) +{ + IO_STACK_LOCATION *p_io_stack; + + p_io_stack = IoGetCurrentIrpStackLocation( h_ioctl ); + switch( p_io_stack->Parameters.DeviceIoControl.IoControlCode & 0x03 ) + { + case METHOD_BUFFERED: + case METHOD_OUT_DIRECT: + case METHOD_NEITHER: + return p_io_stack->Parameters.DeviceIoControl.InputBufferLength; + + case METHOD_IN_DIRECT: + return p_io_stack->Parameters.DeviceIoControl.OutputBufferLength; + } + return 0; +} + + +CL_INLINE void* +cl_ioctl_out_buf( + IN cl_ioctl_handle_t h_ioctl ) +{ + IO_STACK_LOCATION *p_io_stack; + + p_io_stack = IoGetCurrentIrpStackLocation( h_ioctl ); + switch( p_io_stack->Parameters.DeviceIoControl.IoControlCode & 0x03 ) + { + case METHOD_BUFFERED: + return (h_ioctl)->AssociatedIrp.SystemBuffer; + + case METHOD_IN_DIRECT: + case METHOD_OUT_DIRECT: + return (h_ioctl)->MdlAddress; + + case METHOD_NEITHER: + return (h_ioctl)->UserBuffer; + } + return NULL; +} + + +CL_INLINE ULONG +cl_ioctl_out_size( + IN cl_ioctl_handle_t h_ioctl ) +{ + IO_STACK_LOCATION *p_io_stack; + + p_io_stack = IoGetCurrentIrpStackLocation( h_ioctl ); + return p_io_stack->Parameters.DeviceIoControl.OutputBufferLength; +} + + +CL_INLINE void +cl_ioctl_complete( + IN cl_ioctl_handle_t h_ioctl, + IN cl_status_t io_status, + IN size_t ret_bytes ) +{ + h_ioctl->IoStatus.Status = cl_to_ntstatus( io_status ); + h_ioctl->IoStatus.Information = ret_bytes; + IoCompleteRequest( h_ioctl, IO_NO_INCREMENT ); +} + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif // _CL_IOCTL_OSD_H_ diff --git a/branches/WOF2-3/inc/kernel/complib/cl_irqlock_osd.h b/branches/WOF2-3/inc/kernel/complib/cl_irqlock_osd.h new file mode 100644 index 00000000..4398b2c3 --- /dev/null +++ b/branches/WOF2-3/inc/kernel/complib/cl_irqlock_osd.h @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * Abstract: + * Implementation of IRQ lock object. + * + * Environment: + * Windows Kernel Mode + */ + + +#ifndef _CL_IRQLOCK_OSD_H_ +#define _CL_IRQLOCK_OSD_H_ + + +#include + + +typedef struct _cl_irqlock +{ + PKINTERRUPT p_interrupt; + KIRQL irql; + +} cl_irqlock_t; + + +typedef struct _KINTERRUPT cl_interrupt_t; + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +CL_INLINE void +cl_irqlock_construct( + IN cl_irqlock_t* const p_irqlock ) +{ + p_irqlock->p_interrupt = NULL; +} + + +CL_INLINE cl_status_t +cl_irqlock_init( + IN cl_irqlock_t* const p_irqlock, + IN cl_interrupt_t* const p_interrupt ) +{ + cl_irqlock_construct( p_irqlock ); + p_irqlock->p_interrupt = p_interrupt; + return CL_SUCCESS; +} + + +CL_INLINE void +cl_irqlock_destroy( + IN cl_irqlock_t* const p_irqlock ) +{ + p_irqlock->p_interrupt = NULL; +} + + +CL_INLINE void +cl_irqlock_acquire( + IN cl_irqlock_t* const p_irqlock ) +{ +#if WINVER > 0x500 + p_irqlock->irql = KeAcquireInterruptSpinLock( p_irqlock->p_interrupt ); +#else + UNUSED_PARAM( p_irqlock ); +#pragma warning( push, 3 ) + ASSERT( 0 ); +#pragma warning( pop ) +#endif +} + + +CL_INLINE void +cl_irqlock_release( + IN cl_irqlock_t* const p_irqlock ) +{ +#if WINVER > 0x500 + KeReleaseInterruptSpinLock( p_irqlock->p_interrupt, p_irqlock->irql ); +#else + UNUSED_PARAM( p_irqlock ); +#pragma warning( push, 3 ) + ASSERT( 0 ); +#pragma warning( pop ) +#endif +} + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* _CL_IRQLOCK_OSD_H_ */ diff --git a/branches/WOF2-3/inc/kernel/complib/cl_memory_osd.h b/branches/WOF2-3/inc/kernel/complib/cl_memory_osd.h new file mode 100644 index 00000000..20584619 --- /dev/null +++ b/branches/WOF2-3/inc/kernel/complib/cl_memory_osd.h @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * Abstract: + * Defines kernel-only memory related functions. + * + * Environment: + * Windows Kernel Mode + */ + + +#ifndef _CL_MEMORY_OSD_H_ +#define _CL_MEMORY_OSD_H_ + + +#include + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +CL_INLINE void +cl_memset( + IN void* const p_memory, + IN const uint8_t fill, + IN const size_t count ) +{ + RtlFillMemory( p_memory, count, fill ); +} + + +CL_INLINE void* +cl_memcpy( + IN void* const p_dest, + IN const void* const p_src, + IN const size_t count ) +{ + RtlCopyMemory( p_dest, p_src, count ); + return p_dest; +} + + +CL_INLINE int32_t +cl_memcmp( + IN const void* const p_memory1, + IN const void* const p_memory2, + IN const size_t count ) +{ + return( memcmp( p_memory1, p_memory2, count ) ); +} + + +CL_INLINE uint32_t +cl_get_pagesize( void ) +{ + return (PAGE_SIZE); +} + + +#ifdef CL_NTDDK +CL_INLINE uint64_t +cl_get_physaddr( + IN void *vaddr ) +{ + return MmGetPhysicalAddress( vaddr ).QuadPart; +} +#endif + + +CL_INLINE cl_status_t +cl_check_for_read( + IN const void* const vaddr, + IN const size_t count ) +{ + __try + { + ProbeForRead( ( void *)vaddr, count, sizeof(void*) ); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + return CL_INVALID_PERMISSION; + } + return CL_SUCCESS; +} + + +CL_INLINE cl_status_t +cl_check_for_write( + IN void* const vaddr, + IN const size_t count ) +{ + __try + { + /* + * We use ProbeForRead instead of ProbeForWrite because + * the additional checks to make sure the pages can be written + * are not guaranteed to still hold by the time we copy into + * the buffer. + * + * Furthermore, even if the pages don't change, ProbeForWrite will + * cause all pages to be paged in, and these pages could be paged out + * before the copy, requiring the copy to page them in once again. + * + * Micky Snir (mailto:mickys@microsoft.com) recommended *not* using + * ProbeForWrite because the page validity/permissions can change after + * the call and the actual access. + */ + ProbeForRead( vaddr, count, sizeof(void*) ); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + return CL_INVALID_PERMISSION; + } + return CL_SUCCESS; +} + + +CL_INLINE cl_status_t +cl_copy_to_user( + IN void* const p_dest, + IN const void* const p_src, + IN const size_t count ) +{ + /* + * The memory copy must be done within a try/except block as the + * memory could be changing while the buffer is copied. + */ + __try + { + /* + * We use ProbeForRead instead of ProbeForWrite because + * the additional checks to make sure the pages can be written + * are not guaranteed to still hold by the time we copy into + * the buffer. + * + * Furthermore, even if the pages don't change, ProbeForWrite will + * cause all pages to be paged in, and these pages could be paged out + * before the copy, requiring the copy to page them in once again. + * + * Micky Snir (mailto:mickys@microsoft.com) recommended *not* using + * ProbeForWrite because the page validity/permissions can change after + * the call and the actual access. + */ + ProbeForRead( p_dest, count, 1 ); + cl_memcpy( p_dest, p_src, count ); + return CL_SUCCESS; + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + return CL_INVALID_PERMISSION; + } +} + + +CL_INLINE cl_status_t +cl_copy_from_user( + IN void* const p_dest, + IN const void* const p_src, + IN const size_t count ) +{ + /* + * The memory copy must be done within a try/except block as the + * memory could be changing while the buffer is copied. + */ + __try + { + ProbeForRead( (void*)p_src, count, 1 ); + cl_memcpy( p_dest, p_src, count ); + return CL_SUCCESS; + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + return CL_INVALID_PERMISSION; + } +} + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* _CL_MEMORY_OSD_H_ */ + diff --git a/branches/WOF2-3/inc/kernel/complib/cl_mutex_osd.h b/branches/WOF2-3/inc/kernel/complib/cl_mutex_osd.h new file mode 100644 index 00000000..5b607c1d --- /dev/null +++ b/branches/WOF2-3/inc/kernel/complib/cl_mutex_osd.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * Abstract: + * Declaration of mutex object. + * + * Environment: + * Windows Kernel Mode + */ + + +#ifndef _CL_MUTEX_OSD_H_ +#define _CL_MUTEX_OSD_H_ + + +#include + + +typedef FAST_MUTEX cl_mutex_t; + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +CL_INLINE void +cl_mutex_construct( + IN cl_mutex_t* const p_mutex ) +{ + UNUSED_PARAM( p_mutex ); +} + + +CL_INLINE cl_status_t +cl_mutex_init( + IN cl_mutex_t* const p_mutex ) +{ + CL_ASSERT( KeGetCurrentIrql() <= DISPATCH_LEVEL ); + ExInitializeFastMutex( p_mutex ); + return CL_SUCCESS; +} + + +CL_INLINE void +cl_mutex_destroy( + IN cl_mutex_t* const p_mutex ) +{ + UNUSED_PARAM( p_mutex ); +} + + +CL_INLINE void +cl_mutex_acquire( + IN cl_mutex_t* const p_mutex ) +{ + CL_ASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL ); + ExAcquireFastMutex( p_mutex ); +} + + +CL_INLINE void +cl_mutex_release( + IN cl_mutex_t* const p_mutex ) +{ + CL_ASSERT( KeGetCurrentIrql() == APC_LEVEL ); + ExReleaseFastMutex( p_mutex ); +} + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* _CL_MUTEX_OSD_H_ */ diff --git a/branches/WOF2-3/inc/kernel/complib/cl_packoff.h b/branches/WOF2-3/inc/kernel/complib/cl_packoff.h new file mode 100644 index 00000000..2117feb7 --- /dev/null +++ b/branches/WOF2-3/inc/kernel/complib/cl_packoff.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + + +/* Note: The lack of conditional inclusion is intentional. */ +#include diff --git a/branches/WOF2-3/inc/kernel/complib/cl_packon.h b/branches/WOF2-3/inc/kernel/complib/cl_packon.h new file mode 100644 index 00000000..648b239e --- /dev/null +++ b/branches/WOF2-3/inc/kernel/complib/cl_packon.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + + +/* Note: The lack of conditional inclusion is intentional. */ +#include + + +/* + * 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. + * + * Note: + * No Robodoc documentation as with other headers. + */ + +#ifndef PACK_SUFFIX +#define PACK_SUFFIX +#endif diff --git a/branches/WOF2-3/inc/kernel/complib/cl_pnp_po.h b/branches/WOF2-3/inc/kernel/complib/cl_pnp_po.h new file mode 100644 index 00000000..073b57b1 --- /dev/null +++ b/branches/WOF2-3/inc/kernel/complib/cl_pnp_po.h @@ -0,0 +1,994 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + + +#ifndef _CL_PNP_PO_H_ +#define _CL_PNP_PO_H_ + + +#include "complib/cl_types.h" + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/****h* Component Library/Plug and Play +* NAME +* Plug and Play +* +* DESCRIPTION +* Provides plug and play support for kernel drivers. +* +* SEE ALSO +* Callback Types: +* cl_pfn_pnp_po_t +* +* Structures: +* cl_vfptr_pnp_t +*********/ + + +#define CL_DBG_PNP (1 << 1) + + +/****d* Component Library: Plug and Play/cl_irp_action_t +* NAME +* cl_irp_action_t +* +* DESCRIPTION +* Indicates what kind of action to take in response to an IRP. Used +* when processing PnP IRPs. +* +* SYNOPSIS: +*/ +typedef enum _cl_irp_action +{ + IrpPassDown, + IrpSkip, + IrpIgnore, + IrpComplete, + IrpDoNothing + +} cl_irp_action_t; +/* +* VALUES: +* IrpPassDown +* Pass the IRP down to the next driver. The IRP's current stack location +* has been setup properly. +* +* IrpSkip +* Skip the current IRP stack location but sets the IRP's status. +* +* IrpIgnore +* Skip the current IRP without setting its status value since the IRP +* is not interesting. +* +* IrpComplete +* Complete the IRP. Sets the status in the IoStatus block, completes the +* IRP, and returns the status. +* +* IrpDoNothing +* The routine assumed control of the IRP completion. No further +* processing is required in the dispatch routine. The remove lock should +* not be released. +*********/ + + +/****d* Component Library: Plug and Play/cl_pfn_pnp_po_t +* NAME +* cl_pfn_pnp_po_t +* +* DESCRIPTION +* Function prototype for PnP and Power Management IRPs handlers. +* +* SYNOPSIS +*/ +typedef NTSTATUS +(*cl_pfn_pnp_po_t)( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); +/* +* PARAMETERS +* p_dev_obj +* Pointer to the device object that is the IRP target. +* +* p_irp +* Pointer to the request IRP. +* +* p_action +* Action to take for propagating the IRP. +* +* RETURN VALUES +* IRP status value. +* +* SEE ALSO +* Plug and Play, cl_irp_action_t, cl_vfptr_pnp_po_t +*********/ + + +/****d* Component Library: Plug and Play/cl_pfn_release_resources_t +* NAME +* cl_pfn_release_resources_t +* +* DESCRIPTION +* Function prototype for releasing resources associated with a device. +* Called from either the remove handler or the surprise remove handler. +* +* SYNOPSIS +*/ +typedef void +(*cl_pfn_release_resources_t)( + IN DEVICE_OBJECT* const p_dev_obj ); +/* +* PARAMETERS +* p_dev_obj +* Pointer to the device object whose resources to release. +* +* RETURN VALUES +* This function does not return a value. +* +* SEE ALSO +* Plug and Play, cl_vfptr_pnp_po_t +*********/ + + +/****d* Component Library: Plug and Play/cl_vfptr_pnp_po_t +* NAME +* cl_vfptr_pnp_po_t +* +* DESCRIPTION +* Virtual function pointer table for PnP and Power Management IRPs. +* +* SYNOPSIS +*/ +typedef struct _cl_vfptr_pnp_po +{ + const char* identity; + cl_pfn_pnp_po_t pfn_start; + cl_pfn_pnp_po_t pfn_query_stop; + cl_pfn_pnp_po_t pfn_stop; + cl_pfn_pnp_po_t pfn_cancel_stop; + cl_pfn_pnp_po_t pfn_query_remove; + cl_pfn_release_resources_t pfn_release_resources; + cl_pfn_pnp_po_t pfn_remove; + cl_pfn_pnp_po_t pfn_cancel_remove; + cl_pfn_pnp_po_t pfn_surprise_remove; + cl_pfn_pnp_po_t pfn_query_capabilities; + cl_pfn_pnp_po_t pfn_query_pnp_state; + cl_pfn_pnp_po_t pfn_filter_res_req; + cl_pfn_pnp_po_t pfn_dev_usage_notification; + cl_pfn_pnp_po_t pfn_query_bus_relations; + cl_pfn_pnp_po_t pfn_query_ejection_relations; + cl_pfn_pnp_po_t pfn_query_removal_relations; + cl_pfn_pnp_po_t pfn_query_target_relations; + cl_pfn_pnp_po_t pfn_unknown; + cl_pfn_pnp_po_t pfn_query_resources; + cl_pfn_pnp_po_t pfn_query_res_req; + cl_pfn_pnp_po_t pfn_query_bus_info; + cl_pfn_pnp_po_t pfn_query_interface; + cl_pfn_pnp_po_t pfn_read_config; + cl_pfn_pnp_po_t pfn_write_config; + cl_pfn_pnp_po_t pfn_eject; + cl_pfn_pnp_po_t pfn_set_lock; + cl_pfn_pnp_po_t pfn_query_power; + cl_pfn_pnp_po_t pfn_set_power; + cl_pfn_pnp_po_t pfn_power_sequence; + cl_pfn_pnp_po_t pfn_wait_wake; + +} cl_vfptr_pnp_po_t; +/* +* FIELDS +* identity +* string identifying the target, used in generating debug output. +* +* pfn_start +* IRP_MN_START_DEVICE handler. Users must send forward the IRP to lower +* devices as required for their driver type. +* +* pfn_query_stop +* IRP_MN_QUERY_STOP_DEVICE handler. +* +* pfn_stop +* IRP_MN_STOP_DEVICE handler. +* +* pfn_cancel_stop +* IRP_MN_CANCEL_STOP_DEVICE handler. Users must send forward the IRP to +* lower devices as required for their driver type. +* +* pfn_query_remove +* IRP_MN_QUERY_REMOVE_DEVICE handler. +* +* pfn_release_resources +* Called to release resources allocated for the device. +* +* pfn_remove +* IRP_MN_REMOVE_DEVICE handler. +* +* pfn_cancel_remove +* IRP_MN_CANCEL_REMOVE_DEVICE handler. Users must send forward the IRP +* to lower devices as required for their driver type. +* +* pfn_surprise_remove +* IRP_MN_SURPRISE_REMOVE_DEVICE handler. +* +* pfn_query_capabilities +* IRP_MN_QUERY_DEVICE_CAPABILITIES handler. +* +* pfn_query_pnp_state +* IRP_MN_QUERY_PNP_STATE handler. +* +* pfn_filter_res_req +* IRP_MN_FILTER_RESOURCE_REQUIREMENTS handler. +* +* pfn_dev_usage_notification +* IRP_MN_QUERY_DEVICE_USAGE_NOTIFICATION handler. +* +* pfn_query_bus_relations +* IRP_MN_QUERY_BUS_RELATIONS handler. +* +* pfn_query_ejection_relations +* IRP_MN_QUERY_EJECTION_RELATIONS handler. +* +* pfn_query_removal_relations +* IRP_MN_QUERY_REMOVAL_RELATIONS handler. +* +* pfn_query_target_relations +* IRP_MN_QUERY_TARGET_RELATIONS handler. +* +* pfn_unknown +* FDO and Filter drivers should pass this IRP down. Bus drivers should +* complete the request for their PDOs without modifying the status. +* The component library provides the cl_irp_skip and cl_irp_complete +* functions to skip and complete and IRP, respectively. These functions +* can be used to perform the required action. This handler is invoked +* when an undocumented PNP irp is received. +* +* pfn_query_resources +* IRP_MN_QUERY_RESOURCES handler. +* +* pfn_query_res_req +* IRP_MN_QUERY_RESOURCE_REQUIREMENTS handler. +* +* pfn_query_bus_info +* IRP_MN_QUERY_BUS_INFORMATION handler. +* +* pfn_query_interface +* IRP_MN_QUERY_INTERFACE handler. +* +* pfn_read_config +* IRP_MN_READ_CONFIG handler. +* +* pfn_write_config +* IRP_MN_WRITE_CONFIG handler. +* +* pfn_eject +* IRP_MN_EJECT handler. +* +* pfn_set_lock +* IRP_MN_SET_LOCK handler. +* +* pfn_query_power +* IRP_MN_QUERY_POWER handler. +* +* pfn_set_power +* IRP_MN_SET_POWER handler. +* +* pfn_power_sequence +* IRP_MN_POWER_SEQUENCE handler. +* +* pfn_wait_wake +* IRP_MN_WAIT_WAKE handler. +* +* NOTES +* The component library provides default handlers for skiping the IRP, +* completing the IRP without changing the status, and processing the IRP +* on the way up the device stack. Users can set the handler to +* cl_irp_skip, cl_irp_complete, cl_do_sync_pnp. +* +* The handlers specified in pfn_query_power, pfn_set_power, +* pfn_power_sequence, and pfn_wait_wake, if implemented as pageable code, +* should be marked in a single pageable code section. The component library +* will use the first function that is not a component library handler to +* lock down the user's power management code. +* +* SEE ALSO +* Plug and Play, cl_pfn_pnp_po_t, cl_pfn_release_resources_t, cl_do_sync_pnp, +* cl_irp_skip, cl_irp_complete, cl_irp_unsupported, cl_irp_fail +***********/ + + +/****d* Component Library: Plug and Play/cl_pfn_query_text_t +* NAME +* cl_pfn_query_text_t +* +* DESCRIPTION +* Function pointer type for handling IRP_MN_QUERY_DEVICE_TEXT IRPs. +* +* SYNOPSIS +*/ +typedef NTSTATUS +(*cl_pfn_query_text_t)( + IN DEVICE_OBJECT* const p_dev_obj, + OUT IRP* const p_irp ); +/* +* PARAMETERS +* pDevObj +* Pointer to the device object that is the IRP target. +* +* pIrp +* [out] Pointer to the request IRP. Sets the requested device text in +* pIrp->IoStatus.Information. +* +* RETURN VALUES +* NTSTATUS value indicating the result of the query. +* +* NOTES +* Only bus drivers handle the IRP_MN_QUERY_DEVICE_TEXT IRP for their PDOs. +* +* SEE ALSO +* Plug and Play +*********/ + + +/****d* Component Library: Plug and Play/cl_vfptr_query_txt +* NAME +* cl_vfptr_query_txt +* +* DESCRIPTION +* Function pointer table for the various type of text requested by +* IRP_MN_QUERY_DEVICE_TEXT IRPs. +* +* SYNOPSIS +*/ +typedef struct _cl_vfptr_query_txt +{ + cl_pfn_query_text_t pfn_query_device_id; + cl_pfn_query_text_t pfn_query_hardware_id; + cl_pfn_query_text_t pfn_query_compatible_id; + cl_pfn_query_text_t pfn_query_unique_id; + cl_pfn_query_text_t pfn_query_description; + cl_pfn_query_text_t pfn_query_location; + +} cl_vfptr_query_txt_t; +/* +* FIELDS +* pfn_query_device_id +* The request is for the target device's device ID. +* +* pfn_query_hardware_id +* The request is for the target device's device IDs. +* +* pfn_query_compatible_id +* The request is for the target device's comptible IDs. +* +* pfn_query_unique_id +* The request is for the target device's unique ID. +* +* pfn_query_description +* The request is for the target device's description. +* +* pfn_query_location +* The request is for the target device's location text. +* +* NOTES +* Hardware and compatible IDs should be returned in the most specific to +* most general order. The IDs are used to match drivers to devices. +* +* The query text function pointer table is maintained separately from the +* PnP function pointer table to allow FDO and filter drivers to not define +* the table since they typically do not handle these requests. +* +* SEE ALSO +* Plug and Play, cl_pfn_query_text_t +*********/ + + +/****d* Component Library: Plug and Play/cl_pnp_state_t +* NAME +* cl_pnp_state_t +* +* DESCRIPTION +* PnP States for device objects managed by this driver. +* +* SYNOPSIS +*/ +typedef enum _cl_pnp_state +{ + NotStarted = 0, + Started, + StopPending, + Stopped, + RemovePending, + SurpriseRemoved, + Deleted, + UnKnown + +} cl_pnp_state_t; +/* +* VALUES +* NotStarted +* Not started yet. +* +* Started +* Device has received the IPR_MN_START_DEVICE IRP +* +* StopPending +* Device has received the IPR_MN_QUERY_STOP_DEVICE IRP +* +* Stopped +* Device has received the IPR_MN_STOP_DEVICE IRP +* +* RemovePending +* Device has received the IPR_MN_QUERY_REMOVE_DEVICE IRP +* +* SurpriseRemoved +* Device has received the IPR_MN_SURPRISE_REMOVE_DEVICE IRP +* +* Deleted +* Device has received the IPR_MN_REMOVE_DEVICE IRP +* +* UnKnown +* Unknown state +* +* SEE ALSO +* Plug and Play, cl_pnp_po_ext_t +*********/ + + +/****d* Component Library: Plug and Play/cl_pnp_po_ext_t +* NAME +* cl_pnp_po_ext_t +* +* DESCRIPTION +* Device extension structure required for using the component library +* plug and play helper routines. +* +* SYNOPSIS +*/ +typedef struct _cl_pnp_po_ext +{ + cl_pnp_state_t pnp_state; + cl_pnp_state_t last_pnp_state; + + DEVICE_OBJECT *p_self_do; + DEVICE_OBJECT *p_next_do; + DEVICE_OBJECT *p_pdo; + + IO_REMOVE_LOCK remove_lock; + IO_REMOVE_LOCK stop_lock; + + atomic32_t n_paging_files; + atomic32_t n_crash_files; + atomic32_t n_hibernate_files; + + const cl_vfptr_pnp_po_t *vfptr_pnp_po; + const cl_vfptr_query_txt_t *vfptr_query_txt; + + void *h_cl_locked_section; + void *h_user_locked_section; + + atomic32_t n_ifc_ref; + + uint32_t dbg_lvl; + +} cl_pnp_po_ext_t; +/* +* FIELDS +* pnp_state +* Current PnP device state. +* +* last_pnp_state +* Previous PnP device state, to restore in case a query is cancelled. +* +* p_self_do +* Pointer to the device's own device object. +* +* p_next_do +* Pointer to the next device object. Null if the device is a PDO. +* +* p_pdo +* The pointer to the PDO for the device node. +* +* remove_lock +* Remove lock used to synchronize access to the device when handling +* PnP IRPs. +* +* stop_lock +* Lock used to track non-PnP and non-Power IO operations. +* +* n_paging_files +* Number of times the device is in a paging file path. +* +* n_crash_files +* Number of times the device is in a dump file path. +* +* n_hibernate_files +* Number of times the device is in a hibernation files path. +* +* vfptr_pnp +* Funtion pointer table for the PnP and Power Management handlers. +* +* vfptr_query_txt +* Function pointer table for IRP_MN_QUERY_DEVICE_TEXT handlers. +* +* NOTES +* This structure must be first in the device extension so that the device +* extension can successfully be cast to a cl_pnp_po_ext_t pointer by the +* IRP handler routines. +* +* When performing I/O operations, users should acquire the stop lock and +* check status before starting an I/O operation, and release the stop lock +* after completing an I/O operation using the cl_start_io and cl_end_io +* functions respectively. +* +* SEE ALSO +* Plug and Play, cl_vfptr_pnp_po_t, cl_pnp_state_t, cl_start_io, cl_end_io +*********/ + + +/****f* Component Library: Plug and Play/cl_init_pnp_po_ext +* NAME +* cl_init_pnp_po_ext +* +* DESCRIPTION +* Initializes the component library device extension for use. +* +* SYNOPSIS +*/ +CL_EXPORT void +cl_init_pnp_po_ext( + IN OUT DEVICE_OBJECT* const p_dev_obj, + IN DEVICE_OBJECT* const p_next_do, + IN DEVICE_OBJECT* const p_pdo, + IN const uint32_t pnp_po_dbg_lvl, + IN const cl_vfptr_pnp_po_t* const vfptr_pnp, + IN const cl_vfptr_query_txt_t* const vfptr_query_txt OPTIONAL ); +/* +* PARAMETERS +* p_dev_obj +* Pointer to the device object for the device. +* +* p_next_do +* Pointer to the next device object in the device stack. Must be NULL +* for PDO objects. +* +* p_pdo +* Pointer to the PDO for the device node. +* +* pnp_po_dbg_lvl +* Debug level to control flow of debug messages. If the bit for +* CL_DBG_PNP is set, verbose debug messages are generated. +* +* vfptr_pnp_po +* Pointer to the function table of PnP and Power Management handlers. +* +* vfptr_query_txt +* Pointer to the function table for IRP_MN_QUERY_DEVICE_TEXT handlers. +* +* SEE ALSO +* Plug and Play, cl_pnp_po_ext_t, cl_vfptr_pnp_po_t, cl_vfptr_query_txt_t +*********/ + + +/****f* Component Library: Plug and Play/cl_set_pnp_state +* NAME +* cl_set_pnp_state +* +* DESCRIPTION +* Sets the PnP state stored in the common device extension to the desired +* state. Stores the previous state for rollback purposes. +* +* SYNOPSIS +*/ +CL_INLINE void +cl_set_pnp_state( + OUT cl_pnp_po_ext_t* const p_ext, + IN const cl_pnp_state_t new_state ) +{ + p_ext->last_pnp_state = p_ext->pnp_state; + p_ext->pnp_state = new_state; +} +/* +* PARAMTETERS +* p_ext +* Pointer to the device extension whose PnP state to set. +* +* new_state +* New PnP state to store in the device extension. +* +* RETURN VALUES +* This function does not return a value. +* +* SEE ALSO +* Plug and Play, cl_pnp_po_ext_t, cl_pnp_state_t +*********/ + + +/****f* Component Library: Plug and Play/cl_rollback_pnp_state +* NAME +* cl_rollback_pnp_state +* +* DESCRIPTION +* Rolls back a PnP state change. +* +* SYNOPSIS +*/ +CL_INLINE void +cl_rollback_pnp_state( + OUT cl_pnp_po_ext_t* const p_ext ) +{ + p_ext->pnp_state = p_ext->last_pnp_state; +} +/* +* PARAMTETERS +* p_ext +* Pointer to the device extension whose PnP state to set. +* +* RETURN VALUES +* This function does not return a value. +* +* SEE ALSO +* Plug and Play, cl_pnp_po_ext_t +*********/ + + +/****f* Component Library: Plug and Play:/cl_pnp +* NAME +* cl_pnp +* +* DESCRIPTION +* Main PnP entry point for the driver. +* +* SYNOPSIS +*/ +CL_EXPORT NTSTATUS +cl_pnp( + IN PDEVICE_OBJECT p_dev_obj, + IN PIRP p_irp ); +/* +* PARAMTETERS +* p_dev_obj +* Pointer to the device object that is the target of the PnP IRP. +* +* p_irp +* Pointer to the PnP IRP to perform on the specified device. +* +* RETURN VALUES +* STATUS_SUCCESS if the operation is successful +* +* Other NTSTATUS values in case of error. +* +* SEE ALSO +* Plug and Play +**********/ + + +/****f* Component Library: Plug and Play:/cl_power +* NAME +* cl_power +* +* DESCRIPTION +* Main Power Management entry point for the driver. +* +* SYNOPSIS +*/ +CL_EXPORT NTSTATUS +cl_power( + IN PDEVICE_OBJECT p_dev_obj, + IN PIRP p_irp ); +/* +* PARAMTETERS +* p_dev_obj +* Pointer to the device object that is the target of the PnP IRP. +* +* p_irp +* Pointer to the PnP IRP to perform on the specified device. +* +* RETURN VALUES +* STATUS_SUCCESS if the operation is successful +* +* Other NTSTATUS values in case of error. +* +* SEE ALSO +* Plug and Play +**********/ + + +/****f* Component Library: Plug and Play/cl_do_sync_pnp +* NAME +* cl_do_sync_pnp +* +* DESCRIPTION +* Sends an IRP to the next driver synchronously. Returns when the lower +* drivers have completed the IRP. Used to process IRPs on the way up the +* device node. +* +* SYNOPSIS +*/ +CL_EXPORT NTSTATUS +cl_do_sync_pnp( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); +/* +* PARAMETER +* p_dev_obj +* Pointer to the device object that is the IRP target. +* +* p_irp +* Pointer to the request IRP. +* +* p_action +* Action to take for propagating the IRP. +* +* RETURN VALUES +* IRP status value returned by lower driver. +*********/ + + +/****f* Component Library: Plug and Play/cl_alloc_relations +* NAME +* cl_alloc_relations +* +* DESCRIPTION +* Allocates device relations and copies existing device relations, if any. +* +* SYNOPSIS +*/ +CL_EXPORT NTSTATUS +cl_alloc_relations( + IN IRP* const p_irp, + IN const size_t n_devs ); +/* +* PARAMETERS +* p_irp +* Pointer to the IPR_MN_QUERY_DEVICE_RELATIONS IRP for which the +* relations are being allocated. +* +* n_devs +* Number of devices the caller will report in the DEVICE_RELATIONS +* structure stored at pIrp->IoStatus.Infomation upon success. +* +* RETURN VALUES +* STATUS_SUCCESS if the DEVICE_RELATIONS structure was allocated successfully. +* +* STATUS_INSUFFICIENT_RESOURCES if there was not enough memory to complete +* the operation. +* +* NOTES +* Upon failure, any original relations buffer is freed. Users should fail +* the IRP with the returned status value. +* +* SEE ALSO +* Plug and Play +**********/ + + +/****f* Component Library: Plug and Play/cl_do_remove +* NAME +* cl_do_remove +* +* DESCRIPTION +* Propagates an IRP_MN_REMOVE_DEVICE IRP, detaches, and deletes the +* device object. Useable by function and filter drivers only. +* +* SYNOPSIS +*/ +CL_EXPORT NTSTATUS +cl_do_remove( + IN DEVICE_OBJECT* const pDevObj, + IN IRP* const pIrp, + OUT cl_irp_action_t* const pAction ); +/**********/ + + +/****f* Component Library: Plug and Play:/cl_irp_skip +* NAME +* cl_irp_skip +* +* DESCRIPTION +* Default function for skipping a PnP IRP. Sets the IRP's status value. +* Useable only by function and filter drivers. Bus drivers should use +* cl_irp_complete for their PDOs to complete an IRP with no change in status. +* +* SYNOPSIS +*/ +CL_EXPORT NTSTATUS +cl_irp_skip( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); +/* +* PARAMETERS +* p_dev_obj +* Pointer to the device object that is the IRP target. +* +* p_irp +* Pointer to the request IRP. +* +* p_action +* Action to take for propagating the IRP. +* +* RETURN VALUES +* IRP status value. +* +* SEE ALSO +* Plug and Play, cl_irp_action_t +*********/ + + +/****f* Component Library: Plug and Play:/cl_irp_ignore +* NAME +* cl_irp_ignore +* +* DESCRIPTION +* Default function for skipping a PnP IRP without setting the IRP's status. +* Useable only by function and filter drivers. Bus drivers should use +* cl_irp_complete for their PDOs to complete an IRP with no change in status. +* +* SYNOPSIS +*/ +CL_EXPORT NTSTATUS +cl_irp_ignore( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); +/* +* PARAMETERS +* p_dev_obj +* Pointer to the device object that is the IRP target. +* +* p_irp +* Pointer to the request IRP. +* +* p_action +* Action to take for propagating the IRP. +* +* RETURN VALUES +* IRP status value. +* +* SEE ALSO +* Plug and Play, cl_irp_action_t +*********/ + + +/****f* Component Library: Plug and Play:/cl_irp_complete +* NAME +* cl_irp_complete +* +* DESCRIPTION +* Default handler for completeing a PnP or Power Management IRP with no +* action. Should only be used by bus drivers for their PDOs to complete +* an IRP with no change in status. +* +* SYNOPSIS +*/ +CL_EXPORT NTSTATUS +cl_irp_complete( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); +/* +* PARAMETERS +* p_dev_obj +* Pointer to the device object that is the IRP target. +* +* p_irp +* Pointer to the request IRP. +* +* p_action +* Action to take for propagating the IRP. +* +* RETURN VALUES +* IRP status value. +* +* SEE ALSO +* Plug and Play, cl_irp_action_t, cl_vfptr_pnp_po_t +*********/ + + +/****f* Component Library: Plug and Play:/cl_irp_succeed +* NAME +* cl_irp_succeed +* +* DESCRIPTION +* Default handler for succeeding an IRP with STATUS_SUCCESS. +* +* SYNOPSIS +*/ +CL_EXPORT NTSTATUS +cl_irp_succeed( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); +/* +* PARAMETERS +* p_dev_obj +* Pointer to the device object that is the IRP target. +* +* p_irp +* Pointer to the request IRP. +* +* p_action +* Action to take for propagating the IRP. +* +* RETURN VALUES +* IRP status value. +* +* SEE ALSO +* Plug and Play, cl_irp_action_t +*********/ + + +/****f* Component Library: Plug and Play:/cl_irp_unsupported +* NAME +* cl_irp_unsupported +* +* DESCRIPTION +* Default handler for failing an IRP with STATUS_UNSUPPORTED. +* +* SYNOPSIS +*/ +CL_EXPORT NTSTATUS +cl_irp_unsupported( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); +/* +* PARAMETERS +* p_dev_obj +* Pointer to the device object that is the IRP target. +* +* p_irp +* Pointer to the request IRP. +* +* p_action +* Action to take for propagating the IRP. +* +* RETURN VALUES +* IRP status value. +* +* SEE ALSO +* Plug and Play, cl_irp_action_t +*********/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* _CL_PNP_PO_H_ */ diff --git a/branches/WOF2-3/inc/kernel/complib/cl_spinlock_osd.h b/branches/WOF2-3/inc/kernel/complib/cl_spinlock_osd.h new file mode 100644 index 00000000..bf6a4196 --- /dev/null +++ b/branches/WOF2-3/inc/kernel/complib/cl_spinlock_osd.h @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + + +#ifndef _CL_SPINLOCK_OSD_H_ +#define _CL_SPINLOCK_OSD_H_ + + +#include "complib/cl_types.h" +#include "complib/cl_memory.h" + + +/* Spinlock object definition. */ +typedef struct _cl_spinlock +{ + KSPIN_LOCK lock; + KIRQL irql; + +} cl_spinlock_t; + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +CL_INLINE void +cl_spinlock_construct( + IN cl_spinlock_t* const p_spinlock ) +{ + cl_memclr( p_spinlock, sizeof(cl_spinlock_t*) ); +} + + +CL_INLINE cl_status_t +cl_spinlock_init( + IN cl_spinlock_t* const p_spinlock ) +{ + CL_ASSERT( p_spinlock ); + + cl_spinlock_construct( p_spinlock ); + + KeInitializeSpinLock( &p_spinlock->lock ); + return( CL_SUCCESS ); +} + + +CL_INLINE void +cl_spinlock_destroy( + IN cl_spinlock_t* const p_spinlock ) +{ + UNUSED_PARAM( p_spinlock ); +} + + +CL_INLINE void +cl_spinlock_acquire( + IN cl_spinlock_t* const p_spinlock ) +{ + KIRQL irql = KeGetCurrentIrql(); + CL_ASSERT( p_spinlock ); + + if (irql == DISPATCH_LEVEL) { + KeAcquireSpinLockAtDpcLevel( &p_spinlock->lock ); + p_spinlock->irql = irql; + } + else + KeAcquireSpinLock( &p_spinlock->lock, &p_spinlock->irql ); +} + + +CL_INLINE void +cl_spinlock_release( + IN cl_spinlock_t* const p_spinlock ) +{ + CL_ASSERT( p_spinlock ); + + if (p_spinlock->irql == DISPATCH_LEVEL) + KeReleaseSpinLockFromDpcLevel( &p_spinlock->lock ); + else + KeReleaseSpinLock( &p_spinlock->lock, p_spinlock->irql ); +} + + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _CL_SPINLOCK_OSD_H_ diff --git a/branches/WOF2-3/inc/kernel/complib/cl_syscallback_osd.h b/branches/WOF2-3/inc/kernel/complib/cl_syscallback_osd.h new file mode 100644 index 00000000..280835c8 --- /dev/null +++ b/branches/WOF2-3/inc/kernel/complib/cl_syscallback_osd.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + + +#ifndef _CL_SYS_CALLBACK_OSD_H_ +#define _CL_SYS_CALLBACK_OSD_H_ + + +#include "complib/cl_types.h" + + +typedef struct _IO_WORKITEM cl_sys_callback_item_t; + + +#endif // _CL_SYS_CALLBACK_OSD_H_ \ No newline at end of file diff --git a/branches/WOF2-3/inc/kernel/complib/cl_thread_osd.h b/branches/WOF2-3/inc/kernel/complib/cl_thread_osd.h new file mode 100644 index 00000000..14b501ae --- /dev/null +++ b/branches/WOF2-3/inc/kernel/complib/cl_thread_osd.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + + +#ifndef _CL_THREAD_OSD_H_ +#define _CL_THREAD_OSD_H_ + + +#include "complib/cl_types.h" +#include "complib/cl_timer.h" + + +/* OS specific information about the thread. */ +typedef struct _cl_thread_osd +{ + HANDLE h_thread; + PKTHREAD p_thread; + +} cl_thread_osd_t; + + +#ifdef __cplusplus +extern "C" +{ +#endif + +CL_INLINE void +cl_thread_suspend( + IN const uint32_t pause_ms ) +{ + LARGE_INTEGER interval; + + // Convert the delay in milliseconds to 100 nanosecond intervals. + interval.QuadPart = -(int64_t)(((uint64_t)pause_ms * 10000)); + KeDelayExecutionThread( KernelMode, FALSE, &interval ); +} + + +CL_INLINE void +cl_thread_stall( + IN const uint32_t pause_us ) +{ + KeStallExecutionProcessor( pause_us ); +} + + +CL_INLINE boolean_t +cl_is_blockable( void ) +{ + return ( KeGetCurrentIrql() < DISPATCH_LEVEL ); +} + + +#ifdef __cplusplus +} // extern "C" +#endif + + +#endif // _CL_THREAD_OSD_H_ diff --git a/branches/WOF2-3/inc/kernel/complib/cl_timer_osd.h b/branches/WOF2-3/inc/kernel/complib/cl_timer_osd.h new file mode 100644 index 00000000..0935902c --- /dev/null +++ b/branches/WOF2-3/inc/kernel/complib/cl_timer_osd.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + + +#ifndef _CL_TIMER_OSD_H_ +#define _CL_TIMER_OSD_H_ + + +#include "complib/cl_types.h" + + +/* Timer object definition. */ +typedef struct _cl_timer +{ + KTIMER timer; + KDPC dpc; + cl_pfn_timer_callback_t pfn_callback; + const void *context; + uint64_t timeout_time; + KSPIN_LOCK spinlock; + KSPIN_LOCK cb_lock; + +} cl_timer_t; + + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* 100ns to s conversion */ +#define HUNDREDNS_TO_SEC CL_CONST64(10000000) +/* s to µs conversion */ +#define SEC_TO_MICRO CL_CONST64(1000000) + +CL_INLINE uint64_t CL_API +cl_get_time_stamp( void ) +{ + LARGE_INTEGER tick_count, frequency; + + tick_count = KeQueryPerformanceCounter( &frequency ); + return( SEC_TO_MICRO * tick_count.QuadPart / frequency.QuadPart ); +} + +CL_INLINE uint32_t CL_API +cl_get_time_stamp_sec( void ) +{ + return( (uint32_t)(KeQueryInterruptTime() / HUNDREDNS_TO_SEC) ); +} + +CL_INLINE uint64_t CL_API +cl_get_tick_count( void ) +{ + LARGE_INTEGER tick_count; + + tick_count = KeQueryPerformanceCounter( NULL ); + return tick_count.QuadPart; +} + +CL_INLINE uint64_t CL_API +cl_get_tick_freq( void ) +{ + LARGE_INTEGER frequency; + + KeQueryPerformanceCounter( &frequency ); + return frequency.QuadPart; +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // _CL_TIMER_OSD_H_ diff --git a/branches/WOF2-3/inc/kernel/complib/cl_types_osd.h b/branches/WOF2-3/inc/kernel/complib/cl_types_osd.h new file mode 100644 index 00000000..851d8ea6 --- /dev/null +++ b/branches/WOF2-3/inc/kernel/complib/cl_types_osd.h @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + + +#ifndef _CL_TYPES_OSD_H_ +#define _CL_TYPES_OSD_H_ + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +#pragma warning( push ) +#include +#if defined( NDIS_MINIPORT_DRIVER ) +#include +#if NDIS_WDM +#define CL_NTDDK +#endif /* NDIS_WDM */ +#elif !defined( _MINIPORT_ ) +#include +#define CL_NTDDK +#endif /* defined( NDIS_MINIPORT_DRIVER ) */ +#pragma warning( pop ) +/* + * Disable warnings related to taking the address of a dllimport function. + * This is needed to allow user of the PNP/PO abstraction to use the default + * handlers. + */ +#pragma warning( disable:4232 ) + +/* + * Enable warnings about pointer sign extension. + */ +#pragma warning( default:4826 ) + +/* For DECLSPEC_EXPORT and DECLSPEC_IMPORT */ +#include + +#define CL_KERNEL + +#if DBG + #define _DEBUG_ +#else + #undef _DEBUG_ +#endif + +typedef __int8 int8_t; +typedef unsigned __int8 uint8_t; +typedef __int16 int16_t; +typedef unsigned __int16 uint16_t; +typedef __int32 int32_t; +typedef unsigned __int32 uint32_t; +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +/* boolean_t must be intergral sized to avoid a bunch of warnings. */ +typedef int boolean_t; +typedef unsigned char uchar_t; +typedef _W64 __int3264 intn_t; +typedef _W64 unsigned __int3264 uintn_t; +typedef volatile __int32 atomic32_t; + +#ifdef _PREFAST_ +#define CONDITION_ASSUMED(X) __analysis_assume((X)) +#else +#define CONDITION_ASSUMED(X) +#endif // _PREFAST_ + + +#ifndef CL_ASSERT +#ifdef _DEBUG_ +#define CL_ASSERT(X) ASSERT(X);CONDITION_ASSUMED(X) +#else +#define CL_ASSERT ASSERT +#endif +#endif + + +#define UNUSED_PARAM UNREFERENCED_PARAMETER +#if defined(EVENT_TRACING) +#define UNUSED_PARAM_WOWPP(a) +#else +#define UNUSED_PARAM_WOWPP(a)UNREFERENCED_PARAMETER(a) +#endif + + +#define CL_EXPORT + +#if !defined( __cplusplus ) +#define inline __inline +#endif + +#define CL_INLINE CL_EXPORT inline + +#define CL_API + +#define cl_panic DbgBreakPoint + +#ifndef offsetof +#define offsetof FIELD_OFFSET +#endif + +#define PARENT_STRUCT( P, T, M ) CONTAINING_RECORD( (void*)P, T, M ) + +typedef enum _cl_status cl_status_t; + +#define CL_CONST64( x ) x##ui64 + +NTSTATUS +cl_to_ntstatus( + IN enum _cl_status status ); + +DECLSPEC_DEPRECATED enum _cl_status +cl_from_ntstatus( + IN NTSTATUS status ); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // _CL_TYPES_OSD_H_ diff --git a/branches/WOF2-3/inc/kernel/complib/cl_waitobj_osd.h b/branches/WOF2-3/inc/kernel/complib/cl_waitobj_osd.h new file mode 100644 index 00000000..9320cba9 --- /dev/null +++ b/branches/WOF2-3/inc/kernel/complib/cl_waitobj_osd.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + + +#ifndef _CL_WAITOBJ_OSD_H_ +#define _CL_WAITOBJ_OSD_H_ + + +#include +#include + + +typedef PKEVENT cl_waitobj_handle_t; + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + +CL_INLINE cl_waitobj_handle_t +cl_waitobj_ref( + IN void *h_user_wait_obj ) +{ + cl_waitobj_handle_t h_kevent = NULL; + + /* + * Assumption that if the call fails, the h_kevent parameter is unchanged, + * or set to NULL. + */ + ObReferenceObjectByHandle( h_user_wait_obj, STANDARD_RIGHTS_ALL, + *ExEventObjectType, UserMode, (PVOID*)&h_kevent, NULL ); + + return h_kevent; +} + + +CL_INLINE void +cl_waitobj_deref( + IN cl_waitobj_handle_t h_kernel_wait_obj ) +{ + ObDereferenceObject( h_kernel_wait_obj ); +} + + +CL_INLINE cl_status_t +cl_waitobj_signal( + IN cl_waitobj_handle_t h_wait_obj ) +{ + return cl_event_signal( (cl_event_t*)h_wait_obj ); +} + + +CL_INLINE cl_status_t +cl_waitobj_reset( + IN cl_waitobj_handle_t h_wait_obj ) +{ + return cl_event_reset( (cl_event_t*)h_wait_obj ); +} + + +CL_INLINE cl_status_t +cl_waitobj_wait_on( + IN cl_waitobj_handle_t h_wait_obj, + IN const uint32_t wait_us, + IN const boolean_t interruptible ) +{ + return cl_event_wait_on( (cl_event_t*)h_wait_obj, wait_us, interruptible ); +} + + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + + +#endif /* _CL_WAITOBJ_OSD_H_ */ diff --git a/branches/WOF2-3/inc/kernel/iba/ib_al_ifc.h b/branches/WOF2-3/inc/kernel/iba/ib_al_ifc.h new file mode 100644 index 00000000..dc988697 --- /dev/null +++ b/branches/WOF2-3/inc/kernel/iba/ib_al_ifc.h @@ -0,0 +1,775 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + +#if !defined _IB_AL_IFC_H_ +#define _IB_AL_IFC_H_ + + +#include + + +/****h* Access Layer/AL Interface +* NAME +* AL Interface +* +* DESCRIPTION +* Header file for the interface exported to ICT client drivers for access to +* IB resources provided by HCAs. +*********/ + +#define AL_INTERFACE_VERSION (12) + + + +/* Function prototypes. Match definitions in ib_al.h. */ +typedef void +(*ib_pfn_sync_destroy_t)( + IN void *context ); + +typedef ib_api_status_t +(*ib_pfn_open_ca_t)( + IN const ib_al_handle_t h_al, + IN const ib_net64_t ca_guid, + IN const ib_pfn_event_cb_t ca_event_cb OPTIONAL, + IN const void* const ca_context, + OUT ib_ca_handle_t* const ph_ca ); + +typedef ib_api_status_t +(*ib_pfn_query_ca_t)( + IN const ib_ca_handle_t h_ca, + OUT ib_ca_attr_t* const p_ca_attr OPTIONAL, + IN OUT uint32_t* const p_size ); + +typedef DEVICE_OBJECT* +(*ib_pfn_get_ca_dev_t)( + IN const ib_ca_handle_t h_ca ); + +typedef ib_api_status_t +(*ib_pfn_query_ca_by_guid_t)( + IN const ib_al_handle_t h_al, + IN const ib_net64_t ca_guid, + OUT ib_ca_attr_t* const p_ca_attr OPTIONAL, + IN OUT size_t* const p_size ); + +typedef ib_api_status_t +(*ib_pfn_modify_ca_t)( + IN const ib_ca_handle_t h_ca, + IN const uint8_t port_num, + IN const ib_ca_mod_t ca_mod, + IN const ib_port_attr_mod_t* const p_port_attr_mod ); + +typedef ib_api_status_t +(*ib_pfn_close_ca_t)( + IN const ib_ca_handle_t h_ca, + IN const ib_pfn_destroy_cb_t destroy_cb OPTIONAL ); + +typedef ib_api_status_t +(*ib_pfn_alloc_pd_t)( + IN const ib_ca_handle_t h_ca, + IN const ib_pd_type_t pd_type, + IN const void* const pd_context, + OUT ib_pd_handle_t* const ph_pd ); + +typedef ib_api_status_t +(*ib_pfn_dealloc_pd_t)( + IN const ib_pd_handle_t h_pd, + IN const ib_pfn_destroy_cb_t destroy_cb OPTIONAL ); + +typedef ib_api_status_t +(*ib_pfn_create_av_t)( + IN const ib_pd_handle_t h_pd, + IN const ib_av_attr_t* const p_av_attr, + OUT ib_av_handle_t* const ph_av ); + +typedef ib_api_status_t +(*ib_pfn_query_av_t)( + IN const ib_av_handle_t h_av, + OUT ib_av_attr_t* const p_av_attr, + OUT ib_pd_handle_t* const ph_pd ); + +typedef ib_api_status_t +(*ib_pfn_modify_av_t)( + IN const ib_av_handle_t h_av, + IN const ib_av_attr_t* const p_av_attr ); + +typedef ib_api_status_t +(*ib_pfn_destroy_av_t)( + IN const ib_av_handle_t h_av ); + +typedef ib_api_status_t +(*ib_pfn_create_srq_t)( + IN const ib_pd_handle_t h_pd, + IN const ib_srq_attr_t* const p_srq_attr, + IN const void* const srq_context, + IN const ib_pfn_event_cb_t srq_event_cb OPTIONAL, + OUT ib_srq_handle_t* const ph_srq ); + +typedef ib_api_status_t +(*ib_pfn_query_srq_t)( + IN const ib_srq_handle_t h_srq, + OUT ib_srq_attr_t* const p_srq_attr ); + +typedef ib_api_status_t +(*ib_pfn_modify_srq_t)( + IN const ib_srq_handle_t h_srq, + IN const ib_srq_attr_t* const p_srq_attr, + IN const ib_srq_attr_mask_t srq_attr_mask ); + +typedef ib_api_status_t +(*ib_pfn_destroy_srq_t)( + IN const ib_srq_handle_t h_srq, + IN const ib_pfn_destroy_cb_t destroy_cb OPTIONAL ); + +typedef ib_api_status_t +(*ib_pfn_post_srq_recv_t)( + IN const ib_srq_handle_t h_srq, + IN ib_recv_wr_t* const p_recv_wr, + OUT ib_recv_wr_t **pp_recv_failure OPTIONAL ); + +typedef ib_api_status_t +(*ib_pfn_create_qp_t)( + IN const ib_pd_handle_t h_pd, + IN const ib_qp_create_t* const p_qp_create, + IN const void* const qp_context, + IN const ib_pfn_event_cb_t qp_event_cb OPTIONAL, + OUT ib_qp_handle_t* const ph_qp ); + +typedef ib_api_status_t +(*ib_pfn_get_spl_qp_t)( + IN const ib_pd_handle_t h_pd, + IN const ib_net64_t port_guid, + IN const ib_qp_create_t* const p_qp_create, + IN const void* const qp_context, + IN const ib_pfn_event_cb_t qp_event_cb OPTIONAL, + OUT ib_pool_key_t* const p_pool_key OPTIONAL, + OUT ib_qp_handle_t* const ph_qp ); + +typedef ib_api_status_t +(*ib_pfn_query_qp_t)( + IN const ib_qp_handle_t h_qp, + OUT ib_qp_attr_t* const p_qp_attr ); + +typedef ib_api_status_t +(*ib_pfn_modify_qp_t)( + IN const ib_qp_handle_t h_qp, + IN const ib_qp_mod_t* const p_qp_mod ); + +typedef ib_api_status_t +(*ib_pfn_destroy_qp_t)( + IN const ib_qp_handle_t h_qp, + IN const ib_pfn_destroy_cb_t destroy_cb OPTIONAL ); + +typedef ib_api_status_t +(*ib_pfn_create_cq_t)( + IN const ib_ca_handle_t h_ca, + IN OUT ib_cq_create_t* const p_cq_create, + IN const void* const cq_context, + IN const ib_pfn_event_cb_t cq_event_cb OPTIONAL, + OUT ib_cq_handle_t* const ph_cq ); + +typedef ib_api_status_t +(*ib_pfn_modify_cq_t)( + IN const ib_cq_handle_t h_cq, + IN OUT uint32_t* const p_size ); + +typedef ib_api_status_t +(*ib_pfn_query_cq_t)( + IN const ib_cq_handle_t h_cq, + OUT uint32_t* const p_size ); + +typedef ib_api_status_t +(*ib_pfn_destroy_cq_t)( + IN const ib_cq_handle_t h_cq, + IN const ib_pfn_destroy_cb_t destroy_cb OPTIONAL ); + +typedef ib_api_status_t +(*ib_pfn_reg_mem_t)( + IN const ib_pd_handle_t h_pd, + IN const ib_mr_create_t* const p_mr_create, + OUT uint32_t* const p_lkey, + OUT uint32_t* const p_rkey, + OUT ib_mr_handle_t* const ph_mr ); + +typedef ib_api_status_t +(*ib_pfn_reg_phys_t)( + IN const ib_pd_handle_t h_pd, + IN const ib_phys_create_t* const p_phys_create, + IN OUT uint64_t* const p_vaddr, + OUT uint32_t* const p_lkey, + OUT uint32_t* const p_rkey, + OUT ib_mr_handle_t* const ph_mr ); + +typedef ib_api_status_t +(*ib_pfn_query_mr_t)( + IN const ib_mr_handle_t h_mr, + OUT ib_mr_attr_t* const p_mr_attr ); + +typedef ib_api_status_t +(*ib_pfn_rereg_mem_t)( + IN const ib_mr_handle_t h_mr, + IN const ib_mr_mod_t mr_mod_mask, + IN const ib_mr_create_t* const p_mr_create OPTIONAL, + OUT uint32_t* const p_lkey, + OUT uint32_t* const p_rkey, + IN const ib_pd_handle_t h_pd OPTIONAL ); + +typedef ib_api_status_t +(*ib_pfn_rereg_phys_t)( + IN const ib_mr_handle_t h_mr, + IN const ib_mr_mod_t mr_mod_mask, + IN const ib_phys_create_t* const p_phys_create OPTIONAL, + IN OUT void** const p_vaddr, + OUT uint32_t* const p_lkey, + OUT uint32_t* const p_rkey, + IN const ib_pd_handle_t h_pd OPTIONAL ); + +typedef ib_api_status_t +(*ib_pfn_reg_shared_t)( + IN const ib_mr_handle_t h_mr, + IN const ib_pd_handle_t h_pd, + IN const ib_access_t access_ctrl, + IN OUT void** const p_vaddr, + OUT uint32_t* const p_lkey, + OUT uint32_t* const p_rkey, + OUT ib_mr_handle_t* const ph_mr ); + +typedef ib_api_status_t +(*ib_pfn_create_shmid_t)( + IN const ib_pd_handle_t h_pd, + IN const int shmid, + IN const ib_mr_create_t* const p_mr_create, + OUT uint32_t* const p_lkey, + OUT uint32_t* const p_rkey, + OUT ib_mr_handle_t* const ph_mr ); + +typedef ib_api_status_t +(*ib_pfn_reg_shmid_t)( + IN const ib_pd_handle_t h_pd, + IN const ib_shmid_t shmid, + IN const ib_mr_create_t* const p_mr_create, + IN OUT uint64_t* const p_vaddr, + OUT net32_t* const p_lkey, + OUT net32_t* const p_rkey, + OUT ib_mr_handle_t* const ph_mr ); + +typedef ib_api_status_t +(*ib_pfn_dereg_mr_t)( + IN const ib_mr_handle_t h_mr ); + +typedef ib_api_status_t +(*mlnx_pfn_create_fmr_t)( + IN const ib_pd_handle_t h_pd, + IN const mlnx_fmr_create_t* const p_fmr_create, + OUT mlnx_fmr_handle_t* const ph_fmr ); + +typedef ib_api_status_t +(*mlnx_pfn_map_phys_fmr_t)( + IN const mlnx_fmr_handle_t h_fmr, + IN const uint64_t* const paddr_list, + IN const int list_len, + IN OUT uint64_t* const p_vaddr, + OUT net32_t* const p_lkey, + OUT net32_t* const p_rkey ); + +typedef ib_api_status_t +(*mlnx_pfn_unmap_fmr_t)( + IN const mlnx_fmr_handle_t h_fmr ); + +typedef ib_api_status_t +(*mlnx_pfn_destroy_fmr_t)( + IN mlnx_fmr_handle_t const h_fmr ); + + +typedef ib_api_status_t +(*mlnx_pfn_create_fmr_pool_t)( + IN const ib_pd_handle_t h_pd, + IN const mlnx_fmr_pool_create_t *p_fmr_pool_attr, + OUT mlnx_fmr_pool_handle_t* const ph_pool ); + + +typedef ib_api_status_t +(*mlnx_pfn_destroy_fmr_pool_t)( + IN const mlnx_fmr_pool_handle_t h_pool ); + + +typedef ib_api_status_t +(*mlnx_pfn_map_phys_fmr_pool_t)( + IN const mlnx_fmr_pool_handle_t h_pool , + IN const uint64_t* const paddr_list, + IN const int list_len, + IN OUT uint64_t* const p_vaddr, + OUT net32_t* const p_lkey, + OUT net32_t* const p_rkey, + OUT mlnx_fmr_pool_el_t *p_fmr_el); + +typedef ib_api_status_t +(*mlnx_pfn_unmap_fmr_pool_t)( + IN mlnx_fmr_pool_el_t p_fmr_el ); + +typedef ib_api_status_t +(*mlnx_pfn_flush_fmr_pool_t)( + IN const mlnx_fmr_pool_handle_t h_pool ); + +typedef ib_api_status_t +(*ib_pfn_create_mw_t)( + IN const ib_pd_handle_t h_pd, + OUT uint32_t* const p_rkey, + OUT ib_mw_handle_t* const ph_mw ); + +typedef ib_api_status_t +(*ib_pfn_query_mw_t)( + IN const ib_mw_handle_t h_mw, + OUT ib_pd_handle_t* const ph_pd, + OUT uint32_t* const p_rkey ); + +typedef ib_api_status_t +(*ib_pfn_bind_mw_t)( + IN const ib_mw_handle_t h_mw, + IN const ib_qp_handle_t h_qp, + IN ib_bind_wr_t* const p_mw_bind, + OUT uint32_t* const p_rkey ); + +typedef ib_api_status_t +(*ib_pfn_destroy_mw_t)( + IN const ib_mw_handle_t h_mw ); + +typedef ib_api_status_t +(*ib_pfn_post_send_t)( + IN const ib_qp_handle_t h_qp, + IN ib_send_wr_t* const p_send_wr, + OUT ib_send_wr_t **pp_send_failure OPTIONAL ); + +typedef ib_api_status_t +(*ib_pfn_post_recv_t)( + IN const ib_qp_handle_t h_qp, + IN ib_recv_wr_t* const p_recv_wr, + OUT ib_recv_wr_t **pp_recv_failure OPTIONAL ); + +typedef ib_api_status_t +(*ib_pfn_send_mad_t)( + IN const ib_mad_svc_handle_t h_mad_svc, + IN ib_mad_element_t* const p_mad_element_list, + OUT ib_mad_element_t **pp_mad_failure OPTIONAL ); + +typedef ib_api_status_t +(*ib_pfn_cancel_mad_t)( + IN const ib_mad_svc_handle_t h_mad_svc, + IN ib_mad_element_t* const p_mad_element ); + +typedef ib_api_status_t +(*ib_pfn_poll_cq_t)( + IN const ib_cq_handle_t h_cq, + IN OUT ib_wc_t** const pp_free_wclist, + OUT ib_wc_t** const pp_done_wclist ); + +typedef ib_api_status_t +(*ib_pfn_rearm_cq_t)( + IN const ib_cq_handle_t h_cq, + IN const boolean_t solicited ); + +typedef ib_api_status_t +(*ib_pfn_join_mcast_t)( + IN const ib_qp_handle_t h_qp, + IN const ib_mcast_req_t* const p_mcast_req ); + +typedef ib_api_status_t +(*ib_pfn_leave_mcast_t)( + IN const ib_mcast_handle_t h_mcast, + IN const ib_pfn_destroy_cb_t destroy_cb ); + +typedef ib_api_status_t +(*ib_pfn_local_mad_t)( + IN const ib_ca_handle_t h_ca, + IN const uint8_t port_num, + IN const void* const p_mad_in, + OUT void* p_mad_out ); + +typedef ib_api_status_t +(*ib_pfn_cm_listen_t)( + IN const ib_al_handle_t h_al, + IN const ib_cm_listen_t* const p_cm_listen, + IN const void* const listen_context, + OUT ib_listen_handle_t* const ph_cm_listen ); + +typedef ib_api_status_t +(*ib_pfn_cm_cancel_t)( + IN const ib_listen_handle_t h_cm_listen, + IN const ib_pfn_destroy_cb_t destroy_cb OPTIONAL ); + +typedef ib_api_status_t +(*ib_pfn_cm_req_t)( + IN const ib_cm_req_t* const p_cm_req ); + +typedef ib_api_status_t +(*ib_pfn_cm_rep_t)( + IN const ib_cm_handle_t h_cm_req, + IN const ib_cm_rep_t* const p_cm_rep ); + +typedef ib_api_status_t +(*ib_pfn_cm_rtu_t)( + IN const ib_cm_handle_t h_cm_rep, + IN const ib_cm_rtu_t* const p_cm_rtu ); + +typedef ib_api_status_t +(*ib_pfn_cm_rej_t)( + IN const ib_cm_handle_t h_cm, + IN const ib_cm_rej_t* const p_cm_rej ); + +typedef ib_api_status_t +(*ib_pfn_cm_mra_t)( + IN const ib_cm_handle_t h_cm, + IN const ib_cm_mra_t* const p_cm_mra ); + +typedef ib_api_status_t +(*ib_pfn_cm_lap_t)( + IN const ib_cm_lap_t* const p_cm_lap ); + +typedef ib_api_status_t +(*ib_pfn_cm_apr_t)( + IN const ib_cm_handle_t h_cm_lap, + IN const ib_cm_apr_t* const p_cm_apr ); + +typedef ib_api_status_t +(*ib_pfn_force_apm_t)( + IN const ib_qp_handle_t h_qp ); + +typedef ib_api_status_t +(*ib_pfn_cm_dreq_t)( + IN const ib_cm_dreq_t* const p_cm_dreq ); + +typedef ib_api_status_t +(*ib_pfn_cm_drep_t)( + IN const ib_cm_handle_t h_cm_dreq, + IN const ib_cm_drep_t* const p_cm_drep ); + +typedef ib_api_status_t +(*ib_pfn_cm_handoff_t)( + IN const ib_cm_handle_t h_cm_req, + IN const ib_net64_t svc_id ); + +typedef ib_api_status_t +(*ib_pfn_create_ioc_t)( + IN const ib_ca_handle_t h_ca, + IN const ib_ioc_profile_t* const p_ioc_profile, + OUT ib_ioc_handle_t* const ph_ioc ); + +typedef ib_api_status_t +(*ib_pfn_destroy_ioc_t)( + IN const ib_ioc_handle_t h_ioc ); + +typedef ib_api_status_t +(*ib_pfn_reg_ioc_t)( + IN const ib_ioc_handle_t h_ioc ); + +typedef ib_api_status_t +(*ib_pfn_add_svc_entry_t)( + IN const ib_ioc_handle_t h_ioc, + IN const ib_svc_entry_t* const p_svc_entry, + OUT ib_svc_handle_t* const ph_svc ); + +typedef ib_api_status_t +(*ib_pfn_remove_svc_entry_t)( + IN const ib_svc_handle_t h_svc ); + +typedef ib_api_status_t +(*ib_pfn_get_ca_guids_t)( + IN ib_al_handle_t h_al, + OUT ib_net64_t* const p_guid_array OPTIONAL, + IN OUT uintn_t* const p_guid_cnt ); + +typedef ib_api_status_t +(*ib_pfn_get_ca_by_gid_t)( + IN ib_al_handle_t h_al, + IN const ib_gid_t* const p_gid, + OUT ib_net64_t* const p_ca_guid ); + +typedef ib_api_status_t +(*ib_pfn_get_ca_by_gid_t)( + IN ib_al_handle_t h_al, + IN const ib_gid_t* const p_gid, + OUT ib_net64_t* const p_ca_guid ); + +typedef ib_api_status_t +(*ib_pfn_get_port_by_gid_t)( + IN ib_al_handle_t h_al, + IN const ib_gid_t* const p_gid, + OUT ib_net64_t* const p_port_guid ); + +typedef ib_api_status_t +(*ib_pfn_create_mad_pool_t)( + IN const ib_al_handle_t h_al, + IN const size_t min, + IN const size_t max, + IN const size_t grow_size, + OUT ib_pool_handle_t* const ph_pool ); + +typedef ib_api_status_t +(*ib_pfn_destroy_mad_pool_t)( + IN const ib_pool_handle_t h_pool ); + +typedef ib_api_status_t +(*ib_pfn_reg_mad_pool_t)( + IN const ib_pool_handle_t h_pool, + IN const ib_pd_handle_t h_pd, + OUT ib_pool_key_t* const p_pool_key ); + +typedef ib_api_status_t +(*ib_pfn_dereg_mad_pool_t)( + IN const ib_pool_key_t pool_key ); + +typedef ib_api_status_t +(*ib_pfn_get_mad_t)( + IN const ib_pool_key_t pool_key, + IN const size_t buf_size, + OUT ib_mad_element_t **pp_mad_element ); + +typedef ib_api_status_t +(*ib_pfn_put_mad_t)( + IN const ib_mad_element_t* p_mad_element_list ); + +typedef ib_api_status_t +(*ib_pfn_init_dgrm_svc_t)( + IN const ib_qp_handle_t h_qp, + IN const ib_dgrm_info_t* const p_dgrm_info OPTIONAL ); + +typedef ib_api_status_t +(*ib_pfn_reg_mad_svc_t)( + IN const ib_qp_handle_t h_qp, + IN const ib_mad_svc_t* const p_mad_svc, + OUT ib_mad_svc_handle_t* const ph_mad_svc ); + +typedef ib_api_status_t +(*ib_pfn_reg_svc_t)( + IN const ib_al_handle_t h_al, + IN const ib_reg_svc_req_t* const p_reg_svc_req, + OUT ib_reg_svc_handle_t* const ph_reg_svc ); + +typedef ib_api_status_t +(*ib_pfn_dereg_svc_t)( + IN const ib_reg_svc_handle_t h_reg_svc, + IN const ib_pfn_destroy_cb_t destroy_cb OPTIONAL ); + +typedef ib_api_status_t +(*ib_pfn_query_t)( + IN const ib_al_handle_t h_al, + IN const ib_query_req_t* const p_query_req, + OUT ib_query_handle_t* const ph_query OPTIONAL ); + +typedef void +(*ib_pfn_cancel_query_t)( + IN const ib_al_handle_t h_al, + IN const ib_query_handle_t query_hndl ); + +typedef ib_api_status_t +(*ib_pfn_reg_pnp_t)( + IN const ib_al_handle_t h_al, + IN const ib_pnp_req_t* const p_pnp_req, + OUT ib_pnp_handle_t* const ph_pnp ); + +typedef ib_api_status_t +(*ib_pfn_dereg_pnp_t)( + IN const ib_pnp_handle_t h_pnp, + IN const ib_pfn_destroy_cb_t destroy_cb OPTIONAL ); + +typedef ib_api_status_t +(*ib_pfn_subscribe_t)( + IN const ib_al_handle_t h_al, + IN const ib_sub_req_t* const p_sub_req, + OUT ib_sub_handle_t* const ph_sub ); + +typedef ib_api_status_t +(*ib_pfn_unsubscribe_t)( + IN const ib_sub_handle_t h_sub, + IN const ib_pfn_destroy_cb_t destroy_cb OPTIONAL ); + +typedef ib_api_status_t +(*ib_pfn_reject_ioc_t)( + IN const ib_al_handle_t h_al, + IN const ib_pnp_handle_t h_ioc_event ); + +typedef ib_api_status_t +(*ib_pfn_ci_call_t)( + IN ib_ca_handle_t h_ca, + IN const void** const handle_array OPTIONAL, + IN uint32_t num_handles, + IN ib_ci_op_t* const p_ci_op ); + +typedef ib_api_status_t +(*ib_pfn_open_al_t)( + OUT ib_al_handle_t* const ph_al ); + +typedef ib_api_status_t +(*ib_pfn_close_al_t)( + IN const ib_al_handle_t h_al ); + +typedef const char* +(*ib_pfn_get_err_str_t)( + IN ib_api_status_t status ); + +typedef const char* +(*ib_pfn_get_wc_status_str_t)( + IN ib_wc_status_t wc_status ); + + +/* Interface specific data header. */ +typedef struct _ib_al_ifc_data +{ + const GUID *type; + USHORT size; + USHORT version; + void *p_data; + +} ib_al_ifc_data_t; + + +/* Interface definitions */ +typedef struct _ib_al_ifc +{ + /* Standard interface header. */ + INTERFACE wdm; + + /* AL entry points. */ + ib_pfn_sync_destroy_t sync_destroy; + ib_pfn_open_ca_t open_ca; + ib_pfn_query_ca_t query_ca; + ib_pfn_modify_ca_t modify_ca; + ib_pfn_get_ca_dev_t get_dev; + ib_pfn_close_ca_t close_ca; + ib_pfn_alloc_pd_t alloc_pd; + ib_pfn_dealloc_pd_t dealloc_pd; + ib_pfn_create_av_t create_av; + ib_pfn_query_av_t query_av; + ib_pfn_modify_av_t modify_av; + ib_pfn_destroy_av_t destroy_av; + ib_pfn_create_qp_t create_qp; + ib_pfn_get_spl_qp_t get_spl_qp; + ib_pfn_query_qp_t query_qp; + ib_pfn_modify_qp_t modify_qp; + ib_pfn_destroy_qp_t destroy_qp; + ib_pfn_create_cq_t create_cq; + ib_pfn_modify_cq_t modify_cq; + ib_pfn_query_cq_t query_cq; + ib_pfn_destroy_cq_t destroy_cq; + ib_pfn_reg_mem_t reg_mem; + ib_pfn_reg_phys_t reg_phys; + ib_pfn_query_mr_t query_mr; + ib_pfn_rereg_mem_t rereg_mem; + ib_pfn_create_shmid_t create_shmid; + ib_pfn_reg_shmid_t reg_shmid; + ib_pfn_dereg_mr_t dereg_mr; + ib_pfn_create_mw_t create_mw; + ib_pfn_query_mw_t query_mw; + ib_pfn_bind_mw_t bind_mw; + ib_pfn_destroy_mw_t destroy_mw; + ib_pfn_post_send_t post_send; + ib_pfn_post_recv_t post_recv; + ib_pfn_send_mad_t send_mad; + ib_pfn_cancel_mad_t cancel_mad; + ib_pfn_poll_cq_t poll_cq; + ib_pfn_rearm_cq_t rearm_cq; + ib_pfn_join_mcast_t join_mcast; + ib_pfn_leave_mcast_t leave_mcast; + ib_pfn_local_mad_t local_mad; + ib_pfn_cm_listen_t cm_listen; + ib_pfn_cm_cancel_t cm_cancel; + ib_pfn_cm_req_t cm_req; + ib_pfn_cm_rep_t cm_rep; + ib_pfn_cm_rtu_t cm_rtu; + ib_pfn_cm_rej_t cm_rej; + ib_pfn_cm_mra_t cm_mra; + ib_pfn_cm_lap_t cm_lap; + ib_pfn_cm_apr_t cm_apr; + ib_pfn_force_apm_t force_apm; + ib_pfn_cm_dreq_t cm_dreq; + ib_pfn_cm_drep_t cm_drep; + ib_pfn_cm_handoff_t cm_handoff; + ib_pfn_create_ioc_t create_ioc; + ib_pfn_destroy_ioc_t destroy_ioc; + ib_pfn_reg_ioc_t reg_ioc; + ib_pfn_add_svc_entry_t add_svc_entry; + ib_pfn_remove_svc_entry_t remove_svc_entry; + ib_pfn_get_ca_guids_t get_ca_guids; + ib_pfn_get_ca_by_gid_t get_ca_by_gid; + ib_pfn_get_port_by_gid_t get_port_by_gid; + ib_pfn_create_mad_pool_t create_mad_pool; + ib_pfn_destroy_mad_pool_t destroy_mad_pool; + ib_pfn_reg_mad_pool_t reg_mad_pool; + ib_pfn_dereg_mad_pool_t dereg_mad_pool; + ib_pfn_get_mad_t get_mad; + ib_pfn_put_mad_t put_mad; + ib_pfn_init_dgrm_svc_t init_dgrm_svc; + ib_pfn_reg_mad_svc_t reg_mad_svc; + ib_pfn_reg_svc_t reg_svc; + ib_pfn_dereg_svc_t dereg_svc; + ib_pfn_query_t query; + ib_pfn_cancel_query_t cancel_query; + ib_pfn_reg_pnp_t reg_pnp; + ib_pfn_dereg_pnp_t dereg_pnp; + ib_pfn_subscribe_t subscribe; + ib_pfn_unsubscribe_t unsubscribe; + ib_pfn_reject_ioc_t reject_ioc; + ib_pfn_ci_call_t ci_call; + ib_pfn_open_al_t open_al; + ib_pfn_close_al_t close_al; + ib_pfn_get_err_str_t get_err_str; + ib_pfn_get_wc_status_str_t get_wc_status_str; + mlnx_pfn_create_fmr_t create_mlnx_fmr; + mlnx_pfn_map_phys_fmr_t map_phys_mlnx_fmr; + mlnx_pfn_unmap_fmr_t unmap_mlnx_fmr; + mlnx_pfn_destroy_fmr_t destroy_mlnx_fmr; + mlnx_pfn_create_fmr_pool_t create_mlnx_fmr_pool; + mlnx_pfn_destroy_fmr_pool_t destroy_mlnx_fmr_pool; + mlnx_pfn_map_phys_fmr_pool_t map_phys_mlnx_fmr_pool; + mlnx_pfn_unmap_fmr_pool_t unmap_mlnx_fmr_pool; + mlnx_pfn_flush_fmr_pool_t flush_mlnx_fmr_pool; + + ib_pfn_create_srq_t create_srq; + ib_pfn_query_srq_t query_srq; + ib_pfn_modify_srq_t modify_srq; + ib_pfn_destroy_srq_t destroy_srq; + ib_pfn_post_srq_recv_t post_srq_recv; + +} ib_al_ifc_t; + + +#endif /* !defined _IB_AL_IFC_H_ */ + +/* + * AL interface GUID. The GUID is defined outside the conditional include + * on purpose so that it can be instantiated only once where it is actually + * needed. See the DDK docs section "Using GUIDs in Drivers" for more info. + */ +// {96234E89-496F-4dfb-AA90-FCE82BCEC8A8} +DEFINE_GUID(GUID_IB_AL_INTERFACE, +0x96234e89, 0x496f, 0x4dfb, 0xaa, 0x90, 0xfc, 0xe8, 0x2b, 0xce, 0xc8, 0xa8); diff --git a/branches/WOF2-3/inc/kernel/iba/ib_ci_ifc.h b/branches/WOF2-3/inc/kernel/iba/ib_ci_ifc.h new file mode 100644 index 00000000..22fc4849 --- /dev/null +++ b/branches/WOF2-3/inc/kernel/iba/ib_ci_ifc.h @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + +#if !defined _IB_CI_IFC_H_ +#define _IB_CI_IFC_H_ + + +#include "iba/ib_ci.h" + + +/****h* Access Layer/AL Channel Interface +* NAME +* AL Channel Interface +* +* DESCRIPTION +* Header file for the interface exported to HCA drivers to allow them +* to register with AL for use by AL clients. +*********/ + + +#define IB_CI_INTERFACE_VERSION (5) + + +/* Function type for ib_register_ca. Match the definition in ib_ci.h */ +typedef ib_api_status_t +(*ib_pfn_register_ca_t)( + IN const ci_interface_t* const p_ci, + IN const PDEVICE_OBJECT p_hca_dev, + IN const PDEVICE_OBJECT p_fdo + ); + + +/* Function type for ib_deregister_ca. Matches the definition in ib_ci.h */ +typedef ib_api_status_t +(*ib_pfn_deregister_ca_t)( + IN const net64_t ca_guid ); + + +/* + * Appends a CA's device relations given a CA guid to an existing list + * of relations. + */ +typedef NTSTATUS +(*ib_pfn_get_relations_t)( + IN net64_t ca_guid, + IN OUT IRP* const p_irp ); + + +typedef const char* +(*ib_pfn_get_err_str_t)( + IN ib_api_status_t status ); + + + +/****s* Access Layer: AL Channel Interface/ib_ci_ifc_t +* NAME +* ib_ci_ifc_t +* +* DESCRIPTION +* +* SYNOPSIS +*/ +typedef struct _ib_ci_ifc +{ + + INTERFACE wdm; + + ib_pfn_register_ca_t register_ca; + ib_pfn_deregister_ca_t deregister_ca; + ib_pfn_get_relations_t get_relations; + ib_pfn_get_err_str_t get_err_str; + +} ib_ci_ifc_t; +/* +* FIELDS +* wdmr. +* Standard interface header. +* +* register_ca +* Pointer to ib_pfn_register_ca_t function +* +* deregister_ca +* Pointer to ib_pfn_deregister_ca_t function +* +* get_relations +* Pointer to ib_pfn_get_relations_t function +* +* get_err_str +* Pointer to ib_pfn_get_err_str_t function +* +* SEE ALSO +* ib_register_ca,ib_deregister_ca, +*********/ + + +#endif /* !defined _IB_CI_IFC_H_ */ + +/* + * CI interface GUID. The GUID is defined outside the conditional include + * on purpose so that it can be instantiated only once where it is actually + * needed. See the DDK docs section "Using GUIDs in Drivers" for more info. + */ +/* {9B617D6B-65AB-4fe5-9601-555271F7534D} */ +DEFINE_GUID(GUID_IB_CI_INTERFACE, +0x9b617d6b, 0x65ab, 0x4fe5, 0x96, 0x1, 0x55, 0x52, 0x71, 0xf7, 0x53, 0x4d); diff --git a/branches/WOF2-3/inc/kernel/iba/ib_cm_ifc.h b/branches/WOF2-3/inc/kernel/iba/ib_cm_ifc.h new file mode 100644 index 00000000..e895406d --- /dev/null +++ b/branches/WOF2-3/inc/kernel/iba/ib_cm_ifc.h @@ -0,0 +1,318 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef _ib_cm_ifc_h_ +#define _ib_cm_ifc_h_ + +#include +#include +#include +#include + +struct _iba_cm_event; + +typedef struct _iba_cm_id +{ + void *context; + NTSTATUS (*callback)(struct _iba_cm_id *p_id, struct _iba_cm_event *p_event); + net32_t cid; + +} iba_cm_id; + +typedef struct _iba_cm_req +{ + ib_net64_t service_id; + + ib_path_rec_t *p_primary_path; + ib_path_rec_t *p_alt_path; + + net32_t qpn; + ib_qp_type_t qp_type; + net32_t starting_psn; + + void *p_pdata; + uint8_t pdata_len; + + uint8_t max_cm_retries; + uint8_t resp_res; + uint8_t init_depth; + uint8_t remote_resp_timeout; + uint8_t flow_ctrl; + uint8_t local_resp_timeout; + uint8_t rnr_retry_cnt; + uint8_t retry_cnt; + uint8_t srq; + +} iba_cm_req; + +typedef struct _iba_cm_req_event +{ + ib_net64_t service_id; + + ib_path_rec_t primary_path; + ib_path_rec_t alt_path; + + net32_t qpn; + ib_qp_type_t qp_type; + net32_t starting_psn; + + uint8_t pdata[IB_REQ_PDATA_SIZE]; + + uint8_t max_cm_retries; + uint8_t resp_res; + uint8_t init_depth; + uint8_t remote_resp_timeout; + uint8_t flow_ctrl; + uint8_t local_resp_timeout; + uint8_t rnr_retry_cnt; + uint8_t retry_cnt; + uint8_t srq; + + net64_t local_ca_guid; + net64_t remote_ca_guid; + uint16_t pkey_index; + uint8_t port_num; + +} iba_cm_req_event; + +typedef struct _iba_cm_rep +{ + net32_t qpn; + net32_t starting_psn; + + void *p_pdata; + uint8_t pdata_len; + + ib_cm_failover_t failover_accepted; + uint8_t resp_res; + uint8_t init_depth; + uint8_t flow_ctrl; + uint8_t rnr_retry_cnt; + uint8_t srq; + +} iba_cm_rep; + +typedef struct _iba_cm_rep_event +{ + iba_cm_rep rep; + net64_t ca_guid; + uint8_t target_ack_delay; + +} iba_cm_rep_event; + +typedef struct _iba_cm_pdata +{ + void *p_pdata; + uint8_t pdata_len; + +} iba_cm_pdata; +typedef iba_cm_pdata iba_cm_rtu_event; +typedef iba_cm_pdata iba_cm_dreq_event; +typedef iba_cm_pdata iba_cm_drep_event; + +typedef struct _iba_cm_rej_event +{ + void *ari; + void *p_pdata; + ib_rej_status_t reason; + uint8_t ari_length; + uint8_t pdata_len; + +} iba_cm_rej_event; + +typedef struct _iba_cm_mra_event +{ + void *p_pdata; + uint8_t pdata_len; + uint8_t service_timeout; + +} iba_cm_mra_event; + +typedef struct _iba_cm_lap +{ + ib_path_rec_t *p_alt_path; + void *p_pdata; + uint8_t pdata_len; + uint8_t remote_resp_timeout; + +} iba_cm_lap; +typedef iba_cm_lap iba_cm_lap_event; + +typedef struct _iba_cm_apr +{ + void *p_pdata; + ib_apr_info_t *p_info; + uint8_t pdata_len; + uint8_t info_length; + ib_apr_status_t status; + +} iba_cm_apr; +typedef iba_cm_apr iba_cm_apr_event; + +typedef struct _iba_cm_sidr_req +{ + ib_net64_t service_id; + ib_path_rec_t *p_path; + void *p_pdata; + uint8_t pdata_len; + uint8_t max_cm_retries; + uint32_t timeout; + +} iba_cm_sidr_req; + +typedef struct _iba_cm_sidr_req_event +{ + iba_cm_sidr_req sidr_req; + net64_t ca_guid; + uint16_t pkey_index; + uint8_t port_num; + +} iba_cm_sidr_req_event; + +typedef struct _iba_cm_sidr_rep +{ + net32_t qpn; + net32_t qkey; + void *p_pdata; + void *p_info; + uint8_t pdata_len; + uint8_t info_len; + ib_sidr_status_t status; + +} iba_cm_sidr_rep; +typedef iba_cm_sidr_rep iba_cm_sidr_rep_event; + +typedef enum _iba_cm_event_type +{ + iba_cm_req_error, + iba_cm_req_received, + iba_cm_rep_error, + iba_cm_rep_received, + iba_cm_rtu_received, + iba_cm_dreq_error, + iba_cm_dreq_received, + iba_cm_drep_received, + iba_cm_rej_received, + iba_cm_mra_received, + iba_cm_lap_error, + iba_cm_lap_received, + iba_cm_apr_received, + iba_cm_sidr_req_error, + iba_cm_sidr_req_received, + iba_cm_sidr_rep_received + +} iba_cm_event_type; + +typedef struct _iba_cm_event +{ + iba_cm_event_type type; + union + { + iba_cm_req_event req; + iba_cm_rep_event rep; + iba_cm_rtu_event rtu; + iba_cm_dreq_event dreq; + iba_cm_drep_event drep; + iba_cm_rej_event rej; + iba_cm_mra_event mra; + iba_cm_lap_event lap; + iba_cm_apr_event apr; + iba_cm_sidr_req_event sidr_req; + iba_cm_sidr_rep_event sidr_rep; + + } data; + +} iba_cm_event; + +typedef struct _iba_cm_interface +{ + NTSTATUS (*create_id)(NTSTATUS (*callback)(iba_cm_id *p_id, + iba_cm_event *p_event), + void *context, iba_cm_id **pp_id); + void (*destroy_id)(iba_cm_id *p_id); + + NTSTATUS (*listen)(iba_cm_id *p_id, net64_t service_id, void *p_compare_buf, + uint8_t compare_len, uint8_t compare_offset); + NTSTATUS (*get_request)(iba_cm_id *p_listen_id, iba_cm_id **pp_id, + iba_cm_event *p_event); + + NTSTATUS (*send_req)(iba_cm_id *p_id, iba_cm_req *p_req); + NTSTATUS (*send_rep)(iba_cm_id *p_id, iba_cm_rep *p_rep); + NTSTATUS (*send_rtu)(iba_cm_id *p_id, void *p_pdata, uint8_t pdata_len); + + NTSTATUS (*send_dreq)(iba_cm_id *p_id, void *p_pdata, uint8_t pdata_len); + NTSTATUS (*send_drep)(iba_cm_id *p_id, void *p_pdata, uint8_t pdata_len); + + NTSTATUS (*send_rej)(iba_cm_id *p_id, ib_rej_status_t status, + void *p_ari, uint8_t ari_len, + void *p_pdata, uint8_t pdata_len); + NTSTATUS (*send_mra)(iba_cm_id *p_id, uint8_t service_timeout, + void *p_pdata, uint8_t pdata_len); + + NTSTATUS (*send_lap)(iba_cm_id *p_id, iba_cm_lap *p_lap); + NTSTATUS (*send_apr)(iba_cm_id *p_id, iba_cm_apr *p_apr); + + NTSTATUS (*send_sidr_req)(iba_cm_id *p_id, iba_cm_sidr_req *p_req); + NTSTATUS (*send_sidr_rep)(iba_cm_id *p_id, iba_cm_sidr_rep *p_rep); + + NTSTATUS (*get_qp_attr)(iba_cm_id *p_id, ib_qp_state_t state, + ib_qp_mod_t *p_attr); + + NTSTATUS (*migrate)(iba_cm_id *p_id); + NTSTATUS (*established)(iba_cm_id *p_id); + +} iba_cm_interface; + +static inline USHORT IbaCmVersion(UINT8 Major, UINT8 Minor) +{ + return ((USHORT) Major << 8) | ((USHORT) Minor); +} + +static inline UINT8 IbaCmVersionMajor(USHORT Version) +{ + return (UINT8) (Version >> 8); +} + +static inline UINT8 IbaCmVersionMinor(USHORT Version) +{ + return (UINT8) Version; +} + +// {6A11D060-8957-49e6-BE2A-01EDF1BD22B3} +DEFINE_GUID(GUID_INFINIBAND_INTERFACE_CM, 0x6a11d060, 0x8957, 0x49e6, + 0xbe, 0x2a, 0x1, 0xed, 0xf1, 0xbd, 0x22, 0xb3); + +typedef struct _INFINIBAND_INTERFACE_CM +{ + INTERFACE InterfaceHeader; + iba_cm_interface CM; + +} INFINIBAND_INTERFACE_CM; + +#endif // _ib_cm_ifc_h_ \ No newline at end of file diff --git a/branches/WOF2-3/inc/kernel/iba/ib_rdma_cm.h b/branches/WOF2-3/inc/kernel/iba/ib_rdma_cm.h new file mode 100644 index 00000000..b6f01f1c --- /dev/null +++ b/branches/WOF2-3/inc/kernel/iba/ib_rdma_cm.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#ifndef _IB_RDMA_CM_H_ +#define _IB_RDMA_CM_H_ + +#include + +#define IB_CMA_VERSION 0x00 + +#define IB_CMA_SERVICE_ID 0x0000000001000000 +#define IB_CMA_SERVICE_ID_MASK 0xFFFFFFFFFF000000 +#define IB_CMA_CM_RESPONSE_TIMEOUT 20 +#define IB_CMA_MAX_CM_RETRIES 15 + +typedef union _IB_CMA_IP_ADDRESS +{ + UINT8 Ip6Address[16]; + struct { + UINT32 Pad[3]; + UINT32 Address; + + } Ip4; + +} IB_CMA_IP_ADDRESS; + +typedef struct _IB_CMA_HEADER +{ + UINT8 CmaVersion; + UINT8 IpVersion; // IP Version: 7:4 + UINT16 Port; + IB_CMA_IP_ADDRESS SrcAddress; + IB_CMA_IP_ADDRESS DstAddress; + +} IB_CMA_HEADER; + +#endif // _IB_RDMA_CM_H_ \ No newline at end of file diff --git a/branches/WOF2-3/inc/kernel/iba/ioc_ifc.h b/branches/WOF2-3/inc/kernel/iba/ioc_ifc.h new file mode 100644 index 00000000..6ea9328b --- /dev/null +++ b/branches/WOF2-3/inc/kernel/iba/ioc_ifc.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + +#include + + +#if !defined _IOC_IFC_H_ +#define _IOC_IFC_H_ + + +/****h* Access Layer/IO Controler Interface +* NAME +* IO Controler Interface +* +* DESCRIPTION +* Header file for the interface exported to IOC client drivers to retrieve +* IOC device information. +* +* The interface contains information about the particular instance of an IOC. +*********/ + + +#define IOC_INTERFACE_DATA_VERSION (3) + + + +/****s* Access Layer: IO Controler Interface/ioc_ifc_data_t +* NAME +* ioc_ifc_data_t +* +* DESCRIPTION +* I/O Controler interface data. +* +* The ioc_ifc_data_t structure +* +* SYNOPSIS +*/ +typedef struct _ioc_ifc_data +{ + net64_t ca_guid; + net64_t guid; + +} ioc_ifc_data_t; +/* +* FIELDS +* ca_guid +* Local CA GUID through which IOC is accessible. +* +* guid +* IOC GUID. +* +* SEE ALSO +* +*********/ + + +#endif /* !defined _IOC_IFC_H_ */ + +/* + * IOC interface GUID. The GUID is defined outside the conditional include + * on purpose so that it can be instantiated only once where it is actually + * needed. See the DDK docs section "Using GUIDs in Drivers" for more info. + */ +/* {20883ACD-57F3-4da3-AD03-73D0178ACAE9} */ +DEFINE_GUID(GUID_IOC_INTERFACE_DATA, +0x20883acd, 0x57f3, 0x4da3, 0xad, 0x3, 0x73, 0xd0, 0x17, 0x8a, 0xca, 0xe9); diff --git a/branches/WOF2-3/inc/kernel/iba/iou_ifc.h b/branches/WOF2-3/inc/kernel/iba/iou_ifc.h new file mode 100644 index 00000000..ca34e9c2 --- /dev/null +++ b/branches/WOF2-3/inc/kernel/iba/iou_ifc.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + +#include "iba/ib_al_ifc.h" + + +#if !defined _IOU_IFC_H_ +#define _IOU_IFC_H_ + + +/****h* Access Layer/ IO Unit Interface +* NAME +* IO Unit Interface +* +* DESCRIPTION +* Header file for the interface exported to IOU client drivers to retrieve +* IOU device information. +* +* The interface contains information about the particular instance of an IOU. +*********/ + + +#define IOU_INTERFACE_DATA_VERSION (4) + + + +/****s* Access Layer: IO Unit Interface/iou_ifc_data_t +* NAME +* iou_ifc_data_t +* +* DESCRIPTION +* I/O Unit interface data. +* +* The iou_ifc_data_t structure +* +* SYNOPSIS +*/ +typedef struct _iou_ifc_data +{ + net64_t ca_guid; + net64_t chassis_guid; + uint8_t slot; + net64_t guid; + +} iou_ifc_data_t; +/* +* FIELDS +* ca_guid +* Local CA GUID through which IOU is accessible. +* +* chassis_guid +* IOU chassis GUID. +* +* slot +* IOU slot. +* +* guid +* IOU GUID. +* +* SEE ALSO +* +*********/ + +#endif /* !defined _IOU_IFC_H_ */ + +/* + * IOU interface GUID. The GUID is defined outside the conditional include + * on purpose so that it can be instantiated only once where it is actually + * needed. See the DDK docs section "Using GUIDs in Drivers" for more info. + */ +/* {C78F0228-E564-4d46-8A4B-295030414C1A} */ +DEFINE_GUID(GUID_IOU_INTERFACE_DATA, +0xc78f0228, 0xe564, 0x4d46, 0x8a, 0x4b, 0x29, 0x50, 0x30, 0x41, 0x4c, 0x1a); diff --git a/branches/WOF2-3/inc/kernel/iba/ipoib_ifc.h b/branches/WOF2-3/inc/kernel/iba/ipoib_ifc.h new file mode 100644 index 00000000..d34eaf6d --- /dev/null +++ b/branches/WOF2-3/inc/kernel/iba/ipoib_ifc.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2006 Mellanox Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + +#include "iba/ib_al_ifc.h" + + +#if !defined _IPOIB_IFC_H_ +#define _IPOIB_IFC_H_ + + +/****h* Access Layer/IPoIB Interface +* NAME +* IPoIB Interface +* +* DESCRIPTION +* Header file for the interface exported to IPoIB client drivers for access +* to IB resources provided by HCAs. +* +* The actual interface returned is an contains information about the +* particular instance of an IPoIB device. +*********/ + + +#define IPOIB_INTERFACE_DATA_VERSION (5) + + +/****s* Access Layer: IPoIB Interface/ipoib_ifc_data_t +* NAME +* ipoib_ifc_data_t +* +* DESCRIPTION +* IPoIB interface datat. +* +* The port guid combined from guid + PKEY +*/ +typedef struct _port_guid_pkey +{ + net64_t guid; + ib_net16_t pkey; +} port_guid_pkey_t; + + +/* +* The ipoib_ifc_data_t structure +* +* SYNOPSIS +*/ +typedef struct _ipoib_ifc_data +{ + net64_t ca_guid; + port_guid_pkey_t port_guid; + uint8_t port_num; + +} ipoib_ifc_data_t; +/* +* FIELDS +* ca_guid +* HCA GUID for this IPoIB interface +* +* port_guid +* Port GUID for this IPoIB interface +* +* port_num +* Port Number GUID for this IPoIB interface +* +* SEE ALSO +* +*********/ + + + +#endif /* !defined _IPOIB_IFC_H_ */ + +/* + * IPOIB interface GUID. The GUID is defined outside the conditional include + * on purpose so that it can be instantiated only once where it is actually + * needed. See the DDK docs section "Using GUIDs in Drivers" for more info. + */ +/* {B40DDB48-5710-487a-B812-6DAF56C7F423} */ +DEFINE_GUID(GUID_IPOIB_INTERFACE_DATA, +0xb40ddb48, 0x5710, 0x487a, 0xb8, 0x12, 0x6d, 0xaf, 0x56, 0xc7, 0xf4, 0x23); diff --git a/branches/WOF2-3/inc/kernel/index_list.h b/branches/WOF2-3/inc/kernel/index_list.h new file mode 100644 index 00000000..ec0ab7f1 --- /dev/null +++ b/branches/WOF2-3/inc/kernel/index_list.h @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#ifndef _INDEX_LIST_H_ +#define _INDEX_LIST_H_ + +#include + +typedef struct _INDEX_ENTRY +{ + SIZE_T Next; + SIZE_T Prev; + void *pItem; + +} INDEX_ENTRY; + +extern INDEX_ENTRY EmptyList; + +// Synchronization must be provided by the caller. +typedef struct _INDEX_LIST +{ + INDEX_ENTRY *pArray; // pArray[0] is list head of used entries + SIZE_T FreeList; // singly-linked list of free INDEX_ENTRY's + SIZE_T Size; + +} INDEX_LIST; + +static void IndexListInit(INDEX_LIST *pIndexList) +{ + pIndexList->pArray = &EmptyList; + pIndexList->FreeList = 0; + pIndexList->Size = 0; +} + +static void IndexListDestroy(INDEX_LIST *pIndexList) +{ + if (pIndexList->pArray != &EmptyList) { + ExFreePool(pIndexList->pArray); + } +} + +SIZE_T IndexListInsertHead(INDEX_LIST *pIndexList, void *pItem); + +static void *IndexListAt(INDEX_LIST *pIndexList, SIZE_T Index) +{ + return (Index < pIndexList->Size) ? pIndexList->pArray[Index].pItem : NULL; +} + +void *IndexListRemove(INDEX_LIST *pIndexList, SIZE_T Index); + +static void *IndexListRemoveHead(INDEX_LIST *pIndexList) +{ + return IndexListRemove(pIndexList, pIndexList->pArray[0].Next); +} + +#define IndexListForEach(pIndexList, Index) \ + for (Index = (pIndexList)->pArray[0].Next; Index != 0; \ + Index = (pIndexList)->pArray[Index].Next) + +#endif // _INDEX_LIST_H_ diff --git a/branches/WOF2-3/inc/kernel/ip_packet.h b/branches/WOF2-3/inc/kernel/ip_packet.h new file mode 100644 index 00000000..663729da --- /dev/null +++ b/branches/WOF2-3/inc/kernel/ip_packet.h @@ -0,0 +1,561 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#ifndef _IP_PACKET_H_ +#define _IP_PACKET_H_ + + +#include +#include + + +#ifndef HW_ADDR_LEN +#define HW_ADDR_LEN 6 +#endif /* HW_ADDR_LEN */ + + +#define ETH_PROT_TYPE_IP CL_HTON16(0x800) +#define ETH_PROT_TYPE_IPV6 CL_HTON16(0x86DD) +#define ETH_PROT_TYPE_ARP CL_HTON16(0x806) +#define ETH_PROT_TYPE_RARP CL_HTON16(0x8035) +#define ETH_PROT_VLAN_TAG CL_HTON16(0x8100) + + +#define ETH_IS_LOCALLY_ADMINISTERED(addr) \ + (BOOLEAN)(((PUCHAR)(addr))[0] & ((UCHAR)0x02)) + + +#include +/****s* IB Network Drivers/mac_addr_t +* NAME +* mac_addr_t +* +* DESCRIPTION +* Defines the ehternet MAC address. +* +* SYNOPSIS +*/ +typedef struct _mac_addr +{ + uint8_t addr[HW_ADDR_LEN]; + +} PACK_SUFFIX mac_addr_t; +/* +* FIELDS +* addr +* Byte array representing the MAC address. +* +* NOTES +* The HW_ADDR_LEN value must be defined before including this header in order +* to support various address lengths. If not defined, the default length for +* ethernet (6 bytes) is used. +* +* addr[0] & 0x1 indicates multicast +* addr[0] & 0x2 indicates LAA if not multicast +* +* SEE ALSO +* IB Network Drivers, arp_pkt_t, ip_hdr_t, tcp_hdr_t, udp_hdr_t +*********/ +#include + + +#include +/****s* IB Network Drivers/eth_hdr_t +* NAME +* eth_hdr_t +* +* DESCRIPTION +* Defines the ethernet header for IP packets. +* +* SYNOPSIS +*/ +typedef struct _eth_hdr +{ + mac_addr_t dst; + mac_addr_t src; + net16_t type; + +} PACK_SUFFIX eth_hdr_t; +/* +* FIELDS +* dst +* Destination address +* +* src +* Source address +* +* type +* Ethernet protocol type +* +* NOTES +* The HW_ADDR_LEN value must be defined before including this header in order +* to support various address lengths. +* +* SEE ALSO +* IB Network Drivers, arp_pkt_t, ip_hdr_t, tcp_hdr_t, udp_hdr_t +*********/ +#include + + +#define ARP_HW_TYPE_ETH CL_HTON16(1) +#define ARP_HW_TYPE_IB CL_HTON16(32) + +#define ARP_OP_REQ CL_HTON16(1) +#define ARP_OP_REP CL_HTON16(2) + + +#include +/****s* IB Network Drivers/arp_pkt_t +* NAME +* arp_pkt_t +* +* DESCRIPTION +* Defines the ARP packet for IP packets. +* +* SYNOPSIS +*/ +typedef struct _arp_pkt +{ + net16_t hw_type; + net16_t prot_type; + uint8_t hw_size; + uint8_t prot_size; + net16_t op; + mac_addr_t src_hw; + net32_t src_ip; + mac_addr_t dst_hw; + net32_t dst_ip; + +} PACK_SUFFIX arp_pkt_t; +/* +* FIELDS +* hw_type +* Hardware type +* +* prot_type +* Protocol type. See ETH_PROT_TYPE_XXX definitions. +* +* hw_size +* Size of the hardware address +* +* prot_size +* Size of the protocol address +* +* op +* ARP operation +* +* src_hw +* Source HW (MAC) address +* +* src_ip +* Source IP address +* +* dst_hw +* Destination HW (MAC) address +* +* dst_ip +* Destination IP address +* +* NOTES +* The HW_ADDR_LEN value must be defined before including this header in order +* to support various MAC address lengths. +* +* SEE ALSO +* IB Network Drivers, eth_hdr_t, ip_hdr_t, tcp_hdr_t, udp_hdr_t +*********/ +#include + + +#define IP_PROT_IP 4 +#define IP_PROT_TCP 6 +#define IP_PROT_UDP 17 +#define IP_PROT_IGMP 2 +#define IP_PROT_ICMP 1 + + +#include +/****s* IB Network Drivers/ip_hdr_t +* NAME +* ip_hdr_t +* +* DESCRIPTION +* Defines the IP header for IP packets. +* +* SYNOPSIS +*/ +typedef struct _ip_hdr +{ + uint8_t ver_hl; + uint8_t svc_type; + net16_t length; + net16_t id; + net16_t offset; + uint8_t ttl; + uint8_t prot; + net16_t chksum; + net32_t src_ip; + net32_t dst_ip; + +} PACK_SUFFIX ip_hdr_t; +/* +* FIELDS +* ver_hl +* Header version and length. +* +* svc_type +* Service type. +* +* length +* Total length. +* +* id +* Packet identification. +* +* offset +* Fragment offset. +* +* ttl +* Time to live. +* +* prot +* Protocol. +* +* chksum +* Checksum. +* +* src_ip +* Source IP address +* +* dst_ip +* Destination IP address +* +* SEE ALSO +* IB Network Drivers, eth_hdr_t, arp_pkt_t, tcp_hdr_t, udp_hdr_t +*********/ +#include + + +#include +/****s* IB Network Drivers/tcp_hdr_t +* NAME +* tcp_hdr_t +* +* DESCRIPTION +* Defines the IP header for IP packets. +* +* SYNOPSIS +*/ +typedef struct _tcp_hdr +{ + net16_t src_port; + net16_t dst_port; + net32_t seq_num; + net32_t ack_num; + uint8_t offset; + uint8_t flags; + net16_t window; + net16_t chksum; + net16_t urp; + +} PACK_SUFFIX tcp_hdr_t; +/* +* FIELDS +* src_port +* Source port. +* +* dst_port +* Destination port. +* +* seq_num +* Sequence number. +* +* ack_num +* Acknowledge number. +* +* offset +* data offset. +* +* flags +* TCP flags. +* +* window +* Window number. +* +* chksum +* Checksum. +* +* urp +* Urgent pointer. +* +* SEE ALSO +* IB Network Drivers, eth_hdr_t, arp_pkt_t, ip_hdr_t, udp_hdr_t +*********/ +#include + + +#include +/****s* IB Network Drivers/udp_hdr_t +* NAME +* udp_hdr_t +* +* DESCRIPTION +* Defines the IP header for IP packets. +* +* SYNOPSIS +*/ +typedef struct _udp_hdr +{ + net16_t src_port; + net16_t dst_port; + net16_t length; + net16_t chksum; + +} PACK_SUFFIX udp_hdr_t; +/* +* FIELDS +* src_port +* Source port. +* +* dst_port +* Destination port. +* +* length +* Length of datagram. +* +* chksum +* Checksum. +* +* SEE ALSO +* IB Network Drivers, eth_hdr_t, arp_pkt_t, ip_hdr_t, tcp_hdr_t +*********/ +#include + +#define IP_HEADER_LENGTH(pIpHdr) \ + ( (ULONG)((pIpHdr->ver_hl & 0x0F) << 2) ) + +#define TCP_HEADER_LENGTH(pTcpHdr) \ + ((pTcpHdr->offset & 0xF0) >> 2) + +#define IP_FRAGMENT_OFFSET(p_ip_hdr) \ + ( cl_ntoh16( p_ip_hdr->offset & CL_HTON16(0x1fff) ) ) + +#define IP_DONT_FRAGMENT(p_ip_hdr) \ + ( (BOOLEAN)( p_ip_hdr->offset & CL_HTON16(0x4000 ) ) ) + +#define IP_MORE_FRAGMENTS( p_ip_hdr ) \ + ( (BOOLEAN)( p_ip_hdr->offset & CL_HTON16(0x2000) ) ) + +#define IP_SET_MORE_FRAGMENTS( p_ip_hdr ) \ + ( p_ip_hdr->offset |= CL_HTON16(0x2000) ) + +#define IP_SET_LAST_FRAGMENT( p_ip_hdr ) \ + ( p_ip_hdr->offset &= (CL_HTON16(~0x2000) ) ) + +#define PROTOCOL_TCP IP_PROT_TCP + +#define IGMP_V2_MEMBERSHIP_QUERY 0x11 +#define IGMP_V2_MEMBERSHIP_REPORT 0x16 +#define IGMP_V1_MEMBERSHIP_REPORT 0x12 // for backward compatibility with IGMPv1 +#define IGMP_V2_LEAVE_GROUP 0x17 +#include +/****s* IB Network Drivers/igmp__v2_hdr_t +* NAME +* igmp_v2_hdr_t +* +* DESCRIPTION +* Defines the IGMPv2 header for IP packets. +* +* SYNOPSIS +*/ +typedef struct _igmp_v2_hdr +{ + uint8_t type; + uint8_t max_resp_time; + net16_t chksum; + net32_t group_address; +} PACK_SUFFIX igmp_v2_hdr_t; +/* +* FIELDS +* type +* type of IGMPv2 message: query/report/leave +* +* max_resp_time +* The Max Response Time field is meaningful only in Membership Query +* messages, and specifies the maximum allowed time before sending a +* responding report in units of 1/10 second. In all other messages, it +* is set to zero by the sender and ignored by receivers. +* +* checksum +* The checksum is the 16-bit one's complement of the one's complement +* sum of the whole IGMP message (the entire IP payload). +* +* group_address +* In a Membership Query message, the group address field is set to zero +* when sending a General Query, and set to the group address being +* queried when sending a Group-Specific Query. +* +* In a Membership Report or Leave Group message, the group address +* field holds the IP multicast group address of the group being +* reported or left. +* +* SEE ALSO +* IB Network Drivers, eth_hdr_t, arp_pkt_t, ip_hdr_t, tcp_hdr_t +*********/ +#include + +#define DHCP_PORT_SERVER CL_HTON16(67) +#define DHCP_PORT_CLIENT CL_HTON16(68) +#define DHCP_PORT_PROXY_SERVER CL_HTON16(4011) + +#define DHCP_REQUEST 1 +#define DHCP_REPLY 2 +#define DHCP_HW_TYPE_ETH 1 +#define DHCP_HW_TYPE_IB 32 +#define DHCP_OPT_PAD 0 +#define DHCP_OPT_END 255 +#define DHCP_OPT_MSG 53 +#define DHCP_OPT_CLIENT_ID 61 + +#define DHCPDISCOVER 1 +#define DHCPOFFER 2 +#define DHCPREQUEST 3 +#define DHCPDECLINE 4 +#define DHCPACK 5 +#define DHCPNAK 6 +#define DHCPRELEASE 7 +#define DHCPINFORM 8 + +#define DHCP_FLAGS_BROADCAST CL_HTON16(0x8000) +#define DHCP_COOKIE 0x63538263 +#define DHCP_OPTIONS_SIZE 312 +#define DHCP_COOKIE_SIZE 4 + + +/* Minimum DHCP size is without options (but with 4-byte magic cookie). */ +#define DHCP_MIN_SIZE (sizeof(dhcp_pkt_t) + DHCP_COOKIE_SIZE - DHCP_OPTIONS_SIZE ) + +// The length of IPoIB data inside CID field of DHCP packets +static const uint8_t coIPoIB_CID_Len = 20; +static const uint8_t coIPoIB_CID_TotalLen = 22; + + +//static const uint8_t coIPoIB_HwTypeIB = 0xFF; - This definition will not work for C-code (C- C2099) +#define coIPoIB_HwTypeIB 0xFF + +// The default prefix of IPoIB CID field within CID. +static const uint8_t coIBDefaultDHCPPrefix[] = { + coIPoIB_HwTypeIB, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x2, 0x0, + 0x0, 0x2, 0xc, 0x0 +}; + +/* The CID will contain of: + CID[0] = DHCP_OPT_CLIENT_ID; + CID[1] = coIPoIB_CID_Len; + CID[2:13] = coIBDefaultDHCPPrefix; (Here CID[2] always == coIPoIB_HwTypeIB) + CID[14:21] = GUID; +*/ + + + +#include +/****s* IB Network Drivers/dhcp_pkt_t +* NAME +* dhcp_pkt_t +* +* DESCRIPTION +* Defines the DHCP packet format as documented in RFC 2131 +* http://www.zvon.org/tmRFC/RFC2131/Output/index.html +* +* SYNOPSIS +*/ +typedef struct _dhcp_pkt +{ + uint8_t op; + uint8_t htype; + uint8_t hlen; + uint8_t hops; + net32_t xid; + net16_t secs; + net16_t flags; + net32_t ciaddr; + net32_t yiaddr; + net32_t siaddr; + net32_t giaddr; + uint8_t chaddr[16]; + uint8_t sname[64]; + uint8_t file[128]; + uint8_t options[312]; + +} PACK_SUFFIX dhcp_pkt_t; +/* +* SEE ALSO +* IB Network Drivers, eth_hdr_t, arp_pkt_t, ip_hdr_t, udp_hdr_t +*********/ +#include + + +#include +typedef struct _udp_pkt +{ + udp_hdr_t hdr; + dhcp_pkt_t dhcp; + +} PACK_SUFFIX udp_pkt_t; + +typedef struct _ip_pkt +{ + ip_hdr_t hdr; + union _ip_payload + { + tcp_hdr_t tcp; + udp_pkt_t udp; + + } PACK_SUFFIX prot; + +} PACK_SUFFIX ip_pkt_t; + +typedef struct _eth_pkt +{ + eth_hdr_t hdr; + union _eth_payload + { + arp_pkt_t arp; + ip_pkt_t ip; + + } PACK_SUFFIX type; + +} PACK_SUFFIX eth_pkt_t; +#include + + +#endif /* _IP_PACKET_H_ */ diff --git a/branches/WOF2-3/inc/kernel/rdma/verbs.h b/branches/WOF2-3/inc/kernel/rdma/verbs.h new file mode 100644 index 00000000..67f5eac4 --- /dev/null +++ b/branches/WOF2-3/inc/kernel/rdma/verbs.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 1996-2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#ifndef _VERBS_H_ +#define _VERBS_H_ + +#include +#include + +static inline USHORT VerbsVersion(UINT8 Major, UINT8 Minor) +{ + return ((USHORT) Major << 8) | ((USHORT) Minor); +} + +static inline UINT8 VerbsVersionMajor(USHORT Version) +{ + return (UINT8) (Version >> 8); +} + +static inline UINT8 VerbsVersionMinor(USHORT Version) +{ + return (UINT8) Version; +} + +DEFINE_GUID(GUID_RDMA_INTERFACE_VERBS, 0xf0ebae86, 0xedb5, 0x4b40, + 0xa1, 0xa, 0x44, 0xd5, 0xdb, 0x3b, 0x96, 0x4e); + +typedef struct _RDMA_INTERFACE_VERBS +{ + INTERFACE InterfaceHeader; + ci_interface_t Verbs; + +} RDMA_INTERFACE_VERBS; + +#endif // _VERBS_H_ diff --git a/branches/WOF2-3/inc/kernel/shutter.h b/branches/WOF2-3/inc/kernel/shutter.h new file mode 100644 index 00000000..2aed1291 --- /dev/null +++ b/branches/WOF2-3/inc/kernel/shutter.h @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: shutter.h 1611 2006-08-20 14:48:55Z sleybo $ + */ + + +#pragma once + + +// Define the max numbers of operations that can be simultaniously done +#define MAX_OPERATIONS 0x10000000 + +typedef struct _shutter_t { + long cnt; + KEVENT event; + +} shutter_t; + +static inline void shutter_init(shutter_t* p_shutter) +{ + p_shutter->cnt = 0; + KeInitializeEvent( &p_shutter->event, SynchronizationEvent, FALSE ); +} + + +static inline void shutter_sub(shutter_t * p_shutter,long Val) +{ + long res = 0; + ASSERT(Val < 0); + res = InterlockedExchangeAdd( &p_shutter->cnt,Val ); + if ((res+Val) == -MAX_OPERATIONS) + KeSetEvent( &p_shutter->event, 0, FALSE ); +} + +// if RC == true, one can proceed +static inline BOOLEAN shutter_add(shutter_t * p_shutter,long Val) +{ + long res = 0; + ASSERT(Val > 0); + res = InterlockedExchangeAdd(&p_shutter->cnt,Val); + ASSERT(res <= MAX_OPERATIONS); + if (res < 0 ) + { + shutter_sub(p_shutter, -Val); + return FALSE; + } + return TRUE; +} + +static inline void shutter_loose(shutter_t * p_shutter) +{ + long res = InterlockedDecrement( &p_shutter->cnt ); + if (res == -MAX_OPERATIONS) + KeSetEvent( &p_shutter->event, 0, FALSE ); +} + +// if RC > 0, one can proceed +static inline int shutter_use(shutter_t * p_shutter) +{ + long res = InterlockedIncrement( &p_shutter->cnt ); + ASSERT(res <= MAX_OPERATIONS); + if (res <= 0 ) + shutter_loose( p_shutter ); // The object is in shutdown + return res; +} + + +static inline void shutter_shut(shutter_t * p_shutter) +{ + long res = 0; + // + // ASSERT not calling shu twice. + // + ASSERT(p_shutter->cnt - MAX_OPERATIONS >= (-MAX_OPERATIONS)); + + // Mark the counter as locked + res = InterlockedExchangeAdd(&p_shutter->cnt, -MAX_OPERATIONS); + ASSERT(res >= 0); + if (res) + // We are now waiting for the object to reach -MAX_OPERATIONS + KeWaitForSingleObject( &p_shutter->event, Executive, KernelMode, FALSE, NULL ); +} + +static inline void shutter_alive(shutter_t * p_shutter) +{ + long res = 0; + + // Mark the counter as alive + res = InterlockedExchangeAdd(&p_shutter->cnt, MAX_OPERATIONS); + ASSERT(res < 0); +} + + diff --git a/branches/WOF2-3/inc/kernel/work_queue.h b/branches/WOF2-3/inc/kernel/work_queue.h new file mode 100644 index 00000000..8873442f --- /dev/null +++ b/branches/WOF2-3/inc/kernel/work_queue.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#ifndef _WORK_QUEUE_H_ +#define _WORK_QUEUE_H_ + +#include + +// Allow overlaying across IRP.Tail.Overlay.DriverContext +typedef struct _WORK_ENTRY +{ + LIST_ENTRY Entry; + void (*WorkHandler)(struct _WORK_ENTRY *Work); + void *Context; + +} WORK_ENTRY; + +static void WorkEntryInit(WORK_ENTRY *pWork, + void (*WorkHandler)(struct _WORK_ENTRY *Work), void *Context) +{ + pWork->WorkHandler = WorkHandler; + pWork->Context = Context; +} + +#define WorkEntryFromIrp(pIrp) ((WORK_ENTRY *) (pIrp)->Tail.Overlay.DriverContext) + +struct _WORK_QUEUE_TASK; + +typedef struct _WORK_QUEUE +{ + LIST_ENTRY List; + KSPIN_LOCK Lock; + int TaskCount; + struct _WORK_QUEUE_TASK *TaskArray; // TaskArray[0] is for internal use + +} WORK_QUEUE; + +NTSTATUS WorkQueueInit(WORK_QUEUE *pWorkQueue, PDEVICE_OBJECT Device, + int TaskCount); +void WorkQueueDestroy(WORK_QUEUE *pWorkQueue); +void WorkQueueInsert(WORK_QUEUE *pWorkQueue, WORK_ENTRY *pWork); + +#endif // _WORK_QUEUE_H_ diff --git a/branches/WOF2-3/inc/mod_ver.def b/branches/WOF2-3/inc/mod_ver.def new file mode 100644 index 00000000..1d4ff65e --- /dev/null +++ b/branches/WOF2-3/inc/mod_ver.def @@ -0,0 +1,20 @@ + +# Define Major and Minor numbers for the current module build. +# This file is included by openib.def & various makefile.inc so as to define +# major & minor #'s in a single location. +# +# Major & Minor definitions can be defined in a local SOURCES file +# which will override these definitions. + +!IF !DEFINED(IB_MAJORVERSION) +IB_MAJORVERSION=2 +!ENDIF + +!IF !DEFINED(IB_MINORVERSION) +IB_MINORVERSION=1 +!ENDIF + +# unused build version field +!IF !DEFINED(IB_BUILDVERSION) +IB_BUILDVERSION=0 +!ENDIF diff --git a/branches/WOF2-3/inc/mthca/mthca_vc.h b/branches/WOF2-3/inc/mthca/mthca_vc.h new file mode 100644 index 00000000..f2059b95 --- /dev/null +++ b/branches/WOF2-3/inc/mthca/mthca_vc.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2004-2005 Mellanox Technologies, Inc. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#ifndef MTHCA_VC_H +#define MTHCA_VC_H + +#define PTR_ALIGN(size) (((size) + sizeof(void*) - 1) & ~(sizeof(void*) - 1)) + +typedef +struct _map_crspace { + unsigned __int64 va; /* address of CRSPACE, mapped to user space */ + unsigned long size; /* size of CRSPACE, mapped to user space */ + unsigned long reserved; /* to align on quadword boundary */ +} map_crspace; + +/* Definitions for hca_driver commands*/ +#define FW_READ 0x00 +#define FW_WRITE 0x01 +#define FW_READ_CMD 0x08 +#define FW_WRITE_CMD 0x09 +#define FW_MAP_CRSPACE 0x0A +#define FW_UNMAP_CRSPACE 0x0B +#define FW_OPEN_IF 0xe7 +#define FW_CLOSE_IF 0x7e + +struct msix_info { + int valid; + int enabled; + int masked; + int requested; + int granted; + unsigned granted_mask; + unsigned pending_mask; +} ; + +/* uplink info */ +typedef struct { + uint8_t bus_type; /* 1 - PCI, 2 - PCI-X, 3 - PCI_E */ +#define UPLINK_BUS_PCI 1 +#define UPLINK_BUS_PCIX 2 +#define UPLINK_BUS_PCIE 3 + union { + struct { + uint8_t capabilities; +#define UPLINK_BUS_PCIX_133 2 /* 133 MHz capable */ + uint16_t frequency; /* in MHz */ + } pci_x; + struct { + uint8_t capabilities; + uint8_t link_speed; /* 1X link speed */ +#define UPLINK_BUS_PCIE_SDR 1 /* 2.5 Gbps */ +#define UPLINK_BUS_PCIE_DDR 2 /* 5 Gbps */ + uint8_t link_width; /* x1, x2, x4, x8, x12, x16, x32 */ + } pci_e; + } u; + struct msix_info x; +} uplink_info_t; + +/* Defines for get data for vendor specific */ +#define MTHCA_BRD_ID_LEN 64 + +inline char* mthca_get_board_id(ib_ca_attr_t *ca_attr) +{ + return (char*)(ca_attr) + (ca_attr->size - PTR_ALIGN(MTHCA_BRD_ID_LEN) - PTR_ALIGN(sizeof(uplink_info_t))); +} + +inline void* mthca_get_uplink_info(ib_ca_attr_t *ca_attr) +{ + return (char*)(ca_attr) + (ca_attr->size - PTR_ALIGN(sizeof(uplink_info_t))); +} + +#endif diff --git a/branches/WOF2-3/inc/oib_ver.h b/branches/WOF2-3/inc/oib_ver.h new file mode 100644 index 00000000..5af45565 --- /dev/null +++ b/branches/WOF2-3/inc/oib_ver.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include +#include + +#if (VER_FILEBUILD < 10) +#define VER_FILEBPAD "000" +#elif (VER_FILEBUILD < 100) +#define VER_FILEBPAD "00" +#elif (VER_FILEBUILD < 1000) +#define VER_FILEBPAD "0" +#else +#define VER_FILEBPAD +#endif + +#define VER_FILEVERSION VER_FILEMAJORVERSION,\ + VER_FILEMINORVERSION,\ + VER_FILEBUILD,\ + VER_FILEREV + +#define VER_FILEVERSION_STR2(M,m,b,r) #M "." #m "." VER_FILEBPAD #b "." #r +#define VER_FILEVERSION_STR1(M,m,b,r) VER_FILEVERSION_STR2(M,m,b,r) +#define VER_FILEVERSION_STR VER_FILEVERSION_STR1( VER_FILEMAJORVERSION, \ + VER_FILEMINORVERSION, \ + VER_FILEBUILD, \ + VER_FILEREV ) + +#undef __BUILDMACHINE__ + +#ifdef VER_COMPANYNAME_STR +#undef VER_COMPANYNAME_STR +#endif +#define VER_COMPANYNAME_STR IB_COMPANYNAME + +#ifdef VER_PRODUCTNAME_STR +#undef VER_PRODUCTNAME_STR +#endif +#define VER_PRODUCTNAME_STR IB_PRODUCTNAME + +#define VER_LEGALCOPYRIGHT_STR "Copyright\xa9 2008 OpenFabrics Alliance" diff --git a/branches/WOF2-3/inc/openib.def b/branches/WOF2-3/inc/openib.def new file mode 100644 index 00000000..9e606bb2 --- /dev/null +++ b/branches/WOF2-3/inc/openib.def @@ -0,0 +1,31 @@ + +!INCLUDE $(NTMAKEENV)\makefile.def + +# Allow overriding the company name. +!IF !DEFINED(IB_COMPANYNAME) +IB_COMPANYNAME="""OpenFabrics\40Alliance""" +!ENDIF + +# Allow overriding the product name. +!IF !DEFINED(IB_PRODUCTNAME) +IB_PRODUCTNAME="""OpenFabrics\x20Windows""" +!ENDIF + +# get module version: major, minor & build version +!include mod_ver.def + +!IF !DEFINED(OPENIB_REV) +OPENIB_REV=0 +!ENDIF + +!IFNDEF VER_PROVIDER +VER_PROVIDER="""OpenFabrics""" +!ENDIF + +C_DEFINES=$(C_DEFINES) -DIB_COMPANYNAME=$(IB_COMPANYNAME) \ + -DIB_PRODUCTNAME=$(IB_PRODUCTNAME) \ + -DVER_FILEMAJORVERSION=$(IB_MAJORVERSION) \ + -DVER_FILEMINORVERSION=$(IB_MINORVERSION) \ + -DVER_FILEBUILD=$(IB_BUILDVERSION) \ + -DVER_FILEREV=$(OPENIB_REV) \ + -DVER_PROVIDER=$(VER_PROVIDER) diff --git a/branches/WOF2-3/inc/user/comp_channel.h b/branches/WOF2-3/inc/user/comp_channel.h new file mode 100644 index 00000000..d00d4df5 --- /dev/null +++ b/branches/WOF2-3/inc/user/comp_channel.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2009 Intel Corp., Inc. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#ifndef COMP_CHANNEL_H +#define COMP_CHANNEL_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _COMP_ENTRY +{ + struct _COMP_ENTRY *Next; + OVERLAPPED Overlap; + struct _COMP_CHANNEL *Channel; + LONG volatile Busy; + +} COMP_ENTRY; + +typedef struct _COMP_CHANNEL +{ + struct _COMP_MANAGER *Manager; + struct _COMP_CHANNEL *Next; + struct _COMP_SET *Set; + COMP_ENTRY *Head; + COMP_ENTRY **TailPtr; + COMP_ENTRY Entry; + HANDLE Event; + CRITICAL_SECTION Lock; + DWORD Milliseconds; + +} COMP_CHANNEL; + +typedef struct _COMP_SET +{ + COMP_CHANNEL *Head; + COMP_CHANNEL **TailPtr; + HANDLE Event; + +} COMP_SET; + +typedef struct _COMP_MANAGER +{ + HANDLE CompQueue; + HANDLE Thread; + BOOL Run; + +} COMP_MANAGER; + +DWORD CompManagerOpen(COMP_MANAGER *pMgr); +void CompManagerClose(COMP_MANAGER *pMgr); +DWORD CompManagerMonitor(COMP_MANAGER *pMgr, HANDLE hFile, ULONG_PTR Key); + +DWORD CompSetInit(COMP_SET *pSet); +void CompSetCleanup(COMP_SET *pSet); +void CompSetZero(COMP_SET *pSet); +void CompSetAdd(COMP_CHANNEL *pChannel, COMP_SET *pSet); +DWORD CompSetPoll(COMP_SET *pSet, DWORD Milliseconds); +void CompSetCancel(COMP_SET *pSet); + +DWORD CompChannelInit(COMP_MANAGER *pMgr, COMP_CHANNEL *pChannel, + DWORD Milliseconds); +void CompChannelCleanup(COMP_CHANNEL *pChannel); +DWORD CompChannelPoll(COMP_CHANNEL *pChannel, COMP_ENTRY **ppEntry); +void CompChannelCancel(COMP_CHANNEL *pChannel); + +void CompEntryInit(COMP_CHANNEL *pChannel, COMP_ENTRY *pEntry); +DWORD CompEntryPost(COMP_ENTRY *pEntry); +COMP_ENTRY *CompEntryCancel(COMP_ENTRY *pEntry); + +#ifdef __cplusplus +} +#endif + +#endif /* COMP_CHANNEL_H */ diff --git a/branches/WOF2-3/inc/user/complib/cl_atomic_osd.h b/branches/WOF2-3/inc/user/complib/cl_atomic_osd.h new file mode 100644 index 00000000..062177d8 --- /dev/null +++ b/branches/WOF2-3/inc/user/complib/cl_atomic_osd.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + + +#ifndef _CL_ATOMIC_OSD_H_ +#define _CL_ATOMIC_OSD_H_ + + +#include "cl_types.h" + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +CL_INLINE int32_t CL_API +cl_atomic_inc( + IN atomic32_t* const p_value ) +{ + return( InterlockedIncrement( (LONG*)p_value ) ); +} + + +CL_INLINE int32_t CL_API +cl_atomic_dec( + IN atomic32_t* const p_value ) +{ + return( InterlockedDecrement( (LONG*)p_value ) ); +} + + +CL_INLINE int32_t CL_API +cl_atomic_add( + IN atomic32_t* const p_value, + IN const int32_t increment ) +{ + /* Return the incremented value. */ + return( InterlockedExchangeAdd( (long*)p_value, increment ) + increment ); +} + + +CL_INLINE int32_t CL_API +cl_atomic_sub( + IN atomic32_t* const p_value, + IN const int32_t decrement ) +{ + /* Return the decremented value. */ + return( InterlockedExchangeAdd( (long*)p_value, -decrement ) - decrement ); +} + + +CL_INLINE int32_t CL_API +cl_atomic_xchg( + IN atomic32_t* const p_value, + IN const int32_t new_value ) +{ + return( InterlockedExchange( (long*)p_value, new_value ) ); +} + + +CL_INLINE int32_t CL_API +cl_atomic_comp_xchg( + IN atomic32_t* const p_value, + IN const int32_t compare, + IN const int32_t new_value ) +{ + return( InterlockedCompareExchange( (long*)p_value, new_value, compare ) ); +} + + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _CL_ATOMIC_OSD_H_ diff --git a/branches/WOF2-3/inc/user/complib/cl_byteswap_osd.h b/branches/WOF2-3/inc/user/complib/cl_byteswap_osd.h new file mode 100644 index 00000000..3f20c6da --- /dev/null +++ b/branches/WOF2-3/inc/user/complib/cl_byteswap_osd.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + +#ifndef _CL_BYTESWAP_OSD_H_ +#define _CL_BYTESWAP_OSD_H_ + + +#include "complib/cl_types.h" +#include + + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define CPU_LE 1 +#define CPU_BE 0 + +#define cl_ntoh16 _byteswap_ushort +#define cl_hton16 _byteswap_ushort + +#define cl_ntoh32 _byteswap_ulong +#define cl_hton32 _byteswap_ulong + +#define cl_ntoh64 _byteswap_uint64 +#define cl_hton64 _byteswap_uint64 + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _CL_BYTESWAP_OSD_H_ + + + + + diff --git a/branches/WOF2-3/inc/user/complib/cl_debug_osd.h b/branches/WOF2-3/inc/user/complib/cl_debug_osd.h new file mode 100644 index 00000000..3bf6208d --- /dev/null +++ b/branches/WOF2-3/inc/user/complib/cl_debug_osd.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#ifndef _CL_DEBUG_OSD_H_ +#define _CL_DEBUG_OSD_H_ + + +#include "cl_types.h" +#include +#include + + +#if !defined(__MODULE__) +#define __MODULE__ "" +#define __MOD_DELIMITER__ "" +#else /* !defined(__MODULE__) */ +#define __MOD_DELIMITER__ ":" +#endif /* !defined(__MODULE__) */ + + +#if defined( _WIN64 ) +#define PRIdSIZE_T "I64d" +#else +#define PRIdSIZE_T "d" +#endif +#define PRId64 "I64d" +#define PRIx64 "I64x" +#define PRIo64 "I64o" +#define PRIu64 "I64u" + + +#if defined( _DEBUG_ ) +#define cl_dbg_out cl_msg_out +#else +#define cl_dbg_out __noop +#endif /* defined( _DEBUG_ ) */ + + +/* + * The following macros are used internally by the CL_ENTER, CL_TRACE, + * CL_TRACE_EXIT, and CL_EXIT macros. + */ +#define _CL_DBG_ENTER \ + ("0x%x:%s%s%s() [\n", GetCurrentThreadId(), __MODULE__, __MOD_DELIMITER__, __FUNCTION__) + +#define _CL_DBG_EXIT \ + ("0x%x:%s%s%s() ]\n", GetCurrentThreadId(), __MODULE__, __MOD_DELIMITER__, __FUNCTION__) + +#define _CL_DBG_INFO \ + ("0x%x:%s%s%s(): ", GetCurrentThreadId(), __MODULE__, __MOD_DELIMITER__, __FUNCTION__) + +#define _CL_DBG_ERROR \ + ("0x%x:%s%s%s() !ERROR!: ", GetCurrentThreadId(), __MODULE__, __MOD_DELIMITER__, __FUNCTION__) + +#define CL_CHK_STK + +#endif /* _CL_DEBUG_OSD_H_ */ + diff --git a/branches/WOF2-3/inc/user/complib/cl_event_osd.h b/branches/WOF2-3/inc/user/complib/cl_event_osd.h new file mode 100644 index 00000000..44fad4ba --- /dev/null +++ b/branches/WOF2-3/inc/user/complib/cl_event_osd.h @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + + +#ifndef _CL_EVENT_OSD_H_ +#define _CL_EVENT_OSD_H_ + + +#include "cl_types.h" + + +/* Simple definition, eh? */ +typedef HANDLE cl_event_t; + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +CL_INLINE void CL_API +cl_event_construct( + IN cl_event_t* const p_event ) +{ + CL_ASSERT( p_event ); + + *p_event = NULL; +} + + +CL_INLINE cl_status_t CL_API +cl_event_init( + IN cl_event_t* const p_event, + IN const boolean_t manual_reset ) +{ + CL_ASSERT( p_event ); + + *p_event = CreateEvent( NULL, manual_reset, FALSE, NULL ); + if( !*p_event ) + return( CL_ERROR ); + + return( CL_SUCCESS ); +} + + +CL_INLINE void CL_API +cl_event_destroy( + IN cl_event_t* const p_event ) +{ + CL_ASSERT( p_event ); + + if( *p_event ) + CloseHandle( *p_event ); +} + + +CL_INLINE cl_status_t CL_API +cl_event_signal( + IN cl_event_t* const p_event ) +{ + CL_ASSERT( p_event ); + CL_ASSERT( *p_event ); + + if( !SetEvent( *p_event ) ) + return( CL_ERROR ); + + return( CL_SUCCESS ); +} + + +CL_INLINE cl_status_t CL_API +cl_event_reset( + IN cl_event_t* const p_event ) +{ + CL_ASSERT( p_event ); + CL_ASSERT( *p_event ); + + if( !ResetEvent( *p_event ) ) + return( CL_ERROR ); + + return( CL_SUCCESS ); +} + + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _CL_EVENT_OSD_H_ \ No newline at end of file diff --git a/branches/WOF2-3/inc/user/complib/cl_ioctl_osd.h b/branches/WOF2-3/inc/user/complib/cl_ioctl_osd.h new file mode 100644 index 00000000..2c5b9e41 --- /dev/null +++ b/branches/WOF2-3/inc/user/complib/cl_ioctl_osd.h @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * Abstract: + * Declaration of IOCTL object + * + * Environment: + * Windows User Mode + */ + + +#ifndef _CL_IOCTL_OSD_H_ +#define _CL_IOCTL_OSD_H_ + + +#include +#pragma warning(push, 3) +#include +#pragma warning(pop) + + +#define IOCTL_CODE( type, cmd ) \ + CTL_CODE( type, (cmd & 0x0FFF), METHOD_BUFFERED, FILE_ANY_ACCESS) + + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + +CL_INLINE cl_status_t CL_API +cl_ioctl_request( + IN void *h_dev, + IN uint32_t ioctl_code, + IN void *p_in_buf, + IN size_t in_size, + OUT void *p_out_buf, + IN size_t out_size, + OUT size_t *p_ret_bytes OPTIONAL, + IN void *p_async_info OPTIONAL ) +{ + DWORD bytes_ret; + + if( !DeviceIoControl( h_dev, ioctl_code, p_in_buf, (DWORD)in_size, + p_out_buf, (DWORD)out_size, &bytes_ret, (LPOVERLAPPED)p_async_info ) ) + { + if( GetLastError() == ERROR_IO_PENDING ) + return CL_PENDING; + else + return CL_ERROR; + } + + *p_ret_bytes = bytes_ret; + return CL_SUCCESS; +} + + +CL_INLINE cl_status_t CL_API +cl_ioctl_result( + IN void *h_dev, + IN void *p_async_info, + OUT size_t *p_ret_bytes, + IN boolean_t blocking ) +{ + DWORD bytes_ret; + + if( !GetOverlappedResult( + h_dev, (LPOVERLAPPED)p_async_info, &bytes_ret, blocking ) ) + { + if( GetLastError() == ERROR_IO_INCOMPLETE ) + return CL_NOT_DONE; + else + return CL_ERROR; + } + + *p_ret_bytes = bytes_ret; + return CL_SUCCESS; +} + + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif // _CL_IOCTL_OSD_H_ diff --git a/branches/WOF2-3/inc/user/complib/cl_memory_osd.h b/branches/WOF2-3/inc/user/complib/cl_memory_osd.h new file mode 100644 index 00000000..f3cc5db3 --- /dev/null +++ b/branches/WOF2-3/inc/user/complib/cl_memory_osd.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * Abstract: + * Defines platform specific memory related functions. + * + * Environment: + * Windows User Mode + */ + + +#ifndef _CL_MEMORY_OSD_H_ +#define _CL_MEMORY_OSD_H_ + + +#include + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +CL_INLINE void CL_API +cl_memset( + IN void* const p_memory, + IN const uint8_t fill, + IN const size_t count ) +{ + RtlFillMemory( p_memory, count, fill ); +} + + +CL_INLINE void* CL_API +cl_memcpy( + IN void* const p_dest, + IN const void* const p_src, + IN const size_t count ) +{ + RtlCopyMemory( p_dest, p_src, count ); + return p_dest; +} + + +CL_INLINE int32_t CL_API +cl_memcmp( + IN const void* const p_memory1, + IN const void* const p_memory2, + IN const size_t count ) +{ + return( memcmp( p_memory1, p_memory2, count ) ); +} + + +#define _CL_MEMCLR_DEFINED_ +CL_INLINE void CL_API +cl_memclr( + IN void* const p_memory, + IN const size_t count ) +{ + RtlSecureZeroMemory( p_memory, count ); +} + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* _CL_MEMORY_OSD_H_ */ + diff --git a/branches/WOF2-3/inc/user/complib/cl_mutex_osd.h b/branches/WOF2-3/inc/user/complib/cl_mutex_osd.h new file mode 100644 index 00000000..4fd9415f --- /dev/null +++ b/branches/WOF2-3/inc/user/complib/cl_mutex_osd.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * Abstract: + * Declaration of mutex object. + * + * Environment: + * Windows User Mode + */ + + +#ifndef _CL_MUTEX_OSD_H_ +#define _CL_MUTEX_OSD_H_ + + +#include + + +typedef HANDLE cl_mutex_t; + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +CL_INLINE void CL_API +cl_mutex_construct( + IN cl_mutex_t* const p_mutex ) +{ + *p_mutex = NULL; +} + + +CL_INLINE cl_status_t CL_API +cl_mutex_init( + IN cl_mutex_t* const p_mutex ) +{ + *p_mutex = CreateMutex( NULL, FALSE, NULL ); + if( *p_mutex ) + return CL_SUCCESS; + else + return CL_ERROR; +} + + +CL_INLINE void CL_API +cl_mutex_destroy( + IN cl_mutex_t* const p_mutex ) +{ + CloseHandle( *p_mutex ); +} + + +CL_INLINE void CL_API +cl_mutex_acquire( + IN cl_mutex_t* const p_mutex ) +{ + WaitForSingleObject( *p_mutex, INFINITE ); +} + + +CL_INLINE void CL_API +cl_mutex_release( + IN cl_mutex_t* const p_mutex ) +{ + ReleaseMutex( *p_mutex ); +} + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* _CL_MUTEX_OSD_H_ */ diff --git a/branches/WOF2-3/inc/user/complib/cl_packoff.h b/branches/WOF2-3/inc/user/complib/cl_packoff.h new file mode 100644 index 00000000..2117feb7 --- /dev/null +++ b/branches/WOF2-3/inc/user/complib/cl_packoff.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + + +/* Note: The lack of conditional inclusion is intentional. */ +#include diff --git a/branches/WOF2-3/inc/user/complib/cl_packon.h b/branches/WOF2-3/inc/user/complib/cl_packon.h new file mode 100644 index 00000000..648b239e --- /dev/null +++ b/branches/WOF2-3/inc/user/complib/cl_packon.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + + +/* Note: The lack of conditional inclusion is intentional. */ +#include + + +/* + * 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. + * + * Note: + * No Robodoc documentation as with other headers. + */ + +#ifndef PACK_SUFFIX +#define PACK_SUFFIX +#endif diff --git a/branches/WOF2-3/inc/user/complib/cl_spinlock_osd.h b/branches/WOF2-3/inc/user/complib/cl_spinlock_osd.h new file mode 100644 index 00000000..eb07caed --- /dev/null +++ b/branches/WOF2-3/inc/user/complib/cl_spinlock_osd.h @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + + +#ifndef _CL_SPINLOCK_OSD_H_ +#define _CL_SPINLOCK_OSD_H_ + + +#include "cl_types.h" + + +/* Spinlock object definition. */ +typedef struct _cl_spinlock +{ + CRITICAL_SECTION crit_sec; + /* The flag is necessary to conditionally destroy the critical section. */ + boolean_t initialized; + +} cl_spinlock_t; + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +CL_INLINE void CL_API +cl_spinlock_construct( + IN cl_spinlock_t* const p_spinlock ) +{ + p_spinlock->initialized = FALSE; +} + + +CL_INLINE cl_status_t CL_API +cl_spinlock_init( + IN cl_spinlock_t* const p_spinlock ) +{ + CL_ASSERT( p_spinlock ); + + cl_spinlock_construct( p_spinlock ); + + /* + * Documentation recommends a spin count ~4K. + * High bit set to force pre-allocation of event. + */ + if( !InitializeCriticalSectionAndSpinCount( + &p_spinlock->crit_sec, 0x80001000 ) ) + { + return( CL_ERROR ); + } + + p_spinlock->initialized = TRUE; + return( CL_SUCCESS ); +} + + +CL_INLINE void CL_API +cl_spinlock_destroy( + IN cl_spinlock_t* const p_spinlock ) +{ + CL_ASSERT( p_spinlock ); + + if( p_spinlock->initialized ) + { + p_spinlock->initialized = FALSE; + DeleteCriticalSection( &p_spinlock->crit_sec ); + } +} + + +CL_INLINE void CL_API +cl_spinlock_acquire( + IN cl_spinlock_t* const p_spinlock ) +{ + CL_ASSERT( p_spinlock && p_spinlock->initialized ); + + EnterCriticalSection( &p_spinlock->crit_sec ); +} + + +CL_INLINE void CL_API +cl_spinlock_release( + IN cl_spinlock_t* const p_spinlock ) +{ + CL_ASSERT( p_spinlock && p_spinlock->initialized ); + + LeaveCriticalSection( &p_spinlock->crit_sec ); +} + + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _CL_SPINLOCK_OSD_H_ diff --git a/branches/WOF2-3/inc/user/complib/cl_syscallback_osd.h b/branches/WOF2-3/inc/user/complib/cl_syscallback_osd.h new file mode 100644 index 00000000..142eaec9 --- /dev/null +++ b/branches/WOF2-3/inc/user/complib/cl_syscallback_osd.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + + +#ifndef _CL_SYS_CALLBACK_OSD_H_ +#define _CL_SYS_CALLBACK_OSD_H_ + + +#include "cl_types.h" + + +typedef struct _cl_sys_callback_item +{ + cl_pfn_sys_callback_t pfn_callback; + const void* get_context; + const void* queue_context; + +} cl_sys_callback_item_t; + + +#endif // _CL_SYS_CALLBACK_OSD_H_ \ No newline at end of file diff --git a/branches/WOF2-3/inc/user/complib/cl_thread_osd.h b/branches/WOF2-3/inc/user/complib/cl_thread_osd.h new file mode 100644 index 00000000..23705ed8 --- /dev/null +++ b/branches/WOF2-3/inc/user/complib/cl_thread_osd.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + + +#ifndef _CL_THREAD_OSD_H_ +#define _CL_THREAD_OSD_H_ + + +#include "cl_types.h" +#include "cl_timer.h" + + +/* OS specific information about the thread. */ +typedef struct _cl_thread_osd +{ + HANDLE h_thread; + DWORD thread_id; + +} cl_thread_osd_t; + + +#ifdef __cplusplus +extern "C" +{ +#endif + +CL_INLINE void CL_API +cl_thread_suspend( + IN const uint32_t pause_ms ) +{ + Sleep( pause_ms ); +} + + +CL_INLINE void CL_API +cl_thread_stall( + IN const uint32_t pause_us ) +{ + uint64_t end_time; + + end_time = cl_get_time_stamp() + pause_us; + + /* Spin. */ + while( cl_get_time_stamp() < end_time ) + ; +} + + +CL_INLINE boolean_t CL_API +cl_is_blockable( void ) +{ + return TRUE; +} + + +#ifdef __cplusplus +} // extern "C" +#endif + + +#endif // _CL_THREAD_OSD_H_ diff --git a/branches/WOF2-3/inc/user/complib/cl_timer_osd.h b/branches/WOF2-3/inc/user/complib/cl_timer_osd.h new file mode 100644 index 00000000..a4a11958 --- /dev/null +++ b/branches/WOF2-3/inc/user/complib/cl_timer_osd.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + + +#ifndef _CL_TIMER_OSD_H_ +#define _CL_TIMER_OSD_H_ + + +#include "cl_types.h" + +typedef struct _cl_timer +{ + HANDLE h_timer; + cl_pfn_timer_callback_t pfn_callback; + const void *context; + uint64_t timeout_time; + CRITICAL_SECTION lock; + CRITICAL_SECTION cb_lock; + +} cl_timer_t; + + +#endif // _CL_TIMER_OSD_H_ \ No newline at end of file diff --git a/branches/WOF2-3/inc/user/complib/cl_types_osd.h b/branches/WOF2-3/inc/user/complib/cl_types_osd.h new file mode 100644 index 00000000..e205de66 --- /dev/null +++ b/branches/WOF2-3/inc/user/complib/cl_types_osd.h @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + + +#ifndef _CL_TYPES_OSD_H_ +#define _CL_TYPES_OSD_H_ + + +#if !defined( WINVER ) + // Enable Windows 2000 features. + #define _WIN32_WINNT 0x0500 + #define WINVER 0x0500 +#else // !defined( WINVER ) + #if(WINVER < 0x0500) + // Force a compile error. + #error The component library requires Windows 2000 features. \ + WINVER and _WIN32_WINNT must be set to 0x0500 or greater. + #elif !defined(_WIN32_WINNT) + #define _WIN32_WINNT WINVER + #endif +#endif // !defined( WINVER ) + +#if _WIN32_WINNT != WINVER && _WIN32_WINNT != 0x0500 && WINVER != 0x501 + #error _WIN32_WINNT does not match WINVER. +#endif // _WIN32_WINNT != WINVER + +#if !defined( _WINDOWS_ ) + // Include the windows header file. + #include +#endif // !defined( _WINDOWS_ ) + +/* + * Enable warnings about pointer sign extension. + */ +#pragma warning( default:4826 ) + +#if defined( _DEBUG ) || DBG + #define _DEBUG_ +#else + #undef _DEBUG_ +#endif + +#ifdef __GNUC__ + +#include +typedef intptr_t intn_t; +typedef uintptr_t uintn_t; +typedef volatile uint32_t atomic32_t; + +#else /* __GNUC__ */ + +typedef __int8 int8_t; +typedef unsigned __int8 uint8_t; +typedef __int16 int16_t; +typedef unsigned __int16 uint16_t; +typedef __int32 int32_t; +typedef unsigned __int32 uint32_t; +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +typedef unsigned char uchar_t; +typedef _W64 __int3264 intn_t; +typedef _W64 unsigned __int3264 uintn_t; +typedef volatile __int32 atomic32_t; + +#endif /* __GNUC__ */ + +/* boolean_t must be intergral sized to avoid a bunch of warnings. */ +typedef int boolean_t; + +#ifdef _PREFAST_ +#define CONDITION_ASSUMED(X) __analysis_assume((X)) +#else +#define CONDITION_ASSUMED(X) +#endif // _PREFAST_ + +#ifndef CL_ASSERT +#ifdef _DEBUG_ +#define CL_ASSERT( exp ) (void)(!(exp)?OutputDebugString("Assertion Failed:" #exp "\n"),DebugBreak(),FALSE:TRUE);CONDITION_ASSUMED(exp) +#else +#define CL_ASSERT( exp ) +#endif /* _DEBUG_ */ +#endif /* CL_ASSERT */ + + +#define UNUSED_PARAM UNREFERENCED_PARAMETER +#if defined(EVENT_TRACING) +#define UNUSED_PARAM_WOWPP(a) +#else +#define UNUSED_PARAM_WOWPP(a)UNREFERENCED_PARAMETER(a) +#endif + +#if !defined(EXPORT_CL_SYMBOLS) +#define CL_EXPORT DECLSPEC_IMPORT +#else +#define CL_EXPORT __declspec(dllexport) +#endif + +#if !defined( __cplusplus ) +#define inline __inline +#endif + +#define CL_INLINE CL_EXPORT inline + +#define CL_API __stdcall + +#define cl_panic abort + +#ifndef offsetof +#define offsetof FIELD_OFFSET +#endif + +#define PARENT_STRUCT( P, T, M ) CONTAINING_RECORD( (void*)P, T, M ) + +#ifdef __GNUC__ +#define CL_CONST64( x ) x##LLU +#else +#define CL_CONST64( x ) x##ui64 +#endif + + +#if !defined( __cplusplus ) +#define inline __inline +#endif + + +#endif // _CL_TYPES_OSD_H_ diff --git a/branches/WOF2-3/inc/user/complib/cl_waitobj_osd.h b/branches/WOF2-3/inc/user/complib/cl_waitobj_osd.h new file mode 100644 index 00000000..b9f4eee8 --- /dev/null +++ b/branches/WOF2-3/inc/user/complib/cl_waitobj_osd.h @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + + +#ifndef _CL_WAITOBJ_OSD_H_ +#define _CL_WAITOBJ_OSD_H_ + + +#include +#include + +typedef cl_event_t cl_waitobj_handle_t; + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + +CL_INLINE cl_status_t CL_API +cl_waitobj_create( + IN const boolean_t manual_reset, + OUT cl_waitobj_handle_t* const ph_wait_obj ) +{ + cl_event_construct( ph_wait_obj ); + return cl_event_init( ph_wait_obj, manual_reset ); +} + + +CL_INLINE cl_status_t CL_API +cl_waitobj_destroy( + IN cl_waitobj_handle_t h_wait_obj ) +{ + /* + * Note that we can take the address of the function parameter *only* + * because the wait object (and cl_event_t) is just a HANDLE, so + * copying it works. + */ + cl_event_destroy( &h_wait_obj ); + return CL_SUCCESS; +} + + +CL_INLINE cl_status_t CL_API +cl_waitobj_signal( + IN cl_waitobj_handle_t h_wait_obj ) +{ + /* + * Note that we can take the address of the function parameter *only* + * because the wait object (and cl_event_t) is just a HANDLE, so + * copying it works. + */ + return cl_event_signal( &h_wait_obj ); +} + + +CL_INLINE cl_status_t CL_API +cl_waitobj_reset( + IN cl_waitobj_handle_t h_wait_obj ) +{ + /* + * Note that we can take the address of the function parameter *only* + * because the wait object (and cl_event_t) is just a HANDLE, so + * copying it works. + */ + return cl_event_reset( &h_wait_obj ); +} + + +CL_INLINE cl_status_t CL_API +cl_waitobj_wait_on( + IN cl_waitobj_handle_t h_wait_obj, + IN const uint32_t wait_us, + IN const boolean_t interruptible ) +{ + /* + * Note that we can take the address of the function parameter *only* + * because the wait object (and cl_event_t) is just a HANDLE, so + * copying it works. + */ + return cl_event_wait_on( &h_wait_obj, wait_us, interruptible ); +} + + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + + +#endif /* _CL_WAITOBJ_OSD_H_ */ diff --git a/branches/WOF2-3/inc/user/dlist.h b/branches/WOF2-3/inc/user/dlist.h new file mode 100644 index 00000000..5cf93042 --- /dev/null +++ b/branches/WOF2-3/inc/user/dlist.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef _DLIST_H_ +#define _DLIST_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _DLIST_ENTRY +{ + struct _DLIST_ENTRY *Next; + struct _DLIST_ENTRY *Prev; + +} DLIST_ENTRY; + +static void DListInit(DLIST_ENTRY *pHead) +{ + pHead->Next = pHead; + pHead->Prev = pHead; +} + +static int DListEmpty(DLIST_ENTRY *pHead) +{ + return pHead->Next == pHead; +} + +static void DListInsertAfter(DLIST_ENTRY *pNew, DLIST_ENTRY *pHead) +{ + pNew->Next = pHead->Next; + pNew->Prev = pHead; + pHead->Next->Prev = pNew; + pHead->Next = pNew; +} + +static void DListInsertBefore(DLIST_ENTRY *pNew, DLIST_ENTRY *pHead) +{ + DListInsertAfter(pNew, pHead->Prev); +} + +#define DListInsertHead DListInsertAfter +#define DListInsertTail DListInsertBefore + +static void DListRemove(DLIST_ENTRY *pEntry) +{ + pEntry->Prev->Next = pEntry->Next; + pEntry->Next->Prev = pEntry->Prev; +} + +#ifdef __cplusplus +} +#endif + +#endif // _DLIST_H_ \ No newline at end of file diff --git a/branches/WOF2-3/inc/user/getopt.h b/branches/WOF2-3/inc/user/getopt.h new file mode 100644 index 00000000..2f2e9a72 --- /dev/null +++ b/branches/WOF2-3/inc/user/getopt.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef _GETOPT_H_ +#define _GETOPT_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +extern char *optarg; +extern int optind; +extern int opterr; +extern int optopt; + +struct option +{ + const char *name; + int has_arg; + int *flag; + int val; +}; + +enum +{ + no_argument, + required_argument, + optional_argument +}; + +extern int getopt(int argc, char * const argv[], char const *opts); +extern int getopt_long(int argc, char * const argv[], char const *opts, + const struct option *longopts, int *longindex); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif diff --git a/branches/WOF2-3/inc/user/iba/ib_uvp.h b/branches/WOF2-3/inc/user/iba/ib_uvp.h new file mode 100644 index 00000000..cc159686 --- /dev/null +++ b/branches/WOF2-3/inc/user/iba/ib_uvp.h @@ -0,0 +1,3492 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#ifndef __IB_UAL_UVP_H__ +#define __IB_UAL_UVP_H__ + +#include +#include +#include +#include + +/****h* UAL_UVP_Interface/user-mode Verbs +* NAME +* User-mode Verbs -- User-mode Verbs implements the HCA specific +* user-mode functions to plug in to the Usermode Access Layer +* Architecture (UAL) +* +* COPYRIGHT +* Copyright© 2001 Intel Corporation - All Rights Reserved. +* DESCRIPTION +* The user-mode Verbs Interface defines the mechanism for a HCA vendor +* to plug into the User-mode Access Layer (UAL) architecture. +* Access Layer API is what is exposed to the user-mode applications. +* The interface described here is not Verbs API. In this interface model, +* UAL provides a generic mechanism to exchange vendor specific info +* in the implementation of verbs within the UAL architecture. UAL provides +* the support for callback processing. For instance, AL provides a +* QP error callback when a qp incurs error. Such asynchronous events are +* handled with the support of UAL and not by the vendor interface described +* here. +* +* For verbs related AL APIs, UAL packages the parameters in an IOCTL +* and sends it to the kernel AL. In the UAL design, this is broken down +* into 3 steps. +* +* a. Pre-ioctl step +* A vendor specified pre-ioctl function is called with relevant input +* parameters including a private buffer template (ci_umv_buf_t) +* for the vendor to communicate with the corresponding HCA driver. +* For calls that does not go to the HCA driver (for e.g. ib_open_ca()) +* no private buffer will be passed. +* b. Sending IOCTL to kernel AL +* Following step (a), UAL prepares an IOCTL with the relevant parameters +* including the vendor's private buffer. UAL/user-mode proxy does not +* interpret the contents of the private buffer. +* UAL sends the IOCTL to the user-mode proxy in kernel. The proxy +* interfaces with kernel AL to act on behalf the user. AL passes the +* parameters to the Verbs Provider Driver and the results are returned +* back to UAL. +* c. Post-ioctl step. +* Following the return from IOCTL in step (b), UAL calls a +* vendor-specified post-ioctl function with relevant parameters. +* UAL will call the post-ioctl function whether or not step (b) +* succeeded. The ioctl itself could have successfully returned but +* a vendor-specific status in ci_umv_buf_t may indicate a failure. +* UAL also passes the ioctl status to the vendor library so that +* the appropriate action can be taken in the post call. +* +* Use of ci_umv_buf_t and pre/post return values +* +* 1. ci_umv_buf is provided by UAL as a unique buffer template for +* a given verbs call. Vendor could keep any info relevant to +* the specific verbs call in this buffer. This buffer is sufficient +* for uniquely identifying which call it is intended for. For instance, +* the umv buffer set up by vendor in a uvp_pre_create_qp() could later +* tell the uvp_post_create_qp_t() which QP it is intended for. +* +* 2. The success of pre/post-ioctl step to UAL means IB_SUCCESS. +* Any value other than IB_SUCCESS is treated as failure. +* +* 3. The Vendor could exchange a status in ci_umv_buf_t. However, this +* interface does not enumerate the status in ci_umv_buf_t. +* However, the vendor could check the status in ci_umv_buf_t +* returned from the pre-ioctl step and act accordingly. +* +* AUTHOR +* Intel Corporation +* CREATION DATE +* XX.XX.XX +* NOTES +* 1. For user mode verbs that require a kernel transition, handles passed +* to kernel are validated in the user-mode proxy running in kernel. +* Those Verbs that are entirely done in user mode that would affect +* speed path do not perform consistency checks. So invalid pointers +* would lead to application crash with core dumps. +* +******* +* +*/ + +/******/ + +/******/ + +/* +* +* Vendor-specific handles +* +*/ + +/****f* user-mode Verbs/unsupported functions +* NAME +* 1. Register physical memory region with HCA (ci_register_pmr) +* 2. Modify physical memory region with HCA (ci_modify_pmr) +* 3. Create Special QP (ci_create_spl_qp) +* +* For all these functions, the vendor does NOT provide support +* and UAL will return IB_UNSUPPORTED to the caller of Access Layer. +* +* SYNOPSIS +*/ + +/********/ + +/****f* user-mode Verbs/uvp_pre_open_ca_t +* NAME +* uvp_pre_open_ca_t -- Pre-ioctl operation for user-mode ib_open_ca() +* +* SYNOPSIS +*/ + +typedef ib_api_status_t +(AL_API *uvp_pre_open_ca_t) ( + IN const ib_net64_t ca_guid, + IN OUT ci_umv_buf_t *p_umv_buf, + OUT ib_ca_handle_t *ph_uvp_ca); + +/* +* DESCRIPTION +* uvp_pre_open_ca_t() is implemented by vendor. It is the pre-ioctl routine +* for the AL call ib_open_ca() in user-mode. +* +* +* PARAMETERS +* ca_guid +* [in] The HCA adapter's EUI64 identifier. Clients would use other +* enumeration API's to locate all available adapters and their +* guids in a system, e.g. GetCaGuids(), maintained by the IB +* Access Layer. +* +* p_umv_buf +* [in out] On input, UAL provides this buffer template. +* On return from this function, p_umv_buf contains any vendor-specific +* record to be exchanged with the vendor's HCA driver. + +* ph_uvp_ca +* [out] (OPTIONAL) Vendor's Handle to the newly opened instance of the CA. +* +* RETURN VALUE +* IB_SUCCESS +* The pre-ioctl function succeeded. +* IB_INSUFFICIENT_RESOURCES +* Insufficient resources to satisfy request. +* IB_INVALID_PARAMETER +* Invalid GUID. +* +* PORTABILITY +* User Mode +* +* SEE ALSO +* uvp_post_open_ca_t, uvp_pre_query_ca, uvp_post_query_ca_t, uvp_pre_modify_ca, +* uvp_post_modify_ca_t, uvp_pre_close_ca_t, uvp_post_close_ca_t +* +*********/ + +/********/ + +/****f* user-mode Verbs/uvp_post_open_ca_t +* NAME +* uvp_post_open_ca_t -- Post-ioctl operation for user-mode ib_open_ca() +* +* SYNOPSIS +*/ + +typedef ib_api_status_t +(AL_API *uvp_post_open_ca_t) ( + IN const ib_net64_t ca_guid, + IN ib_api_status_t ioctl_status, + IN OUT ib_ca_handle_t *ph_uvp_ca, + IN ci_umv_buf_t *p_umv_buf ); +/* +* DESCRIPTION +* uvp_post_open_ca_t() is implemented by vendor. It is the post-ioctl routine +* for the AL call ib_open_ca() in user-mode. +* +* PARAMETERS +* ca_guid +* [in] The HCA adapter's EUI64 identifier. +* ioctl_status +* [in] The ioctl status of the AL API. +* ph_uvp_ca +* [in out] Pointer to vendor's handle to the newly opened instance of +* the CA. If it specified in pre function than it must be the same value here. +* p_umv_buf +* [in] This contains any vendor-specific private information +* exchanged with the vendor's Verbs Provider Driver (uvp_pre_open_ca). +* Vendor is expected to check vendor-specific status in +* umv_buf as appropriate. +* +* RETURN VALUE +* IB_SUCCESS +* The HCA is return handle is valid. +* IB_INSUFFICIENT_RESOURCES +* Insufficient resources to satisfy request. +* +* PORTABILITY +* User Mode +* +* SEE ALSO +* uvp_pre_open_ca_t, uvp_pre_query_ca, uvp_post_query_ca_t, uvp_pre_modify_ca, +* uvp_post_modify_ca_t, uvp_pre_close_ca_t, uvp_post_close_ca_t +* +*********/ + +/********/ + +/****f* user-mode Verbs/uvp_pre_query_ca +* NAME +* uvp_pre_query_ca -- Pre-ioctl operation for user-mode ib_query_ca() +* +* SYNOPSIS +*/ +typedef ib_api_status_t +(AL_API *uvp_pre_query_ca) ( + IN ib_ca_handle_t h_uvp_ca, + IN ib_ca_attr_t *p_ca_attr, + IN size_t byte_count, + IN ci_umv_buf_t *p_umv_buf ); +/* +* DESCRIPTION +* uvp_pre_query_ca() is implemented by vendor. It is the pre-ioctl routine +* for the AL call ib_query_ca() in user-mode. +* +* PARAMETERS +* h_uvp_ca +* [in] Vendor's user-mode library handle to the open instance of the CA +* p_ca_attr +* [in] Pointer to the user's CA attribute buffer. +* byte_count +* [in] User-supplied size of the CA attribute buffer. +* p_umv_buf +* [in out] On input, UAL provides this buffer template. +* On return from this function, p_umv_buf contains any vendor-specific +* record to be exchanged with the vendor's HCA driver. +* +* RETURN VALUE +* IB_SUCCESS +* The pre-ioctl function succeeded. +* IB_INVALID_CA_HANDLE +* CA handle is invalid +* IB_INSUFFICIENT_RESOURCES +* Insufficient resources to satisfy request. +* +* PORTABILITY +* User Mode +* +* SEE ALSO +* uvp_pre_open_ca_t, uvp_post_open_ca_t, uvp_post_query_ca_t, uvp_pre_modify_ca, +* uvp_post_modify_ca_t, uvp_pre_close_ca_t, uvp_post_close_ca_t +* +*********/ + +/********/ + +/****f* user-mode Verbs/uvp_post_query_ca_t +* NAME +* uvp_post_query_ca_t -- Post-ioctl operation for user-mode ib_query_ca() +* +* SYNOPSIS +*/ + +typedef void +(AL_API *uvp_post_query_ca_t) ( + IN ib_ca_handle_t h_uvp_ca, + IN ib_api_status_t ioctl_status, + IN ib_ca_attr_t *p_ca_attr, + IN size_t byte_count, + IN ci_umv_buf_t *p_umv_buf ); +/* +* DESCRIPTION +* uvp_post_query_ca_t() is implemented by vendor. It is the post-ioctl routine +* for the AL call ib_query_ca() in user-mode. UAL provides the results +* of querying the CA attributes to the vendor's post-ioctl routine. +* +* PARAMETERS +* h_uvp_ca +* [in] Vendor's user-mode library handle to the open instance of the CA +* ioctl_status +* [in] The ioctl status of the AL API. +* p_ca_attr +* [in] CA attribute of this Host Channel adapter (as returned by +* from ioctl to kernel AL). +* byte_count +* [in] Number of bytes in ca_attr buffer. +* p_umv_buf +* [in ] This contains any vendor-specific private information +* exchanged with the vendor's Verbs Provider Driver (uvp_pre_query_ca). +* Vendor is expected to check vendor-specific status in +* umv_buf as appropriate. +* +* RETURN VALUE +* This function does not return a value. +* +* PORTABILITY +* User Mode +* +* SEE ALSO +* uvp_pre_open_ca_t, uvp_post_open_ca_t, uvp_pre_query_ca, uvp_pre_modify_ca, +* uvp_post_modify_ca_t, uvp_pre_close_ca_t, uvp_post_close_ca_t +* +*********/ + +/********/ + +/****f* user-mode Verbs/uvp_pre_modify_ca +* NAME +* uvp_pre_modify_ca -- Pre-ioctl operation for user-mode ib_modify_ca() +* +* SYNOPSIS +*/ + +typedef ib_api_status_t +(AL_API *uvp_pre_modify_ca) ( + IN ib_ca_handle_t h_uvp_ca, + IN uint8_t port_num, + IN ib_ca_mod_t ca_mod, + IN const ib_port_attr_mod_t* const p_port_attr_mod ); + +/* +* DESCRIPTION +* uvp_pre_modify_ca() is implemented by vendor. It is the pre-ioctl routine +* for the AL call ib_modify_ca() in user-mode. +* +* PARAMETERS +* h_uvp_ca +* [in] Vendor's user-mode library handle to the open instance of the CA +* port_num +* [in] An index to the port that is being modified. The port_num matches +* the index of the port as returned through the ib_query_ca call. +* ca_mod +* [in] A mask of the attributes and counters to modify. +* p_port_attr_mod +* [in] A list of the specific port attribute information to modify. For +* the access layer to modify an attribute, its corresponding bit must be +* set in the ca_mod parameter. +* +* RETURN VALUE +* IB_SUCCESS +* The pre-ioctl function succeeded. +* IB_INVALID_CA_HANDLE +* CA handle is invalid. +* IB_INVALID_PARAMETER +* One or more parameters is invalid. +* +* PORTABILITY +* User Mode +* +* SEE ALSO +* uvp_pre_open_ca_t, uvp_post_open_ca_t, uvp_pre_query_ca, uvp_post_query_ca_t, +* uvp_post_modify_ca_t, uvp_pre_close_ca_t, uvp_post_close_ca_t +* +*********/ + +/********/ + +/****f* user-mode Verbs/uvp_post_modify_ca_t +* NAME +* uvp_post_modify_ca_t -- Post-ioctl operation for user-mode ib_modify_ca() +* +* SYNOPSIS +*/ + +typedef void +(AL_API *uvp_post_modify_ca_t) ( + IN ib_ca_handle_t h_uvp_ca, + IN ib_api_status_t ioctl_status ); + +/* +* DESCRIPTION +* uvp_post_modify_ca_t() is implemented by vendor. It is the post-ioctl routine +* for the AL call ib_modify_ca() in user-mode. +* +* PARAMETERS +* h_uvp_ca +* [in] Vendor's user-mode library handle to the open instance of the CA +* ioctl_status +* [in] The ioctl status of the AL API. +* +* RETURN VALUE +* This function does not return a value. +* +* PORTABILITY +* User Mode +* +* SEE ALSO +* uvp_pre_open_ca_t, uvp_post_open_ca_t, uvp_pre_query_ca, uvp_post_query_ca_t, +* uvp_pre_modify_ca, uvp_pre_close_ca_t, uvp_post_close_ca_t +* +*********/ + +/********/ + +/****f* user-mode Verbs/uvp_pre_close_ca_t +* NAME +* uvp_pre_close_ca_t -- Pre-ioctl operation for user-mode ib_close_ca(). +* +* SYNOPSIS +*/ + +typedef ib_api_status_t +(AL_API *uvp_pre_close_ca_t) ( + IN ib_ca_handle_t h_uvp_ca ); + +/* +* DESCRIPTION +* uvp_pre_close_ca_t() is implemented by vendor. It is the pre-ioctl routine +* for the AL call ib_close_ca() in user-mode. +* +* PARAMETERS +* h_uvp_ca +* [in] Vendor's user-mode library handle to the open instance of the CA +* +* RETURN VALUE +* IB_SUCCESS +* Successfully completed the pre-ioctl. +* +* PORTABILITY +* User Mode +* +* SEE ALSO +* uvp_pre_open_ca_t, uvp_post_open_ca_t, uvp_pre_query_ca, uvp_post_query_ca_t, +* uvp_pre_modify_ca, uvp_post_modify_ca_t, uvp_post_close_ca_t +* +*********/ + +/********/ + +/****f* user-mode Verbs/uvp_post_close_ca_t +* NAME +* uvp_post_close_ca_t -- Post-ioctl operation for user-mode ib_close_ca(). +* +* SYNOPSIS +*/ + +typedef ib_api_status_t +(AL_API *uvp_post_close_ca_t) ( + IN ib_ca_handle_t h_uvp_ca, + IN ib_api_status_t ioctl_status ); + +/* +* DESCRIPTION +* uvp_post_close_ca_t() is implemented by vendor. It is the post-ioctl routine +* for the AL call ib_close_ca(). +* UAL calls this function in the context of the asynchronous callback +* from AL notifying the successful destruction of CA. +* +* PARAMETERS +* h_uvp_ca +* [in] Vendor's user-mode library handle to the open instance of the CA +* +* RETURN VALUE +* IB_SUCCESS +* The post-ioctl for ib_close_ca() successfully completed. +* +* PORTABILITY +* User Mode +* +* SEE ALSO +* uvp_pre_open_ca_t, uvp_post_open_ca_t, uvp_pre_query_ca, uvp_post_query_ca_t, +* uvp_pre_modify_ca, uvp_post_modify_ca_t, uvp_pre_close_ca_t +* +*********/ + +/********/ + +/****f* user-mode Verbs/uvp_pre_ci_call +* NAME +* uvp_pre_ci_call -- Pre-ioctl function to ib_ci_call +* +* SYNOPSIS +*/ + +typedef ib_api_status_t +(AL_API *uvp_pre_ci_call) ( + IN const ib_ca_handle_t h_uvp_ca, + IN const void** const handle_array OPTIONAL, + IN uint32_t num_handles, + IN ib_ci_op_t* const p_ci_op, + IN OUT ci_umv_buf_t *p_umv_buf); +/* +* DESCRIPTION +* uvp_pre_ci_call() is implemented by vendor. It is the pre-ioctl +* routine for ib_ci_call(). +* +* PARAMETERS +* h_uvp_ca +* [in] Vendor's user-mode library handle to the CA +* handle_array +* [in] An array of uvp handles. For valid types, refer to ib_ci.h or +* ib_al.h. This is an optional parameter. +* num_handles +* [in] The number of handles in the array. +* p_ci_op +* [in] The operation that is requested by the client. For more info, +* refer ib_types.h +* p_umv_buf +* [in out] On input, UAL provides this buffer template. +* On return from this function, p_umv_buf contains +* any vendor-specific record to be exchanged with the vendor's +* HCA driver. +* +* RETURN VALUE +* IB_SUCCESS +* The pre-ioctl is successful. +* IB_INSUFFICIENT_RESOURCES +* Insufficient resources in Vendor library to complete the call +* +* PORTABILITY +* User Mode +* +* SEE ALSO +* uvp_post_ci_call +* +********/ + +/********/ + +/****f* user-mode Verbs/uvp_post_ci_call +* NAME +* uvp_post_ci_call -- Post-ioctl function to ib_ci_call +* +* SYNOPSIS +*/ + +typedef void +(AL_API *uvp_post_ci_call) ( + IN const ib_ca_handle_t h_uvp_ca, + IN ib_api_status_t ioctl_status, + IN const void* * const handle_array OPTIONAL, + IN uint32_t num_handles, + IN ib_ci_op_t* const p_ci_op, + IN OUT ci_umv_buf_t *p_umv_buf); +/* +* DESCRIPTION +* uvp_post_ci_call() is implemented by vendor. It is the pre-ioctl +* routine for ib_ci_call(). +* +* PARAMETERS +* h_uvp_ca +* [in] Vendor's user-mode library handle to the CA +* ioctl_status +* [in] The ioctl status of the AL API. +* handle_array +* [in] An array of uvp handles. For valid types, refer to ib_ci.h or +* ib_al.h. This is an optional parameter. +* num_handles +* [in] The number of handles in the array. +* p_ci_op +* [in] The operation that is requested by the client. For more info, +* refer ib_types.h +* p_umv_buf +* [in out] On input, UAL provides this buffer template. +* On return from this function, p_umv_buf contains +* any vendor-specific record to be exchanged with the vendor's +* HCA driver. +* +* RETURN VALUE +* This function does not return a value. +* +* PORTABILITY +* User Mode +* +* SEE ALSO +* uvp_pre_ci_call +* +********/ + + +/********/ + +/****f* user-mode Verbs/uvp_pre_allocate_pd +* NAME +* uvp_pre_allocate_pd -- Pre-ioctl function to allocate PD +* +* SYNOPSIS +*/ + +typedef ib_api_status_t +(AL_API *uvp_pre_allocate_pd) ( + IN ib_ca_handle_t h_uvp_ca, + IN OUT ci_umv_buf_t *p_umv_buf, + OUT ib_pd_handle_t *ph_uvp_pd); + +/* +* DESCRIPTION +* uvp_pre_allocate_pd() is implemented by vendor. It is the pre-ioctl routine +* for the AL call ib_alloc_pd() in user-mode. +* +* PARAMETERS +* h_uvp_ca +* [in] Vendor's user-mode library handle to the open instance of the CA +* p_umv_buf +* [in out] On input, UAL provides this buffer template. +* On return from this function, p_umv_buf contains +* any vendor-specific record to be exchanged with the vendor's +* HCA driver. +* ph_uvp_pd +* [out] (OPTIONAL) Vendor's Handle to the newly created protection domain. +* +* RETURN VALUE +* IB_SUCCESS +* The pre-ioctl call is successful. +* IB_INVALID_CA_HANDLE +* CA handle is invalid. +* IB_INSUFFICIENT_RESOURCES +* Insufficient resources in Vendor library to complete the call +* +* PORTABILITY +* User Mode +* +* SEE ALSO +* uvp_post_allocate_pd_t, uvp_pre_deallocate_pd, uvp_post_deallocate_pd_t +* +*******/ + +/********/ + +/****f* user-mode Verbs/uvp_post_allocate_pd_t +* NAME +* uvp_post_allocate_pd_t -- Post-ioctl function to allocate PD +* +* SYNOPSIS +*/ + +typedef void +(AL_API *uvp_post_allocate_pd_t) ( + IN ib_ca_handle_t h_uvp_ca, + IN ib_api_status_t ioctl_status, + IN OUT ib_pd_handle_t *ph_uvp_pd, + IN ci_umv_buf_t *p_umv_buf ); + +/* +* DESCRIPTION +* uvp_post_allocate_pd_t() is implemented by vendor. It is the post-ioctl +* routine for the AL call ib_alloc_pd(). +* +* PARAMETERS +* h_uvp_ca +* [in] Vendor's user-mode library CA handle. +* ioctl_status +* [in] The ioctl status of the AL API. +* ph_uvp_pd +* [in out] The vendor library handle to the newly created protection domain. +* If it specified in pre function than it must be the same value here. +* p_umv_buf +* [in] This contains any vendor-specific private information +* exchanged with the vendor's Verbs Provider Driver (uvp_pre_allocate_pd). +* Vendor is expected to check vendor-specific status in +* umv_buf as appropriate. +* +* RETURN VALUE +* This function does not return a value. +* +* PORTABILITY +* User Mode +* +* SEE ALSO +* uvp_pre_allocate_pd, uvp_pre_deallocate_pd, uvp_post_deallocate_pd_t +* +*******/ + +/********/ + +/****f* user-mode Verbs/uvp_pre_deallocate_pd +* NAME +* uvp_pre_deallocate_pd -- Pre-ioctl function to deallocate PD +* +* SYNOPSIS +*/ + +typedef ib_api_status_t +(AL_API *uvp_pre_deallocate_pd) ( + IN const ib_pd_handle_t h_uvp_pd ); + +/* +* DESCRIPTION +* uvp_pre_deallocate_pd() is implemented by vendor. It is the pre-ioctl +* routine for the AL call ib_deallocate_pd(). +* +* PARAMETERS +* h_uvp_pd +* [in] Vendor's user-mode library PD handle. +* +* RETURN VALUE +* IB_SUCCESS +* The pre-ioctl call is successful. +* +* PORTABILITY +* User Mode +* +* SEE ALSO +* uvp_pre_allocate_pd, uvp_post_allocate_pd_t, uvp_post_deallocate_pd_t +* +*******/ + +/********/ + +/****f* user-mode Verbs/uvp_post_deallocate_pd_t +* NAME +* uvp_post_deallocate_pd_t -- Post-ioctl function to deallocate PD +* +* SYNOPSIS +*/ + +typedef void +(AL_API *uvp_post_deallocate_pd_t) ( + IN const ib_pd_handle_t h_uvp_pd, + IN ib_api_status_t ioctl_status ); + +/* +* DESCRIPTION +* uvp_post_deallocate_pd_t() is implemented by the vendor. It is the +* post-ioctl routine for the AL call ib_dealloc_pd(). +* +* When all the resouces associated with a PD are destroyed, +* UAL invokes this post-ioctl routine to deallocate PD. Since the +* completion of the resource deallocation (e.g QP/CQ) is asynchronous, +* this function is called from a UAL asynchronous callback +* processing thread. +* +* PARAMETERS +* h_uvp_pd +* [in] Vendor's user-mode library PD handle. +* +* RETURN VALUE +* This function does not return a value. +* +* PORTABILITY +* User Mode +* +* SEE ALSO +* uvp_pre_allocate_pd, uvp_post_allocate_pd_t, uvp_pre_deallocate_pd +* +*******/ + +/********/ + +/****f* user-mode Verbs/uvp_pre_create_av +* NAME +* uvp_pre_create_av -- Pre-ioctl function to create AV +* +* SYNOPSIS +*/ + +typedef ib_api_status_t +(AL_API *uvp_pre_create_av) ( + IN const ib_pd_handle_t h_uvp_pd, + IN const ib_av_attr_t *p_addr_vector, + IN OUT ci_umv_buf_t *p_umv_buf, + OUT ib_av_handle_t *ph_uvp_av); +/* +* DESCRIPTION +* uvp_pre_create_av() is implemented by vendor. It is the pre-ioctl +* routine for ib_create_av(). +* +* PARAMETERS +* h_uvp_pd +* [in] Vendor's user-mode library handle to the Protection domain +* to which this AV is associated. +* p_addr_vector +* [in] Parameters to create the address vector. If the grh of the +* address vector is valid, then the grh resv1 field should be set to +* the index of the src_gid. +* p_umv_buf +* [in out] On input, UAL provides this buffer template. +* On return from this function, p_umv_buf contains +* any vendor-specific record to be exchanged with the vendor's +* HCA driver. +* ph_uvp_av +* [out] (OPTIONAL) Vendor's Handle to the newly created address vector. +* +* RETURN VALUE +* IB_SUCCESS +* The pre-ioctl is successful. +* IB_INVALID_SETTING +* Values in the vector is not valid +* IB_INVALID_PD_HANDLE +* The PD handle is invalid. +* IB_INSUFFICIENT_RESOURCES +* Insufficient resources in Vendor library to complete the call +* +* PORTABILITY +* User Mode +* +* SEE ALSO +* uvp_post_create_av_t, uvp_pre_query_av, uvp_post_query_av_t, uvp_pre_modify_av, +* uvp_post_modify_av_t, uvp_pre_destroy_av, uvp_post_destroy_av_t +* +********/ + +/********/ + +/****f* user-mode Verbs/uvp_post_create_av_t +* NAME +* uvp_post_create_av_t -- Post-ioctl function to create AV +* +* SYNOPSIS +*/ + +typedef void +(AL_API *uvp_post_create_av_t) ( + IN const ib_pd_handle_t h_uvp_pd, + IN ib_api_status_t ioctl_status, + IN OUT ib_av_handle_t *ph_uvp_av, + IN ci_umv_buf_t *p_umv_buf ); +/* +* DESCRIPTION +* uvp_post_create_av_t() is implemented by vendor. It is the post-ioctl routine +* for ib_create_av(). +* +* PARAMETERS +* h_uvp_pd +* [in] Vendor's user-mode library handle to the Protection domain +* to which this AV is associated +* ioctl_status +* [in] The ioctl status of the AL API. +* ph_uvp_av +* [in out] Vendor's address vector handle. +* If it specified in pre function than it must be the same value here. +* p_umv_buf +* [in] On input, it contains any vendor-specific private information +* exchanged with the vendor's Verbs Provider Driver (uvp_pre_create_av). +* Vendor is expected to check vendor-specific status in +* umv_buf as appropriate. +* +* RETURN VALUE +* This function does not return a value. +* +* PORTABILITY +* User Mode +* +* SEE ALSO +* uvp_pre_create_av, uvp_pre_query_av, uvp_post_query_av_t, uvp_pre_modify_av, +* uvp_post_modify_av_t, uvp_pre_destroy_av, uvp_post_destroy_av_t +* +********/ + +/********/ + +/****f* user-mode Verbs/uvp_pre_query_av +* NAME +* uvp_pre_query_av -- Pre-ioctl operation for ib_query_ca() +* +* SYNOPSIS +*/ + +typedef ib_api_status_t +(AL_API *uvp_pre_query_av) ( + IN const ib_av_handle_t h_uvp_av, + IN OUT ci_umv_buf_t *p_umv_buf ); + +/* +* DESCRIPTION +* uvp_pre_query_av() is implemented by vendor. It is the pre-ioctl routine +* for the AL call ib_query_av() in user-mode. +* +* PARAMETERS +* h_uvp_av +* [in] Vendor's handle to the address vector in user-mode library +* p_umv_buf +* [in out] On input, UAL provides this buffer template. +* On return from this function, p_umv_buf contains +* any vendor-specific record to be exchanged with the vendor's +* HCA driver. +* +* RETURN VALUE +* IB_SUCCESS +* The pre-ioctl function succeeded. +* IB_INVALID_AV_HANDLE +* AV handle was invalid +* IB_INSUFFICIENT_RESOURCES +* Insufficient resources in Vendor library to complete the call. +* +* PORTABILITY +* User Mode +* +* SEE ALSO +* uvp_pre_create_av, uvp_post_create_av_t, uvp_post_query_av_t, uvp_pre_modify_av, +* uvp_post_modify_av_t, uvp_pre_destroy_av, uvp_post_destroy_av_t +* +*********/ + +/********/ +/****f* user-mode Verbs/uvp_post_query_av_t +* NAME +* +* Vendor-specific post-ioctl operation for user-mode ib_query_ca() +* SYNOPSIS +*/ + +typedef void +(AL_API *uvp_post_query_av_t) ( + IN const ib_av_handle_t h_uvp_av, + IN ib_api_status_t ioctl_status, + IN OUT ib_av_attr_t *p_addr_vector, + IN OUT ib_pd_handle_t *ph_pd, + IN ci_umv_buf_t *p_umv_buf ); + +/* +* DESCRIPTION +* uvp_post_query_av_t() is implemented by vendor. It is the post-ioctl routine +* for the AL call ib_query_av() in user-mode. +* UAL provides the results of the query to the vendor library in this +* post-ioctl routine. +* +* PARAMETERS +* h_uvp_av +* [in] Vendor's handle to the address vector in user-mode library +* ioctl_status +* [in] The ioctl status of the AL API. +* p_addr_vector +* [in out] AV attribute (as returned by the ioctl). +* ph_pd +* [out] The vendor library PD handle associated with this AV. +* p_umv_buf +* [in] +* On input, it contains any vendor-specific private information +* exchanged with the vendor's Verbs Provider Driver (uvp_pre_query_av). +* Vendor is expected to check vendor-specific status in +* umv_buf as appropriate. +* +* RETURN VALUE +* This function does not return a value. +* +* PORTABILITY +* User Mode +* +* SEE ALSO +* uvp_pre_create_av, uvp_post_create_av_t, uvp_pre_query_av, uvp_pre_modify_av, +* uvp_post_modify_av_t, uvp_pre_destroy_av, uvp_post_destroy_av_t +* +*********/ + +/********/ + +/****f* user-mode Verbs/uvp_pre_modify_av +* NAME +* uvp_pre_modify_av -- Pre-ioctl function to modify AV +* +* SYNOPSIS +*/ +typedef ib_api_status_t +(AL_API *uvp_pre_modify_av) ( + IN const ib_av_handle_t h_uvp_av, + IN const ib_av_attr_t *p_addr_vector, + IN OUT ci_umv_buf_t *p_umv_buf ); +/* +* DESCRIPTION +* uvp_pre_modify_av() is implemented by vendor. It is the pre-ioctl routine +* for ib_modify_av(). +* +* PARAMETERS +* h_uvp_av +* [in] Vendor's AV handle in user-mode library. +* p_addr_vector +* [in] Parameters to modify the address vector handle. If the grh of the +* address vector is valid, then the grh resv1 field should be set to +* the index of the src_gid. +* p_umv_buf +* [in out] On input, UAL provides this buffer template. +* On return from this function, p_umv_buf contains +* any vendor-specific record to be exchanged with the vendor's +* HCA driver. +* +* RETURN VALUE +* IB_SUCCESS +* The pre-ioctl is successful. +* IB_INVALID_SETTING +* Values in the vector is not valid. +* IB_INVALID_AV_HANDLE +* The AV handle is invalid. +* IB_INSUFFICIENT_RESOURCES +* Insufficient resources in Vendor library to complete the call. +* +* PORTABILITY +* User Mode +* +* SEE ALSO +* uvp_pre_create_av, uvp_post_create_av_t, uvp_pre_query_av, uvp_post_query_av_t, +* uvp_post_modify_av_t, uvp_pre_destroy_av, uvp_post_destroy_av_t +* +********/ + +/********/ + +/****f* user-mode Verbs/uvp_post_modify_av_t +* NAME +* uvp_post_modify_av_t -- Post-ioctl function to modify AV +* SYNOPSIS +*/ + +typedef void +(AL_API *uvp_post_modify_av_t) ( + IN const ib_av_handle_t h_uvp_av, + IN ib_api_status_t ioctl_status, + IN ci_umv_buf_t *p_umv_buf ); + +/* +* DESCRIPTION +* uvp_post_modify_av_t() is implemented by vendor to modify the attributes +* of AV. It is the post-ioctl routine for ib_modify_av(). +* +* PARAMETERS +* h_uvp_av +* [in] Vendor's av handle in user-mode library. +* ioctl_status +* [in] The ioctl status of the AL API. +* p_umv_buf +* [in out] On input, it contains any vendor-specific private information +* exchanged with the vendor's Verbs Provider Driver (uvp_pre_modify_av). +* Vendor is expected to check vendor-specific status in +* umv_buf as appropriate. +* +* RETURN VALUE +* This function does not return a value. +* +* PORTABILITY +* User Mode +* +* SEE ALSO +* uvp_pre_create_av, uvp_post_create_av_t, uvp_pre_query_av, uvp_post_query_av_t, +* uvp_pre_modify_av, uvp_pre_destroy_av, uvp_post_destroy_av_t +* +********/ + +/********/ + +/****f* user-mode Verbs/uvp_pre_destroy_av +* NAME +* uvp_pre_destroy_av -- Pre-ioctl function to destroy AV +* +* SYNOPSIS +*/ + +typedef ib_api_status_t +(AL_API *uvp_pre_destroy_av) ( + IN const ib_av_handle_t h_uvp_av ); + +/* +* DESCRIPTION +* uvp_pre_destroy_av() is implemented by vendor to destroy the AV. +* It is the pre-ioctl routine for ib_destroy_av(). +* +* PARAMETERS +* h_uvp_av +* [in] Vendor's AV handle in user-mode library. +* +* RETURN VALUE +* IB_SUCCESS +* The pre-ioctl is successful. +* +* PORTABILITY +* User Mode +* +* SEE ALSO +* uvp_pre_create_av, uvp_post_create_av_t, uvp_pre_query_av, uvp_post_query_av_t, +* uvp_pre_modify_av, uvp_post_modify_av_t, uvp_post_destroy_av_t +* +********/ + +/********/ + +/****f* user-mode Verbs/uvp_post_destroy_av_t +* NAME +* uvp_post_destroy_av_t -- Post-ioctl function to destroy AV +* +* SYNOPSIS +*/ + +typedef void +(AL_API *uvp_post_destroy_av_t) ( + IN const ib_av_handle_t h_uvp_av, + IN ib_api_status_t ioctl_status ); + +/* +* DESCRIPTION +* uvp_post_destroy_av_t() is implemented by vendor. It is the post-ioctl +* routine for ib_destroy_av(). +* +* PARAMETERS +* h_uvp_av +* [in] Vendor's AV handle in user-mode library. +* p_umv_buf +* [in out] +* On input, it contains any vendor-specific private information +* exchanged with the vendor's Verbs Provider Driver (uvp_pre_destroy_av). +* Vendor is expected to check vendor-specific status in +* umv_buf as appropriate. +* +* RETURN VALUE +* This function does not return a value. +* +* PORTABILITY +* User Mode +* +* SEE ALSO +* uvp_pre_create_av, uvp_post_create_av_t, uvp_pre_query_av, uvp_post_query_av_t, +* uvp_pre_modify_av, uvp_post_modify_av_t, uvp_pre_destroy_av +* +********/ + +/********/ + +/****f* user-mode Verbs/uvp_pre_create_srq +* NAME +* uvp_pre_create_srq -- Pre-ioctl function to Create a Shared Queue Pair. +* +* SYNOPSIS +*/ + +typedef ib_api_status_t +(AL_API *uvp_pre_create_srq) ( + IN const ib_pd_handle_t h_uvp_pd, + IN const ib_srq_attr_t* const p_srq_attr, + IN OUT ci_umv_buf_t *p_umv_buf, + OUT ib_srq_handle_t *ph_uvp_srq); + +/* +* DESCRIPTION +* uvp_pre_create_srq() is implemented by vendor. It is the pre-ioctl routine +* for ib_create_srq(). +* +* PARAMETERS +* h_uvp_pd +* [in] Vendor's Protection domain handle in user-mode library. +* p_srq_attr +* [in] Initial attributes with which the srq must be created. +* p_umv_buf +* [in out] On input, UAL provides this buffer template. +* On return from this function, p_umv_buf contains +* any vendor-specific record to be exchanged with the vendor's +* HCA driver. +* ph_uvp_srq +* [out] (OPTIONAL) Vendor's Handle to the newly created SRQ. +* +* RETURN VALUE +* IB_SUCCESS +* The pre-ioctl call is successful. +* IB_INVALID_PD_HANDLE +* The PD handle is invalid. +* IB_UNSUPPORTED +* The specified queue pair type was not supported by the channel adapter. +* IB_INVALID_MAX_WRS +* The requested maximum send or receive work request depth could not be +* supported. +* IB_INVALID_MAX_SGE +* The requested maximum number of scatter-gather entries for the send or +* receive queue could not be supported. +* IB_INSUFFICIENT_RESOURCES +* Insufficient resources in Vendor library to complete the call. +* IB_INVALID_PARAMETER +* At least one parameter is invalid. +* +* PORTABILITY +* User Mode +* +* SEE ALSO +* uvp_post_create_srq_t, uvp_pre_query_srq, uvp_post_query_srq_t, uvp_pre_modify_srq, +* uvp_post_modify_srq_t, uvp_pre_destroy_srq, uvp_post_destroy_srq_t +* +********/ + +/********/ + +/****f* user-mode Verbs/uvp_post_create_srq_t +* NAME +* uvp_post_create_srq_t -- Post-ioctl function to Create a Queue Pair. +* +* SYNOPSIS +*/ + +typedef void +(AL_API *uvp_post_create_srq_t) ( + IN const ib_pd_handle_t h_uvp_pd, + IN ib_api_status_t ioctl_status, + IN OUT ib_srq_handle_t *ph_uvp_srq, + IN ci_umv_buf_t *p_umv_buf ); + +/* +* DESCRIPTION +* uvp_post_create_srq_t() is implemented by vendor. It is the post-ioctl routine +* for ib_create_srq(). +* +* PARAMETERS +* h_uvp_pd +* [in] Vendor's Protection domain handle in user-mode library. +* ioctl_status +* [in] The ioctl status of the AL API. +* ph_uvp_srq +* [in out] Vendor's srq handle for the newly created srq. +* If it specified in pre function than it must be the same value here. +* p_umv_buf +* [in out] On input, it contains any vendor-specific private information +* exchanged with the vendor's Verbs Provider Driver (uvp_pre_create_srq). +* Vendor is expected to check vendor-specific status in +* umv_buf as appropriate. +* +* RETURN VALUE +* This function does not return a value. +* +* PORTABILITY +* User Mode +* +* SEE ALSO +* uvp_pre_create_srq, uvp_pre_query_srq, uvp_post_query_srq_t, uvp_pre_modify_srq, +* uvp_post_modify_srq_t, uvp_pre_destroy_srq, uvp_post_destroy_srq_t +* +********/ + +/********/ + +/****f* user-mode Verbs/uvp_pre_modify_srq +* NAME +* uvp_pre_modify_srq -- Pre-ioctl function to Modify attributes of the +* specified srq. +* +* SYNOPSIS +* +*/ + +typedef ib_api_status_t +(AL_API *uvp_pre_modify_srq) ( + IN const ib_srq_handle_t h_uvp_srq, + IN const ib_srq_attr_t * const p_srq_attr, + IN const ib_srq_attr_mask_t srq_attr_mask, + IN OUT ci_umv_buf_t *p_umv_buf ); + +/* +* DESCRIPTION +* uvp_pre_modify_srq() is implemented by vendor to modify the attributes of a +* srq. It is the pre-ioctl routine for ib_modify_srq(). +* +* PARAMETERS +* h_uvp_srq +* [in] Vendor's srq Handle to the queue pair (in user-mode library) +* whose state is to be modified. +* p_srq_attr +* [in] Specifies what attributes need to be modified in the srq. +* srq_attr_mask +* [in] Specifies which fields of ib_srq_attr_t are valid. +* p_umv_buf +* [in out] On input, UAL provides this buffer template. +* On return from this function, p_umv_buf contains +* any vendor-specific record to be exchanged with the vendor's +* HCA driver. +* +* RETURN VALUE +* IB_SUCCESS +* The pre-ioctl call is successful. +* IB_INSUFFICIENT_RESOURCES +* Insufficient resources to complete the requested operation. +* IB_INVALID_SRQ_HANDLE +* Invalid srq handle. +* IB_UNSUPPORTED +* Requested operation is not supported, for e.g. Atomic operations. +* +* PORTABILITY +* User mode +* +* SEE ALSO +* uvp_pre_create_srq, uvp_post_create_srq_t, uvp_pre_query_srq, uvp_post_query_srq_t, +* uvp_post_modify_srq_t, uvp_pre_destroy_srq, uvp_post_destroy_srq_t +* +********/ + +/********/ + +/****f* user-mode Verbs/uvp_post_modify_srq_t +* NAME +* uvp_post_modify_srq_t -- Post-ioctl function to Modify attributes of +* the specified srq. +* +* SYNOPSIS +*/ + +typedef void +(AL_API *uvp_post_modify_srq_t) ( + IN const ib_srq_handle_t h_uvp_srq, + IN ib_api_status_t ioctl_status, + IN ci_umv_buf_t *p_umv_buf ); + +/* +* DESCRIPTION +* uvp_post_modify_srq_t() is implemented by vendor to modify the srq attributes. +* It is the post-ioctl routine for ib_modify_srq(). +* +* PARAMETERS +* h_uvp_srq +* [in] Vendor's srq Handle to the queue pair (in user-mode library) +* whose state is modified. +* ioctl_status +* [in] The ioctl status of the AL API. +* p_umv_buf +* [in out] On input, it contains any vendor-specific private information +* exchanged with the vendor's Verbs Provider Driver (uvp_pre_modify_srq). +* Vendor is expected to check vendor-specific status in +* umv_buf as appropriate. +* +* RETURN VALUE +* This function does not return a value. +* +* PORTABILITY +* User mode +* +* SEE ALSO +* uvp_pre_create_srq, uvp_post_create_srq_t, uvp_pre_query_srq, uvp_post_query_srq_t, +* uvp_pre_modify_srq, uvp_pre_destroy_srq, uvp_post_destroy_srq_t +* +********/ + +/********/ + +/****f* user-mode Verbs/uvp_pre_query_srq +* NAME +* uvp_pre_query_srq -- Pre-ioctl function to Query the attributes of the srq +* +* SYNOPSIS +*/ + +typedef ib_api_status_t +(AL_API *uvp_pre_query_srq) ( + IN ib_srq_handle_t h_uvp_srq, + IN OUT ci_umv_buf_t *p_umv_buf ); + +/* +* DESCRIPTION +* uvp_pre_query_srq() is implemented by vendor. It is the pre-ioctl routine +* for the AL call ib_query_srq(). +* +* PARAMETERS +* h_uvp_srq +* [in] Vendor's handle to the srq (in user-mode library). +* p_umv_buf +* [in out] On input, UAL provides this buffer template. +* On return from this function, p_umv_buf contains +* any vendor-specific record to be exchanged with the vendor's +* HCA driver. +* RETURN VALUE +* IB_SUCCESS +* The pre-ioctl function succeeded. +* IB_INVALID_SRQ_HANDLE +* srq handle is invalid +* IB_INSUFFICIENT_RESOURCES +* Insufficient resources in Vendor library to complete the call. +* +* PORTABILITY +* User Mode +* +* SEE ALSO +* uvp_pre_create_srq, uvp_post_create_srq_t, uvp_post_query_srq_t, uvp_pre_modify_srq, +* uvp_post_modify_srq_t, uvp_pre_destroy_srq, uvp_post_destroy_srq_t +* +*********/ + +/********/ + +/****f* user-mode Verbs/uvp_post_query_srq_t +* NAME +* uvp_post_query_srq_t -- Post-ioctl operation for user-mode ib_query_srq() +* +* SYNOPSIS +*/ + +typedef void +(AL_API *uvp_post_query_srq_t) ( + IN ib_srq_handle_t h_uvp_srq, + IN ib_api_status_t ioctl_status, + IN ib_srq_attr_t *p_query_attr, + IN ci_umv_buf_t *p_umv_buf ); + +/* +* DESCRIPTION +* uvp_post_query_srq_t() is implemented by vendor. It is the post-ioctl routine +* for ib_query_srq(). +* UAL provides the results of the query to the vendor library in this +* post-ioctl routine. +* +* PARAMETERS +* h_uvp_srq +* [in] Vendor's handle to the srq (in user-mode library). +* ioctl_status +* [in] The ioctl status of the AL API. +* p_query_attr +* [in] srq attribute as returned by the ioctl. +* p_umv_buf +* [in out] On input, it contains any vendor-specific private information +* exchanged with the vendor's Verbs Provider Driver (uvp_pre_query_srq). +* Vendor is expected to check vendor-specific status in +* umv_buf as appropriate. +* +* RETURN VALUE +* This function does not return a value. +* +* PORTABILITY +* User Mode +* +* SEE ALSO +* uvp_pre_create_srq, uvp_post_create_srq_t, uvp_pre_query_srq, uvp_pre_modify_srq, +* uvp_post_modify_srq_t, uvp_pre_destroy_srq, uvp_post_destroy_srq_t +* +*********/ + +/********/ + +/****f* user-mode Verbs/uvp_pre_destroy_srq +* NAME +* uvp_pre_destroy_srq -- Pre-ioctl function to Destroy a Queue Pair. +* SYNOPSIS +*/ + +typedef ib_api_status_t +(AL_API *uvp_pre_destroy_srq) ( + IN const ib_srq_handle_t h_uvp_srq ); + +/* +* DESCRIPTION +* uvp_pre_destroy_srq() is the pre-ioctl routine implemented by vendor +* to destroy srq. +* UAL invokes this pre-ioctl routine to destroy srq. +* The vendor is expected to perform any preliminary steps in preparation +* for destroying the srq and perform any book-keeping. +* +* PARAMETERS +* h_uvp_srq +* [in] Vendor's Handle to the srq (in user-mode library) +* that needs to be destroyed. +* p_umv_buf +* [in out] On input, UAL provides this buffer template. +* On return from this function, p_umv_buf contains +* any vendor-specific record to be exchanged with the vendor's +* HCA driver. +* +* RETURN VALUE +* IB_SUCCESS +* The pre-ioctl call is successful. +* +* PORTABILITY +* User mode. +* +* SEE ALSO +* uvp_pre_create_srq, uvp_post_create_srq_t, uvp_pre_query_srq, uvp_post_query_srq_t, +* uvp_pre_modify_srq, uvp_post_modify_srq_t, uvp_post_destroy_srq_t +* +********/ + +/********/ + + +/****f* user-mode Verbs/uvp_post_destroy_srq_t +* NAME +* uvp_post_destroy_srq_t -- Post-ioctl function to Destroy a Queue Pair. +* +* SYNOPSIS +*/ + +typedef void +(AL_API *uvp_post_destroy_srq_t) ( + IN const ib_srq_handle_t h_uvp_srq, + IN ib_api_status_t ioctl_status ); + +/* +* DESCRIPTION +* uvp_post_destroy_srq_t() is implemented by vendor. It is the post-ioctl +* routine for ib_destroy_srq(). +* UAL invokes this post-ioctl routine to destroy srq when it receives +* asynchronous notification from the user-mode proxy in kernel. +* +* PARAMETERS +* h_uvp_srq +* [in] Vendor's Handle to the srq (in user-mode library) +* that needs to be destroyed. +* +* RETURN VALUE +* IB_SUCCESS +* The post-ioctl call is successful. +* +* PORTABILITY +* User mode. +* +* SEE ALSO +* uvp_pre_create_srq, uvp_post_create_srq_t, uvp_pre_query_srq, uvp_post_query_srq_t, +* uvp_pre_modify_srq, uvp_post_modify_srq_t, uvp_pre_destroy_srq +* +********/ + +/********/ + +/****f* user-mode Verbs/uvp_pre_create_qp +* NAME +* uvp_pre_create_qp -- Pre-ioctl function to Create a Queue Pair. +* +* SYNOPSIS +*/ + +typedef ib_api_status_t +(AL_API *uvp_pre_create_qp) ( + IN const ib_pd_handle_t h_uvp_pd, + IN const ib_qp_create_t *p_create_attr, + IN OUT ci_umv_buf_t *p_umv_buf, + OUT ib_qp_handle_t *ph_uvp_qp); + +/* +* DESCRIPTION +* uvp_pre_create_qp() is implemented by vendor. It is the pre-ioctl routine +* for ib_create_qp(). +* +* PARAMETERS +* h_uvp_pd +* [in] Vendor's Protection domain handle in user-mode library. +* p_create_attr +* [in] Initial attributes with which the qp must be created. +* p_umv_buf +* [in out] On input, UAL provides this buffer template. +* On return from this function, p_umv_buf contains +* any vendor-specific record to be exchanged with the vendor's +* HCA driver. +* ph_uvp_qp +* [in out] (OPTIONAL) Vendor's Handle to the newly created QP. +* +* RETURN VALUE +* IB_SUCCESS +* The pre-ioctl call is successful. +* IB_INVALID_PD_HANDLE +* The PD handle is invalid. +* IB_INVALID_CQ_HANDLE +* The send or receive completion queue to associate with the queue pair +* is invalid. +* IB_UNSUPPORTED +* The specified queue pair type was not supported by the channel adapter. +* IB_INVALID_MAX_WRS +* The requested maximum send or receive work request depth could not be +* supported. +* IB_INVALID_MAX_SGE +* The requested maximum number of scatter-gather entries for the send or +* receive queue could not be supported. +* IB_INSUFFICIENT_RESOURCES +* Insufficient resources in Vendor library to complete the call. +* IB_INVALID_PARAMETER +* At least one parameter is invalid. +* +* PORTABILITY +* User Mode +* +* SEE ALSO +* uvp_post_create_qp_t, uvp_pre_query_qp, uvp_post_query_qp_t, uvp_pre_modify_qp, +* uvp_post_modify_qp_t, uvp_pre_destroy_qp, uvp_post_destroy_qp_t +* +********/ + +typedef struct _uvp_qp_create +{ + ib_qp_create_t qp_create; + + void *context; + uint32_t max_inline_send; + uint32_t initiator_depth; + uint32_t responder_resources; + +} uvp_qp_create_t; + +typedef ib_api_status_t +(AL_API *uvp_wv_pre_create_qp) ( + IN const ib_pd_handle_t h_uvp_pd, + IN const uvp_qp_create_t *p_create_attr, + IN OUT ci_umv_buf_t *p_umv_buf, + OUT ib_qp_handle_t *ph_uvp_qp); + +/********/ + +/****f* user-mode Verbs/uvp_post_create_qp_t +* NAME +* uvp_post_create_qp_t -- Post-ioctl function to Create a Queue Pair. +* +* SYNOPSIS +*/ + +typedef ib_api_status_t +(AL_API *uvp_post_create_qp_t) ( + IN const ib_pd_handle_t h_uvp_pd, + IN ib_api_status_t ioctl_status, + IN OUT ib_qp_handle_t *ph_uvp_qp, + IN ci_umv_buf_t *p_umv_buf ); + +/* +* DESCRIPTION +* uvp_post_create_qp_t() is implemented by vendor. It is the post-ioctl routine +* for ib_create_qp(). +* +* PARAMETERS +* h_uvp_pd +* [in] Vendor's Protection domain handle in user-mode library. +* ioctl_status +* [in] The ioctl status of the AL API. +* ph_uvp_qp +* [in out] Vendor's QP handle for the newly created QP. +* If it specified in pre function than it must be the same value here. +* p_umv_buf +* [in out] On input, it contains any vendor-specific private information +* exchanged with the vendor's Verbs Provider Driver (uvp_pre_create_qp). +* Vendor is expected to check vendor-specific status in +* umv_buf as appropriate. +* +* RETURN VALUE +* IB_SUCCESS +* The pre-ioctl call is successful. +* IB_INSUFFICIENT_RESOURCES +* Insufficient resources to satisfy request. +* +* PORTABILITY +* User Mode +* +* SEE ALSO +* uvp_pre_create_qp, uvp_pre_query_qp, uvp_post_query_qp_t, uvp_pre_modify_qp, +* uvp_post_modify_qp_t, uvp_pre_destroy_qp, uvp_post_destroy_qp_t +* +********/ + +/********/ + +/****f* user-mode Verbs/uvp_pre_modify_qp +* NAME +* uvp_pre_modify_qp -- Pre-ioctl function to Modify attributes of the +* specified QP. +* +* SYNOPSIS +* +*/ + +typedef ib_api_status_t +(AL_API *uvp_pre_modify_qp) ( + IN const ib_qp_handle_t h_uvp_qp, + IN const ib_qp_mod_t *p_modify_attr, + IN OUT ci_umv_buf_t *p_umv_buf ); + +/* +* DESCRIPTION +* uvp_pre_modify_qp() is implemented by vendor to modify the attributes of a +* QP. It is the pre-ioctl routine for ib_modify_qp(). +* +* PARAMETERS +* h_uvp_qp +* [in] Vendor's qp Handle to the queue pair (in user-mode library) +* whose state is to be modified. +* p_modify_attr +* [in] Specifies what attributes need to be modified in the qp. +* p_umv_buf +* [in out] On input, UAL provides this buffer template. +* On return from this function, p_umv_buf contains +* any vendor-specific record to be exchanged with the vendor's +* HCA driver. +* +* RETURN VALUE +* IB_SUCCESS +* The pre-ioctl call is successful. +* IB_INSUFFICIENT_RESOURCES +* Insufficient resources to complete the requested operation. +* IB_INVALID_QP_HANDLE +* Invalid QP handle. +* IB_UNSUPPORTED +* Requested operation is not supported, for e.g. Atomic operations. +* IB_QP_INVALID_STATE +* Invalid state transition request. Current QP state not in allowable +* state. +* IB_INVALID_PKEY +* Pkey specified in modify request not valid entry in P_KEY table. Or +* index is out of range. +* IB_INVALID_PMIG_STATE +* Invalid path migration state specified in the request. +* +* PORTABILITY +* User mode +* +* SEE ALSO +* uvp_pre_create_qp, uvp_post_create_qp_t, uvp_pre_query_qp, uvp_post_query_qp_t, +* uvp_post_modify_qp_t, uvp_pre_destroy_qp, uvp_post_destroy_qp_t +* +********/ + +/********/ + +/****f* user-mode Verbs/uvp_post_modify_qp_t +* NAME +* uvp_post_modify_qp_t -- Post-ioctl function to Modify attributes of +* the specified QP. +* +* SYNOPSIS +*/ + +typedef void +(AL_API *uvp_post_modify_qp_t) ( + IN const ib_qp_handle_t h_uvp_qp, + IN ib_api_status_t ioctl_status, + IN ci_umv_buf_t *p_umv_buf ); + +/* +* DESCRIPTION +* uvp_post_modify_qp_t() is implemented by vendor to modify the qp attributes. +* It is the post-ioctl routine for ib_modify_qp(). +* +* PARAMETERS +* h_uvp_qp +* [in] Vendor's qp Handle to the queue pair (in user-mode library) +* whose state is modified. +* ioctl_status +* [in] The ioctl status of the AL API. +* p_umv_buf +* [in out] On input, it contains any vendor-specific private information +* exchanged with the vendor's Verbs Provider Driver (uvp_pre_modify_qp). +* Vendor is expected to check vendor-specific status in +* umv_buf as appropriate. +* +* RETURN VALUE +* This function does not return a value. +* +* PORTABILITY +* User mode +* +* SEE ALSO +* uvp_pre_create_qp, uvp_post_create_qp_t, uvp_pre_query_qp, uvp_post_query_qp_t, +* uvp_pre_modify_qp, uvp_pre_destroy_qp, uvp_post_destroy_qp_t +* +********/ + +/********/ + +/****f* user-mode Verbs/uvp_pre_query_qp +* NAME +* uvp_pre_query_qp -- Pre-ioctl function to Query the attributes of the QP +* +* SYNOPSIS +*/ + +typedef ib_api_status_t +(AL_API *uvp_pre_query_qp) ( + IN ib_qp_handle_t h_uvp_qp, + IN OUT ci_umv_buf_t *p_umv_buf ); + +/* +* DESCRIPTION +* uvp_pre_query_qp() is implemented by vendor. It is the pre-ioctl routine +* for the AL call ib_query_qp(). +* +* PARAMETERS +* h_uvp_qp +* [in] Vendor's handle to the QP (in user-mode library). +* p_umv_buf +* [in out] On input, UAL provides this buffer template. +* On return from this function, p_umv_buf contains +* any vendor-specific record to be exchanged with the vendor's +* HCA driver. +* RETURN VALUE +* IB_SUCCESS +* The pre-ioctl function succeeded. +* IB_INVALID_QP_HANDLE +* QP handle is invalid +* IB_INSUFFICIENT_RESOURCES +* Insufficient resources in Vendor library to complete the call. +* +* PORTABILITY +* User Mode +* +* SEE ALSO +* uvp_pre_create_qp, uvp_post_create_qp_t, uvp_post_query_qp_t, uvp_pre_modify_qp, +* uvp_post_modify_qp_t, uvp_pre_destroy_qp, uvp_post_destroy_qp_t +* +*********/ + +/********/ + +/****f* user-mode Verbs/uvp_post_query_qp_t +* NAME +* uvp_post_query_qp_t -- Post-ioctl operation for user-mode ib_query_qp() +* +* SYNOPSIS +*/ + +typedef void +(AL_API *uvp_post_query_qp_t) ( + IN ib_qp_handle_t h_uvp_qp, + IN ib_api_status_t ioctl_status, + IN ib_qp_attr_t *p_query_attr, + IN ci_umv_buf_t *p_umv_buf ); + +/* +* DESCRIPTION +* uvp_post_query_qp_t() is implemented by vendor. It is the post-ioctl routine +* for ib_query_qp(). +* UAL provides the results of the query to the vendor library in this +* post-ioctl routine. +* +* PARAMETERS +* h_uvp_qp +* [in] Vendor's handle to the QP (in user-mode library). +* ioctl_status +* [in] The ioctl status of the AL API. +* p_query_attr +* [in] QP attribute as returned by the ioctl. +* p_umv_buf +* [in out] On input, it contains any vendor-specific private information +* exchanged with the vendor's Verbs Provider Driver (uvp_pre_query_qp). +* Vendor is expected to check vendor-specific status in +* umv_buf as appropriate. +* +* RETURN VALUE +* This function does not return a value. +* +* PORTABILITY +* User Mode +* +* SEE ALSO +* uvp_pre_create_qp, uvp_post_create_qp_t, uvp_pre_query_qp, uvp_pre_modify_qp, +* uvp_post_modify_qp_t, uvp_pre_destroy_qp, uvp_post_destroy_qp_t +* +*********/ + +/********/ + +/****f* user-mode Verbs/uvp_pre_destroy_qp +* NAME +* uvp_pre_destroy_qp -- Pre-ioctl function to Destroy a Queue Pair. +* SYNOPSIS +*/ + +typedef ib_api_status_t +(AL_API *uvp_pre_destroy_qp) ( + IN const ib_qp_handle_t h_uvp_qp ); + +/* +* DESCRIPTION +* uvp_pre_destroy_qp() is the pre-ioctl routine implemented by vendor +* to destroy QP. +* UAL invokes this pre-ioctl routine to destroy QP. +* The vendor is expected to perform any preliminary steps in preparation +* for destroying the QP and perform any book-keeping. +* +* PARAMETERS +* h_uvp_qp +* [in] Vendor's Handle to the qp (in user-mode library) +* that needs to be destroyed. +* p_umv_buf +* [in out] On input, UAL provides this buffer template. +* On return from this function, p_umv_buf contains +* any vendor-specific record to be exchanged with the vendor's +* HCA driver. +* +* RETURN VALUE +* IB_SUCCESS +* The pre-ioctl call is successful. +* +* PORTABILITY +* User mode. +* +* SEE ALSO +* uvp_pre_create_qp, uvp_post_create_qp_t, uvp_pre_query_qp, uvp_post_query_qp_t, +* uvp_pre_modify_qp, uvp_post_modify_qp_t, uvp_post_destroy_qp_t +* +********/ + +/********/ + + +/****f* user-mode Verbs/uvp_post_destroy_qp_t +* NAME +* uvp_post_destroy_qp_t -- Post-ioctl function to Destroy a Queue Pair. +* +* SYNOPSIS +*/ + +typedef void +(AL_API *uvp_post_destroy_qp_t) ( + IN const ib_qp_handle_t h_uvp_qp, + IN ib_api_status_t ioctl_status ); + +/* +* DESCRIPTION +* uvp_post_destroy_qp_t() is implemented by vendor. It is the post-ioctl +* routine for ib_destroy_qp(). +* UAL invokes this post-ioctl routine to destroy QP when it receives +* asynchronous notification from the user-mode proxy in kernel. +* +* PARAMETERS +* h_uvp_qp +* [in] Vendor's Handle to the qp (in user-mode library) +* that needs to be destroyed. +* +* RETURN VALUE +* IB_SUCCESS +* The post-ioctl call is successful. +* +* PORTABILITY +* User mode. +* +* SEE ALSO +* uvp_pre_create_qp, uvp_post_create_qp_t, uvp_pre_query_qp, uvp_post_query_qp_t, +* uvp_pre_modify_qp, uvp_post_modify_qp_t, uvp_pre_destroy_qp +* +********/ + +/****f* user-mode Verbs/uvp_nd_get_qp_state_t +* NAME +* uvp_nd_get_qp_state_t -- Get QP state. +* +* SYNOPSIS +*/ + +typedef uint32_t +(AL_API *uvp_nd_get_qp_state_t) ( + IN const ib_qp_handle_t h_uvp_qp + ); + +/* +* DESCRIPTION +* uvp_nd_get_qp_state_t() is implemented by vendor. +* There is no post uvp_nd_get_qp_state_t function. +* +* PARAMETERS +* h_uvp_qp +* [in] Vendor's Handle to the qp (in user-mode library) +* that needs to be destroyed. +* +* RETURN VALUE +* +* PORTABILITY +* User mode. +* +* SEE ALSO +* +********/ + +/****f* user-mode Verbs/uvp_nd_modify_qp_t +* NAME +* uvp_nd_modify_qp_t -- Get QP state location and size. +* +* SYNOPSIS +*/ + +typedef void +(AL_API *uvp_nd_modify_qp_t) ( + IN const ib_qp_handle_t h_uvp_qp, + OUT void** pp_outbuf, + OUT DWORD* p_size + ); + +/* +* DESCRIPTION +* uvp_nd_modify_qp_t() is implemented by vendor. +* UAL invokes this pre-ioctl routine to enable KAL to change QP state +* It is used after quick QP modify operation. +* There is no post uvp_ndi_modify_qp_t function. +* +* PARAMETERS +* h_uvp_qp +* [in] Vendor's Handle to the qp (in user-mode library) +* that needs to be destroyed. +* pp_outbuf +* [out] pointer to QP state internal variable; +* p_size +* [out] pointer to the size of QP state internal variable; +* +* RETURN VALUE +* +* PORTABILITY +* User mode. +* +* SEE ALSO +* +********/ + +/********/ + +/****f* user-mode Verbs/uvp_pre_create_cq +* NAME +* uvp_pre_create_cq -- Pre-ioctl function to Create a completion queue (CQ) +* +* SYNOPSIS +*/ + +typedef ib_api_status_t +(AL_API *uvp_pre_create_cq) ( + IN const ib_ca_handle_t h_uvp_ca, + IN OUT uint32_t* const p_size, + IN OUT ci_umv_buf_t *p_umv_buf, + OUT ib_cq_handle_t *ph_uvp_cq); +/* +* DESCRIPTION +* uvp_pre_create_cq() is implemented by vendor. It is the pre-ioctl routine +* for ib_create_cq(). +* +* PARAMETERS +* h_uvp_pd +* [in] Vendor's handle to an existing protection domain (in user-mode +* library) +* p_size +* [in out] Points to a variable containing the number of CQ entries +* requested by the consumer. +* On return, points to the size of the CQ that was created +* by the provider. +* p_umv_buf +* [in out] On input, UAL provides this buffer template. +* On return from this function, p_umv_buf contains +* any vendor-specific record to be exchanged with the vendor's +* HCA driver. +* ph_uvp_cq +* [in out] Vendor's Handle to the newly created CQ. +* +* RETURN VALUE +* IB_SUCCESS +* The operation was successful. +* IB_INVALID_PD_HANDLE +* The h_uvp_pd passed is invalid. +* IB_INSUFFICIENT_RESOURCES +* Insufficient resources to complete request. +* IB_INVALID_CQ_SIZE +* Requested CQ Size is not supported. +* +* PORTABILITY +* User mode. +* +* SEE ALSO +* uvp_post_create_cq_t, uvp_pre_resize_cq, uvp_post_resize_cq_t, +* uvp_pre_query_cq, uvp_post_query_cq_t, uvp_pre_destroy_cq, +* uvp_post_destroy_cq_t +* +********/ + +/********/ + +/****f* user-mode Verbs/uvp_post_create_cq_t +* NAME +* uvp_post_create_cq_t -- Post-ioctl function to Create a completion queue (CQ) +* +* SYNOPSIS +*/ + +typedef void +(AL_API *uvp_post_create_cq_t) ( + IN const ib_ca_handle_t h_uvp_ca, + IN ib_api_status_t ioctl_status, + IN const uint32_t size, + IN OUT ib_cq_handle_t *ph_uvp_cq, + IN ci_umv_buf_t *p_umv_buf ); + +/* +* DESCRIPTION +* uvp_post_create_cq_t() is implemented by vendor to create CQ. +* It is the post-ioctl routine for ib_create_cq(). +* +* PARAMETERS +* h_uvp_pd +* [in] Vendor's handle to an existing protection domain (in user-mode +* library) +* ioctl_status +* [in] The ioctl status of the AL API. +* size +* [in] size of the CQ that was created by the provider. +* If VPD created the CQ in kernel, this is the value as set by +* VPD. If UVP creates the CQ in user-mode, then uvp already knows +* the size of the CQ in the pre-ioctl. +* ph_uvp_cq +* [in out] Vendor's Handle to the newly created CQ. +* If it specified in pre function than it must be the same value here. +* p_umv_buf +* [in out] On input, it contains any vendor-specific private information +* exchanged with the vendor's Verbs Provider Driver (uvp_pre_create_cq). +* Vendor is expected to check vendor-specific status in +* umv_buf as appropriate. +* +* RETURN VALUE +* This function does not return a value. +* +* PORTABILITY +* User mode. +* +* SEE ALSO +* uvp_pre_create_cq, uvp_pre_resize_cq, uvp_post_resize_cq_t, +* uvp_pre_query_cq, uvp_post_query_cq_t, uvp_pre_destroy_cq, +* uvp_post_destroy_cq_t +* +********/ + +/********/ + +/****f* user-mode Verbs/uvp_pre_resize_cq +* NAME +* uvp_pre_resize_cq -- Pre-ioctl function to resize a CQ. +* +* SYNOPSIS +*/ + +typedef ib_api_status_t +(AL_API *uvp_pre_resize_cq) ( + IN const ib_cq_handle_t h_uvp_cq, + IN OUT uint32_t* const p_size, + IN OUT ci_umv_buf_t *p_umv_buf ); + +/* +* DESCRIPTION +* uvp_pre_resize_cq() is implemented by vendor to resize the CQ. +* It is the pre-ioctl routine for ib_resize_cq(). +* +* PARAMETERS +* h_uvp_cq +* [in] Vendor's Handle to the already created CQ (in user-mode library). +* p_size +* [in out] On input, points to a variable containing the number +* of CQ entries requested by the consumer. +* On completion points to the size of the CQ that was resized by +* the provider. +* p_umv_buf +* [in out] On input, UAL provides this buffer template. +* On return from this function, p_umv_buf contains +* any vendor-specific record to be exchanged with the vendor's +* HCA driver. + +* RETURN VALUE +* IB_SUCCESS +* The operation was successful. +* IB_INVALID_CQ_HANDLE +* The CQ handle is invalid. +* IB_INSUFFICIENT_RESOURCES +* Insufficient resources to complete request. +* IB_INVALID_CQ_SIZE +* Requested CQ Size is not supported. +* IB_OVERFLOW +* The CQ has more entries than the resize request. The CQ is not +* modified, and old entries still exist. +* +* PORTABILITY +* User mode. +* +* SEE ALSO +* uvp_pre_create_cq, uvp_post_create_cq_t, uvp_post_resize_cq_t, +* uvp_pre_query_cq, uvp_post_query_cq_t, uvp_pre_destroy_cq, +* uvp_post_destroy_cq_t +* +********/ + +/********/ + +/****f* user-mode Verbs/uvp_post_resize_cq_t +* NAME +* uvp_post_resize_cq_t -- Post-ioctl function to resize a CQ. +* +* SYNOPSIS +*/ + +typedef void +(AL_API *uvp_post_resize_cq_t) ( + IN const ib_cq_handle_t h_uvp_cq, + IN ib_api_status_t ioctl_status, + IN const uint32_t size, + IN ci_umv_buf_t *p_umv_buf ); + +/* +* DESCRIPTION +* uvp_post_resize_cq_t() is implemented by vendor to resize the CQ. +* It is the post-ioctl routine for ib_resize_cq(). +* +* PARAMETERS +* h_uvp_cq +* [in] Vendor's Handle to the already created CQ (in user-mode library). +* ioctl_status +* [in] The ioctl status of the AL API. +* size +* [in] size of the CQ that was created by the provider. +* If VPD resized the CQ in kernel, this is the value as set by +* VPD. If UVP resizes the CQ in user-mode, then uvp already knows +* the size of the CQ in the pre-ioctl. +* p_umv_buf +* [in out] On input, it contains any vendor-specific private information +* exchanged with the vendor's Verbs Provider Driver (uvp_pre_resize_cq). +* Vendor is expected to check vendor-specific status in +* umv_buf as appropriate. +* +* RETURN VALUE +* This function does not return a value. +* +* PORTABILITY +* User mode. +* +* SEE ALSO +* uvp_pre_create_cq, uvp_post_create_cq_t, uvp_pre_resize_cq, +* uvp_pre_query_cq, uvp_post_query_cq_t, uvp_pre_destroy_cq, +* uvp_post_destroy_cq_t +* +********/ + +/********/ + +/****f* user-mode Verbs/uvp_pre_query_cq +* NAME +* uvp_pre_query_cq -- Pre-ioctl to Query the number of entries +* configured for the CQ. +* +* SYNOPSIS +*/ + +typedef ib_api_status_t +(AL_API *uvp_pre_query_cq) ( + IN const ib_cq_handle_t h_uvp_cq, + IN OUT uint32_t* const p_size, + IN OUT ci_umv_buf_t *p_umv_buf ); + +/* +* DESCRIPTION +* uvp_pre_query_cq() is implemented by vendor. It is the pre-ioctl routine +* for ib_query_cq(). +* Can we always go to the kernel to query even if it is created +* in vendor library in user-mode? +* +* PARAMETERS +* h_uvp_cq +* [in] Vendor's Handle to the already created CQ (in user-mode library). +* +* p_size +* [out] Size of the CQ if processing ends in user-mode. +* +* p_umv_buf +* [in out] On input, UAL provides this buffer template. +* On return from this function, p_umv_buf contains +* any vendor-specific record to be exchanged with the vendor's +* HCA driver. +* +* RETURN VALUE +* IB_SUCCESS +* The operation was successful. +* IB_INVALID_CQ_HANDLE +* The CQ handle is invalid. +* IB_INSUFFICIENT_RESOURCES +* Insufficient resources in Vendor library to complete the call. +* IB_VERBS_PROCESSING_DONE +* The UVP fully processed the request. The post_query_cq handler +* will not be invoked. +* +* PORTABILITY +* User mode. +* SEE ALSO +* uvp_pre_create_cq, uvp_post_create_cq_t, uvp_pre_resize_cq, +* uvp_post_resize_cq_t, uvp_post_query_cq_t, uvp_pre_destroy_cq, +* uvp_post_destroy_cq_t +* +********/ + +/********/ + +/****f* user-mode Verbs/uvp_post_query_cq_t +* NAME +* uvp_post_query_cq_t -- Post-ioctl to Query the number of entries +* configured for the CQ. +* +* SYNOPSIS +*/ + +typedef void +(AL_API *uvp_post_query_cq_t) ( + IN const ib_cq_handle_t h_uvp_cq, + IN ib_api_status_t ioctl_status, + IN const uint32_t size, + IN ci_umv_buf_t *p_umv_buf ); + +/* +* DESCRIPTION +* uvp_post_query_cq_t() is implemented by vendor to query CQ. +* It is the post-ioctl routine for ib_query_cq(). +* +* PARAMETERS +* h_uvp_cq +* [in] Vendor's Handle to the already created CQ (in user-mode library). +* ioctl_status +* [in] The ioctl status of the AL API. +* size +* [in] The size of the CQ retuned by the IOCTL. +* p_umv_buf +* [in out] On input, it contains any vendor-specific private information +* exchanged with the vendor's Verbs Provider Driver (uvp_pre_query_cq). +* Vendor is expected to check vendor-specific status in +* umv_buf as appropriate. +* +* RETURN VALUE +* This function does not return a value. +* +* PORTABILITY +* User mode. +* +* SEE ALSO +* uvp_pre_create_cq, uvp_post_create_cq_t, uvp_pre_resize_cq, +* uvp_post_resize_cq_t, uvp_pre_query_cq, uvp_pre_destroy_cq, +* uvp_post_destroy_cq_t +* +********/ + +/********/ + +/****f* user-mode Verbs/uvp_pre_destroy_cq +* NAME +* uvp_pre_destroy_cq -- Pre-ioctl function to Destroy a CQ. +* +* SYNOPSIS +*/ + +typedef ib_api_status_t +(AL_API *uvp_pre_destroy_cq) ( + IN const ib_cq_handle_t h_uvp_cq ); + +/* +* DESCRIPTION +* uvp_pre_destroy_cq() is implemented by vendor to destroy CQ. +* It is the pre-ioctl routine for ib_destroy_cq(). +* +* PARAMETERS +* h_uvp_cq +* [in] Vendor's Handle to the cq (in user-mode library) +* that needs to be destroyed. +* +* RETURN VALUE +* IB_SUCCESS +* The pre-ioctl call is successful. +* +* PORTABILITY +* User mode. +* +* SEE ALSO +* uvp_pre_create_cq, uvp_post_create_cq_t, uvp_pre_resize_cq, +* uvp_post_resize_cq_t, uvp_pre_query_cq, uvp_post_query_cq_t, +* uvp_post_destroy_cq_t +* +********/ + +/********/ + +/****f* user-mode Verbs/uvp_post_destroy_cq_t +* NAME +* uvp_post_destroy_cq_t -- Post-ioctl function to Destroy a CQ. +* +* SYNOPSIS +*/ + +typedef void +(AL_API *uvp_post_destroy_cq_t) ( + IN const ib_cq_handle_t h_uvp_cq, + IN ib_api_status_t ioctl_status ); + +/* +* DESCRIPTION +* uvp_post_destroy_cq_t() is implemented by vendor to destroy CQ. +* It is the post-ioctl routine for ib_destroy_cq(). +* UAL invokes this post-ioctl routine to destroy CQ when it receives +* asynchronous notification from the user-mode proxy. +* +* PARAMETERS +* h_uvp_cq +* [in] Vendor's Handle to the cq (in user-mode library) +* that needs to be destroyed. +* RETURN VALUE +* This function does not return a value. +* +* PORTABILITY +* User mode. +* +* SEE ALSO +* uvp_pre_create_cq, uvp_post_create_cq_t, uvp_pre_resize_cq, +* uvp_post_resize_cq_t, uvp_pre_query_cq, uvp_post_query_cq_t, +* uvp_pre_destroy_cq +* +********/ + +/********/ + +/****f* user-mode Verbs/uvp_pre_create_mw +* NAME +* uvp_pre_create_mw -- Pre-ioctl function to create a memory window +* +* SYNOPSIS +*/ + +typedef ib_api_status_t +(AL_API *uvp_pre_create_mw) ( + IN const ib_pd_handle_t h_uvp_pd, + IN OUT ci_umv_buf_t *p_umv_buf, + OUT ib_mw_handle_t *ph_uvp_mw); +/* +* DESCRIPTION +* uvp_pre_create_mw() is implemented by vendor. It is the pre-ioctl routine +* for ib_create_mw(). +* +* PARAMETERS +* h_uvp_pd +* [in] Vendor's Protection domain handle (in user-mode library) +* to use for this memory window +* p_umv_buf +* [in out] On input, UAL provides this buffer template. +* On return from this function, p_umv_buf contains +* any vendor-specific record to be exchanged with the vendor's +* HCA driver. +* ph_uvp_mw +* [out] (OPTIONAL) Vendor's Handle to the newly created memory window. +* +* RETURN VALUE +* IB_SUCCESS +* The memory window allocation completed successfully. +* IB_INSUFFICIENT_RESOURCES +* Not enough resources to complete the request. +* IB_INVALID_PD_HANDLE +* pd_handle supplied is invalid. +* +* PORTABILITY +* User mode +* +* SEE ALSO +* uvp_post_create_mw_t, uvp_pre_query_mw, uvp_post_query_mw_t, +* uvp_bind_mw, uvp_pre_destroy_mw, uvp_post_destroy_mw_t +* +********/ + + +/********/ + + +/****f* user-mode Verbs/uvp_post_create_mw_t +* NAME +* uvp_post_create_mw_t -- Post-ioctl function to create a memory window +* +* SYNOPSIS +*/ + +typedef void +(AL_API *uvp_post_create_mw_t) ( + IN const ib_pd_handle_t h_uvp_pd, + IN ib_api_status_t ioctl_status, + IN net32_t rkey, + IN OUT ib_mw_handle_t *ph_uvp_mw, + IN ci_umv_buf_t *p_umv_buf ); +/* +* DESCRIPTION +* uvp_post_create_mw_t() is implemented by vendor. It is the post-ioctl routine +* for ib_create_mw(). +* +* PARAMETERS +* h_uvp_pd +* [in] Vendor's Protection domain handle (in user-mode library) +* to use for this memory window +* ioctl_status +* [in] The ioctl status of the AL API. +* p_rkey +* [in] Remote access key that can be exchanged with a remote node to +* perform RDMA transactions on this memory window. +* ph_uvp_mw +* [in out] Vendor's Handle to the newly created memory window. +* If it specified in pre function than it must be the same value here. +* p_umv_buf +* [in out] On input, it contains any vendor-specific private information +* exchanged with the vendor's Verbs Provider Driver (uvp_pre_create_mw). +* Vendor is expected to check vendor-specific status in +* umv_buf as appropriate. +* +* RETURN VALUE +* This function does not return an error. +* +* PORTABILITY +* User mode +* +* SEE ALSO +* uvp_pre_create_mw, uvp_pre_query_mw, uvp_post_query_mw_t, +* uvp_bind_mw, uvp_pre_destroy_mw, uvp_post_destroy_mw_t +* +********/ + +/********/ + +/****f* user-mode Verbs/uvp_pre_query_mw +* NAME +* uvp_pre_query_mw -- Pre-ioctl to Query a memory window +* +* SYNOPSIS +*/ + +typedef ib_api_status_t +(AL_API *uvp_pre_query_mw) ( + IN const ib_mw_handle_t h_uvp_mw, + IN OUT ci_umv_buf_t *p_umv_buf ); + +/* +* DESCRIPTION +* uvp_pre_query_mw is implemented by vendor. It is the pre-ioctl routine +* for ib_query_mw(). +* +* PARAMETERS +* h_uvp_mw +* [in] Vendor's Memory window handle (in user-mode library) +* whose attributes are being retrieved. +* p_umv_buf +* [in out] On input, UAL provides this buffer template. +* On return from this function, p_umv_buf contains +* any vendor-specific record to be exchanged with the vendor's +* HCA driver. +* RETURN VALUE +* IB_SUCCESS +* The pre-ioctl call completed successfully. +* IB_INVALID_MW_HANDLE +* mw_handle supplied is an invalid handle. +* IB_INSUFFICIENT_RESOURCES +* Not enough resources to complete the request. +* +* PORTABILITY +* User mode +* +* SEE ALSO +* uvp_pre_create_mw, uvp_post_create_mw_t, uvp_post_query_mw_t, +* uvp_bind_mw, uvp_pre_destroy_mw, uvp_post_destroy_mw_t +* +********/ + +/********/ + +/****f* user-mode Verbs/uvp_post_query_mw_t +* NAME +* uvp_post_query_mw_t -- Post-ioctl to Query a memory window +* +* SYNOPSIS +*/ + +typedef void +(AL_API *uvp_post_query_mw_t) ( + IN const ib_mw_handle_t h_uvp_mw, + IN ib_api_status_t ioctl_status, + IN net32_t rkey, + OUT ib_pd_handle_t *ph_pd, + IN ci_umv_buf_t *p_umv_buf ); +/* +* DESCRIPTION +* uvp_post_query_mw_t is implemented by vendor. It is the post-ioctl routine +* for ib_query_mw(). +* +* PARAMETERS +* h_uvp_mw +* [in] Vendor's Memory window handle (in user-mode library) +* whose attributes are being retrieved. +* ioctl_status +* [in] The ioctl status of the AL API. +* rkey +* [in] Current R_KEY associated with this mw_handle +* ph_pd +* [in] Protection domain handle associated with this mw_handle +* p_umv_buf +* [in out] On input, it contains any vendor-specific private information +* exchanged with the vendor's Verbs Provider Driver (uvp_pre_query_mw). +* Vendor is expected to check vendor-specific status in +* umv_buf as appropriate. +* +* RETURN VALUE +* IB_SUCCESS +* The query operation completed successfully. +* +* PORTABILITY +* User mode +* +* SEE ALSO +* uvp_pre_create_mw, uvp_post_create_mw_t, uvp_pre_query_mw, +* uvp_bind_mw, uvp_pre_destroy_mw, uvp_post_destroy_mw_t +* +********/ + +/********/ + +/****f* user-mode Verbs/uvp_bind_mw +* NAME +* uvp_bind_mw -- Bind a memory window to a memory region. +* +* SYNOPSIS +*/ + +typedef ib_api_status_t +(AL_API *uvp_bind_mw) ( + IN const ib_mw_handle_t h_uvp_mw, + IN const ib_qp_handle_t h_uvp_qp, + IN ib_bind_wr_t *p_mw_bind, + OUT net32_t* const p_rkey ); +/* +* DESCRIPTION +* This routine posts a request to bind a memory window to a registered +* memory region. If the queue pair was created with selectable signaling, +* once the operation is completed successfully then a completion queue entry +* is generated indicating the bind operation has completed. The IB_POST_FENCE +* option could be specified to cause the requestor to wait until outstanding +* RDMA operations can be completed. +* +* PARAMETERS +* h_uvp_mw +* [in] Vendor's Handle (in user-mode library) to memory window +* that needs to be bound to a memory region. +* h_uvp_qp +* [in] Vendor's QP Handle (in user-mode library) to which +* this bind request is to be posted. +* p_mw_bind +* [in] Input parameters for this bind request, consisting of virtual +* addr range of bind request etc. On successful completion, the new R_KEY +* is returned. +* p_rkey +* [out] Current R_KEY associated with this mw_handle +* +* RETURN VALUE +* IB_SUCCESS +* The memory bind operation was posted successfully. +* IB_INSUFFICIENT_RESOURCES +* Insufficient resources to complete the request. +* No more WQE's to post this request +* No more free WQE's to post this request +* IB_INVALID_MW_HANDLE +* memw_handle supplied is an invalid memory window handle. +* IB_INVALID_PERMISSION +* Invalid access rights specified in request +* IB_INVALID_SERVICE_TYPE +* Invalid service type for this qp_handle. +* IB_INVALID_PARAMETER +* Address or length parameter specified is invalid. +* IB_INVALID_RKEY +* R_KEY specified is invalid for the memory region being bound. +* +* PORTABILITY +* User mode. +* +* SEE ALSO +* uvp_pre_create_mw, uvp_post_create_mw_t, uvp_pre_query_mw, +* uvp_post_query_mw_t, uvp_pre_destroy_mw, uvp_post_destroy_mw_t +* +********/ + +/********/ + +/****f* user-mode Verbs/uvp_pre_destroy_mw +* NAME +* uvp_pre_destroy_mw -- Pre-ioctl function to destroy a memory window +* +* SYNOPSIS +*/ + +typedef ib_api_status_t +(AL_API *uvp_pre_destroy_mw) ( + IN const ib_mw_handle_t h_uvp_mw ); + +/* +* DESCRIPTION +* uvp_pre_destroy_mw() is implemented by vendor. It is the pre-ioctl routine +* for ib_destroy_mw(). +* +* +* PARAMETERS +* h_uvp_mw +* [in] Vendor's handle (in user-mode library) to the memory window +* +* RETURN VALUE +* IB_SUCCESS +* Pre-ioctl succeeded. +* +* PORTABILITY +* User mode + +* SEE ALSO +* uvp_pre_create_mw, uvp_post_create_mw_t, uvp_pre_query_mw, +* uvp_post_query_mw_t, uvp_bind_mw, uvp_post_destroy_mw_t +* +********/ + +/********/ + +/****f* user-mode Verbs/uvp_post_destroy_mw_t +* NAME +* uvp_post_destroy_mw_t -- Post-ioctl function to destroy a memory window +* +* SYNOPSIS +*/ + +typedef void +(AL_API *uvp_post_destroy_mw_t) ( + IN const ib_mw_handle_t h_uvp_mw, + IN ib_api_status_t ioctl_status ); +/* +* DESCRIPTION +* uvp_post_destroy_mw_t() is implemented by vendor. It is the post-ioctl +* routine to destroy a memory window. +* +* +* PARAMETERS +* h_uvp_mw +* [in] Vendor's handle to the memory window +* +* RETURN VALUE +* IB_SUCCESS +* Destroy operation successful. +* +* PORTABILITY +* User mode +* +* SEE ALSO +* uvp_pre_create_mw, uvp_post_create_mw_t, uvp_pre_query_mw, +* uvp_post_query_mw_t, uvp_bind_mw, uvp_pre_destroy_mw +* +********/ + +/********/ + +/****f* user-mode Verbs/uvp_post_send +* NAME +* uvp_post_send -- Post a work request to the send side of a queue pair. +* +* SYNOPSIS +*/ + +typedef ib_api_status_t +(AL_API *uvp_post_send) ( + IN const void* h_qp, + IN ib_send_wr_t* const p_send_wr, + OUT ib_send_wr_t** pp_send_failure ); +/* +* DESCRIPTION +* This routine posts a work request to the send side of the queue pair. +* The different types of work request that can be posted are explained in +* the ib_wr_t structure. For exact details on ordering rules please consult +* the Volume 1, of the InfiniBand Specifications. If there is more +* outstanding requests posted that what the queue is configured for, an +* immediate error is returned. +* +* PARAMETERS +* h_qp +* [in] Type-cast as appropriate for user/kernel mode, this is +* the Queue pair handle to which the receive work request is being +* posted. +* p_send_wr +* [in] List of work requests that needs to be send. +* pp_send_failure +* [out] The work requests that failed. +* +* RETURN VALUE +* Any unsuccessful status indicates the status of the first failed request. +* +* IB_SUCCESS +* All the work requests are completed successfully +* IB_INVALID_QP_HANDLE +* The qp_handle supplied is invalid. +* IB_INSUFFICIENT_RESOURCES +* Insufficient resources to complete the request. +* There are no more work elements in the channel interface to +* process this request, and the total outstanding work request has +* been exceeded. +* IB_INVALID_WR_TYPE +* The work request type was not valid. +* IB_INVALID_QP_STATE +* The queue pair is either in Reset, Init, RTR or Error state. +* IB_INVALID_MAX_SGE +* The work request has too many scatter gather elements than what the +* QP is configured. +* IB_UNSUPPORTED +* Atomics or Reliable datagram request is not supported by this HCA. +* IB_INVALID_ADDR_HANDLE +* Address handle supplied in the work request is invalid. +* IB_INVALID_PARAMETER +* The size of the inline data is too much. +* +* PORTABILITY +* Kernel & User mode. +* +* NOTES +* Please refer to Table 81 and Table 82 for allowed operation types +* on different types of queue pairs, and the different modifiers +* acceptable for the work request for different QP service types. +* +* SEE ALSO +* uvp_post_recv, uvp_poll_cq +* +********/ + +/********/ + +/****f* user-mode Verbs/uvp_post_recv +* NAME +* uvp_post_recv -- Post a work request to the receive queue of a queue pair. +* +* SYNOPSIS +*/ + +typedef ib_api_status_t +(AL_API *uvp_post_recv) ( + IN const void* h_qp, + IN ib_recv_wr_t* const p_recv_wr, + OUT ib_recv_wr_t** pp_recv_failure ); + +/* +* DESCRIPTION +* This routine allows to queue a work request to the receive side of a +* queue pair. The work_req holds necessary data to satisfy an incoming +* receive message. If an attempt is made to queue more work requests than +* what is available, an error is returned. +* +* PARAMETERS +* h_qp +* [in] Type-cast as appropriate for user/kernel mode, this is +* the Queue pair handle to which the receive work request is being +* posted. +* p_recv_wr +* [in] List of recv work requests that needs to be posted. +* pp_recv_failure +* [out] The work requests that failed. + +* RETURN VALUE +* Any unsuccessful status indicates the status of the first failed request. +* +* IB_SUCCESS +* The work request was successfully queued to the receive side of the QP. +* IB_INVALID_QP_HANDLE +* qp_handle supplied is not valid. +* IB_INSUFFICIENT_RESOURCES +* The qp has exceeded its receive queue depth than what is has been +* configured. +* IB_INVALID_WR_TYPE +* Invalid work request type found in the request. +* IB_INVALID_QP_STATE +* QP was in reset or init state. +* (TBD: there may be an errata that allows posting in init state) +* +* PORTABILITY +* Kernel & User mode. +* +* SEE ALSO +* uvp_post_send, uvp_poll_cq +* +********/ + +/********/ + +/****f* user-mode Verbs/uvp_post_srq_recv +* NAME +* uvp_post_srq_recv -- Post a work request to the shared receive queue of a queue pair. +* +* SYNOPSIS +*/ + +typedef ib_api_status_t +(AL_API *uvp_post_srq_recv) ( + IN const void* h_srq, + IN ib_recv_wr_t* const p_recv_wr, + OUT ib_recv_wr_t** pp_recv_failure ); + +/* +* DESCRIPTION +* This routine allows to queue a work request to the receive side of a shared +* queue pair. The work_req holds necessary data to satisfy an incoming +* receive message. If an attempt is made to queue more work requests than +* what is available, an error is returned. +* +* PARAMETERS +* h_srq +* [in] Type-cast as appropriate for user/kernel mode, this is +* the shared Queue pair handle to which the receive work request is being +* posted. +* p_recv_wr +* [in] List of recv work requests that needs to be posted. +* pp_recv_failure +* [out] The work requests that failed. + +* RETURN VALUE +* Any unsuccessful status indicates the status of the first failed request. +* +* IB_SUCCESS +* The work request was successfully queued to the receive side of the QP. +* IB_INVALID_SRQ_HANDLE +* srq_handle supplied is not valid. +* IB_INSUFFICIENT_RESOURCES +* The qp has exceeded its receive queue depth than what is has been +* configured. +* IB_INVALID_WR_TYPE +* Invalid work request type found in the request. +* +* PORTABILITY +* Kernel & User mode. +* +* SEE ALSO +* +********/ + +/********/ + +/****f* user-mode Verbs/uvp_peek_cq +* NAME +* uvp_peek_cq +* +* DESCRIPTION +* Returns the number of entries currently on the completion queue. +* +* SYNOPSIS +*/ + +typedef ib_api_status_t +(AL_API *uvp_peek_cq) ( + IN const void* h_cq, + OUT uint32_t* const p_n_cqes ); + +/* +* PARAMETERS +* h_cq +* [in] Type-cast as appropriate for user/kernel mode, this is the +* CQ handle for the completion queue being peeked. +* +* p_n_cqes +* [out] Upon successful completion of this call, contains the number +* of completion queue entries currently on the completion queue. +* +* RETURN VALUES +* IB_SUCCESS +* The peek operation completed successfully. +* +* IB_INVALID_CQ_HANDLE +* The completion queue handle was invalid. +* +* IB_INVALID_PARAMETER +* A reference to the completion queue entry count was not provided. +* +* PORTABILITY +* Kernel and User mode +* +* SEE ALSO +* uvp_pre_create_cq, uvp_post_create_cq_t, uvp_poll_cq, uvp_rearm_cq, +* uvp_rearm_n_cq +*****/ + +/********/ + +/****f* user-mode Verbs/uvp_poll_cq +* NAME +* uvp_poll_cq -- Retrieve a work completion record from a completion queue +* SYNOPSIS +*/ + +typedef ib_api_status_t +(AL_API *uvp_poll_cq) ( + IN const void* h_cq, + IN OUT ib_wc_t** const pp_free_wclist, + OUT ib_wc_t** const pp_done_wclist ); + +/* +* DESCRIPTION +* This routine retrieves a work completion entry from the specified +* completion queue. The contents of the data returned in a work completion +* is specified in ib_wc_t. +* +* PARAMETERS +* h_cq +* [in] Type-cast as appropriate for user/kernel mode, this is +* the CQ handle for the completion queue being polled. +* pp_free_wclist +* [in out] A list of work request structures provided by the consumer +* for the channel interface to return completed Completion Queue +* entries. If not all the entries are consumed, this list holds the +* list of un-utilized completion entries provided back to the consumer. +* pp_done_wclist +* [out] A list of work completions retrieved from the completion queue +* and successfully processed. +* +* RETURN VALUE +* IB_SUCCESS +* Poll completed successfully. If on completion the wc_free list is +* empty, then there are potentially more entries and the consumer must +* be ready to retrieve entries further. +* IB_INVALID_CQ_HANDLE +* The cq_handle supplied is not valid. +* IB_NOT_FOUND +* There are no more entries found in the specified CQ. +* +* PORTABILITY +* Kernel & User mode. +* +* SEE ALSO +* uvp_pre_create_cq, uvp_post_create_cq_t, uvp_rearm_cq, +* uvp_rearm_n_cq, uvp_post_send, uvp_post_recv +* +********/ + +/********/ + +/* + * Define uvp_wc_t so that we can cast directly to ib_wc_t. + */ +typedef struct _uvp_wc +{ + void* qp_context; + /* If pointer size is 32-bits, then compiler will pad before uint64_t */ + uint64_t wr_id; + ib_wc_type_t wc_type; + + uint32_t length; + uint64_t vendor_specific; + ib_wc_status_t status; + + union _uvp_wc_recv + { + struct _uvp_wc_conn + { + ib_recv_opt_t recv_opt; + ib_net32_t immediate_data; + + } conn; + + struct _uvp_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; + } recv; +} uvp_wc_t; + +typedef int +(AL_API *uvp_poll_cq_array) ( + IN const void* h_cq, + IN const int num_entries, + IN OUT uvp_wc_t* const wcs); + +/********/ + +/****f* user-mode Verbs/uvp_rearm_cq +* NAME +* uvp_rearm_cq -- Invoke the Completion handler, on next entry added. +* +* SYNOPSIS +*/ + +typedef ib_api_status_t +(AL_API *uvp_rearm_cq) ( + IN const void* h_cq, + IN const boolean_t solicited ); + +/* +* DESCRIPTION +* This routine instructs the channel interface to invoke the completion +* handler when the next completion queue entry is added to this CQ. +* Please refer to Volume 1, of the InfiniBand specification for a complete +* description. +* +* PARAMETERS +* h_cq +* [in] Type-cast as appropriate for user/kernel mode, this is the +* CQ handle for the completion queue being armed. +* solicited +* [in] A boolean flag indicating whether the request is to generate a +* notification on the next entry or on the next solicited entry +* being added to the completion queue. +* +* RETURN VALUE +* IB_SUCCESS +* The notification request was registered successfully. +* IB_INVALID_CQ_HANDLE +* cq_handle supplied is not a valid handle. +* +* PORTABILITY +* Kernel and User mode +* +* SEE ALSO +* uvp_pre_create_cq, uvp_post_create_cq_t, uvp_peek_cq, uvp_poll_cq, +* uvp_rearm_n_cq +* +********/ + +/********/ + +/****f* user-mode Verbs/uvp_rearm_n_cq +* NAME +* uvp_rearm_n_cq -- Invoke the Completion handler, when next +* N completions have been added to this CQ. +* +* SYNOPSIS +*/ + +typedef ib_api_status_t +(AL_API *uvp_rearm_n_cq) ( + IN const void* h_cq, + IN const uint32_t n_cqes ); + +/* +* DESCRIPTION +* This routine instructs the channel interface to invoke the completion +* handler when the next N completions are added to this CQ. +* +* PARAMETERS +* h_cq +* [in] Type-cast as appropriate for user/kernel mode, this is the +* CQ handle for the completion queue being armed. +* n_cqes +* [in] The number of completion queue entries to be added to the +* completion queue before notifying the client. This value must +* greater than or equal to one and less than or equal to the size +* of the completion queue. +* +* RETURN VALUE +* IB_SUCCESS +* The notification request was registered successfully. +* IB_INVALID_CQ_HANDLE +* cq_handle supplied is not a valid handle. +* IB_INVALID_PARAMETER +* The requested number of completion queue entries was invalid. +* +* PORTABILITY +* Kernel and User mode +* +* SEE ALSO +* uvp_pre_create_cq, uvp_post_create_cq_t, uvp_peek_cq, uvp_poll_cq, +* uvp_rearm_cq +* +********/ + +/********/ + +/****f* user-mode Verbs/uvp_pre_attach_mcast +* NAME +* uvp_pre_attach_mcast -- Pre-ioctl function to Attach a queue pair +* to a multicast group +* +* SYNOPSIS +*/ + +typedef ib_api_status_t +(AL_API *uvp_pre_attach_mcast) ( + IN const ib_qp_handle_t h_uvp_qp, + IN const ib_gid_t *p_mcast_gid, + IN const uint16_t mcast_lid, + IN OUT ci_umv_buf_t *p_umv_buf, + OUT ib_mcast_handle_t *ph_mcast); + +/* +* DESCRIPTION +* uvp_pre_attach_mcast() is the pre-ioctl routine implemented by vendor +* to attach a queue pair to a multicast group. +* +* PARAMETERS +* h_uvp_qp +* [in] Vendor's Queue pair handle (in user-mode library) +* which needs to be added to the multicast group on the adapter. +* mcast_lid +* [in] The multicast group LID value. +* p_mcast_gid +* [in] IPv6 address associated with this multicast group. +* p_umv_buf +* [in out] On input, UAL provides this buffer template. +* On return from this function, p_umv_buf contains +* any vendor-specific record to be exchanged with the vendor's +* HCA driver. +* ph_mcast +* [out] (OPTIONAL) Vendor's Handle to the newly created Multicast handle +* holding the association of this queue pair to the multicast group. +* +* RETURN VALUE +* IB_SUCCESS +* The queue pair handle was successfully added to the multicast +* group. +* IB_INVALID_QP_HANDLE +* qp_handle supplied is invalid. +* IB_INVALID_SERVICE_TYPE +* Queue pair handle supplied is not of unreliable datagram type. +* IB_INVALID_GID +* The supplied addr is not a valid multicast ipv6 address. +* IB_INSUFFICIENT_RESOURCES +* Insufficient resources to complete the request. +* +* PORTABILITY +* User mode. +* +* SEE ALSO +* uvp_pre_create_qp, uvp_post_create_qp_t, uvp_post_attach_mcast_t, +* uvp_pre_detach_mcast, uvp_post_detach_mcast_t +* +********/ + +/********/ + +/****f* user-mode Verbs/uvp_post_attach_mcast_t +* NAME +* uvp_post_attach_mcast_t -- Post-ioctl function to Attach a queue pair +* to a multicast group +* +* SYNOPSIS +*/ + +typedef void +(AL_API *uvp_post_attach_mcast) ( + IN const ib_qp_handle_t h_uvp_qp, + IN ib_api_status_t ioctl_status, + IN OUT ib_mcast_handle_t *ph_mcast, + IN ci_umv_buf_t *p_umv_buf ); + +/* +* DESCRIPTION +* uvp_post_attach_mcast_t() is the post-ioctl routine implemented by vendor +* to attach a queue pair to a multicast group. +* +* PARAMETERS +* h_uvp_qp +* [in] Vendor's Queue pair handle (in user-mode library) +* which needs to be added to +* the multicast group on the adapter. +* ioctl_status +* [in] The ioctl status of the AL API. +* ph_mcast +* [in out] Vendor's Multicast handle, +* holding the association of this queue pair to the multicast group. +* If it specified in pre function than it must be the same value here. +* p_umv_buf +* [in out] On input, it contains any vendor-specific private information +* exchanged with the vendor's Verbs Provider Driver (uvp_pre_attach_mcast) +* Vendor is expected to check vendor-specific status in +* umv_buf as appropriate. +* +* RETURN VALUE +* This function does not return a value. +* +* PORTABILITY +* Kernel & User mode. +* +* SEE ALSO +* uvp_pre_create_qp, uvp_post_create_qp_t, uvp_pre_attach_mcast, +* uvp_pre_detach_mcast, uvp_post_detach_mcast_t +* +********/ + +/********/ + +/****f* user-mode Verbs/uvp_pre_detach_mcast +* NAME +* uvp_pre_detach_mcast -- Pre-ioctl function to detach a queue pair +* to a multicast group +* +* SYNOPSIS +*/ + +typedef ib_api_status_t +(AL_API *uvp_pre_detach_mcast) ( + IN ib_mcast_handle_t h_uvp_mcast ); + +/* +* DESCRIPTION +* uvp_pre_attach_mcast() is the pre-ioctl routine implemented by vendor +* to attach a queue pair to a multicast group. +* Upon return from the pre-ioctl function, UAL packages up the UMV buffer +* in an IOCTL and passes it on to the user-mode proxy. UAL passes the +* info to the user-mode proxy stating that it no longer wishes to receive +* callback for mcast join for the caller. Note that UAL takes care of +* handling callbcak. +* +* PARAMETERS +* h_uvp_mcast +* [in] Vendor's Multicast handle (in user-mode library) +* holding the association of this queue pair to the multicast group. +* +* RETURN VALUE +* IB_SUCCESS +* The queue pair handle was successfully added to the multicast +* group. +* +* PORTABILITY +* Kernel & User mode. +* +* SEE ALSO +* uvp_pre_create_qp, uvp_post_create_qp_t, uvp_pre_attach_mcast, +* uvp_post_attach_mcast_t, uvp_post_detach_mcast_t +* +********/ + +/********/ + +/****f* user-mode Verbs/uvp_post_detach_mcast_t +* NAME +* uvp_post_detach_mcast_t -- Post-ioctl function to detach a queue pair +* from a multicast group +* +* SYNOPSIS +*/ + +typedef void +(AL_API *uvp_post_detach_mcast) ( + IN ib_mcast_handle_t h_uvp_mcast, + IN ib_api_status_t ioctl_status ); + +/* +* DESCRIPTION +* uvp_post_detach_mcast_t() is the post-ioctl routine implemented by vendor +* to attach a queue pair to a multicast group. +* +* PARAMETERS +* h_uvp_mcast +* [out] Vendor's Multicast handle holding the association of this +* queue pair to the multicast group. +* ioctl_status +* [in] The ioctl status of the AL API. +* +* RETURN VALUE +* This function does not return a value. +* +* PORTABILITY +* Kernel & User mode. +* +* SEE ALSO +* uvp_pre_create_qp, uvp_post_create_qp_t, uvp_pre_attach_mcast, +* uvp_post_attach_mcast_t, uvp_pre_detach_mcast +* +********/ + +/********/ + +/****s* user-mode Verbs/uvp_interface_t +* NAME +* uvp_interface_t -- Interface holding supported Vendor APIs +* +* PURPOSE +* The following structure is supplied by a Vendor library +* providing verbs functionality. +* +* SOURCE +*/ +typedef struct _uvp_interface +{ + uvp_pre_open_ca_t pre_open_ca; + uvp_post_open_ca_t post_open_ca; + uvp_pre_query_ca pre_query_ca; + uvp_post_query_ca_t post_query_ca; + uvp_pre_modify_ca pre_modify_ca; + uvp_post_modify_ca_t post_modify_ca; + uvp_pre_close_ca_t pre_close_ca; + uvp_post_close_ca_t post_close_ca; + + uvp_pre_ci_call pre_ci_call; + uvp_post_ci_call post_ci_call; + + uvp_pre_allocate_pd pre_allocate_pd; + uvp_post_allocate_pd_t post_allocate_pd; + uvp_pre_deallocate_pd pre_deallocate_pd; + uvp_post_deallocate_pd_t post_deallocate_pd; + + uvp_pre_create_av pre_create_av; + uvp_post_create_av_t post_create_av; + uvp_pre_query_av pre_query_av; + uvp_post_query_av_t post_query_av; + uvp_pre_modify_av pre_modify_av; + uvp_post_modify_av_t post_modify_av; + uvp_pre_destroy_av pre_destroy_av; + uvp_post_destroy_av_t post_destroy_av; + + uvp_pre_create_srq pre_create_srq; + uvp_post_create_srq_t post_create_srq; + uvp_pre_modify_srq pre_modify_srq; + uvp_post_modify_srq_t post_modify_srq; + uvp_pre_query_srq pre_query_srq; + uvp_post_query_srq_t post_query_srq; + uvp_pre_destroy_srq pre_destroy_srq; + uvp_post_destroy_srq_t post_destroy_srq; + + uvp_pre_create_qp pre_create_qp; + uvp_post_create_qp_t post_create_qp; + uvp_pre_modify_qp pre_modify_qp; + uvp_post_modify_qp_t post_modify_qp; + uvp_pre_query_qp pre_query_qp; + uvp_post_query_qp_t post_query_qp; + uvp_pre_destroy_qp pre_destroy_qp; + uvp_post_destroy_qp_t post_destroy_qp; + + uvp_pre_create_cq pre_create_cq; + uvp_post_create_cq_t post_create_cq; + uvp_pre_query_cq pre_query_cq; + uvp_post_query_cq_t post_query_cq; + uvp_pre_resize_cq pre_resize_cq; + uvp_post_resize_cq_t post_resize_cq; + uvp_pre_destroy_cq pre_destroy_cq; + uvp_post_destroy_cq_t post_destroy_cq; + + uvp_pre_create_mw pre_create_mw; + uvp_post_create_mw_t post_create_mw; + uvp_pre_query_mw pre_query_mw; + uvp_post_query_mw_t post_query_mw; + uvp_pre_destroy_mw pre_destroy_mw; + uvp_post_destroy_mw_t post_destroy_mw; + + uvp_bind_mw bind_mw; + uvp_post_send post_send; + uvp_post_recv post_recv; + uvp_post_srq_recv post_srq_recv; + + uvp_peek_cq peek_cq; + uvp_poll_cq poll_cq; + uvp_rearm_cq rearm_cq; + uvp_rearm_n_cq rearm_n_cq; + + uvp_pre_attach_mcast pre_attach_mcast; + uvp_post_attach_mcast post_attach_mcast; + uvp_pre_detach_mcast pre_detach_mcast; + uvp_post_detach_mcast post_detach_mcast; + + uvp_nd_modify_qp_t nd_modify_qp; + uvp_nd_get_qp_state_t nd_get_qp_state; + uvp_wv_pre_create_qp wv_pre_create_qp; + uvp_poll_cq_array poll_cq_array; + +} uvp_interface_t; + +/********/ + +// {A1F1EA66-4D17-4d04-B910-893F658241D0} +DEFINE_GUID(IID_UVP, +0xa1f1ea66, 0x4d17, 0x4d04, 0xb9, 0x10, 0x89, 0x3f, 0x65, 0x82, 0x41, 0xd0); + +/****f* user-mode Verbs/uvp_get_interface +* NAME +* uvp_get_interface -- Get the Vendor's supported function calls +* +* SYNOPSIS +*/ +typedef ib_api_status_t +(AL_API *uvp_get_interface_t)( + IN GUID iid, + IN OUT void* pifc); +/* +* DESCRIPTION +* This routine is called to get the functions supported by +* a vendor's library. It may be used to obtain the list of +* verb calls supported by a vendor. +* +* If the vendor does not support an interface, it should returns +* IB_UNSUPPORTED. The specific details of each interface returned +* is dependent upon the requested interface. +* +* PARAMETERS +* iid +* [in] GUID of the requested interface. +* pifc +* [in out] Pointer to the structure that that will receive the +* interface functions. +* +* RETURN VALUE +* IB_SUCCESS +* The interface was returned successfully. +* IB_UNSUPPORTED +* The requested interface isn't supported by the vendor's library. +* +* PORTABILITY +* User mode +* +* SEE ALSO +* uvp_interface_t +* +********/ + +#endif // __IB_UAL_UVP_H__ diff --git a/branches/WOF2-3/inc/user/iba/ibat.h b/branches/WOF2-3/inc/user/iba/ibat.h new file mode 100644 index 00000000..6e84486c --- /dev/null +++ b/branches/WOF2-3/inc/user/iba/ibat.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id:$ + */ + +#ifndef _IBAT_H_ +#define _IBAT_H_ + +#include +#include + +typedef struct _IBAT_PATH_BLOB +{ + UINT8 byte[64]; + +} IBAT_PATH_BLOB; + +#ifdef __cplusplus +namespace IBAT +{ + +HRESULT +Resolve( + __in const struct sockaddr* pSrcAddr, + __in const struct sockaddr* pDestAddr, + __out IBAT_PATH_BLOB* pPath + ); + +HRESULT +ResolvePath( + __in const struct sockaddr* pSrcAddr, + __in const struct sockaddr* pDestAddr, + __out IBAT_PATH_BLOB* pPath, + __in DWORD Timeout /* ms */ + ); + +} +#else /* __cplusplus */ + +HRESULT +IbatResolve( + __in const struct sockaddr* pSrcAddr, + __in const struct sockaddr* pDestAddr, + __out IBAT_PATH_BLOB* pPath + ); + +HRESULT +IbatResolvePath( + __in const struct sockaddr* pSrcAddr, + __in const struct sockaddr* pDestAddr, + __out IBAT_PATH_BLOB* pPath, + __in DWORD Timeout /* ms */ + ); + +#endif /* __cplusplus */ + +#endif // _IBAT_H_ diff --git a/branches/WOF2-3/inc/user/iba/winmad.h b/branches/WOF2-3/inc/user/iba/winmad.h new file mode 100644 index 00000000..35261f55 --- /dev/null +++ b/branches/WOF2-3/inc/user/iba/winmad.h @@ -0,0 +1,162 @@ +/* + * Copyright (c) 1996-2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#ifndef _WINMAD_H_ +#define _WINMAD_H_ + +#include + +#include + +typedef UINT64 NET64; +typedef UINT32 NET32; +typedef UINT16 NET16; + +typedef struct _WM_REGISTER +{ + NET64 Guid; + NET32 Qpn; + UINT8 Port; + UINT8 Class; + UINT8 Version; + UINT8 Reserved[6]; + UINT8 Oui[3]; + UINT8 Methods[16]; + +} WM_REGISTER; + +typedef struct _WM_MAD_AV +{ + NET32 Qpn; + NET32 Qkey; + NET32 VersionClassFlow; + UINT16 PkeyIndex; + UINT8 HopLimit; + UINT8 GidIndex; + UINT8 Gid[16]; + + UINT16 Reserved; + NET16 Lid; + UINT8 ServiceLevel; + UINT8 PathBits; + UINT8 StaticRate; + UINT8 GrhValid; + +} WM_MAD_AV; + +#define WM_SUCCESS 0 +#define WM_TIMEOUT 138 + +#pragma warning(push) +#pragma warning(disable: 4200) +typedef struct _WM_MAD +{ + UINT64 Id; + WM_MAD_AV Address; + + UINT32 Status; + UINT32 Timeout; + UINT32 Retries; + UINT32 Length; + + UINT8 Data[0]; + +} WM_MAD; +#pragma warning(pop) + + +#undef INTERFACE +#define INTERFACE IWMProvider +// {66094220-A6C0-4206-B620-1D766DB2DE63} +DEFINE_GUID(IID_IWMProvider, 0x66094220, 0xa6c0, 0x4206, + 0xb6, 0x20, 0x1d, 0x76, 0x6d, 0xb2, 0xde, 0x63); + +DECLARE_INTERFACE_(IWMProvider, IUnknown) +{ + // IUnknown methods + __override STDMETHOD(QueryInterface)( + THIS_ + REFIID riid, + LPVOID FAR* ppvObj + ) PURE; + + __override STDMETHOD_(ULONG,AddRef)( + THIS + ) PURE; + + __override STDMETHOD_(ULONG,Release)( + THIS + ) PURE; + + // IWVProvider methods + STDMETHOD(CancelOverlappedRequests)( + THIS + ) PURE; + + STDMETHOD(GetOverlappedResult)( + THIS_ + __inout_opt OVERLAPPED *pOverlapped, + __out DWORD *pNumberOfBytesTransferred, + __in BOOL bWait + ) PURE; + + STDMETHOD_(HANDLE,GetFileHandle)( + THIS + ) PURE; + + STDMETHOD(Register)( + THIS_ + __in WM_REGISTER* pAttributes, + __deref_out UINT64* pId + ) PURE; + + STDMETHOD(Deregister)( + THIS_ + __in UINT64 Id + ) PURE; + + STDMETHOD(Send)( + THIS_ + __in WM_MAD* pMad, + __inout_opt OVERLAPPED *pOverlapped + ) PURE; + + STDMETHOD(Receive)( + THIS_ + __inout_bcount_part(*pBufferSize, *pBufferSize) WM_MAD* pMad, + __in SIZE_T pBufferSize, + __inout_opt OVERLAPPED *pOverlapped + ) PURE; +}; + +__declspec(dllexport) HRESULT WmGetObject(REFIID riid, LPVOID FAR* ppvObj); + +#endif // _WINMAD_H_ diff --git a/branches/WOF2-3/inc/user/linux/_errno.h b/branches/WOF2-3/inc/user/linux/_errno.h new file mode 100644 index 00000000..c3e59598 --- /dev/null +++ b/branches/WOF2-3/inc/user/linux/_errno.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2009 Intel Corp, 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 __ERRNO_H_ +#define __ERRNO_H_ + +#include + +/* provide defines missing in older errno.h */ +#ifndef EINVAL +#define EINVAL 22 +#define ERANGE 34 +#define EILSEQ 42 +#define STRUNCATE 80 +#endif + +#ifndef EADDRINUSE +#define EADDRINUSE 100 +#define EADDRNOTAVAIL 101 +#define EAFNOSUPPORT 102 +#define EALREADY 103 +#define EBADMSG 104 +#define ECANCELED 105 +#define ECONNABORTED 106 +#define ECONNREFUSED 107 +#define ECONNRESET 108 +#define EDESTADDRREQ 109 +#define EHOSTUNREACH 110 +#define EIDRM 111 +#define EINPROGRESS 112 +#define EISCONN 113 +#define ELOOP 114 +#define EMSGSIZE 115 +#define ENETDOWN 116 +#define ENETRESET 117 +#define ENETUNREACH 118 +#define ENOBUFS 119 +#define ENODATA 120 +#define ENOLINK 121 +#define ENOMSG 122 +#define ENOPROTOOPT 123 +#define ENOSR 124 +#define ENOSTR 125 +#define ENOTCONN 126 +#define ENOTRECOVERABLE 127 +#define ENOTSOCK 128 +#define ENOTSUP 129 +#define EOPNOTSUPP 130 +#define EOTHER 131 +#define EOVERFLOW 132 +#define EOWNERDEAD 133 +#define EPROTO 134 +#define EPROTONOSUPPORT 135 +#define EPROTOTYPE 136 +#define ETIME 137 +#define ETIMEDOUT 138 +#define ETXTBSY 139 +#define EWOULDBLOCK 140 +#endif + +#endif /* __ERRNO_H_ */ diff --git a/branches/WOF2-3/inc/user/linux/_string.h b/branches/WOF2-3/inc/user/linux/_string.h new file mode 100644 index 00000000..2cb17b21 --- /dev/null +++ b/branches/WOF2-3/inc/user/linux/_string.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2009 Intel Corp, 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 __STRING_H_ +#define __STRING_H_ + +#include + +#define strdup _strdup +#define strdupa _strdup +#define strncasecmp _strnicmp +#define strcasecmp _stricmp +#define strtoull _strtoui64 +#define strtouq _strtoui64 +#define strtok_r strtok_s + +#endif /* __STRING_H_ */ diff --git a/branches/WOF2-3/inc/user/linux/arpa/inet.h b/branches/WOF2-3/inc/user/linux/arpa/inet.h new file mode 100644 index 00000000..18c13a06 --- /dev/null +++ b/branches/WOF2-3/inc/user/linux/arpa/inet.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2009 Intel Corp, 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 _INET_H_ +#define _INET_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if WINVER < 0x600 +int inet_pton(int af, const char *src, void *dst); +const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _INET_H_ */ diff --git a/branches/WOF2-3/inc/user/linux/inttypes.h b/branches/WOF2-3/inc/user/linux/inttypes.h new file mode 100644 index 00000000..19776665 --- /dev/null +++ b/branches/WOF2-3/inc/user/linux/inttypes.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2009 Intel Corp, 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 _INTTYPES_H_ +#define _INTTYPES_H_ + +#endif /* _INTTYPES_H_ */ diff --git a/branches/WOF2-3/inc/user/linux/netdb.h b/branches/WOF2-3/inc/user/linux/netdb.h new file mode 100644 index 00000000..d41035eb --- /dev/null +++ b/branches/WOF2-3/inc/user/linux/netdb.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2009 Intel Corp, 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 _NETDB_H_ +#define _NETDB_H_ + +#endif /* _NETDB_H_ */ diff --git a/branches/WOF2-3/inc/user/linux/netinet/in.h b/branches/WOF2-3/inc/user/linux/netinet/in.h new file mode 100644 index 00000000..ebdff291 --- /dev/null +++ b/branches/WOF2-3/inc/user/linux/netinet/in.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2009 Intel Corp, 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 _IN_H_ +#define _IN_H_ + +#include + +#define ntohll _byteswap_uint64 +#define htonll ntohll + +#endif /* _IN_H_ */ diff --git a/branches/WOF2-3/inc/user/linux/search.h b/branches/WOF2-3/inc/user/linux/search.h new file mode 100644 index 00000000..2923a592 --- /dev/null +++ b/branches/WOF2-3/inc/user/linux/search.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2009 Intel Corp, 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 _SEARCH_H_ +#define _SEARCH_H_ + +#include + +//typedef enum +//{ +// preorder, +// postorder, +// endorder, +// leaf +// +//} VISIT; + +void *tsearch(const void *key, void **rootp, + int (*compar)(const void *, const void *)); +void *tfind(const void *key, void *const *rootp, + int (*compar)(const void *, const void *)); +/* tdelete returns key if found (not parent), otherwise NULL */ +void *tdelete(const void *key, void **rootp, + int (*compar)(const void *, const void *)); +//void twalk(const void *root, +// void (*action)(const void *, VISIT, int)); +//void tdestroy(void *root, void (*free_node)(void *nodep)); + +#endif /* _SEARCH_H_ */ diff --git a/branches/WOF2-3/inc/user/linux/sys/socket.h b/branches/WOF2-3/inc/user/linux/sys/socket.h new file mode 100644 index 00000000..9f4affb3 --- /dev/null +++ b/branches/WOF2-3/inc/user/linux/sys/socket.h @@ -0,0 +1,33 @@ +/* + * This software is available to you under the OpenFabrics.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION 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 _SOCKET_H_ +#define _SOCKET_H_ + +#include + +#endif diff --git a/branches/WOF2-3/inc/user/linux/sys/time.h b/branches/WOF2-3/inc/user/linux/sys/time.h new file mode 100644 index 00000000..36df6ab2 --- /dev/null +++ b/branches/WOF2-3/inc/user/linux/sys/time.h @@ -0,0 +1,41 @@ +/* + * This software is available to you under the OpenFabrics.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION 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 _SYS_TIME_H_ +#define _SYS_TIME_H_ + +#include + +struct timezone { + int tz_minuteswest; /* minutes west of Greenwich */ + int tz_dsttime; /* type of dst correction */ +}; + + +extern int gettimeofday(struct timeval *ptv, void *ignored); + +#endif diff --git a/branches/WOF2-3/inc/user/linux/unistd.h b/branches/WOF2-3/inc/user/linux/unistd.h new file mode 100644 index 00000000..6d17e37a --- /dev/null +++ b/branches/WOF2-3/inc/user/linux/unistd.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2009 Intel Corp, 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 _UNISTD_H_ +#define _UNISTD_H_ + +#include + +#define sleep(s) SleepEx(s * 1000, TRUE) + +static __inline int getdomainname(char *name, size_t len) +{ + return -1; +} + +static __inline char* getpass(char *message) +{ + static char password[128]; + + printf("%s", message); + scanf_s("%127s", password, 128); + return password; +} + +#endif /* _UNISTD_H_ */ diff --git a/branches/WOF2-3/inc/user/rdma/winverbs.h b/branches/WOF2-3/inc/user/rdma/winverbs.h new file mode 100644 index 00000000..933fe7a3 --- /dev/null +++ b/branches/WOF2-3/inc/user/rdma/winverbs.h @@ -0,0 +1,1551 @@ +/* + * Copyright (c) 1996-2010 Intel Corporation. All rights reserved. + * Copyright (c) 2010 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#ifndef _WINVERBS_H_ +#define _WINVERBS_H_ + +#include + +#include +#include +#include +#include + +typedef UINT16 NET16; +typedef UINT32 NET32; +typedef UINT64 NET64; + +typedef union _WV_GID // Network byte order +{ + UINT8 Raw[16]; + +} WV_GID; + +// Device/port capability flags +#define WV_DEVICE_RESIZE_MAX_WR 0x00000001 +#define WV_DEVICE_BAD_PKEY_COUNTER 0x00000002 +#define WV_DEVICE_BAD_QKEY_COUNTER 0x00000004 +// reserved 0x00000008 +#define WV_DEVICE_PATH_MIGRATION 0x00000010 +#define WV_DEVICE_CHANGE_PHYSICAL_PORT 0x00000020 +#define WV_DEVICE_AH_PORT_CHECKING 0x00000040 +#define WV_DEVICE_QP_STATE_MODIFIER 0x00000080 +#define WV_DEVICE_SHUTDOWN_PORT 0x00000100 +#define WV_DEVICE_INIT_TYPE 0x00000200 +#define WV_DEVICE_PORT_ACTIVE_EVENT 0x00000400 +#define WV_DEVICE_SYSTEM_IMAGE_GUID 0x00000800 +#define WV_DEVICE_RC_RNR_NAK_GENERATION 0x00001000 +#define WV_DEVICE_SRQ_RESIZE 0x00002000 +#define WV_DEVICE_BATCH_NOTIFY_CQ 0x00004000 + +typedef enum _WV_DEVICE_TYPE +{ + WvDeviceUnknown, + WvDeviceInfiniband, + WvDeviceIwarp + +} WV_DEVICE_TYPE; + +typedef enum _WV_ATOMIC_CAPABILITIES +{ + WvAtomicNone, + WvAtomicDevice, + WvAtomicNode + +} WV_ATOMIC_CAPABILITIES; + +typedef struct _WV_DEVICE_ATTRIBUTES +{ + UINT64 FwVersion; + NET64 NodeGuid; + NET64 SystemImageGuid; + UINT32 VendorId; + UINT32 VendorPartId; + UINT32 HwVersion; + DWORD CapabilityFlags; + WV_ATOMIC_CAPABILITIES AtomicCapability; + DWORD PageSizeCapabilityFlags; + SIZE_T MaxMrSize; + SIZE_T MaxQp; + SIZE_T MaxQpWr; + SIZE_T MaxSge; + SIZE_T MaxCq; + SIZE_T MaxCqEntries; + SIZE_T MaxMr; + SIZE_T MaxPd; + SIZE_T MaxQpResponderResources; + SIZE_T MaxResponderResources; + SIZE_T MaxQpInitiatorDepth; + SIZE_T MaxInlineSend; + SIZE_T MaxMw; + SIZE_T MaxMulticast; + SIZE_T MaxQpAttach; + SIZE_T MaxMulticastQp; + SIZE_T MaxAh; + SIZE_T MaxFmr; + SIZE_T MaxMapPerFmr; + SIZE_T MaxSrq; + SIZE_T MaxSrqWr; + SIZE_T MaxSrqSge; + SIZE_T MaxPkeys; + WV_DEVICE_TYPE DeviceType; + UINT8 LocalAckDelay; + UINT8 PhysPortCount; + +} WV_DEVICE_ATTRIBUTES; + +typedef enum _WV_PORT_STATE +{ + WvPortNop, + WvPortDown, + WvPortInit, + WvPortArmed, + WvPortActive, + WvPortActiveDefer + +} WV_PORT_STATE; + +typedef struct _WV_PORT_ATTRIBUTES +{ + DWORD PortCabilityFlags; + WV_PORT_STATE State; + UINT32 MaxMtu; + UINT32 ActiveMtu; + UINT32 GidTableLength; + UINT32 MaxMessageSize; + UINT32 BadPkeyCounter; + UINT32 QkeyViolationCounter; + UINT16 PkeyTableLength; + NET16 Lid; + NET16 SmLid; + UINT8 Lmc; + UINT8 MaxVls; + UINT8 SmSl; + UINT8 SubnetTimeout; + UINT8 InitTypeReply; + UINT8 ActiveWidth; + UINT8 ActiveSpeed; + UINT8 PhysicalState; + +} WV_PORT_ATTRIBUTES; + +typedef struct _WV_DEVICE_ADDRESS +{ + NET64 DeviceGuid; + NET16 Pkey; + UINT8 PortNumber; + +} WV_DEVICE_ADDRESS; + +// Port notification flags +#define WV_EVENT_ERROR 0x00000001 +#define WV_EVENT_STATE 0x00000002 +#define WV_EVENT_ADDRESS 0x00000004 +#define WV_EVENT_LINK_ADDRESS 0x00000008 +#define WV_EVENT_PARTITION 0x00000010 +#define WV_EVENT_MANAGEMENT 0x00000020 + +typedef enum _WV_CQ_NOTIFY_TYPE +{ + WvCqError, + WvCqNextCompletion, + WvCqSolicited + +} WV_CQ_NOTIFY_TYPE; + +typedef enum _WV_OPCODE +{ + WvSend, + WvRdmaWrite, + WvRdmaRead, + WvCompareExchange, + WvFetchAdd, + WvBindWindow, + WvReceive = (1 << 7), + WvReceiveRdmaWrite + +} WV_OPCODE; + +typedef enum _WV_WC_STATUS +{ + WvWcSuccess, + WvWcLocalLengthError, + WvWcLocalOpError, + WvWcLocalProtectionError, + WvWcFlushed, + WvWcMwBindError, + WvWcRemoteAccessError, + WvWcRemoteOpError, + WvWcRnrRetryError, + WvWcTimeoutRetryError, + WvWcRemoteInvalidRequest, + WvWcBadResponse, + WvWcLocalAccessError, + WvWcError + +} WV_WC_STATUS; + +// Completion flags +#define WV_WC_IMMEDIATE 0x00000001 +// reserved 0x00000002 +#define WV_WC_GRH_VALID 0x00000004 + +// Defined to allow casts to WinOF / OFED WCs +typedef struct _WV_COMPLETION +{ + VOID* QpContext; + UINT64 WrId; + WV_OPCODE Opcode; + UINT32 Length; + UINT64 VendorCode; + WV_WC_STATUS Status; + + // Receive completion data + DWORD Flags; + NET32 ImmediateData; + NET32 SourceQpn; + UINT16 PkeyIndex; + NET16 SLid; + UINT8 SL; + UINT8 DLidPathBits; + +} WV_COMPLETION; + +typedef struct _WV_MEMORY_KEYS +{ + UINT32 Lkey; + NET32 Rkey; + +} WV_MEMORY_KEYS; + +// Access flags +#define WV_ACCESS_REMOTE_READ 0x00000001 +#define WV_ACCESS_REMOTE_WRITE 0x0000000A +#define WV_ACCESS_REMOTE_ATOMIC 0x00000004 +#define WV_ACCESS_LOCAL_WRITE 0x00000008 +#define WV_ACCESS_MW_BIND 0x00000010 +#define WV_ACCESS_CACHABLE 0x00000020 + +// Send queue operation flags +#define WV_SEND_IMMEDIATE 0x00000001 +#define WV_SEND_FENCE 0x00000002 +#define WV_SEND_SIGNALED 0x00000004 +#define WV_SEND_SOLICITED 0x00000008 +#define WV_SEND_INLINE 0x00000010 + +// Defined to allow casts to WinOF / OFED SGEs +#if defined(_WIN64) +typedef struct _WV_SGE +{ + VOID* pAddress; + UINT32 Length; + UINT32 Lkey; + +} WV_SGE; +#else +// 32-bit: little endian support only +typedef struct _WV_SGE +{ + VOID* pAddress; + UINT32 Reserved; + UINT32 Length; + UINT32 Lkey; + +} WV_SGE; +#endif + +typedef struct _WV_SEND_DATAGRAM +{ + UINT64 WrId; + ULONG_PTR AhKey; + + WV_SGE* pSgl; + SIZE_T nSge; + DWORD Flags; + NET32 ImmediateData; + NET32 DestinationQpn; + NET32 DestinationQkey; + +} WV_SEND_DATAGRAM; + +// Defined to allow casts to WinOF / OFED WRs +typedef struct _WV_SEND_REQUEST +{ + UINT64 WrId; + struct _WV_SEND_REQUEST *pNext; + WV_SGE *pSgl; + UINT32 nSge; + WV_OPCODE Opcode; + DWORD Flags; + NET32 ImmediateData; + + union + { + struct + { + NET64 RemoteAddress; + NET32 Rkey; + + } Rdma; + + struct + { + NET64 RemoteAddress; + NET32 Rkey; + NET64 Compare; + NET64 Exchange; + + } CompareExchange; + + struct + { + NET64 RemoteAddress; + NET32 Rkey; + NET64 Add; + UINT64 Reserved; + + } FetchAdd; + + struct + { + ULONG_PTR AhKey; + NET32 DestinationQpn; + NET32 DestinationQkey; + + } Datagram; + } Wr; + +} WV_SEND_REQUEST; + +typedef struct _WV_NETWORK_ROUTE +{ + UINT8 Valid; + UINT8 Reserved; + UINT8 HopLimit; + UINT8 TrafficClass; + NET32 FlowLabel; + WV_GID SGid; + WV_GID DGid; + +} WV_NETWORK_ROUTE; + +typedef struct _WV_ADDRESS_VECTOR +{ + WV_NETWORK_ROUTE Route; + + UINT16 Reserved; + NET16 DLid; + UINT8 ServiceLevel; + UINT8 SourcePathBits; + UINT8 StaticRate; + UINT8 PortNumber; + +} WV_ADDRESS_VECTOR; + +typedef enum _WV_QP_TYPE +{ + WvQpTypeRc, + WvQpTypeUc, + WvQpTypeReserved, + WvQpTypeUd + +} WV_QP_TYPE; + +typedef enum _WV_QP_STATE +{ + WvQpStateReset, + WvQpStateInit, + WvQpStateRtr, + WvQpStateRts, + WvQpStateSqd, + WvQpStateSqError, + WvQpStateError + +} WV_QP_STATE; + +typedef enum _WV_APM_STATE +{ + WvApmMigrated = 1, + WvApmRearm, + WvApmArmed + +} WV_APM_STATE; + +#define WV_QP_SIGNAL_SENDS 0x00000001 +#define WV_QP_MEMORY_MANAGEMENT 0x00000002 + +typedef struct _WV_QP_CREATE +{ + interface IWVCompletionQueue* pSendCq; + interface IWVCompletionQueue* pReceiveCq; + interface IWVSharedReceiveQueue* pSharedReceiveQueue; + VOID* Context; + + SIZE_T SendDepth; + SIZE_T SendSge; + SIZE_T ReceiveDepth; + SIZE_T ReceiveSge; + SIZE_T MaxInlineSend; + SIZE_T InitiatorDepth; + SIZE_T ResponderResources; + + WV_QP_TYPE QpType; + DWORD QpFlags; + +} WV_QP_CREATE; + +// QP attribute mask +#define WV_QP_ATTR_CAPABILITIES 0x00000001 +#define WV_QP_ATTR_INITIATOR_DEPTH 0x00000002 +#define WV_QP_ATTR_RESPONDER_RESOURCES 0x00000004 +#define WV_QP_ATTR_CURRENT_STATE 0x00000008 +#define WV_QP_ATTR_STATE 0x00000010 +#define WV_QP_ATTR_PATH_MIG_STATE 0x00000020 +#define WV_QP_ATTR_DESTINATION_QPN 0x00000040 +#define WV_QP_ATTR_QKEY 0x00000080 +#define WV_QP_ATTR_SEND_PSN 0x00000100 +#define WV_QP_ATTR_RECEIVE_PSN 0x00000200 +#define WV_QP_ATTR_FLAGS 0x00000400 +#define WV_QP_ATTR_ACCESS_FLAGS 0x00000800 +#define WV_QP_ATTR_AV 0x00001000 +#define WV_QP_ATTR_ALTERNATE_AV 0x00002000 +#define WV_QP_ATTR_PORT_NUMBER 0x00004000 +#define WV_QP_ATTR_PKEY_INDEX 0x00008000 +#define WV_QP_ATTR_ACK_TIMEOUT 0x00010000 +#define WV_QP_ATTR_RNR_NAK_TIMEOUT 0x00020000 +#define WV_QP_ATTR_ERROR_RETRY_COUNT 0x00040000 +#define WV_QP_ATTR_RNR_RETRY_COUNT 0x00080000 + +typedef struct _WV_QP_ATTRIBUTES +{ + interface IWVProtectionDomain* pPd; + interface IWVCompletionQueue* pSendCq; + interface IWVCompletionQueue* pReceiveCq; + interface IWVSharedReceiveQueue* pSharedReceiveQueue; + + SIZE_T SendDepth; + SIZE_T SendSge; + SIZE_T ReceiveDepth; + SIZE_T ReceiveSge; + SIZE_T MaxInlineSend; + SIZE_T InitiatorDepth; + SIZE_T ResponderResources; + + WV_QP_TYPE QpType; + WV_QP_STATE CurrentQpState; + WV_QP_STATE QpState; + WV_APM_STATE ApmState; + NET32 Qpn; + NET32 DestinationQpn; + NET32 Qkey; + NET32 SendPsn; + NET32 ReceivePsn; + + DWORD QpFlags; + DWORD AccessFlags; + + WV_ADDRESS_VECTOR AddressVector; + WV_ADDRESS_VECTOR AlternateAddressVector; + UINT32 PathMtu; + UINT32 AlternatePathMtu; + UINT16 PkeyIndex; + UINT16 AlternatePkeyIndex; + UINT8 LocalAckTimeout; + UINT8 AlternateLocalAckTimeout; + + UINT8 RnrNakTimeout; + UINT8 SequenceErrorRetryCount; + UINT8 RnrRetryCount; + +} WV_QP_ATTRIBUTES; + +#define WV_CM_UDP_QKEY 0x01234567 + +typedef struct _WV_CONNECT_PARAM +{ + SIZE_T DataLength; + SIZE_T ResponderResources; + SIZE_T InitiatorDepth; + UINT8 RetryCount; // Ignored when accepting + UINT8 RnrRetryCount; + UINT8 Reserved[2]; + UINT8 Data[56]; + +} WV_CONNECT_PARAM; + +typedef struct _WV_DATAGRAM_PARAM +{ + SIZE_T DataLength; + WV_ADDRESS_VECTOR AddressVector; + NET32 Qpn; + NET32 Qkey; + UINT8 Data[56]; + +} WV_DATAGRAM_PARAM; + +typedef union _WV_SOCKADDR +{ + SOCKADDR Sa; + SOCKADDR_IN Sin; + SOCKADDR_IN6 Sin6; + +} WV_SOCKADDR; + +typedef struct _WV_CONNECT_ATTRIBUTES +{ + WV_SOCKADDR LocalAddress; + WV_SOCKADDR PeerAddress; + WV_DEVICE_ADDRESS Device; + WV_CONNECT_PARAM Param; + +} WV_CONNECT_ATTRIBUTES; + +typedef struct _WV_DATAGRAM_ATTRIBUTES +{ + WV_SOCKADDR LocalAddress; + WV_SOCKADDR PeerAddress; // Specify when querying + WV_DEVICE_ADDRESS Device; + WV_DATAGRAM_PARAM Param; + +} WV_DATAGRAM_ATTRIBUTES; + +// Endpoint options +#define WV_EP_OPTION_ROUTE 0x00000001 + +#undef INTERFACE +#define INTERFACE IWVOverlapped +// {64687592-aa67-4b55-bc4b-e189bdd2fc4f} +DEFINE_GUID(IID_IWVOverlapped, 0x64687592, 0xaa67, 0x4b55, + 0xbc, 0x4b, 0xe1, 0x89, 0xbd, 0xd2, 0xfc, 0x4f); + +DECLARE_INTERFACE_(IWVOverlapped, IUnknown) +{ + // IUnknown methods + __override STDMETHOD(QueryInterface)( + THIS_ + REFIID riid, + LPVOID FAR* ppvObj + ) PURE; + + __override STDMETHOD_(ULONG,AddRef)( + THIS + ) PURE; + + __override STDMETHOD_(ULONG,Release)( + THIS + ) PURE; + + // IWVOverlapped methods + STDMETHOD(CancelOverlappedRequests)( + THIS + ) PURE; + + STDMETHOD(GetOverlappedResult)( + THIS_ + __inout_opt OVERLAPPED *pOverlapped, + __out DWORD *pNumberOfBytesTransferred, + __in BOOL bWait + ) PURE; +}; + + +#undef INTERFACE +#define INTERFACE IWVCompletionQueue +// {a5f6a8de-18a6-4086-aa93-7b66607a290a} +DEFINE_GUID(IID_IWVCompletionQueue, 0xa5f6a8de, 0x18a6, 0x4086, + 0xaa, 0x93, 0x7b, 0x66, 0x60, 0x7a, 0x29, 0x0a); + +DECLARE_INTERFACE_(IWVCompletionQueue, IWVOverlapped) +{ + // IUnknown methods + __override STDMETHOD(QueryInterface)( + THIS_ + REFIID riid, + LPVOID FAR* ppvObj + ) PURE; + + __override STDMETHOD_(ULONG,AddRef)( + THIS + ) PURE; + + __override STDMETHOD_(ULONG,Release)( + THIS + ) PURE; + + // IWVOverlapped methods + __override STDMETHOD(CancelOverlappedRequests)( + THIS + ) PURE; + + __override STDMETHOD(GetOverlappedResult)( + THIS_ + __inout_opt OVERLAPPED *pOverlapped, + __out DWORD *pNumberOfBytesTransferred, + __in BOOL bWait + ) PURE; + + // IWVCompletionQueue methods + STDMETHOD(Resize)( + THIS_ + __inout SIZE_T* pEntries + ) PURE; + + STDMETHOD(Peek)( + THIS_ + __out SIZE_T* pCompletedEntries + ) PURE; + + STDMETHOD(Notify)( + THIS_ + __in WV_CQ_NOTIFY_TYPE Type, + __in_opt OVERLAPPED* pOverlapped + ) PURE; + + STDMETHOD(BatchNotify)( + THIS_ + __in SIZE_T CompletedEntries, + __in_opt OVERLAPPED* pOverlapped + ) PURE; + + STDMETHOD_(SIZE_T,Poll)( + THIS_ + __inout_ecount(Entries) WV_COMPLETION Completions[], + __in SIZE_T Entries + ) PURE; +}; + + +#undef INTERFACE +#define INTERFACE IWVMemoryWindow +// {e8ae206f-b31f-4709-8dc9-6e87625f93fc} +DEFINE_GUID(IID_IWVMemoryWindow, 0xe8ae206f, 0xb31f, 0x4709, + 0x8d, 0xc9, 0x6e, 0x87, 0x62, 0x5f, 0x93, 0xfc); + +DECLARE_INTERFACE_(IWVMemoryWindow, IUnknown) +{ + // IUnknown methods + __override STDMETHOD(QueryInterface)( + THIS_ + REFIID riid, + LPVOID FAR* ppvObj + ) PURE; + + __override STDMETHOD_(ULONG,AddRef)( + THIS + ) PURE; + + __override STDMETHOD_(ULONG,Release)( + THIS + ) PURE; +}; + + +#undef INTERFACE +#define INTERFACE IWVAddressHandle +// {95903fde-fdac-4007-92b7-e01286cd36e8} +DEFINE_GUID(IID_IWVAddressHandle, 0x95903fde, 0xfdac, 0x4007, + 0x92, 0xb7, 0xe0, 0x12, 0x86, 0xcd, 0x36, 0xe8); + +DECLARE_INTERFACE_(IWVAddressHandle, IUnknown) +{ + // IUnknown methods + __override STDMETHOD(QueryInterface)( + THIS_ + REFIID riid, + LPVOID FAR* ppvObj + ) PURE; + + __override STDMETHOD_(ULONG,AddRef)( + THIS + ) PURE; + + __override STDMETHOD_(ULONG,Release)( + THIS + ) PURE; +}; + + +#undef INTERFACE +#define INTERFACE IWVSharedReceiveQueue +// {b2bf30e4-8c2e-4659-ac7a-4c5e0d2c7114} +DEFINE_GUID(IID_IWVSharedReceiveQueue, 0xb2bf30e4, 0x8c2e, 0x4659, + 0xac, 0x7a, 0x4c, 0x5e, 0x0d, 0x2c, 0x71, 0x14); + +DECLARE_INTERFACE_(IWVSharedReceiveQueue, IWVOverlapped) +{ + // IUnknown methods + __override STDMETHOD(QueryInterface)( + THIS_ + REFIID riid, + LPVOID FAR* ppvObj + ) PURE; + + __override STDMETHOD_(ULONG,AddRef)( + THIS + ) PURE; + + __override STDMETHOD_(ULONG,Release)( + THIS + ) PURE; + + // IWVOverlapped methods + __override STDMETHOD(CancelOverlappedRequests)( + THIS + ) PURE; + + __override STDMETHOD(GetOverlappedResult)( + THIS_ + __inout_opt OVERLAPPED *pOverlapped, + __out DWORD *pNumberOfBytesTransferred, + __in BOOL bWait + ) PURE; + + // IWVSharedReceiveQueue methods + STDMETHOD(Query)( + THIS_ + __out SIZE_T* pMaxWr, + __out SIZE_T* pMaxSge, + __out SIZE_T* pSrqLimit + ) PURE; + + STDMETHOD(Modify)( + THIS_ + __in SIZE_T MaxWr, + __in SIZE_T SrqLimit + ) PURE; + + STDMETHOD(PostReceive)( + THIS_ + __in UINT64 WrId, + __in_ecount(nSge) WV_SGE* pSgl, + __in SIZE_T nSge + ) PURE; + + /* Signaled on limit reached event */ + STDMETHOD(Notify)( + THIS_ + __in_opt OVERLAPPED* pOverlapped + ) PURE; +}; + + +#undef INTERFACE +#define INTERFACE IWVQueuePair +// {35C64226-6A1F-4c8d-9465-C6FEE8053CDD} +DEFINE_GUID(IID_IWVQueuePair, 0x35c64226, 0x6a1f, 0x4c8d, + 0x94, 0x65, 0xc6, 0xfe, 0xe8, 0x5, 0x3c, 0xdd); + +DECLARE_INTERFACE_(IWVQueuePair, IWVOverlapped) +{ + // IUnknown methods + __override STDMETHOD(QueryInterface)( + THIS_ + REFIID riid, + LPVOID FAR* ppvObj + ) PURE; + + __override STDMETHOD_(ULONG,AddRef)( + THIS + ) PURE; + + __override STDMETHOD_(ULONG,Release)( + THIS + ) PURE; + + // IWVOverlapped methods + __override STDMETHOD(CancelOverlappedRequests)( + THIS + ) PURE; + + __override STDMETHOD(GetOverlappedResult)( + THIS_ + __inout_opt OVERLAPPED *pOverlapped, + __out DWORD *pNumberOfBytesTransferred, + __in BOOL bWait + ) PURE; + + // IWVQueuePair methods + STDMETHOD(Query)( + THIS_ + __out WV_QP_ATTRIBUTES* pAttributes + ) PURE; + + STDMETHOD(Modify)( + THIS_ + __in WV_QP_ATTRIBUTES* pAttributes, + __in DWORD Options, + __in_opt OVERLAPPED* pOverlapped + ) PURE; + + STDMETHOD(PostReceive)( + THIS_ + __in UINT64 WrId, + __in_ecount(nSge) WV_SGE* pSgl, + __in SIZE_T nSge + ) PURE; + + STDMETHOD(PostSend)( + THIS_ + __in WV_SEND_REQUEST *pSend, + __out_opt WV_SEND_REQUEST **ppFailed + ) PURE; +}; + + +#undef INTERFACE +#define INTERFACE IWVConnectQueuePair +// {DF905570-AEEB-4114-B30E-4DC3EB5A9AD6} +DEFINE_GUID(IID_IWVConnectQueuePair, 0xdf905570, 0xaeeb, 0x4114, + 0xb3, 0xe, 0x4d, 0xc3, 0xeb, 0x5a, 0x9a, 0xd6); + +DECLARE_INTERFACE_(IWVConnectQueuePair, IWVQueuePair) +{ + // IUnknown methods + __override STDMETHOD(QueryInterface)( + THIS_ + REFIID riid, + LPVOID FAR* ppvObj + ) PURE; + + __override STDMETHOD_(ULONG,AddRef)( + THIS + ) PURE; + + __override STDMETHOD_(ULONG,Release)( + THIS + ) PURE; + + // IWVOverlapped methods + __override STDMETHOD(CancelOverlappedRequests)( + THIS + ) PURE; + + __override STDMETHOD(GetOverlappedResult)( + THIS_ + __inout_opt OVERLAPPED *pOverlapped, + __out DWORD *pNumberOfBytesTransferred, + __in BOOL bWait + ) PURE; + + // IWVQueuePair methods + STDMETHOD(Query)( + THIS_ + __out WV_QP_ATTRIBUTES* pAttributes + ) PURE; + + STDMETHOD(Modify)( + THIS_ + __in WV_QP_ATTRIBUTES* pAttributes, + __in DWORD Options, + __in_opt OVERLAPPED* pOverlapped + ) PURE; + + STDMETHOD(PostReceive)( + THIS_ + __in UINT64 WrId, + __in_ecount(nSge) WV_SGE* pSgl, + __in SIZE_T nSge + ) PURE; + + STDMETHOD(PostSend)( + THIS_ + __in WV_SEND_REQUEST *pSend, + __out_opt WV_SEND_REQUEST **ppFailed + ) PURE; + + // IWVConnectQueuePair methods + STDMETHOD(Send)( + THIS_ + __in UINT64 WrId, + __in_ecount(nSge) WV_SGE* pSgl, + __in SIZE_T nSge, + __in DWORD Flags, + __in NET32 ImmediateData + ) PURE; + + STDMETHOD(Read)( + THIS_ + __in UINT64 WrId, + __in_ecount(nSge) WV_SGE* pSgl, + __in SIZE_T nSge, + __in DWORD Flags, + __in NET64 Address, + __in NET32 Rkey + ) PURE; + + STDMETHOD(Write)( + THIS_ + __in UINT64 WrId, + __in_ecount(nSge) WV_SGE* pSgl, + __in SIZE_T nSge, + __in DWORD Flags, + __in NET32 ImmediateData, + __in NET64 Address, + __in NET32 Rkey + ) PURE; + + STDMETHOD(CompareExchange)( + THIS_ + __in UINT64 WrId, + __in WV_SGE* pSge, + __in DWORD Flags, + __in NET64 Compare, + __in NET64 Exchange, + __in NET64 Address, + __in NET32 Rkey + ) PURE; + + STDMETHOD(FetchAdd)( + THIS_ + __in UINT64 WrId, + __in WV_SGE* pSge, + __in DWORD Flags, + __in NET64 Value, + __in NET64 Address, + __in NET32 Rkey + ) PURE; + + STDMETHOD(BindMemoryWindow)( + THIS_ + __in IWVMemoryWindow* pMw, + __in UINT64 WrId, + __in UINT32 Lkey, + __in DWORD AccessFlags, + __in DWORD SendFlags, + __in_bcount(BufferLength) const VOID* pBuffer, + __in SIZE_T BufferLength, + __out NET32 *pRkey + ) PURE; +}; + + +#undef INTERFACE +#define INTERFACE IWVDatagramQueuePair +// {3BA2F15E-D961-4df8-8FC2-6043A6D67826} +DEFINE_GUID(IID_IWVDatagramQueuePair, 0x3ba2f15e, 0xd961, 0x4df8, + 0x8f, 0xc2, 0x60, 0x43, 0xa6, 0xd6, 0x78, 0x26); + +DECLARE_INTERFACE_(IWVDatagramQueuePair, IWVQueuePair) +{ + // IUnknown methods + __override STDMETHOD(QueryInterface)( + THIS_ + REFIID riid, + LPVOID FAR* ppvObj + ) PURE; + + __override STDMETHOD_(ULONG,AddRef)( + THIS + ) PURE; + + __override STDMETHOD_(ULONG,Release)( + THIS + ) PURE; + + // IWVOverlapped methods + __override STDMETHOD(CancelOverlappedRequests)( + THIS + ) PURE; + + __override STDMETHOD(GetOverlappedResult)( + THIS_ + __inout_opt OVERLAPPED *pOverlapped, + __out DWORD *pNumberOfBytesTransferred, + __in BOOL bWait + ) PURE; + + // IWVQueuePair methods + STDMETHOD(Query)( + THIS_ + __out WV_QP_ATTRIBUTES* pAttributes + ) PURE; + + STDMETHOD(Modify)( + THIS_ + __in WV_QP_ATTRIBUTES* pAttributes, + __in DWORD Options, + __in_opt OVERLAPPED* pOverlapped + ) PURE; + + STDMETHOD(PostReceive)( + THIS_ + __in UINT64 WrId, + __in_ecount(nSge) WV_SGE* pSgl, + __in SIZE_T nSge + ) PURE; + + STDMETHOD(PostSend)( + THIS_ + __in WV_SEND_REQUEST *pSend, + __out_opt WV_SEND_REQUEST **ppFailed + ) PURE; + + // IWVDatagramQueuePair Methods + STDMETHOD(Send)( + THIS_ + __in UINT64 WrId, + __in ULONG_PTR AhKey, + __in WV_SGE* pSge, + __in DWORD Flags, + __in NET32 DestinationQpn, + __in NET32 DestinationQkey + ) PURE; + + STDMETHOD(SendMessage)( + THIS_ + __in WV_SEND_DATAGRAM* pSend + ) PURE; + + STDMETHOD(AttachMulticast)( + THIS_ + __in WV_GID *pGid, + __in NET16 Lid, + __in_opt OVERLAPPED* pOverlapped + ) PURE; + + STDMETHOD(DetachMulticast)( + THIS_ + __in WV_GID *pGid, + __in NET16 Lid, + __in_opt OVERLAPPED* pOverlapped + ) PURE; +}; + + +#undef INTERFACE +#define INTERFACE IWVProtectionDomain +// {E3657ABE-8C4E-4994-BE32-45B49BAE95E4} +DEFINE_GUID(IID_IWVProtectionDomain, 0xe3657abe, 0x8c4e, 0x4994, + 0xbe, 0x32, 0x45, 0xb4, 0x9b, 0xae, 0x95, 0xe4); + +DECLARE_INTERFACE_(IWVProtectionDomain, IWVOverlapped) +{ + // IUnknown methods + __override STDMETHOD(QueryInterface)( + THIS_ + REFIID riid, + LPVOID FAR* ppvObj + ) PURE; + + __override STDMETHOD_(ULONG,AddRef)( + THIS + ) PURE; + + __override STDMETHOD_(ULONG,Release)( + THIS + ) PURE; + + // IWVOverlapped methods + STDMETHOD(CancelOverlappedRequests)( + THIS + ) PURE; + + STDMETHOD(GetOverlappedResult)( + THIS_ + __inout_opt OVERLAPPED *pOverlapped, + __out DWORD *pNumberOfBytesTransferred, + __in BOOL bWait + ) PURE; + + // IWVProtectionDomain methods + STDMETHOD(CreateSharedReceiveQueue)( + THIS_ + __in SIZE_T MaxWr, + __in SIZE_T MaxSge, + __in SIZE_T SrqLimit, + __deref_out IWVSharedReceiveQueue** ppSrq + ) PURE; + + STDMETHOD(CreateConnectQueuePair)( + THIS_ + __in WV_QP_CREATE* pAttributes, + __deref_out IWVConnectQueuePair** ppQp + ) PURE; + + STDMETHOD(CreateDatagramQueuePair)( + THIS_ + __in WV_QP_CREATE* pAttributes, + __deref_out IWVDatagramQueuePair** ppQp + ) PURE; + + STDMETHOD(RegisterMemory)( + THIS_ + __in_bcount(BufferLength) const VOID* pBuffer, + __in SIZE_T BufferLength, + __in DWORD AccessFlags, + __in_opt OVERLAPPED* pOverlapped, + __out WV_MEMORY_KEYS* pKeys + ) PURE; + + STDMETHOD(DeregisterMemory)( + THIS_ + __in UINT32 Lkey, + __in_opt OVERLAPPED* pOverlapped + ) PURE; + + STDMETHOD(AllocateMemoryWindow)( + THIS_ + __deref_out IWVMemoryWindow** ppMw + ) PURE; + + STDMETHOD(CreateAddressHandle)( + THIS_ + __in WV_ADDRESS_VECTOR* pAddress, + __deref_out IWVAddressHandle** ppAh, + __out ULONG_PTR* pAhKey + ) PURE; +}; + + +#undef INTERFACE +#define INTERFACE IWVEndpoint +// {eb2fbd8e-b9b6-4b24-9a5e-94c26ae265f0} +DEFINE_GUID(IID_IWVEndpoint, 0xeb2fbd8e, 0xb9b6, 0x4b24, + 0x9a, 0x5e, 0x94, 0xc2, 0x6a, 0xe2, 0x65, 0xf0); + +DECLARE_INTERFACE_(IWVEndpoint, IWVOverlapped) +{ + // IUnknown methods + __override STDMETHOD(QueryInterface)( + THIS_ + REFIID riid, + LPVOID FAR* ppvObj + ) PURE; + + __override STDMETHOD_(ULONG,AddRef)( + THIS + ) PURE; + + __override STDMETHOD_(ULONG,Release)( + THIS + ) PURE; + + // IWVOverlapped methods + __override STDMETHOD(CancelOverlappedRequests)( + THIS + ) PURE; + + __override STDMETHOD(GetOverlappedResult)( + THIS_ + __inout_opt OVERLAPPED *pOverlapped, + __out DWORD *pNumberOfBytesTransferred, + __in BOOL bWait + ) PURE; + + // IWVEndpoint methods + STDMETHOD(Modify)( + THIS_ + __in DWORD Option, + __in_bcount_opt(OptionLength) const VOID* pOptionData, + __in SIZE_T OptionLength + ) PURE; + + STDMETHOD(BindAddress)( + THIS_ + __in SOCKADDR* pAddress + ) PURE; + + STDMETHOD(Listen)( + THIS_ + __in SIZE_T Backlog + ) PURE; + + STDMETHOD(Reject)( + THIS_ + __in_bcount_opt(UserDataLength) const VOID* pUserData, + __in SIZE_T UserDataLength + ) PURE; +}; + + +#undef INTERFACE +#define INTERFACE IWVConnectEndpoint +// {8FDA0EE7-E7F7-48cc-83D3-17E9C871FEA3} +DEFINE_GUID(IID_IWVConnectEndpoint, 0x8fda0ee7, 0xe7f7, 0x48cc, + 0x83, 0xd3, 0x17, 0xe9, 0xc8, 0x71, 0xfe, 0xa3); + +DECLARE_INTERFACE_(IWVConnectEndpoint, IWVEndpoint) +{ + // IUnknown methods + __override STDMETHOD(QueryInterface)( + THIS_ + REFIID riid, + LPVOID FAR* ppvObj + ) PURE; + + __override STDMETHOD_(ULONG,AddRef)( + THIS + ) PURE; + + __override STDMETHOD_(ULONG,Release)( + THIS + ) PURE; + + // IWVOverlapped methods + __override STDMETHOD(CancelOverlappedRequests)( + THIS + ) PURE; + + __override STDMETHOD(GetOverlappedResult)( + THIS_ + __inout_opt OVERLAPPED *pOverlapped, + __out DWORD *pNumberOfBytesTransferred, + __in BOOL bWait + ) PURE; + + // IWVEndpoint methods + __override STDMETHOD(Modify)( + THIS_ + __in DWORD Option, + __in_bcount_opt(OptionLength) const VOID* pOptionData, + __in SIZE_T OptionLength + ) PURE; + + __override STDMETHOD(BindAddress)( + THIS_ + __in SOCKADDR* pAddress + ) PURE; + + __override STDMETHOD(Listen)( + THIS_ + __in SIZE_T Backlog + ) PURE; + + __override STDMETHOD(Reject)( + THIS_ + __in_bcount_opt(UserDataLength) const VOID* pUserData, + __in SIZE_T UserDataLength + ) PURE; + + // IWVConnectEndpoint methods + STDMETHOD(GetRequest)( + THIS_ + __in IWVConnectEndpoint* pEndpoint, + __in_opt OVERLAPPED* pOverlapped + ) PURE; + + STDMETHOD(Connect)( + THIS_ + __in IWVConnectQueuePair* pQp, + __in const SOCKADDR* pAddress, + __in WV_CONNECT_PARAM* pParam, + __in_opt OVERLAPPED* pOverlapped + ) PURE; + + STDMETHOD(Accept)( + THIS_ + __in_opt IWVConnectQueuePair* pQp, + __in WV_CONNECT_PARAM* pParam, + __in_opt OVERLAPPED* pOverlapped + ) PURE; + + STDMETHOD(Disconnect)( + THIS_ + __in_opt OVERLAPPED* pOverlapped + ) PURE; + + STDMETHOD(NotifyDisconnect)( + THIS_ + __in_opt OVERLAPPED* pOverlapped + ) PURE; + + STDMETHOD(Query)( + THIS_ + __out WV_CONNECT_ATTRIBUTES* pAttributes + ) PURE; +}; + + +#undef INTERFACE +#define INTERFACE IWVDatagramEndpoint +// {1d879de6-f2af-4a8a-8893-52e0ab868130} +DEFINE_GUID(IID_IWVDatagramEndpoint, 0x1d879de6, 0xf2af, 0x4a8a, + 0x88, 0x93, 0x52, 0xe0, 0xab, 0x86, 0x81, 0x30); + +DECLARE_INTERFACE_(IWVDatagramEndpoint, IWVEndpoint) +{ + // IUnknown methods + __override STDMETHOD(QueryInterface)( + THIS_ + REFIID riid, + LPVOID FAR* ppvObj + ) PURE; + + __override STDMETHOD_(ULONG,AddRef)( + THIS + ) PURE; + + __override STDMETHOD_(ULONG,Release)( + THIS + ) PURE; + + // IWVOverlapped methods + __override STDMETHOD(CancelOverlappedRequests)( + THIS + ) PURE; + + __override STDMETHOD(GetOverlappedResult)( + THIS_ + __inout_opt OVERLAPPED *pOverlapped, + __out DWORD *pNumberOfBytesTransferred, + __in BOOL bWait + ) PURE; + + // IWVEndpoint methods + __override STDMETHOD(Modify)( + THIS_ + __in DWORD Option, + __in_bcount_opt(OptionLength) const VOID* pOptionData, + __in SIZE_T OptionLength + ) PURE; + + __override STDMETHOD(BindAddress)( + THIS_ + __in SOCKADDR* pAddress + ) PURE; + + __override STDMETHOD(Listen)( + THIS_ + __in SIZE_T Backlog + ) PURE; + + __override STDMETHOD(Reject)( + THIS_ + __in_bcount_opt(UserDataLength) const VOID* pUserData, + __in SIZE_T UserDataLength + ) PURE; + + // IWVDatagramEndpoint methods + STDMETHOD(GetRequest)( + THIS_ + __in IWVDatagramEndpoint* pEndpoint, + __in_opt OVERLAPPED* pOverlapped + ) PURE; + + STDMETHOD(Lookup)( + THIS_ + __in const SOCKADDR* pAddress, + __in_bcount_opt(UserDataLength) const VOID* pUserData, + __in SIZE_T UserDataLength, + __in_opt OVERLAPPED* pOverlapped + ) PURE; + + STDMETHOD(Accept)( + THIS_ + __in WV_DATAGRAM_PARAM* pParam, + __in_opt OVERLAPPED* pOverlapped + ) PURE; + + STDMETHOD(JoinMulticast)( + THIS_ + __in const SOCKADDR* pAddress, + __in_opt OVERLAPPED* pOverlapped + ) PURE; + + STDMETHOD(LeaveMulticast)( + THIS_ + __in const SOCKADDR* pAddress, + __in_opt OVERLAPPED* pOverlapped + ) PURE; + + STDMETHOD(Query)( + THIS_ + __inout WV_DATAGRAM_ATTRIBUTES* pAttributes + ) PURE; +}; + + +#undef INTERFACE +#define INTERFACE IWVDevice +// {244af78c-b1ac-40e4-9896-271d58d591b8} +DEFINE_GUID(IID_IWVDevice, 0x244af78c, 0xb1ac, 0x40e4, + 0x98, 0x96, 0x27, 0x1d, 0x58, 0xd5, 0x91, 0xb8); + +DECLARE_INTERFACE_(IWVDevice, IWVOverlapped) +{ + // IUnknown methods + __override STDMETHOD(QueryInterface)( + THIS_ + REFIID riid, + LPVOID FAR* ppvObj + ) PURE; + + __override STDMETHOD_(ULONG,AddRef)( + THIS + ) PURE; + + __override STDMETHOD_(ULONG,Release)( + THIS + ) PURE; + + // IWVOverlapped methods + __override STDMETHOD(CancelOverlappedRequests)( + THIS + ) PURE; + + __override STDMETHOD(GetOverlappedResult)( + THIS_ + __inout_opt OVERLAPPED *pOverlapped, + __out DWORD *pNumberOfBytesTransferred, + __in BOOL bWait + ) PURE; + + // IWVDevice methods + STDMETHOD(Query)( + THIS_ + __out WV_DEVICE_ATTRIBUTES* pAttributes + ) PURE; + + STDMETHOD(QueryPort)( + THIS_ + __in UINT8 PortNumber, + __out WV_PORT_ATTRIBUTES* pAttributes + ) PURE; + + STDMETHOD(QueryGid)( + THIS_ + __in UINT8 PortNumber, + __in DWORD Index, + __out WV_GID* pGid + ) PURE; + + STDMETHOD(FindGid)( + THIS_ + __in UINT8 PortNumber, + __in WV_GID* pGid, + __out DWORD* pIndex + ) PURE; + + STDMETHOD(QueryPkey)( + THIS_ + __in UINT8 PortNumber, + __in UINT16 Index, + __out NET16* pPkey + ) PURE; + + STDMETHOD(FindPkey)( + THIS_ + __in UINT8 PortNumber, + __in NET16 Pkey, + __out UINT16* pIndex + ) PURE; + + STDMETHOD(CreateCompletionQueue)( + THIS_ + __inout SIZE_T *pEntries, + __deref_out IWVCompletionQueue** ppCq + ) PURE; + + STDMETHOD(AllocateProtectionDomain)( + THIS_ + __deref_out IWVProtectionDomain** ppPd + ) PURE; + + STDMETHOD(Notify)( + THIS_ + __in UINT8 PortNumber, + __in_opt OVERLAPPED* pOverlapped, + __out DWORD* pFlags + ) PURE; +}; + + +#undef INTERFACE +#define INTERFACE IWVProvider +// {75AD0EDA-23C9-4687-8FFF-D1B34E1EF5BE} +DEFINE_GUID(IID_IWVProvider, 0x75ad0eda, 0x23c9, 0x4687, + 0x8f, 0xff, 0xd1, 0xb3, 0x4e, 0x1e, 0xf5, 0xbe); + +DECLARE_INTERFACE_(IWVProvider, IUnknown) +{ + // IUnknown methods + __override STDMETHOD(QueryInterface)( + THIS_ + REFIID riid, + LPVOID FAR* ppvObj + ) PURE; + + __override STDMETHOD_(ULONG,AddRef)( + THIS + ) PURE; + + __override STDMETHOD_(ULONG,Release)( + THIS + ) PURE; + + // IWVProvider methods + STDMETHOD_(HANDLE,GetFileHandle)( + THIS + ) PURE; + + STDMETHOD(QueryDeviceList)( + THIS_ + __inout_bcount_part_opt(*pBufferSize, *pBufferSize) NET64* pGuidList, + __inout SIZE_T* pBufferSize + ) PURE; + + STDMETHOD(QueryDevice)( + THIS_ + __in NET64 Guid, + __out WV_DEVICE_ATTRIBUTES* pAttributes + ) PURE; + + STDMETHOD(TranslateAddress)( + THIS_ + __in const SOCKADDR* pAddress, + __out WV_DEVICE_ADDRESS* pDeviceAddress + ) PURE; + + STDMETHOD(OpenDevice)( + THIS_ + __in NET64 Guid, + __deref_out IWVDevice** ppDevice + ) PURE; + + STDMETHOD(CreateConnectEndpoint)( + THIS_ + __deref_out IWVConnectEndpoint** ppConnectEndpoint + ) PURE; + + STDMETHOD(CreateDatagramEndpoint)( + THIS_ + __deref_out IWVDatagramEndpoint** ppDatagramEndpoint + ) PURE; +}; + +#ifdef __cplusplus +extern "C" __declspec(dllexport) HRESULT WvGetObject(REFIID riid, LPVOID FAR* ppvObj); +#else +__declspec(dllexport) HRESULT WvGetObject(REFIID riid, LPVOID FAR* ppvObj); +#endif + +#endif // _WINVERBS_H_ diff --git a/branches/WOF2-3/inc/user/rdma/wvstatus.h b/branches/WOF2-3/inc/user/rdma/wvstatus.h new file mode 100644 index 00000000..76450fe9 --- /dev/null +++ b/branches/WOF2-3/inc/user/rdma/wvstatus.h @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#ifndef _WVSTATUS_H_ +#define _WVSTATUS_H_ + +// +// Values are 32 bit values laid out as follows: +// +// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 +// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +// +---+-+-+-----------------------+-------------------------------+ +// |Sev|C|R| Facility | Code | +// +---+-+-+-----------------------+-------------------------------+ +// +// where +// +// Sev - is the severity code +// +// 00 - Success +// 01 - Informational +// 10 - Warning +// 11 - Error +// +// C - is the Customer code flag +// +// R - is a reserved bit +// +// Facility - is the facility code +// +// Code - is the facility's status code +// +// +// Define the facility codes +// +#define FACILITY_WINVERBS 0x38 + + +// +// Define the severity codes +// +#define STATUS_SEVERITY_WARNING 0x2 +#define STATUS_SEVERITY_SUCCESS 0x0 +#define STATUS_SEVERITY_INFORMATIONAL 0x1 +#define STATUS_SEVERITY_ERROR 0x3 + + +// +// Values map to NTSTATUS and NDSTATUS where possible +// +#define WV_SUCCESS ((HRESULT)0x00000000L) +#define WV_TIMEOUT ((HRESULT)0x00000102L) +#define WV_PENDING ((HRESULT)0x00000103L) +#define WV_BUFFER_OVERFLOW ((HRESULT)0x80000005L) +#define WV_DEVICE_BUSY ((HRESULT)0x80000011L) +#define WV_NO_MORE_ENTRIES ((HRESULT)0x8000001AL) +#define WV_IO_PENDING ((HRESULT)0x800703E5L) +#define WV_REJECTED ((HRESULT)0x80070047L) +#define WV_UNSUCCESSFUL ((HRESULT)0xC0000001L) +#define WV_ACCESS_VIOLATION ((HRESULT)0xC0000005L) +#define WV_INVALID_HANDLE ((HRESULT)0xC0000008L) +#define WV_INVALID_PARAMETER ((HRESULT)0xC000000DL) +#define WV_NO_MEMORY ((HRESULT)0xC0000017L) +#define WV_INVALID_PARAMETER_MIX ((HRESULT)0xC0000030L) +#define WV_DATA_OVERRUN ((HRESULT)0xC000003CL) +#define WV_INSUFFICIENT_RESOURCES ((HRESULT)0xC000009AL) +#define WV_NOT_INITIALIZED ((HRESULT)0xC00000A3L) +#define WV_IO_TIMEOUT ((HRESULT)0xC00000B5L) +#define WV_NOT_SUPPORTED ((HRESULT)0xC00000BBL) +#define WV_INTERNAL_ERROR ((HRESULT)0xC00000E5L) +#define WV_INVALID_PARAMETER_1 ((HRESULT)0xC00000EFL) +#define WV_INVALID_PARAMETER_2 ((HRESULT)0xC00000F0L) +#define WV_INVALID_PARAMETER_3 ((HRESULT)0xC00000F1L) +#define WV_INVALID_PARAMETER_4 ((HRESULT)0xC00000F2L) +#define WV_INVALID_PARAMETER_5 ((HRESULT)0xC00000F3L) +#define WV_INVALID_PARAMETER_6 ((HRESULT)0xC00000F4L) +#define WV_INVALID_PARAMETER_7 ((HRESULT)0xC00000F5L) +#define WV_INVALID_PARAMETER_8 ((HRESULT)0xC00000F6L) +#define WV_INVALID_PARAMETER_9 ((HRESULT)0xC00000F7L) +#define WV_INVALID_PARAMETER_10 ((HRESULT)0xC00000F8L) +#define WV_CANCELLED ((HRESULT)0xC0000120L) +#define WV_REMOTE_ERROR ((HRESULT)0xC000013DL) +#define WV_INVALID_ADDRESS ((HRESULT)0xC0000141L) +#define WV_ADDRESS_ALREADY_EXISTS ((HRESULT)0xC000020AL) +#define WV_CONNECTION_REFUSED ((HRESULT)0xC0000236L) +#define WV_CONNECTION_INVALID ((HRESULT)0xC000023AL) +#define WV_CONNECTION_ACTIVE ((HRESULT)0xC000023BL) +#define WV_HOST_UNREACHABLE ((HRESULT)0xC000023DL) +#define WV_CONNECTION_ABORTED ((HRESULT)0xC0000241L) +#define WV_DEVICE_REMOVED ((HRESULT)0xC00002B6L) +#define WV_LOCAL_LENGTH ((HRESULT)0xC0380001L) +#define WV_INVALIDATION_ERROR ((HRESULT)0xC0380002L) +#define WV_LOCAL_OP_ERROR ((HRESULT)0xC0380003L) +#define WV_LOCAL_PROTECTION_ERROR ((HRESULT)0xC0380004L) +#define WV_WR_FLUSHED_ERROR ((HRESULT)0xC0380005L) +#define WV_BIND_WINDOW_ERROR ((HRESULT)0xC0380006L) +#define WV_REMOTE_ACCESS_ERROR ((HRESULT)0xC0380007L) +#define WV_REMOTE_OP_ERROR ((HRESULT)0xC0380008L) +#define WV_RNR_RETRY_ERROR ((HRESULT)0xC0380009L) +#define WV_TIMEOUT_RETRY_ERROR ((HRESULT)0xC038000AL) +#define WV_REMOTE_INVALID_REQUEST_ERROR ((HRESULT)0xC038000BL) +#define WV_BAD_RESPONSE_ERROR ((HRESULT)0xC038000CL) +#define WV_LOCAL_ACCESS_ERROR ((HRESULT)0xC038000DL) +#define WV_UNKNOWN_ERROR ((HRESULT)0xC038000EL) + +#endif // _WVSTATUS_H_ diff --git a/branches/WOF2-3/inc/user/wsd/ibsp_regpath.h b/branches/WOF2-3/inc/user/wsd/ibsp_regpath.h new file mode 100644 index 00000000..90661199 --- /dev/null +++ b/branches/WOF2-3/inc/user/wsd/ibsp_regpath.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#ifndef _IBSP_REGPATH_H_ +#define _IBSP_REGPATH_H_ + +/* these definitions are common for installSP and WSD projects */ +#define IBSP_PM_REGISTRY_PATH \ + TEXT("SYSTEM\\CurrentControlSet\\Services\\IBWSD\\") +#define IBSP_PM_EVENTLOG_PATH \ + TEXT("SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\IBWSD") +#define IBSP_PM_SUBKEY_NAME TEXT("IBWSD") +#define IBSP_PM_SUBKEY_PERF TEXT("Performance") +#define IBSP_PM_INI_FILE "ibsp_perfcounters.ini" +#define IBSP_PM_SYM_H_FILE "ibsp_perfini.h" + + +enum IBSP_PM_COUNTERS +{ + BYTES_SEND = 0, + BYTES_RECV, + BYTES_WRITE, + BYTES_READ, + BYTES_TOTAL, + COMP_SEND, + COMP_RECV, + COMP_TOTAL, + INTR_TOTAL, + IBSP_PM_NUM_COUNTERS + +}; + + +/* counter symbol names */ +#define IBSP_PM_OBJ 0 +#define IBSP_PM_COUNTER( X ) ((X + 1) * 2) + +#endif /* _IBSP_REGPATH_H_ */ diff --git a/branches/WOF2-3/tests/alts/allocdeallocpd.c b/branches/WOF2-3/tests/alts/allocdeallocpd.c new file mode 100644 index 00000000..350dad8e --- /dev/null +++ b/branches/WOF2-3/tests/alts/allocdeallocpd.c @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include +#include +#include +#include +#include + +/* + * Function prototypes + */ + + + +/* + * Test Case AllocDeallocPD + */ + +ib_api_status_t +al_test_alloc_dealloc_pd(void) +{ + ib_api_status_t ib_status = IB_SUCCESS; + ib_al_handle_t h_al = NULL; + ib_ca_handle_t h_ca; + ib_pd_handle_t h_pd; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + while(1) + { + /* Open AL */ + ib_status = alts_open_al(&h_al); + + if(ib_status != IB_SUCCESS) + break; + + CL_ASSERT(h_al); + + /* Open CA */ + ib_status = alts_open_ca(h_al,&h_ca); + if(ib_status != IB_SUCCESS) + break; + + CL_ASSERT(h_ca); + + /* + * Allocate a PD here + */ + ib_status = ib_alloc_pd(h_ca, IB_PDT_NORMAL, NULL, &h_pd); //passing null context + + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_alloc_pd failed status = %s\n", ib_get_err_str(ib_status)) ); + alts_close_ca(h_ca); + break; + } + ALTS_PRINT( ALTS_DBG_INFO, + ("\tib_alloc_pd passed with handle = %p\n",h_pd)); + + ib_status = ib_dealloc_pd(h_pd,alts_pd_destroy_cb); + + if(ib_status == IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_INFO, + ("\tib_dealloc_pd passed\n")); + } + else + { + ALTS_PRINT( ALTS_DBG_INFO, + ("\tib_dealloc_pd failed with status = %s\n",ib_get_err_str(ib_status))); + } + + break; //End of while + } + /* Close AL */ + if(h_al) + alts_close_al(h_al); + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + + + diff --git a/branches/WOF2-3/tests/alts/alts_common.h b/branches/WOF2-3/tests/alts/alts_common.h new file mode 100644 index 00000000..36653946 --- /dev/null +++ b/branches/WOF2-3/tests/alts/alts_common.h @@ -0,0 +1,299 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include +#include +#include + +#if !defined(__ALTS_COMMON_H__) +#define __ALTS_COMMON_H__ + + +typedef struct _mem_region +{ + void *buffer; + struct _ib_mr* mr_h; + uint32_t lkey; + uint32_t rkey; + + uint16_t my_lid; + +} mem_region_t; + + +#ifndef __MODULE__ +#define __MODULE__ "ALTS:" +#endif + + +typedef struct cmd_line_struct_t_ +{ + /* + * TBD + */ + uint32_t pgm_to_run; + boolean_t um; + uint32_t iteration; + ib_api_status_t status; + +} cmd_line_arg_t; + + +/* + * Device Name of this driver + */ +#define ALTS_DEVICE_NAME "/dev/al_test" + +/* + * Define a magic number + */ +#define ALTS_DEV_KEY 'T' + +#define ALTS_MAX_CA 4 + +/* + * List all the supported test cases here. + */ +typedef enum alts_dev_ops +{ + OpenClose = 1, + QueryCAAttribute, + ModifyCAAttribute, + AllocDeallocPD, + CreateDestroyAV, + QueryAndModifyAV, + CreateDestroyQP, + QueryAndModifyQP, + CreateAndDestroyCQ, + QueryAndModifyCQ, + AttachMultiCast, + RegisterMemRegion, + RegisterVarMemRegions, + ReregisterHca, + RegisterPhyMemRegion, + CreateMemWindow, + RegisterSharedMemRegion, + MultiSend, + RegisterPnP, + MadTests, + MadQuery, + CmTests, + MaxTestCase +} alts_dev_ops_t; + +/* + * Define all the IOCTL CMD CODES Here + */ +#define ALTS_OpenClose \ + IOCTL_CODE(ALDEV_KEY, OpenClose) +#define ALTS_QueryCAAttribute \ + IOCTL_CODE(ALDEV_KEY, QueryCAAttribute) +#define ALTS_ModifyCAAttribute \ + IOCTL_CODE(ALDEV_KEY, ModifyCAAttribute) +#define ALTS_AllocDeallocPD \ + IOCTL_CODE(ALDEV_KEY, AllocDeallocPD) +#define ALTS_AllocDeallocRDD \ + IOCTL_CODE(ALDEV_KEY, AllocDeallocRDD) +#define ALTS_CreateDestroyAV \ + IOCTL_CODE(ALDEV_KEY, CreateDestroyAV) +#define ALTS_QueryAndModifyAV \ + IOCTL_CODE(ALDEV_KEY, QueryAndModifyAV) +#define ALTS_CreateDestroyQP \ + IOCTL_CODE(ALDEV_KEY, CreateDestroyQP) +#define ALTS_QueryAndModifyQP \ + IOCTL_CODE(ALDEV_KEY, QueryAndModifyQP) +#define ALTS_CreateAndDestroyCQ \ + IOCTL_CODE(ALDEV_KEY, CreateAndDestroyCQ) +#define ALTS_QueryAndModifyCQ \ + IOCTL_CODE(ALDEV_KEY, QueryAndModifyCQ) +#define ALTS_CreateAndDestroyEEC \ + IOCTL_CODE(ALDEV_KEY, CreateAndDestroyEEC) +#define ALTS_QueryAndModifyEEC \ + IOCTL_CODE(ALDEV_KEY, QueryAndModifyEEC) +#define ALTS_AttachMultiCast \ + IOCTL_CODE(ALDEV_KEY, AttachMultiCast) +#define ALTS_RegisterMemRegion \ + IOCTL_CODE(ALDEV_KEY, RegisterMemRegion) +#define ALTS_RegisterPhyMemRegion \ + IOCTL_CODE(ALDEV_KEY, RegisterPhyMemRegion) +#define ALTS_CreateMemWindow \ + IOCTL_CODE(ALDEV_KEY, CreateMemWindow) +#define ALTS_RegisterSharedMemRegion \ + IOCTL_CODE(ALDEV_KEY, RegisterSharedMemRegion) +#define ALTS_MultiSend \ + IOCTL_CODE(ALDEV_KEY, MultiSend) +#define ALTS_MadTests \ + IOCTL_CODE(ALDEV_KEY, MadTests) + +#define ALTS_CmTests \ + IOCTL_CODE(ALDEV_KEY, CmTests) + + +#define ALTS_CQ_SIZE 0x50 + + +/* + * Function Prototypes for the above test cases + */ +ib_api_status_t +al_test_openclose( void ); + +ib_api_status_t +al_test_modifycaattr( void ); + +ib_api_status_t +al_test_querycaattr( void ); + +ib_api_status_t +al_test_alloc_dealloc_pd( void ); + +ib_api_status_t +al_test_alloc_dealloc_rdd( void ); + +ib_api_status_t +al_test_create_destroy_av( void ); + +ib_api_status_t +al_test_query_modify_av( void ); + +ib_api_status_t +al_test_create_destroy_cq( void ); + +ib_api_status_t +al_test_query_modify_cq( void ); + + +ib_api_status_t +al_test_create_destroy_qp( void ); + +ib_api_status_t +al_test_query_modify_qp( void ); + + +ib_api_status_t +al_test_create_destroy_eec( void ); + +ib_api_status_t +al_test_query_modify_eec( void ); + +ib_api_status_t +al_test_register_mem( void ); + +ib_api_status_t +al_test_create_mem_window( void ); + +ib_api_status_t +al_test_register_var_mem( void ); + +ib_api_status_t +al_test_multi_send_recv( void ); + +ib_api_status_t +al_test_register_pnp( void ); + +ib_api_status_t +al_test_mad( void ); + +ib_api_status_t +al_test_query( void ); + +ib_api_status_t +al_test_cm( void ); + +ib_api_status_t +al_test_register_phys_mem( void ); + +ib_api_status_t +al_test_register_shared_mem( void ); + + +/* + * Misc function prototypes + */ + +ib_api_status_t +alts_open_al( ib_al_handle_t *ph_al ); + +ib_api_status_t +alts_close_al( ib_al_handle_t ph_al ); + +ib_api_status_t +alts_open_ca( + IN ib_al_handle_t h_al, + OUT ib_ca_handle_t *p_alts_ca_h + ); + +ib_api_status_t +alts_close_ca( IN ib_ca_handle_t alts_ca_h ); + +void +alts_ca_err_cb( ib_async_event_rec_t *p_err_rec); + +void +alts_ca_destroy_cb( void *context); + +void +alts_pd_destroy_cb( void *context ); + +void +alts_print_ca_attr( ib_ca_attr_t *alts_ca_attr ); + + +void +alts_qp_err_cb( + ib_async_event_rec_t *p_err_rec ); + +void +alts_qp_destroy_cb( + void *context ); + + + +void +alts_cq_comp_cb( + IN const ib_cq_handle_t h_cq, + IN void *cq_context ); + +void +alts_cq_err_cb( + ib_async_event_rec_t *p_err_rec ); + +void +alts_cq_destroy_cb( + void *context ); + + + + +#endif // __ALTS_COMMON_H__ diff --git a/branches/WOF2-3/tests/alts/alts_debug.h b/branches/WOF2-3/tests/alts/alts_debug.h new file mode 100644 index 00000000..9167c963 --- /dev/null +++ b/branches/WOF2-3/tests/alts/alts_debug.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#if !defined(__ALTS_DEBUG_H__) +#define __ALTS_DEBUG_H__ + +#ifndef __MODULE__ +#define __MODULE__ "alts" +#endif + +#include + +#define ALTS_DBG_NORMAL (1 << 0) +#define ALTS_DBG_PNP (1 << 1) +#define ALTS_DBG_INFO (1 << 2) +#define ALTS_DBG_VERBOSE (1 << 3) +#define ALTS_DBG_DEV (1 << 4) +#define ALTS_DBG_STATUS (1 << 5) +#define ALTS_DBG_ERROR CL_DBG_ERROR + +#define ALTS_DBG_NONE CL_DBG_DISABLE +#define ALTS_DBG_FULL CL_DBG_ALL + +extern uint32_t alts_dbg_lvl; + +/* Macros for simplifying CL_ENTER, CL_TRACE, etc. */ +#define ALTS_ENTER( msg_lvl ) \ + CL_ENTER( msg_lvl, alts_dbg_lvl ) + +#define ALTS_EXIT( msg_lvl ) \ + CL_EXIT( msg_lvl, alts_dbg_lvl ) + +#define ALTS_TRACE( msg_lvl, msg ) \ + CL_TRACE( msg_lvl, alts_dbg_lvl, msg ) + +#define ALTS_TRACE_EXIT( msg_lvl, msg ) \ + CL_TRACE_EXIT( msg_lvl, alts_dbg_lvl, msg ) + +#ifndef CL_KERNEL + +#define ALTS_PRINT( msg_lvl, msg ) \ + printf msg +#else + +#define ALTS_PRINT( msg_lvl, msg ) \ + CL_PRINT( msg_lvl, alts_dbg_lvl, msg ) +#endif + +#endif // __ALTS_DEBUG_H__ diff --git a/branches/WOF2-3/tests/alts/alts_misc.c b/branches/WOF2-3/tests/alts/alts_misc.c new file mode 100644 index 00000000..ae29f36a --- /dev/null +++ b/branches/WOF2-3/tests/alts/alts_misc.c @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * Abstract: + * This module defines the basic AL test suite function + * + * Environment: + * Kernel Mode and User Mode + */ + + +#include +#include +#include +#include +#include +#include + + +ib_api_status_t +alts_open_al( + ib_al_handle_t *ph_al ) +{ + ib_api_status_t ib_status; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + ib_status = ib_open_al(ph_al); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_open_al failed status = %d\n", ib_status) ); + + } + else + { + ALTS_PRINT( ALTS_DBG_INFO, ("ib_open_al PASSED.\n") ); + } + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + +ib_api_status_t +alts_close_al( + ib_al_handle_t h_al ) +{ + ib_api_status_t ib_status; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + ib_status = ib_close_al(h_al); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_close_al failed status = %d\n", ib_status)); + } + else + { + ALTS_PRINT( ALTS_DBG_INFO, ("ib_close_al PASSED.\n") ); + } + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + +ib_api_status_t +alts_open_ca( + IN ib_al_handle_t h_al, + OUT ib_ca_handle_t *p_alts_ca_h ) +{ + ib_api_status_t ib_status = IB_SUCCESS; + size_t guid_count; + ib_net64_t ca_guid_array[ALTS_MAX_CA]; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + do + { + ib_status = ib_get_ca_guids(h_al, NULL, &guid_count); + if(ib_status != IB_INSUFFICIENT_MEMORY) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_get_ca_guids failed status = %d\n", (uint32_t)ib_status) ); + break; + + } + + ALTS_PRINT(ALTS_DBG_INFO, \ + ("Total number of CA in the sytem is %d\n",(uint32_t)guid_count)); + + if(guid_count == 0) + { + ib_status = IB_ERROR; + break; + } + + if (guid_count > ALTS_MAX_CA) + { + guid_count = ALTS_MAX_CA; + + ALTS_PRINT(ALTS_DBG_INFO, \ + ("Resetting guid_count to %d\n",ALTS_MAX_CA)); + } + + ib_status = ib_get_ca_guids(h_al, ca_guid_array, &guid_count); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_get_ca_guids failed with status = %d\n", ib_status) ); + break; + } + + ib_status = ib_open_ca( + h_al, + ca_guid_array[0], //Default open the first CA + alts_ca_err_cb, + NULL, //ca_context + p_alts_ca_h); + + ALTS_PRINT(ALTS_DBG_INFO, + ("GUID = %" PRIx64"\n", ca_guid_array[0])); + + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_open_ca failed with status = %d\n", ib_status) ); + break; + } + + } while (0); + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + + +ib_api_status_t +alts_close_ca( + IN ib_ca_handle_t alts_ca_h + ) +{ + ib_api_status_t ib_status; + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + ib_status = ib_close_ca(alts_ca_h, alts_ca_destroy_cb); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_close_ca failed status = %d\n", ib_status)); + } + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + +void +alts_ca_destroy_cb( + void *context) +{ + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + UNUSED_PARAM( context ); + + ALTS_EXIT( ALTS_DBG_VERBOSE ); +} + +void +alts_pd_destroy_cb( + void *context + ) +{ + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + if(context != NULL) + ALTS_PRINT(ALTS_DBG_INFO, + ("Context is %"PRIdSIZE_T"\n", (size_t)context)); + + + ALTS_EXIT( ALTS_DBG_VERBOSE ); +} + + + +void +alts_ca_err_cb( + ib_async_event_rec_t *p_err_rec + ) +{ + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + UNUSED_PARAM( p_err_rec ); + + ALTS_PRINT( ALTS_DBG_INFO, + ("p_err_rec->code is %d\n",p_err_rec->code)); + + ALTS_EXIT( ALTS_DBG_VERBOSE ); +} + + + +void +alts_print_ca_attr( + ib_ca_attr_t *alts_ca_attr + ) +{ + uint32_t i; + ib_port_attr_t *p_port; + UNUSED_PARAM( alts_ca_attr ); + ALTS_PRINT( ALTS_DBG_VERBOSE, + ("\tdev_id is <0x%x>\n",alts_ca_attr->dev_id)); + + for (i = 0; i < alts_ca_attr->num_ports; i ++) + { + p_port = (alts_ca_attr->p_port_attr +i); + ALTS_PRINT( ALTS_DBG_INFO, + ("Port %d\tPrefix: %#16I64x \tGUID: %#16I64x\nLink Status: %s\tLID %#x \n",i, + cl_ntoh64(p_port->p_gid_table->unicast.prefix), + cl_ntoh64(p_port->p_gid_table->unicast.interface_id), + ib_get_port_state_str(p_port->link_state), + cl_ntoh16(p_port->lid)) ); + } +} + diff --git a/branches/WOF2-3/tests/alts/alts_readme.txt b/branches/WOF2-3/tests/alts/alts_readme.txt new file mode 100644 index 00000000..c5976dfc --- /dev/null +++ b/branches/WOF2-3/tests/alts/alts_readme.txt @@ -0,0 +1,119 @@ +README: + +AL Test Suite consists of a bunch of test cases to test the AL functionality. +Test case are focused for bring up of AL and some data transfer test cases. +AL test suite can be used to test individual AL exposed API's and also can +be used to debug and bring up of SHIM. + +AL Test Suite consists of Kernel Mode component and a user mode component. +All the test cases are under shared/alts directory. These test case +can be compiled for both user mode as well as for kernel mode. + +1)AL Test Suite for User mode + This consists of user mode AL test application which has all the test cases in + usermode test application. No kernel mode component is required here. However + this al test suite needs user mode component library. + + Compiling user mode AL test suite: + a)First compile User mode Component Library. + + >cd ~/linuxuser/iba/complib + >make + + b)To compile AL test suite for User mode, run make command with BUILD_USER set + to 1 as showm below. + + >cd ~/linuxuser/iba/alts + >make BUILD_USER + +2)AL Test Suite for Kernel mode + This consists both a user mode component and a kernel mode component. User mode + component is needed to drive the test. Kernel mode component is a driver + which consists of all the test cases compiled in linked to the driver. + + Compiling kernel mode AL test suite: + a)Compile User mode Component Library. + + >cd ~/linuxuser/iba/complib + >make + + b)Compile Kernel mode Component Library + + >cd ~/linux/drivers/iba/complib + >make + + c>Compile user mode AL test suite + + >cd ~/linuxuser/iba/alts + >make + + d) Compile kernel mode AL test Driver + + >cd ~/linux/drivers/iba/alts + >make + + +3)Running the test: +If you would like to test KAL, then you need to install kernel mode +component of AL test suite as shown below. + +>cd ~/linux/drivers/iba/alts +>insmod altsdrv.o + +Running specific tests are as shown below. + >./alts -tc=XXXXX [-um|-km] + + tc-> stands for test case to run. + -um -> user mode test + -km -> kernel mode test + + XXXX can be any one of the following. + OpenClose + QueryCAAttribute + ModifyCAAttribute + AllocDeallocPD + AllocDeallocRDD + CreateDestroyAV + QueryAndModifyAV + CreateDestroyQP + QueryAndModifyQP + CreateAndDestroyCQ + QueryAndModifyCQ + CreateAndDestroyEEC + QueryAndModifyEEC + AttachMultiCast + RegisterMemRegion + RegisterVarMemRegions + ReregisterHca + RegisterPhyMemRegion + CreateMemWindow + RegisterSharedMemRegion + MultiSend + RegisterPnP + MadTests + MadQuery + CmTests + + To run OpenClose test case in user mode + >./alts -tc=OpenClose -um + + To run OpenClose test case in kernel mode + >./alts -tc=OpenClose -km + + OR + >./alts -tc=OpenClose + + Default is kernel mode. + + +To see the results: +All the log messages by default goes to /var/log/messages file. +Grep for "failed" if any test case has failed you should see +that in this file. + + + + + + + diff --git a/branches/WOF2-3/tests/alts/cmtests.c b/branches/WOF2-3/tests/alts/cmtests.c new file mode 100644 index 00000000..c3585d48 --- /dev/null +++ b/branches/WOF2-3/tests/alts/cmtests.c @@ -0,0 +1,4258 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + +/* + * Abstract: + * mad test does a data transfer between two queue pairs created one + * on each port of the hca. In order for this test to work, two ports of the hca + * should be connected in a loop back and must be configured to ACTIVE PORT STATE. + * + * + * Environment: + * All + */ + + +#include +#include +#include +#include +#include +#include + +/* Parameters */ +#define MAX_QPS 8 +#define SRC_QP 0 +#define DEST_QP 1 + + +#pragma warning(disable:4324) +typedef struct _alts_cm_ca_obj +{ + ib_api_status_t status; + ib_qp_type_t test_type; + ib_pfn_comp_cb_t pfn_comp_cb; + + ib_ca_handle_t h_ca; + ib_ca_attr_t *p_ca_attr; + ib_port_attr_t *p_src_port_attr; + ib_port_attr_t *p_dest_port_attr; + + ib_net32_t src_qp_num; + ib_net32_t dest_qp_num; + + ib_net64_t src_portguid; + uint8_t src_port_num; + + ib_net64_t dest_portguid; + uint8_t dest_port_num; + + ib_net16_t slid; + ib_net16_t dlid; + + ib_pool_key_t h_src_pool; + ib_pool_key_t h_dest_pool; + + ib_mad_svc_handle_t h_src_mad_svc; + ib_mad_svc_handle_t h_dest_mad_svc; + + boolean_t num_cq; + ib_cq_handle_t h_cq; + ib_cq_handle_t h_cq_alt; + uint32_t cq_size; + + ib_pd_handle_t h_pd; + + ib_qp_handle_t h_qp[MAX_QPS]; + uint32_t qkey; + + ib_qp_attr_t qp_attr[MAX_QPS]; + + ib_send_wr_t *p_send_wr; + ib_recv_wr_t *p_recv_wr; + size_t wr_send_size; + size_t wr_recv_size; + uint32_t num_wrs; + uint32_t ds_list_depth; + uint32_t msg_size; // Initialize this field + + ib_av_handle_t h_av_src; + ib_av_handle_t h_av_dest; + + uint32_t send_done; + uint32_t recv_done; + uint32_t cq_done; // total completions + boolean_t is_src; + + boolean_t is_loopback; + boolean_t reply_requested; + boolean_t rdma_enabled; + + // cm stuff + ib_path_rec_t path_src; + ib_path_rec_t path_dest; + + ib_cm_req_t req_src; + ib_cm_req_t req_dest; + + ib_cm_listen_t listen; + ib_listen_handle_t h_cm_listen; + + ib_cm_rep_t rep_dest; + + ib_cm_rtu_t rtu_src; + + uint32_t cm_cbs; + uint32_t cm_errs; + + ib_cm_dreq_t dreq_src; + ib_cm_drep_t drep_dest; + + cl_event_t mra_event; + boolean_t mra_test; + boolean_t rej_test; + + ib_cm_handle_t h_cm_req; + + cl_event_t destroy_event; + + boolean_t handoff; + ib_listen_handle_t h_cm_listen_handoff; + ib_net64_t handoff_svc_id; + + mem_region_t mem_region[10]; + +} alts_cm_ca_obj_t; +#pragma warning(default:4324) + +#define MAX_SERVER 500 + +typedef struct _alts_serv_object +{ + alts_cm_ca_obj_t alts_obj; + + ib_cq_handle_t h_cq[MAX_SERVER]; + ib_qp_handle_t h_qp[MAX_SERVER]; + +} alts_serv_object_t; + + +typedef struct _alts_rmda +{ + char msg_type; + uint64_t vaddr; + ib_net32_t rkey; + char msg[32]; +} alts_rdma_t; + +/* + * Function Prototypes + */ +ib_api_status_t +alts_cm_activate_qp( + alts_cm_ca_obj_t *p_ca_obj, + ib_qp_handle_t h_qp ); + +ib_api_status_t +alts_cm_check_active_ports( + alts_cm_ca_obj_t *p_ca_obj ); + +ib_api_status_t +alts_cm_destroy_resources( + alts_cm_ca_obj_t *p_ca_obj ); + +ib_api_status_t +alts_rc_deregister_mem( + alts_cm_ca_obj_t *p_ca_obj, + uint32_t reg_index ); + +ib_api_status_t +cm_post_sends( + alts_cm_ca_obj_t *p_ca_obj, + uint32_t reg_index, + uint32_t num_posts ); + +void +__mra_thread( + IN void* context ); + +/* + * QP Error callback function + */ +ib_api_status_t +alts_cm_rc_tests ( + ib_ca_handle_t h_ca, + uint32_t ca_attr_size ); + +ib_api_status_t +alts_cm_rc_rej_test ( + ib_ca_handle_t h_ca, + uint32_t ca_attr_size ); + +ib_api_status_t +alts_cm_handoff_test ( + ib_ca_handle_t h_ca, + uint32_t ca_attr_size ); + +ib_api_status_t +alts_cm_rc_flush_test ( + ib_ca_handle_t h_ca, + uint32_t ca_attr_size ); + +ib_api_status_t +alts_rc_no_cm_test ( + ib_ca_handle_t h_ca, + uint32_t ca_attr_size ); + +ib_api_status_t +alts_cm_rc_rdma_tests ( + ib_ca_handle_t h_ca, + uint32_t ca_attr_size ); + +ib_api_status_t +alts_rc_mra_test ( + ib_ca_handle_t h_ca, + uint32_t ca_attr_size ); + +ib_api_status_t +alts_cm_uc_test ( + ib_ca_handle_t h_ca, + uint32_t ca_attr_size ); + +ib_api_status_t +alts_cm_sidr_tests ( + ib_ca_handle_t h_ca, + uint32_t ca_attr_size ); + +#define ALTS_TEST_MGMT_CLASS 0x56 +#define ALTS_TEST_MGMT_CLASS_VER 1 + +/* + * Gloabal Variables + */ +ib_al_handle_t h_al; +ib_dgrm_info_t dgrm_info; +ib_mad_svc_t mad_svc; +ib_send_wr_t send_wr; +ib_local_ds_t send_ds; +ib_recv_wr_t recv_wr; +ib_local_ds_t recv_ds; +alts_cm_ca_obj_t *gp_ca_obj; + +extern ib_cq_create_t cq_create_attr; +extern ib_qp_create_t qp_create_attr; +extern ib_av_attr_t av_attr; +extern ib_wc_t free_wclist; +extern ib_wc_t free_wcl; + +ib_api_status_t cm_client_server=IB_NOT_FOUND; +ib_api_status_t cm_client_server_rej=IB_NOT_FOUND; +ib_api_status_t cm_client_server_flush=IB_NOT_FOUND; +ib_api_status_t cm_client_server_no_cm=IB_NOT_FOUND; +ib_api_status_t cm_rdma=IB_NOT_FOUND; +ib_api_status_t cm_mra=IB_NOT_FOUND; +ib_api_status_t cm_uc=IB_NOT_FOUND; +ib_api_status_t cm_sidr=IB_NOT_FOUND; +ib_api_status_t cm_handoff=IB_NOT_FOUND; + +/* This test case assumes that the HCA has 2 port connected + * through the switch. Sends packets from lower port number to higher + * port number. + */ +ib_api_status_t +al_test_cm(void) +{ + ib_api_status_t ib_status = IB_ERROR; + ib_ca_handle_t h_ca = NULL; + uint32_t bsize; + ib_ca_attr_t *p_ca_attr = NULL; + //alts_cm_ca_obj_t ca_obj; // for testing stack + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + do + { + /* + * Open the AL interface + */ + h_al = NULL; + ib_status = alts_open_al(&h_al); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_open_al failed status = %s\n", + ib_get_err_str( ib_status )) ); + break; + } + + /* + * Default opens the first CA + */ + ib_status = alts_open_ca(h_al, &h_ca); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_open_ca failed status = %s\n", + ib_get_err_str( ib_status )) ); + break; + } + + /* + * Get the CA Attributest + * Check for two active ports + */ + + /* + * Query the CA + */ + bsize = 0; + ib_status = ib_query_ca(h_ca, NULL, &bsize); + if(ib_status != IB_INSUFFICIENT_MEMORY) + { + ALTS_PRINT(ALTS_DBG_ERROR, + ("ib_query_ca failed with status = %s\n", + ib_get_err_str( ib_status )) ); + break; + } + + CL_ASSERT(bsize); + + cm_client_server = alts_cm_rc_tests(h_ca, bsize); + if(cm_client_server != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_cm_rc_tests() failed with status %s\n", + ib_get_err_str( cm_client_server )) ); + break; + } + ALTS_PRINT( ALTS_DBG_VERBOSE, + ("alts_cm_rc_tests() passed\n")); + + cm_client_server_rej = alts_cm_rc_rej_test(h_ca, bsize); + if(cm_client_server_rej != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_cm_rc_rej_test() failed with status %s\n", + ib_get_err_str( cm_client_server_rej )) ); + break; + } + ALTS_PRINT( ALTS_DBG_VERBOSE, + ("alts_cm_rc_rej_test() passed\n")); + + cm_client_server_flush = alts_cm_rc_flush_test(h_ca, bsize); + if(cm_client_server_flush != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_cm_rc_flush_test() failed with status %s\n", + ib_get_err_str( cm_client_server_flush )) ); + break; + } + ALTS_PRINT( ALTS_DBG_VERBOSE, + ("alts_cm_rc_flush_test() passed\n")); + + cm_client_server_no_cm = alts_rc_no_cm_test(h_ca, bsize); + if(cm_client_server_no_cm != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_rc_no_cm_test() failed with status %s\n", + ib_get_err_str( cm_client_server_no_cm )) ); + break; + } + ALTS_PRINT( ALTS_DBG_VERBOSE, + ("alts_rc_no_cm_test() passed\n")); + + cm_rdma = alts_cm_rc_rdma_tests(h_ca, bsize); + if(cm_rdma != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_cm_rc_rdma_tests() failed with status %s\n", + ib_get_err_str( cm_rdma )) ); + break; + } + ALTS_PRINT( ALTS_DBG_VERBOSE, + ("alts_cm_rc_rdma_tests() passed\n")); + + cm_mra = alts_rc_mra_test(h_ca, bsize); + if(cm_mra != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_rc_mra_test() failed with status %s\n", + ib_get_err_str( cm_mra )) ); + break; + } + ALTS_PRINT( ALTS_DBG_VERBOSE, + ("alts_rc_mra_test() passed\n")); + + cm_handoff = alts_cm_handoff_test(h_ca, bsize); + if(cm_handoff != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_cm_handoff_test() failed with status %s\n", + ib_get_err_str( cm_handoff )) ); + break; + } + ALTS_PRINT( ALTS_DBG_VERBOSE, + ("alts_cm_handoff_test() passed\n")); + + cm_uc = alts_cm_uc_test(h_ca, bsize); + if(cm_uc != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_cm_uc_test() failed with status %s\n", + ib_get_err_str( cm_uc )) ); + break; + } + ALTS_PRINT( ALTS_DBG_VERBOSE, + ("alts_cm_uc_test() passed\n")); + + cm_sidr = alts_cm_sidr_tests(h_ca, bsize); + if(cm_sidr != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_cm_sidr_tests() failed with status %s\n", + ib_get_err_str( cm_sidr )) ); + break; + } + ALTS_PRINT( ALTS_DBG_VERBOSE, + ("alts_cm_sidr_tests() passed\n")); + + } while (0); + + /* + * Destroy the resources + */ + if (p_ca_attr) + cl_free(p_ca_attr); + + ALTS_PRINT(ALTS_DBG_STATUS, + ("Test results (cm):\n" + "\trc client server......: %s\n" + "\trc reject.............: %s\n" + "\tqp flush on disconnect: %s\n" + "\trc no cm..............: %s\n" + "\trmda..................: %s\n" + "\tmra...................: %s\n" + "\thandoff...............: %s\n" + "\tuc....................: %s\n" + "\tsidr..................: %s\n", + ib_get_err_str(cm_client_server), + ib_get_err_str(cm_client_server_rej), + ib_get_err_str(cm_client_server_flush), + ib_get_err_str(cm_client_server_no_cm), + ib_get_err_str(cm_rdma), + ib_get_err_str(cm_mra), + ib_get_err_str(cm_handoff), + ib_get_err_str(cm_uc), + ib_get_err_str(cm_sidr) + )); + + if( h_al ) + alts_close_al(h_al); + + ALTS_EXIT( ALTS_DBG_VERBOSE); + + return ib_status; + +} + +static void +__alts_cm_destroy_pd_cb( + IN void *context ) +{ + cl_event_signal( &((alts_cm_ca_obj_t*)context)->destroy_event ); +} + +ib_api_status_t +alts_cm_destroy_resources( + alts_cm_ca_obj_t *p_ca_obj) +{ + uint32_t i, j; + + /* + * Destroy Send QP, Recv QP, CQ and PD + */ + ib_api_status_t ib_status = IB_SUCCESS; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + if (p_ca_obj->h_qp[SRC_QP]) + { + ib_status = ib_destroy_qp(p_ca_obj->h_qp[SRC_QP], NULL); + } + + if (p_ca_obj->is_loopback != TRUE) + { + if (p_ca_obj->h_qp[DEST_QP]) + { + ib_status = ib_destroy_qp(p_ca_obj->h_qp[DEST_QP], NULL); + } + } + + if (p_ca_obj->h_cq) + ib_status = ib_destroy_cq(p_ca_obj->h_cq, NULL); + if (p_ca_obj->h_cq_alt) + ib_status = ib_destroy_cq(p_ca_obj->h_cq_alt, NULL); + + // deregister mem + for (i=0; i < p_ca_obj->num_wrs; i++) + { + alts_rc_deregister_mem(p_ca_obj, i); + } + + // send + for (j=i; j < i + p_ca_obj->num_wrs; j++) + { + ib_status = alts_rc_deregister_mem(p_ca_obj, j); + } + + if (p_ca_obj->h_pd) + { + ib_status = ib_dealloc_pd(p_ca_obj->h_pd,__alts_cm_destroy_pd_cb); + cl_event_wait_on( &p_ca_obj->destroy_event, EVENT_NO_TIMEOUT, FALSE ); + } + + //cl_thread_suspend( 1000 ); + cl_event_destroy( &p_ca_obj->destroy_event ); + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + + +ib_api_status_t +alts_sidr_message_passing( + alts_cm_ca_obj_t *p_ca_obj) +{ + ib_api_status_t ib_status = IB_SUCCESS; + ib_mad_element_t *p_mad_element; + ib_mad_t *p_mad; + char *p_buf; + uint32_t i; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + + //Create an Address vector + av_attr.dlid = p_ca_obj->dlid; + av_attr.port_num = p_ca_obj->src_port_num; + av_attr.sl = 0; + av_attr.path_bits = 0; + av_attr.static_rate = IB_PATH_RECORD_RATE_10_GBS; + av_attr.grh_valid = FALSE; + + ib_status = ib_create_av(p_ca_obj->h_pd,&av_attr,&p_ca_obj->h_av_src); + if(ib_status != IB_SUCCESS) + return ib_status; + + p_ca_obj->send_done = 0; + p_ca_obj->recv_done = 0; + p_ca_obj->cq_done = 0; + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("++++++ dlid(x%x) src_port(%d) ====\n", + av_attr.dlid, av_attr.port_num)); + + for (i=0; inum_wrs; i++) + { + p_mad_element = NULL; + ib_status = ib_get_mad( + p_ca_obj->h_src_pool, + MAD_BLOCK_SIZE, + &p_mad_element ); + if (ib_status != IB_SUCCESS) + { + ALTS_TRACE_EXIT(ALTS_DBG_VERBOSE, + ("Error in ib_get_mad()! %s\n", ib_get_err_str(ib_status))); + return (ib_status); + } + + // format mad + p_mad_element->context1 = (void *)1; + p_mad_element->context2 = p_ca_obj; + + /* Send request information. */ + p_mad_element->h_av = p_ca_obj->h_av_src; + p_mad_element->send_opt = IB_SEND_OPT_SIGNALED; + + + if (p_ca_obj->reply_requested == TRUE) + p_mad_element->resp_expected = TRUE; + else + p_mad_element->resp_expected = FALSE; //TRUE; + + p_mad_element->remote_qp = p_ca_obj->qp_attr[DEST_QP].num; + + p_mad_element->remote_qkey = p_ca_obj->qkey; + p_mad_element->timeout_ms = 10; + p_mad_element->retry_cnt = 1; + + /* Completion information. */ + p_mad_element->status = 0; + + // format mad + p_mad = p_mad_element->p_mad_buf; + + p_buf = (char *)p_mad; + cl_memset(p_buf, 0x66, 256); // set pattern in buffer + + + switch (p_ca_obj->qp_attr[SRC_QP].num) + { + case IB_QP0: + ib_mad_init_new( + p_mad, + IB_MCLASS_SUBN_LID, + ALTS_TEST_MGMT_CLASS_VER, + IB_MAD_METHOD_GET, + (ib_net64_t) CL_NTOH64(0x666), + IB_MAD_ATTR_SM_INFO, + 0 ); + break; + + case IB_QP1: + default: + ib_mad_init_new( + p_mad, + ALTS_TEST_MGMT_CLASS, + ALTS_TEST_MGMT_CLASS_VER, + IB_MAD_METHOD_GET, + (ib_net64_t) CL_NTOH64(0x666), + IB_MAD_ATTR_CLASS_PORT_INFO, + 0 ); + break; + } + + // send + ib_status = ib_send_mad( + p_ca_obj->h_src_mad_svc, + p_mad_element, + NULL ); + + if(ib_status != IB_SUCCESS) + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("ib_send_mad failed\n")); + + //cl_thread_suspend(10); // 10 usec + } + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("sleeping for awhile ...\n")); + + cl_thread_suspend(10000); // 10 seconds + + if (((!p_ca_obj->cq_done) && (p_ca_obj->num_wrs> 2)) || + (p_ca_obj->cq_done != p_ca_obj->num_wrs*2)) + { + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("sleeping for awhile ...\n")); + cl_thread_suspend(10000); // 10 seconds + } + + + if (((!p_ca_obj->cq_done) && (p_ca_obj->num_wrs> 2)) || + (p_ca_obj->cq_done != p_ca_obj->num_wrs*2)) + { + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("sleeping for awhile ...\n")); + cl_thread_suspend(10000); // 10 seconds + } + + if (((!p_ca_obj->cq_done) && (p_ca_obj->num_wrs> 2)) || + (p_ca_obj->cq_done != p_ca_obj->num_wrs*2)) + { + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("sleeping for awhile ...\n")); + cl_thread_suspend(10000); // 10 seconds + } + + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + +ib_api_status_t +cm_post_sends( + alts_cm_ca_obj_t *p_ca_obj, + uint32_t reg_index, + uint32_t num_posts ) +{ + ib_send_wr_t *p_s_wr, *p_send_failure_wr; + uint32_t msg_size, i; + ib_api_status_t ib_status = IB_SUCCESS; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + if (p_ca_obj->test_type == IB_QPT_UNRELIABLE_DGRM) + msg_size = p_ca_obj->msg_size - sizeof(ib_grh_t); + else + msg_size = 64; + + //msg_size = p_ca_obj->msg_size; + + msg_size = 64; + + p_s_wr = p_ca_obj->p_send_wr; + + p_s_wr->p_next = NULL; + p_s_wr->ds_array[0].length = msg_size; + p_s_wr->num_ds = 1; + + p_s_wr->wr_type = WR_SEND; + + if (p_ca_obj->test_type == IB_QPT_UNRELIABLE_DGRM) + { + p_s_wr->dgrm.ud.h_av = p_ca_obj->h_av_src; + p_s_wr->send_opt = IB_SEND_OPT_SIGNALED | IB_SEND_OPT_SOLICITED; +// p_s_wr->send_opt = IB_SEND_OPT_IMMEDIATE | + + p_s_wr->dgrm.ud.remote_qkey = p_ca_obj->qkey; + p_s_wr->dgrm.ud.remote_qp = p_ca_obj->qp_attr[DEST_QP].num; + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("======= qkey(x%x) qp_num(x%x) ========\n", + p_s_wr->dgrm.ud.remote_qkey, + p_s_wr->dgrm.ud.remote_qp)); + + } + else if ( (p_ca_obj->test_type == IB_QPT_RELIABLE_CONN) || + (p_ca_obj->test_type == IB_QPT_UNRELIABLE_CONN) ) + { + p_s_wr->send_opt = IB_SEND_OPT_SIGNALED | IB_SEND_OPT_SOLICITED; +// p_s_wr->send_opt = IB_SEND_OPT_IMMEDIATE | + + /* + p_s_wr->send_opt = IB_SEND_OPT_SIGNALED | \ + IB_SEND_OPT_IMMEDIATE | \ + IB_SEND_OPT_SOLICITED ;*/ + + } + + + for (i = 0; i < num_posts; i++) + { + p_s_wr->wr_id = i+reg_index; + p_s_wr->immediate_data = 0xfeedde00 + i; + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("******vaddr(x%"PRIx64") lkey(x%x) len(%d)*****\n", + (void*)(uintn_t)p_s_wr->ds_array[0].vaddr, + p_s_wr->ds_array[0].lkey, + p_s_wr->ds_array[0].length)); + + ib_status = ib_post_send( + p_ca_obj->h_qp[SRC_QP], + p_s_wr, + &p_send_failure_wr); + + } + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + + +ib_api_status_t +alts_cm_check_active_ports(alts_cm_ca_obj_t *p_ca_obj) +{ + ib_api_status_t ib_status; + ib_ca_attr_t *p_ca_attr; + ib_port_attr_t *p_src_port_attr = NULL; + ib_port_attr_t *p_dest_port_attr = NULL; + uint32_t i; + ib_port_attr_t *p_port_attr; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + CL_ASSERT(p_ca_obj); + + p_ca_attr = p_ca_obj->p_ca_attr; + + CL_ASSERT(p_ca_attr); + + for(i=0; i< p_ca_attr->num_ports; i++) + { + p_port_attr = &p_ca_attr->p_port_attr[i]; + + if (p_port_attr->link_state == IB_LINK_ACTIVE) + { + if (p_src_port_attr == NULL) + p_src_port_attr = p_port_attr; + else + if(p_dest_port_attr == NULL) + p_dest_port_attr = p_port_attr; + else + break; + } + } + + // handle loopback case + if (p_ca_obj->is_loopback == TRUE) + p_dest_port_attr = p_src_port_attr; + + if (p_src_port_attr && p_dest_port_attr) + { + p_ca_obj->p_dest_port_attr = p_dest_port_attr; + p_ca_obj->p_src_port_attr = p_src_port_attr; + + p_ca_obj->dlid = p_dest_port_attr->lid; + p_ca_obj->slid = p_src_port_attr->lid; + + p_ca_obj->dest_portguid = p_dest_port_attr->port_guid; + p_ca_obj->src_portguid = p_src_port_attr->port_guid; + + p_ca_obj->dest_port_num = p_dest_port_attr->port_num; + p_ca_obj->src_port_num = p_src_port_attr->port_num; + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("**** slid = x%x (x%x) ***dlid = x%x (x%x) ***************\n", + p_ca_obj->slid, + CL_NTOH16(p_ca_obj->slid), + p_ca_obj->dlid, + CL_NTOH16(p_ca_obj->dlid) )); + + ib_status = IB_SUCCESS; + + } + else + { + + ib_status = IB_ERROR; + } + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + +void +rc_cm_cq_comp_cb( + void *cq_context, + ib_qp_type_t qp_type + ) +{ + ib_api_status_t ib_status; + uint32_t i = 0, id; + ib_wc_t *p_free_wcl, *p_done_cl= NULL; + alts_cm_ca_obj_t *p_ca_obj; + ib_cq_handle_t h_cq; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + CL_ASSERT(cq_context); + + h_cq = *((ib_cq_handle_t*)cq_context); + p_ca_obj = gp_ca_obj; + + ib_status = ib_rearm_cq(h_cq, FALSE); + + p_free_wcl = &free_wcl; + p_free_wcl->p_next = NULL; + p_done_cl = NULL; + + ib_status = ib_poll_cq(h_cq, &p_free_wcl, &p_done_cl); + + while(p_done_cl) + { + + /* + * print output + */ + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("Got a completion:\n" + "\ttype....:%s\n" + "\twr_id...:%"PRIx64"\n" + "status....:%s\n", + ib_get_wc_type_str(p_done_cl->wc_type), + p_done_cl->wr_id, + ib_get_wc_status_str(p_done_cl->status) )); + + + if (p_done_cl->wc_type == IB_WC_RECV) + { + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("message length..:%d bytes\n", + p_done_cl->length )); + + id = (uint32_t)p_done_cl->wr_id; + + if (qp_type == IB_QPT_UNRELIABLE_DGRM) + { + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("RecvUD info:\n" + "\trecv_opt...:x%x\n" + "\timm_data...:x%x\n" + "\tremote_qp..:x%x\n" + "\tpkey_index.:%d\n" + "\tremote_lid.:x%x\n" + "\tremote_sl..:x%x\n" + "\tpath_bits..:x%x\n", + p_done_cl->recv.ud.recv_opt, + p_done_cl->recv.ud.immediate_data, + CL_NTOH32(p_done_cl->recv.ud.remote_qp), + p_done_cl->recv.ud.pkey_index, + CL_NTOH16(p_done_cl->recv.ud.remote_lid), + p_done_cl->recv.ud.remote_sl, + p_done_cl->recv.ud.path_bits)); + } + else + { + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("RecvRC info:\n" + "\trecv_opt...:x%x\n" + "\timm_data...:x%x\n", + p_done_cl->recv.conn.recv_opt, + p_done_cl->recv.ud.immediate_data )); + } + + } + + p_free_wcl = p_done_cl; + p_free_wcl->p_next = NULL; + p_done_cl = NULL; + i++; + + ib_status = ib_poll_cq(h_cq, &p_free_wcl, &p_done_cl); + } + + p_ca_obj->cq_done += i; + + ALTS_PRINT( ALTS_DBG_INFO, + ("Number of items polled from CQ (in callback=%d) (total=%d)\n", + i, + p_ca_obj->cq_done) ); + + + ALTS_EXIT( ALTS_DBG_VERBOSE); +} + +ib_api_status_t +rc_rdma_write_send( + alts_cm_ca_obj_t *p_ca_obj, + uint32_t reg_index ) +{ + ib_send_wr_t *p_s_wr, *p_send_failure_wr; + uint32_t msg_size; + ib_api_status_t ib_status = IB_SUCCESS; + alts_rdma_t *p_rdma_req; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + msg_size = 64; + //msg_size = p_ca_obj->msg_size; + + p_s_wr = p_ca_obj->p_send_wr; + + p_s_wr->p_next = NULL; + p_s_wr->ds_array[0].length = msg_size; + p_s_wr->num_ds = 1; + + p_s_wr->wr_type = WR_RDMA_WRITE; + + p_s_wr->send_opt = IB_SEND_OPT_SOLICITED ; + //IB_SEND_OPT_IMMEDIATE | + p_s_wr->send_opt = IB_SEND_OPT_SIGNALED; + + p_s_wr->ds_array[0].vaddr = + (uintn_t)p_ca_obj->mem_region[reg_index].buffer; + p_s_wr->ds_array[0].lkey = p_ca_obj->mem_region[reg_index].lkey; + + p_s_wr->wr_id = reg_index; + p_s_wr->immediate_data = 0xfeedde00 + reg_index; + + p_rdma_req = (alts_rdma_t*)p_ca_obj->mem_region[reg_index].buffer; + p_s_wr->remote_ops.vaddr = p_rdma_req->vaddr; + p_s_wr->remote_ops.rkey = p_rdma_req->rkey; + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("******vaddr(x%"PRIx64") lkey(x%x) len(%d)*****\n", + (void*)(uintn_t)p_s_wr->ds_array[0].vaddr, + p_s_wr->ds_array[0].lkey, + p_s_wr->ds_array[0].length)); + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("******remote:vaddr(x%"PRIx64") rkey(x%x) len(%d)*****\n", + p_s_wr->remote_ops.vaddr, + p_s_wr->remote_ops.rkey, + p_s_wr->ds_array[0].length)); + + ib_status = ib_post_send( + p_ca_obj->h_qp[DEST_QP], + p_s_wr, + &p_send_failure_wr); + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + +ib_api_status_t +rc_rdma_read_send( + alts_cm_ca_obj_t *p_ca_obj, + uint32_t reg_index ) +{ + ib_send_wr_t *p_s_wr, *p_send_failure_wr; + uint32_t msg_size; + ib_api_status_t ib_status = IB_SUCCESS; + alts_rdma_t *p_rdma_req; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + msg_size = 64; + //msg_size = p_ca_obj->msg_size; + + p_s_wr = p_ca_obj->p_send_wr; + + p_s_wr->p_next = NULL; + p_s_wr->ds_array[0].length = msg_size; + p_s_wr->num_ds = 1; + + p_s_wr->wr_type = WR_RDMA_READ; + + //p_s_wr->send_opt = IB_SEND_OPT_SOLICITED ; + //IB_SEND_OPT_IMMEDIATE | + p_s_wr->send_opt = IB_SEND_OPT_SIGNALED; + + p_s_wr->ds_array[0].vaddr = + (uintn_t)p_ca_obj->mem_region[reg_index].buffer; + p_s_wr->ds_array[0].lkey = p_ca_obj->mem_region[reg_index].lkey; + + p_s_wr->wr_id = reg_index; + p_s_wr->immediate_data = 0xfeedde00 + reg_index; + + p_rdma_req = (alts_rdma_t*)p_ca_obj->mem_region[reg_index].buffer; + cl_memclr( p_rdma_req->msg, 64 ); + p_s_wr->remote_ops.vaddr = p_rdma_req->vaddr; + p_s_wr->remote_ops.rkey = p_rdma_req->rkey; + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("******vaddr(x%"PRIx64") lkey(x%x) len(%d)*****\n", + (void*)(uintn_t)p_s_wr->ds_array[0].vaddr, + p_s_wr->ds_array[0].lkey, + p_s_wr->ds_array[0].length)); + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("******remote:vaddr(x%"PRIx64") rkey(x%x) len(%d)*****\n", + p_s_wr->remote_ops.vaddr, + p_s_wr->remote_ops.rkey, + p_s_wr->ds_array[0].length)); + + ib_status = ib_post_send( + p_ca_obj->h_qp[DEST_QP], + p_s_wr, + &p_send_failure_wr); + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + +void +process_response( + IN alts_cm_ca_obj_t *p_ca_obj, + IN alts_rdma_t *p_data, + IN uint32_t reg_index ) +{ + + switch(p_data->msg_type) + { + case 'W': + ALTS_PRINT( ALTS_DBG_INFO, ("RDMA Write requested\n" ) ); + p_data->msg_type = 'C'; + rc_rdma_write_send( p_ca_obj, reg_index ); + break; + case 'R': + ALTS_PRINT( ALTS_DBG_INFO, ("RDMA Read requested\n" ) ); + p_data->msg_type = 'C'; + rc_rdma_read_send( p_ca_obj, reg_index ); + break; + + case 'C': + ALTS_PRINT( ALTS_DBG_INFO, ("Msg completed. [%s]\n", + p_data->msg ) ); + break; + + default: + ALTS_PRINT(ALTS_DBG_ERROR, ("Bad RDMA msg!!!\n")); + break; + } + + +} + +void +rdma_cq_comp_cb( + void *cq_context, + ib_qp_type_t qp_type + ) +{ + ib_api_status_t ib_status; + uint32_t i = 0, id; + ib_wc_t *p_free_wcl, *p_done_cl= NULL; + alts_cm_ca_obj_t *p_ca_obj; + ib_cq_handle_t h_cq; + alts_rdma_t *p_data; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + UNUSED_PARAM( qp_type ); + + CL_ASSERT(cq_context); + + h_cq = *((ib_cq_handle_t*)cq_context); + p_ca_obj = gp_ca_obj; + + ib_status = ib_rearm_cq(h_cq, FALSE); + + p_free_wcl = &free_wcl; + p_free_wcl->p_next = NULL; + p_done_cl = NULL; + + ib_status = ib_poll_cq(h_cq, &p_free_wcl, &p_done_cl); + + while(p_done_cl) + { + /* + * print output + */ + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("Got a completion:\n" + "\ttype....:%s\n" + "\twr_id...:%"PRIx64"\n" + "status....:%s\n", + ib_get_wc_type_str(p_done_cl->wc_type), + p_done_cl->wr_id, + ib_get_wc_status_str(p_done_cl->status) )); + + if( p_done_cl->status == IB_WCS_SUCCESS ) + { + if (p_done_cl->wc_type == IB_WC_RECV) + { + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("message length..:%d bytes\n", + p_done_cl->length )); + + id = (uint32_t)p_done_cl->wr_id; + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("RecvRC info:\n" + "\trecv_opt...:x%x\n" + "\timm_data...:x%x\n", + p_done_cl->recv.conn.recv_opt, + p_done_cl->recv.ud.immediate_data )); + + if( p_ca_obj->rdma_enabled == TRUE ) + { + process_response( p_ca_obj, + (alts_rdma_t*)p_ca_obj->mem_region[p_done_cl->wr_id].buffer, + (uint32_t)p_done_cl->wr_id ); + } + } + else + if (p_done_cl->wc_type == IB_WC_RDMA_WRITE) + { + // convert request to read now + p_data = + (alts_rdma_t*)p_ca_obj->mem_region[p_done_cl->wr_id].buffer; + p_data->msg_type = 'R'; + process_response( p_ca_obj, + p_data, + (uint32_t)p_done_cl->wr_id ); + } + else + if (p_done_cl->wc_type == IB_WC_RDMA_READ) + { + id = (uint32_t)p_done_cl->wr_id; + process_response( p_ca_obj, + (alts_rdma_t*)p_ca_obj->mem_region[p_done_cl->wr_id].buffer, + (uint32_t)p_done_cl->wr_id ); + } + } + + p_free_wcl = p_done_cl; + p_free_wcl->p_next = NULL; + p_done_cl = NULL; + i++; + + ib_status = ib_poll_cq(h_cq, &p_free_wcl, &p_done_cl); + } + + p_ca_obj->cq_done += i; + + ALTS_PRINT( ALTS_DBG_INFO, + ("Number of items polled from CQ (in callback=%d) (total=%d)\n", + i, + p_ca_obj->cq_done) ); + + + ALTS_EXIT( ALTS_DBG_VERBOSE); +} + +void +cm_rc_cq_comp_cb( + IN const ib_cq_handle_t h_cq, + IN void *cq_context ) +{ + UNUSED_PARAM( h_cq ); + rc_cm_cq_comp_cb (cq_context, IB_QPT_RELIABLE_CONN); +} + +void +cm_ud_cq_comp_cb( + IN const ib_cq_handle_t h_cq, + IN void *cq_context ) +{ + UNUSED_PARAM( h_cq ); + rc_cm_cq_comp_cb(cq_context, IB_QPT_UNRELIABLE_DGRM); +} + +void +cm_rdma_cq_comp_cb( + IN const ib_cq_handle_t h_cq, + IN void *cq_context ) +{ + UNUSED_PARAM( h_cq ); + rdma_cq_comp_cb(cq_context, IB_QPT_RELIABLE_CONN); +} + +void +rc_cm_cq_err_cb( + ib_async_event_rec_t *p_err_rec + ) +{ + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + UNUSED_PARAM( p_err_rec ); + + ALTS_EXIT( ALTS_DBG_VERBOSE); +} + +void +rc_cm_qp_err_cb( + ib_async_event_rec_t *p_err_rec + ) +{ + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + UNUSED_PARAM( p_err_rec ); + + ALTS_EXIT( ALTS_DBG_VERBOSE); +} + +void +rc_cm_qp_destroy_cb( + void *context + ) +{ + /* + * QP destroy call back + */ + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + UNUSED_PARAM( context ); + + ALTS_EXIT( ALTS_DBG_VERBOSE); +} + +ib_api_status_t +alts_create_test_resources( alts_cm_ca_obj_t *p_ca_obj ) +{ + ib_api_status_t ib_status; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + gp_ca_obj = p_ca_obj; + + cl_event_init( &p_ca_obj->destroy_event, FALSE ); + + cl_memclr(&qp_create_attr, sizeof(ib_qp_create_t)); + + /* + * Allocate a PD + */ + ib_status = ib_alloc_pd( + p_ca_obj->h_ca, + IB_PDT_NORMAL, + p_ca_obj, //pd_context + &p_ca_obj->h_pd); + + CL_ASSERT(ib_status == IB_SUCCESS); + + /* + * Create CQ Attributes + */ + cq_create_attr.size = p_ca_obj->cq_size; + cq_create_attr.pfn_comp_cb = p_ca_obj->pfn_comp_cb; + cq_create_attr.h_wait_obj = NULL; + + if( p_ca_obj->rdma_enabled ) + { + cq_create_attr.pfn_comp_cb = cm_rdma_cq_comp_cb; + } + + ib_status = ib_create_cq( + p_ca_obj->h_ca, + &cq_create_attr, + &p_ca_obj->h_cq, + rc_cm_cq_err_cb, + &p_ca_obj->h_cq ); + CL_ASSERT(ib_status == IB_SUCCESS); + + + p_ca_obj->cq_size = cq_create_attr.size; + + if( p_ca_obj->num_cq > 1 ) + { + ib_status = ib_create_cq( + p_ca_obj->h_ca, + &cq_create_attr, + &p_ca_obj->h_cq_alt, + rc_cm_cq_err_cb, + &p_ca_obj->h_cq_alt ); + + CL_ASSERT(ib_status == IB_SUCCESS); + CL_ASSERT(p_ca_obj->cq_size == cq_create_attr.size); + } + + /* + * Create QP Attributes + */ + qp_create_attr.sq_depth = p_ca_obj->num_wrs; + qp_create_attr.rq_depth = p_ca_obj->num_wrs; + qp_create_attr.sq_sge = 1; + qp_create_attr.rq_sge = 1; + + if( p_ca_obj->num_cq > 1 ) + qp_create_attr.h_sq_cq = p_ca_obj->h_cq_alt; + else + qp_create_attr.h_sq_cq = p_ca_obj->h_cq; + + qp_create_attr.h_rq_cq = p_ca_obj->h_cq; + + qp_create_attr.sq_signaled = TRUE; + //qp_create_attr.sq_signaled = FALSE; + + qp_create_attr.qp_type = p_ca_obj->test_type; + + ib_status = ib_create_qp( + p_ca_obj->h_pd, + &qp_create_attr, + p_ca_obj, + rc_cm_qp_err_cb, + &p_ca_obj->h_qp[SRC_QP]); + + if (ib_status != IB_SUCCESS) + { + ALTS_TRACE_EXIT(ALTS_DBG_VERBOSE, + ("Error in ib_create_qp()! %s\n", + ib_get_err_str(ib_status))); + + return (ib_status); + } + + ib_status = ib_query_qp(p_ca_obj->h_qp[SRC_QP], + &p_ca_obj->qp_attr[SRC_QP]); + + if (ib_status != IB_SUCCESS) + { + ALTS_TRACE_EXIT(ALTS_DBG_VERBOSE, + ("Error in query_qp()! %s\n", + ib_get_err_str(ib_status))); + + ib_destroy_qp(p_ca_obj->h_qp[SRC_QP],rc_cm_qp_destroy_cb); + return (ib_status); + } + + if (p_ca_obj->is_loopback == TRUE) + { + // do loopback on same QP + p_ca_obj->h_qp[DEST_QP] = p_ca_obj->h_qp[SRC_QP]; + } + else + { + ib_status = ib_create_qp( + p_ca_obj->h_pd, + &qp_create_attr, + p_ca_obj, + rc_cm_qp_err_cb, + &p_ca_obj->h_qp[DEST_QP]); + + if (ib_status != IB_SUCCESS) + { + ALTS_TRACE_EXIT(ALTS_DBG_VERBOSE, + ("Error in ib_create_qp()! %s\n", + ib_get_err_str(ib_status))); + + ib_destroy_qp(p_ca_obj->h_qp[SRC_QP],rc_cm_qp_destroy_cb); + return (ib_status); + } + + ib_status = ib_query_qp(p_ca_obj->h_qp[DEST_QP], + &p_ca_obj->qp_attr[DEST_QP]); + + //CL_ASSERT(ib_status == IB_SUCCESS); + if (ib_status != IB_SUCCESS) + { + ALTS_TRACE_EXIT(ALTS_DBG_VERBOSE, + ("Error in query_qp()! %s\n", + ib_get_err_str(ib_status))); + + ib_destroy_qp(p_ca_obj->h_qp[DEST_QP],rc_cm_qp_destroy_cb); + return (ib_status); + } + } + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + +ib_api_status_t +alts_rc_register_mem( + alts_cm_ca_obj_t *p_ca_obj, + uint32_t reg_index, + uint32_t size ) +{ + ib_mr_create_t mr_create = {0}; + ib_api_status_t ib_status = IB_SUCCESS; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + cl_memclr(&mr_create, sizeof(ib_mr_create_t)); + p_ca_obj->mem_region[reg_index].buffer = cl_zalloc(size); + CL_ASSERT (p_ca_obj->mem_region[reg_index].buffer); + + mr_create.vaddr = p_ca_obj->mem_region[reg_index].buffer; + mr_create.length = size; + mr_create.access_ctrl = + IB_AC_LOCAL_WRITE | IB_AC_RDMA_READ | IB_AC_RDMA_WRITE; + + ib_status = ib_reg_mem( + p_ca_obj->h_pd, + &mr_create, + &p_ca_obj->mem_region[reg_index].lkey, + &p_ca_obj->mem_region[reg_index].rkey, + &p_ca_obj->mem_region[reg_index].mr_h); + + ALTS_EXIT( ALTS_DBG_VERBOSE); + + return ib_status; +} + +ib_api_status_t +alts_rc_deregister_mem( + alts_cm_ca_obj_t *p_ca_obj, + uint32_t reg_index + ) +{ + ib_api_status_t ib_status; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + if ( p_ca_obj->mem_region[reg_index].buffer != NULL ) + { + /* + * At times the buffer may have been allocated without a register + */ + if (p_ca_obj->mem_region[reg_index].mr_h) + ib_status = ib_dereg_mr(p_ca_obj->mem_region[reg_index].mr_h); + else + ib_status = IB_ERROR; + + CL_ASSERT(ib_status == IB_SUCCESS); + + if ( ib_status != IB_SUCCESS ) + { + //PRINT the error msg + } + + cl_free(p_ca_obj->mem_region[reg_index].buffer); + + p_ca_obj->mem_region[reg_index].buffer = NULL; + } + else + { + ib_status = IB_ERROR; + + } + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + + +ib_api_status_t +rc_multisend_post_sends( + alts_cm_ca_obj_t *p_ca_obj, + uint32_t reg_index, + uint32_t num_posts ) +{ + ib_send_wr_t *p_s_wr, *p_send_failure_wr; + uint32_t msg_size, i; + ib_api_status_t ib_status = IB_SUCCESS; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + msg_size = 64; + //msg_size = p_ca_obj->msg_size; + + p_s_wr = p_ca_obj->p_send_wr; + + p_s_wr->p_next = NULL; + p_s_wr->ds_array[0].length = msg_size; + p_s_wr->num_ds = 1; + + p_s_wr->wr_type = WR_SEND; + + if( num_posts > 1 ) + { + p_s_wr->send_opt = IB_SEND_OPT_SOLICITED ; + } + else + { + p_s_wr->send_opt = IB_SEND_OPT_SIGNALED | \ + IB_SEND_OPT_IMMEDIATE | \ + IB_SEND_OPT_SOLICITED ; + } + + p_s_wr->send_opt = IB_SEND_OPT_SIGNALED | \ + IB_SEND_OPT_IMMEDIATE | \ + IB_SEND_OPT_SOLICITED ; + + + for (i = 0; i < num_posts; i++) + { + sprintf((char *)p_ca_obj->mem_region[i+reg_index].buffer,"hello %d", i); + + p_s_wr->ds_array[0].vaddr = + (uintn_t)p_ca_obj->mem_region[i+reg_index].buffer; + p_s_wr->ds_array[0].lkey = p_ca_obj->mem_region[i+reg_index].lkey; + + p_s_wr->wr_id = i+reg_index; + p_s_wr->immediate_data = 0xfeedde00 + i; + + p_s_wr->remote_ops.vaddr = 0; + p_s_wr->remote_ops.rkey = 0; + + //p_s_wr->dgrm.ud.h_av + if( (i > 0) && (i == ( num_posts - 1 ))) + { + p_s_wr->send_opt = IB_SEND_OPT_SIGNALED | \ + IB_SEND_OPT_IMMEDIATE | \ + IB_SEND_OPT_SOLICITED ; + } + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("******vaddr(x%"PRIx64") lkey(x%x) len(%d) send_opts(x%x)*****\n", + (void*)(uintn_t)p_s_wr->ds_array[0].vaddr, + p_s_wr->ds_array[0].lkey, + p_s_wr->ds_array[0].length, + p_s_wr->send_opt )); + + ib_status = ib_post_send( + p_ca_obj->h_qp[SRC_QP], + p_s_wr, + &p_send_failure_wr); + + } + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + +ib_api_status_t +rc_multisend_post_recvs( + alts_cm_ca_obj_t *p_ca_obj, + uint32_t reg_index, + uint32_t num_posts ) +{ + ib_recv_wr_t *p_r_wr, *p_failure_wr; + uint32_t msg_size, i; + ib_api_status_t ib_status = IB_SUCCESS; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + + msg_size = 64; + //msg_size = p_ca_obj->msg_size; + + p_r_wr = p_ca_obj->p_recv_wr; + + p_r_wr->p_next = NULL; + p_r_wr->ds_array[0].length = msg_size; + p_r_wr->num_ds = 1; + + for (i = 0; i < num_posts; i++) + { + p_r_wr->ds_array[0].vaddr = + (uintn_t)p_ca_obj->mem_region[i+reg_index].buffer; + p_r_wr->ds_array[0].lkey = p_ca_obj->mem_region[i+reg_index].lkey; + + p_r_wr->wr_id = i+reg_index; + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("******vaddr(x%"PRIx64") lkey(x%x) len(%d)*****\n", + (void*)(uintn_t)p_r_wr->ds_array[0].vaddr, + p_r_wr->ds_array[0].lkey, + p_r_wr->ds_array[0].length)); + + if (p_ca_obj->is_loopback == TRUE) + { + ib_status = ib_post_recv( + p_ca_obj->h_qp[SRC_QP], + p_r_wr, + &p_failure_wr); + } + else + { + ib_status = ib_post_recv( + p_ca_obj->h_qp[DEST_QP], + p_r_wr, + &p_failure_wr); + } + } + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + +ib_api_status_t +alts_rc_message_passing( + alts_cm_ca_obj_t *p_ca_obj, + ib_qp_type_t qp_type) +{ + uint32_t i,j, k; + ib_api_status_t ib_status = IB_SUCCESS; + ib_wc_t *p_free_wclist; + ib_wc_t *p_done_cl; + uint32_t id; + char *buff; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + + p_ca_obj->wr_send_size = sizeof(ib_send_wr_t) + \ + (sizeof(ib_local_ds_t) * p_ca_obj->ds_list_depth); + p_ca_obj->wr_recv_size = sizeof(ib_recv_wr_t) + \ + (sizeof(ib_local_ds_t) * p_ca_obj->ds_list_depth); + + p_ca_obj->p_send_wr = &send_wr; + p_ca_obj->p_recv_wr = &recv_wr; + + p_ca_obj->p_send_wr->ds_array = &send_ds; + p_ca_obj->p_recv_wr->ds_array = &recv_ds; + + // receive + for (i=0; i < p_ca_obj->num_wrs; i++) + { + ib_status = alts_rc_register_mem( p_ca_obj, i, 4096); + + if ( ib_status != IB_SUCCESS ) + { + while( i-- ) + alts_rc_deregister_mem(p_ca_obj, i); + + return ib_status; + } + else + { + p_ca_obj->mem_region[i].my_lid = p_ca_obj->dlid; + } + } + + // send + for (k=0; k < p_ca_obj->num_wrs; k++) + { + ib_status = + alts_rc_register_mem( p_ca_obj, k + p_ca_obj->num_wrs, 4096); + + if ( ib_status != IB_SUCCESS ) + { + while( k-- ) + alts_rc_deregister_mem(p_ca_obj, k + p_ca_obj->num_wrs); + + while( i-- ) + alts_rc_deregister_mem(p_ca_obj, i); + + return ib_status; + } + else + { + p_ca_obj->mem_region[k].my_lid = p_ca_obj->slid; + } + } + + p_ca_obj->cq_done = 0; + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("++++++ dlid(x%x) src_port(%d) ====\n", + p_ca_obj->dlid, p_ca_obj->src_port_num)); + + if(ib_status == IB_SUCCESS) + { + ib_status = ib_rearm_cq(p_ca_obj->h_cq, FALSE); + rc_multisend_post_recvs( p_ca_obj, 0, p_ca_obj->num_wrs ); + + if( p_ca_obj->num_cq > 1 ) + ib_status = ib_rearm_cq(p_ca_obj->h_cq_alt, FALSE); + else + ib_status = ib_rearm_cq(p_ca_obj->h_cq, FALSE); + rc_multisend_post_sends( p_ca_obj, p_ca_obj->num_wrs, p_ca_obj->num_wrs ); + } + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("sleeping for awhile ...\n")); + + cl_thread_suspend(3000); // 10 seconds + +//#if 0 + + if (!p_ca_obj->cq_done) + { + p_free_wclist = &free_wclist; + p_free_wclist->p_next = NULL; + p_done_cl = NULL; + j = 0; + + ib_status = ib_poll_cq(p_ca_obj->h_cq, &p_free_wclist, &p_done_cl); + + while(p_done_cl) + { + /* + * print output + */ + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("Got a completion:\n" + "\ttype....:%s\n" + "\twr_id...:%"PRIx64"\n" + "\tstatus..:%s\n", + ib_get_wc_type_str(p_done_cl->wc_type), + p_done_cl->wr_id, + ib_get_wc_status_str(p_done_cl->status))); + + if (p_done_cl->wc_type == IB_WC_RECV) + { + id = (uint32_t)p_done_cl->wr_id; + buff = (char *)p_ca_obj->mem_region[id].buffer; + if (qp_type == IB_QPT_UNRELIABLE_DGRM) + { + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("---MSG--->%s\n",&buff[40])); + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("RecvUD info:\n" + "\trecv_opt...:x%x\n" + "\timm_data...:x%x\n" + "\tremote_qp..:x%x\n" + "\tpkey_index.:%d\n" + "\tremote_lid.:x%x\n" + "\tremote_sl..:x%x\n" + "\tpath_bits..:x%x\n" + "\tsrc_lid....:x%x\n", + p_done_cl->recv.ud.recv_opt, + p_done_cl->recv.ud.immediate_data, + CL_NTOH32(p_done_cl->recv.ud.remote_qp), + p_done_cl->recv.ud.pkey_index, + CL_NTOH16(p_done_cl->recv.ud.remote_lid), + p_done_cl->recv.ud.remote_sl, + p_done_cl->recv.ud.path_bits, + CL_NTOH16(p_ca_obj->mem_region[id].my_lid))); + } + else + { + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("RecvRC info:\n" + "\trecv_opt...:x%x\n" + "\timm_data...:x%x\n", + p_done_cl->recv.conn.recv_opt, + p_done_cl->recv.ud.immediate_data )); + } + + } + + p_free_wclist = p_done_cl; + p_free_wclist->p_next = NULL; + p_done_cl = NULL; + j++; + p_done_cl = NULL; + ib_status = ib_poll_cq(p_ca_obj->h_cq, &p_free_wclist, &p_done_cl); + } + + ALTS_PRINT( ALTS_DBG_INFO, + ("Number of items polled from CQ is = %d\n", j) ); + + p_ca_obj->cq_done += i; + + ib_status = IB_SUCCESS; + } +//#endif + + while( i-- ) + alts_rc_deregister_mem(p_ca_obj, i); + + while( k-- ) + alts_rc_deregister_mem(p_ca_obj, k + p_ca_obj->num_wrs); + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + + + +// cm cbs +void +alts_cm_apr_cb( + IN ib_cm_apr_rec_t *p_cm_apr_rec ) +{ + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + UNUSED_PARAM( p_cm_apr_rec ); + + ALTS_EXIT( ALTS_DBG_VERBOSE); +} + +void +alts_cm_dreq_cb( + IN ib_cm_dreq_rec_t *p_cm_dreq_rec ) +{ + ib_api_status_t ib_status; + alts_cm_ca_obj_t *p_ca_obj; + ib_cm_drep_t drep; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + CL_ASSERT( p_cm_dreq_rec ); + + p_ca_obj = (alts_cm_ca_obj_t*)p_cm_dreq_rec->qp_context; + CL_ASSERT( p_ca_obj ); + + p_ca_obj->cm_cbs++; // count crows + + // send a drep + cl_memclr(&drep, sizeof(ib_cm_drep_t)); + + ib_status = ib_cm_drep(p_cm_dreq_rec->h_cm_dreq,&drep); + + ALTS_EXIT( ALTS_DBG_VERBOSE); +} + +void +alts_cm_rep_cb( + IN ib_cm_rep_rec_t *p_cm_rep_rec ) +{ + ib_api_status_t ib_status; + alts_cm_ca_obj_t *p_ca_obj; + ib_cm_rtu_t *p_cm_rtu; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + CL_ASSERT( p_cm_rep_rec ); + + if(( p_cm_rep_rec->qp_type == IB_QPT_RELIABLE_CONN ) || + ( p_cm_rep_rec->qp_type == IB_QPT_UNRELIABLE_CONN )) + { + p_ca_obj = (alts_cm_ca_obj_t*)p_cm_rep_rec->qp_context; + CL_ASSERT( p_ca_obj ); + + p_ca_obj->cm_cbs++; // count crows + + p_cm_rtu = &p_ca_obj->rtu_src; + + cl_memclr( p_cm_rtu, sizeof(ib_cm_rtu_t) ); + + p_cm_rtu->access_ctrl = IB_AC_LOCAL_WRITE; + + if( p_ca_obj->rdma_enabled == TRUE ) + { + p_cm_rtu->access_ctrl |= IB_AC_RDMA_READ + IB_AC_RDMA_WRITE; + } + + if( p_ca_obj->p_ca_attr->modify_wr_depth ) + { + p_cm_rtu->sq_depth = 16; + p_cm_rtu->rq_depth = 16; + } + p_cm_rtu->pfn_cm_apr_cb = alts_cm_apr_cb; + p_cm_rtu->pfn_cm_dreq_cb = alts_cm_dreq_cb; + + ib_status = ib_cm_rtu( p_cm_rep_rec->h_cm_rep, p_cm_rtu ); + + ALTS_PRINT( ALTS_DBG_VERBOSE, + ("ib_cm_rtu returned %s\n", ib_get_err_str( ib_status )) ); + } + else + if ( p_cm_rep_rec->qp_type == IB_QPT_UNRELIABLE_DGRM ) + { + ALTS_PRINT( ALTS_DBG_VERBOSE, + ("sidr rep in\n" + "\tstatus........:x%x\n" + "\tremote_qp.....:x%x\n" + "\tremote_qkey...:x%x\n", + p_cm_rep_rec->status, + p_cm_rep_rec->remote_qp, + p_cm_rep_rec->remote_qkey )); + + p_ca_obj = (alts_cm_ca_obj_t*)p_cm_rep_rec->sidr_context; + CL_ASSERT( p_ca_obj ); + + p_ca_obj->cm_cbs++; // count crows + } + else + { + // + return; + } + + + ALTS_EXIT( ALTS_DBG_VERBOSE); +} + + +void +alts_cm_rej_cb( + IN ib_cm_rej_rec_t *p_cm_rej_rec ) +{ + alts_cm_ca_obj_t *p_ca_obj; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + p_ca_obj = (alts_cm_ca_obj_t*)p_cm_rej_rec->qp_context; + + // only use context if qp was set up + if( p_ca_obj ) + { + p_ca_obj->cm_errs++; // count crows + } + + ALTS_EXIT( ALTS_DBG_VERBOSE); +} + +void +alts_cm_mra_cb( + IN ib_cm_mra_rec_t *p_cm_mra_rec ) +{ + alts_cm_ca_obj_t *p_ca_obj; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + p_ca_obj = (alts_cm_ca_obj_t*)p_cm_mra_rec->qp_context; + CL_ASSERT( p_ca_obj ); + + + ALTS_EXIT( ALTS_DBG_VERBOSE); +} + + +void +alts_cm_rtu_cb( + IN ib_cm_rtu_rec_t *p_cm_rtu_rec ) +{ + alts_cm_ca_obj_t *p_ca_obj; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + CL_ASSERT( p_cm_rtu_rec ); + + p_ca_obj = (alts_cm_ca_obj_t*)p_cm_rtu_rec->qp_context; + CL_ASSERT( p_ca_obj ); + + p_ca_obj->cm_cbs++; // count crows + + ALTS_EXIT( ALTS_DBG_VERBOSE); +} + +void +alts_cm_lap_cb( + IN ib_cm_lap_rec_t *p_cm_lap_rec ) +{ + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + UNUSED_PARAM( p_cm_lap_rec ); + + ALTS_EXIT( ALTS_DBG_VERBOSE); +} + +void +alts_cm_req_cb( + IN ib_cm_req_rec_t *p_cm_req_rec ) +{ + ib_api_status_t ib_status; + alts_cm_ca_obj_t *p_ca_obj; + ib_cm_rep_t *p_cm_rep; + ib_cm_mra_t cm_mra; + ib_cm_rej_t cm_rej; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + CL_ASSERT( p_cm_req_rec ); + + p_ca_obj = (alts_cm_ca_obj_t*)p_cm_req_rec->context; + + CL_ASSERT( p_ca_obj ); + + if ( p_cm_req_rec->qp_type == IB_QPT_RELIABLE_CONN ) + { + ALTS_PRINT( ALTS_DBG_VERBOSE, + ("rc connect request in\n")); + } + else + if ( p_cm_req_rec->qp_type == IB_QPT_UNRELIABLE_DGRM ) + { + ALTS_PRINT( ALTS_DBG_VERBOSE, + ("sidr connect request in\n")); + } + else + if ( p_cm_req_rec->qp_type == IB_QPT_UNRELIABLE_CONN ) + { + ALTS_PRINT( ALTS_DBG_VERBOSE, + ("unreliable connect request in\n")); + } + else + { + return; + } + + if( p_ca_obj->rej_test ) + { + ALTS_PRINT( ALTS_DBG_VERBOSE, + ("rejecting request\n")); + cl_memclr( &cm_rej, sizeof( ib_cm_rej_t ) ); + cm_rej.rej_status = IB_REJ_USER_DEFINED; + ib_cm_rej( p_cm_req_rec->h_cm_req, &cm_rej ); + return; + } + + /* initiate handoff process */ + if( p_ca_obj->handoff == TRUE ) + { + /* set it to false to stop all other transactions that happen + in the same cb */ + p_ca_obj->handoff = FALSE; + + ib_status = ib_cm_handoff( p_cm_req_rec->h_cm_req, + p_ca_obj->handoff_svc_id ); + if( ib_status != IB_SUCCESS ) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("handoff failed with %s!\n", ib_get_err_str(ib_status)) ); + } + else + { + ALTS_PRINT( ALTS_DBG_VERBOSE, + ("CM handoff successful\n") ); + } + return; + } + + + p_ca_obj->cm_cbs++; // count crows + + p_cm_rep = &p_ca_obj->rep_dest; + cl_memclr( p_cm_rep, sizeof(ib_cm_rep_t)); + + p_ca_obj->h_cm_req = p_cm_req_rec->h_cm_req; + p_cm_rep->qp_type = p_cm_req_rec->qp_type; + p_cm_rep->h_qp = p_ca_obj->h_qp[DEST_QP]; + + // class specific + if (( p_cm_req_rec->qp_type == IB_QPT_RELIABLE_CONN ) || + ( p_cm_req_rec->qp_type == IB_QPT_UNRELIABLE_CONN )) + { + // rc, uc & rd + p_cm_rep->access_ctrl = IB_AC_LOCAL_WRITE; // | IB_AC_RDMA_READ | IB_AC_RDMA_WRITE; + + /* Verify that the CA supports modify_wr_depth after QP creation. */ + if( p_ca_obj->p_ca_attr->modify_wr_depth ) + { + p_cm_rep->sq_depth = p_ca_obj->num_wrs; + p_cm_rep->rq_depth = p_ca_obj->num_wrs; + } + + p_cm_rep->init_depth = 1; + p_cm_rep->target_ack_delay = 10; + p_cm_rep->failover_accepted = IB_FAILOVER_ACCEPT_UNSUPPORTED; + p_cm_rep->flow_ctrl = TRUE; + p_cm_rep->rnr_nak_timeout = 7; + p_cm_rep->rnr_retry_cnt = 7; + p_cm_rep->pfn_cm_rej_cb = alts_cm_rej_cb; + p_cm_rep->pfn_cm_mra_cb = alts_cm_mra_cb; + p_cm_rep->pfn_cm_rtu_cb = alts_cm_rtu_cb; + p_cm_rep->pfn_cm_lap_cb = alts_cm_lap_cb; + p_cm_rep->pfn_cm_dreq_cb = alts_cm_dreq_cb; + + if( p_ca_obj->mra_test == TRUE ) + { + // send a MRA to test + cm_mra.mra_length = 0; + cm_mra.p_mra_pdata = NULL; + cm_mra.svc_timeout = 21; // equals 8.5 sec wait + packet lifetime + + ib_status = ib_cm_mra( p_cm_req_rec->h_cm_req, &cm_mra ); + ALTS_PRINT( ALTS_DBG_VERBOSE, + ("ib_cm_mra returned %s\n", ib_get_err_str( ib_status )) ); + } + else + { + ib_status = ib_cm_rep( p_cm_req_rec->h_cm_req, p_cm_rep ); + ALTS_PRINT( ALTS_DBG_VERBOSE, + ("ib_cm_rep returned %s\n", ib_get_err_str( ib_status )) ); + } + } + else + { + // ud + if( p_cm_req_rec->pkey != p_ca_obj->p_dest_port_attr->p_pkey_table[0]) + p_cm_rep->status = IB_SIDR_REJECT; + else + p_cm_rep->status = IB_SIDR_SUCCESS; + + ib_status = ib_cm_rep( p_cm_req_rec->h_cm_req, p_cm_rep ); + } + + ALTS_EXIT( ALTS_DBG_VERBOSE); +} + +ib_api_status_t +alts_cm_client_server( + alts_cm_ca_obj_t *p_ca_obj ) +{ + ib_api_status_t ib_status = IB_ERROR; + ib_cm_req_t *p_req_server, *p_req_client; + ib_path_rec_t *p_path_server, *p_path_client; + ib_cm_listen_t *p_listen; + cl_status_t cl_status; + cl_thread_t mra_thread; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + if( p_ca_obj->mra_test == TRUE ) + { + // create a thread to process MRA + cl_status = cl_event_init( &p_ca_obj->mra_event, TRUE ); + if( cl_status != CL_SUCCESS ) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("cl_event_init failed !\n") ); + return IB_ERROR; + } + cl_memclr( &mra_thread, sizeof(cl_thread_t) ); + cl_status = cl_thread_init( &mra_thread, __mra_thread, p_ca_obj, "cm_altsTH" ); + if( cl_status != CL_SUCCESS ) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("cl_thread_init failed !\n") ); + return IB_ERROR; + } + } + + // setup data pointers + p_req_server = &p_ca_obj->req_dest; + p_req_client = &p_ca_obj->req_src; + + p_path_server = &p_ca_obj->path_dest; + p_path_client = &p_ca_obj->path_src; + + p_listen = &p_ca_obj->listen; + + p_ca_obj->cm_cbs = 0; + + // setup server + p_req_server->h_qp = p_ca_obj->h_qp[DEST_QP]; + + cl_memclr( p_listen, sizeof(ib_cm_listen_t) ); + + p_listen->qp_type = p_ca_obj->test_type; + p_listen->svc_id = 1; + p_listen->ca_guid = p_ca_obj->p_ca_attr->ca_guid; + p_listen->port_guid = p_ca_obj->p_dest_port_attr->port_guid; + p_listen->lid = p_ca_obj->dlid; + p_listen->pkey = p_ca_obj->p_dest_port_attr->p_pkey_table[0]; + p_listen->pfn_cm_req_cb = alts_cm_req_cb; + + ib_status = ib_cm_listen(h_al, p_listen, p_ca_obj, &p_ca_obj->h_cm_listen ); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_cm_listen failed with status = %d\n", ib_status) ); + goto cm_end; + } + + // setup handoff server if requested + if( p_ca_obj->handoff == TRUE ) + { + p_listen->svc_id = 2; + p_ca_obj->handoff_svc_id = 2; + + ib_status = ib_cm_listen(h_al, p_listen, p_ca_obj, &p_ca_obj->h_cm_listen_handoff ); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_cm_listen failed for handoff with status = %d\n", + ib_status) ); + goto cm_end; + } + } + + // setup client + cl_memclr( p_path_client, sizeof(ib_path_rec_t) ); + p_path_client->sgid.unicast.interface_id = + p_ca_obj->p_src_port_attr->p_gid_table->unicast.interface_id; + p_path_client->sgid.unicast.prefix = + p_ca_obj->p_src_port_attr->p_gid_table->unicast.prefix; + + p_path_client->dgid.unicast.interface_id = + p_ca_obj->p_dest_port_attr->p_gid_table->unicast.interface_id; + p_path_client->dgid.unicast.prefix = + p_ca_obj->p_dest_port_attr->p_gid_table->unicast.prefix; + + p_path_client->slid = p_ca_obj->slid; + p_path_client->dlid = p_ca_obj->dlid; + p_path_client->num_path = 1; + p_path_client->pkey = p_ca_obj->p_src_port_attr->p_pkey_table[0]; + p_path_client->mtu = IB_MTU_LEN_256; + p_path_client->pkt_life = 10; + + cl_memclr( p_req_client, sizeof(ib_cm_req_t) ); + + p_req_client->qp_type = p_ca_obj->test_type; + p_req_client->svc_id = 1; + + p_req_client->max_cm_retries = 3; + p_req_client->p_primary_path = p_path_client; + p_req_client->pfn_cm_rep_cb = alts_cm_rep_cb; + + if( p_req_client->qp_type == IB_QPT_UNRELIABLE_DGRM ) + { + p_req_client->h_al = h_al; + p_req_client->sidr_context = p_ca_obj; + p_req_client->timeout_ms = 1000; /* 1 sec */ + p_req_client->pkey = p_ca_obj->p_dest_port_attr->p_pkey_table[0]; + } + else + { + p_req_client->resp_res = 3; + p_req_client->init_depth = 1; + p_req_client->remote_resp_timeout = 11; + p_req_client->retry_cnt = 3; + p_req_client->rnr_nak_timeout = 7; + p_req_client->rnr_retry_cnt = 7; + p_req_client->pfn_cm_rej_cb = alts_cm_rej_cb; + p_req_client->pfn_cm_mra_cb = alts_cm_mra_cb; + p_req_client->h_qp = p_ca_obj->h_qp[SRC_QP]; + p_req_client->local_resp_timeout = 12; + } + + ib_status = ib_cm_req(p_req_client); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_cm_req failed with status = %d\n", ib_status) ); + goto cm_end; + } + + if( p_ca_obj->mra_test == TRUE ) + cl_thread_suspend( 10000 ); + else + cl_thread_suspend( 3000 ); + + + switch( p_req_client->qp_type ) + { + case IB_QPT_RELIABLE_CONN: + case IB_QPT_UNRELIABLE_CONN: + if( p_ca_obj->rej_test == TRUE ) + { + if (!p_ca_obj->cm_errs) + ib_status = IB_ERROR; + } + else if( p_ca_obj->cm_cbs != 3 ) + ib_status = IB_ERROR; + break; + + case IB_QPT_UNRELIABLE_DGRM: + if( p_ca_obj->cm_cbs != 2 ) + ib_status = IB_ERROR; + break; + + default: + ib_status = IB_ERROR; + break; + } + + if( ib_status == IB_SUCCESS ) + { + // query QPs + ib_status = ib_query_qp(p_ca_obj->h_qp[SRC_QP], + &p_ca_obj->qp_attr[SRC_QP]); + ib_status = ib_query_qp(p_ca_obj->h_qp[DEST_QP], + &p_ca_obj->qp_attr[DEST_QP]); + ALTS_PRINT( ALTS_DBG_VERBOSE, + ("Src qp_state(%d) dest_qp(x%x) dlid(x%x)\n", + p_ca_obj->qp_attr[SRC_QP].state, + p_ca_obj->qp_attr[SRC_QP].dest_num, + p_ca_obj->qp_attr[SRC_QP].primary_av.dlid ) ); + ALTS_PRINT( ALTS_DBG_VERBOSE, + ("Dest qp_state(%d) dest_qp(%x) dlid(x%x)\n", + p_ca_obj->qp_attr[DEST_QP].state, + p_ca_obj->qp_attr[DEST_QP].dest_num, + p_ca_obj->qp_attr[DEST_QP].primary_av.dlid ) ); + + ALTS_PRINT( ALTS_DBG_VERBOSE, + ("Src sq_psn(x%x) rq_psn(x%x)\n" + "Dest sq_psn(x%x) rq_psn(x%x)\n", + p_ca_obj->qp_attr[SRC_QP].sq_psn, p_ca_obj->qp_attr[SRC_QP].rq_psn, + p_ca_obj->qp_attr[DEST_QP].sq_psn, + p_ca_obj->qp_attr[DEST_QP].rq_psn ) ); + + // return status + ib_status = IB_SUCCESS; + } + + +cm_end: + if( p_ca_obj->mra_test == TRUE ) + { + cl_thread_destroy( &mra_thread ); + cl_event_destroy( &p_ca_obj->mra_event ); + } + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + +void +alts_cm_drep_cb( + IN ib_cm_drep_rec_t *p_cm_drep_rec ) +{ + alts_cm_ca_obj_t *p_ca_obj; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + CL_ASSERT( p_cm_drep_rec ); + + p_ca_obj = (alts_cm_ca_obj_t*)p_cm_drep_rec->qp_context; + CL_ASSERT( p_ca_obj ); + + p_ca_obj->cm_cbs++; // count crows + + ALTS_EXIT( ALTS_DBG_VERBOSE); +} + +void +alts_listen_destroy_cb( + IN void *context ) +{ + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + CL_ASSERT( context ); + UNUSED_PARAM( context ); + + ALTS_EXIT( ALTS_DBG_VERBOSE); +} + +ib_api_status_t +alts_cm_destroy( + alts_cm_ca_obj_t *p_ca_obj ) +{ + ib_api_status_t ib_status = IB_ERROR; + ib_cm_dreq_t *p_dreq_client; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + p_ca_obj->cm_cbs = 0; + + // only dreq for connected types + if( p_ca_obj->test_type != IB_QPT_UNRELIABLE_DGRM ) + { + // setup data pointers + p_dreq_client = &p_ca_obj->dreq_src; + + cl_memclr(p_dreq_client, sizeof(ib_cm_dreq_t)); + p_dreq_client->h_qp = p_ca_obj->h_qp[SRC_QP]; + p_dreq_client->pfn_cm_drep_cb = alts_cm_drep_cb; + + ib_status = ib_cm_dreq(p_dreq_client); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_cm_dreq failed with status = %d\n", ib_status) ); + goto cm_destroy_end; + } + + cl_thread_suspend( 1000 ); + + if (p_ca_obj->cm_cbs) + { + ALTS_PRINT( ALTS_DBG_VERBOSE, + ("ib_cm_dreq successful\n") ); + } + + p_ca_obj->cm_cbs = 0; + } + + ib_status = ib_cm_cancel(p_ca_obj->h_cm_listen, alts_listen_destroy_cb); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_cm_cancel failed with status = %d\n", ib_status) ); + } + +cm_destroy_end: + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + +ib_api_status_t +alts_cm_rc_tests ( + ib_ca_handle_t h_ca, + uint32_t ca_attr_size ) +{ + ib_api_status_t ib_status = IB_ERROR, ib_status2; + uint32_t bsize; + alts_cm_ca_obj_t *p_ca_obj = NULL; + ib_ca_attr_t *p_ca_attr = NULL; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + CL_ASSERT (h_ca); + CL_ASSERT (ca_attr_size); + + do + { + p_ca_obj = (alts_cm_ca_obj_t*)cl_zalloc(sizeof(alts_cm_ca_obj_t)); + if (!p_ca_obj) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("zalloc() failed for alts_cm_ca_obj_t!\n") ); + break; + } + + /* Allocate the memory needed for query_ca */ + bsize = ca_attr_size; + p_ca_attr = (ib_ca_attr_t *)cl_zalloc(bsize); + if (!p_ca_attr) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("zalloc() failed for p_ca_attr!\n") ); + break; + } + + ib_status = ib_query_ca(h_ca, p_ca_attr, &bsize); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_query_ca failed with status = %d\n", ib_status) ); + break; + } + + /* + * Initialize the CA Object + */ + p_ca_obj->h_ca = h_ca; + p_ca_obj->p_ca_attr = p_ca_attr; + p_ca_obj->status = IB_SUCCESS; + p_ca_obj->cq_size = 255*2; + p_ca_obj->qkey = 0; + p_ca_obj->ds_list_depth = 1; + p_ca_obj->num_wrs = 1; + p_ca_obj->msg_size = 256; + + p_ca_obj->src_qp_num = IB_QP1; + p_ca_obj->is_loopback = FALSE; + + p_ca_obj->test_type = IB_QPT_RELIABLE_CONN; + p_ca_obj->pfn_comp_cb = cm_rc_cq_comp_cb; // set your cq handler + + p_ca_obj->reply_requested = TRUE; + + /* + * get an active port + */ + ib_status = alts_cm_check_active_ports(p_ca_obj); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("This test routing atleast 1 active port on the 1st hca\n")); + break; + } + + + /* + * Create the necessary resource PD/QP/QP + */ + p_ca_obj->num_cq = 2; + + ib_status = alts_create_test_resources( p_ca_obj ); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_create_test_resources() failed with status %d\n", ib_status)); + break; + } + + /* + * Start Message passing activity + */ + ib_status = alts_cm_client_server(p_ca_obj); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_cm_client_server failed with status %d\n", ib_status)); + break; + } + + // run the test + ib_status = alts_rc_message_passing(p_ca_obj, IB_QPT_RELIABLE_CONN); + + cl_thread_suspend(1000); /* 1 sec */ + + // destroy connection + ib_status = alts_cm_destroy(p_ca_obj); + + if (p_ca_obj->cq_done == 2) + ib_status = IB_SUCCESS; + else + ib_status = IB_ERROR; + + + } while (0); + + /* + * Destroy the resources + */ + ib_status2 = alts_cm_destroy_resources(p_ca_obj); + if (ib_status == IB_SUCCESS) + ib_status = ib_status2; + + if (p_ca_attr) + cl_free(p_ca_attr); + + if (p_ca_obj) + cl_free(p_ca_obj); + + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + + + +ib_api_status_t +alts_cm_rc_rej_test ( + ib_ca_handle_t h_ca, + uint32_t ca_attr_size ) +{ + ib_api_status_t ib_status = IB_ERROR, ib_status2; + uint32_t bsize; + alts_cm_ca_obj_t *p_ca_obj = NULL; + ib_ca_attr_t *p_ca_attr = NULL; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + CL_ASSERT (h_ca); + CL_ASSERT (ca_attr_size); + + do + { + p_ca_obj = (alts_cm_ca_obj_t*)cl_zalloc(sizeof(alts_cm_ca_obj_t)); + if (!p_ca_obj) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("zalloc() failed for alts_cm_ca_obj_t!\n") ); + break; + } + + /* Allocate the memory needed for query_ca */ + bsize = ca_attr_size; + p_ca_attr = (ib_ca_attr_t *)cl_zalloc(bsize); + if (!p_ca_attr) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("zalloc() failed for p_ca_attr!\n") ); + break; + } + + ib_status = ib_query_ca(h_ca, p_ca_attr, &bsize); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_query_ca failed with status = %d\n", ib_status) ); + break; + } + + /* + * Initialize the CA Object + */ + p_ca_obj->h_ca = h_ca; + p_ca_obj->p_ca_attr = p_ca_attr; + p_ca_obj->status = IB_SUCCESS; + p_ca_obj->cq_size = 255*2; + p_ca_obj->qkey = 0; + p_ca_obj->ds_list_depth = 1; + p_ca_obj->num_wrs = 1; + p_ca_obj->msg_size = 256; + + p_ca_obj->src_qp_num = IB_QP1; + p_ca_obj->is_loopback = FALSE; + + p_ca_obj->test_type = IB_QPT_RELIABLE_CONN; + p_ca_obj->pfn_comp_cb = cm_rc_cq_comp_cb; // set your cq handler + + p_ca_obj->reply_requested = TRUE; + + p_ca_obj->rej_test = TRUE; + + /* + * get an active port + */ + ib_status = alts_cm_check_active_ports(p_ca_obj); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("This test routing atleast 1 active port on the 1st hca\n")); + break; + } + + /* + * Create the necessary resource PD/QP/QP + */ + ib_status = alts_create_test_resources( p_ca_obj ); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_create_test_resources() failed with status %d\n", ib_status)); + break; + } + + /* + * Start Message passing activity + */ + ib_status = alts_cm_client_server(p_ca_obj); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_cm_client_server failed with status %d\n", ib_status)); + break; + } + + // destroy connection + //ib_status = alts_cm_destroy(p_ca_obj); + ib_status = ib_cm_cancel(p_ca_obj->h_cm_listen, alts_listen_destroy_cb); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_cm_cancel failed with status = %d\n", ib_status) ); + } + + } while (0); + + /* + * Destroy the resources + */ + ib_status2 = alts_cm_destroy_resources(p_ca_obj); + if (ib_status == IB_SUCCESS) + ib_status = ib_status2; + + if (p_ca_attr) + cl_free(p_ca_attr); + + if (p_ca_obj) + cl_free(p_ca_obj); + + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + + + +ib_api_status_t +alts_cm_handoff_test ( + ib_ca_handle_t h_ca, + uint32_t ca_attr_size ) +{ + ib_api_status_t ib_status = IB_ERROR, ib_status2; + uint32_t bsize; + alts_cm_ca_obj_t *p_ca_obj = NULL; + ib_ca_attr_t *p_ca_attr = NULL; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + CL_ASSERT (h_ca); + CL_ASSERT (ca_attr_size); + + do + { + p_ca_obj = (alts_cm_ca_obj_t*)cl_zalloc(sizeof(alts_cm_ca_obj_t)); + if (!p_ca_obj) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("zalloc() failed for alts_cm_ca_obj_t!\n") ); + break; + } + + /* Allocate the memory needed for query_ca */ + bsize = ca_attr_size; + p_ca_attr = (ib_ca_attr_t *)cl_zalloc(bsize); + if (!p_ca_attr) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("zalloc() failed for p_ca_attr!\n") ); + break; + } + + ib_status = ib_query_ca(h_ca, p_ca_attr, &bsize); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_query_ca failed with status = %d\n", ib_status) ); + break; + } + + /* + * Initialize the CA Object + */ + p_ca_obj->h_ca = h_ca; + p_ca_obj->p_ca_attr = p_ca_attr; + p_ca_obj->status = IB_SUCCESS; + p_ca_obj->cq_size = 255*2; + p_ca_obj->qkey = 0; + p_ca_obj->ds_list_depth = 1; + p_ca_obj->num_wrs = 1; + p_ca_obj->msg_size = 256; + + p_ca_obj->src_qp_num = IB_QP1; + p_ca_obj->is_loopback = FALSE; + + p_ca_obj->test_type = IB_QPT_RELIABLE_CONN; + p_ca_obj->pfn_comp_cb = cm_rc_cq_comp_cb; // set your cq handler + + p_ca_obj->reply_requested = TRUE; + + p_ca_obj->rej_test = FALSE; + + /* + * get an active port + */ + ib_status = alts_cm_check_active_ports(p_ca_obj); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("This test routing atleast 1 active port on the 1st hca\n")); + break; + } + + /* + * Create the necessary resource PD/QP/QP + */ + ib_status = alts_create_test_resources( p_ca_obj ); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_create_test_resources() failed with status %d\n", ib_status)); + break; + } + + /* + * Create handoff service + */ + p_ca_obj->handoff = TRUE; + + + /* + * Start Message passing activity + */ + ib_status = alts_cm_client_server(p_ca_obj); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_cm_client_server failed with status %d\n", ib_status)); + break; + } + + // destroy connection + ib_status = alts_cm_destroy(p_ca_obj); + + // destroy handoff listen + if( p_ca_obj->h_cm_listen_handoff ) + { + ib_status = ib_cm_cancel(p_ca_obj->h_cm_listen_handoff, + alts_listen_destroy_cb); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_cm_cancel failed with status = %d\n", ib_status) ); + } + } + + } while (0); + + /* + * Destroy the resources + */ + ib_status2 = alts_cm_destroy_resources(p_ca_obj); + if (ib_status == IB_SUCCESS) + ib_status = ib_status2; + + if (p_ca_attr) + cl_free(p_ca_attr); + + if (p_ca_obj) + cl_free(p_ca_obj); + + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + +ib_api_status_t +alts_cm_rc_flush_test ( + ib_ca_handle_t h_ca, + uint32_t ca_attr_size ) +{ + ib_api_status_t ib_status = IB_ERROR, ib_status2; + uint32_t bsize; + alts_cm_ca_obj_t *p_ca_obj = NULL; + ib_ca_attr_t *p_ca_attr = NULL; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + CL_ASSERT (h_ca); + CL_ASSERT (ca_attr_size); + + do + { + p_ca_obj = (alts_cm_ca_obj_t*)cl_zalloc(sizeof(alts_cm_ca_obj_t)); + if (!p_ca_obj) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("zalloc() failed for alts_cm_ca_obj_t!\n") ); + break; + } + + /* Allocate the memory needed for query_ca */ + bsize = ca_attr_size; + p_ca_attr = (ib_ca_attr_t *)cl_zalloc(bsize); + if (!p_ca_attr) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("zalloc() failed for p_ca_attr!\n") ); + break; + } + + ib_status = ib_query_ca(h_ca, p_ca_attr, &bsize); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_query_ca failed with status = %d\n", ib_status) ); + break; + } + + /* + * Initialize the CA Object + */ + p_ca_obj->h_ca = h_ca; + p_ca_obj->p_ca_attr = p_ca_attr; + p_ca_obj->status = IB_SUCCESS; + p_ca_obj->cq_size = 255*2; + p_ca_obj->qkey = 0; + p_ca_obj->ds_list_depth = 1; + p_ca_obj->num_wrs = 4; + p_ca_obj->msg_size = 256; + + p_ca_obj->src_qp_num = IB_QP1; + p_ca_obj->is_loopback = FALSE; + + p_ca_obj->test_type = IB_QPT_RELIABLE_CONN; + p_ca_obj->pfn_comp_cb = cm_rc_cq_comp_cb; // set your cq handler + + p_ca_obj->reply_requested = TRUE; + + /* + * get an active port + */ + ib_status = alts_cm_check_active_ports(p_ca_obj); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("This test routing atleast 1 active port on the 1st hca\n")); + break; + } + + /* + * Create the necessary resource PD/QP/QP + */ + p_ca_obj->num_cq = 2; + + ib_status = alts_create_test_resources( p_ca_obj ); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_create_test_resources() failed with status %d\n", ib_status)); + break; + } + + /* + * Start Message passing activity + */ + ib_status = alts_cm_client_server(p_ca_obj); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_cm_client_server failed with status %d\n", ib_status)); + break; + } + + // run the test + ib_status = alts_rc_message_passing(p_ca_obj, IB_QPT_RELIABLE_CONN); + + cl_thread_suspend(3000); /* 1 sec */ + + ib_status = ib_rearm_cq(p_ca_obj->h_cq, FALSE); + if (p_ca_obj->cq_done == 8) + rc_multisend_post_recvs( p_ca_obj, 0, p_ca_obj->num_wrs ); + + // destroy connection + ib_status = alts_cm_destroy(p_ca_obj); + + cl_thread_suspend(4000); /* 1 sec */ + + /* force a cq completion callback to overcome interrupt issue */ + /* Intel Gen1 hardware does not generate an interrupt cb for a + qp set to error state */ + /* + if(p_ca_obj->cq_done == 8) + rc_cm_cq_comp_cb(p_ca_obj); + */ + + if (p_ca_obj->cq_done == 12) + ib_status = IB_SUCCESS; + else + ib_status = IB_ERROR; + + } while (0); + + /* + * Destroy the resources + */ + ib_status2 = alts_cm_destroy_resources(p_ca_obj); + if (ib_status == IB_SUCCESS) + ib_status = ib_status2; + + if (p_ca_attr) + cl_free(p_ca_attr); + + if (p_ca_obj) + cl_free(p_ca_obj); + + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + +ib_api_status_t +alts_cm_activate_qp( + alts_cm_ca_obj_t *p_ca_obj, + ib_qp_handle_t h_qp + ) +{ + + ib_qp_mod_t qp_mod_attr = {0}; + ib_api_status_t ib_status; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + if(p_ca_obj->is_src == 1) + qp_mod_attr.state.init.primary_port = p_ca_obj->src_port_num; + else + qp_mod_attr.state.init.primary_port = p_ca_obj->dest_port_num; + + qp_mod_attr.state.init.qkey = p_ca_obj->qkey; + qp_mod_attr.state.init.pkey_index = 0x0; + qp_mod_attr.state.init.access_ctrl = IB_AC_LOCAL_WRITE | IB_AC_MW_BIND; + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("******** port num = %d ***************\n", + qp_mod_attr.state.init.primary_port)); + + qp_mod_attr.req_state = IB_QPS_INIT; + ib_status = ib_modify_qp(h_qp, &qp_mod_attr); + + CL_ASSERT(ib_status == IB_SUCCESS); + + // Time to query the QP + if(p_ca_obj->is_src == 1) + { + ib_status = ib_query_qp(h_qp, + &p_ca_obj->qp_attr[SRC_QP]); + CL_ASSERT(ib_status == IB_SUCCESS); + } + else + { + ib_status = ib_query_qp(h_qp, + &p_ca_obj->qp_attr[DEST_QP]); + CL_ASSERT(ib_status == IB_SUCCESS); + } + + + // transition to RTR + cl_memclr(&qp_mod_attr, sizeof(ib_qp_mod_t)); + + qp_mod_attr.state.rtr.opts = 0; + qp_mod_attr.state.rtr.rq_psn = CL_NTOH32(0x00000001); + + switch ( p_ca_obj->test_type ) + { + case IB_QPT_RELIABLE_CONN: + case IB_QPT_UNRELIABLE_CONN: + qp_mod_attr.state.rtr.opts = IB_MOD_QP_PRIMARY_AV; + break; + default: + break; + } + + if (p_ca_obj->is_src == 1) + { + if (p_ca_obj->is_loopback == TRUE) + { + qp_mod_attr.state.rtr.dest_qp = p_ca_obj->qp_attr[SRC_QP].num; + qp_mod_attr.state.rtr.primary_av.port_num = p_ca_obj->src_port_num; + qp_mod_attr.state.rtr.primary_av.dlid = p_ca_obj->slid; + } + else + { + qp_mod_attr.state.rtr.dest_qp = p_ca_obj->qp_attr[DEST_QP].num; + qp_mod_attr.state.rtr.primary_av.port_num = p_ca_obj->src_port_num; + qp_mod_attr.state.rtr.primary_av.dlid = p_ca_obj->dlid; + } + } + else + { + qp_mod_attr.state.rtr.dest_qp = p_ca_obj->qp_attr[SRC_QP].num; + qp_mod_attr.state.rtr.primary_av.port_num = p_ca_obj->dest_port_num; + qp_mod_attr.state.rtr.primary_av.dlid = p_ca_obj->slid; + } + + qp_mod_attr.state.rtr.primary_av.sl = 0; + qp_mod_attr.state.rtr.primary_av.grh_valid = 0; //Set to false + + qp_mod_attr.state.rtr.primary_av.static_rate = IB_PATH_RECORD_RATE_10_GBS; + qp_mod_attr.state.rtr.primary_av.path_bits = 0; + + qp_mod_attr.state.rtr.primary_av.conn.path_mtu = 1; + qp_mod_attr.state.rtr.primary_av.conn.local_ack_timeout = 7; + qp_mod_attr.state.rtr.primary_av.conn.seq_err_retry_cnt = 7; + qp_mod_attr.state.rtr.primary_av.conn.rnr_retry_cnt = 7; + qp_mod_attr.state.rtr.rq_psn = CL_NTOH32(0x00000001); + qp_mod_attr.state.rtr.resp_res = 7; //32; + qp_mod_attr.state.rtr.rnr_nak_timeout = 7; + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("****RTR***** dlid = x%x (x%x) *port_num = %d *dest_qp = %d ***\n", + qp_mod_attr.state.rtr.primary_av.dlid, + CL_NTOH16(qp_mod_attr.state.rtr.primary_av.dlid), + qp_mod_attr.state.rtr.primary_av.port_num, + CL_NTOH32(qp_mod_attr.state.rtr.dest_qp) )); + + qp_mod_attr.req_state = IB_QPS_RTR; + ib_status = ib_modify_qp(h_qp, &qp_mod_attr); + + CL_ASSERT(ib_status == IB_SUCCESS); + + if(p_ca_obj->is_src == 1) + { + ib_status = ib_query_qp(h_qp, + &p_ca_obj->qp_attr[SRC_QP]); + } + else + { + ib_status = ib_query_qp(h_qp, + &p_ca_obj->qp_attr[DEST_QP]); + } + + cl_memclr(&qp_mod_attr, sizeof(ib_qp_mod_t)); + + qp_mod_attr.state.rts.sq_psn = CL_NTOH32(0x00000001); + + // NOTENOTE: Confirm the below time out settings + qp_mod_attr.state.rts.retry_cnt = 7; + qp_mod_attr.state.rts.rnr_retry_cnt = 7; + qp_mod_attr.state.rts.rnr_nak_timeout = 7; + qp_mod_attr.state.rts.local_ack_timeout = 7; + qp_mod_attr.state.rts.init_depth = 3; //3; + + qp_mod_attr.req_state = IB_QPS_RTS; + ib_status = ib_modify_qp(h_qp, &qp_mod_attr); + + CL_ASSERT(ib_status == IB_SUCCESS); + + if(p_ca_obj->is_src == 1) + { + ib_status = ib_query_qp(h_qp, + &p_ca_obj->qp_attr[SRC_QP]); + CL_ASSERT(ib_status == IB_SUCCESS); + } + else + { + ib_status = ib_query_qp(h_qp, + &p_ca_obj->qp_attr[DEST_QP]); + CL_ASSERT(ib_status == IB_SUCCESS); + } + + if (p_ca_obj->is_loopback == TRUE) + { + ib_status = ib_query_qp(h_qp, + &p_ca_obj->qp_attr[DEST_QP]); + } + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return IB_SUCCESS; +} + + +ib_api_status_t +alts_rc_no_cm_test ( + ib_ca_handle_t h_ca, + uint32_t ca_attr_size ) +{ + ib_api_status_t ib_status = IB_ERROR, ib_status2; + uint32_t bsize; + alts_cm_ca_obj_t *p_ca_obj = NULL; + ib_ca_attr_t *p_ca_attr = NULL; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + CL_ASSERT (h_ca); + CL_ASSERT (ca_attr_size); + + do + { + p_ca_obj = (alts_cm_ca_obj_t*)cl_zalloc(sizeof(alts_cm_ca_obj_t)); + if (!p_ca_obj) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("zalloc() failed for alts_cm_ca_obj_t!\n") ); + break; + } + + /* Allocate the memory needed for query_ca */ + bsize = ca_attr_size; + p_ca_attr = (ib_ca_attr_t *)cl_zalloc(bsize); + if (!p_ca_attr) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("zalloc() failed for p_ca_attr!\n") ); + break; + } + + ib_status = ib_query_ca(h_ca, p_ca_attr, &bsize); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_query_ca failed with status = %d\n", ib_status) ); + break; + } + + /* + * Initialize the CA Object + */ + p_ca_obj->h_ca = h_ca; + p_ca_obj->p_ca_attr = p_ca_attr; + p_ca_obj->status = IB_SUCCESS; + p_ca_obj->cq_size = 255*2; + p_ca_obj->qkey = 0; + p_ca_obj->ds_list_depth = 1; + p_ca_obj->num_wrs = 1; + p_ca_obj->msg_size = 256; + + p_ca_obj->src_qp_num = IB_QP1; + p_ca_obj->is_loopback = FALSE; + + p_ca_obj->test_type = IB_QPT_RELIABLE_CONN; + p_ca_obj->pfn_comp_cb = cm_rc_cq_comp_cb; // set your cq handler + + p_ca_obj->reply_requested = TRUE; + + /* + * get an active port + */ + ib_status = alts_cm_check_active_ports(p_ca_obj); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("This test routing atleast 1 active port on the 1st hca\n")); + break; + } + + + /* + * Create the necessary resource PD/QP/QP + */ + p_ca_obj->num_cq = 2; + + ib_status = alts_create_test_resources( p_ca_obj ); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_create_test_resources() failed with status %d\n", ib_status)); + break; + } + + /* + * Time to Activate the QP + */ + p_ca_obj->is_src = 1; + ib_status = alts_cm_activate_qp(p_ca_obj, p_ca_obj->h_qp[SRC_QP]); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_activate_qp failed with status %d\n", ib_status)); + break; + } + + p_ca_obj->is_src = 0; + ib_status = alts_cm_activate_qp(p_ca_obj, p_ca_obj->h_qp[DEST_QP]); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_activate_qp failed with status %d\n", ib_status)); + break; + } + + /* + * Start Message passing activity + */ + + // run the test + ib_status = alts_rc_message_passing(p_ca_obj, IB_QPT_RELIABLE_CONN); + + cl_thread_suspend(3000); /* 1 sec */ + + // destroy connection + ib_status = alts_cm_destroy(p_ca_obj); + + if (p_ca_obj->cq_done == 2) + ib_status = IB_SUCCESS; + else + ib_status = IB_ERROR; + + + } while (0); + + /* + * Destroy the resources + */ + ib_status2 = alts_cm_destroy_resources(p_ca_obj); + if (ib_status == IB_SUCCESS) + ib_status = ib_status2; + + if (p_ca_attr) + cl_free(p_ca_attr); + + if (p_ca_obj) + cl_free(p_ca_obj); + + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + + + + +ib_api_status_t +rc_rdma_post_recvs( + alts_cm_ca_obj_t *p_ca_obj, + uint32_t reg_index, + uint32_t num_posts ) +{ + ib_recv_wr_t *p_r_wr, *p_failure_wr; + uint32_t msg_size, i; + ib_api_status_t ib_status = IB_SUCCESS; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + + msg_size = 64; + //msg_size = p_ca_obj->msg_size; + + p_r_wr = p_ca_obj->p_recv_wr; + + p_r_wr->p_next = NULL; + p_r_wr->ds_array[0].length = msg_size; + p_r_wr->num_ds = 1; + + // post on recv and send side + for (i = 0; i < num_posts; i++) + { + p_r_wr->ds_array[0].vaddr = + (uintn_t)p_ca_obj->mem_region[i+reg_index].buffer; + p_r_wr->ds_array[0].lkey = p_ca_obj->mem_region[i+reg_index].lkey; + + p_r_wr->wr_id = i+reg_index; + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("******vaddr(x%"PRIx64") lkey(x%x) len(%d)*****\n", + (void*)(uintn_t)p_r_wr->ds_array[0].vaddr, + p_r_wr->ds_array[0].lkey, + p_r_wr->ds_array[0].length)); + + ib_status = ib_post_recv( + p_ca_obj->h_qp[DEST_QP], + p_r_wr, + &p_failure_wr); + + + p_r_wr->ds_array[0].vaddr = (uintn_t) + p_ca_obj->mem_region[i+reg_index+num_posts].buffer; + p_r_wr->ds_array[0].lkey = + p_ca_obj->mem_region[i+reg_index+num_posts].lkey; + + p_r_wr->wr_id = i+reg_index+num_posts; + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("******vaddr(x%"PRIx64") lkey(x%x) len(%d)*****\n", + (void*)(uintn_t)p_r_wr->ds_array[0].vaddr, + p_r_wr->ds_array[0].lkey, + p_r_wr->ds_array[0].length)); + + ib_status = ib_post_recv( + p_ca_obj->h_qp[SRC_QP], + p_r_wr, + &p_failure_wr); + + } + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + +ib_api_status_t +rc_rdma_post_sends( + alts_cm_ca_obj_t *p_ca_obj, + uint32_t reg_index, + uint32_t num_posts, + uint32_t rdma_index, + char rdma_type ) +{ + ib_send_wr_t *p_s_wr, *p_send_failure_wr; + uint32_t msg_size, i; + ib_api_status_t ib_status = IB_SUCCESS; + alts_rdma_t *p_rdma_req; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + msg_size = 64; + //msg_size = p_ca_obj->msg_size; + + p_s_wr = p_ca_obj->p_send_wr; + + p_s_wr->p_next = NULL; + p_s_wr->ds_array[0].length = msg_size; + p_s_wr->num_ds = 1; + + p_s_wr->wr_type = WR_SEND; + + p_s_wr->send_opt = IB_SEND_OPT_IMMEDIATE | \ + IB_SEND_OPT_SOLICITED ; + + p_s_wr->send_opt = IB_SEND_OPT_SIGNALED | + IB_SEND_OPT_SOLICITED ; + + + for (i = 0; i < num_posts; i++) + { + p_rdma_req = (alts_rdma_t*)p_ca_obj->mem_region[i+reg_index].buffer; + p_rdma_req->msg_type = rdma_type; // write or read + + p_rdma_req->vaddr = (uintn_t)(p_ca_obj->mem_region[i+rdma_index].buffer); + p_rdma_req->rkey = p_ca_obj->mem_region[i+rdma_index].rkey; + sprintf((char *)p_rdma_req->msg,"hello %d", i); + + p_s_wr->ds_array[0].vaddr = + (uintn_t)p_ca_obj->mem_region[i+reg_index].buffer; + p_s_wr->ds_array[0].lkey = p_ca_obj->mem_region[i+reg_index].lkey; + + p_s_wr->wr_id = i+reg_index; + p_s_wr->immediate_data = 0xfeedde00 + i; + + p_s_wr->remote_ops.vaddr = 0; + p_s_wr->remote_ops.rkey = 0; + + //p_s_wr->dgrm.ud.h_av + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("******vaddr(x%"PRIx64") lkey(x%x) len(%d)*****\n", + (void*)(uintn_t)p_s_wr->ds_array[0].vaddr, + p_s_wr->ds_array[0].lkey, + p_s_wr->ds_array[0].length)); + + ib_status = ib_post_send( + p_ca_obj->h_qp[SRC_QP], + p_s_wr, + &p_send_failure_wr); + + } + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + +ib_api_status_t +alts_rc_rdma_message_passing( + alts_cm_ca_obj_t *p_ca_obj, + ib_qp_type_t qp_type) +{ + uint32_t i, j, k; + ib_api_status_t ib_status = IB_SUCCESS; + ib_wc_t *p_free_wclist; + ib_wc_t *p_done_cl; + uint32_t id; + char *buff; + alts_rdma_t *p_rdma_req; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + + p_ca_obj->wr_send_size = sizeof(ib_send_wr_t) + \ + (sizeof(ib_local_ds_t) * p_ca_obj->ds_list_depth); + p_ca_obj->wr_recv_size = sizeof(ib_recv_wr_t) + \ + (sizeof(ib_local_ds_t) * p_ca_obj->ds_list_depth); + + p_ca_obj->p_send_wr = &send_wr; + p_ca_obj->p_recv_wr = &recv_wr; + + p_ca_obj->p_send_wr->ds_array = &send_ds; + p_ca_obj->p_recv_wr->ds_array = &recv_ds; + + // receive + for (i=0; i < p_ca_obj->num_wrs * 2; i++) + { + ib_status = alts_rc_register_mem( p_ca_obj, i, 4096); + + if ( ib_status != IB_SUCCESS ) + { + while( i-- ) + alts_rc_deregister_mem(p_ca_obj, i); + + return ib_status; + } + else + { + p_ca_obj->mem_region[i].my_lid = p_ca_obj->dlid; + } + } + + // send + for (k=0; k < p_ca_obj->num_wrs * 2; k++) + { + ib_status = + alts_rc_register_mem( p_ca_obj, k + (p_ca_obj->num_wrs * 2), 4096); + + if ( ib_status != IB_SUCCESS ) + { + while( k-- ) + alts_rc_deregister_mem(p_ca_obj, k + (p_ca_obj->num_wrs * 2) ); + + while( i-- ) + alts_rc_deregister_mem(p_ca_obj, i); + + return ib_status; + } + else + { + p_ca_obj->mem_region[k].my_lid = p_ca_obj->slid; + } + } + + p_ca_obj->cq_done = 0; + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("++++++ dlid(x%x) src_port(%d) ====\n", + p_ca_obj->dlid, p_ca_obj->src_port_num)); + + if(ib_status == IB_SUCCESS) + { + ib_status = ib_rearm_cq(p_ca_obj->h_cq, FALSE); + rc_rdma_post_recvs( p_ca_obj, 0, 1 ); // p_ca_obj->num_wrs + + if( p_ca_obj->num_cq > 1 ) + ib_status = ib_rearm_cq(p_ca_obj->h_cq_alt, FALSE); + else + ib_status = ib_rearm_cq(p_ca_obj->h_cq, FALSE); + + rc_rdma_post_sends( p_ca_obj, p_ca_obj->num_wrs * 2, 1, + p_ca_obj->num_wrs, 'W' ); + // send only one for now + //p_ca_obj->num_wrs ); + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("sleeping for awhile ...\n")); + + cl_thread_suspend(1000); // 10 seconds + + // check for rdma recv completion + p_rdma_req = (alts_rdma_t*)p_ca_obj->mem_region[p_ca_obj->num_wrs].buffer; + if( p_rdma_req->msg_type != 'C') // write completed + { + ib_status = IB_ERROR; + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("RDMA_Write failed\n")); + } + else + { + p_ca_obj->cq_done++; + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("RDMA_Write success\n")); + } + } + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("sleeping for awhile ...\n")); + + cl_thread_suspend(3000); // 10 seconds + +//#if 0 + + if (!p_ca_obj->cq_done) + { + p_free_wclist = &free_wclist; + p_free_wclist->p_next = NULL; + p_done_cl = NULL; + j = 0; + + ib_status = ib_poll_cq(p_ca_obj->h_cq, &p_free_wclist, &p_done_cl); + + while(p_done_cl) + { + /* + * print output + */ + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("Got a completion:\n" + "\ttype....:%s\n" + "\twr_id...:%"PRIx64"\n" + "\tstatus..:%s\n", + ib_get_wc_type_str(p_done_cl->wc_type), + p_done_cl->wr_id, + ib_get_wc_status_str(p_done_cl->status))); + + if (p_done_cl->wc_type == IB_WC_RECV) + { + id = (uint32_t)p_done_cl->wr_id; + buff = (char *)p_ca_obj->mem_region[id].buffer; + if (qp_type == IB_QPT_UNRELIABLE_DGRM) + { + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("---MSG--->%s\n",&buff[40])); + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("RecvUD info:\n" + "\trecv_opt...:x%x\n" + "\timm_data...:x%x\n" + "\tremote_qp..:x%x\n" + "\tpkey_index.:%d\n" + "\tremote_lid.:x%x\n" + "\tremote_sl..:x%x\n" + "\tpath_bits..:x%x\n" + "\tsrc_lid....:x%x\n", + p_done_cl->recv.ud.recv_opt, + p_done_cl->recv.ud.immediate_data, + CL_NTOH32(p_done_cl->recv.ud.remote_qp), + p_done_cl->recv.ud.pkey_index, + CL_NTOH16(p_done_cl->recv.ud.remote_lid), + p_done_cl->recv.ud.remote_sl, + p_done_cl->recv.ud.path_bits, + CL_NTOH16(p_ca_obj->mem_region[id].my_lid))); + } + else + { + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("RecvRC info:\n" + "\trecv_opt...:x%x\n" + "\timm_data...:x%x\n", + p_done_cl->recv.conn.recv_opt, + p_done_cl->recv.ud.immediate_data )); + } + + } + + p_free_wclist = p_done_cl; + p_free_wclist->p_next = NULL; + p_done_cl = NULL; + j++; + p_done_cl = NULL; + ib_status = ib_poll_cq(p_ca_obj->h_cq, &p_free_wclist, &p_done_cl); + } + + ALTS_PRINT( ALTS_DBG_INFO, + ("Number of items polled from CQ is = %d\n", j) ); + + p_ca_obj->cq_done += j; + + ib_status = IB_SUCCESS; + } + + + while( i-- ) + alts_rc_deregister_mem(p_ca_obj, i); + + while( k-- ) + alts_rc_deregister_mem(p_ca_obj, k + (p_ca_obj->num_wrs * 2)); + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + +ib_api_status_t +alts_cm_rc_rdma_tests ( + ib_ca_handle_t h_ca, + uint32_t ca_attr_size ) +{ + ib_api_status_t ib_status = IB_ERROR, ib_status2; + uint32_t bsize; + alts_cm_ca_obj_t *p_ca_obj = NULL; + ib_ca_attr_t *p_ca_attr = NULL; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + CL_ASSERT (h_ca); + CL_ASSERT (ca_attr_size); + + do + { + p_ca_obj = (alts_cm_ca_obj_t*)cl_zalloc(sizeof(alts_cm_ca_obj_t)); + if (!p_ca_obj) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("zalloc() failed for alts_cm_ca_obj_t!\n") ); + break; + } + + /* Allocate the memory needed for query_ca */ + bsize = ca_attr_size; + p_ca_attr = (ib_ca_attr_t *)cl_zalloc(bsize); + if (!p_ca_attr) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("zalloc() failed for p_ca_attr!\n") ); + break; + } + + ib_status = ib_query_ca(h_ca, p_ca_attr, &bsize); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_query_ca failed with status = %d\n", ib_status) ); + break; + } + + /* + * Initialize the CA Object + */ + p_ca_obj->h_ca = h_ca; + p_ca_obj->p_ca_attr = p_ca_attr; + p_ca_obj->status = IB_SUCCESS; + p_ca_obj->cq_size = 255*2; + p_ca_obj->qkey = 0; + p_ca_obj->ds_list_depth = 1; + p_ca_obj->num_wrs = 2; + p_ca_obj->msg_size = 256; + + p_ca_obj->src_qp_num = IB_QP1; + p_ca_obj->is_loopback = FALSE; + + p_ca_obj->test_type = IB_QPT_RELIABLE_CONN; + p_ca_obj->pfn_comp_cb = cm_rc_cq_comp_cb; // set your cq handler + + p_ca_obj->rdma_enabled = TRUE; + + p_ca_obj->reply_requested = TRUE; + + /* + * get an active port + */ + ib_status = alts_cm_check_active_ports(p_ca_obj); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("This test routing atleast 1 active port on the 1st hca\n")); + break; + } + + + /* + * Create the necessary resource PD/QP/QP + */ + p_ca_obj->num_cq = 2; + + ib_status = alts_create_test_resources( p_ca_obj ); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_create_test_resources() failed with status %d\n", ib_status)); + break; + } + + //cl_thread_suspend( 30000 ); + + /* + * Start Message passing activity + */ + ib_status = alts_cm_client_server(p_ca_obj); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_cm_client_server failed with status %d\n", ib_status)); + break; + } + + // query qp_info + ib_status = ib_query_qp(p_ca_obj->h_qp[SRC_QP], + &p_ca_obj->qp_attr[SRC_QP]); + ib_status = ib_query_qp(p_ca_obj->h_qp[DEST_QP], + &p_ca_obj->qp_attr[DEST_QP]); + + ALTS_PRINT( ALTS_DBG_VERBOSE, + ("SRC QP Info\n" + "\tstate.........:%d\n" + "\tpri_port......:%d\n" + "\tqp_num........:x%x\n" + "\tdest_qp_num...:x%x\n" + "\taccess_ctl....:x%x\n" + "\tsq_signalled..:%d\n" + "\tsq_psn........:x%x\n" + "\trq_psn........:x%x\n" + "\tresp_res......:x%x\n" + "\tinit_depth....:x%x\n" + "\tsq_depth......:x%x\n" + "\trq_depth......:x%x\n", + p_ca_obj->qp_attr[SRC_QP].state, + p_ca_obj->qp_attr[SRC_QP].primary_port, + p_ca_obj->qp_attr[SRC_QP].num, + p_ca_obj->qp_attr[SRC_QP].dest_num, + p_ca_obj->qp_attr[SRC_QP].access_ctrl, + p_ca_obj->qp_attr[SRC_QP].sq_signaled, + p_ca_obj->qp_attr[SRC_QP].sq_psn, + p_ca_obj->qp_attr[SRC_QP].rq_psn, + p_ca_obj->qp_attr[SRC_QP].resp_res, + p_ca_obj->qp_attr[SRC_QP].init_depth, + p_ca_obj->qp_attr[SRC_QP].sq_depth, + p_ca_obj->qp_attr[SRC_QP].rq_depth )); + + ALTS_PRINT( ALTS_DBG_VERBOSE, + ("DEST QP Info\n" + "\tstate.........:%d\n" + "\tpri_port......:%d\n" + "\tqp_num........:x%x\n" + "\tdest_qp_num...:x%x\n" + "\taccess_ctl....:x%x\n" + "\tsq_signalled..:%d\n" + "\tsq_psn........:x%x\n" + "\trq_psn........:x%x\n" + "\tresp_res......:x%x\n" + "\tinit_depth....:x%x\n" + "\tsq_depth......:x%x\n" + "\trq_depth......:x%x\n", + p_ca_obj->qp_attr[DEST_QP].state, + p_ca_obj->qp_attr[DEST_QP].primary_port, + p_ca_obj->qp_attr[DEST_QP].num, + p_ca_obj->qp_attr[DEST_QP].dest_num, + p_ca_obj->qp_attr[DEST_QP].access_ctrl, + p_ca_obj->qp_attr[DEST_QP].sq_signaled, + p_ca_obj->qp_attr[DEST_QP].sq_psn, + p_ca_obj->qp_attr[DEST_QP].rq_psn, + p_ca_obj->qp_attr[DEST_QP].resp_res, + p_ca_obj->qp_attr[DEST_QP].init_depth, + p_ca_obj->qp_attr[DEST_QP].sq_depth, + p_ca_obj->qp_attr[DEST_QP].rq_depth )); + + //cl_thread_suspend( 30000 ); + + // run the test + ib_status = alts_rc_rdma_message_passing(p_ca_obj, IB_QPT_RELIABLE_CONN); + + ALTS_PRINT( ALTS_DBG_VERBOSE, + ("sleep for 3 seconds...\n" )); + cl_thread_suspend(3000); /* 1 sec */ + + // destroy connection + ib_status = alts_cm_destroy(p_ca_obj); + + if (p_ca_obj->cq_done >= 4) + ib_status = IB_SUCCESS; + else + ib_status = IB_ERROR; + + + } while (0); + + /* + * Destroy the resources + */ + ib_status2 = alts_cm_destroy_resources(p_ca_obj); + if (ib_status == IB_SUCCESS) + ib_status = ib_status2; + + if (p_ca_attr) + cl_free(p_ca_attr); + + if (p_ca_obj) + cl_free(p_ca_obj); + + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + + + +void +__mra_thread( + IN void* context ) +{ + ib_api_status_t ib_status; + alts_cm_ca_obj_t *p_ca_obj; + ib_cm_rep_t *p_cm_rep; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + p_ca_obj = (alts_cm_ca_obj_t*)context; + + ALTS_PRINT( ALTS_DBG_VERBOSE, + ("mra_event sleep (30 secs)...\n") ); + + cl_event_wait_on( &p_ca_obj->mra_event, 8 *1000 * 1000, TRUE ); + + ALTS_PRINT( ALTS_DBG_VERBOSE, + ("mra_event triggered...\n") ); + + p_cm_rep = &p_ca_obj->rep_dest; + + ib_status = ib_cm_rep( p_ca_obj->h_cm_req, p_cm_rep ); + + ALTS_EXIT( ALTS_DBG_VERBOSE); +} + + +ib_api_status_t +alts_rc_mra_test ( + ib_ca_handle_t h_ca, + uint32_t ca_attr_size ) +{ + ib_api_status_t ib_status = IB_ERROR, ib_status2; + uint32_t bsize; + alts_cm_ca_obj_t *p_ca_obj = NULL; + ib_ca_attr_t *p_ca_attr = NULL; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + CL_ASSERT (h_ca); + CL_ASSERT (ca_attr_size); + + do + { + p_ca_obj = (alts_cm_ca_obj_t*)cl_zalloc(sizeof(alts_cm_ca_obj_t)); + if (!p_ca_obj) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("zalloc() failed for alts_cm_ca_obj_t!\n") ); + break; + } + + /* Allocate the memory needed for query_ca */ + bsize = ca_attr_size; + p_ca_attr = (ib_ca_attr_t *)cl_zalloc(bsize); + if (!p_ca_attr) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("zalloc() failed for p_ca_attr!\n") ); + break; + } + + ib_status = ib_query_ca(h_ca, p_ca_attr, &bsize); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_query_ca failed with status = %d\n", ib_status) ); + break; + } + + /* + * Initialize the CA Object + */ + p_ca_obj->h_ca = h_ca; + p_ca_obj->p_ca_attr = p_ca_attr; + p_ca_obj->status = IB_SUCCESS; + p_ca_obj->cq_size = 255*2; + p_ca_obj->qkey = 0; + p_ca_obj->ds_list_depth = 1; + p_ca_obj->num_wrs = 1; + p_ca_obj->msg_size = 256; + + p_ca_obj->src_qp_num = IB_QP1; + p_ca_obj->is_loopback = FALSE; + + p_ca_obj->test_type = IB_QPT_RELIABLE_CONN; + p_ca_obj->pfn_comp_cb = cm_rc_cq_comp_cb; // set your cq handler + + p_ca_obj->reply_requested = TRUE; + + p_ca_obj->mra_test = TRUE; + + /* + * get an active port + */ + ib_status = alts_cm_check_active_ports(p_ca_obj); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("This test routing atleast 1 active port on the 1st hca\n")); + break; + } + + + /* + * Create the necessary resource PD/QP/QP + */ + p_ca_obj->num_cq = 2; + + ib_status = alts_create_test_resources( p_ca_obj ); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_create_test_resources() failed with status %d\n", ib_status)); + break; + } + + /* + * Start Message passing activity + */ + ib_status = alts_cm_client_server(p_ca_obj); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_cm_client_server failed with status %d\n", ib_status)); + break; + } + + // run the test + ib_status = alts_rc_message_passing(p_ca_obj, IB_QPT_RELIABLE_CONN); + + cl_thread_suspend(1000); /* 1 sec */ + + // destroy connection + ib_status = alts_cm_destroy(p_ca_obj); + + if (p_ca_obj->cq_done == 2) + ib_status = IB_SUCCESS; + else + ib_status = IB_ERROR; + + + } while (0); + + /* + * Destroy the resources + */ + ib_status2 = alts_cm_destroy_resources(p_ca_obj); + if (ib_status == IB_SUCCESS) + ib_status = ib_status2; + + if (p_ca_attr) + cl_free(p_ca_attr); + + if (p_ca_obj) + cl_free(p_ca_obj); + + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + + +ib_api_status_t +alts_cm_uc_test ( + ib_ca_handle_t h_ca, + uint32_t ca_attr_size ) +{ + ib_api_status_t ib_status = IB_ERROR, ib_status2; + uint32_t bsize; + alts_cm_ca_obj_t *p_ca_obj = NULL; + ib_ca_attr_t *p_ca_attr = NULL; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + CL_ASSERT (h_ca); + CL_ASSERT (ca_attr_size); + + do + { + p_ca_obj = (alts_cm_ca_obj_t*)cl_zalloc(sizeof(alts_cm_ca_obj_t)); + if (!p_ca_obj) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("zalloc() failed for alts_cm_ca_obj_t!\n") ); + break; + } + + /* Allocate the memory needed for query_ca */ + bsize = ca_attr_size; + p_ca_attr = (ib_ca_attr_t *)cl_zalloc(bsize); + if (!p_ca_attr) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("zalloc() failed for p_ca_attr!\n") ); + break; + } + + ib_status = ib_query_ca(h_ca, p_ca_attr, &bsize); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_query_ca failed with status = %d\n", ib_status) ); + break; + } + + /* + * Initialize the CA Object + */ + p_ca_obj->h_ca = h_ca; + p_ca_obj->p_ca_attr = p_ca_attr; + p_ca_obj->status = IB_SUCCESS; + p_ca_obj->cq_size = 255*2; + p_ca_obj->qkey = 0; + p_ca_obj->ds_list_depth = 1; + p_ca_obj->num_wrs = 1; + p_ca_obj->msg_size = 256; + + p_ca_obj->src_qp_num = IB_QP1; + p_ca_obj->is_loopback = FALSE; + + p_ca_obj->test_type = IB_QPT_UNRELIABLE_CONN; + p_ca_obj->pfn_comp_cb = cm_rc_cq_comp_cb; // set your cq handler + + p_ca_obj->reply_requested = TRUE; + + /* + * get an active port + */ + ib_status = alts_cm_check_active_ports(p_ca_obj); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("This test routing atleast 1 active port on the 1st hca\n")); + break; + } + + + /* + * Create the necessary resource PD/QP/QP + */ + p_ca_obj->num_cq = 2; + + ib_status = alts_create_test_resources( p_ca_obj ); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_create_test_resources() failed with status %d\n", ib_status)); + break; + } + + /* + * Start Message passing activity + */ + ib_status = alts_cm_client_server(p_ca_obj); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_cm_client_server failed with status %d\n", ib_status)); + break; + } + + // run the test + ib_status = alts_rc_message_passing(p_ca_obj, IB_QPT_RELIABLE_CONN); + + cl_thread_suspend(1000); /* 1 sec */ + + // destroy connection + ib_status = alts_cm_destroy(p_ca_obj); + + if (p_ca_obj->cq_done == 2) + ib_status = IB_SUCCESS; + else + ib_status = IB_ERROR; + + + } while (0); + + /* + * Destroy the resources + */ + ib_status2 = alts_cm_destroy_resources(p_ca_obj); + if (ib_status == IB_SUCCESS) + ib_status = ib_status2; + + if (p_ca_attr) + cl_free(p_ca_attr); + + if (p_ca_obj) + cl_free(p_ca_obj); + + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + + +ib_api_status_t +alts_cm_sidr_tests ( + ib_ca_handle_t h_ca, + uint32_t ca_attr_size ) +{ + ib_api_status_t ib_status = IB_ERROR, ib_status2; + uint32_t bsize; + alts_cm_ca_obj_t *p_ca_obj = NULL; + ib_ca_attr_t *p_ca_attr = NULL; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + CL_ASSERT (h_ca); + CL_ASSERT (ca_attr_size); + + do + { + p_ca_obj = (alts_cm_ca_obj_t*)cl_zalloc(sizeof(alts_cm_ca_obj_t)); + if (!p_ca_obj) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("zalloc() failed for alts_cm_ca_obj_t!\n") ); + break; + } + + /* Allocate the memory needed for query_ca */ + bsize = ca_attr_size; + p_ca_attr = (ib_ca_attr_t *)cl_zalloc(bsize); + if (!p_ca_attr) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("zalloc() failed for p_ca_attr!\n") ); + break; + } + + ib_status = ib_query_ca(h_ca, p_ca_attr, &bsize); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_query_ca failed with status = %d\n", ib_status) ); + break; + } + + /* + * Initialize the CA Object + */ + p_ca_obj->h_ca = h_ca; + p_ca_obj->p_ca_attr = p_ca_attr; + p_ca_obj->status = IB_SUCCESS; + p_ca_obj->cq_size = 255*2; + p_ca_obj->qkey = 0x1; + p_ca_obj->ds_list_depth = 1; + p_ca_obj->num_wrs = 1; + p_ca_obj->msg_size = 256; + + p_ca_obj->src_qp_num = IB_QP1; + p_ca_obj->is_loopback = FALSE; + + p_ca_obj->test_type = IB_QPT_UNRELIABLE_DGRM; + p_ca_obj->pfn_comp_cb = cm_ud_cq_comp_cb; // set your cq handler + + p_ca_obj->reply_requested = TRUE; + + /* + * get an active port + */ + ib_status = alts_cm_check_active_ports(p_ca_obj); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("This test routing atleast 1 active port on the 1st hca\n")); + break; + } + + /* + * Create the necessary resource PD/QP/QP + */ + ib_status = alts_create_test_resources( p_ca_obj ); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_create_test_resources() failed with status %d\n", ib_status)); + break; + } + + /* + * Start Message passing activity + */ + ib_status = alts_cm_client_server(p_ca_obj); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_cm_client_server failed with status %d\n", ib_status)); + break; + } + + // run the test + //ib_status = alts_rc_message_passing(p_ca_obj,IB_QPT_UNRELIABLE_DGRM); + + cl_thread_suspend(1000); /* 1 sec */ + + // destroy connection + ib_status = alts_cm_destroy(p_ca_obj); + + } while (0); + + /* + * Destroy the resources + */ + ib_status2 = alts_cm_destroy_resources(p_ca_obj); + if (ib_status == IB_SUCCESS) + ib_status = ib_status2; + + if (p_ca_attr) + cl_free(p_ca_attr); + + if (p_ca_obj) + cl_free(p_ca_obj); + + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} diff --git a/branches/WOF2-3/tests/alts/createanddestroycq.c b/branches/WOF2-3/tests/alts/createanddestroycq.c new file mode 100644 index 00000000..f1cc008c --- /dev/null +++ b/branches/WOF2-3/tests/alts/createanddestroycq.c @@ -0,0 +1,333 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include +#include +#include +#include +#include + + + + +/* + * Function prototypes + */ +ib_api_status_t +alts_cq( + boolean_t modify_cq_attr + ); + +/* + * Test Case CrateDestroyCQ + */ + + +ib_api_status_t +al_test_create_destroy_cq(void) +{ + boolean_t modify_cq_attr = FALSE; + + return alts_cq(modify_cq_attr); +} + +ib_api_status_t +al_test_query_modify_cq(void) +{ + boolean_t modify_cq_attr = TRUE; + + return alts_cq(modify_cq_attr); +} + + +/* Internal Functions */ + +ib_api_status_t +alts_cq( + boolean_t modify_cq_attr + ) +{ + ib_api_status_t ib_status = IB_SUCCESS; + ib_al_handle_t h_al = NULL; + ib_ca_handle_t h_ca; + ib_cq_handle_t h_cq = NULL; + cl_status_t cl_status; + ib_cq_create_t cq_create; + ib_pd_handle_t h_pd; + int iteration = 0; +#ifdef CL_KERNEL + cl_event_t cq_event; + + cl_event_construct( &cq_event ); +#endif + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + while(1) + { + /* Open AL */ + ib_status = alts_open_al(&h_al); + + if(ib_status != IB_SUCCESS) + break; + + CL_ASSERT(h_al); + + /* Open CA */ + ib_status = alts_open_ca(h_al,&h_ca); + if(ib_status != IB_SUCCESS) + break; + + CL_ASSERT(h_ca); + + /* + * Allocate a PD required for CQ + */ + ib_status = ib_alloc_pd(h_ca, IB_PDT_NORMAL, NULL, &h_pd); //passing null context + + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("\tib_alloc_pd failed status = %s\n", ib_get_err_str(ib_status)) ); + alts_close_ca(h_ca); + break; + } + ALTS_PRINT( ALTS_DBG_ERROR, + ("\tib_pd handle = %p\n",h_pd)); + + /* 1st pass: event callback, 2nd pass: wait object. */ + do + { + iteration++; + + /* + * Initialize the CQ creation attributes. + */ + cl_memclr( &cq_create, sizeof( ib_cq_create_t ) ); + if( iteration == 1 ) + { + /* Event callback */ + cq_create.pfn_comp_cb = alts_cq_comp_cb; + } + else if( iteration == 2 ) +#ifdef CL_KERNEL + { + cl_status = cl_event_init( &cq_event, FALSE ); + if( cl_status != CL_SUCCESS ) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("cl_event_init returned status %#x\n", + cl_status) ); + break; + } + cq_create.h_wait_obj = &cq_event; + } +#else + { + /* Wait Object */ + cl_status = + cl_waitobj_create( TRUE, &cq_create.h_wait_obj ); + if( cl_status != CL_SUCCESS ) + { + CL_PRINT( ALTS_DBG_ERROR, alts_dbg_lvl, + ("cl_create_wait_object failed status = 0x%x\n", + cl_status) ); + break; + } + } + else + { + /* Bogus wait object. */ + cq_create.h_wait_obj = (void*)(uintn_t)0xCDEF0000; + } +#endif + + cq_create.size = ALTS_CQ_SIZE; //Size of the CQ // NOTENOTE + + /* Create CQ here */ + ib_status = ib_create_cq(h_ca, &cq_create, + NULL,alts_cq_err_cb, &h_cq); + + /* Trap expected failure. */ + if( iteration == 3 && ib_status != IB_SUCCESS ) + break; + + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_create_cq failed status = %s\n", + ib_get_err_str(ib_status)) ); + break; + } + CL_ASSERT(h_cq); + ALTS_PRINT( ALTS_DBG_INFO,\ + ("ib_create_cq successful size = 0x%x status = %s\n", + cq_create.size, ib_get_err_str(ib_status)) ); + + while( modify_cq_attr == TRUE ) + { + /* + * Query and Modify CQ ATTR + */ + uint32_t cq_size; + + ib_status = ib_query_cq(h_cq,&cq_size); + + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_query_cq failed status = %s\n", + ib_get_err_str(ib_status)) ); + break; + } + + if(cq_size != cq_create.size) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_query_cq failed cq_size=0x%x cq_create.cq_size=0x%x\n", + cq_size,cq_create.size)); + ib_status = IB_INVALID_CQ_SIZE; + break; + } + + ALTS_PRINT( ALTS_DBG_INFO, + ("ib_query_cq cq_size = 0x%x\n", cq_size) ); + + cq_size = 0x90; + + ib_status = ib_modify_cq(h_cq,&cq_size); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_modify_cq failed status = %s\n", + ib_get_err_str(ib_status)) ); + break; + } + + ALTS_PRINT( ALTS_DBG_INFO, + ("ib_modify_cq passed for cq_size = 0x%x\n", cq_size) ); + + break; //Break for the while + } + + ib_status = ib_destroy_cq(h_cq, alts_cq_destroy_cb); + + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_destroy_cq failed status = %s\n", + ib_get_err_str(ib_status)) ); + break; + } + ALTS_PRINT( ALTS_DBG_INFO,\ + ("ib_destroy_cq successful status = %s\n", + ib_get_err_str(ib_status))); + + +#ifdef CL_KERNEL + } while( iteration < 2 ); + + cl_event_destroy( &cq_event ); +#else + if( cq_create.h_wait_obj ) + { + cl_status = cl_waitobj_destroy( cq_create.h_wait_obj ); + if( cl_status != CL_SUCCESS ) + { + CL_PRINT( ALTS_DBG_ERROR, alts_dbg_lvl, + ("cl_destroy_wait_object failed status = 0x%x", + cl_status) ); + } + } + + } while( iteration < 3 ); +#endif + + ib_status = ib_dealloc_pd(h_pd,alts_pd_destroy_cb); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_dealloc_pd failed status = %s\n", + ib_get_err_str(ib_status)) ); + } + + alts_close_ca(h_ca); + + break; //End of while + } + + /* Close AL */ + if(h_al) + alts_close_al(h_al); + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + +void +alts_cq_comp_cb( + IN const ib_cq_handle_t h_cq, + IN void *cq_context ) +{ + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + UNUSED_PARAM( h_cq ); + UNUSED_PARAM( cq_context ); + + ALTS_EXIT( ALTS_DBG_VERBOSE); +} + + +void +alts_cq_err_cb( + ib_async_event_rec_t *p_err_rec ) +{ + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + UNUSED_PARAM( p_err_rec ); + + ALTS_EXIT( ALTS_DBG_VERBOSE); +} + +void +alts_cq_destroy_cb( + void *context + ) +{ + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + UNUSED_PARAM( context ); + + ALTS_EXIT( ALTS_DBG_VERBOSE); +} diff --git a/branches/WOF2-3/tests/alts/createanddestroyqp.c b/branches/WOF2-3/tests/alts/createanddestroyqp.c new file mode 100644 index 00000000..39f864c8 --- /dev/null +++ b/branches/WOF2-3/tests/alts/createanddestroyqp.c @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include +#include +#include +#include +#include + + + + +/* + * Function prototypes + */ +ib_api_status_t +alts_qp( + boolean_t modify_cq_attr + ); + + + +/* + * Test Case CrateDestroyQP + */ + + +ib_api_status_t +al_test_create_destroy_qp(void) +{ + boolean_t modify_qp_attr = FALSE; + + return alts_qp(modify_qp_attr); +} + +ib_api_status_t +al_test_query_modify_qp(void) +{ + boolean_t modify_qp_attr = TRUE; + + return alts_qp(modify_qp_attr); +} + + +/* Internal Functions */ + +ib_api_status_t +alts_qp( + boolean_t modify_cq_attr + ) +{ + ib_api_status_t ib_status = IB_SUCCESS; + ib_al_handle_t h_al = NULL; + ib_ca_handle_t h_ca; + ib_cq_handle_t h_cq = NULL; + ib_qp_handle_t h_qp = NULL; + ib_pd_handle_t h_pd; + cl_status_t cl_status; + ib_cq_create_t cq_create; + ib_qp_create_t qp_create; + uint32_t bsize; + ib_ca_attr_t *p_ca_attr = NULL; + ib_qp_attr_t p_qp_attr; + + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + while(1) + { + /* Open AL */ + ib_status = alts_open_al(&h_al); + + if(ib_status != IB_SUCCESS) + break; + + CL_ASSERT(h_al); + + /* Open CA */ + ib_status = alts_open_ca(h_al,&h_ca); + if(ib_status != IB_SUCCESS) + break; + + CL_ASSERT(h_ca); + + /* + * Allocate a PD required for CQ + */ + ib_status = ib_alloc_pd(h_ca, IB_PDT_NORMAL, NULL, &h_pd); //passing null context + + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("\tib_alloc_pd failed status = %s\n", ib_get_err_str(ib_status)) ); + alts_close_ca(h_ca); + break; + } + ALTS_PRINT( ALTS_DBG_ERROR, + ("\tib_pd handle = %p\n",h_pd)); + + /* + * Get the CA Attributest + * Check for two active ports + */ + + /* + * Query the CA + */ + bsize = 0; + ib_status = ib_query_ca(h_ca, NULL, &bsize); + if(ib_status != IB_INSUFFICIENT_MEMORY) + { + ALTS_PRINT(ALTS_DBG_ERROR, + ("ib_query_ca failed with status = %d\n", ib_status) ); + break; + } + CL_ASSERT(bsize); + + + + p_ca_attr = (ib_ca_attr_t *)cl_zalloc(bsize); + if (!p_ca_attr) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("zalloc() failed for p_ca_attr!\n") ); + break; + } + + ib_status = ib_query_ca(h_ca, p_ca_attr, &bsize); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_query_ca failed with status = %d\n", ib_status) ); + break; + } + + + + + /* + * Create CQ Attributes + */ + cq_create.size = ALTS_CQ_SIZE; + cq_create.pfn_comp_cb = alts_cq_comp_cb; + cq_create.h_wait_obj = NULL; + + ib_status = ib_create_cq( + h_ca, + &cq_create, + NULL, + alts_cq_err_cb, + &h_cq ); + CL_ASSERT(ib_status == IB_SUCCESS); + + + + /* + * Create QP Attributes + */ + cl_memclr(&qp_create, sizeof(ib_qp_create_t)); + qp_create.sq_depth= 1; + qp_create.rq_depth= 1; + qp_create.sq_sge = 1; + qp_create.rq_sge = 1; + qp_create.h_sq_cq = h_cq; //NULL + qp_create.h_rq_cq = h_cq; + + qp_create.sq_signaled = TRUE; + + qp_create.qp_type = IB_QPT_RELIABLE_CONN; + + + ib_status = ib_create_qp( + h_pd, + &qp_create, + NULL, + alts_qp_err_cb, + &h_qp); + + if (ib_status != IB_SUCCESS) + { + ALTS_PRINT(ALTS_DBG_ERROR, + ("Error in ib_create_qp()! %s\n", + ib_get_err_str(ib_status))); + ALTS_EXIT(ALTS_DBG_VERBOSE); + return (ib_status); + } + + ib_status = ib_query_qp(h_qp, + &p_qp_attr); + + if (ib_status != IB_SUCCESS) + { + ALTS_PRINT(ALTS_DBG_ERROR, + ("Error in query_qp()! %s\n", + ib_get_err_str(ib_status))); + + ib_destroy_qp(h_qp,alts_qp_destroy_cb); + ALTS_EXIT(ALTS_DBG_VERBOSE); + return (ib_status); + } + + ib_status = ib_destroy_qp(h_qp, alts_qp_destroy_cb); + + if (h_cq) + ib_status = ib_destroy_cq(h_cq, alts_qp_destroy_cb); + + + ib_status = ib_dealloc_pd(h_pd,alts_pd_destroy_cb); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_dealloc_pd failed status = %s\n", + ib_get_err_str(ib_status)) ); + } + + alts_close_ca(h_ca); + + break; //End of while + } + + /* Close AL */ + if(h_al) + alts_close_al(h_al); + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + +void +alts_qp_err_cb( + ib_async_event_rec_t *p_err_rec ) +{ + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + UNUSED_PARAM( p_err_rec ); + + ALTS_EXIT( ALTS_DBG_VERBOSE); +} + +void +alts_qp_destroy_cb( + void *context + ) +{ + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + UNUSED_PARAM( context ); + + ALTS_EXIT( ALTS_DBG_VERBOSE); +} + + + + diff --git a/branches/WOF2-3/tests/alts/createdestroyav.c b/branches/WOF2-3/tests/alts/createdestroyav.c new file mode 100644 index 00000000..ca7c7106 --- /dev/null +++ b/branches/WOF2-3/tests/alts/createdestroyav.c @@ -0,0 +1,334 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include +#include +#include +#include +#include + +/* + * Function prototypes + */ +ib_api_status_t +alts_av( + boolean_t modify_av_attr + ); + + +/* + * Test Case CrateDestroyAV + */ + +ib_api_status_t +al_test_create_destroy_av(void) +{ + boolean_t modify_av_attr = FALSE; + + return alts_av(modify_av_attr); +} + +ib_api_status_t +al_test_query_modify_av(void) +{ + boolean_t modify_av_attr = TRUE; + + return alts_av(modify_av_attr); +} + + +/* Internal Functions */ + +ib_api_status_t +alts_av( + boolean_t modify_av_attr + ) +{ + ib_api_status_t ib_status = IB_SUCCESS; + ib_al_handle_t h_al = NULL; + size_t guid_count; + ib_port_attr_t *p_alts_port_attr; + ib_av_attr_t alts_av_attr, query_av_attr; + ib_ca_handle_t h_ca; + ib_pd_handle_t h_pd, h_pd1; + ib_av_handle_t h_av; + ib_net64_t ca_guid_array[ALTS_MAX_CA]; + uint32_t bsize; + ib_ca_attr_t *alts_ca_attr = NULL; + uint8_t i; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + while(1) + { + /* Step 1: Open AL */ + ib_status = alts_open_al(&h_al); + + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, \ + ("Open AL failed\n")); + break; + } + + CL_ASSERT(h_al); + + /* + * Step 2: Open the first available CA + */ + + ib_status = ib_get_ca_guids(h_al, NULL, &guid_count); + if(ib_status != IB_INSUFFICIENT_MEMORY) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_get_ca_guids failed status = %s\n",ib_get_err_str(ib_status)) ); + break; + + } + + ALTS_PRINT(ALTS_DBG_INFO, \ + ("Total number of CA in the sytem is %d\n",(uint32_t)guid_count)); + + if(guid_count == 0) + { + ib_status = IB_ERROR; + break; + } + + ib_status = ib_get_ca_guids(h_al, ca_guid_array, &guid_count); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_get_ca_guids failed with status = %s\n", ib_get_err_str(ib_status)) ); + break; + } + + ib_status = ib_open_ca(h_al, + ca_guid_array[0], //Default open the first CA + alts_ca_err_cb, + (void *)1234, //ca_context + &h_ca); + + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_open_ca failed with status = %s\n", ib_get_err_str(ib_status)) ); + break; + + } + CL_ASSERT(h_ca); + + /* + * Step 3: Query for the CA Attributes + */ + + /* Query the CA */ + bsize = 0; + ib_status = ib_query_ca(h_ca, NULL, &bsize); + if(ib_status != IB_INSUFFICIENT_MEMORY) + { + ALTS_PRINT(ALTS_DBG_ERROR, + ("ib_query_ca failed with status = %s\n",ib_get_err_str(ib_status)) ); + + ib_close_ca(h_ca, alts_ca_destroy_cb); + break; + } + CL_ASSERT(bsize); + + /* Allocate the memory needed for query_ca */ + + alts_ca_attr = (ib_ca_attr_t *)cl_zalloc(bsize); + CL_ASSERT(alts_ca_attr); + + ib_status = ib_query_ca(h_ca, alts_ca_attr, &bsize); + + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_query_ca failed with status = %s\n", ib_get_err_str(ib_status)) ); + ib_close_ca(h_ca, alts_ca_destroy_cb); + break; + } + + p_alts_port_attr = alts_ca_attr->p_port_attr; + + /* + * Step 4: Get the active port + */ + ALTS_PRINT( ALTS_DBG_INFO, \ + ("Get the active Port\n")); +//#if 0 + for(i=0;i < alts_ca_attr->num_ports; i++) + { + p_alts_port_attr = &alts_ca_attr->p_port_attr[i]; + if(p_alts_port_attr->link_state == IB_LINK_ACTIVE) + break; + } + + if(p_alts_port_attr->link_state != IB_LINK_ACTIVE) + { + ALTS_PRINT(ALTS_DBG_ERROR, + ("port attribute link state is not active\n") ); + ib_close_ca(h_ca, alts_ca_destroy_cb); + break; + } + + + ALTS_PRINT(ALTS_DBG_INFO, \ + ("Active port number is %d\n",p_alts_port_attr->port_num)); +//#endif + + /* + * Step 5: Construct the AV structure + */ + + alts_av_attr.port_num = p_alts_port_attr->port_num; + //DLID is SM LID + alts_av_attr.dlid = p_alts_port_attr->sm_lid; + + alts_av_attr.sl = 0; + alts_av_attr.static_rate = IB_PATH_RECORD_RATE_10_GBS; + alts_av_attr.path_bits = 0; + alts_av_attr.grh_valid = TRUE; + + alts_av_attr.grh.dest_gid.unicast.interface_id= ca_guid_array[0]; + alts_av_attr.grh.src_gid.unicast.interface_id = ca_guid_array[0]; + alts_av_attr.grh.hop_limit = 0; + alts_av_attr.grh.ver_class_flow = 0; + /* + * step 6: Create a PD + */ + + /* NOTE Try creating PD for IB_PDT_ALIAS type */ + + ib_status = ib_alloc_pd(h_ca, IB_PDT_NORMAL, (void *)1234, &h_pd); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_alloc_pd failed with status = %s\n",ib_get_err_str(ib_status)) ); + ib_close_ca(h_ca, alts_ca_destroy_cb); + break; + } + + + + /* + * Step 7: Create the Address Vector + */ + ib_status = ib_create_av(h_pd, &alts_av_attr, &h_av); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_create_av failed with status = %s\n",ib_get_err_str(ib_status)) ); + ib_status = ib_dealloc_pd(h_pd,alts_pd_destroy_cb); + ib_close_ca(h_ca, alts_ca_destroy_cb); + break; + } + if(modify_av_attr == TRUE) + { + /* + * Query the AV fromt the handle + */ + ib_status = ib_query_av(h_av, &query_av_attr, &h_pd1); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_query_av failed with status = %s\n",ib_get_err_str(ib_status)) ); + + ib_destroy_av(h_av); + ib_status = ib_dealloc_pd(h_pd,alts_pd_destroy_cb); + ib_close_ca(h_ca, alts_ca_destroy_cb); + break; + } + + query_av_attr.dlid = p_alts_port_attr->lid; //DLID is local lid; + + ib_status = ib_modify_av(h_av, &query_av_attr); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_modify_av failed with status = %s\n",ib_get_err_str(ib_status)) ); + ib_destroy_av(h_av); + ib_status = ib_dealloc_pd(h_pd,alts_pd_destroy_cb); + ib_close_ca(h_ca, alts_ca_destroy_cb); + break; + } + /* Again query the AV to verify the modified value*/ + ib_status = ib_query_av(h_av, &query_av_attr, &h_pd1); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_query_av failed with status = %s\n", ib_get_err_str(ib_status)) ); + + ib_destroy_av(h_av); + ib_status = ib_dealloc_pd(h_pd,alts_pd_destroy_cb); + ib_close_ca(h_ca, alts_ca_destroy_cb); + break; + } + CL_ASSERT(query_av_attr.dlid == p_alts_port_attr->lid); + ALTS_PRINT( ALTS_DBG_INFO, + ("ib_modify_av PASSED\n") ); + + + + } + + + /* + * Destroy the address Vector + */ + ib_status = ib_destroy_av(h_av); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_destroy_av failed with status = %s\n", ib_get_err_str(ib_status)) ); + ib_status = ib_dealloc_pd(h_pd,alts_pd_destroy_cb); + ib_close_ca(h_ca, alts_ca_destroy_cb); + break; + } + + ib_status = ib_dealloc_pd(h_pd,alts_pd_destroy_cb); + ib_close_ca(h_ca, alts_ca_destroy_cb); + break; //End of while + } + + /* Close AL */ + if(h_al) + alts_close_al(h_al); + if(alts_ca_attr) + cl_free(alts_ca_attr); + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} diff --git a/branches/WOF2-3/tests/alts/creatememwindow.c b/branches/WOF2-3/tests/alts/creatememwindow.c new file mode 100644 index 00000000..e14ef2d2 --- /dev/null +++ b/branches/WOF2-3/tests/alts/creatememwindow.c @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include +#include +#include +#include +#include + + +/* Test case PARAMETERS */ + +#define MEM_ALLIGN 32 +#define MEM_SIZE 1024 + + +/* + * Function prototypes + */ + + +/* + * Test Case RegisterMemRegion + */ + +ib_api_status_t +al_test_create_mem_window( + void + ) +{ + ib_api_status_t ib_status = IB_SUCCESS; + ib_al_handle_t h_al = NULL; + ib_ca_handle_t h_ca = NULL; + ib_pd_handle_t h_pd = NULL; + + ib_mr_create_t virt_mem; + char *ptr = NULL, *ptr_align; + size_t mask; + uint32_t lkey; + uint32_t rkey; + ib_mr_handle_t h_mr = NULL; + ib_mr_attr_t alts_mr_attr; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + while(1) + { + /* Open AL */ + ib_status = alts_open_al(&h_al); + + if(ib_status != IB_SUCCESS) + break; + + CL_ASSERT(h_al); + + /* Open CA */ + ib_status = alts_open_ca(h_al,&h_ca); + if(ib_status != IB_SUCCESS) + break; + + CL_ASSERT(h_ca); + + /* + * Allocate a PD here + */ + ib_status = ib_alloc_pd(h_ca, IB_PDT_NORMAL, NULL, &h_pd); //passing null context + + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_alloc_pd failed status = %d", ib_status) ); + alts_close_ca(h_ca); + break; + } + + /* + * Allocate the virtual memory which needs to be registered + */ + + mask = MEM_ALLIGN - 1; + + ptr = cl_malloc(MEM_SIZE + MEM_ALLIGN - 1); + + CL_ASSERT(ptr); + + ptr_align = ptr; + + if(((size_t)ptr & mask) != 0) + ptr_align = (char *)(((size_t)ptr+mask)& ~mask); + + virt_mem.vaddr = ptr_align; + virt_mem.length = MEM_SIZE; + virt_mem.access_ctrl = (IB_AC_LOCAL_WRITE | IB_AC_MW_BIND); + + /* + * Register the memory region + */ + + ib_status = ib_reg_mem(h_pd, &virt_mem, &lkey, &rkey, &h_mr); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_reg_mem failed status = %s\n", ib_get_err_str(ib_status)) ); + alts_close_ca(h_ca); + break; + } + + /* + * Query the memory region + */ + ib_status = ib_query_mr(h_mr, &alts_mr_attr); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_query_mr failed status = %s\n", ib_get_err_str(ib_status)) ); + alts_close_ca(h_ca); + break; + } + + /* + * Re-register the memeory region + */ + virt_mem.access_ctrl |= (IB_AC_RDMA_WRITE ); + + ib_status = ib_rereg_mem(h_mr,IB_MR_MOD_ACCESS, + &virt_mem,&lkey,&rkey,NULL); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_rereg_mem failed status = %s\n", ib_get_err_str(ib_status)) ); + } + /* + * Create, Query and Destroy the memory window + */ + + { + + uint32_t rkey_mw; + ib_mw_handle_t h_mw; + + ib_pd_handle_t h_pd_query; + uint32_t rkey_mw_query; + + ib_status = ib_create_mw(h_pd,&rkey_mw,&h_mw); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_create_mw failed status = %s\n",ib_get_err_str(ib_status)) ); + alts_close_ca(h_ca); + break; + } + + ib_status = ib_query_mw(h_mw,&h_pd_query,&rkey_mw_query); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_query_mw failed status = %s\n", ib_get_err_str(ib_status)) ); + alts_close_ca(h_ca); + break; + } + + ib_status = ib_destroy_mw(h_mw); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_destroy_mw failed status = %s\n", ib_get_err_str(ib_status)) ); + alts_close_ca(h_ca); + break; + } + + } + + /* + * De-register the memory region + */ + ib_status = ib_dereg_mr(h_mr); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_dereg_mr failed status = %s\n", ib_get_err_str(ib_status)) ); + alts_close_ca(h_ca); + break; + } + + /* + * Deallocate the PD + */ + + ib_status = ib_dealloc_pd(h_pd,alts_pd_destroy_cb); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_dealloc_pd failed status = %s\n", ib_get_err_str(ib_status)) ); + alts_close_ca(h_ca); + break; + } + + break; //End of while + } + + if( ptr ) + cl_free( ptr ); + + /* Close AL */ + if(h_al) + alts_close_al(h_al); + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} diff --git a/branches/WOF2-3/tests/alts/dirs b/branches/WOF2-3/tests/alts/dirs new file mode 100644 index 00000000..d1917e8a --- /dev/null +++ b/branches/WOF2-3/tests/alts/dirs @@ -0,0 +1,3 @@ +DIRS=\ + user \ +# kernel diff --git a/branches/WOF2-3/tests/alts/ibquery.c b/branches/WOF2-3/tests/alts/ibquery.c new file mode 100644 index 00000000..d2f2ec55 --- /dev/null +++ b/branches/WOF2-3/tests/alts/ibquery.c @@ -0,0 +1,583 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + +/* + * Abstract: + * This test validates the ib_query API. ib_query access layer api queries + * subnet administrator on behalf of clients. + * + * + * Environment: + * All + */ + + +#include +#include +#include +#include +#include +#include + +/* + * Function prototypes + */ + +void +alts_query_cb( +IN ib_query_rec_t *p_query_rec +); +void +alts_reg_svc_cb( +IN ib_reg_svc_rec_t *p_reg_svc_rec +); +void +alts_print_port_guid( +IN ib_port_info_t *p_port_info +); +void +alts_print_node_info( + ib_node_info_t *p_node_info +); + +/* + * Globals + */ +ib_net64_t query_portguid; + +/* This test case assumes that the HCA has been configured by running + * SM. + */ +ib_api_status_t +al_test_query(void) +{ + ib_api_status_t ib_status = IB_ERROR; + ib_al_handle_t h_al = NULL; + + ib_ca_handle_t h_ca = NULL; + uint32_t bsize; + uint32_t i; + ib_ca_attr_t *p_ca_attr = NULL; + //alts_ca_object_t ca_obj; // for testing stack + ib_query_req_t query_req; + ib_port_attr_t *p_port_attr = NULL; + ib_reg_svc_req_t reg_svc_req; + ib_gid_t port_gid = {0}; + ib_net16_t pkey=0; + ib_lid_pair_t lid_pair; + ib_guid_pair_t guid_pair; + ib_gid_pair_t gid_pair; + ib_user_query_t info; + ib_path_rec_t path; + ib_reg_svc_handle_t h_reg_svc; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + do + { + /* + * Open the AL interface + */ + ib_status = alts_open_al(&h_al); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_open_al failed status = %s\n", + ib_get_err_str(ib_status)) ); + break; + } + + /* + * Default opens the first CA + */ + ib_status = alts_open_ca(h_al, &h_ca); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_open_ca failed status = %s\n", + ib_get_err_str(ib_status)) ); + break; + } + + /* + * Query the CA + */ + bsize = 0; + ib_status = ib_query_ca(h_ca, NULL, &bsize); + if(ib_status != IB_INSUFFICIENT_MEMORY) + { + ALTS_PRINT(ALTS_DBG_ERROR, + ("ib_query_ca failed with status = %s\n", + ib_get_err_str(ib_status)) ); + ib_status = IB_ERROR; + break; + } + + CL_ASSERT(bsize); + + + /* Allocate the memory needed for query_ca */ + p_ca_attr = (ib_ca_attr_t *)cl_zalloc(bsize); + if (!p_ca_attr) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("zalloc() failed for p_ca_attr!\n") ); + ib_status = IB_INSUFFICIENT_MEMORY; + break; + } + + ib_status = ib_query_ca(h_ca, p_ca_attr, &bsize); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_query_ca failed with status = %s\n", + ib_get_err_str(ib_status)) ); + break; + } + + //Get the Active port GUID + query_portguid = 0x0; + for(i=0; i< p_ca_attr->num_ports; i++) + { + p_port_attr = &p_ca_attr->p_port_attr[i]; + + if (p_port_attr->link_state == IB_LINK_ACTIVE) + { + query_portguid = p_port_attr->port_guid; + port_gid = p_port_attr->p_gid_table[0]; + pkey = p_port_attr->p_pkey_table[0]; + break; + } + } + + if(query_portguid == 0x0) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("Atlease one port need to be active\n") ); + ib_status = IB_ERROR; + break; + } + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("calling ib_query api\n")); + + +#if 1 + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("sending IB_QUERY_NODE_REC_BY_NODE_GUID\n")); + + query_req.query_type = IB_QUERY_NODE_REC_BY_NODE_GUID; + query_req.p_query_input = &p_ca_attr->ca_guid; //Node GUID + query_req.port_guid = query_portguid; + query_req.timeout_ms = 10000; //milliseconds + query_req.retry_cnt = 3; + query_req.flags = IB_FLAGS_SYNC; + query_req.query_context = NULL; + query_req.pfn_query_cb = alts_query_cb; + + ib_status = ib_query( h_al, &query_req, NULL ); + + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_query api failed with status %s\n", + ib_get_err_str(ib_status)) ); + break; + } + + cl_thread_suspend( 1000 ); + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("sending IB_QUERY_PATH_REC_BY_PORT_GUIDS\n")); + + query_req.query_type = IB_QUERY_PATH_REC_BY_PORT_GUIDS; + query_req.p_query_input = &guid_pair; //Node GUID + query_req.port_guid = query_portguid; + query_req.timeout_ms = 10000; //milliseconds + query_req.retry_cnt = 3; + query_req.flags = IB_FLAGS_SYNC; + query_req.query_context = NULL; + guid_pair.src_guid = query_portguid; + guid_pair.dest_guid = query_portguid; + query_req.pfn_query_cb = alts_query_cb; + + ib_status = ib_query( h_al, &query_req, NULL ); + + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_query api failed with status %s\n", + ib_get_err_str(ib_status)) ); + break; + } + + cl_thread_suspend( 1000 ); + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("sending IB_QUERY_PATH_REC_BY_GIDS\n")); + + query_req.query_type = IB_QUERY_PATH_REC_BY_GIDS; + query_req.p_query_input = &gid_pair; //Node GUID + query_req.port_guid = query_portguid; + query_req.timeout_ms = 10000; //milliseconds + query_req.retry_cnt = 3; + query_req.flags = IB_FLAGS_SYNC; + query_req.query_context = NULL; + ib_gid_set_default( &gid_pair.src_gid, query_portguid ); + ib_gid_set_default( &gid_pair.dest_gid, query_portguid ); + query_req.pfn_query_cb = alts_query_cb; + + ib_status = ib_query( h_al, &query_req, NULL ); + + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_query api failed with status %s\n", + ib_get_err_str(ib_status)) ); + break; + } + + cl_thread_suspend( 1000 ); + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("sending IB_QUERY_PATH_REC_BY_LIDS\n")); + + query_req.query_type = IB_QUERY_PATH_REC_BY_LIDS; + query_req.p_query_input = &lid_pair; //Node GUID + query_req.port_guid = query_portguid; + query_req.timeout_ms = 10000; //milliseconds + query_req.retry_cnt = 3; + query_req.flags = IB_FLAGS_SYNC; + query_req.query_context = NULL; + lid_pair.src_lid = p_port_attr->lid; + lid_pair.dest_lid = p_port_attr->lid; + query_req.pfn_query_cb = alts_query_cb; + + ib_status = ib_query( h_al, &query_req, NULL ); + + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_query api failed with status %s\n", + ib_get_err_str(ib_status)) ); + break; + } + + cl_thread_suspend( 1000 ); + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("sending IB_QUERY_USER_DEFINED\n")); + + query_req.query_type = IB_QUERY_USER_DEFINED; + query_req.p_query_input = &info; //Node GUID + query_req.port_guid = query_portguid; + query_req.timeout_ms = 10000; //milliseconds + query_req.retry_cnt = 3; + query_req.flags = IB_FLAGS_SYNC; + query_req.query_context = NULL; + info.method = IB_MAD_METHOD_GET; + info.attr_id = IB_MAD_ATTR_PATH_RECORD; + info.attr_size = sizeof(ib_path_rec_t); + info.comp_mask = IB_PR_COMPMASK_DLID | IB_PR_COMPMASK_SLID;// | IB_PR_COMPMASK_NUM_PATH; + info.p_attr = &path; + + cl_memclr( &path, sizeof(ib_path_rec_t) ); + path.dlid = p_port_attr->lid; + path.slid = p_port_attr->lid; + path.num_path = 0x1; + query_req.pfn_query_cb = alts_query_cb; + + ib_status = ib_query( h_al, &query_req, NULL ); + + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_query api failed with status %s\n", + ib_get_err_str(ib_status)) ); + break; + } + + cl_thread_suspend( 1000 ); + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("registering a service with the SA\n")); + + cl_memclr( ®_svc_req, sizeof( ib_reg_svc_req_t ) ); + + reg_svc_req.svc_rec.service_id = 0x52413; + reg_svc_req.svc_rec.service_gid = port_gid; + reg_svc_req.svc_rec.service_pkey = pkey; + reg_svc_req.svc_rec.service_lease = 0xFFFFFFFF; + //reg_svc_req.svc_rec.service_key[16]; + strcpy( (char*)reg_svc_req.svc_rec.service_name, "alts" ); + reg_svc_req.svc_data_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; + + reg_svc_req.port_guid = query_portguid; + reg_svc_req.timeout_ms = 10000; + reg_svc_req.retry_cnt = 3; + reg_svc_req.flags = IB_FLAGS_SYNC; + reg_svc_req.svc_context = NULL; + reg_svc_req.pfn_reg_svc_cb = alts_reg_svc_cb; + + ib_status = ib_reg_svc( h_al, ®_svc_req, &h_reg_svc ); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_reg_svc api failed with status %s\n", + ib_get_err_str(ib_status)) ); + break; + } + + /* + * Note we leave this registration registered + * and let ib_close_al clean it up + */ + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("registering a service with the SA\n")); + + cl_memclr( ®_svc_req, sizeof( ib_reg_svc_req_t ) ); + + reg_svc_req.svc_rec.service_id = 0x52413; + reg_svc_req.svc_rec.service_gid = port_gid; + reg_svc_req.svc_rec.service_pkey = pkey; + reg_svc_req.svc_rec.service_lease = 0xFFFFFFFF; + //reg_svc_req.svc_rec.service_key[16]; + strcpy( (char*)reg_svc_req.svc_rec.service_name, "alts" ); + reg_svc_req.svc_data_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; + + reg_svc_req.port_guid = query_portguid; + reg_svc_req.timeout_ms = 10000; + reg_svc_req.retry_cnt = 3; + reg_svc_req.flags = IB_FLAGS_SYNC; + reg_svc_req.svc_context = NULL; + reg_svc_req.pfn_reg_svc_cb = alts_reg_svc_cb; + + ib_status = ib_reg_svc( h_al, ®_svc_req, &h_reg_svc ); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_reg_svc api failed with status %s\n", + ib_get_err_str(ib_status)) ); + break; + } + + ib_status = ib_dereg_svc( h_reg_svc, ib_sync_destroy ); + if( ib_status != IB_SUCCESS ) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_dereg_svc api failed with status %s\n", + ib_get_err_str(ib_status)) ); + break; + } +#endif + + }while (0); + + if( p_ca_attr ) + cl_free( p_ca_attr ); + + if( h_al ) + alts_close_al( h_al ); + + ALTS_EXIT( ALTS_DBG_VERBOSE); + + return ib_status; + +} + + +void +alts_print_port_guid( +ib_port_info_t *p_port_info) +{ + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + UNUSED_PARAM( p_port_info ); + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("ib_port_attr_t info:\n" + "\tsubnet_timeout...:x%x\n" + "\tlocal_port_num....:x%x\n" + "\tmtu_smsl.........:x%x\n" + "\tbase_lid.........:x%x\n", + p_port_info->subnet_timeout, + p_port_info->local_port_num, + p_port_info->mtu_smsl, + p_port_info->base_lid + )); + + ALTS_EXIT( ALTS_DBG_VERBOSE); + +} + +void +alts_print_node_info( + ib_node_info_t *p_node_info +) +{ + UNUSED_PARAM( p_node_info ); + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("alts_print_node_info info:\n" + "\tnode_type...:x%x\n" + "\tnum_ports....:x%x\n" + "\tnode_guid.........:x%"PRIx64"\n" + "\tport_guid.........:x%"PRIx64"\n", + p_node_info->node_type, + p_node_info->num_ports, + p_node_info->node_guid, + p_node_info->port_guid + )); +} + +void +alts_query_cb( +IN ib_query_rec_t *p_query_rec +) +{ + uint32_t i; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("ib_query_rec_t info:\n" + "\tstatus...:x%x\n" + "\tquery_type...:x%x\n", + p_query_rec->status, + p_query_rec->query_type + )); + + if(p_query_rec->status == IB_SUCCESS) + { + ib_node_record_t * p_node_rec; + + switch(p_query_rec->query_type) + { +#if 1 + case IB_QUERY_NODE_REC_BY_NODE_GUID: + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("returning IB_QUERY_NODE_REC_BY_NODE_GUID\n")); + for( i=0; iresult_cnt; i++ ) + { + p_node_rec = (ib_node_record_t *)ib_get_query_result( + p_query_rec->p_result_mad, i ); + alts_print_node_info(&p_node_rec->node_info); + } + break; + + case IB_QUERY_PATH_REC_BY_PORT_GUIDS: + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("returning IB_QUERY_PATH_REC_BY_PORT_GUIDS\n")); + break; + + case IB_QUERY_PATH_REC_BY_GIDS: + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("returning IB_QUERY_PATH_REC_BY_GIDS\n")); + break; + + case IB_QUERY_PATH_REC_BY_LIDS: + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("returning IB_QUERY_PATH_REC_BY_LIDS\n")); + break; + + case IB_QUERY_USER_DEFINED: + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("returning IB_QUERY_USER_DEFINED\n")); + break; + + +#endif + break; + + default: + break; + + } + } + else + { + ALTS_PRINT(ALTS_DBG_ERROR, + ("p_query_rec->status failed\n")); + } + + if( p_query_rec->p_result_mad ) + ib_put_mad( p_query_rec->p_result_mad ); + + ALTS_EXIT( ALTS_DBG_VERBOSE); +} + + + +void +alts_dereg_svc_cb( + IN void *context ) +{ + UNUSED_PARAM( context ); + ALTS_ENTER( ALTS_DBG_VERBOSE ); + ALTS_PRINT( ALTS_DBG_VERBOSE, ("ib_dereg_svc done\n") ); + ALTS_EXIT( ALTS_DBG_VERBOSE); +} + + +void +alts_reg_svc_cb( + IN ib_reg_svc_rec_t *p_reg_svc_rec ) +{ + ALTS_ENTER( ALTS_DBG_VERBOSE ); + +#if defined( CL_KERNEL ) && !defined( _DEBUG_ ) + UNUSED_PARAM( p_reg_svc_rec ); +#endif + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("ib_reg_svc_rec_t info:\n" + "\treq_status...:x%x\n" + "\tresp_status...:x%x\n", + p_reg_svc_rec->req_status, + p_reg_svc_rec->resp_status + )); + + ALTS_EXIT( ALTS_DBG_VERBOSE); +} diff --git a/branches/WOF2-3/tests/alts/kernel/SOURCES b/branches/WOF2-3/tests/alts/kernel/SOURCES new file mode 100644 index 00000000..e78ba363 --- /dev/null +++ b/branches/WOF2-3/tests/alts/kernel/SOURCES @@ -0,0 +1,38 @@ +TARGETNAME=alts +TARGETPATH=..\..\..\bin\kernel\obj$(BUILD_ALT_DIR) +TARGETTYPE=DRIVER + +SOURCES= alts.rc \ + alts_driver.c \ + ..\allocdeallocpd.c \ + ..\alts_misc.c \ + ..\cmtests.c \ + ..\createanddestroycq.c \ + ..\createdestroyav.c \ + ..\creatememwindow.c \ + ..\ibquery.c \ + ..\madtests.c \ + ..\multisendrecv.c \ + ..\openclose.c \ + ..\querycaattr.c \ + ..\registermemregion.c \ + ..\registerpnp.c \ + ..\smatests.c + +INCLUDES=..\..\..\inc;..\..\..\inc\kernel;.. + +C_DEFINES=$(C_DEFINES) -DDRIVER -DDEPRECATE_DDK_FUNCTIONS + +TARGETLIBS= \ + $(TARGETPATH)\*\complib.lib \ + $(TARGETPATH)\*\ibal.lib + +!if !defined(DDK_TARGET_OS) || "$(DDK_TARGET_OS)"=="Win2K" +# +# The driver is built in the Win2K build environment +# - use the library version of safe strings +# +TARGETLIBS= $(TARGETLIBS) $(DDK_LIB_PATH)\ntstrsafe.lib +!endif + +MSC_WARNING_LEVEL= /W4 /wd4127 diff --git a/branches/WOF2-3/tests/alts/kernel/alts.inf b/branches/WOF2-3/tests/alts/kernel/alts.inf new file mode 100644 index 00000000..84b7cffc --- /dev/null +++ b/branches/WOF2-3/tests/alts/kernel/alts.inf @@ -0,0 +1,169 @@ +;/*++ +; +;Copyright 2004 InfiniCon Systems, Inc. All Rights Reserved. +; +;Module Name: +; +; infinihost.inf +; +;Abstract: +; +; INF file for installing the InfiniCon InfiniBand HCAs. +; +;Author: +; +; InfiniCon Systems, Inc +; +;REVISION: +; +; $Revision$ +; +;--*/ + +[Version] +Signature="$Windows NT$" +Class=InfiniBandHca +ClassGUID=%HcaClassGuid% +Provider=%Vendor% +CatalogFile=infiniserv.cat +DriverVer=03/08/2006,1.0.0000.614 + +; ================= Destination directory section ===================== + +[DestinationDirs] +DefaultDestDir=12 +ClassCopyFiles=11 +;MT23108UMCopyFiles=11 +; add additional HCA user-mode section names here. + +; ================= Class Install section ===================== + +[ClassInstall32] +CopyFiles=ClassCopyFiles +AddReg=ClassAddReg + +[ClassCopyFiles] +IbInstaller.dll + +[ClassAddReg] +HKR,,,,"InfiniBand Host Channel Adapters" +HKR,,Icon,,-5 +HKLM,"System\CurrentControlSet\Control\CoDeviceInstallers", \ + %HcaClassGuid%,%REG_MULTI_SZ_APPEND%, "IbInstaller.dll,IbCoInstaller" + +; ================= Device Install section ===================== + +[SourceDisksNames] +1=%DiskId% + +[SourceDisksFiles.x86] +IbInstaller.dll=1 +complib.sys=1 +ibal.sys=1 +mt23108.sys=1 +thca.sys=1 +alts.sys=1 + +[Manufacturer] +%Vendor% = INFINICON_SYS,nt + +[INFINICON_SYS] +; empty since we don't support W9x/Me + +[INFINICON_SYS.nt] +%MT23108.DeviceDesc% = MT23108.Install.nt,PCI\VEN_15B3&DEV_5A44 +; add additional devices here. + +[MT23108.Install.nt] +CopyFiles = MT23108.CopyFiles + +[MT23108.Install.nt.HW] +AddReg = MT23108.FiltersReg + +[MT23108.Install.nt.Services] +AddService = thca,%SPSVCINST_NULL%,THCA.ServiceInstall +AddService = alts,%SPSVCINST_NULL%,ALTS.ServiceInstall +AddService = mt23108,%SPSVCINST_ASSOCSERVICE%,MT23108.ServiceInstall +AddService = ibal,%SPSVCINST_NULL%,Ibal.ServiceInstall + +[MT23108.CopyFiles] +complib.sys +ibal.sys +mt23108.sys +thca.sys +alts.sys + +; +; ============= Service Install section ============== +; + +[MT23108.ServiceInstall] +DisplayName = %MT23108.ServiceDesc% +ServiceType = %SERVICE_KERNEL_DRIVER% +StartType = %SERVICE_DEMAND_START% +ErrorControl = %SERVICE_ERROR_NORMAL% +ServiceBinary = %12%\mt23108.sys +LoadOrderGroup = extended base +AddReg = MT23108.ParamsReg + +[THCA.ServiceInstall] +DisplayName = %THCA.ServiceDesc% +ServiceType = %SERVICE_KERNEL_DRIVER% +StartType = %SERVICE_DEMAND_START% +ErrorControl = %SERVICE_ERROR_NORMAL% +ServiceBinary = %12%\thca.sys +LoadOrderGroup = extended base +AddReg = THCA.ParamsReg + +[ALTS.ServiceInstall] +DisplayName = %ALTS.ServiceDesc% +ServiceType = %SERVICE_KERNEL_DRIVER% +StartType = %SERVICE_DEMAND_START% +ErrorControl = %SERVICE_ERROR_NORMAL% +ServiceBinary = %12%\alts.sys +LoadOrderGroup = extended base + +[Ibal.ServiceInstall] +DisplayName = %Ibal.ServiceDesc% +ServiceType = %SERVICE_KERNEL_DRIVER% +StartType = %SERVICE_DEMAND_START% +ErrorControl = %SERVICE_ERROR_NORMAL% +ServiceBinary = %12%\ibal.sys +AddReg = Ibal.ParamsReg + +[MT23108.FiltersReg] +HKR,,"UpperFilters", 0x00010000,"thca","alts" + +[MT23108.ParamsReg] +HKR,"Parameters","DebugFlags",%REG_DWORD%,0xFFFFFFFF +HKR,"Parameters","ConfAddr",%REG_DWORD%,88 +HKR,"Parameters","ConfData",%REG_DWORD%,92 +HKR,"Parameters","DdrMapOffset",%REG_DWORD%,0x100000 +HKR,"Parameters","DdrMapSize",%REG_DWORD%,0x1600000 +HKR,"Parameters","UseIbMgt",%REG_DWORD%,1 +HKR,"Parameters","ThhLegacySqp",%REG_DWORD%,0 +HKR,"Parameters","ResetCard",%REG_DWORD%,0 + +[THCA.ParamsReg] +HKR,"Parameters","DebugFlags",%REG_DWORD%,0x80000000 + +[Ibal.ParamsReg] +HKR,"Parameters","DebugFlags",%REG_DWORD_NO_CLOBBER%,0x80000000 + +[Strings] +HcaClassGuid = "{58517E00-D3CF-40c9-A679-CEE5752F4491}" +Vendor = "InfiniCon Systems, Inc." +MT23108.DeviceDesc = "InfiniCon MT23108 InfiniBand HCA Test" +MT23108.ServiceDesc = "InfiniCon MT23108 InfiniBand HCA Driver" +THCA.ServiceDesc = "InfiniCon MT23108 HCA VPD for IBAL" +ALTS.ServiceDesc = "InfiniCon Access Layer Test Suite Driver" +Ibal.ServiceDesc = "InfiniCon InfiniBand Access Layer" +DiskId = "InfiniCon InfiniBand HCA installation disk" +SPSVCINST_NULL = 0x0 +SPSVCINST_ASSOCSERVICE = 0x00000002 +SERVICE_KERNEL_DRIVER = 1 +SERVICE_DEMAND_START = 3 +SERVICE_ERROR_NORMAL = 1 +REG_DWORD = 0x00010001 +REG_DWORD_NO_CLOBBER = 0x00010003 +REG_MULTI_SZ_APPEND = 0x00010008 diff --git a/branches/WOF2-3/tests/alts/kernel/alts.rc b/branches/WOF2-3/tests/alts/kernel/alts.rc new file mode 100644 index 00000000..0b0ca481 --- /dev/null +++ b/branches/WOF2-3/tests/alts/kernel/alts.rc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef _DEBUG_ +#define VER_FILEDESCRIPTION_STR "InfiniBand Access Layer Test Driver (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "InfiniBand Access Layer Test Driver" +#endif + +#define VER_INTERNALNAME_STR "alts.sys" +#define VER_ORIGINALFILENAME_STR "alts.sys" + +#include diff --git a/branches/WOF2-3/tests/alts/kernel/alts_driver.c b/branches/WOF2-3/tests/alts/kernel/alts_driver.c new file mode 100644 index 00000000..f16ad350 --- /dev/null +++ b/branches/WOF2-3/tests/alts/kernel/alts_driver.c @@ -0,0 +1,346 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * Provides the driver entry points for the ALTS kernel driver. + */ + + +#include +#include +#include +#include "alts_common.h" +#include "alts_debug.h" +#include + + +#if !defined(FILE_DEVICE_INFINIBAND) // Not defined in WXP DDK +#define FILE_DEVICE_INFINIBAND 0x0000003B +#endif + +uint32_t alts_dbg_lvl = ALTS_DBG_ERROR | ALTS_DBG_STATUS; + + +NTSTATUS +DriverEntry( + IN DRIVER_OBJECT *p_driver_obj, + IN UNICODE_STRING *p_registry_path ); + +static void +alts_drv_unload( + IN DRIVER_OBJECT *p_driver_obj ); + +//static NTSTATUS +//alts_ioctl( +// IN DEVICE_OBJECT *p_dev_obj, +// IN IRP *p_irp ); + +static NTSTATUS +alts_sysctl( + IN DEVICE_OBJECT *p_dev_obj, + IN IRP *p_irp ); + +static NTSTATUS +alts_add_device( + IN DRIVER_OBJECT *p_driver_obj, + IN DEVICE_OBJECT *p_pdo ); + +static NTSTATUS +alts_start_tests( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ); + +static void +alts_release_resources( + IN DEVICE_OBJECT* const p_dev_obj ); + + + +static const cl_vfptr_pnp_po_t alts_vfptr_pnp = { + "ALTS", + alts_start_tests, // StartDevice + cl_irp_skip, + cl_irp_skip, + cl_irp_skip, + cl_irp_skip, // QueryRemove + alts_release_resources, + cl_do_remove, // Remove + cl_irp_skip, // CancelRemove + cl_irp_skip, // SurpriseRemove + cl_irp_skip, + cl_irp_skip, + cl_irp_skip, + cl_irp_skip, + cl_irp_skip, + cl_irp_ignore, + cl_irp_ignore, + cl_irp_ignore, + cl_irp_ignore, + cl_irp_ignore, + cl_irp_ignore, + cl_irp_ignore, + cl_irp_ignore, + cl_irp_ignore, + cl_irp_ignore, + cl_irp_ignore, + cl_irp_ignore, + cl_irp_ignore, // QueryPower + cl_irp_ignore, // SetPower + cl_irp_ignore, // PowerSequence + cl_irp_ignore // WaitWake +}; + + +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT p_driver_obj, + IN PUNICODE_STRING p_registry_path ) +{ + NTSTATUS status; +#ifdef _DEBUG_ + static boolean_t exit = FALSE; +#endif + + ALTS_ENTER( ALTS_DBG_DEV ); + + UNUSED_PARAM( p_registry_path ); + +#ifdef _DEBUG_ + DbgBreakPoint(); + if( exit ) + { + ALTS_TRACE_EXIT( ALTS_DBG_DEV, ("Load aborted.\n") ); + return STATUS_DRIVER_INTERNAL_ERROR; + } +#endif + + status = CL_INIT; + if( !NT_SUCCESS(status) ) + { + ALTS_TRACE_EXIT( ALTS_DBG_ERROR, + ("cl_init returned %08X.\n", status) ); + return status; + } + + p_driver_obj->MajorFunction[IRP_MJ_PNP] = cl_pnp; + p_driver_obj->MajorFunction[IRP_MJ_POWER] = cl_power; +// p_driver_obj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = alts_ioctl; + p_driver_obj->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = alts_sysctl; + p_driver_obj->DriverUnload = alts_drv_unload; + p_driver_obj->DriverExtension->AddDevice = alts_add_device; + + ALTS_EXIT( ALTS_DBG_DEV ); + return STATUS_SUCCESS; +} + + +static void +alts_drv_unload( + IN PDRIVER_OBJECT p_driver_obj ) +{ + ALTS_ENTER( ALTS_DBG_DEV ); + + UNUSED_PARAM( p_driver_obj ); + + CL_DEINIT; + + ALTS_EXIT( ALTS_DBG_DEV ); +} + + +//static NTSTATUS +//alts_ioctl( +// IN DEVICE_OBJECT *p_dev_obj, +// IN IRP *p_irp ) +//{ +// +//} + + +static NTSTATUS +alts_sysctl( + IN DEVICE_OBJECT *p_dev_obj, + IN IRP *p_irp ) +{ + NTSTATUS status; + cl_pnp_po_ext_t *p_ext; + + ALTS_ENTER( ALTS_DBG_DEV ); + + p_ext = p_dev_obj->DeviceExtension; + + IoSkipCurrentIrpStackLocation( p_irp ); + status = IoCallDriver( p_ext->p_next_do, p_irp ); + + ALTS_EXIT( ALTS_DBG_DEV ); + return status; +} + + +static NTSTATUS +alts_add_device( + IN DRIVER_OBJECT *p_driver_obj, + IN DEVICE_OBJECT *p_pdo ) +{ + NTSTATUS status; + DEVICE_OBJECT *p_dev_obj, *p_next_do; + + ALTS_ENTER( ALTS_DBG_PNP ); + + /* + * Create the device so that we have a device extension to store stuff in. + */ + status = IoCreateDevice( p_driver_obj, sizeof(cl_pnp_po_ext_t), + NULL, FILE_DEVICE_INFINIBAND, FILE_DEVICE_SECURE_OPEN, + FALSE, &p_dev_obj ); + if( !NT_SUCCESS( status ) ) + { + ALTS_TRACE_EXIT( ALTS_DBG_ERROR, + ("IoCreateDevice returned 0x%08X.\n", status) ); + return status; + } + + /* Attach to the device stack. */ + p_next_do = IoAttachDeviceToDeviceStack( p_dev_obj, p_pdo ); + if( !p_next_do ) + { + IoDeleteDevice( p_dev_obj ); + ALTS_TRACE_EXIT( ALTS_DBG_ERROR, + ("IoAttachDeviceToDeviceStack failed.\n") ); + return STATUS_NO_SUCH_DEVICE; + } + + /* Inititalize the complib extension. */ + cl_init_pnp_po_ext( p_dev_obj, p_next_do, p_pdo, alts_dbg_lvl, + &alts_vfptr_pnp, NULL ); + + ALTS_EXIT( ALTS_DBG_PNP ); + return status; +} + + +static NTSTATUS +alts_start_tests( + IN DEVICE_OBJECT* const p_dev_obj, + IN IRP* const p_irp, + OUT cl_irp_action_t* const p_action ) +{ + NTSTATUS status; + ib_api_status_t ib_status; + + status = cl_do_sync_pnp( p_dev_obj, p_irp, p_action ); + if( !NT_SUCCESS( status ) ) + return status; + + /* Wait 10 seconds for LIDs to get assigned. */ + cl_thread_suspend( 60000 ); + + /* We're started. Launch the tests. */ + ib_status = al_test_openclose(); + ALTS_TRACE( ALTS_DBG_STATUS, + ("\nOpenClose returned %s\n\n", ib_get_err_str( ib_status )) ); + + ib_status = al_test_querycaattr(); + ALTS_TRACE( ALTS_DBG_STATUS, + ("\nQueryCAAttribute returned %s\n\n", ib_get_err_str( ib_status )) ); + + ib_status = al_test_modifycaattr(); + ALTS_TRACE( ALTS_DBG_STATUS, + ("\nModifyCAAttribute returned %s\n\n", ib_get_err_str( ib_status )) ); + + ib_status = al_test_alloc_dealloc_pd(); + ALTS_TRACE( ALTS_DBG_STATUS, + ("\nAllocDeallocPD returned %s\n\n", ib_get_err_str( ib_status )) ); + + ib_status = al_test_create_destroy_av(); + ALTS_TRACE( ALTS_DBG_STATUS, + ("\nCreateDestroyAV returned %s\n\n", ib_get_err_str( ib_status )) ); + + ib_status = al_test_query_modify_av(); + ALTS_TRACE( ALTS_DBG_STATUS, + ("\nQueryAndModifyAV returned %s\n\n", ib_get_err_str( ib_status )) ); + + ib_status = al_test_create_destroy_cq(); + ALTS_TRACE( ALTS_DBG_STATUS, + ("\nCreateAndDestroyCQ returned %s\n\n", ib_get_err_str( ib_status )) ); + + ib_status = al_test_query_modify_cq(); + ALTS_TRACE( ALTS_DBG_STATUS, + ("\nQueryAndModifyCQ returned %s\n\n", ib_get_err_str( ib_status )) ); + + ib_status = al_test_register_mem(); + ALTS_TRACE( ALTS_DBG_STATUS, + ("\nRegisterMemRegion returned %s\n\n", ib_get_err_str( ib_status )) ); + + ib_status = al_test_register_phys_mem(); + ALTS_TRACE( ALTS_DBG_STATUS, + ("\nRegisterPhyMemRegion returned %s\n\n", ib_get_err_str( ib_status )) ); + + ib_status = al_test_create_mem_window(); + ALTS_TRACE( ALTS_DBG_STATUS, + ("\nCreateMemWindow returned %s\n\n", ib_get_err_str( ib_status )) ); + + ib_status = al_test_register_shared_mem(); + ALTS_TRACE( ALTS_DBG_STATUS, + ("\nRegisterSharedMemRegion returned %s\n\n", ib_get_err_str( ib_status )) ); + + ib_status = al_test_multi_send_recv(); + ALTS_TRACE( ALTS_DBG_STATUS, + ("\nMultiSend returned %s\n\n", ib_get_err_str( ib_status )) ); + + ib_status = al_test_register_pnp(); + ALTS_TRACE( ALTS_DBG_STATUS, + ("\nRegisterPnP returned %s\n\n", ib_get_err_str( ib_status )) ); + + ib_status = al_test_mad(); + ALTS_TRACE( ALTS_DBG_STATUS, + ("\nMadTests returned %s\n\n", ib_get_err_str( ib_status )) ); + + ib_status = al_test_query(); + ALTS_TRACE( ALTS_DBG_STATUS, + ("\nMadQuery returned %s\n\n", ib_get_err_str( ib_status )) ); + + ib_status = al_test_cm(); + ALTS_TRACE( ALTS_DBG_STATUS, + ("\nCmTests returned %s\n\n", ib_get_err_str( ib_status )) ); + + return status; +} + + +static void +alts_release_resources( + IN DEVICE_OBJECT* const p_dev_obj ) +{ + UNUSED_PARAM( p_dev_obj ); +} diff --git a/branches/WOF2-3/tests/alts/kernel/alts_driver.h b/branches/WOF2-3/tests/alts/kernel/alts_driver.h new file mode 100644 index 00000000..1b097345 --- /dev/null +++ b/branches/WOF2-3/tests/alts/kernel/alts_driver.h @@ -0,0 +1,23 @@ +/* BEGIN_ICS_COPYRIGHT **************************************** +** END_ICS_COPYRIGHT ****************************************/ + + + +#if !defined( _ALTS_DRIVER_H_ ) +#define _ALTS_DRIVER_H_ + + +#include +#include +#include +#include "alts_debug.h" + + +typedef struct _alts_dev_ext +{ + cl_pnp_po_ext_t cl_ext; + +} alts_dev_ext_t; + + +#endif /* !defined( _ALTS_DRIVER_H_ ) */ diff --git a/branches/WOF2-3/tests/alts/kernel/makefile b/branches/WOF2-3/tests/alts/kernel/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-3/tests/alts/kernel/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\inc\openib.def diff --git a/branches/WOF2-3/tests/alts/madtests.c b/branches/WOF2-3/tests/alts/madtests.c new file mode 100644 index 00000000..043b5311 --- /dev/null +++ b/branches/WOF2-3/tests/alts/madtests.c @@ -0,0 +1,3035 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + +/* + * Abstract: + * mad test does a data transfer between two queue pairs created one + * on each port of the hca. In order for this test to work, two ports of the hca + * should be connected in a loop back and must be configured to ACTIVE PORT STATE. + * + * + * Environment: + * All + */ + + +#include +#include +#include +#include +#include +#include + +/* Parameters */ + +#define TestUD1 1 +#define TestRC1 2 + +#define MAX_QPS 8 +#define SRC_QP 0 +#define DEST_QP 1 + + +typedef struct _alts_mad_ca_obj +{ + ib_api_status_t status; + uint32_t test_type; + + ib_ca_handle_t h_ca; + ib_ca_attr_t *p_ca_attr; + ib_port_attr_t *p_src_port_attr; + ib_port_attr_t *p_dest_port_attr; + + ib_net32_t src_qp_num; + ib_net32_t dest_qp_num; + + ib_net64_t src_portguid; + uint8_t src_port_num; + + ib_net64_t dest_portguid; + uint8_t dest_port_num; + + ib_net16_t slid; + ib_net16_t dlid; + + ib_pool_key_t h_src_pool; + ib_pool_key_t h_dest_pool; + + ib_mad_svc_handle_t h_src_mad_svc; + ib_mad_svc_handle_t h_dest_mad_svc; + + ib_cq_handle_t h_cq; + uint32_t cq_size; + + ib_pd_handle_t h_pd; + + ib_qp_handle_t h_qp[MAX_QPS]; + uint32_t qkey; + + ib_qp_attr_t qp_attr[MAX_QPS]; + + + ib_send_wr_t *p_send_wr; + ib_recv_wr_t *p_recv_wr; + size_t wr_send_size; + size_t wr_recv_size; + uint32_t num_wrs; + uint32_t ds_list_depth; + uint32_t msg_size; // Initialize this field + + ib_av_handle_t h_av_src; + ib_av_handle_t h_av_dest; + + uint32_t send_done; + uint32_t send_done_error; + uint32_t recv_done; + uint32_t recv_done_error; + uint32_t cq_done; // total completions + boolean_t is_src; + + boolean_t is_loopback; + boolean_t reply_requested; + +} alts_mad_ca_obj_t; + + + +/* + * Function Prototypes + */ + +ib_api_status_t +alts_mad_check_active_ports( + alts_mad_ca_obj_t *p_ca_obj ); + +ib_api_status_t +mad_create_resources( + alts_mad_ca_obj_t *p_ca_obj ); + +ib_api_status_t +mad_activate_svc( + alts_mad_ca_obj_t *p_ca_obj, + ib_qp_handle_t h_qp ); + +ib_api_status_t +alts_spl_destroy_resources( + alts_mad_ca_obj_t *p_ca_obj ); + +ib_api_status_t +mad_post_sends( + alts_mad_ca_obj_t *p_ca_obj, + uint32_t reg_index, + uint32_t num_post ); + +ib_api_status_t +mad_post_recvs( + alts_mad_ca_obj_t *p_ca_obj, + uint32_t reg_index, + uint32_t num_post ); + +void +mad_cq_destroy_cb( + void *context ); + +void +mad_pd_destroy_cb( + void *context ); + +void +mad_qp_destroy_cb( + void *context ); + +/* + * CQ completion callback function + */ + +void +mad_cq_comp_cb( + IN const ib_cq_handle_t h_cq, + IN void *cq_context ); + +/* + * CQ Error callback function + */ + +void +mad_cq_err_cb( + ib_async_event_rec_t *p_err_rec ); + +/* + * QP Error callback function + */ +void +mad_qp_err_cb( + ib_async_event_rec_t *p_err_rec ); + +void +mad_svc_send_cb( + IN const ib_mad_svc_handle_t h_mad_svc, + IN void *mad_svc_context, + IN ib_mad_element_t *p_mad_element ); + +void +mad_svc_recv_cb( + IN const ib_mad_svc_handle_t h_mad_svc, + IN void *mad_svc_context, + IN ib_mad_element_t *p_mad_element ); + +void +mad_svc_qp0_recv_cb( + IN const ib_mad_svc_handle_t h_mad_svc, + IN void *mad_svc_context, + IN ib_mad_element_t *p_mad_element ); + +ib_api_status_t +alts_qp1_loopback( + ib_ca_handle_t h_ca, + uint32_t ca_attr_size ); + +ib_api_status_t +alts_qp1_2_ports( + ib_ca_handle_t h_ca, + uint32_t ca_attr_size ); + +ib_api_status_t +alts_qp1_2_ports_100( + ib_ca_handle_t h_ca, + uint32_t ca_attr_size ); + +ib_api_status_t +alts_qp1_pingpong( + ib_ca_handle_t h_ca, + uint32_t ca_attr_size ); + +ib_api_status_t +alts_qp0_loopback( + ib_ca_handle_t h_ca, + uint32_t ca_attr_size ); + +ib_api_status_t +alts_qp0_2_ports( + ib_ca_handle_t h_ca, + uint32_t ca_attr_size ); + +ib_api_status_t +alts_qp0_2_ports_100( + ib_ca_handle_t h_ca, + uint32_t ca_attr_size ); + +ib_api_status_t +alts_qp0_pingpong( + ib_ca_handle_t h_ca, + uint32_t ca_attr_size ); + +ib_api_status_t +alts_qp0_ping_switch ( + ib_ca_handle_t h_ca, + uint32_t ca_attr_size ); + +#define ALTS_TEST_MGMT_CLASS 0x56 +#define ALTS_TEST_MGMT_CLASS_VER 1 +#define ALTS_TEST_MGMT_METHOD 0x56 + +/* + * Gloabal Variables + */ +ib_al_handle_t h_al; +ib_dgrm_info_t dgrm_info; +ib_mad_svc_t mad_svc; +ib_send_wr_t send_wr; +ib_recv_wr_t recv_wr; + +extern ib_cq_create_t cq_create_attr; +extern ib_qp_create_t qp_create_attr; +extern ib_av_attr_t av_attr; +extern ib_wc_t free_wclist; +extern ib_wc_t free_wcl; + +ib_api_status_t qp1_loopback=IB_NOT_FOUND, qp1_2_ports=IB_NOT_FOUND; +ib_api_status_t qp1_2_ports_100=IB_NOT_FOUND, qp1_pingpong=IB_NOT_FOUND; + +ib_api_status_t qp0_loopback=IB_NOT_FOUND, qp0_2_ports=IB_NOT_FOUND; +ib_api_status_t qp0_2_ports_100=IB_NOT_FOUND, qp0_pingpong=IB_NOT_FOUND; + +ib_api_status_t qp0_ping_switch=IB_NOT_FOUND; + + +/* This test case assumes that the HCA has 2 port connected + * through the switch. Sends packets from lower port number to higher + * port number. + */ +ib_api_status_t +al_test_mad(void) +{ + ib_api_status_t ib_status = IB_ERROR; + ib_ca_handle_t h_ca = NULL; + uint32_t bsize; + ib_ca_attr_t *p_ca_attr = NULL; + //alts_mad_ca_obj_t ca_obj; // for testing stack + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + do + { + /* + * Open the AL interface + */ + h_al = NULL; + ib_status = alts_open_al(&h_al); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_open_al failed status = %d", ib_status) ); + break; + } + + /* + * Default opens the first CA + */ + ib_status = alts_open_ca(h_al, &h_ca); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_open_ca failed status = %d", ib_status) ); + break; + } + + /* + * Get the CA Attributest + * Check for two active ports + */ + + /* + * Query the CA + */ + bsize = 0; + ib_status = ib_query_ca(h_ca, NULL, &bsize); + if(ib_status != IB_INSUFFICIENT_MEMORY) + { + ALTS_PRINT(ALTS_DBG_ERROR, + ("ib_query_ca failed with status = %d\n", ib_status) ); + break; + } + + CL_ASSERT(bsize); + + // run tests + qp1_loopback = alts_qp1_loopback(h_ca, bsize); + if(qp1_loopback != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("qp1_loopback() failed with status %d\n", qp1_loopback)); + break; + } + ALTS_PRINT( ALTS_DBG_VERBOSE, + ("qp1_loopback() passed\n")); + + qp1_2_ports = alts_qp1_2_ports(h_ca, bsize); + if(qp1_2_ports != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_qp1_2_ports() failed with status %d\n", qp1_2_ports)); + break; + } + ALTS_PRINT( ALTS_DBG_VERBOSE, + ("alts_qp1_2_ports() passed\n")); + + qp1_2_ports_100 = alts_qp1_2_ports_100(h_ca, bsize); + if(qp1_2_ports_100 != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_qp1_2_ports_100() failed with status %d\n", + qp1_2_ports_100)); + break; + } + ALTS_PRINT( ALTS_DBG_VERBOSE, + ("alts_qp1_2_ports_100() passed\n")); + + qp1_pingpong = alts_qp1_pingpong(h_ca, bsize); + if(qp1_pingpong != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_qp1_pingpong() failed with status %d\n", + qp1_pingpong)); + //break; + } + else + { + ALTS_PRINT( ALTS_DBG_VERBOSE, + ("alts_qp1_pingpong() passed\n")); + } + + // run tests + qp0_loopback = alts_qp0_loopback(h_ca, bsize); + if(qp0_loopback != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("qp0_loopback() failed with status %d\n", qp0_loopback)); + break; + } + ALTS_PRINT( ALTS_DBG_VERBOSE, + ("qp0_loopback() passed\n")); + + qp0_2_ports = alts_qp0_2_ports(h_ca, bsize); + if(qp0_2_ports != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_qp0_2_ports() failed with status %d\n", qp0_2_ports)); + break; + } + ALTS_PRINT( ALTS_DBG_VERBOSE, + ("alts_qp0_2_ports() passed\n")); + + qp0_2_ports_100 = alts_qp0_2_ports_100(h_ca, bsize); + if(qp0_2_ports_100 != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_qp0_2_ports_100() failed with status %d\n", + qp0_2_ports_100)); + break; + } + ALTS_PRINT( ALTS_DBG_VERBOSE, + ("alts_qp0_2_ports_100() passed\n")); + + qp0_pingpong = alts_qp0_pingpong(h_ca, bsize); + if(qp0_pingpong != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_qp0_pingpong() failed with status %d\n", + qp0_pingpong)); + //break; + } + else + { + ALTS_PRINT( ALTS_DBG_VERBOSE, + ("alts_qp0_pingpong() passed\n")); + } + + qp0_ping_switch = alts_qp0_ping_switch(h_ca, bsize); + if(qp0_ping_switch != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_qp0_ping_switch() failed with status %d\n", + qp0_ping_switch)); + //break; + } + else + { + ALTS_PRINT( ALTS_DBG_VERBOSE, + ("alts_qp0_ping_switch() passed\n")); + } + + } while (0); + + /* + * Destroy the resources + */ + if (p_ca_attr) + cl_free(p_ca_attr); + + ALTS_PRINT(ALTS_DBG_STATUS, + ("Test results (mad):\n" + "\tqp1_loopback..........: %s\n" + "\tqp1_2_ports...........: %s\n" + "\tqp1_2_ports_100_msgs..: %s\n" + "\tqp1_pingpong..........: %s\n", + ib_get_err_str(qp1_loopback), + ib_get_err_str(qp1_2_ports), + ib_get_err_str(qp1_2_ports_100), + ib_get_err_str(qp1_pingpong) + )); + + ALTS_PRINT(ALTS_DBG_STATUS, + ( + "\tqp0_loopback..........: %s\n" + "\tqp0_2_ports...........: %s\n" + "\tqp0_2_ports_100_msgs..: %s\n" + "\tqp0_pingpong..........: %s\n" + "\tqp0_ping_switch.......: %s\n", + ib_get_err_str(qp0_loopback), + ib_get_err_str(qp0_2_ports), + ib_get_err_str(qp0_2_ports_100), + ib_get_err_str(qp0_pingpong), + ib_get_err_str(qp0_ping_switch) + )); + + if( h_al ) + alts_close_al(h_al); + + ALTS_EXIT( ALTS_DBG_VERBOSE); + + return ib_status; + +} + +ib_api_status_t +alts_spl_destroy_resources( + alts_mad_ca_obj_t *p_ca_obj) +{ + /* + * Destroy Send QP, Recv QP, CQ and PD + */ + ib_api_status_t ib_status = IB_SUCCESS; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + if (p_ca_obj->h_qp[SRC_QP]) + { + ib_status = ib_destroy_qp(p_ca_obj->h_qp[SRC_QP], NULL); + } + + if (p_ca_obj->is_loopback != TRUE) + { + if (p_ca_obj->h_qp[DEST_QP]) + { + ib_status = ib_destroy_qp(p_ca_obj->h_qp[DEST_QP], NULL); + } + } + + if (p_ca_obj->h_cq) + ib_status = ib_destroy_cq(p_ca_obj->h_cq, NULL); + + if (p_ca_obj->h_pd) + ib_status = ib_dealloc_pd(p_ca_obj->h_pd,NULL); + + cl_thread_suspend( 1000 ); + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + + +ib_api_status_t +alts_spl_message_passing( + alts_mad_ca_obj_t *p_ca_obj) +{ + ib_api_status_t ib_status = IB_SUCCESS; + ib_mad_element_t *p_mad_element; + ib_mad_t *p_mad; + char *p_buf; + uint32_t i; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + + //Create an Address vector + av_attr.dlid = p_ca_obj->dlid; + av_attr.port_num = p_ca_obj->src_port_num; + av_attr.sl = 0; + av_attr.path_bits = 0; + av_attr.static_rate = IB_PATH_RECORD_RATE_10_GBS; + av_attr.grh_valid = FALSE; + + ib_status = ib_create_av(p_ca_obj->h_pd,&av_attr,&p_ca_obj->h_av_src); + if(ib_status != IB_SUCCESS) + return ib_status; + + p_ca_obj->send_done = 0; + p_ca_obj->send_done_error = 0; + p_ca_obj->recv_done = 0; + p_ca_obj->recv_done_error = 0; + p_ca_obj->cq_done = 0; + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("++++++ dlid(x%x) src_port(%d) ====\n", + av_attr.dlid, av_attr.port_num)); + + for (i=0; inum_wrs; i++) + { + p_mad_element = NULL; + ib_status = ib_get_mad( + p_ca_obj->h_src_pool, + MAD_BLOCK_SIZE, + &p_mad_element ); + if (ib_status != IB_SUCCESS) + { + ALTS_TRACE_EXIT(ALTS_DBG_VERBOSE, + ("Error in ib_get_mad()! %s\n", ib_get_err_str(ib_status))); + return (ib_status); + } + + // format mad + p_mad_element->context1 = (void *)1; + p_mad_element->context2 = p_ca_obj; + + /* Send request information. */ + p_mad_element->h_av = p_ca_obj->h_av_src; + p_mad_element->send_opt = IB_SEND_OPT_SIGNALED; + + + if (p_ca_obj->reply_requested == TRUE) + p_mad_element->resp_expected = TRUE; + else + p_mad_element->resp_expected = FALSE; //TRUE; + + p_mad_element->remote_qp = p_ca_obj->qp_attr[DEST_QP].num; + + p_mad_element->remote_qkey = p_ca_obj->qkey; + p_mad_element->timeout_ms = 20; + p_mad_element->retry_cnt = 1; + + /* Completion information. */ + p_mad_element->status = 0; + + // format mad + p_mad = p_mad_element->p_mad_buf; + + p_buf = (char *)p_mad; + cl_memset(p_buf, 0x66, 256); // set pattern in buffer + + + switch (p_ca_obj->qp_attr[SRC_QP].num) + { + case IB_QP0: + ib_mad_init_new( + p_mad, + IB_MCLASS_SUBN_LID, + ALTS_TEST_MGMT_CLASS_VER, + ALTS_TEST_MGMT_METHOD, + (ib_net64_t) CL_NTOH64(0x666), + IB_MAD_ATTR_SM_INFO, + 0 ); + break; + + case IB_QP1: + default: + ib_mad_init_new( + p_mad, + ALTS_TEST_MGMT_CLASS, + ALTS_TEST_MGMT_CLASS_VER, + ALTS_TEST_MGMT_METHOD, + (ib_net64_t) CL_NTOH64(0x666), + IB_MAD_ATTR_CLASS_PORT_INFO, + 0 ); + break; + } + + // send + ib_status = ib_send_mad( + p_ca_obj->h_src_mad_svc, + p_mad_element, + NULL ); + + if(ib_status != IB_SUCCESS) + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("ib_send_mad failed")); + + //cl_thread_suspend(10); // 10 usec + } + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("sleeping for awhile ...\n")); + + cl_thread_suspend(10000); // 10 seconds + + if (((!p_ca_obj->cq_done) && (p_ca_obj->num_wrs> 2)) || + (p_ca_obj->cq_done != p_ca_obj->num_wrs*2)) + { + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("sleeping for awhile ...\n")); + cl_thread_suspend(10000); // 10 seconds + } + + + if (((!p_ca_obj->cq_done) && (p_ca_obj->num_wrs> 2)) || + (p_ca_obj->cq_done != p_ca_obj->num_wrs*2)) + { + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("sleeping for awhile ...\n")); + cl_thread_suspend(10000); // 10 seconds + } + + if (((!p_ca_obj->cq_done) && (p_ca_obj->num_wrs> 2)) || + (p_ca_obj->cq_done != p_ca_obj->num_wrs*2)) + { + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("sleeping for awhile ...\n")); + cl_thread_suspend(10000); // 10 seconds + } + + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + +ib_api_status_t +alts_qp0_msg_at_hc ( + alts_mad_ca_obj_t *p_ca_obj, + IN const uint8_t hop_count ) +{ + ib_api_status_t ib_status = IB_SUCCESS; + ib_mad_element_t *p_mad_element; + ib_mad_t *p_mad; + char *p_buf; + uint32_t i; + uint8_t path_out[IB_SUBNET_PATH_HOPS_MAX]; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + + //Create an Address vector + av_attr.dlid = IB_LID_PERMISSIVE; + av_attr.port_num = p_ca_obj->src_port_num; + av_attr.sl = 0; + av_attr.path_bits = 0; + av_attr.static_rate = IB_PATH_RECORD_RATE_10_GBS; + av_attr.grh_valid = FALSE; + + ib_status = ib_create_av(p_ca_obj->h_pd,&av_attr,&p_ca_obj->h_av_src); + if(ib_status != IB_SUCCESS) + return ib_status; + + p_ca_obj->send_done = 0; + p_ca_obj->send_done_error = 0; + p_ca_obj->recv_done = 0; + p_ca_obj->recv_done_error = 0; + p_ca_obj->cq_done = 0; + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("++++++ dlid(x%x) src_port(%d) ====\n", + av_attr.dlid, av_attr.port_num)); + + for (i=0; inum_wrs; i++) + { + p_mad_element = NULL; + ib_status = ib_get_mad( + p_ca_obj->h_src_pool, + MAD_BLOCK_SIZE, + &p_mad_element ); + if (ib_status != IB_SUCCESS) + { + ALTS_TRACE_EXIT(ALTS_DBG_VERBOSE, + ("Error in ib_get_mad()! %s\n", ib_get_err_str(ib_status))); + return (ib_status); + } + + // format mad + p_mad_element->context1 = (void *)1; + p_mad_element->context2 = p_ca_obj; + + /* Send request information. */ + p_mad_element->h_av = p_ca_obj->h_av_src; + p_mad_element->send_opt = IB_SEND_OPT_SIGNALED; + + + if (p_ca_obj->reply_requested == TRUE) + p_mad_element->resp_expected = TRUE; + else + p_mad_element->resp_expected = FALSE; //TRUE; + + p_mad_element->remote_qp = p_ca_obj->qp_attr[DEST_QP].num; + + p_mad_element->remote_qkey = p_ca_obj->qkey; + p_mad_element->timeout_ms = 20; + p_mad_element->retry_cnt = 1; + + /* Completion information. */ + p_mad_element->status = 0; + + // format mad + p_mad = p_mad_element->p_mad_buf; + + p_buf = (char *)p_mad; + cl_memset(p_buf, 0x66, 256); // set pattern in buffer + + path_out[1] = p_ca_obj->src_port_num; + + ib_smp_init_new( + (ib_smp_t *)p_mad, + ALTS_TEST_MGMT_METHOD, + (ib_net64_t) CL_NTOH64(0x666), + IB_MAD_ATTR_NODE_DESC, + 0, + hop_count, + 0, + (const uint8_t *)&path_out, + IB_LID_PERMISSIVE, + IB_LID_PERMISSIVE ); + + // send + ib_status = ib_send_mad( + p_ca_obj->h_src_mad_svc, + p_mad_element, + NULL ); + + if(ib_status != IB_SUCCESS) + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("ib_send_mad failed")); + + + + } + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("sleeping for awhile ...\n")); + + cl_thread_suspend(10000); // 10 seconds + + if (((!p_ca_obj->cq_done) && (p_ca_obj->num_wrs> 2)) || + (p_ca_obj->cq_done != p_ca_obj->num_wrs*2)) + { + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("sleeping for awhile ...\n")); + cl_thread_suspend(10000); // 10 seconds + } + + + if (((!p_ca_obj->cq_done) && (p_ca_obj->num_wrs> 2)) || + (p_ca_obj->cq_done != p_ca_obj->num_wrs*2)) + { + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("sleeping for awhile ...\n")); + cl_thread_suspend(10000); // 10 seconds + } + + if (((!p_ca_obj->cq_done) && (p_ca_obj->num_wrs> 2)) || + (p_ca_obj->cq_done != p_ca_obj->num_wrs*2)) + { + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("sleeping for awhile ...\n")); + cl_thread_suspend(10000); // 10 seconds + } + + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + +ib_api_status_t +mad_post_sends( + alts_mad_ca_obj_t *p_ca_obj, + uint32_t reg_index, + uint32_t num_posts ) +{ + ib_send_wr_t *p_s_wr, *p_send_failure_wr; + uint32_t msg_size, i; + ib_api_status_t ib_status = IB_SUCCESS; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + if (p_ca_obj->test_type == TestUD1) + msg_size = p_ca_obj->msg_size - sizeof(ib_grh_t); + else + msg_size = 64; + + //msg_size = p_ca_obj->msg_size; + + msg_size = 64; + + p_s_wr = p_ca_obj->p_send_wr; + + p_s_wr->p_next = NULL; + p_s_wr->ds_array[0].length = msg_size; + p_s_wr->num_ds = 1; + + p_s_wr->wr_type = WR_SEND; + + if (p_ca_obj->test_type == TestUD1) + { + p_s_wr->dgrm.ud.h_av = p_ca_obj->h_av_src; + p_s_wr->send_opt = IB_SEND_OPT_IMMEDIATE | \ + IB_SEND_OPT_SIGNALED | IB_SEND_OPT_SOLICITED; + + p_s_wr->dgrm.ud.remote_qkey = p_ca_obj->qkey; + p_s_wr->dgrm.ud.remote_qp = p_ca_obj->qp_attr[DEST_QP].num; + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("======= qkey(x%x) qp_num(x%x) ========\n", + p_s_wr->dgrm.ud.remote_qkey, + p_s_wr->dgrm.ud.remote_qp)); + + } + else if(p_ca_obj->test_type == TestRC1) + { + p_s_wr->send_opt = IB_SEND_OPT_SIGNALED | \ + IB_SEND_OPT_IMMEDIATE | \ + IB_SEND_OPT_SOLICITED ; + + } + + + for (i = 0; i < num_posts; i++) + { + p_s_wr->wr_id = i+reg_index; + p_s_wr->immediate_data = 0xfeedde00 + i; + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("******vaddr(x%"PRIx64") lkey(x%x) len(%d)*****\n", + (void*)(uintn_t)p_s_wr->ds_array[0].vaddr, + p_s_wr->ds_array[0].lkey, + p_s_wr->ds_array[0].length)); + + ib_status = ib_post_send( + p_ca_obj->h_qp[SRC_QP], + p_s_wr, + &p_send_failure_wr); + + } + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + +ib_api_status_t +mad_post_recvs( + alts_mad_ca_obj_t *p_ca_obj, + uint32_t reg_index, + uint32_t num_posts ) +{ + ib_recv_wr_t *p_r_wr, *p_failure_wr; + uint32_t msg_size, i; + ib_api_status_t ib_status = IB_SUCCESS; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + + if (p_ca_obj->test_type == TestUD1) + msg_size = p_ca_obj->msg_size; + else + msg_size = 64; + //msg_size = p_ca_obj->msg_size; + + if (p_ca_obj->test_type == TestUD1) + msg_size = 64 + sizeof(ib_grh_t); + else + msg_size = 64; + + p_r_wr = p_ca_obj->p_recv_wr; + + p_r_wr->p_next = NULL; + p_r_wr->ds_array[0].length = msg_size; + p_r_wr->num_ds = 1; + + for (i = 0; i < num_posts; i++) + { + + p_r_wr->wr_id = i+reg_index; + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("******vaddr(x%"PRIx64") lkey(x%x) len(%d)*****\n", + (void*)(uintn_t)p_r_wr->ds_array[0].vaddr, + p_r_wr->ds_array[0].lkey, + p_r_wr->ds_array[0].length)); + + if (p_ca_obj->is_loopback == TRUE) + { + ib_status = ib_post_recv( + p_ca_obj->h_qp[SRC_QP], + p_r_wr, + &p_failure_wr); + } + else + { + ib_status = ib_post_recv( + p_ca_obj->h_qp[DEST_QP], + p_r_wr, + &p_failure_wr); + } + } + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + + +ib_api_status_t +mad_activate_svc( + alts_mad_ca_obj_t *p_ca_obj, + ib_qp_handle_t h_qp ) +{ + ib_api_status_t ib_status; + ib_mad_svc_handle_t h_mad_svc; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + // init dgrm svc + if(p_ca_obj->is_src == 1) + dgrm_info.port_guid = p_ca_obj->src_portguid; + else + dgrm_info.port_guid = p_ca_obj->dest_portguid; + + dgrm_info.qkey = p_ca_obj->qkey; + dgrm_info.pkey_index = 0; + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("******** port num = %d ***************\n", + p_ca_obj->src_port_num)); + + ib_status = ib_init_dgrm_svc( + h_qp, + &dgrm_info ); + + if (ib_status != IB_SUCCESS) + return ib_status; + + // create svc + cl_memclr(&mad_svc, sizeof(ib_mad_svc_t)); + + mad_svc.mad_svc_context = p_ca_obj; + mad_svc.pfn_mad_send_cb = mad_svc_send_cb; + mad_svc.pfn_mad_recv_cb = mad_svc_recv_cb; + + mad_svc.support_unsol = TRUE; + + mad_svc.mgmt_class = ALTS_TEST_MGMT_CLASS; + mad_svc.mgmt_version = ALTS_TEST_MGMT_CLASS_VER; + + // fill in methods supported + mad_svc.method_array[ALTS_TEST_MGMT_METHOD] = TRUE; + + ib_status = ib_reg_mad_svc( + h_qp, + &mad_svc, + &h_mad_svc ); + + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return IB_SUCCESS; +} + +ib_api_status_t +alts_mad_check_active_ports(alts_mad_ca_obj_t *p_ca_obj) +{ + ib_api_status_t ib_status; + ib_ca_attr_t *p_ca_attr; + ib_port_attr_t *p_src_port_attr = NULL; + ib_port_attr_t *p_dest_port_attr = NULL; + uint32_t i; + ib_port_attr_t *p_port_attr; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + CL_ASSERT(p_ca_obj); + + p_ca_attr = p_ca_obj->p_ca_attr; + + CL_ASSERT(p_ca_attr); + + for(i=0; i< p_ca_attr->num_ports; i++) + { + p_port_attr = &p_ca_attr->p_port_attr[i]; + + if (p_port_attr->link_state == IB_LINK_ACTIVE) + { + if (p_src_port_attr == NULL) + p_src_port_attr = p_port_attr; + else + if(p_dest_port_attr == NULL) + p_dest_port_attr = p_port_attr; + else + break; + } + } + + // handle loopback case + if (p_ca_obj->is_loopback == TRUE) + p_dest_port_attr = p_src_port_attr; + + if (p_src_port_attr && p_dest_port_attr) + { + p_ca_obj->p_dest_port_attr = p_dest_port_attr; + p_ca_obj->p_src_port_attr = p_src_port_attr; + + p_ca_obj->dlid = p_dest_port_attr->lid; + p_ca_obj->slid = p_src_port_attr->lid; + + p_ca_obj->dest_portguid = p_dest_port_attr->port_guid; + p_ca_obj->src_portguid = p_src_port_attr->port_guid; + + p_ca_obj->dest_port_num = p_dest_port_attr->port_num; + p_ca_obj->src_port_num = p_src_port_attr->port_num; + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("**** slid = x%x (x%x) ***dlid = x%x (x%x) ***************\n", + p_ca_obj->slid, + CL_NTOH16(p_ca_obj->slid), + p_ca_obj->dlid, + CL_NTOH16(p_ca_obj->dlid) )); + + ib_status = IB_SUCCESS; + + } + else + { + + ib_status = IB_ERROR; + } + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + +/* + * Create the CQ, PD and QP + */ +ib_api_status_t +mad_create_resources( alts_mad_ca_obj_t *p_ca_obj ) +{ + ib_api_status_t ib_status; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + cl_memclr(&qp_create_attr, sizeof(ib_qp_create_t)); + + /* + * Allocate a PD + */ + ib_status = ib_alloc_pd( + p_ca_obj->h_ca, + IB_PDT_NORMAL, + p_ca_obj, //pd_context + &p_ca_obj->h_pd); + + CL_ASSERT(ib_status == IB_SUCCESS); + + /* + * Create CQ Attributes + */ + cq_create_attr.size = p_ca_obj->cq_size; + cq_create_attr.pfn_comp_cb = mad_cq_comp_cb; + cq_create_attr.h_wait_obj = NULL; + + ib_status = ib_create_cq( + p_ca_obj->h_ca, + &cq_create_attr, + p_ca_obj, + mad_cq_err_cb, + &p_ca_obj->h_cq ); + CL_ASSERT(ib_status == IB_SUCCESS); + + p_ca_obj->cq_size = cq_create_attr.size; + + /* + * Create QP Attributes + */ + qp_create_attr.sq_depth = p_ca_obj->num_wrs; + qp_create_attr.rq_depth = p_ca_obj->num_wrs; + qp_create_attr.sq_sge = 1; + qp_create_attr.rq_sge = 1; + qp_create_attr.h_sq_cq = p_ca_obj->h_cq; + qp_create_attr.h_rq_cq = p_ca_obj->h_cq; + + qp_create_attr.sq_signaled = TRUE; + + qp_create_attr.qp_type = IB_QPT_MAD; + + ib_status = ib_create_qp( + p_ca_obj->h_pd, + &qp_create_attr, + p_ca_obj, + mad_qp_err_cb, + &p_ca_obj->h_qp[SRC_QP]); + + if (ib_status != IB_SUCCESS) + { + ALTS_TRACE_EXIT(ALTS_DBG_VERBOSE, + ("Error in ib_create_qp()! %s\n", + ib_get_err_str(ib_status))); + + return (ib_status); + } + + ib_status = ib_query_qp(p_ca_obj->h_qp[SRC_QP], + &p_ca_obj->qp_attr[SRC_QP]); + + if (ib_status != IB_SUCCESS) + { + ALTS_TRACE_EXIT(ALTS_DBG_VERBOSE, + ("Error in query_qp()! %s\n", + ib_get_err_str(ib_status))); + + ib_destroy_qp(p_ca_obj->h_qp[SRC_QP],mad_qp_destroy_cb); + return (ib_status); + } + + if (p_ca_obj->is_loopback == TRUE) + { + // do loopback on same QP + p_ca_obj->h_qp[DEST_QP] = p_ca_obj->h_qp[SRC_QP]; + p_ca_obj->qp_attr[DEST_QP] = p_ca_obj->qp_attr[SRC_QP]; + } + else + { + ib_status = ib_create_qp( + p_ca_obj->h_pd, + &qp_create_attr, + p_ca_obj, + mad_qp_err_cb, + &p_ca_obj->h_qp[DEST_QP]); + + if (ib_status != IB_SUCCESS) + { + ALTS_TRACE_EXIT(ALTS_DBG_VERBOSE, + ("Error in ib_create_qp()! %s\n", + ib_get_err_str(ib_status))); + + ib_destroy_qp(p_ca_obj->h_qp[SRC_QP],mad_qp_destroy_cb); + return (ib_status); + } + + ib_status = ib_query_qp(p_ca_obj->h_qp[DEST_QP], + &p_ca_obj->qp_attr[DEST_QP]); + + //CL_ASSERT(ib_status == IB_SUCCESS); + if (ib_status != IB_SUCCESS) + { + ALTS_TRACE_EXIT(ALTS_DBG_VERBOSE, + ("Error in query_qp()! %s\n", + ib_get_err_str(ib_status))); + + ib_destroy_qp(p_ca_obj->h_qp[DEST_QP],mad_qp_destroy_cb); + return (ib_status); + } + } + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + + +void +alts_send_mad_resp( + alts_mad_ca_obj_t *p_ca_obj, + ib_mad_element_t *p_gmp ) +{ + ib_api_status_t ib_status = IB_SUCCESS; + ib_mad_element_t *p_resp; + ib_mad_t *p_mad; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + + //Create an Address vector + av_attr.dlid = p_gmp->remote_lid; + av_attr.port_num = p_ca_obj->dest_port_num; + av_attr.sl = p_gmp->remote_sl; + av_attr.path_bits = p_gmp->path_bits; + av_attr.static_rate = IB_PATH_RECORD_RATE_10_GBS; + + av_attr.grh_valid = p_gmp->grh_valid; + if (p_gmp->grh_valid == TRUE) + av_attr.grh = *p_gmp->p_grh; + + ib_status = ib_create_av(p_ca_obj->h_pd,&av_attr,&p_ca_obj->h_av_dest); + if(ib_status != IB_SUCCESS) + return; + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("++++++ dlid(x%x) src_port(%d) ====\n", + av_attr.dlid, av_attr.port_num)); + + ib_status = ib_get_mad( + p_ca_obj->h_dest_pool, + MAD_BLOCK_SIZE, + &p_resp ); + if (ib_status != IB_SUCCESS) + { + ALTS_TRACE_EXIT(ALTS_DBG_VERBOSE, + ("Error in ib_get_mad()! %s\n", ib_get_err_str(ib_status))); + + return; + } + + // format mad + p_resp->context1 = (void *)1; + p_resp->context2 = p_ca_obj; + + /* Send request information. */ + p_resp->h_av = p_ca_obj->h_av_dest; + p_resp->send_opt = IB_SEND_OPT_SIGNALED; + p_resp->resp_expected = FALSE; //TRUE; + + p_resp->remote_qp = p_gmp->remote_qp; + p_resp->remote_qkey = p_ca_obj->qkey; + p_resp->timeout_ms = 0; + p_resp->retry_cnt = 0; + + /* Completion information. */ + p_resp->status = 0; + + // format mad + p_mad = p_resp->p_mad_buf; + + // copy msg received as response + ib_mad_init_response( + p_gmp->p_mad_buf, + p_mad, + 0 ); + + // send + ib_status = ib_send_mad( + p_ca_obj->h_dest_mad_svc, + p_resp, + NULL ); + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ; +} + +void +mad_svc_send_cb( + IN const ib_mad_svc_handle_t h_mad_svc, + IN void *mad_svc_context, + IN ib_mad_element_t *p_mad_element ) +{ + ib_mad_element_t *p_gmp; + uint32_t i = 0; + alts_mad_ca_obj_t *p_ca_obj; + ib_mad_t *p_mad; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + UNUSED_PARAM( h_mad_svc ); + + CL_ASSERT (mad_svc_context); + CL_ASSERT (p_mad_element); + + p_gmp = p_mad_element; + + p_ca_obj = (alts_mad_ca_obj_t*)mad_svc_context; + + do + { + p_mad = p_gmp->p_mad_buf; + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("Send completed:\n" + "\tstatus......:%s\n" + "\tremote_qp...:x%x\n" + "\tremote_qkey.:x%x\n" + "\ttid.........:x%"PRIx64"\n", + ib_get_wc_status_str(p_gmp->status), + CL_NTOH32(p_gmp->remote_qp), + CL_NTOH32(p_gmp->remote_qkey), + p_mad->trans_id + )); + + if( p_gmp->status == IB_WCS_SUCCESS ) + { + i++; + p_ca_obj->send_done++; + } + else + { + p_ca_obj->send_done_error++; + } + + // loop + p_gmp = p_gmp->p_next; + + } while (p_gmp); + + p_ca_obj->cq_done += i; + + ALTS_PRINT( ALTS_DBG_INFO, + ("Number of items polled from CQ (in callback=%d) (send=%d) (total=%d)\n", + i, + p_ca_obj->send_done, + p_ca_obj->cq_done) ); + + // put it back in the mad owner's pool + ib_put_mad(p_mad_element); + + ALTS_EXIT( ALTS_DBG_VERBOSE); +} + +void +mad_svc_recv_cb( + IN const ib_mad_svc_handle_t h_mad_svc, + IN void *mad_svc_context, + IN ib_mad_element_t *p_mad_element ) +{ + ib_mad_element_t *p_gmp; + uint32_t i = 0; + alts_mad_ca_obj_t *p_ca_obj; + ib_mad_t *p_mad; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + UNUSED_PARAM( h_mad_svc ); + + CL_ASSERT (mad_svc_context); + CL_ASSERT (p_mad_element); + + p_gmp = p_mad_element; + p_ca_obj = (alts_mad_ca_obj_t*)mad_svc_context; + + do + { + p_mad = p_gmp->p_mad_buf; + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("Recv completed:\n" + "\tstatus......:%s\n" + "\tremote_qp...:x%x\n" + "\tremote_lid..:x%x\n" + "\ttid.........:x%"PRIx64"\n", + ib_get_wc_status_str(p_gmp->status), + CL_NTOH32(p_gmp->remote_qp), + p_gmp->remote_lid, + p_mad->trans_id + )); + + if( p_gmp->status == IB_WCS_SUCCESS ) + { + i++; + p_ca_obj->recv_done++; + + // process received mad + if (p_ca_obj->reply_requested == TRUE) + { + // is it a request? + if (ib_mad_is_response(p_mad) != TRUE) + alts_send_mad_resp(p_ca_obj, p_gmp); + } + } + else + { + p_ca_obj->recv_done_error++; + } + + + // loop + p_gmp = p_gmp->p_next; + + } while (p_gmp); + + p_ca_obj->cq_done += i; + + ALTS_PRINT( ALTS_DBG_INFO, + ("Number of items polled from CQ (in callback=%d) (recv=%d) (total=%d)\n", + i, + p_ca_obj->recv_done, + p_ca_obj->cq_done) ); + + // put it back in the mad owner's pool + ib_put_mad(p_mad_element); + + ALTS_EXIT( ALTS_DBG_VERBOSE); +} + +void +mad_svc_qp0_recv_cb( + IN const ib_mad_svc_handle_t h_mad_svc, + IN void *mad_svc_context, + IN ib_mad_element_t *p_mad_element ) +{ + ib_mad_element_t *p_gmp; + uint32_t i = 0; + alts_mad_ca_obj_t *p_ca_obj; + ib_mad_t *p_mad; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + UNUSED_PARAM( h_mad_svc ); + + CL_ASSERT (mad_svc_context); + CL_ASSERT (p_mad_element); + + p_gmp = p_mad_element; + p_ca_obj = (alts_mad_ca_obj_t*)mad_svc_context; + + do + { + p_mad = p_gmp->p_mad_buf; + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("Recv completed:\n" + "\tstatus......:%s\n" + "\tremote_qp...:x%x\n" + "\tremote_lid..:x%x\n" + "\ttid.........:x%"PRIx64"\n", + ib_get_wc_status_str(p_gmp->status), + CL_NTOH32(p_gmp->remote_qp), + p_gmp->remote_lid, + p_mad->trans_id + )); + + if( p_gmp->status == IB_WCS_SUCCESS ) + { + i++; + p_ca_obj->recv_done++; + + // process received mad + if (p_ca_obj->reply_requested == TRUE) + { + // is it a request? + //if (ib_mad_is_response(p_mad) != TRUE) + // alts_send_mad_resp(p_ca_obj, p_gmp); + } + } + else + { + p_ca_obj->recv_done_error++; + } + + + + // loop + p_gmp = p_gmp->p_next; + + } while (p_gmp); + + p_ca_obj->cq_done += i; + + ALTS_PRINT( ALTS_DBG_INFO, + ("Number of items polled from CQ (in callback=%d) (recv=%d) (total=%d)\n", + i, + p_ca_obj->recv_done, + p_ca_obj->cq_done) ); + + // put it back in the mad owner's pool + ib_put_mad(p_mad_element); + + ALTS_EXIT( ALTS_DBG_VERBOSE); +} + +/* + * Create the Spl PD and QP + */ +ib_api_status_t +mad_create_spl_resources( + alts_mad_ca_obj_t *p_ca_obj, + ib_qp_type_t qp_type, + uint8_t mgmt_class, + uint8_t class_ver, + ib_pfn_mad_comp_cb_t pfn_mad_svc_send_cb, + ib_pfn_mad_comp_cb_t pfn_mad_svc_recv_cb ) +{ + ib_api_status_t ib_status; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + + /* + * Allocate a PD + */ + ib_status = ib_alloc_pd( + p_ca_obj->h_ca, + IB_PDT_ALIAS, + p_ca_obj, //pd_context + &p_ca_obj->h_pd); + + CL_ASSERT(ib_status == IB_SUCCESS); + + /* + * Create QP Attributes + */ + cl_memclr(&qp_create_attr, sizeof(ib_qp_create_t)); + + qp_create_attr.sq_depth = p_ca_obj->num_wrs; + qp_create_attr.rq_depth = p_ca_obj->num_wrs; + qp_create_attr.sq_sge = 1; + qp_create_attr.rq_sge = 1; + qp_create_attr.h_sq_cq = NULL; + qp_create_attr.h_rq_cq = NULL; + + qp_create_attr.sq_signaled = TRUE; + + qp_create_attr.qp_type = qp_type; // IB_QPT_QP1_ALIAS or IB_QPT_QP0_ALIAS; + + ib_status = ib_get_spl_qp( + p_ca_obj->h_pd, + p_ca_obj->src_portguid, + &qp_create_attr, + p_ca_obj, // context + mad_qp_err_cb, + &p_ca_obj->h_src_pool, + &p_ca_obj->h_qp[SRC_QP]); + + if (ib_status != IB_SUCCESS) + { + ALTS_TRACE_EXIT(ALTS_DBG_VERBOSE, + ("Error in ib_get_spl_qp()! %s\n", ib_get_err_str(ib_status))); + return (ib_status); + } + + ib_status = ib_query_qp(p_ca_obj->h_qp[SRC_QP], + &p_ca_obj->qp_attr[SRC_QP]); + + // create svc + cl_memclr(&mad_svc, sizeof(ib_mad_svc_t)); + + mad_svc.mad_svc_context = p_ca_obj; + mad_svc.pfn_mad_send_cb = pfn_mad_svc_send_cb; + mad_svc.pfn_mad_recv_cb = pfn_mad_svc_recv_cb; + + mad_svc.support_unsol = TRUE; + + mad_svc.mgmt_class = mgmt_class; + mad_svc.mgmt_version = class_ver; + + + // fill in methods supported + mad_svc.method_array[ALTS_TEST_MGMT_METHOD] = TRUE; + + ib_status = ib_reg_mad_svc( + p_ca_obj->h_qp[SRC_QP], + &mad_svc, + &p_ca_obj->h_src_mad_svc ); + if (ib_status != IB_SUCCESS) + { + ALTS_TRACE_EXIT(ALTS_DBG_VERBOSE, + ("Error in ib_reg_mad_svc()! %s\n", ib_get_err_str(ib_status))); + return (ib_status); + } + + // do the server side too if we are not doing loopback + if (p_ca_obj->is_loopback == TRUE) + { + // do loopback on same QP + p_ca_obj->h_qp[DEST_QP] = p_ca_obj->h_qp[SRC_QP]; + p_ca_obj->qp_attr[DEST_QP] = p_ca_obj->qp_attr[SRC_QP]; + } + else + { + ib_status = ib_get_spl_qp( + p_ca_obj->h_pd, + p_ca_obj->dest_portguid, + &qp_create_attr, + p_ca_obj, // context + mad_qp_err_cb, + &p_ca_obj->h_dest_pool, + &p_ca_obj->h_qp[DEST_QP]); + + if (ib_status != IB_SUCCESS) + { + ALTS_TRACE_EXIT(ALTS_DBG_VERBOSE, + ("Error in ib_get_spl_qp()! %s\n", + ib_get_err_str(ib_status))); + + ib_destroy_qp(p_ca_obj->h_qp[SRC_QP],mad_qp_destroy_cb); + return (ib_status); + } + + ib_status = ib_query_qp(p_ca_obj->h_qp[DEST_QP], + &p_ca_obj->qp_attr[DEST_QP]); + + // create svc + cl_memclr(&mad_svc, sizeof(ib_mad_svc_t)); + + mad_svc.mad_svc_context = p_ca_obj; + mad_svc.pfn_mad_send_cb = pfn_mad_svc_send_cb; + mad_svc.pfn_mad_recv_cb = pfn_mad_svc_recv_cb; + + mad_svc.support_unsol = TRUE; + + if (qp_type == IB_QPT_QP0_ALIAS) + { + mad_svc.mgmt_class = IB_MCLASS_SUBN_LID; + mad_svc.mgmt_version = ALTS_TEST_MGMT_CLASS_VER; + } + else + { + mad_svc.mgmt_class = ALTS_TEST_MGMT_CLASS; + mad_svc.mgmt_version = ALTS_TEST_MGMT_CLASS_VER; + } + + // fill in methods supported + mad_svc.method_array[ALTS_TEST_MGMT_METHOD] = TRUE; + + ib_status = ib_reg_mad_svc( + p_ca_obj->h_qp[DEST_QP], + &mad_svc, + &p_ca_obj->h_dest_mad_svc ); + if (ib_status != IB_SUCCESS) + { + ALTS_TRACE_EXIT(ALTS_DBG_VERBOSE, + ("Error in ib_reg_mad_svc()! %s\n", ib_get_err_str(ib_status))); + return (ib_status); + } + + } + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + + +void +mad_cq_comp_cb( + IN const ib_cq_handle_t h_cq, + IN void *cq_context ) +{ + ib_api_status_t ib_status; + uint32_t i = 0, id; + ib_wc_t *p_free_wcl, *p_done_cl= NULL; + alts_mad_ca_obj_t *p_ca_obj; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + UNUSED_PARAM( h_cq ); + + CL_ASSERT(cq_context); + + p_ca_obj = (alts_mad_ca_obj_t *)cq_context; + + + ib_status = ib_rearm_cq(p_ca_obj->h_cq, TRUE); + + p_free_wcl = &free_wcl; + p_free_wcl->p_next = NULL; + + ib_status = ib_poll_cq(p_ca_obj->h_cq, &p_free_wcl, &p_done_cl); + + while(p_done_cl) + { + + /* + * print output + */ + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("Got a completion:\n" + "\ttype....:%s\n" + "\twr_id...:%"PRIx64"\n", + ib_get_wc_type_str(p_done_cl->wc_type), + p_done_cl->wr_id )); + + + if (p_done_cl->wc_type == IB_WC_RECV) + { + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("message length..:%d bytes\n", + p_done_cl->length )); + + id = (uint32_t)p_done_cl->wr_id; + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("RecvUD info:\n" + "\trecv_opt...:x%x\n" + "\timm_data...:x%x\n", + p_done_cl->recv.conn.recv_opt, + p_done_cl->recv.ud.immediate_data )); + } + + p_free_wcl = p_done_cl; + p_free_wcl->p_next = NULL; + p_done_cl = NULL; + i++; + ib_status = ib_poll_cq(p_ca_obj->h_cq, &p_free_wcl, &p_done_cl); + } + + p_ca_obj->cq_done += i; + + ALTS_PRINT( ALTS_DBG_INFO, + ("Number of items polled from CQ (in callback=%d) (total=%d)\n", + i, + p_ca_obj->cq_done) ); + + + ALTS_EXIT( ALTS_DBG_VERBOSE); +} + +void +mad_cq_err_cb( + ib_async_event_rec_t *p_err_rec + ) +{ + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + UNUSED_PARAM( p_err_rec ); + + ALTS_EXIT( ALTS_DBG_VERBOSE); +} + +void +mad_qp_err_cb( + ib_async_event_rec_t *p_err_rec + ) +{ + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + UNUSED_PARAM( p_err_rec ); + + ALTS_EXIT( ALTS_DBG_VERBOSE); +} + +void +mad_pd_destroy_cb( + void *context + ) +{ +/* + * PD destroy call back + */ + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + UNUSED_PARAM( context ); + + ALTS_EXIT( ALTS_DBG_VERBOSE); +} + + +void +mad_qp_destroy_cb( + void *context + ) +{ +/* + * QP destroy call back + */ + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + UNUSED_PARAM( context ); + + ALTS_EXIT( ALTS_DBG_VERBOSE); +} + +void +mad_cq_destroy_cb( + void *context + ) +{ +/* + * CQ destroy call back + */ + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + UNUSED_PARAM( context ); + + ALTS_EXIT( ALTS_DBG_VERBOSE); +} + +ib_api_status_t +alts_qp1_loopback( + ib_ca_handle_t h_ca, + uint32_t ca_attr_size ) +{ + ib_api_status_t ib_status = IB_ERROR, ib_status2; + uint32_t bsize; + alts_mad_ca_obj_t *p_ca_obj = NULL; + ib_ca_attr_t *p_ca_attr = NULL; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + CL_ASSERT (h_ca); + CL_ASSERT (ca_attr_size); + + do + { + p_ca_obj = (alts_mad_ca_obj_t*)cl_zalloc(sizeof(alts_mad_ca_obj_t)); + if (!p_ca_obj) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("zalloc() failed for alts_mad_ca_obj_t!\n") ); + break; + } + + /* Allocate the memory needed for query_ca */ + bsize = ca_attr_size; + p_ca_attr = (ib_ca_attr_t *)cl_zalloc(bsize); + if (!p_ca_attr) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("zalloc() failed for p_ca_attr!\n") ); + break; + } + + ib_status = ib_query_ca(h_ca, p_ca_attr, &bsize); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_query_ca failed with status = %d\n", ib_status) ); + break; + } + + /* + * Initialize the CA Object + */ + p_ca_obj->h_ca = h_ca; + p_ca_obj->p_ca_attr = p_ca_attr; + p_ca_obj->status = IB_SUCCESS; + p_ca_obj->cq_size = 255*2; + p_ca_obj->qkey = IB_QP1_WELL_KNOWN_Q_KEY; + p_ca_obj->ds_list_depth = 1; + p_ca_obj->num_wrs = 1; + p_ca_obj->msg_size = 256; + + p_ca_obj->src_qp_num = IB_QP1; + p_ca_obj->is_loopback = TRUE; + + /* + * get an active port + */ + ib_status = alts_mad_check_active_ports(p_ca_obj); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("This test routing atleast 1 active port on the 1st hca\n")); + break; + } + + /* + * Create the necessary resource PD/QP/QP + */ + ib_status = mad_create_spl_resources( + p_ca_obj, + IB_QPT_QP1_ALIAS, + ALTS_TEST_MGMT_CLASS, + ALTS_TEST_MGMT_CLASS_VER, + mad_svc_send_cb, + mad_svc_recv_cb ); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("mad_create_spl_resources() failed with status %d\n", ib_status)); + break; + } + + /* + * Start Message passing activity + */ + ib_status = alts_spl_message_passing(p_ca_obj); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_spl_message_passing failed with status %d\n", ib_status)); + break; + } + + cl_thread_suspend(1000); /* 1 sec */ + + if (p_ca_obj->cq_done == 2) + ib_status = IB_SUCCESS; + else + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("errors: send(%d) recv(%d)\n", + p_ca_obj->send_done_error, p_ca_obj->recv_done_error)); + + ib_status = IB_ERROR; + } + + } while (0); + + /* + * Destroy the resources + */ + ib_status2 = alts_spl_destroy_resources(p_ca_obj); + if (ib_status == IB_SUCCESS) + ib_status = ib_status2; + + if (p_ca_attr) + cl_free(p_ca_attr); + + if (p_ca_obj) + cl_free(p_ca_obj); + + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + +ib_api_status_t +alts_qp1_2_ports( + ib_ca_handle_t h_ca, + uint32_t ca_attr_size ) +{ + ib_api_status_t ib_status = IB_ERROR, ib_status2; + uint32_t bsize; + alts_mad_ca_obj_t *p_ca_obj = NULL; + ib_ca_attr_t *p_ca_attr = NULL; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + CL_ASSERT (h_ca); + CL_ASSERT (ca_attr_size); + + do + { + p_ca_obj = (alts_mad_ca_obj_t*)cl_zalloc(sizeof(alts_mad_ca_obj_t)); + if (!p_ca_obj) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("zalloc() failed for alts_mad_ca_obj_t!\n") ); + break; + } + + /* Allocate the memory needed for query_ca */ + bsize = ca_attr_size; + p_ca_attr = (ib_ca_attr_t *)cl_zalloc(bsize); + if (!p_ca_attr) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("zalloc() failed for p_ca_attr!\n") ); + break; + } + + ib_status = ib_query_ca(h_ca, p_ca_attr, &bsize); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_query_ca failed with status = %d\n", ib_status) ); + break; + } + + /* + * Initialize the CA Object + */ + p_ca_obj->h_ca = h_ca; + p_ca_obj->p_ca_attr = p_ca_attr; + p_ca_obj->status = IB_SUCCESS; + p_ca_obj->cq_size = 255*2; + p_ca_obj->qkey = IB_QP1_WELL_KNOWN_Q_KEY; + p_ca_obj->ds_list_depth = 1; + p_ca_obj->num_wrs = 1; + p_ca_obj->msg_size = 256; + + p_ca_obj->src_qp_num = IB_QP1; + p_ca_obj->is_loopback = FALSE; + + /* + * get an active port + */ + ib_status = alts_mad_check_active_ports(p_ca_obj); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("This test routing atleast 1 active port on the 1st hca\n")); + break; + } + + /* + * Create the necessary resource PD/QP/QP + */ + ib_status = mad_create_spl_resources( + p_ca_obj, + IB_QPT_QP1_ALIAS, + ALTS_TEST_MGMT_CLASS, + ALTS_TEST_MGMT_CLASS_VER, + mad_svc_send_cb, + mad_svc_recv_cb ); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("mad_create_spl_resources() failed with status %d\n", ib_status)); + break; + } + + /* + * Start Message passing activity + */ + ib_status = alts_spl_message_passing(p_ca_obj); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_spl_message_passing failed with status %d\n", ib_status)); + break; + } + + cl_thread_suspend(1000); /* 1 sec */ + + if (p_ca_obj->cq_done == 2) + ib_status = IB_SUCCESS; + else + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("errors: send(%d) recv(%d)\n", + p_ca_obj->send_done_error, p_ca_obj->recv_done_error)); + + ib_status = IB_ERROR; + } + + } while (0); + + /* + * Destroy the resources + */ + ib_status2 = alts_spl_destroy_resources(p_ca_obj); + if (ib_status == IB_SUCCESS) + ib_status = ib_status2; + + if (p_ca_attr) + cl_free(p_ca_attr); + + if (p_ca_obj) + cl_free(p_ca_obj); + + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + +ib_api_status_t +alts_qp1_2_ports_100( + ib_ca_handle_t h_ca, + uint32_t ca_attr_size ) +{ + ib_api_status_t ib_status = IB_ERROR, ib_status2; + uint32_t bsize; + alts_mad_ca_obj_t *p_ca_obj = NULL; + ib_ca_attr_t *p_ca_attr = NULL; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + CL_ASSERT (h_ca); + CL_ASSERT (ca_attr_size); + + do + { + p_ca_obj = (alts_mad_ca_obj_t*)cl_zalloc(sizeof(alts_mad_ca_obj_t)); + if (!p_ca_obj) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("zalloc() failed for alts_mad_ca_obj_t!\n") ); + break; + } + + /* Allocate the memory needed for query_ca */ + bsize = ca_attr_size; + p_ca_attr = (ib_ca_attr_t *)cl_zalloc(bsize); + if (!p_ca_attr) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("zalloc() failed for p_ca_attr!\n") ); + break; + } + + ib_status = ib_query_ca(h_ca, p_ca_attr, &bsize); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_query_ca failed with status = %d\n", ib_status) ); + break; + } + + /* + * Initialize the CA Object + */ + p_ca_obj->h_ca = h_ca; + p_ca_obj->p_ca_attr = p_ca_attr; + p_ca_obj->status = IB_SUCCESS; + p_ca_obj->cq_size = 255*2; + p_ca_obj->qkey = IB_QP1_WELL_KNOWN_Q_KEY; + p_ca_obj->ds_list_depth = 1; + p_ca_obj->num_wrs = 100; + p_ca_obj->msg_size = 256; + + p_ca_obj->src_qp_num = IB_QP1; + p_ca_obj->is_loopback = FALSE; + + /* + * get an active port + */ + ib_status = alts_mad_check_active_ports(p_ca_obj); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("This test routing atleast 1 active port on the 1st hca\n")); + break; + } + + /* + * Create the necessary resource PD/QP/QP + */ + ib_status = mad_create_spl_resources( + p_ca_obj, + IB_QPT_QP1_ALIAS, + ALTS_TEST_MGMT_CLASS, + ALTS_TEST_MGMT_CLASS_VER, + mad_svc_send_cb, + mad_svc_recv_cb ); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("mad_create_spl_resources() failed with status %d\n", ib_status)); + break; + } + + /* + * Start Message passing activity + */ + ib_status = alts_spl_message_passing(p_ca_obj); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_spl_message_passing failed with status %d\n", ib_status)); + break; + } + + cl_thread_suspend(1000); /* 1 sec */ + + if (p_ca_obj->cq_done == 200) + ib_status = IB_SUCCESS; + else + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("errors: send(%d) recv(%d)\n", + p_ca_obj->send_done_error, p_ca_obj->recv_done_error)); + + ib_status = IB_ERROR; + } + + } while (0); + + /* + * Destroy the resources + */ + ib_status2 = alts_spl_destroy_resources(p_ca_obj); + if (ib_status == IB_SUCCESS) + ib_status = ib_status2; + + if (p_ca_attr) + cl_free(p_ca_attr); + + if (p_ca_obj) + cl_free(p_ca_obj); + + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + +ib_api_status_t +alts_qp1_pingpong( + ib_ca_handle_t h_ca, + uint32_t ca_attr_size ) +{ + ib_api_status_t ib_status = IB_ERROR, ib_status2; + uint32_t bsize; + alts_mad_ca_obj_t *p_ca_obj = NULL; + ib_ca_attr_t *p_ca_attr = NULL; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + CL_ASSERT (h_ca); + CL_ASSERT (ca_attr_size); + + do + { + p_ca_obj = (alts_mad_ca_obj_t*)cl_zalloc(sizeof(alts_mad_ca_obj_t)); + if (!p_ca_obj) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("zalloc() failed for alts_mad_ca_obj_t!\n") ); + break; + } + + /* Allocate the memory needed for query_ca */ + bsize = ca_attr_size; + p_ca_attr = (ib_ca_attr_t *)cl_zalloc(bsize); + if (!p_ca_attr) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("zalloc() failed for p_ca_attr!\n") ); + break; + } + + ib_status = ib_query_ca(h_ca, p_ca_attr, &bsize); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_query_ca failed with status = %d\n", ib_status) ); + break; + } + + /* + * Initialize the CA Object + */ + p_ca_obj->h_ca = h_ca; + p_ca_obj->p_ca_attr = p_ca_attr; + p_ca_obj->status = IB_SUCCESS; + p_ca_obj->cq_size = 255*2; + p_ca_obj->qkey = IB_QP1_WELL_KNOWN_Q_KEY; + p_ca_obj->ds_list_depth = 1; + p_ca_obj->num_wrs = 1; + p_ca_obj->msg_size = 256; + + p_ca_obj->src_qp_num = IB_QP1; + p_ca_obj->is_loopback = FALSE; + + p_ca_obj->reply_requested = TRUE; // we need a reply + + /* + * get an active port + */ + ib_status = alts_mad_check_active_ports(p_ca_obj); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("This test routing atleast 1 active port on the 1st hca\n")); + break; + } + + /* + * Create the necessary resource PD/QP/QP + */ + ib_status = mad_create_spl_resources( + p_ca_obj, + IB_QPT_QP1_ALIAS, + ALTS_TEST_MGMT_CLASS, + ALTS_TEST_MGMT_CLASS_VER, + mad_svc_send_cb, + mad_svc_recv_cb ); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("mad_create_spl_resources() failed with status %d\n", ib_status)); + break; + } + + /* + * Start Message passing activity + */ + ib_status = alts_spl_message_passing(p_ca_obj); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_spl_message_passing failed with status %d\n", ib_status)); + break; + } + + cl_thread_suspend(1000); /* 1 sec */ + + if (p_ca_obj->cq_done == 4) + ib_status = IB_SUCCESS; + else + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("errors: send(%d) recv(%d)\n", + p_ca_obj->send_done_error, p_ca_obj->recv_done_error)); + + ib_status = IB_ERROR; + } + + } while (0); + + /* + * Destroy the resources + */ + ib_status2 = alts_spl_destroy_resources(p_ca_obj); + if (ib_status == IB_SUCCESS) + ib_status = ib_status2; + + if (p_ca_attr) + cl_free(p_ca_attr); + + if (p_ca_obj) + cl_free(p_ca_obj); + + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + + +ib_api_status_t +alts_qp0_loopback( + ib_ca_handle_t h_ca, + uint32_t ca_attr_size ) +{ + ib_api_status_t ib_status = IB_ERROR, ib_status2; + uint32_t bsize; + alts_mad_ca_obj_t *p_ca_obj = NULL; + ib_ca_attr_t *p_ca_attr = NULL; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + CL_ASSERT (h_ca); + CL_ASSERT (ca_attr_size); + + do + { + p_ca_obj = (alts_mad_ca_obj_t*)cl_zalloc(sizeof(alts_mad_ca_obj_t)); + if (!p_ca_obj) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("zalloc() failed for alts_mad_ca_obj_t!\n") ); + break; + } + + /* Allocate the memory needed for query_ca */ + bsize = ca_attr_size; + p_ca_attr = (ib_ca_attr_t *)cl_zalloc(bsize); + if (!p_ca_attr) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("zalloc() failed for p_ca_attr!\n") ); + break; + } + + ib_status = ib_query_ca(h_ca, p_ca_attr, &bsize); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_query_ca failed with status = %d\n", ib_status) ); + break; + } + + /* + * Initialize the CA Object + */ + p_ca_obj->h_ca = h_ca; + p_ca_obj->p_ca_attr = p_ca_attr; + p_ca_obj->status = IB_SUCCESS; + p_ca_obj->cq_size = 255*2; + p_ca_obj->qkey = 0; + p_ca_obj->ds_list_depth = 1; + p_ca_obj->num_wrs = 1; + p_ca_obj->msg_size = 256; + + p_ca_obj->src_qp_num = IB_QP0; + p_ca_obj->is_loopback = TRUE; + + p_ca_obj->reply_requested = FALSE; + + /* + * get an active port + */ + ib_status = alts_mad_check_active_ports(p_ca_obj); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("This test routing atleast 1 active port on the 1st hca\n")); + break; + } + + /* + * Create the necessary resource PD/QP/QP + */ + ib_status = mad_create_spl_resources( + p_ca_obj, + IB_QPT_QP0_ALIAS, + IB_MCLASS_SUBN_LID, + ALTS_TEST_MGMT_CLASS_VER, + mad_svc_send_cb, + mad_svc_recv_cb ); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("mad_create_spl_resources() failed with status %d\n", ib_status)); + break; + } + + /* + * Start Message passing activity + */ + ib_status = alts_spl_message_passing(p_ca_obj); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_spl_message_passing failed with status %d\n", ib_status)); + break; + } + + cl_thread_suspend(1000); /* 1 sec */ + + if (p_ca_obj->cq_done == 2) + ib_status = IB_SUCCESS; + else + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("errors: send(%d) recv(%d)\n", + p_ca_obj->send_done_error, p_ca_obj->recv_done_error)); + + ib_status = IB_ERROR; + } + + } while (0); + + /* + * Destroy the resources + */ + ib_status2 = alts_spl_destroy_resources(p_ca_obj); + if (ib_status == IB_SUCCESS) + ib_status = ib_status2; + + if (p_ca_attr) + cl_free(p_ca_attr); + + if (p_ca_obj) + cl_free(p_ca_obj); + + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + +ib_api_status_t +alts_qp0_2_ports( + ib_ca_handle_t h_ca, + uint32_t ca_attr_size ) +{ + ib_api_status_t ib_status = IB_ERROR, ib_status2; + uint32_t bsize; + alts_mad_ca_obj_t *p_ca_obj = NULL; + ib_ca_attr_t *p_ca_attr = NULL; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + CL_ASSERT (h_ca); + CL_ASSERT (ca_attr_size); + + do + { + p_ca_obj = (alts_mad_ca_obj_t*)cl_zalloc(sizeof(alts_mad_ca_obj_t)); + if (!p_ca_obj) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("zalloc() failed for alts_mad_ca_obj_t!\n") ); + break; + } + + /* Allocate the memory needed for query_ca */ + bsize = ca_attr_size; + p_ca_attr = (ib_ca_attr_t *)cl_zalloc(bsize); + if (!p_ca_attr) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("zalloc() failed for p_ca_attr!\n") ); + break; + } + + ib_status = ib_query_ca(h_ca, p_ca_attr, &bsize); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_query_ca failed with status = %d\n", ib_status) ); + break; + } + + /* + * Initialize the CA Object + */ + p_ca_obj->h_ca = h_ca; + p_ca_obj->p_ca_attr = p_ca_attr; + p_ca_obj->status = IB_SUCCESS; + p_ca_obj->cq_size = 255*2; + p_ca_obj->qkey = 0; + p_ca_obj->ds_list_depth = 1; + p_ca_obj->num_wrs = 1; + p_ca_obj->msg_size = 256; + + p_ca_obj->src_qp_num = IB_QP0; + p_ca_obj->is_loopback = FALSE; + + p_ca_obj->reply_requested = FALSE; + + /* + * get an active port + */ + ib_status = alts_mad_check_active_ports(p_ca_obj); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("This test routing atleast 1 active port on the 1st hca\n")); + break; + } + + /* + * Create the necessary resource PD/QP/QP + */ + ib_status = mad_create_spl_resources( + p_ca_obj, + IB_QPT_QP0_ALIAS, + IB_MCLASS_SUBN_LID, + ALTS_TEST_MGMT_CLASS_VER, + mad_svc_send_cb, + mad_svc_recv_cb ); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("mad_create_spl_resources() failed with status %d\n", ib_status)); + break; + } + + /* + * Start Message passing activity + */ + ib_status = alts_spl_message_passing(p_ca_obj); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_spl_message_passing failed with status %d\n", ib_status)); + break; + } + + cl_thread_suspend(1000); /* 1 sec */ + + if (p_ca_obj->cq_done == 2) + ib_status = IB_SUCCESS; + else + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("errors: send(%d) recv(%d)\n", + p_ca_obj->send_done_error, p_ca_obj->recv_done_error)); + + ib_status = IB_ERROR; + } + + } while (0); + + /* + * Destroy the resources + */ + ib_status2 = alts_spl_destroy_resources(p_ca_obj); + if (ib_status == IB_SUCCESS) + ib_status = ib_status2; + + if (p_ca_attr) + cl_free(p_ca_attr); + + if (p_ca_obj) + cl_free(p_ca_obj); + + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + +ib_api_status_t +alts_qp0_2_ports_100( + ib_ca_handle_t h_ca, + uint32_t ca_attr_size ) +{ + ib_api_status_t ib_status = IB_ERROR, ib_status2; + uint32_t bsize; + alts_mad_ca_obj_t *p_ca_obj = NULL; + ib_ca_attr_t *p_ca_attr = NULL; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + CL_ASSERT (h_ca); + CL_ASSERT (ca_attr_size); + + do + { + p_ca_obj = (alts_mad_ca_obj_t*)cl_zalloc(sizeof(alts_mad_ca_obj_t)); + if (!p_ca_obj) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("zalloc() failed for alts_mad_ca_obj_t!\n") ); + break; + } + + /* Allocate the memory needed for query_ca */ + bsize = ca_attr_size; + p_ca_attr = (ib_ca_attr_t *)cl_zalloc(bsize); + if (!p_ca_attr) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("zalloc() failed for p_ca_attr!\n") ); + break; + } + + ib_status = ib_query_ca(h_ca, p_ca_attr, &bsize); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_query_ca failed with status = %d\n", ib_status) ); + break; + } + + /* + * Initialize the CA Object + */ + p_ca_obj->h_ca = h_ca; + p_ca_obj->p_ca_attr = p_ca_attr; + p_ca_obj->status = IB_SUCCESS; + p_ca_obj->cq_size = 255*2; + p_ca_obj->qkey = 0; + p_ca_obj->ds_list_depth = 1; + p_ca_obj->num_wrs = 100; + p_ca_obj->msg_size = 256; + + p_ca_obj->src_qp_num = IB_QP0; + p_ca_obj->is_loopback = FALSE; + + p_ca_obj->reply_requested = FALSE; + + /* + * get an active port + */ + ib_status = alts_mad_check_active_ports(p_ca_obj); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("This test routing atleast 1 active port on the 1st hca\n")); + break; + } + + /* + * Create the necessary resource PD/QP/QP + */ + ib_status = mad_create_spl_resources( + p_ca_obj, + IB_QPT_QP0_ALIAS, + IB_MCLASS_SUBN_LID, + ALTS_TEST_MGMT_CLASS_VER, + mad_svc_send_cb, + mad_svc_recv_cb ); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("mad_create_spl_resources() failed with status %d\n", ib_status)); + break; + } + + /* + * Start Message passing activity + */ + ib_status = alts_spl_message_passing(p_ca_obj); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_spl_message_passing failed with status %d\n", ib_status)); + break; + } + + cl_thread_suspend(1000); /* 1 sec */ + + if (p_ca_obj->cq_done == 200) + ib_status = IB_SUCCESS; + else + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("errors: send(%d) recv(%d)\n", + p_ca_obj->send_done_error, p_ca_obj->recv_done_error)); + + ib_status = IB_ERROR; + } + + } while (0); + + /* + * Destroy the resources + */ + ib_status2 = alts_spl_destroy_resources(p_ca_obj); + if (ib_status == IB_SUCCESS) + ib_status = ib_status2; + + if (p_ca_attr) + cl_free(p_ca_attr); + + if (p_ca_obj) + cl_free(p_ca_obj); + + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + +ib_api_status_t +alts_qp0_pingpong( + ib_ca_handle_t h_ca, + uint32_t ca_attr_size ) +{ + ib_api_status_t ib_status = IB_ERROR, ib_status2; + uint32_t bsize; + alts_mad_ca_obj_t *p_ca_obj = NULL; + ib_ca_attr_t *p_ca_attr = NULL; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + CL_ASSERT (h_ca); + CL_ASSERT (ca_attr_size); + + do + { + p_ca_obj = (alts_mad_ca_obj_t*)cl_zalloc(sizeof(alts_mad_ca_obj_t)); + if (!p_ca_obj) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("zalloc() failed for alts_mad_ca_obj_t!\n") ); + break; + } + + /* Allocate the memory needed for query_ca */ + bsize = ca_attr_size; + p_ca_attr = (ib_ca_attr_t *)cl_zalloc(bsize); + if (!p_ca_attr) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("zalloc() failed for p_ca_attr!\n") ); + break; + } + + ib_status = ib_query_ca(h_ca, p_ca_attr, &bsize); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_query_ca failed with status = %d\n", ib_status) ); + break; + } + + /* + * Initialize the CA Object + */ + p_ca_obj->h_ca = h_ca; + p_ca_obj->p_ca_attr = p_ca_attr; + p_ca_obj->status = IB_SUCCESS; + p_ca_obj->cq_size = 255*2; + p_ca_obj->qkey = 0; + p_ca_obj->ds_list_depth = 1; + p_ca_obj->num_wrs = 1; + p_ca_obj->msg_size = 256; + + p_ca_obj->src_qp_num = IB_QP0; + p_ca_obj->is_loopback = FALSE; + + p_ca_obj->reply_requested = TRUE; // we need a reply + + /* + * get an active port + */ + ib_status = alts_mad_check_active_ports(p_ca_obj); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("This test routing atleast 1 active port on the 1st hca\n")); + break; + } + + /* + * Create the necessary resource PD/QP/QP + */ + ib_status = mad_create_spl_resources( + p_ca_obj, + IB_QPT_QP0_ALIAS, + IB_MCLASS_SUBN_LID, + ALTS_TEST_MGMT_CLASS_VER, + mad_svc_send_cb, + mad_svc_recv_cb ); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("mad_create_spl_resources() failed with status %d\n", ib_status)); + break; + } + + /* + * Start Message passing activity + */ + ib_status = alts_spl_message_passing(p_ca_obj); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_spl_message_passing failed with status %d\n", ib_status)); + break; + } + + cl_thread_suspend(1000); /* 1 sec */ + + if (p_ca_obj->cq_done == 4) + ib_status = IB_SUCCESS; + else + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("errors: send(%d) recv(%d)\n", + p_ca_obj->send_done_error, p_ca_obj->recv_done_error)); + + ib_status = IB_ERROR; + } + + } while (0); + + /* + * Destroy the resources + */ + ib_status2 = alts_spl_destroy_resources(p_ca_obj); + if (ib_status == IB_SUCCESS) + ib_status = ib_status2; + + if (p_ca_attr) + cl_free(p_ca_attr); + + if (p_ca_obj) + cl_free(p_ca_obj); + + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + + + +ib_api_status_t +alts_qp0_ping_switch ( + ib_ca_handle_t h_ca, + uint32_t ca_attr_size ) +{ + ib_api_status_t ib_status = IB_ERROR, ib_status2; + uint32_t bsize; + alts_mad_ca_obj_t *p_ca_obj = NULL; + ib_ca_attr_t *p_ca_attr = NULL; + + ib_port_attr_t *p_src_port_attr = NULL; + ib_port_attr_t *p_dest_port_attr = NULL; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + CL_ASSERT (h_ca); + CL_ASSERT (ca_attr_size); + + do + { + p_ca_obj = (alts_mad_ca_obj_t*)cl_zalloc(sizeof(alts_mad_ca_obj_t)); + if (!p_ca_obj) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("zalloc() failed for alts_mad_ca_obj_t!\n") ); + break; + } + + /* Allocate the memory needed for query_ca */ + bsize = ca_attr_size; + p_ca_attr = (ib_ca_attr_t *)cl_zalloc(bsize); + if (!p_ca_attr) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("zalloc() failed for p_ca_attr!\n") ); + break; + } + + ib_status = ib_query_ca(h_ca, p_ca_attr, &bsize); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_query_ca failed with status = %d\n", ib_status) ); + break; + } + + /* + * Initialize the CA Object + */ + p_ca_obj->h_ca = h_ca; + p_ca_obj->p_ca_attr = p_ca_attr; + p_ca_obj->status = IB_SUCCESS; + p_ca_obj->cq_size = 255*2; + p_ca_obj->qkey = 0; + p_ca_obj->ds_list_depth = 1; + p_ca_obj->num_wrs = 1; + p_ca_obj->msg_size = 256; + + p_ca_obj->src_qp_num = IB_QP0; + p_ca_obj->is_loopback = TRUE; + + p_ca_obj->reply_requested = TRUE; + + // set the out port to be the last port + p_src_port_attr = &p_ca_attr->p_port_attr[p_ca_attr->num_ports-1]; + + if (p_src_port_attr->link_state == 0) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("This test requires the last port of HCA connected to a switch.\n")); + + ib_status = IB_ERROR; + break; + } + + // reset src and dest + p_dest_port_attr = p_src_port_attr; + + p_ca_obj->p_dest_port_attr = p_dest_port_attr; + p_ca_obj->p_src_port_attr = p_src_port_attr; + + p_ca_obj->dlid = p_dest_port_attr->lid; + p_ca_obj->slid = p_src_port_attr->lid; + + p_ca_obj->dest_portguid = p_dest_port_attr->port_guid; + p_ca_obj->src_portguid = p_src_port_attr->port_guid; + + p_ca_obj->dest_port_num = p_dest_port_attr->port_num; + p_ca_obj->src_port_num = p_src_port_attr->port_num; + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("**** slid = x%x (x%x) ***dlid = x%x (x%x) ***************\n", + p_ca_obj->slid, + CL_NTOH16(p_ca_obj->slid), + p_ca_obj->dlid, + CL_NTOH16(p_ca_obj->dlid) )); + + + /* + * Create the necessary resource PD/QP/QP + */ + ib_status = mad_create_spl_resources( + p_ca_obj, + IB_QPT_QP0_ALIAS, + IB_MCLASS_SUBN_DIR, + ALTS_TEST_MGMT_CLASS_VER, + mad_svc_send_cb, + mad_svc_recv_cb ); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("mad_create_spl_resources() failed with status %d\n", ib_status)); + break; + } + + /* + * Start Message passing activity + */ + ib_status = alts_qp0_msg_at_hc(p_ca_obj, 1); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_spl_message_passing failed with status %d\n", ib_status)); + break; + } + + cl_thread_suspend(1000); /* 1 sec */ + + if (p_ca_obj->cq_done == 2) + ib_status = IB_SUCCESS; + else + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("errors: send(%d) recv(%d)\n", + p_ca_obj->send_done_error, p_ca_obj->recv_done_error)); + + ib_status = IB_ERROR; + } + + } while (0); + + /* + * Destroy the resources + */ + ib_status2 = alts_spl_destroy_resources(p_ca_obj); + if (ib_status == IB_SUCCESS) + ib_status = ib_status2; + + if (p_ca_attr) + cl_free(p_ca_attr); + + if (p_ca_obj) + cl_free(p_ca_obj); + + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} diff --git a/branches/WOF2-3/tests/alts/multisendrecv.c b/branches/WOF2-3/tests/alts/multisendrecv.c new file mode 100644 index 00000000..5ca95db6 --- /dev/null +++ b/branches/WOF2-3/tests/alts/multisendrecv.c @@ -0,0 +1,2369 @@ +/* +* Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + +/* + * Abstract: + * Multisendrecv test does a data transfer between two queue pairs created one + * on each port of the hca. In order for this test to work, two ports of the hca + * should be connected in a loop back and must be configured to ACTIVE PORT STATE. + * + * + * Environment: + * All + */ + + +#include +#include +#include +#include +#include +#include + +/* Parameters */ + +#define TestUD1 1 +#define TestRC1 2 + +#define MAX_QPS 8 +#define SRC_QP 0 +#define DEST_QP 1 + + +typedef struct _alts_multisr_ca_obj +{ + ib_api_status_t status; + uint32_t test_type; + + ib_ca_handle_t h_ca; + ib_ca_attr_t *p_ca_attr; + ib_port_attr_t *p_src_port_attr; + ib_port_attr_t *p_dest_port_attr; + + ib_net64_t src_portguid; + uint8_t src_port_num; + + ib_net64_t dest_portguid; + uint8_t dest_port_num; + + ib_net16_t slid; + ib_net16_t dlid; + + ib_cq_handle_t h_cq; + uint32_t cq_size; + + ib_pd_handle_t h_pd; + + ib_qp_handle_t h_qp[MAX_QPS]; + ib_net32_t qkey; + + ib_qp_attr_t qp_attr[MAX_QPS]; + + + ib_send_wr_t *p_send_wr; + ib_recv_wr_t *p_recv_wr; + size_t wr_send_size; + size_t wr_recv_size; + uint32_t num_wrs; + uint32_t ds_list_depth; + uint32_t msg_size; // Initialize this field + + ib_av_handle_t h_av_src; + mem_region_t mem_region[200]; + + uint32_t cq_done; // total completions + boolean_t is_src; + boolean_t is_loopback; + +} alts_multisr_ca_obj_t; + + + +/* + * Function Prototypes + */ + +ib_api_status_t +alts_check_active_ports( + alts_multisr_ca_obj_t *p_ca_obj ); + +ib_api_status_t +alts_create_resources( + alts_multisr_ca_obj_t *p_ca_obj ); + +ib_api_status_t +alts_activate_qp( + alts_multisr_ca_obj_t *p_ca_obj, + ib_qp_handle_t h_qp ); + +ib_api_status_t +alts_destroy_resources( + alts_multisr_ca_obj_t *p_ca_obj ); + +ib_api_status_t +alts_register_mem( + alts_multisr_ca_obj_t *p_ca_obj, + uint32_t reg_index, + uint32_t size ); + +ib_api_status_t +alts_deregister_mem( + alts_multisr_ca_obj_t *p_ca_obj, + uint32_t reg_index ); + +ib_api_status_t +multisend_post_sends( + alts_multisr_ca_obj_t *p_ca_obj, + uint32_t reg_index, + uint32_t num_post ); + +ib_api_status_t +multisend_post_recvs( + alts_multisr_ca_obj_t *p_ca_obj, + uint32_t reg_index, + uint32_t num_post ); + +void +multisend_cq_destroy_cb( + void *context ); + +void +multisend_pd_destroy_cb( + void *context ); + +void +multisend_qp_destroy_cb( + void *context ); + +/* + * CQ completion callback function + */ + +void +multisend_cq_comp_cb( + void *cq_context, + ib_qp_type_t qp_type); + +void +ud_multisend_cq_comp_cb( + IN const ib_cq_handle_t h_cq, + IN void *cq_context ); + +void +rc_multisend_cq_comp_cb( + IN const ib_cq_handle_t h_cq, + IN void *cq_context ); +/* + * CQ Error callback function + */ + +void +multisend_cq_err_cb( + ib_async_event_rec_t *p_err_rec ); + +/* + * QP Error callback function + */ +void +multisend_qp_err_cb( + ib_async_event_rec_t *p_err_rec ); + +ib_api_status_t +alts_ud_loopback ( + ib_ca_handle_t h_ca, + uint32_t ca_attr_size ); + +ib_api_status_t +alts_ud_2_ports ( + ib_ca_handle_t h_ca, + uint32_t ca_attr_size ); + +ib_api_status_t +alts_ud_2_ports_100_msgs ( + ib_ca_handle_t h_ca, + uint32_t ca_attr_size ); + +ib_api_status_t +alts_rc_loopback ( + ib_ca_handle_t h_ca, + uint32_t ca_attr_size ); + +ib_api_status_t +alts_rc_2_ports ( + ib_ca_handle_t h_ca, + uint32_t ca_attr_size ); + +ib_api_status_t +alts_rc_2_ports_100_msgs ( + ib_ca_handle_t h_ca, + uint32_t ca_attr_size ); + +/* + * Gloabal Variables + */ +ib_send_wr_t send_wr; +ib_recv_wr_t recv_wr; +ib_local_ds_t send_ds; +ib_local_ds_t recv_ds; +ib_cq_create_t cq_create_attr; +ib_qp_create_t qp_create_attr; +ib_av_attr_t av_attr; +ib_mr_create_t mr_create = {0}; +ib_wc_t free_wclist; +ib_wc_t free_wcl; + +ib_api_status_t ud_loopback=IB_NOT_FOUND, ud_2_ports=IB_NOT_FOUND; +ib_api_status_t rc_loopback=IB_NOT_FOUND, rc_2_ports=IB_NOT_FOUND; +ib_api_status_t ud_2_ports_100=IB_NOT_FOUND, rc_2_ports_100=IB_NOT_FOUND; + +//extern uint32_t g_al_dbg_lvl; + +/* This test case assumes that the HCA has 2 port connected + * through the switch. Sends packets from lower port number to higher + * port number. + */ +ib_api_status_t +al_test_multi_send_recv(void) +{ + ib_api_status_t ib_status = IB_ERROR; + ib_al_handle_t h_al; + ib_ca_handle_t h_ca = NULL; + uint32_t bsize; + ib_ca_attr_t *p_ca_attr = NULL; + //alts_multisr_ca_obj_t ca_obj; // for testing stack + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + do + { + /* + * Open the AL interface + */ + ib_status = alts_open_al(&h_al); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_open_al failed status = %d", ib_status) ); + break; + } + + /* + * Default opens the first CA + */ + ib_status = alts_open_ca(h_al, &h_ca); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_open_ca failed status = %d", ib_status) ); + break; + } + + /* + * Get the CA Attributest + * Check for two active ports + */ + + /* + * Query the CA + */ + bsize = 0; + ib_status = ib_query_ca(h_ca, NULL, &bsize); + if(ib_status != IB_INSUFFICIENT_MEMORY) + { + ALTS_PRINT(ALTS_DBG_ERROR, + ("ib_query_ca failed with status = %d\n", ib_status) ); + break; + } + CL_ASSERT(bsize); + + /* run all tests in succession */ + ib_status = alts_ud_loopback(h_ca, bsize); + ud_loopback = ib_status; + if (ib_status != IB_SUCCESS) + { + ALTS_PRINT(ALTS_DBG_ERROR, + ("alts_ud_loopback failed with status = %d\n", ib_status) ); + + break; + } + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("alts_ud_loopback passed.\n") ); + + ib_status = alts_ud_2_ports(h_ca, bsize); + ud_2_ports = ib_status; + if (ib_status != IB_SUCCESS) + { + ALTS_PRINT(ALTS_DBG_ERROR, + ("alts_ud_2_ports failed with status = %d\n", ib_status) ); + break; + } + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("alts_ud_2_ports passed.\n") ); + + ib_status = alts_ud_2_ports_100_msgs(h_ca, bsize); + ud_2_ports_100 = ib_status; + if (ib_status != IB_SUCCESS) + { + ALTS_PRINT(ALTS_DBG_ERROR, + ("alts_ud_2_ports_100_msgs failed with status = %d\n", + ib_status) ); + break; + } + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("alts_ud_2_ports_100_msgs passed.\n") ); + +//#if 0 + /********* + ********* + Note for Mellanox & other HCA's: + + enable this test to test rc loopback on the same QP + ********/ + + ib_status = alts_rc_loopback(h_ca, bsize); + rc_loopback = ib_status; + if (ib_status != IB_SUCCESS) + { + ALTS_PRINT(ALTS_DBG_ERROR, + ("alts_rc_loopback failed with status = %d\n", ib_status) ); + break; + } + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("alts_rc_loopback passed.\n") ); +//#endif + + ib_status = alts_rc_2_ports(h_ca, bsize); + rc_2_ports = ib_status; + if (ib_status != IB_SUCCESS) + { + ALTS_PRINT(ALTS_DBG_ERROR, + ("alts_rc_2_ports failed with status = %d\n", ib_status) ); + break; + } + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("alts_rc_2_ports passed.\n") ); + + ib_status = alts_rc_2_ports_100_msgs(h_ca, bsize); + rc_2_ports_100 = ib_status; + if (ib_status != IB_SUCCESS) + { + ALTS_PRINT(ALTS_DBG_ERROR, + ("alts_rc_2_ports_100_msgs failed with status = %d\n", + ib_status) ); + break; + } + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("alts_rc_2_ports_100_msgs passed.\n") ); + + } while (0); + + /* Destroy the resources*/ + if (p_ca_attr) + cl_free(p_ca_attr); + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("Test results (MultiSend):\n" + "\tud_loopback..........: %s\n" + "\tud_2_ports...........: %s\n" + "\tud_2_ports_100_msgs..: %s\n" + "\trc_loopback..........: %s\n" + "\trc_2_ports...........: %s\n" + "\trc_2_ports_100_msgs..: %s\n", + ib_get_err_str(ud_loopback), + ib_get_err_str(ud_2_ports), + ib_get_err_str(ud_2_ports_100), + ib_get_err_str(rc_loopback), + ib_get_err_str(rc_2_ports), + ib_get_err_str(rc_2_ports_100) + )); + + alts_close_ca(h_ca); + alts_close_al(h_al); + + ALTS_EXIT( ALTS_DBG_VERBOSE); + + return ib_status; + +} + +ib_api_status_t +alts_destroy_resources( + alts_multisr_ca_obj_t *p_ca_obj) +{ + uint32_t j; + + /* + * Destroy Send QP, Recv QP, CQ and PD + */ + ib_api_status_t ib_status = IB_SUCCESS; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + if (p_ca_obj->h_qp[SRC_QP]) + { + ib_status = ib_destroy_qp(p_ca_obj->h_qp[SRC_QP],multisend_qp_destroy_cb); + } + + if (p_ca_obj->is_loopback != TRUE) + { + if (p_ca_obj->h_qp[DEST_QP]) + { + ib_status = ib_destroy_qp( + p_ca_obj->h_qp[DEST_QP], + multisend_qp_destroy_cb); + } + } + + if (p_ca_obj->h_cq) + ib_status = ib_destroy_cq(p_ca_obj->h_cq,multisend_cq_destroy_cb); + + /* + * Deregister the Memeory + */ + for(j=0; j < p_ca_obj->num_wrs * 2; j++) + { + if(p_ca_obj->mem_region[j].buffer != NULL) + ib_status = alts_deregister_mem(p_ca_obj, j); + } + + if (p_ca_obj->h_pd) + ib_status = ib_dealloc_pd(p_ca_obj->h_pd,multisend_pd_destroy_cb); + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + +ib_api_status_t +alts_message_passing( + alts_multisr_ca_obj_t *p_ca_obj, + ib_qp_type_t qp_type ) +{ + uint32_t i,j, k; + ib_api_status_t ib_status = IB_SUCCESS; +//#if 0 + ib_wc_t *p_free_wclist; + ib_wc_t *p_done_cl; + uint32_t id; + char *buff; +//#endif + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + + p_ca_obj->wr_send_size = sizeof(ib_send_wr_t) + \ + (sizeof(ib_local_ds_t) * p_ca_obj->ds_list_depth); + p_ca_obj->wr_recv_size = sizeof(ib_recv_wr_t) + \ + (sizeof(ib_local_ds_t) * p_ca_obj->ds_list_depth); + + p_ca_obj->p_send_wr = &send_wr; + p_ca_obj->p_recv_wr = &recv_wr; + + p_ca_obj->p_send_wr->ds_array = &send_ds; + p_ca_obj->p_recv_wr->ds_array = &recv_ds; + + // receive + for (i=0; i < p_ca_obj->num_wrs; i++) + { + ib_status = alts_register_mem( p_ca_obj, i, 4096); + + if ( ib_status != IB_SUCCESS ) + { + for(j=0; jmem_region[i].my_lid = p_ca_obj->dlid; + } + } + + if(ib_status != IB_SUCCESS) + return ib_status; + + // send + for (k=i; k < i + p_ca_obj->num_wrs; k++) + { + ib_status = alts_register_mem( p_ca_obj, k, 4096); + + if ( ib_status != IB_SUCCESS ) + { + for(j=i; jmem_region[k].my_lid = p_ca_obj->slid; + } + } + + if(ib_status != IB_SUCCESS) + return ib_status; + + + //Create an Address vector + av_attr.dlid = p_ca_obj->dlid; + av_attr.port_num = p_ca_obj->src_port_num; + av_attr.sl = 0; + av_attr.path_bits = 0; + av_attr.static_rate = IB_PATH_RECORD_RATE_10_GBS; + av_attr.grh_valid = FALSE; + + ib_status = ib_create_av(p_ca_obj->h_pd,&av_attr,&p_ca_obj->h_av_src); + if(ib_status != IB_SUCCESS) + return ib_status; + + p_ca_obj->cq_done = 0; + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("++++++ dlid(x%x) src_port(%d) ====\n", + av_attr.dlid, av_attr.port_num)); + + if(ib_status == IB_SUCCESS) + { + multisend_post_recvs( p_ca_obj, 0, p_ca_obj->num_wrs ); + multisend_post_sends( p_ca_obj, p_ca_obj->num_wrs, p_ca_obj->num_wrs ); +#if 0 + for ( i = 0 ; i < p_ca_obj->num_wrs; ++i) + { + multisend_post_recvs( p_ca_obj, i, p_ca_obj->num_wrs ); + } + + for ( k = i ; k < i + p_ca_obj->num_wrs; ++k) + { + multisend_post_sends( p_ca_obj, k, p_ca_obj->num_wrs ); + } +#endif + } + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("sleeping for awhile ...\n")); + +// cl_thread_suspend(10000); // 10 seconds + + while (((!p_ca_obj->cq_done) && (p_ca_obj->num_wrs> 2)) || + (p_ca_obj->cq_done != p_ca_obj->num_wrs*2)) + { + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("sleeping for awhile ...\n")); + cl_thread_suspend(0); // 10 seconds + } + + + //if (((!p_ca_obj->cq_done) && (p_ca_obj->num_wrs> 2)) || + // (p_ca_obj->cq_done != p_ca_obj->num_wrs*2)) + //{ + // ALTS_PRINT(ALTS_DBG_VERBOSE, + // ("sleeping for awhile ...\n")); + // cl_thread_suspend(10000); // 10 seconds + //} + + //if (((!p_ca_obj->cq_done) && (p_ca_obj->num_wrs> 2)) || + // (p_ca_obj->cq_done != p_ca_obj->num_wrs*2)) + //{ + // ALTS_PRINT(ALTS_DBG_VERBOSE, + // ("sleeping for awhile ...\n")); + // cl_thread_suspend(10000); // 10 seconds + //} + +//#if 0 + + if (!p_ca_obj->cq_done) + { + p_free_wclist = &free_wclist; + p_free_wclist->p_next = NULL; + p_done_cl = NULL; + i = 0; + + ib_status = ib_poll_cq(p_ca_obj->h_cq, &p_free_wclist, &p_done_cl); + + while(p_done_cl) + { + /* + * print output + */ + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("Got a completion:\n" + "\ttype....:%s\n" + "\twr_id...:%"PRIx64"\n", + ib_get_wc_type_str(p_done_cl->wc_type), + p_done_cl->wr_id )); + + if (p_done_cl->wc_type == IB_WC_RECV) + { + id = (uint32_t)p_done_cl->wr_id; + buff = (char *)p_ca_obj->mem_region[id].buffer; + if (qp_type == IB_QPT_UNRELIABLE_DGRM) + { + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("---MSG--->%s\n",&buff[40])); + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("RecvUD info:\n" + "\trecv_opt...:x%x\n" + "\timm_data...:x%x\n" + "\tremote_qp..:x%x\n" + "\tpkey_index.:%d\n" + "\tremote_lid.:x%x\n" + "\tremote_sl..:x%x\n" + "\tpath_bits..:x%x\n" + "\tsrc_lid....:x%x\n", + p_done_cl->recv.ud.recv_opt, + p_done_cl->recv.ud.immediate_data, + CL_NTOH32(p_done_cl->recv.ud.remote_qp), + p_done_cl->recv.ud.pkey_index, + CL_NTOH16(p_done_cl->recv.ud.remote_lid), + p_done_cl->recv.ud.remote_sl, + p_done_cl->recv.ud.path_bits, + CL_NTOH16(p_ca_obj->mem_region[id].my_lid))); + } + else + { + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("RecvRC info:\n" + "\trecv_opt...:x%x\n" + "\timm_data...:x%x\n", + p_done_cl->recv.conn.recv_opt, + p_done_cl->recv.ud.immediate_data )); + } + + } + + p_free_wclist = p_done_cl; + p_free_wclist->p_next = NULL; + p_done_cl = NULL; + i++; + p_done_cl = NULL; + ib_status = ib_poll_cq(p_ca_obj->h_cq, &p_free_wclist, &p_done_cl); + } + + ALTS_PRINT( ALTS_DBG_INFO, + ("Number of items polled from CQ is = %d\n", i) ); + + p_ca_obj->cq_done += i; + + ib_status = IB_SUCCESS; + } +//#endif + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + + +ib_api_status_t +multisend_post_sends( + alts_multisr_ca_obj_t *p_ca_obj, + uint32_t reg_index, + uint32_t num_posts ) +{ + ib_send_wr_t *p_s_wr, *p_send_failure_wr; + uint32_t msg_size, i; + ib_api_status_t ib_status = IB_SUCCESS; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + if (p_ca_obj->test_type == TestUD1) + msg_size = p_ca_obj->msg_size - sizeof(ib_grh_t); + else + msg_size = 64; + + //msg_size = p_ca_obj->msg_size; + + msg_size = 64; + + p_s_wr = p_ca_obj->p_send_wr; + + p_s_wr->p_next = NULL; + p_s_wr->ds_array[0].length = msg_size; + p_s_wr->num_ds = 1; + + p_s_wr->wr_type = WR_SEND; + + if (p_ca_obj->test_type == TestUD1) + { + p_s_wr->dgrm.ud.h_av = p_ca_obj->h_av_src; + p_s_wr->send_opt = IB_SEND_OPT_IMMEDIATE | \ + IB_SEND_OPT_SIGNALED | IB_SEND_OPT_SOLICITED; + + p_s_wr->dgrm.ud.remote_qkey = p_ca_obj->qkey; + p_s_wr->dgrm.ud.remote_qp = p_ca_obj->qp_attr[DEST_QP].num; + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("======= qkey(x%x) qp_num(x%x) ========\n", + p_s_wr->dgrm.ud.remote_qkey, + p_s_wr->dgrm.ud.remote_qp)); + + } + else if(p_ca_obj->test_type == TestRC1) + { + p_s_wr->send_opt = IB_SEND_OPT_SIGNALED | \ + IB_SEND_OPT_IMMEDIATE | \ + IB_SEND_OPT_SOLICITED ; + + } + + + for (i = 0; i < num_posts; i++) + { + sprintf((char *)p_ca_obj->mem_region[i+reg_index].buffer,"hello %d", i); + + p_s_wr->ds_array[0].vaddr = + (uintn_t)p_ca_obj->mem_region[i+reg_index].buffer; + p_s_wr->ds_array[0].lkey = p_ca_obj->mem_region[i+reg_index].lkey; + + p_s_wr->wr_id = i+reg_index; + p_s_wr->immediate_data = 0xfeedde00 + i; + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("***** Send ******vaddr(0x%"PRIx64") lkey(0x%x) len(%d)*****\n", + (void*)(uintn_t)p_s_wr->ds_array[0].vaddr, + p_s_wr->ds_array[0].lkey, + p_s_wr->ds_array[0].length)); + + ib_status = ib_post_send( + p_ca_obj->h_qp[SRC_QP], + p_s_wr, + &p_send_failure_wr); + + } + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + +ib_api_status_t +multisend_post_recvs( + alts_multisr_ca_obj_t *p_ca_obj, + uint32_t reg_index, + uint32_t num_posts ) +{ + ib_recv_wr_t *p_r_wr, *p_failure_wr; + uint32_t msg_size, i; + ib_api_status_t ib_status = IB_SUCCESS; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + + if (p_ca_obj->test_type == TestUD1) + msg_size = p_ca_obj->msg_size; + else + msg_size = 64; + //msg_size = p_ca_obj->msg_size; + + if (p_ca_obj->test_type == TestUD1) + msg_size = 64 + sizeof(ib_grh_t); + else + msg_size = 64; + + p_r_wr = p_ca_obj->p_recv_wr; + + p_r_wr->p_next = NULL; + p_r_wr->ds_array[0].length = msg_size; + p_r_wr->num_ds = 1; + + for (i = 0; i < num_posts; i++) + { + p_r_wr->ds_array[0].vaddr = + (uintn_t)p_ca_obj->mem_region[i+reg_index].buffer; + p_r_wr->ds_array[0].lkey = p_ca_obj->mem_region[i+reg_index].lkey; + + p_r_wr->wr_id = i+reg_index; + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("***** Recv ******vaddr(0x%"PRIx64") lkey(0x%x) len(%d)*****\n", + (void*)(uintn_t)p_r_wr->ds_array[0].vaddr, + p_r_wr->ds_array[0].lkey, + p_r_wr->ds_array[0].length)); + + if (p_ca_obj->is_loopback == TRUE) + { + ib_status = ib_post_recv( + p_ca_obj->h_qp[SRC_QP], + p_r_wr, + &p_failure_wr); + } + else + { + ib_status = ib_post_recv( + p_ca_obj->h_qp[DEST_QP], + p_r_wr, + &p_failure_wr); + } + } + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + +ib_api_status_t +alts_register_mem( + alts_multisr_ca_obj_t *p_ca_obj, + uint32_t reg_index, + uint32_t size ) +{ + ib_mr_create_t mr_create = {0}; + ib_api_status_t ib_status = IB_SUCCESS; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + cl_memclr(&mr_create, sizeof(ib_mr_create_t)); + p_ca_obj->mem_region[reg_index].buffer = cl_zalloc(size); + CL_ASSERT (p_ca_obj->mem_region[reg_index].buffer); + + mr_create.vaddr = p_ca_obj->mem_region[reg_index].buffer; + mr_create.length = size; + mr_create.access_ctrl = IB_AC_LOCAL_WRITE; + + ib_status = ib_reg_mem( + p_ca_obj->h_pd, + &mr_create, + &p_ca_obj->mem_region[reg_index].lkey, + &p_ca_obj->mem_region[reg_index].rkey, + &p_ca_obj->mem_region[reg_index].mr_h); + + ALTS_EXIT( ALTS_DBG_VERBOSE); + + return ib_status; +} + +ib_api_status_t +alts_deregister_mem( + alts_multisr_ca_obj_t *p_ca_obj, + uint32_t reg_index + ) +{ + + ib_api_status_t ib_status; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + if ( p_ca_obj->mem_region[reg_index].buffer != NULL ) + { + ib_status = ib_dereg_mr(p_ca_obj->mem_region[reg_index].mr_h); + + CL_ASSERT(ib_status == IB_SUCCESS); + + if ( ib_status != IB_SUCCESS ) + { + //PRINT the error msg + } + + cl_free(p_ca_obj->mem_region[reg_index].buffer); + + p_ca_obj->mem_region[reg_index].buffer = NULL; + } + else + { + ib_status = IB_ERROR; + + } + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + + + +ib_api_status_t +alts_activate_qp( + alts_multisr_ca_obj_t *p_ca_obj, + ib_qp_handle_t h_qp + ) +{ + + ib_qp_mod_t qp_mod_attr = {0}; + ib_api_status_t ib_status; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + if(p_ca_obj->is_src == 1) + qp_mod_attr.state.init.primary_port = p_ca_obj->src_port_num; + else + qp_mod_attr.state.init.primary_port = p_ca_obj->dest_port_num; + + qp_mod_attr.state.init.qkey = p_ca_obj->qkey; + qp_mod_attr.state.init.pkey_index = 0x0; + qp_mod_attr.state.init.access_ctrl = IB_AC_LOCAL_WRITE | IB_AC_MW_BIND; + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("****INIT***** port num = %d \n", + qp_mod_attr.state.init.primary_port)); + + qp_mod_attr.req_state = IB_QPS_INIT; + ib_status = ib_modify_qp(h_qp, &qp_mod_attr); + + CL_ASSERT(ib_status == IB_SUCCESS); + + // Time to query the QP + if(p_ca_obj->is_src == 1) + { + ib_status = ib_query_qp(h_qp, + &p_ca_obj->qp_attr[SRC_QP]); + CL_ASSERT(ib_status == IB_SUCCESS); + } + else + { + ib_status = ib_query_qp(h_qp, + &p_ca_obj->qp_attr[DEST_QP]); + CL_ASSERT(ib_status == IB_SUCCESS); + } + + + // transition to RTR + cl_memclr(&qp_mod_attr, sizeof(ib_qp_mod_t)); + + qp_mod_attr.state.rtr.opts = 0; + qp_mod_attr.state.rtr.rq_psn = CL_NTOH32(0x00000001); + + switch ( p_ca_obj->test_type ) + { + case TestRC1: + qp_mod_attr.state.rtr.opts = IB_MOD_QP_PRIMARY_AV; + break; + default: + break; + } + + if (p_ca_obj->is_src == 1) + { + if (p_ca_obj->is_loopback == TRUE) + { + qp_mod_attr.state.rtr.dest_qp = p_ca_obj->qp_attr[SRC_QP].num; + qp_mod_attr.state.rtr.primary_av.port_num = p_ca_obj->src_port_num; + qp_mod_attr.state.rtr.primary_av.dlid = p_ca_obj->slid; + } + else + { + qp_mod_attr.state.rtr.dest_qp = p_ca_obj->qp_attr[DEST_QP].num; + qp_mod_attr.state.rtr.primary_av.port_num = p_ca_obj->src_port_num; + qp_mod_attr.state.rtr.primary_av.dlid = p_ca_obj->dlid; + } + } + else + { + qp_mod_attr.state.rtr.dest_qp = p_ca_obj->qp_attr[SRC_QP].num; + qp_mod_attr.state.rtr.primary_av.port_num = p_ca_obj->dest_port_num; + qp_mod_attr.state.rtr.primary_av.dlid = p_ca_obj->slid; + } + + qp_mod_attr.state.rtr.primary_av.sl = 0; + qp_mod_attr.state.rtr.primary_av.grh_valid = 0; //Set to false + + qp_mod_attr.state.rtr.primary_av.static_rate = IB_PATH_RECORD_RATE_10_GBS; + qp_mod_attr.state.rtr.primary_av.path_bits = 0; + + qp_mod_attr.state.rtr.primary_av.conn.path_mtu = 1; + qp_mod_attr.state.rtr.primary_av.conn.local_ack_timeout = 7; + qp_mod_attr.state.rtr.primary_av.conn.seq_err_retry_cnt = 7; + qp_mod_attr.state.rtr.primary_av.conn.rnr_retry_cnt = 7; + qp_mod_attr.state.rtr.rq_psn = CL_NTOH32(0x00000001); + qp_mod_attr.state.rtr.resp_res = 7; //32; + qp_mod_attr.state.rtr.rnr_nak_timeout = 7; + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("****RTR***** dlid = x%x (x%x) port_num = %d dest_qp = %d \n", + qp_mod_attr.state.rtr.primary_av.dlid, + CL_NTOH16(qp_mod_attr.state.rtr.primary_av.dlid), + qp_mod_attr.state.rtr.primary_av.port_num, + CL_NTOH32(qp_mod_attr.state.rtr.dest_qp) )); + + qp_mod_attr.req_state = IB_QPS_RTR; + ib_status = ib_modify_qp(h_qp, &qp_mod_attr); + + CL_ASSERT(ib_status == IB_SUCCESS); + + if(p_ca_obj->is_src == 1) + { + ib_status = ib_query_qp(h_qp, + &p_ca_obj->qp_attr[SRC_QP]); + } + else + { + ib_status = ib_query_qp(h_qp, + &p_ca_obj->qp_attr[DEST_QP]); + } + + cl_memclr(&qp_mod_attr, sizeof(ib_qp_mod_t)); + + qp_mod_attr.state.rts.sq_psn = CL_NTOH32(0x00000001); + + // NOTENOTE: Confirm the below time out settings + qp_mod_attr.state.rts.retry_cnt = 7; + qp_mod_attr.state.rts.rnr_retry_cnt = 7; + qp_mod_attr.state.rts.rnr_nak_timeout = 7; + qp_mod_attr.state.rts.local_ack_timeout = 7; + qp_mod_attr.state.rts.init_depth = 3; //3; + + qp_mod_attr.req_state = IB_QPS_RTS; + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("****RTS***** \n")); + ib_status = ib_modify_qp(h_qp, &qp_mod_attr); + + CL_ASSERT(ib_status == IB_SUCCESS); + + if(p_ca_obj->is_src == 1) + { + ib_status = ib_query_qp(h_qp, + &p_ca_obj->qp_attr[SRC_QP]); + CL_ASSERT(ib_status == IB_SUCCESS); + } + else + { + ib_status = ib_query_qp(h_qp, + &p_ca_obj->qp_attr[DEST_QP]); + CL_ASSERT(ib_status == IB_SUCCESS); + } + + if (p_ca_obj->is_loopback == TRUE) + { + ib_status = ib_query_qp(h_qp, + &p_ca_obj->qp_attr[DEST_QP]); + } + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return IB_SUCCESS; +} + + +ib_api_status_t +alts_check_active_ports(alts_multisr_ca_obj_t *p_ca_obj) +{ + ib_api_status_t ib_status; + ib_ca_attr_t *p_ca_attr; + ib_port_attr_t *p_src_port_attr = NULL; + ib_port_attr_t *p_dest_port_attr = NULL; + uint32_t i; + ib_port_attr_t *p_port_attr; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + CL_ASSERT(p_ca_obj); + + p_ca_attr = p_ca_obj->p_ca_attr; + + CL_ASSERT(p_ca_attr); + + for(i=0; i< p_ca_attr->num_ports; i++) + { + p_port_attr = &p_ca_attr->p_port_attr[i]; + + if (p_port_attr->link_state == IB_LINK_ACTIVE) + { + if (p_src_port_attr == NULL) + p_src_port_attr = p_port_attr; + else + if(p_dest_port_attr == NULL) + p_dest_port_attr = p_port_attr; + else + break; + } + } + + // handle loopback case + if (p_ca_obj->is_loopback == TRUE) + p_dest_port_attr = p_src_port_attr; + + if (p_src_port_attr && p_dest_port_attr) + { + p_ca_obj->p_dest_port_attr = p_dest_port_attr; + p_ca_obj->p_src_port_attr = p_src_port_attr; + + p_ca_obj->dlid = p_dest_port_attr->lid; + p_ca_obj->slid = p_src_port_attr->lid; + + p_ca_obj->dest_portguid = p_dest_port_attr->port_guid; + p_ca_obj->src_portguid = p_src_port_attr->port_guid; + + p_ca_obj->dest_port_num = p_dest_port_attr->port_num; + p_ca_obj->src_port_num = p_src_port_attr->port_num; + + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("****** slid = x%x (x%x) ***dlid = x%x (x%x) ***************\n", + p_ca_obj->slid, + CL_NTOH16(p_ca_obj->slid), + p_ca_obj->dlid, + CL_NTOH16(p_ca_obj->dlid) )); + + ib_status = IB_SUCCESS; + + } + else + { + + ib_status = IB_ERROR; + } + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + +/* + * Create the CQ, PD and QP + */ + +ib_api_status_t +alts_create_resources( alts_multisr_ca_obj_t *p_ca_obj ) +{ + ib_api_status_t ib_status; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + cl_memclr(&qp_create_attr, sizeof(ib_qp_create_t)); + + /* + * Allocate a PD + */ + ib_status = ib_alloc_pd( + p_ca_obj->h_ca, + IB_PDT_NORMAL, + p_ca_obj, //pd_context + &p_ca_obj->h_pd); + + CL_ASSERT(ib_status == IB_SUCCESS); + + /* + * Create CQ Attributes + */ + cq_create_attr.size = p_ca_obj->cq_size; + //cq_create_attr.pfn_comp_cb = multisend_cq_comp_cb; + switch ( p_ca_obj->test_type ) + { + case TestUD1: + cq_create_attr.pfn_comp_cb = ud_multisend_cq_comp_cb; + break; + case TestRC1: + cq_create_attr.pfn_comp_cb = rc_multisend_cq_comp_cb; + break; + } + cq_create_attr.h_wait_obj = NULL; + + ib_status = ib_create_cq( + p_ca_obj->h_ca, + &cq_create_attr, + p_ca_obj, + multisend_cq_err_cb, + &p_ca_obj->h_cq ); + CL_ASSERT(ib_status == IB_SUCCESS); + + + p_ca_obj->cq_size = cq_create_attr.size; + + /* + * Create QP Attributes + */ + qp_create_attr.sq_depth = p_ca_obj->num_wrs; + qp_create_attr.rq_depth = p_ca_obj->num_wrs; + qp_create_attr.sq_sge = 1; + qp_create_attr.rq_sge = 1; + qp_create_attr.h_sq_cq = p_ca_obj->h_cq; + qp_create_attr.h_rq_cq = p_ca_obj->h_cq; + + qp_create_attr.sq_signaled = TRUE; + //qp_create_attr.sq_signaled = FALSE; + + + switch ( p_ca_obj->test_type ) + { + case TestUD1: + qp_create_attr.qp_type = IB_QPT_UNRELIABLE_DGRM; + break; + + case TestRC1: + qp_create_attr.qp_type = IB_QPT_RELIABLE_CONN; + break; + + default: + break; + } + + ib_status = ib_create_qp( + p_ca_obj->h_pd, + &qp_create_attr, + p_ca_obj, + multisend_qp_err_cb, + &p_ca_obj->h_qp[SRC_QP]); + + if (ib_status != IB_SUCCESS) + { + ALTS_TRACE_EXIT(ALTS_DBG_VERBOSE, + ("Error in ib_create_qp()! %s\n", + ib_get_err_str(ib_status))); + + return (ib_status); + } + + ib_status = ib_query_qp(p_ca_obj->h_qp[SRC_QP], + &p_ca_obj->qp_attr[SRC_QP]); + + if (ib_status != IB_SUCCESS) + { + ALTS_TRACE_EXIT(ALTS_DBG_VERBOSE, + ("Error in query_qp()! %s\n", + ib_get_err_str(ib_status))); + + ib_destroy_qp(p_ca_obj->h_qp[SRC_QP],multisend_qp_destroy_cb); + return (ib_status); + } + + if (p_ca_obj->is_loopback == TRUE) + { + // do loopback on same QP + p_ca_obj->h_qp[DEST_QP] = p_ca_obj->h_qp[SRC_QP]; + } + else + { + ib_status = ib_create_qp( + p_ca_obj->h_pd, + &qp_create_attr, + p_ca_obj, + multisend_qp_err_cb, + &p_ca_obj->h_qp[DEST_QP]); + + if (ib_status != IB_SUCCESS) + { + ALTS_TRACE_EXIT(ALTS_DBG_VERBOSE, + ("Error in ib_create_qp()! %s\n", + ib_get_err_str(ib_status))); + + ib_destroy_qp(p_ca_obj->h_qp[SRC_QP],multisend_qp_destroy_cb); + return (ib_status); + } + + ib_status = ib_query_qp(p_ca_obj->h_qp[DEST_QP], + &p_ca_obj->qp_attr[DEST_QP]); + + //CL_ASSERT(ib_status == IB_SUCCESS); + if (ib_status != IB_SUCCESS) + { + ALTS_TRACE_EXIT(ALTS_DBG_VERBOSE, + ("Error in query_qp()! %s\n", + ib_get_err_str(ib_status))); + + ib_destroy_qp(p_ca_obj->h_qp[DEST_QP],multisend_qp_destroy_cb); + return (ib_status); + } + } + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + +void +multisend_cq_comp_cb( + void *cq_context, + ib_qp_type_t qp_type + ) +{ + ib_api_status_t ib_status; + uint32_t i = 0, id; + char *buff; + ib_wc_t *p_free_wcl, *p_done_cl= NULL; + alts_multisr_ca_obj_t *p_ca_obj; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + CL_ASSERT(cq_context); + + p_ca_obj = (alts_multisr_ca_obj_t *)cq_context; + + + p_free_wcl = &free_wcl; + p_free_wcl->p_next = NULL; + p_done_cl = NULL; + + ib_status = ib_poll_cq(p_ca_obj->h_cq, &p_free_wcl, &p_done_cl); + +poll_loop: + while(p_done_cl) + { + + if(p_done_cl->status != IB_WCS_SUCCESS) + { + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("Got a completion with error !!!!!!!! status = %s type=%s\n", + ib_get_wc_status_str(p_done_cl->status), + ib_get_wc_type_str( p_done_cl->wc_type))); + + } + else + { + /* + * print output + */ + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("Got a completion:\n" + "\ttype....:%s\n" + "\twr_id...:%"PRIx64"\n", + ib_get_wc_type_str(p_done_cl->wc_type), + p_done_cl->wr_id )); + + + + if (p_done_cl->wc_type == IB_WC_RECV) + { + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("message length..:%d bytes\n", + p_done_cl->length )); + + id = (uint32_t)p_done_cl->wr_id; + buff = (char *)p_ca_obj->mem_region[id].buffer; + if (qp_type == IB_QPT_UNRELIABLE_DGRM) + { + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("---MSG--->%s\n",&buff[40])); + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("RecvUD info:\n" + "\trecv_opt...:x%x\n" + "\timm_data...:x%x\n" + "\tremote_qp..:x%x\n" + "\tpkey_index.:%d\n" + "\tremote_lid.:x%x\n" + "\tremote_sl..:x%x\n" + "\tpath_bits..:x%x\n" + "\tsrc_lid....:x%x\n", + p_done_cl->recv.ud.recv_opt, + p_done_cl->recv.ud.immediate_data, + CL_NTOH32(p_done_cl->recv.ud.remote_qp), + p_done_cl->recv.ud.pkey_index, + CL_NTOH16(p_done_cl->recv.ud.remote_lid), + p_done_cl->recv.ud.remote_sl, + p_done_cl->recv.ud.path_bits, + CL_NTOH16(p_ca_obj->mem_region[id].my_lid))); + } + else + { + ALTS_PRINT(ALTS_DBG_VERBOSE, + ("RecvRC info:\n" + "\trecv_opt...:x%x\n" + "\timm_data...:x%x\n", + p_done_cl->recv.conn.recv_opt, + p_done_cl->recv.ud.immediate_data )); + } + + } + } + + p_free_wcl = p_done_cl; + p_free_wcl->p_next = NULL; + p_done_cl = NULL; + i++; + ib_status = ib_poll_cq(p_ca_obj->h_cq, &p_free_wcl, &p_done_cl); + } + + /* poll one more time to avoid a race with hw */ + ib_status = ib_rearm_cq(p_ca_obj->h_cq, TRUE); //TRUE); + if( IB_SUCCESS == ib_status ) + { + ib_status = ib_poll_cq(p_ca_obj->h_cq, &p_free_wcl, &p_done_cl); + if( p_done_cl ) + goto poll_loop; + } + + p_free_wcl = &free_wcl; + + p_ca_obj->cq_done += i; + + ALTS_PRINT( ALTS_DBG_INFO, + ("Number of items polled from CQ (in callback=%d) (total=%d)\n", + i, + p_ca_obj->cq_done) ); + + + ALTS_EXIT( ALTS_DBG_VERBOSE); +} + +void +ud_multisend_cq_comp_cb( + IN const ib_cq_handle_t h_cq, + IN void *cq_context ) +{ + UNUSED_PARAM( h_cq ); + multisend_cq_comp_cb (cq_context, IB_QPT_UNRELIABLE_DGRM ); +} + +void +rc_multisend_cq_comp_cb( + IN const ib_cq_handle_t h_cq, + IN void *cq_context ) +{ + UNUSED_PARAM( h_cq ); + multisend_cq_comp_cb (cq_context, IB_QPT_RELIABLE_CONN ); +} + +void +multisend_cq_err_cb( + ib_async_event_rec_t *p_err_rec + ) +{ + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + UNUSED_PARAM( p_err_rec ); + + ALTS_PRINT(ALTS_DBG_VERBOSE,("ERROR: Async CQ error !!!!!!!!!\n")); + + ALTS_EXIT( ALTS_DBG_VERBOSE); +} + +void +multisend_qp_err_cb( + ib_async_event_rec_t *p_err_rec + ) +{ + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + UNUSED_PARAM( p_err_rec ); + + ALTS_PRINT(ALTS_DBG_VERBOSE,("ERROR: Async QP error !!!!!!!!!\n")); + + ALTS_EXIT( ALTS_DBG_VERBOSE); +} + + +void +multisend_pd_destroy_cb( + void *context + ) +{ +/* + * PD destroy call back + */ + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + UNUSED_PARAM( context ); + + ALTS_EXIT( ALTS_DBG_VERBOSE); +} + + +void +multisend_qp_destroy_cb( + void *context + ) +{ +/* + * QP destroy call back + */ + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + UNUSED_PARAM( context ); + + ALTS_EXIT( ALTS_DBG_VERBOSE); +} + +void +multisend_cq_destroy_cb( + void *context + ) +{ +/* + * CQ destroy call back + */ + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + UNUSED_PARAM( context ); + + ALTS_EXIT( ALTS_DBG_VERBOSE); +} + +/* + * The tests + */ +ib_api_status_t +alts_ud_loopback ( + ib_ca_handle_t h_ca, + uint32_t ca_attr_size ) +{ + ib_api_status_t ib_status = IB_ERROR, ib_status2; + uint32_t bsize; + alts_multisr_ca_obj_t *p_ca_obj = NULL; + ib_ca_attr_t *p_ca_attr = NULL; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + CL_ASSERT (h_ca); + CL_ASSERT (ca_attr_size); + + do + { + p_ca_obj = (alts_multisr_ca_obj_t*)cl_zalloc(sizeof(alts_multisr_ca_obj_t)); + if (!p_ca_obj) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("zalloc() failed for alts_multisr_ca_obj_t!\n") ); + break; + } + + /* Allocate the memory needed for query_ca */ + bsize = ca_attr_size; + p_ca_attr = (ib_ca_attr_t *)cl_zalloc(bsize); + if (!p_ca_attr) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("zalloc() failed for p_ca_attr!\n") ); + break; + } + + ib_status = ib_query_ca(h_ca, p_ca_attr, &bsize); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_query_ca failed with status = %d\n", ib_status) ); + break; + } + + /* + * Initialize the CA Object + */ + p_ca_obj->h_ca = h_ca; + p_ca_obj->p_ca_attr = p_ca_attr; + p_ca_obj->status = IB_SUCCESS; + p_ca_obj->cq_size = 255*2; + p_ca_obj->qkey = 0x66; + p_ca_obj->ds_list_depth = 1; + p_ca_obj->num_wrs = 1; + p_ca_obj->msg_size = 256; + + p_ca_obj->test_type = TestUD1; + p_ca_obj->is_loopback = TRUE; + + /* + * get an active port + */ + ib_status = alts_check_active_ports(p_ca_obj); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("This test requires atleast 1 active port on the 1st hca\n")); + break; + } + + /* + * Create the necessary resource PD/CQ/QP/QP + */ + ib_status = alts_create_resources(p_ca_obj); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("Create necessary resource failed with status %d\n", ib_status)); + break; + } + + + /* + * Time to Activate the QP + */ + p_ca_obj->is_src = 1; + ib_status = alts_activate_qp(p_ca_obj, p_ca_obj->h_qp[SRC_QP]); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_activate_qp failed with status %d\n", ib_status)); + break; + } + + /* + * Rearm Q + */ + ib_status = ib_rearm_cq(p_ca_obj->h_cq, FALSE);//TRUE); + + /* + * Start Message passing activity + */ + ib_status = alts_message_passing(p_ca_obj, IB_QPT_UNRELIABLE_DGRM); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_message_passing failed with status %d\n", ib_status)); + break; + } + + +// cl_thread_suspend(1000 ); /* 1 sec */ + + if (p_ca_obj->cq_done == 2) + ib_status = IB_SUCCESS; + else + ib_status = IB_ERROR; + + } while (0); + + /* + * Destroy the resources + */ + ib_status2 = alts_destroy_resources(p_ca_obj); + if (ib_status == IB_SUCCESS) + ib_status = ib_status2; + + if (p_ca_attr) + cl_free(p_ca_attr); + + if (p_ca_obj) + cl_free(p_ca_obj); + + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + +ib_api_status_t +alts_ud_2_ports ( + ib_ca_handle_t h_ca, + uint32_t ca_attr_size ) +{ + ib_api_status_t ib_status = IB_ERROR, ib_status2; + uint32_t bsize; + alts_multisr_ca_obj_t *p_ca_obj = NULL; + ib_ca_attr_t *p_ca_attr = NULL; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + CL_ASSERT (h_ca); + CL_ASSERT (ca_attr_size); + + do + { + p_ca_obj = (alts_multisr_ca_obj_t*)cl_zalloc(sizeof(alts_multisr_ca_obj_t)); + if (!p_ca_obj) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("zalloc() failed for alts_multisr_ca_obj_t!\n") ); + break; + } + + /* Allocate the memory needed for query_ca */ + bsize = ca_attr_size; + p_ca_attr = (ib_ca_attr_t *)cl_zalloc(bsize); + if (!p_ca_attr) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("zalloc() failed for p_ca_attr!\n") ); + break; + } + + ib_status = ib_query_ca(h_ca, p_ca_attr, &bsize); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_query_ca failed with status = %d\n", ib_status) ); + break; + } + + /* + * Initialize the CA Object + */ + p_ca_obj->h_ca = h_ca; + p_ca_obj->p_ca_attr = p_ca_attr; + p_ca_obj->status = IB_SUCCESS; + p_ca_obj->cq_size = 255*2; + p_ca_obj->qkey = 0x66; + p_ca_obj->ds_list_depth = 1; + p_ca_obj->num_wrs = 1; + p_ca_obj->msg_size = 256; + + p_ca_obj->test_type = TestUD1; + p_ca_obj->is_loopback = FALSE; + + /* + * get an active port + */ + ib_status = alts_check_active_ports(p_ca_obj); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("This test requires atleast 2 active ports on the 1st hca\n")); + break; + } + + /* + * Create the necessary resource PD/CQ/QP/QP + */ + ib_status = alts_create_resources(p_ca_obj); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("Create necessary resource failed with status %d\n", ib_status)); + break; + } + + /* + * Time to Activate the QP + */ + p_ca_obj->is_src = 1; + ib_status = alts_activate_qp(p_ca_obj, p_ca_obj->h_qp[SRC_QP]); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_activate_qp failed with status %d\n", ib_status)); + break; + } + + p_ca_obj->is_src = 0; + ib_status = alts_activate_qp(p_ca_obj, p_ca_obj->h_qp[DEST_QP]); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_activate_qp failed with status %d\n", ib_status)); + break; + } + + /* + * Rearm Q + */ + ib_status = ib_rearm_cq(p_ca_obj->h_cq, FALSE);//TRUE); + + /* + * Start Message passing activity + */ + ib_status = alts_message_passing(p_ca_obj, IB_QPT_UNRELIABLE_DGRM); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_message_passing failed with status %d\n", ib_status)); + break; + } + + cl_thread_suspend(1000 ); + + if (p_ca_obj->cq_done == 2) + ib_status = IB_SUCCESS; + else + ib_status = IB_ERROR; + + } while (0); + + /* + * Destroy the resources + */ + ib_status2 = alts_destroy_resources(p_ca_obj); + if (ib_status == IB_SUCCESS) + ib_status = ib_status2; + + if (p_ca_attr) + cl_free(p_ca_attr); + + if (p_ca_obj) + cl_free(p_ca_obj); + + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + +ib_api_status_t +alts_ud_2_ports_100_msgs ( + ib_ca_handle_t h_ca, + uint32_t ca_attr_size ) +{ + ib_api_status_t ib_status = IB_ERROR, ib_status2; + uint32_t bsize; + alts_multisr_ca_obj_t *p_ca_obj = NULL; + ib_ca_attr_t *p_ca_attr = NULL; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + CL_ASSERT (h_ca); + CL_ASSERT (ca_attr_size); + + do + { + p_ca_obj = (alts_multisr_ca_obj_t*)cl_zalloc(sizeof(alts_multisr_ca_obj_t)); + if (!p_ca_obj) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("zalloc() failed for alts_multisr_ca_obj_t!\n") ); + break; + } + + /* Allocate the memory needed for query_ca */ + bsize = ca_attr_size; + p_ca_attr = (ib_ca_attr_t *)cl_zalloc(bsize); + if (!p_ca_attr) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("zalloc() failed for p_ca_attr!\n") ); + break; + } + + ib_status = ib_query_ca(h_ca, p_ca_attr, &bsize); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_query_ca failed with status = %d\n", ib_status) ); + break; + } + + /* + * Initialize the CA Object + */ + p_ca_obj->h_ca = h_ca; + p_ca_obj->p_ca_attr = p_ca_attr; + p_ca_obj->status = IB_SUCCESS; + p_ca_obj->cq_size = 255*2; + p_ca_obj->qkey = 0x66; + p_ca_obj->ds_list_depth = 1; + p_ca_obj->num_wrs = 100; + p_ca_obj->msg_size = 256; + + p_ca_obj->test_type = TestUD1; + p_ca_obj->is_loopback = FALSE; + + /* + * get an active port + */ + ib_status = alts_check_active_ports(p_ca_obj); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("This test requires atleast 2 active ports on the 1st hca\n")); + break; + } + + /* + * Create the necessary resource PD/CQ/QP/QP + */ + ib_status = alts_create_resources(p_ca_obj); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("Create necessary resource failed with status %d\n", ib_status)); + break; + } + + + /* + * Time to Activate the QP + */ + p_ca_obj->is_src = 1; + ib_status = alts_activate_qp(p_ca_obj, p_ca_obj->h_qp[SRC_QP]); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_activate_qp failed with status %d\n", ib_status)); + break; + } + + p_ca_obj->is_src = 0; + ib_status = alts_activate_qp(p_ca_obj, p_ca_obj->h_qp[DEST_QP]); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_activate_qp failed with status %d\n", ib_status)); + break; + } + + /* + * Rearm Q + */ + ib_status = ib_rearm_cq(p_ca_obj->h_cq, FALSE);//TRUE); + + /* + * Start Message passing activity + */ + ib_status = alts_message_passing(p_ca_obj, IB_QPT_UNRELIABLE_DGRM); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_message_passing failed with status %d\n", ib_status)); + break; + } + + cl_thread_suspend(1000); /* 1 sec */ + + if (p_ca_obj->cq_done == 200) + ib_status = IB_SUCCESS; + else + ib_status = IB_ERROR; + + } while (0); + + /* + * Destroy the resources + */ + ib_status2 = alts_destroy_resources(p_ca_obj); + if (ib_status == IB_SUCCESS) + ib_status = ib_status2; + + if (p_ca_attr) + cl_free(p_ca_attr); + + if (p_ca_obj) + cl_free(p_ca_obj); + + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + +ib_api_status_t +alts_rc_loopback ( + ib_ca_handle_t h_ca, + uint32_t ca_attr_size ) +{ + ib_api_status_t ib_status = IB_ERROR, ib_status2; + uint32_t bsize; + alts_multisr_ca_obj_t *p_ca_obj = NULL; + ib_ca_attr_t *p_ca_attr = NULL; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + CL_ASSERT (h_ca); + CL_ASSERT (ca_attr_size); + + do + { + p_ca_obj = (alts_multisr_ca_obj_t*)cl_zalloc(sizeof(alts_multisr_ca_obj_t)); + if (!p_ca_obj) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("zalloc() failed for alts_multisr_ca_obj_t!\n") ); + break; + } + + /* Allocate the memory needed for query_ca */ + bsize = ca_attr_size; + p_ca_attr = (ib_ca_attr_t *)cl_zalloc(bsize); + if (!p_ca_attr) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("zalloc() failed for p_ca_attr!\n") ); + break; + } + + ib_status = ib_query_ca(h_ca, p_ca_attr, &bsize); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_query_ca failed with status = %d\n", ib_status) ); + break; + } + + /* + * check for Intel early ref hardware + */ + if ((p_ca_attr->vend_id == 0x00d0b7) && + (p_ca_attr->dev_id == 0x3101) && + (p_ca_attr->revision < 2)) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("This test cannot run on this revision of the HCA hardware!!!\n")); + ib_status = IB_SUCCESS; + break; + } + + /* + * Initialize the CA Object + */ + p_ca_obj->h_ca = h_ca; + p_ca_obj->p_ca_attr = p_ca_attr; + p_ca_obj->status = IB_SUCCESS; + p_ca_obj->cq_size = 255*2; + p_ca_obj->qkey = 0x66; + p_ca_obj->ds_list_depth = 1; + p_ca_obj->num_wrs = 1; + p_ca_obj->msg_size = 256; + + p_ca_obj->test_type = TestRC1; + p_ca_obj->is_loopback = TRUE; + + /* + * get an active port + */ + ib_status = alts_check_active_ports(p_ca_obj); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("This test routing atleast 1 active port on the 1st hca\n")); + break; + } + + /* + * Create the necessary resource PD/CQ/QP/QP + */ + ib_status = alts_create_resources(p_ca_obj); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("Create necessary resource failed with status %d\n", ib_status)); + break; + } + + + /* + * Time to Activate the QP + */ + p_ca_obj->is_src = 1; + ib_status = alts_activate_qp(p_ca_obj, p_ca_obj->h_qp[SRC_QP]); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_activate_qp failed with status %d\n", ib_status)); + break; + } + + /* + * Rearm Q + */ + ib_status = ib_rearm_cq(p_ca_obj->h_cq, FALSE);//TRUE); + + /* + * Start Message passing activity + */ + ib_status = alts_message_passing(p_ca_obj, IB_QPT_RELIABLE_CONN); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_message_passing failed with status %d\n", ib_status)); + break; + } + + cl_thread_suspend(1000); /* 1 sec */ + + if (p_ca_obj->cq_done == 2) + ib_status = IB_SUCCESS; + else + ib_status = IB_ERROR; + + } while (0); + + /* + * Destroy the resources + */ + ib_status2 = alts_destroy_resources(p_ca_obj); + if (ib_status == IB_SUCCESS) + ib_status = ib_status2; + + if (p_ca_attr) + cl_free(p_ca_attr); + + if (p_ca_obj) + cl_free(p_ca_obj); + + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + + +ib_api_status_t +alts_rc_2_ports ( + ib_ca_handle_t h_ca, + uint32_t ca_attr_size ) +{ + ib_api_status_t ib_status = IB_ERROR, ib_status2; + uint32_t bsize; + alts_multisr_ca_obj_t *p_ca_obj = NULL; + ib_ca_attr_t *p_ca_attr = NULL; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + CL_ASSERT (h_ca); + CL_ASSERT (ca_attr_size); + + do + { + p_ca_obj = (alts_multisr_ca_obj_t*)cl_zalloc(sizeof(alts_multisr_ca_obj_t)); + if (!p_ca_obj) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("zalloc() failed for alts_multisr_ca_obj_t!\n") ); + break; + } + + /* Allocate the memory needed for query_ca */ + bsize = ca_attr_size; + p_ca_attr = (ib_ca_attr_t *)cl_zalloc(bsize); + if (!p_ca_attr) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("zalloc() failed for p_ca_attr!\n") ); + break; + } + + ib_status = ib_query_ca(h_ca, p_ca_attr, &bsize); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_query_ca failed with status = %d\n", ib_status) ); + break; + } + + /* + * Initialize the CA Object + */ + p_ca_obj->h_ca = h_ca; + p_ca_obj->p_ca_attr = p_ca_attr; + p_ca_obj->status = IB_SUCCESS; + p_ca_obj->cq_size = 255*2; + p_ca_obj->qkey = 0x66; + p_ca_obj->ds_list_depth = 1; + p_ca_obj->num_wrs = 1; + p_ca_obj->msg_size = 256; + + p_ca_obj->test_type = TestRC1; + p_ca_obj->is_loopback = FALSE; + + /* + * get an active port + */ + ib_status = alts_check_active_ports(p_ca_obj); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("This test requires atleast 2 active ports on the 1st hca\n")); + break; + } + + /* + * Create the necessary resource PD/CQ/QP/QP + */ + ib_status = alts_create_resources(p_ca_obj); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("Create necessary resource failed with status %d\n", ib_status)); + break; + } + + /* + * Time to Activate the QP + */ + p_ca_obj->is_src = 1; + ib_status = alts_activate_qp(p_ca_obj, p_ca_obj->h_qp[SRC_QP]); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_activate_qp failed with status %d\n", ib_status)); + break; + } + + p_ca_obj->is_src = 0; + ib_status = alts_activate_qp(p_ca_obj, p_ca_obj->h_qp[DEST_QP]); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_activate_qp failed with status %d\n", ib_status)); + break; + } + + /* + * Rearm Q + */ + ib_status = ib_rearm_cq(p_ca_obj->h_cq, FALSE);//TRUE); + + /* + * Start Message passing activity + */ + ib_status = alts_message_passing(p_ca_obj, IB_QPT_RELIABLE_CONN); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_message_passing failed with status %d\n", ib_status)); + break; + } + + cl_thread_suspend(1000); /* 1 sec */ + + if (p_ca_obj->cq_done == 2) + ib_status = IB_SUCCESS; + else + ib_status = IB_ERROR; + + } while (0); + + /* + * Destroy the resources + */ + ib_status2 = alts_destroy_resources(p_ca_obj); + if (ib_status == IB_SUCCESS) + ib_status = ib_status2; + + if (p_ca_attr) + cl_free(p_ca_attr); + + if (p_ca_obj) + cl_free(p_ca_obj); + + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + +ib_api_status_t +alts_rc_2_ports_100_msgs ( + ib_ca_handle_t h_ca, + uint32_t ca_attr_size ) +{ + ib_api_status_t ib_status = IB_ERROR, ib_status2; + uint32_t bsize; + alts_multisr_ca_obj_t *p_ca_obj = NULL; + ib_ca_attr_t *p_ca_attr = NULL; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + CL_ASSERT (h_ca); + CL_ASSERT (ca_attr_size); + + do + { + p_ca_obj = (alts_multisr_ca_obj_t*)cl_zalloc(sizeof(alts_multisr_ca_obj_t)); + if (!p_ca_obj) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("zalloc() failed for alts_multisr_ca_obj_t!\n") ); + break; + } + + /* Allocate the memory needed for query_ca */ + bsize = ca_attr_size; + p_ca_attr = (ib_ca_attr_t *)cl_zalloc(bsize); + if (!p_ca_attr) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("zalloc() failed for p_ca_attr!\n") ); + break; + } + + ib_status = ib_query_ca(h_ca, p_ca_attr, &bsize); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_query_ca failed with status = %d\n", ib_status) ); + break; + } + + /* + * Initialize the CA Object + */ + p_ca_obj->h_ca = h_ca; + p_ca_obj->p_ca_attr = p_ca_attr; + p_ca_obj->status = IB_SUCCESS; + p_ca_obj->cq_size = 255*2; + p_ca_obj->qkey = 0x66; + p_ca_obj->ds_list_depth = 1; + p_ca_obj->num_wrs = 100; + p_ca_obj->msg_size = 256; + + p_ca_obj->test_type = TestRC1; + p_ca_obj->is_loopback = FALSE; + + /* + * get an active port + */ + ib_status = alts_check_active_ports(p_ca_obj); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("This test requires atleast 2 active ports on the 1st hca\n")); + break; + } + + /* + * Create the necessary resource PD/CQ/QP/QP + */ + ib_status = alts_create_resources(p_ca_obj); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("Create necessary resource failed with status %d\n", ib_status)); + break; + } + + /* + * Time to Activate the QP + */ + p_ca_obj->is_src = 1; + ib_status = alts_activate_qp(p_ca_obj, p_ca_obj->h_qp[SRC_QP]); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_activate_qp failed with status %d\n", ib_status)); + break; + } + + p_ca_obj->is_src = 0; + ib_status = alts_activate_qp(p_ca_obj, p_ca_obj->h_qp[DEST_QP]); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_activate_qp failed with status %d\n", ib_status)); + break; + } + + /* + * Rearm Q + */ + ib_status = ib_rearm_cq(p_ca_obj->h_cq, FALSE);//TRUE); + + /* + * Start Message passing activity + */ + ib_status = alts_message_passing(p_ca_obj, IB_QPT_RELIABLE_CONN); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_message_passing failed with status %d\n", ib_status)); + break; + } + + cl_thread_suspend(1000); /* 1 sec */ + + if (p_ca_obj->cq_done == 200) + ib_status = IB_SUCCESS; + else + ib_status = IB_ERROR; + + } while (0); + + /* + * Destroy the resources + */ + ib_status2 = alts_destroy_resources(p_ca_obj); + if (ib_status == IB_SUCCESS) + ib_status = ib_status2; + + if (p_ca_attr) + cl_free(p_ca_attr); + + if (p_ca_obj) + cl_free(p_ca_obj); + + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} diff --git a/branches/WOF2-3/tests/alts/openclose.c b/branches/WOF2-3/tests/alts/openclose.c new file mode 100644 index 00000000..5b404ca0 --- /dev/null +++ b/branches/WOF2-3/tests/alts/openclose.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include +#include +#include +#include + +ib_api_status_t +al_test_openclose(void) +{ + ib_al_handle_t ph_al; + ib_api_status_t ib_status = IB_SUCCESS; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + while(1) + { + + ib_status = ib_open_al(&ph_al); + if(ib_status != IB_SUCCESS) + { + ALTS_TRACE( ALTS_DBG_ERROR, + ("ib_open_al failed status = %s\n", ib_get_err_str(ib_status)) ); + break; + } + + ALTS_PRINT( ALTS_DBG_INFO, ("ib_open_al PASSED!!!\n") ); + + cl_thread_suspend( 1000 ); + + ib_status = ib_close_al(ph_al); + + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_close_al failed status = %s\n",ib_get_err_str(ib_status))); + + break; + } + ALTS_PRINT( ALTS_DBG_INFO, ("ib_close_al PASSED!!!") ); + + break; //Break from while + } + + ALTS_EXIT( ALTS_DBG_VERBOSE ); + return ib_status; +} + + diff --git a/branches/WOF2-3/tests/alts/querycaattr.c b/branches/WOF2-3/tests/alts/querycaattr.c new file mode 100644 index 00000000..c0a02320 --- /dev/null +++ b/branches/WOF2-3/tests/alts/querycaattr.c @@ -0,0 +1,271 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include +#include +#include +#include +#include + +/* + * Function prototypes + */ + +ib_api_status_t +alts_ca_attr( + boolean_t modify_attr + ); + +/* + * Test Case QueryCaAttributes + */ + +ib_api_status_t +al_test_modifycaattr(void) +{ + boolean_t modify_ca_attr = TRUE; + + return alts_ca_attr(modify_ca_attr); +} + +ib_api_status_t +al_test_querycaattr(void) +{ + boolean_t modify_ca_attr = FALSE; + + return alts_ca_attr(modify_ca_attr); +} + + +/* Internal Functions */ + +ib_api_status_t +alts_ca_attr( + boolean_t modify_attr + ) +{ + ib_al_handle_t h_al = NULL; + ib_api_status_t ib_status = IB_SUCCESS; + ib_api_status_t ret_status = IB_SUCCESS; + size_t guid_count; + ib_net64_t ca_guid_array[ALTS_MAX_CA]; + ib_ca_attr_t *alts_ca_attr; + uintn_t i; + ib_ca_handle_t h_ca = NULL; + uint32_t bsize; + ib_port_attr_mod_t port_attr_mod; + + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + while(1) + { + /* + * Open the AL instance + */ + ib_status = ib_open_al(&h_al); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_open_al failed status = %d", ib_status) ); + ret_status = ib_status; + break; + } + + ALTS_PRINT( ALTS_DBG_INFO, ("ib_open_al PASSED.\n") ); + CL_ASSERT(h_al); + + /* + * Get the Local CA Guids + */ + ib_status = ib_get_ca_guids(h_al, NULL, &guid_count); + if(ib_status != IB_INSUFFICIENT_MEMORY) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_get_ca_guids failed status = %d\n", (uint32_t)ib_status) ); + ret_status = ib_status; + goto Cleanup1; + } + + ALTS_PRINT(ALTS_DBG_INFO, + ("Total number of CA in the sytem is %d\n",(uint32_t)guid_count)); + + /* + * If no CA's Present then return + */ + + if(guid_count == 0) + goto Cleanup1; + + // ca_guid_array holds ALTS_MAX_CA + ib_status = ib_get_ca_guids(h_al, ca_guid_array, &guid_count); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_get_ca_guids failed with status = %d\n", ib_status) ); + ret_status = ib_status; + goto Cleanup1; + } + + + + /* + * For Each CA Guid found Open the CA, + * Query the CA Attribute and close the CA + */ + for(i=0; i < guid_count; i++) + { + ALTS_PRINT(ALTS_DBG_INFO, + ("CA[%d] GUID IS 0x%" PRIx64 "\n",i,_byteswap_uint64(ca_guid_array[i])) ); + + /* Open the CA */ + ib_status = ib_open_ca(h_al, + ca_guid_array[i], + alts_ca_err_cb, + NULL, //ca_context + &h_ca); + + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, ("ib_open_ca failed with status = %d\n", ib_status) ); + ret_status = ib_status; + goto Cleanup1; + } + ALTS_PRINT(ALTS_DBG_INFO, + ("ib_open_ca passed\n")); + + + /* Query the CA */ + bsize = 0; + ib_status = ib_query_ca(h_ca, NULL, &bsize); + if(ib_status != IB_INSUFFICIENT_MEMORY) + { + ALTS_PRINT(ALTS_DBG_ERROR, ("ib_query_ca failed with status = %d\n", ib_status) ); + ret_status = ib_status; + goto Cleanup2; + } + CL_ASSERT(bsize); + + /* Allocate the memory needed for query_ca */ + + alts_ca_attr = (ib_ca_attr_t *)cl_zalloc(bsize); + CL_ASSERT(alts_ca_attr); + + ib_status = ib_query_ca(h_ca, alts_ca_attr, &bsize); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_query_ca failed with status = %d\n", ib_status) ); + ret_status = ib_status; + goto Cleanup2; + } + + /* Print_ca_attributes */ + + alts_print_ca_attr(alts_ca_attr); + + if(modify_attr) + { + port_attr_mod.pkey_ctr = 10; + port_attr_mod.qkey_ctr = 10; + + ib_status = ib_modify_ca(h_ca,alts_ca_attr->p_port_attr->port_num, + IB_CA_MOD_QKEY_CTR | IB_CA_MOD_PKEY_CTR , + &port_attr_mod); + + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_modify_ca failed with status = %d\n", ib_status) ); + ret_status = ib_status; + } + + ib_status = ib_query_ca(h_ca, alts_ca_attr, &bsize); + + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_query_ca failed with status = %d\n", ib_status) ); + goto Cleanup2; + } + + CL_ASSERT(port_attr_mod.pkey_ctr != \ + alts_ca_attr->p_port_attr->pkey_ctr); + CL_ASSERT(port_attr_mod.qkey_ctr != \ + alts_ca_attr->p_port_attr->qkey_ctr); + + } + + /* Free the memory */ + cl_free(alts_ca_attr); + alts_ca_attr = NULL; + /* Close the current open CA */ + ib_status = ib_close_ca(h_ca, alts_ca_destroy_cb); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_close_ca failed status = %d", ib_status)); + } + h_ca = NULL; + + } + +Cleanup2: + if(h_ca != NULL) + { + ib_status = ib_close_ca(h_ca, alts_ca_destroy_cb); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_close_ca failed status = %d", ib_status)); + } + } + +Cleanup1: + ib_status = ib_close_al(h_al); + + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_close_al failed status = %d", ib_status)); + } + + break; + + } //End of while(1) + + ALTS_EXIT( ALTS_DBG_VERBOSE ); + return ret_status; +} + diff --git a/branches/WOF2-3/tests/alts/registermemregion.c b/branches/WOF2-3/tests/alts/registermemregion.c new file mode 100644 index 00000000..7dc9babe --- /dev/null +++ b/branches/WOF2-3/tests/alts/registermemregion.c @@ -0,0 +1,724 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include +#include +#include +#include +#include +#include + + +/* Test case PARAMETERS */ + +#define MEM_ALLIGN 32 +#define MEM_SIZE 1024 + + +/* + * Function prototypes + */ + + +/* + * Test Case RegisterMemRegion + */ +ib_api_status_t +al_test_register_mem( + void + ) +{ + ib_api_status_t ib_status = IB_SUCCESS; + ib_al_handle_t h_al = NULL; + ib_ca_handle_t h_ca = NULL; + ib_pd_handle_t h_pd = NULL; + + ib_mr_create_t virt_mem; + char *ptr = NULL, *ptr_align; + size_t mask; + uint32_t lkey; + uint32_t rkey; + ib_mr_handle_t h_mr = NULL; + ib_mr_attr_t alts_mr_attr; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + while(1) + { + /* Open AL */ + ib_status = alts_open_al(&h_al); + + if(ib_status != IB_SUCCESS) + break; + + CL_ASSERT(h_al); + + /* Open CA */ + ib_status = alts_open_ca(h_al,&h_ca); + if(ib_status != IB_SUCCESS) + break; + + CL_ASSERT(h_ca); + + /* + * Allocate a PD here + */ + ib_status = ib_alloc_pd(h_ca, IB_PDT_NORMAL, NULL, &h_pd); //passing null context + + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_alloc_pd failed status = %s\n", ib_get_err_str(ib_status)) ); + alts_close_ca(h_ca); + break; + } + + /* + * Allocate the virtual memory which needs to be registered + */ + + mask = MEM_ALLIGN - 1; + + ptr = cl_malloc(MEM_SIZE + MEM_ALLIGN - 1); + + CL_ASSERT(ptr); + + ptr_align = ptr; + + if(((size_t)ptr & mask) != 0) + ptr_align = (char *)(((size_t)ptr+mask)& ~mask); + + virt_mem.vaddr = ptr_align; + virt_mem.length = MEM_SIZE; + virt_mem.access_ctrl = (IB_AC_LOCAL_WRITE | IB_AC_MW_BIND); + + /* + * Register the memory region + */ + + ib_status = ib_reg_mem(h_pd, &virt_mem, &lkey, &rkey, &h_mr); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_reg_mem failed status = %s\n", ib_get_err_str(ib_status)) ); + alts_close_ca(h_ca); + break; + } + + /* + * Query the memory region + */ + ib_status = ib_query_mr(h_mr, &alts_mr_attr); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_query_mr failed status = %s\n", ib_get_err_str(ib_status)) ); + alts_close_ca(h_ca); + break; + } + + if(alts_mr_attr.lkey != lkey || alts_mr_attr.rkey != rkey) + { + + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_query_mr failed lkey rkey different from reg\n")); + ALTS_PRINT( ALTS_DBG_ERROR, + ("\t\t reg-lkey = %x query-lkey %x reg-rkey%x query-rkey%x\n" , + alts_mr_attr.lkey , lkey , alts_mr_attr.rkey , rkey)); + alts_close_ca(h_ca); + ib_status = IB_INVALID_LKEY; + break; + + } + + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_query_mr passed\n" + "\t\t lkey = %x rkey%x query-rkey%x\n" , + lkey, rkey, alts_mr_attr.rkey) ); + /* + * Re-register the memeory region + */ + virt_mem.access_ctrl |= (IB_AC_RDMA_WRITE ); + + ib_status = ib_rereg_mem(h_mr,IB_MR_MOD_ACCESS, + &virt_mem,&lkey,&rkey,NULL); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_rereg_mem failed status = %s\n", ib_get_err_str(ib_status)) ); + alts_close_ca(h_ca); + break; + } + + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_rereg_mr passed with status = %s\n",ib_get_err_str(ib_status))); + + /* + * De-register the memory region + */ + ib_status = ib_dereg_mr(h_mr); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_dereg_mr failed status = %s\n", ib_get_err_str(ib_status)) ); + alts_close_ca(h_ca); + break; + } + + /* + * Deallocate the PD + */ + + ib_status = ib_dealloc_pd(h_pd,alts_pd_destroy_cb); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_dealloc_pd failed status = %s\n",ib_get_err_str(ib_status)) ); + alts_close_ca(h_ca); + break; + } + + break; //End of while + } + + if ( ptr ) + cl_free ( ptr ); + /* Close AL */ + if(h_al) + alts_close_al(h_al); + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} + + + +/* + * Test Case RegisterVarMemRegions + */ + +#define MIN_MEM_SIZE 1 // size of the first region +#define N_SIZES 27 // number of regions, each next one is twice the size of the previous one +#define ITER_NUM 3 // each region will be re-/deregistered ITER_NUM times + +ib_api_status_t +al_test_register_var_mem( + void + ) +{ + ib_api_status_t ib_status = IB_SUCCESS; + ib_al_handle_t h_al = NULL; + ib_ca_handle_t h_ca = NULL; + ib_pd_handle_t h_pd = NULL; + + ib_mr_create_t virt_mem; + char *ptr = NULL; + uint32_t lkey; + uint32_t rkey; + ib_mr_handle_t h_mr = NULL; + ib_mr_attr_t alts_mr_attr; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + /* Open AL */ + ib_status = alts_open_al(&h_al); + + if(ib_status != IB_SUCCESS) + goto done; + + CL_ASSERT(h_al); + + /* Open CA */ + ib_status = alts_open_ca(h_al,&h_ca); + if(ib_status != IB_SUCCESS) + goto err_open_ca; + + CL_ASSERT(h_ca); + + /* + * Allocate a PD here + */ + ib_status = ib_alloc_pd(h_ca, IB_PDT_NORMAL, NULL, &h_pd); //passing null context + + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_alloc_pd failed status = %s\n", ib_get_err_str(ib_status)) ); + goto err_alloc_pd;; + } + + /* + * Register the memory region + */ + { + #define MAX_MEM_SIZE (MIN_MEM_SIZE << N_SIZES) // 1GB + #define MEM_OFFSET 1 + #define PAGE_SIZE 4096 + #define PAGE_MASK (PAGE_SIZE - 1) + unsigned i, j, offset; + unsigned __int64 size; + unsigned __int64 sizea; + int reg_time[N_SIZES], dereg_time[N_SIZES]; + int reg_tries[N_SIZES], dereg_tries[N_SIZES]; + unsigned __int64 Start, End; + + ALTS_PRINT( ALTS_DBG_ERROR, ("***** min_size %#x, max_size %#x, n_sizes %d \n", + MIN_MEM_SIZE, MAX_MEM_SIZE, N_SIZES )); + + + for (size = MIN_MEM_SIZE, j=0; size < MAX_MEM_SIZE; size <<= 1, ++j) + { + + /* Allocate the virtual memory which needs to be registered */ + sizea = size + MEM_OFFSET - 1; + ptr = cl_malloc((size_t)sizea); + if (!ptr) { + ALTS_PRINT( ALTS_DBG_ERROR, + ("cl_malloc failed on %#x bytes\n", sizea) ); + continue; + } + offset = (int)((ULONG_PTR)ptr & PAGE_MASK); + virt_mem.vaddr = ptr - offset; + virt_mem.length = sizea + offset; + virt_mem.access_ctrl = IB_AC_LOCAL_WRITE; + + reg_time[j] =dereg_time[j] =reg_tries[j] =dereg_tries[j] =0; + for (i=0; i +#include +#include +#include + +ib_api_status_t +al_test_pnp_callback( + IN ib_pnp_rec_t* notify ); + +/* + * al_test_register_pnp test case. + * This test case test the ib_reg_pnp and ib_dereg_pnp calls of AL + */ +ib_api_status_t +al_test_register_pnp(void) +{ + ib_al_handle_t h_al; + ib_api_status_t ib_status = IB_SUCCESS; + ib_pnp_req_t pnp_req; + ib_pnp_handle_t h_pnp; + + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + while(1) + { + ib_status = ib_open_al(&h_al); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_open_al failed status = %d", ib_status) ); + break; + } + + ALTS_PRINT( ALTS_DBG_INFO, + ("ib_open_al PASSED!!!\n") ); + + cl_memclr(&pnp_req,sizeof(ib_pnp_req_t)); + + pnp_req.pnp_context = (void*)(uintn_t)0xdeadbeef; + pnp_req.pfn_pnp_cb = al_test_pnp_callback; + pnp_req.pnp_class = IB_PNP_CA | IB_PNP_FLAG_REG_COMPLETE | IB_PNP_FLAG_REG_SYNC; + + h_pnp = NULL; + ib_status = ib_reg_pnp(h_al, &pnp_req, &h_pnp ); + + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_reg_pnp failed status = %s\n", ib_get_err_str(ib_status))); + + } + else + { + ALTS_PRINT( ALTS_DBG_INFO, + ("ib_reg_pnp PASSED!!\n")); + } + + ALTS_PRINT( ALTS_DBG_INFO, ("h_pnp = (0x%p)\n", h_pnp) ); + + if(h_pnp) + { + //ib_status = ib_dereg_pnp(h_pnp, al_test_pnp_destroy_cb); + ib_status = ib_dereg_pnp(h_pnp, NULL); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_dereg_pnp failed status = %s\n", ib_get_err_str(ib_status))); + } + else + { + ALTS_PRINT( ALTS_DBG_INFO, + ("ib_dereg_pnp PASSED!!\n")); + } + } + + + ib_status = ib_close_al(h_al); + + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_close_al failed status = %s\n", ib_get_err_str(ib_status))); + } + else + { + ALTS_PRINT( ALTS_DBG_INFO, ("ib_close_al PASSED!!!\n") ); + } + + break; //Break from while + } + + ALTS_EXIT( ALTS_DBG_VERBOSE ); + return ib_status; +} + +/* + * This is a pnp callback function call by AL + */ + +ib_api_status_t +al_test_pnp_callback( + IN ib_pnp_rec_t* notify ) +{ + void *context = (void*)0x1234; + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + CL_ASSERT(notify); + + ALTS_PRINT( ALTS_DBG_INFO, + ("AL pnp event (0x%x)\n", notify->pnp_event) ); + + CL_ASSERT( notify->pnp_context == (void*)(uintn_t)0xdeadbeef ); + + switch ( notify->pnp_event ) + { + /* + * Deal with additions + */ + case IB_PNP_CA_ADD: + CL_ASSERT( ((ib_pnp_ca_rec_t*)notify)->p_ca_attr != NULL ); + notify->context = context; + break; + case IB_PNP_PORT_ADD: + CL_ASSERT( ((ib_pnp_port_rec_t*)notify)->p_ca_attr != NULL ); + CL_ASSERT( ((ib_pnp_port_rec_t*)notify)->p_port_attr != NULL ); + notify->context = context; + break; + /* + * Deal with removals + */ + case IB_PNP_CA_REMOVE: + CL_ASSERT( notify->context == context); + break; + case IB_PNP_PORT_REMOVE: + CL_ASSERT( notify->context == context ); + break; + /* + * Deal with link state + */ + case IB_PNP_PORT_ACTIVE: + CL_ASSERT( ((ib_pnp_port_rec_t*)notify)->p_port_attr != NULL ); + CL_ASSERT( notify->context == context ); + /* + * we treat a port up event like a pkey change event + */ + break; + case IB_PNP_PORT_DOWN: + CL_ASSERT( notify->context == context ); + break; + /* + * Deal with PKey changes + */ + case IB_PNP_PKEY_CHANGE: + CL_ASSERT( ((ib_pnp_port_rec_t*)notify)->p_port_attr != NULL ); + CL_ASSERT( notify->context == context ); + break; + case IB_PNP_REG_COMPLETE: + break; + /* + * Deal with unknown/unhandled + */ + default: + ALTS_PRINT( ALTS_DBG_ERROR, + ("Unknown/unhandled AL event (0x%x)\n", notify->pnp_event) ); + + } + ALTS_EXIT( ALTS_DBG_VERBOSE ); + return IB_SUCCESS; +} + + + + diff --git a/branches/WOF2-3/tests/alts/smatests.c b/branches/WOF2-3/tests/alts/smatests.c new file mode 100644 index 00000000..0b8a2f43 --- /dev/null +++ b/branches/WOF2-3/tests/alts/smatests.c @@ -0,0 +1,439 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + +/* + * Abstract: + * mad test does a data transfer between two queue pairs created one + * on each port of the hca. In order for this test to work, two ports of the hca + * should be connected in a loop back and must be configured to ACTIVE PORT STATE. + * + * + * Environment: + * All + */ + + +#include +#include +#include +#include +#include +#include + +extern ib_cq_create_t cq_create_attr; +extern ib_qp_create_t qp_create_attr; +extern ib_av_attr_t av_attr; +extern ib_mad_svc_t mad_svc; + + +typedef struct _alts_sma_object +{ + ib_api_status_t status; + ib_al_handle_t h_al; + ib_ca_handle_t h_ca; + ib_ca_attr_t *p_ca_attr; + ib_port_attr_t *p_send_port_attr; + + ib_pd_handle_t h_pd; + + ib_cq_handle_t h_cq; + uint32_t cq_size; + + ib_pool_key_t h_mad_pool; + ib_qp_handle_t h_qp0; + + ib_mad_svc_handle_t h_sma_mad_svc; + +} alts_sma_object_t; + + +/* Function Prototype */ +ib_api_status_t +alts_get_al_resource( + alts_sma_object_t *p_alts_sma_obj +); + +ib_api_status_t +alts_init_tst_resource_sma( + alts_sma_object_t *p_alts_sma_obj +); +ib_api_status_t +alts_get_send_port( + alts_sma_object_t *p_alts_sma_obj +); + +void +sma_mad_qp_err_cb( + ib_async_event_rec_t *p_err_rec +); +void +alts_sma_mad_svc_send_cb( + IN const ib_mad_svc_handle_t h_mad_svc, + IN void *mad_svc_context, + IN ib_mad_element_t *p_mad_element +); + +void +alts_sma_mad_svc_recv_cb( + IN const ib_mad_svc_handle_t h_mad_svc, + IN void *mad_svc_context, + IN ib_mad_element_t *p_mad_element +); + +ib_api_status_t +alts_discover_fabric( + alts_sma_object_t *p_alts_sma_obj +); + + + +/********************************************************** +***********************************************************/ +ib_api_status_t +al_test_sma(void) +{ + alts_sma_object_t *p_alts_sma_obj; + ib_api_status_t ib_status = IB_ERROR; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + /* Allocate Memory for the alts_sma;*/ + p_alts_sma_obj = (alts_sma_object_t *)cl_zalloc(sizeof(alts_sma_object_t)); + + if(p_alts_sma_obj == NULL) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("cl_zalloc failed\n") ); + ALTS_EXIT( ALTS_DBG_VERBOSE); + return IB_ERROR; + } + + p_alts_sma_obj->cq_size = 255*2; + + do + { + /* Initialize the AL resources */ + ib_status = alts_open_al(&p_alts_sma_obj->h_al); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_open_al failed status = %d\n", ib_status) ); + break; + } + + /* + * Default opens the first CA + */ + + ib_status = alts_open_ca(p_alts_sma_obj->h_al, &p_alts_sma_obj->h_ca); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_open_ca failed status = %d\n", ib_status) ); + break; + } + + ib_status = alts_get_al_resource(p_alts_sma_obj); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_get_al_resource failed status = %d\n", ib_status) ); + break; + } + + + ib_status = alts_init_tst_resource_sma(p_alts_sma_obj); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_init_tst_resource_sma failed status = %d\n", ib_status) ); + break; + } + + ib_status = alts_discover_fabric(p_alts_sma_obj); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_discover_fabric failed status = %d\n", ib_status) ); + break; + } + }while(0); + + if(p_alts_sma_obj->h_ca) + alts_close_ca(p_alts_sma_obj->h_ca); + if(p_alts_sma_obj->h_al) + alts_close_al(p_alts_sma_obj->h_al); + + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} +/********************************************************* +**********************************************************/ +ib_api_status_t +alts_discover_fabric(alts_sma_object_t *p_alts_sma_obj) +{ + UNUSED_PARAM( p_alts_sma_obj ); + return IB_SUCCESS; +} +/********************************************************* +**********************************************************/ +ib_api_status_t +alts_get_al_resource(alts_sma_object_t *p_alts_sma_obj) +{ + uint32_t bsize; + ib_api_status_t ib_status; + ib_ca_attr_t *p_ca_attr; + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + bsize = 0; + ib_status = ib_query_ca(p_alts_sma_obj->h_ca, NULL, &bsize); + if(ib_status != IB_INSUFFICIENT_MEMORY) + { + ALTS_PRINT(ALTS_DBG_ERROR, + ("ib_query_ca failed with status = %d\n", ib_status) ); + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; + } + CL_ASSERT(bsize); + + p_ca_attr = (ib_ca_attr_t *)cl_zalloc(bsize); + if (!p_ca_attr) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("zalloc() failed for p_ca_attr!\n") ); + ALTS_EXIT( ALTS_DBG_VERBOSE); + return IB_ERROR; + } + + ib_status = ib_query_ca(p_alts_sma_obj->h_ca, p_ca_attr, &bsize); + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("ib_query_ca failed with status = %d\n", ib_status) ); + cl_free(p_ca_attr); + ALTS_EXIT( ALTS_DBG_VERBOSE); + return IB_ERROR; + } + p_alts_sma_obj->p_ca_attr = p_ca_attr; + + ib_status = alts_get_send_port(p_alts_sma_obj); + + if(ib_status != IB_SUCCESS) + { + ALTS_PRINT( ALTS_DBG_ERROR, + ("alts_get_send_port failed with status = %d\n", ib_status) ); + ALTS_EXIT( ALTS_DBG_VERBOSE); + return IB_ERROR; + } + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return ib_status; +} +/********************************************************* +**********************************************************/ + +ib_api_status_t +alts_get_send_port(alts_sma_object_t *p_alts_sma_obj) +{ + ib_ca_attr_t *p_ca_attr; + ib_port_attr_t *p_send_port_attr = NULL; + ib_port_attr_t *p_port_attr; + uint32_t i; + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + p_ca_attr = p_alts_sma_obj->p_ca_attr; + + for(i=0; inum_ports; i++) + { + p_port_attr = &p_ca_attr->p_port_attr[i]; + if ((p_port_attr->link_state == IB_LINK_ACTIVE) || + (p_port_attr->link_state == IB_LINK_INIT)) + { + if (p_send_port_attr == NULL) + { + p_send_port_attr = p_port_attr; + break; + } + } + } //end of for + + if(p_send_port_attr == NULL) + { + /* No port is connected */ + ALTS_EXIT( ALTS_DBG_VERBOSE); + return IB_ERROR; + } + + p_alts_sma_obj->p_send_port_attr = p_send_port_attr; + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return IB_SUCCESS; +} +/********************************************************* +**********************************************************/ + +ib_api_status_t +alts_init_tst_resource_sma(alts_sma_object_t *p_alts_sma_obj) +{ + ib_api_status_t ib_status; + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + /* + * Create the necessary resource PD/QP/QP + */ + + /* + * Allocate a PD + */ + ib_status = ib_alloc_pd( + p_alts_sma_obj->h_ca, + IB_PDT_ALIAS, + p_alts_sma_obj, //pd_context + &p_alts_sma_obj->h_pd); + + CL_ASSERT(ib_status == IB_SUCCESS); + + /* + * Create QP Attributes + */ + cl_memclr(&qp_create_attr, sizeof(ib_qp_create_t)); + + qp_create_attr.sq_depth = 10; + qp_create_attr.rq_depth = 10; + qp_create_attr.sq_sge = 1; + qp_create_attr.rq_sge = 1; + qp_create_attr.h_sq_cq = NULL; + qp_create_attr.h_rq_cq = NULL; + + qp_create_attr.sq_signaled = TRUE; + + qp_create_attr.qp_type = IB_QPT_QP0_ALIAS; + + ib_status = ib_get_spl_qp( + p_alts_sma_obj->h_pd, + p_alts_sma_obj->p_send_port_attr->port_guid, + &qp_create_attr, + p_alts_sma_obj, // context + sma_mad_qp_err_cb, + &p_alts_sma_obj->h_mad_pool, + &p_alts_sma_obj->h_qp0); + + if (ib_status != IB_SUCCESS) + { + ALTS_TRACE_EXIT(ALTS_DBG_VERBOSE, + ("Error in ib_get_spl_qp()! %s\n", ib_get_err_str(ib_status))); + ALTS_EXIT( ALTS_DBG_VERBOSE); + return (ib_status); + } + + // create svc + cl_memclr(&mad_svc, sizeof(ib_mad_svc_t)); + + mad_svc.mad_svc_context = p_alts_sma_obj; + mad_svc.pfn_mad_send_cb = alts_sma_mad_svc_send_cb; + mad_svc.pfn_mad_recv_cb = alts_sma_mad_svc_recv_cb; + + mad_svc.support_unsol = TRUE; + + + mad_svc.mgmt_class = IB_MCLASS_SUBN_DIR; + mad_svc.mgmt_version = 0x01; + + // fill in methods supported + 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_TRAP] = TRUE; + mad_svc.method_array[IB_MAD_METHOD_REPORT] = TRUE; + mad_svc.method_array[IB_MAD_METHOD_TRAP_REPRESS] = TRUE; + + ib_status = ib_reg_mad_svc( + p_alts_sma_obj->h_qp0, + &mad_svc, + &p_alts_sma_obj->h_sma_mad_svc ); + + if (ib_status != IB_SUCCESS) + { + ALTS_TRACE_EXIT(ALTS_DBG_VERBOSE, + ("Error in ib_reg_mad_svc()! %s\n", ib_get_err_str(ib_status))); + ALTS_EXIT( ALTS_DBG_VERBOSE); + return (ib_status); + } + + + ALTS_EXIT( ALTS_DBG_VERBOSE); + return IB_SUCCESS; +} +/********************************************************* +**********************************************************/ + +void +alts_sma_mad_svc_send_cb( + IN const ib_mad_svc_handle_t h_mad_svc, + IN void *mad_svc_context, + IN ib_mad_element_t *p_mad_element ) +{ + UNUSED_PARAM( h_mad_svc ); + UNUSED_PARAM( mad_svc_context ); + UNUSED_PARAM( p_mad_element ); +} +/********************************************************* +**********************************************************/ + +void +alts_sma_mad_svc_recv_cb( + IN const ib_mad_svc_handle_t h_mad_svc, + IN void *mad_svc_context, + IN ib_mad_element_t *p_mad_element ) +{ + UNUSED_PARAM( h_mad_svc ); + UNUSED_PARAM( mad_svc_context ); + UNUSED_PARAM( p_mad_element ); +} +/********************************************************* +**********************************************************/ +void +sma_mad_qp_err_cb( + ib_async_event_rec_t *p_err_rec + ) +{ + + ALTS_ENTER( ALTS_DBG_VERBOSE ); + + UNUSED_PARAM( p_err_rec ); + + ALTS_EXIT( ALTS_DBG_VERBOSE); +} diff --git a/branches/WOF2-3/tests/alts/user/SOURCES b/branches/WOF2-3/tests/alts/user/SOURCES new file mode 100644 index 00000000..acd63375 --- /dev/null +++ b/branches/WOF2-3/tests/alts/user/SOURCES @@ -0,0 +1,35 @@ +TARGETNAME=alts +TARGETPATH=..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE=PROGRAM +UMTYPE=console +USE_MSVCRT=1 + +SOURCES=alts_main.c \ + ..\allocdeallocpd.c \ + ..\alts_misc.c \ + ..\cmtests.c \ + ..\createanddestroycq.c \ + ..\createanddestroyqp.c \ + ..\createdestroyav.c \ + ..\creatememwindow.c \ + ..\ibquery.c \ + ..\madtests.c \ + ..\multisendrecv.c \ + ..\openclose.c \ + ..\querycaattr.c \ + ..\registermemregion.c \ + ..\registerpnp.c \ + ..\smatests.c + +INCLUDES=..\..\..\inc;..\..\..\inc\user;..; + +TARGETLIBS= \ +!if $(FREEBUILD) + $(TARGETPATH)\*\complib.lib \ + $(TARGETPATH)\*\ibal.lib +!else + $(TARGETPATH)\*\complibd.lib \ + $(TARGETPATH)\*\ibald.lib +!endif + +MSC_WARNING_LEVEL= /W3 diff --git a/branches/WOF2-3/tests/alts/user/alts_main.c b/branches/WOF2-3/tests/alts/user/alts_main.c new file mode 100644 index 00000000..adce92a7 --- /dev/null +++ b/branches/WOF2-3/tests/alts/user/alts_main.c @@ -0,0 +1,504 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * Abstract: + * This is the main c file for the AL test suite application + * + * Environment: + * User Mode + */ + + +#include "stdio.h" +#include "string.h" +#include "stdlib.h" + + +#include +#include "alts_debug.h" +#include "alts_common.h" + +//#include +//#include + + +//#define COMPILE_USER_MODE +#define strcasecmp lstrcmpi +#define strncasecmp( s1, s2, l ) CompareString( LOCALE_USER_DEFAULT, NORM_IGNORECASE, s1, strlen(s1), s2, l ) + +#if !defined( FALSE ) +#define FALSE 0 +#endif /* !defined( FALSE ) */ + +#if !defined( TRUE ) +#define TRUE 1 +#endif /* !defined( TRUE ) */ + +/* + * Global Varables + */ + +//Global Debug level +uint32_t alts_dbg_lvl = ALTS_DBG_FULL; + +/* + * Data structure + */ + + +/* + * Function Prototype + */ +boolean_t +parse_cmd_line( + cmd_line_arg_t *input_arg, + int argc, + char **argv + ); + +void +usage( + void); + + +#ifndef CL_KERNEL +void +run_ual_test( + cmd_line_arg_t *cmd_line_arg + ); +#endif + +void +run_kal_test( + cmd_line_arg_t *cmd_line_arg + ); + + + +/******************************************************************* +*******************************************************************/ + + +int32_t __cdecl +main( + int32_t argc, + char* argv[]) +{ + boolean_t isvalid = FALSE; + cmd_line_arg_t cmd_line_arg={0}; + + CL_ENTER( ALTS_DBG_VERBOSE, alts_dbg_lvl ); + + cl_memclr(&cmd_line_arg,sizeof(cmd_line_arg)); + + isvalid = parse_cmd_line(&cmd_line_arg, + argc, argv); + + if(cmd_line_arg.pgm_to_run == 0) + { + CL_PRINT( ALTS_DBG_ERROR, alts_dbg_lvl, + ("Command line parse failed\n") ); + usage(); + return 0; + } + + if(cmd_line_arg.um == TRUE) + { + { + #ifndef CL_KERNEL + run_ual_test(&cmd_line_arg); + #else + CL_PRINT( ALTS_DBG_ERROR, alts_dbg_lvl, + ("User Mode test not COMPILED.\n #define COMPILE_USER_MODE to build for usr mode\n") ); + #endif + } + } + else + { + CL_PRINT( ALTS_DBG_ERROR, alts_dbg_lvl, + ("Kernel mode test not supported\n") ); + //run_kal_test(&cmd_line_arg); + } + CL_EXIT( ALTS_DBG_VERBOSE, alts_dbg_lvl ); + + return 0; +} + +#ifndef CL_KERNEL +void +run_ual_test(cmd_line_arg_t *cmd_line_arg) +{ +ib_api_status_t ib_status = IB_ERROR; + + switch(cmd_line_arg->pgm_to_run) + { + case OpenClose: + ib_status = al_test_openclose(); + break; + case QueryCAAttribute: + ib_status = al_test_querycaattr(); + break; + case ModifyCAAttribute: + ib_status = al_test_modifycaattr(); + break; + case AllocDeallocPD: + ib_status = al_test_alloc_dealloc_pd(); + break; + case CreateDestroyAV: + ib_status = al_test_create_destroy_av(); + break; + case QueryAndModifyAV: + ib_status = al_test_query_modify_av(); + break; + case CreateDestroyQP: + ib_status = al_test_create_destroy_qp(); + break; + case QueryAndModifyQP: + CL_PRINT( ALTS_DBG_VERBOSE, alts_dbg_lvl, + ("altsapp: QueryAndModifyQP not implemented.\n") ); + ib_status = IB_SUCCESS; + break; + case CreateAndDestroyCQ: + ib_status = al_test_create_destroy_cq(); + break; + case QueryAndModifyCQ: + ib_status = al_test_query_modify_cq(); + break; + case AttachMultiCast: + CL_PRINT( ALTS_DBG_VERBOSE, alts_dbg_lvl, + ("altsapp: AttachMultiCast not implemented.\n") ); + ib_status = IB_SUCCESS; + break; + case RegisterMemRegion: + ib_status = al_test_register_mem(); + break; + case RegisterVarMemRegions: + ib_status = al_test_register_var_mem(); + break; + case RegisterPhyMemRegion: + CL_PRINT( ALTS_DBG_VERBOSE, alts_dbg_lvl, + ("altsapp: RegisterPhyMemRegion not implemented.\n") ); + ib_status = IB_SUCCESS; + break; + case CreateMemWindow: + ib_status = al_test_create_mem_window(); + break; + case RegisterSharedMemRegion: + ib_status = al_test_register_shared_mem(); + break; + case MultiSend: + ib_status = al_test_multi_send_recv(); + break; + case RegisterPnP: + ib_status = al_test_register_pnp(); + break; + case MadTests: + ib_status = al_test_mad(); + break; + case MadQuery: + ib_status = al_test_query(); + break; + case CmTests: + ib_status = al_test_cm(); + break; + + case MaxTestCase: + break; + default: + break; + } + if(ib_status != IB_SUCCESS) + { + printf("********************************\n"); + printf("altsapp:AL test failed\n"); + printf("********************************\n"); + } + else + { + printf("********************************\n"); + printf("altsapp:AL test passed\n"); + printf("********************************\n"); + } + +} +#endif + +//void +//run_kal_test(cmd_line_arg_t *cmd_line_arg) +//{ +// +// cl_dev_handle_t h_al_test; +// cl_status_t cl_status; +// uint32_t command; +// uintn_t inbufsz = 0; +// uintn_t outbufsz = 0; +// +// CL_ENTER( ALTS_DBG_VERBOSE, alts_dbg_lvl ); +// +// cl_status = cl_open_device(ALTS_DEVICE_NAME, &h_al_test); +// +// if(cl_status != CL_SUCCESS) +// { +// printf("altsapp:cl_open_device failed\n"); +// CL_EXIT( ALTS_DBG_VERBOSE, alts_dbg_lvl ); +// return; +// } +// +// command = IOCTL_CMD(ALTS_DEV_KEY, cmd_line_arg->pgm_to_run); +// inbufsz = sizeof(cmd_line_arg_t); +// +// +// cl_status = cl_ioctl_device( +// h_al_test, +// command, +// cmd_line_arg, +// inbufsz, +// &outbufsz); +// +// +// if(cl_status != CL_SUCCESS) +// { +// printf("********************************\n"); +// printf("altsapp:AL test failed\n"); +// printf("********************************\n"); +// +// CL_EXIT( ALTS_DBG_VERBOSE, alts_dbg_lvl ); +// return; +// } +// +// if(cmd_line_arg->status == IB_SUCCESS) +// { +// printf("********************************\n"); +// printf("altsapp:AL test passed\n"); +// printf("********************************\n"); +// } +// else +// { +// printf("********************************\n"); +// printf("altsapp:AL test failed\n"); +// printf("********************************\n"); +// } +// +// cl_close_device(h_al_test); +// CL_EXIT( ALTS_DBG_VERBOSE, alts_dbg_lvl ); +// +//} + +/* + * Command Line Parser Routine + */ + +boolean_t parse_cmd_line( + cmd_line_arg_t *input_arg, + int argc, + char **argv + ) +{ + size_t i,n,k,j; + char temp[256]; + int Value; + + if (argc <= 1 || (NULL==argv)) + return FALSE; + + input_arg->pgm_to_run = 0; //Set to Zero + + i = argc; + while (--i != 0) + { + /* + * Check for all the test case name + */ + ++argv; + if (strcasecmp(*argv, "--tc=OpenClose") == 0) + { + input_arg->pgm_to_run = OpenClose; + continue; + } + if (strcasecmp(*argv, "--tc=QueryCAAttribute") == 0) + { + input_arg->pgm_to_run = QueryCAAttribute; + continue; + } + if (strcasecmp(*argv, "--tc=ModifyCAAttribute") == 0) + { + input_arg->pgm_to_run = ModifyCAAttribute; + continue; + } + if (strcasecmp(*argv, "--tc=AllocDeallocPD") == 0) + { + input_arg->pgm_to_run = AllocDeallocPD; + continue; + } + if (strcasecmp(*argv, "--tc=CreateDestroyAV") == 0) + { + input_arg->pgm_to_run = CreateDestroyAV; + continue; + } + if (strcasecmp(*argv, "--tc=QueryAndModifyAV") == 0) + { + input_arg->pgm_to_run = QueryAndModifyAV; + continue; + } + if (strcasecmp(*argv, "--tc=CreateDestroyQP") == 0) + { + input_arg->pgm_to_run = CreateDestroyQP; + continue; + } + if (strcasecmp(*argv, "--tc=QueryAndModifyQP") == 0) + { + input_arg->pgm_to_run = QueryAndModifyQP; + continue; + } + if (strcasecmp(*argv, "--tc=CreateAndDestroyCQ") == 0) + { + input_arg->pgm_to_run = CreateAndDestroyCQ; + continue; + } + if (strcasecmp(*argv, "--tc=QueryAndModifyCQ") == 0) + { + input_arg->pgm_to_run = QueryAndModifyCQ; + continue; + } + if (strcasecmp(*argv, "--tc=AttachMultiCast") == 0) + { + input_arg->pgm_to_run = AttachMultiCast; + continue; + } + if (strcasecmp(*argv, "--tc=RegisterMemRegion") == 0) + { + input_arg->pgm_to_run = RegisterMemRegion; + continue; + } + if (strcasecmp(*argv, "--tc=RegisterVarMemRegions") == 0) + { + input_arg->pgm_to_run = RegisterVarMemRegions; + continue; + } + if (strcasecmp(*argv, "--tc=ReregisterHca") == 0) + { + input_arg->pgm_to_run = ReregisterHca; + continue; + } + if (strcasecmp(*argv, "--tc=RegisterPhyMemRegion") == 0) + { + input_arg->pgm_to_run = RegisterPhyMemRegion; + continue; + } + if (strcasecmp(*argv, "--tc=CreateMemWindow") == 0) + { + input_arg->pgm_to_run = CreateMemWindow; + continue; + } + if (strcasecmp(*argv, "--tc=RegisterSharedMemRegion") == 0) + { + input_arg->pgm_to_run = RegisterSharedMemRegion; + continue; + } + if (strcasecmp(*argv, "--tc=MultiSend") == 0) + { + input_arg->pgm_to_run = MultiSend; + continue; + } + if (strcasecmp(*argv, "--tc=RegisterPnP") == 0) + { + input_arg->pgm_to_run = RegisterPnP; + continue; + } + if (strcasecmp(*argv, "--tc=MadTests") == 0) + { + input_arg->pgm_to_run = MadTests; + continue; + } + if (strcasecmp(*argv, "--tc=MadQuery") == 0) + { + input_arg->pgm_to_run = MadQuery; + continue; + } + if (strcasecmp(*argv, "--tc=CmTests") == 0) + { + input_arg->pgm_to_run = CmTests; + continue; + } + + + /* + * Read Other parameter + */ + if (strcasecmp(*argv, "--um") == 0) + { + input_arg->um = TRUE; + printf("altst:Running user mode test case\n"); + continue; + } + + if (strcasecmp(*argv, "--km") == 0) + { + input_arg->um = FALSE; + printf("altst:Running kernel mode test case\n"); + continue; + } + + n = strlen(*argv); + + if (strncasecmp(*argv, "--Iteration=", j=strlen("--Iteration=")) == 0 ) + { + k = 0; + while (j < n){ + temp[k] = (*argv)[j++]; k++;} + temp[k] = '\0'; + + Value = atoi(temp); + printf("/Iteration= %d", Value); + + if (Value < 0 || Value > 50) + printf("Invalid Iteration specified\n"); + else + printf("Valid Iteration specified\n"); + continue; + } + + } + + return TRUE; +} + +void +usage(void) +{ + printf("Usage: ./alts --tc=XXXXX [--um|--km]\n"); + printf("XXXX -> see the alts_readme.txt\n"); + printf("--um -> Usermode\n"); + printf("--km -> Kernelmode\n"); +} diff --git a/branches/WOF2-3/tests/alts/user/makefile b/branches/WOF2-3/tests/alts/user/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-3/tests/alts/user/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\inc\openib.def diff --git a/branches/WOF2-3/tests/cmtest/dirs b/branches/WOF2-3/tests/cmtest/dirs new file mode 100644 index 00000000..389156fd --- /dev/null +++ b/branches/WOF2-3/tests/cmtest/dirs @@ -0,0 +1,2 @@ +DIRS=\ + user diff --git a/branches/WOF2-3/tests/cmtest/user/SOURCES b/branches/WOF2-3/tests/cmtest/user/SOURCES new file mode 100644 index 00000000..3001b4a5 --- /dev/null +++ b/branches/WOF2-3/tests/cmtest/user/SOURCES @@ -0,0 +1,20 @@ +TARGETNAME=cmtest +TARGETPATH=..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE=PROGRAM +UMTYPE=console +USE_MSVCRT=1 + +SOURCES=cmtest_main.c + +INCLUDES=..\..\..\inc;..\..\..\inc\user; + +TARGETLIBS= \ +!if $(FREEBUILD) + $(TARGETPATH)\*\complib.lib \ + $(TARGETPATH)\*\ibal.lib +!else + $(TARGETPATH)\*\complibd.lib \ + $(TARGETPATH)\*\ibald.lib +!endif + +MSC_WARNING_LEVEL= /W3 diff --git a/branches/WOF2-3/tests/cmtest/user/cmtest.rc b/branches/WOF2-3/tests/cmtest/user/cmtest.rc new file mode 100644 index 00000000..19c4021d --- /dev/null +++ b/branches/WOF2-3/tests/cmtest/user/cmtest.rc @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#if DBG +#define VER_FILEDESCRIPTION_STR "IBAL Connection Mgr cli/svr test Application (Debug)" +#define VER_INTERNALNAME_STR "cmtest.exe" +#define VER_ORIGINALFILENAME_STR "cmtest.exe" +#else +#define VER_FILEDESCRIPTION_STR "IBAL Connection Mgr cli/svr test Application" +#define VER_INTERNALNAME_STR "cmtest.exe" +#define VER_ORIGINALFILENAME_STR "cmtest.exe" +#endif + +#include diff --git a/branches/WOF2-3/tests/cmtest/user/cmtest_main.c b/branches/WOF2-3/tests/cmtest/user/cmtest_main.c new file mode 100644 index 00000000..0ce9f102 --- /dev/null +++ b/branches/WOF2-3/tests/cmtest/user/cmtest_main.c @@ -0,0 +1,2036 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 1996-2002 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corp. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * Abstract: + * Command line interface for cmtest. + * + * Environment: + * User Mode + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* Globals */ +#define CMT_DBG_VERBOSE 1 + +#define CMT_BASE_SVC_ID 0xFFEE +#define CMT_ACCESS_CTRL (IB_AC_LOCAL_WRITE + IB_AC_RDMA_READ + IB_AC_RDMA_WRITE) +#define BAD_PKEY_INDEX 0xFFFF + + +typedef enum _cmtest_state +{ + test_idle, test_connecting, test_transfering, test_disconnecting + +} cmtest_state_t; + + + +typedef struct _ib_root +{ + ib_al_handle_t h_al; + ib_pd_handle_t h_pd; + + /* Input parameters to control test. */ + int32_t num_nodes; + uint32_t num_msgs; + boolean_t per_msg_buf; + cl_mutex_t mutex; + + cmtest_state_t state; + atomic32_t num_connected; + uint32_t conn_index; /* current connection id */ + uint32_t total_sent; + uint32_t total_recv; + + uint32_t num_iter; + + uint32_t msg_size; + + ib_ca_handle_t h_ca; + ib_net16_t l_lid; + ib_net16_t r_lid; + ib_net64_t ca_guid; + ib_net64_t port_guid; + uint8_t port_num; + uint16_t num_pkeys; + ib_net16_t *p_pkey_table; + + /* cm info */ + boolean_t is_server; + ib_listen_handle_t h_listen; + ib_path_rec_t path_rec; + + /* CQ info. */ + boolean_t is_polling; + + struct _ib_node *p_nodes; + ib_qp_create_t qp_create; + ib_qp_mod_t qp_mod_reset; + ib_qp_mod_t qp_mod_init; + + /* reg mem info */ + ib_mr_handle_t h_mr; + uint32_t lkey; + uint32_t rkey; + uint8_t *p_mem; + uint8_t *p_mem_recv; + uint8_t *p_mem_send; + + uint64_t conn_start_time; + + /* + * Connection parameters are initialized once to improve connection + * establishment rate. + */ + ib_cm_req_t cm_req; + ib_cm_rep_t cm_rep; + ib_cm_rtu_t cm_rtu; + ib_cm_dreq_t cm_dreq; + ib_cm_drep_t cm_drep; + + uint32_t inst_id; + +} ib_root_t; + + + +typedef enum _cmnode_state +{ + node_idle, node_conn, node_dreq_sent, node_dreq_rcvd + +} cmnode_state_t; + + + +typedef struct _ib_node +{ + uint64_t id; + + ib_cq_handle_t h_send_cq; + ib_cq_handle_t h_recv_cq; + ib_qp_handle_t h_qp; + uint32_t max_inline; + + cmnode_state_t state; + ib_cm_handle_t h_cm_req; + ib_cm_handle_t h_cm_dreq; + + uint32_t send_cnt; + uint32_t recv_cnt; + +} ib_node_t; + + + +uint32_t cmt_dbg_lvl = 0x80000000; + +ib_root_t g_root; + + +static char *wc_type_text[] = { + "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" +}; + +static char *wc_status_text[] = { + "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", + "IB_WCS_CANCELED" +}; + + + +static void AL_API +__req_cb( + IN ib_cm_req_rec_t *p_cm_req_rec ); + +static void AL_API +__rep_cb( + IN ib_cm_rep_rec_t *p_cm_rep_rec ); + +static void AL_API +__rtu_cb( + IN ib_cm_rtu_rec_t *p_cm_rtu_rec ); + +static void AL_API +__rej_cb( + IN ib_cm_rej_rec_t *p_cm_rej_rec ); + +static void AL_API +__mra_cb( + IN ib_cm_mra_rec_t *p_cm_mra_rec ); + +static void AL_API +__apr_cb( + IN ib_cm_apr_rec_t *p_cm_apr_rec ); + +static void AL_API +__lap_cb( + IN ib_cm_lap_rec_t *p_cm_lap_rec ); + +static void AL_API +__dreq_cb( + IN ib_cm_dreq_rec_t *p_cm_dreq_rec ); + +static void AL_API +__drep_cb( + IN ib_cm_drep_rec_t *p_cm_drep_rec ); + +static boolean_t +__poll_cq( + IN ib_node_t *p_node, + IN ib_cq_handle_t h_cq ); + + +/********************************************************************** + **********************************************************************/ +static void +__show_usage() +{ + printf( "\n------- cmtest - Usage and options ----------------------\n" ); + printf( "Usage: cmtest [options]\n"); + printf( "Options:\n" ); + printf( "-s\n" + "--server\n" + " Directs cmtest to act as a Server\n" ); + printf( "-l \n" + "--local \n" + " Local endpoint LID; see vstat port_lid value.\n" + " LID Radix [0x Hex, 0 octal, else decimal]\n"); + printf( "-r \n" + "--remote \n" + " Remote endpoint LID\n" + " LID Radix [0x Hex, 0 octal, else decimal]\n" ); + printf( "-c \n" + "--connect \n" + " Total number of connections to open.\n" + " Default of 1.\n" ); + printf( "-m \n" + "--msize \n" + " Byte size of each message.\n" + " Default is 100 bytes.\n" ); + printf( "-n \n" + "--nmsgs \n" + " Number of messages to send at a time.\n" ); + printf( "-p\n" + "--permsg\n" + " Specify a separate buffer should be used per message.\n" + " Default is one buffer for all messages.\n" ); + printf( "-i \n" + "--iterate \n" + " Set the number of times to loop through 'nmsgs'.\n" + " Default of 1.\n" ); + printf( "-v\n" + "--verbose\n" + " Set verbosity level to debug console.\n" ); + printf( "-h\n" + "--help\n" + " Display this usage info then exit.\n\n" ); +} + + +/* Windows support. */ +struct option +{ + const char *long_name; + unsigned long flag; + void *pfn_handler; + char short_name; +}; + +static char *optarg; + +#define strtoull strtoul + + +char +getopt_long( + int argc, + char *argv[], + const char *short_option, + const struct option *long_option, + void *unused ) +{ + static int i = 1; + int j; + char ret = 0; + + UNUSED_PARAM( unused ); + + if( i == argc ) + return -1; + + if( argv[i][0] != '-' ) + return ret; + + /* find the first character of the value. */ + for( j = 1; isalpha( argv[i][j] ); j++ ) + ; + optarg = &argv[i][j]; + + if( argv[i][1] == '-' ) + { + /* Long option. */ + for( j = 0; long_option[j].long_name; j++ ) + { + if( strncmp( &argv[i][2], long_option[j].long_name, + optarg - argv[i] - 2 ) ) + { + continue; + } + + switch( long_option[j].flag ) + { + case 1: + if( *optarg == '\0' ) + return 0; + default: + break; + } + ret = long_option[j].short_name; + break; + } + } + else + { + for( j = 0; short_option[j] != '\0'; j++ ) + { + if( !isalpha( short_option[j] ) ) + return 0; + + if( short_option[j] == argv[i][1] ) + { + ret = short_option[j]; + break; + } + + if( short_option[j+1] == ':' ) + { + if( *optarg == '\0' ) + return 0; + j++; + } + } + } + i++; + return ret; +} + + +static boolean_t +__parse_options( + int argc, + char* argv[] ) +{ + uint32_t next_option; + const char* const short_option = "esl:r:c:m:n:i:pvh"; + + /* + 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[] = + { + { "event", 2, NULL, 'e'}, + { "server", 2, NULL, 's'}, + { "local", 1, NULL, 'l'}, + { "remote", 1, NULL, 'r'}, + { "connect", 1, NULL, 'c'}, + { "msize", 1, NULL, 'm'}, + { "nmsgs", 1, NULL, 'n'}, + { "iterate", 1, NULL, 'i'}, + { "permsg", 0, NULL, 'p'}, + { "verbose", 0, NULL, 'v'}, + { "help", 0, NULL, 'h'}, + { NULL, 0, NULL, 0 } /* Required at end of array */ + }; + + /* Set the default options. */ + g_root.msg_size = 100; + g_root.num_nodes = 1; + g_root.num_msgs = 0; + g_root.num_iter = 1; + g_root.is_polling = TRUE; + + /* parse cmd line arguments as input params */ + do + { + next_option = getopt_long( argc, argv, short_option, + long_option, NULL ); + + switch( next_option ) + { + case 's': + g_root.is_server = TRUE; + printf( "\tServer mode\n" ); + break; + + case 'd': + g_root.inst_id = strtoull( optarg, NULL, 0 ); + printf( "\tinstance_id..: %d\n", g_root.inst_id ); + break; + + case 'c': + g_root.num_nodes = strtoull( optarg, NULL, 0 ); + printf( "\tconnections..: %d\n", g_root.num_nodes ); + break; + + case 'l': + g_root.l_lid = (uint16_t)strtoull( optarg, NULL, 0 ); + printf( "\tlocal lid....: 0x%x\n", g_root.l_lid ); + g_root.l_lid = cl_hton16( g_root.l_lid ); + break; + + case 'r': + g_root.r_lid = (uint16_t)strtoull( optarg, NULL, 0 ); + printf( "\tremote lid...: 0x%x\n", g_root.r_lid ); + g_root.r_lid = cl_hton16( g_root.r_lid ); + break; + + case 'm': + g_root.msg_size = strtoull( optarg, NULL, 0 ); + printf( "\tmsg size.....: %d bytes\n", g_root.msg_size ); + break; + + case 'n': + g_root.num_msgs = strtoull( optarg, NULL, 0 ); + printf( "\tnum msgs.....: %d\n", g_root.num_msgs ); + break; + + case 'i': + g_root.num_iter = strtoull( optarg, NULL, 0 ); + printf( "\titerate......: %d\n", g_root.num_iter ); + break; + + case 'p': + g_root.per_msg_buf = TRUE; + printf( "\tper message data buffer\n" ); + break; + + case 'v': + cmt_dbg_lvl = 0xFFFFFFFF; + printf( "\tverbose\n" ); + break; + + case 'e': + g_root.is_polling = FALSE; + printf( "\tevent driven completions\n" ); + break; + + case 'h': + __show_usage(); + return FALSE; + + case -1: + break; + + default: /* something wrong */ + __show_usage(); + return FALSE; + } + } while( next_option != -1 ); + + return TRUE; +} + + +/********************************************************************** + **********************************************************************/ +static void +__init_conn_info() +{ + /* Initialize connection request parameters. */ + g_root.cm_req.svc_id = CMT_BASE_SVC_ID + g_root.inst_id; + g_root.cm_req.max_cm_retries = 5; + g_root.cm_req.p_primary_path = &g_root.path_rec; + g_root.cm_req.pfn_cm_rep_cb = __rep_cb; + g_root.cm_req.qp_type = IB_QPT_RELIABLE_CONN; + g_root.cm_req.resp_res = 3; + g_root.cm_req.init_depth = 1; + g_root.cm_req.remote_resp_timeout = 20; + g_root.cm_req.flow_ctrl = TRUE; + g_root.cm_req.local_resp_timeout= 20; + g_root.cm_req.rnr_nak_timeout = 6; + g_root.cm_req.rnr_retry_cnt = 3; + g_root.cm_req.retry_cnt = 5; + g_root.cm_req.pfn_cm_mra_cb = __mra_cb; + g_root.cm_req.pfn_cm_rej_cb = __rej_cb; + + /* Initialize connection reply parameters. */ + g_root.cm_rep.qp_type = IB_QPT_RELIABLE_CONN; + g_root.cm_rep.access_ctrl = CMT_ACCESS_CTRL; + g_root.cm_rep.sq_depth = 0; + g_root.cm_rep.rq_depth = 0; + g_root.cm_rep.init_depth = 1; + g_root.cm_rep.target_ack_delay = 7; + g_root.cm_rep.failover_accepted = IB_FAILOVER_ACCEPT_UNSUPPORTED; + g_root.cm_rep.flow_ctrl = TRUE; + g_root.cm_rep.rnr_nak_timeout = 7; + g_root.cm_rep.rnr_retry_cnt = 6; + g_root.cm_rep.pfn_cm_rej_cb = __rej_cb; + g_root.cm_rep.pfn_cm_mra_cb = __mra_cb; + g_root.cm_rep.pfn_cm_rtu_cb = __rtu_cb; + g_root.cm_rep.pfn_cm_lap_cb = __lap_cb; + g_root.cm_rep.pfn_cm_dreq_cb = __dreq_cb; + + /* Initialize connection RTU parameters. */ + g_root.cm_rtu.pfn_cm_apr_cb = __apr_cb; + g_root.cm_rtu.pfn_cm_dreq_cb = __dreq_cb; + + /* Initialize disconnection request parameters. */ + g_root.cm_dreq.pfn_cm_drep_cb = __drep_cb; + g_root.cm_dreq.qp_type = IB_QPT_RELIABLE_CONN; + + /* Disconnection reply parameters are all zero. */ +} + + + +static uint16_t +__get_pkey_index() +{ + uint16_t i; + + for( i = 0; i < g_root.num_pkeys; i++ ) + { + if( g_root.p_pkey_table[i] == g_root.path_rec.pkey ) + return i; + } + + return BAD_PKEY_INDEX; +} + + + +static void +__init_qp_info() +{ + /* Set common QP attributes for all create calls. */ + g_root.qp_create.qp_type = IB_QPT_RELIABLE_CONN; + if( g_root.num_msgs ) + { + g_root.qp_create.sq_depth = g_root.num_msgs; + g_root.qp_create.rq_depth = g_root.num_msgs; + } + else + { + /* Minimal queue depth of one. */ + g_root.qp_create.sq_depth = 1; + g_root.qp_create.rq_depth = 1; + } + + g_root.qp_create.sq_signaled = FALSE; + g_root.qp_create.sq_sge = 1; + g_root.qp_create.rq_sge = 1; + + /* Set the QP attributes when modifying the QP to the reset state. */ + g_root.qp_mod_reset.req_state = IB_QPS_RESET; + + /* Set the QP attributes when modifying the QP to the init state. */ + g_root.qp_mod_init.req_state = IB_QPS_INIT; + g_root.qp_mod_init.state.init.access_ctrl = CMT_ACCESS_CTRL; + g_root.qp_mod_init.state.init.primary_port = g_root.port_num; + g_root.qp_mod_init.state.init.pkey_index = __get_pkey_index(); +} + + + +static ib_api_status_t +__post_recvs( + IN ib_node_t *p_node ) +{ + ib_api_status_t status = IB_SUCCESS; + ib_recv_wr_t recv_wr; + ib_recv_wr_t *p_recv_failure; + ib_local_ds_t ds_array; + uint32_t i; + + CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl ); + + if( !g_root.num_msgs ) + { + CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl ); + return IB_SUCCESS; + } + + cl_memclr( &recv_wr, sizeof( ib_recv_wr_t ) ); + ds_array.length = g_root.msg_size; + ds_array.lkey = g_root.lkey; + recv_wr.ds_array = &ds_array; + recv_wr.num_ds = (( g_root.msg_size <= 4 )? 0: 1 ); + + for( i = 0; i < g_root.num_msgs; i++ ) + { + CL_PRINT( CMT_DBG_VERBOSE, cmt_dbg_lvl, (".") ); + + if( g_root.per_msg_buf ) + { + ds_array.vaddr = (uintn_t)(g_root.p_mem_recv + (i * g_root.msg_size) + + (p_node->id * g_root.num_msgs * g_root.msg_size)); + } + else + { + ds_array.vaddr = (uintn_t)g_root.p_mem; + } + + recv_wr.wr_id = i; + + status = ib_post_recv( p_node->h_qp, &recv_wr, &p_recv_failure ); + if( status != IB_SUCCESS ) + { + printf( "ib_post_recv failed [%s]!\n", ib_get_err_str(status) ); + break; + } + } + + CL_PRINT( CMT_DBG_VERBOSE, cmt_dbg_lvl, ("\n") ); + CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl ); + return status; +} + + + +static void AL_API +__ca_async_event_cb( + ib_async_event_rec_t *p_err_rec ) +{ + CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl ); + + CL_TRACE( CMT_DBG_VERBOSE, cmt_dbg_lvl, + ( "p_err_rec->code is %d\n", p_err_rec->code ) ); + + CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl ); +} + + + +static void AL_API +__cancel_listen_cb( + IN void *context ) +{ + CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl ); + if( !context ) + printf( "%s NULL context\n", __FUNCTION__ ); + CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl ); +} + + + +/* We need to halt the test and recover from the reject error. */ +static void AL_API +__rej_cb( + IN ib_cm_rej_rec_t *p_cm_rej_rec ) +{ + CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl ); + + /* + * Note - because this callback exits the app, any output beyond the + * the first time may report junk. There have been instances where + * the callback is invoked more times than there are connection requests + * but that behavior disapeared if the call to exit below is removed. + */ + printf( "Connection was rejected, status: 0x%x\n", + p_cm_rej_rec->rej_status ); + + CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl ); + exit( 1 ); +} + + + +static void AL_API +__req_cb( + IN ib_cm_req_rec_t *p_cm_req_rec ) +{ + ib_api_status_t status; + ib_node_t *p_node; + + CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl ); + + CL_ASSERT( p_cm_req_rec ); + + /* Record the starting time for the server. */ + if( !g_root.conn_start_time ) + g_root.conn_start_time = cl_get_time_stamp( ); + + /* + * Do not send replies until the server is ready to establish all + * connections. + */ + cl_mutex_acquire( &g_root.mutex ); + p_node = &g_root.p_nodes[g_root.conn_index++]; + + if( g_root.state == test_connecting ) + { + /* Get a node for this connection and send the reply. */ + g_root.cm_rep.h_qp = p_node->h_qp; + status = ib_cm_rep( p_cm_req_rec->h_cm_req, &g_root.cm_rep ); + if( status != IB_SUCCESS ) + { + printf( "Call to ib_cm_rep failed\n" ); + exit( 1 ); + } + } + else + { + p_node->h_cm_req = p_cm_req_rec->h_cm_req; + } + cl_mutex_release( &g_root.mutex ); + + CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl ); +} + + + +static void AL_API +__rep_cb( + IN ib_cm_rep_rec_t *p_cm_rep_rec ) +{ + ib_api_status_t status; + ib_node_t *p_node; + uint8_t pdata[IB_RTU_PDATA_SIZE]; + ib_cm_mra_t mra; + + CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl ); + CL_ASSERT( p_cm_rep_rec ); + + p_node = (ib_node_t *)p_cm_rep_rec->qp_context; + CL_ASSERT( p_node ); + + mra.p_mra_pdata = NULL; + mra.mra_length = 0; + mra.svc_timeout = 0xff; + + ib_cm_mra( p_cm_rep_rec->h_cm_rep, &mra ); + + __post_recvs( p_node ); + + /* Mark that we're connected before sending the RTU. */ + p_node->state = node_conn; + + g_root.cm_rtu.p_rtu_pdata = pdata; + g_root.cm_rtu.rtu_length = IB_RTU_PDATA_SIZE; + + status = ib_cm_rtu( p_cm_rep_rec->h_cm_rep, &g_root.cm_rtu ); + if( status != IB_SUCCESS ) + { + printf( "Call to ib_cm_rtu returned %s\n", ib_get_err_str( status ) ); + exit( 1 ); + } + + cl_atomic_inc( &g_root.num_connected ); + + CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl ); +} + + + +static void AL_API +__rtu_cb( + IN ib_cm_rtu_rec_t *p_cm_rtu_rec ) +{ + ib_node_t *p_node; + + CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl ); + CL_ASSERT( p_cm_rtu_rec ); + + p_node = (ib_node_t*)p_cm_rtu_rec->qp_context; + p_node->state = node_conn; + + __post_recvs( p_node ); + cl_atomic_inc( &g_root.num_connected ); + + CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl ); +} + + + +static void AL_API +__mra_cb( + IN ib_cm_mra_rec_t *p_cm_mra_rec ) +{ + CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl ); + CL_ASSERT( p_cm_mra_rec ); + CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl ); +} + + + +static void AL_API +__apr_cb( + IN ib_cm_apr_rec_t *p_cm_apr_rec ) +{ + CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl ); + CL_ASSERT( p_cm_apr_rec ); + CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl ); +} + + + +static void AL_API +__lap_cb( + IN ib_cm_lap_rec_t *p_cm_lap_rec ) +{ + CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl ); + CL_ASSERT( p_cm_lap_rec ); + CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl ); +} + + + +static void AL_API +__dreq_cb( + IN ib_cm_dreq_rec_t *p_cm_dreq_rec ) +{ + ib_node_t *p_node; + ib_api_status_t status; + + CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl ); + CL_ASSERT( p_cm_dreq_rec ); + p_node = (ib_node_t*)p_cm_dreq_rec->qp_context; + CL_ASSERT( p_node ); + + /* + * Record that we've already received a DREQ to avoid trying to + * disconnect the QP a second time. Synchronize with the DREQ call + * using the mutex. + */ + cl_mutex_acquire( &g_root.mutex ); + + /* If we need to send or receive more data, don't disconnect yet. */ + if( g_root.state == test_disconnecting ) + { + /* Send the DREP. */ + status = ib_cm_drep( p_cm_dreq_rec->h_cm_dreq, &g_root.cm_drep ); + + /* If the DREP was successful, we're done with this connection. */ + if( status == IB_SUCCESS ) + { + p_node->state = node_idle; + cl_atomic_dec( &g_root.num_connected ); + } + } + else + { + /* Record that we need to disconnect, but don't send the DREP yet. */ + p_node->state = node_dreq_rcvd; + p_node->h_cm_dreq = p_cm_dreq_rec->h_cm_dreq; + } + cl_mutex_release( &g_root.mutex ); + + CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl ); +} + + + +static void AL_API +__drep_cb( + IN ib_cm_drep_rec_t *p_cm_drep_rec ) +{ + ib_node_t *p_node; + + CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl ); + CL_ASSERT( p_cm_drep_rec ); + p_node = (ib_node_t*)p_cm_drep_rec->qp_context; + CL_ASSERT( p_node ); + + /* We're done with this connection. */ + cl_mutex_acquire( &g_root.mutex ); + p_node->state = node_idle; + cl_atomic_dec( &g_root.num_connected ); + cl_mutex_release( &g_root.mutex ); + + CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl ); +} + + + +static void AL_API +__cq_cb( + IN const ib_cq_handle_t h_cq, + IN void* cq_context ) +{ + ib_node_t *p_node = (ib_node_t*)cq_context; + + CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl ); + if( !g_root.is_polling ) + { + if( !__poll_cq( p_node, h_cq ) ) + exit( 1 ); + } + CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl ); +} + + +static ib_api_status_t +__create_qp( + IN ib_node_t *p_node ) +{ + ib_api_status_t status; + ib_qp_attr_t attr; + + /* Set the per node QP attributes. */ + g_root.qp_create.h_sq_cq = p_node->h_send_cq; + g_root.qp_create.h_rq_cq = p_node->h_recv_cq; + + /* Allocate the QP. */ + status = ib_create_qp( g_root.h_pd, &g_root.qp_create, p_node, NULL, + &p_node->h_qp ); + if( status != IB_SUCCESS ) + { + printf( "[%d] ib_create_qp failed [%s]!\n", __LINE__, + ib_get_err_str(status) ); + return status; + } + + /* Store the max inline size. */ + status = ib_query_qp( p_node->h_qp, &attr ); + if( status != IB_SUCCESS ) + p_node->max_inline = 0; + else + p_node->max_inline = attr.sq_max_inline; + + /* + * Transition the QP to the initialize state. This prevents the CM + * from having to make this QP transition and improves the connection + * establishment rate. + */ + status = ib_modify_qp( p_node->h_qp, &g_root.qp_mod_reset ); + if( status != IB_SUCCESS ) + { + printf( "ib_modify_qp to IB_QPS_RESET returned %s\n", + ib_get_err_str(status) ); + return status; + } + + status = ib_modify_qp( p_node->h_qp, &g_root.qp_mod_init ); + if( status != IB_SUCCESS ) + { + printf( "ib_modify_qp to IB_QPS_INIT returned %s\n", + ib_get_err_str(status) ); + return status; + } + + return status; +} + + + +/* + * Allocate new QPs for all nodes. + */ +static ib_api_status_t +__create_qps() +{ + uint64_t start_time, total_time; + int32_t i; + ib_api_status_t status; + + printf( "Creating QPs...\n" ); + start_time = cl_get_time_stamp(); + + for( i = 0; i < g_root.num_nodes; i++ ) + { + /* Allocate a new QP. */ + status = __create_qp( &g_root.p_nodes[i] ); + if( status != IB_SUCCESS ) + break; + } + + total_time = cl_get_time_stamp() - start_time; + printf( "Allocation time: %"PRId64" ms\n", total_time/1000 ); + + return status; +} + + + +/* + * Destroy all QPs for all nodes. + */ +static void +__destroy_qps() +{ + uint64_t start_time, total_time; + int32_t i; + + printf( "Destroying QPs...\n" ); + start_time = cl_get_time_stamp(); + + for( i = 0; i < g_root.num_nodes; i++ ) + { + /* Destroy the QP. */ + if( g_root.p_nodes[i].h_qp ) + { + ib_destroy_qp( g_root.p_nodes[i].h_qp, ib_sync_destroy ); + g_root.p_nodes[i].h_qp = NULL; + } + } + + total_time = cl_get_time_stamp() - start_time; + printf( "Destruction time: %"PRId64" ms\n", total_time/1000 ); +} + + + +static boolean_t +__init_node( + IN OUT ib_node_t* p_node ) +{ + ib_api_status_t status; + ib_cq_create_t cq_create; + + CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl ); + + /* Create the CQs. */ + cl_memclr( &cq_create, sizeof(ib_cq_create_t) ); + if( g_root.num_msgs ) + cq_create.size = g_root.num_msgs; + else + cq_create.size = 1; /* minimal of one entry */ + + cq_create.pfn_comp_cb = __cq_cb; + status = ib_create_cq( g_root.h_ca, &cq_create, p_node, NULL, + &p_node->h_send_cq ); + if( status != IB_SUCCESS ) + { + printf( "ib_create_cq failed for send CQ [%s]!\n", + ib_get_err_str(status) ); + return FALSE; + } + if( !g_root.is_polling ) + { + status = ib_rearm_cq( p_node->h_send_cq, FALSE ); + if( status != IB_SUCCESS ) + { + printf( "ib_rearm_cq failed for send CQ [%s]!\n", + ib_get_err_str(status) ); + return FALSE; + } + } + + status = ib_create_cq( g_root.h_ca, &cq_create, p_node, NULL, + &p_node->h_recv_cq ); + if( status != IB_SUCCESS ) + { + printf( "ib_create_cq failed for recv CQ [%s]!\n", + ib_get_err_str(status) ); + return FALSE; + } + if( !g_root.is_polling ) + { + status = ib_rearm_cq( p_node->h_recv_cq, FALSE ); + if( status != IB_SUCCESS ) + { + printf( "ib_rearm_cq failed for recv CQ [%s]!\n", + ib_get_err_str(status) ); + return FALSE; + } + } + + CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl ); + return TRUE; +} + +static boolean_t +__destroy_node( + IN OUT ib_node_t* p_node ) +{ + ib_api_status_t status = IB_SUCCESS; + CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl ); + if (!p_node ) + return (FALSE); + if ( p_node->h_send_cq ) + { + status = ib_destroy_cq( p_node->h_send_cq, ib_sync_destroy ); + p_node->h_send_cq = NULL; + if( status != IB_SUCCESS ) + { + printf( "ib_destroy_cq failed for send CQ [%s]!\n", + ib_get_err_str(status) ); + } + } + if (p_node->h_recv_cq) + { + status = ib_destroy_cq( p_node->h_recv_cq, ib_sync_destroy ); + p_node->h_recv_cq = NULL; + if( status != IB_SUCCESS ) + { + printf( "ib_destroy_cq failed for recv CQ [%s]!\n", + ib_get_err_str(status) ); + } + } + + CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl ); + return (status == IB_SUCCESS); +} + + + +static boolean_t +__create_nodes() +{ + int32_t i; + + CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl ); + for( i = 0; i < g_root.num_nodes; i++ ) + { + g_root.p_nodes[i].id = i; + + CL_PRINT( CMT_DBG_VERBOSE, cmt_dbg_lvl, + ("--> create connection %d of instance %d\n", i, g_root.inst_id) ); + + if( !__init_node( &g_root.p_nodes[i] ) ) + return FALSE; + } + + CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl ); + return TRUE; +} + +static boolean_t +__destroy_nodes() +{ + int32_t i; + + CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl ); + + for( i = 0; i < g_root.num_nodes; i++ ) + { + if( !__destroy_node( &g_root.p_nodes[i] ) ) + return FALSE; + } + CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl ); + return TRUE; +} + +/* query function called by ib_query() */ +static void AL_API +__sa_query_cb( + IN ib_query_rec_t *p_query_rec ) +{ + ib_path_rec_t *p_path; + ib_api_status_t status; + + CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl ); + + CL_ASSERT( p_query_rec ); + + if( p_query_rec->status != IB_SUCCESS ) + { + printf( "ib_query failed [%d]\n", p_query_rec->status ); + return; + } + + if( p_query_rec->query_type != IB_QUERY_PATH_REC_BY_LIDS ) + { + printf( "Unexpected query type returned.\n" ); + return; + } + + if( !p_query_rec->p_result_mad ) + { + printf( "No result MAD returned from ib_query.\n" ); + return; + } + + /* copy the 1st (zero'th) path record to local storage. */ + p_path = ib_get_query_path_rec( p_query_rec->p_result_mad, 0 ); + memcpy( (void*)&g_root.path_rec, (void*)p_path, + sizeof(ib_path_rec_t) ); + + CL_TRACE( CMT_DBG_VERBOSE, cmt_dbg_lvl, + ( "path{ slid:0x%x, dlid:0x%x }\n", + g_root.path_rec.slid, g_root.path_rec.dlid) ); + + /* release response MAD(s) back to AL pool */ + if( p_query_rec->p_result_mad ) + { + status = ib_put_mad( p_query_rec->p_result_mad ); + if( status != IB_SUCCESS ) + { + printf( "ib_put_mad() failed [%s]\n", + ib_get_err_str(status) ); + } + } + + CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl ); +} + + + +static boolean_t +__query_for_path() +{ + ib_api_status_t status; + ib_query_req_t query_rec; + ib_lid_pair_t lid_pair; + + /* Query the SA for a path record. */ + query_rec.query_type = IB_QUERY_PATH_REC_BY_LIDS; + + lid_pair.src_lid = g_root.l_lid; + lid_pair.dest_lid = g_root.r_lid; + + query_rec.p_query_input = (void*)&lid_pair; + query_rec.port_guid = g_root.port_guid; + query_rec.timeout_ms = 5 * 1000; // seconds + query_rec.retry_cnt = 2; + query_rec.flags = IB_FLAGS_SYNC; + query_rec.query_context = &g_root; + query_rec.pfn_query_cb = __sa_query_cb; + + status = ib_query( g_root.h_al, &query_rec, NULL ); + if( ( status != IB_SUCCESS ) || ( !g_root.path_rec.dlid ) ) + { + printf( "ib_query failed.\n" ); + return FALSE; + } + + return TRUE; +} + + + +static boolean_t +__create_messages() +{ + ib_mr_create_t mr_create; + uint32_t buf_size; + ib_api_status_t status; + + /* If we're not sending messages, just return. */ + if( !g_root.num_msgs || !g_root.msg_size ) + return TRUE; + + /* Allocate the message memory - we ignore the data, so just one buffer. */ + if( g_root.per_msg_buf ) + buf_size = (g_root.num_nodes * g_root.num_msgs * g_root.msg_size) << 1; + else + buf_size = g_root.msg_size; + g_root.p_mem = (uint8_t*)cl_zalloc( buf_size ); + if( !g_root.p_mem ) + { + printf( "Not enough memory for transfers!\n" ); + return FALSE; + } + memset (g_root.p_mem, 0xae, buf_size); + g_root.p_mem_recv = g_root.p_mem; + g_root.p_mem_send = g_root.p_mem + (buf_size >> 1); + + /* Register the memory with AL. */ + mr_create.vaddr = g_root.p_mem; + mr_create.length = buf_size; + mr_create.access_ctrl = IB_AC_LOCAL_WRITE | IB_AC_MW_BIND; + status = ib_reg_mem( g_root.h_pd, &mr_create, &g_root.lkey, + &g_root.rkey, &g_root.h_mr ); + if( status != IB_SUCCESS ) + { + printf( "ib_reg_mem failed [%s]!\n", ib_get_err_str(status) ); + return FALSE; + } + + return TRUE; +} + + + +/* + * PnP callback handler. Record the port GUID of an active port. + */ +static ib_api_status_t AL_API +__pnp_cb( + IN ib_pnp_rec_t *p_pnp_rec ) +{ + ib_pnp_port_rec_t* p_port_rec; + uint32_t size; + + p_port_rec = (ib_pnp_port_rec_t*)p_pnp_rec; + + /* + * Ignore PNP events that are not related to port active, or if + * we already have an active port. + */ + if( p_pnp_rec->pnp_event != IB_PNP_PORT_ACTIVE || g_root.port_guid ) + return IB_SUCCESS; + + /* Find the proper port for the given local LID. */ + if( g_root.l_lid ) + { + if( g_root.l_lid != p_port_rec->p_port_attr->lid ) + return IB_SUCCESS; + } + else + { + g_root.l_lid = p_port_rec->p_port_attr->lid; + printf( "\tlocal lid....: x%x\n", g_root.l_lid ); + } + + /* Record the active port information. */ + g_root.ca_guid = p_port_rec->p_ca_attr->ca_guid; + g_root.port_num = p_port_rec->p_port_attr->port_num; + + /* Record the PKEYs available on the active port. */ + size = sizeof( ib_net16_t ) * p_port_rec->p_port_attr->num_pkeys; + g_root.p_pkey_table = (ib_net16_t *)cl_zalloc( size ); + if( !g_root.p_pkey_table ) + return IB_SUCCESS; + g_root.num_pkeys = p_port_rec->p_port_attr->num_pkeys; + cl_memcpy( g_root.p_pkey_table, + p_port_rec->p_port_attr->p_pkey_table, size ); + + /* Set the port_guid last to indicate that we're ready. */ + g_root.port_guid = p_port_rec->p_port_attr->port_guid; + return IB_SUCCESS; +} + + +/* + * Register for PnP events and wait until a port becomes active. + */ +static boolean_t +__reg_pnp() +{ + ib_api_status_t status; + ib_pnp_req_t pnp_req; + ib_pnp_handle_t h_pnp; + + cl_memclr( &pnp_req, sizeof( ib_pnp_req_t ) ); + pnp_req.pnp_class = IB_PNP_PORT; + pnp_req.pnp_context = &g_root; + pnp_req.pfn_pnp_cb = __pnp_cb; + + /* Register for PnP events. */ + status = ib_reg_pnp( g_root.h_al, &pnp_req, &h_pnp ); + if( status != IB_SUCCESS ) + { + printf( "ib_reg_pnp failed [%s]!\n", ib_get_err_str(status) ); + return FALSE; + } + + /* Wait until a port goes active. */ + while( !g_root.port_guid ) + cl_thread_suspend( 10 ); + + /* Deregister from PnP. */ + ib_dereg_pnp( h_pnp, NULL ); + + return TRUE; +} + + + +static boolean_t +__init_root() +{ + ib_api_status_t status; + + CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl ); + + cl_mutex_construct( &g_root.mutex ); + if( cl_mutex_init( &g_root.mutex ) != CL_SUCCESS ) + return FALSE; + + /* Open AL. */ + status = ib_open_al( &g_root.h_al ); + if( status != IB_SUCCESS ) + { + printf( "ib_open_al failed [%s]!\n", ib_get_err_str(status) ); + return FALSE; + } + + /* Register for PnP events, and wait until we have an active port. */ + if( !__reg_pnp() ) + return FALSE; + + /* Open the CA. */ + status = ib_open_ca( g_root.h_al, + g_root.ca_guid, + __ca_async_event_cb, + &g_root, + &g_root.h_ca ); + if( status != IB_SUCCESS ) + { + printf( "ib_open_ca failed [%s]!\n", ib_get_err_str(status) ); + return FALSE; + } + + /* Create a PD. */ + status = ib_alloc_pd( g_root.h_ca, IB_PDT_NORMAL, &g_root, + &g_root.h_pd ); + if( status != IB_SUCCESS ) + { + printf( "ib_alloc_pd failed [%s]!\n", ib_get_err_str(status) ); + return FALSE; + } + + /* Get a path record to the remote side. */ + if( !__query_for_path() ) + { + printf( "Unable to query for path record!\n" ); + return FALSE; + } + + /* Allocate and register memory for the messages. */ + if( !__create_messages() ) + { + printf( "Unable to create messages!\n" ); + return FALSE; + } + + /* Create the connection endpoints. */ + g_root.p_nodes = (ib_node_t*)cl_zalloc( + sizeof(ib_node_t) * g_root.num_nodes ); + if( !g_root.p_nodes ) + { + printf( "Unable to allocate nodes\n" ); + return FALSE; + } + + CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl ); + return TRUE; +} + + + +static void +__cleanup() +{ + if( g_root.h_listen ) + ib_cm_cancel( g_root.h_listen, __cancel_listen_cb ); + + /* Close AL if it was opened. */ + if( g_root.h_al ) + ib_close_al( g_root.h_al ); + + cl_mutex_destroy( &g_root.mutex ); + + if( g_root.p_mem ) + cl_free( g_root.p_mem ); + + if( g_root.p_pkey_table ) + cl_free( g_root.p_pkey_table ); + + /* Free all allocated memory. */ + if( g_root.p_nodes ) + cl_free( g_root.p_nodes ); +} + + + +/* + * Have the server start listening for connections. + */ +static boolean_t +__listen() +{ + ib_cm_listen_t cm_listen; + ib_api_status_t status; + + cl_memclr( &cm_listen, sizeof( ib_cm_listen_t ) ); + + /* The server side listens. */ + cm_listen.svc_id = CMT_BASE_SVC_ID + g_root.inst_id; + + cm_listen.pfn_cm_req_cb = __req_cb; + + cm_listen.qp_type = IB_QPT_RELIABLE_CONN; + + status = ib_cm_listen( g_root.h_al, + &cm_listen, + &g_root, + &g_root.h_listen ); + if( status != IB_SUCCESS ) + { + printf( "ib_cm_listen failed [%s]!\n", ib_get_err_str(status) ); + return FALSE; + } + return TRUE; +} + + + +/* + * Initiate all client connection requests. + */ +static ib_api_status_t +__conn_reqs() +{ + ib_api_status_t status; + int32_t i; + uint8_t pdata[IB_REQ_PDATA_SIZE]; + + g_root.cm_req.p_req_pdata = pdata; + g_root.cm_req.req_length = IB_REQ_PDATA_SIZE; + + /* Request a connection for each client. */ + for( i = 0; i < g_root.num_nodes; i++ ) + { + g_root.cm_req.h_qp = g_root.p_nodes[i].h_qp; + + status = ib_cm_req( &g_root.cm_req ); + if( status != IB_SUCCESS ) + { + printf( "ib_cm_req failed [%s]!\n", ib_get_err_str(status) ); + return status; + } + } + return IB_SUCCESS; +} + + + +/* + * Send any connection replies waiting to be sent. + */ +static ib_api_status_t +__conn_reps() +{ + ib_api_status_t status; + uintn_t i; + uint8_t pdata[IB_REP_PDATA_SIZE]; + + g_root.cm_rep.p_rep_pdata = pdata; + g_root.cm_rep.rep_length = IB_REP_PDATA_SIZE; + + /* Send a reply for each connection that requires one. */ + for( i = 0; i < g_root.conn_index; i++ ) + { + g_root.cm_rep.h_qp = g_root.p_nodes[i].h_qp; + status = ib_cm_rep( g_root.p_nodes[i].h_cm_req, &g_root.cm_rep ); + if( status != IB_SUCCESS ) + { + printf( "ib_cm_rep failed [%s]!\n", ib_get_err_str(status) ); + return status; + } + } + return IB_SUCCESS; +} + + + +/* + * Establish all connections. + */ +static ib_api_status_t +__connect() +{ + uint64_t total_time; + ib_api_status_t status; + + CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl ); + + printf( "Connecting...\n" ); + cl_mutex_acquire( &g_root.mutex ); + g_root.state = test_connecting; + + /* Initiate the connections. */ + if( g_root.is_server ) + { + /* + * Send any replies. Note that we hold the mutex while sending the + * replies since we need to use the global cm_rep structure. + */ + status = __conn_reps(); + cl_mutex_release( &g_root.mutex ); + } + else + { + cl_mutex_release( &g_root.mutex ); + g_root.conn_start_time = cl_get_time_stamp(); + status = __conn_reqs(); + } + + if( status != IB_SUCCESS ) + return status; + + /* Wait for all connections to complete. */ + while( g_root.num_connected < g_root.num_nodes ) + cl_thread_suspend( 0 ); + + /* Calculate the total connection time. */ + total_time = cl_get_time_stamp() - g_root.conn_start_time; + g_root.state = test_idle; + + /* Reset connection information for next test. */ + g_root.conn_index = 0; + g_root.conn_start_time = 0; + + printf( "Connect time: %"PRId64" ms\n", total_time/1000 ); + + CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl ); + return status; +} + + + +static void +__disconnect() +{ + ib_api_status_t status; + int32_t i; + ib_node_t *p_node; + uint64_t total_time, start_time; + + printf( "Disconnecting...\n" ); + + /* Initiate the disconnection process. */ + cl_mutex_acquire( &g_root.mutex ); + g_root.state = test_disconnecting; + start_time = cl_get_time_stamp(); + cl_mutex_release( &g_root.mutex ); + + /* We hold the mutex to prevent calling ib_cm_drep at the same time. */ + for( i = 0; i < g_root.num_nodes; i++ ) + { + p_node = &g_root.p_nodes[i]; + + /* + * Send the DREQ. Note that some of these may fail, since the + * remote side may be disconnecting at the same time. Call DREQ + * only if we haven't called DREP yet. + */ + cl_mutex_acquire( &g_root.mutex ); + switch( p_node->state ) + { + case node_conn: + g_root.cm_dreq.h_qp = p_node->h_qp; + status = ib_cm_dreq( &g_root.cm_dreq ); + if( status == IB_SUCCESS ) + p_node->state = node_dreq_sent; + break; + + case node_dreq_rcvd: + status = ib_cm_drep( p_node->h_cm_dreq, &g_root.cm_drep ); + + /* If the DREP was successful, we're done with this connection. */ + if( status == IB_SUCCESS ) + { + p_node->state = node_idle; + cl_atomic_dec( &g_root.num_connected ); + } + break; + + default: + /* Node is already disconnected. */ + break; + } + cl_mutex_release( &g_root.mutex ); + } + + /* Wait for all disconnections to complete. */ + while( g_root.num_connected ) + cl_thread_suspend( 0 ); + + if( g_root.h_listen ) + { + ib_cm_cancel( g_root.h_listen, __cancel_listen_cb ); + g_root.h_listen = NULL; + } + /* Calculate the total connection time. */ + total_time = cl_get_time_stamp() - start_time; + g_root.state = test_idle; + + printf( "Disconnect time: %"PRId64" ms\n", total_time/1000 ); +} + + + +/* + * Send the requested number of messages on each connection. + */ +static boolean_t +__send_msgs() +{ + ib_api_status_t status; + int32_t i; + uint32_t m; + ib_send_wr_t send_wr; + ib_send_wr_t *p_send_failure; + ib_local_ds_t ds_array; + + CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl ); + + /* For each connection... */ + for( i = 0; i < g_root.num_nodes; i++ ) + { + /* Send the specified number of messages. */ + for( m = 0; m < g_root.num_msgs; m++ ) + { + /* Get the buffer for this message. */ + if( g_root.per_msg_buf ) + { + ds_array.vaddr = (uintn_t)(g_root.p_mem_send + + (i * g_root.num_msgs) + (m * g_root.msg_size)); + } + else + { + ds_array.vaddr = (uintn_t)g_root.p_mem; + } + ds_array.length = g_root.msg_size; + ds_array.lkey = g_root.lkey; + + /* Format the send WR for this message. */ + send_wr.ds_array = &ds_array; + send_wr.send_opt = IB_SEND_OPT_SIGNALED | IB_SEND_OPT_SOLICITED; + send_wr.send_opt |= ((g_root.msg_size <= 4)? IB_SEND_OPT_IMMEDIATE : 0x0 ); + send_wr.wr_type = WR_SEND; + send_wr.num_ds = ((g_root.msg_size <= 4)? 0 : 1 ); + send_wr.p_next = NULL; + send_wr.wr_id = m; + + if( g_root.msg_size < g_root.p_nodes[i].max_inline ) + send_wr.send_opt |= IB_SEND_OPT_INLINE; + + /* Torpedoes away! Send the message. */ + CL_PRINT( CMT_DBG_VERBOSE, cmt_dbg_lvl, (".") ); + status = ib_post_send( g_root.p_nodes[i].h_qp, &send_wr, + &p_send_failure ); + if( status != IB_SUCCESS ) + { + printf( "ib_post_send failed [%s]!\n", + ib_get_err_str(status) ); + return FALSE; + } + } + } + + CL_PRINT( CMT_DBG_VERBOSE, cmt_dbg_lvl, ("\n") ); + CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl ); + return TRUE; +} + + + +/* + * Remove num_msgs completions from the specified CQ. + */ +static boolean_t +__poll_cq( + IN ib_node_t *p_node, + IN ib_cq_handle_t h_cq ) +{ + ib_api_status_t status = IB_SUCCESS; + ib_wc_t free_wc[2]; + ib_wc_t *p_free_wc, *p_done_wc; + + CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl ); + + while( status != IB_NOT_FOUND ) + { + /* Get all completions. */ + p_free_wc = &free_wc[0]; + free_wc[0].p_next = &free_wc[1]; + free_wc[1].p_next = NULL; + p_done_wc = NULL; + + status = ib_poll_cq( h_cq, &p_free_wc, &p_done_wc ); + + /* Continue polling if nothing is done. */ + if( status == IB_NOT_FOUND ) + break; + + /* Abort if an error occurred. */ + if( status != IB_SUCCESS ) + { + printf( "Error polling status = %#x( wc_status =%s)\n", + status, + ((p_done_wc != NULL )? wc_status_text[p_done_wc->status]:"N/A") ); + return FALSE; + } + + while( p_done_wc ) + { + switch( p_done_wc->status ) + { + case IB_WCS_SUCCESS: + CL_PRINT( CMT_DBG_VERBOSE, cmt_dbg_lvl, + ("Got a completion: \n\ttype....:%s\n\twr_id...:%"PRIx64"\n" + "status....:%s\n", wc_type_text[p_done_wc->wc_type], + p_done_wc->wr_id, wc_status_text[p_done_wc->status] ) ); + + if( p_done_wc->wc_type == IB_WC_RECV ) + { + CL_ASSERT( p_done_wc->wr_id == p_node->recv_cnt ); + if( p_done_wc->length != g_root.msg_size ) + { + printf( "Error: received %d bytes, expected %d.\n", + p_done_wc->length, g_root.msg_size ); + } + + p_node->recv_cnt++; + g_root.total_recv++; + } + else + { + CL_ASSERT( p_done_wc->wr_id == p_node->send_cnt ); + p_node->send_cnt++; + g_root.total_sent++; + } + break; + + default: + printf( "[%d] Bad completion type(%s) status(%s)\n", + __LINE__, wc_type_text[p_done_wc->wc_type], + wc_status_text[p_done_wc->status] ); + return FALSE; + } + p_done_wc = p_done_wc->p_next; + } + } + + if( !g_root.is_polling ) + { + status = ib_rearm_cq(h_cq, FALSE); + if (status != IB_SUCCESS) + { + printf("Failed to rearm CQ %p\n", h_cq ); + return FALSE; + } + } + + CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl ); + return TRUE; +} + + + +/* + * Remove num_msgs completions from all send CQs for all connections. + */ +static boolean_t +__poll_send_cqs() +{ + ib_node_t *p_node; + int32_t i; + + for( i = 0; i < g_root.num_nodes; i++ ) + { + p_node = &g_root.p_nodes[i]; + while( p_node->send_cnt < g_root.num_msgs ) + { + if( !g_root.is_polling ) + cl_thread_suspend( 0 ); + else if( !__poll_cq( p_node, p_node->h_send_cq ) ) + return FALSE; + } + } + return TRUE; +} + + + +/* + * Remove num_msgs completions from all receive CQs for all connections. + */ +static boolean_t +__poll_recv_cqs() +{ + ib_node_t *p_node; + int32_t i; + + for( i = 0; i < g_root.num_nodes; i++ ) + { + p_node = &g_root.p_nodes[i]; + while( p_node->recv_cnt < g_root.num_msgs ) + { + if( !g_root.is_polling ) + cl_thread_suspend( 0 ); + else if( !__poll_cq( p_node, p_node->h_recv_cq ) ) + return FALSE; + } + } + return TRUE; +} + + + +/********************************************************************** + **********************************************************************/ + +int __cdecl +main( + int argc, + char* argv[] ) +{ + uint64_t start_time, total_time; + uint64_t total_xfer; + uint32_t i; + + cl_memclr( &g_root, sizeof(ib_root_t) ); + + /* Set defaults. */ + if( !__parse_options( argc, argv ) ) + return 1; + + /* Initialize the root - open all common HCA resources. */ + if( !__init_root() ) + { + printf( "__init_root failed\n" ); + __cleanup(); + return 1; + } + + /* + * Execute the test the specified number of times. Abort the test + * if any errors occur. + */ + total_xfer = g_root.num_msgs * g_root.msg_size * g_root.num_nodes; + for( i = 0; i < g_root.num_iter; i++ ) + { + printf( "----- Iteration: %d, %d connections -----\n", + i, g_root.num_nodes ); + + /* Initialize the connection parameters. */ + __init_conn_info(); + __init_qp_info(); + __create_nodes(); + /* Start listening for connections if we're the server. */ + if( g_root.is_server ) + __listen(); + + cl_thread_suspend(1000); + /* Allocate a new set of QPs for the connections. */ + if( __create_qps() != IB_SUCCESS ) + { + printf( "Unable to allocate QPs for test.\n" ); + break; + } + + /* Establish all connections. */ + if( __connect() != IB_SUCCESS ) + { + printf( "Failed to establish connections.\n" ); + break; + } + + printf( "Transfering data...\n" ); + g_root.state = test_transfering; + start_time = cl_get_time_stamp(); + + if( g_root.num_msgs ) + { + if( g_root.is_server ) + { + /* The server initiate the sends to avoid race conditions. */ + if( !__send_msgs() ) + break; + + /* Get all send completions. */ + if( !__poll_send_cqs() ) + break; + + /* Get all receive completions. */ + if( !__poll_recv_cqs() ) + break; + } + else + { + /* Get all receive completions. */ + if( !__poll_recv_cqs() ) + break; + + /* Reply to the sends. */ + if( !__send_msgs() ) + break; + + /* Get all send completions. */ + if( !__poll_send_cqs() ) + break; + } + } + + total_time = cl_get_time_stamp() - start_time; + g_root.state = test_idle; + + printf( "Data transfer time: %"PRId64" ms, %d messages/conn, " + "%"PRId64" total bytes", total_time/1000, + g_root.num_msgs, total_xfer ); + if ( total_xfer > (4*1024*1024) ) + { + double mb; + mb = ((double)total_xfer / (1024.0*1024.0)) + / ((double)total_time / 1000000.0); + printf(" %4.2f MB/s",mb); + } + printf("\n"); + + /* Disconnect all connections. */ + __disconnect(); + __destroy_qps(); + __destroy_nodes(); + } + + __cleanup(); + return 0; +} diff --git a/branches/WOF2-3/tests/cmtest/user/makefile b/branches/WOF2-3/tests/cmtest/user/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-3/tests/cmtest/user/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\inc\openib.def diff --git a/branches/WOF2-3/tests/dirs b/branches/WOF2-3/tests/dirs new file mode 100644 index 00000000..9485cbef --- /dev/null +++ b/branches/WOF2-3/tests/dirs @@ -0,0 +1,8 @@ +DIRS=\ + alts \ + cmtest \ + wsd \ + ibat \ + limits \ + wherebu \ + perftest diff --git a/branches/WOF2-3/tests/ibat/dirs b/branches/WOF2-3/tests/ibat/dirs new file mode 100644 index 00000000..389156fd --- /dev/null +++ b/branches/WOF2-3/tests/ibat/dirs @@ -0,0 +1,2 @@ +DIRS=\ + user diff --git a/branches/WOF2-3/tests/ibat/user/PrintIp.c b/branches/WOF2-3/tests/ibat/user/PrintIp.c new file mode 100644 index 00000000..9c5133ae --- /dev/null +++ b/branches/WOF2-3/tests/ibat/user/PrintIp.c @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include +#include +#include +#include +#include "iba\ib_types.h" +#include + + +// Print all ips that are related to infiniband on this computer +int print_ips() +{ + HANDLE hKernelLib; + HRESULT hr = S_OK; + char temp [1000]; + char temp1 [1000]; + IOCTL_IBAT_PORTS_IN ipoib_ports_in; + IOCTL_IBAT_PORTS_OUT *p_ipoib_ports_out; + IBAT_PORT_RECORD *ports_records; + + IOCTL_IBAT_IP_ADDRESSES_IN addresses_in; + IOCTL_IBAT_IP_ADDRESSES_OUT *addresses_out; + IP_ADDRESS *ip_addreses; + + BOOL ret; + int i,j; + DWORD BytesReturned = 0; + + printf("Adapters that are known to the ipoib modules are:\n\n"); + + hKernelLib = + CreateFileW( + IBAT_WIN32_NAME, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, // share mode none + NULL, // no security + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL // no template + ); + + if (hKernelLib == INVALID_HANDLE_VALUE) { + hr = HRESULT_FROM_WIN32(GetLastError()); + printf("failed to open the kernel device hr=0x%x\n", hr); + return 1; + } + RtlSecureZeroMemory(&ipoib_ports_in, sizeof (ipoib_ports_in)); + RtlSecureZeroMemory(&addresses_in, sizeof(addresses_in)); + ipoib_ports_in.Version = IBAT_IOCTL_VERSION; + + p_ipoib_ports_out = (IOCTL_IBAT_PORTS_OUT *)temp; + + ret = DeviceIoControl( + hKernelLib, + IOCTL_IBAT_PORTS, + &ipoib_ports_in, + sizeof(ipoib_ports_in), + p_ipoib_ports_out, + sizeof(temp), + &BytesReturned, + NULL + ); + + if (ret == 0) { + hr = HRESULT_FROM_WIN32(GetLastError()); + printf("DeviceIoControl failed for IOCTL_IBAT_PORTS hr=0x%x\n", hr); + return 1; + } + if (p_ipoib_ports_out->Size > sizeof(temp)) { + printf("Data truncated, please call again with a buffer of %d bytes", p_ipoib_ports_out->Size); + } + + ports_records = p_ipoib_ports_out->Ports; + printf("Number of devices %d\n", p_ipoib_ports_out->NumPorts); + for (i = 0 ; i < p_ipoib_ports_out->NumPorts; i++) + { + printf("%d: ca guid = 0x%I64x port guid=0x%I64x\n", i, CL_NTOH64(ports_records[i].CaGuid), CL_NTOH64(ports_records[i].PortGuid)); + + // print the ip adresses of this port + addresses_in.Version = IBAT_IOCTL_VERSION; + addresses_in.PortGuid = ports_records[i].PortGuid; + + addresses_out = (IOCTL_IBAT_IP_ADDRESSES_OUT *)temp1; + + ret = DeviceIoControl( + hKernelLib, + IOCTL_IBAT_IP_ADDRESSES, + &addresses_in, + sizeof(addresses_in), + addresses_out, + sizeof(temp1), + &BytesReturned, + NULL + ); + + if (ret == 0) + { + hr = HRESULT_FROM_WIN32(GetLastError()); + printf("DeviceIoControl failed for IOCTL_IBAT_IP_ADDRESSES hr=0x%x\n", hr); + return 1; + } + if (addresses_out->Size > sizeof(temp1) ) + { + printf("Data truncated, please call again with a buffer of %d bytes", p_ipoib_ports_out->Size); + return 1; + } + + printf(" found %d ips:", addresses_out->AddressCount); + ip_addreses = addresses_out->Address; + for (j = 0; j < addresses_out->AddressCount; j++) + { + printf(" %d.%d.%d.%d ", + ip_addreses[j].Address[12], + ip_addreses[j].Address[13], + ip_addreses[j].Address[14], + ip_addreses[j].Address[15]); + } + printf("\n"); + } + + return 0; +}; + +void print_usage(char *argv[]) +{ + printf("This program is used to print ip adapters and their addresses or to do arp\n"); + printf("Usage is: %s \n",argv[0]); + printf("or %s (for example %s remoteip 1.2.3.4)\n", argv[0],argv[0]); +} + +int remote_ip(char *remote_ip) +{ + HANDLE hKernelLib; + HRESULT hr = S_OK; + IPAddr ip; + char *pIp = (char *)&ip; + int b1,b2,b3,b4; + DWORD ret; + IOCTL_IBAT_MAC_TO_GID_IN mac; + IOCTL_IBAT_MAC_TO_GID_OUT gid; + DWORD BytesReturned = 0; + + ULONG pMacAddr[2], PhyAddrLen ; + unsigned char *pMac = (unsigned char *)&pMacAddr; + PhyAddrLen = sizeof(pMacAddr); + RtlSecureZeroMemory(&mac, sizeof(mac)); + hKernelLib = + CreateFileW( + IBAT_WIN32_NAME, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, // share mode none + NULL, // no security + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL // no template + ); + + if (hKernelLib == INVALID_HANDLE_VALUE) + { + hr = HRESULT_FROM_WIN32(GetLastError()); + printf("failed to open the kernel device hr=0x%x\n", hr); + return 1; + } + + sscanf(remote_ip, "%d.%d.%d.%d", &b1, &b2, &b3, &b4); + printf("Calling arp for addresses %d.%d.%d.%d\n", b1, b2, b3, b4); + + pIp[0] = (char)b1; + pIp[1] = (char)b2; + pIp[2] = (char)b3; + pIp[3] = (char)b4; + + ret = SendARP(ip ,0 ,pMacAddr, &PhyAddrLen ); + if (ret != NO_ERROR) + { + printf("Error in SendARP"); + return 1; + } + + printf("Mac of the remote addresses is %x-%x-%x-%x-%x-%x\n", + pMac[0], pMac[1], pMac[2], pMac[3], pMac[4], pMac[5] ); + + // query for the gid + memcpy(mac.DestMac, pMac, 6); + + ret = DeviceIoControl( + hKernelLib, + IOCTL_IBAT_MAC_TO_GID, + &mac, + sizeof(mac), + &gid, + sizeof(gid), + &BytesReturned, + NULL ); + + if (ret == 0) + { + hr = HRESULT_FROM_WIN32(GetLastError()); + printf("DeviceIoControl failed for IOCTL_IBAT_IP_ADDRESSES hr=0x%x\n", hr); + } + + printf("lid of remote ip is = 0x%I64x : 0x%I64x\n", CL_NTOH64(gid.DestGid.unicast.prefix), CL_NTOH64(gid.DestGid.unicast.interface_id)); + + return 0; +} + + +int __cdecl main(int argc, char *argv[]) +{ + if (argc < 2) { + print_usage(argv); + return 1; + } + if (!strcmp(argv[1], "print_ips")) { + return print_ips(); + } + if (!strcmp(argv[1], "remoteip")) { + return remote_ip(argv[2]); + } + print_usage(argv); + return 1; +} diff --git a/branches/WOF2-3/tests/ibat/user/SOURCES b/branches/WOF2-3/tests/ibat/user/SOURCES new file mode 100644 index 00000000..99f5ed7e --- /dev/null +++ b/branches/WOF2-3/tests/ibat/user/SOURCES @@ -0,0 +1,18 @@ +TARGETNAME=PrintIP +TARGETPATH=..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE=PROGRAM +UMTYPE=console +USE_MSVCRT=1 + +SOURCES=\ + PrintIp.c + +TARGETLIBS=\ + $(SDK_LIB_PATH)\ws2_32.lib \ + $(SDK_LIB_PATH)\Iphlpapi.lib + +MSC_WARNING_LEVEL= /W4 + +INCLUDES=..\..\..\inc;\ + ..\..\..\inc\user;\ + $(PLATFORM_SDK_PATH)\include; diff --git a/branches/WOF2-3/tests/ibat/user/makefile b/branches/WOF2-3/tests/ibat/user/makefile new file mode 100644 index 00000000..128ed372 --- /dev/null +++ b/branches/WOF2-3/tests/ibat/user/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the Windows NT DDK +# + +!INCLUDE ..\..\..\inc\openib.def diff --git a/branches/WOF2-3/tests/limits/dirs b/branches/WOF2-3/tests/limits/dirs new file mode 100644 index 00000000..389156fd --- /dev/null +++ b/branches/WOF2-3/tests/limits/dirs @@ -0,0 +1,2 @@ +DIRS=\ + user diff --git a/branches/WOF2-3/tests/limits/user/SOURCES b/branches/WOF2-3/tests/limits/user/SOURCES new file mode 100644 index 00000000..b6059f76 --- /dev/null +++ b/branches/WOF2-3/tests/limits/user/SOURCES @@ -0,0 +1,20 @@ +TARGETNAME=ib_limits +TARGETPATH=..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE=PROGRAM +UMTYPE=console +USE_MSVCRT=1 + +SOURCES=limits_main.c + +INCLUDES=..\..\..\inc;..\..\..\inc\user; + +TARGETLIBS= \ +!if $(FREEBUILD) + $(TARGETPATH)\*\complib.lib \ + $(TARGETPATH)\*\ibal.lib +!else + $(TARGETPATH)\*\complibd.lib \ + $(TARGETPATH)\*\ibald.lib +!endif + +MSC_WARNING_LEVEL= /W3 diff --git a/branches/WOF2-3/tests/limits/user/limits_main.c b/branches/WOF2-3/tests/limits/user/limits_main.c new file mode 100644 index 00000000..c23f2d42 --- /dev/null +++ b/branches/WOF2-3/tests/limits/user/limits_main.c @@ -0,0 +1,530 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* + * Abstract: + * Test limits for: + * - memory registration + * - CQ creation + * - CQ resize + * - QP creation + * + * Environment: + * User Mode + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* Globals */ +#define CMT_DBG_VERBOSE 1 + + +uint32_t cmt_dbg_lvl = 0x80000000; + + +/********************************************************************** + **********************************************************************/ +static void +__show_usage() +{ + printf( "\n------- ib_limits - Usage and options ----------------------\n" ); + printf( "Usage: ib_limits [options]\n"); + printf( "Options:\n" ); + printf( "-m\n" + "--memory\n" + "\tThis option directs ib_limits to test memory registration\n" ); + printf( "-c\n" + "--cq\n" + "\tThis option directs ib_limits to test CQ creation\n" ); + printf( "-r\n" + "--resize_cq\n" + "\tThis option directs ib_limits to test CQ resize\n" ); + printf( "-q\n" + "--qp\n" + "\tThis option directs ib_limits to test QP creation\n" ); + printf( "-v\n" + "--verbose\n" + " This option enables verbosity level to debug console.\n" ); + printf( "-h\n" + "--help\n" + " Display this usage info then exit.\n\n" ); +} + + +/* Windows support. */ +struct option +{ + const char *long_name; + unsigned long flag; + void *pfn_handler; + char short_name; +}; + +static char *optarg; + +#define strtoull strtoul + + +boolean_t test_mr, test_cq, test_resize, test_qp; + + +char +getopt_long( + int argc, + char *argv[], + const char *short_option, + const struct option *long_option, + void *unused ) +{ + static int i = 1; + int j; + char ret = 0; + + UNUSED_PARAM( unused ); + + if( i == argc ) + return -1; + + if( argv[i][0] != '-' ) + return ret; + + /* find the first character of the value. */ + for( j = 1; isalpha( argv[i][j] ); j++ ) + ; + optarg = &argv[i][j]; + + if( argv[i][1] == '-' ) + { + /* Long option. */ + for( j = 0; long_option[j].long_name; j++ ) + { + if( strncmp( &argv[i][2], long_option[j].long_name, + optarg - argv[i] - 2 ) ) + { + continue; + } + + switch( long_option[j].flag ) + { + case 1: + if( *optarg == '\0' ) + return 0; + default: + break; + } + ret = long_option[j].short_name; + break; + } + } + else + { + for( j = 0; short_option[j] != '\0'; j++ ) + { + if( !isalpha( short_option[j] ) ) + return 0; + + if( short_option[j] == argv[i][1] ) + { + ret = short_option[j]; + break; + } + + if( short_option[j+1] == ':' ) + { + if( *optarg == '\0' ) + return 0; + j++; + } + } + } + i++; + return ret; +} + + +static boolean_t +__parse_options( + int argc, + char* argv[] ) +{ + uint32_t next_option; + const char* const short_option = "mcrq:vh"; + + /* + 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[] = + { + { "memory", 2, NULL, 'm'}, + { "cq", 2, NULL, 'c'}, + { "resize_cq",2, NULL, 'r'}, + { "qp", 2, NULL, 'q'}, + { "verbose", 0, NULL, 'v'}, + { "help", 0, NULL, 'h'}, + { NULL, 0, NULL, 0 } /* Required at end of array */ + }; + + test_mr = FALSE; + test_cq = FALSE; + test_resize = FALSE; + test_qp = FALSE; + + /* parse cmd line arguments as input params */ + do + { + next_option = getopt_long( argc, argv, short_option, + long_option, NULL ); + + switch( next_option ) + { + case 'm': + test_mr = TRUE; + printf( "\tTest Memory Registration\n" ); + break; + + case 'c': + test_cq = TRUE; + printf( "\tTest CQ\n" ); + break; + + case 'r': + test_resize = TRUE; + printf( "\tTest CQ Resize\n" ); + break; + + case 'q': + test_qp = TRUE; + printf( "\tTest QP\n" ); + break; + + case 'v': + cmt_dbg_lvl = 0xFFFFFFFF; + printf( "\tverbose\n" ); + break; + + case 'h': + __show_usage(); + return FALSE; + + case -1: + break; + + default: /* something wrong */ + __show_usage(); + return FALSE; + } + } while( next_option != -1 ); + + return TRUE; +} + + +struct __mr_buf +{ + cl_list_item_t list_item; + ib_mr_handle_t h_mr; + char buf[8192 - sizeof(ib_mr_handle_t) - sizeof(cl_list_item_t)]; +}; + +static void +__test_mr( + ib_pd_handle_t h_pd ) +{ + ib_api_status_t status = IB_SUCCESS; + struct __mr_buf *p_mr; + int i = 0; + ib_mr_create_t mr_create; + cl_qlist_t mr_list; + net32_t lkey, rkey; + int64_t reg_time, dereg_time, tmp_time, cnt; + + printf( "MR testing [\n" ); + + cl_qlist_init( &mr_list ); + reg_time = 0; + dereg_time = 0; + cnt = 0; + + do + { + p_mr = cl_malloc( sizeof(struct __mr_buf) ); + if( !p_mr ) + { + i++; + printf( "Failed to allocate memory.\n" ); + continue; + } + + mr_create.vaddr = p_mr->buf; + mr_create.length = sizeof(p_mr->buf); + mr_create.access_ctrl = + IB_AC_LOCAL_WRITE | IB_AC_RDMA_READ | IB_AC_RDMA_WRITE; + + tmp_time = cl_get_time_stamp(); + status = ib_reg_mem( h_pd, &mr_create, &lkey, &rkey, &p_mr->h_mr ); + if( status != IB_SUCCESS ) + { + i++; + printf( "ib_reg_mem returned %s\n", ib_get_err_str( status ) ); + cl_free( p_mr ); + continue; + } + reg_time += cl_get_time_stamp() - tmp_time; + cnt++; + + cl_qlist_insert_tail( &mr_list, &p_mr->list_item ); + + } while( status == IB_SUCCESS || i < 1000 ); + + while( cl_qlist_count( &mr_list ) ) + { + p_mr = PARENT_STRUCT( cl_qlist_remove_head( &mr_list ), + struct __mr_buf, list_item ); + + tmp_time = cl_get_time_stamp(); + status = ib_dereg_mr( p_mr->h_mr ); + if( status != IB_SUCCESS ) + printf( "ib_dereg_mr returned %s\n", ib_get_err_str( status ) ); + dereg_time += cl_get_time_stamp() - tmp_time; + + cl_free( p_mr ); + } + + printf( "reg time %f, dereg time %f\n", (double)reg_time/(double)cnt, + (double)dereg_time/(double)cnt ); + printf( "MR testing ]\n" ); +} + + +struct __cq +{ + cl_list_item_t list_item; + ib_cq_handle_t h_cq; +}; + +static void +__test_cq( + ib_ca_handle_t h_ca, + boolean_t resize ) +{ + ib_api_status_t status = IB_SUCCESS; + struct __cq *p_cq; + int i = 0, j; + ib_cq_create_t cq_create; + cl_qlist_t cq_list; + cl_waitobj_handle_t h_waitobj; + uint32_t size; + + printf( "CQ %stesting [\n", resize?"resize ":"" ); + + cl_qlist_init( &cq_list ); + + if( cl_waitobj_create( FALSE, &h_waitobj ) != CL_SUCCESS ) + { + printf( "Failed to allocate CQ wait object.\n" ); + return; + } + + do + { + p_cq = cl_malloc( sizeof(*p_cq) ); + if( !p_cq ) + { + i++; + printf( "Failed to allocate memory.\n" ); + continue; + } + + cq_create.h_wait_obj = h_waitobj; + cq_create.pfn_comp_cb = NULL; + if( resize ) + cq_create.size = 32; + else + cq_create.size = 4096; + + status = ib_create_cq( h_ca, &cq_create, NULL, NULL, &p_cq->h_cq ); + if( status != IB_SUCCESS ) + { + i++; + printf( "ib_create_cq returned %s\n", ib_get_err_str( status ) ); + cl_free( p_cq ); + continue; + } + + if( resize ) + { + size = 256; + j = 0; + + do + { + status = ib_modify_cq( p_cq->h_cq, &size ); + if( status == IB_SUCCESS ) + { + size += 256; + } + else + { + j++; + printf( "ib_modify_cq returned %s\n", + ib_get_err_str( status ) ); + } + + } while( status == IB_SUCCESS || j < 100 ); + } + + cl_qlist_insert_tail( &cq_list, &p_cq->list_item ); + + } while( status == IB_SUCCESS || i < 1000 ); + + while( cl_qlist_count( &cq_list ) ) + { + p_cq = PARENT_STRUCT( cl_qlist_remove_head( &cq_list ), + struct __cq, list_item ); + + status = ib_destroy_cq( p_cq->h_cq, NULL ); + if( status != IB_SUCCESS ) + printf( "ib_destroy_cq returned %s\n", ib_get_err_str( status ) ); + + cl_free( p_cq ); + } + + printf( "CQ %stesting ]\n", resize?"resize ":"" ); +} + +/********************************************************************** + **********************************************************************/ +int __cdecl +main( + int argc, + char* argv[] ) +{ + ib_api_status_t status; + ib_al_handle_t h_al; + ib_ca_handle_t h_ca; + ib_pd_handle_t h_pd; + size_t size; + net64_t *ca_guids; + + /* Set defaults. */ + if( !__parse_options( argc, argv ) ) + return 1; + + status = ib_open_al( &h_al ); + if( status != IB_SUCCESS ) + { + printf( "ib_open_al returned %s\n", ib_get_err_str( status ) ); + return 1; + } + + size = 0; + status = ib_get_ca_guids( h_al, NULL, &size ); + if( status != IB_INSUFFICIENT_MEMORY ) + { + printf( "ib_get_ca_guids for array size returned %s", + ib_get_err_str( status ) ); + goto done; + } + + if( size == 0 ) + { + printf( "No CAs installed.\n" ); + goto done; + } + + ca_guids = malloc( sizeof(net64_t) * size ); + if( !ca_guids ) + { + printf( "Failed to allocate CA GUID array.\n" ); + goto done; + } + + status = ib_get_ca_guids( h_al, ca_guids, &size ); + if( status != IB_SUCCESS ) + { + printf( "ib_get_ca_guids for CA guids returned %s", + ib_get_err_str( status ) ); + free( ca_guids ); + goto done; + } + + status = ib_open_ca( h_al, ca_guids[0], NULL, NULL, &h_ca ); + free( ca_guids ); + if( status != IB_SUCCESS ) + { + printf( "ib_open_ca returned %s", ib_get_err_str( status ) ); + goto done; + } + + status = ib_alloc_pd( h_ca, IB_PDT_NORMAL, NULL, &h_pd ); + if( status != IB_SUCCESS ) + { + printf( "ib_alloc_pd returned %s", ib_get_err_str( status ) ); + goto done; + } + + if( test_mr ) + __test_mr( h_pd ); + + if( test_cq ) + __test_cq( h_ca, FALSE ); + + if( test_resize ) + __test_cq( h_ca, TRUE ); + + //if( test_qp ) + // __test_qp( h_ca, h_pd ); + +done: + ib_close_al( h_al ); + + return 0; +} diff --git a/branches/WOF2-3/tests/limits/user/makefile b/branches/WOF2-3/tests/limits/user/makefile new file mode 100644 index 00000000..9c985f57 --- /dev/null +++ b/branches/WOF2-3/tests/limits/user/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the Windows NT DDK +# + +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/branches/WOF2-3/tests/perftest/dirs b/branches/WOF2-3/tests/perftest/dirs new file mode 100644 index 00000000..de675306 --- /dev/null +++ b/branches/WOF2-3/tests/perftest/dirs @@ -0,0 +1,9 @@ +DIRS = \ + send_bw \ + write_bw \ + read_bw \ + send_lat \ + write_lat \ + read_lat \ + rdma_bw \ + rdma_lat \ No newline at end of file diff --git a/branches/WOF2-3/tests/perftest/perftest.c b/branches/WOF2-3/tests/perftest/perftest.c new file mode 100644 index 00000000..cd398464 --- /dev/null +++ b/branches/WOF2-3/tests/perftest/perftest.c @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies Ltd. All rights reserved. + * Copyright (c) 2005 Hewlett Packard, Inc (Grant Grundler) + * Copyright (c) 2008-2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "perftest.h" +#include + +UINT64 get_cycles() +{ + LARGE_INTEGER counter; + static UINT64 base_adj = 0; + static UINT64 running_adj = 0; + + if (base_adj == 0) { + int i; + + QueryPerformanceCounter(&counter); + base_adj = counter.QuadPart; + for (i = 0; i < (1 << 16) - 2; i++) { + QueryPerformanceCounter(&counter); + } + QueryPerformanceCounter(&counter); + base_adj = (counter.QuadPart - base_adj) >> 16; + } + + QueryPerformanceCounter(&counter); + + running_adj += base_adj; + return counter.QuadPart - running_adj; +} + +UINT64 get_freq() +{ + LARGE_INTEGER freq; + QueryPerformanceFrequency(&freq); + return freq.QuadPart; +} + +cycles_t get_median(int n, cycles_t delta[]) +{ + if ((n - 1) % 2) + return(delta[n / 2] + delta[n / 2 - 1]) / 2; + else + return delta[n / 2]; +} + +int __cdecl cycles_compare(const void * aptr, const void * bptr) +{ + const cycles_t *a = aptr; + const cycles_t *b = bptr; + if (*a < *b) return -1; + if (*a > *b) return 1; + return 0; + +} + +SOCKET pp_client_connect(const char *servername, int port) +{ + struct addrinfo *res, *t; + struct addrinfo hints; + char service[6]; + int n; + SOCKET sockfd = INVALID_SOCKET; + + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + sprintf(service, "%d\0", port); + + n = getaddrinfo(servername, service, &hints, &res); + if (n != 0) { + fprintf(stderr, "%s for %s:%d\n", gai_strerror(n), servername, port); + return INVALID_SOCKET; + } + + for (t = res; t; t = t->ai_next) { + sockfd = socket(t->ai_family, t->ai_socktype, t->ai_protocol); + if (sockfd != INVALID_SOCKET) { + if (!connect(sockfd, t->ai_addr, t->ai_addrlen)) + break; + closesocket(sockfd); + sockfd = INVALID_SOCKET; + } + } + + freeaddrinfo(res); + + if (sockfd == INVALID_SOCKET) { + fprintf(stderr, "Couldn't connect to %s:%d\n", servername, port); + } + return sockfd; +} + +SOCKET pp_server_connect(int port) +{ + struct addrinfo *res, *t; + struct addrinfo hints; + char service[6]; + SOCKET sockfd = INVALID_SOCKET, connfd; + int n; + + memset(&hints, 0, sizeof hints); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + sprintf(service, "%d\0", port); + + n = getaddrinfo(NULL, service, &hints, &res); + if (n != 0) { + fprintf(stderr, "%s for port %d\n", gai_strerror(n), port); + return INVALID_SOCKET; + } + + for (t = res; t; t = t->ai_next) { + sockfd = socket(t->ai_family, t->ai_socktype, t->ai_protocol); + if (sockfd != INVALID_SOCKET) { + n = 0; + setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &n, sizeof n); + n = 1; + setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *) &n, sizeof n); + + if (!bind(sockfd, t->ai_addr, t->ai_addrlen)) + break; + closesocket(sockfd); + sockfd = INVALID_SOCKET; + } + } + + freeaddrinfo(res); + + if (sockfd == INVALID_SOCKET) { + fprintf(stderr, "Couldn't listen to port %d\n", port); + return INVALID_SOCKET; + } + + listen(sockfd, 1); + connfd = accept(sockfd, NULL, 0); + if (connfd == INVALID_SOCKET) { + perror("server accept"); + fprintf(stderr, "accept() failed\n"); + } + + closesocket(sockfd); + return connfd; +} diff --git a/branches/WOF2-3/tests/perftest/perftest.h b/branches/WOF2-3/tests/perftest/perftest.h new file mode 100644 index 00000000..5bc63fa9 --- /dev/null +++ b/branches/WOF2-3/tests/perftest/perftest.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies Ltd. All rights reserved. + * Copyright (c) 2005 Hewlett Packard, Inc (Grant Grundler) + * Copyright (c) 2008-2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef _PERFTEST_H_ +#define _PERFTEST_H_ + +#include + +typedef UINT64 cycles_t; + +UINT64 get_cycles(); +UINT64 get_freq(); + +cycles_t get_median(int n, cycles_t delta[]); +int __cdecl cycles_compare(const void * aptr, const void * bptr); + +SOCKET pp_client_connect(const char *servername, int port); +SOCKET pp_server_connect(int port); + +#endif // _PERFTEST_H_ \ No newline at end of file diff --git a/branches/WOF2-3/tests/perftest/rdma_bw/SOURCES b/branches/WOF2-3/tests/perftest/rdma_bw/SOURCES new file mode 100644 index 00000000..835915f9 --- /dev/null +++ b/branches/WOF2-3/tests/perftest/rdma_bw/SOURCES @@ -0,0 +1,33 @@ +TARGETNAME = ibv_rdma_bw +TARGETPATH = ..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = PROGRAM + +UMTYPE = console +UMENTRY = main + +USE_MSVCRT = 1 +USE_STL = 1 +USE_NATIVE_EH = 1 +USE_IOSTREAM = 1 + +SOURCES = rdma_bw.rc rdma_bw.c ..\perftest.c + +INCLUDES = ..;..\..\..\ulp\libibverbs\include;\ + ..\..\..\ulp\librdmacm\include;\ + ..\..\..\inc;..\..\..\inc\user;\ + ..\..\..\inc\user\linux;..\..\..\etc\user; + +TARGETLIBS = \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\advapi32.lib \ + $(SDK_LIB_PATH)\user32.lib \ + $(SDK_LIB_PATH)\ole32.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\libibverbs.lib \ + $(TARGETPATH)\*\librdmacm.lib +!else + $(TARGETPATH)\*\libibverbsd.lib \ + $(TARGETPATH)\*\librdmacmd.lib +!endif + diff --git a/branches/WOF2-3/tests/perftest/rdma_bw/makefile b/branches/WOF2-3/tests/perftest/rdma_bw/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-3/tests/perftest/rdma_bw/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\inc\openib.def diff --git a/branches/WOF2-3/tests/perftest/rdma_bw/rdma_bw.c b/branches/WOF2-3/tests/perftest/rdma_bw/rdma_bw.c new file mode 100644 index 00000000..111db13c --- /dev/null +++ b/branches/WOF2-3/tests/perftest/rdma_bw/rdma_bw.c @@ -0,0 +1,1126 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies Ltd. All rights reserved. + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include + +#include "getopt.c" +#include "perftest.h" +#include +#include + +#define PINGPONG_RDMA_WRID 3 + +struct pingpong_context { + struct ibv_context *context; + struct ibv_pd *pd; + struct ibv_mr *mr; + struct ibv_cq *rcq; + struct ibv_cq *scq; + struct ibv_qp *qp; + struct ibv_comp_channel *ch; + void *buf; + unsigned size; + int tx_depth; + struct ibv_sge list; + struct ibv_send_wr wr; +}; + +struct pingpong_dest { + int lid; + int qpn; + int psn; + unsigned rkey; + unsigned long long vaddr; +}; + +struct pp_data { + int port; + int ib_port; + unsigned size; + int tx_depth; + int use_cma; + SOCKET sockfd; + char *servername; + struct pingpong_dest my_dest; + struct pingpong_dest *rem_dest; + struct ibv_device *ib_dev; + struct rdma_event_channel *cm_channel; + struct rdma_cm_id *cm_id; +}; + +static void pp_post_recv(struct pingpong_context *); +static void pp_wait_for_done(struct pingpong_context *); +static void pp_send_done(struct pingpong_context *); +static void pp_wait_for_start(struct pingpong_context *); +static void pp_send_start(struct pingpong_context *); +static void pp_close_cma(struct pp_data ); +static struct pingpong_context *pp_init_ctx(void *, struct pp_data *); + +static uint16_t pp_get_local_lid(struct pingpong_context *ctx, int port) +{ + struct ibv_port_attr attr; + + if (ibv_query_port(ctx->context, (uint8_t) port, &attr)) + return 0; + + return attr.lid; +} + +static struct pingpong_context *pp_client_connect_cma(struct pp_data *data) +{ + struct addrinfo *res; + struct addrinfo hints; + char service[6]; + int n; + SOCKET sockfd = INVALID_SOCKET; + struct rdma_cm_event *event; + struct sockaddr_in sin; + struct pingpong_context *ctx = NULL; + struct rdma_conn_param conn_param; + + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + sprintf(service, "%d", data->port); + + n = getaddrinfo(data->servername, service, &hints, &res); + + if (n != 0) { + fprintf(stderr, "%s for %s:%d\n", gai_strerror(n), data->servername, data->port); + goto err1; + } + + sin.sin_addr.s_addr = ((struct sockaddr_in*)res->ai_addr)->sin_addr.s_addr; + sin.sin_family = AF_INET; + sin.sin_port = htons((u_short) data->port); + if (rdma_resolve_addr(data->cm_id, NULL, + (struct sockaddr *)&sin, 2000)) { + fprintf(stderr, "rdma_resolve_addr failed\n"); + goto err2; + } + + if (rdma_get_cm_event(data->cm_channel, &event)) + goto err2; + + if (event->event != RDMA_CM_EVENT_ADDR_RESOLVED) { + fprintf(stderr, "unexpected CM event resolving addr %d\n", event->event); + goto err3; + } + rdma_ack_cm_event(event); + + if (rdma_resolve_route(data->cm_id, 2000)) { + fprintf(stderr, "rdma_resolve_route failed\n"); + goto err2; + } + + if (rdma_get_cm_event(data->cm_channel, &event)) + goto err2; + + if (event->event != RDMA_CM_EVENT_ROUTE_RESOLVED) { + fprintf(stderr, "unexpected CM event resolving route %d\n", event->event); + goto err3; + } + rdma_ack_cm_event(event); + ctx = pp_init_ctx(data->cm_id, data); + if (!ctx) { + fprintf(stderr, "pp_init_ctx failed\n"); + goto err2; + } + data->my_dest.psn = rand() & 0xffffff; + data->my_dest.qpn = 0; + data->my_dest.rkey = ctx->mr->rkey; + data->my_dest.vaddr = (uintptr_t)ctx->buf + ctx->size; + + memset(&conn_param, 0, sizeof conn_param); + conn_param.responder_resources = 1; + conn_param.initiator_depth = 1; + conn_param.retry_count = 5; + conn_param.private_data = &data->my_dest; + conn_param.private_data_len = sizeof(data->my_dest); + + if (rdma_connect(data->cm_id, &conn_param)) { + fprintf(stderr, "rdma_connect failure\n"); + goto err2; + } + + if (rdma_get_cm_event(data->cm_channel, &event)) + goto err2; + + if (event->event != RDMA_CM_EVENT_ESTABLISHED) { + fprintf(stderr, "unexpected CM event connecting %d\n", event->event); + goto err3; + } + if (!event->param.conn.private_data || + (event->param.conn.private_data_len < sizeof(*data->rem_dest))) { + fprintf(stderr, "bad private data ptr %p len %d\n", + event->param.conn.private_data, + event->param.conn.private_data_len); + goto err3; + } + data->rem_dest = malloc(sizeof *data->rem_dest); + if (!data->rem_dest) + goto err3; + + memcpy(data->rem_dest, event->param.conn.private_data, sizeof(*data->rem_dest)); + rdma_ack_cm_event(event); + freeaddrinfo(res); + return ctx; + +err3: + rdma_ack_cm_event(event); +err2: + freeaddrinfo(res); +err1: + return NULL; +} + +static struct pingpong_context *pp_client_connect_socket(struct pp_data *data) +{ + data->sockfd = pp_client_connect(data->servername, data->port); + if (data->sockfd == INVALID_SOCKET) { + return NULL; + } + + return pp_init_ctx(data->ib_dev, data); +} + +static struct pingpong_context *pp_rdma_client_connect(struct pp_data *data) +{ + return data->use_cma ? pp_client_connect_cma(data) : pp_client_connect_socket(data); +} + +static int pp_client_exch_dest(struct pp_data *data) +{ + char msg[sizeof "0000:000000:000000:00000000:0000000000000000"]; + int parsed; + + if (!data->use_cma) { + sprintf(msg, "%04x:%06x:%06x:%08x:%016Lx", data->my_dest.lid, + data->my_dest.qpn, data->my_dest.psn, + data->my_dest.rkey, data->my_dest.vaddr); + if (send(data->sockfd, msg, sizeof msg, 0) != sizeof msg) { + perror("client write"); + fprintf(stderr, "Couldn't send local address\n"); + goto err; + } + + if (recv(data->sockfd, msg, sizeof msg, 0) != sizeof msg) { + perror("client read"); + fprintf(stderr, "Couldn't read remote address\n"); + goto err; + } + + if (data->rem_dest != NULL) + free(data->rem_dest); + data->rem_dest = malloc(sizeof *data->rem_dest); + if (!data->rem_dest) + goto err; + + memset(data->rem_dest, 0, sizeof *data->rem_dest); + parsed = sscanf(msg, "%x:%x:%x:%x:%Lx", &data->rem_dest->lid, + &data->rem_dest->qpn, &data->rem_dest->psn, + &data->rem_dest->rkey, &data->rem_dest->vaddr); + + if (parsed != 5) { + fprintf(stderr, "Couldn't parse line <%.*s>\n", (int)sizeof msg, msg); + free(data->rem_dest); + goto err; + } + } + return 0; +err: + return 1; +} + +static struct pingpong_context *pp_server_connect_cma(struct pp_data *data) +{ + struct addrinfo *res; + struct addrinfo hints; + char service[6]; + SOCKET sockfd = INVALID_SOCKET; + int n; + struct rdma_cm_event *event, *accept_event; + struct sockaddr_in sin; + struct pingpong_context *ctx = NULL; + struct rdma_cm_id *child_cm_id; + struct rdma_conn_param conn_param; + + memset(&hints, 0, sizeof hints); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + sprintf(service, "%d", data->port); + + if ( (n = getaddrinfo(NULL, service, &hints, &res)) != 0 ) { + fprintf(stderr, "%s for port %d\n", gai_strerror(n), data->port); + goto err1; + } + + sin.sin_addr.s_addr = 0; + sin.sin_family = AF_INET; + sin.sin_port = htons((u_short) data->port); + if (rdma_bind_addr(data->cm_id, (struct sockaddr *)&sin)) { + fprintf(stderr, "rdma_bind_addr failed\n"); + goto err2; + } + + if (rdma_listen(data->cm_id, 0)) { + fprintf(stderr, "rdma_listen failed\n"); + goto err2; + } + + if (rdma_get_cm_event(data->cm_channel, &event)) + goto err2; + + if (event->event != RDMA_CM_EVENT_CONNECT_REQUEST) { + fprintf(stderr, "bad event waiting for connect request %d\n", event->event); + goto err3; + } + + if (!event->param.conn.private_data || + (event->param.conn.private_data_len < sizeof(*data->rem_dest))) { + fprintf(stderr, "bad private data len %d\n", event->param.conn.private_data_len); + goto err3; + } + + child_cm_id = (struct rdma_cm_id *)event->id; + data->rem_dest = malloc(sizeof *data->rem_dest); + if (!data->rem_dest) + goto err4; + + memcpy(data->rem_dest, event->param.conn.private_data, sizeof(*data->rem_dest)); + + ctx = pp_init_ctx(child_cm_id, data); + if (!ctx) { + goto err5; + } + data->my_dest.psn = rand() & 0xffffff; + data->my_dest.qpn = 0; + data->my_dest.rkey = ctx->mr->rkey; + data->my_dest.vaddr = (uintptr_t)ctx->buf + ctx->size; + + memset(&conn_param, 0, sizeof conn_param); + conn_param.responder_resources = 1; + conn_param.initiator_depth = 1; + conn_param.private_data = &data->my_dest; + conn_param.private_data_len = sizeof(data->my_dest); + if (rdma_accept(child_cm_id, &conn_param)) { + fprintf(stderr, "rdma_accept failed\n"); + goto err5; + } + if (rdma_get_cm_event(data->cm_channel, &accept_event)) { + fprintf(stderr, "rdma_get_cm_event error\n"); + goto err5; + } + if (accept_event->event != RDMA_CM_EVENT_ESTABLISHED) { + fprintf(stderr, "bad event waiting for established %d\n", event->event); + goto err6; + } + rdma_ack_cm_event(event); + rdma_ack_cm_event(accept_event); + freeaddrinfo(res); + return ctx; + +err6: + rdma_ack_cm_event(accept_event); +err5: + free(data->rem_dest); +err4: + rdma_destroy_id(child_cm_id); +err3: + rdma_ack_cm_event(event); +err2: + freeaddrinfo(res); +err1: + return NULL; +} + +static struct pingpong_context *pp_server_connect_socket(struct pp_data *data) +{ + data->sockfd = pp_server_connect(data->port); + if (data->sockfd == INVALID_SOCKET) { + return NULL; + } + + return pp_init_ctx(data->ib_dev, data); +} + +static struct pingpong_context *pp_rdma_server_connect(struct pp_data *data) +{ + return data->use_cma ? pp_server_connect_cma(data) : pp_server_connect_socket(data); +} + +static int pp_server_exch_dest(struct pp_data *data) +{ + char msg[sizeof "0000:000000:000000:00000000:0000000000000000"]; + int parsed; + int n; + + if (!data->use_cma) { + n = recv(data->sockfd, msg, sizeof msg, 0); + if (n != sizeof msg) { + perror("server read"); + fprintf(stderr, "%d/%d Couldn't read remote address\n", + n, (int) sizeof msg); + goto err; + } + + if (data->rem_dest != NULL) + free(data->rem_dest); + data->rem_dest = malloc(sizeof *data->rem_dest); + if (!data->rem_dest) + goto err; + + memset(data->rem_dest, 0, sizeof *data->rem_dest); + parsed = sscanf(msg, "%x:%x:%x:%x:%Lx", &data->rem_dest->lid, + &data->rem_dest->qpn, &data->rem_dest->psn, + &data->rem_dest->rkey, &data->rem_dest->vaddr); + if (parsed != 5) { + fprintf(stderr, "Couldn't parse line <%.*s>\n", (int)sizeof msg, msg); + free(data->rem_dest); + goto err; + } + + sprintf(msg, "%04x:%06x:%06x:%08x:%016Lx", data->my_dest.lid, + data->my_dest.qpn, data->my_dest.psn, + data->my_dest.rkey, data->my_dest.vaddr); + if (send(data->sockfd, msg, sizeof msg, 0) != sizeof msg) { + perror("server write"); + fprintf(stderr, "%Couldn't send local address\n"); + free(data->rem_dest); + goto err; + } + } + + return 0; +err: + return 1; +} + +static struct pingpong_context *pp_init_ctx(void *ptr, struct pp_data *data) +{ + struct pingpong_context *ctx; + struct ibv_device *ib_dev; + struct rdma_cm_id *cm_id; + struct ibv_qp_init_attr attr; + + ctx = malloc(sizeof *ctx); + if (!ctx) + return NULL; + + ctx->size = data->size; + ctx->tx_depth = data->tx_depth; + + ctx->buf = malloc(ctx->size * 2); + if (!ctx->buf) { + fprintf(stderr, "Couldn't allocate work buf.\n"); + return NULL; + } + + memset(ctx->buf, 0, ctx->size * 2); + + if (data->use_cma) { + cm_id = (struct rdma_cm_id *)ptr; + ctx->context = cm_id->verbs; + if (!ctx->context) { + fprintf(stderr, "Unbound cm_id!!\n"); + return NULL; + } + } else { + ib_dev = (struct ibv_device *)ptr; + ctx->context = ibv_open_device(ib_dev); + if (!ctx->context) { + fprintf(stderr, "Couldn't get context for %s\n", ibv_get_device_name(ib_dev)); + return NULL; + } + } + + ctx->pd = ibv_alloc_pd(ctx->context); + if (!ctx->pd) { + fprintf(stderr, "Couldn't allocate PD\n"); + return NULL; + } + + /* We dont really want IBV_ACCESS_LOCAL_WRITE, but IB spec says: + * The Consumer is not allowed to assign Remote Write or Remote Atomic to + * a Memory Region that has not been assigned Local Write. */ + ctx->mr = ibv_reg_mr(ctx->pd, ctx->buf, ctx->size * 2, + IBV_ACCESS_REMOTE_WRITE | IBV_ACCESS_LOCAL_WRITE); + if (!ctx->mr) { + fprintf(stderr, "Couldn't allocate MR\n"); + return NULL; + } + + ctx->ch = ibv_create_comp_channel(ctx->context); + if (!ctx->ch) { + fprintf(stderr, "Couldn't create comp channel\n"); + return NULL; + } + + ctx->rcq = ibv_create_cq(ctx->context, 1, NULL, NULL, 0); + if (!ctx->rcq) { + fprintf(stderr, "Couldn't create recv CQ\n"); + return NULL; + } + + ctx->scq = ibv_create_cq(ctx->context, ctx->tx_depth, ctx, ctx->ch, 0); + if (!ctx->scq) { + fprintf(stderr, "Couldn't create send CQ\n"); + return NULL; + } + + memset(&attr, 0, sizeof attr); + attr.send_cq = ctx->scq; + attr.recv_cq = ctx->rcq; + attr.cap.max_send_wr = ctx->tx_depth; + attr.cap.max_recv_wr = 1; + attr.cap.max_send_sge = 1; + attr.cap.max_recv_sge = 1; + attr.cap.max_inline_data = 0; + attr.qp_type = IBV_QPT_RC; + + if (data->use_cma) { + if (rdma_create_qp(cm_id, ctx->pd, &attr)) { + fprintf(stderr, "Couldn't create QP\n"); + return NULL; + } + ctx->qp = cm_id->qp; + pp_post_recv(ctx); + return ctx; + } else { + ctx->qp = ibv_create_qp(ctx->pd, &attr); + if (!ctx->qp) { + fprintf(stderr, "Couldn't create QP\n"); + return NULL; + } + { + struct ibv_qp_attr attr; + + attr.qp_state = IBV_QPS_INIT; + attr.pkey_index = 0; + attr.port_num = (uint8_t) data->ib_port; + attr.qp_access_flags = IBV_ACCESS_REMOTE_WRITE; + + if (ibv_modify_qp(ctx->qp, &attr, + IBV_QP_STATE | + IBV_QP_PKEY_INDEX | + IBV_QP_PORT | + IBV_QP_ACCESS_FLAGS)) { + fprintf(stderr, "Failed to modify QP to INIT\n"); + return NULL; + } + } + + return ctx; + } + +} + +static int pp_connect_ctx(struct pingpong_context *ctx, struct pp_data data) +{ + struct ibv_qp_attr attr; + memset(&attr, 0, sizeof attr); + + attr.qp_state = IBV_QPS_RTR; + attr.path_mtu = IBV_MTU_2048; + attr.dest_qp_num = data.rem_dest->qpn; + attr.rq_psn = data.rem_dest->psn; + attr.max_dest_rd_atomic = 1; + attr.min_rnr_timer = 12; + attr.ah_attr.is_global = 0; + attr.ah_attr.dlid = (uint16_t) data.rem_dest->lid; + attr.ah_attr.sl = 0; + attr.ah_attr.src_path_bits = 0; + attr.ah_attr.port_num = (uint8_t) data.ib_port; + if (ibv_modify_qp(ctx->qp, &attr, + IBV_QP_STATE | + IBV_QP_AV | + IBV_QP_PATH_MTU | + IBV_QP_DEST_QPN | + IBV_QP_RQ_PSN | + IBV_QP_MAX_DEST_RD_ATOMIC | + IBV_QP_MIN_RNR_TIMER)) { + fprintf(stderr, "Failed to modify QP to RTR\n"); + return 1; + } + + attr.qp_state = IBV_QPS_RTS; + attr.timeout = 14; + attr.retry_cnt = 7; + attr.rnr_retry = 7; + attr.sq_psn = data.my_dest.psn; + attr.max_rd_atomic = 1; + if (ibv_modify_qp(ctx->qp, &attr, + IBV_QP_STATE | + IBV_QP_TIMEOUT | + IBV_QP_RETRY_CNT | + IBV_QP_RNR_RETRY | + IBV_QP_SQ_PSN | + IBV_QP_MAX_QP_RD_ATOMIC)) { + fprintf(stderr, "Failed to modify QP to RTS\n"); + return 1; + } + + return 0; +} + +static void pp_post_recv(struct pingpong_context *ctx) +{ + struct ibv_sge list; + struct ibv_recv_wr wr, *bad_wr; + int rc; + + list.addr = (uintptr_t) ctx->buf; + list.length = 1; + list.lkey = ctx->mr->lkey; + wr.next = NULL; + wr.wr_id = 0xdeadbeef; + wr.sg_list = &list; + wr.num_sge = 1; + + rc = ibv_post_recv(ctx->qp, &wr, &bad_wr); + if (rc) { + perror("ibv_post_recv"); + fprintf(stderr, "ibv_post_recv failed %d\n", rc); + } +} + +static void pp_wait_for_done(struct pingpong_context *ctx) +{ + struct ibv_wc wc; + int ne; + + do { + ne = ibv_poll_cq(ctx->rcq, 1, &wc); + } while (ne == 0); + + if (wc.status) + fprintf(stderr, "bad wc status %d\n", wc.status); + if (!(wc.opcode & IBV_WC_RECV)) + fprintf(stderr, "bad wc opcode %d\n", wc.opcode); + if (wc.wr_id != 0xdeadbeef) + fprintf(stderr, "bad wc wr_id 0x%x\n", (int)wc.wr_id); +} + +static void pp_send_done(struct pingpong_context *ctx) +{ + struct ibv_send_wr *bad_wr; + struct ibv_wc wc; + int ne; + + ctx->list.addr = (uintptr_t) ctx->buf; + ctx->list.length = 1; + ctx->list.lkey = ctx->mr->lkey; + ctx->wr.wr_id = 0xcafebabe; + ctx->wr.sg_list = &ctx->list; + ctx->wr.num_sge = 1; + ctx->wr.opcode = IBV_WR_SEND; + ctx->wr.send_flags = IBV_SEND_SIGNALED; + ctx->wr.next = NULL; + if (ibv_post_send(ctx->qp, &ctx->wr, &bad_wr)) { + fprintf(stderr, "ibv_post_send failed\n"); + return; + } + do { + ne = ibv_poll_cq(ctx->scq, 1, &wc); + } while (ne == 0); + + if (wc.status) + fprintf(stderr, "bad wc status %d\n", wc.status); + if (wc.opcode != IBV_WC_SEND) + fprintf(stderr, "bad wc opcode %d\n", wc.opcode); + if (wc.wr_id != 0xcafebabe) + fprintf(stderr, "bad wc wr_id 0x%x\n", (int)wc.wr_id); +} + +static void pp_wait_for_start(struct pingpong_context *ctx) +{ + struct ibv_wc wc; + int ne; + + do { + ne = ibv_poll_cq(ctx->rcq, 1, &wc); + } while (ne == 0); + + if (wc.status) + fprintf(stderr, "bad wc status %d\n", wc.status); + if (!(wc.opcode & IBV_WC_RECV)) + fprintf(stderr, "bad wc opcode %d\n", wc.opcode); + if (wc.wr_id != 0xdeadbeef) + fprintf(stderr, "bad wc wr_id 0x%x\n", (int)wc.wr_id); + pp_post_recv(ctx); +} + +static void pp_send_start(struct pingpong_context *ctx) +{ + struct ibv_send_wr *bad_wr; + struct ibv_wc wc; + int ne; + + ctx->list.addr = (uintptr_t) ctx->buf; + ctx->list.length = 1; + ctx->list.lkey = ctx->mr->lkey; + ctx->wr.wr_id = 0xabbaabba; + ctx->wr.sg_list = &ctx->list; + ctx->wr.num_sge = 1; + ctx->wr.opcode = IBV_WR_SEND; + ctx->wr.send_flags = IBV_SEND_SIGNALED; + ctx->wr.next = NULL; + if (ibv_post_send(ctx->qp, &ctx->wr, &bad_wr)) { + fprintf(stderr, "ibv_post_send failed\n"); + return; + } + do { + ne = ibv_poll_cq(ctx->scq, 1, &wc); + } while (ne == 0); + + if (wc.status) + fprintf(stderr, "bad wc status %d\n", wc.status); + if (wc.opcode != IBV_WC_SEND) + fprintf(stderr, "bad wc opcode %d\n", wc.opcode); + if (wc.wr_id != 0xabbaabba) + fprintf(stderr, "bad wc wr_id 0x%x\n", (int)wc.wr_id); +} + +static void pp_close_cma(struct pp_data data) +{ + struct rdma_cm_event *event; + int rc; + + if (data.servername) { + rc = rdma_disconnect(data.cm_id); + if (rc) { + perror("rdma_disconnect"); + fprintf(stderr, "rdma disconnect error\n"); + return; + } + } + + rdma_get_cm_event(data.cm_channel, &event); + if (event->event != RDMA_CM_EVENT_DISCONNECTED) + fprintf(stderr, "unexpected event during disconnect %d\n", event->event); + rdma_ack_cm_event(event); + rdma_destroy_id(data.cm_id); + rdma_destroy_event_channel(data.cm_channel); +} + +static void usage(const char *argv0) +{ + printf("Usage:\n"); + printf(" %s start a server and wait for connection\n", argv0); + printf(" %s -h connect to server at \n", argv0); + printf("\n"); + printf("Options:\n"); + printf(" -p listen on/connect to port (default 18515)\n"); + printf(" -d use IB device (default first device found)\n"); + printf(" -i use port of IB device (default 1)\n"); + printf(" -s size of message to exchange (default 65536)\n"); + printf(" -t size of tx queue (default 100)\n"); + printf(" -n number of exchanges (at least 2, default 1000)\n"); + printf(" -b measure bidirectional bandwidth (default unidirectional)\n"); + printf(" -c use RDMA CM\n"); +} + +static void print_report(unsigned int iters, unsigned size, int duplex, + cycles_t *tposted, cycles_t *tcompleted) +{ + cycles_t cycles_to_units; + unsigned long tsize; /* Transferred size, in megabytes */ + int i, j; + int opt_posted = 0, opt_completed = 0; + cycles_t opt_delta; + cycles_t t; + + opt_delta = tcompleted[opt_posted] - tposted[opt_completed]; + + /* Find the peak bandwidth */ + for (i = 0; i < (int) iters; ++i) + for (j = i; j < (int) iters; ++j) { + t = (tcompleted[j] - tposted[i]) / (j - i + 1); + if (t < opt_delta) { + opt_delta = t; + opt_posted = i; + opt_completed = j; + } + } + + cycles_to_units = get_freq(); + + tsize = duplex ? 2 : 1; + tsize = tsize * size; + + { + double sec = (double) opt_delta / (double) cycles_to_units; + double mbytes = (double) tsize / (double) 0x100000; + printf("\nBandwidth peak (#%d to #%d): %7.2f MB/sec\n", + opt_posted, opt_completed, mbytes / sec); + + sec = (double) (tcompleted[iters - 1] - tposted[0]) / (double) cycles_to_units; + mbytes = (double) tsize * (double) iters / (double) 0x100000; + printf("Bandwidth average: %7.2f MB/sec\n", mbytes / sec); + + printf("Service Demand peak (#%d to #%d): %7.2f cycles/KB\n", + opt_posted, opt_completed, + (double) opt_delta * 1024. / (double) tsize); + printf("Service Demand Avg : %7.2f cycles/KB\n", + (double) (tcompleted[iters - 1] - tposted[0]) * 1024. / (double) (tsize * iters)); + } +} + + +int __cdecl main(int argc, char *argv[]) +{ + struct ibv_device **dev_list; + struct pingpong_context *ctx = NULL; + char *ib_devname = NULL; + int iters = 1000; + int scnt, ccnt; + int duplex = 0; + struct ibv_qp *qp; + cycles_t *tposted; + cycles_t *tcompleted; + struct pp_data data; + WORD version; + WSADATA wsdata; + int err; + + srand((unsigned int) time(NULL)); + version = MAKEWORD(2, 2); + err = WSAStartup(version, &wsdata); + if (err) + return -1; + + memset(&data, 0, sizeof data); + data.port = 18515; + data.ib_port = 1; + data.size = 65536; + data.tx_depth = 100; + data.use_cma = 0; + data.servername = NULL; + data.rem_dest = NULL; + data.ib_dev = NULL; + data.cm_channel = NULL; + data.cm_id = NULL; + + /* Parameter parsing. */ + while (1) { + int c; + + c = getopt(argc, argv, "h:p:d:i:s:n:t:bc"); + if (c == -1) + break; + + switch (c) { + case 'p': + data.port = strtol(optarg, NULL, 0); + if (data.port < 0 || data.port > 65535) { + usage(argv[0]); + return 1; + } + break; + + case 'd': + ib_devname = _strdup(optarg); + break; + + case 'i': + data.ib_port = strtol(optarg, NULL, 0); + if (data.ib_port < 0) { + usage(argv[0]); + return 1; + } + break; + + case 's': + data.size = strtol(optarg, NULL, 0); + break; + + case 't': + data.tx_depth = strtol(optarg, NULL, 0); + if (data.tx_depth < 1) { + usage(argv[0]); + return 1; + } + break; + + case 'n': + iters = strtol(optarg, NULL, 0); + if (iters < 2) { + usage(argv[0]); + return 1; + } + + break; + + case 'b': + duplex = 1; + break; + + case 'c': + data.use_cma = 1; + break; + + case 'h': + if (optarg) { + data.servername = _strdup(optarg); + break; + } + + default: + usage(argv[0]); + return 1; + } + } + + printf("port=%d | ib_port=%d | size=%d | tx_depth=%d | iters=%d | duplex=%d | cma=%d |\n", + data.port, data.ib_port, data.size, data.tx_depth, + iters, duplex, data.use_cma); + + /* Done with parameter parsing. Perform setup. */ + + if (data.use_cma) { + data.cm_channel = rdma_create_event_channel(); + if (!data.cm_channel) { + fprintf(stderr, "rdma_create_event_channel failed\n"); + return 1; + } + if (rdma_create_id(data.cm_channel, &data.cm_id, NULL, RDMA_PS_TCP)) { + fprintf(stderr, "rdma_create_id failed\n"); + return 1; + } + + if (data.servername) { + ctx = pp_rdma_client_connect(&data); + if (!ctx) + return 1; + } else { + ctx = pp_rdma_server_connect(&data); + if (!ctx) + return 1; + } + } else { + dev_list = ibv_get_device_list(NULL); + + if (!ib_devname) { + data.ib_dev = dev_list[0]; + if (!data.ib_dev) { + fprintf(stderr, "No IB devices found\n"); + return 1; + } + } else { + for (; (data.ib_dev = *dev_list); ++dev_list) + if (!strcmp(ibv_get_device_name(data.ib_dev), ib_devname)) + break; + if (!data.ib_dev) { + fprintf(stderr, "IB device %s not found\n", ib_devname); + return 1; + } + } + if (data.servername) { + ctx = pp_rdma_client_connect(&data); + if (!ctx) + return 1; + } else { + ctx = pp_rdma_server_connect(&data); + if (!ctx) + return 1; + } + data.my_dest.lid = pp_get_local_lid(ctx, data.ib_port); + if (!data.my_dest.lid) { + fprintf(stderr, "Local lid 0x0 detected. Is an SM running?\n"); + return 1; + } + data.my_dest.qpn = ctx->qp->qp_num; + data.my_dest.psn = rand() & 0xffffff; + data.my_dest.rkey = ctx->mr->rkey; + data.my_dest.vaddr = (uintptr_t) ctx->buf + ctx->size; + + /* Create connection between client and server. + * We do it by exchanging data over a TCP socket connection. */ + if (data.servername) { + if (pp_client_exch_dest(&data)) + return 1; + } else { + if (pp_server_exch_dest(&data)) + return 1; + } + } + + printf("%d: Local address: LID %#04x, QPN %#06x, PSN %#06x " + "RKey %#08x VAddr %p\n", + data.my_dest.lid, data.my_dest.qpn, data.my_dest.psn, + data.my_dest.rkey, data.my_dest.vaddr); + + printf("%d: Remote address: LID %#04x, QPN %#06x, PSN %#06x, " + "RKey %#08x VAddr %p\n\n", + data.rem_dest->lid, data.rem_dest->qpn, data.rem_dest->psn, + data.rem_dest->rkey, data.rem_dest->vaddr); + + if (data.use_cma) { + + /* + * Synch up and force the server to wait for the client to send + * the first message (MPA requirement). + */ + if (data.servername) { + pp_send_start(ctx); + } else { + pp_wait_for_start(ctx); + } + + } else { + if (pp_connect_ctx(ctx, data)) + return 1; + + /* An additional handshake is required *after* moving qp to RTR. + Arbitrarily reuse exch_dest for this purpose. */ + if (data.servername) { + if (pp_client_exch_dest(&data)) + return 1; + } else { + if (pp_server_exch_dest(&data)) + return 1; + } + } + + /* For half duplex tests, server just waits for client to exit */ + if (!data.servername && !duplex) { + if (data.use_cma) { + pp_wait_for_done(ctx); + pp_send_done(ctx); + //pp_close_cma(data); + } else { + pp_server_exch_dest(&data); + send(data.sockfd, "done", sizeof "done", 0); + closesocket(data.sockfd); + } + return 0; + } + + ctx->list.addr = (uintptr_t) ctx->buf; + ctx->list.length = ctx->size; + ctx->list.lkey = ctx->mr->lkey; + ctx->wr.wr.rdma.remote_addr = data.rem_dest->vaddr; + ctx->wr.wr.rdma.rkey = data.rem_dest->rkey; + ctx->wr.wr_id = PINGPONG_RDMA_WRID; + ctx->wr.sg_list = &ctx->list; + ctx->wr.num_sge = 1; + ctx->wr.opcode = IBV_WR_RDMA_WRITE; + ctx->wr.send_flags = IBV_SEND_SIGNALED; + ctx->wr.next = NULL; + + scnt = 0; + ccnt = 0; + + qp = ctx->qp; + + tposted = malloc(iters * sizeof *tposted); + + if (!tposted) { + perror("malloc"); + return 1; + } + + tcompleted = malloc(iters * sizeof *tcompleted); + + if (!tcompleted) { + perror("malloc"); + return 1; + } + + /* Done with setup. Start the test. */ + + while (scnt < iters || ccnt < iters) { + + while (scnt < iters && scnt - ccnt < data.tx_depth) { + struct ibv_send_wr *bad_wr; + if (data.servername) + tposted[scnt] = get_cycles(); + + if (ibv_post_send(qp, &ctx->wr, &bad_wr)) { + fprintf(stderr, "Couldn't post send: scnt=%d\n", scnt); + return 1; + } + ++scnt; + } + + if (ccnt < iters) { + struct ibv_wc wc; + int ne; + do { + ne = ibv_poll_cq(ctx->scq, 1, &wc); + } while (ne == 0); + + if (data.servername) + tcompleted[ccnt] = get_cycles(); + + if (ne < 0) { + fprintf(stderr, "poll CQ failed %d\n", ne); + return 1; + } + if (wc.status != IBV_WC_SUCCESS) { + fprintf(stderr, "Completion with error at %s:\n", + data.servername ? "client" : "server"); + fprintf(stderr, "Failed status %d: wr_id %d\n", wc.status, (int) wc.wr_id); + fprintf(stderr, "scnt=%d, ccnt=%d\n", scnt, ccnt); + return 1; + } + ccnt += 1; + } + } + + if (data.use_cma) { + /* This is racy when duplex mode is used*/ + pp_send_done(ctx); + pp_wait_for_done(ctx); + pp_close_cma(data); + } else { + if (data.servername) + pp_client_exch_dest(&data); + else + pp_server_exch_dest(&data); + + send(data.sockfd, "done", sizeof "done", 0); + closesocket(data.sockfd); + + } + + print_report(iters, data.size, duplex, tposted, tcompleted); + + free(tposted); + free(tcompleted); + return 0; +} diff --git a/branches/WOF2-3/tests/perftest/rdma_bw/rdma_bw.rc b/branches/WOF2-3/tests/perftest/rdma_bw/rdma_bw.rc new file mode 100644 index 00000000..70745e7a --- /dev/null +++ b/branches/WOF2-3/tests/perftest/rdma_bw/rdma_bw.rc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: write_lat.rc 474 2006-08-31 08:57:19Z sleybo $ + */ + + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef DBG +#define VER_FILEDESCRIPTION_STR "winverbs - RDMA Bandwidth Test (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "winverbs - RDMA Bandwidth Test " +#endif + +#define VER_INTERNALNAME_STR "ibv_rdma_bw.exe" +#define VER_ORIGINALFILENAME_STR "ibv_rdma_bw.exe" + +#include diff --git a/branches/WOF2-3/tests/perftest/rdma_lat/SOURCES b/branches/WOF2-3/tests/perftest/rdma_lat/SOURCES new file mode 100644 index 00000000..ab37d719 --- /dev/null +++ b/branches/WOF2-3/tests/perftest/rdma_lat/SOURCES @@ -0,0 +1,33 @@ +TARGETNAME = ibv_rdma_lat +TARGETPATH = ..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = PROGRAM + +UMTYPE = console +UMENTRY = main + +USE_MSVCRT = 1 +USE_STL = 1 +USE_NATIVE_EH = 1 +USE_IOSTREAM = 1 + +SOURCES = rdma_lat.rc rdma_lat.c ..\perftest.c + +INCLUDES = ..;..\..\..\ulp\libibverbs\include;\ + ..\..\..\ulp\librdmacm\include;\ + ..\..\..\inc;..\..\..\inc\user;\ + ..\..\..\inc\user\linux; + +TARGETLIBS = \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\advapi32.lib \ + $(SDK_LIB_PATH)\user32.lib \ + $(SDK_LIB_PATH)\ole32.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\libibverbs.lib \ + $(TARGETPATH)\*\librdmacm.lib +!else + $(TARGETPATH)\*\libibverbsd.lib \ + $(TARGETPATH)\*\librdmacmd.lib +!endif + diff --git a/branches/WOF2-3/tests/perftest/rdma_lat/makefile b/branches/WOF2-3/tests/perftest/rdma_lat/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-3/tests/perftest/rdma_lat/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\inc\openib.def diff --git a/branches/WOF2-3/tests/perftest/rdma_lat/rdma_lat.c b/branches/WOF2-3/tests/perftest/rdma_lat/rdma_lat.c new file mode 100644 index 00000000..41be5a26 --- /dev/null +++ b/branches/WOF2-3/tests/perftest/rdma_lat/rdma_lat.c @@ -0,0 +1,1147 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies Ltd. All rights reserved. + * Copyright (c) 2005 Hewlett Packard, Inc (Grant Grundler) + * Copyright (c) 2008-2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include + +#include "..\..\..\etc\user\getopt.c" +#include "perftest.h" +#include +#include + +#define PINGPONG_RDMA_WRID 3 +#define MAX_INLINE 400 + +static int inline_size = MAX_INLINE; + +struct report_options { + int unsorted; + int histogram; + int cycles; /* report delta's in cycles, not microsec's */ +}; + + +struct pingpong_context { + struct ibv_context *context; + struct ibv_pd *pd; + struct ibv_mr *mr; + struct ibv_cq *rcq; + struct ibv_cq *scq; + struct ibv_qp *qp; + void *buf; + volatile char *post_buf; + volatile char *poll_buf; + int size; + int tx_depth; + struct ibv_sge list; + struct ibv_send_wr wr; +}; + +struct pingpong_dest { + int lid; + int qpn; + int psn; + unsigned rkey; + unsigned long long vaddr; +}; + +struct pp_data { + int port; + int ib_port; + unsigned size; + int tx_depth; + int use_cma; + SOCKET sockfd; + char *servername; + struct pingpong_dest my_dest; + struct pingpong_dest *rem_dest; + struct ibv_device *ib_dev; + struct rdma_event_channel *cm_channel; + struct rdma_cm_id *cm_id; + +}; + +static void pp_post_recv(struct pingpong_context *); +static void pp_wait_for_done(struct pingpong_context *); +static void pp_send_done(struct pingpong_context *); +static void pp_wait_for_start(struct pingpong_context *); +static void pp_send_start(struct pingpong_context *); +static void pp_close_cma(struct pp_data ); +static struct pingpong_context *pp_init_ctx(void *, struct pp_data *); + +static uint16_t pp_get_local_lid(struct pingpong_context *ctx, int port) +{ + struct ibv_port_attr attr; + + if (ibv_query_port(ctx->context, (uint8_t) port, &attr)) + return 0; + + return attr.lid; +} + +static struct ibv_device *pp_find_dev(const char *ib_devname) +{ + struct ibv_device **dev_list; + struct ibv_device *ib_dev = NULL; + + dev_list = ibv_get_device_list(NULL); + + if (!ib_devname) { + ib_dev = dev_list[0]; + if (!ib_dev) + fprintf(stderr, "No IB devices found\n"); + } else { + for (; (ib_dev = *dev_list); ++dev_list) { + if (!strcmp(ibv_get_device_name(ib_dev), ib_devname)) + break; + } + if (!ib_dev) + fprintf(stderr, "IB device %s not found\n", ib_devname); + } + return ib_dev; +} + +#define KEY_MSG_SIZE (sizeof "0000:000000:000000:00000000:0000000000000000") +#define KEY_PRINT_FMT "%04x:%06x:%06x:%08x:%016Lx" + +static int pp_write_keys(SOCKET sockfd, const struct pingpong_dest *my_dest) +{ + char msg[KEY_MSG_SIZE]; + + sprintf(msg, KEY_PRINT_FMT, my_dest->lid, my_dest->qpn, + my_dest->psn, my_dest->rkey, my_dest->vaddr); + + if (send(sockfd, msg, sizeof msg, 0) != sizeof msg) { + perror("client send"); + fprintf(stderr, "Couldn't send local address\n"); + return -1; + } + + return 0; +} + +static int pp_read_keys(SOCKET sockfd, const struct pingpong_dest *my_dest, + struct pingpong_dest *rem_dest) +{ + int parsed; + char msg[KEY_MSG_SIZE]; + + if (recv(sockfd, msg, sizeof msg, 0) != sizeof msg) { + perror("pp_read_keys"); + fprintf(stderr, "Couldn't recv remote address\n"); + return -1; + } + + parsed = sscanf(msg, KEY_PRINT_FMT, &rem_dest->lid, &rem_dest->qpn, + &rem_dest->psn, &rem_dest->rkey, &rem_dest->vaddr); + + if (parsed != 5) { + fprintf(stderr, "Couldn't parse line <%.*s>\n", + (int)sizeof msg, msg); + return -1; + } + + return 0; +} + +static struct pingpong_context *pp_client_connect_cma(struct pp_data *data) +{ + struct addrinfo *res, *t; + struct addrinfo hints; + char service[6]; + int n; + SOCKET sockfd = INVALID_SOCKET; + struct rdma_cm_event *event; + struct sockaddr_in sin; + struct pingpong_context *ctx = NULL; + struct rdma_conn_param conn_param; + + memset(&hints, 0, sizeof hints); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + sprintf(service, "%d", data->port); + + n = getaddrinfo(data->servername, service, &hints, &res); + if (n < 0) { + fprintf(stderr, "%s for %s:%d\n", gai_strerror(n), + data->servername, data->port); + goto err1; + } + + sin.sin_addr.s_addr = ((struct sockaddr_in*)res->ai_addr)->sin_addr.s_addr; + sin.sin_family = AF_INET; + sin.sin_port = htons((u_short) data->port); + if (rdma_resolve_addr(data->cm_id, NULL, + (struct sockaddr *)&sin, 2000)) { + fprintf(stderr, "rdma_resolve_addr failed\n"); + goto err2; + } + + if (rdma_get_cm_event(data->cm_channel, &event)) + goto err2; + + if (event->event != RDMA_CM_EVENT_ADDR_RESOLVED) { + fprintf(stderr, "unexpected CM event resolving addr %d\n", event->event); + goto err3; + } + rdma_ack_cm_event(event); + + if (rdma_resolve_route(data->cm_id, 2000)) { + fprintf(stderr, "rdma_resolve_route failed\n"); + goto err2; + } + + if (rdma_get_cm_event(data->cm_channel, &event)) + goto err2; + + if (event->event != RDMA_CM_EVENT_ROUTE_RESOLVED) { + fprintf(stderr, "unexpected CM event resolving route %d\n", event->event); + goto err3; + } + rdma_ack_cm_event(event); + ctx = pp_init_ctx(data->cm_id, data); + if (!ctx) { + fprintf(stderr, "pp_init_ctx failed\n"); + goto err2; + } + data->my_dest.psn = rand() & 0xffffff; + data->my_dest.qpn = 0; + data->my_dest.rkey = ctx->mr->rkey; + data->my_dest.vaddr = (uintptr_t)ctx->buf + ctx->size; + + memset(&conn_param, 0, sizeof conn_param); + conn_param.responder_resources = 1; + conn_param.initiator_depth = 1; + conn_param.retry_count = 5; + conn_param.private_data = &data->my_dest; + conn_param.private_data_len = sizeof(data->my_dest); + + if (rdma_connect(data->cm_id, &conn_param)) { + fprintf(stderr, "rdma_connect failure\n"); + goto err2; + } + + if (rdma_get_cm_event(data->cm_channel, &event)) + goto err2; + + if (event->event != RDMA_CM_EVENT_ESTABLISHED) { + fprintf(stderr, "unexpected CM event connecting %d\n", event->event); + goto err3; + } + if (!event->param.conn.private_data || + (event->param.conn.private_data_len < sizeof(*data->rem_dest))) { + fprintf(stderr, "bad private data ptr %p len %d\n", + event->param.conn.private_data, + event->param.conn.private_data_len); + goto err3; + } + data->rem_dest = malloc(sizeof *data->rem_dest); + if (!data->rem_dest) + goto err3; + + memcpy(data->rem_dest, event->param.conn.private_data, sizeof(*data->rem_dest)); + rdma_ack_cm_event(event); + freeaddrinfo(res); + return ctx; + +err3: + rdma_ack_cm_event(event); +err2: + freeaddrinfo(res); +err1: + return NULL; + +} + +static struct pingpong_context *pp_client_connect_socket(struct pp_data *data) +{ + data->sockfd = pp_client_connect(data->servername, data->port); + if (data->sockfd == INVALID_SOCKET) { + return NULL; + } + + return pp_init_ctx(data->ib_dev, data); +} + +static struct pingpong_context *pp_rdma_client_connect(struct pp_data *data) +{ + return data->use_cma ? pp_client_connect_cma(data) : pp_client_connect_socket(data); +} + +static int pp_client_exch_dest(struct pp_data *data) +{ + if (data->rem_dest != NULL) + free(data->rem_dest); + + data->rem_dest = malloc(sizeof *data->rem_dest); + if (!data->rem_dest) + return -1; + + if (pp_write_keys(data->sockfd, &data->my_dest)) + return -1; + + return pp_read_keys(data->sockfd, &data->my_dest, data->rem_dest); +} + +static struct pingpong_context *pp_server_connect_cma(struct pp_data *data) +{ + struct addrinfo *res, *t; + struct addrinfo hints; + char service[6]; + SOCKET sockfd = INVALID_SOCKET, connfd; + int n; + struct rdma_cm_event *event, *accept_event; + struct sockaddr_in sin; + struct pingpong_context *ctx = NULL; + struct rdma_cm_id *child_cm_id; + struct rdma_conn_param conn_param; + + memset(&hints, 0, sizeof hints); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + sprintf(service, "%d", data->port); + + if ( (n = getaddrinfo(NULL, service, &hints, &res)) != 0 ) { + fprintf(stderr, "%s for port %d\n", gai_strerror(n), data->port); + goto err1; + } + + sin.sin_addr.s_addr = 0; + sin.sin_family = AF_INET; + sin.sin_port = htons((u_short) data->port); + if (rdma_bind_addr(data->cm_id, (struct sockaddr *)&sin)) { + fprintf(stderr, "rdma_bind_addr failed\n"); + goto err2; + } + + if (rdma_listen(data->cm_id, 0)) { + fprintf(stderr, "rdma_listen failed\n"); + goto err2; + } + + if (rdma_get_cm_event(data->cm_channel, &event)) + goto err2; + + if (event->event != RDMA_CM_EVENT_CONNECT_REQUEST) { + fprintf(stderr, "bad event waiting for connect request %d\n", event->event); + goto err3; + } + + if (!event->param.conn.private_data || + (event->param.conn.private_data_len < sizeof(*data->rem_dest))) { + fprintf(stderr, "bad private data len %d\n", event->param.conn.private_data_len); + goto err3; + } + + child_cm_id = (struct rdma_cm_id *)event->id; + data->rem_dest = malloc(sizeof *data->rem_dest); + if (!data->rem_dest) + goto err4; + + memcpy(data->rem_dest, event->param.conn.private_data, sizeof(*data->rem_dest)); + + ctx = pp_init_ctx(child_cm_id, data); + if (!ctx) { + goto err5; + } + data->my_dest.psn = rand() & 0xffffff; + data->my_dest.qpn = 0; + data->my_dest.rkey = ctx->mr->rkey; + data->my_dest.vaddr = (uintptr_t)ctx->buf + ctx->size; + + memset(&conn_param, 0, sizeof conn_param); + conn_param.responder_resources = 1; + conn_param.initiator_depth = 1; + conn_param.private_data = &data->my_dest; + conn_param.private_data_len = sizeof(data->my_dest); + if (rdma_accept(child_cm_id, &conn_param)) { + fprintf(stderr, "rdma_accept failed\n"); + goto err5; + } + if (rdma_get_cm_event(data->cm_channel, &accept_event)) { + fprintf(stderr, "rdma_get_cm_event error\n"); + goto err5; + } + if (accept_event->event != RDMA_CM_EVENT_ESTABLISHED) { + fprintf(stderr, "bad event waiting for established %d\n", event->event); + goto err6; + } + rdma_ack_cm_event(event); + rdma_ack_cm_event(accept_event); + freeaddrinfo(res); + return ctx; + +err6: + rdma_ack_cm_event(accept_event); +err5: + free(data->rem_dest); +err4: + rdma_destroy_id(child_cm_id); +err3: + rdma_ack_cm_event(event); +err2: + freeaddrinfo(res); +err1: + return NULL; +} + +static struct pingpong_context *pp_server_connect_socket(struct pp_data *data) +{ + data->sockfd = pp_server_connect(data->port); + if (data->sockfd == INVALID_SOCKET) { + return NULL; + } + + return pp_init_ctx(data->ib_dev, data); +} + +static struct pingpong_context *pp_rdma_server_connect(struct pp_data *data) +{ + return data->use_cma ? pp_server_connect_cma(data) : pp_server_connect_socket(data); +} + +static int pp_server_exch_dest(struct pp_data *data) +{ + if (data->rem_dest != NULL) + free(data->rem_dest); + data->rem_dest = malloc(sizeof *data->rem_dest); + + if (!data->rem_dest) + return -1; + + if (pp_read_keys(data->sockfd, &data->my_dest, data->rem_dest)) + return -1; + + return pp_write_keys(data->sockfd, &data->my_dest); +} + +static struct pingpong_context *pp_init_ctx(void *ptr, struct pp_data *data) +{ + struct pingpong_context *ctx; + struct ibv_device *ib_dev; + struct rdma_cm_id *cm_id; + struct ibv_qp_init_attr attr; + + ctx = malloc(sizeof *ctx); + if (!ctx) + return NULL; + + ctx->size = data->size; + ctx->tx_depth = data->tx_depth; + + ctx->buf = malloc(ctx->size * 2); + if (!ctx->buf) { + fprintf(stderr, "Couldn't allocate work buf.\n"); + return NULL; + } + + memset(ctx->buf, 0, ctx->size * 2); + + ctx->post_buf = (char *)ctx->buf + (ctx->size -1); + ctx->poll_buf = (char *)ctx->buf + (2 * ctx->size -1); + + if (data->use_cma) { + cm_id = (struct rdma_cm_id *)ptr; + ctx->context = cm_id->verbs; + if (!ctx->context) { + fprintf(stderr, "Unbound cm_id!!\n"); + return NULL; + } + + } else { + ib_dev = (struct ibv_device *)ptr; + ctx->context = ibv_open_device(ib_dev); + if (!ctx->context) { + fprintf(stderr, "Couldn't get context for %s\n", + ibv_get_device_name(ib_dev)); + return NULL; + } + } + + ctx->pd = ibv_alloc_pd(ctx->context); + if (!ctx->pd) { + fprintf(stderr, "Couldn't allocate PD\n"); + return NULL; + } + + /* We dont really want IBV_ACCESS_LOCAL_WRITE, but IB spec says: + * The Consumer is not allowed to assign Remote Write or Remote Atomic to + * a Memory Region that has not been assigned Local Write. */ + ctx->mr = ibv_reg_mr(ctx->pd, ctx->buf, ctx->size * 2, + IBV_ACCESS_REMOTE_WRITE | IBV_ACCESS_LOCAL_WRITE); + if (!ctx->mr) { + fprintf(stderr, "Couldn't allocate MR\n"); + return NULL; + } + + ctx->rcq = ibv_create_cq(ctx->context, 1, NULL, NULL, 0); + if (!ctx->rcq) { + fprintf(stderr, "%Couldn't create recv CQ\n"); + return NULL; + } + + ctx->scq = ibv_create_cq(ctx->context, ctx->tx_depth, ctx, NULL, 0); + if (!ctx->scq) { + fprintf(stderr, "Couldn't create send CQ\n"); + return NULL; + } + + memset(&attr, 0, sizeof attr); + attr.send_cq = ctx->scq; + attr.recv_cq = ctx->rcq; + attr.cap.max_send_wr = ctx->tx_depth; + attr.cap.max_recv_wr = 1; + attr.cap.max_send_sge = 1; + attr.cap.max_recv_sge = 1; + attr.cap.max_inline_data = inline_size; + attr.qp_type = IBV_QPT_RC; + + if (data->use_cma) { + if (rdma_create_qp(cm_id, ctx->pd, &attr)) { + fprintf(stderr, "Couldn't create QP\n"); + return NULL; + } + ctx->qp = cm_id->qp; + pp_post_recv(ctx); + } else { + ctx->qp = ibv_create_qp(ctx->pd, &attr); + if (!ctx->qp) { + fprintf(stderr, "Couldn't create QP\n"); + return NULL; + } + { + struct ibv_qp_attr attr; + + attr.qp_state = IBV_QPS_INIT; + attr.pkey_index = 0; + attr.port_num = (uint8_t) data->ib_port; + attr.qp_access_flags = IBV_ACCESS_REMOTE_WRITE; + + if (ibv_modify_qp(ctx->qp, &attr, + IBV_QP_STATE | + IBV_QP_PKEY_INDEX | + IBV_QP_PORT | + IBV_QP_ACCESS_FLAGS)) { + fprintf(stderr, "Failed to modify QP to INIT\n"); + return NULL; + } + } + } + + return ctx; +} + +static int pp_connect_ctx(struct pingpong_context *ctx, struct pp_data *data) +{ + struct ibv_qp_attr attr; + + memset(&attr, 0, sizeof attr); + + attr.qp_state = IBV_QPS_RTR, + attr.path_mtu = IBV_MTU_256, + attr.dest_qp_num = data->rem_dest->qpn, + attr.rq_psn = data->rem_dest->psn, + attr.max_dest_rd_atomic = 1, + attr.min_rnr_timer = 12, + attr.ah_attr.is_global = 0, + attr.ah_attr.dlid = (uint16_t) data->rem_dest->lid, + attr.ah_attr.sl = 0, + attr.ah_attr.src_path_bits = 0, + attr.ah_attr.port_num = (uint8_t) data->ib_port; + + if (ibv_modify_qp(ctx->qp, &attr, + IBV_QP_STATE | + IBV_QP_AV | + IBV_QP_PATH_MTU | + IBV_QP_DEST_QPN | + IBV_QP_RQ_PSN | + IBV_QP_MAX_DEST_RD_ATOMIC | + IBV_QP_MIN_RNR_TIMER)) { + fprintf(stderr, "Failed to modify QP to RTR\n"); + return 1; + } + + attr.qp_state = IBV_QPS_RTS; + attr.timeout = 14; + attr.retry_cnt = 7; + attr.rnr_retry = 7; + attr.sq_psn = data->my_dest.psn; + attr.max_rd_atomic = 1; + if (ibv_modify_qp(ctx->qp, &attr, + IBV_QP_STATE | + IBV_QP_TIMEOUT | + IBV_QP_RETRY_CNT | + IBV_QP_RNR_RETRY | + IBV_QP_SQ_PSN | + IBV_QP_MAX_QP_RD_ATOMIC)) { + fprintf(stderr, "Failed to modify QP to RTS\n"); + return 1; + } + + return 0; +} + +static int pp_open_port(struct pingpong_context *ctx, struct pp_data *data ) +{ + char addr_fmt[] = "%8s address: LID %#04x QPN %#06x PSN %#06x RKey %#08x VAddr %#016Lx\n"; + + /* Create connection between client and server. + * We do it by exchanging data over a TCP socket connection. */ + + data->my_dest.lid = pp_get_local_lid(ctx, data->ib_port); + data->my_dest.qpn = ctx->qp->qp_num; + data->my_dest.psn = rand() & 0xffffff; + if (!data->my_dest.lid) { + fprintf(stderr, "Local lid 0x0 detected. Is an SM running?\n"); + return -1; + } + data->my_dest.rkey = ctx->mr->rkey; + data->my_dest.vaddr = (uintptr_t)ctx->buf + ctx->size; + + printf(addr_fmt, "local", data->my_dest.lid, data->my_dest.qpn, data->my_dest.psn, + data->my_dest.rkey, data->my_dest.vaddr); + + if (data->servername) { + if (pp_client_exch_dest(data)) + return 1; + } else { + if (pp_server_exch_dest(data)) + return 1; + } + + printf(addr_fmt, "remote", data->rem_dest->lid, data->rem_dest->qpn, + data->rem_dest->psn, data->rem_dest->rkey, + data->rem_dest->vaddr); + + if (pp_connect_ctx(ctx, data)) + return 1; + + /* An additional handshake is required *after* moving qp to RTR. + Arbitrarily reuse exch_dest for this purpose. */ + if (data->servername) { + if (pp_client_exch_dest(data)) + return -1; + } else { + if (pp_server_exch_dest(data)) + return -1; + } + + if (send(data->sockfd, "done", sizeof "done", 0) != sizeof "done"){ + perror("send"); + fprintf(stderr, "Couldn't send to socket\n"); + return 1; + } + + closesocket(data->sockfd); + + return 0; +} + +static void pp_post_recv(struct pingpong_context *ctx) +{ + struct ibv_sge list; + struct ibv_recv_wr wr, *bad_wr; + int rc; + + list.addr = (uintptr_t) ctx->buf; + list.length = 1; + list.lkey = ctx->mr->lkey; + wr.next = NULL; + wr.wr_id = 0xdeadbeef; + wr.sg_list = &list; + wr.num_sge = 1; + + rc = ibv_post_recv(ctx->qp, &wr, &bad_wr); + if (rc) { + perror("ibv_post_recv"); + fprintf(stderr, "ibv_post_recv failed %d\n", rc); + } +} + +static void pp_wait_for_done(struct pingpong_context *ctx) +{ + struct ibv_wc wc; + int ne; + + do { + ne = ibv_poll_cq(ctx->rcq, 1, &wc); + } while (ne == 0); + + if (wc.status) + fprintf(stderr, "bad wc status %d\n", wc.status); + if (!(wc.opcode & IBV_WC_RECV)) + fprintf(stderr, "bad wc opcode %d\n", wc.opcode); + if (wc.wr_id != 0xdeadbeef) + fprintf(stderr, "bad wc wr_id 0x%x\n", (int)wc.wr_id); +} + +static void pp_send_done(struct pingpong_context *ctx) +{ + struct ibv_send_wr *bad_wr; + struct ibv_wc wc; + int ne; + + ctx->list.addr = (uintptr_t) ctx->buf; + ctx->list.length = 1; + ctx->list.lkey = ctx->mr->lkey; + ctx->wr.wr_id = 0xcafebabe; + ctx->wr.sg_list = &ctx->list; + ctx->wr.num_sge = 1; + ctx->wr.opcode = IBV_WR_SEND; + ctx->wr.send_flags = IBV_SEND_SIGNALED; + ctx->wr.next = NULL; + if (ibv_post_send(ctx->qp, &ctx->wr, &bad_wr)) { + fprintf(stderr, "ibv_post_send failed\n"); + return; + } + do { + ne = ibv_poll_cq(ctx->scq, 1, &wc); + } while (ne == 0); + + if (wc.status) + fprintf(stderr, "bad wc status %d\n", wc.status); + if (wc.opcode != IBV_WC_SEND) + fprintf(stderr, "bad wc opcode %d\n", wc.opcode); + if (wc.wr_id != 0xcafebabe) + fprintf(stderr, "bad wc wr_id 0x%x\n", (int)wc.wr_id); +} + +static void pp_wait_for_start(struct pingpong_context *ctx) +{ + struct ibv_wc wc; + int ne; + + do { + ne = ibv_poll_cq(ctx->rcq, 1, &wc); + } while (ne == 0); + + if (wc.status) + fprintf(stderr, "bad wc status %d\n", wc.status); + if (!(wc.opcode & IBV_WC_RECV)) + fprintf(stderr, "bad wc opcode %d\n", wc.opcode); + if (wc.wr_id != 0xdeadbeef) + fprintf(stderr, "bad wc wr_id 0x%x\n", (int)wc.wr_id); + pp_post_recv(ctx); +} + +static void pp_send_start(struct pingpong_context *ctx) +{ + struct ibv_send_wr *bad_wr; + struct ibv_wc wc; + int ne; + + ctx->list.addr = (uintptr_t) ctx->buf; + ctx->list.length = 1; + ctx->list.lkey = ctx->mr->lkey; + ctx->wr.wr_id = 0xabbaabba; + ctx->wr.sg_list = &ctx->list; + ctx->wr.num_sge = 1; + ctx->wr.opcode = IBV_WR_SEND; + ctx->wr.send_flags = IBV_SEND_SIGNALED; + ctx->wr.next = NULL; + if (ibv_post_send(ctx->qp, &ctx->wr, &bad_wr)) { + fprintf(stderr, "ibv_post_send failed\n"); + return; + } + do { + ne = ibv_poll_cq(ctx->scq, 1, &wc); + } while (ne == 0); + + if (wc.status) + fprintf(stderr, "bad wc status %d\n", wc.status); + if (wc.opcode != IBV_WC_SEND) + fprintf(stderr, "bad wc opcode %d\n", wc.opcode); + if (wc.wr_id != 0xabbaabba) + fprintf(stderr, "bad wc wr_id 0x%x\n", (int)wc.wr_id); +} + +static void pp_close_cma(struct pp_data data) +{ + struct rdma_cm_event *event; + int rc; + + if (data.servername) { + rc = rdma_disconnect(data.cm_id); + if (rc) { + perror("rdma_disconnect"); + fprintf(stderr, "rdma disconnect error\n"); + return; + } + } + + rdma_get_cm_event(data.cm_channel, &event); + if (event->event != RDMA_CM_EVENT_DISCONNECTED) + fprintf(stderr, "unexpected event during disconnect %d\n", + event->event); + rdma_ack_cm_event(event); + rdma_destroy_id(data.cm_id); + rdma_destroy_event_channel(data.cm_channel); +} + +static void usage(const char *argv0) +{ + printf("Usage:\n"); + printf(" %s start a server and wait for connection\n", argv0); + printf(" %s -h connect to server at \n", argv0); + printf("\n"); + printf("Options:\n"); + printf(" -p, --port= listen on/connect to port (default 18515)\n"); + printf(" -d, --ib-dev= use IB device (default first device found)\n"); + printf(" -i, --ib-port= use port of IB device (default 1)\n"); + printf(" -s, --size= size of message to exchange (default 1)\n"); + printf(" -t, --tx-depth= size of tx queue (default 50)\n"); + printf(" -n, --iters= number of exchanges (at least 2, default 1000)\n"); + printf(" -I, --inline_size= max size of message to be sent in inline mode (default 400)\n"); + printf(" -C, --report-cycles report times in cpu cycle units (default microseconds)\n"); + printf(" -H, --report-histogram print out all results (default print summary only)\n"); + printf(" -U, --report-unsorted (implies -H) print out unsorted results (default sorted)\n"); + printf(" -c, --cma Use the RDMA CMA to setup the RDMA connection\n"); +} + +static void print_report(struct report_options * options, + unsigned int iters, cycles_t *tstamp) +{ + cycles_t cycles_to_units; + cycles_t median; + unsigned int i; + const char* units; + cycles_t *delta = malloc((iters - 1) * sizeof *delta); + + if (!delta) { + perror("malloc"); + return; + } + + for (i = 0; i < iters - 1; ++i) + delta[i] = tstamp[i + 1] - tstamp[i]; + + + if (options->cycles) { + cycles_to_units = 1; + units = "cycles"; + } else { + cycles_to_units = get_freq(); + units = "usec"; + } + + if (options->unsorted) { + printf("#, %s\n", units); + for(i = 0; i < iters - 1; ++i) + printf("%d, %g\n", i + 1, (double) delta[i] / (double) cycles_to_units / 2.0); + } + + qsort(delta, iters - 1, sizeof *delta, cycles_compare); + + if (options->histogram) { + printf("#, %s\n", units); + for(i = 0; i < iters - 1; ++i) + printf("%d, %g\n", i + 1, (double) delta[i] / (double) cycles_to_units / 2.0); + } + + median = get_median(iters - 1, delta); + + printf("Latency typical: %g %s\n", + (double) median / (double) cycles_to_units / 2.0, units); + printf("Latency best : %g %s\n", + (double) delta[0] / (double) cycles_to_units / 2.0, units); + printf("Latency worst : %g %s\n", + (double) delta[iters - 2] / (double) cycles_to_units / 2.0, units); + + free(delta); +} + +int __cdecl main(int argc, char *argv[]) +{ + const char *ib_devname = NULL; + const char *servername = NULL; + int iters = 1000; + struct report_options report; + struct pingpong_context *ctx; + struct ibv_qp *qp; + struct ibv_send_wr *wr; + volatile char *poll_buf; + volatile char *post_buf; + int scnt, rcnt, ccnt; + cycles_t *tstamp; + struct pp_data data; + WORD version; + WSADATA wsdata; + int err; + + srand((unsigned int) time(NULL)); + version = MAKEWORD(2, 2); + err = WSAStartup(version, &wsdata); + if (err) + return -1; + + memset(&report, 0, sizeof report); + memset(&data, 0, sizeof data); + data.port = 18515; + data.ib_port = 1; + data.size = 1; + data.tx_depth = 50; + data.use_cma = 0; + data.servername = NULL; + data.rem_dest = NULL; + data.ib_dev = NULL; + data.cm_channel = NULL; + data.cm_id = NULL; + + /* Parameter parsing. */ + while (1) { + int c; + + c = getopt(argc, argv, "h:p:d:i:s:n:t:I:CHUc"); + if (c == -1) + break; + + switch (c) { + case 'p': + data.port = strtol(optarg, NULL, 0); + if (data.port < 0 || data.port > 65535) { + usage(argv[0]); + return 1; + } + break; + + case 'd': + ib_devname = _strdup(optarg); + break; + + case 'i': + data.ib_port = strtol(optarg, NULL, 0); + if (data.ib_port < 0) { + usage(argv[0]); + return 2; + } + break; + + case 's': + data.size = strtol(optarg, NULL, 0); + if (data.size < 1) { usage(argv[0]); return 3; } + break; + + case 't': + data.tx_depth = strtol(optarg, NULL, 0); + if (data.tx_depth < 1) { usage(argv[0]); return 4; } + break; + + case 'n': + iters = strtol(optarg, NULL, 0); + if (iters < 2) { + usage(argv[0]); + return 5; + } + break; + + case 'I': + inline_size = strtol(optarg, NULL, 0); + break; + + case 'C': + report.cycles = 1; + break; + + case 'H': + report.histogram = 1; + break; + + case 'U': + report.unsorted = 1; + break; + + case 'c': + data.use_cma = 1; + break; + + case 'h': + if (optarg) { + data.servername = _strdup(optarg); + break; + } + + default: + usage(argv[0]); + return 5; + } + } + + if (data.use_cma) { + data.cm_channel = rdma_create_event_channel(); + if (!data.cm_channel) { + fprintf(stderr, "rdma_create_event_channel failed\n"); + return 1; + } + if (rdma_create_id(data.cm_channel, &data.cm_id, NULL, RDMA_PS_TCP)) { + fprintf(stderr, "rdma_create_id failed\n"); + return 1; + } + + if (data.servername) { + ctx = pp_rdma_client_connect(&data); + if (!ctx) + return 1; + } else { + ctx = pp_rdma_server_connect(&data); + if (!ctx) + return 1; + } + + printf("Local address: LID %#04x, QPN %#06x, PSN %#06x " + "RKey %#08x VAddr %#016Lx\n", + data.my_dest.lid, data.my_dest.qpn, data.my_dest.psn, + data.my_dest.rkey, data.my_dest.vaddr); + + printf("Remote address: LID %#04x, QPN %#06x, PSN %#06x, " + "RKey %#08x VAddr %#016Lx\n\n", + data.rem_dest->lid, data.rem_dest->qpn, data.rem_dest->psn, + data.rem_dest->rkey, data.rem_dest->vaddr); + + if (data.servername) { + pp_send_start(ctx); + } else { + pp_wait_for_start(ctx); + } + + } else { + data.ib_dev = pp_find_dev(ib_devname); + if (!data.ib_dev) + return 7; + + if (data.servername) { + ctx = pp_rdma_client_connect(&data); + if (!ctx) + return 8; + } else { + ctx = pp_rdma_server_connect(&data); + if (!ctx) + return 8; + } + + if (pp_open_port(ctx, &data)) + return 9; + } + wr = &ctx->wr; + ctx->list.addr = (uintptr_t) ctx->buf; + ctx->list.length = ctx->size; + ctx->list.lkey = ctx->mr->lkey; + wr->wr.rdma.remote_addr = data.rem_dest->vaddr; + wr->wr.rdma.rkey = data.rem_dest->rkey; + ctx->wr.wr_id = PINGPONG_RDMA_WRID; + ctx->wr.sg_list = &ctx->list; + ctx->wr.num_sge = 1; + ctx->wr.opcode = IBV_WR_RDMA_WRITE; + if (ctx->size > inline_size || ctx->size == 0) { + ctx->wr.send_flags = IBV_SEND_SIGNALED; + } else { + ctx->wr.send_flags = IBV_SEND_SIGNALED | IBV_SEND_INLINE; + } + ctx->wr.next = NULL; + + scnt = 0; + rcnt = 0; + ccnt = 0; + poll_buf = ctx->poll_buf; + post_buf = ctx->post_buf; + qp = ctx->qp; + + tstamp = malloc(iters * sizeof *tstamp); + if (!tstamp) { + perror("malloc"); + return 10; + } + + /* Done with setup. Start the test. */ + + while (scnt < iters || ccnt < iters || rcnt < iters) { + + /* Wait till buffer changes. */ + if (rcnt < iters && !(scnt < 1 && data.servername)) { + ++rcnt; + while (*poll_buf != (char)rcnt) + ; + /* Here the data is already in the physical memory. + If we wanted to actually use it, we may need + a read memory barrier here. */ + } + + if (scnt < iters) { + struct ibv_send_wr *bad_wr; + if (data.servername) + tstamp[scnt] = get_cycles(); + + *post_buf = (char)++scnt; + if (ibv_post_send(qp, wr, &bad_wr)) { + fprintf(stderr, "Couldn't post send: scnt=%d\n", + scnt); + return 11; + } + } + + if (ccnt < iters) { + struct ibv_wc wc; + int ne; + ++ccnt; + do { + ne = ibv_poll_cq(ctx->scq, 1, &wc); + } while (ne == 0); + + if (ne < 0) { + fprintf(stderr, "poll CQ failed %d\n", ne); + return 12; + } + if (wc.status != IBV_WC_SUCCESS) { + fprintf(stderr, "Completion wth error at %s:\n", + servername ? "client" : "server"); + fprintf(stderr, "Failed status %d: wr_id %d\n", + wc.status, (int) wc.wr_id); + fprintf(stderr, "scnt=%d, rcnt=%d, ccnt=%d\n", + scnt, rcnt, ccnt); + return 13; + } + } + } + if (data.use_cma) { + pp_send_done(ctx); + pp_wait_for_done(ctx); + pp_close_cma(data); + } + + print_report(&report, iters, tstamp); + return 0; +} diff --git a/branches/WOF2-3/tests/perftest/rdma_lat/rdma_lat.rc b/branches/WOF2-3/tests/perftest/rdma_lat/rdma_lat.rc new file mode 100644 index 00000000..96b19557 --- /dev/null +++ b/branches/WOF2-3/tests/perftest/rdma_lat/rdma_lat.rc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: write_lat.rc 474 2006-08-31 08:57:19Z sleybo $ + */ + + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef DBG +#define VER_FILEDESCRIPTION_STR "winverbs - RDMA Latency Test (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "winverbs - RDMA Latency Test " +#endif + +#define VER_INTERNALNAME_STR "ibv_rdma_lat.exe" +#define VER_ORIGINALFILENAME_STR "ibv_rdma_lat.exe" + +#include diff --git a/branches/WOF2-3/tests/perftest/read_bw/SOURCES b/branches/WOF2-3/tests/perftest/read_bw/SOURCES new file mode 100644 index 00000000..fbf699fb --- /dev/null +++ b/branches/WOF2-3/tests/perftest/read_bw/SOURCES @@ -0,0 +1,30 @@ +TARGETNAME = ibv_read_bw +TARGETPATH = ..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = PROGRAM + +UMTYPE = console +UMENTRY = main + +USE_MSVCRT = 1 +USE_STL = 1 +USE_NATIVE_EH = 1 +USE_IOSTREAM = 1 + +SOURCES = read_bw.rc read_bw.c ..\perftest.c + +INCLUDES = ..;..\..\..\ulp\libibverbs\include;\ + ..\..\..\inc;..\..\..\inc\user;\ + ..\..\..\inc\user\linux; + +TARGETLIBS = \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\advapi32.lib \ + $(SDK_LIB_PATH)\user32.lib \ + $(SDK_LIB_PATH)\ole32.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\libibverbs.lib +!else + $(TARGETPATH)\*\libibverbsd.lib +!endif + diff --git a/branches/WOF2-3/tests/perftest/read_bw/makefile b/branches/WOF2-3/tests/perftest/read_bw/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-3/tests/perftest/read_bw/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\inc\openib.def diff --git a/branches/WOF2-3/tests/perftest/read_bw/read_bw.c b/branches/WOF2-3/tests/perftest/read_bw/read_bw.c new file mode 100644 index 00000000..62137179 --- /dev/null +++ b/branches/WOF2-3/tests/perftest/read_bw/read_bw.c @@ -0,0 +1,754 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2006 Mellanox Technologies Ltd. All rights reserved. + * Copyright (c) 2008-2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include + +#include "..\..\..\etc\user\getopt.c" +#include "perftest.h" +#include + +#define PINGPONG_READ_WRID 1 +#define VERSION 1.1 +#define ALL 1 +#define RC 0 + +struct user_parameters { + const char *servername; + int connection_type; + int mtu; + int all; /* run all msg size */ + int iters; + int tx_depth; + int max_out_read; + int use_event; +}; + +typedef UINT64 cycles_t; +cycles_t *tposted; +cycles_t *tcompleted; + +struct pingpong_context { + struct ibv_context *context; + struct ibv_comp_channel *channel; + struct ibv_pd *pd; + struct ibv_mr *mr; + struct ibv_cq *cq; + struct ibv_qp *qp; + void *buf; + unsigned size; + int tx_depth; + struct ibv_sge list; + struct ibv_send_wr wr; +}; + +struct pingpong_dest { + int lid; + int qpn; + int psn; + unsigned rkey; + unsigned long long vaddr; +}; + +static uint16_t pp_get_local_lid(struct pingpong_context *ctx, int port) +{ + struct ibv_port_attr attr; + + if (ibv_query_port(ctx->context, (uint8_t) port, &attr)) + return 0; + + return attr.lid; +} + +static struct pingpong_dest * pp_client_exch_dest(SOCKET sockfd, + const struct pingpong_dest *my_dest) +{ + struct pingpong_dest *rem_dest = NULL; + char msg[sizeof "0000:000000:000000:00000000:0000000000000000"]; + int parsed; + + sprintf(msg, "%04x:%06x:%06x:%08x:%016Lx", my_dest->lid, my_dest->qpn, + my_dest->psn,my_dest->rkey,my_dest->vaddr); + if (send(sockfd, msg, sizeof msg, 0) != sizeof msg) { + perror("client send"); + fprintf(stderr, "Couldn't send local address\n"); + goto out; + } + + if (recv(sockfd, msg, sizeof msg, 0) != sizeof msg) { + perror("client recv"); + fprintf(stderr, "Couldn't recv remote address\n"); + goto out; + } + + rem_dest = malloc(sizeof *rem_dest); + if (!rem_dest) + goto out; + + memset(rem_dest, 0, sizeof *rem_dest); + parsed = sscanf(msg, "%x:%x:%x:%x:%Lx", &rem_dest->lid, &rem_dest->qpn, + &rem_dest->psn,&rem_dest->rkey,&rem_dest->vaddr); + + if (parsed != 5) { + fprintf(stderr, "Couldn't parse line <%.*s>\n",(int)sizeof msg, + msg); + free(rem_dest); + rem_dest = NULL; + goto out; + } +out: + return rem_dest; +} + +static struct pingpong_dest *pp_server_exch_dest(SOCKET connfd, const struct pingpong_dest *my_dest) +{ + char msg[sizeof "0000:000000:000000:00000000:0000000000000000"]; + struct pingpong_dest *rem_dest = NULL; + int parsed; + int n; + + n = recv(connfd, msg, sizeof msg, 0); + if (n != sizeof msg) { + perror("server recv"); + fprintf(stderr, "%d/%d: Couldn't recv remote address\n", n, (int) sizeof msg); + goto out; + } + + rem_dest = malloc(sizeof *rem_dest); + if (!rem_dest) + goto out; + + memset(rem_dest, 0, sizeof *rem_dest); + parsed = sscanf(msg, "%x:%x:%x:%x:%Lx", &rem_dest->lid, &rem_dest->qpn, + &rem_dest->psn, &rem_dest->rkey, &rem_dest->vaddr); + if (parsed != 5) { + fprintf(stderr, "Couldn't parse line <%.*s>\n",(int)sizeof msg, + msg); + free(rem_dest); + rem_dest = NULL; + goto out; + } + + sprintf(msg, "%04x:%06x:%06x:%08x:%016Lx", my_dest->lid, my_dest->qpn, + my_dest->psn, my_dest->rkey, my_dest->vaddr); + if (send(connfd, msg, sizeof msg, 0) != sizeof msg) { + perror("server send"); + fprintf(stderr, "Couldn't send local address\n"); + free(rem_dest); + rem_dest = NULL; + goto out; + } +out: + return rem_dest; +} + +static struct pingpong_context *pp_init_ctx(struct ibv_device *ib_dev, + unsigned size, + int tx_depth, int port, + struct user_parameters *user_parm) +{ + struct pingpong_context *ctx; + struct ibv_device_attr device_attr; + ctx = malloc(sizeof *ctx); + if (!ctx) + return NULL; + + ctx->size = size; + ctx->tx_depth = tx_depth; + + ctx->buf = malloc(size * 2); + if (!ctx->buf) { + fprintf(stderr, "Couldn't allocate work buf.\n"); + return NULL; + } + + memset(ctx->buf, 0, size * 2); + + ctx->context = ibv_open_device(ib_dev); + if (!ctx->context) { + fprintf(stderr, "Couldn't get context for %s\n", + ibv_get_device_name(ib_dev)); + return NULL; + } + if (user_parm->mtu == 0) {/*user did not ask for specific mtu */ + if (ibv_query_device(ctx->context, &device_attr)) { + fprintf(stderr, "Failed to query device props"); + return NULL; + } + if (device_attr.vendor_part_id == 23108) + user_parm->mtu = 1024; + else + user_parm->mtu = 2048; + } + if (user_parm->use_event) { + ctx->channel = ibv_create_comp_channel(ctx->context); + if (!ctx->channel) { + fprintf(stderr, "Couldn't create completion channel\n"); + return NULL; + } + } else + ctx->channel = NULL; + ctx->pd = ibv_alloc_pd(ctx->context); + if (!ctx->pd) { + fprintf(stderr, "Couldn't allocate PD\n"); + return NULL; + } + + /* We dont really want IBV_ACCESS_LOCAL_WRITE, but IB spec says: + * The Consumer is not allowed to assign Remote Write or Remote Atomic to + * a Memory Region that has not been assigned Local Write. */ + ctx->mr = ibv_reg_mr(ctx->pd, ctx->buf, size * 2, + IBV_ACCESS_REMOTE_WRITE | IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_READ); + if (!ctx->mr) { + fprintf(stderr, "Couldn't allocate MR\n"); + return NULL; + } + + ctx->cq = ibv_create_cq(ctx->context, tx_depth, NULL, ctx->channel, 0); + if (!ctx->cq) { + fprintf(stderr, "Couldn't create CQ\n"); + return NULL; + } + + { + struct ibv_qp_init_attr attr; + memset(&attr, 0, sizeof(struct ibv_qp_init_attr)); + attr.send_cq = ctx->cq; + attr.recv_cq = ctx->cq; + attr.cap.max_send_wr = tx_depth; + /* Work around: driver doesnt support + * recv_wr = 0 */ + attr.cap.max_recv_wr = 1; + attr.cap.max_send_sge = 1; + attr.cap.max_recv_sge = 1; + attr.qp_type = IBV_QPT_RC; + ctx->qp = ibv_create_qp(ctx->pd, &attr); + if (!ctx->qp) { + fprintf(stderr, "Couldn't create QP\n"); + return NULL; + } + } + + { + struct ibv_qp_attr attr; + + attr.qp_state = IBV_QPS_INIT; + attr.pkey_index = 0; + attr.port_num = (uint8_t) port; + attr.qp_access_flags = IBV_ACCESS_REMOTE_READ; + + if (ibv_modify_qp(ctx->qp, &attr, + IBV_QP_STATE | + IBV_QP_PKEY_INDEX | + IBV_QP_PORT | + IBV_QP_ACCESS_FLAGS)) { + fprintf(stderr, "Failed to modify QP to INIT\n"); + return NULL; + } + } + + return ctx; +} + +static int pp_connect_ctx(struct pingpong_context *ctx, int port, int my_psn, + struct pingpong_dest *dest, struct user_parameters *user_parm) +{ + struct ibv_qp_attr attr; + memset(&attr, 0, sizeof attr); + + attr.qp_state = IBV_QPS_RTR; + switch (user_parm->mtu) { + case 256 : + attr.path_mtu = IBV_MTU_256; + break; + case 512 : + attr.path_mtu = IBV_MTU_512; + break; + case 1024 : + attr.path_mtu = IBV_MTU_1024; + break; + case 2048 : + attr.path_mtu = IBV_MTU_2048; + break; + case 4096 : + attr.path_mtu = IBV_MTU_4096; + break; + } + printf("Mtu : %d\n", user_parm->mtu); + attr.dest_qp_num = dest->qpn; + attr.rq_psn = dest->psn; + attr.max_dest_rd_atomic = (uint8_t) user_parm->max_out_read; + attr.min_rnr_timer = 12; + attr.ah_attr.is_global = 0; + attr.ah_attr.dlid = (uint16_t) dest->lid; + attr.ah_attr.sl = 0; + attr.ah_attr.src_path_bits = 0; + attr.ah_attr.port_num = (uint8_t) port; + if (ibv_modify_qp(ctx->qp, &attr, + IBV_QP_STATE | + IBV_QP_AV | + IBV_QP_PATH_MTU | + IBV_QP_DEST_QPN | + IBV_QP_RQ_PSN | + IBV_QP_MIN_RNR_TIMER | + IBV_QP_MAX_DEST_RD_ATOMIC)) { + fprintf(stderr, "Failed to modify RC QP to RTR\n"); + return 1; + } + attr.timeout = 14; + attr.retry_cnt = 7; + attr.rnr_retry = 7; + attr.qp_state = IBV_QPS_RTS; + attr.sq_psn = my_psn; + attr.max_rd_atomic = (uint8_t) user_parm->max_out_read; + if (ibv_modify_qp(ctx->qp, &attr, + IBV_QP_STATE | + IBV_QP_SQ_PSN | + IBV_QP_TIMEOUT | + IBV_QP_RETRY_CNT | + IBV_QP_RNR_RETRY | + IBV_QP_MAX_QP_RD_ATOMIC)) { + fprintf(stderr, "Failed to modify RC QP to RTS\n"); + return 1; + } + return 0; +} + +static void usage(const char *argv0) +{ + printf("Usage:\n"); + printf(" %s start a server and wait for connection\n", argv0); + printf(" %s -h connect to server at \n", argv0); + printf("\n"); + printf("Options:\n"); + printf(" -p listen on/connect to port (default 18515)\n"); + printf(" -d use IB device (default first device found)\n"); + printf(" -i use port of IB device (default 1)\n"); + printf(" -m mtu size (256 - 4096. default for hermon is 2048)\n"); + printf(" -o = num of outstanding read/atom(default 4)\n"); + printf(" -s size of message to exchange (default 65536)\n"); + printf(" -a Run sizes from 2 till 2^23\n"); + printf(" -t size of tx queue (default 100)\n"); + printf(" -n number of exchanges (at least 2, default 1000)\n"); + printf(" -b measure bidirectional bandwidth (default unidirectional)\n"); + printf(" -V display version number\n"); + printf(" -e sleep on CQ events (default poll)\n"); +} + +static void print_report(unsigned int iters, unsigned size, int duplex, + cycles_t *tposted, cycles_t *tcompleted) +{ + cycles_t cycles_to_units; + unsigned long tsize; /* Transferred size */ + int i, j; + int opt_posted = 0, opt_completed = 0; + cycles_t opt_delta; + cycles_t t; + + opt_delta = tcompleted[opt_posted] - tposted[opt_completed]; + + /* Find the peak bandwidth */ + for (i = 0; i < (int) iters; ++i) + for (j = i; j < (int) iters; ++j) { + t = (tcompleted[j] - tposted[i]) / (j - i + 1); + if (t < opt_delta) { + opt_delta = t; + opt_posted = i; + opt_completed = j; + } + } + + cycles_to_units = get_freq(); + + tsize = duplex ? 2 : 1; + tsize = tsize * size; + printf("%7d %d ", size, iters); + + { + double sec = (double) opt_delta / (double) cycles_to_units; + double mbytes = (double) tsize / (double) 0x100000; + printf("%7.2f ", mbytes / sec); + + sec = (double) (tcompleted[iters - 1] - tposted[0]) / (double) cycles_to_units; + mbytes = (double) tsize * (double) iters / (double) 0x100000; + printf("%7.2f\n", mbytes / sec); + } +} + +static int run_iter(struct pingpong_context *ctx, struct user_parameters *user_param, + struct pingpong_dest *rem_dest, int size) +{ + struct ibv_qp *qp; + int scnt, ccnt ; + + ctx->list.addr = (uintptr_t) ctx->buf; + ctx->list.length = size; + ctx->list.lkey = ctx->mr->lkey; + ctx->wr.wr.rdma.remote_addr = rem_dest->vaddr; + ctx->wr.wr.rdma.rkey = rem_dest->rkey; + ctx->wr.wr_id = PINGPONG_READ_WRID; + ctx->wr.sg_list = &ctx->list; + ctx->wr.num_sge = 1; + ctx->wr.opcode = IBV_WR_RDMA_READ; + ctx->wr.send_flags = IBV_SEND_SIGNALED; + ctx->wr.next = NULL; + + scnt = 0; + ccnt = 0; + + qp = ctx->qp; + + /* Done with setup. Start the test. */ + while (scnt < user_param->iters || ccnt < user_param->iters) { + while (scnt < user_param->iters && (scnt - ccnt) < user_param->tx_depth ) { + struct ibv_send_wr *bad_wr; + if (user_param->servername) + tposted[scnt] = get_cycles(); + if (ibv_post_send(qp, &ctx->wr, &bad_wr)) { + fprintf(stderr, "Couldn't post send: scnt=%d\n", + scnt); + return 1; + } + ++scnt; + } + if (ccnt < user_param->iters) { + struct ibv_wc wc; + int ne; + if (user_param->use_event) { + struct ibv_cq *ev_cq; + void *ev_ctx; + if (ibv_get_cq_event(ctx->channel, &ev_cq, &ev_ctx)) { + fprintf(stderr, "Failed to get cq_event\n"); + return 1; + } + if (ev_cq != ctx->cq) { + fprintf(stderr, "CQ event for unknown CQ %p\n", ev_cq); + return 1; + } + if (ibv_req_notify_cq(ctx->cq, 0)) { + fprintf(stderr, "Couldn't request CQ notification\n"); + return 1; + } + } + do { + ne = ibv_poll_cq(ctx->cq, 1, &wc); + if (ne) { + if (user_param->servername) + tcompleted[ccnt] = get_cycles(); + if (wc.status != IBV_WC_SUCCESS) { + fprintf(stderr, "Completion wth error at %s:\n", + user_param->servername ? "client" : "server"); + fprintf(stderr, "Failed status %d: wr_id %d syndrom 0x%x\n", + wc.status, (int) wc.wr_id, wc.vendor_err); + fprintf(stderr, "scnt=%d, ccnt=%d\n", + scnt, ccnt); + return 1; + } + ccnt = ccnt + ne; + } + } while (ne > 0 ); + + if (ne < 0) { + fprintf(stderr, "poll CQ failed %d\n", ne); + return 1; + } + } + } + + return 0; +} + +int __cdecl main(int argc, char *argv[]) +{ + struct ibv_device **dev_list; + struct ibv_device *ib_dev; + struct pingpong_context *ctx; + struct pingpong_dest my_dest; + struct pingpong_dest *rem_dest; + struct user_parameters user_param; + char *ib_devname = NULL; + int port = 18515; + int ib_port = 1; + int size = 65536; + SOCKET sockfd; + int duplex = 0; + int i = 0; + WORD version; + WSADATA data; + int err; + + srand((unsigned int) time(NULL)); + version = MAKEWORD(2, 2); + err = WSAStartup(version, &data); + if (err) + return -1; + + /* init default values to user's parameters */ + memset(&user_param, 0, sizeof(struct user_parameters)); + user_param.mtu = 0; + user_param.iters = 1000; + user_param.tx_depth = 100; + user_param.servername = NULL; + user_param.use_event = 0; + user_param.max_out_read = 4; /* the device capability on gen2 */ + /* Parameter parsing. */ + while (1) { + int c; + + c = getopt(argc, argv, "h:p:d:i:m:o:s:n:t:abVe"); + if (c == -1) + break; + + switch (c) { + case 'p': + port = strtol(optarg, NULL, 0); + if (port < 0 || port > 65535) { + usage(argv[0]); + return 1; + } + break; + + case 'd': + ib_devname = _strdup(optarg); + break; + case 'e': + ++user_param.use_event; + break; + case 'm': + user_param.mtu = strtol(optarg, NULL, 0); + break; + case 'o': + user_param.max_out_read = strtol(optarg, NULL, 0); + break; + case 'a': + user_param.all = ALL; + break; + case 'V': + printf("read_bw version : %.2f\n",VERSION); + return 0; + case 'i': + ib_port = strtol(optarg, NULL, 0); + if (ib_port < 0) { + usage(argv[0]); + return 1; + } + break; + + case 's': + size = strtol(optarg, NULL, 0); + break; + + case 't': + user_param.tx_depth = strtol(optarg, NULL, 0); + if (user_param.tx_depth < 1) { usage(argv[0]); return 1; } + break; + + case 'n': + user_param.iters = strtol(optarg, NULL, 0); + if (user_param.iters < 2) { + usage(argv[0]); + return 1; + } + + break; + + case 'b': + duplex = 1; + break; + + case 'h': + if (optarg) { + user_param.servername = _strdup(optarg); + break; + } + + default: + usage(argv[0]); + return 1; + } + } + + printf("------------------------------------------------------------------\n"); + if (duplex == 1) + printf(" RDMA_Read Bidirectional BW Test\n"); + else + printf(" RDMA_Read BW Test\n"); + + printf("Connection type : RC\n"); + /* Done with parameter parsing. Perform setup. */ + if (user_param.all == ALL) + /*since we run all sizes */ + size = 8388608; /*2^23 */ + + dev_list = ibv_get_device_list(NULL); + + if (!ib_devname) { + ib_dev = dev_list[0]; + if (!ib_dev) { + fprintf(stderr, "No IB devices found\n"); + return 1; + } + } else { + for (; (ib_dev = *dev_list); ++dev_list) + if (!strcmp(ibv_get_device_name(ib_dev), ib_devname)) + break; + if (!ib_dev) { + fprintf(stderr, "IB device %s not found\n", ib_devname); + return 1; + } + } + + ctx = pp_init_ctx(ib_dev, size, user_param.tx_depth, ib_port, &user_param); + if (!ctx) + return 1; + + /* Create connection between client and server. + * We do it by exchanging data over a TCP socket connection. */ + + my_dest.lid = pp_get_local_lid(ctx, ib_port); + my_dest.qpn = ctx->qp->qp_num; + my_dest.psn = rand() & 0xffffff; + if (!my_dest.lid) { + fprintf(stderr, "Local lid 0x0 detected. Is an SM running?\n"); + return 1; + } + my_dest.rkey = ctx->mr->rkey; + my_dest.vaddr = (uintptr_t)ctx->buf + ctx->size; + + printf(" local address: LID %#04x, QPN %#06x, PSN %#06x " + "RKey %#08x VAddr %#016Lx\n", + my_dest.lid, my_dest.qpn, my_dest.psn, + my_dest.rkey, my_dest.vaddr); + + if (user_param.servername) { + sockfd = pp_client_connect(user_param.servername, port); + if (sockfd == INVALID_SOCKET) + return 1; + rem_dest = pp_client_exch_dest(sockfd, &my_dest); + } else { + sockfd = pp_server_connect(port); + if (sockfd == INVALID_SOCKET) + return 1; + rem_dest = pp_server_exch_dest(sockfd, &my_dest); + } + + if (!rem_dest) + return 1; + + printf(" remote address: LID %#04x, QPN %#06x, PSN %#06x, " + "RKey %#08x VAddr %#016Lx\n", + rem_dest->lid, rem_dest->qpn, rem_dest->psn, + rem_dest->rkey, rem_dest->vaddr); + + if (pp_connect_ctx(ctx, ib_port, my_dest.psn, rem_dest, &user_param)) + return 1; + + /* An additional handshake is required *after* moving qp to RTR. + Arbitrarily reuse exch_dest for this purpose. */ + if (user_param.servername) + rem_dest = pp_client_exch_dest(sockfd, &my_dest); + else + rem_dest = pp_server_exch_dest(sockfd, &my_dest); + + if (!rem_dest) + return 1; + + /* For half duplex tests, server just waits for client to exit */ + + if (!user_param.servername && !duplex) { + rem_dest = pp_server_exch_dest(sockfd, &my_dest); + if (send(sockfd, "done", sizeof "done", 0) != sizeof "done"){ + perror("server write"); + fprintf(stderr, "Couldn't write to socket\n"); + return 1; + } + closesocket(sockfd); + return 0; + } else if (user_param.use_event) { + printf("Test with events.\n"); + if (ibv_req_notify_cq(ctx->cq, 0)) { + fprintf(stderr, "Couldn't request CQ notification\n"); + return 1; + } + } + + printf("------------------------------------------------------------------\n"); + printf(" #bytes #iterations BW peak[MB/sec] BW average[MB/sec] \n"); + + tposted = malloc(user_param.iters * sizeof *tposted); + + if (!tposted) { + perror("malloc"); + return 1; + } + + tcompleted = malloc(user_param.iters * sizeof *tcompleted); + + if (!tcompleted) { + perror("malloc"); + return 1; + } + + if (user_param.all == ALL) { + for (i = 1; i < 24 ; ++i) { + size = 1 << i; + if(run_iter(ctx, &user_param, rem_dest, size)) + return 17; + print_report(user_param.iters, size, duplex, tposted, tcompleted); + } + } else { + if(run_iter(ctx, &user_param, rem_dest, size)) + return 18; + print_report(user_param.iters, size, duplex, tposted, tcompleted); + } + + if (user_param.servername) + rem_dest = pp_client_exch_dest(sockfd, &my_dest); + else + rem_dest = pp_server_exch_dest(sockfd, &my_dest); + + if (send(sockfd, "done", sizeof "done", 0) != sizeof "done"){ + perror("server write"); + fprintf(stderr, "Couldn't write to socket\n"); + return 1; + } + closesocket(sockfd); + + free(tposted); + free(tcompleted); + + printf("------------------------------------------------------------------\n"); + return 0; +} diff --git a/branches/WOF2-3/tests/perftest/read_bw/read_bw.rc b/branches/WOF2-3/tests/perftest/read_bw/read_bw.rc new file mode 100644 index 00000000..2f131528 --- /dev/null +++ b/branches/WOF2-3/tests/perftest/read_bw/read_bw.rc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: write_bw.rc 1611 2006-08-20 14:48:55Z sleybo $ + */ + + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef DBG +#define VER_FILEDESCRIPTION_STR "winverbs - RDMA read Bandwidth Test (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "winverbs - RDMA read Bandwidth Test " +#endif + +#define VER_INTERNALNAME_STR "ibv_read_bw.exe" +#define VER_ORIGINALFILENAME_STR "ibv_read_bw.exe" + +#include diff --git a/branches/WOF2-3/tests/perftest/read_lat/SOURCES b/branches/WOF2-3/tests/perftest/read_lat/SOURCES new file mode 100644 index 00000000..c354d5a1 --- /dev/null +++ b/branches/WOF2-3/tests/perftest/read_lat/SOURCES @@ -0,0 +1,30 @@ +TARGETNAME = ibv_read_lat +TARGETPATH = ..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = PROGRAM + +UMTYPE = console +UMENTRY = main + +USE_MSVCRT = 1 +USE_STL = 1 +USE_NATIVE_EH = 1 +USE_IOSTREAM = 1 + +SOURCES = read_lat.rc read_lat.c ..\perftest.c + +INCLUDES = ..;..\..\..\ulp\libibverbs\include;\ + ..\..\..\inc;..\..\..\inc\user;\ + ..\..\..\inc\user\linux; + +TARGETLIBS = \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\advapi32.lib \ + $(SDK_LIB_PATH)\user32.lib \ + $(SDK_LIB_PATH)\ole32.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\libibverbs.lib +!else + $(TARGETPATH)\*\libibverbsd.lib +!endif + diff --git a/branches/WOF2-3/tests/perftest/read_lat/makefile b/branches/WOF2-3/tests/perftest/read_lat/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-3/tests/perftest/read_lat/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\inc\openib.def diff --git a/branches/WOF2-3/tests/perftest/read_lat/read_lat.c b/branches/WOF2-3/tests/perftest/read_lat/read_lat.c new file mode 100644 index 00000000..0d334075 --- /dev/null +++ b/branches/WOF2-3/tests/perftest/read_lat/read_lat.c @@ -0,0 +1,808 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies Ltd. All rights reserved. + * Copyright (c) 2005 Hewlett Packard, Inc (Grant Grundler) + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include + +#include "..\..\..\etc\user\getopt.c" +#include "perftest.h" +#include + +#define PINGPONG_READ_WRID 1 +#define VERSION 1.1 +#define ALL 1 + +typedef UINT64 cycles_t; +cycles_t *tstamp; + +struct user_parameters { + const char *servername; + int connection_type; + int mtu; + int all; /* run all msg size */ + int iters; + int tx_depth; + SOCKET sockfd; + int max_out_read; + int use_event; + +}; +struct report_options { + int unsorted; + int histogram; + int cycles; /* report delta's in cycles, not microsec's */ +}; + +struct pingpong_context { + struct ibv_context *context; + struct ibv_comp_channel *channel; + struct ibv_pd *pd; + struct ibv_mr *mr; + struct ibv_cq *cq; + struct ibv_qp *qp; + void *buf; + volatile char *post_buf; + volatile char *poll_buf; + int size; + int tx_depth; + struct ibv_sge list; + struct ibv_send_wr wr; +}; + +struct pingpong_dest { + int lid; + int qpn; + int psn; + unsigned rkey; + unsigned long long vaddr; +}; +struct pingpong_dest my_dest; + +static uint16_t pp_get_local_lid(struct pingpong_context *ctx, int port) +{ + struct ibv_port_attr attr; + + if (ibv_query_port(ctx->context, (uint8_t) port, &attr)) + return 0; + + return attr.lid; +} + +static struct ibv_device *pp_find_dev(const char *ib_devname) { + struct ibv_device **dev_list; + struct ibv_device *ib_dev = NULL; + + dev_list = ibv_get_device_list(NULL); + if (!dev_list) + return NULL; + + if (!ib_devname) { + ib_dev = dev_list[0]; + if (!ib_dev) + fprintf(stderr, "No IB devices found\n"); + } else { + for (; (ib_dev = *dev_list); ++dev_list) + if (!strcmp(ibv_get_device_name(ib_dev), ib_devname)) + break; + if (!ib_dev) + fprintf(stderr, "IB device %s not found\n", ib_devname); + } + return ib_dev; +} + +#define KEY_MSG_SIZE (sizeof "0000:000000:000000:00000000:0000000000000000") +#define KEY_PRINT_FMT "%04x:%06x:%06x:%08x:%016Lx" + +static int pp_write_keys(SOCKET sockfd, const struct pingpong_dest *my_dest) +{ + char msg[KEY_MSG_SIZE]; + + sprintf(msg, KEY_PRINT_FMT, my_dest->lid, my_dest->qpn, + my_dest->psn, my_dest->rkey, my_dest->vaddr); + + if (send(sockfd, msg, sizeof msg, 0) != sizeof msg) { + perror("client write"); + fprintf(stderr, "Couldn't send local address\n"); + return -1; + } + + return 0; +} + +static int pp_read_keys(SOCKET sockfd, const struct pingpong_dest *my_dest, + struct pingpong_dest *rem_dest) +{ + int parsed; + char msg[KEY_MSG_SIZE]; + + if (recv(sockfd, msg, sizeof msg, 0) != sizeof msg) { + perror("pp_read_keys"); + fprintf(stderr, "Couldn't read remote address\n"); + return -1; + } + + memset(rem_dest, 0, sizeof *rem_dest); + parsed = sscanf(msg, KEY_PRINT_FMT, &rem_dest->lid, &rem_dest->qpn, + &rem_dest->psn, &rem_dest->rkey, &rem_dest->vaddr); + + if (parsed != 5) { + fprintf(stderr, "Couldn't parse line <%.*s>\n", + (int)sizeof msg, msg); + return -1; + } + + return 0; +} + +static int pp_client_exch_dest(SOCKET sockfd, const struct pingpong_dest *my_dest, + struct pingpong_dest *rem_dest) +{ + if (pp_write_keys(sockfd, my_dest)) + return -1; + + return pp_read_keys(sockfd, my_dest, rem_dest); +} + +static int pp_server_exch_dest(SOCKET sockfd, const struct pingpong_dest *my_dest, + struct pingpong_dest* rem_dest) +{ + + if (pp_read_keys(sockfd, my_dest, rem_dest)) + return -1; + + return pp_write_keys(sockfd, my_dest); +} + +static struct pingpong_context *pp_init_ctx(struct ibv_device *ib_dev, int size, + int tx_depth, int port, struct user_parameters *user_parm) +{ + struct pingpong_context *ctx; + struct ibv_device_attr device_attr; + + ctx = malloc(sizeof *ctx); + if (!ctx) + return NULL; + + ctx->size = size; + ctx->tx_depth = tx_depth; + + ctx->buf = malloc(size * 2); + if (!ctx->buf) { + fprintf(stderr, "Couldn't allocate work buf.\n"); + return NULL; + } + + memset(ctx->buf, 0, size * 2); + + ctx->post_buf = (char*)ctx->buf + (size - 1); + ctx->poll_buf = (char*)ctx->buf + (2 * size - 1); + + ctx->context = ibv_open_device(ib_dev); + if (!ctx->context) { + fprintf(stderr, "Couldn't get context for %s\n", + ibv_get_device_name(ib_dev)); + return NULL; + } + if (user_parm->mtu == 0) {/*user did not ask for specific mtu */ + if (ibv_query_device(ctx->context, &device_attr)) { + fprintf(stderr, "Failed to query device props"); + return NULL; + } + if (device_attr.vendor_part_id == 23108) { + user_parm->mtu = 1024; + } else { + user_parm->mtu = 2048; + } + } + if (user_parm->use_event) { + ctx->channel = ibv_create_comp_channel(ctx->context); + if (!ctx->channel) { + fprintf(stderr, "Couldn't create completion channel\n"); + return NULL; + } + } else + ctx->channel = NULL; + ctx->pd = ibv_alloc_pd(ctx->context); + if (!ctx->pd) { + fprintf(stderr, "Couldn't allocate PD\n"); + return NULL; + } + + ctx->mr = ibv_reg_mr(ctx->pd, ctx->buf, size * 2, + IBV_ACCESS_REMOTE_WRITE | IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_READ); + if (!ctx->mr) { + fprintf(stderr, "Couldn't allocate MR\n"); + return NULL; + } + + ctx->cq = ibv_create_cq(ctx->context, tx_depth, NULL, ctx->channel, 0); + if (!ctx->cq) { + fprintf(stderr, "Couldn't create CQ\n"); + return NULL; + } + + { + struct ibv_qp_init_attr attr; + memset(&attr, 0, sizeof(struct ibv_qp_init_attr)); + attr.send_cq = ctx->cq; + attr.recv_cq = ctx->cq; + attr.cap.max_send_wr = tx_depth; + /* Work around: driver doesnt support + * recv_wr = 0 */ + attr.cap.max_recv_wr = 1; + attr.cap.max_send_sge = 1; + attr.cap.max_recv_sge = 1; + if (user_parm->connection_type==1) { + attr.qp_type = IBV_QPT_UC; + } else { + attr.qp_type = IBV_QPT_RC; + } + ctx->qp = ibv_create_qp(ctx->pd, &attr); + if (!ctx->qp) { + fprintf(stderr, "Couldn't create QP\n"); + return NULL; + } + } + + { + struct ibv_qp_attr attr; + + attr.qp_state = IBV_QPS_INIT; + attr.pkey_index = 0; + attr.port_num = (uint8_t) port; + attr.qp_access_flags = IBV_ACCESS_REMOTE_READ; + + if (ibv_modify_qp(ctx->qp, &attr, + IBV_QP_STATE | + IBV_QP_PKEY_INDEX | + IBV_QP_PORT | + IBV_QP_ACCESS_FLAGS)) { + fprintf(stderr, "Failed to modify QP to INIT\n"); + return NULL; + } + } + + ctx->wr.wr_id = PINGPONG_READ_WRID; + ctx->wr.sg_list = &ctx->list; + ctx->wr.num_sge = 1; + ctx->wr.opcode = IBV_WR_RDMA_READ; + ctx->wr.send_flags = IBV_SEND_SIGNALED; + ctx->wr.next = NULL; + + return ctx; +} + +static int pp_connect_ctx(struct pingpong_context *ctx, int port, int my_psn, + struct pingpong_dest *dest,struct user_parameters *user_parm) +{ + struct ibv_qp_attr attr; + memset(&attr, 0, sizeof(struct ibv_qp_attr)); + attr.qp_state = IBV_QPS_RTR; + switch (user_parm->mtu) { + case 256 : + attr.path_mtu = IBV_MTU_256; + break; + case 512 : + attr.path_mtu = IBV_MTU_512; + break; + case 1024 : + attr.path_mtu = IBV_MTU_1024; + break; + case 2048 : + attr.path_mtu = IBV_MTU_2048; + break; + case 4096 : + attr.path_mtu = IBV_MTU_4096; + break; + } + printf("Mtu : %d\n", user_parm->mtu); + attr.dest_qp_num = dest->qpn; + attr.rq_psn = dest->psn; + attr.max_dest_rd_atomic = (uint8_t) user_parm->max_out_read; + attr.min_rnr_timer = 12; + attr.ah_attr.is_global = 0; + attr.ah_attr.dlid = (uint16_t) dest->lid; + attr.ah_attr.sl = 0; + attr.ah_attr.src_path_bits = 0; + attr.ah_attr.port_num = (uint8_t) port; + if (ibv_modify_qp(ctx->qp, &attr, + IBV_QP_STATE | + IBV_QP_AV | + IBV_QP_PATH_MTU | + IBV_QP_DEST_QPN | + IBV_QP_RQ_PSN | + IBV_QP_MIN_RNR_TIMER | + IBV_QP_MAX_DEST_RD_ATOMIC)) { + fprintf(stderr, "Failed to modify RC QP to RTR\n"); + return 1; + } + attr.timeout = 14; + attr.retry_cnt = 7; + attr.rnr_retry = 7; + attr.qp_state = IBV_QPS_RTS; + attr.sq_psn = my_psn; + + if (user_parm->connection_type==0) { + attr.max_rd_atomic = (uint8_t) user_parm->max_out_read; + if (ibv_modify_qp(ctx->qp, &attr, + IBV_QP_STATE | + IBV_QP_SQ_PSN | + IBV_QP_TIMEOUT | + IBV_QP_RETRY_CNT | + IBV_QP_RNR_RETRY | + IBV_QP_MAX_QP_RD_ATOMIC)) { + fprintf(stderr, "Failed to modify RC QP to RTS\n"); + return 1; + } + } else { + if (ibv_modify_qp(ctx->qp, &attr, + IBV_QP_STATE | + IBV_QP_SQ_PSN)) { + fprintf(stderr, "Failed to modify UC QP to RTS\n"); + return 1; + } + + } + return 0; +} + +static SOCKET pp_open_port(struct pingpong_context *ctx, const char * servername, + int ib_port, int port, struct pingpong_dest *rem_dest, + struct user_parameters *user_parm) +{ + char addr_fmt[] = "%8s address: LID %#04x QPN %#06x PSN %#06x RKey %#08x VAddr %#016Lx\n"; + SOCKET sockfd; + int rc; + + /* Create connection between client and server. + * We do it by exchanging data over a TCP socket connection. */ + + my_dest.lid = pp_get_local_lid(ctx, ib_port); + my_dest.qpn = ctx->qp->qp_num; + my_dest.psn = rand() & 0xffffff; + if (!my_dest.lid) { + fprintf(stderr, "Local lid 0x0 detected. Is an SM running?\n"); + return INVALID_SOCKET; + } + my_dest.rkey = ctx->mr->rkey; + my_dest.vaddr = (uintptr_t)ctx->buf + ctx->size; + + printf(addr_fmt, "local", my_dest.lid, my_dest.qpn, my_dest.psn, + my_dest.rkey, my_dest.vaddr); + + sockfd = servername ? pp_client_connect(servername, port) : + pp_server_connect(port); + + if (sockfd == INVALID_SOCKET) { + printf("pp_connect_sock(%s,%d) failed (%d)!\n", + servername, port, sockfd); + return sockfd; + } + + rc = servername ? pp_client_exch_dest(sockfd, &my_dest, rem_dest) : + pp_server_exch_dest(sockfd, &my_dest, rem_dest); + if (rc) + return INVALID_SOCKET; + + printf(addr_fmt, "remote", rem_dest->lid, rem_dest->qpn, rem_dest->psn, + rem_dest->rkey, rem_dest->vaddr); + + if ((rc = pp_connect_ctx(ctx, ib_port, my_dest.psn, rem_dest,user_parm))) + return INVALID_SOCKET; + + /* An additional handshake is required *after* moving qp to RTR. + * Arbitrarily reuse exch_dest for this purpose. + */ + + rc = servername ? pp_client_exch_dest(sockfd, &my_dest, rem_dest) : + pp_server_exch_dest(sockfd, &my_dest, rem_dest); + + if (rc) + return INVALID_SOCKET; + + return sockfd; +} + +static void usage(const char *argv0) +{ + printf("Usage:\n"); + printf(" %s start a server and wait for connection\n", argv0); + printf(" %s -h connect to server at \n", argv0); + printf("\n"); + printf("Options:\n"); + printf(" -p listen on/connect to port (default 18515)\n"); + printf(" -c connection type RC/UC (default RC)\n"); + printf(" -m mtu size (256 - 4096. default for hermon is 2048)\n"); + printf(" -d use IB device (default first device found)\n"); + printf(" -i use port of IB device (default 1)\n"); + printf(" -s size of message to exchange (default 1)\n"); + printf(" -t size of tx queue (default 50)\n"); + printf(" -n number of exchanges (at least 2, default 1000)\n"); + printf(" -o num of outstanding read/atom(default 4)\n"); + printf(" -a Run sizes from 2 till 2^23\n"); + printf(" -C report times in cpu cycle units (default microseconds)\n"); + printf(" -H print out all results (default print summary only)\n"); + printf(" -U (implies -H) print out unsorted results (default sorted)\n"); + printf(" -V display version number\n"); + printf(" -e sleep on CQ events (default poll)\n"); +} + +static void print_report(struct report_options * options, + unsigned int iters, cycles_t *tstamp,int size) +{ + cycles_t cycles_to_units; + cycles_t median; + unsigned int i; + const char* units; + cycles_t *delta = malloc((iters - 1) * sizeof *delta); + + if (!delta) { + perror("malloc"); + return; + } + + for (i = 0; i < iters - 1; ++i) + delta[i] = tstamp[i + 1] - tstamp[i]; + + if (options->cycles) { + cycles_to_units = 1; + units = "cycles"; + } else { + cycles_to_units = get_freq(); + units = "sec"; + } + + if (options->unsorted) { + printf("#, %s, frequency=%I64d\n", units, get_freq()); + for (i = 0; i < iters - 1; ++i) + printf("%d, %g\n", i + 1, delta[i] / cycles_to_units); + } + + qsort(delta, iters - 1, sizeof *delta, cycles_compare); + + if (options->histogram) { + printf("#, %s, frequency=%I64d\n", units, get_freq()); + for (i = 0; i < iters - 1; ++i) + printf("%d, %7.2f\n", i + 1, (double) delta[i] / (double) cycles_to_units); + } + + median = get_median(iters - 1, delta); + printf("%7d %d %7.2f %7.2f %7.2f\n", + size, iters, (double) delta[0] / (double) cycles_to_units * 1000000., + (double) delta[iters - 2] / (double) cycles_to_units * 1000000., + (double) median / (double) cycles_to_units * 1000000.); + free(delta); +} + +static int run_iter(struct pingpong_context *ctx, struct user_parameters *user_param, + struct pingpong_dest *rem_dest, int size) +{ + struct ibv_qp *qp; + struct ibv_send_wr *wr; + volatile char *poll_buf; + volatile char *post_buf; + + int scnt, ccnt; + int iters; + int tx_depth; + + struct ibv_wc wc; + int ne; + + if (!user_param->servername) + return 0; + + iters = user_param->iters; + tx_depth = user_param->tx_depth; + wr = &ctx->wr; + ctx->list.addr = (uintptr_t) ctx->buf; + ctx->list.length = size; + ctx->list.lkey = ctx->mr->lkey; + wr->wr.rdma.remote_addr = rem_dest->vaddr; + wr->wr.rdma.rkey = rem_dest->rkey; + scnt = 0; + ccnt = 0; + poll_buf = ctx->poll_buf; + post_buf = ctx->post_buf; + qp = ctx->qp; + + /* Done with setup. Start the test. */ + + while (scnt < user_param->iters ) { + struct ibv_send_wr *bad_wr; + *post_buf = (char)++scnt; + tstamp[scnt - 1] = get_cycles(); + if (ibv_post_send(qp, wr, &bad_wr)) { + fprintf(stderr, "Couldn't post send: scnt=%d\n", + scnt); + return 11; + } + if (user_param->use_event) { + struct ibv_cq *ev_cq; + void *ev_ctx; + + if (ibv_get_cq_event(ctx->channel, &ev_cq, &ev_ctx)) { + fprintf(stderr, "Failed to get cq_event\n"); + return 1; + } + + if (ev_cq != ctx->cq) { + fprintf(stderr, "CQ event for unknown RCQ %p\n", ev_cq); + return 1; + } + + if (ibv_req_notify_cq(ctx->cq, 0)) { + fprintf(stderr, "Couldn't request CQ notification\n"); + return 1; + } + } + do { + ne = ibv_poll_cq(ctx->cq, 1, &wc); + } while (!user_param->use_event && ne < 1); + + if (ne < 0) { + fprintf(stderr, "poll CQ failed %d\n", ne); + return 12; + } + if (wc.status != IBV_WC_SUCCESS) { + fprintf(stderr, "Completion wth error at %s:\n", + user_param->servername ? "client" : "server"); + fprintf(stderr, "Failed status %d: wr_id %d\n", + wc.status, (int) wc.wr_id); + fprintf(stderr, "scnt=%d, ccnt=%d\n", + scnt, ccnt); + return 13; + } + } + return 0; +} + +int __cdecl main(int argc, char *argv[]) +{ + const char *ib_devname = NULL; + int port = 18515; + int ib_port = 1; + int size = 2; + int tmp_size; + int i = 0; + struct report_options report; + struct pingpong_context *ctx; + struct pingpong_dest rem_dest; + struct ibv_device *ib_dev; + struct user_parameters user_param; + WORD version; + WSADATA data; + int err; + + srand((unsigned int) time(NULL)); + version = MAKEWORD(2, 2); + err = WSAStartup(version, &data); + if (err) + return -1; + + /* init default values to user's parameters */ + memset(&report, 0, sizeof report); + memset(&user_param, 0, sizeof(struct user_parameters)); + user_param.mtu = 0; + user_param.iters = 1000; + user_param.tx_depth = 50; + user_param.servername = NULL; + user_param.use_event = 0; + user_param.max_out_read = 4; /* the device capability on gen2 */ + + /* Parameter parsing. */ + while (1) { + int c; + + c = getopt(argc, argv, "h:p:c:m:d:i:s:o:n:t:aeHUV"); + if (c == -1) + break; + + switch (c) { + case 'p': + port = strtol(optarg, NULL, 0); + if (port < 0 || port > 65535) { + usage(argv[0]); + return 1; + } + break; + case 'c': + if (strcmp("UC",optarg)==0) + user_param.connection_type=1; + /* default is 0 for any other option RC*/ + break; + case 'e': + ++user_param.use_event; + break; + + case 'm': + user_param.mtu = strtol(optarg, NULL, 0); + break; + case 'o': + user_param.max_out_read = strtol(optarg, NULL, 0); + break; + case 'a': + user_param.all = ALL; + break; + case 'V': + printf("perftest version : %.2f\n",VERSION); + return 0; + case 'd': + ib_devname = _strdup(optarg); + break; + + case 'i': + ib_port = strtol(optarg, NULL, 0); + if (ib_port < 0) { + usage(argv[0]); + return 2; + } + break; + + case 's': + size = strtol(optarg, NULL, 0); + if (size < 1) { + usage(argv[0]); return 3; + } + break; + + case 't': + user_param.tx_depth = strtol(optarg, NULL, 0); + if (user_param.tx_depth < 1) { + usage(argv[0]); return 4; + } + break; + + case 'n': + user_param.iters = strtol(optarg, NULL, 0); + if (user_param.iters < 2) { + usage(argv[0]); + return 5; + } + break; + + case 'C': + report.cycles = 1; + break; + + case 'H': + report.histogram = 1; + break; + + case 'U': + report.unsorted = 1; + break; + + case 'h': + if (optarg) { + user_param.servername = _strdup(optarg); + break; + } + + default: + usage(argv[0]); + return 5; + } + } + + /* + * Done with parameter parsing. Perform setup. + */ + tstamp = malloc(user_param.iters * sizeof *tstamp); + if (!tstamp) { + perror("malloc"); + return 10; + } + printf("------------------------------------------------------------------\n"); + printf(" RDMA_Read Latency Test\n"); + printf("Connection type : RC\n"); + /* anyway make sure the connection is RC */ + tmp_size = size; + if (user_param.all == ALL) { + /*since we run all sizes */ + size = 8388608; /*2^23 */ + } else if (size < 128) { + /* can cut up to 70 nsec probably related to cache line size */ + size = 128; + } + user_param.connection_type = 0; + + ib_dev = pp_find_dev(ib_devname); + if (!ib_dev) + return 7; + + ctx = pp_init_ctx(ib_dev, size, user_param.tx_depth, ib_port,&user_param); + if (!ctx) + return 8; + + user_param.sockfd=pp_open_port(ctx, user_param.servername, ib_port, port, &rem_dest,&user_param); + if (user_param.sockfd == INVALID_SOCKET) { + return 9; + } + /* fix for true size in small msg size */ + if (tmp_size < 128) { + size = tmp_size ; + } + if (user_param.use_event) { + printf("Test with events.\n"); + if (ibv_req_notify_cq(ctx->cq, 0)) { + fprintf(stderr, "Couldn't request RCQ notification\n"); + return 1; + } + } + printf("------------------------------------------------------------------\n"); + printf(" #bytes #iterations t_min[usec] t_max[usec] t_typical[usec]\n"); + if (user_param.all == ALL) { + for (i = 1; i < 24 ; ++i) { + size = 1 << i; + if(run_iter(ctx, &user_param, &rem_dest, size)) + return 17; + if(user_param.servername) { + print_report(&report, user_param.iters, tstamp, size); + } + } + } else { + if(run_iter(ctx, &user_param, &rem_dest, size)) + return 18; + if(user_param.servername) { + print_report(&report, user_param.iters, tstamp, size); + } + } + + /* done close sockets */ + if(user_param.servername) { + /*Signal client is finished */ + pp_client_exch_dest(user_param.sockfd, &my_dest, &rem_dest); + if (send(user_param.sockfd, "done", sizeof "done", 0) != sizeof "done"){ + perror("client write"); + fprintf(stderr, "Couldn't write to socket\n"); + return 1; + } + closesocket(user_param.sockfd); + } else { + /*Server is finished wait for client */ + pp_server_exch_dest(user_param.sockfd, &my_dest, &rem_dest); + if (send(user_param.sockfd, "done", sizeof "done", 0) != sizeof "done"){ + perror("server write"); + fprintf(stderr, "Couldn't write to socket\n"); + return 1; + } + closesocket(user_param.sockfd); + } + printf("------------------------------------------------------------------\n"); + free(tstamp); + return 0; +} diff --git a/branches/WOF2-3/tests/perftest/read_lat/read_lat.rc b/branches/WOF2-3/tests/perftest/read_lat/read_lat.rc new file mode 100644 index 00000000..b35d8321 --- /dev/null +++ b/branches/WOF2-3/tests/perftest/read_lat/read_lat.rc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: write_bw.rc 1611 2006-08-20 14:48:55Z sleybo $ + */ + + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef _DEBUG_ +#define VER_FILEDESCRIPTION_STR "winverbs - RDMA read Latency Test (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "winverbs - RDMA read Latency Test " +#endif + +#define VER_INTERNALNAME_STR "ibv_read_lat.exe" +#define VER_ORIGINALFILENAME_STR "ibv_read_lat.exe" + +#include diff --git a/branches/WOF2-3/tests/perftest/send_bw/SOURCES b/branches/WOF2-3/tests/perftest/send_bw/SOURCES new file mode 100644 index 00000000..382d17ad --- /dev/null +++ b/branches/WOF2-3/tests/perftest/send_bw/SOURCES @@ -0,0 +1,30 @@ +TARGETNAME = ibv_send_bw +TARGETPATH = ..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = PROGRAM + +UMTYPE = console +UMENTRY = main + +USE_MSVCRT = 1 +USE_STL = 1 +USE_NATIVE_EH = 1 +USE_IOSTREAM = 1 + +SOURCES = send_bw.rc send_bw.c ..\perftest.c + +INCLUDES = ..;..\..\..\ulp\libibverbs\include;\ + ..\..\..\inc;..\..\..\inc\user;\ + ..\..\..\inc\user\linux; + +TARGETLIBS = \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\advapi32.lib \ + $(SDK_LIB_PATH)\user32.lib \ + $(SDK_LIB_PATH)\ole32.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\libibverbs.lib +!else + $(TARGETPATH)\*\libibverbsd.lib +!endif + diff --git a/branches/WOF2-3/tests/perftest/send_bw/makefile b/branches/WOF2-3/tests/perftest/send_bw/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-3/tests/perftest/send_bw/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\inc\openib.def diff --git a/branches/WOF2-3/tests/perftest/send_bw/send_bw.c b/branches/WOF2-3/tests/perftest/send_bw/send_bw.c new file mode 100644 index 00000000..3a736d82 --- /dev/null +++ b/branches/WOF2-3/tests/perftest/send_bw/send_bw.c @@ -0,0 +1,1177 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include + +#include "..\..\..\etc\user\getopt.c" +#include "perftest.h" +#include + +#define PINGPONG_SEND_WRID 1 +#define PINGPONG_RECV_WRID 2 +#define RC 0 +#define UC 1 +#define UD 3 +#define VERSION 1.1 +#define SIGNAL 1 +#define MAX_INLINE 400 +#define ALL 1 +#define MCG_LID 0xc001 +#define MCG_GID {255,1,0,0,0,2,201,133,0,0,0,0,0,0,0,0} + +struct user_parameters { + const char *servername; + int connection_type; + int mtu; + int all; /* run all msg size */ + int signal_comp; + int iters; + int tx_depth; + int rx_depth; + int duplex; + int use_event; + int use_mcg; + int inline_size; +}; + +typedef UINT64 cycles_t; +cycles_t *tposted; +cycles_t *tcompleted; +int post_recv; + +struct pingpong_context { + struct ibv_context *context; + struct ibv_comp_channel *channel; + struct ibv_pd *pd; + struct ibv_mr *mr; + struct ibv_cq *cq; + struct ibv_qp *qp; + void *buf; + unsigned size; + int tx_depth; + int rx_depth; + struct ibv_sge list; + struct ibv_sge recv_list; + struct ibv_send_wr wr; + struct ibv_recv_wr rwr; + struct ibv_ah *ah; +}; + +struct pingpong_dest { + int lid; + int qpn; + int psn; + unsigned rkey; + unsigned long long vaddr; +}; + +static uint16_t pp_get_local_lid(struct pingpong_context *ctx, int port) +{ + struct ibv_port_attr attr; + + if (ibv_query_port(ctx->context, (uint8_t) port, &attr)) + return 0; + + return attr.lid; +} + +static struct pingpong_dest * pp_client_exch_dest(SOCKET sockfd, + const struct pingpong_dest *my_dest) +{ + struct pingpong_dest *rem_dest = NULL; + char msg[sizeof "0000:000000:000000:00000000:0000000000000000"]; + int parsed; + + sprintf(msg, "%04x:%06x:%06x:%08x:%016Lx", my_dest->lid, my_dest->qpn, + my_dest->psn,my_dest->rkey,my_dest->vaddr); + if (send(sockfd, msg, sizeof msg, 0) != sizeof msg) { + perror("client send"); + fprintf(stderr, "Couldn't send local address\n"); + goto out; + } + + if (recv(sockfd, msg, sizeof msg, 0) != sizeof msg) { + perror("client recv"); + fprintf(stderr, "Couldn't recv remote address\n"); + goto out; + } + + rem_dest = malloc(sizeof *rem_dest); + if (!rem_dest) + goto out; + + memset(rem_dest, 0, sizeof *rem_dest); + parsed = sscanf(msg, "%x:%x:%x:%x:%Lx", &rem_dest->lid, &rem_dest->qpn, + &rem_dest->psn,&rem_dest->rkey,&rem_dest->vaddr); + + if (parsed != 5) { + fprintf(stderr, "Couldn't parse line <%.*s>\n",(int)sizeof msg, + msg); + free(rem_dest); + rem_dest = NULL; + goto out; + } +out: + return rem_dest; +} + +static struct pingpong_dest *pp_server_exch_dest(SOCKET connfd, const struct pingpong_dest *my_dest) +{ + char msg[sizeof "0000:000000:000000:00000000:0000000000000000"]; + struct pingpong_dest *rem_dest = NULL; + int parsed; + int n; + + n = recv(connfd, msg, sizeof msg, 0); + if (n != sizeof msg) { + perror("server recv"); + fprintf(stderr, "%d/%d: Couldn't recv remote address\n", n, (int) sizeof msg); + goto out; + } + + rem_dest = malloc(sizeof *rem_dest); + if (!rem_dest) + goto out; + + memset(rem_dest, 0, sizeof *rem_dest); + parsed = sscanf(msg, "%x:%x:%x:%x:%Lx", &rem_dest->lid, &rem_dest->qpn, + &rem_dest->psn, &rem_dest->rkey, &rem_dest->vaddr); + if (parsed != 5) { + fprintf(stderr, "Couldn't parse line <%.*s>\n",(int)sizeof msg, + msg); + free(rem_dest); + rem_dest = NULL; + goto out; + } + + sprintf(msg, "%04x:%06x:%06x:%08x:%016Lx", my_dest->lid, my_dest->qpn, + my_dest->psn, my_dest->rkey, my_dest->vaddr); + if (send(connfd, msg, sizeof msg, 0) != sizeof msg) { + perror("server send"); + fprintf(stderr, "Couldn't send local address\n"); + free(rem_dest); + rem_dest = NULL; + goto out; + } +out: + return rem_dest; +} + +static struct pingpong_context *pp_init_ctx(struct ibv_device *ib_dev, + unsigned size, + int tx_depth, int rx_depth, int port, + struct user_parameters *user_parm) +{ + struct pingpong_context *ctx; + struct ibv_device_attr device_attr; + + ctx = malloc(sizeof *ctx); + if (!ctx) + return NULL; + + ctx->size = size; + ctx->tx_depth = tx_depth; + ctx->rx_depth = rx_depth + tx_depth; + /* in case of UD need space for the GRH */ + if (user_parm->connection_type==UD) { + ctx->buf = malloc((size + 40) * 2); + if (!ctx->buf) { + fprintf(stderr, "Couldn't allocate work buf.\n"); + return NULL; + } + memset(ctx->buf, 0, ( size + 40 ) * 2); + } else { + ctx->buf = malloc(size * 2); + if (!ctx->buf) { + fprintf(stderr, "Couldn't allocate work buf.\n"); + return NULL; + } + memset(ctx->buf, 0, size * 2); + } + + + ctx->context = ibv_open_device(ib_dev); + if (!ctx->context) { + fprintf(stderr, "Couldn't get context for %s\n", + ibv_get_device_name(ib_dev)); + return NULL; + } + if (user_parm->mtu == 0) {/*user did not ask for specific mtu */ + if (ibv_query_device(ctx->context, &device_attr)) { + fprintf(stderr, "Failed to query device props"); + return NULL; + } + if (device_attr.vendor_part_id == 23108) { + user_parm->mtu = 1024; + } else { + user_parm->mtu = 2048; + } + } + if (user_parm->use_event) { + ctx->channel = ibv_create_comp_channel(ctx->context); + if (!ctx->channel) { + fprintf(stderr, "Couldn't create completion channel\n"); + return NULL; + } + } else + ctx->channel = NULL; + ctx->pd = ibv_alloc_pd(ctx->context); + if (!ctx->pd) { + fprintf(stderr, "Couldn't allocate PD\n"); + return NULL; + } + + /* We dont really want IBV_ACCESS_LOCAL_WRITE, but IB spec says: + * The Consumer is not allowed to assign Remote Write or Remote Atomic to + * a Memory Region that has not been assigned Local Write. */ + if (user_parm->connection_type==UD) { + ctx->mr = ibv_reg_mr(ctx->pd, ctx->buf, (size + 40 ) * 2, + IBV_ACCESS_REMOTE_WRITE | IBV_ACCESS_LOCAL_WRITE); + if (!ctx->mr) { + fprintf(stderr, "Couldn't allocate MR\n"); + return NULL; + } + } else { + ctx->mr = ibv_reg_mr(ctx->pd, ctx->buf, size * 2, + IBV_ACCESS_REMOTE_WRITE | IBV_ACCESS_LOCAL_WRITE); + if (!ctx->mr) { + fprintf(stderr, "Couldn't allocate MR\n"); + return NULL; + } + } + + ctx->cq = ibv_create_cq(ctx->context, ctx->rx_depth, NULL, ctx->channel, 0); + if (!ctx->cq) { + fprintf(stderr, "Couldn't create CQ\n"); + return NULL; + } + { + struct ibv_qp_init_attr attr; + memset(&attr, 0, sizeof(struct ibv_qp_init_attr)); + attr.send_cq = ctx->cq; + attr.recv_cq = ctx->cq; + attr.cap.max_send_wr = tx_depth; + /* Work around: driver doesnt support + * recv_wr = 0 */ + attr.cap.max_recv_wr = ctx->rx_depth; + attr.cap.max_send_sge = 1; + attr.cap.max_recv_sge = 1; + attr.cap.max_inline_data = user_parm->inline_size; + switch (user_parm->connection_type) { + case RC : + attr.qp_type = IBV_QPT_RC; + break; + case UC : + attr.qp_type = IBV_QPT_UC; + break; + case UD : + attr.qp_type = IBV_QPT_UD; + break; + default: + fprintf(stderr, "Unknown connection type %d \n",user_parm->connection_type); + return NULL; + } + /*attr.sq_sig_all = 0;*/ + + ctx->qp = ibv_create_qp(ctx->pd, &attr); + if (!ctx->qp) { + fprintf(stderr, "Couldn't create QP\n"); + return NULL; + } + + if ((user_parm->connection_type==UD) && (user_parm->use_mcg)) { + union ibv_gid gid; + uint8_t mcg_gid[16] = MCG_GID; + + /* use the local QP number as part of the mcg */ + mcg_gid[11] = (user_parm->servername) ? 0 : 1; + *(uint32_t *)(&mcg_gid[12]) = ctx->qp->qp_num; + memcpy(gid.raw, mcg_gid, 16); + + if (ibv_attach_mcast(ctx->qp, &gid, MCG_LID)) { + fprintf(stderr, "Couldn't attach QP to mcg\n"); + return NULL; + } + } + } + + { + struct ibv_qp_attr attr; + + attr.qp_state = IBV_QPS_INIT; + attr.pkey_index = 0; + attr.port_num = (uint8_t) port; + if (user_parm->connection_type==UD) + attr.qkey = 0x11111111; + else + attr.qp_access_flags = IBV_ACCESS_REMOTE_WRITE | IBV_ACCESS_LOCAL_WRITE; + + if (user_parm->connection_type==UD) { + if (ibv_modify_qp(ctx->qp, &attr, + IBV_QP_STATE | + IBV_QP_PKEY_INDEX | + IBV_QP_PORT | + IBV_QP_QKEY)) { + fprintf(stderr, "Failed to modify UD QP to INIT\n"); + return NULL; + } + } else if (ibv_modify_qp(ctx->qp, &attr, + IBV_QP_STATE | + IBV_QP_PKEY_INDEX | + IBV_QP_PORT | + IBV_QP_ACCESS_FLAGS)) { + fprintf(stderr, "Failed to modify QP to INIT\n"); + return NULL; + } + } + return ctx; +} + +static int pp_connect_ctx(struct pingpong_context *ctx, int port, int my_psn, + struct pingpong_dest *dest, struct user_parameters *user_parm) +{ + struct ibv_qp_attr attr; + memset(&attr, 0, sizeof attr); + + attr.qp_state = IBV_QPS_RTR; + switch (user_parm->mtu) { + case 256 : + attr.path_mtu = IBV_MTU_256; + break; + case 512 : + attr.path_mtu = IBV_MTU_512; + break; + case 1024 : + attr.path_mtu = IBV_MTU_1024; + break; + case 2048 : + attr.path_mtu = IBV_MTU_2048; + break; + case 4096 : + attr.path_mtu = IBV_MTU_4096; + break; + } + printf("Mtu : %d\n", user_parm->mtu); + attr.dest_qp_num = dest->qpn; + attr.rq_psn = dest->psn; + if (user_parm->connection_type == RC) { + attr.max_dest_rd_atomic = 1; + attr.min_rnr_timer = 12; + } + attr.ah_attr.is_global = 0; + attr.ah_attr.dlid = (uint16_t) dest->lid; + attr.ah_attr.sl = 0; + attr.ah_attr.src_path_bits = 0; + attr.ah_attr.port_num = (uint8_t) port; + if ((user_parm->connection_type==UD) && (user_parm->use_mcg)) { + uint8_t mcg_gid[16] = MCG_GID; + /* send the message to the mcg of the other side */ + mcg_gid[11] = (user_parm->servername) ? 1 : 0; + *(uint32_t *)(&mcg_gid[12]) = dest->qpn; + attr.ah_attr.dlid = MCG_LID; + attr.ah_attr.is_global = 1; + attr.ah_attr.grh.sgid_index = 0; + memcpy(attr.ah_attr.grh.dgid.raw, mcg_gid, 16); + } else { + attr.ah_attr.dlid = (uint16_t) dest->lid; + attr.ah_attr.is_global = 0; + } + if (user_parm->connection_type == RC) { + if (ibv_modify_qp(ctx->qp, &attr, + IBV_QP_STATE | + IBV_QP_AV | + IBV_QP_PATH_MTU | + IBV_QP_DEST_QPN | + IBV_QP_RQ_PSN | + IBV_QP_MIN_RNR_TIMER | + IBV_QP_MAX_DEST_RD_ATOMIC)) { + fprintf(stderr, "Failed to modify RC QP to RTR\n"); + return 1; + } + attr.timeout = 14; + attr.retry_cnt = 7; + attr.rnr_retry = 7; + } else if (user_parm->connection_type == UC) { + if (ibv_modify_qp(ctx->qp, &attr, + IBV_QP_STATE | + IBV_QP_AV | + IBV_QP_PATH_MTU | + IBV_QP_DEST_QPN | + IBV_QP_RQ_PSN)) { + fprintf(stderr, "Failed to modify UC QP to RTR\n"); + return 1; + } + } else { + if (ibv_modify_qp(ctx->qp, &attr, + IBV_QP_STATE )) { + fprintf(stderr, "Failed to modify UC QP to RTR\n"); + return 1; + } + } + attr.qp_state = IBV_QPS_RTS; + attr.sq_psn = my_psn; + attr.max_rd_atomic = 1; + if (user_parm->connection_type == RC) { + attr.max_rd_atomic = 1; + if (ibv_modify_qp(ctx->qp, &attr, + IBV_QP_STATE | + IBV_QP_SQ_PSN | + IBV_QP_TIMEOUT | + IBV_QP_RETRY_CNT | + IBV_QP_RNR_RETRY | + IBV_QP_MAX_QP_RD_ATOMIC)) { + fprintf(stderr, "Failed to modify RC QP to RTS\n"); + return 1; + } + } else { /*both UC and UD */ + if (ibv_modify_qp(ctx->qp, &attr, + IBV_QP_STATE | + IBV_QP_SQ_PSN)) { + fprintf(stderr, "Failed to modify UC QP to RTS\n"); + return 1; + } + + } + if (user_parm->connection_type==UD) { + ctx->ah = ibv_create_ah(ctx->pd, &attr.ah_attr); + if (!ctx->ah) { + fprintf(stderr, "Failed to create AH for UD\n"); + return 1; + } + } + /* post receive max msg size*/ + { + int i; + struct ibv_recv_wr *bad_wr_recv; + //receive + ctx->rwr.wr_id = PINGPONG_RECV_WRID; + ctx->rwr.sg_list = &ctx->recv_list; + ctx->rwr.num_sge = 1; + ctx->rwr.next = NULL; + ctx->recv_list.addr = (uintptr_t) ctx->buf; + if (user_parm->connection_type==UD) { + ctx->recv_list.length = ctx->size + 40; + } else { + ctx->recv_list.length = ctx->size; + } + ctx->recv_list.lkey = ctx->mr->lkey; + for (i = 0; i < ctx->rx_depth; ++i) + if (ibv_post_recv(ctx->qp, &ctx->rwr, &bad_wr_recv)) { + fprintf(stderr, "Couldn't post recv: counter=%d\n", i); + return 14; + } + } + post_recv = ctx->rx_depth; + return 0; +} + +static void usage(const char *argv0) +{ + printf("Usage:\n"); + printf(" %s start a server and wait for connection\n", argv0); + printf(" %s -h connect to server at \n", argv0); + printf("\n"); + printf("Options:\n"); + printf(" -p listen on/connect to port (default 18515)\n"); + printf(" -d, use IB device (default first device found)\n"); + printf(" -i use port of IB device (default 1)\n"); + printf(" -c connection type RC/UC/UD (default RC)\n"); + printf(" -m mtu size (256 - 4096. default for hermon is 2048)\n"); + printf(" -s size of message to exchange (default 65536)\n"); + printf(" -a Run sizes from 2 till 2^23\n"); + printf(" -t size of tx queue (default 300)\n"); + printf(" -g send messages to multicast group(only available in UD connection\n"); + printf(" -r make rx queue bigger than tx (default 600)\n"); + printf(" -n number of exchanges (at least 2, default 1000)\n"); + printf(" -I max size of message to be sent in inline mode (default 400)\n"); + printf(" -b measure bidirectional bandwidth (default unidirectional)\n"); + printf(" -V display version number\n"); + printf(" -e sleep on CQ events (default poll)\n"); + printf(" -N cancel peak-bw calculation (default with peak-bw)\n"); +} + +static void print_report(unsigned int iters, unsigned size, int duplex, + cycles_t *tposted, cycles_t *tcompleted, int noPeak) +{ + cycles_t cycles_to_units; + unsigned long tsize; /* Transferred size */ + int i, j; + int opt_posted = 0, opt_completed = 0; + cycles_t opt_delta; + cycles_t t; + + opt_delta = tcompleted[opt_posted] - tposted[opt_completed]; + + if (!noPeak) { + /* Find the peak bandwidth, unless asked not to in command line */ + for (i = 0; i < (int) iters; ++i) + for (j = i; j < (int) iters; ++j) { + t = (tcompleted[j] - tposted[i]) / (j - i + 1); + if (t < opt_delta) { + opt_delta = t; + opt_posted = i; + opt_completed = j; + } + } + } + + cycles_to_units = get_freq(); + + tsize = duplex ? 2 : 1; + tsize = tsize * size; + printf("%7d %d ", size, iters); + + { + double sec = (double) opt_delta / (double) cycles_to_units; + double mbytes = (double) !(noPeak) * (double) tsize / (double) 0x100000; + printf("%7.2f ", mbytes / sec); + + sec = (double) (tcompleted[iters - 1] - tposted[0]) / (double) cycles_to_units; + mbytes = (double) tsize * (double) iters / (double) 0x100000; + printf("%7.2f\n", mbytes / sec); + } +} + +static int run_iter_bi(struct pingpong_context *ctx, struct user_parameters *user_param, + struct pingpong_dest *rem_dest, int size) +{ + struct ibv_qp *qp; + int scnt, ccnt, rcnt; + struct ibv_recv_wr *bad_wr_recv; + if (user_param->connection_type == UD) { + if (size > 2048) + size = 2048; + } + /********************************************* + * Important note : + * In case of UD/UC this is NOT the way to measure + * BW sicen we are running with loop on the send side + * while we should run on the receive side or enable retry in SW + * Since the sender may be faster than the reciver than although + * we had posted receive it is not enough and might end this will + * result in deadlock of test since both sides are stuck on poll cq + * In this test i do not solve this for the general test ,need to send + * seperate test for UC/UD but in case the tx_depth is ~1/3 from the + * number of iterations this should be ok . + * Also note that the sender is limited in the number of send, and + * i try to make the receiver full + *********************************************/ + + if (user_param->connection_type == UD) + ctx->recv_list.length = ctx->size + 40; + else + ctx->recv_list.length = ctx->size; + if (size > user_param->inline_size) /*compliance to perf_main */ + ctx->wr.send_flags = IBV_SEND_SIGNALED; + else + ctx->wr.send_flags = IBV_SEND_SIGNALED | IBV_SEND_INLINE; + + ctx->list.length = size; + scnt = 0; + ccnt = 0; + rcnt = 0; + qp = ctx->qp; + + while (ccnt < user_param->iters || rcnt < user_param->iters ) { + struct ibv_wc wc; + int ne; + while (scnt < user_param->iters && + (scnt - ccnt) < user_param->tx_depth / 2) { + struct ibv_send_wr *bad_wr; + if (user_param->servername) + tposted[scnt] = get_cycles(); + if (ibv_post_send(qp, &ctx->wr, &bad_wr)) { + fprintf(stderr, "Couldn't post send: scnt=%d\n", + scnt); + return 1; + } + ++scnt; + } + if (user_param->use_event) { + struct ibv_cq *ev_cq; + void *ev_ctx; + if (ibv_get_cq_event(ctx->channel, &ev_cq, &ev_ctx)) { + fprintf(stderr, "Failed to get cq_event\n"); + return 1; + } + if (ev_cq != ctx->cq) { + fprintf(stderr, "CQ event for unknown CQ %p\n", ev_cq); + return 1; + } + if (ibv_req_notify_cq(ctx->cq, 0)) { + fprintf(stderr, "Couldn't request CQ notification\n"); + return 1; + } + } + for (;;) { + ne = ibv_poll_cq(ctx->cq, 1, &wc); + if (ne <= 0) + break; + + if (wc.status != IBV_WC_SUCCESS) { + fprintf(stderr, "Completion wth error at %s:\n", + user_param->servername ? "client" : "server"); + fprintf(stderr, "Failed status %d: wr_id %d syndrom 0x%x\n", + wc.status, (int) wc.wr_id, wc.vendor_err); + fprintf(stderr, "scnt=%d, ccnt=%d\n", + scnt, ccnt); + return 1; + } + switch ((int) wc.wr_id) { + case PINGPONG_SEND_WRID: + if (user_param->servername) + tcompleted[ccnt] = get_cycles(); + ccnt += 1; + break; + case PINGPONG_RECV_WRID: + if (--post_recv <= ctx->rx_depth - 2) { + while (rcnt < user_param->iters && + (ctx->rx_depth - post_recv) > 0 ) { + ++post_recv; + if (ibv_post_recv(qp, &ctx->rwr, &bad_wr_recv)) { + fprintf(stderr, "Couldn't post recv: rcnt=%d\n", + rcnt); + return 15; + } + } + } + rcnt += 1; + break; + default: + fprintf(stderr, "Completion for unknown wr_id %d\n", + (int) wc.wr_id); + break; + } + } + + if (ne < 0) { + fprintf(stderr, "poll CQ failed %d\n", ne); + return 1; + } + } + + return(0); +} + +static int run_iter_uni(struct pingpong_context *ctx, struct user_parameters *user_param, + struct pingpong_dest *rem_dest, int size) +{ + struct ibv_qp *qp; + int scnt, ccnt, rcnt; + struct ibv_recv_wr *bad_wr_recv; + + if (user_param->connection_type == UD) { + if (size > 2048) + size = 2048; + } + + if (user_param->connection_type == UD) + ctx->recv_list.length = ctx->size + 40; + else + ctx->recv_list.length = ctx->size; + + if (size > user_param->inline_size) { /*complaince to perf_main */ + ctx->wr.send_flags = IBV_SEND_SIGNALED; + } else { + ctx->wr.send_flags = IBV_SEND_SIGNALED | IBV_SEND_INLINE; + } + ctx->list.length = size; + scnt = 0; + ccnt = 0; + rcnt = 0; + qp = ctx->qp; + if (!user_param->servername) { + while (rcnt < user_param->iters) { + int ne; + struct ibv_wc wc; + /*Server is polling on receive first */ + if (user_param->use_event) { + struct ibv_cq *ev_cq; + void *ev_ctx; + if (ibv_get_cq_event(ctx->channel, &ev_cq, &ev_ctx)) { + fprintf(stderr, "Failed to get cq_event\n"); + return 1; + } + if (ev_cq != ctx->cq) { + fprintf(stderr, "CQ event for unknown CQ %p\n", ev_cq); + return 1; + } + if (ibv_req_notify_cq(ctx->cq, 0)) { + fprintf(stderr, "Couldn't request CQ notification\n"); + return 1; + } + } + do { + ne = ibv_poll_cq(ctx->cq, 1, &wc); + if (ne) { + if (user_param->servername) + tcompleted[ccnt] = get_cycles(); + if (wc.status != IBV_WC_SUCCESS) { + fprintf(stderr, "Completion wth error at %s:\n", + user_param->servername ? "client" : "server"); + fprintf(stderr, "Failed status %d: wr_id %d syndrom 0x%x\n", + wc.status, (int) wc.wr_id, wc.vendor_err); + fprintf(stderr, "scnt=%d, ccnt=%d\n", + scnt, ccnt); + return 1; + } + ++rcnt; + if (ibv_post_recv(qp, &ctx->rwr, &bad_wr_recv)) { + fprintf(stderr, "Couldn't post recv: rcnt=%d\n", + rcnt); + return 15; + } + + } + } while (ne > 0 ); + + if (ne < 0) { + fprintf(stderr, "Poll Receive CQ failed %d\n", ne); + return 12; + } + } + } else { + /* client is posting and not receiving. */ + while (scnt < user_param->iters || ccnt < user_param->iters) { + while (scnt < user_param->iters && (scnt - ccnt) < user_param->tx_depth ) { + struct ibv_send_wr *bad_wr; + if (user_param->servername) + tposted[scnt] = get_cycles(); + if (ibv_post_send(qp, &ctx->wr, &bad_wr)) { + fprintf(stderr, "Couldn't post send: scnt=%d\n", + scnt); + return 1; + } + ++scnt; + } + if (ccnt < user_param->iters) { + struct ibv_wc wc; + int ne; + if (user_param->use_event) { + struct ibv_cq *ev_cq; + void *ev_ctx; + if (ibv_get_cq_event(ctx->channel, &ev_cq, &ev_ctx)) { + fprintf(stderr, "Failed to get cq_event\n"); + return 1; + } + if (ev_cq != ctx->cq) { + fprintf(stderr, "CQ event for unknown CQ %p\n", ev_cq); + return 1; + } + if (ibv_req_notify_cq(ctx->cq, 0)) { + fprintf(stderr, "Couldn't request CQ notification\n"); + return 1; + } + } + for (;;) { + ne = ibv_poll_cq(ctx->cq, 1, &wc); + if (ne <= 0) + break; + + if (user_param->servername) + tcompleted[ccnt] = get_cycles(); + if (wc.status != IBV_WC_SUCCESS) { + fprintf(stderr, "Completion wth error at %s:\n", + user_param->servername ? "client" : "server"); + fprintf(stderr, "Failed status %d: wr_id %d syndrom 0x%x\n", + wc.status, (int) wc.wr_id, wc.vendor_err); + fprintf(stderr, "scnt=%d, ccnt=%d\n", + scnt, ccnt); + return 1; + } + ccnt += ne; + } + + if (ne < 0) { + fprintf(stderr, "poll CQ failed %d\n", ne); + return 1; + } + } + } + } + return 0; +} + +int __cdecl main(int argc, char *argv[]) +{ + struct ibv_device **dev_list; + struct ibv_device *ib_dev; + struct pingpong_context *ctx; + struct pingpong_dest my_dest; + struct pingpong_dest *rem_dest; + struct user_parameters user_param; + struct ibv_device_attr device_attribute; + char *ib_devname = NULL; + int port = 18515; + int ib_port = 1; + int size = 65536; + SOCKET sockfd; + int i = 0; + int size_max_pow = 24; + int noPeak = 0;/*noPeak == 0: regular peak-bw calculation done*/ + int inline_given_in_cmd = 0; + struct ibv_context *context; + WORD version; + WSADATA data; + int err; + + srand((unsigned int) time(NULL)); + version = MAKEWORD(2, 2); + err = WSAStartup(version, &data); + if (err) + return -1; + + /* init default values to user's parameters */ + memset(&user_param, 0, sizeof(struct user_parameters)); + user_param.mtu = 0; + user_param.iters = 1000; + user_param.tx_depth = 300; + user_param.servername = NULL; + user_param.use_event = 0; + user_param.duplex = 0; + user_param.inline_size = MAX_INLINE; + + /* Parameter parsing. */ + while (1) { + int c; + + c = getopt(argc, argv, "h:p:d:i:m:c:s:n:t:I:r:ebaVgN"); + if (c == -1) + break; + + switch (c) { + case 'p': + port = strtol(optarg, NULL, 0); + if (port < 0 || port > 65535) { + usage(argv[0]); + return 1; + } + break; + case 'e': + ++user_param.use_event; + break; + case 'g': + ++user_param.use_mcg; + break; + case 'd': + ib_devname = _strdup(optarg); + break; + case 'c': + if (strcmp("UC",optarg)==0) + user_param.connection_type=UC; + if (strcmp("UD",optarg)==0) + user_param.connection_type=UD; + break; + case 'm': + user_param.mtu = strtol(optarg, NULL, 0); + break; + case 'a': + user_param.all = ALL; + break; + case 'V': + printf("send_bw version : %.2f\n",VERSION); + return 0; + case 'i': + ib_port = strtol(optarg, NULL, 0); + if (ib_port < 0) { + usage(argv[0]); + return 1; + } + break; + + case 's': + size = strtol(optarg, NULL, 0); + break; + + case 't': + user_param.tx_depth = strtol(optarg, NULL, 0); + if (user_param.tx_depth < 1) { + usage(argv[0]); + return 1; + } + break; + + case 'I': + user_param.inline_size = strtol(optarg, NULL, 0); + inline_given_in_cmd =1; + if (user_param.inline_size > MAX_INLINE) { + usage(argv[0]); + return 7; + } + + case 'r': + errno = 0; + user_param.rx_depth = strtol(optarg, NULL, 0); + if (errno) { + usage(argv[0]); + return 1; + } + break; + + case 'n': + user_param.iters = strtol(optarg, NULL, 0); + if (user_param.iters < 2) { + usage(argv[0]); + return 1; + } + break; + + case 'b': + user_param.duplex = 1; + break; + + case 'N': + noPeak = 1; + break; + + case 'h': + if (optarg) { + user_param.servername = _strdup(optarg); + break; + } + + default: + usage(argv[0]); + return 1; + } + } + + printf("------------------------------------------------------------------\n"); + if (user_param.duplex == 1 && (!user_param.use_mcg || !(user_param.connection_type == UD))) + printf(" Send Bidirectional BW Test\n"); + else if (user_param.duplex == 1 && user_param.use_mcg && (user_param.connection_type == UD)) + printf(" Send Bidirectional BW Multicast Test\n"); + else if (!user_param.duplex == 1 && user_param.use_mcg && (user_param.connection_type == UD)) + printf(" Send BW Multicast Test\n"); + else + printf(" Send BW Test\n"); + + if (user_param.connection_type == RC) + printf("Connection type : RC\n"); + else if (user_param.connection_type == UC) + printf("Connection type : UC\n"); + else{ + printf("Connection type : UD\n"); + } + + /* Done with parameter parsing. Perform setup. */ + if (user_param.all == ALL) + /*since we run all sizes */ + size = 8388608; /*2^23 */ + else if (user_param.connection_type == UD && size > 2048) { + printf("Max msg size in UD is 2048 changing to 2048\n"); + size = 2048; + } + + dev_list = ibv_get_device_list(NULL); + + if (!ib_devname) { + ib_dev = dev_list[0]; + if (!ib_dev) { + fprintf(stderr, "No IB devices found\n"); + return 1; + } + } else { + for (; (ib_dev = *dev_list); ++dev_list) + if (!strcmp(ibv_get_device_name(ib_dev), ib_devname)) + break; + if (!ib_dev) { + fprintf(stderr, "IB device %s not found\n", ib_devname); + return 1; + } + } + + context = ibv_open_device(ib_dev); + if (ibv_query_device(context, &device_attribute)) { + fprintf(stderr, "Failed to query device props"); + return 1; + } + if ((device_attribute.vendor_part_id == 25418) && (!inline_given_in_cmd)) { + user_param.inline_size = 1; + } + printf("Inline data is used up to %d bytes message\n", user_param.inline_size); + + ctx = pp_init_ctx(ib_dev, size, user_param.tx_depth, user_param.rx_depth, + ib_port, &user_param); + if (!ctx) + return 1; + + /* Create connection between client and server. + * We do it by exchanging data over a TCP socket connection. */ + + my_dest.lid = pp_get_local_lid(ctx, ib_port); + my_dest.qpn = ctx->qp->qp_num; + my_dest.psn = rand() & 0xffffff; + if (!my_dest.lid) { + fprintf(stderr, "Local lid 0x0 detected. Is an SM running?\n"); + return 1; + } + my_dest.rkey = ctx->mr->rkey; + my_dest.vaddr = (uintptr_t)ctx->buf + size; + printf(" local address: LID %#04x, QPN %#06x, PSN %#06x\n", + my_dest.lid, my_dest.qpn, my_dest.psn); + + if (user_param.servername) { + sockfd = pp_client_connect(user_param.servername, port); + if (sockfd == INVALID_SOCKET) + return 1; + rem_dest = pp_client_exch_dest(sockfd, &my_dest); + } else { + sockfd = pp_server_connect(port); + if (sockfd == INVALID_SOCKET) + return 1; + rem_dest = pp_server_exch_dest(sockfd, &my_dest); + } + + if (!rem_dest) + return 1; + + printf(" remote address: LID %#04x, QPN %#06x, PSN %#06x\n", + rem_dest->lid, rem_dest->qpn, rem_dest->psn); + + if (pp_connect_ctx(ctx, ib_port, my_dest.psn, rem_dest, &user_param)) + return 1; + + /* An additional handshake is required *after* moving qp to RTR. + Arbitrarily reuse exch_dest for this purpose. */ + if (user_param.servername) { + rem_dest = pp_client_exch_dest(sockfd, &my_dest); + } else { + rem_dest = pp_server_exch_dest(sockfd, &my_dest); + } + if (user_param.use_event) { + printf("Test with events.\n"); + if (ibv_req_notify_cq(ctx->cq, 0)) { + fprintf(stderr, "Couldn't request CQ notification\n"); + return 1; + } + } + printf("------------------------------------------------------------------\n"); + printf(" #bytes #iterations BW peak[MB/sec] BW average[MB/sec] \n"); + + tposted = malloc(user_param.iters * sizeof *tposted); + + if (!tposted) { + perror("malloc"); + return 1; + } + + tcompleted = malloc(user_param.iters * sizeof *tcompleted); + + if (!tcompleted) { + perror("malloc"); + return 1; + } + /* send */ + if (user_param.connection_type == UD) { + ctx->list.addr = (uintptr_t) ctx->buf + 40; + ctx->wr.wr.ud.ah = ctx->ah; + ctx->wr.wr.ud.remote_qpn = rem_dest->qpn; + ctx->wr.wr.ud.remote_qkey = 0x11111111; + if (user_param.use_mcg) { + ctx->wr.wr.ud.remote_qpn = 0xffffff; + } else { + ctx->wr.wr.ud.remote_qpn = rem_dest->qpn; + } + } else + ctx->list.addr = (uintptr_t) ctx->buf; + ctx->list.lkey = ctx->mr->lkey; + ctx->wr.wr_id = PINGPONG_SEND_WRID; + ctx->wr.sg_list = &ctx->list; + ctx->wr.num_sge = 1; + ctx->wr.opcode = IBV_WR_SEND; + ctx->wr.next = NULL; + + /* receive */ + ctx->rwr.wr_id = PINGPONG_RECV_WRID; + ctx->rwr.sg_list = &ctx->recv_list; + ctx->rwr.num_sge = 1; + ctx->rwr.next = NULL; + ctx->recv_list.addr = (uintptr_t) ctx->buf; + ctx->recv_list.lkey = ctx->mr->lkey; + + if (user_param.all == ALL) { + if (user_param.connection_type == UD) + size_max_pow = 12; + + for (i = 1; i < size_max_pow ; ++i) { + size = 1 << i; + if (user_param.duplex) { + if(run_iter_bi(ctx, &user_param, rem_dest, size)) + return 17; + } else { + if(run_iter_uni(ctx, &user_param, rem_dest, size)) + return 17; + } + if (user_param.servername) { + print_report(user_param.iters, size, user_param.duplex, tposted, tcompleted, noPeak); + /* sync again for the sake of UC/UC */ + rem_dest = pp_client_exch_dest(sockfd, &my_dest); + } else + rem_dest = pp_server_exch_dest(sockfd, &my_dest); + } + } else { + if (user_param.duplex) { + if (run_iter_bi(ctx, &user_param, rem_dest, size)) + return 18; + } + else { + if(run_iter_uni(ctx, &user_param, rem_dest, size)) + return 18; + } + + if (user_param.servername) + print_report(user_param.iters, size, user_param.duplex, tposted, tcompleted, noPeak); + } + + /* close sockets */ + if (user_param.servername) + rem_dest = pp_client_exch_dest(sockfd, &my_dest); + else + rem_dest = pp_server_exch_dest(sockfd, &my_dest); + + if (send(sockfd, "done", sizeof "done", 0) != sizeof "done"){ + perror("send"); + fprintf(stderr, "Couldn't send to socket\n"); + return 1; + } + closesocket(sockfd); + + free(tposted); + free(tcompleted); + + printf("------------------------------------------------------------------\n"); + return 0; +} diff --git a/branches/WOF2-3/tests/perftest/send_bw/send_bw.rc b/branches/WOF2-3/tests/perftest/send_bw/send_bw.rc new file mode 100644 index 00000000..192ed112 --- /dev/null +++ b/branches/WOF2-3/tests/perftest/send_bw/send_bw.rc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: send_bw.rc 474 2006-08-31 08:57:19Z sleybo $ + */ + + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef DBG +#define VER_FILEDESCRIPTION_STR "winverbs - Send/Recv Bandwidth Test (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "winverbs - Send/Recv Bandwidth Test " +#endif + +#define VER_INTERNALNAME_STR "ibv_send_bw.exe" +#define VER_ORIGINALFILENAME_STR "ibv_send_bw.exe" + +#include diff --git a/branches/WOF2-3/tests/perftest/send_lat/SOURCES b/branches/WOF2-3/tests/perftest/send_lat/SOURCES new file mode 100644 index 00000000..92e2f546 --- /dev/null +++ b/branches/WOF2-3/tests/perftest/send_lat/SOURCES @@ -0,0 +1,30 @@ +TARGETNAME = ibv_send_lat +TARGETPATH = ..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = PROGRAM + +UMTYPE = console +UMENTRY = main + +USE_MSVCRT = 1 +USE_STL = 1 +USE_NATIVE_EH = 1 +USE_IOSTREAM = 1 + +SOURCES = send_lat.rc send_lat.c ..\perftest.c + +INCLUDES = ..;..\..\..\ulp\libibverbs\include;\ + ..\..\..\inc;..\..\..\inc\user;\ + ..\..\..\inc\user\linux; + +TARGETLIBS = \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\advapi32.lib \ + $(SDK_LIB_PATH)\user32.lib \ + $(SDK_LIB_PATH)\ole32.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\libibverbs.lib +!else + $(TARGETPATH)\*\libibverbsd.lib +!endif + diff --git a/branches/WOF2-3/tests/perftest/send_lat/makefile b/branches/WOF2-3/tests/perftest/send_lat/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-3/tests/perftest/send_lat/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\inc\openib.def diff --git a/branches/WOF2-3/tests/perftest/send_lat/send_lat.c b/branches/WOF2-3/tests/perftest/send_lat/send_lat.c new file mode 100644 index 00000000..57958038 --- /dev/null +++ b/branches/WOF2-3/tests/perftest/send_lat/send_lat.c @@ -0,0 +1,1059 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies Ltd. All rights reserved. + * Copyright (c) 2005 Hewlett Packard, Inc (Grant Grundler) + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include + +#include "..\..\..\etc\user\getopt.c" +#include "perftest.h" +#include + +#define PINGPONG_SEND_WRID 1 +#define PINGPONG_RECV_WRID 2 +#define RC 0 +#define UC 1 +#define UD 3 +#define VERSION 1.1 +#define SIGNAL 1 +#define MAX_INLINE 400 +#define MCG_LID 0xc001 +#define MCG_GID {255,1,0,0,0,2,201,133,0,0,0,0,0,0,0,0} + +typedef UINT64 cycles_t; +cycles_t *tstamp; + +struct user_parameters { + const char *servername; + int connection_type; + int mtu; + int signal_comp; + int all; /* run all msg size */ + int iters; + int tx_depth; + int use_event; + int inline_size; + int use_mcg; +}; + +struct report_options { + int unsorted; + int histogram; + int cycles; /* report delta's in cycles, not microsec's */ +}; + +struct pingpong_context { + struct ibv_sge list; + struct ibv_sge recv_list; + struct ibv_send_wr wr; + struct ibv_recv_wr rwr; + struct ibv_context *context; + struct ibv_comp_channel *channel; + struct ibv_pd *pd; + struct ibv_mr *mr; + struct ibv_cq *scq; + struct ibv_cq *rcq; + struct ibv_qp *qp; + struct ibv_ah *ah; + void *buf; + volatile char *post_buf; + volatile char *poll_buf; + int size; + int tx_depth; +}; + +struct pingpong_dest { + unsigned long long vaddr; + int lid; + int qpn; + int psn; + unsigned int rkey; +}; + +static uint16_t pp_get_local_lid(struct pingpong_context *ctx, int port) +{ + struct ibv_port_attr attr; + + if (ibv_query_port(ctx->context, (uint8_t) port, &attr)) + return 0; + + return attr.lid; +} + +static struct ibv_device *pp_find_dev(const char *ib_devname) { + struct ibv_device **dev_list; + struct ibv_device *ib_dev = NULL; + + dev_list = ibv_get_device_list(NULL); + if (!dev_list) + return NULL; + + if (!ib_devname) { + ib_dev = dev_list[0]; + if (!ib_dev) + fprintf(stderr, "No IB devices found\n"); + } else { + for (; (ib_dev = *dev_list); ++dev_list) + if (!strcmp(ibv_get_device_name(ib_dev), ib_devname)) + break; + if (!ib_dev) + fprintf(stderr, "IB device %s not found\n", ib_devname); + } + return ib_dev; +} + +#define KEY_MSG_SIZE (sizeof "0000:000000:000000:00000000:0000000000000000") +#define KEY_PRINT_FMT "%04x:%06x:%06x:%08x:%016Lx" + +static int pp_write_keys(SOCKET sockfd, const struct pingpong_dest *my_dest) +{ + char msg[KEY_MSG_SIZE]; + + sprintf(msg, KEY_PRINT_FMT, my_dest->lid, my_dest->qpn, + my_dest->psn, my_dest->rkey, my_dest->vaddr); + + if (send(sockfd, msg, sizeof msg, 0) != sizeof msg) { + perror("client write"); + fprintf(stderr, "Couldn't send local address\n"); + return -1; + } + + return 0; +} + +static int pp_read_keys(SOCKET sockfd, const struct pingpong_dest *my_dest, + struct pingpong_dest *rem_dest) +{ + int parsed; + char msg[KEY_MSG_SIZE]; + + if (recv(sockfd, msg, sizeof msg, 0) != sizeof msg) { + perror("pp_read_keys"); + fprintf(stderr, "Couldn't read remote address\n"); + return -1; + } + + memset(rem_dest, 0, sizeof *rem_dest); + parsed = sscanf(msg, KEY_PRINT_FMT, &rem_dest->lid, &rem_dest->qpn, + &rem_dest->psn, &rem_dest->rkey, &rem_dest->vaddr); + + if (parsed != 5) { + fprintf(stderr, "Couldn't parse line <%.*s>\n", + (int)sizeof msg, msg); + return -1; + } + + return 0; +} + +static int pp_client_exch_dest(SOCKET sockfd, const struct pingpong_dest *my_dest, + struct pingpong_dest *rem_dest) +{ + if (pp_write_keys(sockfd, my_dest)) + return -1; + + return pp_read_keys(sockfd, my_dest, rem_dest); +} + +static int pp_server_exch_dest(SOCKET sockfd, const struct pingpong_dest *my_dest, + struct pingpong_dest* rem_dest) +{ + + if (pp_read_keys(sockfd, my_dest, rem_dest)) + return -1; + + return pp_write_keys(sockfd, my_dest); +} + +static struct pingpong_context *pp_init_ctx(struct ibv_device *ib_dev, int size, + int tx_depth, int port,struct user_parameters *user_parm) { + struct pingpong_context *ctx; + struct ibv_device_attr device_attr; + + ctx = malloc(sizeof *ctx); + if (!ctx) + return NULL; + + ctx->size = size; + ctx->tx_depth = tx_depth; + /* in case of UD need space for the GRH */ + if (user_parm->connection_type==UD) { + ctx->buf = malloc(( size + 40 ) * 2); + if (!ctx->buf) { + fprintf(stderr, "Couldn't allocate work buf.\n"); + return NULL; + } + memset(ctx->buf, 0, ( size + 40 ) * 2); + } else { + ctx->buf = malloc(size * 2); + if (!ctx->buf) { + fprintf(stderr, "Couldn't allocate work buf.\n"); + return NULL; + } + memset(ctx->buf, 0, size * 2); + } + + ctx->post_buf = (char*)ctx->buf + (size - 1); + ctx->poll_buf = (char*)ctx->buf + (2 * size - 1); + + ctx->context = ibv_open_device(ib_dev); + if (!ctx->context) { + fprintf(stderr, "Couldn't get context for %s\n", + ibv_get_device_name(ib_dev)); + return NULL; + } + if (user_parm->mtu == 0) {/*user did not ask for specific mtu */ + if (ibv_query_device(ctx->context, &device_attr)) { + fprintf(stderr, "Failed to query device props"); + return NULL; + } + if (device_attr.vendor_part_id == 23108) { + user_parm->mtu = 1024; + } else { + user_parm->mtu = 2048; + } + } + if (user_parm->use_event) { + ctx->channel = ibv_create_comp_channel(ctx->context); + if (!ctx->channel) { + fprintf(stderr, "Couldn't create completion channel\n"); + return NULL; + } + } else + ctx->channel = NULL; + ctx->pd = ibv_alloc_pd(ctx->context); + if (!ctx->pd) { + fprintf(stderr, "Couldn't allocate PD\n"); + return NULL; + } + if (user_parm->connection_type==UD) { + ctx->mr = ibv_reg_mr(ctx->pd, ctx->buf, (size + 40 ) * 2, + IBV_ACCESS_REMOTE_WRITE | IBV_ACCESS_LOCAL_WRITE); + if (!ctx->mr) { + fprintf(stderr, "Couldn't allocate MR\n"); + return NULL; + } + } else { + ctx->mr = ibv_reg_mr(ctx->pd, ctx->buf, size * 2, + IBV_ACCESS_REMOTE_WRITE | IBV_ACCESS_LOCAL_WRITE); + if (!ctx->mr) { + fprintf(stderr, "Couldn't allocate MR\n"); + return NULL; + } + } + + ctx->scq = ibv_create_cq(ctx->context, tx_depth, NULL, ctx->channel, 0); + if (!ctx->scq) { + fprintf(stderr, "Couldn't create CQ\n"); + return NULL; + } + ctx->rcq = ibv_create_cq(ctx->context, tx_depth, NULL, ctx->channel, 0); + if (!ctx->rcq) { + fprintf(stderr, "Couldn't create Receive CQ\n"); + return NULL; + } + { + struct ibv_qp_init_attr attr; + memset(&attr, 0, sizeof(struct ibv_qp_init_attr)); + attr.send_cq = ctx->scq; + attr.recv_cq = ctx->rcq; + attr.cap.max_send_wr = tx_depth; + /* Work around: driver doesnt support + * recv_wr = 0 */ + attr.cap.max_recv_wr = tx_depth; + attr.cap.max_send_sge = 1; + attr.cap.max_recv_sge = 1; + attr.cap.max_inline_data = user_parm->inline_size; + switch (user_parm->connection_type) { + case RC : + attr.qp_type = IBV_QPT_RC; + break; + case UC : + attr.qp_type = IBV_QPT_UC; + break; + case UD : + attr.qp_type = IBV_QPT_UD; + break; + default: + fprintf(stderr, "Unknown connection type %d \n",user_parm->connection_type); + return NULL; + } + attr.sq_sig_all = 0; + ctx->qp = ibv_create_qp(ctx->pd, &attr); + if (!ctx->qp) { + fprintf(stderr, "Couldn't create QP\n"); + return NULL; + } + + if ((user_parm->connection_type==UD) && (user_parm->use_mcg)) { + union ibv_gid gid; + uint8_t mcg_gid[16] = MCG_GID; + + /* use the local QP number as part of the mcg */ + mcg_gid[11] = (user_parm->servername) ? 0 : 1; + *(uint32_t *)(&mcg_gid[12]) = ctx->qp->qp_num; + memcpy(gid.raw, mcg_gid, 16); + + if (ibv_attach_mcast(ctx->qp, &gid, MCG_LID)) { + fprintf(stderr, "Couldn't attach QP to mcg\n"); + return NULL; + } + } + } + + { + struct ibv_qp_attr attr; + memset(&attr, 0, sizeof(struct ibv_qp_init_attr)); + attr.qp_state = IBV_QPS_INIT; + attr.pkey_index = 0; + attr.port_num = (uint8_t) port; + if (user_parm->connection_type==UD) { + attr.qkey = 0x11111111; + } else { + attr.qp_access_flags = IBV_ACCESS_REMOTE_WRITE | IBV_ACCESS_LOCAL_WRITE; + } + + if (user_parm->connection_type==UD) { + if (ibv_modify_qp(ctx->qp, &attr, + IBV_QP_STATE | + IBV_QP_PKEY_INDEX | + IBV_QP_PORT | + IBV_QP_QKEY)) { + fprintf(stderr, "Failed to modify UD QP to INIT\n"); + return NULL; + } + } else if (ibv_modify_qp(ctx->qp, &attr, + IBV_QP_STATE | + IBV_QP_PKEY_INDEX | + IBV_QP_PORT | + IBV_QP_ACCESS_FLAGS)) { + fprintf(stderr, "Failed to modify QP to INIT\n"); + return NULL; + } + } + //send + ctx->wr.wr_id = PINGPONG_SEND_WRID; + ctx->wr.sg_list = &ctx->list; + ctx->wr.num_sge = 1; + ctx->wr.opcode = IBV_WR_SEND; + ctx->wr.next = NULL; + //receive + ctx->rwr.wr_id = PINGPONG_RECV_WRID; + ctx->rwr.sg_list = &ctx->recv_list; + ctx->rwr.num_sge = 1; + ctx->rwr.next = NULL; + return ctx; +} + +static int pp_connect_ctx(struct pingpong_context *ctx, int port, int my_psn, + struct pingpong_dest *dest,struct user_parameters *user_parm) +{ + struct ibv_qp_attr attr; + memset(&attr, 0, sizeof(struct ibv_qp_attr)); + attr.qp_state = IBV_QPS_RTR; + if (user_parm->connection_type != UD) { + switch (user_parm->mtu) { + case 256 : + attr.path_mtu = IBV_MTU_256; + break; + case 512 : + attr.path_mtu = IBV_MTU_512; + break; + case 1024 : + attr.path_mtu = IBV_MTU_1024; + break; + case 2048 : + attr.path_mtu = IBV_MTU_2048; + break; + case 4096 : + attr.path_mtu = IBV_MTU_4096; + break; + } + printf("Mtu : %d\n", user_parm->mtu); + attr.dest_qp_num = dest->qpn; + attr.rq_psn = dest->psn; + } + if (user_parm->connection_type==RC) { + attr.max_dest_rd_atomic = 1; + attr.min_rnr_timer = 12; + } + + attr.ah_attr.is_global = 0; + attr.ah_attr.dlid = (uint16_t) dest->lid; + attr.ah_attr.sl = 0; + attr.ah_attr.src_path_bits = 0; + attr.ah_attr.port_num = (uint8_t) port; + if ((user_parm->connection_type==UD) && (user_parm->use_mcg)) { + uint8_t mcg_gid[16] = MCG_GID; + + /* send the message to the mcg of the other side */ + mcg_gid[11] = (user_parm->servername) ? 1 : 0; + *(uint32_t *)(&mcg_gid[12]) = dest->qpn; + + attr.ah_attr.dlid = MCG_LID; + attr.ah_attr.is_global = 1; + attr.ah_attr.grh.sgid_index = 0; + memcpy(attr.ah_attr.grh.dgid.raw, mcg_gid, 16); + } else { + attr.ah_attr.dlid = (uint16_t) dest->lid; + attr.ah_attr.is_global = 0; + } + + if (user_parm->connection_type==RC) { + if (ibv_modify_qp(ctx->qp, &attr, + IBV_QP_STATE | + IBV_QP_AV | + IBV_QP_PATH_MTU | + IBV_QP_DEST_QPN | + IBV_QP_RQ_PSN | + IBV_QP_MIN_RNR_TIMER | + IBV_QP_MAX_DEST_RD_ATOMIC)) { + fprintf(stderr, "Failed to modify RC QP to RTR\n"); + return 1; + } + attr.timeout = 14; + attr.retry_cnt = 7; + attr.rnr_retry = 7; + } else if (user_parm->connection_type==UC) { + if (ibv_modify_qp(ctx->qp, &attr, + IBV_QP_STATE | + IBV_QP_AV | + IBV_QP_PATH_MTU | + IBV_QP_DEST_QPN | + IBV_QP_RQ_PSN)) { + fprintf(stderr, "Failed to modify UC QP to RTR\n"); + return 1; + } + + } else { + if (ibv_modify_qp(ctx->qp, &attr, + IBV_QP_STATE )) { + fprintf(stderr, "Failed to modify UC QP to RTR\n"); + return 1; + } + + } + attr.qp_state = IBV_QPS_RTS; + attr.sq_psn = my_psn; + if (user_parm->connection_type==RC) { + attr.max_rd_atomic = 1; + if (ibv_modify_qp(ctx->qp, &attr, + IBV_QP_STATE | + IBV_QP_SQ_PSN | + IBV_QP_TIMEOUT | + IBV_QP_RETRY_CNT | + IBV_QP_RNR_RETRY | + IBV_QP_MAX_QP_RD_ATOMIC)) { + fprintf(stderr, "Failed to modify RC QP to RTS\n"); + return 1; + } + } else { /*both UC and UD */ + if (ibv_modify_qp(ctx->qp, &attr, + IBV_QP_STATE | + IBV_QP_SQ_PSN)) { + fprintf(stderr, "Failed to modify UC/UD QP to RTS\n"); + return 1; + } + + } + if (user_parm->connection_type==UD) { + ctx->ah = ibv_create_ah(ctx->pd, &attr.ah_attr); + if (!ctx->ah) { + fprintf(stderr, "Failed to create AH for UD\n"); + return 1; + } + } + /* post receive max msg size*/ + { + int i; + struct ibv_recv_wr *bad_wr_recv; + + ctx->recv_list.addr = (uintptr_t) ctx->buf; + if (user_parm->connection_type==UD) { + ctx->recv_list.length = ctx->size + 40; + } else { + ctx->recv_list.length = ctx->size; + } + ctx->recv_list.lkey = ctx->mr->lkey; + for (i = 0; i < user_parm->tx_depth / 2; ++i) { + if (ibv_post_recv(ctx->qp, &ctx->rwr, &bad_wr_recv)) { + fprintf(stderr, "Couldn't post recv: counter=%d\n", + i); + return 14; + } + } + } + return 0; +} + +static int pp_open_port(struct pingpong_context *ctx, const char * servername, + int ib_port, int port, struct pingpong_dest *rem_dest,struct user_parameters *user_parm) +{ + char addr_fmt[] = "%8s address: LID %#04x QPN %#06x PSN %#06x\n"; + struct pingpong_dest my_dest; + SOCKET sockfd; + int rc; + + /* Create connection between client and server. + * We do it by exchanging data over a TCP socket connection. */ + + my_dest.lid = pp_get_local_lid(ctx, ib_port); + my_dest.qpn = ctx->qp->qp_num; + my_dest.psn = rand() & 0xffffff; + if (!my_dest.lid) { + fprintf(stderr, "Local lid 0x0 detected. Is an SM running?\n"); + return -1; + } + my_dest.rkey = ctx->mr->rkey; + my_dest.vaddr = (uintptr_t)ctx->buf + ctx->size; + + printf(addr_fmt, "local", my_dest.lid, my_dest.qpn, my_dest.psn); + + sockfd = servername ? pp_client_connect(servername, port) : + pp_server_connect(port); + + if (sockfd == INVALID_SOCKET) { + printf("pp_connect_sock(%s,%d) failed (%d)!\n", + servername, port, sockfd); + return (int) sockfd; + } + + rc = servername ? pp_client_exch_dest(sockfd, &my_dest, rem_dest) : + pp_server_exch_dest(sockfd, &my_dest, rem_dest); + if (rc) + return rc; + + printf(addr_fmt, "remote", rem_dest->lid, rem_dest->qpn, rem_dest->psn, + rem_dest->rkey, rem_dest->vaddr); + + if ((rc = pp_connect_ctx(ctx, ib_port, my_dest.psn, rem_dest,user_parm))) + return rc; + + /* An additional handshake is required *after* moving qp to RTR. + * Arbitrarily reuse exch_dest for this purpose. + */ + + rc = servername ? pp_client_exch_dest(sockfd, &my_dest, rem_dest) : + pp_server_exch_dest(sockfd, &my_dest, rem_dest); + + if (rc) + return rc; + + if (send(sockfd, "done", sizeof "done", 0) != sizeof "done"){ + perror("write"); + fprintf(stderr, "Couldn't write to socket\n"); + return 1; + } + + closesocket(sockfd); + return 0; +} + +static void usage(const char *argv0) +{ + printf("Usage:\n"); + printf(" %s start a server and wait for connection\n", argv0); + printf(" %s -h connect to server at \n", argv0); + printf("\n"); + printf("Options:\n"); + printf(" -p listen on/connect to port (default 18515)\n"); + printf(" -c connection type RC/UC/UD (default RC)\n"); + printf(" -m mtu size (256 - 4096. default for hermon is 2048)\n"); + printf(" -d use IB device (default first device found)\n"); + printf(" -i use port of IB device (default 1)\n"); + printf(" -s size of message to exchange (default 1)\n"); + printf(" -t size of tx queue (default 50)\n"); + printf(" -l signal completion on each msg\n"); + printf(" -a Run sizes from 2 till 2^23\n"); + printf(" -n number of exchanges (at least 2, default 1000)\n"); + printf(" -I max size of message to be sent in inline mode (default 400)\n"); + printf(" -C report times in cpu cycle units (default microseconds)\n"); + printf(" -H print out all results (default print summary only)\n"); + printf(" -U (implies -H) print out unsorted results (default sorted)\n"); + printf(" -V display version number\n"); + printf(" -e sleep on CQ events (default poll)\n"); + printf(" -g send messages to multicast group(only available in UD connection\n"); +} + +static void print_report(struct report_options * options, + unsigned int iters, cycles_t *tstamp,int size) +{ + cycles_t cycles_to_units; + cycles_t median; + unsigned int i; + const char* units; + cycles_t *delta = malloc((iters - 1) * sizeof *delta); + + if (!delta) { + perror("malloc"); + return; + } + + for (i = 0; i < iters - 1; ++i) + delta[i] = tstamp[i + 1] - tstamp[i]; + + if (options->cycles) { + cycles_to_units = 1; + units = "cycles"; + } else { + cycles_to_units = get_freq(); + units = "sec"; + } + + if (options->unsorted) { + printf("#, %s, frequency=%I64d\n", units, get_freq()); + for (i = 0; i < iters - 1; ++i) + printf("%d, %g\n", i + 1, delta[i] / cycles_to_units / 2. * 1000000.); + } + + qsort(delta, iters - 1, sizeof *delta, cycles_compare); + + if (options->histogram) { + printf("#, %s\n", units); + for (i = 0; i < iters - 1; ++i) + printf("%d, %7.2f\n", i + 1, (double) delta[i] / (double) cycles_to_units / 2. * 1000000.); + } + + median = get_median(iters - 1, delta); + printf("%7d %d %7.2f %7.2f %7.2f\n", + size, iters, (double) delta[0] / (double) cycles_to_units / 2. * 1000000., + (double) delta[iters - 2] / (double) cycles_to_units / 2. * 1000000., + (double) median / (double) cycles_to_units / 2. * 1000000.); + free(delta); +} + +static int run_iter(struct pingpong_context *ctx, struct user_parameters *user_param, + struct pingpong_dest *rem_dest, int size) +{ + struct ibv_qp *qp; + struct ibv_send_wr *wr, *bad_wr; + struct ibv_recv_wr rwr; + struct ibv_recv_wr *bad_wr_recv; + volatile char *poll_buf; + volatile char *post_buf; + int scnt, rcnt, ccnt, poll; + int iters; + int tx_depth; + iters = user_param->iters; + tx_depth = user_param->tx_depth; + + if (user_param->connection_type==UD) { + if (size > 2048) { + size = 2048; + } + } + + ///send // + wr = &ctx->wr; + if (user_param->connection_type==UD) { + ctx->list.addr = (uintptr_t) ctx->buf + 40; + } else { + ctx->list.addr = (uintptr_t) ctx->buf; + } + ctx->list.length = size; + ctx->list.lkey = ctx->mr->lkey; + if (user_param->connection_type==UD) { + ctx->wr.wr.ud.ah = ctx->ah; + ctx->wr.wr.ud.remote_qpn = rem_dest->qpn; + ctx->wr.wr.ud.remote_qkey = 0x11111111; + if (user_param->use_mcg) { + ctx->wr.wr.ud.remote_qpn = 0xffffff; + } else { + ctx->wr.wr.ud.remote_qpn = rem_dest->qpn; + } + } + /// receive // + rwr = ctx->rwr; + ctx->recv_list.addr = (uintptr_t) ctx->buf; + if (user_param->connection_type==UD) { + ctx->recv_list.length = ctx->size + 40; + } else { + ctx->recv_list.length = ctx->size; + } + + ctx->recv_list.lkey = ctx->mr->lkey; + + scnt = 0; + rcnt = 0; + ccnt = 0; + poll = 0; + poll_buf = ctx->poll_buf; + post_buf = ctx->post_buf; + qp = ctx->qp; + if (size > user_param->inline_size || size == 0) {/* complaince to perf_main don't signal*/ + ctx->wr.send_flags = 0; + } else { + ctx->wr.send_flags = IBV_SEND_INLINE; + } + + while (scnt < iters || rcnt < iters) { + if (rcnt < iters && !(scnt < 1 && user_param->servername)) { + int ne; + struct ibv_wc wc; + /*Server is polling on receive first */ + ++rcnt; + if (ibv_post_recv(qp, &rwr, &bad_wr_recv)) { + fprintf(stderr, "Couldn't post recv: rcnt=%d\n", + rcnt); + return 15; + } + if (user_param->use_event) { + struct ibv_cq *ev_cq; + void *ev_ctx; + + if (ibv_get_cq_event(ctx->channel, &ev_cq, &ev_ctx)) { + fprintf(stderr, "Failed to get receive cq_event\n"); + return 1; + } + + if (ev_cq != ctx->rcq) { + fprintf(stderr, "CQ event for unknown RCQ %p\n", ev_cq); + return 1; + } + + if (ibv_req_notify_cq(ctx->rcq, 0)) { + fprintf(stderr, "Couldn't request RCQ notification\n"); + return 1; + } + } + do { + ne = ibv_poll_cq(ctx->rcq, 1, &wc); + } while (!user_param->use_event && ne < 1); + + if (ne < 0) { + fprintf(stderr, "Poll Receive CQ failed %d\n", ne); + return 12; + } + if (wc.status != IBV_WC_SUCCESS) { + fprintf(stderr, "Receive Completion wth error at %s:\n", + user_param->servername ? "client" : "server"); + fprintf(stderr, "Failed status %d: wr_id %d\n", + wc.status, (int) wc.wr_id); + fprintf(stderr, "scnt=%d, rcnt=%d, ccnt=%d\n", + scnt, rcnt, ccnt); + return 13; + } + } + if (scnt < iters ) { + if (ccnt == (tx_depth - 2) || (user_param->signal_comp == SIGNAL) + || (scnt == (iters - 1)) ) { + ccnt = 0; + poll=1; + if (size > user_param->inline_size || size == 0) {/* complaince to perf_main */ + ctx->wr.send_flags = IBV_SEND_SIGNALED; + } else { + ctx->wr.send_flags = IBV_SEND_SIGNALED | IBV_SEND_INLINE; + } + + } + /* client post first */ + if (user_param->servername) + tstamp[scnt] = get_cycles(); + *post_buf = (char)++scnt; + if (ibv_post_send(qp, wr, &bad_wr)) { + fprintf(stderr, "Couldn't post send: scnt=%d\n", + scnt); + return 11; + } + } + if (poll == 1) { + struct ibv_wc wc; + int ne; + if (user_param->use_event) { + struct ibv_cq *ev_cq; + void *ev_ctx; + + if (ibv_get_cq_event(ctx->channel, &ev_cq, &ev_ctx)) { + fprintf(stderr, "Failed to get send cq_event\n"); + return 1; + } + + if (ev_cq != ctx->scq) { + fprintf(stderr, "CQ event for unknown SCQ %p\n", ev_cq); + return 1; + } + + if (ibv_req_notify_cq(ctx->scq, 0)) { + fprintf(stderr, "Couldn't request SCQ notification\n"); + return 1; + } + } + /* poll on scq */ + do { + ne = ibv_poll_cq(ctx->scq, 1, &wc); + } while (!user_param->use_event && ne < 1); + + if (ne < 0) { + fprintf(stderr, "poll SCQ failed %d\n", ne); + return 12; + } + if (wc.status != IBV_WC_SUCCESS) { + fprintf(stderr, "Completion wth error at %s:\n", + user_param->servername ? "client" : "server"); + fprintf(stderr, "Failed status %d: wr_id %d\n", + wc.status, (int) wc.wr_id); + fprintf(stderr, "scnt=%d, rcnt=%d, ccnt=%d\n", + scnt, rcnt, ccnt); + return 13; + } + poll = 0; + if (size > user_param->inline_size || size == 0) {/* complaince to perf_main don't signal*/ + ctx->wr.send_flags = 0; + } else { + ctx->wr.send_flags = IBV_SEND_INLINE; + } + + } + ++ccnt; + } + + return(0); +} + +int __cdecl main(int argc, char *argv[]) +{ + const char *ib_devname = NULL; + int port = 18515; + int ib_port = 1; + int size = 2; + int i = 0; + int size_max_pow = 24; + struct report_options report; + struct pingpong_context *ctx; + struct pingpong_dest rem_dest; + struct ibv_device *ib_dev; + struct user_parameters user_param; + WORD version; + WSADATA data; + int err; + + srand((unsigned int) time(NULL)); + version = MAKEWORD(2, 2); + err = WSAStartup(version, &data); + if (err) + return -1; + + /* init default values to user's parameters */ + memset(&report, 0, sizeof report); + memset(&user_param, 0, sizeof(struct user_parameters)); + user_param.mtu = 0; + user_param.iters = 1000; + user_param.tx_depth = 50; + user_param.servername = NULL; + user_param.use_event = 0; + user_param.use_mcg = 0; + user_param.inline_size = MAX_INLINE; + user_param.signal_comp = 0; + + /* Parameter parsing. */ + while (1) { + int c; + + c = getopt(argc, argv, "h:p:c:m:d:i:s:n:t:I:laeCHUVg"); + if (c == -1) + break; + + switch (c) { + case 'p': + port = strtol(optarg, NULL, 0); + if (port < 0 || port > 65535) { + usage(argv[0]); + return 1; + } + break; + case 'c': + if (strcmp("UC",optarg)==0) + user_param.connection_type=UC; + if (strcmp("UD",optarg)==0) + user_param.connection_type=UD; + /* default is 0 for any other option RC*/ + break; + case 'e': + ++user_param.use_event; + break; + case 'g': + ++user_param.use_mcg; + break; + case 'm': + user_param.mtu = strtol(optarg, NULL, 0); + break; + case 'l': + user_param.signal_comp = SIGNAL; + break; + case 'a': + user_param.all = SIGNAL; + break; + case 'V': + printf("perftest version : %.2f\n",VERSION); + return 0; + case 'd': + ib_devname = _strdup(optarg); + break; + + case 'i': + ib_port = strtol(optarg, NULL, 0); + if (ib_port < 0) { + usage(argv[0]); + return 2; + } + break; + + case 's': + size = strtol(optarg, NULL, 0); + if (size < 1) { + usage(argv[0]); return 3; + } + break; + + case 't': + user_param.tx_depth = strtol(optarg, NULL, 0); + if (user_param.tx_depth < 1) { + usage(argv[0]); return 4; + } + break; + + case 'I': + user_param.inline_size = strtol(optarg, NULL, 0); + if (user_param.inline_size > MAX_INLINE) { + usage(argv[0]); + return 19; + } + break; + + case 'n': + user_param.iters = strtol(optarg, NULL, 0); + if (user_param.iters < 2) { + usage(argv[0]); + return 5; + } + + break; + + case 'C': + report.cycles = 1; + break; + + case 'H': + report.histogram = 1; + break; + + case 'U': + report.unsorted = 1; + break; + + case 'h': + if (optarg) { + user_param.servername = _strdup(optarg); + break; + } + + default: + usage(argv[0]); + return 5; + } + } + + /* + * Done with parameter parsing. Perform setup. + */ + tstamp = malloc(user_param.iters * sizeof *tstamp); + if (!tstamp) { + perror("malloc"); + return 10; + } + /* Print header data */ + printf("------------------------------------------------------------------\n"); + if (user_param.use_mcg && (user_param.connection_type == UD)) + printf(" Send Latency Multicast Test\n"); + else + printf(" Send Latency Test\n"); + printf("Inline data is used up to %d bytes message\n", user_param.inline_size); + if (user_param.connection_type==RC) { + printf("Connection type : RC\n"); + } else if (user_param.connection_type==UC) { + printf("Connection type : UC\n"); + } else { + printf("Connection type : UD\n"); + } + if (user_param.all == 1) { + /*since we run all sizes lets allocate big enough buffer */ + size = 8388608; /*2^23 */ + } + + ib_dev = pp_find_dev(ib_devname); + if (!ib_dev) + return 7; + + ctx = pp_init_ctx(ib_dev, size, user_param.tx_depth, ib_port,&user_param); + if (!ctx) + return 8; + + if (pp_open_port(ctx, user_param.servername, ib_port, port, &rem_dest,&user_param)) + return 9; + if (user_param.use_event) { + printf("Test with events.\n"); + if (ibv_req_notify_cq(ctx->rcq, 0)) { + fprintf(stderr, "Couldn't request RCQ notification\n"); + return 1; + } + if (ibv_req_notify_cq(ctx->scq, 0)) { + fprintf(stderr, "Couldn't request SCQ notification\n"); + return 1; + } + + } + printf("------------------------------------------------------------------\n"); + printf(" #bytes #iterations t_min[usec] t_max[usec] t_typical[usec]\n"); + + if (user_param.all == 1) { + if (user_param.connection_type==UD) { + size_max_pow = 12; + } + for (i = 1; i < size_max_pow ; ++i) { + size = 1 << i; + if(run_iter(ctx, &user_param, &rem_dest, size)) + return 17; + + print_report(&report, user_param.iters, tstamp, size); + } + } else { + if(run_iter(ctx, &user_param, &rem_dest, size)) + return 18; + print_report(&report, user_param.iters, tstamp, size); + } + printf("------------------------------------------------------------------\n"); + free(tstamp); + return 0; +} diff --git a/branches/WOF2-3/tests/perftest/send_lat/send_lat.rc b/branches/WOF2-3/tests/perftest/send_lat/send_lat.rc new file mode 100644 index 00000000..f70c64da --- /dev/null +++ b/branches/WOF2-3/tests/perftest/send_lat/send_lat.rc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: send_lat.rc 474 2006-08-31 08:57:19Z sleybo $ + */ + + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef DBG +#define VER_FILEDESCRIPTION_STR "winverbs - Send/Recv Latency Test (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "winverbs - Send/Recv Latency Test " +#endif + +#define VER_INTERNALNAME_STR "ibv_send_lat.exe" +#define VER_ORIGINALFILENAME_STR "ibv_send_lat.exe" + +#include diff --git a/branches/WOF2-3/tests/perftest/write_bw/SOURCES b/branches/WOF2-3/tests/perftest/write_bw/SOURCES new file mode 100644 index 00000000..8b7426d7 --- /dev/null +++ b/branches/WOF2-3/tests/perftest/write_bw/SOURCES @@ -0,0 +1,29 @@ +TARGETNAME = ibv_write_bw +TARGETPATH = ..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = PROGRAM + +UMTYPE = console +UMENTRY = main + +USE_MSVCRT = 1 +USE_STL = 1 +USE_NATIVE_EH = 1 +USE_IOSTREAM = 1 + +SOURCES = write_bw.rc write_bw.c ..\perftest.c + +INCLUDES = ..;..\..\..\ulp\libibverbs\include;\ + ..\..\..\inc;..\..\..\inc\user;\ + ..\..\..\inc\user\linux; +TARGETLIBS = \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\advapi32.lib \ + $(SDK_LIB_PATH)\user32.lib \ + $(SDK_LIB_PATH)\ole32.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\libibverbs.lib +!else + $(TARGETPATH)\*\libibverbsd.lib +!endif + diff --git a/branches/WOF2-3/tests/perftest/write_bw/makefile b/branches/WOF2-3/tests/perftest/write_bw/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-3/tests/perftest/write_bw/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\inc\openib.def diff --git a/branches/WOF2-3/tests/perftest/write_bw/write_bw.c b/branches/WOF2-3/tests/perftest/write_bw/write_bw.c new file mode 100644 index 00000000..194899f5 --- /dev/null +++ b/branches/WOF2-3/tests/perftest/write_bw/write_bw.c @@ -0,0 +1,887 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies Ltd. All rights reserved. + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include + +#include "..\..\..\etc\user\getopt.c" +#include "perftest.h" +#include + +#define PINGPONG_RDMA_WRID 3 +#define VERSION 2.0 +#define ALL 1 +#define MAX_INLINE 400 +#define RC 0 +#define UC 1 + +struct user_parameters { + const char *servername; + int connection_type; + int mtu; + int all; /* run all msg size */ + int iters; + int tx_depth; + int numofqps; + int maxpostsofqpiniteration; + int inline_size; +}; + +struct extended_qp { + struct ibv_qp *qp; + int scnt, ccnt ; +}; + +typedef UINT64 cycles_t; +cycles_t *tposted; +cycles_t *tcompleted; + +struct pingpong_context { + struct ibv_context *context; + struct ibv_pd *pd; + struct ibv_mr *mr; + struct ibv_cq *cq; + struct ibv_qp **qp; + void *buf; + unsigned size; + int tx_depth; + struct ibv_sge list; + struct ibv_send_wr wr; + int *scnt; + int *ccnt; +}; + +struct pingpong_dest { + int lid; + int qpn; + int psn; + unsigned rkey; + unsigned long long vaddr; +}; + +static uint16_t pp_get_local_lid(struct pingpong_context *ctx, int port) +{ + struct ibv_port_attr attr; + + if (ibv_query_port(ctx->context, (uint8_t) port, &attr)) + return 0; + + return attr.lid; +} + +static struct pingpong_dest * pp_client_exch_dest(SOCKET sockfd, + const struct pingpong_dest *my_dest) +{ + struct pingpong_dest *rem_dest = NULL; + char msg[sizeof "0000:000000:000000:00000000:0000000000000000"]; + int parsed; + + sprintf(msg, "%04x:%06x:%06x:%08x:%016Lx", my_dest->lid, my_dest->qpn, + my_dest->psn,my_dest->rkey,my_dest->vaddr); + if (send(sockfd, msg, sizeof msg, 0) != sizeof msg) { + perror("client send"); + fprintf(stderr, "Couldn't send local address\n"); + goto out; + } + + if (recv(sockfd, msg, sizeof msg, 0) != sizeof msg) { + perror("client recv"); + fprintf(stderr, "Couldn't recv remote address\n"); + goto out; + } + + rem_dest = malloc(sizeof *rem_dest); + if (!rem_dest) + goto out; + + memset(rem_dest, 0, sizeof *rem_dest); + parsed = sscanf(msg, "%x:%x:%x:%x:%Lx", &rem_dest->lid, &rem_dest->qpn, + &rem_dest->psn,&rem_dest->rkey,&rem_dest->vaddr); + + if (parsed != 5) { + fprintf(stderr, "Couldn't parse line <%.*s>\n",(int)sizeof msg, + msg); + free(rem_dest); + rem_dest = NULL; + goto out; + } +out: + return rem_dest; +} + +static struct pingpong_dest *pp_server_exch_dest(SOCKET connfd, const struct pingpong_dest *my_dest) +{ + char msg[sizeof "0000:000000:000000:00000000:0000000000000000"]; + struct pingpong_dest *rem_dest = NULL; + int parsed; + int n; + + n = recv(connfd, msg, sizeof msg, 0); + if (n != sizeof msg) { + perror("server recv"); + fprintf(stderr, "%d/%d: Couldn't recv remote address\n", n, (int) sizeof msg); + goto out; + } + + rem_dest = malloc(sizeof *rem_dest); + if (!rem_dest) + goto out; + + memset(rem_dest, 0, sizeof *rem_dest); + parsed = sscanf(msg, "%x:%x:%x:%x:%Lx", &rem_dest->lid, &rem_dest->qpn, + &rem_dest->psn, &rem_dest->rkey, &rem_dest->vaddr); + if (parsed != 5) { + fprintf(stderr, "Couldn't parse line <%.*s>\n",(int)sizeof msg, + msg); + free(rem_dest); + rem_dest = NULL; + goto out; + } + + sprintf(msg, "%04x:%06x:%06x:%08x:%016Lx", my_dest->lid, my_dest->qpn, + my_dest->psn, my_dest->rkey, my_dest->vaddr); + if (send(connfd, msg, sizeof msg, 0) != sizeof msg) { + perror("server send"); + fprintf(stderr, "Couldn't send local address\n"); + free(rem_dest); + rem_dest = NULL; + goto out; + } +out: + return rem_dest; +} + +static struct pingpong_context *pp_init_ctx(struct ibv_device *ib_dev, + unsigned size, + int tx_depth, int port, struct user_parameters *user_parm) +{ + struct pingpong_context *ctx; + struct ibv_device_attr device_attr; + int counter; + + ctx = malloc(sizeof *ctx); + if (!ctx) + return NULL; + ctx->qp = malloc(sizeof (struct ibv_qp*) * user_parm->numofqps); + ctx->size = size; + ctx->tx_depth = tx_depth; + ctx->scnt = malloc(user_parm->numofqps * sizeof (int)); + if (!ctx->scnt) { + perror("malloc"); + return NULL; + } + ctx->ccnt = malloc(user_parm->numofqps * sizeof (int)); + if (!ctx->ccnt) { + perror("malloc"); + return NULL; + } + memset(ctx->scnt, 0, user_parm->numofqps * sizeof (int)); + memset(ctx->ccnt, 0, user_parm->numofqps * sizeof (int)); + + ctx->buf = malloc(size * 2 * user_parm->numofqps); + if (!ctx->buf) { + fprintf(stderr, "Couldn't allocate work buf.\n"); + return NULL; + } + + memset(ctx->buf, 0, size * 2 * user_parm->numofqps); + + ctx->context = ibv_open_device(ib_dev); + if (!ctx->context) { + fprintf(stderr, "Couldn't get context for %s\n", + ibv_get_device_name(ib_dev)); + return NULL; + } + if (user_parm->mtu == 0) {/*user did not ask for specific mtu */ + if (ibv_query_device(ctx->context, &device_attr)) { + fprintf(stderr, "Failed to query device props"); + return NULL; + } + if (device_attr.vendor_part_id == 23108) { + user_parm->mtu = 1024; + } else { + user_parm->mtu = 2048; + } + } + + ctx->pd = ibv_alloc_pd(ctx->context); + if (!ctx->pd) { + fprintf(stderr, "Couldn't allocate PD\n"); + return NULL; + } + + /* We dont really want IBV_ACCESS_LOCAL_WRITE, but IB spec says: + * The Consumer is not allowed to assign Remote Write or Remote Atomic to + * a Memory Region that has not been assigned Local Write. */ + ctx->mr = ibv_reg_mr(ctx->pd, ctx->buf, size * 2 * user_parm->numofqps, + IBV_ACCESS_REMOTE_WRITE | IBV_ACCESS_LOCAL_WRITE); + if (!ctx->mr) { + fprintf(stderr, "Couldn't allocate MR\n"); + return NULL; + } + + ctx->cq = ibv_create_cq(ctx->context, tx_depth * user_parm->numofqps , NULL, NULL, 0); + if (!ctx->cq) { + fprintf(stderr, "Couldn't create CQ\n"); + return NULL; + } + for (counter =0 ; counter < user_parm->numofqps ; counter++) + { + struct ibv_qp_init_attr initattr; + struct ibv_qp_attr attr; + memset(&initattr, 0, sizeof(struct ibv_qp_init_attr)); + initattr.send_cq = ctx->cq; + initattr.recv_cq = ctx->cq; + initattr.cap.max_send_wr = tx_depth; + /* Work around: driver doesnt support + * recv_wr = 0 */ + initattr.cap.max_recv_wr = 1; + initattr.cap.max_send_sge = 1; + initattr.cap.max_recv_sge = 1; + initattr.cap.max_inline_data = user_parm->inline_size; + + if (user_parm->connection_type == 1) { + initattr.qp_type = IBV_QPT_UC; + } else { + initattr.qp_type = IBV_QPT_RC; + } + ctx->qp[counter] = ibv_create_qp(ctx->pd, &initattr); + if (!ctx->qp[counter]) { + fprintf(stderr, "Couldn't create QP\n"); + return NULL; + } + + attr.qp_state = IBV_QPS_INIT; + attr.pkey_index = 0; + attr.port_num = (uint8_t) port; + attr.qp_access_flags = IBV_ACCESS_REMOTE_WRITE; + + if (ibv_modify_qp(ctx->qp[counter], &attr, + IBV_QP_STATE | + IBV_QP_PKEY_INDEX | + IBV_QP_PORT | + IBV_QP_ACCESS_FLAGS)) { + fprintf(stderr, "Failed to modify QP to INIT\n"); + return NULL; + } + } + + return ctx; +} + +static int pp_connect_ctx(struct pingpong_context *ctx, int port, int my_psn, + struct pingpong_dest *dest, struct user_parameters *user_parm, int qpindex) +{ + struct ibv_qp_attr attr; + memset(&attr, 0, sizeof attr); + + attr.qp_state = IBV_QPS_RTR; + switch (user_parm->mtu) { + case 256 : + attr.path_mtu = IBV_MTU_256; + break; + case 512 : + attr.path_mtu = IBV_MTU_512; + break; + case 1024 : + attr.path_mtu = IBV_MTU_1024; + break; + case 2048 : + attr.path_mtu = IBV_MTU_2048; + break; + case 4096 : + attr.path_mtu = IBV_MTU_4096; + break; + } + printf("Mtu : %d\n", user_parm->mtu); + attr.dest_qp_num = dest->qpn; + attr.rq_psn = dest->psn; + if (user_parm->connection_type==RC) { + attr.max_dest_rd_atomic = 1; + attr.min_rnr_timer = 12; + } + attr.ah_attr.is_global = 0; + attr.ah_attr.dlid = (uint16_t) dest->lid; + attr.ah_attr.sl = 0; + attr.ah_attr.src_path_bits = 0; + attr.ah_attr.port_num = (uint8_t) port; + if (user_parm->connection_type == RC) { + if (ibv_modify_qp(ctx->qp[qpindex], &attr, + IBV_QP_STATE | + IBV_QP_AV | + IBV_QP_PATH_MTU | + IBV_QP_DEST_QPN | + IBV_QP_RQ_PSN | + IBV_QP_MIN_RNR_TIMER | + IBV_QP_MAX_DEST_RD_ATOMIC)) { + fprintf(stderr, "Failed to modify RC QP to RTR\n"); + return 1; + } + attr.timeout = 14; + attr.retry_cnt = 7; + attr.rnr_retry = 7; + } else { + if (ibv_modify_qp(ctx->qp[qpindex], &attr, + IBV_QP_STATE | + IBV_QP_AV | + IBV_QP_PATH_MTU | + IBV_QP_DEST_QPN | + IBV_QP_RQ_PSN)) { + fprintf(stderr, "Failed to modify UC QP to RTR\n"); + return 1; + } + + } + attr.qp_state = IBV_QPS_RTS; + attr.sq_psn = my_psn; + attr.max_rd_atomic = 1; + if (user_parm->connection_type == 0) { + attr.max_rd_atomic = 1; + if (ibv_modify_qp(ctx->qp[qpindex], &attr, + IBV_QP_STATE | + IBV_QP_SQ_PSN | + IBV_QP_TIMEOUT | + IBV_QP_RETRY_CNT | + IBV_QP_RNR_RETRY | + IBV_QP_MAX_QP_RD_ATOMIC)) { + fprintf(stderr, "Failed to modify RC QP to RTS\n"); + return 1; + } + } else { + if (ibv_modify_qp(ctx->qp[qpindex], &attr, + IBV_QP_STATE | + IBV_QP_SQ_PSN)) { + fprintf(stderr, "Failed to modify UC QP to RTS\n"); + return 1; + } + + } + return 0; +} + +static void usage(const char *argv0) +{ + printf("Usage:\n"); + printf(" %s start a server and wait for connection\n", argv0); + printf(" %s -h connect to server at \n", argv0); + printf("\n"); + printf("Options:\n"); + printf(" -p listen on/connect to port (default 18515)\n"); + printf(" -d use IB device (default first device found)\n"); + printf(" -i use port of IB device (default 1)\n"); + printf(" -c connection type RC/UC (default RC)\n"); + printf(" -m mtu size (256 - 4096. default for hermon is 2048)\n"); + printf(" -g number of posts for each qp in the chain (default tx_depth)\n"); + printf(" -q Num of qp's(default 1)\n"); + printf(" -s size of message to exchange (default 65536)\n"); + printf(" -a Run sizes from 2 till 2^23\n"); + printf(" -t size of tx queue (default 100)\n"); + printf(" -n number of exchanges (at least 2, default 5000)\n"); + printf(" -I max size of message to be sent in inline mode (default 400)\n"); + printf(" -b measure bidirectional bandwidth (default unidirectional)\n"); + printf(" -V display version number\n"); + printf(" -N cancel peak-bw calculation (default with peak-bw)\n"); +} + +static void print_report(unsigned int iters, unsigned size, int duplex, + cycles_t *tposted, cycles_t *tcompleted, struct user_parameters *user_param, + int noPeak) +{ + cycles_t cycles_to_units; + unsigned long tsize; /* Transferred size */ + int i, j; + int opt_posted = 0, opt_completed = 0; + cycles_t opt_delta; + cycles_t t; + + opt_delta = tcompleted[opt_posted] - tposted[opt_completed]; + + if (!noPeak) { + /* Find the peak bandwidth, unless asked not to in command line */ + for (i = 0; i < (int) iters; ++i) + for (j = i; j < (int) iters; ++j) { + t = (tcompleted[j] - tposted[i]) / (j - i + 1); + if (t < opt_delta) { + opt_delta = t; + opt_posted = i; + opt_completed = j; + } + } + } + + cycles_to_units = get_freq(); + + tsize = duplex ? 2 : 1; + tsize = tsize * size; + printf("%7d %d ", size, iters); + + { + double sec = (double) opt_delta / (double) cycles_to_units; + double mbytes = (double) !(noPeak) * (double) tsize / (double) 0x100000; + printf("%7.2f ", mbytes / sec); + + sec = (double) (tcompleted[iters - 1] - tposted[0]) / (double) cycles_to_units; + mbytes = (double) tsize * (double) iters / (double) 0x100000; + printf("%7.2f\n", mbytes / sec); + } +} + +static int run_iter(struct pingpong_context *ctx, struct user_parameters *user_param, + struct pingpong_dest **rem_dest, int size) +{ + struct ibv_qp *qp; + int totscnt, totccnt ; + int index ,warmindex; + int inline_size; + struct ibv_send_wr *bad_wr; + struct ibv_wc wc; + ctx->list.addr = (uintptr_t) ctx->buf; + ctx->list.length = size; + ctx->list.lkey = ctx->mr->lkey; + + ctx->wr.sg_list = &ctx->list; + ctx->wr.num_sge = 1; + ctx->wr.opcode = IBV_WR_RDMA_WRITE; + inline_size = user_param->inline_size; + if (size > inline_size) {/* complaince to perf_main */ + ctx->wr.send_flags = IBV_SEND_SIGNALED; + } else { + ctx->wr.send_flags = IBV_SEND_SIGNALED | IBV_SEND_INLINE; + } + ctx->wr.next = NULL; + + totscnt = 0; + totccnt = 0; + /*clear the scnt ccnt counters for each iteration*/ + for (index =0 ; index < user_param->numofqps ; index++) { + ctx->scnt[index] = 0; + ctx->ccnt[index] = 0; + } + index = 0; + + /* Done with setup. Start the test. + warm up posting of total 100 wq's per qp + 1 for each qp till all qps have 100 */ + for (warmindex =0 ;warmindex < user_param->maxpostsofqpiniteration ;warmindex ++ ) { + for (index =0 ; index < user_param->numofqps ; index++) { + ctx->wr.wr.rdma.remote_addr = rem_dest[index]->vaddr; + ctx->wr.wr.rdma.rkey = rem_dest[index]->rkey; + qp = ctx->qp[index]; + ctx->wr.wr_id = index; + if (user_param->servername) + tposted[totscnt] = get_cycles(); + if (ibv_post_send(qp, &ctx->wr, &bad_wr)) { + fprintf(stderr, "Couldn't post warmup send: qp index = %d qp scnt=%d total scnt %d\n", + index,ctx->scnt[index],totscnt); + return 1; + } + ctx->scnt[index]= ctx->scnt[index]+1; + ++totscnt; + } + } + + /* main loop for posting */ + while (totscnt < (user_param->iters * user_param->numofqps) || + totccnt < (user_param->iters * user_param->numofqps) ) { + /* main loop to run over all the qps and post each time n messages */ + for (index =0 ; index < user_param->numofqps ; index++) { + ctx->wr.wr.rdma.remote_addr = rem_dest[index]->vaddr; + ctx->wr.wr.rdma.rkey = rem_dest[index]->rkey; + qp = ctx->qp[index]; + ctx->wr.wr_id = index; + + while (ctx->scnt[index] < user_param->iters && + (ctx->scnt[index] - ctx->ccnt[index]) < user_param->maxpostsofqpiniteration) { + if (user_param->servername) + tposted[totscnt] = get_cycles(); + if (ibv_post_send(qp, &ctx->wr, &bad_wr)) { + fprintf(stderr, "Couldn't post send: qp index = %d qp scnt=%d total scnt %d\n", + index,ctx->scnt[index],totscnt); + return 1; + } + ctx->scnt[index]= ctx->scnt[index]+1; + ++totscnt; + } + } + + /* finished posting now polling */ + if (totccnt < (user_param->iters * user_param->numofqps) ) { + int ne; + do { + ne = ibv_poll_cq(ctx->cq, 1, &wc); + } while (ne == 0); + + if (user_param->servername) + tcompleted[totccnt] = get_cycles(); + + if (ne < 0) { + fprintf(stderr, "poll CQ failed %d\n", ne); + return 1; + } + + if (wc.status != IBV_WC_SUCCESS) { + fprintf(stderr, "Completion wth error at %s:\n", + user_param->servername ? "client" : "server"); + fprintf(stderr, "Failed status %d: wr_id %d\n", + wc.status, (int) wc.wr_id); + fprintf(stderr, "qp index %d ,qp scnt=%d, qp ccnt=%d total scnt %d total ccnt %d\n", + (int)wc.wr_id, ctx->scnt[(int)wc.wr_id], ctx->ccnt[(int)wc.wr_id], totscnt, totccnt); + return 1; + } + /*here the id is the index to the qp num */ + ctx->ccnt[(int)wc.wr_id] = ctx->ccnt[(int)wc.wr_id]+1; + totccnt += 1; + } + } + return(0); +} + +int __cdecl main(int argc, char *argv[]) +{ + struct ibv_device **dev_list; + struct ibv_device *ib_dev; + struct pingpong_context *ctx; + struct pingpong_dest *my_dest; + struct pingpong_dest **rem_dest; + struct user_parameters user_param; + struct ibv_device_attr device_attribute; + char *ib_devname = NULL; + int port = 18515; + int ib_port = 1; + int size = 65536; + SOCKET sockfd; + int duplex = 0; + int i = 0; + int noPeak = 0;/*noPeak == 0: regular peak-bw calculation done*/ + int inline_given_in_cmd = 0; + struct ibv_context *context; + WORD version; + WSADATA data; + int err; + + srand((unsigned int) time(NULL)); + version = MAKEWORD(2, 2); + err = WSAStartup(version, &data); + if (err) + return -1; + + /* init default values to user's parameters */ + memset(&user_param, 0, sizeof(struct user_parameters)); + user_param.mtu = 0; + user_param.iters = 5000; + user_param.tx_depth = 100; + user_param.servername = NULL; + user_param.numofqps = 1; + user_param.maxpostsofqpiniteration = 100; + user_param.inline_size = MAX_INLINE; + + /* Parameter parsing. */ + while (1) { + int c; + + c = getopt(argc, argv, "h:p:d:i:m:q:g:c:s:n:t:I:baVN"); + if (c == -1) + break; + + switch (c) { + case 'p': + port = strtol(optarg, NULL, 0); + if (port < 0 || port > 65535) { + usage(argv[0]); + return 1; + } + break; + + case 'd': + ib_devname = _strdup(optarg); + break; + case 'c': + if (strcmp("UC",optarg)==0) + user_param.connection_type=UC; + break; + + case 'm': + user_param.mtu = strtol(optarg, NULL, 0); + break; + case 'q': + user_param.numofqps = strtol(optarg, NULL, 0); + break; + case 'g': + user_param.maxpostsofqpiniteration = strtol(optarg, NULL, 0); + break; + case 'a': + user_param.all = ALL; + break; + case 'V': + printf("rdma_bw version : %.2f\n",VERSION); + return 0; + case 'i': + ib_port = strtol(optarg, NULL, 0); + if (ib_port < 0) { + usage(argv[0]); + return 1; + } + break; + + case 's': + size = strtol(optarg, NULL, 0); + break; + + case 't': + user_param.tx_depth = strtol(optarg, NULL, 0); + if (user_param.tx_depth < 1) { usage(argv[0]); return 1; } + break; + + case 'I': + user_param.inline_size = strtol(optarg, NULL, 0); + inline_given_in_cmd =1; + if (user_param.inline_size > MAX_INLINE) { + usage(argv[0]); + return 7; + } + break; + + case 'n': + user_param.iters = strtol(optarg, NULL, 0); + if (user_param.iters < 2) { + usage(argv[0]); + return 1; + } + break; + + case 'b': + duplex = 1; + break; + + case 'N': + noPeak = 1; + break; + + case 'h': + if (optarg) { + user_param.servername = _strdup(optarg); + break; + } + + default: + usage(argv[0]); + return 1; + } + } + + printf("------------------------------------------------------------------\n"); + if (duplex == 1) { + printf(" RDMA_Write Bidirectional BW Test\n"); + } else { + printf(" RDMA_Write BW Test\n"); + } + + printf("Number of qp's running %d\n",user_param.numofqps); + if (user_param.connection_type==RC) { + printf("Connection type : RC\n"); + } else { + printf("Connection type : UC\n"); + } + if (user_param.maxpostsofqpiniteration > user_param.tx_depth ) { + printf("Can not post more than tx_depth , adjusting number of post to tx_depth\n"); + user_param.maxpostsofqpiniteration = user_param.tx_depth; + } + if (user_param.maxpostsofqpiniteration > user_param.iters ) { + printf("Can not post more than iterations per qp , adjusting max number of post to num of iteration\n"); + user_param.maxpostsofqpiniteration = user_param.iters; + } + printf("Each Qp will post up to %d messages each time\n",user_param.maxpostsofqpiniteration); + /* Done with parameter parsing. Perform setup. */ + if (user_param.all == ALL) { + /*since we run all sizes */ + size = 8388608; /*2^23 */ + } + + dev_list = ibv_get_device_list(NULL); + + if (!ib_devname) { + ib_dev = dev_list[0]; + if (!ib_dev) { + fprintf(stderr, "No IB devices found\n"); + return 1; + } + } else { + for (; (ib_dev = *dev_list); ++dev_list) + if (!strcmp(ibv_get_device_name(ib_dev), ib_devname)) + break; + if (!ib_dev) { + fprintf(stderr, "IB device %s not found\n", ib_devname); + return 1; + } + } + + context = ibv_open_device(ib_dev); + if (ibv_query_device(context, &device_attribute)) { + fprintf(stderr, "Failed to query device props"); + return 1; + } + if ((device_attribute.vendor_part_id == 25418) && (!inline_given_in_cmd)) { + user_param.inline_size = 1; + } + printf("Inline data is used up to %d bytes message\n", user_param.inline_size); + + ctx = pp_init_ctx(ib_dev, size, user_param.tx_depth, ib_port, &user_param); + if (!ctx) + return 1; + + + if (user_param.servername) { + sockfd = pp_client_connect(user_param.servername, port); + if (sockfd == INVALID_SOCKET) + return 1; + } else { + sockfd = pp_server_connect(port); + if (sockfd == INVALID_SOCKET) + return 1; + } + + my_dest = malloc(user_param.numofqps * sizeof *my_dest); + if (!my_dest) { + perror("malloc my_dest"); + return 1; + } + rem_dest = malloc(sizeof (struct pingpong_dest*) * user_param.numofqps ); + if (!rem_dest ) { + perror("malloc rem_dest"); + return 1; + } + + for (i =0 ;iqp[i]->qp_num; + /* TBD this should be changed inot VA and different key to each qp */ + my_dest[i].rkey = ctx->mr->rkey; + my_dest[i].vaddr = (uintptr_t)ctx->buf + ctx->size; + + printf(" local address: LID %#04x, QPN %#06x, PSN %#06x " + "RKey %#08x VAddr %#016Lx\n", + my_dest[i].lid, my_dest[i].qpn, my_dest[i].psn, + my_dest[i].rkey, my_dest[i].vaddr); + if (user_param.servername) { + rem_dest[i] = pp_client_exch_dest(sockfd, &my_dest[i]); + } else { + rem_dest[i] = pp_server_exch_dest(sockfd, &my_dest[i]); + } + if (!rem_dest[i]) + return 1; + printf(" remote address: LID %#04x, QPN %#06x, PSN %#06x, " + "RKey %#08x VAddr %#016Lx\n", + rem_dest[i]->lid, rem_dest[i]->qpn, rem_dest[i]->psn, + rem_dest[i]->rkey, rem_dest[i]->vaddr); + if (pp_connect_ctx(ctx, ib_port, my_dest[i].psn, rem_dest[i], &user_param, i)) + return 1; + + /* An additional handshake is required *after* moving qp to RTR. + Arbitrarily reuse exch_dest for this purpose. */ + if (user_param.servername) { + rem_dest[i] = pp_client_exch_dest(sockfd, &my_dest[i]); + } else { + rem_dest[i] = pp_server_exch_dest(sockfd, &my_dest[i]); + } + } + + printf("------------------------------------------------------------------\n"); + printf(" #bytes #iterations BW peak[MB/sec] BW average[MB/sec] \n"); + /* For half duplex tests, server just waits for client to exit */ + /* the 0th place is arbitrary to signal finish ... */ + if (!user_param.servername && !duplex) { + rem_dest[0] = pp_server_exch_dest(sockfd, &my_dest[0]); + if (send(sockfd, "done", sizeof "done", 0) != sizeof "done"){ + perror("server write"); + fprintf(stderr, "Couldn't write to socket\n"); + return 1; + } + closesocket(sockfd); + return 0; + } + + tposted = malloc(user_param.iters * user_param.numofqps * sizeof *tposted); + + if (!tposted) { + perror("malloc"); + return 1; + } + + tcompleted = malloc(user_param.iters * user_param.numofqps * sizeof *tcompleted); + + if (!tcompleted) { + perror("malloc"); + return 1; + } + + if (user_param.all == ALL) { + for (i = 1; i < 24 ; ++i) { + size = 1 << i; + if(run_iter(ctx, &user_param, rem_dest, size)) + return 17; + print_report(user_param.iters, size, duplex, tposted, tcompleted, &user_param, noPeak); + } + } else { + if(run_iter(ctx, &user_param, rem_dest, size)) + return 18; + print_report(user_param.iters, size, duplex, tposted, tcompleted, &user_param, noPeak); + } + /* the 0th place is arbitrary to signal finish ... */ + if (user_param.servername) { + rem_dest[0] = pp_client_exch_dest(sockfd, &my_dest[0]); + } else { + rem_dest[0] = pp_server_exch_dest(sockfd, &my_dest[0]); + } + + if (send(sockfd, "done", sizeof "done", 0) != sizeof "done"){ + perror("write"); + fprintf(stderr, "Couldn't write to socket\n"); + return 1; + } + closesocket(sockfd); + + free(tposted); + free(tcompleted); + + printf("------------------------------------------------------------------\n"); + return 0; +} diff --git a/branches/WOF2-3/tests/perftest/write_bw/write_bw.rc b/branches/WOF2-3/tests/perftest/write_bw/write_bw.rc new file mode 100644 index 00000000..fc997c6a --- /dev/null +++ b/branches/WOF2-3/tests/perftest/write_bw/write_bw.rc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: write_bw.rc 474 2006-08-31 08:57:19Z sleybo $ + */ + + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef DBG +#define VER_FILEDESCRIPTION_STR "winverbs - RDMA write Bandwidth Test (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "winverbs - RDMA write Bandwidth Test " +#endif + +#define VER_INTERNALNAME_STR "ibv_write_bw.exe" +#define VER_ORIGINALFILENAME_STR "ibv_write_bw.exe" + +#include diff --git a/branches/WOF2-3/tests/perftest/write_bw_postlist/SOURCES b/branches/WOF2-3/tests/perftest/write_bw_postlist/SOURCES new file mode 100644 index 00000000..c31e7564 --- /dev/null +++ b/branches/WOF2-3/tests/perftest/write_bw_postlist/SOURCES @@ -0,0 +1,30 @@ +TARGETNAME = ibv_write_bw_postlist +TARGETPATH = ..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = PROGRAM + +UMTYPE = console +UMENTRY = main + +USE_MSVCRT = 1 +USE_STL = 1 +USE_NATIVE_EH = 1 +USE_IOSTREAM = 1 + +SOURCES = \ + write_bw_postlist.rc \ + write_bw_postlist.c + +INCLUDES = ..\..\..\ulp\libibverbs\include;..\..\..\inc;..\..\..\inc\user; + +TARGETLIBS = \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\advapi32.lib \ + $(SDK_LIB_PATH)\user32.lib \ + $(SDK_LIB_PATH)\ole32.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\libibverbs.lib +!else + $(TARGETPATH)\*\libibverbsd.lib +!endif + diff --git a/branches/WOF2-3/tests/perftest/write_bw_postlist/makefile b/branches/WOF2-3/tests/perftest/write_bw_postlist/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-3/tests/perftest/write_bw_postlist/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\inc\openib.def diff --git a/branches/WOF2-3/tests/perftest/write_bw_postlist/write_bw_postlist.c b/branches/WOF2-3/tests/perftest/write_bw_postlist/write_bw_postlist.c new file mode 100644 index 00000000..d80a7a5b --- /dev/null +++ b/branches/WOF2-3/tests/perftest/write_bw_postlist/write_bw_postlist.c @@ -0,0 +1,987 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies Ltd. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "get_clock.h" + +#define PINGPONG_RDMA_WRID 3 +#define VERSION 1.0 +#define ALL 1 +#define MAX_INLINE 400 +#define RC 0 +#define UC 1 + +struct user_parameters { + const char *servername; + int connection_type; + int mtu; + int all; /* run all msg size */ + int iters; + int tx_depth; + int numofqps; + int maxpostsofqpiniteration; + int inline_size; +}; +struct extended_qp { + struct ibv_qp *qp; + int scnt, ccnt ; +}; +static int page_size; + +cycles_t *tposted; +cycles_t *tcompleted; +struct pingpong_context { + struct ibv_context *context; + struct ibv_pd *pd; + struct ibv_mr *mr; + struct ibv_cq *cq; + struct ibv_qp **qp; + void *buf; + unsigned size; + int tx_depth; + struct ibv_sge list; + struct ibv_send_wr wr; + int *scnt; + int *ccnt ; +}; + +struct pingpong_dest { + int lid; + int qpn; + int psn; + unsigned rkey; + unsigned long long vaddr; +}; + + +static uint16_t pp_get_local_lid(struct pingpong_context *ctx, int port) +{ + struct ibv_port_attr attr; + + if (ibv_query_port(ctx->context, port, &attr)) + return 0; + + return attr.lid; +} + +static int pp_client_connect(const char *servername, int port) +{ + struct addrinfo *res, *t; + struct addrinfo hints = { + .ai_family = AF_UNSPEC, + .ai_socktype = SOCK_STREAM + }; + char *service; + int n; + int sockfd = -1; + + if (asprintf(&service, "%d", port) < 0) + return -1; + + n = getaddrinfo(servername, service, &hints, &res); + + if (n < 0) { + fprintf(stderr, "%s for %s:%d\n", gai_strerror(n), servername, port); + return n; + } + + for (t = res; t; t = t->ai_next) { + sockfd = socket(t->ai_family, t->ai_socktype, t->ai_protocol); + if (sockfd >= 0) { + if (!connect(sockfd, t->ai_addr, t->ai_addrlen)) + break; + close(sockfd); + sockfd = -1; + } + } + + freeaddrinfo(res); + + if (sockfd < 0) { + fprintf(stderr, "Couldn't connect to %s:%d\n", servername, port); + return sockfd; + } + return sockfd; +} + +struct pingpong_dest * pp_client_exch_dest(int sockfd, + const struct pingpong_dest *my_dest) +{ + struct pingpong_dest *rem_dest = NULL; + char msg[sizeof "0000:000000:000000:00000000:0000000000000000"]; + int parsed; + + sprintf(msg, "%04x:%06x:%06x:%08x:%016Lx", my_dest->lid, my_dest->qpn, + my_dest->psn,my_dest->rkey,my_dest->vaddr); + if (write(sockfd, msg, sizeof msg) != sizeof msg) { + perror("client write"); + fprintf(stderr, "Couldn't send local address\n"); + goto out; + } + + if (read(sockfd, msg, sizeof msg) != sizeof msg) { + perror("client read"); + fprintf(stderr, "Couldn't read remote address\n"); + goto out; + } + + rem_dest = malloc(sizeof *rem_dest); + if (!rem_dest) + goto out; + + parsed = sscanf(msg, "%x:%x:%x:%x:%Lx", &rem_dest->lid, &rem_dest->qpn, + &rem_dest->psn,&rem_dest->rkey,&rem_dest->vaddr); + + if (parsed != 5) { + fprintf(stderr, "Couldn't parse line <%.*s>\n",(int)sizeof msg, + msg); + free(rem_dest); + rem_dest = NULL; + goto out; + } +out: + return rem_dest; +} + +int pp_server_connect(int port) +{ + struct addrinfo *res, *t; + struct addrinfo hints = { + .ai_flags = AI_PASSIVE, + .ai_family = AF_UNSPEC, + .ai_socktype = SOCK_STREAM + }; + char *service; + int sockfd = -1, connfd; + int n; + + if (asprintf(&service, "%d", port) < 0) + return -1; + + n = getaddrinfo(NULL, service, &hints, &res); + + if (n < 0) { + fprintf(stderr, "%s for port %d\n", gai_strerror(n), port); + return n; + } + + for (t = res; t; t = t->ai_next) { + sockfd = socket(t->ai_family, t->ai_socktype, t->ai_protocol); + if (sockfd >= 0) { + n = 1; + + setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &n, sizeof n); + + if (!bind(sockfd, t->ai_addr, t->ai_addrlen)) + break; + close(sockfd); + sockfd = -1; + } + } + + freeaddrinfo(res); + + if (sockfd < 0) { + fprintf(stderr, "Couldn't listen to port %d\n", port); + return sockfd; + } + + listen(sockfd, 1); + connfd = accept(sockfd, NULL, 0); + if (connfd < 0) { + perror("server accept"); + fprintf(stderr, "accept() failed\n"); + close(sockfd); + return connfd; + } + + close(sockfd); + return connfd; +} + +static struct pingpong_dest *pp_server_exch_dest(int connfd, const struct pingpong_dest *my_dest) +{ + char msg[sizeof "0000:000000:000000:00000000:0000000000000000"]; + struct pingpong_dest *rem_dest = NULL; + int parsed; + int n; + + n = read(connfd, msg, sizeof msg); + if (n != sizeof msg) { + perror("server read"); + fprintf(stderr, "%d/%d: Couldn't read remote address\n", n, (int) sizeof msg); + goto out; + } + + rem_dest = malloc(sizeof *rem_dest); + if (!rem_dest) + goto out; + + parsed = sscanf(msg, "%x:%x:%x:%x:%Lx", &rem_dest->lid, &rem_dest->qpn, + &rem_dest->psn, &rem_dest->rkey, &rem_dest->vaddr); + if (parsed != 5) { + fprintf(stderr, "Couldn't parse line <%.*s>\n",(int)sizeof msg, + msg); + free(rem_dest); + rem_dest = NULL; + goto out; + } + + sprintf(msg, "%04x:%06x:%06x:%08x:%016Lx", my_dest->lid, my_dest->qpn, + my_dest->psn, my_dest->rkey, my_dest->vaddr); + if (write(connfd, msg, sizeof msg) != sizeof msg) { + perror("server write"); + fprintf(stderr, "Couldn't send local address\n"); + free(rem_dest); + rem_dest = NULL; + goto out; + } +out: + return rem_dest; +} + +static struct pingpong_context *pp_init_ctx(struct ibv_device *ib_dev, + unsigned size, + int tx_depth, int port, struct user_parameters *user_parm) +{ + struct pingpong_context *ctx; + struct ibv_device_attr device_attr; + int counter; + + ctx = malloc(sizeof *ctx); + if (!ctx) + return NULL; + ctx->qp = malloc(sizeof (struct ibv_qp*) * user_parm->numofqps ); + ctx->size = size; + ctx->tx_depth = tx_depth; + ctx->scnt = malloc(user_parm->numofqps * sizeof (int)); + if (!ctx->scnt) { + perror("malloc"); + return NULL; + } + ctx->ccnt = malloc(user_parm->numofqps * sizeof (int)); + if (!ctx->ccnt) { + perror("malloc"); + return NULL; + } + memset(ctx->scnt, 0, user_parm->numofqps * sizeof (int)); + memset(ctx->ccnt, 0, user_parm->numofqps * sizeof (int)); + + ctx->buf = memalign(page_size, size * 2 * user_parm->numofqps ); + if (!ctx->buf) { + fprintf(stderr, "Couldn't allocate work buf.\n"); + return NULL; + } + + memset(ctx->buf, 0, size * 2 * user_parm->numofqps); + + ctx->context = ibv_open_device(ib_dev); + if (!ctx->context) { + fprintf(stderr, "Couldn't get context for %s\n", + ibv_get_device_name(ib_dev)); + return NULL; + } + if (user_parm->mtu == 0) {/*user did not ask for specific mtu */ + if (ibv_query_device(ctx->context, &device_attr)) { + fprintf(stderr, "Failed to query device props"); + return NULL; + } + if (device_attr.vendor_part_id == 23108) { + user_parm->mtu = 1024; + } else { + user_parm->mtu = 2048; + } + } + + ctx->pd = ibv_alloc_pd(ctx->context); + if (!ctx->pd) { + fprintf(stderr, "Couldn't allocate PD\n"); + return NULL; + } + + /* We dont really want IBV_ACCESS_LOCAL_WRITE, but IB spec says: + * The Consumer is not allowed to assign Remote Write or Remote Atomic to + * a Memory Region that has not been assigned Local Write. */ + ctx->mr = ibv_reg_mr(ctx->pd, ctx->buf, size * 2 * user_parm->numofqps, + IBV_ACCESS_REMOTE_WRITE | IBV_ACCESS_LOCAL_WRITE); + if (!ctx->mr) { + fprintf(stderr, "Couldn't allocate MR\n"); + return NULL; + } + + ctx->cq = ibv_create_cq(ctx->context, tx_depth * user_parm->numofqps , NULL, NULL, 0); + if (!ctx->cq) { + fprintf(stderr, "Couldn't create CQ\n"); + return NULL; + } + for (counter =0 ; counter < user_parm->numofqps ; counter++) + { + struct ibv_qp_init_attr initattr; + struct ibv_qp_attr attr; + memset(&initattr, 0, sizeof(struct ibv_qp_init_attr)); + initattr.send_cq = ctx->cq; + initattr.recv_cq = ctx->cq; + initattr.cap.max_send_wr = tx_depth; + /* Work around: driver doesnt support + * recv_wr = 0 */ + initattr.cap.max_recv_wr = 1; + initattr.cap.max_send_sge = 1; + initattr.cap.max_recv_sge = 1; + initattr.cap.max_inline_data = user_parm->inline_size; + + if (user_parm->connection_type == 1) { + initattr.qp_type = IBV_QPT_UC; + } else { + initattr.qp_type = IBV_QPT_RC; + } + ctx->qp[counter] = ibv_create_qp(ctx->pd, &initattr); + if (!ctx->qp[counter]) { + fprintf(stderr, "Couldn't create QP\n"); + return NULL; + } + + attr.qp_state = IBV_QPS_INIT; + attr.pkey_index = 0; + attr.port_num = port; + attr.qp_access_flags = IBV_ACCESS_REMOTE_WRITE; + + if (ibv_modify_qp(ctx->qp[counter], &attr, + IBV_QP_STATE | + IBV_QP_PKEY_INDEX | + IBV_QP_PORT | + IBV_QP_ACCESS_FLAGS)) { + fprintf(stderr, "Failed to modify QP to INIT\n"); + return NULL; + } + } + + return ctx; +} + +static int pp_connect_ctx(struct pingpong_context *ctx, int port, int my_psn, + struct pingpong_dest *dest, struct user_parameters *user_parm, int qpindex) +{ + struct ibv_qp_attr attr; + memset(&attr, 0, sizeof attr); + + attr.qp_state = IBV_QPS_RTR; + switch (user_parm->mtu) { + case 256 : + attr.path_mtu = IBV_MTU_256; + break; + case 512 : + attr.path_mtu = IBV_MTU_512; + break; + case 1024 : + attr.path_mtu = IBV_MTU_1024; + break; + case 2048 : + attr.path_mtu = IBV_MTU_2048; + break; + case 4096 : + attr.path_mtu = IBV_MTU_4096; + break; + } + printf("Mtu : %d\n", user_parm->mtu); + attr.dest_qp_num = dest->qpn; + attr.rq_psn = dest->psn; + if (user_parm->connection_type==RC) { + attr.max_dest_rd_atomic = 1; + attr.min_rnr_timer = 12; + } + attr.ah_attr.is_global = 0; + attr.ah_attr.dlid = dest->lid; + attr.ah_attr.sl = 0; + attr.ah_attr.src_path_bits = 0; + attr.ah_attr.port_num = port; + if (user_parm->connection_type == RC) { + if (ibv_modify_qp(ctx->qp[qpindex], &attr, + IBV_QP_STATE | + IBV_QP_AV | + IBV_QP_PATH_MTU | + IBV_QP_DEST_QPN | + IBV_QP_RQ_PSN | + IBV_QP_MIN_RNR_TIMER | + IBV_QP_MAX_DEST_RD_ATOMIC)) { + fprintf(stderr, "Failed to modify RC QP to RTR\n"); + return 1; + } + attr.timeout = 14; + attr.retry_cnt = 7; + attr.rnr_retry = 7; + } else { + if (ibv_modify_qp(ctx->qp[qpindex], &attr, + IBV_QP_STATE | + IBV_QP_AV | + IBV_QP_PATH_MTU | + IBV_QP_DEST_QPN | + IBV_QP_RQ_PSN)) { + fprintf(stderr, "Failed to modify UC QP to RTR\n"); + return 1; + } + + } + attr.qp_state = IBV_QPS_RTS; + attr.sq_psn = my_psn; + attr.max_rd_atomic = 1; + if (user_parm->connection_type == 0) { + attr.max_rd_atomic = 1; + if (ibv_modify_qp(ctx->qp[qpindex], &attr, + IBV_QP_STATE | + IBV_QP_SQ_PSN | + IBV_QP_TIMEOUT | + IBV_QP_RETRY_CNT | + IBV_QP_RNR_RETRY | + IBV_QP_MAX_QP_RD_ATOMIC)) { + fprintf(stderr, "Failed to modify RC QP to RTS\n"); + return 1; + } + } else { + if (ibv_modify_qp(ctx->qp[qpindex], &attr, + IBV_QP_STATE | + IBV_QP_SQ_PSN)) { + fprintf(stderr, "Failed to modify UC QP to RTS\n"); + return 1; + } + + } + return 0; +} + +static void usage(const char *argv0) +{ + printf("Usage:\n"); + printf(" %s start a server and wait for connection\n", argv0); + printf(" %s connect to server at \n", argv0); + printf("\n"); + printf("Options:\n"); + printf(" -p, --port= listen on/connect to port (default 18515)\n"); + printf(" -d, --ib-dev= use IB device (default first device found)\n"); + printf(" -i, --ib-port= use port of IB device (default 1)\n"); + printf(" -c, --connection= connection type RC/UC (default RC)\n"); + printf(" -m, --mtu= mtu size (256 - 4096. default for hermon is 2048)\n"); + printf(" -g, --post= number of posts for each qp in the chain (default tx_depth)\n"); + printf(" -q, --qp= Num of qp's(default 1)\n"); + printf(" -s, --size= size of message to exchange (default 65536)\n"); + printf(" -a, --all Run sizes from 2 till 2^23\n"); + printf(" -t, --tx-depth= size of tx queue (default 100)\n"); + printf(" -n, --iters= number of exchanges (at least 2, default 5000)\n"); + printf(" -I, --inline_size= max size of message to be sent in inline mode (default 400)\n"); + printf(" -b, --bidirectional measure bidirectional bandwidth (default unidirectional)\n"); + printf(" -V, --version display version number\n"); +} + +static void print_report(unsigned int iters, unsigned size, int duplex, + cycles_t *tposted, cycles_t *tcompleted, struct user_parameters *user_param) +{ + double cycles_to_units; + unsigned long tsize; /* Transferred size, in megabytes */ + int i, j; + int opt_posted = 0, opt_completed = 0; + cycles_t opt_delta; + cycles_t t; + + + opt_delta = tcompleted[opt_posted] - tposted[opt_completed]; + + /* Find the peak bandwidth */ + for (i = 0; i < iters * user_param->numofqps; ++i) + for (j = i; j < iters * user_param->numofqps; ++j) { + t = (tcompleted[j] - tposted[i]) / (j - i + 1); + if (t < opt_delta) { + opt_delta = t; + opt_posted = i; + opt_completed = j; + } + } + + cycles_to_units = get_cpu_mhz() * 1000000; + + tsize = duplex ? 2 : 1; + tsize = tsize * size; + printf("%7d %d %7.2f %7.2f\n", + size,iters,tsize * cycles_to_units / opt_delta / 0x100000, + tsize * iters * user_param->numofqps * cycles_to_units /(tcompleted[(iters* user_param->numofqps) - 1] - tposted[0]) / 0x100000); +} +int run_iter(struct pingpong_context *ctx, struct user_parameters *user_param, + struct pingpong_dest **rem_dest, int size) +{ + struct ibv_qp *qp; + int totscnt, totccnt ; + int index , qpindex; + int numpostperqp ; + struct ibv_send_wr *wrlist; + struct ibv_send_wr *bad_wr; + struct ibv_wc wc; + + wrlist = malloc(user_param->numofqps * sizeof (struct ibv_send_wr) * user_param->tx_depth); + if (!wrlist) { + perror("malloc"); + return -1; + } + ctx->list.addr = (uintptr_t) ctx->buf; + ctx->list.length = size; + ctx->list.lkey = ctx->mr->lkey; + + /* prepare the wqe */ + ctx->wr.sg_list = &ctx->list; + ctx->wr.num_sge = 1; + ctx->wr.opcode = IBV_WR_RDMA_WRITE; + if (size > user_param->inline_size) {/* complaince to perf_main */ + ctx->wr.send_flags = IBV_SEND_SIGNALED; + } else { + ctx->wr.send_flags = IBV_SEND_SIGNALED | IBV_SEND_INLINE; + } + ctx->wr.next = NULL; + /*These should be the i'th place ... */ + ctx->wr.wr.rdma.remote_addr = rem_dest[0]->vaddr; + ctx->wr.wr.rdma.rkey = rem_dest[0]->rkey; + /* lets make the list with the right id's*/ + for (qpindex=0 ; qpindex < user_param->numofqps ; qpindex++) { + for (index =0 ; index < user_param->maxpostsofqpiniteration ; index++) { + wrlist[qpindex*user_param->maxpostsofqpiniteration+index]=ctx->wr; + wrlist[qpindex*user_param->maxpostsofqpiniteration+ index].wr_id = qpindex ; + if(index < user_param->maxpostsofqpiniteration -1) { + wrlist[qpindex*user_param->maxpostsofqpiniteration+index].next=&wrlist[qpindex*user_param->maxpostsofqpiniteration+index+1]; + } else { + wrlist[qpindex*user_param->maxpostsofqpiniteration+index].next=NULL; + } + } + } + totscnt = 0; + totccnt = 0; + /*clear the scnt ccnt counters for each iteration*/ + for (index =0 ; index < user_param->numofqps ; index++) { + ctx->scnt[index] = 0; + ctx->ccnt[index] = 0; + } + index = 0; + + /* Done with setup. Start the test. */ + + while (totscnt < (user_param->iters * user_param->numofqps) || totccnt < (user_param->iters * user_param->numofqps) ) { + /* main loop to run over all the qps and post for each accumulated 40 wq's */ + for (qpindex =0 ; qpindex < user_param->numofqps ; qpindex++) { + qp = ctx->qp[qpindex]; + if (user_param->iters > ctx->scnt[qpindex] ) { + numpostperqp = user_param->maxpostsofqpiniteration - (ctx->scnt[qpindex] - ctx->ccnt[qpindex]); + if (numpostperqp > 40 || ((user_param->iters - ctx->scnt[qpindex]) <= 40 && numpostperqp > 0) ){ + wrlist[qpindex*user_param->maxpostsofqpiniteration+numpostperqp-1].next=NULL; + tposted[totscnt] = get_cycles(); + if (ibv_post_send(qp, &wrlist[qpindex*user_param->maxpostsofqpiniteration], &bad_wr)) { + fprintf(stderr, "Couldn't post %d send: qp index = %d qp scnt=%d total scnt %d qp scnt=%d total ccnt=%d\n", + numpostperqp,qpindex,ctx->scnt[qpindex],totscnt,ctx->ccnt[qpindex],totccnt); + return 1; + } + ctx->scnt[qpindex]= ctx->scnt[qpindex]+numpostperqp; + totscnt=totscnt + numpostperqp; + wrlist[qpindex*user_param->maxpostsofqpiniteration+numpostperqp-1].next=&wrlist[qpindex*user_param->maxpostsofqpiniteration+numpostperqp]; + } + } + /*FINISHED POSTING */ + } + if (totccnt < (user_param->iters * user_param->numofqps) ) { + int ne; + do { + ne = ibv_poll_cq(ctx->cq, 1, &wc); + } while (ne == 0); + tcompleted[totccnt] = get_cycles(); + if (ne < 0) { + fprintf(stderr, "poll CQ failed %d\n", ne); + return 1; + } + if (wc.status != IBV_WC_SUCCESS) { + fprintf(stderr, "Completion wth error at %s:\n", + user_param->servername ? "client" : "server"); + fprintf(stderr, "Failed status %d: wr_id %d\n", + wc.status, (int) wc.wr_id); + fprintf(stderr, "qp index %d ,qp scnt=%d, qp ccnt=%d total scnt %d total ccnt %d\n", + (int)wc.wr_id, ctx->scnt[(int)wc.wr_id], ctx->ccnt[(int)wc.wr_id], totscnt, totccnt); + return 1; + } + /*here the id is the index to the qp num */ + ctx->ccnt[(int)wc.wr_id] = ctx->ccnt[(int)wc.wr_id]+1; + totccnt += 1; + } + } + free(wrlist); + return(0); +} + +int main(int argc, char *argv[]) +{ + struct ibv_device **dev_list; + struct ibv_device *ib_dev; + struct pingpong_context *ctx; + struct pingpong_dest *my_dest; + struct pingpong_dest **rem_dest; + struct user_parameters user_param; + struct ibv_device_attr device_attribute; + char *ib_devname = NULL; + int port = 18515; + int ib_port = 1; + long long size = 65536; + int sockfd; + int duplex = 0; + int i = 0; + int inline_given_in_cmd = 0; + struct ibv_context *context; + + /* init default values to user's parameters */ + memset(&user_param, 0, sizeof(struct user_parameters)); + user_param.mtu = 0; + user_param.iters = 5000; + user_param.tx_depth = 100; + user_param.servername = NULL; + user_param.numofqps = 1; + user_param.maxpostsofqpiniteration = 100; + user_param.inline_size = MAX_INLINE; + /* Parameter parsing. */ + while (1) { + int c; + + static struct option long_options[] = { + { .name = "port", .has_arg = 1, .val = 'p' }, + { .name = "ib-dev", .has_arg = 1, .val = 'd' }, + { .name = "ib-port", .has_arg = 1, .val = 'i' }, + { .name = "mtu", .has_arg = 1, .val = 'm' }, + { .name = "qp", .has_arg = 1, .val = 'q' }, + { .name = "post", .has_arg = 1, .val = 'g' }, + { .name = "connection", .has_arg = 1, .val = 'c' }, + { .name = "size", .has_arg = 1, .val = 's' }, + { .name = "iters", .has_arg = 1, .val = 'n' }, + { .name = "tx-depth", .has_arg = 1, .val = 't' }, + { .name = "inline_size", .has_arg = 1, .val = 'I' }, + { .name = "all", .has_arg = 0, .val = 'a' }, + { .name = "bidirectional", .has_arg = 0, .val = 'b' }, + { .name = "version", .has_arg = 0, .val = 'V' }, + { 0 } + }; + + c = getopt_long(argc, argv, "p:d:i:m:q:g:c:s:n:t:I:baV", long_options, NULL); + if (c == -1) + break; + + switch (c) { + case 'p': + port = strtol(optarg, NULL, 0); + if (port < 0 || port > 65535) { + usage(argv[0]); + return 1; + } + break; + + case 'd': + ib_devname = strdupa(optarg); + break; + case 'c': + if (strcmp("UC",optarg)==0) + user_param.connection_type=UC; + break; + + case 'm': + user_param.mtu = strtol(optarg, NULL, 0); + break; + case 'q': + user_param.numofqps = strtol(optarg, NULL, 0); + break; + case 'g': + user_param.maxpostsofqpiniteration = strtol(optarg, NULL, 0); + break; + case 'a': + user_param.all = ALL; + break; + case 'V': + printf("rdma_bw version : %.2f\n",VERSION); + return 0; + break; + case 'i': + ib_port = strtol(optarg, NULL, 0); + if (ib_port < 0) { + usage(argv[0]); + return 1; + } + break; + + case 's': + size = strtoll(optarg, NULL, 0); + if (size < 1 || size > UINT_MAX / 2) { + usage(argv[0]); + return 1; + } + break; + + case 't': + user_param.tx_depth = strtol(optarg, NULL, 0); + if (user_param.tx_depth < 1) { usage(argv[0]); return 1; } + break; + + case 'I': + user_param.inline_size = strtol(optarg, NULL, 0); + inline_given_in_cmd =1; + if (user_param.inline_size > MAX_INLINE) { + usage(argv[0]); + return 7; + } + + break; + + case 'n': + user_param.iters = strtol(optarg, NULL, 0); + if (user_param.iters < 2) { + usage(argv[0]); + return 1; + } + + break; + + case 'b': + duplex = 1; + break; + + default: + usage(argv[0]); + return 1; + } + } + + if (optind == argc - 1) { + if (!argv[optind]) { + usage(argv[0]); + return 1; + } + user_param.servername = strdupa(argv[optind]); + } + else if (optind < argc) { + usage(argv[0]); + return 1; + } + + printf("------------------------------------------------------------------\n"); + if (duplex == 1) { + printf(" RDMA_Write Bidirectional Post List BW Test\n"); + } else { + printf(" RDMA_Write Post List BW Test\n"); + } + + printf("Number of qp's running %d\n",user_param.numofqps); + if (user_param.connection_type==RC) { + printf("Connection type : RC\n"); + } else { + printf("Connection type : UC\n"); + } + if (user_param.maxpostsofqpiniteration > user_param.tx_depth ) { + printf("Can not post more than tx_depth , adjusting number of post to tx_depth\n"); + user_param.maxpostsofqpiniteration = user_param.tx_depth; + } else { + printf("Each Qp will post %d messages each time\n",user_param.maxpostsofqpiniteration); + } + /* Done with parameter parsing. Perform setup. */ + if (user_param.all == ALL) { + /*since we run all sizes */ + size = 8388608; /*2^23 */ + } + srand48(getpid() * time(NULL)); + + page_size = sysconf(_SC_PAGESIZE); + + dev_list = ibv_get_device_list(NULL); + + if (!ib_devname) { + ib_dev = dev_list[0]; + if (!ib_dev) { + fprintf(stderr, "No IB devices found\n"); + return 1; + } + } else { + for (; (ib_dev = *dev_list); ++dev_list) + if (!strcmp(ibv_get_device_name(ib_dev), ib_devname)) + break; + if (!ib_dev) { + fprintf(stderr, "IB device %s not found\n", ib_devname); + return 1; + } + } + + context = ibv_open_device(ib_dev); + if (ibv_query_device(context, &device_attribute)) { + fprintf(stderr, "Failed to query device props"); + return 1; + } + if ((device_attribute.vendor_part_id == 25418) && (!inline_given_in_cmd)) { + user_param.inline_size = 1; + } + printf("Inline data is used up to %d bytes message\n", user_param.inline_size); + + ctx = pp_init_ctx(ib_dev, size, user_param.tx_depth, ib_port, &user_param); + if (!ctx) + return 1; + + + if (user_param.servername) { + sockfd = pp_client_connect(user_param.servername, port); + if (sockfd < 0) + return 1; + } else { + sockfd = pp_server_connect(port); + if (sockfd < 0) + return 1; + } + + my_dest = malloc(user_param.numofqps * sizeof *my_dest); + rem_dest = malloc(sizeof (struct pingpong_dest*) * user_param.numofqps ); + + for (i =0 ; iqp[i]->qp_num; + /* TBD this should be changed into VA and diffreent key to each qp */ + my_dest[i].rkey = ctx->mr->rkey; + my_dest[i].vaddr = (uintptr_t)ctx->buf + ctx->size; + + printf(" local address: LID %#04x, QPN %#06x, PSN %#06x " + "RKey %#08x VAddr %#016Lx\n", + my_dest[i].lid, my_dest[i].qpn, my_dest[i].psn, + my_dest[i].rkey, my_dest[i].vaddr); + if (user_param.servername) { + rem_dest[i] = pp_client_exch_dest(sockfd, &my_dest[i]); + } else { + rem_dest[i] = pp_server_exch_dest(sockfd, &my_dest[i]); + } + if (!rem_dest[i]) + return 1; + printf(" remote address: LID %#04x, QPN %#06x, PSN %#06x, " + "RKey %#08x VAddr %#016Lx\n", + rem_dest[i]->lid, rem_dest[i]->qpn, rem_dest[i]->psn, + rem_dest[i]->rkey, rem_dest[i]->vaddr); + if (pp_connect_ctx(ctx, ib_port, my_dest[i].psn, rem_dest[i], &user_param, i)) + return 1; + + /* An additional handshake is required *after* moving qp to RTR. + Arbitrarily reuse exch_dest for this purpose. */ + if (user_param.servername) { + rem_dest[i] = pp_client_exch_dest(sockfd, &my_dest[i]); + } else { + rem_dest[i] = pp_server_exch_dest(sockfd, &my_dest[i]); + } + } + + printf("------------------------------------------------------------------\n"); + printf(" #bytes #iterations BW peak[MB/sec] BW average[MB/sec] \n"); + /* For half duplex tests, server just waits for client to exit */ + /* the 0th place is arbitrary to signal finish ... */ + if (!user_param.servername && !duplex) { + rem_dest[0] = pp_server_exch_dest(sockfd, &my_dest[0]); + if (write(sockfd, "done", sizeof "done") != sizeof "done"){ + perror("server write"); + fprintf(stderr, "Couldn't write to socket\n"); + return 1; + } + close(sockfd); + return 0; + } + + tposted = malloc(user_param.iters * user_param.numofqps * sizeof *tposted); + + if (!tposted) { + perror("malloc"); + return 1; + } + + tcompleted = malloc(user_param.iters * user_param.numofqps * sizeof *tcompleted); + + if (!tcompleted) { + perror("malloc"); + return 1; + } + + if (user_param.all == ALL) { + for (i = 1; i < 24 ; ++i) { + size = 1 << i; + if(run_iter(ctx, &user_param, rem_dest, size)) + return 17; + print_report(user_param.iters, size, duplex, tposted, tcompleted, &user_param); + } + } else { + if(run_iter(ctx, &user_param, rem_dest, size)) + return 18; + print_report(user_param.iters, size, duplex, tposted, tcompleted, &user_param); + } + /* the 0th place is arbitrary to signal finish ... */ + if (user_param.servername) { + rem_dest[0] = pp_client_exch_dest(sockfd, &my_dest[0]); + } else { + rem_dest[0] = pp_server_exch_dest(sockfd, &my_dest[0]); + } + + if (write(sockfd, "done", sizeof "done") != sizeof "done"){ + perror("write"); + fprintf(stderr, "Couldn't write to socket\n"); + return 1; + } + close(sockfd); + + free(tposted); + free(tcompleted); + + printf("------------------------------------------------------------------\n"); + return 0; +} diff --git a/branches/WOF2-3/tests/perftest/write_bw_postlist/write_bw_postlist.rc b/branches/WOF2-3/tests/perftest/write_bw_postlist/write_bw_postlist.rc new file mode 100644 index 00000000..0f144d37 --- /dev/null +++ b/branches/WOF2-3/tests/perftest/write_bw_postlist/write_bw_postlist.rc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: write_lat.rc 474 2006-08-31 08:57:19Z sleybo $ + */ + + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef DBG +#define VER_FILEDESCRIPTION_STR "winverbs - RDMA_Write Post List BW Test (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "winverbs - RDMA_Write Post List BW Test" +#endif + +#define VER_INTERNALNAME_STR "ibv_write_lat.exe" +#define VER_ORIGINALFILENAME_STR "ibv_write_lat.exe" + +#include diff --git a/branches/WOF2-3/tests/perftest/write_lat/SOURCES b/branches/WOF2-3/tests/perftest/write_lat/SOURCES new file mode 100644 index 00000000..6e948e27 --- /dev/null +++ b/branches/WOF2-3/tests/perftest/write_lat/SOURCES @@ -0,0 +1,30 @@ +TARGETNAME = ibv_write_lat +TARGETPATH = ..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = PROGRAM + +UMTYPE = console +UMENTRY = main + +USE_MSVCRT = 1 +USE_STL = 1 +USE_NATIVE_EH = 1 +USE_IOSTREAM = 1 + +SOURCES = write_lat.rc write_lat.c ..\perftest.c + +INCLUDES = ..;..\..\..\ulp\libibverbs\include;\ + ..\..\..\inc;..\..\..\inc\user;\ + ..\..\..\inc\user\linux; + +TARGETLIBS = \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\advapi32.lib \ + $(SDK_LIB_PATH)\user32.lib \ + $(SDK_LIB_PATH)\ole32.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\libibverbs.lib +!else + $(TARGETPATH)\*\libibverbsd.lib +!endif + diff --git a/branches/WOF2-3/tests/perftest/write_lat/makefile b/branches/WOF2-3/tests/perftest/write_lat/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-3/tests/perftest/write_lat/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\inc\openib.def diff --git a/branches/WOF2-3/tests/perftest/write_lat/write_lat.c b/branches/WOF2-3/tests/perftest/write_lat/write_lat.c new file mode 100644 index 00000000..af7d782c --- /dev/null +++ b/branches/WOF2-3/tests/perftest/write_lat/write_lat.c @@ -0,0 +1,798 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies Ltd. All rights reserved. + * Copyright (c) 2005 Hewlett Packard, Inc (Grant Grundler) + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include + +#include "..\..\..\etc\user\getopt.c" +#include "perftest.h" +#include + +#define PINGPONG_RDMA_WRID 3 +#define VERSION 1.0 +#define ALL 1 +#define MAX_INLINE 400 + +typedef UINT64 cycles_t; +cycles_t *tstamp; + +struct user_parameters { + const char *servername; + int connection_type; + int mtu; + int all; /* run all msg size */ + int iters; + int tx_depth; + int inline_size; +}; + +struct report_options { + int unsorted; + int histogram; + int cycles; /* report delta's in cycles, not microsec's */ +}; + +struct pingpong_context { + struct ibv_context *context; + struct ibv_pd *pd; + struct ibv_mr *mr; + struct ibv_cq *cq; + struct ibv_qp *qp; + void *buf; + volatile char *post_buf; + volatile char *poll_buf; + int size; + int tx_depth; + struct ibv_sge list; + struct ibv_send_wr wr; +}; + +struct pingpong_dest { + int lid; + int qpn; + int psn; + unsigned rkey; + unsigned long long vaddr; +}; + +static uint16_t pp_get_local_lid(struct pingpong_context *ctx, int port) +{ + struct ibv_port_attr attr; + + if (ibv_query_port(ctx->context, (uint8_t) port, &attr)) + return 0; + + return attr.lid; +} + +static struct ibv_device *pp_find_dev(const char *ib_devname) { + struct ibv_device **dev_list; + struct ibv_device *ib_dev = NULL; + + dev_list = ibv_get_device_list(NULL); + if (!dev_list) + return NULL; + + if (!ib_devname) { + ib_dev = dev_list[0]; + if (!ib_dev) + fprintf(stderr, "No IB devices found\n"); + } else { + for (; (ib_dev = *dev_list); ++dev_list) + if (!strcmp(ibv_get_device_name(ib_dev), ib_devname)) + break; + if (!ib_dev) + fprintf(stderr, "IB device %s not found\n", ib_devname); + } + return ib_dev; +} + +#define KEY_MSG_SIZE (sizeof "0000:000000:000000:00000000:0000000000000000") +#define KEY_PRINT_FMT "%04x:%06x:%06x:%08x:%016Lx" + +static int pp_write_keys(SOCKET sockfd, const struct pingpong_dest *my_dest) +{ + char msg[KEY_MSG_SIZE]; + + sprintf(msg, KEY_PRINT_FMT, my_dest->lid, my_dest->qpn, + my_dest->psn, my_dest->rkey, my_dest->vaddr); + + if (send(sockfd, msg, sizeof msg, 0) != sizeof msg) { + perror("client write"); + fprintf(stderr, "Couldn't send local address\n"); + return -1; + } + + return 0; +} + +static int pp_read_keys(SOCKET sockfd, const struct pingpong_dest *my_dest, + struct pingpong_dest *rem_dest) +{ + int parsed; + char msg[KEY_MSG_SIZE]; + + if (recv(sockfd, msg, sizeof msg, 0) != sizeof msg) { + perror("pp_read_keys"); + fprintf(stderr, "Couldn't read remote address\n"); + return -1; + } + + memset(rem_dest, 0, sizeof *rem_dest); + parsed = sscanf(msg, KEY_PRINT_FMT, &rem_dest->lid, &rem_dest->qpn, + &rem_dest->psn, &rem_dest->rkey, &rem_dest->vaddr); + + if (parsed != 5) { + fprintf(stderr, "Couldn't parse line <%.*s>\n", + (int)sizeof msg, msg); + return -1; + } + + return 0; +} + +static int pp_client_exch_dest(SOCKET sockfd, const struct pingpong_dest *my_dest, + struct pingpong_dest *rem_dest) +{ + if (pp_write_keys(sockfd, my_dest)) + return -1; + + return pp_read_keys(sockfd, my_dest, rem_dest); +} + +static int pp_server_exch_dest(SOCKET sockfd, const struct pingpong_dest *my_dest, + struct pingpong_dest* rem_dest) +{ + + if (pp_read_keys(sockfd, my_dest, rem_dest)) + return -1; + + return pp_write_keys(sockfd, my_dest); +} + +static struct pingpong_context *pp_init_ctx(struct ibv_device *ib_dev, int size, + int tx_depth, int port, struct user_parameters *user_parm) +{ + struct pingpong_context *ctx; + struct ibv_device_attr device_attr; + + ctx = malloc(sizeof *ctx); + if (!ctx) + return NULL; + + ctx->size = size; + ctx->tx_depth = tx_depth; + + ctx->buf = malloc(size * 2); + if (!ctx->buf) { + fprintf(stderr, "Couldn't allocate work buf.\n"); + return NULL; + } + + memset(ctx->buf, 0, size * 2); + + ctx->post_buf = (char*)ctx->buf + (size - 1); + ctx->poll_buf = (char*)ctx->buf + (2 * size - 1); + + ctx->context = ibv_open_device(ib_dev); + if (!ctx->context) { + fprintf(stderr, "Couldn't get context for %s\n", + ibv_get_device_name(ib_dev)); + return NULL; + } + if (user_parm->mtu == 0) {/*user did not ask for specific mtu */ + if (ibv_query_device(ctx->context, &device_attr)) { + fprintf(stderr, "Failed to query device props"); + return NULL; + } + if (device_attr.vendor_part_id == 23108) { + user_parm->mtu = 1024; + } else { + user_parm->mtu = 2048; + } + } + ctx->pd = ibv_alloc_pd(ctx->context); + if (!ctx->pd) { + fprintf(stderr, "Couldn't allocate PD\n"); + return NULL; + } + + ctx->mr = ibv_reg_mr(ctx->pd, ctx->buf, size * 2, + IBV_ACCESS_REMOTE_WRITE | IBV_ACCESS_LOCAL_WRITE); + if (!ctx->mr) { + fprintf(stderr, "Couldn't allocate MR\n"); + return NULL; + } + + ctx->cq = ibv_create_cq(ctx->context, tx_depth, NULL, NULL, 0); + if (!ctx->cq) { + fprintf(stderr, "Couldn't create CQ\n"); + return NULL; + } + + { + struct ibv_qp_init_attr attr; + memset(&attr, 0, sizeof(struct ibv_qp_init_attr)); + attr.send_cq = ctx->cq; + attr.recv_cq = ctx->cq; + attr.cap.max_send_wr = tx_depth; + /* Work around: driver doesnt support + * recv_wr = 0 */ + attr.cap.max_recv_wr = 1; + attr.cap.max_send_sge = 1; + attr.cap.max_recv_sge = 1; + attr.cap.max_inline_data = user_parm->inline_size; + + if (user_parm->connection_type==1) { + attr.qp_type = IBV_QPT_UC; + } else { + attr.qp_type = IBV_QPT_RC; + } + ctx->qp = ibv_create_qp(ctx->pd, &attr); + if (!ctx->qp) { + fprintf(stderr, "Couldn't create QP\n"); + return NULL; + } + } + + { + struct ibv_qp_attr attr; + + memset(&attr, 0, sizeof attr); + attr.qp_state = IBV_QPS_INIT; + attr.pkey_index = 0; + attr.port_num = (uint8_t) port; + attr.qp_access_flags = IBV_ACCESS_REMOTE_WRITE; + + if (ibv_modify_qp(ctx->qp, &attr, + IBV_QP_STATE | + IBV_QP_PKEY_INDEX | + IBV_QP_PORT | + IBV_QP_ACCESS_FLAGS)) { + fprintf(stderr, "Failed to modify QP to INIT\n"); + return NULL; + } + } + + memset(&ctx->wr, 0, sizeof(ctx->wr)); + + ctx->wr.wr_id = PINGPONG_RDMA_WRID; + ctx->wr.sg_list = &ctx->list; + ctx->wr.num_sge = 1; + ctx->wr.opcode = IBV_WR_RDMA_WRITE; + ctx->wr.next = NULL; + + return ctx; +} + +static int pp_connect_ctx(struct pingpong_context *ctx, int port, int my_psn, + struct pingpong_dest *dest,struct user_parameters *user_parm) +{ + struct ibv_qp_attr attr; + memset(&attr, 0, sizeof(struct ibv_qp_attr)); + attr.qp_state = IBV_QPS_RTR; + switch (user_parm->mtu) { + case 256 : + attr.path_mtu = IBV_MTU_256; + break; + case 512 : + attr.path_mtu = IBV_MTU_512; + break; + case 1024 : + attr.path_mtu = IBV_MTU_1024; + break; + case 2048 : + attr.path_mtu = IBV_MTU_2048; + break; + case 4096 : + attr.path_mtu = IBV_MTU_4096; + break; + } + printf("Mtu : %d\n", user_parm->mtu); + attr.dest_qp_num = dest->qpn; + attr.rq_psn = dest->psn; + + if (user_parm->connection_type==0) { + attr.max_dest_rd_atomic = 1; + attr.min_rnr_timer = 12; + } + + attr.ah_attr.is_global = 0; + attr.ah_attr.dlid = (uint16_t) dest->lid; + attr.ah_attr.sl = 0; + attr.ah_attr.src_path_bits = 0; + attr.ah_attr.port_num = (uint8_t) port; + + if (user_parm->connection_type == 0) { + if (ibv_modify_qp(ctx->qp, &attr, + IBV_QP_STATE | + IBV_QP_AV | + IBV_QP_PATH_MTU | + IBV_QP_DEST_QPN | + IBV_QP_RQ_PSN | + IBV_QP_MIN_RNR_TIMER | + IBV_QP_MAX_DEST_RD_ATOMIC)) { + fprintf(stderr, "Failed to modify RC QP to RTR\n"); + return 1; + } + attr.timeout = 14; + attr.retry_cnt = 7; + attr.rnr_retry = 7; + } else { + if (ibv_modify_qp(ctx->qp, &attr, + IBV_QP_STATE | + IBV_QP_AV | + IBV_QP_PATH_MTU | + IBV_QP_DEST_QPN | + IBV_QP_RQ_PSN)) { + fprintf(stderr, "Failed to modify UC QP to RTR\n"); + return 1; + } + + } + attr.qp_state = IBV_QPS_RTS; + attr.sq_psn = my_psn; + + if (user_parm->connection_type == 0) { + attr.max_rd_atomic = 1; + if (ibv_modify_qp(ctx->qp, &attr, + IBV_QP_STATE | + IBV_QP_SQ_PSN | + IBV_QP_TIMEOUT | + IBV_QP_RETRY_CNT | + IBV_QP_RNR_RETRY | + IBV_QP_MAX_QP_RD_ATOMIC)) { + fprintf(stderr, "Failed to modify RC QP to RTS\n"); + return 1; + } + } else { + if (ibv_modify_qp(ctx->qp, &attr, + IBV_QP_STATE | + IBV_QP_SQ_PSN)) { + fprintf(stderr, "Failed to modify UC QP to RTS\n"); + return 1; + } + + } + return 0; +} + +static int pp_open_port(struct pingpong_context *ctx, const char * servername, + int ib_port, int port, struct pingpong_dest *rem_dest,struct user_parameters *user_parm) +{ + char addr_fmt[] = "%8s address: LID %#04x QPN %#06x PSN %#06x RKey %#08x VAddr %#016Lx\n"; + struct pingpong_dest my_dest; + SOCKET sockfd; + int rc; + + /* Create connection between client and server. + * We do it by exchanging data over a TCP socket connection. */ + + my_dest.lid = pp_get_local_lid(ctx, ib_port); + my_dest.qpn = ctx->qp->qp_num; + my_dest.psn = rand() & 0xffffff; + if (!my_dest.lid) { + fprintf(stderr, "Local lid 0x0 detected. Is an SM running?\n"); + return -1; + } + my_dest.rkey = ctx->mr->rkey; + my_dest.vaddr = (uintptr_t)ctx->buf + ctx->size; + + printf(addr_fmt, "local", my_dest.lid, my_dest.qpn, my_dest.psn, + my_dest.rkey, my_dest.vaddr); + + sockfd = servername ? pp_client_connect(servername, port) : + pp_server_connect(port); + + if (sockfd == INVALID_SOCKET) { + printf("pp_connect_sock(%s,%d) failed (%d)!\n", + servername, port, sockfd); + return (int) sockfd; + } + + rc = servername ? pp_client_exch_dest(sockfd, &my_dest, rem_dest) : + pp_server_exch_dest(sockfd, &my_dest, rem_dest); + if (rc) + return rc; + + printf(addr_fmt, "remote", rem_dest->lid, rem_dest->qpn, rem_dest->psn, + rem_dest->rkey, rem_dest->vaddr); + + if ((rc = pp_connect_ctx(ctx, ib_port, my_dest.psn, rem_dest,user_parm))) + return rc; + + /* An additional handshake is required *after* moving qp to RTR. + * Arbitrarily reuse exch_dest for this purpose. + */ + + rc = servername ? pp_client_exch_dest(sockfd, &my_dest, rem_dest) : + pp_server_exch_dest(sockfd, &my_dest, rem_dest); + + if (rc) + return rc; + + if (send(sockfd, "done", sizeof "done", 0) != sizeof "done"){ + perror("write"); + fprintf(stderr, "Couldn't write to socket\n"); + return 1; + } + closesocket(sockfd); + return 0; +} + +static void usage(const char *argv0) +{ + printf("Usage:\n"); + printf(" %s start a server and wait for connection\n", argv0); + printf(" %s -h connect to server at \n", argv0); + printf("\n"); + printf("Options:\n"); + printf(" -p listen on/connect to port (default 18515)\n"); + printf(" -c connection type RC/UC (default RC)\n"); + printf(" -m mtu size (256 - 4096. default for hermon is 2048)\n"); + printf(" -d use IB device (default first device found)\n"); + printf(" -i use port of IB device (default 1)\n"); + printf(" -s size of message to exchange (default 1)\n"); + printf(" -a Run sizes from 2 till 2^23\n"); + printf(" -t size of tx queue (default 50)\n"); + printf(" -n number of exchanges (at least 2, default 1000)\n"); + printf(" -I max size of message to be sent in inline mode (default 400)\n"); + printf(" -C report times in cpu cycle units (default microseconds)\n"); + printf(" -H print out all results (default print summary only)\n"); + printf(" -U (implies -H) print out unsorted results (default sorted)\n"); + printf(" -V display version number\n"); +} + +static void print_report(struct report_options * options, + unsigned int iters, cycles_t *tstamp,int size) +{ + cycles_t cycles_to_units; + cycles_t median; + unsigned int i; + const char* units; + cycles_t *delta = malloc((iters - 1) * sizeof *delta); + + if (!delta) { + perror("malloc"); + return; + } + + for (i = 0; i < iters - 1; ++i) + delta[i] = tstamp[i + 1] - tstamp[i]; + + if (options->cycles) { + cycles_to_units = 1; + units = "cycles"; + } else { + cycles_to_units = get_freq(); + units = "sec"; + } + + if (options->unsorted) { + printf("#, %s, frequency=%I64d\n", units, get_freq()); + for (i = 0; i < iters - 1; ++i) + printf("%d, %g\n", i + 1, delta[i] / cycles_to_units / 2. * 1000000.); + } + + qsort(delta, iters - 1, sizeof *delta, cycles_compare); + + if (options->histogram) { + printf("#, %s\n", units); + for (i = 0; i < iters - 1; ++i) + printf("%d, %7.2f\n", i + 1, (double) delta[i] / (double) cycles_to_units / 2. * 1000000.); + } + + median = get_median(iters - 1, delta); + printf("%7d %d %7.2f %7.2f %7.2f\n", + size, iters, (double) delta[0] / (double) cycles_to_units / 2. * 1000000., + (double) delta[iters - 2] / (double) cycles_to_units / 2. * 1000000., + (double) median / (double) cycles_to_units / 2. * 1000000.); + free(delta); +} + +static int run_iter(struct pingpong_context *ctx, struct user_parameters *user_param, + struct pingpong_dest *rem_dest, int size) +{ + struct ibv_qp *qp; + struct ibv_send_wr *wr; + volatile char *poll_buf; + volatile char *post_buf; + + int scnt, ccnt, rcnt; + int iters; + int tx_depth; + int inline_size; + + iters = user_param->iters; + tx_depth = user_param->tx_depth; + inline_size = user_param->inline_size; + + wr = &ctx->wr; + ctx->list.addr = (uintptr_t) ctx->buf; + ctx->list.length = size; + ctx->list.lkey = ctx->mr->lkey; + wr->wr.rdma.remote_addr = rem_dest->vaddr; + wr->wr.rdma.rkey = rem_dest->rkey; + + if (size > inline_size) {/* complaince to perf_main */ + ctx->wr.send_flags = IBV_SEND_SIGNALED; + } else { + ctx->wr.send_flags = IBV_SEND_SIGNALED | IBV_SEND_INLINE; + } + scnt = 0; + rcnt = 0; + ccnt = 0; + + if(user_param->all == ALL) { + post_buf = (char*)ctx->buf + size - 1; + poll_buf = (char*)ctx->buf + 8388608 + size - 1; + } else { + poll_buf = ctx->poll_buf; + post_buf = ctx->post_buf; + } + qp = ctx->qp; + + /* Done with setup. Start the test. */ + while (scnt < iters || ccnt < iters || rcnt < iters) { + + /* Wait till buffer changes. */ + if (rcnt < user_param->iters && !(scnt < 1 && user_param->servername)) { + ++rcnt; + while (*poll_buf != (char)rcnt) + ; + /* Here the data is already in the physical memory. + If we wanted to actually use it, we may need + a read memory barrier here. */ + } + + if (scnt < user_param->iters) { + struct ibv_send_wr *bad_wr; + if (user_param->servername) + tstamp[scnt] = get_cycles(); + + *post_buf = (char)++scnt; + + if (ibv_post_send(qp, wr, &bad_wr)) { + fprintf(stderr, "Couldn't post send: scnt=%d\n", + scnt); + return 11; + } + } + + if (ccnt < user_param->iters) { + struct ibv_wc wc; + int ne; + ++ccnt; + do { + ne = ibv_poll_cq(ctx->cq, 1, &wc); + } while (ne == 0); + if (ne < 0) { + fprintf(stderr, "poll CQ failed %d\n", ne); + return 12; + } + if (wc.status != IBV_WC_SUCCESS) { + fprintf(stderr, "Completion wth error at %s:\n", + user_param->servername ? "client" : "server"); + fprintf(stderr, "Failed status %d: wr_id %d\n", + wc.status, (int) wc.wr_id); + fprintf(stderr, "scnt=%d, rcnt=%d, ccnt=%d\n", + scnt, rcnt, ccnt); + return 13; + } + } + } + return(0); +} + +int __cdecl main(int argc, char *argv[]) +{ + const char *ib_devname = NULL; + int port = 18515; + int ib_port = 1; + int size = 2; + int i = 0; + struct report_options report; + struct pingpong_context *ctx; + struct pingpong_dest rem_dest; + struct ibv_device *ib_dev; + struct user_parameters user_param; + WORD version; + WSADATA data; + int err; + + srand((unsigned int) time(NULL)); + version = MAKEWORD(2, 2); + err = WSAStartup(version, &data); + if (err) + return -1; + + /* init default values to user's parameters */ + memset(&report, 0, sizeof report); + memset(&user_param, 0, sizeof(struct user_parameters)); + user_param.mtu = 0; /* signal choose default by device */ + user_param.iters = 1000; + user_param.tx_depth = 50; + user_param.servername = NULL; + user_param.inline_size = MAX_INLINE; + + /* Parameter parsing. */ + while (1) { + int c; + + c = getopt(argc, argv, "h:p:c:m:d:i:s:n:t:I:aCHUV"); + if (c == -1) + break; + + switch (c) { + case 'p': + port = strtol(optarg, NULL, 0); + if (port < 0 || port > 65535) { + usage(argv[0]); + return 1; + } + break; + case 'c': + if (strcmp("UC",optarg)==0) + user_param.connection_type=1; + /* default is 0 for any other option RC*/ + break; + + case 'm': + user_param.mtu = strtol(optarg, NULL, 0); + break; + case 'a': + user_param.all = ALL; + break; + case 'V': + printf("perftest version : %.2f\n",VERSION); + return 0; + case 'd': + ib_devname = _strdup(optarg); + break; + + case 'i': + ib_port = strtol(optarg, NULL, 0); + if (ib_port < 0) { + usage(argv[0]); + return 2; + } + break; + + case 's': + size = strtol(optarg, NULL, 0); + if (size < 1) { + usage(argv[0]); return 3; + } + break; + + case 't': + user_param.tx_depth = strtol(optarg, NULL, 0); + if (user_param.tx_depth < 1) { + usage(argv[0]); return 4; + } + break; + + case 'I': + user_param.inline_size = strtol(optarg, NULL, 0); + if (user_param.inline_size > MAX_INLINE) { + usage(argv[0]); return 7; + } + break; + + case 'n': + user_param.iters = strtol(optarg, NULL, 0); + if (user_param.iters < 2) { + usage(argv[0]); + return 5; + } + break; + + case 'C': + report.cycles = 1; + break; + + case 'H': + report.histogram = 1; + break; + + case 'U': + report.unsorted = 1; + break; + + case 'h': + if (optarg) { + user_param.servername = _strdup(optarg); + break; + } + + default: + usage(argv[0]); + return 5; + } + } + + /* + * Done with parameter parsing. Perform setup. + */ + + tstamp = malloc(user_param.iters * sizeof *tstamp); + if (!tstamp) { + perror("malloc"); + return 10; + } + printf("------------------------------------------------------------------\n"); + printf(" RDMA_Write Latency Test\n"); + printf("Inline data is used up to %d bytes message\n", user_param.inline_size); + if (user_param.connection_type==0) { + printf("Connection type : RC\n"); + } else { + printf("Connection type : UC\n"); + } + if (user_param.all == ALL) { + /*since we run all sizes */ + size = 8388608; /*2^23 */ + } + + ib_dev = pp_find_dev(ib_devname); + if (!ib_dev) + return 7; + + ctx = pp_init_ctx(ib_dev, size, user_param.tx_depth, ib_port,&user_param); + if (!ctx) + return 8; + + if (pp_open_port(ctx, user_param.servername, ib_port, port, &rem_dest,&user_param)) + return 9; + printf("------------------------------------------------------------------\n"); + printf(" #bytes #iterations t_min[usec] t_max[usec] t_typical[usec]\n"); + + if (user_param.all == ALL) { + for (i = 1; i < 24 ; ++i) { + size = 1 << i; + if(run_iter(ctx, &user_param, &rem_dest, size)) + return 17; + print_report(&report, user_param.iters, tstamp, size); + } + } else { + if(run_iter(ctx, &user_param, &rem_dest, size)) + return 18; + print_report(&report, user_param.iters, tstamp, size); + } + + printf("------------------------------------------------------------------\n"); + free(tstamp); + return 0; +} diff --git a/branches/WOF2-3/tests/perftest/write_lat/write_lat.rc b/branches/WOF2-3/tests/perftest/write_lat/write_lat.rc new file mode 100644 index 00000000..4d028fd0 --- /dev/null +++ b/branches/WOF2-3/tests/perftest/write_lat/write_lat.rc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: write_lat.rc 474 2006-08-31 08:57:19Z sleybo $ + */ + + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef DBG +#define VER_FILEDESCRIPTION_STR "winverbs - RDMA write Latency Test (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "winverbs - RDMA write Latency Test " +#endif + +#define VER_INTERNALNAME_STR "ibv_write_lat.exe" +#define VER_ORIGINALFILENAME_STR "ibv_write_lat.exe" + +#include diff --git a/branches/WOF2-3/tests/wherebu/dirs b/branches/WOF2-3/tests/wherebu/dirs new file mode 100644 index 00000000..389156fd --- /dev/null +++ b/branches/WOF2-3/tests/wherebu/dirs @@ -0,0 +1,2 @@ +DIRS=\ + user diff --git a/branches/WOF2-3/tests/wherebu/user/SOURCES b/branches/WOF2-3/tests/wherebu/user/SOURCES new file mode 100644 index 00000000..f2f18046 --- /dev/null +++ b/branches/WOF2-3/tests/wherebu/user/SOURCES @@ -0,0 +1,20 @@ +TARGETNAME=wherebu +TARGETPATH=..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE=PROGRAM +UMTYPE=console +USE_MSVCRT=1 + +SOURCES=\ + wherebu.cpp + +TARGETLIBS=\ + $(TARGETPATH)\*\ibat.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ + $(SDK_LIB_PATH)\Iphlpapi.lib + +MSC_WARNING_LEVEL= /W4 + +INCLUDES=$(SDK_INC_PATH);\ + ..\..\..\inc;\ + ..\..\..\inc\user;\ + $(PLATFORM_SDK_PATH)\include; diff --git a/branches/WOF2-3/tests/wherebu/user/makefile b/branches/WOF2-3/tests/wherebu/user/makefile new file mode 100644 index 00000000..128ed372 --- /dev/null +++ b/branches/WOF2-3/tests/wherebu/user/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the Windows NT DDK +# + +!INCLUDE ..\..\..\inc\openib.def diff --git a/branches/WOF2-3/tests/wherebu/user/wherebu.cpp b/branches/WOF2-3/tests/wherebu/user/wherebu.cpp new file mode 100644 index 00000000..c87ed852 --- /dev/null +++ b/branches/WOF2-3/tests/wherebu/user/wherebu.cpp @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id:$ + */ + + +#include "stdlib.h" +#include "stdio.h" +#include "iba/ib_types.h" +#include "iba/ibat.h" + + +inline LONGLONG GetElapsedTime() +{ + LARGE_INTEGER elapsed; + QueryPerformanceCounter(&elapsed); + return elapsed.QuadPart; +} + +inline LONGLONG GetFrequency() +{ + LARGE_INTEGER Frequency; + QueryPerformanceFrequency(&Frequency); + return Frequency.QuadPart; +} + +int PrintUsage( int argc, char *argv[] ) +{ + UNREFERENCED_PARAMETER( argc ); + printf( "%s \n", argv[0] ); + + return __LINE__; +} + +int __cdecl main(int argc, char *argv[]) +{ + if( argc < 3 ) + return PrintUsage( argc, argv ); + + struct sockaddr_in srcAddr = {0}; + srcAddr.sin_family = AF_INET; + srcAddr.sin_addr.s_addr = inet_addr( argv[1] ); + + struct sockaddr_in destAddr = {0}; + destAddr.sin_family = AF_INET; + destAddr.sin_addr.s_addr = inet_addr( argv[2] ); + + ib_path_rec_t path; + HRESULT hr = IBAT::Resolve( + (struct sockaddr*)&srcAddr, + (struct sockaddr*)&destAddr, + (IBAT_PATH_BLOB*)&path + ); + if( FAILED( hr ) ) + { + printf( "Resolve returned %08x.\n", hr ); + return hr; + } + + printf( + "I B at:\n" + "partition %x\n" + "source GID %x%x:%x%x:%x%x:%x%x:%x%x:%x%x:%x%x:%x%x\n" + "destination GID %x%x:%x%x:%x%x:%x%x:%x%x:%x%x:%x%x:%x%x\n", + path.pkey, + path.sgid.raw[0], path.sgid.raw[1], path.sgid.raw[2], path.sgid.raw[3], + path.sgid.raw[4], path.sgid.raw[5], path.sgid.raw[6], path.sgid.raw[7], + path.sgid.raw[8], path.sgid.raw[9], path.sgid.raw[10], path.sgid.raw[11], + path.sgid.raw[12], path.sgid.raw[13], path.sgid.raw[14], path.sgid.raw[15], + path.dgid.raw[0], path.dgid.raw[1], path.dgid.raw[2], path.dgid.raw[3], + path.dgid.raw[4], path.dgid.raw[5], path.dgid.raw[6], path.dgid.raw[7], + path.dgid.raw[8], path.dgid.raw[9], path.dgid.raw[10], path.dgid.raw[11], + path.dgid.raw[12], path.dgid.raw[13], path.dgid.raw[14], path.dgid.raw[15] + ); + + LONGLONG StartTime = GetElapsedTime(); + for( int i = 0; i < 2000; i++ ) + { + HRESULT hr = IBAT::Resolve( + (struct sockaddr*)&srcAddr, + (struct sockaddr*)&destAddr, + (IBAT_PATH_BLOB*)&path + ); + if( FAILED( hr ) ) + { + printf( "Resolve returned %08x.\n", hr ); + return hr; + } + } + LONGLONG RunTime = GetElapsedTime() - StartTime; + double Rate = 2000.0 / ((double)RunTime / (double)GetFrequency()); + printf( "%7.2f lookups per second\n", Rate ); + + return 0; +} diff --git a/branches/WOF2-3/tests/wsd/dirs b/branches/WOF2-3/tests/wsd/dirs new file mode 100644 index 00000000..389156fd --- /dev/null +++ b/branches/WOF2-3/tests/wsd/dirs @@ -0,0 +1,2 @@ +DIRS=\ + user diff --git a/branches/WOF2-3/tests/wsd/user/contest/contest.c b/branches/WOF2-3/tests/wsd/user/contest/contest.c new file mode 100644 index 00000000..78012031 --- /dev/null +++ b/branches/WOF2-3/tests/wsd/user/contest/contest.c @@ -0,0 +1,200 @@ + +#define WIN32_LEAN_AND_MEAN +#include +#include +#include + +#include "contest.h" + +static int init_winsock(void) +{ + // initialization of the winsock DLL first + WORD wVersionRequested; + WSADATA wsaData; + int ret; + + wVersionRequested = MAKEWORD( 2, 2 ); + ret = WSAStartup( wVersionRequested, &wsaData ); + if ( ret != 0 ) { + printf("WSAStartup Error!\n"); + return 1; + } + + if ( LOBYTE( wsaData.wVersion ) != 2 || + HIBYTE( wsaData.wVersion ) != 2) { + WSACleanup( ); + printf("Bad winsock version!\n"); + } + + return 0; +} + + +static struct { + SOCKET s; +} conn[MAX_CONNS]; + + +int client(const char *host) +{ + struct sockaddr_in to_addr; + int i; + char message[100]; + int recd, sent, len; + + if (init_winsock()) { + return 1; + } + + to_addr.sin_family = AF_INET; + to_addr.sin_addr.s_addr = inet_addr(host); + to_addr.sin_port = htons(CONTEST_PORT); + + printf("Creating sockets\n"); + + for (i=0; iguid)); + + for(item_port = cl_qlist_head(&hca->ports_list); + item_port != cl_qlist_end(&hca->ports_list); + item_port = cl_qlist_next(item_port)) { + + struct ibsp_port *port = PARENT_STRUCT(item_port, struct ibsp_port, item); + + printf(" found port %d, guid %I64x\n", port->port_num, + CL_NTOH64(port->guid)); + + for(item_ip = cl_qlist_head(&port->ip_list); + item_ip != cl_qlist_end(&port->ip_list); + item_ip = cl_qlist_next(item_ip)) { + + struct ibsp_ip_addr *ip = + PARENT_STRUCT(item_ip, struct ibsp_ip_addr, item); + + printf(" %s\n", inet_ntoa(ip->ip_addr)); + + /* Remember that for the PR test */ + port_pr = port; + ip_addr_pr = ip->ip_addr; + } + } + } + + cl_spinlock_release(&g_ibsp.hca_mutex); + + if (port_pr == NULL) { + printf("BAD: port_pr is NULL\n"); + return 1; + } + + /* Display the list of all IP addresses */ + printf("List of IP addresses:\n"); + + cl_spinlock_acquire(&g_ibsp.ip_mutex); + + for(item_ip = cl_qlist_head(&g_ibsp.ip_list); + item_ip != cl_qlist_end(&g_ibsp.ip_list); item_ip = cl_qlist_next(item_ip)) { + + struct ibsp_ip_addr *ip = + PARENT_STRUCT(item_ip, struct ibsp_ip_addr, item_global); + + printf(" %s\n", inet_ntoa(ip->ip_addr)); + } + + cl_spinlock_release(&g_ibsp.ip_mutex); + + /* Query for the GUID of all local IP addresses */ + printf("Guid of local IP addresses:\n"); + for(item_ip = cl_qlist_head(&g_ibsp.ip_list); + item_ip != cl_qlist_end(&g_ibsp.ip_list); item_ip = cl_qlist_next(item_ip)) { + + struct ibsp_ip_addr *ip = + PARENT_STRUCT(item_ip, struct ibsp_ip_addr, item_global); + + ret = query_guid_address(port_pr, ip->ip_addr.S_un.S_addr, &remote_guid); + if (ret) { + printf("query_guid_address failed\n"); + return 1; + } + + printf("got GUID %I64x for IP %s\n", CL_NTOH64(remote_guid), + inet_ntoa(ip->ip_addr)); + } + + /* Query for the GUID of all IP addresses */ + printf("Guid of IP addresses:\n"); + for(i = 0; i < ROUTING_SIZE; i++) { + struct in_addr in; + ib_net32_t ip_addr; + + ip_addr = inet_addr(routing[i].ip_source); + in.S_un.S_addr = ip_addr; + + ret = query_guid_address(port_pr, ip_addr, &remote_guid); + if (ret) { + printf("query_guid_address failed for IP %s\n", inet_ntoa(in)); + } else { + in.S_un.S_addr = ip_addr; + printf("got GUID %I64x for IP %s\n", CL_NTOH64(remote_guid), inet_ntoa(in)); + } + + /* TODO: fill routing.guid */ + } + + /* Find the remote IP */ + remote_ip_addr.S_un.S_addr = INADDR_ANY; + for(i = 0; i < ROUTING_SIZE; i++) { + if (ip_addr_pr.S_un.S_addr == inet_addr(routing[i].ip_source)) { + remote_ip_addr.S_un.S_addr = inet_addr(routing[i].ip_dest); + break; + } + } + if (remote_ip_addr.S_un.S_addr == INADDR_ANY) { + /* Did not find source address. */ + printf("BAD- source IP %s not in routing\n", inet_ntoa(ip_addr_pr)); + return 1; + } + + printf("going to test between %s", inet_ntoa(ip_addr_pr)); + printf(" and %s\n", inet_ntoa(remote_ip_addr)); + + ret = query_guid_address(port_pr, remote_ip_addr.S_un.S_addr, &remote_guid); + if (ret) { + printf("query_guid_address failed for remote IP\n"); + return 1; + } + + printf("querying PR between %I64x and %I64x\n", + CL_NTOH64(port_pr->guid), CL_NTOH64(remote_guid)); + + ret = query_pr(port_pr, remote_guid, &path_rec); + if (ret) { + printf("query_pr failed\n"); + return 1; + } +#if 0 + /* Stressing query PR */ + for(i = 0; i < 1000000; i++) { + ret = query_pr(port_pr, remote_guid, &path_rec); + if (ret) { + printf("query_pr failed (at %d)\n", i); + return 1; + } + if (i % 1000 == 0) { + printf("."); + fflush(stdout); + } + } +#endif + +#if 0 + while(1) { + /* Display the list of all IP addresses */ + printf("List of IP addresses:\n"); + + cl_spinlock_acquire(&g_ibsp.ip_mutex); + + for(item_ip = cl_qlist_head(&g_ibsp.ip_list); + item_ip != cl_qlist_end(&g_ibsp.ip_list); item_ip = cl_qlist_next(item_ip)) { + + struct ibsp_ip_addr *ip = + PARENT_STRUCT(item_ip, struct ibsp_ip_addr, item_global); + + printf(" %s\n", inet_ntoa(ip->ip_addr)); + } + + cl_spinlock_release(&g_ibsp.ip_mutex); + + Sleep(100); + } +#endif + + return 0; +} + +int +main(void) +{ + int ret; + + memset(&g_ibsp, 0, sizeof(g_ibsp)); + if (init_globals()) { + CL_ERROR(IBSP_DBG_TEST, gdbg_lvl, ("init_globals failed\n")); + return 1; + } + + ret = ibsp_initialize(); + if (ret) { + printf("ib_initialize failed (%d)\n", ret); + return 1; + } + + do_test(); + + ib_release(); + + release_globals(); + + return 0; +} diff --git a/branches/WOF2-3/tests/wsd/user/test2/ibwrap.c b/branches/WOF2-3/tests/wsd/user/test2/ibwrap.c new file mode 100644 index 00000000..50a6cce4 --- /dev/null +++ b/branches/WOF2-3/tests/wsd/user/test2/ibwrap.c @@ -0,0 +1,599 @@ +#include "ibwrap.h" + +/* CQ completion handler */ +static void ib_cq_comp(void *cq_context) +{ + ib_api_status_t status; + ib_wc_t wclist; + ib_wc_t *free_wclist; + ib_wc_t *done_wclist; + BOOL need_rearm; + struct qp_pack *qp = cq_context; + + need_rearm = TRUE; + + again: + while(1) { + + wclist.p_next = NULL; + + free_wclist = &wclist; + + status = ib_poll_cq(qp->cq_handle, &free_wclist, &done_wclist); + + switch (status) { + case IB_NOT_FOUND: + goto done; + + case IB_SUCCESS: + printf("got a completion\n"); + break; + + default: + printf("ib_poll_cq failed badly (%d)\n", status); + need_rearm = FALSE; + goto done; + } + + if (done_wclist->status != IB_WCS_SUCCESS) { + printf("operation failed - status %d\n", done_wclist->status); + } + + need_rearm = TRUE; + + /* We have some completions. */ + while(done_wclist) { + + cl_atomic_dec(&qp->wq_posted); + + done_wclist = done_wclist->p_next; + }; + + if (free_wclist != NULL) { + /* No more completions */ + goto done; + } + }; + + done: + if (need_rearm) { + + need_rearm = FALSE; + + status = ib_rearm_cq(qp->cq_handle, FALSE); + if (status != IB_SUCCESS) { + printf("ib_poll_cq failed badly (%d)\n", status); + } + + goto again; + } +} + +/* Enable or disable completion. */ +int control_qp_completion(struct qp_pack *qp, int enable) +{ + ib_api_status_t status; + + if (enable) { + + status = ib_rearm_cq(qp->cq_handle, FALSE); + if (status) { + printf("ib_rearm_cq failed (%d)\n", status); + goto fail; + } + + } + + return 0; + + fail: + return -1; +} + +int create_qp(struct qp_pack *qp) +{ + ib_api_status_t status; + ib_cq_create_t cq_create; + ib_qp_create_t qp_create; + ib_qp_mod_t qp_mod; + ib_net64_t *guid_list = NULL; + size_t adapter_count; + size_t ca_attr_size = 0; + + qp->wq_posted = 0; + + /* Open AL */ + status = ib_open_al(&qp->al_handle); + if (status != IB_SUCCESS) { + printf("ib_open_al failed (%d)\n", status); + goto fail; + } + + /* Find a CA */ + adapter_count = 10; + guid_list = malloc(sizeof(ib_net64_t) * adapter_count); + if (guid_list == NULL) { + printf("can't get enough memory (%d, %d)\n", sizeof(ib_net64_t), adapter_count); + goto fail; + } + + status = ib_get_ca_guids(qp->al_handle, guid_list, &adapter_count); + if (status != IB_SUCCESS) { + printf("second ib_get_ca_guids failed (%d)\n", status); + goto fail; + } + + if (adapter_count < 1) { + printf("not enough CA (%d)\n", adapter_count); + goto fail; + } + + /* Open the hca */ + status = ib_open_ca(qp->al_handle, guid_list[0], NULL, /* event handler */ + NULL, /* context */ + &qp->hca_handle); + + if (status != IB_SUCCESS) { + printf("ib_open_ca failed (%d)\n", status); + goto fail; + } + + + /* Get the HCA attributes */ + ca_attr_size = 0; + query_ca_again: + status = ib_query_ca(qp->hca_handle, qp->ca_attr, &ca_attr_size); + + if (status == IB_INSUFFICIENT_MEMORY) { + + printf("ib_query_ca needs %d bytes\n", ca_attr_size); + + /* Allocate more memory */ + qp->ca_attr = malloc(ca_attr_size); + + if (qp->ca_attr) + goto query_ca_again; + else { + printf("HeapAlloc failed\n"); + goto fail; + } + } else if (status != IB_SUCCESS) { + printf("ib_query_ca failed (%d)\n", status); + goto fail; + } + + /* Find a port */ + if (qp->ca_attr->num_ports < 1) { + printf("not enough ports (%d)\n", qp->ca_attr->num_ports); + goto fail; + } + + qp->hca_port = &qp->ca_attr->p_port_attr[0]; + + /* Create a PD */ + status = ib_alloc_pd(qp->hca_handle, IB_PDT_NORMAL, qp, /* context */ + &qp->pd_handle); + if (status) { + printf("ib_alloc_pd failed (%d)\n", status); + goto fail; + } + + /* Create a CQ */ + cq_create.size = 50; + cq_create.pfn_comp_cb = ib_cq_comp; + cq_create.h_wait_obj = NULL; /* we use signaled completion instead */ + + status = ib_create_cq(qp->hca_handle, &cq_create, qp, /* context */ + NULL, /* async handler */ + &qp->cq_handle); + if (status) { + printf("ib_create_cq failed (%d)\n", status); + goto fail; + } + + status = ib_rearm_cq(qp->cq_handle, FALSE); + if (status) { + printf("ib_rearm_cq failed (%d)\n", status); + goto fail; + } + + /* Arm the CQ handler */ + if (control_qp_completion(qp, 1) != 0) { + printf("control_qp_completion failed\n"); + goto fail; + } + + /* Create a qp */ + cl_memclr(&qp_create, sizeof(ib_qp_create_t)); + qp_create.qp_type = IB_QPT_RELIABLE_CONN; + qp_create.h_rdd = NULL; + qp_create.sq_depth = 255; + qp_create.rq_depth = 255; + qp_create.sq_sge = 1; + qp_create.rq_sge = 1; + qp_create.h_rq_cq = qp->cq_handle; + qp_create.h_sq_cq = qp->cq_handle; + qp_create.sq_signaled = TRUE; + + status = ib_create_qp(qp->pd_handle, &qp_create, qp, /* context */ + NULL, /* async handler */ + &qp->qp_handle); + if (status) { + printf("ib_create_qp failed (%d)\n", status); + goto fail; + } + + /* Modify QP to INIT state */ + memset(&qp_mod, 0, sizeof(qp_mod)); + + qp_mod.req_state = IB_QPS_INIT; + qp_mod.state.init.pkey_index = 0; + qp_mod.state.init.primary_port = qp->hca_port->port_num; + qp_mod.state.init.access_ctrl = IB_AC_RDMA_READ | IB_AC_RDMA_WRITE | IB_AC_LOCAL_WRITE; + qp_mod.state.init.opts = IB_MOD_QP_PRIMARY_PORT | IB_MOD_QP_ACCESS_CTRL | IB_MOD_QP_PKEY; + + status = ib_modify_qp(qp->qp_handle, &qp_mod); + if (status) { + printf("ib_modify_qp failed (%d)\n", status); + goto fail; + } + + if (query_qp(qp)) { + printf("query failed\n"); + goto fail; + } + + return 0; + + fail: + return -1; +} + +int query_qp(struct qp_pack *qp) +{ + ib_api_status_t status; + + status = ib_query_qp(qp->qp_handle, &qp->qp_attr); + if (status) { + printf("ib_query_qp failed (%d)\n", status); + goto fail; + } + + return 0; + + fail: + return -1; +} + +int connect_qp(struct qp_pack *qp1, struct qp_pack *qp2) +{ + ib_api_status_t status; + ib_qp_mod_t qp_mod; + + /* Update attributes */ + if (query_qp(qp1)) { + printf("query failed\n"); + goto fail; + } + + if (query_qp(qp2)) { + printf("query failed\n"); + goto fail; + } + + /* Modify QP to RTR state */ + memset(&qp_mod, 0, sizeof(qp_mod)); + + qp_mod.req_state = IB_QPS_RTR; + qp_mod.state.rtr.rq_psn = 0x1234; /* random */ + qp_mod.state.rtr.dest_qp = qp2->qp_attr.num; + qp_mod.state.rtr.primary_av.dlid = qp2->hca_port->lid; + qp_mod.state.rtr.primary_av.static_rate = 1; + qp_mod.state.rtr.primary_av.port_num = qp1->hca_port->port_num; + + qp_mod.state.rtr.primary_av.conn.local_ack_timeout = 0; + qp_mod.state.rtr.primary_av.conn.path_mtu = IB_MTU_LEN_2048; + qp_mod.state.rtr.primary_av.conn.rnr_retry_cnt = 6; + qp_mod.state.rtr.primary_av.conn.seq_err_retry_cnt = 6; + + qp_mod.state.rtr.qkey = 0; + qp_mod.state.rtr.resp_res = 4; + qp_mod.state.rtr.rnr_nak_timeout = 6; + + qp_mod.state.rtr.opts = IB_MOD_QP_QKEY | IB_MOD_QP_PRIMARY_AV | IB_MOD_QP_RNR_NAK_TIMEOUT | IB_MOD_QP_RESP_RES; + + status = ib_modify_qp(qp1->qp_handle, &qp_mod); + if (status) { + printf("ib_modify_qp 1 failed (%d)\n", status); + goto fail; + } + + /* Modify QP to RTS state */ + memset(&qp_mod, 0, sizeof(qp_mod)); + + qp_mod.req_state = IB_QPS_RTS; + qp_mod.state.rts.sq_psn = 0x1234; + qp_mod.state.rts.retry_cnt = 7; + qp_mod.state.rts.rnr_retry_cnt = 7; + + qp_mod.state.rts.opts = IB_MOD_QP_RETRY_CNT | IB_MOD_QP_RNR_RETRY_CNT; + + status = ib_modify_qp(qp1->qp_handle, &qp_mod); + if (status) { + printf("ib_modify_qp 2 failed (%d)\n", status); + goto fail; + } + + return 0; + + fail: + return -1; +} + +#if 0 +/* Move the QP to the error state. Wait for the CQ to flush. */ +int move_qp_to_error(struct qp_pack *qp) +{ + ib_api_status_t status; + VAPI_qp_attr_t qp_attr; + VAPI_qp_attr_mask_t qp_attr_mask; + VAPI_qp_cap_t qp_cap; + + /* Modify QP to ERROR state */ + memset(&qp_attr, 0, sizeof(qp_attr)); + + qp_attr.qp_state = VAPI_ERR; + + qp_attr_mask = QP_ATTR_QP_STATE; + + vret = VAPI_modify_qp(qp->hca_handle, qp->qp_handle, &qp_attr, &qp_attr_mask, &qp_cap); + + if (vret != VAPI_OK) { + VAPI_ERR_LOG("VAPI_modify_qp(ERROR) failed ", vret); + goto fail; + } + + while(qp->wq_posted != 0) { + usleep(10000); + } + + return 0; + + fail: + return -1; +} +#endif + +#if 0 +int move_qp_to_reset(struct qp_pack *qp) +{ + ib_api_status_t status; + VAPI_qp_attr_t qp_attr; + VAPI_qp_attr_mask_t qp_attr_mask; + VAPI_qp_cap_t qp_cap; + + /* Modify QP to RESET state */ + memset(&qp_attr, 0, sizeof(qp_attr)); + + qp_attr.qp_state = VAPI_RESET; + + qp_attr_mask = QP_ATTR_QP_STATE; + + vret = VAPI_modify_qp(qp->hca_handle, qp->qp_handle, &qp_attr, &qp_attr_mask, &qp_cap); + + if (vret != VAPI_OK) { + VAPI_ERR_LOG("VAPI_modify_qp(ERROR) failed ", vret); + goto fail; + } + + return 0; + + fail: + return -1; +} + +int move_qp_to_drain(struct qp_pack *qp) +{ + ib_api_status_t status; + VAPI_qp_attr_t qp_attr; + VAPI_qp_attr_mask_t qp_attr_mask; + VAPI_qp_cap_t qp_cap; + + /* Modify QP to SQD state */ + memset(&qp_attr, 0, sizeof(qp_attr)); + + qp_attr.qp_state = VAPI_SQD; + qp_attr_mask = QP_ATTR_QP_STATE; + + vret = VAPI_modify_qp(qp->hca_handle, qp->qp_handle, &qp_attr, &qp_attr_mask, &qp_cap); + + if (vret != VAPI_OK) { + VAPI_ERR_LOG("VAPI_modify_qp(SQD) failed ", vret); + goto fail; + } + + return 0; + + fail: + return -1; +} +#endif + +int destroy_qp(struct qp_pack *qp) +{ + ib_api_status_t status; + + if (qp->qp_handle) { + status = ib_destroy_qp(qp->qp_handle, NULL); + if (status) { + printf("ib_destroy_qp failed (%d)\n", status); + } + qp->qp_handle = NULL; + } + + if (qp->cq_handle) { + status = ib_destroy_cq(qp->cq_handle, NULL); + if (status) { + printf("ib_destroy_cq failed (%d)\n", status); + } + qp->cq_handle = NULL; + } + + if (qp->pd_handle) { + status = ib_dealloc_pd(qp->pd_handle, NULL); + if (status) { + printf("ib_dealloc_pd failed (%d)\n", status); + } + qp->pd_handle = NULL; + } + + if (qp->hca_handle) { + status = ib_close_ca(qp->hca_handle, NULL); + if (status != IB_SUCCESS) { + printf("ib_close_ca failed (%d)\n", status); + } + qp->hca_handle = NULL; + } + + if (qp->al_handle) { + status = ib_close_al(qp->al_handle); + if (status != IB_SUCCESS) { + printf("ib_close_al failed (%d)\n", status); + } + qp->al_handle = NULL; + } + + return 0; +} + +/* Create and register a memory region which will be used for rdma transfer. */ +int create_mr(struct qp_pack *qp, struct mr_pack *mr, ib_access_t acl) { + + ib_api_status_t status; + ib_mr_create_t mr_create; + + mr->buf = malloc(mr->size); + if (mr->buf == NULL) { + printf("malloc failed\n"); + goto fail; + } + + mr_create.access_ctrl = acl; + mr_create.length = mr->size; + mr_create.vaddr = mr->buf; + + status = ib_reg_mem(qp->pd_handle, &mr_create, + &mr->lkey, &mr->rkey, &mr->mr_handle); + + if (status) { + printf("ib_reg_mem failed (%d)\n", status); + goto fail; + } + + return 0; + + fail: + return -1; +} + +/* Unregister and free a local memory region. */ +int delete_mr(struct mr_pack *mr) { + ib_api_status_t status; + + status = ib_dereg_mr(mr->mr_handle); + if (status) { + printf("ib_dereg_mr failed (%d)\n", status); + goto fail; + } + + free(mr->buf); + mr->buf = NULL; + + return 0; + + fail: + return -1; +} + +#if 0 +int post_receive_buffer(struct qp_pack *qp, struct mr_pack *mr) +{ + VAPI_rr_desc_t rwr; + VAPI_sg_lst_entry_t dataseg[1]; + ib_api_status_t status; + + /* Post receive buffer on qp1 */ + memset(&rwr, 0, sizeof(rwr)); + rwr.id = (VAPI_wr_id_t)(MT_virt_addr_t)qp; + rwr.opcode = VAPI_RECEIVE; + rwr.comp_type = VAPI_SIGNALED; + + rwr.sg_lst_len = 1; + rwr.sg_lst_p = dataseg; + + dataseg[0].addr = (unsigned long)mr->buf; + dataseg[0].len = mr->size; + dataseg[0].lkey = mr->rep_mrw.l_key; + + /* Post the work request */ + vret = VAPI_post_rr(qp->hca_handle, qp->qp_handle, &rwr); + + cl_atomic_inc(&qp->wq_posted); + + if (vret != VAPI_OK) { + VAPI_ERR_LOG("VAPI_post_rr failed ", vret); + atomic_dec(&qp->wq_posted); + goto fail; + } + + return 0; + + fail: + return -1; +} +#endif + +int post_send_buffer(struct qp_pack *qp, struct mr_pack *local_mr, + struct mr_pack *remote_mr, ib_wr_type_t opcode, int offset, size_t length) +{ + ib_api_status_t status; + ib_local_ds_t dataseg; + ib_send_wr_t swr; + + /* Post send buffer on qp2. */ + memset(&swr, 0, sizeof(swr)); + swr.wr_id = (uint64_t) (uintptr_t)qp; + swr.wr_type = opcode; + + if (length == 0) { + swr.num_ds = 0; + swr.ds_array = NULL; + } else { + swr.num_ds = 1; + swr.ds_array = &dataseg; + + dataseg.length = (uint32_t)length; + dataseg.vaddr = (uint64_t) (uintptr_t) local_mr->buf + offset; + dataseg.lkey = local_mr->lkey; + } + + if (opcode == WR_RDMA_WRITE) { + swr.remote_ops.vaddr = (uint64_t) (uintptr_t) remote_mr->buf; + swr.remote_ops.rkey = remote_mr->rkey; + } + + cl_atomic_inc(&qp->wq_posted); + + status = ib_post_send(qp->qp_handle, &swr, NULL); + + if (status != IB_SUCCESS) { + cl_atomic_dec(&qp->wq_posted); + printf("ib_post_send failed (%d)\n", status); + goto fail; + } + + return 0; + + fail: + return -1; +} diff --git a/branches/WOF2-3/tests/wsd/user/test2/ibwrap.h b/branches/WOF2-3/tests/wsd/user/test2/ibwrap.h new file mode 100644 index 00000000..0b30d8c4 --- /dev/null +++ b/branches/WOF2-3/tests/wsd/user/test2/ibwrap.h @@ -0,0 +1,41 @@ +#include + +struct qp_pack { + ib_al_handle_t al_handle; + ib_ca_handle_t hca_handle; + ib_pd_handle_t pd_handle; + ib_qp_handle_t qp_handle; + ib_cq_handle_t cq_handle; + + atomic32_t wq_posted; + + ib_ca_attr_t *ca_attr; + ib_port_attr_t *hca_port; /* Port to use */ + ib_qp_attr_t qp_attr; +}; + +struct mr_pack { + void *buf; + size_t size; + + net32_t lkey; + net32_t rkey; +TO_LONG_PTR( ib_mr_handle_t , mr_handle) ; +}; + + +extern int create_mr(struct qp_pack *qp, struct mr_pack *mr, ib_access_t acl); +extern int delete_mr(struct mr_pack *mr); +extern int create_qp(struct qp_pack *qp); +extern int connect_qp(struct qp_pack *qp1, struct qp_pack *qp2); +extern int post_send_buffer(struct qp_pack *qp, struct mr_pack *local_mr, struct mr_pack *remote_mr, ib_wr_type_t opcode, int offset, size_t length); +extern int destroy_qp(struct qp_pack *qp); +extern int query_qp(struct qp_pack *qp); + +#if 0 +extern int post_receive_buffer(struct qp_pack *qp, struct mr_pack *mr); +extern int move_qp_to_error(struct qp_pack *qp); +extern int move_qp_to_reset(struct qp_pack *qp); +extern int move_qp_to_drain(struct qp_pack *qp); +extern int control_qp_completion(struct qp_pack *qp, int enable); +#endif diff --git a/branches/WOF2-3/tests/wsd/user/test2/test2.c b/branches/WOF2-3/tests/wsd/user/test2/test2.c new file mode 100644 index 00000000..5a1348b0 --- /dev/null +++ b/branches/WOF2-3/tests/wsd/user/test2/test2.c @@ -0,0 +1,64 @@ +#include + +#include "ibwrap.h" + +int main(void) +{ + struct qp_pack qp1, qp2; + struct mr_pack mr1, mr2, mr3; + + while(1) { + /* Create both QP and move them into the RTR state */ + if (create_qp(&qp1) || create_qp(&qp2)) { + printf("Failed to create a QP\n"); + goto done; + } + + /* Connect both QP */ + if (connect_qp(&qp1, &qp2)) { + printf("Failed to connect QP1\n"); + goto done; + } + if (connect_qp(&qp2, &qp1)) { + printf("Failed to connect QP2\n"); + goto done; + } + + /* Create RDMA buffers */ + mr1.size = mr2.size = mr3.size = 500000; + if (create_mr(&qp1, &mr1, IB_AC_LOCAL_WRITE | IB_AC_RDMA_WRITE | IB_AC_RDMA_READ) || + create_mr(&qp1, &mr2, IB_AC_LOCAL_WRITE | IB_AC_RDMA_WRITE | IB_AC_RDMA_READ) || + create_mr(&qp2, &mr3, IB_AC_LOCAL_WRITE | IB_AC_RDMA_WRITE | IB_AC_RDMA_READ)) { + printf("Cannot create RDMA buffers\n"); + goto done; + } + + if (post_send_buffer(&qp1, &mr1, &mr3, WR_RDMA_WRITE, 1004, mr1.size-1004)) { + printf("post_send_buffer failed1\n"); + goto done; + } + + if (post_send_buffer(&qp1, &mr2, &mr3, WR_RDMA_WRITE, 1004, mr1.size-1004)) { + printf("post_send_buffer failed1\n"); + goto done; + } + + /* Wait for both wr to complete. */ + while(qp1.wq_posted != 0) { + Sleep(100); + } + + if (delete_mr(&mr1) || delete_mr(&mr2) || delete_mr(&mr3)) { + printf("cannot destroy mr\n"); + } + + if (destroy_qp(&qp1) || destroy_qp(&qp2)) { + printf("cannot destroy QP\n"); + } + } + + printf("End of test\n"); + + done: + return 0; +} diff --git a/branches/WOF2-3/tests/wsd/user/test3/ibwrap.c b/branches/WOF2-3/tests/wsd/user/test3/ibwrap.c new file mode 100644 index 00000000..dd3e90d3 --- /dev/null +++ b/branches/WOF2-3/tests/wsd/user/test3/ibwrap.c @@ -0,0 +1,610 @@ +#include "ibwrap.h" + +/* CQ completion handler */ +static void ib_cq_comp(void *cq_context) +{ + ib_api_status_t status; + ib_wc_t wclist; + ib_wc_t *free_wclist; + ib_wc_t *done_wclist; + BOOL need_rearm; + struct qp_pack *qp = cq_context; + + need_rearm = TRUE; + + again: + while(1) { + + wclist.p_next = NULL; + + free_wclist = &wclist; + + status = ib_poll_cq(qp->cq_handle, &free_wclist, &done_wclist); + + switch (status) { + case IB_NOT_FOUND: + goto done; + + case IB_SUCCESS: + //printf("got a completion\n"); + break; + + default: + printf("ib_poll_cq failed badly (%d)\n", status); + need_rearm = FALSE; + goto done; + } + +#if 0 + if (done_wclist->status != IB_WCS_SUCCESS) { + printf("operation failed - status %d\n", done_wclist->status); + } +#endif + + need_rearm = TRUE; + + /* We have some completions. */ + while(done_wclist) { + + cl_atomic_dec(&qp->wq_posted); + + if (qp->comp) qp->comp(qp, done_wclist); + + done_wclist = done_wclist->p_next; + }; + + if (free_wclist != NULL) { + /* No more completions */ + goto done; + } + }; + + done: + if (need_rearm) { + + need_rearm = FALSE; + + status = ib_rearm_cq(qp->cq_handle, FALSE); + if (status != IB_SUCCESS) { + printf("ib_poll_cq failed badly (%d)\n", status); + } + + goto again; + } +} + +/* Enable or disable completion. */ +int control_qp_completion(struct qp_pack *qp, int enable) +{ + ib_api_status_t status; + + if (enable) { + + status = ib_rearm_cq(qp->cq_handle, FALSE); + if (status) { + printf("ib_rearm_cq failed (%d)\n", status); + goto fail; + } + + } + + return 0; + + fail: + return -1; +} + +int create_qp(struct qp_pack *qp) +{ + ib_api_status_t status; + ib_cq_create_t cq_create; + ib_qp_create_t qp_create; + ib_qp_mod_t qp_mod; + ib_net64_t *guid_list = NULL; + size_t adapter_count; + size_t ca_attr_size = 0; + + qp->wq_posted = 0; + + /* Open AL */ + status = ib_open_al(&qp->al_handle); + if (status != IB_SUCCESS) { + printf("ib_open_al failed (%d)\n", status); + goto fail; + } + + /* Find a CA */ + adapter_count = 10; + guid_list = malloc(sizeof(ib_net64_t) * adapter_count); + if (guid_list == NULL) { + printf("can't get enough memory (%d, %d)\n", sizeof(ib_net64_t), adapter_count); + goto fail; + } + + status = ib_get_ca_guids(qp->al_handle, guid_list, &adapter_count); + if (status != IB_SUCCESS) { + printf("second ib_get_ca_guids failed (%d)\n", status); + goto fail; + } + + if (adapter_count < 1) { + printf("not enough CA (%d)\n", adapter_count); + goto fail; + } + + /* Open the hca */ + status = ib_open_ca(qp->al_handle, guid_list[0], NULL, /* event handler */ + NULL, /* context */ + &qp->hca_handle); + + if (status != IB_SUCCESS) { + printf("ib_open_ca failed (%d)\n", status); + goto fail; + } + + + /* Get the HCA attributes */ + ca_attr_size = 0; + query_ca_again: + status = ib_query_ca(qp->hca_handle, qp->ca_attr, &ca_attr_size); + + if (status == IB_INSUFFICIENT_MEMORY) { + + printf("ib_query_ca needs %d bytes\n", ca_attr_size); + + /* Allocate more memory */ + qp->ca_attr = malloc(ca_attr_size); + + if (qp->ca_attr) + goto query_ca_again; + else { + printf("HeapAlloc failed\n"); + goto fail; + } + } else if (status != IB_SUCCESS) { + printf("ib_query_ca failed (%d)\n", status); + goto fail; + } + + /* Find a port */ + if (qp->ca_attr->num_ports < 1) { + printf("not enough ports (%d)\n", qp->ca_attr->num_ports); + goto fail; + } + + qp->hca_port = &qp->ca_attr->p_port_attr[0]; + + /* Create a PD */ + status = ib_alloc_pd(qp->hca_handle, IB_PDT_NORMAL, qp, /* context */ + &qp->pd_handle); + if (status) { + printf("ib_alloc_pd failed (%d)\n", status); + goto fail; + } + + /* Create a CQ */ + cq_create.size = 50; + cq_create.pfn_comp_cb = ib_cq_comp; + cq_create.h_wait_obj = NULL; /* we use signaled completion instead */ + + status = ib_create_cq(qp->hca_handle, &cq_create, qp, /* context */ + NULL, /* async handler */ + &qp->cq_handle); + if (status) { + printf("ib_create_cq failed (%d)\n", status); + goto fail; + } + + status = ib_rearm_cq(qp->cq_handle, FALSE); + if (status) { + printf("ib_rearm_cq failed (%d)\n", status); + goto fail; + } + + /* Arm the CQ handler */ + if (control_qp_completion(qp, 1) != 0) { + printf("control_qp_completion failed\n"); + goto fail; + } + + /* Create a qp */ + cl_memclr(&qp_create, sizeof(ib_qp_create_t)); + qp_create.qp_type = IB_QPT_RELIABLE_CONN; + qp_create.h_rdd = NULL; + qp_create.sq_depth = 255; + qp_create.rq_depth = 255; + qp_create.sq_sge = 1; + qp_create.rq_sge = 1; + qp_create.h_rq_cq = qp->cq_handle; + qp_create.h_sq_cq = qp->cq_handle; + qp_create.sq_signaled = TRUE; + + status = ib_create_qp(qp->pd_handle, &qp_create, qp, /* context */ + NULL, /* async handler */ + &qp->qp_handle); + if (status) { + printf("ib_create_qp failed (%d)\n", status); + goto fail; + } + + /* Modify QP to INIT state */ + memset(&qp_mod, 0, sizeof(qp_mod)); + + qp_mod.req_state = IB_QPS_INIT; + qp_mod.state.init.pkey_index = 0; + qp_mod.state.init.primary_port = qp->hca_port->port_num; + qp_mod.state.init.access_ctrl = IB_AC_RDMA_READ | IB_AC_RDMA_WRITE | IB_AC_LOCAL_WRITE; + qp_mod.state.init.opts = IB_MOD_QP_PRIMARY_PORT | IB_MOD_QP_ACCESS_CTRL | IB_MOD_QP_PKEY; + + status = ib_modify_qp(qp->qp_handle, &qp_mod); + if (status) { + printf("ib_modify_qp failed (%d)\n", status); + goto fail; + } + + if (query_qp(qp)) { + printf("query failed\n"); + goto fail; + } + + return 0; + + fail: + return -1; +} + +int query_qp(struct qp_pack *qp) +{ + ib_api_status_t status; + + status = ib_query_qp(qp->qp_handle, &qp->qp_attr); + if (status) { + printf("ib_query_qp failed (%d)\n", status); + goto fail; + } + + return 0; + + fail: + return -1; +} + +int connect_qp(struct qp_pack *qp1, struct qp_pack *qp2) +{ + ib_api_status_t status; + ib_qp_mod_t qp_mod; + + /* Update attributes */ + if (query_qp(qp1)) { + printf("query failed\n"); + goto fail; + } + + if (query_qp(qp2)) { + printf("query failed\n"); + goto fail; + } + + /* Modify QP to RTR state */ + memset(&qp_mod, 0, sizeof(qp_mod)); + + qp_mod.req_state = IB_QPS_RTR; + qp_mod.state.rtr.rq_psn = 0x1234; /* random */ + qp_mod.state.rtr.dest_qp = qp2->qp_attr.num; + qp_mod.state.rtr.primary_av.dlid = qp2->hca_port->lid; + qp_mod.state.rtr.primary_av.static_rate = 1; + qp_mod.state.rtr.primary_av.port_num = qp1->hca_port->port_num; + + qp_mod.state.rtr.primary_av.conn.local_ack_timeout = 0; + qp_mod.state.rtr.primary_av.conn.path_mtu = IB_MTU_LEN_2048; + qp_mod.state.rtr.primary_av.conn.rnr_retry_cnt = 6; + qp_mod.state.rtr.primary_av.conn.seq_err_retry_cnt = 6; + + qp_mod.state.rtr.qkey = 0; + qp_mod.state.rtr.resp_res = 4; + qp_mod.state.rtr.rnr_nak_timeout = 6; + + qp_mod.state.rtr.opts = IB_MOD_QP_QKEY | IB_MOD_QP_PRIMARY_AV | IB_MOD_QP_RNR_NAK_TIMEOUT | IB_MOD_QP_RESP_RES; + + status = ib_modify_qp(qp1->qp_handle, &qp_mod); + if (status) { + printf("ib_modify_qp 1 failed (%d)\n", status); + goto fail; + } + + /* Modify QP to RTS state */ + memset(&qp_mod, 0, sizeof(qp_mod)); + + qp_mod.req_state = IB_QPS_RTS; + qp_mod.state.rts.sq_psn = 0x1234; + qp_mod.state.rts.retry_cnt = 7; + qp_mod.state.rts.rnr_retry_cnt = 7; + + qp_mod.state.rts.opts = IB_MOD_QP_RETRY_CNT | IB_MOD_QP_RNR_RETRY_CNT; + + status = ib_modify_qp(qp1->qp_handle, &qp_mod); + if (status) { + printf("ib_modify_qp 2 failed (%d)\n", status); + goto fail; + } + + return 0; + + fail: + return -1; +} + +#if 0 +/* Move the QP to the error state. Wait for the CQ to flush. */ +int move_qp_to_error(struct qp_pack *qp) +{ + ib_api_status_t status; + VAPI_qp_attr_t qp_attr; + VAPI_qp_attr_mask_t qp_attr_mask; + VAPI_qp_cap_t qp_cap; + + /* Modify QP to ERROR state */ + memset(&qp_attr, 0, sizeof(qp_attr)); + + qp_attr.qp_state = VAPI_ERR; + + qp_attr_mask = QP_ATTR_QP_STATE; + + vret = VAPI_modify_qp(qp->hca_handle, qp->qp_handle, &qp_attr, &qp_attr_mask, &qp_cap); + + if (vret != VAPI_OK) { + VAPI_ERR_LOG("VAPI_modify_qp(ERROR) failed ", vret); + goto fail; + } + + while(qp->wq_posted != 0) { + usleep(10000); + } + + return 0; + + fail: + return -1; +} +#endif + +#if 0 +int move_qp_to_reset(struct qp_pack *qp) +{ + ib_api_status_t status; + VAPI_qp_attr_t qp_attr; + VAPI_qp_attr_mask_t qp_attr_mask; + VAPI_qp_cap_t qp_cap; + + /* Modify QP to RESET state */ + memset(&qp_attr, 0, sizeof(qp_attr)); + + qp_attr.qp_state = VAPI_RESET; + + qp_attr_mask = QP_ATTR_QP_STATE; + + vret = VAPI_modify_qp(qp->hca_handle, qp->qp_handle, &qp_attr, &qp_attr_mask, &qp_cap); + + if (vret != VAPI_OK) { + VAPI_ERR_LOG("VAPI_modify_qp(ERROR) failed ", vret); + goto fail; + } + + return 0; + + fail: + return -1; +} + +int move_qp_to_drain(struct qp_pack *qp) +{ + ib_api_status_t status; + VAPI_qp_attr_t qp_attr; + VAPI_qp_attr_mask_t qp_attr_mask; + VAPI_qp_cap_t qp_cap; + + /* Modify QP to SQD state */ + memset(&qp_attr, 0, sizeof(qp_attr)); + + qp_attr.qp_state = VAPI_SQD; + qp_attr_mask = QP_ATTR_QP_STATE; + + vret = VAPI_modify_qp(qp->hca_handle, qp->qp_handle, &qp_attr, &qp_attr_mask, &qp_cap); + + if (vret != VAPI_OK) { + VAPI_ERR_LOG("VAPI_modify_qp(SQD) failed ", vret); + goto fail; + } + + return 0; + + fail: + return -1; +} +#endif + +int destroy_qp(struct qp_pack *qp) +{ + ib_api_status_t status; + + if (qp->qp_handle) { + status = ib_destroy_qp(qp->qp_handle, NULL); + if (status) { + printf("ib_destroy_qp failed (%d)\n", status); + } + qp->qp_handle = NULL; + } + + if (qp->cq_handle) { + status = ib_destroy_cq(qp->cq_handle, NULL); + if (status) { + printf("ib_destroy_cq failed (%d)\n", status); + } + qp->cq_handle = NULL; + } + + if (qp->pd_handle) { + status = ib_dealloc_pd(qp->pd_handle, NULL); + if (status) { + printf("ib_dealloc_pd failed (%d)\n", status); + } + qp->pd_handle = NULL; + } + + if (qp->hca_handle) { + status = ib_close_ca(qp->hca_handle, NULL); + if (status != IB_SUCCESS) { + printf("ib_close_ca failed (%d)\n", status); + } + qp->hca_handle = NULL; + } + + if (qp->al_handle) { + status = ib_close_al(qp->al_handle); + if (status != IB_SUCCESS) { + printf("ib_close_al failed (%d)\n", status); + } + qp->al_handle = NULL; + } + + return 0; +} + +/* Create and register a memory region which will be used for rdma transfer. */ +int create_mr(struct qp_pack *qp, struct mr_pack *mr, size_t len) { + + ib_api_status_t status; + ib_mr_create_t mr_create; + + mr->size = len; + + mr->buf = malloc(mr->size); + if (mr->buf == NULL) { + printf("malloc failed\n"); + goto fail; + } + + mr_create.access_ctrl = IB_AC_LOCAL_WRITE | IB_AC_RDMA_WRITE | IB_AC_RDMA_READ; + mr_create.length = mr->size; + mr_create.vaddr = mr->buf; + + status = ib_reg_mem(qp->pd_handle, &mr_create, + &mr->lkey, &mr->rkey, &mr->mr_handle); + + if (status) { + printf("ib_reg_mem failed (%d)\n", status); + goto fail; + } + + return 0; + + fail: + return -1; +} + +/* Unregister and free a local memory region. */ +int delete_mr(struct mr_pack *mr) { + ib_api_status_t status; + + status = ib_dereg_mr(mr->mr_handle); + if (status) { + printf("ib_dereg_mr failed (%d)\n", status); + goto fail; + } + + free(mr->buf); + memset(mr, 0, sizeof(struct mr_pack)); + + return 0; + + fail: + return -1; +} + +int post_receive_buffer(struct qp_pack *qp, struct mr_pack *mr, + int offset, size_t length) +{ + ib_api_status_t status; + ib_local_ds_t dataseg; + ib_recv_wr_t rwr; + + /* Post receive buffer on qp1 */ + memset(&rwr, 0, sizeof(rwr)); + + rwr.wr_id = (uint64_t) (uintptr_t)qp; + + rwr.num_ds = 1; + rwr.ds_array = &dataseg; + + dataseg.length = (uint32_t)length; + dataseg.vaddr = (uint64_t) (uintptr_t) mr->buf + offset; + dataseg.lkey = mr->lkey; + + cl_atomic_inc(&qp->wq_posted); + + status = ib_post_recv(qp->qp_handle, &rwr, NULL); + + if (status != IB_SUCCESS) { + cl_atomic_dec(&qp->wq_posted); + printf("ib_post_send failed (%d)\n", status); + goto fail; + } + + return 0; + + fail: + return -1; +} + +int post_send_buffer(struct qp_pack *qp, struct mr_pack *local_mr, + struct mr_pack *remote_mr, ib_wr_type_t opcode, int offset, size_t length) +{ + ib_api_status_t status; + ib_local_ds_t dataseg; + ib_send_wr_t swr; + + /* Post send buffer on qp2. */ + memset(&swr, 0, sizeof(swr)); + swr.wr_id = (uint64_t) (uintptr_t)qp; + swr.wr_type = opcode; + + if (length == 0) { + swr.num_ds = 0; + swr.ds_array = NULL; + } else { + swr.num_ds = 1; + swr.ds_array = &dataseg; + + dataseg.length = (uint32_t)length; + dataseg.vaddr = (uint64_t) (uintptr_t) local_mr->buf + offset; + dataseg.lkey = local_mr->lkey; + } + + if (opcode == WR_RDMA_WRITE || opcode == WR_RDMA_READ) { + swr.remote_ops.vaddr = (uint64_t) (uintptr_t) remote_mr->buf; + swr.remote_ops.rkey = remote_mr->rkey; + + printf("RDMA %d %I64x %x - %I64x %x\n", + swr.ds_array[0].length, + swr.ds_array[0].vaddr, + swr.ds_array[0].lkey, + swr.remote_ops.vaddr, + swr.remote_ops.rkey); + printf("REM RDMA %p %x\n", remote_mr->buf, remote_mr->rkey); + } + + cl_atomic_inc(&qp->wq_posted); + + status = ib_post_send(qp->qp_handle, &swr, NULL); + + if (status != IB_SUCCESS) { + cl_atomic_dec(&qp->wq_posted); + printf("ib_post_send failed (%d)\n", status); + goto fail; + } + + return 0; + + fail: + return -1; +} diff --git a/branches/WOF2-3/tests/wsd/user/test3/ibwrap.h b/branches/WOF2-3/tests/wsd/user/test3/ibwrap.h new file mode 100644 index 00000000..c4e4ec37 --- /dev/null +++ b/branches/WOF2-3/tests/wsd/user/test3/ibwrap.h @@ -0,0 +1,44 @@ +#include + +struct qp_pack { + ib_al_handle_t al_handle; + ib_ca_handle_t hca_handle; + ib_pd_handle_t pd_handle; + ib_qp_handle_t qp_handle; + ib_cq_handle_t cq_handle; + + atomic32_t wq_posted; + + ib_ca_attr_t *ca_attr; + ib_port_attr_t *hca_port; /* Port to use */ + ib_qp_attr_t qp_attr; + + void (*comp)(struct qp_pack *, ib_wc_t *wc); +}; + +struct mr_pack { + void *buf; + size_t size; + + net32_t lkey; + net32_t rkey; +TO_LONG_PTR( ib_mr_handle_t , mr_handle) ; +}; + + +extern int create_mr(struct qp_pack *qp, struct mr_pack *mr, ib_access_t acl); +extern int delete_mr(struct mr_pack *mr); +extern int create_qp(struct qp_pack *qp); +extern int connect_qp(struct qp_pack *qp1, struct qp_pack *qp2); +extern int post_send_buffer(struct qp_pack *qp, struct mr_pack *local_mr, struct mr_pack *remote_mr, ib_wr_type_t opcode, int offset, size_t length); +extern int destroy_qp(struct qp_pack *qp); +extern int query_qp(struct qp_pack *qp); +int post_receive_buffer(struct qp_pack *qp, struct mr_pack *mr, + int offset, size_t length); + +#if 0 +extern int move_qp_to_error(struct qp_pack *qp); +extern int move_qp_to_reset(struct qp_pack *qp); +extern int move_qp_to_drain(struct qp_pack *qp); +extern int control_qp_completion(struct qp_pack *qp, int enable); +#endif diff --git a/branches/WOF2-3/tests/wsd/user/test3/test3.c b/branches/WOF2-3/tests/wsd/user/test3/test3.c new file mode 100644 index 00000000..a202da82 --- /dev/null +++ b/branches/WOF2-3/tests/wsd/user/test3/test3.c @@ -0,0 +1,126 @@ +#include + +#include "ibwrap.h" + +#define SR_BUFFER_SIZE 1576 +#define RDMA_BUFFER 500000 + +struct qp_pack qp1, qp2; +struct mr_pack mr1_send, mr1_recv, mr2_send, mr2_recv, mr1_rdma, mr2_rdma; + +void qp1_comp(struct qp_pack *qp, ib_wc_t *wc) +{ + printf("QP1 - completion error %d for op %d\n", wc->status, wc->wc_type); + + if (wc->status) goto done; + + if (wc->wc_type == IB_WC_RECV) { + + if (create_mr(qp, &mr1_rdma, RDMA_BUFFER)) { + printf("Cannot create RDMA buffer\n"); + goto done; + } + + if (post_send_buffer(qp, &mr1_rdma, &mr2_rdma, WR_RDMA_READ, 0, RDMA_BUFFER)) { + printf("post_send_buffer failed1\n"); + goto done; + } + + if (post_send_buffer(qp, &mr1_send, NULL, WR_SEND, 0, 40)) { + printf("post_send_buffer failed1\n"); + goto done; + } + } + +done: + ; +} + +void qp2_comp(struct qp_pack *qp, ib_wc_t *wc) +{ + printf("QP2 - completion error %d for op %d\n", wc->status, wc->wc_type); + + if (wc->status) goto done; + + if (wc->wc_type == IB_WC_RECV) { + delete_mr(&mr2_rdma); + } + +done: + ; +} + +int main(void) +{ + int i; + + /* Create both QP and move them into the RTR state */ + if (create_qp(&qp1) || create_qp(&qp2)) { + printf("Failed to create a QP\n"); + goto done; + } + qp1.comp = qp1_comp; + qp2.comp = qp2_comp; + + /* Connect both QP */ + if (connect_qp(&qp1, &qp2)) { + printf("Failed to connect QP1\n"); + goto done; + } + if (connect_qp(&qp2, &qp1)) { + printf("Failed to connect QP2\n"); + goto done; + } + + /* Create RDMA buffers */ + mr1_send.size = mr1_recv.size = mr2_send.size = mr2_recv.size = SR_BUFFER_SIZE; + if (create_mr(&qp1, &mr1_send, 5*SR_BUFFER_SIZE) || + create_mr(&qp1, &mr1_recv, 6*SR_BUFFER_SIZE) || + create_mr(&qp2, &mr2_send, 5*SR_BUFFER_SIZE) || + create_mr(&qp2, &mr2_recv, 6*SR_BUFFER_SIZE)) { + printf("Cannot create RDMA buffers\n"); + goto done; + } + + /* Post receives */ + for (i=0; i<6; i++) { + if (post_receive_buffer(&qp1, &mr1_recv, i*SR_BUFFER_SIZE, SR_BUFFER_SIZE)) { + printf("post_recv_buffer failed1\n"); + goto done; + } + } + + for (i=0; i<6; i++) { + if (post_receive_buffer(&qp2, &mr2_recv, i*SR_BUFFER_SIZE, SR_BUFFER_SIZE)) { + printf("post_recv_buffer failed1\n"); + goto done; + } + } + + if (create_mr(&qp2, &mr2_rdma, RDMA_BUFFER)) { + printf("Cannot create RDMA buffer\n"); + } + + if (post_send_buffer(&qp2, &mr2_send, NULL, WR_SEND, 0, 40)) { + printf("post_send_buffer failed1\n"); + goto done; + } + +#if 0 + /* Wait for both wr to complete. */ + while(qp1.wq_posted != 0) { + Sleep(100); + } +#endif + + Sleep(4000); + + if (destroy_qp(&qp1) || destroy_qp(&qp2)) { + printf("cannot destroy QP\n"); + } + + printf("End of test\n"); + + done: + return 0; +} diff --git a/branches/WOF2-3/tests/wsd/user/ttcp/SOURCES b/branches/WOF2-3/tests/wsd/user/ttcp/SOURCES new file mode 100644 index 00000000..2012f091 --- /dev/null +++ b/branches/WOF2-3/tests/wsd/user/ttcp/SOURCES @@ -0,0 +1,13 @@ +TARGETNAME=ttcp +TARGETPATH=..\..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE=PROGRAM +UMTYPE=console +USE_MSVCRT=1 + +SOURCES=\ + ttcp.c + +TARGETLIBS=\ + $(SDK_LIB_PATH)\ws2_32.lib + +MSC_WARNING_LEVEL= /W3 diff --git a/branches/WOF2-3/tests/wsd/user/ttcp/makefile b/branches/WOF2-3/tests/wsd/user/ttcp/makefile new file mode 100644 index 00000000..9c985f57 --- /dev/null +++ b/branches/WOF2-3/tests/wsd/user/ttcp/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the Windows NT DDK +# + +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/branches/WOF2-3/tests/wsd/user/ttcp/ttcp.c b/branches/WOF2-3/tests/wsd/user/ttcp/ttcp.c new file mode 100644 index 00000000..aba293e3 --- /dev/null +++ b/branches/WOF2-3/tests/wsd/user/ttcp/ttcp.c @@ -0,0 +1,860 @@ +/* + * T T C P . C + * + * Test TCP connection. Makes a connection on port 5001 + * and transfers fabricated buffers or data copied from stdin. + * + * Ported to MS Windows enviroment, Nov. 1999 + * Lily Yang, Intel Corp. + * Always in sinkmode, use only real time for measurement. + * So, -s and -v options are not accepted. + * + * Usable on 4.2, 4.3, and 4.1a systems by defining one of + * BSD42 BSD43 (BSD41a) + * Machines using System V with BSD sockets should define SYSV. + * + * Modified for operation under 4.2BSD, 18 Dec 84 + * T.C. Slattery, USNA + * Minor improvements, Mike Muuss and Terry Slattery, 16-Oct-85. + * Modified in 1989 at Silicon Graphics, Inc. + * catch SIGPIPE to be able to print stats when receiver has died + * for tcp, don't look for sentinel during reads to allow small transfers + * increased default buffer size to 8K, nbuf to 2K to transfer 16MB + * moved default port to 5001, beyond IPPORT_USERRESERVED + * make sinkmode default because it is more popular, + * -s now means don't sink/source + * count number of read/write system calls to see effects of + * blocking from full socket buffers + * for tcp, -D option turns off buffered writes (sets TCP_NODELAY sockopt) + * buffer alignment options, -A and -O + * print stats in a format that's a bit easier to use with grep & awk + * for SYSV, mimic BSD routines to use most of the existing timing code + * Modified by Steve Miller of the University of Maryland, College Park + * -b sets the socket buffer size (SO_SNDBUF/SO_RCVBUF) + * Modified Sept. 1989 at Silicon Graphics, Inc. + * restored -s sense at request of tcs@brl + * Modified Oct. 1991 at Silicon Graphics, Inc. + * use getopt(3) for option processing, add -f and -T options. + * SGI IRIX 3.3 and 4.0 releases don't need #define SYSV. + * + * Distribution Status - + * Public Domain. Distribution Unlimited. + */ + + +#include +#include +#include +#include + +#define DBG_SPEW 0 + +#if DBG_SPEW +#define DEBUG_OUT(x) { \ + char str[256];\ + sprintf(str, "%s:%d:0x%x:0x%x: %s", "ttcp", __LINE__, GetCurrentProcessId(),\ + GetCurrentThreadId(), (x));\ + OutputDebugString(str);\ +} + +#define DEBUG_OUT1(x,p) { \ + char str[256];\ + sprintf(str, "%s:%d:0x%x:0x%x: buf=0x%p %s", "ttcp", __LINE__, GetCurrentProcessId(),\ + GetCurrentThreadId(), (p),(x));\ + OutputDebugString(str);\ +} +#else +#define DEBUG_OUT(x) +#define DEBUG_OUT1(x,p) +#endif + +struct sockaddr_in sinhim; +struct sockaddr_in frominet; + +int domain, fromlen; + +int buflen = 8 * 1024; /* length of buffer */ +char *buf; /* ptr to dynamic buffer */ +int nbuf = 2 * 32; /* number of buffers to send in sinkmode */ + +int bufoffset = 0; /* align buffer to this */ +int bufalign = 16*1024; /* modulo this */ + +int udp = 0; /* 0 = tcp, !0 = udp */ +int options = 0; /* socket options */ +int one = 1; /* for 4.3 BSD style setsockopt() */ +short port = 5001; /* TCP port number */ +char *host = 0; /* ptr to name of host */ +int trans; /* 0=receive, !0=transmit mode */ +int nodelay = 0; /* set TCP_NODELAY socket option */ +int b_flag = 0; /* use mread() */ +int sockbufsize = 0; /* socket buffer size to use */ +char fmt = 'K'; /* output format: k = kilobits, K = kilobytes, + * m = megabits, M = megabytes, + * g = gigabits, G = gigabytes */ +int touchdata = 0; /* access data after reading */ + +#ifndef errno +extern int errno; +#endif + +char Usage[] = "\ +Usage: ttcp -t [-options] host \n\ + ttcp -r [-options]\n\ +Common options:\n\ + -l ## length of bufs read from or written to network (default 8192)\n\ + -u use UDP instead of TCP\n\ + -p ## port number to send to or listen at (default 5001)\n\ + -A align the start of buffers to this modulus (default 16384)\n\ + -O start buffers at this offset from the modulus (default 0)\n\ + -d set SO_DEBUG socket option\n\ + -b ## set socket buffer size (if supported)\n\ + -f X format for rate: k,K = kilo{bit,byte}; m,M = mega; g,G = giga\n\ +Options specific to -t:\n\ + -n## number of source bufs written to network (default 2048)\n\ + -D don't buffer TCP writes (sets TCP_NODELAY socket option)\n\ +Options specific to -r:\n\ + -B for -s, only output full blocks as specified by -l (for TAR)\n\ + -T \"touch\": access each byte as it's read\n\ +"; + +double nbytes = 0; /* bytes on net */ +unsigned long numCalls; /* # of I/O system calls */ +double realt; /* user, real time (seconds) */ +SOCKET fd = (SOCKET)SOCKET_ERROR; +SOCKET fd_orig = (SOCKET)SOCKET_ERROR; + +BOOL DoGracefulShutdown(SOCKET sock); +void err(); +void mes(); +void winsockInit(); +void commandLine(); +void bind_socket(); +void showTime(PSYSTEMTIME pst); +void pattern(); +int Nread(); +int Nwrite(); +int mread(); +void delay(); +void timer(); +double time_elapsed(); +char *outfmt(); + +int __cdecl main(int argc, char **argv) +{ + SYSTEMTIME time0, time1; + int cnt; + + commandLine(argc, argv); + winsockInit(); + + memset(&sinhim,0,sizeof(sinhim)); + + if(trans) { + struct hostent * pHostAddr; + // xmitr + memset(&sinhim,0,sizeof(sinhim)); + sinhim.sin_family = AF_INET; + if (atoi(host) > 0 ) { + // Numeric + sinhim.sin_addr.s_addr = inet_addr(host); + } else { + if ((pHostAddr=gethostbyname(host)) == NULL) + err("bad hostname"); + sinhim.sin_addr.s_addr = *(u_long*)pHostAddr->h_addr; + } + sinhim.sin_port = htons(port); + } + + + if (udp && buflen < 5) { + buflen = 5; // send more than the sentinel size + } + + if ( (buf = (char *)malloc(buflen+bufalign)) == (char *)NULL) + err("malloc"); + if (bufalign != 0) + buf +=(bufalign - ((uintptr_t)buf % bufalign) + bufoffset) % bufalign; + + fprintf(stdout, "ttcp PID=0x%x TID=0x%x\n", GetCurrentProcessId(), GetCurrentThreadId()); + + if (trans) { + fprintf(stdout, "ttcp -t: buflen=%d, nbuf=%d, align=%d/%d, port=%d", + buflen, nbuf, bufalign, bufoffset, port); + if (sockbufsize) + fprintf(stdout, ", sockbufsize=%d", sockbufsize); + fprintf(stdout, " %s -> %s\n", udp?"udp":"tcp", host); + } else { + fprintf(stdout, + "ttcp -r: buflen=%d, nbuf=%d, align=%d/%d, port=%d", + buflen, nbuf, bufalign, bufoffset, port); + if (sockbufsize) + fprintf(stdout, ", sockbufsize=%d", sockbufsize); + fprintf(stdout, " %s\n", udp?"udp":"tcp"); + } + DEBUG_OUT(("socket() start.\n")); + if ((fd = socket(AF_INET, udp?SOCK_DGRAM:SOCK_STREAM, 0)) == INVALID_SOCKET){ + err("socket"); + } + DEBUG_OUT(("socket() finish.\n")); + fprintf(stdout, "fd=0x%x\n",fd); + + DEBUG_OUT(("bind_socket() start.\n")); + if (trans) { + bind_socket(fd, 0); + } else { + bind_socket(fd, port); + } + DEBUG_OUT(("bind_socket() finish.\n")); + + /* + * CLOSE_ISSUE + * If the SO_LINGER option is enabled, then closesocket() seems to wake + * up a separate thread (previously spawned by the switch during connect() call) + * after l_linger seconds, and this thread takes care of calling GetOverlappedResult, + * DeregisterMemory, etc. In this case, there is no delay in the WSACleanup() + * call, and both the provide WSPCloseSocket() and WSPCleanup() calls are + * seen. + */ +#if 0 + { + struct linger ling; + ling.l_onoff = 1; + ling.l_linger = 3; + DEBUG_OUT(("setsockopt(SO_LINGER) start.\n")); + if (setsockopt(fd, SOL_SOCKET, SO_LINGER, + (const char*)&ling, sizeof(ling)) < 0){ + err("setsockopt: SO_LINGER"); + } + DEBUG_OUT(("setsockopt(SO_LINGER) finished.\n")); + } + +#endif + + if (sockbufsize) { + if (trans) { + if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, + (const char*)&sockbufsize,sizeof sockbufsize) < 0) + err("setsockopt: sndbuf"); + } else { + if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, + (const char*)&sockbufsize,sizeof sockbufsize) < 0) + err("setsockopt: rcvbuf"); + } + } + + if (!udp) { + if (trans) { + // We are the client if transmitting + if (options) { + if( setsockopt(fd, SOL_SOCKET, options, (const char*)&one, + sizeof(one)) < 0) + err("setsockopt"); + } + if (nodelay) { + struct protoent *p; + p = getprotobyname("tcp"); + if( p && setsockopt(fd, p->p_proto, TCP_NODELAY, + (const char*)&one, sizeof(one)) < 0) + err("setsockopt: nodelay"); + } + DEBUG_OUT(("connect() start.\n")); + if(connect(fd, (const struct sockaddr *)&sinhim, sizeof(sinhim) ) < 0){ + err("connect"); + } + DEBUG_OUT(("connect() finished.\n")); + fprintf(stdout,"ttcp -t: TCP connection established! \n"); + } else { + + // otherwise, we are the server and + //should listen for the connections + + DEBUG_OUT(("listen() start.\n")); + listen(fd,1); // workaround for alleged u4.2 bug + DEBUG_OUT(("listen() finish.\n")); + if(options) { + if( setsockopt(fd, SOL_SOCKET, options, (const char*)&one, + sizeof(one)) < 0) + err("setsockopt"); + } + fromlen = sizeof(frominet); + domain = AF_INET; + fd_orig=fd; + + DEBUG_OUT(("accept() start.\n")); + if((fd=accept(fd, (struct sockaddr *)&frominet, &fromlen) ) == INVALID_SOCKET){ + err("accept"); + } + DEBUG_OUT(("accept() finish.\n")); + + { + struct sockaddr_in peer; + int peerlen = sizeof(peer); + + fprintf(stdout,"closesocket(fd_orig)..\n"); + if (closesocket(fd_orig)==SOCKET_ERROR){ + err("socket close fd_orig!"); + fd_orig = (SOCKET)SOCKET_ERROR; + } + + + if (getpeername(fd, (struct sockaddr *) &peer, + &peerlen) < 0) { + err("getpeername"); + } + fprintf(stdout,"ttcp -r: accept from %s fd=0x%p\n", + inet_ntoa(peer.sin_addr), fd); + } + } + } + + if (trans) { + fprintf(stdout,"ttcp -t: start transmitting ...\n"); + pattern( buf, buflen ); + if(udp) (void)Nwrite( fd, buf, 4 ); // rcvr start + timer(&time0); + while (nbuf-- && Nwrite(fd,buf,buflen) == buflen){ + nbytes += buflen; +#if DBG_SPEW + fprintf(stdout,"nbytes=%.0f nbuf=%d, buflen=%d\n", nbytes, nbuf, buflen); +#endif + } + timer(&time1); +#if DBG_SPEW + fprintf(stdout,"nbytes=%.0f nbuf=%d\n", nbytes, nbuf); +#endif + if(udp) (void)Nwrite( fd, buf, 4 ); // rcvr end + } else { + + fprintf(stdout,"ttcp -r: start receiving ...\n"); + if (udp) { + while ((cnt=Nread(fd,buf,buflen)) > 0) { + static int going = 0; + if( cnt <= 4 ) { + if( going ) + break; // "EOF" + going = 1; + timer(&time0); + } else { + nbytes += cnt; + } + } + } else { + timer(&time0); + while ((cnt=Nread(fd,buf,buflen)) > 0) { + nbytes += cnt; +#if DBG_SPEW + fprintf(stdout,"nbytes=%.0f cnt=%d\n", nbytes, cnt); +#endif + } + timer(&time1); +#if DBG_SPEW + fprintf(stdout,"nbytes=%.0f cnt=%d\n", nbytes, cnt); +#endif + } + } + + if(0){ + fprintf(stdout, "Pausing before close...\n"); + _getch(); + } + +#if 1 + /* + * CLOSE_ISSUE + * Calling closesocket() without any linger option results in + * approximately a 15 second delay in the WSACleanup() call, + * with no provider WSPCloseSocket() or WSPCleanup() calls ever + * seen. + */ + DEBUG_OUT(("closesocket() start.\n")); + fprintf(stdout,"closesocket(fd)..\n"); + if (closesocket(fd)==SOCKET_ERROR) { + err("socket close fd!"); + } + DEBUG_OUT(("closesocket() finish.\n")); +#else + /* + * CLOSE_ISSUE + * If DoGracefulShutdown is called, then the closesocket() (in DoGracefulShutdown()) + * seems to wake up a separate thread (previously spawned by the switch during + * connect() call) and this thread takes care of calling GetOverlappedResult, + * DeregisterMemory, etc. In this case, there is no delay in the WSACleanup() + * call, and both the provide WSPCloseSocket() and WSPCleanup() calls are + * seen. + */ + DoGracefulShutdown(fd); +#endif + + + if(0){ + fprintf(stdout, "Pausing before cleanup...\n"); + _getch(); + } + + + DEBUG_OUT(("WSACleanup() start.\n")); + fprintf(stdout,"WSACleanup()..\n"); + /* + * CLOSE_ISSUE without SO_LINGER, or DoGracefulShutdown(), WSACleanup() + * can hang for 15 seconds. No WSPCloseSocket() or WSPCleanup() calls + * are seen in the provider for this case. + */ + if (WSACleanup()==SOCKET_ERROR) { + err("WSACleanup"); + } + DEBUG_OUT(("WSACleanup() finish.\n")); + + if(0){ + fprintf(stdout, "Pausing after cleanup...\n"); + _getch(); + } + + realt = time_elapsed(&time0, &time1); + + if(udp&&trans) { + (void)Nwrite( fd, buf, 4 ); // rcvr end + (void)Nwrite( fd, buf, 4 ); // rcvr end + (void)Nwrite( fd, buf, 4 ); // rcvr end + (void)Nwrite( fd, buf, 4 ); // rcvr end + } + if( realt <= 0.0 ) realt = 0.001; + fprintf(stdout, + "ttcp %s: %.0f bytes in %.2f real MilliSeconds = %s/sec +++\n", + trans?"-t":"-r", + nbytes, realt, outfmt(nbytes*1000/realt)); + fprintf(stdout, + "ttcp %s: %d I/O calls, msec/call = %.2f, calls/sec = %.2f\n", + trans?"-t":"-r", + numCalls, + realt/((double)numCalls), + ((double)(1000*numCalls))/realt); + fflush(stdout); + +#if 0 + if(1){ + fprintf(stdout, "Pausing before return...\n"); + _getch(); + } +#endif + + return(0); +} + +void err(char *s) +{ + fprintf(stderr,"ERROR -- ttcp %s: ", trans?"-t":"-r"); + fprintf(stderr,"%s\n",s); + fprintf(stderr, "Cleaning up\n"); + if(fd!=SOCKET_ERROR){ + if (closesocket(fd)==SOCKET_ERROR) + fprintf(stderr, "socket close fd!"); + } + + fprintf(stderr,"\n"); + exit(-1); +} + +void mes(char *s) +{ + fprintf(stdout,"ttcp %s: %s\n", trans?"-t":"-r", s); + return; +} + +void pattern(char *cp, int cnt) +{ + register char c; + c = 0; + while( cnt-- > 0 ) { + while( !isprint((c&0x7F)) ) c++; + *cp++ = (c++&0x7F); + } +} + +char *outfmt(double b) +{ + static char obuf[50]; + switch (fmt) { + case 'G': + sprintf(obuf, "%.2f GByte", b / 1024.0 / 1024.0 / 1024.0); + break; + default: + case 'K': + sprintf(obuf, "%.2f KByte", b / 1024.0); + break; + case 'M': + sprintf(obuf, "%.2f MByte", b / 1024.0 / 1024.0); + break; + case 'g': + sprintf(obuf, "%.2f Gbit", b * 8.0 / 1024.0 / 1024.0 / 1024.0); + break; + case 'k': + sprintf(obuf, "%.2f Kbit", b * 8.0 / 1024.0); + break; + case 'm': + sprintf(obuf, "%.2f Mbit", b * 8.0 / 1024.0 / 1024.0); + break; + } + return obuf; +} + +/* + * T I M E R + */ +void timer(PSYSTEMTIME time) +{ + GetSystemTime(time); +// showTime(time); +} +/* + * N R E A D + */ +int Nread(int fd, void *buf, int count) +{ + struct sockaddr_in from; + int len = sizeof(from); + register int cnt; + if( udp ) { + cnt = recvfrom( fd, buf, count, 0, (struct sockaddr *)&from, &len ); + numCalls++; + } else { + if( b_flag ) + cnt = mread( fd, buf, count ); // fill buf + else { + DEBUG_OUT(("recv() start.\n")); + cnt = recv(fd, buf, count, 0); + DEBUG_OUT(("recv() finish.\n")); + numCalls++; + } + if (touchdata && cnt > 0) { + register int c = cnt, sum=0; + register char *b = buf; + while (c--) + sum += *b++; + } + } + return(cnt); +} + +/* + * N W R I T E + */ +int Nwrite(int fd, void *buf, int count) +{ + register int cnt; + if( udp ) { +again: + cnt = sendto( fd, buf, count, 0, (const struct sockaddr *)&sinhim, + sizeof(sinhim) ); + numCalls++; + if( cnt<0 && WSAGetLastError() == WSAENOBUFS ) { + delay(18000); + goto again; + } + } else { + DEBUG_OUT1(("send() start.\n"),buf); + cnt = send(fd, buf, count, 0); + DEBUG_OUT1(("send() finish.\n"),buf); + numCalls++; + } + return(cnt); +} + +void delay(int us) +{ + struct timeval tv; + + tv.tv_sec = 0; + tv.tv_usec = us; + (void)select( 1, NULL, NULL, NULL, &tv ); +} + +/* + * M R E A D + * + * This function performs the function of a read(II) but will + * call read(II) multiple times in order to get the requested + * number of characters. This can be necessary because + * network connections don't deliver data with the same + * grouping as it is written with. Written by Robert S. Miles, BRL. + */ +int mread(int fd, char *bufp, unsigned int n) +{ + register unsigned count = 0; + register int nread; + + do { + nread = recv(fd, bufp, n-count, 0); + numCalls++; + if(nread < 0) { + perror("ttcp_mread"); + return(-1); + } + if(nread == 0) + return((int)count); + count += (unsigned)nread; + bufp += nread; + } while(count < n); + + return((int)count); +} + +void winsockInit() +{ + // initialization of the winsock DLL first + WORD wVersionRequested; + WSADATA wsaData; + int ret; + + wVersionRequested = MAKEWORD( 2, 0 ); + ret = WSAStartup( wVersionRequested, &wsaData ); + if ( ret != 0 ) { + // Tell the user that we couldn't find a usable + // WinSock DLL. + err(" Winsock Error!"); + } + + // Confirm that the WinSock DLL supports 2.0. + // Note that if the DLL supports versions greater + // than 2.0 in addition to 2.0, it will still return + // 2.0 in wVersion since that is the version we + // requested. + + if ( LOBYTE( wsaData.wVersion ) != 2 || + HIBYTE( wsaData.wVersion ) != 0 ) { + // Tell the user that we couldn't find a usable + // WinSock DLL. + WSACleanup( ); + err(" Winsock Error!"); + } + return; + +} + +void commandLine(int argc, char ** argv) +{ + int i; + char carg; + + if (argc < 2) goto usage; + + i=1; + while (ih_addr; + } +#else + addr.sin_addr.s_addr = INADDR_ANY; +#endif + + // bind with the socket + if (bind(fd, (const struct sockaddr*)&addr, + sizeof(addr)) == SOCKET_ERROR) { + err("socket error!"); + } + free(hostname); + return; + +} + +void showTime(PSYSTEMTIME pst) +{ + fprintf(stdout, "It is now %02u:%02u:%02u:%03u on %02u/%02u/%4u.\n", + pst->wHour, pst->wMinute, pst->wSecond, pst->wMilliseconds, \ + pst->wMonth, pst->wDay, pst->wYear); +} + +double time_elapsed(PSYSTEMTIME pst0,PSYSTEMTIME pst1) +{ + double diff=0; + diff += pst1->wMilliseconds - pst0->wMilliseconds; + diff += (pst1->wSecond - pst0->wSecond)*1000; + diff += (pst1->wMinute - pst0->wMinute)*60*1000; + diff += (pst1->wHour - pst0->wHour)*60*60*1000; + diff += (pst1->wHour - pst0->wHour)*60*60*1000; + diff += (pst1->wDay - pst0->wDay)*24*60*60*1000; + diff += (pst1->wMonth - pst0->wMonth)*30*24*60*60*1000; + diff += (pst1->wYear - pst0->wYear)*365*24*60*60*1000; + return diff; +} + +// Do a graceful shutdown of a the given socket sock. +BOOL DoGracefulShutdown(SOCKET sock) +{ + BOOL bRetVal = FALSE; + WSAEVENT hEvent = WSA_INVALID_EVENT; + long lNetworkEvents = 0; + int status = 0; + + hEvent = WSACreateEvent(); + if (hEvent == WSA_INVALID_EVENT) + { + fprintf(stderr, "DoGracefulShutdown: WSACreateEvent failed: %d\n", + WSAGetLastError()); + goto CLEANUP; + } + + DEBUG_OUT(("WSAEventSelect() start.\n")); + lNetworkEvents = FD_CLOSE; + if (WSAEventSelect(sock, hEvent, lNetworkEvents) != 0) + { + fprintf(stderr, "DoGracefulShutdown: WSAEventSelect failed: %d\n", + WSAGetLastError()); + goto CLEANUP; + } + DEBUG_OUT(("WSAEventSelect() finish.\n")); + + DEBUG_OUT(("shutdown() start.\n")); + if (shutdown(sock, SD_SEND) != 0) + { + fprintf(stderr, "DoGracefulShutdown: shutdown failed: %d\n", + WSAGetLastError()); + goto CLEANUP; + } + DEBUG_OUT(("shutdown() finish.\n")); + + DEBUG_OUT(("WaitForSingleObject() start.\n")); + if (WaitForSingleObject(hEvent, INFINITE) != WAIT_OBJECT_0) + { + fprintf(stderr, "DoGracefulShutdown: WaitForSingleObject failed: %d\n", + WSAGetLastError()); + goto CLEANUP; + } + DEBUG_OUT(("WaitForSingleObject() finish.\n")); + + do + { + char buf[128]; + + DEBUG_OUT(("recv() start.\n")); + status = recv(sock, buf, sizeof(buf), 0); + DEBUG_OUT(("recv() finish.\n")); + } while (!(status == 0 || status == SOCKET_ERROR)); + + DEBUG_OUT(("closesocket() start.\n")); + if (closesocket(sock) != 0) + { + fprintf(stderr, "DoGracefulShutdown: closesocket failed: %d\n", + WSAGetLastError()); + goto CLEANUP; + } + DEBUG_OUT(("closesocket() finish.\n")); + + printf("Socket %d has been closed gracefully\n", sock); + sock = INVALID_SOCKET; + bRetVal = TRUE; + +CLEANUP: + + if (hEvent != WSA_INVALID_EVENT) + { + WSACloseEvent(hEvent); + hEvent = WSA_INVALID_EVENT; + } + + if (sock != INVALID_SOCKET) + { + fprintf(stderr, "DoGracefulShutdown: Can't close socket gracefully. " + "So, closing it anyway ... \n"); + closesocket(sock); + sock = INVALID_SOCKET; + } + + return bRetVal; +} + diff --git a/branches/WOF2-3/tools/dirs b/branches/WOF2-3/tools/dirs new file mode 100644 index 00000000..58507221 --- /dev/null +++ b/branches/WOF2-3/tools/dirs @@ -0,0 +1,9 @@ +DIRS = \ + wsdinstall \ + vstat \ + nsc \ + perftests \ + part_man \ + infiniband-diags \ + qlgcvnic_config \ + ndinstall diff --git a/branches/WOF2-3/tools/infiniband-diags/dirs b/branches/WOF2-3/tools/infiniband-diags/dirs new file mode 100644 index 00000000..60fcb0f9 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/dirs @@ -0,0 +1 @@ +DIRS = src diff --git a/branches/WOF2-3/tools/infiniband-diags/include/grouping.h b/branches/WOF2-3/tools/infiniband-diags/include/grouping.h new file mode 100644 index 00000000..811e372f --- /dev/null +++ b/branches/WOF2-3/tools/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; + unsigned char chassisnum; + unsigned char chassistype; + unsigned 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/branches/WOF2-3/tools/infiniband-diags/include/ibdiag_common.h b/branches/WOF2-3/tools/infiniband-diags/include/ibdiag_common.h new file mode 100644 index 00000000..9b2add72 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/include/ibdiag_common.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2006-2007 The Regents of the University of California. + * Copyright (c) 2004-2009 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 + +extern int ibverbose; +extern char *ibd_ca; +extern int ibd_ca_port; +extern enum MAD_DEST ibd_dest_type; +extern ib_portid_t *ibd_sm_id; +extern int ibd_timeout; + +/*========================================================*/ +/* External interface */ +/*========================================================*/ + +#undef DEBUG +#define DEBUG(fmt, ...) do { \ + if (ibdebug) IBDEBUG(fmt, ## __VA_ARGS__); \ +} while (0) +#define VERBOSE(fmt, ...) do { \ + if (ibverbose) IBVERBOSE(fmt, ## __VA_ARGS__); \ +} while (0) +#define IBERROR(fmt, ...) iberror(__FUNCTION__, fmt, ## __VA_ARGS__) + +struct ibdiag_opt { + const char *name; + char letter; + unsigned has_arg; + const char *arg_tmpl; + const char *description; +}; + +extern int ibdiag_process_opts(int argc, char *const argv[], void *context, + const char *exclude_common_str, + const struct ibdiag_opt custom_opts[], + int (*custom_handler) (void *cxt, int val, + char *optarg), + const char *usage_args, + const char *usage_examples[]); +extern void ibdiag_show_usage(); +extern void iberror(const char *fn, char *msg, ...); + +#endif /* _IBDIAG_COMMON_H_ */ diff --git a/branches/WOF2-3/tools/infiniband-diags/include/ibnetdiscover.h b/branches/WOF2-3/tools/infiniband-diags/include/ibnetdiscover.h new file mode 100644 index 00000000..02266155 --- /dev/null +++ b/branches/WOF2-3/tools/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/branches/WOF2-3/tools/infiniband-diags/include/windows/config.h b/branches/WOF2-3/tools/infiniband-diags/include/windows/config.h new file mode 100644 index 00000000..c6365bf1 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/include/windows/config.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2009 Intel Corp, 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 _CONFIG_H_ +#define _CONFIG_H_ + +#include <_errno.h> +#include <_string.h> + +#endif /* _CONFIG_H_ */ diff --git a/branches/WOF2-3/tools/infiniband-diags/include/windows/ibdiag_version.h b/branches/WOF2-3/tools/infiniband-diags/include/windows/ibdiag_version.h new file mode 100644 index 00000000..6464d3e5 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/include/windows/ibdiag_version.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2008 Voltaire Inc. All rights reserved. + * Copyright (c) 2009 Intel Corp, 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_ + +// TODO: figure this out +#define IBDIAG_VERSION "@OPENIB_REV@" + +#endif /* _IBDIAG_VERSION_H_ */ diff --git a/branches/WOF2-3/tools/infiniband-diags/patches/ibping-cdecl.diff b/branches/WOF2-3/tools/infiniband-diags/patches/ibping-cdecl.diff new file mode 100644 index 00000000..50a309a1 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/patches/ibping-cdecl.diff @@ -0,0 +1,19 @@ +ib-diags/ibping: thread callback must be __cdecl for windows + +The WDK build environment builds using stdcall, but the thread callback must be __cdecl. +This is a windows specific build issue with the ported ib-diags. + +Signed-off-by: Sean Hefty +--- +diff -up -r -I '\$Id:' infiniband-diags.git/src/ibping.c infiniband-diags/src/ibping.c +--- infiniband-diags.git/src/ibping.c 2009-05-27 12:50:36.676250000 -0700 ++++ infiniband-diags/src/ibping.c 2009-05-27 12:31:12.443931500 -0700 +@@ -141,7 +141,7 @@ static uint64_t minrtt = ~0ull, maxrtt, + static uint64_t start, total_time, replied, lost, ntrans; + static ib_portid_t portid = {0}; + +-void report(int sig) ++void __cdecl report(int sig) + { + total_time = cl_get_time_stamp() - start; + diff --git a/branches/WOF2-3/tools/infiniband-diags/src/dirs b/branches/WOF2-3/tools/infiniband-diags/src/dirs new file mode 100644 index 00000000..822f3257 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/dirs @@ -0,0 +1,19 @@ +DIRS = \ + ibaddr \ + iblinkinfo \ + ibnetdiscover \ + ibping \ + ibportstate \ + ibqueryerrors \ + ibroute \ + ibsendtrap \ + ibstat \ + ibsysstat \ + ibtracert \ + mcm_rereg_test \ + perfquery \ + saquery \ + sminfo \ + smpdump \ + smpquery \ + vendstat \ No newline at end of file diff --git a/branches/WOF2-3/tools/infiniband-diags/src/grouping.c b/branches/WOF2-3/tools/infiniband-diags/src/grouping.c new file mode 100644 index 00000000..048efc74 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/grouping.c @@ -0,0 +1,785 @@ +/* + * Copyright (c) 2004-2007 Voltaire Inc. All rights reserved. + * Copyright (c) 2007 Xsigo Systems Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/*========================================================*/ +/* FABRIC SCANNER SPECIFIC DATA */ +/*========================================================*/ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include + +#include + +#include "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 */ +char 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 }; +char 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 }; +char 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 }; +char 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 */ +char 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 */ +char 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 }; +char 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 }; +char 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 }; +char 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; + uint64_t 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/branches/WOF2-3/tools/infiniband-diags/src/ibaddr.c b/branches/WOF2-3/tools/infiniband-diags/src/ibaddr.c new file mode 100644 index 00000000..6e174580 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/ibaddr.c @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2004-2009 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include + +#include +#include + +#include "ibdiag_common.h" + +struct ibmad_port *srcport; + +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_via(nodeinfo, portid, IB_ATTR_NODE_INFO, 0, 0, srcport)) + return -1; + + if (!smp_query_via(portinfo, portid, IB_ATTR_PORT_INFO, portnum, 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(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 int show_lid, show_gid; + +static int process_opt(void *context, int ch, char *optarg) +{ + switch (ch) { + case 'g': + show_gid = 1; + break; + case 'l': + show_lid++; + break; + case 'L': + show_lid = -100; + break; + default: + return -1; + } + return 0; +} + +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 }; + int port = 0; + + const struct ibdiag_opt opts[] = { + {"gid_show", 'g', 0, NULL, "show gid address only"}, + {"lid_show", 'l', 0, NULL, "show lid range only"}, + {"Lid_show", 'L', 0, NULL, "show lid range (in decimal) only"}, + {0} + }; + char usage_args[] = "[]"; + const char *usage_examples[] = { + "\t\t# local port's address", + "32\t\t# show lid range and gid of lid 32", + "-G 0x8f1040023\t# same but using guid address", + "-l 32\t\t# show lid range only", + "-L 32\t\t# show decimal lid range only", + "-g 32\t\t# show gid address only", + NULL + }; + + ibdiag_process_opts(argc, argv, NULL, "L", opts, process_opt, + usage_args, usage_examples); + + argc -= optind; + argv += optind; + + if (argc > 1) + port = strtoul(argv[1], 0, 0); + + if (!show_lid && !show_gid) + show_lid = show_gid = 1; + + srcport = mad_rpc_open_port(ibd_ca, ibd_ca_port, mgmt_classes, 3); + if (!srcport) + IBERROR("Failed to open '%s' port '%d'", ibd_ca, ibd_ca_port); + + if (argc) { + if (ib_resolve_portid_str_via(&portid, argv[0], ibd_dest_type, + ibd_sm_id, srcport) < 0) + IBERROR("can't resolve destination port %s", argv[0]); + } else { + if (ib_resolve_self_via(&portid, &port, 0, srcport) < 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"); + + mad_rpc_close_port(srcport); + exit(0); +} diff --git a/branches/WOF2-3/tools/infiniband-diags/src/ibaddr/SOURCES b/branches/WOF2-3/tools/infiniband-diags/src/ibaddr/SOURCES new file mode 100644 index 00000000..1a98f88c --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/ibaddr/SOURCES @@ -0,0 +1,34 @@ +TARGETNAME = ibaddr +TARGETPATH = ..\..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = PROGRAM + +UMTYPE = console +UMENTRY = main + +USE_MSVCRT = 1 + +SOURCES = ..\ibaddr.c ..\ibdiag_common.c ..\ibdiag_windows.c ibaddr.rc + +INCLUDES = ..\..\include;..\..\include\windows;\ + ..\..\..\..\ulp\libibnetdisc\include;\ + ..\..\..\..\ulp\libibmad\include;\ + ..\..\..\..\ulp\libibumad\include;\ + ..\..\..\..\inc;..\..\..\..\inc\user;\ + ..\..\..\..\inc\user\linux; + +C_DEFINES = $(C_DEFINES) /DHAVE_CONFIG_H /DUSE_INET + +TARGETLIBS = \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\libibmad.lib \ + $(TARGETPATH)\*\libibumad.lib \ + $(TARGETPATH)\*\libibnetdisc.lib +!else + $(TARGETPATH)\*\libibmadd.lib \ + $(TARGETPATH)\*\libibumadd.lib \ + $(TARGETPATH)\*\libibnetdiscd.lib +!endif + +MSC_WARNING_LEVEL = /W3 /WX /wd4007 diff --git a/branches/WOF2-3/tools/infiniband-diags/src/ibaddr/ibaddr.rc b/branches/WOF2-3/tools/infiniband-diags/src/ibaddr/ibaddr.rc new file mode 100644 index 00000000..c7341a87 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/ibaddr/ibaddr.rc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef DBG +#define VER_FILEDESCRIPTION_STR "InfiniBand Address Information (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "InfiniBand Address Information" +#endif + +#define VER_INTERNALNAME_STR "ibaddr.exe" +#define VER_ORIGINALFILENAME_STR "ibaddr.exe" + +#include diff --git a/branches/WOF2-3/tools/infiniband-diags/src/ibaddr/makefile b/branches/WOF2-3/tools/infiniband-diags/src/ibaddr/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/ibaddr/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\..\inc\openib.def diff --git a/branches/WOF2-3/tools/infiniband-diags/src/ibdiag_common.c b/branches/WOF2-3/tools/infiniband-diags/src/ibdiag_common.c new file mode 100644 index 00000000..99861f13 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/ibdiag_common.c @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2006-2007 The Regents of the University of California. + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/** + * Define common functions which can be included in the various C based diags. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +int ibverbose; +char *ibd_ca; +int ibd_ca_port; +enum MAD_DEST ibd_dest_type = IB_DEST_LID; +ib_portid_t *ibd_sm_id; +int ibd_timeout; + +static ib_portid_t sm_portid = { 0 }; + +static const char *prog_name; +static const char *prog_args; +static const char **prog_examples; +static struct option *long_opts; +static const struct ibdiag_opt *opts_map[256]; + +const static char *get_build_version(void) +{ + return "BUILD VERSION: " IBDIAG_VERSION " Build date: " __DATE__ " " + __TIME__; +} + +static void pretty_print(int start, int width, const char *str) +{ + int len = width - start; + const char *p, *e; + + while (1) { + while (isspace(*str)) + str++; + p = str; + do { + e = p + 1; + p = strchr(e, ' '); + } while (p && p - str < len); + if (!p) { + fprintf(stderr, "%s", str); + break; + } + if (e - str == 1) + e = p; + fprintf(stderr, "%.*s\n%*s", (int)(e - str), str, start, ""); + str = e; + } +} + +void ibdiag_show_usage() +{ + struct option *o = long_opts; + int n; + + fprintf(stderr, "\nUsage: %s [options] %s\n\n", prog_name, + prog_args ? prog_args : ""); + + if (long_opts[0].name) + fprintf(stderr, "Options:\n"); + for (o = long_opts; o->name; o++) { + const struct ibdiag_opt *io = opts_map[o->val]; + n = fprintf(stderr, " --%s", io->name); + if (isprint(io->letter)) + n += fprintf(stderr, ", -%c", io->letter); + if (io->has_arg) + n += fprintf(stderr, " %s", + io->arg_tmpl ? io->arg_tmpl : ""); + if (io->description && *io->description) { + n += fprintf(stderr, "%*s ", 24 - n > 0 ? 24 - n : 0, + ""); + pretty_print(n, 74, io->description); + } + fprintf(stderr, "\n"); + } + + if (prog_examples) { + const char **p; + fprintf(stderr, "\nExamples:\n"); + for (p = prog_examples; *p && **p; p++) + fprintf(stderr, " %s %s\n", prog_name, *p); + } + + fprintf(stderr, "\n"); + + exit(2); +} + +static int process_opt(int ch, char *optarg) +{ + int val; + + switch (ch) { + case 'h': + case 'u': + ibdiag_show_usage(); + break; + case 'V': + fprintf(stderr, "%s %s\n", prog_name, get_build_version()); + exit(0); + case 'e': + madrpc_show_errors(1); + break; + case 'v': + ibverbose++; + break; + case 'd': + ibdebug++; + madrpc_show_errors(1); + umad_debug(ibdebug - 1); + break; + case 'C': + ibd_ca = optarg; + break; + case 'P': + ibd_ca_port = strtoul(optarg, 0, 0); + break; + case 'D': + ibd_dest_type = IB_DEST_DRPATH; + break; + case 'L': + ibd_dest_type = IB_DEST_LID; + break; + case 'G': + ibd_dest_type = IB_DEST_GUID; + break; + case 't': + val = strtoul(optarg, 0, 0); + madrpc_set_timeout(val); + ibd_timeout = val; + break; + case 's': + /* srcport is not required when resolving via IB_DEST_LID */ + if (ib_resolve_portid_str_via(&sm_portid, optarg, IB_DEST_LID, + 0, NULL) < 0) + IBERROR("cannot resolve SM destination port %s", + optarg); + ibd_sm_id = &sm_portid; + break; + default: + return -1; + } + + return 0; +} + +static const struct ibdiag_opt common_opts[] = { + {"Ca", 'C', 1, "", "Ca name to use"}, + {"Port", 'P', 1, "", "Ca port number to use"}, + {"Direct", 'D', 0, NULL, "use Direct address argument"}, + {"Lid", 'L', 0, NULL, "use LID address argument"}, + {"Guid", 'G', 0, NULL, "use GUID address argument"}, + {"timeout", 't', 1, "", "timeout in ms"}, + {"sm_port", 's', 1, "", "SM port lid"}, + {"errors", 'e', 0, NULL, "show send and receive errors"}, + {"verbose", 'v', 0, NULL, "increase verbosity level"}, + {"debug", 'd', 0, NULL, "raise debug level"}, + {"usage", 'u', 0, NULL, "usage message"}, + {"help", 'h', 0, NULL, "help message"}, + {"version", 'V', 0, NULL, "show version"}, + {0} +}; + +static void make_opt(struct option *l, const struct ibdiag_opt *o, + const struct ibdiag_opt *map[]) +{ + l->name = o->name; + l->has_arg = o->has_arg; + l->flag = NULL; + l->val = o->letter; + if (!map[l->val]) + map[l->val] = o; +} + +static struct option *make_long_opts(const char *exclude_str, + const struct ibdiag_opt *custom_opts, + const struct ibdiag_opt *map[]) +{ + struct option *long_opts, *l; + const struct ibdiag_opt *o; + unsigned n = 0; + + if (custom_opts) + for (o = custom_opts; o->name; o++) + n++; + + long_opts = malloc((sizeof(common_opts) / sizeof(common_opts[0]) + n) * + sizeof(*long_opts)); + if (!long_opts) + return NULL; + + l = long_opts; + + if (custom_opts) + for (o = custom_opts; o->name; o++) + make_opt(l++, o, map); + + for (o = common_opts; o->name; o++) { + if (exclude_str && strchr(exclude_str, o->letter)) + continue; + make_opt(l++, o, map); + } + + memset(l, 0, sizeof(*l)); + + return long_opts; +} + +static void make_str_opts(const struct option *o, char *p, unsigned size) +{ + unsigned i, n = 0; + + for (n = 0; o->name && n + 2 + o->has_arg < size; o++) { + p[n++] = (char)o->val; + for (i = 0; i < (unsigned)o->has_arg; i++) + p[n++] = ':'; + } + p[n] = '\0'; +} + +int ibdiag_process_opts(int argc, char *const argv[], void *cxt, + const char *exclude_common_str, + const struct ibdiag_opt custom_opts[], + int (*custom_handler) (void *cxt, int val, + char *optarg), + const char *usage_args, const char *usage_examples[]) +{ + char str_opts[1024]; + const struct ibdiag_opt *o; + + prog_name = argv[0]; + prog_args = usage_args; + prog_examples = usage_examples; + + long_opts = make_long_opts(exclude_common_str, custom_opts, opts_map); + if (!long_opts) + return -1; + + make_str_opts(long_opts, str_opts, sizeof(str_opts)); + + while (1) { + int ch = getopt_long(argc, argv, str_opts, long_opts, NULL); + if (ch == -1) + break; + o = opts_map[ch]; + if (!o) + ibdiag_show_usage(); + if (custom_handler) { + if (custom_handler(cxt, ch, optarg) && + process_opt(ch, optarg)) + ibdiag_show_usage(); + } else if (process_opt(ch, optarg)) + ibdiag_show_usage(); + } + + free(long_opts); + + return 0; +} + +void iberror(const char *fn, char *msg, ...) +{ + char buf[512]; + va_list va; + int n; + + va_start(va, msg); + n = vsprintf(buf, msg, va); + va_end(va); + buf[n] = 0; + + if (ibdebug) + printf("%s: iberror: [pid %d] %s: failed: %s\n", + prog_name ? prog_name : "", getpid(), fn, buf); + else + printf("%s: iberror: failed: %s\n", + prog_name ? prog_name : "", buf); + + exit(-1); +} diff --git a/branches/WOF2-3/tools/infiniband-diags/src/ibdiag_windows.c b/branches/WOF2-3/tools/infiniband-diags/src/ibdiag_windows.c new file mode 100644 index 00000000..419dde92 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/ibdiag_windows.c @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2009 Intel Corp., Inc. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION 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 "..\..\..\..\etc\user\getopt.c" + +#if USE_INET +#if WINVER < 0x600 +#include "..\..\..\..\etc\user\inet.c" +#endif +#endif \ No newline at end of file diff --git a/branches/WOF2-3/tools/infiniband-diags/src/iblinkinfo.c b/branches/WOF2-3/tools/infiniband-diags/src/iblinkinfo.c new file mode 100644 index 00000000..d0c9b137 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/iblinkinfo.c @@ -0,0 +1,419 @@ +/* + * Copyright (c) 2004-2009 Voltaire Inc. All rights reserved. + * Copyright (c) 2007 Xsigo Systems Inc. All rights reserved. + * Copyright (c) 2008 Lawrence Livermore National Lab. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "ibdiag_common.h" + +static char *node_name_map_file = NULL; +static nn_map_t *node_name_map = NULL; +static char *load_cache_file = NULL; + +static uint64_t guid = 0; +static char *guid_str = NULL; +static char *dr_path = NULL; +static int all = 0; + +static int down_links_only = 0; +static int line_mode = 0; +static int add_sw_settings = 0; +static int print_port_guids = 0; + +static unsigned int get_max(unsigned int num) +{ + unsigned r = 0; // r will be lg(num) + + while (num >>= 1) // unroll for more speed... + r++; + + return (1 << r); +} + +void get_msg(char *width_msg, char *speed_msg, int msg_size, ibnd_port_t * port) +{ + char buf[64]; + uint32_t max_speed = 0; + + uint32_t max_width = get_max(mad_get_field(port->info, 0, + IB_PORT_LINK_WIDTH_SUPPORTED_F) + & mad_get_field(port->remoteport->info, 0, + IB_PORT_LINK_WIDTH_SUPPORTED_F)); + if ((max_width & mad_get_field(port->info, 0, + IB_PORT_LINK_WIDTH_ACTIVE_F)) == 0) + // we are not at the max supported width + // print what we could be at. + snprintf(width_msg, msg_size, "Could be %s", + mad_dump_val(IB_PORT_LINK_WIDTH_ACTIVE_F, + buf, 64, &max_width)); + + max_speed = get_max(mad_get_field(port->info, 0, + IB_PORT_LINK_SPEED_SUPPORTED_F) + & mad_get_field(port->remoteport->info, 0, + IB_PORT_LINK_SPEED_SUPPORTED_F)); + if ((max_speed & mad_get_field(port->info, 0, + IB_PORT_LINK_SPEED_ACTIVE_F)) == 0) + // we are not at the max supported speed + // print what we could be at. + snprintf(speed_msg, msg_size, "Could be %s", + mad_dump_val(IB_PORT_LINK_SPEED_ACTIVE_F, + buf, 64, &max_speed)); +} + +void print_port(ibnd_node_t * node, ibnd_port_t * port) +{ + char width[64], speed[64], state[64], physstate[64]; + char remote_guid_str[256]; + char remote_str[256]; + char link_str[256]; + char width_msg[256]; + char speed_msg[256]; + char ext_port_str[256]; + int iwidth, ispeed, istate, iphystate; + int n = 0; + + if (!port) + return; + + iwidth = mad_get_field(port->info, 0, IB_PORT_LINK_WIDTH_ACTIVE_F); + ispeed = mad_get_field(port->info, 0, IB_PORT_LINK_SPEED_ACTIVE_F); + istate = mad_get_field(port->info, 0, IB_PORT_STATE_F); + iphystate = mad_get_field(port->info, 0, IB_PORT_PHYS_STATE_F); + + remote_guid_str[0] = '\0'; + remote_str[0] = '\0'; + link_str[0] = '\0'; + width_msg[0] = '\0'; + speed_msg[0] = '\0'; + + /* C14-24.2.1 states that a down port allows for invalid data to be + * returned for all PortInfo components except PortState and + * PortPhysicalState */ + if (istate != IB_LINK_DOWN) { + n = snprintf(link_str, 256, "(%3s %9s %6s/%8s)", + mad_dump_val(IB_PORT_LINK_WIDTH_ACTIVE_F, width, 64, + &iwidth), + mad_dump_val(IB_PORT_LINK_SPEED_ACTIVE_F, speed, 64, + &ispeed), + mad_dump_val(IB_PORT_STATE_F, state, 64, &istate), + mad_dump_val(IB_PORT_PHYS_STATE_F, physstate, 64, + &iphystate)); + } else { + n = snprintf(link_str, 256, "( %6s/%8s)", + mad_dump_val(IB_PORT_STATE_F, state, 64, &istate), + mad_dump_val(IB_PORT_PHYS_STATE_F, physstate, 64, + &iphystate)); + } + + /* again default values due to C14-24.2.1 */ + if (add_sw_settings && istate != IB_LINK_DOWN) { + snprintf(link_str + n, 256 - n, + " (HOQ:%d VL_Stall:%d)", + mad_get_field(port->info, 0, + IB_PORT_HOQ_LIFE_F), + mad_get_field(port->info, 0, + IB_PORT_VL_STALL_COUNT_F)); + } + + if (port->remoteport) { + char *remap = + remap_node_name(node_name_map, port->remoteport->node->guid, + port->remoteport->node->nodedesc); + + if (port->remoteport->ext_portnum) + snprintf(ext_port_str, 256, "%d", + port->remoteport->ext_portnum); + else + ext_port_str[0] = '\0'; + + get_msg(width_msg, speed_msg, 256, port); + + if (line_mode) { + if (print_port_guids) + snprintf(remote_guid_str, 256, + "0x%016" PRIx64 " ", + port->remoteport->guid); + else + snprintf(remote_guid_str, 256, + "0x%016" PRIx64 " ", + port->remoteport->node->guid); + } + + snprintf(remote_str, 256, "%s%6d %4d[%2s] \"%s\" (%s %s)\n", + remote_guid_str, port->remoteport->base_lid ? + port->remoteport->base_lid : + port->remoteport->node->smalid, + port->remoteport->portnum, ext_port_str, remap, + width_msg, speed_msg); + free(remap); + } else + snprintf(remote_str, 256, " [ ] \"\" ( )\n"); + + if (port->ext_portnum) + snprintf(ext_port_str, 256, "%d", port->ext_portnum); + else + ext_port_str[0] = '\0'; + + if (line_mode) { + char *remap = remap_node_name(node_name_map, node->guid, + node->nodedesc); + printf("0x%016" PRIx64 " \"%30s\" ", node->guid, remap); + free(remap); + } else + printf(" "); + + printf("%6d %4d[%2s] ==%s==> %s", + node->smalid, port->portnum, ext_port_str, link_str, remote_str); +} + +void print_switch(ibnd_node_t * node, void *user_data) +{ + int i = 0; + int head_print = 0; + char *remap = + remap_node_name(node_name_map, node->guid, node->nodedesc); + + for (i = 1; i <= node->numports; i++) { + ibnd_port_t *port = node->ports[i]; + if (!port) + continue; + if (!down_links_only || + mad_get_field(port->info, 0, + IB_PORT_STATE_F) == IB_LINK_DOWN) { + if (!head_print && !line_mode) { + printf("Switch 0x%016" PRIx64 " %s:\n", + node->guid, remap); + head_print = 1; + } + print_port(node, port); + } + } + free(remap); +} + +static int process_opt(void *context, int ch, char *optarg) +{ + struct ibnd_config *cfg = context; + switch (ch) { + case 1: + node_name_map_file = strdup(optarg); + break; + case 2: + load_cache_file = strdup(optarg); + break; + case 'S': + guid_str = optarg; + guid = (uint64_t) strtoull(guid_str, 0, 0); + break; + case 'D': + dr_path = strdup(optarg); + break; + case 'a': + all = 1; + break; + case 'n': + cfg->max_hops = strtoul(optarg, NULL, 0); + break; + case 'd': + down_links_only = 1; + break; + case 'l': + line_mode = 1; + break; + case 'p': + add_sw_settings = 1; + break; + case 'g': + print_port_guids = 1; + break; + case 'R': /* nop */ + break; + case 'o': + cfg->max_smps = strtoul(optarg, NULL, 0); + break; + default: + return -1; + } + + return 0; +} + +int main(int argc, char **argv) +{ + struct ibnd_config config = { 0 }; + int rc = 0; + int resolved = -1; + ibnd_fabric_t *fabric = NULL; + struct ibmad_port *ibmad_port; + ib_portid_t port_id = { 0 }; + int mgmt_classes[3] = + { IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS }; + + const struct ibdiag_opt opts[] = { + {"node-name-map", 1, 1, "", "node name map file"}, + {"switch", 'S', 1, "", + "query only (hex format)"}, + {"Direct", 'D', 1, "", + "query only node specified by "}, + {"all", 'a', 0, NULL, + "print all switches found in a partial fabric scan"}, + {"hops", 'n', 1, "", + "Number of hops to include away from specified node"}, + {"down", 'd', 0, NULL, "print only down links"}, + {"line", 'l', 0, NULL, + "(line mode) print all information for each link on a single line"}, + {"additional", 'p', 0, NULL, + "print additional switch settings (PktLifeTime, HoqLife, VLStallCount)"}, + {"portguids", 'g', 0, NULL, + "print port guids instead of node guids"}, + {"load-cache", 2, 1, "", + "filename of ibnetdiscover cache to load"}, + {"outstanding_smps", 'o', 1, NULL, + "specify the number of outstanding SMP's which should be " + "issued during the scan"}, + {"GNDN", 'R', 0, NULL, + "(This option is obsolete and does nothing)"}, + {0} + }; + char usage_args[] = ""; + + ibdiag_process_opts(argc, argv, &config, "SDandlpgRGL", opts, + process_opt, usage_args, NULL); + + argc -= optind; + argv += optind; + + ibmad_port = mad_rpc_open_port(ibd_ca, ibd_ca_port, mgmt_classes, 3); + if (!ibmad_port) { + fprintf(stderr, "Failed to open %s port %d", ibd_ca, + ibd_ca_port); + exit(1); + } + + if (ibd_timeout) { + mad_rpc_set_timeout(ibmad_port, ibd_timeout); + config.timeout_ms = ibd_timeout; + } + + node_name_map = open_node_name_map(node_name_map_file); + + if (dr_path && load_cache_file) { + fprintf(stderr, "Cannot specify cache and direct route path\n"); + exit(1); + } + + if (dr_path) { + /* only scan part of the fabric */ + if ((resolved = + ib_resolve_portid_str_via(&port_id, dr_path, + IB_DEST_DRPATH, NULL, + ibmad_port)) < 0) + IBWARN("Failed to resolve %s; attempting full scan\n", + dr_path); + } else if (guid_str) { + if ((resolved = + ib_resolve_portid_str_via(&port_id, guid_str, IB_DEST_GUID, + NULL, ibmad_port)) < 0) + IBWARN("Failed to resolve %s; attempting full scan\n", + guid_str); + } + + if (load_cache_file) { + if ((fabric = ibnd_load_fabric(load_cache_file, 0)) == NULL) { + fprintf(stderr, "loading cached fabric failed\n"); + exit(1); + } + } else { + if (resolved >= 0 && + !(fabric = + ibnd_discover_fabric(ibd_ca, ibd_ca_port, &port_id, &config))) + IBWARN("Single node discover failed;" + " attempting full scan\n"); + + if (!fabric && + !(fabric = ibnd_discover_fabric(ibd_ca, ibd_ca_port, NULL, &config))) { + fprintf(stderr, "discover failed\n"); + rc = 1; + goto close_port; + } + } + + if (!all && guid_str) { + ibnd_node_t *sw = ibnd_find_node_guid(fabric, guid); + if (sw) + print_switch(sw, NULL); + else + fprintf(stderr, "Failed to find switch: %s\n", + guid_str); + } else if (!all && dr_path) { + ibnd_node_t *sw = NULL; + uint8_t ni[IB_SMP_DATA_SIZE]; + + if (!smp_query_via(ni, &port_id, IB_ATTR_NODE_INFO, 0, + ibd_timeout, ibmad_port)) + return -1; + mad_decode_field(ni, IB_NODE_GUID_F, &(guid)); + + sw = ibnd_find_node_guid(fabric, guid); + if (sw) + print_switch(sw, NULL); + else + fprintf(stderr, "Failed to find switch: %s\n", dr_path); + } else + ibnd_iter_nodes_type(fabric, print_switch, IB_NODE_SWITCH, + NULL); + + ibnd_destroy_fabric(fabric); + +close_port: + close_node_name_map(node_name_map); + mad_rpc_close_port(ibmad_port); + exit(rc); +} diff --git a/branches/WOF2-3/tools/infiniband-diags/src/iblinkinfo/SOURCES b/branches/WOF2-3/tools/infiniband-diags/src/iblinkinfo/SOURCES new file mode 100644 index 00000000..ee5de7bb --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/iblinkinfo/SOURCES @@ -0,0 +1,36 @@ +TARGETNAME = iblinkinfo +TARGETPATH = ..\..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = PROGRAM + +UMTYPE = console +UMENTRY = main + +USE_MSVCRT = 1 + +SOURCES = ..\iblinkinfo.c ..\ibdiag_common.c ..\ibdiag_windows.c\ + iblinkinfo.rc + +INCLUDES = ..\..\include;..\..\include\windows;\ + ..\..\..\..\ulp\libibnetdisc\include;\ + ..\..\..\..\ulp\libibmad\include;\ + ..\..\..\..\ulp\libibumad\include;\ + ..\..\..\..\inc;..\..\..\..\inc\user;\ + ..\..\..\..\inc\user\linux; + +C_DEFINES = $(C_DEFINES) /DHAVE_CONFIG_H + +TARGETLIBS = \ + $(SDK_LIB_PATH)\kernel32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\complib.lib \ + $(TARGETPATH)\*\libibmad.lib \ + $(TARGETPATH)\*\libibumad.lib \ + $(TARGETPATH)\*\libibnetdisc.lib +!else + $(TARGETPATH)\*\complibd.lib \ + $(TARGETPATH)\*\libibmadd.lib \ + $(TARGETPATH)\*\libibumadd.lib \ + $(TARGETPATH)\*\libibnetdiscd.lib +!endif + +MSC_WARNING_LEVEL = /W3 /WX /wd4007 \ No newline at end of file diff --git a/branches/WOF2-3/tools/infiniband-diags/src/iblinkinfo/iblinkinfo.rc b/branches/WOF2-3/tools/infiniband-diags/src/iblinkinfo/iblinkinfo.rc new file mode 100644 index 00000000..9dfb7538 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/iblinkinfo/iblinkinfo.rc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef DBG +#define VER_FILEDESCRIPTION_STR "InfiniBand Network Link Information (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "InfiniBand Network Link Information" +#endif + +#define VER_INTERNALNAME_STR "iblinkinfo.exe" +#define VER_ORIGINALFILENAME_STR "iblinkinfo.exe" + +#include diff --git a/branches/WOF2-3/tools/infiniband-diags/src/iblinkinfo/makefile b/branches/WOF2-3/tools/infiniband-diags/src/iblinkinfo/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/iblinkinfo/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\..\inc\openib.def diff --git a/branches/WOF2-3/tools/infiniband-diags/src/ibnetdiscover.c b/branches/WOF2-3/tools/infiniband-diags/src/ibnetdiscover.c new file mode 100644 index 00000000..347e7b2d --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/ibnetdiscover.c @@ -0,0 +1,1008 @@ +/* + * Copyright (c) 2004-2009 Voltaire Inc. All rights reserved. + * Copyright (c) 2007 Xsigo Systems Inc. All rights reserved. + * Copyright (c) 2008 Lawrence Livermore National Lab. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +#include +#endif /* HAVE_CONFIG_H */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "ibdiag_common.h" + +#define LIST_CA_NODE (1 << IB_NODE_CA) +#define LIST_SWITCH_NODE (1 << IB_NODE_SWITCH) +#define LIST_ROUTER_NODE (1 << IB_NODE_ROUTER) + +#define DIFF_FLAG_SWITCH 0x01 +#define DIFF_FLAG_CA 0x02 +#define DIFF_FLAG_ROUTER 0x04 +#define DIFF_FLAG_PORT_CONNECTION 0x08 +#define DIFF_FLAG_LID 0x10 +#define DIFF_FLAG_NODE_DESCRIPTION 0x20 + +#define DIFF_FLAG_DEFAULT (DIFF_FLAG_SWITCH | DIFF_FLAG_CA | DIFF_FLAG_ROUTER \ + | DIFF_FLAG_PORT_CONNECTION) + +static FILE *f; + +static char *node_name_map_file = NULL; +static nn_map_t *node_name_map = NULL; +static char *cache_file = NULL; +static char *load_cache_file = NULL; +static char *diff_cache_file = NULL; +static unsigned diffcheck_flags = DIFF_FLAG_DEFAULT; + +static int report_max_hops = 0; + +/** + * Define our own conversion functions to maintain compatibility with the old + * ibnetdiscover which did not use the ibmad conversion functions. + */ +char *dump_linkspeed_compat(uint32_t speed) +{ + switch (speed) { + case 1: + return ("SDR"); + break; + case 2: + return ("DDR"); + break; + case 4: + return ("QDR"); + break; + } + return ("???"); +} + +char *dump_linkwidth_compat(uint32_t width) +{ + switch (width) { + case 1: + return ("1x"); + break; + case 2: + return ("4x"); + break; + case 4: + return ("8x"); + break; + case 8: + return ("12x"); + break; + } + return ("??"); +} + +static inline const char *ports_nt_str_compat(ibnd_node_t * node) +{ + switch (node->type) { + case IB_NODE_SWITCH: + return "SW"; + case IB_NODE_CA: + return "CA"; + case IB_NODE_ROUTER: + return "RT"; + } + return "??"; +} + +char *node_name(ibnd_node_t * node) +{ + static char buf[256]; + + switch (node->type) { + case IB_NODE_SWITCH: + sprintf(buf, "\"%s", "S"); + break; + case IB_NODE_CA: + sprintf(buf, "\"%s", "H"); + break; + case IB_NODE_ROUTER: + sprintf(buf, "\"%s", "R"); + break; + default: + sprintf(buf, "\"%s", "?"); + break; + } + sprintf(buf + 2, "-%016" PRIx64 "\"", node->guid); + + return buf; +} + +void list_node(ibnd_node_t * node, void *user_data) +{ + char *node_type; + char *nodename = remap_node_name(node_name_map, node->guid, + node->nodedesc); + + switch (node->type) { + case IB_NODE_SWITCH: + node_type = "Switch"; + break; + case IB_NODE_CA: + node_type = "Ca"; + break; + case IB_NODE_ROUTER: + 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->guid, node->numports, mad_get_field(node->info, 0, + IB_NODE_DEVID_F), + mad_get_field(node->info, 0, IB_NODE_VENDORID_F), nodename); + + free(nodename); +} + +void list_nodes(ibnd_fabric_t * fabric, int list) +{ + if (list & LIST_CA_NODE) + ibnd_iter_nodes_type(fabric, list_node, IB_NODE_CA, NULL); + if (list & LIST_SWITCH_NODE) + ibnd_iter_nodes_type(fabric, list_node, IB_NODE_SWITCH, NULL); + if (list & LIST_ROUTER_NODE) + ibnd_iter_nodes_type(fabric, list_node, IB_NODE_ROUTER, NULL); +} + +void out_ids(ibnd_node_t * node, int group, char *chname, char *out_prefix) +{ + uint64_t sysimgguid = + mad_get_field64(node->info, 0, IB_NODE_SYSTEM_GUID_F); + + fprintf(f, "\n%svendid=0x%x\n", out_prefix ? out_prefix : "", + mad_get_field(node->info, 0, IB_NODE_VENDORID_F)); + fprintf(f, "%sdevid=0x%x\n", out_prefix ? out_prefix : "", + mad_get_field(node->info, 0, IB_NODE_DEVID_F)); + if (sysimgguid) + fprintf(f, "%ssysimgguid=0x%" PRIx64, + out_prefix ? out_prefix : "", sysimgguid); + if (group && node->chassis && node->chassis->chassisnum) { + fprintf(f, "\t\t# Chassis %d", node->chassis->chassisnum); + if (chname) + fprintf(f, " (%s)", clean_nodedesc(chname)); + if (ibnd_is_xsigo_tca(node->guid) && node->ports[1] && + node->ports[1]->remoteport) + fprintf(f, " slot %d", + node->ports[1]->remoteport->portnum); + } + fprintf(f, "\n"); +} + +uint64_t out_chassis(ibnd_fabric_t * fabric, unsigned char chassisnum) +{ + uint64_t guid; + + fprintf(f, "\nChassis %u", chassisnum); + guid = ibnd_get_chassis_guid(fabric, chassisnum); + if (guid) + fprintf(f, " (guid 0x%" PRIx64 ")", guid); + fprintf(f, "\n"); + return guid; +} + +void out_switch_detail(ibnd_node_t * node, char *sw_prefix) +{ + char *nodename = NULL; + + nodename = remap_node_name(node_name_map, node->guid, node->nodedesc); + + fprintf(f, "%sSwitch\t%d %s\t\t# \"%s\" %s port 0 lid %d lmc %d", + sw_prefix ? sw_prefix : "", node->numports, node_name(node), + nodename, node->smaenhsp0 ? "enhanced" : "base", + node->smalid, node->smalmc); + + free(nodename); +} + +void out_switch(ibnd_node_t * node, int group, char *chname, char *id_prefix, + char *sw_prefix) +{ + char *str; + char str2[256]; + + out_ids(node, group, chname, id_prefix); + fprintf(f, "%sswitchguid=0x%" PRIx64, + id_prefix ? id_prefix : "", node->guid); + fprintf(f, "(%" PRIx64 ")", + mad_get_field64(node->info, 0, IB_NODE_PORT_GUID_F)); + if (group) { + fprintf(f, "\t# "); + str = ibnd_get_chassis_type(node); + if (str) + fprintf(f, "%s ", str); + str = ibnd_get_chassis_slot_str(node, str2, 256); + if (str) + fprintf(f, "%s", str); + } + fprintf(f, "\n"); + + out_switch_detail(node, sw_prefix); + fprintf(f, "\n"); +} + +void out_ca_detail(ibnd_node_t * node, char *ca_prefix) +{ + char *node_type; + + switch (node->type) { + case IB_NODE_CA: + node_type = "Ca"; + break; + case IB_NODE_ROUTER: + node_type = "Rt"; + break; + default: + node_type = "???"; + break; + } + + fprintf(f, "%s%s\t%d %s\t\t# \"%s\"", ca_prefix ? ca_prefix : "", + node_type, node->numports, node_name(node), + clean_nodedesc(node->nodedesc)); +} + +void out_ca(ibnd_node_t * node, int group, char *chname, char *id_prefix, + char *ca_prefix) +{ + char *node_type; + + out_ids(node, group, chname, id_prefix); + switch (node->type) { + case IB_NODE_CA: + node_type = "ca"; + break; + case IB_NODE_ROUTER: + node_type = "rt"; + break; + default: + node_type = "???"; + break; + } + + fprintf(f, "%s%sguid=0x%" PRIx64 "\n", + id_prefix ? id_prefix : "", node_type, node->guid); + out_ca_detail(node, ca_prefix); + if (group && ibnd_is_xsigo_hca(node->guid)) + fprintf(f, " (scp)"); + fprintf(f, "\n"); +} + +#define OUT_BUFFER_SIZE 16 +static char *out_ext_port(ibnd_port_t * port, int group) +{ + static char mapping[OUT_BUFFER_SIZE]; + + if (group && port->ext_portnum != 0) { + snprintf(mapping, OUT_BUFFER_SIZE, + "[ext %d]", port->ext_portnum); + return (mapping); + } + + return (NULL); +} + +void out_switch_port(ibnd_port_t * port, int group, char *out_prefix) +{ + char *ext_port_str = NULL; + char *rem_nodename = NULL; + uint32_t iwidth = mad_get_field(port->info, 0, + IB_PORT_LINK_WIDTH_ACTIVE_F); + uint32_t ispeed = mad_get_field(port->info, 0, + IB_PORT_LINK_SPEED_ACTIVE_F); + + DEBUG("port %p:%d remoteport %p\n", port, port->portnum, + port->remoteport); + fprintf(f, "%s[%d]", out_prefix ? out_prefix : "", 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->guid, + 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 != IB_NODE_SWITCH) + fprintf(f, "(%" PRIx64 ") ", port->remoteport->guid); + fprintf(f, "\t\t# \"%s\" lid %d %s%s", + rem_nodename, + port->remoteport->node->type == IB_NODE_SWITCH ? + port->remoteport->node->smalid : + port->remoteport->base_lid, + dump_linkwidth_compat(iwidth), dump_linkspeed_compat(ispeed)); + + if (ibnd_is_xsigo_tca(port->remoteport->guid)) + fprintf(f, " slot %d", port->portnum); + else if (ibnd_is_xsigo_hca(port->remoteport->guid)) + fprintf(f, " (scp)"); + fprintf(f, "\n"); + + free(rem_nodename); +} + +void out_ca_port(ibnd_port_t * port, int group, char *out_prefix) +{ + char *str = NULL; + char *rem_nodename = NULL; + uint32_t iwidth = mad_get_field(port->info, 0, + IB_PORT_LINK_WIDTH_ACTIVE_F); + uint32_t ispeed = mad_get_field(port->info, 0, + IB_PORT_LINK_SPEED_ACTIVE_F); + + fprintf(f, "%s[%d]", out_prefix ? out_prefix : "", port->portnum); + if (port->node->type != IB_NODE_SWITCH) + fprintf(f, "(%" PRIx64 ") ", port->guid); + 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 != IB_NODE_SWITCH) + fprintf(f, " (%" PRIx64 ") ", port->remoteport->guid); + + rem_nodename = remap_node_name(node_name_map, + port->remoteport->node->guid, + port->remoteport->node->nodedesc); + + fprintf(f, "\t\t# lid %d lmc %d \"%s\" lid %d %s%s\n", + port->base_lid, port->lmc, rem_nodename, + port->remoteport->node->type == IB_NODE_SWITCH ? + port->remoteport->node->smalid : + port->remoteport->base_lid, + dump_linkwidth_compat(iwidth), dump_linkspeed_compat(ispeed)); + + free(rem_nodename); +} + +struct iter_user_data { + int group; + int skip_chassis_nodes; +}; + +static void switch_iter_func(ibnd_node_t * node, void *iter_user_data) +{ + ibnd_port_t *port; + int p = 0; + struct iter_user_data *data = (struct iter_user_data *)iter_user_data; + + DEBUG("SWITCH: node %p\n", node); + + /* skip chassis based switches if flagged */ + if (data->skip_chassis_nodes && node->chassis + && node->chassis->chassisnum) + return; + + out_switch(node, data->group, NULL, NULL, NULL); + for (p = 1; p <= node->numports; p++) { + port = node->ports[p]; + if (port && port->remoteport) + out_switch_port(port, data->group, NULL); + } +} + +static void ca_iter_func(ibnd_node_t * node, void *iter_user_data) +{ + ibnd_port_t *port; + int p = 0; + struct iter_user_data *data = (struct iter_user_data *)iter_user_data; + + DEBUG("CA: node %p\n", node); + /* Now, skip chassis based CAs */ + if (data->group && node->chassis && node->chassis->chassisnum) + return; + out_ca(node, data->group, NULL, NULL, NULL); + + for (p = 1; p <= node->numports; p++) { + port = node->ports[p]; + if (port && port->remoteport) + out_ca_port(port, data->group, NULL); + } +} + +static void router_iter_func(ibnd_node_t * node, void *iter_user_data) +{ + ibnd_port_t *port; + int p = 0; + struct iter_user_data *data = (struct iter_user_data *)iter_user_data; + + DEBUG("RT: node %p\n", node); + /* Now, skip chassis based RTs */ + if (data->group && node->chassis && node->chassis->chassisnum) + return; + out_ca(node, data->group, NULL, NULL, NULL); + for (p = 1; p <= node->numports; p++) { + port = node->ports[p]; + if (port && port->remoteport) + out_ca_port(port, data->group, NULL); + } +} + +int dump_topology(int group, ibnd_fabric_t * fabric) +{ + ibnd_node_t *node; + ibnd_port_t *port; + int i = 0, p = 0; + time_t t = time(0); + uint64_t chguid; + char *chname = NULL; + struct iter_user_data iter_user_data; + + fprintf(f, "#\n# Topology file: generated on %s#\n", ctime(&t)); + if (report_max_hops) + fprintf(f, "# Reported max hops discovered: %u\n" + "# Total MADs used: %u\n", + fabric->maxhops_discovered, fabric->total_mads_used); + fprintf(f, "# Initiated from node %016" PRIx64 " port %016" PRIx64 "\n", + fabric->from_node->guid, + mad_get_field64(fabric->from_node->info, 0, + IB_NODE_PORT_GUID_F)); + + /* Make pass on switches */ + if (group) { + ibnd_chassis_t *ch = NULL; + + /* Chassis based switches first */ + for (ch = fabric->chassis; ch; ch = ch->next) { + int n = 0; + + if (!ch->chassisnum) + continue; + chguid = out_chassis(fabric, ch->chassisnum); + chname = NULL; + if (ibnd_is_xsigo_guid(chguid)) { + for (node = ch->nodes; node; + node = node->next_chassis_node) { + if (ibnd_is_xsigo_hca(node->guid)) { + chname = node->nodedesc; + fprintf(f, "Hostname: %s\n", + clean_nodedesc + (node->nodedesc)); + } + } + } + + fprintf(f, "\n# Spine Nodes"); + for (n = 1; n <= SPINES_MAX_NUM; n++) { + if (ch->spinenode[n]) { + out_switch(ch->spinenode[n], group, + chname, NULL, NULL); + for (p = 1; + p <= ch->spinenode[n]->numports; + p++) { + port = + ch->spinenode[n]->ports[p]; + if (port && port->remoteport) + out_switch_port(port, + group, + NULL); + } + } + } + fprintf(f, "\n# Line Nodes"); + for (n = 1; n <= LINES_MAX_NUM; n++) { + if (ch->linenode[n]) { + out_switch(ch->linenode[n], group, + chname, NULL, NULL); + for (p = 1; + p <= ch->linenode[n]->numports; + p++) { + port = + ch->linenode[n]->ports[p]; + if (port && port->remoteport) + out_switch_port(port, + group, + NULL); + } + } + } + + fprintf(f, "\n# Chassis Switches"); + for (node = ch->nodes; node; + node = node->next_chassis_node) { + if (node->type == IB_NODE_SWITCH) { + out_switch(node, group, chname, NULL, + NULL); + for (p = 1; p <= node->numports; p++) { + port = node->ports[p]; + if (port && port->remoteport) + out_switch_port(port, + group, + NULL); + } + } + + } + + fprintf(f, "\n# Chassis CAs"); + for (node = ch->nodes; node; + node = node->next_chassis_node) { + if (node->type == IB_NODE_CA) { + out_ca(node, group, chname, NULL, NULL); + for (p = 1; p <= node->numports; p++) { + port = node->ports[p]; + if (port && port->remoteport) + out_ca_port(port, group, + NULL); + } + } + } + + } + + } else { /* !group */ + iter_user_data.group = group; + iter_user_data.skip_chassis_nodes = 0; + ibnd_iter_nodes_type(fabric, switch_iter_func, IB_NODE_SWITCH, + &iter_user_data); + } + + chname = NULL; + if (group) { + iter_user_data.group = group; + iter_user_data.skip_chassis_nodes = 1; + + fprintf(f, "\nNon-Chassis Nodes\n"); + + ibnd_iter_nodes_type(fabric, switch_iter_func, IB_NODE_SWITCH, + &iter_user_data); + } + + iter_user_data.group = group; + iter_user_data.skip_chassis_nodes = 0; + /* Make pass on CAs */ + ibnd_iter_nodes_type(fabric, ca_iter_func, IB_NODE_CA, &iter_user_data); + + /* Make pass on routers */ + ibnd_iter_nodes_type(fabric, router_iter_func, IB_NODE_ROUTER, + &iter_user_data); + + return i; +} + +void dump_ports_report(ibnd_node_t * node, void *user_data) +{ + int p = 0; + ibnd_port_t *port = NULL; + + /* for each port */ + for (p = node->numports, port = node->ports[p]; p > 0; + port = node->ports[--p]) { + uint32_t iwidth, ispeed; + if (port == NULL) + continue; + iwidth = + mad_get_field(port->info, 0, IB_PORT_LINK_WIDTH_ACTIVE_F); + ispeed = + mad_get_field(port->info, 0, IB_PORT_LINK_SPEED_ACTIVE_F); + fprintf(stdout, "%2s %5d %2d 0x%016" PRIx64 " %s %s", + ports_nt_str_compat(node), + node->type == + IB_NODE_SWITCH ? node->smalid : port->base_lid, + port->portnum, port->guid, + dump_linkwidth_compat(iwidth), + dump_linkspeed_compat(ispeed)); + if (port->remoteport) + fprintf(stdout, + " - %2s %5d %2d 0x%016" PRIx64 + " ( '%s' - '%s' )\n", + ports_nt_str_compat(port->remoteport->node), + port->remoteport->node->type == IB_NODE_SWITCH ? + port->remoteport->node->smalid : + port->remoteport->base_lid, + port->remoteport->portnum, + port->remoteport->guid, port->node->nodedesc, + port->remoteport->node->nodedesc); + else + fprintf(stdout, "%36s'%s'\n", "", port->node->nodedesc); + } +} + +struct iter_diff_data { + uint32_t diff_flags; + ibnd_fabric_t *fabric1; + ibnd_fabric_t *fabric2; + char *fabric1_prefix; + char *fabric2_prefix; + void (*out_header) (ibnd_node_t *, int, char *, char *, char *); + void (*out_header_detail) (ibnd_node_t *, char *); + void (*out_port) (ibnd_port_t *, int, char *); +}; + +static void diff_iter_out_header(ibnd_node_t * node, + struct iter_diff_data *data, + int *out_header_flag) +{ + if (!(*out_header_flag)) { + (*data->out_header) (node, 0, NULL, NULL, NULL); + (*out_header_flag)++; + } +} + +static void diff_ports(ibnd_node_t * fabric1_node, ibnd_node_t * fabric2_node, + int *out_header_flag, struct iter_diff_data *data) +{ + ibnd_port_t *fabric1_port; + ibnd_port_t *fabric2_port; + int p; + + for (p = 1; p <= fabric1_node->numports; p++) { + int fabric1_out = 0, fabric2_out = 0; + + fabric1_port = fabric1_node->ports[p]; + fabric2_port = fabric2_node->ports[p]; + + if (data->diff_flags & DIFF_FLAG_PORT_CONNECTION) { + if ((fabric1_port && !fabric2_port) + || ((fabric1_port && fabric2_port) + && (fabric1_port->remoteport + && !fabric2_port->remoteport))) + fabric1_out++; + else if ((!fabric1_port && fabric2_port) + || ((fabric1_port && fabric2_port) + && (!fabric1_port->remoteport + && fabric2_port->remoteport))) + fabric2_out++; + else if ((fabric1_port && fabric2_port) + && ((fabric1_port->guid != fabric2_port->guid) + || + ((fabric1_port->remoteport + && fabric2_port->remoteport) + && (fabric1_port->remoteport->guid != + fabric2_port->remoteport->guid)))) { + fabric1_out++; + fabric2_out++; + } + } + + if ((data->diff_flags & DIFF_FLAG_LID) + && fabric1_port && fabric2_port + && fabric1_port->base_lid != fabric2_port->base_lid) { + fabric1_out++; + fabric2_out++; + } + + if (fabric1_out) { + diff_iter_out_header(fabric1_node, data, + out_header_flag); + (*data->out_port) (fabric1_port, 0, + data->fabric1_prefix); + } + if (fabric2_out) { + diff_iter_out_header(fabric1_node, data, + out_header_flag); + (*data->out_port) (fabric2_port, 0, + data->fabric2_prefix); + } + } +} + +static void diff_iter_func(ibnd_node_t * fabric1_node, void *iter_user_data) +{ + struct iter_diff_data *data = iter_user_data; + ibnd_node_t *fabric2_node; + ibnd_port_t *fabric1_port; + int p; + + DEBUG("DEBUG: fabric1_node %p\n", fabric1_node); + + fabric2_node = ibnd_find_node_guid(data->fabric2, fabric1_node->guid); + if (!fabric2_node) { + (*data->out_header) (fabric1_node, 0, NULL, + data->fabric1_prefix, + data->fabric1_prefix); + for (p = 1; p <= fabric1_node->numports; p++) { + fabric1_port = fabric1_node->ports[p]; + if (fabric1_port && fabric1_port->remoteport) + (*data->out_port) (fabric1_port, 0, + data->fabric1_prefix); + } + } else if (data->diff_flags & + (DIFF_FLAG_PORT_CONNECTION | DIFF_FLAG_LID + | DIFF_FLAG_NODE_DESCRIPTION)) { + int out_header_flag = 0; + + if ((data->diff_flags & DIFF_FLAG_LID + && fabric1_node->smalid != fabric2_node->smalid) || + (data->diff_flags & DIFF_FLAG_NODE_DESCRIPTION + && memcmp(fabric1_node->nodedesc, fabric2_node->nodedesc, + IB_SMP_DATA_SIZE))) { + (*data->out_header) (fabric1_node, 0, NULL, NULL, + data->fabric1_prefix); + (*data->out_header_detail) (fabric2_node, + data->fabric2_prefix); + fprintf(f, "\n"); + out_header_flag++; + } + + if (fabric1_node->numports != fabric2_node->numports) { + diff_iter_out_header(fabric1_node, data, + &out_header_flag); + fprintf(f, "%snumports = %d\n", data->fabric1_prefix, + fabric1_node->numports); + fprintf(f, "%snumports = %d\n", data->fabric2_prefix, + fabric2_node->numports); + return; + } + + if (data->diff_flags & DIFF_FLAG_PORT_CONNECTION + || data->diff_flags & DIFF_FLAG_LID) + diff_ports(fabric1_node, fabric2_node, &out_header_flag, + data); + } +} + +static int diff_common(ibnd_fabric_t * orig_fabric, ibnd_fabric_t * new_fabric, + int node_type, uint32_t diff_flags, + void (*out_header) (ibnd_node_t *, int, char *, char *, + char *), + void (*out_header_detail) (ibnd_node_t *, char *), + void (*out_port) (ibnd_port_t *, int, char *)) +{ + struct iter_diff_data iter_diff_data; + + iter_diff_data.diff_flags = diff_flags; + iter_diff_data.fabric1 = orig_fabric; + iter_diff_data.fabric2 = new_fabric; + iter_diff_data.fabric1_prefix = "< "; + iter_diff_data.fabric2_prefix = "> "; + iter_diff_data.out_header = out_header; + iter_diff_data.out_header_detail = out_header_detail; + iter_diff_data.out_port = out_port; + ibnd_iter_nodes_type(orig_fabric, diff_iter_func, node_type, + &iter_diff_data); + + /* Do opposite diff to find existence of node types + * in new_fabric but not in orig_fabric. + * + * In this diff, we don't need to check port connections, + * lids, or node descriptions since it has already been + * done (i.e. checks are only done when guid exists on both + * orig and new). + */ + iter_diff_data.diff_flags = diff_flags & ~DIFF_FLAG_PORT_CONNECTION; + iter_diff_data.diff_flags &= ~DIFF_FLAG_LID; + iter_diff_data.diff_flags &= ~DIFF_FLAG_NODE_DESCRIPTION; + iter_diff_data.fabric1 = new_fabric; + iter_diff_data.fabric2 = orig_fabric; + iter_diff_data.fabric1_prefix = "> "; + iter_diff_data.fabric2_prefix = "< "; + iter_diff_data.out_header = out_header; + iter_diff_data.out_header_detail = out_header_detail; + iter_diff_data.out_port = out_port; + ibnd_iter_nodes_type(new_fabric, diff_iter_func, node_type, + &iter_diff_data); + + return 0; +} + +int diff(ibnd_fabric_t * orig_fabric, ibnd_fabric_t * new_fabric) +{ + if (diffcheck_flags & DIFF_FLAG_SWITCH) + diff_common(orig_fabric, new_fabric, IB_NODE_SWITCH, + diffcheck_flags, out_switch, out_switch_detail, + out_switch_port); + + if (diffcheck_flags & DIFF_FLAG_CA) + diff_common(orig_fabric, new_fabric, IB_NODE_CA, + diffcheck_flags, out_ca, out_ca_detail, + out_ca_port); + + if (diffcheck_flags & DIFF_FLAG_ROUTER) + diff_common(orig_fabric, new_fabric, IB_NODE_ROUTER, + diffcheck_flags, out_ca, out_ca_detail, + out_ca_port); + + return 0; +} + +static int list, group, ports_report; + +static int process_opt(void *context, int ch, char *optarg) +{ + struct ibnd_config *cfg = context; + char *p; + + switch (ch) { + case 1: + node_name_map_file = strdup(optarg); + break; + case 2: + cache_file = strdup(optarg); + break; + case 3: + load_cache_file = strdup(optarg); + break; + case 4: + diff_cache_file = strdup(optarg); + break; + case 5: + diffcheck_flags = 0; + p = strtok(optarg, ","); + while (p) { + if (!strcasecmp(p, "sw")) + diffcheck_flags |= DIFF_FLAG_SWITCH; + else if (!strcasecmp(p, "ca")) + diffcheck_flags |= DIFF_FLAG_CA; + else if (!strcasecmp(p, "router")) + diffcheck_flags |= DIFF_FLAG_ROUTER; + else if (!strcasecmp(p, "port")) + diffcheck_flags |= DIFF_FLAG_PORT_CONNECTION; + else if (!strcasecmp(p, "lid")) + diffcheck_flags |= DIFF_FLAG_LID; + else if (!strcasecmp(p, "nodedesc")) + diffcheck_flags |= DIFF_FLAG_NODE_DESCRIPTION; + else { + fprintf(stderr, "invalid diff check key: %s\n", + p); + return -1; + } + p = strtok(NULL, ","); + } + break; + case 's': + cfg->show_progress = 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 'p': + ports_report = 1; + break; + case 'm': + report_max_hops = 1; + break; + case 'o': + cfg->max_smps = strtoul(optarg, NULL, 0); + break; + default: + return -1; + } + + return 0; +} + +int main(int argc, char **argv) +{ + struct ibnd_config config = { 0 }; + ibnd_fabric_t *fabric = NULL; + ibnd_fabric_t *diff_fabric = NULL; + + const struct ibdiag_opt opts[] = { + {"show", 's', 0, NULL, "show more information"}, + {"list", 'l', 0, NULL, "list of connected nodes"}, + {"grouping", 'g', 0, NULL, "show grouping"}, + {"Hca_list", 'H', 0, NULL, "list of connected CAs"}, + {"Switch_list", 'S', 0, NULL, "list of connected switches"}, + {"Router_list", 'R', 0, NULL, "list of connected routers"}, + {"node-name-map", 1, 1, "", "node name map file"}, + {"cache", 2, 1, "", + "filename to cache ibnetdiscover data to"}, + {"load-cache", 3, 1, "", + "filename of ibnetdiscover cache to load"}, + {"diff", 4, 1, "", + "filename of ibnetdiscover cache to diff"}, + {"diffcheck", 5, 1, "", + "specify checks to execute for --diff"}, + {"ports", 'p', 0, NULL, "obtain a ports report"}, + {"max_hops", 'm', 0, NULL, + "report max hops discovered by the library"}, + {"outstanding_smps", 'o', 1, NULL, + "specify the number of outstanding SMP's which should be " + "issued during the scan"}, + {0} + }; + char usage_args[] = "[topology-file]"; + + ibdiag_process_opts(argc, argv, &config, "sGDL", opts, process_opt, + usage_args, NULL); + + f = stdout; + + argc -= optind; + argv += optind; + + if (ibd_timeout) + config.timeout_ms = ibd_timeout; + + if (argc && !(f = fopen(argv[0], "w"))) + IBERROR("can't open file %s for writing", argv[0]); + + node_name_map = open_node_name_map(node_name_map_file); + + if (diff_cache_file && + !(diff_fabric = ibnd_load_fabric(diff_cache_file, 0))) + IBERROR("loading cached fabric for diff failed\n"); + + if (load_cache_file) { + if ((fabric = ibnd_load_fabric(load_cache_file, 0)) == NULL) + IBERROR("loading cached fabric failed\n"); + } else { + if ((fabric = + ibnd_discover_fabric(ibd_ca, ibd_ca_port, NULL, &config)) == NULL) + IBERROR("discover failed\n"); + } + + if (ports_report) + ibnd_iter_nodes(fabric, dump_ports_report, NULL); + else if (list) + list_nodes(fabric, list); + else if (diff_fabric) + diff(diff_fabric, fabric); + else + dump_topology(group, fabric); + + if (cache_file) + if (ibnd_cache_fabric(fabric, cache_file, 0) < 0) + IBERROR("caching ibnetdiscover data failed\n"); + + ibnd_destroy_fabric(fabric); + if (diff_fabric) + ibnd_destroy_fabric(diff_fabric); + close_node_name_map(node_name_map); + exit(0); +} diff --git a/branches/WOF2-3/tools/infiniband-diags/src/ibnetdiscover/SOURCES b/branches/WOF2-3/tools/infiniband-diags/src/ibnetdiscover/SOURCES new file mode 100644 index 00000000..03f03844 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/ibnetdiscover/SOURCES @@ -0,0 +1,36 @@ +TARGETNAME = ibnetdiscover +TARGETPATH = ..\..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = PROGRAM + +UMTYPE = console +UMENTRY = main + +USE_MSVCRT = 1 + +SOURCES = ..\ibnetdiscover.c ..\ibdiag_common.c ..\ibdiag_windows.c\ + ibnetdiscover.rc + +INCLUDES = ..\..\include;..\..\include\windows;\ + ..\..\..\..\ulp\libibnetdisc\include;\ + ..\..\..\..\ulp\libibmad\include;\ + ..\..\..\..\ulp\libibumad\include;\ + ..\..\..\..\inc;..\..\..\..\inc\user;\ + ..\..\..\..\inc\user\linux; + +C_DEFINES = $(C_DEFINES) /DHAVE_CONFIG_H + +TARGETLIBS = \ + $(SDK_LIB_PATH)\kernel32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\complib.lib \ + $(TARGETPATH)\*\libibmad.lib \ + $(TARGETPATH)\*\libibumad.lib \ + $(TARGETPATH)\*\libibnetdisc.lib +!else + $(TARGETPATH)\*\complibd.lib \ + $(TARGETPATH)\*\libibmadd.lib \ + $(TARGETPATH)\*\libibumadd.lib \ + $(TARGETPATH)\*\libibnetdiscd.lib +!endif + +MSC_WARNING_LEVEL = /W3 /WX /wd4007 \ No newline at end of file diff --git a/branches/WOF2-3/tools/infiniband-diags/src/ibnetdiscover/ibnetdiscover.rc b/branches/WOF2-3/tools/infiniband-diags/src/ibnetdiscover/ibnetdiscover.rc new file mode 100644 index 00000000..8f3509a3 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/ibnetdiscover/ibnetdiscover.rc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef DBG +#define VER_FILEDESCRIPTION_STR "InfiniBand Network Topology Discovery (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "InfiniBand Network Topology Discovery" +#endif + +#define VER_INTERNALNAME_STR "ibnetdiscover.exe" +#define VER_ORIGINALFILENAME_STR "ibnetdiscover.exe" + +#include diff --git a/branches/WOF2-3/tools/infiniband-diags/src/ibnetdiscover/makefile b/branches/WOF2-3/tools/infiniband-diags/src/ibnetdiscover/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/ibnetdiscover/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\..\inc\openib.def diff --git a/branches/WOF2-3/tools/infiniband-diags/src/ibping.c b/branches/WOF2-3/tools/infiniband-diags/src/ibping.c new file mode 100644 index 00000000..dafab1c8 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/ibping.c @@ -0,0 +1,265 @@ +/* + * Copyright (c) 2004-2009 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "ibdiag_common.h" + +struct ibmad_port *srcport; + +static char host_and_domain[IB_VENDOR_RANGE2_DATA_SIZE]; +static char last_host[IB_VENDOR_RANGE2_DATA_SIZE]; + +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_via(0, -1, srcport))) { + + 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_via(umad, 0, 0, srcport) < 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 = cl_get_time_stamp(); + + 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_via(data, portid, &call, srcport)) + return ~0ull; + + rtt = cl_get_time_stamp() - 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 uint64_t minrtt = ~0ull, maxrtt, total_rtt; +static uint64_t start, total_time, replied, lost, ntrans; +static ib_portid_t portid = { 0 }; + +void __cdecl report(int sig) +{ + total_time = cl_get_time_stamp() - 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); +} + +static int server = 0, flood = 0, oui = IB_OPENIB_OUI; +static unsigned count = ~0; + +static int process_opt(void *context, int ch, char *optarg) +{ + switch (ch) { + case 'c': + count = strtoul(optarg, 0, 0); + break; + case 'f': + flood++; + break; + case 'o': + oui = strtoul(optarg, 0, 0); + break; + case 'S': + server++; + break; + default: + return -1; + } + return 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; + uint64_t rtt; + char *err; + + const struct ibdiag_opt opts[] = { + {"count", 'c', 1, "", "stop after count packets"}, + {"flood", 'f', 0, NULL, "flood destination"}, + {"oui", 'o', 1, NULL, "use specified OUI number"}, + {"Server", 'S', 0, NULL, "start in server mode"}, + {0} + }; + char usage_args[] = ""; + + ibdiag_process_opts(argc, argv, NULL, "D", opts, process_opt, + usage_args, NULL); + + argc -= optind; + argv += optind; + + if (!argc && !server) + ibdiag_show_usage(); + + srcport = mad_rpc_open_port(ibd_ca, ibd_ca_port, mgmt_classes, 3); + if (!srcport) + IBERROR("Failed to open '%s' port '%d'", ibd_ca, ibd_ca_port); + + if (server) { + if (mad_register_server_via(ping_class, 0, 0, oui, srcport) < 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_via(ping_class, 0, srcport) < 0) + IBERROR("can't register ping class %d on this port", + ping_class); + + if (ib_resolve_portid_str_via(&portid, argv[0], ibd_dest_type, + ibd_sm_id, srcport) < 0) + IBERROR("can't resolve destination port %s", argv[0]); + + signal(SIGINT, report); + signal(SIGTERM, report); + + start = cl_get_time_stamp(); + + 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); + + mad_rpc_close_port(srcport); + + exit(-1); +} diff --git a/branches/WOF2-3/tools/infiniband-diags/src/ibping/SOURCES b/branches/WOF2-3/tools/infiniband-diags/src/ibping/SOURCES new file mode 100644 index 00000000..2b187a8b --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/ibping/SOURCES @@ -0,0 +1,33 @@ +TARGETNAME = ibping +TARGETPATH = ..\..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = PROGRAM + +UMTYPE = console +UMENTRY = main + +USE_MSVCRT = 1 + +SOURCES = ..\ibping.c ..\ibdiag_common.c ..\ibdiag_windows.c ibping.rc + +INCLUDES = ..\..\include;..\..\include\windows;\ + ..\..\..\..\ulp\libibmad\include;\ + ..\..\..\..\ulp\libibumad\include;\ + ..\..\..\..\inc;..\..\..\..\inc\user;\ + ..\..\..\..\inc\user\linux; + +C_DEFINES = $(C_DEFINES) /DHAVE_CONFIG_H + +TARGETLIBS = \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\complib.lib \ + $(TARGETPATH)\*\libibmad.lib \ + $(TARGETPATH)\*\libibumad.lib +!else + $(TARGETPATH)\*\complibd.lib \ + $(TARGETPATH)\*\libibmadd.lib \ + $(TARGETPATH)\*\libibumadd.lib +!endif + +MSC_WARNING_LEVEL = /W3 /WX /wd4007 diff --git a/branches/WOF2-3/tools/infiniband-diags/src/ibping/ibping.rc b/branches/WOF2-3/tools/infiniband-diags/src/ibping/ibping.rc new file mode 100644 index 00000000..62ee7657 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/ibping/ibping.rc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef DBG +#define VER_FILEDESCRIPTION_STR "InfiniBand MAD Ping (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "InfiniBand MAD Ping" +#endif + +#define VER_INTERNALNAME_STR "ibping.exe" +#define VER_ORIGINALFILENAME_STR "ibping.exe" + +#include diff --git a/branches/WOF2-3/tools/infiniband-diags/src/ibping/makefile b/branches/WOF2-3/tools/infiniband-diags/src/ibping/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/ibping/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\..\inc\openib.def diff --git a/branches/WOF2-3/tools/infiniband-diags/src/ibportstate.c b/branches/WOF2-3/tools/infiniband-diags/src/ibportstate.c new file mode 100644 index 00000000..499dabcb --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/ibportstate.c @@ -0,0 +1,485 @@ +/* + * Copyright (c) 2004-2009 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include + +#include +#include + +#include "ibdiag_common.h" + +enum port_ops { + QUERY, + ENABLE, + RESET, + DISABLE, + SPEED, + WIDTH, + DOWN, + ARM, + ACTIVE, + VLS, + MTU, + LID, + SMLID, + LMC, +}; + +struct ibmad_port *srcport; +int speed = 0; /* no state change */ +int width = 0; /* no state change */ +int lid; +int smlid; +int lmc; +int mtu; +int vls = 0; /* no state change */ + +struct { + const char *name; + int *val; + int set; +} port_args[] = { + {"query", NULL, 0}, /* QUERY */ + {"enable", NULL, 0}, /* ENABLE */ + {"reset", NULL, 0}, /* RESET */ + {"disable", NULL, 0}, /* DISABLE */ + {"speed", &speed, 0}, /* SPEED */ + {"width", &width, 0}, /* WIDTH */ + {"down", NULL, 0}, /* DOWN */ + {"arm", NULL, 0}, /* ARM */ + {"active", NULL, 0}, /* ACTIVE */ + {"vls", &vls, 0}, /* VLS */ + {"mtu", &mtu, 0}, /* MTU */ + {"lid", &lid, 0}, /* LID */ + {"smlid", &smlid, 0}, /* SMLID */ + {"lmc", &lmc, 0}, /* LMC */ +}; + +#define NPORT_ARGS (sizeof(port_args) / sizeof(port_args[0])) + +/*******************************************/ + +/* + * Return 1 if port is a switch, else zero. + */ +static int get_node_info(ib_portid_t * dest, uint8_t * data) +{ + int node_type; + + if (!smp_query_via(data, dest, IB_ATTR_NODE_INFO, 0, 0, srcport)) + IBERROR("smp query nodeinfo failed"); + + node_type = mad_get_field(data, 0, IB_NODE_TYPE_F); + if (node_type == IB_NODE_SWITCH) /* Switch NodeType ? */ + return 1; + else + return 0; +} + +static void get_port_info(ib_portid_t * dest, uint8_t * data, int portnum) +{ + if (!smp_query_via(data, dest, IB_ATTR_PORT_INFO, portnum, 0, srcport)) + IBERROR("smp query portinfo failed"); +} + +static void show_port_info(ib_portid_t * dest, uint8_t * data, int portnum) +{ + char buf[2048]; + char val[64]; + + mad_dump_portstates(buf, sizeof buf, data, sizeof data); + mad_decode_field(data, IB_PORT_LID_F, val); + mad_dump_field(IB_PORT_LID_F, buf + strlen(buf), + sizeof buf - strlen(buf), val); + sprintf(buf + strlen(buf), "%s", "\n"); + mad_decode_field(data, IB_PORT_SMLID_F, val); + mad_dump_field(IB_PORT_SMLID_F, buf + strlen(buf), + sizeof buf - strlen(buf), val); + sprintf(buf + strlen(buf), "%s", "\n"); + mad_decode_field(data, IB_PORT_LMC_F, val); + mad_dump_field(IB_PORT_LMC_F, buf + strlen(buf), + sizeof buf - strlen(buf), val); + sprintf(buf + strlen(buf), "%s", "\n"); + 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"); + + printf("# Port info: %s port %d\n%s", portid2str(dest), portnum, buf); +} + +static void set_port_info(ib_portid_t * dest, uint8_t * data, int portnum) +{ + if (!smp_set_via(data, dest, IB_ATTR_PORT_INFO, portnum, 0, srcport)) + IBERROR("smp set portinfo failed"); + + printf("\nAfter PortInfo set:\n"); + show_port_info(dest, data, portnum); +} + +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 & peerwidth & 0x8)) { + if (lwa != 8) + IBWARN + ("Peer ports operating at active width %d rather than 8 (12x)", + lwa); + } else if ((width & peerwidth & 0x4)) { + if (lwa != 4) + IBWARN + ("Peer ports operating at active width %d rather than 4 (8x)", + lwa); + } else if ((width & peerwidth & 0x2)) { + if (lwa != 2) + IBWARN + ("Peer ports operating at active width %d rather than 2 (4x)", + lwa); + } else if ((width & 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 & peerspeed & 0x4)) { + if (lsa != 4) + IBWARN + ("Peer ports operating at active speed %d rather than 4 (10.0 Gbps)", + lsa); + } else if ((speed & peerspeed & 0x2)) { + if (lsa != 2) + IBWARN + ("Peer ports operating at active speed %d rather than 2 (5.0 Gbps)", + lsa); + } else if ((speed & peerspeed & 0x1)) { + if (lsa != 1) + IBWARN + ("Peer ports operating at active speed %d rather than 1 (2.5 Gbps)", + lsa); + } +} + +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 }; + int port_op = -1; + int is_switch; + int state, physstate, lwe, lws, lwa, lse, lss, lsa; + int peerlocalportnum, peerlwe, peerlws, peerlwa, peerlse, peerlss, + peerlsa; + int 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; + int changed = 0; + int i; + long val; + char usage_args[] = " []\n" + "\nSupported ops: enable, disable, reset, speed, width, query,\n" + "\tdown, arm, active, vls, mtu, lid, smlid, lmc\n"; + const char *usage_examples[] = { + "3 1 disable\t\t\t# by lid", + "-G 0x2C9000100D051 1 enable\t# by guid", + "-D 0 1\t\t\t# (query) by direct route", + "3 1 reset\t\t\t# by lid", + "3 1 speed 1\t\t\t# by lid", + "3 1 width 1\t\t\t# by lid", + "-D 0 1 lid 0x1234 arm\t\t# by direct route", + NULL + }; + + ibdiag_process_opts(argc, argv, NULL, NULL, NULL, NULL, + usage_args, usage_examples); + + argc -= optind; + argv += optind; + + if (argc < 2) + ibdiag_show_usage(); + + srcport = mad_rpc_open_port(ibd_ca, ibd_ca_port, mgmt_classes, 3); + if (!srcport) + IBERROR("Failed to open '%s' port '%d'", ibd_ca, ibd_ca_port); + + if (ib_resolve_portid_str_via(&portid, argv[0], ibd_dest_type, + ibd_sm_id, srcport) < 0) + IBERROR("can't resolve destination port %s", argv[0]); + + if (argc > 1) + portnum = strtol(argv[1], 0, 0); + + for (i = 2; i < argc; i++) { + int j; + + for (j = 0; j < NPORT_ARGS; j++) { + if (strcmp(argv[i], port_args[j].name)) + continue; + port_args[j].set = 1; + if (!port_args[j].val) { + if (port_op >= 0) + IBERROR("%s only one of: ", + "query, enable, disable, " + "reset, down, arm, active, " + "can be specified", + port_args[j].name); + port_op = j; + break; + } + if (++i >= argc) + IBERROR("%s requires an additional parameter", + port_args[j].name); + val = strtol(argv[i], 0, 0); + switch (j) { + case SPEED: + if (val < 0 || val > 15) + IBERROR("invalid speed value %ld", val); + break; + case WIDTH: + if (val < 0 || (val > 15 && val != 255)) + IBERROR("invalid width value %ld", val); + break; + case VLS: + if (val <= 0 || val > 5) + IBERROR("invalid vls value %ld", val); + break; + case MTU: + if (val <= 0 || val > 5) + IBERROR("invalid mtu value %ld", val); + break; + case LID: + if (val <= 0 || val >= 0xC000) + IBERROR("invalid lid value 0x%lx", val); + break; + case SMLID: + if (val <= 0 || val >= 0xC000) + IBERROR("invalid smlid value 0x%lx", + val); + break; + case LMC: + if (val < 0 || val > 7) + IBERROR("invalid lmc value %ld", val); + } + *port_args[j].val = (int)val; + changed = 1; + break; + } + if (j == NPORT_ARGS) + IBERROR("invalid operation: %s", argv[i]); + } + if (port_op < 0) + port_op = QUERY; + + is_switch = get_node_info(&portid, data); + + if (port_op != QUERY || changed) + printf("Initial %s PortInfo:\n", is_switch ? "Switch" : "CA"); + else + printf("%s PortInfo:\n", is_switch ? "Switch" : "CA"); + get_port_info(&portid, data, portnum); + show_port_info(&portid, data, portnum); + + if (port_op != QUERY || changed) { + /* + * If we aren't setting the LID and the LID is the default, + * the SMA command will fail due to an invalid LID. + * Set it to something unlikely but valid. + */ + val = mad_get_field(data, 0, IB_PORT_LID_F); + if (!port_args[LID].set && (!val || val == 0xFFFF)) + mad_set_field(data, 0, IB_PORT_LID_F, 0x1234); + val = mad_get_field(data, 0, IB_PORT_SMLID_F); + if (!port_args[SMLID].set && (!val || val == 0xFFFF)) + mad_set_field(data, 0, IB_PORT_SMLID_F, 0x1234); + mad_set_field(data, 0, IB_PORT_STATE_F, 0); /* NOP */ + mad_set_field(data, 0, IB_PORT_PHYS_STATE_F, 0); /* NOP */ + + switch (port_op) { + case ENABLE: + case RESET: + /* Polling */ + mad_set_field(data, 0, IB_PORT_PHYS_STATE_F, 2); + break; + case DISABLE: + printf("Disable may be irreversible\n"); + mad_set_field(data, 0, IB_PORT_PHYS_STATE_F, 3); + break; + case DOWN: + mad_set_field(data, 0, IB_PORT_STATE_F, 1); + break; + case ARM: + mad_set_field(data, 0, IB_PORT_STATE_F, 3); + break; + case ACTIVE: + mad_set_field(data, 0, IB_PORT_STATE_F, 4); + break; + } + + /* always set enabled speed/width - defaults to NOP */ + mad_set_field(data, 0, IB_PORT_LINK_SPEED_ENABLED_F, speed); + mad_set_field(data, 0, IB_PORT_LINK_WIDTH_ENABLED_F, width); + + if (port_args[VLS].set) + mad_set_field(data, 0, IB_PORT_OPER_VLS_F, vls); + if (port_args[MTU].set) + mad_set_field(data, 0, IB_PORT_NEIGHBOR_MTU_F, mtu); + if (port_args[LID].set) + mad_set_field(data, 0, IB_PORT_LID_F, lid); + if (port_args[SMLID].set) + mad_set_field(data, 0, IB_PORT_SMLID_F, smlid); + if (port_args[LMC].set) + mad_set_field(data, 0, IB_PORT_LMC_F, lmc); + + set_port_info(&portid, data, portnum); + + } else if (is_switch && 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] = (uint8_t) portnum; + + /* Set DrSLID to local lid */ + if (ib_resolve_self_via(&selfportid, + &selfport, 0, srcport) < 0) + IBERROR("could not resolve self"); + peerportid.drpath.drslid = (uint16_t) selfportid.lid; + peerportid.drpath.drdlid = 0xffff; + + /* Get peer port NodeInfo to obtain peer port number */ + get_node_info(&peerportid, data); + + mad_decode_field(data, IB_NODE_LOCAL_PORT_F, + &peerlocalportnum); + + printf("Peer PortInfo:\n"); + /* Get peer port characteristics */ + get_port_info(&peerportid, data, peerlocalportnum); + show_port_info(&peerportid, data, peerlocalportnum); + + 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); + } + } + + mad_rpc_close_port(srcport); + exit(0); +} diff --git a/branches/WOF2-3/tools/infiniband-diags/src/ibportstate/SOURCES b/branches/WOF2-3/tools/infiniband-diags/src/ibportstate/SOURCES new file mode 100644 index 00000000..da92223e --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/ibportstate/SOURCES @@ -0,0 +1,30 @@ +TARGETNAME = ibportstate +TARGETPATH = ..\..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = PROGRAM + +UMTYPE = console +UMENTRY = main + +USE_MSVCRT = 1 + +SOURCES = ..\ibportstate.c ..\ibdiag_common.c ..\ibdiag_windows.c ibportstate.rc + +INCLUDES = ..\..\include;..\..\include\windows;\ + ..\..\..\..\ulp\libibmad\include;\ + ..\..\..\..\ulp\libibumad\include;\ + ..\..\..\..\inc;..\..\..\..\inc\user;\ + ..\..\..\..\inc\user\linux; + +C_DEFINES = $(C_DEFINES) /DHAVE_CONFIG_H + +TARGETLIBS = \ + $(SDK_LIB_PATH)\kernel32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\libibmad.lib \ + $(TARGETPATH)\*\libibumad.lib +!else + $(TARGETPATH)\*\libibmadd.lib \ + $(TARGETPATH)\*\libibumadd.lib +!endif + +MSC_WARNING_LEVEL = /W3 /WX /wd4007 diff --git a/branches/WOF2-3/tools/infiniband-diags/src/ibportstate/ibportstate.rc b/branches/WOF2-3/tools/infiniband-diags/src/ibportstate/ibportstate.rc new file mode 100644 index 00000000..8ba95aff --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/ibportstate/ibportstate.rc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef DBG +#define VER_FILEDESCRIPTION_STR "InfiniBand Port State (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "InfiniBand Port State" +#endif + +#define VER_INTERNALNAME_STR "ibportstate.exe" +#define VER_ORIGINALFILENAME_STR "ibportstate.exe" + +#include diff --git a/branches/WOF2-3/tools/infiniband-diags/src/ibportstate/makefile b/branches/WOF2-3/tools/infiniband-diags/src/ibportstate/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/ibportstate/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\..\inc\openib.def diff --git a/branches/WOF2-3/tools/infiniband-diags/src/ibqueryerrors.c b/branches/WOF2-3/tools/infiniband-diags/src/ibqueryerrors.c new file mode 100644 index 00000000..f04e47f0 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/ibqueryerrors.c @@ -0,0 +1,688 @@ +/* + * Copyright (c) 2004-2009 Voltaire Inc. All rights reserved. + * Copyright (c) 2007 Xsigo Systems Inc. All rights reserved. + * Copyright (c) 2008 Lawrence Livermore National Lab. All rights reserved. + * Copyright (c) 2009 HNR Consulting. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "ibdiag_common.h" + +struct ibmad_port *ibmad_port; +static char *node_name_map_file = NULL; +static nn_map_t *node_name_map = NULL; +static char *load_cache_file = NULL; + +int data_counters = 0; +int port_config = 0; +uint64_t node_guid = 0; +char *node_guid_str = NULL; +#define SUP_MAX 64 +int sup_total = 0; +enum MAD_FIELDS suppressed_fields[SUP_MAX]; +char *dr_path = NULL; +uint8_t node_type_to_print = 0; +unsigned clear_errors = 0, clear_counts = 0, details = 0; + +#define PRINT_SWITCH 0x1 +#define PRINT_CA 0x2 +#define PRINT_ROUTER 0x4 +#define PRINT_ALL 0xFF /* all nodes default flag */ + +static unsigned int get_max(unsigned int num) +{ + unsigned r = 0; // r will be lg(num) + + while (num >>= 1) // unroll for more speed... + r++; + + return (1 << r); +} + +static void get_msg(char *width_msg, char *speed_msg, int msg_size, + ibnd_port_t * port) +{ + char buf[64]; + uint32_t max_speed = 0; + + uint32_t max_width = get_max(mad_get_field(port->info, 0, + IB_PORT_LINK_WIDTH_SUPPORTED_F) + & mad_get_field(port->remoteport->info, 0, + IB_PORT_LINK_WIDTH_SUPPORTED_F)); + if ((max_width & mad_get_field(port->info, 0, + IB_PORT_LINK_WIDTH_ACTIVE_F)) == 0) + // we are not at the max supported width + // print what we could be at. + snprintf(width_msg, msg_size, "Could be %s", + mad_dump_val(IB_PORT_LINK_WIDTH_ACTIVE_F, + buf, 64, &max_width)); + + max_speed = get_max(mad_get_field(port->info, 0, + IB_PORT_LINK_SPEED_SUPPORTED_F) + & mad_get_field(port->remoteport->info, 0, + IB_PORT_LINK_SPEED_SUPPORTED_F)); + if ((max_speed & mad_get_field(port->info, 0, + IB_PORT_LINK_SPEED_ACTIVE_F)) == 0) + // we are not at the max supported speed + // print what we could be at. + snprintf(speed_msg, msg_size, "Could be %s", + mad_dump_val(IB_PORT_LINK_SPEED_ACTIVE_F, + buf, 64, &max_speed)); +} + +static void print_port_config(char *node_name, ibnd_node_t * node, int portnum) +{ + char width[64], speed[64], state[64], physstate[64]; + char remote_str[256]; + char link_str[256]; + char width_msg[256]; + char speed_msg[256]; + char ext_port_str[256]; + int iwidth, ispeed, istate, iphystate; + + ibnd_port_t *port = node->ports[portnum]; + + if (!port) + return; + + iwidth = mad_get_field(port->info, 0, IB_PORT_LINK_WIDTH_ACTIVE_F); + ispeed = mad_get_field(port->info, 0, IB_PORT_LINK_SPEED_ACTIVE_F); + istate = mad_get_field(port->info, 0, IB_PORT_STATE_F); + iphystate = mad_get_field(port->info, 0, IB_PORT_PHYS_STATE_F); + + remote_str[0] = '\0'; + link_str[0] = '\0'; + width_msg[0] = '\0'; + speed_msg[0] = '\0'; + + /* C14-24.2.1 states that a down port allows for invalid data to be + * returned for all PortInfo components except PortState and + * PortPhysicalState */ + if (istate != IB_LINK_DOWN) { + snprintf(link_str, 256, "(%3s %9s %6s/%8s)", + mad_dump_val(IB_PORT_LINK_WIDTH_ACTIVE_F, width, 64, &iwidth), + mad_dump_val(IB_PORT_LINK_SPEED_ACTIVE_F, speed, 64, &ispeed), + mad_dump_val(IB_PORT_STATE_F, state, 64, &istate), + mad_dump_val(IB_PORT_PHYS_STATE_F, physstate, 64, &iphystate)); + } else { + snprintf(link_str, 256, "( %6s/%8s)", + mad_dump_val(IB_PORT_STATE_F, state, 64, &istate), + mad_dump_val(IB_PORT_PHYS_STATE_F, physstate, 64, &iphystate)); + } + + if (port->remoteport) { + char *rem_node_name = NULL; + + if (port->remoteport->ext_portnum) + snprintf(ext_port_str, 256, "%d", + port->remoteport->ext_portnum); + else + ext_port_str[0] = '\0'; + + get_msg(width_msg, speed_msg, 256, port); + + rem_node_name = remap_node_name(node_name_map, + port->remoteport->node->guid, + port->remoteport->node-> + nodedesc); + + snprintf(remote_str, 256, + "0x%016" PRIx64 " %6d %4d[%2s] \"%s\" (%s %s)\n", + port->remoteport->node->guid, + port->remoteport->base_lid ? port->remoteport-> + base_lid : port->remoteport->node->smalid, + port->remoteport->portnum, ext_port_str, rem_node_name, + width_msg, speed_msg); + + free(rem_node_name); + } else + snprintf(remote_str, 256, " [ ] \"\" ( )\n"); + + if (port->ext_portnum) + snprintf(ext_port_str, 256, "%d", port->ext_portnum); + else + ext_port_str[0] = '\0'; + + if (node->type == IB_NODE_SWITCH) + printf(" Link info: %6d", node->smalid); + else + printf(" Link info: %6d", port->base_lid); + + printf("%4d[%2s] ==%s==> %s", + port->portnum, ext_port_str, link_str, remote_str); +} + +static int suppress(enum MAD_FIELDS field) +{ + int i = 0; + for (i = 0; i < sup_total; i++) + if (field == suppressed_fields[i]) + return 1; + return 0; +} + +static void report_suppressed(void) +{ + int i = 0; + printf("Suppressing:"); + for (i = 0; i < sup_total; i++) + printf(" %s", mad_field_name(suppressed_fields[i])); + printf("\n"); +} + +static int query_and_dump(char *buf, size_t size, ib_portid_t * portid, + ibnd_node_t * node, char *node_name, int portnum, + const char *attr_name, uint16_t attr_id, + int start_field, int end_field) +{ + uint8_t pc[1024]; + uint32_t val = 0; + int i, n; + + memset(pc, 0, sizeof(pc)); + + if (!pma_query_via(pc, portid, portnum, ibd_timeout, attr_id, + ibmad_port)) { + IBWARN("%s query failed on %s, %s port %d", attr_name, + node_name, portid2str(portid), portnum); + return 0; + } + + for (n = 0, i = start_field; i < end_field; i++) { + mad_decode_field(pc, i, (void *)&val); + if (val) + n += snprintf(buf + n, size - n, " [%s == %u]", + mad_field_name(i), val); + } + + return n; +} + +static void print_results(ib_portid_t * portid, char *node_name, + ibnd_node_t * node, uint8_t * pc, int portnum, + int *header_printed) +{ + char buf[1024]; + char *str = buf; + uint32_t val = 0; + int i, n; + + for (n = 0, i = IB_PC_ERR_SYM_F; i <= IB_PC_VL15_DROPPED_F; i++) { + if (suppress(i)) + continue; + + /* this is not a counter, skip it */ + if (i == IB_PC_COUNTER_SELECT2_F) + continue; + + mad_decode_field(pc, i, (void *)&val); + if (val) + n += snprintf(str + n, 1024 - n, " [%s == %u]", + mad_field_name(i), val); + + /* If there are PortXmitDiscards, get details (if supported) */ + if (i == IB_PC_XMT_DISCARDS_F && details && val) { + n += query_and_dump(str + n, sizeof(buf) - n, portid, + node, node_name, portnum, + "PortXmitDiscardDetails", + IB_GSI_PORT_XMIT_DISCARD_DETAILS, + IB_PC_RCV_LOCAL_PHY_ERR_F, + IB_PC_RCV_ERR_LAST_F); + /* If there are PortRcvErrors, get details (if supported) */ + } else if (i == IB_PC_ERR_RCV_F && details && val) { + n += query_and_dump(str + n, sizeof(buf) - n, portid, + node, node_name, portnum, + "PortRcvErrorDetails", + IB_GSI_PORT_RCV_ERROR_DETAILS, + IB_PC_XMT_INACT_DISC_F, + IB_PC_XMT_DISC_LAST_F); + } + } + + if (!suppress(IB_PC_XMT_WAIT_F)) { + mad_decode_field(pc, IB_PC_XMT_WAIT_F, (void *)&val); + if (val) + n += snprintf(str + n, 1024 - n, " [%s == %u]", + mad_field_name(IB_PC_XMT_WAIT_F), val); + } + + /* if we found errors. */ + if (n != 0) { + if (data_counters) + for (i = IB_PC_XMT_BYTES_F; i <= IB_PC_RCV_PKTS_F; i++) { + uint64_t val64 = 0; + mad_decode_field(pc, i, (void *)&val64); + if (val64) + n += snprintf(str + n, 1024 - n, + " [%s == %" PRIu64 "]", + mad_field_name(i), val64); + } + + if (!*header_printed) { + printf("Errors for 0x%" PRIx64 " \"%s\"\n", node->guid, + node_name); + *header_printed = 1; + } + + printf(" GUID 0x%" PRIx64 " port %d:%s\n", node->guid, + portnum, str); + if (port_config) + print_port_config(node_name, node, portnum); + } +} + +static int query_cap_mask(ib_portid_t * portid, char *node_name, int portnum, + uint16_t * cap_mask) +{ + uint8_t pc[1024]; + uint16_t rc_cap_mask; + + /* PerfMgt ClassPortInfo is a required attribute */ + if (!pma_query_via(pc, portid, portnum, ibd_timeout, CLASS_PORT_INFO, + ibmad_port)) { + IBWARN("classportinfo query failed on %s, %s port %d", + node_name, portid2str(portid), portnum); + return -1; + } + + /* ClassPortInfo should be supported as part of libibmad */ + memcpy(&rc_cap_mask, pc + 2, sizeof(rc_cap_mask)); /* CapabilityMask */ + + *cap_mask = ntohs(rc_cap_mask); + return 0; +} + +static void print_port(ib_portid_t * portid, uint16_t cap_mask, char *node_name, + ibnd_node_t * node, int portnum, int *header_printed) +{ + uint8_t pc[1024]; + + memset(pc, 0, 1024); + + if (!pma_query_via(pc, portid, portnum, ibd_timeout, + IB_GSI_PORT_COUNTERS, ibmad_port)) { + IBWARN("IB_GSI_PORT_COUNTERS query failed on %s, %s port %d", + node_name, portid2str(portid), portnum); + return; + } + if (!(cap_mask & 0x1000)) { + /* if PortCounters:PortXmitWait not supported clear this counter */ + uint32_t foo = 0; + mad_encode_field(pc, IB_PC_XMT_WAIT_F, &foo); + } + print_results(portid, node_name, node, pc, portnum, header_printed); +} + +static void clear_port(ib_portid_t * portid, uint16_t cap_mask, + char *node_name, int port) +{ + uint8_t pc[1024]; + /* bits defined in Table 228 PortCounters CounterSelect and + * CounterSelect2 + */ + uint32_t mask = 0; + + if (!clear_errors && !clear_counts) + return; + + if (clear_errors) { + mask |= 0xFFF; + if (cap_mask & 0x1000) + mask |= 0x10000; + } + if (clear_counts) + mask |= 0xF000; + + if (!performance_reset_via(pc, portid, port, mask, ibd_timeout, + IB_GSI_PORT_COUNTERS, ibmad_port)) + IBERROR("Failed to reset errors %s port %d", node_name, port); + + if (details && clear_errors) { + performance_reset_via(pc, portid, port, 0xf, ibd_timeout, + IB_GSI_PORT_XMIT_DISCARD_DETAILS, + ibmad_port); + performance_reset_via(pc, portid, port, 0x3f, ibd_timeout, + IB_GSI_PORT_RCV_ERROR_DETAILS, + ibmad_port); + } +} + +void print_node(ibnd_node_t * node, void *user_data) +{ + int header_printed = 0; + int p = 0; + int startport = 1; + int type = 0; + int all_port_sup = 0; + ib_portid_t portid = { 0 }; + uint16_t cap_mask = 0; + char *node_name = NULL; + + switch (node->type) { + case IB_NODE_SWITCH: + type = PRINT_SWITCH; + break; + case IB_NODE_CA: + type = PRINT_CA; + break; + case IB_NODE_ROUTER: + type = PRINT_ROUTER; + break; + } + + if ((type & node_type_to_print) == 0) + return; + + if (node->type == IB_NODE_SWITCH && node->smaenhsp0) + startport = 0; + + node_name = remap_node_name(node_name_map, node->guid, node->nodedesc); + + for (p = startport; p <= node->numports; p++) { + if (node->ports[p]) { + if (node->type == IB_NODE_SWITCH) + ib_portid_set(&portid, node->smalid, 0, 0); + else + ib_portid_set(&portid, node->ports[p]->base_lid, + 0, 0); + + if (query_cap_mask(&portid, node_name, p, &cap_mask) < + 0) + continue; + + if (cap_mask & 0x100) + all_port_sup = 1; + + print_port(&portid, cap_mask, node_name, node, p, + &header_printed); + if (!all_port_sup) + clear_port(&portid, cap_mask, node_name, p); + } + } + + if (all_port_sup) + clear_port(&portid, cap_mask, node_name, 0xFF); + + free(node_name); +} + +static void add_suppressed(enum MAD_FIELDS field) +{ + if (sup_total >= SUP_MAX) { + IBWARN("Maximum (%d) fields have been suppressed; skipping %s", + sup_total, mad_field_name(field)); + return; + } + suppressed_fields[sup_total++] = field; +} + +static void calculate_suppressed_fields(char *str) +{ + enum MAD_FIELDS f; + char *val, *lasts = NULL; + char *tmp = strdup(str); + + val = strtok_r(tmp, ",", &lasts); + while (val) { + for (f = IB_PC_FIRST_F; f <= IB_PC_LAST_F; f++) + if (strcmp(val, mad_field_name(f)) == 0) + add_suppressed(f); + val = strtok_r(NULL, ",", &lasts); + } + + free(tmp); +} + +static int process_opt(void *context, int ch, char *optarg) +{ + struct ibnd_config *cfg = context; + switch (ch) { + case 's': + calculate_suppressed_fields(optarg); + break; + case 'c': + /* Right now this is the only "common" error */ + add_suppressed(IB_PC_ERR_SWITCH_REL_F); + break; + case 1: + node_name_map_file = strdup(optarg); + break; + case 2: + data_counters++; + break; + case 3: + node_type_to_print |= PRINT_SWITCH; + break; + case 4: + node_type_to_print |= PRINT_CA; + break; + case 5: + node_type_to_print |= PRINT_ROUTER; + break; + case 6: + details = 1; + break; + case 7: + load_cache_file = strdup(optarg); + break; + case 'G': + case 'S': + node_guid_str = optarg; + node_guid = strtoull(optarg, 0, 0); + break; + case 'D': + dr_path = strdup(optarg); + break; + case 'r': + port_config++; + break; + case 'R': /* nop */ + break; + case 'k': + clear_errors = 1; + break; + case 'K': + clear_counts = 1; + break; + case 'o': + cfg->max_smps = strtoul(optarg, NULL, 0); + break; + default: + return -1; + } + + return 0; +} + +int main(int argc, char **argv) +{ + struct ibnd_config config = { 0 }; + int resolved = -1; + ib_portid_t portid = { 0 }; + int rc = 0; + ibnd_fabric_t *fabric = NULL; + + int mgmt_classes[4] = { IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS, + IB_PERFORMANCE_CLASS + }; + + const struct ibdiag_opt opts[] = { + {"suppress", 's', 1, "", + "suppress errors listed"}, + {"suppress-common", 'c', 0, NULL, + "suppress some of the common counters"}, + {"node-name-map", 1, 1, "", "node name map file"}, + {"node-guid", 'G', 1, "", "query only "}, + {"", 'S', 1, "", + "Same as \"-G\" for backward compatibility"}, + {"Direct", 'D', 1, "", + "query only switch specified by "}, + {"report-port", 'r', 0, NULL, + "report port configuration information"}, + {"GNDN", 'R', 0, NULL, + "(This option is obsolete and does nothing)"}, + {"data", 2, 0, NULL, "include the data counters in the output"}, + {"switch", 3, 0, NULL, "print data for switches only"}, + {"ca", 4, 0, NULL, "print data for CA's only"}, + {"router", 5, 0, NULL, "print data for routers only"}, + {"details", 6, 0, NULL, "include transmit discard details"}, + {"clear-errors", 'k', 0, NULL, + "Clear error counters after read"}, + {"clear-counts", 'K', 0, NULL, + "Clear data counters after read"}, + {"load-cache", 7, 1, "", + "filename of ibnetdiscover cache to load"}, + {"outstanding_smps", 'o', 1, NULL, + "specify the number of outstanding SMP's which should be " + "issued during the scan"}, + {0} + }; + char usage_args[] = ""; + + memset(suppressed_fields, 0, sizeof suppressed_fields); + ibdiag_process_opts(argc, argv, &config, "scnSrRDGL", opts, process_opt, + usage_args, NULL); + + argc -= optind; + argv += optind; + + if (!node_type_to_print) + node_type_to_print = PRINT_ALL; + + ibmad_port = mad_rpc_open_port(ibd_ca, ibd_ca_port, mgmt_classes, 4); + if (!ibmad_port) + IBERROR("Failed to open port; %s:%d\n", ibd_ca, ibd_ca_port); + + if (ibd_timeout) { + mad_rpc_set_timeout(ibmad_port, ibd_timeout); + config.timeout_ms = ibd_timeout; + } + + node_name_map = open_node_name_map(node_name_map_file); + + if (dr_path && load_cache_file) { + fprintf(stderr, "Cannot specify cache and direct route path\n"); + exit(1); + } + + /* limit the scan the fabric around the target */ + if (dr_path) { + if ((resolved = + ib_resolve_portid_str_via(&portid, dr_path, IB_DEST_DRPATH, + NULL, ibmad_port)) < 0) + IBWARN("Failed to resolve %s; attempting full scan", + dr_path); + } else if (node_guid_str) { + if ((resolved = + ib_resolve_portid_str_via(&portid, node_guid_str, + IB_DEST_GUID, ibd_sm_id, + ibmad_port)) < 0) + IBWARN("Failed to resolve %s; attempting full scan", + node_guid_str); + } + + if (load_cache_file) { + if ((fabric = ibnd_load_fabric(load_cache_file, 0)) == NULL) { + fprintf(stderr, "loading cached fabric failed\n"); + exit(1); + } + } else { + if (resolved >= 0 && + !(fabric = ibnd_discover_fabric(ibd_ca, ibd_ca_port, + &portid, &config))) + IBWARN("Single node discover failed;" + " attempting full scan"); + + if (!fabric && !(fabric = ibnd_discover_fabric(ibd_ca, + ibd_ca_port, + NULL, + &config))) { + fprintf(stderr, "discover failed\n"); + rc = 1; + goto close_port; + } + } + + report_suppressed(); + + if (node_guid_str) { + ibnd_node_t *node = ibnd_find_node_guid(fabric, node_guid); + if (node) + print_node(node, NULL); + else + fprintf(stderr, "Failed to find node: %s\n", + node_guid_str); + } else if (dr_path) { + ibnd_node_t *node = ibnd_find_node_dr(fabric, dr_path); + uint8_t ni[IB_SMP_DATA_SIZE]; + + if (!smp_query_via(ni, &portid, IB_ATTR_NODE_INFO, 0, + ibd_timeout, ibmad_port)) { + rc = -1; + goto destroy_fabric; + } + mad_decode_field(ni, IB_NODE_GUID_F, &(node_guid)); + + node = ibnd_find_node_guid(fabric, node_guid); + if (node) + print_node(node, NULL); + else + fprintf(stderr, "Failed to find node: %s\n", dr_path); + } else + ibnd_iter_nodes(fabric, print_node, NULL); + +destroy_fabric: + ibnd_destroy_fabric(fabric); + +close_port: + mad_rpc_close_port(ibmad_port); + close_node_name_map(node_name_map); + exit(rc); +} diff --git a/branches/WOF2-3/tools/infiniband-diags/src/ibqueryerrors/SOURCES b/branches/WOF2-3/tools/infiniband-diags/src/ibqueryerrors/SOURCES new file mode 100644 index 00000000..75b9f903 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/ibqueryerrors/SOURCES @@ -0,0 +1,36 @@ +TARGETNAME = ibqueryerrors +TARGETPATH = ..\..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = PROGRAM + +UMTYPE = console +UMENTRY = main + +USE_MSVCRT = 1 + +SOURCES = ..\ibqueryerrors.c ..\ibdiag_common.c ..\ibdiag_windows.c ibqueryerrors.rc + +INCLUDES = ..\..\include;..\..\include\windows;\ + ..\..\..\..\ulp\libibnetdisc\include;\ + ..\..\..\..\ulp\libibmad\include;\ + ..\..\..\..\ulp\libibumad\include;\ + ..\..\..\..\inc;..\..\..\..\inc\user;\ + ..\..\..\..\inc\user\linux; + +C_DEFINES = $(C_DEFINES) /DHAVE_CONFIG_H + +TARGETLIBS = \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\complib.lib \ + $(TARGETPATH)\*\libibmad.lib \ + $(TARGETPATH)\*\libibumad.lib \ + $(TARGETPATH)\*\libibnetdisc.lib +!else + $(TARGETPATH)\*\complibd.lib \ + $(TARGETPATH)\*\libibmadd.lib \ + $(TARGETPATH)\*\libibumadd.lib \ + $(TARGETPATH)\*\libibnetdiscd.lib +!endif + +MSC_WARNING_LEVEL = /W3 /WX /wd4007 diff --git a/branches/WOF2-3/tools/infiniband-diags/src/ibqueryerrors/ibqueryerrors.rc b/branches/WOF2-3/tools/infiniband-diags/src/ibqueryerrors/ibqueryerrors.rc new file mode 100644 index 00000000..a14b4a05 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/ibqueryerrors/ibqueryerrors.rc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef DBG +#define VER_FILEDESCRIPTION_STR "InfiniBand Error Reporting (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "InfiniBand Error Reporting" +#endif + +#define VER_INTERNALNAME_STR "ibqueryerrors.exe" +#define VER_ORIGINALFILENAME_STR "ibqueryerrors.exe" + +#include diff --git a/branches/WOF2-3/tools/infiniband-diags/src/ibqueryerrors/makefile b/branches/WOF2-3/tools/infiniband-diags/src/ibqueryerrors/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/ibqueryerrors/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\..\inc\openib.def diff --git a/branches/WOF2-3/tools/infiniband-diags/src/ibroute.c b/branches/WOF2-3/tools/infiniband-diags/src/ibroute.c new file mode 100644 index 00000000..b765c847 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/ibroute.c @@ -0,0 +1,452 @@ +/* + * Copyright (c) 2004-2009 Voltaire Inc. All rights reserved. + * Copyright (c) 2009 Mellanox Technologies LTD. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "ibdiag_common.h" + +struct ibmad_port *srcport; + +static int brief, dump_all, multicast; + +/*******************************************/ + +char *check_switch(ib_portid_t * portid, unsigned 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_via(ni, portid, IB_ATTR_NODE_INFO, 0, 0, srcport)) { + xdump(stderr, "nodeinfo\n", ni, sizeof ni); + return "node info failed: valid addr?"; + } + + if (!smp_query_via(nd, portid, IB_ATTR_NODE_DESC, 0, 0, srcport)) + 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_via(sw, portid, IB_ATTR_SWITCH_INFO, 0, 0, srcport)) + 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, unsigned mlid, unsigned nports, + uint16_t mft[16][IB_MLIDS_IN_BLOCK]) +{ + uint16_t mask; + unsigned i, chunk, bit, nonzero = 0; + + if (brief) { + int n = 0; + unsigned 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, unsigned startlid, + unsigned 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; + unsigned block, i, j, e, nports, cap, chunks, startblock, lastblock, + top; + int n = 0; + + if ((s = check_switch(portid, &nports, &nodeguid, sw, nd))) + return s; + + mad_decode_field(sw, IB_SW_MCAST_FDB_CAP_F, &cap); + mad_decode_field(sw, IB_SW_MCAST_FDB_TOP_F, &top); + + if (!endlid || endlid > IB_MIN_MCAST_LID + cap - 1) + endlid = IB_MIN_MCAST_LID + cap - 1; + if (!dump_all && top && top < endlid) { + if (top < IB_MIN_MCAST_LID - 1) + IBWARN("illegal top mlid %x", top); + else + endlid = top; + } + + if (!startlid) + startlid = IB_MIN_MCAST_LID; + else 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 (ibverbose) + printf("Switch multicast mlid capability is %d top is 0x%x\n", + cap, top); + + 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_via + (mft + j, portid, IB_ATTR_MULTICASTFORWTBL, mod, 0, + srcport)) + 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_via(nd, &lidport, IB_ATTR_NODE_DESC, 0, 100, srcport) || + !smp_query_via(pi, &lidport, IB_ATTR_PORT_INFO, 0, 100, srcport) || + !smp_query_via(ni, &lidport, IB_ATTR_NODE_INFO, 0, 100, srcport)) + 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, top; + unsigned nports; + 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("illegal 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_via(lft, portid, IB_ATTR_LINEARFORWTBL, block, + 0, srcport)) + 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; +} + +static int process_opt(void *context, int ch, char *optarg) +{ + switch (ch) { + case 'a': + dump_all++; + break; + case 'M': + multicast++; + break; + case 'n': + brief++; + break; + default: + return -1; + } + return 0; +} + +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 }; + unsigned startlid = 0, endlid = 0; + char *err; + + const struct ibdiag_opt opts[] = { + {"all", 'a', 0, NULL, "show all lids, even invalid entries"}, + {"no_dests", 'n', 0, NULL, + "do not try to resolve destinations"}, + {"Multicast", 'M', 0, NULL, "show multicast forwarding tables"}, + {0} + }; + char usage_args[] = "[ [ []]]"; + const char *usage_examples[] = { + " -- Unicast examples:", + "4\t# dump all lids with valid out ports of switch with lid 4", + "-a 4\t# same, but dump all lids, even with invalid out ports", + "-n 4\t# simple dump format - no destination resolving", + "4 10\t# dump lids starting from 10", + "4 0x10 0x20\t# dump lid range", + "-G 0x08f1040023\t# resolve switch by GUID", + "-D 0,1\t# resolve switch by direct path", + " -- Multicast examples:", + "-M 4\t# dump all non empty mlids of switch with lid 4", + "-M 4 0xc010 0xc020\t# same, but with range", + "-M -n 4\t# simple dump format", + NULL, + }; + + ibdiag_process_opts(argc, argv, NULL, NULL, opts, process_opt, + usage_args, usage_examples); + + argc -= optind; + argv += optind; + + if (!argc) + ibdiag_show_usage(); + + if (argc > 1) + startlid = strtoul(argv[1], 0, 0); + if (argc > 2) + endlid = strtoul(argv[2], 0, 0); + + srcport = mad_rpc_open_port(ibd_ca, ibd_ca_port, mgmt_classes, 3); + if (!srcport) + IBERROR("Failed to open '%s' port '%d'", ibd_ca, ibd_ca_port); + + if (!argc) { + if (ib_resolve_self_via(&portid, 0, 0, srcport) < 0) + IBERROR("can't resolve self addr"); + } else if (ib_resolve_portid_str_via(&portid, argv[0], ibd_dest_type, + ibd_sm_id, srcport) < 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); + + mad_rpc_close_port(srcport); + exit(0); +} diff --git a/branches/WOF2-3/tools/infiniband-diags/src/ibroute/SOURCES b/branches/WOF2-3/tools/infiniband-diags/src/ibroute/SOURCES new file mode 100644 index 00000000..9c01dfcf --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/ibroute/SOURCES @@ -0,0 +1,33 @@ +TARGETNAME = ibroute +TARGETPATH = ..\..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = PROGRAM + +UMTYPE = console +UMENTRY = main + +USE_MSVCRT = 1 + +SOURCES = ..\ibroute.c ..\ibdiag_common.c ..\ibdiag_windows.c ibroute.rc + +INCLUDES = ..\..\include;..\..\include\windows;\ + ..\..\..\..\ulp\libibmad\include;\ + ..\..\..\..\ulp\libibumad\include;\ + ..\..\..\..\inc;..\..\..\..\inc\user;\ + ..\..\..\..\inc\user\linux; + +C_DEFINES = $(C_DEFINES) /DHAVE_CONFIG_H + +TARGETLIBS = \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\complib.lib \ + $(TARGETPATH)\*\libibmad.lib \ + $(TARGETPATH)\*\libibumad.lib +!else + $(TARGETPATH)\*\complibd.lib \ + $(TARGETPATH)\*\libibmadd.lib \ + $(TARGETPATH)\*\libibumadd.lib +!endif + +MSC_WARNING_LEVEL = /W3 /WX /wd4007 \ No newline at end of file diff --git a/branches/WOF2-3/tools/infiniband-diags/src/ibroute/ibroute.rc b/branches/WOF2-3/tools/infiniband-diags/src/ibroute/ibroute.rc new file mode 100644 index 00000000..8fa48bbf --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/ibroute/ibroute.rc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef DBG +#define VER_FILEDESCRIPTION_STR "Query InfiniBand Switch Forwarding Tables (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "Query InfiniBand Switch Forwarding Tables" +#endif + +#define VER_INTERNALNAME_STR "ibroute.exe" +#define VER_ORIGINALFILENAME_STR "ibroute.exe" + +#include diff --git a/branches/WOF2-3/tools/infiniband-diags/src/ibroute/makefile b/branches/WOF2-3/tools/infiniband-diags/src/ibroute/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/ibroute/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\..\inc\openib.def diff --git a/branches/WOF2-3/tools/infiniband-diags/src/ibsendtrap.c b/branches/WOF2-3/tools/infiniband-diags/src/ibsendtrap.c new file mode 100644 index 00000000..1b915955 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/ibsendtrap.c @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2008 Lawrence Livermore National Security + * Copyright (c) 2008-2009 Voltaire Inc. All rights reserved. + * Copyright (c) 2009 HNR Consulting. All rights reserved. + * + * Produced at Lawrence Livermore National Laboratory. + * Written by Ira Weiny . + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#include +#include +#include +#include + +#define _GNU_SOURCE +#include + +#include +#include + +#include "ibdiag_common.h" + +struct ibmad_port *srcport; +/* for local link integrity */ +int error_port = 1; + +static uint16_t get_node_type(ib_portid_t * port) +{ + uint16_t node_type = IB_NODE_TYPE_CA; + uint8_t data[IB_SMP_DATA_SIZE]; + + if (smp_query_via(data, port, IB_ATTR_NODE_INFO, 0, 0, srcport)) + node_type = (uint16_t) mad_get_field(data, 0, IB_NODE_TYPE_F); + return node_type; +} + +static uint32_t get_cap_mask(ib_portid_t * port) +{ + uint8_t data[IB_SMP_DATA_SIZE]; + uint32_t cap_mask = 0; + + if (smp_query_via(data, port, IB_ATTR_PORT_INFO, 0, 0, srcport)) + cap_mask = (uint32_t) mad_get_field(data, 0, IB_PORT_CAPMASK_F); + return cap_mask; +} + +static void build_trap145(ib_mad_notice_attr_t * n, ib_portid_t * port) +{ + n->generic_type = 0x80 | IB_NOTICE_TYPE_INFO; + n->g_or_v.generic.prod_type_lsb = cl_hton16(get_node_type(port)); + n->g_or_v.generic.trap_num = cl_hton16(145); + n->issuer_lid = cl_hton16((uint16_t) port->lid); + n->data_details.ntc_145.new_sys_guid = cl_hton64(0x1234567812345678); +} + +static void build_trap144_local(ib_mad_notice_attr_t * n, ib_portid_t * port) +{ + n->generic_type = 0x80 | IB_NOTICE_TYPE_INFO; + n->g_or_v.generic.prod_type_lsb = cl_hton16(get_node_type(port)); + n->g_or_v.generic.trap_num = cl_hton16(144); + n->issuer_lid = cl_hton16((uint16_t) port->lid); + n->data_details.ntc_144.lid = n->issuer_lid; + n->data_details.ntc_144.new_cap_mask = cl_hton32(get_cap_mask(port)); + n->data_details.ntc_144.local_changes = + TRAP_144_MASK_OTHER_LOCAL_CHANGES; +} + +static void build_trap144_nodedesc(ib_mad_notice_attr_t * n, ib_portid_t * port) +{ + build_trap144_local(n, port); + n->data_details.ntc_144.change_flgs = + TRAP_144_MASK_NODE_DESCRIPTION_CHANGE; +} + +static void build_trap144_linkspeed(ib_mad_notice_attr_t * n, + ib_portid_t * port) +{ + build_trap144_local(n, port); + n->data_details.ntc_144.change_flgs = + TRAP_144_MASK_LINK_SPEED_ENABLE_CHANGE; +} + +static void build_trap129(ib_mad_notice_attr_t * n, ib_portid_t * port) +{ + n->generic_type = 0x80 | IB_NOTICE_TYPE_URGENT; + n->g_or_v.generic.prod_type_lsb = cl_hton16(get_node_type(port)); + n->g_or_v.generic.trap_num = cl_hton16(129); + n->issuer_lid = cl_hton16((uint16_t) port->lid); + n->data_details.ntc_129_131.lid = n->issuer_lid; + n->data_details.ntc_129_131.pad = 0; + n->data_details.ntc_129_131.port_num = (uint8_t) error_port; +} + +static int send_trap(const char *name, + void (*build) (ib_mad_notice_attr_t *, ib_portid_t *)) +{ + 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_via(&selfportid, &selfport, NULL, srcport)) + IBERROR("can't resolve self"); + + if (ib_resolve_smlid_via(&sm_port, 0, srcport)) + IBERROR("can't resolve SM destination port"); + + memset(&trap_rpc, 0, sizeof(trap_rpc)); + trap_rpc.mgtclass = IB_SMI_CLASS; + trap_rpc.method = IB_MAD_METHOD_TRAP; + trap_rpc.trid = mad_trid(); + trap_rpc.attr.id = NOTICE; + trap_rpc.datasz = IB_SMP_DATA_SIZE; + trap_rpc.dataoffs = IB_SMP_DATA_OFFS; + + memset(¬ice, 0, sizeof(notice)); + build(¬ice, &selfportid); + + return mad_send_via(&trap_rpc, &sm_port, NULL, ¬ice, srcport); +} + +typedef struct _trap_def { + char *trap_name; + void (*build_func) (ib_mad_notice_attr_t *, ib_portid_t *); +} trap_def_t; + +static const trap_def_t traps[] = { + {"node_desc_change", build_trap144_nodedesc}, + {"link_speed_enabled_change", build_trap144_linkspeed}, + {"local_link_integrity", build_trap129}, + {"sys_image_guid_change", build_trap145}, + {NULL, NULL} +}; + +int process_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 send_trap(trap_name, traps[i].build_func); + ibdiag_show_usage(); + return 1; +} + +int main(int argc, char **argv) +{ + char usage_args[1024]; + int mgmt_classes[2] = { IB_SMI_CLASS, IB_SMI_DIRECT_CLASS }; + char *trap_name = NULL; + int i, n, rc; + + n = sprintf(usage_args, "[] []\n" + "\nArgument can be one of the following:\n"); + for (i = 0; traps[i].trap_name; i++) { + n += snprintf(usage_args + n, sizeof(usage_args) - n, + " %s\n", traps[i].trap_name); + if (n >= sizeof(usage_args)) + exit(-1); + } + snprintf(usage_args + n, sizeof(usage_args) - n, + "\n default behavior is to send \"%s\"", traps[0].trap_name); + + ibdiag_process_opts(argc, argv, NULL, "DLG", NULL, NULL, + usage_args, NULL); + + argc -= optind; + argv += optind; + + trap_name = argv[0] ? argv[0] : traps[0].trap_name; + + if (argc > 1) + error_port = atoi(argv[1]); + + madrpc_show_errors(1); + + srcport = mad_rpc_open_port(ibd_ca, ibd_ca_port, mgmt_classes, 2); + if (!srcport) + IBERROR("Failed to open '%s' port '%d'", ibd_ca, ibd_ca_port); + + rc = process_send_trap(trap_name); + mad_rpc_close_port(srcport); + return rc; +} diff --git a/branches/WOF2-3/tools/infiniband-diags/src/ibsendtrap/SOURCES b/branches/WOF2-3/tools/infiniband-diags/src/ibsendtrap/SOURCES new file mode 100644 index 00000000..f50020db --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/ibsendtrap/SOURCES @@ -0,0 +1,30 @@ +TARGETNAME = ibsendtrap +TARGETPATH = ..\..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = PROGRAM + +UMTYPE = console +UMENTRY = main + +USE_MSVCRT = 1 + +SOURCES = ..\ibsendtrap.c ..\ibdiag_common.c ..\ibdiag_windows.c ibsendtrap.rc + +INCLUDES = ..\..\include;..\..\include\windows;\ + ..\..\..\..\ulp\libibmad\include;\ + ..\..\..\..\ulp\libibumad\include;\ + ..\..\..\..\inc;..\..\..\..\inc\user;\ + ..\..\..\..\inc\user\linux; + +C_DEFINES = $(C_DEFINES) /DHAVE_CONFIG_H + +TARGETLIBS = \ + $(SDK_LIB_PATH)\kernel32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\libibmad.lib \ + $(TARGETPATH)\*\libibumad.lib +!else + $(TARGETPATH)\*\libibmadd.lib \ + $(TARGETPATH)\*\libibumadd.lib +!endif + +MSC_WARNING_LEVEL = /W3 /WX /wd4007 \ No newline at end of file diff --git a/branches/WOF2-3/tools/infiniband-diags/src/ibsendtrap/ibsendtrap.rc b/branches/WOF2-3/tools/infiniband-diags/src/ibsendtrap/ibsendtrap.rc new file mode 100644 index 00000000..19e3e8f0 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/ibsendtrap/ibsendtrap.rc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef DBG +#define VER_FILEDESCRIPTION_STR "Send InfiniBand Traps (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "Send InfiniBand Traps" +#endif + +#define VER_INTERNALNAME_STR "ibsendtrap.exe" +#define VER_ORIGINALFILENAME_STR "ibsendtrap.exe" + +#include diff --git a/branches/WOF2-3/tools/infiniband-diags/src/ibsendtrap/makefile b/branches/WOF2-3/tools/infiniband-diags/src/ibsendtrap/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/ibsendtrap/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\..\inc\openib.def diff --git a/branches/WOF2-3/tools/infiniband-diags/src/ibstat.c b/branches/WOF2-3/tools/infiniband-diags/src/ibstat.c new file mode 100644 index 00000000..c44d8c4b --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/ibstat.c @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2004-2009 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#define _GNU_SOURCE + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +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", + ((unsigned)ca->node_type <= + IB_NODE_MAX ? node_type_str[ca->node_type] : "???"), + ca->ca_name); + printf("\t%s type: %s\n", + ((unsigned)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, + (unsigned)port->state <= + 4 ? port_state_str[port->state] : "???"); + printf("%sPhysical state: %s\n", pre, + (unsigned)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, ntohl(port->capmask)); + printf("%sPort GUID: 0x%016llx\n", pre, + (long long unsigned)ntohll(port->port_guid)); + printf("%sLink layer: %s\n", pre, port->link_layer); + 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)", + ((unsigned)ca.node_type <= + IB_NODE_MAX ? node_type_str[ca.node_type] : + "???"), ca_name, portnum, ca.numports); + return -1; + } + printf("%s: '%s'\n", + ((unsigned)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; +} + +static int list_only, short_format, list_ports; + +static int process_opt(void *context, int ch, char *optarg) +{ + switch (ch) { + case 'l': + list_only++; + break; + case 's': + short_format++; + break; + case 'p': + list_ports++; + break; + default: + return -1; + } + return 0; +} + +int main(int argc, char *argv[]) +{ + char names[UMAD_MAX_DEVICES][UMAD_CA_NAME_LEN]; + int dev_port = -1; + int n, i; + + const struct ibdiag_opt opts[] = { + {"list_of_cas", 'l', 0, NULL, "list all IB devices"}, + {"short", 's', 0, NULL, "short output"}, + {"port_list", 'p', 0, NULL, "show port list"}, + {0} + }; + char usage_args[] = " [portnum]"; + const char *usage_examples[] = { + "-l # list all IB devices", + "mthca0 2 # stat port 2 of 'mthca0'", + NULL + }; + + ibdiag_process_opts(argc, argv, NULL, "sDGLCPte", opts, process_opt, + usage_args, usage_examples); + + 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/branches/WOF2-3/tools/infiniband-diags/src/ibstat/SOURCES b/branches/WOF2-3/tools/infiniband-diags/src/ibstat/SOURCES new file mode 100644 index 00000000..e78103c9 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/ibstat/SOURCES @@ -0,0 +1,31 @@ +TARGETNAME = ibstat +TARGETPATH = ..\..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = PROGRAM + +UMTYPE = console +UMENTRY = main + +USE_MSVCRT = 1 + +SOURCES = ..\ibstat.c ..\ibdiag_common.c ..\ibdiag_windows.c ibstat.rc + +INCLUDES = ..\..\include;..\..\include\windows;\ + ..\..\..\..\ulp\libibmad\include;\ + ..\..\..\..\ulp\libibumad\include;\ + ..\..\..\..\inc;..\..\..\..\inc\user;\ + ..\..\..\..\inc\user\linux; + +C_DEFINES = $(C_DEFINES) /DHAVE_CONFIG_H + +TARGETLIBS = \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\libibmad.lib \ + $(TARGETPATH)\*\libibumad.lib +!else + $(TARGETPATH)\*\libibmadd.lib \ + $(TARGETPATH)\*\libibumadd.lib +!endif + +MSC_WARNING_LEVEL = /W3 /WX /wd4007 diff --git a/branches/WOF2-3/tools/infiniband-diags/src/ibstat/ibstat.rc b/branches/WOF2-3/tools/infiniband-diags/src/ibstat/ibstat.rc new file mode 100644 index 00000000..08dcd480 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/ibstat/ibstat.rc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef DBG +#define VER_FILEDESCRIPTION_STR "InfiniBand Fabric Stats (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "InfiniBand Fabric Stats" +#endif + +#define VER_INTERNALNAME_STR "ibstat.exe" +#define VER_ORIGINALFILENAME_STR "ibstat.exe" + +#include diff --git a/branches/WOF2-3/tools/infiniband-diags/src/ibstat/makefile b/branches/WOF2-3/tools/infiniband-diags/src/ibstat/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/ibstat/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\..\inc\openib.def diff --git a/branches/WOF2-3/tools/infiniband-diags/src/ibsysstat.c b/branches/WOF2-3/tools/infiniband-diags/src/ibsysstat.c new file mode 100644 index 00000000..f007aa3e --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/ibsysstat.c @@ -0,0 +1,370 @@ +/* + * Copyright (c) 2004-2009 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include + +#include +#include + +#include "ibdiag_common.h" + +#define MAX_CPUS 8 + +struct ibmad_port *srcport; + +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; + +static int server_respond(void *umad, int size) +{ + ib_rpc_t rpc = { 0 }; + ib_rmpp_hdr_t rmpp = { 0 }; + ib_portid_t rport; + uint8_t *mad = umad_get_mad(umad); + ib_mad_addr_t *mad_addr; + + 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; + if (!rport.qkey && rport.qp == 1) + rport.qkey = IB_DEFAULT_QP1_QKEY; + + rpc.mgtclass = mad_get_field(mad, 0, IB_MAD_MGMTCLASS_F); + rpc.method = IB_MAD_METHOD_GET | 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); + rpc.oui = mad_get_field(mad, 0, IB_VEND2_OUI_F); + rpc.trid = mad_get_field64(mad, 0, IB_MAD_TRID_F); + + if (size > IB_MAD_SIZE) + rmpp.flags = IB_RMPP_FLAG_ACTIVE; + + DEBUG("responding %d bytes to %s, attr 0x%x mod 0x%x qkey %x", + size, portid2str(&rport), rpc.attr.id, rpc.attr.mod, rport.qkey); + + if (mad_build_pkt(umad, &rpc, &rport, &rmpp, 0) < 0) + return -1; + + if (ibdebug > 1) + xdump(stderr, "mad respond pkt\n", mad, IB_MAD_SIZE); + + if (umad_send(mad_rpc_portid(srcport), + mad_rpc_class_agent(srcport, rpc.mgtclass), umad, size, + rpc.timeout, 0) < 0) { + DEBUG("send failed; %m"); + return -1; + } + + return 0; +} + +static int mk_reply(int attr, void *data, int sz) +{ + char *s = data; + int n, i, ret = 0; + + 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 - 1) { + ret = sz; + break; + } + s[n] = '.'; + s += n + 1; + sz -= n + 1; + ret += n + 1; + if (getdomainname(s, sz) < 0) + snprintf(s, sz, "?domainname?"); + if ((n = strlen(s)) == 0) + s[-1] = 0; /* no domain */ + else + ret += n; + break; + case IB_CPUINFO_ATTR: + s[0] = '\0'; + 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"); + ret = sz; + break; + } + sz -= n; + s += n; + ret += n; + } + ret++; + break; + default: + DEBUG("unknown attr %d", attr); + } + return ret; +} + +static uint8_t buf[2048]; + +static char *ibsystat_serv(void) +{ + void *umad; + void *mad; + int attr, mod, size; + + DEBUG("starting to serve..."); + + while ((umad = mad_receive_via(buf, -1, srcport))) { + if (umad_status(buf)) { + DEBUG("drop mad with status %x: %s", umad_status(buf), + strerror(umad_status(buf))); + continue; + } + + 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); + + size = + mk_reply(attr, (uint8_t *) mad + IB_VENDOR_RANGE2_DATA_OFFS, + sizeof(buf) - umad_size() - + IB_VENDOR_RANGE2_DATA_OFFS); + + if (server_respond(umad, IB_VENDOR_RANGE2_DATA_OFFS + size) < 0) + DEBUG("respond failed"); + } + + 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) +{ + ib_rpc_t rpc = { 0 }; + int fd, agent, timeout, len; + void *data = (uint8_t *) umad_get_mad(buf) + IB_VENDOR_RANGE2_DATA_OFFS; + + DEBUG("Sysstat ping.."); + + rpc.mgtclass = IB_VENDOR_OPENIB_SYSSTAT_CLASS; + rpc.method = IB_MAD_METHOD_GET; + rpc.attr.id = attr; + rpc.attr.mod = 0; + rpc.oui = IB_OPENIB_OUI; + rpc.timeout = 0; + rpc.datasz = IB_VENDOR_RANGE2_DATA_SIZE; + rpc.dataoffs = IB_VENDOR_RANGE2_DATA_OFFS; + + portid->qp = 1; + if (!portid->qkey) + portid->qkey = IB_DEFAULT_QP1_QKEY; + + if ((len = mad_build_pkt(buf, &rpc, portid, NULL, NULL)) < 0) + IBPANIC("cannot build packet."); + + fd = mad_rpc_portid(srcport); + agent = mad_rpc_class_agent(srcport, rpc.mgtclass); + timeout = ibd_timeout ? ibd_timeout : MAD_DEF_TIMEOUT_MS; + + if (umad_send(fd, agent, buf, len, timeout, 0) < 0) + IBPANIC("umad_send failed."); + + len = sizeof(buf) - umad_size(); + if (umad_recv(fd, buf, &len, timeout) < 0) + IBPANIC("umad_recv failed."); + + if (umad_status(buf)) + return strerror(umad_status(buf)); + + 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 int server = 0, oui = IB_OPENIB_OUI; + +static int process_opt(void *context, int ch, char *optarg) +{ + switch (ch) { + case 'o': + oui = strtoul(optarg, 0, 0); + break; + case 'S': + server++; + break; + default: + return -1; + } + return 0; +} + +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 }; + int attr = IB_PING_ATTR; + char *err; + + const struct ibdiag_opt opts[] = { + {"oui", 'o', 1, NULL, "use specified OUI number"}, + {"Server", 'S', 0, NULL, "start in server mode"}, + {0} + }; + char usage_args[] = " []"; + + ibdiag_process_opts(argc, argv, NULL, "D", opts, process_opt, + usage_args, NULL); + + argc -= optind; + argv += optind; + + if (!argc && !server) + ibdiag_show_usage(); + + if (argc > 1 && (attr = match_attr(argv[1])) < 0) + ibdiag_show_usage(); + + srcport = mad_rpc_open_port(ibd_ca, ibd_ca_port, mgmt_classes, 3); + if (!srcport) + IBERROR("Failed to open '%s' port '%d'", ibd_ca, ibd_ca_port); + + if (server) { + if (mad_register_server_via(sysstat_class, 1, 0, oui, srcport) < + 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_via(sysstat_class, 1, srcport) < 0) + IBERROR("can't register to sysstat class %d", sysstat_class); + + if (ib_resolve_portid_str_via(&portid, argv[0], ibd_dest_type, + ibd_sm_id, srcport) < 0) + IBERROR("can't resolve destination port %s", argv[0]); + + if ((err = ibsystat(&portid, attr))) + IBERROR("ibsystat to %s: %s", portid2str(&portid), err); + + mad_rpc_close_port(srcport); + exit(0); +} diff --git a/branches/WOF2-3/tools/infiniband-diags/src/ibsysstat/SOURCES b/branches/WOF2-3/tools/infiniband-diags/src/ibsysstat/SOURCES new file mode 100644 index 00000000..4fb54642 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/ibsysstat/SOURCES @@ -0,0 +1,31 @@ +TARGETNAME = ibsysstat +TARGETPATH = ..\..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = PROGRAM + +UMTYPE = console +UMENTRY = main + +USE_MSVCRT = 1 + +SOURCES = ..\ibsysstat.c ..\ibdiag_common.c ..\ibdiag_windows.c ibsysstat.rc + +INCLUDES = ..\..\include;..\..\include\windows;\ + ..\..\..\..\ulp\libibmad\include;\ + ..\..\..\..\ulp\libibumad\include;\ + ..\..\..\..\inc;..\..\..\..\inc\user;\ + ..\..\..\..\inc\user\linux; + +C_DEFINES = $(C_DEFINES) /DHAVE_CONFIG_H + +TARGETLIBS = \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\libibmad.lib \ + $(TARGETPATH)\*\libibumad.lib +!else + $(TARGETPATH)\*\libibmadd.lib \ + $(TARGETPATH)\*\libibumadd.lib +!endif + +MSC_WARNING_LEVEL = /W3 /WX /wd4007 \ No newline at end of file diff --git a/branches/WOF2-3/tools/infiniband-diags/src/ibsysstat/ibsysstat.rc b/branches/WOF2-3/tools/infiniband-diags/src/ibsysstat/ibsysstat.rc new file mode 100644 index 00000000..b1afa84f --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/ibsysstat/ibsysstat.rc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef DBG +#define VER_FILEDESCRIPTION_STR "InfiniBand SM Information (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "InfiniBand SM Information" +#endif + +#define VER_INTERNALNAME_STR "sminfo.exe" +#define VER_ORIGINALFILENAME_STR "sminfo.exe" + +#include diff --git a/branches/WOF2-3/tools/infiniband-diags/src/ibsysstat/makefile b/branches/WOF2-3/tools/infiniband-diags/src/ibsysstat/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/ibsysstat/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\..\inc\openib.def diff --git a/branches/WOF2-3/tools/infiniband-diags/src/ibtracert.c b/branches/WOF2-3/tools/infiniband-diags/src/ibtracert.c new file mode 100644 index 00000000..80694f2c --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/ibtracert.c @@ -0,0 +1,824 @@ +/* + * Copyright (c) 2004-2009 Voltaire Inc. All rights reserved. + * Copyright (c) 2009 HNR Consulting. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "ibdiag_common.h" + +struct ibmad_port *srcport; + +#define MAXHOPS 63 + +static char *node_type_str[] = { + "???", + "ca", + "switch", + "router", + "iwarp rnic" +}; + +static int timeout = 0; /* ms */ +static int force; +static FILE *f; + +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_via(ni, portid, IB_ATTR_NODE_INFO, 0, timeout, srcport)) + return -1; + + if (!smp_query_via(nd, portid, IB_ATTR_NODE_DESC, 0, timeout, srcport)) + return -1; + + for (s = nd, e = s + 64; s < e; s++) { + if (!*s) + break; + if (!isprint(*s)) + *s = ' '; + } + + if (!smp_query_via(pi, portid, IB_ATTR_PORT_INFO, 0, timeout, srcport)) + 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_via(si, portid, IB_ATTR_SWITCH_INFO, 0, timeout, + srcport)) + 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_via(fdb, portid, IB_ATTR_LINEARFORWTBL, lid / 64, + timeout, srcport)) + 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] = (uint8_t) 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 && !ibverbose) + 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_via(pi, portid, IB_ATTR_PORT_INFO, portnum, timeout, + srcport)) + 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(ibverbose, "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_via(si, portid, IB_ATTR_SWITCH_INFO, 0, timeout, + srcport)) + 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_via(mdb, portid, IB_ATTR_MULTICASTFORWTBL, + block | (set << 28), timeout, srcport)) + 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(ibverbose, "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(ibverbose, "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 int dumplevel = 2, multicast, mlid; + +static int process_opt(void *context, int ch, char *optarg) +{ + switch (ch) { + case 1: + node_name_map_file = strdup(optarg); + break; + case 'm': + multicast++; + mlid = strtoul(optarg, 0, 0); + break; + case 'f': + force++; + break; + case 'n': + dumplevel = 1; + break; + default: + return -1; + } + return 0; +} + +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 }; + Node *endnode; + + const struct ibdiag_opt opts[] = { + {"force", 'f', 0, NULL, "force"}, + {"no_info", 'n', 0, NULL, "simple format"}, + {"mlid", 'm', 1, "", "multicast trace of the mlid"}, + {"node-name-map", 1, 1, "", "node name map file"}, + {0} + }; + char usage_args[] = " "; + const char *usage_examples[] = { + "- Unicast examples:", + "4 16\t\t\t# show path between lids 4 and 16", + "-n 4 16\t\t# same, but using simple output format", + "-G 0x8f1040396522d 0x002c9000100d051\t# use guid addresses", + + " - Multicast examples:", + "-m 0xc000 4 16\t# show multicast path of mlid 0xc000 between lids 4 and 16", + NULL, + }; + + ibdiag_process_opts(argc, argv, NULL, NULL, opts, process_opt, + usage_args, usage_examples); + + f = stdout; + argc -= optind; + argv += optind; + + if (argc < 2) + ibdiag_show_usage(); + + if (ibd_timeout) + timeout = ibd_timeout; + + srcport = mad_rpc_open_port(ibd_ca, ibd_ca_port, mgmt_classes, 3); + if (!srcport) + IBERROR("Failed to open '%s' port '%d'", ibd_ca, ibd_ca_port); + + node_name_map = open_node_name_map(node_name_map_file); + + if (ib_resolve_portid_str_via(&src_portid, argv[0], ibd_dest_type, + ibd_sm_id, srcport) < 0) + IBERROR("can't resolve source port %s", argv[0]); + + if (ib_resolve_portid_str_via(&dest_portid, argv[1], ibd_dest_type, + ibd_sm_id, srcport) < 0) + IBERROR("can't resolve destination port %s", argv[1]); + + if (ibd_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"); + ibdiag_show_usage(); + } + + if (ibd_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); + + mad_rpc_close_port(srcport); + + exit(0); +} diff --git a/branches/WOF2-3/tools/infiniband-diags/src/ibtracert/SOURCES b/branches/WOF2-3/tools/infiniband-diags/src/ibtracert/SOURCES new file mode 100644 index 00000000..3f5b8065 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/ibtracert/SOURCES @@ -0,0 +1,33 @@ +TARGETNAME = ibtracert +TARGETPATH = ..\..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = PROGRAM + +UMTYPE = console +UMENTRY = main + +USE_MSVCRT = 1 + +SOURCES = ..\ibtracert.c ..\ibdiag_common.c ..\ibdiag_windows.c ibtracert.rc + +INCLUDES = ..\..\include;..\..\include\windows;\ + ..\..\..\..\ulp\libibmad\include;\ + ..\..\..\..\ulp\libibumad\include;\ + ..\..\..\..\inc;..\..\..\..\inc\user;\ + ..\..\..\..\inc\user\linux; + +C_DEFINES = $(C_DEFINES) /DHAVE_CONFIG_H + +TARGETLIBS = \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\complib.lib \ + $(TARGETPATH)\*\libibmad.lib \ + $(TARGETPATH)\*\libibumad.lib +!else + $(TARGETPATH)\*\complibd.lib \ + $(TARGETPATH)\*\libibmadd.lib \ + $(TARGETPATH)\*\libibumadd.lib +!endif + +MSC_WARNING_LEVEL = /W3 /WX /wd4007 \ No newline at end of file diff --git a/branches/WOF2-3/tools/infiniband-diags/src/ibtracert/ibtracert.rc b/branches/WOF2-3/tools/infiniband-diags/src/ibtracert/ibtracert.rc new file mode 100644 index 00000000..bca55815 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/ibtracert/ibtracert.rc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef DBG +#define VER_FILEDESCRIPTION_STR "Trace InfiniBand Path (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "Trace InfiniBand Path" +#endif + +#define VER_INTERNALNAME_STR "ibtracert.exe" +#define VER_ORIGINALFILENAME_STR "ibtracert.exe" + +#include diff --git a/branches/WOF2-3/tools/infiniband-diags/src/ibtracert/makefile b/branches/WOF2-3/tools/infiniband-diags/src/ibtracert/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/ibtracert/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\..\inc\openib.def diff --git a/branches/WOF2-3/tools/infiniband-diags/src/mcm_rereg_test.c b/branches/WOF2-3/tools/infiniband-diags/src/mcm_rereg_test.c new file mode 100644 index 00000000..a764d021 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/mcm_rereg_test.c @@ -0,0 +1,500 @@ +/* + * Copyright (c) 2006-2009 Voltaire, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include + +#include +#include + +#define info(fmt, ...) fprintf(stderr, "INFO: " fmt, ## __VA_ARGS__ ) +#define err(fmt, ...) fprintf(stderr, "ERR: " fmt, ## __VA_ARGS__ ) +#ifdef NOISY_DEBUG +#define dbg(fmt, ...) fprintf(stderr, "DBG: " fmt, ## __VA_ARGS__ ) +#else +#define dbg(fmt, ...) +#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 +}; + +struct ibmad_port *srcport; + +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; + unsigned i; + int 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; + unsigned 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; + unsigned i; + int 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(0xfe80000000000000ull); + uint64_t guid = htonll(0x0002c90200223825ull); + 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]; + + srcport = mad_rpc_open_port(NULL, 0, mgmt_classes, 2); + if (!srcport) + err("Failed to open port"); + +#if 1 + ib_resolve_smlid_via(&dport_id, TMO, srcport); +#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 = mad_rpc_portid(srcport); +#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/branches/WOF2-3/tools/infiniband-diags/src/mcm_rereg_test/SOURCES b/branches/WOF2-3/tools/infiniband-diags/src/mcm_rereg_test/SOURCES new file mode 100644 index 00000000..ac933ad2 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/mcm_rereg_test/SOURCES @@ -0,0 +1,30 @@ +TARGETNAME = mcm_rereg_test +TARGETPATH = ..\..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = PROGRAM + +UMTYPE = console +UMENTRY = main + +USE_MSVCRT = 1 + +SOURCES = ..\mcm_rereg_test.c ..\ibdiag_common.c ..\ibdiag_windows.c mcm_rereg_test.rc + +INCLUDES = ..\..\include;..\..\include\windows;\ + ..\..\..\..\ulp\libibmad\include;\ + ..\..\..\..\ulp\libibumad\include;\ + ..\..\..\..\inc;..\..\..\..\inc\user;\ + ..\..\..\..\inc\user\linux; + +C_DEFINES = $(C_DEFINES) /DHAVE_CONFIG_H + +TARGETLIBS = \ + $(SDK_LIB_PATH)\kernel32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\libibmad.lib \ + $(TARGETPATH)\*\libibumad.lib +!else + $(TARGETPATH)\*\libibmadd.lib \ + $(TARGETPATH)\*\libibumadd.lib +!endif + +MSC_WARNING_LEVEL = /W3 /WX /wd4007 \ No newline at end of file diff --git a/branches/WOF2-3/tools/infiniband-diags/src/mcm_rereg_test/makefile b/branches/WOF2-3/tools/infiniband-diags/src/mcm_rereg_test/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/mcm_rereg_test/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\..\inc\openib.def diff --git a/branches/WOF2-3/tools/infiniband-diags/src/mcm_rereg_test/mcm_rereg_test.rc b/branches/WOF2-3/tools/infiniband-diags/src/mcm_rereg_test/mcm_rereg_test.rc new file mode 100644 index 00000000..b10df8f6 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/mcm_rereg_test/mcm_rereg_test.rc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef DBG +#define VER_FILEDESCRIPTION_STR "InfiniBand Multicase Registration Test (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "InfiniBand Multicase Registration Test" +#endif + +#define VER_INTERNALNAME_STR "mcm_rereg_test.exe" +#define VER_ORIGINALFILENAME_STR "mcm_rereg_test.exe" + +#include diff --git a/branches/WOF2-3/tools/infiniband-diags/src/perfquery.c b/branches/WOF2-3/tools/infiniband-diags/src/perfquery.c new file mode 100644 index 00000000..07a92264 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/perfquery.c @@ -0,0 +1,620 @@ +/* + * Copyright (c) 2004-2009 Voltaire Inc. All rights reserved. + * Copyright (c) 2007 Xsigo Systems Inc. All rights reserved. + * Copyright (c) 2009 HNR Consulting. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include + +#include +#include + +#include "ibdiag_common.h" + +struct ibmad_port *srcport; + +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; + uint32_t xmtwait; +}; + +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 }; + +#define ALL_PORTS 0xFF + +/* 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); + mad_decode_field(pc, IB_PC_XMT_WAIT_F, &val); + aggregate_32bit(&perf_count.xmtwait, 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_encode_field(pc, IB_PC_XMT_WAIT_F, &perf_count.xmtwait); + + 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 extended 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 (!pma_query_via(pc, portid, port, timeout, + IB_GSI_PORT_COUNTERS, srcport)) + IBERROR("perfquery"); + if (!(cap_mask & 0x1000)) { + /* if PortCounters:PortXmitWait not supported clear this counter */ + VERBOSE("PortXmitWait not indicated" + " so ignore this counter"); + perf_count.xmtwait = 0; + mad_encode_field(pc, IB_PC_XMT_WAIT_F, + &perf_count.xmtwait); + } + if (aggregate) + aggregate_perfcounters(); + else + mad_dump_fields(buf, sizeof buf, pc, sizeof pc, + IB_PC_FIRST_F, + (cap_mask & 0x1000)?IB_PC_LAST_F:(IB_PC_RCV_PKTS_F+1)); + + } 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 (!pma_query_via(pc, portid, port, timeout, + IB_GSI_PORT_COUNTERS_EXT, srcport)) + IBERROR("perfextquery"); + if (aggregate) + aggregate_perfcounters_ext(); + else + mad_dump_perfcounters_ext(buf, sizeof buf, pc, + sizeof pc); + } + + if (!aggregate) { + if (extended) + printf("# Port extended counters: %s port %d\n%s", + portid2str(portid), port, buf); + else + 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 (!performance_reset_via(pc, portid, port, mask, timeout, + IB_GSI_PORT_COUNTERS, srcport)) + IBERROR("perf reset"); + } else { + if (!performance_reset_via(pc, portid, port, mask, timeout, + IB_GSI_PORT_COUNTERS_EXT, srcport)) + IBERROR("perf ext reset"); + } +} + +static int reset, reset_only, all_ports, loop_ports, port, extended, xmt_sl, + rcv_sl, xmt_disc, rcv_err, smpl_ctl; + +static void common_func(ib_portid_t * portid, int port_num, int mask, + unsigned query, unsigned reset, + const char *name, uint16_t attr, + void dump_func(char *, int, void *, int)) +{ + char buf[1024]; + + if (query) { + if (!pma_query_via(pc, portid, port_num, ibd_timeout, attr, + srcport)) + IBERROR("cannot query %s", name); + + dump_func(buf, sizeof(buf), pc, sizeof(pc)); + + printf("# %s counters: %s port %d\n%s", name, + portid2str(portid), port_num, buf); + } + + if (reset && !performance_reset_via(pc, portid, port, mask, ibd_timeout, + attr, srcport)) + IBERROR("cannot reset %s", name); +} + +static void xmt_sl_query(ib_portid_t * portid, int port, int mask) +{ + common_func(portid, port, mask, !reset_only, (reset_only || reset), + "PortXmitDataSL", IB_GSI_PORT_XMIT_DATA_SL, + mad_dump_perfcounters_xmt_sl); +} + +static void rcv_sl_query(ib_portid_t * portid, int port, int mask) +{ + common_func(portid, port, mask, !reset_only, (reset_only || reset), + "PortRcvDataSL", IB_GSI_PORT_RCV_DATA_SL, + mad_dump_perfcounters_rcv_sl); +} + +static void xmt_disc_query(ib_portid_t * portid, int port, int mask) +{ + common_func(portid, port, mask, !reset_only, (reset_only || reset), + "PortXmitDiscardDetails", IB_GSI_PORT_XMIT_DISCARD_DETAILS, + mad_dump_perfcounters_xmt_disc); +} + +static void rcv_err_query(ib_portid_t * portid, int port, int mask) +{ + common_func(portid, port, mask, !reset_only, (reset_only || reset), + "PortRcvErrorDetails", IB_GSI_PORT_RCV_ERROR_DETAILS, + mad_dump_perfcounters_rcv_err); +} + +void dump_portsamples_control(ib_portid_t * portid, int port) +{ + char buf[1024]; + + if (!pma_query_via(pc, portid, port, ibd_timeout, + IB_GSI_PORT_SAMPLES_CONTROL, srcport)) + IBERROR("sampctlquery"); + + mad_dump_portsamples_control(buf, sizeof buf, pc, sizeof pc); + printf("# PortSamplesControl: %s port %d\n%s", portid2str(portid), + port, buf); +} + +static int process_opt(void *context, int ch, char *optarg) +{ + switch (ch) { + case 'x': + extended = 1; + break; + case 'X': + xmt_sl = 1; + break; + case 'S': + rcv_sl = 1; + break; + case 'D': + xmt_disc = 1; + break; + case 'E': + rcv_err = 1; + break; + case 'c': + smpl_ctl = 1; + break; + case 'a': + all_ports++; + port = ALL_PORTS; + break; + case 'l': + loop_ports++; + break; + case 'r': + reset++; + break; + case 'R': + reset_only++; + break; + default: + return -1; + } + return 0; +} + +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 portid = { 0 }; + int mask = 0xffff; + uint16_t cap_mask; + int all_ports_loop = 0; + int node_type, num_ports = 0; + uint8_t data[IB_SMP_DATA_SIZE]; + int start_port = 1; + int enhancedport0; + int i; + + const struct ibdiag_opt opts[] = { + {"extended", 'x', 0, NULL, "show extended port counters"}, + {"xmtsl", 'X', 0, NULL, "show Xmt SL port counters"}, + {"rcvsl", 'S', 0, NULL, "show Rcv SL port counters"}, + {"xmtdisc", 'D', 0, NULL, "show Xmt Discard Details"}, + {"rcverr", 'E', 0, NULL, "show Rcv Error Details"}, + {"smplctl", 'c', 0, NULL, "show samples control"}, + {"all_ports", 'a', 0, NULL, "show aggregated counters"}, + {"loop_ports", 'l', 0, NULL, "iterate through each port"}, + {"reset_after_read", 'r', 0, NULL, "reset counters after read"}, + {"Reset_only", 'R', 0, NULL, "only reset counters"}, + {0} + }; + char usage_args[] = " [ [[port] [reset_mask]]]"; + const char *usage_examples[] = { + "\t\t# read local port's performance counters", + "32 1\t\t# read performance counters from lid 32, port 1", + "-x 32 1\t# read extended performance counters from lid 32, port 1", + "-a 32\t\t# read performance counters from lid 32, all ports", + "-r 32 1\t# read performance counters and reset", + "-x -r 32 1\t# read extended performance counters and reset", + "-R 0x20 1\t# reset performance counters of port 1 only", + "-x -R 0x20 1\t# reset extended performance counters of port 1 only", + "-R -a 32\t# reset performance counters of all ports", + "-R 32 2 0x0fff\t# reset only error counters of port 2", + "-R 32 2 0xf000\t# reset only non-error counters of port 2", + NULL, + }; + + ibdiag_process_opts(argc, argv, NULL, "D", opts, process_opt, + usage_args, usage_examples); + + argc -= optind; + argv += optind; + + if (argc > 1) + port = strtoul(argv[1], 0, 0); + if (argc > 2) + mask = strtoul(argv[2], 0, 0); + + srcport = mad_rpc_open_port(ibd_ca, ibd_ca_port, mgmt_classes, 4); + if (!srcport) + IBERROR("Failed to open '%s' port '%d'", ibd_ca, ibd_ca_port); + + if (argc) { + if (ib_resolve_portid_str_via(&portid, argv[0], ibd_dest_type, + ibd_sm_id, srcport) < 0) + IBERROR("can't resolve destination port %s", argv[0]); + } else { + if (ib_resolve_self_via(&portid, &port, 0, srcport) < 0) + IBERROR("can't resolve self port %s", argv[0]); + } + + /* PerfMgt ClassPortInfo is a required attribute */ + if (!pma_query_via(pc, &portid, port, ibd_timeout, CLASS_PORT_INFO, + srcport)) + 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 (xmt_sl) { + xmt_sl_query(&portid, port, mask); + goto done; + } + + if (rcv_sl) { + rcv_sl_query(&portid, port, mask); + goto done; + } + + if (xmt_disc) { + xmt_disc_query(&portid, port, mask); + goto done; + } + + if (rcv_err) { + rcv_err_query(&portid, port, mask); + goto done; + } + + if (smpl_ctl) { + dump_portsamples_control(&portid, port); + goto done; + } + + if (all_ports_loop || (loop_ports && (all_ports || port == ALL_PORTS))) { + if (smp_query_via(data, &portid, IB_ATTR_NODE_INFO, 0, 0, + srcport) < 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_via(data, &portid, IB_ATTR_SWITCH_INFO, + 0, 0, srcport) < 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, ibd_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, ibd_timeout, cap_mask, &portid, + port, 0); + + if (!reset) + goto done; + +do_reset: + if (argc <= 2 && !extended && (cap_mask & 0x1000)) + mask |= (1 << 16); /* reset portxmitwait */ + + if (all_ports_loop || (loop_ports && (all_ports || port == ALL_PORTS))) { + for (i = start_port; i <= num_ports; i++) + reset_counters(extended, ibd_timeout, mask, &portid, i); + } else + reset_counters(extended, ibd_timeout, mask, &portid, port); + +done: + mad_rpc_close_port(srcport); + exit(0); +} diff --git a/branches/WOF2-3/tools/infiniband-diags/src/perfquery/SOURCES b/branches/WOF2-3/tools/infiniband-diags/src/perfquery/SOURCES new file mode 100644 index 00000000..2467aedd --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/perfquery/SOURCES @@ -0,0 +1,31 @@ +TARGETNAME = perfquery +TARGETPATH = ..\..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = PROGRAM + +UMTYPE = console +UMENTRY = main + +USE_MSVCRT = 1 + +SOURCES = ..\perfquery.c ..\ibdiag_common.c ..\ibdiag_windows.c perfquery.rc + +INCLUDES = ..\..\include;..\..\include\windows;\ + ..\..\..\..\ulp\libibmad\include;\ + ..\..\..\..\ulp\libibumad\include;\ + ..\..\..\..\inc;..\..\..\..\inc\user;\ + ..\..\..\..\inc\user\linux; + +C_DEFINES = $(C_DEFINES) /DHAVE_CONFIG_H + +TARGETLIBS = \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\libibmad.lib \ + $(TARGETPATH)\*\libibumad.lib +!else + $(TARGETPATH)\*\libibmadd.lib \ + $(TARGETPATH)\*\libibumadd.lib +!endif + +MSC_WARNING_LEVEL = /W3 /WX /wd4007 diff --git a/branches/WOF2-3/tools/infiniband-diags/src/perfquery/makefile b/branches/WOF2-3/tools/infiniband-diags/src/perfquery/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/perfquery/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\..\inc\openib.def diff --git a/branches/WOF2-3/tools/infiniband-diags/src/perfquery/perfquery.rc b/branches/WOF2-3/tools/infiniband-diags/src/perfquery/perfquery.rc new file mode 100644 index 00000000..b555e062 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/perfquery/perfquery.rc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef DBG +#define VER_FILEDESCRIPTION_STR "InfiniBand Performance Stats Query (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "InfiniBand Performance Stats Query" +#endif + +#define VER_INTERNALNAME_STR "perfquery.exe" +#define VER_ORIGINALFILENAME_STR "perfquery.exe" + +#include diff --git a/branches/WOF2-3/tools/infiniband-diags/src/saquery.c b/branches/WOF2-3/tools/infiniband-diags/src/saquery.c new file mode 100644 index 00000000..5e9a5ad1 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/saquery.c @@ -0,0 +1,1827 @@ +/* + * Copyright (c) 2006,2007 The Regents of the University of California. + * Copyright (c) 2004-2009 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) 2009 HNR Consulting. All rights reserved. + * + * Produced at Lawrence Livermore National Laboratory. + * Written by Ira Weiny . + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include + +#define _GNU_SOURCE +#include + +#include +#include +#include +#include + +#include "ibdiag_common.h" + +struct bind_handle { + int fd, agent; + ib_portid_t dport; +}; + +struct query_res { + int status; + unsigned result_cnt; + void *p_result_madw; +}; + +typedef struct bind_handle *bind_handle_t; + +struct query_params { + ib_gid_t sgid, dgid, gid, mgid; + uint16_t slid, dlid, mlid; + uint32_t flow_label; + int hop_limit; + uint8_t tclass; + int reversible, numb_path; + uint16_t pkey; + int qos_class, sl; + uint8_t mtu, rate, pkt_life; + uint32_t qkey; + uint8_t scope; + uint8_t join_state; + int proxy_join; +}; + +struct query_cmd { + const char *name, *alias; + uint16_t query_type; + const char *usage; + int (*handler) (const struct query_cmd * q, bind_handle_t h, + struct query_params * p, int argc, char *argv[]); +}; + +static char *node_name_map_file = NULL; +static nn_map_t *node_name_map = NULL; +static uint64_t smkey = 1; + +/** + * Declare some globals because I don't want this to be too complex. + */ +#define MAX_PORTS (8) +#define DEFAULT_SA_TIMEOUT_MS (1000) +static struct query_res result; + +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; +uint16_t requested_lid = 0; +int requested_lid_flag = 0; +uint64_t requested_guid = 0; +int requested_guid_flag = 0; + +#define SA_ERR_UNKNOWN IB_SA_MAD_STATUS_PRIO_SUGGESTED + +const char *ib_sa_error_str[] = { + "SA_NO_ERROR", + "SA_ERR_NO_RESOURCES", + "SA_ERR_REQ_INVALID", + "SA_ERR_NO_RECORDS", + "SA_ERR_TOO_MANY_RECORDS", + "SA_ERR_REQ_INVALID_GID", + "SA_ERR_REQ_INSUFFICIENT_COMPONENTS", + "SA_ERR_REQ_DENIED", + "SA_ERR_STATUS_PRIO_SUGGESTED", + "SA_ERR_UNKNOWN" +}; + +static inline const char *ib_sa_err_str(IN uint8_t status) +{ + if (status > SA_ERR_UNKNOWN) + status = SA_ERR_UNKNOWN; + return (ib_sa_error_str[status]); +} + +static inline void report_err(int status) +{ + int st = status & 0xff; + char sm_err_str[64] = { 0 }; + char sa_err_str[64] = { 0 }; + + if (st) + sprintf(sm_err_str, " SM(%s)", ib_get_err_str(st)); + + st = status >> 8; + if (st) + sprintf(sa_err_str, " SA(%s)", ib_sa_err_str((uint8_t) st)); + + fprintf(stderr, "ERROR: Query result returned 0x%04x, %s%s\n", + status, sm_err_str, sa_err_str); +} + +static int sa_query(struct bind_handle *h, uint8_t method, + uint16_t attr, uint32_t mod, uint64_t comp_mask, + uint64_t sm_key, void *data) +{ + ib_rpc_t rpc; + void *umad, *mad; + int ret, offset, len = 256; + + memset(&rpc, 0, sizeof(rpc)); + rpc.mgtclass = IB_SA_CLASS; + rpc.method = method; + rpc.attr.id = attr; + rpc.attr.mod = mod; + rpc.mask = comp_mask; + rpc.datasz = IB_SA_DATA_SIZE; + rpc.dataoffs = IB_SA_DATA_OFFS; + + umad = calloc(1, len + umad_size()); + if (!umad) + IBPANIC("cannot alloc mem for umad: %s\n", strerror(errno)); + + mad_build_pkt(umad, &rpc, &h->dport, NULL, data); + + mad_set_field64(umad_get_mad(umad), 0, IB_SA_MKEY_F, sm_key); + + if (ibdebug > 1) + xdump(stdout, "SA Request:\n", umad_get_mad(umad), len); + + ret = umad_send(h->fd, h->agent, umad, len, ibd_timeout, 0); + if (ret < 0) + IBPANIC("umad_send failed: attr %u: %s\n", + attr, strerror(errno)); + +recv_mad: + ret = umad_recv(h->fd, umad, &len, ibd_timeout); + if (ret < 0) { + if (errno == ENOSPC) { + umad = realloc(umad, umad_size() + len); + goto recv_mad; + } + IBPANIC("umad_recv failed: attr 0x%x: %s\n", attr, + strerror(errno)); + } + + if ((ret = umad_status(umad))) + return ret; + + mad = umad_get_mad(umad); + + if (ibdebug > 1) + xdump(stdout, "SA Response:\n", mad, len); + + method = (uint8_t) mad_get_field(mad, 0, IB_MAD_METHOD_F); + offset = mad_get_field(mad, 0, IB_SA_ATTROFFS_F); + result.status = mad_get_field(mad, 0, IB_MAD_STATUS_F); + result.p_result_madw = mad; + if (result.status) + result.result_cnt = 0; + else if (method != IB_MAD_METHOD_GET_TABLE) + result.result_cnt = 1; + else if (!offset) + result.result_cnt = 0; + else + result.result_cnt = (len - IB_SA_DATA_OFFS) / (offset << 3); + + return 0; +} + +static void *get_query_rec(void *mad, unsigned i) +{ + int offset = mad_get_field(mad, 0, IB_SA_ATTROFFS_F); + return (uint8_t *) mad + IB_SA_DATA_OFFS + i * (offset << 3); +} + +static unsigned valid_gid(ib_gid_t * gid) +{ + ib_gid_t zero_gid; + memset(&zero_gid, 0, sizeof zero_gid); + return memcmp(&zero_gid, gid, sizeof(*gid)); +} + +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'; +} + +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 dump_node_record(void *data) +{ + ib_node_record_t *nr = data; + ib_node_info_t *ni = &nr->node_info; + + 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...............%u\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................%u\n" + "\t\tvendor_id...............0x%X\n" + "\t\tNodeDescription.........%s\n", + cl_ntoh16(nr->lid), cl_ntoh16(nr->resv), + ni->base_version, ni->class_version, + ib_get_node_type_str(ni->node_type), ni->num_ports, + cl_ntoh64(ni->sys_guid), cl_ntoh64(ni->node_guid), + cl_ntoh64(ni->port_guid), cl_ntoh16(ni->partition_cap), + cl_ntoh16(ni->device_id), cl_ntoh32(ni->revision), + ib_node_info_get_local_port_num(ni), + cl_ntoh32(ib_node_info_get_vendor_id(ni)), + clean_nodedesc((char *)nr->node_desc.description)); +} + +static void print_node_record(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; + char *name; + + 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; + } + + dump_node_record(node_record); +} + +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....................%u\n" + "\t\tslid....................%u\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%02X%02X%02X%02X%02X%02X\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, + p_pr->resv2[0], p_pr->resv2[1], p_pr->resv2[2], + p_pr->resv2[3], p_pr->resv2[4], p_pr->resv2[5]); +} + +static void dump_class_port_info(void *data) +{ + char gid_str[INET6_ADDRSTRLEN]; + char gid_str2[INET6_ADDRSTRLEN]; + ib_class_port_info_t *cpi = 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.............%u\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.................%u\n" + "\t\tTrap PKey................0x%04X\n" + "\t\tTrap HL/QP...............0x%08X\n" + "\t\tTrap QKey................0x%08X\n", + cpi->base_ver, cpi->class_ver, cl_ntoh16(cpi->cap_mask), + ib_class_cap_mask2(cpi), ib_class_resp_time_val(cpi), + inet_ntop(AF_INET6, &(cpi->redir_gid), gid_str, sizeof gid_str), + cl_ntoh32(cpi->redir_tc_sl_fl), cl_ntoh16(cpi->redir_lid), + cl_ntoh16(cpi->redir_pkey), cl_ntoh32(cpi->redir_qp), + cl_ntoh32(cpi->redir_qkey), + inet_ntop(AF_INET6, &(cpi->trap_gid), gid_str2, sizeof gid_str2), + cl_ntoh32(cpi->trap_tc_sl_fl), cl_ntoh16(cpi->trap_lid), + cl_ntoh16(cpi->trap_pkey), cl_ntoh32(cpi->trap_hop_qp), + cl_ntoh32(cpi->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..............%u\n" + "\t\tPortNum.................%u\n" + "\t\tbase_lid................%u\n" + "\t\tmaster_sm_base_lid......%u\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.................%u\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_one_mcmember_record(void *data) +{ + char mgid[INET6_ADDRSTRLEN], gid[INET6_ADDRSTRLEN]; + ib_member_rec_t *mr = data; + uint32_t flow; + uint8_t sl, hop, scope, join; + ib_member_get_sl_flow_hop(mr->sl_flow_hop, &sl, &flow, &hop); + ib_member_get_scope_state(mr->scope_state, &scope, &join); + printf("MCMember Record dump:\n" + "\t\tMGID....................%s\n" + "\t\tPortGid.................%s\n" + "\t\tqkey....................0x%x\n" + "\t\tmlid....................0x%x\n" + "\t\tmtu.....................0x%x\n" + "\t\tTClass..................0x%x\n" + "\t\tpkey....................0x%x\n" + "\t\trate....................0x%x\n" + "\t\tpkt_life................0x%x\n" + "\t\tSL......................0x%x\n" + "\t\tFlowLabel...............0x%x\n" + "\t\tHopLimit................0x%x\n" + "\t\tScope...................0x%x\n" + "\t\tJoinState...............0x%x\n" + "\t\tProxyJoin...............0x%x\n", + inet_ntop(AF_INET6, mr->mgid.raw, mgid, sizeof(mgid)), + inet_ntop(AF_INET6, mr->port_gid.raw, gid, sizeof(gid)), + cl_ntoh32(mr->qkey), cl_ntoh16(mr->mlid), mr->mtu, mr->tclass, + cl_ntoh16(mr->pkey), mr->rate, mr->pkt_life, sl, + cl_ntoh32(flow), hop, scope, join, mr->proxy_join); +} + +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); + unsigned i = 0; + char *node_name = ""; + + /* go through the node records searching for a port guid which matches + * this port gid interface id. + * This gives us a node name to print, if available. + */ + for (i = 0; i < result.result_cnt; i++) { + ib_node_record_t *nr = get_query_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[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, sizeof gid), + 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.........%u\n" + "\t\tlid_range_end...........%u\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.........%u\n" + "\t\tlid_range_end...........%u\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|\n" + "\t\tWeight:%2u|%2u|%2u|%2u|%2u|%2u|%2u|%2u|" + "%2u|%2u|%2u|%2u|%2u|%2u|%2u|%2u|\n", + 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, + 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); +} + +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(struct query_res *r, void (*dump_func) (void *)) +{ + unsigned i; + for (i = 0; i < r->result_cnt; i++) { + void *data = get_query_rec(r->p_result_madw, i); + dump_func(data); + } +} + +static void return_mad(void) +{ + if (result.p_result_madw) { + free((uint8_t *) result.p_result_madw - umad_size()); + result.p_result_madw = NULL; + } +} + +/** + * Get any record(s) + */ +static int get_any_records(bind_handle_t h, + uint16_t attr_id, uint32_t attr_mod, + ib_net64_t comp_mask, void *attr, uint64_t sm_key) +{ + int ret = sa_query(h, IB_MAD_METHOD_GET_TABLE, attr_id, attr_mod, + cl_ntoh64(comp_mask), sm_key, attr); + if (ret) { + fprintf(stderr, "Query SA failed: %s\n", ib_get_err_str(ret)); + return ret; + } + + if (result.status != IB_SUCCESS) { + report_err(result.status); + return result.status; + } + + return ret; +} + +static int get_and_dump_any_records(bind_handle_t h, uint16_t attr_id, + uint32_t attr_mod, ib_net64_t comp_mask, + void *attr, uint64_t sm_key, + void (*dump_func) (void *)) +{ + int ret = get_any_records(h, attr_id, attr_mod, comp_mask, attr, + sm_key); + if (ret) + return ret; + + dump_results(&result, dump_func); + + return 0; +} + +/** + * Get all the records available for requested query type. + */ +static int get_all_records(bind_handle_t h, uint16_t attr_id, int trusted) +{ + return get_any_records(h, attr_id, 0, 0, NULL, trusted ? smkey : 0); +} + +static int get_and_dump_all_records(bind_handle_t h, uint16_t attr_id, + int trusted, void (*dump_func) (void *)) +{ + int ret = get_all_records(h, attr_id, 0); + if (ret) + return ret; + + dump_results(&result, dump_func); + return_mad(); + return ret; +} + +/** + * return the lid from the node descriptor (name) supplied + */ +static int get_lid_from_name(bind_handle_t h, const char *name, uint16_t * lid) +{ + ib_node_record_t *node_record = NULL; + ib_node_info_t *p_ni = NULL; + unsigned i; + int ret; + + ret = get_all_records(h, IB_SA_ATTR_NODERECORD, 0); + if (ret) + return ret; + + for (i = 0; i < result.result_cnt; i++) { + node_record = get_query_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 0; +} + +static uint16_t get_lid(bind_handle_t h, const char *name) +{ + uint16_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 = (uint16_t) 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(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; +} + +#define cl_hton8(x) (x) +#define CHECK_AND_SET_VAL(val, size, comp_with, target, name, mask) \ + if ((int##size##_t) val != (int##size##_t) comp_with) { \ + target = cl_hton##size((uint##size##_t) val); \ + comp_mask |= IB_##name##_COMPMASK_##mask; \ + } + +#define CHECK_AND_SET_GID(val, target, name, mask) \ + if (valid_gid(&(val))) { \ + memcpy(&(target), &(val), sizeof(val)); \ + comp_mask |= IB_##name##_COMPMASK_##mask; \ + } + +#define CHECK_AND_SET_VAL_AND_SEL(val, target, name, mask, sel) \ + if (val) { \ + target = val; \ + comp_mask |= IB_##name##_COMPMASK_##mask##sel; \ + comp_mask |= IB_##name##_COMPMASK_##mask; \ + } + +/* + * Get the portinfo records available with IsSM or IsSMdisabled CapabilityMask bit on. + */ +static int get_issm_records(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_SA_ATTR_PORTINFORECORD, 1 << 31, + IB_PIR_COMPMASK_CAPMASK, &attr, 0); +} + +static int print_node_records(bind_handle_t h) +{ + unsigned i; + int ret; + + ret = get_all_records(h, IB_SA_ATTR_NODERECORD, 0); + if (ret) + return ret; + + if (node_print_desc == ALL_DESC) { + printf(" LID \"name\"\n"); + printf("================\n"); + } + for (i = 0; i < result.result_cnt; i++) { + ib_node_record_t *node_record; + node_record = get_query_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 ret; +} + +static int get_print_class_port_info(bind_handle_t h) +{ + int ret = sa_query(h, IB_MAD_METHOD_GET, CLASS_PORT_INFO, 0, 0, + 0, NULL); + if (ret) { + fprintf(stderr, "ERROR: Query SA failed: %s\n", + ib_get_err_str(ret)); + return ret; + } + if (result.status != IB_SUCCESS) { + report_err(result.status); + return (result.status); + } + dump_results(&result, dump_class_port_info); + return_mad(); + return ret; +} + +static int query_path_records(const struct query_cmd *q, bind_handle_t h, + struct query_params *p, int argc, char *argv[]) +{ + ib_path_rec_t pr; + ib_net64_t comp_mask = 0; + uint32_t flow = 0; + uint16_t qos_class = 0; + uint8_t reversible = 0; + + memset(&pr, 0, sizeof(pr)); + CHECK_AND_SET_GID(p->sgid, pr.sgid, PR, SGID); + CHECK_AND_SET_GID(p->dgid, pr.dgid, PR, DGID); + CHECK_AND_SET_VAL(p->slid, 16, 0, pr.slid, PR, SLID); + CHECK_AND_SET_VAL(p->dlid, 16, 0, pr.dlid, PR, DLID); + CHECK_AND_SET_VAL(p->hop_limit, 32, -1, pr.hop_flow_raw, PR, HOPLIMIT); + CHECK_AND_SET_VAL(p->flow_label, 8, 0, flow, PR, FLOWLABEL); + pr.hop_flow_raw |= cl_hton32(flow << 8); + CHECK_AND_SET_VAL(p->tclass, 8, 0, pr.tclass, PR, TCLASS); + CHECK_AND_SET_VAL(p->reversible, 8, -1, reversible, PR, REVERSIBLE); + CHECK_AND_SET_VAL(p->numb_path, 8, -1, pr.num_path, PR, NUMBPATH); + pr.num_path |= reversible << 7; + CHECK_AND_SET_VAL(p->pkey, 16, 0, pr.pkey, PR, PKEY); + CHECK_AND_SET_VAL(p->sl, 16, -1, pr.qos_class_sl, PR, SL); + CHECK_AND_SET_VAL(p->qos_class, 16, -1, qos_class, PR, QOS_CLASS); + ib_path_rec_set_qos_class(&pr, qos_class); + CHECK_AND_SET_VAL_AND_SEL(p->mtu, pr.mtu, PR, MTU, SELEC); + CHECK_AND_SET_VAL_AND_SEL(p->rate, pr.rate, PR, RATE, SELEC); + CHECK_AND_SET_VAL_AND_SEL(p->pkt_life, pr.pkt_life, PR, PKTLIFETIME, + SELEC); + + return get_and_dump_any_records(h, IB_SA_ATTR_PATHRECORD, 0, comp_mask, + &pr, 0, dump_path_record); +} + +static ib_api_status_t print_issm_records(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 int print_multicast_member_records(bind_handle_t h) +{ + struct query_res mc_group_result; + int ret; + + ret = get_all_records(h, IB_SA_ATTR_MCRECORD, 1); + if (ret) + return ret; + + mc_group_result = result; + + ret = get_all_records(h, IB_SA_ATTR_NODERECORD, 0); + if (ret) + goto return_mc; + + dump_results(&mc_group_result, dump_multicast_member_record); + return_mad(); + +return_mc: + if (mc_group_result.p_result_madw) + free((uint8_t *) mc_group_result.p_result_madw - umad_size()); + + return ret; +} + +static int print_multicast_group_records(bind_handle_t h) +{ + return get_and_dump_all_records(h, IB_SA_ATTR_MCRECORD, 0, + dump_multicast_group_record); +} + +static int query_class_port_info(const struct query_cmd *q, bind_handle_t h, + struct query_params *p, int argc, char *argv[]) +{ + return get_print_class_port_info(h); +} + +static int query_node_records(const struct query_cmd *q, bind_handle_t h, + struct query_params *p, int argc, char *argv[]) +{ + ib_node_record_t nr; + ib_net64_t comp_mask = 0; + int lid = 0; + + if (argc > 0) + parse_lid_and_ports(h, argv[0], &lid, NULL, NULL); + + memset(&nr, 0, sizeof(nr)); + CHECK_AND_SET_VAL(lid, 16, 0, nr.lid, NR, LID); + + return get_and_dump_any_records(h, IB_SA_ATTR_NODERECORD, 0, comp_mask, + &nr, 0, dump_node_record); +} + +static int query_portinfo_records(const struct query_cmd *q, + bind_handle_t h, struct query_params *p, + int argc, char *argv[]) +{ + ib_portinfo_record_t pir; + ib_net64_t comp_mask = 0; + int lid = 0, port = -1; + + if (argc > 0) + parse_lid_and_ports(h, argv[0], &lid, &port, NULL); + + memset(&pir, 0, sizeof(pir)); + CHECK_AND_SET_VAL(lid, 16, 0, pir.lid, PIR, LID); + CHECK_AND_SET_VAL(port, 8, -1, pir.port_num, PIR, PORTNUM); + + return get_and_dump_any_records(h, IB_SA_ATTR_PORTINFORECORD, 0, + comp_mask, &pir, 0, + dump_one_portinfo_record); +} + +static int query_mcmember_records(const struct query_cmd *q, + bind_handle_t h, struct query_params *p, + int argc, char *argv[]) +{ + ib_member_rec_t mr; + ib_net64_t comp_mask = 0; + uint32_t flow = 0; + uint8_t sl = 0, hop = 0, scope = 0; + + memset(&mr, 0, sizeof(mr)); + CHECK_AND_SET_GID(p->mgid, mr.mgid, MCR, MGID); + CHECK_AND_SET_GID(p->gid, mr.port_gid, MCR, PORT_GID); + CHECK_AND_SET_VAL(p->mlid, 16, 0, mr.mlid, MCR, MLID); + CHECK_AND_SET_VAL(p->qkey, 32, 0, mr.qkey, MCR, QKEY); + CHECK_AND_SET_VAL_AND_SEL(p->mtu, mr.mtu, MCR, MTU, _SEL); + CHECK_AND_SET_VAL_AND_SEL(p->rate, mr.rate, MCR, RATE, _SEL); + CHECK_AND_SET_VAL_AND_SEL(p->pkt_life, mr.pkt_life, MCR, LIFE, _SEL); + CHECK_AND_SET_VAL(p->tclass, 8, 0, mr.tclass, MCR, TCLASS); + CHECK_AND_SET_VAL(p->pkey, 16, 0, mr.pkey, MCR, PKEY); + CHECK_AND_SET_VAL(p->sl, 8, -1, sl, MCR, SL); + CHECK_AND_SET_VAL(p->flow_label, 8, 0, flow, MCR, FLOW); + CHECK_AND_SET_VAL(p->hop_limit, 8, -1, hop, MCR, HOP); + mr.sl_flow_hop = ib_member_set_sl_flow_hop(sl, flow, hop); + CHECK_AND_SET_VAL(p->scope, 8, 0, scope, MCR, SCOPE); + CHECK_AND_SET_VAL(p->join_state, 8, 0, mr.scope_state, MCR, JOIN_STATE); + mr.scope_state |= scope << 4; + CHECK_AND_SET_VAL(p->proxy_join, 8, -1, mr.proxy_join, MCR, PROXY); + + return get_and_dump_any_records(h, IB_SA_ATTR_MCRECORD, 0, comp_mask, + &mr, smkey, dump_one_mcmember_record); +} + +static int query_service_records(const struct query_cmd *q, bind_handle_t h, + struct query_params *p, int argc, char *argv[]) +{ + return get_and_dump_all_records(h, IB_SA_ATTR_SERVICERECORD, 0, + dump_service_record); +} + +static int query_informinfo_records(const struct query_cmd *q, + bind_handle_t h, struct query_params *p, + int argc, char *argv[]) +{ + return get_and_dump_all_records(h, IB_SA_ATTR_INFORMINFORECORD, 0, + dump_inform_info_record); +} + +static int query_link_records(const struct query_cmd *q, bind_handle_t h, + struct query_params *p, 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; + + 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)); + CHECK_AND_SET_VAL(from_lid, 16, 0, lr.from_lid, LR, FROM_LID); + CHECK_AND_SET_VAL(from_port, 8, -1, lr.from_port_num, LR, FROM_PORT); + CHECK_AND_SET_VAL(to_lid, 16, 0, lr.to_lid, LR, TO_LID); + CHECK_AND_SET_VAL(to_port, 8, -1, lr.to_port_num, LR, TO_PORT); + + return get_and_dump_any_records(h, IB_SA_ATTR_LINKRECORD, 0, comp_mask, + &lr, 0, dump_one_link_record); +} + +static int query_sl2vl_records(const struct query_cmd *q, bind_handle_t h, + struct query_params *p, 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; + + if (argc > 0) + parse_lid_and_ports(h, argv[0], &lid, &in_port, &out_port); + + memset(&slvl, 0, sizeof(slvl)); + CHECK_AND_SET_VAL(lid, 16, 0, slvl.lid, SLVL, LID); + CHECK_AND_SET_VAL(in_port, 8, -1, slvl.in_port_num, SLVL, IN_PORT); + CHECK_AND_SET_VAL(out_port, 8, -1, slvl.out_port_num, SLVL, OUT_PORT); + + return get_and_dump_any_records(h, IB_SA_ATTR_SL2VLTABLERECORD, 0, + comp_mask, &slvl, 0, + dump_one_slvl_record); +} + +static int query_vlarb_records(const struct query_cmd *q, bind_handle_t h, + struct query_params *p, int argc, char *argv[]) +{ + ib_vl_arb_table_record_t vlarb; + ib_net64_t comp_mask = 0; + int lid = 0, port = -1, block = -1; + + if (argc > 0) + parse_lid_and_ports(h, argv[0], &lid, &port, &block); + + memset(&vlarb, 0, sizeof(vlarb)); + CHECK_AND_SET_VAL(lid, 16, 0, vlarb.lid, VLA, LID); + CHECK_AND_SET_VAL(port, 8, -1, vlarb.port_num, VLA, OUT_PORT); + CHECK_AND_SET_VAL(block, 8, -1, vlarb.block_num, VLA, BLOCK); + + return get_and_dump_any_records(h, IB_SA_ATTR_VLARBTABLERECORD, 0, + comp_mask, &vlarb, 0, + dump_one_vlarb_record); +} + +static int query_pkey_tbl_records(const struct query_cmd *q, + bind_handle_t h, struct query_params *p, + int argc, char *argv[]) +{ + ib_pkey_table_record_t pktr; + ib_net64_t comp_mask = 0; + int lid = 0, port = -1, block = -1; + + if (argc > 0) + parse_lid_and_ports(h, argv[0], &lid, &port, &block); + + memset(&pktr, 0, sizeof(pktr)); + CHECK_AND_SET_VAL(lid, 16, 0, pktr.lid, PKEY, LID); + CHECK_AND_SET_VAL(port, 8, -1, pktr.port_num, PKEY, PORT); + CHECK_AND_SET_VAL(block, 16, -1, pktr.block_num, PKEY, BLOCK); + + return get_and_dump_any_records(h, IB_SA_ATTR_PKEYTABLERECORD, 0, + comp_mask, &pktr, smkey, + dump_one_pkey_tbl_record); +} + +static int query_lft_records(const struct query_cmd *q, bind_handle_t h, + struct query_params *p, int argc, char *argv[]) +{ + ib_lft_record_t lftr; + ib_net64_t comp_mask = 0; + int lid = 0, block = -1; + + if (argc > 0) + parse_lid_and_ports(h, argv[0], &lid, &block, NULL); + + memset(&lftr, 0, sizeof(lftr)); + CHECK_AND_SET_VAL(lid, 16, 0, lftr.lid, LFTR, LID); + CHECK_AND_SET_VAL(block, 16, -1, lftr.block_num, LFTR, BLOCK); + + return get_and_dump_any_records(h, IB_SA_ATTR_LFTRECORD, 0, comp_mask, + &lftr, 0, dump_one_lft_record); +} + +static int query_mft_records(const struct query_cmd *q, bind_handle_t h, + struct query_params *p, int argc, char *argv[]) +{ + ib_mft_record_t mftr; + ib_net64_t comp_mask = 0; + int lid = 0, block = -1, position = -1; + uint16_t pos = 0; + + if (argc > 0) + parse_lid_and_ports(h, argv[0], &lid, &position, &block); + + memset(&mftr, 0, sizeof(mftr)); + CHECK_AND_SET_VAL(lid, 16, 0, mftr.lid, MFTR, LID); + CHECK_AND_SET_VAL(block, 16, -1, mftr.position_block_num, MFTR, BLOCK); + mftr.position_block_num &= cl_hton16(IB_MCAST_BLOCK_ID_MASK_HO); + CHECK_AND_SET_VAL(position, 8, -1, pos, MFTR, POSITION); + mftr.position_block_num |= cl_hton16(pos << 12); + + return get_and_dump_any_records(h, IB_SA_ATTR_MFTRECORD, 0, comp_mask, + &mftr, 0, dump_one_mft_record); +} + +static bind_handle_t get_bind_handle(void) +{ + static struct ibmad_port *srcport; + static struct bind_handle handle; + int mgmt_classes[2] = { IB_SMI_CLASS, IB_SMI_DIRECT_CLASS }; + + srcport = mad_rpc_open_port(ibd_ca, ibd_ca_port, mgmt_classes, 2); + if (!srcport) + IBERROR("Failed to open '%s' port '%d'", ibd_ca, ibd_ca_port); + + ib_resolve_smlid_via(&handle.dport, ibd_timeout, srcport); + if (!handle.dport.lid) + IBPANIC("No SM found."); + + handle.dport.qp = 1; + if (!handle.dport.qkey) + handle.dport.qkey = IB_DEFAULT_QP1_QKEY; + + handle.fd = mad_rpc_portid(srcport); + handle.agent = umad_register(handle.fd, IB_SA_CLASS, 2, 1, NULL); + + return &handle; +} + +static void clean_up(struct bind_handle *h) +{ + umad_unregister(h->fd, h->agent); + umad_close_port(h->fd); + umad_done(); +} + +static const struct query_cmd query_cmds[] = { + {"ClassPortInfo", "CPI", CLASS_PORT_INFO, + NULL, query_class_port_info}, + {"NodeRecord", "NR", IB_SA_ATTR_NODERECORD, + "[lid]", query_node_records}, + {"PortInfoRecord", "PIR", IB_SA_ATTR_PORTINFORECORD, + "[[lid]/[port]]", query_portinfo_records}, + {"SL2VLTableRecord", "SL2VL", IB_SA_ATTR_SL2VLTABLERECORD, + "[[lid]/[in_port]/[out_port]]", query_sl2vl_records}, + {"PKeyTableRecord", "PKTR", IB_SA_ATTR_PKEYTABLERECORD, + "[[lid]/[port]/[block]]", query_pkey_tbl_records}, + {"VLArbitrationTableRecord", "VLAR", IB_SA_ATTR_VLARBTABLERECORD, + "[[lid]/[port]/[block]]", query_vlarb_records}, + {"InformInfoRecord", "IIR", IB_SA_ATTR_INFORMINFORECORD, + NULL, query_informinfo_records}, + {"LinkRecord", "LR", IB_SA_ATTR_LINKRECORD, + "[[from_lid]/[from_port]] [[to_lid]/[to_port]]", query_link_records}, + {"ServiceRecord", "SR", IB_SA_ATTR_SERVICERECORD, + NULL, query_service_records}, + {"PathRecord", "PR", IB_SA_ATTR_PATHRECORD, + NULL, query_path_records}, + {"MCMemberRecord", "MCMR", IB_SA_ATTR_MCRECORD, + NULL, query_mcmember_records}, + {"LFTRecord", "LFTR", IB_SA_ATTR_LFTRECORD, + "[[lid]/[block]]", query_lft_records}, + {"MFTRecord", "MFTR", IB_SA_ATTR_MFTRECORD, + "[[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(uint16_t type) +{ + const struct query_cmd *q; + + for (q = query_cmds; q->name; q++) + if (q->query_type == type) + return q; + + return NULL; +} + +enum saquery_command { + SAQUERY_CMD_QUERY, + SAQUERY_CMD_NODE_RECORD, + SAQUERY_CMD_CLASS_PORT_INFO, + SAQUERY_CMD_ISSM, + SAQUERY_CMD_MCGROUPS, + SAQUERY_CMD_MCMEMBERS, +}; + +static enum saquery_command command = SAQUERY_CMD_QUERY; +static uint16_t query_type; +static char *src_lid, *dst_lid; + +static int process_opt(void *context, int ch, char *optarg) +{ + struct query_params *p = context; + + switch (ch) { + case 1: + { + src_lid = strdup(optarg); + dst_lid = strchr(src_lid, ':'); + if (!dst_lid) + ibdiag_show_usage(); + *dst_lid++ = '\0'; + } + p->numb_path = 0x7f; + query_type = IB_SA_ATTR_PATHRECORD; + break; + case 2: + { + char *src_addr = strdup(optarg); + char *dst_addr = strchr(src_addr, '-'); + if (!dst_addr) + ibdiag_show_usage(); + *dst_addr++ = '\0'; + if (inet_pton(AF_INET6, src_addr, &p->sgid) <= 0) + ibdiag_show_usage(); + if (inet_pton(AF_INET6, dst_addr, &p->dgid) <= 0) + ibdiag_show_usage(); + free(src_addr); + } + p->numb_path = 0x7f; + query_type = IB_SA_ATTR_PATHRECORD; + 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"); + ibdiag_show_usage(); + } + smkey = strtoull(optarg, NULL, 0); + break; + case 'p': + query_type = IB_SA_ATTR_PATHRECORD; + break; + case 'D': + node_print_desc = ALL_DESC; + break; + case 'c': + command = SAQUERY_CMD_CLASS_PORT_INFO; + break; + case 'S': + query_type = IB_SA_ATTR_SERVICERECORD; + break; + case 'I': + query_type = IB_SA_ATTR_INFORMINFORECORD; + break; + case 'N': + command = SAQUERY_CMD_NODE_RECORD; + break; + case 'L': + node_print_desc = LID_ONLY; + command = SAQUERY_CMD_NODE_RECORD; + break; + case 'l': + node_print_desc = UNIQUE_LID_ONLY; + command = SAQUERY_CMD_NODE_RECORD; + break; + case 'G': + node_print_desc = GUID_ONLY; + command = SAQUERY_CMD_NODE_RECORD; + break; + case 'O': + node_print_desc = NAME_OF_LID; + command = SAQUERY_CMD_NODE_RECORD; + break; + case 'U': + node_print_desc = NAME_OF_GUID; + command = SAQUERY_CMD_NODE_RECORD; + 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_SA_ATTR_LINKRECORD; + break; + case 5: + p->slid = (uint16_t) strtoul(optarg, NULL, 0); + break; + case 6: + p->dlid = (uint16_t) strtoul(optarg, NULL, 0); + break; + case 7: + p->mlid = (uint16_t) strtoul(optarg, NULL, 0); + break; + case 14: + if (inet_pton(AF_INET6, optarg, &p->sgid) <= 0) + ibdiag_show_usage(); + break; + case 15: + if (inet_pton(AF_INET6, optarg, &p->dgid) <= 0) + ibdiag_show_usage(); + break; + case 16: + if (inet_pton(AF_INET6, optarg, &p->gid) <= 0) + ibdiag_show_usage(); + break; + case 17: + if (inet_pton(AF_INET6, optarg, &p->mgid) <= 0) + ibdiag_show_usage(); + break; + case 'r': + p->reversible = strtoul(optarg, NULL, 0); + break; + case 'n': + p->numb_path = strtoul(optarg, NULL, 0); + break; + case 18: + if (!isxdigit(*optarg) && !(optarg = getpass("P_Key: "))) { + fprintf(stderr, "cannot get P_Key\n"); + ibdiag_show_usage(); + } + p->pkey = (uint16_t) strtoul(optarg, NULL, 0); + break; + case 'Q': + p->qos_class = strtoul(optarg, NULL, 0); + break; + case 19: + p->sl = strtoul(optarg, NULL, 0); + break; + case 'M': + p->mtu = (uint8_t) strtoul(optarg, NULL, 0); + break; + case 'R': + p->rate = (uint8_t) strtoul(optarg, NULL, 0); + break; + case 20: + p->pkt_life = (uint8_t) strtoul(optarg, NULL, 0); + break; + case 'q': + if (!isxdigit(*optarg) && !(optarg = getpass("Q_Key: "))) { + fprintf(stderr, "cannot get Q_Key\n"); + ibdiag_show_usage(); + } + p->qkey = strtoul(optarg, NULL, 0); + break; + case 'T': + p->tclass = (uint8_t) strtoul(optarg, NULL, 0); + break; + case 'F': + p->flow_label = strtoul(optarg, NULL, 0); + break; + case 'H': + p->hop_limit = strtoul(optarg, NULL, 0); + break; + case 21: + p->scope = (uint8_t) strtoul(optarg, NULL, 0); + break; + case 'J': + p->join_state = (uint8_t) strtoul(optarg, NULL, 0); + break; + case 'X': + p->proxy_join = strtoul(optarg, NULL, 0); + break; + default: + return -1; + } + return 0; +} + +int main(int argc, char **argv) +{ + char usage_args[1024]; + bind_handle_t h; + struct query_params params; + const struct query_cmd *q; + ib_api_status_t status; + int n; + + const struct ibdiag_opt opts[] = { + {"p", 'p', 0, NULL, "get PathRecord info"}, + {"N", 'N', 0, NULL, "get NodeRecord info"}, + {"L", 'L', 0, NULL, "return the Lids of the name specified"}, + {"l", 'l', 0, NULL, + "return the unique Lid of the name specified"}, + {"G", 'G', 0, NULL, "return the Guids of the name specified"}, + {"O", 'O', 0, NULL, "return name for the Lid specified"}, + {"U", 'U', 0, NULL, "return name for the Guid specified"}, + {"s", 's', 0, NULL, "return the PortInfoRecords with isSM or" + " isSMdisabled capability mask bit on"}, + {"g", 'g', 0, NULL, "get multicast group info"}, + {"m", 'm', 0, NULL, "get multicast member info (if multicast" + " group specified, list member GIDs only for group specified," + " for example 'saquery -m 0xC000')"}, + {"x", 'x', 0, NULL, "get LinkRecord info"}, + {"c", 'c', 0, NULL, "get the SA's class port info"}, + {"S", 'S', 0, NULL, "get ServiceRecord info"}, + {"I", 'I', 0, NULL, "get InformInfoRecord (subscription) info"}, + {"list", 'D', 0, NULL, "the node desc of the CA's"}, + {"src-to-dst", 1, 1, "", "get a PathRecord for" + " where src and dst are either node names or LIDs"}, + {"sgid-to-dgid", 2, 1, "", "get a PathRecord for" + " where sgid and dgid are addresses in IPv6 format"}, + {"node-name-map", 3, 1, "", + "specify a node name map file"}, + {"smkey", 4, 1, "", + "SA SM_Key value for the query." + " If non-numeric value (like 'x') is specified then" + " saquery will prompt for a value"}, + {"slid", 5, 1, "", "Source LID (PathRecord)"}, + {"dlid", 6, 1, "", "Destination LID (PathRecord)"}, + {"mlid", 7, 1, "", "Multicast LID (MCMemberRecord)"}, + {"sgid", 14, 1, "", + "Source GID (IPv6 format) (PathRecord)"}, + {"dgid", 15, 1, "", + "Destination GID (IPv6 format) (PathRecord)"}, + {"gid", 16, 1, "", "Port GID (MCMemberRecord)"}, + {"mgid", 17, 1, "", "Multicast GID (MCMemberRecord)"}, + {"reversible", 'r', 1, NULL, "Reversible path (PathRecord)"}, + {"numb_path", 'n', 1, NULL, "Number of paths (PathRecord)"}, + {"pkey", 18, 1, NULL, "P_Key (PathRecord, MCMemberRecord)." + " If non-numeric value (like 'x') is specified then" + " saquery will prompt for a value"}, + {"qos_class", 'Q', 1, NULL, "QoS Class (PathRecord)"}, + {"sl", 19, 1, NULL, + "Service level (PathRecord, MCMemberRecord)"}, + {"mtu", 'M', 1, NULL, + "MTU and selector (PathRecord, MCMemberRecord)"}, + {"rate", 'R', 1, NULL, + "Rate and selector (PathRecord, MCMemberRecord)"}, + {"pkt_lifetime", 20, 1, NULL, + "Packet lifetime and selector (PathRecord, MCMemberRecord)"}, + {"qkey", 'q', 1, NULL, "Q_Key (MCMemberRecord)." + " If non-numeric value (like 'x') is specified then" + " saquery will prompt for a value"}, + {"tclass", 'T', 1, NULL, + "Traffic Class (PathRecord, MCMemberRecord)"}, + {"flow_label", 'F', 1, NULL, + "Flow Label (PathRecord, MCMemberRecord)"}, + {"hop_limit", 'H', 1, NULL, + "Hop limit (PathRecord, MCMemberRecord)"}, + {"scope", 21, 1, NULL, "Scope (MCMemberRecord)"}, + {"join_state", 'J', 1, NULL, "Join state (MCMemberRecord)"}, + {"proxy_join", 'X', 1, NULL, "Proxy join (MCMemberRecord)"}, + {0} + }; + + memset(¶ms, 0, sizeof params); + params.hop_limit = -1; + params.reversible = -1; + params.numb_path = -1; + params.qos_class = -1; + params.sl = -1; + params.proxy_join = -1; + + n = sprintf(usage_args, "[query-name] [ | | ]\n" + "\nSupported query names (and aliases):\n"); + for (q = query_cmds; q->name; q++) { + n += snprintf(usage_args + n, sizeof(usage_args) - n, + " %s (%s) %s\n", q->name, + q->alias ? q->alias : "", + q->usage ? q->usage : ""); + if (n >= sizeof(usage_args)) + exit(-1); + } + snprintf(usage_args + n, sizeof(usage_args) - n, + "\n Queries node records by default."); + + q = NULL; + ibd_timeout = DEFAULT_SA_TIMEOUT_MS; + + ibdiag_process_opts(argc, argv, ¶ms, "DLGs", opts, process_opt, + usage_args, NULL); + + argc -= optind; + argv += optind; + + if (!query_type && command == SAQUERY_CMD_QUERY) { + if (!argc || !(q = find_query(argv[0]))) + query_type = IB_SA_ATTR_NODERECORD; + else { + query_type = q->query_type; + argc--; + argv++; + } + } + + if (argc) { + if (node_print_desc == NAME_OF_LID) { + requested_lid = (uint16_t) strtoul(argv[0], NULL, 0); + requested_lid_flag++; + } else if (node_print_desc == NAME_OF_GUID) { + requested_guid = 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"); + ibdiag_show_usage(); + } + + if (node_print_desc == NAME_OF_LID && !requested_lid_flag) { + fprintf(stderr, "ERROR: lid not specified\n"); + ibdiag_show_usage(); + } + + if (node_print_desc == NAME_OF_GUID && !requested_guid_flag) { + fprintf(stderr, "ERROR: guid not specified\n"); + ibdiag_show_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"); + ibdiag_show_usage(); + } + + h = get_bind_handle(); + node_name_map = open_node_name_map(node_name_map_file); + + if (src_lid && *src_lid) + params.slid = get_lid(h, src_lid); + if (dst_lid && *dst_lid) + params.dlid = get_lid(h, dst_lid); + + switch (command) { + case SAQUERY_CMD_NODE_RECORD: + status = print_node_records(h); + 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, ¶ms, argc, argv); + break; + } + + if (src_lid) + free(src_lid); + clean_up(h); + close_node_name_map(node_name_map); + return (status); +} diff --git a/branches/WOF2-3/tools/infiniband-diags/src/saquery/SOURCES b/branches/WOF2-3/tools/infiniband-diags/src/saquery/SOURCES new file mode 100644 index 00000000..02d6ebd8 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/saquery/SOURCES @@ -0,0 +1,35 @@ +TARGETNAME = saquery +TARGETPATH = ..\..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = PROGRAM + +UMTYPE = console +UMENTRY = main + +USE_MSVCRT = 1 + +SOURCES = ..\saquery.c ..\ibdiag_common.c ..\ibdiag_windows.c saquery.rc + +INCLUDES = ..\..\include;..\..\include\windows;\ + ..\..\..\..\ulp\libibmad\include;\ + ..\..\..\..\ulp\libibumad\include;\ + ..\..\..\..\inc;..\..\..\..\inc\user;\ + ..\..\..\..\inc\user\linux; + +C_DEFINES = $(C_DEFINES) /DHAVE_CONFIG_H /DUSE_INET + +TARGETLIBS = \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\ibal.lib \ + $(TARGETPATH)\*\complib.lib \ + $(TARGETPATH)\*\libibmad.lib \ + $(TARGETPATH)\*\libibumad.lib +!else + $(TARGETPATH)\*\ibald.lib \ + $(TARGETPATH)\*\complibd.lib \ + $(TARGETPATH)\*\libibmadd.lib \ + $(TARGETPATH)\*\libibumadd.lib +!endif + +MSC_WARNING_LEVEL = /W3 /WX /wd4242 /wd4007 \ No newline at end of file diff --git a/branches/WOF2-3/tools/infiniband-diags/src/saquery/makefile b/branches/WOF2-3/tools/infiniband-diags/src/saquery/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/saquery/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\..\inc\openib.def diff --git a/branches/WOF2-3/tools/infiniband-diags/src/saquery/saquery.rc b/branches/WOF2-3/tools/infiniband-diags/src/saquery/saquery.rc new file mode 100644 index 00000000..52109aba --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/saquery/saquery.rc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef DBG +#define VER_FILEDESCRIPTION_STR "InfiniBand SA Query Utility (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "InfiniBand SA Query Utility" +#endif + +#define VER_INTERNALNAME_STR "saquery.exe" +#define VER_ORIGINALFILENAME_STR "saquery.exe" + +#include diff --git a/branches/WOF2-3/tools/infiniband-diags/src/sminfo.c b/branches/WOF2-3/tools/infiniband-diags/src/sminfo.c new file mode 100644 index 00000000..ef139115 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/sminfo.c @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2004-2009 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include + +#include +#include + +#include "ibdiag_common.h" + +static uint8_t sminfo[1024]; + +struct ibmad_port *srcport; + +int strdata, xdata = 1, bindata; + +enum { + SMINFO_NOTACT, + SMINFO_DISCOVER, + SMINFO_STANDBY, + SMINFO_MASTER, + + SMINFO_STATE_LAST, +}; + +char *statestr[] = { + "SMINFO_NOTACT", + "SMINFO_DISCOVER", + "SMINFO_STANDBY", + "SMINFO_MASTER", +}; + +#define STATESTR(s) (((unsigned)(s)) < SMINFO_STATE_LAST ? statestr[s] : "???") + +static unsigned act; +static int prio, state = SMINFO_STANDBY; + +static int process_opt(void *context, int ch, char *optarg) +{ + switch (ch) { + case 'a': + act = strtoul(optarg, 0, 0); + break; + case 's': + state = strtoul(optarg, 0, 0); + break; + case 'p': + prio = strtoul(optarg, 0, 0); + break; + default: + return -1; + } + return 0; +} + +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 }; + uint8_t *p; + uint64_t guid = 0, key = 0; + + const struct ibdiag_opt opts[] = { + {"state", 's', 1, "<0-3>", "set SM state"}, + {"priority", 'p', 1, "<0-15>", "set SM priority"}, + {"activity", 'a', 1, NULL, "set activity count"}, + {0} + }; + char usage_args[] = " [modifier]"; + + ibdiag_process_opts(argc, argv, NULL, "s", opts, process_opt, + usage_args, NULL); + + argc -= optind; + argv += optind; + + if (argc > 1) + mod = atoi(argv[1]); + + srcport = mad_rpc_open_port(ibd_ca, ibd_ca_port, mgmt_classes, 3); + if (!srcport) + IBERROR("Failed to open '%s' port '%d'", ibd_ca, ibd_ca_port); + + if (argc) { + if (ib_resolve_portid_str_via(&portid, argv[0], ibd_dest_type, + 0, srcport) < 0) + IBERROR("can't resolve destination port %s", argv[0]); + } else { + if (ib_resolve_smlid_via(&portid, ibd_timeout, srcport) < 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_via(sminfo, &portid, IB_ATTR_SMINFO, mod, + ibd_timeout, srcport))) + IBERROR("query"); + } else if (!(p = smp_query_via(sminfo, &portid, IB_ATTR_SMINFO, 0, + ibd_timeout, srcport))) + 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)); + + mad_rpc_close_port(srcport); + exit(0); +} diff --git a/branches/WOF2-3/tools/infiniband-diags/src/sminfo/SOURCES b/branches/WOF2-3/tools/infiniband-diags/src/sminfo/SOURCES new file mode 100644 index 00000000..ffc43cf3 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/sminfo/SOURCES @@ -0,0 +1,30 @@ +TARGETNAME = sminfo +TARGETPATH = ..\..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = PROGRAM + +UMTYPE = console +UMENTRY = main + +USE_MSVCRT = 1 + +SOURCES = ..\sminfo.c ..\ibdiag_common.c ..\ibdiag_windows.c sminfo.rc + +INCLUDES = ..\..\include;..\..\include\windows;\ + ..\..\..\..\ulp\libibmad\include;\ + ..\..\..\..\ulp\libibumad\include;\ + ..\..\..\..\inc;..\..\..\..\inc\user;\ + ..\..\..\..\inc\user\linux; + +C_DEFINES = $(C_DEFINES) /DHAVE_CONFIG_H + +TARGETLIBS = \ + $(SDK_LIB_PATH)\kernel32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\libibmad.lib \ + $(TARGETPATH)\*\libibumad.lib +!else + $(TARGETPATH)\*\libibmadd.lib \ + $(TARGETPATH)\*\libibumadd.lib +!endif + +MSC_WARNING_LEVEL = /W3 /WX /wd4007 \ No newline at end of file diff --git a/branches/WOF2-3/tools/infiniband-diags/src/sminfo/makefile b/branches/WOF2-3/tools/infiniband-diags/src/sminfo/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/sminfo/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\..\inc\openib.def diff --git a/branches/WOF2-3/tools/infiniband-diags/src/sminfo/sminfo.rc b/branches/WOF2-3/tools/infiniband-diags/src/sminfo/sminfo.rc new file mode 100644 index 00000000..b1afa84f --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/sminfo/sminfo.rc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef DBG +#define VER_FILEDESCRIPTION_STR "InfiniBand SM Information (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "InfiniBand SM Information" +#endif + +#define VER_INTERNALNAME_STR "sminfo.exe" +#define VER_ORIGINALFILENAME_STR "sminfo.exe" + +#include diff --git a/branches/WOF2-3/tools/infiniband-diags/src/smpdump.c b/branches/WOF2-3/tools/infiniband-diags/src/smpdump.c new file mode 100644 index 00000000..a6c4dfa3 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/smpdump.c @@ -0,0 +1,304 @@ +/* + * Copyright (c) 2004-2009 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#define _GNU_SOURCE + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +static int mad_agent; +static int drmad_tid = 0x123; + +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 = IB_SMI_DIRECT_CLASS; + 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 = (uint8_t) 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 = IB_SMI_CLASS; + 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, 0, 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 = (uint8_t) 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] = (char)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; +} + +static int dump_char, mgmt_class = IB_SMI_CLASS; + +static int process_opt(void *context, int ch, char *optarg) +{ + switch (ch) { + case 's': + dump_char++; + break; + case 'D': + mgmt_class = IB_SMI_DIRECT_CLASS; + break; + case 'L': + mgmt_class = IB_SMI_CLASS; + break; + default: + return -1; + } + return 0; +} + +int main(int argc, char *argv[]) +{ + int dlid = 0; + void *umad; + struct drsmp *smp; + int i, portid, mod = 0, attr; + DRPath path; + uint8_t *desc; + int length; + + const struct ibdiag_opt opts[] = { + {"sring", 's', 0, NULL, ""}, + {0} + }; + char usage_args[] = " [mod]"; + const char *usage_examples[] = { + " -- DR routed examples:", + "-D 0,1,2,3,5 16 # NODE DESC", + "-D 0,1,2 0x15 2 # PORT INFO, port 2", + " -- LID routed examples:", + "3 0x15 2 # PORT INFO, lid 3 port 2", + "0xa0 0x11 # NODE INFO, lid 0xa0", + NULL + }; + + ibd_timeout = 1000; + + ibdiag_process_opts(argc, argv, NULL, "Gs", opts, process_opt, + usage_args, usage_examples); + + argc -= optind; + argv += optind; + + if (argc < 2) + ibdiag_show_usage(); + + if (mgmt_class == IB_SMI_DIRECT_CLASS && + str2DRPath(strdupa(argv[0]), &path) < 0) + IBPANIC("bad path str '%s'", argv[0]); + + if (mgmt_class == IB_SMI_CLASS) + 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(ibd_ca, ibd_ca_port)) < 0) + IBPANIC("can't open UMAD port (%s:%d)", ibd_ca, ibd_ca_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 == IB_SMI_DIRECT_CLASS) + drsmp_get_init(umad, &path, attr, mod); + else + smp_get_init(umad, dlid, attr, mod); + + if (ibdebug > 1) + xdump(stderr, "before send:\n", smp, 256); + + length = IB_MAD_SIZE; + if (umad_send(portid, mad_agent, umad, length, ibd_timeout, 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)); + goto exit; + } + + 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)); + +exit: + umad_free(umad); + return 0; +} diff --git a/branches/WOF2-3/tools/infiniband-diags/src/smpdump/SOURCES b/branches/WOF2-3/tools/infiniband-diags/src/smpdump/SOURCES new file mode 100644 index 00000000..4afe2ac6 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/smpdump/SOURCES @@ -0,0 +1,31 @@ +TARGETNAME = smpdump +TARGETPATH = ..\..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = PROGRAM + +UMTYPE = console +UMENTRY = main + +USE_MSVCRT = 1 + +SOURCES = ..\smpdump.c ..\ibdiag_common.c ..\ibdiag_windows.c smpdump.rc + +INCLUDES = ..\..\include;..\..\include\windows;\ + ..\..\..\..\ulp\libibmad\include;\ + ..\..\..\..\ulp\libibumad\include;\ + ..\..\..\..\inc;..\..\..\..\inc\user;\ + ..\..\..\..\inc\user\linux; + +C_DEFINES = $(C_DEFINES) /DHAVE_CONFIG_H + +TARGETLIBS = \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\libibmad.lib \ + $(TARGETPATH)\*\libibumad.lib +!else + $(TARGETPATH)\*\libibmadd.lib \ + $(TARGETPATH)\*\libibumadd.lib +!endif + +MSC_WARNING_LEVEL = /W3 /WX /wd4007 diff --git a/branches/WOF2-3/tools/infiniband-diags/src/smpdump/makefile b/branches/WOF2-3/tools/infiniband-diags/src/smpdump/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/smpdump/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\..\inc\openib.def diff --git a/branches/WOF2-3/tools/infiniband-diags/src/smpdump/smpdump.rc b/branches/WOF2-3/tools/infiniband-diags/src/smpdump/smpdump.rc new file mode 100644 index 00000000..1c68e93b --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/smpdump/smpdump.rc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef DBG +#define VER_FILEDESCRIPTION_STR "Display IB SM Attributes (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "Display IB SM Attributes" +#endif + +#define VER_INTERNALNAME_STR "smpdump.exe" +#define VER_ORIGINALFILENAME_STR "smpdump.exe" + +#include diff --git a/branches/WOF2-3/tools/infiniband-diags/src/smpquery.c b/branches/WOF2-3/tools/infiniband-diags/src/smpquery.c new file mode 100644 index 00000000..a1559e88 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/smpquery.c @@ -0,0 +1,475 @@ +/* + * Copyright (c) 2004-2009 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include + +#define __STDC_FORMAT_MACROS +#include + +#include +#include +#include + +#include "ibdiag_common.h" + +struct ibmad_port *srcport; + +typedef char *(op_fn_t) (ib_portid_t * dest, char **argv, int argc); + +typedef struct match_rec { + const char *name, *alias; + 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", "NI", node_info}, + {"NodeDesc", "ND", node_desc}, + {"PortInfo", "PI", port_info, 1}, + {"SwitchInfo", "SI", switch_info}, + {"PKeyTable", "PKeys", pkey_table, 1}, + {"SL2VLTable", "SL2VL", sl2vl_table, 1}, + {"VLArbitration", "VLArb", vlarb_table, 1}, + {"GUIDInfo", "GI", guid_info}, + {0} +}; + +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_via(data, dest, IB_ATTR_NODE_INFO, 0, 0, srcport)) + 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_via(nd, dest, IB_ATTR_NODE_DESC, 0, 0, srcport)) + 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_via(data, dest, IB_ATTR_NODE_INFO, 0, 0, srcport)) + 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_via(data, dest, IB_ATTR_PORT_INFO, portnum, 0, srcport)) + 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_via(data, dest, IB_ATTR_SWITCH_INFO, 0, 0, srcport)) + 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]; + int 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_via(data, dest, IB_ATTR_NODE_INFO, 0, 0, srcport)) + 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_via(data, dest, IB_ATTR_SWITCH_INFO, 0, 0, + srcport)) + 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_via(data, dest, IB_ATTR_PKEY_TBL, mod, 0, + srcport)) + 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_via(data, dest, IB_ATTR_SLVL_TABLE, portnum, 0, srcport)) + 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_via(data, dest, IB_ATTR_NODE_INFO, 0, 0, srcport)) + 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_via(data, dest, IB_ATTR_VL_ARBITRATION, + (offset << 16) | portnum, 0, srcport)) + 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_via(data, dest, IB_ATTR_NODE_INFO, 0, 0, + srcport)) + return "node info query failed"; + + mad_decode_field(data, IB_NODE_TYPE_F, &type); + if (type == IB_NODE_SWITCH) { + if (!smp_query_via(data, dest, IB_ATTR_SWITCH_INFO, 0, + 0, srcport)) + 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_via(data, dest, IB_ATTR_PORT_INFO, portnum, 0, srcport)) + 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]; + int i, j, k; + uint64_t *p; + unsigned mod; + int n; + + /* Get the guid capacity */ + if (!smp_query_via(data, dest, IB_ATTR_PORT_INFO, 0, 0, srcport)) + 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_via(data, dest, IB_ATTR_GUID_INFO, mod, 0, + srcport)) + 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; + unsigned len = strlen(name); + for (r = match_tbl; r->name; r++) + if (!strncasecmp(r->name, name, len) || + (r->alias && !strncasecmp(r->alias, name, len))) + return r->fn; + return NULL; +} + +static int process_opt(void *context, int ch, char *optarg) +{ + switch (ch) { + case 1: + node_name_map_file = strdup(optarg); + break; + case 'c': + ibd_dest_type = IB_DEST_DRSLID; + break; + default: + return -1; + } + return 0; +} + +int main(int argc, char **argv) +{ + char usage_args[1024]; + int mgmt_classes[3] = + { IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS }; + ib_portid_t portid = { 0 }; + char *err; + op_fn_t *fn; + const match_rec_t *r; + int n; + + const struct ibdiag_opt opts[] = { + {"combined", 'c', 0, NULL, + "use Combined route address argument"}, + {"node-name-map", 1, 1, "", "node name map file"}, + {0} + }; + const char *usage_examples[] = { + "portinfo 3 1\t\t\t\t# portinfo by lid, with port modifier", + "-G switchinfo 0x2C9000100D051 1\t# switchinfo by guid", + "-D nodeinfo 0\t\t\t\t# nodeinfo by direct route", + "-c nodeinfo 6 0,12\t\t\t# nodeinfo by combined route", + NULL + }; + + n = sprintf(usage_args, " [op params]\n" + "\nSupported ops (and aliases, case insensitive):\n"); + for (r = match_tbl; r->name; r++) { + n += snprintf(usage_args + n, sizeof(usage_args) - n, + " %s (%s) %s\n", r->name, + r->alias ? r->alias : "", + r->opt_portnum ? " []" : ""); + if (n >= sizeof(usage_args)) + exit(-1); + } + + ibdiag_process_opts(argc, argv, NULL, NULL, opts, process_opt, + usage_args, usage_examples); + + argc -= optind; + argv += optind; + + if (argc < 2) + ibdiag_show_usage(); + + if (!(fn = match_op(argv[0]))) + IBERROR("operation '%s' not supported", argv[0]); + + srcport = mad_rpc_open_port(ibd_ca, ibd_ca_port, mgmt_classes, 3); + if (!srcport) + IBERROR("Failed to open '%s' port '%d'", ibd_ca, ibd_ca_port); + + node_name_map = open_node_name_map(node_name_map_file); + + if (ibd_dest_type != IB_DEST_DRSLID) { + if (ib_resolve_portid_str_via(&portid, argv[1], ibd_dest_type, + ibd_sm_id, srcport) < 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_via(&portid, concat, ibd_dest_type, + ibd_sm_id, srcport) < 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); + mad_rpc_close_port(srcport); + exit(0); +} diff --git a/branches/WOF2-3/tools/infiniband-diags/src/smpquery/SOURCES b/branches/WOF2-3/tools/infiniband-diags/src/smpquery/SOURCES new file mode 100644 index 00000000..84765275 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/smpquery/SOURCES @@ -0,0 +1,33 @@ +TARGETNAME = smpquery +TARGETPATH = ..\..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = PROGRAM + +UMTYPE = console +UMENTRY = main + +USE_MSVCRT = 1 + +SOURCES = ..\smpquery.c ..\ibdiag_common.c ..\ibdiag_windows.c smpquery.rc + +INCLUDES = ..\..\include;..\..\include\windows;\ + ..\..\..\..\ulp\libibmad\include;\ + ..\..\..\..\ulp\libibumad\include;\ + ..\..\..\..\inc;..\..\..\..\inc\user;\ + ..\..\..\..\inc\user\linux; + +C_DEFINES = $(C_DEFINES) /DHAVE_CONFIG_H + +TARGETLIBS = \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\complib.lib \ + $(TARGETPATH)\*\libibmad.lib \ + $(TARGETPATH)\*\libibumad.lib +!else + $(TARGETPATH)\*\complibd.lib \ + $(TARGETPATH)\*\libibmadd.lib \ + $(TARGETPATH)\*\libibumadd.lib +!endif + +MSC_WARNING_LEVEL = /W3 /WX /wd4007 diff --git a/branches/WOF2-3/tools/infiniband-diags/src/smpquery/makefile b/branches/WOF2-3/tools/infiniband-diags/src/smpquery/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/smpquery/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\..\inc\openib.def diff --git a/branches/WOF2-3/tools/infiniband-diags/src/smpquery/smpquery.rc b/branches/WOF2-3/tools/infiniband-diags/src/smpquery/smpquery.rc new file mode 100644 index 00000000..0f8b2d41 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/smpquery/smpquery.rc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef DBG +#define VER_FILEDESCRIPTION_STR "Query IB SM Attributes (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "Query IB SM Attributes" +#endif + +#define VER_INTERNALNAME_STR "smpquery.exe" +#define VER_ORIGINALFILENAME_STR "smpquery.exe" + +#include diff --git a/branches/WOF2-3/tools/infiniband-diags/src/vendstat.c b/branches/WOF2-3/tools/infiniband-diags/src/vendstat.c new file mode 100644 index 00000000..92a90c8f --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/vendstat.c @@ -0,0 +1,442 @@ +/* + * Copyright (c) 2004-2009 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include + +#include +#include + +#include "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 +#define IB_MLX_IS4_COUNTER_GROUP_INFO 0x90 +#define IB_MLX_IS4_CONFIG_COUNTER_GROUP 0x91 +/* Config space addresses */ +#define IB_MLX_IS3_PORT_XMIT_WAIT 0x10013C + +struct ibmad_port *srcport; + +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 { + uint8_t reserved[8]; + struct is3_record { + uint32_t address; + uint32_t data; + uint32_t mask; + } record[18]; +} is3_config_space_t; + +#define COUNTER_GROUPS_NUM 2 + +typedef struct { + uint8_t reserved1[8]; + uint8_t reserved[3]; + uint8_t num_of_counter_groups; + uint32_t group_masks[COUNTER_GROUPS_NUM]; +} is4_counter_group_info_t; + +typedef struct { + uint8_t reserved[3]; + uint8_t group_select; +} is4_group_select_t; + +typedef struct { + uint8_t reserved1[8]; + uint8_t reserved[4]; + is4_group_select_t group_selects[COUNTER_GROUPS_NUM]; +} is4_config_counter_groups_t; + +static int do_vendor(ib_portid_t *portid, struct ibmad_port *srcport, + uint8_t class, uint8_t method, uint16_t attr_id, + uint32_t attr_mod, void *data) +{ + ib_vendor_call_t call; + + memset(&call, 0, sizeof(call)); + call.mgmt_class = class; + call.method = method; + call.timeout = ibd_timeout; + call.attrid = attr_id; + call.mod = attr_mod; + + if (!ib_vendor_call_via(data, portid, &call, srcport)) + IBERROR("vendstat: method %u, attribute %u", method, attr_id); + + return 0; +} + +static void do_config_space_records(ib_portid_t *portid, unsigned set, + is3_config_space_t *cs, unsigned records) +{ + unsigned i; + + if (records > 18) + records = 18; + for (i = 0; i < records; i++) { + cs->record[i].address = htonl(cs->record[i].address); + cs->record[i].data = htonl(cs->record[i].data); + cs->record[i].mask = htonl(cs->record[i].mask); + } + + if (do_vendor(portid, srcport, IB_MLX_VENDOR_CLASS, + set ? IB_MAD_METHOD_SET : IB_MAD_METHOD_GET, + IB_MLX_IS3_CONFIG_SPACE_ACCESS, 2 << 22 | records << 16, + cs)) + IBERROR("cannot %s config space records", set ? "set" : "get"); + + for (i = 0; i < records; i++) { + printf("Config space record at 0x%x: 0x%x\n", + ntohl(cs->record[i].address), + ntohl(cs->record[i].data & cs->record[i].mask)); + } +} + +static void counter_groups_info(ib_portid_t * portid, int port) +{ + char buf[1024]; + is4_counter_group_info_t *cg_info; + int i, num_cg; + + /* Counter Group Info */ + memset(&buf, 0, sizeof(buf)); + if (do_vendor(portid, srcport, IB_MLX_VENDOR_CLASS, IB_MAD_METHOD_GET, + IB_MLX_IS4_COUNTER_GROUP_INFO, port, buf)) + IBERROR("counter group info query"); + + cg_info = (is4_counter_group_info_t *) & buf; + num_cg = cg_info->num_of_counter_groups; + printf("counter_group_info:\n"); + printf("%d counter groups\n", num_cg); + for (i = 0; i < num_cg; i++) + printf("group%d mask %#x\n", i, ntohl(cg_info->group_masks[i])); +} + +/* Group0 counter config values */ +#define IS4_G0_PortXmtDataSL_0_7 0 +#define IS4_G0_PortXmtDataSL_8_15 1 +#define IS4_G0_PortRcvDataSL_0_7 2 + +/* Group1 counter config values */ +#define IS4_G1_PortXmtDataSL_8_15 1 +#define IS4_G1_PortRcvDataSL_0_7 2 +#define IS4_G1_PortRcvDataSL_8_15 8 + +static int cg0, cg1; + +static void config_counter_groups(ib_portid_t * portid, int port) +{ + char buf[1024]; + is4_config_counter_groups_t *cg_config; + + /* configure counter groups for groups 0 and 1 */ + memset(&buf, 0, sizeof(buf)); + cg_config = (is4_config_counter_groups_t *) & buf; + + printf("counter_groups_config: configuring group0 %d group1 %d\n", cg0, + cg1); + cg_config->group_selects[0].group_select = (uint8_t) cg0; + cg_config->group_selects[1].group_select = (uint8_t) cg1; + + if (do_vendor(portid, srcport, IB_MLX_VENDOR_CLASS, IB_MAD_METHOD_SET, + IB_MLX_IS4_CONFIG_COUNTER_GROUP, port, buf)) + IBERROR("config counter group set"); + + /* get config counter groups */ + memset(&buf, 0, sizeof(buf)); + + if (do_vendor(portid, srcport, IB_MLX_VENDOR_CLASS, IB_MAD_METHOD_GET, + IB_MLX_IS4_CONFIG_COUNTER_GROUP, port, buf)) + IBERROR("config counter group query"); +} + +static int general_info, xmit_wait, counter_group_info, config_counter_group; +static is3_config_space_t write_cs, read_cs; +static unsigned write_cs_records, read_cs_records; + + +static int process_opt(void *context, int ch, char *optarg) +{ + int ret; + switch (ch) { + case 'N': + general_info = 1; + break; + case 'w': + xmit_wait = 1; + break; + case 'i': + counter_group_info = 1; + break; + case 'c': + config_counter_group = 1; + ret = sscanf(optarg, "%d,%d", &cg0, &cg1); + if (ret != 2) + return -1; + break; + case 'R': + if (read_cs_records >= 18) + break; + ret = sscanf(optarg, "%x,%x", + &read_cs.record[read_cs_records].address, + &read_cs.record[read_cs_records].mask); + if (ret < 1) + return -1; + else if (ret == 1) + read_cs.record[read_cs_records].mask = 0xffffffff; + read_cs_records++; + break; + case 'W': + if (write_cs_records >= 18) + break; + ret = sscanf(optarg, "%x,%x,%x", + &write_cs.record[write_cs_records].address, + &write_cs.record[write_cs_records].data, + &write_cs.record[write_cs_records].mask); + if (ret < 2) + return -1; + else if (ret == 2) + write_cs.record[write_cs_records].mask = 0xffffffff; + write_cs_records++; + break; + default: + return -1; + } + return 0; +} + +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 portid = { 0 }; + int port = 0; + char buf[1024]; + is3_general_info_t *gi; + + const struct ibdiag_opt opts[] = { + {"N", 'N', 0, NULL, "show IS3 or IS4 general information"}, + {"w", 'w', 0, NULL, "show IS3 port xmit wait counters"}, + {"i", 'i', 0, NULL, "show IS4 counter group info"}, + {"c", 'c', 1, "", "configure IS4 counter groups"}, + {"Read", 'R', 1, "", "Read configuration space record at addr"}, + {"Write", 'W', 1, "", "Write configuration space record at addr"}, + {0} + }; + + char usage_args[] = " [port]"; + const char *usage_examples[] = { + "-N 6\t\t# read IS3 or IS4 general information", + "-w 6\t\t# read IS3 port xmit wait counters", + "-i 6 12\t# read IS4 port 12 counter group info", + "-c 0,1 6 12\t# configure IS4 port 12 counter groups for PortXmitDataSL", + "-c 2,8 6 12\t# configure IS4 port 12 counter groups for PortRcvDataSL", + NULL + }; + + ibdiag_process_opts(argc, argv, NULL, "D", opts, process_opt, + usage_args, usage_examples); + + argc -= optind; + argv += optind; + + if (argc > 1) + port = strtoul(argv[1], 0, 0); + + srcport = mad_rpc_open_port(ibd_ca, ibd_ca_port, mgmt_classes, 4); + if (!srcport) + IBERROR("Failed to open '%s' port '%d'", ibd_ca, ibd_ca_port); + + if (argc) { + if (ib_resolve_portid_str_via(&portid, argv[0], ibd_dest_type, + ibd_sm_id, srcport) < 0) + IBERROR("can't resolve destination port %s", argv[0]); + } else { + if (ib_resolve_self_via(&portid, &port, 0, srcport) < 0) + IBERROR("can't resolve self port %s", argv[0]); + } + + if (counter_group_info) { + counter_groups_info(&portid, port); + exit(0); + } + + if (config_counter_group) { + config_counter_groups(&portid, port); + exit(0); + } + + if (read_cs_records || write_cs_records) { + if (read_cs_records) + do_config_space_records(&portid, 0, &read_cs, + read_cs_records); + if (write_cs_records) + do_config_space_records(&portid, 1, &write_cs, + write_cs_records); + exit(0); + } + + /* These are Mellanox specific vendor MADs */ + /* but vendors change the VendorId so how know for sure ? */ + /* 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"); + + /* Would need a list of these and it might not be complete */ + /* so for right now, punt on this */ + + /* vendor ClassPortInfo is required attribute if class supported */ + memset(&buf, 0, sizeof(buf)); + if (do_vendor(&portid, srcport, IB_MLX_VENDOR_CLASS, IB_MAD_METHOD_GET, + CLASS_PORT_INFO, 0, buf)) + IBERROR("classportinfo query"); + + memset(&buf, 0, sizeof(buf)); + gi = (is3_general_info_t *) & buf; + if (do_vendor(&portid, srcport, IB_MLX_VENDOR_CLASS, IB_MAD_METHOD_GET, + IB_MLX_IS3_GENERAL_INFO, 0, gi)) + + if (general_info) { + /* dump IS3 or IS4 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) { + is3_config_space_t *cs; + unsigned i; + + 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)); + /* 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 (do_vendor(&portid, srcport, IB_MLX_VENDOR_CLASS, + IB_MAD_METHOD_GET, IB_MLX_IS3_CONFIG_SPACE_ACCESS, + 2 << 22 | 16 << 16, cs)) + 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)); + /* 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 (do_vendor(&portid, srcport, IB_MLX_VENDOR_CLASS, + IB_MAD_METHOD_GET, IB_MLX_IS3_CONFIG_SPACE_ACCESS, + 2 << 22 | 8 << 16, cs)) + 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)); + } + + mad_rpc_close_port(srcport); + exit(0); +} diff --git a/branches/WOF2-3/tools/infiniband-diags/src/vendstat/SOURCES b/branches/WOF2-3/tools/infiniband-diags/src/vendstat/SOURCES new file mode 100644 index 00000000..fcda4188 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/vendstat/SOURCES @@ -0,0 +1,31 @@ +TARGETNAME = vendstat +TARGETPATH = ..\..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = PROGRAM + +UMTYPE = console +UMENTRY = main + +USE_MSVCRT = 1 + +SOURCES = ..\vendstat.c ..\ibdiag_common.c ..\ibdiag_windows.c vendstat.rc + +INCLUDES = ..\..\include;..\..\include\windows;\ + ..\..\..\..\ulp\libibmad\include;\ + ..\..\..\..\ulp\libibumad\include;\ + ..\..\..\..\inc;..\..\..\..\inc\user;\ + ..\..\..\..\inc\user\linux; + +C_DEFINES = $(C_DEFINES) /DHAVE_CONFIG_H + +TARGETLIBS = \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\libibmad.lib \ + $(TARGETPATH)\*\libibumad.lib +!else + $(TARGETPATH)\*\libibmadd.lib \ + $(TARGETPATH)\*\libibumadd.lib +!endif + +MSC_WARNING_LEVEL = /W3 /WX /wd4007 diff --git a/branches/WOF2-3/tools/infiniband-diags/src/vendstat/makefile b/branches/WOF2-3/tools/infiniband-diags/src/vendstat/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/vendstat/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\..\inc\openib.def diff --git a/branches/WOF2-3/tools/infiniband-diags/src/vendstat/vendstat.rc b/branches/WOF2-3/tools/infiniband-diags/src/vendstat/vendstat.rc new file mode 100644 index 00000000..2ad580c7 --- /dev/null +++ b/branches/WOF2-3/tools/infiniband-diags/src/vendstat/vendstat.rc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef DBG +#define VER_FILEDESCRIPTION_STR "InfiniBand Vendor HW Stats (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "InfiniBand Vendor HW Stats" +#endif + +#define VER_INTERNALNAME_STR "vendstat.exe" +#define VER_ORIGINALFILENAME_STR "vendstat.exe" + +#include diff --git a/branches/WOF2-3/tools/ndinstall/dirs b/branches/WOF2-3/tools/ndinstall/dirs new file mode 100644 index 00000000..389156fd --- /dev/null +++ b/branches/WOF2-3/tools/ndinstall/dirs @@ -0,0 +1,2 @@ +DIRS=\ + user diff --git a/branches/WOF2-3/tools/ndinstall/user/SOURCES b/branches/WOF2-3/tools/ndinstall/user/SOURCES new file mode 100644 index 00000000..9bcc2e49 --- /dev/null +++ b/branches/WOF2-3/tools/ndinstall/user/SOURCES @@ -0,0 +1,23 @@ +TARGETNAME=ndinstall +TARGETPATH=..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE=PROGRAM +UMTYPE=console +USE_MSVCRT=1 + +INCLUDES=..\..\..\inc;\ + ..\..\..\inc\user; + +SOURCES= \ + installsp.rc \ + installsp.c + +USER_C_FLAGS=$(USER_C_FLAGS) +#-DPERFMON_ENABLED + +TARGETLIBS=\ + $(SDK_LIB_PATH)\ws2_32.lib \ + $(SDK_LIB_PATH)\LoadPerf.lib + +MSC_WARNING_LEVEL= /W3 + +LINKER_FLAGS=$(LINKER_FLAGS) diff --git a/branches/WOF2-3/tools/ndinstall/user/installsp.c b/branches/WOF2-3/tools/ndinstall/user/installsp.c new file mode 100644 index 00000000..d95e2a45 --- /dev/null +++ b/branches/WOF2-3/tools/ndinstall/user/installsp.c @@ -0,0 +1,354 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * Copyright (c) 2009 Intel Corp, Inc. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +/* + * Module Name: installsp.c + * Description: This module installs/removes the NetworkDirect provider for infiniband. + * execute: + * To install the service provider + * installsp -i + * To remove the service provider + * installsp -r + */ + +#include +#include +#include +#include +#include +#include "..\..\..\..\etc\user\getopt.c" + +#ifndef PFL_NETWORKDIRECT_PROVIDER +#define PFL_NETWORKDIRECT_PROVIDER 0x00000010 +#endif + +/* Initialize the LSP's provider path for Infiniband Service Provider dll */ +#define IBAL_INDEX 0 +#define IBAL_DEBUG_INDEX 1 +#define WV_INDEX 2 +#define WV_DEBUG_INDEX 3 +#define MAX_INDEX 4 + +#define DEFAULT_PROVIDER_INDEX IBAL_INDEX + +static int g_index=DEFAULT_PROVIDER_INDEX; + +static const char * const provider_name[MAX_INDEX] = { + "IBAL", "IBAL (debug)", "WinVerbs", "WinVerbs (debug)" +}; + +static const WCHAR * const provider_path[MAX_INDEX] = { + L"%SYSTEMROOT%\\system32\\ibndprov.dll", + L"%SYSTEMROOT%\\system32\\ibndprov.dll", + L"%SYSTEMROOT%\\system32\\wvndprov.dll", + L"%SYSTEMROOT%\\system32\\wvndprovd.dll" +}; + +static const WCHAR * const provider_desc[MAX_INDEX] = { + L"OpenFabrics Network Direct Provider", + L"OpenFabrics Network Direct Provider (Debug)", + L"OpenFabrics Winverbs Network Direct Provider", + L"OpenFabrics Winverbs Network Direct Provider (Debug)" +}; + +static GUID provider_guid[MAX_INDEX] = { + // {52CDAA00-29D0-46be-8FC6-E51D7075C338} + { 0x52CDAA00, 0x29D0, 0x46be, { 0x8f, 0xc6, 0xe5, 0x1d, 0x70, 0x75, 0xc3, 0x38 } }, + // {52CDAA00-29D0-46be-8FC6-E51D7075C338} + { 0x52CDAA00, 0x29D0, 0x46be, { 0x8f, 0xc6, 0xe5, 0x1d, 0x70, 0x75, 0xc3, 0x38 } }, + // {854DCE83-C872-4462-A3EB-C961C40E59D0} + { 0x854dce83, 0xc872, 0x4462, { 0xa3, 0xeb, 0xc9, 0x61, 0xc4, 0x0e, 0x59, 0xd0 } }, + // {1B8F1692-EDD9-4153-A159-605A73BCFFCF} + { 0x1b8f1692, 0xedd9, 0x4153, { 0xa1, 0x59, 0x60, 0x5a, 0x73, 0xbc, 0xff, 0xcf } } +}; + +#ifdef _WIN64 +#define WSCInstallProvider WSCInstallProvider64_32 +#endif /* _WIN64 */ + +static void +show_usage (char *progname) +{ + char drv[_MAX_DRIVE]; + char dir[_MAX_DIR]; + char fname[_MAX_FNAME]; + char ext[_MAX_EXT]; + + _splitpath(progname,drv,dir,fname,ext); // sad basename() equivalent. + + printf("usage: %s%s\n",fname,ext); + printf("\tRemove, install and list OFA NetworkDirect providers\n\n"); + printf("\t[-[i|r] [provider]] Install/remove the specified/default" + " provider\n"); + printf("\t[-d] Install/remove debug version of provider\n"); + printf("\t[-l] list OFA ND providers\n"); + printf("\t[-q] Suppress default listing of providers\n"); + printf("\t[-h] This text\n"); + printf("\tprovider must be one of the following names:\n"); + printf("\t\tibal\n"); + printf("\t\twinverbs\n"); + printf("\t\t use the default ND provider '%s'\n", + provider_name[DEFAULT_PROVIDER_INDEX]); +} + + +static void print_providers(void) +{ + WSAPROTOCOL_INFOW *protocol_info; + unsigned int protocol_count; + unsigned int i; + DWORD protocol_size; + INT err_no; + int rc; + + /* Find the size of the buffer */ + protocol_size = 0; + rc = WSCEnumProtocols (NULL, NULL, &protocol_size, &err_no); + if (rc == SOCKET_ERROR && err_no != WSAENOBUFS) { + printf("WSCEnumProtocols() returned error (%d)\n", err_no); + return; + } + + protocol_info = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, protocol_size); + if (protocol_info == NULL) { + printf("HeapAlloc() failed\n"); + return; + } + + /* Enumerate the catalog for real */ + rc = WSCEnumProtocols (NULL, protocol_info, &protocol_size, &err_no); + if (rc == SOCKET_ERROR) { + printf("WSCEnumProtocols returned error for real enumeration (%d)\n", + err_no); + HeapFree (GetProcessHeap (), 0, protocol_info); + return; + } + + protocol_count = rc; + + printf("\nCurrent providers:\n"); + for (i = 0; i < protocol_count; i++) { + printf ("\t%010d - %S\n", protocol_info[i].dwCatalogEntryId, + protocol_info[i].szProtocol); + } + + HeapFree (GetProcessHeap (), 0, protocol_info); + + return; +} + +/* + * Function: install_provider + * Description: installs the service provider + * + * Note: most of the information setup here comes from "MSDN Home > + * MSDN Library > Windows Development > Network Devices and + * Protocols > Design Guide > System Area Networks > Windows Sockets + * Direct > Windows Sockets Direct Component Operation > Installing + * Windows Sockets Direct Components". + * The direct link is http://msdn.microsoft.com/library/default.asp?url=/library/en-us/network/hh/network/wsdp_2xrb.asp + */ +static int install_provider(void) +{ + int rc, err_no; + WSAPROTOCOL_INFOW provider; + + /* Setup the values in PROTOCOL_INFO */ + provider.dwServiceFlags1 = + XP1_GUARANTEED_DELIVERY | + XP1_GUARANTEED_ORDER | + XP1_MESSAGE_ORIENTED | + XP1_CONNECT_DATA; /*XP1_GRACEFUL_CLOSE;*/ + provider.dwServiceFlags2 = 0; /* Reserved */ + provider.dwServiceFlags3 = 0; /* Reserved */ + provider.dwServiceFlags4 = 0; /* Reserved */ + provider.dwProviderFlags = PFL_HIDDEN | PFL_NETWORKDIRECT_PROVIDER; + provider.ProviderId = provider_guid[g_index]; + provider.dwCatalogEntryId = 0; + provider.ProtocolChain.ChainLen = 1; /* Base Protocol Service Provider */ + provider.iVersion = 1; + if (g_index == IBAL_INDEX || g_index == IBAL_DEBUG_INDEX) { + provider.iAddressFamily = AF_INET; + provider.iMaxSockAddr = sizeof(SOCKADDR_IN); + } else { + provider.iAddressFamily = AF_INET6; + provider.iMaxSockAddr = sizeof(SOCKADDR_IN6); + } + provider.iMinSockAddr = 16; + provider.iSocketType = -1; + provider.iProtocol = 0; + provider.iProtocolMaxOffset = 0; + provider.iNetworkByteOrder = BIGENDIAN; + provider.iSecurityScheme = SECURITY_PROTOCOL_NONE; + provider.dwMessageSize = 0xFFFFFFFF; /* IB supports 32-bit lengths for data transfers on RC */ + provider.dwProviderReserved = 0; + wcscpy( provider.szProtocol, provider_desc[g_index] ); + + printf("\nInstalling %s provider: ", provider_name[g_index]); + rc = WSCInstallProvider( + &provider_guid[g_index], provider_path[g_index], &provider, 1, &err_no ); + if( rc == SOCKET_ERROR ) + { + if( err_no == WSANO_RECOVERY ) + printf("already installed\n"); + else + printf("WSCInstallProvider failed: %d\n", err_no); + rc = err_no; + } else { + printf("successful\n"); + rc = 0; + } + return rc; +} + +/* + * Function: remove_provider + * Description: removes our provider. + */ +static int remove_provider(void) +{ + int rc=0, err_no, rc1; + + /* Remove from the catalog */ + printf("\nRemoving %s provider: ", provider_name[g_index]); + rc1 = WSCDeinstallProvider(&provider_guid[g_index], &err_no); + if (rc1 == SOCKET_ERROR) { + printf ("WSCDeinstallProvider failed: %d\n", err_no); + rc1 = err_no; + } else { + printf ("successful\n"); + rc1 = 0; + } + +#ifdef _WIN64 + /* Remove from the 32-bit catalog too! */ + printf("Removing 32-bit %s provider: ", provider_name[g_index]); + rc = WSCDeinstallProvider32(&provider_guid[g_index], &err_no); + if (rc == SOCKET_ERROR) { + printf ("WSCDeinstallProvider32 failed: %d\n", err_no); + rc = err_no; + } else { + printf ("successful\n"); + rc = 0; + } +#endif /* _WIN64 */ + if ( rc || rc1 ) + return (rc ? rc : rc1); + return 0; +} + +static int get_prov_index(char *name) +{ + int i; + + if ( !name ) + return 0; /* assumes global 'g_index' set to default provider index. */ + + for (i = 0; i < MAX_INDEX; i++) { + if (!_stricmp(provider_name[i], name)) { + g_index = i; + return 0; + } + } + return -1; +} + +int __cdecl main (int argc, char *argv[]) +{ + int ret=0, op; + int install = 0, remove = 0, debug = 0, quiet = 0; + WSADATA wsd; + char *prov; + + while ((op = getopt(argc, argv, "?hi::r::dlq")) != -1) { + switch (op) { + case '?': + case 'h': + goto usage; + case 'i': + if (install || remove || get_prov_index(optarg)) { + goto usage; + } + install = 1; + break; + case 'r': + if (install || remove || get_prov_index(optarg)) { + goto usage; + } + remove = 1; + break; + case 'd': + debug = 1; + break; + case 'l': + quiet = 0; + break; + case 'q': + quiet = 1; + break; + default: + goto usage; + } + } + + g_index += debug; + + if (WSAStartup (MAKEWORD (2, 2), &wsd) != 0) { + printf ("InstallSP: Unable to load Winsock: %d\n", GetLastError ()); + return -1; + } + + if (LOBYTE (wsd.wVersion) != 2 || HIBYTE (wsd.wVersion) != 2) { + WSACleanup (); + printf("InstallSP: Unable to find a usable version of Winsock DLL\n"); + ret = -1; + goto exit; + } + + if (install) { + ret = install_provider(); + } else if (remove) { + ret = remove_provider(); + } + + if (quiet == 0) + print_providers(); + +exit: + WSACleanup(); + return ret; + +usage: + show_usage(argv[0]); + return -1; +} diff --git a/branches/WOF2-3/tools/ndinstall/user/installsp.rc b/branches/WOF2-3/tools/ndinstall/user/installsp.rc new file mode 100644 index 00000000..afac7a57 --- /dev/null +++ b/branches/WOF2-3/tools/ndinstall/user/installsp.rc @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef _DEBUG_ +#define VER_FILEDESCRIPTION_STR "NetworkDirect for InfiniBand installer (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "NetworkDirect for InfiniBand installer" +#endif + +#define VER_INTERNALNAME_STR "ndinstall.exe" +#define VER_ORIGINALFILENAME_STR "ndinstall.exe" + +#include diff --git a/branches/WOF2-3/tools/ndinstall/user/makefile b/branches/WOF2-3/tools/ndinstall/user/makefile new file mode 100644 index 00000000..4d9185ba --- /dev/null +++ b/branches/WOF2-3/tools/ndinstall/user/makefile @@ -0,0 +1,15 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# +# If Network Direct SDK is not installed then disable all ndinstall.exe builds. + +!IFNDEF ND_INC +!MESSAGE Skipping ndinstall build: HPC SDK not installed. +DDK_BLOCK_ON_IA64=1 +DDK_BLOCK_ON_X86=1 +DDK_BLOCK_ON_AMD64=1 +!ENDIF + +!INCLUDE ..\..\..\inc\openib.def diff --git a/branches/WOF2-3/tools/nsc/SOURCES b/branches/WOF2-3/tools/nsc/SOURCES new file mode 100644 index 00000000..54ced72c --- /dev/null +++ b/branches/WOF2-3/tools/nsc/SOURCES @@ -0,0 +1,26 @@ +TARGETNAME=nsc +TARGETPATH=..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE=PROGRAM +UMTYPE=console +USE_MSVCRT=1 + +SOURCES=nsc.c \ + nsc.rc + +INCLUDES=$(SDK_INC_PATH); + +RCOPTIONS=/I..\..\inc; + +TARGETLIBS=$(SDK_LIB_PATH)\user32.lib $(SDK_LIB_PATH)\ws2_32.lib + +!if $(FREEBUILD) + +!else +C_DEFINES=$(C_DEFINES) -DDEBUG +!endif + +C_DEFINES=$(C_DEFINES) -D__WIN__ + +386_STDCALL=0 + + diff --git a/branches/WOF2-3/tools/nsc/makefile b/branches/WOF2-3/tools/nsc/makefile new file mode 100644 index 00000000..af203a50 --- /dev/null +++ b/branches/WOF2-3/tools/nsc/makefile @@ -0,0 +1,8 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the Windows NT DDK +# + +!INCLUDE ..\..\inc\openib.def + diff --git a/branches/WOF2-3/tools/nsc/nsc.c b/branches/WOF2-3/tools/nsc/nsc.c new file mode 100644 index 00000000..19d102ff --- /dev/null +++ b/branches/WOF2-3/tools/nsc/nsc.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2007 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * broadcast a settings changed message to all top-level windows in the system, + * including disabled or invisible unowned windows, overlapped windows, + * and pop-up windows; message is not sent to child windows. + * + * Utilized to notify top-level windows that an environment variable has + * been modified; specifically PATH. Functionality utilized during WinOF + * installation. + * +*/ +#include +#include +#include +#include + +int main(int argc, char* argv[]) +{ + DWORD dwReturnValue; + LRESULT rc; + + rc = SendMessageTimeout ( HWND_BROADCAST, + WM_SETTINGCHANGE, + 0, + (LPARAM) "Environment", + SMTO_ABORTIFHUNG, + 5000, + (PDWORD_PTR)&dwReturnValue ); + if (rc != 1) + printf("%s() SendMessageTimeout() returns %d\n", + __FUNCTION__,rc); + + return 0; +} + diff --git a/branches/WOF2-3/tools/nsc/nsc.rc b/branches/WOF2-3/tools/nsc/nsc.rc new file mode 100644 index 00000000..92df29a5 --- /dev/null +++ b/branches/WOF2-3/tools/nsc/nsc.rc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2007 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#if DBG +#define VER_FILEDESCRIPTION_STR "Broadcast a setting changed message to root windows (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "Broadcast a setting changed message to root windows" +#endif + +#define VER_INTERNALNAME_STR "notifychange.exe" +#define VER_ORIGINALFILENAME_STR "notifychange.exe" + +#include diff --git a/branches/WOF2-3/tools/part_man/dirs b/branches/WOF2-3/tools/part_man/dirs new file mode 100644 index 00000000..389156fd --- /dev/null +++ b/branches/WOF2-3/tools/part_man/dirs @@ -0,0 +1,2 @@ +DIRS=\ + user diff --git a/branches/WOF2-3/tools/part_man/user/SOURCES b/branches/WOF2-3/tools/part_man/user/SOURCES new file mode 100644 index 00000000..1c2a3bc7 --- /dev/null +++ b/branches/WOF2-3/tools/part_man/user/SOURCES @@ -0,0 +1,23 @@ +TARGETNAME=part_man +TARGETPATH=..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE=PROGRAM +UMTYPE=console +USE_MSVCRT=1 + +SOURCES=part_man.c \ + part_man.rc + +INCLUDES=..\..\..\inc;..\..\..\inc\user;..\..\..\core\al + +RCOPTIONS=/I..\..\win\include + +TARGETLIBS= \ +!if $(FREEBUILD) + $(TARGETPATH)\*\complib.lib \ + $(TARGETPATH)\*\ibal.lib +!else + $(TARGETPATH)\*\complibd.lib \ + $(TARGETPATH)\*\ibald.lib +!endif + +MSC_WARNING_LEVEL= /W3 diff --git a/branches/WOF2-3/tools/part_man/user/makefile b/branches/WOF2-3/tools/part_man/user/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-3/tools/part_man/user/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\inc\openib.def diff --git a/branches/WOF2-3/tools/part_man/user/part_man.c b/branches/WOF2-3/tools/part_man/user/part_man.c new file mode 100644 index 00000000..5eda787f --- /dev/null +++ b/branches/WOF2-3/tools/part_man/user/part_man.c @@ -0,0 +1,587 @@ + +#include "stdio.h" +#include "string.h" +#include "stdlib.h" +#include +#include +#include +#include "al_dev.h" + +#define IS_FULL_MEMBER_PKEY(pkey) (0x8000 & (pkey)) + +typedef enum +{ + pkey_show = 0, + pkey_add, + pkey_rem +}Pkey_action; + +/* common query parameters */ +typedef struct _REQUEST_IN +{ + union + { + struct + { + net64_t port_guid; + unsigned short pkey_num; + unsigned __int16 pkeys[MAX_NUM_PKEY]; + Pkey_action action; + }guid_pkey; + }u; +}REQUEST_IN; + +#define DEFAULT_BUFER_SIZE 1024 +static const char IBBUS_SERV_KEY[] = {"SYSTEM\\CurrentControlSet\\Services\\ibbus\\Parameters"}; + +void show_help() +{ + printf("Usage : part_man.exe \n"); +} + +/******************************************************************** +* name : reg_ibbus_pkey_show +* read registry pkey and optionally prints it +* input : show - whether to print +* output: partKey - contains read pkeys, reg_handle +* return: number of characters read +********************************************************************/ +static int reg_ibbus_pkey_show(IN BOOLEAN show,OUT char *partKey, OUT HKEY *reg_handle) +{ + LONG ret; + int retval; + DWORD read_length = DEFAULT_BUFER_SIZE; + const char *sep_group = ";"; + const char *sep_guid_pkey = ":,"; + ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE,IBBUS_SERV_KEY,0,KEY_SET_VALUE | KEY_QUERY_VALUE ,reg_handle); + if (ERROR_SUCCESS != ret) + { + return 0; + } + + do + { + ret = RegQueryValueEx(*reg_handle,"PartitionKey",NULL,NULL,(LPBYTE)partKey,&read_length); + if (ERROR_MORE_DATA == ret) + { + retval = 0; + break; + } + + if (ERROR_SUCCESS != ret) + { + retval = 0; + break; + } + retval = (int)read_length; + if(retval > 4) + { + if(show) + { + char *pkey_group, *pkey_group_next, *pkey_guid, tmp; + int i,j,k; + unsigned short *guid_vstat; + pkey_group = partKey; + while(pkey_group && (*pkey_group != '\0')) + { + pkey_group_next = strstr(pkey_group,sep_group); + if(pkey_group_next) + *pkey_group_next = '\0'; + pkey_guid = strtok(pkey_group,sep_guid_pkey); + i = 0; + while(pkey_guid) + { + if(i == 0) + { + j = 1; + for (k = strlen(pkey_guid) -1; k > 1; k--) + { + if (j%2) + { + tmp = pkey_guid[k -1]; + pkey_guid[k -1] = pkey_guid[k]; + pkey_guid[k] = tmp; + } + printf("%c",pkey_guid[k]); + if ((j%4 == 0) && (k > 2)) + { + printf(":"); + j = 1; + } + else + j++; + } + printf("\t"); + } + else + { + printf("%s\t",pkey_guid); + } + pkey_guid = strtok(NULL,sep_guid_pkey); + if((++i)%5 == 0) + printf("\n\t\t\t"); + } + printf("\n\n"); + if(pkey_group_next) + pkey_group = pkey_group_next + 1; + else + pkey_group = NULL; + } + } + } + else + retval = 0; + } + while(FALSE); + return retval; +} + +static int reg_ibbus_print_pkey() +{ + int result; + char pkeyBuf[DEFAULT_BUFER_SIZE]; + HKEY hreg = NULL; + + result = reg_ibbus_pkey_show(TRUE,(char*)pkeyBuf,&hreg); + if(hreg) + RegCloseKey( hreg ); + + if (result < 4) + { + printf("No configured pkey found\n"); + return 1; + } + return 0; +} + +static int reg_ibbus_pkey_add(const uint16_t *pkeys, uint16_t pkey_num,OUT pkey_array_t *pkey, OUT char **final_reg_string, OUT DWORD *reg_length) +{ + static char partKey[DEFAULT_BUFER_SIZE]; + char tmp[20]; + char *guid_string, *p; + HKEY reg_handle; + LONG ret; + char *tmpbuff = NULL; + int cnt; + int retval = 0; + uint16_t i = 0; + DWORD read_length; + + *final_reg_string = NULL; + read_length = reg_ibbus_pkey_show(FALSE,(char*)partKey,®_handle); + p = NULL; + guid_string = NULL; + if (read_length < 4) + { + /* empty string read, simply write to registry */ + cnt = sprintf(partKey,"0x%I64X:",pkey->port_guid); + } + else + { + /* update the existed registry list */ + sprintf(tmp,"0x%I64X",pkey->port_guid); + guid_string = strstr(partKey,tmp); + if(guid_string) + { + p = strstr(guid_string,";"); + tmpbuff = (char*)malloc(strlen(p) + 1); + if(!tmpbuff) + { + printf("Failed memory allocation\n"); + return 1; + } + /* save the rest of the string */ + strcpy(tmpbuff,p); + cnt = (int)(p - partKey); + } + else + { + sprintf(partKey + strlen(partKey),"%s:",tmp); + cnt = strlen(partKey); + } + } + + for (i = 0 ;i < pkey_num; i++) + { + char *same_pkey; + sprintf(tmp,"0x%04X",pkeys[i]); + if ( guid_string ) + { + same_pkey = strstr(guid_string,tmp); + if( same_pkey && (same_pkey < p) ) + continue; + } + pkey->pkey_array[pkey->pkey_num] = pkeys[i]; + pkey->pkey_num++; + if( (i == 0) && (!guid_string)) + cnt += sprintf(partKey + cnt,"0x%04X",pkeys[i]); + else + cnt += sprintf(partKey + cnt,",0x%04X",pkeys[i]); + } + if(tmpbuff) + { + cnt += sprintf(partKey + cnt,"%s",tmpbuff); + free(tmpbuff); + } + else + cnt += sprintf(partKey + cnt,";\0"); + + if(pkey->pkey_num) + { + *final_reg_string = partKey; + *reg_length = (DWORD)cnt; + } + else + { + printf("Required pkeys already exist\n"); + retval = 1; + } + RegCloseKey( reg_handle ); + return retval; +} + +static int reg_ibbus_pkey_rem(const unsigned __int16 *pkeys, unsigned short pkey_num,OUT pkey_array_t *pkey) +{ + static char partKey[DEFAULT_BUFER_SIZE]; + static char newKey[DEFAULT_BUFER_SIZE] = {'\0'}; + + HKEY reg_handle; + LONG ret; + DWORD read_length; + int converted,cnt; + unsigned __int16 cur_pkey; + int retval = 0; + unsigned short i = 0; + char pkey_sep[] = ","; + char *pfrom, *pto; + char *guid_string; + char tmp[20]; + char *token; + char *pafter = NULL; + boolean_t found2remove; + boolean_t pkey_not_written = TRUE; + + read_length = reg_ibbus_pkey_show(FALSE,(char*)partKey,®_handle); + do + { + if (read_length < 4) + { + /* empty string read, nothing to delete */ + printf("No pkey configured - nothing to remove\n"); + retval = 1; + break; + } + + sprintf(tmp,"0x%I64X\0",pkey->port_guid); + guid_string = strstr(partKey,tmp); + if (! guid_string) + { + printf("No guid configured - nothing to remove\n"); + retval = 1; + break; + } + pfrom = strstr(guid_string,":"); + pto = strstr(guid_string,";"); + if ( (!pfrom) || (!pto)) + { + printf("Error configuration\n"); + retval = 1; + break; + } + + pfrom++; + pafter = (char*)malloc(strlen(pto) + 1); + + if(!pafter) + { + printf("Allocation failed\n"); + retval = 1; + break; + } + _snprintf(newKey,(int)(pfrom - partKey),"%s",partKey); + cnt = (int)(pfrom - partKey); + strcpy(pafter,pto); + pto[0] = '\0'; + strcpy(partKey,pfrom); + token = strtok(partKey,pkey_sep); + while(token) + { + found2remove = FALSE; + converted = sscanf(token,"0x%X",&cur_pkey); + if(!converted || (converted == EOF)) + { + printf("invalid registry format\n"); + retval = 1; + break; + } + + for (i = 0; i < pkey_num; i++) + { + found2remove = (boolean_t)(cur_pkey == pkeys[i]); + if(found2remove) + { + pkey->pkey_array[pkey->pkey_num] = pkeys[i]; + break; + } + } + + if(found2remove) + { + pkey->pkey_num++; + } + else + { + if(pkey_not_written) + { + cnt += sprintf(newKey + cnt,"0x%04X",cur_pkey); + pkey_not_written = FALSE; + } + else + cnt += sprintf(newKey + cnt,",0x%04X",cur_pkey); + } + token = strtok(NULL,pkey_sep); + } + + if(! pkey->pkey_num) + { + /* nothing to delete */ + printf("Nothing to remove\n"); + retval = 1; + break; + } + + if(pkey_not_written) + cnt -= (2 + strlen(tmp)); + + strcpy(newKey + cnt,pafter); + ret = RegSetValueEx(reg_handle,"PartitionKey",0,REG_SZ,(BYTE*)newKey, (DWORD)strlen(newKey)); + if (ERROR_SUCCESS != ret) + { + printf("registry operation failed error = %d\n",GetLastError()); + retval = 1; + break; + } + } + while(FALSE); + if(pafter) + free(pafter); + + RegCloseKey( reg_handle ); + return retval; +} + +static int send_pdo_req(pkey_array_t *pkeys,DWORD iocode) +{ + HANDLE hKernelLib; + DWORD bytesReturned; + + hKernelLib = + CreateFile( + "\\\\.\\ibal", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, // share mode none + NULL, // no security + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL // no template + ); + + if (hKernelLib == INVALID_HANDLE_VALUE) + { + printf("failed to open the kernel device : error = %d\n",GetLastError()); + return 1; + } + + if (! DeviceIoControl(hKernelLib, + iocode, + pkeys,sizeof(pkey_array_t), + NULL,0, + &bytesReturned, + NULL)) + { + DWORD err = GetLastError(); + if (err == 1168) + printf("No matched port guid (0x%I64X) found\n",pkeys->port_guid); + else if (err == 1117) + printf("operation failed - internal driver error\n"); + else if(err == 87) + printf("operation failed - invalid input to driver\n"); + else + printf("operation failed with error %d\n",err); + + CloseHandle(hKernelLib); + return 1; + } + CloseHandle(hKernelLib); + return 0; +} + + +boolean_t reg_pkey_operation(const REQUEST_IN *input) +{ + pkey_array_t pkeys; + HKEY reg_handle; + char *p_reg_string; + DWORD reg_length = 0; + int result; + int i; + LONG ret; + if(!input) + { + printf("invalid input parameter\n"); + return FALSE; + } + + RtlZeroMemory(&pkeys,sizeof(pkeys)); + pkeys.port_guid = input->u.guid_pkey.port_guid; + + if(input->u.guid_pkey.action == pkey_add) + result = reg_ibbus_pkey_add((unsigned __int16*)input->u.guid_pkey.pkeys, input->u.guid_pkey.pkey_num, &pkeys,&p_reg_string,®_length); + else if(input->u.guid_pkey.action == pkey_rem) + result = reg_ibbus_pkey_rem((unsigned __int16*)input->u.guid_pkey.pkeys, input->u.guid_pkey.pkey_num, &pkeys); + else if(input->u.guid_pkey.action == pkey_show) + { + reg_ibbus_print_pkey(); + return TRUE; + } + else + printf("Invalid command to part_man.exe\n"); + + if( 0 != result) + return FALSE; + + if(pkeys.pkey_num) + { + if(input->u.guid_pkey.action == pkey_add) + { + if( 0 == send_pdo_req(&pkeys,UAL_REQ_CREATE_PDO)) + { + ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE,IBBUS_SERV_KEY,0,KEY_SET_VALUE | KEY_QUERY_VALUE ,®_handle); + ret = RegSetValueEx(reg_handle,"PartitionKey",0,REG_SZ,(BYTE*)p_reg_string,reg_length); + RegCloseKey( reg_handle ); + if (ERROR_SUCCESS == ret) + { + return TRUE; + } + else + { + printf("registry operation failed = %d\n",GetLastError()); + } + } + } + else if(input->u.guid_pkey.action == pkey_rem) + { + return (boolean_t)( 0 == send_pdo_req(&pkeys,UAL_REQ_REMOVE_PDO)); + } + } + return FALSE; +} + +int prepare_reg_pkey_input(OUT REQUEST_IN *input,char* cmd[],int num) +{ + int i; + input->u.guid_pkey.pkey_num = 0; + + if(strstr(cmd[1],"add")) + input->u.guid_pkey.action = pkey_add; + else if(strstr(cmd[1],"rem")) + input->u.guid_pkey.action = pkey_rem; + else if(strstr(cmd[1],"show")) + { + input->u.guid_pkey.action = pkey_show; + return 1; + } + else + { + printf("invalid command %s\n",cmd[1]); + return 0; + } + + if(num < 4) + { + printf("invalid command %s\n",cmd[1]); + return 0; + } + + /* vstat output format 0008:f104:0397:7ccc + For port guid add 1 for each port + */ + if (strstr(cmd[2],":")) + { + int i; + unsigned short *guid_vstat; + guid_vstat = (unsigned short*)&input->u.guid_pkey.port_guid; + if (4 == sscanf(cmd[2],"%x:%x:%x:%x",&guid_vstat[0],&guid_vstat[1],&guid_vstat[2],&guid_vstat[3])) + { + for( i = 0; i < 4; i++) + guid_vstat[i] = (guid_vstat[i] << 8) | (guid_vstat[i] >> 8); + } + else + { + goto bad_inp; + } + } + else + { + goto bad_inp; + } + + for( i = 3; i < num; i++) + { + if((strstr(cmd[i],"ffff")) || (strstr(cmd[i],"FFFF"))) + continue; + if (strstr(cmd[i],"0x") || strstr(cmd[i],"0X")) + sscanf(cmd[i],"0x%x",&input->u.guid_pkey.pkeys[input->u.guid_pkey.pkey_num]); + else + sscanf(cmd[i],"%x",&input->u.guid_pkey.pkeys[input->u.guid_pkey.pkey_num]); + + if (! IS_FULL_MEMBER_PKEY(input->u.guid_pkey.pkeys[input->u.guid_pkey.pkey_num])) + { + printf("partial member pkey %s is not suported\n",cmd[i]); + return 0; + } + input->u.guid_pkey.pkey_num++; + } + return 1; +bad_inp: + printf("port guid %s - illegal port guid format, expected xxxx:xxxx:xxxx:xxxx\n",cmd[2]); + return 0; +} + +void partition_operation(char* cmd[],int num) +{ + REQUEST_IN input; + + if (! prepare_reg_pkey_input(&input, cmd, num)) + return; + + if(! reg_pkey_operation(&input)) + printf("Pkey operation failed\n"); + else + printf("Done...\n"); +} + +int32_t __cdecl +main( + int32_t argc, + char* argv[]) +{ + BOOLEAN showHelp = FALSE; + if (argc < 2) + { + showHelp = TRUE; + } + else + { + if(!_stricmp(argv[1], "-h") || !_stricmp(argv[1], "-help")) + { + showHelp = TRUE; + } + else + partition_operation(argv,argc); + } + if (showHelp) + show_help(); +} + + diff --git a/branches/WOF2-3/tools/part_man/user/part_man.rc b/branches/WOF2-3/tools/part_man/user/part_man.rc new file mode 100644 index 00000000..d095f33d --- /dev/null +++ b/branches/WOF2-3/tools/part_man/user/part_man.rc @@ -0,0 +1,15 @@ +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef _DEBUG_ +#define VER_FILEDESCRIPTION_STR "Partition manager application(Debug)" +#else +#define VER_FILEDESCRIPTION_STR "Partition manager application" +#endif + +#define VER_INTERNALNAME_STR "part_man.exe" +#define VER_ORIGINALFILENAME_STR "part_man.exe" + +#include \ No newline at end of file diff --git a/branches/WOF2-3/tools/perftests/dirs b/branches/WOF2-3/tools/perftests/dirs new file mode 100644 index 00000000..389156fd --- /dev/null +++ b/branches/WOF2-3/tools/perftests/dirs @@ -0,0 +1,2 @@ +DIRS=\ + user diff --git a/branches/WOF2-3/tools/perftests/user/README b/branches/WOF2-3/tools/perftests/user/README new file mode 100644 index 00000000..213a6e17 --- /dev/null +++ b/branches/WOF2-3/tools/perftests/user/README @@ -0,0 +1,101 @@ +This directory includes gen2 uverbs microbenchmarks. + +The tests are intended as: + 1) simple, efficient usage examples. + Please see the COPYING file if you intend to copy it literally. + + 2) a useful benchmark + e.g. for HW or SW tuning and/or functional testing. + Please post results/observations to the openib-general mailing + list. See http://openib.org/mailman/listinfo/openib-general + and http://www.openib.org "Contact Us" link for contact details. + + +Testing methodology +------------------- + +- uses CPU cycle counter to get time stamps without context switch. + Some CPU architectures do NOT have such capability. e.g. Intel 80486 + or older PPC. + +- measures round-trip time but reports half of that as one-way latency. + ie. May not be sufficiently accurate for asymetrical configurations. + +- Min/Median/Max result is reported. + The median (vs average) is less sensitive to extreme scores. + Typically the "Max" value is the first value measured. + +- larger samples only marginally help. The default (1000) is pretty good. + Note that an array of cycles_t (typically unsigned long) is allocated + once to collect samples and again to store the difference between them. + Really big sample sizes (e.g. 1 million) might expose other problems + with the program. + +- "-H" option will dump the histogram for additional statistical analysis. + See xgraph, ygraph, r-base (http://www.r-project.org/), pspp, or other + statistical math programs. + +Architectures tested: i686, x86_64, ia64 + + + +Test Descriptions +----------------- + +rdma_lat.c - latency test with RDMA write transactions +rdma_bw.c - streaming BW test with RDMA write transactions + + +The following tests are mainly useful for HW/SW benchmarking. +They are not intended as actual usage examples. +----------------- + +send_lat.c - latency test with send transactions +send_bw.c - BW test with send transactions +write_lat.c - latency test with RDMA write transactions +write_bw.c - BW test with RDMA write transactions +read_lat.c - latency test with RDMA read transactions +read_bw.c - BW test with RDMA read transactions + + +Build Tests +----------- + +"make" to build all tests + + Debian: build-dep on linux-kernel-headers (for asm/timex.h file) + build-dep on libibverbs-dev + depends on libibverbs1 + + +Run Tests +--------- + +Prerequisites: + kernel 2.6 + ib_uverbs (kernel module) matches libibverbs + ("match" means binary compatible, but ideally same SVN rev) + Debian: dpkg -i libibverbs1_0.1.0-1_ia64.deb + +Server: ./ +Client: ./ + + o IMPORTANT: The SAME OPTIONS must be passed to both server and client. + o "--help" will list the available . + o is IPv4 or IPv6 address. + You can use the IPoIB address if you have IPoIB configured. + +You need to be running a Subnet Manager on the switch or one of the nodes +in your fabric. To use the opensm tool for this purpose, run + modprobe ib_umad + opensm & +on one of the nodes + +First load ib_uverbs on both client and server with something like: + modprobe ib_uverbs + +Then (e.g.) "rdma_lat -C" on the server side. +Lastly "rmda_lat -C 10.0.1.31" on the client. + +rmda_lat will exit on both server and client after printing results. + diff --git a/branches/WOF2-3/tools/perftests/user/TODO b/branches/WOF2-3/tools/perftests/user/TODO new file mode 100644 index 00000000..9cd24526 --- /dev/null +++ b/branches/WOF2-3/tools/perftests/user/TODO @@ -0,0 +1 @@ +- support -- option ( like --port ...) diff --git a/branches/WOF2-3/tools/perftests/user/clock_test.c b/branches/WOF2-3/tools/perftests/user/clock_test.c new file mode 100644 index 00000000..3effb469 --- /dev/null +++ b/branches/WOF2-3/tools/perftests/user/clock_test.c @@ -0,0 +1,24 @@ +#include +#include +#include "get_clock.h" + +int main() +{ + double mhz; + mhz = get_cpu_mhz(); + cycles_t c1, c2; + + if (!mhz) { + printf("Unable to calibrate cycles. Exiting.\n"); + return 2; + } + + printf("Type CTRL-C to cancel.\n"); + for(;;) + { + c1 = get_cycles(); + sleep(1); + c2 = get_cycles(); + printf("1 sec = %g usec\n", (c2 - c1) / mhz); + } +} diff --git a/branches/WOF2-3/tools/perftests/user/dirs b/branches/WOF2-3/tools/perftests/user/dirs new file mode 100644 index 00000000..efc41e71 --- /dev/null +++ b/branches/WOF2-3/tools/perftests/user/dirs @@ -0,0 +1,9 @@ +DIRS=\ + send_bw \ + send_lat \ + write_lat \ + write_bw \ + read_lat \ + read_bw + +# write_bw_postlist rdma_lat rdma_bw send_lat write_lat write_bw read_lat read_bwr diff --git a/branches/WOF2-3/tools/perftests/user/get_clock.c b/branches/WOF2-3/tools/perftests/user/get_clock.c new file mode 100644 index 00000000..eceb5152 --- /dev/null +++ b/branches/WOF2-3/tools/perftests/user/get_clock.c @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2005 Mellanox Technologies Ltd. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + * + * Author: Michael S. Tsirkin + */ + +/* #define DEBUG 1 */ +/* #define DEBUG_DATA 1 */ +/* #define GET_CPU_MHZ_FROM_PROC 1 */ + +/* For gettimeofday */ +#define _BSD_SOURCE +#include + +#include +#include +#include "get_clock.h" + +#ifndef DEBUG +#define DEBUG 0 +#endif +#ifndef DEBUG_DATA +#define DEBUG_DATA 0 +#endif + +#define MEASUREMENTS 200 +#define USECSTEP 10 +#define USECSTART 100 + +/* + Use linear regression to calculate cycles per microsecond. + http://en.wikipedia.org/wiki/Linear_regression#Parameter_estimation +*/ +static double sample_get_cpu_mhz(void) +{ + struct timeval tv1, tv2; + cycles_t start; + double sx = 0, sy = 0, sxx = 0, syy = 0, sxy = 0; + double tx, ty; + int i; + + /* Regression: y = a + b x */ + long x[MEASUREMENTS]; + cycles_t y[MEASUREMENTS]; + double a; /* system call overhead in cycles */ + double b; /* cycles per microsecond */ + double r_2; + + for (i = 0; i < MEASUREMENTS; ++i) { + start = get_cycles(); + + if (gettimeofday(&tv1, NULL)) { + fprintf(stderr, "gettimeofday failed.\n"); + return 0; + } + + do { + if (gettimeofday(&tv2, NULL)) { + fprintf(stderr, "gettimeofday failed.\n"); + return 0; + } + } while ((tv2.tv_sec - tv1.tv_sec) * 1000000 + + (tv2.tv_usec - tv1.tv_usec) < USECSTART + i * USECSTEP); + + x[i] = (tv2.tv_sec - tv1.tv_sec) * 1000000 + + tv2.tv_usec - tv1.tv_usec; + y[i] = get_cycles() - start; + if (DEBUG_DATA) + fprintf(stderr, "x=%ld y=%Ld\n", x[i], (long long)y[i]); + } + + for (i = 0; i < MEASUREMENTS; ++i) { + tx = x[i]; + ty = y[i]; + sx += tx; + sy += ty; + sxx += tx * tx; + syy += ty * ty; + sxy += tx * ty; + } + + b = (MEASUREMENTS * sxy - sx * sy) / (MEASUREMENTS * sxx - sx * sx); + a = (sy - b * sx) / MEASUREMENTS; + + if (DEBUG) + fprintf(stderr, "a = %g\n", a); + if (DEBUG) + fprintf(stderr, "b = %g\n", b); + if (DEBUG) + fprintf(stderr, "a / b = %g\n", a / b); + r_2 = (MEASUREMENTS * sxy - sx * sy) * (MEASUREMENTS * sxy - sx * sy) / + (MEASUREMENTS * sxx - sx * sx) / + (MEASUREMENTS * syy - sy * sy); + + if (DEBUG) + fprintf(stderr, "r^2 = %g\n", r_2); + if (r_2 < 0.9) { + fprintf(stderr,"Correlation coefficient r^2: %g < 0.9\n", r_2); + return 0; + } + + return b; +} + +static double proc_get_cpu_mhz(void) +{ + FILE* f; + char buf[256]; + double mhz = 0.0; + + f = fopen("/proc/cpuinfo","r"); + if (!f) + return 0.0; + while(fgets(buf, sizeof(buf), f)) { + double m; + int rc; + rc = sscanf(buf, "cpu MHz : %lf", &m); + if (rc != 1) { /* PPC has a different format */ + rc = sscanf(buf, "clock : %lf", &m); + if (rc != 1) + continue; + } + if (mhz == 0.0) { + mhz = m; + continue; + } + if (mhz != m) { + fprintf(stderr, "Conflicting CPU frequency values" + " detected: %lf != %lf\n", mhz, m); + return 0.0; + } + } + fclose(f); + return mhz; +} + + +double get_cpu_mhz(void) +{ + double sample, proc, delta; + sample = sample_get_cpu_mhz(); + proc = proc_get_cpu_mhz(); + + if (!proc || !sample) + return 0; + + delta = proc > sample ? proc - sample : sample - proc; + if (delta / proc > 0.01) { + fprintf(stderr, "Warning: measured timestamp frequency " + "%g differs from nominal %g MHz\n", + sample, proc); + return sample; + } + return proc; +} diff --git a/branches/WOF2-3/tools/perftests/user/get_clock.h b/branches/WOF2-3/tools/perftests/user/get_clock.h new file mode 100644 index 00000000..d46cb2c2 --- /dev/null +++ b/branches/WOF2-3/tools/perftests/user/get_clock.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2005 Mellanox Technologies Ltd. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + * + * Author: Michael S. Tsirkin + */ + +#ifndef GET_CLOCK_H +#define GET_CLOCK_H + +#include "complib/cl_timer.h" + +typedef uint64_t cycles_t; + +static int __cdecl cycles_compare(const void * aptr, const void * bptr) +{ + const cycles_t *a = aptr; + const cycles_t *b = bptr; + if (*a < *b) return -1; + if (*a > *b) return 1; + return 0; + +} +/* + * When there is an + * odd number of samples, the median is the middle number. + * even number of samples, the median is the mean of the + * two middle numbers. + * + */ +inline cycles_t get_median(int n, cycles_t delta[]) +{ + if (n % 2) + return(delta[n / 2] + delta[n / 2 - 1]) / 2; + else + return delta[n / 2]; +} + + +static inline cycles_t get_cycles() +{ + return cl_get_tick_count(); +} + +static double get_cpu_mhz(void) +{ + return (double)cl_get_tick_freq(); +} + +#endif diff --git a/branches/WOF2-3/tools/perftests/user/getopt.c b/branches/WOF2-3/tools/perftests/user/getopt.c new file mode 100644 index 00000000..485e272a --- /dev/null +++ b/branches/WOF2-3/tools/perftests/user/getopt.c @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include +#include +#include +#include +#include + +#include "getopt.h" + +/* for preventing C4996-warning on deprecated functions like strtok in VS 8.0. */ +#pragma warning(disable : 4996) + +/* Global variables for getopt_long */ +char *optarg; +int optind = 1; +int opterr = 1; +int optopt = '?'; + +static char* get_char_option(const char* optstring,char*const* argv,int argc, int iArg, int* opt_ind,char* opt_p); + +/* * * * * * * * * * */ + +int iArg = 1; + +int getopt(int argc, char *const*argv, const char *optstring) +{ + + char chOpt; + + if (iArg == argc) + { + return (EOF); + } + + if (argv[iArg][0] != '-') + { + /* Does not start with a - - we are done scanning */ + return (EOF); + } + + /*termination of scanning */ + if (!strcmp("--",argv[iArg])) { + return EOF; + } + optarg = get_char_option(optstring,argv,argc,iArg,&optind,&chOpt); + iArg = optind; + return chOpt; +} + +/* * * * * * * * * * */ + +int getopt_long(int argc, char *const*argv, + const char *optstring, + const struct option *longopts, int *longindex) +{ + char chOpt; + char tmp_str[256]; + char* tmp_arg = NULL; + char* tok=NULL; + int i; + char tokens[2] = {'='}; + + if (iArg == argc) + { + return (EOF); + } + + if (argv[iArg][0] != '-') + { + /* Does not start with a - - we are done scanning */ + return (EOF); + } + + /*termination of scanning */ + if (!strcmp("--",argv[iArg])) { + return EOF; + } + + + /* char option : -d 5 */ + if ((argv[iArg][0] == '-') &&(argv[iArg][1] != '-') ) { + optarg = get_char_option(optstring,argv,argc,iArg,&optind,&chOpt); + iArg = optind; + return chOpt; + } + + /* Look for this string in longopts */ + strcpy(tmp_str,&(argv[iArg][2])); + + /*get the option */ + tok = strtok(tmp_str,tokens); + + for (i = 0; longopts[i].name; i++){ + if (strcmp (tok, longopts[i].name) == 0) + { + /* We have a match */ + if (longindex != NULL) *longindex = i; + + if (longopts[i].flag != NULL) { + *(longopts[i].flag) = longopts[i].val; + } + + if (longopts[i].has_arg != no_argument) + { + /*get the argument */ + + if (strchr(argv[iArg],'=') != NULL) + { + optarg = strtok(NULL,tokens); + }else { + /*the next arg in cmd line is the param */ + tmp_arg = argv[iArg+1]; + if (*tmp_arg == '-') { + /*no param is found */ + chOpt = '?'; + if ((longopts[i].has_arg == required_argument) && opterr) + { + fprintf (stderr, "Option %s requires argument\n",tok); + } + + }else { + optarg = tmp_arg; + iArg++; + optind++; + } + } + + }/*longopts */ + + iArg++; + optind++; + if (longopts[i].flag == 0) + return (longopts[i].val); + else return 0; + + }/*end if strcmp */ + } + + return ('?'); +} + +/* * * * * * * * * * * */ + +static char* get_char_option(const char* optstring,char*const* argv,int argc, int iArg, int* opt_ind,char* opt_p) + { + char chOpt; + char* tmp_str; + char* prm = NULL; + + chOpt = argv[iArg][1]; + + + /*non valid argument*/ + if (!isalpha(chOpt)) + { + chOpt = EOF; + goto end; + } + + tmp_str = strchr(optstring, chOpt); + + /*the argument wasn't found in optstring */ + if (tmp_str == NULL){ + chOpt = EOF; + optopt = chOpt; + goto end; + } + + /* don't need argument */ + if (tmp_str[1]!= ':' ) { + goto end; + } + + if (argv[iArg][2] != '\0') + { + // param is attached to option: -po8889 + prm = &(argv[iArg][2]); + goto end; + } + + // must look at next argv for param + /*at the end of arg list */ + if ((iArg)+1 == argc) { + /* no param will be found */ + if (tmp_str[2]== ':' ) { + /* optional argument ::*/ + goto end; + }else{ + chOpt = EOF; + goto end; + } + } + + prm = &(argv[(iArg)+1][0]); + if (*prm == '-' ) + { + // next argv is a new option, so param + // not given for current option + if (tmp_str[2]== ':' ) { + /* optional argument ::*/ + goto end; + } + else + { + chOpt = EOF; + goto end; + } + } + + // next argv is the param + (*opt_ind)++; + + +end: + (*opt_ind)++; + *opt_p = chOpt; + return prm; +} + diff --git a/branches/WOF2-3/tools/perftests/user/getopt.h b/branches/WOF2-3/tools/perftests/user/getopt.h new file mode 100644 index 00000000..20efd5cc --- /dev/null +++ b/branches/WOF2-3/tools/perftests/user/getopt.h @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#ifndef GETOPT_H +#define GETOPT_H + +/* the string argument that came with the option */ +extern char *optarg; + +/* Index in ARGV of the next element to be scanned. + + When `getopt' returns -1, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +extern int optind; + +/* Callers store zero here to inhibit the error message `getopt' prints + for unrecognized options. */ + +extern int opterr; + +/* Set to an option character which was unrecognized. */ +extern int optopt; + +/* Describe the long-named options requested by the application. + The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector + of `struct option' terminated by an element containing a name which is + zero. + + The field `has_arg' is: + no_argument (or 0) if the option does not take an argument, + required_argument (or 1) if the option requires an argument, + optional_argument (or 2) if the option takes an optional argument. + + If the field `flag' is not NULL, it points to a variable that is set + to the value given in the field `val' when the option is found, but + left unchanged if the option is not found. + + To have a long-named option do something other than set an `int' to + a compiled-in constant, such as set a value from `optarg', set the + option's `flag' field to zero and its `val' field to a nonzero + value (the equivalent single-letter option character, if there is + one). For long options that have a zero `flag' field, `getopt' + returns the contents of the `val' field. */ + +struct option +{ + const char *name; + int has_arg; + int *flag; + int val; +}; + +/* Names for the values of the `has_arg' field of `struct option'. */ +#define no_argument 0 +#define required_argument 1 +#define optional_argument 2 + +/* Return the option character from OPTS just read. Return -1 when + there are no more options. For unrecognized options, or options + missing arguments, `optopt' is set to the option letter, and '?' is + returned. + + The OPTS string is a list of characters which are recognized option + letters, optionally followed by colons, specifying that that letter + takes an argument, to be placed in `optarg'. + + If a letter in OPTS is followed by two colons, its argument is + optional. This behavior is specific to the GNU `getopt'. + + The argument `--' causes premature termination of argument + scanning, explicitly telling `getopt' that there are no more + options. + + If OPTS begins with `--', then non-option arguments are treated as + arguments to the option '\0'. This behavior is specific to the GNU + `getopt'. */ + +extern int getopt(int argc, char *const *argv, const char *shortopts); +extern int getopt_long(int argc, char *const*argv, + const char *optstring, + const struct option *longopts, int *longindex); + + +#endif diff --git a/branches/WOF2-3/tools/perftests/user/perf_defs.h b/branches/WOF2-3/tools/perftests/user/perf_defs.h new file mode 100644 index 00000000..e2370544 --- /dev/null +++ b/branches/WOF2-3/tools/perftests/user/perf_defs.h @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2005 Mellanox Technologies Ltd. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + * + * Author: Yossi Leybovich + */ + +#ifndef H_PERF_SOCK_H +#define H_PERF_SOCK_H + + +#include +#include + +#include +#include +#include +#include +#include +#include + + +#include +#include + +#define KEY_MSG_SIZE (sizeof "0000:000000:000000:00000000:0000000000000000") +#define KEY_PRINT_FMT "%04x:%06x:%06x:%08x:%016I64x" +#define KEY_SCAN_FMT "%x:%x:%x:%x:%x" + +#define VERSION 2.0 +#define ALL 1 + +#define RC 0 +#define UC 1 +#define UD 3 + + +#define PINGPONG_SEND_WRID 1 +#define PINGPONG_RECV_WRID 2 +#define PINGPONG_RDMA_WRID 3 + + +#define SIGNAL 1 +#define MAX_INLINE 400 + + +#if 0 +#define PERF_ENTER printf("%s: ===>\n",__FUNCTION__); +#define PERF_EXIT printf("%s: <===\n",__FUNCTION__); +#define PERF_DEBUG printf +#else +#define PERF_ENTER +#define PERF_EXIT +#define PERF_DEBUG // +#endif + +struct pingpong_context { + ib_ca_handle_t context; + ib_ca_handle_t ca; + ib_ca_attr_t *ca_attr; + ib_al_handle_t al; +//PORTED struct ibv_comp_channel *channel; + void* channel; //PORTED REMOVE + ib_pd_handle_t pd; + ib_mr_handle_t mr; + uint32_t rkey; + uint32_t lkey; + ib_cq_handle_t scq; + ib_cq_handle_t rcq; + ib_qp_handle_t *qp; + ib_qp_attr_t *qp_attr; + void *buf; + unsigned size; + int tx_depth; + + ib_local_ds_t list; + ib_local_ds_t recv_list; + ib_send_wr_t wr; + ib_recv_wr_t rwr; + + ib_av_handle_t av; + + volatile char *post_buf; + volatile char *poll_buf; + + int *scnt,*ccnt; + cl_waitobj_handle_t cq_waitobj; +}; + + +struct pingpong_dest { + ib_net16_t lid; + ib_net32_t qpn; + ib_net32_t psn; + uint32_t rkey; + uint64_t vaddr; +}; + + +struct report_options { + int unsorted; + int histogram; + int cycles; /* report delta's in cycles, not microsec's */ +}; + + +static int +pp_write_keys(SOCKET sockfd, const struct pingpong_dest *my_dest); + +static int +pp_read_keys(SOCKET sockfd, struct pingpong_dest *rem_dest); + + SOCKET + pp_client_connect(const char *servername, int port); + +int +pp_client_exch_dest(SOCKET sockfd, const struct pingpong_dest *my_dest, + struct pingpong_dest *rem_dest); + +SOCKET +pp_server_connect(int port); + +int +pp_server_exch_dest(SOCKET sockfd, const struct pingpong_dest *my_dest, + struct pingpong_dest* rem_dest); + +#endif diff --git a/branches/WOF2-3/tools/perftests/user/perf_utils.c b/branches/WOF2-3/tools/perftests/user/perf_utils.c new file mode 100644 index 00000000..e56f5ee7 --- /dev/null +++ b/branches/WOF2-3/tools/perftests/user/perf_utils.c @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2004-2005 Mellanox Technologies, Inc. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Version: $Id$ + */ + +#include "perf_defs.h" + +const char *sock_get_error_str(void) +{ + switch (WSAGetLastError()) { + case WSANOTINITIALISED: + return "WSANOTINITIALISED"; /* A successful WSAStartup call must occur before using this function */ + case WSAENETDOWN: + return "WSAENETDOWN"; /* The network subsystem has failed */ + case WSAEFAULT: + return "WSAEFAULT"; /* The buf parameter is not completely contained in a valid part of the user address space */ + case WSAENOTCONN: + return "WSAENOTCONN"; /* The socket is not connected */ + case WSAEINTR: + return "WSAEINTR"; /* The (blocking) call was canceled through WSACancelBlockingCall */ + case WSAEINPROGRESS: + return "WSAEINPROGRESS"; /* A blocking Windows Sockets 1.1 call is in progress, or the service provider is still processing a callback function */ + case WSAENETRESET: + return "WSAENETRESET"; /* The connection has been broken due to the keep-alive activity detecting a failure while the operation was in progress */ + case WSAENOTSOCK: + return "WSAENOTSOCK"; /* The descriptor is not a socket */ + case WSAEOPNOTSUPP: + return "WSAEOPNOTSUPP"; /* MSG_OOB was specified, but the socket is not stream-style such as type SOCK_STREAM, OOB data is not supported in the communication domain associated with this socket, or the socket is unidirectional and supports only send operations */ + case WSAESHUTDOWN: + return "WSAESHUTDOWN"; /* The socket has been shut down; it is not possible to receive on a socket after shutdown has been invoked with how set to SD_RECEIVE or SD_BOTH */ + case WSAEWOULDBLOCK: + return "WSAEWOULDBLOCK"; /* The socket is marked as nonblocking and the receive operation would block */ + case WSAEMSGSIZE: + return "WSAEMSGSIZE"; /* The message was too large to fit into the specified buffer and was truncated */ + case WSAEINVAL: + return "WSAEINVAL"; /* The socket has not been bound with bind, or an unknown flag was specified, or MSG_OOB was specified for a socket with SO_OOBINLINE enabled or (for byte stream sockets only) len was zero or negative */ + case WSAECONNABORTED: + return "WSAECONNABORTED"; /* The virtual circuit was terminated due to a time-out or other failure. The application should close the socket as it is no longer usable */ + case WSAETIMEDOUT: + return "WSAETIMEDOUT"; /* The connection has been dropped because of a network failure or because the peer system failed to respond */ + case WSAECONNRESET: + return "WSAECONNRESET"; /* The virtual circuit was reset by the remote side executing a hard or abortive close. The application should close the socket as it is no longer usable. On a UPD-datagram socket this error would indicate that a previous send operation resulted in an ICMP "Port Unreachable" message */ + default: + return "Unknown error"; + } +} + +static int pp_write_keys(SOCKET sockfd, const struct pingpong_dest *my_dest) +{ + char msg[KEY_MSG_SIZE]; + PERF_ENTER; + sprintf(msg, KEY_PRINT_FMT,cl_hton16(my_dest->lid), cl_hton32(my_dest->qpn), + cl_hton32(my_dest->psn), cl_hton32(my_dest->rkey), my_dest->vaddr); + + if (send(sockfd, msg, sizeof msg,0) != sizeof msg) { + perror("pp_write_keys"); + fprintf(stderr, "Couldn't send local address %s\n",sock_get_error_str()); + return -1; + } + PERF_EXIT; + return 0; +} + +static int pp_read_keys(SOCKET sockfd, + struct pingpong_dest *rem_dest) +{ + int parsed; + + char msg[KEY_MSG_SIZE]; + PERF_ENTER; + if (recv(sockfd, msg, sizeof msg, 0) != sizeof msg) { + perror("pp_read_keys"); + fprintf(stderr, "Couldn't read remote address %s\n",sock_get_error_str()); + return -1; + } + + parsed = sscanf(msg, KEY_PRINT_FMT, &rem_dest->lid, &rem_dest->qpn, + &rem_dest->psn,&rem_dest->rkey, &rem_dest->vaddr); + rem_dest->lid = cl_ntoh16(rem_dest->lid); + rem_dest->qpn = cl_ntoh32(rem_dest->qpn); + rem_dest->psn = cl_ntoh32(rem_dest->psn); + rem_dest->rkey = cl_ntoh32(rem_dest->rkey); + + if (parsed != 5) { + fprintf(stderr, "Couldn't parse line <%.*s > parsed = %d %s\n", + (int)sizeof msg, msg,parsed,sock_get_error_str()); + return -1; + } + rem_dest->vaddr = (uintptr_t) rem_dest->vaddr; + PERF_EXIT; + return 0; +} + +SOCKET pp_client_connect(const char *servername, int port) +{ + struct addrinfo *res, *t; + struct addrinfo hints = { + 0, //ai_flags + AF_UNSPEC, // ai_family + SOCK_STREAM //ai_socktype + }; + char service[8]; + int n; + SOCKET sockfd = INVALID_SOCKET; + PERF_ENTER; + sprintf(service, "%d", port); + n = getaddrinfo(servername, service, &hints, &res); + + if (n) { + fprintf(stderr, "%s for %s:%d\n", sock_get_error_str(), servername, port); + return sockfd; + } + + for (t = res; t; t = t->ai_next) { + if (t->ai_family != AF_INET) + continue; + sockfd = socket(t->ai_family, t->ai_socktype, t->ai_protocol); + if (sockfd != INVALID_SOCKET) { + if (!connect(sockfd, t->ai_addr, t->ai_addrlen)) + break; + closesocket(sockfd); + sockfd = INVALID_SOCKET; + } + } + + freeaddrinfo(res); + + if (sockfd == INVALID_SOCKET) { + fprintf(stderr, "Couldn't connect to %s:%d\n", servername, port); + return sockfd; + } + PERF_EXIT; + return sockfd; +} + +int pp_client_exch_dest(SOCKET sockfd, const struct pingpong_dest *my_dest, + struct pingpong_dest *rem_dest) +{ + PERF_ENTER; + if (pp_write_keys(sockfd, my_dest)) + return -1; + PERF_EXIT; + return pp_read_keys(sockfd,rem_dest); +} + +SOCKET pp_server_connect(int port) +{ + struct addrinfo *res, *t; + struct addrinfo hints = { + AI_PASSIVE, //ai_flags + AF_UNSPEC, // ai_family + SOCK_STREAM //ai_socktype + }; + char service[8]; + SOCKET sockfd = INVALID_SOCKET, connfd; + int n; + PERF_ENTER; + sprintf(service, "%d", port); + n = getaddrinfo(NULL, service, &hints, &res); + + if (n) { + fprintf(stderr, "%s for port %d\n", sock_get_error_str(), port); + return n; + } + + for (t = res; t; t = t->ai_next) { + if (t->ai_family != AF_INET) + continue; + sockfd = socket(t->ai_family, t->ai_socktype, t->ai_protocol); + if (sockfd != INVALID_SOCKET) { + n = 1; + + setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&n, sizeof n); + + if (!bind(sockfd, t->ai_addr, t->ai_addrlen)) + break; + closesocket(sockfd); + sockfd = INVALID_SOCKET; + } + } + + freeaddrinfo(res); + + if (sockfd == INVALID_SOCKET) { + fprintf(stderr, "Couldn't listen to port %d\n", port); + return sockfd; + } + + listen(sockfd, 1); + connfd = accept(sockfd, NULL, 0); + if (connfd == INVALID_SOCKET) { + perror("server accept"); + fprintf(stderr, "accept() failed\n"); + closesocket(sockfd); + return connfd; + } + + closesocket(sockfd); + PERF_EXIT; + return connfd; +} + +int pp_server_exch_dest(SOCKET sockfd, const struct pingpong_dest *my_dest, + struct pingpong_dest* rem_dest) +{ + PERF_ENTER; + if (pp_read_keys(sockfd, rem_dest)) + return -1; + + PERF_EXIT; + return pp_write_keys(sockfd, my_dest); +} + + + + + + + diff --git a/branches/WOF2-3/tools/perftests/user/read_bw/SOURCES b/branches/WOF2-3/tools/perftests/user/read_bw/SOURCES new file mode 100644 index 00000000..3edb8ece --- /dev/null +++ b/branches/WOF2-3/tools/perftests/user/read_bw/SOURCES @@ -0,0 +1,28 @@ +TARGETNAME=ib_read_bw +TARGETPATH=..\..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE=PROGRAM +UMTYPE=console +USE_MSVCRT=1 + +C_DEFINES=$(C_DEFINES) /D__WIN__ + +SOURCES=read_bw.rc \ + ..\getopt.c \ + ..\perf_utils.c \ + read_bw.c + +INCLUDES=..;..\..\..\..\inc;..\..\..\..\inc\user + +RCOPTIONS=/I..\..\win\include + +TARGETLIBS= \ + $(DDK_LIB_PATH)\Ws2_32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\complib.lib \ + $(TARGETPATH)\*\ibal.lib +!else + $(TARGETPATH)\*\complibd.lib \ + $(TARGETPATH)\*\ibald.lib +!endif + +MSC_WARNING_LEVEL= /W3 diff --git a/branches/WOF2-3/tools/perftests/user/read_bw/makefile b/branches/WOF2-3/tools/perftests/user/read_bw/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-3/tools/perftests/user/read_bw/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\..\inc\openib.def diff --git a/branches/WOF2-3/tools/perftests/user/read_bw/read_bw.c b/branches/WOF2-3/tools/perftests/user/read_bw/read_bw.c new file mode 100644 index 00000000..b0c4d2bc --- /dev/null +++ b/branches/WOF2-3/tools/perftests/user/read_bw/read_bw.c @@ -0,0 +1,788 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies Ltd. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: read_bw.c 2292 2008-04-02 14:27:02Z xalex $ + */ + +#include "getopt.h" +#include "perf_defs.h" +#include "get_clock.h" + +struct user_parameters { + const char *servername; + int connection_type; + int mtu; + int all; /* run all msg size */ + int iters; + int tx_depth; + int max_out_read; +}; + +static int page_size; + +cycles_t *tposted; +cycles_t *tcompleted; + + +void +pp_cq_comp_cb( + IN const ib_cq_handle_t h_cq, + IN void *cq_context ) +{ + UNUSED_PARAM( h_cq ); + UNUSED_PARAM( cq_context); + return ; +} + +static struct pingpong_context *pp_init_ctx(unsigned size,int port, struct user_parameters *user_parm) +{ + + struct pingpong_context *ctx; + ib_api_status_t ib_status = IB_SUCCESS; + size_t guid_count; + ib_net64_t *ca_guid_array; + + + ctx = malloc(sizeof *ctx); + if (!ctx){ + perror("malloc"); + return NULL; + } + + memset(ctx, 0, sizeof(struct pingpong_context)); + ctx->size = size; + ctx->tx_depth = user_parm->tx_depth; + + ctx->qp = malloc(sizeof (ib_qp_handle_t)); + if (!ctx->qp) { + perror("malloc"); + return NULL; + } + + ctx->qp_attr = malloc(sizeof (ib_qp_attr_t)); + if (!ctx->qp_attr) { + perror("malloc"); + return NULL; + } + + ctx->buf = malloc( size * 2 ); + if (!ctx->buf) { + fprintf(stderr, "Couldn't allocate work buf.\n"); + return NULL; + } + + memset(ctx->buf, 0, size * 2 ); + + + /* + * Open the AL instance + */ + ib_status = ib_open_al(&ctx->al); + if(ib_status != IB_SUCCESS) + { + fprintf(stderr,"ib_open_al failed status = %d\n", ib_status); + return NULL; + } + + /* + * Get the Local CA Guids + */ + ib_status = ib_get_ca_guids(ctx->al, NULL, &guid_count); + if(ib_status != IB_INSUFFICIENT_MEMORY) + { + fprintf(stderr,"ib_get_ca_guids1 failed status = %d\n", (uint32_t)ib_status); + return NULL; + } + + /* + * If no CA's Present then return + */ + + if(guid_count == 0) + return NULL; + + + ca_guid_array = (ib_net64_t*)malloc(sizeof(ib_net64_t) * guid_count); + + ib_status = ib_get_ca_guids(ctx->al, ca_guid_array, &guid_count); + if(ib_status != IB_SUCCESS) + { + fprintf(stderr,"ib_get_ca_guids2 failed with status = %d\n", ib_status); + return NULL; + } + + /* + * Open only the first HCA + */ + /* Open the CA */ + ib_status = ib_open_ca(ctx->al ,ca_guid_array[0] ,NULL, + NULL, //ca_context + &ctx->ca); + + if(ib_status != IB_SUCCESS) + { + fprintf(stderr,"ib_open_ca failed with status = %d\n", ib_status); + return NULL; + } + + //xxx + //printf("ib_open_ca passed i=%d\n",i); + //xxx + + + + { + /* Query the CA */ + uint32_t bsize = 0; + ib_status = ib_query_ca(ctx->ca, NULL, &bsize); + if(ib_status != IB_INSUFFICIENT_MEMORY) + { + fprintf(stderr, "Failed to query device props"); + return NULL; + } + + ctx->ca_attr = (ib_ca_attr_t *)malloc(bsize); + + ib_status = ib_query_ca(ctx->ca, ctx->ca_attr, &bsize); + if(ib_status != IB_SUCCESS) + { + printf("ib_query_ca failed with status = %d\n", ib_status); + return NULL; + } + if (user_parm->mtu == 0) {/*user did not ask for specific mtu */ + if (ctx->ca_attr->dev_id == 23108) { + user_parm->mtu = 1024; + } else { + user_parm->mtu = 2048; + } + } + } + + ib_status = ib_alloc_pd(ctx->ca , + IB_PDT_NORMAL, + ctx, //pd_context + &ctx->pd); + if (ib_status != IB_SUCCESS) { + fprintf(stderr, "Couldn't allocate PD\n"); + return NULL; + } + + + /* We dont really want IBV_ACCESS_LOCAL_WRITE, but IB spec says: + * The Consumer is not allowed to assign Remote Write or Remote Atomic to + * a Memory Region that has not been assigned Local Write. */ + + + { + ib_mr_create_t mr_create; + + mr_create.length = size * 2; + + mr_create.vaddr = ctx->buf; + mr_create.access_ctrl = IB_AC_RDMA_WRITE| IB_AC_LOCAL_WRITE|IB_AC_RDMA_READ; + + ib_status = ib_reg_mem(ctx->pd ,&mr_create ,&ctx->lkey ,&ctx->rkey ,&ctx->mr); + if (ib_status != IB_SUCCESS) { + fprintf(stderr, "Couldn't allocate MR\n"); + return NULL; + } + } + + { + ib_cq_create_t cq_create; + + cq_create.size = user_parm->tx_depth; + cq_create.h_wait_obj = NULL; + cq_create.pfn_comp_cb = pp_cq_comp_cb; + ib_status = ib_create_cq(ctx->ca,&cq_create ,ctx, NULL, &ctx->scq); + if (ib_status != IB_SUCCESS) { + fprintf(stderr, "Couldn't create CQ ib_status = %d\n",ib_status); + return NULL; + } + } + + { + + ib_qp_create_t qp_create; + ib_qp_mod_t qp_modify; + ib_qp_attr_t qp_attr; + + memset(&qp_create, 0, sizeof(ib_qp_create_t)); + qp_create.h_sq_cq = ctx->scq; + qp_create.h_rq_cq = ctx->scq; + qp_create.sq_depth = user_parm->tx_depth; + qp_create.rq_depth = user_parm->tx_depth; + qp_create.sq_sge = 1; + qp_create.rq_sge = 1; + //TODO MAX_INLINE + qp_create.qp_type= IB_QPT_RELIABLE_CONN; + qp_create.sq_signaled = FALSE; + /*attr.sq_sig_all = 0;*/ + + ib_status = ib_create_qp(ctx->pd, &qp_create,NULL,NULL,&ctx->qp[0]); + if (ib_status != IB_SUCCESS){ + fprintf(stderr, "Couldn't create QP\n"); + return NULL; + } + + + + + memset(&qp_modify, 0, sizeof(ib_qp_mod_t)); + qp_modify.req_state = IB_QPS_INIT; + qp_modify.state.init.pkey_index = 0 ; + qp_modify.state.init.primary_port = (uint8_t)port; + qp_modify.state.init.access_ctrl = IB_AC_RDMA_WRITE | IB_AC_LOCAL_WRITE|IB_AC_RDMA_READ; + + + ib_status = ib_modify_qp(ctx->qp[0], &qp_modify); + if (ib_status != IB_SUCCESS){ + fprintf(stderr, "Failed to modify QP to INIT\n"); + return NULL; + } + + memset(&qp_attr, 0, sizeof(ib_qp_attr_t)); + ib_status = ib_query_qp(ctx->qp[0],&ctx->qp_attr[0]); + if (ib_status != IB_SUCCESS){ + fprintf(stderr, "Failed to modify QP to INIT\n"); + return NULL; + } + fprintf(stderr, "max inline size %d\n",ctx->qp_attr[0].sq_max_inline); + } + return ctx; +} + + + + + +static int pp_connect_ctx(struct pingpong_context *ctx, int port, int my_psn, + struct pingpong_dest *dest, struct user_parameters *user_parm,int qpindex) +{ + + ib_api_status_t ib_status; + ib_qp_mod_t attr; + memset(&attr, 0, sizeof(ib_qp_mod_t)); + + attr.req_state = IB_QPS_RTR; + switch (user_parm->mtu) { + case 256 : + attr.state.rtr.primary_av.conn.path_mtu = IB_MTU_LEN_256; + break; + case 512 : + attr.state.rtr.primary_av.conn.path_mtu = IB_MTU_LEN_512; + break; + case 1024 : + attr.state.rtr.primary_av.conn.path_mtu = IB_MTU_LEN_1024; + break; + case 2048 : + attr.state.rtr.primary_av.conn.path_mtu = IB_MTU_LEN_2048; + break; + } + printf("Mtu : %d\n", user_parm->mtu); + attr.state.rtr.dest_qp = dest->qpn;; + attr.state.rtr.rq_psn = dest->psn; + attr.state.rtr.resp_res = (uint8_t)user_parm->max_out_read; + attr.state.rtr.rnr_nak_timeout = 12; + attr.state.rtr.primary_av.grh_valid = 0; + attr.state.rtr.primary_av.dlid = dest->lid; + attr.state.rtr.primary_av.sl = 0; + attr.state.rtr.primary_av.path_bits = 0; + attr.state.rtr.primary_av.port_num = (uint8_t)port; + attr.state.rtr.primary_av.static_rate = IB_PATH_RECORD_RATE_10_GBS; + attr.state.rtr.opts = IB_MOD_QP_LOCAL_ACK_TIMEOUT | + IB_MOD_QP_RESP_RES | + IB_MOD_QP_PRIMARY_AV; + + + ib_status = ib_modify_qp(ctx->qp[0], &attr); + if(ib_status != IB_SUCCESS){ + fprintf(stderr, "Failed to modify QP to RTR\n"); + return 1; + } + + + + memset(&attr, 0, sizeof(ib_qp_mod_t)); + attr.req_state = IB_QPS_RTS; + attr.state.rts.sq_psn = my_psn; + attr.state.rts.init_depth = (uint8_t)user_parm->max_out_read; + attr.state.rts.local_ack_timeout = 14; + attr.state.rts.retry_cnt = 7; + attr.state.rts.rnr_retry_cnt = 7; + attr.state.rts.opts = IB_MOD_QP_RNR_RETRY_CNT | + IB_MOD_QP_RETRY_CNT | + IB_MOD_QP_INIT_DEPTH | + IB_MOD_QP_LOCAL_ACK_TIMEOUT; + + ib_status = ib_modify_qp(ctx->qp[0], &attr); + if(ib_status != IB_SUCCESS){ + fprintf(stderr, "Failed to modify QP to RTS\n"); + return 1; + } + return 0; +} + + +static SOCKET pp_open_port(struct pingpong_context *ctx, const char * servername, + int ib_port, int port, struct pingpong_dest **p_my_dest, + struct pingpong_dest **p_rem_dest,struct user_parameters *user_parm) +{ + struct pingpong_dest *my_dest; + struct pingpong_dest *rem_dest; + SOCKET sockfd; + int rc; + int i; + int numofqps = 1; + + /* Create connection between client and server. + * We do it by exchanging data over a TCP socket connection. */ + + + my_dest = malloc( sizeof (struct pingpong_dest) * numofqps ); + if (!my_dest){ + perror("malloc"); + return INVALID_SOCKET; + } + memset( my_dest, 0, sizeof (struct pingpong_dest) * numofqps ); + + rem_dest = malloc(sizeof (struct pingpong_dest) * numofqps ); + if (!rem_dest){ + perror("malloc"); + return INVALID_SOCKET; + } + memset( rem_dest, 0, sizeof (struct pingpong_dest) * numofqps ); + + sockfd = servername ? pp_client_connect(servername, port) : + pp_server_connect(port); + + if (sockfd == INVALID_SOCKET) { + printf("pp_connect_sock(%s,%d) failed (%d)!\n", + servername, port, sockfd); + return INVALID_SOCKET; + } + + + for (i =0 ;ica_attr->p_port_attr[ib_port-1].lid; + my_dest[i].psn = cl_hton32(rand() & 0xffffff); + if (!my_dest[i].lid) { + fprintf(stderr, "Local lid 0x0 detected. Is an SM running?\n"); + return 1; + } + my_dest[i].qpn = ctx->qp_attr[i].num; + /* TBD this should be changed inot VA and different key to each qp */ + my_dest[i].rkey = ctx->rkey; + my_dest[i].vaddr = (uintptr_t)ctx->buf + ctx->size; + + printf(" local address: LID %#04x, QPN %#06x, PSN %#06x, " + "RKey %#08x VAddr %#016Lx\n", + my_dest[i].lid, my_dest[i].qpn, my_dest[i].psn, + my_dest[i].rkey, my_dest[i].vaddr); + + rc = servername ? pp_client_exch_dest(sockfd, &my_dest[i],&rem_dest[i]): + pp_server_exch_dest(sockfd, &my_dest[i],&rem_dest[i]); + if (rc) + return INVALID_SOCKET; + printf(" remote address: LID %#04x, QPN %#06x, PSN %#06x, " + "RKey %#08x VAddr %#016Lx\n", + rem_dest[i].lid, rem_dest[i].qpn, rem_dest[i].psn, + rem_dest[i].rkey, rem_dest[i].vaddr); + + if (pp_connect_ctx(ctx, ib_port, my_dest[i].psn, &rem_dest[i], user_parm,i)) + return INVALID_SOCKET; + /* An additional handshake is required *after* moving qp to RTR. + Arbitrarily reuse exch_dest for this purpose. */ + rc = servername ? pp_client_exch_dest(sockfd, &my_dest[i],&rem_dest[i]): + pp_server_exch_dest(sockfd, &my_dest[i],&rem_dest[i]); + if (rc) + return INVALID_SOCKET; + } + *p_rem_dest = rem_dest; + *p_my_dest = my_dest; + return sockfd; +} + +static void usage(const char *argv0) +{ + printf("Usage:\n"); + printf(" %s start a server and wait for connection\n", argv0); + printf(" %s connect to server at \n", argv0); + printf("\n"); + printf("Options:\n"); + printf(" -p, --port= listen on/connect to port (default 18515)\n"); + printf(" -i, --ib-port= use port of IB device (default 1)\n"); + printf(" -m, --mtu= mtu size (default 1024)\n"); + printf(" -o, --outs= num of outstanding read/atom(default 4)\n"); + printf(" -s, --size= size of message to exchange (default 65536)\n"); + printf(" -a, --all Run sizes from 2 till 2^23\n"); + printf(" -t, --tx-depth= size of tx queue (default 100)\n"); + printf(" -n, --iters= number of exchanges (at least 2, default 1000)\n"); + printf(" -b, --bidirectional measure bidirectional bandwidth (default unidirectional)\n"); + printf(" -V, --version display version number\n"); +} + +static void print_report(unsigned int iters, unsigned size, int duplex, + cycles_t *tposted, cycles_t *tcompleted) +{ + double cycles_to_units; + uint64_t tsize; /* Transferred size, in megabytes */ + unsigned int i, j; + int opt_posted = 0, opt_completed = 0; + cycles_t opt_delta; + cycles_t t; + + + opt_delta = tcompleted[opt_posted] - tposted[opt_completed]; + + /* Find the peak bandwidth */ + for (i = 0; i < iters; ++i) + for (j = i; j < iters; ++j) { + t = (tcompleted[j] - tposted[i]) / (j - i + 1); + if (t < opt_delta) { + opt_delta = t; + opt_posted = i; + opt_completed = j; + } + } + + cycles_to_units = get_cpu_mhz() ; + + tsize = duplex ? 2 : 1; + tsize = tsize * size; + printf("%7d %d %7.2f %7.2f\n", + size,iters,tsize * cycles_to_units / opt_delta / 0x100000, + (uint64_t)tsize * iters * cycles_to_units /(tcompleted[iters - 1] - tposted[0]) / 0x100000); +} + + + +int run_iter(struct pingpong_context *ctx, struct user_parameters *user_param, + struct pingpong_dest *rem_dest, int size) +{ + ib_api_status_t ib_status; + int scnt, ccnt ; + ib_send_wr_t *bad_wr; + + ctx->list.vaddr = (uintptr_t) ctx->buf; + ctx->list.length = size; + ctx->list.lkey = ctx->lkey; + ctx->wr.remote_ops.vaddr = rem_dest->vaddr; + ctx->wr.remote_ops.rkey = rem_dest->rkey; + ctx->wr.wr_id = PINGPONG_RDMA_WRID; + ctx->wr.ds_array = &ctx->list; + ctx->wr.num_ds = 1; + ctx->wr.wr_type = WR_RDMA_READ; + ctx->wr.send_opt = IB_SEND_OPT_SIGNALED; + ctx->wr.p_next = NULL; + + scnt = 0; + ccnt = 0; + + /* Done with setup. Start the test. */ + while (scnt < user_param->iters || ccnt < user_param->iters) { + + while (scnt < user_param->iters && (scnt - ccnt) < user_param->tx_depth ) { + + tposted[scnt] = get_cycles(); + ib_status = ib_post_send(ctx->qp[0], &ctx->wr, &bad_wr); + if (ib_status != IB_SUCCESS) + { + fprintf(stderr, "Couldn't post send: scnt %d ccnt %d\n",scnt,ccnt); + return 1; + } + ++scnt; + PERF_DEBUG("scnt = %d \n",scnt); + + } + + if (ccnt < user_param->iters) + { + ib_wc_t wc; + ib_wc_t *p_wc_done,*p_wc_free; + + p_wc_free = &wc; + p_wc_done = NULL; + p_wc_free->p_next = NULL; + + + do { + ib_status = ib_poll_cq(ctx->scq, &p_wc_free, &p_wc_done); + if (ib_status == IB_SUCCESS) { + tcompleted[ccnt] = get_cycles(); + if (p_wc_done->status != IB_WCS_SUCCESS) { + fprintf(stderr, "Completion wth error at %s:\n", + user_param->servername ? "client" : "server"); + fprintf(stderr, "Failed status %d: wr_id %d syndrom 0x%x\n", + p_wc_done->status, (int) p_wc_done->wr_id, p_wc_done->vendor_specific); + return 1; + } + + /*here the id is the index to the qp num */ + ++ccnt; + PERF_DEBUG("ccnt = %d \n",ccnt); + p_wc_free = p_wc_done; + p_wc_free->p_next = NULL; + p_wc_done = NULL; + } + + + } while (ib_status == IB_SUCCESS); + + if (ib_status != IB_NOT_FOUND) { + fprintf(stderr, "Poll Receive CQ failed %d\n", ib_status); + return 12; + } + + } + } + + return(0); +} + +int __cdecl main(int argc, char *argv[]) +{ + struct pingpong_context *ctx; + struct pingpong_dest *my_dest; + struct pingpong_dest *rem_dest; + struct user_parameters user_param; + char *ib_devname = NULL; + int port = 18515; + int ib_port = 1; + unsigned size = 65536; + SOCKET sockfd = INVALID_SOCKET; + WSADATA wsaData; + int iResult; + int i = 0; + int duplex = 0; + + /* init default values to user's parameters */ + memset(&user_param, 0, sizeof(struct user_parameters)); + user_param.mtu = 0; /* signal choose default by device */ + user_param.iters = 1000; + user_param.tx_depth = 100; + user_param.servername = NULL; + user_param.connection_type = RC; + user_param.max_out_read = 4; /* the device capability on gen2 */ + /* Parameter parsing. */ + while (1) { + int c; + + static struct option long_options[] = { + { "port", 1, NULL, 'p' }, + { "ib-dev", 1, NULL, 'd' }, + { "ib-port", 1, NULL, 'i' }, + { "mtu", 1, NULL, 'm' }, + { "outs", 1, NULL, 'o' }, + { "size", 1, NULL, 's' }, + { "iters", 1, NULL, 'n' }, + { "tx-depth", 1, NULL, 't' }, + { "all", 0, NULL, 'a' }, + { "bidirectional", 0, NULL, 'b' }, + { "version", 0, NULL, 'V' }, + { 0 } + }; + c = getopt_long(argc, argv, "p:d:i:m:o:s:n:t:ba", long_options, NULL); + if (c == -1) + break; + + switch (c) { + case 'p': + port = strtol(optarg, NULL, 0); + if (port < 0 || port > 65535) { + usage(argv[0]); + return 1; + } + break; + + case 'd': + ib_devname = _strdup(optarg); + break; + case 'm': + user_param.mtu = strtol(optarg, NULL, 0); + break; + case 'o': + user_param.max_out_read = strtol(optarg, NULL, 0); + break; + case 'a': + user_param.all = ALL; + break; + case 'V': + printf("read_bw version : %.2f\n",VERSION); + return 0; + break; + case 'i': + ib_port = strtol(optarg, NULL, 0); + if (ib_port < 0) { + usage(argv[0]); + return 1; + } + break; + + case 's': + size = strtol(optarg, NULL, 0); + if (size < 1 || size > UINT_MAX / 2) { + usage(argv[0]); + return 1; + } + break; + + case 't': + user_param.tx_depth = strtol(optarg, NULL, 0); + if (user_param.tx_depth < 1) { usage(argv[0]); return 1; } + break; + + case 'n': + user_param.iters = strtol(optarg, NULL, 0); + if (user_param.iters < 2) { + usage(argv[0]); + return 1; + } + + break; + + case 'b': + duplex = 1; + break; + + default: + usage(argv[0]); + return 1; + } + } + + if (optind == argc - 1) + user_param.servername = _strdup(argv[optind]); + else if (optind < argc) { + usage(argv[0]); + return 6; + } + printf("------------------------------------------------------------------\n"); + if (duplex == 1) { + printf(" RDMA_Read Bidirectional BW Test\n"); + } else { + printf(" RDMA_Read BW Test\n"); + } + printf("Connection type : RC\n"); + /* Done with parameter parsing. Perform setup. */ + + // Initialize Winsock + iResult = WSAStartup(MAKEWORD(2,2), &wsaData); + if (iResult != NO_ERROR) { + printf("Error at WSAStartup()\n"); + return 1; + } + + + if (user_param.all == ALL) { + /*since we run all sizes */ + size = 8388608; /*2^23 */ + } + + srand(GetCurrentProcessId() * GetTickCount()); + + //TODO: get pagesize from sysinfo + page_size = 4096; + + //TODO:get the device names + + + ctx = pp_init_ctx(size,ib_port, &user_param); + if (!ctx) + return 8; + + + sockfd = pp_open_port(ctx, user_param.servername, ib_port, port,&my_dest,&rem_dest,&user_param); + if (sockfd == INVALID_SOCKET) + return 9; + + + printf("------------------------------------------------------------------\n"); + printf(" #bytes #iterations BW peak[MB/sec] BW average[MB/sec] \n"); + /* For half duplex tests, server just waits for client to exit */ + /* use dummy my_dest struct*/ + if (!user_param.servername && !duplex) { + pp_server_exch_dest(sockfd, my_dest,rem_dest); + send(sockfd, "done", sizeof "done",0); + closesocket(sockfd); + return 0; + } + + tposted = malloc(user_param.iters * sizeof *tposted); + + if (!tposted) { + perror("malloc"); + return 1; + } + + tcompleted = malloc(user_param.iters * sizeof *tcompleted); + + if (!tcompleted) { + perror("malloc"); + return 1; + } + + + + if (user_param.all == ALL) { + for (i = 1; i < 24 ; ++i) { + size = 1 << i; + if(run_iter(ctx, &user_param, rem_dest, size)) + return 17; + print_report(user_param.iters, size, duplex, tposted, tcompleted); + } + } else { + if(run_iter(ctx, &user_param, rem_dest, size)) + return 18; + print_report(user_param.iters, size, duplex, tposted, tcompleted); + } + + if (user_param.servername) { + pp_client_exch_dest(sockfd, my_dest,rem_dest); + } else { + pp_server_exch_dest(sockfd, my_dest,rem_dest); + } + + send(sockfd, "done", sizeof "done",0); + closesocket(sockfd); + + free(tposted); + free(tcompleted); + + printf("------------------------------------------------------------------\n"); + return 0; +} diff --git a/branches/WOF2-3/tools/perftests/user/read_bw/read_bw.rc b/branches/WOF2-3/tools/perftests/user/read_bw/read_bw.rc new file mode 100644 index 00000000..13e5f43d --- /dev/null +++ b/branches/WOF2-3/tools/perftests/user/read_bw/read_bw.rc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: write_bw.rc 1611 2006-08-20 14:48:55Z sleybo $ + */ + + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef _DEBUG_ +#define VER_FILEDESCRIPTION_STR "RDMA read Bandwidth Test (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "RDMA read Bandwidth Test " +#endif + +#define VER_INTERNALNAME_STR "ib_read_bw.exe" +#define VER_ORIGINALFILENAME_STR "ib_read_bw.exe" + +#include diff --git a/branches/WOF2-3/tools/perftests/user/read_lat/SOURCES b/branches/WOF2-3/tools/perftests/user/read_lat/SOURCES new file mode 100644 index 00000000..554d8707 --- /dev/null +++ b/branches/WOF2-3/tools/perftests/user/read_lat/SOURCES @@ -0,0 +1,28 @@ +TARGETNAME=ib_read_lat +TARGETPATH=..\..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE=PROGRAM +UMTYPE=console +USE_MSVCRT=1 + +C_DEFINES=$(C_DEFINES) /D__WIN__ + +SOURCES=read_lat.rc \ + ..\getopt.c \ + ..\perf_utils.c \ + read_lat.c + +INCLUDES=..;..\..\..\..\inc;..\..\..\..\inc\user + +RCOPTIONS=/I..\..\win\include + +TARGETLIBS= \ + $(DDK_LIB_PATH)\Ws2_32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\complib.lib \ + $(TARGETPATH)\*\ibal.lib +!else + $(TARGETPATH)\*\complibd.lib \ + $(TARGETPATH)\*\ibald.lib +!endif + +MSC_WARNING_LEVEL= /W3 diff --git a/branches/WOF2-3/tools/perftests/user/read_lat/makefile b/branches/WOF2-3/tools/perftests/user/read_lat/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-3/tools/perftests/user/read_lat/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\..\inc\openib.def diff --git a/branches/WOF2-3/tools/perftests/user/read_lat/read_lat.c b/branches/WOF2-3/tools/perftests/user/read_lat/read_lat.c new file mode 100644 index 00000000..0c15f83c --- /dev/null +++ b/branches/WOF2-3/tools/perftests/user/read_lat/read_lat.c @@ -0,0 +1,810 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies Ltd. All rights reserved. + * Copyright (c) 2005 Hewlett Packard, Inc (Grant Grundler) + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: read_lat.c 2292 2008-04-02 14:27:02Z xalex $ + */ + +#include "getopt.h" +#include "perf_defs.h" +#include "get_clock.h" + + + + +struct user_parameters { + const char *servername; + int connection_type; + int mtu; + int all; /* run all msg size */ + int iters; + int tx_depth; + int max_out_read; +}; + +static int page_size; + +cycles_t *tstamp; + + + +void +pp_cq_comp_cb( + IN const ib_cq_handle_t h_cq, + IN void *cq_context ) +{ + UNUSED_PARAM( h_cq ); + UNUSED_PARAM( cq_context); + return ; +} + +static struct pingpong_context *pp_init_ctx(unsigned size,int port, struct user_parameters *user_parm) +{ + + + struct pingpong_context *ctx; + ib_api_status_t ib_status = IB_SUCCESS; + size_t guid_count; + ib_net64_t *ca_guid_array; + + + ctx = malloc(sizeof *ctx); + if (!ctx){ + perror("malloc"); + return NULL; + } + memset(ctx, 0, sizeof(struct pingpong_context)); + ctx->size = size; + ctx->tx_depth = user_parm->tx_depth; + + ctx->qp = malloc(sizeof (ib_qp_handle_t)); + if (!ctx->qp) { + perror("malloc"); + return NULL; + } + + ctx->qp_attr = malloc(sizeof (ib_qp_attr_t)); + if (!ctx->qp_attr) { + perror("malloc"); + return NULL; + } + + ctx->buf = malloc( size * 2); + if (!ctx->buf) { + fprintf(stderr, "Couldn't allocate work buf.\n"); + return NULL; + } + + memset(ctx->buf, 0, size * 2); + + + /* + * Open the AL instance + */ + ib_status = ib_open_al(&ctx->al); + if(ib_status != IB_SUCCESS) + { + fprintf(stderr,"ib_open_al failed status = %d\n", ib_status); + return NULL; + } + + /* + * Get the Local CA Guids + */ + ib_status = ib_get_ca_guids(ctx->al, NULL, &guid_count); + if(ib_status != IB_INSUFFICIENT_MEMORY) + { + fprintf(stderr,"ib_get_ca_guids1 failed status = %d\n", (uint32_t)ib_status); + return NULL; + } + + /* + * If no CA's Present then return + */ + + if(guid_count == 0) + return NULL; + + + ca_guid_array = (ib_net64_t*)malloc(sizeof(ib_net64_t) * guid_count); + + ib_status = ib_get_ca_guids(ctx->al, ca_guid_array, &guid_count); + if(ib_status != IB_SUCCESS) + { + fprintf(stderr,"ib_get_ca_guids2 failed with status = %d\n", ib_status); + return NULL; + } + + /* + * Open only the first HCA + */ + /* Open the CA */ + ib_status = ib_open_ca(ctx->al ,ca_guid_array[0] ,NULL, + NULL, //ca_context + &ctx->ca); + + if(ib_status != IB_SUCCESS) + { + fprintf(stderr,"ib_open_ca failed with status = %d\n", ib_status); + return NULL; + } + + //xxx + //printf("ib_open_ca passed i=%d\n",i); + //xxx + + + + + { + /* Query the CA */ + uint32_t bsize = 0; + ib_status = ib_query_ca(ctx->ca, NULL, &bsize); + if(ib_status != IB_INSUFFICIENT_MEMORY) + { + fprintf(stderr, "Failed to query device props"); + return NULL; + } + + ctx->ca_attr = (ib_ca_attr_t *)malloc(bsize); + + ib_status = ib_query_ca(ctx->ca, ctx->ca_attr, &bsize); + if(ib_status != IB_SUCCESS) + { + printf("ib_query_ca failed with status = %d\n", ib_status); + return NULL; + } + if (user_parm->mtu == 0) {/*user did not ask for specific mtu */ + if (ctx->ca_attr->dev_id == 23108) { + user_parm->mtu = 1024; + } else { + user_parm->mtu = 2048; + } + } + } + + + + ib_status = ib_alloc_pd(ctx->ca , + IB_PDT_NORMAL, + ctx, //pd_context + &ctx->pd); + if (ib_status != IB_SUCCESS) { + fprintf(stderr, "Couldn't allocate PD\n"); + return NULL; + } + + + /* We dont really want IBV_ACCESS_LOCAL_WRITE, but IB spec says: + * The Consumer is not allowed to assign Remote Write or Remote Atomic to + * a Memory Region that has not been assigned Local Write. */ + + + { + ib_mr_create_t mr_create; + + mr_create.length = size * 2; + + mr_create.vaddr = ctx->buf; + mr_create.access_ctrl = IB_AC_RDMA_WRITE| IB_AC_LOCAL_WRITE|IB_AC_RDMA_READ; + + ib_status = ib_reg_mem(ctx->pd ,&mr_create ,&ctx->lkey ,&ctx->rkey ,&ctx->mr); + if (ib_status != IB_SUCCESS) { + fprintf(stderr, "Couldn't allocate MR\n"); + return NULL; + } + } + + { + ib_cq_create_t cq_create; + + cq_create.size = user_parm->tx_depth; + cq_create.h_wait_obj = NULL; + cq_create.pfn_comp_cb = pp_cq_comp_cb; + ib_status = ib_create_cq(ctx->ca,&cq_create ,ctx, NULL, &ctx->scq); + if (ib_status != IB_SUCCESS) { + fprintf(stderr, "Couldn't create CQ ib_status = %d\n",ib_status); + return NULL; + } + } + + { + + ib_qp_create_t qp_create; + ib_qp_mod_t qp_modify; + ib_qp_attr_t qp_attr; + + memset(&qp_create, 0, sizeof(ib_qp_create_t)); + qp_create.h_sq_cq = ctx->scq; + qp_create.h_rq_cq = ctx->scq; + qp_create.sq_depth = user_parm->tx_depth; + qp_create.rq_depth = 1; + qp_create.sq_sge = 1; + qp_create.rq_sge = 1; + //TODO MAX_INLINE + qp_create.qp_type= IB_QPT_RELIABLE_CONN; + qp_create.sq_signaled = FALSE; + /*attr.sq_sig_all = 0;*/ + + ib_status = ib_create_qp(ctx->pd, &qp_create,NULL,NULL,&ctx->qp[0]); + if (ib_status != IB_SUCCESS){ + fprintf(stderr, "Couldn't create QP\n"); + return NULL; + } + + + + + memset(&qp_modify, 0, sizeof(ib_qp_mod_t)); + qp_modify.req_state = IB_QPS_INIT; + qp_modify.state.init.pkey_index = 0 ; + qp_modify.state.init.primary_port = (uint8_t)port; + qp_modify.state.init.access_ctrl = IB_AC_RDMA_WRITE | IB_AC_LOCAL_WRITE|IB_AC_RDMA_READ; + + + ib_status = ib_modify_qp(ctx->qp[0], &qp_modify); + if (ib_status != IB_SUCCESS){ + fprintf(stderr, "Failed to modify QP to INIT\n"); + return NULL; + } + + + memset(&qp_attr, 0, sizeof(ib_qp_attr_t)); + ib_status = ib_query_qp(ctx->qp[0], &ctx->qp_attr[0]); + if (ib_status != IB_SUCCESS){ + fprintf(stderr, "Failed to modify QP to INIT\n"); + return NULL; + } + fprintf(stderr, "max inline size %d\n",ctx->qp_attr[0].sq_max_inline); + } + return ctx; +} + + + + + +static int pp_connect_ctx(struct pingpong_context *ctx, int port, int my_psn, + struct pingpong_dest *dest, struct user_parameters *user_parm,int qpindex) +{ + + ib_api_status_t ib_status; + ib_qp_mod_t attr; + memset(&attr, 0, sizeof(ib_qp_mod_t)); + + attr.req_state = IB_QPS_RTR; + switch (user_parm->mtu) { + case 256 : + attr.state.rtr.primary_av.conn.path_mtu = IB_MTU_LEN_256; + break; + case 512 : + attr.state.rtr.primary_av.conn.path_mtu = IB_MTU_LEN_512; + break; + case 1024 : + attr.state.rtr.primary_av.conn.path_mtu = IB_MTU_LEN_1024; + break; + case 2048 : + attr.state.rtr.primary_av.conn.path_mtu = IB_MTU_LEN_2048; + break; + } + printf("Mtu : %d\n", user_parm->mtu); + attr.state.rtr.dest_qp = dest->qpn;; + attr.state.rtr.rq_psn = dest->psn; + attr.state.rtr.resp_res = (uint8_t)user_parm->max_out_read; + attr.state.rtr.rnr_nak_timeout = 12; + attr.state.rtr.primary_av.grh_valid = 0; + attr.state.rtr.primary_av.dlid = dest->lid; + attr.state.rtr.primary_av.sl = 0; + attr.state.rtr.primary_av.path_bits = 0; + attr.state.rtr.primary_av.port_num = (uint8_t)port; + attr.state.rtr.primary_av.static_rate = IB_PATH_RECORD_RATE_10_GBS; + attr.state.rtr.opts = IB_MOD_QP_LOCAL_ACK_TIMEOUT | + IB_MOD_QP_RESP_RES | + IB_MOD_QP_PRIMARY_AV; + + + ib_status = ib_modify_qp(ctx->qp[0], &attr); + if(ib_status != IB_SUCCESS){ + fprintf(stderr, "Failed to modify QP to RTR\n"); + return 1; + } + + + + memset(&attr, 0, sizeof(ib_qp_mod_t)); + attr.req_state = IB_QPS_RTS; + attr.state.rts.sq_psn = my_psn; + + attr.state.rts.init_depth = (uint8_t)user_parm->max_out_read; + attr.state.rts.local_ack_timeout = 14; + attr.state.rts.retry_cnt = 7; + attr.state.rts.rnr_retry_cnt = 7; + attr.state.rts.opts = IB_MOD_QP_RNR_RETRY_CNT | + IB_MOD_QP_RETRY_CNT | + IB_MOD_QP_INIT_DEPTH | + IB_MOD_QP_LOCAL_ACK_TIMEOUT; + + ib_status = ib_modify_qp(ctx->qp[0], &attr); + if(ib_status != IB_SUCCESS){ + fprintf(stderr, "Failed to modify QP to RTS\n"); + return 1; + } + + return 0; +} + + +static SOCKET pp_open_port(struct pingpong_context *ctx, const char * servername, + int ib_port, int port, struct pingpong_dest **p_my_dest, + struct pingpong_dest **p_rem_dest,struct user_parameters *user_parm) +{ + //char addr_fmt[] = "%8s address: LID %#04x QPN %#06x PSN %#06x RKey %#08x VAddr %#016Lx\n"; + struct pingpong_dest *my_dest; + struct pingpong_dest *rem_dest; + SOCKET sockfd; + int rc; + int i; + int numofqps = 1; + + /* Create connection between client and server. + * We do it by exchanging data over a TCP socket connection. */ + + + my_dest = malloc( sizeof (struct pingpong_dest) * numofqps); + if (!my_dest){ + perror("malloc"); + return INVALID_SOCKET; + } + memset( my_dest, 0, sizeof (struct pingpong_dest) * numofqps ); + + rem_dest = malloc(sizeof (struct pingpong_dest) * numofqps ); + if (!rem_dest){ + perror("malloc"); + return INVALID_SOCKET; + } + memset( rem_dest, 0, sizeof (struct pingpong_dest) * numofqps ); + + sockfd = servername ? pp_client_connect(servername, port) : + pp_server_connect(port); + + if (sockfd == INVALID_SOCKET) { + printf("pp_connect_sock(%s,%d) failed (%d)!\n", + servername, port, sockfd); + return INVALID_SOCKET; + } + + + for (i =0 ;ica_attr->p_port_attr[ib_port-1].lid; + my_dest[i].psn = cl_hton32(rand() & 0xffffff); + if (!my_dest[i].lid) { + fprintf(stderr, "Local lid 0x0 detected. Is an SM running?\n"); + return 1; + } + my_dest[i].qpn = ctx->qp_attr[i].num; + /* TBD this should be changed inot VA and different key to each qp */ + my_dest[i].rkey = ctx->rkey; + my_dest[i].vaddr = (uintptr_t)ctx->buf + ctx->size; + + printf(" local address: LID %#04x, QPN %#06x, PSN %#06x, " + "RKey %#08x VAddr %#016Lx\n", + my_dest[i].lid, my_dest[i].qpn, my_dest[i].psn, + my_dest[i].rkey, my_dest[i].vaddr); + + rc = servername ? pp_client_exch_dest(sockfd, &my_dest[i],&rem_dest[i]): + pp_server_exch_dest(sockfd, &my_dest[i],&rem_dest[i]); + if (rc) + return INVALID_SOCKET; + printf(" remote address: LID %#04x, QPN %#06x, PSN %#06x, " + "RKey %#08x VAddr %#016Lx\n", + rem_dest[i].lid, rem_dest[i].qpn, rem_dest[i].psn, + rem_dest[i].rkey, rem_dest[i].vaddr); + + if (pp_connect_ctx(ctx, ib_port, my_dest[i].psn, &rem_dest[i], user_parm, i)) + return INVALID_SOCKET; + /* An additional handshake is required *after* moving qp to RTR. + Arbitrarily reuse exch_dest for this purpose. */ + rc = servername ? pp_client_exch_dest(sockfd, &my_dest[i],&rem_dest[i]): + pp_server_exch_dest(sockfd, &my_dest[i],&rem_dest[i]); + if (rc) + return INVALID_SOCKET; + } + *p_rem_dest = rem_dest; + *p_my_dest = my_dest; + return sockfd; +} + +static void usage(const char *argv0) +{ + printf("Usage:\n"); + printf(" %s start a server and wait for connection\n", argv0); + printf(" %s connect to server at \n", argv0); + printf("\n"); + printf("Options:\n"); + printf(" -p, --port= listen on/connect to port (default 18515)\n"); + printf(" -m, --mtu= mtu size (default 256)\n"); + printf(" -i, --ib-port= use port of IB device (default 1)\n"); + printf(" -s, --size= size of message to exchange (default 1)\n"); + printf(" -t, --tx-depth= size of tx queue (default 50)\n"); + printf(" -n, --iters= number of exchanges (at least 2, default 1000)\n"); + printf(" -o, --outs= num of outstanding read/atom(default 4)\n"); + printf(" -a, --all Run sizes from 2 till 2^23\n"); + printf(" -C, --report-cycles report times in cpu cycle units (default microseconds)\n"); + printf(" -H, --report-histogram print out all results (default print summary only)\n"); + printf(" -U, --report-unsorted (implies -H) print out unsorted results (default sorted)\n"); + printf(" -V, --version display version number\n"); +} + + + +static void print_report(struct report_options * options, + unsigned int iters, cycles_t *tstamp,int size) +{ + double cycles_to_units; + cycles_t median; + unsigned int i; + const char* units; + cycles_t *delta = malloc(iters * sizeof *delta); + + if (!delta) { + perror("malloc"); + return; + } + + for (i = 0; i < iters - 1; ++i) + delta[i] = tstamp[i + 1] - tstamp[i]; + + + if (options->cycles) { + cycles_to_units = 1; + units = "cycles"; + } else { + cycles_to_units = get_cpu_mhz()/1000000; + units = "usec"; + } + + if (options->unsorted) { + printf("#, %s\n", units); + for (i = 0; i < iters - 1; ++i) + printf("%d, %g\n", i + 1, delta[i] / cycles_to_units ); + } + + qsort(delta, iters - 1, sizeof *delta, cycles_compare); + + if (options->histogram) { + printf("#, %s\n", units); + for (i = 0; i < iters - 1; ++i) + printf("%d, %g\n", i + 1, delta[i] / cycles_to_units ); + } + + median = get_median(iters - 1, delta); + printf("%7d %d %7.2f %7.2f %7.2f\n", + size,iters,delta[0] / cycles_to_units , + delta[iters - 3] / cycles_to_units ,median / cycles_to_units ); + + free(delta); +} + +int run_iter(struct pingpong_context *ctx, struct user_parameters *user_param, + struct pingpong_dest *rem_dest, int size) +{ + ib_api_status_t ib_status; + int scnt, ccnt ; + ib_send_wr_t *bad_wr; + + ctx->list.vaddr = (uintptr_t) ctx->buf ; + ctx->list.length = size; + ctx->list.lkey = ctx->lkey; + ctx->wr.remote_ops.vaddr = rem_dest->vaddr; + ctx->wr.remote_ops.rkey = rem_dest->rkey; + ctx->wr.wr_id = PINGPONG_RDMA_WRID; + ctx->wr.ds_array = &ctx->list; + ctx->wr.num_ds = 1; + ctx->wr.wr_type = WR_RDMA_READ; + ctx->wr.send_opt = IB_SEND_OPT_SIGNALED; + ctx->wr.p_next = NULL; + + scnt = 0; + ccnt = 0; + + + /* Done with setup. Start the test. */ + + if(user_param->servername) { + while (scnt < user_param->iters ) { + + ib_status = ib_post_send(ctx->qp[0], &ctx->wr, &bad_wr); + if (ib_status != IB_SUCCESS) + { + fprintf(stderr, "Couldn't post send: scnt %d ccnt %d\n",scnt,ccnt); + return 1; + } + tstamp[scnt] = get_cycles(); + ++scnt; + PERF_DEBUG("scnt = %d \n",scnt); + + { + ib_wc_t wc; + ib_wc_t *p_wc_done,*p_wc_free; + + p_wc_free = &wc; + p_wc_done = NULL; + p_wc_free->p_next = NULL; + + do{ + ib_status = ib_poll_cq(ctx->scq, &p_wc_free, &p_wc_done); + } while (ib_status == IB_NOT_FOUND); + + if (ib_status != IB_SUCCESS) { + fprintf(stderr, "Poll Send CQ failed %d\n", ib_status); + return 12; + } + + if (p_wc_done->status != IB_WCS_SUCCESS) { + fprintf(stderr, "Completion wth error at %s:\n", + user_param->servername ? "client" : "server"); + fprintf(stderr, "Failed status %d: wr_id %d syndrom 0x%x\n", + p_wc_done->status, (int) p_wc_done->wr_id, p_wc_done->vendor_specific); + return 1; + } + ++ccnt; + PERF_DEBUG("ccnt = %d \n",ccnt); + + } + + } + } + return(0); +} + + +int __cdecl main(int argc, char *argv[]) +{ + struct pingpong_context *ctx; + struct pingpong_dest *my_dest; + struct pingpong_dest *rem_dest; + struct user_parameters user_param; + char *ib_devname = NULL; + int port = 18515; + int ib_port = 1; + unsigned tmp_size,size = 2; + SOCKET sockfd = INVALID_SOCKET; + WSADATA wsaData; + int iResult; + int i = 0; + struct report_options report = {0}; + + + /* init default values to user's parameters */ + memset(&user_param, 0, sizeof(struct user_parameters)); + user_param.mtu = 0; /* signal choose default by device */ + user_param.iters = 1000; + user_param.tx_depth = 50; + user_param.servername = NULL; + user_param.connection_type = RC; + user_param.max_out_read = 4; /* the device capability on gen2 */ +/* Parameter parsing. */ + while (1) { + int c; + + static struct option long_options[] = { + { "port", 1, NULL, 'p' }, + { "mtu", 1, NULL, 'm' }, + { "outs", 1, NULL, 'o' }, + { "ib-dev", 1, NULL, 'd' }, + { "ib-port", 1, NULL, 'i' }, + { "size", 1, NULL, 's' }, + { "iters", 1, NULL, 'n' }, + { "tx-depth", 1, NULL, 't' }, + { "all", 0, NULL, 'a' }, + { "report-cycles", 0, NULL, 'C' }, + { "report-histogram", 0, NULL, 'H' }, + { "report-unsorted", 0, NULL, 'U' }, + { "version", 0, NULL, 'V' }, + { 0 } + }; + + + c = getopt_long(argc, argv, "p:m:d:i:s:n:t:aHUV", long_options, NULL); + if (c == -1) + break; + + switch (c) { + case 'p': + port = strtol(optarg, NULL, 0); + if (port < 0 || port > 65535) { + usage(argv[0]); + return 1; + } + break; + case 'm': + user_param.mtu = strtol(optarg, NULL, 0); + break; + case 'o': + user_param.max_out_read = strtol(optarg, NULL, 0); + break; + case 'a': + user_param.all = ALL; + break; + case 'V': + printf("read_lat version : %.2f\n",VERSION); + return 0; + break; + case 'd': + ib_devname = _strdup(optarg); + break; + + case 'i': + ib_port = strtol(optarg, NULL, 0); + if (ib_port < 0) { + usage(argv[0]); + return 2; + } + break; + + case 's': + size = strtol(optarg, NULL, 0); + if (size < 1) { + usage(argv[0]); return 3; + } + break; + + case 't': + user_param.tx_depth = strtol(optarg, NULL, 0); + if (user_param.tx_depth < 1) { + usage(argv[0]); return 4; + } + break; + + case 'n': + user_param.iters = strtol(optarg, NULL, 0); + if (user_param.iters < 2) { + usage(argv[0]); + return 5; + } + + break; + + case 'C': + report.cycles = 1; + break; + + case 'H': + report.histogram = 1; + break; + + case 'U': + report.unsorted = 1; + break; + + default: + usage(argv[0]); + return 5; + } + } + + if (optind == argc - 1) + user_param.servername = _strdup(argv[optind]); + else if (optind < argc) { + usage(argv[0]); + return 6; + } + + /* + * Done with parameter parsing. Perform setup. + */ + tstamp = malloc(user_param.iters * sizeof *tstamp); + if (!tstamp) { + perror("malloc"); + return 10; + } + printf("------------------------------------------------------------------\n"); + printf(" RDMA_Read Latency Test\n"); + + + // Initialize Winsock + iResult = WSAStartup(MAKEWORD(2,2), &wsaData); + if (iResult != NO_ERROR) { + printf("Error at WSAStartup()\n"); + return 1; + } + + tmp_size = size; + /* anyway make sure the connection is RC */ + if (user_param.all == ALL) { + /*since we run all sizes */ + size = 8388608; /*2^23 */ + } else if (size < 128) { + /* can cut up to 70 nsec probably related to cache line size */ + size = 128; + } + + srand(GetCurrentProcessId() * GetTickCount()); + + //TODO: get pagesize from sysinfo + page_size = 4096; + + //TODO:get the device names + + + ctx = pp_init_ctx(size,ib_port, &user_param); + if (!ctx) + return 8; + + + sockfd = pp_open_port(ctx, user_param.servername, ib_port, port,&my_dest,&rem_dest,&user_param); + if (sockfd == INVALID_SOCKET) + return 9; + + + printf("------------------------------------------------------------------\n"); + printf(" #bytes #iterations t_min[usec] t_max[usec] t_typical[usec]\n"); + /* For half duplex tests, server just waits for client to exit */ + /* use dummy my_dest struct*/ + if (!user_param.servername) { + pp_server_exch_dest(sockfd, my_dest,rem_dest); + send(sockfd, "done", sizeof "done",0); + closesocket(sockfd); + return 0; + } + + /* fix for true size in small msg size */ + if (tmp_size < 128) { + size = tmp_size ; + } + + if (user_param.all == ALL) { + for (i = 1; i < 24 ; ++i) { + size = 1 << i; + if(run_iter(ctx, &user_param, rem_dest, size)) + return 17; + print_report(&report, user_param.iters, tstamp, size); + } + } else { + if(run_iter(ctx, &user_param, rem_dest, size)) + return 18; + print_report(&report, user_param.iters, tstamp, size); + } + + pp_client_exch_dest(sockfd, my_dest,rem_dest); + send(sockfd, "done", sizeof "done",0); + closesocket(sockfd); + + printf("------------------------------------------------------------------\n"); + free(tstamp); + return 0; +} diff --git a/branches/WOF2-3/tools/perftests/user/read_lat/read_lat.rc b/branches/WOF2-3/tools/perftests/user/read_lat/read_lat.rc new file mode 100644 index 00000000..2dd3fb9e --- /dev/null +++ b/branches/WOF2-3/tools/perftests/user/read_lat/read_lat.rc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: write_bw.rc 1611 2006-08-20 14:48:55Z sleybo $ + */ + + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef _DEBUG_ +#define VER_FILEDESCRIPTION_STR "RDMA read Latency Test (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "RDMA read Latency Test " +#endif + +#define VER_INTERNALNAME_STR "ib_read_lat.exe" +#define VER_ORIGINALFILENAME_STR "ib_read_lat.exe" + +#include diff --git a/branches/WOF2-3/tools/perftests/user/send_bw/SOURCES b/branches/WOF2-3/tools/perftests/user/send_bw/SOURCES new file mode 100644 index 00000000..274106a1 --- /dev/null +++ b/branches/WOF2-3/tools/perftests/user/send_bw/SOURCES @@ -0,0 +1,28 @@ +TARGETNAME=ib_send_bw +TARGETPATH=..\..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE=PROGRAM +UMTYPE=console +USE_MSVCRT=1 + +C_DEFINES=$(C_DEFINES) /D__WIN__ + +SOURCES=send_bw.rc \ + ..\getopt.c \ + ..\perf_utils.c \ + send_bw.c + +INCLUDES=..;..\..\..\..\inc;..\..\..\..\inc\user + +RCOPTIONS=/I..\..\win\include + +TARGETLIBS= \ + $(DDK_LIB_PATH)\Ws2_32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\complib.lib \ + $(TARGETPATH)\*\ibal.lib +!else + $(TARGETPATH)\*\complibd.lib \ + $(TARGETPATH)\*\ibald.lib +!endif + +MSC_WARNING_LEVEL= /W3 diff --git a/branches/WOF2-3/tools/perftests/user/send_bw/makefile b/branches/WOF2-3/tools/perftests/user/send_bw/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-3/tools/perftests/user/send_bw/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\..\inc\openib.def diff --git a/branches/WOF2-3/tools/perftests/user/send_bw/send_bw.c b/branches/WOF2-3/tools/perftests/user/send_bw/send_bw.c new file mode 100644 index 00000000..4021bf0a --- /dev/null +++ b/branches/WOF2-3/tools/perftests/user/send_bw/send_bw.c @@ -0,0 +1,1208 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies Ltd. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include "getopt.h" +#include "get_clock.h" + +#include "perf_defs.h" + +#define SIGNAL 1 +#define MAX_INLINE 400 + +struct user_parameters { + const char *servername; + int connection_type; + int mtu; + int all; /* run all msg size */ + int signal_comp; + int iters; + int tx_depth; + int duplex; + int use_event; +}; + +static int page_size; +cycles_t *tposted; +cycles_t *tcompleted; +int post_recv; + + +void +pp_cq_comp_cb( + IN const ib_cq_handle_t h_cq, + IN void *cq_context ) +{ + UNUSED_PARAM( h_cq ); + UNUSED_PARAM( cq_context); + return ; +} + + + +static struct pingpong_context *pp_init_ctx(unsigned size,int port, + struct user_parameters *user_parm) +{ + + struct pingpong_context *ctx; + ib_api_status_t ib_status = IB_SUCCESS; + size_t guid_count; + ib_net64_t *ca_guid_array; + + + + ctx = malloc(sizeof *ctx); + if (!ctx) + return NULL; + + ctx->qp = malloc(sizeof (ib_qp_handle_t)); + if (!ctx->qp) { + perror("malloc"); + return NULL; + } + ctx->qp_attr = malloc(sizeof (ib_qp_attr_t)); + if (!ctx->qp_attr) { + perror("malloc"); + return NULL; + } + + ctx->size = size; + ctx->tx_depth = user_parm->tx_depth; + /* in case of UD need space for the GRH */ + if (user_parm->connection_type==UD) { + ctx->buf = malloc(( size + 40 ) * 2); + if (!ctx->buf) { + fprintf(stderr, "Couldn't allocate work buf.\n"); + return NULL; + } + memset(ctx->buf, 0, ( size + 40 ) * 2); + } else { + ctx->buf = malloc( size * 2); + if (!ctx->buf) { + fprintf(stderr, "Couldn't allocate work buf.\n"); + return NULL; + } + memset(ctx->buf, 0, size * 2); + } + + /* + * Open the AL instance + */ + ib_status = ib_open_al(&ctx->al); + if(ib_status != IB_SUCCESS) + { + fprintf(stderr,"ib_open_al failed status = %d\n", ib_status); + return NULL; + } + + /* + * Get the Local CA Guids + */ + ib_status = ib_get_ca_guids(ctx->al, NULL, &guid_count); + if(ib_status != IB_INSUFFICIENT_MEMORY) + { + fprintf(stderr,"ib_get_ca_guids1 failed status = %d\n", (uint32_t)ib_status); + return NULL; + } + + /* + * If no CA's Present then return + */ + + if(guid_count == 0) + return NULL; + + + ca_guid_array = (ib_net64_t*)malloc(sizeof(ib_net64_t) * guid_count); + + ib_status = ib_get_ca_guids(ctx->al, ca_guid_array, &guid_count); + if(ib_status != IB_SUCCESS) + { + fprintf(stderr,"ib_get_ca_guids2 failed with status = %d\n", ib_status); + return NULL; + } + + /* + * Open only the first HCA + */ + /* Open the CA */ + ib_status = ib_open_ca(ctx->al ,ca_guid_array[0] ,NULL, + NULL, //ca_context + &ctx->ca); + + if(ib_status != IB_SUCCESS) + { + fprintf(stderr,"ib_open_ca failed with status = %d\n", ib_status); + return NULL; + } + + //xxx + //printf("ib_open_ca passed i=%d\n",i); + //xxx + + + { + + /* Query the CA */ + uint32_t bsize = 0; + ib_status = ib_query_ca(ctx->ca, NULL, &bsize); + if(ib_status != IB_INSUFFICIENT_MEMORY) + { + fprintf(stderr, "Failed to query device props"); + return NULL; + } + + ctx->ca_attr = (ib_ca_attr_t *)malloc(bsize); + + ib_status = ib_query_ca(ctx->ca, ctx->ca_attr, &bsize); + if(ib_status != IB_SUCCESS) + { + printf("ib_query_ca failed with status = %d\n", ib_status); + return NULL; + } + if (user_parm->mtu == 0) {/*user did not ask for specific mtu */ + if (ctx->ca_attr->dev_id == 23108) { + user_parm->mtu = 1024; + } else { + user_parm->mtu = 2048; + } + } + } + + ctx->channel = NULL; + + ib_status = ib_alloc_pd(ctx->ca , + IB_PDT_NORMAL, + ctx, //pd_context + &ctx->pd); + if (ib_status != IB_SUCCESS) { + fprintf(stderr, "Couldn't allocate PD\n"); + return NULL; + } + + + { + ib_mr_create_t mr_create; + ib_cq_create_t cq_create; + /* We dont really want IBV_ACCESS_LOCAL_WRITE, but IB spec says: + * The Consumer is not allowed to assign Remote Write or Remote Atomic to + * a Memory Region that has not been assigned Local Write. */ + if (user_parm->connection_type==UD) { + mr_create.length = (size + 40 ) * 2; + } else { + mr_create.length = size * 2; + } + + mr_create.vaddr = ctx->buf; + mr_create.access_ctrl = IB_AC_RDMA_WRITE| IB_AC_LOCAL_WRITE; + + ib_status = ib_reg_mem(ctx->pd ,&mr_create ,&ctx->lkey ,&ctx->rkey ,&ctx->mr); + if (ib_status != IB_SUCCESS) { + fprintf(stderr, "Couldn't allocate MR\n"); + return NULL; + } + + if (user_parm->use_event) { + cl_status_t cl_status; + + cl_status = cl_waitobj_create( FALSE, &ctx->cq_waitobj ); + if( cl_status != CL_SUCCESS ) { + ctx->cq_waitobj = NULL; + fprintf(stderr, "cl_waitobj_create() returned %s\n", CL_STATUS_MSG(cl_status) ); + return NULL; + } + + cq_create.h_wait_obj = ctx->cq_waitobj; + cq_create.pfn_comp_cb = NULL; + } else { + cq_create.h_wait_obj = NULL; + cq_create.pfn_comp_cb = pp_cq_comp_cb; + } + + cq_create.size = user_parm->tx_depth*2; + ib_status = ib_create_cq(ctx->ca,&cq_create ,ctx, NULL, &ctx->scq); + if (ib_status != IB_SUCCESS) { + fprintf(stderr, "Couldn't create CQ\n"); + fprintf(stderr, "ib_status = %d\n", ib_status); + return NULL; + } + + if (user_parm->use_event) { + ib_status = ib_rearm_cq( ctx->scq, FALSE ); + if( ib_status ) + { + ib_destroy_cq( ctx->scq, NULL ); + fprintf(stderr,"ib_rearm_cq returned %s\n", ib_get_err_str( ib_status )); + return NULL; + } + } + } + + { + ib_qp_create_t qp_create; + memset(&qp_create, 0, sizeof(ib_qp_create_t)); + qp_create.h_sq_cq = ctx->scq; + qp_create.h_rq_cq = ctx->scq; + qp_create.sq_depth = user_parm->tx_depth; + qp_create.rq_depth = user_parm->tx_depth; + qp_create.sq_sge = 1; + qp_create.rq_sge = 1; + //TODO MAX_INLINE + + switch (user_parm->connection_type) { + case RC : + qp_create.qp_type= IB_QPT_RELIABLE_CONN; + break; + case UC : + qp_create.qp_type = IB_QPT_UNRELIABLE_CONN; + break; + case UD : + qp_create.qp_type = IB_QPT_UNRELIABLE_DGRM; + break; + default: + fprintf(stderr, "Unknown connection type %d \n",user_parm->connection_type); + return NULL; + } + + qp_create.sq_signaled = FALSE; + /*attr.sq_sig_all = 0;*/ + + ib_status = ib_create_qp(ctx->pd, &qp_create,NULL,NULL,&ctx->qp[0]); + if (ib_status != IB_SUCCESS){ + fprintf(stderr, "Couldn't create QP\n"); + return NULL; + } + } + + { + ib_qp_mod_t qp_modify; + ib_qp_attr_t qp_attr; + memset(&qp_modify, 0, sizeof(ib_qp_mod_t)); + qp_modify.req_state = IB_QPS_INIT; + qp_modify.state.init.pkey_index = 0 ; + qp_modify.state.init.primary_port = (uint8_t)port; + if (user_parm->connection_type==UD) { + qp_modify.state.init.qkey = 0x11111111; + } else { + qp_modify.state.init.access_ctrl = IB_AC_RDMA_WRITE | IB_AC_LOCAL_WRITE; + } + + ib_status = ib_modify_qp(ctx->qp[0], &qp_modify); + if (ib_status != IB_SUCCESS){ + fprintf(stderr, "Failed to modify QP to INIT\n"); + return NULL; + } + + + memset(&qp_attr, 0, sizeof(ib_qp_attr_t)); + ib_status = ib_query_qp(ctx->qp[0], &ctx->qp_attr[0]); + if (ib_status != IB_SUCCESS){ + fprintf(stderr, "Failed to modify QP to INIT\n"); + return NULL; + } + fprintf(stderr, "max inline size %d\n",ctx->qp_attr[0].sq_max_inline); + + } + return ctx; + +} + +static int pp_connect_ctx(struct pingpong_context *ctx, int port, int my_psn, + struct pingpong_dest *dest, struct user_parameters *user_parm,int index) +{ + + ib_api_status_t ib_status; + ib_qp_mod_t attr; + memset(&attr, 0, sizeof(ib_qp_mod_t)); + + attr.req_state = IB_QPS_RTR; + switch (user_parm->mtu) { + case 256 : + attr.state.rtr.primary_av.conn.path_mtu = IB_MTU_LEN_256; + break; + case 512 : + attr.state.rtr.primary_av.conn.path_mtu = IB_MTU_LEN_512; + break; + case 1024 : + attr.state.rtr.primary_av.conn.path_mtu = IB_MTU_LEN_1024; + break; + case 2048 : + attr.state.rtr.primary_av.conn.path_mtu = IB_MTU_LEN_2048; + break; + } + printf("Mtu : %d\n", user_parm->mtu); + attr.state.rtr.dest_qp = (dest->qpn); + attr.state.rtr.rq_psn = (dest->psn); + if (user_parm->connection_type==RC) { + attr.state.rtr.resp_res = 1; + attr.state.rtr.rnr_nak_timeout = 12; + } + attr.state.rtr.primary_av.grh_valid = 0; + attr.state.rtr.primary_av.dlid = dest->lid; + attr.state.rtr.primary_av.sl = 0; + attr.state.rtr.primary_av.path_bits = 0; + attr.state.rtr.primary_av.port_num = (uint8_t)port; + attr.state.rtr.primary_av.static_rate = IB_PATH_RECORD_RATE_10_GBS; + attr.state.rtr.opts = IB_MOD_QP_LOCAL_ACK_TIMEOUT | + IB_MOD_QP_RESP_RES | + IB_MOD_QP_PRIMARY_AV; + + + ib_status = ib_modify_qp(ctx->qp[0], &attr); + if(ib_status != IB_SUCCESS){ + fprintf(stderr, "Failed to modify UC QP to RTR\n"); + return 1; + } + + if (user_parm->connection_type == UD) { + ib_av_attr_t av_attr; + + av_attr.grh_valid = 0; + av_attr.dlid = dest->lid; + av_attr.sl = 0; + av_attr.path_bits = 0; + av_attr.port_num = (uint8_t)port; + av_attr.static_rate = IB_PATH_RECORD_RATE_10_GBS; + + ib_status = ib_create_av(ctx->pd,&av_attr, &ctx->av); + if (ib_status != IB_SUCCESS) { + fprintf(stderr, "Failed to create AH for UD\n"); + return 1; + } + } + + + memset(&attr, 0, sizeof(ib_qp_mod_t)); + attr.req_state = IB_QPS_RTS; + attr.state.rts.sq_psn = my_psn; + + if (user_parm->connection_type == RC) { + attr.state.rts.resp_res = 1; + attr.state.rts.local_ack_timeout = 14; + attr.state.rts.retry_cnt = 7; + attr.state.rts.rnr_retry_cnt = 7; + attr.state.rts.opts = IB_MOD_QP_RNR_RETRY_CNT | + IB_MOD_QP_RETRY_CNT | + IB_MOD_QP_LOCAL_ACK_TIMEOUT; + + } + ib_status = ib_modify_qp(ctx->qp[index], &attr); + if(ib_status != IB_SUCCESS){ + fprintf(stderr, "Failed to modify UC QP to RTS\n"); + return 1; + } + + + + /* post receive max msg size*/ + { + int i; + ib_recv_wr_t *bad_wr_recv; + //receive + ctx->rwr.wr_id = PINGPONG_RECV_WRID; + ctx->rwr.ds_array = &ctx->recv_list; + ctx->rwr.num_ds = 1; + ctx->rwr.p_next = NULL; + ctx->recv_list.vaddr = (uintptr_t) ctx->buf; + if (user_parm->connection_type==UD) { + ctx->recv_list.length = ctx->size + 40; + } else { + ctx->recv_list.length = ctx->size; + } + ctx->recv_list.lkey = ctx->lkey; + for (i = 0; i < user_parm->tx_depth; ++i) { + ib_status = ib_post_recv(ctx->qp[index], &ctx->rwr, &bad_wr_recv); + if (ib_status != IB_SUCCESS) + { + fprintf(stderr, "Couldn't post recv: counter=%d\n", i); + return 14; + } + PERF_DEBUG("rcnt = %d \n",i); + } + } + post_recv = user_parm->tx_depth; + + return 0; +} + +static SOCKET pp_open_port(struct pingpong_context *ctx, const char * servername, + int ib_port, int port, struct pingpong_dest **p_my_dest, + struct pingpong_dest **p_rem_dest,struct user_parameters *user_parm) +{ + struct pingpong_dest *my_dest; + struct pingpong_dest *rem_dest; + SOCKET sockfd; + int rc; + int i; + int numofqps = 1; + + /* Create connection between client and server. + * We do it by exchanging data over a TCP socket connection. */ + + + my_dest = malloc( sizeof (struct pingpong_dest) * numofqps); + if (!my_dest){ + perror("malloc"); + return INVALID_SOCKET; + } + memset( my_dest, 0, sizeof (struct pingpong_dest) * numofqps ); + + rem_dest = malloc(sizeof (struct pingpong_dest) * numofqps ); + if (!rem_dest){ + perror("malloc"); + return INVALID_SOCKET; + } + memset( rem_dest, 0, sizeof (struct pingpong_dest) * numofqps ); + + sockfd = servername ? pp_client_connect(servername, port) : + pp_server_connect(port); + + if (sockfd == INVALID_SOCKET) { + printf("pp_connect_sock(%s,%d) failed (%d)!\n", + servername, port, sockfd); + return INVALID_SOCKET; + } + + + for (i =0 ;ica_attr->p_port_attr[ib_port-1].lid; + my_dest[i].psn = cl_hton32(rand() & 0xffffff); + if (!my_dest[i].lid) { + fprintf(stderr, "Local lid 0x0 detected. Is an SM running?\n"); + return 1; + } + my_dest[i].qpn = ctx->qp_attr[i].num; + /* TBD this should be changed inot VA and different key to each qp */ + my_dest[i].rkey = ctx->rkey; + my_dest[i].vaddr = (uintptr_t)ctx->buf + ctx->size; + + printf(" local address: LID %#04x, QPN %#06x, PSN %#06x, " + "RKey %#08x VAddr %#016Lx\n", + my_dest[i].lid, my_dest[i].qpn, my_dest[i].psn, + my_dest[i].rkey, my_dest[i].vaddr); + + rc = servername ? pp_client_exch_dest(sockfd, &my_dest[i],&rem_dest[i]): + pp_server_exch_dest(sockfd, &my_dest[i],&rem_dest[i]); + if (rc) + return INVALID_SOCKET; + printf(" remote address: LID %#04x, QPN %#06x, PSN %#06x, " + "RKey %#08x VAddr %#016Lx\n", + rem_dest[i].lid, rem_dest[i].qpn, rem_dest[i].psn, + rem_dest[i].rkey, rem_dest[i].vaddr); + + if (pp_connect_ctx(ctx, ib_port, my_dest[i].psn, &rem_dest[i], user_parm, i)) + return INVALID_SOCKET; + /* An additional handshake is required *after* moving qp to RTR. + Arbitrarily reuse exch_dest for this purpose. */ + rc = servername ? pp_client_exch_dest(sockfd, &my_dest[i],&rem_dest[i]): + pp_server_exch_dest(sockfd, &my_dest[i],&rem_dest[i]); + if (rc) + return INVALID_SOCKET; + } + *p_rem_dest = rem_dest; + *p_my_dest = my_dest; + return sockfd; +} + + +static void usage(const char *argv0) +{ + printf("Usage:\n"); + printf(" %s start a server and wait for connection\n", argv0); + printf(" %s connect to server at \n", argv0); + printf("\n"); + printf("Options:\n"); + printf(" -p, --port= listen on/connect to port (default 18515)\n"); + printf(" -i, --ib-port= use port of IB device (default 1)\n"); + printf(" -c, --connection= connection type RC/UC/UD (default RC)\n"); + printf(" -m, --mtu= mtu size (default 1024)\n"); + printf(" -s, --size= size of message to exchange (default 65536)\n"); + printf(" -a, --all Run sizes from 2 till 2^23\n"); + printf(" -t, --tx-depth= size of tx queue (default 300)\n"); + printf(" -n, --iters= number of exchanges (at least 2, default 1000)\n"); + printf(" -b, --bidirectional measure bidirectional bandwidth (default unidirectional)\n"); + printf(" -V, --version display version number\n"); +} + +static void print_report(unsigned int iters, unsigned size, int duplex, + cycles_t *tposted, cycles_t *tcompleted) +{ + double cycles_to_units; + uint64_t tsize; /* Transferred size, in megabytes */ + int i, j; + int opt_posted = 0, opt_completed = 0; + cycles_t opt_delta; + cycles_t t; + + + opt_delta = tcompleted[opt_posted] - tposted[opt_completed]; + + /* Find the peak bandwidth */ + for (i = 0; i < (int)iters; ++i) + for (j = i; j < (int)iters; ++j) { + t = (tcompleted[j] - tposted[i]) / (j - i + 1); + if (t < opt_delta) { + opt_delta = t; + opt_posted = i; + opt_completed = j; + } + } + + cycles_to_units = get_cpu_mhz(); + + tsize = duplex ? 2 : 1; + tsize = tsize * size; + printf("%7d %d %7.2f %7.2f \n", + size,iters,tsize * cycles_to_units / opt_delta / 0x100000, + (uint64_t)tsize * iters * cycles_to_units /(tcompleted[iters - 1] - tposted[0]) / 0x100000); +} + + +int run_iter_bi(struct pingpong_context *ctx, struct user_parameters *user_param, + struct pingpong_dest *rem_dest, int size) +{ + + ib_qp_handle_t qp; + int scnt, ccnt, rcnt; + ib_recv_wr_t *bad_wr_recv; + ib_api_status_t ib_status; + + /********************************************* + * Important note : + * In case of UD/UC this is NOT the way to measure + * BW since we are running with loop on the send side + * while we should run on the receive side or enable retry in SW + * Since the sender may be faster than the reciver than although + * we had posted receive it is not enough and might end this will + * result in deadlock of test since both sides are stuck on poll cq + * In this test i do not solve this for the general test ,need to write + * separate test for UC/UD but in case the tx_depth is ~1/3 from the + * number of iterations this should be ok . + * Also note that the sender is limited in the number of send, ans + * i try to make the receiver full + *********************************************/ + /* send */ + if (user_param->connection_type==UD) { + ctx->list.vaddr = (uintptr_t) ctx->buf + 40; + ctx->wr.dgrm.ud.h_av = ctx->av; + ctx->wr.dgrm.ud.remote_qp = rem_dest->qpn; + ctx->wr.dgrm.ud.remote_qkey = 0x11111111; + } else { + ctx->list.vaddr = (uintptr_t) ctx->buf; + } + ctx->list.lkey = ctx->lkey; + ctx->wr.wr_id = PINGPONG_SEND_WRID; + ctx->wr.ds_array = &ctx->list; + ctx->wr.num_ds = 1; + ctx->wr.wr_type = WR_SEND; + ctx->wr.p_next = NULL; + + if ((uint32_t)size > ctx->qp_attr[0].sq_max_inline) { /*complaince to perf_main */ + ctx->wr.send_opt = IB_SEND_OPT_SIGNALED; + } else { + ctx->wr.send_opt = IB_SEND_OPT_SIGNALED | IB_SEND_OPT_INLINE; + } + + ctx->list.length = size; + scnt = 0; + ccnt = 0; + rcnt = 0; + qp = ctx->qp[0]; + + while (ccnt < user_param->iters || rcnt < user_param->iters ) { + while (scnt < user_param->iters && (scnt - ccnt) < user_param->tx_depth / 2) { + ib_send_wr_t *bad_wr; + tposted[scnt] = get_cycles(); + ib_status = ib_post_send(qp, &ctx->wr, &bad_wr); + if (ib_status != IB_SUCCESS) { + fprintf(stderr, "Couldn't post send: scnt=%d ib_status %d\n", + scnt,ib_status); + return 1; + } + ++scnt; + PERF_DEBUG("scnt = %d \n",scnt); + } + + { + ib_wc_t wc; + ib_wc_t *p_wc_done,*p_wc_free; + + + p_wc_free = &wc; + p_wc_free->p_next = NULL; + p_wc_done = NULL; + + if (user_param->use_event) { + cl_status_t cl_status; + + PERF_DEBUG("%s:%d IN cl_waitobj_wait_on", __FUNCTION__, __LINE__); + cl_status = cl_waitobj_wait_on( ctx->cq_waitobj, EVENT_NO_TIMEOUT, TRUE ); + if( cl_status != CL_SUCCESS ) + { + fprintf(stderr, "cl_waitobj_wait_on() (%d)\n", cl_status); + return 1; + } + } + + do { + ib_status = ib_poll_cq(ctx->scq, &p_wc_free, &p_wc_done); + if (ib_status == IB_SUCCESS ) { + if (p_wc_done->status != IB_WCS_SUCCESS) { + fprintf(stderr, "Completion wth error at %s:\n", + user_param->servername ? "client" : "server"); + fprintf(stderr, "Failed status %d: wr_id %d syndrom 0x%x\n", + p_wc_done->status, (int) p_wc_done->wr_id, p_wc_done->vendor_specific); + fprintf(stderr, "scnt=%d, ccnt=%d\n", + scnt, ccnt); + return 1; + } + + switch ((int) p_wc_done->wr_id) { + case PINGPONG_SEND_WRID: + tcompleted[ccnt] = get_cycles(); + ++ccnt; + break; + case PINGPONG_RECV_WRID: + if (--post_recv <= user_param->tx_depth - 2) { + while (rcnt < user_param->iters && (user_param->tx_depth - post_recv) > 0 ) { + post_recv++; + ib_status = ib_post_recv(ctx->qp[0], &ctx->rwr, &bad_wr_recv); + if (ib_status != IB_SUCCESS) + { + fprintf(stderr, "Couldn't post recv: rcnt=%d\n", + rcnt); + return 15; + } + } + } + ++rcnt; + break; + default: + fprintf(stderr, "Completion for unknown wr_id %d\n", + (int) wc.wr_id); + break; + } + p_wc_free = p_wc_done; + p_wc_free->p_next = NULL; + p_wc_done = NULL; + PERF_DEBUG("ccnt = %d \n",ccnt); + PERF_DEBUG("rcnt = %d \n",rcnt); + } + } while (ib_status == IB_SUCCESS ); + + if (ib_status != IB_NOT_FOUND) { + fprintf(stderr, "poll CQ failed %d\n", ib_status); + return 1; + } + + if (user_param->use_event) { + ib_status = ib_rearm_cq( ctx->scq, FALSE ); + if( ib_status ) + { + ib_destroy_cq( ctx->scq, NULL ); + fprintf(stderr,"ib_rearm_cq returned %s\n", ib_get_err_str( ib_status )); + return 1; + } + } + } + } + return(0); +} + + +int run_iter_uni(struct pingpong_context *ctx, struct user_parameters *user_param, + struct pingpong_dest *rem_dest, int size) +{ + + ib_qp_handle_t qp; + int scnt, ccnt, rcnt; + ib_recv_wr_t *bad_wr_recv; + ib_api_status_t ib_status; + + + /* send */ + if (user_param->connection_type==UD) { + ctx->list.vaddr = (uintptr_t) ctx->buf + 40; + ctx->wr.dgrm.ud.h_av = ctx->av; + ctx->wr.dgrm.ud.remote_qp = rem_dest->qpn; + ctx->wr.dgrm.ud.remote_qkey = 0x11111111; + } else { + ctx->list.vaddr = (uintptr_t) ctx->buf; + } + ctx->list.lkey = ctx->lkey; + ctx->wr.wr_id = PINGPONG_SEND_WRID; + ctx->wr.ds_array = &ctx->list; + ctx->wr.num_ds = 1; + ctx->wr.wr_type = WR_SEND; + ctx->wr.p_next = NULL; + + + if ((uint32_t)size > ctx->qp_attr[0].sq_max_inline) { /*complaince to perf_main */ + ctx->wr.send_opt = IB_SEND_OPT_SIGNALED; + } else { + ctx->wr.send_opt = IB_SEND_OPT_SIGNALED | IB_SEND_OPT_INLINE; + } + ctx->list.length = size; + + scnt = 0; + ccnt = 0; + rcnt = 0; + qp = ctx->qp[0]; + if (!user_param->servername) { + while (rcnt < user_param->iters) { + ib_wc_t wc; + ib_wc_t *p_wc_done,*p_wc_free; + + p_wc_free = &wc; + p_wc_done = NULL; + p_wc_free->p_next = NULL; + + /*Server is polling on receive first */ + if (user_param->use_event) { + cl_status_t cl_status; + + PERF_DEBUG("%s:%d IN cl_waitobj_wait_on\n", __FUNCTION__, __LINE__); + cl_status = cl_waitobj_wait_on( ctx->cq_waitobj, EVENT_NO_TIMEOUT, TRUE ); + if( cl_status != CL_SUCCESS ) + { + fprintf(stderr, "cl_waitobj_wait_on() (%d)\n", cl_status); + return 1; + } + PERF_DEBUG("%s:%d OUT cl_waitobj_wait_on\n", __FUNCTION__, __LINE__); + } + + do { + + ib_status = ib_poll_cq(ctx->scq, &p_wc_free, &p_wc_done); + if (ib_status == IB_SUCCESS) { + tcompleted[ccnt] = get_cycles(); + if (p_wc_done->status != IB_WCS_SUCCESS) { + fprintf(stderr, "Completion wth error at %s:\n", + user_param->servername ? "client" : "server"); + fprintf(stderr, "Failed status %d: wr_id %d syndrom 0x%x\n", + p_wc_done->status, (int) p_wc_done->wr_id, p_wc_done->vendor_specific); + fprintf(stderr, "scnt=%d, ccnt=%d\n", + scnt, ccnt); + return 1; + } + + ib_status = ib_post_recv(ctx->qp[0], &ctx->rwr, &bad_wr_recv); + if (ib_status != IB_SUCCESS) + { + fprintf(stderr, "Couldn't post recv: rcnt=%d\n", + rcnt); + return 15; + } + ++rcnt; + ++ccnt; + PERF_DEBUG("ccnt = %d \n",ccnt); + PERF_DEBUG("rcnt = %d \n",rcnt); + + p_wc_free = p_wc_done; + p_wc_free->p_next = NULL; + p_wc_done = NULL; + } + } while (ib_status == IB_SUCCESS); + if (ib_status != IB_NOT_FOUND) { + fprintf(stderr, "Poll Receive CQ failed %d\n", ib_status); + return 12; + } + + if (user_param->use_event) { + ib_status = ib_rearm_cq( ctx->scq, FALSE ); + if( ib_status ) + { + ib_destroy_cq( ctx->scq, NULL ); + fprintf(stderr,"ib_rearm_cq returned %s\n", ib_get_err_str( ib_status )); + return 1; + } + } + + } + } else { + /* client is posting and not receiving. */ + while (scnt < user_param->iters || ccnt < user_param->iters) { + while (scnt < user_param->iters && (scnt - ccnt) < user_param->tx_depth ) { + ib_send_wr_t *bad_wr; + + tposted[scnt] = get_cycles(); + ib_status = ib_post_send(qp, &ctx->wr, &bad_wr); + if (ib_status != IB_SUCCESS) { + fprintf(stderr, "Couldn't post send: scnt=%d ib_status %d\n", + scnt,ib_status); + return 1; + } + ++scnt; + PERF_DEBUG("scnt = %d \n",scnt); + } + if (ccnt < user_param->iters) { + ib_wc_t wc; + ib_wc_t *p_wc_done,*p_wc_free; + + + p_wc_free = &wc; + p_wc_free->p_next = NULL; + p_wc_done = NULL; + + if ( (user_param->use_event) ) { + cl_status_t cl_status; + + PERF_DEBUG("%s:%d IN cl_waitobj_wait_on\n", __FUNCTION__, __LINE__); + cl_status = cl_waitobj_wait_on( ctx->cq_waitobj, EVENT_NO_TIMEOUT, TRUE ); + if( cl_status != CL_SUCCESS ) + { + fprintf(stderr, "cl_waitobj_wait_on() (%d)\n", cl_status); + return 1; + } + PERF_DEBUG("%s:%d OUT cl_waitobj_wait_on\n", __FUNCTION__, __LINE__); + } + + do { + ib_status = ib_poll_cq(ctx->scq, &p_wc_free, &p_wc_done); + if (ib_status == IB_SUCCESS ) { + tcompleted[ccnt] = get_cycles(); + if (p_wc_done->status != IB_WCS_SUCCESS) { + fprintf(stderr, "Completion wth error at %s:\n", + user_param->servername ? "client" : "server"); + fprintf(stderr, "Failed status %d: wr_id %d syndrom 0x%x\n", + p_wc_done->status, (int) p_wc_done->wr_id, p_wc_done->vendor_specific); + fprintf(stderr, "scnt=%d, ccnt=%d\n", + scnt, ccnt); + return 1; + } + ccnt ++; + p_wc_free = p_wc_done; + p_wc_free->p_next = NULL; + p_wc_done = NULL; + } + } while (ib_status == IB_SUCCESS ); + if (ib_status != IB_NOT_FOUND) { + fprintf(stderr, "poll CQ failed %d\n", ib_status); + return 1; + } + + if ( (user_param->use_event) ) { + ib_status = ib_rearm_cq( ctx->scq, FALSE ); + if( ib_status ) + { + ib_destroy_cq( ctx->scq, NULL ); + fprintf(stderr,"ib_rearm_cq returned %s\n", ib_get_err_str( ib_status )); + return 1; + } + } + + PERF_DEBUG("ccnt = %d \n",ccnt); + } + } + } + return(0); +} + + +int __cdecl main(int argc, char *argv[]) +{ + struct pingpong_context *ctx; + struct pingpong_dest *my_dest; + struct pingpong_dest *rem_dest; + struct user_parameters user_param; + char *ib_devname = NULL; + int port = 18515; + int ib_port = 1; + unsigned size = 65536; + SOCKET sockfd = INVALID_SOCKET; + int i = 0; + int size_max_pow = 24; + WSADATA wsaData; + int iResult; + + + /* init default values to user's parameters */ + memset(&user_param, 0, sizeof(struct user_parameters)); + user_param.mtu = 0; + user_param.iters = 1000; + user_param.tx_depth = 1000; + user_param.servername = NULL; + user_param.use_event = 0; + user_param.duplex = 0; + /* Parameter parsing. */ + while (1) { + int c; + + static struct option long_options[] = { + { "port", 1, NULL, 'p' }, + { "ib-dev", 1, NULL, 'd' }, + { "ib-port", 1, NULL, 'i' }, + { "mtu", 1, NULL, 'm' }, + { "connection", 1, NULL, 'c' }, + { "size", 1, NULL, 's' }, + { "iters", 1, NULL, 'n' }, + { "tx-depth", 1, NULL, 't' }, + { "all", 0, NULL, 'a' }, + { "bidirectional", 0, NULL, 'b' }, + { "version", 0, NULL, 'V' }, + { "events", 0, NULL, 'e' }, + { 0 } + }; + + c = getopt_long(argc, argv, "p:d:i:m:c:s:n:t:ebaVh", long_options, NULL); + if (c == -1) + break; + + switch (c) { + case 'p': + port = strtol(optarg, NULL, 0); + if (port < 0 || port > 65535) { + usage(argv[0]); + return 1; + } + break; + case 'e': + ++user_param.use_event; + break; + case 'd': + ib_devname = _strdup(optarg); + break; + case 'c': + if (strcmp("UC",optarg)==0) + user_param.connection_type=UC; + if (strcmp("UD",optarg)==0) + user_param.connection_type=UD; + break; + + case 'm': + user_param.mtu = strtol(optarg, NULL, 0); + break; + case 'a': + user_param.all = ALL; + break; + case 'V': + printf("send_bw version : %.2f\n",VERSION); + return 0; + break; + case 'i': + ib_port = strtol(optarg, NULL, 0); + if (ib_port <= 0) { + usage(argv[0]); + return 1; + } + break; + + case 's': + size = (unsigned)_strtoui64(optarg, NULL, 0); + if (size < 1 || size > UINT_MAX / 2) { + usage(argv[0]); + return 1; + } + + break; + + case 't': + user_param.tx_depth = strtol(optarg, NULL, 0); + if (user_param.tx_depth < 1) { usage(argv[0]); return 1; } + break; + + case 'n': + user_param.iters = strtol(optarg, NULL, 0); + if (user_param.iters < 2) { + usage(argv[0]); + return 1; + } + + break; + + case 'b': + user_param.duplex = 1; + break; + case 'h': + default: + usage(argv[0]); + return 1; + } + } + + if (optind == argc - 1) + user_param.servername = _strdup(argv[optind]); + else if (optind < argc) { + usage(argv[0]); + return 1; + } + printf("------------------------------------------------------------------\n"); + if (user_param.duplex == 1) + printf(" Send Bidirectional BW Test\n"); + else + printf(" Send BW Test\n"); + + printf("Inline data is used up to 400 bytes message\n"); + if (user_param.connection_type==RC) { + printf("Connection type : RC\n"); + } else if (user_param.connection_type==UC) { + printf("Connection type : UC\n"); + } else { + printf("Connection type : UD\n"); + } + + /* Done with parameter parsing. Perform setup. */ + + // Initialize Winsock + iResult = WSAStartup(MAKEWORD(2,2), &wsaData); + if (iResult != NO_ERROR) { + printf("Error at WSAStartup()\n"); + return 1; + } + + if (user_param.all == ALL && user_param.connection_type!=UD) { + /*since we run all sizes */ + printf("test\n"); + size = 8388608; /*2^23 */ + } else if (user_param.connection_type==UD ) { + printf("Max msg size in UD is 2048 changing to 2048\n"); + size = 2048; + } + + + srand(GetCurrentProcessId() * GetTickCount()); + + //TODO: get pagesize from sysinfo + page_size = 4096; + + //TODO:get the device names + + + // init the context + ctx = pp_init_ctx(size, ib_port, &user_param); + if (!ctx) + return 1; + + sockfd = pp_open_port(ctx, user_param.servername, ib_port, port,&my_dest,&rem_dest,&user_param); + if (sockfd == INVALID_SOCKET) + return 9; + + if (user_param.use_event) { + printf("Test with events.\n"); + } + + printf("------------------------------------------------------------------\n"); + printf(" #bytes #iterations BW peak[MB/sec] BW average[MB/sec] \n"); + + tposted = malloc(user_param.iters * sizeof *tposted); + + if (!tposted) { + perror("malloc"); + return 1; + } + + tcompleted = malloc(user_param.iters * sizeof *tcompleted); + + if (!tcompleted) { + perror("malloc"); + return 1; + } + + + if (user_param.all == ALL) { + if (user_param.connection_type==UD) { + size_max_pow = 12; + } + for (i = 1; i < size_max_pow ; ++i) { + size = 1 << i; + if (user_param.duplex) { + if(run_iter_bi(ctx, &user_param, rem_dest, size)) + return 17; + } else { + if(run_iter_uni(ctx, &user_param, rem_dest, size)) + return 17; + } + if (user_param.servername) { + print_report(user_param.iters, size, user_param.duplex, tposted, tcompleted); + /* sync again for the sake of UC/UC */ + if(pp_client_exch_dest(sockfd, my_dest,rem_dest)) + return 19; + + } else { + if(pp_server_exch_dest(sockfd,my_dest,rem_dest)) + return 19; + + } + + } + } else { + if (user_param.duplex) { + if(run_iter_bi(ctx, &user_param,rem_dest, size)) + return 18; + } else { + if(run_iter_uni(ctx, &user_param,rem_dest, size)) + return 18; + } + if (user_param.servername) { + print_report(user_param.iters, size, user_param.duplex, tposted, tcompleted); + } + } + + /* close sockets */ + if (user_param.servername) { + pp_client_exch_dest(sockfd, my_dest,rem_dest); + } else { + pp_server_exch_dest(sockfd, my_dest,rem_dest); + } + + send(sockfd, "done", sizeof "done",0); + closesocket(sockfd); + + free(tposted); + free(tcompleted); + + printf("------------------------------------------------------------------\n"); + goto end; + + +end: + if (user_param.use_event) { + cl_status_t cl_status; + + cl_status = cl_waitobj_destroy( ctx->cq_waitobj ); + if( cl_status != CL_SUCCESS ) + { + fprintf (stderr, + "cl_waitobj_destroy() returned %s\n", CL_STATUS_MSG(cl_status)); + } + } + + WSACleanup(); + return 0; +} diff --git a/branches/WOF2-3/tools/perftests/user/send_bw/send_bw.rc b/branches/WOF2-3/tools/perftests/user/send_bw/send_bw.rc new file mode 100644 index 00000000..b66c9e13 --- /dev/null +++ b/branches/WOF2-3/tools/perftests/user/send_bw/send_bw.rc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef _DEBUG_ +#define VER_FILEDESCRIPTION_STR "Send/Recv Bandwidth Test (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "Send/Recv Bandwidth Test " +#endif + +#define VER_INTERNALNAME_STR "ib_send_bw.exe" +#define VER_ORIGINALFILENAME_STR "ib_send_bw.exe" + +#include diff --git a/branches/WOF2-3/tools/perftests/user/send_lat/SOURCES b/branches/WOF2-3/tools/perftests/user/send_lat/SOURCES new file mode 100644 index 00000000..86150e1e --- /dev/null +++ b/branches/WOF2-3/tools/perftests/user/send_lat/SOURCES @@ -0,0 +1,28 @@ +TARGETNAME=ib_send_lat +TARGETPATH=..\..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE=PROGRAM +UMTYPE=console +USE_MSVCRT=1 + +C_DEFINES=$(C_DEFINES) /D__WIN__ + +SOURCES=send_lat.rc \ + ..\getopt.c \ + ..\perf_utils.c \ + send_lat.c + +INCLUDES=..;..\..\..\..\inc;..\..\..\..\inc\user + +RCOPTIONS=/I..\..\win\include + +TARGETLIBS= \ + $(DDK_LIB_PATH)\Ws2_32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\complib.lib \ + $(TARGETPATH)\*\ibal.lib +!else + $(TARGETPATH)\*\complibd.lib \ + $(TARGETPATH)\*\ibald.lib +!endif + +MSC_WARNING_LEVEL= /W3 diff --git a/branches/WOF2-3/tools/perftests/user/send_lat/makefile b/branches/WOF2-3/tools/perftests/user/send_lat/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-3/tools/perftests/user/send_lat/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\..\inc\openib.def diff --git a/branches/WOF2-3/tools/perftests/user/send_lat/send_lat.c b/branches/WOF2-3/tools/perftests/user/send_lat/send_lat.c new file mode 100644 index 00000000..b0a91362 --- /dev/null +++ b/branches/WOF2-3/tools/perftests/user/send_lat/send_lat.c @@ -0,0 +1,1025 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies Ltd. All rights reserved. + * Copyright (c) 2005 Hewlett Packard, Inc (Grant Grundler) + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include "getopt.h" +#include "get_clock.h" +#include "perf_defs.h" + + + +static int page_size; +cycles_t *tstamp; + +struct user_parameters { + const char *servername; + int connection_type; + int mtu; + int signal_comp; + int all; /* run all msg size */ + int iters; + int tx_depth; +}; + + + +void +pp_cq_comp_cb( + IN const ib_cq_handle_t h_cq, + IN void *cq_context ) +{ + UNUSED_PARAM( h_cq ); + UNUSED_PARAM( cq_context); + return ; +} + + +static struct pingpong_context *pp_init_ctx(unsigned int size,int port,struct user_parameters *user_parm) { + + struct pingpong_context *ctx; + ib_api_status_t ib_status = IB_SUCCESS; + size_t guid_count; + ib_net64_t *ca_guid_array; + + + + ctx = malloc(sizeof *ctx); + if (!ctx) + return NULL; + + ctx->qp = malloc(sizeof (ib_qp_handle_t)); + if (!ctx->qp) { + perror("malloc"); + return NULL; + } + + ctx->qp_attr = malloc(sizeof (ib_qp_attr_t)); + if (!ctx->qp_attr) { + perror("malloc"); + return NULL; + } + + ctx->size = size; + ctx->tx_depth = user_parm->tx_depth; + /* in case of UD need space for the GRH */ + if (user_parm->connection_type==UD) { + ctx->buf = malloc(( size + 40 ) * 2); //PORTED ALINGED + if (!ctx->buf) { + fprintf(stderr, "Couldn't allocate work buf.\n"); + return NULL; + } + memset(ctx->buf, 0, ( size + 40 ) * 2); + } else { + ctx->buf = malloc( size * 2); //PORTED ALINGED + if (!ctx->buf) { + fprintf(stderr, "Couldn't allocate work buf.\n"); + return NULL; + } + memset(ctx->buf, 0, size * 2); + } + + + ctx->post_buf = (char*)ctx->buf + (size - 1); + ctx->poll_buf = (char*)ctx->buf + (2 * size - 1); + + /* + * Open the AL instance + */ + ib_status = ib_open_al(&ctx->al); + if(ib_status != IB_SUCCESS) + { + fprintf(stderr,"ib_open_al failed status = %d\n", ib_status); + return NULL; + } + + /* + * Get the Local CA Guids + */ + ib_status = ib_get_ca_guids(ctx->al, NULL, &guid_count); + if(ib_status != IB_INSUFFICIENT_MEMORY) + { + fprintf(stderr,"ib_get_ca_guids1 failed status = %d\n", (uint32_t)ib_status); + return NULL; + } + + /* + * If no CA's Present then return + */ + + if(guid_count == 0) + return NULL; + + + ca_guid_array = (ib_net64_t*)malloc(sizeof(ib_net64_t) * guid_count); + + ib_status = ib_get_ca_guids(ctx->al, ca_guid_array, &guid_count); + if(ib_status != IB_SUCCESS) + { + fprintf(stderr,"ib_get_ca_guids2 failed with status = %d\n", ib_status); + return NULL; + } + + /* + * Open only the first HCA + */ + /* Open the CA */ + ib_status = ib_open_ca(ctx->al ,ca_guid_array[0] ,NULL, + NULL, //ca_context + &ctx->ca); + + if(ib_status != IB_SUCCESS) + { + fprintf(stderr,"ib_open_ca failed with status = %d\n", ib_status); + return NULL; + } + + //xxx + //printf("ib_open_ca passed i=%d\n",i); + //xxx + + + { + + + /* Query the CA */ + uint32_t bsize = 0; + ib_status = ib_query_ca(ctx->ca, NULL, &bsize); + if(ib_status != IB_INSUFFICIENT_MEMORY) + { + fprintf(stderr, "Failed to query device props"); + return NULL; + } + + ctx->ca_attr = (ib_ca_attr_t *)malloc(bsize); + + ib_status = ib_query_ca(ctx->ca, ctx->ca_attr, &bsize); + if(ib_status != IB_SUCCESS) + { + printf("ib_query_ca failed with status = %d\n", ib_status); + return NULL; + } + if (user_parm->mtu == 0) {/*user did not ask for specific mtu */ + if (ctx->ca_attr->dev_id == 23108) { + user_parm->mtu = 1024; + } else { + user_parm->mtu = 2048; + } + } + } + + ib_status = ib_alloc_pd(ctx->ca , + IB_PDT_NORMAL, + ctx, //pd_context + &ctx->pd); + if (ib_status != IB_SUCCESS) { + fprintf(stderr, "Couldn't allocate PD\n"); + return NULL; + } + + + { + ib_mr_create_t mr_create; + ib_cq_create_t cq_create; + /* We dont really want IBV_ACCESS_LOCAL_WRITE, but IB spec says: + * The Consumer is not allowed to assign Remote Write or Remote Atomic to + * a Memory Region that has not been assigned Local Write. */ + if (user_parm->connection_type==UD) { + mr_create.length = (size + 40 ) * 2; + } else { + mr_create.length = size * 2; + } + + mr_create.vaddr = ctx->buf; + mr_create.access_ctrl = IB_AC_RDMA_WRITE| IB_AC_LOCAL_WRITE; + + ib_status = ib_reg_mem(ctx->pd ,&mr_create ,&ctx->lkey ,&ctx->rkey ,&ctx->mr); + if (ib_status != IB_SUCCESS) { + fprintf(stderr, "Couldn't allocate MR\n"); + return NULL; + } + + + cq_create.size = user_parm->tx_depth*2; + cq_create.h_wait_obj = NULL; + cq_create.pfn_comp_cb = pp_cq_comp_cb; + ib_status = ib_create_cq(ctx->ca,&cq_create ,ctx, NULL, &ctx->rcq); + if (ib_status != IB_SUCCESS) { + fprintf(stderr, "Couldn't create CQ\n"); + return NULL; + } + + + cq_create.size = user_parm->tx_depth*2; + cq_create.h_wait_obj = NULL; + cq_create.pfn_comp_cb = pp_cq_comp_cb; + ib_status = ib_create_cq(ctx->ca,&cq_create ,ctx, NULL, &ctx->scq); + if (ib_status != IB_SUCCESS) { + fprintf(stderr, "Couldn't create CQ\n"); + return NULL; + } + } + + { + ib_qp_create_t qp_create; + memset(&qp_create, 0, sizeof(ib_qp_create_t)); + qp_create.h_sq_cq = ctx->scq; + qp_create.h_rq_cq = ctx->rcq; + qp_create.sq_depth = user_parm->tx_depth; + qp_create.rq_depth = user_parm->tx_depth; + qp_create.sq_sge = 1; + qp_create.rq_sge = 1; + //TODO MAX_INLINE + + switch (user_parm->connection_type) { + case RC : + qp_create.qp_type= IB_QPT_RELIABLE_CONN; + break; + case UC : + qp_create.qp_type = IB_QPT_UNRELIABLE_CONN; + break; + case UD : + qp_create.qp_type = IB_QPT_UNRELIABLE_DGRM; + break; + default: + fprintf(stderr, "Unknown connection type %d \n",user_parm->connection_type); + return NULL; + } + + qp_create.sq_signaled = FALSE; + /*attr.sq_sig_all = 0;*/ + + ib_status = ib_create_qp(ctx->pd, &qp_create,NULL,NULL,&ctx->qp[0]); + if (ib_status != IB_SUCCESS){ + fprintf(stderr, "Couldn't create QP\n"); + return NULL; + } + } + + { + ib_qp_mod_t qp_modify; + ib_qp_attr_t qp_attr; + memset(&qp_modify, 0, sizeof(ib_qp_mod_t)); + qp_modify.req_state = IB_QPS_INIT; + qp_modify.state.init.pkey_index = 0 ; + qp_modify.state.init.primary_port = (uint8_t)port; + if (user_parm->connection_type==UD) { + qp_modify.state.init.qkey = 0x11111111; + } else { + qp_modify.state.init.access_ctrl = IB_AC_RDMA_WRITE | IB_AC_LOCAL_WRITE; + } + + ib_status = ib_modify_qp(ctx->qp[0], &qp_modify); + if (ib_status != IB_SUCCESS){ + fprintf(stderr, "Failed to modify QP to INIT\n"); + return NULL; + } + + + memset(&qp_attr, 0, sizeof(ib_qp_attr_t)); + ib_status = ib_query_qp(ctx->qp[0], &ctx->qp_attr[0]); + if (ib_status != IB_SUCCESS){ + fprintf(stderr, "Failed to modify QP to INIT\n"); + return NULL; + } + } + + + //send + ctx->wr.wr_id = PINGPONG_SEND_WRID; + ctx->wr.ds_array = &ctx->list; + ctx->wr.num_ds = 1; + ctx->wr.wr_type = WR_SEND; + ctx->wr.p_next = NULL; + + //receive + ctx->rwr.wr_id = PINGPONG_RECV_WRID; + ctx->rwr.ds_array = &ctx->recv_list; + ctx->rwr.num_ds = 1; + ctx->rwr.p_next = NULL; + return ctx; +} + +static int pp_connect_ctx(struct pingpong_context *ctx, int port, int my_psn, + struct pingpong_dest *dest,struct user_parameters *user_parm,int index) +{ + ib_api_status_t ib_status; + ib_qp_mod_t attr; + memset(&attr, 0, sizeof(ib_qp_mod_t)); + + attr.req_state = IB_QPS_RTR; + switch (user_parm->mtu) { + case 256 : + attr.state.rtr.primary_av.conn.path_mtu = IB_MTU_LEN_256; + break; + case 512 : + attr.state.rtr.primary_av.conn.path_mtu = IB_MTU_LEN_512; + break; + case 1024 : + attr.state.rtr.primary_av.conn.path_mtu = IB_MTU_LEN_1024; + break; + case 2048 : + attr.state.rtr.primary_av.conn.path_mtu = IB_MTU_LEN_2048; + break; + } + printf("Mtu : %d\n", user_parm->mtu); + attr.state.rtr.dest_qp = (dest->qpn); + attr.state.rtr.rq_psn = (dest->psn); + if (user_parm->connection_type==RC) { + attr.state.rtr.resp_res = 1; + attr.state.rtr.rnr_nak_timeout = 12; + } + attr.state.rtr.primary_av.grh_valid = 0; + attr.state.rtr.primary_av.dlid = dest->lid; + attr.state.rtr.primary_av.sl = 0; + attr.state.rtr.primary_av.path_bits = 0; + attr.state.rtr.primary_av.port_num = (uint8_t)port; + attr.state.rtr.primary_av.static_rate = IB_PATH_RECORD_RATE_10_GBS; + attr.state.rtr.opts = IB_MOD_QP_LOCAL_ACK_TIMEOUT | + IB_MOD_QP_RESP_RES | + IB_MOD_QP_PRIMARY_AV; + + + ib_status = ib_modify_qp(ctx->qp[0], &attr); + if(ib_status != IB_SUCCESS){ + fprintf(stderr, "Failed to modify UC QP to RTR\n"); + return 1; + } + + + if (user_parm->connection_type == UD) { + ib_av_attr_t av_attr; + + av_attr.grh_valid = 0; + av_attr.dlid = dest->lid; + av_attr.dlid = dest->lid; + av_attr.sl = 0; + av_attr.path_bits = 0; + av_attr.port_num = (uint8_t)port; + av_attr.static_rate = IB_PATH_RECORD_RATE_10_GBS; + ib_status = ib_create_av(ctx->pd,&av_attr, &ctx->av); + if (ib_status != IB_SUCCESS) { + fprintf(stderr, "Failed to create AH for UD\n"); + return 1; + } + } + memset(&attr, 0, sizeof(ib_qp_mod_t)); + attr.req_state = IB_QPS_RTS; + attr.state.rts.sq_psn = my_psn; + + if (user_parm->connection_type == RC) { + attr.state.rts.resp_res = 1; + attr.state.rts.local_ack_timeout = 14; + attr.state.rts.retry_cnt = 7; + attr.state.rts.rnr_retry_cnt = 7; + attr.state.rts.opts = IB_MOD_QP_RNR_RETRY_CNT | + IB_MOD_QP_RETRY_CNT | + IB_MOD_QP_LOCAL_ACK_TIMEOUT; + + } + ib_status = ib_modify_qp(ctx->qp[index], &attr); + if(ib_status != IB_SUCCESS){ + fprintf(stderr, "Failed to modify UC QP to RTS\n"); + return 1; + } + + + + /* post receive max msg size*/ + { + int i; + ib_recv_wr_t *bad_wr_recv; + //receive + ctx->rwr.wr_id = PINGPONG_RECV_WRID; + ctx->rwr.ds_array = &ctx->recv_list; + ctx->rwr.num_ds = 1; + ctx->rwr.p_next = NULL; + ctx->recv_list.vaddr = (uintptr_t) ctx->buf; + if (user_parm->connection_type==UD) { + ctx->recv_list.length = ctx->size + 40; + } else { + ctx->recv_list.length = ctx->size; + } + ctx->recv_list.lkey = ctx->lkey; + for (i = 0; i < user_parm->tx_depth / 2; ++i) { + if (ib_post_recv(ctx->qp[index], &ctx->rwr, &bad_wr_recv)) { + fprintf(stderr, "Couldn't post recv: counter=%d\n", i); + return 14; + } + } + } + return 0; +} + +static SOCKET pp_open_port(struct pingpong_context *ctx, const char * servername, + int ib_port, int port, struct pingpong_dest **p_my_dest, + struct pingpong_dest **p_rem_dest,struct user_parameters *user_parm) +{ + struct pingpong_dest *my_dest; + struct pingpong_dest *rem_dest; + SOCKET sockfd; + int rc; + int i; + int numofqps = 1; + + /* Create connection between client and server. + * We do it by exchanging data over a TCP socket connection. */ + + + my_dest = malloc( sizeof (struct pingpong_dest) * numofqps); + if (!my_dest){ + perror("malloc"); + return INVALID_SOCKET; + } + memset( my_dest, 0, sizeof (struct pingpong_dest) * numofqps ); + + rem_dest = malloc(sizeof (struct pingpong_dest) * numofqps ); + if (!rem_dest){ + perror("malloc"); + return INVALID_SOCKET; + } + memset( rem_dest, 0, sizeof (struct pingpong_dest) * numofqps ); + + sockfd = servername ? pp_client_connect(servername, port) : + pp_server_connect(port); + + if (sockfd == INVALID_SOCKET) { + printf("pp_connect_sock(%s,%d) failed (%d)!\n", + servername, port, sockfd); + return INVALID_SOCKET; + } + + + for (i =0 ;ica_attr->p_port_attr[ib_port-1].lid; + my_dest[i].psn = cl_hton32(rand() & 0xffffff); + if (!my_dest[i].lid) { + fprintf(stderr, "Local lid 0x0 detected. Is an SM running?\n"); + return 1; + } + my_dest[i].qpn = ctx->qp_attr[i].num; + /* TBD this should be changed inot VA and different key to each qp */ + my_dest[i].rkey = ctx->rkey; + my_dest[i].vaddr = (uintptr_t)ctx->buf + ctx->size; + + printf(" local address: LID %#04x, QPN %#06x, PSN %#06x, " + "RKey %#08x VAddr %#016Lx\n", + my_dest[i].lid, my_dest[i].qpn, my_dest[i].psn, + my_dest[i].rkey, my_dest[i].vaddr); + + rc = servername ? pp_client_exch_dest(sockfd, &my_dest[i],&rem_dest[i]): + pp_server_exch_dest(sockfd, &my_dest[i],&rem_dest[i]); + if (rc) + return INVALID_SOCKET; + printf(" remote address: LID %#04x, QPN %#06x, PSN %#06x, " + "RKey %#08x VAddr %#016Lx\n", + rem_dest[i].lid, rem_dest[i].qpn, rem_dest[i].psn, + rem_dest[i].rkey, rem_dest[i].vaddr); + + if (pp_connect_ctx(ctx, ib_port, my_dest[i].psn, &rem_dest[i], user_parm, i)) + return INVALID_SOCKET; + /* An additional handshake is required *after* moving qp to RTR. + Arbitrarily reuse exch_dest for this purpose. */ + rc = servername ? pp_client_exch_dest(sockfd, &my_dest[i],&rem_dest[i]): + pp_server_exch_dest(sockfd, &my_dest[i],&rem_dest[i]); + if (rc) + return INVALID_SOCKET; + } + *p_rem_dest = rem_dest; + *p_my_dest = my_dest; + return sockfd; +} + + + +static void usage(const char *argv0) +{ + printf("Usage:\n"); + printf(" %s start a server and wait for connection\n", argv0); + printf(" %s connect to server at \n", argv0); + printf("\n"); + printf("Options:\n"); + printf(" -p, --port= listen on/connect to port (default 18515)\n"); + printf(" -c, --connection= connection type RC/UC (default RC)\n"); + printf(" -m, --mtu= mtu size (default 2048)\n"); + printf(" -i, --ib-port= use port of IB device (default 1)\n"); + printf(" -s, --size= size of message to exchange (default 1)\n"); + printf(" -t, --tx-depth= size of tx queue (default 50)\n"); + printf(" -l, --signal signal completion on each msg\n"); + printf(" -a, --all Run sizes from 2 till 2^23\n"); + printf(" -n, --iters= number of exchanges (at least 2, default 1000)\n"); + printf(" -C, --report-cycles report times in cpu cycle units (default microseconds)\n"); + printf(" -H, --report-histogram print out all results (default print summary only)\n"); + printf(" -U, --report-unsorted (implies -H) print out unsorted results (default sorted)\n"); + printf(" -V, --version display version number\n"); +} + + + +static void print_report(struct report_options * options, + unsigned int iters, cycles_t *tstamp,int size) +{ + double cycles_to_units; + cycles_t median; + unsigned int i; + const char* units; + cycles_t *delta = malloc(iters * sizeof *delta); + + if (!delta) { + perror("malloc"); + return; + } + + for (i = 0; i < iters - 1; ++i) + delta[i] = tstamp[i + 1] - tstamp[i]; + + + if (options->cycles) { + cycles_to_units = 1; + units = "cycles"; + } else { + cycles_to_units = get_cpu_mhz()/1000000; + units = "usec"; + } + + if (options->unsorted) { + printf("#, %s\n", units); + for (i = 0; i < iters - 1; ++i) + printf("%d, %g\n", i + 1, delta[i] / cycles_to_units / 2); + } + + qsort(delta, iters - 1, sizeof *delta, cycles_compare); + + if (options->histogram) { + printf("#, %s\n", units); + for (i = 0; i < iters - 1; ++i) + printf("%d, %g\n", i + 1, delta[i] / cycles_to_units / 2); + } + + median = get_median(iters - 1, delta); + printf("%7d %d %7.2f %7.2f %7.2f\n", + size,iters,delta[0] / cycles_to_units / 2, + delta[iters - 2] / cycles_to_units / 2,median / cycles_to_units / 2); + free(delta); +} + +int run_iter(struct pingpong_context *ctx, struct user_parameters *user_param, + struct pingpong_dest *rem_dest, int size) +{ + ib_api_status_t ib_status; + ib_qp_handle_t qp; + ib_recv_wr_t rwr; + ib_recv_wr_t *bad_wr_recv; + volatile char *poll_buf; + volatile char *post_buf; + + int scnt, rcnt, ccnt, poll; + int iters; + int tx_depth; + iters = user_param->iters; + tx_depth = user_param->tx_depth; + + ///send // + if (user_param->connection_type==UD) { + ctx->list.vaddr = (uintptr_t) ctx->buf + 40; + } else { + ctx->list.vaddr = (uintptr_t) ctx->buf; + } + ctx->list.length = size; + ctx->list.lkey = ctx->lkey; + if (user_param->connection_type==UD) { + ctx->wr.dgrm.ud.h_av = ctx->av; + ctx->wr.dgrm.ud.remote_qp = rem_dest->qpn; + ctx->wr.dgrm.ud.remote_qkey = 0x11111111; + } + + /// receive // + rwr = ctx->rwr; + ctx->recv_list.vaddr = (uintptr_t) ctx->buf; + if (user_param->connection_type==UD) { + ctx->recv_list.length = ctx->size + 40; + } else { + ctx->recv_list.length = ctx->size; + } + + ctx->recv_list.lkey = ctx->lkey; + + scnt = 0; + rcnt = 0; + ccnt = 0; + poll = 0; + poll_buf = ctx->poll_buf; + post_buf = ctx->post_buf; + qp = ctx->qp[0]; + if ((uint32_t)size > ctx->qp_attr[0].sq_max_inline || size == 0) {/* complaince to perf_main don't signal*/ + ctx->wr.send_opt = 0; + } else { + ctx->wr.send_opt = IB_SEND_OPT_INLINE; + } + + while (scnt < iters || rcnt < iters) { + if (rcnt < iters && !(scnt < 1 && user_param->servername)) { + ib_wc_t wc; + ib_wc_t *p_wc_done,*p_wc_free; + + p_wc_free = &wc; + p_wc_done = NULL; + p_wc_free->p_next = NULL; + PERF_DEBUG("rcnt %d\n",rcnt); + PERF_DEBUG("scnt %d\n",scnt); + /*Server is polling on receive first */ + ++rcnt; + if (ib_post_recv(qp, &rwr, &bad_wr_recv)) { + fprintf(stderr, "Couldn't post recv: rcnt=%d\n", + rcnt); + return 15; + } + +#if PORTED + if (user_param->use_event) { + struct ibv_cq *ev_cq; + void *ev_ctx; + + if (ibv_get_cq_event(ctx->channel, &ev_cq, &ev_ctx)) { + fprintf(stderr, "Failed to get receive cq_event\n"); + return 1; + } + + if (ev_cq != ctx->rcq) { + fprintf(stderr, "CQ event for unknown RCQ %p\n", ev_cq); + return 1; + } + + if (ibv_req_notify_cq(ctx->rcq, 0)) { + fprintf(stderr, "Couldn't request RCQ notification\n"); + return 1; + } + } +#endif + + do { + ib_status = ib_poll_cq(ctx->rcq,&p_wc_free, &p_wc_done); + } while (ib_status == IB_NOT_FOUND); + + if (ib_status != IB_SUCCESS) { + fprintf(stderr, "Poll Receive CQ failed %d\n", ib_status); + return 12; + } + + if (p_wc_done->status != IB_WCS_SUCCESS) { + fprintf(stderr, "Receive Completion wth error at %s:\n", + user_param->servername ? "client" : "server"); + fprintf(stderr, "Failed status %d: wr_id %d\n", + wc.status, (int) wc.wr_id); + fprintf(stderr, "scnt=%d, rcnt=%d, ccnt=%d\n", + scnt, rcnt, ccnt); + return 13; + } + } + + if (scnt < iters ) { + ib_send_wr_t *bad_wr; + + PERF_DEBUG("rcnt1 %d\n",rcnt); + PERF_DEBUG("scnt1 %d\n",scnt); + if (ccnt == (tx_depth - 2) || (user_param->signal_comp == SIGNAL) + || (scnt == (iters - 1)) ) { + ccnt = 0; + poll=1; + if ((uint32_t)size > ctx->qp_attr[0].sq_max_inline || size == 0) {/* complaince to perf_main */ + ctx->wr.send_opt = IB_SEND_OPT_SIGNALED; + } else { + ctx->wr.send_opt = IB_SEND_OPT_SIGNALED | IB_SEND_OPT_INLINE; + } + + } + + /* client post first */ + *post_buf = (char)++scnt; + if (ib_post_send(qp,&ctx->wr, &bad_wr)) { + fprintf(stderr, "Couldn't post send: scnt=%d\n", + scnt); + return 11; + } + tstamp[scnt-1] = get_cycles(); + } + if (poll == 1) { + ib_wc_t wc; + ib_wc_t *p_wc_done,*p_wc_free; + + PERF_DEBUG("rcnt2 %d\n",rcnt); + PERF_DEBUG("scnt2 %d\n",scnt); + p_wc_free = &wc; + p_wc_done = NULL; + p_wc_free->p_next = NULL; + + + /* poll on scq */ + do { + ib_status = ib_poll_cq(ctx->scq, &p_wc_free, &p_wc_done); + } while (ib_status == IB_NOT_FOUND); + + if (ib_status != IB_SUCCESS) { + fprintf(stderr, "Poll Receive CQ failed %d\n", ib_status); + return 12; + } + + if (wc.status != IB_WCS_SUCCESS) { + fprintf(stderr, "Receive Completion wth error at %s:\n", + user_param->servername ? "client" : "server"); + fprintf(stderr, "Failed status %d: wr_id %d\n", + wc.status, (int) wc.wr_id); + fprintf(stderr, "scnt=%d, rcnt=%d, ccnt=%d\n", + scnt, rcnt, ccnt); + return 13; + } + + poll = 0; + if ((uint32_t)size > ctx->qp_attr[0].sq_max_inline || size == 0) {/* complaince to perf_main don't signal*/ + ctx->wr.send_opt = 0; + } else { + ctx->wr.send_opt = IB_SEND_OPT_INLINE; + } + + } + ++ccnt; + } + + return(0); +} + + + +int __cdecl main(int argc, char *argv[]) +{ + + struct pingpong_context *ctx; + struct pingpong_dest *my_dest; + struct pingpong_dest *rem_dest; + struct user_parameters user_param; + char *ib_devname = NULL; + int port = 18515; + int ib_port = 1; + unsigned size = 2; + SOCKET sockfd = INVALID_SOCKET; + int i = 0; + int size_max_pow = 24; + WSADATA wsaData; + int iResult; + + + struct report_options report = {0}; + + /* init default values to user's parameters */ + memset(&user_param, 0, sizeof(struct user_parameters)); + user_param.mtu = 0; + user_param.iters = 1000; + user_param.tx_depth = 50; + user_param.servername = NULL; + /* Parameter parsing. */ + while (1) { + int c; + + static struct option long_options[] = { + { "port", 1,NULL, 'p' }, + { "connection", 1,NULL, 'c' }, + { "mtu", 1,NULL, 'm' }, + { "ib-dev", 1,NULL, 'd' }, + { "ib-port", 1,NULL, 'i' }, + { "size", 1,NULL, 's' }, + { "iters", 1,NULL, 'n' }, + { "tx-depth", 1,NULL, 't' }, + { "signal", 0,NULL, 'l' }, + { "all", 0,NULL, 'a' }, + { "report-cycles", 0,NULL, 'C' }, + { "report-histogram", 0,NULL, 'H' }, + { "report-unsorted", 0,NULL, 'U' }, + { "version", 0,NULL, 'V' }, + { 0 } + }; + + c = getopt_long(argc, argv, "p:c:m:d:i:s:n:t:laeCHUV", long_options, NULL); + if (c == -1) + break; + + switch (c) { + case 'p': + port = strtol(optarg, NULL, 0); + if (port < 0 || port > 65535) { + usage(argv[0]); + return 1; + } + break; + case 'c': + if (strcmp("UC",optarg)==0) + user_param.connection_type=UC; + if (strcmp("UD",optarg)==0) + user_param.connection_type=UD; + /* default is 0 for any other option RC*/ + break; + case 'm': + user_param.mtu = strtol(optarg, NULL, 0); + break; + case 'l': + user_param.signal_comp = SIGNAL; + break; + case 'a': + user_param.all = SIGNAL; + break; + case 'V': + printf("perftest version : %.2f\n",VERSION); + return 0; + break; + case 'd': + ib_devname = _strdup(optarg); + break; + + case 'i': + ib_port = strtol(optarg, NULL, 0); + if (ib_port < 0) { + usage(argv[0]); + return 2; + } + break; + + case 's': + size = strtol(optarg, NULL, 0); + if (size < 1) { + usage(argv[0]); return 3; + } + break; + + case 't': + user_param.tx_depth = strtol(optarg, NULL, 0); + if (user_param.tx_depth < 1) { + usage(argv[0]); return 4; + } + break; + + case 'n': + user_param.iters = strtol(optarg, NULL, 0); + if (user_param.iters < 2) { + usage(argv[0]); + return 5; + } + + break; + + case 'C': + report.cycles = 1; + break; + + case 'H': + report.histogram = 1; + break; + + case 'U': + report.unsorted = 1; + break; + + default: + usage(argv[0]); + return 5; + } + } + + if (optind == argc - 1) + user_param.servername = _strdup(argv[optind]); + else if (optind < argc) { + usage(argv[0]); + return 6; + } + + /* + * Done with parameter parsing. Perform setup. + */ + tstamp = malloc(user_param.iters * sizeof *tstamp); + if (!tstamp) { + perror("malloc"); + return 10; + } + /* Print header data */ + printf("------------------------------------------------------------------\n"); + printf(" Send Latency Test\n"); + printf("Inline data is used up to 400 bytes message\n"); + if (user_param.connection_type==RC) { + printf("Connection type : RC\n"); + } else if (user_param.connection_type==UC) { + printf("Connection type : UC\n"); + } else { + printf("Connection type : UD\n"); + } + + /* Done with parameter parsing. Perform setup. */ + + // Initialize Winsock + iResult = WSAStartup(MAKEWORD(2,2), &wsaData); + if (iResult != NO_ERROR) { + printf("Error at WSAStartup()\n"); + return 1; + } + + + if (user_param.all == ALL && user_param.connection_type!=UD) { + /*since we run all sizes */ + printf("test\n"); + size = 8388608; /*2^23 */ + } else if (user_param.connection_type==UD ) { + printf("Max msg size in UD is 2048 changing to 2048\n"); + size = 2048; + } + + srand(GetCurrentProcessId() * GetTickCount()); + + //TODO: get pagesize from sysinfo + page_size = 4096; + + //TODO get the device names + + ctx = pp_init_ctx( size, ib_port,&user_param); + if (!ctx) + return 8; + + sockfd = pp_open_port(ctx, user_param.servername, ib_port, port,&my_dest,&rem_dest,&user_param); + if (sockfd == INVALID_SOCKET) + return 9; + + +#if PORTED + if (user_param.use_event) { + printf("Test with events.\n"); + if (ibv_req_notify_cq(ctx->rcq, 0)) { + fprintf(stderr, "Couldn't request RCQ notification\n"); + return 1; + } + if (ibv_req_notify_cq(ctx->scq, 0)) { + fprintf(stderr, "Couldn't request SCQ notification\n"); + return 1; + } + } +#endif + + printf("------------------------------------------------------------------\n"); + printf(" #bytes #iterations t_min[usec] t_max[usec] t_typical[usec]\n"); + + if (user_param.all == 1) { + if (user_param.connection_type==UD) { + size_max_pow = 12; + } + for (i = 1; i < size_max_pow ; ++i) { + size = 1 << i; + if(run_iter(ctx, &user_param, rem_dest, size)) + return 17; + + print_report(&report, user_param.iters, tstamp, size); + } + } else { + if(run_iter(ctx, &user_param, rem_dest, size)) + return 18; + print_report(&report, user_param.iters, tstamp, size); + } + printf("------------------------------------------------------------------\n"); + + send(sockfd, "done", sizeof "done",0); + closesocket(sockfd); + + + free(tstamp); + return 0; +} diff --git a/branches/WOF2-3/tools/perftests/user/send_lat/send_lat.rc b/branches/WOF2-3/tools/perftests/user/send_lat/send_lat.rc new file mode 100644 index 00000000..f661becc --- /dev/null +++ b/branches/WOF2-3/tools/perftests/user/send_lat/send_lat.rc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef _DEBUG_ +#define VER_FILEDESCRIPTION_STR "Send/Recv Latency Test (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "Send/Recv Latency Test " +#endif + +#define VER_INTERNALNAME_STR "ib_send_lat.exe" +#define VER_ORIGINALFILENAME_STR "ib_send_lat.exe" + +#include diff --git a/branches/WOF2-3/tools/perftests/user/write_bw/SOURCES b/branches/WOF2-3/tools/perftests/user/write_bw/SOURCES new file mode 100644 index 00000000..4e9a6794 --- /dev/null +++ b/branches/WOF2-3/tools/perftests/user/write_bw/SOURCES @@ -0,0 +1,28 @@ +TARGETNAME=ib_write_bw +TARGETPATH=..\..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE=PROGRAM +UMTYPE=console +USE_MSVCRT=1 + +C_DEFINES=$(C_DEFINES) /D__WIN__ + +SOURCES=write_bw.rc \ + ..\getopt.c \ + ..\perf_utils.c \ + write_bw.c + +INCLUDES=..;..\..\..\..\inc;..\..\..\..\inc\user + +RCOPTIONS=/I..\..\win\include + +TARGETLIBS= \ + $(DDK_LIB_PATH)\Ws2_32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\complib.lib \ + $(TARGETPATH)\*\ibal.lib +!else + $(TARGETPATH)\*\complibd.lib \ + $(TARGETPATH)\*\ibald.lib +!endif + +MSC_WARNING_LEVEL= /W3 diff --git a/branches/WOF2-3/tools/perftests/user/write_bw/makefile b/branches/WOF2-3/tools/perftests/user/write_bw/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-3/tools/perftests/user/write_bw/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\..\inc\openib.def diff --git a/branches/WOF2-3/tools/perftests/user/write_bw/write_bw.c b/branches/WOF2-3/tools/perftests/user/write_bw/write_bw.c new file mode 100644 index 00000000..8dde1593 --- /dev/null +++ b/branches/WOF2-3/tools/perftests/user/write_bw/write_bw.c @@ -0,0 +1,881 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies Ltd. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include "getopt.h" +#include "perf_defs.h" +#include "get_clock.h" + + + +struct user_parameters { + const char *servername; + int connection_type; + int mtu; + int all; /* run all msg size */ + int iters; + int tx_depth; + int numofqps; + int maxpostsofqpiniteration; +}; + +static int page_size; + +cycles_t *tposted; +cycles_t *tcompleted; + + +void +pp_cq_comp_cb( + IN const ib_cq_handle_t h_cq, + IN void *cq_context ) +{ + UNUSED_PARAM( h_cq ); + UNUSED_PARAM( cq_context); + return ; +} +static struct pingpong_context *pp_init_ctx(unsigned size, int port, struct user_parameters *user_parm) +{ + + struct pingpong_context *ctx; + ib_api_status_t ib_status = IB_SUCCESS; + size_t guid_count; + ib_net64_t *ca_guid_array; + int counter; + + ctx = malloc(sizeof *ctx); + if (!ctx){ + perror("malloc"); + return NULL; + } + memset(ctx, 0, sizeof(struct pingpong_context)); + ctx->size = size; + ctx->tx_depth = user_parm->tx_depth; + + ctx->qp = malloc(sizeof (ib_qp_handle_t) * user_parm->numofqps ); + if (!ctx->qp) { + perror("malloc"); + return NULL; + } + ctx->qp_attr = malloc(sizeof (ib_qp_attr_t) * user_parm->numofqps ); + if (!ctx->qp_attr) { + perror("malloc"); + return NULL; + } + + ctx->scnt = malloc(user_parm->numofqps * sizeof (int)); + if (!ctx->scnt) { + perror("malloc"); + return NULL; + } + ctx->ccnt = malloc(user_parm->numofqps * sizeof (int)); + if (!ctx->ccnt) { + perror("malloc"); + return NULL; + } + memset(ctx->scnt, 0, user_parm->numofqps * sizeof (int)); + memset(ctx->ccnt, 0, user_parm->numofqps * sizeof (int)); + + ctx->buf = malloc( size * 2 * user_parm->numofqps ); + if (!ctx->buf) { + fprintf(stderr, "Couldn't allocate work buf.\n"); + return NULL; + } + + memset(ctx->buf, 0, size * 2 * user_parm->numofqps); + + + + /* + * Open the AL instance + */ + ib_status = ib_open_al(&ctx->al); + if(ib_status != IB_SUCCESS) + { + fprintf(stderr,"ib_open_al failed status = %d\n", ib_status); + return NULL; + } + + /* + * Get the Local CA Guids + */ + ib_status = ib_get_ca_guids(ctx->al, NULL, &guid_count); + if(ib_status != IB_INSUFFICIENT_MEMORY) + { + fprintf(stderr,"ib_get_ca_guids1 failed status = %d\n", (uint32_t)ib_status); + return NULL; + } + + /* + * If no CA's Present then return + */ + + if(guid_count == 0) + return NULL; + + + ca_guid_array = (ib_net64_t*)malloc(sizeof(ib_net64_t) * guid_count); + + ib_status = ib_get_ca_guids(ctx->al, ca_guid_array, &guid_count); + if(ib_status != IB_SUCCESS) + { + fprintf(stderr,"ib_get_ca_guids2 failed with status = %d\n", ib_status); + return NULL; + } + + /* + * Open only the first HCA + */ + /* Open the CA */ + ib_status = ib_open_ca(ctx->al ,ca_guid_array[0] ,NULL, + NULL, //ca_context + &ctx->ca); + + if(ib_status != IB_SUCCESS) + { + fprintf(stderr,"ib_open_ca failed with status = %d\n", ib_status); + return NULL; + } + + //xxx + //printf("ib_open_ca passed i=%d\n",i); + //xxx + + + + + { + /* Query the CA */ + uint32_t bsize = 0; + ib_status = ib_query_ca(ctx->ca, NULL, &bsize); + if(ib_status != IB_INSUFFICIENT_MEMORY) + { + fprintf(stderr, "Failed to query device props"); + return NULL; + } + + ctx->ca_attr = (ib_ca_attr_t *)malloc(bsize); + + ib_status = ib_query_ca(ctx->ca, ctx->ca_attr, &bsize); + if(ib_status != IB_SUCCESS) + { + printf("ib_query_ca failed with status = %d\n", ib_status); + return NULL; + } + if (user_parm->mtu == 0) {/*user did not ask for specific mtu */ + if (ctx->ca_attr->dev_id == 23108) { + user_parm->mtu = 1024; + } else { + user_parm->mtu = 2048; + } + } + } + + + ib_status = ib_alloc_pd(ctx->ca , + IB_PDT_NORMAL, + ctx, //pd_context + &ctx->pd); + if (ib_status != IB_SUCCESS) { + fprintf(stderr, "Couldn't allocate PD\n"); + return NULL; + } + + + { + ib_mr_create_t mr_create; + + mr_create.length = size * 2; + + mr_create.vaddr = ctx->buf; + mr_create.access_ctrl = IB_AC_RDMA_WRITE| IB_AC_LOCAL_WRITE; + + ib_status = ib_reg_mem(ctx->pd ,&mr_create ,&ctx->lkey ,&ctx->rkey ,&ctx->mr); + if (ib_status != IB_SUCCESS) { + fprintf(stderr, "Couldn't allocate MR\n"); + return NULL; + } + } + + { + ib_cq_create_t cq_create; + + cq_create.size = user_parm->tx_depth * user_parm->numofqps; + cq_create.h_wait_obj = NULL; + cq_create.pfn_comp_cb = pp_cq_comp_cb; + ib_status = ib_create_cq(ctx->ca,&cq_create ,ctx, NULL, &ctx->scq); + if (ib_status != IB_SUCCESS) { + fprintf(stderr, "Couldn't create CQ ib_status = %d\n",ib_status); + return NULL; + } + } + + + + + for (counter =0 ; counter < user_parm->numofqps ; counter++) + { + + ib_qp_create_t qp_create; + ib_qp_mod_t qp_modify; + ib_qp_attr_t qp_attr; + + memset(&qp_create, 0, sizeof(ib_qp_create_t)); + qp_create.h_sq_cq = ctx->scq; + qp_create.h_rq_cq = ctx->scq; + qp_create.sq_depth = user_parm->tx_depth; + qp_create.rq_depth = user_parm->tx_depth; + qp_create.sq_sge = 1; + qp_create.rq_sge = 1; + //TODO MAX_INLINE + + switch (user_parm->connection_type) { + case RC : + qp_create.qp_type= IB_QPT_RELIABLE_CONN; + break; + case UC : + qp_create.qp_type = IB_QPT_UNRELIABLE_CONN; + break; + default: + fprintf(stderr, "Unknown connection type %d \n",user_parm->connection_type); + return NULL; + } + + qp_create.sq_signaled = FALSE; + /*attr.sq_sig_all = 0;*/ + + ib_status = ib_create_qp(ctx->pd, &qp_create,NULL,NULL,&ctx->qp[counter]); + if (ib_status != IB_SUCCESS){ + fprintf(stderr, "Couldn't create QP\n"); + return NULL; + } + + + + + memset(&qp_modify, 0, sizeof(ib_qp_mod_t)); + qp_modify.req_state = IB_QPS_INIT; + qp_modify.state.init.pkey_index = 0 ; + qp_modify.state.init.primary_port = (uint8_t)port; + qp_modify.state.init.access_ctrl = IB_AC_RDMA_WRITE | IB_AC_LOCAL_WRITE; + + + ib_status = ib_modify_qp(ctx->qp[counter], &qp_modify); + if (ib_status != IB_SUCCESS){ + fprintf(stderr, "Failed to modify QP to INIT\n"); + return NULL; + } + + + memset(&qp_attr, 0, sizeof(ib_qp_attr_t)); + ib_status = ib_query_qp(ctx->qp[counter], &ctx->qp_attr[counter]); + if (ib_status != IB_SUCCESS){ + fprintf(stderr, "Failed to modify QP to INIT\n"); + return NULL; + } + fprintf(stderr, "max inline size %d\n",ctx->qp_attr[counter].sq_max_inline); + } + + return ctx; +} + + +static int pp_connect_ctx(struct pingpong_context *ctx, int port, int my_psn, + struct pingpong_dest *dest, struct user_parameters *user_parm, int qpindex) +{ + + ib_api_status_t ib_status; + ib_qp_mod_t attr; + memset(&attr, 0, sizeof(ib_qp_mod_t)); + + attr.req_state = IB_QPS_RTR; + switch (user_parm->mtu) { + case 256 : + attr.state.rtr.primary_av.conn.path_mtu = IB_MTU_LEN_256; + break; + case 512 : + attr.state.rtr.primary_av.conn.path_mtu = IB_MTU_LEN_512; + break; + case 1024 : + attr.state.rtr.primary_av.conn.path_mtu = IB_MTU_LEN_1024; + break; + case 2048 : + attr.state.rtr.primary_av.conn.path_mtu = IB_MTU_LEN_2048; + break; + } + printf("Mtu : %d\n", user_parm->mtu); + attr.state.rtr.dest_qp = dest->qpn;; + attr.state.rtr.rq_psn = dest->psn; + if (user_parm->connection_type==RC) { + attr.state.rtr.resp_res = 1; + attr.state.rtr.rnr_nak_timeout = 12; + } + attr.state.rtr.primary_av.grh_valid = 0; + attr.state.rtr.primary_av.dlid = dest->lid; + attr.state.rtr.primary_av.sl = 0; + attr.state.rtr.primary_av.path_bits = 0; + attr.state.rtr.primary_av.port_num = (uint8_t)port; + attr.state.rtr.primary_av.static_rate = IB_PATH_RECORD_RATE_10_GBS; + attr.state.rtr.opts = IB_MOD_QP_LOCAL_ACK_TIMEOUT | + IB_MOD_QP_RESP_RES | + IB_MOD_QP_PRIMARY_AV; + + + ib_status = ib_modify_qp(ctx->qp[qpindex], &attr); + if(ib_status != IB_SUCCESS){ + fprintf(stderr, "Failed to modify QP to RTR\n"); + return 1; + } + + memset(&attr, 0, sizeof(ib_qp_mod_t)); + attr.req_state = IB_QPS_RTS; + attr.state.rts.sq_psn = my_psn; + + if (user_parm->connection_type == RC) { + attr.state.rts.init_depth = 1; + attr.state.rts.local_ack_timeout = 14; + attr.state.rts.retry_cnt = 7; + attr.state.rts.rnr_retry_cnt = 7; + attr.state.rts.opts = IB_MOD_QP_RNR_RETRY_CNT | + IB_MOD_QP_RETRY_CNT | + IB_MOD_QP_INIT_DEPTH | + IB_MOD_QP_LOCAL_ACK_TIMEOUT; + + } + ib_status = ib_modify_qp(ctx->qp[qpindex], &attr); + if(ib_status != IB_SUCCESS){ + fprintf(stderr, "Failed to modify QP to RTS\n"); + return 1; + } + + return 0; + +} + +static SOCKET pp_open_port(struct pingpong_context *ctx, const char * servername, + int ib_port, int port, struct pingpong_dest **p_my_dest, + struct pingpong_dest **p_rem_dest,struct user_parameters *user_parm) +{ + struct pingpong_dest *my_dest; + struct pingpong_dest *rem_dest; + SOCKET sockfd; + int rc; + int i; + int numofqps = user_parm->numofqps; + + /* Create connection between client and server. + * We do it by exchanging data over a TCP socket connection. */ + + + my_dest = malloc( sizeof (struct pingpong_dest) * numofqps); + if (!my_dest){ + perror("malloc"); + return INVALID_SOCKET; + } + memset( my_dest, 0, sizeof (struct pingpong_dest) * numofqps ); + + rem_dest = malloc(sizeof (struct pingpong_dest) * numofqps ); + if (!rem_dest){ + perror("malloc"); + return INVALID_SOCKET; + } + memset( rem_dest, 0, sizeof (struct pingpong_dest) * numofqps ); + + sockfd = servername ? pp_client_connect(servername, port) : + pp_server_connect(port); + + if (sockfd == INVALID_SOCKET) { + printf("pp_connect_sock(%s,%d) failed (%d)!\n", + servername, port, sockfd); + return INVALID_SOCKET; + } + + + for (i =0 ;ica_attr->p_port_attr[ib_port-1].lid; + my_dest[i].psn = cl_hton32(rand() & 0xffffff); + if (!my_dest[i].lid) { + fprintf(stderr, "Local lid 0x0 detected. Is an SM running?\n"); + return 1; + } + my_dest[i].qpn = ctx->qp_attr[i].num; + /* TBD this should be changed inot VA and different key to each qp */ + my_dest[i].rkey = ctx->rkey; + my_dest[i].vaddr = (uintptr_t)ctx->buf + ctx->size; + + printf(" local address: LID %#04x, QPN %#06x, PSN %#06x, " + "RKey %#08x VAddr %#016Lx\n", + my_dest[i].lid, my_dest[i].qpn, my_dest[i].psn, + my_dest[i].rkey, my_dest[i].vaddr); + + rc = servername ? pp_client_exch_dest(sockfd, &my_dest[i],&rem_dest[i]): + pp_server_exch_dest(sockfd, &my_dest[i],&rem_dest[i]); + if (rc) + return INVALID_SOCKET; + printf(" remote address: LID %#04x, QPN %#06x, PSN %#06x, " + "RKey %#08x VAddr %#016Lx\n", + rem_dest[i].lid, rem_dest[i].qpn, rem_dest[i].psn, + rem_dest[i].rkey, rem_dest[i].vaddr); + + if (pp_connect_ctx(ctx, ib_port, my_dest[i].psn, &rem_dest[i], user_parm, i)) + return INVALID_SOCKET; + /* An additional handshake is required *after* moving qp to RTR. + Arbitrarily reuse exch_dest for this purpose. */ + rc = servername ? pp_client_exch_dest(sockfd, &my_dest[i],&rem_dest[i]): + pp_server_exch_dest(sockfd, &my_dest[i],&rem_dest[i]); + if (rc) + return INVALID_SOCKET; + } + *p_rem_dest = rem_dest; + *p_my_dest = my_dest; + return sockfd; +} + + +static void usage(const char *argv0) +{ + printf("Usage:\n"); + printf(" %s start a server and wait for connection\n", argv0); + printf(" %s connect to server at \n", argv0); + printf("\n"); + printf("Options:\n"); + printf(" -p, --port= listen on/connect to port (default 18515)\n"); + printf(" -i, --ib-port= use port of IB device (default 1)\n"); + printf(" -c, --connection= connection type RC/UC (default RC)\n"); + printf(" -m, --mtu= mtu size (default 1024)\n"); + printf(" -g, --post= number of posts for each qp in the chain (default tx_depth)\n"); + printf(" -q, --qp= Num of qp's(default 1)\n"); + printf(" -s, --size= size of message to exchange (default 65536)\n"); + printf(" -a, --all Run sizes from 2 till 2^23\n"); + printf(" -t, --tx-depth= size of tx queue (default 100)\n"); + printf(" -n, --iters= number of exchanges (at least 2, default 5000)\n"); + printf(" -b, --bidirectional measure bidirectional bandwidth (default unidirectional)\n"); + printf(" -V, --version display version number\n"); +} + +static void + print_report(unsigned int iters, unsigned size, int duplex, + cycles_t *tposted, cycles_t *tcompleted, struct user_parameters *user_param) +{ + double cycles_to_units; + uint64_t tsize; /* Transferred size, in megabytes */ + unsigned int i, j; + int opt_posted = 0, opt_completed = 0; + cycles_t opt_delta; + cycles_t t; + + + opt_delta = tcompleted[opt_posted] - tposted[opt_completed]; + + /* Find the peak bandwidth */ + for (i = 0; i < iters * user_param->numofqps; ++i) + for (j = i; j < iters * user_param->numofqps; ++j) { + t = (tcompleted[j] - tposted[i]) / (j - i + 1); + if (t < opt_delta) { + opt_delta = t; + opt_posted = i; + opt_completed = j; + } + } + + + cycles_to_units = get_cpu_mhz(); + + tsize = duplex ? 2 : 1; + tsize = tsize * size; + printf("%7d %d %7.2f %7.2f\n", + size,iters,tsize * cycles_to_units / opt_delta / 0x100000, + (uint64_t)tsize * iters * user_param->numofqps * cycles_to_units /(tcompleted[(iters* user_param->numofqps) - 1] - tposted[0]) / 0x100000); + +} + + +int run_iter(struct pingpong_context *ctx, struct user_parameters *user_param, + struct pingpong_dest *rem_dest, int size) +{ + ib_api_status_t ib_status; + ib_qp_handle_t qp; + int scnt, ccnt ; + int index; + ib_send_wr_t *bad_wr; + + + + ctx->list.vaddr = (uintptr_t) ctx->buf; + ctx->list.length = size; + ctx->list.lkey = ctx->lkey; + + ctx->wr.ds_array = &ctx->list; + ctx->wr.num_ds= 1; + ctx->wr.wr_type = WR_RDMA_WRITE; + + if ((uint32_t)size > ctx->qp_attr[0].sq_max_inline) { /*complaince to perf_main */ + ctx->wr.send_opt = IB_SEND_OPT_SIGNALED; + } else { + ctx->wr.send_opt = IB_SEND_OPT_SIGNALED | IB_SEND_OPT_INLINE; + } + ctx->wr.p_next = NULL; + + scnt = 0; + ccnt = 0; + /*clear the scnt ccnt counters for each iteration*/ + for (index =0 ; index < user_param->numofqps ; index++) { + ctx->scnt[index] = 0; + ctx->ccnt[index] = 0; + } + index = 0; + + + /* main loop for posting */ + while (scnt < (user_param->iters * user_param->numofqps) || + ccnt < (user_param->iters * user_param->numofqps) ) + { + /* main loop to run over all the qps and post each time n messages */ + for (index =0 ; index < user_param->numofqps ; index++) { + + ctx->wr.remote_ops.vaddr = rem_dest[index].vaddr; + ctx->wr.remote_ops.rkey = rem_dest[index].rkey; + qp = ctx->qp[index]; + ctx->wr.wr_id = index ; + + while (ctx->scnt[index] < user_param->iters && + (ctx->scnt[index] - ctx->ccnt[index]) < user_param->maxpostsofqpiniteration) + { + //if(ctx->scnt[index] - ctx->ccnt[index] < 10 ) + // fprintf(stderr, "Lower WQEs: qp index = %d qp scnt=%d total scnt %d qp ccnt=%d total ccnt %d\n", + // index,ctx->scnt[index],scnt,ctx->ccnt[index],ccnt); + tposted[scnt] = get_cycles(); + ib_status = ib_post_send(qp, &ctx->wr, &bad_wr); + if (ib_status != IB_SUCCESS) + { + fprintf(stderr, "Couldn't post send: qp index = %d qp scnt=%d total scnt %d qp ccnt=%d total ccnt %d\n", + index,ctx->scnt[index],scnt,ctx->ccnt[index],ccnt); + return 1; + } + ctx->scnt[index]= ctx->scnt[index]+1; + ++scnt; + PERF_DEBUG("scnt = %d \n",scnt); + } + + } + + /* finished posting now polling */ + if (ccnt < (user_param->iters * user_param->numofqps) ) + { + ib_wc_t wc; + ib_wc_t *p_wc_done,*p_wc_free; + + p_wc_free = &wc; + p_wc_done = NULL; + p_wc_free->p_next = NULL; + + do{ + ib_status = ib_poll_cq(ctx->scq, &p_wc_free, &p_wc_done); + if (ib_status == IB_SUCCESS) { + tcompleted[ccnt] = get_cycles(); + if (p_wc_done->status != IB_WCS_SUCCESS) { + fprintf(stderr, "Completion wth error at %s:\n", + user_param->servername ? "client" : "server"); + fprintf(stderr, "Failed status %d: wr_id %d syndrom 0x%x\n", + p_wc_done->status, (int) p_wc_done->wr_id, p_wc_done->vendor_specific); + return 1; + } + + /*here the id is the index to the qp num */ + ctx->ccnt[(int)wc.wr_id] = ctx->ccnt[(int)wc.wr_id]+1; + ++ccnt; + PERF_DEBUG("ccnt = %d \n",ccnt); + p_wc_free = p_wc_done; + p_wc_free->p_next = NULL; + p_wc_done = NULL; + } + + + } while (ib_status == IB_SUCCESS); + + if (ib_status != IB_NOT_FOUND) { + fprintf(stderr, "Poll Receive CQ failed %d\n", ib_status); + return 12; + } + + + + } + } + return(0); +} + + +int __cdecl main(int argc, char *argv[]) +{ + struct pingpong_context *ctx; + struct pingpong_dest *my_dest; + struct pingpong_dest *rem_dest; + struct user_parameters user_param; + char *ib_devname = NULL; + int port = 18515; + int ib_port = 1; + unsigned size = 65536; + SOCKET sockfd = INVALID_SOCKET; + WSADATA wsaData; + int iResult; + int i = 0; + int duplex = 0; + + + /* init default values to user's parameters */ + memset(&user_param, 0, sizeof(struct user_parameters)); + user_param.mtu = 0; + user_param.iters = 5000; + user_param.tx_depth = 100; + user_param.servername = NULL; + user_param.numofqps = 1; + user_param.maxpostsofqpiniteration = 100; + + /* Parameter parsing. */ + while (1) { + int c; + + static struct option long_options[] = { + { "port", 1, NULL, 'p' }, + { "ib-dev", 1, NULL, 'd' }, + { "ib-port", 1, NULL, 'i' }, + { "mtu", 1, NULL, 'm' }, + { "qp", 1, NULL, 'q' }, + { "post", 1, NULL, 'g' }, + { "connection", 1, NULL, 'c' }, + { "size", 1, NULL, 's' }, + { "iters", 1, NULL, 'n' }, + { "tx-depth", 1, NULL, 't' }, + { "all", 0, NULL, 'a' }, + { "bidirectional", 0, NULL, 'b' }, + { "version", 0, NULL, 'V' }, + { 0 } + }; + + c = getopt_long(argc, argv, "p:d:i:m:q:g:c:s:n:t:baV", long_options, NULL); + if (c == -1) + break; + + switch (c) { + case 'p': + port = strtol(optarg, NULL, 0); + if (port < 0 || port > 65535) { + usage(argv[0]); + return 1; + } + break; + + case 'd': + ib_devname = _strdup(optarg); + break; + case 'c': + if (strcmp("UC",optarg)==0) + user_param.connection_type=UC; + break; + + case 'm': + user_param.mtu = strtol(optarg, NULL, 0); + break; + case 'q': + user_param.numofqps = strtol(optarg, NULL, 0); + break; + case 'g': + user_param.maxpostsofqpiniteration = strtol(optarg, NULL, 0); + break; + case 'a': + user_param.all = ALL; + break; + case 'V': + printf("rdma_bw version : %.2f\n",VERSION); + return 0; + break; + case 'i': + ib_port = strtol(optarg, NULL, 0); + if (ib_port < 0) { + usage(argv[0]); + return 2; + } + break; + + case 's': + size = strtol(optarg, NULL, 0); + if (size < 1 || size > UINT_MAX / 2) { + usage(argv[0]); + return 1; + } + break; + + case 't': + user_param.tx_depth = strtol(optarg, NULL, 0); + if (user_param.tx_depth < 1) { + usage(argv[0]); return 4; + } + break; + + case 'n': + user_param.iters = strtol(optarg, NULL, 0); + if (user_param.iters < 2) { + usage(argv[0]); + return 5; + } + + break; + + case 'b': + duplex = 1; + break; + + default: + usage(argv[0]); + return 5; + } + } + + if (optind == argc - 1) + user_param.servername = _strdup(argv[optind]); + else if (optind < argc) { + usage(argv[0]); + return 6; + } + + printf("------------------------------------------------------------------\n"); + if (duplex == 1) { + printf(" RDMA_Write Bidirectional BW Test\n"); + } else { + printf(" RDMA_Write BW Test\n"); + } + + printf("Number of qp's running %d\n",user_param.numofqps); + printf("Number of iterations %d\n",user_param.iters); + printf("Massege size %d\n",size); + if (user_param.connection_type==RC) { + printf("Connection type : RC\n"); + } else { + printf("Connection type : UC\n"); + } + if (user_param.maxpostsofqpiniteration > user_param.tx_depth ) { + printf("Can not post more than tx_depth , adjusting number of post to tx_depth\n"); + user_param.maxpostsofqpiniteration = user_param.tx_depth; + } else { + printf("Each Qp will post up to %d messages each time\n",user_param.maxpostsofqpiniteration); + } + /* Done with parameter parsing. Perform setup. */ + + // Initialize Winsock + iResult = WSAStartup(MAKEWORD(2,2), &wsaData); + if (iResult != NO_ERROR) { + printf("Error at WSAStartup()\n"); + return 1; + } + + + if (user_param.all == ALL) { + /*since we run all sizes lets allocate big enough buffer */ + size = 8388608; /*2^23 */ + } + srand(GetCurrentProcessId() * GetTickCount()); + + //TODO: get pagesize from sysinfo + page_size = 4096; + + //TODO get the device names + + + ctx = pp_init_ctx(size, ib_port, &user_param); + if (!ctx) + return 8; + sockfd = pp_open_port(ctx, user_param.servername, ib_port, port,&my_dest,&rem_dest,&user_param); + if (sockfd == INVALID_SOCKET) + return 9; + + + printf("------------------------------------------------------------------\n"); + printf(" #bytes #iterations BW peak[MB/sec] BW average[MB/sec] \n"); + /* For half duplex tests, server just waits for client to exit */ + /* use dummy my_dest struct*/ + if (!user_param.servername && !duplex) { + pp_server_exch_dest(sockfd, my_dest,rem_dest); + send(sockfd, "done", sizeof "done",0); + closesocket(sockfd); + return 0; + } + + tposted = malloc(user_param.iters * user_param.numofqps * sizeof *tposted); + + if (!tposted) { + perror("malloc"); + return 1; + } + + tcompleted = malloc(user_param.iters * user_param.numofqps * sizeof *tcompleted); + + if (!tcompleted) { + perror("malloc"); + return 1; + } + + if (user_param.all == ALL) { + for (i = 1; i < 24 ; ++i) { + size = 1 << i; + if(run_iter(ctx, &user_param, rem_dest, size)) + return 17; + print_report(user_param.iters, size, duplex, tposted, tcompleted, &user_param); + } + } else { + if(run_iter(ctx, &user_param, rem_dest, size)) + return 18; + print_report(user_param.iters, size, duplex, tposted, tcompleted, &user_param); + + } + + /* use dummy my_dest struct*/ + if (user_param.servername) { + pp_client_exch_dest(sockfd, my_dest,rem_dest); + } else { + pp_server_exch_dest(sockfd, my_dest,rem_dest); + } + send(sockfd, "done", sizeof "done",0); + closesocket(sockfd); + + free(tposted); + free(tcompleted); + printf("------------------------------------------------------------------\n"); + return 0; +} diff --git a/branches/WOF2-3/tools/perftests/user/write_bw/write_bw.rc b/branches/WOF2-3/tools/perftests/user/write_bw/write_bw.rc new file mode 100644 index 00000000..98e02bb3 --- /dev/null +++ b/branches/WOF2-3/tools/perftests/user/write_bw/write_bw.rc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef _DEBUG_ +#define VER_FILEDESCRIPTION_STR "RDMA write Bandwidth Test (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "RDMA write Bandwidth Test " +#endif + +#define VER_INTERNALNAME_STR "ib_write_bw.exe" +#define VER_ORIGINALFILENAME_STR "ib_write_bw.exe" + +#include diff --git a/branches/WOF2-3/tools/perftests/user/write_lat/SOURCES b/branches/WOF2-3/tools/perftests/user/write_lat/SOURCES new file mode 100644 index 00000000..77075732 --- /dev/null +++ b/branches/WOF2-3/tools/perftests/user/write_lat/SOURCES @@ -0,0 +1,28 @@ +TARGETNAME=ib_write_lat +TARGETPATH=..\..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE=PROGRAM +UMTYPE=console +USE_MSVCRT=1 + +C_DEFINES=$(C_DEFINES) /D__WIN__ + +SOURCES=write_lat.rc \ + ..\getopt.c \ + ..\perf_utils.c \ + write_lat.c + +INCLUDES=..;..\..\..\..\inc;..\..\..\..\inc\user + +RCOPTIONS=/I..\..\win\include + +TARGETLIBS= \ + $(DDK_LIB_PATH)\Ws2_32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\complib.lib \ + $(TARGETPATH)\*\ibal.lib +!else + $(TARGETPATH)\*\complibd.lib \ + $(TARGETPATH)\*\ibald.lib +!endif + +MSC_WARNING_LEVEL= /W3 diff --git a/branches/WOF2-3/tools/perftests/user/write_lat/makefile b/branches/WOF2-3/tools/perftests/user/write_lat/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-3/tools/perftests/user/write_lat/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\..\inc\openib.def diff --git a/branches/WOF2-3/tools/perftests/user/write_lat/write_lat.c b/branches/WOF2-3/tools/perftests/user/write_lat/write_lat.c new file mode 100644 index 00000000..5eb21aff --- /dev/null +++ b/branches/WOF2-3/tools/perftests/user/write_lat/write_lat.c @@ -0,0 +1,849 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies Ltd. All rights reserved. + * Copyright (c) 2005 Hewlett Packard, Inc (Grant Grundler) + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include "getopt.h" +#include "perf_defs.h" +#include "get_clock.h" + + + +struct user_parameters { + const char *servername; + int connection_type; + int mtu; + int all; /* run all msg size */ + int iters; + int tx_depth; + int stamp_freq; /* to measure once in 'stamp_freq' iterations */ +}; + +static int page_size; + +cycles_t *tstamp; + + + +void +pp_cq_comp_cb( + IN const ib_cq_handle_t h_cq, + IN void *cq_context ) +{ + UNUSED_PARAM( h_cq ); + UNUSED_PARAM( cq_context); + return ; +} + + +static struct pingpong_context *pp_init_ctx(unsigned size, int port, struct user_parameters *user_parm) +{ + + + struct pingpong_context *ctx; + ib_api_status_t ib_status = IB_SUCCESS; + size_t guid_count; + ib_net64_t *ca_guid_array; + + ctx = malloc(sizeof *ctx); + if (!ctx){ + perror("malloc"); + return NULL; + } + memset(ctx, 0, sizeof(struct pingpong_context)); + ctx->size = size; + ctx->tx_depth = user_parm->tx_depth; + + ctx->qp = malloc(sizeof (ib_qp_handle_t)); + if (!ctx->qp) { + perror("malloc"); + return NULL; + } + ctx->qp_attr = malloc(sizeof (ib_qp_attr_t)); + if (!ctx->qp_attr) { + perror("malloc"); + return NULL; + } + + ctx->buf = malloc( size * 2); + if (!ctx->buf) { + fprintf(stderr, "Couldn't allocate work buf.\n"); + return NULL; + } + + memset(ctx->buf, 0, size * 2); + ctx->post_buf = (char*)ctx->buf + (size - 1); + ctx->poll_buf = (char*)ctx->buf + (2 * size - 1); + + + + /* + * Open the AL instance + */ + ib_status = ib_open_al(&ctx->al); + if(ib_status != IB_SUCCESS) + { + fprintf(stderr,"ib_open_al failed status = %d\n", ib_status); + return NULL; + } + + /* + * Get the Local CA Guids + */ + ib_status = ib_get_ca_guids(ctx->al, NULL, &guid_count); + if(ib_status != IB_INSUFFICIENT_MEMORY) + { + fprintf(stderr,"ib_get_ca_guids1 failed status = %d\n", (uint32_t)ib_status); + return NULL; + } + + /* + * If no CA's Present then return + */ + + if(guid_count == 0) + return NULL; + + + ca_guid_array = (ib_net64_t*)malloc(sizeof(ib_net64_t) * guid_count); + + ib_status = ib_get_ca_guids(ctx->al, ca_guid_array, &guid_count); + if(ib_status != IB_SUCCESS) + { + fprintf(stderr,"ib_get_ca_guids2 failed with status = %d\n", ib_status); + return NULL; + } + + /* + * Open only the first HCA + */ + /* Open the CA */ + ib_status = ib_open_ca(ctx->al ,ca_guid_array[0] ,NULL, + NULL, //ca_context + &ctx->ca); + + if(ib_status != IB_SUCCESS) + { + fprintf(stderr,"ib_open_ca failed with status = %d\n", ib_status); + return NULL; + } + + //xxx + //printf("ib_open_ca passed i=%d\n",i); + //xxx + + + + + { + /* Query the CA */ + uint32_t bsize = 0; + ib_status = ib_query_ca(ctx->ca, NULL, &bsize); + if(ib_status != IB_INSUFFICIENT_MEMORY) + { + fprintf(stderr, "Failed to query device props"); + return NULL; + } + + ctx->ca_attr = (ib_ca_attr_t *)malloc(bsize); + + ib_status = ib_query_ca(ctx->ca, ctx->ca_attr, &bsize); + if(ib_status != IB_SUCCESS) + { + printf("ib_query_ca failed with status = %d\n", ib_status); + return NULL; + } + if (user_parm->mtu == 0) {/*user did not ask for specific mtu */ + if (ctx->ca_attr->dev_id == 23108) { + user_parm->mtu = 1024; + } else { + user_parm->mtu = 2048; + } + } + } + + + ib_status = ib_alloc_pd(ctx->ca , + IB_PDT_NORMAL, + ctx, //pd_context + &ctx->pd); + if (ib_status != IB_SUCCESS) { + fprintf(stderr, "Couldn't allocate PD\n"); + return NULL; + } + + + { + ib_mr_create_t mr_create; + + mr_create.length = size * 2; + + mr_create.vaddr = ctx->buf; + mr_create.access_ctrl = IB_AC_RDMA_WRITE| IB_AC_LOCAL_WRITE; + + ib_status = ib_reg_mem(ctx->pd ,&mr_create ,&ctx->lkey ,&ctx->rkey ,&ctx->mr); + if (ib_status != IB_SUCCESS) { + fprintf(stderr, "Couldn't allocate MR\n"); + return NULL; + } + } + + { + ib_cq_create_t cq_create; + + cq_create.size = user_parm->tx_depth; + cq_create.h_wait_obj = NULL; + cq_create.pfn_comp_cb = pp_cq_comp_cb; + ib_status = ib_create_cq(ctx->ca,&cq_create ,ctx, NULL, &ctx->scq); + if (ib_status != IB_SUCCESS) { + fprintf(stderr, "Couldn't create CQ ib_status = %d\n",ib_status); + return NULL; + } + } + + { + + ib_qp_create_t qp_create; + ib_qp_mod_t qp_modify; + ib_qp_attr_t qp_attr; + + memset(&qp_create, 0, sizeof(ib_qp_create_t)); + qp_create.h_sq_cq = ctx->scq; + qp_create.h_rq_cq = ctx->scq; + qp_create.sq_depth = user_parm->tx_depth; + qp_create.rq_depth = 1; + qp_create.sq_sge = 1; + qp_create.rq_sge = 1; + //TODO MAX_INLINE + + switch (user_parm->connection_type) { + case RC : + qp_create.qp_type= IB_QPT_RELIABLE_CONN; + break; + case UC : + qp_create.qp_type = IB_QPT_UNRELIABLE_CONN; + break; + default: + fprintf(stderr, "Unknown connection type %d \n",user_parm->connection_type); + return NULL; + } + + qp_create.sq_signaled = FALSE; + /*attr.sq_sig_all = 0;*/ + + ib_status = ib_create_qp(ctx->pd, &qp_create,NULL,NULL,&ctx->qp[0]); + if (ib_status != IB_SUCCESS){ + fprintf(stderr, "Couldn't create QP\n"); + return NULL; + } + + + + + memset(&qp_modify, 0, sizeof(ib_qp_mod_t)); + qp_modify.req_state = IB_QPS_INIT; + qp_modify.state.init.pkey_index = 0 ; + qp_modify.state.init.primary_port = (uint8_t)port; + qp_modify.state.init.access_ctrl = IB_AC_RDMA_WRITE | IB_AC_LOCAL_WRITE; + + + ib_status = ib_modify_qp(ctx->qp[0], &qp_modify); + if (ib_status != IB_SUCCESS){ + fprintf(stderr, "Failed to modify QP to INIT\n"); + return NULL; + } + + + memset(&qp_attr, 0, sizeof(ib_qp_attr_t)); + ib_status = ib_query_qp(ctx->qp[0], &ctx->qp_attr[0]); + if (ib_status != IB_SUCCESS){ + fprintf(stderr, "Failed to modify QP to INIT\n"); + return NULL; + } + fprintf(stderr, "max inline size %d\n",ctx->qp_attr[0].sq_max_inline); + } + + return ctx; +} + + + + +static int pp_connect_ctx(struct pingpong_context *ctx, int port, int my_psn, + struct pingpong_dest *dest, struct user_parameters *user_parm,int qpindex) +{ + + ib_api_status_t ib_status; + ib_qp_mod_t attr; + memset(&attr, 0, sizeof(ib_qp_mod_t)); + + attr.req_state = IB_QPS_RTR; + switch (user_parm->mtu) { + case 256 : + attr.state.rtr.primary_av.conn.path_mtu = IB_MTU_LEN_256; + break; + case 512 : + attr.state.rtr.primary_av.conn.path_mtu = IB_MTU_LEN_512; + break; + case 1024 : + attr.state.rtr.primary_av.conn.path_mtu = IB_MTU_LEN_1024; + break; + case 2048 : + attr.state.rtr.primary_av.conn.path_mtu = IB_MTU_LEN_2048; + break; + } + printf("Mtu : %d\n", user_parm->mtu); + attr.state.rtr.dest_qp = dest->qpn;; + attr.state.rtr.rq_psn = dest->psn; + if (user_parm->connection_type==RC) { + attr.state.rtr.resp_res = 1; + attr.state.rtr.rnr_nak_timeout = 12; + } + attr.state.rtr.primary_av.grh_valid = 0; + attr.state.rtr.primary_av.dlid = dest->lid; + attr.state.rtr.primary_av.sl = 0; + attr.state.rtr.primary_av.path_bits = 0; + attr.state.rtr.primary_av.port_num = (uint8_t)port; + attr.state.rtr.primary_av.static_rate = IB_PATH_RECORD_RATE_10_GBS; + attr.state.rtr.opts = IB_MOD_QP_LOCAL_ACK_TIMEOUT | + IB_MOD_QP_RESP_RES | + IB_MOD_QP_PRIMARY_AV; + + + ib_status = ib_modify_qp(ctx->qp[0], &attr); + if(ib_status != IB_SUCCESS){ + fprintf(stderr, "Failed to modify QP to RTR\n"); + return 1; + } + + memset(&attr, 0, sizeof(ib_qp_mod_t)); + attr.req_state = IB_QPS_RTS; + attr.state.rts.sq_psn = my_psn; + + if (user_parm->connection_type == RC) { + attr.state.rts.init_depth = 1; + attr.state.rts.local_ack_timeout = 14; + attr.state.rts.retry_cnt = 7; + attr.state.rts.rnr_retry_cnt = 7; + attr.state.rts.opts = IB_MOD_QP_RNR_RETRY_CNT | + IB_MOD_QP_RETRY_CNT | + IB_MOD_QP_INIT_DEPTH | + IB_MOD_QP_LOCAL_ACK_TIMEOUT; + + } + ib_status = ib_modify_qp(ctx->qp[0], &attr); + if(ib_status != IB_SUCCESS){ + fprintf(stderr, "Failed to modify QP to RTS\n"); + return 1; + } + + return 0; + +} + + +static SOCKET pp_open_port(struct pingpong_context *ctx, const char * servername, + int ib_port, int port, struct pingpong_dest **p_my_dest, + struct pingpong_dest **p_rem_dest,struct user_parameters *user_parm) +{ + struct pingpong_dest *my_dest; + struct pingpong_dest *rem_dest; + SOCKET sockfd; + int rc; + int i; + int numofqps = 1; + + /* Create connection between client and server. + * We do it by exchanging data over a TCP socket connection. */ + + + my_dest = malloc( sizeof (struct pingpong_dest) * numofqps); + if (!my_dest){ + perror("malloc"); + return INVALID_SOCKET; + } + memset( my_dest, 0, sizeof (struct pingpong_dest) * numofqps ); + + rem_dest = malloc(sizeof (struct pingpong_dest) * numofqps ); + if (!rem_dest){ + perror("malloc"); + return INVALID_SOCKET; + } + memset( rem_dest, 0, sizeof (struct pingpong_dest) * numofqps ); + + sockfd = servername ? pp_client_connect(servername, port) : + pp_server_connect(port); + + if (sockfd == INVALID_SOCKET) { + printf("pp_connect_sock(%s,%d) failed (%d)!\n", + servername, port, sockfd); + return INVALID_SOCKET; + } + + + for (i =0 ;ica_attr->p_port_attr[ib_port-1].lid; + my_dest[i].psn = cl_hton32(rand() & 0xffffff); + if (!my_dest[i].lid) { + fprintf(stderr, "Local lid 0x0 detected. Is an SM running?\n"); + return 1; + } + my_dest[i].qpn = ctx->qp_attr[i].num; + /* TBD this should be changed inot VA and different key to each qp */ + my_dest[i].rkey = ctx->rkey; + my_dest[i].vaddr = (uintptr_t)ctx->buf + ctx->size; + + printf(" local address: LID %#04x, QPN %#06x, PSN %#06x, " + "RKey %#08x VAddr %#016Lx\n", + my_dest[i].lid, my_dest[i].qpn, my_dest[i].psn, + my_dest[i].rkey, my_dest[i].vaddr); + + rc = servername ? pp_client_exch_dest(sockfd, &my_dest[i],&rem_dest[i]): + pp_server_exch_dest(sockfd, &my_dest[i],&rem_dest[i]); + if (rc) + return INVALID_SOCKET; + printf(" remote address: LID %#04x, QPN %#06x, PSN %#06x, " + "RKey %#08x VAddr %#016Lx\n", + rem_dest[i].lid, rem_dest[i].qpn, rem_dest[i].psn, + rem_dest[i].rkey, rem_dest[i].vaddr); + + if (pp_connect_ctx(ctx, ib_port, my_dest[i].psn, &rem_dest[i], user_parm, i)) + return INVALID_SOCKET; + /* An additional handshake is required *after* moving qp to RTR. + Arbitrarily reuse exch_dest for this purpose. */ + rc = servername ? pp_client_exch_dest(sockfd, &my_dest[i],&rem_dest[i]): + pp_server_exch_dest(sockfd, &my_dest[i],&rem_dest[i]); + if (rc) + return INVALID_SOCKET; + } + *p_rem_dest = rem_dest; + *p_my_dest = my_dest; + return sockfd; +} + +static void usage(const char *argv0) +{ + printf("Usage:\n"); + printf(" %s start a server and wait for connection\n", argv0); + printf(" %s connect to server at \n", argv0); + printf("\n"); + printf("Options:\n"); + printf(" -p, --port= listen on/connect to port (default 18515)\n"); + printf(" -c, --connection= connection type RC/UC (default RC)\n"); + printf(" -m, --mtu= mtu size (default 1024)\n"); + printf(" -i, --ib-port= use port of IB device (default 1)\n"); + printf(" -s, --size= size of message to exchange (default 1)\n"); + printf(" -a, --all Run sizes from 2 till 2^23\n"); + printf(" -t, --tx-depth= size of tx queue (default 50)\n"); + printf(" -f, --freq= frequence of taking of time stamp\n"); + printf(" -n, --iters= number of exchanges (at least 2, default 1000)\n"); + printf(" -C, --report-cycles report times in cpu cycle units (default microseconds)\n"); + printf(" -H, --report-histogram print out all results (default print summary only)\n"); + printf(" -U, --report-unsorted (implies -H) print out unsorted results (default sorted)\n"); + printf(" -V, --version display version number\n"); +} + + + +static void print_report(struct report_options * options, + unsigned int full_iters, cycles_t *tstamp, int size, int freq) +{ + double cycles_to_units; + cycles_t median; + unsigned int i; + const char* units; + unsigned int iters = full_iters / freq; + cycles_t *delta = malloc(iters * sizeof *delta); + + if (!delta) { + perror("malloc"); + return; + } + + for (i = 0; i < iters - 1; ++i) + delta[i] = (tstamp[i + 1] - tstamp[i]); + + if (options->cycles) { + cycles_to_units = 1; + units = "cycles"; + } else { + cycles_to_units = get_cpu_mhz()/1000000; + units = "usec"; + } + + if (options->unsorted) { + printf("#, %s\n", units); + for (i = 0; i < iters - 1; ++i) + printf("%d, %g\n", i + 1, delta[i] / cycles_to_units / 2); + } + + qsort(delta, iters - 1, sizeof *delta, cycles_compare); + + if (options->histogram) { + printf("#, %s\n", units); + for (i = 0; i < iters - 1; ++i) + printf("%d, %g\n", i + 1, delta[i] / freq / cycles_to_units / 2); + } + + median = get_median(iters - 1, delta); + printf("%7d %d %7.2f %7.2f %7.2f\n", + size, + iters,delta[0] / freq / cycles_to_units / 2, + delta[iters - 2] / freq / cycles_to_units / 2, + median / freq / cycles_to_units / 2); + + free(delta); +} + + + +int run_iter(struct pingpong_context *ctx, struct user_parameters *user_param, + struct pingpong_dest *rem_dest, int size) +{ + ib_api_status_t ib_status; + int scnt, ccnt, rcnt; + ib_send_wr_t *bad_wr; + volatile char *poll_buf; + volatile char *post_buf; + int freq = 0, tcnt; + + + + + + ctx->list.vaddr = (uintptr_t) ctx->buf ; + ctx->list.length = size; + ctx->list.lkey = ctx->lkey; + ctx->wr.remote_ops.vaddr = rem_dest->vaddr; + ctx->wr.remote_ops.rkey = rem_dest->rkey; + ctx->wr.wr_id = PINGPONG_RDMA_WRID; + ctx->wr.ds_array = &ctx->list; + ctx->wr.num_ds = 1; + ctx->wr.wr_type = WR_RDMA_WRITE; + + if ((uint32_t)size > ctx->qp_attr[0].sq_max_inline) {/* complaince to perf_main */ + ctx->wr.send_opt = IB_SEND_OPT_SIGNALED; + } else { + ctx->wr.send_opt = IB_SEND_OPT_SIGNALED | IB_SEND_OPT_INLINE; + } + scnt = 0; + rcnt = 0; + ccnt = 0; + tcnt = 0; + + if(user_param->all == ALL) { + post_buf = (char*)ctx->buf + size - 1; + poll_buf = (char*)ctx->buf + 8388608 + size - 1; + } else { + poll_buf = ctx->poll_buf; + post_buf = ctx->post_buf; + } + + /* Done with setup. Start the test. */ + while (scnt < user_param->iters || ccnt < user_param->iters || rcnt < user_param->iters) { + + /* Wait till buffer changes. */ + if (rcnt < user_param->iters && !(scnt < 1 && user_param->servername)) { + ++rcnt; + while (*poll_buf != (char)rcnt) + ; + /* Here the data is already in the physical memory. + If we wanted to actually use it, we may need + a read memory barrier here. */ + } + + if (scnt < user_param->iters) { + + *post_buf = (char)++scnt; + + ib_status = ib_post_send(ctx->qp[0], &ctx->wr, &bad_wr); + if (ib_status != IB_SUCCESS) + { + fprintf(stderr, "Couldn't post send:scnt %d ccnt=%d \n",scnt,ccnt); + return 1; + } + if (++freq >= user_param->stamp_freq) { + tstamp[tcnt++] = get_cycles(); + freq = 0; + } + } + + if (ccnt < user_param->iters) { + ib_wc_t wc; + ib_wc_t *p_wc_done,*p_wc_free; + + p_wc_free = &wc; + p_wc_done = NULL; + p_wc_free->p_next = NULL; + + do{ + ib_status = ib_poll_cq(ctx->scq, &p_wc_free, &p_wc_done); + } while (ib_status == IB_NOT_FOUND); + + if (ib_status != IB_SUCCESS) { + fprintf(stderr, "Poll Send CQ failed %d\n", ib_status); + return 12; + } + + if (p_wc_done->status != IB_WCS_SUCCESS) { + fprintf(stderr, "Completion wth error at %s:\n", + user_param->servername ? "client" : "server"); + fprintf(stderr, "Failed status %d: wr_id %d syndrom 0x%x\n", + p_wc_done->status, (int) p_wc_done->wr_id, p_wc_done->vendor_specific); + return 1; + } + + ++ccnt; + } + PERF_DEBUG("ccnt = %d \n",ccnt); + } + return(0); +} + + + + + + +int __cdecl main(int argc, char *argv[]) +{ + struct pingpong_context *ctx; + struct pingpong_dest *my_dest; + struct pingpong_dest *rem_dest; + struct user_parameters user_param; + char *ib_devname = NULL; + int port = 18515; + int ib_port = 1; + unsigned size = 2; + SOCKET sockfd = INVALID_SOCKET; + WSADATA wsaData; + int i = 0; + int iResult; + struct report_options report = {0}; + + + /* init default values to user's parameters */ + memset(&user_param, 0, sizeof(struct user_parameters)); + user_param.mtu = 0; /* signal choose default by device */ + user_param.iters = 1000; + user_param.tx_depth = 50; + user_param.stamp_freq = 1; + user_param.servername = NULL; + /* Parameter parsing. */ + while (1) { + int c; + + static struct option long_options[] = { + { "port", 1, NULL, 'p' }, + { "connection", 1, NULL, 'c' }, + { "mtu", 1, NULL, 'm' }, + { "ib-dev", 1, NULL, 'd' }, + { "ib-port", 1, NULL, 'i' }, + { "size", 1, NULL, 's' }, + { "iters", 1, NULL, 'n' }, + { "tx-depth", 1, NULL, 't' }, + { "stamp_freq", 1, NULL, 'f' }, + { "all", 0, NULL, 'a' }, + { "report-cycles", 0, NULL, 'C' }, + { "report-histogram", 0, NULL, 'H' }, + { "report-unsorted", 0, NULL, 'U' }, + { "version", 0, NULL, 'V' }, + { 0 } + }; + + c = getopt_long(argc, argv, "p:c:m:d:i:s:n:t:f:aCHUV", long_options, NULL); + if (c == -1) + break; + + switch (c) { + case 'p': + port = strtol(optarg, NULL, 0); + if (port < 0 || port > 65535) { + usage(argv[0]); + return 1; + } + break; + case 'c': + if (strcmp("UC",optarg)==0) + user_param.connection_type=UC; + break; + + case 'm': + user_param.mtu = strtol(optarg, NULL, 0); + break; + case 'a': + user_param.all = ALL; + break; + case 'V': + printf("perftest version : %.2f\n",VERSION); + return 0; + break; + case 'd': + ib_devname = _strdup(optarg); + break; + + case 'i': + ib_port = strtol(optarg, NULL, 0); + if (ib_port < 0) { + usage(argv[0]); + return 2; + } + break; + + case 's': + size = strtol(optarg, NULL, 0); + if (size < 1) { + usage(argv[0]); return 3; + } + break; + + case 't': + user_param.tx_depth = strtol(optarg, NULL, 0); + if (user_param.tx_depth < 1) { + usage(argv[0]); return 4; + } + break; + + case 'n': + user_param.iters = strtol(optarg, NULL, 0); + if (user_param.iters < 2) { + usage(argv[0]); + return 5; + } + + break; + + case 'C': + report.cycles = 1; + break; + + case 'H': + report.histogram = 1; + break; + + case 'U': + report.unsorted = 1; + break; + + case 'f': + user_param.stamp_freq = strtol(optarg, NULL, 0); + break; + + default: + usage(argv[0]); + return 5; + } + } + + if (optind == argc - 1) + user_param.servername = _strdup(argv[optind]); + else if (optind < argc) { + usage(argv[0]); + return 6; + } + + /* + * Done with parameter parsing. Perform setup. + */ + + tstamp = malloc(user_param.iters * sizeof *tstamp); + if (!tstamp) { + perror("malloc"); + return 10; + } + printf("------------------------------------------------------------------\n"); + printf(" RDMA_Write Latency Test\n"); + if (user_param.connection_type==0) { + printf("Connection type : RC\n"); + } else { + printf("Connection type : UC\n"); + } + + + + // Initialize Winsock + iResult = WSAStartup(MAKEWORD(2,2), &wsaData); + if (iResult != NO_ERROR) { + printf("Error at WSAStartup()\n"); + return 1; + } + + + if (user_param.all == ALL) { + /*since we run all sizes lets allocate big enough buffer */ + size = 8388608; /*2^23 */ + } + srand(GetCurrentProcessId() * GetTickCount()); + + //TODO: get pagesize from sysinfo + page_size = 4096; + + //TODO get the device names + + + ctx = pp_init_ctx( size, ib_port,&user_param); + if (!ctx) + return 8; + sockfd = pp_open_port(ctx, user_param.servername, ib_port, port,&my_dest,&rem_dest,&user_param); + if (sockfd == INVALID_SOCKET) + return 9; + + printf("------------------------------------------------------------------\n"); + printf(" #bytes #iterations t_min[usec] t_max[usec] t_typical[usec]\n"); + + if (user_param.all == ALL) { + for (i = 1; i < 24 ; ++i) { + size = 1 << i; + if(run_iter(ctx, &user_param, rem_dest, size)) + return 17; + print_report(&report, user_param.iters, tstamp, size, user_param.stamp_freq); + } + } else { + if(run_iter(ctx, &user_param, rem_dest, size)) + return 18; + print_report(&report, user_param.iters, tstamp, size, user_param.stamp_freq); + } + send(sockfd, "done", sizeof "done",0); + closesocket(sockfd); + + + printf("------------------------------------------------------------------\n"); + free(tstamp); + return 0; +} diff --git a/branches/WOF2-3/tools/perftests/user/write_lat/write_lat.rc b/branches/WOF2-3/tools/perftests/user/write_lat/write_lat.rc new file mode 100644 index 00000000..9cd1a3f9 --- /dev/null +++ b/branches/WOF2-3/tools/perftests/user/write_lat/write_lat.rc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef _DEBUG_ +#define VER_FILEDESCRIPTION_STR "RDMA write Latency Test (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "RDMA write Latency Test " +#endif + +#define VER_INTERNALNAME_STR "ib_write_lat.exe" +#define VER_ORIGINALFILENAME_STR "ib_write_lat.exe" + +#include diff --git a/branches/WOF2-3/tools/qlgcvnic_config/SOURCES b/branches/WOF2-3/tools/qlgcvnic_config/SOURCES new file mode 100644 index 00000000..c65295f9 --- /dev/null +++ b/branches/WOF2-3/tools/qlgcvnic_config/SOURCES @@ -0,0 +1,20 @@ +TARGETNAME=qlgcvnic_config +TARGETPATH=..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE=PROGRAM +UMTYPE=console +USE_MSVCRT=1 + +SOURCES= qlgcvnic_config.rc \ + vnic_child_config.c + +INCLUDES=..\..\inc;..\..\inc\user;..\..\core\al +TARGETLIBS= \ +!if $(FREEBUILD) + $(TARGETPATH)\*\complib.lib \ +!else + $(TARGETPATH)\*\complibd.lib \ +!endif + +RCOPTIONS=/I..\..\win\include + +MSC_WARNING_LEVEL= /W3 diff --git a/branches/WOF2-3/tools/qlgcvnic_config/makefile b/branches/WOF2-3/tools/qlgcvnic_config/makefile new file mode 100644 index 00000000..783b1843 --- /dev/null +++ b/branches/WOF2-3/tools/qlgcvnic_config/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\inc\openib.def diff --git a/branches/WOF2-3/tools/qlgcvnic_config/qlgcvnic_config.rc b/branches/WOF2-3/tools/qlgcvnic_config/qlgcvnic_config.rc new file mode 100644 index 00000000..b31d14cd --- /dev/null +++ b/branches/WOF2-3/tools/qlgcvnic_config/qlgcvnic_config.rc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2009 QLogic Corporation. All rights reserved. + * + * This software is available to you under the OpenFabrics.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef _DEBUG_ +#define VER_FILEDESCRIPTION_STR "QLogic Vnic configuration Application (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "QLogic Vnic configuration Application" +#endif + +#define VER_INTERNALNAME_STR "qlgc_config.exe" +#define VER_ORIGINALFILENAME_STR "qlcg_config.exe" + +#include diff --git a/branches/WOF2-3/tools/qlgcvnic_config/vnic_child_config.c b/branches/WOF2-3/tools/qlgcvnic_config/vnic_child_config.c new file mode 100644 index 00000000..dd018891 --- /dev/null +++ b/branches/WOF2-3/tools/qlgcvnic_config/vnic_child_config.c @@ -0,0 +1,560 @@ +/* + * Copyright (c) 2009 QLogic Corporation. All rights reserved. + * + * This software is available to you under the OpenFabrics.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include +#include +#include +#include +#include +#include +#include + +#define MAX_DEVICE_ID_LEN 200 +#define MAX_DEVICE_STRING_LEN MAX_DEVICE_ID_LEN + 2 /* add extra 4 bytes in case we need double NULL ending */ + +#pragma pack(push, 1) +typedef struct _ca_ioc_info { + net64_t ca_guid; + ib_ioc_info_t info; + ib_svc_entry_t svc_entry_array[1]; +} ca_ioc_info_t; + +typedef struct _child_device_info { + wchar_t device_id[MAX_DEVICE_STRING_LEN]; + uint32_t device_id_size; + wchar_t compatible_id[MAX_DEVICE_STRING_LEN]; + uint32_t compatible_id_size; + wchar_t hardware_id[MAX_DEVICE_STRING_LEN]; + uint32_t hardware_id_size; + wchar_t description[MAX_DEVICE_STRING_LEN]; + uint32_t description_size; + ca_ioc_info_t ca_ioc_path; + uint32_t uniqueinstanceid; +} child_device_info_t; + +#pragma pack(pop) + +int usage() +{ + printf( "Correct usage to create VNIC child devices is:-\n" ); + printf( "qlgcvnic_config -c " + " \n" ); + printf( "Executing qlgcvnic_config without any option or with -l " + "option will list the IOCs reachable from the host\n" ); + return -1; +} + +DWORD send_device_ioctl( DWORD ioctlcode, PVOID input_buf, DWORD in_size, PVOID *output_buf, PDWORD out_size ) +{ + DWORD dwRet = 0, dwMemSize, dwBytesRet = 0; + BOOL bRet; + PVOID pBuf; + HANDLE hDevice = INVALID_HANDLE_VALUE; + + hDevice = CreateFileW ( L"\\\\.\\VNICCONFIG", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, /* share mode none */ + NULL, /* no security */ + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL ); /* no template; */ + + if ( hDevice == INVALID_HANDLE_VALUE ) + { + printf( "Error opening VNICCONFIG device file\n" ); + return ERROR_FILE_NOT_FOUND; + } + + switch( ioctlcode ) + { + case UAL_IOC_DEVICE_CREATE: + bRet = DeviceIoControl( hDevice, ioctlcode, input_buf, in_size, NULL, 0, &dwBytesRet, NULL ); + + if ( !bRet ) + { + dwRet = GetLastError(); + printf( "GetLastError after UAL_IOC_DEVICE_CREATE gives %d\n", dwRet ); + } + break; + + case UAL_IOC_LIST: + dwMemSize = sizeof(ca_ioc_info_t ) * 2; + pBuf = NULL; + + do + { + if ( pBuf ) + { + cl_free( pBuf ); + dwMemSize *= 2; + pBuf = NULL; + } + + pBuf = cl_malloc( dwMemSize ); + + if ( !pBuf ) + { + printf( "Insufficient memory\n" ); + dwRet = ERROR_NOT_ENOUGH_MEMORY; + break; + } + + bRet = DeviceIoControl( hDevice, ioctlcode, NULL, 0, pBuf, dwMemSize, &dwBytesRet, NULL ); + dwRet = GetLastError(); + + if ( bRet ) + { + dwRet = 0; + break; + } + + }while( dwRet == ERROR_INSUFFICIENT_BUFFER ); + + *output_buf = pBuf; + *out_size = dwBytesRet; + + break; + } + + CloseHandle( hDevice ); + return dwRet; +} + +ca_ioc_info_t *find_ca_ioc_path ( ca_ioc_info_t *pList, DWORD nListSize, + uint64_t ca_guid, uint64_t ioc_guid ) +{ + while ( nListSize ) + { + + if ( pList->ca_guid == ca_guid && pList->info.profile.ioc_guid == ioc_guid ) + { + return pList; + } + nListSize--; + pList++; + } + + return NULL; +} + +#define IBIOU_SERVICE_PARAM_KEY "SYSTEM\\CurrentControlSet\\Services\\ibiou" +#define IBIOU_PARAM_KEY_DEVICE_VALUE "StaticChild" +#define IBIOU_PARAMETER_NAME "Parameters" +#define MAX_VALUE_LENGTH 2048 + +DWORD write_device_name( char *device_name ) +{ + + DWORD dwRet = 0, dwBytesRet = 0, n_size = 100, dwType; + HKEY hKey = INVALID_HANDLE_VALUE; + LONG lRet = -1; + PVOID pOldValue, pNewValue, pBuf; + char szKeyName[200]; + + sprintf( szKeyName, "%s\\%s", IBIOU_SERVICE_PARAM_KEY, IBIOU_PARAMETER_NAME ); + lRet = RegOpenKeyExA( HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_ALL_ACCESS, + &hKey ); + + + if ( lRet != ERROR_SUCCESS ) + { + printf( "Opening services key of ibiou failed\n" ); + dwRet = -1; + } + else + { + do + { + pOldValue = cl_malloc( n_size ); + + if ( !pOldValue ) + { + printf( "Not enough memory on system\n" ); + break; + } + dwType = REG_MULTI_SZ; + + lRet = RegQueryValueExA( hKey, IBIOU_PARAM_KEY_DEVICE_VALUE, 0, &dwType, pOldValue, &dwBytesRet ); + + + if ( lRet == ERROR_MORE_DATA ) + { + cl_free( pOldValue ); + pOldValue = NULL; + n_size = n_size*2; + } + + } while( lRet == ERROR_MORE_DATA && n_size < MAX_VALUE_LENGTH ); + + if ( lRet != ERROR_SUCCESS ) + { + cl_free( pOldValue ); + pOldValue = NULL; + } + + + n_size = dwBytesRet + strlen( device_name )*sizeof( char ) + 2*sizeof( char ); /* more for NULLs */ + pNewValue = cl_malloc( n_size ); + pBuf = pNewValue; + cl_memset( pNewValue, 0x00, n_size ); + if ( !pNewValue ) + { + printf( "Not enough memory on system\n" ); + } + else + { + if ( pOldValue ) + { /* Come here only when "StaticChild" key was there already*/ + cl_memcpy( pBuf, pOldValue, dwBytesRet ); + + while ( *( ( PBYTE )pBuf ) != 0 || *( ( PBYTE ) pBuf + 1 ) != 0 ) + pBuf = ( PBYTE ) pBuf + 1; + + pBuf = ( PBYTE ) pBuf + 1; + cl_free( pOldValue ); + pOldValue = NULL; + } + + cl_memcpy( pBuf, device_name, strlen( device_name ) ); + lRet = RegSetValueExA( hKey, IBIOU_PARAM_KEY_DEVICE_VALUE, 0, REG_MULTI_SZ, + pNewValue, ( strlen( device_name ) + dwBytesRet + 2 ) ); /* Two bytes for extra NULLs*/ + cl_free( pNewValue ); + RegCloseKey( hKey ); + if ( lRet != ERROR_SUCCESS ) + { + printf( "Error setting device name in value of services key of ibiou\n" ); + dwRet = -1; + } + } + + } + return dwRet; +} + +static const char *value_names[] = { + "CAGUID", +#define CAGUID_INDEX 0 + "IOCGUID", +#define IOCGUID_INDEX 1 + "CompatibleId", +#define COMPATIBLEID_INDEX 2 + "Description", +#define DESCRIPTION_INDEX 3 + "DeviceId", +#define DEVICEID_INDEX 4 + "HardwareId", +#define HARDWAREID_INDEX 5 + "InstanceId" +#define INSTANCEID_INDEX 6 +#define MAXVALUE_INDEX 7 +}; + +DWORD write_deviceinfo_to_registry( uint64_t ca_guid, uint64_t ioc_guid, + uint32_t instance_id, char *device_name ) +{ + DWORD dwRet = 0, dwDisposition, dwType, dwSize; + HKEY hKey = INVALID_HANDLE_VALUE; + char szKeyName[250]; + LONG lRet; + DWORD dwIndex; + PVOID pBuf; + + dwRet = write_device_name( device_name ); + + if ( dwRet == 0 ) + { + sprintf( szKeyName, "%s\\%s\\%s", + IBIOU_SERVICE_PARAM_KEY, IBIOU_PARAMETER_NAME, device_name ); + lRet = RegCreateKeyExA( HKEY_LOCAL_MACHINE, szKeyName, 0, + NULL, REG_OPTION_NON_VOLATILE, + KEY_ALL_ACCESS, NULL, &hKey, &dwDisposition ); + + if ( dwDisposition == REG_CREATED_NEW_KEY ) + { + dwIndex = CAGUID_INDEX; + + while ( dwIndex < MAXVALUE_INDEX ) + { + + switch( dwIndex ) + { + case CAGUID_INDEX: + pBuf = &ca_guid; + dwType = REG_BINARY; + dwSize = sizeof( uint64_t ); + break; + + case IOCGUID_INDEX: + pBuf = &ioc_guid; + dwType = REG_BINARY; + dwSize = sizeof( uint64_t ); + break; + + case DEVICEID_INDEX: + pBuf = "IBA\\qlgcvnic"; + dwType = REG_SZ; + dwSize = strlen( pBuf ) + 1; + break; + + case COMPATIBLEID_INDEX: /* Currently all id's used are same. */ + case HARDWAREID_INDEX: + pBuf = "IBA\\qlgcvnic"; + dwType = REG_MULTI_SZ; + dwSize = strlen( pBuf ) + 1; + break; + + case DESCRIPTION_INDEX: + pBuf = device_name; + dwType = REG_SZ; + dwSize = strlen( pBuf ) + 1; + break; + + case INSTANCEID_INDEX: + pBuf = &instance_id; + dwType = REG_DWORD; + dwSize = sizeof( instance_id ); + break; + + default: + break; + } + lRet = RegSetValueExA( hKey, value_names[dwIndex], 0, + dwType, pBuf, dwSize ); + + if ( lRet != ERROR_SUCCESS ) + { + printf( "Failed in setting device information as Parameters of ibiou driver\n" ); + dwRet = -1; + break; + } + + dwIndex++; + } + } + + if ( hKey != INVALID_HANDLE_VALUE ) + { + RegCloseKey( hKey ); + } + } + + return dwRet; +} + +DWORD create_child_device( uint64_t ca_guid, uint64_t ioc_guid, uint32_t instance_id, char *device_name ) +{ + ca_ioc_info_t *pList = NULL, *p_ca_ioc_entry = NULL; + DWORD dwRet = 0, dwBytesRet; + child_device_info_t *child_dev = NULL; + WCHAR szDevName[200]; + + + dwRet = send_device_ioctl( UAL_IOC_LIST, NULL, 0, &pList, &dwBytesRet ); + + if ( dwRet ) + { + printf( "Obtaining IOC LIST from ibiou failed\n" ); + } + else + { + p_ca_ioc_entry = find_ca_ioc_path( pList, dwBytesRet/sizeof( ca_ioc_info_t ), + ca_guid, ioc_guid ); + + if ( p_ca_ioc_entry ) + { + child_dev = cl_malloc( sizeof( child_device_info_t ) ); + cl_memset( child_dev, 0x00, sizeof( child_device_info_t ) ); + + if ( !child_dev ) + { + printf( "Allocating memory for child device failed\n" ); + } + else + { + child_dev->ca_ioc_path = *p_ca_ioc_entry; + wcscpy( child_dev->device_id, L"IBA\\qlgcvnic" ); + child_dev->device_id_size = ( wcslen( child_dev->device_id ) + 1 )*sizeof( WCHAR ); + wcscpy( child_dev->hardware_id, L"IBA\\qlgcvnic" ); + child_dev->hardware_id_size = ( wcslen( child_dev->hardware_id ) + 2 )*sizeof( WCHAR ); + wcscpy( child_dev->compatible_id, L"IBA\\qlgcvnic" ); + child_dev->compatible_id_size = ( wcslen( child_dev->compatible_id ) + 2 )*sizeof( WCHAR ); + swprintf( szDevName, L"%S", device_name ); + wcscpy( child_dev->description, szDevName ); + child_dev->description_size = ( wcslen( child_dev->description ) + 1 )*sizeof( WCHAR ); + child_dev->uniqueinstanceid = instance_id; + + dwRet = send_device_ioctl( UAL_IOC_DEVICE_CREATE, child_dev, sizeof( *child_dev ), NULL, NULL ); + + if ( !dwRet ) + { + printf( "Child device creation for CA = %I64X and IOC = %I64X was successful\n", + cl_ntoh64( ca_guid ), cl_ntoh64( ioc_guid ) ); + dwRet = write_deviceinfo_to_registry( ca_guid, ioc_guid, instance_id, device_name ); + } + } + } + else + { + dwRet = -1; + printf( "No path CA=%I64X to IOC=%I64X found\n", + cl_ntoh64( ca_guid ), cl_ntoh64( ioc_guid ) ); + } + } + + if ( dwRet ) + { + printf( "Child device creation for CA = %I64X and IOC = %I64X failed\n", + cl_ntoh64( ca_guid ), cl_ntoh64( ioc_guid ) ); + } + + + if ( pList ) + { + cl_free( pList ); + } + + return dwRet; +} + +DWORD list_ca_ioc_paths() +{ + DWORD dwBytesRet = 0, dwRet, n_ca_ioc_path = 0; + ca_ioc_info_t *pList = NULL; + PVOID pBuf = NULL; + + dwRet = send_device_ioctl( UAL_IOC_LIST, NULL, 0, &pList, &dwBytesRet ); + + if ( dwRet ) + { + printf( "Obtaining IOC list from ibiou failed\n" ); + } + else if ( dwBytesRet ) + { + pBuf = pList; + n_ca_ioc_path = dwBytesRet/sizeof( ca_ioc_info_t ); + + while ( n_ca_ioc_path ) + { + printf( "Channel Adapter %I64X reaches to IOC %I64X\n", + cl_ntoh64( pList->ca_guid ), cl_ntoh64( pList->info.profile.ioc_guid ) ); + pList++; n_ca_ioc_path--; + } + } + else + { + printf( "No IOCs are reachable from the host\nPlease check the connections of host\n" ); + } + + if ( pBuf ) + { + cl_free( pBuf ); + } + + return dwRet; +} + +int _cdecl main ( int argc, char *argv[] ) +{ + char device_name[200]; + int i = 1; + BOOLEAN b_list_ioc_paths = FALSE; + BOOLEAN b_create_device = FALSE; + uint64_t ca_guid, ioc_guid; + uint32_t unique_id; + DWORD ret = 0; + + while ( i < argc ) + { + if ( !strcmp( argv[i], "-l" ) ) + { + b_list_ioc_paths = TRUE; + } + else if ( !strcmp( argv[i], "-c" ) ) + { + b_create_device = TRUE; + + if ( argv[++i] ) + { + ca_guid = _strtoui64( argv[i], NULL, 16 ); + } + else + { + return usage(); + } + if ( argv[++i] ) + { + ioc_guid = _strtoui64( argv[i], NULL, 16 ); + } + else + { + return usage(); + } + if ( argv[++i] ) + { + unique_id = strtoul( argv[i], NULL, 10 ); + } + else + { + return usage(); + } + if ( argv[++i] ) + { + strcpy( device_name, argv[i] ); + } + else + { + return usage(); + } + + } + else + { + return usage(); + } + i++; + } + + if ( b_list_ioc_paths && b_create_device ) + { + return usage(); + } + + else if ( b_create_device ) + { + ret = create_child_device( cl_hton64( ca_guid ), cl_hton64( ioc_guid ), unique_id, device_name ); + } + else + { + ret = list_ca_ioc_paths(); + } + + return 0; +} diff --git a/branches/WOF2-3/tools/vstat/dirs b/branches/WOF2-3/tools/vstat/dirs new file mode 100644 index 00000000..389156fd --- /dev/null +++ b/branches/WOF2-3/tools/vstat/dirs @@ -0,0 +1,2 @@ +DIRS=\ + user diff --git a/branches/WOF2-3/tools/vstat/user/SOURCES b/branches/WOF2-3/tools/vstat/user/SOURCES new file mode 100644 index 00000000..75b634bb --- /dev/null +++ b/branches/WOF2-3/tools/vstat/user/SOURCES @@ -0,0 +1,23 @@ +TARGETNAME=vstat +TARGETPATH=..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE=PROGRAM +UMTYPE=console +USE_MSVCRT=1 + +SOURCES=vstat.rc \ + vstat_main.c + +INCLUDES=..\..\..\inc;..\..\..\inc\user; + +RCOPTIONS=/I..\..\win\include + +TARGETLIBS= \ +!if $(FREEBUILD) + $(TARGETPATH)\*\complib.lib \ + $(TARGETPATH)\*\ibal.lib +!else + $(TARGETPATH)\*\complibd.lib \ + $(TARGETPATH)\*\ibald.lib +!endif + +MSC_WARNING_LEVEL= /W3 diff --git a/branches/WOF2-3/tools/vstat/user/makefile b/branches/WOF2-3/tools/vstat/user/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-3/tools/vstat/user/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\inc\openib.def diff --git a/branches/WOF2-3/tools/vstat/user/vstat.rc b/branches/WOF2-3/tools/vstat/user/vstat.rc new file mode 100644 index 00000000..19a9103b --- /dev/null +++ b/branches/WOF2-3/tools/vstat/user/vstat.rc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef _DEBUG_ +#define VER_FILEDESCRIPTION_STR "HCA Status Report Application (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "HCA Status Report Application" +#endif + +#define VER_INTERNALNAME_STR "vstat.exe" +#define VER_ORIGINALFILENAME_STR "vstat.exe" + +#include diff --git a/branches/WOF2-3/tools/vstat/user/vstat_main.c b/branches/WOF2-3/tools/vstat/user/vstat_main.c new file mode 100644 index 00000000..3f1e4a47 --- /dev/null +++ b/branches/WOF2-3/tools/vstat/user/vstat_main.c @@ -0,0 +1,781 @@ +/* + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + +#include "stdio.h" +#include "string.h" +#include "stdlib.h" + + +#include +#include +#ifndef WIN32 +#include +#endif +#include + + +#define VEND_ID_MELLNOX 0x02c9 +#define VEND_ID_VOLTAIRE 0x08f1 + +enum link_speed_type_e { + LINK_SPEED_SUPPORTED = 0, + LINK_SPEED_ENABLED, + LINK_SPEED_ACTIVE +}; + +/******************************************************************* +*******************************************************************/ + + +void print64bit(ib_net64_t u64, BOOLEAN hexFormat){ + ib_net64_t mask = (1<<16)-1; + ib_net16_t tmp; + int i; + for(i=0;i<4;i++){ + tmp = (uint16_t)((u64>>(i*16))& mask); + if(hexFormat){ + printf("%04x",cl_hton16(tmp)); + if(i<3){ + printf(":"); + } + }else{ + + if((tmp>>8)<100){ + printf("%02d", tmp>>8); + }else{ + printf("%03d", tmp>>8); + } + printf("."); + if((tmp&(mask<<8)) <100){ + printf("%02d", tmp&(mask<<8)); + }else{ + printf("%03d", tmp&(mask<<8)); + } + + } + } +} + +void printGUID(char *title, ib_net64_t guid){ + printf(title); + print64bit(guid, TRUE); + printf("\n"); +} + +void printPortGID(ib_net64_t subnetPrefix, ib_net64_t portGuid){ + printf("\t\tGID[0]="); + print64bit(subnetPrefix, TRUE); + printf(":"); + print64bit(portGuid, TRUE); + printf("\n"); +} + + +void printPortLinkState(int portState){ //TODO: check that these are all the options and that they are correct + switch(portState){ + case 1: + printf("\t\tport_state=PORT_DOWN (%d)\n",portState); + break; + case 2: + printf("\t\tport_state=PORT_INITIALIZE (%d)\n",portState); + break; + case 3: + printf("\t\tport_state=PORT_ARMED (%d)\n",portState); + break; + case 4: + printf("\t\tport_state=PORT_ACTIVE (%d)\n",portState); + break; + case 5: + printf("\t\tport_state=PORT_ACTDEFER (%d)\n",portState); + break; + default: + printf("\t\tport_state=UNKNOWN (%d)\n",portState); + } +} + +void printPortPhysState(uint8_t physState){ + switch(physState){ + case 1: + printf("\t\tport_phys_state=SLEEP (%d)\n",physState); + break; + case 2: + printf("\t\tport_phys_state=POLLING (%d)\n",physState); + break; + case 3: + printf("\t\tport_phys_state=DISABLED (%d)\n",physState); + break; + case 4: + printf("\t\tport_phys_state=CFG_TRAINING (%d)\n",physState); + break; + case 5: + printf("\t\tport_phys_state=LINK_UP (%d)\n",physState); + break; + case 6: + printf("\t\tport_phys_state=LINK_ERROR_RECOVERY (%d)\n",physState); + break; + case 7: + printf("\t\tport_phys_state=PHY_TEST (%d)\n",physState); + break; + default: + printf("\t\tport_phys_state=UNKNOWN (%d)\n",physState); + } +} + +void printPortRate(enum link_speed_type_e link_speed_type, int speed, int width, int portState, BOOLEAN moreVerbose){ + char *link_speed_type_str[] = { "Supported", "Enabled", "Active" }; + + if ((portState == 1) && (link_speed_type == LINK_SPEED_ACTIVE)){ /* In case the port is in Down state */ + printf("\t\tlink_speed=NA\n"); + printf("\t\tlink_width=NA \n\t\trate=NA\n"); + }else{ + if (moreVerbose) { + int link_width_arr[4] = { 1, 4, 8, 12 }; + float link_rate_arr[4] = { 2.5, 10.0, 20.0, 30.0 }; + int i, link_flag; + float base_speed = 2.5; + + link_flag = 0; + printf("\t\t%s_link_speed=", link_speed_type_str[link_speed_type]); + for (i=1; i <= 4; i*=2) + if (speed & i) { + printf("%2.1f Gbps (%d), ", base_speed*i, i); + link_flag = 1; + } + if (!link_flag) + printf("UNKNOWN (%d)",speed); + printf("\n"); + + link_flag = 0; + printf("\t\t%s_link_width=", link_speed_type_str[link_speed_type]); + for (i=0; i < 4; i++) + if ((width >> i) & 1) { + printf("%dx (%d), ", link_width_arr[i], 1<cap) printf( #name "," ) + + printf("\t\tcapabilities: "); + PRINT_CAP(cm, CM); + PRINT_CAP(snmp, SNMP_TUNNEL); + PRINT_CAP(dev_mgmt, DEVICE_MGMT); + PRINT_CAP(sm_disable, SM_DISABLED); + PRINT_CAP(sm, SM); + PRINT_CAP(vend, VENDOR_CLASS); + PRINT_CAP(notice, NOTICE); + PRINT_CAP(trap, TRAP); + PRINT_CAP(apm, APM); + PRINT_CAP(slmap, SL_MAP); + PRINT_CAP(ledinfo, LED_INFO); + PRINT_CAP(client_reregister, CLIENT_REG); + PRINT_CAP(sysguid, SYSGUID); + PRINT_CAP(boot_mgmt, BOOT_MGMT); + PRINT_CAP(pkey_switch_ext_port, PKEY_SW_EXT_PORT_TRAP); + PRINT_CAP(link_rtl, LINK_LATENCY); + PRINT_CAP(reinit, REINIT); + PRINT_CAP(ipd, OPT_IPD); + PRINT_CAP(mkey_nvram, MKEY_NVRAM); + PRINT_CAP(pkey_nvram, PKEY_NVRAM); + printf("\n"); +} + +void printPortActiveSpeed(uint8_t speed){ + switch(speed){ + case 1: + printf("\t\tactive_speed=2.5 Gbps (%d)\n",speed); + break; + case 2: + printf("\t\tactive_speed=5.0 Gbps (%d)\n",speed); + break; + case 4: + printf("\t\tactive_speed=10.0 Gbps (%d)\n",speed); + break; + default: + printf("\t\tactive_speed=UNKNOWN (%d)\n",speed); + } +} + +void printPortInfo(ib_port_attr_t* portPtr, ib_port_info_t portInfo, BOOLEAN fullPrint, BOOLEAN moreVerbose){ + printf("\t\tport=%d\n", portPtr->port_num); + printPortLinkState(portPtr->link_state); + if (moreVerbose) { + printPortRate(LINK_SPEED_SUPPORTED, portInfo.state_info1>>4, portInfo.link_width_supported, portPtr->link_state, moreVerbose); + printPortRate(LINK_SPEED_ENABLED, (portInfo.link_speed & 0xF), portInfo.link_width_enabled, portPtr->link_state, moreVerbose); + } + printPortRate(LINK_SPEED_ACTIVE, portInfo.link_speed>>4, portInfo.link_width_active, portPtr->link_state, moreVerbose); + printPortPhysState(portPtr->phys_state); + printPortActiveSpeed(portPtr->active_speed); + printf("\t\tsm_lid=0x%04x\n", cl_ntoh16(portPtr->sm_lid)); + printf("\t\tport_lid=0x%04x\n", cl_ntoh16(portPtr->lid)); + printf("\t\tport_lmc=0x%x\n", portPtr->lmc); + printPortMTU(portPtr->mtu); + if(fullPrint){ + printf("\t\tmax_msg_sz=0x%x (Max message size)\n", portPtr->max_msg_size); + printPortCaps( &portPtr->cap ); + printf("\t\tmax_vl_num=0x%x (Maximum number of VL supported by this port)\n", portPtr->max_vls); + printf("\t\tbad_pkey_counter=0x%x (Bad PKey counter)\n", portPtr->pkey_ctr); + printf("\t\tqkey_viol_counter=0x%x (QKey violation counter)\n", portPtr->qkey_ctr); + printf("\t\tsm_sl=0x%x (IB_SL to be used in communication with subnet manager)\n", portPtr->sm_sl); + printf("\t\tpkey_tbl_len=0x%x (Current size of pkey table)\n", portPtr->num_pkeys); + printf("\t\tgid_tbl_len=0x%x (Current size of GID table)\n", portPtr->num_gids); + printf("\t\tsubnet_timeout=0x%x (Subnet Timeout for this port (see PortInfo))\n", portPtr->subnet_timeout); + printf("\t\tinitTypeReply=0x%x (optional InitTypeReply value. 0 if not supported)\n", portPtr->init_type_reply); + printPortGID(portPtr->p_gid_table->unicast.prefix, portPtr->p_gid_table->unicast.interface_id); + } + printf("\n"); +} + +void print_uplink_info(ib_ca_attr_t* ca_attr) +{ + uplink_info_t*p_uplink_info = mthca_get_uplink_info(ca_attr); + char *bus_type, *link_speed, cap; + int freq; + + switch (p_uplink_info->bus_type) { + case UPLINK_BUS_PCI: bus_type = "PCI"; break; + case UPLINK_BUS_PCIX: bus_type = "PCI_X"; break; + case UPLINK_BUS_PCIE: bus_type = "PCI_E"; break; + default: printf("\tuplink={BUS=UNRECOGNIZED (%d)}\n", p_uplink_info->bus_type); return; + } + + switch (p_uplink_info->bus_type) { + case UPLINK_BUS_PCI: + case UPLINK_BUS_PCIX: + if (p_uplink_info->u.pci_x.capabilities == UPLINK_BUS_PCIX_133) + freq = 133; + else + freq = 66; + printf("\tuplink={BUS=%s, CAPS=%d MHz}\n", bus_type, freq ); + break; + + case UPLINK_BUS_PCIE: + cap = p_uplink_info->u.pci_e.capabilities; + if (p_uplink_info->u.pci_e.link_speed == UPLINK_BUS_PCIE_SDR) + link_speed = "2.5 Gbps"; + else + if (p_uplink_info->u.pci_e.link_speed == UPLINK_BUS_PCIE_DDR) + link_speed = "5.0 Gbps"; + else + link_speed = "unknown"; + printf("\tuplink={BUS=%s, SPEED=%s, WIDTH=x%d, CAPS=%s*x%d}\n", + bus_type, link_speed, p_uplink_info->u.pci_e.link_width, + (cap&1) ? "2.5" : "5", cap>>2 ); + break; + } + + /* MSI-X */ + if (p_uplink_info->x.valid) + printf("\tMSI-X={ENABLED=%d, SUPPORTED=%d, GRANTED=%d, ALL_MASKED=%s}\n", + p_uplink_info->x.enabled, p_uplink_info->x.requested, + p_uplink_info->x.granted, p_uplink_info->x.masked ? "Y" : "N"); +} + +void vstat_print_ca_attr(int idx, ib_ca_attr_t* ca_attr, ib_port_info_t* vstat_port_info, + BOOLEAN fullPrint, BOOLEAN moreVerbose){ + int i; + + printf("\n\thca_idx=%d\n", idx); + print_uplink_info(ca_attr); + printf("\tvendor_id=0x%04x\n", ca_attr->vend_id); + if(moreVerbose) + printf("\tvendor_part_id=0x%04x (%d)\n", ca_attr->dev_id, ca_attr->dev_id); + else + printf("\tvendor_part_id=%hu\n", ca_attr->dev_id); + + if (!ca_attr->num_ports) { + printf("\n\tATTENTION! \n\t The driver has reported zero physical ports. " + "\n\t It can be a result of incompatibility of user and kernel components." + "\n\t It can be also caused by a driver failure on startup. " + "\n\t Look into System Event Log for driver reports. " + "\n\t Use firmware tools to solve the problem (in second case)." + "\n\t The work with IB stack is impossible. \n"); + return; + } + + printf("\thw_ver=0x%x\n", ca_attr->revision); //TODO: ??? + if(ca_attr->vend_id == VEND_ID_MELLNOX || ca_attr->vend_id == VEND_ID_VOLTAIRE) { + printf("\tfw_ver=%d.%.2d.%.4d\n", + (uint16_t)(ca_attr->fw_ver>>32), + (uint16_t)(ca_attr->fw_ver>>16), + (uint16_t)(ca_attr->fw_ver)); + printf("\tPSID=%s\n",mthca_get_board_id(ca_attr)); + }else{ + printf("\tfw_ver=0x%I64x\n",ca_attr->fw_ver); + } + printGUID("\tnode_guid=", ca_attr->ca_guid); + if(fullPrint){ + printGUID("\tsys_image_guid=", ca_attr->system_image_guid); + printf("\tnum_phys_ports = %d\n",ca_attr->num_ports); + printf("\tmax_num_qp = 0x%x (Maximum Number of QPs supported)\n", ca_attr->max_qps); + printf("\tmax_qp_ous_wr = 0x%x (Maximum Number of outstanding WR on any WQ)\n", ca_attr->max_wrs); + printf("\tmax_num_sg_ent = 0x%x (Max num of scatter/gather entries for WQE other than RD)\n", ca_attr->max_sges); + printf("\tmax_num_sg_ent_rd = 0x%x (Max num of scatter/gather entries for RD WQE)\n", ca_attr->max_rd_sges); + printf("\tmax_num_srq = 0x%x (Maximum Number of SRQs supported)\n", ca_attr->max_srq); + printf("\tmax_wqe_per_srq = 0x%x (Maximum Number of outstanding WR on any SRQ)\n", ca_attr->max_srq_wrs); + printf("\tmax_srq_sentries = 0x%x (Maximum Number of scatter/gather entries for SRQ WQE)\n", ca_attr->max_srq_sges); + printf("\tsrq_resize_supported = %d (SRQ resize supported)\n", ca_attr->modify_srq_depth); + printf("\tmax_num_cq = 0x%x (Max num of supported CQs)\n", ca_attr->max_cqs); + printf("\tmax_num_ent_cq = 0x%x (Max num of supported entries per CQ)\n", ca_attr->max_cqes); + printf("\tmax_num_mr = 0x%x (Maximum number of memory region supported)\n", ca_attr->init_regions); + printf("\tmax_mr_size = 0x%x (Largest contiguous block of memory region in bytes)\n", ca_attr->init_region_size); + printf("\tmax_pd_num = 0x%x (Maximum number of protection domains supported)\n", ca_attr->max_pds); + printf("\tpage_size_cap = 0x%x (Largest page size supported by this HCA)\n",ca_attr->p_page_size[ca_attr->num_page_sizes-1]); + + printf("\tlocal_ca_ack_delay = 0x%x (Log2 4.096usec Max. RX to ACK or NAK delay)\n", ca_attr->local_ack_delay); + printf("\tmax_qp_ous_rd_atom = 0x%x (Maximum number of oust. RDMA read/atomic as target)\n",ca_attr->max_qp_resp_res); + printf("\tmax_ee_ous_rd_atom = 0 (EE Maximum number of outs. RDMA read/atomic as target)\n"); + printf("\tmax_res_rd_atom = 0x%x (Max. Num. of resources used for RDMA read/atomic as target)\n",ca_attr->max_resp_res); + printf("\tmax_qp_init_rd_atom = 0x%x (Max. Num. of outs. RDMA read/atomic as initiator)\n",ca_attr->max_qp_init_depth); + printf("\tmax_ee_init_rd_atom = 0 (EE Max. Num. of outs. RDMA read/atomic as initiator)\n"); + printf("\tatomic_cap = %s (Level of Atomicity supported)\n",ca_attr->atomicity == IB_ATOMIC_GLOBAL?"GLOBAL": + ca_attr->atomicity == IB_ATOMIC_LOCAL?"LOCAL":"NORMAL"); + printf("\tmax_ee_num = 0x0 (Maximum number of EEC supported)\n"); + printf("\tmax_rdd_num = 0x0 (Maximum number of IB_RDD supported)\n"); + printf("\tmax_mw_num = 0x%x (Maximum Number of memory windows supported)\n", ca_attr->init_windows); + printf("\tmax_raw_ipv6_qp = 0x%x (Maximum number of Raw IPV6 QPs supported)\n", ca_attr->max_ipv6_qps); + printf("\tmax_raw_ethy_qp = 0x%x (Maximum number of Raw Ethertypes QPs supported)\n", ca_attr->max_ether_qps); + printf("\tmax_mcast_grp_num = 0x%x (Maximum Number of multicast groups)\n", ca_attr->max_mcast_grps); + printf("\tmax_mcast_qp_attach_num = 0x%x (Maximum number of QP per multicast group)\n", ca_attr->max_qps_per_mcast_grp); + printf("\tmax_ah_num = 0x%I64x (Maximum number of address handles)\n", ca_attr->max_addr_handles); + printf("\tmax_num_fmr = 0x%x (Maximum number FMRs)\n", ca_attr->max_fmr); + printf("\tmax_num_map_per_fmr = 0x%x (Maximum number of (re)maps per FMR before an unmap operation in required)\n", ca_attr->max_map_per_fmr); + printf("\tmodify_wr_depth = %d (Capabilities: change QP depth during a modify QP)\n", !!ca_attr->modify_wr_depth); + printf("\tmodify_srq_depth = %d (Capabilities: change SRQ depth - Not supported by driver!)\n", !!ca_attr->modify_srq_depth); + printf("\tchange_primary_port = %d (Capabilities: change primary port for a QP during a SQD->RTS transition)\n", !!ca_attr->change_primary_port); + printf("\tav_port_check = %d (Capabilities: check port number in address handles)\n", !!ca_attr->av_port_check); + printf("\tinit_type_support = %d (Capabilities: set init_type)\n", !!ca_attr->init_type_support); + printf("\tshutdown_port = %d (Capabilities: shutdown port support)\n", !!ca_attr->shutdown_port_capability); + }else{ + printf("\tnum_phys_ports=%d\n", ca_attr->num_ports); + } + for (i = 0; inum_ports; i++){ + printPortInfo(ca_attr->p_port_attr+i, vstat_port_info[i], fullPrint, moreVerbose); + } +} +/* Internal Functions */ + +void vstat_get_counters(ib_ca_handle_t h_ca,uint8_t port_num) +{ + ib_mad_t *mad_in = NULL; + ib_mad_t *mad_out = NULL; + ib_port_counters_t *port_counters; + ib_api_status_t ib_status = IB_SUCCESS; + int i; + + mad_out = (ib_mad_t*)cl_zalloc(256); + CL_ASSERT(mad_out); + + mad_in = (ib_mad_t*)cl_zalloc(256); + CL_ASSERT(mad_in); + + + mad_in->attr_id = IB_MAD_ATTR_PORT_CNTRS; + mad_in->method = IB_MAD_METHOD_GET; + mad_in->base_ver = 1; + mad_in->class_ver =1; + mad_in->mgmt_class = IB_MCLASS_PERF; + + port_counters = (ib_port_counters_t*)(((ib_gmp_t*)mad_in)->data); + + port_counters->port_select= port_num; + port_counters->counter_select= 0xff; + + ib_status = ib_local_mad(h_ca ,port_num ,mad_in ,mad_out); + if(ib_status != IB_SUCCESS) + { + printf("ib_local_mad failed with status = %d\n", ib_status); + return; + } + + port_counters = (ib_port_counters_t*)(((ib_gmp_t*)mad_out)->data); + + printf("\n\tport counters for port %d\n",port_num); + printf("\t\tlink_error_recovery_counter\t0x%x \n",port_counters->link_error_recovery_counter); + printf("\t\tlink_down_counter\t\t0x%x \n",port_counters->link_down_counter); + printf("\t\tport_rcv_errors\t\t\t0x%x \n",CL_NTOH16(port_counters->port_rcv_errors)); + printf("\t\tport_rcv_remote_physical_errors\t0x%x \n",CL_NTOH16(port_counters->port_rcv_remote_physical_errors)); + printf("\t\tport_rcv_switch_relay_errors\t0x%x \n",CL_NTOH16(port_counters->port_rcv_switch_relay_errors)); + printf("\t\tport_xmit_discard\t\t0x%x \n",CL_NTOH16(port_counters->port_xmit_discard)); + printf("\t\tport_xmit_constraint_errors\t0x%x \n",port_counters->port_xmit_constraint_errors); + printf("\t\tport_rcv_constraint_errors\t0x%x \n",port_counters->port_rcv_constraint_errors); + printf("\t\tvl15_dropped\t\t\t0x%x \n",CL_NTOH16(port_counters->vl15_dropped)); + printf("\t\tport_rcv_data\t\t\t0x%x \n",CL_NTOH32(port_counters->port_rcv_data)); + printf("\t\tport_xmit_data\t\t\t0x%x \n",CL_NTOH32(port_counters->port_xmit_data)); + printf("\t\tport_rcv_pkts\t\t\t0x%x \n",CL_NTOH32(port_counters->port_rcv_pkts)); + printf("\t\tport_xmit_pkts\t\t\t0x%x \n\n",CL_NTOH32(port_counters->port_xmit_pkts)); + +} + + +void vstat_get_port_info(ib_ca_handle_t h_ca,uint8_t port_num, ib_port_info_t* vstat_port_info) +{ + ib_mad_t *mad_in = NULL; + ib_mad_t *mad_out = NULL; + ib_api_status_t ib_status = IB_SUCCESS; + int i; + + mad_out = (ib_mad_t*)cl_zalloc(256); + CL_ASSERT(mad_out); + + mad_in = (ib_mad_t*)cl_zalloc(256); + CL_ASSERT(mad_in); + + + mad_in->attr_id = IB_MAD_ATTR_PORT_INFO; + mad_in->method = IB_MAD_METHOD_GET; + mad_in->base_ver = 1; + mad_in->class_ver =1; + mad_in->mgmt_class = IB_MCLASS_SUBN_LID; + + + + ib_status = ib_local_mad(h_ca ,port_num ,mad_in ,mad_out); + if(ib_status != IB_SUCCESS && 0 != mad_in->status ) + { + printf("ib_local_mad failed with status = %d mad status = %d\n", ib_status,mad_in->status); + return; + } + + cl_memcpy(vstat_port_info,(ib_port_info_t*)(((ib_smp_t*)mad_out)->data),sizeof(ib_port_info_t)); + + +} + + +ib_api_status_t +vstat_ca_attr( + boolean_t modify_attr, + BOOLEAN fullPrint, + BOOLEAN getCounters, + BOOLEAN moreVerbose + ) +{ + ib_al_handle_t h_al = NULL; + ib_api_status_t ib_status = IB_SUCCESS; + ib_api_status_t ret_status = IB_SUCCESS; + size_t guid_count; + ib_net64_t *ca_guid_array; + ib_ca_attr_t *vstat_ca_attr; + ib_port_info_t vstat_port_info[2]; + size_t i; + ib_ca_handle_t h_ca = NULL; + uint32_t bsize; + ib_port_attr_mod_t port_attr_mod; + uint8_t port_idx; + + while(1) + { + /* + * Open the AL instance + */ + ib_status = ib_open_al(&h_al); + if(ib_status != IB_SUCCESS) + { + printf("ib_open_al failed status = %d\n", ib_status); + ret_status = ib_status; + break; + } + //xxxx + //printf("ib_open_al PASSED.\n"); + //xxx + CL_ASSERT(h_al); + + /* + * Get the Local CA Guids + */ + ib_status = ib_get_ca_guids(h_al, NULL, &guid_count); + if(ib_status != IB_INSUFFICIENT_MEMORY) + { + printf("ib_get_ca_guids1 failed status = %d\n", (uint32_t)ib_status); + ret_status = ib_status; + goto Cleanup1; + } + + + + /* + * If no CA's Present then return + */ + + if(guid_count == 0) + goto Cleanup1; + + + ca_guid_array = (ib_net64_t*)cl_malloc(sizeof(ib_net64_t) * guid_count); + CL_ASSERT(ca_guid_array); + + ib_status = ib_get_ca_guids(h_al, ca_guid_array, &guid_count); + if(ib_status != IB_SUCCESS) + { + printf("ib_get_ca_guids2 failed with status = %d\n", ib_status); + ret_status = ib_status; + goto Cleanup1; + } + + + + /* + * For Each CA Guid found Open the CA, + * Query the CA Attribute and close the CA + */ + for(i=0; i < guid_count; i++) + { + + /* Open the CA */ + ib_status = ib_open_ca(h_al, + ca_guid_array[i], + NULL, + NULL, //ca_context + &h_ca); + + if(ib_status != IB_SUCCESS) + { + printf("ib_open_ca failed with status = %d\n", ib_status); + ret_status = ib_status; + goto Cleanup1; + } + + //xxx + //printf("ib_open_ca passed i=%d\n",i); + //xxx + + + /* Query the CA */ + bsize = 0; + ib_status = ib_query_ca(h_ca, NULL, &bsize); + if(ib_status != IB_INSUFFICIENT_MEMORY) + { + printf("ib_query_ca failed with status = %d\n", ib_status); + ret_status = ib_status; + goto Cleanup2; + } + CL_ASSERT(bsize); + //xxxx + //printf("ib_query_ca PASSED bsize = 0x%x.\n",bsize); + //xxx + /* Allocate the memory needed for query_ca */ + + vstat_ca_attr = (ib_ca_attr_t *)cl_zalloc(bsize); + CL_ASSERT(vstat_ca_attr); + + ib_status = ib_query_ca(h_ca, vstat_ca_attr, &bsize); + if(ib_status != IB_SUCCESS) + { + printf("ib_query_ca failed with status = %d\n", ib_status); + ret_status = ib_status; + goto Cleanup2; + } + + for(port_idx =0; port_idx< vstat_ca_attr->num_ports;port_idx++){ + vstat_get_port_info(h_ca ,port_idx+1,&vstat_port_info[port_idx]); + } + + vstat_print_ca_attr((int)i, vstat_ca_attr, vstat_port_info, fullPrint, moreVerbose); + if(getCounters) + { + for(port_idx =0; port_idx< vstat_ca_attr->num_ports;port_idx++){ + vstat_get_counters(h_ca ,port_idx+1); + } + } + + /* Free the memory */ + cl_free(vstat_ca_attr); + vstat_ca_attr = NULL; + /* Close the current open CA */ + ib_status = ib_close_ca(h_ca, NULL); + if(ib_status != IB_SUCCESS) + { + printf("ib_close_ca failed status = %d", ib_status); + ret_status = ib_status; + } + h_ca = NULL; + + } + +Cleanup2: + if(h_ca != NULL) + { + ib_status = ib_close_ca(h_ca, NULL); + if(ib_status != IB_SUCCESS) + { + printf("ib_close_ca failed status = %d", ib_status); + } + } + +Cleanup1: + cl_free(ca_guid_array); + ib_status = ib_close_al(h_al); + + if(ib_status != IB_SUCCESS) + { + printf("ib_close_al failed status = %d", ib_status); + } + + break; + + } //End of while(1) + + + return ret_status; +} + +void vstat_help() +{ + printf("\n\tUsage: vstat [-v] [-c] [-m]\n"); + printf("\t\t -v - verbose mode\n"); + printf("\t\t -c - HCA error/statistic counters\n"); + printf("\t\t -m - more verbose mode\n"); + +} + +int32_t __cdecl +main( + int32_t argc, + char* argv[]) +{ + ib_api_status_t ib_status; + BOOLEAN fullPrint = FALSE; + BOOLEAN getCounters = FALSE; + BOOLEAN showHelp = FALSE; + BOOLEAN moreVerbose = FALSE; + if(argc>1){ + int i = 2; + while(i<=argc){ + if(!_stricmp(argv[i-1], "-v")){ + fullPrint = TRUE; + i+=1; + }else if(!_stricmp(argv[i-1], "-h") || + !_stricmp(argv[i-1], "-help")){ + showHelp = TRUE; + i+=1; + }else if(!_stricmp(argv[i-1], "-c")){ + getCounters = TRUE; + i+=1; + }else if(!_stricmp(argv[i-1], "-m")){ + fullPrint = TRUE; + moreVerbose = TRUE; + i+=1; + }else{ + i+=2; + } + } + } + if (showHelp) + vstat_help(); + else + ib_status = vstat_ca_attr(FALSE, fullPrint,getCounters, moreVerbose); + + return 0; +} + + + diff --git a/branches/WOF2-3/tools/wsdinstall/dirs b/branches/WOF2-3/tools/wsdinstall/dirs new file mode 100644 index 00000000..389156fd --- /dev/null +++ b/branches/WOF2-3/tools/wsdinstall/dirs @@ -0,0 +1,2 @@ +DIRS=\ + user diff --git a/branches/WOF2-3/tools/wsdinstall/user/InstallSP.sln b/branches/WOF2-3/tools/wsdinstall/user/InstallSP.sln new file mode 100644 index 00000000..9c8f2cb0 --- /dev/null +++ b/branches/WOF2-3/tools/wsdinstall/user/InstallSP.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "InstallSP", "InstallSP.vcproj", "{B3A2B7A0-1906-413E-A457-8AD2FC5E88BB}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {B3A2B7A0-1906-413E-A457-8AD2FC5E88BB}.Debug.ActiveCfg = Debug|Win32 + {B3A2B7A0-1906-413E-A457-8AD2FC5E88BB}.Debug.Build.0 = Debug|Win32 + {B3A2B7A0-1906-413E-A457-8AD2FC5E88BB}.Release.ActiveCfg = Release|Win32 + {B3A2B7A0-1906-413E-A457-8AD2FC5E88BB}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/branches/WOF2-3/tools/wsdinstall/user/SOURCES b/branches/WOF2-3/tools/wsdinstall/user/SOURCES new file mode 100644 index 00000000..5914a25d --- /dev/null +++ b/branches/WOF2-3/tools/wsdinstall/user/SOURCES @@ -0,0 +1,23 @@ +TARGETNAME=installsp +TARGETPATH=..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE=PROGRAM +UMTYPE=console +USE_MSVCRT=1 + +INCLUDES=..\..\..\inc;\ + ..\..\..\inc\user;\ + $(PLATFORM_SDK_PATH)\include; + +SOURCES= \ + installsp.rc \ + installsp.c + +USER_C_FLAGS=$(USER_C_FLAGS) -DPERFMON_ENABLED + +TARGETLIBS=\ + $(SDK_LIB_PATH)\ws2_32.lib \ + $(SDK_LIB_PATH)\LoadPerf.lib + +MSC_WARNING_LEVEL= /W3 + +LINKER_FLAGS=$(LINKER_FLAGS) diff --git a/branches/WOF2-3/tools/wsdinstall/user/installsp.c b/branches/WOF2-3/tools/wsdinstall/user/installsp.c new file mode 100644 index 00000000..e0cba2e8 --- /dev/null +++ b/branches/WOF2-3/tools/wsdinstall/user/installsp.c @@ -0,0 +1,759 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +/* + * Module Name: installsp.c + * Description: This module installs/removes a winsock service provider for infiniband. + * execute: + * To install the service provider + * installsp -i + * To remove the service provider + * installsp -r + */ + +#include +#include +#include +#include + + +/* Initialize the LSP's provider path for Infiband Service Provider dll */ +static const WCHAR provider_path[] = L"%SYSTEMROOT%\\system32\\ibwsd.dll"; +static const WCHAR provider_prefix[] =L" Winsock Direct for InfiniBand"; //includes one whitespace +static const char provider_name[] = VER_PROVIDER ;//L"%VER_PROVIDER% Winsock Direct for InfiniBand"; //(VER_PROVIDER ## WINDIR); +static const char winsock_key_path[] = + "System\\CurrentControlSet\\Services\\Winsock\\Parameters\\TCP on SAN"; +static const char openib_key_name[] = IB_COMPANYNAME; + +/* Unique provider GUID generated with "uuidgen -s" */ +static GUID provider_guid = { + /* c943654d-2c84-4db7-af3e-fdf1c5322458 */ + 0xc943654d, 0x2c84, 0x4db7, + { 0xaf, 0x3e, 0xfd, 0xf1, 0xc5, 0x32, 0x24, 0x58 } +}; + +#ifdef _WIN64 +#define WSCInstallProvider WSCInstallProvider64_32 +#endif /* _WIN64 */ + +#ifdef PERFMON_ENABLED +#include +#include "wsd/ibsp_regpath.h" + + +typedef struct _pm_symbol_def +{ + DWORD name_def; + CHAR name_str[40]; + CHAR name_desc[40]; + CHAR help_desc[256]; + +} pm_symbol_def_t; + +static pm_symbol_def_t _pm_symbols[]= +{ + { IBSP_PM_OBJ, + "IBSP_PM_OBJ", + "IB Winsock Direct", + "InfiniBand Windows Sockets Direct Provider." + }, + { IBSP_PM_COUNTER(BYTES_SEND), + "IBSP_PM_BYTES_TX_SEC", + "Send bytes/sec", + "Send bytes/second, excluding RDMA Write." + }, + { IBSP_PM_COUNTER(BYTES_RECV), + "IBSP_PM_BYTES_RX_SEC", + "Recv bytes/sec", + "Receive bytes/second, excluding RDMA Read." + }, + { IBSP_PM_COUNTER(BYTES_WRITE), + "IBSP_PM_RDMA_WR_SEC", + "RDMA Write bytes/sec", + "RDMA Write bytes/second." + }, + { IBSP_PM_COUNTER(BYTES_READ), + "IBSP_PM_RDMA_RD_SEC", + "RDMA Read bytes/sec", + "RDMA Read bytes/second." + }, + { IBSP_PM_COUNTER(BYTES_TOTAL), + "IBSP_PM_BYTES_SEC", + "Total bytes/sec", + "Total bytes transmitted per second, including send, " + "receive, RDMA Write, and RDMA Read." + }, + { IBSP_PM_COUNTER(COMP_SEND), + "IBSP_PM_SEND_COMPLETIONS_SEC", + "Send Completions/sec", + "Send and RDMA Write Completions/sec." + }, + { IBSP_PM_COUNTER(COMP_RECV), + "IBSP_PM_RECV_COMPLETIONS_SEC", + "Recv Completions/sec", + "Recv and RDMA Read Completions/sec." + }, + { IBSP_PM_COUNTER(COMP_TOTAL), + "IBSP_PM_COMPLETIONS_SEC", + "Total Completions/sec", + "Total Completions processed per second." + }, + { IBSP_PM_COUNTER(INTR_TOTAL), + "IBSP_PM_COMPLETIONS_INTR", + "Total Interrupts/sec", + "Completion Queue events per second." + } +}; + +#define IBSP_PM_NUM_SYMBOLS (sizeof(_pm_symbols)/sizeof(pm_symbol_def_t)) +#define IBSP_PM_LANGUAGE "009" /* good for English */ + +static CHAR * +_IBSPGenerateFileName(char *header, char *file ) +{ + DWORD size1, size; + CHAR *full_file_name; + int header_len = header == NULL ? 0 : strlen(header); + + size = GetTempPath(0, NULL); + if (size == 0) + { + fprintf( stderr, "GetTempPath failed\n" ); + return NULL; + } + size1 = size + strlen(file) + header_len; + full_file_name = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, size1); + if ( full_file_name == NULL ) + { + fprintf( stderr, "GetTempPath failed\n" ); + return NULL; + } + size1 = GetTempPath(size, full_file_name + header_len); + if (size != size1 + 1) + { + fprintf( stderr, "Very strange, GetTempPath returned something different\n" ); + HeapFree (GetProcessHeap (), 0, full_file_name); + return NULL; + } + if (header_len != 0) + { + memcpy(full_file_name, header, header_len); + } + strcat(full_file_name, file); + return full_file_name; +} + + +static DWORD +_IBSPPerfmonIniFilesGenerate( void ) +{ + FILE *f_handle; + DWORD num; + DWORD ret = ERROR_SUCCESS; + char *ibsp_pm_sym_file = NULL; + char *ibsp_pm_ini_file = NULL; + + /* create ".h" file first */ + ibsp_pm_sym_file = _IBSPGenerateFileName(NULL, IBSP_PM_SYM_H_FILE); + if( !ibsp_pm_sym_file ) + { + fprintf( stderr, "_IBSPGenerateFileName failed\n" ); + ret = ERROR_NOT_ENOUGH_MEMORY; + goto Cleanup; + } + + f_handle = fopen( ibsp_pm_sym_file, "w+" ); + + if( !f_handle ) + { + fprintf( stderr, "Create Header file %s failed\n", ibsp_pm_sym_file ); + ret = ERROR_FILE_INVALID; + goto Cleanup; + } + + fprintf( + f_handle, "/* %s Generated by program */ \r\n", ibsp_pm_sym_file ); + + + for( num = 0; num < IBSP_PM_NUM_SYMBOLS; num++ ) + { + fprintf( f_handle, "#define\t%s\t%d\r\n", + _pm_symbols[num].name_str, _pm_symbols[num].name_def ); + } + + fflush( f_handle ); + fclose( f_handle ); + + /* create 'ini' file next */ + ibsp_pm_ini_file = _IBSPGenerateFileName(NULL, IBSP_PM_INI_FILE); + if( !ibsp_pm_sym_file ) + { + fprintf( stderr, "_IBSPGenerateFileName failed\n" ); + ret = ERROR_NOT_ENOUGH_MEMORY; + goto Cleanup; + } + f_handle = fopen( ibsp_pm_ini_file, "w+" ); + + if( !f_handle ) + { + fprintf( stderr, "Create INI file %s failed\n", ibsp_pm_ini_file ); + ret = ERROR_FILE_INVALID; + goto Cleanup; + } + + fprintf( f_handle, "[info]\r\ndrivername=" IBSP_PM_SUBKEY_NAME + "\r\nsymbolfile=%s\r\n\r\n", ibsp_pm_sym_file ); + fprintf( f_handle,"[languages]\r\n" IBSP_PM_LANGUAGE + "=language" IBSP_PM_LANGUAGE "\r\n\r\n" ); + + fprintf( f_handle, + "[objects]\r\n%s_" IBSP_PM_LANGUAGE "_NAME=%s\r\n\r\n[text]\r\n", + _pm_symbols[0].name_str, _pm_symbols[0].name_desc ); + + for( num = 0; num < IBSP_PM_NUM_SYMBOLS; num++ ) + { + fprintf( f_handle,"%s_" IBSP_PM_LANGUAGE "_NAME=%s\r\n", + _pm_symbols[num].name_str, _pm_symbols[num].name_desc ); + fprintf( f_handle,"%s_" IBSP_PM_LANGUAGE "_HELP=%s\r\n", + _pm_symbols[num].name_str, _pm_symbols[num].help_desc ); + } + + fflush( f_handle ); + fclose( f_handle ); + +Cleanup: + if ( ibsp_pm_sym_file ) + { + HeapFree (GetProcessHeap (), 0, ibsp_pm_sym_file); + } + if ( ibsp_pm_ini_file ) + { + HeapFree (GetProcessHeap (), 0, ibsp_pm_ini_file); + } + return ret; +} + + +static void +_IBSPPerfmonIniFilesRemove( void ) +{ + char *ibsp_pm_sym_file = NULL; + char *ibsp_pm_ini_file = NULL; + + ibsp_pm_sym_file = _IBSPGenerateFileName(NULL, IBSP_PM_SYM_H_FILE); + if( !ibsp_pm_sym_file ) + { + fprintf( stderr, "_IBSPGenerateFileName failed\n" ); + goto Cleanup; + } + + ibsp_pm_ini_file = _IBSPGenerateFileName(NULL, IBSP_PM_INI_FILE); + if( !ibsp_pm_sym_file ) + { + fprintf( stderr, "_IBSPGenerateFileName failed\n" ); + goto Cleanup; + } + + if( !DeleteFile( ibsp_pm_ini_file ) ) + { + fprintf( stderr, "Delete file %s failed status %d\n", + ibsp_pm_ini_file, GetLastError() ); + } + if( !DeleteFile( ibsp_pm_sym_file ) ) + { + fprintf( stderr,"Delete file %s failed status %d\n", + ibsp_pm_sym_file, GetLastError() ); + } + +Cleanup: + if ( ibsp_pm_sym_file ) + { + HeapFree (GetProcessHeap (), 0, ibsp_pm_sym_file); + } + if ( ibsp_pm_ini_file ) + { + HeapFree (GetProcessHeap (), 0, ibsp_pm_ini_file); + } + +} + + +/* Try to create IB WSD Performance Register Keys */ +static LONG +_IBSPPerfmonRegisterKeys( void ) +{ + LONG reg_status; + HKEY pm_hkey; + DWORD typesSupp = 7; + + reg_status = RegCreateKeyEx( HKEY_LOCAL_MACHINE, + IBSP_PM_REGISTRY_PATH IBSP_PM_SUBKEY_PERF, 0, NULL, + REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &pm_hkey, NULL ); + + if( reg_status != ERROR_SUCCESS ) + { + fprintf( stderr, + "_IBSPPerfmonRegisterKeys Create Key %s failed with %d\n", + IBSP_PM_REGISTRY_PATH IBSP_PM_SUBKEY_PERF, reg_status ); + return reg_status; + } + + /* create/assign values to the key */ + RegSetValueExW( pm_hkey, L"Library", 0, REG_EXPAND_SZ, + (LPBYTE)provider_path, sizeof(provider_path) ); + + RegSetValueEx( pm_hkey, TEXT("Open"), 0, REG_SZ, + (LPBYTE)TEXT("IBSPPmOpen"), sizeof(TEXT("IBSPPmOpen")) ); + + RegSetValueEx( pm_hkey, TEXT("Collect"), 0, REG_SZ, + (LPBYTE)TEXT("IBSPPmCollectData"), sizeof(TEXT("IBSPPmCollectData")) ); + + RegSetValueEx( pm_hkey, TEXT("Close"), 0, REG_SZ, + (LPBYTE)TEXT("IBSPPmClose"), sizeof(TEXT("IBSPPmClose")) ); + + RegFlushKey( pm_hkey ); + RegCloseKey( pm_hkey ); + + reg_status = RegCreateKeyEx( HKEY_LOCAL_MACHINE, + IBSP_PM_EVENTLOG_PATH, 0, NULL, + REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &pm_hkey, NULL ); + + if( reg_status != ERROR_SUCCESS ) + { + fprintf(stderr, "Create EventLog Key failed with %d\n", reg_status ); + return reg_status; + } + + /* create/assign values to the key */ + RegSetValueExW( pm_hkey, L"EventMessageFile", 0, REG_EXPAND_SZ,\ + (LPBYTE)provider_path, sizeof(provider_path) ); + + RegSetValueEx( pm_hkey, TEXT("TypesSupported"), 0, REG_DWORD, + (LPBYTE)&typesSupp, sizeof(typesSupp) ); + + RegFlushKey( pm_hkey ); + RegCloseKey( pm_hkey ); + + return reg_status; +} + + +/* Try to destroy IB WSD Performance Register Keys */ +static LONG +_IBSPPerfmonDeregisterKeys( void ) +{ + LONG reg_status; + + reg_status = RegDeleteKeyEx( HKEY_LOCAL_MACHINE, + IBSP_PM_REGISTRY_PATH IBSP_PM_SUBKEY_PERF, + (KEY_WOW64_32KEY | KEY_WOW64_64KEY), 0 ); + + if( reg_status != ERROR_SUCCESS ) + { + fprintf( stderr, + "_IBSPPerfmonRegisterKeys Remove SubKey failed with %d\n", + GetLastError() ); + } + + reg_status = RegDeleteKeyEx( HKEY_LOCAL_MACHINE, + IBSP_PM_REGISTRY_PATH, (KEY_WOW64_32KEY | KEY_WOW64_64KEY), 0 ); + + if( reg_status != ERROR_SUCCESS ) + { + fprintf( stderr, + "_IBSPPerfmonRegisterKeys Remove SubKey failed with %d\n", + GetLastError() ); + } + + reg_status = RegDeleteKeyEx( HKEY_LOCAL_MACHINE, + IBSP_PM_EVENTLOG_PATH, (KEY_WOW64_32KEY | KEY_WOW64_64KEY), 0 ); + + if( reg_status != ERROR_SUCCESS ) + { + fprintf( stderr, + "_IBSPPerfmonRegisterKeys Remove SubKey failed with %d\n", + GetLastError() ); + } + + return reg_status; +} + + +/* + * functions will try to register performance counters + * definitions with PerfMon application. + * API externally called by lodctr.exe/unlodctr.exe utilities. + */ +static DWORD +_IBSPPerfmonRegisterCounters( void ) +{ + DWORD status; + char *ibsp_pm_ini_file = NULL; + + ibsp_pm_ini_file = _IBSPGenerateFileName("unused ", IBSP_PM_INI_FILE); + if( !ibsp_pm_ini_file ) + { + fprintf( stderr, "_IBSPGenerateFileName failed\n" ); + status = ERROR_NOT_ENOUGH_MEMORY; + goto Cleanup; + } + + /* + * format commandline string, as per SDK : + * Pointer to a null-terminated string that consists of one or more + * arbitrary letters, a space, and then the name of the initialization + * file. + */ + status = LoadPerfCounterTextStrings( ibsp_pm_ini_file, TRUE ); + if( status != ERROR_SUCCESS ) + { + status = GetLastError(); + fprintf( stderr, + "IBSPPerfmonRegisterCounters install failed status %d\n", status ); + } +Cleanup: + if ( ibsp_pm_ini_file ) + { + HeapFree (GetProcessHeap (), 0, ibsp_pm_ini_file); + } + + return status; +} + + +/* + * functions will try to unregister performance counters + * definitions with PerfMon application. + * API externally called by lodctr.exe/unlodctr.exe utilities. + */ +static DWORD +_IBSPPerfmonDeregisterCounters( void ) +{ + DWORD status; + + /* + * format commandline string, as per SDK : + * Pointer to a null-terminated string that consists of one or more + * arbitrary letters, a space, and then the name of the initialization + * file. + */ + status = UnloadPerfCounterTextStrings( + TEXT("unused ") TEXT(IBSP_PM_SUBKEY_NAME), TRUE ); + if( status != ERROR_SUCCESS ) + { + fprintf( stderr, + "IBSPPerfmonDeregisterCounters remove failed status %d\n", + status ); + } + return status; +} + +#endif /* PERFMON_ENABLED */ + + +/* + * Function: usage + * Description: Prints usage information. + */ +static void +usage (char *progname) +{ + printf ("usage: %s [-i/-r [-p]]\n", progname); + printf (" -i Install the service provider\n" + " -r Remove the %s service provider\n" + " -r Remove the specified service provider\n" + " -l List service providers\n",VER_PROVIDER); +} + + +/* Function: print_providers + * Description: + * This function prints out each entry in the Winsock catalog. +*/ +static void print_providers(void) +{ + WSAPROTOCOL_INFOW *protocol_info; + unsigned int protocol_count; + unsigned int i; + DWORD protocol_size; + INT err_no; + int rc; + + /* Find the size of the buffer */ + protocol_size = 0; + rc = WSCEnumProtocols (NULL, NULL, &protocol_size, &err_no); + if (rc == SOCKET_ERROR && err_no != WSAENOBUFS) { + printf("WSCEnumProtocols() returned error (%d)\n", err_no); + return; + } + + /* Allocate the buffer */ + protocol_info = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, protocol_size); + if (protocol_info == NULL) { + printf("HeapAlloc() failed\n"); + return; + } + + /* Enumerate the catalog for real */ + rc = WSCEnumProtocols (NULL, protocol_info, &protocol_size, &err_no); + if (rc == SOCKET_ERROR) { + printf("WSCEnumProtocols returned error for real enumeration (%d)\n", + err_no); + HeapFree (GetProcessHeap (), 0, protocol_info); + return; + } + + protocol_count = rc; + + for (i = 0; i < protocol_count; i++) { + printf ("%010d - %S\n", protocol_info[i].dwCatalogEntryId, + protocol_info[i].szProtocol); + } + + HeapFree (GetProcessHeap (), 0, protocol_info); + + return; +} + +/* + * Function: install_provider + * Description: installs the service provider + * + * Note: most of the information setup here comes from "MSDN Home > + * MSDN Library > Windows Development > Network Devices and + * Protocols > Design Guide > System Area Networks > Windows Sockets + * Direct > Windows Sockets Direct Component Operation > Installing + * Windows Sockets Direct Components". + * The direct link is http://msdn.microsoft.com/library/default.asp?url=/library/en-us/network/hh/network/wsdp_2xrb.asp + */ +static void install_provider(void) +{ + int rc; + INT err_no; + LONG reg_error; + WSAPROTOCOL_INFOW provider; + HKEY hkey; + size_t res; + size_t st_len; + + /* Now setup the key. */ + reg_error = RegCreateKeyExA( HKEY_LOCAL_MACHINE, winsock_key_path, + 0, NULL, REG_OPTION_NON_VOLATILE, (KEY_WRITE | KEY_READ), NULL, + &hkey, NULL ); + if( reg_error == ERROR_SUCCESS ) + { + reg_error = RegSetValueExA( hkey, openib_key_name, 0, REG_BINARY, + (PBYTE)&provider_guid, sizeof(GUID) ); + if( reg_error == ERROR_SUCCESS ) + { + /* Force the system to write the new key now. */ + RegFlushKey(hkey); + } + else + { + fprintf(stderr, "RegSetValueEx failed with %d\n", GetLastError()); + } + + RegCloseKey(hkey); + } + else + { + fprintf(stderr, "Could not get a handle on Winsock registry (%d)\n", GetLastError()); + } + + /* Setup the values in PROTOCOL_INFO */ + provider.dwServiceFlags1 = + XP1_GUARANTEED_DELIVERY | + XP1_GUARANTEED_ORDER | + XP1_MESSAGE_ORIENTED | + XP1_GRACEFUL_CLOSE; + provider.dwServiceFlags2 = 0; /* Reserved */ + provider.dwServiceFlags3 = 0; /* Reserved */ + provider.dwServiceFlags4 = 0; /* Reserved */ + provider.dwProviderFlags = PFL_HIDDEN; + provider.ProviderId = provider_guid; /* Service Provider ID provided by vendor. Need to be changed later */ + provider.dwCatalogEntryId = 0; + provider.ProtocolChain.ChainLen = 1; /* Base Protocol Service Provider */ + provider.iVersion = 2; /* don't know what it is */ + provider.iAddressFamily = AF_INET; + provider.iMaxSockAddr = 16; + provider.iMinSockAddr = 16; + provider.iSocketType = SOCK_STREAM; + provider.iProtocol = IPPROTO_TCP; + provider.iProtocolMaxOffset = 0; + provider.iNetworkByteOrder = BIGENDIAN; + provider.iSecurityScheme = SECURITY_PROTOCOL_NONE; + provider.dwMessageSize = 0xFFFFFFFF; /* IB supports 32-bit lengths for data transfers on RC */ + provider.dwProviderReserved = 0; + + st_len = strlen(provider_name); + rc = mbstowcs(provider.szProtocol, provider_name,st_len); //do not count \0 + // We can't use there mbstowcs_s + //rc = mbstowcs_s(&convertedChars, provider.szProtocol, sizeof(provider_name), provider_name, ); + if (rc != st_len) { + printf(" Can't convert string %s to WCHAR\n",provider_name); + printf("Converted %d from %d\n", rc, st_len); + } + wcscpy( provider.szProtocol + st_len, provider_prefix); + //wprintf(L"provider.szProtocol = %s\n",provider.szProtocol); + + rc = WSCInstallProvider( + &provider_guid, provider_path, &provider, 1, &err_no ); + if( rc == SOCKET_ERROR ) + { + if( err_no == WSANO_RECOVERY ) + printf("The provider is already installed\n"); + else + printf("install_provider: WSCInstallProvider failed: %d\n", err_no); + } +} + +/* + * Function: remove_provider + * Description: removes our provider. + */ +static void remove_provider( const char* const provider_name ) +{ + int rc; + int err_no; + LONG reg_error; + HKEY hkey; + + /* Remove our key */ + reg_error = RegOpenKeyExA(HKEY_LOCAL_MACHINE, + winsock_key_path, + 0, + (KEY_WRITE | KEY_READ), + &hkey); + if (reg_error == ERROR_SUCCESS) { + + reg_error = RegDeleteValueA(hkey, provider_name); + if (reg_error == ERROR_SUCCESS) { + /* Force the system to remove the key now. */ + RegFlushKey(hkey); + } else { + fprintf(stderr, "RegDeleteValue failed with %d\n", GetLastError()); + } + + RegCloseKey(hkey); + } + + /* Remove from the catalog */ + rc = WSCDeinstallProvider(&provider_guid, &err_no); + if (rc == SOCKET_ERROR) { + printf ("WSCDeinstallProvider failed: %d\n", err_no); + } + +#ifdef _WIN64 + /* Remove from the 32-bit catalog too! */ + rc = WSCDeinstallProvider32(&provider_guid, &err_no); + if (rc == SOCKET_ERROR) { + printf ("WSCDeinstallProvider32 failed: %d\n", err_no); + } +#endif /* _WIN64 */ +} + +/* Function: main + * + * Description: + * Parse the command line arguments and call either the install or remove + * routine. + */ +int __cdecl main (int argc, char *argv[]) +{ + WSADATA wsd; + + /* Load Winsock */ + if (WSAStartup (MAKEWORD (2, 2), &wsd) != 0) { + printf ("InstallSP: Unable to load Winsock: %d\n", GetLastError ()); + return -1; + } + + /* Confirm that the WinSock DLL supports 2.2. Note that if the + * DLL supports versions greater than 2.2 in addition to 2.2, it + * will still return 2.2 in wVersion since that is the version we + * requested. */ + if (LOBYTE (wsd.wVersion) != 2 || HIBYTE (wsd.wVersion) != 2) { + + /* Tell the user that we could not find a usable WinSock DLL. */ + WSACleanup (); + printf + ("InstallSP: Unable to find a usable version of Winsock DLL\n"); + return -1; + } + if (argc < 2) { + usage (argv[0]); + return -1; + } + if ((strlen (argv[1]) != 2) && (argv[1][0] != '-') + && (argv[1][0] != '/')) { + usage (argv[0]); + return -1; + } + switch (tolower (argv[1][1])) { + + case 'i': + /* Install the Infiniband Service Provider */ + install_provider (); +#ifdef PERFMON_ENABLED + _IBSPPerfmonIniFilesGenerate(); + if ( _IBSPPerfmonRegisterKeys() == ERROR_SUCCESS ) + _IBSPPerfmonRegisterCounters(); +#endif + break; + + case 'r': + /* Remove the service provider */ + if( argc == 2 ) + remove_provider( openib_key_name ); + else + remove_provider( argv[2] ); +#ifdef PERFMON_ENABLED + _IBSPPerfmonIniFilesRemove(); + if ( _IBSPPerfmonDeregisterCounters() == ERROR_SUCCESS ) + _IBSPPerfmonDeregisterKeys(); +#endif + break; + + case 'l': + /* List existing providers */ + print_providers(); + break; + + default: + usage (argv[0]); + break; + } + + WSACleanup (); + + return 0; +} diff --git a/branches/WOF2-3/tools/wsdinstall/user/installsp.exe.manifest b/branches/WOF2-3/tools/wsdinstall/user/installsp.exe.manifest new file mode 100644 index 00000000..d5e574e6 --- /dev/null +++ b/branches/WOF2-3/tools/wsdinstall/user/installsp.exe.manifest @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/branches/WOF2-3/tools/wsdinstall/user/installsp.rc b/branches/WOF2-3/tools/wsdinstall/user/installsp.rc new file mode 100644 index 00000000..51a73c81 --- /dev/null +++ b/branches/WOF2-3/tools/wsdinstall/user/installsp.rc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef _DEBUG_ +#define VER_FILEDESCRIPTION_STR "Winsock Direct for InfiniBand installer (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "Winsock Direct for InfiniBand installer" +#endif + +#define VER_INTERNALNAME_STR "installsp.exe" +#define VER_ORIGINALFILENAME_STR "installsp.exe" + +#include diff --git a/branches/WOF2-3/tools/wsdinstall/user/makefile b/branches/WOF2-3/tools/wsdinstall/user/makefile new file mode 100644 index 00000000..a28a5610 --- /dev/null +++ b/branches/WOF2-3/tools/wsdinstall/user/makefile @@ -0,0 +1,8 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# +MINIMUM_NT_TARGET_VERSION=0x502 + +!INCLUDE ..\..\..\inc\openib.def diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_adapter_util.h b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_adapter_util.h new file mode 100644 index 00000000..f032aae0 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_adapter_util.h @@ -0,0 +1,300 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dapl_adapter_util.h + * + * PURPOSE: Utility defs & routines for the adapter data structure + * + * $Id$ + * + **********************************************************************/ + +#ifndef _DAPL_ADAPTER_UTIL_H_ +#define _DAPL_ADAPTER_UTIL_H_ + +#include +typedef enum async_handler_type +{ + DAPL_ASYNC_UNAFILIATED, + DAPL_ASYNC_CQ_ERROR, + DAPL_ASYNC_CQ_COMPLETION, + DAPL_ASYNC_QP_ERROR +} DAPL_ASYNC_HANDLER_TYPE; + + +DAT_RETURN dapls_ib_enum_hcas ( + OUT DAPL_HCA_NAME **hca_names, + OUT DAT_COUNT *total_hca_count, + IN const char *vendor ); + +DAT_RETURN dapls_ib_open_hca ( + IN IB_HCA_NAME name, + OUT ib_hca_handle_t *ib_hca_handle); + +DAT_RETURN dapls_ib_close_hca ( + IN ib_hca_handle_t ib_hca_handle); + +DAT_RETURN dapls_ib_qp_alloc ( + IN DAPL_IA *ia_ptr, + IN DAPL_EP *ep_ptr, + IN DAPL_EP *ep_ctx_ptr ); + +DAT_RETURN dapls_ib_qp_free ( + IN DAPL_IA *ia_ptr, + IN DAPL_EP *ep_ptr ); + +DAT_RETURN dapls_ib_qp_modify ( + IN DAPL_IA *ia_ptr, + IN DAPL_EP *ep_ptr, + IN DAT_EP_ATTR *ep_attr ); +DAT_RETURN dapls_ib_connect ( + IN DAT_EP_HANDLE ep_handle, + IN DAT_IA_ADDRESS_PTR remote_ia_address, + IN DAT_CONN_QUAL remote_conn_qual, + IN DAT_COUNT prd_size, + IN DAPL_PRIVATE *prd_ptr ); + +DAT_RETURN dapls_ib_disconnect ( + IN DAPL_EP *ep_ptr, + IN DAT_CLOSE_FLAGS close_flags ); + +DAT_RETURN dapls_ib_setup_conn_listener ( + IN DAPL_IA *ia_ptr, + IN DAT_UINT64 ServiceID, + IN DAPL_SP *sp_ptr ); + +DAT_RETURN dapls_ib_remove_conn_listener ( + IN DAPL_IA *ia_ptr, + IN DAPL_SP *sp_ptr); + +DAT_RETURN dapls_ib_accept_connection ( + IN DAT_CR_HANDLE cr_handle, + IN DAT_EP_HANDLE ep_handle, + IN DAT_COUNT private_data_size, + IN DAPL_PRIVATE *prd_ptr ); + +DAT_RETURN dapls_ib_reject_connection ( + IN ib_cm_handle_t cm_handle, + IN int reject_reason ); + +DAT_RETURN dapls_ib_cr_handoff ( + IN DAT_CR_HANDLE cr_handle, + IN DAT_CONN_QUAL cr_handoff ); + +DAT_RETURN dapls_ib_setup_async_callback ( + IN DAPL_IA *ia_ptr, + IN DAPL_ASYNC_HANDLER_TYPE handler_type, + IN unsigned int * callback_handle, + IN ib_async_handler_t callback, + IN void *context ); + +DAT_RETURN dapls_ib_cq_alloc ( + IN DAPL_IA *ia_ptr, + IN DAPL_EVD *evd_ptr, + IN DAT_COUNT *cqlen); + +DAT_RETURN dapls_ib_cq_resize ( + IN DAPL_IA *ia_ptr, + IN DAPL_EVD *evd_ptr, + IN DAT_COUNT *qlen ); + +DAT_RETURN dapls_ib_cq_free ( + IN DAPL_IA *ia_ptr, + IN DAPL_EVD *evd_ptr); + +DAT_RETURN dapls_set_cq_notify ( + IN DAPL_IA *ia_ptr, + IN DAPL_EVD *evd_ptr); + +DAT_RETURN dapls_ib_cqd_create ( + IN DAPL_HCA *hca_ptr); + +DAT_RETURN dapls_ib_cqd_destroy ( + IN DAPL_HCA *hca_ptr); + +DAT_RETURN dapls_ib_pd_alloc ( + IN DAPL_IA *ia_ptr, + IN DAPL_PZ *pz); + +DAT_RETURN dapls_ib_pd_free ( + IN DAPL_PZ *pz); + +DAT_RETURN dapls_ib_mr_register ( + IN DAPL_IA *ia_ptr, + IN DAPL_LMR *lmr, + IN DAT_PVOID virt_addr, + IN DAT_VLEN length, + IN DAT_MEM_PRIV_FLAGS privileges); + +DAT_RETURN dapls_ib_mr_deregister ( + IN DAPL_LMR *lmr); + +DAT_RETURN dapls_ib_mr_register_shared ( + IN DAPL_IA *ia_ptr, + IN DAPL_LMR *lmr, + IN DAT_MEM_PRIV_FLAGS privileges); + +DAT_RETURN dapls_ib_get_any_svid ( + IN DAPL_HCA *hca_ptr, + OUT DAT_CONN_QUAL *p_svid); + +DAT_RETURN dapls_ib_mw_alloc ( + IN DAPL_RMR *rmr); + +DAT_RETURN dapls_ib_mw_free ( + IN DAPL_RMR *rmr); + +DAT_RETURN dapls_ib_mw_bind ( + IN DAPL_RMR *rmr, + IN DAPL_LMR *lmr, + IN DAPL_EP *ep, + IN DAPL_COOKIE *cookie, + IN DAT_VADDR virtual_address, + IN DAT_VLEN length, + IN DAT_MEM_PRIV_FLAGS mem_priv, + IN ib_bool_t is_signaled); + +DAT_RETURN dapls_ib_mw_unbind ( + IN DAPL_RMR *rmr, + IN DAPL_EP *ep, + IN DAPL_COOKIE *cookie, + IN ib_bool_t is_signaled); + +DAT_RETURN dapls_ib_query_hca ( + IN DAPL_HCA *hca_ptr, + OUT DAT_IA_ATTR *ia_attr, + OUT DAT_EP_ATTR *ep_attr, + OUT DAT_SOCK_ADDR6 *ip_addr); + +DAT_RETURN dapls_ib_completion_poll ( + IN ib_hca_handle_t hca_handle, + IN ib_cq_handle_t cq_handle, + IN ib_work_completion_t *cqe_ptr); + +DAT_RETURN dapls_ib_completion_notify ( + IN ib_hca_handle_t hca_handle, + IN ib_cq_handle_t cq_handle, + IN ib_notification_type_t type); + +DAT_RETURN +dapls_ib_n_completions_notify ( + IN ib_hca_handle_t hca_handle, + IN ib_cq_handle_t cq_handle, + IN uint32_t n_cqes); + +DAT_RETURN +dapls_ib_peek_cq ( + IN ib_cq_handle_t cq_handle, + OUT uint32_t* p_n_cqes); + +DAT_RETURN +dapls_ib_wait_object_create ( + IN cl_waitobj_handle_t *p_cq_wait_obj_handle); + +DAT_RETURN +dapls_ib_wait_object_destroy ( + IN cl_waitobj_handle_t cq_wait_obj_handle); + +DAT_RETURN +dapls_ib_wait_object_wakeup ( + IN cl_waitobj_handle_t cq_wait_obj_handle); + +DAT_RETURN +dapls_ib_wait_object_wait ( + IN cl_waitobj_handle_t cq_wait_obj_handle, + IN uint32_t timeout); + +DAT_DTO_COMPLETION_STATUS +dapls_ib_get_dto_status( + IN ib_work_completion_t *cqe_ptr); + +DAT_RETURN +dapls_ib_reinit_ep ( + IN DAPL_EP *ep_ptr); + +void dapls_ib_disconnect_clean ( + IN DAPL_EP *ep_ptr, + IN DAT_BOOLEAN passive, + IN const ib_cm_events_t ib_cm_event); + +DAT_RETURN dapls_ib_get_async_event( + IN ib_error_record_t *cause_ptr, + OUT DAT_EVENT_NUMBER *async_event); + +DAT_COUNT dapls_ib_private_data_size ( + IN DAPL_PRIVATE *prd_ptr, + IN DAPL_PDATA_OP conn_op); + +DAT_EVENT_NUMBER dapls_ib_get_dat_event ( + IN const ib_cm_events_t ib_cm_event, + IN DAT_BOOLEAN active); + +ib_cm_events_t dapls_ib_get_cm_event ( + IN DAT_EVENT_NUMBER dat_event_num); + +DAT_RETURN dapls_ib_cm_remote_addr ( + IN DAT_HANDLE dat_handle, + IN DAPL_PRIVATE *prd_ptr, + OUT DAT_SOCK_ADDR6 *remote_ia_address ); + +/* + * Values for provider DAT_NAMED_ATTR + */ +#define IB_QP_STATE 1 /* QP state change request */ + + +#ifndef NO_NAME_SERVICE + +DAT_RETURN dapls_ib_ns_create_gid_map ( + IN DAPL_HCA *hca_ptr); + +DAT_RETURN dapls_ib_ns_remove_gid_map ( + IN DAPL_HCA *hca_ptr); + +DAT_RETURN dapls_ib_ns_map_gid ( + IN DAPL_HCA *hca_ptr, + IN DAT_IA_ADDRESS_PTR p_ia_address, + OUT GID *p_gid); + +DAT_RETURN dapls_ib_ns_map_ipaddr ( + IN DAPL_HCA *hca_ptr, + IN GID gid, + OUT DAT_IA_ADDRESS_PTR p_ia_address); + +#endif /* NO_NAME_SERVICE */ + +#ifdef IBAPI +#include "dapl_ibapi_dto.h" +#elif VAPI +#include "dapl_vapi_dto.h" +#else +#include "dapl_ibal_dto.h" +#endif + + +#endif /* _DAPL_ADAPTER_UTIL_H_ */ diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_cno_create.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_cno_create.c new file mode 100644 index 00000000..f7fee96b --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_cno_create.c @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_cno_create.c + * + * PURPOSE: Consumer Notification Object creation + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 3.2.1 + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_cno_util.h" +#include "dapl_ia_util.h" + +/* + * dapl_cno_create + * + * DAPL Requirements Version xxx, 6.3.4.1 + * + * Create a consumer notification object instance + * + * Input: + * ia_handle + * wait_agent + * cno_handle + * + * Output: + * cno_handle + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_HANDLE + * DAT_INVALID_PARAMETER + */ +DAT_RETURN dapl_cno_create( + IN DAT_IA_HANDLE ia_handle, /* ia_handle */ + IN DAT_OS_WAIT_PROXY_AGENT wait_agent, /* agent */ + OUT DAT_CNO_HANDLE *cno_handle) /* cno_handle */ + +{ + DAPL_IA *ia_ptr; + DAPL_CNO *cno_ptr; + DAT_RETURN dat_status; + + ia_ptr = (DAPL_IA *)ia_handle; + cno_ptr = NULL; + dat_status = DAT_SUCCESS; + + if (DAPL_BAD_HANDLE (ia_handle, DAPL_MAGIC_IA)) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE,DAT_INVALID_HANDLE_IA); + goto bail; + } + + cno_ptr = dapl_cno_alloc(ia_ptr, wait_agent); + + if (!cno_ptr) + { + dat_status = DAT_ERROR (DAT_INSUFFICIENT_RESOURCES,DAT_RESOURCE_MEMORY); + goto bail; + } + + cno_ptr->cno_state = DAPL_CNO_STATE_UNTRIGGERED; + + dapl_ia_link_cno(ia_ptr, cno_ptr); + + *cno_handle = cno_ptr; + + bail: + if (dat_status != DAT_SUCCESS && cno_ptr != NULL) + { + dapl_cno_dealloc(cno_ptr); + } + return dat_status; +} + diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_cno_free.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_cno_free.c new file mode 100644 index 00000000..5efee23d --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_cno_free.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_cno_free.c + * + * PURPOSE: Consumer Notification Object destruction + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 3.2.2 + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_ia_util.h" +#include "dapl_cno_util.h" + +/* + * dapl_cno_free + * + * DAPL Requirements Version xxx, 6.3.2.2 + * + * Destroy a consumer notification object instance + * + * Input: + * cno_handle + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + * DAT_INVALID_STATE + */ +DAT_RETURN dapl_cno_free( + IN DAT_CNO_HANDLE cno_handle) /* cno_handle */ + +{ + DAPL_CNO *cno_ptr; + DAT_RETURN dat_status; + + dat_status = DAT_SUCCESS; + cno_ptr = (DAPL_CNO *)cno_handle; + + if (DAPL_BAD_HANDLE (cno_handle, DAPL_MAGIC_CNO)) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE,DAT_INVALID_HANDLE_CNO); + goto bail; + } + + if (cno_ptr->cno_ref_count != 0 + || cno_ptr->cno_waiters != 0) + { + dat_status = DAT_ERROR (DAT_INVALID_STATE,DAT_INVALID_STATE_CNO_IN_USE); + goto bail; + } + + dapl_ia_unlink_cno (cno_ptr->header.owner_ia, cno_ptr); + dapl_cno_dealloc (cno_ptr); + +bail: + return dat_status; +} + diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_cno_modify_agent.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_cno_modify_agent.c new file mode 100644 index 00000000..b60ebb9d --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_cno_modify_agent.c @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_cno_modify_agent.c + * + * PURPOSE: Modify the wait proxy agent associted with the CNO + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 3.2.4 + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" + +/* + * dapl_cno_modify_agent + * + * DAPL Requirements Version xxx, 6.3.2.4 + * + * Modify the wait proxy agent associted with the CNO + * + * Input: + * cno_handle + * prx_agent + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + * DAT_INVALID_PARAMETER + */ +DAT_RETURN dapl_cno_modify_agent( + IN DAT_CNO_HANDLE cno_handle, /* cno_handle */ + IN DAT_OS_WAIT_PROXY_AGENT prx_agent ) /* agent */ + +{ + DAPL_CNO *cno_ptr; + DAT_RETURN dat_status; + + dat_status = DAT_SUCCESS; + if ( DAPL_BAD_HANDLE (cno_handle, DAPL_MAGIC_CNO) ) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE,DAT_INVALID_HANDLE_CNO); + goto bail; + } + + cno_ptr = (DAPL_CNO *) cno_handle; + dapl_os_lock(&cno_ptr->header.lock); + cno_ptr->cno_wait_agent = prx_agent; + dapl_os_unlock(&cno_ptr->header.lock); + + bail: + return dat_status; +} + diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_cno_query.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_cno_query.c new file mode 100644 index 00000000..76b3e4ab --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_cno_query.c @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_cno_query.c + * + * PURPOSE: Return the consumer parameters of the CNO + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 3.2.5 + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" + +/* + * dapl_cno_query + * + * DAPL Requirements Version xxx, 6.3.2.5 + * + * Return the consumer parameters of the CNO + * + * Input: + * cno_handle + * cno_param_mask + * cno_param + * + * Output: + * cno_param + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + * DAT_INVALID_PARAMETER + */ +DAT_RETURN dapl_cno_query( + IN DAT_CNO_HANDLE cno_handle, /* cno_handle */ + IN DAT_CNO_PARAM_MASK cno_param_mask, /* cno_param_mask */ + OUT DAT_CNO_PARAM *cno_param ) /* cno_param */ + + +{ + DAPL_CNO *cno_ptr; + DAT_RETURN dat_status; + + dat_status = DAT_SUCCESS; + + if ( DAPL_BAD_HANDLE (cno_handle, DAPL_MAGIC_CNO) ) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE,DAT_INVALID_HANDLE_CNO); + goto bail; + } + + if ( NULL == cno_param ) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER,DAT_INVALID_ARG3); + goto bail; + } + + cno_ptr = (DAPL_CNO *) cno_handle; + if ( cno_param_mask ) + { + cno_param->ia_handle = cno_ptr->header.owner_ia; + cno_param->agent = cno_ptr->cno_wait_agent; + } + else + { + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG2); + } + bail: + return dat_status; +} + diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_cno_util.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_cno_util.c new file mode 100644 index 00000000..cc83220b --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_cno_util.c @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_cno_util.c + * + * PURPOSE: Manage CNO Info structure + * + * $Id$ + **********************************************************************/ + +#include "dapl_ia_util.h" +#include "dapl_cno_util.h" +#include "dapl_adapter_util.h" + + + +/* + * dapl_cno_alloc + * + * alloc and initialize an EVD struct + * + * Input: + * ia + * + * Returns: + * cno_ptr, or null on failure. + */ +DAPL_CNO * +dapl_cno_alloc( + IN DAPL_IA *ia_ptr, + IN DAT_OS_WAIT_PROXY_AGENT wait_agent) +{ + DAPL_CNO *cno_ptr; + + cno_ptr = (DAPL_CNO *) dapl_os_alloc(sizeof (DAPL_CNO)); + if (!cno_ptr) + { + return NULL; + } + + /* zero the structure */ + dapl_os_memzero(cno_ptr, sizeof(DAPL_CNO)); + + /* + * Initialize the header. + */ + cno_ptr->header.provider = ia_ptr->header.provider; + cno_ptr->header.magic = DAPL_MAGIC_CNO; + cno_ptr->header.handle_type = DAT_HANDLE_TYPE_CNO; + cno_ptr->header.owner_ia = ia_ptr; + cno_ptr->header.user_context.as_64 = 0; + cno_ptr->header.user_context.as_ptr = NULL; + dapl_llist_init_entry (&cno_ptr->header.ia_list_entry); + dapl_os_lock_init (&cno_ptr->header.lock); + + /* + * Initialize the body + */ + cno_ptr->cno_waiters = 0; + cno_ptr->cno_ref_count = 0; + cno_ptr->cno_state = DAPL_CNO_STATE_UNTRIGGERED; + cno_ptr->cno_evd_triggered = NULL; + cno_ptr->cno_wait_agent = wait_agent; + dapl_os_wait_object_init(&cno_ptr->cno_wait_object); + + return cno_ptr; +} + +/* + * dapl_cno_dealloc + * + * Free the passed in CNO structure. + * + * Input: + * cno_ptr + * + * Output: + * none + * + * Returns: + * none + * + */ +void +dapl_cno_dealloc( + IN DAPL_CNO *cno_ptr) +{ + dapl_os_assert (cno_ptr->header.magic == DAPL_MAGIC_CNO); + dapl_os_assert (cno_ptr->cno_ref_count == 0); + + /* + * deinitialize the header + */ + cno_ptr->header.magic = DAPL_MAGIC_INVALID; /* reset magic to prevent reuse */ + + dapl_os_wait_object_destroy (&cno_ptr->cno_wait_object); + dapl_os_free (cno_ptr, sizeof (DAPL_CNO)); +} + + +/* + * dapl_cno_trigger + * + * DAPL Internal routine to trigger the specified CNO. + * Called by the callback of some EVD associated with the CNO. + * + * Input: + * cno_ptr + * evd_ptr EVD triggering + * + * Output: + * None + * + * Returns: + * None + */ +void +dapl_cno_trigger( + IN DAPL_CNO *cno_ptr, + IN DAPL_EVD *evd_ptr) +{ + dapl_os_assert (cno_ptr != NULL ); + dapl_os_assert(cno_ptr->header.magic == DAPL_MAGIC_CNO); + dapl_os_assert(evd_ptr == NULL || evd_ptr->header.magic == DAPL_MAGIC_EVD); + + dapl_os_lock(&cno_ptr->header.lock); + + /* Maybe I should just return, but this really shouldn't happen. */ + dapl_os_assert(cno_ptr->cno_state != DAPL_CNO_STATE_DEAD); + + if (cno_ptr->cno_state == DAPL_CNO_STATE_UNTRIGGERED) + { + DAT_OS_WAIT_PROXY_AGENT agent; + + /* Squirrel away wait agent, and delete link. */ + agent = cno_ptr->cno_wait_agent; + + /* Separate assignments for windows compiler. */ + cno_ptr->cno_wait_agent.instance_data = NULL; + cno_ptr->cno_wait_agent.proxy_agent_func = NULL; + + cno_ptr->cno_evd_triggered = evd_ptr; + + /* + * Must set to triggerred and let waiter untrigger to handle + * timeout of waiter. + */ + cno_ptr->cno_state = DAPL_CNO_STATE_TRIGGERED; + if (cno_ptr->cno_waiters > 0) + { + dapl_os_wait_object_wakeup(&cno_ptr->cno_wait_object); + } + + dapl_os_unlock(&cno_ptr->header.lock); + + /* Trigger the OS proxy wait agent, if one exists. */ + if (agent.proxy_agent_func != (DAT_AGENT_FUNC) NULL) + { + agent.proxy_agent_func ( + agent.instance_data, (DAT_EVD_HANDLE) evd_ptr ); + } + } + else + { + dapl_os_unlock(&cno_ptr->header.lock); + } + + return; +} + diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_cno_util.h b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_cno_util.h new file mode 100644 index 00000000..4d647e6e --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_cno_util.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dapl_cno_util.h + * + * PURPOSE: Utility defs & routines for the cno data structure + * + * $Id$ + * + **********************************************************************/ + +#ifndef _DAPL_CNO_UTIL_H_ +#define _DAPL_CNO_UTIL_H_ + +#include "dapl.h" + +DAPL_CNO * +dapl_cno_alloc ( + IN DAPL_IA *ia_ptr, + IN DAT_OS_WAIT_PROXY_AGENT wait_agent) ; + +void +dapl_cno_dealloc ( + IN DAPL_CNO *cno_ptr) ; + +void +dapl_cno_trigger( + IN DAPL_CNO *cno_ptr, + IN DAPL_EVD *evd_ptr); + +#endif diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_cno_wait.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_cno_wait.c new file mode 100644 index 00000000..0504734a --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_cno_wait.c @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_cno_wait.c + * + * PURPOSE: Wait for a consumer notification event + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 3.2.3 + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" + +/* + * dapl_cno_wait + * + * DAPL Requirements Version xxx, 6.3.2.3 + * + * Wait for a consumer notification event + * + * Input: + * cno_handle + * timeout + * evd_handle + * + * Output: + * evd_handle + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + * DAT_QUEUE_EMPTY + * DAT_INVALID_PARAMETER + */ +DAT_RETURN dapl_cno_wait( + IN DAT_CNO_HANDLE cno_handle, /* cno_handle */ + IN DAT_TIMEOUT timeout, /* agent */ + OUT DAT_EVD_HANDLE *evd_handle) /* ia_handle */ + +{ + DAPL_CNO *cno_ptr; + DAT_RETURN dat_status; + + if ( DAPL_BAD_HANDLE (cno_handle, DAPL_MAGIC_CNO) ) + { + dat_status = DAT_INVALID_HANDLE | DAT_INVALID_HANDLE_CNO; + goto bail; + } + + dat_status = DAT_SUCCESS; + + cno_ptr = (DAPL_CNO *) cno_handle; + + if ( cno_ptr->cno_state == DAPL_CNO_STATE_DEAD ) + { + dat_status = DAT_ERROR (DAT_INVALID_STATE,DAT_INVALID_STATE_CNO_DEAD); + goto bail; + } + + dapl_os_lock ( &cno_ptr->header.lock ); + while (cno_ptr->cno_state == DAPL_CNO_STATE_UNTRIGGERED + && DAT_GET_TYPE(dat_status) != DAT_TIMEOUT_EXPIRED) + { + cno_ptr->cno_waiters++; + dapl_os_unlock ( &cno_ptr->header.lock ); + dat_status = dapl_os_wait_object_wait ( + &cno_ptr->cno_wait_object, timeout ); + dapl_os_lock ( &cno_ptr->header.lock ); + cno_ptr->cno_waiters--; + } + + if ( cno_ptr->cno_state == DAPL_CNO_STATE_DEAD ) + { + dat_status = DAT_ERROR (DAT_INVALID_STATE,DAT_INVALID_STATE_CNO_DEAD); + } + else if ( dat_status == DAT_SUCCESS ) + { + /* + * After the first triggering, this will be a valid handle. + * If we're racing with wakeups of other CNO waiters, + * that's ok. + */ + dapl_os_assert ( cno_ptr->cno_state == DAPL_CNO_STATE_TRIGGERED ); + cno_ptr->cno_state = DAPL_CNO_STATE_UNTRIGGERED; + *evd_handle = cno_ptr->cno_evd_triggered; + } + else if ( dat_status == DAT_TIMEOUT_EXPIRED ) + { + cno_ptr->cno_state = DAPL_CNO_STATE_UNTRIGGERED; + *evd_handle = NULL; + dat_status = DAT_QUEUE_EMPTY; + } + else + { + /* + * The only other reason we could have made it out of + * the loop is a timeout or an interrupted system call. + */ + dapl_os_assert(DAT_GET_TYPE(dat_status) == DAT_TIMEOUT_EXPIRED || + DAT_GET_TYPE(dat_status) == DAT_INTERRUPTED_CALL); + } + dapl_os_unlock ( &cno_ptr->header.lock ); + + bail: + return dat_status; +} + diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_cookie.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_cookie.c new file mode 100644 index 00000000..28dbddfd --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_cookie.c @@ -0,0 +1,400 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_cookie.c + * + * PURPOSE: Manage CQE cookie structures + * + * The DAPL spec requires that all a cookies passed to a posting operation + * be returned in the operation's corresponding completion. + * + * Implementing this feature is complicated by the user's ability to + * suppress event generation for specific operations. When these operations + * complete successfully, the provider does not have an easy way to + * deallocate resources devoted to storing context data for these operations. + * + * To support this feature, a pool of memory is allocated up front large + * enough to hold cookie data for the maximum number of operations possible + * on an endpoint. + * + * Two pieces of information are maintained to manage cookie allocation: + * + * head index : index of next unallocated cookie + * tail index : index of last unallocated cookie + * + * Each cookie store its index in this memory pool. + * + * When an event is received, the index stored in the event's cookie will be + * used to update the tail. This will implicitly deallocate all of the cookies + * "between" the old tail and the new tail. + * + * The implementation relies on the following assumptions: + * + * - there can be only 1 thread in dat_ep_post_send(), dat_ep_post_rdma_write(), + * dat_ep_post_rdma_read(), or dat_rmr_bind() at a time, therefore + * dapls_cb_get() does not need to be thread safe when manipulating + * request data structures. + * + * - there can be only 1 thread in dat_ep_post_recv(), therefore + * dapls_cb_get() does not need to be thread safe when manipulating + * receive data structures. + * + * - there can be only 1 thread generating completions for a given EP's request + * opeartions, therefore dapls_cb_put() does not need to be thread safe when + * manipulating request data structures. + * + * - there can be only 1 thread generating completions for a given EP's receive + * opeartions therefore dapls_cb_put() does not need to be thread safe when + * manipulating receive data structures. + * + * - completions are delivered in order + * + * $Id$ + **********************************************************************/ + +#include "dapl_cookie.h" +#include "dapl_ring_buffer_util.h" + + +/********************************************************************* + * * + * Function Prototypes * + * * + *********************************************************************/ + +DAT_RETURN +dapls_cb_get ( + DAPL_COOKIE_BUFFER *buffer, + DAPL_COOKIE **cookie_ptr ); + +DAT_RETURN +dapls_cb_put ( + DAPL_COOKIE_BUFFER *buffer, + DAPL_COOKIE *cookie ); + + +/********************************************************************* + * * + * Function Definitions * + * * + *********************************************************************/ + + +/* + * dapls_cb_create + * + * Given a DAPL_COOKIE_BUFFER, allocate and initialize memory for + * the data structure. + * + * Input: + * buffer pointer to DAPL_COOKIE_BUFFER + * ep endpoint to associate with cookies + * size number of elements to allocate & manage + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * + */ +DAT_RETURN +dapls_cb_create ( + IN DAPL_COOKIE_BUFFER *buffer, + IN DAPL_EP *ep, + IN DAT_COUNT size ) +{ + DAT_COUNT i; + + /* + * allocate one additional entry so that the tail + * can always point at an empty location + */ + size++; + + buffer->pool = dapl_os_alloc (size * sizeof (DAPL_COOKIE)); + if ( NULL != buffer->pool ) + { + buffer->pool_size = size; + buffer->head = 0; + buffer->tail = 0; + dapl_os_lock_init (&buffer->lock); + + for ( i = 0; i < size; i++ ) + { +#ifdef DAPL_DBG + buffer->pool[i].type = DAPL_COOKIE_TYPE_NULL; +#endif + buffer->pool[i].index = i; + buffer->pool[i].ep = ep; + } + + return (DAT_SUCCESS); + } + else + { + return (DAT_INSUFFICIENT_RESOURCES); + } +} + + +/* + * dapls_cb_free + * + * Free the data structure + * + * Input: + * buffer pointer to DAPL_COOKIE_BUFFER + * + * Output: + * none + * + * Returns: + * none + * + */ +void +dapls_cb_free ( + IN DAPL_COOKIE_BUFFER *buffer ) +{ + dapl_os_lock ( &buffer->lock ); + if ( NULL != buffer->pool ) + { + dapl_os_free (buffer->pool, buffer->pool_size * sizeof (DAPL_COOKIE)); + } + dapl_os_unlock ( &buffer->lock ); +} + + +/* + * dapls_cb_get + * + * Remove an entry from the buffer + * + * Input: + * buffer pointer to DAPL_COOKIE_BUFFER + * + * Output: + * cookie_ptr pointer to pointer to cookie + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + * DAT_INSUFFICIENT_RESOURCES + * + */ +DAT_RETURN +dapls_cb_get ( + IN DAPL_COOKIE_BUFFER *buffer, + OUT DAPL_COOKIE **cookie_ptr ) +{ + DAT_RETURN dat_status; + DAT_COUNT new_head; + + dapl_os_assert(NULL != cookie_ptr); + dapl_os_lock ( &buffer->lock ); + + new_head = (buffer->head + 1) % buffer->pool_size; + + if ( new_head == buffer->tail ) + { + dat_status = DAT_INSUFFICIENT_RESOURCES; + goto bail; + } + else + { + buffer->head = new_head; + + *cookie_ptr = &buffer->pool[buffer->head]; + +#ifdef DAPL_DBG + if ( buffer->pool[buffer->head].type != DAPL_COOKIE_TYPE_NULL ) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, "--> DsCkGet: EP %p cookie %p at %d in use as 0x%x\n", + buffer->pool[buffer->head].ep, + &buffer->pool[buffer->head], buffer->head, + buffer->pool[buffer->head].type ); + } +#endif + dat_status = DAT_SUCCESS; + } +bail: + dapl_os_unlock ( &buffer->lock ); + return dat_status; +} + + +/* + * dapls_cb_put + * + * Add entry(s) to the buffer + * + * Input: + * buffer pointer to DAPL_COOKIE_BUFFER + * cookie pointer to cookie + * + * Output: + * entry entry removed from the ring buffer + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_EMPTY + * + */ +DAT_RETURN +dapls_cb_put ( + IN DAPL_COOKIE_BUFFER *buffer, + IN DAPL_COOKIE *cookie ) +{ + dapl_os_lock ( &buffer->lock ); + +#ifdef DAPL_DBG + cookie->type = DAPL_COOKIE_TYPE_NULL; +#endif + buffer->tail = cookie->index; + + dapl_os_unlock ( &buffer->lock ); + + return DAT_SUCCESS; +} + + +/* + * dapls_rmr_cookie_alloc + * + * Allocate an RMR Bind cookie + * + * Input: + * buffer pointer to DAPL_COOKIE_BUFFER + * rmr rmr to associate with the cookie + * user_cookie user's cookie data + * + * Output: + * cookie_ptr pointer to pointer to allocated cookie + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_EMPTY + * + */ +DAT_RETURN +dapls_rmr_cookie_alloc ( + IN DAPL_COOKIE_BUFFER *buffer, + IN DAPL_RMR *rmr, + IN DAT_RMR_COOKIE user_cookie, + OUT DAPL_COOKIE **cookie_ptr ) +{ + DAPL_COOKIE *cookie; + DAT_RETURN dat_status; + + if ( DAT_SUCCESS != dapls_cb_get (buffer, &cookie) ) + { + *cookie_ptr = NULL; + dat_status = DAT_ERROR (DAT_INSUFFICIENT_RESOURCES,DAT_RESOURCE_MEMORY); + goto bail; + } + + dat_status = DAT_SUCCESS; + cookie->type = DAPL_COOKIE_TYPE_RMR; + cookie->val.rmr.rmr = rmr; + cookie->val.rmr.cookie = user_cookie; + + *cookie_ptr = cookie; + + bail: + return dat_status; +} + + +/* + * dapls_dto_cookie_alloc + * + * Allocate a DTO cookie + * + * Input: + * buffer pointer to DAPL_COOKIE_BUFFER + * type DTO type + * user_cookie user's cookie data + * + * Output: + * cookie_ptr pointer to pointer to allocated cookie + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_EMPTY + * + */ +DAT_RETURN +dapls_dto_cookie_alloc ( + IN DAPL_COOKIE_BUFFER *buffer, + IN DAPL_DTO_TYPE type, + IN DAT_DTO_COOKIE user_cookie, + OUT DAPL_COOKIE **cookie_ptr ) +{ + DAPL_COOKIE *cookie; + + if ( DAT_SUCCESS != dapls_cb_get (buffer, &cookie) ) + { + *cookie_ptr = NULL; + return DAT_ERROR (DAT_INSUFFICIENT_RESOURCES,DAT_RESOURCE_MEMORY); + } + + cookie->type = DAPL_COOKIE_TYPE_DTO; + cookie->val.dto.type = type; + cookie->val.dto.cookie = user_cookie; + cookie->val.dto.size = 0; +/* + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, "--> DsCkAlloc: %p, ck(%p,%llx,%llx) u_ck(%p,%llx,%llx)\n", + cookie, + cookie->val.dto.cookie.as_ptr, + cookie->val.dto.cookie.as_64, + cookie->val.dto.cookie.as_index, + user_cookie.as_ptr, user_cookie.as_64, user_cookie.as_index ); +*/ + + *cookie_ptr = cookie; + return DAT_SUCCESS; +} + +void +dapls_cookie_dealloc ( + IN DAPL_COOKIE_BUFFER *buffer, + IN DAPL_COOKIE *cookie) +{ + dapls_cb_put (buffer, cookie); +} + + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_cookie.h b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_cookie.h new file mode 100644 index 00000000..8502b2c4 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_cookie.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dapl_cookie.h + * + * PURPOSE: Utility defs & routines for the cookie data structure + * + * $Id$ + * + **********************************************************************/ + +#ifndef _DAPL_COOKIE_H +#define _DAPL_COOKIE_H_ + +#include "dapl.h" + +extern DAT_RETURN +dapls_cb_create ( + DAPL_COOKIE_BUFFER *buffer, + DAPL_EP *ep, + DAT_COUNT size ); + +extern void +dapls_cb_free ( + DAPL_COOKIE_BUFFER *buffer ); + +extern DAT_RETURN +dapls_rmr_cookie_alloc ( + IN DAPL_COOKIE_BUFFER *buffer, + IN DAPL_RMR *rmr, + IN DAT_RMR_COOKIE user_cookie, + OUT DAPL_COOKIE **cookie_ptr ); + +extern DAT_RETURN +dapls_dto_cookie_alloc ( + IN DAPL_COOKIE_BUFFER *buffer, + IN DAPL_DTO_TYPE type, + IN DAT_DTO_COOKIE user_cookie, + OUT DAPL_COOKIE **cookie_ptr ); + +extern void +dapls_cookie_dealloc ( + IN DAPL_COOKIE_BUFFER *buffer, + IN DAPL_COOKIE *cookie ); + +#endif /* _DAPL_COOKIE_H_ */ diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_cr_accept.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_cr_accept.c new file mode 100644 index 00000000..cb9a0c18 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_cr_accept.c @@ -0,0 +1,322 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_cr_accept.c + * + * PURPOSE: Connection management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 4 + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_adapter_util.h" +#include "dapl_evd_util.h" +#include "dapl_sp_util.h" +#include "dapl_cr_util.h" +/* + * dapl_cr_accept + * + * DAPL Requirements Version xxx, 6.4.2.1 + * + * Establish a connection between active remote side requesting Endpoint + * and passic side local Endpoint. + * + * Input: + * cr_handle + * ep_handle + * private_data_size + * private_data + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + * DAT_INVALID_ATTRIBUTE + */ +DAT_RETURN +dapl_cr_accept ( + IN DAT_CR_HANDLE cr_handle, + IN DAT_EP_HANDLE ep_handle, + IN DAT_COUNT private_data_size, + IN const DAT_PVOID private_data ) +{ + DAPL_EP *ep_ptr; + DAT_RETURN dat_status; + DAPL_PRIVATE prd; + DAPL_CR *cr_ptr; + DAPL_SP *sp_ptr; + DAT_UINT32 ib_rep_pdata_size; + DAT_EP_STATE entry_ep_state; + DAT_EP_HANDLE entry_ep_handle; + + dapl_dbg_log (DAPL_DBG_TYPE_API, + "dapl_cr_accept (%p, %p, %d, %p)\n", + cr_handle, + ep_handle, + private_data_size, + private_data); + + if ( DAPL_BAD_HANDLE (cr_handle, DAPL_MAGIC_CR) ) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE,DAT_INVALID_HANDLE_CR); + goto bail; + } + + cr_ptr = (DAPL_CR *) cr_handle; + + /* + * Return an error if we have an ep_handle and the CR already has an + * EP, indicating this is an RSP connection or PSP_PROVIDER_FLAG was + * specified. + */ + if ( ep_handle != NULL && + ( DAPL_BAD_HANDLE (ep_handle, DAPL_MAGIC_EP) || + cr_ptr->param.local_ep_handle != NULL ) ) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE,DAT_INVALID_HANDLE_EP); + goto bail; + } + + /* Make sure we have an EP handle in one place or another */ + if ( ep_handle == NULL && cr_ptr->param.local_ep_handle == NULL ) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP); + goto bail; + } + + if ( (0 != private_data_size) && (NULL == private_data) ) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER,DAT_INVALID_ARG4); + goto bail; + } + + /* + * Verify the private data size doesn't exceed the max + */ + ib_rep_pdata_size = private_data_size + + (sizeof(DAPL_PRIVATE) - DAPL_MAX_PRIVATE_DATA_SIZE); + + if (ib_rep_pdata_size > IB_MAX_REP_PDATA_SIZE) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER,DAT_INVALID_ARG3); + goto bail; + } + + /* + * ep_handle is NULL if the user specified DAT_PSP_PROVIDER_FLAG + * OR this is an RSP connection; retrieve it from the cr. + */ + if ( ep_handle == NULL ) + { + ep_handle = cr_ptr->param.local_ep_handle; + if ( (((DAPL_EP *) ep_handle)->param.ep_state != + DAT_EP_STATE_TENTATIVE_CONNECTION_PENDING) && + (((DAPL_EP *)ep_handle)->param.ep_state != + DAT_EP_STATE_PASSIVE_CONNECTION_PENDING) ) + { + dat_status = DAT_ERROR (DAT_INVALID_STATE,DAT_INVALID_STATE_EP_NOTREADY); + goto bail; + } + } else + { + /* ensure this EP isn't connected or in use*/ + if ( ((DAPL_EP *) ep_handle)->param.ep_state != + DAT_EP_STATE_UNCONNECTED ) + { + dat_status = DAT_ERROR (DAT_INVALID_STATE,DAT_INVALID_STATE_EP_NOTREADY); + goto bail; + } + } + + ep_ptr = (DAPL_EP *) ep_handle; + + /* + * Verify the attributes of the EP handle before we connect it. Test + * all of the handles to make sure they are currently valid. + * Specifically: + * pz_handle required + * recv_evd_handle optional, but must be valid + * request_evd_handle optional, but must be valid + * connect_evd_handle required + * We do all verification and state change under lock, at which + * point the EP state should protect us from most races. + */ + dapl_os_lock ( &ep_ptr->header.lock ); + if ( ep_ptr->param.pz_handle == NULL + || DAPL_BAD_HANDLE (ep_ptr->param.pz_handle, DAPL_MAGIC_PZ) + /* test connect handle */ + || ep_ptr->param.connect_evd_handle == NULL + || DAPL_BAD_HANDLE (ep_ptr->param.connect_evd_handle, DAPL_MAGIC_EVD) + || ! (((DAPL_EVD *)ep_ptr->param.connect_evd_handle)->evd_flags & DAT_EVD_CONNECTION_FLAG) + /* test optional completion handles */ + || (ep_ptr->param.recv_evd_handle != DAT_HANDLE_NULL && + (DAPL_BAD_HANDLE (ep_ptr->param.recv_evd_handle, DAPL_MAGIC_EVD))) + || (ep_ptr->param.request_evd_handle != DAT_HANDLE_NULL && + (DAPL_BAD_HANDLE (ep_ptr->param.request_evd_handle, DAPL_MAGIC_EVD)))) + { + dapl_os_unlock ( &ep_ptr->header.lock ); + dat_status = DAT_ERROR (DAT_INVALID_HANDLE,DAT_INVALID_HANDLE_EP); + goto bail; + } + + if ( ep_ptr->qp_state == DAPL_QP_STATE_UNATTACHED ) + { + /* + * If we are lazy attaching the QP then we may need to + * hook it up here. Typically, we run this code only for + * DAT_PSP_PROVIDER_FLAG + */ + dat_status = dapls_ib_qp_alloc ( cr_ptr->header.owner_ia, ep_ptr, ep_ptr ); + + if ( dat_status != DAT_SUCCESS) + { + /* This is not a great error code, but all the spec allows */ + dapl_os_unlock ( &ep_ptr->header.lock ); + dat_status = DAT_ERROR (DAT_INVALID_HANDLE,DAT_INVALID_HANDLE_EP); + goto bail; + } + } + else + { + dapl_dbg_log (DAPL_DBG_TYPE_CM,"<<< CR ACCEPT:EP:%p qp_state:%#x\n", ep_ptr,ep_ptr->qp_state ); + if (ep_ptr->qp_state == IB_QPS_RESET || + ep_ptr->qp_state == IB_QPS_ERROR ) + { + if (ep_ptr->qp_handle != IB_INVALID_HANDLE ) + { + dat_status = dapls_ib_reinit_ep (ep_ptr); + if ( dat_status != DAT_SUCCESS) + { + dapl_os_unlock ( &ep_ptr->header.lock ); + dat_status = DAT_ERROR (DAT_INVALID_HANDLE,DAT_INVALID_HANDLE_EP); + goto bail; + } + } + } + } + entry_ep_state = ep_ptr->param.ep_state; + entry_ep_handle = cr_ptr->param.local_ep_handle; + ep_ptr->param.ep_state = DAT_EP_STATE_COMPLETION_PENDING; + ep_ptr->cm_handle = cr_ptr->ib_cm_handle; + ep_ptr->cr_ptr = cr_ptr; + ep_ptr->param.remote_ia_address_ptr = cr_ptr->param.remote_ia_address_ptr; + cr_ptr->param.local_ep_handle = ep_handle; + + /* + * Deal with private data: we need to put the size in the header + * before sending. Given that this is a reply, we don't need to + * put the IP address in the header. + */ + dapl_os_memcpy(prd.private_data, private_data, private_data_size); + dapl_os_memzero (prd.private_data + private_data_size, + DAPL_MAX_PRIVATE_DATA_SIZE - private_data_size); + + dapl_os_unlock ( &ep_ptr->header.lock ); + + dat_status = dapls_ib_accept_connection ( cr_handle, + ep_handle, + private_data_size, + &prd ); + + /* + * If the provider failed, unwind the damage so we are back at + * the initial state. + */ + if ( dat_status != DAT_SUCCESS) + { + if ( DAT_GET_TYPE(dat_status) == DAT_INVALID_STATE ) + { + /* The remote connection request has disappeared; timeout, + * system error, app termination, perhaps other reasons. + */ + + /* Take the CR off the list, we can't use it */ + sp_ptr = cr_ptr->sp_ptr; + + cr_ptr->header.magic = DAPL_MAGIC_CR_DESTROYED; + + dapl_sp_remove_cr (sp_ptr, cr_ptr); + + dapls_cr_free (cr_ptr); + + ep_ptr->cr_ptr = NULL; + ep_ptr->param.ep_state = entry_ep_state; + ep_ptr->param.remote_ia_address_ptr = NULL; + dapls_ib_qp_free (ep_ptr->header.owner_ia, ep_ptr); + dat_status = dapls_ib_reinit_ep (ep_ptr ); /* it will reallocate QP for EP */ + + /* notify User */ + dat_status = dapls_evd_post_connection_event ( + ep_ptr->param.request_evd_handle, + DAT_CONNECTION_EVENT_ACCEPT_COMPLETION_ERROR, + (DAT_HANDLE) ep_ptr, + 0, + 0 ); + } + else + { + ep_ptr->param.ep_state = entry_ep_state; + cr_ptr->param.local_ep_handle = entry_ep_handle; + ep_ptr->cr_ptr = NULL; + ep_ptr->param.remote_ia_address_ptr = NULL; + } + + /* + * After restoring values above, we now check if we need + * to translate the error + */ + if ( DAT_GET_TYPE(dat_status) == DAT_LENGTH_ERROR ) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER, DAT_INVALID_ARG3); + } + + } + else + { + /* Make this CR invalid. We need to hang on to it until + * the connection terminates, but it's destroyed from + * the app point of view. + */ + cr_ptr->header.magic = DAPL_MAGIC_CR_DESTROYED; + } + + bail: + return dat_status; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_cr_callback.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_cr_callback.c new file mode 100644 index 00000000..b67043b6 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_cr_callback.c @@ -0,0 +1,615 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapls_cr_callback.c + * + * PURPOSE: implements passive side connection callbacks + * + * Description: Accepts asynchronous callbacks from the Communications Manager + * for EVDs that have been specified as the connection_evd. + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_evd_util.h" +#include "dapl_cr_util.h" +#include "dapl_ia_util.h" +#include "dapl_sp_util.h" +#include "dapl_ep_util.h" +#include "dapl_adapter_util.h" +#include "dapl_ring_buffer_util.h" + + +/* + * Prototypes + */ +DAT_RETURN dapli_connection_request ( + IN ib_cm_handle_t ib_cm_handle, + IN DAPL_SP *sp_ptr, + IN DAPL_PRIVATE *prd_ptr, + IN DAPL_EVD *evd_ptr, + IN DAT_IA_ADDRESS_PTR p_remote_ia_addr); + +DAPL_EP * dapli_get_sp_ep ( + IN ib_cm_handle_t ib_cm_handle, + IN DAPL_SP *sp_ptr, + IN DAT_EVENT_NUMBER dat_event_num); + + +/* + * dapls_cr_callback + * + * The callback function registered with verbs for passive side of + * connection requests. The interface is specified by cm_api.h + * + * + * Input: + * ib_cm_handle, Handle to CM + * ib_cm_event Specific CM event + * instant_data Private data with DAT ADDRESS header + * context SP pointer + * + * Output: + * None + * + */ +void +dapls_cr_callback ( + IN ib_cm_handle_t ib_cm_handle, + IN const ib_cm_events_t ib_cm_event, + IN const void *private_data_ptr, /* event data */ + IN const void *context, + IN DAT_IA_ADDRESS_PTR p_remote_ia_addr) +{ + DAPL_EP *ep_ptr; + DAPL_EVD *evd_ptr; + DAPL_SP *sp_ptr; + DAPL_PRIVATE *prd_ptr; + DAT_EVENT_NUMBER dat_event_num; + DAT_RETURN dat_status; + + dapl_dbg_log (DAPL_DBG_TYPE_CM | DAPL_DBG_TYPE_CALLBACK, + "--> dapl_cr_callback! context: %p event: %x cm_handle %d\n", + context, + ib_cm_event, + ib_cm_handle.cid ); + + /* + * Passive side of the connection, context is a SP and + * we need to look up the EP. + */ + sp_ptr = (DAPL_SP *) context; + /* + * The context pointer could have been cleaned up in a racing + * CM callback, check to see if we should just exit here + */ + if (sp_ptr->header.magic == DAPL_MAGIC_INVALID) + { + return; + } + dapl_os_assert ( sp_ptr->header.magic == DAPL_MAGIC_PSP || + sp_ptr->header.magic == DAPL_MAGIC_RSP ); + + /* Obtain the event number from the provider layer */ + dat_event_num = dapls_ib_get_dat_event (ib_cm_event, DAT_FALSE); + + /* + * CONNECT_REQUEST events create an event on the PSP + * EVD, which will trigger connection processing. The + * sequence is: + * CONNECT_REQUEST Event to SP + * CONNECTED Event to EP + * DISCONNECT Event to EP + * + * Obtain the EP if required and set an event up on the correct + * EVD. + */ + if (dat_event_num == DAT_CONNECTION_REQUEST_EVENT) + { + ep_ptr = NULL; + evd_ptr = sp_ptr->evd_handle; + } + else + { + /* see if there is an EP connected with this CM handle */ + ep_ptr = dapli_get_sp_ep ( ib_cm_handle, + sp_ptr, + dat_event_num ); + + /* if we lost a race with the CM just exit. */ + if (ep_ptr == NULL) + { + return; + } + evd_ptr = (DAPL_EVD *) ep_ptr->param.connect_evd_handle; + /* if something has happened to our EVD, bail. */ + if (evd_ptr == NULL) + { + return; + } + } + + prd_ptr = (DAPL_PRIVATE *)private_data_ptr; + + dat_status = DAT_INTERNAL_ERROR; /* init to ERR */ + + switch (dat_event_num) + { + case DAT_CONNECTION_REQUEST_EVENT: + { + /* + * Requests arriving on a disabled SP are immediatly rejected + */ + + dapl_os_lock (&sp_ptr->header.lock); + if ( sp_ptr->listening == DAT_FALSE ) + { + dapl_os_unlock (&sp_ptr->header.lock); + dapl_dbg_log (DAPL_DBG_TYPE_CM, + "---> dapls_cr_callback: conn event on down SP\n"); + (void)dapls_ib_reject_connection (ib_cm_handle, + DAT_CONNECTION_EVENT_UNREACHABLE ); + + return; + } + + if ( sp_ptr->header.handle_type == DAT_HANDLE_TYPE_RSP ) + { + /* + * RSP connections only allow a single connection. Close + * it down NOW so we reject any further connections. + */ + sp_ptr->listening = DAT_FALSE; + } + dapl_os_unlock (&sp_ptr->header.lock); + + /* + * Only occurs on the passive side of a connection + * dapli_connection_request will post the connection + * event if appropriate. + */ + dat_status = dapli_connection_request ( ib_cm_handle, + sp_ptr, + prd_ptr, + evd_ptr, + p_remote_ia_addr ); + /* Set evd_ptr = NULL so we don't generate an event below */ + evd_ptr = NULL; + + break; + } + case DAT_CONNECTION_EVENT_ESTABLISHED: + { + /* This is just a notification the connection is now + * established, there isn't any private data to deal with. + * + * Update the EP state and cache a copy of the cm handle, + * then let the user know we are ready to go. + */ + dapl_dbg_log (DAPL_DBG_TYPE_CM, + "--> dapls_cr_callback: CONN_EVENT_ESTABLISHED EP: %p ep_state: %x\n",ep_ptr, + ep_ptr->param.ep_state); + dapl_os_lock ( &ep_ptr->header.lock ); + if (ep_ptr->header.magic != DAPL_MAGIC_EP || + ep_ptr->param.ep_state != DAT_EP_STATE_COMPLETION_PENDING) + { + /* If someone pulled the plug on the EP or connection, + * just exit + */ + dapl_os_unlock ( &ep_ptr->header.lock ); + dat_status = DAT_SUCCESS; + break; + } + + + ep_ptr->param.ep_state = DAT_EP_STATE_CONNECTED; + ep_ptr->cm_handle = ib_cm_handle; + dapl_os_unlock ( &ep_ptr->header.lock ); + + break; + } + case DAT_CONNECTION_EVENT_DISCONNECTED: + { + /* + * EP is now fully disconnected; initiate any post processing + * to reset the underlying QP and get the EP ready for + * another connection + */ + dapl_dbg_log (DAPL_DBG_TYPE_CM, + "--> dapls_cr_callback: EVENT_DISCONNECTED EP: %p ep_state: %x\n",ep_ptr, + ep_ptr->param.ep_state); + dapl_os_lock ( &ep_ptr->header.lock ); + if (ep_ptr->param.ep_state == DAT_EP_STATE_DISCONNECTED) + { + /* The disconnect has already occurred, we are now + * cleaned up and ready to exit + */ + dapl_os_unlock ( &ep_ptr->header.lock ); + return; + } + ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECTED; + dapls_ib_disconnect_clean (ep_ptr, DAT_FALSE, ib_cm_event); + dapl_sp_remove_ep (ep_ptr); + dapl_os_unlock ( &ep_ptr->header.lock ); + + break; + } + case DAT_CONNECTION_EVENT_NON_PEER_REJECTED: + case DAT_CONNECTION_EVENT_PEER_REJECTED: + case DAT_CONNECTION_EVENT_UNREACHABLE: + { + /* + * After posting an accept the requesting node has + * stopped talking. + */ + dapl_os_lock ( &ep_ptr->header.lock ); + ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECTED; + cl_memclr( &ep_ptr->cm_handle, sizeof(ib_cm_handle_t) ); + ep_ptr->cm_handle.cid = 0xFFFFFFFF; + dapls_ib_disconnect_clean (ep_ptr, DAT_FALSE, ib_cm_event); + dapl_os_unlock ( &ep_ptr->header.lock ); + + break; + } + case DAT_CONNECTION_EVENT_BROKEN: + { + dapl_os_lock ( &ep_ptr->header.lock ); + ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECTED; + dapls_ib_disconnect_clean (ep_ptr, DAT_FALSE, ib_cm_event); + dapl_os_unlock ( &ep_ptr->header.lock ); + + break; + } + default: + { + evd_ptr = NULL; + dapl_os_assert (0); /* shouldn't happen */ + break; + } + } + dapl_dbg_log (DAPL_DBG_TYPE_CM," dapl_cr_callback: POST EVENT %d EP: %p EVD: %p \n",dat_event_num, ep_ptr, evd_ptr); + if (evd_ptr != NULL ) + { + dat_status = dapls_evd_post_connection_event ( + evd_ptr, + dat_event_num, + (DAT_HANDLE) ep_ptr, + 0, + NULL); + } + + if (dat_status != DAT_SUCCESS) + { + /* The event post failed; take appropriate action. */ + (void)dapls_ib_reject_connection ( ib_cm_handle, + DAT_CONNECTION_EVENT_BROKEN); + + return; + } +} + + +/* + * dapli_connection_request + * + * Process a connection request on the Passive side of a connection. + * Create a CR record and link it on to the SP so we can update it + * and free it later. Create an EP if specified by the PSP flags. + * + * Input: + * ib_cm_handle, + * sp_ptr + * event_ptr + * prd_ptr + * + * Output: + * None + * + * Returns + * DAT_INSUFFICIENT_RESOURCES + * DAT_SUCCESS + * + */ +DAT_RETURN +dapli_connection_request ( + IN ib_cm_handle_t ib_cm_handle, + IN DAPL_SP *sp_ptr, + IN DAPL_PRIVATE *prd_ptr, + IN DAPL_EVD *evd_ptr, + IN DAT_IA_ADDRESS_PTR p_remote_ia_addr) +{ + DAT_RETURN dat_status; + + DAPL_CR *cr_ptr; + DAPL_EP *ep_ptr; + DAPL_IA *ia_ptr; + DAT_SP_HANDLE sp_handle; + + cr_ptr = dapls_cr_alloc (sp_ptr->header.owner_ia); + if ( cr_ptr == NULL ) + { + /* Invoking function will call dapls_ib_cm_reject() */ + return DAT_INSUFFICIENT_RESOURCES; + } + + /* + * Set up the CR + */ + cr_ptr->sp_ptr = sp_ptr; /* maintain sp_ptr in case of reject */ + cr_ptr->param.remote_port_qual = 0; + cr_ptr->ib_cm_handle = ib_cm_handle; + + /* + * Copy the remote address and private data out of the private_data + * payload and put them in a local structure + */ + if (p_remote_ia_addr != NULL) + { + dapl_os_memcpy ((void *)&cr_ptr->remote_ia_address, + (void *)p_remote_ia_addr, + sizeof (DAT_SOCK_ADDR6)); + } + cr_ptr->param.remote_ia_address_ptr = (DAT_IA_ADDRESS_PTR)&cr_ptr->remote_ia_address; + + /* + * Private data size is always the max allowable by IB + */ + cr_ptr->param.private_data_size = IB_MAX_REQ_PDATA_SIZE; + cr_ptr->param.private_data = cr_ptr->private_data; + dapl_os_memcpy (cr_ptr->private_data, +#ifdef NO_NAME_SERVICE + prd_ptr->private_data, +#else + (void *) prd_ptr, +#endif + IB_MAX_REQ_PDATA_SIZE); + +#ifdef DAPL_DBG +#if 0 + { + int i; + + dapl_dbg_log ( DAPL_DBG_TYPE_EP, "--> private_data: "); + + for ( i = 0 ; i < IB_MAX_REQ_PDATA_SIZE ; i++ ) + { + dapl_dbg_log ( DAPL_DBG_TYPE_EP, + "0x%x ", cr_ptr->private_data[i]); + + } + dapl_dbg_log ( DAPL_DBG_TYPE_EP, "\n"); + + } +#endif +#endif + + /* EP will be NULL unless RSP service point */ + ep_ptr = (DAPL_EP *) sp_ptr->ep_handle; + + if ( sp_ptr->psp_flags == DAT_PSP_PROVIDER_FLAG ) + { + /* + * Never true for RSP connections + * + * Create an EP for the user. If we can't allocate an + * EP we are out of resources and need to tell the + * requestor that we cant help them. + */ + ia_ptr = sp_ptr->header.owner_ia; + ep_ptr = dapl_ep_alloc (ia_ptr, NULL); + if ( ep_ptr == NULL ) + { + dapls_cr_free (cr_ptr); + /* Invoking function will call dapls_ib_cm_reject() */ + return DAT_INSUFFICIENT_RESOURCES; + } + /* + * Link the EP onto the IA + */ + dapl_ia_link_ep (ia_ptr, ep_ptr); + } + + cr_ptr->param.local_ep_handle = ep_ptr; + + if ( ep_ptr != NULL ) + { + /* Assign valid EP fields: RSP and PSP_PROVIDER_FLAG only */ + if ( sp_ptr->psp_flags == DAT_PSP_PROVIDER_FLAG ) + { + ep_ptr->param.ep_state = + DAT_EP_STATE_TENTATIVE_CONNECTION_PENDING; + } + else + /* RSP */ + { + dapl_os_assert (sp_ptr->header.handle_type == DAT_HANDLE_TYPE_RSP); + ep_ptr->param.ep_state = + DAT_EP_STATE_PASSIVE_CONNECTION_PENDING; + } + ep_ptr->cm_handle = ib_cm_handle; + ep_ptr->cr_ptr = cr_ptr; + } + + /* link the CR onto the SP so we can pick it up later */ + dapl_sp_link_cr (sp_ptr, cr_ptr); + + /* Post the event. */ + /* assign sp_ptr to union to avoid typecast errors from some compilers */ + sp_handle.psp_handle = (DAT_PSP_HANDLE)sp_ptr; + dat_status = dapls_evd_post_cr_arrival_event ( + evd_ptr, + DAT_CONNECTION_REQUEST_EVENT, + sp_handle, + (DAT_IA_ADDRESS_PTR)&sp_ptr->header.owner_ia->hca_ptr->hca_address, + sp_ptr->conn_qual, + (DAT_CR_HANDLE)cr_ptr); + if (dat_status != DAT_SUCCESS) + { + if ( ep_ptr != NULL ) + { + ep_ptr->cr_ptr = NULL; + } + dapls_cr_free (cr_ptr); + (void)dapls_ib_reject_connection (ib_cm_handle, + DAT_CONNECTION_EVENT_BROKEN); + + /* Take the CR off the list, we can't use it */ + dapl_os_lock (&sp_ptr->header.lock); + dapl_sp_remove_cr (sp_ptr, cr_ptr); + dapl_os_unlock (&sp_ptr->header.lock); + return DAT_INSUFFICIENT_RESOURCES; + } + + + return DAT_SUCCESS; +} + + +/* + * dapli_get_sp_ep + * + * Passive side of a connection is now fully established. Clean + * up resources and obtain the EP pointer associated with a CR in + * the SP + * + * Input: + * ib_cm_handle, + * sp_ptr + * connection_event + * + * Output: + * none + * + * Returns + * ep_ptr + * + */ +DAPL_EP * +dapli_get_sp_ep ( + IN ib_cm_handle_t ib_cm_handle, + IN DAPL_SP *sp_ptr, + IN DAT_EVENT_NUMBER dat_event_num) +{ + DAPL_CR *cr_ptr; + DAPL_EP *ep_ptr; + + /* + * acquire the lock, we may be racing with other threads here + */ + dapl_os_lock (&sp_ptr->header.lock); + /* Verify under lock that the SP is still valid */ + if (sp_ptr->header.magic == DAPL_MAGIC_INVALID) + { + dapl_os_unlock (&sp_ptr->header.lock); + return NULL; + } + /* + * There are potentially multiple connections in progress. Need to + * go through the list and find the one we are interested + * in. There is no guarantee of order. dapl_sp_search_cr + * leaves the CR on the SP queue. + */ + cr_ptr = dapl_sp_search_cr (sp_ptr, ib_cm_handle); + if ( cr_ptr == NULL ) + { + dapl_os_unlock (&sp_ptr->header.lock); + return NULL; + } + + ep_ptr = (DAPL_EP *)cr_ptr->param.local_ep_handle; + + + /* Quick check to ensure our EP is still valid */ + if ( (DAPL_BAD_HANDLE (ep_ptr, DAPL_MAGIC_EP )) ) + { + ep_ptr = NULL; + } + + /* The CR record is discarded in all except for the CONNECTED case, + * as it will have no further relevance. + */ + if (dat_event_num != DAT_CONNECTION_EVENT_ESTABLISHED) + { + /* Remove the CR from the queue */ + dapl_sp_remove_cr (sp_ptr, cr_ptr); + /* + * Last event, time to clean up and dispose of the resource + */ + if (ep_ptr != NULL) + { + ep_ptr->cr_ptr = NULL; + } + + /* + * If this SP has been removed from service, free it + * up after the last CR is removed + */ + if ( sp_ptr->listening != DAT_TRUE && sp_ptr->cr_list_count == 0 && + sp_ptr->state != DAPL_SP_STATE_FREE ) + { + dapl_dbg_log (DAPL_DBG_TYPE_CM, + "--> dapli_get_sp_ep! disconnect dump sp: %p \n", sp_ptr); + /* Decrement the ref count on the EVD */ + if (sp_ptr->evd_handle) + { + dapl_os_atomic_dec (& ((DAPL_EVD *)sp_ptr->evd_handle)->evd_ref_count); + sp_ptr->evd_handle = NULL; + } + sp_ptr->state = DAPL_SP_STATE_FREE; + dapl_os_unlock (&sp_ptr->header.lock); + (void)dapls_ib_remove_conn_listener ( sp_ptr->header.owner_ia, + sp_ptr ); + dapls_ia_unlink_sp ( (DAPL_IA *)sp_ptr->header.owner_ia, + sp_ptr ); + dapls_sp_free_sp ( sp_ptr ); + goto skip_unlock; + } + + dapl_os_unlock (&sp_ptr->header.lock); + /* free memory outside of the lock */ + dapls_cr_free (cr_ptr); + } + else + { + dapl_os_unlock (&sp_ptr->header.lock); + } + +skip_unlock: + return ep_ptr; +} + + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * c-brace-offset: -4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_cr_handoff.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_cr_handoff.c new file mode 100644 index 00000000..9495d785 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_cr_handoff.c @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_cr_handoff.c + * + * PURPOSE: Connection management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 4 + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_adapter_util.h" + +/* + * dapl_cr_handoff + * + * DAPL Requirements Version xxx, 6.4.2.4 + * + * Hand the connection request to another Sevice pont specified by the + * Connectin Qualifier. + * + * Input: + * cr_handle + * cr_handoff + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + * DAT_INVALID_PARAMETER + */ +DAT_RETURN +dapl_cr_handoff ( + IN DAT_CR_HANDLE cr_handle, + IN DAT_CONN_QUAL cr_handoff ) /* handoff */ +{ + DAT_RETURN dat_status; + + if ( DAPL_BAD_HANDLE (cr_handle, DAPL_MAGIC_CR) ) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_CR); + goto bail; + } + + dat_status = dapls_ib_cr_handoff ( cr_handle, cr_handoff ); + +bail: + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_cr_query.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_cr_query.c new file mode 100644 index 00000000..4bb7de02 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_cr_query.c @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_cr_query.c + * + * PURPOSE: Connection management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 4 + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_adapter_util.h" + +/* + * dapl_cr_query + * + * DAPL Requirements Version xxx, 6.4.2.1 + * + * Return Connection Request args + * + * Input: + * cr_handle + * cr_param_mask + * + * Output: + * cr_param + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + * DAT_INVALID_HANDLE + */ +DAT_RETURN +dapl_cr_query ( + IN DAT_CR_HANDLE cr_handle, + IN DAT_CR_PARAM_MASK cr_param_mask, + OUT DAT_CR_PARAM *cr_param) +{ + DAPL_CR *cr_ptr; + DAT_RETURN dat_status; + + dapl_dbg_log (DAPL_DBG_TYPE_API, + "dapl_cr_query (%p, %x, %p)\n", + cr_handle, + cr_param_mask, + cr_param); + + dat_status = DAT_SUCCESS; + if ( DAPL_BAD_HANDLE (cr_handle, DAPL_MAGIC_CR) ) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE,DAT_INVALID_HANDLE_CR); + goto bail; + } + + if (NULL == cr_param) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER,DAT_INVALID_ARG3); + goto bail; + } + + cr_ptr = (DAPL_CR *) cr_handle; + + /* obtain the remote IP address */ + if (cr_param_mask & DAT_CR_FIELD_REMOTE_IA_ADDRESS_PTR) + { + dat_status = dapls_ib_cm_remote_addr ((DAT_HANDLE)cr_handle, + NULL, + &cr_ptr->remote_ia_address ); + } + + /* since the arguments are easily accessible, ignore the mask */ + dapl_os_memcpy (cr_param, &cr_ptr->param, sizeof (DAT_CR_PARAM)); + + bail: + return dat_status; +} + diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_cr_reject.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_cr_reject.c new file mode 100644 index 00000000..fbe6356a --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_cr_reject.c @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_cr_reject.c + * + * PURPOSE: Connection management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 4 + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_cr_util.h" +#include "dapl_sp_util.h" +#include "dapl_adapter_util.h" + +/* + * dapl_cr_reject + * + * DAPL Requirements Version xxx, 6.4.2.2 + * + * Reject a connection request from the active remote side requesting + * an Endpoint. + * + * Input: + * cr_handle + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + */ +DAT_RETURN +dapl_cr_reject ( + IN DAT_CR_HANDLE cr_handle ) +{ + DAPL_CR *cr_ptr; + DAPL_EP *ep_ptr; + DAT_EP_STATE entry_ep_state; + DAT_EP_HANDLE entry_ep_handle; + DAPL_SP *sp_ptr; + DAT_RETURN dat_status; + + dapl_dbg_log (DAPL_DBG_TYPE_API, "dapl_cr_reject (%p)\n", cr_handle); + + if ( DAPL_BAD_HANDLE (cr_handle, DAPL_MAGIC_CR) ) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE,DAT_INVALID_HANDLE_CR); + goto bail; + } + + cr_ptr = (DAPL_CR *)cr_handle; + + /* + * Clean up provider created EP if there is one: only if + * DAT_PSP_PROVIDER_FLAG was set on the PSP + */ + ep_ptr = (DAPL_EP *)cr_ptr->param.local_ep_handle; + entry_ep_handle = cr_ptr->param.local_ep_handle; + entry_ep_state = 0; + if ( ep_ptr != NULL ) + { + entry_ep_state = ep_ptr->param.ep_state; + ep_ptr->param.ep_state = DAT_EP_STATE_UNCONNECTED; + cr_ptr->param.local_ep_handle = NULL; + } + + dat_status = dapls_ib_reject_connection ( cr_ptr->ib_cm_handle, + IB_CM_REJ_REASON_CONSUMER_REJ ); + + if ( dat_status != DAT_SUCCESS) + { + if ( ep_ptr != NULL ) + { + /* Revert our state to the beginning */ + ep_ptr->param.ep_state = entry_ep_state; + cr_ptr->param.local_ep_handle = entry_ep_handle; + cr_ptr->param.local_ep_handle = (DAT_EP_HANDLE)ep_ptr; + } + } + else + { + /* + * If this EP has been allocated by the provider, clean it up; + * see DAT 1.1 spec, page 100, lines 3-4 (section 6.4.3.1.1.1). + * RSP and user-provided EPs are in the control of the user. + */ + sp_ptr = cr_ptr->sp_ptr; + if ( ep_ptr != NULL && + sp_ptr->psp_flags == DAT_PSP_PROVIDER_FLAG ) + { + (void)dapl_ep_free (ep_ptr); + } + + /* Remove the CR from the queue, then free it */ + dapl_os_lock (&sp_ptr->header.lock); + dapl_sp_remove_cr ( sp_ptr, cr_ptr ); + dapl_os_unlock (&sp_ptr->header.lock); + + dapls_cr_free ( cr_ptr ); + } + + bail: + return dat_status; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_cr_util.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_cr_util.c new file mode 100644 index 00000000..e0c5b6f9 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_cr_util.c @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_cr_util.c + * + * PURPOSE: Manage CR (Connection Request) structure + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_cr_util.h" + +/* + * dapls_cr_create + * + * Create a CR. Part of the passive side of a connection + * + * Input: + * ia_ptr + * cno_ptr + * qlen + * evd_flags + * + * Output: + * evd_ptr_ptr + * + * Returns: + * none + * + */ + +DAPL_CR * +dapls_cr_alloc ( + DAPL_IA *ia_ptr ) +{ + DAPL_CR *cr_ptr; + + /* Allocate EP */ + cr_ptr = (DAPL_CR *)dapl_os_alloc (sizeof (DAPL_CR)); + if ( cr_ptr == NULL ) + { + return (NULL); + } + + /* zero the structure */ + dapl_os_memzero (cr_ptr, sizeof (DAPL_CR)); + + /* + * initialize the header + */ + cr_ptr->header.provider = ia_ptr->header.provider; + cr_ptr->header.magic = DAPL_MAGIC_CR; + cr_ptr->header.handle_type = DAT_HANDLE_TYPE_CR; + cr_ptr->header.owner_ia = ia_ptr; + cr_ptr->header.user_context.as_64 = 0; + cr_ptr->header.user_context.as_ptr = NULL; + dapl_llist_init_entry (&cr_ptr->header.ia_list_entry); + dapl_os_lock_init (&cr_ptr->header.lock); + + return (cr_ptr); +} + + +/* + * dapls_cr_free + * + * Free the passed in EP structure. + * + * Input: + * entry point pointer + * + * Output: + * none + * + * Returns: + * none + * + */ +void +dapls_cr_free ( + IN DAPL_CR *cr_ptr ) +{ + dapl_os_assert (cr_ptr->header.magic == DAPL_MAGIC_CR || + cr_ptr->header.magic == DAPL_MAGIC_CR_DESTROYED ); + + cr_ptr->header.magic = DAPL_MAGIC_INVALID; /* reset magic to prevent reuse */ + dapl_os_free (cr_ptr, sizeof (DAPL_CR)); +} + diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_cr_util.h b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_cr_util.h new file mode 100644 index 00000000..392f3ef4 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_cr_util.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dapl_cr_util.h + * + * PURPOSE: Utility defs & routines for the CR data structure + * + * $Id$ + * + **********************************************************************/ + +#ifndef _DAPL_CR_UTIL_H_ +#define _DAPL_CR_UTIL_H_ + +#include "dapl.h" + +DAPL_CR * +dapls_cr_alloc ( + DAPL_IA *ia_ptr ); + +void +dapls_cr_free ( + IN DAPL_CR *cr_ptr ); + +void +dapls_cr_callback ( + IN ib_cm_handle_t ib_cm_handle, + IN const ib_cm_events_t ib_cm_event, + IN const void *instant_data_p, + IN const void *context, + IN DAT_IA_ADDRESS_PTR p_remote_ia_addr); + +#endif /* _DAPL_CR_UTIL_H_ */ diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_debug.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_debug.c new file mode 100644 index 00000000..4dd36838 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_debug.c @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_debug.h" +#include "dapl.h" +#include +#include + +DAPL_DBG_TYPE g_dapl_dbg_type; /* initialized in dapl_init.c */ +DAPL_DBG_DEST g_dapl_dbg_dest; /* initialized in dapl_init.c */ + +#ifdef DAPL_DBG + +void dapl_internal_dbg_log ( DAPL_DBG_TYPE type, const char *fmt, ...) +{ + va_list args; + + if ( type & g_dapl_dbg_type ) + { + va_start (args, fmt); + + if ( DAPL_DBG_DEST_STDOUT & g_dapl_dbg_dest ) + { + dapl_os_vprintf (fmt, args); + } + + if ( DAPL_DBG_DEST_SYSLOG & g_dapl_dbg_dest ) + { + dapl_os_syslog(fmt, args); + } + va_end (args); + } +} + +#endif /* DAPL_DBG */ + +void dapl_internal_log ( DAPL_DBG_TYPE type, const char *fmt, ...) +{ + va_list args; + + if ( type & g_dapl_dbg_type ) + { + va_start (args, fmt); + dapl_os_vprintf (fmt, args); + va_end (args); + } +} + + +#if defined(DAPL_COUNTERS) +long dapl_dbg_counters[DAPL_CNTR_MAX]; + +/* + * The order of this list must match exactly with the #defines + * in dapl_debug.h + */ +char *dapl_dbg_counter_names[] = { + "dapl_ep_create", + "dapl_ep_free", + "dapl_ep_connect", + "dapl_ep_disconnect", + "dapl_ep_post_send", + "dapl_ep_post_recv", + "dapl_ep_post_rdma_write", + "dapl_ep_post_rdma_read", + "dapl_evd_create", + "dapl_evd_free", + "dapl_evd_wait", + "dapl_evd_blocked", + "dapl_evd_completion_notify", + "dapl_evd_dto_callback", + "dapl_evd_connection_callback", + "dapl_evd_dequeue", + "dapl_evd_poll", + "dapl_evd_found", + "dapl_evd_not_found", + "dapls_timer_set", + "dapls_timer_cancel", + 0 +}; +#endif /* DAPL_COUNTERS */ + diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_connect.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_connect.c new file mode 100644 index 00000000..a2c6c096 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_connect.c @@ -0,0 +1,373 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ep_connect.c + * + * PURPOSE: Endpoint management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 5 + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_ep_util.h" +#include "dapl_adapter_util.h" +#include "dapl_evd_util.h" +#include "dapl_timer_util.h" + +/* + * dapl_ep_connect + * + * DAPL Requirements Version xxx, 6.5.7 + * + * Request a connection be established between the local Endpoint + * and a remote Endpoint. This operation is used by the active/client + * side of a connection + * + * Input: + * ep_handle + * remote_ia_address + * remote_conn_qual + * timeout + * private_data_size + * privaet_data + * qos + * connect_flags + * + * Output: + * None + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOUCRES + * DAT_INVALID_PARAMETER + * DAT_MODLE_NOT_SUPPORTED + */ +DAT_RETURN +dapl_ep_connect ( + IN DAT_EP_HANDLE ep_handle, + IN DAT_IA_ADDRESS_PTR remote_ia_address, + IN DAT_CONN_QUAL remote_conn_qual, + IN DAT_TIMEOUT timeout, + IN DAT_COUNT private_data_size, + IN const DAT_PVOID private_data, + IN DAT_QOS qos, + IN DAT_CONNECT_FLAGS connect_flags ) +{ + DAPL_EP *ep_ptr; + DAPL_PRIVATE prd; + DAPL_EP alloc_ep; + DAT_RETURN dat_status; + DAT_COUNT ib_req_pdata_size; + DAT_COUNT max_req_pdata_size; + + dapl_dbg_log (DAPL_DBG_TYPE_API | DAPL_DBG_TYPE_CM, + "dapl_ep_connect (%p, {%u.%u.%u.%u}, %#I64x, %d, %d, %p, %x, %x)\n", + ep_handle, + remote_ia_address->sa_data[2], + remote_ia_address->sa_data[3], + remote_ia_address->sa_data[4], + remote_ia_address->sa_data[5], + remote_conn_qual, + timeout, + private_data_size, + private_data, + qos, + connect_flags); + DAPL_CNTR (DCNT_EP_CONNECT); + + dat_status = DAT_SUCCESS; + ep_ptr = (DAPL_EP *) ep_handle; + + /* + * Verify parameter & state. The connection handle must be good + * at this point. + */ + if ( DAPL_BAD_HANDLE (ep_ptr, DAPL_MAGIC_EP ) ) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP); + goto bail; + } + + if ( DAPL_BAD_HANDLE (ep_ptr->param.connect_evd_handle, DAPL_MAGIC_EVD) ) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EVD_CONN); + goto bail; + } + + /* Can't do a connection in 0 time, reject outright */ + if ( timeout == 0 ) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER, DAT_INVALID_ARG4); + goto bail; + } + + /* + * If the endpoint needs a QP, associated the QP with it. + * This needs to be done carefully, in order to: + * * Avoid allocating under a lock. + * * Not step on data structures being altered by + * routines with which we are racing. + * So we: + * * Confirm that a new QP is needed and is not forbidden by the + * current state. + * * Allocate it into a separate EP. + * * Take the EP lock. + * * Reconfirm that the EP is in a state where it needs a QP. + * * Assign the QP and release the lock. + */ + if ( ep_ptr->qp_state == DAPL_QP_STATE_UNATTACHED ) + { + if ( ep_ptr->param.pz_handle == NULL + || DAPL_BAD_HANDLE (ep_ptr->param.pz_handle, DAPL_MAGIC_PZ) ) + { + dat_status = DAT_ERROR (DAT_INVALID_STATE, DAT_INVALID_STATE_EP_NOTREADY); + goto bail; + } + alloc_ep = *ep_ptr; + + dat_status = dapls_ib_qp_alloc ( ep_ptr->header.owner_ia, + &alloc_ep, + ep_ptr ); + if ( dat_status != DAT_SUCCESS ) + { + dat_status = DAT_ERROR (DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); + goto bail; + } + + dapl_os_lock ( &ep_ptr->header.lock ); + /* + * PZ shouldn't have changed since we're only racing with + * dapl_cr_accept() + */ + if ( ep_ptr->qp_state != DAPL_QP_STATE_UNATTACHED ) + { + /* Bail, cleaning up. */ + dapl_os_unlock ( &ep_ptr->header.lock ); + dat_status = dapls_ib_qp_free ( ep_ptr->header.owner_ia, + &alloc_ep ); + if (dat_status != DAT_SUCCESS) + { + dapl_dbg_log (DAPL_DBG_TYPE_WARN, + "ep_connect: ib_qp_free failed with %x\n", + dat_status); + } + dat_status = DAT_ERROR (DAT_INVALID_STATE, dapls_ep_state_subtype (ep_ptr)); + goto bail; + } + + ep_ptr->qp_handle = alloc_ep.qp_handle; + ep_ptr->qpn = alloc_ep.qpn; + ep_ptr->qp_state = alloc_ep.qp_state; + + dapl_os_unlock ( &ep_ptr->header.lock ); + } + + /* + * We do state checks and transitions under lock. + * The only code we're racing against is dapl_cr_accept. + */ + dapl_os_lock ( &ep_ptr->header.lock ); + + /* + * Verify the attributes of the EP handle before we connect it. Test + * all of the handles to make sure they are currently valid. + * Specifically: + * pz_handle required + * recv_evd_handle optional, but must be valid + * request_evd_handle optional, but must be valid + * connect_evd_handle required + */ + if ( ep_ptr->param.pz_handle == NULL + || DAPL_BAD_HANDLE (ep_ptr->param.pz_handle, DAPL_MAGIC_PZ) + /* test connect handle */ + || ep_ptr->param.connect_evd_handle == NULL + || DAPL_BAD_HANDLE (ep_ptr->param.connect_evd_handle, DAPL_MAGIC_EVD) + || ! (((DAPL_EVD *)ep_ptr->param.connect_evd_handle)->evd_flags & DAT_EVD_CONNECTION_FLAG) + /* test optional completion handles */ + || (ep_ptr->param.recv_evd_handle != DAT_HANDLE_NULL && + (DAPL_BAD_HANDLE (ep_ptr->param.recv_evd_handle, DAPL_MAGIC_EVD))) + || (ep_ptr->param.request_evd_handle != DAT_HANDLE_NULL && + (DAPL_BAD_HANDLE (ep_ptr->param.request_evd_handle, DAPL_MAGIC_EVD)))) + { + dapl_os_unlock ( &ep_ptr->header.lock ); + dat_status = DAT_ERROR (DAT_INVALID_STATE, DAT_INVALID_STATE_EP_NOTREADY); + goto bail; + } + + /* Check both the EP state and the QP state: if we don't have a QP + * we need to attach one now. + */ + if ( ep_ptr->qp_state == DAPL_QP_STATE_UNATTACHED ) + { + dat_status = dapls_ib_qp_alloc ( ep_ptr->header.owner_ia, + ep_ptr, ep_ptr ); + + if ( dat_status != DAT_SUCCESS) + { + dapl_os_unlock ( &ep_ptr->header.lock ); + dat_status = DAT_ERROR (DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_TEP); + goto bail; + } + } + + if ( ep_ptr->param.ep_state != DAT_EP_STATE_UNCONNECTED ) + { + dapl_os_unlock ( &ep_ptr->header.lock ); + dat_status = DAT_ERROR (DAT_INVALID_STATE, dapls_ep_state_subtype (ep_ptr)); + goto bail; + } + + if ( qos != DAT_QOS_BEST_EFFORT || + connect_flags != DAT_CONNECT_DEFAULT_FLAG ) + { + /* + * At this point we only support one QOS level + */ + dapl_os_unlock ( &ep_ptr->header.lock ); + dat_status = DAT_ERROR (DAT_MODEL_NOT_SUPPORTED, 0); + goto bail; + } + + /* + * Verify the private data size doesn't exceed the max + */ + ib_req_pdata_size = private_data_size + + (sizeof (DAPL_PRIVATE) - DAPL_MAX_PRIVATE_DATA_SIZE); + + max_req_pdata_size = dapls_ib_private_data_size (NULL, DAPL_PDATA_CONN_REQ); + + if (ib_req_pdata_size > max_req_pdata_size) + { + dapl_os_unlock ( &ep_ptr->header.lock ); + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER, DAT_INVALID_ARG5); + goto bail; + } + + /* transition the state before requesting a connection to avoid + * race conditions + */ + ep_ptr->param.ep_state = DAT_EP_STATE_ACTIVE_CONNECTION_PENDING; + + /* + * At this point we're committed, and done with the endpoint + * except for the connect, so we can drop the lock. + */ + dapl_os_unlock ( &ep_ptr->header.lock ); + + /* + * Copy interesting data into the private data header + */ +#ifdef NO_NAME_SERVICE + dapl_os_memcpy (&prd.hca_address, + &ep_ptr->header.owner_ia->hca_ptr->hca_address, + sizeof (DAT_SOCK_ADDR)); +#endif + + /* + * The spec calls for us to use the entire private data size; + * put the message in and pad with NULLs + */ + dapl_os_memcpy (prd.private_data, private_data, private_data_size); + dapl_os_memzero (prd.private_data + private_data_size, + DAPL_MAX_PRIVATE_DATA_SIZE - private_data_size); + + /* Copy the connection qualifiers */ + dapl_os_memcpy ( ep_ptr->param.remote_ia_address_ptr, + remote_ia_address, + sizeof ( DAT_SOCK_ADDR) ); + ep_ptr->param.remote_port_qual = remote_conn_qual; + + dat_status = dapls_ib_connect ( ep_handle, + remote_ia_address, + remote_conn_qual, + private_data_size, + &prd ); + + if ( dat_status != DAT_SUCCESS ) + { + ep_ptr->param.ep_state = DAT_EP_STATE_UNCONNECTED; + + /* + * Some implementations provide us with an error code that the + * remote destination is unreachable, but DAT doesn't have a + * synchronous error code to communicate this. So the provider + * layer generates an INTERNAL_ERROR with a subtype; when + * this happens, return SUCCESS and generate the event + */ + if (dat_status == DAT_ERROR (DAT_INTERNAL_ERROR, 1) ) + { + dapls_evd_post_connection_event ( + (DAPL_EVD *)ep_ptr->param.connect_evd_handle, + DAT_CONNECTION_EVENT_UNREACHABLE, + (DAT_HANDLE) ep_ptr, + 0, + 0); + dat_status = DAT_SUCCESS; + } + } + else + { + /* + * Acquire the lock and recheck the state of the EP; this + * thread could have been descheduled after issuing the connect + * request and the EP is now connected. Set up a timer if + * necessary. + */ + dapl_os_lock ( &ep_ptr->header.lock ); + if (ep_ptr->param.ep_state == DAT_EP_STATE_ACTIVE_CONNECTION_PENDING && + timeout != DAT_TIMEOUT_INFINITE ) + { + ep_ptr->cxn_timer = + (DAPL_OS_TIMER *)dapl_os_alloc (sizeof (DAPL_OS_TIMER)); + + dapls_timer_set ( ep_ptr->cxn_timer, + dapls_ep_timeout, + ep_ptr, + timeout ); + } + dapl_os_unlock ( &ep_ptr->header.lock ); + } + +bail: + dapl_dbg_log (DAPL_DBG_TYPE_RTN | DAPL_DBG_TYPE_CM, + "dapl_ep_connect () returns 0x%x\n", + dat_status); + + return dat_status; +} + + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_create.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_create.c new file mode 100644 index 00000000..f68e4a0e --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_create.c @@ -0,0 +1,344 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ep_create.c + * + * PURPOSE: Endpoint management + * Description: Interfaces in this file are completely described in + * the kDAPL 1.1 API, Chapter 6, section 5 + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_ia_util.h" +#include "dapl_ep_util.h" +#include "dapl_adapter_util.h" + + +/* + * dapl_ep_create + * + * uDAPL Version 1.1, 6.5.3 + * + * Create an instance of an Endpoint that is provided to the + * consumer at ep_handle. + * + * Input: + * ia_handle + * pz_handle + * recv_evd_handle (recv DTOs) + * request_evd_handle (xmit DTOs) + * connect_evd_handle + * ep_attrs + * + * Output: + * ep_handle + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + * DAT_INVALID_ATTRIBUTE + * DAT_MODEL_NOT_SUPPORTED + */ +DAT_RETURN +dapl_ep_create ( + IN DAT_IA_HANDLE ia_handle, + IN DAT_PZ_HANDLE pz_handle, + IN DAT_EVD_HANDLE recv_evd_handle, + IN DAT_EVD_HANDLE request_evd_handle, + IN DAT_EVD_HANDLE connect_evd_handle, + IN const DAT_EP_ATTR *ep_attr, + OUT DAT_EP_HANDLE *ep_handle ) +{ + DAPL_IA *ia_ptr; + DAPL_EP *ep_ptr; + DAT_EP_ATTR ep_attr_limit; + DAPL_EVD *evd_ptr; + DAT_RETURN dat_status; + + dapl_dbg_log (DAPL_DBG_TYPE_API, + "dapl_ep_create (%p, %p, %p, %p, %p, %p, %p)\n", + ia_handle, + pz_handle, + recv_evd_handle, + request_evd_handle, + connect_evd_handle, + ep_attr, + ep_handle); + DAPL_CNTR(DCNT_EP_CREATE); + + ia_ptr = (DAPL_IA *)ia_handle; + dat_status = DAT_SUCCESS; + + /* + * Verify parameters + */ + if ( DAPL_BAD_HANDLE (ia_ptr, DAPL_MAGIC_IA) ) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_IA); + goto bail; + } + + /* + * Verify non-required parameters. + * N.B. Assumption: any parameter that can be + * modified by dat_ep_modify() is not strictly + * required when the EP is created + */ + if ( pz_handle != NULL && + DAPL_BAD_HANDLE (pz_handle, DAPL_MAGIC_PZ) ) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_PZ); + goto bail; + } + + /* If connect handle is !NULL verify handle is good */ + if (connect_evd_handle != DAT_HANDLE_NULL && + (DAPL_BAD_HANDLE (connect_evd_handle, DAPL_MAGIC_EVD) || + ! (((DAPL_EVD *)connect_evd_handle)->evd_flags & DAT_EVD_CONNECTION_FLAG)) ) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EVD_CONN); + goto bail; + } + /* If recv_evd is !NULL, verify handle is good and flags are valid */ + if (recv_evd_handle != DAT_HANDLE_NULL && + (DAPL_BAD_HANDLE (recv_evd_handle, DAPL_MAGIC_EVD) || + ! (((DAPL_EVD *)recv_evd_handle)->evd_flags & DAT_EVD_DTO_FLAG) ) ) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EVD_RECV); + goto bail; + } + + /* If req_evd is !NULL, verify handle is good and flags are valid */ + if (request_evd_handle != DAT_HANDLE_NULL && + (DAPL_BAD_HANDLE (request_evd_handle, DAPL_MAGIC_EVD) || + ! (((DAPL_EVD *)request_evd_handle)->evd_flags & DAT_EVD_DTO_FLAG) ) ) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EVD_REQUEST); + goto bail; + } + + if ( ep_handle == NULL ) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER, DAT_INVALID_ARG7); + goto bail; + } + + if (( DAT_UVERYLONG _w64)ep_attr & 3) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER, DAT_INVALID_ARG6); + goto bail; + } + + /* + * Qualify EP Attributes are legal and make sense. Note that if one + * or both of the DTO handles are NULL, then the corresponding + * max_*_dtos must 0 as the user will not be able to post dto ops on + * the respective queue. + */ + if (ep_attr != NULL && + (ep_attr->service_type != DAT_SERVICE_TYPE_RC || + (recv_evd_handle == DAT_HANDLE_NULL && ep_attr->max_recv_dtos != 0) || + (recv_evd_handle != DAT_HANDLE_NULL && ep_attr->max_recv_dtos == 0) || + (request_evd_handle == DAT_HANDLE_NULL && ep_attr->max_request_dtos != 0) || + (request_evd_handle != DAT_HANDLE_NULL && ep_attr->max_request_dtos == 0) || + ep_attr->max_recv_iov == 0 || + ep_attr->max_request_iov == 0 || + (DAT_SUCCESS != dapl_ep_check_recv_completion_flags ( + ep_attr->recv_completion_flags)) )) + { + dat_status = DAT_INVALID_PARAMETER | DAT_INVALID_ARG6; + goto bail; + } + + /* Verify the attributes against the transport */ + if (ep_attr != NULL) + { + dapl_os_memzero (&ep_attr_limit, sizeof (DAT_EP_ATTR)); + dat_status = dapls_ib_query_hca (ia_ptr->hca_ptr, + NULL, &ep_attr_limit, NULL); + if (dat_status != DAT_SUCCESS) + { + goto bail; + } + if ( ep_attr->max_mtu_size > ep_attr_limit.max_mtu_size || + ep_attr->max_rdma_size > ep_attr_limit.max_rdma_size || + ep_attr->max_recv_dtos > ep_attr_limit.max_recv_dtos || + ep_attr->max_request_dtos > ep_attr_limit.max_request_dtos || + ep_attr->max_recv_iov > ep_attr_limit.max_recv_iov || + ep_attr->max_request_iov > ep_attr_limit.max_request_iov || + ep_attr->max_rdma_read_in > ep_attr_limit.max_rdma_read_in || + ep_attr->max_rdma_read_out> ep_attr_limit.max_rdma_read_out ) + + { + dat_status = DAT_INVALID_PARAMETER | DAT_INVALID_ARG6; + goto bail; + } + } + + /* + * Verify the completion flags for the EVD and the EP + */ + /* + * XXX FIXME + * XXX Need to make assign the EVD to the right completion type + * XXX depending on the EP attributes. Fail if the types don't + * XXX match, they are mutually exclusive. + */ + evd_ptr = (DAPL_EVD *)recv_evd_handle; + if (evd_ptr != NULL && evd_ptr->completion_type == DAPL_EVD_STATE_INIT) + { + if (ep_attr != NULL && + ep_attr->recv_completion_flags == DAT_COMPLETION_DEFAULT_FLAG) + { + evd_ptr->completion_type = DAPL_EVD_STATE_THRESHOLD; + } + else + { + evd_ptr->completion_type = ep_attr->recv_completion_flags; + } + } + + evd_ptr = (DAPL_EVD *)request_evd_handle; + if (evd_ptr != NULL && evd_ptr->completion_type == DAPL_EVD_STATE_INIT) + { + if (ep_attr != NULL && + ep_attr->request_completion_flags == DAT_COMPLETION_DEFAULT_FLAG) + { + evd_ptr->completion_type = DAPL_EVD_STATE_THRESHOLD; + } + else + { + evd_ptr->completion_type = ep_attr->request_completion_flags; + } + } + + + /* Allocate EP */ + ep_ptr = dapl_ep_alloc ( ia_ptr, ep_attr ); + if ( ep_ptr == NULL ) + { + dat_status = DAT_ERROR (DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); + goto bail; + } + + /* + * Fill in the EP + */ + ep_ptr->header.owner_ia = ia_ptr; + ep_ptr->param.ia_handle = ia_handle; + ep_ptr->param.ep_state = DAT_EP_STATE_UNCONNECTED; + ep_ptr->param.local_ia_address_ptr= + (DAT_IA_ADDRESS_PTR)&ia_ptr->hca_ptr->hca_address; + /* Set the remote address pointer to the end of the EP struct */ + ep_ptr->param.remote_ia_address_ptr = (DAT_IA_ADDRESS_PTR) (ep_ptr + 1); + + ep_ptr->param.pz_handle = pz_handle; + ep_ptr->param.recv_evd_handle = recv_evd_handle; + ep_ptr->param.request_evd_handle = request_evd_handle; + ep_ptr->param.connect_evd_handle = connect_evd_handle; + + /* + * Make sure we handle the NULL DTO EVDs + */ + if ( recv_evd_handle == DAT_HANDLE_NULL && ep_attr == NULL ) + { + ep_ptr->param.ep_attr.max_recv_dtos = 0; + } + + if ( request_evd_handle == DAT_HANDLE_NULL && ep_attr == NULL ) + { + ep_ptr->param.ep_attr.max_request_dtos = 0; + } + + /* + * If the user has specified a PZ handle we allocate a QP for + * this EP; else we defer until it is assigned via ep_modify(). + * As much as possible we try to keep QP creation out of the + * connect path to avoid resource errors in strange places. + */ + if (pz_handle != DAT_HANDLE_NULL ) + { + /* Take a reference on the PZ handle */ + dapl_os_atomic_inc (& ((DAPL_PZ *)pz_handle)->pz_ref_count); + + /* + * Get a QP from the IB provider + */ + dat_status = dapls_ib_qp_alloc ( ia_ptr, ep_ptr, ep_ptr ); + + if ( dat_status != DAT_SUCCESS) + { + dapl_os_atomic_dec (& ((DAPL_PZ *)pz_handle)->pz_ref_count); + dapl_ep_dealloc ( ep_ptr ); + goto bail; + } + } + else + { + ep_ptr->qp_state = DAPL_QP_STATE_UNATTACHED; + } + + /* + * Update ref counts. See the spec where the endpoint marks + * a data object as 'in use' + * pz_handle: dat_pz_free, uDAPL Document, 6.6.1.2 + * evd_handles: + * + * N.B. This should really be done by a util routine. + */ + dapl_os_atomic_inc (& ((DAPL_EVD *)connect_evd_handle)->evd_ref_count); + /* Optional handles */ + if (recv_evd_handle != DAT_HANDLE_NULL) + { + dapl_os_atomic_inc (& ((DAPL_EVD *)recv_evd_handle)->evd_ref_count); + } + if (request_evd_handle != DAT_HANDLE_NULL) + { + dapl_os_atomic_inc (& ((DAPL_EVD *)request_evd_handle)->evd_ref_count); + } + + /* Link it onto the IA */ + dapl_ia_link_ep (ia_ptr, ep_ptr); + + *ep_handle = ep_ptr; + +bail: + return dat_status; +} + + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_disconnect.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_disconnect.c new file mode 100644 index 00000000..a26f2294 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_disconnect.c @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ep_disconnect.c + * + * PURPOSE: Endpoint management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 5 + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_ia_util.h" +#include "dapl_ep_util.h" +#include "dapl_sp_util.h" +#include "dapl_evd_util.h" +#include "dapl_adapter_util.h" +#include "dapl_cr_util.h" /* for callback routine */ + +/* + * dapl_ep_disconnect + * + * DAPL Requirements Version xxx, 6.5.9 + * + * Terminate a connection. + * + * Input: + * ep_handle + * disconnect_flags + * + * Output: + * None + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + */ +DAT_RETURN +dapl_ep_disconnect ( + IN DAT_EP_HANDLE ep_handle, + IN DAT_CLOSE_FLAGS disconnect_flags) +{ + DAPL_EP *ep_ptr; + DAPL_EVD *evd_ptr; + DAPL_CR *cr_ptr; + DAT_RETURN dat_status = DAT_SUCCESS; + + dapl_dbg_log (DAPL_DBG_TYPE_API | DAPL_DBG_TYPE_CM, + "dapl_ep_disconnect (EP :%p, close flag: %x)\n", + ep_handle, + disconnect_flags); + DAPL_CNTR(DCNT_EP_DISCONNECT); + + ep_ptr = (DAPL_EP *) ep_handle; + + /* + * Verify parameter & state + */ + if ( DAPL_BAD_HANDLE (ep_ptr, DAPL_MAGIC_EP ) ) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP); + goto bail; + } + + /* + * Do the verification of parameters and the state change atomically + */ + dapl_os_lock (&ep_ptr->header.lock); + + switch ( ep_ptr->param.ep_state ) + { + case DAT_EP_STATE_DISCONNECTED: + break; + case DAT_EP_STATE_COMPLETION_PENDING: + dapls_ib_disconnect(ep_ptr, DAT_CLOSE_ABRUPT_FLAG); + break; + case DAT_EP_STATE_DISCONNECT_PENDING: + if (disconnect_flags == DAT_CLOSE_GRACEFUL_FLAG ) + { + break; + } + case DAT_EP_STATE_CONNECTED: + if (disconnect_flags == DAT_CLOSE_GRACEFUL_FLAG ) + { + ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECT_PENDING; + } + if (ep_ptr->sent_discreq != TRUE ) + { + dapls_ib_disconnect(ep_ptr, disconnect_flags); + } + break; + case DAT_EP_STATE_ACTIVE_CONNECTION_PENDING: + if (ep_ptr->sent_discreq != TRUE ) + { + dapls_ib_disconnect(ep_ptr, disconnect_flags); + } + evd_ptr = (DAPL_EVD *) ep_ptr->param.connect_evd_handle; + dapls_evd_post_connection_event(evd_ptr, + DAT_CONNECTION_EVENT_DISCONNECTED, + (DAT_HANDLE) ep_ptr, + 0, + 0); + break; + default: + dat_status = DAT_ERROR (DAT_INVALID_STATE,dapls_ep_state_subtype (ep_ptr)); + break; + } + + dapl_os_unlock ( &ep_ptr->header.lock ); + +bail: + dapl_dbg_log (DAPL_DBG_TYPE_RTN | DAPL_DBG_TYPE_CM, + "dapl_ep_disconnect () returns 0x%x\n", dat_status); + + return dat_status; +} + + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_dup_connect.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_dup_connect.c new file mode 100644 index 00000000..d5eb6cb7 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_dup_connect.c @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ep_dup_connect.c + * + * PURPOSE: Endpoint management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 5 + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_ep_util.h" +#include "dapl_adapter_util.h" +#include "dapl_timer_util.h" + +/* + * dapl_ep_dup_connect + * + * DAPL Requirements Version xxx, 6.5.8 + * + * Requst that a connection be established between the local Endpoint + * and a remote Endpoint. The remote Endpoint is identified by the + * dup_ep. + * + * Input: + * ep_handle + * ep_dup_handle + * conn_qual + * timeout + * private_data_size + * private_data + * qos + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + * DAT_INVALID_STATE + * DAT_MODEL_NOT_SUPPORTED + */ +DAT_RETURN +dapl_ep_dup_connect ( + IN DAT_EP_HANDLE ep_handle, + IN DAT_EP_HANDLE ep_dup_handle, + IN DAT_TIMEOUT timeout, + IN DAT_COUNT private_data_size, + IN const DAT_PVOID private_data, + IN DAT_QOS qos) +{ + DAPL_EP *ep_dup_ptr; + DAT_RETURN dat_status; + DAT_IA_ADDRESS_PTR remote_ia_address_ptr; + DAT_CONN_QUAL remote_conn_qual; + + ep_dup_ptr = (DAPL_EP *) ep_dup_handle; + + /* + * Verify the dup handle, which must be connected. All other + * parameters will be verified by dapl_ep_connect + */ + if ( DAPL_BAD_HANDLE (ep_dup_handle, DAPL_MAGIC_EP ) ) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE,DAT_INVALID_HANDLE_EP); + goto bail; + } + + /* Can't do a connection in 0 time, reject outright */ + if ( timeout == 0 ) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER, DAT_INVALID_ARG3); + goto bail; + } + + /* Check both the EP state and the QP state: if we don't have a QP + * there is a problem. Do this under a lock and pull out + * the connection parameters for atomicity. + */ + dapl_os_lock ( &ep_dup_ptr->header.lock ); + if ( ep_dup_ptr->param.ep_state != DAT_EP_STATE_CONNECTED ) + { + dapl_os_unlock ( &ep_dup_ptr->header.lock ); + dat_status = DAT_ERROR (DAT_INVALID_STATE,dapls_ep_state_subtype (ep_dup_ptr)); + goto bail; + } + remote_ia_address_ptr = ep_dup_ptr->param.remote_ia_address_ptr; + remote_conn_qual = ep_dup_ptr->param.remote_port_qual; + dapl_os_unlock ( &ep_dup_ptr->header.lock ); + + dat_status = dapl_ep_connect ( ep_handle, + remote_ia_address_ptr, + remote_conn_qual, + timeout, + private_data_size, + private_data, + qos, + DAT_CONNECT_DEFAULT_FLAG ); + bail: + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_free.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_free.c new file mode 100644 index 00000000..0f4ff677 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_free.c @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ep_free.c + * + * PURPOSE: Endpoint management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 5.4 + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_ia_util.h" +#include "dapl_ep_util.h" +#include "dapl_adapter_util.h" +#include "dapl_ring_buffer_util.h" +#include "dapl_timer_util.h" + +/* + * dapl_ep_free + * + * DAPL Requirements Version xxx, 6.5.3 + * + * Destroy an instance of the Endpoint + * + * Input: + * ep_handle + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + * DAT_INVALID_STATE + */ +DAT_RETURN +dapl_ep_free ( + IN DAT_EP_HANDLE ep_handle) +{ + DAPL_EP *ep_ptr; + DAPL_IA *ia_ptr; + DAT_EP_PARAM *param; + ib_qp_state_t save_qp_state; + DAT_RETURN dat_status = DAT_SUCCESS; + + dapl_dbg_log (DAPL_DBG_TYPE_API, "dapl_ep_free (%p)\n", ep_handle); + DAPL_CNTR(DCNT_EP_FREE); + + ep_ptr = (DAPL_EP *) ep_handle; + param = &ep_ptr->param; + + /* + * Verify parameter & state + */ + if ( DAPL_BAD_HANDLE (ep_ptr, DAPL_MAGIC_EP ) ) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP); + goto bail; + } + + if ( ep_ptr->param.ep_state == DAT_EP_STATE_RESERVED || + ep_ptr->param.ep_state == DAT_EP_STATE_PASSIVE_CONNECTION_PENDING || + ep_ptr->param.ep_state == DAT_EP_STATE_TENTATIVE_CONNECTION_PENDING ) + { + dapl_dbg_log (DAPL_DBG_TYPE_WARN, + "--> dapl_ep_free: invalid state: %x, ep %p\n", + ep_ptr->param.ep_state, + ep_ptr); + dat_status = DAT_ERROR (DAT_INVALID_STATE, + dapls_ep_state_subtype (ep_ptr)); + goto bail; + } + + ia_ptr = ep_ptr->header.owner_ia; + + /* If we are connected, issue a disconnect. If we are in the + * disconnect_pending state, disconnect with the ABRUPT flag + * set. + */ + + /* + * Invoke ep_disconnect to clean up outstanding connections + */ + (void) dapl_ep_disconnect (ep_ptr, DAT_CLOSE_ABRUPT_FLAG); + dapl_os_assert (ep_ptr->param.ep_state == DAT_EP_STATE_DISCONNECTED || + ep_ptr->param.ep_state == DAT_EP_STATE_UNCONNECTED); + + /* + * Do verification of parameters and the state change atomically. + */ + dapl_os_lock ( &ep_ptr->header.lock ); + + if (ep_ptr->cxn_timer != NULL) + { + dapls_timer_cancel ( ep_ptr->cxn_timer ); + dapl_os_free ( ep_ptr->cxn_timer, sizeof ( DAPL_OS_TIMER ) ); + ep_ptr->cxn_timer = NULL; + } + + /* Remove the EP from the IA */ + dapl_ia_unlink_ep ( ia_ptr, ep_ptr ); + + /* + * Update ref counts. Note the user may have used ep_modify + * to set handles to NULL. Set handles to NULL so this routine + * is idempotent. + */ + if ( param->pz_handle != NULL ) + { + dapl_os_atomic_dec (& ((DAPL_PZ *)param->pz_handle)->pz_ref_count); + param->pz_handle = NULL; + } + if ( param->recv_evd_handle != NULL ) + { + dapl_os_atomic_dec (& ((DAPL_EVD *)param->recv_evd_handle)->evd_ref_count); + param->recv_evd_handle = NULL; + } + if ( param->request_evd_handle != NULL ) + { + dapl_os_atomic_dec (& ((DAPL_EVD *)param->request_evd_handle)->evd_ref_count); + param->request_evd_handle = NULL; + } + if ( param->connect_evd_handle != NULL ) + { + dapl_os_atomic_dec (& ((DAPL_EVD *)param->connect_evd_handle)->evd_ref_count); + param->connect_evd_handle = NULL; + } + + /* + * Finish tearing everything down. + */ + dapl_dbg_log (DAPL_DBG_TYPE_EP, + "dapl_ep_free: Free EP: %x, ep %p qp_state %x qp_handle %x\n", + ep_ptr->param.ep_state, + ep_ptr, + ep_ptr->qp_state, + ep_ptr->qp_handle); + /* + * Take care of the transport resource. Make a copy of the qp_state + * to prevent race conditions when we exit the lock. + */ + save_qp_state = ep_ptr->qp_state; + ep_ptr->qp_state = DAPL_QP_STATE_UNATTACHED; + dapl_os_unlock (&ep_ptr->header.lock); + + /* Free the QP. If the EP has never been used, the QP is invalid */ + if ( save_qp_state != DAPL_QP_STATE_UNATTACHED ) + { + dat_status = dapls_ib_qp_free (ia_ptr, ep_ptr); + /* This should always succeed, but report to the user if + * there is a problem. The qp_state must be restored so + * they can try it again in the face of EINTR or similar + * where the QP is OK but the call couldn't complete. + */ + if (dat_status != DAT_SUCCESS) + { + ep_ptr->qp_state = save_qp_state; + goto bail; + } + } + + /* Free the resource */ + dapl_ep_dealloc (ep_ptr); + +bail: + return dat_status; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_get_status.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_get_status.c new file mode 100644 index 00000000..217581a4 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_get_status.c @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ep_get_status.c + * + * PURPOSE: Endpoint management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 5 + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_ring_buffer_util.h" + +/* + * dapl_ep_get_status + * + * DAPL Requirements Version xxx, 6.5.4 + * + * Provide the consumer with a quick snapshot of the Endpoint. + * The snapshot consists of Endpoint state and DTO information. + * + * Input: + * ep_handle + * + * Output: + * ep_state + * in_dto_idle + * out_dto_idle + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + */ +DAT_RETURN +dapl_ep_get_status ( + IN DAT_EP_HANDLE ep_handle, + OUT DAT_EP_STATE *ep_state, + OUT DAT_BOOLEAN *in_dto_idle, + OUT DAT_BOOLEAN *out_dto_idle) +{ + DAPL_EP *ep_ptr; + DAT_RETURN dat_status; + + dapl_dbg_log (DAPL_DBG_TYPE_API, + "dapl_ep_get_status (%p, %p, %p, %p)\n", + ep_handle, + ep_state, + in_dto_idle, + out_dto_idle); + + ep_ptr = (DAPL_EP *) ep_handle; + dat_status = DAT_SUCCESS; + + /* + * Verify parameter & state + */ + if ( DAPL_BAD_HANDLE (ep_ptr, DAPL_MAGIC_EP ) ) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE,DAT_INVALID_HANDLE_EP); + goto bail; + } + + /* + * Gather state info for user + */ + if ( ep_state != NULL ) + { + *ep_state = ep_ptr->param.ep_state; + } + + if ( in_dto_idle != NULL ) + { + *in_dto_idle = (ep_ptr->recv_count) ? DAT_FALSE : DAT_TRUE; + } + + if ( out_dto_idle != NULL ) + { + *out_dto_idle = (ep_ptr->req_count) ? DAT_FALSE : DAT_TRUE; + } + + bail: + return dat_status; +} + + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_modify.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_modify.c new file mode 100644 index 00000000..6c0a84ed --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_modify.c @@ -0,0 +1,756 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ep_modify.c + * + * PURPOSE: Endpoint management + * Description: Interfaces in this file are completely described in + * the DAPL 1.0 API, Chapter 6, section 5 + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_cookie.h" +#include "dapl_ep_util.h" +#include "dapl_adapter_util.h" + +/* + * Internal prototypes + */ + +static _INLINE_ DAT_RETURN +dapli_ep_modify_validate_parameters ( + IN DAT_EP_HANDLE ep_handle, + IN DAT_EP_PARAM_MASK ep_param_mask, + IN const DAT_EP_PARAM *ep_param, + OUT DAPL_IA **ia_ptr, + OUT DAPL_EP **ep_ptr, + OUT DAT_EP_ATTR *ep_attr_ptr ); + + +/* + * dapl_ep_modify + * + * DAPL Requirements Version xxx, 6.5.6 + * + * Provide the consumer parameters, including attributes and status of + * the Endpoint. + * + * Input: + * ep_handle + * ep_args_mask + * + * Output: + * ep_args + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + * DAT_INVALID_ATTRIBUTE + * DAT_INVALID_STATE + */ +DAT_RETURN +dapl_ep_modify ( + IN DAT_EP_HANDLE ep_handle, + IN DAT_EP_PARAM_MASK ep_param_mask, + IN const DAT_EP_PARAM *ep_param ) +{ + DAPL_IA *ia; + DAPL_EP *ep1, *ep2; + DAT_EP_ATTR ep_attr1, ep_attr2; + DAPL_EP new_ep, copy_of_old_ep; + DAPL_EP alloc_ep; /* Holder for resources. */ + DAPL_PZ *tmp_pz; + DAPL_EVD *tmp_evd; + DAT_RETURN dat_status; + + /* Flag indicating we've allocated a new one of these. */ + DAT_BOOLEAN qp_allocated = DAT_FALSE; + DAT_BOOLEAN rqst_cb_allocated = DAT_FALSE; + DAT_BOOLEAN recv_cb_allocated = DAT_FALSE; + DAT_BOOLEAN rqst_iov_allocated = DAT_FALSE; + DAT_BOOLEAN recv_iov_allocated = DAT_FALSE; + + /* Flag indicating we've used (assigned to QP) a new one of these. */ + DAT_BOOLEAN qp_used = DAT_FALSE; + DAT_BOOLEAN rqst_cb_used = DAT_FALSE; + DAT_BOOLEAN recv_cb_used = DAT_FALSE; + DAT_BOOLEAN rqst_iov_used = DAT_FALSE; + DAT_BOOLEAN recv_iov_used = DAT_FALSE; + + dapl_os_memzero ( (void*)&alloc_ep, sizeof(DAPL_EP) ); + dapl_os_memzero ( (void*)&new_ep, sizeof(DAPL_EP) ); + dapl_os_memzero ( (void*)©_of_old_ep, sizeof(DAPL_EP) ); + + dat_status = dapli_ep_modify_validate_parameters ( ep_handle, + ep_param_mask, + ep_param, + &ia, + &ep1, + &ep_attr1); + if ( DAT_SUCCESS != dat_status) + { + goto bail; + } + + /* + * Setup the alloc_ep with the appropriate parameters (primarily + * for allocating the QP. + */ + alloc_ep = *ep1; + alloc_ep.param.ep_attr = ep_attr1; + if ( ep_param_mask & DAT_EP_FIELD_PZ_HANDLE ) + { + alloc_ep.param.pz_handle = ep_param->pz_handle; + } + + if ( ep_param_mask & DAT_EP_FIELD_RECV_EVD_HANDLE ) + { + alloc_ep.param.recv_evd_handle = ep_param->recv_evd_handle; + } + + if ( ep_param_mask & DAT_EP_FIELD_REQUEST_EVD_HANDLE ) + { + alloc_ep.param.request_evd_handle = ep_param->request_evd_handle; + } + + if ( ep_param_mask & DAT_EP_FIELD_CONNECT_EVD_HANDLE ) + { + alloc_ep.param.connect_evd_handle = ep_param->connect_evd_handle; + } + + /* + * Allocate everything that might be needed. + * We allocate separately, and into a different "holding" + * ep, since we a) want the copy of the old ep into the new ep to + * be atomic with the assignment back (under lock), b) want the + * assignment of the allocated materials to be after the copy of the + * old ep into the new ep, and c) don't want the allocation done + * under lock. + */ + dat_status = dapls_cb_create ( + &alloc_ep.req_buffer, + ep1, /* For pointer in buffer bool. */ + ep_attr1.max_request_dtos ); + if ( DAT_SUCCESS != dat_status ) + { + goto bail; + } + rqst_cb_allocated = DAT_TRUE; + + dat_status = dapls_cb_create ( + &alloc_ep.recv_buffer, + ep1, /* For pointer in buffer bool. */ + ep_attr1.max_recv_dtos ); + if ( DAT_SUCCESS != dat_status ) + { + goto bail; + } + recv_cb_allocated = DAT_TRUE; + + alloc_ep.send_iov_num = ep_attr1.max_request_iov; + alloc_ep.send_iov = dapl_os_alloc (ep_attr1.max_request_iov + * sizeof (ib_data_segment_t)); + if ( alloc_ep.recv_iov == NULL ) + { + dat_status = DAT_ERROR (DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); + goto bail; + } + recv_iov_allocated = DAT_TRUE; + + alloc_ep.recv_iov_num = ep_attr1.max_recv_iov; + alloc_ep.recv_iov = dapl_os_alloc (ep_attr1.max_recv_iov + * sizeof (ib_data_segment_t)); + if ( alloc_ep.recv_iov == NULL ) + { + dat_status = DAT_ERROR (DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); + goto bail; + } + recv_iov_allocated = DAT_TRUE; + + dat_status = dapls_ib_qp_alloc ( ia, &alloc_ep, ep1 ); + if ( dat_status != DAT_SUCCESS ) + { + goto bail; + } + qp_allocated = DAT_TRUE; + + /* + * Now we atomically modify the EP, under lock + * There's a lot of work done here, but there should be no + * allocation or blocking. + */ + dapl_os_lock ( &ep1->header.lock ); + + /* + * Revalidate parameters; make sure that races haven't + * changed anything important. + */ + dat_status = dapli_ep_modify_validate_parameters ( ep_handle, + ep_param_mask, + ep_param, + &ia, + &ep2, + &ep_attr2 ); + if ( DAT_SUCCESS != dat_status ) + { + dapl_os_unlock ( &ep2->header.lock ); + goto bail; + } + + /* + * All of the following should be impossible, if validation + * occurred. But they're important to the logic of this routine, + * so we check. + */ + dapl_os_assert ( ep1 == ep2 ); + dapl_os_assert ( ep_attr2.max_recv_dtos == ep_attr1.max_recv_dtos ); + dapl_os_assert ( ep_attr2.max_request_dtos == ep_attr1.max_request_dtos ); + dapl_os_assert ( ep_attr2.max_recv_iov == ep_attr1.max_recv_iov ); + dapl_os_assert ( ep_attr2.max_request_iov == ep_attr1.max_request_iov ); + + copy_of_old_ep = *ep2; + + /* + * Setup new ep. + */ + new_ep = *ep2; + new_ep.param.ep_attr = ep_attr2; + + /* + * We can initialize the PZ and EVD handles from the alloc_ep because + * the only thing that could have changed since we setup the alloc_ep + * is stuff changed by dapl_cr_accept, and neither PZ nor EVD is in that + * list. + */ + new_ep.param.pz_handle = alloc_ep.param.pz_handle; + new_ep.param.recv_evd_handle = alloc_ep.param.recv_evd_handle; + new_ep.param.request_evd_handle = alloc_ep.param.request_evd_handle; + new_ep.param.connect_evd_handle = alloc_ep.param.connect_evd_handle; + + /* Deal with each of the allocation fields. */ + if ( ep_param_mask & DAT_EP_FIELD_EP_ATTR_MAX_RECV_DTOS + && (ep_param->ep_attr.max_recv_dtos + != ep2->param.ep_attr.max_recv_dtos) ) + { + new_ep.recv_buffer = alloc_ep.recv_buffer; + recv_cb_used = DAT_TRUE; + } + + if ( ep_param_mask & DAT_EP_FIELD_EP_ATTR_MAX_REQUEST_DTOS + && (ep_param->ep_attr.max_request_dtos + != ep2->param.ep_attr.max_request_dtos) ) + { + new_ep.req_buffer = alloc_ep.req_buffer; + rqst_cb_used = DAT_TRUE; + } + + if ( ep_param_mask & DAT_EP_FIELD_EP_ATTR_MAX_RECV_IOV + && new_ep.recv_iov_num != ep2->recv_iov_num ) + { + new_ep.recv_iov = alloc_ep.recv_iov; + recv_iov_used = DAT_TRUE; + } + + if ( ep_param_mask & DAT_EP_FIELD_EP_ATTR_MAX_REQUEST_IOV + && new_ep.send_iov_num != ep2->send_iov_num ) + { + new_ep.send_iov = alloc_ep.send_iov; + rqst_iov_used = DAT_TRUE; + } + + /* + * We need to change the QP only if there already was a QP + * (leave things the way you found them!) and one of the + * following has changed: send/recv EVD, send/recv reqs/IOV max. + */ + if ( DAPL_QP_STATE_UNATTACHED != new_ep.qp_state + && (ep_param_mask + & (DAT_EP_FIELD_EP_ATTR_MAX_REQUEST_IOV + | DAT_EP_FIELD_EP_ATTR_MAX_RECV_IOV + | DAT_EP_FIELD_EP_ATTR_MAX_REQUEST_DTOS + | DAT_EP_FIELD_EP_ATTR_MAX_RECV_DTOS + | DAT_EP_FIELD_RECV_EVD_HANDLE + | DAT_EP_FIELD_REQUEST_EVD_HANDLE)) ) + { + /* + * We shouldn't be racing with connection establishment + * because the parameter validate routine should protect us, + * but it's an important enough point that we assert it. + */ + dapl_os_assert ( (ep2->param.ep_state + != DAT_EP_STATE_PASSIVE_CONNECTION_PENDING) + && (ep2->param.ep_state + != DAT_EP_STATE_ACTIVE_CONNECTION_PENDING) ); + + new_ep.qp_handle = alloc_ep.qp_handle; + new_ep.qpn = alloc_ep.qpn; + } + + /* + * The actual assignment, including modifying QP parameters. + * Modifying QP parameters needs to come first, as if it fails + * we need to exit. + */ + if ( DAPL_QP_STATE_UNATTACHED != new_ep.qp_state ) + { + dat_status = dapls_ib_qp_modify ( ia, ep2, &ep_attr2 ); + if ( dat_status != DAT_SUCCESS ) + { + dapl_os_unlock ( & ep2->header.lock ); + goto bail; + } + } + *ep2 = new_ep; + + dapl_os_unlock ( &ep2->header.lock ); + + /* + * Modify reference counts, incrementing new ones + * and then decrementing old ones (so if they're the same + * the refcount never drops to zero). + */ + tmp_pz = (DAPL_PZ *) new_ep.param.pz_handle; + if ( NULL != tmp_pz ) + { + dapl_os_atomic_inc (&tmp_pz->pz_ref_count); + } + + tmp_evd = (DAPL_EVD *) new_ep.param.recv_evd_handle; + if ( NULL != tmp_evd ) + { + dapl_os_atomic_inc (&tmp_evd->evd_ref_count); + } + + tmp_evd = (DAPL_EVD *) new_ep.param.request_evd_handle; + if ( NULL != tmp_evd ) + { + dapl_os_atomic_inc (&tmp_evd->evd_ref_count); + } + + tmp_evd = (DAPL_EVD *) new_ep.param.connect_evd_handle; + if ( NULL != tmp_evd ) + { + dapl_os_atomic_inc (&tmp_evd->evd_ref_count); + } + + /* decreament the old reference counts */ + tmp_pz = (DAPL_PZ *) copy_of_old_ep.param.pz_handle; + if ( NULL != tmp_pz ) + { + dapl_os_atomic_dec (&tmp_pz->pz_ref_count); + } + + tmp_evd = (DAPL_EVD *) copy_of_old_ep.param.recv_evd_handle; + if ( NULL != tmp_evd ) + { + dapl_os_atomic_dec (&tmp_evd->evd_ref_count); + } + + tmp_evd = (DAPL_EVD *) copy_of_old_ep.param.request_evd_handle; + if ( NULL != tmp_evd ) + { + dapl_os_atomic_dec (&tmp_evd->evd_ref_count); + } + + tmp_evd = (DAPL_EVD *) copy_of_old_ep.param.connect_evd_handle; + if ( NULL != tmp_evd ) + { + dapl_os_atomic_dec (&tmp_evd->evd_ref_count); + } + +bail: + if ( qp_allocated ) + { + DAT_RETURN local_dat_status; + if ( dat_status != DAT_SUCCESS || !qp_used ) + { + local_dat_status = dapls_ib_qp_free (ia, &alloc_ep ); + } + else + { + local_dat_status = dapls_ib_qp_free (ia, ©_of_old_ep ); + } + if (local_dat_status != DAT_SUCCESS) + { + dapl_dbg_log (DAPL_DBG_TYPE_WARN, + "ep_modify: Failed to free QP; status %x\n", + local_dat_status); + } + } + + if ( rqst_cb_allocated ) + { + if ( dat_status != DAT_SUCCESS || !rqst_cb_used ) + { + dapls_cb_free ( &alloc_ep.req_buffer ); + } + else + { + dapls_cb_free ( ©_of_old_ep.req_buffer ); + } + } + + if ( recv_cb_allocated ) + { + if ( dat_status != DAT_SUCCESS || !recv_cb_used ) + { + dapls_cb_free ( &alloc_ep.recv_buffer ); + } + else + { + dapls_cb_free ( ©_of_old_ep.recv_buffer ); + } + } + + if ( rqst_iov_allocated ) + { + if ( dat_status != DAT_SUCCESS || !rqst_iov_used ) + { + dapl_os_free ( alloc_ep.send_iov, + (alloc_ep.send_iov_num + * sizeof (ib_data_segment_t))); + } + else + { + dapl_os_free ( copy_of_old_ep.send_iov, + (copy_of_old_ep.send_iov_num + * sizeof (ib_data_segment_t))); + } + } + + if ( recv_iov_allocated ) + { + if ( dat_status != DAT_SUCCESS || !recv_iov_used ) + { + dapl_os_free ( alloc_ep.recv_iov, + (alloc_ep.recv_iov_num + * sizeof (ib_data_segment_t))); + } + else + { + dapl_os_free ( copy_of_old_ep.recv_iov, + (copy_of_old_ep.recv_iov_num + * sizeof (ib_data_segment_t))); + } + } + return dat_status; +} + + +/* + * dapli_ep_modify_validate_parameters + * + * Validate parameters + * + * The space for the ep_attr_ptr parameter should be allocated by the + * consumer. Upon success, this parameter will contain the current ep + * attribute values with the requested modifications made. + * + */ + +static DAT_RETURN +dapli_ep_modify_validate_parameters ( + IN DAT_EP_HANDLE ep_handle, + IN DAT_EP_PARAM_MASK ep_param_mask, + IN const DAT_EP_PARAM *ep_param, + OUT DAPL_IA **ia_ptr, + OUT DAPL_EP **ep_ptr, + OUT DAT_EP_ATTR *ep_attr_ptr ) +{ + DAPL_IA *ia; + DAPL_EP *ep; + DAT_EP_ATTR ep_attr; + DAT_EP_ATTR ep_attr_limit; + DAT_EP_ATTR ep_attr_request; + DAT_RETURN dat_status; + + *ia_ptr = NULL; + *ep_ptr = NULL; + dat_status = DAT_SUCCESS; + + if ( DAPL_BAD_HANDLE (ep_handle, DAPL_MAGIC_EP ) ) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP); + goto bail; + } + + ep = (DAPL_EP *) ep_handle; + ia = ep->header.owner_ia; + + /* + * Verify parameters valid in current EP state + */ + if ( ep_param_mask & (DAT_EP_FIELD_IA_HANDLE | + DAT_EP_FIELD_EP_STATE | + DAT_EP_FIELD_LOCAL_IA_ADDRESS_PTR | + DAT_EP_FIELD_LOCAL_PORT_QUAL | + DAT_EP_FIELD_REMOTE_IA_ADDRESS_PTR | + DAT_EP_FIELD_REMOTE_PORT_QUAL) ) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER, DAT_INVALID_ARG2); + goto bail; + } + + /* + * Can only change the PZ handle if we are UNCONNECTED or + * TENTATIVE_CONNECTION_PENDING (psp PROVIDER allocated EP) + */ + if ( (ep_param_mask & DAT_EP_FIELD_PZ_HANDLE) && + ( ep->param.ep_state != DAT_EP_STATE_UNCONNECTED && + ep->param.ep_state != DAT_EP_STATE_TENTATIVE_CONNECTION_PENDING ) ) + { + dat_status = DAT_ERROR (DAT_INVALID_STATE, dapls_ep_state_subtype (ep)); + goto bail; + } + + if ( (ep_param_mask & (DAT_EP_FIELD_RECV_EVD_HANDLE | + DAT_EP_FIELD_REQUEST_EVD_HANDLE | + DAT_EP_FIELD_CONNECT_EVD_HANDLE | + DAT_EP_FIELD_EP_ATTR_SERVICE_TYPE | + DAT_EP_FIELD_EP_ATTR_MAX_MESSAGE_SIZE | + DAT_EP_FIELD_EP_ATTR_MAX_RDMA_SIZE | + DAT_EP_FIELD_EP_ATTR_QOS | + DAT_EP_FIELD_EP_ATTR_REQUEST_COMPLETION_FLAGS | + DAT_EP_FIELD_EP_ATTR_RECV_COMPLETION_FLAGS | + DAT_EP_FIELD_EP_ATTR_MAX_RECV_DTOS | + DAT_EP_FIELD_EP_ATTR_MAX_REQUEST_DTOS | + DAT_EP_FIELD_EP_ATTR_MAX_RECV_IOV | + DAT_EP_FIELD_EP_ATTR_MAX_REQUEST_IOV )) && + ( ep->param.ep_state != DAT_EP_STATE_UNCONNECTED && + ep->param.ep_state != DAT_EP_STATE_RESERVED && + ep->param.ep_state != DAT_EP_STATE_TENTATIVE_CONNECTION_PENDING ) ) + { + dat_status = DAT_ERROR (DAT_INVALID_STATE, dapls_ep_state_subtype (ep)); + goto bail; + } + + /* + * Validate handles being modified + */ + if ( ep_param_mask & DAT_EP_FIELD_PZ_HANDLE ) + { + if (ep_param->pz_handle != NULL && + DAPL_BAD_HANDLE (ep_param->pz_handle, DAPL_MAGIC_PZ) ) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER, DAT_INVALID_ARG3); + goto bail; + } + } + + if ( ep_param_mask & DAT_EP_FIELD_RECV_EVD_HANDLE ) + { + if (ep_param->recv_evd_handle != NULL && + (DAPL_BAD_HANDLE (ep_param->recv_evd_handle, DAPL_MAGIC_EVD) || + ! ((DAPL_EVD *)ep_param->recv_evd_handle)->evd_flags & DAT_EVD_DTO_FLAG)) + + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER, DAT_INVALID_ARG3); + goto bail; + } + } + + if ( ep_param_mask & DAT_EP_FIELD_REQUEST_EVD_HANDLE ) + { + if (ep_param->request_evd_handle != NULL && + DAPL_BAD_HANDLE (ep_param->request_evd_handle, DAPL_MAGIC_EVD)) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER, DAT_INVALID_ARG3); + goto bail; + } + } + + if ( ep_param_mask & DAT_EP_FIELD_CONNECT_EVD_HANDLE ) + { + if (ep_param->connect_evd_handle != NULL && + DAPL_BAD_HANDLE (ep_param->connect_evd_handle, DAPL_MAGIC_EVD) && + ! (((DAPL_EVD *)ep_param->connect_evd_handle)->evd_flags & DAT_EVD_CONNECTION_FLAG) ) + + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER, DAT_INVALID_ARG3); + goto bail; + } + } + + /* + * Validate the attributes against the HCA limits + */ + ep_attr = ep->param.ep_attr; + + dapl_os_memzero (&ep_attr_limit, sizeof (DAT_EP_ATTR)); + dat_status = dapls_ib_query_hca (ia->hca_ptr, NULL, &ep_attr_limit, NULL); + if ( dat_status != DAT_SUCCESS ) + { + goto bail; + } + + ep_attr_request = ep_param->ep_attr; + + if ( ep_param_mask & DAT_EP_FIELD_EP_ATTR_SERVICE_TYPE ) + { + if ( ep_attr_request.service_type != DAT_SERVICE_TYPE_RC ) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER, DAT_INVALID_ARG3); + goto bail; + } + } + + if ( ep_param_mask & DAT_EP_FIELD_EP_ATTR_MAX_MESSAGE_SIZE ) + { + if ( ep_attr_request.max_mtu_size > ep_attr_limit.max_mtu_size) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER, DAT_INVALID_ARG3); + goto bail; + } + else + { + ep_attr.max_mtu_size = ep_attr_request.max_mtu_size; + } + } + + /* Do nothing if the DAT_EP_FIELD_EP_ATTR_MAX_RDMA_SIZE flag is */ + /* set. Each RDMA transport/provider may or may not have a limit */ + /* on the size of an RDMA DTO. For InfiniBand, this parameter is */ + /* validated in the implementation of the dapls_ib_qp_modify() */ + /* function. */ + /* */ + /* if ( ep_param_mask & DAT_EP_FIELD_EP_ATTR_MAX_RDMA_SIZE ) */ + /* { */ + /* */ + /* } */ + + if ( ep_param_mask & DAT_EP_FIELD_EP_ATTR_QOS ) + { + /* Do nothing, not defined in the spec yet */ + } + + if ( ep_param_mask & DAT_EP_FIELD_EP_ATTR_RECV_COMPLETION_FLAGS ) + { + dat_status = dapl_ep_check_recv_completion_flags ( + ep_attr_request.recv_completion_flags); + if ( dat_status != DAT_SUCCESS ) + + { + goto bail; + } + else + { + ep_attr.recv_completion_flags = + ep_attr_request.recv_completion_flags; + } + } + + if ( ep_param_mask & DAT_EP_FIELD_EP_ATTR_REQUEST_COMPLETION_FLAGS ) + { + dat_status = dapl_ep_check_request_completion_flags ( + ep_attr_request.request_completion_flags); + if ( dat_status != DAT_SUCCESS ) + { + goto bail; + } + else + { + ep_attr.request_completion_flags = + ep_attr_request.request_completion_flags; + } + } + + if ( ep_param_mask & DAT_EP_FIELD_EP_ATTR_MAX_RECV_DTOS ) + { + if ( ep_attr_request.max_recv_dtos > ep_attr_limit.max_recv_dtos || + ( ep_param->recv_evd_handle == DAT_HANDLE_NULL && + ( ep_attr_request.max_recv_dtos > 0 ) ) ) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER, DAT_INVALID_ARG3); + goto bail; + } + else + { + ep_attr.max_recv_dtos = ep_attr_request.max_recv_dtos; + } + } + + if ( ep_param_mask & DAT_EP_FIELD_EP_ATTR_MAX_REQUEST_DTOS ) + { + if ( ep_attr_request.max_request_dtos > ep_attr_limit.max_request_dtos || + ( ep_param->request_evd_handle == DAT_HANDLE_NULL && + ( ep_attr_request.max_request_dtos > 0 ) ) ) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER, DAT_INVALID_ARG3); + goto bail; + } + else + { + ep_attr.max_request_dtos = ep_attr_request.max_request_dtos; + } + } + + if ( ep_param_mask & DAT_EP_FIELD_EP_ATTR_MAX_RECV_IOV ) + { + if ( ep_attr_request.max_recv_iov > ep_attr_limit.max_recv_iov) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER, DAT_INVALID_ARG3); + goto bail; + } + else + { + ep_attr.max_recv_iov = ep_attr_request.max_recv_iov; + } + } + + if ( ep_param_mask & DAT_EP_FIELD_EP_ATTR_MAX_REQUEST_IOV ) + { + if ( ep_attr_request.max_request_iov > ep_attr_limit.max_request_iov) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER, DAT_INVALID_ARG3); + goto bail; + } + else + { + ep_attr.max_request_iov = ep_attr_request.max_request_iov; + } + } + + *ia_ptr = ia; + *ep_ptr = ep; + *ep_attr_ptr = ep_attr; + +bail: + return dat_status; +} + + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ + diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_post_rdma_read.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_post_rdma_read.c new file mode 100644 index 00000000..8d5b8d20 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_post_rdma_read.c @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ep_post_rdma_read.c + * + * PURPOSE: Endpoint management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 5 + * + * $Id$ + **********************************************************************/ + +#include "dapl_ep_util.h" + +/* + * dapl_ep_post_rdma_read + * + * DAPL Requirements Version xxx, 6.5.12 + * + * Request the xfer of all data specified by the remote_iov over the + * connection of ep handle Endpint into the local_iov + * + * Input: + * ep_handle + * num_segments + * local_iov + * user_cookie + * remote_iov + * completion_flags + * + * Output: + * None. + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + * DAT_INVALID_STATE + * DAT_LENGTH_ERROR + * DAT_PROTECTION_VIOLATION + * DAT_PRIVILEGES_VIOLATION + */ +DAT_RETURN +dapl_ep_post_rdma_read ( + IN DAT_EP_HANDLE ep_handle, + IN DAT_COUNT num_segments, + IN DAT_LMR_TRIPLET *local_iov, + IN DAT_DTO_COOKIE user_cookie, + IN const DAT_RMR_TRIPLET *remote_iov, + IN DAT_COMPLETION_FLAGS completion_flags) +{ + + DAT_RETURN dat_status; + + dapl_dbg_log (DAPL_DBG_TYPE_API, + "dapl_ep_post_rdma_read (%p, %d, %p, %p, %p, %x)\n", + ep_handle, + num_segments, + local_iov, + user_cookie.as_64, + remote_iov, + completion_flags); + DAPL_CNTR(DCNT_POST_RDMA_READ); + + dat_status = dapl_ep_post_send_req(ep_handle, + num_segments, + local_iov, + user_cookie, + remote_iov, + completion_flags, + DAPL_DTO_TYPE_RDMA_READ, + OP_RDMA_READ); + + dapl_dbg_log (DAPL_DBG_TYPE_RTN, + "dapl_ep_post_rdma_read () returns 0x%x", + dat_status); + + return dat_status; +} + diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_post_rdma_write.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_post_rdma_write.c new file mode 100644 index 00000000..3e92b299 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_post_rdma_write.c @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ep_post_rdma_write.c + * + * PURPOSE: Endpoint management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 5 + * + * $Id$ + **********************************************************************/ + +#include "dapl_ep_util.h" + +/* + * dapl_ep_post_rdma_write + * + * DAPL Requirements Version xxx, 6.5.13 + * + * Request the xfer of all data specified by the local_iov over the + * connection of ep handle Endpint into the remote_iov + * + * Input: + * ep_handle + * num_segments + * local_iov + * user_cookie + * remote_iov + * compltion_flags + * + * Output: + * None. + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + * DAT_INVALID_STATE + * DAT_LENGTH_ERROR + * DAT_PROTECTION_VIOLATION + * DAT_PRIVILEGES_VIOLATION + */ +DAT_RETURN +dapl_ep_post_rdma_write ( + IN DAT_EP_HANDLE ep_handle, + IN DAT_COUNT num_segments, + IN DAT_LMR_TRIPLET *local_iov, + IN DAT_DTO_COOKIE user_cookie, + IN const DAT_RMR_TRIPLET *remote_iov, + IN DAT_COMPLETION_FLAGS completion_flags ) +{ + DAT_RETURN dat_status; + + dapl_dbg_log (DAPL_DBG_TYPE_API, + "dapl_ep_post_rdma_write (%p, %d, %p, %#I64x, %p, %x)\n", + ep_handle, + num_segments, + local_iov, + user_cookie.as_64, + remote_iov, + completion_flags); + DAPL_CNTR(DCNT_POST_RDMA_WRITE); + + dat_status = dapl_ep_post_send_req(ep_handle, + num_segments, + local_iov, + user_cookie, + remote_iov, + completion_flags, + DAPL_DTO_TYPE_RDMA_WRITE, + OP_RDMA_WRITE); + if (dat_status) + { + dapl_dbg_log (DAPL_DBG_TYPE_RTN, + "dapl_ep_post_rdma_write () returns 0x%x", dat_status); + } + + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_post_recv.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_post_recv.c new file mode 100644 index 00000000..cbde689a --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_post_recv.c @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ep_post_recv.c + * + * PURPOSE: Endpoint management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 5 + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_cookie.h" +#include "dapl_adapter_util.h" + +/* + * dapl_ep_post_recv + * + * DAPL Requirements Version xxx, 6.5.11 + * + * Request to receive data over the connection of ep handle into + * local_iov + * + * Input: + * ep_handle + * num_segments + * local_iov + * user_cookie + * completion_flags + * + * Output: + * None. + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + * DAT_INVALID_STATE + * DAT_PROTECTION_VIOLATION + * DAT_PROVILEGES_VIOLATION + */ +DAT_RETURN +dapl_ep_post_recv ( + IN DAT_EP_HANDLE ep_handle, + IN DAT_COUNT num_segments, + IN DAT_LMR_TRIPLET *local_iov, + IN DAT_DTO_COOKIE user_cookie, + IN DAT_COMPLETION_FLAGS completion_flags ) +{ + DAPL_EP *ep_ptr; + DAPL_COOKIE *cookie; + DAT_RETURN dat_status; + + dapl_dbg_log (DAPL_DBG_TYPE_API, + "dapl_ep_post_recv (%p, %d, %p, %P, %x)\n", + ep_handle, + num_segments, + local_iov, + user_cookie.as_64, + completion_flags); + DAPL_CNTR (DCNT_POST_RECV); + + if ( DAPL_BAD_HANDLE (ep_handle, DAPL_MAGIC_EP) ) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP); + goto bail; + } + + ep_ptr = (DAPL_EP *) ep_handle; + + /* + * Synchronization ok since this buffer is only used for receive + * requests, which aren't allowed to race with each other. + */ + dat_status = dapls_dto_cookie_alloc (&ep_ptr->recv_buffer, + DAPL_DTO_TYPE_RECV, + user_cookie, + &cookie); + if ( DAT_SUCCESS != dat_status) + { + goto bail; + } + + /* + * Take reference before posting to avoid race conditions with + * completions + */ + dapl_os_atomic_inc (&ep_ptr->recv_count); + + /* + * Invoke provider specific routine to post DTO + */ + dat_status = dapls_ib_post_recv (ep_ptr, cookie, num_segments, local_iov); + + if ( dat_status != DAT_SUCCESS ) + { + dapl_os_atomic_dec (&ep_ptr->recv_count); + dapls_cookie_dealloc (&ep_ptr->recv_buffer, cookie); + } + +bail: + if (dat_status) + { + dapl_dbg_log (DAPL_DBG_TYPE_RTN, "dapl_ep_post_recv () returns 0x%x\n", + dat_status); + } + + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_post_send.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_post_send.c new file mode 100644 index 00000000..335cc4b6 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_post_send.c @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ep_post_send.c + * + * PURPOSE: Endpoint management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 5 + * + * $Id$ + **********************************************************************/ + +#include "dapl_ep_util.h" + +/* + * dapl_ep_post_send + * + * DAPL Requirements Version xxx, 6.5.10 + * + * Request a transfer of all the data from the local_iov over + * the connection of the ep handle Endpoint to the remote side. + * + * Input: + * ep_handle + * num_segments + * local_iov + * user_cookie + * completion_flags + * + * Output: + * None + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + * DAT_INVALID_STATE + * DAT_PROTECTION_VIOLATION + * DAT_PRIVILEGES_VIOLATION + */ +DAT_RETURN +dapl_ep_post_send ( + IN DAT_EP_HANDLE ep_handle, + IN DAT_COUNT num_segments, + IN DAT_LMR_TRIPLET *local_iov, + IN DAT_DTO_COOKIE user_cookie, + IN DAT_COMPLETION_FLAGS completion_flags ) +{ + DAT_RMR_TRIPLET remote_iov = {0,0,0,0}; + DAT_RETURN dat_status; + + dapl_dbg_log (DAPL_DBG_TYPE_API, + "dapl_ep_post_send (%p, %d, %p, %I64x, %x)\n", + ep_handle, + num_segments, + local_iov, + user_cookie.as_64, + completion_flags); + DAPL_CNTR(DCNT_POST_SEND); + + dat_status = dapl_ep_post_send_req(ep_handle, + num_segments, + local_iov, + user_cookie, + &remote_iov, + completion_flags, + DAPL_DTO_TYPE_SEND, + OP_SEND); + if (dat_status) + { + dapl_dbg_log (DAPL_DBG_TYPE_RTN, "dapl_ep_post_send () returns 0x%x\n", + dat_status); + } + + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_query.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_query.c new file mode 100644 index 00000000..77a80103 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_query.c @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ep_query.c + * + * PURPOSE: Endpoint management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 5 + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_adapter_util.h" + +/* + * dapl_ep_query + * + * DAPL Requirements Version xxx, 6.5.5 + * + * Provide the consumer parameters, including attributes and status of + * the Endpoint. + * + * Input: + * ep_handle + * ep_param_mask + * + * Output: + * ep_param + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + */ +DAT_RETURN +dapl_ep_query ( + IN DAT_EP_HANDLE ep_handle, + IN DAT_EP_PARAM_MASK ep_param_mask, + OUT DAT_EP_PARAM *ep_param ) +{ + DAPL_EP *ep_ptr; + DAT_RETURN dat_status; + + dapl_dbg_log (DAPL_DBG_TYPE_API, + "dapl_ep_query (%p, %x, %p)\n", + ep_handle, + ep_param_mask, + ep_param); + + dat_status = DAT_SUCCESS; + ep_ptr = (DAPL_EP *) ep_handle; + + /* + * Verify parameter & state + */ + if ( DAPL_BAD_HANDLE(ep_ptr, DAPL_MAGIC_EP ) ) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE,DAT_INVALID_HANDLE_EP); + goto bail; + } + + if ( ep_param == NULL) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER,DAT_INVALID_ARG3); + goto bail; + } + + /* + * Fill in according to user request + * + * N.B. Just slam all values into the user structure, there + * is nothing to be gained by checking for each bit. + */ + if ( ep_param_mask & DAT_EP_FIELD_ALL ) + { + if ( ep_ptr->param.ep_state == DAT_EP_STATE_CONNECTED ) + { + /* obtain the remote IP address */ + dat_status = dapls_ib_cm_remote_addr ((DAT_HANDLE)ep_handle, + NULL, + &ep_ptr->remote_ia_address ); + } + ep_ptr->param.remote_ia_address_ptr = + (DAT_IA_ADDRESS_PTR) &ep_ptr->remote_ia_address; + *ep_param = ep_ptr->param; + } + + bail: + return dat_status; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ + diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_reset.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_reset.c new file mode 100644 index 00000000..31bb1103 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_reset.c @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ep_reset.c + * + * PURPOSE: Endpoint management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 5.13 + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_ia_util.h" +#include "dapl_ep_util.h" +#include "dapl_adapter_util.h" +#include "dapl_ring_buffer_util.h" + +/* + * dapl_ep_reset + * + * DAPL Requirements Version 1.1, 6.5.13 + * + * Reset the QP attached to this Endpoint, transitioning back to the + * INIT state + * + * Input: + * ep_handle + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + * DAT_INVALID_STATE + */ +DAT_RETURN +dapl_ep_reset ( + IN DAT_EP_HANDLE ep_handle) +{ + DAPL_EP *ep_ptr; + DAT_RETURN dat_status; + + dat_status = DAT_SUCCESS; + + ep_ptr = (DAPL_EP *) ep_handle; + + /* + * Verify parameter & state + */ + if ( DAPL_BAD_HANDLE (ep_ptr, DAPL_MAGIC_EP ) ) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE,DAT_INVALID_HANDLE_EP); + goto bail; + } + + if ( ep_ptr->param.ep_state != DAT_EP_STATE_UNCONNECTED + && ep_ptr->param.ep_state != DAT_EP_STATE_DISCONNECTED ) + { + dat_status = DAT_ERROR (DAT_INVALID_STATE,dapls_ep_state_subtype (ep_ptr)); + goto bail; + } + + if ( ep_ptr->param.ep_state == DAT_EP_STATE_DISCONNECTED ) + { + dat_status = dapls_ib_reinit_ep ( ep_ptr ); + ep_ptr->param.ep_state = DAT_EP_STATE_UNCONNECTED; + } + + bail: + return dat_status; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_util.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_util.c new file mode 100644 index 00000000..0ef2ff50 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_util.c @@ -0,0 +1,559 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ep_util.c + * + * PURPOSE: Manage EP Info structure + * + * $Id$ + **********************************************************************/ + +#include "dapl_ep_util.h" +#include "dapl_ring_buffer_util.h" +#include "dapl_cookie.h" +#include "dapl_adapter_util.h" +#include "dapl_evd_util.h" + +/* + * Local definitions + */ +/* + * Default number of I/O operations on an end point + */ +#define IB_IO_DEFAULT 16 + +/* + * Default number of scatter/gather entries available to a single + * post send/recv + */ +#define IB_IOV_DEFAULT 4 + +/* + * Default number of RDMA operations in progress at a time + */ +#define IB_RDMA_DEFAULT 4 + +extern void dapli_ep_default_attrs ( + IN DAPL_EP *ep_ptr ); + + +/* + * dapl_ep_alloc + * + * alloc and initialize an EP INFO struct + * + * Input: + * IA INFO struct ptr + * + * Output: + * ep_ptr + * + * Returns: + * none + * + */ +DAPL_EP * +dapl_ep_alloc ( + IN DAPL_IA *ia_ptr, + IN const DAT_EP_ATTR *ep_attr ) +{ + DAPL_EP *ep_ptr; + + /* Allocate EP */ + ep_ptr = (DAPL_EP *)dapl_os_alloc (sizeof (DAPL_EP) + sizeof (DAT_SOCK_ADDR)); + if ( ep_ptr == NULL ) + { + goto bail; + } + + /* zero the structure */ + dapl_os_memzero (ep_ptr, sizeof (DAPL_EP)+ sizeof (DAT_SOCK_ADDR)); + + /* + * initialize the header + */ + ep_ptr->header.provider = ia_ptr->header.provider; + ep_ptr->header.magic = DAPL_MAGIC_EP; + ep_ptr->header.handle_type = DAT_HANDLE_TYPE_EP; + ep_ptr->header.owner_ia = ia_ptr; + ep_ptr->header.user_context.as_64 = 0; + ep_ptr->header.user_context.as_ptr = NULL; + + dapl_llist_init_entry (&ep_ptr->header.ia_list_entry); + dapl_os_lock_init (&ep_ptr->header.lock); + + /* + * Initialize the body + */ + dapl_os_memzero (&ep_ptr->param, sizeof (DAT_EP_PARAM)); + ep_ptr->param.ep_state = DAT_EP_STATE_UNCONNECTED; + ep_ptr->param.local_ia_address_ptr = + (DAT_IA_ADDRESS_PTR)&ia_ptr->hca_ptr->hca_address; + /* Set the remote address pointer to the end of the EP struct */ + ep_ptr->param.remote_ia_address_ptr = (DAT_IA_ADDRESS_PTR)(ep_ptr + 1); + + /* + * Set up default parameters if the user passed in a NULL + */ + if ( ep_attr == NULL ) + { + dapli_ep_default_attrs (ep_ptr); + } + else + { + ep_ptr->param.ep_attr = *ep_attr; + } + + /* + * IBM OS API specific fields + */ + ep_ptr->qp_handle = IB_INVALID_HANDLE; + ep_ptr->qpn = 0; + ep_ptr->qp_state = DAPL_QP_STATE_UNATTACHED; + cl_memclr( &ep_ptr->cm_handle, sizeof(ib_cm_handle_t) ); + ep_ptr->cm_handle.cid = 0xFFFFFFFF; + + ep_ptr->req_count = 0; + ep_ptr->recv_count = 0; + + ep_ptr->recv_discreq = DAT_FALSE; + ep_ptr->sent_discreq = DAT_FALSE; + + /* allocate viol event queue size = max_recv_dtos / 2 */ + if (DAT_SUCCESS != dapls_rbuf_alloc ( + &ep_ptr->viol_event_queue, + ep_ptr->param.ep_attr.max_recv_dtos / 2) ) + { + dapl_ep_dealloc (ep_ptr); + ep_ptr = NULL; + goto bail; + } + ep_ptr->viol_order = DAT_FALSE; + + if ( DAT_SUCCESS != dapls_cb_create ( + &ep_ptr->req_buffer, + ep_ptr, + ep_ptr->param.ep_attr.max_request_dtos) ) + { + dapl_ep_dealloc (ep_ptr); + ep_ptr = NULL; + goto bail; + } + + if ( DAT_SUCCESS != dapls_cb_create ( + &ep_ptr->recv_buffer, + ep_ptr, + ep_ptr->param.ep_attr.max_recv_dtos) ) + { + dapl_ep_dealloc (ep_ptr); + ep_ptr = NULL; + goto bail; + } + + ep_ptr->recv_iov_num = ep_ptr->param.ep_attr.max_recv_iov; + ep_ptr->send_iov_num = ep_ptr->param.ep_attr.max_request_iov; + + ep_ptr->recv_iov = dapl_os_alloc ( + ep_ptr->recv_iov_num * sizeof (ib_data_segment_t)); + + if ( NULL == ep_ptr->recv_iov ) + { + dapl_ep_dealloc (ep_ptr); + ep_ptr = NULL; + goto bail; + } + + ep_ptr->send_iov = dapl_os_alloc ( + ep_ptr->send_iov_num * sizeof (ib_data_segment_t)); + + if ( NULL == ep_ptr->send_iov ) + { + dapl_ep_dealloc (ep_ptr); + ep_ptr = NULL; + goto bail; + } + + dapls_io_trc_alloc (ep_ptr); + +bail: + return ep_ptr; +} + + +/* + * dapl_ep_dealloc + * + * Free the passed in EP structure. + * + * Input: + * entry point pointer + * + * Output: + * none + * + * Returns: + * none + * + */ +void +dapl_ep_dealloc ( + IN DAPL_EP *ep_ptr ) +{ + dapl_os_assert (ep_ptr->header.magic == DAPL_MAGIC_EP); + + ep_ptr->header.magic = DAPL_MAGIC_INVALID; /* reset magic to prevent reuse */ + + dapls_cb_free ( &ep_ptr->req_buffer ); + dapls_cb_free ( &ep_ptr->recv_buffer ); + + if ( NULL != ep_ptr->recv_iov ) + { + dapl_os_free (ep_ptr->recv_iov, ep_ptr->recv_iov_num * sizeof (ib_data_segment_t)); + } + + if ( NULL != ep_ptr->send_iov ) + { + dapl_os_free (ep_ptr->send_iov, ep_ptr->send_iov_num * sizeof (ib_data_segment_t)); + } + + if ( NULL != ep_ptr->cxn_timer ) + { + dapl_os_free ( ep_ptr->cxn_timer, sizeof ( DAPL_OS_TIMER ) ); + } + + dapl_os_free (ep_ptr, sizeof (DAPL_EP) + sizeof (DAT_SOCK_ADDR) ); +} + + +/* + * dapl_ep_default_attrs + * + * Set default values in the parameter fields + * + * Input: + * entry point pointer + * + * Output: + * none + * + * Returns: + * none + * + */ +void +dapli_ep_default_attrs ( + IN DAPL_EP *ep_ptr ) +{ + DAT_EP_ATTR *ep_attr; + + ep_attr = &ep_ptr->param.ep_attr; + /* Set up defaults */ + dapl_os_memzero (ep_attr, sizeof (DAT_EP_ATTR)); + + /* mtu and rdma sizes fixed in IB as per IBTA 1.1, 9.4.3, 9.4.4, 9.7.7. */ + ep_attr->max_mtu_size = 0x80000000; + ep_attr->max_rdma_size = 0x80000000; + + ep_attr->qos = DAT_QOS_BEST_EFFORT; + ep_attr->service_type = DAT_SERVICE_TYPE_RC; + ep_attr->max_recv_dtos = IB_IO_DEFAULT; + ep_attr->max_request_dtos = IB_IO_DEFAULT; + ep_attr->max_recv_iov = IB_IOV_DEFAULT; + ep_attr->max_request_iov = IB_IOV_DEFAULT; + ep_attr->max_rdma_read_in = IB_RDMA_DEFAULT; + ep_attr->max_rdma_read_out= IB_RDMA_DEFAULT; + + /* + * Configure the EP as a standard completion type, which will be + * used by the EVDs. A threshold of 1 is the default state of an + * EVD. + */ + ep_attr->request_completion_flags = DAT_COMPLETION_EVD_THRESHOLD_FLAG; + ep_attr->recv_completion_flags = DAT_COMPLETION_EVD_THRESHOLD_FLAG; + /* + * Unspecified defaults: + * - ep_privileges: No RDMA capabilities + * - num_transport_specific_params: none + * - transport_specific_params: none + * - num_provider_specific_params: 0 + * - provider_specific_params: 0 + */ + + return; +} + + +DAT_RETURN +dapl_ep_check_recv_completion_flags ( + DAT_COMPLETION_FLAGS flags ) +{ + + /* + * InfiniBand will not allow signal suppression for RECV completions, + * see the 1.0.1 spec section 10.7.3.1, 10.8.6. + * N.B. SIGNALLED has a different meaning in dapl than it does + * in IB; IB SIGNALLED is the same as DAPL SUPPRESS. DAPL + * SIGNALLED simply means the user will not get awakened when + * an EVD completes, even though the dapl handler is invoked. + */ + + if (flags & DAT_COMPLETION_SUPPRESS_FLAG) + { + return DAT_INVALID_PARAMETER; + } + + return DAT_SUCCESS; +} + +DAT_RETURN +dapl_ep_check_request_completion_flags ( + DAT_COMPLETION_FLAGS flags ) +{ + UNREFERENCED_PARAMETER(flags); + return DAT_SUCCESS; +} + + +DAT_RETURN +dapl_ep_post_send_req ( + IN DAT_EP_HANDLE ep_handle, + IN DAT_COUNT num_segments, + IN DAT_LMR_TRIPLET *local_iov, + IN DAT_DTO_COOKIE user_cookie, + IN const DAT_RMR_TRIPLET *remote_iov, + IN DAT_COMPLETION_FLAGS completion_flags, + IN DAPL_DTO_TYPE dto_type, + IN ib_send_op_type_t op_type) +{ + DAPL_EP *ep_ptr; + DAPL_COOKIE *cookie = NULL; + DAT_RETURN dat_status; + + if ( DAPL_BAD_HANDLE (ep_handle, DAPL_MAGIC_EP) ) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE,DAT_INVALID_HANDLE_EP); + goto bail; + } + + ep_ptr = (DAPL_EP *) ep_handle; + + /* + * Synchronization ok since this buffer is only used for send + * requests, which aren't allowed to race with each other. + * Only if completion is expected + */ + if (!(DAT_COMPLETION_SUPPRESS_FLAG & completion_flags)) + { + dat_status = dapls_dto_cookie_alloc ( + &ep_ptr->req_buffer, + dto_type, + user_cookie, + &cookie ); + if ( dat_status != DAT_SUCCESS ) + { + goto bail; + } + dapl_os_atomic_inc (&ep_ptr->req_count); + } + + /* + * Invoke provider specific routine to post DTO + */ + dat_status = dapls_ib_post_send ( ep_ptr, + op_type, + cookie, + num_segments, + local_iov, + remote_iov, + completion_flags ); + + if ( dat_status != DAT_SUCCESS ) + { + if ( cookie != NULL ) + { + dapls_cookie_dealloc (&ep_ptr->req_buffer, cookie); + dapl_os_atomic_dec (&ep_ptr->req_count); + } + } + + bail: + return dat_status; +} + + +/* + * dapli_ep_timeout + * + * If this routine is invoked before a connection occurs, generate an + * event + */ +void +dapls_ep_timeout ( + void *arg ) +{ + DAPL_EP *ep_ptr; + ib_cm_events_t ib_cm_event; + + dapl_dbg_log (DAPL_DBG_TYPE_CM, "--> dapls_ep_timeout! ep %lx\n", arg); + + ep_ptr = (DAPL_EP *)arg; + + /* reset the EP state */ + ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECTED; + + /* Clean up the EP and put the underlying QP into the ERROR state. + * The disconnect_clean interface requires the provided dependent + *cm event number. + */ + ib_cm_event = dapls_ib_get_cm_event (DAT_CONNECTION_EVENT_DISCONNECTED); + dapls_ib_disconnect_clean ( ep_ptr, + DAT_TRUE, + ib_cm_event ); + + (void) dapls_evd_post_connection_event ( + (DAPL_EVD *)ep_ptr->param.connect_evd_handle, + DAT_CONNECTION_EVENT_TIMED_OUT, + (DAT_HANDLE) ep_ptr, + 0, + 0); +} + + +/* + * dapls_ep_state_subtype + * + * Return the INVALID_STATE connection subtype associated with an + * INVALID_STATE on an EP. Strictly for error reporting. + */ +DAT_RETURN_SUBTYPE +dapls_ep_state_subtype( + IN DAPL_EP *ep_ptr ) +{ + DAT_RETURN_SUBTYPE dat_status; + + switch ( ep_ptr->param.ep_state ) + { + case DAT_EP_STATE_UNCONNECTED: + { + dat_status = DAT_INVALID_STATE_EP_UNCONNECTED; + break; + } + case DAT_EP_STATE_RESERVED: + { + dat_status = DAT_INVALID_STATE_EP_RESERVED; + break; + } + case DAT_EP_STATE_PASSIVE_CONNECTION_PENDING: + { + dat_status = DAT_INVALID_STATE_EP_PASSCONNPENDING; + break; + } + case DAT_EP_STATE_ACTIVE_CONNECTION_PENDING: + { + dat_status = DAT_INVALID_STATE_EP_ACTCONNPENDING; + break; + } + case DAT_EP_STATE_TENTATIVE_CONNECTION_PENDING: + { + dat_status = DAT_INVALID_STATE_EP_TENTCONNPENDING; + break; + } + case DAT_EP_STATE_CONNECTED: + { + dat_status = DAT_INVALID_STATE_EP_CONNECTED; + break; + } + case DAT_EP_STATE_DISCONNECT_PENDING: + { + dat_status = DAT_INVALID_STATE_EP_DISCPENDING; + break; + } + case DAT_EP_STATE_DISCONNECTED: + { + dat_status = DAT_INVALID_STATE_EP_DISCONNECTED; + break; + } + case DAT_EP_STATE_COMPLETION_PENDING: + { + dat_status = DAT_INVALID_STATE_EP_COMPLPENDING; + break; + } + + default: + { + dat_status = 0; + break; + } + } + + return dat_status; +} + +#ifdef DAPL_DBG_IO_TRC +/* allocate trace buffer */ +void +dapls_io_trc_alloc ( + DAPL_EP *ep_ptr) +{ + DAT_RETURN dat_status; + int i; + struct io_buf_track *ibt; + + ep_ptr->ibt_dumped = 0; /* bool to control how often we print */ + dat_status = dapls_rbuf_alloc (&ep_ptr->ibt_queue, DBG_IO_TRC_QLEN); + if (dat_status != DAT_SUCCESS) + { + goto bail; + } + ibt = (struct io_buf_track *)dapl_os_alloc (sizeof (struct io_buf_track) * DBG_IO_TRC_QLEN); + + if (dat_status != DAT_SUCCESS) + { + dapls_rbuf_destroy (&ep_ptr->ibt_queue); + goto bail; + } + ep_ptr->ibt_base = ibt; + dapl_os_memzero (ibt, sizeof (struct io_buf_track) * DBG_IO_TRC_QLEN); + + /* add events to free event queue */ + for (i = 0; i < DBG_IO_TRC_QLEN; i++) + { + dapls_rbuf_add (&ep_ptr->ibt_queue, ibt++); + } +bail: + return; +} +#endif /* DAPL_DBG_IO_TRC */ + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_util.h b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_util.h new file mode 100644 index 00000000..a1675221 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ep_util.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dapl_ep_util.h + * + * PURPOSE: Utility defs & routines for the EP data structure + * + * $Id$ + * + **********************************************************************/ + +#ifndef _DAPL_EP_UTIL_H_ +#define _DAPL_EP_UTIL_H_ + +#include "dapl.h" +#include "dapl_adapter_util.h" + +/* function prototypes */ + +extern DAPL_EP * +dapl_ep_alloc ( + IN DAPL_IA *ia, + IN const DAT_EP_ATTR *ep_attr ); + +extern void +dapl_ep_dealloc ( + IN DAPL_EP *ep_ptr ); + +extern DAT_RETURN +dapl_ep_check_recv_completion_flags ( + DAT_COMPLETION_FLAGS flags ); + +extern DAT_RETURN +dapl_ep_check_request_completion_flags ( + DAT_COMPLETION_FLAGS flags ); + +extern DAT_RETURN +dapl_ep_post_send_req ( + IN DAT_EP_HANDLE ep_handle, + IN DAT_COUNT num_segments, + IN DAT_LMR_TRIPLET *local_iov, + IN DAT_DTO_COOKIE user_cookie, + IN const DAT_RMR_TRIPLET *remote_iov, + IN DAT_COMPLETION_FLAGS completion_flags, + IN DAPL_DTO_TYPE dto_type, + IN ib_send_op_type_t op_type ); + +void dapls_ep_timeout (void *arg ); + +DAT_RETURN_SUBTYPE +dapls_ep_state_subtype( + IN DAPL_EP *ep_ptr ); + +#endif /* _DAPL_EP_UTIL_H_ */ diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_clear_unwaitable.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_clear_unwaitable.c new file mode 100644 index 00000000..eeda8a24 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_clear_unwaitable.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_evd_clear_unwaitable.c + * + * PURPOSE: EVENT management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 3.4.8 + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" + +/* + * dapl_evd_clear_unwaitable + * + * DAPL Requirements Version 1.1, 6.3.4.8 + * + * Transition the Event Dispatcher into a waitable state + * + * Input: + * evd_handle + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + */ +DAT_RETURN +dapl_evd_clear_unwaitable ( + IN DAT_EVD_HANDLE evd_handle ) +{ + DAPL_EVD *evd_ptr; + DAT_RETURN dat_status; + + evd_ptr = (DAPL_EVD *)evd_handle; + dat_status = DAT_SUCCESS; + + if ( DAPL_BAD_HANDLE (evd_handle, DAPL_MAGIC_EVD) ) + + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE,0); + goto bail; + } + dapl_os_lock ( &evd_ptr->header.lock ); + evd_ptr->evd_waitable = DAT_TRUE; + dapl_os_unlock ( &evd_ptr->header.lock ); + + dat_status = DAT_SUCCESS; + +bail: + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_connection_callb.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_connection_callb.c new file mode 100644 index 00000000..1510ad09 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_connection_callb.c @@ -0,0 +1,263 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_evd_connection_callback.c + * + * PURPOSE: implements connection callbacks + * + * Description: Accepts asynchronous callbacks from the Communications Manager + * for EVDs that have been specified as the connection_evd. + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_evd_util.h" +#include "dapl_ep_util.h" +#include "dapl_timer_util.h" +#include "dapl_ring_buffer_util.h" + + +/* + * dapl_evd_connection_callback + * + * Connection callback function for ACTIVE connection requests; callbacks + * generated by the Connection Manager in response to issuing a + * connect call. + * + * Input: + * ib_cm_handle, + * ib_cm_event + * private_data_ptr + * context (evd) + * cr_pp + * + * Output: + * None + * + */ + +void +dapl_evd_connection_callback ( + IN ib_cm_handle_t ib_cm_handle, + IN const ib_cm_events_t ib_cm_event, + IN const void *private_data_ptr, + IN const void *context) +{ + DAPL_EP *ep_ptr; + DAPL_EVD *evd_ptr; + DAPL_PRIVATE *prd_ptr; + DAT_EVENT_NUMBER dat_event_num; + DAT_RETURN dat_status; + int private_data_size; + + + dapl_dbg_log ( + DAPL_DBG_TYPE_CM | DAPL_DBG_TYPE_CALLBACK, + "--> dapl_evd_connection_callback: ctxt: %p event: %x cm_handle %d\n", + context, + ib_cm_event, + ib_cm_handle.cid); + DAPL_CNTR(DCNT_EVD_CONN_CALLBACK); + + /* + * Determine the type of handle passed back to us in the context + * and sort out key parameters. + */ + if ( context == NULL || ((DAPL_HEADER *)context)->magic != DAPL_MAGIC_EP) + { + return; + } + + /* + * Active side of the connection, context is an EP and + * PSP is irrelevant. + */ + ep_ptr = (DAPL_EP *) context; + evd_ptr = (DAPL_EVD *) ep_ptr->param.connect_evd_handle; + + prd_ptr = (DAPL_PRIVATE *)private_data_ptr; + private_data_size = 0; + /* + * All operations effect the EP, so lock it once and unlock + * when necessary + */ + dapl_os_lock (&ep_ptr->header.lock); + + /* + * If a connection timer has been set up on this EP, cancel it now + */ + if ( ep_ptr->cxn_timer != NULL ) + { + dapls_timer_cancel ( ep_ptr->cxn_timer ); + dapl_os_free ( ep_ptr->cxn_timer, sizeof ( DAPL_OS_TIMER ) ); + ep_ptr->cxn_timer = NULL; + } + + /* Obtain the event number from the provider layer */ + dat_event_num = dapls_ib_get_dat_event (ib_cm_event, DAT_TRUE); + + switch (dat_event_num) + { + case DAT_CONNECTION_EVENT_ESTABLISHED: + { + /* If we don't have an EP at this point we are very screwed + * up + */ + if ( ep_ptr->param.ep_state != DAT_EP_STATE_ACTIVE_CONNECTION_PENDING) + { + /* If someone pulled the plug on the connection, just + * exit + */ + dapl_os_unlock ( &ep_ptr->header.lock ); + dat_status = DAT_SUCCESS; + break; + } + ep_ptr->param.ep_state = DAT_EP_STATE_CONNECTED; + ep_ptr->cm_handle = ib_cm_handle; + if (prd_ptr == NULL) + { + private_data_size = 0; + } + else + { + private_data_size = + dapls_ib_private_data_size (prd_ptr, DAPL_PDATA_CONN_REP); + } + + if (private_data_size > 0) + { + /* copy in the private data */ + dapl_os_memcpy ( ep_ptr->private_data, + prd_ptr->private_data, + DAPL_MIN (private_data_size, DAPL_MAX_PRIVATE_DATA_SIZE)); + } + dapl_os_unlock (&ep_ptr->header.lock); + + break; + } + case DAT_CONNECTION_EVENT_DISCONNECTED: + { + /* + * EP is now fully disconnected; initiate any post processing + * to reset the underlying QP and get the EP ready for + * another connection + */ + ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECTED; + ep_ptr->recv_discreq = DAT_FALSE; + ep_ptr->sent_discreq = DAT_FALSE; + dapls_ib_disconnect_clean (ep_ptr, DAT_TRUE, ib_cm_event); + dapl_os_unlock (&ep_ptr->header.lock); + + break; + } + case DAT_CONNECTION_EVENT_PEER_REJECTED: + { + ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECTED; + dapls_ib_disconnect_clean (ep_ptr, DAT_TRUE, ib_cm_event); + dapl_os_unlock (&ep_ptr->header.lock); + + break; + } + case DAT_CONNECTION_EVENT_UNREACHABLE: + { + ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECTED; + dapls_ib_disconnect_clean (ep_ptr, DAT_TRUE, ib_cm_event); + dapl_os_unlock (&ep_ptr->header.lock); + + break; + } + case DAT_CONNECTION_EVENT_NON_PEER_REJECTED: + { + ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECTED; + dapls_ib_disconnect_clean (ep_ptr, DAT_TRUE, ib_cm_event); + dapl_os_unlock (&ep_ptr->header.lock); + + break; + } + case DAT_CONNECTION_EVENT_BROKEN: + { + dapl_os_lock ( &ep_ptr->header.lock ); + ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECTED; + dapls_ib_disconnect_clean (ep_ptr, DAT_FALSE, ib_cm_event); + dapl_os_unlock ( &ep_ptr->header.lock ); + + break; + } + case DAT_CONNECTION_REQUEST_EVENT: + default: + { + dapl_os_unlock (&ep_ptr->header.lock); + evd_ptr = NULL; + + dapl_os_assert (0); /* shouldn't happen */ + break; + } + } + + /* + * Post the event + * If the EP has been freed, the evd_ptr will be NULL + */ + if ( evd_ptr != NULL ) + { + dat_status = dapls_evd_post_connection_event ( + evd_ptr, + dat_event_num, + (DAT_HANDLE) ep_ptr, + private_data_size, /* 0 except for CONNECTED */ + ep_ptr->private_data ); + + if (dat_status != DAT_SUCCESS && + dat_event_num == DAT_CONNECTION_EVENT_ESTABLISHED) + { + /* We can't tell the user we are connected, something + * is wrong locally. Just kill the connection and + * reset the state to DISCONNECTED as we don't + * expect a callback on an ABRUPT disconnect. + */ + dapls_ib_disconnect (ep_ptr, DAT_CLOSE_ABRUPT_FLAG); + dapl_os_lock (&ep_ptr->header.lock); + ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECTED; + dapl_os_unlock (&ep_ptr->header.lock); + } + } + + dapl_dbg_log (DAPL_DBG_TYPE_CM | DAPL_DBG_TYPE_CALLBACK, + "dapl_evd_connection_callback () returns\n"); + +} + + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_cq_async_error_callb.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_cq_async_error_callb.c new file mode 100644 index 00000000..aba28eaf --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_cq_async_error_callb.c @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_evd_cq_async_error_callback.c + * + * PURPOSE: implements CQ async_callbacks from verbs + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_evd_util.h" + +/* + * dapl_evd_cq_async_error_callback + * + * The callback function registered with verbs for cq async errors + * + * Input: + * ib_hca_handle, + * error_ptr + * context (evd) + * + * Output: + * None + * + */ + +void +dapl_evd_cq_async_error_callback ( + IN ib_hca_handle_t ib_hca_handle, + IN ib_error_record_t *error_ptr, + IN void *context) + +{ + DAPL_EVD *async_evd; + DAPL_EVD *evd; + DAT_RETURN dat_status; + + dapl_dbg_log (DAPL_DBG_TYPE_CALLBACK | DAPL_DBG_TYPE_EXCEPTION , + "dapl_evd_cq_async_error_callback (%p, %p, %p)\n", + ib_hca_handle, + error_ptr, + context); + + if ( NULL == context ) + { + dapl_os_panic ("NULL == context\n"); + } + + evd = (DAPL_EVD *) context; + async_evd = evd->header.owner_ia->async_error_evd; + + dat_status = dapls_evd_post_async_error_event( + async_evd, + DAT_ASYNC_ERROR_EVD_OVERFLOW, + (DAT_IA_HANDLE) async_evd->header.owner_ia); + + + if ( dat_status != DAT_SUCCESS ) + { + dapl_os_panic ("async EVD overflow\n"); + } + + dapl_dbg_log (DAPL_DBG_TYPE_CALLBACK | DAPL_DBG_TYPE_EXCEPTION , + "dapl_evd_cq_async_error_callback () returns\n"); +} diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_create.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_create.c new file mode 100644 index 00000000..c0e16236 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_create.c @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_evd_create.c + * + * PURPOSE: EVENT management + * + * Description: Interfaces in this file are completely defined in + * the uDAPL 1.1 API, Chapter 6, section 3 + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_evd_util.h" + +/* + * dapl_evd_create + * + * DAPL Requirements Version xxx, 6.3.2.1 + * + * Create and instance of Event Dispatcher. + * + * Input: + * ia_handle + * cno_handle + * evd_min_qlen + * evd_flags + * + * Output: + * evd_handle + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + */ + +/* ** REVISIT ** + * + * Selecting the cqe handing domain must still be done. + * We *probably* want one per hca, but we could have one + * per provider or one per consumer. + */ +/* Note that if there already is a cq, it is not deleted + * even if it is not required. However, it will not be armed. + */ + +DAT_RETURN dapl_evd_create ( + IN DAT_IA_HANDLE ia_handle, + IN DAT_COUNT evd_min_qlen, + IN DAT_CNO_HANDLE cno_handle, + IN DAT_EVD_FLAGS evd_flags, + OUT DAT_EVD_HANDLE *evd_handle ) +{ + DAPL_IA *ia_ptr; + DAPL_EVD *evd_ptr; + DAPL_CNO *cno_ptr; + DAT_RETURN dat_status; + DAT_PROVIDER_ATTR provider_attr; + int i; + int j; + int flag_mask[6]; + + dapl_dbg_log (DAPL_DBG_TYPE_API, + "dapl_evd_create (%p, %d, %p, 0x%x, %p)\n", + ia_handle, + evd_min_qlen, + cno_handle, + evd_flags, + evd_handle); + DAPL_CNTR(DCNT_EVD_CREATE); + + ia_ptr = (DAPL_IA *)ia_handle; + cno_ptr = (DAPL_CNO *)cno_handle; + evd_ptr = NULL; + *evd_handle = NULL; + dat_status = DAT_SUCCESS; + + if (DAPL_BAD_HANDLE (ia_handle, DAPL_MAGIC_IA)) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE,DAT_INVALID_HANDLE_IA); + goto bail; + } + + if ( evd_min_qlen <= 0 ) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER,DAT_INVALID_ARG2); + goto bail; + } + if ( evd_min_qlen > ia_ptr->hca_ptr->ia_attr.max_evd_qlen ) + { + dat_status = DAT_ERROR (DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_TEVD); + goto bail; + } + + if (cno_handle != DAT_HANDLE_NULL + && DAPL_BAD_HANDLE(cno_handle, DAPL_MAGIC_CNO)) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE,DAT_INVALID_HANDLE_CNO); + goto bail; + } + + /* + * Check the merging attributes to ensure the combination of + * flags requested is supported. + */ + dapl_ia_query (ia_handle, NULL, + 0, NULL, + DAT_PROVIDER_FIELD_ALL, &provider_attr); + + /* Set up an array of flags to compare against; the EVD bits are + * a sparse array that need to be mapped to the merging flags + */ + flag_mask[0] = DAT_EVD_SOFTWARE_FLAG; + flag_mask[1] = DAT_EVD_CR_FLAG; + flag_mask[2] = DAT_EVD_DTO_FLAG; + flag_mask[3] = DAT_EVD_CONNECTION_FLAG; + flag_mask[4] = DAT_EVD_RMR_BIND_FLAG; + flag_mask[5] = DAT_EVD_ASYNC_FLAG; + + for (i = 0; i < 6; i++) + { + if (flag_mask[i] & evd_flags) + { + for (j = 0; j < 6; j++) + { + if (flag_mask[j] & evd_flags) + { + if (provider_attr.evd_stream_merging_supported[i][j] == DAT_FALSE) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER,DAT_INVALID_ARG4); + goto bail; + } + } + } /* end for j */ + } + } /* end for i */ + + dat_status = dapls_evd_internal_create (ia_ptr, + cno_ptr, + evd_min_qlen, + evd_flags, + &evd_ptr); + if (dat_status != DAT_SUCCESS) + { + goto bail; + } + + evd_ptr->evd_state = DAPL_EVD_STATE_OPEN; + + *evd_handle = (DAT_EVD_HANDLE) evd_ptr; + +bail: + if (dat_status != DAT_SUCCESS) + { + if (evd_ptr) + { + dapl_evd_free (evd_ptr); + } + } + + dapl_dbg_log (DAPL_DBG_TYPE_RTN, + "dapl_evd_create () returns 0x%x\n", + dat_status); + + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_dequeue.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_dequeue.c new file mode 100644 index 00000000..e1a80305 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_dequeue.c @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_evd_dequeue.c + * + * PURPOSE: Event Management + * + * Description: Interfaces in this file are completely described in + * the uDAPL 1.1 API, Chapter 6, section 3 + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_ring_buffer_util.h" +#include "dapl_evd_util.h" + +/* + * dapl_evd_dequeue + * + * DAPL Requirements Version xxx, 6.3.2.7 + * + * Remove first element from an event dispatcher + * + * Input: + * evd_handle + * + * Output: + * event + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + * DAT_INVALID_PARAMETER + * DAT_INVALID_STATE + * DAT_QUEUE_EMPTY + */ + +DAT_RETURN dapl_evd_dequeue ( + IN DAT_EVD_HANDLE evd_handle, + OUT DAT_EVENT *event) + +{ + DAPL_EVD *evd_ptr; + DAT_EVENT *local_event; + DAT_RETURN dat_status; + + dapl_dbg_log (DAPL_DBG_TYPE_EVENT_DQ, + "dapl_evd_dequeue (%p, %p)\n", + evd_handle, + event); + + DAPL_CNTR(DCNT_EVD_DEQUEUE); + + evd_ptr = (DAPL_EVD *)evd_handle; + dat_status = DAT_SUCCESS; + + if (DAPL_BAD_HANDLE (evd_handle, DAPL_MAGIC_EVD)) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE,0); + goto bail; + } + + if (event == NULL) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER,DAT_INVALID_ARG2); + goto bail; + } + + /* + * We need to dequeue under lock, as the IB OS Access API + * restricts us from having multiple threads in CQ poll, and the + * DAPL 1.1 API allows multiple threads in dat_evd_dequeue() + */ + dapl_os_lock ( &evd_ptr->header.lock ); + + /* + * Make sure there are no other waiters and the evd is active. + * Currently this means only the OPEN state is allowed. + */ + if (evd_ptr->evd_state != DAPL_EVD_STATE_OPEN || + evd_ptr->catastrophic_overflow) + { + dapl_os_unlock ( &evd_ptr->header.lock ); + dat_status = DAT_ERROR (DAT_INVALID_STATE,0); + goto bail; + } + + /* + * Try the EVD rbuf first; poll from the CQ only if that's empty. + * This keeps events in order if dat_evd_wait() has copied events + * from CQ to EVD. + */ + local_event = (DAT_EVENT *)dapls_rbuf_remove(&evd_ptr->pending_event_queue); + if (local_event != NULL) + { + *event = *local_event; + dat_status = dapls_rbuf_add (&evd_ptr->free_event_queue, local_event); + DAPL_CNTR(DCNT_EVD_DEQUEUE_FOUND); + } + else if (evd_ptr->ib_cq_handle != IB_INVALID_HANDLE) + { + dat_status = dapls_evd_cq_poll_to_event(evd_ptr, event); + DAPL_CNTR(DCNT_EVD_DEQUEUE_POLL); + } + else + { + dat_status = DAT_ERROR (DAT_QUEUE_EMPTY,0); + DAPL_CNTR(DCNT_EVD_DEQUEUE_NOT_FOUND); + } + + dapl_os_unlock ( &evd_ptr->header.lock ); + bail: + +#ifdef DAPL_DBG // XXX STAN + if ( DAPL_DBG_TYPE_EVENT_DQ & g_dapl_dbg_type ) + { + if ( dat_status && ((dat_status & 0xd0000) != 0xd0000) ) + { + dapl_log (DAPL_DBG_TYPE_EVENT_DQ, "dapl_evd_dequeue () returns 0x%x\n", + dat_status); + } + } +#endif + + return dat_status; +} + diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_disable.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_disable.c new file mode 100644 index 00000000..a35659c6 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_disable.c @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_evd_disable.c + * + * PURPOSE: EVENT management + * + * Description: Interfaces in this file are completely defined in + * the uDAPL 1.1 API, Chapter 6, section 3 + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" + +/* + * dapl_evd_disable + * + * DAPL Requirements Version xxx, 6.3.2.5 + * + * Modify the size fo the event queue of an Event Dispatcher + * + * Input: + * evd_handle + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + */ + +DAT_RETURN dapl_evd_disable ( + IN DAT_EVD_HANDLE evd_handle) +{ + DAPL_EVD *evd_ptr; + DAT_RETURN dat_status; + + evd_ptr = (DAPL_EVD *)evd_handle; + dat_status = DAT_SUCCESS; + + if ( DAPL_BAD_HANDLE (evd_handle, DAPL_MAGIC_EVD) ) + + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE,0); + goto bail; + } + + evd_ptr->evd_enabled = DAT_FALSE; + +bail: + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_dto_callb.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_dto_callb.c new file mode 100644 index 00000000..76a38a1f --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_dto_callb.c @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_evd_dto_callback.c + * + * PURPOSE: implements DTO callbacks from verbs + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_evd_util.h" +#include "dapl_cno_util.h" +#include "dapl_cookie.h" +#include "dapl_adapter_util.h" + +/********************************************************************* + * * + * Function Prototypes * + * * + *********************************************************************/ + + +/********************************************************************* + * * + * Function Definitions * + * * + *********************************************************************/ + +/* + * dapl_evd_dto_callback + * + * Input: + * hca_handle_in, + * cq_handle_in, + * user_context_cq_p + * + * Output: + * none + * + * This is invoked for both DTO and MW bind completions. Strictly + * speaking it is an event callback rather than just a DTO callback. + * + */ + +void +dapl_evd_dto_callback ( + IN ib_hca_handle_t hca_handle, + IN ib_cq_handle_t cq_handle, + IN void* user_context) +{ + DAPL_EVD *evd_ptr; + DAT_RETURN dat_status; + DAPL_EVD_STATE state; + + dapl_dbg_log (DAPL_DBG_TYPE_CALLBACK, + "dapl_evd_dto_callback(%p, %p, %p)\n", + hca_handle, + cq_handle, + user_context); + DAPL_CNTR(DCNT_EVD_DTO_CALLBACK); + + evd_ptr = (DAPL_EVD *) user_context; + + dapl_os_assert (hca_handle == evd_ptr->header.owner_ia->hca_ptr->ib_hca_handle); + dapl_os_assert (evd_ptr->ib_cq_handle == cq_handle); + dapl_os_assert (evd_ptr->header.magic == DAPL_MAGIC_EVD); + + /* Read once. */ + state = *(volatile DAPL_EVD_STATE *) &evd_ptr->evd_state; + + dapl_dbg_log (DAPL_DBG_TYPE_EVD, + "--> dapl_evd_dto_callback: CQ %p, state %x\n", + (void *)evd_ptr->ib_cq_handle, + state); + + /* + * This function does not dequeue from the CQ; only the consumer + * can do that. Instead, it wakes up waiters if any exist. + * It rearms the completion only if completions should always occur + * (specifically if a CNO is associated with the EVD and the + * EVD is enabled. + */ + + if (state == DAPL_EVD_STATE_WAITED) + { + /* + * If we could, it would be best to avoid this wakeup + * (and the context switch) unless the number of events/CQs + * waiting for the waiter was its threshold. We don't + * currently have the ability to determine that without + * dequeueing the events, and we can't do that for + * synchronization reasons (racing with the waiter waking + * up and dequeuing, sparked by other callbacks). + */ + + /* + * We don't need to worry about taking the lock for the + * wakeup because wakeups are sticky. + */ + if (evd_ptr->cq_wait_obj_handle) + { + dapls_ib_wait_object_wakeup(evd_ptr->cq_wait_obj_handle); + } + else + { + dapl_os_wait_object_wakeup(&evd_ptr->wait_object); + } + } + else if (state == DAPL_EVD_STATE_OPEN) + { + DAPL_CNO *cno = evd_ptr->cno_ptr; + if (evd_ptr->evd_enabled && (evd_ptr->cno_ptr != NULL)) + { + /* + * Re-enable callback, *then* trigger. + * This guarantees we won't miss any events. + */ + dat_status = dapls_ib_completion_notify (hca_handle, + evd_ptr->ib_cq_handle, + IB_NOTIFY_ON_NEXT_COMP); + + if ( DAT_SUCCESS != dat_status ) + { + (void) dapls_evd_post_async_error_event( + evd_ptr->header.owner_ia->async_error_evd, + DAT_ASYNC_ERROR_PROVIDER_INTERNAL_ERROR, + (DAT_IA_HANDLE) evd_ptr->header.owner_ia); + } + + dapl_cno_trigger(cno, evd_ptr); + } + } + dapl_dbg_log (DAPL_DBG_TYPE_RTN, "dapl_evd_dto_callback () returns\n"); +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_enable.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_enable.c new file mode 100644 index 00000000..6e2758e7 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_enable.c @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_evd_enable.c + * + * PURPOSE: EVENT management + * + * Description: Interfaces in this file are completely defined in + * the uDAPL 1.1 API, Chapter 6, section 3 + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_adapter_util.h" + +/* + * dapl_evd_enable + * + * DAPL Requirements Version xxx, 6.3.2.5 + * + * Modify the size fo the event queue of an Event Dispatcher + * + * Input: + * evd_handle + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + */ + +DAT_RETURN dapl_evd_enable ( + IN DAT_EVD_HANDLE evd_handle) +{ + DAPL_EVD *evd_ptr; + DAT_RETURN dat_status; + + evd_ptr = (DAPL_EVD *)evd_handle; + dat_status = DAT_SUCCESS; + + if ( DAPL_BAD_HANDLE (evd_handle, DAPL_MAGIC_EVD) ) + + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE,0); + goto bail; + } + + evd_ptr->evd_enabled = DAT_TRUE; + + /* We need to enable the callback handler if there is a CNO. */ + if (evd_ptr->cno_ptr != NULL && + evd_ptr->ib_cq_handle != IB_INVALID_HANDLE ) + { + dat_status = dapls_ib_completion_notify ( + evd_ptr->header.owner_ia->hca_ptr->ib_hca_handle, + evd_ptr->ib_cq_handle, + IB_NOTIFY_ON_NEXT_COMP); + + /* FIXME report error */ + dapl_os_assert(dat_status == DAT_SUCCESS); + } + +bail: + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_free.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_free.c new file mode 100644 index 00000000..3835a083 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_free.c @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_evd_free.c + * + * PURPOSE: Event management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 3 + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_evd_util.h" +#include "dapl_ia_util.h" +#include "dapl_cno_util.h" /* for __KDAPL__ */ + +/* + * dapl_evd_free + * + * DAPL Requirements Version xxx, 6.3.2.2 + * + * Destroy a specific instance of the Event Dispatcher + * + * Input: + * evd_handle + * + * Output: + * None + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + * DAT_INVALID_STATE + */ +DAT_RETURN dapl_evd_free ( + IN DAT_EVD_HANDLE evd_handle) + +{ + DAPL_EVD *evd_ptr; + DAPL_CNO *cno_ptr; + DAT_RETURN dat_status; + + dapl_dbg_log (DAPL_DBG_TYPE_API, "dapl_evd_free (%p)\n", evd_handle); + DAPL_CNTR (DCNT_EVD_FREE); + + dat_status = DAT_SUCCESS; + evd_ptr = (DAPL_EVD *)evd_handle; + + if (DAPL_BAD_HANDLE (evd_handle, DAPL_MAGIC_EVD)) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE, 0); + goto bail; + } + + if (evd_ptr->evd_ref_count != 0) + { + dat_status = DAT_ERROR (DAT_INVALID_STATE, DAT_INVALID_STATE_EVD_IN_USE); + goto bail; + } + + /* obtain the cno_ptr before the evd is released, which must occur + * before deallocating the CNO + */ + cno_ptr = evd_ptr->cno_ptr; + + dapl_ia_unlink_evd (evd_ptr->header.owner_ia, evd_ptr); + + dat_status = dapls_evd_dealloc (evd_ptr); + if (dat_status != DAT_SUCCESS) + { + dapl_ia_link_evd (evd_ptr->header.owner_ia, evd_ptr); + } + + if (cno_ptr != NULL) + { + if (cno_ptr->cno_ref_count == 0 && cno_ptr->cno_waiters > 0) + { + /* + * Last reference on the CNO, trigger a notice. See + * uDAPL 1.1 spec 6.3.2.3 + */ + dapl_cno_trigger (cno_ptr, NULL); + } + } + +bail: + dapl_dbg_log (DAPL_DBG_TYPE_RTN, + "dapl_evd_free () returns 0x%x\n", + dat_status); + + return dat_status; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_modify_cno.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_modify_cno.c new file mode 100644 index 00000000..88ede7dc --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_modify_cno.c @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_evd_modify_cno.c + * + * PURPOSE: Event Management + * + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 3 + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_adapter_util.h" + +/* + * dapl_evd_modify_cno + * + * DAPL Requirements Version xxx, 6.3.2.4 + * + * Modify the CNO associated with the EVD + * + * Input: + * evd_handle + * cno_handle + * + * Output: + * none + * + * Returns: + * DAT_SUCCSSS + * DAT_INVALID_HANDLE + */ + +DAT_RETURN dapl_evd_modify_cno ( + IN DAT_EVD_HANDLE evd_handle, + IN DAT_CNO_HANDLE cno_handle) + + +{ + DAPL_EVD *evd_ptr; + DAPL_CNO *cno_ptr; + DAPL_CNO *old_cno_ptr; + DAT_RETURN dat_status; + + evd_ptr = (DAPL_EVD *)evd_handle; + cno_ptr = (DAPL_CNO *)cno_handle; + dat_status = DAT_SUCCESS; + + if (DAPL_BAD_HANDLE (evd_handle, DAPL_MAGIC_EVD)) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE, 0); + goto bail; + } + if (cno_handle != NULL && + DAPL_BAD_HANDLE (cno_handle, DAPL_MAGIC_CNO)) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_CNO); + goto bail; + } + dapl_os_lock (&evd_ptr->header.lock); + old_cno_ptr = evd_ptr->cno_ptr; + evd_ptr->cno_ptr = cno_ptr; + dapl_os_unlock (&evd_ptr->header.lock); + if (cno_ptr) + { + dapl_os_atomic_inc ( & (cno_ptr->cno_ref_count) ); + } + if (old_cno_ptr) + { + dapl_os_atomic_dec ( & (old_cno_ptr->cno_ref_count) ); + } + + /* We need to enable the callback handler if the EVD is enabled. */ + if (evd_ptr->evd_enabled && + cno_handle != DAT_HANDLE_NULL && + evd_ptr->ib_cq_handle != IB_INVALID_HANDLE) + { + dat_status = dapls_ib_completion_notify ( + evd_ptr->header.owner_ia->hca_ptr->ib_hca_handle, + evd_ptr->ib_cq_handle, + IB_NOTIFY_ON_NEXT_COMP); + + /* FIXME report error */ + dapl_os_assert (dat_status == DAT_SUCCESS); + } + +bail: + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_post_se.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_post_se.c new file mode 100644 index 00000000..05614fb4 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_post_se.c @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_evd_post_se.c + * + * PURPOSE: Event Management + * + * Description: Interfaces in this file are completely defined in + * the uDAPL 1.1 API, Chapter 6, section 3 + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_evd_util.h" +#include "dapl_ia_util.h" + +/* + * dapl_evd_post_se + * + * DAPL Requirements Version xxx, 6.3.2.7 + * + * Post a software event to the Event Dispatcher event queue. + * + * Input: + * evd_handle + * event + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + */ + + +DAT_RETURN dapl_evd_post_se ( + DAT_EVD_HANDLE evd_handle, + const DAT_EVENT *event) + +{ + DAPL_EVD *evd_ptr; + DAT_RETURN dat_status; + + evd_ptr = (DAPL_EVD *)evd_handle; + dat_status = DAT_SUCCESS; + + if (DAPL_BAD_HANDLE (evd_handle, DAPL_MAGIC_EVD)) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE,0); + goto bail; + } + /* Only post to EVDs that are specific to software events */ + if ( !(evd_ptr->evd_flags & DAT_EVD_SOFTWARE_FLAG) ) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER,DAT_INVALID_ARG1); + goto bail; + } + + if (!event) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER,DAT_INVALID_ARG2); + goto bail; + } + if (event->event_number != DAT_SOFTWARE_EVENT) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER,DAT_INVALID_ARG2); + goto bail; + } + + dat_status = dapls_evd_post_software_event( + evd_ptr, + DAT_SOFTWARE_EVENT, + event->event_data.software_event_data.pointer); + + bail: + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_qp_async_error_callb.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_qp_async_error_callb.c new file mode 100644 index 00000000..70425530 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_qp_async_error_callb.c @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_evd_qp_async_error_callback.c + * + * PURPOSE: implements QP callbacks from verbs + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_evd_util.h" +#include "dapl_adapter_util.h" + +/* + * dapl_evd_qp_async_error_callback + * + * The callback function registered with verbs for qp async erros + * + * Maps to ib_async_handler_t as follow: + * + * typedef void (*ib_async_handler_t)( + * IN ib_hca_handle_t ib_hca_handle, + * IN ib_error_record_t *err_code, + * IN void *context); + * + * Output: + * None + * + */ + +void +dapl_evd_qp_async_error_callback ( + IN ib_hca_handle_t ib_hca_handle, + IN ib_error_record_t *err_code, + IN void *context) + +{ + /* + * This is an affiliated error and hence should be able to + * supply us with exact information on the error type and QP. + * + * However IB vendor APIs for registering this callback + * are different. + * + * Therefore we always specify the context as the asyncronous EVD + * to be compatible with all APIs. + */ + + DAPL_IA *ia_ptr; + DAPL_EP *ep_ptr; + DAPL_EVD *async_evd; + DAT_EVENT_NUMBER async_event; + DAT_RETURN dat_status; + UNREFERENCED_PARAMETER(ib_hca_handle); + + ep_ptr = (DAPL_EP *) context; + ia_ptr = ep_ptr->header.owner_ia; + async_evd = (DAPL_EVD *) ia_ptr->async_error_evd; + + dapl_dbg_log ( + DAPL_DBG_TYPE_CALLBACK | DAPL_DBG_TYPE_EXCEPTION, + "--> dapl_evd_qp_async_error_callback: ep %p qp %p (%x) state %d\n", + ep_ptr, + ep_ptr->qp_handle, + ep_ptr->qpn, + ep_ptr->param.ep_state); + + /* + * Transition to ERROR if we are connected; other states need to + * complete first (e.g. pending states) + */ + if ( ep_ptr->param.ep_state == DAT_EP_STATE_CONNECTED) + { + ep_ptr->param.ep_state = DAT_EP_STATE_ERROR; + } + + dapl_os_assert (async_evd != NULL); + + dat_status = dapls_ib_get_async_event(err_code, &async_event); + if ( dat_status == DAT_SUCCESS ) + { + /* + * If dapls_ib_get_async_event is not successful, + * an event has been generated by the provide that + * we are not interested in. + */ + (void) dapls_evd_post_async_error_event( async_evd, + async_event, + async_evd->header.owner_ia); + } + dapl_dbg_log (DAPL_DBG_TYPE_CALLBACK | DAPL_DBG_TYPE_EXCEPTION, + "dapl_evd_qp_async_error_callback () returns\n"); +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_query.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_query.c new file mode 100644 index 00000000..5aa596bc --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_query.c @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_evd_query.c + * + * PURPOSE: Event management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 3 + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" + +/* + * dapl_evd_query + * + * DAPL Requirements Version xxx, 6.3.2.3 + * + * Provides the consumer with arguments of the Event Dispatcher. + * + * Input: + * evd_handle + * evd_mask + * + * Output: + * evd_param + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + * DAT_INVALID_PARAMETER + */ +DAT_RETURN +dapl_evd_query ( + IN DAT_EVD_HANDLE evd_handle, + IN DAT_EVD_PARAM_MASK evd_param_mask, + OUT DAT_EVD_PARAM *evd_param ) +{ + DAPL_EVD *evd_ptr; + DAT_RETURN dat_status; + + dat_status = DAT_SUCCESS; + + if ( NULL == evd_param ) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER,DAT_INVALID_ARG3); + goto bail; + } + + /* Note: the spec. allows for events to be directed to a NULL EVD */ + /* with handle of type DAT_HANDLE_NULL. See 6.3.1 */ + if ( DAT_HANDLE_NULL == evd_handle ) + { + dapl_os_memzero (evd_param, sizeof (DAT_EVD_PARAM)); + } + else + { + if ( DAPL_BAD_HANDLE (evd_handle, DAPL_MAGIC_EVD) ) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE,0); + goto bail; + } + + evd_ptr = (DAPL_EVD *) evd_handle; + + /* + * We may be racing against the thread safe modify + * calls here (dat_evd_{enable,disable,{set,clear}_unwaitable}). + * They are thread safe, so our reads need to be atomic with + * regard to those calls. The below is ok (a single bit + * read counts as atomic; if it's in transition you'll get one + * of the correct values) but we'll need to be careful + * about reading the state variable atomically when we add + * in waitable/unwaitable. + */ + if (evd_param_mask & DAT_EVD_FIELD_ALL ) + { + evd_param->evd_state = + (evd_ptr->evd_enabled ? DAT_EVD_STATE_ENABLED : DAT_EVD_STATE_DISABLED); + evd_param->evd_state |= + (evd_ptr->evd_waitable ? DAT_EVD_STATE_WAITABLE : DAT_EVD_STATE_UNWAITABLE); + evd_param->ia_handle = evd_ptr->header.owner_ia; + evd_param->evd_qlen = evd_ptr->qlen; + evd_param->cno_handle = (DAT_CNO_HANDLE) evd_ptr->cno_ptr; + evd_param->evd_flags = evd_ptr->evd_flags; + } + } + +bail: + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_resize.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_resize.c new file mode 100644 index 00000000..f183a3e8 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_resize.c @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_evd_resize.c + * + * PURPOSE: EVENT management + * + * Description: Interfaces in this file are completely defined in + * the uDAPL 1.1 API, Chapter 6, section 3 + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_evd_util.h" +#include "dapl_adapter_util.h" +#include "dapl_ring_buffer_util.h" + +/* + * dapl_evd_resize + * + * DAPL Requirements Version xxx, 6.3.2.5 + * + * Modify the size fo the event queue of an Event Dispatcher + * + * Input: + * evd_handle + * evd_qlen + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_STATE + */ + +DAT_RETURN dapl_evd_resize ( + IN DAT_EVD_HANDLE evd_handle, + IN DAT_COUNT evd_qlen ) +{ + + DAPL_EVD *evd_ptr; + DAT_EVENT *event_ptr; + DAT_EVENT *events; + DAT_EVENT *orig_event; + DAPL_RING_BUFFER free_event_queue; + DAPL_RING_BUFFER pending_event_queue; + DAT_COUNT i; + DAT_COUNT pend_cnt; + + evd_ptr = (DAPL_EVD *) evd_handle; + + dapl_dbg_log (DAPL_DBG_TYPE_API, "dapl_evd_resize (%p, %d)\n", + evd_handle, evd_qlen); + + if (DAPL_BAD_HANDLE (evd_ptr, DAPL_MAGIC_EVD)) + { + return DAT_ERROR (DAT_INVALID_PARAMETER,DAT_INVALID_ARG1); + } + if (evd_qlen <= 0) + { + return DAT_ERROR (DAT_INVALID_PARAMETER,DAT_INVALID_ARG2); + } + + dapl_os_lock(&evd_ptr->header.lock); + + if (evd_ptr->evd_state == DAPL_EVD_STATE_WAITED) + { + dapl_os_unlock(&evd_ptr->header.lock); + return DAT_ERROR (DAT_INVALID_STATE,0); + } + + pend_cnt = dapls_rbuf_count(&evd_ptr->pending_event_queue); + if (pend_cnt > evd_qlen) { + dapl_os_unlock(&evd_ptr->header.lock); + return DAT_ERROR (DAT_INVALID_STATE,0); + } + + if (DAT_SUCCESS != dapls_ib_cq_resize(evd_ptr->header.owner_ia, + evd_ptr, + &evd_qlen)) { + dapl_os_unlock(&evd_ptr->header.lock); + return DAT_ERROR (DAT_INSUFFICIENT_RESOURCES,DAT_RESOURCE_MEMORY); + } + + /* Allocate EVENTs */ + events = (DAT_EVENT *) dapl_os_alloc (evd_qlen * sizeof (DAT_EVENT)); + if (!events) + { + dapl_os_unlock(&evd_ptr->header.lock); + return DAT_ERROR (DAT_INSUFFICIENT_RESOURCES,DAT_RESOURCE_MEMORY); + } + event_ptr = events; + + /* allocate free event queue */ + + if (DAT_SUCCESS != dapls_rbuf_alloc (&free_event_queue, evd_qlen)) + { + dapl_os_free(event_ptr, evd_qlen * sizeof (DAT_EVENT)); + dapl_os_unlock(&evd_ptr->header.lock); + return DAT_ERROR (DAT_INSUFFICIENT_RESOURCES,DAT_RESOURCE_MEMORY); + } + + /* allocate pending event queue */ + if (DAT_SUCCESS != dapls_rbuf_alloc (&pending_event_queue, evd_qlen)) + { + dapl_os_free(event_ptr, evd_qlen * sizeof (DAT_EVENT)); + dapl_os_unlock(&evd_ptr->header.lock); + return DAT_ERROR (DAT_INSUFFICIENT_RESOURCES,DAT_RESOURCE_MEMORY); + } + + for (i = 0; i < pend_cnt; i++) { + orig_event = dapls_rbuf_remove(&evd_ptr->pending_event_queue); + if (orig_event == NULL) { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, " Inconsistent event queue\n"); + dapl_os_free(event_ptr, evd_qlen * sizeof (DAT_EVENT)); + dapl_os_unlock(&evd_ptr->header.lock); + return DAT_ERROR (DAT_INSUFFICIENT_RESOURCES,DAT_RESOURCE_MEMORY); + } + memcpy(event_ptr, orig_event, sizeof(DAT_EVENT)); + if (DAT_SUCCESS != dapls_rbuf_add(&pending_event_queue, event_ptr)) { + dapl_os_free(event_ptr, evd_qlen * sizeof (DAT_EVENT)); + dapl_os_unlock(&evd_ptr->header.lock); + return DAT_ERROR (DAT_INSUFFICIENT_RESOURCES,DAT_RESOURCE_MEMORY); + } + event_ptr++; + } + + for (i = pend_cnt; i < evd_qlen; i++) + { + if (DAT_SUCCESS != dapls_rbuf_add(&free_event_queue, + (void *) event_ptr)) { + dapl_os_free(event_ptr, evd_qlen * sizeof (DAT_EVENT)); + dapl_os_unlock(&evd_ptr->header.lock); + return DAT_ERROR (DAT_INSUFFICIENT_RESOURCES,DAT_RESOURCE_MEMORY); + } + event_ptr++; + } + + dapls_rbuf_destroy (&evd_ptr->free_event_queue); + dapls_rbuf_destroy (&evd_ptr->pending_event_queue); + if (evd_ptr->events) + { + dapl_os_free (evd_ptr->events, evd_ptr->qlen * sizeof (DAT_EVENT)); + } + evd_ptr->free_event_queue = free_event_queue; + evd_ptr->pending_event_queue = pending_event_queue; + evd_ptr->events = events; + evd_ptr->qlen = evd_qlen; + + dapl_os_unlock(&evd_ptr->header.lock); + + dapl_dbg_log (DAPL_DBG_TYPE_RTN, + "dapl_evd_resize returns SUCCESS\n"); + + return DAT_SUCCESS; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_set_unwaitable.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_set_unwaitable.c new file mode 100644 index 00000000..f2fea18f --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_set_unwaitable.c @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_evd_set_unwaitable.c + * + * PURPOSE: EVENT management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 3.4.7 + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_adapter_util.h" +/* + * dapl_evd_set_unwaitable + * + * DAPL Requirements Version 1.1, 6.3.4.7 + * + * Transition the Event Dispatcher into an unwaitable state + * + * Input: + * evd_handle + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + */ +DAT_RETURN +dapl_evd_set_unwaitable ( + IN DAT_EVD_HANDLE evd_handle ) +{ + DAPL_EVD *evd_ptr; + DAT_RETURN dat_status; + + evd_ptr = (DAPL_EVD *)evd_handle; + dat_status = DAT_SUCCESS; + + if ( DAPL_BAD_HANDLE (evd_handle, DAPL_MAGIC_EVD) ) + + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE,0); + goto bail; + } + dapl_os_lock ( &evd_ptr->header.lock ); + evd_ptr->evd_waitable = DAT_FALSE; + dapl_os_unlock ( &evd_ptr->header.lock ); + + /* + * If this evd is waiting, wake it up. There is an obvious race + * condition here where we may wakeup the waiter before it goes to + * sleep; but the wait_object allows this and will do the right + * thing. + */ + if (evd_ptr->evd_state == DAPL_EVD_STATE_WAITED) + { + if (evd_ptr->cq_wait_obj_handle) + { + dapls_ib_wait_object_wakeup (evd_ptr->cq_wait_obj_handle); + } + else + { + dapl_os_wait_object_wakeup (&evd_ptr->wait_object); + } + } +bail: + return dat_status; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_un_async_error_callb.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_un_async_error_callb.c new file mode 100644 index 00000000..c55a280a --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_un_async_error_callb.c @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_evd_un_async_error_callback.c + * + * PURPOSE: implements Unaffiliated callbacks from verbs + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_evd_util.h" +#include "dapl_adapter_util.h" + +/* + * dapl_evd_un_async_error_callback + * + * The callback function registered with verbs for unaffiliated async errors + * + * Input: + * ib_hca_handle, + * error_ptr + * context (async_evd) + * + * Output: + * None + * + */ + +void +dapl_evd_un_async_error_callback ( + IN ib_hca_handle_t ib_hca_handle, + IN ib_error_record_t *error_ptr, + IN void *context) + +{ + DAPL_EVD *async_evd; + DAT_EVENT_NUMBER async_event; + DAT_RETURN dat_status; + + dapl_dbg_log (DAPL_DBG_TYPE_CALLBACK | DAPL_DBG_TYPE_EXCEPTION, + "dapl_evd_un_async_error_callback (%p, %p, %p)\n", + ib_hca_handle, + error_ptr, + context); + + if ( NULL == context ) + { + dapl_os_panic ("NULL == context\n"); + return; + } + + async_evd = (DAPL_EVD *) context; + + dat_status = dapls_ib_get_async_event(error_ptr, &async_event); + + if ( dat_status == DAT_SUCCESS ) + { + /* + * If dapls_ib_get_async_event is not successful, + * an event has been generated by the provider that + * we are not interested in. E.g. LINK_UP. + */ + dapls_evd_post_async_error_event( async_evd, + async_event, + async_evd->header.owner_ia); + } + dapl_dbg_log (DAPL_DBG_TYPE_CALLBACK | DAPL_DBG_TYPE_EXCEPTION, + "dapl_evd_un_async_error_callback () returns\n"); +} + diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_util.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_util.c new file mode 100644 index 00000000..a5cf340f --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_util.c @@ -0,0 +1,1457 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_evd_util.c + * + * PURPOSE: Manage EVD Info structure + * + * $Id$ + **********************************************************************/ + +#include "dapl_evd_util.h" +#include "dapl_ia_util.h" +#include "dapl_cno_util.h" +#include "dapl_ring_buffer_util.h" +#include "dapl_adapter_util.h" +#include "dapl_cookie.h" +#include "dapl.h" + +STATIC _INLINE_ void dapli_evd_eh_print_cqe ( + IN ib_work_completion_t cqe); + +DAT_RETURN dapli_evd_event_alloc ( + IN DAPL_EVD *evd_ptr, + IN DAPL_CNO *cno_ptr, + IN DAT_COUNT qlen); + + +/* + * dapls_evd_internal_create + * + * actually create the evd. this is called after all parameter checking + * has been performed in dapl_ep_create. it is also called from dapl_ia_open + * to create the default async evd. + * + * Input: + * ia_ptr + * cno_ptr + * qlen + * evd_flags + * + * Output: + * evd_ptr_ptr + * + * Returns: + * none + * + */ + +DAT_RETURN +dapls_evd_internal_create ( + DAPL_IA *ia_ptr, + DAPL_CNO *cno_ptr, + DAT_COUNT min_qlen, + DAT_EVD_FLAGS evd_flags, + DAPL_EVD **evd_ptr_ptr) +{ + DAPL_EVD *evd_ptr; + DAT_COUNT cq_len; + DAT_RETURN dat_status; + + dat_status = DAT_SUCCESS; + *evd_ptr_ptr = NULL; + cq_len = min_qlen; + + evd_ptr = dapls_evd_alloc (ia_ptr, + cno_ptr, + evd_flags, + min_qlen); + if (!evd_ptr) + { + dat_status = DAT_ERROR (DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); + goto bail; + } + + /* + * If we are dealing with event streams besides a CQ event stream, + * be conservative and set producer side locking. Otherwise, no. + */ + evd_ptr->evd_producer_locking_needed = + ((evd_flags & ~ (DAT_EVD_DTO_FLAG|DAT_EVD_RMR_BIND_FLAG)) != 0); + + /* Before we setup any callbacks, transition state to OPEN. */ + evd_ptr->evd_state = DAPL_EVD_STATE_OPEN; + + if (evd_flags & DAT_EVD_ASYNC_FLAG) + { + /* + * There is no cq associate with async evd. Set it to invalid + */ + evd_ptr->ib_cq_handle = IB_INVALID_HANDLE; + + } + else if ( 0 != (evd_flags & ~ (DAT_EVD_SOFTWARE_FLAG + | DAT_EVD_CONNECTION_FLAG + | DAT_EVD_CR_FLAG) ) ) + { + +#if defined(_VENDOR_IBAL_) + + /* + * The creation of CQ required a PD (PZ) associated with it and + * we do not have a PD here; therefore, the work-around is that we + * will postpone the creation of the cq till the creation of QP which + * this cq will associate with. + */ + evd_ptr->ib_cq_handle = IB_INVALID_HANDLE; + +#else + + dat_status = dapls_ib_cq_alloc (ia_ptr, + evd_ptr, + &cq_len); + if (dat_status != DAT_SUCCESS) + { + goto bail; + } + + dat_status = dapls_ib_setup_async_callback (ia_ptr, + DAPL_ASYNC_CQ_COMPLETION, + (unsigned int *) evd_ptr->ib_cq_handle, + (ib_async_handler_t)dapl_evd_dto_callback, + evd_ptr); + if (dat_status != DAT_SUCCESS) + { + goto bail; + } + + dat_status = dapls_set_cq_notify (ia_ptr, evd_ptr); + + if (dat_status != DAT_SUCCESS) + { + goto bail; + } + +#endif /* _VENDOR_IBAL_ */ + + } + + /* We now have an accurate count of events, so allocate them into + * the EVD + */ + dat_status = dapli_evd_event_alloc (evd_ptr, cno_ptr, cq_len); + if (dat_status != DAT_SUCCESS) + { + goto bail; + } + + /* We're assuming success in the following. */ + dapl_os_assert (dat_status == DAT_SUCCESS); + dapl_ia_link_evd (ia_ptr, evd_ptr); + *evd_ptr_ptr = evd_ptr; + +bail: + if (dat_status != DAT_SUCCESS) + { + if (evd_ptr) + { + dapls_evd_dealloc (evd_ptr); + } + } + + return dat_status; +} + +/* + * dapls_evd_alloc + * + * alloc and initialize an EVD struct + * + * Input: + * ia + * + * Output: + * evd_ptr + * + * Returns: + * none + * + */ +DAPL_EVD * +dapls_evd_alloc ( + IN DAPL_IA *ia_ptr, + IN DAPL_CNO *cno_ptr, + IN DAT_EVD_FLAGS evd_flags, + IN DAT_COUNT qlen) +{ + DAPL_EVD *evd_ptr; + UNREFERENCED_PARAMETER(cno_ptr); + evd_ptr = NULL; + + /* Allocate EVD */ + evd_ptr = (DAPL_EVD *)dapl_os_alloc (sizeof (DAPL_EVD)); + if (!evd_ptr) + { + goto bail; + } + + /* zero the structure */ + dapl_os_memzero (evd_ptr, sizeof (DAPL_EVD)); + + /* + * initialize the header + */ + evd_ptr->header.provider = ia_ptr->header.provider; + evd_ptr->header.magic = DAPL_MAGIC_EVD; + evd_ptr->header.handle_type = DAT_HANDLE_TYPE_EVD; + evd_ptr->header.owner_ia = ia_ptr; + evd_ptr->header.user_context.as_64 = 0; + evd_ptr->header.user_context.as_ptr = NULL; + dapl_llist_init_entry (&evd_ptr->header.ia_list_entry); + dapl_os_lock_init (&evd_ptr->header.lock); + + /* + * Initialize the body + */ + evd_ptr->evd_state = DAPL_EVD_STATE_INITIAL; + evd_ptr->evd_flags = evd_flags; + evd_ptr->evd_enabled = DAT_TRUE; + evd_ptr->evd_waitable = DAT_TRUE; + evd_ptr->evd_producer_locking_needed = 1;/* Conservative value. */ + evd_ptr->ib_cq_handle = IB_INVALID_HANDLE; + evd_ptr->evd_ref_count = 0; + evd_ptr->catastrophic_overflow = DAT_FALSE; + evd_ptr->qlen = qlen; + evd_ptr->completion_type = DAPL_EVD_STATE_THRESHOLD; /* FIXME: should be DAPL_EVD_STATE_INIT */ + dapl_os_wait_object_init (&evd_ptr->wait_object); + evd_ptr->cq_wait_obj_handle = 0; + //dapls_ib_wait_object_create (&evd_ptr->cq_wait_obj_handle); + +bail: + return evd_ptr; +} + + +/* + * dapls_evd_event_alloc + * + * alloc events into an EVD. + * + * Input: + * evd_ptr + * qlen + * + * Output: + * NONE + * + * Returns: + * DAT_SUCCESS + * ERROR + * + */ +DAT_RETURN +dapli_evd_event_alloc ( + IN DAPL_EVD *evd_ptr, + IN DAPL_CNO *cno_ptr, + IN DAT_COUNT qlen) +{ + DAT_EVENT *event_ptr; + DAT_COUNT i; + DAT_RETURN dat_status; + + dat_status = DAT_SUCCESS; + event_ptr = NULL; + + /* Allocate EVENTs */ + event_ptr = (DAT_EVENT *) dapl_os_alloc (evd_ptr->qlen * sizeof (DAT_EVENT)); + if (!event_ptr) + { + goto bail; + } + evd_ptr->events = event_ptr; + + /* allocate free event queue */ + dat_status = dapls_rbuf_alloc (&evd_ptr->free_event_queue, qlen); + if (dat_status != DAT_SUCCESS) + { + goto bail; + } + + /* allocate pending event queue */ + dat_status = dapls_rbuf_alloc (&evd_ptr->pending_event_queue, qlen); + if (dat_status != DAT_SUCCESS) + { + goto bail; + } + + /* add events to free event queue */ + for (i = 0; i < evd_ptr->qlen; i++) + { + dapls_rbuf_add (&evd_ptr->free_event_queue, (void *)event_ptr); + event_ptr++; + } + + evd_ptr->cq_notified = DAT_FALSE; + evd_ptr->cq_notified_when = 0; + evd_ptr->cno_active_count = 0; + if ( cno_ptr != NULL ) + { + /* Take a reference count on the CNO */ + dapl_os_atomic_inc ( &cno_ptr->cno_ref_count ); + } + evd_ptr->cno_ptr = cno_ptr; + evd_ptr->threshold = 0; + + bail: + return dat_status; +} + +/* + * dapls_evd_event_realloc + * + * realloc events into an EVD. + * + * Input: + * evd_ptr + * qlen + * + * Output: + * NONE + * + * Returns: + * DAT_SUCCESS + * ERROR + * + */ +DAT_RETURN +dapls_evd_event_realloc ( + IN DAPL_EVD *evd_ptr, + IN DAT_COUNT qlen) +{ + DAT_EVENT *event_ptr; + DAT_COUNT i; + DAT_RETURN dat_status; + + /* Allocate EVENTs */ + event_ptr = (DAT_EVENT *) dapl_os_realloc (evd_ptr->events, + qlen * sizeof (DAT_EVENT)); + if (event_ptr == NULL) + { + dat_status = DAT_ERROR (DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); + goto bail; + } + evd_ptr->events = event_ptr; + + /* allocate free event queue */ + dat_status = dapls_rbuf_realloc (&evd_ptr->free_event_queue, qlen); + if (dat_status != DAT_SUCCESS) + { + goto bail; + } + + /* allocate pending event queue */ + dat_status = dapls_rbuf_realloc (&evd_ptr->pending_event_queue, qlen); + if (dat_status != DAT_SUCCESS) + { + goto bail; + } + + evd_ptr->qlen = qlen; + + /* + * add events to free event queue. Need to verify that an entry is + * not on the current queues before putting it on the free queue + */ + for (i = 0; i < qlen; i++, event_ptr++) + { + if (dapls_rbuf_contains (&evd_ptr->free_event_queue, event_ptr) + || dapls_rbuf_contains (&evd_ptr->pending_event_queue, event_ptr)) + { + continue; + } + dapls_rbuf_add (&evd_ptr->free_event_queue, (void *)event_ptr); + } + +bail: + + return dat_status; +} + +/* + * dapls_evd_dealloc + * + * Free the passed in EVD structure. If an error occurs, this function + * will clean up all of the internal data structures and report the + * error. + * + * Input: + * evd_ptr + * + * Output: + * none + * + * Returns: + * status + * + */ +DAT_RETURN +dapls_evd_dealloc ( + IN DAPL_EVD *evd_ptr ) +{ + DAT_RETURN dat_status; + DAPL_IA *ia_ptr; + + dat_status = DAT_SUCCESS; + + dapl_os_assert (evd_ptr->header.magic == DAPL_MAGIC_EVD); + dapl_os_assert (evd_ptr->evd_ref_count == 0); + + /* + * Destroy the CQ first, to keep any more callbacks from coming + * up from it. + */ + if (evd_ptr->ib_cq_handle != IB_INVALID_HANDLE) + { + ia_ptr = evd_ptr->header.owner_ia; + + dat_status = dapls_ib_cq_free (ia_ptr, evd_ptr); + + if (dat_status != DAT_SUCCESS) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "dapl_evd_dealloc failed to rel. CQ %p \n", + evd_ptr->ib_cq_handle); + goto bail; + } + } + + /* + * We should now be safe to invalidate the EVD; reset the + * magic to prevent reuse. + */ + evd_ptr->header.magic = DAPL_MAGIC_INVALID; + + /* Release reference on the CNO if it exists */ + if ( evd_ptr->cno_ptr != NULL ) + { + dapl_os_atomic_dec ( &evd_ptr->cno_ptr->cno_ref_count ); + evd_ptr->cno_ptr = NULL; + } + + /* If the ring buffer allocation failed, then the dapls_rbuf_destroy */ + /* function will detect that the ring buffer's internal data (ex. base */ + /* pointer) are invalid and will handle the situation appropriately */ + dapls_rbuf_destroy (&evd_ptr->free_event_queue); + dapls_rbuf_destroy (&evd_ptr->pending_event_queue); + + if (evd_ptr->events) + { + dapl_os_free (evd_ptr->events, evd_ptr->qlen * sizeof (DAT_EVENT)); + } + + dapl_os_wait_object_destroy (&evd_ptr->wait_object); + if (evd_ptr->cq_wait_obj_handle) + dapls_ib_wait_object_destroy (evd_ptr->cq_wait_obj_handle); + dapl_os_free (evd_ptr, sizeof (DAPL_EVD)); + +bail: + return dat_status; +} + + +/* + * dapli_evd_eh_print_cqe + * + * Input: + * cqe + * + * Output: + * none + * + * Prints out a CQE for debug purposes + * + */ +void +dapli_evd_eh_print_cqe ( + IN ib_work_completion_t cqe) +{ +#if defined(DAPL_DBG) + static char *optable[] = + { + "INVALID_OP", + "OP_SEND", + "OP_RDMA_WRITE", + "OP_RDMA_READ", + "OP_COMP_AND_SWAP", + "OP_FETCH_AND_ADD", + "OP_RECEIVE", + "OP_BIND_MW", + "INVALID_OP" + }; + + dapl_dbg_log (DAPL_DBG_TYPE_DTO_COMP_ERR, + "\t >>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<\n"); + dapl_dbg_log (DAPL_DBG_TYPE_DTO_COMP_ERR, + "\t dapl_evd_dto: CQE \n"); + dapl_dbg_log (DAPL_DBG_TYPE_DTO_COMP_ERR, "\t\t work_req_id 0x" F64x "\n", + DAPL_GET_CQE_WRID(&cqe)); + dapl_dbg_log (DAPL_DBG_TYPE_DTO_COMP_ERR, "\t\t op_type: %s\n", + optable[DAPL_GET_CQE_OPTYPE(&cqe)] ); + dapl_dbg_log (DAPL_DBG_TYPE_DTO_COMP_ERR, "\t\t bytes_num %d\n", + DAPL_GET_CQE_BYTESNUM(&cqe)); + dapl_dbg_log (DAPL_DBG_TYPE_DTO_COMP_ERR, "\t\t status %d\n", + DAPL_GET_CQE_STATUS(&cqe)); + dapl_dbg_log (DAPL_DBG_TYPE_DTO_COMP_ERR, + "\t >>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<\n"); +#endif /* DAPL_DBG */ +} + + + + +/* + * Event posting code follows. + */ + +/* + * These next two functions (dapli_evd_get_event and dapli_evd_post_event) + * are a pair. They are always called together, from one of the functions + * at the end of this file (dapl_evd_post_*_event). + * + * Note that if producer side locking is enabled, the first one takes the + * EVD lock and the second releases it. + */ + +/* dapli_evd_get_event + * + * Get an event struct from the evd. The caller should fill in the event + * and call dapl_evd_post_event. + * + * If there are no events available, an overflow event is generated to the + * async EVD handler. + * + * If this EVD required producer locking, a successful return implies + * that the lock is held. + * + * Input: + * evd_ptr + * + * Output: + * event + * + */ + +static DAT_EVENT * +dapli_evd_get_event ( + DAPL_EVD *evd_ptr) +{ + DAT_EVENT *event; + + if (evd_ptr->evd_producer_locking_needed) + { + dapl_os_lock(&evd_ptr->header.lock); + } + + event = (DAT_EVENT *)dapls_rbuf_remove (&evd_ptr->free_event_queue); + + /* Release the lock if it was taken and the call failed. */ + if (!event && evd_ptr->evd_producer_locking_needed) + { + dapl_os_unlock(&evd_ptr->header.lock); + } + + return event; +} + +/* dapli_evd_post_event + * + * Post the to the evd. If possible, invoke the evd's CNO. + * Otherwise post the event on the pending queue. + * + * If producer side locking is required, the EVD lock must be held upon + * entry to this function. + * + * Input: + * evd_ptr + * event + * + * Output: + * none + * + */ + +static void +dapli_evd_post_event ( + IN DAPL_EVD *evd_ptr, + IN const DAT_EVENT *event_ptr) +{ + DAT_RETURN dat_status; + DAPL_CNO *cno_to_trigger = NULL; + + dapl_dbg_log(DAPL_DBG_TYPE_EVD, + "--> dapli_evd_post_event: Called with event # %x %p\n", + event_ptr->event_number, event_ptr); + + dat_status = dapls_rbuf_add (&evd_ptr->pending_event_queue, + (void *)event_ptr); + dapl_os_assert (dat_status == DAT_SUCCESS); + + dapl_os_assert (evd_ptr->evd_state == DAPL_EVD_STATE_WAITED + || evd_ptr->evd_state == DAPL_EVD_STATE_OPEN); + + if (evd_ptr->evd_state == DAPL_EVD_STATE_OPEN) + { + /* No waiter. Arrange to trigger a CNO if it exists. */ + + if (evd_ptr->evd_enabled) + { + cno_to_trigger = evd_ptr->cno_ptr; + } + if (evd_ptr->evd_producer_locking_needed) + { + dapl_os_unlock (&evd_ptr->header.lock); + } + } + else + { + DAT_COUNT total_events = 0; + DAT_BOOLEAN wakeup = FALSE; + DAT_UINT32 num_cqes = 0; + + /* + * We're in DAPL_EVD_STATE_WAITED. Take the lock if + * we don't have it, recheck, and signal. + */ + if (!evd_ptr->evd_producer_locking_needed) + { + dapl_os_lock(&evd_ptr->header.lock); + } + + total_events = dapls_rbuf_count (&evd_ptr->pending_event_queue); + + if (evd_ptr->evd_state == DAPL_EVD_STATE_WAITED + && (total_events >= evd_ptr->threshold)) + + { + dapl_os_unlock(&evd_ptr->header.lock); + wakeup = TRUE; + } + else if (total_events < evd_ptr->threshold) + { + dat_status = dapls_ib_peek_cq ( evd_ptr->ib_cq_handle, &num_cqes ); + + if ( dat_status != DAT_SUCCESS ) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "--> DiEPE: peek_cq failed to rel. CQ %p \n", + evd_ptr->ib_cq_handle); + } + else if ( (num_cqes >= (DAT_UINT32)(evd_ptr->threshold - total_events)) ) + { + if ( evd_ptr->evd_state == DAPL_EVD_STATE_WAITED ) + wakeup = TRUE; + } + else + { + if (evd_ptr->completion_type != DAPL_EVD_STATE_SOLICITED_WAIT) + { + dat_status = dapls_ib_n_completions_notify ( + evd_ptr->header.owner_ia->hca_ptr->ib_hca_handle, + evd_ptr->ib_cq_handle, + evd_ptr->threshold - total_events ); + } + } + + dapl_os_unlock(&evd_ptr->header.lock); + } + else + { + dapl_os_unlock(&evd_ptr->header.lock); + } + + if (wakeup) + { + if (evd_ptr->cq_wait_obj_handle) + { + dapls_ib_wait_object_wakeup (evd_ptr->cq_wait_obj_handle); + } + else + { + dapl_os_wait_object_wakeup (&evd_ptr->wait_object); + } + } + } + + if (cno_to_trigger != NULL) + { + dapl_cno_trigger(cno_to_trigger, evd_ptr); + } +} + + +/* dapli_evd_post_event_nosignal + * + * Post the to the evd. Do not do any wakeup processing. + * This function should only be called if it is known that there are + * no waiters that it is appropriate to wakeup on this EVD. An example + * of such a situation is during internal dat_evd_wait() processing. + * + * If producer side locking is required, the EVD lock must be held upon + * entry to this function. + * + * Input: + * evd_ptr + * event + * + * Output: + * none + * + */ + +static void +dapli_evd_post_event_nosignal ( + IN DAPL_EVD *evd_ptr, + IN const DAT_EVENT *event_ptr) +{ + DAT_RETURN dat_status; + + dapl_dbg_log (DAPL_DBG_TYPE_EVD, + "dapli_evd_post_event_nosignal: event # %x %p\n", + event_ptr->event_number, event_ptr); + + dat_status = dapls_rbuf_add (&evd_ptr->pending_event_queue, + (void *)event_ptr); + dapl_os_assert (dat_status == DAT_SUCCESS); + + dapl_os_assert (evd_ptr->evd_state == DAPL_EVD_STATE_WAITED + || evd_ptr->evd_state == DAPL_EVD_STATE_OPEN); + + if (evd_ptr->evd_producer_locking_needed) + { + dapl_os_unlock (&evd_ptr->header.lock); + } +} + +/* dapli_evd_format_overflow_event + * + * format an overflow event for posting + * + * Input: + * evd_ptr + * event_ptr + * + * Output: + * none + * + */ +static void +dapli_evd_format_overflow_event ( + IN DAPL_EVD *evd_ptr, + OUT DAT_EVENT *event_ptr) +{ + DAPL_IA *ia_ptr; + + ia_ptr = evd_ptr->header.owner_ia; + + event_ptr->evd_handle = (DAT_EVD_HANDLE)evd_ptr; + event_ptr->event_number = DAT_ASYNC_ERROR_EVD_OVERFLOW; + event_ptr->event_data.asynch_error_event_data.ia_handle = (DAT_IA_HANDLE)ia_ptr; +} + +/* dapli_evd_post_overflow_event + * + * post an overflow event + * + * Input: + * async_evd_ptr + * evd_ptr + * + * Output: + * none + * + */ +static void +dapli_evd_post_overflow_event ( + IN DAPL_EVD *async_evd_ptr, + IN DAPL_EVD *overflow_evd_ptr) +{ + DAT_EVENT *overflow_event; + + /* The overflow_evd_ptr mght be the same as evd. + * In that case we've got a catastrophic overflow. + */ + if (async_evd_ptr == overflow_evd_ptr) + { + async_evd_ptr->catastrophic_overflow = DAT_TRUE; + async_evd_ptr->evd_state = DAPL_EVD_STATE_DEAD; + return; + } + + overflow_event = dapli_evd_get_event (overflow_evd_ptr); + if (!overflow_event) + { + /* this is not good */ + overflow_evd_ptr->catastrophic_overflow = DAT_TRUE; + overflow_evd_ptr->evd_state = DAPL_EVD_STATE_DEAD; + return; + } + dapli_evd_format_overflow_event (overflow_evd_ptr, overflow_event); + dapli_evd_post_event (overflow_evd_ptr, overflow_event); + + return; +} + +static DAT_EVENT * +dapli_evd_get_and_init_event ( + IN DAPL_EVD *evd_ptr, + IN DAT_EVENT_NUMBER event_number) +{ + DAT_EVENT *event_ptr; + + event_ptr = dapli_evd_get_event (evd_ptr); + if (NULL == event_ptr) + { + dapli_evd_post_overflow_event ( + evd_ptr->header.owner_ia->async_error_evd, + evd_ptr); + } + else + { + event_ptr->evd_handle = (DAT_EVD_HANDLE) evd_ptr; + event_ptr->event_number = event_number; + } + + return event_ptr; +} + +DAT_RETURN +dapls_evd_post_cr_arrival_event ( + IN DAPL_EVD *evd_ptr, + IN DAT_EVENT_NUMBER event_number, + IN DAT_SP_HANDLE sp_handle, + DAT_IA_ADDRESS_PTR ia_address_ptr, + DAT_CONN_QUAL conn_qual, + DAT_CR_HANDLE cr_handle) +{ + DAT_EVENT *event_ptr; + event_ptr = dapli_evd_get_and_init_event (evd_ptr, event_number); + /* + * Note event lock may be held on successful return + * to be released by dapli_evd_post_event(), if provider side locking + * is needed. + */ + + if (!event_ptr) + { + return DAT_INSUFFICIENT_RESOURCES | DAT_RESOURCE_MEMORY; + } + + event_ptr->event_data.cr_arrival_event_data.sp_handle = sp_handle; + event_ptr->event_data.cr_arrival_event_data.local_ia_address_ptr + = ia_address_ptr; + event_ptr->event_data.cr_arrival_event_data.conn_qual = conn_qual; + event_ptr->event_data.cr_arrival_event_data.cr_handle = cr_handle; + + dapli_evd_post_event (evd_ptr, event_ptr); + return DAT_SUCCESS; +} + + +DAT_RETURN +dapls_evd_post_connection_event ( + IN DAPL_EVD *evd_ptr, + IN DAT_EVENT_NUMBER event_number, + IN DAT_EP_HANDLE ep_handle, + IN DAT_COUNT private_data_size, + IN DAT_PVOID private_data) +{ + DAT_EVENT *event_ptr; + event_ptr = dapli_evd_get_and_init_event (evd_ptr, event_number); + /* + * Note event lock may be held on successful return + * to be released by dapli_evd_post_event(), if provider side locking + * is needed. + */ + + if (!event_ptr) + { + return DAT_INSUFFICIENT_RESOURCES | DAT_RESOURCE_MEMORY; + } + + event_ptr->event_data.connect_event_data.ep_handle = ep_handle; + event_ptr->event_data.connect_event_data.private_data_size + = private_data_size; + event_ptr->event_data.connect_event_data.private_data = private_data; + + dapli_evd_post_event (evd_ptr, event_ptr); + return DAT_SUCCESS; +} + + +DAT_RETURN +dapls_evd_post_async_error_event ( + IN DAPL_EVD *evd_ptr, + IN DAT_EVENT_NUMBER event_number, + IN DAT_IA_HANDLE ia_handle) +{ + DAT_EVENT *event_ptr; + event_ptr = dapli_evd_get_and_init_event (evd_ptr, event_number); + /* + * Note event lock may be held on successful return + * to be released by dapli_evd_post_event(), if provider side locking + * is needed. + */ + + if (!event_ptr) + { + return DAT_INSUFFICIENT_RESOURCES | DAT_RESOURCE_MEMORY; + } + + event_ptr->event_data.asynch_error_event_data.ia_handle = ia_handle; + + dapli_evd_post_event (evd_ptr, event_ptr); + return DAT_SUCCESS; +} + + +DAT_RETURN +dapls_evd_post_software_event ( + IN DAPL_EVD *evd_ptr, + IN DAT_EVENT_NUMBER event_number, + IN DAT_PVOID pointer) +{ + DAT_EVENT *event_ptr; + event_ptr = dapli_evd_get_and_init_event (evd_ptr, event_number); + /* + * Note event lock may be held on successful return + * to be released by dapli_evd_post_event(), if provider side locking + * is needed. + */ + + if (!event_ptr) + { + return DAT_QUEUE_FULL; + } + + event_ptr->event_data.software_event_data.pointer = pointer; + + dapli_evd_post_event (evd_ptr, event_ptr); + return DAT_SUCCESS; +} + +/* + * dapli_evd_cqe_to_event + * + * Convert a CQE into an event structure. + * + * Input: + * evd_ptr + * cqe_ptr + * + * Output: + * event_ptr + * + * Returns: + * ep_ptr + * + */ +static DAPL_EP * +dapli_evd_cqe_to_event ( + IN DAPL_EVD *evd_ptr, + IN ib_work_completion_t *cqe_ptr, + OUT DAT_EVENT *event_ptr) +{ + DAPL_EP *ep_ptr; + DAPL_COOKIE *cookie; + DAT_DTO_COMPLETION_STATUS dto_status; + + /* + * All that can be relied on if the status is bad is the status + * and WRID. + */ + dto_status = dapls_ib_get_dto_status (cqe_ptr); + + cookie = (DAPL_COOKIE *) DAPL_GET_CQE_WRID (cqe_ptr); + dapl_os_assert ( (NULL != cookie) ); + + dapl_dbg_log (DAPL_DBG_TYPE_EVD, + "dapli_evd_cqe_to_event: EP %p cqe %p cqe_type %#x dto_status %#x\n", + cookie->ep, cookie, cookie->type, dto_status); + + ep_ptr = cookie->ep; + dapl_os_assert ( (NULL != ep_ptr) ); + dapl_os_assert ( (ep_ptr->header.magic == DAPL_MAGIC_EP) || + (ep_ptr->header.magic == DAPL_MAGIC_EP_EXIT) ); + + dapls_io_trc_update_completion (ep_ptr, cookie, dto_status); + + event_ptr->evd_handle = (DAT_EVD_HANDLE) evd_ptr; + + switch (cookie->type) + { + case DAPL_COOKIE_TYPE_DTO: + { + DAPL_COOKIE_BUFFER *buffer; + + if ( DAPL_DTO_TYPE_RECV == cookie->val.dto.type ) + { + dapl_os_atomic_dec (&ep_ptr->recv_count); + buffer = &ep_ptr->recv_buffer; + } + else + { + dapl_os_atomic_dec (&ep_ptr->req_count); + buffer = &ep_ptr->req_buffer; + } + + event_ptr->event_number = DAT_DTO_COMPLETION_EVENT; + event_ptr->event_data.dto_completion_event_data.ep_handle = + cookie->ep; + event_ptr->event_data.dto_completion_event_data.user_cookie = + cookie->val.dto.cookie; + event_ptr->event_data.dto_completion_event_data.status = dto_status; + +#ifdef DAPL_DBG + if (dto_status == DAT_DTO_SUCCESS) + { + uint32_t ibtype; + + ibtype = DAPL_GET_CQE_OPTYPE (cqe_ptr); + + dapl_os_assert ((ibtype == OP_SEND && + cookie->val.dto.type == DAPL_DTO_TYPE_SEND) + || (ibtype == OP_RECEIVE && + cookie->val.dto.type == DAPL_DTO_TYPE_RECV) + || (ibtype == OP_RDMA_WRITE && + cookie->val.dto.type == DAPL_DTO_TYPE_RDMA_WRITE) + || (ibtype == OP_RDMA_READ && + cookie->val.dto.type == DAPL_DTO_TYPE_RDMA_READ)); + } +#endif /* DAPL_DBG */ + + if ( cookie->val.dto.type == DAPL_DTO_TYPE_SEND || + cookie->val.dto.type == DAPL_DTO_TYPE_RDMA_WRITE ) + { + /* Get size from DTO; CQE value may be off. */ + event_ptr->event_data.dto_completion_event_data.transfered_length = + cookie->val.dto.size; + } + else + { + event_ptr->event_data.dto_completion_event_data.transfered_length = + DAPL_GET_CQE_BYTESNUM (cqe_ptr); + } + + dapls_cookie_dealloc (buffer, cookie); + break; + } + + case DAPL_COOKIE_TYPE_RMR: + { + dapl_os_atomic_dec (&ep_ptr->req_count); + + event_ptr->event_number = DAT_RMR_BIND_COMPLETION_EVENT; + + event_ptr->event_data.rmr_completion_event_data.rmr_handle = + cookie->val.rmr.rmr; + event_ptr->event_data.rmr_completion_event_data.user_cookie = + cookie->val.rmr.cookie; + if (dto_status == DAT_DTO_SUCCESS) + { + event_ptr->event_data.rmr_completion_event_data.status = + DAT_RMR_BIND_SUCCESS; + dapl_os_assert ((DAPL_GET_CQE_OPTYPE (cqe_ptr)) == OP_BIND_MW); + } + else + { + dapl_dbg_log (DAPL_DBG_TYPE_DTO_COMP_ERR, + " MW bind completion ERROR: %d: op %#x ep: %p\n", + dto_status, + DAPL_GET_CQE_OPTYPE (cqe_ptr), ep_ptr); + event_ptr->event_data.rmr_completion_event_data.status = + DAT_RMR_OPERATION_FAILED; + } + + dapls_cookie_dealloc (&ep_ptr->req_buffer, cookie); + break; + } + default: + { + dapl_os_assert (!"Invalid Operation type"); + break; + } + } /* end switch */ + + /* + * Most error DTO ops result in disconnecting the EP. See + * IBTA Vol 1.1, Chapter 10,Table 68, for expected effect on + * state. + */ + if ((dto_status != DAT_DTO_SUCCESS) && + (dto_status != DAT_DTO_ERR_FLUSHED)) + { + DAPL_EVD *evd_ptr; + + /* + * If we are connected, generate disconnect and generate an + * event. We may be racing with other disconnect ops, so we + * need to check. We may also be racing CM connection events, + * requiring us to check for connection pending states too. + */ + dapl_os_lock ( &ep_ptr->header.lock ); + if (ep_ptr->param.ep_state == DAT_EP_STATE_CONNECTED || + ep_ptr->param.ep_state == DAT_EP_STATE_ACTIVE_CONNECTION_PENDING || + ep_ptr->param.ep_state == DAT_EP_STATE_PASSIVE_CONNECTION_PENDING|| + ep_ptr->param.ep_state == DAT_EP_STATE_COMPLETION_PENDING ) + + { + ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECTED; + dapl_os_unlock ( &ep_ptr->header.lock ); + dapls_io_trc_dump (ep_ptr, cqe_ptr, dto_status); + + /* Let the other side know we have disconnected */ + (void) dapls_ib_disconnect (ep_ptr, DAT_CLOSE_ABRUPT_FLAG); + + /* ... and clean up the local side */ + evd_ptr = (DAPL_EVD *) ep_ptr->param.connect_evd_handle; + if (evd_ptr != NULL) + { + dapls_evd_post_connection_event (evd_ptr, + DAT_CONNECTION_EVENT_BROKEN, + (DAT_HANDLE) ep_ptr, + 0, + 0); + } + } + else + { + dapl_os_unlock ( &ep_ptr->header.lock ); + } + + dapl_dbg_log (DAPL_DBG_TYPE_DTO_COMP_ERR, + " DTO completion ERROR: %d: op %#x (ep disconnected)\n", + DAPL_GET_CQE_STATUS (cqe_ptr), + DAPL_GET_CQE_OPTYPE (cqe_ptr)); + } + return ep_ptr; +} + +/* + * dapls_evd_copy_cq + * + * Copy all entries on a CQ associated with the EVD onto that EVD + * Up to caller to handle races, if any. Note that no EVD waiters will + * be awoken by this copy. + * + * Input: + * evd_ptr + * + * Output: + * None + * + * Returns: + * none + * + */ +void +dapls_evd_copy_cq ( + DAPL_EVD *evd_ptr) +{ + ib_work_completion_t cur_cqe; + DAT_RETURN dat_status; + ib_cq_handle_t cq_handle; + ib_hca_handle_t hca_handle; + DAPL_EP *ep_ptr; + DAT_EVENT *event; + + cq_handle = evd_ptr->ib_cq_handle; + hca_handle = evd_ptr->header.owner_ia->hca_ptr->ib_hca_handle; + + if (cq_handle == IB_INVALID_HANDLE) + { + /* Nothing to do if no CQ. */ + return; + } + + for ( ;; ) + { + dat_status = dapls_ib_completion_poll(hca_handle, + cq_handle, + &cur_cqe); + + if (dat_status != DAT_SUCCESS) + { + break; + } + + /* + * Can use DAT_DTO_COMPLETION_EVENT because dapli_evd_cqe_to_event + * will overwrite. + */ + + event = dapli_evd_get_and_init_event ( + evd_ptr, DAT_DTO_COMPLETION_EVENT ); + if ( event == NULL ) + { + /* We've already attempted the overflow post; return. */ + return; + } + + ep_ptr = dapli_evd_cqe_to_event ( evd_ptr, &cur_cqe, event ); + dapl_os_assert ( (NULL != ep_ptr) ); + + /* For debugging. */ + if (DAPL_GET_CQE_STATUS(&cur_cqe)) + { + dapli_evd_eh_print_cqe(cur_cqe); + dapl_dbg_log (DAPL_DBG_TYPE_DTO_COMP_ERR, + "--> DsECP_ERR: EP=%p QP=%p event=%p state=0x%x \n", + ep_ptr, ep_ptr->qp_handle, + event, ep_ptr->param.ep_state); + } + + if ( (ep_ptr->param.ep_state == DAT_EP_STATE_COMPLETION_PENDING) || + (ep_ptr->param.ep_state == DAT_EP_STATE_ACTIVE_CONNECTION_PENDING) ) + { + dapl_dbg_log (DAPL_DBG_TYPE_WARN, + "--> DsECC: EP = %p QP = %p viol_event = %p VIOL_ORDER\n", + ep_ptr, ep_ptr->qp_handle, event); + + dapl_os_lock (&ep_ptr->header.lock); + ep_ptr->viol_order = TRUE; + dapls_rbuf_add (&ep_ptr->viol_event_queue, + (void *) event); + + dapl_os_unlock (&ep_ptr->header.lock); + + if (evd_ptr->evd_producer_locking_needed) + { + dapl_os_unlock(&evd_ptr->header.lock); + } + } + else + { + dapli_evd_post_event_nosignal ( evd_ptr, event ); + } + } + + if ( DAT_GET_TYPE (dat_status) != DAT_QUEUE_EMPTY) + { + dapl_os_printf( + "dapls_evd_copy_cq: dapls_ib_completion_poll returned 0x%x\n", + dat_status); + //dapl_os_assert(!"Bad return from dapls_ib_completion_poll"); + } +} + +/* + * dapls_evd_cq_poll_to_event + * + * Attempt to dequeue a single CQE from a CQ and turn it into + * an event. + * + * Input: + * evd_ptr + * + * Output: + * event + * + * Returns: + * Status of operation + * + */ +DAT_RETURN +dapls_evd_cq_poll_to_event ( + IN DAPL_EVD *evd_ptr, + OUT DAT_EVENT *event) +{ + DAT_RETURN dat_status; + ib_cq_handle_t cq_handle; + ib_hca_handle_t hca_handle; + ib_work_completion_t cur_cqe; + DAPL_EP *ep_ptr; + DAT_EVENT *viol_event; + + cq_handle = evd_ptr->ib_cq_handle; + hca_handle = evd_ptr->header.owner_ia->hca_ptr->ib_hca_handle; + ep_ptr = NULL; + + dat_status = dapls_ib_completion_poll(hca_handle, + cq_handle, + &cur_cqe); + if (dat_status == DAT_SUCCESS) + { + + + ep_ptr = dapli_evd_cqe_to_event ( evd_ptr, &cur_cqe, event ); + dapl_os_assert ( (NULL != ep_ptr) ); + + /* For debugging. */ + if (DAPL_GET_CQE_STATUS(&cur_cqe)) + { + dapli_evd_eh_print_cqe(cur_cqe); + dapl_dbg_log (DAPL_DBG_TYPE_DTO_COMP_ERR, + "--> DsECPTE_ERR: EP=%p QP=%p event=%p state=0x%x \n", + ep_ptr, ep_ptr->qp_handle, + event, ep_ptr->param.ep_state ); + } + + if ( (ep_ptr->param.ep_state == DAT_EP_STATE_COMPLETION_PENDING) || + (ep_ptr->param.ep_state == DAT_EP_STATE_ACTIVE_CONNECTION_PENDING) ) + { + if (evd_ptr->evd_producer_locking_needed) + { + dapl_os_unlock(&evd_ptr->header.lock); + } + + viol_event = dapli_evd_get_and_init_event ( + evd_ptr, DAT_DTO_COMPLETION_EVENT ); + if ( viol_event == NULL ) + { + return dat_status = DAT_QUEUE_EMPTY; + } + + *viol_event = *event; + + dapl_dbg_log (DAPL_DBG_TYPE_WARN, + "--> DsECPTE: EP = %p QP = %p viol_event = %p VIOL_ORDER\n", + ep_ptr, ep_ptr->qp_handle, viol_event); + + dapl_os_lock (&ep_ptr->header.lock); + ep_ptr->viol_order = TRUE; + dapls_rbuf_add (&ep_ptr->viol_event_queue, + (void *) viol_event); + dapl_os_unlock (&ep_ptr->header.lock); + + if (evd_ptr->evd_producer_locking_needed) + { + dapl_os_unlock(&evd_ptr->header.lock); + } + /* Overiding the status */ + dat_status = DAT_QUEUE_EMPTY; + } + } + + return dat_status; +} + + +DAT_RETURN +dapls_evd_post_viol_event ( + IN DAPL_EVD *evd_ptr, + IN DAT_EVENT *event_ptr) +{ + dapli_evd_post_event(evd_ptr, event_ptr); + return DAT_SUCCESS; +} +#ifdef DAPL_DBG_IO_TRC +/* + * Update I/O completions in the I/O trace buffer. I/O is posted to + * the buffer, then we find it here using the cookie and mark it + * completed with the completion status + */ +void +dapls_io_trc_update_completion ( + DAPL_EP *ep_ptr, + DAPL_COOKIE *cookie, + DAT_DTO_COMPLETION_STATUS dto_status) +{ + int i; + static unsigned int c_cnt = 1; + + for (i = 0; i < DBG_IO_TRC_QLEN; i++) + { + if (ep_ptr->ibt_base[i].cookie == cookie) + { + ep_ptr->ibt_base[i].status = dto_status; + ep_ptr->ibt_base[i].done = c_cnt++; + } + } +} + +/* + * Dump the I/O trace buffers + */ +void +dapls_io_trc_dump ( + DAPL_EP *ep_ptr, + ib_work_completion_t *cqe_ptr, + DAT_DTO_COMPLETION_STATUS dto_status) +{ + struct io_buf_track *ibt; + int i; + int cnt; + + dapl_os_printf ("DISCONNECTING: dto_status = %x\n", dto_status); + dapl_os_printf (" OpType = %x\n", + DAPL_GET_CQE_OPTYPE (cqe_ptr)); + dapl_os_printf (" Bytes = %x\n", + DAPL_GET_CQE_BYTESNUM (cqe_ptr)); + dapl_os_printf (" WRID (cookie) = %llx\n", + DAPL_GET_CQE_WRID (cqe_ptr)); + + if (ep_ptr->ibt_dumped == 0) + { + + dapl_os_printf ("EP %p (qpn %d) I/O trace buffer\n", + ep_ptr, ep_ptr->qpn); + + ep_ptr->ibt_dumped = 1; + ibt = (struct io_buf_track *)dapls_rbuf_remove (&ep_ptr->ibt_queue); + cnt = DBG_IO_TRC_QLEN; + while (ibt != NULL && cnt > 0) + { + dapl_os_printf ("%2d. %3s (%2d, %d) OP: %x cookie %p wqe %p rmv_target_addr %llx rmv_rmr_context %x\n", + cnt, ibt->done == 0 ? "WRK" : "DON", ibt->status, ibt->done, + ibt->op_type, ibt->cookie, ibt->wqe, + ibt->remote_iov.target_address, + ibt->remote_iov.rmr_context); + for (i = 0; i < 3; i++) + { + if (ibt->iov[i].segment_length != 0) + { + dapl_os_printf (" (%4llx, %8x, %8llx)\n", + ibt->iov[i].segment_length, + ibt->iov[i].lmr_context, + ibt->iov[i].virtual_address); + } + } + ibt = (struct io_buf_track *)dapls_rbuf_remove (&ep_ptr->ibt_queue); + cnt--; + } + } +} +#endif /* DAPL_DBG_IO_TRC */ + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_util.h b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_util.h new file mode 100644 index 00000000..7fe76c9f --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_util.h @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dapl_evd_util.h + * + * PURPOSE: Utility defs & routines for the EVD data structure + * + * $Id$ + * + **********************************************************************/ + +#ifndef _DAPL_EVD_UTIL_H_ +#define _DAPL_EVD_UTIL_H_ + +#include "dapl.h" + +DAT_RETURN +dapls_evd_internal_create ( + IN DAPL_IA *ia_ptr, + IN DAPL_CNO *cno_ptr, + IN DAT_COUNT min_qlen, + IN DAT_EVD_FLAGS evd_flags, + OUT DAPL_EVD **evd_ptr_ptr) ; + +DAPL_EVD * +dapls_evd_alloc ( + IN DAPL_IA *ia_ptr, + IN DAPL_CNO *cno_ptr, + IN DAT_EVD_FLAGS evd_flags, + IN DAT_COUNT qlen) ; + +DAT_RETURN +dapls_evd_dealloc ( + IN DAPL_EVD *evd_ptr) ; + +DAT_RETURN dapls_evd_event_realloc ( + IN DAPL_EVD *evd_ptr, + IN DAT_COUNT qlen); + +/* + * Each of these functions will retrieve a free event from + * the specified EVD, fill in the elements of that event, and + * post the event back to the EVD. If there is no EVD available, + * an overflow event will be posted to the async EVD associated + * with the EVD. + * + * DAT_INSUFFICIENT_RESOURCES will be returned on overflow, + * DAT_SUCCESS otherwise. + */ + +DAT_RETURN +dapls_evd_post_cr_arrival_event ( + IN DAPL_EVD *evd_ptr, + IN DAT_EVENT_NUMBER event_number, + IN DAT_SP_HANDLE sp_handle, + DAT_IA_ADDRESS_PTR ia_address_ptr, + DAT_CONN_QUAL conn_qual, + DAT_CR_HANDLE cr_handle); + +DAT_RETURN +dapls_evd_post_connection_event ( + IN DAPL_EVD *evd_ptr, + IN DAT_EVENT_NUMBER event_number, + IN DAT_EP_HANDLE ep_handle, + IN DAT_COUNT private_data_size, + IN DAT_PVOID private_data); + +DAT_RETURN +dapls_evd_post_async_error_event ( + IN DAPL_EVD *evd_ptr, + IN DAT_EVENT_NUMBER event_number, + IN DAT_IA_HANDLE ia_handle); + +DAT_RETURN +dapls_evd_post_software_event ( + IN DAPL_EVD *evd_ptr, + IN DAT_EVENT_NUMBER event_number, + IN DAT_PVOID pointer); + +DAT_RETURN +dapls_evd_post_viol_event ( + IN DAPL_EVD *evd_ptr, + IN DAT_EVENT *event_ptr); + +/************************************* + * dapl internal callbacks functions * + *************************************/ + +/* connection verb callback */ +extern void dapl_evd_connection_callback ( + IN ib_cm_handle_t ib_cm_handle, + IN const ib_cm_events_t ib_cm_events, + IN const void *instant_data_p, + IN const void * context ); + +/* dto verb callback */ +extern void dapl_evd_dto_callback ( + IN ib_hca_handle_t ib_hca_handle, + IN ib_cq_handle_t ib_cq_handle, + IN void* context); + +/* async verb callbacks */ +extern void dapl_evd_un_async_error_callback ( + IN ib_hca_handle_t ib_hca_handle, + IN ib_error_record_t *err_code, + IN void * context); + +extern void dapl_evd_cq_async_error_callback ( + IN ib_hca_handle_t ib_hca_handle, + IN ib_error_record_t *err_code, + IN void * context); + +extern void dapl_evd_qp_async_error_callback ( + IN ib_hca_handle_t ib_hca_handle, + IN ib_error_record_t *err_code, + IN void * context); + +extern void dapls_evd_copy_cq ( + DAPL_EVD *evd_ptr); + +extern DAT_RETURN dapls_evd_cq_poll_to_event ( + IN DAPL_EVD *evd_ptr, + OUT DAT_EVENT *event); + +#endif diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_wait.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_wait.c new file mode 100644 index 00000000..d4189e4c --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_evd_wait.c @@ -0,0 +1,283 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_evd_wait.c + * + * PURPOSE: EVENT management + * + * Description: Interfaces in this file are completely defined in + * the uDAPL 1.1 API specification + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_evd_util.h" +#include "dapl_ring_buffer_util.h" +#include "dapl_adapter_util.h" + +/* + * dapl_evd_wait + * + * UDAPL Requirements Version xxx, + * + * Wait, up to specified timeout, for notification event on EVD. + * Then return first available event. + * + * Input: + * evd_handle + * timeout + * + * Output: + * event + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + * DAT_INVALID_STATE + */ + +DAT_RETURN dapl_evd_wait ( + IN DAT_EVD_HANDLE evd_handle, + IN DAT_TIMEOUT time_out, + IN DAT_COUNT threshold, + OUT DAT_EVENT *event, + OUT DAT_COUNT *nmore) + +{ + DAPL_EVD *evd_ptr; + DAT_RETURN dat_status; + DAT_EVENT *local_event; + DAT_BOOLEAN notify_requested = DAT_FALSE; + DAT_BOOLEAN waitable; + DAPL_EVD_STATE evd_state; + + dapl_dbg_log (DAPL_DBG_TYPE_API, + "dapl_evd_wait (%p, %d, %d, %p, %p)\n", + evd_handle, + time_out, + threshold, + event, + nmore); + DAPL_CNTR(DCNT_EVD_WAIT); + + evd_ptr = (DAPL_EVD *)evd_handle; + dat_status = DAT_SUCCESS; + + if (DAPL_BAD_HANDLE (evd_ptr, DAPL_MAGIC_EVD)) + { + /* + * We return directly rather than bailing because + * bailing attempts to update the evd, and we don't have + * one. + */ + dat_status = DAT_ERROR (DAT_INVALID_HANDLE,0); + goto bail; + } + if (!event) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER,DAT_INVALID_ARG4); + goto bail; + } + if (!nmore) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER,DAT_INVALID_ARG5); + goto bail; + } + if (threshold <= 0 || + (threshold > 1 && evd_ptr->completion_type != DAPL_EVD_STATE_THRESHOLD) || + threshold > evd_ptr->qlen) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER,DAT_INVALID_ARG3); + goto bail; + } + if ( evd_ptr->catastrophic_overflow ) + { + dat_status = DAT_ERROR (DAT_INVALID_STATE,0); + goto bail; + } + + dapl_dbg_log (DAPL_DBG_TYPE_EVD, + "dapl_evd_wait: EVD %p, CQ %p\n", + evd_ptr, + (void *)evd_ptr->ib_cq_handle); + + /* + * Make sure there are no other waiters and the evd is active. + * Currently this means only the OPEN state is allowed. + * Do this atomically. We need to take a lock to synchronize + * with dapl_evd_dequeue(), but the atomic transition allows + * non-locking synchronization with dapl_evd_query() and + * dapl_evd_{query,enable,disable,{set,clear}_unwaitable}. + */ + + dapl_os_lock ( &evd_ptr->header.lock ); + waitable = evd_ptr->evd_waitable; + + dapl_os_assert ( sizeof(DAT_COUNT) == sizeof(DAPL_EVD_STATE) ); + evd_state = dapl_os_atomic_assign ( (DAPL_ATOMIC *)&evd_ptr->evd_state, + (DAT_COUNT) DAPL_EVD_STATE_OPEN, + (DAT_COUNT) DAPL_EVD_STATE_WAITED ); + dapl_os_unlock ( &evd_ptr->header.lock ); + + if ( evd_state != DAPL_EVD_STATE_OPEN ) + { + /* Bogus state, bail out */ + dat_status = DAT_ERROR (DAT_INVALID_STATE,0); + goto bail; + } + + if (!waitable) + { + /* This EVD is not waitable, reset the state and bail */ + (void) dapl_os_atomic_assign ((DAPL_ATOMIC *)&evd_ptr->evd_state, + (DAT_COUNT) DAPL_EVD_STATE_WAITED, + evd_state); + dat_status = DAT_ERROR (DAT_INVALID_STATE, DAT_INVALID_STATE_EVD_UNWAITABLE); + goto bail; + } + + /* + * We now own the EVD, even though we don't have the lock anymore, + * because we're in the WAITED state. + */ + + evd_ptr->threshold = threshold; + + for (;;) + { + /* + * Ideally we'd just check the number of entries on the CQ, but + * we don't have a way to do that. Because we have to set *nmore + * at some point in this routine, we'll need to do this copy + * sometime even if threshold == 1. + * + * For connection evd or async evd, the function checks and + * return right away if the ib_cq_handle associate with these evd + * equal to IB_INVALID_HANDLE + */ + dapls_evd_copy_cq(evd_ptr); + + if (dapls_rbuf_count(&evd_ptr->pending_event_queue) >= threshold) + { + break; + } + + /* + * Do not enable the completion notification if this evd is not + * a DTO_EVD or RMR_BIND_EVD + */ + if ( (!notify_requested) && + ((evd_ptr->evd_flags & DAT_EVD_DTO_FLAG) || + (evd_ptr->evd_flags & DAT_EVD_RMR_BIND_FLAG)) ) + { + dat_status = dapls_ib_completion_notify ( + evd_ptr->header.owner_ia->hca_ptr->ib_hca_handle, + evd_ptr->ib_cq_handle, + (evd_ptr->completion_type == DAPL_EVD_STATE_SOLICITED_WAIT) ? + IB_NOTIFY_ON_SOLIC_COMP : IB_NOTIFY_ON_NEXT_COMP ); + + DAPL_CNTR(DCNT_EVD_WAIT_CMP_NTFY); + /* FIXME report error */ + dapl_os_assert(dat_status == DAT_SUCCESS); + + notify_requested = DAT_TRUE; + + /* Try again. */ + continue; + } + + + /* + * Unused by poster; it has no way to tell how many + * items are on the queue without copying them over to the + * EVD queue, and we're the only ones allowed to dequeue + * from the CQ for synchronization/locking reasons. + */ + evd_ptr->threshold = threshold; + + DAPL_CNTR(DCNT_EVD_WAIT_BLOCKED); + +#ifdef CQ_WAIT_OBJECT + if (evd_ptr->cq_wait_obj_handle) + dat_status = dapls_ib_wait_object_wait ( + evd_ptr->cq_wait_obj_handle, time_out ); + else +#endif + dat_status = dapl_os_wait_object_wait ( + &evd_ptr->wait_object, time_out ); + /* + * FIXME: if the thread loops around and waits again + * the time_out value needs to be updated. + */ + + notify_requested = DAT_FALSE; /* We've used it up. */ + + /* See if we were awakened by evd_set_unwaitable */ + if ( !evd_ptr->evd_waitable ) + { + dat_status = DAT_ERROR (DAT_INVALID_STATE,0); + } + + if (dat_status != DAT_SUCCESS) + { + /* + * If the status is DAT_TIMEOUT, we'll break out of the + * loop, *not* dequeue an event (because dat_status + * != DAT_SUCCESS), set *nmore (as we should for timeout) + * and return DAT_TIMEOUT. + */ + break; + } + } + + evd_ptr->evd_state = DAPL_EVD_STATE_OPEN; + + if (dat_status == DAT_SUCCESS) + { + local_event = dapls_rbuf_remove(&evd_ptr->pending_event_queue); + *event = *local_event; + dapls_rbuf_add(&evd_ptr->free_event_queue, local_event); + } + + /* + * Valid if dat_status == DAT_SUCCESS || dat_status == DAT_TIMEOUT + * Undefined otherwise, so ok to set it. + */ + *nmore = dapls_rbuf_count(&evd_ptr->pending_event_queue); + + bail: + if (dat_status) + { + dapl_dbg_log (DAPL_DBG_TYPE_RTN, "dapl_evd_wait () returns 0x%x\n", + dat_status); + } + + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_get_consumer_context.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_get_consumer_context.c new file mode 100644 index 00000000..90125b1f --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_get_consumer_context.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_get_consumer_context.c + * + * PURPOSE: Interface Adapter management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 2 + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" + +/* + * dapl_get_consumer_context + * + * DAPL Requirements Version xxx, 6.2.2.2 + * + * Gets the consumer context from the specified dat_object + * + * Input: + * dat_handle + * + * Output: + * context + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + */ +DAT_RETURN +dapl_get_consumer_context ( + IN DAT_HANDLE dat_handle, + OUT DAT_CONTEXT *context ) +{ + DAT_RETURN dat_status; + DAPL_HEADER *header; + + dat_status = DAT_SUCCESS; + + header = (DAPL_HEADER *)dat_handle; + if ( ((header) == NULL) || + ((DAT_UVERYLONG)(header) & 3) || + (header->magic != DAPL_MAGIC_IA && + header->magic != DAPL_MAGIC_EVD && + header->magic != DAPL_MAGIC_EP && + header->magic != DAPL_MAGIC_LMR && + header->magic != DAPL_MAGIC_RMR && + header->magic != DAPL_MAGIC_PZ && + header->magic != DAPL_MAGIC_PSP && + header->magic != DAPL_MAGIC_RSP && + header->magic != DAPL_MAGIC_CR)) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE,0); + goto bail; + } + if ( context == NULL || ((DAT_UVERYLONG)(header) & 3) ) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER,DAT_INVALID_ARG2); + goto bail; + } + + *context = header->user_context; + +bail: + return dat_status; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_get_handle_type.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_get_handle_type.c new file mode 100644 index 00000000..009b72fa --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_get_handle_type.c @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_get_handle_type.c + * + * PURPOSE: Interface Adapter management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 2 + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" + +/* + * dapl_get_handle_type + * + * DAPL Requirements Version xxx, 6.2.2.6 + * + * Gets the handle type for the given dat_handle + * + * Input: + * dat_handle + * + * Output: + * handle_type + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + */ + +DAT_RETURN +dapl_get_handle_type ( + IN DAT_HANDLE dat_handle, + OUT DAT_HANDLE_TYPE *handle_type ) +{ + DAT_RETURN dat_status; + DAPL_HEADER *header; + + dat_status = DAT_SUCCESS; + + header = (DAPL_HEADER *)dat_handle; + if ( ((header) == NULL) || + ((DAT_UVERYLONG)(header) & 3) || + (header->magic != DAPL_MAGIC_IA && + header->magic != DAPL_MAGIC_EVD && + header->magic != DAPL_MAGIC_EP && + header->magic != DAPL_MAGIC_LMR && + header->magic != DAPL_MAGIC_RMR && + header->magic != DAPL_MAGIC_PZ && + header->magic != DAPL_MAGIC_PSP && + header->magic != DAPL_MAGIC_RSP && + header->magic != DAPL_MAGIC_CR)) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE,0); + goto bail; + } + *handle_type = header->handle_type; + +bail: + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_hash.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_hash.c new file mode 100644 index 00000000..7b5011ba --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_hash.c @@ -0,0 +1,537 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_hash.c + * + * PURPOSE: Hash Table + * Description: + * + * Provides a generic hash table with chaining. + * + * $Id$ + **********************************************************************/ + +#include "dapl_hash.h" + +/********************************************************************* + * * + * Structures * + * * + *********************************************************************/ + +/* + * A hash table element + */ +typedef struct DAPL_HASH_ELEM +{ + struct DAPL_HASH_ELEM * next_element; + DAPL_HASH_KEY key; + void * datum; +} DAPL_HASH_ELEM; + +/* + * The hash table + */ +struct dapl_hash_table +{ + unsigned long num_entries; + unsigned long tbl_size; + DAPL_HASH_ELEM *table; + DAPL_OS_LOCK lock; + /* + * statistics - we tally on insert operations, counting + * the number of entries in the whole hash table, as + * well as the length of chains we walk to insert. This + * ignores empty buckets, giving us data on overall table + * occupancy, as well as max/average chain length for + * the buckets used. If our hash function results in + * hot buckets, this will show it. + */ + uint64_t hash_tbl_inserts; /* total inserts ops */ + uint64_t hash_tbl_max; /* max in entire table */ + uint64_t hash_tbl_total; /* total in table */ + uint64_t hash_chn_max; /* longest chain */ + uint64_t hash_chn_total; /* total non-0 lenghts */ +}; + + +/********************************************************************* + * * + * Defines * + * * + *********************************************************************/ + +/* datum value in empty table slots (use 0UL or ~0UL as appropriate) */ +#define NO_DATUM_VALUE ((void *) 0UL) +#define NO_DATUM(value) ((value) == NO_DATUM_VALUE) + +/* Lookup macro (which falls back to function to rehash) */ +#define DAPL_HASHLOOKUP( p_table, in_key, out_datum, bucket_head) \ + { \ + DAPL_HASH_KEY save_key = in_key; \ + DAPL_HASH_ELEM *element = \ + &((p_table)->table)[DAPL_DOHASH(in_key,(p_table)->tbl_size)]; \ + in_key = save_key; \ + if (NO_DATUM(element->datum)) { \ + (bucket_head) = (void *)0; \ + } else if (element->key == (DAPL_HASH_KEY) (in_key)) { \ + (out_datum) = element->datum; \ + (bucket_head) = (void *)element; \ + } else if (element->next_element) { \ + dapli_hash_rehash(element, \ + (in_key), \ + (void **)&(out_datum), \ + (DAPL_HASH_ELEM **)&(bucket_head)); \ + } else { \ + (bucket_head) = (void *)0; \ + }\ + } + + +/********************************************************************* + * * + * Internal Functions * + * * + *********************************************************************/ + +/* + * Rehash the key (used by add and lookup functions) + * + * Inputs: element element to rehash key + * key, datum datum for key head + * head head for list + */ +static void +dapli_hash_rehash ( + DAPL_HASH_ELEM * element, + DAPL_HASH_KEY key, + void **datum, + DAPL_HASH_ELEM ** head) +{ + /* + * assume we looked at the contents of element already, + * and start with the next element. + */ + dapl_os_assert (element->next_element); + dapl_os_assert (!NO_DATUM (element->datum)); + + *head = element; + for(;;) + { + element = element->next_element; + if (!element) + { + break; + } + if (element->key == key) + { + *datum = element->datum; + return; + } + } + *head = 0; +} + +/* + * Add a new key to the hash table + * + * Inputs: + * table, key and datum to be added + * allow_dup - DAT_TRUE if dups are allowed + * Outputs: + * report_dup - should you care to know + * Returns: + * DAT_TRUE on success + */ +static DAT_BOOLEAN +dapli_hash_add ( + DAPL_HASH_TABLEP p_table, + DAPL_HASH_KEY key, + void *datum, + DAT_BOOLEAN allow_dup, + DAT_BOOLEAN * report_dup) +{ + void *olddatum; + DAPL_HASH_KEY hashValue, save_key = key; + DAPL_HASH_ELEM *found; + DAT_BOOLEAN status = DAT_FALSE; + unsigned int chain_len = 0; + + if (report_dup) + { + (*report_dup) = DAT_FALSE; + } + + if (NO_DATUM (datum)) + { + /* + * Reserved value used for datum + */ + dapl_dbg_log ( + DAPL_DBG_TYPE_ERR, + "dapli_hash_add () called with magic NO_DATA value (%p) " + "used as datum!\n", datum); + return DAT_FALSE; + } + + DAPL_HASHLOOKUP (p_table, key, olddatum, found); + if (found) + { + /* + * key exists already + */ + if (report_dup) + { + *report_dup = DAT_TRUE; + } + + if (!allow_dup) + { + dapl_dbg_log ( + DAPL_DBG_TYPE_ERR, + "dapli_hash_add () called with duplicate key (" F64x ")\n", + key); + return DAT_FALSE; + } + } + + hashValue = DAPL_DOHASH (key, p_table->tbl_size); + key = save_key; + if (NO_DATUM (p_table->table[hashValue].datum)) + { + /* + * Empty head - just fill it in + */ + p_table->table[hashValue].key = key; + p_table->table[hashValue].datum = datum; + p_table->table[hashValue].next_element = 0; + p_table->num_entries++; + status = DAT_TRUE; + } + else + { + DAPL_HASH_ELEM *newelement = (DAPL_HASH_ELEM *) + dapl_os_alloc (sizeof (DAPL_HASH_ELEM)); + /* + * Add an element to the end of the chain + */ + if (newelement) + { + DAPL_HASH_ELEM *lastelement; + newelement->key = key; + newelement->datum = datum; + newelement->next_element = 0; + for (lastelement = &p_table->table[hashValue]; + lastelement->next_element; + lastelement = lastelement->next_element) + { + /* Walk to the end of the chain */ + chain_len++; + } + lastelement->next_element = newelement; + p_table->num_entries++; + status = DAT_TRUE; + } + else + { + /* allocation failed - should not happen */ + status = DAT_FALSE; + } + } + + /* + * Tally up our counters. chain_len is one less than current chain + * length. + */ + chain_len++; + p_table->hash_tbl_inserts++; + p_table->hash_tbl_total += p_table->num_entries; + p_table->hash_chn_total += chain_len; + if (p_table->num_entries > p_table->hash_tbl_max) + { + p_table->hash_tbl_max = p_table->num_entries; + } + if (chain_len > p_table->hash_chn_max) + { + p_table->hash_chn_max = chain_len; + } + + return status; +} + + +/* + * Remove element from hash bucket + * + * Inputs: + * element, key to be deleted + * Returns: + * DAT_TRUE on success + */ +static DAT_BOOLEAN +dapl_hash_delete_element (DAPL_HASH_ELEM * element, + DAPL_HASH_KEY key, + DAPL_HASH_DATA *p_datum) +{ + DAPL_HASH_ELEM *curelement; + DAPL_HASH_ELEM *lastelement; + + lastelement = NULL; + for (curelement = element; + curelement; + lastelement = curelement, curelement = curelement->next_element) + { + if (curelement->key == key) + { + if (p_datum) + { + *p_datum = curelement->datum; + } + if (lastelement) + { + /* + * curelement was malloc'd; free it + */ + lastelement->next_element = curelement->next_element; + dapl_os_free ((void *) curelement, sizeof (DAPL_HASH_ELEM)); + } + else + { + /* + * curelement is static list head + */ + DAPL_HASH_ELEM *n = curelement->next_element; + if (n) + { + /* + * If there is a next element, copy its contents into the + * head and free the original next element. + */ + curelement->key = n->key; + curelement->datum = n->datum; + curelement->next_element = n->next_element; + dapl_os_free ((void *) n, sizeof (DAPL_HASH_ELEM)); + } + else + { + curelement->datum = NO_DATUM_VALUE; + } + } + break; + } + } + + return ( curelement != NULL ? DAT_TRUE : DAT_FALSE ); +} + + +/********************************************************************* + * * + * External Functions * + * * + *********************************************************************/ + + +/* + * Create a new hash table with at least 'table_size' hash buckets. + */ +DAT_RETURN +dapls_hash_create ( + IN DAT_COUNT table_size, + OUT DAPL_HASH_TABLE **pp_table) +{ + DAPL_HASH_TABLE *p_table; + DAT_COUNT table_length = table_size * sizeof (DAPL_HASH_ELEM); + DAT_RETURN dat_status; + DAT_COUNT i; + + dapl_os_assert (pp_table); + dat_status = DAT_SUCCESS; + + /* Allocate hash table */ + p_table = dapl_os_alloc (sizeof (DAPL_HASH_TABLE)); + if (NULL == p_table) + { + dat_status = DAT_ERROR (DAT_INSUFFICIENT_RESOURCES,DAT_RESOURCE_MEMORY); + goto bail; + } + + /* Init hash table, allocate and init and buckets */ + dapl_os_memzero (p_table, sizeof (DAPL_HASH_TABLE)); + p_table->tbl_size = table_size; + p_table->table = (DAPL_HASH_ELEM *) dapl_os_alloc (table_length); + if (NULL == p_table->table) + { + dapl_os_free (p_table, sizeof (DAPL_HASH_TABLE)); + dat_status = DAT_ERROR (DAT_INSUFFICIENT_RESOURCES,DAT_RESOURCE_MEMORY); + goto bail; + } + + dapl_os_lock_init (&p_table->lock); + for (i = 0; i < table_size; i++) + { + p_table->table[i].datum = NO_DATUM_VALUE; + p_table->table[i].key = 0; + p_table->table[i].next_element = 0; + } + + *pp_table = p_table; + + bail: + return DAT_SUCCESS; +} + + +/* + * Destroy a hash table + */ +DAT_RETURN +dapls_hash_free ( + IN DAPL_HASH_TABLE *p_table) +{ + dapl_os_assert (p_table && p_table->table); + + dapl_os_lock_destroy (&p_table->lock); + dapl_os_free (p_table->table, sizeof (DAPL_HASH_ELEM) * p_table->tbl_size); + dapl_os_free (p_table, sizeof (DAPL_HASH_TABLE)); + + return DAT_SUCCESS; +} + + +/* + * Returns the number of elements stored in the table + */ + +DAT_RETURN +dapls_hash_size ( + IN DAPL_HASH_TABLE *p_table, + OUT DAT_COUNT *p_size) +{ + dapl_os_assert (p_table && p_size); + + *p_size = p_table->num_entries; + + return DAT_SUCCESS; +} + + +/* + * Inserts the specified data into the table with the given key. + * Duplicates are not expected, and return in error, having done nothing. + */ + +DAT_RETURN +dapls_hash_insert ( + IN DAPL_HASH_TABLE *p_table, + IN DAPL_HASH_KEY key, + IN DAPL_HASH_DATA data) +{ + DAT_RETURN dat_status; + + dapl_os_assert (p_table); + dat_status = DAT_SUCCESS; + + dapl_os_lock (&p_table->lock); + if (!dapli_hash_add (p_table, key, data, DAT_FALSE, NULL)) + { + dat_status = DAT_ERROR (DAT_INSUFFICIENT_RESOURCES,DAT_RESOURCE_MEMORY); + } + dapl_os_unlock (&p_table->lock); + + return dat_status; +} + + +/* + * Searches for the given key. If found, + * DAT_SUCCESS is returned and the associated + * data is returned in the DAPL_HASH_DATA + * pointer if that pointer is not NULL. + */ +DAT_RETURN +dapls_hash_search ( + IN DAPL_HASH_TABLE *p_table, + IN DAPL_HASH_KEY key, + OUT DAPL_HASH_DATA *p_data) +{ + DAT_RETURN dat_status; + void *olddatum = NULL; + DAPL_HASH_ELEM *found; + + dapl_os_assert (p_table); + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER,0); + + dapl_os_lock (&p_table->lock); + DAPL_HASHLOOKUP (p_table, key, olddatum, found); + dapl_os_unlock (&p_table->lock); + + if (found) + { + if (p_data) + { + *p_data = olddatum; + } + dat_status = DAT_SUCCESS; + } + + return dat_status; +} + + +DAT_RETURN +dapls_hash_remove ( + IN DAPL_HASH_TABLE *p_table, + IN DAPL_HASH_KEY key, + OUT DAPL_HASH_DATA *p_data) +{ + DAT_RETURN dat_status; + DAPL_HASH_KEY hashValue, save_key = key; + + dapl_os_assert (p_table); + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER,0); + + if (p_table->num_entries == 0) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "dapls_hash_remove () called on empty hash table!\n"); + return dat_status; + } + + hashValue = DAPL_DOHASH (key, p_table->tbl_size); + key = save_key; + dapl_os_lock (&p_table->lock); + if (dapl_hash_delete_element (&p_table->table[hashValue], key, p_data)) + { + p_table->num_entries--; + dat_status = DAT_SUCCESS; + } + dapl_os_unlock (&p_table->lock); + + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_hash.h b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_hash.h new file mode 100644 index 00000000..0c5c15b4 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_hash.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dapl_hash.h + * + * PURPOSE: Utility defs & routines for the hash data structure + * + * $Id$ + **********************************************************************/ + +#ifndef _DAPL_HASH_H_ +#define _DAPL_HASH_H_ + +#include "dapl.h" + + +/********************************************************************* + * * + * Defines * + * * + *********************************************************************/ + +/* + * Hash table size. + * + * Default is small; use the larger sample values for hash tables + * known to be heavily used. The sample values chosen are the + * largest primes below 2^8, 2^9, and 2^10. + */ +#define DAPL_DEF_HASHSIZE 251 +#define DAPL_MED_HASHSIZE 509 +#define DAPL_LRG_HASHSIZE 1021 + +#define DAPL_HASH_TABLE_DEFAULT_CAPACITY DAPL_DEF_HASHSIZE + +/* The hash function */ +#define DAPL_DOHASH(key,hashsize) ((uint64_t)((key) % (hashsize))) + +/********************************************************************* + * * + * Function Prototypes * + * * + *********************************************************************/ + +extern DAT_RETURN +dapls_hash_create( + IN DAT_COUNT capacity, + OUT DAPL_HASH_TABLE **pp_table); + +extern DAT_RETURN +dapls_hash_free( + IN DAPL_HASH_TABLE *p_table); + +extern DAT_RETURN +dapls_hash_size( + IN DAPL_HASH_TABLE *p_table, + OUT DAT_COUNT *p_size); + +extern DAT_RETURN +dapls_hash_insert( + IN DAPL_HASH_TABLE *p_table, + IN DAPL_HASH_KEY key, + IN DAPL_HASH_DATA data); + +extern DAT_RETURN +dapls_hash_search( + IN DAPL_HASH_TABLE *p_table, + IN DAPL_HASH_KEY key, + OUT DAPL_HASH_DATA *p_data); + +extern DAT_RETURN +dapls_hash_remove( + IN DAPL_HASH_TABLE *p_table, + IN DAPL_HASH_KEY key, + OUT DAPL_HASH_DATA *p_data); + + +#endif /* _DAPL_HASH_H_ */ diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_hca_util.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_hca_util.c new file mode 100644 index 00000000..87204727 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_hca_util.c @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_hca_util.c + * + * PURPOSE: Manage HCA structure + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_adapter_util.h" +#include "dapl_provider.h" +#include "dapl_hca_util.h" +#include "dapl_hash.h" + + +/* + * dapl_hca_alloc + * + * alloc and initialize an HCA struct + * + * Input: + * name + * port + * + * Output: + * hca_ptr + * + * Returns: + * none + * + */ +DAPL_HCA * +dapl_hca_alloc ( + char *name, + char *port ) +{ + DAPL_HCA *hca_ptr; + + hca_ptr = dapl_os_alloc (sizeof (DAPL_HCA)); + if ( NULL != hca_ptr ) + { + dapl_os_memzero (hca_ptr, sizeof (DAPL_HCA)); + + if ( DAT_SUCCESS == dapls_hash_create ( + DAPL_HASH_TABLE_DEFAULT_CAPACITY, &hca_ptr->lmr_hash_table) ) + { + dapl_os_lock_init(&hca_ptr->lock); + dapl_llist_init_head(&hca_ptr->ia_list_head); + + hca_ptr->name = dapl_ib_convert_name(name); + hca_ptr->ib_hca_handle = IB_INVALID_HANDLE; + hca_ptr->port_num = (ib_hca_port_t)dapl_os_strtol(port, NULL, 0); + hca_ptr->null_ib_cq_handle = IB_INVALID_HANDLE; + } + else + { + dapl_os_free (hca_ptr, sizeof (DAPL_HCA)); + hca_ptr = NULL; + } + } + + return (hca_ptr); +} + +/* + * dapl_hca_free + * + * free an IA INFO struct + * + * Input: + * hca_ptr + * + * Output: + * none + * + * Returns: + * none + * + */ +void +dapl_hca_free ( DAPL_HCA *hca_ptr ) +{ + (void) dapls_hash_free ( hca_ptr->lmr_hash_table ); + dapl_os_free (hca_ptr, sizeof (DAPL_HCA)); +} + +/* + * dapl_hca_link_ia + * + * Add an ia to the HCA structure + * + * Input: + * hca_ptr + * ia_ptr + * + * Output: + * none + * + * Returns: + * none + * + */ +void +dapl_hca_link_ia ( + IN DAPL_HCA *hca_ptr, + IN DAPL_IA *ia_ptr) +{ + dapl_os_lock (&hca_ptr->lock); + dapl_llist_add_head (&hca_ptr->ia_list_head, + &ia_ptr->hca_ia_list_entry, + ia_ptr); + dapl_os_unlock (&hca_ptr->lock); +} + +/* + * dapl_hca_unlink_ia + * + * Remove an ia from the hca info structure + * + * Input: + * hca_ptr + * ia_ptr + * + * Output: + * none + * + * Returns: + * none + * + */ +void +dapl_hca_unlink_ia ( + IN DAPL_HCA *hca_ptr, + IN DAPL_IA *ia_ptr) +{ + dapl_os_lock (&hca_ptr->lock); + /* + * If an error occurred when we were opening the IA it + * will not be linked on the list; don't unlink an unlinked + * list! + */ + if ( ! dapl_llist_is_empty (&hca_ptr->ia_list_head) ) + { + dapl_llist_remove_entry (&hca_ptr->ia_list_head, + &ia_ptr->hca_ia_list_entry); + } + dapl_os_unlock (&hca_ptr->lock); +} diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_hca_util.h b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_hca_util.h new file mode 100644 index 00000000..f722e70d --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_hca_util.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dapl_hca_util.h + * + * PURPOSE: Utility defs & routines for the HCA data structure + * + * $Id$ + **********************************************************************/ + +#ifndef _DAPL_HCA_UTIL_H_ +#define _DAPL_HCA_UTIL_H_ + +#include "dapl.h" + +DAPL_HCA * +dapl_hca_alloc ( char *name, + char *port ) ; + +void +dapl_hca_free ( DAPL_HCA *hca_ptr ) ; + +void +dapl_hca_link_ia ( + IN DAPL_HCA *hca_ptr, + IN DAPL_IA *ia_info ) ; + +void +dapl_hca_unlink_ia ( + IN DAPL_HCA *hca_ptr, + IN DAPL_IA *ia_info ) ; + + +#endif diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ia_close.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ia_close.c new file mode 100644 index 00000000..d2652f25 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ia_close.c @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ia_close.c + * + * PURPOSE: Interface Adapter management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 2 + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_ia_util.h" + +/* + * dapl_ia_close + * + * DAPL Requirements Version xxx, 6.2.1.2 + * + * Close a provider, clean up resources, etc. + * + * Input: + * ia_handle + * + * Output: + * none + * + * Return Values: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + */ +DAT_RETURN +dapl_ia_close ( + IN DAT_IA_HANDLE ia_handle, + IN DAT_CLOSE_FLAGS ia_flags) +{ + DAPL_IA *ia_ptr; + DAT_RETURN dat_status; + + dapl_dbg_log (DAPL_DBG_TYPE_API, + "dapl_ia_close (%p, %d)\n", + ia_handle, + ia_flags); + + ia_ptr = (DAPL_IA *)ia_handle; + + if (DAPL_BAD_HANDLE (ia_ptr, DAPL_MAGIC_IA)) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE,DAT_INVALID_HANDLE_IA); + goto bail; + } + + if ( DAT_CLOSE_ABRUPT_FLAG == ia_flags ) + { + dat_status = dapl_ia_abrupt_close (ia_ptr); + } + else if ( DAT_CLOSE_GRACEFUL_FLAG == ia_flags ) + { + dat_status = dapl_ia_graceful_close (ia_ptr); + } + else + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER,DAT_INVALID_ARG2); + } + + bail: + + if (dat_status) + printf ("dapl_ia_close (%p, %d) RC %d\n",ia_handle,ia_flags,dat_status); + + return dat_status; +} + diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ia_open.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ia_open.c new file mode 100644 index 00000000..283cfdbc --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ia_open.c @@ -0,0 +1,529 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ia_open.c + * + * PURPOSE: Interface Adapter management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 2 + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_provider.h" +#include "dapl_evd_util.h" +#include "dapl_hca_util.h" +#include "dapl_ia_util.h" +#include "dapl_adapter_util.h" + +#ifndef NO_NAME_SERVICE +#include "dapl_name_service.h" +#endif + +/* + * LOCAL PROTOTYPES + */ +#ifdef IBHOSTS_NAMING +void dapli_assign_hca_ip_address( + DAPL_HCA *hca_ptr, + char *device_name); +#endif +char *dapli_get_adapter_num ( + char *device_name); + +void dapli_setup_dummy_addr( + IN DAPL_HCA *hca_ptr, + IN char *hca_name); + +void dapli_hca_cleanup ( + DAPL_HCA *hca_ptr, + DAT_BOOLEAN dec_ref ); + +int32_t dapl_ib_init_complete = FALSE; + +/* + * dapl_ia_open + * + * DAPL Requirements Version xxx, 6.2.1.1 + * + * Open a provider and return a handle. The handle enables the user + * to invoke operations on this provider. + * + * The dat_ia_open call is actually part of the DAT registration module. + * That function maps the DAT_NAME parameter of dat_ia_open to a DAT_PROVIDER, + * and calls this function. + * + * Input: + * provider + * async_evd_qlen + * async_evd_handle_ptr + * + * Output: + * async_evd_handle + * ia_handle + * + * Return Values: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + * DAT_INVALID_HANDLE + * DAT_PROVIDER_NOT_FOUND (returned by dat registry if necessary) + */ +DAT_RETURN +dapl_ia_open ( + IN const DAT_NAME_PTR name, + IN DAT_COUNT async_evd_qlen, + INOUT DAT_EVD_HANDLE *async_evd_handle_ptr, + OUT DAT_IA_HANDLE *ia_handle_ptr) +{ + DAT_RETURN dat_status; + DAT_PROVIDER *provider; + DAPL_HCA *hca_ptr; + DAPL_IA *ia_ptr; + DAPL_EVD *evd_ptr; + + dat_status = DAT_SUCCESS; + hca_ptr = NULL; + ia_ptr = NULL; + + dapl_dbg_log (DAPL_DBG_TYPE_API, + "dapl_ia_open (%s, %d, %p, %p)\n", + name, + async_evd_qlen, + async_evd_handle_ptr, + ia_handle_ptr); + + /* Initialize IB verbs library and provider list */ + if ( !dapl_ib_init_complete ) + { + dapls_ib_init (); + dapl_ib_init_complete = TRUE; + + /* initialize the provider list */ + dat_status = dapl_provider_list_create(); + if (DAT_SUCCESS != dat_status) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "dapl_provider_list_create failed %d\n", dat_status); + goto bail; + } + } + + dat_status = dapl_provider_list_search (name, &provider); + if (dat_status != DAT_SUCCESS) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER, DAT_INVALID_ARG1); + goto bail; + } + + /* ia_handle_ptr and async_evd_handle_ptr cannot be NULL */ + if (ia_handle_ptr == NULL) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER, DAT_INVALID_ARG4); + goto bail; + } + if (async_evd_handle_ptr == NULL) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER, DAT_INVALID_ARG3); + goto bail; + } + + /* initialize the caller's OUT param */ + *ia_handle_ptr = DAT_HANDLE_NULL; + + /* get the hca_ptr */ + hca_ptr = (DAPL_HCA *)provider->extension; + + /* + * Open the HCA if it has not been done before. + */ + dapl_os_lock (&hca_ptr->lock); + if (hca_ptr->ib_hca_handle == IB_INVALID_HANDLE ) + { + /* register with the HW */ + dat_status = dapls_ib_open_hca (hca_ptr->name, + &hca_ptr->ib_hca_handle); + + if (dat_status != DAT_SUCCESS) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "dapls_ib_open_hca failed %d\n", dat_status); + dapl_os_unlock (&hca_ptr->lock); + goto bail; + } + + /* create a cq domain for this HCA */ + dat_status = dapls_ib_cqd_create (hca_ptr); + + if (dat_status != DAT_SUCCESS) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "ERR: Cannot allocate CQD: err 0x%x\n", + dat_status); + dapli_hca_cleanup (hca_ptr, DAT_FALSE); + dapl_os_unlock (&hca_ptr->lock); + goto bail; + } + /* + * Obtain the IP address associated with this name and HCA. + */ +#ifdef IBHOSTS_NAMING + dapli_assign_hca_ip_address (hca_ptr, name); +#endif + /* + * Obtain IA attributes from the HCA to limit certain operations. + * If using DAPL_ATS naming, ib_query_hca will also set the ip + * address -- FIXME: will revisit this when add DAPL_ATS flag + */ + dat_status = dapls_ib_query_hca (hca_ptr, + &hca_ptr->ia_attr, + NULL, + &hca_ptr->hca_address); + if (dat_status != DAT_SUCCESS) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "dapls_ib_query_hca failed 0x%x\n", dat_status); + dapli_hca_cleanup (hca_ptr, DAT_FALSE); + dapl_os_unlock (&hca_ptr->lock); + goto bail; + } + + } + + /* Take a reference on the hca_handle */ + dapl_os_atomic_inc (& hca_ptr->handle_ref_count ); + dapl_os_unlock (&hca_ptr->lock); + + /* Allocate and initialize ia structure */ + ia_ptr = dapl_ia_alloc (provider, hca_ptr); + if (!ia_ptr) + { + dapl_os_lock (&hca_ptr->lock); + dapli_hca_cleanup (hca_ptr, DAT_TRUE); + dapl_os_unlock (&hca_ptr->lock); + dat_status = DAT_ERROR (DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); + goto bail; + } + + /* we need an async EVD for this IA + * use the one passed in (if non-NULL) or create one + */ + + evd_ptr = (DAPL_EVD *) *async_evd_handle_ptr; + if (evd_ptr) + { + if (evd_ptr != DAT_EVD_ASYNC_EXISTS) + { + if (DAPL_BAD_HANDLE (evd_ptr, DAPL_MAGIC_EVD) || + ! (evd_ptr->evd_flags & DAT_EVD_ASYNC_FLAG)) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EVD_ASYNC); + goto bail; + } + + /* InfiniBand allows only 1 asychronous event handler per HCA */ + /* (see InfiniBand Spec, release 1.1, vol I, section 11.5.2, */ + /* page 559). */ + /* */ + /* We need only make sure that this EVD's CQ belongs to */ + /* the same HCA as is being opened. */ + + if ( evd_ptr->header.owner_ia->hca_ptr->ib_hca_handle != + hca_ptr->ib_hca_handle ) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EVD_ASYNC); + goto bail; + } + + ia_ptr->cleanup_async_error_evd = DAT_FALSE; + ia_ptr->async_error_evd = evd_ptr; + } + } + else + { + /* + * Verify we have > 0 length, and let the provider check the size + */ + if (async_evd_qlen <= 0) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER, DAT_INVALID_ARG2); + goto bail; + } + dat_status = dapls_evd_internal_create (ia_ptr, + NULL, /* CNO ptr */ + async_evd_qlen, + DAT_EVD_ASYNC_FLAG, + &evd_ptr); + if (dat_status != DAT_SUCCESS) + { + goto bail; + } + + /* Reference to the EVD from the IA/async event stream. */ + dapl_os_atomic_inc (& evd_ptr->evd_ref_count); + + dapl_os_lock ( &hca_ptr->lock ); + if ( hca_ptr->async_evd != (DAPL_EVD *) 0 ) + { + /* + * The async EVD for this HCA has already been assigned. + * It's an error to try and assign another one. + */ + + dapl_os_atomic_dec ( &evd_ptr->evd_ref_count ); + dapl_evd_free ( evd_ptr ); + /* + dapl_os_unlock ( &hca_ptr->lock ); + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER, DAT_INVALID_ARG4); + goto bail; + */ + ia_ptr->cleanup_async_error_evd = DAT_FALSE; + ia_ptr->async_error_evd = hca_ptr->async_evd; + dapl_os_unlock ( &hca_ptr->lock ); + + dat_status = DAT_SUCCESS; + *async_evd_handle_ptr = hca_ptr->async_evd; + } + else + { + hca_ptr->async_evd = evd_ptr; + dapl_os_unlock ( &hca_ptr->lock ); + + ia_ptr->cleanup_async_error_evd = DAT_TRUE; + ia_ptr->async_error_evd = evd_ptr; + + /* Register the handlers associated with the async EVD. */ + dat_status = dapls_ia_setup_callbacks ( ia_ptr, evd_ptr ); + if ( dat_status != DAT_SUCCESS ) + { + goto bail; + } + *async_evd_handle_ptr = evd_ptr; + } + } + + *ia_handle_ptr = ia_ptr; + +bail: + if (dat_status != DAT_SUCCESS) + { + if (ia_ptr) + { + dapl_ia_close (ia_ptr, DAT_CLOSE_ABRUPT_FLAG); + } + } + + dapl_dbg_log (DAPL_DBG_TYPE_RTN, + "dapl_ia_open() returns 0x%x\n", dat_status); + + return (dat_status); +} + +/* + * dapli_hca_cleanup + * + * Clean up partially allocated HCA stuff. Strictly to make cleanup + * simple. + */ +void +dapli_hca_cleanup ( + DAPL_HCA *hca_ptr, + DAT_BOOLEAN dec_ref ) +{ + dapls_ib_close_hca (hca_ptr->ib_hca_handle); + hca_ptr->ib_hca_handle = IB_INVALID_HANDLE; + if ( dec_ref == DAT_TRUE ) + { + dapl_os_atomic_dec (& hca_ptr->handle_ref_count ); + } +} + + +/* + * dapli_assign_hca_ip_address + * + * Obtain the IP address of the adapter. This is a simple + * scheme that creates a name that must appear available to + * DNS, e.g. it must be in the local site DNS or in the local + * /etc/hosts file, etc. + * + * -ib + * + * This scheme obviously doesn't work with adapters from + * multiple vendors, but will suffice in common installations. + * + * Input: + * hca_ptr Pointer to HCA structure + * device_name Name of device as reported by the provider + * + * Output: + * none + * + * Returns: + * char * to string number + */ + +#define NAMELEN 128 + +void +dapli_assign_hca_ip_address ( + DAPL_HCA *hca_ptr, + char *device_name) +{ + char *adapter_num; +#ifdef IBHOSTS_NAMING + struct addrinfo *addr; +#endif + char hostname[NAMELEN]; + char *str; + int rc; + + rc = gethostname (hostname, NAMELEN); + + /* + * Strip off domain info if it exists (e.g. mynode.mydomain.com) + */ + for (str = hostname; *str && *str != '.'; ) + { + str++; + } + if ( *str == '.' ) + { + *str = '\0'; + } + strcat (hostname, "_ib"); + adapter_num = dapli_get_adapter_num (device_name); + strcat (hostname, adapter_num); + +#ifdef IBHOSTS_NAMING + rc = dapls_osd_getaddrinfo (hostname, &addr); + if(!rc) + { + hca_ptr->hca_address = *((DAT_SOCK_ADDR6 *)addr->ai_addr); + return; + } + dapls_osd_freeaddrinfo(addr); +#endif /* IBHOSTS_NAMING */ + /* Not registered in DNS, provide a dummy value */ + dapli_setup_dummy_addr(hca_ptr, hostname); +#if 0 + dapl_os_memzero (&hca_ptr->hca_address, sizeof (DAT_SOCK_ADDR6)); + + hca_ptr->hca_address.sin6_family = AF_INET6; + + dapl_os_memcpy (&hca_ptr->hca_address.sin6_addr.s6_addr[12], + &((struct sockaddr_in *)addr->ai_addr)->sin_addr.s_addr, + 4); +#endif +} + + +/* + * dapli_stup_dummy_addr + * + * Set up a dummy local address for the HCA. Things are not going + * to work too well if this happens. + * We call this routine if: + * - remote host adapter name is not in DNS + * - IPoIB implementation is not correctly set up + * - Similar nonsense. + * + * Input: + * hca_ptr + * rhost_name Name of remote adapter + * + * Output: + * none + * + * Returns: + * none + */ +void +dapli_setup_dummy_addr ( + IN DAPL_HCA *hca_ptr, + IN char *rhost_name ) +{ + struct sockaddr_in *si; + + /* Not registered in DNS, provide a dummy value */ + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "WARNING: <%s> not registered in DNS, using dummy IP value\n", + rhost_name); + si = (struct sockaddr_in *)&hca_ptr->hca_address; + hca_ptr->hca_address.sin6_family = AF_INET; + si->sin_addr.s_addr = 0x01020304; +} + + +/* + * dapls_get_adapter_num + * + * Given a device name, return a string of the device number + * + * Input: + * device_name Name of device as reported by the provider + * + * Output: + * none + * + * Returns: + * char * to string number + */ +char * +dapli_get_adapter_num ( + char *device_name) +{ + static char *zero = "0"; + char *p; + + /* + * Optimisticaly simple algorithm: the device number appears at + * the end of the device name string. Device that do not end + * in a number are by default "0". + */ + + for (p = device_name; *p; p++) + { + if ( isdigit (*p) ) + { + return p; + } + } + + return zero; +} + + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ia_query.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ia_query.c new file mode 100644 index 00000000..c213b050 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ia_query.c @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ia_query.c + * + * PURPOSE: Interface Adapter management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 2 + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_adapter_util.h" +#include "dapl_vendor.h" + +/* + * dapl_ia_query + * + * DAPL Requirements Version xxx, 6.2.1.3 + * + * Provide the consumer with Interface Adapter and Provider parameters. + * + * Input: + * ia_handle + * ia_mask + * provider_mask + * + * Output: + * async_evd_handle + * ia_parameters + * provider_parameters + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + */ +DAT_RETURN +dapl_ia_query ( + IN DAT_IA_HANDLE ia_handle, + OUT DAT_EVD_HANDLE *async_evd_handle, + IN DAT_IA_ATTR_MASK ia_attr_mask, + OUT DAT_IA_ATTR *ia_attr, + IN DAT_PROVIDER_ATTR_MASK provider_attr_mask, + OUT DAT_PROVIDER_ATTR *provider_attr ) +{ + DAPL_IA *ia_ptr; + DAT_RETURN dat_status; + struct evd_merge_type { + DAT_BOOLEAN array[6][6]; + } *evd_merge; + DAT_BOOLEAN val; + int i; + int j; + + dapl_dbg_log (DAPL_DBG_TYPE_API, + "dapl_ia_query (%p, %p, 0x%x, %p, 0x%x, %p)\n", + ia_handle, + async_evd_handle, + ia_attr_mask, + ia_attr, + provider_attr_mask, + provider_attr); + + ia_ptr = (DAPL_IA *)ia_handle; + dat_status = DAT_SUCCESS; + + if (DAPL_BAD_HANDLE (ia_ptr, DAPL_MAGIC_IA)) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_IA); + goto bail; + } + + if ( NULL != async_evd_handle ) + { + *async_evd_handle = ia_ptr->async_error_evd; + } + + if ( ia_attr_mask & DAT_IA_ALL ) + { + if ( NULL == ia_attr ) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER, DAT_INVALID_ARG4); + goto bail; + } + + /* + * Obtain parameters from the HCA. Protect against multiple + * IAs beating on the HCA at the same time. + */ + dat_status = dapls_ib_query_hca (ia_ptr->hca_ptr, ia_attr, NULL, NULL); + if (dat_status != DAT_SUCCESS) + { + goto bail; + } + } + + if ( ia_attr_mask & ~DAT_IA_ALL ) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER, DAT_INVALID_ARG3); + goto bail; + } + + if ( provider_attr_mask & DAT_PROVIDER_FIELD_ALL ) + { + if ( NULL == provider_attr ) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER, DAT_INVALID_ARG6); + goto bail; + } + + dapl_os_memcpy ( provider_attr->provider_name, + ia_ptr->header.provider->device_name, + min ((int)dapl_os_strlen (ia_ptr->header.provider->device_name),(int)DAT_NAME_MAX_LENGTH ) ); + provider_attr->provider_version_major = VN_PROVIDER_MAJOR; + provider_attr->provider_version_minor = VN_PROVIDER_MINOR; + provider_attr->dapl_version_major = DAT_VERSION_MAJOR; + provider_attr->dapl_version_minor = DAT_VERSION_MINOR; + provider_attr->lmr_mem_types_supported = + DAT_MEM_TYPE_VIRTUAL | DAT_MEM_TYPE_LMR; +#if VN_MEM_SHARED_VIRTUAL_SUPPORT > 0 + provider_attr->lmr_mem_types_supported |= DAT_MEM_TYPE_SHARED_VIRTUAL; +#endif + provider_attr->iov_ownership_on_return = DAT_IOV_CONSUMER; + provider_attr->dat_qos_supported = DAT_QOS_BEST_EFFORT; + provider_attr->completion_flags_supported = DAT_COMPLETION_DEFAULT_FLAG; + provider_attr->is_thread_safe = DAT_THREADSAFE; + /* + * N.B. The second part of the following equation will evaluate + * to 0 unless IBHOSTS_NAMING is enabled. + */ + provider_attr->max_private_data_size = + dapls_ib_private_data_size (NULL, DAPL_PDATA_CONN_REQ) - + (sizeof (DAPL_PRIVATE) - DAPL_MAX_PRIVATE_DATA_SIZE); + provider_attr->supports_multipath = DAT_FALSE; + provider_attr->ep_creator = DAT_PSP_CREATES_EP_NEVER; + provider_attr->optimal_buffer_alignment = DAT_OPTIMAL_ALIGNMENT; + provider_attr->num_provider_specific_attr = 0; + provider_attr->provider_specific_attr = NULL; + /* + * Set up evd_stream_merging_supported options. Note there is + * one bit per allowable combination, using the ordinal + * position of the DAT_EVD_FLAGS as positions in the + * array. e.g. + * [0][0] is DAT_EVD_SOFTWARE_FLAG | DAT_EVD_SOFTWARE_FLAG, + * [0][1] is DAT_EVD_SOFTWARE_FLAG | DAT_EVD_CR_FLAG, and + * [2][4] is DAT_EVD_DTO_FLAG | DAT_EVD_RMR_BIND_FLAG + * + * Most combinations are true, so initialize the array that way. + * Then finish by resetting the bad combinations. + * + * DAT_EVD_ASYNC_FLAG is not supported. InfiniBand only allows + * a single asynchronous event handle per HCA, and the first + * dat_ia_open forces the creation of the only one that can be + * used. We disallow the user from creating an ASYNC EVD here. + */ + + evd_merge = (struct evd_merge_type *)&provider_attr->evd_stream_merging_supported[0][0]; + val = DAT_TRUE; + for ( i = 0; i < 6; i++) + { + if (i > 4) + { + /* ASYNC EVD is 5, so entire row will be 0 */ + val = DAT_FALSE; + } + for ( j = 0; j < 5; j++) + { + evd_merge->array[i][j] = val; + } + /* Set the ASYNC_EVD column to FALSE */ + evd_merge->array[i][5] = DAT_FALSE; + } + +#ifndef DAPL_MERGE_CM_DTO + /* DAT_EVD_DTO_FLAG | DAT_EVD_CONNECTION_FLAG */ + evd_merge->array[2][3] = DAT_FALSE; + /* DAT_EVD_CONNECTION_FLAG | DAT_EVD_DTO_FLAG */ + evd_merge->array[3][2] = DAT_FALSE; +#endif + } + +bail: + if (dat_status) + { + dapl_dbg_log (DAPL_DBG_TYPE_RTN, "dapl_ia_query () returns 0x%x\n", + dat_status); + } + + return dat_status; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ia_util.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ia_util.c new file mode 100644 index 00000000..6a970db6 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ia_util.c @@ -0,0 +1,1244 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ia_util.c + * + * PURPOSE: Manage IA Info structure + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_hca_util.h" +#include "dapl_ia_util.h" +#include "dapl_sp_util.h" +#include "dapl_evd_util.h" +#include "dapl_cno_util.h" +#include "dapl_cr_util.h" +#include "dapl_adapter_util.h" +#ifndef NO_NAME_SERVICE +#include "dapl_name_service.h" +#endif + +/* Internal prototype */ +void dapli_ia_release_hca ( + DAPL_HCA *hca_ptr ); + + +/* + * dapl_ia_alloc + * + * alloc and initialize an IA INFO struct + * + * Input: + * none + * + * Output: + * ia_ptr + * + * Returns: + * none + * + */ +DAPL_IA * +dapl_ia_alloc ( DAT_PROVIDER * provider, DAPL_HCA * hca_ptr ) +{ + DAPL_IA * ia_ptr; + + /* Allocate IA */ + ia_ptr = (DAPL_IA *) dapl_os_alloc (sizeof (DAPL_IA)); + if (ia_ptr == NULL) + { + return (NULL); + } + + /* zero the structure */ + dapl_os_memzero (ia_ptr, sizeof (DAPL_IA)); + + /* + * initialize the header + */ + ia_ptr->header.provider = provider; + ia_ptr->header.magic = DAPL_MAGIC_IA; + ia_ptr->header.handle_type = DAT_HANDLE_TYPE_IA; + ia_ptr->header.owner_ia = ia_ptr; + ia_ptr->header.user_context.as_64 = 0; + ia_ptr->header.user_context.as_ptr = NULL; + dapl_llist_init_entry (&ia_ptr->header.ia_list_entry); + dapl_os_lock_init (&ia_ptr->header.lock); + + /* + * initialize the body + */ + ia_ptr->hca_ptr = hca_ptr; + ia_ptr->async_error_evd = NULL; + ia_ptr->cleanup_async_error_evd = DAT_FALSE; + dapl_llist_init_entry (&ia_ptr->hca_ia_list_entry); + dapl_llist_init_head (&ia_ptr->ep_list_head); + dapl_llist_init_head (&ia_ptr->lmr_list_head); + dapl_llist_init_head (&ia_ptr->rmr_list_head); + dapl_llist_init_head (&ia_ptr->pz_list_head); + dapl_llist_init_head (&ia_ptr->evd_list_head); + dapl_llist_init_head (&ia_ptr->cno_list_head); + dapl_llist_init_head (&ia_ptr->rsp_list_head); + dapl_llist_init_head (&ia_ptr->psp_list_head); + + dapl_hca_link_ia (hca_ptr, ia_ptr); + + return (ia_ptr); +} + + +/* + * dapl_ia_abrupt_close + * + * Performs an abrupt close of the IA + * + * Input: + * ia_ptr + * + * Output: + * none + * + * Returns: + * status + * + */ + + +DAT_RETURN +dapl_ia_abrupt_close ( + IN DAPL_IA *ia_ptr ) +{ + DAT_RETURN dat_status; + DAPL_EP *ep_ptr, *next_ep_ptr; + DAPL_LMR *lmr_ptr, *next_lmr_ptr; + DAPL_RMR *rmr_ptr, *next_rmr_ptr; + DAPL_PZ *pz_ptr, *next_pz_ptr; + DAPL_EVD *evd_ptr, *next_evd_ptr; + DAPL_CNO *cno_ptr, *next_cno_ptr; + DAPL_SP *sp_ptr, *next_sp_ptr; /* for PSP and RSP queues */ + DAPL_CR *cr_ptr, *next_cr_ptr; + DAPL_HCA *hca_ptr; + + dapl_dbg_log (DAPL_DBG_TYPE_API | DAPL_DBG_TYPE_CM, + "dapl_ia_abrupt_close (%p)\n",ia_ptr); + + dat_status = DAT_SUCCESS; + + /* + * clear all the data structures associated with the IA. + * this must be done in order (rmr,rsp) before (ep lmr psp) before + * (pz evd) + * + * Note that in all the following we can leave the loop either + * when we run out of entries, or when we get back to the head + * if we end up skipping an entry. + */ + + rmr_ptr = (dapl_llist_is_empty (&ia_ptr->rmr_list_head) + ? NULL : dapl_llist_peek_head (&ia_ptr->rmr_list_head)); + while (rmr_ptr != NULL) + { + next_rmr_ptr = dapl_llist_next_entry (&ia_ptr->rmr_list_head, + &rmr_ptr->header.ia_list_entry); + dat_status = dapl_rmr_free (rmr_ptr); + if (dat_status != DAT_SUCCESS) + { + dapl_dbg_log (DAPL_DBG_TYPE_WARN, + "ia_close(ABRUPT): rmr_free(%p) returns %x\n", + rmr_ptr, + dat_status ); + } + rmr_ptr = next_rmr_ptr; + } + + sp_ptr = (dapl_llist_is_empty (&ia_ptr->rsp_list_head) + ? NULL : dapl_llist_peek_head (&ia_ptr->rsp_list_head)); + while (sp_ptr != NULL) + { + next_sp_ptr = dapl_llist_next_entry (&ia_ptr->rsp_list_head, + &sp_ptr->header.ia_list_entry); + dat_status = dapl_rsp_free (sp_ptr); + if (dat_status != DAT_SUCCESS) + { + dapl_dbg_log (DAPL_DBG_TYPE_WARN, + "ia_close(ABRUPT): rsp_free(%p) returns %x\n", + sp_ptr, + dat_status ); + } + sp_ptr = next_sp_ptr; + } + + ep_ptr = (dapl_llist_is_empty (&ia_ptr->ep_list_head) + ? NULL : dapl_llist_peek_head (&ia_ptr->ep_list_head)); + while (ep_ptr != NULL) + { + next_ep_ptr = dapl_llist_next_entry (&ia_ptr->ep_list_head, + &ep_ptr->header.ia_list_entry); + /* + * Issue a disconnect if the EP needs it + */ + if ( ep_ptr->param.ep_state == DAT_EP_STATE_CONNECTED || + ep_ptr->param.ep_state == DAT_EP_STATE_DISCONNECTED || + ep_ptr->param.ep_state == DAT_EP_STATE_ACTIVE_CONNECTION_PENDING || + ep_ptr->param.ep_state == DAT_EP_STATE_COMPLETION_PENDING || + ep_ptr->param.ep_state == DAT_EP_STATE_DISCONNECT_PENDING ) + { + dat_status = dapl_ep_disconnect (ep_ptr, DAT_CLOSE_ABRUPT_FLAG); + if (dat_status != DAT_SUCCESS) + { + dapl_dbg_log (DAPL_DBG_TYPE_WARN, + "ia_close(ABRUPT): ep_disconnect(%p) returns %x\n", + ep_ptr, + dat_status ); + } + } + /* force the EP into error state to force flush all posted DTOs. */ + { + DAT_EP_ATTR ep_attr; + DAT_NAMED_ATTR ep_state; + + dapl_os_memzero (&ep_attr, sizeof (DAT_EP_ATTR)); + ep_state.name = (char *)IB_QP_STATE; + ep_state.value = (char *)DAPL_QP_STATE_ERROR; + ep_attr.ep_provider_specific_count = 1; + ep_attr.ep_provider_specific = &ep_state; + + (void) dapls_ib_qp_modify (ia_ptr, + ep_ptr, + &ep_attr ); + } + + dat_status = dapl_ep_free (ep_ptr); + if (dat_status != DAT_SUCCESS) + { + dapl_dbg_log (DAPL_DBG_TYPE_WARN, + "ia_close(ABRUPT): ep_free(%p) returns %x\n", + ep_ptr, + dat_status ); + } + ep_ptr = next_ep_ptr; + } + + lmr_ptr = (dapl_llist_is_empty (&ia_ptr->lmr_list_head) + ? NULL : dapl_llist_peek_head (&ia_ptr->lmr_list_head)); + while (lmr_ptr != NULL) + { + next_lmr_ptr = dapl_llist_next_entry (&ia_ptr->lmr_list_head, + &lmr_ptr->header.ia_list_entry); + dat_status = dapl_lmr_free (lmr_ptr); + if (dat_status != DAT_SUCCESS) + { + dapl_dbg_log (DAPL_DBG_TYPE_WARN, + "ia_close(ABRUPT): lmr_free(%p) returns %x\n", + lmr_ptr, + dat_status ); + } + lmr_ptr = next_lmr_ptr; + } + + sp_ptr = (dapl_llist_is_empty (&ia_ptr->psp_list_head) + ? NULL : dapl_llist_peek_head (&ia_ptr->psp_list_head)); + while (sp_ptr != NULL) + { + /* + * Shut down the PSP so we get no further callbacks. There + * should be no competing threads after this. + */ + dat_status = dapls_ib_remove_conn_listener (ia_ptr, + sp_ptr); + if (dat_status != DAT_SUCCESS) + { + dapl_dbg_log (DAPL_DBG_TYPE_WARN, + "ia_close(ABRUPT): psp cannot remove listener, returns %x\n", + dat_status); + } + + next_sp_ptr = dapl_llist_next_entry (&ia_ptr->psp_list_head, + &sp_ptr->header.ia_list_entry); + + /* Remove CR's from this PSP and clean them up */ + cr_ptr = dapl_llist_is_empty (&sp_ptr->cr_list_head) ? NULL : + dapl_llist_peek_head (&sp_ptr->cr_list_head); + while (cr_ptr != NULL) + { + next_cr_ptr = dapl_llist_next_entry (&sp_ptr->cr_list_head, + &cr_ptr->header.ia_list_entry); + /* Remove the CR from the queue & cleanup*/ + dapl_os_lock (&sp_ptr->header.lock); + dapl_sp_remove_cr (sp_ptr, cr_ptr); + dapl_os_unlock (&sp_ptr->header.lock); + + dapls_cr_free (cr_ptr); + cr_ptr = next_cr_ptr; + } + + dat_status = dapl_psp_free (sp_ptr); + if (dat_status != DAT_SUCCESS) + { + dapl_dbg_log (DAPL_DBG_TYPE_WARN, + "ia_close(ABRUPT): psp_free(%p) returns %x\n", + sp_ptr, + dat_status ); + } + + sp_ptr = next_sp_ptr; + } + + pz_ptr = (dapl_llist_is_empty (&ia_ptr->pz_list_head) + ? NULL : dapl_llist_peek_head (&ia_ptr->pz_list_head)); + while (pz_ptr != NULL) + { + next_pz_ptr = dapl_llist_next_entry (&ia_ptr->pz_list_head, + &pz_ptr->header.ia_list_entry); + dat_status = dapl_pz_free (pz_ptr); + if (dat_status != DAT_SUCCESS) + { + dapl_dbg_log (DAPL_DBG_TYPE_WARN, + "ia_close(ABRUPT): pz_free(%p) returns %x\n", + pz_ptr, + dat_status ); + } + pz_ptr = next_pz_ptr; + } + + /* + * EVDs are tricky; we want to release all except for the async + * EVD. That EVD needs to stick around until after we close the + * HCA, to accept any async events that occur. So we cycle through + * the list with dapl_llist_next_entry instead of dapl_llist_is_empty. + */ + evd_ptr = (dapl_llist_is_empty (&ia_ptr->evd_list_head) + ? NULL : dapl_llist_peek_head (&ia_ptr->evd_list_head)); + while (evd_ptr != NULL) + { + next_evd_ptr = dapl_llist_next_entry (&ia_ptr->evd_list_head, + &evd_ptr->header.ia_list_entry); + if (evd_ptr == ia_ptr->async_error_evd) + { + /* Don't delete the EVD, but break any CNO connections. */ + dapl_evd_disable(evd_ptr); + dapl_evd_modify_cno(evd_ptr, DAT_HANDLE_NULL); + } + else + { + /* it isn't the async EVD; delete it. */ + dat_status = dapl_evd_free (evd_ptr); + if (dat_status != DAT_SUCCESS) + { + dapl_dbg_log (DAPL_DBG_TYPE_WARN, + "ia_close(ABRUPT): evd_free(%p) returns %x\n", + evd_ptr, + dat_status ); + } + } + evd_ptr = next_evd_ptr; + } + + cno_ptr = (dapl_llist_is_empty (&ia_ptr->cno_list_head) + ? NULL : dapl_llist_peek_head (&ia_ptr->cno_list_head)); + while (cno_ptr != NULL) + { + next_cno_ptr = dapl_llist_next_entry (&ia_ptr->cno_list_head, + &cno_ptr->header.ia_list_entry); + if (cno_ptr->cno_waiters > 0) + { + /* Notify the waiter the IA is going away: see uDAPL 1.1 spec, + * 6.3.2.3 + */ + dapl_cno_trigger (cno_ptr, NULL); + } + /* clean up the CNO */ + dat_status = dapl_cno_free (cno_ptr); + if (dat_status != DAT_SUCCESS) + { + dapl_dbg_log (DAPL_DBG_TYPE_WARN, + "ia_close(ABRUPT): cno_free(%p) returns %x\n", + cno_ptr, + dat_status ); + } + cno_ptr = next_cno_ptr; + } + + hca_ptr = ia_ptr->hca_ptr; + + /* + * Free the async EVD, shutting down callbacks from the HCA. + */ + if ( ia_ptr->async_error_evd && + (DAT_TRUE == ia_ptr->cleanup_async_error_evd) ) + { + dat_status = dapls_ia_teardown_callbacks ( ia_ptr ); + + hca_ptr->async_evd = NULL; /* It was our async EVD; nuke it. */ + + dapl_os_atomic_dec (& ia_ptr->async_error_evd->evd_ref_count); + dat_status = dapl_evd_free (ia_ptr->async_error_evd); + + if (DAT_SUCCESS != dat_status) + { + dapl_dbg_log (DAPL_DBG_TYPE_WARN, + "ia_close(ABRUPT): evd_free(%p) returns %x\n", + ia_ptr->async_error_evd, + dat_status ); + } + + ia_ptr->async_error_evd = NULL; + } + + /* + * Release our reference on the hca_handle. If we are the last + * one, close it + */ + dapli_ia_release_hca (hca_ptr); + + dapls_ia_free (ia_ptr); + + return DAT_SUCCESS; /* Abrupt close can't fail. */ +} + + +/* + * dapl_ia_graceful_close + * + * Performs an graceful close of the IA + * + * Input: + * ia_ptr + * + * Output: + * none + * + * Returns: + * status + * + */ + +DAT_RETURN +dapl_ia_graceful_close ( + IN DAPL_IA *ia_ptr ) +{ + DAT_RETURN dat_status; + DAT_RETURN cur_dat_status; + DAPL_EVD *evd_ptr; + DAPL_LLIST_ENTRY *entry; + DAPL_HCA *hca_ptr; + + dat_status = DAT_SUCCESS; + + if ( !dapl_llist_is_empty (&ia_ptr->rmr_list_head) || + !dapl_llist_is_empty (&ia_ptr->rsp_list_head) || + !dapl_llist_is_empty (&ia_ptr->ep_list_head) || + !dapl_llist_is_empty (&ia_ptr->lmr_list_head) || + !dapl_llist_is_empty (&ia_ptr->psp_list_head) || + !dapl_llist_is_empty (&ia_ptr->pz_list_head) ) + { + dat_status = DAT_ERROR (DAT_INVALID_STATE, DAT_INVALID_STATE_IA_IN_USE); + goto bail; + } + + /* if the async evd does not need to be cleaned up */ + /* (ie. it was not created by dapl_ia_open) */ + /* then the evd list should be empty */ + if ( DAT_FALSE == ia_ptr->cleanup_async_error_evd ) + { + if ( !dapl_llist_is_empty (&ia_ptr->evd_list_head) ) + { + dat_status = DAT_ERROR (DAT_INVALID_STATE, DAT_INVALID_STATE_IA_IN_USE); + goto bail; + } + } + /* else the async evd should be the only evd in */ + /* the list. */ + else + { + evd_ptr = (dapl_llist_is_empty (&ia_ptr->evd_list_head) + ? NULL : dapl_llist_peek_head (&ia_ptr->evd_list_head)); + + if ( evd_ptr != NULL && + ! (evd_ptr->evd_flags & DAT_EVD_ASYNC_FLAG) ) + { + dat_status = DAT_ERROR (DAT_INVALID_STATE, DAT_INVALID_STATE_IA_IN_USE); + goto bail; + } + + entry = ia_ptr->evd_list_head; + + /* if the async evd is not the only element in the list */ + if ( entry->blink != entry->flink ) + { + dat_status = DAT_ERROR (DAT_INVALID_STATE, DAT_INVALID_STATE_IA_IN_USE); + goto bail; + } + + /* + * If the async evd has a non-unary ref count (i.e. it's in + * use by someone besides us. + */ + if ( evd_ptr->evd_ref_count != 1 ) + { + dat_status = DAT_ERROR (DAT_INVALID_STATE, DAT_INVALID_STATE_IA_IN_USE); + goto bail; + } + } + + /* + * We've validated the call; now we can start the teardown. + * Because we're in the IA close routine, we're safe from races with DAPL + * consumers on this IA (operate/destroy races are disallowed in + * DAPL). + */ + hca_ptr = ia_ptr->hca_ptr; + + /* Tear down the async EVD if needed, first shutting down callbacks. */ + if ( ia_ptr->async_error_evd && + (DAT_TRUE == ia_ptr->cleanup_async_error_evd) ) + { + cur_dat_status = dapls_ia_teardown_callbacks ( ia_ptr ); + if ( DAT_SUCCESS != cur_dat_status ) + { + dat_status = cur_dat_status; + } + hca_ptr->async_evd = NULL; + dapl_os_atomic_dec (& ia_ptr->async_error_evd->evd_ref_count); + cur_dat_status = dapl_evd_free (ia_ptr->async_error_evd); + if ( DAT_SUCCESS != cur_dat_status ) + { + dat_status = cur_dat_status; + } + + ia_ptr->async_error_evd = NULL; + } + + dapli_ia_release_hca (hca_ptr); + + dapls_ia_free (ia_ptr); + +bail: + return dat_status; +} + +/* + * Release a reference on the HCA handle. If it is 0, close the + * handle. Manipulate under lock to prevent races with threads trying to + * open the HCA. + */ +void +dapli_ia_release_hca ( + DAPL_HCA *hca_ptr ) +{ + DAT_RETURN dat_status; + + dapl_os_lock (&hca_ptr->lock); + dapl_os_atomic_dec (& hca_ptr->handle_ref_count ); + if ( hca_ptr->handle_ref_count == 0 ) + { + +#ifndef NO_NAME_SERVICE + /* + * Remove an record {ServiceID, IP-address} + */ + dat_status = dapls_ns_remove_gid_map (hca_ptr); + + if (DAT_SUCCESS != dat_status) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "dapls_ns_revmove_gid_map failed %d\n", dat_status); + } + +#endif /* NO_NAME_SERVICE */ + + /* + * Get rid of the cqd associated with the hca. + * Print out instead of status return as this routine + * shouldn't fail. + */ + dat_status = dapls_ib_cqd_destroy (hca_ptr); + if (dat_status != DAT_SUCCESS) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "ERR: Cannot free CQD: err %x\n", dat_status); + } + + dat_status = dapls_ib_close_hca (hca_ptr->ib_hca_handle); + if (dat_status != DAT_SUCCESS) + { + /* this is not good - I mean, this is bad! */ + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "<1> ERROR: hca_close failed %d\n", dat_status); + } + hca_ptr->ib_hca_handle = IB_INVALID_HANDLE; + } + dapl_os_unlock (&hca_ptr->lock); +} + + +/* + * dapls_ia_free + * + * free an IA INFO struct + * + * Input: + * ia_ptr + * + * Output: + * one + * + * Returns: + * none + * + */ +void +dapls_ia_free ( DAPL_IA *ia_ptr ) +{ + dapl_os_assert (ia_ptr->header.magic == DAPL_MAGIC_IA); + + dapl_os_assert (ia_ptr->async_error_evd == NULL); + dapl_os_assert (dapl_llist_is_empty (&ia_ptr->lmr_list_head)); + dapl_os_assert (dapl_llist_is_empty (&ia_ptr->rmr_list_head)); + dapl_os_assert (dapl_llist_is_empty (&ia_ptr->ep_list_head)); + dapl_os_assert (dapl_llist_is_empty (&ia_ptr->evd_list_head)); + dapl_os_assert (dapl_llist_is_empty (&ia_ptr->cno_list_head)); + dapl_os_assert (dapl_llist_is_empty (&ia_ptr->psp_list_head)); + dapl_os_assert (dapl_llist_is_empty (&ia_ptr->rsp_list_head)); + + /* + * deinitialize the header + */ + dapl_hca_unlink_ia (ia_ptr->hca_ptr, ia_ptr); + ia_ptr->header.magic = DAPL_MAGIC_INVALID; /* reset magic to prevent reuse */ + dapl_os_lock_destroy (&ia_ptr->header.lock); + + dapl_os_free (ia_ptr, sizeof (DAPL_IA)); +} + +/* + * dapl_ia_link_ep + * + * Add an ep to the IA structure + * + * Input: + * ia_ptr + * ep_ptr + * + * Output: + * none + * + * Returns: + * none + * + */ +void +dapl_ia_link_ep ( + IN DAPL_IA *ia_ptr, + IN DAPL_EP *ep_ptr) +{ + dapl_os_lock (&ia_ptr->header.lock); + dapl_llist_add_head (&ia_ptr->ep_list_head, + &ep_ptr->header.ia_list_entry, + ep_ptr); + dapl_os_unlock (&ia_ptr->header.lock); +} + +/* + * dapl_ia_unlink_ep + * + * Remove an ep from the ia info structure + * + * Input: + * ia_ptr + * ep_ptr + * + * Output: + * none + * + * Returns: + * none + * + */ +void +dapl_ia_unlink_ep ( + IN DAPL_IA *ia_ptr, + IN DAPL_EP *ep_ptr) +{ + dapl_os_lock (&ia_ptr->header.lock); + dapl_llist_remove_entry (&ia_ptr->ep_list_head, + &ep_ptr->header.ia_list_entry); + dapl_os_unlock (&ia_ptr->header.lock); +} + +/* + * dapl_ia_link_lmr + * + * Add an lmr to the IA structure + * + * Input: + * ia_ptr + * lmr_ptr + * + * Output: + * none + * + * Returns: + * none + * + */ +void +dapl_ia_link_lmr ( + IN DAPL_IA *ia_ptr, + IN DAPL_LMR *lmr_ptr) +{ + dapl_os_lock (&ia_ptr->header.lock); + dapl_llist_add_head (&ia_ptr->lmr_list_head, + &lmr_ptr->header.ia_list_entry, + lmr_ptr); + dapl_os_unlock (&ia_ptr->header.lock); +} + +/* + * dapl_ia_unlink_lmr + * + * Remove an lmr from the ia info structure + * + * Input: + * ia_ptr + * lmr_ptr + * + * Output: + * none + * + * Returns: + * none + * + */ +void +dapl_ia_unlink_lmr ( + IN DAPL_IA *ia_ptr, + IN DAPL_LMR *lmr_ptr) +{ + dapl_os_lock (&ia_ptr->header.lock); + dapl_llist_remove_entry (&ia_ptr->lmr_list_head, + &lmr_ptr->header.ia_list_entry); + dapl_os_unlock (&ia_ptr->header.lock); +} + +/* + * dapl_ia_link_rmr + * + * Add an rmr to the IA structure + * + * Input: + * ia_ptr + * rmr_ptr + * + * Output: + * none + * + * Returns: + * none + * + */ +void +dapl_ia_link_rmr ( + IN DAPL_IA *ia_ptr, + IN DAPL_RMR *rmr_ptr) +{ + dapl_os_lock (&ia_ptr->header.lock); + dapl_llist_add_head (&ia_ptr->rmr_list_head, + &rmr_ptr->header.ia_list_entry, + rmr_ptr); + dapl_os_unlock (&ia_ptr->header.lock); +} + +/* + * dapl_ia_unlink_rmr + * + * Remove an rmr from the ia info structure + * + * Input: + * ia_ptr + * rmr_ptr + * + * Output: + * none + * + * Returns: + * none + * + */ +void +dapl_ia_unlink_rmr ( + IN DAPL_IA *ia_ptr, + IN DAPL_RMR *rmr_ptr) +{ + dapl_os_lock (&ia_ptr->header.lock); + dapl_llist_remove_entry (&ia_ptr->rmr_list_head, + &rmr_ptr->header.ia_list_entry); + dapl_os_unlock (&ia_ptr->header.lock); +} + +/* + * dapl_ia_link_pz + * + * Add an pz to the IA structure + * + * Input: + * ia_ptr + * pz_ptr + * + * Output: + * none + * + * Returns: + * none + * + */ +void +dapl_ia_link_pz ( + IN DAPL_IA *ia_ptr, + IN DAPL_PZ *pz_ptr) +{ + dapl_os_lock (&ia_ptr->header.lock); + dapl_llist_add_head (&ia_ptr->pz_list_head, + &pz_ptr->header.ia_list_entry, + pz_ptr); + dapl_os_unlock (&ia_ptr->header.lock); +} + +/* + * dapl_ia_unlink_pz + * + * Remove an pz from the ia info structure + * + * Input: + * ia_ptr + * pz_ptr + * + * Output: + * none + * + * Returns: + * none + * + */ +void +dapl_ia_unlink_pz ( + IN DAPL_IA *ia_ptr, + IN DAPL_PZ *pz_ptr) +{ + dapl_os_lock (&ia_ptr->header.lock); + dapl_llist_remove_entry (&ia_ptr->pz_list_head, + &pz_ptr->header.ia_list_entry); + dapl_os_unlock (&ia_ptr->header.lock); +} + +/* + * dapl_ia_link_evd + * + * Add an evd to the IA structure + * + * Input: + * ia_ptr + * evd_ptr + * + * Output: + * none + * + * Returns: + * none + * + */ +void +dapl_ia_link_evd ( + IN DAPL_IA *ia_ptr, + IN DAPL_EVD *evd_ptr) +{ + dapl_os_lock (&ia_ptr->header.lock); + dapl_llist_add_head (&ia_ptr->evd_list_head, + &evd_ptr->header.ia_list_entry, + evd_ptr); + dapl_os_unlock (&ia_ptr->header.lock); +} + +/* + * dapl_ia_unlink_evd + * + * Remove an evd from the ia info structure + * + * Input: + * ia_ptr + * evd_ptr + * + * Output: + * none + * + * Returns: + * none + * + */ +void +dapl_ia_unlink_evd ( + IN DAPL_IA *ia_ptr, + IN DAPL_EVD *evd_ptr) +{ + dapl_os_lock (&ia_ptr->header.lock); + dapl_llist_remove_entry (&ia_ptr->evd_list_head, + &evd_ptr->header.ia_list_entry); + dapl_os_unlock (&ia_ptr->header.lock); +} + +/* + * dapl_ia_link_cno + * + * Add an cno to the IA structure + * + * Input: + * ia_ptr + * cno_ptr + * + * Output: + * none + * + * Returns: + * none + * + */ +void +dapl_ia_link_cno ( + IN DAPL_IA *ia_ptr, + IN DAPL_CNO *cno_ptr) +{ + dapl_os_lock (&ia_ptr->header.lock); + dapl_llist_add_head (&ia_ptr->cno_list_head, + &cno_ptr->header.ia_list_entry, + cno_ptr); + dapl_os_unlock (&ia_ptr->header.lock); +} + +/* + * dapl_ia_unlink_cno + * + * Remove an cno from the ia info structure + * + * Input: + * ia_ptr + * cno_ptr + * + * Output: + * none + * + * Returns: + * none + * + */ +void +dapl_ia_unlink_cno ( + IN DAPL_IA *ia_ptr, + IN DAPL_CNO *cno_ptr) +{ + dapl_os_lock (&ia_ptr->header.lock); + dapl_llist_remove_entry (&ia_ptr->cno_list_head, + &cno_ptr->header.ia_list_entry); + dapl_os_unlock (&ia_ptr->header.lock); +} + +/* + * dapl_ia_link_psp + * + * Add an psp to the IA structure + * + * Input: + * ia_ptr + * sp_ptr + * + * Output: + * none + * + * Returns: + * none + * + */ +void +dapl_ia_link_psp ( + IN DAPL_IA *ia_ptr, + IN DAPL_SP *sp_ptr) +{ + dapl_os_lock (&ia_ptr->header.lock); + dapl_llist_add_head (&ia_ptr->psp_list_head, + &sp_ptr->header.ia_list_entry, + sp_ptr); + dapl_os_unlock (&ia_ptr->header.lock); +} + +/* + * daps_ia_unlink_sp + * + * Remove an sp from the appropriate ia rsp or psp queue + * + * Input: + * ia_ptr + * sp_ptr + * + * Output: + * none + * + * Returns: + * none + * + */ +void +dapls_ia_unlink_sp ( + IN DAPL_IA *ia_ptr, + IN DAPL_SP *sp_ptr) +{ + DAPL_LLIST_HEAD *list_head; + + if ( sp_ptr->header.handle_type == DAT_HANDLE_TYPE_PSP ) + { + list_head = &ia_ptr->psp_list_head; + } + else + { + dapl_os_assert (sp_ptr->header.handle_type == DAT_HANDLE_TYPE_RSP); + list_head = &ia_ptr->rsp_list_head; + } + + dapl_os_lock (&ia_ptr->header.lock); + dapl_llist_remove_entry (list_head, + &sp_ptr->header.ia_list_entry); + dapl_os_unlock (&ia_ptr->header.lock); +} + +/* + * dapls_ia_sp_search + * + * Find an RSP or PSP on the IA list with a matching conn_qual value + * + * Input: + * ia_ptr + * sp_ptr + * + * Output: + * none + * + * Returns: + * none + * + */ +DAPL_SP * +dapls_ia_sp_search ( + IN DAPL_IA *ia_ptr, + IN DAT_CONN_QUAL conn_qual, + IN DAT_BOOLEAN is_psp ) +{ + DAPL_SP *sp_ptr; + DAPL_LLIST_HEAD *list_head; + + if ( is_psp ) + { + list_head = &ia_ptr->psp_list_head; + } + else + { + list_head = &ia_ptr->rsp_list_head; + } + + dapl_os_lock (&ia_ptr->header.lock); + + sp_ptr = (dapl_llist_is_empty (list_head) ? NULL : + dapl_llist_peek_head (list_head)); + + while (sp_ptr != NULL) + { + if ( sp_ptr->conn_qual == conn_qual ) + { + break; + } + sp_ptr = dapl_llist_next_entry (list_head, + &sp_ptr->header.ia_list_entry); + } + + dapl_os_unlock (&ia_ptr->header.lock); + + return sp_ptr; +} + + +/* + * dapl_ia_link_rsp + * + * Add an rsp to the IA structure + * + * Input: + * ia_ptr + * sp_ptr + * + * Output: + * none + * + * Returns: + * none + * + */ +void +dapl_ia_link_rsp ( + IN DAPL_IA *ia_ptr, + IN DAPL_SP *sp_ptr) +{ + dapl_os_lock (&ia_ptr->header.lock); + dapl_llist_add_head (&ia_ptr->rsp_list_head, + &sp_ptr->header.ia_list_entry, + sp_ptr); + dapl_os_unlock (&ia_ptr->header.lock); +} + + +DAT_RETURN +dapls_ia_setup_callbacks ( + IN DAPL_IA *ia_ptr, + IN DAPL_EVD *async_evd_ptr ) +{ + dapl_ibal_ca_t *p_ca = (dapl_ibal_ca_t *) ia_ptr->hca_ptr->ib_hca_handle; + DAT_RETURN dat_status = DAT_SUCCESS; + + /* back reference to ia_ptr needed for DAPL_ASYNC_UNAFILIATED callback */ + if ( p_ca == NULL ) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "dapls_ia_setup_callbacks failed %d\n", dat_status); + return (DAT_INVALID_HANDLE); + } + + p_ca->ia_ptr = (DAT_PVOID*)ia_ptr; + + /* unaffiliated handler */ + dat_status = + dapls_ib_setup_async_callback ( + ia_ptr, + DAPL_ASYNC_UNAFILIATED, + NULL, + (ib_async_handler_t)dapl_evd_un_async_error_callback, + async_evd_ptr); + + if (dat_status != DAT_SUCCESS) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "ib_set_un_async_error_eh failed %d\n", dat_status); + goto bail; + } + + /* affiliated cq handler */ + dat_status = dapls_ib_setup_async_callback ( + ia_ptr, + DAPL_ASYNC_CQ_ERROR, + NULL, + (ib_async_handler_t)dapl_evd_cq_async_error_callback, + async_evd_ptr); + + if (dat_status != DAT_SUCCESS) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "ib_set_cq_async_error_eh failed %d\n", dat_status); + goto bail; + } + + /* affiliated qp handler */ + dat_status = dapls_ib_setup_async_callback ( + ia_ptr, + DAPL_ASYNC_QP_ERROR, + NULL, + (ib_async_handler_t)dapl_evd_qp_async_error_callback, + ia_ptr); + if (dat_status != DAT_SUCCESS) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "ib_set_qp_async_error_eh failed %d\n", dat_status); + goto bail; + } + +bail: + return dat_status; +} + + +DAT_RETURN +dapls_ia_teardown_callbacks ( + IN DAPL_IA *ia_ptr) +{ + DAT_RETURN dat_status = DAT_SUCCESS; + + /* unaffiliated handler */ + dat_status = + dapls_ib_setup_async_callback ( + ia_ptr, + DAPL_ASYNC_UNAFILIATED, + NULL, + (ib_async_handler_t) 0, + NULL); + + if (dat_status != DAT_SUCCESS) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "ib_set_un_async_error_eh failed %d\n", dat_status); + goto bail; + } + + /* affiliated cq handler */ + dat_status = dapls_ib_setup_async_callback ( + ia_ptr, + DAPL_ASYNC_CQ_ERROR, + NULL, + (ib_async_handler_t) 0, + NULL); + + if (dat_status != DAT_SUCCESS) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "ib_set_cq_async_error_eh failed %d\n", dat_status); + goto bail; + } + + /* affiliated qp handler */ + dat_status = dapls_ib_setup_async_callback ( + ia_ptr, + DAPL_ASYNC_QP_ERROR, + NULL, + (ib_async_handler_t) 0, + NULL); + if (dat_status != DAT_SUCCESS) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "ib_set_qp_async_error_eh failed %d\n", dat_status); + goto bail; + } + +bail: + return dat_status; +} + diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ia_util.h b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ia_util.h new file mode 100644 index 00000000..a674a019 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ia_util.h @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dapl_ia_util.h + * + * PURPOSE: Utility defs & routines for the IA data structure + * + * $Id$ + **********************************************************************/ + +#ifndef _DAPL_IA_UTIL_H_ +#define _DAPL_IA_UTIL_H_ + +#include "dapl.h" + +DAPL_IA * +dapl_ia_alloc ( + DAT_PROVIDER *provider, + DAPL_HCA *hca_ptr) ; + +DAT_RETURN +dapl_ia_abrupt_close ( + IN DAPL_IA *ia_ptr ) ; + +DAT_RETURN +dapl_ia_graceful_close ( + IN DAPL_IA *ia_ptr ) ; + +void +dapls_ia_free ( DAPL_IA *ia_ptr ) ; + +void +dapl_ia_link_ep ( + IN DAPL_IA *ia_ptr, + IN DAPL_EP *ep_info ) ; + +void +dapl_ia_unlink_ep ( + IN DAPL_IA *ia_ptr, + IN DAPL_EP *ep_info ) ; + +void +dapl_ia_link_lmr ( + IN DAPL_IA *ia_ptr, + IN DAPL_LMR *lmr_info ) ; + +void +dapl_ia_unlink_lmr ( + IN DAPL_IA *ia_ptr, + IN DAPL_LMR *lmr_info ) ; + +void +dapl_ia_link_rmr ( + IN DAPL_IA *ia_ptr, + IN DAPL_RMR *rmr_info ) ; + +void +dapl_ia_unlink_rmr ( + IN DAPL_IA *ia_ptr, + IN DAPL_RMR *rmr_info ) ; + +void +dapl_ia_link_pz ( + IN DAPL_IA *ia_ptr, + IN DAPL_PZ *pz_info ) ; + +void +dapl_ia_unlink_pz ( + IN DAPL_IA *ia_ptr, + IN DAPL_PZ *pz_info ) ; + +void +dapl_ia_link_evd ( + IN DAPL_IA *ia_ptr, + IN DAPL_EVD *evd_info ) ; + +void +dapl_ia_unlink_evd ( + IN DAPL_IA *ia_ptr, + IN DAPL_EVD *evd_info ) ; + +void +dapl_ia_link_cno ( + IN DAPL_IA *ia_ptr, + IN DAPL_CNO *cno_info ) ; + +void +dapl_ia_unlink_cno ( + IN DAPL_IA *ia_ptr, + IN DAPL_CNO *cno_info ) ; + +void +dapl_ia_link_psp ( + IN DAPL_IA *ia_ptr, + IN DAPL_SP *sp_info ) ; + +void +dapls_ia_unlink_sp ( + IN DAPL_IA *ia_ptr, + IN DAPL_SP *sp_info ) ; + +void +dapl_ia_link_rsp ( + IN DAPL_IA *ia_ptr, + IN DAPL_SP *sp_info ) ; + +DAPL_SP * +dapls_ia_sp_search ( + IN DAPL_IA *ia_ptr, + IN DAT_CONN_QUAL conn_qual, + IN DAT_BOOLEAN is_psp ) ; + +DAT_RETURN +dapls_ia_setup_callbacks ( + IN DAPL_IA *ia_ptr, + IN DAPL_EVD *async_evd_ptr ); + +DAT_RETURN +dapls_ia_teardown_callbacks ( + IN DAPL_IA *ia_ptr ); + +#endif diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_init.h b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_init.h new file mode 100644 index 00000000..2002c911 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_init.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dapl_init.h + * + * PURPOSE: Prototypes for library-interface init and fini functions + * + * $Id$ + * + **********************************************************************/ + + +#ifndef _DAPL_INIT_H_ +#define _DAPL_INIT_H_ + +DAPL_EXPORT void DAT_API +DAT_PROVIDER_INIT_FUNC_NAME ( + IN const DAT_PROVIDER_INFO *, + IN const char * ); /* instance data */ + +DAPL_EXPORT void DAT_API +DAT_PROVIDER_FINI_FUNC_NAME ( + IN const DAT_PROVIDER_INFO * ); + +extern void +dapl_init ( void ) ; + +extern void +dapl_fini ( void ) ; + +#endif diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_llist.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_llist.c new file mode 100644 index 00000000..95d2d8ef --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_llist.c @@ -0,0 +1,380 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_llist.c + * + * PURPOSE: Manage doubly linked lists within the DAPL Reference Implementation + * + * A link list head points to the first member of a linked list, but + * is itself not a member of the list. + * + * +---------------------------------------------+ + * | entry entry entry | + * HEAD -> | +-------+ +-------+ +-------+ | + * +--> | flink | --> | flink | --> | flink | >--+ + * | data | | data | | data | + * +--< | blink | <-- | blink | <-- | blink | <--| + * | +-------+ +-------+ +-------+ | + * | | + * +---------------------------------------------+ + * + * Note: Each of the remove functions takes an assertion failure if + * an element cannot be removed from the list. + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" + +/* + * dapl_llist_init_head() + * + * Purpose: initialize a linked list head + */ +void +dapl_llist_init_head (DAPL_LLIST_HEAD * head) +{ + *head = NULL; +} + +/* + * dapl_llist_init_entry() + * + * Purpose: initialize a linked list entry + */ +void +dapl_llist_init_entry (DAPL_LLIST_ENTRY * entry) +{ + entry->blink = NULL; + entry->flink = NULL; + entry->data = 0; + entry->list_head = NULL; +} + +/* + * dapl_llist_is_empty() + * + * Purpose: returns TRUE if the linked list is empty + */ +DAT_BOOLEAN +dapl_llist_is_empty (DAPL_LLIST_HEAD * head) +{ + return (*head == NULL); +} + +/* + * dapl_llist_add_head() + * + * Purpose: Add an entry to the head of a linked list + */ +void +dapl_llist_add_head (DAPL_LLIST_HEAD * head, + DAPL_LLIST_ENTRY * entry, + void * data) +{ + DAPL_LLIST_ENTRY *first; + + /* deal with empty list */ + if (dapl_llist_is_empty (head)) + { + entry->flink = entry; + entry->blink = entry; + } + else + { + first = *head; + entry->flink = first; + entry->blink = first->blink; + first->blink->flink = entry; + first->blink = entry; + } + + *head = entry; + entry->data = data; + entry->list_head = head; +} + +/* + * dapl_llist_add_tail() + * + * Purpose: Add an entry to the tail of a linked list + */ +void +dapl_llist_add_tail (DAPL_LLIST_HEAD * head, + DAPL_LLIST_ENTRY * entry, + void * data) +{ + DAPL_LLIST_ENTRY *last; + + /* deal with empty list */ + if (dapl_llist_is_empty (head)) + { + *head = entry; + entry->flink = entry; + entry->blink = entry; + } + else + { + last = (*head)->blink; + entry->flink = last->flink; + entry->blink = last; + last->flink->blink = entry; + last->flink = entry; + } + entry->data = data; + entry->list_head = head; +} + + +/* + * dapl_llist_add_entry() + * + * Purpose: Add an entry before an element in the list. Does + * not verify the list or the validity of the entries passed in. + */ +void +dapl_llist_add_entry (DAPL_LLIST_HEAD * head, + DAPL_LLIST_ENTRY * entry, + DAPL_LLIST_ENTRY * new_entry, + void * data) +{ + DAPL_LLIST_ENTRY *last; + + /* deal with empty list */ + if (dapl_llist_is_empty (head)) + { + *head = entry; + entry->flink = entry; + entry->blink = entry; + } + else + { + last = entry->blink; + entry->blink = new_entry; + last->flink = new_entry; + + new_entry->flink = entry; + new_entry->blink = last; + + } + new_entry->data = data; + new_entry->list_head = head; +} + +/* + * dapl_llist_remove_head() + * + * Purpose: Remove the first entry of a linked list + */ +void * +dapl_llist_remove_head (DAPL_LLIST_HEAD *head) +{ + DAPL_LLIST_ENTRY *first; + + dapl_os_assert (!dapl_llist_is_empty (head)); + first = *head; + *head = first->flink; + + first->flink->blink = first->blink; + first->blink->flink = first->flink; + + if (first->flink == first) + { + *head = NULL; + } + /* clean up the links for good measure */ + first->flink = NULL; + first->blink = NULL; + first->list_head = NULL; + return (first->data); +} + +/* + * dapl_llist_remove_tail() + * + * Purpose: Remove the last entry of a linked list + */ +void * +dapl_llist_remove_tail (DAPL_LLIST_HEAD *head) +{ + DAPL_LLIST_ENTRY *last; + + dapl_os_assert (!dapl_llist_is_empty (head)); + last = (*head)->blink; + + last->blink->flink = last->flink; + last->flink->blink = last->blink; + + if (last->flink == last) + { + *head = NULL; + } + /* clean up the links for good measure */ + last->flink = NULL; + last->blink = NULL; + last->list_head = NULL; + + return (last->data); +} + +/* + * dapl_llist_remove_entry() + * + * Purpose: Remove the specified entry from a linked list + */ +void * +dapl_llist_remove_entry (DAPL_LLIST_HEAD *head, DAPL_LLIST_ENTRY *entry) +{ + DAPL_LLIST_ENTRY *first; + + dapl_os_assert (!dapl_llist_is_empty (head)); + first = *head; + + /* if it's the first entry, pull it off */ + if (first == entry) + { + (*head) = first->flink; + /* if it was the only entry, kill the list */ + if (first->flink == first) + { + (*head) = NULL; + } + } +#ifdef VERIFY_LINKED_LIST + else + { + DAPL_LLIST_ENTRY *try_entry; + + try_entry = first->flink; + for (;;) + { + if (try_entry == first) + { + /* not finding the element on the list is a BAD thing */ + dapl_os_assert (0); + break; + } + if (try_entry == entry) + { + break; + } + try_entry = try_entry->flink; + } + } +#endif /* VERIFY_LINKED_LIST */ + + dapl_os_assert ( entry->list_head == head ); + entry->list_head = NULL; + + entry->flink->blink = entry->blink; + entry->blink->flink = entry->flink; + entry->flink = NULL; + entry->blink = NULL; + + return (entry->data); +} + +/* + * dapl_llist_peek_head + */ + +void * +dapl_llist_peek_head (DAPL_LLIST_HEAD *head) +{ + DAPL_LLIST_ENTRY *first; + + dapl_os_assert (!dapl_llist_is_empty (head)); + first = *head; + return (first->data); +} + + +/* + * dapl_llist_next_entry + * + * Obtain the next entry in the list, return NULL when we get to the + * head + */ + +void * +dapl_llist_next_entry (IN DAPL_LLIST_HEAD *head, + IN DAPL_LLIST_ENTRY *cur_ent) +{ + DAPL_LLIST_ENTRY *next; + + dapl_os_assert (!dapl_llist_is_empty (head)); + if ( cur_ent == NULL ) + { + next = *head; + } else + { + next = cur_ent->flink; + if ( next == *head ) + { + return NULL; + } + } + return (next->data); +} + +#ifdef DAPL_DBG +/* + * dapl_llist_debug_print_list() + * + * Purpose: Prints the linked list for debugging + */ +void +dapl_llist_debug_print_list (DAPL_LLIST_HEAD *head) +{ + DAPL_LLIST_ENTRY * entry; + DAPL_LLIST_ENTRY * first; + first = *head; + if (!first) + { + dapl_os_printf ("EMPTY_LIST\n"); + return; + } + dapl_os_printf ("HEAD %p\n", *head); + dapl_os_printf ("Entry %p %p %p %p\n", + first, + first->flink, + first->blink, + first->data); + entry = first->flink; + while (entry != first) + { + dapl_os_printf ("Entry %p %p %p %p\n", + entry, + entry->flink, + entry->blink, + entry->data); + entry = entry->flink; + } +} + +#endif /* DAPL_DBG */ diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_lmr_create.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_lmr_create.c new file mode 100644 index 00000000..07773d37 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_lmr_create.c @@ -0,0 +1,537 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_lmr_create.c + * + * PURPOSE: Memory management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 6 + * + * $Id$ + **********************************************************************/ + +#include "dapl_lmr_util.h" +#include "dapl_adapter_util.h" + +/********************************************************************* + * * + * Function Prototypes * + * * + *********************************************************************/ + +STATIC _INLINE_ DAT_RETURN +dapl_lmr_create_virtual ( + IN DAPL_IA *ia, + IN DAT_PVOID virt_addr, + IN DAT_VLEN length, + IN DAPL_PZ *pz, + IN DAT_MEM_PRIV_FLAGS privileges, + OUT DAT_LMR_HANDLE *lmr_handle, + OUT DAT_LMR_CONTEXT *lmr_context, + OUT DAT_RMR_CONTEXT *rmr_context, + OUT DAT_VLEN *registered_length, + OUT DAT_VADDR *registered_address ); + +STATIC _INLINE_ DAT_RETURN +dapl_lmr_create_lmr ( + IN DAPL_IA *ia, + IN DAPL_LMR *original_lmr, + IN DAPL_PZ *pz, + IN DAT_MEM_PRIV_FLAGS privileges, + OUT DAT_LMR_HANDLE *lmr_handle, + OUT DAT_LMR_CONTEXT *lmr_context, + OUT DAT_RMR_CONTEXT *rmr_context, + OUT DAT_VLEN *registered_length, + OUT DAT_VADDR *registered_address ); + +STATIC _INLINE_ DAT_RETURN +dapl_lmr_create_shared_virtual ( + IN DAPL_IA *ia, + IN DAT_SHARED_MEMORY shared_memory, + IN DAT_VLEN length, + IN DAPL_PZ *pz, + IN DAT_MEM_PRIV_FLAGS privileges, + OUT DAT_LMR_HANDLE *lmr_handle, + OUT DAT_LMR_CONTEXT *lmr_context, + OUT DAT_RMR_CONTEXT *rmr_context, + OUT DAT_VLEN *registered_length, + OUT DAT_VADDR *registered_address ); + +/********************************************************************* + * * + * Function Definitions * + * * + *********************************************************************/ + +STATIC _INLINE_ DAT_RETURN +dapl_lmr_create_virtual ( + IN DAPL_IA *ia, + IN DAT_PVOID virt_addr, + IN DAT_VLEN length, + IN DAPL_PZ *pz, + IN DAT_MEM_PRIV_FLAGS privileges, + OUT DAT_LMR_HANDLE *lmr_handle, + OUT DAT_LMR_CONTEXT *lmr_context, + OUT DAT_RMR_CONTEXT *rmr_context, + OUT DAT_VLEN *registered_length, + OUT DAT_VADDR *registered_address ) +{ + DAPL_LMR *lmr; + DAT_REGION_DESCRIPTION reg_desc; + DAT_RETURN dat_status; + + reg_desc.for_va = virt_addr; + dat_status = DAT_SUCCESS; + + lmr = dapl_lmr_alloc (ia, + DAT_MEM_TYPE_VIRTUAL, + reg_desc, + length, + (DAT_PZ_HANDLE) pz, + privileges); + + if ( NULL == lmr ) + { + dat_status = DAT_ERROR (DAT_INSUFFICIENT_RESOURCES,DAT_RESOURCE_MEMORY); + goto bail; + } + + dat_status = dapls_ib_mr_register (ia, + lmr, + virt_addr, + length, + privileges); + + if (DAT_SUCCESS != dat_status) + { + dapl_lmr_dealloc (lmr); + goto bail; + } + + /* if the LMR context is already in the hash table */ + dat_status = dapls_hash_search (ia->hca_ptr->lmr_hash_table, + lmr->param.lmr_context, + NULL); + if (dat_status == DAT_SUCCESS) + { + (void)dapls_ib_mr_deregister (lmr); + dapl_lmr_dealloc (lmr); + + dat_status = DAT_ERROR (DAT_INVALID_STATE,DAT_INVALID_STATE_LMR_IN_USE); + goto bail; + } + + dat_status = dapls_hash_insert (ia->hca_ptr->lmr_hash_table, + lmr->param.lmr_context, + lmr); + if (dat_status != DAT_SUCCESS) + { + (void)dapls_ib_mr_deregister (lmr); + dapl_lmr_dealloc (lmr); + + /* The value returned by dapls_hash_insert(.) is not */ + /* returned to the consumer because the spec. requires */ + /* that dat_lmr_create(.) return only certain values. */ + dat_status = DAT_ERROR (DAT_INSUFFICIENT_RESOURCES,DAT_RESOURCE_MEMORY); + goto bail; + } + + dapl_os_atomic_inc (&pz->pz_ref_count); + + if (NULL != lmr_handle) + { + *lmr_handle = (DAT_LMR_HANDLE) lmr; + } + if (NULL != lmr_context) + { + *lmr_context = lmr->param.lmr_context; + } + if (NULL != rmr_context) + { + *rmr_context = lmr->param.rmr_context; + } + if (NULL != registered_length) + { + *registered_length = lmr->param.registered_size; + } + if (NULL != registered_address) + { + *registered_address = lmr->param.registered_address; + } + + bail: + return dat_status; +} + + +STATIC _INLINE_ DAT_RETURN +dapl_lmr_create_lmr ( + IN DAPL_IA *ia, + IN DAPL_LMR *original_lmr, + IN DAPL_PZ *pz, + IN DAT_MEM_PRIV_FLAGS privileges, + OUT DAT_LMR_HANDLE *lmr_handle, + OUT DAT_LMR_CONTEXT *lmr_context, + OUT DAT_RMR_CONTEXT *rmr_context, + OUT DAT_VLEN *registered_length, + OUT DAT_VADDR *registered_address ) +{ + DAPL_LMR *lmr; + DAT_REGION_DESCRIPTION reg_desc; + DAT_RETURN dat_status; + + dapl_dbg_log (DAPL_DBG_TYPE_API, + "dapl_lmr_create_lmr (%p, %p, %p, %x, %p, %p, %p, %p)\n", + ia, + original_lmr, + pz, privileges, + lmr_handle, + lmr_context, + registered_length, + registered_address); + + dat_status = dapls_hash_search (ia->hca_ptr->lmr_hash_table, + original_lmr->param.lmr_context, + (DAPL_HASH_DATA *) &lmr); + if ( dat_status != DAT_SUCCESS ) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER,DAT_INVALID_ARG2); + goto bail; + } + + reg_desc.for_lmr_handle = (DAT_LMR_HANDLE) original_lmr; + + lmr = dapl_lmr_alloc (ia, + DAT_MEM_TYPE_LMR, + reg_desc, + 0, /* length is meaningless */ + (DAT_PZ_HANDLE) pz, + privileges); + + if (NULL == lmr) + { + dat_status = DAT_ERROR (DAT_INSUFFICIENT_RESOURCES,DAT_RESOURCE_MEMORY); + goto bail; + } + + dat_status = dapls_ib_mr_register_shared (ia, + lmr, + privileges); + + if (DAT_SUCCESS != dat_status) + { + dapl_lmr_dealloc (lmr); + goto bail; + } + + /* if the LMR context is already in the hash table */ + dat_status = dapls_hash_search (ia->hca_ptr->lmr_hash_table, + lmr->param.lmr_context, + NULL); + if (dat_status == DAT_SUCCESS) + { + dapls_ib_mr_deregister (lmr); + dapl_lmr_dealloc (lmr); + + dat_status = DAT_ERROR (DAT_INVALID_STATE,DAT_INVALID_STATE_LMR_IN_USE); + goto bail; + } + + dat_status = dapls_hash_insert (ia->hca_ptr->lmr_hash_table, + lmr->param.lmr_context, + lmr); + if (dat_status != DAT_SUCCESS) + { + dapls_ib_mr_deregister (lmr); + dapl_lmr_dealloc (lmr); + + /* The value returned by dapls_hash_insert(.) is not */ + /* returned to the consumer because the spec. requires */ + /* that dat_lmr_create(.) return only certain values. */ + dat_status = DAT_ERROR (DAT_INSUFFICIENT_RESOURCES,DAT_RESOURCE_MEMORY); + goto bail; + } + + dapl_os_atomic_inc (&pz->pz_ref_count); + + if (NULL != lmr_handle) + { + *lmr_handle = (DAT_LMR_HANDLE) lmr; + } + if (NULL != lmr_context) + { + *lmr_context = lmr->param.lmr_context; + } + if (NULL != rmr_context) + { + *rmr_context = lmr->param.rmr_context; + } + if (NULL != registered_length) + { + *registered_length = original_lmr->param.registered_size; + } + if (NULL != registered_address) + { + *registered_address = original_lmr->param.registered_address; + } + + bail: + return DAT_SUCCESS; +} + + +STATIC _INLINE_ DAT_RETURN +dapl_lmr_create_shared_virtual ( + IN DAPL_IA *ia, + IN DAT_SHARED_MEMORY shared_memory, + IN DAT_VLEN length, + IN DAPL_PZ *pz, + IN DAT_MEM_PRIV_FLAGS privileges, + OUT DAT_LMR_HANDLE *lmr_handle, + OUT DAT_LMR_CONTEXT *lmr_context, + OUT DAT_RMR_CONTEXT *rmr_context, + OUT DAT_VLEN *registered_length, + OUT DAT_VADDR *registered_address ) +{ + DAT_RETURN dat_status; + DAPL_LMR *new_lmr; + DAT_REGION_DESCRIPTION reg_desc; + + reg_desc.for_shared_memory = shared_memory; + dat_status = DAT_SUCCESS; + + new_lmr = dapl_lmr_alloc ( ia, + DAT_MEM_TYPE_SHARED_VIRTUAL, + reg_desc, + length, + (DAT_PZ_HANDLE) pz, + privileges); + + if (NULL == new_lmr) + { + dat_status = DAT_ERROR (DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); + goto bail; + } + + dapl_os_memcpy ( + new_lmr->param.region_desc.for_shared_memory.shared_memory_id, + shared_memory.shared_memory_id, DAT_LMR_COOKIE_SIZE ); + + + dat_status = dapls_ib_mr_register (ia, + new_lmr, + shared_memory.virtual_address, + length, + privileges); + + if (DAT_SUCCESS != dat_status) + { + dapl_lmr_dealloc (new_lmr); + goto bail; + } + + /* if the LMR context is already in the hash table */ + dat_status = dapls_hash_search (ia->hca_ptr->lmr_hash_table, + new_lmr->param.lmr_context, + NULL); + if (DAT_SUCCESS == dat_status) + { + (void)dapls_ib_mr_deregister (new_lmr); + dapl_lmr_dealloc (new_lmr); + dat_status = DAT_ERROR (DAT_INVALID_STATE, DAT_INVALID_STATE_LMR_IN_USE); + goto bail; + } + + dat_status = dapls_hash_insert (ia->hca_ptr->lmr_hash_table, + new_lmr->param.lmr_context, + new_lmr); + if (DAT_SUCCESS != dat_status) + { + (void)dapls_ib_mr_deregister (new_lmr); + dapl_lmr_dealloc (new_lmr); + goto bail; + + /* The value returned by dapls_hash_insert(.) is not */ + /* returned to the consumer because the spec. requires */ + /* that dat_lmr_create(.) return only certain values. */ + } + + dat_status = dapls_ib_mr_register_shared ( ia, + new_lmr, + privileges ); + + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "--> DLCSV: register_shared ret %x, mr_handle %p\n", + dat_status, new_lmr->mr_handle); + + if (DAT_SUCCESS != dat_status) + { + + dapl_lmr_dealloc ( new_lmr ); + goto bail; + } + + (void) dapl_os_atomic_inc (&pz->pz_ref_count); + dapl_dbg_log (DAPL_DBG_TYPE_EP, + "--> DaLmrCsv: ++ LMR(%p) pz(%p)->ref_count = %d\n", + new_lmr, pz, pz->pz_ref_count ); + + if (NULL != lmr_handle) + { + *lmr_handle = (DAT_LMR_HANDLE) new_lmr; + } + if (NULL != lmr_context) + { + *lmr_context = new_lmr->param.lmr_context; + } + if (NULL != rmr_context) + { + *rmr_context = new_lmr->param.rmr_context; + } + if (NULL != registered_length) + { + *registered_length = length; + } + if (NULL != registered_address) + { + *registered_address = (DAT_VADDR) ((uintptr_t) shared_memory.virtual_address); + } + +bail: + return dat_status; + +} + + + +/* + * dapl_lmr_create + * + * DAPL Requirements Version xxx, 6.6.3.1 + * + * Register a memory region with an Interface Adaptor. + * + * Input: + * ia_handle + * mem_type + * region_description + * length + * pz_handle + * privileges + * + * Output: + * lmr_handle + * lmr_context + * registered_length + * registered_address + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + * DAT_INVALID_STATE + * DAT_MODEL_NOT_SUPPORTED + * + */ +DAT_RETURN +dapl_lmr_create ( + IN DAT_IA_HANDLE ia_handle, + IN DAT_MEM_TYPE mem_type, + IN DAT_REGION_DESCRIPTION region_description, + IN DAT_VLEN length, + IN DAT_PZ_HANDLE pz_handle, + IN DAT_MEM_PRIV_FLAGS privileges, + OUT DAT_LMR_HANDLE *lmr_handle, + OUT DAT_LMR_CONTEXT *lmr_context, + OUT DAT_RMR_CONTEXT *rmr_context, + OUT DAT_VLEN *registered_length, + OUT DAT_VADDR *registered_address ) +{ + DAPL_IA *ia; + DAPL_PZ *pz; + DAT_RETURN dat_status; + + if ( DAPL_BAD_HANDLE (ia_handle, DAPL_MAGIC_IA) ) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_IA); + goto bail; + } + if ( DAPL_BAD_HANDLE (pz_handle, DAPL_MAGIC_PZ) ) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_PZ); + goto bail; + } + + ia = (DAPL_IA *) ia_handle; + pz = (DAPL_PZ *) pz_handle; + + switch (mem_type) + { + case DAT_MEM_TYPE_VIRTUAL: + { + dat_status = dapl_lmr_create_virtual ( + ia, region_description.for_va, length, pz, privileges, + lmr_handle, lmr_context, rmr_context, registered_length, + registered_address); + break; + } + case DAT_MEM_TYPE_LMR: + { + DAPL_LMR *lmr; + + if ( DAPL_BAD_HANDLE (region_description.for_lmr_handle, DAPL_MAGIC_LMR) ) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_LMR); + goto bail; + } + + lmr = (DAPL_LMR *) region_description.for_lmr_handle; + + dat_status = dapl_lmr_create_lmr ( + ia, lmr, pz, privileges, lmr_handle, + lmr_context, rmr_context, registered_length, registered_address); + break; + } + case DAT_MEM_TYPE_SHARED_VIRTUAL: + { + dat_status = dapl_lmr_create_shared_virtual ( + ia, region_description.for_shared_memory, length, pz, + privileges, lmr_handle, lmr_context, rmr_context, + registered_length, registered_address); + break; + } + default: + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER, DAT_INVALID_ARG2); + break; + } + } + +bail: + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_lmr_free.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_lmr_free.c new file mode 100644 index 00000000..923ad9b1 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_lmr_free.c @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_lmr_free.c + * + * PURPOSE: Memory management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 6 + * + * $Id$ + **********************************************************************/ + +#include "dapl_lmr_util.h" +#include "dapl_adapter_util.h" +#include "dapl_ia_util.h" + +/* + * dapl_lmr_free + * + * DAPL Requirements Version xxx, 6.6.3.2 + * + * Destroy an instance of the Local Memory Region + * + * Input: + * lmr_handle + * + * Output: + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + * DAT_INVALID_PARAMETER + * DAT_INVALID_STATE + */ + +DAT_RETURN +dapl_lmr_free ( + IN DAT_LMR_HANDLE lmr_handle ) +{ + DAPL_LMR *lmr; + DAT_RETURN dat_status; + + dapl_dbg_log (DAPL_DBG_TYPE_API, "dapl_lmr_free (%p)\n", lmr_handle); + + if ( DAPL_BAD_HANDLE (lmr_handle, DAPL_MAGIC_LMR) ) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE,DAT_INVALID_HANDLE_LMR); + goto bail; + } + + lmr = (DAPL_LMR *) lmr_handle; + + switch (lmr->param.mem_type) + { + case DAT_MEM_TYPE_VIRTUAL: + /* fall through */ + case DAT_MEM_TYPE_LMR: + /* fall through */ + case DAT_MEM_TYPE_SHARED_VIRTUAL: + { + DAPL_PZ *pz; + + if ( 0 != lmr->lmr_ref_count ) + { + return DAT_INVALID_STATE; + } + + dat_status = dapls_hash_remove (lmr->header.owner_ia->hca_ptr->lmr_hash_table, + lmr->param.lmr_context, NULL); + if (dat_status != DAT_SUCCESS) + { + goto bail; + } + + dat_status = dapls_ib_mr_deregister (lmr); + + if (dat_status == DAT_SUCCESS) + { + + pz = (DAPL_PZ *) lmr->param.pz_handle; + dapl_os_atomic_dec (&pz->pz_ref_count); + + dapl_lmr_dealloc (lmr); + } + else + { + /* + * Deregister failed; put it back in the + * hash table. + */ + dapls_hash_insert (lmr->header.owner_ia->hca_ptr->lmr_hash_table, + lmr->param.lmr_context, lmr); + } + + break; + } + default: + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "--> DLF: lmr_free(%p) mem_type %d mr_handle %p\n", + lmr, lmr->param.mem_type, lmr->mr_handle); + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER, DAT_INVALID_ARG1); + break; + } + } + +bail: + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_lmr_query.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_lmr_query.c new file mode 100644 index 00000000..35b89c6a --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_lmr_query.c @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_lmr_query.c + * + * PURPOSE: Memory management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 6 + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" + +/* + * dapl_lmr_query + * + * DAPL Requirements Version xxx, 6.6.3.3 + * + * Provide the LMR arguments. + * + * Input: + * lmr_handle + * lmr_param_mask + * lmr_param + * + * Output: + * lmr_param + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + * DAT_INVALID_PARAMETER + */ +DAT_RETURN +dapl_lmr_query ( + IN DAT_LMR_HANDLE lmr_handle, + IN DAT_LMR_PARAM_MASK lmr_param_mask, + IN DAT_LMR_PARAM *lmr_param ) +{ + DAPL_LMR *lmr; + DAT_RETURN dat_status; + + dapl_dbg_log (DAPL_DBG_TYPE_API, + "dapl_lmr_query (%p, 0x%x, %p)\n", + lmr_handle, + lmr_param_mask, + lmr_param); + + if ( DAPL_BAD_HANDLE (lmr_handle, DAPL_MAGIC_LMR) ) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE,DAT_INVALID_HANDLE_LMR); + goto bail; + } + if (NULL == lmr_param) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER,DAT_INVALID_ARG3); + goto bail; + } + + dat_status = DAT_SUCCESS; + lmr = (DAPL_LMR *) lmr_handle; + + dapl_os_memcpy (lmr_param, &lmr->param, sizeof (DAT_LMR_PARAM)); + + bail: + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_lmr_util.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_lmr_util.c new file mode 100644 index 00000000..99de0c9a --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_lmr_util.c @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_lmr_util.c + * + * PURPOSE: Memory management support routines + * Description: Support routines for LMR functions + * + * $Id$ + **********************************************************************/ + +#include "dapl_lmr_util.h" +#include "dapl_ia_util.h" + +DAPL_LMR * +dapl_lmr_alloc ( + IN DAPL_IA *ia, + IN DAT_MEM_TYPE mem_type, + IN DAT_REGION_DESCRIPTION region_desc, + IN DAT_VLEN length, + IN DAT_PZ_HANDLE pz_handle, + IN DAT_MEM_PRIV_FLAGS mem_priv) +{ + DAPL_LMR *lmr; + + /* Allocate LMR */ + lmr = (DAPL_LMR *) dapl_os_alloc (sizeof (DAPL_LMR)); + if (NULL == lmr) + { + return (NULL); + } + + /* zero the structure */ + dapl_os_memzero (lmr, sizeof (DAPL_LMR)); + + /* + * initialize the header + */ + lmr->header.provider = ia->header.provider; + lmr->header.magic = DAPL_MAGIC_LMR; + lmr->header.handle_type = DAT_HANDLE_TYPE_LMR; + lmr->header.owner_ia = ia; + lmr->header.user_context.as_64 = 0; + lmr->header.user_context.as_ptr = NULL; + dapl_llist_init_entry (&lmr->header.ia_list_entry); + dapl_ia_link_lmr (ia, lmr); + dapl_os_lock_init (&lmr->header.lock); + + /* + * initialize the body + */ + lmr->param.ia_handle = (DAT_IA_HANDLE) ia; + lmr->param.mem_type = mem_type; + lmr->param.region_desc = region_desc; + lmr->param.length = length; + lmr->param.pz_handle = pz_handle; + lmr->param.mem_priv = mem_priv; + lmr->lmr_ref_count = 0; + + if (mem_type == DAT_MEM_TYPE_SHARED_VIRTUAL) + { + lmr->param.region_desc.for_shared_memory.shared_memory_id = + dapl_os_alloc (DAT_LMR_COOKIE_SIZE); + } + + return (lmr); +} + +void +dapl_lmr_dealloc ( + IN DAPL_LMR *lmr) +{ + lmr->header.magic = DAPL_MAGIC_INVALID; /* reset magic to prevent reuse */ + dapl_ia_unlink_lmr (lmr->header.owner_ia, lmr); + dapl_os_lock_destroy (&lmr->header.lock); + + if (lmr->param.mem_type == DAT_MEM_TYPE_SHARED_VIRTUAL) + { + dapl_os_free (lmr->param.region_desc.for_shared_memory.shared_memory_id, + DAT_LMR_COOKIE_SIZE); + } + + dapl_os_free ((void *) lmr, sizeof (DAPL_LMR)); +} diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_lmr_util.h b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_lmr_util.h new file mode 100644 index 00000000..5e92f186 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_lmr_util.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dapl_lmr_util.h + * + * PURPOSE: Utility defs & routines for the LMR data structure + * + * $Id$ + * + **********************************************************************/ + +#ifndef _DAPL_LMR_UTIL_H_ +#define _DAPL_LMR_UTIL_H_ + +#include "dapl_mr_util.h" + +/********************************************************************* + * * + * Function Prototypes * + * * + *********************************************************************/ + +extern DAPL_LMR * +dapl_lmr_alloc ( + IN DAPL_IA *ia, + IN DAT_MEM_TYPE mem_type, + IN DAT_REGION_DESCRIPTION region_desc, + IN DAT_VLEN length, + IN DAT_PZ_HANDLE pz_handle, + IN DAT_MEM_PRIV_FLAGS mem_priv); + +extern void +dapl_lmr_dealloc ( + IN DAPL_LMR *lmr); + +STATIC _INLINE_ int32_t +dapl_lmr_convert_privileges ( + IN DAT_MEM_PRIV_FLAGS privileges); + + +/********************************************************************* + * * + * Inline Functions * + * * + *********************************************************************/ + +STATIC _INLINE_ int32_t +dapl_lmr_convert_privileges ( + IN DAT_MEM_PRIV_FLAGS privileges) +{ + int32_t value = 0; + + /* + * if (DAT_MEM_PRIV_LOCAL_READ_FLAG & privileges) + * do nothing + */ + + if (DAT_MEM_PRIV_LOCAL_WRITE_FLAG & privileges) + { + value |= IB_ACCESS_LOCAL_WRITE; + } + + if (DAT_MEM_PRIV_REMOTE_READ_FLAG & privileges) + { + value |= IB_ACCESS_REMOTE_READ; + } + + if (DAT_MEM_PRIV_REMOTE_WRITE_FLAG & privileges) + { + value |= IB_ACCESS_REMOTE_WRITE; + } + + return value; +} + +#endif /* _DAPL_LMR_UTIL_H_*/ diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_mr_util.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_mr_util.c new file mode 100644 index 00000000..0b931a02 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_mr_util.c @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_mr_util.c + * + * PURPOSE: Common Memory Management functions and data structures + * + * $Id$ + **********************************************************************/ + +#include "dapl_mr_util.h" + +/********************************************************************* + * * + * Function Definitions * + * * + *********************************************************************/ + +/* + * dapl_mr_get_address + * + * Returns the memory address associated with the given memory descriptor + * + */ + +DAT_VADDR +dapl_mr_get_address (DAT_REGION_DESCRIPTION desc, DAT_MEM_TYPE type) +{ + switch (type) + { + case DAT_MEM_TYPE_VIRTUAL: + { + return (DAT_VADDR) (uintptr_t) desc.for_va; + } + case DAT_MEM_TYPE_LMR: + { + DAPL_LMR *lmr; + + lmr = (DAPL_LMR *) desc.for_lmr_handle; + + /* Since this function is recoursive we cannot inline it */ + return dapl_mr_get_address (lmr->param.region_desc, + lmr->param.mem_type); + } + case DAT_MEM_TYPE_SHARED_VIRTUAL: + { + return (DAT_VADDR) (uintptr_t) desc.for_shared_memory.virtual_address; + } + default: + { + dapl_os_assert (0); + return 0; + } + } +} diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_mr_util.h b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_mr_util.h new file mode 100644 index 00000000..4b07164d --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_mr_util.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dapl_mr_util.h + * + * PURPOSE: Utility defs & routines for memory registration functions + * + * $Id$ + * + **********************************************************************/ + +#ifndef _DAPL_MR_UTIL_H_ +#define _DAPL_MR_UTIL_H_ + +#include "dapl.h" +#include "dapl_hash.h" + + +/********************************************************************* + * * + * Function Prototypes * + * * + *********************************************************************/ + +extern DAT_VADDR +dapl_mr_get_address ( + IN DAT_REGION_DESCRIPTION desc, + IN DAT_MEM_TYPE type); + +STATIC _INLINE_ DAT_BOOLEAN +dapl_mr_bounds_check ( + IN DAT_VADDR addr_a, + IN DAT_VLEN length_a, + IN DAT_VADDR addr_b, + IN DAT_VLEN length_b); + + +/********************************************************************* + * * + * Inline Functions * + * * + *********************************************************************/ + +/* + * dapl_mr_bounds_check + * + * Returns true if region B is contained within region A + * and false otherwise + * + */ + +STATIC _INLINE_ DAT_BOOLEAN +dapl_mr_bounds_check (DAT_VADDR addr_a, DAT_VLEN length_a, + DAT_VADDR addr_b, DAT_VLEN length_b) +{ + if ( (addr_a <= addr_b) && + (addr_b + length_b) <= (addr_a + length_a)) + { + return DAT_TRUE; + } + else + { + return DAT_FALSE; + } +} + +#endif /* _DAPL_MR_UTIL_H_ */ diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_provider.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_provider.c new file mode 100644 index 00000000..01c0db38 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_provider.c @@ -0,0 +1,401 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_provider.c + * + * PURPOSE: Provider function table + * Description: DAT Interfaces to this provider + * + * $Id$ + **********************************************************************/ + +#include "dapl_provider.h" + +extern DAT_RETURN dapl_not_implemented (void); + +/********************************************************************* + * * + * Global Data * + * * + *********************************************************************/ + +DAPL_PROVIDER_LIST g_dapl_provider_list; + + +/* + * the function table for this provider + */ + +DAT_PROVIDER g_dapl_provider_template = +{ + NULL, + 0, + &dapl_ia_open, + &dapl_ia_query, + &dapl_ia_close, + + &dapl_set_consumer_context, + &dapl_get_consumer_context, + &dapl_get_handle_type, + + &dapl_cno_create, + &dapl_cno_modify_agent, + &dapl_cno_query, + &dapl_cno_free, + &dapl_cno_wait, + + &dapl_cr_query, + &dapl_cr_accept, + &dapl_cr_reject, + &dapl_cr_handoff, + + &dapl_evd_create, + &dapl_evd_query, + &dapl_evd_modify_cno, + &dapl_evd_enable, + &dapl_evd_disable, + &dapl_evd_wait, + &dapl_evd_resize, + &dapl_evd_post_se, + &dapl_evd_dequeue, + &dapl_evd_free, + + &dapl_ep_create, + &dapl_ep_query, + &dapl_ep_modify, + &dapl_ep_connect, + &dapl_ep_dup_connect, + &dapl_ep_disconnect, + &dapl_ep_post_send, + &dapl_ep_post_recv, + &dapl_ep_post_rdma_read, + &dapl_ep_post_rdma_write, + &dapl_ep_get_status, + &dapl_ep_free, + + &dapl_lmr_create, + &dapl_lmr_query, + &dapl_lmr_free, + + &dapl_rmr_create, + &dapl_rmr_query, + &dapl_rmr_bind, + &dapl_rmr_free, + + &dapl_psp_create, + &dapl_psp_query, + &dapl_psp_free, + + &dapl_rsp_create, + &dapl_rsp_query, + &dapl_rsp_free, + + &dapl_pz_create, + &dapl_pz_query, + &dapl_pz_free, + + &dapl_psp_create_any, + &dapl_ep_reset, + &dapl_evd_set_unwaitable, + &dapl_evd_clear_unwaitable +}; + + + +/********************************************************************* + * * + * Function Prototypes * + * * + *********************************************************************/ + +static DAT_BOOLEAN +dapl_provider_list_key_cmp ( + const char *name_a, + const char *name_b ); + + +/********************************************************************* + * * + * Function Definitions * + * * + *********************************************************************/ + +DAT_RETURN +dapl_provider_list_create ( void ) +{ + DAT_RETURN status; + + status = DAT_SUCCESS; + + /* create the head node */ + g_dapl_provider_list.head = dapl_os_alloc (sizeof (DAPL_PROVIDER_LIST_NODE)); + if ( NULL == g_dapl_provider_list.head ) + { + status = DAT_ERROR (DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); + goto bail; + } + + dapl_os_memzero (g_dapl_provider_list.head, sizeof (DAPL_PROVIDER_LIST_NODE)); + + /* create the tail node */ + g_dapl_provider_list.tail = dapl_os_alloc (sizeof (DAPL_PROVIDER_LIST_NODE)); + if ( NULL == g_dapl_provider_list.tail ) + { + status = DAT_ERROR (DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); + goto bail; + } + + dapl_os_memzero (g_dapl_provider_list.tail, sizeof (DAPL_PROVIDER_LIST_NODE)); + + g_dapl_provider_list.head->next = g_dapl_provider_list.tail; + g_dapl_provider_list.tail->prev = g_dapl_provider_list.head; + g_dapl_provider_list.size = 0; + g_dapl_provider_list.initialized = DAT_TRUE; + +bail: + if ( DAT_SUCCESS != status ) + { + if ( NULL != g_dapl_provider_list.head ) + { + dapl_os_free (g_dapl_provider_list.head, sizeof (DAPL_PROVIDER_LIST_NODE)); + } + + if ( NULL != g_dapl_provider_list.tail ) + { + dapl_os_free (g_dapl_provider_list.tail, sizeof (DAPL_PROVIDER_LIST_NODE)); + } + g_dapl_provider_list.initialized = DAT_FALSE; + } + + return status; +} + + +DAT_RETURN +dapl_provider_list_destroy ( void ) +{ + DAPL_PROVIDER_LIST_NODE *cur_node; + + while ( NULL != g_dapl_provider_list.head ) + { + cur_node = g_dapl_provider_list.head; + g_dapl_provider_list.head = cur_node->next; + + dapl_os_free (cur_node, sizeof (DAPL_PROVIDER_LIST_NODE)); + } + + g_dapl_provider_list.initialized = DAT_FALSE; + + return DAT_SUCCESS; +} + + +DAT_COUNT +dapl_provider_list_size ( void ) +{ + return g_dapl_provider_list.size; +} + + +DAT_RETURN +dapl_provider_list_insert ( + IN const char *name, + IN DAT_PROVIDER **p_data ) +{ + DAPL_PROVIDER_LIST_NODE *cur_node, *prev_node, *next_node; + DAT_RETURN status; + unsigned int len; + + status = DAT_SUCCESS; + + cur_node = dapl_os_alloc (sizeof (DAPL_PROVIDER_LIST_NODE)); + + if ( NULL == cur_node ) + { + status = DAT_ERROR (DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); + goto bail; + } + + if ( g_dapl_provider_list.initialized != DAT_TRUE ) + { + status = DAT_ERROR (DAT_INVALID_STATE,DAT_INVALID_ARG2); + goto bail; + } + + len = dapl_os_strlen(name); + + if ( DAT_NAME_MAX_LENGTH <= len ) + { + status = DAT_ERROR (DAT_INSUFFICIENT_RESOURCES,DAT_RESOURCE_MEMORY); + goto bail; + } + + /* insert node at end of list to preserve registration order*/ + prev_node = g_dapl_provider_list.tail->prev; + next_node = g_dapl_provider_list.tail; + + dapl_os_memcpy (cur_node->name, name, len); + cur_node->name[len] = '\0'; + cur_node->data = g_dapl_provider_template; + cur_node->data.device_name = cur_node->name; + cur_node->next = next_node; + cur_node->prev = prev_node; + + prev_node->next = cur_node; + next_node->prev = cur_node; + + g_dapl_provider_list.size++; + + if ( NULL != p_data ) + { + *p_data = &cur_node->data; + } + +bail: + if ( DAT_SUCCESS != status ) + { + if ( NULL != cur_node ) + { + dapl_os_free (cur_node, sizeof (DAPL_PROVIDER_LIST_NODE)); + } + } + + return status; +} + + +DAT_RETURN +dapl_provider_list_search ( + IN const char *name, + OUT DAT_PROVIDER **p_data ) +{ + DAPL_PROVIDER_LIST_NODE *cur_node; + DAT_RETURN status; + + status = DAT_ERROR (DAT_PROVIDER_NOT_FOUND,0); + + if ( g_dapl_provider_list.initialized != DAT_TRUE ) + { + status = DAT_ERROR (DAT_INVALID_STATE,DAT_INVALID_ARG2); + goto bail; + } + + + for (cur_node = g_dapl_provider_list.head->next; + g_dapl_provider_list.tail != cur_node; + cur_node = cur_node->next) + { + if ( dapl_provider_list_key_cmp (cur_node->name, name) ) + { + if ( NULL != p_data ) + { + *p_data = &cur_node->data; + } + + status = DAT_SUCCESS; + goto bail; + } + } + +bail: + return status; +} + + +DAT_RETURN +dapl_provider_list_remove ( + IN const char *name ) +{ + DAPL_PROVIDER_LIST_NODE *cur_node, *prev_node, *next_node; + DAT_RETURN status; + + status = DAT_ERROR (DAT_PROVIDER_NOT_FOUND,0); + + if ( g_dapl_provider_list.initialized != DAT_TRUE ) + { + status = DAT_ERROR (DAT_INVALID_STATE,DAT_INVALID_ARG2); + goto bail; + } + + for (cur_node = g_dapl_provider_list.head->next; + g_dapl_provider_list.tail != cur_node; + cur_node = cur_node->next) + { + if ( dapl_provider_list_key_cmp (cur_node->name, name) ) + { + prev_node = cur_node->prev; + next_node = cur_node->next; + + prev_node->next = next_node; + next_node->prev = prev_node; + + dapl_os_free (cur_node, sizeof (DAPL_PROVIDER_LIST_NODE)); + + g_dapl_provider_list.size--; + + status = DAT_SUCCESS; + goto bail; + } + } + +bail: + return status; +} + + +DAT_BOOLEAN +dapl_provider_list_key_cmp ( + const char *name_a, + const char *name_b ) +{ + unsigned int len; + + len = dapl_os_strlen (name_a); + + if ( dapl_os_strlen (name_b) != len ) + { + return DAT_FALSE; + } + else if ( dapl_os_memcmp (name_a, name_b, len) ) + { + return DAT_FALSE; + } + else + { + return DAT_TRUE; + } +} + + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_provider.h b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_provider.h new file mode 100644 index 00000000..06a2d7ff --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_provider.h @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dapl_provider.h + * + * PURPOSE: Provider function table + * Description: DAT Interfaces to this provider + * + * $Id$ + **********************************************************************/ + +#ifndef _DAPL_PROVIDER_H_ +#define _DAPL_PROVIDER_H_ + +#include "dapl.h" + + +/********************************************************************* + * * + * Structures * + * * + *********************************************************************/ + +typedef struct DAPL_PROVIDER_LIST_NODE +{ + char name[DAT_NAME_MAX_LENGTH]; + DAT_PROVIDER data; + struct DAPL_PROVIDER_LIST_NODE *next; + struct DAPL_PROVIDER_LIST_NODE *prev; +} DAPL_PROVIDER_LIST_NODE; + + +typedef struct DAPL_PROVIDER_LIST +{ + DAPL_PROVIDER_LIST_NODE *head; + DAPL_PROVIDER_LIST_NODE *tail; + DAT_COUNT size; + DAT_BOOLEAN initialized; +} DAPL_PROVIDER_LIST; + + +/********************************************************************* + * * + * Global Data * + * * + *********************************************************************/ + +extern DAPL_PROVIDER_LIST g_dapl_provider_list; +extern DAT_PROVIDER g_dapl_provider_template; +extern int g_dapl_loopback_connection; + + +/********************************************************************* + * * + * Function Prototypes * + * * + *********************************************************************/ + +extern DAT_RETURN +dapl_provider_list_create( void ); + +extern DAT_RETURN +dapl_provider_list_destroy( void ); + +extern DAT_COUNT +dapl_provider_list_size( void ); + +extern DAT_RETURN +dapl_provider_list_insert( + IN const char *name, + OUT DAT_PROVIDER **p_data ); + +extern DAT_RETURN +dapl_provider_list_search( + IN const char *name, + OUT DAT_PROVIDER **p_data ); + +extern DAT_RETURN +dapl_provider_list_remove( + IN const char *name ); + + +#endif /* _DAPL_PROVIDER_H_ */ diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_psp_create.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_psp_create.c new file mode 100644 index 00000000..7fd3024c --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_psp_create.c @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_psp_create.c + * + * PURPOSE: Connection management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 4 + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_sp_util.h" +#include "dapl_ia_util.h" +#include "dapl_adapter_util.h" + +/* + * dapl_psp_create + * + * uDAPL: User Direct Access Program Library Version 1.1, 6.4.1.1 + * + * Create a persistent Public Service Point that can recieve multiple + * requests for connections and generate multiple connection request + * instances that wil be delivered to the specified Event Dispatcher + * in a notification event. + * + * Input: + * ia_handle + * conn_qual + * evd_handle + * psp_flags + * + * Output: + * psp_handle + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + * DAT_CONN_QUAL_IN_USE + * DAT_MODEL_NOT_SUPPORTED + */ +DAT_RETURN +dapl_psp_create ( + IN DAT_IA_HANDLE ia_handle, + IN DAT_CONN_QUAL conn_qual, + IN DAT_EVD_HANDLE evd_handle, + IN DAT_PSP_FLAGS psp_flags, + OUT DAT_PSP_HANDLE *psp_handle ) +{ + DAPL_IA *ia_ptr; + DAPL_SP *sp_ptr; + DAPL_EVD *evd_ptr; + DAT_BOOLEAN sp_found; + DAT_RETURN dat_status; + + ia_ptr = (DAPL_IA *)ia_handle; + dat_status = DAT_SUCCESS; + + if ( DAPL_BAD_HANDLE (ia_ptr, DAPL_MAGIC_IA)) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE,DAT_INVALID_HANDLE_IA); + goto bail; + } + if (DAPL_BAD_HANDLE (evd_handle, DAPL_MAGIC_EVD)) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE,DAT_INVALID_HANDLE_EVD_CR); + goto bail; + } + + if ( psp_handle == NULL ) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER,DAT_INVALID_ARG5); + goto bail; + } + + evd_ptr = (DAPL_EVD *)evd_handle; + if ( ! (evd_ptr->evd_flags & DAT_EVD_CR_FLAG) ) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE,DAT_INVALID_HANDLE_EVD_CR); + goto bail; + } + + if (psp_flags != DAT_PSP_CONSUMER_FLAG && + psp_flags != DAT_PSP_PROVIDER_FLAG) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER,DAT_INVALID_ARG4); + goto bail; + } + + + /* + * See if we have a quiescent listener to use for this PSP, else + * create one and set it listening + */ + sp_ptr = dapls_ia_sp_search (ia_ptr, conn_qual, DAT_TRUE); + sp_found = DAT_TRUE; + if (sp_ptr == NULL) + { + /* Allocate PSP */ + sp_found = DAT_FALSE; + sp_ptr = dapls_sp_alloc ( ia_ptr, DAT_TRUE ); + if ( sp_ptr == NULL ) + { + dat_status = + DAT_ERROR (DAT_INSUFFICIENT_RESOURCES,DAT_RESOURCE_MEMORY); + goto bail; + } + } + else if (sp_ptr->listening == DAT_TRUE) + { + dat_status = DAT_ERROR (DAT_CONN_QUAL_IN_USE, 0); + goto bail; + } + + /* + * Fill out the args for a PSP + */ + sp_ptr->ia_handle = ia_handle; + sp_ptr->conn_qual = conn_qual; + sp_ptr->evd_handle = evd_handle; + sp_ptr->psp_flags = psp_flags; + sp_ptr->ep_handle = NULL; + + /* + * Take a reference on the EVD handle + */ + dapl_os_atomic_inc (& ((DAPL_EVD *)evd_handle)->evd_ref_count); + + /* + * Set up a listener for a connection. Connections can arrive + * even before this call returns! + */ + sp_ptr->state = DAPL_SP_STATE_PSP_LISTENING; + sp_ptr->listening = DAT_TRUE; + + /* + * If this is a new sp we need to add it to the IA queue, and set up + * a conn_listener. + */ + if (sp_found == DAT_FALSE) + { + /* Link it onto the IA before enabling it to receive conn + * requests + */ + dapl_ia_link_psp (ia_ptr, sp_ptr); + + dat_status = dapls_ib_setup_conn_listener ( ia_ptr, + conn_qual, + sp_ptr ); + + if ( dat_status != DAT_SUCCESS ) + { + /* + * Have a problem setting up the connection, something + * wrong! Decrements the EVD refcount & release it. + */ + dapl_os_atomic_dec (& ((DAPL_EVD *)evd_handle)->evd_ref_count); + sp_ptr->evd_handle = NULL; + dapls_ia_unlink_sp ( ia_ptr, sp_ptr ); + dapls_sp_free_sp ( sp_ptr ); + + dapl_dbg_log (DAPL_DBG_TYPE_CM, + "--> dapl_psp_create setup_conn_listener failed: %x\n", + dat_status); + + goto bail; + } + } + + /* + * Return handle to the user + */ + *psp_handle = (DAT_PSP_HANDLE)sp_ptr; + + bail: + return dat_status; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * c-brace-offset: -4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_psp_create_any.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_psp_create_any.c new file mode 100644 index 00000000..64f1728d --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_psp_create_any.c @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_psp_create.c + * + * PURPOSE: Connection management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 4 + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_sp_util.h" +#include "dapl_ia_util.h" +#include "dapl_adapter_util.h" + +/* + * dapl_psp_create_any + * + * uDAPL: User Direct Access Program Library Version 1.1, 6.4.3.3 + * + * Create a persistent Public Service Point that can recieve multiple + * requests for connections and generate multiple connection request + * instances that wil be delivered to the specified Event Dispatcher + * in a notification event. Differs from dapl_psp_create() in that + * the conn_qual is selected by the implementation and returned to + * the user. + * + * Input: + * ia_handle + * evd_handle + * psp_flags + * + * Output: + * conn_qual + * psp_handle + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_HANDLE + * DAT_INVALID_PARAMETER + * DAT_CONN_QUAL_IN_USE + * DAT_MODEL_NOT_SUPPORTED + */ +DAT_RETURN +dapl_psp_create_any ( + IN DAT_IA_HANDLE ia_handle, + OUT DAT_CONN_QUAL *conn_qual, + IN DAT_EVD_HANDLE evd_handle, + IN DAT_PSP_FLAGS psp_flags, + OUT DAT_PSP_HANDLE *psp_handle ) +{ + DAPL_IA *ia_ptr; + DAPL_SP *sp_ptr; + DAPL_EVD *evd_ptr; + DAT_RETURN dat_status; + static DAT_CONN_QUAL hint_conn_qual = 1000; /* seed value */ + DAT_CONN_QUAL limit_conn_qual; + + ia_ptr = (DAPL_IA *)ia_handle; + dat_status = DAT_SUCCESS; + + if ( DAPL_BAD_HANDLE (ia_ptr, DAPL_MAGIC_IA)) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE,DAT_INVALID_HANDLE_IA); + goto bail; + } + if (DAPL_BAD_HANDLE (evd_handle, DAPL_MAGIC_EVD)) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE,DAT_INVALID_HANDLE_EVD_CR); + goto bail; + } + + if ( psp_handle == NULL ) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER,DAT_INVALID_ARG5); + goto bail; + } + if (conn_qual == NULL) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER,DAT_INVALID_ARG2); + goto bail; + } + + evd_ptr = (DAPL_EVD *)evd_handle; + if ( ! (evd_ptr->evd_flags & DAT_EVD_CR_FLAG) ) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE,DAT_INVALID_HANDLE_EVD_CR); + goto bail; + } + + if (psp_flags != DAT_PSP_CONSUMER_FLAG && + psp_flags != DAT_PSP_PROVIDER_FLAG) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER,DAT_INVALID_ARG4); + goto bail; + } + + /* Allocate PSP */ + sp_ptr = dapls_sp_alloc ( ia_ptr, DAT_TRUE ); + if ( sp_ptr == NULL ) + { + dat_status = DAT_ERROR (DAT_INSUFFICIENT_RESOURCES,DAT_RESOURCE_MEMORY); + goto bail; + } + + /* + * Fill out the args for a PSP + */ + sp_ptr->ia_handle = ia_handle; + sp_ptr->evd_handle = evd_handle; + sp_ptr->psp_flags = psp_flags; + sp_ptr->ep_handle = NULL; + + /* + * Take a reference on the EVD handle + */ + dapl_os_atomic_inc (& ((DAPL_EVD *)evd_handle)->evd_ref_count); + + /* Link it onto the IA */ + dapl_ia_link_psp (ia_ptr, sp_ptr); + + /* + * Set up a listener for a connection. Connections can arrive + * even before this call returns! + */ + sp_ptr->state = DAPL_SP_STATE_PSP_LISTENING; + sp_ptr->listening = DAT_TRUE; + + limit_conn_qual = 0; + dat_status = ~DAT_SUCCESS; + + while (dat_status != DAT_SUCCESS) + { + srand ( (DAT_UINT32)dapl_os_get_ticks () ); + hint_conn_qual += rand(); + sp_ptr->conn_qual = hint_conn_qual; + + dat_status = dapls_ib_setup_conn_listener ( ia_ptr, + sp_ptr->conn_qual, + sp_ptr ); + /* + * If we have a big number of tries and we still haven't + * found a service_ID we can use, bail out with an error, + * something is wrong! + */ + if ( limit_conn_qual++ > 100000) + { + dat_status = DAT_CONN_QUAL_UNAVAILABLE; + break; + } + } + + if ( dat_status != DAT_SUCCESS ) + { + /* + * Have a problem setting up the connection, something wrong! + */ + dapl_os_atomic_dec (& ((DAPL_EVD *)evd_handle)->evd_ref_count); + sp_ptr->evd_handle = NULL; + dapls_ia_unlink_sp ( ia_ptr, sp_ptr ); + dapls_sp_free_sp ( sp_ptr ); + + dapl_os_printf ("--> dapl_psp_create cannot set up conn listener: %x\n", dat_status); + + goto bail; + } + + /* + * Return handle to the user + */ + *conn_qual = sp_ptr->conn_qual; + *psp_handle = (DAT_PSP_HANDLE)sp_ptr; + + bail: + return dat_status; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * c-brace-offset: -4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_psp_free.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_psp_free.c new file mode 100644 index 00000000..1f184279 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_psp_free.c @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_psp_free.c + * + * PURPOSE: Connection management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 4 + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_sp_util.h" +#include "dapl_ia_util.h" +#include "dapl_adapter_util.h" + +/* + * dapl_psp_free + * + * uDAPL: User Direct Access Program Library Version 1.1, 6.4.1.2 + * + * Destroy a specific instance of a Service Point. + * + * Input: + * psp_handle + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + */ +DAT_RETURN +dapl_psp_free ( + IN DAT_PSP_HANDLE psp_handle ) +{ + DAPL_IA *ia_ptr; + DAPL_SP *sp_ptr; + DAT_RETURN dat_status; + + sp_ptr = (DAPL_SP *) psp_handle; + dat_status = DAT_SUCCESS; + /* + * Verify handle + */ + dapl_dbg_log (DAPL_DBG_TYPE_CM, ">>> dapl_psp_free %p\n", psp_handle); + + if ( DAPL_BAD_HANDLE (sp_ptr, DAPL_MAGIC_PSP ) ) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE,DAT_INVALID_HANDLE_PSP); + goto bail; + } + + /* ia_ptr = (DAPL_IA *)sp_ptr->header.owner_ia; */ + ia_ptr = sp_ptr->header.owner_ia; + /* + * Remove the connection listener if it has been established + * and there are no current connections in progress. + * If we defer removing the sp it becomes something of a zombie + * container until the last connection is disconnected, after + * which it will be cleaned up. + */ + dapl_os_lock (&sp_ptr->header.lock); + + sp_ptr->listening = DAT_FALSE; + + /* Release reference on EVD. If an error was encountered in a previous + * free the evd_handle will be NULL + */ + if (sp_ptr->evd_handle) + { + dapl_os_atomic_dec (& ((DAPL_EVD *)sp_ptr->evd_handle)->evd_ref_count); + sp_ptr->evd_handle = NULL; + } + + /* + * Release the base resource if there are no outstanding + * connections; else the last disconnect on this PSP will free it + * up. The PSP is used to contain CR records for each connection, + * which contain information necessary to disconnect. + */ + if ( (sp_ptr->state == DAPL_SP_STATE_PSP_LISTENING || + sp_ptr->state == DAPL_SP_STATE_PSP_PENDING) && + sp_ptr->cr_list_count == 0 ) + { + sp_ptr->state = DAPL_SP_STATE_FREE; + dapl_os_unlock (&sp_ptr->header.lock); + + dat_status = dapls_ib_remove_conn_listener ( ia_ptr, + sp_ptr ); + if (dat_status != DAT_SUCCESS) + { + /* revert to entry state on error */ + sp_ptr->state = DAPL_SP_STATE_PSP_LISTENING; + goto bail; + } + dapls_ia_unlink_sp ( ia_ptr, sp_ptr ); + dapls_sp_free_sp ( sp_ptr ); + } + else + { + /* The PSP is now in the pending state, where it will sit until + * the last connection terminates or the app uses the same + * ServiceID again, which will reactivate it. + */ + sp_ptr->state = DAPL_SP_STATE_PSP_PENDING; + dapl_os_unlock (&sp_ptr->header.lock); + dapl_dbg_log (DAPL_DBG_TYPE_CM, ">>> dapl_psp_free: PSP PENDING\n"); + } + + bail: + return dat_status; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * c-brace-offset: -4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_psp_query.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_psp_query.c new file mode 100644 index 00000000..6bd49c89 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_psp_query.c @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_psp_query.c + * + * PURPOSE: Connection management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 4 + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" + +/* + * dapl_psp_query + * + * uDAPL: User Direct Access Program Library Version 1.1, 6.4.1.3 + * + * Provide arguments of the public service points + * + * Input: + * psp_handle + * psp_args_mask + * + * Output: + * psp_args + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + */ +DAT_RETURN +dapl_psp_query ( + IN DAT_PSP_HANDLE psp_handle, + IN DAT_PSP_PARAM_MASK psp_args_mask, + OUT DAT_PSP_PARAM *psp_param ) +{ + DAPL_SP *sp_ptr; + DAT_RETURN dat_status; + UNREFERENCED_PARAMETER(psp_args_mask); + + dat_status = DAT_SUCCESS; + + if ( DAPL_BAD_HANDLE (psp_handle, DAPL_MAGIC_PSP) || + ((DAPL_SP *)psp_handle)->listening != DAT_TRUE ) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE,DAT_INVALID_HANDLE_PSP); + goto bail; + } + + if (NULL == psp_param) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER,DAT_INVALID_ARG3); + goto bail; + } + + sp_ptr = (DAPL_SP *) psp_handle; + + /* + * Fill in the PSP params + */ + psp_param->ia_handle = sp_ptr->ia_handle; + psp_param->conn_qual = sp_ptr->conn_qual; + psp_param->evd_handle = sp_ptr->evd_handle; + psp_param->psp_flags = sp_ptr->psp_flags; + + bail: + return dat_status; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * c-brace-offset: -4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_pz_create.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_pz_create.c new file mode 100644 index 00000000..b129b845 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_pz_create.c @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_pz_create.c + * + * PURPOSE: Memory management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 6 + * + * $Id$ + **********************************************************************/ + +#include "dapl_pz_util.h" +#include "dapl_adapter_util.h" + +/* + * dapl_pz_create + * + * DAPL Requirements Version xxx, 6.6.2.1 + * + * Create an instance of a protection zone + * + * Input: + * ia_handle + * + * Output: + * pz_handle + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + */ +DAT_RETURN +dapl_pz_create ( + IN DAT_IA_HANDLE ia_handle, + OUT DAT_PZ_HANDLE *pz_handle) +{ + DAPL_IA *ia; + DAPL_PZ *pz; + DAT_RETURN dat_status; + + dapl_dbg_log (DAPL_DBG_TYPE_API, + "dapl_pz_create (%p, %p)\n", + ia_handle, + pz_handle); + + dat_status = DAT_SUCCESS; + if ( DAPL_BAD_HANDLE (ia_handle, DAPL_MAGIC_IA) ) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE,DAT_INVALID_HANDLE_IA); + goto bail; + } + + if (NULL == pz_handle) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER,DAT_INVALID_ARG2); + goto bail; + } + + ia = (DAPL_IA *) ia_handle; + + pz = dapl_pz_alloc (ia); + if ( pz == NULL ) + { + dat_status = DAT_ERROR (DAT_INSUFFICIENT_RESOURCES,DAT_RESOURCE_MEMORY); + goto bail; + } + + dat_status = dapls_ib_pd_alloc (ia, pz); + + if ( dat_status != DAT_SUCCESS ) + { + dapl_pz_dealloc (pz); + pz = NULL; + } + + *pz_handle = pz; + + bail: + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_pz_free.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_pz_free.c new file mode 100644 index 00000000..95c3950a --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_pz_free.c @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_pz_create.c + * + * PURPOSE: Memory management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 6 + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_pz_util.h" +#include "dapl_adapter_util.h" +#include "dapl_ia_util.h" + +/* + * dapl_pz_free + * + * DAPL Requirements Version xxx, 6.6.2.1 + * + * Remove an instance of a protection zone + * + * Input: + * pz_handle + * + * Output: + * None. + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + * DAT_INVALID_STATE + */ +DAT_RETURN +dapl_pz_free ( + IN DAT_PZ_HANDLE pz_handle) +{ + DAPL_PZ *pz; + DAT_RETURN dat_status; + + dapl_dbg_log (DAPL_DBG_TYPE_API, "dapl_pz_free (%p)\n", pz_handle); + + dat_status = DAT_SUCCESS; + if ( DAPL_BAD_HANDLE (pz_handle, DAPL_MAGIC_PZ) ) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE,DAT_INVALID_HANDLE_PZ); + goto bail; + } + + pz = (DAPL_PZ *) pz_handle; + + if ( 0 != pz->pz_ref_count ) + { + dat_status = DAT_ERROR (DAT_INVALID_STATE,DAT_INVALID_STATE_PZ_IN_USE); + goto bail; + } + + dat_status = dapls_ib_pd_free (pz); + + if ( dat_status == DAT_SUCCESS ) + { + dapl_pz_dealloc (pz); + } + + bail: + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_pz_query.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_pz_query.c new file mode 100644 index 00000000..7ebcd534 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_pz_query.c @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_pz_query.c + * + * PURPOSE: Memory management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 6 + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" + +/* + * dapl_pz_query + * + * DAPL Requirements Version xxx, 6.6.2.1 + * + * Return the ia associated with the protection zone pz + * + * Input: + * pz_handle + * pz_param_mask + * + * Output: + * pz_param + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + * DAT_INVALID_PARAMETER + */ +DAT_RETURN +dapl_pz_query ( + IN DAT_PZ_HANDLE pz_handle, + IN DAT_PZ_PARAM_MASK pz_param_mask, + OUT DAT_PZ_PARAM *pz_param) +{ + DAPL_PZ *pz; + DAT_RETURN dat_status; + + dapl_dbg_log (DAPL_DBG_TYPE_API, + "dapl_pz_query (%p, %x, %p)\n", + pz_handle, + pz_param_mask, + pz_param); + + dat_status = DAT_SUCCESS; + + if ( DAPL_BAD_HANDLE (pz_handle, DAPL_MAGIC_PZ) ) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE,DAT_INVALID_HANDLE_PZ); + goto bail; + } + if (NULL == pz_param) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER,DAT_INVALID_ARG3); + goto bail; + } + + pz = (DAPL_PZ *) pz_handle; + + /* Since the DAT_PZ_ARGS values are easily accessible, */ + /* don't bother checking the DAT_PZ_ARGS_MASK value */ + pz_param->ia_handle = (DAT_IA_HANDLE) pz->header.owner_ia; + + bail: + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_pz_util.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_pz_util.c new file mode 100644 index 00000000..ac3d871e --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_pz_util.c @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_pz_util.c + * + * PURPOSE: Manage PZ structure + * + * $Id$ + **********************************************************************/ + +#include "dapl_pz_util.h" +#include "dapl_ia_util.h" + +/* + * dapl_pz_alloc + * + * alloc and initialize an PZ struct + * + * Input: + * none + * + * Output: + * pz_ptr + * + * Returns: + * none + * + */ +DAPL_PZ * +dapl_pz_alloc ( + IN DAPL_IA *ia) +{ + DAPL_PZ *pz; + + /* Allocate PZ */ + pz = (DAPL_PZ *) dapl_os_alloc (sizeof (DAPL_PZ)); + if (NULL == pz) + { + return (NULL); + } + + /* zero the structure */ + dapl_os_memzero (pz, sizeof (DAPL_PZ)); + + /* + * initialize the header + */ + pz->header.provider = ia->header.provider; + pz->header.magic = DAPL_MAGIC_PZ; + pz->header.handle_type = DAT_HANDLE_TYPE_PZ; + pz->header.owner_ia = ia; + pz->header.user_context.as_64 = 0; + pz->header.user_context.as_ptr = NULL; + dapl_llist_init_entry (&pz->header.ia_list_entry); + dapl_ia_link_pz (ia, pz); + dapl_os_lock_init (&pz->header.lock); + + /* + * initialize the body + */ + pz->pz_ref_count = 0; + + return (pz); +} + +/* + * dapl_pz_free + * + * free an PZ struct + * + * Input: + * pz_ptr + * + * Output: + * none + * + * Returns: + * none + * + */ +void +dapl_pz_dealloc ( + IN DAPL_PZ *pz) +{ + pz->header.magic = DAPL_MAGIC_INVALID; /* reset magic to prevent reuse */ + dapl_ia_unlink_pz (pz->header.owner_ia, pz); + dapl_os_lock_destroy (&pz->header.lock); + + dapl_os_free (pz, sizeof (DAPL_PZ)); +} diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_pz_util.h b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_pz_util.h new file mode 100644 index 00000000..6e90fd72 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_pz_util.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dapl_pz_util.h + * + * PURPOSE: Utility defs & routines for the PZ data structure + * + * $Id$ + * + **********************************************************************/ + +#ifndef _DAPL_PZ_UTIL_H_ +#define _DAPL_PZ_UTIL_H_ + +#include "dapl.h" + +extern DAPL_PZ * +dapl_pz_alloc ( + IN DAPL_IA *ia); + +extern void +dapl_pz_dealloc ( + IN DAPL_PZ *pz); + +#endif /* _DAPL_PZ_UTIL_H_ */ diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ring_buffer_util.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ring_buffer_util.c new file mode 100644 index 00000000..11d574ff --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ring_buffer_util.c @@ -0,0 +1,348 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ring_buffer_util.c + * + * PURPOSE: Ring buffer management + * Description: Support and management functions for ring buffers + * + * $Id$ + **********************************************************************/ + +#include "dapl_ring_buffer_util.h" + + +/* + * dapls_rbuf_alloc + * + * Given a DAPL_RING_BUFFER, initialize it and provide memory for + * the ringbuf itself. A passed in size will be adjusted to the next + * largest power of two number to simplify management. + * + * Input: + * rbuf pointer to DAPL_RING_BUFFER + * size number of elements to allocate & manage + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * + */ +DAT_RETURN +dapls_rbuf_alloc ( + INOUT DAPL_RING_BUFFER *rbuf, + IN DAT_COUNT size ) +{ + unsigned int rsize; /* real size */ + + /* The circular buffer must be allocated one too large. + * This eliminates any need for a distinct counter, as that + * having the two pointers equal always means "empty" -- never "full" + */ + size++; + + /* Put size on a power of 2 boundary */ + rsize = 1; + while ( (DAT_COUNT)rsize < size) + { + rsize <<= 1; + } + + rbuf->base = (void *) dapl_os_alloc (rsize * sizeof (void *)); + if ( rbuf->base != NULL ) + { + rbuf->lim = rsize - 1; + rbuf->head = 0; + rbuf->tail = 0; + } + else + { + return DAT_INSUFFICIENT_RESOURCES | DAT_RESOURCE_MEMORY; + } + + return DAT_SUCCESS; +} + + +/* + * dapls_rbuf_realloc + * + * Resizes an empty DAPL_RING_BUFFER. This function is not thread safe; + * adding or removing elements from a ring buffer while resizing + * will have indeterminate results. + * + * Input: + * rbuf pointer to DAPL_RING_BUFFER + * size number of elements to allocate & manage + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_STATE + * DAT_INSUFFICIENT_RESOURCES + * + */ +DAT_RETURN +dapls_rbuf_realloc ( + INOUT DAPL_RING_BUFFER *rbuf, + IN DAT_COUNT size ) +{ + int rsize; /* real size */ + DAT_RETURN dat_status; + + dat_status = DAT_SUCCESS; + + /* if the ring buffer is not empty */ + if ( rbuf->head != rbuf->tail ) + { + dat_status = DAT_ERROR (DAT_INVALID_STATE,0); + goto bail; + } + + /* Put size on a power of 2 boundary */ + rsize = 1; + while (rsize < size) + { + rsize <<= 1; + } + + rbuf->base = (void *) dapl_os_realloc (rbuf->base, rsize * sizeof (void *)); + if ( NULL == rbuf->base ) + { + dat_status = DAT_ERROR (DAT_INSUFFICIENT_RESOURCES,DAT_RESOURCE_MEMORY); + goto bail; + } + + rbuf->lim = rsize - 1; + + bail: + return dat_status; +} + + +/* + * dapls_rbuf_destroy + * + * Release the buffer and reset pointers to a DAPL_RING_BUFFER + * + * Input: + * rbuf pointer to DAPL_RING_BUFFER + * + * Output: + * none + * + * Returns: + * none + * + */ +void +dapls_rbuf_destroy ( + IN DAPL_RING_BUFFER *rbuf) +{ + if ( (NULL == rbuf) || + (NULL == rbuf->base) ) + { + return; + } + + dapl_os_free (rbuf->base, (rbuf->lim + 1) * sizeof (void *)); + rbuf->base = NULL; + rbuf->lim = 0; + + return; +} + +/* + * dapls_rbuf_add + * + * Add an entry to the ring buffer + * + * Input: + * rbuf pointer to DAPL_RING_BUFFER + * entry entry to add + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES (queue full) + * + */ +DAT_RETURN +dapls_rbuf_add ( + IN DAPL_RING_BUFFER *rbuf, + IN void *entry) +{ + int pos; + int val; + + while ( ((rbuf->head + 1) & rbuf->lim) != (rbuf->tail & rbuf->lim) ) + { + pos = rbuf->head; + val = dapl_os_atomic_assign (&rbuf->head, pos, pos + 1); + if ( val == pos ) + { + pos = (pos + 1) & rbuf->lim; /* verify in range */ + rbuf->base[pos] = entry; + return DAT_SUCCESS; + } + } + + return DAT_ERROR (DAT_INSUFFICIENT_RESOURCES,DAT_RESOURCE_MEMORY); + +} + + +/* + * dapls_rbuf_remove + * + * Remove an entry from the ring buffer + * + * Input: + * rbuf pointer to DAPL_RING_BUFFER + * + * Output: + * entry entry removed from the ring buffer + * + * Returns: + * DAT_SUCCESS + * DAT_QUEUE_EMPTY + + */ +void * +dapls_rbuf_remove ( + IN DAPL_RING_BUFFER *rbuf ) +{ + int pos; + int val; + + while ( rbuf->head != rbuf->tail ) + { + pos = rbuf->tail; + val = dapl_os_atomic_assign (&rbuf->tail, pos, pos + 1); + if ( val == pos ) + { + pos = (pos + 1) & rbuf->lim; /* verify in range */ + + return (rbuf->base[pos]); + } + } + + return NULL; + +} + +/* + * dapli_rbuf_count + * + * Return the number of entries in use in the ring buffer + * + * Input: + * rbuf pointer to DAPL_RING_BUFFER + * + * + * Output: + * none + * + * Returns: + * count of entries + * + */ +DAT_COUNT +dapls_rbuf_count ( + IN DAPL_RING_BUFFER *rbuf ) +{ + DAT_COUNT count; + int head; + int tail; + + head = rbuf->head & rbuf->lim; + tail = rbuf->tail & rbuf->lim; + if ( head > tail ) + { + count = head - tail; + } + else + { + /* add 1 to lim as it is a mask, number of entries - 1 */ + count = (rbuf->lim + 1 - tail + head) & rbuf->lim; + } + + return count; +} + + +/* + * dapls_rbuf_contains + * + * Return TRUE or FALSE if an element exists in a ring buffer + * + * Input: + * rbuf pointer to DAPL_RING_BUFFER + * entry entry to match + * + * Output: + * none + * + * Returns: + * DAT_TRUE + * DAT_FALSE + + */ +DAT_BOOLEAN +dapls_rbuf_contains ( + IN DAPL_RING_BUFFER *rbuf, + IN void *entry) +{ + int pos; + + pos = rbuf->head; + while ( pos != rbuf->tail ) + { + if (rbuf->base[pos] == entry) + return DAT_TRUE; + pos = (pos + 1) & rbuf->lim; /* verify in range */ + } + + return DAT_FALSE; + +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ring_buffer_util.h b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ring_buffer_util.h new file mode 100644 index 00000000..58a585b1 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_ring_buffer_util.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dapl_ring_buffer_util.h + * + * PURPOSE: Utility defs & routines for the ring buffer data structure + * + * $Id$ + * + **********************************************************************/ + +#ifndef _DAPL_RING_BUFFER_H_ +#define _DAPL_RING_BUFFER_H_ + +#include "dapl.h" + +/* + * Prototypes + */ +DAT_RETURN dapls_rbuf_alloc ( + DAPL_RING_BUFFER *rbuf, + DAT_COUNT size ); + +DAT_RETURN dapls_rbuf_realloc ( + DAPL_RING_BUFFER *rbuf, + DAT_COUNT size ); + +void dapls_rbuf_destroy ( + DAPL_RING_BUFFER *rbuf); + +DAT_RETURN dapls_rbuf_add ( + DAPL_RING_BUFFER *rbuf, + void *entry); + +void * dapls_rbuf_remove ( + DAPL_RING_BUFFER *rbuf); + +DAT_COUNT dapls_rbuf_count ( + DAPL_RING_BUFFER *rbuf ); + +DAT_BOOLEAN dapls_rbuf_contains ( + IN DAPL_RING_BUFFER *rbuf, + IN void *entry); + + +/* + * Simple functions + */ +#define dapls_rbuf_empty(rbuf) (rbuf->head == rbuf->tail) + + +#endif /* _DAPL_RING_BUFFER_H_ */ diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_rmr_bind.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_rmr_bind.c new file mode 100644 index 00000000..4de96685 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_rmr_bind.c @@ -0,0 +1,348 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_rmr_bind.c + * + * PURPOSE: Memory management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 6 + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_rmr_util.h" +#include "dapl_ep_util.h" +#include "dapl_cookie.h" +#include "dapl_adapter_util.h" + +/********************************************************************* + * * + * Function Prototypes * + * * + *********************************************************************/ + +STATIC _INLINE_ DAT_RETURN +dapli_rmr_bind_fuse ( + IN DAPL_RMR *rmr, + IN const DAT_LMR_TRIPLET *lmr_triplet, + IN DAT_MEM_PRIV_FLAGS mem_priv, + IN DAPL_EP *ep_ptr, + IN DAT_RMR_COOKIE user_cookie, + IN DAT_COMPLETION_FLAGS completion_flags, + OUT DAT_RMR_CONTEXT *rmr_context ); + +STATIC _INLINE_ DAT_RETURN +dapli_rmr_bind_unfuse ( + IN DAPL_RMR *rmr, + IN DAPL_EP *ep_ptr, + IN DAT_RMR_COOKIE user_cookie, + IN DAT_COMPLETION_FLAGS completion_flags); + + +/********************************************************************* + * * + * Function Definitions * + * * + *********************************************************************/ + +STATIC _INLINE_ DAT_RETURN +dapli_rmr_bind_fuse ( + IN DAPL_RMR *rmr, + IN const DAT_LMR_TRIPLET* lmr_triplet, + IN DAT_MEM_PRIV_FLAGS mem_priv, + IN DAPL_EP *ep_ptr, + IN DAT_RMR_COOKIE user_cookie, + IN DAT_COMPLETION_FLAGS completion_flags, + OUT DAT_RMR_CONTEXT *rmr_context ) +{ + DAPL_LMR *lmr; + DAPL_COOKIE *cookie; + DAT_RETURN dat_status; + ib_bool_t is_signaled; + + dat_status = dapls_hash_search (rmr->header.owner_ia->hca_ptr->lmr_hash_table, + lmr_triplet->lmr_context, + (DAPL_HASH_DATA *) &lmr); + if ( DAT_SUCCESS != dat_status) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER, DAT_INVALID_ARG2); + goto bail; + } + + /* if the ep in unconnected return an error. IB requires that the */ + /* QP be connected to change a memory window binding since: */ + /* */ + /* - memory window bind operations are WQEs placed on a QP's */ + /* send queue */ + /* */ + /* - QP's only process WQEs on the send queue when the QP is in */ + /* the RTS state */ + if (DAT_EP_STATE_CONNECTED != ep_ptr->param.ep_state) + { + dat_status = DAT_ERROR (DAT_INVALID_STATE, dapls_ep_state_subtype (ep_ptr)); + goto bail; + } + + if ( DAT_FALSE == dapl_mr_bounds_check ( + dapl_mr_get_address (lmr->param.region_desc, lmr->param.mem_type), + lmr->param.length, + lmr_triplet->virtual_address, + lmr_triplet->segment_length) ) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER, DAT_INVALID_ARG2); + goto bail; + } + + /* If the LMR, RMR, and EP are not in the same PZ, there is an error */ + if ( (ep_ptr->param.pz_handle != lmr->param.pz_handle) || + (ep_ptr->param.pz_handle != rmr->param.pz_handle) ) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER, DAT_INVALID_ARG4); + goto bail; + } + + if ( !dapl_rmr_validate_completion_flag (DAT_COMPLETION_SUPPRESS_FLAG, + ep_ptr->param.ep_attr.request_completion_flags, + completion_flags) || + !dapl_rmr_validate_completion_flag (DAT_COMPLETION_UNSIGNALLED_FLAG, + ep_ptr->param.ep_attr.request_completion_flags, + completion_flags) || + !dapl_rmr_validate_completion_flag (DAT_COMPLETION_BARRIER_FENCE_FLAG, + ep_ptr->param.ep_attr.request_completion_flags, + completion_flags) ) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER, DAT_INVALID_ARG4); + goto bail; + } + + dat_status = dapls_rmr_cookie_alloc (&ep_ptr->req_buffer, + rmr, + user_cookie, + &cookie); + if ( DAT_SUCCESS != dat_status ) + { + goto bail; + } + + is_signaled = (completion_flags & DAT_COMPLETION_SUPPRESS_FLAG) ? false : true; + + /* + * Take reference before posting to avoid race conditions with + * completions + */ + dapl_os_atomic_inc (&ep_ptr->req_count); + + dat_status = dapls_ib_mw_bind (rmr, + lmr, + ep_ptr, + cookie, + lmr_triplet->virtual_address, + lmr_triplet->segment_length, + mem_priv, + is_signaled); + if ( DAT_SUCCESS != dat_status ) + { + dapl_os_atomic_dec (&ep_ptr->req_count); + dapls_cookie_dealloc (&ep_ptr->req_buffer, cookie); + goto bail; + } + + dapl_os_atomic_inc (&lmr->lmr_ref_count); + + /* if the RMR was previously bound */ + if ( NULL != rmr->lmr ) + { + dapl_os_atomic_dec (&rmr->lmr->lmr_ref_count); + } + + rmr->param.mem_priv = mem_priv; + rmr->param.lmr_triplet = *lmr_triplet; + rmr->ep = ep_ptr; + rmr->lmr = lmr; + + if ( NULL != rmr_context ) + { + *rmr_context = rmr->param.rmr_context; + } + +bail: + return dat_status; +} + + +STATIC _INLINE_ DAT_RETURN +dapli_rmr_bind_unfuse ( + IN DAPL_RMR *rmr, + IN DAPL_EP *ep_ptr, + IN DAT_RMR_COOKIE user_cookie, + IN DAT_COMPLETION_FLAGS completion_flags) +{ + DAPL_COOKIE *cookie; + DAT_RETURN dat_status; + ib_bool_t is_signaled; + + dat_status = DAT_SUCCESS; + /* + * if the ep in unconnected return an error. IB requires that the + * QP be connected to change a memory window binding since: + * + * - memory window bind operations are WQEs placed on a QP's + * send queue + * + * - QP's only process WQEs on the send queue when the QP is in + * the RTS state + */ + if (DAT_EP_STATE_CONNECTED != ep_ptr->param.ep_state) + { + dat_status = DAT_ERROR (DAT_INVALID_STATE, dapls_ep_state_subtype (ep_ptr)); + goto bail1; + } + + /* If the RMR and EP are not in the same PZ, there is an error */ + if ( ep_ptr->param.pz_handle != rmr->param.pz_handle ) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER, DAT_INVALID_ARG2); + goto bail1; + } + + if ( !dapl_rmr_validate_completion_flag (DAT_COMPLETION_SUPPRESS_FLAG, + ep_ptr->param.ep_attr.request_completion_flags, + completion_flags) || + !dapl_rmr_validate_completion_flag (DAT_COMPLETION_UNSIGNALLED_FLAG, + ep_ptr->param.ep_attr.request_completion_flags, + completion_flags) || + !dapl_rmr_validate_completion_flag (DAT_COMPLETION_BARRIER_FENCE_FLAG, + ep_ptr->param.ep_attr.request_completion_flags, + completion_flags) ) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER, DAT_INVALID_ARG2); + goto bail1; + } + + dat_status = dapls_rmr_cookie_alloc (&ep_ptr->req_buffer, + rmr, + user_cookie, + &cookie); + if ( DAT_SUCCESS != dat_status ) + { + goto bail1; + } + + is_signaled = (completion_flags & DAT_COMPLETION_UNSIGNALLED_FLAG) ? false : true; + + /* + * Take reference before posting to avoid race conditions with + * completions + */ + dapl_os_atomic_inc (&ep_ptr->req_count); + + dat_status = dapls_ib_mw_unbind (rmr, + ep_ptr, + cookie, + is_signaled); + if ( DAT_SUCCESS != dat_status ) + { + dapl_os_atomic_dec (&ep_ptr->req_count); + dapls_cookie_dealloc (&ep_ptr->req_buffer, cookie); + goto bail1; + } + + /* if the RMR was previously bound */ + if ( NULL != rmr->lmr ) + { + dapl_os_atomic_dec (&rmr->lmr->lmr_ref_count); + } + + rmr->param.mem_priv = DAT_MEM_PRIV_NONE_FLAG; + rmr->param.lmr_triplet.lmr_context = 0; + rmr->param.lmr_triplet.virtual_address = 0; + rmr->param.lmr_triplet.segment_length = 0; + rmr->ep = ep_ptr; + rmr->lmr = NULL; + +bail1: + return dat_status; +} + + +/* + * dapl_rmr_bind + * + * DAPL Requirements Version xxx, 6.6.4.4 + * + * Bind the RMR to the specified memory region within the LMR and + * provide a new rmr_context value. + * + * Input: + * Output: + */ +DAT_RETURN +dapl_rmr_bind ( + IN DAT_RMR_HANDLE rmr_handle, + IN const DAT_LMR_TRIPLET *lmr_triplet, + IN DAT_MEM_PRIV_FLAGS mem_priv, + IN DAT_EP_HANDLE ep_handle, + IN DAT_RMR_COOKIE user_cookie, + IN DAT_COMPLETION_FLAGS completion_flags, + OUT DAT_RMR_CONTEXT *rmr_context ) +{ + DAPL_RMR *rmr; + DAPL_EP *ep_ptr; + + if ( DAPL_BAD_HANDLE (rmr_handle, DAPL_MAGIC_RMR) ) + { + return DAT_ERROR (DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_RMR); + } + if ( DAPL_BAD_HANDLE (ep_handle, DAPL_MAGIC_EP) ) + { + return DAT_ERROR (DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP); + } + + rmr = (DAPL_RMR *) rmr_handle; + ep_ptr = (DAPL_EP *) ep_handle; + + /* if the rmr should be bound */ + if (0 != lmr_triplet->segment_length) + { + return dapli_rmr_bind_fuse (rmr, + lmr_triplet, + mem_priv, + ep_ptr, + user_cookie, + completion_flags, + rmr_context); + } + else /* the rmr should be unbound */ + { + return dapli_rmr_bind_unfuse (rmr, + ep_ptr, + user_cookie, + completion_flags); + } +} diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_rmr_create.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_rmr_create.c new file mode 100644 index 00000000..3b47d761 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_rmr_create.c @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_rmr_create.c + * + * PURPOSE: Memory management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 6 + * + * $Id$ + **********************************************************************/ + +#include "dapl_rmr_util.h" +#include "dapl_adapter_util.h" + +/* + * dapl_rmr_create + * + * DAPL Requirements Version xxx, 6.6.4.1 + * + * Create a remote memory region for the specified protection zone + * + * Input: + * pz_handle + * + * Output: + * rmr_handle + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + */ +DAT_RETURN +dapl_rmr_create ( + IN DAT_PZ_HANDLE pz_handle, + OUT DAT_RMR_HANDLE *rmr_handle) +{ + DAPL_PZ *pz; + DAPL_RMR *rmr; + DAT_RETURN dat_status; + + dat_status = DAT_SUCCESS; + + if ( DAPL_BAD_HANDLE (pz_handle, DAPL_MAGIC_PZ) ) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE,DAT_INVALID_HANDLE_PZ); + goto bail; + } + + pz = (DAPL_PZ *) pz_handle; + + rmr = dapl_rmr_alloc (pz); + + if ( rmr == NULL ) + { + dat_status = DAT_ERROR (DAT_INSUFFICIENT_RESOURCES,DAT_RESOURCE_MEMORY); + goto bail; + } + + dat_status = dapls_ib_mw_alloc (rmr); + + if ( dat_status != DAT_SUCCESS ) + { + dapl_rmr_dealloc (rmr); + dat_status = DAT_ERROR (DAT_INSUFFICIENT_RESOURCES,DAT_RESOURCE_MEMORY_REGION); + goto bail; + } + + dapl_os_atomic_inc (&pz->pz_ref_count); + + *rmr_handle = rmr; + + bail: + return dat_status; +} + + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_rmr_free.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_rmr_free.c new file mode 100644 index 00000000..15878bd5 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_rmr_free.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_rmr_free.c + * + * PURPOSE: Memory management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 6 + * + * $Id$ + **********************************************************************/ + +#include "dapl_rmr_util.h" +#include "dapl_adapter_util.h" +#include "dapl_ia_util.h" + +/* + * dapl_rmr_free + * + * DAPL Requirements Version xxx, 6.6.4.2 + * + * Destroy an instance of the Remote Memory Region + * + * Input: + * rmr_handle + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + */ +DAT_RETURN +dapl_rmr_free ( + IN DAT_RMR_HANDLE rmr_handle ) +{ + DAPL_RMR *rmr; + DAT_RETURN dat_status; + + dat_status = DAT_SUCCESS; + + if ( DAPL_BAD_HANDLE (rmr_handle, DAPL_MAGIC_RMR) ) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE,DAT_INVALID_HANDLE_RMR); + goto bail; + } + + rmr = (DAPL_RMR *) rmr_handle; + + /* + * If the user did not perform an unbind op, release + * counts here. + */ + if ( rmr->param.lmr_triplet.virtual_address != 0 ) + { + dapl_os_atomic_dec (&rmr->lmr->lmr_ref_count); + rmr->param.lmr_triplet.virtual_address = 0; + } + + dat_status = dapls_ib_mw_free (rmr); + + if (dat_status != DAT_SUCCESS) + { + goto bail; + } + + dapl_os_atomic_dec (&rmr->pz->pz_ref_count); + + dapl_rmr_dealloc (rmr); + + bail: + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_rmr_query.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_rmr_query.c new file mode 100644 index 00000000..500b7b05 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_rmr_query.c @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_rmr_query.c + * + * PURPOSE: Memory management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 6 + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" + +/* + * dapl_rmr_query + * + * DAPL Requirements Version xxx, 6.6.4.3 + * + * Provide the RMR arguments. + * + * Input: + * rmr_handle + * rmr_args_mask + * + * Output: + * rmr_args + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + * DAT_INVALID_PARAMETER + */ +DAT_RETURN +dapl_rmr_query ( + IN DAT_RMR_HANDLE rmr_handle, + IN DAT_RMR_PARAM_MASK rmr_param_mask, + IN DAT_RMR_PARAM *rmr_param ) +{ + DAPL_RMR *rmr; + DAT_RETURN dat_status; + + dat_status = DAT_SUCCESS; + + if ( DAPL_BAD_HANDLE (rmr_handle, DAPL_MAGIC_RMR) ) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE,DAT_INVALID_HANDLE_RMR); + goto bail; + } + if (NULL == rmr_param) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER,DAT_INVALID_ARG3); + goto bail; + } + + rmr = (DAPL_RMR *) rmr_handle; + + /* If the RMR is unbound, there is no LMR triplet associated with */ + /* this RMR. If the consumer requests this field, return an error. */ + if ( (rmr_param_mask & DAT_RMR_FIELD_LMR_TRIPLET) && (NULL == rmr->lmr) ) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER,DAT_INVALID_ARG2); + goto bail; + } + + dapl_os_memcpy (rmr_param, &rmr->param, sizeof (DAT_RMR_PARAM)); + + bail: + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_rmr_util.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_rmr_util.c new file mode 100644 index 00000000..23fc30fa --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_rmr_util.c @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dapl_rmr_util.c + * + * PURPOSE: Utility defs & routines for the RMR data structure + * + * + **********************************************************************/ + +#include "dapl_rmr_util.h" +#include "dapl_ia_util.h" + +DAPL_RMR * +dapl_rmr_alloc( + IN DAPL_PZ *pz) +{ + DAPL_RMR *rmr; + + /* Allocate LMR */ + rmr = (DAPL_RMR *) dapl_os_alloc(sizeof(DAPL_RMR)); + if (NULL == rmr) + { + return (NULL); + } + + /* zero the structure */ + dapl_os_memzero(rmr, sizeof(DAPL_RMR)); + + /* + * initialize the header + */ + rmr->header.provider = pz->header.provider; + rmr->header.magic = DAPL_MAGIC_RMR; + rmr->header.handle_type = DAT_HANDLE_TYPE_RMR; + rmr->header.owner_ia = pz->header.owner_ia; + rmr->header.user_context.as_64 = 0; + rmr->header.user_context.as_ptr = 0; + dapl_llist_init_entry (&rmr->header.ia_list_entry); + dapl_ia_link_rmr(rmr->header.owner_ia, rmr); + dapl_os_lock_init(&rmr->header.lock); + + /* + * initialize the body + */ + rmr->param.ia_handle = (DAT_IA_HANDLE) pz->header.owner_ia; + rmr->param.pz_handle = (DAT_PZ_HANDLE) pz; + rmr->param.lmr_triplet.lmr_context = 0; + rmr->param.lmr_triplet.pad = 0; + rmr->param.lmr_triplet.virtual_address = 0; + rmr->param.lmr_triplet.segment_length = 0; + + rmr->param.mem_priv = 0; + rmr->pz = pz; + rmr->lmr = NULL; + + return (rmr); +} + + +void +dapl_rmr_dealloc( + IN DAPL_RMR *rmr) +{ + rmr->header.magic = DAPL_MAGIC_INVALID; /* reset magic to prevent reuse */ + + dapl_ia_unlink_rmr(rmr->header.owner_ia, rmr); + dapl_os_lock_destroy(&rmr->header.lock); + + dapl_os_free((void *) rmr, sizeof(DAPL_RMR)); +} diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_rmr_util.h b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_rmr_util.h new file mode 100644 index 00000000..e9cf2eb9 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_rmr_util.h @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dapl_rmr_util.h + * + * PURPOSE: Utility defs & routines for the RMR data structure + * + * $Id$ + * + **********************************************************************/ + +#ifndef _DAPL_RMR_UTIL_H_ +#define _DAPL_RMR_UTIL_H_ + +#include "dapl_mr_util.h" + +/********************************************************************* + * * + * Function Prototypes * + * * + *********************************************************************/ + +extern DAPL_RMR * +dapl_rmr_alloc ( + IN DAPL_PZ *pz); + +extern void +dapl_rmr_dealloc ( + IN DAPL_RMR *rmr); + +STATIC _INLINE_ DAT_BOOLEAN +dapl_rmr_validate_completion_flag ( + IN DAT_COMPLETION_FLAGS mask, + IN DAT_COMPLETION_FLAGS allow, + IN DAT_COMPLETION_FLAGS request); + +STATIC _INLINE_ int32_t +dapl_rmr_convert_privileges ( + IN DAT_MEM_PRIV_FLAGS privileges); + + +/********************************************************************* + * * + * Inline Functions * + * * + *********************************************************************/ + +STATIC _INLINE_ DAT_BOOLEAN +dapl_rmr_validate_completion_flag ( + IN DAT_COMPLETION_FLAGS mask, + IN DAT_COMPLETION_FLAGS allow, + IN DAT_COMPLETION_FLAGS request) +{ + if ( (mask & request ) && ! (mask & allow) ) + { + return DAT_FALSE; + } + else + { + return DAT_TRUE; + } +} + +STATIC _INLINE_ int32_t +dapl_rmr_convert_privileges ( + IN DAT_MEM_PRIV_FLAGS privileges) +{ + int32_t value = 0; + + if (DAT_MEM_PRIV_REMOTE_READ_FLAG & privileges) + { + value |= IB_ACCESS_REMOTE_READ; + } + + if (DAT_MEM_PRIV_REMOTE_WRITE_FLAG & privileges) + { + value |= IB_ACCESS_REMOTE_WRITE; + } + + return value; +} + +#endif /* _DAPL_RMR_UTIL_H_*/ diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_rsp_create.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_rsp_create.c new file mode 100644 index 00000000..2434369c --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_rsp_create.c @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_rsp_create.c + * + * PURPOSE: Connection management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 4 + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_sp_util.h" +#include "dapl_ia_util.h" +#include "dapl_ep_util.h" +#include "dapl_adapter_util.h" + +/* + * dapl_rsp_create + * + * uDAPL: User Direct Access Program Library Version 1.1, 6.4.3.4.1 + * + * Create a Resereved Service Point with the specified Endpoint + * that generates at most one Connection Request that is + * delivered to the specified Event Dispatcher in a notification + * event + * + * Input: + * ia_handle + * conn_qual + * ep_handle + * evd_handle + * + * Output: + * rsp_handle + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + * DAT_INVALID_STATE + * DAT_CONN_QUAL_IN_USE + */ +DAT_RETURN +dapl_rsp_create ( + IN DAT_IA_HANDLE ia_handle, + IN DAT_CONN_QUAL conn_qual, + IN DAT_EP_HANDLE ep_handle, + IN DAT_EVD_HANDLE evd_handle, + OUT DAT_RSP_HANDLE *rsp_handle ) +{ + DAPL_IA *ia_ptr; + DAPL_SP *sp_ptr; + DAPL_EVD *evd_ptr; + DAPL_EP *ep_ptr; + DAT_BOOLEAN sp_found; + DAT_RETURN dat_status; + + dat_status = DAT_SUCCESS; + ia_ptr = (DAPL_IA *)ia_handle; + + dapl_dbg_log (DAPL_DBG_TYPE_CM, + ">>> dapl_rsp_free conn_qual: %x EP: %p\n", + conn_qual, ep_handle); + + if ( DAPL_BAD_HANDLE (ia_ptr, DAPL_MAGIC_IA) ) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE,DAT_INVALID_HANDLE_IA); + goto bail; + } + if ( DAPL_BAD_HANDLE (ep_handle, DAPL_MAGIC_EP) ) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE,DAT_INVALID_HANDLE_EP); + goto bail; + } + if ( DAPL_BAD_HANDLE (evd_handle, DAPL_MAGIC_EVD) ) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE,DAT_INVALID_HANDLE_EVD_CR); + goto bail; + } + + if ( rsp_handle == NULL ) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER,DAT_INVALID_ARG5); + goto bail; + } + + ep_ptr = (DAPL_EP *) ep_handle; + if ( ep_ptr->param.ep_state != DAT_EP_STATE_UNCONNECTED ) + { + dat_status = DAT_ERROR (DAT_INVALID_STATE,dapls_ep_state_subtype (ep_ptr)); + goto bail; + } + + evd_ptr = (DAPL_EVD *)evd_handle; + if ( ! (evd_ptr->evd_flags & DAT_EVD_CR_FLAG) ) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE,DAT_INVALID_HANDLE_EVD_CR); + goto bail; + } + + sp_ptr = dapls_ia_sp_search (ia_ptr, conn_qual, DAT_FALSE); + sp_found = DAT_TRUE; + if (sp_ptr == NULL) + { + sp_found = DAT_FALSE; + + /* Allocate RSP */ + sp_ptr = dapls_sp_alloc ( ia_ptr, DAT_FALSE ); + if ( sp_ptr == NULL ) + { + dat_status = + DAT_ERROR (DAT_INSUFFICIENT_RESOURCES,DAT_RESOURCE_MEMORY); + goto bail; + } + } + + /* + * Fill out the RSP args + */ + sp_ptr->ia_handle = ia_handle; + sp_ptr->conn_qual = conn_qual; + sp_ptr->evd_handle = evd_handle; + sp_ptr->psp_flags = 0; + sp_ptr->ep_handle = ep_handle; + + /* + * Take a reference on the EVD handle + */ + dapl_os_atomic_inc (& ((DAPL_EVD *)evd_handle)->evd_ref_count); + + /* + * Update the EP state indicating the provider now owns it + */ + ep_ptr->param.ep_state = DAT_EP_STATE_RESERVED; + + /* + * Set up a listener for a connection. Connections can arrive + * even before this call returns! + */ + sp_ptr->state = DAPL_SP_STATE_RSP_LISTENING; + sp_ptr->listening = DAT_TRUE; + + if (sp_found == DAT_FALSE) + { + /* Link it onto the IA */ + dapl_ia_link_rsp (ia_ptr, sp_ptr); + + dat_status = dapls_ib_setup_conn_listener ( ia_ptr, + conn_qual, + sp_ptr ); + + if ( dat_status != DAT_SUCCESS ) + { + /* + * Have a problem setting up the connection, something + * wrong! Decrements the EVD refcount & release it. Set + * the state to FREE, so we know the call failed. + */ + dapl_os_atomic_dec (& ((DAPL_EVD *)evd_handle)->evd_ref_count); + sp_ptr->evd_handle = NULL; + sp_ptr->state = DAPL_SP_STATE_FREE; + dapls_ia_unlink_sp (ia_ptr, sp_ptr); + dapls_sp_free_sp (sp_ptr); + + dapl_dbg_log (DAPL_DBG_TYPE_CM, + "--> dapl_rsp_create setup_conn_listener failed: %x\n", + dat_status); + + goto bail; + } + } + + /* + * Return handle to the user + */ + *rsp_handle = (DAT_RSP_HANDLE)sp_ptr; + + bail: + return dat_status; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * c-brace-offset: -4 + * tab-width: 8 + * End: + */ + + diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_rsp_free.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_rsp_free.c new file mode 100644 index 00000000..2c279e90 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_rsp_free.c @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_rsp_free.c + * + * PURPOSE: Connection management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 4 + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_sp_util.h" +#include "dapl_ia_util.h" +#include "dapl_adapter_util.h" + +/* + * dapl_rsp_free + * + * uDAPL: User Direct Access Program Library Version 1.1, 6.4.3.5 + * + * Destroy a specific instance of a Reserved Service Point. + * + * Input: + * rsp_handle + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + */ +DAT_RETURN +dapl_rsp_free ( + IN DAT_RSP_HANDLE rsp_handle ) +{ + DAPL_IA *ia_ptr; + DAPL_SP *sp_ptr; + DAPL_EP *ep_ptr; + DAT_RETURN dat_status; + + dat_status = DAT_SUCCESS; + + sp_ptr = (DAPL_SP *) rsp_handle; + /* + * Verify handle + */ + dapl_dbg_log (DAPL_DBG_TYPE_CM, + ">>> dapl_rsp_free %p\n", + rsp_handle); + if ( DAPL_BAD_HANDLE (sp_ptr, DAPL_MAGIC_RSP ) ) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE,DAT_INVALID_HANDLE_RSP); + goto bail; + } + + /* ia_ptr = (DAPL_IA *)sp_ptr->header.owner_ia; */ + ia_ptr = sp_ptr->header.owner_ia; + + /* + * Remove the connection listener if there are no connections. If + * we defer removing the sp it becomes something of a zombie + * container until disconnection, after which it will be cleaned up. + */ + dapl_os_lock (&sp_ptr->header.lock); + + /* + * Make sure we don't leave a dangling EP. If the state is still + * RESERVED then the RSP still owns it. + */ + ep_ptr = (DAPL_EP *)sp_ptr->ep_handle; + if ( ep_ptr != NULL && ep_ptr->param.ep_state == DAT_EP_STATE_RESERVED ) + { + ep_ptr->param.ep_state = DAT_EP_STATE_UNCONNECTED; + } + sp_ptr->ep_handle = NULL; + + /* Release reference on EVD. If an error was encountered in a previous + * free the evd_handle will be NULL + */ + if (sp_ptr->evd_handle) + { + dapl_os_atomic_dec (& ((DAPL_EVD *)sp_ptr->evd_handle)->evd_ref_count); + sp_ptr->evd_handle = NULL; + } + + /* + * Release the base resource if there are no outstanding connections; + * else the last disconnect on this RSP will free it up. The RSP + * is used to contain CR records for each connection, which + * contain information necessary to disconnect. + * sp_ptr->listening will be DAT_TRUE if there has never been a + * connection event, and DAT_FALSE if a connection attempt resulted + * in a reject. + */ + if ( sp_ptr->cr_list_count == 0 ) + { + /* This RSP has never been used. Clean it up */ + sp_ptr->listening = DAT_FALSE; + sp_ptr->state = DAPL_SP_STATE_FREE; + dapl_os_unlock (&sp_ptr->header.lock); + + dat_status = dapls_ib_remove_conn_listener ( ia_ptr, + sp_ptr ); + if (dat_status != DAT_SUCCESS) + { + sp_ptr->state = DAPL_SP_STATE_RSP_LISTENING; + goto bail; + } + dapls_ia_unlink_sp ( ia_ptr, sp_ptr ); + dapls_sp_free_sp ( sp_ptr ); + } + else + { + /* The RSP is now in the pending state, where it will sit until + * the connection terminates or the app uses the same + * ServiceID again, which will reactivate it. + */ + sp_ptr->state = DAPL_SP_STATE_RSP_PENDING; + dapl_os_unlock (&sp_ptr->header.lock); + } + + bail: + return dat_status; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * c-brace-offset: -4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_rsp_query.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_rsp_query.c new file mode 100644 index 00000000..dc811de7 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_rsp_query.c @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_rsp_query.c + * + * PURPOSE: Connection management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 4 + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" + +/* + * dapl_rsp_query + * + * uDAPL: User Direct Access Program Library Version 1.1, 6.4.1.6 + * + * Provide arguments of the reserved service points + * + * Input: + * rsp_handle + * rsp_args_mask + * + * Output: + * rsp_args + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + */ +DAT_RETURN +dapl_rsp_query ( + IN DAT_RSP_HANDLE rsp_handle, + IN DAT_RSP_PARAM_MASK rsp_mask, + OUT DAT_RSP_PARAM *rsp_param ) +{ + DAPL_SP *sp_ptr; + DAT_RETURN dat_status; + UNREFERENCED_PARAMETER(rsp_mask); + + dat_status = DAT_SUCCESS; + + if ( DAPL_BAD_HANDLE (rsp_handle, DAPL_MAGIC_RSP) ) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE,DAT_INVALID_HANDLE_RSP); + goto bail; + } + + if (NULL == rsp_param) + { + dat_status = DAT_ERROR (DAT_INVALID_PARAMETER,DAT_INVALID_ARG3); + goto bail; + } + + sp_ptr = (DAPL_SP *) rsp_handle; + + /* + * Fill in the RSP params + */ + rsp_param->ia_handle = sp_ptr->ia_handle; + rsp_param->conn_qual = sp_ptr->conn_qual; + rsp_param->evd_handle = sp_ptr->evd_handle; + rsp_param->ep_handle = sp_ptr->ep_handle; + + bail: + return dat_status; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * c-brace-offset: -4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_set_consumer_context.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_set_consumer_context.c new file mode 100644 index 00000000..7f0914ef --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_set_consumer_context.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_set_consumer_context.c + * + * PURPOSE: Interface Adapter management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 2 + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" + +/* + * dapl_set_consumer_context + * + * DAPL Requirements Version xxx, 6.2.2.1 + * + * Set a consumer context in the provided dat_handle + * + * Input: + * dat_handle + * context + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + */ +DAT_RETURN +dapl_set_consumer_context ( + IN DAT_HANDLE dat_handle, + IN DAT_CONTEXT context ) +{ + DAT_RETURN dat_status; + DAPL_HEADER *header; + + dat_status = DAT_SUCCESS; + + header = (DAPL_HEADER *)dat_handle; + if ( ((header) == NULL) || + (((DAT_UVERYLONG)header) & 3) || + (header->magic != DAPL_MAGIC_IA && + header->magic != DAPL_MAGIC_EVD && + header->magic != DAPL_MAGIC_EP && + header->magic != DAPL_MAGIC_LMR && + header->magic != DAPL_MAGIC_RMR && + header->magic != DAPL_MAGIC_PZ && + header->magic != DAPL_MAGIC_PSP && + header->magic != DAPL_MAGIC_RSP && + header->magic != DAPL_MAGIC_CR)) + { + dat_status = DAT_ERROR (DAT_INVALID_HANDLE,0); + goto bail; + } + header->user_context = context; + +bail: + return dat_status; +} + diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_sp_util.c b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_sp_util.c new file mode 100644 index 00000000..a5554bf4 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_sp_util.c @@ -0,0 +1,316 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_sp_util.c + * + * PURPOSE: Manage PSP Info structure + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_ep_util.h" +#include "dapl_sp_util.h" +#include "dapl_cr_util.h" + +/* + * Local definitions + */ + + +/* + * dapl_sp_alloc + * + * alloc and initialize a PSP INFO struct + * + * Input: + * IA INFO struct ptr + * + * Output: + * sp_ptr + * + * Returns: + * NULL + * pointer to sp info struct + * + */ +DAPL_SP * +dapls_sp_alloc ( + IN DAPL_IA *ia_ptr, + IN DAT_BOOLEAN is_psp ) +{ + DAPL_SP *sp_ptr; + + /* Allocate EP */ + sp_ptr = (DAPL_SP *)dapl_os_alloc (sizeof (DAPL_SP)); + if ( sp_ptr == NULL ) + { + return (NULL); + } + + /* zero the structure */ + dapl_os_memzero (sp_ptr, sizeof (DAPL_SP)); + + /* + * initialize the header + */ + sp_ptr->header.provider = ia_ptr->header.provider; + if ( is_psp ) + { + sp_ptr->header.magic = DAPL_MAGIC_PSP; + sp_ptr->header.handle_type = DAT_HANDLE_TYPE_PSP; + } + else + { + sp_ptr->header.magic = DAPL_MAGIC_RSP; + sp_ptr->header.handle_type = DAT_HANDLE_TYPE_RSP; + } + sp_ptr->header.owner_ia = ia_ptr; + sp_ptr->header.user_context.as_64 = 0; + sp_ptr->header.user_context.as_ptr = NULL; + dapl_llist_init_entry (&sp_ptr->header.ia_list_entry); + dapl_os_lock_init (&sp_ptr->header.lock); + dapl_os_wait_object_init( &sp_ptr->wait_object ); + + /* + * Initialize the Body (set to NULL above) + */ + dapl_llist_init_head (&sp_ptr->cr_list_head); + + return ( sp_ptr ); +} + + +/* + * dapl_sp_free + * + * Free the passed in PSP structure. + * + * Input: + * entry point pointer + * + * Output: + * none + * + * Returns: + * none + * + */ +void +dapls_sp_free_sp ( + IN DAPL_SP *sp_ptr ) +{ + dapl_os_assert (sp_ptr->header.magic == DAPL_MAGIC_PSP || + sp_ptr->header.magic == DAPL_MAGIC_RSP); + dapl_os_assert (dapl_llist_is_empty(&sp_ptr->cr_list_head)); + + dapl_os_lock (&sp_ptr->header.lock); + sp_ptr->header.magic = DAPL_MAGIC_INVALID; /* reset magic to prevent reuse */ + dapl_os_unlock (&sp_ptr->header.lock); + dapl_os_wait_object_destroy (&sp_ptr->wait_object); + dapl_os_free (sp_ptr, sizeof (DAPL_SP)); +} + + +/* + * dapl_cr_link_cr + * + * Add a cr to a PSP structure + * + * Input: + * sp_ptr + * cr_ptr + * + * Output: + * none + * + * Returns: + * none + * + */ +void +dapl_sp_link_cr ( + IN DAPL_SP *sp_ptr, + IN DAPL_CR *cr_ptr ) +{ + dapl_os_lock (&sp_ptr->header.lock); + dapl_llist_add_tail (&sp_ptr->cr_list_head, + &cr_ptr->header.ia_list_entry, + cr_ptr); + sp_ptr->cr_list_count++; + dapl_os_unlock (&sp_ptr->header.lock); +} + + +/* + * dapl_sp_search_cr + * + * Search for a CR on the PSP cr_list with a matching cm_handle. When + * found, remove it from the list and update fields. + * + * Must be called with the sp_ptr lock taken. + * + * Input: + * sp_ptr + * ib_cm_handle + * + * Output: + * none + * + * Returns: + * cr_ptr_fnd Pointer to matching DAPL_CR + * + */ +DAPL_CR * +dapl_sp_search_cr ( + IN DAPL_SP *sp_ptr, + IN ib_cm_handle_t ib_cm_handle ) +{ + DAPL_CR *cr_ptr; + DAPL_CR *cr_ptr_fnd; + + dapl_os_lock (&sp_ptr->header.lock); + if ( dapl_llist_is_empty (&sp_ptr->cr_list_head) ) + { + dapl_os_unlock (&sp_ptr->header.lock); + return NULL; + } + cr_ptr_fnd = NULL; + cr_ptr = (DAPL_CR *) dapl_llist_peek_head (&sp_ptr->cr_list_head); + + do + { + if ( cr_ptr->ib_cm_handle.cid == ib_cm_handle.cid ) + { + cr_ptr_fnd = cr_ptr; + + break; + } + cr_ptr = cr_ptr->header.ia_list_entry.flink->data; + } while ((void *)cr_ptr != (void *)sp_ptr->cr_list_head->data); + + dapl_os_unlock (&sp_ptr->header.lock); + + return cr_ptr_fnd; +} + + + +/* + * dapl_sp_remove_cr + * + * Remove the CR from the PSP. Done prior to freeing the CR resource. + * + * Must be called with the sp_ptr lock taken. + * + * Input: + * sp_ptr + * cr_ptr + * + * Output: + * none + * + * Returns: + * void + * + */ +void +dapl_sp_remove_cr ( + IN DAPL_SP *sp_ptr, + IN DAPL_CR *cr_ptr ) +{ + dapl_os_lock (&sp_ptr->header.lock); + + if ( dapl_llist_is_empty(&sp_ptr->cr_list_head) ) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "***dapl_sp_remove_cr: removing from empty queue! sp %p\n", + sp_ptr ); + dapl_os_unlock (&sp_ptr->header.lock); + return; + } + + dapl_llist_remove_entry (&sp_ptr->cr_list_head, + &cr_ptr->header.ia_list_entry); + sp_ptr->cr_list_count--; + + dapl_os_unlock (&sp_ptr->header.lock); +} + + + +/* + * dapl_sp_remove_ep + * + * Remove a CR from a PSP, given an EP. + * + * + * Input: + * ep_ptr + * + * Output: + * none + * + * Returns: + * void + * + */ +void +dapl_sp_remove_ep ( + IN DAPL_EP *ep_ptr ) +{ + DAPL_SP *sp_ptr; + DAPL_CR *cr_ptr; + + cr_ptr = ep_ptr->cr_ptr; + + if (cr_ptr != NULL) + { + sp_ptr = cr_ptr->sp_ptr; + + dapl_os_lock (&sp_ptr->header.lock); + + /* Remove the CR from the queue */ + dapl_sp_remove_cr (sp_ptr, cr_ptr); + + dapl_os_unlock (&sp_ptr->header.lock); + + /* free memory outside of the lock */ + dapls_cr_free (cr_ptr); + + return; + } +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl/dapl/common/dapl_sp_util.h b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_sp_util.h new file mode 100644 index 00000000..1442ace0 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/common/dapl_sp_util.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dapl_sp_util.h + * + * PURPOSE: Utility defs & routines for the PSP & RSP data structure + * + * $Id$ + * + **********************************************************************/ + +#ifndef _DAPL_PSP_UTIL_H_ +#define _DAPL_PSP_UTIL_H_ + +DAPL_SP *dapls_sp_alloc ( + IN DAPL_IA *ia_ptr, + IN DAT_BOOLEAN is_psp ); + +void dapls_sp_free_sp ( + IN DAPL_SP *sp_ptr ); + +void dapl_sp_link_cr ( + IN DAPL_SP *sp_ptr, + IN DAPL_CR *cr_ptr ); + +DAPL_CR *dapl_sp_search_cr ( + IN DAPL_SP *sp_ptr, + IN ib_cm_handle_t ib_cm_handle ); + +void dapl_sp_remove_cr ( + IN DAPL_SP *sp_ptr, + IN DAPL_CR *cr_ptr ); + +void dapl_sp_remove_ep ( + IN DAPL_EP *ep_ptr ); + +#endif /* _DAPL_PSP_UTIL_H_ */ diff --git a/branches/WOF2-3/ulp/dapl/dapl/dirs b/branches/WOF2-3/ulp/dapl/dapl/dirs new file mode 100644 index 00000000..2d7badc4 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/dirs @@ -0,0 +1 @@ +DIRS=udapl diff --git a/branches/WOF2-3/ulp/dapl/dapl/ibal/dapl_ibal_cm.c b/branches/WOF2-3/ulp/dapl/dapl/ibal/dapl_ibal_cm.c new file mode 100644 index 00000000..cbc90475 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/ibal/dapl_ibal_cm.c @@ -0,0 +1,2004 @@ + +/* + * Copyright (c) 2002, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ibal_cm.c + * + * PURPOSE: IB Connection routines for access to IBAL APIs + * + * $Id$ + * + **********************************************************************/ + +#include "dapl.h" +#include "dapl_adapter_util.h" +#include "dapl_evd_util.h" +#include "dapl_cr_util.h" +#include "dapl_sp_util.h" +#include "dapl_ia_util.h" +#include "dapl_ibal_util.h" +#include "dapl_name_service.h" + +#define IB_INFINITE_SERVICE_LEASE 0xFFFFFFFF +#define DAPL_ATS_SERVICE_ID ATS_SERVICE_ID //0x10000CE100415453 +#define DAPL_ATS_NAME ATS_NAME +#define HCA_IPV6_ADDRESS_LENGTH 16 + +int g_dapl_loopback_connection = 0; +extern dapl_ibal_root_t dapl_ibal_root; + +/* + * Prototypes + */ +static void AL_API +dapli_ib_sa_query_cb ( + IN ib_query_rec_t *p_query_rec ); + + + +#ifndef NO_NAME_SERVICE + +static void +dapli_ib_reg_svc_cb ( + IN ib_reg_svc_rec_t *p_reg_svc_rec ) +{ + DAPL_HCA *hca_ptr; + + hca_ptr = (DAPL_HCA *) p_reg_svc_rec->svc_context; + + dapl_os_assert (hca_ptr); + + if (IB_SUCCESS == p_reg_svc_rec->req_status) + { + hca_ptr->name_service_handle = (void *) p_reg_svc_rec->h_reg_svc; + + dapl_dbg_log ( DAPL_DBG_TYPE_CM | DAPL_DBG_TYPE_CALLBACK, + "--> DiRScb: register to SA successfully for port %d\n", + hca_ptr->port_num); + + dapl_dbg_log ( DAPL_DBG_TYPE_CM | DAPL_DBG_TYPE_CALLBACK, + "--> DiRScb: reg_service_handle %p\n", + hca_ptr->name_service_handle); + + } + else + { + hca_ptr->name_service_handle = IB_INVALID_HANDLE; + dapl_dbg_log ( DAPL_DBG_TYPE_ERR,"--> DiRScb: Register service to SA failed = %s\n", + ib_get_err_str(p_reg_svc_rec->req_status)); + } + +} + + + +DAT_RETURN +dapls_ib_ns_map_gid ( + IN DAPL_HCA *hca_ptr, + IN DAT_IA_ADDRESS_PTR p_ia_address, + OUT GID *p_gid) +{ + ib_user_query_t user_query; + dapl_ibal_ca_t *p_ca; + dapl_ibal_port_t *p_active_port; + ib_service_record_t service_rec; + ib_api_status_t ib_status; + ib_query_req_t query_req; + DAT_SOCK_ADDR6 ipv6_addr; + + p_ca = (dapl_ibal_ca_t *) hca_ptr->ib_hca_handle; + + if (NULL == p_ca) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR,"--> DsNMG: There is no HCA = %d\n", __LINE__); + return (DAT_INVALID_HANDLE); + } + + /* + * We are using the first active port in the list for + * communication. We have to get back here when we decide to support + * fail-over and high-availability. + */ + p_active_port = dapli_ibal_get_port ( p_ca, (uint8_t)hca_ptr->port_num ); + + if (NULL == p_active_port) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR,"--> DsNMG: Port %d is not available = %d\n", + hca_ptr->port_num, __LINE__); + return (DAT_INVALID_STATE); + } + + if (p_active_port->p_attr->lid == 0) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR,"--> DsNMG: Port %d has no LID assigned; can not operate\n", + p_active_port->p_attr->port_num); + return (DAT_INVALID_STATE); + } + else + { + if (!dapl_os_memcmp (p_ia_address, + &hca_ptr->hca_address, + HCA_IPV6_ADDRESS_LENGTH)) + { + /* + * We are operating in the LOOPBACK mode + */ + p_gid->guid = + p_active_port->p_attr->p_gid_table[0].unicast.interface_id; + p_gid->gid_prefix = + p_active_port->p_attr->p_gid_table[0].unicast.prefix; + return DAT_SUCCESS; + } + else if (p_active_port->p_attr->link_state != IB_LINK_ACTIVE) + { + /* + * Port is DOWN; can not send or recv messages + */ + dapl_dbg_log ( DAPL_DBG_TYPE_ERR,"--> DsNMG: Port %d is DOWN; can not send to fabric\n", + p_active_port->p_attr->port_num); + return (DAT_INVALID_STATE); + } + } + + dapl_os_memzero (&user_query, sizeof (ib_user_query_t)); + dapl_os_memzero (&service_rec, sizeof (ib_service_record_t)); + dapl_os_memzero (&query_req, sizeof (ib_query_req_t)); + dapl_os_memzero (&ipv6_addr, sizeof (DAT_SOCK_ADDR6)); + + if (p_ia_address->sa_family == AF_INET) + { + dapl_os_memcpy (&ipv6_addr.sin6_addr.s6_addr[12], + &((struct sockaddr_in *)p_ia_address)->sin_addr.s_addr, + 4); +#ifdef DAPL_DBG + { + int rval; + + rval = ((struct sockaddr_in *) p_ia_address)->sin_addr.s_addr; + + dapl_dbg_log (DAPL_DBG_TYPE_CM, + "--> DsNMG: Remote ia_address = %d.%d.%d.%d \n", + (rval >> 0) & 0xff, + (rval >> 8) & 0xff, + (rval >> 16) & 0xff, + (rval >> 24) & 0xff); + } +#endif + + } + else + { + /* + * Assume IPv6 address + */ + dapl_os_assert (p_ia_address->sa_family == AF_INET6); + dapl_os_memcpy (ipv6_addr.sin6_addr.s6_addr, + ((DAT_SOCK_ADDR6 *)p_ia_address)->sin6_addr.s6_addr, + HCA_IPV6_ADDRESS_LENGTH); +#ifdef DAPL_DBG + { + int i; + uint8_t *tmp = ipv6_addr.sin6_addr.s6_addr; + + dapl_dbg_log ( DAPL_DBG_TYPE_CM, + "--> DsNMG: Remote ia_address - "); + + for ( i = 1; i < HCA_IPV6_ADDRESS_LENGTH; i++) + { + dapl_dbg_log ( DAPL_DBG_TYPE_CM, "%x:", + tmp[i-1] ); + } + dapl_dbg_log ( DAPL_DBG_TYPE_CM, "%x\n", + tmp[i-1] ); + } +#endif + + } + + /* + * query SA for GID + */ + //service_rec.service_id = CL_HTON64 (DAPL_ATS_SERVICE_ID); + dapl_os_memcpy ( service_rec.service_name, ATS_NAME, __min(sizeof(ATS_NAME),sizeof(ib_svc_name_t))); + dapl_os_memcpy (&service_rec.service_data8[0], + ipv6_addr.sin6_addr.s6_addr, + HCA_IPV6_ADDRESS_LENGTH); + service_rec.service_lease = IB_INFINITE_SERVICE_LEASE; + service_rec.service_pkey = IB_DEFAULT_PKEY; + + user_query.method = IB_MAD_METHOD_GETTABLE; + user_query.attr_id = IB_MAD_ATTR_SERVICE_RECORD; + user_query.comp_mask = IB_SR_COMPMASK_SPKEY | + IB_SR_COMPMASK_SLEASE | + IB_SR_COMPMASK_SNAME | + IB_SR_COMPMASK_SDATA8_0 | + IB_SR_COMPMASK_SDATA8_1 | + IB_SR_COMPMASK_SDATA8_2 | + IB_SR_COMPMASK_SDATA8_3 | + IB_SR_COMPMASK_SDATA8_4 | + IB_SR_COMPMASK_SDATA8_5 | + IB_SR_COMPMASK_SDATA8_6 | + IB_SR_COMPMASK_SDATA8_7 | + IB_SR_COMPMASK_SDATA8_8 | + IB_SR_COMPMASK_SDATA8_9 | + IB_SR_COMPMASK_SDATA8_10 | + IB_SR_COMPMASK_SDATA8_11 | + IB_SR_COMPMASK_SDATA8_12 | + IB_SR_COMPMASK_SDATA8_13 | + IB_SR_COMPMASK_SDATA8_14 | + IB_SR_COMPMASK_SDATA8_15; + + user_query.attr_size = sizeof (ib_service_record_t); + user_query.p_attr = (void *)&service_rec; + + query_req.query_type = IB_QUERY_USER_DEFINED; + query_req.p_query_input = (void *)&user_query; + query_req.flags = IB_FLAGS_SYNC; /* this is a blocking call */ + query_req.timeout_ms = 1 * 1000; /* 1 second */ + query_req.retry_cnt = 5; + /* query SA using this port */ + query_req.port_guid = p_active_port->p_attr->port_guid; + query_req.query_context = (void *) &user_query; + query_req.pfn_query_cb = dapli_ib_sa_query_cb; + + ib_status = ib_query (dapl_ibal_root.h_al, &query_req, NULL); + + if (ib_status != IB_SUCCESS) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR,"ns_map_gid: status %s @line = %d\n", + ib_get_err_str(ib_status), __LINE__); + return (dapl_ib_status_convert (ib_status)); + } + else if (service_rec.service_gid.unicast.interface_id == 0) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR,"--> %s: query SA found no record\n","DsNMG"); + return DAT_INVALID_PARAMETER; + } + + /* + * return the GID + */ + p_gid->guid = service_rec.service_gid.unicast.interface_id; + p_gid->gid_prefix = service_rec.service_gid.unicast.prefix; + + return DAT_SUCCESS; +} + + + +DAT_RETURN +dapls_ib_ns_map_ipaddr ( + IN DAPL_HCA *hca_ptr, + IN GID gid, + OUT DAT_IA_ADDRESS_PTR p_ia_address) +{ + ib_user_query_t user_query; + dapl_ibal_ca_t *p_ca; + dapl_ibal_port_t *p_active_port; + ib_service_record_t service_rec; + ib_api_status_t ib_status; + ib_query_req_t query_req; + + p_ca = (dapl_ibal_ca_t *) hca_ptr->ib_hca_handle; + + if (NULL == p_ca) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "--> DsNMI: NULL HCA @ line# %d?\n", __LINE__ ); + return (DAT_INVALID_HANDLE); + } + + /* + * We are using the first active port in the list for + * communication. We have to get back here when we decide to support + * fail-over and high-availability. + */ + p_active_port = dapli_ibal_get_port ( p_ca, (uint8_t)hca_ptr->port_num ); + + if (NULL == p_active_port) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "--> DsNMI: Port %d !available @ line# %d\n", + hca_ptr->port_num, __LINE__); + return (DAT_INVALID_STATE); + } + + if (p_active_port->p_attr->lid == 0) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR,"--> DsNMI: Port %d has no LID " + "assigned; can not operate\n", + p_active_port->p_attr->port_num ); + return (DAT_INVALID_STATE); + } + /*else + { + // + // We are operating in the LOOPBACK mode + // + if ((gid.gid_prefix == + p_active_port->p_attr->p_gid_table[0].unicast.prefix) && + (gid.guid == + p_active_port->p_attr->p_gid_table[0].unicast.interface_id)) + { + dapl_os_memcpy (((DAT_SOCK_ADDR6 *)p_ia_address)->sin6_addr.s6_addr, + hca_ptr->hca_address.sin6_addr.s6_addr, + HCA_IPV6_ADDRESS_LENGTH); + return DAT_SUCCESS; + } + + }*/ + if (p_active_port->p_attr->link_state != IB_LINK_ACTIVE) + { + /* + * Port is DOWN; can not send or recv messages + */ + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, "--> DsNMI: Port %d is DOWN; " + "can not send/recv to/from fabric\n", + p_active_port->p_attr->port_num ); + return (DAT_INVALID_STATE); + } + + dapl_os_memzero (&user_query, sizeof (ib_user_query_t)); + dapl_os_memzero (&service_rec, sizeof (ib_service_record_t)); + dapl_os_memzero (&query_req, sizeof (ib_query_req_t)); + + /* + * query SA for IPAddress + */ + //service_rec.service_id = CL_HTON64 (DAPL_ATS_SERVICE_ID); + dapl_os_memcpy ( service_rec.service_name, + ATS_NAME, + __min (sizeof(ATS_NAME), sizeof(ib_svc_name_t)) ); + service_rec.service_gid.unicast.interface_id = gid.guid; + service_rec.service_gid.unicast.prefix = gid.gid_prefix; + service_rec.service_pkey = IB_DEFAULT_PKEY; + service_rec.service_lease = IB_INFINITE_SERVICE_LEASE; + + user_query.method = IB_MAD_METHOD_GETTABLE; + user_query.attr_id = IB_MAD_ATTR_SERVICE_RECORD; + + user_query.comp_mask = IB_SR_COMPMASK_SGID | + IB_SR_COMPMASK_SPKEY | + IB_SR_COMPMASK_SLEASE | + IB_SR_COMPMASK_SNAME; + + user_query.attr_size = sizeof (ib_service_record_t); + user_query.p_attr = (void *)&service_rec; + + query_req.query_type = IB_QUERY_USER_DEFINED; + query_req.p_query_input = (void *)&user_query; + query_req.flags = IB_FLAGS_SYNC; /* this is a blocking call */ + query_req.timeout_ms = 1 * 1000; /* 1 second */ + query_req.retry_cnt = 5; + + /* query SA using this port */ + query_req.port_guid = p_active_port->p_attr->port_guid; + query_req.query_context = (void *) &user_query; + query_req.pfn_query_cb = dapli_ib_sa_query_cb; + + ib_status = ib_query (dapl_ibal_root.h_al, &query_req, NULL); + + if (ib_status != IB_SUCCESS) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "ns_map_ipaddr: exits status %s @line %d\n", + ib_get_err_str(ib_status), __LINE__); + return (dapl_ib_status_convert (ib_status)); + } + + /* *********************** + * return the IP_address + *************************/ + dapl_os_memcpy ( + (void *)&((struct sockaddr_in *)p_ia_address)->sin_addr.s_net, + (const void *)&service_rec.service_data8[ATS_IPV4_OFFSET], + 4 ); //HCA_IPV6_ADDRESS_LENGTH); + ((DAT_SOCK_ADDR6 *)p_ia_address)->sin6_family = AF_INET; + + return (DAT_SUCCESS); +} + + +/* + * dapls_ib_ns_create_gid_map() + * + * Register a ServiceRecord containing uDAPL_svc_id, IP address and GID to SA + * Other nodes can look it up by quering the SA + * + * Input: + * hca_ptr HCA device pointer + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + */ +DAT_RETURN +dapls_ib_ns_create_gid_map ( + IN DAPL_HCA *hca_ptr) +{ + UNUSED_PARAM( hca_ptr ); + return (DAT_SUCCESS); +} + + +DAT_RETURN +dapls_ib_ns_remove_gid_map ( + IN DAPL_HCA *hca_ptr) +{ + UNUSED_PARAM( hca_ptr ); + return (DAT_SUCCESS); +} + +#endif /* NO_NAME_SERVICE */ + + +static void AL_API +dapli_ib_sa_query_cb ( + IN ib_query_rec_t *p_query_rec ) +{ + ib_api_status_t ib_status; + + if (IB_SUCCESS != p_query_rec->status) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "sa_query_cb: SA query callback failed status %s\n", + ib_get_err_str(p_query_rec->status) ); + return; + } + + if (!p_query_rec->p_result_mad) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "sa_query_cb: SA query callback [no mad] @line %d\n", + __LINE__ ); + return; + } + + switch (p_query_rec->query_type) + { + case IB_QUERY_PATH_REC_BY_GIDS: + { + ib_path_rec_t *p_path_rec; + + p_path_rec = ib_get_query_path_rec (p_query_rec->p_result_mad, 0); + if (p_path_rec) + { + dapl_os_memcpy ((void *) p_query_rec->query_context, + (void *) p_path_rec, + sizeof (ib_path_rec_t)); + dapl_dbg_log ( DAPL_DBG_TYPE_CM | DAPL_DBG_TYPE_CALLBACK, + "sa_query_cb: path {slid: 0x%x, dlid: 0x%x}\n", + p_path_rec->slid, p_path_rec->dlid ); + } + else + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "sa_query_cb: NULL path_rec? @line %d\n", + __LINE__ ); + return; + } + break; + } + + case IB_QUERY_SVC_REC_BY_ID: + { + ib_service_record_t *p_svc_rec; + + p_svc_rec = ib_get_query_svc_rec (p_query_rec->p_result_mad, 0); + if (p_svc_rec) + { + dapl_os_memcpy ((void *) p_query_rec->query_context, + (void *) p_svc_rec, + sizeof (ib_service_record_t)); + dapl_dbg_log ( + DAPL_DBG_TYPE_CM | DAPL_DBG_TYPE_CALLBACK, + "sa_query_cb: SER{0x%I64x, 0x%I64x}\n", + cl_hton64 (p_svc_rec->service_gid.unicast.prefix), + cl_hton64 (p_svc_rec->service_gid.unicast.interface_id)); + } + else + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "sa_query_cb: return NULL? @line %d\n",__LINE__); + return; + } + break; + + } + + case IB_QUERY_USER_DEFINED: + { + ib_user_query_t *p_user_query; + + p_user_query =(ib_user_query_t *)p_query_rec->query_context; + if (p_user_query) + { + switch (p_user_query->attr_id) + { + case IB_MAD_ATTR_SERVICE_RECORD: + { + ib_service_record_t *p_svc_rec; + + p_svc_rec = ib_get_query_svc_rec (p_query_rec->p_result_mad, 0); + if (p_svc_rec) + { + dapl_os_memcpy ((void *) p_user_query->p_attr, + (void *) p_svc_rec, + sizeof (ib_service_record_t)); + dapl_dbg_log ( + DAPL_DBG_TYPE_CM | DAPL_DBG_TYPE_CALLBACK, + "sa_query_cb: GID{0x" F64x ", 0x" F64x "} record count %d\n", + cl_hton64(p_svc_rec->service_gid.unicast.prefix), + cl_hton64(p_svc_rec->service_gid.unicast.interface_id ), + p_query_rec->result_cnt); + } + else + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "sa_query_cb: NULL svc_rec? @line %d\n", + __LINE__); + return; + } + break; + + } + default: + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "sa_query_cb: USER_DEFINED %d\n", + p_user_query->attr_id ); + break; + } + } + } + else + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "sa_query_cb: NULL user_query? @line %d\n", + __LINE__ ); + return; + } + break; + } + + default: + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "sa_query_cb: unsupported TYPE %d?\n", + p_query_rec->query_type ); + break; + } + + } + + if ((ib_status = ib_put_mad (p_query_rec->p_result_mad)) != IB_SUCCESS) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, "sa_query_cb: can not free MAD %s\n", + ib_get_err_str(ib_status) ); + } +} + +static void +dapli_ib_cm_apr_cb ( + IN ib_cm_apr_rec_t *p_cm_apr_rec ) +{ + UNUSED_PARAM( p_cm_apr_rec ); + dapl_dbg_log (DAPL_DBG_TYPE_CM, + "--> DiCAcb: CM callback APR (Alternate Path Request)\n"); +} + +static void +dapli_ib_cm_lap_cb ( + IN ib_cm_lap_rec_t *p_cm_lap_rec ) +{ + UNUSED_PARAM( p_cm_lap_rec ); + dapl_dbg_log (DAPL_DBG_TYPE_CM, + "--> DiCLcb: CM callback LAP (Load Alternate Path)\n"); +} + +static void +dapli_ib_cm_dreq_cb ( + IN ib_cm_dreq_rec_t *p_cm_dreq_rec ) +{ + ib_cm_drep_t cm_drep; + DAPL_SP *sp_ptr; + DAPL_EP *ep_ptr; + + dapl_os_assert (p_cm_dreq_rec); + + ep_ptr = (DAPL_EP *) p_cm_dreq_rec->qp_context; + + if ( ep_ptr == NULL || + ep_ptr->header.magic == DAPL_MAGIC_INVALID ) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "--> DiCDcb: EP = %p invalid or FREED\n", ep_ptr); + return; + } + + dapl_os_lock (&ep_ptr->header.lock); + dapl_dbg_log (DAPL_DBG_TYPE_CM, + "--> DiCDcb: EP = %p QP = %p in state = %d\n", + ep_ptr, ep_ptr->qp_handle, ep_ptr->param.ep_state); + + if (ep_ptr->param.ep_state == DAT_EP_STATE_DISCONNECTED) + { + dapl_os_unlock (&ep_ptr->header.lock); + return; + } + + ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECT_PENDING; + ep_ptr->recv_discreq = DAT_TRUE; + dapl_os_unlock (&ep_ptr->header.lock); + + dapl_os_memzero (&cm_drep, sizeof ( ib_cm_drep_t)); + + /* Could fail if we received reply from other side, no need to retry */ + /* Wait for any transaction in process holding reference */ + while ( ep_ptr->req_count ) + { + dapl_dbg_log (DAPL_DBG_TYPE_CM, + "--> DiCDcb: WAIT for EP=%p req_count(%d) == 0 \n", + ep_ptr, ep_ptr->req_count); + dapl_os_sleep_usec (1000); /* 1 ms */ + } + + ib_cm_drep (p_cm_dreq_rec->h_cm_dreq, &cm_drep); + + /* CM puts QP in reset state */ + ep_ptr->qp_state = IB_QPS_RESET; + + if (ep_ptr->cr_ptr) + { + sp_ptr = ((DAPL_CR *) ep_ptr->cr_ptr)->sp_ptr; + + dapls_cr_callback ( p_cm_dreq_rec->h_cm_dreq, + IB_CME_DISCONNECTED, + (void *) p_cm_dreq_rec->p_dreq_pdata, + (void *) sp_ptr, + NULL); + } + else + { + sp_ptr = NULL; + + dapl_evd_connection_callback ( p_cm_dreq_rec->h_cm_dreq, + IB_CME_DISCONNECTED, + (void *) p_cm_dreq_rec->p_dreq_pdata, + p_cm_dreq_rec->qp_context); + } +} + +static void +dapli_ib_cm_drep_cb ( + IN ib_cm_drep_rec_t *p_cm_drep_rec ) +{ + DAPL_SP *sp_ptr; + DAPL_EP *ep_ptr; + + dapl_os_assert (p_cm_drep_rec != NULL); + + ep_ptr = (DAPL_EP *) p_cm_drep_rec->qp_context; + + if (ep_ptr) + { + + dapl_dbg_log (DAPL_DBG_TYPE_CM, + "--> DiCDpcb: EP = %p QP = %p in state = %d\n", + ep_ptr, ep_ptr->qp_handle, ep_ptr->param.ep_state); + + if ( ep_ptr->param.ep_state == DAT_EP_STATE_DISCONNECTED ) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "--> DiCDpcb: EP = %p QP = %p already disconnected\n", + ep_ptr, ep_ptr->qp_handle); + return; + } + + if (ep_ptr->cr_ptr) + { + sp_ptr = ((DAPL_CR *) ep_ptr->cr_ptr)->sp_ptr; + + dapls_cr_callback ( ep_ptr->cm_handle, + IB_CME_DISCONNECTED, + (void *) p_cm_drep_rec->p_drep_pdata, + (void *) sp_ptr, + NULL); + } + else + { + sp_ptr = NULL; + + dapl_evd_connection_callback ( ep_ptr->cm_handle, + IB_CME_DISCONNECTED, + (void *) p_cm_drep_rec->p_drep_pdata, + p_cm_drep_rec->qp_context); + } + } +} + + +static void +dapli_ib_cm_rep_cb ( + IN ib_cm_rep_rec_t *p_cm_rep_rec ) +{ + ib_api_status_t ib_status; + ib_cm_rtu_t cm_rtu; + uint8_t cm_cb_op; + DAPL_PRIVATE *prd_ptr; + DAPL_EP *ep_ptr; + dapl_ibal_ca_t *p_ca; + + dapl_os_assert (p_cm_rep_rec != NULL); + + dapl_os_memzero (&cm_rtu, sizeof ( ib_cm_rtu_t )); + + dapl_os_assert ( ((DAPL_HEADER *) p_cm_rep_rec->qp_context)->magic == + DAPL_MAGIC_EP ); + + ep_ptr = (DAPL_EP *) p_cm_rep_rec->qp_context; + dapl_dbg_log (DAPL_DBG_TYPE_CM, + "--> DiCRpcb: EP = %p local_max_rdma_read_in %d\n", + ep_ptr, p_cm_rep_rec->resp_res); + + p_ca = (dapl_ibal_ca_t *) + ep_ptr->header.owner_ia->hca_ptr->ib_hca_handle; + + cm_rtu.pfn_cm_apr_cb = dapli_ib_cm_apr_cb; + cm_rtu.pfn_cm_dreq_cb = dapli_ib_cm_dreq_cb; + cm_rtu.p_rtu_pdata = NULL; + cm_rtu.access_ctrl = IB_AC_LOCAL_WRITE|IB_AC_RDMA_WRITE|IB_AC_MW_BIND; + if ((ep_ptr->param.ep_attr.max_rdma_read_in > 0) || + (ep_ptr->param.ep_attr.max_rdma_read_out > 0)) + { + cm_rtu.access_ctrl |= IB_AC_RDMA_READ; + } + + cm_rtu.rq_depth = 0; + cm_rtu.sq_depth = 0; + + ib_status = ib_cm_rtu (p_cm_rep_rec->h_cm_rep, &cm_rtu); + + if (ib_status == IB_SUCCESS) + { + cm_cb_op = IB_CME_CONNECTED; + } + else + { + cm_cb_op = IB_CME_LOCAL_FAILURE; + } + + prd_ptr = (DAPL_PRIVATE *) p_cm_rep_rec->p_rep_pdata; + +#ifdef DAPL_DBG +#if 0 + { + int i; + + dapl_dbg_log ( DAPL_DBG_TYPE_EP, "--> DiCRpcb: private_data: "); + + for ( i = 0 ; i < IB_MAX_REP_PDATA_SIZE ; i++ ) + { + dapl_dbg_log ( DAPL_DBG_TYPE_EP, + "0x%x ", prd_ptr->private_data[i]); + + } + dapl_dbg_log ( DAPL_DBG_TYPE_EP, "\n"); + + } +#endif +#endif + + dapl_evd_connection_callback ( + p_cm_rep_rec->h_cm_rep, + cm_cb_op, + (void *) prd_ptr, + (void *) p_cm_rep_rec->qp_context); +} + + +static void +dapli_ib_cm_rej_cb ( + IN ib_cm_rej_rec_t *p_cm_rej_rec ) +{ + DAPL_EP *ep_ptr; + ib_cm_events_t cm_event; + + dapl_os_assert (p_cm_rej_rec); + + ep_ptr = (DAPL_EP *) p_cm_rej_rec->qp_context; + + dapl_dbg_log (DAPL_DBG_TYPE_CM, + "--> DiCRjcb: EP = %p QP = %p rej reason = 0x%x\n", + ep_ptr, ep_ptr->qp_handle, CL_NTOH16(p_cm_rej_rec->rej_status)); + + switch (p_cm_rej_rec->rej_status) + { + case IB_REJ_INSUF_RESOURCES: + case IB_REJ_INSUF_QP: + case IB_REJ_INVALID_COMM_ID: + case IB_REJ_INVALID_COMM_INSTANCE: + case IB_REJ_INVALID_PKT_RATE: + case IB_REJ_INVALID_ALT_GID: + case IB_REJ_INVALID_ALT_LID: + case IB_REJ_INVALID_ALT_SL: + case IB_REJ_INVALID_ALT_TRAFFIC_CLASS: + case IB_REJ_INVALID_ALT_PKT_RATE: + case IB_REJ_INVALID_ALT_HOP_LIMIT: + case IB_REJ_INVALID_ALT_FLOW_LBL: + case IB_REJ_INVALID_GID: + case IB_REJ_INVALID_LID: + case IB_REJ_INVALID_SID: + case IB_REJ_INVALID_SL: + case IB_REJ_INVALID_TRAFFIC_CLASS: + case IB_REJ_PORT_REDIRECT: + case IB_REJ_INVALID_MTU: + case IB_REJ_INSUFFICIENT_RESP_RES: + case IB_REJ_INVALID_CLASS_VER: + case IB_REJ_INVALID_FLOW_LBL: + cm_event = IB_CME_DESTINATION_REJECT; + break; + + case IB_REJ_TIMEOUT: + cm_event = IB_CME_DESTINATION_UNREACHABLE; + break; + + case IB_REJ_USER_DEFINED: + cm_event = IB_CME_DESTINATION_REJECT; + dapl_dbg_log (DAPL_DBG_TYPE_CM, + "--> DiCRjcb: user defined rej reason %s\n", + p_cm_rej_rec->p_ari); + break; + + default: + cm_event = IB_CME_LOCAL_FAILURE; + dapl_dbg_log (DAPL_DBG_TYPE_CM, + "--> DiCRjcb: with unknown status %x\n", + p_cm_rej_rec->rej_status); + break; + } + + /* FIXME - Vu + * We do not take care off the user defined rej reason with additional + * rejection information (p_ari) + */ + + if (ep_ptr->cr_ptr) + { + dapls_cr_callback ( ep_ptr->cm_handle, + cm_event, + (void *) p_cm_rej_rec->p_rej_pdata, + (void *) ((DAPL_CR *) ep_ptr->cr_ptr)->sp_ptr, + NULL); + } + else + { + dapl_evd_connection_callback ( ep_ptr->cm_handle, + cm_event, + (void *) p_cm_rej_rec->p_rej_pdata, + (void *) p_cm_rej_rec->qp_context); + } + +} + +static void +dapli_ib_cm_req_cb ( + IN ib_cm_req_rec_t *p_cm_req_rec ) +{ + DAPL_SP *sp_ptr; + DAT_SOCK_ADDR6 dest_ia_addr; + + + dapl_os_assert (p_cm_req_rec); + + sp_ptr = (DAPL_SP *) p_cm_req_rec->context; + + dapl_os_assert (sp_ptr); + + + /* + * Save the cm_srvc_handle to avoid the race condition between + * the return of the ib_cm_listen and the notification of a conn req + */ + if (sp_ptr->cm_srvc_handle != p_cm_req_rec->h_cm_listen) + { + dapl_dbg_log (DAPL_DBG_TYPE_CM | DAPL_DBG_TYPE_CALLBACK, + "--> DiCRqcb: cm_service_handle is changed\n"); + sp_ptr->cm_srvc_handle = p_cm_req_rec->h_cm_listen; + } + + dapl_os_memzero (&dest_ia_addr, sizeof (dest_ia_addr)); + +#ifdef NO_NAME_SERVICE + + { + DAPL_PRIVATE *prd_ptr; + + prd_ptr = (DAPL_PRIVATE *)p_cm_req_rec->p_req_pdata; + + dapl_os_memcpy ((void *)&dest_ia_addr, + (void *)&prd_ptr->hca_address, + sizeof (DAT_SOCK_ADDR6)); + } + +#else + + { + GID dest_gid; + + dapl_os_memzero (&dest_gid, sizeof (dest_gid)); + + dest_gid.guid = p_cm_req_rec->primary_path.dgid.unicast.interface_id; + dest_gid.gid_prefix = p_cm_req_rec->primary_path.dgid.unicast.prefix; + + if (DAT_SUCCESS != dapls_ns_map_ipaddr ( + sp_ptr->header.owner_ia->hca_ptr, + dest_gid, + (DAT_IA_ADDRESS_PTR)&dest_ia_addr)) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR,"cm_req_cb: SP = %p failed mapping GID-IPaddr\n", + sp_ptr); + } + } + +#endif /* NO_NAME_SERVICE */ + +#ifdef DAPL_DBG + { + int rval; + + rval = ((struct sockaddr_in *) &(dest_ia_addr))->sin_addr.s_addr; + + dapl_dbg_log (DAPL_DBG_TYPE_CM|DAPL_DBG_TYPE_CALLBACK, + "cm_req_cb: query SA for RemoteAddr: %d.%d.%d.%d\n", + (rval >> 0) & 0xff, + (rval >> 8) & 0xff, + (rval >> 16) & 0xff, + (rval >> 24) & 0xff); + } +#endif + + /* FIXME - Vu + * We have NOT used/saved the primary and alternative path record + * ie. p_cm_req_rec->p_primary_path and p_cm_req_rec->p_alt_path + * We should cache some fields in path record in the Name Service DB + * such as: dgid, dlid + * Also we do not save resp_res (ie. max_oustanding_rdma_read/atomic) + * rnr_retry_cnt and flow_ctrl fields + */ + dapl_dbg_log (DAPL_DBG_TYPE_CM, + "cm_req_cb: SP = %p rem_max_rdma_read_in %d\n", + sp_ptr, p_cm_req_rec->resp_res); + + dapls_cr_callback ( p_cm_req_rec->h_cm_req, + IB_CME_CONNECTION_REQUEST_PENDING, + (void *) p_cm_req_rec->p_req_pdata, + (void *) p_cm_req_rec->context, + (DAT_IA_ADDRESS_PTR)&dest_ia_addr); +} + + +static void +dapli_ib_cm_mra_cb ( + IN ib_cm_mra_rec_t *p_cm_mra_rec ) +{ + UNUSED_PARAM( p_cm_mra_rec ); + dapl_dbg_log (DAPL_DBG_TYPE_CM | DAPL_DBG_TYPE_CALLBACK, + "--> DiCMcb: CM callback MRA\n"); +} + +static void +dapli_ib_cm_rtu_cb ( + IN ib_cm_rtu_rec_t *p_cm_rtu_rec ) +{ + DAPL_EP *ep_ptr; + + dapl_os_assert (p_cm_rtu_rec != NULL); + + ep_ptr = (DAPL_EP *) p_cm_rtu_rec->qp_context; + + dapl_dbg_log (DAPL_DBG_TYPE_CM | DAPL_DBG_TYPE_CALLBACK, + "--> DiCRucb: EP = %p QP = %p\n", ep_ptr, ep_ptr->qp_handle); + + if (ep_ptr->cr_ptr) + { + DAPL_SP *sp_ptr; + + sp_ptr = ((DAPL_CR *) ep_ptr->cr_ptr)->sp_ptr; + + dapls_cr_callback ( ep_ptr->cm_handle, + IB_CME_CONNECTED, + (void *) p_cm_rtu_rec->p_rtu_pdata, + (void *) sp_ptr, + NULL); + + } + else + { + dapl_evd_connection_callback ( + ep_ptr->cm_handle, + IB_CME_CONNECTED, + (void *) p_cm_rtu_rec->p_rtu_pdata, + (void *) ep_ptr); + } +} + +static void +dapli_ib_cm_cancel_cb( void *context ) +{ + DAPL_SP *sp_ptr; + + sp_ptr = (DAPL_SP *) context; + dapl_os_assert ( sp_ptr ); + dapl_os_assert ( sp_ptr->header.magic == DAPL_MAGIC_PSP || + sp_ptr->header.magic == DAPL_MAGIC_RSP ); + + dapl_os_wait_object_wakeup( &sp_ptr->wait_object ); +} + +DAT_RETURN +dapls_ib_cm_remote_addr ( + IN DAT_HANDLE dat_handle, + IN DAPL_PRIVATE *prd_ptr, + OUT DAT_SOCK_ADDR6 *remote_ia_address ) +{ + UNUSED_PARAM( dat_handle ); + UNUSED_PARAM( prd_ptr ); + UNUSED_PARAM( remote_ia_address ); + return DAT_SUCCESS; +} + + +/* + * dapls_ib_connect + * + * Initiate a connection with the passive listener on another node + * + * Input: + * ep_handle, + * remote_ia_address, + * remote_conn_qual, + * prd_size size of private data and structure + * prd_prt pointer to private data structure + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + * + */ +DAT_RETURN +dapls_ib_connect ( + IN DAT_EP_HANDLE ep_handle, + IN DAT_IA_ADDRESS_PTR remote_ia_address, + IN DAT_CONN_QUAL remote_conn_qual, + IN DAT_COUNT prd_size, + IN DAPL_PRIVATE *prd_ptr ) +{ + DAPL_EP *ep_ptr; + DAPL_IA *ia_ptr; + ib_api_status_t ib_status; + dapl_ibal_port_t *p_active_port; + dapl_ibal_ca_t *p_ca; + ib_cm_req_t cm_req; + ib_path_rec_t path_rec; + GID dest_GID; + ib_query_req_t query_req; + ib_gid_pair_t gid_pair; + ib_service_record_t service_rec; + int retry_cnt; + DAT_RETURN dat_status; + + ep_ptr = (DAPL_EP *) ep_handle; + ia_ptr = ep_ptr->header.owner_ia; + ep_ptr->cr_ptr = NULL; + retry_cnt = 0; + dat_status = DAT_SUCCESS; + + p_ca = (dapl_ibal_ca_t *) ia_ptr->hca_ptr->ib_hca_handle; + + /* + * We are using the first active port in the list for + * communication. We have to get back here when we decide to support + * fail-over and high-availability. + */ + p_active_port = dapli_ibal_get_port ( p_ca, (uint8_t)ia_ptr->hca_ptr->port_num ); + + if (NULL == p_active_port) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR,"--> DsC: Port %d is not available = %d\n", + ia_ptr->hca_ptr->port_num, __LINE__); + return (DAT_INVALID_STATE); + } + + dapl_os_memzero (&dest_GID, sizeof (GID)); + dapl_os_memzero (&cm_req, sizeof (ib_cm_req_t)); + dapl_os_memzero (&path_rec, sizeof (ib_path_rec_t)); + dapl_os_memzero (&service_rec, sizeof (ib_service_record_t)); + dapl_os_memzero (&query_req, sizeof (ib_query_req_t)); + dapl_os_memzero (&gid_pair, sizeof (ib_gid_pair_t)); + dapl_os_memzero (&ep_ptr->remote_ia_address, sizeof (DAT_SOCK_ADDR6)); + + dapl_os_memcpy (&ep_ptr->remote_ia_address, + remote_ia_address, + sizeof (ep_ptr->remote_ia_address)); + + +#ifdef NO_NAME_SERVICE + + if (DAT_SUCCESS != + (dat_status = dapls_ns_lookup_address ( + ia_ptr, + remote_ia_address, + &dest_GID ))) + { + /* + * Remote address not in the table, this is a + * strange return code! + */ + dapl_dbg_log ( DAPL_DBG_TYPE_ERR,"--> DsC: exits status = %x\n", dat_status); + return dat_status; + } + + dest_GID.guid = CL_HTON64 (dest_GID.guid); + dest_GID.gid_prefix = CL_HTON64 (dest_GID.gid_prefix); + +#else + + /* + * We query the SA to get the dest_gid with the + * {uDAPL_svc_id, IP-address} as the key to get GID. + */ + if (DAT_SUCCESS != + (dat_status = dapls_ns_map_gid (ia_ptr->hca_ptr, + remote_ia_address, + &dest_GID))) + + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR,"--> DsC: fail to map remote_ia_addr (sa_family %d) to gid\n", + remote_ia_address->sa_family); + return dat_status; + } + +#endif /* NO_NAME_SERVICE */ + + gid_pair.dest_gid.unicast.interface_id = dest_GID.guid; + gid_pair.dest_gid.unicast.prefix = dest_GID.gid_prefix; + + dapl_dbg_log (DAPL_DBG_TYPE_CM, + "dapls_ib_connect: EP = %p QP = %p SERVER GID{0x" F64x ", 0x" F64x "}\n", + ep_ptr, ep_ptr->qp_handle, cl_hton64 (gid_pair.dest_gid.unicast.prefix), + cl_hton64 (gid_pair.dest_gid.unicast.interface_id)); + + gid_pair.src_gid = p_active_port->p_attr->p_gid_table[0]; +/* + if ((gid_pair.src_gid.unicast.interface_id == + gid_pair.dest_gid.unicast.interface_id ) && + (gid_pair.src_gid.unicast.prefix == + gid_pair.dest_gid.unicast.prefix )) + { + path_rec.dgid = gid_pair.dest_gid; + path_rec.sgid = gid_pair.src_gid; + path_rec.slid = path_rec.dlid = p_active_port->p_attr->lid; + path_rec.pkey = p_active_port->p_attr->p_pkey_table[0]; + path_rec.mtu = p_active_port->p_attr->mtu; + path_rec.pkt_life = 18; // 1 sec + path_rec.rate = IB_PATH_RECORD_RATE_10_GBS; + + } + else + { + */ /* + * Query SA to get the path record from pair of GIDs + */ + dapl_os_memzero (&query_req, sizeof (ib_query_req_t)); + query_req.query_type = IB_QUERY_PATH_REC_BY_GIDS; + query_req.p_query_input = (void *) &gid_pair; + query_req.flags = IB_FLAGS_SYNC; + query_req.timeout_ms = 1 * 1000; /* 1 second */ + query_req.retry_cnt = 3; + /* query SA using this port */ + query_req.port_guid = p_active_port->p_attr->port_guid; + query_req.query_context = (void *) &path_rec; + query_req.pfn_query_cb = dapli_ib_sa_query_cb; + + ib_status = ib_query (dapl_ibal_root.h_al, &query_req, NULL); + + if ((ib_status != IB_SUCCESS) || (!path_rec.dlid)) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR,"--> DsC: EP = %p QP = %p query pair_gids status = %s\n", + ep_ptr, ep_ptr->qp_handle, ib_get_err_str(ib_status)); + return DAT_INVALID_PARAMETER; + } + + //} + + /* + * Tavor has a HW bug that causes bandwidth with 2K MTU to be less than + * with 1K MTU. Cap the MTU based on device ID to compensate for this. + */ + if( (p_ca->p_ca_attr->dev_id == 0x5A44) && + (ib_path_rec_mtu( &path_rec ) > IB_MTU_LEN_1024) ) + { + /* Local endpoint is Tavor - cap MTU to 1K for extra bandwidth. */ + path_rec.mtu &= IB_PATH_REC_SELECTOR_MASK; + path_rec.mtu |= IB_MTU_LEN_1024; + } + + /* + * prepare the Service ID from conn_qual + */ + cm_req.svc_id = remote_conn_qual; + cm_req.p_primary_path = &path_rec; + cm_req.p_alt_path = NULL; + cm_req.h_qp = ep_ptr->qp_handle; + cm_req.qp_type = IB_QPT_RELIABLE_CONN; + cm_req.p_req_pdata = (uint8_t *) prd_ptr; + cm_req.req_length = (uint8_t)prd_size; + /* cm retry to send this request messages, IB max of 4 bits */ + cm_req.max_cm_retries = 15; /* timer outside of call, s/be infinite */ + /* qp retry to send any wr */ + cm_req.retry_cnt = 5; + /* max num of oustanding RDMA read/atomic support */ + cm_req.resp_res = (uint8_t)ep_ptr->param.ep_attr.max_rdma_read_in; + /* max num of oustanding RDMA read/atomic will use */ + cm_req.init_depth = (uint8_t)ep_ptr->param.ep_attr.max_rdma_read_out; + + /* time wait before retrying a pkt after receiving a RNR NAK */ + cm_req.rnr_nak_timeout = IB_RNR_NAK_TIMEOUT; /* dapl_ibal_util.h */ + + /* + * number of time local QP should retry after receiving RNR NACK before + * reporting an error + */ + cm_req.rnr_retry_cnt = IB_RNR_RETRY_CNT; + + cm_req.remote_resp_timeout = 16; /* 250ms */ + cm_req.local_resp_timeout = 16; /* 250ms */ + + cm_req.flow_ctrl = TRUE; + cm_req.flags = 0; + /* + * We do not use specific data buffer to check for specific connection + */ + cm_req.p_compare_buffer = NULL; + cm_req.compare_offset = 0; + cm_req.compare_length = 0; + + dapl_dbg_log (DAPL_DBG_TYPE_CM, + "--> DsConn: EP=%p QP=%p rio=%d,%d, pl=%d, mtu=%d slid=%#x dlid=%#x\n", + ep_ptr, ep_ptr->qp_handle, cm_req.resp_res, + cm_req.init_depth, + ib_path_rec_pkt_life(&path_rec), + ib_path_rec_mtu(&path_rec), + cm_req.p_primary_path->slid, + cm_req.p_primary_path->dlid); + + /* + * We do not support peer_to_peer; therefore, we set pfn_cm_req_cb = NULL + */ + cm_req.pfn_cm_req_cb = NULL; + cm_req.pfn_cm_rep_cb = dapli_ib_cm_rep_cb; + cm_req.pfn_cm_rej_cb = dapli_ib_cm_rej_cb; + /* callback when a message received acknowledgement is received */ + cm_req.pfn_cm_mra_cb = dapli_ib_cm_mra_cb; + + ib_status = ib_cm_req (&cm_req); + + if ( ib_status != IB_SUCCESS ) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR,"--> DsC: EP = %p QP = %p conn_request failed = %s\n", + ep_ptr, ep_ptr->qp_handle, ib_get_err_str(ib_status)); + return (dapl_ib_status_convert (ib_status)); + } + + return DAT_SUCCESS; +} + + +/* + * dapls_ib_disconnect + * + * Disconnect an EP + * + * Input: + * ep_handle, + * disconnect_flags + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + * + */ +DAT_RETURN + dapls_ib_disconnect ( + IN DAPL_EP *ep_ptr, + IN DAT_CLOSE_FLAGS disconnect_flags) +{ + ib_api_status_t ib_status = IB_SUCCESS; + ib_cm_dreq_t cm_dreq; + + UNUSED_PARAM( disconnect_flags ); + + dapl_os_memzero(&cm_dreq, sizeof(ib_cm_dreq_t)); + + cm_dreq.qp_type = IB_QPT_RELIABLE_CONN; + cm_dreq.h_qp = ep_ptr->qp_handle; + cm_dreq.pfn_cm_drep_cb = dapli_ib_cm_drep_cb; + + dapl_dbg_log (DAPL_DBG_TYPE_CM, + "--> DsD: EP=%p QP=%p ep_state=%d, dr %d, ds %d\n", + ep_ptr, ep_ptr->qp_handle, + ep_ptr->param.ep_state, + ep_ptr->recv_discreq, ep_ptr->sent_discreq ); + + /* + * Currently we do not send any disconnect private data to + * the other endpoint because DAT 1.0 & 1.1 does not support + */ + cm_dreq.p_dreq_pdata = NULL; + + if ( (ep_ptr->recv_discreq == DAT_FALSE ) + && (ep_ptr->sent_discreq == DAT_FALSE ) ) + //(disconnect_flags == DAT_CLOSE_ABRUPT_FLAG ) ) + { + ep_ptr->sent_discreq = DAT_TRUE; + ib_status = ib_cm_dreq ( &cm_dreq ); + + /* tolerate INVALID_STATE error as the other side can race ahead and + * generate a DREQ before we do. + */ + if ( ib_status == IB_INVALID_STATE ) + ib_status = IB_SUCCESS; + + if (ib_status ) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "--> DsD: EP=%p QP= %p DREQ SEND status %s\n", + ep_ptr, ep_ptr->qp_handle,ib_get_err_str(ib_status)); + } + } + return dapl_ib_status_convert (ib_status); +} + + +/* + * dapl_ib_setup_conn_listener + * + * Have the CM set up a connection listener. + * + * Input: + * ibm_hca_handle HCA handle + * qp_handle QP handle + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + * + */ +DAT_RETURN +dapls_ib_setup_conn_listener ( + IN DAPL_IA *ia_ptr, + IN DAT_UINT64 ServiceID, + IN DAPL_SP *sp_ptr ) +{ + ib_api_status_t ib_status; + ib_cm_listen_t cm_listen; + dapl_ibal_ca_t *p_ca; + dapl_ibal_port_t *p_active_port; + + p_ca = (dapl_ibal_ca_t *) ia_ptr->hca_ptr->ib_hca_handle; + + /* + * We are using the first active port in the list for + * communication. We have to get back here when we decide to support + * fail-over and high-availability. + */ + p_active_port = dapli_ibal_get_port ( p_ca, (uint8_t)ia_ptr->hca_ptr->port_num ); + + if (NULL == p_active_port) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR,"setup_conn_listener: SP = %p port %d is not available\n", + sp_ptr, ia_ptr->hca_ptr->port_num); + return (DAT_INVALID_STATE); + } + + if (p_active_port->p_attr->lid == 0) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR,"--> DsSCL: SP = %p SID = 0x" F64x " port %d\n", + sp_ptr, cl_hton64(ServiceID), p_active_port->p_attr->port_num); + return (DAT_INVALID_STATE); + } + + dapl_dbg_log (DAPL_DBG_TYPE_CM, + "Setup_conn_listener: SP = %p port %d GID{0x" F64x ", 0x" F64x "} and SID 0x" F64x "\n", + sp_ptr, p_active_port->p_attr->port_num, + cl_hton64 (p_active_port->p_attr->p_gid_table[0].unicast.prefix), + cl_hton64 (p_active_port->p_attr->p_gid_table[0].unicast.interface_id), + cl_hton64 (ServiceID)); + + dapl_os_memzero (&cm_listen, sizeof (ib_cm_listen_t)); + + /* + * Listen for all request on this specific CA + */ + cm_listen.ca_guid = (p_ca->p_ca_attr->ca_guid); + cm_listen.svc_id = ServiceID; + cm_listen.qp_type = IB_QPT_RELIABLE_CONN; + + /* + * We do not use specific data buffer to check for specific connection + */ + cm_listen.p_compare_buffer = NULL;//(uint8_t*)&sp_ptr->conn_qual; + cm_listen.compare_offset = 0;//IB_MAX_REQ_PDATA_SIZE - sizeof(DAT_CONN_QUAL); + cm_listen.compare_length = 0;//sizeof(DAT_CONN_QUAL); + + /* + * We can pick a port here for communication and the others are reserved + * for fail-over / high-availability - TBD + */ + cm_listen.port_guid = p_active_port->p_attr->port_guid; + cm_listen.lid = p_active_port->p_attr->lid; + cm_listen.pkey = p_active_port->p_attr->p_pkey_table[0]; + + /* + * Register request or mra callback functions + */ + cm_listen.pfn_cm_req_cb = dapli_ib_cm_req_cb; + + ib_status = ib_cm_listen ( dapl_ibal_root.h_al, + &cm_listen, + (void *) sp_ptr, + &sp_ptr->cm_srvc_handle); + + if (ib_status != IB_SUCCESS) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR,"setup_conn_listener: SP = %p SID = 0x" F64x " listen failed = %s\n", + sp_ptr, cl_hton64 (ServiceID), ib_get_err_str(ib_status)); + } + + return dapl_ib_status_convert (ib_status); +} + +/* + * dapl_ib_remove_conn_listener + * + * Have the CM remove a connection listener. + * + * Input: + * ia_handle IA handle + * ServiceID IB Channel Service ID + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + * + */ +DAT_RETURN dapls_ib_remove_conn_listener ( + IN DAPL_IA *ia_ptr, + IN DAPL_SP *sp_ptr) +{ + ib_api_status_t ib_status; + DAT_RETURN dat_status = DAT_SUCCESS; + + UNUSED_PARAM( ia_ptr ); + + if (sp_ptr->cm_srvc_handle) + { + ib_status = ib_cm_cancel (sp_ptr->cm_srvc_handle, + dapli_ib_cm_cancel_cb ); + + if (ib_status != IB_SUCCESS) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR,"--> DsRCL: SP = %p ib_cm_cancel failed = %s\n", + sp_ptr, ib_get_err_str(ib_status)); + return (DAT_INVALID_PARAMETER); + } + dat_status = dapl_os_wait_object_wait ( + &sp_ptr->wait_object, DAT_TIMEOUT_INFINITE ); + + if ( DAT_SUCCESS != dat_status ) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR,"--> DsRCL: SP = %p wait failed = 0x%x\n", + sp_ptr, dat_status ); + return dat_status; + } + + sp_ptr->cm_srvc_handle = NULL; + } + + return DAT_SUCCESS; +} + +/* + * dapls_ib_reject_connection + * + * Perform necessary steps to reject a connection + * + * Input: + * cr_handle + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + * + */ +DAT_RETURN +dapls_ib_reject_connection ( + IN ib_cm_handle_t ib_cm_handle, + IN int reject_reason ) +{ + ib_api_status_t ib_status; + ib_cm_rej_t cm_rej; + static char *rej_table[] = + { + "INVALID_REJ_REASON", + "INVALID_REJ_REASON", + "INVALID_REJ_REASON", + "INVALID_REJ_REASON", + "INVALID_REJ_REASON", + "IB_CME_DESTINATION_REJECT", + "IB_CME_DESTINATION_REJECT_PRIVATE_DATA", + "IB_CME_DESTINATION_UNREACHABLE", + "IB_CME_TOO_MANY_CONNECTION_REQUESTS", + "IB_CME_LOCAL_FAILURE", + "IB_CM_LOCAL_FAILURE" + }; + +#define REJ_TABLE_SIZE IB_CM_LOCAL_FAILURE + + reject_reason = __min( reject_reason & 0xff, REJ_TABLE_SIZE); + + cm_rej.rej_status = IB_REJ_USER_DEFINED; + cm_rej.p_ari = (ib_ari_t *)&rej_table[reject_reason]; + cm_rej.ari_length = (uint8_t)strlen (rej_table[reject_reason]); + cm_rej.p_rej_pdata = NULL; + cm_rej.rej_length = 0; + + ib_status = ib_cm_rej ( ib_cm_handle, &cm_rej); + + if (ib_status != IB_SUCCESS) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR,"--> DsRjC: cm_handle = %p reject failed = %s\n", + &ib_cm_handle, ib_get_err_str(ib_status)); + } + + return ( dapl_ib_status_convert ( ib_status ) ); + +} + + + + +/* + * dapls_ib_accept_connection + * + * Perform necessary steps to accept a connection + * + * Input: + * cr_handle + * ep_handle + * private_data_size + * private_data + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + * + */ +DAT_RETURN +dapls_ib_accept_connection ( + IN DAT_CR_HANDLE cr_handle, + IN DAT_EP_HANDLE ep_handle, + IN DAT_COUNT private_data_size, + IN DAPL_PRIVATE *prd_ptr ) +{ + DAPL_CR *cr_ptr; + DAPL_EP *ep_ptr; + DAPL_IA *ia_ptr; + DAT_RETURN dat_status; + ib_api_status_t ib_status; + dapl_ibal_ca_t *p_ca; + dapl_ibal_port_t *p_active_port; + ib_cm_rep_t cm_rep; + + cr_ptr = (DAPL_CR *) cr_handle; + ep_ptr = (DAPL_EP *) ep_handle; + ia_ptr = ep_ptr->header.owner_ia; + + if ( ep_ptr->qp_state == DAPL_QP_STATE_UNATTACHED ) + { + /* + * If we are lazy attaching the QP then we may need to + * hook it up here. Typically, we run this code only for + * DAT_PSP_PROVIDER_FLAG + */ + dat_status = dapls_ib_qp_alloc ( ia_ptr, ep_ptr, ep_ptr ); + + if ( dat_status != DAT_SUCCESS) + { + /* This is not a great error code, but all the spec allows */ + dapl_dbg_log ( DAPL_DBG_TYPE_ERR,"--> DsAC: CR = %p EP = %p alloc QP failed = 0x%x\n", + cr_ptr, ep_ptr, dat_status); + return (dat_status); + } + } + + p_ca = (dapl_ibal_ca_t *) ia_ptr->hca_ptr->ib_hca_handle; + p_active_port = dapli_ibal_get_port ( p_ca, (uint8_t)ia_ptr->hca_ptr->port_num ); + + if (NULL == p_active_port) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR,"--> DsAC: CR = %p EP = %p port %d is not available\n", + cr_ptr, ep_ptr, ia_ptr->hca_ptr->port_num); + return (DAT_INVALID_STATE); + } + + cr_ptr->param.local_ep_handle = ep_handle; + ep_ptr->cm_handle = cr_ptr->ib_cm_handle; + ep_ptr->qp_state = IB_QPS_INIT; + ep_ptr->cr_ptr = cr_ptr; + + dapl_os_memzero ( &cm_rep, sizeof (ib_cm_rep_t) ); + + cm_rep.h_qp = ep_ptr->qp_handle; + cm_rep.qp_type = IB_QPT_RELIABLE_CONN; + cm_rep.p_rep_pdata = (uint8_t *) prd_ptr->private_data; + cm_rep.rep_length = (uint8_t) private_data_size; + + dapl_dbg_log ( DAPL_DBG_TYPE_CM, + "--> DsAC: CR = %p EP = %p QP = %p cm_handle = %p\n", + cr_ptr, ep_ptr, ep_ptr->qp_handle, ep_ptr->cm_handle ); + +#ifdef DAPL_DBG +#if 0 + { + int i; + + dapl_dbg_log ( DAPL_DBG_TYPE_EP, "--> DsAC: private_data: "); + + for ( i = 0 ; i < IB_MAX_REP_PDATA_SIZE ; i++ ) + { + dapl_dbg_log ( DAPL_DBG_TYPE_EP, + "0x%x ", prd_ptr->private_data[i]); + + } + dapl_dbg_log ( DAPL_DBG_TYPE_EP, "\n"); + + } +#endif +#endif + + cm_rep.pfn_cm_rej_cb = dapli_ib_cm_rej_cb; + cm_rep.pfn_cm_mra_cb = dapli_ib_cm_mra_cb; + cm_rep.pfn_cm_rtu_cb = dapli_ib_cm_rtu_cb; + cm_rep.pfn_cm_lap_cb = dapli_ib_cm_lap_cb; + cm_rep.pfn_cm_dreq_cb = dapli_ib_cm_dreq_cb; + + /* + * FIXME - Vu + * Play attention to the attributes. + * Some of them are desirably set by DAT consumers + */ + /* + * We enable the qp associate with this connection ep all the access right + * We enable the flow_ctrl, retry till success + * We will limit the access right and flow_ctrl upon DAT consumers + * requirements + */ + cm_rep.access_ctrl = IB_AC_LOCAL_WRITE|IB_AC_RDMA_WRITE|IB_AC_MW_BIND; + if ((ep_ptr->param.ep_attr.max_rdma_read_in > 0) + || (ep_ptr->param.ep_attr.max_rdma_read_out > 0)) + { + cm_rep.access_ctrl |= IB_AC_RDMA_READ; + } + + cm_rep.sq_depth = 0; + cm_rep.rq_depth = 0; + /* max num of oustanding RDMA read/atomic will use */ + cm_rep.init_depth = (uint8_t)ep_ptr->param.ep_attr.max_rdma_read_out; + cm_rep.flow_ctrl = TRUE; + cm_rep.flags = 0; + cm_rep.failover_accepted = IB_FAILOVER_ACCEPT_UNSUPPORTED; + cm_rep.target_ack_delay = 14; + /* see dapl_ibal_util.h for IB_RNR_XXX */; + cm_rep.rnr_nak_timeout = IB_RNR_NAK_TIMEOUT; + cm_rep.rnr_retry_cnt = IB_RNR_RETRY_CNT; + cm_rep.p_recv_wr = NULL; + cm_rep.pp_recv_failure = NULL; + + ib_status = ib_cm_rep ( cr_ptr->ib_cm_handle, &cm_rep); + + if (ib_status != IB_SUCCESS) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR,"--> DsAC: EP = %p QP = %p cm_handle = %p reply failed = %#x\n", + ep_ptr, ep_ptr->qp_handle, ep_ptr->cm_handle, ib_status ); + } + + return ( dapl_ib_status_convert ( ib_status ) ); +} + + + +/* + * dapls_ib_disconnect_clean + * + * Clean up outstanding connection data. This routine is invoked + * after the final disconnect callback has occurred. Only on the + * ACTIVE side of a connection. + * + * Input: + * ep_ptr DAPL_EP + * + * Output: + * none + * + * Returns: + * void + * + */ +void +dapls_ib_disconnect_clean ( + IN DAPL_EP *ep_ptr, + IN DAT_BOOLEAN active, + IN const ib_cm_events_t ib_cm_event ) +{ + DAPL_IA *ia_ptr; + ib_qp_attr_t qp_attr; + ib_api_status_t ib_status; + + ia_ptr = ep_ptr->header.owner_ia; + + if ( ia_ptr == NULL || ia_ptr->header.magic != DAPL_MAGIC_IA ) + { + return; + } + dapl_os_assert ( ep_ptr->header.magic == DAPL_MAGIC_EP || + ep_ptr->header.magic == DAPL_MAGIC_EP_EXIT ); + + /* + * Query the QP to get the current state */ + ib_status = ib_query_qp ( ep_ptr->qp_handle, &qp_attr ); + + if ( ib_status != IB_SUCCESS ) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, ">>>DSCONN_CLEAN(%s): Query QP failed = %#x\n", + (active?"Act":"Pas"),ib_status ); + return; + } + + ep_ptr->qp_state = qp_attr.state; + + dapl_dbg_log (DAPL_DBG_TYPE_CM,">>>DSCONN_CLEAN(%s): cm_event: %d ep_ptr=%p ep_state:%d qp_state: %#x\n", + (active?"A":"P"), + ib_cm_event, + ep_ptr, + ep_ptr->param.ep_state, + ep_ptr->qp_state); + if ( ep_ptr->qp_state != IB_QPS_ERROR && + ep_ptr->qp_state != IB_QPS_RESET && + ep_ptr->qp_state != IB_QPS_INIT ) + { + ep_ptr->qp_state = IB_QPS_ERROR; + dapls_modify_qp_state_to_error (ep_ptr->qp_handle); + } + return; +} + + +/* + * dapls_ib_cr_handoff + * + * Hand off the connection request to another service point + * + * Input: + * cr_handle DAT_CR_HANDLE + * handoff_serv_id DAT_CONN_QUAL + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + * + */ +DAT_RETURN +dapls_ib_cr_handoff ( + IN DAT_CR_HANDLE cr_handle, + IN DAT_CONN_QUAL handoff_serv_id ) +{ + DAPL_CR *cr_ptr; + ib_api_status_t ib_status; + + cr_ptr = (DAPL_CR *) cr_handle; + + if (cr_ptr->ib_cm_handle.cid == 0xFFFFFFFF) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR,"--> DsCH: CR = %p invalid cm handle\n", cr_ptr); + return DAT_INVALID_PARAMETER; + } + + if (cr_ptr->sp_ptr == IB_INVALID_HANDLE) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR,"--> DsCH: CR = %p invalid psp handle\n", cr_ptr); + return DAT_INVALID_PARAMETER; + } + + ib_status = ib_cm_handoff (cr_ptr->ib_cm_handle, handoff_serv_id); + + if (ib_status != IB_SUCCESS) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR,"--> DsCH: CR = %p handoff failed = %s\n", + cr_ptr, ib_get_err_str(ib_status)); + return dapl_ib_status_convert (ib_status); + } + + /* Remove the CR from the queue */ + dapl_sp_remove_cr (cr_ptr->sp_ptr, cr_ptr); + + /* + * If this SP has been removed from service, free it + * up after the last CR is removed + */ + dapl_os_lock (&cr_ptr->sp_ptr->header.lock); + if ( cr_ptr->sp_ptr->listening != DAT_TRUE && + cr_ptr->sp_ptr->cr_list_count == 0 && + cr_ptr->sp_ptr->state != DAPL_SP_STATE_FREE ) + { + dapl_dbg_log (DAPL_DBG_TYPE_CM, + "--> DsCH: CR = %p disconnect dump SP = %p \n", + cr_ptr, cr_ptr->sp_ptr); + /* Decrement the ref count on the EVD */ + if (cr_ptr->sp_ptr->evd_handle) + { + dapl_os_atomic_dec (& ((DAPL_EVD *)cr_ptr->sp_ptr->evd_handle)->evd_ref_count); + cr_ptr->sp_ptr->evd_handle = NULL; + } + cr_ptr->sp_ptr->state = DAPL_SP_STATE_FREE; + dapl_os_unlock (&cr_ptr->sp_ptr->header.lock); + (void)dapls_ib_remove_conn_listener ( cr_ptr->sp_ptr->header.owner_ia, + cr_ptr->sp_ptr ); + dapls_ia_unlink_sp ( (DAPL_IA *)cr_ptr->sp_ptr->header.owner_ia, + cr_ptr->sp_ptr ); + dapls_sp_free_sp ( cr_ptr->sp_ptr ); + } + else + { + dapl_os_unlock (&cr_ptr->sp_ptr->header.lock); + } + + /* + * Clean up and dispose of the resource + */ + dapls_cr_free (cr_ptr); + + return (DAT_SUCCESS); +} + +/* + * dapls_ib_private_data_size + * + * Return the size of private data given a connection op type + * + * Input: + * prd_ptr private data pointer + * conn_op connection operation type + * + * If prd_ptr is NULL, this is a query for the max size supported by + * the provider, otherwise it is the actual size of the private data + * contained in prd_ptr. + * + * Infiniband has fixed size private data, so prd_ptr is ignored. + * + * Output: + * None + * + * Returns: + * length of private data + * + */ +DAT_COUNT +dapls_ib_private_data_size ( + IN DAPL_PRIVATE *prd_ptr, + IN DAPL_PDATA_OP conn_op) +{ + int size; + + UNUSED_PARAM( prd_ptr ); + + switch (conn_op) + { + case DAPL_PDATA_CONN_REQ: + { + size = IB_MAX_REQ_PDATA_SIZE; + break; + } + case DAPL_PDATA_CONN_REP: + { + size = IB_MAX_REP_PDATA_SIZE; + break; + } + case DAPL_PDATA_CONN_REJ: + { + size = IB_MAX_REJ_PDATA_SIZE; + break; + } + case DAPL_PDATA_CONN_DREQ: + { + size = IB_MAX_DREQ_PDATA_SIZE; + break; + } + case DAPL_PDATA_CONN_DREP: + { + size = IB_MAX_DREP_PDATA_SIZE; + break; + } + default: + { + size = 0; + } + } /* end case */ + + return size; +} + + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ + diff --git a/branches/WOF2-3/ulp/dapl/dapl/ibal/dapl_ibal_dto.h b/branches/WOF2-3/ulp/dapl/dapl/ibal/dapl_ibal_dto.h new file mode 100644 index 00000000..ae9159f4 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/ibal/dapl_ibal_dto.h @@ -0,0 +1,354 @@ + +/* + * Copyright (c) 2002, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ibal_dto.h + * + * PURPOSE: Utility routines for data transfer operations using the + * IBAL APIs + * + * $Id$ + * + **********************************************************************/ + +#ifndef _DAPL_IBAL_DTO_H +#define _DAPL_IBAL_DTO_H + +#include "dapl_ibal_util.h" + +STATIC _INLINE_ int +dapls_cqe_opcode_convert (ib_work_completion_t *cqe_p); + +extern DAT_RETURN +dapls_ib_cq_late_alloc ( + IN ib_pd_handle_t pd_handle, + IN DAPL_EVD *evd_ptr); + +#define DAPL_DEFAULT_DS_ENTRIES 8 + +/* + * dapls_ib_post_recv + * + * Provider specific Post RECV function + */ +STATIC _INLINE_ DAT_RETURN +dapls_ib_post_recv ( + IN DAPL_EP *ep_ptr, + IN DAPL_COOKIE *cookie, + IN DAT_COUNT num_segments, + IN DAT_LMR_TRIPLET *local_iov) +{ + ib_api_status_t ib_status; + ib_recv_wr_t recv_wr, *failed_wr_p; + ib_local_ds_t ds_array[DAPL_DEFAULT_DS_ENTRIES], *ds_array_p; + DAT_COUNT i, total_len; + + dapl_os_memzero(&recv_wr, sizeof(ib_recv_wr_t)); +#ifndef _WIN64 + // Fix MS compiler warning C4826: Conversion from 'DAPL_COOKIE *' to + // 'DAT_UINT64' sign-extends; This may cause unexpected runtime behavior. + recv_wr.wr_id = (DAT_UINT64) (DAT_UINT32) cookie; +#else + recv_wr.wr_id = (DAT_UINT64) cookie; +#endif + recv_wr.num_ds = num_segments; + + if( num_segments <= DAPL_DEFAULT_DS_ENTRIES ) + { + ds_array_p = ds_array; + } + else + { + ds_array_p = dapl_os_alloc( num_segments * sizeof(ib_local_ds_t) ); + } + recv_wr.ds_array = ds_array_p; + + if (NULL == ds_array_p) + { + return (DAT_INSUFFICIENT_RESOURCES); + } + + total_len = 0; + + for (i = 0; i < num_segments; i++, ds_array_p++) + { + ds_array_p->length = (uint32_t)local_iov[i].segment_length; + ds_array_p->lkey = local_iov[i].lmr_context; + ds_array_p->vaddr = local_iov[i].virtual_address; + total_len += ds_array_p->length; + } + + if (cookie != NULL) + { + cookie->val.dto.size = total_len; + dapl_dbg_log (DAPL_DBG_TYPE_EP, + "--> DsPR: EP = %p QP = %p cookie= %p, num_seg= %d\n", + ep_ptr, ep_ptr->qp_handle, cookie, num_segments); + } + recv_wr.p_next = NULL; + + ib_status = ib_post_recv( ep_ptr->qp_handle, &recv_wr, &failed_wr_p ); + + if( num_segments > DAPL_DEFAULT_DS_ENTRIES ) + dapl_os_free( recv_wr.ds_array, num_segments * sizeof(ib_local_ds_t) ); + + if (IB_SUCCESS == ib_status) + { + return DAT_SUCCESS; + } + + dapl_dbg_log (DAPL_DBG_TYPE_DTO_COMP_ERR, + "--> DsPR: post_recv status %s\n", + ib_get_err_str(ib_status)); + /* + * Moving QP to error state; + */ + (void) dapls_modify_qp_state_to_error ( ep_ptr->qp_handle); + ep_ptr->qp_state = IB_QPS_ERROR; + + return (dapl_ib_status_convert (ib_status)); +} + + +/* + * dapls_ib_post_send + * + * Provider specific Post SEND function + */ +STATIC _INLINE_ DAT_RETURN +dapls_ib_post_send ( + IN DAPL_EP *ep_ptr, + IN ib_send_op_type_t op_type, + IN DAPL_COOKIE *cookie, + IN DAT_COUNT num_segments, + IN DAT_LMR_TRIPLET *local_iov, + IN const DAT_RMR_TRIPLET *remote_iov, + IN DAT_COMPLETION_FLAGS completion_flags ) +{ + ib_api_status_t ib_status; + ib_send_wr_t send_wr, *failed_wr_p; + ib_local_ds_t ds_array[DAPL_DEFAULT_DS_ENTRIES], *ds_array_p; + DAT_COUNT i, total_len; + + if (ep_ptr->param.ep_state != DAT_EP_STATE_CONNECTED) + { + ib_qp_attr_t qp_attr; + + (void) ib_query_qp ( ep_ptr->qp_handle, &qp_attr ); + + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "--> DsPS: !CONN EP (%p) ep_state=%d QP_state=%d\n", + ep_ptr, ep_ptr->param.ep_state, qp_attr.state ); + + return(DAT_ERROR(DAT_INVALID_STATE, DAT_INVALID_STATE_EP_DISCONNECTED)); + } + dapl_os_memzero (&send_wr, sizeof(ib_send_wr_t)); + + send_wr.wr_type = op_type; + send_wr.num_ds = num_segments; + + if( num_segments <= DAPL_DEFAULT_DS_ENTRIES ) + { + ds_array_p = ds_array; + } + else + { + ds_array_p = dapl_os_alloc( num_segments * sizeof(ib_local_ds_t) ); + } + send_wr.ds_array = ds_array_p; + + if (NULL == ds_array_p) + { + return (DAT_INSUFFICIENT_RESOURCES); + } + + total_len = 0; + + for (i = 0; i < num_segments; i++, ds_array_p++) + { + ds_array_p->length = (uint32_t)local_iov[i].segment_length; + ds_array_p->lkey = local_iov[i].lmr_context; + ds_array_p->vaddr = local_iov[i].virtual_address; + total_len += ds_array_p->length; + } + + /* NULL cookie is OK if no Completion event is requested */ + if (cookie != NULL) + { + dapl_os_assert( cookie->ep == ep_ptr ); + cookie->val.dto.size = total_len; + + dapl_dbg_log (DAPL_DBG_TYPE_EP, "--> DsPS: EVD=%p EP=%p QP=%p type=%d " + "sg=%d ln=%d ck=%p 0x" F64x "\n", + ep_ptr->param.request_evd_handle, ep_ptr, ep_ptr->qp_handle, + op_type, num_segments, total_len, + cookie, cookie->val.dto.cookie.as_64 ); + } +#ifndef _WIN64 + // Fix MS compiler warning C4826: Conversion from 'DAPL_COOKIE *' to + // 'DAT_UTIN64' sign-extends; This may cause unexpected runtime behavior. + send_wr.wr_id = (DAT_UINT64) (DAT_UINT32)cookie; +#else + send_wr.wr_id = (DAT_UINT64) cookie; +#endif + + /* RC for now */ + if (total_len > 0) + { + send_wr.remote_ops.vaddr = remote_iov->target_address; + send_wr.remote_ops.rkey = remote_iov->rmr_context; + } + + send_wr.send_opt = 0; + + send_wr.send_opt |= (DAT_COMPLETION_BARRIER_FENCE_FLAG & + completion_flags) ? IB_SEND_OPT_FENCE : 0; + send_wr.send_opt |= (DAT_COMPLETION_SUPPRESS_FLAG & + completion_flags) ? 0 : IB_SEND_OPT_SIGNALED; + send_wr.send_opt |= (DAT_COMPLETION_SOLICITED_WAIT_FLAG & + completion_flags) ? IB_SEND_OPT_SOLICITED : 0; + + dapl_dbg_log (DAPL_DBG_TYPE_EP, "--> DsPS: EP=%p QP=%p send_opt=0x%x," + "rem_addr=%p, rem_rkey=0x%x completion_flags=0x%x\n", + ep_ptr, ep_ptr->qp_handle, + send_wr.send_opt, (void *)(uintptr_t) send_wr.remote_ops.vaddr, + send_wr.remote_ops.rkey, completion_flags); + + send_wr.p_next = NULL; + + /* hold reference for QP command serialization on destruction */ + dapl_os_atomic_inc (&ep_ptr->req_count); + ib_status = ib_post_send( ep_ptr->qp_handle, &send_wr, &failed_wr_p ); + dapl_os_atomic_dec (&ep_ptr->req_count); + + if( num_segments > DAPL_DEFAULT_DS_ENTRIES ) + dapl_os_free( send_wr.ds_array, num_segments * sizeof(ib_local_ds_t) ); + + if (IB_SUCCESS == ib_status) + { + return DAT_SUCCESS; + } + + dapl_dbg_log (DAPL_DBG_TYPE_DTO_COMP_ERR, + "--> DsPS: EP=%p post_send status %s\n", + ep_ptr, ib_get_err_str(ib_status)); + /* + * Moving QP to error state; + */ + (void) dapls_modify_qp_state_to_error ( ep_ptr->qp_handle); + ep_ptr->qp_state = IB_QPS_ERROR; + + return (dapl_ib_status_convert (ib_status)); +} + +/* + * dapls_ib_optional_prv_dat + * + * Allocate space for private data to be used in CR calls + * + * Input: + * cr_ptr CR handle + * event_data data provided by the provider callback function + * cr_pp Pointer for private data + * + * Output: + * cr_pp Area + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * + */ +STATIC _INLINE_ DAT_RETURN +dapls_ib_optional_prv_dat ( + IN DAPL_CR *cr_ptr, + IN const void *event_data, + OUT DAPL_CR **cr_pp) +{ + DAT_RETURN dat_status = DAT_SUCCESS; + DAPL_PRIVATE *p_prv_data = (DAPL_PRIVATE *)event_data; + + if ( ! cr_ptr->param.private_data_size ) + { + cr_ptr->param.private_data_size = sizeof(cr_ptr->private_data); + cr_ptr->param.private_data = cr_ptr->private_data; + dapl_os_memcpy(cr_ptr->private_data, p_prv_data->private_data, cr_ptr->param.private_data_size ); + *cr_pp = (DAPL_CR *)cr_ptr->param.private_data; + } + return dat_status; +} + + +STATIC _INLINE_ int +dapls_cqe_opcode_convert (ib_work_completion_t *cqe_p) +{ + switch (((ib_work_completion_t *)cqe_p)->wc_type) + { + case IB_WC_SEND: + { + return (OP_SEND); + } + case IB_WC_RDMA_WRITE: + case IB_WC_RECV_RDMA_WRITE: + { + return (OP_RDMA_WRITE); + } + case IB_WC_RDMA_READ: + { + return (OP_RDMA_READ); + } + case IB_WC_COMPARE_SWAP: + { + return (OP_COMP_AND_SWAP); + } + case IB_WC_FETCH_ADD: + { + return (OP_FETCH_AND_ADD); + } + case IB_WC_MW_BIND: + { + return (OP_BIND_MW); + } + case IB_WC_RECV: + { + return (OP_RECEIVE); + } + default : + { + /* error */ + return (IB_ERROR); + } + } +} + +#define DAPL_GET_CQE_WRID(cqe_p) ((ib_work_completion_t *)cqe_p)->wr_id +#define DAPL_GET_CQE_OPTYPE(cqe_p) dapls_cqe_opcode_convert(cqe_p) +#define DAPL_GET_CQE_BYTESNUM(cqe_p) ((ib_work_completion_t *)cqe_p)->length +#define DAPL_GET_CQE_STATUS(cqe_p) ((ib_work_completion_t *)cqe_p)->status + +#endif /* _DAPL_IBAL_DTO_H */ diff --git a/branches/WOF2-3/ulp/dapl/dapl/ibal/dapl_ibal_kmod.h b/branches/WOF2-3/ulp/dapl/dapl/ibal/dapl_ibal_kmod.h new file mode 100644 index 00000000..114687e2 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/ibal/dapl_ibal_kmod.h @@ -0,0 +1,107 @@ + +/* + * Copyright (c) 2002, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ibal_kmod.h + * + * PURPOSE: Utility defs & routines for access to Intel IBAL APIs + * + * $Id$ + * + **********************************************************************/ + +#ifndef _DAPL_IBAL_KMOD_H_ +#define _DAPL_IBAL_KMOD_H_ + +#include +#include +#include + +#define MVDAPL_DEV_KEY 'm' +#define MVDAPL_GET_ANY_SVID _IO ( MVDAPL_DEV_KEY, psp_get_any_svid ) +#define MVDAPL_MRDB_RECORD_INSERT _IO ( MVDAPL_DEV_KEY, mrdb_record_insert ) +#define MVDAPL_MRDB_RECORD_DEC _IO ( MVDAPL_DEV_KEY, mrdb_record_dec ) +#define MVDAPL_MRDB_RECORD_QUERY _IO ( MVDAPL_DEV_KEY, mrdb_record_query ) +#define MVDAPL_MRDB_RECORD_UPDATE _IO ( MVDAPL_DEV_KEY, mrdb_record_update ) + +typedef enum +{ + psp_get_any_svid, + mrdb_record_insert, + mrdb_record_dec, + mrdb_record_query, + mrdb_record_update, + mvdapl_max_ops +} mvdapl_dev_ops_t; + +typedef struct _mvdapl_user_ctx +{ + cl_spinlock_t oust_mrdb_lock; + cl_qlist_t oust_mrdb_head; +} mvdapl_user_ctx_t; + + +typedef struct _mvdapl_ca_t +{ + cl_spinlock_t mrdb_lock; + cl_qlist_t mrdb_head; + boolean_t initialized; + cl_dev_handle_t mrdb_dev_handle; + ib_net64_t ca_guid; +} mvdapl_ca_t; + + +typedef struct _mvdapl_root +{ + ib_al_handle_t h_al; + intn_t guid_count; + mvdapl_ca_t *mvdapl_ca_tbl; + +} mvdapl_root_t; + +typedef struct _mrdb_record_t +{ + cl_list_item_t next; + ib_lmr_cookie_t key_cookie; + void *mr_handle; + int ib_shmid; + uint32_t ref_count; + boolean_t initialized; + cl_spinlock_t record_lock; +} mrdb_record_t; + + +typedef struct _oust_mrdb_rec +{ + cl_list_item_t next; + mrdb_record_t *p_record; + uint32_t ref_count; +} oust_mrdb_rec_t; + + +#endif /* _DAPL_IBAL_KMOD_H_ */ diff --git a/branches/WOF2-3/ulp/dapl/dapl/ibal/dapl_ibal_mrdb.c b/branches/WOF2-3/ulp/dapl/dapl/ibal/dapl_ibal_mrdb.c new file mode 100644 index 00000000..883dca9b --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/ibal/dapl_ibal_mrdb.c @@ -0,0 +1,408 @@ + +/* + * Copyright (c) 2002, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ibal_mrdb.c + * + * PURPOSE: Utility routines for access to IBAL APIs + * + * $Id$ + * + **********************************************************************/ + +#include "dapl.h" +#include "dapl_adapter_util.h" +#include "dapl_ibal_kmod.h" +#include "dapl_ibal_mrdb.h" + +DAT_RETURN dapls_mrdb_init ( + IN DAPL_HCA *hca_ptr) +{ + cl_status_t cl_status; + char name[32]; + dapl_ibal_ca_t *p_ca; + + p_ca = (dapl_ibal_ca_t *) hca_ptr->ib_hca_handle; + + if (p_ca == NULL) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> %s: p_ca is NULL\n","DsMI"); + return DAT_INVALID_PARAMETER; + } + + sprintf (name, + "/dev/mvdapl%x", + (uint32_t) cl_ntoh64 (p_ca->p_ca_attr->ca_guid)); + + cl_status = cl_open_device ( (cl_dev_name_t) name, &p_ca->mlnx_device); + + if (cl_status != CL_SUCCESS) + { + /* dapl_dbg_log ( DAPL_DBG_TYPE_UTIL, + "--> DsMI: Init MRDB failed = 0x%x\n", cl_status); */ + p_ca->mlnx_device = 0; + } + + return DAT_SUCCESS; +} + + +DAT_RETURN dapls_mrdb_exit ( + IN DAPL_HCA *hca_ptr) +{ + dapl_ibal_ca_t *p_ca; + + p_ca = (dapl_ibal_ca_t *) hca_ptr->ib_hca_handle; + + if (p_ca == NULL) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> %s: p_ca is NULL\n","DsME"); + return DAT_INVALID_PARAMETER; + } + + if (p_ca->mlnx_device) + { + cl_close_device (p_ca->mlnx_device); + } + + return DAT_SUCCESS; +} + + +DAT_RETURN dapls_mrdb_record_insert ( + IN DAPL_HCA *hca_ptr, + IN DAT_LMR_COOKIE shared_mem_id, + OUT int *p_ib_shmid) +{ + cl_status_t cl_status; + mrdb_rec_insert_ioctl_t ioctl_buf; + uintn_t bytes_ret; + dapl_ibal_ca_t *p_ca; + + p_ca = (dapl_ibal_ca_t *) hca_ptr->ib_hca_handle; + + if (p_ca == NULL) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> %s: p_ca is NULL\n","DsMRI"); + return DAT_INVALID_PARAMETER; + } + + bytes_ret = 0; + cl_memclr (&ioctl_buf, sizeof (ioctl_buf)); + cl_memcpy (ioctl_buf.shared_mem_id, shared_mem_id, IBAL_LMR_COOKIE_SIZE); + + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "--> DsMRI: MVDAPL_MRDB_REC_INSERT mem_cookie %p\n", + shared_mem_id); +#if defined(DAPL_DBG) + { + int i; + char *c = (char *) shared_mem_id; + + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "--> DsMRI: mem_cookie: \n"); + + for ( i = 0; i < IBAL_LMR_COOKIE_SIZE ; i++) + { + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "0x%x ", *(c+i)); + } + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, "\n"); + + } +#endif /* DAPL_DBG */ + + cl_status = cl_ioctl_device ( p_ca->mlnx_device, + MVDAPL_MRDB_RECORD_INSERT, + &ioctl_buf, + sizeof (mrdb_rec_insert_ioctl_t), + &bytes_ret); + if ((cl_status != CL_SUCCESS) || + (ioctl_buf.status == IB_INSUFFICIENT_MEMORY)) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> DsMRI: Failed to IOCTL record_insert 0x%x\n", cl_status); + return DAT_INSUFFICIENT_RESOURCES; + } + + *p_ib_shmid = (int) ioctl_buf.inout_f; + + if (ioctl_buf.status == IB_ERROR) + { + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "--> DsMRI: There is a record with shmid 0x%x\n", + *p_ib_shmid); + return DAT_INVALID_STATE; + } + else + { + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "--> DsMRI: Insert new mrdb record with shmid 0x%x\n", + *p_ib_shmid); + } + + return DAT_SUCCESS; +} + +DAT_RETURN dapls_mrdb_record_dec ( + IN DAPL_HCA *hca_ptr, + IN DAT_LMR_COOKIE shared_mem_id) +{ + cl_status_t cl_status; + mrdb_rec_dec_ioctl_t ioctl_buf; + uintn_t bytes_ret; + dapl_ibal_ca_t *p_ca; + + p_ca = (dapl_ibal_ca_t *) hca_ptr->ib_hca_handle; + + if (p_ca == NULL) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> %s: p_ca is NULL\n","DsMRD"); + return DAT_INVALID_PARAMETER; + } + + bytes_ret = 0; + cl_memclr (&ioctl_buf, sizeof (ioctl_buf)); + cl_memcpy (ioctl_buf.shared_mem_id, shared_mem_id, IBAL_LMR_COOKIE_SIZE); + + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "--> DsMRD: MVDAPL_MRDB_REC_DEC mem_cookie 0x%p\n", + shared_mem_id); +#if defined(DAPL_DBG) + { + int i; + char *c = (char *) shared_mem_id; + + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "--> DsMRD: mem_cookie: \n"); + + for ( i = 0; i < IBAL_LMR_COOKIE_SIZE ; i++) + { + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "0x%x ", *(c+i)); + } + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, "\n"); + + } +#endif /* DAPL_DBG */ + + cl_status = cl_ioctl_device ( p_ca->mlnx_device, + MVDAPL_MRDB_RECORD_DEC, + &ioctl_buf, + sizeof (mrdb_rec_dec_ioctl_t), + &bytes_ret); + if ((cl_status != CL_SUCCESS) || + (ioctl_buf.status != IB_SUCCESS)) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> DsMRD: IOCTL failed 'cause there is no record %s\n", + ib_get_err_str(ioctl_buf.status)); + return DAT_INVALID_STATE; + } + + return DAT_SUCCESS; +} + +DAT_RETURN dapls_mrdb_record_update ( + IN DAPL_HCA *hca_ptr, + IN DAT_LMR_COOKIE shared_mem_id, + IN struct _ib_mr* mr_handle) +{ + cl_status_t cl_status; + mrdb_rec_update_ioctl_t ioctl_buf; + uintn_t bytes_ret; + dapl_ibal_ca_t *p_ca; + + p_ca = (dapl_ibal_ca_t *) hca_ptr->ib_hca_handle; + + if (p_ca == NULL) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> %s: p_ca is NULL\n","DsMRU"); + return DAT_INVALID_PARAMETER; + } + + bytes_ret = 0; + cl_memclr (&ioctl_buf, sizeof (ioctl_buf)); + cl_memcpy (ioctl_buf.shared_mem_id, shared_mem_id, IBAL_LMR_COOKIE_SIZE); + ioctl_buf.mr_handle = mr_handle; + + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "--> DsMRU: MVDAPL_MRDB_REC_UPDATE mr_handle %p\n", mr_handle); +#if defined(DAPL_DBG) + { + int i; + char *c = (char *) shared_mem_id; + + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "--> DsMRU: mem_cookie: \n"); + + for ( i = 0; i < IBAL_LMR_COOKIE_SIZE ; i++) + { + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "0x%x ", *(c+i)); + } + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, "\n"); + + } +#endif /* DAPL_DBG */ + + cl_status = cl_ioctl_device ( p_ca->mlnx_device, + MVDAPL_MRDB_RECORD_UPDATE, + &ioctl_buf, + sizeof (mrdb_rec_update_ioctl_t), + &bytes_ret); + if ((cl_status != CL_SUCCESS) || + (ioctl_buf.status != IB_SUCCESS)) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> DsMRU: IOCTL update_record failed %s\n", + ib_get_err_str(ioctl_buf.status)); + return DAT_INTERNAL_ERROR; + } + + return DAT_SUCCESS; +} + + +DAT_RETURN dapls_mrdb_record_query ( + IN DAPL_HCA *hca_ptr, + IN DAT_LMR_COOKIE shared_mem_id, + OUT int *p_ib_shmid, + OUT struct _ib_mr* *p_mr_handle) +{ + cl_status_t cl_status; + mrdb_rec_query_ioctl_t ioctl_buf; + uintn_t bytes_ret; + dapl_ibal_ca_t *p_ca; + + p_ca = (dapl_ibal_ca_t *) hca_ptr->ib_hca_handle; + + if (p_ca == NULL) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> %s: p_ca is NULL\n","DsMRQ"); + return DAT_INVALID_PARAMETER; + } + + bytes_ret = 0; + cl_memclr (&ioctl_buf, sizeof (ioctl_buf)); + + cl_memcpy (ioctl_buf.shared_mem_id, shared_mem_id, IBAL_LMR_COOKIE_SIZE); + + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "--> DsMRQ: MVDAPL_MRDB_REC_QUERY mem_cookie 0x%p\n", + shared_mem_id); + #if defined(DAPL_DBG) + { + int i; + char *c = (char *) shared_mem_id; + + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "--> DsMRQ: mem_cookie: \n"); + + for ( i = 0; i < IBAL_LMR_COOKIE_SIZE ; i++) + { + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "0x%x ", *(c+i)); + } + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, "\n"); + + } + #endif + + cl_status = cl_ioctl_device ( p_ca->mlnx_device, + MVDAPL_MRDB_RECORD_QUERY, + &ioctl_buf, + sizeof (mrdb_rec_query_ioctl_t), + &bytes_ret); + if ((cl_status != CL_SUCCESS) || + (ioctl_buf.status != IB_SUCCESS)) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> DsMRQ: IOCTL query_record failed %s\n", + ib_get_err_str(ioctl_buf.status)); + return DAT_INTERNAL_ERROR; + } + + *p_mr_handle = ioctl_buf.mr_handle; + *p_ib_shmid = (int) ioctl_buf.inout_f; + + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "--> DsMRQ: MVDAPL_MRDB_REC_QUERY mr_handle 0x%p shmid 0x%x\n", + *p_mr_handle, *p_ib_shmid); + + return DAT_SUCCESS; +} + + +DAT_RETURN dapls_ib_get_any_svid ( + IN DAPL_HCA *hca_ptr, + OUT DAT_CONN_QUAL *p_svid) +{ + cl_status_t cl_status; + psp_get_any_svid_ioctl_t ioctl_buf; + uintn_t bytes_ret; + dapl_ibal_ca_t *p_ca; + + p_ca = (dapl_ibal_ca_t *) hca_ptr->ib_hca_handle; + + if (p_ca == NULL) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> %s: p_ca is NULL\n","DsPGAS"); + return DAT_INVALID_PARAMETER; + } + + bytes_ret = 0; + cl_memclr (&ioctl_buf, sizeof (ioctl_buf)); + + cl_status = cl_ioctl_device ( p_ca->mlnx_device, + MVDAPL_GET_ANY_SVID, + &ioctl_buf, + sizeof (psp_get_any_svid_ioctl_t), + &bytes_ret); + if ((cl_status != CL_SUCCESS) || + (ioctl_buf.status != IB_SUCCESS)) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> DsMRQ: IOCTL query_record failed %s\n", + ib_get_err_str(ioctl_buf.status)); + return DAT_INTERNAL_ERROR; + } + + *p_svid = (DAT_CONN_QUAL) ioctl_buf.inout_f; + + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "--> DsPGAS: new ServiceID 0x%x\n", + *p_svid); + + return DAT_SUCCESS; +} + + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ + diff --git a/branches/WOF2-3/ulp/dapl/dapl/ibal/dapl_ibal_mrdb.h b/branches/WOF2-3/ulp/dapl/dapl/ibal/dapl_ibal_mrdb.h new file mode 100644 index 00000000..c0a94e56 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/ibal/dapl_ibal_mrdb.h @@ -0,0 +1,68 @@ + +/* + * Copyright (c) 2002, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ibal_mrdb.h + * + * PURPOSE: Utility defs & routines for access to Intel IBAL APIs + * + * $Id$ + * + **********************************************************************/ + +#ifndef _DAPL_IBAL_MRDB_H_ +#define _DAPL_IBAL_MRDB_H_ + +#include +#include + +#define MVDAPL_BASE_SHMID 0xF00 +#define MVDAPL_BASE_SVID 0xF +#define MVDAPL_MAX_SHMID 0xFFFFFFFF +#define MVDAPL_MAX_SVID 0xEFFFFFFF + +#define IBAL_LMR_COOKIE_SIZE 40 +typedef char (* ib_lmr_cookie_t)[IBAL_LMR_COOKIE_SIZE]; + +typedef struct _mrdb_record_ioctl +{ + char *shared_mem_id[IBAL_LMR_COOKIE_SIZE]; + void *mr_handle; + ib_net64_t inout_f; + ib_api_status_t status; +} mrdb_record_ioctl_t; + +typedef mrdb_record_ioctl_t mrdb_rec_dec_ioctl_t; +typedef mrdb_record_ioctl_t mrdb_rec_insert_ioctl_t; +typedef mrdb_record_ioctl_t mrdb_rec_query_ioctl_t; +typedef mrdb_record_ioctl_t mrdb_rec_update_ioctl_t; +typedef mrdb_record_ioctl_t psp_get_any_svid_ioctl_t; + + +#endif /* _DAPL_IBAL_MRDB_H_ */ + diff --git a/branches/WOF2-3/ulp/dapl/dapl/ibal/dapl_ibal_qp.c b/branches/WOF2-3/ulp/dapl/dapl/ibal/dapl_ibal_qp.c new file mode 100644 index 00000000..09510278 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/ibal/dapl_ibal_qp.c @@ -0,0 +1,698 @@ + +/* + * Copyright (c) 2002, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ibal_qp.c + * + * PURPOSE: IB QP routines for access to IBAL APIs + * + * $Id$ + * + **********************************************************************/ + +#include "dapl.h" +#include "dapl_adapter_util.h" +#include "dapl_evd_util.h" +#include "dapl_ibal_util.h" + +#define DAPL_IBAL_QKEY 0 +#define DAPL_IBAL_START_PSN 0 + +static void +dapli_ib_qp_async_error_cb( + IN ib_async_event_rec_t* p_err_rec ) +{ + DAPL_EP *ep_ptr = (DAPL_EP *)p_err_rec->context; + DAPL_EVD *evd_ptr; + DAPL_IA *ia_ptr; + dapl_ibal_ca_t *p_ca; + dapl_ibal_evd_cb_t *evd_cb; + + dapl_dbg_log (DAPL_DBG_TYPE_ERR,"--> DiQpAEC QP error %d for qp context %p\n", + p_err_rec->code, p_err_rec->context); + dapl_dbg_log (DAPL_DBG_TYPE_ERR,"--> DiQpAEC qp_handle %p qpn %u\n", + ((DAPL_EP *)p_err_rec->context)->qp_handle, + ((DAPL_EP *)p_err_rec->context)->qpn); + + /* + * Verify handles EP, EVD, and hca_handle + */ + if ( DAPL_BAD_HANDLE (ep_ptr, DAPL_MAGIC_EP ) || + DAPL_BAD_HANDLE (ep_ptr->param.connect_evd_handle, DAPL_MAGIC_EVD) ) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR,"--> DiQpAEC: invalid EP %p \n", ep_ptr); + return; + } + ia_ptr = ep_ptr->header.owner_ia; + evd_ptr = ia_ptr->async_error_evd; + + if (DAPL_BAD_HANDLE (evd_ptr, DAPL_MAGIC_EVD) || + ! (evd_ptr->evd_flags & DAT_EVD_ASYNC_FLAG)) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR,"--> DiQpAEC: invalid EVD %p \n", evd_ptr); + return; + } + p_ca = (dapl_ibal_ca_t *) ia_ptr->hca_ptr->ib_hca_handle; + if (p_ca == NULL) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR,"--> DiQpAEC: can't find %s HCA\n", + (ia_ptr->header.provider)->device_name); + return; + } + + /* find QP error callback using ia_ptr for context */ + evd_cb = dapli_find_evd_cb_by_context (ia_ptr, p_ca); + if ((evd_cb == NULL) || (evd_cb->pfn_async_qp_err_cb == NULL)) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR,"--> DiQpAEC: no ERROR cb on %p found \n", p_ca); + return; + } + + dapl_os_lock (&ep_ptr->header.lock); + ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECT_PENDING; + dapl_os_unlock (&ep_ptr->header.lock); + + /* force disconnect, QP error state, to insure DTO's get flushed */ + dapls_ib_disconnect ( ep_ptr, DAT_CLOSE_ABRUPT_FLAG ); + + /* maps to dapl_evd_qp_async_error_callback(), context is EP */ + evd_cb->pfn_async_qp_err_cb( (ib_hca_handle_t)p_ca, + (ib_error_record_t*)&p_err_rec->code, ep_ptr); +} + +/* + * dapl_ib_qp_alloc + * + * Alloc a QP + * + * Input: + * *ia_ptr pointer to DAPL IA + * *ep_ptr pointer to DAPL EP + * *ep_ctx_ptr pointer to DAPL EP context + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * + */ +DAT_RETURN +dapls_ib_qp_alloc ( + IN DAPL_IA *ia_ptr, + IN DAPL_EP *ep_ptr, + IN DAPL_EP *ep_ctx_ptr) +{ + DAT_EP_ATTR *attr; + DAPL_EVD *recv_evd_ptr, *request_evd_ptr; + DAT_RETURN dat_status; + ib_api_status_t ib_status; + ib_qp_create_t qp_create; + ib_pd_handle_t ib_pd_handle; + ib_cq_handle_t cq_recv; + ib_cq_handle_t cq_send; + dapl_ibal_ca_t *p_ca; + dapl_ibal_port_t *p_active_port; + ib_qp_attr_t qp_attr; + + attr = &ep_ptr->param.ep_attr; + + dapl_os_assert ( ep_ptr->param.pz_handle != NULL ); + + ib_pd_handle = ((DAPL_PZ *)ep_ptr->param.pz_handle)->pd_handle; + recv_evd_ptr = (DAPL_EVD *) ep_ptr->param.recv_evd_handle; + request_evd_ptr = (DAPL_EVD *) ep_ptr->param.request_evd_handle; + + cq_recv = IB_INVALID_HANDLE; + cq_send = IB_INVALID_HANDLE; + + dapl_os_assert ( recv_evd_ptr != DAT_HANDLE_NULL ); + { + cq_recv = (ib_cq_handle_t) recv_evd_ptr->ib_cq_handle; + + if ((cq_recv == IB_INVALID_HANDLE) && + ( 0 != (recv_evd_ptr->evd_flags & ~DAT_EVD_SOFTWARE_FLAG) )) + { + dat_status = dapls_ib_cq_late_alloc ( + ib_pd_handle, + recv_evd_ptr); + if (dat_status != DAT_SUCCESS) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> %s: failed to create CQ\n","DsQA"); + return (dat_status); + } + + dat_status = dapls_set_cq_notify (ia_ptr, recv_evd_ptr); + + if (dat_status != DAT_SUCCESS) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> %s: failed to enable notify CQ\n","DsQA"); + return (dat_status); + } + + cq_recv = (ib_cq_handle_t) recv_evd_ptr->ib_cq_handle; + dapl_dbg_log (DAPL_DBG_TYPE_EP, + "--> DsQA: alloc_recv_CQ = %p\n", cq_recv); + + } + } + + dapl_os_assert ( request_evd_ptr != DAT_HANDLE_NULL ); + { + cq_send = (ib_cq_handle_t) request_evd_ptr->ib_cq_handle; + + if ((cq_send == IB_INVALID_HANDLE) && + ( 0 != (request_evd_ptr->evd_flags & ~DAT_EVD_SOFTWARE_FLAG) )) + { + dat_status = dapls_ib_cq_late_alloc ( + ib_pd_handle, + request_evd_ptr); + if (dat_status != DAT_SUCCESS) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> %s: failed to create CQ\n","DsQA"); + return (dat_status); + } + + dat_status = dapls_set_cq_notify (ia_ptr, request_evd_ptr); + + if (dat_status != DAT_SUCCESS) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> %s: failed to enable notify CQ\n","DsQA"); + return (dat_status); + } + + cq_send = (ib_cq_handle_t) request_evd_ptr->ib_cq_handle; + dapl_dbg_log (DAPL_DBG_TYPE_EP, + "--> DsQA: alloc_send_CQ = %p\n", cq_send); + } + } + + /* + * Get the CA structure + */ + p_ca = (dapl_ibal_ca_t *) ia_ptr->hca_ptr->ib_hca_handle; + + dapl_os_memzero (&qp_create, sizeof (qp_create)); + qp_create.qp_type = IB_QPT_RELIABLE_CONN; + qp_create.sq_depth = attr->max_request_dtos; + qp_create.rq_depth = attr->max_recv_dtos; + qp_create.sq_sge = attr->max_recv_iov; + qp_create.rq_sge = attr->max_request_iov; + qp_create.h_sq_cq = cq_send; + qp_create.h_rq_cq = cq_recv; + qp_create.sq_signaled = FALSE; + + dapl_dbg_log (DAPL_DBG_TYPE_EP, + "--> DsQA: sqd,iov=%d,%d rqd,iov=%d,%d\n", + attr->max_request_dtos, attr->max_request_iov, + attr->max_recv_dtos, attr->max_recv_iov); + + ib_status = ib_create_qp ( + ib_pd_handle, + &qp_create, + (void *) ep_ctx_ptr /* context */, + dapli_ib_qp_async_error_cb, + &ep_ptr->qp_handle); + + if (ib_status != IB_SUCCESS) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "--> DsQA: Create QP failed = %s\n", ib_get_err_str(ib_status)); + return (DAT_INSUFFICIENT_RESOURCES); + } + + dapl_dbg_log (DAPL_DBG_TYPE_EP, + "--> DsQA: EP=%p, tEVD=%p, rEVD=%p QP=%p\n", + ep_ptr, ep_ptr->param.request_evd_handle, + ep_ptr->param.recv_evd_handle, + ep_ptr->qp_handle ); + + ep_ptr->qp_state = IB_QPS_RESET; + + p_active_port = dapli_ibal_get_port ( p_ca, (uint8_t)ia_ptr->hca_ptr->port_num ); + + if (NULL == p_active_port) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> DsQA: Port %d is not available = %d\n", + ia_ptr->hca_ptr->port_num, __LINE__); + return (DAT_INVALID_STATE); + } + + ib_status = dapls_modify_qp_state_to_init ( + ep_ptr->qp_handle, + &ep_ptr->param.ep_attr, p_active_port); + + if ( ib_status != IB_SUCCESS ) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> DsQA: Change QP state to INIT failed = %s\n", + ib_get_err_str(ib_status)); + return (DAT_INVALID_HANDLE); + } + ib_status = ib_query_qp ( ep_ptr->qp_handle, &qp_attr ); + + ep_ptr->qp_state = qp_attr.state; + ep_ptr->qpn = qp_attr.num; + + dapl_dbg_log (DAPL_DBG_TYPE_EP, + "--> DsQAQA: EP:%p new_QP = %p state = %#x\n", ep_ptr, ep_ptr->qp_handle, ep_ptr->qp_state); + + return (DAT_SUCCESS); +} + + +/* + * dapl_ib_qp_free + * + * Free a QP + * + * Input: + * *ia_ptr pointer to IA structure + * *ep_ptr pointer to EP structure + * + * Output: + * none + * + * Returns: + * none + * + */ +DAT_RETURN +dapls_ib_qp_free ( + IN DAPL_IA *ia_ptr, + IN DAPL_EP *ep_ptr ) +{ + + ib_qp_handle_t qp_handle; + UNREFERENCED_PARAMETER(ia_ptr); + + dapl_dbg_log (DAPL_DBG_TYPE_EP, + "--> DsQF: free %p, state=%d\n", + ep_ptr->qp_handle,ep_ptr->qp_state ); + + if (( ep_ptr->qp_handle != IB_INVALID_HANDLE ) && + ( ep_ptr->qp_state != DAPL_QP_STATE_UNATTACHED )) + { + qp_handle = ep_ptr->qp_handle; + ep_ptr->qp_handle = IB_INVALID_HANDLE; + ep_ptr->qp_state = DAPL_QP_STATE_UNATTACHED; + ib_destroy_qp ( qp_handle, NULL /* callback */); + dapl_dbg_log (DAPL_DBG_TYPE_EP, + "--> DsQF: freed QP %p\n", qp_handle ); + } + + return DAT_SUCCESS; +} + + +/* + * dapl_ib_qp_modify + * + * Set the QP to the parameters specified in an EP_PARAM + * + * We can't be sure what state the QP is in so we first obtain the state + * from the driver. The EP_PARAM structure that is provided has been + * sanitized such that only non-zero values are valid. + * + * Input: + * *ia_ptr pointer to DAPL IA + * *ep_ptr pointer to DAPL EP + * *ep_attr pointer to DAT EP attribute + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + * + */ +DAT_RETURN +dapls_ib_qp_modify ( + IN DAPL_IA *ia_ptr, + IN DAPL_EP *ep_ptr, + IN DAT_EP_ATTR *ep_attr ) +{ + ib_qp_attr_t qp_attr; + ib_api_status_t ib_status; + ib_qp_handle_t qp_handle; + ib_qp_state_t qp_state; + ib_qp_mod_t qp_mod; + ib_av_attr_t *p_av_attr; + ib_qp_opts_t *p_qp_opts; + uint32_t *p_sq_depth, *p_rq_depth; + DAT_BOOLEAN need_modify; + DAT_RETURN dat_status; + + qp_handle = ep_ptr->qp_handle; + need_modify = DAT_FALSE; + dat_status = DAT_SUCCESS; + if ( ia_ptr == NULL || ia_ptr->header.magic != DAPL_MAGIC_IA ) + { + dat_status = DAT_INVALID_HANDLE; + goto bail; + } + /* + * Query the QP to get the current state */ + ib_status = ib_query_qp ( qp_handle, &qp_attr ); + + if ( ib_status != IB_SUCCESS ) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> DsIQM: Query QP failed = %s\n", ib_get_err_str(ib_status)); + dat_status = DAT_INTERNAL_ERROR; + goto bail; + } + + qp_state = qp_attr.state; + + dapl_dbg_log (DAPL_DBG_TYPE_EP, + "--> DsIQM: modify qp state=%d\n",qp_state); + /* + * Check if we have the right qp_state or not + */ + if ( (qp_state != IB_QPS_RTR ) && + (qp_state != IB_QPS_RTS ) ) + { + dapl_dbg_log (DAPL_DBG_TYPE_EP, + "--> DsIQM: postpone to modify qp to EP values later\n"); + dat_status = DAT_SUCCESS; + goto bail; + } + + dapl_os_memzero (&qp_mod, sizeof (ib_qp_mod_t)); + + if (qp_state == IB_QPS_RTR) + { + p_av_attr = &qp_mod.state.rtr.primary_av; + p_qp_opts = &qp_mod.state.rtr.opts; + p_sq_depth = &qp_mod.state.rtr.sq_depth; + p_rq_depth = &qp_mod.state.rtr.rq_depth; + } + else + { + /* + * RTS does not have primary_av field + */ + p_av_attr = &qp_mod.state.rts.alternate_av; + p_qp_opts = &qp_mod.state.rts.opts; + p_sq_depth = &qp_mod.state.rts.sq_depth; + p_rq_depth = &qp_mod.state.rts.rq_depth; + } + + if ( (ep_attr->max_recv_dtos > 0) && + ((DAT_UINT32)ep_attr->max_recv_dtos != qp_attr.rq_depth) ) + { + dapl_dbg_log (DAPL_DBG_TYPE_EP, + "--> DsIQM: rq_depth modified (%d,%d)\n", + qp_attr.rq_depth, ep_attr->max_recv_dtos); + + *p_rq_depth = ep_attr->max_recv_dtos; + *p_qp_opts |= IB_MOD_QP_RQ_DEPTH; + need_modify = DAT_TRUE; + } + + if ( (ep_attr->max_request_dtos > 0) && + ((DAT_UINT32)ep_attr->max_request_dtos != qp_attr.sq_depth) ) + { + dapl_dbg_log (DAPL_DBG_TYPE_EP, + "--> DsIQM: sq_depth modified (%d,%d)\n", + qp_attr.sq_depth, ep_attr->max_request_dtos); + + *p_sq_depth = ep_attr->max_request_dtos; + *p_qp_opts |= IB_MOD_QP_SQ_DEPTH; + need_modify = DAT_TRUE; + } + + qp_mod.req_state = qp_state; + + if ( need_modify == DAT_TRUE ) + { + ib_status = ib_modify_qp (qp_handle, &qp_mod); + + if ( ib_status != IB_SUCCESS) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> %s: ib_status = %d\n", "DsIQM", ib_status); + dat_status = DAT_INTERNAL_ERROR; + } + } + +bail: + + return dat_status; +} + + +ib_api_status_t +dapls_modify_qp_state_to_error ( + ib_qp_handle_t qp_handle ) +{ + ib_qp_mod_t qp_mod; + ib_api_status_t ib_status; + + dapl_dbg_log (DAPL_DBG_TYPE_WARN, + "--> DsIQM_ERR: QP state change\n"); + + dapl_os_memzero (&qp_mod, sizeof (ib_qp_mod_t)); + + qp_mod.req_state = IB_QPS_ERROR; + + ib_status = ib_modify_qp (qp_handle, &qp_mod); + + return (ib_status); +} + + +ib_api_status_t +dapls_modify_qp_state_to_reset ( + ib_qp_handle_t qp_handle ) +{ + ib_qp_mod_t qp_mod; + ib_api_status_t ib_status; + + dapl_dbg_log (DAPL_DBG_TYPE_EP, + "--> DsIQM_RESET: QP state change\n"); + + dapl_os_memzero (&qp_mod, sizeof (ib_qp_mod_t)); + + qp_mod.req_state = IB_QPS_RESET; + + ib_status = ib_modify_qp (qp_handle, &qp_mod); + + return (ib_status); +} + + +ib_api_status_t +dapls_modify_qp_state_to_init ( + IN ib_qp_handle_t qp_handle, + IN DAT_EP_ATTR *p_attr, + IN dapl_ibal_port_t *p_port ) +{ + ib_qp_mod_t qp_mod; + ib_api_status_t ib_status; + + dapl_dbg_log (DAPL_DBG_TYPE_EP, + "--> DsIQM_INIT: QP state change\n"); + + dapl_os_memzero (&qp_mod, sizeof (ib_qp_mod_t)); + + qp_mod.req_state = IB_QPS_INIT; + qp_mod.state.init.primary_port = p_port->p_attr->port_num; + qp_mod.state.init.qkey = DAPL_IBAL_QKEY; + qp_mod.state.init.pkey_index = 0; + qp_mod.state.init.access_ctrl = + IB_AC_LOCAL_WRITE|IB_AC_RDMA_WRITE|IB_AC_MW_BIND; + if ((p_attr->max_rdma_read_in > 0) || + (p_attr->max_rdma_read_out > 0)) + { + qp_mod.state.init.access_ctrl |= IB_AC_RDMA_READ; + } + ib_status = ib_modify_qp (qp_handle, &qp_mod); + + return (ib_status); +} + +ib_api_status_t +dapls_modify_qp_state_to_rtr ( + ib_qp_handle_t qp_handle, + ib_net32_t dest_qp, + ib_lid_t dest_lid, + dapl_ibal_port_t *p_port) +{ + ib_qp_mod_t qp_mod; + ib_api_status_t ib_status; + + dapl_dbg_log (DAPL_DBG_TYPE_EP, + "--> DsIQM_RTR: QP state change\n"); + + dapl_os_memzero (&qp_mod, sizeof (ib_qp_mod_t)); + + qp_mod.req_state = IB_QPS_RTR; + qp_mod.state.rtr.rq_psn = DAPL_IBAL_START_PSN; + qp_mod.state.rtr.dest_qp = dest_qp; + qp_mod.state.rtr.resp_res = 4; // in-flight RDMAs + qp_mod.state.rtr.rnr_nak_timeout = IB_RNR_NAK_TIMEOUT; + qp_mod.state.rtr.primary_av.sl = 0; + qp_mod.state.rtr.primary_av.dlid = dest_lid; + qp_mod.state.rtr.primary_av.port_num = p_port->p_attr->port_num; + qp_mod.state.rtr.primary_av.grh_valid = 0; /* FALSE */ + qp_mod.state.rtr.primary_av.path_bits = 0; + qp_mod.state.rtr.primary_av.static_rate = IB_PATH_RECORD_RATE_10_GBS; + qp_mod.state.rtr.primary_av.conn.path_mtu = p_port->p_attr->mtu; + qp_mod.state.rtr.primary_av.conn.rnr_retry_cnt = IB_RNR_RETRY_CNT; + qp_mod.state.rtr.primary_av.conn.local_ack_timeout = 7; + qp_mod.state.rtr.primary_av.conn.seq_err_retry_cnt = 7; + + qp_mod.state.rtr.opts = IB_MOD_QP_PRIMARY_AV | IB_MOD_QP_RESP_RES; + + ib_status = ib_modify_qp (qp_handle, &qp_mod); + + return (ib_status); +} + +ib_api_status_t +dapls_modify_qp_state_to_rts ( + ib_qp_handle_t qp_handle ) +{ + ib_qp_mod_t qp_mod; + ib_api_status_t ib_status; + + dapl_dbg_log (DAPL_DBG_TYPE_EP, + "--> DsIQM_RTS: QP state change\n"); + + dapl_os_memzero (&qp_mod, sizeof (ib_qp_mod_t)); + + qp_mod.req_state = IB_QPS_RTS; + qp_mod.state.rts.sq_psn = DAPL_IBAL_START_PSN; + qp_mod.state.rts.retry_cnt = 7; + /* see dapl_ibal_util.h for IB_RNR_XXX */ + qp_mod.state.rts.rnr_retry_cnt = IB_RNR_RETRY_CNT; + qp_mod.state.rts.rnr_nak_timeout = IB_RNR_NAK_TIMEOUT; + qp_mod.state.rts.local_ack_timeout = 7; + qp_mod.state.rts.init_depth = 4; + + ib_status = ib_modify_qp (qp_handle, &qp_mod); + + return (ib_status); +} + + +/* + * dapls_ib_reinit_ep + * + * Move the QP to INIT state again. + * + * Input: + * ep_ptr DAPL_EP + * + * Output: + * none + * + * Returns: + * void + * + */ +DAT_RETURN +dapls_ib_reinit_ep ( + IN DAPL_EP *ep_ptr) +{ + DAPL_IA *ia_ptr; + ib_api_status_t ib_status; + dapl_ibal_ca_t *p_ca; + dapl_ibal_port_t *p_active_port; + + dapl_dbg_log (DAPL_DBG_TYPE_EP, + "--> DsIQM_REINIT: EP(%p) QP(%p) state change\n", + ep_ptr, ep_ptr->qp_handle ); + + if ( ep_ptr->param.ep_state != DAT_EP_STATE_DISCONNECTED ) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR,"--> DsIRE: EP invalid state(%d)\n", ep_ptr->param.ep_state); + return DAT_INVALID_STATE; + } + + ia_ptr = ep_ptr->header.owner_ia; + + /* Re-create QP if cleaned up, alloc will return init state */ + if ( ep_ptr->qp_handle == IB_INVALID_HANDLE ) + { + dapl_dbg_log (DAPL_DBG_TYPE_EP, + "--> DsIRE: !EP(%p)->qp_handle, re-create QP\n",ep_ptr); + return ( dapls_ib_qp_alloc ( ia_ptr, ep_ptr, ep_ptr ) ); + } + + ib_status = dapls_modify_qp_state_to_reset ( ep_ptr->qp_handle); + + if ( ib_status != IB_SUCCESS ) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR,"--> DsIRE: failed to move qp to RESET status = %s\n", + ib_get_err_str(ib_status)); + return DAT_INTERNAL_ERROR; + } + + ep_ptr->qp_state = IB_QPS_RESET; + + p_ca = (dapl_ibal_ca_t *) ia_ptr->hca_ptr->ib_hca_handle; + p_active_port = dapli_ibal_get_port ( p_ca, (uint8_t)ia_ptr->hca_ptr->port_num ); + + if (NULL == p_active_port) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR,"--> DsIRE: Port %d is not available = %d\n", + ia_ptr->hca_ptr->port_num, __LINE__); + return DAT_INTERNAL_ERROR; + } + + /* May fail if QP still RESET and in timewait, keep in reset state */ + ib_status = dapls_modify_qp_state_to_init ( ep_ptr->qp_handle, + &ep_ptr->param.ep_attr, + p_active_port); + if ( ib_status != IB_SUCCESS ) + { + ep_ptr->qp_state = IB_QPS_RESET; + + dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> DsIRE: failed to move qp to INIT status = %s\n", + ib_get_err_str(ib_status)); + return DAT_INTERNAL_ERROR; + } + + ep_ptr->qp_state = IB_QPS_INIT; + + return DAT_SUCCESS; + +} + + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ + diff --git a/branches/WOF2-3/ulp/dapl/dapl/ibal/dapl_ibal_util.c b/branches/WOF2-3/ulp/dapl/dapl/ibal/dapl_ibal_util.c new file mode 100644 index 00000000..f409a85e --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/ibal/dapl_ibal_util.c @@ -0,0 +1,2515 @@ + +/* + * Copyright (c) 2002, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ibal_util.c + * + * PURPOSE: Utility routines for access to IBAL APIs + * + * $Id$ + * + **********************************************************************/ + +#include "dapl.h" +#include "dapl_adapter_util.h" +#include "dapl_evd_util.h" +#include "dapl_cr_util.h" +#include "dapl_lmr_util.h" +#include "dapl_rmr_util.h" +#include "dapl_cookie.h" +#include "dapl_ring_buffer_util.h" + +#ifndef NO_NAME_SERVICE +#include "dapl_name_service.h" +#endif /* NO_NAME_SERVICE */ + +#define DAPL_IBAL_MAX_CA 4 +#define DAT_ADAPTER_NAME "InfiniHost (Tavor)" +#define DAT_VENDOR_NAME "Mellanox Technolgy Inc." + +/* + * Root data structure for DAPL_IIBA. + */ +dapl_ibal_root_t dapl_ibal_root; +DAPL_HCA_NAME dapl_ibal_hca_name_array [DAPL_IBAL_MAX_CA] = + {"IbalHca0", "IbalHca1", "IbalHca2", "IbalHca3"}; +ib_net64_t *gp_ibal_ca_guid_tbl = NULL; + +/* + * DAT spec does not tie max_mtu_size with IB MTU + * +static ib_net32_t dapl_ibal_mtu_table[6] = {0, 256, 512, 1024, 2048, 4096}; + */ + +int g_loopback_connection = 0; + + +static cl_status_t +dapli_init_root_ca_list( + IN dapl_ibal_root_t *root ) +{ + cl_status_t status; + + cl_qlist_init (&root->ca_head); + status = cl_spinlock_init (&root->ca_lock); + + if (status == CL_SUCCESS) + { + /* + * Get the time ready to go but don't start here + */ + root->shutdown = FALSE; + root->initialized = TRUE; + } + else + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, "--> DiIRCL: cl_spinlock_init returned %d\n", status); + root->initialized = FALSE; + } + + root->h_al = NULL; + + return (status); +} + + +static cl_status_t +dapli_destroy_root_ca_list( + IN dapl_ibal_root_t *root ) +{ + + root->initialized = FALSE; + + /* + * At this point the lock should not be necessary + */ + if (!cl_is_qlist_empty (&root->ca_head) ) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, "--> Destroying nonempty ca list (%s)\n", + "DiDRCL"); + } + cl_spinlock_destroy (&root->ca_lock); + + return CL_SUCCESS; +} + + +static void +dapli_shutdown_port_access( + IN dapl_ibal_ca_t *ca ) +{ + dapl_ibal_port_t *p_port; + + TAKE_LOCK( ca->port_lock ); + { + while ( ! cl_is_qlist_empty( &ca->port_head ) ) + { + p_port = (dapl_ibal_port_t *)cl_qlist_remove_head( &ca->port_head ); + RELEASE_LOCK( ca->port_lock ); + { + REMOVE_REFERENCE( &p_port->refs ); + REMOVE_REFERENCE( &p_port->ca->refs ); + + dapl_os_free (p_port, sizeof (dapl_ibal_port_t)); + } + TAKE_LOCK( ca->port_lock ); + } + } + RELEASE_LOCK( ca->port_lock ); +} + + +static void dapli_shutdown_ca_access (void) +{ + dapl_ibal_ca_t *ca; + + if ( dapl_ibal_root.initialized == FALSE ) + { + goto destroy_root; + } + + TAKE_LOCK (dapl_ibal_root.ca_lock); + { + while ( ! cl_is_qlist_empty (&dapl_ibal_root.ca_head) ) + { + ca = (dapl_ibal_ca_t *) cl_qlist_remove_head (&dapl_ibal_root.ca_head); + + if (ca->p_ca_attr) + { + dapl_os_free (ca->p_ca_attr, sizeof (ib_ca_attr_t)); + } + + + RELEASE_LOCK (dapl_ibal_root.ca_lock); + { + dapli_shutdown_port_access (ca); + REMOVE_REFERENCE (&ca->refs); + } + TAKE_LOCK (dapl_ibal_root.ca_lock); + } + } + RELEASE_LOCK (dapl_ibal_root.ca_lock); + +destroy_root: + /* + * Destroy the root CA list and list lock + */ + dapli_destroy_root_ca_list (&dapl_ibal_root); + + /* + * Signal we're all done and wake any waiter + */ + dapl_ibal_root.shutdown = FALSE; +} + + +dapl_ibal_evd_cb_t * +dapli_find_evd_cb_by_context( + IN void *context, + IN dapl_ibal_ca_t *ca) +{ + dapl_ibal_evd_cb_t *evd_cb = NULL; + + TAKE_LOCK( ca->evd_cb_lock ); + + evd_cb = (dapl_ibal_evd_cb_t *) cl_qlist_head( &ca->evd_cb_head ); + while ( &evd_cb->next != cl_qlist_end( &ca->evd_cb_head ) ) + { + if ( context == evd_cb->context) + { + goto found; + } + + /* + * Try again + */ + evd_cb = (dapl_ibal_evd_cb_t *) cl_qlist_next( &evd_cb->next ); + } + /* + * No joy + */ + evd_cb = NULL; + +found: + + RELEASE_LOCK( ca->evd_cb_lock ); + + return ( evd_cb ); +} + + +static cl_status_t +dapli_init_ca_evd_cb_list( + IN dapl_ibal_ca_t *ca ) +{ + cl_status_t status; + + cl_qlist_init( &ca->evd_cb_head ); + status = cl_spinlock_init( &ca->evd_cb_lock ); + if ( status != CL_SUCCESS ) + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, "--> DiICECL: cl_spinlock_init returned %d\n", status); + return ( status ); +} + + +static cl_status_t +dapli_init_ca_port_list( + IN dapl_ibal_ca_t *ca ) +{ + cl_status_t status; + + cl_qlist_init( &ca->port_head ); + status = cl_spinlock_init( &ca->port_lock ); + if ( status != CL_SUCCESS ) + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, "--> DiICPL: cl_spinlock_init returned %d\n", status); + return ( status ); +} + +dapl_ibal_port_t * +dapli_ibal_get_port ( + IN dapl_ibal_ca_t *p_ca, + IN uint8_t port_num) +{ + cl_list_item_t *p_active_port = NULL; + + TAKE_LOCK (p_ca->port_lock); + for ( p_active_port = cl_qlist_head( &p_ca->port_head ); + p_active_port != cl_qlist_end ( &p_ca->port_head); + p_active_port = cl_qlist_next ( p_active_port ) ) + { + if (((dapl_ibal_port_t *)p_active_port)->p_attr->port_num == port_num) + break; + } + RELEASE_LOCK (p_ca->port_lock); + + return (dapl_ibal_port_t *)p_active_port; +} + +static void +dapli_ibal_cq_async_error_callback( + IN ib_async_event_rec_t* p_err_rec ) +{ + DAPL_EVD *evd_ptr = (DAPL_EVD*)((void *)p_err_rec->context); + DAPL_EVD *async_evd_ptr; + DAPL_IA *ia_ptr; + dapl_ibal_ca_t *p_ca; + dapl_ibal_evd_cb_t *evd_cb; + + dapl_dbg_log (DAPL_DBG_TYPE_ERR,"--> DiCqAEC: CQ error %d for EVD context %p\n", + p_err_rec->code, p_err_rec->context); + + if (DAPL_BAD_HANDLE (evd_ptr, DAPL_MAGIC_EVD)) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR,"--> DiCqAEC: invalid EVD %p \n", evd_ptr); + return; + } + + ia_ptr = evd_ptr->header.owner_ia; + async_evd_ptr = ia_ptr->async_error_evd; + if (async_evd_ptr == NULL) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR,"--> DiCqAEC: can't find async_error_evd on %s HCA\n", + (ia_ptr->header.provider)->device_name ); + return; + } + + p_ca = (dapl_ibal_ca_t *) ia_ptr->hca_ptr->ib_hca_handle; + if (p_ca == NULL) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR,"--> DiCqAEC: can't find %s HCA\n", + (ia_ptr->header.provider)->device_name); + return; + } + + /* find CQ error callback using ia_ptr for context */ + evd_cb = dapli_find_evd_cb_by_context ( async_evd_ptr, p_ca ); + if ((evd_cb == NULL) || (evd_cb->pfn_async_cq_err_cb == NULL)) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR,"--> DiCqAEC: no ERROR cb on %p found \n", p_ca); + return; + } + + /* maps to dapl_evd_cq_async_error_callback(), context is EVD */ + evd_cb->pfn_async_cq_err_cb( (ib_hca_handle_t)p_ca, + (ib_error_record_t*)&p_err_rec->code, evd_ptr); + +} + +void +dapli_ibal_ca_async_error_callback( + IN ib_async_event_rec_t* p_err_rec ) +{ + dapl_ibal_ca_t *p_ca = (dapl_ibal_ca_t*)((void *)p_err_rec->context); + dapl_ibal_evd_cb_t *evd_cb; + DAPL_IA *ia_ptr; + + dapl_dbg_log (DAPL_DBG_TYPE_ERR,"--> DiCaAEC: CA error %d for context %p\n", + p_err_rec->code, p_err_rec->context); + + if (p_ca == NULL) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR,"--> DiCaAEC: invalid p_ca(%p)in async event rec\n",p_ca); + return; + } + + ia_ptr = (DAPL_IA*)p_ca->ia_ptr; + if (ia_ptr == NULL) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR,"--> DiCaAEC: invalid ia_ptr in %p ca \n", p_ca ); + return; + } + + if (ia_ptr->async_error_evd == NULL) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR,"--> DiCqAEC: can't find async_error_evd on %s HCA\n", + (ia_ptr->header.provider)->device_name ); + return; + } + + /* find QP error callback using p_ca for context */ + evd_cb = dapli_find_evd_cb_by_context (ia_ptr->async_error_evd, p_ca); + if ((evd_cb == NULL) || (evd_cb->pfn_async_err_cb == NULL)) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR,"--> DiCaAEC: no ERROR cb on %p found \n", p_ca); + return; + } + + /* maps to dapl_evd_un_async_error_callback(), context is async_evd */ + evd_cb->pfn_async_err_cb( (ib_hca_handle_t)p_ca, + (ib_error_record_t*)&p_err_rec->code, + ia_ptr->async_error_evd); + +} + + +static dapl_ibal_port_t * +dapli_alloc_port( + IN dapl_ibal_ca_t *ca, + IN ib_port_attr_t *ib_port ) +{ + dapl_ibal_port_t *p_port = NULL; + if (ca->h_ca == NULL ) + { + return NULL; + } + /* + * Allocate the port structure memory. This will also deal with the + * copying ib_port_attr_t including GID and P_Key tables + */ + p_port = dapl_os_alloc ( sizeof(dapl_ibal_port_t ) ); + + if ( p_port ) + { + dapl_os_memzero (p_port, sizeof(dapl_ibal_port_t ) ); + + /* + * We're good to go after initializing reference. + */ + INIT_REFERENCE( &p_port->refs, 1, p_port, NULL /* pfn_destructor */ ); + + p_port->p_attr = ib_port; + } + return ( p_port ); +} + +static void +dapli_add_active_port( IN dapl_ibal_ca_t *ca) +{ + dapl_ibal_port_t *p_port; + ib_port_attr_t *p_port_attr; + ib_ca_attr_t *p_ca_attr; + int i; + + p_ca_attr = ca->p_ca_attr; + + dapl_os_assert (p_ca_attr != NULL); + + for (i = 0; i < p_ca_attr->num_ports; i++) + { + p_port_attr = &p_ca_attr->p_port_attr[i]; + + { + p_port = dapli_alloc_port( ca, p_port_attr ); + if ( p_port ) + { + TAKE_REFERENCE (&ca->refs); + + /* + * Record / update attribues + */ + p_port->p_attr = p_port_attr; + + /* + * Remember the parant CA keeping the reference we took above + */ + p_port->ca = ca; + + /* + * We're good to go - Add the new port to the list on the CA + */ + LOCK_INSERT_TAIL( ca->port_lock, ca->port_head, p_port->next ); + } + else + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, "--> %s: Could not allocate " + "dapl_ibal_port_t\n", "DiAAP"); + } + } + dapl_dbg_log( DAPL_DBG_TYPE_UTIL, "--> DiAAP: Port %d logical link is %s lid = %#x\n", + p_port_attr->port_num, + ( p_port_attr->link_state != IB_LINK_ACTIVE ? "DOWN": "UP" ), + CL_HTON16(p_port_attr->lid) ); + + } /* for loop */ + + return; +} + +static dapl_ibal_ca_t * +dapli_alloc_ca( + IN ib_al_handle_t h_al, + IN ib_net64_t ca_guid) +{ + dapl_ibal_ca_t *p_ca; + ib_api_status_t status; + uint32_t attr_size; + + /* + * Allocate the CA structure + */ + p_ca = dapl_os_alloc( sizeof(dapl_ibal_ca_t) ); + dapl_os_memzero (p_ca, sizeof(dapl_ibal_ca_t) ); + + if ( p_ca ) + { + /* + * Now we pass dapli_ibal_ca_async_error_callback as the + * async error callback + */ + status = ib_open_ca( h_al, + ca_guid, + dapli_ibal_ca_async_error_callback, + p_ca, + &p_ca->h_ca ); + if ( status != IB_SUCCESS ) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, "--> DiAC: ib_open_ca returned %d\n", status); + dapl_os_free (p_ca, sizeof (dapl_ibal_ca_t)); + return (NULL); + } + + /* + * Get port list lock and list head initialized + */ + if (( dapli_init_ca_port_list( p_ca ) != CL_SUCCESS ) || + ( dapli_init_ca_evd_cb_list( p_ca ) != CL_SUCCESS )) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, "--> %s: dapli_init_ca_port_list returned failed\n", + "DiAC"); + goto close_and_free_ca; + } + + attr_size = 0; + status = ib_query_ca (p_ca->h_ca, NULL, &attr_size); + if (status != IB_INSUFFICIENT_MEMORY) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "--> DiAC: ib_query_ca returned failed status = %d\n", + status); + goto close_and_free_ca; + } + + p_ca->p_ca_attr = dapl_os_alloc ((int)attr_size); + if (p_ca->p_ca_attr == NULL) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "--> %s: dapli_alloc_ca failed to alloc memory\n", + "DiAC"); + goto close_and_free_ca; + } + + status = ib_query_ca ( + p_ca->h_ca, + p_ca->p_ca_attr, + &attr_size); + if (status != IB_SUCCESS) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "--> ib_query_ca returned failed status = %d\n", + status); + dapl_os_free (p_ca->p_ca_attr, (int)attr_size); + goto close_and_free_ca; + } + + p_ca->ca_attr_size = attr_size; + + INIT_REFERENCE( &p_ca->refs, 1, p_ca, NULL /* pfn_destructor */ ); + + dapli_add_active_port (p_ca); + + /* + * We're good to go + */ + return ( p_ca ); + } + else + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, "--> %s: Error allocating CA structure\n","DiAC"); + return ( NULL ); + } + +close_and_free_ca: + /* + * Close the CA. + */ + (void) ib_close_ca ( p_ca->h_ca, NULL /* callback */); + dapl_os_free (p_ca, sizeof (dapl_ibal_ca_t)); + + /* + * If we get here, there was an initialization failure + */ + return ( NULL ); +} + + +static dapl_ibal_ca_t * +dapli_add_ca( + IN ib_al_handle_t h_al, + IN ib_net64_t ca_guid) +{ + dapl_ibal_ca_t *p_ca; + + /* + * Allocate a CA structure + */ + p_ca = dapli_alloc_ca( h_al, ca_guid ); + if ( p_ca ) + { + /* + * Add the new CA to the list + */ + LOCK_INSERT_TAIL( dapl_ibal_root.ca_lock, + dapl_ibal_root.ca_head, p_ca->next ); + } + else + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, "--> %s: Could not allocate dapl_ibal_ca_t \n","DiAA"); + } + + return ( p_ca ); +} + + +int32_t dapls_ib_init (void) +{ + ib_api_status_t status; + + /* + * Initialize the root structure + */ + if (dapli_init_root_ca_list (&dapl_ibal_root) == CL_SUCCESS) + { + /* + * Register with the access layer + */ + status = ib_open_al (&dapl_ibal_root.h_al); + + if (status == IB_SUCCESS) + { + intn_t guid_count; + + status = ib_get_ca_guids (dapl_ibal_root.h_al, NULL, &(size_t)guid_count); + if (status != IB_INSUFFICIENT_MEMORY) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, "--> DsII: ib_get_ca_guids failed = %d\n", status); + return -1; + } + + if (guid_count == 0) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, "--> %s: found NO HCA in the system\n", + "DsII"); + return -1; + } + + if (guid_count > DAPL_IBAL_MAX_CA) + { + guid_count = DAPL_IBAL_MAX_CA; + } + + gp_ibal_ca_guid_tbl = ( ib_net64_t*)dapl_os_alloc ((int)(guid_count * + sizeof (ib_net64_t)) ); + + if (gp_ibal_ca_guid_tbl == NULL) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, "--> %s: can not alloc gp_ibal_ca_guid_tbl\n", + "DsII"); + + return -1; + } + + status = ib_get_ca_guids ( dapl_ibal_root.h_al, + gp_ibal_ca_guid_tbl, + &(size_t)guid_count ); + + + if ( status != IB_SUCCESS ) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, "--> DsII: ib_get_ca_guids failed = %s\n", + ib_get_err_str(status) ); + return -1; + } + + dapl_dbg_log ( DAPL_DBG_TYPE_UTIL, + "--> DsII: Success open AL & found %d HCA avail\n", + guid_count); + return 0; + } + else + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, "--> DsII: ib_open_al returned %s\n", ib_get_err_str(status)); + /* + * Undo CA list + */ + dapli_destroy_root_ca_list (&dapl_ibal_root); + } + } + return -1; +} + + +int32_t dapls_ib_release (void) +{ + dapl_ibal_root.shutdown = TRUE; + + dapli_shutdown_ca_access(); + + /* + * If shutdown not complete, wait for it + */ + if (dapl_ibal_root.shutdown) + { + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "--> DsIR: timeout waiting for completion\n"); + } + + if ( dapl_ibal_root.h_al != NULL ) + { + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "--> DsIR: ib_close_al called\n"); + ib_close_al (dapl_ibal_root.h_al); + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "--> DsIR: ib_close_al return\n"); + dapl_ibal_root.h_al = NULL; + } + + return 0; +} + + +/* + * dapls_ib_enum_hcas + * + * Enumerate all HCAs on the system + * + * Input: + * none + * + * Output: + * hca_names Array of hca names + * total_hca_count + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * + */ +DAT_RETURN +dapls_ib_enum_hcas ( + OUT DAPL_HCA_NAME **hca_names, + OUT DAT_COUNT *total_hca_count, + IN const char *vendor ) +{ + intn_t guid_count; + ib_api_status_t ib_status; + UNREFERENCED_PARAMETER(vendor); + + ib_status = ib_get_ca_guids (dapl_ibal_root.h_al, NULL, &(size_t)guid_count); + if (ib_status != IB_INSUFFICIENT_MEMORY) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, "--> DsIEH: ib_get_ca_guids failed status = %d\n", ib_status); + return dapl_ib_status_convert (ib_status); + } + + if (guid_count == 0) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, "--> %s: ib_get_ca_guids no HCA in the system\n", + "DsIEH"); + return (DAT_PROVIDER_NOT_FOUND); + } + + if (guid_count > DAPL_IBAL_MAX_CA) + { + guid_count = DAPL_IBAL_MAX_CA; + } + + gp_ibal_ca_guid_tbl = (ib_net64_t *)dapl_os_alloc ((int)(guid_count * sizeof (ib_net64_t)) ); + + if (gp_ibal_ca_guid_tbl == NULL) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, "--> %s: can not alloc resources @line%d\n", + "DsIEH", __LINE__); + return (DAT_INSUFFICIENT_RESOURCES); + } + + ib_status = ib_get_ca_guids ( + dapl_ibal_root.h_al, gp_ibal_ca_guid_tbl, &(size_t)guid_count); + + if (ib_status != IB_SUCCESS) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, "--> DsIEH: ib_get_ca_guids failed status = %s\n", + ib_get_err_str(ib_status)); + return dapl_ib_status_convert (ib_status); + } + + *hca_names = (DAPL_HCA_NAME*)dapl_os_alloc ((int)(guid_count * sizeof (DAPL_HCA_NAME)) ); + + if (*hca_names == NULL) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, "--> %s: can not alloc resources @line%d\n", + "DsIEH", __LINE__); + return (DAT_INSUFFICIENT_RESOURCES); + } + + dapl_os_memcpy (*hca_names, + dapl_ibal_hca_name_array, + (int)(guid_count * sizeof (DAPL_HCA_NAME)) ); + + *total_hca_count = (DAT_COUNT)guid_count; + + { + int i; + + for (i = 0; i < guid_count; i++) + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "--> DsIEH: %d) hca_names = %s\n", + i, dapl_ibal_hca_name_array[i]); + } + + return (DAT_SUCCESS); +} + + + +IB_HCA_NAME +dapl_ib_convert_name( + IN char *name) +{ + int i; + + if (gp_ibal_ca_guid_tbl == NULL) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, "--> DICN: found no HCA with name %s\n", name); + return 0; + } + + for (i = 0; i < DAPL_IBAL_MAX_CA; i++) + { + if (strcmp (name, dapl_ibal_hca_name_array[i]) == 0) + { + break; + } + } + + if (i >= DAPL_IBAL_MAX_CA) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, "--> DICN: can't find any HCA with name %s\n", name); + return 0; + } + + return (gp_ibal_ca_guid_tbl[i]); +} + + +/* + * dapls_ib_open_hca + * + * Open HCA + * + * Input: + * *hca_name pointer to provider device name + * *ib_hca_handle_p pointer to provide HCA handle + * + * Output: + * none + * + * Return: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * + */ +DAT_RETURN dapls_ib_open_hca ( + IN IB_HCA_NAME hca_name, + OUT ib_hca_handle_t *p_ib_hca_handle) +{ + dapl_ibal_ca_t *p_ca; + + if (gp_ibal_ca_guid_tbl == NULL) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, "--> DsIOH: found no HCA with ca_guid" F64x "\n", hca_name); + return (DAT_PROVIDER_NOT_FOUND); + } + + p_ca = dapli_add_ca (dapl_ibal_root.h_al, hca_name); + + if (p_ca == NULL) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, "--> DsIOH: can not create ca with ca_guid" F64x "\n", hca_name); + return (DAT_INSUFFICIENT_RESOURCES); + } + + *p_ib_hca_handle = (ib_hca_handle_t) p_ca; + + return (DAT_SUCCESS); +} + + +/* + * dapls_ib_close_hca + * + * Open HCA + * + * Input: + * ib_hca_handle provide HCA handle + * + * Output: + * none + * + * Return: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * + */ +DAT_RETURN dapls_ib_close_hca ( + IN ib_hca_handle_t ib_hca_handle) +{ + dapl_ibal_ca_t *p_ca; + + p_ca = (dapl_ibal_ca_t *) ib_hca_handle; + + /* + * Remove it from the list + */ + TAKE_LOCK (dapl_ibal_root.ca_lock); + { + cl_qlist_remove_item (&dapl_ibal_root.ca_head, &p_ca->next); + } + RELEASE_LOCK (dapl_ibal_root.ca_lock); + + dapli_shutdown_port_access (p_ca); + + /* + * Remove the constructor reference + */ + REMOVE_REFERENCE (&p_ca->refs); + + cl_spinlock_destroy (&p_ca->port_lock); + cl_spinlock_destroy (&p_ca->evd_cb_lock); + + if (p_ca->p_ca_attr) + dapl_os_free (p_ca->p_ca_attr, sizeof (ib_ca_attr_t)); + + (void) ib_close_ca (p_ca->h_ca, NULL /* close_callback */); + + dapl_os_free (p_ca, sizeof (dapl_ibal_ca_t)); + + return (DAT_SUCCESS); +} + +/* + * dapli_ibal_cq_competion_callback + * + * Completion callback for a CQ + * + * Input: + * cq_context User context + * + * Output: + * none + * + * Returns: + */ +static void +dapli_ib_cq_completion_cb ( + IN const ib_cq_handle_t h_cq, + IN void *cq_context ) +{ + DAPL_EVD *evd_ptr; + dapl_ibal_ca_t *p_ca; + + evd_ptr = (DAPL_EVD *) cq_context; + + dapl_dbg_log (DAPL_DBG_TYPE_CALLBACK, + "--> DiICCC: cq_completion_cb evd %p CQ %p\n", + evd_ptr, evd_ptr->ib_cq_handle); + + dapl_os_assert (evd_ptr != DAT_HANDLE_NULL); + + p_ca = (dapl_ibal_ca_t *) evd_ptr->header.owner_ia->hca_ptr->ib_hca_handle; + + dapl_os_assert( h_cq == evd_ptr->ib_cq_handle ); + + dapl_evd_dto_callback ( + (ib_hca_handle_t) p_ca, + h_cq, + cq_context); + return; +} + + +/* + * dapl_ib_cq_late_alloc + * + * Alloc a CQ + * + * Input: + * ia_handle IA handle + * evd_ptr pointer to EVD struct + * cqlen minimum QLen + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * + */ +DAT_RETURN +dapls_ib_cq_late_alloc ( + IN ib_pd_handle_t pd_handle, + IN DAPL_EVD *evd_ptr) +{ + ib_cq_create_t cq_create; + ib_api_status_t ib_status; + DAT_RETURN dat_status; + dapl_ibal_ca_t *ibal_ca = (dapl_ibal_ca_t *)evd_ptr->header.owner_ia->hca_ptr->ib_hca_handle; + + dat_status = DAT_SUCCESS; + cq_create.size = evd_ptr->qlen; + + + if (evd_ptr->cq_wait_obj_handle) + { + cq_create.h_wait_obj = evd_ptr->cq_wait_obj_handle; + cq_create.pfn_comp_cb = NULL; + } + else + { + cq_create.h_wait_obj = NULL; + cq_create.pfn_comp_cb = dapli_ib_cq_completion_cb; + } + + ib_status = ib_create_cq ( + (ib_ca_handle_t)ibal_ca->h_ca, + &cq_create, + evd_ptr /* context */, + dapli_ibal_cq_async_error_callback, + &evd_ptr->ib_cq_handle); + + dat_status = dapl_ib_status_convert (ib_status); + + if ( dat_status != DAT_SUCCESS ) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, "--> DsICLA: failed to create CQ for EVD %p\n", evd_ptr); + goto bail; + } + + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "--> DsCQ_alloc: pd=%p cq=%p Csz=%d Qln=%d \n", + pd_handle, evd_ptr->ib_cq_handle, + cq_create.size, evd_ptr->qlen ); + + + if ( cq_create.size > (uint32_t)evd_ptr->qlen ) + { + DAT_COUNT pending_cnt, free_cnt; + DAT_EVENT *event_ptr; + DAT_COUNT i; + + dapl_os_lock ( &evd_ptr->header.lock ); + + pending_cnt = dapls_rbuf_count ( &evd_ptr->pending_event_queue ); + free_cnt = dapls_rbuf_count ( &evd_ptr->free_event_queue ); + + if ( pending_cnt == 0 ) + { + dat_status = dapls_rbuf_realloc ( &evd_ptr->pending_event_queue, + cq_create.size ); + + if ( dat_status != DAT_SUCCESS ) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, "--> DsICLA: failed to resize EVD pending_event_queue" + "from %d to %d\n", + evd_ptr->qlen, cq_create.size ); + dat_status = DAT_SUCCESS; + } + + } + + + for (i = 0; i < free_cnt; i++) + { + event_ptr = (DAT_EVENT *) + dapls_rbuf_remove ( &evd_ptr->free_event_queue ); + } + + dat_status = dapls_rbuf_realloc ( &evd_ptr->free_event_queue, + cq_create.size ); + + if ( dat_status != DAT_SUCCESS ) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, "--> DsICLA: failed to resize EVD free_event_queue" + "from %d to %d\n", + evd_ptr->qlen, cq_create.size ); + + dapl_os_unlock ( &evd_ptr->header.lock ); + + dapls_ib_cq_free ( evd_ptr->header.owner_ia, evd_ptr); + + goto bail; + } + + if (evd_ptr->events) + { + evd_ptr->events = (void *) + dapl_os_realloc ( + evd_ptr->events, + cq_create.size * sizeof (DAT_EVENT)); + } + else + { + evd_ptr->events = (void *) + dapl_os_alloc ( + cq_create.size * sizeof (DAT_EVENT)); + } + + if ( evd_ptr->events == NULL ) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, "--> DsICLA: failed to resize EVD events buffers" + "from %d to %d\n", + evd_ptr->qlen, cq_create.size ); + dat_status = DAT_INSUFFICIENT_RESOURCES; + + dapl_os_unlock ( &evd_ptr->header.lock ); + + dapls_ib_cq_free ( evd_ptr->header.owner_ia, evd_ptr); + + goto bail; + } + + event_ptr = evd_ptr->events; + + /* add events to free event queue */ + for (i = 0; (uint32_t)i < cq_create.size; i++) + { + dapls_rbuf_add (&evd_ptr->free_event_queue, (void *)event_ptr); + event_ptr++; + } + + dapl_dbg_log (DAPL_DBG_TYPE_EVD, + "--> DsICLA: resize EVD events buffers from %d to %d\n", + evd_ptr->qlen, cq_create.size); + + evd_ptr->qlen = cq_create.size; + + dapl_os_unlock ( &evd_ptr->header.lock ); + + } + +bail: + return dat_status; +} + +/* + * dapl_ib_cq_free + * + * Dealloc a CQ + * + * Input: + * ia_handle IA handle + * evd_ptr pointer to EVD struct + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + * DAT_INSUFFICIENT_RESOURCES + * + */ +DAT_RETURN +dapls_ib_cq_free ( + IN DAPL_IA *ia_ptr, + IN DAPL_EVD *evd_ptr) +{ + ib_api_status_t ib_status; + + if ( ia_ptr == NULL || ia_ptr->header.magic != DAPL_MAGIC_IA ) + { + return DAT_INVALID_HANDLE; + } + + ib_status = ib_destroy_cq (evd_ptr->ib_cq_handle, + /* destroy_callback */ NULL); + + return dapl_ib_status_convert (ib_status); +} + +/* + * dapls_cq_resize + * + * Resize CQ completion notifications + * + * Input: + * ia_handle IA handle + * evd_ptr pointer to EVD struct + * cqlen minimum QLen + * + * Output: + * cqlen may round up for optimal memory boundaries + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + * DAT_INSUFFICIENT_RESOURCES + * + */ + +DAT_RETURN +dapls_ib_cq_resize ( + IN DAPL_IA *ia_ptr, + IN DAPL_EVD *evd_ptr, + IN DAT_COUNT *cqlen ) +{ + ib_api_status_t ib_status = IB_SUCCESS; + if ( ia_ptr == NULL || ia_ptr->header.magic != DAPL_MAGIC_IA ) + { + return DAT_INVALID_HANDLE; + } + /* + * Resize CQ only if CQ handle is valid, may be delayed waiting + * for PZ allocation with IBAL + */ +#if defined(_VENDOR_IBAL_) + if ( evd_ptr->ib_cq_handle != IB_INVALID_HANDLE ) +#endif /* _VENDOR_IBAL_ */ + { + ib_status = ib_modify_cq ( evd_ptr->ib_cq_handle, + (uint32_t *)cqlen ); + dapl_dbg_log (DAPL_DBG_TYPE_EVD, + "ib_modify_cq ( new cqlen = %d, status=%d ) \n", + *cqlen, ib_status ); + } + return dapl_ib_status_convert (ib_status); +} + + +/* + * dapl_set_cq_notify + * + * Set up CQ completion notifications + * + * Input: + * ia_handle IA handle + * evd_ptr pointer to EVD struct + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + * DAT_INSUFFICIENT_RESOURCES + * + */ +DAT_RETURN +dapls_set_cq_notify ( + IN DAPL_IA *ia_ptr, + IN DAPL_EVD *evd_ptr) +{ + ib_api_status_t ib_status; + if ( ia_ptr == NULL || ia_ptr->header.magic != DAPL_MAGIC_IA ) + { + return DAT_INVALID_HANDLE; + } + ib_status = ib_rearm_cq ( + evd_ptr->ib_cq_handle, + FALSE /* next event but not solicited event */ ); + + return dapl_ib_status_convert (ib_status); +} + + +/* + * dapls_ib_cqd_create + * + * Set up CQ notification event thread + * + * Input: + * ia_handle HCA handle + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + * DAT_INSUFFICIENT_RESOURCES + * + */ +DAT_RETURN +dapls_ib_cqd_create ( + IN DAPL_HCA *hca_ptr) +{ + /* + * We do not have CQD concept + */ + hca_ptr->ib_cqd_handle = IB_INVALID_HANDLE; + + return DAT_SUCCESS; +} + + +/* + * dapl_cqd_destroy + * + * Destroy CQ notification event thread + * + * Input: + * ia_handle IA handle + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + * DAT_INSUFFICIENT_RESOURCES + * + */ +DAT_RETURN +dapls_ib_cqd_destroy ( + IN DAPL_HCA *hca_ptr) +{ + hca_ptr->ib_cqd_handle = IB_INVALID_HANDLE; + return (DAT_SUCCESS); +} + + +/* + * dapl_ib_pd_alloc + * + * Alloc a PD + * + * Input: + * ia_handle IA handle + * PZ_ptr pointer to PZEVD struct + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * + */ +DAT_RETURN +dapls_ib_pd_alloc ( + IN DAPL_IA *ia, + IN DAPL_PZ *pz) +{ + ib_api_status_t ib_status; + dapl_ibal_ca_t *p_ca; + + p_ca = (dapl_ibal_ca_t *) ia->hca_ptr->ib_hca_handle; + ib_status = ib_alloc_pd ( + p_ca->h_ca, + IB_PDT_NORMAL, + ia, + &pz->pd_handle); + + return dapl_ib_status_convert (ib_status); +} + + +/* + * dapl_ib_pd_free + * + * Free a PD + * + * Input: + * PZ_ptr pointer to PZ struct + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * + */ +DAT_RETURN +dapls_ib_pd_free ( + IN DAPL_PZ *pz) +{ + ib_api_status_t ib_status; + + ib_status = ib_dealloc_pd (pz->pd_handle, /* destroy_callback */ NULL); + + pz->pd_handle = IB_INVALID_HANDLE; + + return dapl_ib_status_convert (ib_status); +} + + +/* + * dapl_ib_mr_register + * + * Register a virtual memory region + * + * Input: + * ia_handle IA handle + * lmr pointer to dapl_lmr struct + * virt_addr virtual address of beginning of mem region + * length length of memory region + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * + */ +DAT_RETURN +dapls_ib_mr_register ( + IN DAPL_IA *ia, + IN DAPL_LMR *lmr, + IN DAT_PVOID virt_addr, + IN DAT_VLEN length, + IN DAT_MEM_PRIV_FLAGS privileges) +{ + ib_api_status_t ib_status; + ib_mr_handle_t mr_handle; + ib_mr_create_t mr_create; + uint32_t l_key, r_key; + + if ( ia == NULL || ia->header.magic != DAPL_MAGIC_IA ) + { + return DAT_INVALID_HANDLE; + } + mr_create.vaddr = (void *) virt_addr; + mr_create.length = (size_t)length; + mr_create.access_ctrl = dapl_lmr_convert_privileges (privileges); + mr_create.access_ctrl |= IB_AC_MW_BIND; + + if (lmr->param.mem_type == DAT_MEM_TYPE_SHARED_VIRTUAL) + { + ib_status = ib_reg_shmid ( + ((DAPL_PZ *)lmr->param.pz_handle)->pd_handle, + (const uint8_t*)&lmr->ib_shmid, + &mr_create, + (uint64_t *)&virt_addr, + &l_key, + &r_key, + &mr_handle); + } + else + { + ib_status = ib_reg_mem ( + ((DAPL_PZ *)lmr->param.pz_handle)->pd_handle, + &mr_create, + &l_key, + &r_key, + &mr_handle); + } + + if (ib_status != IB_SUCCESS) + { + return (dapl_ib_status_convert (ib_status)); + } + + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, "--> DsIMR: lmr (%p) lkey 0x%x r_key %#x " + "mr_handle %p vaddr 0x%LX len 0x%LX\n", + lmr, l_key, r_key, mr_handle, virt_addr, length); + + lmr->param.lmr_context = l_key; + lmr->param.rmr_context = r_key; + lmr->param.registered_size = length; +#ifndef _WIN64 + // Fix MS compiler warning C4826: Conversion from 'DAT_PVOID' to 'DAT_VADDR' + // is sign-extended. This may cause unexpected runtime behavior. + lmr->param.registered_address = (DAT_VADDR) (DAT_UINT32) virt_addr; +#else + lmr->param.registered_address = (DAT_VADDR)virt_addr; +#endif + lmr->mr_handle = mr_handle; + + return (DAT_SUCCESS); +} + + +/* + * dapl_ib_mr_deregister + * + * Free a memory region + * + * Input: + * lmr pointer to dapl_lmr struct + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * + */ +DAT_RETURN +dapls_ib_mr_deregister ( + IN DAPL_LMR *lmr) +{ + ib_api_status_t ib_status; + + ib_status = ib_dereg_mr (lmr->mr_handle); + + if (ib_status != IB_SUCCESS) + { + return dapl_ib_status_convert (ib_status); + } + + lmr->param.lmr_context = 0; + lmr->mr_handle = IB_INVALID_HANDLE; + + return (DAT_SUCCESS); +} + + +/* + * dapl_ib_mr_register_shared + * + * Register a virtual memory region + * + * Input: + * ia_handle IA handle + * lmr pointer to dapl_lmr struct + * virt_addr virtual address of beginning of mem region + * length length of memory region + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * + */ +DAT_RETURN +dapls_ib_mr_register_shared ( + IN DAPL_IA *ia, + IN DAPL_LMR *lmr, + IN DAT_MEM_PRIV_FLAGS privileges) +{ + DAT_VADDR virt_addr; + ib_mr_handle_t mr_handle; + ib_api_status_t ib_status; + ib_mr_handle_t new_mr_handle; + ib_access_t access_ctrl; + uint32_t l_key, r_key; + ib_mr_create_t mr_create; + if ( ia == NULL || ia->header.magic != DAPL_MAGIC_IA ) + { + return DAT_INVALID_HANDLE; + } + virt_addr = dapl_mr_get_address (lmr->param.region_desc, + lmr->param.mem_type); + + access_ctrl = dapl_lmr_convert_privileges (privileges); + access_ctrl |= IB_AC_MW_BIND; + + mr_create.vaddr = (void *) virt_addr; + mr_create.access_ctrl = access_ctrl; + mr_handle = (ib_mr_handle_t) lmr->mr_handle; + + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "--> DsIMRS: orig mr_handle %p vaddr %p\n", + mr_handle, virt_addr); + + if (lmr->param.mem_type == DAT_MEM_TYPE_SHARED_VIRTUAL) + { + ib_status = ib_reg_shmid ( + ((DAPL_PZ *)lmr->param.pz_handle)->pd_handle, + (const uint8_t*)&lmr->ib_shmid, + &mr_create, + &virt_addr, + &l_key, + &r_key, + &new_mr_handle); + } + else + { + + ib_status = ib_reg_shared ( + mr_handle, + ((DAPL_PZ *)lmr->param.pz_handle)->pd_handle, + access_ctrl, + /* in/out */(DAT_UINT64 *)&virt_addr, + &l_key, + &r_key, + &new_mr_handle); + } + + if (ib_status != IB_SUCCESS) + { + return dapl_ib_status_convert (ib_status); + } + /* + * FIXME - Vu + * What if virt_addr as an OUTPUT having the actual virtual address + * assigned to the register region + */ + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "--> DsIMRS: lmr (%p) lkey = 0x%x new mr_handle %p vaddr %p\n", + lmr, l_key, new_mr_handle, virt_addr); + + lmr->param.lmr_context = l_key; + lmr->param.rmr_context = r_key; + lmr->param.registered_address = (DAT_VADDR) (uintptr_t) virt_addr; + lmr->mr_handle = new_mr_handle; + + return (DAT_SUCCESS); +} + + +/* + * dapls_ib_mw_alloc + * + * Bind a protection domain to a memory window + * + * Input: + * rmr Initialized rmr to hold binding handles + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * + */ +DAT_RETURN +dapls_ib_mw_alloc ( + IN DAPL_RMR *rmr) +{ + ib_api_status_t ib_status; + uint32_t r_key; + ib_mw_handle_t mw_handle; + + ib_status = ib_create_mw ( + ((DAPL_PZ *)rmr->param.pz_handle)->pd_handle, + &r_key, + &mw_handle); + + if (ib_status != IB_SUCCESS) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, "--> DsIMA: create MW failed = %s\n", ib_get_err_str(ib_status)); + return dapl_ib_status_convert (ib_status); + } + + rmr->mw_handle = mw_handle; + rmr->param.rmr_context = (DAT_RMR_CONTEXT) r_key; + + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "--> DsIMA: mw_handle %p r_key = 0x%x\n", + mw_handle, r_key); + + return (DAT_SUCCESS); +} + + +/* + * dapls_ib_mw_free + * + * Release bindings of a protection domain to a memory window + * + * Input: + * rmr Initialized rmr to hold binding handles + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * + */ +DAT_RETURN +dapls_ib_mw_free ( + IN DAPL_RMR *rmr) +{ + ib_api_status_t ib_status; + + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "--> DsIMF: mw_handle %p\n", rmr->mw_handle); + + ib_status = ib_destroy_mw (rmr->mw_handle); + + if (ib_status != IB_SUCCESS) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, "--> DsIMF: Free MW failed = %s\n", ib_get_err_str(ib_status)); + return dapl_ib_status_convert (ib_status); + } + + rmr->param.rmr_context = 0; + rmr->mw_handle = IB_INVALID_HANDLE; + + return (DAT_SUCCESS); +} + +/* + * dapls_ib_mw_bind + * + * Bind a protection domain to a memory window + * + * Input: + * rmr Initialized rmr to hold binding handles + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * + */ +DAT_RETURN +dapls_ib_mw_bind ( + IN DAPL_RMR *rmr, + IN DAPL_LMR *lmr, + IN DAPL_EP *ep, + IN DAPL_COOKIE *cookie, + IN DAT_VADDR virtual_address, + IN DAT_VLEN length, + IN DAT_MEM_PRIV_FLAGS mem_priv, + IN ib_bool_t is_signaled) +{ + ib_api_status_t ib_status; + ib_bind_wr_t bind_wr_prop; + uint32_t new_rkey; + + bind_wr_prop.local_ds.vaddr = virtual_address; + bind_wr_prop.local_ds.length = (uint32_t)length; + bind_wr_prop.local_ds.lkey = lmr->param.lmr_context; + bind_wr_prop.current_rkey = rmr->param.rmr_context; + bind_wr_prop.access_ctrl = dapl_rmr_convert_privileges (mem_priv); + bind_wr_prop.send_opt = (is_signaled == TRUE) ? + IB_SEND_OPT_SIGNALED : 0; + bind_wr_prop.wr_id = (uint64_t) ((uintptr_t) cookie); + bind_wr_prop.h_mr = lmr->mr_handle; + + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "--> DsIMB: mr_handle %p, mw_handle %p vaddr %#I64x length %#I64x\n", + lmr->mr_handle, rmr->mw_handle, virtual_address, length); + + ib_status = ib_bind_mw ( + rmr->mw_handle, + ep->qp_handle, + &bind_wr_prop, + &new_rkey); + + if (ib_status != IB_SUCCESS) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, "--> DsIMB: Bind MW failed = %s\n", + ib_get_err_str(ib_status)); + return (dapl_ib_status_convert (ib_status)); + } + + rmr->param.rmr_context = (DAT_RMR_CONTEXT) new_rkey; + + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "--> DsIMB: new_rkey = 0x%x\n",new_rkey); + return (DAT_SUCCESS); +} + +/* + * dapls_ib_mw_unbind + * + * Unbind a memory window + * + * Input: + * rmr Initialized rmr to hold binding handles + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * + */ +DAT_RETURN +dapls_ib_mw_unbind ( + IN DAPL_RMR *rmr, + IN DAPL_EP *ep, + IN DAPL_COOKIE *cookie, + IN ib_bool_t is_signaled) +{ + ib_api_status_t ib_status; + ib_bind_wr_t bind_wr_prop; + uint32_t new_rkey; + + bind_wr_prop.local_ds.vaddr = 0; + bind_wr_prop.local_ds.length = 0; + bind_wr_prop.local_ds.lkey = 0; + bind_wr_prop.access_ctrl = 0; + bind_wr_prop.send_opt = (is_signaled == TRUE) ? + IB_SEND_OPT_SIGNALED : 0; + bind_wr_prop.wr_id = (uint64_t) ((uintptr_t) cookie); + + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "--> DsIMU: mw_handle = %p\n", rmr->mw_handle); + + ib_status = ib_bind_mw ( + rmr->mw_handle, + ep->qp_handle, + &bind_wr_prop, + &new_rkey); + + if (ib_status != IB_SUCCESS) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, "--> DsIMU: Unbind MW failed = %s\n", + ib_get_err_str(ib_status)); + return (dapl_ib_status_convert (ib_status)); + } + + rmr->param.rmr_context = (DAT_RMR_CONTEXT) new_rkey; + + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "--> DsIMU: unbind new_rkey = 0x%x\n", new_rkey); + return (DAT_SUCCESS); +} + + +/* + * dapls_ib_setup_async_callback + * + * Set up an asynchronous callbacks of various kinds + * + * Input: + * ia_handle IA handle + * handler_type type of handler to set up + * callback_handle handle param for completion callbacks + * callback callback routine pointer + * context argument for callback routine + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + * + */ +DAT_RETURN +dapls_ib_setup_async_callback ( + IN DAPL_IA *ia_ptr, + IN DAPL_ASYNC_HANDLER_TYPE handler_type, + IN unsigned int *callback_handle, + IN ib_async_handler_t callback, + IN void *context ) +{ + dapl_ibal_ca_t *p_ca; + dapl_ibal_evd_cb_t *evd_cb; + UNREFERENCED_PARAMETER(callback_handle); + + p_ca = (dapl_ibal_ca_t *) ia_ptr->hca_ptr->ib_hca_handle; + + if (p_ca == NULL) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, "--> DsISAC: can't find %s HCA\n", + (ia_ptr->header.provider)->device_name); + return (DAT_INVALID_HANDLE); + } + + if (handler_type != DAPL_ASYNC_CQ_COMPLETION) + { + evd_cb = dapli_find_evd_cb_by_context (context, p_ca); + + if (evd_cb == NULL) + { + /* + * No record for this evd. We allocate one + */ + evd_cb = dapl_os_alloc (sizeof (dapl_ibal_evd_cb_t)); + dapl_os_memzero (evd_cb, sizeof(dapl_ibal_evd_cb_t)); + + if (evd_cb == NULL) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, "--> %s: can't alloc res\n","DsISAC"); + return (DAT_INSUFFICIENT_RESOURCES); + } + + evd_cb->context = context; + + /* + * Add the new EVD CB to the list + */ + LOCK_INSERT_TAIL( p_ca->evd_cb_lock, + p_ca->evd_cb_head, + evd_cb->next ); + } + + switch (handler_type) + { + case DAPL_ASYNC_UNAFILIATED: + evd_cb->pfn_async_err_cb = callback; + break; + case DAPL_ASYNC_CQ_ERROR: + evd_cb->pfn_async_cq_err_cb = callback; + break; + case DAPL_ASYNC_QP_ERROR: + evd_cb->pfn_async_qp_err_cb = callback; + break; + default: + break; + } + + } + + return DAT_SUCCESS; +} + + +/* + * dapls_ib_query_hca + * + * Query the hca attribute + * + * Input: + * hca_handl hca handle + * ep_attr attribute of the ep + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + */ + +DAT_RETURN dapls_ib_query_hca ( + IN DAPL_HCA *hca_ptr, + OUT DAT_IA_ATTR *ia_attr, + OUT DAT_EP_ATTR *ep_attr, + OUT DAT_SOCK_ADDR6 *ip_addr) +{ + ib_ca_attr_t *p_hca_attr; + dapl_ibal_ca_t *p_ca; + ib_api_status_t ib_status; + ib_hca_port_t port_num; + GID gid; + DAT_SOCK_ADDR6 *p_sock_addr; + DAT_RETURN dat_status = DAT_SUCCESS; + + port_num = hca_ptr->port_num; + + p_ca = (dapl_ibal_ca_t *) hca_ptr->ib_hca_handle; + + if (p_ca == NULL) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, "--> DsIQH: invalid handle %p", + hca_ptr ); + return (DAT_INVALID_HANDLE); + } + + ib_status = ib_query_ca ( p_ca->h_ca, + p_ca->p_ca_attr, + &p_ca->ca_attr_size ); + + if (ib_status != IB_SUCCESS) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "--> DsIQH: ib_query_ca returned failed status = %s\n", + ib_get_err_str(ib_status)); + return (dapl_ib_status_convert (ib_status)); + } + + p_hca_attr = p_ca->p_ca_attr; + + if (ip_addr != NULL) + { + p_sock_addr = dapl_os_alloc(sizeof(DAT_SOCK_ADDR6)); + if ( !p_sock_addr ) + { + dat_status = DAT_INSUFFICIENT_RESOURCES; + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + " Query Hca alloc Err: status %d\n", dat_status); + return dat_status; + } + dapl_os_memzero(p_sock_addr, sizeof(DAT_SOCK_ADDR6)); + + gid.gid_prefix = + p_hca_attr->p_port_attr[port_num-1].p_gid_table->unicast.prefix; + + gid.guid = + p_hca_attr->p_port_attr[port_num-1].p_gid_table->unicast.interface_id; + + dat_status = dapls_ns_map_ipaddr(hca_ptr, gid, + (DAT_IA_ADDRESS_PTR)p_sock_addr); + + if ( dat_status != DAT_SUCCESS ) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + " SA Query for local IP failed= %d\n", + dat_status ); + /* what to do next ? */ + } + else + { + dapl_dbg_log (DAPL_DBG_TYPE_CM, "SA query GID for IP: "); + dapl_dbg_log ( DAPL_DBG_TYPE_CM, "%0d:%d:%d:%d\n", + (uint8_t)((DAT_IA_ADDRESS_PTR )p_sock_addr)->sa_data[2]&0xff, + (uint8_t)((DAT_IA_ADDRESS_PTR )p_sock_addr)->sa_data[3]&0xff, + (uint8_t)((DAT_IA_ADDRESS_PTR )p_sock_addr)->sa_data[4]&0xff, + (uint8_t)((DAT_IA_ADDRESS_PTR )p_sock_addr)->sa_data[5]&0xff); + } + + hca_ptr->hca_address = *p_sock_addr; + + /* if structure address not from our hca_ptr */ + if ( ip_addr != &hca_ptr->hca_address ) + { + *ip_addr = *p_sock_addr; + } + dapl_os_free (p_sock_addr, sizeof(DAT_SOCK_ADDR6)); + } /* ip_addr != NULL */ + + if ( ia_attr != NULL ) + { + dapl_os_memzero (ia_attr->adapter_name, + (int)sizeof(ia_attr->adapter_name )); + dapl_os_memcpy (ia_attr->adapter_name, + DAT_ADAPTER_NAME, + min ( (int)dapl_os_strlen(DAT_ADAPTER_NAME), + (int)(DAT_NAME_MAX_LENGTH)-1 ) ); + + dapl_os_memzero (ia_attr->vendor_name, + (int)sizeof(ia_attr->vendor_name)); + dapl_os_memcpy(ia_attr->vendor_name, + DAT_VENDOR_NAME, + min ((int)dapl_os_strlen(DAT_VENDOR_NAME), + (int)(DAT_NAME_MAX_LENGTH)-1 )); + + /* FIXME : Vu + * this value should be revisited + * It can be set by DAT consumers + */ + ia_attr->ia_address_ptr = (DAT_PVOID)&hca_ptr->hca_address; + ia_attr->hardware_version_major = p_hca_attr->dev_id; + ia_attr->hardware_version_minor = p_hca_attr->revision; + ia_attr->max_eps = p_hca_attr->max_qps; + ia_attr->max_dto_per_ep = p_hca_attr->max_wrs; + ia_attr->max_rdma_read_per_ep = p_hca_attr->max_qp_resp_res; + ia_attr->max_evds = p_hca_attr->max_cqs; + ia_attr->max_evd_qlen = p_hca_attr->max_cqes; + ia_attr->max_iov_segments_per_dto = p_hca_attr->max_sges; + ia_attr->max_lmrs = p_hca_attr->init_regions; + ia_attr->max_lmr_block_size = p_hca_attr->init_region_size; + ia_attr->max_rmrs = p_hca_attr->init_windows; + ia_attr->max_lmr_virtual_address = p_hca_attr->max_addr_handles; + ia_attr->max_rmr_target_address = p_hca_attr->max_addr_handles; + ia_attr->max_pzs = p_hca_attr->max_pds; + /* + * DAT spec does not tie max_mtu_size with IB MTU + * + ia_attr->max_mtu_size = + dapl_ibal_mtu_table[p_hca_attr->p_port_attr->mtu]; + */ + ia_attr->max_mtu_size = + p_hca_attr->p_port_attr->max_msg_size; + ia_attr->max_rdma_size = + p_hca_attr->p_port_attr->max_msg_size; + ia_attr->num_transport_attr = 0; + ia_attr->transport_attr = NULL; + ia_attr->num_vendor_attr = 0; + ia_attr->vendor_attr = NULL; + + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, " --> DsIMU_qHCA: (ver=%x) ep %d " + "ep_q %d evd %d evd_q %d\n", + ia_attr->hardware_version_major, + ia_attr->max_eps, ia_attr->max_dto_per_ep, + ia_attr->max_evds, ia_attr->max_evd_qlen ); + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, + " --> DsIMU_qHCA: mtu %llu rdma %llu iov %d lmr %d rmr %d" + " rdma_io %d\n", + ia_attr->max_mtu_size, ia_attr->max_rdma_size, + ia_attr->max_iov_segments_per_dto, ia_attr->max_lmrs, + ia_attr->max_rmrs, ia_attr->max_rdma_read_per_ep ); + } + + if ( ep_attr != NULL ) + { + /* + * DAT spec does not tie max_mtu_size with IB MTU + * + ep_attr->max_mtu_size = + dapl_ibal_mtu_table[p_hca_attr->p_port_attr->mtu]; + */ + ep_attr->max_mtu_size = p_hca_attr->p_port_attr->max_msg_size; + ep_attr->max_rdma_size = p_hca_attr->p_port_attr->max_msg_size; + ep_attr->max_recv_dtos = p_hca_attr->max_wrs; + ep_attr->max_request_dtos = p_hca_attr->max_wrs; + ep_attr->max_recv_iov = p_hca_attr->max_sges; + ep_attr->max_request_iov = p_hca_attr->max_sges; + ep_attr->max_rdma_read_in = p_hca_attr->max_qp_resp_res; + ep_attr->max_rdma_read_out= p_hca_attr->max_qp_resp_res; + + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, + " --> DsIMU_qHCA: msg %llu dto %d iov %d rdma i%d,o%d\n", + ep_attr->max_mtu_size, + ep_attr->max_recv_dtos, ep_attr->max_recv_iov, + ep_attr->max_rdma_read_in, ep_attr->max_rdma_read_out); + } + + return DAT_SUCCESS; +} + + +DAT_RETURN +dapls_ib_completion_poll ( + IN ib_hca_handle_t hca_handle, + IN ib_cq_handle_t cq_handle, + IN ib_work_completion_t* cqe_ptr) +{ + ib_api_status_t ib_status; + ib_work_completion_t *cqe_filled; + + /* + * FIXME - Vu + * Now we only poll for one cqe. We can poll for more than + * one completions later for better. However, this requires + * to change the logic in dapl_evd_dto_callback function + * to process more than one completion. + */ + cqe_ptr->p_next = NULL; + cqe_filled = NULL; + if ( !hca_handle ) + { + return DAT_INVALID_HANDLE; + } + ib_status = ib_poll_cq (cq_handle, &cqe_ptr, &cqe_filled); + + if ( ib_status == IB_INVALID_CQ_HANDLE ) + ib_status = IB_NOT_FOUND; + + return dapl_ib_status_convert (ib_status); +} + + +DAT_RETURN +dapls_ib_completion_notify ( + IN ib_hca_handle_t hca_handle, + IN ib_cq_handle_t cq_handle, + IN ib_notification_type_t type) +{ + ib_api_status_t ib_status; + DAT_BOOLEAN solic_notify; + if ( !hca_handle ) + { + return DAT_INVALID_HANDLE; + } + solic_notify = (type == IB_NOTIFY_ON_SOLIC_COMP) ? DAT_TRUE : DAT_FALSE; + ib_status = ib_rearm_cq ( cq_handle, solic_notify ); + + return dapl_ib_status_convert (ib_status); +} + + +DAT_RETURN +dapls_ib_n_completions_notify ( + IN ib_hca_handle_t hca_handle, + IN ib_cq_handle_t cq_handle, + IN uint32_t n_cqes) +{ + ib_api_status_t ib_status; + UNREFERENCED_PARAMETER(hca_handle); + + ib_status = ib_rearm_n_cq ( + cq_handle, + n_cqes ); + + return dapl_ib_status_convert (ib_status); +} + + +DAT_RETURN +dapls_ib_peek_cq ( + IN ib_cq_handle_t cq_handle, + OUT uint32_t* p_n_cqes) +{ + ib_api_status_t ib_status; + + ib_status = ib_peek_cq ( + cq_handle, + p_n_cqes ); + + return dapl_ib_status_convert (ib_status); +} + + +DAT_RETURN +dapls_ib_wait_object_create ( + IN cl_waitobj_handle_t* p_cq_wait_obj_handle) +{ + cl_status_t cl_status; + + cl_status = cl_waitobj_create (FALSE /* auto_reset */, p_cq_wait_obj_handle); + + if (cl_status == CL_SUCCESS) + return DAT_SUCCESS; + + return DAT_INTERNAL_ERROR; +} + + +DAT_RETURN +dapls_ib_wait_object_destroy ( + IN cl_waitobj_handle_t cq_wait_obj_handle) +{ + cl_status_t cl_status; + + cl_status = cl_waitobj_destroy (cq_wait_obj_handle); + + if (cl_status == CL_SUCCESS) + return DAT_SUCCESS; + + return DAT_INTERNAL_ERROR; +} + + +DAT_RETURN +dapls_ib_wait_object_wakeup ( + IN cl_waitobj_handle_t cq_wait_obj_handle) +{ + cl_status_t cl_status; + + cl_status = cl_waitobj_signal (cq_wait_obj_handle); + + if (cl_status == CL_SUCCESS) + return DAT_SUCCESS; + + return DAT_INTERNAL_ERROR; +} + + +DAT_RETURN +dapls_ib_wait_object_wait ( + IN cl_waitobj_handle_t cq_wait_obj_handle, + IN uint32_t timeout) +{ + cl_status_t cl_status; + + cl_status = cl_waitobj_wait_on (cq_wait_obj_handle, timeout, TRUE ); + + switch (cl_status) + { + case CL_SUCCESS: + return DAT_SUCCESS; + case CL_TIMEOUT: + dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> wait_object_wait: cl_timeout: %d\n", timeout); + return DAT_TIMEOUT_EXPIRED; + case CL_NOT_DONE: + return DAT_SUCCESS; + default: + dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> wait_object_wait: cl_error: %d\n", cl_status); + return DAT_INTERNAL_ERROR; + } +} + + +/* + * dapls_ib_get_async_event + * + * Translate an asynchronous event type to the DAT event. + * Note that different providers have different sets of errors. + * + * Input: + * cause_ptr provider event cause + * + * Output: + * async_event DAT mapping of error + * + * Returns: + * DAT_SUCCESS + * DAT_NOT_IMPLEMENTED Caller is not interested this event + */ + +DAT_RETURN dapls_ib_get_async_event( + IN ib_async_event_rec_t *cause_ptr, + OUT DAT_EVENT_NUMBER *async_event) +{ + ib_async_event_t event_id; + DAT_RETURN dat_status; + + dat_status = DAT_SUCCESS; + event_id = cause_ptr->code; + + dapl_dbg_log (DAPL_DBG_TYPE_WARN, + "--> DsAE: event_id = %d%d\n", event_id); + + switch (event_id ) + { + case IB_AE_SQ_ERROR: + case IB_AE_SQ_DRAINED: + case IB_AE_RQ_ERROR: + { + *async_event = DAT_ASYNC_ERROR_EP_BROKEN; + break; + } + + + + /* INTERNAL errors */ + case IB_AE_QP_FATAL: + case IB_AE_CQ_ERROR: + case IB_AE_LOCAL_FATAL: + case IB_AE_WQ_REQ_ERROR: + case IB_AE_WQ_ACCESS_ERROR: + { + *async_event = DAT_ASYNC_ERROR_PROVIDER_INTERNAL_ERROR; + break; + } + + /* CATASTROPHIC errors */ + case IB_AE_FLOW_CTRL_ERROR: + case IB_AE_BUF_OVERRUN: + { + *async_event = DAT_ASYNC_ERROR_IA_CATASTROPHIC; + break; + } + default: + { + /* + * Errors we are not interested in reporting: + * IB_AE_QP_APM + * IB_AE_PKEY_TRAP + * IB_AE_QKEY_TRAP + * IB_AE_MKEY_TRAP + * IB_AE_PORT_TRAP + * IB_AE_QP_APM_ERROR + * IB_AE_PORT_ACTIVE + * ... + */ + dat_status = DAT_NOT_IMPLEMENTED; + } + + } + + return dat_status; +} + +/* + * dapls_ib_get_dto_status + * + * Return the DAT status of a DTO operation + * + * Input: + * cqe_ptr pointer to completion queue entry + * + * Output: + * none + * + * Returns: + * Value from ib_status_map table above + */ + +DAT_DTO_COMPLETION_STATUS +dapls_ib_get_dto_status( + IN ib_work_completion_t *cqe_ptr) +{ + ib_uint32_t ib_status; + + ib_status = DAPL_GET_CQE_STATUS (cqe_ptr); + + switch (ib_status) + { + case IB_COMP_ST_SUCCESS : + return DAT_DTO_SUCCESS; + case IB_COMP_ST_LOCAL_LEN_ERR: + return DAT_DTO_ERR_LOCAL_LENGTH; + case IB_COMP_ST_LOCAL_OP_ERR: + return DAT_DTO_ERR_LOCAL_EP; + case IB_COMP_ST_LOCAL_PROTECT_ERR: + return DAT_DTO_ERR_LOCAL_PROTECTION; + case IB_COMP_ST_WR_FLUSHED_ERR: + return DAT_DTO_ERR_FLUSHED; + case IB_COMP_ST_MW_BIND_ERR: + return DAT_RMR_OPERATION_FAILED; + case IB_COMP_ST_REM_ACC_ERR: + return DAT_DTO_ERR_REMOTE_ACCESS; + case IB_COMP_ST_REM_OP_ERR: + return DAT_DTO_ERR_REMOTE_RESPONDER; + case IB_COMP_ST_RNR_COUNTER: + return DAT_DTO_ERR_RECEIVER_NOT_READY; + case IB_COMP_ST_TRANSP_COUNTER: + return DAT_DTO_ERR_TRANSPORT; + case IB_COMP_ST_REM_REQ_ERR: + return DAT_DTO_ERR_REMOTE_RESPONDER; + case IB_COMP_ST_BAD_RESPONSE_ERR: + return DAT_DTO_ERR_BAD_RESPONSE; + case IB_COMP_ST_EE_STATE_ERR: + case IB_COMP_ST_EE_CTX_NO_ERR: + return DAT_DTO_ERR_TRANSPORT; + default: + return DAT_DTO_FAILURE; + } +} + + +/* + * Map all IBAPI DTO completion codes to the DAT equivelent. + * + * dapls_ib_get_dat_event + * + * Return a DAT connection event given a provider CM event. + * + * N.B. Some architectures combine async and CM events into a + * generic async event. In that case, dapls_ib_get_dat_event() + * and dapls_ib_get_async_event() should be entry points that + * call into a common routine. + * + * Input: + * ib_cm_event event provided to the dapl callback routine + * active switch indicating active or passive connection + * + * Output: + * none + * + * Returns: + * DAT_EVENT_NUMBER of translated provider value + */ + +DAT_EVENT_NUMBER +dapls_ib_get_dat_event ( + IN const ib_cm_events_t ib_cm_event, + IN DAT_BOOLEAN active) +{ + DAT_EVENT_NUMBER dat_event_num = 0; + UNREFERENCED_PARAMETER (active); + + switch ( ib_cm_event) + { + case IB_CME_CONNECTED: + dat_event_num = DAT_CONNECTION_EVENT_ESTABLISHED; + break; + case IB_CME_DISCONNECTED: + dat_event_num = DAT_CONNECTION_EVENT_DISCONNECTED; + break; + case IB_CME_DISCONNECTED_ON_LINK_DOWN: + dat_event_num = DAT_CONNECTION_EVENT_DISCONNECTED; + break; + case IB_CME_CONNECTION_REQUEST_PENDING: + dat_event_num = DAT_CONNECTION_REQUEST_EVENT; + break; + case IB_CME_CONNECTION_REQUEST_PENDING_PRIVATE_DATA: + dat_event_num = DAT_CONNECTION_REQUEST_EVENT; + break; + case IB_CME_DESTINATION_REJECT: + dat_event_num = DAT_CONNECTION_EVENT_NON_PEER_REJECTED; + break; + case IB_CME_DESTINATION_REJECT_PRIVATE_DATA: + dat_event_num = DAT_CONNECTION_EVENT_PEER_REJECTED; + break; + case IB_CME_DESTINATION_UNREACHABLE: + dat_event_num = DAT_CONNECTION_EVENT_UNREACHABLE; + break; + case IB_CME_TOO_MANY_CONNECTION_REQUESTS: + dat_event_num = DAT_CONNECTION_EVENT_NON_PEER_REJECTED; + break; + case IB_CME_LOCAL_FAILURE: + dat_event_num = DAT_CONNECTION_EVENT_BROKEN; + break; + case IB_CME_REPLY_RECEIVED: + case IB_CME_REPLY_RECEIVED_PRIVATE_DATA: + default: + break; + } + dapl_dbg_log (DAPL_DBG_TYPE_CM, + " dapls_ib_get_dat_event: event translation: (%s) " + "ib_event 0x%x dat_event 0x%x\n", + active ? "active" : "passive", + ib_cm_event, + dat_event_num); + + return dat_event_num; +} + + +/* + * dapls_ib_get_dat_event + * + * Return a DAT connection event given a provider CM event. + * + * N.B. Some architectures combine async and CM events into a + * generic async event. In that case, dapls_ib_get_cm_event() + * and dapls_ib_get_async_event() should be entry points that + * call into a common routine. + * + * WARNING: In this implementation, there are multiple CM + * events that map to a single DAT event. Be very careful + * with provider routines that depend on this reverse mapping, + * they may have to accomodate more CM events than they + * 'naturally' would. + * + * Input: + * dat_event_num DAT event we need an equivelent CM event for + * + * Output: + * none + * + * Returns: + * ib_cm_event of translated DAPL value + */ +ib_cm_events_t +dapls_ib_get_cm_event ( + IN DAT_EVENT_NUMBER dat_event_num) +{ + ib_cm_events_t ib_cm_event = 0; + + switch (dat_event_num) + { + case DAT_CONNECTION_EVENT_ESTABLISHED: + ib_cm_event = IB_CME_CONNECTED; + break; + case DAT_CONNECTION_EVENT_DISCONNECTED: + ib_cm_event = IB_CME_DISCONNECTED; + break; + case DAT_CONNECTION_REQUEST_EVENT: + ib_cm_event = IB_CME_CONNECTION_REQUEST_PENDING; + break; + case DAT_CONNECTION_EVENT_NON_PEER_REJECTED: + ib_cm_event = IB_CME_DESTINATION_REJECT; + break; + case DAT_CONNECTION_EVENT_PEER_REJECTED: + ib_cm_event = IB_CME_DESTINATION_REJECT_PRIVATE_DATA; + break; + case DAT_CONNECTION_EVENT_UNREACHABLE: + ib_cm_event = IB_CME_DESTINATION_UNREACHABLE; + break; + case DAT_CONNECTION_EVENT_BROKEN: + ib_cm_event = IB_CME_LOCAL_FAILURE; + break; + default: + break; + } + + return ib_cm_event; +} + + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ + diff --git a/branches/WOF2-3/ulp/dapl/dapl/ibal/dapl_ibal_util.h b/branches/WOF2-3/ulp/dapl/dapl/ibal/dapl_ibal_util.h new file mode 100644 index 00000000..c123ebf2 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/ibal/dapl_ibal_util.h @@ -0,0 +1,433 @@ + +/* + * Copyright (c) 2002, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ibal_util.h + * + * PURPOSE: Utility defs & routines for access to Intel IBAL APIs + * + * $Id$ + * + **********************************************************************/ + +#ifndef _DAPL_IBAL_UTIL_H_ +#define _DAPL_IBAL_UTIL_H_ + +#include +#include +#include +#include + +STATIC _INLINE_ DAT_RETURN +dapl_ib_status_convert ( + IN int32_t ib_status); + +/* + * Typedefs to map IBAL types to more generic 'ib' types + */ +typedef ib_net64_t IB_HCA_NAME; +typedef ib_listen_handle_t ib_cm_srvc_handle_t; +typedef ib_ca_handle_t ib_hca_handle_t; +typedef DAT_PVOID ib_cqd_handle_t; +typedef ib_async_event_rec_t ib_error_record_t; +typedef ib_wr_type_t ib_send_op_type_t; +typedef ib_wc_t ib_work_completion_t; +typedef uint32_t ib_hca_port_t; +typedef uint32_t ib_uint32_t; +typedef uint32_t ib_comp_handle_t; +typedef ib_local_ds_t ib_data_segment_t; + +typedef unsigned __int3264 cl_dev_handle_t; + +typedef void (*ib_async_handler_t)( + IN ib_hca_handle_t ib_hca_handle, + IN ib_error_record_t *err_code, + IN void *context); + +typedef ib_net64_t ib_guid_t; +typedef ib_net16_t ib_lid_t; +typedef boolean_t ib_bool_t; + +typedef struct _GID +{ + uint64_t gid_prefix; + uint64_t guid; +} GID; + +typedef enum +{ + IB_CME_CONNECTED, + IB_CME_DISCONNECTED, + IB_CME_DISCONNECTED_ON_LINK_DOWN, + IB_CME_CONNECTION_REQUEST_PENDING, + IB_CME_CONNECTION_REQUEST_PENDING_PRIVATE_DATA, + IB_CME_DESTINATION_REJECT, + IB_CME_DESTINATION_REJECT_PRIVATE_DATA, + IB_CME_DESTINATION_UNREACHABLE, + IB_CME_TOO_MANY_CONNECTION_REQUESTS, + IB_CME_LOCAL_FAILURE, + IB_CME_REPLY_RECEIVED, + IB_CME_REPLY_RECEIVED_PRIVATE_DATA, + IB_CM_LOCAL_FAILURE +} ib_cm_events_t; + +typedef enum +{ + IB_NOTIFY_ON_NEXT_COMP, + IB_NOTIFY_ON_SOLIC_COMP +} ib_notification_type_t; + +typedef struct _ib_hca_name +{ + DAT_NAME_PTR hca_name[DAT_NAME_MAX_LENGTH]; +} ib_hca_name_t; + + +#define IB_INVALID_HANDLE NULL +#define true TRUE +#define false FALSE + +#define IB_MAX_REQ_PDATA_SIZE 92 +#define IB_MAX_REP_PDATA_SIZE 196 +#define IB_MAX_REJ_PDATA_SIZE 148 +#define IB_MAX_DREQ_PDATA_SIZE 220 +#define IB_MAX_DREP_PDATA_SIZE 224 + +/* Resource Not Ready + 1-6 is an actual retry count which is decremented to zero before + an error condition is set. + 7 is 'magic' in that it implies Infinite retry, just keeps trying. +*/ +#define IB_RNR_RETRY_CNT 7 + +/* +IB 1.2 spec, page 331, table 45, RNR NAK timeout encoding (5-bits) + +00000=655.36ms(milliseconds) +00001=0.01ms +00010=0.02ms +00011=0.03ms +00100=0.04ms +00101=0.06ms +00110=0.08ms +00111=0.12ms + +11100=163.84ms 28d +11101=245.76ms 29d +11110=327.68ms 30d +11111=491.52ms 31d +*/ +#define IB_RNR_NAK_TIMEOUT 0 + +typedef void +(*dapl_ibal_pfn_destructor_t)( + IN void* context ); + +typedef struct _dapl_ibal_refs +{ + atomic32_t count; // number of references + void* context; // context for destructor + dapl_ibal_pfn_destructor_t destructor; // called when reference goes to zero + +} dapl_ibal_refs_t; + + +typedef struct _dapl_ibal_root +{ + ib_al_handle_t h_al; // handle to Access Layer + cl_spinlock_t ca_lock; // CA list lock + cl_qlist_t ca_head; // list head of CAs + boolean_t shutdown; // when true, driver is shutting down + boolean_t initialized; // when true, lib is initialized + +} dapl_ibal_root_t; + + +typedef struct _dapl_ibal_ca +{ + cl_list_item_t next; // peer CA list + ib_ca_handle_t h_ca; // handle to open CA + ib_ca_attr_t *p_ca_attr; // CA attributes + uint32_t ca_attr_size;// size of ca attribute + dapl_ibal_refs_t refs; // reference counting + cl_spinlock_t port_lock; // port list lock + cl_qlist_t port_head; // port list head for this CA + cl_spinlock_t evd_cb_lock; // EVD async error cb list lock + cl_qlist_t evd_cb_head; // EVD async error cb list head for this CA + cl_dev_handle_t mlnx_device; + DAT_PVOID *ia_ptr; // hook for CA async callbacks + +} dapl_ibal_ca_t; + + +typedef struct _dapl_ibal_port +{ + cl_list_item_t next; // peer CA list + dapl_ibal_ca_t *ca; // pointer to parent CA + ib_port_attr_t *p_attr; // port attributes + dapl_ibal_refs_t refs; // reference counting +} dapl_ibal_port_t; + +typedef struct _dapl_ibal_evd_cb +{ + cl_list_item_t next; // peer CA list + ib_async_handler_t pfn_async_err_cb; + ib_async_handler_t pfn_async_qp_err_cb; + ib_async_handler_t pfn_async_cq_err_cb; + void *context; +} dapl_ibal_evd_cb_t; + +/* + * Definitions to map DTO OPs + */ +#define OP_RDMA_READ WR_RDMA_READ +#define OP_RDMA_WRITE WR_RDMA_WRITE +#define OP_SEND WR_SEND +#define OP_COMP_AND_SWAP WR_COMPARE_SWAP +#define OP_FETCH_AND_ADD WR_FETCH_ADD +#define OP_RECEIVE 6 /* no-equip */ +#define OP_BIND_MW 7 /* no-equip */ + +/* + * Definitions to map QP state + */ +#define IB_QP_STATE_RESET IB_QPS_RESET +#define IB_QP_STATE_INIT IB_QPS_INIT +#define IB_QP_STATE_RTR IB_QPS_RTR +#define IB_QP_STATE_RTS IB_QPS_RTS +#define IB_QP_STATE_SQE IB_QPS_SQERR +#define IB_QP_STATE_SQD IB_QPS_SQD +#define IB_QP_STATE_ERROR IB_QPS_ERROR + +/* + * Definitions to map Memory OPs + */ +#define IB_ACCESS_LOCAL_WRITE IB_AC_LOCAL_WRITE +#define IB_ACCESS_REMOTE_READ IB_AC_RDMA_READ +#define IB_ACCESS_REMOTE_WRITE IB_AC_RDMA_WRITE + +/* + * CQE status + */ +enum _dapl_comp_status +{ + IB_COMP_ST_SUCCESS = IB_WCS_SUCCESS, + IB_COMP_ST_LOCAL_LEN_ERR = IB_WCS_LOCAL_LEN_ERR, + IB_COMP_ST_LOCAL_OP_ERR = IB_WCS_LOCAL_OP_ERR, + IB_COMP_ST_LOCAL_PROTECT_ERR = IB_WCS_LOCAL_PROTECTION_ERR, + IB_COMP_ST_WR_FLUSHED_ERR = IB_WCS_WR_FLUSHED_ERR, + IB_COMP_ST_MW_BIND_ERR = IB_WCS_MEM_WINDOW_BIND_ERR, + IB_COMP_ST_REM_ACC_ERR = IB_WCS_REM_ACCESS_ERR, + IB_COMP_ST_REM_OP_ERR = IB_WCS_REM_OP_ERR, + IB_COMP_ST_RNR_COUNTER = IB_WCS_RNR_RETRY_ERR, + IB_COMP_ST_TRANSP_COUNTER = IB_WCS_TIMEOUT_RETRY_ERR, + IB_COMP_ST_REM_REQ_ERR = IB_WCS_REM_INVALID_REQ_ERR, + IB_COMP_ST_BAD_RESPONSE_ERR = IB_WCS_UNMATCHED_RESPONSE, + IB_COMP_ST_EE_STATE_ERR, + IB_COMP_ST_EE_CTX_NO_ERR +}; + + +/* + * Macro to check the state of an EP/QP + */ +#define DAPLIB_NEEDS_INIT(ep) ((ep)->qp_state == IB_QPS_ERROR) + + +/* + * Resolve IBAL return codes to their DAPL equivelent. + * Do not return invalid Handles, the user is not able + * to deal with them. + */ +STATIC _INLINE_ DAT_RETURN +dapl_ib_status_convert ( + IN int32_t ib_status) +{ + switch ( ib_status ) + { + case IB_SUCCESS: + { + return DAT_SUCCESS; + } + case IB_INSUFFICIENT_RESOURCES: + case IB_INSUFFICIENT_MEMORY: + case IB_RESOURCE_BUSY: + { + return DAT_INSUFFICIENT_RESOURCES; + } + case IB_INVALID_CA_HANDLE: + case IB_INVALID_CQ_HANDLE: + case IB_INVALID_QP_HANDLE: + case IB_INVALID_PD_HANDLE: + case IB_INVALID_MR_HANDLE: + case IB_INVALID_MW_HANDLE: + case IB_INVALID_AL_HANDLE: + case IB_INVALID_AV_HANDLE: + { + return DAT_INVALID_HANDLE; + } + case IB_INVALID_PKEY: + { + return DAT_PROTECTION_VIOLATION; + } + case IB_INVALID_LKEY: + case IB_INVALID_RKEY: + case IB_INVALID_PERMISSION: + { + return DAT_PRIVILEGES_VIOLATION; + } + case IB_INVALID_MAX_WRS: + case IB_INVALID_MAX_SGE: + case IB_INVALID_CQ_SIZE: + case IB_INVALID_SETTING: + case IB_INVALID_SERVICE_TYPE: + case IB_INVALID_GID: + case IB_INVALID_LID: + case IB_INVALID_GUID: + case IB_INVALID_PARAMETER: + { + return DAT_INVALID_PARAMETER; + } + case IB_INVALID_QP_STATE: + case IB_INVALID_APM_STATE: + case IB_INVALID_PORT_STATE: + case IB_INVALID_STATE: + { + return DAT_INVALID_STATE; + } + case IB_NOT_FOUND: + { + return DAT_QUEUE_EMPTY; + } + case IB_OVERFLOW: + { + return DAT_QUEUE_FULL; + } + case IB_UNSUPPORTED: + { + return DAT_NOT_IMPLEMENTED; + } + case IB_TIMEOUT: + { + return DAT_TIMEOUT_EXPIRED; + } + case IB_CANCELED: + { + return DAT_ABORT; + } + default: + { + return DAT_INTERNAL_ERROR; + } + } +} + +#define TAKE_LOCK( lock ) \ + cl_spinlock_acquire( &(lock) ) + +#define RELEASE_LOCK( lock ) \ + cl_spinlock_release( &(lock) ) + +#define LOCK_INSERT_HEAD( lock, head, item ) \ +{ \ + TAKE_LOCK( lock ); \ + cl_qlist_insert_head( &head, (cl_list_item_t*)(&item) ); \ + RELEASE_LOCK( lock ); \ +} + +#define LOCK_INSERT_TAIL( lock, tail, item ) \ +{ \ + TAKE_LOCK( lock ); \ + cl_qlist_insert_tail( &tail, (cl_list_item_t*)(&item) ); \ + RELEASE_LOCK( lock ); \ +} + +#define INIT_REFERENCE( p_ref, n, con, destruct ) \ +{ \ + (p_ref)->count = n; \ + (p_ref)->context = con; \ + (p_ref)->destructor = destruct; \ +} + +#define TAKE_REFERENCE( p_ref ) \ + cl_atomic_inc( &(p_ref)->count ) + +#define REMOVE_REFERENCE( p_ref ) \ +{ \ + if ( cl_atomic_dec( &(p_ref)->count ) == 0 ) \ + if ( (p_ref)->destructor ) \ + (p_ref)->destructor( (p_ref)->context ); \ +} + + +/* + * Prototype + */ + +extern ib_api_status_t +dapls_modify_qp_state_to_error ( + ib_qp_handle_t qp_handle ); + +extern ib_api_status_t +dapls_modify_qp_state_to_reset ( + ib_qp_handle_t); + +extern ib_api_status_t +dapls_modify_qp_state_to_init ( + ib_qp_handle_t, DAT_EP_ATTR *, dapl_ibal_port_t *); + +extern ib_api_status_t +dapls_modify_qp_state_to_rtr ( + ib_qp_handle_t, ib_net32_t, ib_lid_t, dapl_ibal_port_t *); + +extern ib_api_status_t +dapls_modify_qp_state_to_rts ( + ib_qp_handle_t); + +extern void +dapli_ibal_ca_async_error_callback( + IN ib_async_event_rec_t* p_err_rec ); + +extern dapl_ibal_port_t * +dapli_ibal_get_port ( + IN dapl_ibal_ca_t *p_ca, + IN uint8_t port_num); + +extern int32_t dapls_ib_init (void); +extern int32_t dapls_ib_release (void); + +extern dapl_ibal_evd_cb_t * +dapli_find_evd_cb_by_context( + IN void *context, + IN dapl_ibal_ca_t *ca); + +extern IB_HCA_NAME +dapl_ib_convert_name( + IN char *name); + +#endif /* _DAPL_IBAL_UTIL_H_ */ diff --git a/branches/WOF2-3/ulp/dapl/dapl/include/dapl.h b/branches/WOF2-3/ulp/dapl/dapl/include/dapl.h new file mode 100644 index 00000000..6c377931 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/include/dapl.h @@ -0,0 +1,1042 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl.h + * + * PURPOSE: defines common data structures for the DAPL reference implemenation + * + * Description: This file describes the working data structures used within + * DAPL RI. + * + * + * $Id$ + **********************************************************************/ + +#ifndef _DAPL_H_ +#define _DAPL_H_ + +#include +#include +#include "dapl_osd.h" +#include "dapl_debug.h" + +#ifdef IBAPI +#include "dapl_ibapi_util.h" +#elif VAPI +#include "dapl_vapi_util.h" +#else +#include "dapl_ibal_util.h" +#endif + +/********************************************************************* + * * + * Enumerations * + * * + *********************************************************************/ + +typedef enum dapl_magic +{ + /* magic number values for verification & debug */ + DAPL_MAGIC_IA = 0xCafeF00d, + DAPL_MAGIC_EVD = 0xFeedFace, + DAPL_MAGIC_EP = 0xDeadBabe, + DAPL_MAGIC_LMR = 0xBeefCafe, + DAPL_MAGIC_RMR = 0xABadCafe, + DAPL_MAGIC_PZ = 0xDeafBeef, + DAPL_MAGIC_PSP = 0xBeadeD0c, + DAPL_MAGIC_RSP = 0xFab4Feed, + DAPL_MAGIC_CR = 0xBe12Cee1, + DAPL_MAGIC_CR_DESTROYED = 0xB12bDead, + DAPL_MAGIC_CNO = 0xDeadF00d, + DAPL_MAGIC_EP_EXIT = 0xBabeDead, + DAPL_MAGIC_INVALID = 0xFFFFFFFF +} DAPL_MAGIC; + +typedef enum dapl_evd_state +{ + DAPL_EVD_STATE_TERMINAL, + DAPL_EVD_STATE_INITIAL, + DAPL_EVD_STATE_OPEN, + DAPL_EVD_STATE_WAITED, + DAPL_EVD_STATE_DEAD = 0xDEAD +} DAPL_EVD_STATE; + +typedef enum dapl_evd_completion +{ + DAPL_EVD_STATE_INIT, + DAPL_EVD_STATE_SOLICITED_WAIT, + DAPL_EVD_STATE_THRESHOLD, + DAPL_EVD_STATE_UNSIGNALLED +} DAPL_EVD_COMPLETION; + +typedef enum dapl_cno_state +{ + DAPL_CNO_STATE_UNTRIGGERED, + DAPL_CNO_STATE_TRIGGERED, + DAPL_CNO_STATE_DEAD = 0xDeadFeed, +} DAPL_CNO_STATE; + +typedef enum dapl_qp_state +{ + DAPL_QP_STATE_UNCONNECTED, + DAPL_QP_STATE_RESERVED, + DAPL_QP_STATE_PASSIVE_CONNECTION_PENDING, + DAPL_QP_STATE_ACTIVE_CONNECTION_PENDING, + DAPL_QP_STATE_TENTATIVE_CONNECTION_PENDING, + DAPL_QP_STATE_CONNECTED, + DAPL_QP_STATE_DISCONNECT_PENDING, + DAPL_QP_STATE_ERROR, + DAPL_QP_STATE_NOT_REUSABLE, + DAPL_QP_STATE_FREE +} DAPL_QP_STATE; + + +/********************************************************************* + * * + * Constants * + * * + *********************************************************************/ + +/* + * number of HCAs allowed + */ +#define DAPL_MAX_HCA_COUNT 4 + +/* + * Configures the RMR bind evd restriction + */ + +#define DAPL_RMR_BIND_EVD_RESTRICTION DAT_RMR_EVD_SAME_AS_REQUEST_EVD + +/* + * special qp_state indicating the EP does not have a QP attached yet + */ +#define DAPL_QP_STATE_UNATTACHED 0xFFF0 + +#define DAPL_MAX_PRIVATE_DATA_SIZE 256 + +/********************************************************************* + * * + * Macros * + * * + *********************************************************************/ + +/* + * Simple macro to verify a handle is bad. Conditions: + * - pointer is NULL + * - pointer is not word aligned + * - pointer's magic number is wrong + */ +#define DAPL_BAD_HANDLE(h, magicNum) ( \ + ((h) == NULL) || \ + ((DAT_UVERYLONG)(h) & 3) || \ + (((DAPL_HEADER *)(h))->magic != (magicNum))) + +#define DAPL_MIN(a, b) ((a < b) ? (a) : (b)) +#define DAPL_MAX(a, b) ((a > b) ? (a) : (b)) + +#if NDEBUG > 0 +#define DEBUG_IS_BAD_HANDLE(h, magicNum) (DAPL_BAD_HANDLE(h, magicNum)) +#else +#define DEBUG_IS_BAD_HANDLE(h, magicNum) (0) +#endif + +#define DAT_ERROR(Type, SubType) ((DAT_RETURN)(DAT_CLASS_ERROR | Type | SubType)) + +/********************************************************************* + * * + * Typedefs * + * * + *********************************************************************/ + +typedef struct dapl_llist_entry DAPL_LLIST_ENTRY; +typedef DAPL_LLIST_ENTRY * DAPL_LLIST_HEAD; +typedef struct dapl_ring_buffer DAPL_RING_BUFFER; +typedef struct dapl_cookie_buffer DAPL_COOKIE_BUFFER; + +typedef struct dapl_hash_table DAPL_HASH_TABLE; +typedef struct dapl_hash_table *DAPL_HASH_TABLEP; +typedef DAT_UINT64 DAPL_HASH_KEY; +typedef void * DAPL_HASH_DATA; + +typedef struct dapl_hca DAPL_HCA; + +typedef struct dapl_header DAPL_HEADER; + +typedef struct dapl_ia DAPL_IA; +typedef struct dapl_cno DAPL_CNO; +typedef struct dapl_evd DAPL_EVD; +typedef struct dapl_ep DAPL_EP; +typedef struct dapl_pz DAPL_PZ; +typedef struct dapl_lmr DAPL_LMR; +typedef struct dapl_rmr DAPL_RMR; +typedef struct dapl_sp DAPL_SP; +typedef struct dapl_cr DAPL_CR; + +typedef struct dapl_cookie DAPL_COOKIE; +typedef struct dapl_dto_cookie DAPL_DTO_COOKIE; +typedef struct dapl_rmr_cookie DAPL_RMR_COOKIE; + +typedef struct dapl_private DAPL_PRIVATE; + +typedef void (*DAPL_CONNECTION_STATE_HANDLER) ( + IN DAPL_EP *, + IN ib_cm_events_t, + IN const void *, + OUT DAT_EVENT *); + + +/********************************************************************* + * * + * Structures * + * * + *********************************************************************/ + +struct dapl_llist_entry +{ + struct dapl_llist_entry *flink; + struct dapl_llist_entry *blink; + void *data; + DAPL_LLIST_HEAD *list_head; /* for consistency checking */ +}; + +struct dapl_ring_buffer +{ + void **base; /* base of element array */ + DAT_COUNT lim; /* mask, number of entries - 1 */ + DAPL_ATOMIC head; /* head pointer index */ + DAPL_ATOMIC tail; /* tail pointer index */ +}; + +struct dapl_cookie_buffer +{ + DAPL_OS_LOCK lock; + DAPL_COOKIE *pool; + DAT_COUNT pool_size; + DAPL_ATOMIC head; + DAPL_ATOMIC tail; +}; + +struct dapl_hca +{ + DAPL_OS_LOCK lock; + DAPL_LLIST_HEAD ia_list_head; + DAPL_EVD *async_evd; + DAPL_EVD *async_error_evd; + DAT_SOCK_ADDR6 hca_address; /* local address of HCA*/ + /* Values specific to IB OS API */ + IB_HCA_NAME name; + ib_hca_handle_t ib_hca_handle; + DAPL_ATOMIC handle_ref_count; /* count of ia_opens on handle */ + ib_hca_port_t port_num; /* number of physical port */ + ib_uint32_t partition_max; + ib_guid_t node_GUID; + ib_lid_t lid; + ib_cqd_handle_t ib_cqd_handle; /* cq domain handle */ + ib_cq_handle_t null_ib_cq_handle; /* CQ handle with 0 entries */ + /* Memory Subsystem Support */ + DAPL_HASH_TABLE *lmr_hash_table; + /* Limits & useful HCA attributes */ + DAT_IA_ATTR ia_attr; + /* Name service support */ + void *name_service_handle; /* handle to name service */ +}; + +/* DAPL Objects always have the following header */ +struct dapl_header +{ + DAT_PROVIDER *provider; /* required by DAT - must be first */ + DAPL_MAGIC magic; /* magic number for verification */ + DAT_HANDLE_TYPE handle_type; /* struct type */ + DAPL_IA *owner_ia; /* ia which owns this stuct */ + DAPL_LLIST_ENTRY ia_list_entry; /* link entry on ia struct */ + DAT_CONTEXT user_context; /* user context - opaque to DAPL */ + DAPL_OS_LOCK lock; /* lock - in header for easier macros */ +}; + +/* DAPL_IA maps to DAT_IA_HANDLE */ +struct dapl_ia +{ + DAPL_HEADER header; + DAPL_HCA *hca_ptr; + DAPL_EVD *async_error_evd; + DAT_BOOLEAN cleanup_async_error_evd; + + DAPL_LLIST_ENTRY hca_ia_list_entry; /* HCAs list of IAs */ + DAPL_LLIST_HEAD ep_list_head; /* EP queue */ + DAPL_LLIST_HEAD lmr_list_head; /* LMR queue */ + DAPL_LLIST_HEAD rmr_list_head; /* RMR queue */ + DAPL_LLIST_HEAD pz_list_head; /* PZ queue */ + DAPL_LLIST_HEAD evd_list_head; /* EVD queue */ + DAPL_LLIST_HEAD cno_list_head; /* CNO queue */ + DAPL_LLIST_HEAD psp_list_head; /* PSP queue */ + DAPL_LLIST_HEAD rsp_list_head; /* RSP queue */ +}; + +/* DAPL_CNO maps to DAT_CNO_HANDLE */ +struct dapl_cno +{ + DAPL_HEADER header; + + /* A CNO cannot be freed while it is referenced elsewhere. */ + DAPL_ATOMIC cno_ref_count; + DAPL_CNO_STATE cno_state; + + DAT_COUNT cno_waiters; + DAPL_EVD *cno_evd_triggered; + DAT_OS_WAIT_PROXY_AGENT cno_wait_agent; + + DAPL_OS_WAIT_OBJECT cno_wait_object; +}; + +/* DAPL_EVD maps to DAT_EVD_HANDLE */ +struct dapl_evd +{ + DAPL_HEADER header; + + DAPL_EVD_STATE evd_state; + DAT_EVD_FLAGS evd_flags; + DAT_BOOLEAN evd_enabled; /* For attached CNO. */ + DAT_BOOLEAN evd_waitable; /* EVD state. */ + + /* Derived from evd_flags; see dapls_evd_internal_create. */ + DAT_BOOLEAN evd_producer_locking_needed; + + /* Every EVD has a CQ unless it is a SOFTWARE_EVENT only EVD */ + ib_cq_handle_t ib_cq_handle; + + /* Mellanox Specific completion handle for registration/de-registration */ + ib_comp_handle_t ib_comp_handle; + + /* An Event Dispatcher cannot be freed while + * it is referenced elsewhere. + */ + DAPL_ATOMIC evd_ref_count; + + /* Set if there has been a catastrophic overflow */ + DAT_BOOLEAN catastrophic_overflow; + + /* the actual events */ + DAT_COUNT qlen; + DAT_EVENT *events; + DAPL_RING_BUFFER free_event_queue; + DAPL_RING_BUFFER pending_event_queue; + + /* CQ Completions are not placed into 'deferred_events' + ** rather they are simply left on the Completion Queue + ** and the fact that there was a notification is flagged. + */ + DAT_BOOLEAN cq_notified; + DAPL_OS_TICKS cq_notified_when; + cl_waitobj_handle_t cq_wait_obj_handle; + + DAT_COUNT cno_active_count; + DAPL_CNO *cno_ptr; + + DAPL_OS_WAIT_OBJECT wait_object; + DAT_COUNT threshold; + DAPL_EVD_COMPLETION completion_type; +}; + + + +/* uDAPL timer entry, used to queue timeouts */ +struct dapl_timer_entry +{ + DAPL_LLIST_ENTRY list_entry; /* link entry on ia struct */ + DAPL_OS_TIMEVAL expires; + void (*function)(void*); + void *data; +}; + +#ifdef DAPL_DBG_IO_TRC + +#define DBG_IO_TRC_QLEN 32 /* length of trace buffer */ +#define DBG_IO_TRC_IOV 3 /* iov elements we keep track of */ + +struct io_buf_track +{ + Ib_send_op_type op_type; + DAPL_COOKIE *cookie; + DAT_LMR_TRIPLET iov[DBG_IO_TRC_IOV]; + DAT_RMR_TRIPLET remote_iov; + unsigned int done; /* count to track completion ordering */ + int status; + void *wqe; +}; + +#endif /* DAPL_DBG_IO_TRC */ + +/* DAPL_EP maps to DAT_EP_HANDLE */ +struct dapl_ep +{ + DAPL_HEADER header; + /* What the DAT Consumer asked for */ + DAT_EP_PARAM param; + + /* The RC Queue Pair (IBM OS API) */ + ib_qp_handle_t qp_handle; + unsigned int qpn; /* qp number */ + ib_qp_state_t qp_state; + + /* communications manager handle (IBM OS API) */ + ib_cm_handle_t cm_handle; + /* store the remote IA address here, reference from the param + * struct which only has a pointer, no storage + */ + DAT_SOCK_ADDR6 remote_ia_address; + + /* For passive connections we maintain a back pointer to the CR */ + void * cr_ptr; + + /* pointer to connection timer, if set */ + struct dapl_timer_entry *cxn_timer; + + /* private data container */ + unsigned char private_data[DAPL_MAX_PRIVATE_DATA_SIZE]; + + /* DTO data */ + DAPL_ATOMIC req_count; + DAPL_ATOMIC recv_count; + + DAPL_COOKIE_BUFFER req_buffer; + DAPL_COOKIE_BUFFER recv_buffer; + + ib_data_segment_t *recv_iov; + DAT_COUNT recv_iov_num; + + ib_data_segment_t *send_iov; + DAT_COUNT send_iov_num; + DAT_BOOLEAN recv_discreq; + DAT_BOOLEAN sent_discreq; + DAT_BOOLEAN viol_order; + DAPL_RING_BUFFER viol_event_queue; +#ifdef DAPL_DBG_IO_TRC + int ibt_dumped; + struct io_buf_track *ibt_base; + DAPL_RING_BUFFER ibt_queue; +#endif /* DAPL_DBG_IO_TRC */ +}; + +/* DAPL_PZ maps to DAT_PZ_HANDLE */ +struct dapl_pz +{ + DAPL_HEADER header; + ib_pd_handle_t pd_handle; + DAPL_ATOMIC pz_ref_count; +}; + +/* DAPL_LMR maps to DAT_LMR_HANDLE */ +struct dapl_lmr +{ + DAPL_HEADER header; + DAT_LMR_PARAM param; + ib_mr_handle_t mr_handle; + DAPL_ATOMIC lmr_ref_count; + ib_shmid_t ib_shmid; +}; + +/* DAPL_RMR maps to DAT_RMR_HANDLE */ +struct dapl_rmr +{ + DAPL_HEADER header; + DAT_RMR_PARAM param; + DAPL_EP *ep; + DAPL_PZ *pz; + DAPL_LMR *lmr; + ib_mw_handle_t mw_handle; +}; + +/* SP types, indicating the state and queue */ +typedef enum dapl_sp_state +{ + DAPL_SP_STATE_FREE, + DAPL_SP_STATE_PSP_LISTENING, + DAPL_SP_STATE_PSP_PENDING, + DAPL_SP_STATE_RSP_LISTENING, + DAPL_SP_STATE_RSP_PENDING +} DAPL_SP_STATE; + +/* DAPL_SP maps to DAT_PSP_HANDLE and DAT_RSP_HANDLE */ +struct dapl_sp +{ + DAPL_HEADER header; + DAPL_SP_STATE state; /* type and queue of the SP */ + + /* PSP/RSP PARAM fields */ + DAT_IA_HANDLE ia_handle; + DAT_CONN_QUAL conn_qual; + DAT_EVD_HANDLE evd_handle; + DAT_PSP_FLAGS psp_flags; + DAT_EP_HANDLE ep_handle; + + /* wait object needed for SP destroy */ + DAPL_OS_WAIT_OBJECT wait_object; + + /* maintenence fields */ + DAT_BOOLEAN listening; /* PSP is registered & active */ + ib_cm_srvc_handle_t cm_srvc_handle; /* Used by VAPI CM */ + DAPL_LLIST_HEAD cr_list_head; /* CR pending queue */ + DAT_COUNT cr_list_count; /* count of CRs on queue */ +}; + +/* DAPL_CR maps to DAT_CR_HANDLE */ +struct dapl_cr +{ + DAPL_HEADER header; + + /* for convenience the data is kept as a DAT_CR_PARAM. + * however, the "local_endpoint" field is always NULL + * so this wastes a pointer. This is probably ok to + * simplify code, espedially dat_cr_query. + */ + DAT_CR_PARAM param; + /* IB specific fields */ + ib_cm_handle_t ib_cm_handle; + + DAT_SOCK_ADDR6 remote_ia_address; + /* Assuming that the maximum private data size is small. + * If it gets large, use of a pointer may be appropriate. + */ + unsigned char private_data[DAPL_MAX_PRIVATE_DATA_SIZE]; + /* + * Need to be able to associate the CR back to the PSP for + * dapl_cr_reject. + */ + DAPL_SP *sp_ptr; +}; + +typedef enum dapl_dto_type +{ + DAPL_DTO_TYPE_SEND, + DAPL_DTO_TYPE_RECV, + DAPL_DTO_TYPE_RDMA_WRITE, + DAPL_DTO_TYPE_RDMA_READ, +} DAPL_DTO_TYPE; + +typedef enum dapl_cookie_type +{ + DAPL_COOKIE_TYPE_NULL, + DAPL_COOKIE_TYPE_DTO, + DAPL_COOKIE_TYPE_RMR, +} DAPL_COOKIE_TYPE; + +/* DAPL_DTO_COOKIE used as context for DTO WQEs */ +struct dapl_dto_cookie +{ + DAPL_DTO_TYPE type; + DAT_DTO_COOKIE cookie; + DAT_COUNT size; /* used for SEND and RDMA write */ +}; + +/* DAPL_RMR_COOKIE used as context for bind WQEs */ +struct dapl_rmr_cookie +{ + DAPL_RMR *rmr; + DAT_RMR_COOKIE cookie; +}; + +/* DAPL_COOKIE used as context for WQEs */ +struct dapl_cookie +{ + DAPL_COOKIE_TYPE type; /* Must be first, to define struct. */ + DAPL_EP *ep; + DAT_COUNT index; + union + { + DAPL_DTO_COOKIE dto; + DAPL_RMR_COOKIE rmr; + } val; +}; + +/* DAPL_PRIVATE used to pass private data in a connection */ +struct dapl_private +{ +#ifdef NO_NAME_SERVICE + DAT_SOCK_ADDR6 hca_address; /* local address of HCA*/ +#endif + unsigned char private_data[DAPL_MAX_PRIVATE_DATA_SIZE]; +}; + +/* + * Private Data operations. Used to obtain the size of the private + * data from the provider layer. + */ +typedef enum dapl_private_data_op +{ + DAPL_PDATA_CONN_REQ = 0, /* connect request */ + DAPL_PDATA_CONN_REP = 1, /* connect reply */ + DAPL_PDATA_CONN_REJ = 2, /* connect reject */ + DAPL_PDATA_CONN_DREQ = 3, /* disconnect request */ + DAPL_PDATA_CONN_DREP = 4, /* disconnect reply */ +} DAPL_PDATA_OP; + + +/* + * Generic HCA name field + */ +#define DAPL_HCA_NAME_MAX_LEN 260 +typedef char DAPL_HCA_NAME[DAPL_HCA_NAME_MAX_LEN+1]; + +#ifdef NO_NAME_SERVICE + +/* + * Simple mapping table to match IP addresses to GIDs. Loaded + * by dapl_init. + */ +typedef struct _dapl_gid_map_table { + uint32_t ip_address; + GID gid; +} DAPL_GID_MAP; + +#endif /* NO_NAME_SERVICE */ + +/* + * IBTA defined reason for reject message: See IBTA 1.1 specification, + * 12.6.7.2 REJECTION REASON section. + */ +#define IB_CM_REJ_REASON_CONSUMER_REJ 0x001C + + +#if defined(DAPL_DBG_IO_TRC) +/********************************************************************* + * * + * Debug I/O tracing support prototypes * + * * + *********************************************************************/ +/* + * I/O tracing support + */ +void dapls_io_trc_alloc ( + DAPL_EP *ep_ptr); + +void dapls_io_trc_update_completion ( + DAPL_EP *ep_ptr, + DAPL_COOKIE *cookie, + ib_uint32_t ib_status ); + +void dapls_io_trc_dump ( + DAPL_EP *ep_ptr, + ib_work_completion_t *cqe_ptr, + ib_uint32_t ib_status); + +#else /* DAPL_DBG_IO_TRC */ + +#define dapls_io_trc_alloc(a) +#define dapls_io_trc_update_completion(a, b, c) +#define dapls_io_trc_dump(a, b, c) + +#endif /* DAPL_DBG_IO_TRC */ + + +/********************************************************************* + * * + * Function Prototypes * + * * + *********************************************************************/ + +/* + * DAT Mandated functions + */ + +extern DAT_RETURN DAT_API dapl_ia_open ( + IN const DAT_NAME_PTR, /* name */ + IN DAT_COUNT, /* asynch_evd_qlen */ + INOUT DAT_EVD_HANDLE *, /* asynch_evd_handle */ + OUT DAT_IA_HANDLE * ); /* ia_handle */ + +extern DAT_RETURN DAT_API dapl_ia_close ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_CLOSE_FLAGS ); /* ia_flags */ + + +extern DAT_RETURN DAT_API dapl_ia_query ( + IN DAT_IA_HANDLE, /* ia handle */ + OUT DAT_EVD_HANDLE *, /* async_evd_handle */ + IN DAT_IA_ATTR_MASK, /* ia_params_mask */ + OUT DAT_IA_ATTR *, /* ia_params */ + IN DAT_PROVIDER_ATTR_MASK, /* provider_params_mask */ + OUT DAT_PROVIDER_ATTR * ); /* provider_params */ + + +/* helper functions */ + +extern DAT_RETURN DAT_API dapl_set_consumer_context ( + IN DAT_HANDLE, /* dat handle */ + IN DAT_CONTEXT); /* context */ + +extern DAT_RETURN DAT_API dapl_get_consumer_context ( + IN DAT_HANDLE, /* dat handle */ + OUT DAT_CONTEXT * ); /* context */ + +extern DAT_RETURN DAT_API dapl_get_handle_type ( + IN DAT_HANDLE, + OUT DAT_HANDLE_TYPE * ); + +/* CNO functions */ + +extern DAT_RETURN DAT_API dapl_cno_create ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_OS_WAIT_PROXY_AGENT, /* agent */ + OUT DAT_CNO_HANDLE *); /* cno_handle */ + +extern DAT_RETURN DAT_API dapl_cno_modify_agent ( + IN DAT_CNO_HANDLE, /* cno_handle */ + IN DAT_OS_WAIT_PROXY_AGENT); /* agent */ + +extern DAT_RETURN DAT_API dapl_cno_query ( + IN DAT_CNO_HANDLE, /* cno_handle */ + IN DAT_CNO_PARAM_MASK, /* cno_param_mask */ + OUT DAT_CNO_PARAM * ); /* cno_param */ + +extern DAT_RETURN DAT_API dapl_cno_free ( + IN DAT_CNO_HANDLE); /* cno_handle */ + +extern DAT_RETURN DAT_API dapl_cno_wait ( + IN DAT_CNO_HANDLE, /* cno_handle */ + IN DAT_TIMEOUT, /* timeout */ + OUT DAT_EVD_HANDLE *); /* evd_handle */ + +/* CR Functions */ + +extern DAT_RETURN DAT_API dapl_cr_query ( + IN DAT_CR_HANDLE, /* cr_handle */ + IN DAT_CR_PARAM_MASK, /* cr_args_mask */ + OUT DAT_CR_PARAM * ); /* cwr_args */ + +extern DAT_RETURN DAT_API dapl_cr_accept ( + IN DAT_CR_HANDLE, /* cr_handle */ + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_COUNT, /* private_data_size */ + IN const DAT_PVOID ); /* private_data */ + +extern DAT_RETURN DAT_API dapl_cr_reject ( + IN DAT_CR_HANDLE ); + +extern DAT_RETURN DAT_API dapl_cr_handoff ( + IN DAT_CR_HANDLE, /* cr_handle */ + IN DAT_CONN_QUAL); /* handoff */ + +/* EVD Functions */ + +extern DAT_RETURN DAT_API dapl_evd_create ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_COUNT, /* evd_min_qlen */ + IN DAT_CNO_HANDLE, /* cno_handle */ + IN DAT_EVD_FLAGS, /* evd_flags */ + OUT DAT_EVD_HANDLE * ); /* evd_handle */ + +extern DAT_RETURN DAT_API dapl_evd_query ( + IN DAT_EVD_HANDLE, /* evd_handle */ + IN DAT_EVD_PARAM_MASK, /* evd_args_mask */ + OUT DAT_EVD_PARAM * ); /* evd_args */ + +extern DAT_RETURN DAT_API dapl_evd_modify_cno ( + IN DAT_EVD_HANDLE, /* evd_handle */ + IN DAT_CNO_HANDLE); /* cno_handle */ + +extern DAT_RETURN DAT_API dapl_evd_enable ( + IN DAT_EVD_HANDLE); /* evd_handle */ + +extern DAT_RETURN DAT_API dapl_evd_disable ( + IN DAT_EVD_HANDLE); /* evd_handle */ + +extern DAT_RETURN DAT_API dapl_evd_wait ( + IN DAT_EVD_HANDLE, /* evd_handle */ + IN DAT_TIMEOUT, /* timeout */ + IN DAT_COUNT, /* threshold */ + OUT DAT_EVENT *, /* event */ + OUT DAT_COUNT *); /* nmore */ + +extern DAT_RETURN DAT_API dapl_evd_resize ( + IN DAT_EVD_HANDLE, /* evd_handle */ + IN DAT_COUNT ); /* evd_qlen */ + +extern DAT_RETURN DAT_API dapl_evd_wait ( + IN DAT_EVD_HANDLE, /* evd_handle */ + IN DAT_TIMEOUT, /* timeout */ + IN DAT_COUNT, /* threshold */ + OUT DAT_EVENT *, /* event */ + OUT DAT_COUNT *); /* nmore */ + +extern DAT_RETURN DAT_API dapl_evd_post_se ( + DAT_EVD_HANDLE, /* evd_handle */ + const DAT_EVENT * ); /* event */ + +extern DAT_RETURN DAT_API dapl_evd_dequeue ( + IN DAT_EVD_HANDLE, /* evd_handle */ + OUT DAT_EVENT * ); /* event */ + +extern DAT_RETURN DAT_API dapl_evd_free ( + IN DAT_EVD_HANDLE ); + +extern DAT_RETURN DAT_API +dapl_evd_set_unwaitable ( + IN DAT_EVD_HANDLE evd_handle ); + +extern DAT_RETURN DAT_API +dapl_evd_clear_unwaitable ( + IN DAT_EVD_HANDLE evd_handle ); + +/* EP functions */ + +extern DAT_RETURN DAT_API dapl_ep_create ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_PZ_HANDLE, /* pz_handle */ + IN DAT_EVD_HANDLE, /* in_dto_completion_evd_handle */ + IN DAT_EVD_HANDLE, /* out_dto_completion_evd_handle */ + IN DAT_EVD_HANDLE, /* connect_evd_handle */ + IN const DAT_EP_ATTR *, /* ep_parameters */ + OUT DAT_EP_HANDLE * ); /* ep_handle */ + +extern DAT_RETURN DAT_API dapl_ep_query ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_EP_PARAM_MASK, /* ep_args_mask */ + OUT DAT_EP_PARAM * ); /* ep_args */ + +extern DAT_RETURN DAT_API dapl_ep_modify ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_EP_PARAM_MASK, /* ep_args_mask */ + IN const DAT_EP_PARAM * ); /* ep_args */ + +extern DAT_RETURN DAT_API dapl_ep_connect ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_IA_ADDRESS_PTR, /* remote_ia_address */ + IN DAT_CONN_QUAL, /* remote_conn_qual */ + IN DAT_TIMEOUT, /* timeout */ + IN DAT_COUNT, /* private_data_size */ + IN const DAT_PVOID, /* private_data */ + IN DAT_QOS, /* quality_of_service */ + IN DAT_CONNECT_FLAGS ); /* connect_flags */ + +extern DAT_RETURN DAT_API dapl_ep_dup_connect ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_EP_HANDLE, /* ep_dup_handle */ + IN DAT_TIMEOUT, /* timeout*/ + IN DAT_COUNT, /* private_data_size */ + IN const DAT_PVOID, /* private_data */ + IN DAT_QOS); /* quality_of_service */ + +extern DAT_RETURN DAT_API dapl_ep_disconnect ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_CLOSE_FLAGS ); /* disconnect_flags */ + +extern DAT_RETURN DAT_API dapl_ep_post_send ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_COUNT, /* num_segments */ + IN DAT_LMR_TRIPLET *, /* local_iov */ + IN DAT_DTO_COOKIE, /* user_cookie */ + IN DAT_COMPLETION_FLAGS ); /* completion_flags */ + +extern DAT_RETURN DAT_API dapl_ep_post_recv ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_COUNT, /* num_segments */ + IN DAT_LMR_TRIPLET *, /* local_iov */ + IN DAT_DTO_COOKIE, /* user_cookie */ + IN DAT_COMPLETION_FLAGS ); /* completion_flags */ + +extern DAT_RETURN DAT_API dapl_ep_post_rdma_read ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_COUNT, /* num_segments */ + IN DAT_LMR_TRIPLET *, /* local_iov */ + IN DAT_DTO_COOKIE, /* user_cookie */ + IN const DAT_RMR_TRIPLET *, /* remote_iov */ + IN DAT_COMPLETION_FLAGS ); /* completion_flags */ + +extern DAT_RETURN DAT_API dapl_ep_post_rdma_write ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_COUNT, /* num_segments */ + IN DAT_LMR_TRIPLET *, /* local_iov */ + IN DAT_DTO_COOKIE, /* user_cookie */ + IN const DAT_RMR_TRIPLET *, /* remote_iov */ + IN DAT_COMPLETION_FLAGS ); /* completion_flags */ + +extern DAT_RETURN DAT_API dapl_ep_get_status ( + IN DAT_EP_HANDLE, /* ep_handle */ + OUT DAT_EP_STATE *, /* ep_state */ + OUT DAT_BOOLEAN *, /* in_dto_idle */ + OUT DAT_BOOLEAN * ); /* out_dto_idle */ + +extern DAT_RETURN DAT_API dapl_ep_free ( + IN DAT_EP_HANDLE); /* ep_handle */ + +extern DAT_RETURN DAT_API dapl_ep_reset ( + IN DAT_EP_HANDLE); /* ep_handle */ + +/* LMR functions */ + +extern DAT_RETURN DAT_API dapl_lmr_create ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_MEM_TYPE, /* mem_type */ + IN DAT_REGION_DESCRIPTION, /* region_description */ + IN DAT_VLEN, /* length */ + IN DAT_PZ_HANDLE, /* pz_handle */ + IN DAT_MEM_PRIV_FLAGS, /* privileges */ + OUT DAT_LMR_HANDLE *, /* lmr_handle */ + OUT DAT_LMR_CONTEXT *, /* lmr_context */ + OUT DAT_RMR_CONTEXT *, /* rmr_context */ + OUT DAT_VLEN *, /* registered_length */ + OUT DAT_VADDR * ); /* registered_address */ + +extern DAT_RETURN DAT_API dapl_lmr_query ( + IN DAT_LMR_HANDLE, + IN DAT_LMR_PARAM_MASK, + OUT DAT_LMR_PARAM *); + +extern DAT_RETURN DAT_API dapl_lmr_free ( + IN DAT_LMR_HANDLE); + +/* RMR Functions */ + +extern DAT_RETURN DAT_API dapl_rmr_create ( + IN DAT_PZ_HANDLE, /* pz_handle */ + OUT DAT_RMR_HANDLE *); /* rmr_handle */ + +extern DAT_RETURN DAT_API dapl_rmr_query ( + IN DAT_RMR_HANDLE, /* rmr_handle */ + IN DAT_RMR_PARAM_MASK, /* rmr_args_mask */ + OUT DAT_RMR_PARAM *); /* rmr_args */ + +extern DAT_RETURN DAT_API dapl_rmr_bind ( + IN DAT_RMR_HANDLE, /* rmr_handle */ + IN const DAT_LMR_TRIPLET *, /* lmr_triplet */ + IN DAT_MEM_PRIV_FLAGS, /* mem_priv */ + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_RMR_COOKIE, /* user_cookie */ + IN DAT_COMPLETION_FLAGS, /* completion_flags */ + INOUT DAT_RMR_CONTEXT * ); /* context */ + +extern DAT_RETURN DAT_API dapl_rmr_free ( + IN DAT_RMR_HANDLE); + +/* PSP Functions */ + +extern DAT_RETURN DAT_API dapl_psp_create ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_CONN_QUAL, /* conn_qual */ + IN DAT_EVD_HANDLE, /* evd_handle */ + IN DAT_PSP_FLAGS, /* psp_flags */ + OUT DAT_PSP_HANDLE * ); /* psp_handle */ + +extern DAT_RETURN DAT_API dapl_psp_create_any ( + IN DAT_IA_HANDLE, /* ia_handle */ + OUT DAT_CONN_QUAL *, /* conn_qual */ + IN DAT_EVD_HANDLE, /* evd_handle */ + IN DAT_PSP_FLAGS, /* psp_flags */ + OUT DAT_PSP_HANDLE *); /* psp_handle */ + +extern DAT_RETURN DAT_API dapl_psp_query ( + IN DAT_PSP_HANDLE, + IN DAT_PSP_PARAM_MASK, + OUT DAT_PSP_PARAM * ); + +extern DAT_RETURN DAT_API dapl_psp_free ( + IN DAT_PSP_HANDLE ); /* psp_handle */ + +/* RSP Functions */ + +extern DAT_RETURN DAT_API dapl_rsp_create ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_CONN_QUAL, /* conn_qual */ + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_EVD_HANDLE, /* evd_handle */ + OUT DAT_RSP_HANDLE * ); /* rsp_handle */ + +extern DAT_RETURN DAT_API dapl_rsp_query ( + IN DAT_RSP_HANDLE, + IN DAT_RSP_PARAM_MASK, + OUT DAT_RSP_PARAM * ); + +extern DAT_RETURN DAT_API dapl_rsp_free ( + IN DAT_RSP_HANDLE ); /* rsp_handle */ + +/* PZ Functions */ + +extern DAT_RETURN DAT_API dapl_pz_create ( + IN DAT_IA_HANDLE, /* ia_handle */ + OUT DAT_PZ_HANDLE * ); /* pz_handle */ + +extern DAT_RETURN DAT_API dapl_pz_query ( + IN DAT_PZ_HANDLE, /* pz_handle */ + IN DAT_PZ_PARAM_MASK, /* pz_args_mask */ + OUT DAT_PZ_PARAM * ); /* pz_args */ + +extern DAT_RETURN DAT_API dapl_pz_free ( + IN DAT_PZ_HANDLE ); /* pz_handle */ + +/* + * DAPL internal utility function prototpyes + */ + +extern void dapl_llist_init_head ( + DAPL_LLIST_HEAD * head); + +extern void dapl_llist_init_entry ( + DAPL_LLIST_ENTRY * entry); + +extern DAT_BOOLEAN dapl_llist_is_empty ( + DAPL_LLIST_HEAD * head); + +extern void dapl_llist_add_head ( + DAPL_LLIST_HEAD * head, + DAPL_LLIST_ENTRY * entry, + void * data); + +extern void dapl_llist_add_tail ( + DAPL_LLIST_HEAD * head, + DAPL_LLIST_ENTRY * entry, + void * data); + +extern void dapl_llist_add_entry ( + DAPL_LLIST_HEAD * head, + DAPL_LLIST_ENTRY * entry, + DAPL_LLIST_ENTRY * new_entry, + void * data); + +extern void * dapl_llist_remove_head ( + DAPL_LLIST_HEAD * head); + +extern void * dapl_llist_remove_tail ( + DAPL_LLIST_HEAD * head); + +extern void * dapl_llist_remove_entry ( + DAPL_LLIST_HEAD * head, + DAPL_LLIST_ENTRY * entry); + +extern void * dapl_llist_peek_head ( + DAPL_LLIST_HEAD * head); + +extern void * dapl_llist_next_entry ( + IN DAPL_LLIST_HEAD *head, + IN DAPL_LLIST_ENTRY *cur_ent); + +extern void dapl_llist_debug_print_list ( + DAPL_LLIST_HEAD * head); + + +#endif /* _DAPL_H_ */ diff --git a/branches/WOF2-3/ulp/dapl/dapl/include/dapl_debug.h b/branches/WOF2-3/ulp/dapl/dapl/include/dapl_debug.h new file mode 100644 index 00000000..de67aa96 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/include/dapl_debug.h @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_debug.h + * + * PURPOSE: defines common deuggging flags & data for the DAPL reference + * implemenation + * + * Description: + * + * + * $Id$ + **********************************************************************/ + +#ifndef _DAPL_DEBUG_H_ +#define _DAPL_DEBUG_H_ + +/* + * Debug level switches + * + * Use these bits to enable various tracing/debug options. Each bit + * represents debugging in a particular subsystem or area of the code. + * + * The ERR bit should always be on unless someone disables it for a + * reason: The ERR flag is used sparingly and will print useful + * information if it fires. + */ +typedef enum +{ + DAPL_DBG_TYPE_ERR = 0x0001, + DAPL_DBG_TYPE_WARN = 0x0002, + DAPL_DBG_TYPE_EVD = 0x0004, + DAPL_DBG_TYPE_CM = 0x0008, + DAPL_DBG_TYPE_EP = 0x0010, + DAPL_DBG_TYPE_UTIL = 0x0020, + DAPL_DBG_TYPE_CALLBACK = 0x0040, + DAPL_DBG_TYPE_DTO_COMP_ERR = 0x0080, + DAPL_DBG_TYPE_API = 0x0100, + DAPL_DBG_TYPE_RTN = 0x0200, + DAPL_DBG_TYPE_EXCEPTION = 0x0400, + DAPL_DBG_TYPE_EVENT_DQ = 0x0800 +} DAPL_DBG_TYPE; + +typedef enum +{ + DAPL_DBG_DEST_STDOUT = 0x0001, + DAPL_DBG_DEST_SYSLOG = 0x0002, +} DAPL_DBG_DEST; + + +extern DAPL_DBG_TYPE g_dapl_dbg_type; +extern DAPL_DBG_DEST g_dapl_dbg_dest; + +#if defined(DAPL_DBG) + +#define dapl_dbg_log g_dapl_dbg_type==0 ? (void) 1 : dapl_internal_dbg_log +extern void dapl_internal_dbg_log ( DAPL_DBG_TYPE type, const char *fmt, ...); + +#else /* !DAPL_DBG */ + +#define dapl_dbg_log + +#endif /* !DAPL_DBG */ + +#define dapl_log g_dapl_dbg_type==0 ? (void) 1 : dapl_internal_log +extern void dapl_internal_log ( DAPL_DBG_TYPE type, const char *fmt, ...); + + +/* + * Counters + */ +#define DCNT_EP_CREATE 0 +#define DCNT_EP_FREE 1 +#define DCNT_EP_CONNECT 2 +#define DCNT_EP_DISCONNECT 3 +#define DCNT_POST_SEND 4 +#define DCNT_POST_RECV 5 +#define DCNT_POST_RDMA_WRITE 6 +#define DCNT_POST_RDMA_READ 7 +#define DCNT_EVD_CREATE 8 +#define DCNT_EVD_FREE 9 +#define DCNT_EVD_WAIT 10 +#define DCNT_EVD_WAIT_BLOCKED 11 +#define DCNT_EVD_WAIT_CMP_NTFY 12 +#define DCNT_EVD_DTO_CALLBACK 13 +#define DCNT_EVD_CONN_CALLBACK 14 +#define DCNT_EVD_DEQUEUE 15 +#define DCNT_EVD_DEQUEUE_POLL 16 +#define DCNT_EVD_DEQUEUE_FOUND 17 +#define DCNT_EVD_DEQUEUE_NOT_FOUND 18 +#define DCNT_TIMER_SET 19 +#define DCNT_TIMER_CANCEL 20 +#define DCNT_LAST_COUNTER 22 /* Always the last counter */ + +#if defined(DAPL_COUNTERS) +#include "dapl_counters.h" + +#define DAPL_CNTR(cntr) dapl_os_atomic_inc (&dapl_dbg_counters[cntr]); +#else + +#define DAPL_CNTR(cntr) +#define DAPL_COUNTERS_INIT() +#define DAPL_COUNTERS_NEW(__tag, __id) +#define DAPL_COUNTERS_RESET(__id, __incr) +#define DAPL_COUNTERS_INCR(__id, __incr) + +#endif /* DAPL_COUNTERS */ + + +#endif /* _DAPL_DEBUG_H_ */ diff --git a/branches/WOF2-3/ulp/dapl/dapl/include/dapl_ipoib_names.h b/branches/WOF2-3/ulp/dapl/dapl/include/dapl_ipoib_names.h new file mode 100644 index 00000000..f0d117d8 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/include/dapl_ipoib_names.h @@ -0,0 +1,261 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: ipoib_naming.h + * + * PURPOSE: Defines flags and prototypes for IPoIB API + * + * Description: + * This defines a simple naming interface for discovering + * the IP addresses available to a provider, then a set + * of query mechanisms useful to map an IP address to + * a provider specific address; a GID in InfiniBand. + * + * NOTE: As implementations mature this may not be necessary. + * + * $Id$ + **********************************************************************/ + +#ifndef _IPOIB_NAMING_H_ +#define _IPOIB_NAMING_H_ + +typedef enum _ipoib_port_num { + HCA_PORT_1= 1, + HCA_PORT_2, + HCA_PORT_ANY +} IPOIB_PORT_NUM; + +typedef struct if_query_info +{ + uint64_t guid; + uint32_t port_num; + uint32_t state; +}IF_QUERY_INFO; + +/*********************************************************************** + * ipoib_enum_if() + * + * PURPOSE + * Returns count of IP interfaces. + * + * ARGUMENTS + * hca_index: index of HCA in the provider library. In general + * terms, the index represents the HCA number, e.g. + * 1 == First HCA, 2 == Second HCA, etc. + * + * port: an enum of + * HCA_PORT_0 + * HCA_PORT_1 + * HCA_PORT_ANY + * HCA_PORT_ANY enum value returns all IP instances assigned to the HCA. + * + * RETURNS + * count of IP interfaces supported on physical port + * + ***********************************************************************/ +int +ipoib_enum_if( + IN uint32_t hca_index, + IN IPOIB_PORT_NUM port); + + +/*********************************************************************** + * ipoib_get_if() + * + * PURPOSE + * Returns array of IP Addresses of all instances. Port parameter may + * restrict instances of interest. + * + * ARGUMENTS + * hca_index: index of HCA in the provider library. + * + * port: IPOIB_PORT_NUM as described above + * + * ip_addr_list: pointer to user-allocated space in which an array of + * IP addresses found for this hca and port will be returned + * + * ip_addr_count: number of returned addresses + * + * RETURNS + * 0 for SUCCESS + * !0 for failure + * + ***********************************************************************/ +int +ipoib_get_if( + IN uint32_t hca_index, + IN IPOIB_PORT_NUM port, + OUT struct sockaddr **ip_addr_list, + OUT int *ip_addr_count); + +/*********************************************************************** + * + * PURPOSE + * Returns a handle to this interface, to be used for subsequent + * operations + * + * ARGUMENTS + * ip_address: input IP address + * + * ipoib_handle: handle to be used in subsequent operations. + * + * RETURNS + * 0 for SUCCESS + * !0 for failure + * + ***********************************************************************/ +int +ipoib_open_if( + IN struct sockaddr *ip_address, + OUT void *ipoib_handle); + +/*********************************************************************** + * ipoib_query_if() + * + * PURPOSE + * if_query_if returns information on local ipoib_handle such as GID, + * Port number, IPoIB state, anything interesting + * + * ARGUMENTS + * ipoib_handle: handle for instance + * + * if_qry_info: info struct. Looks like: + * + * RETURNS + * 0 for SUCCESS + * !0 for failure + * + ***********************************************************************/ +int +ipoib_query_if( + IN void *ipoib_handle, + OUT IF_QUERY_INFO *if_qry_info); + +/*********************************************************************** + * + * + * PURPOSE + * Obtain a GID from an IP Address. Used by the active side of + * a connection. + * + * The behavior of this routine is specified to provide control + * over the underlying implementation. + * Returns immediately if the remote information is available. If + * callback_routine_ptr is NULL then it will block until information is + * available or known to be unavailable. If callback_routine_ptr is + * specified then it will be invoked when remote information is + * available or known to be unavailable. Remote_Addr_info contains + * remote GID information. + * + * ARGUMENTS + * ipoib_handle: handle for instance + * + * remote_ip_address: IP address of remote instance + * + * callback_routine_ptr: routine to invoke for asynch callback. If + * NULL ipoib_getaddrinfo() will block. + * + * context: argument to pass to asynch callback_routine. + * + * Remote_Addr_info: Remote GID + * + * RETURNS + * 0 for SUCCESS + * !0 for failure + * + ***********************************************************************/ +int +ipoib_getaddrinfo( + IN void *ipoib_handle, + IN struct sockaddr *remote_ip_address, + IN void *callback_routine_ptr, + IN void *context, + OUT void *Remote_Addr_info ); + +/*********************************************************************** + * + * + * PURPOSE + * Obtain an IP Address from a GID. Used by the passive side of a + * connection. + * + * The behavior of this routine is specified to provide control over + * the underlying implementation. Returns immediately if the remote + * information is available. If callback_routine_ptr is NULL then it + * will block until information is available or known to be + * unavailable. If callback_routine_ptr is specified then it will be + * invoked when remote information is available or known to be + * unavailable. + * + * ARGUMENTS + * ipoib_handle: handle for instance + * + * remote_gidAddr: Remote GID. It is not defined on how the application + * will obtain this GID from the connection manager. + * + * callback_routine_ptr: + * routine to invoke for async callback. If NULL + * ipoib_getgidinfo() will block. + * + * context: argument to pass to asynch callback_routine. + * + * remote_ip_address: + * IP address of remote instance + * + * RETURNS + * 0 for SUCCESS + * !0 for failure + * + ***********************************************************************/ +int +ipoib_getgidinfo( + IN void *ipoib_handle, + IN GID *remote_gid, + IN void *callback_routine_ptr, + IN void *context, + OUT struct sockaddr *remote_ip_address); + +/*********************************************************************** + * + * PURPOSE + * Release handle. + * + * ARGUMENTS + * ipoib_handle: handle for instance + * + * RETURNS + * 0 for SUCCESS + * !0 for failure + * + ***********************************************************************/ +int +ipoib_close( + IN void *ipoib_handle); + + +#endif /* _IPOIB_NAMING_H_ */ diff --git a/branches/WOF2-3/ulp/dapl/dapl/include/dapl_vendor.h b/branches/WOF2-3/ulp/dapl/dapl/include/dapl_vendor.h new file mode 100644 index 00000000..1741b871 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/include/dapl_vendor.h @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_vendor.h + * + * PURPOSE: + * Vendor provides values for their implementation. Most of + * these values are returned in the DAT_IA_ATTR parameter of + * dat_ia_query() + * + * $Id$ + **********************************************************************/ + +/********************************************************************** + * DAT_IA_ATTR attributes + * + * These values are used in the provider support routine + * dapls_ib_query_hca (). Many of the values there are HW + * specific, the the vendor should look to make sure they are + * appropriate for their implementation. Specifically, + * vendors are encouraged to update transport and vendor + * attributes: the reference implementation sets these to NULL. + */ + +/* + * Product name of the adapter. + * Returned in DAT_IA_ATTR.adapter_name + */ +#define VN_ADAPTER_NAME "Generic InfiniBand HCA" + + +/* + * Vendor name + * Returned in DAT_IA_ATTR.vendor_name + */ +#define VN_VENDOR_NAME "DAPL Reference Implementation" + + +/********************************************************************** + * PROVIDER Attributes + * + * These values are used in ./common/dapl_ia_query.c, in dapl_ia_query (). + * The values below are the most common for vendors to change, but + * there are several other values that may be updated once the + * implementation becomes mature. + * + */ + +/* + * Provider Versions + * Returned in DAT_PROVIDER_ATTR.provider_version_major and + * DAT_PROVIDER_ATTR.provider_version_minor + */ + +#define VN_PROVIDER_MAJOR 1 +#define VN_PROVIDER_MINOR 0 + +/* + * Provider support for memory types. The reference implementation + * always supports DAT_MEM_TYPE_VIRTUAL and DAT_MEM_TYPE_LMR, so + * the vendor must indicate if they support DAT_MEM_TYPE_SHARED_VIRTUAL. + * Set this value to '1' if DAT_MEM_TYPE_SHARED_VIRTUAL is supported. + * + * Returned in DAT_PROVIDER_ATTR.lmr_mem_types_supported + */ + +#define VN_MEM_SHARED_VIRTUAL_SUPPORT 1 + + +/********************************************************************** + * + * This value will be assigned to dev_name_prefix in ./udapl/dapl_init.c. + * + * DAT is designed to support multiple DAPL instances simultaneously, + * with different dapl libraries originating from different providers. + * There is always the possibility of name conflicts, so a dat name + * prefix is provided to make a vendor's name unique. This is + * especially true of the IBM Access API, which returns adapter + * names that are simply ordinal numbers (e.g. 0, 1, 2). If + * a vendor doesn't need or want a prefix, it should be left + * as a NULL. + * This works by setting up a _VENDOR_ variable in the Makefile + * Values that might be used: + * #define VN_PREFIX "jni" (JNI: OS Acces API) + * #define VN_PREFIX "ibm" (IBM: OS Acces API) + * #define VN_PREFIX "" (Mellanox: VAPI) + * #define VN_PREFIX "" (Intel: IB Common API) + */ +#if defined(_VENDOR_JNI_) +#define VN_PREFIX "jni" +#elif defined(_VENDOR_MELLANOX_) +#define VN_PREFIX "" +#elif defined(_VENDOR_IBAL_) +#define VN_PREFIX "" +#elif defined(_VENDOR_IBM_) +#define VN_PREFIX "ibm" +#else +#define VN_PREFIX "" +#error "Must define _VENDOR_= in Makefile" +#endif diff --git a/branches/WOF2-3/ulp/dapl/dapl/udapl/Makefile.cygwin b/branches/WOF2-3/ulp/dapl/dapl/udapl/Makefile.cygwin new file mode 100644 index 00000000..7d1cbbc9 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/udapl/Makefile.cygwin @@ -0,0 +1,396 @@ +# +# Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. +# +# This Software is licensed under either one of the following two licenses: +# +# 1) under the terms of the "Common Public License 1.0" a copy of which is +# in the file LICENSE.txt in the root directory. The license is also +# available from the Open Source Initiative, see +# http://www.opensource.org/licenses/cpl.php. +# OR +# +# 2) under the terms of the "The BSD License" a copy of which is in the file +# LICENSE2.txt in the root directory. The license is also available from +# the Open Source Initiative, see +# http://www.opensource.org/licenses/bsd-license.php. +# +# Licensee has the right to choose either one of the above two licenses. +# +# Redistributions of source code must retain both the above copyright +# notice and either one of the license notices. +# +# Redistributions in binary form must reproduce both the above copyright +# notice, either one of the license notices in the documentation +# and/or other materials provided with the distribution. +# + +#********************************************************************** +# +# MODULE: Makefile +# +# PURPOSE: Makefile for dapl reference provider for CYGWIN environment +# +#*********************************************************************/ + + +############################################################## +# Application variables +# + +CP = cp -p -u +AS = $(CROSS_COMPILE)as +LD = $(CROSS_COMPILE)link.exe +CC = $(CROSS_COMPILE)cl.exe +CPP = $(CC) +AR = $(CROSS_COMPILE)ar +NM = $(CROSS_COMPILE)nm +STRIP = $(CROSS_COMPILE)strip +OBJCOPY = $(CROSS_COMPILE)objcopy +OBJDUMP = $(CROSS_COMPILE)objdump +RANLIB = $(CROSS_COMPILE)ranlib +MKDIR = mkdir -p +SED = /bin/sed +SHELL = /bin/sh + +TOPDIR = . + +COMMON = $(TOPDIR)/../common +WINDOWS = $(TOPDIR)/windows + +ifeq ($(VERBS),mellanox) +PROVIDER = $(TOPDIR)/../tavor +PROVIDER_INCDIRS = $(MTHOME)/include +else +PROVIDER = $(TOPDIR)/../torrent +PROVIDER_INCDIRS := ../include/ib/IBM \ + ../include/ib/IBM/us +endif + +OBJ_DIR = $(TOPDIR)/Obj +TARGET_DIR = $(TOPDIR)/Target + +SRCDIRS := \ + $(TOPDIR) \ + $(COMMON) \ + $(WINDOWS) \ + $(PROVIDER) + +INCDIRS := \ + $(SRCDIRS) \ + ../include \ + ../../dat/include \ + $(PROVIDER_INCDIRS) + +vpath %.c . ${SRCDIRS} +vpath %.h . ${INCDIRS} + + +################################################## +# targets +TARLIBS = dapl +TARSHLIBS = dapl + +# data for user libraries +dapl_SOURCES = $(COMMON_SRCS) $(WIN_SRCS) $(PROVIDER_SRCS) $(UDAPL_SRCS) + + +ifeq ($(VERBS),mellanox) +PROVIDER_SRCS = dapl_tavor_util.c dapl_tavor_qp.c dapl_tavor_cm.c +else +PROVIDER_SRCS = dapl_torrent_util.c dapl_torrent_qp.c dapl_torrent_cm.c +endif + +UDAPL_SRCS = dapl_init.c dapl_name_service.c + +WIN_SRCS = dapl_osd.c + +COMMON_SRCS = dapl_cookie.c \ + dapl_cr_accept.c \ + dapl_cr_query.c \ + dapl_cr_reject.c \ + dapl_cr_util.c \ + dapl_cr_callback.c \ + dapl_cr_handoff.c \ + dapl_ep_connect.c \ + dapl_ep_create.c \ + dapl_ep_disconnect.c \ + dapl_ep_dup_connect.c \ + dapl_ep_free.c \ + dapl_ep_get_status.c \ + dapl_ep_modify.c \ + dapl_ep_post_rdma_read.c \ + dapl_ep_post_rdma_write.c \ + dapl_ep_post_recv.c \ + dapl_ep_post_send.c \ + dapl_ep_query.c \ + dapl_ep_util.c \ + dapl_evd_create.c \ + dapl_evd_dequeue.c \ + dapl_evd_disable.c \ + dapl_evd_enable.c \ + dapl_evd_free.c \ + dapl_evd_modify_cno.c \ + dapl_evd_post_se.c \ + dapl_evd_query.c \ + dapl_evd_resize.c \ + dapl_evd_wait.c \ + dapl_evd_util.c \ + dapl_evd_cq_async_error_callb.c \ + dapl_evd_qp_async_error_callb.c \ + dapl_evd_un_async_error_callb.c \ + dapl_evd_connection_callb.c \ + dapl_evd_dto_callb.c \ + dapl_evd_set_unwaitable.c \ + dapl_evd_clear_unwaitable.c \ + dapl_extension_util.c \ + dapl_get_consumer_context.c \ + dapl_get_handle_type.c \ + dapl_hash.c \ + dapl_hca_util.c \ + dapl_ia_close.c \ + dapl_ia_open.c \ + dapl_ia_query.c \ + dapl_ia_util.c \ + dapl_llist.c \ + dapl_lmr_create.c \ + dapl_lmr_free.c \ + dapl_lmr_query.c \ + dapl_lmr_util.c \ + dapl_mr_util.c \ + dapl_provider.c \ + dapl_sp_util.c \ + dapl_psp_create.c \ + dapl_psp_free.c \ + dapl_psp_query.c \ + dapl_pz_create.c \ + dapl_pz_free.c \ + dapl_pz_query.c \ + dapl_pz_util.c \ + dapl_rmr_create.c \ + dapl_rmr_free.c \ + dapl_rmr_bind.c \ + dapl_rmr_query.c \ + dapl_rmr_util.c \ + dapl_rsp_create.c \ + dapl_rsp_free.c \ + dapl_rsp_query.c \ + dapl_cno_create.c \ + dapl_cno_modify_agent.c \ + dapl_cno_free.c \ + dapl_cno_wait.c \ + dapl_cno_query.c \ + dapl_cno_util.c \ + dapl_set_consumer_context.c \ + dapl_ring_buffer_util.c \ + dapl_debug.c + + + +#################################################### +# compiler options CFLAGS +# + +# common flags +UOPTIONS += /nologo /MDd /W3 /GX /Od /FD /GZ /Gm /Zi + +# common defines +UCOMDEFS += /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "WIN32" /D "_DEBUG" \ + -D_WIN32_WINNT=0x0500 -DWINVER=0x0500 +# other options: /FR /Fd + +# private defines +UPRIVDEFS += /D "__WIN__" /D "__MSC__" /D "__i386__" + +CFLAGS += $(UOPTIONS) $(UCOMDEFS) $(UPRIVDEFS) + +# +# Provider specific CFLAGS definition +# + +CFLAGS += -DDAPL_DBG + +ifeq ($(VERBS),mellanox) +CFLAGS += -DSMR_BUSTED -DNO_NAME_SERVICE -DCM_BUSTED # -DPOLLING_COMPLETIONS # -DMW_BUSTED +CFLAGS += -DMTL_MODULE=M_dapl # -DMAX_TRACE=8 -DMAX_DEBUG=8 -DMAX_ERROR=8 +else +CFLAGS += -DNO_NAME_SERVICE # -DCM_BUSTED +endif + +########################################################### +# common included libraries +# +ULDLIBS += kernel32 user32 gdi32 winspool \ + comdlg32 advapi32 shell32 ole32 oleaut32 \ + uuid odbc32 odbccp32 Ws2_32 dat + +# +# Provider specific included libraries +# +ifeq ($(VERBS),mellanox) +ULDLIBS += vapi mtl_common mosal mtib \ + mpga vapi_common mtgetopt +else +ULDLIBS += VerbsLibrary +endif + + + +######################################################### +# link options LDFLAGS +# + +MTARFLAGS= -cr + +TARFLAGS += cr + +# common flags +ULDOPTIONS += /nologo /incremental:no /machine:I386 /debug + +# common directories +ULDDIRS += /LIBPATH:"$(OBJ_DIR)" +ULDDIRS += /LIBPATH:"$(TOPDIR)/../../dat/udat/Target" + +# module entry +ULDENTRY = /entry:DllMain + +# specific DLL flags +ifndef NO_DEF_FILE +USE_DEF_FILE = /def:$(WINDOWS)/dapl_win.def +endif + +ifndef NO_LIB_FILE +USE_LIB_FILE = $(@:%.dll=/implib:%.lib) +endif + +ifndef NO_PDB_FILE +USE_PDB_FILE = $(@:%.dll=/PDB:%.pdb) +endif + +DLLFLAGS += $(USE_DEF_FILE) $(USE_LIB_FILE) $(USE_PDB_FILE) + +# DLL flags +UDLLFLAGS += /dll $(DLLFLAGS) + +LDFLAGS += $(ULDOPTIONS) $(ULDENTRY) $(ULDDIRS) $(ULDLIBS:%=%.lib) + +# +# Provider specific ULDFLAGS +# +LDFLAGS += /LIBPATH:"$(MTHOME)/lib" + +# user DLL +LDSHFLAGS += $(LDFLAGS) $(UDLLFLAGS) + + + +############################################################# +# Local functions +# +bsndir = $(notdir $(basename $1)) + +############################################################ +# Common rules +# +define COMPILE +$(CC) -c $(strip ${CFLAGS}) $(strip $(INCDIRS:%=-I%)) $(EXTRA_CFLAGS) $($(@:${OBJ_DIR}/%.obj=%.c_CFLAGS)) /Fo"$@" $< +endef + +define DEF_SET_VAR_SRCS +@echo "$@_VAR_SRCS += $($(basename $(call bsndir,$@))_SOURCES)" >> $@ +endef + +define DEF_SET_VAR_OBJS +@echo "$@_VAR_OBJS += $($(basename $(call bsndir,$@))_OBJECTS)" >> $@ +endef + + + +########################################################################### +# Start rules +# + +all: $(TARSHLIBS:%=${TARGET_DIR}/%.dll) $(TAROBJS:%=${OBJ_DIR}/%.obj) $(TARLIBS:%=${TARGET_DIR}/%.lib) + + +########################################################################## +# Simple objects (user) + +$(TAROBJS:%=${OBJ_DIR}/%.obj): ${OBJ_DIR}/%.obj: %.c + @if [ ! -d $(OBJ_DIR) ]; then mkdir -p $(OBJ_DIR); fi + $(COMPILE) + +$(OBJ_DIR)/%.obj: %.c + $(COMPILE) + + +########################################################################## +# Static libraries +# +$(TARLIBS:%=$(TARGET_DIR)/%.lib): % : %.mk +$(TARLIBS:%=$(TARGET_DIR)/%.lib.mk): Makefile.cygwin + @if [ ! -d $(OBJ_DIR) ]; then mkdir -p $(OBJ_DIR); fi + @if [ ! -d $(TARGET_DIR) ]; then mkdir -p $(TARGET_DIR); fi + @echo "# Do not edit. Automatically generated file." > $@ + @ + @${DEF_SET_VAR_OBJS} + @${DEF_SET_VAR_SRCS} + @ + @echo "SOURCES += \$$($@_VAR_SRCS)" >> $@ + @ + @echo "$(@:%.mk=%): \$$($@_VAR_SRCS:%.c=$(OBJ_DIR)/%.obj) " >> $@ + @echo "$(@:%.mk=%): \$$($@_VAR_OBJS:%.c=$(OBJ_DIR)/%.obj) " >> $@ + @echo -e "\t\$$(AR) \$$(MTARFLAGS) \$$@ \c" >> $@ + @echo -e "\$$($@_VAR_SRCS:%.c=$(OBJ_DIR)/%.obj) \c" >> $@ + @echo "\$$($@_VAR_OBJS) \$$(\$$(@:$(OBJ_DIR)/%.lib=%)_ARFLAGS) " >> $@ + @echo -e "\t\$$(RANLIB) \$$@" >> $@ + + +ifneq ($(MAKECMDGOALS), clean) +ifneq ($(strip $(TARLIBS)),) +-include $(patsubst %,$(OBJ_DIR)/%.lib.mk,$(TARLIBS)) +endif +endif + + +########################################################################## +# Shared libraries +# +$(TARSHLIBS:%=$(TARGET_DIR)/%.dll): % : %.mk +$(TARSHLIBS:%=$(TARGET_DIR)/%.dll.mk): Makefile.cygwin + @if [ ! -d $(OBJ_DIR) ]; then mkdir -p $(OBJ_DIR); fi + @if [ ! -d $(TARGET_DIR) ]; then mkdir -p $(TARGET_DIR); fi + @echo "# Do not edit. Automatically generated file." > $@ + @ + @${DEF_SET_VAR_OBJS} + @${DEF_SET_VAR_SRCS} + @ + @echo "SOURCES += \$$($@_VAR_SRCS)" >> $@ + @ + @echo "$(@:%.mk=%): \$$($@_VAR_SRCS:%.c=$(OBJ_DIR)/%.obj)" >> $@ + @echo "$(@:%.mk=%): \$$($@_VAR_OBJS:%.c=$(OBJ_DIR)/%.obj)" >> $@ + @echo -e "\t\$$(LD) \$$(LDSHFLAGS) /out:\"\$$@\" \c" >> $@ + @echo -e "\$$($@_VAR_SRCS:%.c=$(OBJ_DIR)/%.obj) \c" >> $@ + @echo -e "\$$($@_VAR_OBJS) \c" >> $@ + @echo -e "\$$(LDSHLIBS:%=%) \$$(LIBSHDIRS:%=/LIBPATH:%) \c" >> $@ + + +ifneq ($(MAKECMDGOALS), clean) +ifneq ($(strip $(TARSHLIBS)),) +-include $(patsubst %,$(TARGET_DIR)/%.dll.mk,$(TARSHLIBS)) +endif +endif + + +########################################################################## +# Clean rules +# +CLEANDIRS = $(OBJ_DIR) $(TARGET_DIR) + +CLEANFILES = *.obj *.dll *.lib *.sys *.pdb *.idb *.exp *.ilk *.sbr *.mk + +clean: $(CLEANDIRS) + @echo deleting dump files at $(shell pwd) + @rm -f $(CLEANFILES) + @if [ -d $(OBJ_DIR) ] ; then rm -f $(CLEANFILES:%=$(OBJ_DIR)/%); fi + @if [ -d $(TARGET_DIR) ] ; then rm -f $(CLEANFILES:%=$(TARGET_DIR)/%); fi + diff --git a/branches/WOF2-3/ulp/dapl/dapl/udapl/Makefile.org b/branches/WOF2-3/ulp/dapl/dapl/udapl/Makefile.org new file mode 100644 index 00000000..49c880db --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/udapl/Makefile.org @@ -0,0 +1,200 @@ + # + # Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + # + # This Software is licensed under either one of the following two licenses: + # + # 1) under the terms of the "Common Public License 1.0" a copy of which is + # in the file LICENSE.txt in the root directory. The license is also + # available from the Open Source Initiative, see + # http://www.opensource.org/licenses/cpl.php. + # OR + # + # 2) under the terms of the "The BSD License" a copy of which is in the file + # LICENSE2.txt in the root directory. The license is also available from + # the Open Source Initiative, see + # http://www.opensource.org/licenses/bsd-license.php. + # + # Licensee has the right to choose either one of the above two licenses. + # + # Redistributions of source code must retain both the above copyright + # notice and either one of the license notices. + # + # Redistributions in binary form must reproduce both the above copyright + # notice, either one of the license notices in the documentation + # and/or other materials provided with the distribution. + # + +#********************************************************************** +# +# MODULE: Makefile +# +# PURPOSE: Makefile for dapl reference provider +# +#*********************************************************************/ + +TOPDIR = $(shell /bin/pwd) + +SRC_PATH = $(TOPDIR) +COMMON = $(TOPDIR)/../common +LINUX = $(TOPDIR)/../udapl/linux +IBA_HOME = ../../.. +PROVIDER = $(TOPDIR)/../ibal +VERBS=ibal + +# +# Set DAPL_EXPOSE_HCA_PORTS to 1 if you want to expose HCA ports as real +# names in the dat registry. This results in 3 entries for each HCA: the +# basename, port 1 and port 2. For example, if my basename is "foo" the +# result will be "foo", "fooa", and "foob". "foo" and "fooa" are +# synonyms, they even share the same data structures. +# NOTE: If DAT is using the static registry, you will need to update +# dat.conf with entries for the ports; "fooa" and "foob" in our example. +# +DAPL_EXPOSE_HCA_PORTS=0 + +SO_TARGET = libdapl.so.0.0 +SO_NAME = libdapl.so +L_TARGET := libdapl.a + +# +# CFLAGS definition +# +EXTRA_CFLAGS = -O $(CPPFLAGS) +ifeq ($(BLD),debug) +EXTRA_CFLAGS += -DDAPL_DBG +endif +EXTRA_CFLAGS += -DIBAL -DOLD_QP_STATE_TO_INIT # -DNO_NAME_SERVICE # +EXTRA_CFLAGS += -I. +EXTRA_CFLAGS += -I.. +EXTRA_CFLAGS += -I../../dat/include +EXTRA_CFLAGS += -I../include +EXTRA_CFLAGS += -I$(PROVIDER) +EXTRA_CFLAGS += -I../udapl/linux +EXTRA_CFLAGS += -I../common +EXTRA_CFLAGS += -Wall +EXTRA_CFLAGS += -Wstrict-prototypes +#EXTRA_CFLAGS += -Wmissing-prototypes +#EXTRA_CFLAGS += -Wmissing-declarations +EXTRA_CFLAGS += -Werror +EXTRA_CFLAGS += -g3 +ifdef GPROF +EXTRA_CFLAGS += -pg +endif +EXTRA_CFLAGS += -D_VENDOR_IBAL_ + +ifeq ($(DAPL_EXPOSE_HCA_PORTS),1) +EXTRA_CFLAGS += -DDAPL_EXPOSE_HCA_PORTS +endif + + +# +# EXTRA_LDFLAGS definition +# +EXTRA_LDFLAGS += -init dapl_init +EXTRA_LDFLAGS += -fini dapl_fini +EXTRA_LDFLAGS += -L${IBA_HOME}/al -R${IBA_HOME}/al +EXTRA_LDFLAGS += -L${IBA_HOME}/complib -R${IBA_HOME}/complib +EXTRA_LDFLAGS += -lallib +EXTRA_LDFLAGS += -lcomplib +EXTRA_LDFLAGS += -ldl -lpthread + +PROVIDER_SRCS = dapl_ibal_util.c dapl_ibal_qp.c dapl_ibal_cm.c dapl_ibal_mrdb.c +VPATH = $(SRC_PATH) $(COMMON) $(LINUX) $(PROVIDER) + +UDAPL_SRCS = dapl_init.c dapl_name_service.c dapl_timer_util.c + +COMMON_SRCS = dapl_cookie.c \ + dapl_cr_accept.c \ + dapl_cr_query.c \ + dapl_cr_reject.c \ + dapl_cr_util.c \ + dapl_cr_callback.c \ + dapl_cr_handoff.c \ + dapl_ep_connect.c \ + dapl_ep_create.c \ + dapl_ep_disconnect.c \ + dapl_ep_dup_connect.c \ + dapl_ep_free.c \ + dapl_ep_get_status.c \ + dapl_ep_modify.c \ + dapl_ep_post_rdma_read.c \ + dapl_ep_post_rdma_write.c \ + dapl_ep_post_recv.c \ + dapl_ep_post_send.c \ + dapl_ep_query.c \ + dapl_ep_reset.c \ + dapl_ep_util.c \ + dapl_evd_create.c \ + dapl_evd_dequeue.c \ + dapl_evd_disable.c \ + dapl_evd_enable.c \ + dapl_evd_free.c \ + dapl_evd_modify_cno.c \ + dapl_evd_post_se.c \ + dapl_evd_query.c \ + dapl_evd_resize.c \ + dapl_evd_wait.c \ + dapl_evd_util.c \ + dapl_evd_cq_async_error_callb.c \ + dapl_evd_qp_async_error_callb.c \ + dapl_evd_un_async_error_callb.c \ + dapl_evd_connection_callb.c \ + dapl_evd_dto_callb.c \ + dapl_evd_set_unwaitable.c \ + dapl_evd_clear_unwaitable.c \ + dapl_get_consumer_context.c \ + dapl_get_handle_type.c \ + dapl_hash.c \ + dapl_hca_util.c \ + dapl_ia_close.c \ + dapl_ia_open.c \ + dapl_ia_query.c \ + dapl_ia_util.c \ + dapl_llist.c \ + dapl_lmr_create.c \ + dapl_lmr_free.c \ + dapl_lmr_query.c \ + dapl_lmr_util.c \ + dapl_mr_util.c \ + dapl_provider.c \ + dapl_sp_util.c \ + dapl_psp_create.c \ + dapl_psp_create_any.c \ + dapl_psp_free.c \ + dapl_psp_query.c \ + dapl_pz_create.c \ + dapl_pz_free.c \ + dapl_pz_query.c \ + dapl_pz_util.c \ + dapl_rmr_create.c \ + dapl_rmr_free.c \ + dapl_rmr_bind.c \ + dapl_rmr_query.c \ + dapl_rmr_util.c \ + dapl_rsp_create.c \ + dapl_rsp_free.c \ + dapl_rsp_query.c \ + dapl_cno_create.c \ + dapl_cno_modify_agent.c \ + dapl_cno_free.c \ + dapl_cno_wait.c \ + dapl_cno_query.c \ + dapl_cno_util.c \ + dapl_set_consumer_context.c \ + dapl_ring_buffer_util.c \ + dapl_debug.c + +LINUX_SRCS = dapl_osd.c + +UDAPL_OBJS = $(UDAPL_SRCS:%.c=%.o) +COMMON_OBJS = $(COMMON_SRCS:%.c=%.o) +LINUX_OBJS = $(LINUX_SRCS:%.c=%.o) +PROVIDER_OBJS = $(PROVIDER_SRCS:%.c=%.o) + +DAPL_OBJS = $(UDAPL_OBJS) $(COMMON_OBJS) $(LINUX_OBJS) $(PROVIDER_OBJS) + +S_OBJS = $(DAPL_OBJS) +L_OBJS = $(S_OBJS) + +include $(IBA_HOME)/Makefile.config +include $(IBA_HOME)/Makefile.rules diff --git a/branches/WOF2-3/ulp/dapl/dapl/udapl/Makefile.orig b/branches/WOF2-3/ulp/dapl/dapl/udapl/Makefile.orig new file mode 100644 index 00000000..f98ef9d0 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/udapl/Makefile.orig @@ -0,0 +1,305 @@ +# +# Copyright (c) 2002, Network Appliance, Inc. All rights reserved. +# +# This Software is licensed under the terms of the "IBM Common Public +# License 1.0" a copy of which is in the file LICENSE.txt in the +# root directory. The license is also available from the Open Source +# Initiative, see http://www.opensource.org/licenses/ibmpl.html. +# +# + +#********************************************************************** +# +# MODULE: Makefile +# +# PURPOSE: Makefile for dapl reference provider +# +# $Id$ +#*********************************************************************/ + +TOPDIR = $(shell /bin/pwd) + +SRC_PATH = $(TOPDIR) +OBJ_PATH = $(TOPDIR)/Obj +TARGET_PATH = $(TOPDIR)/Target + +TARGET = $(TARGET_PATH)/libdapl.so +STATIC = $(TARGET_PATH)/libdapl.a +COMMON = $(TOPDIR)/../common +LINUX = $(TOPDIR)/../udapl/linux + +CC = gcc + +# +# Set DAPL_EXPOSE_HCA_PORTS to 1 if you want to expose HCA ports as real +# names in the dat registry. This results in 3 entries for each HCA: the +# basename, port 1 and port 2. For example, if my basename is "foo" the +# result will be "foo", "fooa", and "foob". "foo" and "fooa" are +# synonyms, they even share the same data structures. +# NOTE: If DAT is using the static registry, you will need to update +# dat.conf with entries for the ports; "fooa" and "foob" in our example. +# +DAPL_EXPOSE_HCA_PORTS=0 + + +# +# CFLAGS definition +# + +CFLAGS = -O $(CPPFLAGS) -DDAPL_DBG +ifeq ($(VERBS),mellanox) +DAPL_IBLIB_DIR = /usr/mellanox/lib +PROVIDER = $(TOPDIR)/../vapi +CFLAGS += -DVAPI -DSMR_BUSTED -DNO_NAME_SERVICE -DOLD_QP_STATE_TO_INIT # -DCM_BUSTED # -DMW_BUSTED +else +ifeq ($(VERBS),ibal) +DAPL_IBLIB_DIR = $(LD_LIBRARY_PATH) +KERVER =$(shell uname -r) +PROVIDER = $(TOPDIR)/../ibal +CFLAGS += -DIBAL -DOLD_QP_STATE_TO_INIT # -DNO_NAME_SERVICE +else +PROVIDER = $(TOPDIR)/../ibapi +CFLAGS += -DIBAPI #-DNO_NAME_SERVICE # -DCM_BUSTED +endif +endif + +CFLAGS += -I. +CFLAGS += -I.. +CFLAGS += -I../../dat/include +CFLAGS += -I../include + +ifeq ($(VERBS),mellanox) +CFLAGS += -I/usr/mellanox/include +#CFLAGS += -I../include/ib/MELLANOX +else +ifeq ($(VERBS),ibal) +CFLAGS += -I../include/ib/IBAL/ +CFLAGS += -I../include/ib/IBAL/iba +CFLAGS += -I/usr/src/linux-$(KERVER)/include +CFLAGS += -DCONFIG_X86 +else +CFLAGS += -I../include/ib/IBM +CFLAGS += -I../include/ib/IBM/us +endif +endif + +CFLAGS += -I$(PROVIDER) +CFLAGS += -I../udapl/linux +CFLAGS += -I../common +CFLAGS += -Wall +CFLAGS += -Wstrict-prototypes +CFLAGS += -Wmissing-prototypes +CFLAGS += -Wmissing-declarations +CFLAGS += -Werror +CFLAGS += -g3 +ifdef GPROF +CFLAGS += -pg +endif + +LD = ld + +# +# LDFLAGS definition +# +LDFLAGS = -shared +LDFLAGS += -lpthread +LDFLAGS += -init dapl_init +LDFLAGS += -fini dapl_fini + +AR = ar +# +# ARFLAGS definition +# +ARFLAGS = r + +# +# To build with IBM verbs: make VERBS=ibm +# To build with JNI verbs: make VERBS=jni [default] +# To build with PSC verbs: make VERBS=psc +# +# Verb libraries should be in /usr/lib +# +# +# Vendor string, _VENDOR_: define for HCA vendor. If you +# add a new vendor name, you must add a new prefix to dev_name_prefix in +# dapl_init.c +# + +# Allow specification in the environment of a location for the +# verbs library, to allow running DAPL without installing +# the verbs library in /usr/lib. For development. +ifneq (${DAPL_IBLIB_DIR},) +LDFLAGS += -L${DAPL_IBLIB_DIR} -R${DAPL_IBLIB_DIR} +endif + +ifeq ($(VERBS),ibm) +CFLAGS += -D_VENDOR_IBM_ +CFLAGS += -D_IBM -DIBM +LDFLAGS += -lIBusd +LDFLAGS += -lIBlueHCAd +LDFLAGS += -ldl +PROVIDER_SRCS = dapl_ibapi_util.c dapl_ibapi_qp.c dapl_ibapi_cm.c +else +ifeq ($(VERBS),mellanox) +CFLAGS += -D_VENDOR_MELLANOX_ +CFLAGS += -DMTL_MODULE=M_dapl -DMAX_TRACE=8 -DMAX_DEBUG=8 -DMAX_ERROR=8 +PROVIDER_SRCS = dapl_vapi_util.c dapl_vapi_qp.c dapl_vapi_cm.c +LDFLAGS += -lvapi +LDFLAGS += -lmpga +LDFLAGS += -lmtl_common +LDFLAGS += -lcm +else +ifeq ($(VERBS),ibal) +CFLAGS += -D_VENDOR_IBAL_ +PROVIDER_SRCS = dapl_ibal_util.c dapl_ibal_qp.c dapl_ibal_cm.c +PROVIDER_SRCS += dapl_ibal_mrdb.c +LDFLAGS += -lallib +LDFLAGS += -lcomplib +LDFLAGS += -ldl +else +CFLAGS += -D_VENDOR_JNI_ # -DIPOIB_NAMING +CFLAGS += -DJNI # -DPOLLING_COMPLETIONS +LDFLAGS += -lJniTavorVerbs +LDFLAGS += -lpthread +PROVIDER_SRCS = dapl_ibapi_util.c dapl_ibapi_qp.c dapl_ibapi_cm.c +endif +endif +endif + +ifeq ($(DAPL_EXPOSE_HCA_PORTS),1) +CFLAGS += -DDAPL_EXPOSE_HCA_PORTS +endif + +UDAPL_SRCS = dapl_init.c dapl_name_service.c dapl_timer_util.c + +COMMON_SRCS = dapl_cookie.c \ + dapl_cr_accept.c \ + dapl_cr_query.c \ + dapl_cr_reject.c \ + dapl_cr_util.c \ + dapl_cr_callback.c \ + dapl_cr_handoff.c \ + dapl_ep_connect.c \ + dapl_ep_create.c \ + dapl_ep_disconnect.c \ + dapl_ep_dup_connect.c \ + dapl_ep_free.c \ + dapl_ep_get_status.c \ + dapl_ep_modify.c \ + dapl_ep_post_rdma_read.c \ + dapl_ep_post_rdma_write.c \ + dapl_ep_post_recv.c \ + dapl_ep_post_send.c \ + dapl_ep_query.c \ + dapl_ep_reset.c \ + dapl_ep_util.c \ + dapl_evd_create.c \ + dapl_evd_dequeue.c \ + dapl_evd_disable.c \ + dapl_evd_enable.c \ + dapl_evd_free.c \ + dapl_evd_modify_cno.c \ + dapl_evd_post_se.c \ + dapl_evd_query.c \ + dapl_evd_resize.c \ + dapl_evd_wait.c \ + dapl_evd_util.c \ + dapl_evd_cq_async_error_callb.c \ + dapl_evd_qp_async_error_callb.c \ + dapl_evd_un_async_error_callb.c \ + dapl_evd_connection_callb.c \ + dapl_evd_dto_callb.c \ + dapl_extension_util.c \ + dapl_get_consumer_context.c \ + dapl_get_handle_type.c \ + dapl_hash.c \ + dapl_hca_util.c \ + dapl_ia_close.c \ + dapl_ia_open.c \ + dapl_ia_query.c \ + dapl_ia_util.c \ + dapl_llist.c \ + dapl_lmr_create.c \ + dapl_lmr_free.c \ + dapl_lmr_query.c \ + dapl_lmr_util.c \ + dapl_mr_util.c \ + dapl_provider.c \ + dapl_sp_util.c \ + dapl_psp_create.c \ + dapl_psp_create_any.c \ + dapl_psp_free.c \ + dapl_psp_query.c \ + dapl_pz_create.c \ + dapl_pz_free.c \ + dapl_pz_query.c \ + dapl_pz_util.c \ + dapl_rmr_create.c \ + dapl_rmr_free.c \ + dapl_rmr_bind.c \ + dapl_rmr_query.c \ + dapl_rmr_util.c \ + dapl_rsp_create.c \ + dapl_rsp_free.c \ + dapl_rsp_query.c \ + dapl_cno_create.c \ + dapl_cno_modify_agent.c \ + dapl_cno_free.c \ + dapl_cno_wait.c \ + dapl_cno_query.c \ + dapl_cno_util.c \ + dapl_set_consumer_context.c \ + dapl_ring_buffer_util.c + +LINUX_SRCS = dapl_osd.c + +SRCS = $(UDAPL_SRCS) $(COMMON_SRCS) $(LINUX_SRCS) $(PROVIDER_SRCS) + + +UDAPL_OBJS = $(UDAPL_SRCS:%.c=$(OBJ_PATH)/%.o) +COMMON_OBJS = $(COMMON_SRCS:%.c=$(OBJ_PATH)/%.o) +LINUX_OBJS = $(LINUX_SRCS:%.c=$(OBJ_PATH)/%.o) +PROVIDER_OBJS = $(PROVIDER_SRCS:%.c=$(OBJ_PATH)/%.o) + +OBJS = $(UDAPL_OBJS) $(COMMON_OBJS) $(LINUX_OBJS) $(PROVIDER_OBJS) + + +all: mkdirs $(TARGET) $(STATIC) + +mkdirs: + @[ -d $(TARGET_PATH) ] || /bin/mkdir -p $(TARGET_PATH) + @[ -d $(OBJ_PATH) ] || /bin/mkdir -p $(OBJ_PATH) + +$(UDAPL_OBJS): $(OBJ_PATH)/%.o : %.c + @echo Compiling $< + $(CC) $(CFLAGS) -c $< -o $@ + +$(COMMON_OBJS): $(OBJ_PATH)/%.o : $(COMMON)/%.c + @echo Compiling $< + $(CC) $(CFLAGS) -c $< -o $@ + +$(LINUX_OBJS): $(OBJ_PATH)/%.o : $(LINUX)/%.c + @echo Compiling $< + $(CC) $(CFLAGS) -c $< -o $@ + +$(PROVIDER_OBJS): $(OBJ_PATH)/%.o : $(PROVIDER)/%.c + @echo Compiling $< + $(CC) $(CFLAGS) -c $< -o $@ + +$(TARGET): $(OBJS) + @echo Linking $(TARGET) + $(LD) $(LDFLAGS) $^ -o $(TARGET) + +$(STATIC): $(OBJS) + @echo Archiving $(STATIC) + @$(AR) $(ARFLAGS) $(STATIC) $^ + +clean: + rm -f $(OBJS) + rm -f $(TARGET) $(STATIC) + +tidy: + rm -f *~ + rm -f ../common/*~ + rm -f ../include/*~ + rm -f linux/*~ diff --git a/branches/WOF2-3/ulp/dapl/dapl/udapl/SOURCES b/branches/WOF2-3/ulp/dapl/dapl/udapl/SOURCES new file mode 100644 index 00000000..0d227c56 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/udapl/SOURCES @@ -0,0 +1,45 @@ +!if $(FREEBUILD) +TARGETNAME=dapl +!else +TARGETNAME=dapld +!endif +TARGETPATH=..\..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE=DYNLINK +DLLENTRY=_DllMainCRTStartup +!if $(_NT_TOOLS_VERSION) == 0x700 +# DDK +DLLDEF=$O\udapl_exports.def +!else +# WDK +DLLDEF=$(OBJ_PATH)\$O\udapl_exports.def +!endif +USE_MSVCRT=1 + +SOURCES=udapl.rc \ + dapl_init.c \ + dapl_name_service.c \ + dapl_timer_util.c \ + udapl_sources.c + +INCLUDES=..\include;..\common;windows;..\ibal;..\..\dat\include;\ + ..\..\..\..\inc;..\..\..\..\inc\user; + +USER_C_FLAGS=$(USER_C_FLAGS) -DEXPORT_DAPL_SYMBOLS -D_VENDOR_IBAL_ -DDAPL_MERGE_CM_DTO +!if !$(FREEBUILD) +USER_C_FLAGS=$(USER_C_FLAGS) -DDAPL_DBG +!endif + +TARGETLIBS= \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\dat.lib \ + $(TARGETPATH)\*\complib.lib \ + $(TARGETPATH)\*\ibal.lib +!else + $(TARGETPATH)\*\datd.lib \ + $(TARGETPATH)\*\complibd.lib \ + $(TARGETPATH)\*\ibald.lib +!endif + +MSC_WARNING_LEVEL= /W3 diff --git a/branches/WOF2-3/ulp/dapl/dapl/udapl/dapl_init.c b/branches/WOF2-3/ulp/dapl/dapl/udapl/dapl_init.c new file mode 100644 index 00000000..856be598 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/udapl/dapl_init.c @@ -0,0 +1,318 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_init.c + * + * PURPOSE: Interface Adapter management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 2 + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_hca_util.h" +#include "dapl_init.h" +#include "dapl_provider.h" +#include "dapl_mr_util.h" +#include "dapl_osd.h" /* needed for g_daplDebugLevel */ +#include "dapl_adapter_util.h" +#include "dapl_name_service.h" +#include "dapl_timer_util.h" +#include "dapl_vendor.h" + + +/* + * If DAPL_EXPOSE_HCA_PORTS is defined then extra entries are placed + * in the registry for each port of the HCA. For example, without + * this option only "jni0" will be registered; but with it, you will + * get "jni0a" and "jni0b". + */ +/* + * DHCA_PORT_COUNT is the number of ports on an HCA. If you are not + * exposing the ports, this is always 1 + */ +#ifdef DAPL_EXPOSE_HCA_PORTS +#define DHCA_PORT_COUNT 2 +#else +#define DHCA_PORT_COUNT 1 +#endif /* DAPL_EXPOSE_HCA_PORTS */ + +extern int32_t dapl_ib_init_complete; + +/* + * dapl_init + * + * initialize this provider + * includes initialization of all global variables + * as well as registering all supported IAs with the dat registry + * + * This function needs to be called once when the provider is loaded. + * + * Input: + * none + * + * Output: + * none + * + * Return Values: + */ +void +dapl_init ( void ) +{ + DAT_RETURN dat_status; + +#if defined(DAPL_DBG) + /* set up debug level */ + g_dapl_dbg_type = dapl_os_get_env_val ( "DAPL_DBG_TYPE", + DAPL_DBG_TYPE_ERR | DAPL_DBG_TYPE_WARN); + /* set up debug level */ + g_dapl_dbg_dest = dapl_os_get_env_val ( "DAPL_DBG_DEST", + DAPL_DBG_DEST_STDOUT); +#endif /* DAPL_DBG */ + + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, "DAPL: Started (dapl_init)\n"); + + /* See if the user is on a loopback setup */ + g_dapl_loopback_connection = dapl_os_get_env_bool ( "DAPL_LOOPBACK" ); + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "--> %s Setting loopback\n", + g_dapl_loopback_connection ? "" : "NOT" ); + + /* initialize the timer */ + dapls_timer_init(); + + dat_status = dapls_ns_init (); + + if (DAT_SUCCESS != dat_status) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "dapls_ns_init failed %d\n", dat_status); + goto bail; + } + + return; + +bail: + dapl_dbg_log (DAPL_DBG_TYPE_ERR, "ERROR: dapl_init failed\n"); + dapl_fini (); + return; +} + +/* + * dapl_fini + * + * finalize this provider + * includes freeing of all global variables + * as well as deregistering all supported IAs from the dat registry + * + * This function needs to be called once when the provider is loaded. + * + * Input: + * none + * + * Output: + * none + * + * Return Values: + */ +void +dapl_fini ( void ) +{ + DAT_RETURN dat_status; + + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, "DAPL: Stopped (dapl_fini)\n"); + + dat_status = dapl_provider_list_destroy (); + if (DAT_SUCCESS != dat_status) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "dapl_provider_list_destroy failed %d\n", dat_status); + } + + dapls_ib_release (); + + return; +} + + +/* + * + * This function is called by the registry to initialize a provider + * + * The instance data string is expected to have the following form: + * + * + * + */ +void +DAT_PROVIDER_INIT_FUNC_NAME ( + IN const DAT_PROVIDER_INFO *provider_info, + IN const char *instance_data ) +{ + DAT_PROVIDER *provider; + DAPL_HCA *hca_ptr; + DAT_RETURN dat_status; + char * data; + char * name; + char * port; + unsigned int len = 0; + unsigned int i; + + data = NULL; + provider = NULL; + hca_ptr = NULL; + + dapl_init(); + /* Initialize IB verbs library and provider list */ + if ( !dapl_ib_init_complete ) + { + dapls_ib_init (); + dapl_ib_init_complete = TRUE; + + /* initialize the provider list */ + dat_status = dapl_provider_list_create(); + if (DAT_SUCCESS != dat_status) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "dapl_provider_list_create failed %d\n", dat_status); + goto bail; + } + } + + dat_status = dapl_provider_list_insert(provider_info->ia_name, &provider); + if ( DAT_SUCCESS != dat_status ) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "dat_provider_list_insert failed: %x\n", dat_status); + goto bail; + } + + data = dapl_os_strdup(instance_data); + if ( NULL == data ) + { + goto bail; + } + + len = dapl_os_strlen(data); + + for ( i = 0; i < len; i++ ) + { + if ( ' ' == data[i] ) + { + data[i] = '\0'; + break; + } + } + + /* if the instance data did not have a valid format */ + if ( i == len ) + { + goto bail; + } + + name = data; + port = data + (i + 1); + + hca_ptr = dapl_hca_alloc (name, port); + if ( NULL == hca_ptr ) + { + goto bail; + } + + provider->extension = hca_ptr; + + /* register providers with dat_registry */ + dat_status = dat_registry_add_provider (provider, provider_info); + if ( DAT_SUCCESS != dat_status ) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "dat_registry_add_provider failed: %x\n", dat_status); + goto bail; + } + + bail: + if ( NULL != data ) + { + dapl_os_free(data, len + 1); + } + + if ( DAT_SUCCESS != dat_status ) + { + if ( NULL != provider ) + { + (void) dapl_provider_list_remove(provider_info->ia_name); + } + + if ( NULL != hca_ptr ) + { + dapl_hca_free (hca_ptr); + } + } +} + + +/* + * + * This function is called by the registry to de-initialize a provider + * + */ +void +DAT_PROVIDER_FINI_FUNC_NAME ( + IN const DAT_PROVIDER_INFO *provider_info ) +{ + DAT_PROVIDER *provider; + DAT_RETURN dat_status; + + dat_status = dapl_provider_list_search(provider_info->ia_name, &provider); + if ( DAT_SUCCESS != dat_status ) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "dat_provider_list_search failed: %x\n", dat_status); + return; + } + + dat_status = dat_registry_remove_provider (provider, provider_info); + if ( DAT_SUCCESS != dat_status ) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "dat_registry_remove_provider failed: %x\n", dat_status); + } + + (void) dapl_provider_list_remove(provider_info->ia_name); + dapl_fini(); +} + + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl/dapl/udapl/dapl_name_service.c b/branches/WOF2-3/ulp/dapl/dapl/udapl/dapl_name_service.c new file mode 100644 index 00000000..1adcad58 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/udapl/dapl_name_service.c @@ -0,0 +1,333 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_name_service.c + * + * PURPOSE: Provide simple, file base name services in the absence + * of DNS hooks for a particular transport type. If an + * InfiniBand implementation supports IPoIB, this should + * not be used. + * + * Description: Interfaces in this file are completely described in + * dapl_name_service.h + * + * $Id$ + **********************************************************************/ + +/* + * Include files for setting up a network name + */ +#include "dapl.h" +#include "dapl_name_service.h" + +/* + * Prototypes + */ +#ifdef NO_NAME_SERVICE +DAT_RETURN dapli_ns_create_gid_map(void); + +DAT_RETURN dapls_ns_add_address( + IN DAPL_GID_MAP *gme); +#endif /* NO_NAME_SERVICE */ + +/* + * dapls_ns_init + * + * Initialize naming services + * + * Input: + * none + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + */ +DAT_RETURN +dapls_ns_init (void) +{ + DAT_RETURN dat_status; + + dat_status = DAT_SUCCESS; +#ifdef NO_NAME_SERVICE + dat_status = dapli_ns_create_gid_map (); +#endif + + return dat_status; +} + + +#ifdef NO_NAME_SERVICE + +#define MAX_GID_ENTRIES 32 +DAPL_GID_MAP g_gid_map_table[MAX_GID_ENTRIES]; + +#ifdef _WIN32 +#define MAP_FILE "C:/WINDOWS/system32/drivers/etc/ibhosts" +#else +#define MAP_FILE "/etc/dapl/ibhosts" +#endif + + +/* + * dapli_ns_create_gid_map() + * + * Read /usr/local/etc/ibhosts to obtain host names and GIDs. + * Create a table containing IP addresses and GIDs which can + * be used for lookups. + * + * This implementation is a simple method providing name services + * when more advanced mechanisms do not exist. The proper way + * to obtain these mappings is to use a name service such as is + * provided by IPoIB on InfiniBand. + * + * Input: + * device_name Name of device as reported by the provider + * + * Output: + * none + * + * Returns: + * char * to string number + */ +DAT_RETURN +dapli_ns_create_gid_map (void) +{ + FILE *f; + GID gid; + char hostname[128]; + char tmp_buf[512]; + int rc = 0; + struct addrinfo *addr; + struct sockaddr_in *si; + DAPL_GID_MAP gmt; + + f = fopen (MAP_FILE, "r"); + if ( f == NULL ) + { + dapl_os_printf ("ERROR: Must have file <%s> for IP/GID mappings\n", + MAP_FILE); + return DAT_INTERNAL_ERROR; + } + dapl_os_memzero(tmp_buf,sizeof(tmp_buf)); + + while ( rc != EOF ) + { + if(feof(f)) + break; + + if (fgets(tmp_buf,sizeof(tmp_buf),f) != NULL) + { + if(tmp_buf[0] == '#' || tmp_buf[0] == '\n' || tmp_buf[0] == 0x20) + { + continue; + } + if ( (rc = sscanf ( tmp_buf, "%s " F64x " " F64x , hostname, &gid.gid_prefix, &gid.guid) ) != 3 ) + { + continue; + } + } + //rc = fscanf ( f, "%s " F64x " " F64x , hostname, &gid.gid_prefix, &gid.guid); + rc = dapls_osd_getaddrinfo (hostname, &addr); + + if ( rc != 0 ) + { + /* + * hostname not registered in DNS, provide a dummy value + */ + int err = WSAGetLastError(); + dapl_os_printf ("WARNING: <%s> not registered in DNS err = %u, using dummy IP value\n", + hostname, err); + /*dapl_os_memcpy(hca_ptr->hca_address.sa_data, "0x01020304", 4);*/ + gmt.ip_address = 0x01020304; + } + else + { + /* + * Load into the ip/gid mapping table + */ + si = (struct sockaddr_in *)addr->ai_addr; + if ( AF_INET == addr->ai_addr->sa_family ) + { + gmt.ip_address = si->sin_addr.s_addr; + } + else + { + dapl_dbg_log (DAPL_DBG_TYPE_WARN, + "WARNING: <%s> Address family not supported, using dummy IP value\n", + hostname); + gmt.ip_address = 0x01020304; + } + dapls_osd_freeaddrinfo (addr); + } + gmt.gid.gid_prefix = gid.gid_prefix; + gmt.gid.guid = gid.guid; + + dapls_ns_add_address (&gmt); + //rc = fscanf ( f, "%s " F64x " " F64x , hostname, &gid.gid_prefix, &gid.guid); + } + + fclose (f); + + return DAT_SUCCESS; +} + + +/* + * dapls_ns_add_address + * + * Add a table entry to the gid_map_table. + * + * Input: + * remote_ia_address remote IP address + * gid pointer to output gid + * + * Output: + * gid filled in GID + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + */ +DAT_RETURN +dapls_ns_add_address ( + IN DAPL_GID_MAP *gme) +{ + DAPL_GID_MAP *gmt; + int count; + + gmt = g_gid_map_table; + + for ( count = 0, gmt = g_gid_map_table; gmt->ip_address; gmt++ ) + { + count++; + } + + if ( count > MAX_GID_ENTRIES ) + { + return DAT_INSUFFICIENT_RESOURCES; + } + + *gmt = *gme; + + return DAT_SUCCESS; +} + + +/* + * dapls_ns_lookup_address + * + * Look up the provided IA_ADDRESS in the gid_map_table. Return + * the gid if found. + * + * Input: + * remote_ia_address remote IP address + * gid pointer to output gid + * + * Output: + * gid filled in GID + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + */ +DAT_RETURN +dapls_ns_lookup_address ( + IN DAPL_IA *ia_ptr, + IN DAT_IA_ADDRESS_PTR remote_ia_address, + OUT GID *gid) +{ + DAPL_GID_MAP *gmt; + struct sockaddr_in *si; + + ia_ptr = ia_ptr; /* unused here */ + + si = (struct sockaddr_in *)remote_ia_address; + + for ( gmt = g_gid_map_table; gmt->ip_address; gmt++ ) + { + if (gmt->ip_address == si->sin_addr.s_addr) + { + gid->guid = gmt->gid.guid; + gid->gid_prefix = gmt->gid.gid_prefix; + + return DAT_SUCCESS; + } + } + + return DAT_INVALID_PARAMETER; +} + +#else /* NO_NAME_SERVICE */ + +DAT_RETURN +dapls_ns_create_gid_map ( + IN DAPL_HCA *hca_ptr) +{ + return (dapls_ib_ns_create_gid_map (hca_ptr)); +} + + +DAT_RETURN +dapls_ns_remove_gid_map ( + IN DAPL_HCA *hca_ptr) +{ + return (dapls_ib_ns_remove_gid_map (hca_ptr)); +} + + +DAT_RETURN dapls_ns_map_gid ( + IN DAPL_HCA *hca_ptr, + IN DAT_IA_ADDRESS_PTR remote_ia_address, + OUT GID *gid) +{ + return (dapls_ib_ns_map_gid (hca_ptr, remote_ia_address, gid)); +} + +DAT_RETURN dapls_ns_map_ipaddr ( + IN DAPL_HCA *hca_ptr, + IN GID gid, + OUT DAT_IA_ADDRESS_PTR remote_ia_address) +{ + return (dapls_ib_ns_map_ipaddr (hca_ptr, gid, remote_ia_address)); +} + +#endif /* NO_NAME_SERVICE */ + + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl/dapl/udapl/dapl_name_service.h b/branches/WOF2-3/ulp/dapl/dapl/udapl/dapl_name_service.h new file mode 100644 index 00000000..8982f59d --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/udapl/dapl_name_service.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dapl_name_service.h + * + * PURPOSE: Utility defs & routines supporting name services + * + * $Id$ + * + **********************************************************************/ + +#include "dapl.h" +#include "dapl_adapter_util.h" + +/* + * Prototypes for name service routines + */ + +DAT_RETURN dapls_ns_init (void); + +#ifdef NO_NAME_SERVICE + +DAT_RETURN dapls_ns_lookup_address ( + IN DAPL_IA *ia_ptr, + IN DAT_IA_ADDRESS_PTR remote_ia_address, + OUT GID *gid); + + +#else + +DAT_RETURN dapls_ns_create_gid_map(DAPL_HCA *hca_ptr); +DAT_RETURN dapls_ns_remove_gid_map(DAPL_HCA *hca_ptr); + +DAT_RETURN dapls_ns_map_gid ( + IN DAPL_HCA *hca_ptr, + IN DAT_IA_ADDRESS_PTR remote_ia_address, + OUT GID *gid); + +DAT_RETURN dapls_ns_map_ipaddr ( + IN DAPL_HCA *hca_ptr, + IN GID gid, + OUT DAT_IA_ADDRESS_PTR remote_ia_address); + +#endif /* NO_NAME_SERVICE */ + diff --git a/branches/WOF2-3/ulp/dapl/dapl/udapl/dapl_timer_util.c b/branches/WOF2-3/ulp/dapl/dapl/udapl/dapl_timer_util.c new file mode 100644 index 00000000..7907a69d --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/udapl/dapl_timer_util.c @@ -0,0 +1,336 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_timer_util.c + * + * PURPOSE: DAPL timer management + * Description: Routines to add and cancel timer records. A timer record + * is put on the global timer queue. If the timer thread is + * not running, start it. The timer thread will sleep + * until a timer event or until a process wakes it up + * to notice a new timer is available; we use a DAPL_WAIT_OBJ + * for synchronization. + * + * If a timer is cancelled, it is simlpy removed from the + * queue. The timer may wakeup and notice there is no timer + * record to awaken at this time, so it will reset for the + * next entry. When there are no timer records to manage, + * the timer thread just sleeps until awakened. + * + * This file also contains the timer handler thread, + * embodied in dapls_timer_thread(). + * + * $Id$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_timer_util.h" + + +struct timer_head +{ + DAPL_LLIST_HEAD timer_list_head; + DAPL_OS_LOCK lock; + DAPL_OS_WAIT_OBJECT wait_object; + DAPL_OS_THREAD timeout_thread_handle; +} g_daplTimerHead; + +typedef struct timer_head DAPL_TIMER_HEAD; + + +void dapls_timer_thread (void *arg ); + +void +dapls_timer_init () +{ + /* + * Set up the timer thread elements. The timer thread isn't + * started until it is actually needed + */ + g_daplTimerHead.timer_list_head = NULL; + dapl_os_lock_init ( &g_daplTimerHead.lock ); + dapl_os_wait_object_init ( &g_daplTimerHead.wait_object ); + g_daplTimerHead.timeout_thread_handle = 0; +} + + +/* + * dapls_timer_set + * + * Set a timer. The timer will invoke the specified function + * after a number of useconds expires. + * + * Input: + * timer User provided timer structure + * func Function to invoke when timer expires + * data Argument passed to func() + * expires microseconds until timer fires + * + * Returns: + * no return value + * + */ +DAT_RETURN +dapls_timer_set ( + IN DAPL_OS_TIMER *timer, + IN void (*func) (void*), + IN void *data, + IN DAPL_OS_TIMEVAL expires ) +{ + DAPL_OS_TIMER *list_ptr; + DAPL_OS_TIMEVAL cur_time; + DAT_BOOLEAN wakeup_tmo_thread; + + DAPL_CNTR(DCNT_TIMER_SET); + /* + * Start the timer thread the first time we need a timer + */ + if ( g_daplTimerHead.timeout_thread_handle == 0 ) + { + dapl_os_thread_create ( dapls_timer_thread, + &g_daplTimerHead, + &g_daplTimerHead.timeout_thread_handle ); + } + + dapl_llist_init_entry ( &timer->list_entry); + wakeup_tmo_thread = false; + dapl_os_get_time ( &cur_time ); + timer->expires = cur_time + expires; /* calculate future time */ + timer->function = func; + timer->data = data; + + /* + * Put the element on the queue: sorted by wakeup time, eariliest + * first. + */ + dapl_os_lock ( &g_daplTimerHead.lock ); + /* + * Deal with 3 cases due to our list structure: + * 1) list is empty: become the list head + * 2) New timer is sooner than list head: become the list head + * 3) otherwise, sort the timer into the list, no need to wake + * the timer thread up + */ + if ( dapl_llist_is_empty ( &g_daplTimerHead.timer_list_head) ) + { + /* Case 1: add entry to head of list */ + dapl_llist_add_head ( &g_daplTimerHead.timer_list_head, + (DAPL_LLIST_ENTRY *)&timer->list_entry, + timer ); + wakeup_tmo_thread = true; + } + else + { + list_ptr = (DAPL_OS_TIMER *) + dapl_llist_peek_head (&g_daplTimerHead.timer_list_head); + + if ( timer->expires < list_ptr->expires ) + { + /* Case 2: add entry to head of list */ + dapl_llist_add_head ( &g_daplTimerHead.timer_list_head, + (DAPL_LLIST_ENTRY *)&timer->list_entry, + timer ); + wakeup_tmo_thread = true; + } + else + { + /* Case 3: figure out where entry goes in sorted list */ + list_ptr = dapl_llist_next_entry ( + &g_daplTimerHead.timer_list_head, + (DAPL_LLIST_ENTRY *)&list_ptr->list_entry); + + while (list_ptr != NULL) + { + if ( timer->expires < list_ptr->expires ) + { + dapl_llist_add_entry ( &g_daplTimerHead.timer_list_head, + (DAPL_LLIST_ENTRY *)&list_ptr->list_entry, + (DAPL_LLIST_ENTRY *)&timer->list_entry, + timer ); + break; + + } + list_ptr = dapl_llist_next_entry ( + &g_daplTimerHead.timer_list_head, + (DAPL_LLIST_ENTRY *)&list_ptr->list_entry); + } + if (list_ptr == NULL) + { + /* entry goes to the end of the list */ + dapl_llist_add_tail ( &g_daplTimerHead.timer_list_head, + (DAPL_LLIST_ENTRY *)&timer->list_entry, + timer ); + } + } + + } + dapl_os_unlock ( &g_daplTimerHead.lock ); + + if ( wakeup_tmo_thread ) + { + dapl_os_wait_object_wakeup (&g_daplTimerHead.wait_object); + } + + return DAT_SUCCESS; +} + + +/* + * dapls_os_timer_cancel + * + * Cancel a timer. Simply deletes the timer with no function invocations + * + * Input: + * timer User provided timer structure + * + * Returns: + * no return value + */ +void +dapls_timer_cancel ( + IN DAPL_OS_TIMER *timer) +{ + DAPL_CNTR(DCNT_TIMER_CANCEL); + dapl_os_lock ( &g_daplTimerHead.lock ); + /* + * make sure the entry has not been removed by another thread + */ + if ( ! dapl_llist_is_empty ( &g_daplTimerHead.timer_list_head ) && + timer->list_entry.list_head == &g_daplTimerHead.timer_list_head ) + { + dapl_llist_remove_entry ( &g_daplTimerHead.timer_list_head, + (DAPL_LLIST_ENTRY *)&timer->list_entry ); + } + /* + * If this was the first entry on the queue we could awaken the + * thread and have it reset the list; but it will just wake up + * and find that the timer entry has been removed, then go back + * to sleep, so don't bother. + */ + dapl_os_unlock ( &g_daplTimerHead.lock ); +} + + +/* + * dapls_timer_thread + * + * Core worker thread dealing with all timers. Basic algorithm: + * - Sleep until work shows up + * - Take first element of sorted timer list and wake + * invoke the callback if expired + * - Sleep for the timeout period if not expired + * + * Input: + * timer_head Timer head structure to manage timer lists + * + * Returns: + * no return value + */ +void +dapls_timer_thread ( + void *arg ) +{ + DAPL_OS_TIMER *list_ptr; + DAPL_OS_TIMEVAL cur_time; + DAT_RETURN dat_status = DAT_SUCCESS; + DAPL_TIMER_HEAD *timer_head; + + timer_head = arg; + + for (;;) + { + if ( dapl_llist_is_empty ( &timer_head->timer_list_head ) ) + { + dat_status = dapl_os_wait_object_wait (&timer_head->wait_object, + DAT_TIMEOUT_INFINITE ); + } + + /* + * Lock policy: + * While this thread is accessing the timer list, it holds the + * lock. Otherwise, it doesn't. + */ + dapl_os_lock ( &timer_head->lock ); + while ( ! dapl_llist_is_empty ( &timer_head->timer_list_head) ) + { + list_ptr = (DAPL_OS_TIMER *) + dapl_llist_peek_head ( &g_daplTimerHead.timer_list_head ); + dapl_os_get_time ( &cur_time ); + + if ( list_ptr->expires <= cur_time ) + { + /* + * Remove the entry from the list. Sort out how much + * time we need to sleep for the next one + */ + list_ptr = dapl_llist_remove_head ( &timer_head->timer_list_head ); + dapl_os_unlock ( &timer_head->lock ); + + /* + * Invoke the user callback + */ + list_ptr->function ( list_ptr->data ); + /* timer structure was allocated by caller, we don't + * free it here. + */ + + /* reacquire the lock */ + dapl_os_lock ( &timer_head->lock ); + } + else + { + dapl_os_unlock( &timer_head->lock ); + dat_status = + dapl_os_wait_object_wait ( &timer_head->wait_object, + (DAT_TIMEOUT)(list_ptr->expires - cur_time) ); + dapl_os_lock( &timer_head->lock ); + } + } + /* + * release the lock before going back to the top to sleep + */ + dapl_os_unlock( &timer_head->lock ); + + if ( dat_status == DAT_INTERNAL_ERROR ) + { + /* + * XXX What do we do here? + */ + } + } /* for (;;) */ +} + + + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl/dapl/udapl/dapl_timer_util.h b/branches/WOF2-3/ulp/dapl/dapl/udapl/dapl_timer_util.h new file mode 100644 index 00000000..21cea8cb --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/udapl/dapl_timer_util.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dapl_timer_util.h + * + * PURPOSE: DAPL timer management + * Description: support for dapl_timer.h + * + * $Id$ + **********************************************************************/ + +void dapls_timer_init ( void ); + +DAT_RETURN dapls_timer_set ( + IN DAPL_OS_TIMER *timer, + IN void (*func) (void*), + IN void *data, + IN DAPL_OS_TIMEVAL expires ); + +void dapls_timer_cancel ( + IN DAPL_OS_TIMER *timer); diff --git a/branches/WOF2-3/ulp/dapl/dapl/udapl/linux/dapl_osd.c b/branches/WOF2-3/ulp/dapl/dapl/udapl/linux/dapl_osd.c new file mode 100644 index 00000000..fec18fe7 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/udapl/linux/dapl_osd.c @@ -0,0 +1,642 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_osd.c + * + * PURPOSE: Operating System Dependent layer + * Description: + * Provide OS dependent functions with a canonical DAPL + * interface. Designed to be portable and hide OS specific quirks + * of common functions. + * + * + * $Id$ + **********************************************************************/ + +#include "dapl_osd.h" +#include "dapl.h" +#include "dapl_hca_util.h" +#include "dapl_ia_util.h" +#include "dapl_rmr_util.h" +#include "dapl_lmr_util.h" +#include "dapl_pz_util.h" +#include "dapl_ep_util.h" +#include "dapl_cr_util.h" +#include "dapl_evd_util.h" +#include "dapl_sp_util.h" +#include "dapl_adapter_util.h" +#include "dapl_provider.h" +#include "dapl_hash.h" +#include "dapl_timer_util.h" +#include "dapl_debug.h" + +#include +#include /* needed for getenv() */ +#include /* needed for pthread_atfork() */ +#include /* needed for thread setup */ + +static void dapls_osd_fork_cleanup (void); + +/* + * dapl_osd_init + * + * Do Linux initialization: + * - Set up fork handler to clean up DAPL resources in the child + * process after a fork(). + * + * Input: + * none + * + * Returns: + * DAT_SUCCESS + */ +void +dapl_os_init ( ) +{ + int status; + + /* + * Set up fork control + */ + status = pthread_atfork ( NULL, NULL, dapls_osd_fork_cleanup ); + if ( status != 0 ) + { + dapl_os_printf ("WARNING: pthread_atfork %d\n", status); + } +} + + +/* + * dapl_os_get_time + * + * Return 64 bit value of current time in microseconds. + * + * Input: + * loc User location to place current time + * + * Returns: + * DAT_SUCCESS + */ + +DAT_RETURN +dapl_os_get_time ( + OUT DAPL_OS_TIMEVAL * loc) +{ + struct timeval tv; + struct timezone tz; + + + gettimeofday (&tv, &tz); + *loc = ((DAT_UINT64) (tv.tv_sec) * 1000000L) + (DAT_UINT64) tv.tv_usec; + + return DAT_SUCCESS; +} + + +/* + * dapl_os_get__env_bool + * + * Return boolean value of passed in environment variable: 1 if present, + * 0 if not + * + * Input: + * + * + * Returns: + * TRUE or FALSE + */ +int +dapl_os_get_env_bool ( + char *env_str ) +{ + char *env_var; + + env_var = getenv (env_str); + if (env_var != NULL) + { + return 1; + } + + return 0; +} + + +/* + * dapl_os_get_env_val + * + * Update val to value of passed in environment variable if present + * + * Input: + * env_str + * def_val default value if environment variable does not exist + * + * Returns: + * TRUE or FALSE + */ +int +dapl_os_get_env_val ( + char *env_str, + int def_val ) +{ + char *env_var; + + env_var = getenv (env_str); + if ( env_var != NULL ) + { + def_val = strtol (env_var, NULL, 0); + } + + return def_val; +} + + +/* + * Wait object routines + */ + +/* + * dapl_os_wait_object_init + * + * Initialize a wait object + * + * Input: + * wait_obj + * + * Returns: + * DAT_SUCCESS + * DAT_INTERNAL_ERROR + */ +DAT_RETURN +dapl_os_wait_object_init ( + IN DAPL_OS_WAIT_OBJECT *wait_obj) +{ + wait_obj->signaled = DAT_FALSE; + if ( 0 != pthread_cond_init ( &wait_obj->cv, NULL ) ) + { + return DAT_ERROR (DAT_INTERNAL_ERROR,0); + } + + /* Always returns 0. */ + pthread_mutex_init ( &wait_obj->lock, NULL ); + + return DAT_SUCCESS; +} + + +/* Wait on the supplied wait object, up to the specified time_out. + * A timeout of DAT_TIMEOUT_INFINITE will wait indefinitely. + * Timeout should be specified in micro seconds. + * + * Functional returns: + * DAT_SUCCESS -- another thread invoked dapl_os_wait object_wakeup + * DAT_INVALID_STATE -- someone else is already waiting in this wait + * object. + * only one waiter is allowed at a time. + * DAT_ABORT -- another thread invoked dapl_os_wait_object_destroy + * DAT_TIMEOUT -- the specified time limit was reached. + */ + +DAT_RETURN +dapl_os_wait_object_wait ( + IN DAPL_OS_WAIT_OBJECT *wait_obj, + IN DAT_TIMEOUT timeout_val) +{ + DAT_RETURN dat_status; + int pthread_status; + struct timespec future; + + dat_status = DAT_SUCCESS; + pthread_status = 0; + + if ( timeout_val != DAT_TIMEOUT_INFINITE ) + { + struct timeval now; + struct timezone tz; + unsigned int microsecs; + + gettimeofday (&now, &tz); + microsecs = now.tv_usec + (timeout_val % 1000000); + if (microsecs > 1000000) + { + now.tv_sec = now.tv_sec + timeout_val / 1000000 + 1; + now.tv_usec = microsecs - 1000000; + } + else + { + now.tv_sec = now.tv_sec + timeout_val / 1000000; + now.tv_usec = microsecs; + } + + /* Convert timeval to timespec */ + future.tv_sec = now.tv_sec; + future.tv_nsec = now.tv_usec * 1000; + + pthread_mutex_lock (&wait_obj->lock); + while ( wait_obj->signaled == DAT_FALSE && pthread_status == 0) + { + pthread_status = pthread_cond_timedwait ( + &wait_obj->cv , &wait_obj->lock , &future ); + + /* + * No need to reset &future if we go around the loop; + * It's an absolute time. + */ + } + /* Reset the signaled status if we were woken up. */ + if (pthread_status == 0) + { + wait_obj->signaled = DAT_FALSE; + } + pthread_mutex_unlock (&wait_obj->lock); + } + else + { + pthread_mutex_lock (&wait_obj->lock); + while ( wait_obj->signaled == DAT_FALSE && pthread_status == 0) + { + pthread_status = pthread_cond_wait ( + &wait_obj->cv , &wait_obj->lock ); + } + /* Reset the signaled status if we were woken up. */ + if (pthread_status == 0) + { + wait_obj->signaled = DAT_FALSE; + } + pthread_mutex_unlock (&wait_obj->lock); + } + + if (ETIMEDOUT == pthread_status) + { + dat_status = DAT_ERROR (DAT_TIMEOUT_EXPIRED,0); + } + else if ( 0 != pthread_status) + { + dat_status = DAT_ERROR (DAT_INTERNAL_ERROR,0); + } + + return dat_status; +} + + +/* + * dapl_os_wait_object_wakeup + * + * Wakeup a thread waiting on a wait object + * + * Input: + * wait_obj + * + * Returns: + * DAT_SUCCESS + * DAT_INTERNAL_ERROR + */ +DAT_RETURN +dapl_os_wait_object_wakeup ( + IN DAPL_OS_WAIT_OBJECT *wait_obj) +{ + pthread_mutex_lock ( &wait_obj->lock ); + wait_obj->signaled = DAT_TRUE; + pthread_mutex_unlock ( &wait_obj->lock ); + if ( 0 != pthread_cond_signal ( &wait_obj->cv ) ) + { + return DAT_ERROR (DAT_INTERNAL_ERROR,0); + } + + return DAT_SUCCESS; +} + + +/* + * dapl_os_wait_object_destroy + * + * Destroy a wait object + * + * Input: + * wait_obj + * + * Returns: + * DAT_SUCCESS + * DAT_INTERNAL_ERROR + */ +DAT_RETURN +dapl_os_wait_object_destroy ( + IN DAPL_OS_WAIT_OBJECT *wait_obj) +{ + if ( 0 != pthread_cond_destroy ( &wait_obj->cv ) ) + { + return DAT_ERROR (DAT_INTERNAL_ERROR,0); + } + if ( 0 != pthread_mutex_destroy ( &wait_obj->lock ) ) + { + return DAT_ERROR (DAT_INTERNAL_ERROR,0); + } + + return DAT_SUCCESS; +} + + +/* + * dapls_osd_fork_cleanup + * + * Update val to value of passed in environment variable if present + * + * Input: + * env_str + * val Updated if environment variable exists + * + * Returns: + * TRUE or FALSE + */ +void dapls_osd_fork_cleanup (void) +{ + DAPL_PROVIDER_LIST_NODE *cur_node; + DAPL_HCA *hca_ptr; + DAPL_IA *ia_ptr; + DAPL_LMR *lmr_ptr; + DAPL_RMR *rmr_ptr; + DAPL_PZ *pz_ptr; + DAPL_CR *cr_ptr; + DAPL_EP *ep_ptr; + DAPL_EVD *evd_ptr; + DAT_EP_PARAM *param; + DAPL_SP *sp_ptr; + + while ( NULL != g_dapl_provider_list.head ) + { + cur_node = g_dapl_provider_list.head; + g_dapl_provider_list.head = cur_node->next; + + hca_ptr = (DAPL_HCA *) cur_node->data.extension; + + /* + * Walk the list of IA ptrs & clean up. This is purposely + * a destructive list walk, we really don't want to preserve + * any of it. + */ + while (!dapl_llist_is_empty ( &hca_ptr->ia_list_head ) ) + { + ia_ptr = (DAPL_IA *) + dapl_llist_peek_head ( &hca_ptr->ia_list_head ); + + /* + * The rest of the cleanup code is similar to dapl_ia_close, + * the big difference is that we don't release IB resources, + * only memory; the underlying IB subsystem doesn't deal + * with fork at all, so leave IB handles alone. + */ + while (!dapl_llist_is_empty ( &ia_ptr->rmr_list_head ) ) + { + rmr_ptr = (DAPL_RMR *) + dapl_llist_peek_head (&ia_ptr->rmr_list_head); + if ( rmr_ptr->param.lmr_triplet.virtual_address != 0 ) + { + (void) dapl_os_atomic_dec (&rmr_ptr->lmr->lmr_ref_count); + rmr_ptr->param.lmr_triplet.virtual_address = 0; + } + dapl_os_atomic_dec ( &rmr_ptr->pz->pz_ref_count ); + dapl_dbg_log (DAPL_DBG_TYPE_ERR,"FC_421:rmr- pz=%p,ref=0x%x\n", + rmr_ptr->pz,rmr_ptr->pz->pz_ref_count); + + dapl_rmr_dealloc ( rmr_ptr ); + } + + while (!dapl_llist_is_empty ( &ia_ptr->rsp_list_head )) + { + sp_ptr = (DAPL_SP *) + dapl_llist_peek_head ( &ia_ptr->rsp_list_head ); + dapl_os_atomic_dec (& ((DAPL_EVD *)sp_ptr->evd_handle)->evd_ref_count); + dapls_ia_unlink_sp ( ia_ptr, sp_ptr ); + dapls_sp_free_sp ( sp_ptr ); + } + + while (!dapl_llist_is_empty ( &ia_ptr->ep_list_head ) ) + { + ep_ptr = (DAPL_EP *) + dapl_llist_peek_head ( &ia_ptr->ep_list_head ); + param = &ep_ptr->param; + if ( param->pz_handle != NULL ) + { + dapl_os_atomic_dec ( & ((DAPL_PZ *)param->pz_handle)->pz_ref_count ); + dapl_dbg_log (DAPL_DBG_TYPE_ERR,"FC_441:ep- pz=%p,ref=0x%x\n", + ((DAPL_PZ *)param->pz_handle), + ((DAPL_PZ *)param->pz_handle)->pz_ref_count); + } + if ( param->recv_evd_handle != NULL ) + { + dapl_os_atomic_dec (& ((DAPL_EVD *)param->recv_evd_handle)->evd_ref_count); + } + if ( param->request_evd_handle ) + { + dapl_os_atomic_dec (& ((DAPL_EVD *)param->request_evd_handle)->evd_ref_count); + } + if ( param->connect_evd_handle != NULL ) + { + dapl_os_atomic_dec (& ((DAPL_EVD *)param->connect_evd_handle)->evd_ref_count); + } + + /* ...and free the resource */ + dapl_ia_unlink_ep ( ia_ptr, ep_ptr ); + dapl_ep_dealloc ( ep_ptr ); + } + + while ( !dapl_llist_is_empty (&ia_ptr->lmr_list_head) ) + { + lmr_ptr = (DAPL_LMR *) + dapl_llist_peek_head ( &ia_ptr->lmr_list_head ); + + (void) dapls_hash_remove ( lmr_ptr->header.owner_ia->hca_ptr->lmr_hash_table, + lmr_ptr->param.lmr_context, + NULL ); + + pz_ptr = (DAPL_PZ *) lmr_ptr->param.pz_handle; + dapl_os_atomic_dec ( &pz_ptr->pz_ref_count ); + dapl_dbg_log (DAPL_DBG_TYPE_ERR,"FC_471:lmr- pz=%p,ref=0x%x\n", + pz_ptr, pz_ptr->pz_ref_count); + dapl_lmr_dealloc ( lmr_ptr ); + } + + while ( !dapl_llist_is_empty ( &ia_ptr->psp_list_head ) ) + { + sp_ptr = (DAPL_SP *) + dapl_llist_peek_head ( &ia_ptr->psp_list_head ); + while ( !dapl_llist_is_empty (&sp_ptr->cr_list_head) ) + { + cr_ptr = (DAPL_CR *) + dapl_llist_peek_head ( &sp_ptr->cr_list_head ); + dapl_sp_remove_cr (sp_ptr, cr_ptr); + dapls_cr_free (cr_ptr); + } + + dapls_ia_unlink_sp ( ia_ptr, sp_ptr ); + dapl_os_atomic_dec (& ((DAPL_EVD *)sp_ptr->evd_handle)->evd_ref_count); + dapls_sp_free_sp ( sp_ptr ); + } + + while (!dapl_llist_is_empty ( &ia_ptr->pz_list_head ) ) + { + pz_ptr = (DAPL_PZ *) + dapl_llist_peek_head ( &ia_ptr->pz_list_head ); + dapl_pz_dealloc ( pz_ptr ); + } + + while (!dapl_llist_is_empty (&ia_ptr->evd_list_head)) + { + evd_ptr = (DAPL_EVD *) + dapl_llist_peek_head ( &ia_ptr->evd_list_head ); + dapl_ia_unlink_evd ( evd_ptr->header.owner_ia, evd_ptr ); + /* reset the cq_handle to avoid having it removed */ + evd_ptr->ib_cq_handle = IB_INVALID_HANDLE; + dapls_evd_dealloc ( evd_ptr ); + } + + dapl_hca_unlink_ia ( ia_ptr->hca_ptr, ia_ptr ); + /* asycn error evd was taken care of above, reset the pointer */ + ia_ptr->async_error_evd = NULL; + dapls_ia_free ( ia_ptr ); + } /* end while ( ia_ptr != NULL ) */ + + + dapl_os_free (cur_node, sizeof (DAPL_PROVIDER_LIST_NODE)); + } /* end while (NULL != g_dapl_provider_list.head) */ +} + + +/* + * Structure to contain all elements of a thread in order to enable a + * local routine to intercept and do some necessary initialization. + */ +struct thread_draft +{ + void (*func) (void *); /* start routine */ + void *data; /* argument to start routine */ +}; + +void dapli_thread_init ( struct thread_draft *thread_draft); + +/* + * dapls_os_thread_create + * + * Create a thread for dapl + * + * Input: + * func function to invoke thread + * f_arg argument to pass to function + * + * Output + * thread_id handle for thread + * + * Returns: + * DAT_SUCCESS + */ +DAT_RETURN +dapl_os_thread_create ( + IN void (*func) (void *), + IN void *data, + OUT DAPL_OS_THREAD *thread_id ) +{ + pthread_attr_t thread_attr; + struct thread_draft *thread_draft; + int status; + + /* + * Get default set of thread attributes + */ + status = pthread_attr_init ( &thread_attr ); + if ( status != 0 ) + { + return DAT_ERROR (DAT_INTERNAL_ERROR,0); + } + + /* Create dapl threads as detached from this process */ + status = pthread_attr_setdetachstate ( &thread_attr, + PTHREAD_CREATE_DETACHED ); + if ( status != 0 ) + { + return DAT_ERROR (DAT_INTERNAL_ERROR,0); + } + + thread_draft = dapl_os_alloc (sizeof ( struct thread_draft)); + + thread_draft->func = func; + thread_draft->data = data; + + /* Create the thread. Observe that we first invoke a local + * routine to set up OS parameters, before invoking the user + * specified routine. + */ + status = pthread_create ( thread_id, + &thread_attr, + (void * (*) (void *))dapli_thread_init, + (void *)thread_draft ); + + /* clean up resources */ + (void) pthread_attr_destroy ( &thread_attr ); + + if ( status != 0 ) + { + return DAT_ERROR (DAT_INSUFFICIENT_RESOURCES,0); + } + + return DAT_SUCCESS; +} + +/* + * dapli_thread_init + * + * Need to mask all signals from this thread in order to be a good + * citizen. Signals will arrive randomly and will be processed by + * whatever thread is running unless they are specifically blocked; and + * this should be a user thread, not a dapl thread + */ + +void +dapli_thread_init ( + struct thread_draft *thread_draft) +{ + sigset_t sigset; + void (*func) (void *); + void *data; + + sigfillset (&sigset); + pthread_sigmask ( SIG_BLOCK, &sigset, NULL); + + func = thread_draft->func; + data = thread_draft->data; + dapl_os_free (thread_draft, sizeof ( struct thread_draft )); + + (*func) (data); +} + + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl/dapl/udapl/linux/dapl_osd.h b/branches/WOF2-3/ulp/dapl/dapl/udapl/linux/dapl_osd.h new file mode 100644 index 00000000..3f786b6f --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/udapl/linux/dapl_osd.h @@ -0,0 +1,553 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dapl_osd.h + * + * PURPOSE: Operating System Dependent layer + * Description: + * Provide OS dependent data structures & functions with + * a canonical DAPL interface. Designed to be portable + * and hide OS specific quirks of common functions. + * + * $Id$ + **********************************************************************/ + +#ifndef _DAPL_OSD_H_ +#define _DAPL_OSD_H_ + +/* + * This file is defined for Linux systems only, including it on any + * other build will cause an error + */ +#ifndef __linux__ +#error UNDEFINED OS TYPE +#endif /* __linux__ */ + +#ifdef __IA64__ +#define IA64 +#endif + +#if !defined (__i386__) && !defined (IA64) +#error UNDEFINED ARCH +#endif + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for printf */ +#include +#include +#include /* for getaddrinfo */ + +#include "dapl_debug.h" + +/* + * Include files for setting up a network name + */ +#include +#include +#include +#include + +#ifdef IA64 +#include +#include +#endif + + +/* Useful debug definitions */ +#ifndef STATIC +#define STATIC static +#endif /* STATIC */ +#ifndef _INLINE_ +#define _INLINE_ __inline__ +#endif /* _INLINE_ */ + +void dapl_os_init ( void ); /* initialization function */ + +#define dapl_os_panic(...) \ + do { \ + fprintf(stderr, "PANIC in %s:%i:%s\n", __FILE__, __LINE__, __func__); \ + fprintf(stderr, __VA_ARGS__); \ + exit(1); \ + } while(0) + +#define dapl_ip_addr6(sockaddr) (((struct sockaddr_in6 *)sockaddr)->sin6_addr.s6_addr32) + +/* + * Atomic operations + */ + +typedef volatile DAT_COUNT DAPL_ATOMIC; + +/* atomic function prototypes */ +STATIC _INLINE_ DAT_COUNT +dapl_os_atomic_inc ( + INOUT DAPL_ATOMIC *v); + +STATIC _INLINE_ DAT_COUNT +dapl_os_atomic_dec ( + INOUT DAPL_ATOMIC *v); + +STATIC _INLINE_ DAT_COUNT +dapl_os_atomic_assign ( + INOUT DAPL_ATOMIC *v, + IN DAT_COUNT match_value, + IN DAT_COUNT new_value ); + +int dapl_os_get_env_bool ( + char *env_str ); + +int dapl_os_get_env_val ( + char *env_str, + int def_val ); + + + +/* atomic functions */ + +/* dapl_os_atomic_inc + * + * get the current value of '*v', and then increment it. + * + * This is equivalent to an IB atomic fetch and add of 1, + * except that a DAT_COUNT might be 32 bits, rather than 64 + * and it occurs in local memory. + */ + +STATIC _INLINE_ DAT_COUNT +dapl_os_atomic_inc ( + INOUT DAPL_ATOMIC *v) +{ + DAT_COUNT old_value; + + /* + * Use the Pentium Exchange and Add instruction. + * The assembler doesn't deal with xadd so forge it. + */ +#ifdef IA64 +IA64_FETCHADD (old_value,v,1,4); + +#else + __asm__ __volatile__ ( + ".byte 0xf0, 0x0f, 0xc1, 0x02" // lock; xaddl %eax, (%edx) + : "=a" (old_value) + : "0" (+1), "m" (*v), "d" (v) + : "memory"); +#endif + return old_value; +} + + +/* dapl_os_atomic_dec + * + * decrement the current value of '*v'. No return value is required. + */ + +STATIC _INLINE_ DAT_COUNT +dapl_os_atomic_dec ( + INOUT DAPL_ATOMIC *v) +{ + DAT_COUNT old_value; + + assert(*v != 0); + + /* + * Use the Pentium Exchange and Add instruction. + * The assembler doesn't deal with xadd so forge it + */ + +#ifdef IA64 +IA64_FETCHADD (old_value,v,-1,4); + +#else + __asm__ __volatile__ ( + ".byte 0xf0, 0x0f, 0xc1, 0x02" // lock; xaddl %eax, (%edx) + : "=a" (old_value) + : "0" (-1), "m" (*v), "d" (v) + : "memory"); + +#endif + return old_value; +} + + +/* dapl_os_atomic_assign + * + * assign 'new_value' to '*v' if the current value + * matches the provided 'match_value'. + * + * Make no assignment if there is no match. + * + * Return the current value in any case. + * + * This matches the IBTA atomic operation compare & swap + * except that it is for local memory and a DAT_COUNT may + * be only 32 bits, rather than 64. + */ + +STATIC _INLINE_ DAT_COUNT +dapl_os_atomic_assign ( + INOUT DAPL_ATOMIC *v, + IN DAT_COUNT match_value, + IN DAT_COUNT new_value ) +{ + DAT_COUNT current_value; + + /* + * Use the Pentium compare and exchange instruction + */ + +#ifdef IA64 + +current_value = ia64_cmpxchg("acq",v,match_value,new_value,4); + +#else + __asm__ __volatile__ ( + "lock; cmpxchgl %1, %2" + : "=a" (current_value) + : "q" (new_value), "m" (*v), "0" (match_value) + : "memory"); +#endif + return current_value; +} + +/* + * Thread Functions + */ +typedef pthread_t DAPL_OS_THREAD; + +DAT_RETURN +dapl_os_thread_create ( + IN void (*func) (void *), + IN void *data, + OUT DAPL_OS_THREAD *thread_id ); + + +/* + * Lock Functions + */ + +typedef pthread_mutex_t DAPL_OS_LOCK; + +/* function prototypes */ +STATIC _INLINE_ DAT_RETURN +dapl_os_lock_init ( + IN DAPL_OS_LOCK *m); + +STATIC _INLINE_ DAT_RETURN +dapl_os_lock ( + IN DAPL_OS_LOCK *m); + +STATIC _INLINE_ DAT_RETURN +dapl_os_unlock ( + IN DAPL_OS_LOCK *m); + +STATIC _INLINE_ DAT_RETURN +dapl_os_lock_destroy ( + IN DAPL_OS_LOCK *m); + +/* lock functions */ +STATIC _INLINE_ DAT_RETURN +dapl_os_lock_init ( + IN DAPL_OS_LOCK *m) +{ + /* pthread_mutex_init always returns 0 */ + pthread_mutex_init (m, NULL); + + return DAT_SUCCESS; +} + +STATIC _INLINE_ DAT_RETURN +dapl_os_lock ( + IN DAPL_OS_LOCK *m) +{ + if (0 == pthread_mutex_lock (m)) + { + return DAT_SUCCESS; + } + else + { + return DAT_CLASS_ERROR | DAT_INTERNAL_ERROR; + } +} + +STATIC _INLINE_ DAT_RETURN +dapl_os_unlock ( + IN DAPL_OS_LOCK *m) +{ + if (0 == pthread_mutex_unlock (m)) + { + return DAT_SUCCESS; + } + else + { + return DAT_CLASS_ERROR | DAT_INTERNAL_ERROR; + } +} + +STATIC _INLINE_ DAT_RETURN +dapl_os_lock_destroy ( + IN DAPL_OS_LOCK *m) +{ + if (0 == pthread_mutex_destroy (m)) + { + return DAT_SUCCESS; + } + else + { + return DAT_CLASS_ERROR | DAT_INTERNAL_ERROR; + } +} + + +/* + * Wait Objects + */ + +/* + * The wait object invariant: Presuming a call to dapl_os_wait_object_wait + * occurs at some point, there will be at least one wakeup after each call + * to dapl_os_wait_object_signal. I.e. Signals are not ignored, though + * they may be coallesced. + */ + +typedef struct +{ + DAT_BOOLEAN signaled; + pthread_cond_t cv; + pthread_mutex_t lock; +} DAPL_OS_WAIT_OBJECT; + +/* function prototypes */ +DAT_RETURN +dapl_os_wait_object_init ( + IN DAPL_OS_WAIT_OBJECT *wait_obj); + +DAT_RETURN +dapl_os_wait_object_wait ( + IN DAPL_OS_WAIT_OBJECT *wait_obj, + IN DAT_TIMEOUT timeout_val); + +DAT_RETURN +dapl_os_wait_object_wakeup ( + IN DAPL_OS_WAIT_OBJECT *wait_obj); + +DAT_RETURN +dapl_os_wait_object_destroy ( + IN DAPL_OS_WAIT_OBJECT *wait_obj); + +/* + * Memory Functions + */ + +/* function prototypes */ +STATIC _INLINE_ void *dapl_os_alloc (int size); + +STATIC _INLINE_ void *dapl_os_realloc (void *ptr, int size); + +STATIC _INLINE_ void dapl_os_free (void *ptr, int size); + +STATIC _INLINE_ void * dapl_os_memzero (void *loc, int size); + +STATIC _INLINE_ void * dapl_os_memcpy (void *dest, const void *src, int len); + +STATIC _INLINE_ int dapl_os_memcmp (const void *mem1, const void *mem2, int len); + +/* memory functions */ + + +STATIC _INLINE_ void *dapl_os_alloc (int size) +{ + return malloc (size); +} + +STATIC _INLINE_ void *dapl_os_realloc (void *ptr, int size) +{ + return realloc(ptr, size); +} + +STATIC _INLINE_ void dapl_os_free (void *ptr, int size) +{ + free (ptr); +} + +STATIC _INLINE_ void * dapl_os_memzero (void *loc, int size) +{ + return memset (loc, 0, size); +} + +STATIC _INLINE_ void * dapl_os_memcpy (void *dest, const void *src, int len) +{ + return memcpy (dest, src, len); +} + +STATIC _INLINE_ int dapl_os_memcmp (const void *mem1, const void *mem2, int len) +{ + return memcmp (mem1, mem2, len); +} + +/* + * String Functions + */ + +STATIC _INLINE_ unsigned int dapl_os_strlen(const char *str) +{ + return strlen(str); +} + +STATIC _INLINE_ char * dapl_os_strdup(const char *str) +{ + return strdup(str); +} + + +/* + * Timer Functions + */ + +typedef DAT_UINT64 DAPL_OS_TIMEVAL; + + +typedef struct dapl_timer_entry DAPL_OS_TIMER; +typedef unsigned long long int DAPL_OS_TICKS; + +/* function prototypes */ + +/* + * Sleep for the number of micro seconds specified by the invoking + * function + */ +STATIC _INLINE_ void dapl_os_sleep_usec (int sleep_time) +{ + struct timespec sleep_spec, rem; + + /* + * Sleep for the specified number of microseconds + */ + sleep_spec.tv_sec = sleep_time / 100000; + sleep_spec.tv_nsec = sleep_time % 100000 * 1000; + nanosleep (&sleep_spec, &rem); +} + +STATIC _INLINE_ DAPL_OS_TICKS dapl_os_get_ticks (void); + +STATIC _INLINE_ int dapl_os_ticks_to_seconds (DAPL_OS_TICKS ticks); + + +DAT_RETURN dapl_os_get_time (DAPL_OS_TIMEVAL *); +/* timer functions */ + +STATIC _INLINE_ DAPL_OS_TICKS dapl_os_get_ticks (void) +{ + DAPL_OS_TICKS x; + __asm__ volatile(".byte 0x0f,0x31" : "=A" (x)); + return x; +} + +STATIC _INLINE_ int dapl_os_ticks_to_seconds (DAPL_OS_TICKS ticks) +{ + /* NOT YET IMPLEMENTED IN USER-SPACE */ + return 0; +} + + +/* + * dapl_os_timer_cancel() + * + * Cancel a running timer. The timer will invoke the specified + * function after a number of useconds expires. + * + * Input: + * timer Running timer + * + * Returns: + * no return value + * + */ +void dapl_os_timer_cancel ( DAPL_OS_TIMER *timer ); + + +/* + * + * Name Service Helper functions + * + */ +#define dapls_osd_getaddrinfo(name, addr_ptr) getaddrinfo(name,NULL,NULL,addr_ptr) +#define dapls_osd_freeaddrinfo(addr) freeaddrinfo (addr) + +/* + * *printf format helpers. We use the C string constant concatenation + * ability to define 64 bit formats, which unfortunatly are non standard + * in the C compiler world. E.g. %llx for gcc, %I64x for Windows + */ +#define F64d "%lld" +#define F64u "%llu" +#define F64x "%llx" +#define F64X "%llX" + + +/* + * Conversion Functions + */ + +STATIC _INLINE_ long int +dapl_os_strtol(const char *nptr, char **endptr, int base) +{ + return strtol(nptr, endptr, base); +} + + +/* + * Helper Functions + */ + + +#define dapl_os_assert(expression) assert(expression) +#define dapl_os_printf(...) fprintf(stderr,__VA_ARGS__) +#define dapl_os_vprintf(fmt,args) vfprintf(stderr, fmt, args); +#define dapl_os_syslog(fmt,args) vsyslog (LOG_USER | LOG_DEBUG,fmt,args) + + + +#endif /* _DAPL_OSD_H_ */ + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl/dapl/udapl/makefile b/branches/WOF2-3/ulp/dapl/dapl/udapl/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/udapl/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\..\inc\openib.def diff --git a/branches/WOF2-3/ulp/dapl/dapl/udapl/makefile.wnd b/branches/WOF2-3/ulp/dapl/dapl/udapl/makefile.wnd new file mode 100644 index 00000000..ba237b8a --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/udapl/makefile.wnd @@ -0,0 +1,283 @@ +# +# Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. +# +# This Software is licensed under either one of the following two licenses: +# +# 1) under the terms of the "Common Public License 1.0" a copy of which is +# in the file LICENSE.txt in the root directory. The license is also +# available from the Open Source Initiative, see +# http://www.opensource.org/licenses/cpl.php. +# OR +# +# 2) under the terms of the "The BSD License" a copy of which is in the file +# LICENSE2.txt in the root directory. The license is also available from +# the Open Source Initiative, see +# http://www.opensource.org/licenses/bsd-license.php. +# +# Licensee has the right to choose either one of the above two licenses. +# +# Redistributions of source code must retain both the above copyright +# notice and either one of the license notices. +# +# Redistributions in binary form must reproduce both the above copyright +# notice, either one of the license notices in the documentation +# and/or other materials provided with the distribution. +# + +#********************************************************************* +# +# MODULE: Makefile +# +# PURPOSE: Makefile for DAT registration module +# +#********************************************************************* + +#********************************************************************* +# +# Dot Directives +# +#*********************************************************************/ + +.SUFFIXES : # clear the .SUFFIXES list +.SUFFIXES : .c # initialize .SUFFIXES list + + +#********************************************************************* +# +# Macros +# +#*********************************************************************/ + +UDAPL = . +UDAPL_INCLUDE = $(UDAPL)/../include +UDAPL_COMMON = $(UDAPL)/../common +UDAPL_WINDOWS = $(UDAPL)/windows + +OBJ_PATH = $(UDAPL)/Obj +TARGET_PATH = $(UDAPL)/Target + +OBJS = $(OBJ_PATH)/dapl_init.obj \ + $(OBJ_PATH)/dapl_timer_util.obj \ + $(OBJ_PATH)/dapl_name_service.obj \ + $(OBJ_PATH)/dapl_osd.obj \ + $(OBJ_PATH)/dapl_cookie.obj \ + $(OBJ_PATH)/dapl_cr_accept.obj \ + $(OBJ_PATH)/dapl_cr_query.obj \ + $(OBJ_PATH)/dapl_cr_reject.obj \ + $(OBJ_PATH)/dapl_cr_util.obj \ + $(OBJ_PATH)/dapl_cr_callback.obj \ + $(OBJ_PATH)/dapl_cr_handoff.obj \ + $(OBJ_PATH)/dapl_ep_connect.obj \ + $(OBJ_PATH)/dapl_ep_create.obj \ + $(OBJ_PATH)/dapl_ep_disconnect.obj \ + $(OBJ_PATH)/dapl_ep_dup_connect.obj \ + $(OBJ_PATH)/dapl_ep_free.obj \ + $(OBJ_PATH)/dapl_ep_reset.obj \ + $(OBJ_PATH)/dapl_ep_get_status.obj \ + $(OBJ_PATH)/dapl_ep_modify.obj \ + $(OBJ_PATH)/dapl_ep_post_rdma_read.obj \ + $(OBJ_PATH)/dapl_ep_post_rdma_write.obj \ + $(OBJ_PATH)/dapl_ep_post_recv.obj \ + $(OBJ_PATH)/dapl_ep_post_send.obj \ + $(OBJ_PATH)/dapl_ep_query.obj \ + $(OBJ_PATH)/dapl_ep_util.obj \ + $(OBJ_PATH)/dapl_evd_create.obj \ + $(OBJ_PATH)/dapl_evd_dequeue.obj \ + $(OBJ_PATH)/dapl_evd_disable.obj \ + $(OBJ_PATH)/dapl_evd_enable.obj \ + $(OBJ_PATH)/dapl_evd_free.obj \ + $(OBJ_PATH)/dapl_evd_modify_cno.obj \ + $(OBJ_PATH)/dapl_evd_post_se.obj \ + $(OBJ_PATH)/dapl_evd_query.obj \ + $(OBJ_PATH)/dapl_evd_resize.obj \ + $(OBJ_PATH)/dapl_evd_wait.obj \ + $(OBJ_PATH)/dapl_evd_util.obj \ + $(OBJ_PATH)/dapl_evd_cq_async_error_callb.obj \ + $(OBJ_PATH)/dapl_evd_qp_async_error_callb.obj \ + $(OBJ_PATH)/dapl_evd_un_async_error_callb.obj \ + $(OBJ_PATH)/dapl_evd_connection_callb.obj \ + $(OBJ_PATH)/dapl_evd_dto_callb.obj \ + $(OBJ_PATH)/dapl_evd_set_unwaitable.obj \ + $(OBJ_PATH)/dapl_evd_clear_unwaitable.obj \ + $(OBJ_PATH)/dapl_get_consumer_context.obj \ + $(OBJ_PATH)/dapl_get_handle_type.obj \ + $(OBJ_PATH)/dapl_hash.obj \ + $(OBJ_PATH)/dapl_hca_util.obj \ + $(OBJ_PATH)/dapl_ia_close.obj \ + $(OBJ_PATH)/dapl_ia_open.obj \ + $(OBJ_PATH)/dapl_ia_query.obj \ + $(OBJ_PATH)/dapl_ia_util.obj \ + $(OBJ_PATH)/dapl_llist.obj \ + $(OBJ_PATH)/dapl_lmr_create.obj \ + $(OBJ_PATH)/dapl_lmr_free.obj \ + $(OBJ_PATH)/dapl_lmr_query.obj \ + $(OBJ_PATH)/dapl_lmr_util.obj \ + $(OBJ_PATH)/dapl_mr_util.obj \ + $(OBJ_PATH)/dapl_provider.obj \ + $(OBJ_PATH)/dapl_sp_util.obj \ + $(OBJ_PATH)/dapl_psp_create.obj \ + $(OBJ_PATH)/dapl_psp_create_any.obj \ + $(OBJ_PATH)/dapl_psp_free.obj \ + $(OBJ_PATH)/dapl_psp_query.obj \ + $(OBJ_PATH)/dapl_pz_create.obj \ + $(OBJ_PATH)/dapl_pz_free.obj \ + $(OBJ_PATH)/dapl_pz_query.obj \ + $(OBJ_PATH)/dapl_pz_util.obj \ + $(OBJ_PATH)/dapl_rmr_create.obj \ + $(OBJ_PATH)/dapl_rmr_free.obj \ + $(OBJ_PATH)/dapl_rmr_bind.obj \ + $(OBJ_PATH)/dapl_rmr_query.obj \ + $(OBJ_PATH)/dapl_rmr_util.obj \ + $(OBJ_PATH)/dapl_rsp_create.obj \ + $(OBJ_PATH)/dapl_rsp_free.obj \ + $(OBJ_PATH)/dapl_rsp_query.obj \ + $(OBJ_PATH)/dapl_cno_create.obj \ + $(OBJ_PATH)/dapl_cno_modify_agent.obj \ + $(OBJ_PATH)/dapl_cno_free.obj \ + $(OBJ_PATH)/dapl_cno_wait.obj \ + $(OBJ_PATH)/dapl_cno_query.obj \ + $(OBJ_PATH)/dapl_cno_util.obj \ + $(OBJ_PATH)/dapl_set_consumer_context.obj \ + $(OBJ_PATH)/dapl_ring_buffer_util.obj \ + $(OBJ_PATH)/dapl_debug.obj + +LIBRARY = $(TARGET_PATH)/dapl.dll + +# +# Provider specific flags & files +# + +PROVIDER_LIB = $(SYSTEMROOT)\VerbsLibrary.lib + +# Define Provider for this build +#IBAPI=1 +# VAPI=1 +IBAL=1 +!if defined(VAPI) + +PROVIDER = $(UDAPL)/../vapi + +PROVIDER_OBJS = \ + $(OBJDIR)/dapl_vapi_util.obj \ + $(OBJDIR)/dapl_vapi_qp.obj \ + $(OBJDIR)/dapl_vapi_cm.obj + +PROVIDER_INCLUDES = \ + /I $(PROVIDER) \ + /I $(MTHOME)/include +# /I $(DAPL_BASE)/include/ib/MELLANOX + +PROVIDER_CFLAGS = -DMTL_MODULE=M_dapl -DMAX_TRACE=8 -DMAX_DEBUG=8 -DMAX_ERROR=8 -DDAPL_DBG -DVAPI + +!endif + +!if defined(IBAPI) + +PROVIDER = $(UDAPL)/../ibapi + +PROVIDER_OBJS = $(OBJ_PATH)/dapl_ibapi_cm.obj \ + $(OBJ_PATH)/dapl_ibapi_qp.obj \ + $(OBJ_PATH)/dapl_ibapi_util.obj + +PROVIDER_INCLUDES = \ + /I $(PROVIDER) \ + /I $(UDAPL_INCLUDE)/ib/IBM \ + /I $(UDAPL_INCLUDE)/ib/IBM/us + +PROVIDER_CFLAGS = -DIBAPI -DDAPL_ATS + +!endif +!if defined(IBAL) + +PROVIDER = $(UDAPL)/../ibal + +PROVIDER_OBJS = $(OBJ_PATH)/dapl_ibal_cm.obj \ + $(OBJ_PATH)/dapl_ibal_qp.obj \ + $(OBJ_PATH)/dapl_ibal_util.obj + +PROVIDER_INCLUDES = \ + /I $(PROVIDER) \ + /I $(UDAPL_INCLUDE)/../../../winuser/include/ \ + /I $(UDAPL_INCLUDE)/../../../shared/include/ \ + /I $(UDAPL_INCLUDE)/../../../shared/include/iba + +PROVIDER_CFLAGS = /DIBAL /DDAPL_ATS /D_VENDOR_IBAL_ /DDAPL_DBG + +!endif + +# +# Compiler +# + +CC = cl + +INC_FLAGS = \ + /I ../../dat/include \ + /I $(UDAPL) \ + /I $(UDAPL_INCLUDE) \ + /I $(UDAPL_COMMON) \ + /I $(UDAPL_WINDOWS) \ + $(PROVIDER_INCLUDES) + +CC_FLAGS = \ + /nologo /Zel /Gy /W3 /Gd /QIfdiv- /QIf /QI0f /GB /Gi- /Gm- \ + /GX- /GR- /GF /Z7 /Od /Oi /Oy- /DWIN32 /D_X86_ /D__i386__ \ + $(INC_FLAGS) $(PROVIDER_CFLAGS) + +# +# Linker +# + +LINK = link + +LIBS = libc.lib ws2_32.lib $(PROVIDER_LIB) ../../dat/udat/Target/dat.lib + +LINK_FLAGS = \ + /nologo /dll /DEF:$(UDAPL_WINDOWS)/dapl_win.def \ + /DEBUG /incremental:no /machine:I386 $(LIBS) + +# +# System Utilities +# + +RM = rm -f + + +#********************************************************************* +# +# Inference Rules +# +#*********************************************************************/ + +{$(UDAPL)}.c{$(OBJ_PATH)}.obj: + $(CC) $(CC_FLAGS) /Fo$@ /c $< + +{$(UDAPL_COMMON)}.c{$(OBJ_PATH)}.obj: + $(CC) $(CC_FLAGS) /Fo$@ /c $< + +{$(UDAPL_WINDOWS)}.c{$(OBJ_PATH)}.obj: + $(CC) $(CC_FLAGS) /Fo$@ /c $< + +{$(PROVIDER)}.c{$(OBJ_PATH)}.obj: + $(CC) $(CC_FLAGS) /Fo$@ /c $< + + +#********************************************************************* +# +# Description Blocks +# +#*********************************************************************/ + +all : mkdirs $(LIBRARY) + +mkdirs: + if not exist "$(OBJ_PATH)" mkdir "$(OBJ_PATH)" + if not exist "$(TARGET_PATH)" mkdir "$(TARGET_PATH)" + +$(LIBRARY) : $(OBJS) $(PROVIDER_OBJS) + $(LINK) $(LINK_FLAGS) /out:$(LIBRARY) $(OBJS) $(PROVIDER_OBJS) + +clean: + $(RM) $(OBJS) $(PROVIDER_OBJS) + $(RM) $(LIBRARY) + $(RM) $(TARGET_PATH)/*.pdb $(TARGET_PATH)/*.exp $(TARGET_PATH)/*.lib diff --git a/branches/WOF2-3/ulp/dapl/dapl/udapl/udapl.rc b/branches/WOF2-3/ulp/dapl/dapl/udapl/udapl.rc new file mode 100644 index 00000000..e00b3280 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/udapl/udapl.rc @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2007 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#if DBG +#define VER_FILEDESCRIPTION_STR "Direct Access Provider Library v1.1 (Debug)" +#define VER_INTERNALNAME_STR "dapld.dll" +#define VER_ORIGINALFILENAME_STR "dapld.dll" +#else +#define VER_FILEDESCRIPTION_STR "Direct Access Provider Library v1.1" +#define VER_INTERNALNAME_STR "dapl.dll" +#define VER_ORIGINALFILENAME_STR "dapl.dll" +#endif + +#include diff --git a/branches/WOF2-3/ulp/dapl/dapl/udapl/udapl_exports.src b/branches/WOF2-3/ulp/dapl/dapl/udapl/udapl_exports.src new file mode 100644 index 00000000..214effb7 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/udapl/udapl_exports.src @@ -0,0 +1,11 @@ +#if DBG +LIBRARY dapld.dll +#else +LIBRARY dapl.dll +#endif + +#ifndef _WIN64 +EXPORTS +dat_provider_init +dat_provider_fini +#endif diff --git a/branches/WOF2-3/ulp/dapl/dapl/udapl/udapl_sources.c b/branches/WOF2-3/ulp/dapl/dapl/udapl/udapl_sources.c new file mode 100644 index 00000000..1acb06e2 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/udapl/udapl_sources.c @@ -0,0 +1,112 @@ +/* + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/* + * Include all files that are not in children directories. + */ + +#include "..\common\dapl_cno_create.c" +#include "..\common\dapl_cno_free.c" +#include "..\common\dapl_cno_modify_agent.c" +#include "..\common\dapl_cno_query.c" +#include "..\common\dapl_cno_util.c" +#include "..\common\dapl_cno_wait.c" +#include "..\common\dapl_cookie.c" +#include "..\common\dapl_cr_accept.c" +#include "..\common\dapl_cr_callback.c" +#include "..\common\dapl_cr_handoff.c" +#include "..\common\dapl_cr_query.c" +#include "..\common\dapl_cr_reject.c" +#include "..\common\dapl_cr_util.c" +#include "..\common\dapl_debug.c" +#include "..\common\dapl_ep_connect.c" +#include "..\common\dapl_ep_create.c" +#include "..\common\dapl_ep_disconnect.c" +#include "..\common\dapl_ep_dup_connect.c" +#include "..\common\dapl_ep_free.c" +#include "..\common\dapl_ep_get_status.c" +#include "..\common\dapl_ep_modify.c" +#include "..\common\dapl_ep_post_rdma_read.c" +#include "..\common\dapl_ep_post_rdma_write.c" +#include "..\common\dapl_ep_post_recv.c" +#include "..\common\dapl_ep_post_send.c" +#include "..\common\dapl_ep_query.c" +#include "..\common\dapl_ep_reset.c" +#include "..\common\dapl_ep_util.c" +#include "..\common\dapl_evd_clear_unwaitable.c" +#include "..\common\dapl_evd_connection_callb.c" +#include "..\common\dapl_evd_cq_async_error_callb.c" +#include "..\common\dapl_evd_create.c" +#include "..\common\dapl_evd_dequeue.c" +#include "..\common\dapl_evd_disable.c" +#include "..\common\dapl_evd_dto_callb.c" +#include "..\common\dapl_evd_enable.c" +#include "..\common\dapl_evd_free.c" +#include "..\common\dapl_evd_modify_cno.c" +#include "..\common\dapl_evd_post_se.c" +#include "..\common\dapl_evd_qp_async_error_callb.c" +#include "..\common\dapl_evd_query.c" +#include "..\common\dapl_evd_resize.c" +#include "..\common\dapl_evd_set_unwaitable.c" +#include "..\common\dapl_evd_un_async_error_callb.c" +#include "..\common\dapl_evd_util.c" +#include "..\common\dapl_evd_wait.c" +#include "..\common\dapl_get_consumer_context.c" +#include "..\common\dapl_get_handle_type.c" +#include "..\common\dapl_hash.c" +#include "..\common\dapl_hca_util.c" +#include "..\common\dapl_ia_close.c" +#include "..\common\dapl_ia_open.c" +#include "..\common\dapl_ia_query.c" +#include "..\common\dapl_ia_util.c" +#include "..\common\dapl_llist.c" +#include "..\common\dapl_lmr_create.c" +#include "..\common\dapl_lmr_free.c" +#include "..\common\dapl_lmr_query.c" +#include "..\common\dapl_lmr_util.c" +#include "..\common\dapl_mr_util.c" +#include "..\common\dapl_provider.c" +#include "..\common\dapl_psp_create.c" +#include "..\common\dapl_psp_create_any.c" +#include "..\common\dapl_psp_free.c" +#include "..\common\dapl_psp_query.c" +#include "..\common\dapl_pz_create.c" +#include "..\common\dapl_pz_free.c" +#include "..\common\dapl_pz_query.c" +#include "..\common\dapl_pz_util.c" +#include "..\common\dapl_ring_buffer_util.c" +#include "..\common\dapl_rmr_bind.c" +#include "..\common\dapl_rmr_create.c" +#include "..\common\dapl_rmr_free.c" +#include "..\common\dapl_rmr_query.c" +#include "..\common\dapl_rmr_util.c" +#include "..\common\dapl_rsp_create.c" +#include "..\common\dapl_rsp_free.c" +#include "..\common\dapl_rsp_query.c" +#include "..\common\dapl_set_consumer_context.c" +#include "..\common\dapl_sp_util.c" +#include "..\ibal\dapl_ibal_cm.c" +#include "..\ibal\dapl_ibal_qp.c" +#include "..\ibal\dapl_ibal_util.c" +#include "windows\dapl_osd.c" diff --git a/branches/WOF2-3/ulp/dapl/dapl/udapl/windows/dapl_osd.c b/branches/WOF2-3/ulp/dapl/dapl/udapl/windows/dapl_osd.c new file mode 100644 index 00000000..6d07686b --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/udapl/windows/dapl_osd.c @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_osd.c + * + * PURPOSE: Operating System Dependent layer + * Description: + * Provide OS dependent functions with a canonical DAPL + * interface. Designed to be portable and hide OS specific quirks + * of common functions. + * + * + * $Id$ + **********************************************************************/ + +/* + * MUST have the Microsoft Platform SDK installed for Windows to build + * and work properly + */ +#include "dapl.h" +#include "dapl_osd.h" +#include +#include /* needed for getenv() */ + + + +/* + * DllMain + * + * Primary Windows entry point + * + * Input: + * hDllHandle handle to DLL module + * fdwReason reason for calling function + * lpReserved reserved + * + * Returns: + * DAT_SUCCESS + */ + +BOOL WINAPI +DllMain ( + IN HINSTANCE hDllHandle, + IN DWORD fdwReason, + IN LPVOID lpReserved ) +{ + UNREFERENCED_PARAMETER(lpReserved); + switch( fdwReason ) + { + case DLL_PROCESS_ATTACH: + /* + * We don't attach/detach threads that need any sort + * of initialization, so disable this ability to optimize + * the working set size of the DLL. Also allows us to + * remove two case statemens: + * DLL_THREAD_DETACH and DLL_THREAD_ATTACH + */ + if ( (DisableThreadLibraryCalls( hDllHandle )) != 0) + { + //fprintf(stderr, "DAPL dll_PROCESS_attach!\n"); + //dapl_init (); + break; + } + else + { + DWORD err = GetLastError(); + dapl_os_printf("DAPL Init Failed with code %u\n", err); + break; + } + case DLL_PROCESS_DETACH: + /* + * Do library cleanup + */ + //dapl_fini (); + break; + } + return TRUE; +} + + +/* + * dapl_osd_init + * + * Do Windows specific initialization: + * - nothing at this time + * + * Input: + * none + * + * Returns: + * none + */ +void +dapl_osd_init ( ) +{ + return; +} + + +/* + * dapl_os_get_time + * + * Return 64 bit value of current time in microseconds. + * + * Input: + * loc User location to place current time + * + * Returns: + * DAT_SUCCESS + */ + +DAT_RETURN +dapl_os_get_time ( + OUT DAPL_OS_TIMEVAL * loc) +{ + struct _timeb tb; + + _ftime ( &tb ); + + *loc = ((DAT_UINT64) (tb.time * 1000000L) + (DAT_UINT64) tb.millitm * 1000); + + return DAT_SUCCESS; +} + + +/* + * dapl_os_get_bool_env + * + * Return boolean value of passed in environment variable: 1 if present, + * 0 if not + * + * Input: + * + * + * Returns: + * TRUE or FALSE + */ +int +dapl_os_get_env_bool ( + char *env_str ) +{ + char *env_var; + + env_var = getenv (env_str); + if (env_var != NULL) + { + return 1; + } + + return 0; +} + + +/* + * dapl_os_get_val_env + * + * Update val to value of passed in environment variable if present + * + * Input: + * env_str + * def_val default value if environment variable does not exist + * + * Returns: + * TRUE or FALSE + */ +int +dapl_os_get_env_val ( + char *env_str, + int def_val ) +{ + char *env_var; + + env_var = getenv (env_str); + if ( env_var != NULL ) + { + def_val = strtol (env_var, NULL, 0); + } + + return def_val; +} + + +/* + * dapls_os_thread_create + * + * Create a thread for dapl + * + * Input: + * func function to invoke thread + * data argument to pass to function + * + * Output + * thread_id handle for thread + * + * Returns: + * DAT_SUCCESS + */ +DAT_RETURN +dapl_os_thread_create ( + IN void (*func) (void *), + IN void *data, + OUT DAPL_OS_THREAD *thread_id ) +{ + + *thread_id = CreateThread( + NULL, /* &thread security attrs */ + 8 * 1024, /* initial thread stack size */ + (LPTHREAD_START_ROUTINE)func, /* &thread function */ + data, /* argument for new thread */ + 0, /* creation flags */ + NULL); /* thread ID (ignore) */ + + if ( *thread_id == NULL ) + { + return DAT_ERROR (DAT_INSUFFICIENT_RESOURCES, 0); + } + + return DAT_SUCCESS; +} + + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl/dapl/udapl/windows/dapl_osd.h b/branches/WOF2-3/ulp/dapl/dapl/udapl/windows/dapl_osd.h new file mode 100644 index 00000000..0f39272b --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/udapl/windows/dapl_osd.h @@ -0,0 +1,538 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dapl_osd.h + * + * PURPOSE: Operating System Dependent layer + * Description: + * Provide OS dependent data structures & functions with + * a canonical DAPL interface. Designed to be portable + * and hide OS specific quirks of common functions. + * + * $Id$ + **********************************************************************/ + +#ifndef _DAPL_OSD_H_ +#define _DAPL_OSD_H_ + +/* + * This file is defined for Linux systems only, including it on any + * other build will cause an error + */ +#ifndef _WIN32 +#error UNDEFINED OS TYPE +#endif /* WIN32 */ + +#include +#include +#pragma warning ( push, 3 ) +#include +#include +#include +#include +#include +#include +#pragma warning ( pop ) + +#include "dapl_debug.h" + +/* Export Header */ +#ifdef EXPORT_DAPL_SYMBOLS /* 1 when building DAPL DLL, 0 for clients */ +#define DAPL_EXPORT __declspec( dllexport ) +#else +#define DAPL_EXPORT __declspec( dllimport ) +#endif + +/* Useful debug definitions */ +#ifndef STATIC +#define STATIC static +#endif /* STATIC */ +#ifndef _INLINE_ +#define _INLINE_ __inline +#endif /* _INLINE_ */ +/* +typedef int * intptr_t; +typedef unsigned int * uintptr_t; +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +typedef __int32 int32_t; +typedef unsigned __int32 uint32_t; +*/ +#define dapl_ip_addr6(sockaddr) (((struct sockaddr_in6 *)sockaddr)->sin6_addr.s6_addr) + + +#define dapl_os_panic(str) \ + { \ + fprintf(stderr, "PANIC in %s:%i:%s\n", __FILE__, __LINE__); \ + fprintf(stderr, str); \ + exit(1); \ + } + +/* + * Atomic operations + */ + +typedef volatile DAT_COUNT DAPL_ATOMIC; + +/* atomic function prototypes */ +STATIC _INLINE_ DAT_COUNT +dapl_os_atomic_inc ( + INOUT DAPL_ATOMIC *v); + +STATIC _INLINE_ DAT_COUNT +dapl_os_atomic_dec ( + INOUT DAPL_ATOMIC *v); + +STATIC _INLINE_ DAT_COUNT +dapl_os_atomic_assign ( + INOUT DAPL_ATOMIC *v, + IN DAT_COUNT match_value, + IN DAT_COUNT new_value ); + +int dapl_os_get_env_bool ( + char *env_str ); + +int dapl_os_get_env_val ( + char *env_str, + int def_val ); + + +/* atomic functions */ + +/* dapl_os_atomic_inc + * + * get the current value of '*v', and then increment it. + * + * This is equivalent to an IB atomic fetch and add of 1, + * except that a DAT_COUNT might be 32 bits, rather than 64 + * and it occurs in local memory. + */ + +STATIC _INLINE_ DAT_COUNT +dapl_os_atomic_inc ( + INOUT DAPL_ATOMIC *v) +{ + return InterlockedIncrement( v ); +} + + +/* dapl_os_atomic_dec + * + * decrement the current value of '*v'. No return value is required. + */ + +STATIC _INLINE_ DAT_COUNT +dapl_os_atomic_dec ( + INOUT DAPL_ATOMIC *v) +{ + return InterlockedDecrement( v ); +} + + +/* dapl_os_atomic_assign + * + * assign 'new_value' to '*v' if the current value + * matches the provided 'match_value'. + * + * Make no assignment if there is no match. + * + * Return the current value in any case. + * + * This matches the IBTA atomic operation compare & swap + * except that it is for local memory and a DAT_COUNT may + * be only 32 bits, rather than 64. + */ + +STATIC _INLINE_ DAT_COUNT +dapl_os_atomic_assign ( + INOUT DAPL_ATOMIC *v, + IN DAT_COUNT match_value, + IN DAT_COUNT new_value ) +{ + return InterlockedCompareExchange((LPLONG)v, + new_value, + match_value); +} + + +/* + * Thread Functions + */ +typedef HANDLE DAPL_OS_THREAD; /* XXX Need to implement! */ + +DAT_RETURN +dapl_os_thread_create ( + IN void (*func) (void *), + IN void *data, + OUT DAPL_OS_THREAD *thread_id ); + + +/* + * Lock Functions + */ +typedef HANDLE DAPL_OS_LOCK; + +/* function prototypes */ +STATIC _INLINE_ DAT_RETURN +dapl_os_lock_init ( + IN DAPL_OS_LOCK *m); + +STATIC _INLINE_ DAT_RETURN +dapl_os_lock ( + IN DAPL_OS_LOCK *m); + +STATIC _INLINE_ DAT_RETURN +dapl_os_unlock ( + IN DAPL_OS_LOCK *m); + +STATIC _INLINE_ DAT_RETURN +dapl_os_lock_destroy ( + IN DAPL_OS_LOCK *m); + +/* lock functions */ +STATIC _INLINE_ DAT_RETURN +dapl_os_lock_init ( + IN DAPL_OS_LOCK *m) +{ + *m = CreateMutex (0, FALSE, 0); + + return *m ? DAT_SUCCESS : (DAT_CLASS_ERROR | DAT_INSUFFICIENT_RESOURCES); +} + +STATIC _INLINE_ DAT_RETURN +dapl_os_lock ( + IN DAPL_OS_LOCK *m) +{ + WaitForSingleObject (*m, INFINITE); + + return DAT_SUCCESS; +} + +STATIC _INLINE_ DAT_RETURN +dapl_os_unlock ( + IN DAPL_OS_LOCK *m) +{ + ReleaseMutex (*m); + + return DAT_SUCCESS; +} + +STATIC _INLINE_ DAT_RETURN +dapl_os_lock_destroy ( + IN DAPL_OS_LOCK *m) +{ + CloseHandle (*m); + + return DAT_SUCCESS; +} + + +/* + * Wait Objects + */ + +/* + * The wait object invariant: Presuming a call to dapl_os_wait_object_wait + * occurs at some point, there will be at least one wakeup after each call + * to dapl_os_wait_object_signal. I.e. Signals are not ignored, though + * they may be coallesced. + */ + +typedef HANDLE DAPL_OS_WAIT_OBJECT; + +/* function prototypes */ +STATIC _INLINE_ DAT_RETURN +dapl_os_wait_object_init ( + IN DAPL_OS_WAIT_OBJECT *wait_obj); + +STATIC _INLINE_ DAT_RETURN +dapl_os_wait_object_wait ( + IN DAPL_OS_WAIT_OBJECT *wait_obj, + IN DAT_TIMEOUT timeout_val); + +STATIC _INLINE_ DAT_RETURN +dapl_os_wait_object_wakeup ( + IN DAPL_OS_WAIT_OBJECT *wait_obj); + +STATIC _INLINE_ DAT_RETURN +dapl_os_wait_object_destroy ( + IN DAPL_OS_WAIT_OBJECT *wait_obj); +/* wait_object functions */ + +/* Initialize a wait object to an empty state + */ + +STATIC _INLINE_ DAT_RETURN +dapl_os_wait_object_init ( + IN DAPL_OS_WAIT_OBJECT *wait_obj) +{ + *wait_obj = CreateEvent(NULL,FALSE,FALSE,NULL); + + if ( *wait_obj == NULL ) + { + return DAT_CLASS_ERROR | DAT_INTERNAL_ERROR; + } + + return DAT_SUCCESS; +} + + +/* Wait on the supplied wait object, up to the specified time_out, + * and reacquiring it after the wait ends. + * A timeout of DAT_TIMEOUT_INFINITE will wait indefinitely. + * Timeout should be specified in micro seconds. + * + * Functional returns: + * DAT_SUCCESS -- another thread invoked dapl_os_wait object_wakeup + * DAT_INVALID_STATE -- someone else is already waiting in this wait + * object. + * only one waiter is allowed at a time. + * DAT_ABORT -- another thread invoked dapl_os_wait_object_destroy + * DAT_TIMEOUT -- the specified time limit was reached. + */ + +STATIC _INLINE_ DAT_RETURN +dapl_os_wait_object_wait ( + IN DAPL_OS_WAIT_OBJECT *wait_obj, + IN DAT_TIMEOUT timeout_val) +{ + DAT_RETURN status; + DWORD op_status; + + status = DAT_SUCCESS; + + if ( DAT_TIMEOUT_INFINITE == timeout_val ) + { + op_status = WaitForSingleObject(*wait_obj, INFINITE); + } + else + { + /* convert to milliseconds */ + op_status = WaitForSingleObject(*wait_obj, timeout_val/1000); + } + + if (op_status == WAIT_TIMEOUT) + { + status = DAT_CLASS_ERROR | DAT_TIMEOUT_EXPIRED; + } + else if ( op_status == WAIT_FAILED) + { + status = DAT_CLASS_ERROR | DAT_INTERNAL_ERROR; + } + + return status; +} + +STATIC _INLINE_ DAT_RETURN +dapl_os_wait_object_wakeup ( + IN DAPL_OS_WAIT_OBJECT *wait_obj) +{ + DWORD op_status; + + op_status = SetEvent(*wait_obj); + if ( op_status == 0 ) + { + return DAT_CLASS_ERROR | DAT_INTERNAL_ERROR; + } + + return DAT_SUCCESS; +} + +STATIC _INLINE_ DAT_RETURN +dapl_os_wait_object_destroy ( + IN DAPL_OS_WAIT_OBJECT *wait_obj) +{ + DWORD op_status; + DAT_RETURN status = DAT_SUCCESS; + + op_status = CloseHandle(*wait_obj); + + if ( op_status == 0 ) + { + status = DAT_CLASS_ERROR | DAT_INTERNAL_ERROR; + } + + return status; +} + + +/* + * Memory Functions + */ + +/* function prototypes */ +STATIC _INLINE_ void *dapl_os_alloc (int size); + +STATIC _INLINE_ void *dapl_os_realloc (void *ptr, int size); + +STATIC _INLINE_ void dapl_os_free (void *ptr, int size); + +STATIC _INLINE_ void * dapl_os_memzero (void *loc, int size); + +STATIC _INLINE_ void * dapl_os_memcpy (void *dest, const void *src, int len); + +STATIC _INLINE_ int dapl_os_memcmp (const void *mem1, const void *mem2, int len); + +/* memory functions */ + + +STATIC _INLINE_ void *dapl_os_alloc (int size) +{ + return malloc (size); +} + +STATIC _INLINE_ void *dapl_os_realloc (void *ptr, int size) +{ + return realloc(ptr, size); +} + +STATIC _INLINE_ void dapl_os_free (void *ptr, int size) +{ + size = size; + free (ptr); + ptr = NULL; +} + +STATIC _INLINE_ void * dapl_os_memzero (void *loc, int size) +{ + return memset (loc, 0, size); +} + +STATIC _INLINE_ void * dapl_os_memcpy (void *dest, const void *src, int len) +{ + return memcpy (dest, src, len); +} + +STATIC _INLINE_ int dapl_os_memcmp (const void *mem1, const void *mem2, int len) +{ + return memcmp (mem1, mem2, len); +} + + +STATIC _INLINE_ unsigned int dapl_os_strlen(const char *str) +{ + return ((unsigned int)strlen(str)); +} + +STATIC _INLINE_ char * dapl_os_strdup(const char *str) +{ + return _strdup(str); +} + + +/* + * Timer Functions + */ + +typedef DAT_UINT64 DAPL_OS_TIMEVAL; +typedef struct dapl_timer_entry DAPL_OS_TIMER; +typedef unsigned long DAPL_OS_TICKS; + +/* function prototypes */ + +/* + * Sleep for the number of micro seconds specified by the invoking + * function + */ +STATIC _INLINE_ void dapl_os_sleep_usec (int sleep_time) +{ + Sleep(sleep_time/1000); +} + +STATIC _INLINE_ DAPL_OS_TICKS dapl_os_get_ticks (void); + +STATIC _INLINE_ int dapl_os_ticks_to_seconds (DAPL_OS_TICKS ticks); + +DAT_RETURN dapl_os_get_time (DAPL_OS_TIMEVAL *); +/* timer functions */ + +STATIC _INLINE_ DAPL_OS_TICKS dapl_os_get_ticks (void) +{ + return GetTickCount (); +} + +STATIC _INLINE_ int dapl_os_ticks_to_seconds (DAPL_OS_TICKS ticks) +{ + ticks = ticks; + /* NOT YET IMPLEMENTED IN USER-SPACE */ + return 0; +} + + +/* + * + * Name Service Helper functions + * + */ +#ifdef IBHOSTS_NAMING +#define dapls_osd_getaddrinfo(name, addr_ptr) getaddrinfo(name,NULL,NULL,addr_ptr) +#define dapls_osd_freeaddrinfo(addr) freeaddrinfo (addr) + +#endif /* IBHOSTS_NAMING */ + +/* + * *printf format helpers. We use the C string constant concatenation + * ability to define 64 bit formats, which unfortunatly are non standard + * in the C compiler world. E.g. %llx for gcc, %I64x for Windows + */ +#define F64d "%I64d" +#define F64u "%I64u" +#define F64x "%I64x" +#define F64X "%I64X" + +/* + * Conversion Functions + */ + +STATIC _INLINE_ long int +dapl_os_strtol(const char *nptr, char **endptr, int base) +{ + return strtol(nptr, endptr, base); +} + + +/* + * Debug Helper Functions + */ + +#define dapl_os_assert(expression) CL_ASSERT(expression) + +#define dapl_os_printf printf +#define dapl_os_vprintf(fmt,args) vprintf(fmt,args) +#define dapl_os_syslog(fmt,args) /* XXX Need log routine call */ + + +#endif /* _DAPL_OSD_H_ */ + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl/dapl/udapl/windows/dapl_win.def b/branches/WOF2-3/ulp/dapl/dapl/udapl/windows/dapl_win.def new file mode 100644 index 00000000..681a02c1 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/udapl/windows/dapl_win.def @@ -0,0 +1,61 @@ +EXPORTS + +dapl_ia_open +dapl_ia_close +dapl_ia_query +dapl_set_consumer_context +dapl_get_consumer_context +dapl_get_handle_type +dapl_cno_create +dapl_cno_modify_agent +dapl_cno_query +dapl_cno_free +dapl_cno_wait +dapl_cr_query +dapl_cr_accept +dapl_cr_reject +dapl_cr_handoff +dapl_evd_create +dapl_evd_query +dapl_evd_modify_cno +dapl_evd_enable +dapl_evd_disable +dapl_evd_wait +dapl_evd_post_se +dapl_evd_dequeue +dapl_evd_free +dapl_ep_create +dapl_ep_query +dapl_ep_modify +dapl_ep_connect +dapl_ep_dup_connect +dapl_ep_disconnect +dapl_ep_post_send +dapl_ep_post_recv +dapl_ep_post_rdma_read +dapl_ep_post_rdma_write +dapl_ep_get_status +dapl_ep_free +dapl_lmr_create +dapl_lmr_query +dapl_lmr_free +dapl_rmr_create +dapl_rmr_query +dapl_rmr_bind +dapl_rmr_free +dapl_psp_create +dapl_psp_query +dapl_psp_free +dapl_rsp_create +dapl_rsp_query +dapl_rsp_free +dapl_pz_create +dapl_pz_query +dapl_pz_free +dapl_init +dapl_fini + + + + + diff --git a/branches/WOF2-3/ulp/dapl/dapl/udapl/windows/dapllib.rc b/branches/WOF2-3/ulp/dapl/dapl/udapl/windows/dapllib.rc new file mode 100644 index 00000000..e4b5f803 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dapl/udapl/windows/dapllib.rc @@ -0,0 +1,50 @@ +#include + +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Update Version info for each release +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,0,0,5 + PRODUCTVERSION 0,0,0,5 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", "DAPL Reference Implementation, available at https://sourceforge.net/projects/dapl/ \0" + VALUE "CompanyName", "DAT Collaborative\0" + VALUE "FileDescription", "dapl.dll\0" + VALUE "FileVersion", "0, 0, 0, 4\0" + VALUE "InternalName", "dapl.dll\0" + VALUE "LegalCopyright", "Common Public License 1.0 or The BSD License\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "dapl.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "DAPL Reference Implementation\0" + VALUE "ProductVersion", "0, 0, 0, 4\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + + diff --git a/branches/WOF2-3/ulp/dapl/dat/common/dat_dictionary.c b/branches/WOF2-3/ulp/dapl/dat/common/dat_dictionary.c new file mode 100644 index 00000000..9ab6ae26 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dat/common/dat_dictionary.c @@ -0,0 +1,467 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dat_dictionary.c + * + * PURPOSE: dictionary data structure + * + **********************************************************************/ + + +#include "dat_dictionary.h" + + +/********************************************************************* + * * + * Structures * + * * + *********************************************************************/ + +typedef struct DAT_DICTIONARY_NODE +{ + DAT_PROVIDER_INFO key; + DAT_DICTIONARY_DATA data; + struct DAT_DICTIONARY_NODE *prev; + struct DAT_DICTIONARY_NODE *next; +} DAT_DICTIONARY_NODE; + + +struct DAT_DICTIONARY +{ + DAT_DICTIONARY_NODE *head; + DAT_DICTIONARY_NODE *tail; + DAT_COUNT size; +}; + +/********************************************************************* + * * + * Function Declarations * + * * + *********************************************************************/ + +static DAT_RETURN +dat_dictionary_key_dup ( + const DAT_PROVIDER_INFO *old_key, + DAT_PROVIDER_INFO *new_key ); + +static DAT_BOOLEAN +dat_dictionary_key_is_equal ( + const DAT_PROVIDER_INFO *key_a, + const DAT_PROVIDER_INFO *key_b ); + + +/********************************************************************* + * * + * External Functions * + * * + *********************************************************************/ + + +/*********************************************************************** + * Function: dat_dictionary_create + ***********************************************************************/ + +DAT_RETURN +dat_dictionary_create ( + OUT DAT_DICTIONARY **pp_dictionary) +{ + DAT_DICTIONARY *p_dictionary; + DAT_RETURN status; + + dat_os_assert ( NULL != pp_dictionary); + + status = DAT_SUCCESS; + + /* create the dictionary */ + p_dictionary = dat_os_alloc (sizeof (DAT_DICTIONARY)); + if (NULL == p_dictionary) + { + status = DAT_ERROR (DAT_INSUFFICIENT_RESOURCES,DAT_RESOURCE_MEMORY); + goto bail; + } + + dat_os_memset (p_dictionary, '\0', sizeof (DAT_DICTIONARY)); + + /* create the head node */ + p_dictionary->head = dat_os_alloc (sizeof (DAT_DICTIONARY_NODE)); + if (NULL == p_dictionary->head) + { + status = DAT_ERROR (DAT_INSUFFICIENT_RESOURCES,DAT_RESOURCE_MEMORY); + goto bail; + } + + dat_os_memset (p_dictionary->head, '\0', sizeof (DAT_DICTIONARY_NODE)); + + /* create the tail node */ + p_dictionary->tail = dat_os_alloc (sizeof (DAT_DICTIONARY_NODE)); + if (NULL == p_dictionary->tail) + { + status = DAT_ERROR (DAT_INSUFFICIENT_RESOURCES,DAT_RESOURCE_MEMORY); + goto bail; + } + + dat_os_memset (p_dictionary->tail, '\0', sizeof (DAT_DICTIONARY_NODE)); + + p_dictionary->head->next = p_dictionary->tail; + p_dictionary->tail->prev = p_dictionary->head; + + *pp_dictionary = p_dictionary; + + bail: + if ( DAT_SUCCESS != status ) + { + if ( NULL != p_dictionary ) + { + dat_os_free (p_dictionary, sizeof (DAT_DICTIONARY)); + + if ( NULL != p_dictionary->head ) + { + dat_os_free (p_dictionary->head, sizeof (DAT_DICTIONARY_NODE)); + } + + if ( NULL != p_dictionary->tail ) + { + dat_os_free (p_dictionary->tail, sizeof (DAT_DICTIONARY_NODE)); + } + } + } + + return status; +} + + +/*********************************************************************** + * Function: dat_dictionary_destroy + ***********************************************************************/ + +DAT_RETURN +dat_dictionary_destroy ( + IN DAT_DICTIONARY *p_dictionary) +{ + DAT_DICTIONARY_NODE *cur_node; + + dat_os_assert (NULL != p_dictionary); + + while (NULL != p_dictionary->head) + { + cur_node = p_dictionary->head; + p_dictionary->head = cur_node->next; + + dat_os_free (cur_node, sizeof (DAT_DICTIONARY_NODE)); + } + + dat_os_free (p_dictionary, sizeof (DAT_DICTIONARY)); + + return DAT_SUCCESS; +} + + +/*********************************************************************** + * Function: dat_dictionary_size + ***********************************************************************/ + +DAT_RETURN +dat_dictionary_size ( + IN DAT_DICTIONARY *p_dictionary, + OUT DAT_COUNT *p_size) +{ + dat_os_assert (NULL != p_dictionary); + dat_os_assert (NULL != p_size); + + *p_size = p_dictionary->size; + + return DAT_SUCCESS; +} + + +/*********************************************************************** + * Function: dat_dictionary_entry_create + ***********************************************************************/ + +DAT_RETURN +dat_dictionary_entry_create ( + OUT DAT_DICTIONARY_ENTRY *p_entry) +{ + DAT_DICTIONARY_NODE *node; + DAT_RETURN dat_status; + + dat_os_assert (NULL != p_entry); + + dat_status = DAT_SUCCESS; + + node = dat_os_alloc (sizeof (DAT_DICTIONARY_NODE)); + if (NULL == node) + { + dat_status = DAT_ERROR (DAT_INSUFFICIENT_RESOURCES,DAT_RESOURCE_MEMORY); + goto bail; + } + + *p_entry = node; + + bail: + return dat_status; +} + + +/*********************************************************************** + * Function: dat_dictionary_entry_destroy + ***********************************************************************/ + +DAT_RETURN +dat_dictionary_entry_destroy ( + OUT DAT_DICTIONARY_ENTRY entry) +{ + dat_os_free (entry, sizeof (DAT_DICTIONARY_NODE)); + return DAT_SUCCESS; +} + + +/*********************************************************************** + * Function: dat_dictionary_insert + ***********************************************************************/ + +DAT_RETURN +dat_dictionary_insert ( + IN DAT_DICTIONARY *p_dictionary, + IN DAT_DICTIONARY_ENTRY entry, + IN const DAT_PROVIDER_INFO *key, + IN DAT_DICTIONARY_DATA data) +{ + DAT_RETURN dat_status; + DAT_DICTIONARY_NODE *cur_node, *prev_node, *next_node; + + dat_os_assert (NULL != p_dictionary); + dat_os_assert (NULL != entry); + + cur_node = entry; + + if ( DAT_SUCCESS == dat_dictionary_search (p_dictionary, key, NULL) ) + { + dat_status = DAT_ERROR (DAT_PROVIDER_ALREADY_REGISTERED,0); + goto bail; + } + + dat_status = dat_dictionary_key_dup ( key, &cur_node->key ); + if ( DAT_SUCCESS != dat_status ) + { + goto bail; + } + + /* insert node at end of list to preserve registration order*/ + prev_node = p_dictionary->tail->prev; + next_node = p_dictionary->tail; + + cur_node->data = data; + cur_node->next = next_node; + cur_node->prev = prev_node; + + prev_node->next = cur_node; + next_node->prev = cur_node; + + p_dictionary->size++; + + bail: + return dat_status; +} + + +/*********************************************************************** + * Function: dat_dictionary_search + ***********************************************************************/ + +DAT_RETURN +dat_dictionary_search ( + IN DAT_DICTIONARY *p_dictionary, + IN const DAT_PROVIDER_INFO *key, + OUT DAT_DICTIONARY_DATA *p_data) +{ + DAT_DICTIONARY_NODE *cur_node; + DAT_RETURN status; + + dat_os_assert (NULL != p_dictionary); + + status = DAT_ERROR (DAT_PROVIDER_NOT_FOUND,0); + + for (cur_node = p_dictionary->head->next; + p_dictionary->tail != cur_node; + cur_node = cur_node->next) + { + if ( DAT_TRUE == dat_dictionary_key_is_equal (&cur_node->key, key) ) + { + if ( NULL != p_data ) + { + *p_data = cur_node->data; + } + + status = DAT_SUCCESS; + goto bail; + } + } + + bail: + return status; +} + + +/*********************************************************************** + * Function: dat_dictionary_enumerate + ***********************************************************************/ + +DAT_RETURN +dat_dictionary_enumerate ( + IN DAT_DICTIONARY *p_dictionary, + IN DAT_DICTIONARY_DATA array[], + IN DAT_COUNT array_size) +{ + DAT_DICTIONARY_NODE *cur_node; + DAT_COUNT i; + DAT_RETURN status; + + dat_os_assert (NULL != p_dictionary); + dat_os_assert (NULL != array); + + status = DAT_SUCCESS; + + if ( array_size < p_dictionary->size ) + { + status = DAT_ERROR (DAT_INSUFFICIENT_RESOURCES,0); + goto bail; + } + + for (cur_node = p_dictionary->head->next, i = 0; + p_dictionary->tail != cur_node; + cur_node = cur_node->next, i++) + { + array[i] = cur_node->data; + } + + bail: + return status; +} + + +/*********************************************************************** + * Function: dat_dictionary_remove + ***********************************************************************/ + +DAT_RETURN +dat_dictionary_remove ( + IN DAT_DICTIONARY *p_dictionary, + IN DAT_DICTIONARY_ENTRY *p_entry, + IN const DAT_PROVIDER_INFO *key, + OUT DAT_DICTIONARY_DATA *p_data) +{ + DAT_DICTIONARY_NODE *cur_node, *prev_node, *next_node; + DAT_RETURN status; + + dat_os_assert (NULL != p_dictionary); + dat_os_assert (NULL != p_entry); + + status = DAT_ERROR (DAT_PROVIDER_NOT_FOUND,0); + + for (cur_node = p_dictionary->head->next; + p_dictionary->tail != cur_node; + cur_node = cur_node->next) + { + if ( DAT_TRUE == dat_dictionary_key_is_equal (&cur_node->key, key) ) + { + if ( NULL != p_data ) + { + *p_data = cur_node->data; + } + + prev_node = cur_node->prev; + next_node = cur_node->next; + + prev_node->next = next_node; + next_node->prev = prev_node; + + *p_entry = cur_node; + + p_dictionary->size--; + + status = DAT_SUCCESS; + goto bail; + } + } + + bail: + return status; +} + + +/********************************************************************* + * * + * Internal Function Definitions * + * * + *********************************************************************/ + + +/*********************************************************************** + * Function: dat_dictionary_key_create + ***********************************************************************/ + +DAT_RETURN +dat_dictionary_key_dup ( + const DAT_PROVIDER_INFO *old_key, + DAT_PROVIDER_INFO *new_key ) +{ + dat_os_assert (NULL != old_key); + dat_os_assert (NULL != new_key); + + dat_os_strncpy (new_key->ia_name, old_key->ia_name, DAT_NAME_MAX_LENGTH); + new_key->dapl_version_major = old_key->dapl_version_major; + new_key->dapl_version_minor = old_key->dapl_version_minor; + new_key->is_thread_safe = old_key->is_thread_safe; + + return DAT_SUCCESS; +} + + +/*********************************************************************** + * Function: dat_dictionary_key_is_equal + ***********************************************************************/ + +DAT_BOOLEAN +dat_dictionary_key_is_equal ( + const DAT_PROVIDER_INFO *key_a, + const DAT_PROVIDER_INFO *key_b ) +{ + if ( ( dat_os_strlen (key_a->ia_name) == dat_os_strlen (key_b->ia_name) ) && + ( !dat_os_strncmp (key_a->ia_name, key_b->ia_name, dat_os_strlen (key_a->ia_name)) ) && + ( key_a->dapl_version_major == key_b->dapl_version_major ) && + ( key_a->dapl_version_minor == key_b->dapl_version_minor ) && + ( key_a->is_thread_safe == key_b->is_thread_safe ) ) + { + return DAT_TRUE; + } + else + { + return DAT_FALSE; + } +} diff --git a/branches/WOF2-3/ulp/dapl/dat/common/dat_dictionary.h b/branches/WOF2-3/ulp/dapl/dat/common/dat_dictionary.h new file mode 100644 index 00000000..a96c4fbe --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dat/common/dat_dictionary.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dat_dictionary.h + * + * PURPOSE: dictionary data structure + * + **********************************************************************/ + +#ifndef _DAT_DICTIONARY_H_ +#define _DAT_DICTIONARY_H_ + + +#include "dat_osd.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************* + * * + * Typedefs * + * * + *********************************************************************/ + +typedef struct DAT_DICTIONARY DAT_DICTIONARY; +typedef void * DAT_DICTIONARY_DATA; +typedef void * DAT_DICTIONARY_ENTRY; + + +/********************************************************************* + * * + * Function Prototypes * + * * + *********************************************************************/ + +extern DAT_RETURN +dat_dictionary_create( + OUT DAT_DICTIONARY **pp_dictionary); + +extern DAT_RETURN +dat_dictionary_destroy( + IN DAT_DICTIONARY *p_dictionary); + +extern DAT_RETURN +dat_dictionary_size( + IN DAT_DICTIONARY *p_dictionary, + OUT DAT_COUNT *p_size); + +extern DAT_RETURN +dat_dictionary_entry_create( + OUT DAT_DICTIONARY_ENTRY *p_entry); + +extern DAT_RETURN +dat_dictionary_entry_destroy( + IN DAT_DICTIONARY_ENTRY entry); + +extern DAT_RETURN +dat_dictionary_insert( + IN DAT_DICTIONARY *p_dictionary, + IN DAT_DICTIONARY_ENTRY entry, + IN const DAT_PROVIDER_INFO *key, + IN DAT_DICTIONARY_DATA data); + +extern DAT_RETURN +dat_dictionary_search( + IN DAT_DICTIONARY *p_dictionary, + IN const DAT_PROVIDER_INFO *key, + OUT DAT_DICTIONARY_DATA *p_data); + +extern DAT_RETURN +dat_dictionary_enumerate( + IN DAT_DICTIONARY *p_dictionary, + IN DAT_DICTIONARY_DATA array[], + IN DAT_COUNT array_size); + + +extern DAT_RETURN +dat_dictionary_remove( + IN DAT_DICTIONARY *p_dictionary, + IN DAT_DICTIONARY_ENTRY *p_entry, + IN const DAT_PROVIDER_INFO *key, + OUT DAT_DICTIONARY_DATA *p_data); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/branches/WOF2-3/ulp/dapl/dat/common/dat_dr.c b/branches/WOF2-3/ulp/dapl/dat/common/dat_dr.c new file mode 100644 index 00000000..aef07ece --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dat/common/dat_dr.c @@ -0,0 +1,381 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dat_dr.c + * + * PURPOSE: dynamic registry implementation + * + **********************************************************************/ + + +#include "dat_dr.h" + +#include "dat_dictionary.h" + + +/********************************************************************* + * * + * Global Variables * + * * + *********************************************************************/ + +static DAT_OS_LOCK g_dr_lock; +static DAT_DICTIONARY *g_dr_dictionary = NULL; + + +/********************************************************************* + * * + * External Functions * + * * + *********************************************************************/ + + +//*********************************************************************** +// Function: dat_dr_init +//*********************************************************************** + +DAT_RETURN +dat_dr_init ( void ) +{ + DAT_RETURN status; + + status = dat_os_lock_init (&g_dr_lock); + if ( DAT_SUCCESS != status ) + { + return status; + } + + status = dat_dictionary_create (&g_dr_dictionary); + if ( DAT_SUCCESS != status ) + { + dat_os_dbg_print (DAT_OS_DBG_TYPE_ERROR, + "DAT Registry: DR Init Failed\n"); + return status; + } + + return DAT_SUCCESS; +} + + +//*********************************************************************** +// Function: dat_dr_fini +//*********************************************************************** + +DAT_RETURN +dat_dr_fini ( void ) +{ + DAT_RETURN status; + + status = dat_os_lock_destroy (&g_dr_lock); + if ( DAT_SUCCESS != status ) + { + return status; + } + + status = dat_dictionary_destroy (g_dr_dictionary); + if ( DAT_SUCCESS != status ) + { + return status; + } + + return DAT_SUCCESS; +} + + +//*********************************************************************** +// Function: dat_dr_insert +//*********************************************************************** + +extern DAT_RETURN +dat_dr_insert ( + IN const DAT_PROVIDER_INFO *info, + IN DAT_DR_ENTRY *entry ) +{ + DAT_RETURN status; + DAT_DICTIONARY_ENTRY dict_entry = NULL; + DAT_DR_ENTRY *data; + + data = dat_os_alloc (sizeof (DAT_DR_ENTRY)); + if ( NULL == data ) + { + status = DAT_ERROR (DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); + goto bail; + } + + *data = *entry; + + status = dat_dictionary_entry_create (&dict_entry); + if ( DAT_SUCCESS != status ) + { + goto bail; + } + + dat_os_lock (&g_dr_lock); + + status = dat_dictionary_insert (g_dr_dictionary, + dict_entry, + info, + (DAT_DICTIONARY_DATA *) data); + + dat_os_unlock (&g_dr_lock); + +bail: + if ( DAT_SUCCESS != status ) + { + if ( NULL != data ) + { + dat_os_free (data, sizeof (DAT_DR_ENTRY)); + } + + + if ( NULL != dict_entry ) + { + (void) dat_dictionary_entry_destroy(dict_entry); + } + } + + return status; +} + + +//*********************************************************************** +// Function: dat_dr_remove +//*********************************************************************** + +extern DAT_RETURN +dat_dr_remove ( + IN const DAT_PROVIDER_INFO *info ) +{ + DAT_DR_ENTRY *data; + DAT_DICTIONARY_ENTRY dict_entry = NULL; + DAT_RETURN status; + + dat_os_lock (&g_dr_lock); + + status = dat_dictionary_search ( g_dr_dictionary, + info, + (DAT_DICTIONARY_DATA *) &data); + + if ( DAT_SUCCESS != status ) + { + /* return status from dat_dictionary_search() */ + goto bail; + } + + if ( 0 != data->ref_count ) + { + status = DAT_ERROR (DAT_PROVIDER_IN_USE, 0); + goto bail; + } + + status = dat_dictionary_remove ( g_dr_dictionary, + &dict_entry, + info, + (DAT_DICTIONARY_DATA *) &data); + if ( DAT_SUCCESS != status ) + { + /* return status from dat_dictionary_remove() */ + goto bail; + } + + dat_os_free (data, sizeof (DAT_DR_ENTRY)); + +bail: + dat_os_unlock (&g_dr_lock); + + if ( NULL != dict_entry ) + { + (void) dat_dictionary_entry_destroy(dict_entry); + } + + return status; +} + + +//*********************************************************************** +// Function: dat_dr_provider_open +//*********************************************************************** + +extern DAT_RETURN +dat_dr_provider_open ( + IN const DAT_PROVIDER_INFO *info, + OUT DAT_IA_OPEN_FUNC *p_ia_open_func ) +{ + DAT_RETURN status; + DAT_DR_ENTRY *data; + + dat_os_lock (&g_dr_lock); + + status = dat_dictionary_search ( g_dr_dictionary, + info, + (DAT_DICTIONARY_DATA *) &data); + + dat_os_unlock (&g_dr_lock); + + if ( DAT_SUCCESS == status ) + { + data->ref_count++; + *p_ia_open_func = data->ia_open_func; + } + + return status; +} + + +//*********************************************************************** +// Function: dat_dr_provider_close +//*********************************************************************** + +extern DAT_RETURN +dat_dr_provider_close ( + IN const DAT_PROVIDER_INFO *info ) +{ + DAT_RETURN status; + DAT_DR_ENTRY *data; + + dat_os_lock (&g_dr_lock); + + status = dat_dictionary_search ( g_dr_dictionary, + info, + (DAT_DICTIONARY_DATA *) &data); + + dat_os_unlock (&g_dr_lock); + + if ( DAT_SUCCESS == status ) + { + data->ref_count--; + } + + return status; +} + + +//*********************************************************************** +// Function: dat_dr_size +//*********************************************************************** + +DAT_RETURN +dat_dr_size ( + OUT DAT_COUNT *size ) +{ + return dat_dictionary_size (g_dr_dictionary, size); +} + + +//*********************************************************************** +// Function: dat_dr_list +//*********************************************************************** + +DAT_RETURN +dat_dr_list ( + IN DAT_COUNT max_to_return, + OUT DAT_COUNT *entries_returned, + OUT DAT_PROVIDER_INFO * (dat_provider_list[]) ) +{ + DAT_DR_ENTRY **array; + DAT_COUNT array_size; + DAT_COUNT i; + DAT_RETURN status; + + array = NULL; + status = DAT_SUCCESS; + + /* The dictionary size may increase between the call to */ + /* dat_dictionary_size() and dat_dictionary_enumerate(). */ + /* Therefore we loop until a successful enumeration is made. */ + *entries_returned = 0; + for (;;) + { + status = dat_dictionary_size (g_dr_dictionary, &array_size); + if ( status != DAT_SUCCESS ) + { + goto bail; + } + + if (array_size == 0) + { + status = DAT_SUCCESS; + goto bail; + } + + array = dat_os_alloc (array_size * sizeof (DAT_DR_ENTRY *)); + if ( array == NULL ) + { + status = DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); + goto bail; + } + + dat_os_lock (&g_dr_lock); + + status = dat_dictionary_enumerate (g_dr_dictionary, + (DAT_DICTIONARY_DATA *) array, + array_size); + + dat_os_unlock (&g_dr_lock); + + if ( DAT_SUCCESS == status ) + { + break; + } + else + { + dat_os_free (array, array_size * sizeof (DAT_DR_ENTRY *)); + array = NULL; + continue; + } + } + + for ( i = 0; (i < max_to_return) && (i < array_size); i++) + { + if ( NULL == dat_provider_list[i] ) + { + status = DAT_ERROR (DAT_INVALID_PARAMETER, DAT_INVALID_ARG3); + goto bail; + } + + *dat_provider_list[i] = array[i]->info; + } + + *entries_returned = i; + +bail: + if ( NULL != array ) + { + dat_os_free (array, array_size * sizeof (DAT_DR_ENTRY *)); + } + + return status; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl/dat/common/dat_dr.h b/branches/WOF2-3/ulp/dapl/dat/common/dat_dr.h new file mode 100644 index 00000000..12546f7d --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dat/common/dat_dr.h @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dat_dr.h + * + * PURPOSE: dynamic registry interface declarations + * + **********************************************************************/ + +#ifndef __DAT_DR_H__ +#define __DAT_DR_H__ + + +#include "dat_osd.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************* + * * + * Strucutres * + * * + *********************************************************************/ + +typedef struct +{ + DAT_COUNT ref_count; + DAT_IA_OPEN_FUNC ia_open_func; + DAT_PROVIDER_INFO info; +} DAT_DR_ENTRY; + + +/********************************************************************* + * * + * Function Declarations * + * * + *********************************************************************/ + +extern DAT_RETURN +dat_dr_init( void ); + +extern DAT_RETURN +dat_dr_fini( void ); + +extern DAT_RETURN +dat_dr_insert ( + IN const DAT_PROVIDER_INFO *info, + IN DAT_DR_ENTRY *entry ); + +extern DAT_RETURN +dat_dr_remove ( + IN const DAT_PROVIDER_INFO *info ); + + +extern DAT_RETURN +dat_dr_provider_open ( + IN const DAT_PROVIDER_INFO *info, + OUT DAT_IA_OPEN_FUNC *p_ia_open_func ); + +extern DAT_RETURN +dat_dr_provider_close ( + IN const DAT_PROVIDER_INFO *info); + +extern DAT_RETURN +dat_dr_size ( + OUT DAT_COUNT *size); + +extern DAT_RETURN +dat_dr_list ( + IN DAT_COUNT max_to_return, + OUT DAT_COUNT *entries_returned, + OUT DAT_PROVIDER_INFO * (dat_provider_list[]) ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/branches/WOF2-3/ulp/dapl/dat/common/dat_init.c b/branches/WOF2-3/ulp/dapl/dat/common/dat_init.c new file mode 100644 index 00000000..3d7dbc37 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dat/common/dat_init.c @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dat_init.c + * + * PURPOSE: DAT registry implementation for uDAPL + * Description: init and fini functions for DAT module. + * + **********************************************************************/ + +#include "dat_init.h" + +#include "dat_dr.h" +#include "dat_osd.h" + +#ifndef DAT_NO_STATIC_REGISTRY +#include "dat_sr.h" +#endif + + +/********************************************************************* + * * + * Global Variables * + * * + *********************************************************************/ + +/* + * Ideally, the following two rules could be enforced: + * + * - The DAT Registry's initialization function is executed before that + * of any DAT Providers and hence all calls into the registry occur + * after the registry module is initialized. + * + * - The DAT Registry's deinitialization function is executed after that + * of any DAT Providers and hence all calls into the registry occur + * before the registry module is deinitialized. + * + * However, on many platforms few guarantees are provided regarding the + * order in which modules initialization and deinitialization functions + * are invoked. + * + * To understand why these rules are difficult to enforce using only + * features common to all platforms, consider the Linux platform. The order + * in which Linux shared libraries are loaded into a process's address space + * is undefined. When a DAT consumer explicitly links to DAT provider + * libraries, the order in which library initialization and deinitialization + * functions are invoked becomes important. For example if the DAPL provider + * calls dat_registry_add_provider() before the registry has been initialized, + * an error will occur. + * + * We assume that modules are loaded with a single thread. Given + * this assumption, we can use a simple state variable to determine + * the state of the DAT registry. + */ + +static DAT_MODULE_STATE g_module_state = DAT_MODULE_STATE_UNINITIALIZED; + + +//*********************************************************************** +// Function: dat_module_get_state +//*********************************************************************** + +DAT_MODULE_STATE +dat_module_get_state ( void ) +{ + return g_module_state; +} + + +//*********************************************************************** +// Function: dat_init +//*********************************************************************** + +void +dat_init ( void ) +{ + DAT_RETURN status= DAT_SUCCESS; + if ( DAT_MODULE_STATE_UNINITIALIZED == g_module_state ) + { + /* + * update the module state flag immediately in case there + * is a recursive call to dat_init(). + */ + g_module_state = DAT_MODULE_STATE_INITIALIZING; + + dat_os_dbg_init (); + + dat_os_dbg_print (DAT_OS_DBG_TYPE_GENERIC, + "DAT Registry: Started (dat_init)\n"); + +#ifndef DAT_NO_STATIC_REGISTRY + dat_sr_init (); +#endif + status = dat_dr_init (); + if (status != DAT_SUCCESS) + { + dat_os_dbg_print (DAT_OS_DBG_TYPE_GENERIC, + "DAT Registry: (dat_init) failed\n"); + g_module_state = DAT_MODULE_STATE_UNINITIALIZED; + return; + } + g_module_state = DAT_MODULE_STATE_INITIALIZED; + } +} + + +//*********************************************************************** +// Function: dat_fini +//*********************************************************************** + +void +dat_fini ( void ) +{ + if ( DAT_MODULE_STATE_INITIALIZED == g_module_state ) + { + g_module_state = DAT_MODULE_STATE_DEINITIALIZING; + + dat_dr_fini (); +#ifndef DAT_NO_STATIC_REGISTRY + dat_sr_fini (); +#endif + + dat_os_dbg_print (DAT_OS_DBG_TYPE_GENERIC, "DAT Registry: Stopped (dat_fini)\n"); + + g_module_state = DAT_MODULE_STATE_DEINITIALIZED; + } +} + + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl/dat/common/dat_init.h b/branches/WOF2-3/ulp/dapl/dat/common/dat_init.h new file mode 100644 index 00000000..523d8133 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dat/common/dat_init.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dat_init.h + * + * PURPOSE: DAT registry global data + * + **********************************************************************/ + +#ifndef _DAT_INIT_H_ +#define _DAT_INIT_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************* + * * + * Enumerations * + * * + *********************************************************************/ + +typedef enum +{ + DAT_MODULE_STATE_UNINITIALIZED, + DAT_MODULE_STATE_INITIALIZING, + DAT_MODULE_STATE_INITIALIZED, + DAT_MODULE_STATE_DEINITIALIZING, + DAT_MODULE_STATE_DEINITIALIZED +} DAT_MODULE_STATE; + +/********************************************************************* + * * + * Function Prototypes * + * * + *********************************************************************/ + +DAT_MODULE_STATE +dat_module_get_state ( void ) ; + +void +dat_init ( void ) ; + +void +dat_fini ( void ) ; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/branches/WOF2-3/ulp/dapl/dat/common/dat_sr.c b/branches/WOF2-3/ulp/dapl/dat/common/dat_sr.c new file mode 100644 index 00000000..e140ccec --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dat/common/dat_sr.c @@ -0,0 +1,412 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dat_sr.c + * + * PURPOSE: static registry implementation + * + **********************************************************************/ + + +#include "dat_sr.h" + +#include "dat_dictionary.h" +#include "udat_sr_parser.h" + + +/********************************************************************* + * * + * Global Variables * + * * + *********************************************************************/ + +static DAT_OS_LOCK g_sr_lock; +static DAT_DICTIONARY *g_sr_dictionary = NULL; + + +/********************************************************************* + * * + * External Functions * + * * + *********************************************************************/ + + +//*********************************************************************** +// Function: dat_sr_init +//*********************************************************************** + +DAT_RETURN +dat_sr_init ( void ) +{ + DAT_RETURN status; + + status = dat_os_lock_init (&g_sr_lock); + if ( DAT_SUCCESS != status ) + { + return status; + } + + status = dat_dictionary_create (&g_sr_dictionary); + if ( DAT_SUCCESS != status ) + { + return status; + } + + /* + * Since DAT allows providers to be loaded by either the static + * registry or explicitly through OS dependent methods, do not + * return an error if no providers are loaded via the static registry. + */ + + status = dat_sr_load (); + dat_os_dbg_print (DAT_OS_DBG_TYPE_GENERIC, + "DAT Registry: SR Load return %#x\n", status); + + return DAT_SUCCESS; +} + + +//*********************************************************************** +// Function: dat_sr_fini +//*********************************************************************** + +extern DAT_RETURN +dat_sr_fini ( void ) +{ + DAT_RETURN status; + + status = dat_os_lock_destroy (&g_sr_lock); + if ( DAT_SUCCESS != status ) + { + return status; + } + + status = dat_dictionary_destroy (g_sr_dictionary); + if ( DAT_SUCCESS != status ) + { + return status; + } + + return DAT_SUCCESS; +} + + +//*********************************************************************** +// Function: dat_sr_insert +//*********************************************************************** + +extern DAT_RETURN +dat_sr_insert ( + IN const DAT_PROVIDER_INFO *info, + IN DAT_SR_ENTRY *entry ) +{ + DAT_RETURN status; + DAT_SR_ENTRY *data; + DAT_UINT32 lib_path_size = 0; + DAT_UINT32 lib_path_len = 0; + DAT_UINT32 ia_params_size = 0; + DAT_UINT32 ia_params_len = 0; + DAT_DICTIONARY_ENTRY dict_entry = NULL; + + if ( NULL == (data = dat_os_alloc (sizeof (DAT_SR_ENTRY))) ) + { + status = DAT_ERROR (DAT_INSUFFICIENT_RESOURCES,DAT_RESOURCE_MEMORY); + goto bail; + } + + lib_path_len = (DAT_UINT32)dat_os_strlen (entry->lib_path); + lib_path_size = (lib_path_len + 1) * sizeof (char); + + if ( NULL == (data->lib_path = dat_os_alloc (lib_path_size)) ) + { + status = DAT_ERROR (DAT_INSUFFICIENT_RESOURCES,DAT_RESOURCE_MEMORY); + goto bail; + } + + dat_os_strncpy (data->lib_path, entry->lib_path, lib_path_len); + data->lib_path[lib_path_len] = '\0'; + + ia_params_len = (DAT_UINT32)dat_os_strlen (entry->ia_params); + ia_params_size = (ia_params_len + 1) * sizeof (char); + + if ( NULL == (data->ia_params = dat_os_alloc (ia_params_size)) ) + { + status = DAT_ERROR (DAT_INSUFFICIENT_RESOURCES,DAT_RESOURCE_MEMORY); + goto bail; + } + + dat_os_strncpy (data->ia_params, entry->ia_params, ia_params_len); + data->ia_params[ia_params_len] = '\0'; + + data->info = entry->info; + data->lib_handle = entry->lib_handle; + data->ref_count = entry->ref_count; + + dict_entry = NULL; + status = dat_dictionary_entry_create (&dict_entry); + if ( DAT_SUCCESS != status ) + { + goto bail; + } + + dat_os_lock (&g_sr_lock); + + status = dat_dictionary_insert (g_sr_dictionary, + dict_entry, + info, + (DAT_DICTIONARY_DATA *) data); + dat_os_unlock (&g_sr_lock); + +bail: + if ( DAT_SUCCESS != status ) + { + if ( NULL != data ) + { + if ( NULL != data->lib_path ) + { + dat_os_free (data->lib_path, lib_path_size); + } + + if ( NULL != data->ia_params ) + { + dat_os_free (data->ia_params, ia_params_size); + } + + dat_os_free (data, sizeof (DAT_SR_ENTRY)); + } + + if ( NULL != dict_entry ) + { + (void) dat_dictionary_entry_destroy(dict_entry); + } + } + + dat_os_dbg_print(DAT_OS_DBG_TYPE_SR, + "DAT Registry: insert to sr_dictionary for %s : 0x%x\n", + entry->info.ia_name, status); + + return status; +} + + +//*********************************************************************** +// Function: dat_sr_size +//*********************************************************************** + +extern DAT_RETURN +dat_sr_size ( + OUT DAT_COUNT *size ) +{ + return dat_dictionary_size (g_sr_dictionary, size); +} + + +//*********************************************************************** +// Function: dat_sr_list +//*********************************************************************** + +extern DAT_RETURN +dat_sr_list ( + IN DAT_COUNT max_to_return, + OUT DAT_COUNT *entries_returned, + OUT DAT_PROVIDER_INFO * (dat_provider_list[]) ) +{ + DAT_SR_ENTRY **array; + DAT_COUNT array_size; + DAT_COUNT i; + DAT_RETURN status; + + array = NULL; + status = DAT_SUCCESS; + + /* The dictionary size may increase between the call to */ + /* dat_dictionary_size() and dat_dictionary_enumerate(). */ + /* Therefore we loop until a successful enumeration is made. */ + *entries_returned = 0; + for (;;) + { + status = dat_dictionary_size (g_sr_dictionary, &array_size); + if ( DAT_SUCCESS != status ) + { + goto bail; + } + + if (array_size == 0) + { + status = DAT_SUCCESS; + goto bail; + } + + array = dat_os_alloc (array_size * sizeof (DAT_SR_ENTRY *)); + if ( array == NULL ) + { + status = DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); + goto bail; + } + + dat_os_lock (&g_sr_lock); + + status = dat_dictionary_enumerate (g_sr_dictionary, + (DAT_DICTIONARY_DATA *) array, + array_size); + + dat_os_unlock (&g_sr_lock); + + if ( DAT_SUCCESS == status ) + { + break; + } + else + { + dat_os_free (array, array_size * sizeof (DAT_SR_ENTRY *)); + array = NULL; + continue; + } + } + + for ( i = 0; (i < max_to_return) && (i < array_size); i++) + { + if ( NULL == dat_provider_list[i] ) + { + status = DAT_ERROR (DAT_INVALID_PARAMETER,DAT_INVALID_ARG3); + goto bail; + } + + *dat_provider_list[i] = array[i]->info; + } + + *entries_returned = i; + +bail: + if ( NULL != array ) + { + dat_os_free (array, array_size * sizeof (DAT_SR_ENTRY *)); + } + + return status; +} + + + +//*********************************************************************** +// Function: dat_sr_provider_open +//*********************************************************************** + +extern DAT_RETURN +dat_sr_provider_open ( + IN const DAT_PROVIDER_INFO *info ) +{ + DAT_RETURN status; + DAT_SR_ENTRY *data; + + dat_os_lock (&g_sr_lock); + + status = dat_dictionary_search (g_sr_dictionary, + info, + (DAT_DICTIONARY_DATA *) &data); + + if ( DAT_SUCCESS == status ) + { + if ( 0 == data->ref_count ) + { + status = dat_os_library_load (data->lib_path, &data->lib_handle); + if ( status == DAT_SUCCESS ) + { + data->ref_count++; + } + else + { + dat_os_dbg_print (DAT_OS_DBG_TYPE_SR, + "DAT Registry: static registry unable to " + "load library %s\n", data->lib_path); + goto bail; + } + + data->init_func = (DAT_PROVIDER_INIT_FUNC)dat_os_library_sym (data->lib_handle, DAT_PROVIDER_INIT_FUNC_STR); + data->fini_func = (DAT_PROVIDER_FINI_FUNC)dat_os_library_sym (data->lib_handle, DAT_PROVIDER_FINI_FUNC_STR); + + if ( NULL != data->init_func ) + { + (*data->init_func)(&data->info, data->ia_params); + } + } + else + { + data->ref_count++; + } + } + + bail: + dat_os_unlock (&g_sr_lock); + + return status; +} + + +//*********************************************************************** +// Function: dat_sr_provider_close +//*********************************************************************** + +extern DAT_RETURN +dat_sr_provider_close ( + IN const DAT_PROVIDER_INFO *info ) +{ + DAT_RETURN status; + DAT_SR_ENTRY *data; + + dat_os_lock (&g_sr_lock); + + status = dat_dictionary_search (g_sr_dictionary, + info, + (DAT_DICTIONARY_DATA *) &data); + + if ( DAT_SUCCESS == status ) + { + if ( 1 == data->ref_count ) + { + if ( NULL != data->fini_func ) + { + (*data->fini_func)(&data->info); + } + + status = dat_os_library_unload (data->lib_handle); + if ( status == DAT_SUCCESS ) + { + data->ref_count--; + } + } + else + { + data->ref_count--; + } + } + + dat_os_unlock (&g_sr_lock); + + return status; +} diff --git a/branches/WOF2-3/ulp/dapl/dat/common/dat_sr.h b/branches/WOF2-3/ulp/dapl/dat/common/dat_sr.h new file mode 100644 index 00000000..5551ee20 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dat/common/dat_sr.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dat_sr.h + * + * PURPOSE: static registry (SR) inteface declarations + * + **********************************************************************/ + +#ifndef _DAT_SR_H_ +#define _DAT_SR_H_ + + +#include +#include + +#include "dat_osd.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************* + * * + * Strucutres * + * * + *********************************************************************/ + +typedef struct +{ + DAT_PROVIDER_INFO info; + char * lib_path; + char * ia_params; + DAT_OS_LIBRARY_HANDLE lib_handle; + DAT_PROVIDER_INIT_FUNC init_func; + DAT_PROVIDER_FINI_FUNC fini_func; + DAT_COUNT ref_count; +} DAT_SR_ENTRY; + + +/********************************************************************* + * * + * Function Declarations * + * * + *********************************************************************/ + +extern DAT_RETURN +dat_sr_init( void ); + +extern DAT_RETURN +dat_sr_fini( void ); + +extern DAT_RETURN +dat_sr_insert ( + IN const DAT_PROVIDER_INFO *info, + IN DAT_SR_ENTRY *entry ); + +extern DAT_RETURN +dat_sr_size ( + OUT DAT_COUNT *size); + +extern DAT_RETURN +dat_sr_list ( + IN DAT_COUNT max_to_return, + OUT DAT_COUNT *entries_returned, + OUT DAT_PROVIDER_INFO *(dat_provider_list[]) ); + +extern DAT_RETURN +dat_sr_provider_open ( + IN const DAT_PROVIDER_INFO *info ); + +extern DAT_RETURN +dat_sr_provider_close ( + IN const DAT_PROVIDER_INFO *info ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/branches/WOF2-3/ulp/dapl/dat/common/dat_strerror.c b/branches/WOF2-3/ulp/dapl/dat/common/dat_strerror.c new file mode 100644 index 00000000..6ee77fe4 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dat/common/dat_strerror.c @@ -0,0 +1,600 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dat_strerror.c + * + * PURPOSE: Convert DAT_RETURN values to humman readable string + * + * $Id$ + **********************************************************************/ + +#include + + +/********************************************************************* + * * + * Internal Function Declarations * + * * + *********************************************************************/ + +DAT_RETURN +dat_strerror_major ( + IN DAT_RETURN value, + OUT const char **message ); + +DAT_RETURN +dat_strerror_minor ( + IN DAT_RETURN value, + OUT const char **message ); + + +/********************************************************************* + * * + * Internal Function Definitions * + * * + *********************************************************************/ + +DAT_RETURN +dat_strerror_major ( + IN DAT_RETURN value, + OUT const char **message ) +{ + switch ( DAT_GET_TYPE(value) ) + { + case DAT_SUCCESS: + { + *message = "DAT_SUCCESS"; + return DAT_SUCCESS; + } + case DAT_ABORT: + { + *message = "DAT_ABORT"; + return DAT_SUCCESS; + } + case DAT_CONN_QUAL_IN_USE: + { + *message = "DAT_CONN_QUAL_IN_USE"; + return DAT_SUCCESS; + } + case DAT_INSUFFICIENT_RESOURCES: + { + *message = "DAT_INSUFFICIENT_RESOURCES"; + return DAT_SUCCESS; + } + case DAT_INTERNAL_ERROR: + { + *message = "DAT_INTERNAL_ERROR"; + return DAT_SUCCESS; + } + case DAT_INVALID_HANDLE: + { + *message = "DAT_INVALID_HANDLE"; + return DAT_SUCCESS; + } + case DAT_INVALID_PARAMETER: + { + *message = "DAT_INVALID_PARAMETER"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE: + { + *message = "DAT_INVALID_STATE"; + return DAT_SUCCESS; + } + case DAT_LENGTH_ERROR: + { + *message = "DAT_LENGTH_ERROR"; + return DAT_SUCCESS; + } + case DAT_MODEL_NOT_SUPPORTED: + { + *message = "DAT_MODEL_NOT_SUPPORTED"; + return DAT_SUCCESS; + } + case DAT_PROVIDER_NOT_FOUND: + { + *message = "DAT_PROVIDER_NOT_FOUND"; + return DAT_SUCCESS; + } + case DAT_PRIVILEGES_VIOLATION: + { + *message = "DAT_PRIVILEGES_VIOLATION"; + return DAT_SUCCESS; + } + case DAT_PROTECTION_VIOLATION: + { + *message = "DAT_PROTECTION_VIOLATION"; + return DAT_SUCCESS; + } + case DAT_QUEUE_EMPTY: + { + *message = "DAT_QUEUE_EMPTY"; + return DAT_SUCCESS; + } + case DAT_QUEUE_FULL: + { + *message = "DAT_QUEUE_FULL"; + return DAT_SUCCESS; + } + case DAT_TIMEOUT_EXPIRED: + { + *message = "DAT_TIMEOUT_EXPIRED"; + return DAT_SUCCESS; + } + case DAT_PROVIDER_ALREADY_REGISTERED: + { + *message = "DAT_PROVIDER_ALREADY_REGISTERED"; + return DAT_SUCCESS; + } + case DAT_PROVIDER_IN_USE: + { + *message = "DAT_PROVIDER_IN_USE"; + return DAT_SUCCESS; + } + case DAT_INVALID_ADDRESS: + { + *message = "DAT_INVALID_ADDRESS"; + return DAT_SUCCESS; + } + case DAT_INTERRUPTED_CALL: + { + *message = "DAT_INTERRUPTED_CALL"; + return DAT_SUCCESS; + } + case DAT_NOT_IMPLEMENTED: + { + *message = "DAT_NOT_IMPLEMENTED"; + return DAT_SUCCESS; + } + default: + { + return DAT_INVALID_PARAMETER; + } + } +} + + +DAT_RETURN +dat_strerror_minor ( + IN DAT_RETURN value, + OUT const char **message ) +{ + switch ( DAT_GET_SUBTYPE(value) ) + { + + case DAT_NO_SUBTYPE: /* NO subtype */ + { + *message = ""; + return DAT_SUCCESS; + } + case DAT_SUB_INTERRUPTED: + { + *message = "DAT_SUB_INTERRUPTED"; + return DAT_SUCCESS; + } + case DAT_RESOURCE_MEMORY: + { + *message = "DAT_RESOURCE_MEMORY"; + return DAT_SUCCESS; + } + case DAT_RESOURCE_DEVICE: + { + *message = "DAT_RESOURCE_DEVICE"; + return DAT_SUCCESS; + } + case DAT_RESOURCE_TEP: + { + *message = "DAT_RESOURCE_TEP"; + return DAT_SUCCESS; + } + case DAT_RESOURCE_TEVD: + { + *message = "DAT_RESOURCE_TEVD"; + return DAT_SUCCESS; + } + case DAT_RESOURCE_PROTECTION_DOMAIN: + { + *message = "DAT_RESOURCE_PROTECTION_DOMAIN"; + return DAT_SUCCESS; + } + case DAT_RESOURCE_MEMORY_REGION: + { + *message = "DAT_RESOURCE_MEMORY_REGION"; + return DAT_SUCCESS; + } + case DAT_RESOURCE_ERROR_HANDLER: + { + *message = "DAT_RESOURCE_ERROR_HANDLER"; + return DAT_SUCCESS; + } + case DAT_RESOURCE_CREDITS: + { + *message = "DAT_RESOURCE_CREDITS"; + return DAT_SUCCESS; + } + case DAT_INVALID_HANDLE_IA: + { + *message = "DAT_INVALID_HANDLE_IA"; + return DAT_SUCCESS; + } + case DAT_INVALID_HANDLE_EP: + { + *message = "DAT_INVALID_HANDLE_EP"; + return DAT_SUCCESS; + } + case DAT_INVALID_HANDLE_LMR: + { + *message = "DAT_INVALID_HANDLE_LMR"; + return DAT_SUCCESS; + } + case DAT_INVALID_HANDLE_RMR: + { + *message = "DAT_INVALID_HANDLE_RMR"; + return DAT_SUCCESS; + } + case DAT_INVALID_HANDLE_PZ: + { + *message = "DAT_INVALID_HANDLE_PZ"; + return DAT_SUCCESS; + } + case DAT_INVALID_HANDLE_PSP: + { + *message = "DAT_INVALID_HANDLE_PSP"; + return DAT_SUCCESS; + } + case DAT_INVALID_HANDLE_RSP: + { + *message = "DAT_INVALID_HANDLE_RSP"; + return DAT_SUCCESS; + } + case DAT_INVALID_HANDLE_CR: + { + *message = "DAT_INVALID_HANDLE_CR"; + return DAT_SUCCESS; + } + case DAT_INVALID_HANDLE_CNO: + { + *message = "DAT_INVALID_HANDLE_CNO"; + return DAT_SUCCESS; + } + case DAT_INVALID_HANDLE_EVD_CR: + { + *message = "DAT_INVALID_HANDLE_EVD_CR"; + return DAT_SUCCESS; + } + case DAT_INVALID_HANDLE_EVD_REQUEST: + { + *message = "DAT_INVALID_HANDLE_EVD_REQUEST"; + return DAT_SUCCESS; + } + case DAT_INVALID_HANDLE_EVD_RECV: + { + *message = "DAT_INVALID_HANDLE_EVD_RECV"; + return DAT_SUCCESS; + } + case DAT_INVALID_HANDLE_EVD_CONN: + { + *message = "DAT_INVALID_HANDLE_EVD_CONN"; + return DAT_SUCCESS; + } + case DAT_INVALID_HANDLE_EVD_ASYNC: + { + *message = "DAT_INVALID_HANDLE_EVD_ASYNC"; + return DAT_SUCCESS; + } + case DAT_INVALID_ARG1: + { + *message = "DAT_INVALID_ARG1"; + return DAT_SUCCESS; + } + case DAT_INVALID_ARG2: + { + *message = "DAT_INVALID_ARG2"; + return DAT_SUCCESS; + } + case DAT_INVALID_ARG3: + { + *message = "DAT_INVALID_ARG3"; + return DAT_SUCCESS; + } + case DAT_INVALID_ARG4: + { + *message = "DAT_INVALID_ARG4"; + return DAT_SUCCESS; + } + case DAT_INVALID_ARG5: + { + *message = "DAT_INVALID_ARG5"; + return DAT_SUCCESS; + } + case DAT_INVALID_ARG6: + { + *message = "DAT_INVALID_ARG6"; + return DAT_SUCCESS; + } + case DAT_INVALID_ARG7: + { + *message = "DAT_INVALID_ARG7"; + return DAT_SUCCESS; + } + case DAT_INVALID_ARG8: + { + *message = "DAT_INVALID_ARG8"; + return DAT_SUCCESS; + } + case DAT_INVALID_ARG9: + { + *message = "DAT_INVALID_ARG9"; + return DAT_SUCCESS; + } + case DAT_INVALID_ARG10: + { + *message = "DAT_INVALID_ARG10"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_EP_UNCONNECTED: + { + *message = "DAT_INVALID_STATE_EP_UNCONNECTED"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_EP_ACTCONNPENDING: + { + *message = "DAT_INVALID_STATE_EP_ACTCONNPENDING"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_EP_PASSCONNPENDING: + { + *message = "DAT_INVALID_STATE_EP_PASSCONNPENDING"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_EP_TENTCONNPENDING: + { + *message = "DAT_INVALID_STATE_EP_TENTCONNPENDING"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_EP_CONNECTED: + { + *message = "DAT_INVALID_STATE_EP_CONNECTED"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_EP_DISCONNECTED: + { + *message = "DAT_INVALID_STATE_EP_DISCONNECTED"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_EP_RESERVED: + { + *message = "DAT_INVALID_STATE_EP_RESERVED"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_EP_COMPLPENDING: + { + *message = "DAT_INVALID_STATE_EP_COMPLPENDING"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_EP_DISCPENDING: + { + *message = "DAT_INVALID_STATE_EP_DISCPENDING"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_EP_PROVIDERCONTROL: + { + *message = "DAT_INVALID_STATE_EP_PROVIDERCONTROL"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_EP_NOTREADY: + { + *message = "DAT_INVALID_STATE_EP_NOTREADY"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_CNO_IN_USE: + { + *message = "DAT_INVALID_STATE_CNO_IN_USE"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_CNO_DEAD: + { + *message = "DAT_INVALID_STATE_CNO_DEAD"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_EVD_OPEN: + { + *message = "DAT_INVALID_STATE_EVD_OPEN"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_EVD_ENABLED: + { + *message = "DAT_INVALID_STATE_EVD_ENABLED"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_EVD_DISABLED: + { + *message = "DAT_INVALID_STATE_EVD_DISABLED"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_EVD_WAITABLE: + { + *message = "DAT_INVALID_STATE_EVD_WAITABLE"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_EVD_UNWAITABLE: + { + *message = "DAT_INVALID_STATE_EVD_UNWAITABLE"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_EVD_IN_USE: + { + *message = "DAT_INVALID_STATE_EVD_IN_USE"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_EVD_CONFIG_NOTIFY: + { + *message = "DAT_INVALID_STATE_EVD_CONFIG_NOTIFY"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_EVD_CONFIG_SOLICITED: + { + *message = "DAT_INVALID_STATE_EVD_CONFIG_SOLICITED"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_EVD_CONFIG_THRESHOLD: + { + *message = "DAT_INVALID_STATE_EVD_CONFIG_THRESHOLD"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_EVD_WAITER: + { + *message = "DAT_INVALID_STATE_EVD_WAITER"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_EVD_ASYNC: + { + *message = "DAT_INVALID_STATE_EVD_ASYNC"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_IA_IN_USE: + { + *message = "DAT_INVALID_STATE_IA_IN_USE"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_LMR_IN_USE: + { + *message = "DAT_INVALID_STATE_LMR_IN_USE"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_LMR_FREE: + { + *message = "DAT_INVALID_STATE_LMR_FREE"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_PZ_IN_USE: + { + *message = "DAT_INVALID_STATE_PZ_IN_USE"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_PZ_FREE: + { + *message = "DAT_INVALID_STATE_PZ_FREE"; + return DAT_SUCCESS; + } + case DAT_PRIVILEGES_READ: + { + *message = "DAT_PRIVILEGES_READ"; + return DAT_SUCCESS; + } + case DAT_PRIVILEGES_WRITE: + { + *message = "DAT_PRIVILEGES_WRITE"; + return DAT_SUCCESS; + } + case DAT_PRIVILEGES_RDMA_READ: + { + *message = "DAT_PRIVILEGES_RDMA_READ"; + return DAT_SUCCESS; + } + case DAT_PRIVILEGES_RDMA_WRITE: + { + *message = "DAT_PRIVILEGES_RDMA_WRITE"; + return DAT_SUCCESS; + } + case DAT_PROTECTION_READ: + { + *message = "DAT_PROTECTION_READ"; + return DAT_SUCCESS; + } + case DAT_PROTECTION_WRITE: + { + *message = "DAT_PROTECTION_WRITE"; + return DAT_SUCCESS; + } + case DAT_PROTECTION_RDMA_READ: + { + *message = "DAT_PROTECTION_RDMA_READ"; + return DAT_SUCCESS; + } + case DAT_PROTECTION_RDMA_WRITE: + { + *message = "DAT_PROTECTION_RDMA_WRITE"; + return DAT_SUCCESS; + } + case DAT_INVALID_ADDRESS_UNSUPPORTED: + { + *message = "DAT_INVALID_ADDRESS_UNSUPPORTED"; + return DAT_SUCCESS; + } + case DAT_INVALID_ADDRESS_UNREACHABLE: + { + *message = "DAT_INVALID_ADDRESS_UNREACHABLE"; + return DAT_SUCCESS; + } + case DAT_INVALID_ADDRESS_MALFORMED: + { + *message = "DAT_INVALID_ADDRESS_MALFORMED"; + return DAT_SUCCESS; + } + default: + { + return DAT_INVALID_PARAMETER; + } + } +} + + +/********************************************************************* + * * + * External Function Definitions * + * * + *********************************************************************/ + +DAT_RETURN DAT_API +dat_strerror ( + IN DAT_RETURN value, + OUT const char **major_message, + OUT const char **minor_message ) +{ + /* + * The DAT specification contains a note to implementers + * suggesting that the consumer's DAT_RETURN value be used + * as an index into a table of text strings. However, + * the DAT_RETURN values are not consecutive. Therefore this + * implementation does not follow the suggested implementation. + */ + + if ( DAT_SUCCESS != dat_strerror_major(value, major_message) ) + { + return DAT_INVALID_PARAMETER; + } + else if ( DAT_SUCCESS != dat_strerror_minor(value, minor_message) ) + { + return DAT_INVALID_PARAMETER; + } + else + { + return DAT_SUCCESS; + } +} diff --git a/branches/WOF2-3/ulp/dapl/dat/dirs b/branches/WOF2-3/ulp/dapl/dat/dirs new file mode 100644 index 00000000..97d2b67c --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dat/dirs @@ -0,0 +1 @@ +DIRS=udat diff --git a/branches/WOF2-3/ulp/dapl/dat/include/dat/dat.h b/branches/WOF2-3/ulp/dapl/dat/include/dat/dat.h new file mode 100644 index 00000000..10854020 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dat/include/dat/dat.h @@ -0,0 +1,958 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dat.h + * + * PURPOSE: defines the common DAT API for uDAPL and kDAPL. + * + * Description: Header file for "uDAPL: User Direct Access Programming + * Library, Version: 1.1" + * + * Mapping rules: + * All global symbols are prepended with "DAT_" or "dat_" + * All DAT objects have an 'api' tag which, such as 'ep' or 'lmr' + * The method table is in the provider definition structure. + * + * + **********************************************************************/ + +#ifndef _DAT_H_ +#define _DAT_H_ + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Generic DAT types */ + +typedef char * DAT_NAME_PTR; /* Format for ia_name and attributes */ +#define DAT_NAME_MAX_LENGTH 256 + +/* + * Used for provider, vendor, transport, hardware specific attributes + * definitions. + */ + +typedef struct dat_named_attr + { + const char * name; /* Name of attribute */ + const char * value; /* Value of attribute */ + } DAT_NAMED_ATTR; + +typedef enum dat_boolean + { + DAT_FALSE = 0, + DAT_TRUE = 1 + } DAT_BOOLEAN; + +typedef union dat_context + { + DAT_PVOID as_ptr; + DAT_UINT64 as_64; + DAT_UVERYLONG as_index; + } DAT_CONTEXT; + +typedef DAT_CONTEXT DAT_DTO_COOKIE; +typedef DAT_CONTEXT DAT_RMR_COOKIE; + +typedef enum dat_completion_flags + { + /* Completes with notification */ + DAT_COMPLETION_DEFAULT_FLAG = 0x00, + + /* Completions suppressed if successful */ + DAT_COMPLETION_SUPPRESS_FLAG = 0x01, + + /* Sender controlled notification for recv completion */ + DAT_COMPLETION_SOLICITED_WAIT_FLAG = 0x02, + + /* Completions with unsignaled notifications */ + DAT_COMPLETION_UNSIGNALLED_FLAG = 0x04, + + /* Do not start processing until all previous RDMA reads complete. */ + DAT_COMPLETION_BARRIER_FENCE_FLAG = 0x08, + + /* Only valid for uDAPL as EP attribute for Recv Completion flags. + * Waiter unblocking is controlled by Threshold value of dat_evd_wait. + * UNSIGNALLED for RECV not allowed when EP has this attribute */ + DAT_COMPLETION_EVD_THRESHOLD_FLAG = 0x10 + + } DAT_COMPLETION_FLAGS; + + +typedef DAT_UINT32 DAT_TIMEOUT; /* microseconds */ + +/* timeout = infinity */ +#define DAT_TIMEOUT_INFINITE ((DAT_TIMEOUT) ~0) + +/* dat handles */ +typedef DAT_PVOID DAT_HANDLE; +typedef DAT_HANDLE DAT_CR_HANDLE; +typedef DAT_HANDLE DAT_EP_HANDLE; +typedef DAT_HANDLE DAT_EVD_HANDLE; +typedef DAT_HANDLE DAT_IA_HANDLE; +typedef DAT_HANDLE DAT_LMR_HANDLE; +typedef DAT_HANDLE DAT_PSP_HANDLE; +typedef DAT_HANDLE DAT_PZ_HANDLE; +typedef DAT_HANDLE DAT_RMR_HANDLE; +typedef DAT_HANDLE DAT_RSP_HANDLE; + + +/* dat NULL handles */ +#define DAT_HANDLE_NULL ((DAT_HANDLE)NULL) + +typedef DAT_SOCK_ADDR * DAT_IA_ADDRESS_PTR; + +typedef DAT_UINT64 DAT_CONN_QUAL; +typedef DAT_UINT64 DAT_PORT_QUAL; + +/* QOS definitions */ +typedef enum dat_qos + { + DAT_QOS_BEST_EFFORT = 0x00, + DAT_QOS_HIGH_THROUGHPUT = 0x01, + DAT_QOS_LOW_LATENCY = 0x02, + /* not low latency, nor high throughput */ + DAT_QOS_ECONOMY = 0x04, + /* both low latency and high throughput */ + DAT_QOS_PREMIUM = 0x08 + } DAT_QOS; + +/* + * FLAGS + */ + +typedef enum dat_connect_flags + { + DAT_CONNECT_DEFAULT_FLAG = 0x00, + DAT_CONNECT_MULTIPATH_FLAG = 0x01 + } DAT_CONNECT_FLAGS; + +typedef enum dat_close_flags + { + DAT_CLOSE_ABRUPT_FLAG = 0x00, + DAT_CLOSE_GRACEFUL_FLAG = 0x01 + } DAT_CLOSE_FLAGS; + +#define DAT_CLOSE_DEFAULT DAT_CLOSE_ABRUPT_FLAG + +typedef enum dat_evd_flags + { + DAT_EVD_SOFTWARE_FLAG = 0x01, + DAT_EVD_CR_FLAG = 0x10, + DAT_EVD_DTO_FLAG = 0x20, + DAT_EVD_CONNECTION_FLAG = 0x40, + DAT_EVD_RMR_BIND_FLAG = 0x80, + DAT_EVD_ASYNC_FLAG = 0x100, + /* DAT events only, no software events */ + DAT_EVD_DEFAULT_FLAG = 0x1F0 + } DAT_EVD_FLAGS; + +typedef enum dat_psp_flags + { + DAT_PSP_CONSUMER_FLAG = 0x00, /* Consumer creates an endpoint */ + DAT_PSP_PROVIDER_FLAG = 0x01 /* Provider creates an endpoint */ + + } DAT_PSP_FLAGS; + +/* + * Memory Buffers + * + * Both LMR and RMR triplets specify 64-bit addresses in the local host's byte + * order, even when that exceeds the size of a DAT_PVOID for the host + * architecture. + */ + +typedef DAT_UINT32 DAT_LMR_CONTEXT; +typedef DAT_UINT32 DAT_RMR_CONTEXT; + +typedef DAT_UINT64 DAT_VLEN; +typedef DAT_UINT64 DAT_VADDR; + +/* It is legal for Consumer to specify zero for segment_length + * of the dat_lmr_triplet. When 0 is specified for the + * segment_length then the other two elements of the + * dat_lmr_triplet are irrelevant and can be invalid. */ + +typedef struct dat_lmr_triplet + { + DAT_LMR_CONTEXT lmr_context; + DAT_UINT32 pad; + DAT_VADDR virtual_address; + DAT_VLEN segment_length; + } DAT_LMR_TRIPLET; + +typedef struct dat_rmr_triplet + { + DAT_RMR_CONTEXT rmr_context; + DAT_UINT32 pad; + DAT_VADDR target_address; + DAT_VLEN segment_length; + } DAT_RMR_TRIPLET; + + +/* Memory privileges */ + +typedef enum dat_mem_priv_flags + { + DAT_MEM_PRIV_NONE_FLAG = 0x00, + DAT_MEM_PRIV_LOCAL_READ_FLAG = 0x01, + DAT_MEM_PRIV_REMOTE_READ_FLAG = 0x02, + DAT_MEM_PRIV_LOCAL_WRITE_FLAG = 0x10, + DAT_MEM_PRIV_REMOTE_WRITE_FLAG = 0x20, + DAT_MEM_PRIV_ALL_FLAG = 0x33 + } DAT_MEM_PRIV_FLAGS; + +/* For backwards compatibility with DAT-1.0 memory privileges values are supported */ +#define DAT_MEM_PRIV_READ_FLAG (DAT_MEM_PRIV_LOCAL_READ_FLAG | DAT_MEM_PRIV_REMOTE_READ_FLAG) +#define DAT_MEM_PRIV_WRITE_FLAG (DAT_MEM_PRIV_LOCAL_WRITE_FLAG | DAT_MEM_PRIV_REMOTE_WRITE_FLAG) + +/* LMR Arguments Mask */ + +typedef enum dat_lmr_param_mask + { + DAT_LMR_FIELD_IA_HANDLE = 0x001, + DAT_LMR_FIELD_MEM_TYPE = 0x002, + DAT_LMR_FIELD_REGION_DESC = 0x004, + DAT_LMR_FIELD_LENGTH = 0x008, + DAT_LMR_FIELD_PZ_HANDLE = 0x010, + DAT_LMR_FIELD_MEM_PRIV = 0x020, + DAT_LMR_FIELD_LMR_CONTEXT = 0x040, + DAT_LMR_FIELD_RMR_CONTEXT = 0x080, + DAT_LMR_FIELD_REGISTERED_SIZE = 0x100, + DAT_LMR_FIELD_REGISTERED_ADDRESS = 0x200, + + DAT_LMR_FIELD_ALL = 0x3FF + } DAT_LMR_PARAM_MASK; + +/* RMR Argumments & RMR Arguments Mask */ + +typedef struct dat_rmr_param + { + DAT_IA_HANDLE ia_handle; + DAT_PZ_HANDLE pz_handle; + DAT_LMR_TRIPLET lmr_triplet; + DAT_MEM_PRIV_FLAGS mem_priv; + DAT_RMR_CONTEXT rmr_context; + } DAT_RMR_PARAM; + +typedef enum dat_rmr_param_mask + { + DAT_RMR_FIELD_IA_HANDLE = 0x01, + DAT_RMR_FIELD_PZ_HANDLE = 0x02, + DAT_RMR_FIELD_LMR_TRIPLET = 0x04, + DAT_RMR_FIELD_MEM_PRIV = 0x08, + DAT_RMR_FIELD_RMR_CONTEXT = 0x10, + + DAT_RMR_FIELD_ALL = 0x1F + } DAT_RMR_PARAM_MASK; + +/* Provider attributes */ + +typedef enum dat_iov_ownership + { + /* Not modification by provider, consumer can use anytime. */ + DAT_IOV_CONSUMER = 0x0, + + /* Provider does not modify returned IOV DTO on completion. */ + DAT_IOV_PROVIDER_NOMOD = 0x1, + + /* Provider may modify IOV DTO on completion, can't trust it. */ + DAT_IOV_PROVIDER_MOD = 0x2 + + } DAT_IOV_OWNERSHIP; + +typedef enum dat_ep_creator_for_psp + { + DAT_PSP_CREATES_EP_NEVER, /* provider never creates endpoint */ + DAT_PSP_CREATES_EP_IFASKED, /* provider creates endpoint if asked */ + DAT_PSP_CREATES_EP_ALWAYS /* provider always creates endpoint */ + } DAT_EP_CREATOR_FOR_PSP; + +/* Endpoint attributes */ + +typedef enum dat_service_type + { + DAT_SERVICE_TYPE_RC /* reliable connections */ + } DAT_SERVICE_TYPE; + +typedef struct dat_ep_attr { + DAT_SERVICE_TYPE service_type; + DAT_VLEN max_mtu_size; + DAT_VLEN max_rdma_size; + DAT_QOS qos; + DAT_COMPLETION_FLAGS recv_completion_flags; + DAT_COMPLETION_FLAGS request_completion_flags; + DAT_COUNT max_recv_dtos; + DAT_COUNT max_request_dtos; + DAT_COUNT max_recv_iov; + DAT_COUNT max_request_iov; + DAT_COUNT max_rdma_read_in; + DAT_COUNT max_rdma_read_out; + DAT_COUNT ep_transport_specific_count; + DAT_NAMED_ATTR * ep_transport_specific; + DAT_COUNT ep_provider_specific_count; + DAT_NAMED_ATTR * ep_provider_specific; + } DAT_EP_ATTR; + +/* Endpoint Parameters */ + +/* For backwards compatability */ +#define DAT_EP_STATE_ERROR DAT_EP_STATE_DISCONNECTED + +typedef enum dat_ep_state + { + DAT_EP_STATE_UNCONNECTED, /* quiescent state */ + DAT_EP_STATE_RESERVED, + DAT_EP_STATE_PASSIVE_CONNECTION_PENDING, + DAT_EP_STATE_ACTIVE_CONNECTION_PENDING, + DAT_EP_STATE_TENTATIVE_CONNECTION_PENDING, + DAT_EP_STATE_CONNECTED, + DAT_EP_STATE_DISCONNECT_PENDING, + DAT_EP_STATE_DISCONNECTED, + DAT_EP_STATE_COMPLETION_PENDING + } DAT_EP_STATE; + +typedef struct dat_ep_param + { + DAT_IA_HANDLE ia_handle; + DAT_EP_STATE ep_state; + DAT_IA_ADDRESS_PTR local_ia_address_ptr; + DAT_PORT_QUAL local_port_qual; + DAT_IA_ADDRESS_PTR remote_ia_address_ptr; + DAT_PORT_QUAL remote_port_qual; + DAT_PZ_HANDLE pz_handle; + DAT_EVD_HANDLE recv_evd_handle; + DAT_EVD_HANDLE request_evd_handle; + DAT_EVD_HANDLE connect_evd_handle; + DAT_EP_ATTR ep_attr; + } DAT_EP_PARAM; + +typedef enum dat_ep_param_mask + { + DAT_EP_FIELD_IA_HANDLE = 0x00000001, + DAT_EP_FIELD_EP_STATE = 0x00000002, + DAT_EP_FIELD_LOCAL_IA_ADDRESS_PTR = 0x00000004, + DAT_EP_FIELD_LOCAL_PORT_QUAL = 0x00000008, + DAT_EP_FIELD_REMOTE_IA_ADDRESS_PTR = 0x00000010, + DAT_EP_FIELD_REMOTE_PORT_QUAL = 0x00000020, + DAT_EP_FIELD_PZ_HANDLE = 0x00000040, + DAT_EP_FIELD_RECV_EVD_HANDLE = 0x00000080, + DAT_EP_FIELD_REQUEST_EVD_HANDLE = 0x00000100, + DAT_EP_FIELD_CONNECT_EVD_HANDLE = 0x00000200, + + /* Remainder of values from EP_ATTR, 0x00001000 and up */ + + DAT_EP_FIELD_EP_ATTR_SERVICE_TYPE = 0x00001000, + DAT_EP_FIELD_EP_ATTR_MAX_MESSAGE_SIZE = 0x00002000, + DAT_EP_FIELD_EP_ATTR_MAX_RDMA_SIZE = 0x00004000, + DAT_EP_FIELD_EP_ATTR_QOS = 0x00008000, + + DAT_EP_FIELD_EP_ATTR_RECV_COMPLETION_FLAGS = 0x00010000, + DAT_EP_FIELD_EP_ATTR_REQUEST_COMPLETION_FLAGS = 0x00020000, + DAT_EP_FIELD_EP_ATTR_MAX_RECV_DTOS = 0x00040000, + DAT_EP_FIELD_EP_ATTR_MAX_REQUEST_DTOS = 0x00080000, + + DAT_EP_FIELD_EP_ATTR_MAX_RECV_IOV = 0x00100000, + DAT_EP_FIELD_EP_ATTR_MAX_REQUEST_IOV = 0x00200000, + + DAT_EP_FIELD_EP_ATTR_MAX_RDMA_READ_IN = 0x00400000, + DAT_EP_FIELD_EP_ATTR_MAX_RDMA_READ_OUT = 0x00800000, + + DAT_EP_FIELD_EP_ATTR_NUM_TRANSPORT_ATTR = 0x01000000, + DAT_EP_FIELD_EP_ATTR_TRANSPORT_SPECIFIC_ATTR = 0x02000000, + + DAT_EP_FIELD_EP_ATTR_NUM_PROVIDER_ATTR = 0x04000000, + DAT_EP_FIELD_EP_ATTR_PROVIDER_SPECIFIC_ATTR = 0x08000000, + + DAT_EP_FIELD_EP_ATTR_ALL = 0x0FFFF000, + DAT_EP_FIELD_ALL = 0x0FFFF5FF + } DAT_EP_PARAM_MASK; + +/* PZ Parameters */ + +typedef struct dat_pz_param + { + DAT_IA_HANDLE ia_handle; + } DAT_PZ_PARAM; + +typedef enum dat_pz_param_mask + { + DAT_PZ_FIELD_IA_HANDLE = 0x01, + + DAT_PZ_FIELD_ALL = 0x01 + } DAT_PZ_PARAM_MASK; + +/* PSP Parameters */ + +typedef struct dat_psp_param + { + DAT_IA_HANDLE ia_handle; + DAT_CONN_QUAL conn_qual; + DAT_EVD_HANDLE evd_handle; + DAT_PSP_FLAGS psp_flags; + } DAT_PSP_PARAM; + +typedef enum dat_psp_param_mask + { + DAT_PSP_FIELD_IA_HANDLE = 0x01, + DAT_PSP_FIELD_CONN_QUAL = 0x02, + DAT_PSP_FIELD_EVD_HANDLE = 0x04, + DAT_PSP_FIELD_PSP_FLAGS = 0x08, + + DAT_PSP_FIELD_ALL = 0x0F + } DAT_PSP_PARAM_MASK; + +/* RSP Parameters */ + +typedef struct dat_rsp_param + { + DAT_IA_HANDLE ia_handle; + DAT_CONN_QUAL conn_qual; + DAT_EVD_HANDLE evd_handle; + DAT_EP_HANDLE ep_handle; + } DAT_RSP_PARAM; + +typedef enum dat_rsp_param_mask + { + DAT_RSP_FIELD_IA_HANDLE = 0x01, + DAT_RSP_FIELD_CONN_QUAL = 0x02, + DAT_RSP_FIELD_EVD_HANDLE = 0x04, + DAT_RSP_FIELD_EP_HANDLE = 0x08, + + DAT_RSP_FIELD_ALL = 0x0F + } DAT_RSP_PARAM_MASK; + +/* Connection Request Parameters. + * + * The Connection Request does not provide Remote Endpoint attributes. + * If a local Consumer needs this information, the remote Consumer should + * encode it into Private Data. + */ + +typedef struct dat_cr_param + { + /* Remote IA whose Endpoint requested the connection. */ + DAT_IA_ADDRESS_PTR remote_ia_address_ptr; + + /* Port qualifier of the remote Endpoint of the requested connection. */ + DAT_PORT_QUAL remote_port_qual; + + /* Size of the Private Data. */ + DAT_COUNT private_data_size; + + /* Pointer to the Private Data passed by remote side in the Connection + * Request. */ + DAT_PVOID private_data; + + /* The local Endpoint provided by the Service Point for the requested + * connection. It is the only Endpoint that can accept a Connection + * Request on this Service Point. The value DAT_HANDLE_NULL represents + * that there is no associated local Endpoint for the requested + * connection. */ + DAT_EP_HANDLE local_ep_handle; + + } DAT_CR_PARAM; + +typedef enum dat_cr_param_mask + { + DAT_CR_FIELD_REMOTE_IA_ADDRESS_PTR = 0x01, + DAT_CR_FIELD_REMOTE_PORT_QUAL = 0x02, + DAT_CR_FIELD_PRIVATE_DATA_SIZE = 0x04, + DAT_CR_FIELD_PRIVATE_DATA = 0x08, + DAT_CR_FIELD_LOCAL_EP_HANDLE = 0x10, + + DAT_CR_FIELD_ALL = 0x1F + } DAT_CR_PARAM_MASK; + +/************************** Events ******************************************/ + +/* Completion status flags */ + + /* dto completion status */ + + /* For backwards compatability */ +#define DAT_DTO_LENGTH_ERROR DAT_DTO_ERR_LOCAL_LENGTH +#define DAT_DTO_FAILURE DAT_DTO_ERR_FLUSHED + +typedef enum dat_dto_completion_status + { + DAT_DTO_SUCCESS = 0, + DAT_DTO_ERR_FLUSHED = 1, + DAT_DTO_ERR_LOCAL_LENGTH = 2, + DAT_DTO_ERR_LOCAL_EP = 3, + DAT_DTO_ERR_LOCAL_PROTECTION = 4, + DAT_DTO_ERR_BAD_RESPONSE = 5, + DAT_DTO_ERR_REMOTE_ACCESS = 6, + DAT_DTO_ERR_REMOTE_RESPONDER = 7, + DAT_DTO_ERR_TRANSPORT = 8, + DAT_DTO_ERR_RECEIVER_NOT_READY = 9, + DAT_DTO_ERR_PARTIAL_PACKET = 10, + DAT_RMR_OPERATION_FAILED = 11 + } DAT_DTO_COMPLETION_STATUS; + + /* rmr completion status */ + + /* For backwards compatability */ +#define DAT_RMR_BIND_SUCCESS DAT_DTO_SUCCESS +#define DAT_RMR_BIND_FAILURE DAT_DTO_ERR_FLUSHED + +#define DAT_RMR_BIND_COMPLETION_STATUS DAT_DTO_COMPLETION_STATUS + +/* Completion group structs (six total) */ + + /* DTO completion event data */ +typedef struct dat_dto_completion_event_data + { + DAT_EP_HANDLE ep_handle; + DAT_DTO_COOKIE user_cookie; + DAT_DTO_COMPLETION_STATUS status; + DAT_VLEN transfered_length; + } DAT_DTO_COMPLETION_EVENT_DATA; + + /* rmr bind completion event data */ +typedef struct dat_rmr_bind_completion_event_data + { + DAT_RMR_HANDLE rmr_handle; + DAT_RMR_COOKIE user_cookie; + DAT_RMR_BIND_COMPLETION_STATUS status; + } DAT_RMR_BIND_COMPLETION_EVENT_DATA; + +typedef union dat_sp_handle +{ + DAT_RSP_HANDLE rsp_handle; + DAT_PSP_HANDLE psp_handle; +} DAT_SP_HANDLE; + + /* Connection Request Arrival event data */ +typedef struct dat_cr_arrival_event_data + { + /* Handle to the Service Point that received the Connection Request from + * the remote side. If the Service Point was Reserved, sp is DAT_HANDLE_NULL + * because the reserved Service Point is automatically destroyed upon + * generating this event. Can be PSP or RSP. */ + DAT_SP_HANDLE sp_handle; + + /* Address of the IA on which the Connection Request arrived. */ + DAT_IA_ADDRESS_PTR local_ia_address_ptr; + + /* Connection Qualifier of the IA on which the Service Point received a + * Connection Request. */ + DAT_CONN_QUAL conn_qual; + + /* The Connection Request instance created by a Provider for the arrived + * Connection Request. Consumers can find out private_data passed by a remote + * Consumer from cr_handle. It is up to a Consumer to dat_cr_accept or + * dat_cr_reject of the Connection Request. */ + DAT_CR_HANDLE cr_handle; + + } DAT_CR_ARRIVAL_EVENT_DATA; + + + /* Connection event data */ +typedef struct dat_connection_event_data + { + DAT_EP_HANDLE ep_handle; + DAT_COUNT private_data_size; + DAT_PVOID private_data; + } DAT_CONNECTION_EVENT_DATA; + + /* Async Error event data */ +typedef struct dat_asynch_error_event_data + { + DAT_IA_HANDLE ia_handle; + } DAT_ASYNCH_ERROR_EVENT_DATA; + + /* SE completion event data */ +typedef struct dat_software_event_data + { + DAT_PVOID pointer; + } DAT_SOFTWARE_EVENT_DATA; + +typedef enum dat_event_number + { + DAT_DTO_COMPLETION_EVENT = 0x00001, + + DAT_RMR_BIND_COMPLETION_EVENT = 0x01001, + + DAT_CONNECTION_REQUEST_EVENT = 0x02001, + + DAT_CONNECTION_EVENT_ESTABLISHED = 0x04001, + DAT_CONNECTION_EVENT_PEER_REJECTED = 0x04002, + DAT_CONNECTION_EVENT_NON_PEER_REJECTED = 0x04003, + DAT_CONNECTION_EVENT_ACCEPT_COMPLETION_ERROR = 0x04004, + DAT_CONNECTION_EVENT_DISCONNECTED = 0x04005, + DAT_CONNECTION_EVENT_BROKEN = 0x04006, + DAT_CONNECTION_EVENT_TIMED_OUT = 0x04007, + DAT_CONNECTION_EVENT_UNREACHABLE = 0x04008, + + DAT_ASYNC_ERROR_EVD_OVERFLOW = 0x08001, + DAT_ASYNC_ERROR_IA_CATASTROPHIC = 0x08002, + DAT_ASYNC_ERROR_EP_BROKEN = 0x08003, + DAT_ASYNC_ERROR_TIMED_OUT = 0x08004, + DAT_ASYNC_ERROR_PROVIDER_INTERNAL_ERROR = 0x08005, + + DAT_SOFTWARE_EVENT = 0x10001 + } DAT_EVENT_NUMBER; + +/* Union for event Data */ + +typedef union dat_event_data + { + DAT_DTO_COMPLETION_EVENT_DATA dto_completion_event_data; + DAT_RMR_BIND_COMPLETION_EVENT_DATA rmr_completion_event_data; + DAT_CR_ARRIVAL_EVENT_DATA cr_arrival_event_data; + DAT_CONNECTION_EVENT_DATA connect_event_data; + DAT_ASYNCH_ERROR_EVENT_DATA asynch_error_event_data; + DAT_SOFTWARE_EVENT_DATA software_event_data; + } DAT_EVENT_DATA; + +/* Event struct that holds all event information */ + +typedef struct dat_event + { + DAT_EVENT_NUMBER event_number; + DAT_EVD_HANDLE evd_handle; + DAT_EVENT_DATA event_data; + } DAT_EVENT; + +/* Provider/registration info */ + +typedef struct dat_provider_info { + char ia_name[DAT_NAME_MAX_LENGTH]; + DAT_UINT32 dapl_version_major; + DAT_UINT32 dapl_version_minor; + DAT_BOOLEAN is_thread_safe; + } DAT_PROVIDER_INFO ; + +/**************************************************************************** + * FUNCTION PROTOTYPES + ****************************************************************************/ +/* + * IA functions + * + * Note that there are actual 'dat_ia_open' and 'dat_ia_close' + * functions, it is not just a re-directing #define. That is + * because the functions may have to ensure that the provider + * library is loaded before it can call it, and may choose to + * unload the library after the last close. + */ + +typedef DAT_RETURN (DAT_API *DAT_IA_OPEN_FUNC)( + IN const DAT_NAME_PTR, /* provider */ + IN DAT_COUNT, /* asynch_evd_min_qlen */ + INOUT DAT_EVD_HANDLE *, /* asynch_evd_handle */ + OUT DAT_IA_HANDLE *); /* ia_handle */ + +typedef DAT_RETURN (DAT_API *DAT_IA_OPENV_FUNC)( + IN const DAT_NAME_PTR, /* provider */ + IN DAT_COUNT, /* asynch_evd_min_qlen */ + INOUT DAT_EVD_HANDLE *, /* asynch_evd_handle */ + OUT DAT_IA_HANDLE *, /* ia_handle */ + IN DAT_UINT32, /* dat major version number */ + IN DAT_UINT32, /* dat minor version number */ + IN DAT_BOOLEAN); /* dat thread safety */ + +typedef DAT_RETURN (DAT_API *DAT_IA_CLOSE_FUNC)( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_CLOSE_FLAGS ); /* close_flags */ + +/* helper functions */ + +typedef DAT_RETURN (DAT_API *DAT_SET_CONSUMER_CONTEXT_FUNC)( + IN DAT_HANDLE, /* dat handle */ + IN DAT_CONTEXT); /* context */ + +typedef DAT_RETURN (DAT_API *DAT_GET_CONSUMER_CONTEXT_FUNC)( + IN DAT_HANDLE, /* dat handle */ + OUT DAT_CONTEXT * ); /* context */ + +typedef DAT_RETURN (DAT_API *DAT_GET_HANDLE_TYPE_FUNC)( + IN DAT_HANDLE, + OUT DAT_HANDLE_TYPE * ); + +/* CR Functions */ + +typedef DAT_RETURN (DAT_API *DAT_CR_QUERY_FUNC)( + IN DAT_CR_HANDLE, /* cr_handle */ + IN DAT_CR_PARAM_MASK, /* cr_param_mask */ + OUT DAT_CR_PARAM * ); /* cr_param */ + +typedef DAT_RETURN (DAT_API *DAT_CR_ACCEPT_FUNC)( + IN DAT_CR_HANDLE, /* cr_handle */ + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_COUNT, /* private_data_size */ + IN const DAT_PVOID ); /* private_data */ + +typedef DAT_RETURN (DAT_API *DAT_CR_REJECT_FUNC)( + IN DAT_CR_HANDLE ); + +/* For DAT-1.1 this function is defined for both uDAPL and kDAPL. + * For DAT-1.0 it was only defined for uDAPL. + */ +typedef DAT_RETURN (DAT_API *DAT_CR_HANDOFF_FUNC)( + IN DAT_CR_HANDLE, /* cr_handle */ + IN DAT_CONN_QUAL); /* handoff */ + +/* EVD Functions */ + +typedef DAT_RETURN (DAT_API *DAT_EVD_RESIZE_FUNC)( + IN DAT_EVD_HANDLE, /* evd_handle */ + IN DAT_COUNT ); /* evd_min_qlen */ + +typedef DAT_RETURN (DAT_API *DAT_EVD_POST_SE_FUNC)( + IN DAT_EVD_HANDLE, /* evd_handle */ + IN const DAT_EVENT * ); /* event */ + +typedef DAT_RETURN (DAT_API *DAT_EVD_DEQUEUE_FUNC)( + IN DAT_EVD_HANDLE, /* evd_handle */ + OUT DAT_EVENT * ); /* event */ + +typedef DAT_RETURN (DAT_API *DAT_EVD_FREE_FUNC)( + IN DAT_EVD_HANDLE ); + +/* ep functions */ + +typedef DAT_RETURN (DAT_API *DAT_EP_CREATE_FUNC)( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_PZ_HANDLE, /* pz_handle */ + IN DAT_EVD_HANDLE, /* recv_completion_evd_handle */ + IN DAT_EVD_HANDLE, /* request_completion_evd_handle */ + IN DAT_EVD_HANDLE, /* connect_evd_handle */ + IN const DAT_EP_ATTR *, /* ep_attributes */ + OUT DAT_EP_HANDLE * ); /* ep_handle */ + +typedef DAT_RETURN (DAT_API *DAT_EP_QUERY_FUNC)( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_EP_PARAM_MASK, /* ep_param_mask */ + OUT DAT_EP_PARAM * ); /* ep_param */ + +typedef DAT_RETURN (DAT_API *DAT_EP_MODIFY_FUNC)( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_EP_PARAM_MASK, /* ep_param_mask */ + IN const DAT_EP_PARAM * ); /* ep_param */ + +typedef DAT_RETURN (DAT_API *DAT_EP_CONNECT_FUNC)( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_IA_ADDRESS_PTR, /* remote_ia_address */ + IN DAT_CONN_QUAL, /* remote_conn_qual */ + IN DAT_TIMEOUT, /* timeout */ + IN DAT_COUNT, /* private_data_size */ + IN const DAT_PVOID, /* private_data */ + IN DAT_QOS, /* quality_of_service */ + IN DAT_CONNECT_FLAGS ); /* connect_flags */ + +typedef DAT_RETURN (DAT_API *DAT_EP_DUP_CONNECT_FUNC)( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_EP_HANDLE, /* ep_dup_handle */ + IN DAT_TIMEOUT, /* timeout */ + IN DAT_COUNT, /* private_data_size */ + IN const DAT_PVOID, /* private_data */ + IN DAT_QOS); /* quality_of_service */ + +typedef DAT_RETURN (DAT_API *DAT_EP_DISCONNECT_FUNC)( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_CLOSE_FLAGS ); /* close_flags */ + +typedef DAT_RETURN (DAT_API *DAT_EP_POST_SEND_FUNC)( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_COUNT, /* num_segments */ + IN DAT_LMR_TRIPLET *, /* local_iov */ + IN DAT_DTO_COOKIE, /* user_cookie */ + IN DAT_COMPLETION_FLAGS ); /* completion_flags */ + +typedef DAT_RETURN (DAT_API *DAT_EP_POST_RECV_FUNC)( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_COUNT, /* num_segments */ + IN DAT_LMR_TRIPLET *, /* local_iov */ + IN DAT_DTO_COOKIE, /* user_cookie */ + IN DAT_COMPLETION_FLAGS ); /* completion_flags */ + +typedef DAT_RETURN (DAT_API *DAT_EP_POST_RDMA_READ_FUNC)( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_COUNT, /* num_segments */ + IN DAT_LMR_TRIPLET *, /* local_iov */ + IN DAT_DTO_COOKIE, /* user_cookie */ + IN const DAT_RMR_TRIPLET *,/* remote_iov */ + IN DAT_COMPLETION_FLAGS ); /* completion_flags */ + +typedef DAT_RETURN (DAT_API *DAT_EP_POST_RDMA_WRITE_FUNC)( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_COUNT, /* num_segments */ + IN DAT_LMR_TRIPLET *, /* local_iov */ + IN DAT_DTO_COOKIE, /* user_cookie */ + IN const DAT_RMR_TRIPLET *,/* remote_iov */ + IN DAT_COMPLETION_FLAGS ); /* completion_flags */ + +typedef DAT_RETURN (DAT_API *DAT_EP_GET_STATUS_FUNC)( + IN DAT_EP_HANDLE, /* ep_handle */ + OUT DAT_EP_STATE *, /* ep_state */ + OUT DAT_BOOLEAN *, /* recv_idle */ + OUT DAT_BOOLEAN * ); /* request_idle */ + +typedef DAT_RETURN (DAT_API *DAT_EP_FREE_FUNC)( + IN DAT_EP_HANDLE); /* ep_handle */ + +typedef DAT_RETURN (DAT_API *DAT_EP_RESET_FUNC)( + IN DAT_EP_HANDLE); /* ep_handle */ + +/* LMR functions */ + +typedef DAT_RETURN (DAT_API *DAT_LMR_FREE_FUNC)( + IN DAT_LMR_HANDLE); + +/* RMR Functions */ + +typedef DAT_RETURN (DAT_API *DAT_RMR_CREATE_FUNC)( + IN DAT_PZ_HANDLE, /* pz_handle */ + OUT DAT_RMR_HANDLE *); /* rmr_handle */ + +typedef DAT_RETURN (DAT_API *DAT_RMR_QUERY_FUNC)( + IN DAT_RMR_HANDLE, /* rmr_handle */ + IN DAT_RMR_PARAM_MASK, /* rmr_param_mask */ + OUT DAT_RMR_PARAM *); /* rmr_param */ + +typedef DAT_RETURN (DAT_API *DAT_RMR_BIND_FUNC)( + IN DAT_RMR_HANDLE, /* rmr_handle */ + IN const DAT_LMR_TRIPLET *,/* lmr_triplet */ + IN DAT_MEM_PRIV_FLAGS, /* mem_priv */ + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_RMR_COOKIE, /* user_cookie */ + IN DAT_COMPLETION_FLAGS, /* completion_flags */ + OUT DAT_RMR_CONTEXT * ); /* context */ + +typedef DAT_RETURN (DAT_API *DAT_RMR_FREE_FUNC)( + IN DAT_RMR_HANDLE); + +/* PSP Functions */ + +typedef DAT_RETURN (DAT_API *DAT_PSP_CREATE_FUNC)( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_CONN_QUAL, /* conn_qual */ + IN DAT_EVD_HANDLE, /* evd_handle */ + IN DAT_PSP_FLAGS, /* psp_flags */ + OUT DAT_PSP_HANDLE * ); /* psp_handle */ + +typedef DAT_RETURN (DAT_API *DAT_PSP_CREATE_ANY_FUNC)( + IN DAT_IA_HANDLE, /* ia_handle */ + OUT DAT_CONN_QUAL *, /* conn_qual */ + IN DAT_EVD_HANDLE, /* evd_handle */ + IN DAT_PSP_FLAGS, /* psp_flags */ + OUT DAT_PSP_HANDLE * ); /* psp_handle */ + +typedef DAT_RETURN (DAT_API *DAT_PSP_QUERY_FUNC)( + IN DAT_PSP_HANDLE, + IN DAT_PSP_PARAM_MASK, + OUT DAT_PSP_PARAM * ); + +typedef DAT_RETURN (DAT_API *DAT_PSP_FREE_FUNC)( + IN DAT_PSP_HANDLE ); /* psp_handle */ + +/* RSP Functions */ + +typedef DAT_RETURN (DAT_API *DAT_RSP_CREATE_FUNC)( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_CONN_QUAL, /* conn_qual */ + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_EVD_HANDLE, /* evd_handle */ + OUT DAT_RSP_HANDLE * ); /* rsp_handle */ + +typedef DAT_RETURN (DAT_API *DAT_RSP_QUERY_FUNC) ( + IN DAT_RSP_HANDLE, + IN DAT_RSP_PARAM_MASK, + OUT DAT_RSP_PARAM * ); + +typedef DAT_RETURN (DAT_API *DAT_RSP_FREE_FUNC)( + IN DAT_RSP_HANDLE ); /* rsp_handle */ + +/* PZ Functions */ + +typedef DAT_RETURN (DAT_API *DAT_PZ_CREATE_FUNC)( + IN DAT_IA_HANDLE, /* ia_handle */ + OUT DAT_PZ_HANDLE * ); /* pz_handle */ + +typedef DAT_RETURN (DAT_API *DAT_PZ_QUERY_FUNC)( + IN DAT_PZ_HANDLE, /* pz_handle */ + IN DAT_PZ_PARAM_MASK, /* pz_param_mask */ + OUT DAT_PZ_PARAM *); /* pz_param */ + +typedef DAT_RETURN (DAT_API *DAT_PZ_FREE_FUNC)( + IN DAT_PZ_HANDLE ); /* pz_handle */ + +/* + * DAT registry functions. + * + * Note the dat_ia_open and dat_ia_close functions are linked to + * registration code which "redirects" to the appropriate provider. + */ + +DAT_EXPORT DAT_RETURN DAT_API dat_ia_openv ( + IN const DAT_NAME_PTR, /* device name */ + IN DAT_COUNT, /* async_evd_qlen */ + INOUT DAT_EVD_HANDLE *, /* async_evd_handle */ + OUT DAT_IA_HANDLE *, /* ia_handle */ + IN DAT_UINT32, /* dat major version number */ + IN DAT_UINT32, /* dat minor version number */ + IN DAT_BOOLEAN); /* dat thread safety */ + +#define dat_ia_open(name,qlen,async_evd,ia) \ + dat_ia_openv((name), (qlen), (async_evd), (ia), \ + DAT_VERSION_MAJOR, DAT_VERSION_MINOR, \ + DAT_THREADSAFE) + +DAT_EXPORT DAT_RETURN DAT_API dat_ia_close ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_CLOSE_FLAGS ); /* close_flags */ + +DAT_EXPORT DAT_RETURN DAT_API dat_registry_list_providers( + IN DAT_COUNT, /* max_to_return */ + OUT DAT_COUNT *, /* entries_returned */ + OUT DAT_PROVIDER_INFO *(dat_provider_list[]) ); /* dat_provider_list */ + +typedef DAT_RETURN ( DAT_API *DAT_REGISTRY_LIST_PROVIDERS_FUNC)( + IN DAT_COUNT, /* max_to_return */ + OUT DAT_COUNT *, /* entries_returned */ + OUT DAT_PROVIDER_INFO *(dat_provider_list[])); /* dat_provider_list */ + +/* + * DAT error functions. + */ +DAT_EXPORT DAT_RETURN DAT_API dat_strerror ( + IN DAT_RETURN, /* dat function return */ + OUT const char ** , /* major message string */ + OUT const char ** ); /* minor message string */ + +#ifdef __cplusplus +} +#endif + +#endif /* _DAT_H_ */ + diff --git a/branches/WOF2-3/ulp/dapl/dat/include/dat/dat_error.h b/branches/WOF2-3/ulp/dapl/dat/include/dat/dat_error.h new file mode 100644 index 00000000..67e46f09 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dat/include/dat/dat_error.h @@ -0,0 +1,333 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/*********************************************************** + * + * HEADER: dat_error.h + * + * PURPOSE: DAT return codes + * + * Description: Header file for "uDAPL: User Direct Access Programming + * Library, Version: 1.1" + * + * Mapping rules: Major error codes occupies upper 16 of a 32 bit field. + * detailed error code occupies lower 16 bits. + * + * + *********************************************************/ + +#ifndef _DAT_ERROR_H_ +#define _DAT_ERROR_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* + * + * All return codes are actually a 3-way tuple: + * + * type: CLASS DAT_TYPE_STATUS DAT_SUBTYPE_STATUS + * bits: 31-30 29-16 15-0 + * + * +----------------------------------------------------------------------+ + * |3130 | 29282726252423222120191817 | 1615141312111009080706054003020100| + * |CLAS | DAT_TYPE_STATUS | SUBTYPE_STATUS | + * +----------------------------------------------------------------------+ + */ + +/* + * Class Bits + */ +#define DAT_CLASS_ERROR 0x80000000 +#define DAT_CLASS_WARNING 0x40000000 +#define DAT_CLASS_SUCCESS 0x00000000 + +/* + * DAT Error bits + */ +#define DAT_TYPE_MASK 0x3fff0000 /* mask for DAT_TYPE_STATUS bits */ +#define DAT_SUBTYPE_MASK 0x0000FFFF /* mask for DAT_SUBTYPE_STATUS bits */ + +/* + * Determining the success of an operation is best done with a macro, + * each of these returns a boolean value. + */ +#define DAT_IS_SUCCESS(status) ((int)(status) >= 0) +#define DAT_IS_WARNING(status) ((DAT_UINT32)(status) & DAT_CLASS_ WARNING) + +#define DAT_GET_TYPE(status) ((DAT_UINT32)(status) & DAT_TYPE_MASK) +#define DAT_GET_SUBTYPE(status) ((DAT_UINT32)(status) & DAT_SUBTYPE_MASK) + +/* + * DAT return types. The ERROR bit is enabled for these definitions + */ +typedef enum dat_return + { + /* The operation was successful. */ + DAT_SUCCESS = 0x000000, + + /* The operation was aborted because IA was closed or EVD was * + * destroyed. */ + DAT_ABORT = 0x00010000, + + /* The specified Connection Qualifier was in use. */ + DAT_CONN_QUAL_IN_USE = 0x00020000, + + /* The operation failed due to resource limitations. */ + DAT_INSUFFICIENT_RESOURCES = 0x00030000, + + /* Provider internal error. This error can be returned by any * + * operation when the Provider have detected an internal error. * + * This error does no mask any error causes by Consumer. */ + DAT_INTERNAL_ERROR = 0x00040000, + + /* One of the DAT handles was invalid. */ + DAT_INVALID_HANDLE = 0x00050000, + + /* One of the parameters was invalid. */ + DAT_INVALID_PARAMETER = 0x00060000, + + /* One of the parameters was invalid for this operation. There * + * are Event Streams associated with the Event Dispatcher feeding * + * it. */ + DAT_INVALID_STATE = 0x00070000, + + /* The size of the receiving buffer is too small for sending * + * buffer data. The size of the local buffer is too small for * + * the data of the remote buffer. */ + DAT_LENGTH_ERROR = 0x00080000, + + /* The requested Model was not supported by the Provider. */ + DAT_MODEL_NOT_SUPPORTED = 0x00090000, + + /* The specified IA name was not found in the list of registered * + * Providers. */ + + DAT_PROVIDER_NOT_FOUND = 0x000A0000, + + /* Protection violation for local or remote memory * + * access. Protection Zone mismatch between an LMR of one of the * + * local_iov segments and the local Endpoint. */ + DAT_PRIVILEGES_VIOLATION = 0x000B0000, + + /* Privileges violation for local or re-mote memory access. One * + * of the LMRs used in local_iov was either invalid or did not * + * have the local read privileges. */ + DAT_PROTECTION_VIOLATION = 0x000C0000, + + /* The operation timed out without a notification. */ + DAT_QUEUE_EMPTY = 0x000D0000, + + /* The Event Dispatcher queue is full. */ + DAT_QUEUE_FULL = 0x000E0000, + + /* The operation timed out. UDAPL ONLY */ + DAT_TIMEOUT_EXPIRED = 0x000F0000, + + /* The provider name was already registered */ + DAT_PROVIDER_ALREADY_REGISTERED = 0x00100000, + + /* The provider is "in-use" and cannot be closed at this time */ + DAT_PROVIDER_IN_USE = 0x00110000, + + /* The requested remote address is not valid or not reachable */ + DAT_INVALID_ADDRESS = 0x00120000, + + /* [Unix only] dat_evd_wait or dat_cno_wait has been interrupted. */ + DAT_INTERRUPTED_CALL = 0x00130000, + + /* No Connection Qualifiers are available */ + DAT_CONN_QUAL_UNAVAILABLE = 0x00140000, + DAT_NOT_IMPLEMENTED = 0x0FFF0000 + + } DAT_RETURN; + + +/* + * DAT_RETURN_SUBTYPE + * + * The 16 bits of subtype information allow for 256 different + * values. + */ + +typedef enum dat_return_subtype + { + /* First element is no subtype */ + DAT_NO_SUBTYPE, + /* ABORT sub types */ + /* call was interrupted by a signal, or otherwise */ + DAT_SUB_INTERRUPTED, + + /* DAT_CONN_QUAL_IN_USE has no subtypes */ + + /* INSUFFICIENT_RESOURCES subtypes */ + DAT_RESOURCE_MEMORY, + DAT_RESOURCE_DEVICE, + DAT_RESOURCE_TEP, /* transport endpoint, e.g. QP */ + DAT_RESOURCE_TEVD, /* transport EVD, e.g. CQ */ + DAT_RESOURCE_PROTECTION_DOMAIN, + DAT_RESOURCE_MEMORY_REGION, /* HCA memory for LMR or RMR */ + DAT_RESOURCE_ERROR_HANDLER, + DAT_RESOURCE_CREDITS, /* e.g outstanding RDMA Read credit as target */ + + /* DAT_INTERNAL_ERROR has no subtypes */ + + /* INVALID_HANDLE subtypes */ + DAT_INVALID_HANDLE_IA, + DAT_INVALID_HANDLE_EP, + DAT_INVALID_HANDLE_LMR, + DAT_INVALID_HANDLE_RMR, + DAT_INVALID_HANDLE_PZ, + DAT_INVALID_HANDLE_PSP, + DAT_INVALID_HANDLE_RSP, + DAT_INVALID_HANDLE_CR, + DAT_INVALID_HANDLE_CNO, + DAT_INVALID_HANDLE_EVD_CR, + DAT_INVALID_HANDLE_EVD_REQUEST, + DAT_INVALID_HANDLE_EVD_RECV, + DAT_INVALID_HANDLE_EVD_CONN, + DAT_INVALID_HANDLE_EVD_ASYNC, + + /* DAT_INVALID_PARAMETER subtypes */ + DAT_INVALID_ARG1, + DAT_INVALID_ARG2, + DAT_INVALID_ARG3, + DAT_INVALID_ARG4, + DAT_INVALID_ARG5, + DAT_INVALID_ARG6, + DAT_INVALID_ARG7, + DAT_INVALID_ARG8, + DAT_INVALID_ARG9, + DAT_INVALID_ARG10, + + /* DAT_INVALID_EP_STATE subtypes */ + DAT_INVALID_STATE_EP_UNCONNECTED, + DAT_INVALID_STATE_EP_ACTCONNPENDING, + DAT_INVALID_STATE_EP_PASSCONNPENDING, + DAT_INVALID_STATE_EP_TENTCONNPENDING, + DAT_INVALID_STATE_EP_CONNECTED, + DAT_INVALID_STATE_EP_DISCONNECTED, + DAT_INVALID_STATE_EP_RESERVED, + DAT_INVALID_STATE_EP_COMPLPENDING, + DAT_INVALID_STATE_EP_DISCPENDING, + DAT_INVALID_STATE_EP_PROVIDERCONTROL, + DAT_INVALID_STATE_EP_NOTREADY, + + DAT_INVALID_STATE_CNO_IN_USE, + DAT_INVALID_STATE_CNO_DEAD, + + /* EVD states. Enabled/Disabled, Waitable/Unwaitable, * + * and Notify/Solicited/Threshold are 3 orthogonal * + * bands of EVD state.The Threshold one is uDAPL specific. */ + DAT_INVALID_STATE_EVD_OPEN, + /* EVD can be either in enabled or disabled but not both * + * or neither at the same time */ + DAT_INVALID_STATE_EVD_ENABLED, + DAT_INVALID_STATE_EVD_DISABLED, + /* EVD can be either in waitable or unwaitable but not * + * both or neither at the same time */ + DAT_INVALID_STATE_EVD_WAITABLE, + DAT_INVALID_STATE_EVD_UNWAITABLE, + /* Do not release an EVD if it is in use */ + DAT_INVALID_STATE_EVD_IN_USE, + + /* EVD can be either in notify or solicited or threshold * + * but not any pair, or all, or none at the same time. * + * The threshold one is for uDAPL only */ + DAT_INVALID_STATE_EVD_CONFIG_NOTIFY, + DAT_INVALID_STATE_EVD_CONFIG_SOLICITED, + DAT_INVALID_STATE_EVD_CONFIG_THRESHOLD, + DAT_INVALID_STATE_EVD_WAITER, + DAT_INVALID_STATE_EVD_ASYNC, /* Async EVD required */ + DAT_INVALID_STATE_IA_IN_USE, + DAT_INVALID_STATE_LMR_IN_USE, + DAT_INVALID_STATE_LMR_FREE, + DAT_INVALID_STATE_PZ_IN_USE, + DAT_INVALID_STATE_PZ_FREE, + + /* DAT_LENGTH_ERROR has no subtypes */ + /* DAT_MODEL_NOT_SUPPORTED has no subtypes */ + + /* DAT_PROVIDER_NOT_FOUND has no subtypes */ + + /* DAT_PRIVILEGES_VIOLATION subtypes */ + DAT_PRIVILEGES_READ, + DAT_PRIVILEGES_WRITE, + DAT_PRIVILEGES_RDMA_READ, + DAT_PRIVILEGES_RDMA_WRITE, + + /* DAT_PROTECTION_VIOLATION subtypes */ + DAT_PROTECTION_READ, + DAT_PROTECTION_WRITE, + DAT_PROTECTION_RDMA_READ, + DAT_PROTECTION_RDMA_WRITE, + + /* DAT_QUEUE_EMPTY has no subtypes */ + /* DAT_QUEUE_FULL has no subtypes */ + /* DAT_TIMEOUT_EXPIRED has no subtypes */ + /* DAT_PROVIDER_ALREADY_REGISTERED has no subtypes */ + /* DAT_PROVIDER_IN_USE has no subtypes */ + + /* DAT_INVALID_ADDRESS subtypes */ + /* Unsupported addresses - those that are not Malformed, * + * but are incorrect for use in DAT (regardless of local * + * routing capabilities): IPv6 Multicast Addresses (ff/8) * + * IPv4 Broadcast/Multicast Addresses */ + DAT_INVALID_ADDRESS_UNSUPPORTED, + /* Unreachable addresses - A Provider may know that certain * + * addresses are unreachable immediately. One examples would * + * be an IPv6 addresses on an IPv4-only system. This may also * + * be returned if it is known that there is no route to the * + * host. A Provider is not obligated to check for this + * condition. */ + DAT_INVALID_ADDRESS_UNREACHABLE, + /* Malformed addresses -- these cannot be valid in any context.* + * Those listed in RFC1884 section 2.3 as "Reserved" or + * "Unassigned". */ + DAT_INVALID_ADDRESS_MALFORMED, + + /* DAT_INTERRUPTED_CALL */ + + /* DAT_PROVIDER_NOT_FOUND subtypes. Erratta to the 1.1 spec */ + DAT_NAME_NOT_REGISTERED, + DAT_MAJOR_NOT_FOUND, + DAT_MINOR_NOT_FOUND, + DAT_THREAD_SAFETY_NOT_FOUND, + + + } DAT_RETURN_SUBTYPE; + +#ifdef __cplusplus +} +#endif + +#endif /* _DAT_ERROR_H_ */ + + + + diff --git a/branches/WOF2-3/ulp/dapl/dat/include/dat/dat_platform_specific.h b/branches/WOF2-3/ulp/dapl/dat/include/dat/dat_platform_specific.h new file mode 100644 index 00000000..3ce32fa8 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dat/include/dat/dat_platform_specific.h @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dat_platform_specific.h + * + * PURPOSE: defines Platform specific types. + * + * Description: Header file for "uDAPL: User Direct Access Programming + * Library, Version: 1.1" + * + * Mapping rules: + * + **********************************************************************/ + +#ifndef _DAT_PLATFORM_SPECIFIC_H_ +#define _DAT_PLATFORM_SPECIFIC_H_ + +/* OS, processor, compiler type definitions. Add OS's as needed. */ + +/* + * This captures the alignment for the bus transfer from the HCA/IB chip + * to the main memory. + */ +#ifndef DAT_OPTIMAL_ALIGNMENT +#define DAT_OPTIMAL_ALIGNMENT 256 /* Performance optimal alignment */ +#endif /* DAT_OPTIMAL_ALIGNMENT */ + +/* Assume all O/Ss use sockaddr, for address family: IPv4 == AF_INET, + * IPv6 == AF_INET6. Use of "namelen" field indicated. + * + * The Interface Adaptor Address names an Interface Adaptor local or + * remote that is used for connection management and Name + * Service. The format of the dat_ia_address_ptr follows the normal + * socket programming practice of struct sockaddr *. DAT supports both + * IPv4 and IPv6 address families. Allocation and initialization of + * DAT IA address structures must follow normal Sockets programming + * procedures. The underlying type of the DAT IA address is the native + * struct sockaddr for each target operating system. In all cases, + * storage appropriate for the address family in use by the target + * Provider must be allocated. For instance, when IPv6 addressing is + * in use, this should be allocated as struct sockaddr_net6 . The + * sockaddr sa_family and, if present, sa_len fields must be + * initialized appropriately, as well as the address information. + * When passed across the DAPL API this storage is cast to the + * DAT_IA_ADDRESS_PTR type. It is the responsibility of the callee to + * verify that the sockaddr contains valid data for the requested + * operation. It is always the responsibility of the caller to manage + * the storage. + * + * Code example for Linux: + * + * #include + * #include + * #include + * #include + * + * struct sockaddr_in6 addr; + * DAT_IA_ADDRESS_PTR ia_addr; + * int status, i; + * + * // Note: linux pton requires explicit encoding of IPv4 in IPv6 + * + * addr.sin6_family = AF_INET6; + * if (inet_pton(AF_INET6, "0:0:0:0:0:FFFF:192.168.0.1", + * &addr.sin6_addr) <= 0) + * return(-1); // Bad address or no address family support + * + * // initialize other necessary fields such as port, flow, etc + * + * ia_addr = (DAT_IA_ADDRESS_PTR) &addr; + * dat_ep_connect(ep_handle, ia_addr, conn_qual, timeout, 0, NULL, + * qos, DAT_CONNECT_DEFAULT_FLAG); + * + */ + +#if defined(sun) || defined(__sun) || defined (_sun_) || defined (__solaris__) /* Solaris */ +#include + +typedef uint32_t DAT_UINT32; /* Unsigned host order, 32 bits */ +typedef uint64_t DAT_UINT64; /* unsigned host order, 64 bits */ +typedef unsigned long long DAT_UVERYLONG; /* unsigned longest native to compiler */ + +typedef void * DAT_PVOID; +typedef int DAT_COUNT; + +#include +#include +typedef struct sockaddr DAT_SOCK_ADDR; /* Socket address header native to OS */ +typedef struct sockaddr_in6 DAT_SOCK_ADDR6; /* Socket address header native to OS */ + +#define DAT_AF_INET AF_INET +#define DAT_AF_INET6 AF_INET6 + +#define DAT_API +#define DAT_EXPORT extern + +/* Solaris */ + +#elif defined(__linux__) /* Linux */ +#include + +typedef u_int32_t DAT_UINT32; /* unsigned host order, 32 bits */ +typedef u_int64_t DAT_UINT64; /* unsigned host order, 64 bits */ +typedef unsigned long long DAT_UVERYLONG; /* unsigned longest native to compiler */ + +typedef void * DAT_PVOID; +typedef int DAT_COUNT; + +#include +typedef struct sockaddr DAT_SOCK_ADDR; /* Socket address header native to OS */ +typedef struct sockaddr_in6 DAT_SOCK_ADDR6; /* Socket address header native to OS */ + +#define DAT_AF_INET AF_INET +#define DAT_AF_INET6 AF_INET6 + +#define DAT_API +#define DAT_EXPORT extern + +/* Linux */ + +#elif defined(_MSC_VER) || defined(_WIN32) || defined(_WIN64) +/* NT. MSC compiler, Win32 platform */ +#include +typedef unsigned __int32 DAT_UINT32; /* Unsigned host order, 32 bits */ +typedef unsigned __int64 DAT_UINT64; /* unsigned host order, 64 bits */ +typedef unsigned __int16 DAT_UINT16; +typedef unsigned __int8 DAT_UINT8; +typedef unsigned __int3264 __w64 DAT_UVERYLONG; /* unsigned longest native to compiler */ + +typedef void * DAT_PVOID; +typedef long DAT_COUNT; + +typedef struct sockaddr DAT_SOCK_ADDR; /* Socket address header native to OS */ +typedef struct sockaddr_in6 DAT_SOCK_ADDR6; /* Socket address header native to OS */ + +#define DAT_AF_INET AF_INET +#define DAT_AF_INET6 AF_INET6 + +#ifdef EXPORT_DAT_SYMBOLS +#define DAT_EXPORT __declspec( dllexport ) +#else +#define DAT_EXPORT __declspec( dllimport ) +#endif + +#define DAT_API __stdcall + +/* Windoze */ + +#else +#error dat_platform_specific.h : OS type not defined +#endif + +#ifndef IN +#define IN +#endif +#ifndef OUT +#define OUT +#endif +#ifndef INOUT +#define INOUT +#endif + +#endif /* _DAT_PLATFORM_SPECIFIC_H_ */ + + + diff --git a/branches/WOF2-3/ulp/dapl/dat/include/dat/dat_redirection.h b/branches/WOF2-3/ulp/dapl/dat/include/dat/dat_redirection.h new file mode 100644 index 00000000..7324a57c --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dat/include/dat/dat_redirection.h @@ -0,0 +1,333 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dat_redirection.h + * + * PURPOSE: Defines the common redirection macros + * + * Description: Header file for "uDAPL: User Direct Access Programming + * Library, Version: 1.1" + * + * Mapping rules: + * All global symbols are prepended with "DAT_" or "dat_" + * All DAT objects have an 'api' tag which, such as 'ep' or 'lmr' + * The method table is in the provider definition structure. + * + * + * + **********************************************************************/ + +#ifndef _DAT_REDIRECTION_H_ +#define _DAT_REDIRECTION_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +typedef struct dat_provider DAT_PROVIDER; + +#ifndef DAT_HANDLE_TO_PROVIDER + +/* A utility macro to fetch the Provider Library for any object + * + * An alternate version could be defined for single library systems. + * it would look something like: + * extern const struct dat_ia my_single_ia_provider; + * #define DAT_HANDLE_TO_PROVIDER(ignore) &my_single_ia_provider + * + * This would allow a good compiler to avoid indirection overhead when + * making function calls. + */ + +#define DAT_HANDLE_TO_PROVIDER(handle) (*(DAT_PROVIDER **)(handle)) +#endif + +#define dat_ia_query(ia,evd,ia_msk,ia_ptr,p_msk,p_ptr) \ + (*DAT_HANDLE_TO_PROVIDER(ia)->ia_query_func)(\ + (ia),\ + (evd),\ + (ia_msk),\ + (ia_ptr),\ + (p_msk),\ + (p_ptr)) + +#define dat_set_consumer_context(handle,context) \ + (*DAT_HANDLE_TO_PROVIDER(handle)->set_consumer_context_func)(\ + (handle),\ + (context)) + +#define dat_get_consumer_context(handle,context) \ + (*DAT_HANDLE_TO_PROVIDER(handle)->get_consumer_context_func)(\ + (handle),\ + (context)) + +#define dat_get_handle_type(handle,handle_type) \ + (*DAT_HANDLE_TO_PROVIDER(handle)->get_handle_type_func)(\ + (handle),\ + (handle_type)) + +#define dat_cr_query(cr,mask,param) \ + (*DAT_HANDLE_TO_PROVIDER(cr)->cr_query_func)(\ + (cr),\ + (mask),\ + (param)) + +#define dat_cr_accept(cr,ep,size,pdata) \ + (*DAT_HANDLE_TO_PROVIDER(cr)->cr_accept_func)(\ + (cr),\ + (ep),\ + (size),\ + (pdata)) + +#define dat_cr_reject(cr) \ + (*DAT_HANDLE_TO_PROVIDER(cr)->cr_reject_func)(\ + (cr)) + +#define dat_evd_query(evd,mask,param) \ + (*DAT_HANDLE_TO_PROVIDER(evd)->evd_query_func)(\ + (evd),\ + (mask),\ + (param)) + +#define dat_evd_resize(evd,qsize) \ + (*DAT_HANDLE_TO_PROVIDER(evd)->evd_resize_func)(\ + (evd),\ + (qsize)) + +#define dat_evd_post_se(evd,event) \ + (*DAT_HANDLE_TO_PROVIDER(evd)->evd_post_se_func)(\ + (evd),\ + (event)) + +#define dat_evd_dequeue(evd,event) \ + (*DAT_HANDLE_TO_PROVIDER(evd)->evd_dequeue_func)(\ + (evd),\ + (event)) + +#define dat_evd_free(evd)\ + (*DAT_HANDLE_TO_PROVIDER(evd)->evd_free_func)(\ + (evd)) + +#define dat_ep_create(ia,pz,in_evd,out_evd,connect_evd,attr,ep) \ + (*DAT_HANDLE_TO_PROVIDER(ia)->ep_create_func)(\ + (ia),\ + (pz),\ + (in_evd),\ + (out_evd),\ + (connect_evd),\ + (attr),\ + (ep)) + +#define dat_ep_query(ep,mask,param) \ + (*DAT_HANDLE_TO_PROVIDER(ep)->ep_query_func)(\ + (ep),\ + (mask),\ + (param)) + +#define dat_ep_modify(ep,mask,param) \ + (*DAT_HANDLE_TO_PROVIDER(ep)->ep_modify_func)(\ + (ep),\ + (mask),\ + (param)) + +#define dat_ep_connect(ep,ia_addr,conn_qual,timeout,psize,pdata,qos,flags) \ + (*DAT_HANDLE_TO_PROVIDER(ep)->ep_connect_func)(\ + (ep),\ + (ia_addr),\ + (conn_qual),\ + (timeout),\ + (psize),\ + (pdata),\ + (qos),\ + (flags)) + +#define dat_ep_dup_connect(ep,dup,timeout,psize,pdata,qos) \ + (*DAT_HANDLE_TO_PROVIDER(ep)->ep_dup_connect_func)(\ + (ep),\ + (dup),\ + (timeout),\ + (psize),\ + (pdata),\ + (qos)) + +#define dat_ep_disconnect(ep,flags) \ + (*DAT_HANDLE_TO_PROVIDER(ep)->ep_disconnect_func)(\ + (ep),\ + (flags)) + +#define dat_ep_post_send(ep,size,lbuf,cookie,flags) \ + (*DAT_HANDLE_TO_PROVIDER(ep)->ep_post_send_func)(\ + (ep),\ + (size),\ + (lbuf),\ + (cookie),\ + (flags)) + +#define dat_ep_post_recv(ep,size,lbuf,cookie,flags) \ + (*DAT_HANDLE_TO_PROVIDER(ep)->ep_post_recv_func)(\ + (ep),\ + (size),\ + (lbuf),\ + (cookie),\ + (flags)) + +#define dat_ep_post_rdma_read(ep,size,lbuf,cookie,rbuf,flags) \ + (*DAT_HANDLE_TO_PROVIDER(ep)->ep_post_rdma_read_func)(\ + (ep),\ + (size),\ + (lbuf),\ + (cookie),\ + (rbuf),\ + (flags)) + +#define dat_ep_post_rdma_write(ep,size,lbuf,cookie,rbuf,flags) \ + (*DAT_HANDLE_TO_PROVIDER(ep)->ep_post_rdma_write_func)(\ + (ep),\ + (size),\ + (lbuf),\ + (cookie),\ + (rbuf),\ + (flags)) + +#define dat_ep_get_status(ep,ep_state,recv_idle,request_idle) \ + (*DAT_HANDLE_TO_PROVIDER(ep)->ep_get_status_func)(\ + (ep),\ + (ep_state),\ + (recv_idle),\ + (request_idle)) + +#define dat_ep_free(ep)\ + (*DAT_HANDLE_TO_PROVIDER(ep)->ep_free_func)(\ + (ep)) + +#define dat_ep_reset(ep)\ + (*DAT_HANDLE_TO_PROVIDER(ep)->ep_reset_func)(\ + (ep)) + +#define dat_lmr_query(lmr,mask,param)\ + (*DAT_HANDLE_TO_PROVIDER(lmr)->lmr_query_func)(\ + (lmr),\ + (mask),\ + (param)) + +#define dat_lmr_free(lmr)\ + (*DAT_HANDLE_TO_PROVIDER(lmr)->lmr_free_func)(\ + (lmr)) + +#define dat_rmr_create(pz,rmr) \ + (*DAT_HANDLE_TO_PROVIDER(pz)->rmr_create_func)(\ + (pz),\ + (rmr)) + +#define dat_rmr_query(rmr,mask,param) \ + (*DAT_HANDLE_TO_PROVIDER(rmr)->rmr_query_func)(\ + (rmr),\ + (mask),\ + (param)) + +#define dat_rmr_bind(rmr,lmr,mem_priv,ep,cookie,flags,context) \ + (*DAT_HANDLE_TO_PROVIDER(rmr)->rmr_bind_func)(\ + (rmr),\ + (lmr),\ + (mem_priv),\ + (ep),\ + (cookie),\ + (flags),\ + (context)) + +#define dat_rmr_free(rmr)\ + (*DAT_HANDLE_TO_PROVIDER(rmr)->rmr_free_func)(\ + (rmr)) + +#define dat_psp_create(ia,conn_qual,evd,flags,handle) \ + (*DAT_HANDLE_TO_PROVIDER(ia)->psp_create_func)(\ + (ia),\ + (conn_qual),\ + (evd),\ + (flags),\ + (handle)) + +#define dat_psp_create_any(ia,conn_qual,evd,flags,handle) \ + (*DAT_HANDLE_TO_PROVIDER(ia)->psp_create_any_func)(\ + (ia),\ + (conn_qual),\ + (evd),\ + (flags),\ + (handle)) + +#define dat_psp_query(psp,mask,param) \ + (*DAT_HANDLE_TO_PROVIDER(psp)->psp_query_func)(\ + (psp),\ + (mask),\ + (param)) + +#define dat_psp_free(psp)\ + (*DAT_HANDLE_TO_PROVIDER(psp)->psp_free_func)(\ + (psp)) + +#define dat_rsp_create(ia,conn_qual,ep,evd,handle) \ + (*DAT_HANDLE_TO_PROVIDER(ia)->rsp_create_func)(\ + (ia),\ + (conn_qual),\ + (ep),\ + (evd),\ + (handle)) + +#define dat_rsp_query(rsp,mask,param) \ + (*DAT_HANDLE_TO_PROVIDER(rsp)->rsp_query_func)(\ + (rsp),\ + (mask),\ + (param)) + +#define dat_rsp_free(rsp)\ + (*DAT_HANDLE_TO_PROVIDER(rsp)->rsp_free_func)(\ + (rsp)) + +#define dat_pz_create(ia,pz) \ + (*DAT_HANDLE_TO_PROVIDER(ia)->pz_create_func)(\ + (ia),\ + (pz)) + +#define dat_pz_query(pz,mask,param) \ + (*DAT_HANDLE_TO_PROVIDER(pz)->pz_query_func)(\ + (pz),\ + (mask),\ + (param)) + +#define dat_pz_free(pz) \ + (*DAT_HANDLE_TO_PROVIDER(pz)->pz_free_func)(\ + (pz)) + +#ifdef __cplusplus +} +#endif + +#endif /* _DAT_REDIRECTION_H_ */ + + diff --git a/branches/WOF2-3/ulp/dapl/dat/include/dat/dat_registry.h b/branches/WOF2-3/ulp/dapl/dat/include/dat/dat_registry.h new file mode 100644 index 00000000..c0b20384 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dat/include/dat/dat_registry.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dat_registry.h + * + * PURPOSE: DAT registration API signatures + * + * Description: Contains registration external reference signatures for + * dat registry functions. This file is *only* included by + * providers, not consumers. + * + * Header file for "uDAPL: User Direct Access Programming + * Library, Version: 1.1" + + * + * Mapping rules: + * All global symbols are prepended with "DAT_" or "dat_" + * All DAT objects have an 'api' tag which, such as 'ep' or 'lmr' + * The method table is in the provider definition structure. + * + * + * + **********************************************************************/ + +#ifndef _DAT_REGISTRY_H_ +#define _DAT_REGISTRY_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* + * dat registration API. + * + * Technically the dat_ia_open is part of the registration API. This + * is so the registration module can map the device name to a provider + * structure and then call the provider dat_ia_open function. + * dat_is_close is also part of the registration API so that the + * registration code can be aware when an ia is no longer in use. + * + * + */ + +DAT_EXPORT DAT_RETURN DAT_API dat_registry_add_provider( + IN DAT_PROVIDER*, /* provider */ + IN const DAT_PROVIDER_INFO* ); /* provider info */ + +DAT_EXPORT DAT_RETURN DAT_API dat_registry_remove_provider( + IN DAT_PROVIDER*, /* provider */ + IN const DAT_PROVIDER_INFO* ); /* provider info */ + +/* + * Provider initialization APIs. + * + * Providers that support being automatically loaded by the Registry must + * implement these APIs and export them as public symbols. + */ + +#define DAT_PROVIDER_INIT_FUNC_NAME dat_provider_init +#define DAT_PROVIDER_FINI_FUNC_NAME dat_provider_fini + +#define DAT_PROVIDER_INIT_FUNC_STR "dat_provider_init" +#define DAT_PROVIDER_FINI_FUNC_STR "dat_provider_fini" + +typedef void (DAT_API *DAT_PROVIDER_INIT_FUNC)( + IN const DAT_PROVIDER_INFO *, + IN const char *); /* instance data */ + +typedef void (DAT_API *DAT_PROVIDER_FINI_FUNC) ( + IN const DAT_PROVIDER_INFO *); + +#ifdef __cplusplus +} +#endif + +#endif /* _DAT_REGISTRY_H_ */ + diff --git a/branches/WOF2-3/ulp/dapl/dat/include/dat/dat_vendor_specific.h b/branches/WOF2-3/ulp/dapl/dat/include/dat/dat_vendor_specific.h new file mode 100644 index 00000000..81e6d100 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dat/include/dat/dat_vendor_specific.h @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dat_vendor_specific.h + * + * PURPOSE: + * + * Description: Header file for "uDAPL: User Direct Access Programming + * Library, Version: 1.1" + * + * Mapping rules: + * All global symbols are prepended with "DAT_" or "dat_" + * All DAT objects have an 'api' tag which, such as 'ep' or 'lmr' + * The method table is in the provider definition structure. + * + * + **********************************************************************/ + +#ifndef _DAT_VENDOR_SPECIFIC_H_ +#define _DAT_VENDOR_SPECIFIC_H_ + + +/* General Interface Adapter attributes. These apply to both udat and kdat. */ + +/* To support backwards compatibility for DAPL-1.0 */ +#define max_rdma_read_per_ep max_rdma_read_per_ep_in +#define DAT_IA_FIELD_IA_MAX_DTO_PER_OP DAT_IA_FIELD_IA_ MAX_DTO_PER_EP_IN + +#ifdef __cplusplus +extern "C" +{ +#endif + +#if defined(__ia64__) || defined(_M_IA64) +#define _ALIGN8 __declspec(align(8)) +#else +#define _ALIGN8 +#endif + +typedef _ALIGN8 struct dat_ia_attr + { + char adapter_name[DAT_NAME_MAX_LENGTH]; + char vendor_name[DAT_NAME_MAX_LENGTH]; + DAT_UINT32 hardware_version_major; + DAT_UINT32 hardware_version_minor; + DAT_UINT32 firmware_version_major; + DAT_UINT32 firmware_version_minor; + DAT_IA_ADDRESS_PTR ia_address_ptr; + DAT_COUNT max_eps; + DAT_COUNT max_dto_per_ep; + DAT_COUNT max_rdma_read_per_ep_in; + DAT_COUNT max_rdma_read_per_ep_out; + DAT_COUNT max_evds; + DAT_COUNT max_evd_qlen; + DAT_COUNT max_iov_segments_per_dto; + DAT_COUNT max_lmrs; + DAT_VLEN max_lmr_block_size; + DAT_VADDR max_lmr_virtual_address; + DAT_COUNT max_pzs; + DAT_VLEN max_mtu_size; + DAT_VLEN max_rdma_size; + DAT_COUNT max_rmrs; + DAT_VADDR max_rmr_target_address; + DAT_COUNT num_transport_attr; + DAT_NAMED_ATTR *transport_attr; + DAT_COUNT num_vendor_attr; + DAT_NAMED_ATTR *vendor_attr; + } DAT_IA_ATTR; + +typedef enum dat_ia_attr_mask + { + DAT_IA_FIELD_IA_ADAPTER_NAME = 0x000001, + DAT_IA_FIELD_IA_VENDOR_NAME = 0x000002, + DAT_IA_FIELD_IA_HARDWARE_MAJOR_VERSION = 0x000004, + DAT_IA_FIELD_IA_HARDWARE_MINOR_VERSION = 0x000008, + DAT_IA_FIELD_IA_FIRMWARE_MAJOR_VERSION = 0x000010, + DAT_IA_FIELD_IA_FIRMWARE_MINOR_VERSION = 0x000020, + DAT_IA_FIELD_IA_ADDRESS_PTR = 0x000040, + DAT_IA_FIELD_IA_MAX_EPS = 0x000080, + DAT_IA_FIELD_IA_MAX_DTO_PER_EP = 0x000100, + DAT_IA_FIELD_IA_MAX_RDMA_READ_PER_EP_IN = 0x000200, + DAT_IA_FIELD_IA_MAX_RDMA_READ_PER_EP_OUT = 0x000400, + DAT_IA_FIELD_IA_MAX_EVDS = 0x000800, + DAT_IA_FIELD_IA_MAX_EVD_QLEN = 0x001000, + DAT_IA_FIELD_IA_MAX_IOV_SEGMENTS_PER_DTO = 0x002000, + DAT_IA_FIELD_IA_MAX_LMRS = 0x004000, + DAT_IA_FIELD_IA_MAX_LMR_BLOCK_SIZE = 0x008000, + DAT_IA_FIELD_IA_MAX_LMR_VIRTUAL_ADDRESS = 0x010000, + DAT_IA_FIELD_IA_MAX_PZS = 0x020000, + DAT_IA_FIELD_IA_MAX_MTU_SIZE = 0x040000, + DAT_IA_FIELD_IA_MAX_RDMA_SIZE = 0x080000, + DAT_IA_FIELD_IA_MAX_RMRS = 0x100000, + DAT_IA_FIELD_IA_MAX_RMR_TARGET_ADDRESS = 0x200000, + DAT_IA_FIELD_IA_NUM_TRANSPORT_ATTR = 0x400000, + DAT_IA_FIELD_IA_TRANSPORT_ATTR = 0x800000, + DAT_IA_FIELD_IA_NUM_VENDOR_ATTR = 0x1000000, + DAT_IA_FIELD_IA_VENDOR_ATTR = 0x2000000, + + DAT_IA_ALL = 0x3FFFFFF + } DAT_IA_ATTR_MASK; + + +/* Vendor Specific extensions */ + +#if defined(_JNI) + +#elif defined(_INTEL) + +#elif defined(_INFINISWITCH) + +#elif defined(_MELLANOX) + +#elif defined(_INFINICON) + +#elif defined(_TOPSPIN) + +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _VENDOR_SPECIFIC_H_ */ + + diff --git a/branches/WOF2-3/ulp/dapl/dat/include/dat/kdat.h b/branches/WOF2-3/ulp/dapl/dat/include/dat/kdat.h new file mode 100644 index 00000000..d30a601e --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dat/include/dat/kdat.h @@ -0,0 +1,240 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: kdat.h + * + * PURPOSE: defines the KDAT API + * + * Description: + * + * Mapping rules: + * All global symbols are prepended with "DAT_" or "dat_" + * All DAT objects have an 'api' tag which, such as 'ep' or 'lmr' + * The method table is in the provider definition structure. + * + * + * + **********************************************************************/ + +#ifndef _KDAT_H_ +#define _KDAT_H_ + +#include + +typedef enum dat_mem_type + { + /* Shared between udat and kdat */ + DAT_MEM_TYPE_VIRTUAL = 0x00, + DAT_MEM_TYPE_LMR = 0x01, + /* kdat specific */ + DAT_MEM_TYPE_PHYSICAL = 0x10, + DAT_MEM_TYPE_PLATFORM = 0x20, + DAT_MEM_TYPE_IA = 0x40, + DAT_MEM_TYPE_BYPASS = 0x80 + } DAT_MEM_TYPE; + +/* dat handle types */ +typedef enum dat_handle_type + { + DAT_HANDLE_TYPE_CR, + DAT_HANDLE_TYPE_EP, + DAT_HANDLE_TYPE_EVD, + DAT_HANDLE_TYPE_IA, + DAT_HANDLE_TYPE_LMR, + DAT_HANDLE_TYPE_PSP, + DAT_HANDLE_TYPE_PZ, + DAT_HANDLE_TYPE_RMR, + DAT_HANDLE_TYPE_RSP + } DAT_HANDLE_TYPE; + +typedef enum dat_evd_param_mask + { + DAT_EVD_FIELD_IA_HANDLE = 0x01, + DAT_EVD_FIELD_EVD_QLEN = 0x02, + DAT_EVD_FIELD_UPCALL_POLICY = 0x04, + DAT_EVD_FIELD_UPCALL = 0x08, + DAT_EVD_FIELD_EVD_FLAGS = 0x10, + + DAT_EVD_FIELD_ALL = 0x1F + + } DAT_EVD_PARAM_MASK; + + +#include + +#include + +/* Upcall support */ + +typedef enum dat_upcall_policy + { + DAT_UPCALL_DISABLE = 0, /* support no_upcalls */ + DAT_UPCALL_SINGLE_INSTANCE = 1, /* support only one upcall */ + DAT_UPCALL_MANY = 100 /* support multiple upcalls */ + } DAT_UPCALL_POLICY; + +typedef void (*DAT_UPCALL_FUNC)( + DAT_PVOID, /* instance_data */ + const DAT_EVENT *, /* event */ + DAT_BOOLEAN); /* more_events */ + +typedef struct dat_upcall_object + { + DAT_PVOID instance_data; + DAT_UPCALL_FUNC upcall_func; + } DAT_UPCALL_OBJECT; + +/* Define NULL upcall */ + +#define DAT_UPCALL_NULL(DAT_UPCALL_OBJECT) \ + {(DAT_PVOID) NULL, \ + (DAT_UPCALL_FUNC) NULL} + +typedef struct dat_evd_param + { + DAT_IA_HANDLE ia_handle; + DAT_COUNT evd_qlen; + DAT_UPCALL_POLICY upcall_policy; + DAT_UPCALL_OBJECT upcall; + DAT_EVD_FLAGS evd_flags; + } DAT_EVD_PARAM; + +#include + +/* + * Memory types + * + * Specifing memory type for LMR create. A consumer must use a single + * value when registering memory. The union of any of these + * flags is used in the provider parameter to indicate what memory + * type provider supports for LMR memory creation. + */ + +/* memory data types */ + +typedef enum dat_mem_optimize_flags + { + DAT_MEM_OPTIMIZE_DONT_CARE = 0x00, + DAT_MEM_OPTIMIZE_IA = 0x01, + DAT_MEM_OPTIMIZE_MIN_EXPOSURE = 0x02, + DAT_MEM_OPTIMIZE_EXACT_EXPOSURE = 0x04 + } DAT_MEM_OPTIMIZE_FLAGS; + + +typedef union dat_region_description + { + DAT_PVOID for_va; + DAT_LMR_HANDLE for_lmr_handle; + void * for_pointer; /* For kdapl only */ + void * for_array; /* For kdapl only */ + } DAT_REGION_DESCRIPTION; + +typedef struct dat_lmr_param + { + DAT_IA_HANDLE ia_handle; + DAT_MEM_TYPE mem_type; + DAT_REGION_DESCRIPTION region_desc; + DAT_VLEN length; + DAT_PZ_HANDLE pz_handle; + DAT_MEM_PRIV_FLAGS mem_priv; + DAT_LMR_CONTEXT lmr_context; + DAT_VLEN registered_size; + DAT_VADDR registered_address; + } DAT_LMR_PARAM; + + +/****************************************************************************/ + +/* + * Kernel DAT function call definitions, + */ + +typedef DAT_RETURN (*DAT_LMR_KCREATE_FUNC)( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_MEM_TYPE, /* mem_type */ + IN DAT_REGION_DESCRIPTION, /* region_description */ + IN DAT_VLEN, /* length */ + IN DAT_PZ_HANDLE, /* pz_handle */ + IN DAT_MEM_PRIV_FLAGS, /* privileges */ + IN DAT_MEM_OPTIMIZE_FLAGS, /* mem_optimization */ + OUT DAT_LMR_HANDLE *, /* lmr_handle */ + OUT DAT_LMR_CONTEXT *, /* lmr_context */ + OUT DAT_VLEN *, /* registered_length */ + OUT DAT_VADDR * ); /* registered_address */ + + +typedef DAT_RETURN (*DAT_IA_MEMTYPE_HINT_FUNC)( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_MEM_TYPE, /* mem_type */ + IN DAT_VLEN, /* length */ + IN DAT_MEM_OPTIMIZE_FLAGS, /* mem_optimization */ + OUT DAT_VLEN *, /* preferred_length */ + OUT DAT_VADDR * ); /* preferred_alignment */ + +typedef DAT_RETURN (*DAT_EVD_KCREATE_FUNC)( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_COUNT, /* evd_min_qlen */ + IN DAT_UPCALL_POLICY, /* upcall_policy */ + IN DAT_UPCALL_OBJECT, /* upcall */ + IN DAT_EVD_FLAGS, /* evd_flags */ + OUT DAT_EVD_HANDLE * ); /* evd_handle */ + +typedef DAT_RETURN (*DAT_EVD_MODIFY_UPCALL_FUNC)( + IN DAT_EVD_HANDLE, /* evd_handle */ + IN DAT_UPCALL_POLICY, /* upcall_policy */ + IN DAT_UPCALL_OBJECT ); /* upcall */ + +/* The following two DAT function calls are also found in udat.h. + * They were removed from dat.h to remove dependancy issues with + * dat.h file. There may be a better way to fix the dependancy + * + */ + +typedef DAT_RETURN (*DAT_IA_QUERY_FUNC)( + IN DAT_IA_HANDLE, /* ia handle */ + OUT DAT_EVD_HANDLE *, /* async_evd_handle */ + IN DAT_IA_ATTR_MASK, /* ia_attr_mask */ + OUT DAT_IA_ATTR *, /* ia_attr */ + IN DAT_PROVIDER_ATTR_MASK, /* provider_attr_mask */ + OUT DAT_PROVIDER_ATTR * ); /* provider_attr */ + +typedef DAT_RETURN (*DAT_EVD_QUERY_FUNC)( + IN DAT_EVD_HANDLE, /* evd_handle */ + IN DAT_EVD_PARAM_MASK, /* evd_param_mask */ + OUT DAT_EVD_PARAM * ); /* evd_param */ + +typedef DAT_RETURN (*DAT_LMR_QUERY_FUNC)( + IN DAT_LMR_HANDLE, + IN DAT_LMR_PARAM_MASK, + OUT DAT_LMR_PARAM *); + +#include + +#endif /* _KDAT_H_ */ + + diff --git a/branches/WOF2-3/ulp/dapl/dat/include/dat/kdat_config.h b/branches/WOF2-3/ulp/dapl/dat/include/dat/kdat_config.h new file mode 100644 index 00000000..6e45f162 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dat/include/dat/kdat_config.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: kdat_config.h + * + * PURPOSE: defines the common DAT API for uDAPL and kDAPL. + * + * Description: Header file for "uDAPL: User Direct Access Programming + * Library, Version: 1.1" + * + * Mapping rules: + * All global symbols are prepended with "DAT_" or "dat_" + * All DAT objects have an 'api' tag which, such as 'ep' or 'lmr' + * The method table is in the provider definition structure. + * + * + **********************************************************************/ + +#ifndef _KDAT_CONFIG_H_ +#define _UDAT_CONFIG_H_ + +#define DAT_VERSION_MAJOR 1 +#define DAT_VERSION_MINOR 1 + + +/* + * The official header files will default DAT_THREADSAFE to DAT_TRUE. If + * your project does not wish to use this default, you must ensure that + * DAT_THREADSAFE will be set to DAT_FALSE. This may be done by an + * explicit #define in a common project header file that is included + * before any DAT header files, or through command line directives to the + * compiler (presumably controlled by the make environment). + */ + +/* + * A site, project or platform may consider setting an alternate default + * via their make rules, but are discouraged from doing so by editing + * the official header files. + */ + +/* + * The Reference Implementation is not Thread Safe. The Reference + * Implementation has chosen to go with the first method and define it + * explicitly in the header file. + */ + +#define DAT_THREADSAFE DAT_FALSE + +#ifndef DAT_THREADSAFE +#define DAT_THREADSAFE DAT_TRUE +#endif /* DAT_THREADSAFE */ + +#endif /* _KDAT_CONFIG_H_ */ diff --git a/branches/WOF2-3/ulp/dapl/dat/include/dat/kdat_redirection.h b/branches/WOF2-3/ulp/dapl/dat/include/dat/kdat_redirection.h new file mode 100644 index 00000000..532e1d95 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dat/include/dat/kdat_redirection.h @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: kdat_redirection.h + * + * PURPOSE: Kernel DAT macro definitions + * + * Description: + * + * Mapping rules: + * All global symbols are prepended with "DAT_" or "dat_" + * All DAT objects have an 'api' tag which, such as 'ep' or 'lmr' + * The method table is in the provider definition structure. + * + * + * + **********************************************************************/ + +#ifndef _KDAT_REDIRCTION_H_ +#define _KDAT_REDIRCTION_H_ + + + +/* ia_memtype_hint macro */ + +#define dat_ia_memtype_hint(ia,mem_type,len,mem_opt,pref_len,pref_align) \ + (DAT_HANDLE_TO_PROVIDER(ia)->ia_memtype_hint_func)(\ + (ia),\ + (mem_type),\ + (len),\ + (mem_opt),\ + (pref_len),\ + (pref_align)) + +/* evd_modify_upcall macro */ + +#define dat_evd_modify_upcall(evd,policy,upcall) \ + (*DAT_HANDLE_TO_PROVIDER(evd)->evd_modify_upcall_func)(\ + (evd),\ + (policy),\ + (upcall)) + +/* evd_create macro */ + +#define dat_evd_kcreate(ia,policy,upcall,qlen,flags,handle) \ + (*DAT_HANDLE_TO_PROVIDER(ia)->evd_kcreate_func)(\ + (ia),\ + (qlen),\ + (policy),\ + (upcall),\ + (flags),\ + (handle)) + +/* lmr_create macro */ + +#define dat_lmr_kcreate(ia,mtype,reg_desc,len,pz,priv,mem_opt,\ + lmr,context,reg_len,reg_addr) \ + (*DAT_HANDLE_TO_PROVIDER(ia)->lmr_kcreate_func)(\ + (ia),\ + (mtype),\ + (reg_desc),\ + (len),\ + (pz),\ + (priv),\ + (mem_opt),\ + (lmr),\ + (context),\ + (reg_len),\ + (reg_addr)) + + +#include "dat_redirection.h" + +struct dat_provider + { + const char * device_name; + DAT_PVOID extension; + + DAT_IA_OPEN_FUNC ia_open_func; + DAT_IA_QUERY_FUNC ia_query_func; + DAT_IA_CLOSE_FUNC ia_close_func; + DAT_IA_MEMTYPE_HINT_FUNC ia_memtype_hint_func; /* kdat only */ + + DAT_SET_CONSUMER_CONTEXT_FUNC set_consumer_context_func; + DAT_GET_CONSUMER_CONTEXT_FUNC get_consumer_context_func; + DAT_GET_HANDLE_TYPE_FUNC get_handle_type_func; + + DAT_CR_QUERY_FUNC cr_query_func; + DAT_CR_ACCEPT_FUNC cr_accept_func; + DAT_CR_REJECT_FUNC cr_reject_func; + + DAT_EVD_KCREATE_FUNC evd_kcreate_func; + DAT_EVD_QUERY_FUNC evd_query_func; + + DAT_EVD_MODIFY_UPCALL_FUNC evd_modify_upcall_func; /* kdat only */ + + DAT_EVD_RESIZE_FUNC evd_resize_func; + DAT_EVD_POST_SE_FUNC evd_post_se_func; + DAT_EVD_DEQUEUE_FUNC evd_dequeue_func; + DAT_EVD_FREE_FUNC evd_free_func; + + DAT_EP_CREATE_FUNC ep_create_func; + DAT_EP_QUERY_FUNC ep_query_func; + DAT_EP_MODIFY_FUNC ep_modify_func; + DAT_EP_CONNECT_FUNC ep_connect_func; + DAT_EP_DUP_CONNECT_FUNC ep_dup_connect_func; + DAT_EP_DISCONNECT_FUNC ep_disconnect_func; + DAT_EP_POST_SEND_FUNC ep_post_send_func; + DAT_EP_POST_RECV_FUNC ep_post_recv_func; + DAT_EP_POST_RDMA_READ_FUNC ep_post_rdma_read_func; + DAT_EP_POST_RDMA_WRITE_FUNC ep_post_rdma_write_func; + DAT_EP_GET_STATUS_FUNC ep_get_status_func; + DAT_EP_FREE_FUNC ep_free_func; + + DAT_LMR_KCREATE_FUNC lmr_kcreate_func; + DAT_LMR_QUERY_FUNC lmr_query_func; + DAT_LMR_FREE_FUNC lmr_free_func; + + DAT_RMR_CREATE_FUNC rmr_create_func; + DAT_RMR_QUERY_FUNC rmr_query_func; + DAT_RMR_BIND_FUNC rmr_bind_func; + DAT_RMR_FREE_FUNC rmr_free_func; + + DAT_PSP_CREATE_FUNC psp_create_func; + DAT_PSP_QUERY_FUNC psp_query_func; + DAT_PSP_FREE_FUNC psp_free_func; + + DAT_RSP_CREATE_FUNC rsp_create_func; + DAT_RSP_QUERY_FUNC rsp_query_func; + DAT_RSP_FREE_FUNC rsp_free_func; + + DAT_PZ_CREATE_FUNC pz_create_func; + DAT_PZ_QUERY_FUNC pz_query_func; + DAT_PZ_FREE_FUNC pz_free_func; + }; + +#endif /* _KDAT_REDIRCTION_H_ */ + diff --git a/branches/WOF2-3/ulp/dapl/dat/include/dat/kdat_vendor_specific.h b/branches/WOF2-3/ulp/dapl/dat/include/dat/kdat_vendor_specific.h new file mode 100644 index 00000000..d617713c --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dat/include/dat/kdat_vendor_specific.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: kdat_vendor_specific.h + * + * PURPOSE: + * + * Description: + * + * Mapping rules: + * All global symbols are prepended with "DAT_" or "dat_" + * All DAT objects have an 'api' tag which, such as 'ep' or 'lmr' + * The method table is in the provider definition structure. + * + * + **********************************************************************/ + +#ifndef _KDAT_VENDOR_SPECIFIC_H_ +#define _KDAT_VENDOR_SPECIFIC_H_ + +/* General Provider attributes. kdat specific. */ +typedef struct dat_provider_attr + { + char provider_name[DAT_NAME_MAX_LENGTH]; + DAT_UINT32 provider_version_major; + DAT_UINT32 provider_version_minor; + DAT_UINT32 dapl_version_major; + DAT_UINT32 dapl_version_minor; + DAT_MEM_TYPE lmr_mem_types_supported; + DAT_RMR_BIND_EVD_RESTRICTION_TYPE rmr_bind_evd_restriction; + DAT_IOV_OWNERSHIP iov_ownership_on_return; + DAT_QOS dat_qos_supported; + DAT_COMPLETION_FLAGS completion_flags_supported; + DAT_BOOLEAN is_thread_safe; + DAT_COUNT max_private_data_size; + DAT_BOOLEAN supports_multipath; + DAT_EP_CREATOR_FOR_PSP ep_creator; + DAT_UPCALL_POLICY upcall_policy; + DAT_COUNT num_provider_specific_attr; + DAT_NAMED_ATTR * provider_specific_attr; + } DAT_PROVIDER_ATTR; + +typedef enum dat_provider_attr_mask + { + DAT_PROVIDER_FIELD_PROVIDER_NAME = 0x00001, + DAT_PROVIDER_FIELD_PROVIDER_VERSION_MAJOR = 0x00002, + DAT_PROVIDER_FIELD_PROVIDER_VERSION_MINOR = 0x00004, + DAT_PROVIDER_FIELD_DAPL_VERSION_MAJOR = 0x00008, + DAT_PROVIDER_FIELD_DAPL_VERSION_MINOR = 0x00010, + DAT_PROVIDER_FIELD_LMR_MEM_TYPE_SUPPORTED = 0x00020, + DAT_PROVIDER_FIELD_RMR_BIND_RESTRICTION = 0x00040, + DAT_PROVIDER_FIELD_IOV_OWNERSHIP = 0x00080, + DAT_PROVIDER_FIELD_DAT_QOS_SUPPORTED = 0x00100, + DAT_PROVIDER_FIELD_COMPLETION_FLAGS_SUPPORTED = 0x00200, + DAT_PROVIDER_FIELD_IS_THREAD_SAFE = 0x00400, + DAT_PROVIDER_FIELD_MAX_PRIVATE_DATA_SIZE = 0x00800, + DAT_PROVIDER_FIELD_SUPPORTS_MULTIPATH = 0x01000, + DAT_PROVIDER_FIELD_EP_CREATOR = 0x02000, + DAT_PROVIDER_FIELD_UPCALL_POLICY = 0x04000, + DAT_PROVIDER_FIELD_NUM_PROVIDER_SPECIFIC_ATTR = 0x10000, + DAT_PROVIDER_FIELD_PROVIDER_SPECIFIC_ATTR = 0x20000, + + DAT_PROVIDER_FIELD_ALL = 0x37FFF + } DAT_PROVIDER_ATTR_MASK; + +#include "dat_vendor_specific.h" /* Interface Adaptor attributes */ + +/* Vendor specific extensions */ + +#if defined(_JNI) + +#elif defined(_INTEL) + +#elif defined(_INFINISWITCH) + +#elif defined(_MELLANOX) + +#elif defined(_INFINICON) + +#elif defined(_TOPSPIN) + +#endif + +#endif /* _KDAT_VENDOR_SPECIFIC_H_ */ + + + diff --git a/branches/WOF2-3/ulp/dapl/dat/include/dat/udat.h b/branches/WOF2-3/ulp/dapl/dat/include/dat/udat.h new file mode 100644 index 00000000..1900408c --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dat/include/dat/udat.h @@ -0,0 +1,332 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: udat.h + * + * PURPOSE: defines the user DAT API + * + * Description: Interfaces in this file are completely described in + * the uDAPL 1.1 API + * + * Mapping rules: + * All global symbols are prepended with "DAT_" or "dat_" + * All DAT objects have an 'api' tag which, such as 'ep' or 'lmr' + * The method table is in the provider definition structure. + * + * + **********************************************************************/ + +#ifndef _UDAT_H_ +#define _UDAT_H_ + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +typedef enum dat_mem_type + { + /* Shared between udat and kdat */ + DAT_MEM_TYPE_VIRTUAL = 0x00, + DAT_MEM_TYPE_LMR = 0x01, + /* udat specific */ + DAT_MEM_TYPE_SHARED_VIRTUAL = 0x02 + } DAT_MEM_TYPE; + +/* dat handle types */ +typedef enum dat_handle_type + { + DAT_HANDLE_TYPE_CR, + DAT_HANDLE_TYPE_EP, + DAT_HANDLE_TYPE_EVD, + DAT_HANDLE_TYPE_IA, + DAT_HANDLE_TYPE_LMR, + DAT_HANDLE_TYPE_PSP, + DAT_HANDLE_TYPE_PZ, + DAT_HANDLE_TYPE_RMR, + DAT_HANDLE_TYPE_RSP, + DAT_HANDLE_TYPE_CNO + } DAT_HANDLE_TYPE; + +/* + * EVD state consists of 3 orthogonal substates. One for + * enabled/disabled, one for waitable/unwaitable, and one + * for configuration. Within each substates the values are + * mutually exclusive. + */ +typedef enum dat_evd_state + { + DAT_EVD_STATE_ENABLED = 0x01, + DAT_EVD_STATE_DISABLED = 0x02, + DAT_EVD_STATE_WAITABLE = 0x04, + DAT_EVD_STATE_UNWAITABLE = 0x08, + DAT_EVD_STATE_CONFIG_NOTIFY = 0x10, + DAT_EVD_STATE_CONFIG_SOLICITED = 0x20, + DAT_EVD_STATE_CONFIG_THRESHOLD = 0x30 + } DAT_EVD_STATE; + +typedef enum dat_evd_param_mask + { + DAT_EVD_FIELD_IA_HANDLE = 0x01, + DAT_EVD_FIELD_EVD_QLEN = 0x02, + DAT_EVD_FIELD_EVD_STATE = 0x04, + DAT_EVD_FIELD_CNO = 0x08, + DAT_EVD_FIELD_EVD_FLAGS = 0x10, + + DAT_EVD_FIELD_ALL = 0x1F + } DAT_EVD_PARAM_MASK; + +#include + +#include + +typedef DAT_HANDLE DAT_CNO_HANDLE; + +typedef struct dat_evd_param + { + DAT_IA_HANDLE ia_handle; + DAT_COUNT evd_qlen; + DAT_EVD_STATE evd_state; + DAT_CNO_HANDLE cno_handle; + DAT_EVD_FLAGS evd_flags; + } DAT_EVD_PARAM; + +#define DAT_LMR_COOKIE_SIZE 40 /* size of DAT_LMR_COOKIE in bytes */ +typedef char (* DAT_LMR_COOKIE)[DAT_LMR_COOKIE_SIZE]; + +/* Format for OS wait proxy agent function */ + +typedef void (DAT_API *DAT_AGENT_FUNC) + ( + DAT_PVOID, /* instance data */ + DAT_EVD_HANDLE /* Event Dispatcher*/ + ); + +/* Definition */ + +typedef struct dat_os_wait_proxy_agent + { + DAT_PVOID instance_data; + DAT_AGENT_FUNC proxy_agent_func; + } DAT_OS_WAIT_PROXY_AGENT; + +/* Define NULL Proxy agent */ + +#define DAT_OS_WAIT_PROXY_AGENT_NULL \ + (DAT_OS_WAIT_PROXY_AGENT) { \ + (DAT_PVOID) NULL, \ + (DAT_AGENT_FUNC) NULL } + + +/* Flags */ + +/* The value specified by the uDAPL Consumer for dat_ia_open to indicate + * that not async EVD should be created for the opening instance of an IA. + * The same IA have been open before that has the only async EVD to + * handle async errors for all open instances of the IA. + */ + +#define DAT_EVD_ASYNC_EXISTS (DAT_EVD_HANDLE) 0x1 + +/* + * The value return by the dat_ia_query for the case when there is no + * async EVD for the IA instance. Consumer had specified the value of + * DAT_EVD_ASYNC_EXISTS for the async_evd_handle for dat_ia_open. + */ + +#define DAT_EVD_OUT_OF_SCOPE (DAT_EVD_HANDLE) 0x2 + +/* + * Memory types + * + * Specifing memory type for LMR create. A consumer must use a single + * value when registering memory. The union of any of these + * flags is used in the provider parameters to indicate what memory + * type provider supports for LMR memory creation. + */ + + + +/* For udapl only */ + +typedef struct dat_shared_memory + { + DAT_PVOID virtual_address; + DAT_LMR_COOKIE shared_memory_id; + } DAT_SHARED_MEMORY; + +typedef union dat_region_description + { + DAT_PVOID for_va; + DAT_LMR_HANDLE for_lmr_handle; + DAT_SHARED_MEMORY for_shared_memory; /* For udapl only */ + } DAT_REGION_DESCRIPTION; + +/* LMR Arguments */ + +typedef struct dat_lmr_param + { + DAT_IA_HANDLE ia_handle; + DAT_MEM_TYPE mem_type; + DAT_REGION_DESCRIPTION region_desc; + DAT_VLEN length; + DAT_PZ_HANDLE pz_handle; + DAT_MEM_PRIV_FLAGS mem_priv; + DAT_LMR_CONTEXT lmr_context; + DAT_RMR_CONTEXT rmr_context; + DAT_VLEN registered_size; + DAT_VADDR registered_address; + } DAT_LMR_PARAM; + + +typedef struct dat_cno_param + { + DAT_IA_HANDLE ia_handle; + DAT_OS_WAIT_PROXY_AGENT agent; + } DAT_CNO_PARAM; + +typedef enum dat_cno_param_mask + { + DAT_CNO_FIELD_IA_HANDLE = 0x1, + DAT_CNO_FIELD_AGENT = 0x2, + + DAT_CNO_FIELD_ALL = 0x3 + } DAT_CNO_PARAM_MASK; + +#include + +/****************************************************************************/ + +/* + * User DAT functions definitions. + */ + + +typedef DAT_RETURN (DAT_API *DAT_LMR_CREATE_FUNC)( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_MEM_TYPE, /* mem_type */ + IN DAT_REGION_DESCRIPTION, /* region_description */ + IN DAT_VLEN, /* length */ + IN DAT_PZ_HANDLE, /* pz_handle */ + IN DAT_MEM_PRIV_FLAGS, /* privileges */ + OUT DAT_LMR_HANDLE *, /* lmr_handle */ + OUT DAT_LMR_CONTEXT *, /* lmr_context */ + OUT DAT_RMR_CONTEXT *, /* rmr_context */ + OUT DAT_VLEN *, /* registered_length */ + OUT DAT_VADDR * ); /* registered_address */ + +/* Event Functions */ + +typedef DAT_RETURN (DAT_API *DAT_EVD_CREATE_FUNC)( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_COUNT, /* evd_min_qlen */ + IN DAT_CNO_HANDLE, /* cno_handle */ + IN DAT_EVD_FLAGS, /* evd_flags */ + OUT DAT_EVD_HANDLE * ); /* evd_handle */ + +typedef DAT_RETURN (DAT_API *DAT_EVD_MODIFY_CNO_FUNC)( + IN DAT_EVD_HANDLE, /* evd_handle */ + IN DAT_CNO_HANDLE); /* cno_handle */ + +typedef DAT_RETURN (DAT_API *DAT_CNO_CREATE_FUNC)( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_OS_WAIT_PROXY_AGENT,/* agent */ + OUT DAT_CNO_HANDLE *); /* cno_handle */ + +typedef DAT_RETURN (DAT_API *DAT_CNO_MODIFY_AGENT_FUNC)( + IN DAT_CNO_HANDLE, /* cno_handle */ + IN DAT_OS_WAIT_PROXY_AGENT);/* agent */ + +typedef DAT_RETURN (DAT_API *DAT_CNO_QUERY_FUNC)( + IN DAT_CNO_HANDLE, /* cno_handle */ + IN DAT_CNO_PARAM_MASK, /* cno_param_mask */ + OUT DAT_CNO_PARAM * ); /* cno_param */ + +typedef DAT_RETURN (DAT_API *DAT_CNO_FREE_FUNC)( + IN DAT_CNO_HANDLE); /* cno_handle */ + +typedef DAT_RETURN (DAT_API *DAT_CNO_WAIT_FUNC)( + IN DAT_CNO_HANDLE, /* cno_handle */ + IN DAT_TIMEOUT, /* timeout */ + OUT DAT_EVD_HANDLE *); /* evd_handle */ + +typedef DAT_RETURN (DAT_API *DAT_EVD_ENABLE_FUNC)( + IN DAT_EVD_HANDLE); /* evd_handle */ + +typedef DAT_RETURN (DAT_API *DAT_EVD_WAIT_FUNC)( + IN DAT_EVD_HANDLE, /* evd_handle */ + IN DAT_TIMEOUT, /* Timeout */ + IN DAT_COUNT, /* Threshold */ + OUT DAT_EVENT *, /* event */ + OUT DAT_COUNT * ); /* N more events */ + +typedef DAT_RETURN (DAT_API *DAT_EVD_DISABLE_FUNC)( + IN DAT_EVD_HANDLE); /* evd_handle */ + +typedef DAT_RETURN (DAT_API *DAT_EVD_SET_UNWAITABLE_FUNC)( + IN DAT_EVD_HANDLE); /* evd_handle */ + +typedef DAT_RETURN (DAT_API *DAT_EVD_CLEAR_UNWAITABLE_FUNC)( + IN DAT_EVD_HANDLE); /* evd_handle */ + +/* The following three DAT function calls are also found in kdat.h. + * They were removed from dat.h to remove dependancy issues with + * dat.h file. There may be a better way to fix the dependancy. + */ + +typedef DAT_RETURN (DAT_API *DAT_IA_QUERY_FUNC)( + IN DAT_IA_HANDLE, /* ia handle */ + OUT DAT_EVD_HANDLE *, /* async_evd_handle */ + IN DAT_IA_ATTR_MASK, /* ia_attr_mask */ + OUT DAT_IA_ATTR *, /* ia_attr */ + IN DAT_PROVIDER_ATTR_MASK, /* provider_attr_mask */ + OUT DAT_PROVIDER_ATTR * ); /* provider_attr */ + +typedef DAT_RETURN (DAT_API *DAT_EVD_QUERY_FUNC)( + IN DAT_EVD_HANDLE, /* evd_handle */ + IN DAT_EVD_PARAM_MASK, /* evd_param_mask */ + OUT DAT_EVD_PARAM * ); /* evd_param */ + +typedef DAT_RETURN (DAT_API *DAT_LMR_QUERY_FUNC)( + IN DAT_LMR_HANDLE, + IN DAT_LMR_PARAM_MASK, + OUT DAT_LMR_PARAM *); + +#include + +#ifdef __cplusplus +} +#endif + +#endif /* _UDAT_H_ */ + + + + diff --git a/branches/WOF2-3/ulp/dapl/dat/include/dat/udat_config.h b/branches/WOF2-3/ulp/dapl/dat/include/dat/udat_config.h new file mode 100644 index 00000000..172a12ba --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dat/include/dat/udat_config.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: udat_config.h + * + * PURPOSE: defines the common DAT API for uDAPL and kDAPL. + * + * Description: Header file for "uDAPL: User Direct Access Programming + * Library, Version: 1.1" + * + * Mapping rules: + * All global symbols are prepended with "DAT_" or "dat_" + * All DAT objects have an 'api' tag which, such as 'ep' or 'lmr' + * The method table is in the provider definition structure. + * + * + **********************************************************************/ + +#ifndef _UDAT_CONFIG_H_ +#define _UDAT_CONFIG_H_ + +#define DAT_VERSION_MAJOR 1 +#define DAT_VERSION_MINOR 1 + +/* + * The official header files will default DAT_THREADSAFE to DAT_TRUE. If + * your project does not wish to use this default, you must ensure that + * DAT_THREADSAFE will be set to DAT_FALSE. This may be done by an + * explicit #define in a common project header file that is included + * before any DAT header files, or through command line directives to the + * compiler (presumably controlled by the make environment). + */ + +/* + * A site, project or platform may consider setting an alternate default + * via their make rules, but are discouraged from doing so by editing + * the official header files. + */ + +/* + * The Reference Implementation is not Thread Safe. The Reference + * Implementation has chosen to go with the first method and define it + * explicitly in the header file. + */ + + +#ifndef DAT_THREADSAFE +#define DAT_THREADSAFE DAT_TRUE +#endif /* DAT_THREADSAFE */ + +#endif /* _UDAT_CONFIG_H_ */ diff --git a/branches/WOF2-3/ulp/dapl/dat/include/dat/udat_redirection.h b/branches/WOF2-3/ulp/dapl/dat/include/dat/udat_redirection.h new file mode 100644 index 00000000..848679c9 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dat/include/dat/udat_redirection.h @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: udat_redirection.h + * + * PURPOSE: User DAT macro definitions + * + * Description: Header file for "uDAPL: User Direct Access Programming + * Library, Version: 1.1" + * + * Mapping rules: + * All global symbols are prepended with "DAT_" or "dat_" + * All DAT objects have an 'api' tag which, such as 'ep' or 'lmr' + * The method table is in the provider definition structure. + * + * + * + **********************************************************************/ + +#ifndef _UDAT_REDIRECTION_H_ +#define _UDAT_REDIRECTION_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define dat_lmr_create(ia,mtype,reg_desc,len,pz,priv,\ + lmr,lmr_context,rmr_context,reg_len,reg_addr) \ + (*DAT_HANDLE_TO_PROVIDER(ia)->lmr_create_func)(\ + (ia),\ + (mtype),\ + (reg_desc),\ + (len),\ + (pz),\ + (priv),\ + (lmr),\ + (lmr_context),\ + (rmr_context),\ + (reg_len),\ + (reg_addr)) + +#define dat_evd_create(ia,qlen,cno,flags,handle) \ + (*DAT_HANDLE_TO_PROVIDER(ia)->evd_create_func)(\ + (ia),\ + (qlen),\ + (cno),\ + (flags),\ + (handle)) + +#define dat_evd_enable(evd) \ + (*DAT_HANDLE_TO_PROVIDER(evd)->evd_enable_func)(\ + (evd)) + +#define dat_evd_wait(evd,timeout,threshold,event,nmore) \ + (*DAT_HANDLE_TO_PROVIDER(evd)->evd_wait_func)(\ + (evd),\ + (timeout),\ + (threshold),\ + (event),\ + (nmore)) + +#define dat_evd_disable(evd) \ + (*DAT_HANDLE_TO_PROVIDER(evd)->evd_disable_func)(\ + (evd)) + +#define dat_evd_set_unwaitable(evd) \ + (*DAT_HANDLE_TO_PROVIDER(evd)->evd_set_unwaitable_func)(\ + (evd)) + +#define dat_evd_clear_unwaitable(evd) \ + (*DAT_HANDLE_TO_PROVIDER(evd)->evd_clear_unwaitable_func)(\ + (evd)) + +#define dat_evd_modify_cno(evd,cno) \ + (*DAT_HANDLE_TO_PROVIDER(evd)->evd_modify_cno_func)(\ + (evd),\ + (cno)) + +#define dat_cno_create(ia,proxy,cno) \ + (*DAT_HANDLE_TO_PROVIDER(ia)->cno_create_func)(\ + (ia),\ + (proxy),\ + (cno)) + +#define dat_cno_modify_agent(cno,proxy) \ + (*DAT_HANDLE_TO_PROVIDER(cno)->cno_modify_agent_func)(\ + (cno),\ + (proxy)) + +#define dat_cno_query(cno,mask,param) \ + (*DAT_HANDLE_TO_PROVIDER(cno)->cno_query_func)(\ + (cno),\ + (mask),\ + (param)) + +#define dat_cno_free(cno) \ + (*DAT_HANDLE_TO_PROVIDER(cno)->cno_free_func)(\ + (cno)) + +#define dat_cno_wait(cno,timeout,evd) \ + (*DAT_HANDLE_TO_PROVIDER(cno)->cno_wait_func)(\ + (cno),\ + (timeout),\ + (evd)) + +#define dat_cr_handoff(cr,qual) \ + (*DAT_HANDLE_TO_PROVIDER(cr)->cr_handoff_func)(\ + (cr),\ + (qual)) + +#include + +struct dat_provider + { + const char * device_name; + DAT_PVOID extension; + + DAT_IA_OPEN_FUNC ia_open_func; + DAT_IA_QUERY_FUNC ia_query_func; + DAT_IA_CLOSE_FUNC ia_close_func; + + DAT_SET_CONSUMER_CONTEXT_FUNC set_consumer_context_func; + DAT_GET_CONSUMER_CONTEXT_FUNC get_consumer_context_func; + DAT_GET_HANDLE_TYPE_FUNC get_handle_type_func; + + DAT_CNO_CREATE_FUNC cno_create_func; /* udat only */ + DAT_CNO_MODIFY_AGENT_FUNC cno_modify_agent_func; /* udat only */ + DAT_CNO_QUERY_FUNC cno_query_func; /* udat only */ + DAT_CNO_FREE_FUNC cno_free_func; /* udat only */ + DAT_CNO_WAIT_FUNC cno_wait_func; /* udat only */ + + DAT_CR_QUERY_FUNC cr_query_func; + DAT_CR_ACCEPT_FUNC cr_accept_func; + DAT_CR_REJECT_FUNC cr_reject_func; + DAT_CR_HANDOFF_FUNC cr_handoff_func; /* udat only */ + + DAT_EVD_CREATE_FUNC evd_create_func; + DAT_EVD_QUERY_FUNC evd_query_func; + + DAT_EVD_MODIFY_CNO_FUNC evd_modify_cno_func; /* udat only */ + DAT_EVD_ENABLE_FUNC evd_enable_func; /* udat only */ + DAT_EVD_DISABLE_FUNC evd_disable_func; /* udat only */ + DAT_EVD_WAIT_FUNC evd_wait_func; /* udat only */ + + DAT_EVD_RESIZE_FUNC evd_resize_func; + DAT_EVD_POST_SE_FUNC evd_post_se_func; + DAT_EVD_DEQUEUE_FUNC evd_dequeue_func; + DAT_EVD_FREE_FUNC evd_free_func; + + DAT_EP_CREATE_FUNC ep_create_func; + DAT_EP_QUERY_FUNC ep_query_func; + DAT_EP_MODIFY_FUNC ep_modify_func; + DAT_EP_CONNECT_FUNC ep_connect_func; + DAT_EP_DUP_CONNECT_FUNC ep_dup_connect_func; + DAT_EP_DISCONNECT_FUNC ep_disconnect_func; + DAT_EP_POST_SEND_FUNC ep_post_send_func; + DAT_EP_POST_RECV_FUNC ep_post_recv_func; + DAT_EP_POST_RDMA_READ_FUNC ep_post_rdma_read_func; + DAT_EP_POST_RDMA_WRITE_FUNC ep_post_rdma_write_func; + DAT_EP_GET_STATUS_FUNC ep_get_status_func; + DAT_EP_FREE_FUNC ep_free_func; + + DAT_LMR_CREATE_FUNC lmr_create_func; + DAT_LMR_QUERY_FUNC lmr_query_func; + + DAT_LMR_FREE_FUNC lmr_free_func; + + DAT_RMR_CREATE_FUNC rmr_create_func; + DAT_RMR_QUERY_FUNC rmr_query_func; + DAT_RMR_BIND_FUNC rmr_bind_func; + DAT_RMR_FREE_FUNC rmr_free_func; + + DAT_PSP_CREATE_FUNC psp_create_func; + DAT_PSP_QUERY_FUNC psp_query_func; + DAT_PSP_FREE_FUNC psp_free_func; + + DAT_RSP_CREATE_FUNC rsp_create_func; + DAT_RSP_QUERY_FUNC rsp_query_func; + DAT_RSP_FREE_FUNC rsp_free_func; + + DAT_PZ_CREATE_FUNC pz_create_func; + DAT_PZ_QUERY_FUNC pz_query_func; + DAT_PZ_FREE_FUNC pz_free_func; + + /* udat-1.1 */ + DAT_PSP_CREATE_ANY_FUNC psp_create_any_func; + DAT_EP_RESET_FUNC ep_reset_func; + DAT_EVD_SET_UNWAITABLE_FUNC evd_set_unwaitable_func; + DAT_EVD_CLEAR_UNWAITABLE_FUNC evd_clear_unwaitable_func; + + }; + +#ifdef __cplusplus +} +#endif + +#endif /* _UDAT_REDIRECTION_H_ */ + + diff --git a/branches/WOF2-3/ulp/dapl/dat/include/dat/udat_vendor_specific.h b/branches/WOF2-3/ulp/dapl/dat/include/dat/udat_vendor_specific.h new file mode 100644 index 00000000..6321abbc --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dat/include/dat/udat_vendor_specific.h @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: udat_vendor_specific.h + * + * PURPOSE: + * + * Description: Header file for "uDAPL: User Direct Access Programming + * Library, Version: 1.1" + * + * Mapping rules: + * All global symbols are prepended with "DAT_" or "dat_" + * All DAT objects have an 'api' tag which, such as 'ep' or 'lmr' + * The method table is in the provider definition structure. + * + * + **********************************************************************/ + +#ifndef _UDAT_VENDOR_SPECIFIC_H_ +#define _UDAT_VENDOR_SPECIFIC_H_ + +/* General Provider attributes. udat specific. */ +#ifdef __cplusplus +extern "C" +{ +#endif + +typedef enum dat_pz_support + { + DAT_PZ_UNIQUE, + DAT_PZ_SAME, + DAT_PZ_SHAREABLE + } DAT_PZ_SUPPORT; + +/* Provider should support merging of all event stream types. Provider + * attribute specify support for merging different event stream types. + * It is a 2D binary matrix where each row and column represents an event + * stream type. Each binary entry is 1 if the event streams of its raw + * and column can fed the same EVD, and 0 otherwise. The order of event + * streams in row and column is the same as in the definition of + * DAT_EVD_FLAGS: index 0 - Software Event, 1- Connection Request, + * 2 - DTO Completion, 3 - Connection event, 4 - RMR Bind Completion, + * 5 - Asynchronous event. By definition each diagonal entry is 1. + * Consumer allocates an array for it and passes it IN as a pointer + * for the array that Provider fills. Provider must fill the array + * that Consumer passes. + */ + +typedef struct dat_provider_attr + { + char provider_name[DAT_NAME_MAX_LENGTH]; + DAT_UINT32 provider_version_major; + DAT_UINT32 provider_version_minor; + DAT_UINT32 dapl_version_major; + DAT_UINT32 dapl_version_minor; + DAT_MEM_TYPE lmr_mem_types_supported; + DAT_IOV_OWNERSHIP iov_ownership_on_return; + DAT_QOS dat_qos_supported; + DAT_COMPLETION_FLAGS completion_flags_supported; + DAT_BOOLEAN is_thread_safe; + DAT_COUNT max_private_data_size; + DAT_BOOLEAN supports_multipath; + DAT_EP_CREATOR_FOR_PSP ep_creator; + DAT_UINT32 optimal_buffer_alignment; + DAT_BOOLEAN evd_stream_merging_supported[6][6]; + DAT_PZ_SUPPORT pz_support; + DAT_COUNT num_provider_specific_attr; + DAT_NAMED_ATTR * provider_specific_attr; + } DAT_PROVIDER_ATTR; + +typedef enum dat_provider_attr_mask + { + DAT_PROVIDER_FIELD_PROVIDER_NAME = 0x00001, + DAT_PROVIDER_FIELD_PROVIDER_VERSION_MAJOR = 0x00002, + DAT_PROVIDER_FIELD_PROVIDER_VERSION_MINOR = 0x00004, + DAT_PROVIDER_FIELD_DAPL_VERSION_MAJOR = 0x00008, + DAT_PROVIDER_FIELD_DAPL_VERSION_MINOR = 0x00010, + DAT_PROVIDER_FIELD_LMR_MEM_TYPE_SUPPORTED = 0x00020, + DAT_PROVIDER_FIELD_IOV_OWNERSHIP = 0x00040, + DAT_PROVIDER_FIELD_DAT_QOS_SUPPORTED = 0x00080, + DAT_PROVIDER_FIELD_COMPLETION_FLAGS_SUPPORTED = 0x00100, + DAT_PROVIDER_FIELD_IS_THREAD_SAFE = 0x00200, + DAT_PROVIDER_FIELD_MAX_PRIVATE_DATA_SIZE = 0x00400, + DAT_PROVIDER_FIELD_SUPPORTS_MULTIPATH = 0x00800, + DAT_PROVIDER_FIELD_EP_CREATOR = 0x01000, + DAT_PROVIDER_FIELD_PZ_SUPPORT = 0x02000, + DAT_PROVIDER_FIELD_OPTIMAL_BUFFER_ALIGNMENT = 0x04000, + DAT_PROVIDER_FIELD_EVD_STREAM_MERGING_SUPPORTED = 0x08000, + DAT_PROVIDER_FIELD_NUM_PROVIDER_SPECIFIC_ATTR = 0x10000, + DAT_PROVIDER_FIELD_PROVIDER_SPECIFIC_ATTR = 0x20000, + + DAT_PROVIDER_FIELD_ALL = 0x37FFF + } DAT_PROVIDER_ATTR_MASK; + +#include + +#if defined(_JNI) + +#elif defined(_INTEL) + +#elif defined(_INFINISWITCH) + +#elif defined(_MELLANOX) + +#elif defined(_INFINICON) + +#elif defined(_TOPSPIN) + +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _UDAT_VENDOR_SPECIFIC_H_ */ + + + diff --git a/branches/WOF2-3/ulp/dapl/dat/kdat/Makefile b/branches/WOF2-3/ulp/dapl/dat/kdat/Makefile new file mode 100644 index 00000000..875fa01d --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dat/kdat/Makefile @@ -0,0 +1,113 @@ +# +# Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. +# +# This Software is licensed under either one of the following two licenses: +# +# 1) under the terms of the "Common Public License 1.0" a copy of which is +# in the file LICENSE.txt in the root directory. The license is also +# available from the Open Source Initiative, see +# http://www.opensource.org/licenses/cpl.php. +# OR +# +# 2) under the terms of the "The BSD License" a copy of which is in the file +# LICENSE2.txt in the root directory. The license is also available from +# the Open Source Initiative, see +# http://www.opensource.org/licenses/bsd-license.php. +# +# Licensee has the right to choose either one of the above two licenses. +# +# Redistributions of source code must retain both the above copyright +# notice and either one of the license notices. +# +# Redistributions in binary form must reproduce both the above copyright +# notice, either one of the license notices in the documentation +# and/or other materials provided with the distribution. +# + +#********************************************************************* +# +# MODULE: Makefile +# +# PURPOSE: Makefile for DAT registration module +# +# $Id$ +#*********************************************************************/ +UNAME = $(strip $(shell /bin/uname -r)) +KERNEL_INCLUDE_DIR = /lib/modules/$(UNAME)/build/include + +TOPDIR = $(shell /bin/pwd) +COMMON = $(TOPDIR)/../common + +SRC_PATH = $(TOPDIR)/ +OBJ_PATH = $(TOPDIR)/Obj/ +#TARGET_PATH = $(TOPDIR)/Target/$(UNAME)/ +TARGET_PATH = $(TOPDIR)/Target + +TARGET = $(TARGET_PATH)/dat_registry.o + +CC=gcc + +# +# CFLAGS definition +# +CFLAGS = -O $(CPPFLAGS) +CFLAGS += -D__KERNEL__ +CFLAGS += -DMODULE +CFLAGS += -I. +CFLAGS += -I.. +CFLAGS += -I../include +CFLAGS += -I./linux +CFLAGS += -I../common +CFLAGS += -I$(KERNEL_INCLUDE_DIR) +CFLAGS += -Wall +CFLAGS += -Wstrict-prototypes +# The following two lines will cause warnings to appear on the +# compile time output when including certain kernel .h files +#CFLAGS += -Wmissing-prototypes +#CFLAGS += -Wmissing-declarations +CFLAGS += -Werror + +KDAT_SRCS = dat_kdapl.c \ + dat_module.c + +COMMON_SRCS = dat_data.c \ + dat_init.c \ + dat_register.c + +SRCS = $(KDAT_SRCS) $(COMMON_SRCS) + +KDAT_OBJS = $(KDAT_SRCS:%.c=$(OBJ_PATH)%.o) +COMMON_OBJS = $(COMMON_SRCS:%.c=$(OBJ_PATH)%.o) + +OBJS = $(KDAT_OBJS) $(COMMON_OBJS) + + +all: mkdirs $(TARGET) + +mkdirs: + @[ -d $(TARGET_PATH) ] || /bin/mkdir -p $(TARGET_PATH) + @[ -d $(OBJ_PATH) ] || /bin/mkdir -p $(OBJ_PATH) + +$(KDAT_OBJS): $(OBJ_PATH)%.o : %.c + @echo Compiling $< + $(CC) $(CFLAGS) -c $< -o $@ + +$(COMMON_OBJS): $(OBJ_PATH)%.o : $(COMMON)/%.c + @echo Compiling $< + $(CC) $(CFLAGS) -c $< -o $@ + +$(TARGET): $(OBJS) + @echo Linking $(TARGET) + $(LD) -r $^ -o $(TARGET) + +clean: + rm -f $(OBJS) + rm -f $(TARGET) + +load: $(TARGET) + @sudo insmod $(TARGET) + @sudo tail -3 /var/log/messages | grep -v sudo + +unload: + @sudo rmmod dat_registry + @sudo tail -3 /var/log/messages | grep -v sudo diff --git a/branches/WOF2-3/ulp/dapl/dat/kdat/dat_kdapl.c b/branches/WOF2-3/ulp/dapl/dat/kdat/dat_kdapl.c new file mode 100644 index 00000000..c702e931 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dat/kdat/dat_kdapl.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dat_kdapl.c + * + * PURPOSE: kdapl functions required to be part of the DAT registry. + * Description: Interfaces in this file are completely described in + *the kDAPL 1.0 API + * + * $Id$ + **********************************************************************/ + +#include "dat_osd.h" +#include +#include "dat_register.h" + +/*********************************************************************** + * Function: dat_ia_open + ***********************************************************************/ +DAT_RETURN +dat_ia_open ( + IN const DAT_NAME_PTR device_name, + IN DAT_COUNT async_event_qlen, + INOUT DAT_EVD_HANDLE *async_event_handle, + OUT DAT_IA_HANDLE *ia_handle) +{ + DAT_RETURN status; + DAT_PROVIDER *provider; + + if (!ia_handle) + { + return DAT_INVALID_HANDLE | DAT_INVALID_HANDLE_IA; + } + *ia_handle = 0; + dat_os_printf ("<1>DAT Registry: dat_ia_open\n"); + + /* make sure the provider is registered */ + provider = dat_get_provider(device_name); + if (!provider) + { + status = DAT_NAME_NOT_FOUND; + goto error_exit; + } + + /* call the real provider open function */ + status = (*provider->ia_open_func) ( provider, + async_event_qlen, + async_event_handle, + ia_handle); + + error_exit: + return status; +} + +/*********************************************************************** + * Function: dat_ia_close + ***********************************************************************/ +DAT_RETURN +dat_ia_close (IN DAT_IA_HANDLE ia_handle) +{ + DAT_RETURN status; + DAT_PROVIDER *provider; + + provider = DAT_HANDLE_TO_PROVIDER(ia_handle); + status = (*provider->ia_close_func) (ia_handle); + + return status; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl/dat/kdat/dat_module.c b/branches/WOF2-3/ulp/dapl/dat/kdat/dat_module.c new file mode 100644 index 00000000..f1264227 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dat/kdat/dat_module.c @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dat_module.c + * + * PURPOSE: DAT registry module implementation, exists in the Linux + * kernel + * Description: a linux module implementation + * + * $Id$ + **********************************************************************/ + +#include "dat_osd.h" +#include +#include "dat_data.h" + +/*********************************************************************** + * init_module + * + * Entry point for a Linux module, performs simple initialization + * + * Input: + * none + * + * Output: + * none + * + * Returns: + * SUCCESS + ***********************************************************************/ + +int init_module(void) +{ + int i; + + dat_os_printf ("<1>DAT Registry: Started\n"); + + dat_os_lock_init(&dat_registry_lock); + for (i = 0; i < DAT_MAX_NICS; i++) + { + dat_registry[i] = NULL; + } + return (0); /* success */ +} + +/*********************************************************************** + * cleanup_module + * + * Entry point for a Linux module, cleans up the module on exit + * + * Input: + * none + * + * Output: + * none + * + * Returns: + * void + ***********************************************************************/ +void cleanup_module(void) +{ + dat_os_lock_destroy(&dat_registry_lock); + dat_os_printf ("<1>DAT Registry: Stopped\n"); + return; +} + +/* Module exports */ + +EXPORT_SYMBOL (dat_ia_open); +EXPORT_SYMBOL (dat_ia_close); + + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl/dat/kdat/linux/dat_osd.c b/branches/WOF2-3/ulp/dapl/dat/kdat/linux/dat_osd.c new file mode 100644 index 00000000..b463e68b --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dat/kdat/linux/dat_osd.c @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dat_osd.c + * + * PURPOSE: Operating System Dependent layer + * Description: + * Provide OS dependent functions with a canonical DAT + * interface. Designed to be portable and hide OS specific quirks + * of common functions. + * + * + * $Id$ + **********************************************************************/ + +#include +#include + +#include +#include "dat_osd.h" + +/* + * Internal structures + */ + +typedef struct THREAD_INFO { + void (*function)(void *); + void *arg; + int thread_id; + DAT_OS_THREAD_STATE state; + wait_queue_head_t wchan; +} THREAD_INFO; + + +/* + * dat_os_start_thread + * + * Simple internal routine that allows us to catch the thread before + * invoking the user supplied function. Linux threads are activated + * and run, but our semantics allow us to create them in a sleep + * state. + * + * Input: + * arg Thread state structure to pass initial data + * + * Returns: + * DAT_SUCCESS + */ +static int +dat_os_thread_start (void *arg) +{ + IN THREAD_INFO *thread_state = (THREAD_INFO *) arg; + + if (thread_state->state == DAT_OS_THREAD_WAIT) + { + /* + * Wait for a wakeup event on our thread_state + * structure. A thread_resume() or a signal will + * wake us up. + */ + interruptible_sleep_on (&thread_state->wchan); + } + + /* + * invoke the user specified routine + */ + (thread_state->function) (thread_state->arg); + + return (0); +} + + +/* + * dat_os_thread_create + * + * Returns a pointer to an internal thread structure that provides + * the implementation with a measure of control over the threads. + * Much of this is mandated by the desire to start threads in a + * wait queue, then to enable them when the implementation is ready. + * + * There is no upfront checking, invoker is assumed to know what they + * are doing. + * + * Input: + * function Function to invoke thread + * arg Argument to start routine + * state Initial thread state + * DAT_OS_THREAD_RUN Immediate execution + * DAT_OS_THREAD_WAIT new thread will wait + * thread_id User allocated space for thread ID. + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + */ +DAT_RETURN +dat_os_thread_create ( + IN void (*function) (void *), + IN void *arg, + IN DAT_OS_THREAD_STATE state, + OUT DAT_OS_THREAD *thread_id ) +{ + int pid; + THREAD_INFO *thread_state; + + /* Get a thread_state structure and fill it in. */ + thread_state = kmalloc(sizeof(thread_state), GFP_ATOMIC); + if (thread_state == NULL) + { + return DAT_INSUFFICIENT_RESOURCES | DAT_RESOURCE_MEMORY; + } + + thread_state->function = function; + thread_state->arg = arg; + thread_state->state = state; + + /* set up a wait queue for a delayed start */ + if ( state == DAT_OS_THREAD_WAIT ) + { + init_waitqueue_head (&thread_state->wchan); + } + + if ((pid = kernel_thread (dat_os_thread_start, + thread_state, /* argument */ + 0)) < 0) /* clone arguments 0 */ + { + /* Error: options are: + * EAGAIN: Need to try again + * else, insufficient resources. + * Just return INSUFFICIENT_RESOURCES for any error + */ + kfree(thread_state); + return DAT_INSUFFICIENT_RESOURCES; + } + + thread_state->thread_id = pid; + *thread_id = (DAT_OS_THREAD)thread_state; + + return DAT_SUCCESS; +} + + +/* + * dat_os_thread_resume + * + * Set a blocked thread running. + * + * Input: + * thread_id Pointer to thread_state entry + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + */ +DAT_RETURN +dat_os_thread_resume ( + IN DAT_OS_THREAD thread_id ) +{ + THREAD_INFO *thread_state = (THREAD_INFO *) thread_id; + + if (thread_state == NULL) + { + return DAT_INVALID_PARAMETER | DAT_INVALID_ARG1; + } + + if (thread_state->state == DAT_OS_THREAD_WAIT) + { + /* Set the thread to running */ + thread_state->state = DAT_OS_THREAD_RUN; + wake_up_interruptible (&thread_state->wchan); + } + + return DAT_SUCCESS; +} + +/* + * dat_os_thread_kill + * + * Set a blocked thread running. + * + * Input: + * thread_id Pointer to thread_state entry + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + */ +DAT_RETURN +dat_os_thread_destroy ( + IN DAT_OS_THREAD thread_id ) +{ + THREAD_INFO *thread_state = (THREAD_INFO *) thread_id; + + if (thread_state == NULL) + { + return DAT_INVALID_PARAMETER | DAT_INVALID_ARG1; + } + + kill_proc (thread_state->thread_id, SIGTERM, 1); + + kfree(thread_state); /* release thread resources */ + + return DAT_SUCCESS; +} + + +/* + * dat_os_get_time + * + * Return 64 bit value of current time in microseconds. + * + * Input: + * tm User location to place current time + * + * Returns: + * DAT_SUCCESS + */ +DAT_RETURN +dat_os_get_time (DAT_OS_TIMEVAL * loc) +{ + struct timeval tv; + + do_gettimeofday (&tv); + *loc = ((uint64_t) (tv.tv_sec) * 1000000L) + (uint64_t) tv.tv_usec; + + return DAT_SUCCESS; +} + + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl/dat/kdat/linux/dat_osd.h b/branches/WOF2-3/ulp/dapl/dat/kdat/linux/dat_osd.h new file mode 100644 index 00000000..1a4cf15c --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dat/kdat/linux/dat_osd.h @@ -0,0 +1,258 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dat_osd.h + * + * PURPOSE: Operating System Dependent layer + * Description: + * Provide OS dependent data structures & functions with + * a canonical DAT interface. Designed to be portable + * and hide OS specific quirks of common functions. + * + * $Id$ + **********************************************************************/ + +#ifndef _DAT_OSD_H_ +#define _DAT_OSD_H_ + +/* + * This file is defined for Linux systems only, including it on any + * other build will cause an error + */ +#ifndef __linux__ +#error UNDEFINED OS TYPE +#endif /* __linux__ */ + +#ifndef __KERNEL__ +#error "Must compile for the kernel" +#endif /* __KERNEL__ */ + + +#include + + +#include +#include +#include +#include +#include + + +/* + * Thread package + */ +typedef void * DAT_OS_THREAD; + +typedef enum dat_os_thread_state +{ + DAT_OS_THREAD_WAIT, + DAT_OS_THREAD_RUN +} DAT_OS_THREAD_STATE; + + +/* + * Lock functions: Simply use spinlocks at this point. + * + * N.B. No lock can be taken in both common code and an upcall, + * which has the possibility of being called in interrupt + * context. If this is a requirement we need to change + * from buzz locks (spinlock) to semaphores. + */ +typedef spinlock_t DAT_OS_LOCK; + + +STATIC _INLINE_ void dat_os_lock_init(DAT_OS_LOCK *lock) +{ + spin_lock_init( lock ); +} + +STATIC _INLINE_ void dat_os_lock_destroy(DAT_OS_LOCK *lock) +{ + /* Nothing */; +} + +STATIC _INLINE_ void dat_os_lock(DAT_OS_LOCK *lock) +{ + spin_lock(lock); /* down(mutex); */ +} + +STATIC _INLINE_ void dat_os_unlock(DAT_OS_LOCK *lock) +{ + spin_unlock(lock); /* up(mutex); */ +} + + +/* + * Atomic operations + */ +typedef atomic_t DAT_OS_ATOMIC; + +STATIC _INLINE_ void dat_os_atomic_add(int i, DAT_OS_ATOMIC * v) +{ + atomic_add(i,v); +} + +STATIC _INLINE_ void dat_os_atomic_sub(int i, DAT_OS_ATOMIC * v) +{ + atomic_sub(i,v); +} + + +/* + * Memory Functions + */ +STATIC _INLINE_ void *dat_os_alloc(int size) +{ + return kmalloc(size, GFP_ATOMIC); + /* If too much memory is requested from the Linux SLAB + * allocator, we may need to use vmalloc(sz) instead + */ +} + +STATIC _INLINE_ void dat_os_free(void *ptr, int size) +{ + kfree(ptr); + /* If too much memory is requested from the Linux SLAB + * allocator, we may need to use vfree(ptr) instead + */ +} + + +/* + * memory block functions + */ + +STATIC _INLINE_ void * dat_os_memzero(void *loc, int size) +{ + return memset(loc,0,size); +} + +STATIC _INLINE_ void * dat_os_memcpy(void *dest, void *src, int len) +{ + return memcpy(dest,src,len); +} + +STATIC _INLINE_ int dat_os_memcmp(void *mem1, void *mem2, int len) +{ + return memcmp(mem1,mem2,len); +} + +/* + * Timers + */ +typedef uint64_t DAT_OS_TIMEVAL; +typedef struct timer_list *DAT_OS_TIMER; +typedef unsigned long DAT_OS_TICKS; + +DAT_RETURN dat_os_get_time (DAT_OS_TIMEVAL *); + +STATIC _INLINE_ DAT_OS_TICKS dat_os_get_ticks(void) +{ + return jiffies; +} + +STATIC _INLINE_ int dat_os_ticks_to_seconds(DAT_OS_TICKS ticks) +{ + return ticks / HZ; +} + + +/* + * dat_os_set_timer() + * + * Set a timer. The timer will invoke the specified function + * after a number of useconds expires. + * + * Input: + * timer User provided timer structure + * func Function to invoke when timer expires + * data Argument passed to func() + * expires microseconds until timer fires + * + * Returns: + * no return value + * + */ +STATIC _INLINE_ void dat_os_set_timer( + DAT_OS_TIMER timer, + void (*func)(unsigned long), + unsigned long data, + DAT_OS_TIMEVAL expires ) +{ + init_timer(timer); + timer->function = func; + timer->data = data; + /* Change from useconds to jiffies */ + expires += 1000000L / HZ - 1; + expires /= 1000000L / HZ; + /* set the timer */ + timer->expires = jiffies + (unsigned long)expires; + + add_timer(timer); +} + + +/* + * dat_os_timer_cancel() + * + * Cancel a running timer. The timer will invoke the specified + * function after a number of useconds expires. + * + * Input: + * timer Running timer + * + * Returns: + * no return value + * + */ +STATIC _INLINE_ void dat_os_timer_cancel(DAT_OS_TIMER timer) +{ + /* del_timer_sync returns number of times timer was deleted; + * just ignore */ + (void) del_timer_sync(timer); +} + + +/* + * Thread functions: prototypes + */ +DAT_RETURN dat_os_thread_create ( void (*)(void *), void *, + DAT_OS_THREAD_STATE, DAT_OS_THREAD *); +DAT_RETURN dat_os_thread_resume (DAT_OS_THREAD); +DAT_RETURN dat_os_thread_destroy (DAT_OS_THREAD); + + +/* + * Debug helper routines in the Linux kernel + */ +#define dat_os_printf printk +#define dat_os_assert assert +#define dat_os_breakpoint breakpoint + + +#endif /* _DAT_OSD_H_ */ diff --git a/branches/WOF2-3/ulp/dapl/dat/udat/Makefile.cygwin b/branches/WOF2-3/ulp/dapl/dat/udat/Makefile.cygwin new file mode 100644 index 00000000..aad1d67c --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dat/udat/Makefile.cygwin @@ -0,0 +1,271 @@ +# +# Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. +# +# This Software is licensed under either one of the following two licenses: +# +# 1) under the terms of the "Common Public License 1.0" a copy of which is +# in the file LICENSE.txt in the root directory. The license is also +# available from the Open Source Initiative, see +# http://www.opensource.org/licenses/cpl.php. +# OR +# +# 2) under the terms of the "The BSD License" a copy of which is in the file +# LICENSE2.txt in the root directory. The license is also available from +# the Open Source Initiative, see +# http://www.opensource.org/licenses/bsd-license.php. +# +# Licensee has the right to choose either one of the above two licenses. +# +# Redistributions of source code must retain both the above copyright +# notice and either one of the license notices. +# +# Redistributions in binary form must reproduce both the above copyright +# notice, either one of the license notices in the documentation +# and/or other materials provided with the distribution. +# + +#********************************************************************** +# +# MODULE: Makefile +# +# PURPOSE: Makefile for DAT registration module for CYGWIN environment +# +#*********************************************************************/ + + +############################################################## +# Application variables +# + +CP = cp -p -u +AS = $(CROSS_COMPILE)as +LD = $(CROSS_COMPILE)link.exe +CC = $(CROSS_COMPILE)cl.exe +CPP = $(CC) +AR = $(CROSS_COMPILE)ar +NM = $(CROSS_COMPILE)nm +STRIP = $(CROSS_COMPILE)strip +OBJCOPY = $(CROSS_COMPILE)objcopy +OBJDUMP = $(CROSS_COMPILE)objdump +RANLIB = $(CROSS_COMPILE)ranlib +MKDIR = mkdir -p +SED = /bin/sed +SHELL = /bin/sh + +TOPDIR = . + +COMMON = $(TOPDIR)/../common +WINDOWS = $(TOPDIR)/windows + +OBJ_DIR = $(TOPDIR)/Obj +TARGET_DIR = $(TOPDIR)/Target + +SRCDIRS := \ + $(TOPDIR) \ + $(COMMON) \ + $(WINDOWS) + +INCDIRS := \ + $(SRCDIRS) \ + $(TOPDIR)/../include + +vpath %.c . ${SRCDIRS} +vpath %.h . ${INCDIRS} + + +################################################## +# targets +TARLIBS = dat +TARSHLIBS = dat + +# data for user libraries +dat_SOURCES = $(COMMON_SRCS) $(UDAT_SRCS) $(WIN_SRCS) + +UDAT_SRCS = dat_udapl.c + +WIN_SRCS = # dat_osd.c + +COMMON_SRCS = dat_data.c \ + dat_init.c \ + dat_register.c + + + +#################################################### +# compiler options CFLAGS +# + +# common flags +UOPTIONS += /nologo /MDd /W3 /GX /Od /FD /GZ /Gm /Zi + +# common defines +UCOMDEFS += /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "WIN32" /D "_DEBUG" \ + -D_WIN32_WINNT=0x0500 -DWINVER=0x0500 +# other options: /FR /Fd + +# private defines +UPRIVDEFS += /D "__WIN__" /D "__MSC__" /D "__i386__" + +CFLAGS += $(UOPTIONS) $(UCOMDEFS) $(UPRIVDEFS) + +########################################################### +# common included libraries +# +ULDLIBS += kernel32 user32 gdi32 winspool \ + comdlg32 advapi32 shell32 ole32 oleaut32 \ + uuid odbc32 odbccp32 Ws2_32 + + +######################################################### +# link options LDFLAGS +# + +MTARFLAGS= -cr + +TARFLAGS += cr + +# common flags +ULDOPTIONS += /nologo /incremental:no /machine:I386 /debug + +# common directories +ULDDIRS += /LIBPATH:"$(OBJ_DIR)" + +# module entry +ULDENTRY = /noentry + +# specific DLL flags +ifndef NO_DEF_FILE +USE_DEF_FILE = /def:$(WINDOWS)/dat_win.def +endif + +ifndef NO_LIB_FILE +USE_LIB_FILE = $(@:%.dll=/implib:%.lib) +endif + +ifndef NO_PDB_FILE +USE_PDB_FILE = $(@:%.dll=/PDB:%.pdb) +endif + +DLLFLAGS += $(USE_DEF_FILE) $(USE_LIB_FILE) $(USE_PDB_FILE) + +# DLL flags +UDLLFLAGS += /dll $(DLLFLAGS) + +LDFLAGS += $(ULDOPTIONS) $(ULDENTRY) $(ULDDIRS) $(ULDLIBS:%=%.lib) + +# user DLL +LDSHFLAGS += $(LDFLAGS) $(UDLLFLAGS) + + + +############################################################# +# Local functions +# +bsndir = $(notdir $(basename $1)) + +############################################################ +# Common rules +# +define COMPILE +$(CC) -c $(strip ${CFLAGS}) $(strip $(INCDIRS:%=-I%)) $(EXTRA_CFLAGS) $($(@:${OBJ_DIR}/%.obj=%.c_CFLAGS)) /Fo"$@" $< +endef + +define DEF_SET_VAR_SRCS +@echo "$@_VAR_SRCS += $($(basename $(call bsndir,$@))_SOURCES)" >> $@ +endef + +define DEF_SET_VAR_OBJS +@echo "$@_VAR_OBJS += $($(basename $(call bsndir,$@))_OBJECTS)" >> $@ +endef + + + +########################################################################### +# Start rules +# + +all: $(TARSHLIBS:%=${TARGET_DIR}/%.dll) $(TAROBJS:%=${OBJ_DIR}/%.obj) $(TARLIBS:%=${TARGET_DIR}/%.lib) + + +########################################################################## +# Simple objects (user) + +$(TAROBJS:%=${OBJ_DIR}/%.obj): ${OBJ_DIR}/%.obj: %.c + @if [ ! -d $(OBJ_DIR) ]; then mkdir -p $(OBJ_DIR); fi + $(COMPILE) + +$(OBJ_DIR)/%.obj: %.c + $(COMPILE) + + +########################################################################## +# Static libraries +# +$(TARLIBS:%=$(TARGET_DIR)/%.lib): % : %.mk +$(TARLIBS:%=$(TARGET_DIR)/%.lib.mk): Makefile.cygwin + @if [ ! -d $(OBJ_DIR) ]; then mkdir -p $(OBJ_DIR); fi + @if [ ! -d $(TARGET_DIR) ]; then mkdir -p $(TARGET_DIR); fi + @echo "# Do not edit. Automatically generated file." > $@ + @ + @${DEF_SET_VAR_OBJS} + @${DEF_SET_VAR_SRCS} + @ + @echo "SOURCES += \$$($@_VAR_SRCS)" >> $@ + @ + @echo "$(@:%.mk=%): \$$($@_VAR_SRCS:%.c=$(OBJ_DIR)/%.obj) " >> $@ + @echo "$(@:%.mk=%): \$$($@_VAR_OBJS:%.c=$(OBJ_DIR)/%.obj) " >> $@ + @echo -e "\t\$$(AR) \$$(MTARFLAGS) \$$@ \c" >> $@ + @echo -e "\$$($@_VAR_SRCS:%.c=$(OBJ_DIR)/%.obj) \c" >> $@ + @echo "\$$($@_VAR_OBJS) \$$(\$$(@:$(OBJ_DIR)/%.lib=%)_ARFLAGS) " >> $@ + @echo -e "\t\$$(RANLIB) \$$@" >> $@ + + +ifneq ($(MAKECMDGOALS), clean) +ifneq ($(strip $(TARLIBS)),) +-include $(patsubst %,$(OBJ_DIR)/%.lib.mk,$(TARLIBS)) +endif +endif + + +########################################################################## +# Shared libraries +# +$(TARSHLIBS:%=$(TARGET_DIR)/%.dll): % : %.mk +$(TARSHLIBS:%=$(TARGET_DIR)/%.dll.mk): Makefile.cygwin + @if [ ! -d $(OBJ_DIR) ]; then mkdir -p $(OBJ_DIR); fi + @if [ ! -d $(TARGET_DIR) ]; then mkdir -p $(TARGET_DIR); fi + @echo "# Do not edit. Automatically generated file." > $@ + @ + @${DEF_SET_VAR_OBJS} + @${DEF_SET_VAR_SRCS} + @ + @echo "SOURCES += \$$($@_VAR_SRCS)" >> $@ + @ + @echo "$(@:%.mk=%): \$$($@_VAR_SRCS:%.c=$(OBJ_DIR)/%.obj)" >> $@ + @echo "$(@:%.mk=%): \$$($@_VAR_OBJS:%.c=$(OBJ_DIR)/%.obj)" >> $@ + @echo -e "\t\$$(LD) \$$(LDSHFLAGS) /out:\"\$$@\" \c" >> $@ + @echo -e "\$$($@_VAR_SRCS:%.c=$(OBJ_DIR)/%.obj) \c" >> $@ + @echo -e "\$$($@_VAR_OBJS) \c" >> $@ + @echo -e "\$$(LDSHLIBS:%=%) \$$(LIBSHDIRS:%=/LIBPATH:%) \c" >> $@ + + +ifneq ($(MAKECMDGOALS), clean) +ifneq ($(strip $(TARSHLIBS)),) +-include $(patsubst %,$(TARGET_DIR)/%.dll.mk,$(TARSHLIBS)) +endif +endif + + +########################################################################## +# Clean rules +# +CLEANDIRS = $(OBJ_DIR) $(TARGET_DIR) + +CLEANFILES = *.obj *.dll *.lib *.sys *.pdb *.idb *.exp *.ilk *.sbr *.mk + +clean: $(CLEANDIRS) + @echo deleting dump files at $(shell pwd) + @rm -f $(CLEANFILES) + @if [ -d $(OBJ_DIR) ] ; then rm -f $(CLEANFILES:%=$(OBJ_DIR)/%); fi + @if [ -d $(TARGET_DIR) ] ; then rm -f $(CLEANFILES:%=$(TARGET_DIR)/%); fi + diff --git a/branches/WOF2-3/ulp/dapl/dat/udat/Makefile.org b/branches/WOF2-3/ulp/dapl/dat/udat/Makefile.org new file mode 100644 index 00000000..fdb4c64d --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dat/udat/Makefile.org @@ -0,0 +1,86 @@ + + # + # Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + # + # This Software is licensed under either one of the following two licenses: + # + # 1) under the terms of the "Common Public License 1.0" a copy of which is + # in the file LICENSE.txt in the root directory. The license is also + # available from the Open Source Initiative, see + # http://www.opensource.org/licenses/cpl.php. + # OR + # + # 2) under the terms of the "The BSD License" a copy of which is in the file + # LICENSE2.txt in the root directory. The license is also available from + # the Open Source Initiative, see + # http://www.opensource.org/licenses/bsd-license.php. + # + # Licensee has the right to choose either one of the above two licenses. + # + # Redistributions of source code must retain both the above copyright + # notice and either one of the license notices. + # + # Redistributions in binary form must reproduce both the above copyright + # notice, either one of the license notices in the documentation + # and/or other materials provided with the distribution. + # + +#********************************************************************* +# +# MODULE: Makefile +# +# PURPOSE: Makefile for DAT registration module +# +#*********************************************************************/ + +IBA_HOME = ../../.. + +UDAT_ROOT = $(shell /bin/pwd) +UDAT_LINUX = $(UDAT_ROOT)/linux +UDAT_COMMON = $(UDAT_ROOT)/../common + +DAT_HEADERS = $(UDAT_ROOT)/../include +DAT_HEADERS_SYSTEM_PATH = /usr/include/dat + +VPATH = $(UDAT_ROOT) $(UDAT_LINUX) $(UDAT_COMMON) + +SO_TARGET = libdat.so.0.0 +SO_NAME = libdat.so +L_TARGET := libdat.a + +DAT_OBJS = udat.o \ + dat_osd.o \ + dat_dictionary.o \ + dat_dr.o \ + dat_init.o \ + dat_sr.o \ + udat_sr_parser.o \ + dat_strerror.o + +S_OBJS = $(DAT_OBJS) +L_OBJS = $(S_OBJS) + +EXTRA_CFLAGS = -O $(CPPFLAGS) +EXTRA_CFLAGS += -g +EXTRA_CFLAGS += -I. +EXTRA_CFLAGS += -I.. +EXTRA_CFLAGS += -I../.. +EXTRA_CFLAGS += -I../common +EXTRA_CFLAGS += -I./linux +EXTRA_CFLAGS += -I$(DAT_HEADERS) +EXTRA_CFLAGS += -Wall +EXTRA_CFLAGS += -Wstrict-prototypes +EXTRA_CFLAGS += -Wmissing-prototypes +EXTRA_CFLAGS += -Wmissing-declarations +EXTRA_CFLAGS += -Werror +ifdef GPROF +EXTRA_CFLAGS += -pg +endif + +EXTRA_LDFLAGS = -init dat_init +EXTRA_LDFLAGS += -fini dat_fini +EXTRA_LDFLAGS += -ldl +EXTRA_LDFLAGS += -lpthread + +include $(IBA_HOME)/Makefile.config +include $(IBA_HOME)/Makefile.rules diff --git a/branches/WOF2-3/ulp/dapl/dat/udat/Makefile.orig b/branches/WOF2-3/ulp/dapl/dat/udat/Makefile.orig new file mode 100644 index 00000000..2e2f4f9c --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dat/udat/Makefile.orig @@ -0,0 +1,114 @@ +# +# Copyright (c) 2002, Network Appliance, Inc. All rights reserved. +# +# This Software is licensed under the terms of the "IBM Common Public +# License 1.0" a copy of which is in the file LICENSE.txt in the +# root directory. The license is also available from the Open Source +# Initiative, see http://www.opensource.org/licenses/ibmpl.html. +# +# + +#********************************************************************* +# +# MODULE: Makefile +# +# PURPOSE: Makefile for DAT registration module +# +# $Id$ +#*********************************************************************/ + +UDAT_ROOT = $(shell /bin/pwd) +UDAT_LINUX = $(UDAT_ROOT)/linux +UDAT_COMMON = $(UDAT_ROOT)/../common + +VPATH = $(UDAT_ROOT) $(UDAT_LINUX) $(UDAT_COMMON) + +OBJ_PATH = $(UDAT_ROOT)/Obj +TARGET_PATH = $(UDAT_ROOT)/Target + +STATIC = $(TARGET_PATH)/libdat.a +DYNAMIC = $(TARGET_PATH)/libdat.so + +OBJS = $(OBJ_PATH)/udat.o \ + $(OBJ_PATH)/dat_osd.o \ + $(OBJ_PATH)/dat_osd_sr.o \ + $(OBJ_PATH)/dat_dictionary.o \ + $(OBJ_PATH)/dat_dr.o \ + $(OBJ_PATH)/dat_init.o \ + $(OBJ_PATH)/dat_sr.o + +# +# CC definitions +# + +CC = gcc + +CFLAGS = -O $(CPPFLAGS) +CFLAGS += -g +CFLAGS += -I. +CFLAGS += -I.. +CFLAGS += -I../.. +CFLAGS += -I../include +CFLAGS += -I./linux +CFLAGS += -I../common +CFLAGS += -Wall +CFLAGS += -Wstrict-prototypes +CFLAGS += -Wmissing-prototypes +CFLAGS += -Wmissing-declarations +CFLAGS += -Werror +ifdef GPROF +CFLAGS += -pg +endif + +# +# LD definitions +# + +LD = ld + +LDFLAGS = -shared +LDFLAGS += -ldl +LDFLAGS += -init dat_init +LDFLAGS += -fini dat_fini + + +# +# AR definitions +# + +AR = ar + +ARFLAGS = r + + +# +# Rules +# + +all: mkdirs $(DYNAMIC) $(STATIC) + +mkdirs: + @[ -d $(TARGET_PATH) ] || /bin/mkdir -p $(TARGET_PATH) + @[ -d $(OBJ_PATH) ] || /bin/mkdir -p $(OBJ_PATH) + +$(OBJ_PATH)/%.o : %.c + @echo Compiling $< + $(CC) $(CFLAGS) -c $< -o $@ + +$(DYNAMIC): $(OBJS) + @echo Linking $(DYNAMIC) + $(LD) $(LDFLAGS) $^ -o $(DYNAMIC) + +$(STATIC): $(OBJS) + @echo Archiving $(STATIC) + $(AR) $(ARFLAGS) $(STATIC) $^ + +clean: + rm -f $(OBJ_PATH)/*.o + rm -f $(DYNAMIC) + rm -f $(STATIC) + +tidy: + rm -f $(UDAT_ROOT)/*~ + rm -f $(UDAT_LINUX)/*~ + rm -f $(UDAT_COMMON)/*~ diff --git a/branches/WOF2-3/ulp/dapl/dat/udat/SOURCES b/branches/WOF2-3/ulp/dapl/dat/udat/SOURCES new file mode 100644 index 00000000..efcc8b9d --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dat/udat/SOURCES @@ -0,0 +1,31 @@ +!if $(FREEBUILD) +TARGETNAME=dat +!else +TARGETNAME=datd +!endif +TARGETPATH=..\..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE=DYNLINK +DLLENTRY=_DllMainCRTStartup +!if $(_NT_TOOLS_VERSION) == 0x700 +# DDK +DLLDEF=$O\udat_exports.def +!else +# WDK +DLLDEF=$(OBJ_PATH)\$O\udat_exports.def +!endif +USE_MSVCRT=1 + +SOURCES=udat.rc \ + udat.c \ + udat_sr_parser.c \ + udat_sources.c + +INCLUDES=windows;..\common;..\include; +RCOPTIONS=/I..\..\..\..\inc; + +USER_C_FLAGS=$(USER_C_FLAGS) -DEXPORT_DAT_SYMBOLS + +TARGETLIBS= \ + $(SDK_LIB_PATH)\kernel32.lib + +MSC_WARNING_LEVEL= /W3 diff --git a/branches/WOF2-3/ulp/dapl/dat/udat/dat.conf b/branches/WOF2-3/ulp/dapl/dat/udat/dat.conf new file mode 100644 index 00000000..3eaa4782 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dat/udat/dat.conf @@ -0,0 +1,7 @@ +# DAT configuration file +##################################### + +HcaPort1 u1.1 threadsafe default dapl.dll ri.1.1 "IbalHca0 1" " " +HcaPort2 u1.1 threadsafe default dapl.dll ri.1.1 "IbalHca0 2" " " +# HcaPort1d u1.1 threadsafe default dapld.dll ri.1.1 "IbalHca0 1" " " +# HcaPort2d u1.1 threadsafe default dapld.dll ri.1.1 "IbalHca0 2" " " diff --git a/branches/WOF2-3/ulp/dapl/dat/udat/ibhosts b/branches/WOF2-3/ulp/dapl/dat/udat/ibhosts new file mode 100644 index 00000000..1463f9d8 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dat/udat/ibhosts @@ -0,0 +1,7 @@ +# DAPL IB hosts GID configuration +#hostname Network Port GUID +#-------- ------------------ ------------------ +#endrin_ib0 0xfe80000000000000 0x00066a00a0000405 +#rockaway_ib0 0xfe80000000000000 0x00066a00a0000117 +#gack_ib0 0xfe80000000000000 0x00066a00a00001f2 +#gack_ib1 0xfe80000000000000 0x00066a01a00001f2 diff --git a/branches/WOF2-3/ulp/dapl/dat/udat/linux/dat-1.1.spec b/branches/WOF2-3/ulp/dapl/dat/udat/linux/dat-1.1.spec new file mode 100644 index 00000000..1f0c0122 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dat/udat/linux/dat-1.1.spec @@ -0,0 +1,80 @@ +# Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. +# +# This Software is licensed under either one of the following two licenses: +# +# 1) under the terms of the "Common Public License 1.0" a copy of which is +# in the file LICENSE.txt in the root directory. The license is also +# available from the Open Source Initiative, see +# http://www.opensource.org/licenses/cpl.php. +# OR +# +# 2) under the terms of the "The BSD License" a copy of which is in the file +# LICENSE2.txt in the root directory. The license is also available from +# the Open Source Initiative, see +# http://www.opensource.org/licenses/bsd-license.php. +# +# Licensee has the right to choose either one of the above two licenses. +# +# Redistributions of source code must retain both the above copyright +# notice and either one of the license notices. +# +# Redistributions in binary form must reproduce both the above copyright +# notice, either one of the license notices in the documentation +# and/or other materials provided with the distribution. +# +# +# DAT Registry RPM SPEC file +# + +%define make_dir udat + +# +# Preamble +# + +Summary: DAT Registry +Name: dat +Version: 1.1 +Release: 0 +Vendor: Dat Collaborative +Exclusiveos: Linux +Exclusivearch: i386 +License: BSD and CPL +Group: System/Libraries +Source: %{name}-%{version}.tgz +URL: http://www.datcollaborative.org + +%description +This package contains the DAT Registry. + +# +# Preparation +# + +%prep +%setup -n dat + +# +# Build +# + +%build +cd %{make_dir} +make + +# +# Install +# + +%install +cd %{make_dir} +make install + +# +# Files +# + +%files +/usr/include/dat +/usr/lib/libdat.so +/usr/lib/libdat.a diff --git a/branches/WOF2-3/ulp/dapl/dat/udat/linux/dat_osd.c b/branches/WOF2-3/ulp/dapl/dat/udat/linux/dat_osd.c new file mode 100644 index 00000000..3101eea6 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dat/udat/linux/dat_osd.c @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dat_osd.c + * + * PURPOSE: Operating System Dependent layer + * Description: + * Provide OS dependent functions with a canonical DAPL + * interface. Designed to be portable and hide OS specific quirks + * of common functions. + * + * $Id$ + **********************************************************************/ + +#include "dat_osd.h" + + +/********************************************************************* + * * + * Constants * + * * + *********************************************************************/ + +#define DAT_DBG_TYPE_ENV "DAT_DBG_TYPE" +#define DAT_DBG_DEST_ENV "DAT_DBG_DEST" + + +/********************************************************************* + * * + * Enumerations * + * * + *********************************************************************/ + +typedef int DAT_OS_DBG_DEST; + +typedef enum +{ + DAT_OS_DBG_DEST_STDOUT = 0x1, + DAT_OS_DBG_DEST_SYSLOG = 0x2, + DAT_OS_DBG_DEST_ALL = 0x3 +} DAT_OS_DBG_DEST_TYPE; + + +/********************************************************************* + * * + * Global Variables * + * * + *********************************************************************/ + +static DAT_OS_DBG_TYPE_VAL g_dbg_type = 0; +static DAT_OS_DBG_DEST g_dbg_dest = DAT_OS_DBG_DEST_STDOUT; + + +/*********************************************************************** + * Function: dat_os_dbg_init + ***********************************************************************/ + +void +dat_os_dbg_init( void ) +{ + char *dbg_type; + char *dbg_dest; + + if ( NULL != (dbg_type = dat_os_getenv (DAT_DBG_TYPE_ENV)) ) + { + g_dbg_type = dat_os_strtol(dbg_type, NULL, 0); + } + + if ( NULL != (dbg_dest = dat_os_getenv (DAT_DBG_DEST_ENV)) ) + { + g_dbg_dest = dat_os_strtol(dbg_dest, NULL, 0); + } +} + + +/*********************************************************************** + * Function: dat_os_dbg_print + ***********************************************************************/ + +void +dat_os_dbg_print ( + DAT_OS_DBG_TYPE_VAL type, + const char * fmt, + ...) +{ + if ( (DAT_OS_DBG_TYPE_ERROR == type) || (type & g_dbg_type) ) + { + va_list args; + + va_start(args, fmt); + + if ( DAT_OS_DBG_DEST_STDOUT & g_dbg_dest ) + { + vfprintf(stderr, fmt, args); + fflush(stderr); + } + + if ( DAT_OS_DBG_DEST_SYSLOG & g_dbg_dest ) + { + vsyslog(LOG_USER | LOG_DEBUG, fmt, args); + } + + va_end(args); + } +} + + +/*********************************************************************** + * Function: dat_os_library_load + ***********************************************************************/ + +DAT_RETURN +dat_os_library_load ( + const char *library_path, + DAT_OS_LIBRARY_HANDLE *library_handle_ptr) +{ + DAT_OS_LIBRARY_HANDLE library_handle; + + if ( NULL != (library_handle = dlopen(library_path, RTLD_NOW)) ) + { + if ( NULL != library_handle_ptr ) + { + *library_handle_ptr = library_handle; + } + + return DAT_SUCCESS; + } + else + { + dat_os_dbg_print(DAT_OS_DBG_TYPE_ERROR, + "DAT: library load failure: %s\n", + dlerror()); + return DAT_INTERNAL_ERROR; + } +} + + +/*********************************************************************** + * Function: dat_os_library_unload + ***********************************************************************/ + +DAT_RETURN +dat_os_library_unload ( + const DAT_OS_LIBRARY_HANDLE library_handle) +{ + if ( 0 != dlclose(library_handle) ) + { + return DAT_INTERNAL_ERROR; + } + else + { + return DAT_SUCCESS; + } +} diff --git a/branches/WOF2-3/ulp/dapl/dat/udat/linux/dat_osd.h b/branches/WOF2-3/ulp/dapl/dat/udat/linux/dat_osd.h new file mode 100644 index 00000000..d7f5e312 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dat/udat/linux/dat_osd.h @@ -0,0 +1,394 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dat_osd.h + * + * PURPOSE: Operating System Dependent layer + * Description: + * Provide OS dependent data structures & functions with + * a canonical DAT interface. Designed to be portable + * and hide OS specific quirks of common functions. + * + * $Id$ + **********************************************************************/ + +#ifndef _DAT_OSD_H_ +#define _DAT_OSD_H_ + +/* + * This file is defined for Linux systems only, including it on any + * other build will cause an error + */ +#ifndef __linux__ +#error "UNDEFINED OS TYPE" +#endif /* __linux__ */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef STATIC +#define STATIC static +#endif /* STATIC */ + +#ifndef INLINE +#define INLINE __inline__ +#endif /* INLINE */ + + +/********************************************************************* + * * + * Debuging * + * * + *********************************************************************/ + +#define dat_os_assert(expr) assert(expr) + +typedef int DAT_OS_DBG_TYPE_VAL; + +typedef enum +{ + DAT_OS_DBG_TYPE_ERROR = 0x1, + DAT_OS_DBG_TYPE_GENERIC = 0x2, + DAT_OS_DBG_TYPE_SR = 0x4, + DAT_OS_DBG_TYPE_DR = 0x8, + DAT_OS_DBG_TYPE_PROVIDER_API = 0x10, + DAT_OS_DBG_TYPE_CONSUMER_API = 0x20, + DAT_OS_DBG_TYPE_ALL = 0xff +} DAT_OS_DBG_TYPE; + +extern void +dat_os_dbg_init ( void ); + +extern void +dat_os_dbg_print ( + DAT_OS_DBG_TYPE_VAL type, + const char * fmt, + ...); + + +/********************************************************************* + * * + * Utility Functions * + * * + *********************************************************************/ + +#define DAT_ERROR(Type,SubType) ((DAT_RETURN)(DAT_CLASS_ERROR | Type | SubType)) + +typedef size_t DAT_OS_SIZE; +typedef void * DAT_OS_LIBRARY_HANDLE; + +extern DAT_RETURN +dat_os_library_load ( + const char *library_path, + DAT_OS_LIBRARY_HANDLE *library_handle_ptr ); + +STATIC INLINE void * +dat_os_library_sym ( + DAT_OS_LIBRARY_HANDLE library_handle, + char *sym) +{ + return dlsym(library_handle, sym); +} + +extern DAT_RETURN +dat_os_library_unload ( + const DAT_OS_LIBRARY_HANDLE library_handle ); + +STATIC INLINE char * +dat_os_getenv ( + const char *name) +{ + return getenv(name); +} + +STATIC INLINE long int +dat_os_strtol ( + const char *nptr, + char **endptr, + int base) +{ + return strtol(nptr, endptr, base); +} + +STATIC INLINE DAT_OS_SIZE +dat_os_strlen ( + const char *s ) +{ + return strlen(s); +} + +STATIC INLINE int +dat_os_strncmp ( + const char *s1, + const char *s2, + DAT_OS_SIZE n) +{ + return strncmp(s1, s2, n); +} + +STATIC INLINE void * +dat_os_strncpy ( + char *dest, + const char *src, + DAT_OS_SIZE len) +{ + return strncpy (dest, src, len); +} + +STATIC INLINE DAT_BOOLEAN +dat_os_isblank( + int c) +{ + if ( (' ' == c) || ('\t' == c) ) + { + return DAT_TRUE; + } + else + { + return DAT_FALSE; + } +} + +STATIC INLINE DAT_BOOLEAN +dat_os_isdigit( + int c) +{ + if ( isdigit(c) ) + { + return DAT_TRUE; + } + else + { + return DAT_FALSE; + } +} + +STATIC INLINE void +dat_os_usleep( + unsigned long usec) +{ + usleep(usec); +} + + +/********************************************************************* + * * + * Memory Functions * + * * + *********************************************************************/ + +STATIC INLINE void * +dat_os_alloc ( + int size) +{ + return malloc (size); +} + +STATIC INLINE void +dat_os_free ( + void *ptr, + int size) +{ + free (ptr); +} + +STATIC INLINE void * +dat_os_memset (void *loc, int c, DAT_OS_SIZE size) +{ + return memset (loc, c, size); +} + + +/********************************************************************* + * * + * File I/O * + * * + *********************************************************************/ + +typedef FILE DAT_OS_FILE; +typedef fpos_t DAT_OS_FILE_POS; + + +STATIC INLINE DAT_OS_FILE * +dat_os_fopen ( + const char * path) +{ + /* always open files in read only mode*/ + return fopen(path, "r"); +} + +STATIC INLINE DAT_RETURN +dat_os_fgetpos ( + DAT_OS_FILE *file, + DAT_OS_FILE_POS *pos) +{ + if ( 0 == fgetpos(file, pos) ) + { + return DAT_SUCCESS; + } + else + { + return DAT_INTERNAL_ERROR; + } +} + +STATIC INLINE DAT_RETURN +dat_os_fsetpos ( + DAT_OS_FILE *file, + DAT_OS_FILE_POS *pos) +{ + if ( 0 == fsetpos(file, pos) ) + { + return DAT_SUCCESS; + } + else + { + return DAT_INTERNAL_ERROR; + } +} + +/* dat_os_fgetc() returns EOF on error or end of file. */ +STATIC INLINE int +dat_os_fgetc ( + DAT_OS_FILE *file) +{ + return fgetc(file); +} + +/* dat_os_fgetc() returns EOF on error or end of file. */ +STATIC INLINE int +dat_os_fputc ( + DAT_OS_FILE *file, int c) +{ + return fputc(c, file); +} + +/* dat_os_fread returns the number of bytes read from the file. */ +STATIC INLINE DAT_OS_SIZE +dat_os_fread ( + DAT_OS_FILE *file, + char *buf, + DAT_OS_SIZE len) +{ + return fread(buf, sizeof(char), len, file); +} + +STATIC INLINE DAT_RETURN +dat_os_fclose ( + DAT_OS_FILE *file) +{ + if ( 0 == fclose(file) ) { return DAT_SUCCESS; } + else { return DAT_INTERNAL_ERROR; } +} + + +/********************************************************************* + * * + * Locks * + * * + *********************************************************************/ + +typedef pthread_mutex_t DAT_OS_LOCK; + + +/* lock functions */ +STATIC INLINE DAT_RETURN +dat_os_lock_init ( + IN DAT_OS_LOCK *m) +{ + /* pthread_mutex_init always returns 0 */ + pthread_mutex_init(m, NULL); + + return DAT_SUCCESS; +} + +STATIC INLINE DAT_RETURN +dat_os_lock ( + IN DAT_OS_LOCK *m) +{ + if (0 == pthread_mutex_lock(m)) + { + return DAT_SUCCESS; + } + else + { + return DAT_INTERNAL_ERROR; + } +} + +STATIC INLINE DAT_RETURN +dat_os_unlock ( + IN DAT_OS_LOCK *m) +{ + if (0 == pthread_mutex_unlock(m)) + { + return DAT_SUCCESS; + } + else + { + return DAT_INTERNAL_ERROR; + } +} + +STATIC INLINE DAT_RETURN +dat_os_lock_destroy ( + IN DAT_OS_LOCK *m) +{ + if (0 == pthread_mutex_destroy(m)) + { + return DAT_SUCCESS; + } + else + { + return DAT_INTERNAL_ERROR; + } +} + + +#endif /* _DAT_OSD_H_ */ + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ + diff --git a/branches/WOF2-3/ulp/dapl/dat/udat/makefile b/branches/WOF2-3/ulp/dapl/dat/udat/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dat/udat/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\..\inc\openib.def diff --git a/branches/WOF2-3/ulp/dapl/dat/udat/makefile.wnd b/branches/WOF2-3/ulp/dapl/dat/udat/makefile.wnd new file mode 100644 index 00000000..0b4e4f9e --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dat/udat/makefile.wnd @@ -0,0 +1,144 @@ +# +# Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. +# +# This Software is licensed under either one of the following two licenses: +# +# 1) under the terms of the "Common Public License 1.0" a copy of which is +# in the file LICENSE.txt in the root directory. The license is also +# available from the Open Source Initiative, see +# http://www.opensource.org/licenses/cpl.php. +# OR +# +# 2) under the terms of the "The BSD License" a copy of which is in the file +# LICENSE2.txt in the root directory. The license is also available from +# the Open Source Initiative, see +# http://www.opensource.org/licenses/bsd-license.php. +# +# Licensee has the right to choose either one of the above two licenses. +# +# Redistributions of source code must retain both the above copyright +# notice and either one of the license notices. +# +# Redistributions in binary form must reproduce both the above copyright +# notice, either one of the license notices in the documentation +# and/or other materials provided with the distribution. +# + +#********************************************************************* +# +# MODULE: Makefile +# +# PURPOSE: Makefile for DAT registration module +# +# $Id$ +#*********************************************************************/ + +#********************************************************************* +# +# Dot Directives +# +#*********************************************************************/ + +.SUFFIXES : # clear the .SUFFIXES list +.SUFFIXES : .c # initialize .SUFFIXES list + + +#********************************************************************* +# +# Macros +# +#*********************************************************************/ + +UDAT_ROOT = . +UDAT_COMMON = $(UDAT_ROOT)/../common +UDAT_WINDOWS = $(UDAT_ROOT)/windows + +OBJ_PATH = $(UDAT_ROOT)/Obj +TARGET_PATH = $(UDAT_ROOT)/Target + +OBJS = \ + $(OBJ_PATH)/udat.obj \ + $(OBJ_PATH)/dat_osd.obj \ + $(OBJ_PATH)/dat_dictionary.obj \ + $(OBJ_PATH)/dat_dr.obj \ + $(OBJ_PATH)/dat_init.obj \ + $(OBJ_PATH)/dat_sr.obj \ + $(OBJ_PATH)/udat_sr_parser.obj \ + $(OBJ_PATH)/dat_strerror.obj + +LIBRARY = $(TARGET_PATH)/dat.dll + +# +# Compiler +# + +CC = cl + +INC_FLAGS = \ + /I . \ + /I ../include \ + /I $(UDAT_COMMON) \ + /I $(UDAT_WINDOWS) \ + /I ../../../shared/include \ + /I ../../../winuser/include + +CC_FLAGS = \ + /nologo /Zel /Zp1 /Gy /W3 /Gd /QIfdiv- /QIf /QI0f /GB /Gi- /Gm- /GX- \ + /GR- /GF -Z7 /Od /Oi /Oy- /DWIN32 /D_X86_ -D__i386__ $(INC_FLAGS) + + +# +# Linker +# + +LINK = link + +LIBS = libc.lib kernel32.lib + +LINK_FLAGS = \ + /nologo /dll /DEF:$(UDAT_WINDOWS)/dat_win.def \ + /DEBUG /incremental:no /machine:I386 $(LIBS) + +# +# System Utilities +# + +RM = rm -f + + +#********************************************************************* +# +# Inference Rules +# +#*********************************************************************/ + +{$(UDAT_ROOT)}.c{$(OBJ_PATH)}.obj: + $(CC) $(CC_FLAGS) /Fo$@ /c $< + +{$(UDAT_COMMON)}.c{$(OBJ_PATH)}.obj: + $(CC) $(CC_FLAGS) /Fo$@ /c $< + +{$(UDAT_WINDOWS)}.c{$(OBJ_PATH)}.obj: + $(CC) $(CC_FLAGS) /Fo$@ /c $< + + +#********************************************************************* +# +# Description Blocks +# +#*********************************************************************/ + +all : mkdirs $(LIBRARY) + +mkdirs : + if not exist "$(OBJ_PATH)" mkdir "$(OBJ_PATH)" + if not exist "$(TARGET_PATH)" mkdir "$(TARGET_PATH)" + +$(LIBRARY) : $(OBJS) + $(LINK) $(LINK_FLAGS) /out:$(LIBRARY) $(OBJS) + +clean : + $(RM) $(OBJS) + $(RM) $(LIBRARY) + $(RM) $(TARGET_PATH)/*.pdb $(TARGET_PATH)/*.exp $(TARGET_PATH)/*.lib + diff --git a/branches/WOF2-3/ulp/dapl/dat/udat/udat.c b/branches/WOF2-3/ulp/dapl/dat/udat/udat.c new file mode 100644 index 00000000..99678152 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dat/udat/udat.c @@ -0,0 +1,420 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: udat.c + * + * PURPOSE: DAT Provider and Consumer registry functions. + * + * $Id$ + **********************************************************************/ + +#include +#include /* Provider API function prototypes */ + +#include "dat_dr.h" +#include "dat_init.h" +#include "dat_osd.h" +#ifndef DAT_NO_STATIC_REGISTRY +#include "dat_sr.h" +#endif + + +#define UDAT_IS_BAD_POINTER(p) ( NULL == (p) ) + +/********************************************************************* + * * + * Internal Function Declarations * + * * + *********************************************************************/ + +DAT_BOOLEAN +udat_check_state ( void ); + + +/********************************************************************* + * * + * External Function Definitions * + * * + *********************************************************************/ + + +/* + * + * Provider API + * + */ + + +/*********************************************************************** + * Function: dat_registry_add_provider + ***********************************************************************/ + +DAT_RETURN DAT_API +dat_registry_add_provider ( + IN DAT_PROVIDER *provider, + IN const DAT_PROVIDER_INFO *provider_info ) +{ + DAT_DR_ENTRY entry; + + dat_os_dbg_print (DAT_OS_DBG_TYPE_PROVIDER_API, + "DAT Registry: dat_registry_add_provider () called\n"); + + if ( UDAT_IS_BAD_POINTER (provider) ) + { + return DAT_ERROR (DAT_INVALID_PARAMETER, DAT_INVALID_ARG1); + } + + if ( UDAT_IS_BAD_POINTER (provider_info) ) + { + return DAT_ERROR (DAT_INVALID_PARAMETER, DAT_INVALID_ARG2); + } + + if ( DAT_FALSE == udat_check_state () ) + { + return DAT_ERROR (DAT_INVALID_STATE, 0); + } + + entry.ref_count = 0; + entry.ia_open_func = provider->ia_open_func; + entry.info = *provider_info; + + return dat_dr_insert (provider_info, &entry); +} + + +//*********************************************************************** +// Function: dat_registry_remove_provider +//*********************************************************************** + +DAT_RETURN DAT_API +dat_registry_remove_provider ( + IN DAT_PROVIDER *provider, + IN const DAT_PROVIDER_INFO *provider_info ) +{ + dat_os_dbg_print (DAT_OS_DBG_TYPE_PROVIDER_API, + "DAT Registry: dat_registry_remove_provider () called\n"); + + if ( UDAT_IS_BAD_POINTER (provider) ) + { + return DAT_ERROR (DAT_INVALID_PARAMETER, DAT_INVALID_ARG1); + } + + if ( DAT_FALSE == udat_check_state () ) + { + return DAT_ERROR (DAT_INVALID_STATE, 0); + } + + return dat_dr_remove (provider_info); +} + + +/* + * + * Consumer API + * + */ + +/*********************************************************************** + * Function: dat_ia_open + ***********************************************************************/ + +DAT_RETURN DAT_API +dat_ia_openv ( + IN const DAT_NAME_PTR name, + IN DAT_COUNT async_event_qlen, + INOUT DAT_EVD_HANDLE *async_event_handle, + OUT DAT_IA_HANDLE *ia_handle, + IN DAT_UINT32 dapl_major, + IN DAT_UINT32 dapl_minor, + IN DAT_BOOLEAN thread_safety ) +{ + DAT_IA_OPEN_FUNC ia_open_func; + DAT_PROVIDER_INFO info; + DAT_RETURN status; + DAT_OS_SIZE len; + + dat_os_dbg_print (DAT_OS_DBG_TYPE_CONSUMER_API, + "DAT Registry: dat_ia_open () called\n"); + + if ( UDAT_IS_BAD_POINTER (name) ) + { + return DAT_ERROR (DAT_INVALID_PARAMETER, DAT_INVALID_ARG1); + } + + len = dat_os_strlen(name); + + if ( DAT_NAME_MAX_LENGTH < len ) + { + return DAT_ERROR (DAT_INVALID_PARAMETER, DAT_INVALID_ARG1); + } + + if ( UDAT_IS_BAD_POINTER (ia_handle) ) + { + return DAT_ERROR (DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_IA); + } + + if ( DAT_FALSE == udat_check_state () ) + { + return DAT_ERROR (DAT_INVALID_STATE, 0); + } + + dat_os_strncpy(info.ia_name, name, len); + info.ia_name[len] = '\0'; + + info.dapl_version_major = dapl_major; + info.dapl_version_minor = dapl_minor; + info.is_thread_safe = thread_safety; + + /* + * Since DAT allows providers to be loaded by either the static + * registry or explicitly through OS dependent methods, do not + * return an error if no providers are loaded via the static registry. + * Don't even bother calling the static registry if DAT is compiled + * with no static registry support. + */ + +#ifndef DAT_NO_STATIC_REGISTRY + (void) dat_sr_provider_open ( &info ); +#endif + + status = dat_dr_provider_open ( &info, &ia_open_func); + if ( status != DAT_SUCCESS ) + { + dat_os_dbg_print (DAT_OS_DBG_TYPE_CONSUMER_API, + "DAT Registry: dat_ia_open () provider information " + "for IA name %s not found in dynamic registry\n", + info.ia_name); + + return status; + } + + return (*ia_open_func) (name, + async_event_qlen, + async_event_handle, + ia_handle); +} + + +/************************************************************************ + * Function: dat_ia_close + ***********************************************************************/ + +DAT_RETURN DAT_API +dat_ia_close ( + IN DAT_IA_HANDLE ia_handle, + IN DAT_CLOSE_FLAGS ia_flags) +{ + DAT_PROVIDER *provider; + DAT_PROVIDER_ATTR provider_attr; + DAT_RETURN status; + const char *ia_name; + + dat_os_dbg_print (DAT_OS_DBG_TYPE_CONSUMER_API, + "DAT Registry: dat_ia_close () called\n"); + + if ( UDAT_IS_BAD_POINTER (ia_handle) ) + { + return DAT_ERROR (DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_IA); + } + + if ( DAT_FALSE == udat_check_state () ) + { + return DAT_ERROR (DAT_INVALID_STATE, 0); + } + + provider = DAT_HANDLE_TO_PROVIDER(ia_handle); + + if ( !provider ) + return DAT_INVALID_HANDLE; + + ia_name = provider->device_name; + + if ( DAT_SUCCESS != (status = dat_ia_query (ia_handle, + NULL, + 0, + NULL, + DAT_PROVIDER_FIELD_ALL, + &provider_attr)) ) + { + dat_os_dbg_print (DAT_OS_DBG_TYPE_CONSUMER_API, + "DAT Registry: query function for %s provider failed\n", + ia_name); + } + else if ( DAT_SUCCESS != (status = + (*provider->ia_close_func)(ia_handle, ia_flags)) ) + { + dat_os_dbg_print (DAT_OS_DBG_TYPE_CONSUMER_API, + "DAT Registry: close function for %s provider failed\n", + ia_name); + } + else + { + DAT_PROVIDER_INFO info; + DAT_OS_SIZE len; + + len = dat_os_strlen(ia_name); + + dat_os_assert( len <= DAT_NAME_MAX_LENGTH ); + + dat_os_strncpy(info.ia_name, ia_name, len); + info.ia_name[len] = '\0'; + + info.dapl_version_major = provider_attr.dapl_version_major; + info.dapl_version_minor = provider_attr.dapl_version_minor; + info.is_thread_safe = provider_attr.is_thread_safe; + + status = dat_dr_provider_close ( &info ); + if ( DAT_SUCCESS != status ) + { + dat_os_dbg_print (DAT_OS_DBG_TYPE_CONSUMER_API, + "DAT Registry: dynamic registry unable to close " + "provider for IA name %s\n", + ia_name); + } + +#ifndef DAT_NO_STATIC_REGISTRY + status = dat_sr_provider_close ( &info ); + if ( DAT_SUCCESS != status ) + { + dat_os_dbg_print (DAT_OS_DBG_TYPE_CONSUMER_API, + "DAT Registry: static registry unable to close " + "provider for IA name %s\n", + ia_name); + } +#endif + } + + return status; +} + + +//*********************************************************************** +// Function: dat_registry_list_providers +//*********************************************************************** + +DAT_RETURN DAT_API +dat_registry_list_providers ( + IN DAT_COUNT max_to_return, + OUT DAT_COUNT *entries_returned, + OUT DAT_PROVIDER_INFO * (dat_provider_list[])) +{ + DAT_RETURN dat_status; + + dat_status = DAT_SUCCESS; + dat_os_dbg_print (DAT_OS_DBG_TYPE_CONSUMER_API, + "DAT Registry: dat_registry_list_providers () called\n"); + + if ( DAT_FALSE == udat_check_state () ) + { + return DAT_ERROR (DAT_INVALID_STATE, 0); + } + + if ( ( UDAT_IS_BAD_POINTER (entries_returned) ) ) + { + return DAT_ERROR (DAT_INVALID_PARAMETER, DAT_INVALID_ARG2); + } + + if (0 != max_to_return && ( UDAT_IS_BAD_POINTER (dat_provider_list) ) ) + { + return DAT_ERROR (DAT_INVALID_PARAMETER, DAT_INVALID_ARG3); + } + + if ( 0 == max_to_return ) + { + /* the user is allowed to call with max_to_return set to zero. + * in which case we simply return (in *entries_returned) the + * number of providers currently installed. We must also + * (per spec) return an error + */ +#ifndef DAT_NO_STATIC_REGISTRY + (void) dat_sr_size ( entries_returned ); +#else + (void) dat_dr_size ( entries_returned ); +#endif + return DAT_ERROR (DAT_INVALID_PARAMETER, DAT_INVALID_ARG1); + } + else + { +#ifndef DAT_NO_STATIC_REGISTRY + dat_status = dat_sr_list (max_to_return, + entries_returned, + dat_provider_list); +#else + dat_status = dat_dr_list (max_to_return, + entries_returned, + dat_provider_list); +#endif + } + return dat_status; +} + + +/********************************************************************* + * * + * Internal Function Definitions * + * * + *********************************************************************/ + + +//*********************************************************************** +// Function: udat_check_state +//*********************************************************************** + +/* + * This function returns TRUE if the DAT registry is in a state capable + * of handling DAT API calls and false otherwise. + */ + +DAT_BOOLEAN +udat_check_state ( void ) +{ + DAT_MODULE_STATE state; + DAT_BOOLEAN status = DAT_FALSE; + + state = dat_module_get_state (); + + if ( DAT_MODULE_STATE_UNINITIALIZED == state ) + { + dat_init (); + state = dat_module_get_state (); + } + if ( DAT_MODULE_STATE_INITIALIZED == state ) + { + status = DAT_TRUE; + } + return status; +} + + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl/dat/udat/udat.rc b/branches/WOF2-3/ulp/dapl/dat/udat/udat.rc new file mode 100644 index 00000000..6f200001 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dat/udat/udat.rc @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2007 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#if DBG +#define VER_FILEDESCRIPTION_STR "User-mode Direct Access Transport Library v1.1 (Debug)" +#define VER_INTERNALNAME_STR "datd.dll" +#define VER_ORIGINALFILENAME_STR "datd.dll" +#else +#define VER_FILEDESCRIPTION_STR "User-mode Direct Access Transport Library v1.1" +#define VER_INTERNALNAME_STR "dat.dll" +#define VER_ORIGINALFILENAME_STR "dat.dll" +#endif + +#include diff --git a/branches/WOF2-3/ulp/dapl/dat/udat/udat_exports.src b/branches/WOF2-3/ulp/dapl/dat/udat/udat_exports.src new file mode 100644 index 00000000..1ee36f72 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dat/udat/udat_exports.src @@ -0,0 +1,15 @@ +#if DBG +LIBRARY datd.dll +#else +LIBRARY dat.dll +#endif + +#ifndef _WIN64 +EXPORTS +dat_ia_openv +dat_ia_close +dat_registry_list_providers +dat_strerror +dat_registry_add_provider +dat_registry_remove_provider +#endif diff --git a/branches/WOF2-3/ulp/dapl/dat/udat/udat_sources.c b/branches/WOF2-3/ulp/dapl/dat/udat/udat_sources.c new file mode 100644 index 00000000..4232086d --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dat/udat/udat_sources.c @@ -0,0 +1,33 @@ +/* + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ +/* + * Include all files that are not in children directories. + */ + +#include "../common/dat_dictionary.c" +#include "../common/dat_dr.c" +#include "../common/dat_init.c" +#include "../common/dat_sr.c" +#include "../common/dat_strerror.c" +#include "windows/dat_osd.c" diff --git a/branches/WOF2-3/ulp/dapl/dat/udat/udat_sr_parser.c b/branches/WOF2-3/ulp/dapl/dat/udat/udat_sr_parser.c new file mode 100644 index 00000000..81a24c49 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dat/udat/udat_sr_parser.c @@ -0,0 +1,1551 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dat_sr_parser.c + * + * PURPOSE: static registry parser + * + * $Id$ + **********************************************************************/ + + +#include "udat_sr_parser.h" +#include "dat_sr.h" + + +/********************************************************************* + * * + * Constants * + * * + *********************************************************************/ + +#define DAT_SR_CONF_ENV "DAT_OVERRIDE" +#define DAT_SR_SYSTEM_DRIVE "SystemDrive" +#define DAT_SR_DRIVE_DEFAULT "C:" +#define DAT_SR_CONF_DEFAULT "\\Dat\\dat.conf" +#define DAT_SR_TOKEN_THREADSAFE "threadsafe" +#define DAT_SR_TOKEN_NONTHREADSAFE "nonthreadsafe" +#define DAT_SR_TOKEN_DEFAULT "default" +#define DAT_SR_TOKEN_NONDEFAULT "nondefault" + +#define DAT_SR_CHAR_NEWLINE '\n' +#define DAT_SR_CHAR_COMMENT '#' +#define DAT_SR_CHAR_QUOTE '"' +#define DAT_SR_CHAR_BACKSLASH '\\' + + +/********************************************************************* + * * + * Enumerations * + * * + *********************************************************************/ + +typedef enum +{ + DAT_SR_TOKEN_STRING, /* text field (both quoted or unquoted) */ + DAT_SR_TOKEN_EOR, /* end of record (newline) */ + DAT_SR_TOKEN_EOF /* end of file */ +} DAT_SR_TOKEN_TYPE; + +typedef enum +{ + DAT_SR_API_UDAT, + DAT_SR_API_KDAT +} DAT_SR_API_TYPE; + + +/********************************************************************* + * * + * Structures * + * * + *********************************************************************/ + +typedef struct +{ + DAT_SR_TOKEN_TYPE type; + char * value; /* valid if type is DAT_SR_TOKEN_STRING */ + DAT_OS_SIZE value_len; +} DAT_SR_TOKEN; + +typedef struct DAT_SR_STACK_NODE +{ + DAT_SR_TOKEN token; + struct DAT_SR_STACK_NODE *next; +} DAT_SR_STACK_NODE; + +typedef struct +{ + DAT_UINT32 major; + DAT_UINT32 minor; +} DAT_SR_VERSION; + +typedef struct +{ + char * id; + DAT_SR_VERSION version; +} DAT_SR_PROVIDER_VERSION; + +typedef struct +{ + DAT_SR_API_TYPE type; + DAT_SR_VERSION version; +} DAT_SR_API_VERSION; + +typedef struct +{ + char * ia_name; + DAT_SR_API_VERSION api_version; + DAT_BOOLEAN is_thread_safe; + DAT_BOOLEAN is_default; + char * lib_path; + DAT_SR_PROVIDER_VERSION provider_version; + char * ia_params; + char * platform_params; +} DAT_SR_CONF_ENTRY; + + +/********************************************************************* + * * + * Internal Function Declarations * + * * + *********************************************************************/ + +static DAT_RETURN +dat_sr_load_entry ( + DAT_SR_CONF_ENTRY *entry); + +static DAT_BOOLEAN +dat_sr_is_valid_entry ( + DAT_SR_CONF_ENTRY *entry); + +static char * +dat_sr_type_to_str( + DAT_SR_TOKEN_TYPE type); + +static DAT_RETURN +dat_sr_parse_eof( + DAT_OS_FILE *file); + +static DAT_RETURN +dat_sr_parse_entry( + DAT_OS_FILE *file); + +static DAT_RETURN +dat_sr_parse_ia_name( + DAT_OS_FILE *file, + DAT_SR_CONF_ENTRY *entry); + +static DAT_RETURN +dat_sr_parse_api( + DAT_OS_FILE *file, + DAT_SR_CONF_ENTRY *entry); + +static DAT_RETURN +dat_sr_parse_thread_safety( + DAT_OS_FILE *file, + DAT_SR_CONF_ENTRY *entry); + +static DAT_RETURN +dat_sr_parse_default( + DAT_OS_FILE *file, + DAT_SR_CONF_ENTRY *entry); + +static DAT_RETURN +dat_sr_parse_lib_path( + DAT_OS_FILE *file, + DAT_SR_CONF_ENTRY *entry); + +static DAT_RETURN +dat_sr_parse_provider_version( + DAT_OS_FILE *file, + DAT_SR_CONF_ENTRY *entry); + +static DAT_RETURN +dat_sr_parse_ia_params( + DAT_OS_FILE *file, + DAT_SR_CONF_ENTRY *entry); + +static DAT_RETURN +dat_sr_parse_platform_params( + DAT_OS_FILE *file, + DAT_SR_CONF_ENTRY *entry); + +static DAT_RETURN +dat_sr_parse_eoe( + DAT_OS_FILE *file, + DAT_SR_CONF_ENTRY *entry); + +static DAT_RETURN +dat_sr_convert_api( + char *str, + DAT_SR_API_VERSION *api_version); + +static DAT_RETURN +dat_sr_convert_thread_safety( + char *str, + DAT_BOOLEAN *is_thread_safe); + +static DAT_RETURN +dat_sr_convert_default( + char *str, + DAT_BOOLEAN *is_default); + +static DAT_RETURN +dat_sr_convert_provider_version( + char *str, + DAT_SR_PROVIDER_VERSION *provider_version); + +static DAT_RETURN +dat_sr_get_token ( + DAT_OS_FILE *file, + DAT_SR_TOKEN *token); + +static DAT_RETURN +dat_sr_put_token ( + DAT_OS_FILE *file, + DAT_SR_TOKEN *token); + +static DAT_RETURN +dat_sr_read_token ( + DAT_OS_FILE *file, + DAT_SR_TOKEN *token); + +static DAT_RETURN +dat_sr_read_str ( + DAT_OS_FILE *file, + DAT_SR_TOKEN *token, + DAT_OS_SIZE token_len); + +static DAT_RETURN +dat_sr_read_quoted_str ( + DAT_OS_FILE *file, + DAT_SR_TOKEN *token, + DAT_OS_SIZE token_len, + DAT_COUNT num_escape_seq); + +static void +dat_sr_read_comment( + DAT_OS_FILE *file); + + +/********************************************************************* + * * + * Global Variables * + * * + *********************************************************************/ + +static DAT_SR_STACK_NODE *g_token_stack = NULL; + + +/********************************************************************* + * * + * External Function Definitions * + * * + *********************************************************************/ + +/*********************************************************************** + * Function: dat_sr_load + ***********************************************************************/ + +DAT_RETURN +dat_sr_load (void) +{ + char *sr_path; + DAT_OS_FILE *sr_file; + char env_path[256]; + + dat_os_memset(env_path, 0, sizeof(env_path)); + + sr_path = dat_os_getenv (DAT_SR_CONF_ENV); + if ( sr_path == NULL ) + { + sr_path = dat_os_getenv(DAT_SR_SYSTEM_DRIVE); + if ( sr_path != NULL ) + { + strncat(env_path,sr_path, __min(sizeof(env_path)-1,strlen(sr_path))); + + if ( strlen(env_path) < sizeof(env_path) ) + { + strncat( &env_path[strlen(env_path)],DAT_SR_CONF_DEFAULT, + __min(sizeof(env_path)-strlen(env_path)-1, strlen(DAT_SR_CONF_DEFAULT ))); + } + sr_path = env_path; + } + else + { + strncat(env_path,DAT_SR_DRIVE_DEFAULT,sizeof(DAT_SR_DRIVE_DEFAULT)); + if ( strlen(env_path) < sizeof(env_path) ) + { + strncat(&env_path[strlen(env_path)],DAT_SR_CONF_DEFAULT, + __min( sizeof(env_path)-strlen(env_path)-1, strlen(DAT_SR_CONF_DEFAULT ))); + sr_path = env_path; + } + } + } + + dat_os_dbg_print(DAT_OS_DBG_TYPE_SR, + "DAT Registry: static registry file <%s> \n", sr_path); + + sr_file = dat_os_fopen(sr_path); + if ( sr_file == NULL ) + { + dat_os_dbg_print(DAT_OS_DBG_TYPE_ERROR, + "DAT Registry: Failed to open static registry file <%s> \n", sr_path); + return DAT_INTERNAL_ERROR; + } + + for (;;) + { + if ( DAT_SUCCESS == dat_sr_parse_eof(sr_file) ) + { + break; + } + else if ( DAT_SUCCESS == dat_sr_parse_entry(sr_file) ) + { + continue; + } + else + { + dat_os_assert(!"unable to parse static registry file"); + break; + } + } + + if ( 0 != dat_os_fclose(sr_file) ) + { + return DAT_INTERNAL_ERROR; + } + + return DAT_SUCCESS; +} + + +/********************************************************************* + * * + * Internal Function Definitions * + * * + *********************************************************************/ + +/*********************************************************************** + * Function: dat_sr_is_valid_entry + ***********************************************************************/ + +DAT_BOOLEAN +dat_sr_is_valid_entry ( + DAT_SR_CONF_ENTRY *entry) +{ + if ( ( DAT_SR_API_UDAT == entry->api_version.type ) && + (entry->is_default) ) + { + return DAT_TRUE; + } + else + { + return DAT_FALSE; + } +} + + +/*********************************************************************** + * Function: dat_sr_load_entry + ***********************************************************************/ + +DAT_RETURN +dat_sr_load_entry ( + DAT_SR_CONF_ENTRY *conf_entry) +{ + DAT_SR_ENTRY entry; + + if ( DAT_NAME_MAX_LENGTH < (strlen(conf_entry->ia_name) + 1) ) + { + dat_os_dbg_print(DAT_OS_DBG_TYPE_SR, + "DAT Registry: ia name %s is longer than " + "DAT_NAME_MAX_LENGTH (%i)\n", + conf_entry->ia_name, DAT_NAME_MAX_LENGTH); + + return DAT_INSUFFICIENT_RESOURCES; + } + + dat_os_strncpy(entry.info.ia_name, conf_entry->ia_name, DAT_NAME_MAX_LENGTH); + entry.info.dapl_version_major = conf_entry->api_version.version.major; + entry.info.dapl_version_minor = conf_entry->api_version.version.minor; + entry.info.is_thread_safe = conf_entry->is_thread_safe; + entry.lib_path = conf_entry->lib_path; + entry.ia_params = conf_entry->ia_params; + entry.lib_handle = NULL; + entry.ref_count = 0; + + dat_os_dbg_print(DAT_OS_DBG_TYPE_SR, + "DAT Registry: loading provider for %s\n", + conf_entry->ia_name); + + return dat_sr_insert(&entry.info, &entry); +} + + +/*********************************************************************** + * Function: dat_sr_type_to_str + ***********************************************************************/ + +char * +dat_sr_type_to_str ( + DAT_SR_TOKEN_TYPE type) +{ + static char *str_array[] = { "string", "eor", "eof" }; + + if ( (type < 0) || (2 < type) ) + { + return "error: invalid token type"; + } + + return str_array[type]; +} + + +/*********************************************************************** + * Function: dat_sr_parse_eof + ***********************************************************************/ + +DAT_RETURN +dat_sr_parse_eof( + DAT_OS_FILE *file) +{ + DAT_SR_TOKEN token; + + if ( DAT_SUCCESS != dat_sr_get_token(file, &token) ) + { + return DAT_INTERNAL_ERROR; + } + + if ( DAT_SR_TOKEN_EOF == token.type ) + { + return DAT_SUCCESS; + } + else + { + dat_sr_put_token(file, &token); + return DAT_INTERNAL_ERROR; + } +} + + +/*********************************************************************** + * Function: dat_sr_parse_ia_name + ***********************************************************************/ + +DAT_RETURN +dat_sr_parse_entry( + DAT_OS_FILE *file) +{ + DAT_SR_CONF_ENTRY entry; + DAT_RETURN status; + + dat_os_memset(&entry, 0, sizeof(DAT_SR_CONF_ENTRY)); + + if ( (DAT_SUCCESS == dat_sr_parse_ia_name(file, &entry)) && + (DAT_SUCCESS == dat_sr_parse_api(file, &entry)) && + (DAT_SUCCESS == dat_sr_parse_thread_safety(file, &entry)) && + (DAT_SUCCESS == dat_sr_parse_default(file, &entry)) && + (DAT_SUCCESS == dat_sr_parse_lib_path(file, &entry)) && + (DAT_SUCCESS == dat_sr_parse_provider_version(file, &entry)) && + (DAT_SUCCESS == dat_sr_parse_ia_params(file, &entry)) && + (DAT_SUCCESS == dat_sr_parse_platform_params(file, &entry)) && + (DAT_SUCCESS == dat_sr_parse_eoe(file, &entry)) ) + { + dat_os_dbg_print(DAT_OS_DBG_TYPE_SR, + "\n" + "DAT Registry: entry \n" + " ia_name %s\n" + " api_version\n" + " type 0x%X\n" + " major.minor %d.%d\n" + " is_thread_safe %d\n" + " is_default %d\n" + " lib_path %s\n" + " provider_version\n" + " id %s\n" + " major.minor %d.%d\n" + " ia_params %s\n" + "\n", + entry.ia_name, + entry.api_version.type, + entry.api_version.version.major, + entry.api_version.version.minor, + entry.is_thread_safe, + entry.is_default, + entry.lib_path, + entry.provider_version.id, + entry.provider_version.version.major, + entry.provider_version.version.minor, + entry.ia_params); + + if ( DAT_TRUE == dat_sr_is_valid_entry(&entry) ) + { + /* + * The static registry configuration file may have multiple + * entries with the same IA name. The first entry will be + * installed in the static registry causing subsequent attempts + * to register the same IA name to fail. Therefore the return code + * from dat_sr_load_entry() is ignored. + */ + (void) dat_sr_load_entry(&entry); + } + + status = DAT_SUCCESS; + } + else /* resync */ + { + DAT_SR_TOKEN token; + + /* + * The static registry format is specified in the DAT specification. + * While the registry file's contents may change between revisions of + * the specification, there is no way to determine the specification + * version to which the configuration file conforms. If an entry is + * found that does not match the expected format, the entry is discarded + * and the parsing of the file continues. There is no way to determine if + * the entry was an error or an entry confirming to an alternate version + * of specification. + */ + + for (;;) + { + if ( DAT_SUCCESS != dat_sr_get_token(file, &token) ) + { + status = DAT_INTERNAL_ERROR; + break; + } + + if ( DAT_SR_TOKEN_STRING != token.type ) + { + status = DAT_SUCCESS; + break; + } + else + { + dat_os_free(token.value, + (sizeof(char) * (int)dat_os_strlen(token.value)) + 1); + continue; + } + } + } + + /* free resources */ + if ( NULL != entry.ia_name ) + { + dat_os_free(entry.ia_name, + sizeof(char) * ((int)dat_os_strlen(entry.ia_name) + 1)); + } + if ( NULL != entry.lib_path ) + { + dat_os_free(entry.lib_path, + sizeof(char) * ((int)dat_os_strlen(entry.lib_path) + 1)); + } + + if ( NULL != entry.provider_version.id ) + { + dat_os_free(entry.provider_version.id, + sizeof(char) * ((int)dat_os_strlen(entry.provider_version.id) + 1)); + } + + if ( NULL != entry.ia_params ) + { + dat_os_free(entry.ia_params, + sizeof(char) * ((int)dat_os_strlen(entry.ia_params) + 1)); + } + + return status; +} + + +/*********************************************************************** + * Function: dat_sr_parse_ia_name + ***********************************************************************/ + +DAT_RETURN +dat_sr_parse_ia_name( + DAT_OS_FILE *file, + DAT_SR_CONF_ENTRY *entry) +{ + DAT_SR_TOKEN token; + DAT_RETURN status; + + if ( DAT_SUCCESS != dat_sr_get_token(file, &token) ) + { + return DAT_INTERNAL_ERROR; + } + + if ( DAT_SR_TOKEN_STRING != token.type ) + { + status = DAT_INTERNAL_ERROR; + } + else + { + entry->ia_name = token.value; + + status = DAT_SUCCESS; + } + + if ( DAT_SUCCESS != status ) + { + DAT_RETURN status_success; + + status_success = dat_sr_put_token(file, &token); + dat_os_assert( DAT_SUCCESS == status_success); + } + + return status; +} + + +/*********************************************************************** + * Function: dat_sr_parse_ia_name + ***********************************************************************/ + +DAT_RETURN +dat_sr_parse_api( + DAT_OS_FILE *file, + DAT_SR_CONF_ENTRY *entry) +{ + DAT_SR_TOKEN token; + DAT_RETURN status; + + if ( DAT_SUCCESS != dat_sr_get_token(file, &token) ) + { + return DAT_INTERNAL_ERROR; + } + + if ( DAT_SR_TOKEN_STRING != token.type ) + { + status = DAT_INTERNAL_ERROR; + } + else if ( DAT_SUCCESS != dat_sr_convert_api( + token.value, &entry->api_version) ) + { + status = DAT_INTERNAL_ERROR; + } + else + { + dat_os_free(token.value, + (sizeof(char) * (int)dat_os_strlen(token.value)) + 1); + + status = DAT_SUCCESS; + } + + if ( DAT_SUCCESS != status ) + { + DAT_RETURN status_success; + + status_success = dat_sr_put_token(file, &token); + dat_os_assert( DAT_SUCCESS == status_success); + } + + return status; +} + + +/*********************************************************************** + * Function: dat_sr_parse_thread_safety + ***********************************************************************/ + +static DAT_RETURN +dat_sr_parse_thread_safety( + DAT_OS_FILE *file, + DAT_SR_CONF_ENTRY *entry) +{ + DAT_SR_TOKEN token; + DAT_RETURN status; + + if ( DAT_SUCCESS != dat_sr_get_token(file, &token) ) + { + return DAT_INTERNAL_ERROR; + } + + if ( DAT_SR_TOKEN_STRING != token.type ) + { + status = DAT_INTERNAL_ERROR; + } + else if ( DAT_SUCCESS != dat_sr_convert_thread_safety( + token.value, &entry->is_thread_safe) ) + { + status = DAT_INTERNAL_ERROR; + } + else + { + dat_os_free(token.value, + (sizeof(char) * (int)dat_os_strlen(token.value)) + 1); + + status = DAT_SUCCESS; + } + + if ( DAT_SUCCESS != status ) + { + DAT_RETURN status_success; + + status_success = dat_sr_put_token(file, &token); + dat_os_assert( DAT_SUCCESS == status_success); + } + + return status; +} + + +/*********************************************************************** + * Function: dat_sr_parse_default + ***********************************************************************/ + +DAT_RETURN +dat_sr_parse_default( + DAT_OS_FILE *file, + DAT_SR_CONF_ENTRY *entry) +{ + DAT_SR_TOKEN token; + DAT_RETURN status; + + if ( DAT_SUCCESS != dat_sr_get_token(file, &token) ) + { + return DAT_INTERNAL_ERROR; + } + + if ( DAT_SR_TOKEN_STRING != token.type ) + { + status = DAT_INTERNAL_ERROR; + } + else if ( DAT_SUCCESS != dat_sr_convert_default( + token.value, &entry->is_default) ) + { + status = DAT_INTERNAL_ERROR; + } + else + { + dat_os_free(token.value, + (sizeof(char) * (int)dat_os_strlen(token.value)) + 1); + + status = DAT_SUCCESS; + } + + if ( DAT_SUCCESS != status ) + { + DAT_RETURN status_success; + + status_success = dat_sr_put_token(file, &token); + dat_os_assert( DAT_SUCCESS == status_success); + } + + return status; +} + + +/*********************************************************************** + * Function: dat_sr_parse_lib_path + ***********************************************************************/ + +DAT_RETURN +dat_sr_parse_lib_path( + DAT_OS_FILE *file, + DAT_SR_CONF_ENTRY *entry) +{ + DAT_SR_TOKEN token; + DAT_RETURN status; + + if ( DAT_SUCCESS != dat_sr_get_token(file, &token) ) + { + return DAT_INTERNAL_ERROR; + } + + if ( DAT_SR_TOKEN_STRING != token.type ) + { + status = DAT_INTERNAL_ERROR; + } + else + { + entry->lib_path = token.value; + + status = DAT_SUCCESS; + } + + if ( DAT_SUCCESS != status ) + { + DAT_RETURN status_success; + + status_success = dat_sr_put_token(file, &token); + dat_os_assert( DAT_SUCCESS == status_success); + } + + return status; +} + +/*********************************************************************** + * Function: dat_sr_parse_provider_version + ***********************************************************************/ + +DAT_RETURN +dat_sr_parse_provider_version( + DAT_OS_FILE *file, + DAT_SR_CONF_ENTRY *entry) +{ + DAT_SR_TOKEN token; + DAT_RETURN status; + + if ( DAT_SUCCESS != dat_sr_get_token(file, &token) ) + { + return DAT_INTERNAL_ERROR; + } + + if ( DAT_SR_TOKEN_STRING != token.type ) + { + status = DAT_INTERNAL_ERROR; + } + else if ( DAT_SUCCESS != dat_sr_convert_provider_version( + token.value, &entry->provider_version) ) + { + status = DAT_INTERNAL_ERROR; + } + else + { + dat_os_free(token.value, + (sizeof(char) * (int)dat_os_strlen(token.value)) + 1); + + status = DAT_SUCCESS; + } + + if ( DAT_SUCCESS != status ) + { + DAT_RETURN status_success; + + status_success = dat_sr_put_token(file, &token); + dat_os_assert( DAT_SUCCESS == status_success); + } + + return status; +} + + +/*********************************************************************** + * Function: dat_sr_parse_ia_params + ***********************************************************************/ + +DAT_RETURN +dat_sr_parse_ia_params( + DAT_OS_FILE *file, + DAT_SR_CONF_ENTRY *entry) +{ + DAT_SR_TOKEN token; + DAT_RETURN status; + + if ( DAT_SUCCESS != dat_sr_get_token(file, &token) ) + { + return DAT_INTERNAL_ERROR; + } + + if ( DAT_SR_TOKEN_STRING != token.type ) + { + status = DAT_INTERNAL_ERROR; + } + else + { + entry->ia_params = token.value; + + status = DAT_SUCCESS; + } + + if ( DAT_SUCCESS != status ) + { + DAT_RETURN status_success; + + status_success = dat_sr_put_token(file, &token); + dat_os_assert( DAT_SUCCESS == status_success); + } + + return status; +} + + +/*********************************************************************** + * Function: dat_sr_parse_platform_params + ***********************************************************************/ + +DAT_RETURN +dat_sr_parse_platform_params( + DAT_OS_FILE *file, + DAT_SR_CONF_ENTRY *entry) +{ + DAT_SR_TOKEN token; + DAT_RETURN status; + + if ( DAT_SUCCESS != dat_sr_get_token(file, &token) ) + { + return DAT_INTERNAL_ERROR; + } + + if ( DAT_SR_TOKEN_STRING != token.type ) + { + status = DAT_INTERNAL_ERROR; + } + else + { + entry->platform_params = token.value; + + status = DAT_SUCCESS; + } + + if ( DAT_SUCCESS != status ) + { + DAT_RETURN status_success; + + status_success = dat_sr_put_token(file, &token); + dat_os_assert( DAT_SUCCESS == status_success); + } + + return status; +} + + +/*********************************************************************** + * Function: dat_sr_parse_eoe + ***********************************************************************/ + +DAT_RETURN +dat_sr_parse_eoe( + DAT_OS_FILE *file, + DAT_SR_CONF_ENTRY *entry) +{ + DAT_SR_TOKEN token; + DAT_RETURN status; + + if( entry == NULL ) + return DAT_INVALID_PARAMETER; + + if ( DAT_SUCCESS != dat_sr_get_token(file, &token) ) + { + return DAT_INTERNAL_ERROR; + } + + if ( (DAT_SR_TOKEN_EOF != token.type) && + (DAT_SR_TOKEN_EOR != token.type) ) + { + status = DAT_INTERNAL_ERROR; + } + else + { + status = DAT_SUCCESS; + } + + if ( DAT_SUCCESS != status ) + { + DAT_RETURN status_success; + + status_success = dat_sr_put_token(file, &token); + dat_os_assert( DAT_SUCCESS == status_success); + } + + return status; +} + + +/*********************************************************************** + * Function: dat_sr_convert_api + ***********************************************************************/ + +DAT_RETURN +dat_sr_convert_api ( + char *str, + DAT_SR_API_VERSION *api_version) +{ + int i; + int minor_i; + + dat_os_assert( 0 < dat_os_strlen(str) ); + + if ( 'u' == str[0] ) + { + api_version->type = DAT_SR_API_UDAT; + } + else if ( 'k' == str[0] ) + { + api_version->type = DAT_SR_API_KDAT; + } + else + { + return DAT_INTERNAL_ERROR; + } + + for ( i = 1 /* move past initial [u|k] */; '\0' != str[i]; i++ ) + { + if ( '.' == str[i] ) + { + break; + } + else if ( DAT_TRUE != dat_os_isdigit(str[i]) ) + { + return DAT_INTERNAL_ERROR; + } + } + + api_version->version.major = (DAT_UINT32) dat_os_strtol(str + 1, NULL, 10); + + /* move past '.' */ + minor_i = ++i; + + for ( ; '\0' != str[i]; i++ ) + { + if ( DAT_TRUE != dat_os_isdigit(str[i]) ) + { + return DAT_INTERNAL_ERROR; + } + } + + api_version->version.minor = (DAT_UINT32) dat_os_strtol(str + minor_i, NULL, 10); + + if ( '\0' != str[i] ) + { + return DAT_INTERNAL_ERROR; + } + + return DAT_SUCCESS; +} + + +/*********************************************************************** + * Function: dat_sr_convert_thread_safety + ***********************************************************************/ + +static DAT_RETURN +dat_sr_convert_thread_safety( + char *str, + DAT_BOOLEAN *is_thread_safe) +{ + if ( !dat_os_strncmp(str, + DAT_SR_TOKEN_THREADSAFE, + dat_os_strlen(DAT_SR_TOKEN_THREADSAFE)) ) + { + *is_thread_safe = DAT_TRUE; + return DAT_SUCCESS; + } + else if ( !dat_os_strncmp(str, + DAT_SR_TOKEN_NONTHREADSAFE, + dat_os_strlen(DAT_SR_TOKEN_NONTHREADSAFE)) ) + { + *is_thread_safe = DAT_FALSE; + return DAT_SUCCESS; + } + else + { + return DAT_INTERNAL_ERROR; + } +} + + +/*********************************************************************** + * Function: dat_sr_convert_default + ***********************************************************************/ + +static DAT_RETURN +dat_sr_convert_default ( + char *str, + DAT_BOOLEAN *is_default) +{ + if ( !dat_os_strncmp(str, + DAT_SR_TOKEN_DEFAULT, + dat_os_strlen(DAT_SR_TOKEN_DEFAULT)) ) + { + *is_default = DAT_TRUE; + return DAT_SUCCESS; + } + else if ( !dat_os_strncmp(str, + DAT_SR_TOKEN_NONDEFAULT, + dat_os_strlen(DAT_SR_TOKEN_NONDEFAULT)) ) + { + *is_default = DAT_FALSE; + return DAT_SUCCESS; + } + else + { + return DAT_INTERNAL_ERROR; + } +} + + +/*********************************************************************** + * Function: dat_sr_convert_provider_version + ***********************************************************************/ + +DAT_RETURN +dat_sr_convert_provider_version ( + char *str, + DAT_SR_PROVIDER_VERSION *provider_version) +{ + DAT_RETURN status; + int i; + int decimal_i; + + dat_os_assert( 0 < dat_os_strlen(str) ); + dat_os_assert( NULL == provider_version->id ); + + status = DAT_SUCCESS; + + for ( i = 0; '\0' != str[i]; i++ ) + { + if ( '.' == str[i] ) + { + break; + } + } + + /* if no id value was found */ + if ( 0 == i ) + { + status = DAT_INTERNAL_ERROR; + goto exit; + } + + if ( NULL == (provider_version->id = dat_os_alloc(sizeof(char) * (i + 1))) ) + { + status = DAT_INSUFFICIENT_RESOURCES | DAT_RESOURCE_MEMORY; + goto exit; + } + + dat_os_strncpy(provider_version->id, str, i); + provider_version->id[i] = '\0'; + + /* move past '.' */ + decimal_i = ++i; + + for ( ; '\0' != str[i]; i++ ) + { + if ( '.' == str[i] ) + { + break; + } + else if ( DAT_TRUE != dat_os_isdigit(str[i]) ) + { + status = DAT_INTERNAL_ERROR; + goto exit; + } + } + + /* if no version value was found */ + if ( decimal_i == i ) + { + status = DAT_INTERNAL_ERROR; + goto exit; + } + + provider_version->version.major = (DAT_UINT32) + dat_os_strtol(str + decimal_i, NULL, 10); + + /* move past '.' */ + decimal_i = ++i; + + for ( ; '\0' != str[i]; i++ ) + { + if ( DAT_TRUE != dat_os_isdigit(str[i]) ) + { + status = DAT_INTERNAL_ERROR; + goto exit; + } + } + + /* if no version value was found */ + if ( decimal_i == i ) + { + status = DAT_INTERNAL_ERROR; + goto exit; + } + + provider_version->version.minor = (DAT_UINT32) + dat_os_strtol(str + decimal_i, NULL, 10); + + if ( '\0' != str[i] ) + { + status = DAT_INTERNAL_ERROR; + goto exit; + } + + exit: + if ( DAT_SUCCESS != status ) + { + if ( NULL != provider_version->id ) + { + dat_os_free(provider_version->id, + sizeof(char) * ((int)dat_os_strlen(provider_version->id) + 1)); + provider_version->id = NULL; + } + } + + return status; +} + + +/*********************************************************************** + * Function: dat_sr_get_token + ***********************************************************************/ + +DAT_RETURN +dat_sr_get_token ( + DAT_OS_FILE *file, + DAT_SR_TOKEN *token) +{ + if ( NULL == g_token_stack ) + { + return dat_sr_read_token(file, token); + } + else + { + DAT_SR_STACK_NODE *top; + + top = g_token_stack; + + *token = top->token; + g_token_stack = top->next; + + dat_os_free(top, sizeof(DAT_SR_STACK_NODE)); + + return DAT_SUCCESS; + } +} + + +/*********************************************************************** + * Function: dat_sr_put_token + ***********************************************************************/ + +DAT_RETURN +dat_sr_put_token ( + DAT_OS_FILE *file, + DAT_SR_TOKEN *token) +{ + DAT_SR_STACK_NODE *top; + + if ( NULL == (top = dat_os_alloc(sizeof(DAT_SR_STACK_NODE))) ) + { + return DAT_INSUFFICIENT_RESOURCES | DAT_RESOURCE_MEMORY; + } + + top->token = *token; + top->next = g_token_stack; + g_token_stack = top; + + return DAT_SUCCESS; +} + + +/*********************************************************************** + * Function: dat_sr_read_token + ***********************************************************************/ + +DAT_RETURN +dat_sr_read_token ( + DAT_OS_FILE *file, + DAT_SR_TOKEN *token) +{ + DAT_OS_FILE_POS pos; + DAT_OS_SIZE token_len; + DAT_COUNT num_escape_seq; + DAT_BOOLEAN is_quoted_str; + DAT_BOOLEAN is_prev_char_backslash; + DAT_OS_FILE_POS cur_pos = 0; + /* + * The DAT standard does not specify a maximum size for quoted strings. + * Therefore the tokenizer must be able to read in a token of arbitrary + * size. Instead of allocating a fixed length buffer, the tokenizer first + * scans the input a single character at a time looking for the begining + * and end of the token. Once the these positions are found, the entire + * token is read into memory. By using this algorithm,the implementation + * does not place an arbitrary maximum on the token size. + */ + + token_len = 0; + num_escape_seq = 0; + is_quoted_str = DAT_FALSE; + is_prev_char_backslash = DAT_FALSE; + + for (;;) + { + + int c; + + /* if looking for start of the token */ + if ( 0 == token_len ) + { + if ( DAT_SUCCESS != dat_os_fgetpos(file, &cur_pos) ) + { + return DAT_INTERNAL_ERROR; + } + } + + c = dat_os_fgetc(file); + + /* if looking for start of the token */ + if ( 0 == token_len ) + { + if ( EOF == c ) + { + token->type = DAT_SR_TOKEN_EOF; + token->value = NULL; + token->value_len = 0; + goto success; + } + else if ( DAT_SR_CHAR_NEWLINE == c ) + { + token->type = DAT_SR_TOKEN_EOR; + token->value = NULL; + token->value_len = 0; + goto success; + } + else if ( dat_os_isblank(c) ) + { + continue; + } + else if ( DAT_SR_CHAR_COMMENT == c ) + { + dat_sr_read_comment(file); + continue; + } + else + { + if ( DAT_SR_CHAR_QUOTE == c ) + { + is_quoted_str = DAT_TRUE; + } + + pos = cur_pos; + token_len++; + } + } + else /* looking for the end of the token */ + { + if ( EOF == c ) + { + break; + } + else if ( DAT_SR_CHAR_NEWLINE == c ) + { + /* put back the newline */ + dat_os_fputc(file, c); + break; + } + else if ( !is_quoted_str && dat_os_isblank(c) ) + { + break; + } + else + { + token_len++; + + if ( (DAT_SR_CHAR_QUOTE == c) && !is_prev_char_backslash ) + { + break; + } + else if ( (DAT_SR_CHAR_BACKSLASH == c) && !is_prev_char_backslash ) + { + is_prev_char_backslash = DAT_TRUE; + num_escape_seq++; + } + else + { + is_prev_char_backslash = DAT_FALSE; + } + } + } + } + + /* the token was a string */ + if ( DAT_SUCCESS != dat_os_fsetpos(file, &pos) ) + { + return DAT_INTERNAL_ERROR; + } + + if ( is_quoted_str ) + { + if ( DAT_SUCCESS != dat_sr_read_quoted_str(file, + token, + token_len, + num_escape_seq) ) + { + return DAT_INTERNAL_ERROR; + } + } + else + { + if ( DAT_SUCCESS != dat_sr_read_str(file, + token, + token_len) ) + { + return DAT_INTERNAL_ERROR; + } + } + + success: + dat_os_dbg_print(DAT_OS_DBG_TYPE_SR, + "\n" + "DAT Registry: token\n" + " type %s\n" + " value <%s>\n" + "\n", + dat_sr_type_to_str(token->type), + ((DAT_SR_TOKEN_STRING == token->type) ? token->value : "") ); + + return DAT_SUCCESS; +} + + +/*********************************************************************** + * Function: dat_sr_read_str + ***********************************************************************/ + +DAT_RETURN +dat_sr_read_str ( + DAT_OS_FILE *file, + DAT_SR_TOKEN *token, + DAT_OS_SIZE token_len) +{ + token->type = DAT_SR_TOKEN_STRING; + token->value_len = sizeof(char) * (token_len + 1); /* +1 for null termination */ + if ( NULL == (token->value = dat_os_alloc((int)token->value_len)) ) + { + return DAT_INSUFFICIENT_RESOURCES | DAT_RESOURCE_MEMORY; + } + + if ( token_len != dat_os_fread(file, token->value, token_len) ) + { + dat_os_free(token->value, (int)token->value_len); + token->value = NULL; + + return DAT_INTERNAL_ERROR; + } + + token->value[token->value_len - 1] = '\0'; + + return DAT_SUCCESS; +} + + +/*********************************************************************** + * Function: dat_sr_read_quoted_str + ***********************************************************************/ + +DAT_RETURN +dat_sr_read_quoted_str ( + DAT_OS_FILE *file, + DAT_SR_TOKEN *token, + DAT_OS_SIZE token_len, + DAT_COUNT num_escape_seq) +{ + DAT_OS_SIZE str_len; + DAT_OS_SIZE i; + DAT_OS_SIZE j; + int c; + DAT_RETURN status; + DAT_BOOLEAN is_prev_char_backslash; + + str_len = token_len - 2; /* minus 2 " characters */ + is_prev_char_backslash = DAT_FALSE; + status = DAT_SUCCESS; + + token->type = DAT_SR_TOKEN_STRING; + /* +1 for null termination */ + token->value_len = sizeof(char) * (str_len - num_escape_seq + 1); + + if ( NULL == (token->value = dat_os_alloc((int)token->value_len)) ) + { + status = DAT_INSUFFICIENT_RESOURCES | DAT_RESOURCE_MEMORY; + goto exit; + } + + /* throw away " */ + if ( DAT_SR_CHAR_QUOTE != dat_os_fgetc(file) ) + { + status = DAT_INTERNAL_ERROR; + goto exit; + } + + for ( i = 0, j = 0; i < str_len; i++ ) + { + c = dat_os_fgetc(file); + + if ( EOF == c ) + { + status = DAT_INTERNAL_ERROR; + goto exit; + } + else if ( (DAT_SR_CHAR_BACKSLASH == c) && !is_prev_char_backslash ) + { + is_prev_char_backslash = DAT_TRUE; + } + else + { + token->value[j] = (DAT_UINT8)c; + j++; + + is_prev_char_backslash = DAT_FALSE; + } + } + + /* throw away " */ + if ( DAT_SR_CHAR_QUOTE != dat_os_fgetc(file) ) + { + status = DAT_INTERNAL_ERROR; + goto exit; + } + + token->value[token->value_len - 1] = '\0'; + +exit: + if ( DAT_SUCCESS != status ) + { + if ( NULL != token->value ) + { + dat_os_free(token->value, (int)token->value_len); + token->value = NULL; + } + } + + return status; +} + + +/*********************************************************************** + * Function: dat_sr_read_comment + ***********************************************************************/ + +void +dat_sr_read_comment ( + DAT_OS_FILE *file) +{ + int c; + + /* read up to an EOR or EOF to move past the comment */ + do + { + c = dat_os_fgetc(file); + } while ( (DAT_SR_CHAR_NEWLINE != c) && (EOF != c) ); + + /* put back the newline */ + dat_os_ungetc(file, c); +} diff --git a/branches/WOF2-3/ulp/dapl/dat/udat/udat_sr_parser.h b/branches/WOF2-3/ulp/dapl/dat/udat/udat_sr_parser.h new file mode 100644 index 00000000..de5b3e61 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dat/udat/udat_sr_parser.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dat_sr_parser.h + * + * PURPOSE: static registry (SR) parser inteface declarations + * + * $Id$ + **********************************************************************/ + +#ifndef _DAT_SR_PARSER_H_ +#define _DAT_SR_PARSER_H_ + + +#include "dat_osd.h" + + +/********************************************************************* + * * + * Function Declarations * + * * + *********************************************************************/ + +/* + * The static registry exports the same interface regardless of + * platform. The particular implementation of dat_sr_load() is + * found with other platform dependent sources. + */ + +extern DAT_RETURN +dat_sr_load (void); + + +#endif /* _DAT_SR_PARSER_H_ */ diff --git a/branches/WOF2-3/ulp/dapl/dat/udat/windows/dat_osd.c b/branches/WOF2-3/ulp/dapl/dat/udat/windows/dat_osd.c new file mode 100644 index 00000000..8cf0b3f3 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dat/udat/windows/dat_osd.c @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dat_osd.c + * + * PURPOSE: Operating System Dependent layer + * Description: + * Provide OS dependent functions with a canonical DAPL + * interface. Designed to be portable and hide OS specific quirks + * of common functions. + * + * $Id$ + **********************************************************************/ + +#include "dat_osd.h" +#include "dat_init.h" + + +/********************************************************************* + * * + * Constants * + * * + *********************************************************************/ + +#define DAT_DBG_LEVEL_ENV "DAT_DBG_LEVEL" +#define DAT_DBG_DEST_ENV "DAT_DBG_DEST" + + +/********************************************************************* + * * + * Enumerations * + * * + *********************************************************************/ + +typedef int DAT_OS_DBG_DEST; + +typedef enum +{ + DAT_OS_DBG_DEST_STDOUT = 0x1, +} DAT_OS_DBG_DEST_TYPE; + + +/********************************************************************* + * * + * Global Variables * + * * + *********************************************************************/ + +static DAT_OS_DBG_TYPE_VAL g_dbg_type = DAT_OS_DBG_TYPE_ERROR; +static DAT_OS_DBG_DEST g_dbg_dest = DAT_OS_DBG_DEST_STDOUT; + + +/*********************************************************************** + * Function: dat_os_dbg_set_level + ***********************************************************************/ + +void +dat_os_dbg_init ( void ) +{ + char *dbg_type; + char *dbg_dest; + + dbg_type = dat_os_getenv (DAT_DBG_LEVEL_ENV); + if ( dbg_type != NULL ) + { + g_dbg_type = dat_os_strtol(dbg_type, NULL, 0); + } + + dbg_dest = dat_os_getenv (DAT_DBG_DEST_ENV); + if ( dbg_dest != NULL ) + { + g_dbg_dest = dat_os_strtol(dbg_dest, NULL, 0); + } +} + + +/*********************************************************************** + * Function: dat_os_dbg_print + ***********************************************************************/ + +void +dat_os_dbg_print ( + DAT_OS_DBG_TYPE_VAL type, + const char * fmt, + ...) +{ + if ( (DAT_OS_DBG_TYPE_ERROR == type) || (type & g_dbg_type) ) + { + va_list args; + + va_start(args, fmt); + + if ( DAT_OS_DBG_DEST_STDOUT & g_dbg_dest ) + { + vfprintf(stdout, fmt, args); + } + + va_end(args); + + fflush(stdout); + } +} + + +BOOL APIENTRY +DllMain( + IN HINSTANCE h_module, + IN DWORD ul_reason_for_call, + IN LPVOID lp_reserved ) +{ + UNREFERENCED_PARAMETER( lp_reserved ); + + switch( ul_reason_for_call ) + { + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls( h_module ); + dat_init(); + break; + + case DLL_PROCESS_DETACH: + dat_fini(); + } + return TRUE; +} diff --git a/branches/WOF2-3/ulp/dapl/dat/udat/windows/dat_osd.h b/branches/WOF2-3/ulp/dapl/dat/udat/windows/dat_osd.h new file mode 100644 index 00000000..a8d3185f --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dat/udat/windows/dat_osd.h @@ -0,0 +1,409 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dat_osd.h + * + * PURPOSE: Operating System Dependent layer + * Description: + * Provide OS dependent data structures & functions with + * a canonical DAPL interface. Designed to be portable + * and hide OS specific quirks of common functions. + * + * $Id$ + **********************************************************************/ + +#ifndef _DAT_OSD_H_ +#define _DAT_OSD_H_ + +/* + * This file is defined for windows systems only, including it on any + * other build will cause an error + */ +#ifndef WIN32 +#error "UNDEFINED OS TYPE" +#endif /* WIN32 */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#ifndef STATIC +#define STATIC static +#endif /* STATIC */ + +#ifndef INLINE +#define INLINE __inline +#endif /* INLINE */ + +/********************************************************************* + * * + * Debuging * + * * + *********************************************************************/ + +#define dat_os_assert(expr) assert(expr) + +typedef int DAT_OS_DBG_TYPE_VAL; + +typedef enum +{ + DAT_OS_DBG_TYPE_ERROR = 0x1, + DAT_OS_DBG_TYPE_GENERIC = 0x2, + DAT_OS_DBG_TYPE_SR = 0x4, + DAT_OS_DBG_TYPE_DR = 0x8, + DAT_OS_DBG_TYPE_PROVIDER_API = 0x10, + DAT_OS_DBG_TYPE_CONSUMER_API = 0x20, + DAT_OS_DBG_TYPE_ALL = 0xff +} DAT_OS_DBG_TYPE_TYPE; + +extern void +dat_os_dbg_init ( void ); + +extern void +dat_os_dbg_print ( + DAT_OS_DBG_TYPE_VAL type, + const char * fmt, + ...); + + +/********************************************************************* + * * + * Utility Functions * + * * + *********************************************************************/ + +#define DAT_ERROR(Type,SubType) ((DAT_RETURN)(DAT_CLASS_ERROR | Type | SubType)) + +typedef size_t DAT_OS_SIZE; +typedef HMODULE DAT_OS_LIBRARY_HANDLE; + +STATIC INLINE DAT_RETURN +dat_os_library_load ( + const char *library_path, + DAT_OS_LIBRARY_HANDLE *library_handle_ptr) +{ + DAT_OS_LIBRARY_HANDLE library_handle; + + if ( NULL != (library_handle = LoadLibrary(library_path)) ) + { + if ( NULL != library_handle_ptr ) + { + *library_handle_ptr = library_handle; + } + + return DAT_SUCCESS; + } + else + { + dat_os_dbg_print(DAT_OS_DBG_TYPE_ERROR, + "DAT: library load failure\n"); + return DAT_INTERNAL_ERROR; + } +} +#ifdef WIN32_LEAN_AND_MEAN +#define dat_os_library_sym GetProcAddress +#else +STATIC INLINE +dat_os_library_sym ( + DAT_OS_LIBRARY_HANDLE library_handle, + char *sym) +{ + return GetProcAddress(library_handle, sym); +} +#endif /* WIN32_LEAN_AND_MEAN */ +STATIC INLINE DAT_RETURN +dat_os_library_unload ( + const DAT_OS_LIBRARY_HANDLE library_handle) +{ + if ( 0 == FreeLibrary(library_handle) ) + { + return DAT_INTERNAL_ERROR; + } + else + { + return DAT_SUCCESS; + } +} + +STATIC INLINE char * +dat_os_getenv ( + const char *name) +{ + return getenv(name); +} + +STATIC INLINE long int +dat_os_strtol ( + const char *nptr, + char **endptr, + int base) +{ + return strtol(nptr, endptr, base); +} + +STATIC INLINE DAT_OS_SIZE +dat_os_strlen ( + const char *s ) +{ + return strlen(s); +} + +STATIC INLINE int +dat_os_strncmp ( + const char *s1, + const char *s2, + DAT_OS_SIZE n) +{ + return strncmp(s1, s2, n); +} + +STATIC INLINE void * +dat_os_strncpy ( + char *dest, + const char *src, + DAT_OS_SIZE len) +{ + return strncpy (dest, src, len); +} + +STATIC INLINE DAT_BOOLEAN +dat_os_isblank( + int c) +{ + if ( (' ' == c) || ('\t' == c) ) { return DAT_TRUE; } + else { return DAT_FALSE; } +} + +STATIC INLINE DAT_BOOLEAN +dat_os_isdigit( + int c) +{ + if ( isdigit(c) ) { return DAT_TRUE; } + else { return DAT_FALSE; } +} + +STATIC INLINE void +dat_os_usleep( + unsigned long usec) +{ + Sleep(usec/1000); +} + + +/********************************************************************* + * * + * Memory Functions * + * * + *********************************************************************/ + +STATIC INLINE void * +dat_os_alloc ( + int size) +{ + return malloc (size); +} + +STATIC INLINE void +dat_os_free ( + void *ptr, + int size) +{ + free (ptr); +} + +STATIC INLINE void * +dat_os_memset (void *loc, int c, DAT_OS_SIZE size) +{ + return memset (loc, c, size); +} + + +/********************************************************************* + * * + * File I/O * + * * + *********************************************************************/ + +typedef FILE DAT_OS_FILE; +typedef fpos_t DAT_OS_FILE_POS; + + +STATIC INLINE DAT_OS_FILE * +dat_os_fopen ( + const char * path) +{ + /* always open files in read only mode*/ + return fopen(path, "r"); +} + +STATIC INLINE DAT_RETURN +dat_os_fgetpos ( + DAT_OS_FILE *file, + DAT_OS_FILE_POS *pos) +{ + if ( 0 == fgetpos(file, pos) ) + { + return DAT_SUCCESS; + } + else + { + return DAT_INTERNAL_ERROR; + } +} + +STATIC INLINE DAT_RETURN +dat_os_fsetpos ( + DAT_OS_FILE *file, + DAT_OS_FILE_POS *pos) +{ + if ( 0 == fsetpos(file, pos) ) + { + return DAT_SUCCESS; + } + else + { + return DAT_INTERNAL_ERROR; + } +} + +/* dat_os_fgetc() returns EOF on error or end of file. */ +STATIC INLINE int +dat_os_fgetc ( + DAT_OS_FILE *file) +{ + return fgetc(file); +} + +/* dat_os_fputc() returns int c or EOF on error */ +STATIC INLINE int +dat_os_fputc ( + DAT_OS_FILE *file, int c) +{ + return fputc(c, file); +} + +/* dat_os_ungetc() pushd 'c' back into stream for subsequent read. + * returns EOF on error or pushed char c. + */ +STATIC INLINE int +dat_os_ungetc ( + DAT_OS_FILE *file, int c) +{ + return ungetc(c, file); +} + +/* dat_os_fread returns the number of bytes read from the file. */ +STATIC INLINE DAT_OS_SIZE +dat_os_fread ( + DAT_OS_FILE *file, + char *buf, + DAT_OS_SIZE len) +{ + return fread(buf, sizeof(char), len, file); +} + +STATIC INLINE DAT_RETURN +dat_os_fclose ( + DAT_OS_FILE *file) +{ + if ( 0 == fclose(file) ) + { + return DAT_SUCCESS; + } + else + { + return DAT_INTERNAL_ERROR; + } +} + + +/********************************************************************* + * * + * Locks * + * * + *********************************************************************/ + +typedef HANDLE DAT_OS_LOCK; + +/* lock functions */ +STATIC INLINE DAT_RETURN +dat_os_lock_init ( + IN DAT_OS_LOCK *m) +{ + *m = CreateMutex (0, FALSE, 0); + if (*(HANDLE *)m == NULL) + { + return DAT_INTERNAL_ERROR; + } + return DAT_SUCCESS; +} + +STATIC INLINE DAT_RETURN +dat_os_lock ( + IN DAT_OS_LOCK *m) +{ + WaitForSingleObject(*m, INFINITE); + + return DAT_SUCCESS; +} + +STATIC INLINE DAT_RETURN +dat_os_unlock ( + IN DAT_OS_LOCK *m) +{ + ReleaseMutex (*m); + + return DAT_SUCCESS; +} + +STATIC INLINE DAT_RETURN +dat_os_lock_destroy ( + IN DAT_OS_LOCK *m) +{ + CloseHandle (*m); + + return DAT_SUCCESS; +} + + +#endif /* _DAT_OSD_H_ */ + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ + diff --git a/branches/WOF2-3/ulp/dapl/dat/udat/windows/dat_osd_sr.h b/branches/WOF2-3/ulp/dapl/dat/udat/windows/dat_osd_sr.h new file mode 100644 index 00000000..fa24ed3d --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dat/udat/windows/dat_osd_sr.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2002, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dat_osd_sr.h + * + * PURPOSE: static registry (SR) platform specific inteface declarations + * + * $Id$ + **********************************************************************/ + +#ifndef _DAT_OSD_SR_H_ +#define _DAT_OSD_SR_H_ + + +#include "dat_osd.h" + + +/********************************************************************* + * * + * Function Declarations * + * * + *********************************************************************/ + +/* + * The static registry exports the same interface regardless of + * platform. The particular implementation of dat_sr_load() is + * found with other platform dependent sources. + */ + +extern DAT_RETURN +dat_sr_load (void); + + +#endif /* _DAT_OSD_SR_H_ */ diff --git a/branches/WOF2-3/ulp/dapl/dat/udat/windows/dat_win.def b/branches/WOF2-3/ulp/dapl/dat/udat/windows/dat_win.def new file mode 100644 index 00000000..976ef99a --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dat/udat/windows/dat_win.def @@ -0,0 +1,9 @@ +EXPORTS + +dat_init +dat_fini +dat_registry_add_provider +dat_registry_remove_provider +dat_registry_list_providers +dat_ia_openv +dat_ia_close diff --git a/branches/WOF2-3/ulp/dapl/dirs b/branches/WOF2-3/ulp/dapl/dirs new file mode 100644 index 00000000..11081a4b --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/dirs @@ -0,0 +1,4 @@ +DIRS=\ + test \ + dat \ + dapl diff --git a/branches/WOF2-3/ulp/dapl/doc/dapl_coding_style.txt b/branches/WOF2-3/ulp/dapl/doc/dapl_coding_style.txt new file mode 100644 index 00000000..cf41ae68 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/doc/dapl_coding_style.txt @@ -0,0 +1,264 @@ +####################################################################### +# # +# DAPL Coding style reference # +# # +# Steve Sears # +# sjs2 at users.sourceforge.net # +# # +# 12/13/2002 # +# # +####################################################################### + +====================================================================== +Introduction +====================================================================== + +The purpose of this document is to establish the coding style adopted by +the team implementing the DAPL reference implementation. The rules +presented here were arrived at by consensus, they are intended to +provide consistency of implementation and make it intuitive to work with +the source code. + +====================================================================== +Source code conventions +====================================================================== + +1. Brackets + + Brackets should follow C99 conventions and declare a block. The + following convention is followed: + + if (x) + { + statement; + statement; + } + + The following bracket styles are to be avoided: + + K&R style: + + if (x) { /* DON'T DO THIS */ + statement; + } + + GNU style: + + if (x) /* DON'T DO THIS */ + { + statement; + } + + Statements are always indented from brackets. + + Brackets are always used for any statement in order to avoid dangling + clause bugs. E.g. + + RIGHT: + if ( x ) + { + j = 0; + } + + WRONG: + if ( x ) + j = 0; + +2. Indents + + Indents are always 4, tabs 8. A tab may serve as a double + indent. Many of the reference implementation file have an emacs + format statement at the bottom. + +3. Comments + + Comments are always full C style comments, and never C++ + style. Comments take the form: + + /* + * comment + */ + +4. Variable Declarations + + Variables are always declared on their own line, we do not declare + multiple variables on the same line. + + Variables are never initialized in their declaration, they are + initialized in the body of the code. + +5. Function Declarations + + The return type of a function is declared on a separate line from the + function name. + + Parameters each receive a line and should be clearly labeled as IN + or OUT or INOUT. Parameter declarations begin one tab stop from the + margin. + + For example: + + DAT_RETURN + dapl_function ( + IN DAT_IA_HANDLE ia_handle, + OUT DAT_EP_HANDLE *ep_handle ) + { + ... function body ... + } + +5. White space + + Don't be afraid of white space, the goal is to make the code readable + and maintainable. We use white space: + + - One space following function names or conditional expressions. It + might be better to say one space before any open parenthesis. + + - Suggestion: One space following open parens and one space before + closing parens. Not all of the code follows this convention, use + your best judgment. + + Example: + + foo ( x1, x2 ); + +6. Conditional code + + We generally try to avoid conditional compilation, but there are + certain places where it cannot be avoided. Whenever possible, move + the conditional code into a macro or otherwise work to put it into an + include file that can be used by the platform (e.g. Linux or Windows + osd files), or by the underlying provider (e.g. IBM Torrent or + Mellanox Tavor). + + Conditionals should be descriptive, and the associated #endif should + contain the declaration. E.g. + + #ifdef THIS_IS_AN_EXAMPLE + + /* code */ + + #endif /* THIS_IS_AN_EXAMPLE */ + + You may change the ending comment if a #else clause is present. E.g. + + #ifdef THIS_IS_AN_EXAMPLE + /* code */ + + #else + /* other code */ + + #endif /* !THIS_IS_AN_EXAMPLE */ + + +====================================================================== +Naming conventions +====================================================================== + +1. Variable Names + + Variable names for DAPL data structures generally follow their type + and should be the same in all source files. A few examples: + + Handles + DAT_IA_HANDLE ia_handle + DAT_EP_HANDLE ep_handle + + Pointers + + DAPL_IA *ia_ptr; + DAPL_EP *ep_ptr; + +2. Return Code Names + + There are at least two different subsystems supported in the DAPL + reference implementation. In order to bring sanity to the error + space, return codes are named and used for their appropriate + subsystem. E.g. + + ib_status: InfiniBand status return code + dat_status: DAT/DAPL return code + +3. Function Names + + Function names describe the scope to which they apply. There are + essentially three names in the reference implementation: + + dapl_* Name of an exported function visible externally. + These functions have a 1 to 1 correspondence to + their DAT counterparts. + + dapls_* Name of a function that is called from more than one + source file, but is limited to a subsystem. + + dapli_* Local function, internal to a file. Should always be + of type STATIC. + + +====================================================================== +Util files +====================================================================== + +The Reference implementation is organized such that a single, exported +function is located in its' own file. If you are trying to find the DAPL +function to create and End Point, it will be found in the dapl version +of the DAT function in the spec. E.g. + +dapl_ep_create() is found in dapl_ep_create.c +dapl_evd_free() is found in dapl_evd_free.c + +It is often the case that the implementation must interact with data +structures or call into other subsystems. All utility functions for a +subsystem are gathered into the appropriate "util" file. + +For example, dapl_ep_create must allocate a DAPL_EP structure. The +routine to allocate and initialize memory is found in the +dapl_ep_util.c file and is named dapl_ep_alloc(). Appropriate routines +for the util file are + + - Alloc + - Free + - Assign defaults + - linking routines + - Check restrictions + - Perform operations on a data structure. + +The idea of a util file is an object oriented idea for a non OO +language. It encourages a clean implementation. + +For each util.c file, there is also a util.h file. The purpose of the +util include file is to define the prototypes for the util file, and to +supply any local flags or values necessary to the subsystem. + +====================================================================== +Include files, prototypes +====================================================================== + +Include files are organized according to subsystem and/or OS +platform. The include directory contains files that are global to the +entire source set. Prototypes are found in include files that pertain to +the data they support. + +Commenting on the DAPL Reference Implementation tree: + + dapl/common + dapl/include + Contains global dapl data structures, symbols, and + prototypes + dapl/tavor + Contains tavor prototypes and symbols + dapl/torrent + Contains torrent prototypes and symbols + dapl/udapl + Contains include files to support udapl specific files + dapl/udapl/linux + Contains osd files for Linux + dapl/udapl/windows + Contains osd files for Windows + +For completeness, the dat files described by the DAT Specification are +in the tree under the dat/ subdirectory, + + dat/include/dat/ + + diff --git a/branches/WOF2-3/ulp/dapl/doc/dapl_end_point_design.txt b/branches/WOF2-3/ulp/dapl/doc/dapl_end_point_design.txt new file mode 100644 index 00000000..c03cda76 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/doc/dapl_end_point_design.txt @@ -0,0 +1,908 @@ +####################################################################### +# # +# DAPL End Point Management Design # +# # +# Steve Sears # +# sjs2 at users.sourceforge.net # +# # +# 10/04/2002 # +# # +####################################################################### + + +====================================================================== +Referenced Documents +====================================================================== + +uDAPL: User Direct Access Programming Library, Version 1.0. Published +6/21/2002. http://www.datcollaborative.org/uDAPL_062102.pdf. +Referred to in this document as the "DAT Specification". + +InfiniBand Access Application Programming Interface Specification, +Version 1.2, 4/15/2002. In DAPL SourceForge repository at +doc/api/access_api.pdf. Referred to in this document as the "IBM +Access API Specification". + +InfiniBand Architecture Specification Volume 1, Release 1.0.a Referred +to in this document at the "InfiniBand Spec". + +====================================================================== +Introduction to EndPoints +====================================================================== + +An EndPoint is the fundamental channel abstraction for the DAT API. An +application communicates and exchanges data using an +EndPoint. Most of the time EndPoints are explicitly allocated, but +there is an exception whereby a connection event can yield an EndPoint +as a side effect; this is not supported by all transports or +implementations, and it is not currently supported in the InfiniBand +reference implementation. + +Each DAT API function is implemented in a file named + + dapl_.c + +There is a simple mapping provided by the dat library that maps +dat_* to dapl_*. For example, dat_pz_create is implemented in +dapl_pz_create.c. For example: + + DAT DAPL Found in + ------------ --------------- ------------------ + dat_ep_create dapl_ep_create dapl_ep_create.c + dat_ep_query dapl_ep_query dapl_ep_query.c + +There are very few exceptions to this naming convention, the Reference +Implementation tried to be consistent. + +There are also dapl__util.{h,c} files for each object. +For example, there are dapl_pz_util.h and dapl_pz_util.c files which +contain common helper functions specific to the 'pz' subsystem. The +use of util files follows the convention used elsewhere in the DAPL +reference implementation. These files contain common object creation +and destruction code, link list manipulation, other helper functions. + +This implementation has a simple naming convention designed to alert +someone reading the source code to the nature and scope of a +function. The convention is in the function name, such that: + + dapl_ Primary entry from a dat_ function, e.g. + dapl_ep_create(), which mirrors dat_ep_create(). + dapls_ The 's' restricts it to the subsystem, e.g. the + 'ep' subsystem. dapls_ functions are not exposed + externally, but are internal to dapl. + dapli_ The 'i' restricts the function to the file where it + is declared. These functions are always 'static' C + functions. + +1. EndPoints (EPs) +------------------------- +DAPL EndPoints provide a channel abstraction necessary to transmit and +receive data. EndPoints interact with Service Points, either Public +Service Points or Reserved Service Points, to establish a connection +from one provider to another. + +The primary EP entry points in the DAT API as they relate to DAPL are +listed in the following table: + + dat_ep_create + dat_ep_query + dat_ep_modify + dat_ep_connect + dat_ep_dup_connect + dat_ep_disconnect + dat_ep_post_send + dat_ep_post_recv + dat_ep_post_rdma_read + dat_ep_post_rdma_write + dat_ep_get_status + dat_ep_free + +Additionally, the following connection functions interact with +EndPoints: + dat_psp_create + dat_psp_query + dat_psp_free + dat_rsp_create + dat_rsp_query + dat_rsp_free + +The reference implementation maps the EndPoint abstraction onto an +InfiniBand Queue Pair (QP). + +The DAPL_EP structure is used to maintain the state and components of +the EP object and the underlying QP. As will be explained below, +keeping track of the QP state is critical for successful +operation. Accesses to the DAPL_EP fields are done atomically. + + +====================================================================== +Goals +====================================================================== + +Initial goals +------------- +-- Implement the dat_ep_* calls described in the DAT Specification with + the following exceptions: + - dat_dup_connect + - the timeout value of dap_ep_connect + +-- Implement connection calls described in the DAT Specification with + the following exceptions: + - dat_rsp_* calls + - support for DAT_PSP_PROVIDER flag on PSP creation + +-- The implementation should be as portable as possible, to facilitate + HCA Vendors efforts to implement vendor-specific versions of DAPL. + +-- The implementation must be able to work during ongoing development + of InfiniBand agents, drivers, etc. + +Later goals +----------- +-- Examine various possible performance optimizations. This document + lists potential performance improvements, but the specific + performance improvements implemented should be guided by customer + requirements. + +-- Implement the dat_rsp_* calls described in the DAT 1.0 spec + +-- Implement dat_dup_connect + +-- Resolve the timeout issue for dat_ep_connect + +-- Implement DAT_PSP_PROVIDER flag on PSP creation + +-- Remove hacks & work arounds necessitated by developing IB + implementations. + +============================================ +Requirements, constraints, and design inputs +============================================ + +The EndPoint is the base channel abstraction. An Endpoint must be +established before data can be exchanged with a remote node. The +EndPoint is mapped to the underlying InfiniBand QP channel +abstraction. When a connection is initiated, the InfiniBand +Connection Manager will be solicited. The implementation is +constrained by the capabilities and behavior of the underlying +InfiniBand facilities. + +An EP is not an exact match to an InfiniBand QP, the differences +introduce constraints that are not obvious. There are three primary +areas of conflict between the DAPL and InfiniBand models: + +1) EP and QP creation differences +2) Provider provided EPs on passive side of connections +3) Connection timeouts + +-- EP and QP creation + +The most obvious difference between an EP and a QP is the presence of +a memory handle with the object is created. InfiniBand requires a +Protection Domain be specified when a QP is created; in the DAPL +world, a Protection Zone (PZ) maps to an InfiniBand Protection Domain. +DAPL does not require a PZ to be present when an EP is created, and +that introduces two problems: + +1) If a PZ is NULL when an EP is created, a QP will not be bound to + the EP until dat_ep_modify is used to assign it later. A PZ is + required before RECV requests can be posted and before a connection + can be established. + +2) If a DAPL user changes the PZ on an EP before it is connected, + DAPL must release the current QP and create a new one with a + new Protection Domain. + +-- Provider provided EPs on connection + +The second area where the DAPL and IB models conflict is a direct result +of the requirement to specify a Protection Domain when a QP is created. + +DAPL allows a PSP to be created in such a way that an EP will +automatically be provided to the user when a connection occurs. This +is not critical to the DAPL model but in fact does provide some +convenience to the user. InfiniBand provides a similar mechanism, but +with an important difference: InfiniBand requires the user to supply +the Protection Domain for the passive connection endpoint that will be +supplied to all QPs created as a result of connection requests; DAPL +mandates a NULL PZ and requires the user to change the PZ before using +the EP. + +The reference implementation will create an 'empty' EP when the user +specifies the DAT_PSP_PROVIDER flag; it is empty in the sense that a +QP is not attached to the EP. Before the user can dat_cr_accept the +connection, the EP must be modified to have a PZ bound to it, which in +turn will cause a QP to be bound to the EP. + +-- Connection Timeouts + +The third difference in the DAPL and InfiniBand models has to do with +timeouts on connections. InfiniBand does not provide a way to specify +a connection timeout, it will wait indefinitely for a connection to +occur. dat_ep_connect supports a timeout value providing the user with +control over how long they are willing to wait for a connection to +occur. The initial implementation does not resolve this mismatch, +although it could be resolved with a separate timeout thread that will +wakeup and terminate the connection request. + +====================================================================== +DAPL EP Subsystem Design +====================================================================== + +In section 6.5.1 of the DAT Specification there is a UML state +transition diagram for an EndPoint which goes over the transitions and +states during the lifetime of an EP. It is nearly impossible to read. +The reference implementation is faithful to the DAT Spec and is +believed to be correct. + +This description of the EP will follow from creation to connection to +termination. It will also discuss the source code organization as this +is part of the design expression. + +-- EP and QP creation + +The preamble to creating an EP requires us to verify the attributes +specified by the user. If a user were to specify max_recv_dtos as 0, +for example, the EP would not be useful in any regard. If the user +does not provide EP attrs, the DAPL layer will supply a set of common +defaults resulting in a reasonable EP. + +A number of handles are bound to the EP, so a reference count is taken +on each of them. All reference counts in the DAPL system are +incremented or decremented using atomic operations; it is important to +always use the OS dependent atomic routines and not substitute a lock, +as it will not be observed elsewhere in the system and will have +unpredictable results. + +As has been discussed above, each EP is bound to a QP before it can be +connected. If a valid PZ is provided at creation time then a QP is bound +to the EP immediately. If the user later uses ep_modify to change the PZ, +the QP will be destroyed and a new one created with the appropriate +Protection Domain. + +Finally, an EP is an IA resource and is linked onto the EP chain of +the superior IA. EP's linked onto an IA are assumed to be complete, +so this is the final step of EP creation. + +After an EP is created, the ep_state will be DAT_EP_STATE_UNCONNECTED +and the qp_state will either be DAPL_QP_STATE_UNATTACHED or +IB_QP_STATE_INIT. The qp_state indicates the QP binding and the +current state of the QP. + +A qp_state of DAPL_QP_STATE_UNATTACHED indicates there is no QP bound +to this EP. This is a result of a NULL PZ when dat_ep_create was +invoked, and which has been explained in detail above. The user must +call dat_ep_modify and install a valid PZ before the EP can be used. + +When a QP is created it is in the RESET state, which is specified in +the InfiniBand Spec, section 10.3. However, DAPL requires an +unconnected EP to be able to queue RECV requests before a connection +occurs. The InfiniBand spec allows RECV requests to be queued on an QP +if the QP is in the INIT state, so after creating a QP the DAPL code +will transition it to the INIT state. + +There is an obvious design tradeoff in transitioning the QP +state. Immediately moving the state to INIT takes extra time at +creation but allows immediate posting of RECV operations; however, it +will involve a more complex tear down procedure if the QP must be +replaced as a side effect of a dat_ep_modify operation. The +alternative would be to delay transitioning the QP to INIT until a +post operation is invoked, but that requires a run time check for +every post operation. This design assumes users will infrequently +cause a QP to be replaced after it is created and prefer to pay the +state transition penalty at creation time. + +-- EP Query and Modify operations + +Because all of the ep_param data are kept up to date in the dapl_ep +structure, and because they use the complete DAT specified structure, a +query operation is trivial; a simple assignment from the internal +structure to the user parameter. uDAPL allows the implementation to +either return the fields specified by the user, or to return more than +the user requested; the reference implementation does the latter. It is +simpler and faster to copy the entire structure rather than to determine +which of all of the possible fields the user requested. + +The ep_modify operation will modify the fields in the DAT_PARAM +structure. There are some fields that cannot be updated, and there are +others that can only be updated if the EP is in the correct state. The +uDAPL spec outlines the EP states permitting ep modifications, but +generally they are DAT_EP_STATE_UNCONNECTED and +DAT_EP_STATE_PASSIVE_CONNECTION_PENDING. + +When replacing EVD handles it is a simple matter of releasing a +reference on the previous handle and taking a new reference on the new +handle. All of the implementation does resource tracking using +reference counts, which guarantees a particular handle will not be +released prematurely. Reference counts are checked in the free +routines for various objects. + +As has been mentioned previously, if the PZ handle is changed then the +QP must be released, if there is one, and a new QP must be created to +bind to this EP. + +There are some fields in the DAT_PARAM structure that are related to the +underlying hardware implementation. For these values DAPL will do a +fresh query of the QP, rather than depend on stale values. Even so, the +values returned are 'best effort' as a competing thread may change +certain values before the requesting thread has the opportunity to read +them. Applications should protect against this. + +Finally, the underlying IB provider is invoked to update the QP with +the new values, but only if some of the attributes have been changed. +As is true of most of the implementation, we only invoke the provider +code when necessary. + +====================================================================== +Connections +====================================================================== + +There are of course two sides to a connection, and in the DAPL PSP model +there is an Active and a Passive side. For clarity, the Passive side +is a server waiting for a connection, and the Active side is a client +requesting a connection from the Passive server. We will discuss each +of these in turn. + +Connections happen in the InfiniBand world by using a Connection Manager +interface. Those unfamiliar with the IB model of addressing and +management agents may want to familiarize themselves with these aspects of +the IB spec before proceeding in this document. + +First, let's walk through a primitive diagram of a connection: + + +SERVER (passive) CLIENT (active) +--------------- --------------- +1. dapl_psp_create + [ now listening ] + +2. dapl_ep_connect + <------------- +3. dapls_cr_callback + IB_CME_CONNECTION_REQUEST_PENDING_PRIVATE_DATA + [ Create and post a DAT_CONNECTION_REQUEST_EVENT event ] + +4. Event code processing + +5. Create an EP (unless PSP created) + +6. dapl_cr_accept or dapl_cr_reject + -------------> +7. dapl_evd_connection_callback + IB_CME_CONNECTED + [ Create and post a + DAT_CONNECTION_EVENT_ESTABLISHED + event ] + +8i. <------------- RTU + +9. dapls_cr_callback + IB_CME_CONNECTED + [ Create and post a DAT_CONNECTION_EVENT_ESTABLISHED + event ] + +10. ...processing... + +11. Either side issues a dat_ep_disconnect + +12. dapls_cr_callback + IB_CME_DISCONNECTED + + [ Create and post a + DAT_CONNECTION_EVENT_DISCONNECTED + event ] + +13. dapl_evd_connection_callback + IB_CME_DISCONNECTED + [ Create and post a + DAT_CONNECTION_EVENT_DISCONNECTED + event ] + + +In the above diagram, time is numbered in the left hand column and is +represented vertically. + +We will continue our discussion of connections using the above +diagram, following a sequential order for connection establishment. + +There are in fact two types of service points detailed in the uDAPL +specification. At this time only the PSP model, which is a client +server model, has been implemented, so our discussion will focus +there. + +The reader should observe that all passive side connection events will +be received by dapls_cr_callback(), and all active side connection +events occur through dapl_evd_connection_callback(). At one point +during the implementation these routines were combined as they are +very similar, but there are subtle differences causing them to remain +separate. + +Progressing through the series of events as outlined in the diagram +above: + +1. dapl_psp_create + + When a PSP is created, the final act will be to set it listening + for connections from remote nodes. It is important to realize that + a connection may in fact arrive from a remote node before the + routine setting up a listener has returned to dapl_psp_create; as + soon as dapls_ib_setup_conn_listener() is invoked connection + callbacks may arrive. To avoid race conditions this routine must be + called as the last practical operation when creating a PSP. + + dapls_ib_setup_conn_listener() is provider specific. The key + insight is that the DAPL connection qualifier (conn_qual) will + become the InfiniBand Service ID. The passive side of the + connection is now listening for connection requests. It should be + obvious that the conn_qual must be unique. + +2. dapl_ep_connect + + The active side initiates a connection with dapl_ep_connect, which + will transition the EP into DAT_EP_STATE_ACTIVE_CONNECTION_PENDING. + Again, connections are in the domain of the providers' Connection + Manager and the mechanics are very much provider specific. The key + points are that a DAT_IA_ADDRESS_PTR must be translated to a GID + before a connection initiation can occur. This is discussed below. + + InfiniBand supports different amounts of private data on various + connection functions. The DAPL connection code does not enforce a + fixed amount of private data, but rather makes available to the + user all it has available. When initiating a connection, and when + the remote node accepts a connection, we prefix the user data with + a private data header. The header contains + + - Local host IP address + - private data size + - private data payload + + The underlying implementation will copy the private data into a + buffer to be sent, so we need to assemble all of it before passing + it down to the CM. + + The Local host IP address is required by the DAT spec when a + connection event occurs, and there is no other way for the remote + node to get it; even with a LID or GID the IB implementation could + support multiple IP interfaces, so it must be supplied here. + + The private data size is transmitted to provide the obvious + information. Some CM implementations do not keep track of the size, + so it is required for them; for other implementations it is a + convenience. + + At this time there is no InfiniBand API available that will allow us + to transmit or obtain the host IP address. The DAT Spec is very + careful to avoid imposing a protocol, and yet here is a wire protocol + that vendors must implement if there is any hope of + interoperability. The header just described is currently considered + temporary until a better method can be ascertained, presumably with a + fully working IPoIB implementation. However, it may be the case that + this simple transmission of the host IP address in the private data + is the best solution, in which case it should be promoted into the + DAT Spec as required by InfiniBand providers. + + We observe in passing that the IP address can take up to 16 bytes, + while there are 92 bytes total private data in a REQ message + (connection request); leaving 76 bytes for an application. This + exactly allows the SDP Hello Header to fit in the Private Data + space remaining. An SDP implementation could be done on top of + DAPL. + + +* Addressing and Naming + + The DAT Spec calls for a DAT_IA_ADDRESS_PTR to be an IP address, + either IPv4 or IPv6. It is in fact a struct sockaddr in most + systems. + + The long term solution to resolving an IP address to a GID is to us + an IPoIB implementation with an API capable of performing this + function. At the time of this writing this API is being worked out + with an HCA vendor, with the hope that other HCA vendors will + follow suite. + + Until IPoIB is working properly, the DAPL implementation provides a + simple name service facility under the #ifdef NO_NAME_SERVICE. This + depends on two things: valid IP addresses registered and available + to standard DNS system calls such as gethostbyname(); and a + name/GID mapping file. + + IP addresses may be set up by system administrators or by a local + power user simply by editing the values into the /etc/hosts file. + Setting IP addresses up in this manner is beyond the scope of this + document. + + A simple mapping of names to GIDs is maintained in the ibhosts + file, currently located at /etc/dapl/ibhosts. The format of + the file is: + + 0x 0x + + For example: + + dat-linux3-ib0p0 0xfe80000000000000 0x0001730000003d11 + dat-linux3-ib0p1 0xfe80000000000000 0x0001730000003d11 + dat-linux3-ib1 0xfe80000000000000 0x0001730000003d52 + dat-linux5-ib0 0xfe80000000000000 0x0001730000003d91 + + And for each hostname, there must be an entry in the /etc/hosts file + similar to: + + dat-linux3-ib0p0 198.165.10.11 + dat-linux3-ib0p1 198.165.10.12 + dat-linux3-ib1 198.165.10.21 + dat-linux5-ib0 198.165.10.31 + + + In this example we have adopted the convention of naming each + InfiniBand interface by using the form + + -ib[port_number] + + In the above example we can see that the machine dat-linux3 has three + InfiniBand interfaces, which in this case we have named two ports on + the first HCA and another port on a second. Utilizing standard DNS + naming, the conventions used for identifying individual ports is + completely up to the administrator. + + The GID Prefix and GUID are obtained from the HCA and map a port on + the HCA: together they form the GID that is required by a CM to + connect with the remote node. + + The simple name service builds an internal table after processing + the ibhosts file which contains IP addresses and GIDs. It will use + the standard getaddrinfo() function to obtain IP address + information. + + When an application invoked dat_ep_connect(), the + DAT_IA_ADDRESS_PTR will be compared in the table for a match and + the destination GID established if found. If the address is not + found then the user must first add the name to the ibhosts file. + + With a valid GID for the destination node, the underlying CM is + invoked to make a connection. + +* Connection Management + + Getting a working CM has taken some time, in fact the DAPL project + was nearly complete by the time a CM was available. In order to + make progress, a connection hack was introduced that allows + specific connections to take place. This is noted in the code by + the CM_BUSTED #def. + + CM_BUSTED takes the place of a CM and will manually transition a QP + through the various states to connect: INIT->RTR->RTS. It will also + disconnect the connection, although the Torrent implementation + simply destroys the QP and recreates a new one rather than + transitioning through the typical disconnect states (which didn't + work on early IB implementations). + + CM_BUSTED makes some assumptions about the remote end of the + connection as no real information is exchanged. The Torrent + implementation assumes both HCAs have the same LID, which implies + there is no SM running. The Tavor implementation assumes the LIDs + are 0 and 1. Depending on the hardware, the LID value may in fact + not make any difference. This code does not set the Global Route + Header (GRH), which would cause the InfiniBand chip to be carefully + checking LID information. + + The QP number is assumed to be identical on both ends of the + connection, of differing by 1 if this is a loopback. There is an + environment variable that will be read at initialization time if + you are configured with a loopback, this value is checked when + setting up a QP. The obvious downside to this scheme is that + applications must stay synchronized in their QP usage or the + initial exchange will fail as they are not truly connected. + + Add to this the limitation that HCAs must be connected in + Point-to-Point topology or in a loopback. Without a GRH it will not + work in a fabric. Again, using an SM will not work when CM_BUSTED + is enabled. + + Despite these shortcomings, CM_BUSTED has proven very useful and + will remain in the code for a while in order to aid development + groups with new hardware and software. + +3. dapls_cr_callback + + The connection sequence is entirely event driven. An operation is + posted, then an asynchronous event will occur some time later. The + event may cause other actions to occur which may result in still + more events. + + dapls_ib_setup_conn_listener() registered for a callback for + connection events, and we now receive + IB_CME_CONNECTION_REQUEST_PENDING_PRIVATE_DATA. As has been + discussed above, DAPL will always send private data on a connection + so this is the event we will get. + + The astute reader will observe that there is not a dapl_cr_create + call: CR records are created as part of a connection attempt on the + passive side of the connection. A CR is created now and set up. A + point that will become important later, caps for emphasis: + + A CR WILL EXIST FOR THE LIFE OF A CONNECTION; THEY ARE DESTROYED AT + DISCONNECT TIME. + + In the connection request processing a CR and an EVENT are created, + the event will be posted along with the connection information just + received. + + We also check the PSP to see if an EP is created at this point, and + allocate one if so. The EP will be provided back to the user in the + event, as per the DAT model. + +4. Event code processing +5. Create an EP (unless PSP created) + + (4) and (5) are all done in user mode. The only interesting thing is + that when the user calls dat_cr_accept a ready EP must be + provided. If the EP was supplied by the PSP in the callback, it + must have a PZ associated with it and whatever other attributes + need to be set. + +6. dapl_cr_accept or dapl_cr_reject + + For discussion purposes, we will follow the accept + path. dapl_cr_reject says you are done and there will be no further + events to deal with. + + The accept call is intuitive and simple. Again, private data will + be exchanged and so the private data header is used. The requesting + node presumably know where the request comes from so we don't put + the address into the header here. + +7. dapl_evd_connection_callback + + The connecting side of the connection will now get a callback in + dapl_evd_connection_callback() with connection event + IB_CME_CONNECTED. + + The code will transition the EP to CONNECTED and post a + DAT_CONNECTION_EVENT_ESTABLISHED event for the user to pick up. + The connection is now established, however the passive or server + side of the connection doesn't know it yet: the EP is still in + DAT_EP_STATE_PASSIVE_CONNECTION_PENDING. + +8i. RTU + + This item is labeled "8i" as it is internal to the InfiniBand + implementation, it is not initiated by dapl. The final leg of a + connection is an RTU sent from the initiating node to the server + node, indicating the connection has been made successfully. + +9. dapls_cr_callback + + The RTU above results in another callback into dapls_cr_callback, + this time with connection event IB_CME_CONNECTED. + + There is no reason to deal with private data, from a dapl point of + view this was purely an internal message and simply a connection + state change. A DAT_CONNECTION_EVENT_ESTABLISHED event is created + and posted. + + The architectually interesting feature of this exchange occurs + because of differences in the InfiniBand and the DAT connection + models, which will be briefly outlined. + + InfiniBand maintains the original connecting objects throughout the + life of the connection. That is, we originally get a callback event + associated with the Service (DAT PSP) that is listening for + connection events. A QP will be connected but the callback event + will still be received on the Service. Later, a callback event will + occur for a DISCONNECT, and again the Service will be the object of + the connection. In the DAPL implementation, the Service will + provide the PSP that is registered as listening on that connection + qualifier. + + DAT has a PSP receive a connection event, but subsequently hands + all connection events off to an EP. After a dat_cr_accept is + issued, all connection/disconnection events occur on the EP. + + To support the DAT model the CR is maintained through the life of + the connection. There is exactly one CR per connection, but any + number of CRs may exist for any given PSP. CRs are maintained on a + link list pointed to by the PSP structure. A search routine will + match the cm_handle, unique for each connection, with the + appropriate CR. This allows us to find the appropriate EP which + will be used to create an event to be posted to the user. + +* dat_psp_destroy + + It should be understood that the PSP will maintain all of the CR + records, and hence the PSP must persist until the final disconnect. + In the DAT model there is no association between a PSP and a + connected QP, so there is no reason not to destroy a PSP before the + final disconnect. + + Because of the model mismatch we must preserve the PSP until the + final disconnect. If the user invokes dat_psp_destroy(), all of the + associations maintained by the PSP will be severed; but the PSP + structure itself remains as a container for the CR records. The PSP + structure maintains a simple count of CR records so we can easily + determine the final disconnect and release memory. Once a + disconnect event is received for a specific cm_handle, no further + events will be received and it is safe to discard the CR record. + +10. ...processing... + + This is just a place holder to show that applications actually do + something after making a connection. They might not too... + +11. Either side issues a dat_ep_disconnect + + dat_ep_disconnect() can be initiated by either side of a + connection. There are two kinds of disconnect flags that can be + passed in, but the final result is largely the same. + + DAT_CLOSE_ABRUPT_FLAG will cause the connection to be immediately + terminated. In InfiniBand terms, the QP is immediately moved to the + ERROR state, and after some time it will be moved to the RESET + state. + + DAT_CLOSE_GRACEFUL_FLAG will allow in-progress DTOs to complete. + The underlying implementation will first transition the QP to the + SQE state, before going to RESET. + + Both cases are handled by the underlying CM, there is no extra work + for DAPL. + + +12. dapls_cr_callback + + A disconnect will arrive on the passive side of the connection + through dapls_cr_callback() with connection event + IB_CME_DISCONNECTED. With this event the EP lookup code will free + the CR associated with the connection, and may free the PSP if it + is no longer listening, indicating it has been freed by the + application. + + The callback will create and post a + DAT_CONNECTION_EVENT_DISCONNECTED event for the user. + +13. dapl_evd_connection_callback + + The active side of the connection will receive IB_CME_DISCONNECTED + as the connection event for dapl_evd_connection_callback(), and + will create and post a DAT_CONNECTION_EVENT_DISCONNECTED event. + Other than transitioning the EP to the DISCONNECTED state, there is + no further processing. + + +-- Notes on Disconnecting + +An EP can only be disconnected if it is connected or unconnected; you +cannot disconnect 'in progress' connections. An 'in progress +connection may in fact time out, but the DAT Spec does not allow you +to 'kill' it. DAPL will use the CM interface to disconnect from the +remote node; this of course results in an asynchronous callback +notifying the application the disconnect is complete. + +Disconnecting an unconnected EP is currently the only way to remove +pending RECV operations from the EP. The DAPL spec notes that all +DTO's must be removed from an EP before it can be deallocated, yet +there is no explicit interface to remove pending RECV DTOs. The user +will disconnect an unconnected EP to force the pending operations off +of the queue, resulting in DTO callbacks indicating an error. The +underlying InfiniBand implementation will cause the correct behavior +to result. When doing this operation the DAT_CLOSE flag is ignored, +DAPL will instruct the IB layer to abruptly disconnect the QP. + +As has been noted previously, specifying DAT_CLOSE_ABRUPT_FLAG as the +disconnect completion flag will cause the CM implementation to +transition the QP to the ERROR state to abort all operations, and then +transition to the RESET state; if the flag is DAT_CLOSE_GRACEFUL_FLAG, +the CM will first move to the SQE state and allow all pending I/O's to +drain before moving to the RESET state. In either case, DAPL only +needs to know that the QP is now in the RESET state, as it will need +to be transitioned to the INIT state before it can be used again. + +====================================================================== +Data Transfer Operations (DTOs) +====================================================================== + +The DTO code is a straightforward translation of the DAT_LMR_TRIPLET +to an InfiniBand work request. Unfortunately, IB does not specify what +a work request looks like so this tends to be very vendor specific +code. Each provider will supply a routine for this operation. + +InfiniBand allows the DTO to attach a unique 64 bit work_req_id to +each work request. The DAPL implementation will install a pointer to a +DAPL_DTO_COOKIE in this field. Observe that a DAPL_DTO_COOKIE is not +the same as the user DAT_DTO_COOKIE; indeed, the former has a pointer +field pointing to the latter. Different values will be placed in the +cookie, according to the type of operation it is and the type of data +required by its completion event. This is a simple scheme to bind DAPL +data to the DTO and associated completion callback. Each DTO has a +unique cookie associated with it. + +DAPL_DTO_COOKIE structures are currently allocated using a simple +malloc. An obvious performance gain can be had by using a ready made +pool of structures to minimize the time involved on this critical +path. + +The underlying InfiniBand implementation will invoke +dapl_evd_dto_callback() upon completion of DTO operations. During the +development of the Reference Implementation there was a period when +DTO callbacks were not working, so we implemented a mechanism where a +thread continually polls the CQs looking for completions, and then +invokes the callback when something completes. This code may be useful +in the future and is still maintained in the code under the +POLLING_COMPLETIONS #ifdef. + +POLLING_COMPLETIONS will simulate callbacks but will not provide a high +performance implementation. + +dapl_evd_dto_callback() is the asynchronous completion for a DTO and +will create and post an event for the user. Much of this callback is +concerned with managing error completions. + + +====================================================================== +Data Structure +====================================================================== + +The main data structure for and EndPoint is the dapl_ep structure, +defined in include/dapl.h. The reference implementation uses the +InfiniBand QP to maintain hardware state, providing a relatively +simple mapping. + +/* DAPL_EP maps to DAT_EP_HANDLE */ +struct dapl_ep +{ + DAPL_HEADER header; + /* What the DAT Consumer asked for */ + DAT_EP_PARAM param; + + /* The RC Queue Pair (IBM OS API) */ + ib_qp_handle_t qp_handle; + int qpn; /* qp number */ + Ib_qp_state qp_state; + + /* communications manager handle (IBM OS API) */ + ib_cm_handle_t cm_handle; + + /* The DTO Circular buffers */ + DAPL_RING_BUFFER out; + DAPL_RING_BUFFER in; + + /* state dependent connection event handler */ + DAPL_CONNECTION_STATE_HANDLER ep_connect_handler; +}; + + +The simple explanation of the fields in the dapl_ep structure follows: + +header: The dapl object header, common to all dapl objects. + It contains a lock field, links to appropriate lists, and + handles specifying the IA domain it is a part of. + +param: The bulk of the EP attributes called out in the DAT + specification and are maintained in the DAT_EP_PARAM + structure. All internal references to these fields + use this structure. + +qp_handle: Handle to the underlying InfiniBand provider implementation + for a QP. All EPs are mapped to an InfiniBand QP. + +qpn: Number of the QP as returned by the underlying provider + implementation. Primarily useful for debugging. + +qp_state: Current state of the QP. The values of this field indicate + if a QP is bound to the EP, and the current state of a + QP. + +cm_handle: Handle to the IB provider's CMA (Connection Manager Agent). + Used for CM operations used to connect and disconnect. + +out: Ring buffer tracking all SEND work requests (WR). A WR + is put into the list when a SEND is initiated, then removed + when the send completes. + +in: Ring buffer tracking all RECV work requests (WR). A WR + is put into the list when a RECV is initiated, then removed + when the recv completes. + +ep_connect_handler: + Pointer to callback routine invoked when CM events appear. + MAY BE UNUSED IN THE IMPLEMENTATION. diff --git a/branches/WOF2-3/ulp/dapl/doc/dapl_environ.txt b/branches/WOF2-3/ulp/dapl/doc/dapl_environ.txt new file mode 100644 index 00000000..6cca3b27 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/doc/dapl_environ.txt @@ -0,0 +1,42 @@ + DAPL Environment Guide v. 0.01 + ------------------------------ + +The following environment variables affect the behavior of the DAPL +provider library: + + +DAPL_DBG_TYPE +------------- + + Value specifies which parts of the registry will print debugging + information, valid values are + + DAPL_DBG_TYPE_ERR = 0x0001 + DAPL_DBG_TYPE_WARN = 0x0002 + DAPL_DBG_TYPE_EVD = 0x0004 + DAPL_DBG_TYPE_CM = 0x0008 + DAPL_DBG_TYPE_EP = 0x0010 + DAPL_DBG_TYPE_UTIL = 0x0020 + DAPL_DBG_TYPE_CALLBACK = 0x0040 + DAPL_DBG_TYPE_DTO_COMP_ERR = 0x0080 + DAPL_DBG_TYPE_API = 0x0100 + DAPL_DBG_TYPE_RTN = 0x0200 + DAPL_DBG_TYPE_EXCEPTION = 0x0400 + + or any combination of these. For example you can use 0xC to get both + EVD and CM output. + + Example setenv DAPL_DBG_TYPE 0xC + + +DAPL_DBG_DEST +------------- + + Value sets the output destination, valid values are + + DAPL_DBG_DEST_STDOUT = 0x1 + DAPL_DBG_DEST_SYSLOG = 0x2 + DAPL_DBG_DEST_ALL = 0x3 + + For example, 0x3 will output to both stdout and the syslog. + diff --git a/branches/WOF2-3/ulp/dapl/doc/dapl_event_design.txt b/branches/WOF2-3/ulp/dapl/doc/dapl_event_design.txt new file mode 100644 index 00000000..0b896bb7 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/doc/dapl_event_design.txt @@ -0,0 +1,875 @@ + DAPL Event Subsystem Design v. 0.96 + ----------------------------------- + +================= +Table of Contents +================= + +* Table of Contents +* Referenced Documents +* Goals + + Initial Goals + + Later Goals +* Requirements, constraints, and design inputs + + DAT Specification Constraints + + Object and routine functionality, in outline + + Detailed object and routine specification + + Synchronization + + IBM Access API constraints + + Nature of DAPL Event Streams in IBM Access API. + + Nature of access to CQs + + Operating System (Pthread) Constraints + + Performance model + + A note on context switches +* DAPL Event Subsystem Design + + OS Proxy Wait Object + + Definition + + Suggested Usage + + Event Storage + + Synchronization + + EVD Synchronization: Locking vs. Producer/Consumer queues + + EVD Synchronization: Waiter vs. Callback + + CNO Synchronization + + Inter-Object Synchronization + + CQ -> CQEH Assignments + + CQ Callbacks + + Dynamic Resizing of EVDs + + Structure and pseudo-code + + EVD + + CNO +* Future directions + + Performance improvements: Reducing context switches + + Performance improvements: Reducing copying of event data + + Performance improvements: Reducing locking + + Performance improvements: Reducing atomic operations + + Performance improvements: Incrementing concurrency. + +==================== +Referenced Documents +==================== + +uDAPL: User Direct Access Programming Library, Version 1.0. Published +6/21/2002. http://www.datcollaborative.org/uDAPL_062102.pdf. +Referred to in this document as the "DAT Specification". + +InfiniBand Access Application Programming Interface Specification, +Version 1.2, 4/15/2002. In DAPL SourceForge repository at +doc/api/access_api.pdf. Referred to in this document as the "IBM +Access API Specification". + +===== +Goals +===== + +Initial goals +------------- +-- Implement the dat_evd_* calls described in the DAT Specification (except + for dat_evd_resize). + +-- The implementation should be as portable as possible, to facilitate + HCA Vendors efforts to implement vendor-specific versions of DAPL. + +Later goals +----------- +-- Examine various possible performance optimizations. This document + lists potential performance improvements, but the specific + performance improvements implemented should be guided by customer + requirements. + +-- Implement the dat_cno_* calls described in the DAT 1.0 spec + +-- Implement OS Proxy Wait Objects. + +-- Implement dat_evd_resize + +Non-goals +--------- +-- Thread safe implementation + +============================================ +Requirements, constraints, and design inputs +============================================ + +DAT Specification Constraints +----------------------------- + +-- Object and routine functionality, in outline + +The following section summarizes the requirements of the DAT +Specification in a form that is simpler to follow for purposes of +implementation. This section presumes the reader has read the DAT +Specification with regard to events. + +Events are delivered to DAPL through Event Streams. Each Event Stream +targets a specific Event Descriptor (EVD); multiple Event Streams may +target the same EVD. The Event Stream<->EVD association is +effectively static; it may not be changed after the time at which +events start being delivered. The DAT Consumer always retrieves +events from EVDs. EVDs are intended to be 1-to-1 associated with the +"native" event convergence object on the underlying transport. For +InfiniBand, this would imply a 1-to-1 association between EVDs and +CQs. + +EVDs may optionally have an associated Consumer Notification Object +(CNO). Multiple EVDs may target the same CNO, and the EVD<->CNO +association may be dynamically altered. The DAT Consumer may wait for +events on either EVDs or CNOs; if there is no waiter on an EVD and it +is enabled, its associated CNO is triggered on event arrival. An EVD +may have only a single waiter; a CNO may have multiple waiters. +Triggering of a CNO is "sticky"; if there is no waiter on a CNO when +it is triggered, the next CNO waiter will return immediately. + +CNOs may have an associated OS Proxy Wait Object, which is signaled +when the CNO is triggered. + +-- Detailed object and routine specification + +Individual events may be "signaling" or "non-signaling", depending +on the interaction of: + * Receive completion endpoint attributes + * Request completion endpoint attributes + * dat_ep_post_send completion flags + * dat_ep_post_recv completion flags +The nature of this interaction is outside the scope of this document; +see the DAT Specification 1.0 (or, failing that, clarifications in a +later version of the DAT Specification). + +A call to dat_evd_dequeue returns successfully if there are events on +the EVD to dequeue. A call to dat_evd_wait blocks if there are fewer +events present on the EVD than the value of the "threshold" parameter +passed in the call. Such a call to dat_evd_wait will be awoken by the +first signaling event arriving on the EVD that raises the EVD's event +count to >= the threshold value specified by dat_evd_wait(). + +If a signaling event arrives on an EVD that does not have a waiter, +and that EVD is enabled, the CNO associated with the EVD will be +triggered. + +A CNO has some number of associated waiters, and an optional +associated OS Proxy Wait Object. When a CNO is triggered, two things +happen independently: + * The OS Proxy Wait Object associated with the CNO, if any, is + signaled, given the handle of an EVD associated with the CNO + that has an event on it, and disassociated from the CNO. + * If: + * there is one or more waiters associated with the + CNO, one of the waiters is unblocked and given the + handle of an EVD associated with the CNO that has an + event on it. + * there are no waiters associated with the CNO, the + CNO is placed in the triggered state. + +When a thread waits on a CNO, if: + * The CNO is in the untriggered state, the waiter goes to + sleep pending the CNO being triggered. + * The CNO is in the triggered state, the waiter returns + immediately with the handle of an EVD associated with the + CNO that has an event on it, and the CNO is moved to the + untriggered state. + +Note specifically that the signaling of the OS Proxy Wait Object is +independent of the CNO moving into the triggered state or not; it +occurs based on the state transition from Not-Triggered to Triggered. +Signaling the OS Proxy Wait Object only occurs when a CNO is +triggered. In contrast, waiters on a CNO are unblocked whenever the +CNO is in the triggered *state*, and that state is sticky. + +Note also that which EVD is returned to the caller in a CNO wait is +not specified; it may be any EVD associated with the CNO on which an +event arrival might have triggered the CNO. This includes the +possibility that the EVD returned to the caller may not have any +events on it, if the dat_cno_wait() caller raced with a separate +thread doing a dat_evd_dequeue(). + +The DAT Specification is silent as to what behavior is to be expected +from an EVD after an overflow error has occurred on it. Thus this +design will also be silent on that issue. + +The DAT Specification has minimal requirements on inter-Event Stream +ordering of events. Specifically, any connection events must precede +(in consumption order) any DTO Events for the same endpoint. +Similarly, any successful disconnection events must follow any DTO +Events for an endpoint. + +-- Synchronization + +Our initial implementation is not thread safe. This means that we do +not need to protect against the possibility of multiple simultaneous +user calls occurring on the same object (EVD, CNO, EP, etc.); that is +the responsibility of the DAT Consumer. + +However, there are synchronization guards that we do need to protect +against because the DAT Consumer cannot. Specifically, since the user +cannot control the timing of callbacks from the IBM Access API +Implementation, we need to protect against possible collisions between +user calls and such callbacks. We also need to make sure that such +callbacks do not conflict with one another in some fashion, possibly +by assuring that they are single-threaded. + +In addition, for the sake of simplicity in the user interface, I have +defined "not thread safe" as "It is the DAT Consumer's responsibility +to make sure that all calls against an individual object do not +conflict". This does, however, suggest that the DAPL library needs to +protect against calls to different objects that may result in +collisions "under the covers" (e.g. a call on an EVD vs. a call on its +associated CNO). + +So our synchronization requirements for this implementation are: + + Protection against collisions between user calls and IBM + Access API callbacks. + + Avoidance of or protection against collisions between + different IBM Access API callbacks. + + Protection against collisions between user calls targeted at + different DAT objects. + +IBM Access API constraints +-------------------------- + +-- Nature of DAPL Event Streams in IBM Access API + +DAPL Event Streams are delivered through the IBM Access API in two fashions: + + Delivery of a completion to a CQ. + + A callback is made directly to a previously registered DAPL + function with parameters describing the event. +(Software events are not delivered through the IBM Access API). + +The delivery of a completion to a CQ may spark a call to a previously +registered callback depending on the attributes of the CQ and the +reason for the completion. Event Streams that fall into this class +are: + + Send data transport operation + + Receive data transport operation + + RMR bind + +The Event Streams that are delivered directly through a IBM Access API +callback include: + + Connection request arrival + + Connection resolution (establishment or rejection) + + Disconnection + + Asynchronous errors + +Callbacks associated with CQs are further structured by a member of a +particular CQ Event Handling (CQEH) domain (specified at CQ creation +time). All CQ callbacks within a CQEH domain are serviced by the same +thread, and hence will not collide. + +In addition, all connection-related callbacks are serviced by the same +thread, and will not collide. Similarly, all asynchronous error +callbacks are serviced by the same thread, and will not collide. +Collisions between any pair of a CQEH domain, a connection callback, +and an asynchronous error callback are possible. + +-- Nature of access to CQs + +The only probe operation the IBM Access API allows on CQs is +dequeuing. The only notification operation the IBM Access API +supports for CQs is calling a previously registered callback. + +Specifically, the IB Consumer may not query the number of completions +on the CQ; the only way to find out the number of completions on a CQ +is through dequeuing them all. It is not possible to block waiting +on a CQ for the next completion to arrive, with or without a +threshold parameter. + +Operating System Constraints +---------------------------- + +The initial platform for implementation of DAPL is RedHat Linux 7.2 on +Intel hardware. On this platform, inter-thread synchronization is +provided by a POSIX Pthreads implementation. From the viewpoint of +DAPL, the details of the Pthreads interface are platform specific. +However, Pthreads is a very widely used threading library, common on +almost all Unix variants (though not used on the different variations +of Microsoft Windows(tm)). In addition, RedHat Linux 7.2 provides +POSIX thread semaphore operations (e.g. see sem_init(3)), which are +not normally considered part of pthreads. + +Microsoft Windows(tm) provides many synchronization primitives, +including mutual exclusion locks, and semaphores. + +DAPL defines an internal API (not exposed to the consumer), though +which it accesses Operating Systems Dependent services; this is called +the OSD API. It is intended that this layer contain all operating +system dependencies, and that porting DAPL to a new operating system +should only require changes to this layer. + +We have chosen to define the synchronization interfaces established at +this layer in terms of two specific objects: mutexes and sempahores w/ +timeout on waiting. Mutexes provide mutual exclusion in a way that is +common to all known operating systems. The functionality of +semaphores also exists on most known operating systems, though the +sempahores provided by POSIX do not provide timeout capabilities. +This is for three reasons. First, in contrast to Condition Variables +(the native pthreads waiting/signalling object), operations on +sempahores do not require use of other synchronization variables +(i.e. mutexes). Second, it is fairly easy to emulate sempahores using +condition variables, and it is not simple to emulate condition +variables using semaphores. And third, there are some anticipated +platforms for DAPL that implement condition variables in relation to +some types of locks but not others, and hence constrain appropriate +implementation choices for a potential DAPL interface modeled after +condition variables. + +Implementation of the DAPL OS Wait Objects will initially be based on +condition variables (requiring the use of an internal lock) since +POSIX semaphores do not provide a needed timeout capability. However, +if improved performance is required, a helper thread could be created +that arranges to signal waiting semaphores when timeouts have +expired. This is a potential future (or vendor) optimization. + +Performance Model +----------------- +One constraint on the DAPL Event Subsystem implementation is that it +should perform as well as possible. We define "as well as possible" +by listing the characteristics of this subsystem that will affect its +performance most strongly. In approximate order of importance, these +are: + + The number of context switches on critical path + + The amount of copying on the critical path. + + The base cost of locking (assuming no contention) on the + critical path. This is proportional to the number of locks + taken. + + The amount of locking contention expected. We make a + simplifying assumption and take this as the number of cycles + for which we expect to hold locks on the critical path. + + The number of "atomic" bus operations executed (these take + more cycles than normal operations, as they require locking + the bus). + +We obviously wish to minimize all of these costs. + +-- A note on context switches + +In general, it's difficult to minimize context switches in a user +space library directly communicating with a hardware board. This is +because context switches, by their nature, have to go through the +operating system, but the information about which thread to wake up +and whether to wake it up is generally in user space. In addition, +the IBM Access API delivers all Event Streams as callbacks in user +context (as opposed to, for example, allowing a thread to block within +the API waiting for a wakeup). For this reason, the default sequence +of events for a wakeup generated from the hardware is: + * Hardware interrupts the main processor. + * Interrupt thread schedules a user-level IBM Access API + provider service thread parked in the kernel. + * Provider service thread wakes up the sleeping user-level + event DAT implementation thread. +This implies that any wakeup will involve three context switches. +This could be reduced by one if there were a way for user threads to +block in the kernel, we might skip the user-level provider thread. + +=========================== +DAPL Event Subsystem Design +=========================== + + +OS Proxy Wait Object +-------------------- + +The interface and nature of the OS Proxy Wait Object is specified in +the uDAPL v. 1.0 header files as a DAT_OS_WAIT_PROXY_AGENT via the +following defines: + +typedef void (*DAT_AGENT_FUNC) + ( + DAT_PVOID, /* instance data */ + DAT_EVD_HANDLE /* Event Dispatcher*/ + ); + +typedef struct dat_os_wait_proxy_agent + { + DAT_PVOID instance_data; + DAT_AGENT_FUNC proxy_agent_func; + } DAT_OS_WAIT_PROXY_AGENT; + +In other words, an OS Proxy Wait Object is a (function, data) pair, +and signalling the OS Proxy Wait Object is a matter of calling the +function on the data and an EVD handle associated with the CNO. +The nature of that function and its associated data is completely up +to the uDAPL consumer. + +Event Storage +------------- + +The data associated with an Event (the type, the EVD, and any type +specific data required) must be stored between event production and +event consumption. If storage is not provided by the underlying +Verbs, that data must be stored in the EVD itself. This may require +an extra copy (one at event production and one at event consumption). + +Event Streams associated purely with callbacks (i.e. IB events that +are not mediated by CQs) or user calls (i.e. software events) don't +have any storage allocated for them by the underlying verbs and hence +must store their data in the EVD. + +Event Streams that are associated with CQs have the possibility of +leaving the information associated with the CQ between the time the +event is produced and the time it is consumed. However, even in this +case, if the user calls dat_evd_wait with a threshold argument, the +events information must be copied to storage in the CQ. This is +because it is not possible to determine how many completions there are +on a CQ without dequeuing them, and that determination must be made by +the CQ notification callback in order to decide whether to wakeup a +dat_evd_wait() waiter. Note that this determination must be made +dynamically based on the arguments to dat_evd_wait(). + +Further, leaving events from Event Streams associated with the CQs "in +the CQs" until event consumption raises issues about in what order +events should be dequeued if there are multiple event streams entering +an EVD. Should the CQ events be dequeued first, or should the events +stored in the EVD be dequeued first? In general this is a complex +question; the uDAPL spec does not put many restrictions on event +order, but the major one that it does place is to restrict connection +events associated with a QP to be dequeued before DTOs associated with +that QP, and disconnection events after. Unfortunately, if we adopt +the policy of always dequeueing CQ events first, followed by EVD +events, this means that in situations where CQ events have been copied +to the EVD, CQ events may be received on the EVD out of order. + +However, leaving events from Event Streams associated with CQs allows +us to avoid enabling CQ callbacks in cases where there is no waiter +associated with the EVDs. This can be a potentially large savings of +gratuitous context switches. + +For the initial implementation, we will leave all event information +associated with CQs until dequeued by the consumer. All other event +information will be put in storage on the EVD itself. We will always +dequeue from the EVD first and the CQ second, to handle ordering among +CQ events in cases in which CQ events have been copied to the EVD. + + +Synchronization +--------------- + +-- EVD synchronization: Locking vs. Producer/Consumer queues. + +In the current code, two circular producer/consumer queues are used +for non-CQ event storage (one holds free events, one holds posted +events). Event producers "consume" events from the free queue, and +produce events onto the posted event queue. Event consumers consume +events from the posted event queue, and "produce" events onto the free +queue. In what follows, we discuss synchronization onto the posted +event queue, but since the usage of the queues is symmetric, all of +what we say also applies to the free event queue (just in the reverse +polarity). + +The reason for using these circular queues is to allow synchronization +between producer and consumer without locking in some situations. +Unfortunately, a circular queue is only an effective method of +synchronization if we can guarantee that there are only two accessors +to it at a given time: one producer, and one consumer. The model will +not work if there are multiple producers, or if there are multiple +consumers (though obviously a subsidiary lock could be used to +single-thread either the producers or the consumers). + +There are several difficulties with guaranteeing the producers and +consumers will each be single threaded in accessing the EVD: + * Constraints of the IB specification and IBM Access API + (differing sources for event streams without guarantees of + IB provider synchronization between them) make it difficult + to avoid multiple producers. + * The primitives used for the producer/consumer queue are not + as widely accepted as locks, and may render the design less + portable. + +We will take locks when needed when producing events. The details of +this plan are described below. + +This reasoning is described in more detail below to inform judgments +about future performance improvements. + +* EVD producer synchronization + +The producers fall into two classes: + * Callbacks announcing IA associated events such as connection + requests, connections, disconnections, DT ops, RMR bind, + etc. + * User calls posting a software event onto the EVD. + +It is the users responsibility to protect against simultaneous +postings of software events onto the same EVD. Similarly, the CQEH +mechanism provided by the IBM Access API allows us to avoid collisions +between IBM Access API callbacks associated with CQs. However, we +must protect against software events colliding with IBM Access API +callbacks, and against non-CQ associated IB verb callbacks (connection +events and asynchronous errors) colliding with CQ associated IBM +Access API callbacks, or with other non-CQ associated IBM Access API +callbacks (i.e. a connection callback colliding with an asynchronous +error callback). + +Note that CQ related callbacks do not act as producers on the circular +list; instead they leave the event information on the CQ until +dequeue; see "Event Storage" above. However, there are certain +situations in which it is necessary for the consumer to determine the +number of events on the EVD. The only way that IB provides to do this +is to dequeue the CQEs from the CQ and count them. In these +situations, the consumer will also act as an event producer for the +EVD event storage, copying all event information from the CQ to the +EVD. + +Based on the above, the only case in which we may do without locking +on the producer side is when all Event Streams of all of the following +types may be presumed to be single threaded: + * Software events + * Non-CQ associated callbacks + * Consumer's within dat_evd_wait + +We use a lock on the producer side of the EVD whenever we have +multiple threads of producers. + +* EVD Consumer synchronization + +It is the consumer's responsibility to avoid multiple callers into +dat_evd_wait and dat_evd_dequeue. For this reason, there is no +requirement for a lock on the consumer side. + +* CQ synchronization + +We simplify synchronization on the CQ by identifying the CQ consumer +with the EVD consumer. In other words, we prohibit any thread other +than a user thread in dat_evd_wait() or dat_evd_dequeue() from +dequeueing events from the CQ. This means that we can rely on the +uDAPL spec guarantee that only a single thread will be in the +dat_evd_wait() or dat_evd_dequeue() on a single CQ at a time. It has +the negative cost that (because there is no way to probe for the +number of entries on a CQ without dequeueing) the thread blocked in +dat_evd_wait() with a threshold argument greater than 1 will be woken +up on each notification on that CQ, in order to dequeue entries from +the CQ and determine if the threshold value has been reached. + +-- EVD Synchronization: Waiter vs. Callback + +Our decision to restrict dequeueing from the IB CQ to the user thread +(rather than the notification callback thread) means that +re-requesting notifications must also be done from that thread. This +leads to a subtle requirement for synchronization: the request for +notification (ib_completion_notify) must be atomic with the wait on +the condition variable by the user thread (atomic in the sense that +locks must be held to force the signalling from any such notification +to occur after the sleep on the condition variable). Otherwise it is +possible for the notification requested by the ib_completion_notify +call to occur before the return from that call. The signal done by +that notify will be ignored, and no further notifications will be +enabled, resulting in the thread sleep waiting forever. The CQE +associated with the notification might be noticed upon return from the +notify request, but that CQE might also have been reaped by a previous +call. + +-- CNO Synchronization + +In order to protect data items that are changed during CNO signalling +(OS Proxy Wait Object, EVD associated with triggering, CNO state), it +is necessary to use locking when triggering and waiting on a CNO. + +Note that the synchronization between trigerrer and waiter on CNO must +take into account the possibility of the waiter returning from the +wait because of a timeout. I.e. it must handle the possibility that, +even though the waiter was detected and the OS Wait Object signalled +under an atomic lock, there would be no waiter on the OS Wait Object +when it was signalled. To handle this case, we make the job of the +triggerer to be setting the state to triggered and signalling the OS +Wait Object; all other manipulation is done by the waiter. + +-- Inter-Object Synchronization + +By the requirements specified above, the DAPL implementation is +responsible for avoiding collisions between DAT Consumer calls on +different DAT objects, even in a non-thread safe implementation. +Luckily, no such collisions exist in this implementation; all exported +DAPL Event Subsystem calls involve operations only on the objects to +which they are targeted. No inter-object synchronization is +required. + +The one exception to this is the posting of a software event on an EVD +associated with a CNO; this may result in triggering the CNO. +However, this case was dealt with above in the discussion of +synchronizing between event producers and consumers; the posting of a +software event is a DAPL API call, but it's also a event producer. + +To avoid lock hierarchy issues between EVDs and CNOs and minimize lock +contention, we arrange not to hold the EVD lock when triggering the +CNO. That is the only context in which we would naturally attempt to +hold both locks. + +-- CQ -> CQEH Assignments + +For the initial implementation, we will assign all CQs to the same +CQEH. This is for simplicity and efficient use of threading +resources; we do not want to dedicate a thread per CQ (where the +number of CQs may grow arbitrarily high), and we have no way of +knowing which partitioning of CQs is best for the DAPL consumer. + +CQ Callbacks +------------ + +The responsibility of a CQ callback is to wakeup any waiters +associated with the CQ--no data needs to be dequeued/delivered, since +that is always done by the consumer. Therefore, CQ callbacks must be +enabled when: + * Any thread is in dat_evd_wait() on the EVD associated with + the CQ. + * The EVD is enabled and has a non-null CNO. (An alternative + design would be to have waiters on a CNO enable callbacks on + all CQs associated with all EVDs associated with the CNO, + but this choice does not scale well as the number of EVDs + associated with a CNO increases). + +Dynamic Resizing of EVDs +------------------------ + +dat_evd_resize() creates a special problem for the implementor, as it +requires that the storage allocated in the EVD be changed in size as +events may be arriving. If a lock is held by all operations that use +the EVD, implementation of dat_evd_resize() is trivial; it substitutes +a new storage mechanism for the old one, copying over all current +events, all under lock. + +However, we wish to avoid universal locking for the initial +implementation. This puts the implementation of dat_evd_resize() into +a tar pit. Because of the DAT Consumer requirements for a non-thread +safe DAPL Implementation, there will be no danger of conflict with +Event Consumers. However, if an Event Producer is in process of +adding an event to the circular list when the resize occurs, that +event may be lost or overwrite freed memory. + +If we are willing to make the simplifying decision that any EVD that +has non-CQ events on it will always do full producer side locking, we +can solve this problem relatively easily. Resizing of the underlying +CQ can be done via ib_cq_resize(), which we can assume available +because of the IB spec. Resizing of the EVD storage may be done under +lock, and there will be no collisions with other uses of the EVD as +all other uses of the EVD must either take the lock or are prohibitted +by the uDAPL spec. + +dat_evd_resize() has not yet been implemented in the DAPL Event +subsystem. + +Structure and pseudo-code +------------------------- + +-- EVD + +All EVDs will have associated with them: + + a lock + + A DAPL OS Wait Object + + An enabled/disabled bit + + A CNO pointer (may be null) + + A state (no_waiter, waiter, dead) + + A threshold count + + An event list + + A CQ (optional, but common) + +Posting an event to the EVD (presumably from a callback) will involve: +^ + Checking for valid state +|lock A + Putting the event on the event list +| ^lock B + Signal the DAPL OS Wait Object, if appropriate +v v (waiter & signaling event & over threshold) + + Trigger the CNO if appropriate (enabled & signaling + event & no waiter). Note that the EVD lock is not + held for this operation to avoid holding multiple locks. + +("lock A" is used if producer side locking is needed. "lock B" is +used if producer side locking is not needed. Regardless, the lock is +only held to confirm that the EVD is in the WAITED state, not for +the wakeup). + +Waiting on an EVD will include: + + Loop: + + Copy all elements from CQ to EVD + + If we have enough, break + + If we haven't enabled the CQ callback + + Enable it + + Continue + + Sleep on DAPL OS Wait Object + + Dequeue and return an event + +The CQ callback will include: + + If there's a waiter: + + Signal it + + Otherwise, if the evd is in the OPEN state, there's + a CNO, and the EVD is enabled: + + Reenable completion + + Trigger CNO + +Setting the enable/disable state of the EVD or setting the associated +CNO will simply set the bits and enable the completion if needed (if a +CNO trigger is implied); no locking is required. + +-- CNO + +All CNOs will have associated with them: + + A lock + + A DAPL OS Wait Object + + A state (triggered, untriggered, dead) + + A waiter count + + An EVD handle (last event which triggered the CNO) + + An OS Proxy Wait Object pointer (may be null) + +Triggering a CNO will involve: + ^ + If the CNO state is untriggerred: + | + Set it to triggered + | + Note the OS Proxy wait object and zero it. + | + If there are any waiters associated with the CNO, + | signal them. + v + Signal the OS proxy wait object if noted + +Waiting on a CNO will involve: + ^ + While the state is not triggered and the timeout has not occurred: + | + Increment the CNO waiter count + lock + Wait on the DAPL OS Wait Object + | + Decrement the CNO waiter count + v + If the state is trigerred, note fact&EVD and set to untrigerred. + + Return EVD and success if state was trigerred + + Return timeout otherwise + +Setting the OS Proxy Wait Object on a CNO, under lock, checks for a +valid state and sets the OS Proxy Wait Object. + + +============== +Known Problems +============== + +-- Because many event streams are actually delivered to EVDs by + callbacks, we cannot in general make any guarantees about the order + in which those event streams arrive; we are at the mercy of the + thread scheduler. Thus we cannot hold to the guarantee given by + the uDAPL 1.0 specification that within a particular EVD, + connection events on a QP will always be before successful DTO + operations on that QP. + + Because we have chosen to dequeue EVD events first and CQ events + second, we will also not be able to guarantee that all successful + DTO events will be received before a disconnect event. Ability to + probe the CQ for its number of entries would solve this problem. + + +================= +Future Directions +================= + +This section includes both functionality enhancements, and a series of +performance improvements. I mark these performance optimizations with +the following flags: + * VerbMod: Requires modifications to the IB Verbs/the IBM + Access API to be effective. + * VerbInteg: Requires integration between the DAPL + implementation and the IB Verbs implementation and IB device + driver. + +Functionality Enhancements +-------------------------- + +-- dat_evd_resize() may be implemented by forcing producer side + locking whenever an event producer may occur asynchronously with + calls to dat_evd_resize() (i.e. when there are non-CQ event streams + associated with the EVD). See the details under "Dynamic Resizing + of EVDs" above. + +-- [VerbMod] If we ahd a verbs modification allowing us to probe for + the current number of entries on a CQ, we could: + * Avoid waking up a dat_evd_wait(threshold>1) thread until + there were enough events for it. + * Avoid copying events from the CQ to the EVD to satisfy the + requirements of the "*nmore" out argument to dat_evd_wait(), + as well as the non-unary threshold argument. + * Implement the "all successful DTO operation events before + disconnect event" uDAPL guarantee (because we would no + longer have to copy CQ events to an EVD, and hence dequeue + first from the EVD and then from the CQ. + This optimization also is relevant for two of the performance + improvements cases below (Reducing context switches, and reducing + copies). + + +Performance improvements: Reducing context switches +--------------------------------------------------- +-- [VerbMod] If we had a verbs modification allowing us to probe for + the current size of a CQ, we could avoid waking up a + dat_evd_wait(threshhold>1) thread until there were enough events + for it. See the Functionality Enhancement entry covering this + possibility. + +-- [VerbMod] If we had a verbs modification allowing threads to wait + for completions to occur on CQs (presumably in the kernel in some + efficient manner), we could optimize the case of + dat_evd_wait(...,threshold=1,...) on EVDs with only a single CQ + associated Event Stream. In this case, we could avoid the extra + context switch into the user callback thread; instead, the user + thread waiting on the EVD would be woken up by the kernel directly. + +-- [VerbMod] If we had the above verbs modification with a threshold + argument on CQs, we could implement the threshold=n case. + +-- [VerbInteg] In general, It would be useful to provide ways for + threads blocked on EVDs or CNOs to sleep in the hardware driver, + and for the driver interrupt thread to determine if they should be + awoken rather than handing that determination off to another, + user-level thread. This would allow us to reduce by one the number + of context switches required for waking up the various blocked + threads. + +-- If an EVD has only a single Event Stream coming into it that is + only associated with one work queue (send or receive), it may be + possible to create thresholding by marking only ever nth WQE on + the associated send or receive WQ to signal a completion. The + difficulty with this is that the threshold is specified when + waiting on an EVD, and requesting completion signaling is + specified when posting a WQE; those two events may not in general + be synchronized enough for this strategy. It is probably + worthwhile letting the consumer implement this strategy directly if + they so choose, by specifying the correct flags on EP and DTO so + that the CQ events are only signaling on every nth completion. + They could then use dat_evd_wait() with a threshold of 1. + +Performance improvements: Reducing copying of event data +-------------------------------------------------------- +-- [VerbMod] If we had the ability to query a CQ for the number of + completions on it, we could avoid the cost of copying event data from the + CQ to the EVD. This is a duplicate of the second entry under + "Functionality Enhancements" above. + +Performance improvements: Reducing locking +------------------------------------------ +-- dat_evd_dequeue() may be modified to not take any locks. + +-- If there is no waiter associated with an EVD and there is only a + single event producer, we may avoid taking any locks in producing + events onto that EVD. This must be done carefully to handle the + case of racing with a waiter waiting on the EVD as we deliver the + event. + +-- If there is no waiter associated with an EVD, and we create a + producer/consumer queue per event stream with a central counter + modified with atomic operations, we may avoid locking on the EVD. + +-- It may be possible, though judicious use of atomic operations, to + avoid locking when triggering a CNO unless there is a waiter on the + CNO. This has not been done to keep the initial design simple. + +Performance improvements: Reducing atomic operations +---------------------------------------------------- +-- We could combine the EVD circular lists, to avoid a single atomic + operation on each production and each consumption of an event. In + this model, event structures would not move from list to list; + whether or not they had valid information on them would simply + depend on where they were on the lists. + +-- We may avoid the atomic increments on the circular queues (which + have a noticeable performance cost on the bus) if all accesses to an + EVD take locks. + + +Performance improvements: Increasing concurrency +------------------------------------------------ +-- When running on a multi-CPU platform, it may be appropriate to + assign CQs to several separate CQEHs, to increase the concurrency + of execution of CQ callbacks. However, note that consumer code is + never run within a CQ callback, so those callbacks should take very + little time per callback. This plan would only make sense in + situations where there were very many CQs, all of which were + active, and for whatever reason (high threshold, polling, etc) + user threads were usually not woken up by the execution of a + provider CQ callback. + + diff --git a/branches/WOF2-3/ulp/dapl/doc/dapl_memory_management_design.txt b/branches/WOF2-3/ulp/dapl/doc/dapl_memory_management_design.txt new file mode 100644 index 00000000..70d41dba --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/doc/dapl_memory_management_design.txt @@ -0,0 +1,173 @@ +####################################################################### +# # +# DAPL Memory Management Design # +# # +# James Lentini # +# jlentini at users.sourceforge.net # +# # +# Created 05/06/2002 # +# Updated 08/22/2002 # +# # +####################################################################### + + +Contents +------- +0. Introduction +1. Protection Zones (PZs) +2. Local Memory Regions (LMRs) +3. Remote Memory Regions (RMRs) + + +0. Introduction +--------------- + + The memory management subsystem allows consumers to register and +unregister memory regions. The DAT API distinguishes between local +and remote memory areas. The former server as local buffers for DTO +operations while the later are used for RDMA operations. + +Each DAT function is implemented in a file named dapl_.c. +For example, dat_pz_create is implemented in dapl_pz_create.c. There +are also dapl__util.{h,c} files for each object. For +example, there are dapl_pz_util.h and dapl_pz_util.c files. The +use of util files follows the convention used elsewhere in the DAPL +reference provider. These files contain common object creation and +destruction code. + + +1. Protection Zones (PZs) +------------------------- + + DAPL protection zones provide consumers with a means to associate +various DAPL objects with one another. The association can then be +validated before allowing these objects to be manipulated. The DAT +functions related to PZs are: + +dat_pz_create +dat_pz_free +dat_pz_query + +These are implemented in the DAPL reference provider by + +dapl_pz_create +dapl_pz_free +dapl_pz_query + +The reference implementation maps the DAPL PZ concept onto Infiniband +protections domains (PDs). + +The DAT_PZ_HANDLE value returned to DAT consumers is a pointer to a +DAPL_PZ data structure. The DAPL_PZ structure is used to represent all +PZ objects. Code that manipulates this structure should atomically +increment and decrement the ref_count member to track the number of +objects referencing the PZ. + + +2. Local Memory Regions (LMRs) +------------------------------ + + DAPL local memory regions represent a memory area on the host +system that the consumer wishes to access via local DTO operations. +The DAT functions related to LMRs are: + +dat_lmr_create +dat_lmr_free +dat_lmr_query + +These are implemented in + +dapl_lmr_create +dapl_lmr_free +dapl_lmr_query + +In the reference implementation, DAPL LMRs are mapped onto +Infiniband memory regions (MRs). + +LMR creation produces two values: a DAT_LMR_CONTEXT and a +DAT_LRM_HANDLE. + +The DAT_LMR_CONTEXT value is used to uniquely identify the LMR +when posting data transfer operations. These values map directly +to Infiniband L_KEYs. + +Since some DAT functions need to translate a DAT_LMR_CONTEXT value +into a DAT_LMR_HANDLE (ex. dat_rmr_bind), a dictionary data structure +is used to associate DAT_LMR_CONTEXT values with their corresponding +DAT_LMR_HANDLE. Each time a new LMR is created, the DAT_LMR_HANDLE +should be inserted into the dictionary with the associated +DAT_LMR_CONTEXT as the key. + +A hash table was chosen to implement this data structure. Since the +L_KEY values are being used by the CA hardware for indexing purposes, +there distribution is expected to be uniform and hence ideal for hashing. + +The DAT_LMR_HANDLE value returned to DAT consumers is a pointer to +a DAPL_LMR data structure. The DAPL_LMR structure is used to represent +all LMR objects. The ref_count member should be used to track objects +associated with a given LMR. + +The DAT API exposes the DAT_LMR_CONTEXT to consumers to allow +for sharing of memory registrations between multiple address spaces. +The mechanism by which such a feature would be implemented does not +yet exist. Consumers may be able to take advantage of this +feature on future transports. + + +3. Remote Memory Regions (RMRs) +------------------------------- + + DAPL remote memory regions represent a memory area on the host +system to which the consumer wishes to allow RMDA operations. The +related DAT functions are + +dat_rmr_create +dat_rmr_free +dat_rmr_query +dat_rmr_bind + +which are implemented in + +dapl_rmr_create +dapl_rmr_free +dapl_rmr_query +dapl_rmr_bind + +The reference provider maps RMR objects onto Infiniband memory +windows. + +The DAT_RMR_HANDLE value returned to DAT consumers is a pointer to +a DAPL_RMR data structure. The DAPL_RMR structure is used to represent +all RMR objects. + +The API for binding a LMR to a RMR has the following function +signature: + +DAT_RETURN +dapl_rmr_bind ( + IN DAT_RMR_HANDLE rmr_handle, + IN const DAT_LMR_TRIPLET *lmr_triplet, + IN DAT_MEM_PRIV_FLAGS mem_priv, + IN DAT_EP_HANDLE ep_handle, + IN DAT_RMR_COOKIE user_cookie, + IN DAT_COMPLETION_FLAGS completion_flags, + OUT DAT_RMR_CONTEXT *rmr_context ) + +where a DAT_LMR_TRIPLET is defined as: + +typedef struct dat_lmr_triplet + { + DAT_LMR_CONTEXT lmr_context; + DAT_UINT32 pad; + DAT_VADDR virtual_address; + DAT_VLEN segment_length; + } DAT_LMR_TRIPLET; + +In the case of IB, the DAT_LMR_CONTEXT value is a L_KEY. +As described in the IB spec, the Bind Memory Window verb +takes both a L_KEY and Memory Region Handle among other +parameters. Therefore a data structure must be used to +map a DAT_LMR_CONTEXT (L_KEY) value to a DAPL_LMR so +that the needed memory region handle can be retrieved. +The LMR hash table described above is used for this +purpose. diff --git a/branches/WOF2-3/ulp/dapl/doc/dapl_registry_design.txt b/branches/WOF2-3/ulp/dapl/doc/dapl_registry_design.txt new file mode 100644 index 00000000..c4701a25 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/doc/dapl_registry_design.txt @@ -0,0 +1,631 @@ + DAT Registry Subsystem Design v. 0.90 + ------------------------------------- + +================= +Table of Contents +================= + +* Table of Contents +* Referenced Documents +* Introduction +* Goals +* Provider API +* Consumer API +* Registry Design + + Registry Database + + Provider API pseudo-code + + Consumer API pseudo-code + + Platform Specific API pseudo-code + +==================== +Referenced Documents +==================== + +uDAPL: User Direct Access Programming Library, Version 1.0. Published +6/21/2002. http://www.datcollaborative.org/uDAPL_062102.pdf. Referred +to in this document as the "DAT Specification". + +============ +Introduction +============ + +The DAT architecture supports the use of multiple DAT providers within +a single consumer application. Consumers implicitly select a provider +using the Interface Adapter name parameter passed to dat_ia_open(). + +The subsystem that maps Interface Adapter names to provider +implementations is known as the DAT registry. When a consumer calls +dat_ia_open(), the appropriate provider is found and notified of the +consumer's request to access the IA. After this point, all DAT API +calls acting on DAT objects are automatically directed to the +appropriate provider entry points. + +A persistent, administratively configurable database is used to store +mappings from IA names to provider information. This provider +information includes: the file system path to the provider library +object, version information, and thread safety information. The +location and format of the registry is platform dependent. This +database is know as the Static Registry (SR). The process of adding a +provider entry is termed Static Registration. + +Within each DAT consumer, there is a per-process database that +maps from ia_name -> provider information. When dat_ia_open() is +called, the provider library is loaded, the ia_open_func is found, and +the ia_open_func is called. + +===== +Goals +===== + +-- Implement the registration mechanism described in the uDAPL + Specification. + +-- The DAT registry should be thread safe. + +-- On a consumer's performance critical data transfer path, the DAT + registry should not require any significant overhead. + +-- The DAT registry should not limit the number of IAs or providers + supported. + +-- The user level registry should be tolerant of arbitrary library + initialization orders and support calls from library initialization + functions. + +============ +Provider API +============ + +Provider libraries must register themselves with the DAT registry. +Along with the Interface Adapter name they wish to map, they must +provide a routines vector containing provider-specific implementations +of all DAT APIs. If a provider wishes to service multiple Interface +Adapter names with the same DAT APIs, it must register each name +separately with the DAT registry. The Provider API is not exposed to +consumers. + +The user level registry must ensure that the Provider API may be +called from a library's initialization function. Therefore the +registry must not rely on a specific library initialization order. + + DAT_RETURN + dat_registry_add_provider( + IN DAT_PROVIDER *provider ) + +Description: Allows the provider to add a mapping. It will return an +error if the Interface Adapter name already exists. + + DAT_RETURN + dat_registry_remove_provider( + IN DAT_PROVIDER *provider ) + +Description: Allows the Provider to remove a mapping. It will return +an error if the mapping does not already exist. + +============ +Consumer API +============ + +Consumers that wish to use a provider library call the DAT registry to +map Interface Adapter names to provider libraries. The consumer API is +exposed to both consumers and providers. + + DAT_RETURN + dat_ia_open ( + IN const DAT_NAME device_name, + IN DAT_COUNT async_event_qlen, + INOUT DAT_EVD_HANDLE *async_event_handle, + OUT DAT_IA_HANDLE *ia_handle ) + +Description: Upon success, this function returns an DAT_IA_HANDLE to +the consumer. This handle, while opaque to the consumer, provides +direct access to the provider supplied library. To support this +feature, all DAT_HANDLEs must be pointers to a pointer to a +DAT_PROVIDER structure. + + DAT_RETURN + dat_ia_close ( + IN DAT_IA_HANDLE ia_handle ) + +Description: Closes the Interface Adapter. + + DAT_RETURN + dat_registry_list_providers( + IN DAT_COUNT max_to_return, + OUT DAT_COUNT *entries_returned, + OUT DAT_PROVIDER_INFO *(dat_provider_list[]) ) + +Description: Lists the current mappings. + +=============== +Registry Design +=============== + +There are three separate portions of the DAT registry system: + +* Registry Database + +* Provider API + +* Consumer API + +We address each of these areas in order. The final section will +describe any necessary platform specific functions. + +Registry Database +----------------- + +Static Registry +................ + +The Static Registry is a persistent database containing provider +information keyed by Interface Adapter name. The Static Registry will +be examined once when the DAT library is loaded. + +There is no synchronization mechanism protecting access to the Static +Registry. Multiple readers and writers may concurrently access the +Static Registry and as a result there is no guarantee that the +database will be in a consistent format at any given time. DAT +consumers should be aware of this and not run DAT programs when the +registry is being modified (for example, when a new provider is being +installed). However, the DAT library must be robust enough to recognize +an inconsistent Static Registry and ignore invalid entries. + +Information in the Static Registry will be used to initialize the +registry database. The registry will refuse to load libraries for DAT +API versions different than its DAT API version. Switching API +versions will require switching versions of the registry library (the +library explicitly placed on the link line of DAPL programs) as well +as the header files included by the program. + +Set DAT_NO_STATIC_REGISTRY at compile time if you wish to compile +DAT without a static registry. + +UNIX Registry Format +..................... + +The UNIX registry will be a plain text file with the following +properties: + * All characters after # on a line are ignored (comments). + * Lines on which there are no characters other than whitespace + and comments are considered blank lines and are ignored. + * Non-blank lines must have seven whitespace separated fields. + These fields may contain whitespace if the field is quoted + with double quotes. Within fields quoated with double quotes, + the following are valid escape sequences: + + \\ backslash + \" quote + + * Each non-blank line will contain the following fields: + + - The IA Name. + - The API version of the library: + [k|u]major.minor where "major" and "minor" are both integers + in decimal format. Examples: "k1.0", "u1.0", and "u1.1". + - Whether the library is thread-safe: + [threadsafe|nonthreadsafe] + - Whether this is the default section: [default|nondefault] + - The path name for the library image to be loaded. + - The version of the driver: major.minor, for example, "5.13". + +The format of any remaining fields on the line is dependent on the API +version of the library specified on that line. For API versions 1.0 +and 1.1 (both kDAPL and uDAPL), there is only a single additional +field, which is: + + - An optional string with instance data, which will be passed to + the loaded library as its run-time arguments. + +This file format is described by the following grammar: + + -> | + -> + [|] | + [| -> string + -> [k|u]decimal.decimal + -> [threadsafe|nonthreadsafe] + -> [default|nondefault] + -> string + -> decimal.decimal + -> string + -> end of file + -> newline + +The location of this file may be specified by setting the environment +variable DAT_CONF. If DAT_CONF is not set, the default location will +be /etc/dat.conf. + +Windows Registry Format +....................... + +Standardization of the Windows registry format is not complete at this +time. + +Registry Database Data Structures +................................. + +The Registry Database is implemented as a dictionary data structure that +stores (key, value) pairs. + +Initially the dictionary will be implemented as a linked list. This +will allow for an arbitrary number of mappings within the resource +limits of a given system. Although the search algorithm will have O(n) +worst case time when n elements are stored in the data structure, we +do not anticipate this to be an issue. We believe that the number of +IA names and providers will remain relatively small (on the order of +10). If performance is found to be an issue, the dictionary can be +re-implemented using another data structure without changing the +Registry Database API. + +The dictionary uses IA name strings as keys and stores pointers to a +DAT_REGISTRY_ENTRY structure, which contains the following +information: + + - provider library path string, library_path + - DAT_OS_LIBRARY_HANDLE, library_handle + - IA parameter string, ia_params + - DAT_IA_OPEN_FUNC function pointer, ia_open_func + - thread safety indicator, is_thread_safe + - reference counter, ref_count + +The entire registry database data structure is protected by a single +lock. All threads that wish to query/modify the database must posses +this lock. Serializing access in this manner is not expected to have a +detrimental effect on performance as contention is expected to be +minimal. + +An important property of the registry is that entries may be inserted +into the registry, but no entries are ever removed. The contents of +the static registry are used to populate the initially empty registry +database. Since these mapping are by definition persistent, no +mechanism is provided to remove them from the registry database. + +NOTE: There is currently no DAT interface to set a provider's IA +specific parameters. A solution for this problem has been proposed for +uDAPL 1.1. + +Registry Database API +..................... + +The static variable Dat_Registry_Db is used to store information about +the Registry Database and has the following members: + + - lock + - dictionary + +The Registry Database is accessed via the following internal API: + +Algorithm: dat_registry_init + Input: void + Output: DAT_RETURN +{ + initialize Dat_Registry_Db + + dat_os_sr_load() +} + +Algorithm: dat_registry_insert + Input: IN const DAT_STATIC_REGISTRY_ENTRY sr_entry + Output: DAT_RETURN +{ + dat_os_lock(&Dat_Registry_Db.lock) + + create and initialize DAT_REGISTRY_ENTRY structure + + dat_dictionary_add(&Dat_Registry_Db.dictionary, &entry) + + dat_os_unlock(&Dat_Registry_Db.lock) +} + +Algorithm: dat_registry_search + Input: IN const DAT_NAME_PTR ia_name + IN DAT_REGISTRY_ENTRY **entry + Output: DAT_RETURN +{ + dat_os_lock(&Dat_Registry_Db.lock) + + entry gets dat_dictionary_search(&Dat_Registry_Db.dictionary, &ia_name) + + dat_os_unlock(&Dat_Registry_Db.lock) +} + +Algorithm: dat_registry_list + Input: IN DAT_COUNT max_to_return + OUT DAT_COUNT *entries_returned + OUT DAT_PROVIDER_INFO *(dat_provider_list[]) + Output: DAT_RETURN +{ + dat_os_lock(&Dat_Registry_Db.lock) + + size = dat_dictionary_size(Dat_Registry_Db.dictionary) + + for ( i = 0, j = 0; + (i < max_to_return) && (j < size); + i++, j++ ) + { + initialize dat_provider_list[i] w/ j-th element in dictionary + } + + dat_os_unlock(&Dat_Registry_Db.lock) + + *entries_returned = i; +} + +Provider API pseudo-code +------------------------ + ++ dat_registry_add_provider() + +Algorithm: dat_registry_add_provider + Input: IN DAT_PROVIDER *provider + Output: DAT_RETURN +{ + dat_init() + + dat_registry_search(provider->device_name, &entry) + + if IA name is not found then dat_registry_insert(new entry) + + if entry.ia_open_func is not NULL return an error + + entry.ia_open_func = provider->ia_open_func +} + ++ dat_registry_remove_provider() + +Algorithm: dat_registry_remove_provider + Input: IN DAT_PROVIDER *provider + Output: DAT_RETURN +{ + dat_init() + + dat_registry_search(provider->device_name, &entry) + + if IA name is not found return an error + + entry.ia_open_func = NULL +} + +Consumer API pseudo-code +------------------------ + +* dat_ia_open() + +This function looks up the specified IA name in the ia_dictionary, +loads the provider library, retrieves a function pointer to the +provider's IA open function from the provider_dictionary, and calls +the providers IA open function. + +Algorithm: dat_ia_open + Input: IN const DAT_NAME_PTR name + IN DAT_COUNT async_event_qlen + INOUT DAT_EVD_HANDLE *async_event_handle + OUT DAT_IA_HANDLE *ia_handle + Output: DAT_RETURN + +{ + dat_registry_search(name, &entry) + + if the name is not found return an error + + dat_os_library_load(entry.library_path, &entry.library_handle) + + if the library fails to load return an error + + if the entry's ia_open_func is invalid + { + dl_os_library_unload(entry.library_handle) + return an error + } + + (*ia_open_func) (name, + async_event_qlen, + async_event_handle, + ia_handle); +} + +* dat_ia_close() + +Algorithm: dat_ia_close + Input: IN DAT_IA_HANDLE ia_handle + IN DAT_CLOSE_FLAGS ia_flags + Output: DAT_RETURN +{ + provider = DAT_HANDLE_TO_PROVIDER(ia_handle) + + (*provider->ia_close_func) (ia_handle, ia_flags) + + dat_registry_search(provider->device_name, &entry) + + dat_os_library_unload(entry.library_handle) +} + ++ dat_registry_list_providers() + +Algorithm: dat_registry_list_providers + Input: IN DAT_COUNT max_to_return + OUT DAT_COUNT *entries_returned + OUT DAT_PROVIDER_INFO *(dat_provider_list[]) + Output: DAT_RETURN +{ + validate parameters + + dat_registry_list(max_to_return, entries_returned, dat_provider_list) +} + +Platform Specific API pseudo-code +-------------------------------- + +Below are descriptions of platform specific functions required by the +DAT Registry. These descriptions are for Linux. + +Each entry in the static registry is represented by an OS specific +structure, DAT_OS_STATIC_REGISTRY_ENTRY. On Linux, this structure will +have the following members: + + - IA name string + - API version + - thread safety + - default section + - library path string + - driver version + - IA parameter string + +The tokenizer will return a DAT_OS_SR_TOKEN structure +containing: + + - DAT_OS_SR_TOKEN_TYPE value + - string with the fields value + +The tokenizer will ignore all white space and comments. The tokenizer +will also translate any escape sequences found in a string. + +Algorithm: dat_os_sr_load + Input: n/a + Output: DAT_RETURN +{ + if DAT_CONF environment variable is set + static_registry_file = contents of DAT_CONF + else + static_registry_file = /etc/dat.conf + + sr_fd = dat_os_open(static_registry_file) + + forever + { + initialize DAT_OS_SR_ENTRY entry + + do + { + // discard blank lines + dat_os_token_next(sr_fd, &token) + } while token is newline + + if token type is EOF then break // all done + // else the token must be a string + + entry.ia_name = token.value + + dat_os_token_next(sr_fd, &token) + + if token type is EOF then break // all done + else if token type is not string then + { + // an error has occurred + dat_os_token_sync(sr_fd) + continue + } + else if ( dat_os_convert_api(token.value, &entry.api) fails ) + { + // an error has occurred + dat_os_token_sync(sr_fd) + continue + } + + dat_os_token_next(sr_fd, &token) + + if token type is EOF then break // all done + else if token type is not string then + { + // an error has occurred + dat_os_token_sync(sr_fd) + continue + } + else if ( dat_os_convert_thread_safety(token.value, &entry.thread_safety) fails ) + { + // an error has occurred + dat_os_token_sync(sr_fd) + continue + } + + dat_os_token_next(sr_fd, &token) + + if token type is EOF then break // all done + else if token type is not string then + { + // an error has occurred + dat_os_token_sync(sr_fd) + continue + } + else if ( dat_os_convert_default(token.value, &entry.default) fails ) + { + // an error has occurred + dat_os_token_sync(sr_fd) + continue + } + + dat_os_token_next(sr_fd, &token) + + if token type is EOF then break // all done + else if token type is not string then + { + // an error has occurred + dat_os_token_sync(sr_fd) + continue + } + + entry.lib_path = token.value + + dat_os_token_next(sr_fd, &token) + + if token type is EOF then break // all done + else if token type is not string then + { + // an error has occurred + dat_os_token_sync(sr_fd) + continue + } + else if ( dat_os_convert_driver_version(token.value, &entry.driver_version) fails ) + { + // an error has occurred + dat_os_token_sync(sr_fd) + continue + } + + dat_os_token_next(sr_fd, &token) + + if token type is EOF then break // all done + else if token type is not string then + { + // an error has occurred + dat_os_token_sync(sr_fd) + continue + } + + entry.ia_params = token.value + + dat_os_token_next(sr_fd, &token) + + if token type is EOF then break // all done + else if token type is not newline then + { + // an error has occurred + dat_os_token_sync(sr_fd) + continue + } + + if ( dat_os_sr_is_valid(entry) ) + { + dat_registry_insert(entry) + } + } + + dat_os_close(sr_fd) +} + +Algorithm: dat_os_library_load + Input: IN const DAT_NAME_PTR *library_path + OUT DAT_LIBRARY_HANDLE *library_handle + Output: DAT_RETURN +{ + *library_handle = dlopen(library_path); +} + +Algorithm: dat_os_library_unload + Input: IN const DAT_LIBRARY_HANDLE library_handle + Output: DAT_RETURN +{ + dlclose(library_handle) +} diff --git a/branches/WOF2-3/ulp/dapl/doc/dapl_shared_memory_design.txt b/branches/WOF2-3/ulp/dapl/doc/dapl_shared_memory_design.txt new file mode 100644 index 00000000..4f0ca14c --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/doc/dapl_shared_memory_design.txt @@ -0,0 +1,867 @@ +####################################################################### +# # +# DAPL Shared Memory Design # +# # +# James Lentini # +# jlentini at users.sourceforge.net # +# # +# Created 09/17/2002 # +# Version 0.03 # +# # +####################################################################### + + +Contents +-------- +0. Introduction +1. Referenced Documents +2. Requirements +3. Interface +4. Implementation Options + + +Introduction +------------ + +This document describes the design of shared memory registration for +the DAPL reference implementation (RI). + +Implementing shared memory support completely within the DAPL RI +would not be a ideal solution. A more robust and efficient +implementation can be acheived by HCA vendors that integrate a DAT +provider into their software stack. Therefore the RI will not contain +an implementation of this feature. + + +Referenced Documents +-------------------- + +uDAPL: User Direct Access Programming Library, Version 1.1. +Available at http://www.datcollaborative.org/uDAPLv11.pdf. +Referred to in this document as the "DAT Specification". + +InfiniBand Access Application Programming Interface Specification, +Version 1.2, 4/15/2002. In DAPL SourceForge repository at +doc/api/access_api.pdf. Referred to in this document as the "IBM +Access API Specification". + +InfiniBand Architecture Specification, Volumes 1 and 2, Release +1.1, Available from http://www.infinibandta.org/ +Referred to in this document as the "Infiniband Specification". + + +Requirements +------------ + +The DAT shared memory model can be characterized as a peer-to-peer +model since the order in which consumers register a region is not +dictated by the programming interface. + +The DAT API function used to register shared memory is: + +DAT_RETURN +dat_lmr_create ( + IN DAT_IA_HANDLE ia_handle, + IN DAT_MEM_TYPE mem_type, + IN DAT_REGION_DESCRIPTION region_description, + IN DAT_VLEN length, + IN DAT_PZ_HANDLE pz_handle, + IN DAT_MEM_PRIV_FLAGS mem_privileges, + OUT DAT_LMR_HANDLE *lmr_handle, + OUT DAT_LMR_CONTEXT *lmr_context, + OUT DAT_RMR_CONTEXT *rmr_context, + OUT DAT_VLEN *registered_length, + OUT DAT_VADDR *registered_address ); + +where a DAT_REGION_DESCRIPTION is defined as: + +typedef union dat_region_description + { + DAT_PVOID for_va; + DAT_LMR_HANDLE for_lmr_handle; + DAT_SHARED_MEMORY for_shared_memory; + } DAT_REGION_DESCRIPTION; + +In the case of a shared memory registration the DAT consumer will set +the DAT_MEM_TYPE flag to DAT_MEM_TYPE_SHARED_VIRTUAL and place a +cookie in the DAT_REGION_DESCRIPTION union's DAT_SHARED_MEMORY +member. The DAT_SHARED_MEMORY type is defined as follows: + +typedef struct dat_shared_memory + { + DAT_PVOID virtual_address; + DAT_LMR_COOKIE shared_memory_id; + } DAT_SHARED_MEMORY; + +Unlike the DAT peer-to-peer model, the Infiniband shared memory model +requires a master-slave relationship. A memory region must first be +registered using the Register Memory Region verb with subsequent +registrations made using the Register Shared Memory Region verb. This +verb is implemented in the IBM OS Access API as: + +ib_int32_t +ib_mr_shared_register_us( + ib_hca_handle_t hca_handle, + ib_mr_handle_t *mr_handle, /* IN-OUT: could be changed */ + ib_pd_handle_t pd_handle, /* IN */ + ib_uint32_t access_control, /* IN */ + ib_uint32_t *l_key, /* OUT */ + ib_uint32_t *r_key, /* OUT: if remote access needed */ + ib_uint8_t **va ); /* IN-OUT: virt. addr. to register */ + +The important parameter is the memory region handle which must be the +same as an already registered region. + +Two requirements are implied by this difference between the DAT and +Infiniband models. First, DAPL implementations need a way to determine +the first registration of a shared region. Second implementations must +map DAT_LMR_COOKIE values to memory region handles both within and +across processes. To satisfy the above requirements DAPL must maintain +this information in a system wide database. + +The difficulty of implementing such a database at the DAT provider +level is the reason the RI's shared memory code is meant to be +temporary. Such a database is much better suited as part of the HCA +vendor's software stack, specifically as part of their HCA driver. + +If DAPL was based on a master-slave model like InfiniBand, the +implementation of shared memory would be straight +forward. Specifically the complexity is a result of the consumer being +responsible for specifying the DAT_LMR_COOKIE values. If the DAPL +spec. were changed to allow the provider and not the consumer to +specify the DAT_LMR_COOKIE value, the implementation of this feature +would be greatly simplified. Since the DAPL API already requires +consumers to communicate the DAT_LMR_COOKIE values between processes, +such a change places minimal additional requirements on the +consumer. The dapl_lmr_query call could easily be adapted to allow the +consumer to query the provider for a given LMR's DAT_LMR_COOKIE +value. The only spec changes needed would be to add a DAT_LMR_COOKIE +member to the DAT_LMR_PARAM structure and a DAT_LMR_FIELD_LMR_COOKIE +constant to the DAT_LMR_PARAM_MASK enumeration. A provider could then +store the given LMR's memory region handle in this value, greatly +simplifying the implementation of shared memory in DAPL. + + +Interface +--------- + +To allow the database implementation to easily change, the RI would use +a well defined interface between the memory subsystem and the +database. Conceptually the database would contain a single table with +the following columns: + +[ LMR Cookie ][ MR Handle ][ Reference Count ][ Initialized ] + +where the LMR Cookie column is the primary key. + +The following functions would be used to access the database: + +DAT_RETURN +dapls_mrdb_init ( + void ); + + Called by dapl_init(.) to perform any necessary database + initialization. + +DAT_RETURN +dapls_mrdb_exit ( + void ); + + Called by dapl_fini(.) to perform any necessary database cleanup. + +DAT_RETURN +dapls_mrdb_record_insert ( + IN DAPL_LMR_COOKIE cookie ); + + If there is no record for the specified cookie, an empty record is + added with a reference count of 1 and the initialized field is set to + false. If a record already exists, the function returns an error. + +DAT_RETURN +dapls_mrdb_record_update ( + IN DAPL_LMR_COOKIE cookie, + IN ib_mr_handle_t mr_handle ); + + If there is a record for the specified cookie, the MR handle field is + set to the specified mr_handle value and the initialized field is set + to true. Otherwise an error is returned. + +DAT_RETURN +dapls_mrdb_record_query ( + IN DAPL_LMR_COOKIE cookie, + OUT ib_mr_handle_t *mr_handle ); + + If there is a record for the specified cookie and the initialized + field is true, the MR handle field is returned and the reference + count field is incremented. Otherwise an error is returned. + +DAT_RETURN +dapls_mrdb_record_dec ( + IN DAPL_LMR_COOKIE cookie ); + + If there is a record for the specified cookie, the reference count + field is decremented. If the reference count is zero after the + decrement, the record is removed from the database. Otherwise an + error is returned. + +The generic algorithms for creating and destroying a shared memory +region are: + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: CreateShared + Inputs: + ia_handle + pz_handle + address + length + lmr_cookie + privileges + Outputs: + lmr_handle + lmr_context + registered_address + registered_length + +forever +{ + if dapls_mrdb_record_insert(cookie) is successful + { + if dapl_lmr_create_virtual is not successful + dapls_mrdb_record_dec(cookie) + return error + + else if dapls_mrdb_record_update(cookie, lmr->mr_handle) is not successful + dapls_mrdb_record_dec(cookie) + return error + + else break + } + else if dapls_mrdb_record_query(cookie, mr_handle) is successful + { + if ib_mrdb_shared_register_us is not successful + dapls_mrdb_record_dec(cookie) + return error + + else break + } +} + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: FreeShared + Inputs: + lmr + Outputs: + +if dapls_ib_mr_deregister(lmr) is successful + dapls_mrdb_record_dec(lmr->cookie) + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + +Implementation Options +---------------------- + +As described above the crucial functionality needed to implement +shared memory support is a system wide database for mapping LMR +cookies to memory region handles. The following designs represent some +of the options for implementing such a database. Adding a database +increases the complexity of DAPL from both an implementor and user's +perspective. These designs should be evaluated on the degree to which +they minimize the additional complexity while still providing a robust +solution. + + + File System Database + -------------------- + +Employing a database that is already part of the system would be +ideal. One option on Linux is to use the file system. An area of the +file system could be set aside for the creation of files to represent +each LMR cookie. The area of the file system could be specified +through a hard coded value, an environment variable, or a +configuration file. A good candidate would be a DAPL subdirectory of +/tmp. + +Exclusive file creation is available through the creat(2) system call +in Linux. The standard I/O interface (fopen(3), etc.) does not support +this feature making porting difficult. However porting to other +environments is not a goal of this design since the entire scheme is +only a temporary solution. + +Determining when to delete the files is a difficult problem. A +reference count is required to properly remove a file once all the +memory regions it represents are deregistered. The synchronization +mechanism necessary for maintaining the reference count is not easily +implemented. As an alternative, a script could be provided to clean up +the database by removing all the files. The script would need to be +run before any DAPL consumers were started to ensure a clean +database. The disadvantage of using a script is that no DAPL instances +can be running when it is used. Another option would be to store the +process ID (PID) of the process that created the file as part of the +file's contents. Upon finding a record for a given LMR cookie value, a +DAPL instance could determine if there was a process with the same PID +in the system. To accomplish this the kill(2) system call could be +used (ex. kill(pid, 0) ). This method of validating the record assumes +that all DAPL instances can signal one another and that the PID values +do not wrap before the check is made. + +Another difficulty with this solution is choosing an accessible +portion of the file system. The area must have permissions that allow +all processes using DAPL to access and modify its contents. System +administrators are typically reluctant to allow areas without any +access controls. Typically such areas are on a dedicated file system +of a minimal size to ensure that malicious or malfunctioning software +does not monopolize the system's storage capacity. Since very little +information will be stored in each file it is unlikely that DAPL would +need a large amount of storage space even if a large number of shared +memory regions were in use. However since a file is needed for each +shared region, a large number of shared registrations may lead to the +consumption of all a file system's inodes. Again since this solution +is meant to be only temporary this constraint may be acceptable. + +There is also the possibility for database corruption should a process +crash or deadlock at an inopportune time. If a process creates file x +and then crashes all other processes waiting for the memory handle to +be written to x will fail. + +The database interface could be implemented as follows: + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: dapls_mrdb_init + Inputs: + + Outputs: + +return success + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: dapls_mrdb_exit + Inputs: + + Outputs: + +return success + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: dapls_mrdb_record_insert + Inputs: + cookie + Outputs: + +file_name = convert cookie to valid file name + +fd = exclusively create file_name +if fd is invalid + return failure + +if close fd fails + return failure + +return success + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: dapls_mrdb_record_update + Inputs: + cookie + mr_handle + Outputs: + +file_name = convert cookie to valid file name + +fd = open file_name +if fd is invalid + return failure + +if write mr_handle to file_name fails + return failure + +if close fd fails + return failure + +return success + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: dapls_mrdb_record_query + Inputs: + cookie + + Outputs: + mr_handle + +file_name = convert cookie to valid file name + +fd = open file_name +if fd is invalid + return failure + +if read mr_handle from file_name fails + return failure + +if close fd fails + return failure + +return success + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: dapls_mrdb_record_dec + Inputs: + cookie + Outputs: + +return success + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + + Daemon Database + --------------- + +The database could be maintained by a separate daemon process. +The DAPL instances would act as clients of the daemon server and +communicate with the daemon through the various IPC mechanisms +available on Linux: Unix sockets, TCP/IP sockets, System V message +queues, FIFOs, or RPCs. + +As with the file system based database, process crashes can potentially +cause database corruption. + +While the portability of this implementation will depend on the chosen +IPC mechanism, this approach will be at best Unix centric and possibly +Linux specific. + +The database interface could be implemented as follows: + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: dapls_mrdb_init + Inputs: + + Outputs: + +initialize IPC mechanism + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: dapls_mrdb_exit + Inputs: + + Outputs: + +shutdown IPC mechanism + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: dapls_mrdb_record_insert + Inputs: + cookie + Outputs: + +if send insert message for cookie fails + return error + +if receive insert response message fails + return error + +if insert success + return success +else return error + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: dapls_mrdb_record_update + Inputs: + cookie + mr_handle + + Outputs: + +if send update message for cookie and mr_handle fails + return error +else return success + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: dapls_mrdb_record_query + Inputs: + cookie + + Outputs: + mr_handle + +if send query message for cookie fails + return error + +else if receive query response message with mr_handle fails + return error + +else return success + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: dapls_mrdb_record_dec + Inputs: + cookie + Outputs: + +if send decrement message for cookie fails + return error +else return success + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + + Shared Memory Database + ---------------------- + +The database could be maintained in an area of memory shared by all +DAPL instances running on a system. Linux supports the System V shared +memory functions shmget(2), shmctl(2), shmat(2), and shmdt(2). A hard +coded key_t value could be used so that each DAPL instance attached to +the same piece of shared memory. The size of the database would be +constrained by the size of the shared memory region. Synchronization +could be achieved by using atomic operations targeting memory in the +shared region. + +Such a design would suffer from the corruption problems described +above. If a process crashed there would be no easy way to clean up its +locks and roll back the database to a consistent state. + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: dapls_mrdb_init + Inputs: + + Outputs: + +attach shared region + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: dapls_mrdb_exit + Inputs: + + Outputs: + +detach shared region + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: dapls_mrdb_record_insert + Inputs: + cookie + Outputs: + +lock database + +if db does not contain cookie + add record for cookie + +unlock database + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: dapls_mrdb_record_update + Inputs: + cookie + mr_handle + Outputs: + +lock database + +if db contains cookie + update record's mr_handle + +unlock database + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: dapls_mrdb_record_query + Inputs: + cookie + + Outputs: + mr_handle + +lock database + +if db contains cookie + set mr_handle to record's value + increment record's reference count + +unlock database + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: dapls_mrdb_record_dec + Inputs: + cookie + Outputs: + +lock database + +if db contains cookie + decrement record's reference count + + if reference count is 0 + remove record + +unlock database + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + + Kernel Module Database + ---------------------- + +If the DAT library were integrated with an HCA vendor's software +stack, the database could be managed by the HCA driver. Placing the +database in the kernel would alleviate the synchronization problems +posed by multiple processes. Since memory registration operations +already involve a transition into the kernel, no extra overhead would +be incurred by this design. + +The RI could include a kernel module with this functionality as a +temporary solution. The module could identify itself as a character +device driver and communicate with user level processes through an +ioctl(2). The driver could also create an entry in the proc file +system to display the database's contents for diagnostic purposes. + +A major benefit of a kernel based implementation is that the database +can remain consistent even in the presence of application +errors. Since DAPL instances communicate with the driver by means of +ioctl(2) calls on a file, the driver can be arrange to be informed +when the file is closed and perform any necessary actions. The driver +is guaranteed to be notified of a close regardless of the manner in +which the process exits. + +The database could be implemented as a dictionary using the LMR cookie +values as keys. + +The following pseudo-code describes the functions needed by the kernel +module and the database interface. + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: KernelModuleInit + Inputs: + + Outputs: + +dictionary = create_dictionary() +create_proc_entry() +create_character_device_entry() + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: KernelModuleExit + Inputs: + + Outputs: + +remove_character_device_entry() +remove_proc_entry() +fee_dictionary(dictionary) + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: DeviceOpen + Inputs: + file + + Outputs: + +dev_data = allocate device data + +file->private_data = dev_data + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: DeviceClose + Inputs: + file + + Outputs: + +dev_data = file->private_data + +for each record in dev_data +{ + RecordDecIoctl +} + +deallocate dev_data + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: RecordInsertIoctl + Inputs: + file + cookie + + Outputs: + +lock dictionary + +if cookie is not in dictionary + insert cookie into dictionary + + +unlock dictionary + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: RecordUpdateIoctl + Inputs: + file + cookie + mr_handle + + Outputs: + +dev_data = file->private_data + +lock dictionary + +if cookie is in dictionary + add record reference to dev_data + update mr_handle + +unlock dictionary + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: RecordQueryIoctl + Inputs: + file + cookie + + Outputs: + mr_handle + +dev_data = file->private_data + +lock dictionary + +if cookie is in dictionary + add record reference to dev_data + retrieve mr_handle + +unlock dictionary + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: RecordDecIoctl + Inputs: + file + cookie + + Outputs: + +dev_data = file->private_data +remove record reference from dev_data + +lock dictionary + +if cookie is in dictionary + decrement reference count + if reference count is 0 + remove record + +unlock dictionary + + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: dapls_mrdb_init + Inputs: + + Outputs: + +fd = open device file + +if fd is invalid + return error +else + return success + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: dapls_mrdb_exit + Inputs: + + Outputs: + +close fd + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: dapls_mrdb_record_insert + Inputs: + cookie + Outputs: + +ioctl on fd + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: dapls_mrdb_record_update + Inputs: + cookie + mr_handle + Outputs: + +ioctl on fd + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: dapls_mrdb_record_query + Inputs: + cookie + + Outputs: + mr_handle + +ioctl on fd + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: dapls_mrdb_record_dec + Inputs: + cookie + Outputs: + +ioctl on fd + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ diff --git a/branches/WOF2-3/ulp/dapl/doc/dapl_vendor_specific_changes.txt b/branches/WOF2-3/ulp/dapl/doc/dapl_vendor_specific_changes.txt new file mode 100644 index 00000000..aa437807 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/doc/dapl_vendor_specific_changes.txt @@ -0,0 +1,394 @@ + Suggested Vendor-Specific Changes v. 0.92 + ----------------------------------------- + +================= +Table of Contents +================= + +* Table of Contents +* Introduction +* Referenced documents +* Functionality Changes + + Missing Functionality + + dat_evd_resize + + Ordering guarantees on connect/disconnect. + + Shared memory + + dat_cr_handoff +* Performance optimizations + + Reduction of context switches + [Many interrelated optimizations] + + Reducing copying of data + + Avoidance of s/g list copy on posting + + Avoidance of event data copy from CQ to EVD + + Elimination of locks + + Eliminating subroutine calls + + +============ +Introduction +============ + +This document is a list of functionality enhancements and +optimizations hardware vendors porting uDAPL may want to consider as +part of their port. The functionality enhancements mentioned in this +document are situations in which HCA Vendors, with their access to +driver and verb-level source code, and their reduced portability +concerns, are in a much better position than the reference +implementation to implement portions of the uDAPL v. 1.0 +specification. (Additional areas in which the reference +implementation, because of a lack of time or resources, did not fully +implement the uDAPL 1.0 specification are not addressed in this file; +see the file doc/dapl_unimplemented_functionality.txt, forthcoming). +Vendors should be guided in their implementation of these +functionality enhancements by their customers need for the features +involved. + +The optimizations suggested in this document have been identified by +the uDAPL Reference Implementation team as areas in which performance +may be improved by "breaching" the IB Verbs API boundary. They are +inappropriate for the reference implementation (which has portability +as one of its primary goals) but may be appropriate for a HCA-specific +port of uDAPL. Note that no expected performance gain is attached to +the suggested optimizations. This is intentional. Vendors should be +guided in their performance improvements by performance evaluations +done in the context of a representative workload, and the expected +benefit from a particular optimization weighed against the cost in +code complexity and scheduling, before the improvement is implemented. +This document is intended to seed that process; it is not intended to +be a roadmap for that process. + +We divide functionality changes into two categories + * Areas in which functionality is lacking in the reference + implementation. + * Areas in which the functionality is present in the reference + implementation, but needs improvement. + +We divide performance improvements into three types: + * Reducing context switches + * Reducing copying of data (*) + * Eliminating subroutine calls + +(*) Note that the data referred to in "reducing copying of data" is +the meta data describing an operation (e.g. scatter/gather list or +event information), not the actual data to be transferred. No data +transfer copies are required within the uDAPL reference +implementation. + +==================== +Referenced Documents +==================== + +uDAPL: User Direct Access Programming Library, Version 1.0. Published +6/21/2002. http://www.datcollaborative.org/uDAPL_062102.pdf. +Referred to in this document as the "DAT Specification". + +InfiniBand Access Application Programming Interface Specification, +Version 1.2, 4/15/2002. In DAPL SourceForge repository at +doc/api/access_api.pdf. Referred to in this document as the "IBM +Access API Specification". + +uDAPL Reference Implementation Event System Design. In DAPL +SourceForge repository at doc/dapl_event_design.txt. + +uDAPL Reference Implementation Shared Memory Design. In DAPL +SourceForge repository at doc/dapl_shared_memory_design.txt. + +uDAPL list of unimplmented functionality. In DAPL SourceForge +repository at doc/dapl_unimplemented_funcitonality.txt (forthcoming). + +=========================================== +Suggested Vendor Functionality Enhancements +=========================================== + +Missing Functionality +--------------------- +-- dat_evd_resize + +The uDAPL event system does not currently implement dat_evd_resize. +The primary reason for this is that it is not currently possible to +identify EVDs with the CQs that back them. Hence uDAPL must keep a +separate list of events, and any changes to the size of that event +list would require careful synchronization with all users of that EVD +(see the uDAPL Event System design for more details). If the various +vendor specific optimizations in this document were implemented that +eliminated the requirement for the EVD to keep its own event list, +dat_evd_resize might be easily implemented by a call or calls to +ib_cq_resize. + +-- Ordering guarantees on connect/disconnect. + +The DAPL 1.1 specification specifies that if an EVD combines event +streams for connection events and DTO events for the same endpoint, +there is an ordering guarantee: the connection event on the AP occurs +before any DTO events, and the disconnection event occurs after all +successful DTO events. Since DTO events are provided by the IBM OS +Access API through ib_completion_poll (in response to consumer +request) and connection events are provided through callbacks (which +may race with consumer requests) there is no trivial way to implement +this functionality. The functionality may be implemented through +under the table synchronizations between EVD and EP; specifically: + * The first time a DTO event is seen on an endpoint, if the + connection event has not yet arrived it is created and + delivered ahead of that DTO event. + * When a connection event is seen on an endpoint, if a + connection event has already been created for that endpoint + it is silently discarded. + * When a disconnection event is seen on an endpoint, it is + "held" until either: a) all expected DTO events for that + endpoint have completed, or b) a DTO marked as "flushed by + disconnect" is received. At that point it is delivered. + +Because of the complexity and performance overhead of implementating +this feature, the DAPL 1.1 reference implementation has chosen to take +the second approach allowed by the 1.1 specification: disallowing +integration of connection and data transfer events on the same EVD. +This fineses the problem, is in accordance with the specification, and +is more closely aligned with the ITWG IT-API currently in development, +which only allows a single event stream type for each simple EVD. +However, other vendors may choose to implement the functionality +described above in order to support more integration of event streams. + +-- Shared memory implementation + +The difficulties involved in the dapl shared memory implementation are +fully described in doc/dapl_shared_memory_design.txt. To briefly +recap: + +The uDAPL spec describes a peer-to-peer shared memory model; all uDAPL +instances indicate that they want to share registration resources for +a section of memory do so by providing the same cookie. No uDAPL +instance is unique; all register their memory in the same way, and no +communication between the instances is required. + +In contrast, the IB shared memory interface requires the first process +to register the memory to do so using the standard memory registration +verbs. All other processes after that must use the shared memory +registration verb, and provide to that verb the memory region handle +returned from the initial call. This means that the first process to +register the memory must communicate the memory region handle it +receives to all the other processes who wish to share this memory. +This is a master-slave model of shared memory registration; the +initial process (the master), is unique in its role, and it must tell +the slaves how to register the memory after it. + +To translate between these two models, the uDAPL implementation +requires some mapping between the shared cookie and the memory region +handle. This mapping must be exclusive and must have inserts occur +atomically with lookups (so that only one process can set the memory +region handle; the others retrieve it). It must also track the +deregistration of the shared memory, and the exiting of the processes +registering the shared memory; when all processes have deregistered +(possibly by exitting) it must remove the mapping from cookie to +memory region handle. + +This mapping must obviously be shared between all uDAPL +implementations on a given host. Implementing such a shared mapping +is problematic in a pure user-space implementation (as the reference +implementation is) but is expected to be relatively easy in vendor +supplied uDAFS implementations, which will presumably include a +kernel/device driver component. For this reason, we have chosen to +leave this functionality unimplemented in the reference implementation. + +-- Implementation of dat_cr_handoff + +Given that the change of service point involves a change in associated +connection qualifier, which has been advertised at the underlying +Verbs/driver level, it is not clear how to implement this function +cleanly within the reference implementation. We thus choose to defer +it for implementation by the hardware vendors. + +========================= +Performance Optimizations +========================= + + +Reduction of context switches +----------------------------- +Currently, three context switches are required on the standard +uDAPL notification path. These are: + * Invocation of the hardware interrupt handler in the kernel. + Through this method the hardware notifies the CPU of + completion queue entries for operations that have requested + notification. + * Unblocking of the per-process IB provider service thread + blocked within the driver. This thread returns to + user-space within its process, where it causes + * Unblocking of the user thread blocked within the uDAPL entry + point (dat_evd_wait() or dat_cno_wait()). + +There are several reasons for the high number of context switches, +specifically: + * The fact that the IB interface delivers notifications + through callbacks rather than through unblocking waiting + threads; this does not match uDAPL's blocking interface. + * The fact that the IB interface for blocking on a CQ doesn't + have a threshhold. If it did, we could often convert a + dat_evd_wait() into a wait on that CQ. + * The lack of a parallel concept to the CNO within IB. + +These are all areas in which closer integration between the IB +verbs/driver and uDAPL could allow the user thread to wait within the +driver. This would allow the hardware interrupt thread to directly +unblock the user thread, saving a context switch. + +A specific listing of the optimizations considered here are: + * Allow blocking on an IB CQ. This would allow removal of the + excess context switch for dat_evd_wait() in cases where + there is a 1-to-1 correspondence between an EVD and a CQ and + no threshold was passed to dat_evd_wait(). + * Allow blocking on an IB CQ to take a threshold argument. + This would allow removal of the excess context switch for + dat_evd_wait() in cases where there is a 1-to-1 + correspondence between an EVD and a CQ regardless of the + threshold value. + * Give the HCA device driver knowledge of and access to the + implementation of the uDAPL EVD, and implement dat_evd_wait() + as an ioctl blocking within the device driver. This would + allow removal of the excess context switch in all cases for + a dat_evd_wait(). + * Give the HCA device driver knowledge of and access to the + implementation of the uDAPL CNO, and implement dat_cno_wait() + as an ioctl blocking within the device driver. This would + allow removal of the excess context switch in all cases for + a dat_cno_wait(), and could improve performance for blocking + on OS Proxy Wait Objects related to the uDAPL CNO. + +See the DAPL Event Subsystem Design (doc/dapl_event_design.txt) for +more details on this class of optimization. + +======================== +Reducing Copying of Data +======================== + +There are two primary places in which a closer integration between the +IB verbs/driver and the uDAPL implementation could reducing copying +costs: + +-- Avoidance of s/g list copy on posting + +Currently there are two copies involved in posting a data transfer +request in uDAPL: + * From the user context to uDAPL. This copy is required + because the scatter/gather list formats for uDAPL and IB + differ; a copy is required to change formats. + * From uDAPL to the WQE. This copy is required because IB + specifies that all user parameters are owned by the user + upon return from the IB call, and therefore IB must keep its + own copy for use during the data transfer operation. + +If the uDAPL data transfer dispatch operations were implemented +directly on the IB hardware, these copies could be combined. + +-- Avoidance of Event data copy from CQ to EVD + +Currently there are two copies of data involved in receiving an event +in a standard data transfer operation: + * From the CQ on which the IB completion occurs to an event + structure held within the uDAPL EVD. This is because the IB + verbs provide no way to discover how many elements have been + posted to a CQ. This copy is not + required for dat_evd_dequeue. However, dat_evd_wait + requires this copy in order to correctly implement the + threshhold argument; the callback must know when to wakeup + the waiting thread. In addition, copying all CQ entries + (not just the one to be returned) is necessary before + returning from dat_evd_wait in order to set the *nmore OUT + parameter. + * From the EVD into the event structure provided in the + dat_evd_wait() call. This copy is required because of the + DAT specification, which requires a user-provided event + structure to the dat_evd_wait() call in which the event + information will be returned. If dat_evd_wait() were + instead, for example, to hand back a pointer to the already + allocated event structure, that would eventually require the + event subsystem to allocate more event structures. This is + avoided in the critical path. + +A tighter integration between the IB verbs/driver and the uDAPL +implementation would allow the avoidance of the first copy. +Specifically, providing a way to get information as to the number of +completions on a CQ would allow avoidance of that copy. + +See the uDAPL Event Subsystem Design for more details on this class of +optimization. + +==================== +Elimination of Locks +==================== + +Currently there is only a single lock used on the critical path in the +reference implementation, in dat_evd_wait() and dat_evd_dequeue(). +This lock is in place because the ib_completion_poll() routine is not +defined as thread safe, and both dat_evd_wait() and dat_evd_dequeue() +are. If there was some way for a vendor to make ib_completion_poll() +thread safe without a lock (e.g. if the appropriate hardware/software +interactions were naturally safe against races), and certain other +modifications made to the code, the lock might be removed. + +The modifications required are: + * Making racing consumers from DAPL ring buffers thread safe. + This is possible, but somewhat tricky; the key is to make + the interaction with the producer occur through a count of + elements on the ring buffer (atomically incremented and + decremented), but to dequeue elements with a separate atomic + pointer increment. The atomic modification of the element + count synchronizes with the producer and acquires the right + to do an atomic pointer increment to get the actual data. + The atomic pointer increment synchronizes with the other + consumers and actually gets the buffer data. + * The optimization described above for avoiding copies from + the CQ to the DAPL EVD Event storage queue. Without this + optimization a potential race between dat_evd_dequeue() and + dat_evd_wait() exists where dat_evd_dequeue will return an + element advanced in the event stream from the one returned + from dat_evd_wait(): + + dat_evd_dequeue() called + + EVD state checked; ok for + dat_evd_dequeue() + dat_evd_wait() called + + State changed to reserve EVD + for dat_evd_wait() + + Partial copy of CQ to EVD Event store + + Dequeue of CQE from CQ + + Completion of copy of CQ to EVD Event store + + Return of first CQE copied to EVD Event store. + + Return of thie CQE from the middle + of the copied stream. + + + If no copy occurs, dat_evd_wait() and dat_evd_dequeue() may + race, but if all operations on which they may race (access + to the EVD Event Queue and access to the CQ) are thread + safe, this race will cause no problems. + +============================ +Eliminating Subroutine Calls +============================ + +This area is the simplest, as there are many DAPL calls on the +critical path that are very thin veneers on top of their IB +equivalents. All of these calls are canidates for being merged with +those IB equivalents. In cases where there are other optimizations +that may be acheived with the call described above (e.g. within the +event subsystem, the data transfer operation posting code), that call +is not mentioned here: + * dat_pz_create + * dat_pz_free + * dat_pz_query + * dat_lmr_create + * dat_lmr_free + * dat_lmr_query + * dat_rmr_create + * dat_rmr_free + * dat_rmr_query + * dat_rmr_bind + + diff --git a/branches/WOF2-3/ulp/dapl/doc/dat.conf b/branches/WOF2-3/ulp/dapl/doc/dat.conf new file mode 100644 index 00000000..eba45e7a --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/doc/dat.conf @@ -0,0 +1,11 @@ +# +# Generic DAT 1.1 configuration file +# + +# Each entry should have the following fields: +# \ +# + +# This is the dapl provider configuration for HCA0 port 1 +IbalHca0 u1.1 nonthreadsafe default /usr/lib/libdapl.so.0.0 mv_dapl.1.1 "IbalHca0 1" "" + diff --git a/branches/WOF2-3/ulp/dapl/doc/dat_environ.txt b/branches/WOF2-3/ulp/dapl/doc/dat_environ.txt new file mode 100644 index 00000000..638ba9dc --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/doc/dat_environ.txt @@ -0,0 +1,45 @@ + DAT Environment Guide v. 0.01 + ----------------------------- + +The following environment variables affect the behavior of the DAT +library: + + +DAT_OVERRIDE +------------ + Value used as the static registry configuration file, overriding the + default location, /etc/dat.conf + + Example: setenv DAT_OVERRIDE /path/to/my/private.conf + + +DAT_DBG_TYPE +------------ + + Value specifies which parts of the registry will print debugging + information, valid values are + + DAT_OS_DBG_TYPE_ERROR = 0x1 + DAT_OS_DBG_TYPE_GENERIC = 0x2 + DAT_OS_DBG_TYPE_SR = 0x4 + DAT_OS_DBG_TYPE_DR = 0x8 + DAT_OS_DBG_TYPE_PROVIDER_API = 0x10 + DAT_OS_DBG_TYPE_CONSUMER_API = 0x20 + DAT_OS_DBG_TYPE_ALL = 0xff + + or any combination of these. For example you can use 0xC to get both + static and dynamic registry output. + + Example setenv DAT_DBG_TYPE 0xC + +DAT_DBG_DEST +------------ + + Value sets the output destination, valid values are + + DAT_OS_DBG_DEST_STDOUT = 0x1 + DAT_OS_DBG_DEST_SYSLOG = 0x2 + DAT_OS_DBG_DEST_ALL = 0x3 + + For example, 0x3 will output to both stdout and the syslog. + diff --git a/branches/WOF2-3/ulp/dapl/doc/ibhosts b/branches/WOF2-3/ulp/dapl/doc/ibhosts new file mode 100644 index 00000000..792fb503 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/doc/ibhosts @@ -0,0 +1,3 @@ +dat-linux3-ib0 0xfe80000000000000 0x0001730000003d11 +dat-linux5-ib0 0xfe80000000000000 0x0001730000003d91 +dat-linux6-ib0 0xfe80000000000000 0x0001730000009791 diff --git a/branches/WOF2-3/ulp/dapl/doc/mv_dapl_readme.txt b/branches/WOF2-3/ulp/dapl/doc/mv_dapl_readme.txt new file mode 100644 index 00000000..b7e7dc3f --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/doc/mv_dapl_readme.txt @@ -0,0 +1,226 @@ + +Source Forge Notes + +1) Log onto Source Force site + a. http://infiniband.sourceforge.net + +2) Download "Bitkeeper" software + a. Click on Bitkeeper Repository link (under Source Forge Services) + b. Click on download link + c. Click on Download Bitkeeper + d. Determine proper platform and complete download + e. Note: You must fill in form and provide email address. + SW will email you login info to "bitmover site" + f. http://www.bitmover.com/download + * login: bitkeeper + * password: get bitkeeper + +3) After you have downloaded bitkeeper software, change the mode of the + file to make it executable (i.e. chmod a+x *.bin) + a. chmod a+x 3.0.1-x86-glibc22-linux.bin + b. ./ 3.0.1-x86-glibc22-linux.bin + +4) The above process creates an executable called "bk". It also creates + a symbolic link from bk to /usr/bin/bk + +5) Create a directory where you would like to place the SF project + a. Ex. mkdir /usr/sf-iba + +6) Use the bk program to pick up a clone of the latest Source Force release + for iba + a. cd /usr/sf-iba + b. bk clone http://project.bkbits.net/repository + where: project = infiniband, repository = iba; producing: + c. bk clone http:/infiniband.bkbits.net/iba + +7) Running "bk" will create a sub_folder in your current working directory + a. => /usr/sf-iba/iba + +8) Add Mellanox source to newly downloaded source tree + a. cd /usr/sf-iba/iba + b. Download and copy mellanox_xxx.tgz file to this directory and + unzip/untar file. Note: archive will place into base and create + linux folders. It is very important that you place the mellanox + files into the correct directory structure + c. tar xzvf mellanox_xxx.tgz. This will create the following: + * /usr/sf-iba/iba/base/linux/hca/mellanox + * /usr/sf-iba/iba/linux/run + +9) Create a build tree for the project using the "mktree" command. + This will pull out all sources from the base directory to a directory + of your choosing + a. cd /usr/sf-iba/iba/base/linux/utils + b. ./mktree -source /usr/sf-iba/iba -target /usr/sf-iba/iba + * mktree create 2 new directories linux and linuxuser in + /usr/sf-iba/iba + +10) Rebuild the kernel and boot with new kernel (example using + linux-2.4.18-10 kernel tree) + a. cd /usr/src/linux-2.4.18-10 + b. make xconfig + * make any changes to fit your hardware configuration: + o SMP/UP option (YES for Process type and features/Symmetric + multi-processing support buttons) + o network driver (YES for Network device support/Ethernet + (10 or 100Mbit)/Ethernet (10 or 100Mbit)... buttons + o scsi driver (YES for SCSI support/ SCSI low-level drivers/... + buttons) + o local file system (YES for File systems/Ext3 journaling + file system support - Second extended fs support buttons) + * hit "save and exit" button + c. Patch the kernel to support IPoIB with larger MAX_ADDR_LEN + * edit /usr/src/linux-2.4.18-10/include/linux/netdevice.h to + change MAX_ADDR_LEN = 8 to = 32 + * edit /usr/src/linux-2.4.18-10/net/core/dev.c to change: + The SIOCGIFHWADDR case from: + memcpy(ifr->ifr_hwaddr.sa_data, dev->dev_addr, MAX_ADDR_LEN); + to + memcpy(ifr->ifr_hwaddr.sa_data, dev->dev_addr, + min((unsigned char) sizeof(ifr->ifr_hwaddr.sa_data), + dev->addr_len)); + + The SIOCSIFHWBROADCAST case from: + memcpy(dev->broadcast, ifr->ifr_hwaddr.sa_data, MAX_ADDR_LEN); + to + memcpy(dev->broadcast, ifr->ifr_hwaddr.sa_data, + min((unsigned char) sizeof(ifr->ifr_hwaddr.sa_data), + dev->addr_len)); + d. make dep + e. make bzImage + f. make install + g. verify /etc/lilo.conf (or /etc/grub.conf) to reboot the system + with new kernel + +11) Install Mellanox MST and MSDK + a. install mst driver + b. install MSDK + c. verify the installation (at least run vapi start) + +12) The next step is to build all the driver for the stack (including + Mellanox module) + a. cd /usr/sf-iba/iba/linux + b. edit Makeconf.inc + * edit LINUX_VERSION = 2.4.18-10 + * edit REDHAT=1 if you run original kernel from RH installation. + In our case, we are running costumed kernel, we leave it as default + * edit LINUX_SRC. In our case, we edit LINUX_VERSION; therefore, + we leave this as default + c. edit Makefile.config + * Change BUILD_SMP line to: BUILD_SMP =0 (if kernel is UP) + * Change BUILD_SMP line to: BUILD_SMP =1 (if kernel is SMP) + d. Edit Makefile; Change "MLNX=n" to "MLNX=y, MODEL,SHIM=y to + MODEL,SHIM=n) + +13) Build/Compile kernel driver components by running make from top level + directory + a. cd /usr/sf-iba/iba/linux + b. make debug (or free) + c. All the object files are in + * ~bin/$(ARCH)/$(LINUX_VERSION)/$(MP_MODE)/$BLD + * in our case ARCH=x86, LINUX_VERSION=2.4.18-10, MP_MODE=up, BLD=debug + +14) Build/Compile user mode driver components. + a. cd /usr/sf-iba/iba/linuxuser/iba + b. make debug (or free) + c. All the executable files (opensm, alts...) are in + /usr/sf-iba/iba/linuxuser/bin/$(ARCH)/$(LINUX_VERSION)/bin/$(BLD) + d. All the libraries are in + /usr/sf-iba/iba/linuxuser/bin/$(ARCH)/$(LINUX_VERSION)/lib/$(BLD) + e. In our case ARCH=x86, LINUX_VERSION=2.4.18-10, BLD=debug + f. create the symbolic link for liballib, libcomplib and libmlnx_uvp + * cd /usr/sf-iba/iba/linuxuser/bin/x86/2.4.18-10/lib/debug + * ln -s liballib.so.0.0 liballib.so + * ln -s libcomplib.so.0.0 libcomplib.so + +15) Run the stack with "ibal" script which is the equivalent to "vapi" script + a. cd /usr/sf-iba/iba/linux/run + b. edit ibal + * edit line 35,36. + * Assuming that we are running UP kernel and debug mode then + o line 35 should be MODPATH_I=$IBAL_PATH/bin/x86/$KERVER/up/debug + o line 36 should be + MODPATH_TV=$IBAL_PATH/drivers/iba/hca/mellanox/thh/obj_linux_x86_up + * Assuming that we are running SMP kernel and free mode then + o line 35 should be MODPATH_I=$IBAL_PATH/bin/x86/$KERVER/smp/free + o line 36 should be + MODPATH_TV=$IBAL_PATH/drivers/iba/hca/mellanox/thh/obj_linux_x86_smp + c. cd /usr/sf-iba/iba/linux and issue command "run/ibal start" + +16) Set up the linking library path. There are two ways. + a. Edit the /root/.bashrc and add in the following line + * export LD_LIBRARY_PATH= + /usr/sf-iba/iba/linuxuser/bin/x86/2.4.18-10/lib/debug + b. Or + * edit /etc/ld.so.conf and add in the following line + /usr/sf-iba/iba/linuxuser/bin/x86/2.4.18-10/lib/debug + * run ldconfig + +17) Run the OPENSM + a. opensm executable file locates at + /usr/sf-iba/iba/linuxuser/bin/x86/2.4.18-10/bin/debug or + /usr/sf-iba/iba/linuxuser/iba/opensm directories + b. cd /usr/sf-iba/iba/linuxuser/bin/x86/2.4.18-10/bin/debug + c. ./opensm + d. Whew... finally + e. leave the opensm running still (sweeping mode) + +18) Run IPoIB + a. cd /usr/sf-iba/iba/linux/bin/x86/2.4.18-10/up/debug + b. insmod ipoib.o + c. ifconfig -a ( you will see ib01 and ib02 pop up) + d. ifconfig ib01 11.0.0.1 + e. ping 11.0.0.1 + +19) Run uDAPL + a. edit /etc/hosts to add in IPaddress for all DAPL nodes in cluster. + Distribute the file for every node in the cluster. IPaddress + can be the same as IPoIB IP address as long as node name has to end + with "xx-ibX". Even though you are not running IPoIB, you have to add + in Interface Adapter Address (IP address) for DAPL IA. For now, + one IP address for each DAPL IA (for each HCA) + + Example: local node is mtilab10 + + 10.2.2.10 mtilab10 ==> this is ethernet 0 + 10.2.2.11 mtilab11 + 192.0.0.10 mtilab10-ib0 ==> this is IPoIB or Interface Adapter + address for local DAPL IA 1 + 192.0.0.14 mtilab10-ib0a ==> this is IPoIB or Interface Adapter + address for local DAPL IA 1 port 1 + 192.0.0.12 mtilab10-ib1 ==> this is IPoIB or Interface Adapter + address for local DAPL IA 2 + 192.0.0.11 mtilab11-ib0 ==> this is IPoIB or Interface Adapter + address for remote DAPL IA + + b. Copy mv_dapl/doc/dat.conf to /etc/dat.conf. Please read + mv_dapl/doc/dapl_registry_design.txt for more infomation how to + edit /etc/dat.conf correctly + + NOTES: If you compile dapltest with EXPLICIT_LINK=1 then dapltest + is explicitly linked to libdapl.so library; therefore, you + have to uncomment the entry in dat.conf or do not have + dat.conf in /etc. + + c. dapltest executable file locates at + /usr/sf-iba/iba/linuxuser/bin/x86/2.4.18-10/up(smp)/debug(free) or + /usr/sf-iba/iba/linuxuser/iba/mv_dapl/test/udapl/dapltest + + c. Run dapltest testsuite for 2 nodes (mtilab10-ib0 and mtilab11-ib0) + * At both nodes + o start the driver (ibal start) + o cd /usr/sf-iba/iba/linuxuser/iba/mv_dapl/test/udapl/dapltest + + * At mtilab10-ib0 + o ./srv.sh ==> start server + + * At mtilab11-ib0 + o ./bw.sh mtilab10-ib0 ==> run bw test + o ./lat_poll.sh mtilab10-ib0 ==> run latency polling mode test + o ./lat_block.sh mtilab10-ib0 ==> run latency blocking mode test + o ./cl.sh mtilab10-ib0 ==> run transaction tests + o ./regress.sh mtilab10-ib0 ==> run transaction regression test + o ./quit.sh mtilab10-ib0 ==> instruct the server to quit + + * both can run limit test ./lim.sh (don't need to run server) + + d. Please reference to dapltest.txt for more test options diff --git a/branches/WOF2-3/ulp/dapl/doc/mv_dapl_relnotes.txt b/branches/WOF2-3/ulp/dapl/doc/mv_dapl_relnotes.txt new file mode 100644 index 00000000..5702eea8 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/doc/mv_dapl_relnotes.txt @@ -0,0 +1,167 @@ + Release Notes for uDAPL/IBAL + +RELEASE NOTES + + We would like to officially announce the availability of a + public source implementation of uDAPL over IBAL API. + + This uDAPL source code is derived from Source Forge DAPL foundry, see + + http://sourceforge.net/projects/dapl + +BETA RELEASE July 7, 2004 + +1. What is new from Alpha 2.0 Release + + Performance Improvements, additional functionality, bug fixes. + Tested with SourceForge BK Changeset 1.275. + + * DAT 1.1 compliance + * dat_evd_resize implemented + * async callbacks for CQ, QP, and IA implemented + * dat_psp_create_any improvements, no longer require kernel IOCTL. + * Performance enhancements, MTU, removed malloc in speed path, disconnect processing + * cleaned up many disconnect/close serialization issues + + * dynamic DTO-EVD sizing based on request/receive DTO depths + * enable re-use of EP, with dap_ep_reset, after EP connection termination. + * enhancements to dat_evd_wait to prevent missing completions + * dapls_ib_post_send; add refs/checking for disconnecting state, avoids losing completion + * dapl and dapltest build warnings resolved + +2. Expected Bugs and status + + +ALPHA 2.0 RELEASE Sept 25, 2003 + +1. What news from Alpha 1.1 Release + + This release is equivalent to Beta 1.09 uDAPL Source Forge Releases + It basically inherits the feature sets of Source Forge Beta 1.09 + Release plus extra feature sets coming from previous Alpha 1.1 Release + + Please refer to Beta 1.09 uDAPL Soure Force Release README for further + infomation. + + +ALPHA 1.1 RELEASE Jun 20, 2003 + +1. Feature sets + + This release is equivalent to Alpha 10-16 uDAPL Source Forge Releases + It basically inherit the feature sets of those Releases with minus/plus + followed features + + * Shared memory design and reference implementation + + * Map IA per HCA and/or individual port work. + + * Retry connection after a reject + + * Global LMR context hash table per HCA data structure + + * Implementing dat_psp_create_any functionality + + * Partial compliance to DAT 1.1 + +2. Expected Bugs and status + + * dapltest transaction test server fail to RDMA Read/Write to client + due to timing racing issue; however, client can do RDMA Read/Write + to server. + --> fixed + + * While dapltest server and client setup connections, abnormally kill + dapltest (ctrl+c) server and/or client, then unload the driver will + crash the system. + --> half fixed. Sometimes we successfully unload the driver, + sometimes we cannot due to resources are still dangling in kernel + (lsmod shows that module ibal is still in-used by other modules) + --> ChangeSet 1.112 target to fix this bug (# 745700); howerver, it + introduce other bug which dapltest fail to retry connection after + a reject. + --> With ChangeSet 1.110, test is running fine except unloading the + driver will crash system. + + * dapltest transaction test with multiple threads and multiple Endpoints + will have segmentation fault at the end of the test when multiple + threads exits + --> opened + + * dapltest transaction test with multiple threads (30) and multiple + Endpoints (100 for each thread) will fail to set up connection + --> need to invest and collect trace. Preliminary assesmment show + mad drop or SA/SM fail to response to queries. + + + +ALPHA 1.0 RELEASE May 29, 2003 + +1. Feature sets + + This release is derived from Alpha 9.0 uDAPL Source Forge Release + It basically inherit the feature sets of Alpha 9.0 SF Release; moreover + it has the following enhancements + + * Name Service and Address Resolution using SA/SM query mechanism. + Moving away from troublesome IPoIB and file-based mechanisms + + * Introducing dat_cr_handoff functionality. + + * Creating infrastructure to map IA per HCA and/or individual port of + the HCA. This feature can be selected for different type of + applications to obtain the high bandwidth or high availability. + + * Creating infrastructure to operate in loopback mode when the fabric + is down (without SA/SM) + +2. Expected bugs + + * dapltest transaction test server fail to RDMA Read/Write to client + due to timing racing issue; however, client can do RDMA Read/Write + to server. + + * dapltest transaction test with multiple threads and multiple Endpoints + will have segmentation fault at the end of the test when multiple + threads exits + + * While dapltest server and client setup connections, abnormally kill + dapltest (ctrl+c) server and/or client, then unload the driver will + crash the system. + +3. Future Enhancements + + * Performance enhancement. Test and measure performance when OS bypass + functionality of IBAL is available + + * Fixing the bug list mentioned above. + + * Selectively migrate to Source Forge Alpha 10.0 - 15.0 Releases + + * Shared memory region: mapping peer-to-peer DAPL shared memory region + model to master-slave InfiniBand shared memory region model. + + * Implement dat_psp_create_any() functionality + + * Conforming to DAT 1.1 Specification + +4. Performance Statistics + + * The performance of this release is limited due to the inavailability + of OS kernel bypass functionality of IBAL - Mellanox uVP/kVP + + * Testing with the following configuration: + o PIII 1 Ghz, PCI 64/66, 512 MB, ServerWork Grand Champion LE chipset + o Tavor A0 back to back + o Mellanox MSDK 0.0.6, FW 1.18 + o 2.4.18 & 2.4.18-10 UP/SMP kernels + + Bandwidth: 210 MB/s for 64-KB message + Latency polling mode: 26.2 usecs for 4-byte message + Latency blocking mode: 61.2 usecs for 4-byte message + + * With Xeon 2.4 Ghz, PCI-X 133 Mhz, Serverwork chipset for hardware + configuration and OS bypass enable for SW, we expect to achieve + 700-750 MB/s , 15 usecs for polling latency, and 35 usecs for + blocking latency + diff --git a/branches/WOF2-3/ulp/dapl/test/dirs b/branches/WOF2-3/ulp/dapl/test/dirs new file mode 100644 index 00000000..2d7badc4 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/dirs @@ -0,0 +1 @@ +DIRS=udapl diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/.DT_defaults b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/.DT_defaults new file mode 100644 index 00000000..706d8296 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/.DT_defaults @@ -0,0 +1,12 @@ +# +# Defaults for dapltest (chosen for the author's convenience) +# +setenv DBG " " # to debug, or not to debug, that is the question +setenv THR 1 # number of threads to use +setenv EPS 1 # number of EPs per thread +setenv ITER 10 # number of iterations over the set of OPs +setenv HOST dat-linux3 # hostname running the server side of dapltest +setenv DEV JniIbdd0 # name of IA device +setenv CMD SR # OP command: SR, RW, RR +setenv SZ 4096 # OP buffer segment size +setenv SEGS 1 # OP number of segments diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/.DT_onetest b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/.DT_onetest new file mode 100644 index 00000000..a56089e0 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/.DT_onetest @@ -0,0 +1,35 @@ +# +# time format: %U user %S sys %E elapsed %P CPU +# %w block (voluntarily, eg: dat_evd_wait) +# %c cswitch (involuntary, eg: time slice expired) +# +# dapltest: whatever is requested, plus 2 ops for inter-loop sync +# +/usr/bin/time -f "%U user %S sys %E real %P cpu %w block" \ +dapltest -T T $DBG -t $THR -w $EPS -i $ITER -s $HOST -D $DEV \ + client $CMD $SZ $SEGS client $CMD $SZ $SEGS \ + client $CMD $SZ $SEGS client $CMD $SZ $SEGS \ + client $CMD $SZ $SEGS client $CMD $SZ $SEGS \ + client $CMD $SZ $SEGS client $CMD $SZ $SEGS \ + client $CMD $SZ $SEGS client $CMD $SZ $SEGS \ + client $CMD $SZ $SEGS client $CMD $SZ $SEGS \ + client $CMD $SZ $SEGS client $CMD $SZ $SEGS \ + client $CMD $SZ $SEGS client $CMD $SZ $SEGS \ + client $CMD $SZ $SEGS client $CMD $SZ $SEGS \ + client $CMD $SZ $SEGS client $CMD $SZ $SEGS \ + client $CMD $SZ $SEGS client $CMD $SZ $SEGS \ + client $CMD $SZ $SEGS client $CMD $SZ $SEGS \ + client $CMD $SZ $SEGS client $CMD $SZ $SEGS \ + client $CMD $SZ $SEGS client $CMD $SZ $SEGS \ + client $CMD $SZ $SEGS client $CMD $SZ $SEGS \ + client $CMD $SZ $SEGS client $CMD $SZ $SEGS \ + client $CMD $SZ $SEGS client $CMD $SZ $SEGS \ + client $CMD $SZ $SEGS client $CMD $SZ $SEGS \ + client $CMD $SZ $SEGS client $CMD $SZ $SEGS \ + client $CMD $SZ $SEGS client $CMD $SZ $SEGS \ + client $CMD $SZ $SEGS client $CMD $SZ $SEGS \ + client $CMD $SZ $SEGS client $CMD $SZ $SEGS \ + client $CMD $SZ $SEGS client $CMD $SZ $SEGS \ + client $CMD $SZ $SEGS client $CMD $SZ $SEGS \ + client $CMD $SZ $SEGS client $CMD $SZ $SEGS \ + client SR 8 1 -f server SR 8 1 -f diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/.DT_perf.csh b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/.DT_perf.csh new file mode 100644 index 00000000..88d67aa9 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/.DT_perf.csh @@ -0,0 +1,42 @@ +#!/bin/csh -f +# +# Run through a number of DAPL test cases +# +set wholename = $0 +set me = $wholename:t +unset wholename +set echo +# +# Set Defaults +# +source .DT_defaults +# +# Iterate over the three transfer methods +# +foreach CMD ( SR RW RR) + # + # Iterate over the sizes of interest + # + foreach SZ ( 8 256 4096 65536 262144 ) + # + # XXX Following code is here because server side is run-once; + # XXX when fixed, move out of loops, above. (BURT 79002) + # Run the server asynchronously + # + if ($?DAPL_LOOPBACK) then + dapltest -T S -D $DEV & + else + rsh -n $HOST dapltest -T S -D $DEV & + endif + # + # Run the client side here, 'inline' + # + echo ===== $CMD $SZ ===== + source .DT_onetest + # + # wait for the async server + # + wait + echo "" + end +end diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/DaplTest_how_2.txt b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/DaplTest_how_2.txt new file mode 100644 index 00000000..8085e39c --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/DaplTest_how_2.txt @@ -0,0 +1,292 @@ +NAME + + dapltest - test for the Direct Access Programming Library (DAPL) + +DESCRIPTION + + Dapltest is a set of tests developed to exercise, characterize, + and verify the DAPL interfaces during development and porting. + At least two instantiations of the test must be run. One acts + as the server, fielding requests and spawning server-side test + threads as needed. Other client invocations connect to the + server and issue test requests. + + The server side of the test, once invoked, listens continuously + for client connection requests, until quit or killed. Upon + receipt of a connection request, the connection is established, + the server and client sides swap version numbers to verify that + they are able to communicate, and the client sends the test + request to the server. If the version numbers match, and the + test request is well-formed, the server spawns the threads + needed to run the test before awaiting further connections. + +USAGE + + dapltest [ -f script_file_name ] + [ -T S|Q|T|P|L ] [ -D device_name ] [ -d ] [ -R HT|LL|EC|PM|BE ] + + With no arguments, dapltest runs as a server using default values, + and loops accepting requests from clients. The -f option allows + all arguments to be placed in a file, to ease test automation. + The following arguments are common to all tests: + + [ -T S|Q|T|P|L ] Test function to be performed: + S - server loop + Q - quit, client requests that server + wait for any outstanding tests to + complete, then clean up and exit + T - transaction test, transfers data between + client and server + P - performance test, times DTO operations + L - limit test, exhausts various resources, + runs in client w/o server interaction + Default: S + + [ -D device_name ] Specifies the name of the device (interface adapter). + Default: host-specific, look for DT_MdepDeviceName + in dapl_mdep.h + + [ -d ] Enables extra debug verbosity, primarily tracing + of the various DAPL operations as they progress. + Repeating this parameter increases debug spew. + Errors encountered result in the test spewing some + explanatory text and stopping; this flag provides + more detail about what lead up to the error. + Default: zero + + [ -R BE ] Indicate the quality of service (QoS) desired. + Choices are: + HT - high throughput + LL - low latency + EC - economy (neither HT nor LL) + PM - premium + BE - best effort + Default: BE + +USAGE - Quit test client + + dapltest [Common_Args] [ -s server_name ] + + Quit testing (-T Q) connects to the server to ask it to clean up and + exit (after it waits for any outstanding test runs to complete). + In addition to being more polite than simply killing the server, + this test exercises the DAPL object teardown code paths. + There is only one argument other than those supported by all tests: + + -s server_name Specifies the name of the server interface. + No default. + + +USAGE - Transaction test client + + dapltest [Common_Args] [ -s server_name ] + [ -t threads ] [ -w endpoints ] [ -i iterations ] [ -Q ] + [ -V ] [ -P ] OPclient OPserver [ op3, + + Transaction testing (-T T) transfers a variable amount of data between + client and server. The data transfer can be described as a sequence of + individual operations; that entire sequence is transferred 'iterations' + times by each thread over all of its endpoint(s). + + The following parameters determine the behavior of the transaction test: + + -s server_name Specifies the hostname of the dapltest server. + No default. + + [ -t threads ] Specify the number of threads to be used. + Default: 1 + + [ -w endpoints ] Specify the number of connected endpoints per thread. + Default: 1 + + [ -i iterations ] Specify the number of times the entire sequence + of data transfers will be made over each endpoint. + Default: 1000 + + [ -Q ] Funnel completion events into a CNO. + Default: use EVDs + + [ -V ] Validate the data being transferred. + Default: ignore the data + + [ -P ] Turn on DTO completion polling + Default: off + + OP1 OP2 [ OP3, ... ] + A single transaction (OPx) consists of: + + server|client Indicates who initiates the + data transfer. + + SR|RR|RW Indicates the type of transfer: + SR send/recv + RR RDMA read + RW RDMA write + Defaults: none + + [ seg_size [ num_segs ] ] + Indicates the amount and format + of the data to be transferred. + Default: 4096 1 + (i.e., 1 4KB buffer) + + [ -f ] For SR transfers only, indicates + that a client's send transfer + completion should be reaped when + the next recv completion is reaped. + Sends and receives must be paired + (one client, one server, and in that + order) for this option to be used. + + Restrictions: + + Due to the flow control algorithm used by the transaction test, there + must be at least one SR OP for both the client and the server. + + Requesting data validation (-V) causes the test to automatically append + three OPs to those specified. These additional operations provide + synchronization points during each iteration, at which all user-specified + transaction buffers are checked. These three appended operations satisfy + the "one SR in each direction" requirement. + + The transaction OP list is printed out if -d is supplied. + +USAGE - Performance test client + + dapltest [Common_Args] -s server_name [ -m p|b ] + [ -i iterations ] [ -p pipeline ] OP + + Performance testing (-T P) times the transfer of an operation. + The operation is posted 'iterations' times. + + The following parameters determine the behavior of the transaction test: + + -s server_name Specifies the hostname of the dapltest server. + No default. + + -m b|p Used to choose either blocking (b) or polling (p) + Default: blocking (b) + + [ -i iterations ] Specify the number of times the entire sequence + of data transfers will be made over each endpoint. + Default: 1000 + + [ -p pipeline ] Specify the pipline length, valid arguments are in + the range [0,MAX_SEND_DTOS]. If a value greater than + MAX_SEND_DTOS is requested the value will be + adjusted down to MAX_SEND_DTOS. + Default: MAX_SEND_DTOS + + OP + An operation consists of: + + RR|RW Indicates the type of transfer: + RR RDMA read + RW RDMA write + Default: none + + [ seg_size [ num_segs ] ] + Indicates the amount and format + of the data to be transferred. + Default: 4096 1 + (i.e., 1 4KB buffer) + +USAGE - Limit test client + + Limit testing (-T L) neither requires nor connects to any server + instance. The client runs one or more tests which attempt to + exhaust various resources to determine DAPL limits and exercise + DAPL error paths. If no arguments are given, all tests are run. + + Limit testing creates the sequence of DAT objects needed to + move data back and forth, attempting to find the limits supported + for the DAPL object requested. For example, if the LMR creation + limit is being examined, the test will create a set of + {IA, PZ, CNO, EVD, EP} before trying to run dat_lmr_create() to + failure using that set of DAPL objects. The 'width' parameter + can be used to control how many of these parallel DAPL object + sets are created before beating upon the requested constructor. + Use of -m limits the number of dat_*_create() calls that will + be attempted, which can be helpful if the DAPL in use supports + essentailly unlimited numbers of some objects. + + The limit test arguments are: + + [ -m maximum ] Specify the maximum number of dapl_*_create() + attempts. + Default: run to object creation failure + + [ -w width ] Specify the number of DAPL object sets to + create while initializing. + Default: 1 + + [ limit_ia ] Attempt to exhaust dat_ia_open() + + [ limit_pz ] Attempt to exhaust dat_pz_create() + + [ limit_cno ] Attempt to exhaust dat_cno_create() + + [ limit_evd ] Attempt to exhaust dat_evd_create() + + [ limit_ep ] Attempt to exhaust dat_ep_create() + + [ limit_rsp ] Attempt to exhaust dat_rsp_create() + + [ limit_psp ] Attempt to exhaust dat_psp_create() + + [ limit_lmr ] Attempt to exhaust dat_lmr_create(4KB) + + [ limit_rpost ] Attempt to exhaust dat_ep_post_recv(4KB) + + [ limit_size_lmr ] Probe maximum size dat_lmr_create() + + Default: run all tests + + +EXAMPLES + + dapltest -T S -d -D ibnic0 + + Starts a server process with debug verbosity. + + dapltest -T T -d -s winIB -D ibnic0 -i 100 \ + client SR 4096 2 server SR 4096 2 + + Runs a transaction test, with both sides + sending one buffer with two 4KB segments, + one hundred times; dapltest server is on host winIB. + + dapltest -T P -d -s winIB -D JniIbdd0 -i 100 SR 4096 2 + + Runs a performance test, with the client + sending one buffer with two 4KB segments, + one hundred times. + + dapltest -T Q -s winIB -D ibnic0 + + Asks the dapltest server at host 'winIB' to clean up and exit. + + dapltest -T L -D ibnic0 -d -w 16 -m 1000 + + Runs all of the limit tests, setting up + 16 complete sets of DAPL objects, and + creating at most a thousand instances + when trying to exhaust resources. + + dapltest -T T -V -d -t 2 -w 4 -i 55555 -s winIB -D ibnic0 \ + client RW 4096 1 server RW 2048 4 \ + client SR 1024 4 server SR 4096 2 \ + client SR 1024 3 -f server SR 2048 1 -f + + Runs a more complicated transaction test, + with two thread using four EPs each, + sending a more complicated buffer pattern + for a larger number of iterations, + validating the data received. + + +BUGS (and To Do List) + + Use of CNOs (-Q) is not yet supported. + + Further limit tests could be added. diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/Makefile.cygwin b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/Makefile.cygwin new file mode 100644 index 00000000..a0766ef1 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/Makefile.cygwin @@ -0,0 +1,250 @@ +# +# Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. +# +# This Software is licensed under either one of the following two licenses: +# +# 1) under the terms of the "Common Public License 1.0" a copy of which is +# in the file LICENSE.txt in the root directory. The license is also +# available from the Open Source Initiative, see +# http://www.opensource.org/licenses/cpl.php. +# OR +# +# 2) under the terms of the "The BSD License" a copy of which is in the file +# LICENSE2.txt in the root directory. The license is also available from +# the Open Source Initiative, see +# http://www.opensource.org/licenses/bsd-license.php. +# +# Licensee has the right to choose either one of the above two licenses. +# +# Redistributions of source code must retain both the above copyright +# notice and either one of the license notices. +# +# Redistributions in binary form must reproduce both the above copyright +# notice, either one of the license notices in the documentation +# and/or other materials provided with the distribution. +# + +#********************************************************************** +# +# MODULE: Makefile +# +# PURPOSE: Makefile for dapl reference provider for CYGWIN environment +# +#*********************************************************************/ + + +############################################################## +# Application variables +# + +LD = $(CROSS_COMPILE)link.exe +CC = $(CROSS_COMPILE)cl.exe +CPP = $(CC) +AR = $(CROSS_COMPILE)ar +NM = $(CROSS_COMPILE)nm +STRIP = $(CROSS_COMPILE)strip +OBJCOPY = $(CROSS_COMPILE)objcopy +OBJDUMP = $(CROSS_COMPILE)objdump +RANLIB = $(CROSS_COMPILE)ranlib +MKDIR = mkdir -p +SED = /bin/sed +SHELL = /bin/sh + +TOPDIR = . + +OBJ_DIR = $(TOPDIR) +TARGET_DIR = $(TOPDIR) + +INCDIRS := \ + ../../../dat/include + +vpath %.h . ${INCDIRS} + + +################################################## +# targets +TAREXES = dapltest + +# data for user libraries +dapltest_SOURCES = $(SRCS) + +SRCS := \ + dapl_bpool.c \ + dapl_client.c \ + dapl_client_info.c \ + dapl_cnxn.c \ + dapl_endian.c \ + dapl_fft_cmd.c \ + dapl_fft_connmgt.c \ + dapl_fft_dataxfer.c \ + dapl_fft_dataxfer_client.c \ + dapl_fft_endpoint.c \ + dapl_fft_hwconn.c \ + dapl_fft_mem.c \ + dapl_fft_pz.c \ + dapl_fft_queryinfo.c \ + dapl_fft_test.c \ + dapl_fft_util.c \ + dapl_getopt.c \ + dapl_limit.c \ + dapl_limit_cmd.c \ + dapl_main.c \ + dapl_mdep.c \ + dapl_memlist.c \ + dapl_netaddr.c \ + dapl_params.c \ + dapl_performance_client.c \ + dapl_performance_cmd.c \ + dapl_performance_server.c \ + dapl_performance_stats.c \ + dapl_performance_util.c \ + dapl_quit_cmd.c \ + dapl_server.c \ + dapl_server_cmd.c \ + dapl_server_info.c \ + dapl_test_data.c \ + dapl_test_util.c \ + dapl_thread.c \ + dapl_transaction_cmd.c \ + dapl_transaction_stats.c \ + dapl_transaction_test.c \ + dapl_transaction_util.c \ + dapl_util.c + + +#################################################### +# compiler options CFLAGS +# + +# common flags +UOPTIONS += /nologo /MDd /W3 /GX /Od /FD /GZ /Gm /Zi + +# common defines +UCOMDEFS += /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "WIN32" /D "_DEBUG" \ + -D_WIN32_WINNT=0x0500 -DWINVER=0x0500 +# other options: /FR /Fd + +# private defines +UPRIVDEFS += /D "__WIN__" /D "__MSC__" /D "__i386__" + +CFLAGS += $(UOPTIONS) $(UCOMDEFS) $(UPRIVDEFS) + +# +# Provider specific CFLAGS definition +# + +########################################################### +# common included libraries +# Provider specific included libraries +# +ULDLIBS = dapl dat Ws2_32 advapi32 + + + + +######################################################### +# link options LDFLAGS +# + +MTARFLAGS= -cr + +TARFLAGS += cr + +# common flags +ULDOPTIONS += /nologo /incremental:no /machine:I386 /debug + +# common directories +ULDDIRS += /LIBPATH:"$(OBJ_DIR)" +ULDDIRS += /LIBPATH:"$(TOPDIR)/../../../dat/udat/Target" +ULDDIRS += /LIBPATH:"$(TOPDIR)/../../../dapl/udapl/Target" + +LDFLAGS += $(ULDOPTIONS) $(ULDDIRS) $(ULDLIBS:%=%.lib) + +# +# Provider specific ULDFLAGS +# +LDFLAGS += /LIBPATH:"$(MTHOME)/lib" + + +############################################################# +# Local functions +# +bsndir = $(notdir $(basename $1)) + +############################################################ +# Common rules +# +define COMPILE +$(CC) -c $(strip ${CFLAGS}) $(strip $(INCDIRS:%=-I%)) $(EXTRA_CFLAGS) $($(@:${OBJ_DIR}/%.obj=%.c_CFLAGS)) /Fo"$@" $< +endef + +define DEF_SET_VAR_SRCS +@echo "$@_VAR_SRCS += $($(basename $(call bsndir,$@))_SOURCES)" >> $@ +endef + +define DEF_SET_VAR_OBJS +@echo "$@_VAR_OBJS += $($(basename $(call bsndir,$@))_OBJECTS)" >> $@ +endef + + + +########################################################################### +# Start rules +# + +all: $(TAREXES:%=${TARGET_DIR}/%) $(TAROBJS:%=${OBJ_DIR}/%.obj) + + +########################################################################## +# Simple objects (user) + +$(TAROBJS:%=${OBJ_DIR}/%.obj): ${OBJ_DIR}/%.obj: %.c + @if [ ! -d $(OBJ_DIR) ]; then mkdir -p $(OBJ_DIR); fi + $(COMPILE) + + +$(OBJ_DIR)/%.obj: %.c + $(COMPILE) + + +########################################################################## +# Simple executables +# +$(TAREXES:%=$(TARGET_DIR)/%): % : %.mk +$(TAREXES:%=$(TARGET_DIR)/%.mk): Makefile.cygwin + @if [ ! -d $(OBJ_DIR) ]; then mkdir -p $(OBJ_DIR); fi + @if [ ! -d $(TARGET_DIR) ]; then mkdir -p $(TARGET_DIR); fi + @echo "# Do not edit. Automatically generated file." > $@ + @ + @${DEF_SET_VAR_OBJS} + @${DEF_SET_VAR_SRCS} + @ + @echo "SOURCES += $($(call bsndir,$@)_SOURCES)" >> $@ + @ + @echo "$(@:%.mk=%): \$$($@_VAR_SRCS:%.c=$(OBJ_DIR)/%.obj)" >> $@ + @echo "$(@:%.mk=%): \$$($@_VAR_OBJS:%.c=$(OBJ_DIR)/%.obj)" >> $@ + @echo -e "\t\$$(LD) \$$(LDFLAGS) \$$(\$$(@:$(OBJ_DIR)/%=%)_LDFLAGS) /out:\"\$$(@:%=%.exe)\" \c" >> $@ + @echo -e "\$$($@_VAR_SRCS:%.c=$(OBJ_DIR)/%.obj) \$$($@_VAR_OBJS) \c" >> $@ + @echo -e "\$$(LDLIBS:%=%.lib) \$$(LIBDIRS:%=/LIBPATH:%) \$$(\$$(@:$(OBJ_DIR)/%=%)_LDLIBS:%=%.lib) \c" >> $@ + @echo "\$$(\$$(@:$(OBJ_DIR)/%=%)_LIBDIRS:%=/LIBPATH:%)" >> $@ + + +ifneq ($(MAKECMDGOALS), clean) +ifneq ($(strip $(TAREXES)),) +-include $(patsubst %,$(OBJ_DIR)/%.mk,$(TAREXES)) +endif +endif + + +########################################################################## +# Clean rules +# +CLEANDIRS = $(OBJ_DIR) $(TARGET_DIR) + +CLEANFILES = *.obj *.dll *.lib *.sys *.pdb *.idb *.exp *.ilk *.sbr *.mk *.exe + +clean: $(CLEANDIRS) + @echo deleting dump files at $(shell pwd) + @rm -f $(CLEANFILES) + @if [ -d $(OBJ_DIR) ] ; then rm -f $(CLEANFILES:%=$(OBJ_DIR)/%); fi + diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/Makefile.org b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/Makefile.org new file mode 100644 index 00000000..479afca2 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/Makefile.org @@ -0,0 +1,54 @@ +# +# Copyright (c) 2002, Network Appliance, Inc. All rights reserved. +# +# This Software is licensed under the terms of the "IBM Common Public +# License 1.0" a copy of which is in the file LICENSE.txt in the +# root directory. The license is also available from the Open Source +# Initiative, see http://www.opensource.org/licenses/ibmpl.html. +# +# + +# ----------------------------------------------------- +# +# Description : Makefile for dapltest +# +# ----------------------------------------------------- + +IBA_HOME = ../../../.. +DAPL_ROOT = ../../.. + +M_OBJS = $(ALLOBJS) +M_TARGET := dapltest +I_TARGET := $(M_TARGET) + +EXTRA_CFLAGS = -g3 +EXTRA_CFLAGS += -Wall +EXTRA_CFLAGS += -Wmissing-prototypes +EXTRA_CFLAGS += -Wstrict-prototypes +EXTRA_CFLAGS += -Wmissing-declarations +EXTRA_CFLAGS += -pipe +EXTRA_CFLAGS += -D__LINUX__ +EXTRA_CFLAGS += -DDAT_THREAD_SAFE=DAT_FALSE +EXTRA_CFLAGS += -I$(DAPL_ROOT)/dat/include/ +EXTRA_CFLAGS += -Werror + + +EXTRA_LDFLAGS = -L$(DAPL_ROOT)/dat/udat +EXTRA_LDFLAGS += -ldat +EXTRA_LDFLAGS += -lpthread +EXTRA_LDFLAGS += -ldl + +ifeq ($(EXPLICIT_LINK),1) +EXTRA_LDFLAGS += -L$(DAPL_ROOT)/dapl/udapl +EXTRA_LDFLAGS += -ldapl +endif + +include $(IBA_HOME)/Makefile.config +include $(IBA_HOME)/Makefile.rules + +ifneq ($(ARCH),ia64) +EXTRA_CFLAGS += -Werror +EXTRA_CFLAGS += -D__PENTIUM__ +else +EXTRA_CFLAGS += -DIA64 +endif diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/Makefile.orig b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/Makefile.orig new file mode 100644 index 00000000..996384de --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/Makefile.orig @@ -0,0 +1,134 @@ +# +# Copyright (c) 2002, Network Appliance, Inc. All rights reserved. +# +# This Software is licensed under the terms of the "IBM Common Public +# License 1.0" a copy of which is in the file LICENSE.txt in the +# root directory. The license is also available from the Open Source +# Initiative, see http://www.opensource.org/licenses/ibmpl.html. +# +# + +# ----------------------------------------------------- +# +# Description : Makefile for dapltest +# +# ----------------------------------------------------- + + +.SILENT: + + +# +# Variables +# + +# DAPL_ROOT = path to DAPL root directory +DAPL_ROOT = $(shell pwd)/../../.. +# OBJECT_DIR = directory for object files +OBJECT_DIR = . +# SOURCE_DIRS = directories containing source files +SOURCE_DIRS = . +# EXEC = exectuable name +EXEC = dapltest + +# -------------- Automatic Variables ------------------ +SOURCE_FILES = $(shell ls $(foreach DIR, $(SOURCE_DIRS), $(DIR)/*.c)) +OBJECT_FILES = ${patsubst %.c,$(OBJECT_DIR)/%.o,$(notdir ${SOURCE_FILES})} +EXEC_FILE = $(OBJECT_DIR)/$(EXEC) + +VPATH = $(SOURCE_DIRS) +# ----------------------------------------------------- + + +# +# Tools +# + +ECHO = echo +INSTALL = /usr/bin/install +MAKEDEPEND = makedepend +RM = rm + + +# +# Compiler +# + +CC = gcc + +# DEFINES +DEFINES = __LINUX__ +DEFINES += __PENTIUM__ + +# INCLUDE_DIRS = directories containing include files +INCLUDE_DIRS = $(DAPL_ROOT)/dat/include/ + +CC_FLAGS = -g3 +CC_FLAGS += -Wall +CC_FLAGS += -Wmissing-prototypes +CC_FLAGS += -Wstrict-prototypes +CC_FLAGS += -Wmissing-declarations +CC_FLAGS += -Werror +CC_FLAGS += -pipe + +# -------------- Automatic Variables ------------------ +INCLUDE_PATH = $(foreach DIR, $(SOURCE_DIRS), -I$(DIR)) +INCLUDE_PATH += $(foreach DIR, $(INCLUDE_DIRS), -I$(DIR)) + +CC_FLAGS += $(INCLUDE_PATH) +CC_FLAGS += $(foreach DEFINE, $(DEFINES), -D$(DEFINE)) +# ----------------------------------------------------- + + +# +# Linker +# + +LD = gcc + +# LIB_OBJS = library object files +LIB_OBJS = dat +LIB_OBJS += pthread + +# LIB_DIRS = directories for library object files +LIB_DIRS = $(DAPL_ROOT)/dat/udat/Target + +# if the provider library should be explicitly linked +EXPLICIT_LINK=1 +ifeq ($(EXPLICIT_LINK),1) +# in addition to providers listed in the DAT static registry +# the specified provider will be available to the consumer +LIB_OBJS += dapl +LIB_DIRS += $(DAPL_ROOT)/dapl/udapl/Target +endif + +# -------------- Automatic Variables ------------------ +LD_FLAGS = $(foreach DIR, $(LIB_DIRS), -L$(DIR)) +LD_FLAGS += $(foreach DIR, $(LIB_DIRS), -Wl,-R$(DIR)) +LD_FLAGS += $(foreach OBJ, $(LIB_OBJS), -l$(OBJ)) +# ----------------------------------------------------- + + +# +# Rules +# + +all : $(EXEC_FILE) + +$(EXEC_FILE) : $(OBJECT_DIR) $(OBJECT_FILES) + $(ECHO) "--- Linking $@ ---" + $(LD) $(LD_FLAGS) $(OBJECT_FILES) -o $@ + +$(OBJECT_DIR) : + $(ECHO) "--- Creating Directory $@ ---" + $(INSTALL) -d $@ + +$(OBJECT_DIR)/%.o: %.c + $(ECHO) "--- Compiling $< ---" + $(CC) $(CC_FLAGS) -o $@ -c $< + +tidy: + $(RM) -f $(foreach DIR, $(SOURCE_DIRS), $(DIR)/*~) + +clean: tidy + $(RM) -f $(OBJECT_DIR)/*.o $(OBJECT_DIR)/$(EXEC) diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/SOURCES b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/SOURCES new file mode 100644 index 00000000..58285780 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/SOURCES @@ -0,0 +1,69 @@ +!if $(FREEBUILD) +TARGETNAME=dapltest +!else +TARGETNAME=dapltestd +!endif +TARGETPATH=..\..\..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE=PROGRAM +UMTYPE=console +USE_MSVCRT=1 + +SOURCES=dapltest.rc \ + dapl_bpool.c \ + dapl_client.c \ + dapl_client_info.c \ + dapl_cnxn.c \ + dapl_endian.c \ + dapl_fft_cmd.c \ + dapl_fft_connmgt.c \ + dapl_fft_dataxfer.c \ + dapl_fft_dataxfer_client.c \ + dapl_fft_endpoint.c \ + dapl_fft_hwconn.c \ + dapl_fft_mem.c \ + dapl_fft_pz.c \ + dapl_fft_queryinfo.c \ + dapl_fft_test.c \ + dapl_fft_util.c \ + dapl_getopt.c \ + dapl_limit.c \ + dapl_limit_cmd.c \ + dapl_main.c \ + dapl_mdep.c \ + dapl_memlist.c \ + dapl_netaddr.c \ + dapl_params.c \ + dapl_performance_client.c \ + dapl_performance_cmd.c \ + dapl_performance_server.c \ + dapl_performance_stats.c \ + dapl_performance_util.c \ + dapl_quit_cmd.c \ + dapl_server.c \ + dapl_server_cmd.c \ + dapl_server_info.c \ + dapl_test_data.c \ + dapl_test_util.c \ + dapl_thread.c \ + dapl_transaction_cmd.c \ + dapl_transaction_stats.c \ + dapl_transaction_test.c \ + dapl_transaction_util.c \ + dapl_util.c + +INCLUDES=..\..\..\dapl\include;..\..\..\dat\include; +RCOPTIONS=/I..\..\..\..\..\inc; + +# Set defines particular to the driver. A good Idea to build listings +USER_C_FLAGS=$(USER_C_FLAGS) -DDYNAMIC_DAT_LOADING +!if $(FREEBUILD) +USER_C_FLAGS=$(USER_C_FLAGS) -DDAT_DLL_NAME=\"dat.dll\" +DATLIB=dat.lib +!else +USER_C_FLAGS=$(USER_C_FLAGS) -DDAT_DLL_NAME=\"datd.dll\" +DATLIB=datd.lib +!endif + +TARGETLIBS=$(TARGETPATH)\*\$(DATLIB) $(SDK_LIB_PATH)\ws2_32.lib + +MSC_WARNING_LEVEL= /W3 diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/bw.sh b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/bw.sh new file mode 100644 index 00000000..9a5c03e5 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/bw.sh @@ -0,0 +1,22 @@ +#!/bin/sh +# +# Sample client invocation +# +# +me=`basename $0` +case $# in +0) echo Usage: $me '[hostname [size [device]]]' 1>&2 ; exit 1;; +1) host=$1 + device=IbalHca0 + size=65536 ;; +2) host=$1 + device=IbalHca0 + size=$2 ;; +3) host=$1 + device=$3 + size=$2 ;; +*) echo Usage: $me '[hostname [size [device]]]' 1>&2 ; exit 1;; +esac + +./dapltest -T P -d -i 1024 -s ${host} -D ${device} \ + -p 16 -m p RW ${size} 1 diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/cl.sh b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/cl.sh new file mode 100644 index 00000000..94c8cfe2 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/cl.sh @@ -0,0 +1,30 @@ +#!/bin/sh +# +# Sample client invocation +# +# +me=`basename $0` +case $# in +0) host=mtilab11-ib0 + device=IbalHca0 ;; +1) host=$1 + device=IbalHca0 ;; +2) host=$1 + device=$2 ;; +*) echo Usage: $me '[hostname [device] ]' 1>&2 ; exit 1;; +esac +# +# +# ./dapltest -T T -V -d -t 2 -w 2 -i 1000111 -s ${host} -D ${device} \ +# client RW 4096 1 server RW 2048 4 \ +# client RR 1024 2 server RR 2048 2 \ +# client SR 1024 3 -f server SR 256 3 -f + + ./dapltest -T T -P -d -t 1 -w 1 -i 1024 -s ${host} -D ${device} \ + client RW 4096 1 server RW 2048 4 \ + server RR 1024 2 client RR 2048 2 \ + client SR 1024 3 -f server SR 256 3 -f + +#dapltest -T T -d -s ${host} -D ${device} -i 10000 -t 1 -w 1 \ +# client SR 256 \ +# server SR 256 diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_bpool.c b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_bpool.c new file mode 100644 index 00000000..0acd5965 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_bpool.c @@ -0,0 +1,348 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_test_data.h" +#include "dapl_bpool.h" +#include "dapl_mdep.h" +#include "dapl_memlist.h" +#include "dapl_proto.h" + +/*****************************************************************************/ +/* + * Allocate buffer pool (data buffers) + * + * Caller wants to allocate buffers of bytes, + * with each buffer aligned as requested. The caller is free to + * use the buffers separately, or as one contiguous segment, so + * we allocate IOV entries enough to support either usage. + */ +Bpool * +DT_BpoolAlloc ( + Per_Test_Data_t * pt_ptr, + DAT_IA_HANDLE ia_handle, + DAT_PZ_HANDLE pz_handle, + DAT_EP_HANDLE ep_handle, + DAT_EVD_HANDLE rmr_evd_handle, + DAT_COUNT seg_size, + DAT_COUNT num_segs, + DAT_COUNT alignment, + DAT_BOOLEAN enable_rdma_write, + DAT_BOOLEAN enable_rdma_read) +{ + unsigned char *module = "DT_BpoolAlloc"; + unsigned char *alloc_ptr = 0; + Bpool *bpool_ptr = 0; + DAT_COUNT alloc_size; + DAT_REGION_DESCRIPTION region; + DAT_RETURN ret; + + /* We'll hand out aligned buffers, compensate here */ + seg_size = DT_RoundSize (seg_size, alignment); + alloc_size = seg_size * num_segs + alignment; + + alloc_ptr = (unsigned char *) DT_MemListAlloc ( pt_ptr, "bpool", BUFF, + alloc_size); + if (!alloc_ptr) + { + DT_Mdep_printf ("No Memory to create bpool buffer!\n"); + goto err; + } + + bpool_ptr = (Bpool *) DT_MemListAlloc (pt_ptr, "bpool", BPOOL, sizeof (Bpool) + + num_segs * sizeof (DAT_LMR_TRIPLET)); + if (!bpool_ptr) + { + DT_Mdep_printf ("No Memory to create Bpool!\n"); + goto err; + } + + bpool_ptr->alloc_ptr = alloc_ptr; + bpool_ptr->alloc_size = alloc_size; + bpool_ptr->pz_handle = pz_handle; + bpool_ptr->num_segs = num_segs; + bpool_ptr->ep_handle = ep_handle; + bpool_ptr->buffer_size = seg_size * num_segs; + bpool_ptr->buffer_start = DT_AlignPtr (alloc_ptr, alignment); + bpool_ptr->tripl_start = (DAT_LMR_TRIPLET *) (bpool_ptr + 1); + bpool_ptr->seg_size = seg_size; + bpool_ptr->enable_rdma_write = enable_rdma_write; + bpool_ptr->enable_rdma_read = enable_rdma_read; + bpool_ptr->rmr_evd_handle = rmr_evd_handle; + + DT_Mdep_spew (3, ("lmr_create [%p, %x]\n", bpool_ptr->buffer_start, + bpool_ptr->buffer_size)); + + memset (®ion, 0, sizeof (region)); + region.for_va = bpool_ptr->buffer_start; + ret = dat_lmr_create (ia_handle, + DAT_MEM_TYPE_VIRTUAL, + region, + bpool_ptr->buffer_size, + pz_handle, + DAT_MEM_PRIV_ALL_FLAG, + &bpool_ptr->lmr_handle, + &bpool_ptr->lmr_context, + &bpool_ptr->rmr_context, + &bpool_ptr->reg_size, + &bpool_ptr->reg_addr); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_lmr_create failed %s\n", + module, DT_RetToString (ret)); + goto err; + } + /* verify that the outputs are reasonable */ + if (((uintptr_t)bpool_ptr->reg_addr > (uintptr_t)bpool_ptr->buffer_start) + || (bpool_ptr->reg_size < bpool_ptr->buffer_size + + ((uintptr_t)bpool_ptr->buffer_start - (uintptr_t)bpool_ptr->reg_addr))) + { + DT_Mdep_printf ( "%s: dat_lmr_create bogus" + "in: 0x%p, %x out 0x" F64x ", " F64x "\n", + module, + bpool_ptr->buffer_start, bpool_ptr->buffer_size, + (DAT_UVERYLONG)bpool_ptr->reg_addr, + (DAT_UVERYLONG)bpool_ptr->reg_size); + goto err; + } + + DT_Mdep_spew (3, ("lmr_create OK [0x" F64x ", " F64x ", lctx=%x]\n", + (DAT_UVERYLONG)bpool_ptr->reg_addr, + (DAT_UVERYLONG)bpool_ptr->reg_size, bpool_ptr->lmr_context)); +#ifdef ALLOW_MW /* no BIND RMR */ /* Enable RDMA if requested */ + if (enable_rdma_write || enable_rdma_read) + { + DAT_LMR_TRIPLET iov; + DAT_RMR_COOKIE cookie; + DAT_MEM_PRIV_FLAGS mflags; + DAT_RMR_BIND_COMPLETION_EVENT_DATA rmr_stat; + + /* create the RMR */ + ret = dat_rmr_create (pz_handle, &bpool_ptr->rmr_handle); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_rmr_create failed %s\n", + module, DT_RetToString (ret)); + goto err; + } + + /* bind the RMR */ + iov.virtual_address = bpool_ptr->reg_addr; + iov.segment_length = bpool_ptr->reg_size; + iov.lmr_context = bpool_ptr->lmr_context; + cookie.as_64 = (DAT_UINT64)0UL; + cookie.as_ptr = (DAT_PVOID) (uintptr_t) bpool_ptr->reg_addr; + mflags = (enable_rdma_write && enable_rdma_read ? DAT_MEM_PRIV_ALL_FLAG + : (enable_rdma_write ? DAT_MEM_PRIV_WRITE_FLAG + : (enable_rdma_read ? DAT_MEM_PRIV_READ_FLAG : 0))); + + DT_Mdep_spew (3, ("rmr_bind [" F64x ", " F64x "]\n", + (DAT_UVERYLONG)bpool_ptr->reg_addr, + (DAT_UVERYLONG)bpool_ptr->reg_size)); + + ret = dat_rmr_bind ( bpool_ptr->rmr_handle, + &iov, + mflags, + bpool_ptr->ep_handle, + cookie, + DAT_COMPLETION_DEFAULT_FLAG, + &bpool_ptr->rmr_context); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_rmr_bind failed %s\n", + module, DT_RetToString (ret)); + goto err; + } + + DT_Mdep_spew (3, ("rmr_bind-wait\n")); + + /* await the bind result */ + if (!DT_rmr_event_wait (bpool_ptr->rmr_evd_handle, &rmr_stat) || + !DT_rmr_check (&rmr_stat, + bpool_ptr->rmr_handle, + (DAT_PVOID) (uintptr_t) bpool_ptr->reg_addr, + "Bpool")) + { + goto err; + } + + DT_Mdep_spew (3, ("rmr_bound [OK Rctx=%x]\n", bpool_ptr->rmr_context)); + } +#endif /** ALLOW_MW */ + + /* + * Finally! Return the newly created Bpool. + */ + return ( bpool_ptr ); + + + /* ********************************* + * Whoops - clean up and return NULL + */ +err: + if (bpool_ptr) + { + if (bpool_ptr->rmr_handle) + { + ret = dat_rmr_free (bpool_ptr->rmr_handle); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_rmr_free failed %s\n", + module, DT_RetToString (ret)); + } + } + if (bpool_ptr->lmr_handle) + { + ret = dat_lmr_free (bpool_ptr->lmr_handle); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_lmr_free failed %s\n", + module, DT_RetToString (ret)); + } + } + DT_MemListFree (pt_ptr, bpool_ptr); + } + if (alloc_ptr) + { + DT_MemListFree (pt_ptr, alloc_ptr); + } + + return ( 0 ); +} + +/*****************************************************************************/ +bool +DT_Bpool_Destroy (Per_Test_Data_t * pt_ptr, + Bpool * bpool_ptr) +{ + unsigned char *module = "DT_Bpool_Destroy"; + bool rval = true; + + if (bpool_ptr) + { + if (bpool_ptr->alloc_ptr) + { + if (bpool_ptr->rmr_handle) + { + DAT_LMR_TRIPLET iov; + DAT_RMR_COOKIE cookie; + DAT_RETURN ret; + + iov.virtual_address = bpool_ptr->reg_addr; + iov.segment_length = 0; /* un-bind */ + iov.lmr_context = bpool_ptr->lmr_context; + cookie.as_64 = (DAT_UINT64)0UL; + cookie.as_ptr = (DAT_PVOID) (uintptr_t)bpool_ptr->reg_addr; + + /* + * Do not attempt to unbind here. The remote node + * is going through the same logic and may disconnect + * before an unbind completes. Any bind/unbind + * operation requires a CONNECTED QP to complete, + * a disconnect will cause problems. Unbind is + * a simple optimization to allow rebinding of + * an RMR, doing an rmr_free will pull the plug + * and cleanup properly. + */ + ret = dat_rmr_free (bpool_ptr->rmr_handle); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_rmr_free failed %s\n", + module, DT_RetToString (ret)); + rval = false; + } + } + + if (bpool_ptr->lmr_handle) + { + DAT_RETURN ret = dat_lmr_free (bpool_ptr->lmr_handle); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_lmr_free failed %s\n", + module, DT_RetToString (ret)); + rval = false; + } + } + DT_MemListFree (pt_ptr, bpool_ptr->alloc_ptr); + } + DT_MemListFree (pt_ptr, bpool_ptr); + } + + return (rval); +} + +/*****************************************************************************/ +unsigned char * +DT_Bpool_GetBuffer (Bpool * bpool_ptr, int index) +{ + return ( bpool_ptr->buffer_start + index * bpool_ptr->seg_size ); +} + +/*****************************************************************************/ +DAT_COUNT +DT_Bpool_GetBuffSize (Bpool * bpool_ptr, int index) +{ + return ( bpool_ptr->seg_size ); +} + +/*****************************************************************************/ +DAT_LMR_TRIPLET * +DT_Bpool_GetIOV (Bpool * bpool_ptr, int index) +{ + return ( bpool_ptr->tripl_start + index ); +} + +/*****************************************************************************/ +DAT_LMR_CONTEXT +DT_Bpool_GetLMR (Bpool * bpool_ptr, int index) +{ + return ( bpool_ptr->lmr_context ); +} + +/*****************************************************************************/ +DAT_RMR_CONTEXT +DT_Bpool_GetRMR (Bpool * bpool_ptr, int index) +{ + return ( bpool_ptr->rmr_context ); +} + +/*****************************************************************************/ +void +DT_Bpool_print (Bpool * bpool_ptr) +{ + DT_Mdep_printf ("BPOOL %p\n", bpool_ptr); + DT_Mdep_printf ("BPOOL alloc_ptr %p\n", (unsigned char *) bpool_ptr->alloc_ptr); + DT_Mdep_printf ("BPOOL alloc_size %x\n", (int) bpool_ptr->alloc_size); + DT_Mdep_printf ("BPOOL pz_handle %p\n", (uintptr_t*) bpool_ptr->pz_handle); + DT_Mdep_printf ("BPOOL num_segs %x\n", (int) bpool_ptr->num_segs); + DT_Mdep_printf ("BPOOL seg_size %x\n", (int) bpool_ptr->seg_size); + DT_Mdep_printf ("BPOOL tripl_start %p\n", bpool_ptr->tripl_start); + DT_Mdep_printf ("BPOOL buffer_start %p\n", bpool_ptr->buffer_start); + DT_Mdep_printf ("BPOOL buffer_size %x\n", (int) bpool_ptr->buffer_size); + DT_Mdep_printf ("BPOOL rdma_write %x\n", + (int) bpool_ptr->enable_rdma_write); + DT_Mdep_printf ("BPOOL rdmaread %x\n", + (int) bpool_ptr->enable_rdma_read); +} diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_bpool.h b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_bpool.h new file mode 100644 index 00000000..161416e6 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_bpool.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#ifndef __DAPL_BPOOL_H__ +#define __DAPL_BPOOL_H__ + +#include "dapl_mdep.h" +#include + +#pragma pack(1) +typedef struct Bpool_tag Bpool; +/* + * struct Bpool + */ + +struct Bpool_tag +{ + unsigned char *alloc_ptr; + DAT_UINT32 alloc_size; + DAT_PZ_HANDLE pz_handle; + DAT_COUNT seg_size; + DAT_COUNT num_segs; /* num segments */ + unsigned char *buffer_start; /* Start of buffer area */ + DAT_COUNT buffer_size; /* Size of data buffer (rounded) */ + DAT_VADDR reg_addr; /* start of registered area */ + DAT_VLEN reg_size; /* size of registered area */ + DAT_EP_HANDLE ep_handle; /* EP area is registered to */ + DAT_LMR_HANDLE lmr_handle; /* local access */ + DAT_LMR_CONTEXT lmr_context; + DAT_LMR_TRIPLET*tripl_start; /* local IOV */ + DAT_BOOLEAN enable_rdma_write; /* remote access */ + DAT_BOOLEAN enable_rdma_read; + DAT_RMR_HANDLE rmr_handle; + DAT_RMR_CONTEXT rmr_context; + DAT_EVD_HANDLE rmr_evd_handle; +}; +#pragma pack() +#endif diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_client.c b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_client.c new file mode 100644 index 00000000..d170a830 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_client.c @@ -0,0 +1,603 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_server_info.h" +#include "dapl_test_data.h" +#include "dapl_mdep.h" +#include "dapl_memlist.h" +#include "dapl_proto.h" +#include "dapl_transaction_test.h" +#include "dapl_version.h" +#include "dapl_cnxn.h" +#include +#include + +#define DFLT_QLEN 40 /* default event queue length */ +#define MAX_CONN_RETRY 8 + +/* + * Client control routine Connect to the server, send the command across. + * Then start the client-side of the test - creating threads as needed + */ +void +DT_cs_Client (Params_t * params_ptr, + char *dapl_name, + char *server_name, + DAT_UINT32 total_threads) +{ + Per_Test_Data_t *pt_ptr = NULL; + DAT_IA_HANDLE ia_handle = DAT_HANDLE_NULL; + DAT_PZ_HANDLE pz_handle = DAT_HANDLE_NULL; + DAT_EVD_HANDLE recv_evd_hdl = DAT_HANDLE_NULL; + DAT_EVD_HANDLE reqt_evd_hdl = DAT_HANDLE_NULL; + DAT_EVD_HANDLE conn_evd_hdl = DAT_HANDLE_NULL; + DAT_EVD_HANDLE async_evd_hdl = DAT_HANDLE_NULL; + DAT_EP_HANDLE ep_handle = DAT_HANDLE_NULL; + Server_Info_t *sinfo = NULL; + Transaction_Cmd_t *Transaction_Cmd = NULL; + Performance_Cmd_t *Performance_Cmd = NULL; + Quit_Cmd_t *Quit_Cmd = NULL; + Bpool *bpool = NULL; + DAT_IA_ADDRESS_PTR remote_netaddr = NULL; + unsigned char *module = "DT_cs_Client"; + unsigned int did_connect = 0; + unsigned int retry_cnt = 0; + DAT_DTO_COOKIE dto_cookie; + + DAT_DTO_COMPLETION_EVENT_DATA dto_stat; + DAT_EVENT_NUMBER event_num; + unsigned char * buffp; + DAT_RETURN ret; + + dto_cookie.as_64 = LZERO; + + DT_Mdep_printf ("%s: Starting Test ... \n", module); + + /* Set up the Per_Test_Data */ + pt_ptr = DT_Alloc_Per_Test_Data (); + if (!pt_ptr) + { + DT_Mdep_printf ("%s: no memory for Per_Test_Data\n", module); + return; + } + DT_MemListInit (pt_ptr); /* init MemlistLock and memListHead */ + DT_Thread_Init (pt_ptr); /* init ThreadLock and threadcount */ + pt_ptr->local_is_server = false; + pt_ptr->Client_Info.dapltest_version = DAPLTEST_VERSION; + pt_ptr->Client_Info.is_little_endian = DT_local_is_little_endian; + pt_ptr->Client_Info.test_type = params_ptr->test_type; + pt_ptr->Client_Info.total_threads = total_threads; + memcpy ( (void *) (uintptr_t) &pt_ptr->Params, + (const void *) params_ptr, + sizeof (Params_t)); + + /* Allocate and fill in the Server's address */ + remote_netaddr = DT_NetAddrAlloc (pt_ptr); + if ( !remote_netaddr + || !DT_NetAddrLookupHostAddress (remote_netaddr, server_name)) + { + DT_Mdep_printf ("%s: Cannot find server address\n", module); + goto client_exit; + } + +#ifdef DYNAMIC_DAT_LOADING + /* Open the IA */ + ret = dat_open (dapl_name, + DFLT_QLEN, + &async_evd_hdl, + &ia_handle, + DAT_VERSION_MAJOR, + DAT_VERSION_MINOR, + DAT_THREADSAFE); +#else + ret = dat_ia_open (dapl_name, + DFLT_QLEN, + &async_evd_hdl, + &ia_handle); +#endif //DYNAMIC_DAT_LOADING + + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf( "%s: Could not open %s (%s)\n", + module, dapl_name, DT_RetToString (ret)); + ia_handle = DAT_HANDLE_NULL; + goto client_exit; + } + DT_Mdep_debug (("%s: IA %s opened\n", module, dapl_name)); + + /* Create a PZ */ + ret = dat_pz_create (ia_handle, &pz_handle); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_pz_create error: %s\n", + module, DT_RetToString (ret)); + pz_handle = DAT_HANDLE_NULL; + goto client_exit; + } + + /* Create 3 events - recv, request, connect */ + ret = dat_evd_create (ia_handle, + DFLT_QLEN, + DAT_HANDLE_NULL, + DAT_EVD_DTO_FLAG, + &recv_evd_hdl); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_evd_create (recv) failed %s\n", + module, DT_RetToString (ret)); + recv_evd_hdl = DAT_HANDLE_NULL; + goto client_exit; + } + ret = dat_evd_create (ia_handle, + DFLT_QLEN, + DAT_HANDLE_NULL, + DAT_EVD_DTO_FLAG | DAT_EVD_RMR_BIND_FLAG, + &reqt_evd_hdl); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_evd_create (send) failed %s\n", + module, DT_RetToString (ret)); + reqt_evd_hdl = DAT_HANDLE_NULL; + goto client_exit; + } + ret = dat_evd_create (ia_handle, + DFLT_QLEN, + DAT_HANDLE_NULL, + DAT_EVD_CONNECTION_FLAG, + &conn_evd_hdl); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_evd_create (conn) failed %s\n", + module, DT_RetToString (ret)); + conn_evd_hdl = DAT_HANDLE_NULL; + goto client_exit; + } + + /* Create an EP */ + ret = dat_ep_create (ia_handle, /* IA */ + pz_handle, /* PZ */ + recv_evd_hdl, /* recv */ + reqt_evd_hdl, /* request */ + conn_evd_hdl, /* connect */ + (DAT_EP_ATTR *) NULL, + &ep_handle); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_ep_create error: %s\n", + module, + DT_RetToString (ret)); + ep_handle = DAT_HANDLE_NULL; + goto client_exit; + } + DT_Mdep_debug (("%s: EP created\n", module)); + + /* + * Gather whatever info we want about defaults, + * and check that we can handle the requested parameters. + */ + if (!DT_query (pt_ptr, ia_handle, ep_handle) || + !DT_check_params (pt_ptr, module)) + { + goto client_exit; + } + + bpool = DT_BpoolAlloc (pt_ptr, + ia_handle, + pz_handle, + ep_handle, + DAT_HANDLE_NULL, /* no RMR */ + DT_RoundSize (sizeof (Transaction_Cmd_t), 8192), + 3, /* num_buffers */ + DAT_OPTIMAL_ALIGNMENT, + false, + false); + if (bpool == 0) + { + DT_Mdep_printf ("%s: no memory for command buffer pool.\n", module); + goto client_exit; + } + + DT_Mdep_spew (3, ("RecvSrvInfo 0 %p\n", (DAT_PVOID) DT_Bpool_GetBuffer ( + bpool, 0))); + DT_Mdep_spew (3, ("SndCliInfo 1 %p\n", (DAT_PVOID) DT_Bpool_GetBuffer ( + bpool, 1))); + DT_Mdep_spew (3, ("SndCommand 2 %p\n", (DAT_PVOID) DT_Bpool_GetBuffer ( + bpool, 2))); + + /* Post recv buffer for Server_Info (1st buffer in pool) */ + DT_Mdep_debug (("%s: Posting 1 recv buffer\n", module)); +retry_repost: + if (!DT_post_recv_buffer (ep_handle, + bpool, + 0, + DT_Bpool_GetBuffSize (bpool, 0))) + { + DT_Mdep_printf ("%s: cannot post Server_Info recv buffer.\n", module); + goto client_exit; + } + + DT_Mdep_debug (("%s: Connect Endpoint\n", module)); +retry: + ret = dat_ep_connect (ep_handle, + remote_netaddr, + SERVER_PORT_NUMBER, + DAT_TIMEOUT_INFINITE, + 0, (DAT_PVOID) 0, /* no private data */ + params_ptr->ReliabilityLevel, + DAT_CONNECT_DEFAULT_FLAG); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: Cannot connect Endpoint %s\n", + module, DT_RetToString (ret)); + goto client_exit; + } + + DT_Mdep_debug (("%s: Await connection ...\n", module)); + if (!DT_conn_event_wait (ep_handle, conn_evd_hdl, &event_num)) + { + if ( event_num == DAT_CONNECTION_EVENT_PEER_REJECTED ) + { + DAT_EVENT event; + DAT_COUNT drained = 0; + + DT_Mdep_Sleep (1000); + DT_Mdep_printf ("%s: retrying connection...\n", module); + retry_cnt++; + /* + * See if any buffers were flushed as a result of + * the REJECT; clean them up and repost if so + */ + dat_ep_reset (ep_handle); + do + { + + ret = dat_evd_dequeue ( recv_evd_hdl, + &event); + drained++; + } while (ret != DAT_QUEUE_EMPTY); + + if (drained > 1 && retry_cnt < MAX_CONN_RETRY) + { + DT_Mdep_printf("Reposting!!! %d\n", drained); + goto retry_repost; + } + if (retry_cnt < MAX_CONN_RETRY) + { + goto retry; + } + } + DT_Mdep_printf ("%s: bad connection event\n", module); + goto client_exit; + } + + did_connect++; + if (DT_dapltest_debug) + { + DT_Mdep_debug (("%s: Connected!\n", module)); + get_ep_connection_state (ep_handle); + } + +#ifdef CM_BUSTED + /***** XXX Chill out a bit to give the kludged CM a chance ... + *****/DT_Mdep_Sleep (1000); +#endif + + + /* Send Client_Info (using 2nd buffer in the pool) */ + DT_Mdep_debug (("%s: Sending Client_Info\n", module)); + buffp = DT_Bpool_GetBuffer (bpool, 1); + memcpy ( (void *)buffp, + (const void *) &pt_ptr->Client_Info, + sizeof (Client_Info_t)); + DT_Client_Info_Endian ((Client_Info_t *) buffp); + if (!DT_post_send_buffer ( ep_handle, + bpool, + 1, + DT_Bpool_GetBuffSize (bpool, 1))) + { + DT_Mdep_printf ("%s: cannot send Client_Info\n", module); + goto client_exit; + } + /* reap the send and verify it */ + dto_cookie.as_ptr = (DAT_PVOID) (uintptr_t) DT_Bpool_GetBuffer ( bpool, 1); + DT_Mdep_debug (("%s: Sent Client_Info - awaiting completion\n", module)); + if (!DT_dto_event_wait (reqt_evd_hdl, &dto_stat) || + !DT_dto_check ( &dto_stat, + ep_handle, + DT_Bpool_GetBuffSize (bpool, 1), + dto_cookie, + "Client_Info_Send")) + { + goto client_exit; + } + + /* Set up the Command (using 3rd buffer in pool) */ + DT_Mdep_debug (("%s: Sending Command\n", module)); + buffp = DT_Bpool_GetBuffer (bpool, 2); + switch (pt_ptr->Client_Info.test_type) + { + case QUIT_TEST: + { + Quit_Cmd = &pt_ptr->Params.u.Quit_Cmd; + memcpy ( (void *)buffp, + (const void *)Quit_Cmd, + sizeof (Quit_Cmd_t)); + DT_Quit_Cmd_Endian ((Quit_Cmd_t *) buffp, true); + break; + } + case TRANSACTION_TEST: + { + Transaction_Cmd = &pt_ptr->Params.u.Transaction_Cmd; + memcpy ( (void *)buffp, + (const void *)Transaction_Cmd, + sizeof (Transaction_Cmd_t)); + DT_Transaction_Cmd_Endian ((Transaction_Cmd_t *)buffp, true); + break; + } + case PERFORMANCE_TEST: + { + Performance_Cmd = &pt_ptr->Params.u.Performance_Cmd; + memcpy ( (void *)buffp, + (const void *)Performance_Cmd, + sizeof (Performance_Cmd_t)); + DT_Performance_Cmd_Endian ((Performance_Cmd_t *)buffp); + break; + } + default: + { + DT_Mdep_printf ("Unknown Test Type\n"); + goto client_exit; + } + } + + /* Send the Command buffer */ + if (!DT_post_send_buffer ( ep_handle, + bpool, + 2, + DT_Bpool_GetBuffSize (bpool, 2))) + { + DT_Mdep_printf ("%s: cannot send Command\n", module); + goto client_exit; + } + /* reap the send and verify it */ + dto_cookie.as_64 = LZERO; + dto_cookie.as_ptr = (DAT_PVOID) (uintptr_t) DT_Bpool_GetBuffer ( bpool, 2); + DT_Mdep_debug (("%s: Sent Command - awaiting completion\n", module)); + if (!DT_dto_event_wait (reqt_evd_hdl, &dto_stat) || + !DT_dto_check ( &dto_stat, + ep_handle, + DT_Bpool_GetBuffSize (bpool, 2), + dto_cookie, + "Client_Cmd_Send")) + { + goto client_exit; + } + + /************************************************************************/ + dto_cookie.as_64 = LZERO; + dto_cookie.as_ptr = (DAT_PVOID) (uintptr_t) DT_Bpool_GetBuffer ( bpool, 0); + DT_Mdep_debug (("%s: Waiting for Server_Info\n", module)); + if (!DT_dto_event_wait (recv_evd_hdl, &dto_stat) || + !DT_dto_check ( &dto_stat, + ep_handle, + DT_Bpool_GetBuffSize (bpool, 0), + dto_cookie, + "Server_Info_Recv")) + { + goto client_exit; + } + + DT_Mdep_debug (("%s: Server_Info Received\n", module)); + sinfo = (Server_Info_t*) DT_Bpool_GetBuffer (bpool, 0); + DT_Server_Info_Endian (sinfo); + memcpy ( (void *) (uintptr_t)&pt_ptr->Server_Info, + (const void *)sinfo, + sizeof (Server_Info_t)); + + /* Perform obligatory version check */ + if (pt_ptr->Server_Info.dapltest_version != DAPLTEST_VERSION) + { + DT_Mdep_printf ("%s: DAPLTEST VERSION MISMATCH: Server %d, Client %d\n", + module, + pt_ptr->Server_Info.dapltest_version, + DAPLTEST_VERSION); + goto client_exit; + } + DT_Mdep_debug (("%s: Version OK!\n", module)); + + /* Dump out what we know, if requested */ + if (DT_dapltest_debug) + { + DT_Server_Info_Print (&pt_ptr->Server_Info); + DT_Client_Info_Print (&pt_ptr->Client_Info); + } + + /* Onward to running the actual test requested */ + switch (pt_ptr->Client_Info.test_type) + { + case TRANSACTION_TEST: + { + if (Transaction_Cmd->debug) + { + DT_Transaction_Cmd_Print (Transaction_Cmd); + } + DT_Transaction_Test_Client (pt_ptr, + ia_handle, + remote_netaddr); + break; + } + case PERFORMANCE_TEST: + { + if (Performance_Cmd->debug) + { + DT_Performance_Cmd_Print (Performance_Cmd); + } + DT_Performance_Test_Client (pt_ptr, + ia_handle, + remote_netaddr); + break; + } + case QUIT_TEST: + { + DT_Quit_Cmd_Print (Quit_Cmd); + break; + } + } + + /********************************************************************* + * Done - clean up and go home + */ +client_exit: + DT_Mdep_debug (("%s: Cleaning Up ...\n", module)); + + /* Disconnect the EP */ + if (ep_handle) + { + /* + * graceful attempt might fail because we got here due to + * some error above, so we may as well try harder. + */ + ret = dat_ep_disconnect (ep_handle, DAT_CLOSE_ABRUPT_FLAG); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_ep_disconnect (abrupt) error: %s\n", + module, + DT_RetToString (ret)); + } + else if (did_connect && + !DT_disco_event_wait (conn_evd_hdl, NULL)) + { + DT_Mdep_printf ("%s: bad disconnect event\n", module); + } + } + + /* Free the bpool (if any) */ + DT_Bpool_Destroy (pt_ptr, bpool); + + /* Free the EP */ + if (ep_handle) + { + DAT_EVENT event; + /* + * Drain off outstanding DTOs that may have been + * generated by racing disconnects + */ + do + { + ret = dat_evd_dequeue ( recv_evd_hdl, + &event); + } while ( DAT_GET_TYPE(ret) != DAT_QUEUE_EMPTY ); + + ret = dat_ep_free (ep_handle); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_ep_free error: %s\n", + module, DT_RetToString (ret)); + /* keep going */ + } + } + + /* Free the 3 EVDs */ + if (conn_evd_hdl) + { + ret = dat_evd_free (conn_evd_hdl); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_evd_free (conn) error: %s\n", + module, DT_RetToString (ret)); + /* keep going */ + } + } + if (reqt_evd_hdl) + { + ret = dat_evd_free (reqt_evd_hdl); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_evd_free (reqt) error: %s\n", + module, DT_RetToString (ret)); + /* keep going */ + } + } + if (recv_evd_hdl) + { + ret = dat_evd_free (recv_evd_hdl); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_evd_free (recv) error: %s\n", + module, DT_RetToString (ret)); + /* keep going */ + } + } + + /* Free the PZ */ + if (pz_handle) + { + ret = dat_pz_free (pz_handle); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_pz_free error: %s\n", + module, DT_RetToString (ret)); + /* keep going */ + } + } + + /* Close the IA */ + if (ia_handle) + { + /* DT_ia_close cleans up async evd handle, too */ + ret = DT_ia_close (ia_handle, DAT_CLOSE_GRACEFUL_FLAG); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: DT_ia_close (graceful) error: %s\n", + module, DT_RetToString (ret)); + ret = DT_ia_close (ia_handle, DAT_CLOSE_ABRUPT_FLAG); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: DT_ia_close (abrupt) error: %s\n", + module, DT_RetToString (ret)); + } + /* keep going */ + } + else + { + DT_Mdep_debug (("%s: IA %s closed\n", module, dapl_name)); + } + } + + /* Free the Server's address */ + if (remote_netaddr) + { + DT_NetAddrFree (pt_ptr, remote_netaddr); + } + + /* Free the Per_Test_Data */ + DT_Mdep_LockDestroy (&pt_ptr->Thread_counter_lock); + DT_PrintMemList (pt_ptr); /* check if we return all space allocated */ + DT_Mdep_LockDestroy (&pt_ptr->MemListLock); + DT_Free_Per_Test_Data (pt_ptr); + + DT_Mdep_printf ("%s: ========== End of Work -- Client Exiting\n", module); +} diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_client_info.c b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_client_info.c new file mode 100644 index 00000000..1e346b3a --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_client_info.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_client_info.h" +#include "dapl_proto.h" +#include "dapl_test_data.h" + +void +DT_Client_Info_Endian (Client_Info_t * client_info) +{ + client_info->dapltest_version = DT_Endian32 (client_info->dapltest_version); + client_info->is_little_endian = DT_Endian32 (client_info->is_little_endian); + client_info->test_type = DT_Endian32 (client_info->test_type); + client_info->total_threads = DT_Endian32 (client_info->total_threads); +} + + +void +DT_Client_Info_Print (Client_Info_t * client_info) +{ + DT_Mdep_printf ("-------------------------------------\n"); + DT_Mdep_printf ("Client_Info.dapltest_version : %d\n", + client_info->dapltest_version); + DT_Mdep_printf ("Client_Info.is_little_endian : %d\n", + client_info->is_little_endian); + DT_Mdep_printf ("Client_Info.test_type : %d\n", + client_info->test_type); +} diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_client_info.h b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_client_info.h new file mode 100644 index 00000000..3a3b20c6 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_client_info.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#ifndef __DAPL_CLIENT_INFO_H__ +#define __DAPL_CLIENT_INFO_H__ + +#include "dapl_mdep.h" +#include + +#pragma pack(1) + +typedef struct +{ + DAT_UINT32 dapltest_version; + DAT_UINT32 is_little_endian; + DAT_UINT32 test_type; + DAT_UINT32 total_threads; +} Client_Info_t; +#pragma pack() + +#endif diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_cnxn.c b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_cnxn.c new file mode 100644 index 00000000..d653150c --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_cnxn.c @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_mdep.h" +#include "dapl_memlist.h" +#include "dapl_proto.h" +#include "dapl_cnxn.h" + + +/****************************************************************************/ +int +get_ep_connection_state (DAT_EP_HANDLE ep_handle) +{ + DAT_EP_STATE ep_state; + DAT_BOOLEAN in_dto_idle; + DAT_BOOLEAN out_dto_idle; + DAT_RETURN ret; + char *recv_status = "Idle"; + char *req_status = "Idle"; + ret = dat_ep_get_status (ep_handle, &ep_state, &in_dto_idle, + &out_dto_idle); + if (ret != 0) + { + DT_Mdep_printf ("DAT_ERROR: Can't get Connection State %s\n", + DT_RetToString (ret)); + } + else + { + if (in_dto_idle == 0) + { + recv_status = "Active"; + } + if (out_dto_idle == 0) + { + req_status = "Active"; + } + + DT_Mdep_printf ("DAT_STATE: %s\n", DT_State2Str (ep_state)); + DT_Mdep_printf ("DAT_STATE: Inbound DTO Status: %s \n", recv_status); + DT_Mdep_printf ("DAT_STATE: Outbound DTO Status: %s\n", req_status); + } + + return 0; +} + diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_cnxn.h b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_cnxn.h new file mode 100644 index 00000000..97548bae --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_cnxn.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#ifndef __DAPL_CNXN_H__ +#define __DAPL_CNXN_H__ + +#include "dapl_bpool.h" +#include "dapl_mdep.h" + +#define MAXHOSTNAMELEN 256 + +#endif diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_common.h b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_common.h new file mode 100644 index 00000000..7216067f --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_common.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#ifndef __DAPL_COMMON_H__ +#define __DAPL_COMMON_H__ + +#include + +typedef enum +{ + RDMA_READ, + RDMA_WRITE, + SEND_RECV +} DT_Transfer_Type; + + +typedef struct +{ + DAT_RMR_CONTEXT rmr_context; + DAT_CONTEXT mem_address; +} RemoteMemoryInfo; + + +#endif /* __DAPL_COMMON_H__ */ diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_endian.c b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_endian.c new file mode 100644 index 00000000..d1ab3fac --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_endian.c @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" + +void +DT_Endian_Init (void) +{ + int endian; + endian = 1; + DT_local_is_little_endian = * ((unsigned char *) (&endian)) == 1; +} + +/* + * Big/Little Endian conversion functions + */ + +#define c1a32 ((DAT_UINT32)0x00FF00FF) +#define c1b32 ((DAT_UINT32)0xFF00FF00) +#define c2a32 ((DAT_UINT32)0x0000FFFF) +#define c2b32 ((DAT_UINT32)0xFFFF0000) +#define c164 ((DAT_UINT64)0x00FF00FF) +#define c1a64 (c164 | (c164 << 32)) +#define c1b64 (c1a64 << 8) +#define c264 ((DAT_UINT64)0x0000FFFF) +#define c2a64 (c264 | (c264 << 32)) +#define c2b64 (c2a64 << 16) +#define c3a64 ((DAT_UINT64)0xFFFFFFFF) +#define c3b64 (c3a64 << 32) + +DAT_UINT32 +DT_Endian32 (DAT_UINT32 val) +{ + if (DT_local_is_little_endian) + { + return val; + } + val = ((val & c1a32) << 8) | ((val & c1b32) >> 8); + val = ((val & c2a32) << 16) | ((val & c2b32) >> 16); + return (val); +} + +DAT_UINT64 +DT_Endian64 (DAT_UINT64 val) +{ + if (DT_local_is_little_endian) + { + return val; + } + val = ((val & c1a64) << 8) | ((val & c1b64) >> 8); + val = ((val & c2a64) << 16) | ((val & c2b64) >> 16); + val = ((val & c3a64) << 32) | ((val & c3b64) >> 32); + return (val); +} + +DAT_UINT32 +DT_EndianMemHandle (DAT_UINT32 val) +{ + val = ((val & c1a32) << 8) | ((val & c1b32) >> 8); + val = ((val & c2a32) << 16) | ((val & c2b32) >> 16); + return (val); +} + +DAT_UINT64 +DT_EndianMemAddress (DAT_UINT64 val) +{ + DAT_UINT64 val64; + val64 = val; + val64 = ((val64 & c1a64) << 8) | ((val64 & c1b64) >> 8); + val64 = ((val64 & c2a64) << 16) | ((val64 & c2b64) >> 16); + val64 = ((val64 & c3a64) << 32) | ((val64 & c3b64) >> 32); + return val64; +} diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_fft_cmd.c b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_fft_cmd.c new file mode 100644 index 00000000..96fae75a --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_fft_cmd.c @@ -0,0 +1,356 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_test_data.h" +#include "dapl_mdep.h" +#include "dapl_proto.h" +#include "dapl_fft_cmd.h" + +//--------------------------------------------------------------------------- +void DT_FFT_Cmd_Init (FFT_Cmd_t *cmd) +{ + int i; + memset ((void *)cmd, 0, sizeof (FFT_Cmd_t)); + cmd->fft_type = NONE; + cmd->device_name[0] = '\0'; + cmd->server_name[0] = '\0'; + for (i=0; icases_flag[i] = false; + } + cmd->size = 0; + cmd->num_iter = 1000; + cmd->num_threads = 10; + cmd->num_vis = 500; + cmd->ReliabilityLevel = DAT_QOS_BEST_EFFORT; +} + +//------------------------------------------------------------------------------ +bool DT_FFT_Cmd_Parse (FFT_Cmd_t *cmd, + int my_argc, + char ** my_argv, + mygetopt_t *opts) +{ + char c; + int i, caseNum; + unsigned int len; + + for (;;) + { + c = DT_mygetopt_r (my_argc, my_argv, "D:f:s:i:t:v:R:", opts); + if (c == EOF) + { + break; + } + switch (c) + { + case 'D': //device name + { + strcpy (cmd->device_name, opts->optarg); + break; + } + case 's': //server name + { + strcpy (cmd->server_name, opts->optarg); + break; + } + case 'i': // num iterations + { + len = (unsigned int)strspn (opts->optarg, "0123456789"); + if (len == 0 || len != strlen (opts->optarg)) + { + DT_Mdep_printf ("Syntax Error -i option\n"); + DT_FFT_Cmd_Usage (); + return (false); + } + cmd->num_iter = atoi (opts->optarg); + break; + } + case 't': // num threads + { + len = (unsigned int)strspn (opts->optarg, "0123456789"); + if (len == 0 || len != strlen (opts->optarg)) + { + DT_Mdep_printf ("Syntax Error -t option\n"); + DT_FFT_Cmd_Usage (); + return (false); + } + cmd->num_threads = atoi (opts->optarg); + break; + } + case 'v': // num vis + { + len = (unsigned int)strspn (opts->optarg, "0123456789"); + if (len == 0 || len != strlen (opts->optarg)) + { + DT_Mdep_printf ("Syntax Error -v option\n"); + DT_FFT_Cmd_Usage (); + return (false); + } + cmd->num_vis = atoi (opts->optarg); + break; + } + case 'f': //function feature + { + if (strcmp (opts->optarg, "hwconn")==0) + { + cmd->fft_type = HWCONN; + cmd->size = 4; //4 cases for hwconn + break; + } + else if (strcmp (opts->optarg, "cqmgt")==0) + { + cmd->fft_type = CQMGT; + cmd->size = 10; //10 cases for cqmgt + break; + } + else if (strcmp (opts->optarg, "endpoint")==0) + { + cmd->fft_type = ENDPOINT; + cmd->size = 3; //13 cases for endpoint + break; + } + else if (strcmp (opts->optarg, "pz")==0) + { + cmd->fft_type = PTAGMGT; + cmd->size = 3; //10 cases for Ptagmgt + break; + } + else if (strcmp (opts->optarg, "mem")==0) + { + cmd->fft_type = MEMMGT; + cmd->size = 5; //12 cases for Memmgt + break; + } + else if (strcmp (opts->optarg, "connmgt")==0) + { + cmd->fft_type = CONNMGT; + cmd->size = 2; //16 cases for connmgt + break; + } + else if (strcmp (opts->optarg, "connmgt_client")==0) + { + cmd->fft_type = CONNMGT_CLIENT; + cmd->size = 16; //16 cases for connmgt_client + break; + } + else if (strcmp (opts->optarg, "dataxfer")==0) + { + cmd->fft_type = DATAXFER; + cmd->size = 4; //21 cases for dataxfer + break; + } + else if (strcmp (opts->optarg, "dataxfer_client")==0) + { + cmd->fft_type = DATAXFER_CLIENT; + cmd->size = 1; //21 cases for dataxfer_client + break; + } + else if (strcmp (opts->optarg, "queryinfo")==0) + { + cmd->fft_type = QUERYINFO; + cmd->size = 18; //18 cases for queryinfo + break; + } + else if (strcmp (opts->optarg, "ns")==0) + { + cmd->fft_type = NS; + cmd->size = 10; //10 cases for ns + break; + } + else if (strcmp (opts->optarg, "errhand")==0) + { + cmd->fft_type = ERRHAND; + cmd->size = 2; //2 cases for errhand + break; + } + else if (strcmp (opts->optarg, "unsupp")==0) + { + cmd->fft_type = UNSUPP; + cmd->size = 2; //2 cases for unsupp + break; + } + else if (strcmp (opts->optarg, "stress")==0) + { + cmd->fft_type = STRESS; + cmd->size = 6; //6 cases for stress + break; + } + else if (strcmp (opts->optarg, "stress_client")==0) + { + cmd->fft_type = STRESS_CLIENT; + cmd->size = 6; //6 cases for stress_client + break; + } + else + { + DT_Mdep_printf ("don't know this function feature: %s\n", + opts->optarg); + DT_FFT_Cmd_Usage (); + return (false); + } + } + case 'R': // Service Reliability Level + { + cmd->ReliabilityLevel = DT_ParseQoS (opts->optarg); + if (0 == cmd->ReliabilityLevel) + { + DT_Mdep_printf ("Invalid FFT Test Parameter: %c\n", c); + DT_FFT_Cmd_Usage (); + return (false); + } + break; + } + + case '?': + default: + { + DT_Mdep_printf ("Invalid FFT Test Parameter: %c\n", c); + DT_FFT_Cmd_Usage (); + return (false); + } + } + } + if (cmd->device_name[0] == '\0') + { + if (!DT_Mdep_GetDefaultDeviceName (cmd->device_name)) + { + DT_Mdep_printf ("can't get default device name\n"); + DT_FFT_Cmd_Usage (); + return (false); + } + } + + if (cmd->fft_type ==NONE) + { + DT_Mdep_printf ("must define the function feature with -f to test\n"); + DT_FFT_Cmd_Usage (); + return (false); + } + if (cmd->server_name[0] =='\0' && + (cmd->fft_type==CONNMGT_CLIENT || cmd->fft_type == DATAXFER_CLIENT || + cmd->fft_type == UNSUPP || cmd->fft_type == STRESS_CLIENT)) + { + DT_Mdep_printf ("must define the server name with -s option\n"); + DT_FFT_Cmd_Usage (); + return (false); + } + + if (cmd->server_name[0] =='\0' && cmd->fft_type==NS ) + { + DT_Mdep_printf ("\ + Must specify host name or host IP address with -s option to be tested\n"); + DT_FFT_Cmd_Usage (); + return (false); + } + + //now parse the test cases + if (opts->optind == my_argc) //default: test all cases + { + for (i=0; isize; i++) + { + cmd->cases_flag[i] = true; + } + return true; + } + + //test specified cases + i = opts->optind; + while (i=cmd->size) + { + DT_Mdep_printf ("test case number must be within range : 0 -- %d\n", + cmd->size-1); + DT_FFT_Cmd_Usage (); + return (false); + } + cmd->cases_flag[caseNum] = true; + i++; + } + return (true); +} + +//-------------------------------------------------------------- +void DT_FFT_Cmd_Usage (void) +{ + char usage[] = + { + "dapltest -T F [-D ] -f [-i ] \n" + "[-t ] [-v ] [-s ] [case0] [case1] [...]\n" + "USAGE: [-D ]\n" + "USAGE: (Linux: JniIbdd0)\n" + "USAGE: -f \n" + "USAGE: hwconn\n" + "USAGE: endpoint\n" + "USAGE: pz\n" + "USAGE: mem\n" + "USAGE: dataxfer\n" + "USAGE: dataxfer_client\n" + "USAGE: connmgt\n" + "USAGE: connmgt_client (not yet implemented)\n" + "USAGE: cqmgt (not yet implemented)\n" + "USAGE: queryinfo\n" + "USAGE: ns (not yet implemented)\n" + "USAGE: errhand (not yet implemented)\n" + "USAGE: unsupp (not yet implemented)\n" + "USAGE: stress (not yet implemented)\n" + "USAGE: stress_client (not yet implemented)\n" + "USAGE: -i : itreration time for stress test\n" + "USAGE: -t : number of threads for stress test\n" + "USAGE: -v : number of vis for stress test\n" + "USAGE: -s \n" + "USAGE: server host name or ip address\n" + "USAGE: [-R ]\n" + "USAGE: (BE == QOS_BEST_EFFORT - Default )\n" + "USAGE: (HT == QOS_HIGH_THROUGHPUT))\n" + "USAGE: (LL == QOS_LOW_LATENCY)\n" + "USAGE: (EC == QOS_ECONOMY)\n" + "USAGE: (PM == QOS_PREMIUM)\n" + "NOTE: iter_num is just for stress_client test, default 100000\n" + "NOTE: Server_name must be specified for connmgt_client, dataxfer_client, \n" + " NS and unsupp function feature.\n" + "NOTE: if test cases are not specified, test all cases in that function\n" + " feature. else just test the specified cases\n" + }; + + DT_Mdep_printf ("USAGE: -------FFT TEST------------\n"); + DT_Mdep_printf ("%s\n", usage); +} diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_fft_cmd.h b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_fft_cmd.h new file mode 100644 index 00000000..45e24c6f --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_fft_cmd.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#ifndef __DAPL_FFT_CMD_H__ +#define __DAPL_FFT_CMD_H__ + +#include "dapl_mdep.h" + +#define MAXCASES 100 + +typedef enum +{ + NONE, + HWCONN, + CQMGT, + ENDPOINT, + PTAGMGT, + MEMMGT, + CONNMGT, + CONNMGT_CLIENT, + DATAXFER, + DATAXFER_CLIENT, + QUERYINFO, + NS, + ERRHAND, + UNSUPP, + STRESS, + STRESS_CLIENT, +} FFT_Type_e; + + +typedef struct +{ + FFT_Type_e fft_type; + char device_name[256]; //-D + char server_name[256]; + bool cases_flag[MAXCASES]; + int size; + int num_iter; //-i + int num_threads; //-t + int num_vis; //-v + DAT_QOS ReliabilityLevel; //-R +} FFT_Cmd_t; + +typedef struct +{ + int (*fun) ( FFT_Cmd_t*); +} FFT_Testfunc_t; + +#endif diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_fft_connmgt.c b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_fft_connmgt.c new file mode 100644 index 00000000..0c5bb378 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_fft_connmgt.c @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" +#include "dapl_fft_util.h" + +int DT_connmgt_case0 (FFT_Cmd_t *cmd) +{ + FFT_Connection_t conn; + int res = 1; + DAT_RETURN rc = 0; + + DT_Mdep_printf ("\ + Description: Ensure time in dat_evd_wait works correctly\n"); + + DT_fft_init_server (cmd, &conn); + DT_assert (NULL != conn.ia_handle); + + rc = dat_evd_wait (conn.cr_evd, 10*1000000, 1, &conn.event, + &conn.count); + DT_assert_dat (DAT_GET_TYPE(rc) == DAT_TIMEOUT_EXPIRED); + +cleanup: + rc = DT_fft_destroy_conn_struct (&conn); + DT_assert_clean (rc == DAT_SUCCESS); + + return res; +} + +int DT_connmgt_case1 (FFT_Cmd_t *cmd) +{ + FFT_Connection_t conn; + int res = 1; + DAT_RETURN rc; + + DT_Mdep_printf ("\ + Description: Attempt to use timeout of 0 in dat_evd_wait\n"); + + DT_fft_init_server (cmd, &conn); + DT_assert (NULL != conn.ia_handle); + + rc = dat_evd_wait (conn.cr_evd, 0, 1, &conn.event, &conn.count); + DT_assert_dat (DAT_GET_TYPE(rc) == DAT_TIMEOUT_EXPIRED); + +cleanup: + rc = DT_fft_destroy_conn_struct (&conn); + DT_assert_clean (rc == DAT_SUCCESS); + return res; + +} + + +void DT_connmgt_test (FFT_Cmd_t *cmd) +{ + int i; + int res; + FFT_Testfunc_t cases_func[] = + { + { DT_connmgt_case0 }, + { DT_connmgt_case1 }, + }; + + for (i = 0; i < cmd->size; i++) + { + if (cmd->cases_flag[i]) + { + if (cmd->cases_flag[i]) + { + + DT_Mdep_printf ("\ + *********************************************************************\n"); + DT_Mdep_printf ("\ + Function feature: Connect Management (Server side) case: %d\n", i); + res = cases_func[i].fun (cmd); + if (res==1) + { + DT_Mdep_printf ("Result: PASS\n"); + } + else if (res ==0) + { + DT_Mdep_printf ("Result: FAIL\n"); + } + else if (res ==-1) + { + DT_Mdep_printf ("Result: use other test tool\n"); + } + else if (res ==-2) + { + DT_Mdep_printf ("Result: not support or next stage to develop\n"); + } + + DT_Mdep_printf ("\ + *********************************************************************\n"); + } + } + } +} diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_fft_dataxfer.c b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_fft_dataxfer.c new file mode 100644 index 00000000..14786994 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_fft_dataxfer.c @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" +#include "dapl_fft_util.h" + +/*--------------------------------------------------------*/ +int DT_dataxfer_generic ( FFT_Cmd_t *cmd, int test_case) +{ + FFT_Connection_t conn; + DAT_RETURN rc=0; + int res=1; + DT_fft_init_server (cmd, &conn); + DT_assert (NULL != conn.ia_handle); + + DT_fft_listen (&conn); + + switch (test_case) + { + case 0: + { + DT_Mdep_printf ("Posting null send buffer\n"); + rc = DT_post_send_buffer (0, conn.bpool, 0, + DT_Bpool_GetBuffSize (conn.bpool, 0)); + DT_assert_dat (DAT_GET_TYPE(rc) == DAT_INVALID_HANDLE); + break; + } + case 1: + { + DT_Mdep_printf ("Call evd wait with null evd\n"); + rc =dat_evd_wait (0, DAT_TIMEOUT_INFINITE, 1, &conn.event, + &conn.count); + DT_assert_dat (DAT_GET_TYPE(rc) == DAT_INVALID_HANDLE); + break; + } + case 2: + { + DT_Mdep_printf ("Call evd wait with empty send queue\n"); + rc =dat_evd_wait (conn.send_evd, 10*1000000, 1, &conn.event, + &conn.count); + DT_assert_dat (DAT_GET_TYPE(rc) == DAT_TIMEOUT_EXPIRED); + break; + } + case 3: + { + DT_Mdep_printf ("Posting null recv buffer\n"); + rc =DT_post_recv_buffer (0, conn.bpool, 0, + DT_Bpool_GetBuffSize (conn.bpool, 0)); + DT_assert_dat (DAT_GET_TYPE(rc) == DAT_INVALID_HANDLE); + break; + } + } +cleanup: + DT_assert_clean (DT_fft_destroy_conn_struct (&conn)); + return res; +} + +int DT_dataxfer_case0 ( FFT_Cmd_t *cmd) +{ + DT_Mdep_printf ("\ + Description: Call dat_ep_post_send with null ep_handle.\n"); + return DT_dataxfer_generic (cmd, 0); +} + +int DT_dataxfer_case1 ( FFT_Cmd_t *cmd) +{ + DT_Mdep_printf ("\ + Description: Call dat_evd_wait with null evd.\n"); + return DT_dataxfer_generic (cmd, 1); +} + +int DT_dataxfer_case2 ( FFT_Cmd_t *cmd) +{ + DT_Mdep_printf ("\ + Description: Call dat_evd_wait with null evd.\n"); + return DT_dataxfer_generic (cmd, 2); +} + +int DT_dataxfer_case3 ( FFT_Cmd_t *cmd) +{ + DT_Mdep_printf ("\ + Description: Call dat_evd_wait with null evd.\n"); + return DT_dataxfer_generic (cmd, 3); +} + +/*-------------------------------------------------------------*/ +void DT_dataxfer_test (FFT_Cmd_t *cmd) +{ + int i; + int res; + FFT_Testfunc_t cases_func[] = + { + { DT_dataxfer_case0 }, + { DT_dataxfer_case1 }, + { DT_dataxfer_case2 }, + { DT_dataxfer_case3 }, + }; + + for (i=0; isize; i++) + { + if (cmd->cases_flag[i]) + { + DT_Mdep_printf ("\ + *********************************************************************\n"); + DT_Mdep_printf ("\ + Function feature: Protection Zone management case: %d\n", i); + res = cases_func[i].fun (cmd); + if (res==1) + { + DT_Mdep_printf ("Result: PASS\n"); + } + else if (res ==0) + { + DT_Mdep_printf ("Result: FAIL\n"); + } + else if (res ==-1) + { + DT_Mdep_printf ("Result: use other test tool\n"); + } + else if (res ==-2) + { + DT_Mdep_printf ("Result: not support or next stage to develop\n"); + } + + DT_Mdep_printf ("\ + *********************************************************************\n"); + } + } + return; +} diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_fft_dataxfer_client.c b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_fft_dataxfer_client.c new file mode 100644 index 00000000..b37cd6ef --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_fft_dataxfer_client.c @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" +#include "dapl_fft_util.h" + +#define CONN_STATE 1 +#define TIMEOUT_TEST 2 +#define DATAXFER_TEST 3 + +int DT_dataxfer_client_generic (FFT_Cmd_t *cmd, int flag) +{ + int res=1; + FFT_Connection_t conn; + DAT_RETURN rc=0; + + DT_fft_init_client (cmd, &conn); + DT_assert_dat(conn.ia_handle != NULL) + + DT_assert (DT_fft_connect (&conn)); + + if (flag == CONN_STATE) + { + res = 1; + goto cleanup; + } + else if (flag == TIMEOUT_TEST) + { + + + } + else if (flag == DATAXFER_TEST) + { + conn.bpool = DT_BpoolAlloc (0, conn.ia_handle, conn.pz_handle, NULL, + NULL, 4096, 2, DAT_OPTIMAL_ALIGNMENT, false, false); + DT_assert (conn.bpool != 0); + rc = DT_post_send_buffer (conn.ep_handle, conn.bpool, 0, + DT_Bpool_GetBuffSize (conn.bpool, 0)); + DT_assert_dat (rc == DAT_SUCCESS); + rc = dat_evd_wait (conn.send_evd, 10*1000000, 1, &conn.event, + &conn.count); + DT_assert_dat (rc == DAT_SUCCESS); + res = 1; + goto cleanup; + } + // cleanup +cleanup: + + if (conn.ep_handle) + { + // disconnect + DT_Mdep_printf ("Disconnect\n"); + rc = dat_ep_disconnect (conn.ep_handle, DAT_CLOSE_ABRUPT_FLAG); + DT_assert_clean (rc == DAT_SUCCESS); + } + rc = DT_fft_destroy_conn_struct (&conn); + DT_assert_clean (rc == DAT_SUCCESS); + + return res; +} + +int DT_dataxfer_client_case0 (FFT_Cmd_t *cmd) +{ + DT_Mdep_printf ("\ + Description: This is a helper case on the client side for dataxfer case0.\n"); + return DT_dataxfer_client_generic (cmd, CONN_STATE); +} + +void DT_dataxfer_client_test (FFT_Cmd_t *cmd) +{ + int i; + int res; + FFT_Testfunc_t cases_func[] = + { + { DT_dataxfer_client_case0 }, + }; + + for (i=0; isize; i++) + { + if (cmd->cases_flag[i]) + { + DT_Mdep_printf ("\ + *********************************************************************\n"); + DT_Mdep_printf ("\ + Function feature: Dataxfer client case: %d\n", i); + res = cases_func[i].fun (cmd); + if (res==1) + { + DT_Mdep_printf ("Result: PASS\n"); + } + else if (res ==0) + { + DT_Mdep_printf ("Result: FAIL\n"); + } + else if (res ==-1) + { + + DT_Mdep_printf ("Result: use other test tool\n"); + } + else if (res ==-2) + { + DT_Mdep_printf ("Result: not support or next stage to develop\n"); + } + + DT_Mdep_printf ("\ + *********************************************************************\n"); + } + } + return; +} diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_fft_endpoint.c b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_fft_endpoint.c new file mode 100644 index 00000000..4fc9427a --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_fft_endpoint.c @@ -0,0 +1,281 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" +#include "dapl_fft_util.h" + +#define CQENTRYCOUNT 100 +#define BUFFSIZE 1024 +#define DEFAULT_QUEUE_LEN 10 + +int DT_endpoint_generic (FFT_Cmd_t *cmd, + bool destroy_pz_early) +{ + char *dev_name; + DAT_IA_HANDLE ia_handle; + DAT_PZ_HANDLE pz_handle; + DAT_EP_HANDLE ep_handle; + DAT_EVD_HANDLE evd_handle; + DAT_EVD_HANDLE conn_evd_handle; + DAT_EVD_HANDLE send_evd_handle; + DAT_EVD_HANDLE recv_evd_handle; + DAT_RETURN rc, wanted; + int res; + + res = 1; + ia_handle = NULL; + pz_handle = NULL; + ep_handle = NULL; + evd_handle = NULL; + conn_evd_handle = NULL; + send_evd_handle = NULL; + recv_evd_handle = NULL; + dev_name = cmd->device_name; + evd_handle = DAT_HANDLE_NULL; + +#ifdef DYNAMIC_DAT_LOADING + rc = dat_open ((const DAT_NAME_PTR)dev_name, + DEFAULT_QUEUE_LEN, &evd_handle, &ia_handle, + DAT_VERSION_MAJOR, + DAT_VERSION_MINOR, + DAT_THREADSAFE); +#else + rc = dat_ia_open ((const DAT_NAME_PTR)dev_name, + DEFAULT_QUEUE_LEN, &evd_handle, &ia_handle); +#endif //DYNAMIC_DAT_LOADING + DT_assert_dat (rc == DAT_SUCCESS); + + rc = dat_pz_create (ia_handle, &pz_handle); + DT_assert_dat (rc == DAT_SUCCESS); + + if (destroy_pz_early) + { + if (pz_handle) + { + rc = dat_pz_free (pz_handle); + DT_assert_dat (rc == DAT_SUCCESS); + } + } + + rc = dat_evd_create (ia_handle, DEFAULT_QUEUE_LEN, NULL, + DAT_EVD_DTO_FLAG | DAT_EVD_RMR_BIND_FLAG, + &send_evd_handle); + DT_assert_dat (rc == DAT_SUCCESS); + + rc = dat_evd_create (ia_handle, DEFAULT_QUEUE_LEN, NULL, DAT_EVD_DTO_FLAG, + &recv_evd_handle); + DT_assert_dat (rc == DAT_SUCCESS); + + rc = dat_evd_create (ia_handle, DEFAULT_QUEUE_LEN, NULL, + DAT_EVD_CONNECTION_FLAG, &conn_evd_handle); + DT_assert_dat (rc == DAT_SUCCESS); + + rc = dat_ep_create (ia_handle, pz_handle, recv_evd_handle, send_evd_handle, + conn_evd_handle, NULL, &ep_handle); + if (destroy_pz_early) + { + wanted = DAT_INVALID_HANDLE; + } + else + { + wanted = DAT_SUCCESS; + } + DT_assert_dat (DAT_GET_TYPE(rc) == wanted); + +cleanup: + if (ep_handle) + { + rc = dat_ep_free (ep_handle); + DT_assert_clean (rc == DAT_SUCCESS); + } + + if (send_evd_handle) + { + rc = dat_evd_free (send_evd_handle); + DT_assert_clean (rc == DAT_SUCCESS); + } + + if (recv_evd_handle) + { + rc = dat_evd_free (recv_evd_handle); + DT_assert_clean (rc == DAT_SUCCESS); + } + + if (conn_evd_handle) + { + rc = dat_evd_free (conn_evd_handle); + DT_assert_clean (rc == DAT_SUCCESS); + } + + if (!destroy_pz_early && pz_handle) + { + rc = dat_pz_free (pz_handle); + DT_assert_clean (rc == DAT_SUCCESS); + } + + if (ia_handle) + { + rc = DT_ia_close (ia_handle, DAT_CLOSE_ABRUPT_FLAG); + DT_assert_clean (rc == DAT_SUCCESS); + } + return res; +} + +int DT_endpoint_case0 (FFT_Cmd_t *cmd) +{ + DT_Mdep_printf ("\ + Description: Test if we can normally create endpoint and destory it.\n"); + DT_Mdep_printf ("\ + The endpoint is not associated with a CQ\n"); + return DT_endpoint_generic (cmd, + false); /* destroy pz early */ +} + +int DT_endpoint_case1 (FFT_Cmd_t *cmd) +{ + DT_Mdep_printf ("\ + Description: try to create endpoint with pz already destroyed\n"); + return DT_endpoint_generic (cmd, + true); /* destroy pz early */ +} + +int DT_endpoint_case2 (FFT_Cmd_t *cmd) +{ + char *dev_name; + DAT_IA_HANDLE ia_handle; + DAT_EP_HANDLE ep_handle; + DAT_EVD_HANDLE send_evd, conn_evd, recv_evd, cr_evd; + DAT_PZ_HANDLE pz_handle; + DAT_EVENT event; + Bpool *bpool; + int res; + DAT_RETURN rc; + + DT_Mdep_printf ("\ + Description: try to destroy ep with descriptor still in working queue\n"); + res = 1; + bpool = 0; + pz_handle = 0; + ia_handle = 0; + ep_handle = 0; + send_evd = 0; + conn_evd = 0; + recv_evd = 0; + cr_evd = 0; + dev_name = cmd->device_name; + + rc = DT_ia_open (dev_name, &ia_handle); + DT_assert_dat (rc == DAT_SUCCESS); + rc = dat_pz_create (ia_handle, &pz_handle); + DT_assert_dat (rc == DAT_SUCCESS); + rc = DT_ep_create (ia_handle, pz_handle, &cr_evd, &conn_evd, &send_evd, + &recv_evd, &ep_handle); + DT_assert_dat (rc == DAT_SUCCESS); + bpool = DT_BpoolAlloc (0, ia_handle, pz_handle, NULL, NULL, 4096, 1, + DAT_OPTIMAL_ALIGNMENT, false, false); + DT_assert (bpool != 0); + DT_assert (DT_post_recv_buffer (ep_handle, bpool, 0, 4096) == true); + if (ep_handle) + { + rc = dat_ep_free (ep_handle); + DT_assert_dat (rc == DAT_SUCCESS); + } + + /* + * Remove all DTOs. The disconnect above may have + * flushed all posted operations, so this is just a + * clean up. + */ + do + { + rc = dat_evd_dequeue ( recv_evd, + &event); + } while ( DAT_GET_TYPE(rc) != DAT_QUEUE_EMPTY ); +cleanup: + if (bpool) + { + rc = DT_Bpool_Destroy (0, bpool); + DT_assert_clean (rc != false); + } + if (pz_handle) + { + rc = dat_pz_free (pz_handle); + DT_assert_clean (rc == DAT_SUCCESS); + } + if (ia_handle) + { + rc = DT_ia_close (ia_handle, DAT_CLOSE_ABRUPT_FLAG); + DT_assert_clean (rc == DAT_SUCCESS); + } + return res; + +} + +/*-------------------------------------------------------------*/ +void DT_endpoint_test (FFT_Cmd_t *cmd) +{ + int i; + int res; + FFT_Testfunc_t cases_func[] = + { + { DT_endpoint_case0 }, + { DT_endpoint_case1 }, + { DT_endpoint_case2 }, + }; + + for (i=0; isize; i++) + { + if (cmd->cases_flag[i]) + { + DT_Mdep_printf ("\ + *********************************************************************\n"); + DT_Mdep_printf ("\ + Function feature: EndPoint management case: %d\n", i + ); + res = cases_func[i].fun (cmd); + if (res==1) + { + DT_Mdep_printf ("Result: PASS\n"); + } + else if (res ==0) + { + DT_Mdep_printf ("Result: FAIL\n"); + } + else if (res ==-1) + { + DT_Mdep_printf ("Result: use other test tool\n"); + } + else if (res ==-2) + { + DT_Mdep_printf ("Result: not support or next stage to develop\n"); + } + + DT_Mdep_printf ("\ + *********************************************************************\n"); + } + } + return; +} diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_fft_hwconn.c b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_fft_hwconn.c new file mode 100644 index 00000000..6cd9e332 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_fft_hwconn.c @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" + + +/*--------------------------------------------------------*/ +int DT_hwconn_case0 ( FFT_Cmd_t *cmd) +{ + char* dev_name; + DAT_IA_HANDLE nic_handle; + DAT_EVD_HANDLE evd_handle; + DAT_RETURN rc; + int res = 1; + + DT_Mdep_printf ("\ + Description: Test if we can normally Open NIC and then close it\n"); + + dev_name= cmd->device_name; + nic_handle=0; + evd_handle = DAT_HANDLE_NULL; +#ifdef DYNAMIC_DAT_LOADING + rc=dat_open ((const DAT_NAME_PTR)dev_name, 10, &evd_handle, &nic_handle, + DAT_VERSION_MAJOR, + DAT_VERSION_MINOR, + DAT_THREADSAFE); +#else + rc=dat_ia_open ((const DAT_NAME_PTR)dev_name, 10, &evd_handle, &nic_handle); +#endif // DYNAMIC_DAT_LOADING + DT_assert_dat (rc == DAT_SUCCESS); + rc=DT_ia_close (nic_handle, DAT_CLOSE_ABRUPT_FLAG); + DT_assert_dat (rc == DAT_SUCCESS); +cleanup: + + return res; +} + +/*--------------------------------------------------------*/ +int DT_hwconn_case1 ( FFT_Cmd_t *cmd) +{ + DAT_IA_HANDLE nic_handle; + DAT_RETURN rc; + DAT_EVD_HANDLE evd_handle; + char dev_name[100]; + int i; + + DT_Mdep_printf ("Description: try to open NIC with incorrect device name\n"); + DT_Mdep_printf (" (just num, one letter, multiple letter, num_letter\n"); + DT_Mdep_printf ("letter_num). You alse can do this test manually\n"); + DT_Mdep_printf ("dapltest -T F -D -f hwconn \n"); + + for (i=0; i< 5; i++) + { + if (i==0) + { + sprintf (dev_name, "%s", "40"); /* just number */ + } + else if (i==1) + { + sprintf (dev_name, "%s", "x"); /* just letter */ + } + else if (i==2) + { + sprintf (dev_name, "%s", "xsdf"); /* multiple letter */ + } + else if (i==3) + { + sprintf (dev_name, "%s", "x34"); /* letter_number */ + } + else if (i==4) + { + sprintf (dev_name, "%s", "34df"); /* number_letter */ + } + + evd_handle = DAT_HANDLE_NULL; +#ifdef DYNAMIC_DAT_LOADING + rc=dat_open ((const DAT_NAME_PTR)dev_name, 10, &evd_handle, &nic_handle, + DAT_VERSION_MAJOR, + DAT_VERSION_MINOR, + DAT_THREADSAFE); +#else + rc=dat_ia_open ((const DAT_NAME_PTR)dev_name, 10, &evd_handle, &nic_handle); +#endif //DYNAMIC_DAT_LOADING + if (DAT_GET_TYPE(rc) != DAT_PROVIDER_NOT_FOUND) + { + //const char *major_msg, *minor_msg; + + DT_Mdep_printf (" \ + fff not get expected result when open NIC with device name: %s\n", dev_name); + //dat_strerror (rc, &major_msg, &minor_msg); + DT_Mdep_printf ("ERROR: %x \n",rc); + + + if (rc==DAT_SUCCESS) + { + rc = DT_ia_close (nic_handle, DAT_CLOSE_ABRUPT_FLAG); + + DT_assert_clean (rc == DAT_SUCCESS); + } + return 0; + } + } + return 1; +} + +/*--------------------------------------------------------*/ +int DT_hwconn_case2 ( FFT_Cmd_t *cmd) +{ + DAT_IA_HANDLE nic_handle; + DAT_RETURN rc; + int res=1; + + DT_Mdep_printf ("\ + Description: Try to close nic with Nic handle is null (NIC not open)\n"); + nic_handle=0; + rc=DT_ia_close (nic_handle, DAT_CLOSE_ABRUPT_FLAG); + DT_assert_dat (DAT_GET_TYPE(rc) ==DAT_INVALID_HANDLE); + +cleanup: + return res; +} + +/*--------------------------------------------------------*/ +int DT_hwconn_case3 ( FFT_Cmd_t *cmd) +{ + FFT_Connection_t conn; + DAT_RETURN rc; + int res; + + DT_Mdep_printf ("Description: Test if we can close NIC when the created \n"); + DT_Mdep_printf ("endpoint has not been destroyed.\n"); + DT_Mdep_printf ("The problem for this case is that once the hca is closed, \n"); + DT_Mdep_printf ("there is no way to destroy the endpoint's resources\n"); + DT_Mdep_printf ("thus the test leaks a small amount of memory\n"); + + res=1; + + DT_fft_init_client (cmd, &conn); + + /* try to close nic when vi have not destroyed */ + if (conn.ia_handle) + { + rc= DT_ia_close (conn.ia_handle, DAT_CLOSE_ABRUPT_FLAG); + if (rc !=DAT_SUCCESS) + { + DT_Mdep_printf ("Warning: DT_ia_close fails %s, reboot for cleanup\n", + DT_RetToString (rc)); + return 0; + } + } + /* if nic is closed, it is impossible to destory vi and ptag */ + //DT_fft_destroy_conn_struct(&conn); + return res; + +} + + +/*-------------------------------------------------------------*/ +void DT_hwconn_test (FFT_Cmd_t *cmd) +{ + int i; + int res; + FFT_Testfunc_t cases_func[] = + { + { DT_hwconn_case0 }, + { DT_hwconn_case1 }, + { DT_hwconn_case2 }, + { DT_hwconn_case3 }, + }; + + for (i=0; isize; i++) + { + if (cmd->cases_flag[i]) + { + DT_Mdep_printf ("\ + *********************************************************************\n"); + DT_Mdep_printf ("\ + Function feature: Hardware connection case: %d\n", i); + res = cases_func[i].fun (cmd); + if (res==1) + { + DT_Mdep_printf ("Result: PASS\n"); + } + else if (res ==0) + { + DT_Mdep_printf ("Result: FAIL\n"); + } + else if (res ==-1) + { + DT_Mdep_printf ("Result: use other test tool\n"); + } + else if (res ==-2) + { + DT_Mdep_printf ("Result: next stage to develop\n"); + } + + DT_Mdep_printf ("\ + *********************************************************************\n"); + } + } + return; +} diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_fft_mem.c b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_fft_mem.c new file mode 100644 index 00000000..fe263066 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_fft_mem.c @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" +#include "dapl_fft_util.h" +#include + +#define CQENTRYCOUNT 100 +#define BUFFSIZE 1024 + +/*--------------------------------------------------------*/ +int DT_mem_generic (FFT_Cmd_t *cmd, int flag) +{ + DAT_RETURN rc, expect; + FFT_Connection_t conn; + DAT_REGION_DESCRIPTION region; + DAT_VLEN reg_size; + DAT_LMR_HANDLE lmr_handle; + DAT_LMR_CONTEXT lmr_context; + DAT_VADDR reg_addr; + unsigned char *alloc_ptr; + int res; + DAT_COUNT buffer_size; + DAT_IA_HANDLE ia_handle; + DAT_PZ_HANDLE pz_handle; + + rc = 0; + expect = 0; + res = 1; + lmr_handle = 0; + lmr_context = 0; + reg_addr = 0; + alloc_ptr = 0; + ia_handle = 0; + pz_handle = 0; + + DT_fft_init_client (cmd, &conn); + DT_assert (NULL != conn.ia_handle); + + if (flag == 2) + { + buffer_size = 0; + alloc_ptr = 0; + } + else + { + buffer_size = BUFFSIZE * sizeof (unsigned char); + alloc_ptr = (unsigned char *)DT_Mdep_Malloc (buffer_size); + DT_assert (alloc_ptr); + } + + + memset (®ion, 0, sizeof (region)); + region.for_va = alloc_ptr; + + ia_handle = conn.ia_handle; + + if (flag != 3) + { + pz_handle = conn.pz_handle; + } + + if (flag != 4) + { + DT_Mdep_printf ("Registering memory\n"); + rc = dat_lmr_create (ia_handle, + DAT_MEM_TYPE_VIRTUAL, + region, + buffer_size, + conn.pz_handle, + DAT_MEM_PRIV_ALL_FLAG, + &lmr_handle, + &lmr_context, + NULL, /* FIXME */ + ®_size, + ®_addr); + if (flag == 2) + { + expect = DAT_LENGTH_ERROR; + } + else + { + expect = DAT_SUCCESS; + } + DT_assert_dat (DAT_GET_TYPE(rc) == expect); + } + if (flag == 1) + { + if (lmr_handle) + { + rc = dat_lmr_free (lmr_handle); + DT_assert_dat (rc == DAT_SUCCESS); + } + lmr_handle = 0; + + rc = dat_lmr_create (conn.ia_handle, + DAT_MEM_TYPE_VIRTUAL, + region, + buffer_size, + conn.pz_handle, + DAT_MEM_PRIV_ALL_FLAG, + &lmr_handle, + &lmr_context, + NULL, /* FIXME */ + ®_size, + ®_addr); + DT_assert_dat (rc == DAT_SUCCESS); + } + +cleanup: + if (lmr_handle) + { + rc = dat_lmr_free (lmr_handle); + DT_assert_clean (rc == DAT_SUCCESS); + } + if (alloc_ptr) + { + DT_Mdep_Free (alloc_ptr); + } + rc = DT_fft_destroy_conn_struct (&conn); + DT_assert_clean (rc == DAT_SUCCESS); + + return res; + +} +int DT_mem_case0 ( FFT_Cmd_t *cmd) +{ + DT_Mdep_printf ("\ + Description: Test if we can register typical size of memory\n"); + DT_Mdep_printf ("\ + then deregister it.\n"); + return DT_mem_generic (cmd, 0); +} + +/*--------------------------------------------------------*/ +int DT_mem_case1 ( FFT_Cmd_t *cmd) +{ + DT_Mdep_printf ("\ + Description: Test if we can register typical size of memory\n"); + DT_Mdep_printf ("\ + deregister, then register it again.\n"); + return DT_mem_generic (cmd, 1); +} + +/*--------------------------------------------------------*/ +int DT_mem_case2 ( FFT_Cmd_t *cmd) +{ + DT_Mdep_printf ("\ + Description: Try to register memory with memory size 0\n"); + return DT_mem_generic (cmd, 2); +} + +/*--------------------------------------------------------*/ +int DT_mem_case3 ( FFT_Cmd_t *cmd) +{ + DT_Mdep_printf ("\ + Description: Try to register memory with null pz\n"); + return DT_mem_generic (cmd, 3); +} + +/*--------------------------------------------------------*/ +int DT_mem_case4 ( FFT_Cmd_t *cmd) +{ + DT_Mdep_printf ("\ + Description: Try to deregister memory with null lmr_handle\n"); + return DT_mem_generic (cmd, 4); +} + +/*-------------------------------------------------------------*/ +void DT_mem_test (FFT_Cmd_t *cmd) +{ + int i; + int res; + FFT_Testfunc_t cases_func[] = + { + { DT_mem_case0 }, + { DT_mem_case1 }, + { DT_mem_case2 }, + { DT_mem_case3 }, + { DT_mem_case4 }, + }; + + for (i=0; isize; i++) + { + if (cmd->cases_flag[i]) + { + DT_Mdep_printf ("\ + *********************************************************************\n"); + DT_Mdep_printf ("\ + Function feature: Memory register/deregister case: %d\n", i); + res = cases_func[i].fun (cmd); + if (res==1) + { + DT_Mdep_printf ("Result: PASS\n"); + } + else if (res ==0) + { + DT_Mdep_printf ("Result: FAIL\n"); + } + else if (res ==-1) + { + DT_Mdep_printf ("Result: use other test tool\n"); + } + else if (res ==-2) + { + DT_Mdep_printf ("Result: not support or next stage to develop\n"); + } + + DT_Mdep_printf ("\ + *********************************************************************\n"); + } + } + return; +} diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_fft_pz.c b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_fft_pz.c new file mode 100644 index 00000000..c7d48c6b --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_fft_pz.c @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" +#include "dapl_fft_cmd.h" +#include "dapl_fft_util.h" + +#define CQENTRYCOUNT 100 +#define BUFFSIZE 1024 + +/*--------------------------------------------------------*/ +int DT_pz_case0 ( FFT_Cmd_t *cmd) +{ + char* dev_name; + DAT_IA_HANDLE ia_handle; + DAT_PZ_HANDLE pz_handle; + DAT_EVD_HANDLE evd_handle; + DAT_RETURN rc; + int res; + + DT_Mdep_printf ("\ + Description: Test if we can normally create pz and destroy it.\n"); + + res=1; + ia_handle=0; + pz_handle =0; + evd_handle = DAT_HANDLE_NULL; + dev_name= cmd->device_name; + + rc = DT_ia_open (dev_name, &ia_handle); + DT_assert_dat (rc == DAT_SUCCESS); + rc = dat_pz_create (ia_handle, &pz_handle); + DT_assert_dat (rc == DAT_SUCCESS); + +cleanup: + if (pz_handle) + { + rc = dat_pz_free (pz_handle); + DT_assert_dat (rc == DAT_SUCCESS); + } + if (ia_handle) + { + rc = DT_ia_close (ia_handle, DAT_CLOSE_ABRUPT_FLAG); + DT_assert_dat (rc == DAT_SUCCESS); + } + return res; +} + +/*--------------------------------------------------------*/ +int DT_pz_case1 ( FFT_Cmd_t *cmd) +{ + char* dev_name; + DAT_IA_HANDLE ia_handle; + DAT_PZ_HANDLE pz_handle; + DAT_EP_HANDLE ep_handle; + DAT_EVD_HANDLE conn_evd, send_evd, recv_evd, cr_evd; + DAT_RETURN rc; + int res; + + DT_Mdep_printf ("\ + Description: try to destroy pz with vi still associated with it\n"); + + res=1; + ia_handle=0; + pz_handle =0; + ep_handle=0; + conn_evd = 0; + send_evd = 0; + recv_evd = 0; + cr_evd = 0; + dev_name= cmd->device_name; + + rc = DT_ia_open (dev_name, &ia_handle); + DT_assert_dat (rc == DAT_SUCCESS); + + rc = dat_pz_create (ia_handle, &pz_handle); + DT_assert_dat (rc == DAT_SUCCESS); + + rc = DT_ep_create (ia_handle, pz_handle, &cr_evd, &conn_evd, &send_evd, + &recv_evd, &ep_handle); + DT_assert_dat (rc == DAT_SUCCESS); + + if (pz_handle) + { + rc = dat_pz_free (pz_handle); + DT_assert_dat (DAT_GET_TYPE(rc) == DAT_INVALID_STATE); + } + +cleanup: + /* corrrect order */ + if (ep_handle) + { + rc=dat_ep_free (ep_handle); + DT_assert_clean (rc == DAT_SUCCESS); + } + if (conn_evd) + { + rc = dat_evd_free (conn_evd); + DT_assert_clean (rc == DAT_SUCCESS); + } + if (send_evd) + { + rc = dat_evd_free (send_evd); + DT_assert_clean (rc == DAT_SUCCESS); + } + if (recv_evd) + { + rc = dat_evd_free (recv_evd); + DT_assert_clean (rc == DAT_SUCCESS); + } + if (pz_handle) + { + rc=dat_pz_free (pz_handle); + DT_assert_clean (rc == DAT_SUCCESS); + } + + if (ia_handle) + { + rc=DT_ia_close (ia_handle, DAT_CLOSE_ABRUPT_FLAG); + DT_assert_clean (rc == DAT_SUCCESS); + } + + return res; +} + +/*--------------------------------------------------------*/ +int DT_pz_case2 ( FFT_Cmd_t *cmd) +{ + char* dev_name; + DAT_IA_HANDLE ia_handle; + DAT_PZ_HANDLE pz_handle; + Bpool *bpool; + DAT_RETURN rc; + int res; + + DT_Mdep_printf ("\ + Description: try to destroy pz with registered memory still\n"); + DT_Mdep_printf ("\ + associated with it\n"); + + res=1; + ia_handle=0; + pz_handle =0; + bpool=0; + dev_name= cmd->device_name; + + rc = DT_ia_open (dev_name, &ia_handle); + DT_assert_dat (rc == DAT_SUCCESS); + + rc = dat_pz_create (ia_handle, &pz_handle); + DT_assert_dat (rc == DAT_SUCCESS); + + /* allocate and register bpool */ + bpool = DT_BpoolAlloc (0, ia_handle, pz_handle, NULL, + NULL, BUFFSIZE, 1, DAT_OPTIMAL_ALIGNMENT, + false, false); + DT_assert (bpool != 0); + + if (pz_handle) + { + rc = dat_pz_free (pz_handle); + DT_assert_dat (DAT_GET_TYPE(rc) == DAT_INVALID_STATE); + } + +cleanup: + + /* deregister and free bpool */ + if (DT_Bpool_Destroy (0, bpool)==false) + { + DT_Mdep_printf ("Warning: Destroy bpool fails, reboot for cleanup\n"); + return 0; + } + if (pz_handle) + { + rc=dat_pz_free (pz_handle); + DT_assert_clean (rc == DAT_SUCCESS); + } + + if (ia_handle) + { + rc=DT_ia_close (ia_handle, DAT_CLOSE_ABRUPT_FLAG); + DT_assert_clean (rc == DAT_SUCCESS); + } + + return res; +} + +/*-------------------------------------------------------------*/ +void DT_pz_test (FFT_Cmd_t *cmd) +{ + int i; + int res; + FFT_Testfunc_t cases_func[] = + { + { DT_pz_case0 }, + { DT_pz_case1 }, + { DT_pz_case2 }, + }; + + for (i=0; isize; i++) + { + if (cmd->cases_flag[i]) + { + DT_Mdep_printf ("\ + *********************************************************************\n"); + DT_Mdep_printf ("\ + Function feature: Protection Zone management case: %d\n", i); + res = cases_func[i].fun (cmd); + if (res==1) + { + DT_Mdep_printf ("Result: PASS\n"); + } + else if (res ==0) + { + DT_Mdep_printf ("Result: FAIL\n"); + } + else if (res ==-1) + { + DT_Mdep_printf ("Result: use other test tool\n"); + } + else if (res ==-2) + { + DT_Mdep_printf ("Result: not support or next stage to develop\n"); + } + + DT_Mdep_printf ("\ + *********************************************************************\n"); + } + } + return; +} diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_fft_queryinfo.c b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_fft_queryinfo.c new file mode 100644 index 00000000..5c0676e3 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_fft_queryinfo.c @@ -0,0 +1,621 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" +#include "dapl_fft_util.h" + +#define CQENTRYCOUNT 100 +#define BUFFSIZE 1024 +#define DEFAULT_QUEUE_LEN 10 + +#if defined(WIN32) +static DAT_OS_WAIT_PROXY_AGENT NULLPROXY = { + (DAT_PVOID) NULL,(DAT_AGENT_FUNC) NULL}; +#endif + +int DT_queryinfo_basic (FFT_Cmd_t *cmd, + FFT_query_enum object_to_query, + DAT_RETURN result_wanted) +{ + char *dev_name; + DAT_IA_HANDLE ia_handle; + DAT_IA_ATTR ia_attributes; + DAT_PROVIDER_ATTR provider_attributes; + DAT_EVD_HANDLE evd_handle; + DAT_EVD_HANDLE conn_evd_handle; + DAT_EVD_HANDLE cr_evd_handle; + DAT_EVD_HANDLE send_evd_handle; + DAT_EVD_HANDLE recv_evd_handle; + DAT_EP_HANDLE ep_handle; + DAT_EP_PARAM ep_param; + DAT_CNO_HANDLE cno_handle; + DAT_CNO_PARAM cno_param; + DAT_EVD_PARAM evd_param; + DAT_PSP_HANDLE psp_handle; + DAT_PSP_PARAM psp_param; + DAT_RSP_HANDLE rsp_handle; + DAT_RSP_PARAM rsp_param; + DAT_PZ_HANDLE pz_handle; + DAT_PZ_PARAM pz_param; + DAT_LMR_HANDLE lmr_handle; + DAT_LMR_PARAM lmr_param; + DAT_LMR_CONTEXT lmr_context; + DAT_RMR_HANDLE rmr_handle; + DAT_RMR_PARAM rmr_param; + DAT_REGION_DESCRIPTION region; + DAT_VLEN reg_size; + DAT_VADDR reg_addr; + DAT_COUNT buffer_size; + unsigned char *alloc_ptr; + + DAT_RETURN rc; + int res = 1; + buffer_size = BUFFSIZE * sizeof (unsigned char); + reg_addr = 0; + alloc_ptr = 0; + + ia_handle = NULL; + pz_handle = NULL; + ep_handle = NULL; + lmr_handle = NULL; + rmr_handle = NULL; + pz_handle = NULL; + psp_handle = NULL; + rsp_handle = NULL; + cno_handle = NULL; + + evd_handle = DAT_HANDLE_NULL; + conn_evd_handle = DAT_HANDLE_NULL; + cr_evd_handle = DAT_HANDLE_NULL; + recv_evd_handle = DAT_HANDLE_NULL; + send_evd_handle = DAT_HANDLE_NULL; + dev_name = cmd->device_name; + + /* All functions require an ia_handle to be created */ +#ifdef DYNAMIC_DAT_LOADING + rc = dat_open ((const DAT_NAME_PTR)dev_name, + DEFAULT_QUEUE_LEN, + &evd_handle, + &ia_handle, + DAT_VERSION_MAJOR, + DAT_VERSION_MINOR, + DAT_THREADSAFE); +#else + rc = dat_ia_open ((const DAT_NAME_PTR)dev_name, + DEFAULT_QUEUE_LEN, + &evd_handle, + &ia_handle); +#endif // DYNAMIC_DAT_LOADING + DT_assert_dat (rc == DAT_SUCCESS); + + /* These functions require a pz_handle to be created */ + if ( (object_to_query == QUERY_EVD) || + (object_to_query == QUERY_RMR) || + (object_to_query == QUERY_LMR) || + (object_to_query == QUERY_EP) || + (object_to_query == QUERY_RSP) || + (object_to_query == QUERY_PZ) ) + { + rc = dat_pz_create (ia_handle, + &pz_handle); + DT_assert_dat (rc == DAT_SUCCESS); + } + + /* These functions require a ep_handle to be created */ + if ( (object_to_query == QUERY_EP) || + (object_to_query == QUERY_RSP) ) + { + rc = dat_evd_create (ia_handle, + DEFAULT_QUEUE_LEN, + cno_handle, + DAT_EVD_DTO_FLAG | DAT_EVD_RMR_BIND_FLAG, + &send_evd_handle); + DT_assert_dat (rc == DAT_SUCCESS); + + rc = dat_evd_create (ia_handle, + DEFAULT_QUEUE_LEN, + cno_handle, + DAT_EVD_DTO_FLAG, + &recv_evd_handle); + DT_assert_dat (rc == DAT_SUCCESS); + + rc = dat_evd_create (ia_handle, + DEFAULT_QUEUE_LEN, + cno_handle, + DAT_EVD_CONNECTION_FLAG, + &conn_evd_handle); + DT_assert_dat (rc == DAT_SUCCESS); + + rc = dat_ep_create (ia_handle, + pz_handle, + recv_evd_handle, + send_evd_handle, + conn_evd_handle, + NULL, + &ep_handle); + DT_assert_dat (rc == DAT_SUCCESS); + } + + /* These functions require a CR EVD to be created. */ + if ( (object_to_query == QUERY_PSP) || + (object_to_query == QUERY_RSP) ) + { + rc = dat_evd_create (ia_handle, + DEFAULT_QUEUE_LEN, + cno_handle, + DAT_EVD_CR_FLAG, + &cr_evd_handle); + DT_assert_dat (rc == DAT_SUCCESS); + } + + /* Test dat_ia_query function */ + if (object_to_query == QUERY_IA) + { + if (result_wanted == DAT_SUCCESS) + { + rc = dat_ia_query (ia_handle, + &evd_handle, + DAT_IA_ALL, + &ia_attributes, + DAT_PROVIDER_FIELD_ALL, + &provider_attributes); + } + else if (result_wanted == DAT_INVALID_PARAMETER) + { + /* + * The only way to get an invalid parameter is to + * NULL out ia_attr and for the DAT_IA_ATTR_MASK to + * have values + */ + rc = dat_ia_query (ia_handle, + &evd_handle, + DAT_IA_ALL, + NULL, + DAT_PROVIDER_FIELD_ALL, + &provider_attributes); + } + else if (result_wanted == DAT_INVALID_HANDLE) + { + rc = dat_ia_query (evd_handle, + &evd_handle, + DAT_IA_ALL, + &ia_attributes, + DAT_PROVIDER_FIELD_ALL, + &provider_attributes); + } + } + + /* Test dat_cno_query function */ + else if (object_to_query == QUERY_CNO) + { +#if defined(WIN32) + rc = dat_cno_create (ia_handle, + NULLPROXY, + &cno_handle); +#else + rc = dat_cno_create (ia_handle, + DAT_OS_WAIT_PROXY_AGENT_NULL, + &cno_handle); +#endif + + DT_assert_dat (rc == DAT_SUCCESS); + + if (result_wanted == DAT_SUCCESS) + { + rc = dat_cno_query (cno_handle, + DAT_CNO_FIELD_ALL, + &cno_param); + } + else if (result_wanted == DAT_INVALID_PARAMETER) + { + rc = dat_cno_query (cno_handle, + DAT_CNO_FIELD_ALL, + NULL); + } + else if (result_wanted == DAT_INVALID_HANDLE) + { + rc = dat_cno_query (ia_handle, + DAT_CNO_FIELD_ALL, + &cno_param); + } + } + /* Test dat_evd_query function */ + else if (object_to_query == QUERY_EVD) + { + if (result_wanted == DAT_SUCCESS) + { + rc = dat_evd_query (evd_handle, + DAT_EVD_FIELD_ALL, + &evd_param); + } + else if (result_wanted == DAT_INVALID_PARAMETER) + { + rc = dat_evd_query (evd_handle, + DAT_EVD_FIELD_ALL, + NULL); + } + else if (result_wanted == DAT_INVALID_HANDLE) + { + rc = dat_evd_query (ia_handle, + DAT_EVD_FIELD_ALL, + &evd_param); + } + } + + /* Test dat_psp_query function */ + else if (object_to_query == QUERY_PSP) + { + rc = dat_psp_create (ia_handle, + SERVER_PORT_NUMBER, + cr_evd_handle, + DAT_PSP_PROVIDER_FLAG, + &psp_handle); + DT_assert_dat (rc == DAT_SUCCESS); + if (result_wanted == DAT_SUCCESS) + { + rc = dat_psp_query (psp_handle, + DAT_PSP_FIELD_ALL, + &psp_param); + } + else if (result_wanted == DAT_INVALID_PARAMETER) + { + rc = dat_psp_query (psp_handle, + DAT_PSP_FIELD_ALL, + NULL); + } + else if (result_wanted == DAT_INVALID_HANDLE) + { + rc = dat_psp_query (evd_handle, + DAT_PSP_FIELD_ALL, + &psp_param); + } + } + + /* Test dat_rsp_query function */ + else if (object_to_query == QUERY_RSP) + { + rc = dat_rsp_create (ia_handle, + SERVER_PORT_NUMBER, + ep_handle, + cr_evd_handle, + &rsp_handle); + DT_assert_dat (rc == DAT_SUCCESS); + rc = dat_rsp_query (rsp_handle, + DAT_RSP_FIELD_ALL, + &rsp_param); + } + + /* Test dat_cr_query function */ + else if (object_to_query == QUERY_CR) + { + /* This query is tested in the conmgt test */ + res = -1; + } + + /* Test dat_ep_query function */ + else if (object_to_query == QUERY_EP) + { + rc = dat_ep_query (ep_handle, + DAT_EP_FIELD_ALL, + &ep_param); + } + + /* Test dat_pz_query function */ + else if (object_to_query == QUERY_PZ) + { + rc = dat_pz_query (pz_handle, + DAT_PZ_FIELD_ALL, + &pz_param); + } + + /* Test dat_lmr_query function */ + else if (object_to_query == QUERY_LMR) + { + alloc_ptr = (unsigned char *)DT_Mdep_Malloc (buffer_size); + DT_assert (alloc_ptr); + memset (®ion, 0, sizeof (region)); + region.for_va = alloc_ptr; + rc = dat_lmr_create (ia_handle, + DAT_MEM_TYPE_VIRTUAL, + region, + buffer_size, + pz_handle, + DAT_MEM_PRIV_ALL_FLAG, + &lmr_handle, + &lmr_context, + NULL, /* FIXME */ + ®_size, + ®_addr); + DT_assert_dat (rc == DAT_SUCCESS); + rc = dat_lmr_query (lmr_handle, + DAT_LMR_FIELD_ALL, + &lmr_param); + } + + /* Test dat_rmr_query function */ + else if (object_to_query == QUERY_RMR) + { + rc = dat_rmr_create (pz_handle, + &rmr_handle); + DT_assert_dat (rc == DAT_SUCCESS); + /* We don't bind the RMR to anything, so don't ask for the + * LMR_TRIPLET flag + */ + rc = dat_rmr_query (rmr_handle, + DAT_RMR_FIELD_ALL - DAT_RMR_FIELD_LMR_TRIPLET, + &rmr_param); + } + + DT_assert_dat (DAT_GET_TYPE(rc) == result_wanted); + +cleanup: + if (rsp_handle) + { + rc = dat_rsp_free (rsp_handle); + DT_assert_clean (rc == DAT_SUCCESS); + } + + if (ep_handle) + { + rc = dat_ep_free (ep_handle); + DT_assert_clean (rc == DAT_SUCCESS); + } + + if (send_evd_handle) + { + rc = dat_evd_free (send_evd_handle); + DT_assert_clean (rc == DAT_SUCCESS); + } + + if (recv_evd_handle) + { + rc = dat_evd_free (recv_evd_handle); + DT_assert_clean (rc == DAT_SUCCESS); + } + + if (conn_evd_handle) + { + rc = dat_evd_free (conn_evd_handle); + DT_assert_clean (rc == DAT_SUCCESS); + } + + if (lmr_handle) + { + rc = dat_lmr_free (lmr_handle); + DT_assert_clean (rc == DAT_SUCCESS); + } + + if (rmr_handle) + { + rc = dat_rmr_free (rmr_handle); + DT_assert_clean (rc == DAT_SUCCESS); + } + + if (cno_handle) + { + rc = dat_cno_free (cno_handle); + DT_assert_clean (rc == DAT_SUCCESS); + } + + if (psp_handle) + { + rc = dat_psp_free (psp_handle); + DT_assert_clean (rc == DAT_SUCCESS); + } + + if (cr_evd_handle) + { + rc = dat_evd_free (cr_evd_handle); + DT_assert_clean (rc == DAT_SUCCESS); + } + + if (pz_handle) + { + rc = dat_pz_free (pz_handle); + DT_assert_clean (rc == DAT_SUCCESS); + } + + if (ia_handle) + { + rc = DT_ia_close (ia_handle, DAT_CLOSE_ABRUPT_FLAG); + DT_assert_clean (rc == DAT_SUCCESS); + } + + return res; +} + +int DT_queryinfo_case0 (FFT_Cmd_t *cmd) +{ + DT_Mdep_printf ("Description: Verify IA Querying information is successful using\nDAT_IA_QUERY.\n"); + return DT_queryinfo_basic (cmd, QUERY_IA, DAT_SUCCESS); +} + +int DT_queryinfo_case1 (FFT_Cmd_t *cmd) +{ + DT_Mdep_printf ("Description: Verify CNO Querying information is successful using\nDAT_CNO_QUERY.\n"); + return DT_queryinfo_basic (cmd, QUERY_CNO, DAT_SUCCESS); +} + +int DT_queryinfo_case2 (FFT_Cmd_t *cmd) +{ + DT_Mdep_printf ("Description: Verify EVD Querying information is successful using\nDAT_EVD_QUERY.\n"); + return DT_queryinfo_basic (cmd, QUERY_EVD, DAT_SUCCESS); +} + +int DT_queryinfo_case3 (FFT_Cmd_t *cmd) +{ + DT_Mdep_printf ("Description: Verify PSP Querying information is successful using\nDAT_PSP_QUERY.\n"); + return DT_queryinfo_basic (cmd, QUERY_PSP, DAT_SUCCESS); +} + +int DT_queryinfo_case4 (FFT_Cmd_t *cmd) +{ + DT_Mdep_printf ("Description: Verify RSP Querying information is successful using\nDAT_RSP_QUERY.\n"); + return DT_queryinfo_basic (cmd, QUERY_RSP, DAT_SUCCESS); +} + +int DT_queryinfo_case5 (FFT_Cmd_t *cmd) +{ + DT_Mdep_printf ("Description: Verify CR Querying information is successful using\nDAT_CR_QUERY.\n"); + return DT_queryinfo_basic (cmd, QUERY_CR, DAT_SUCCESS); +} + +int DT_queryinfo_case6 (FFT_Cmd_t *cmd) +{ + DT_Mdep_printf ("Description: Verify EP Querying information is successful using\nDAT_EP_QUERY.\n"); + return DT_queryinfo_basic (cmd, QUERY_EP, DAT_SUCCESS); +} + +int DT_queryinfo_case7 (FFT_Cmd_t *cmd) +{ + DT_Mdep_printf ("Description: Verify PZ Querying information is successful using\n"); + DT_Mdep_printf ("DAT_PZ_QUERY\n"); + return DT_queryinfo_basic (cmd, QUERY_PZ, DAT_SUCCESS); +} + +int DT_queryinfo_case8 (FFT_Cmd_t *cmd) +{ + DT_Mdep_printf ("Description: Verify LMR Querying information is successful using\n"); + DT_Mdep_printf ("DAT_LMR_QUERY\n"); + return DT_queryinfo_basic (cmd, QUERY_LMR, DAT_SUCCESS); +} + +int DT_queryinfo_case9 (FFT_Cmd_t *cmd) +{ + DT_Mdep_printf ("Description: Verify RMR Querying information is successful using\n"); + DT_Mdep_printf ("DAT_RMR_QUERY\n"); + return DT_queryinfo_basic (cmd, QUERY_RMR, DAT_SUCCESS); +} + +int DT_queryinfo_case10 (FFT_Cmd_t *cmd) +{ + DT_Mdep_printf ("Description: Verify IA Querying fails with DAT_INVALID_PARAMETER when\n"); + DT_Mdep_printf ("passing a bad parameter to DAT_IA_QUERY\n"); + return DT_queryinfo_basic (cmd, QUERY_IA, DAT_INVALID_PARAMETER); +} + +int DT_queryinfo_case11 (FFT_Cmd_t *cmd) +{ + DT_Mdep_printf ("Description: Verify IA Querying fails with DAT_INVALID_HANDLE when\n"); + DT_Mdep_printf ("passing an invalid handle to DAT_IA_QUERY\n"); + return DT_queryinfo_basic (cmd, QUERY_IA, DAT_INVALID_HANDLE); +} + +int DT_queryinfo_case12 (FFT_Cmd_t *cmd) +{ + DT_Mdep_printf ("Description: Verify CNO Querying fails with DAT_INVALID_PARAMETER when\n"); + DT_Mdep_printf ("passing a bad parameter to DAT_CNO_QUERY\n"); + return DT_queryinfo_basic (cmd, QUERY_CNO, DAT_INVALID_PARAMETER); +} + +int DT_queryinfo_case13 (FFT_Cmd_t *cmd) +{ + DT_Mdep_printf ("Description: Verify CNO Querying fails with DAT_INVALID_HANDLE when\n"); + DT_Mdep_printf ("passing an invalid handle to DAT_CNO_QUERY\n"); + return DT_queryinfo_basic (cmd, QUERY_CNO, DAT_INVALID_HANDLE); +} + +int DT_queryinfo_case14 (FFT_Cmd_t *cmd) +{ + DT_Mdep_printf ("Description: Verify EVD Querying fails with DAT_INVALID_PARAMETER when\n"); + DT_Mdep_printf ("passing a bad parameter to DAT_EVD_QUERY\n"); + return DT_queryinfo_basic (cmd, QUERY_EVD, DAT_INVALID_PARAMETER); +} + +int DT_queryinfo_case15 (FFT_Cmd_t *cmd) +{ + DT_Mdep_printf ("Description: Verify EVD Querying fails with DAT_INVALID_HANDLE when\n"); + DT_Mdep_printf ("passing an invalid handle to DAT_EVD_QUERY\n"); + return DT_queryinfo_basic (cmd, QUERY_EVD, DAT_INVALID_HANDLE); +} + +int DT_queryinfo_case16 (FFT_Cmd_t *cmd) +{ + DT_Mdep_printf ("Description: Verify PSP Querying fails with DAT_INVALID_PARAMETER when\n"); + DT_Mdep_printf ("passing a bad parameter to DAT_PSP_QUERY\n"); + return DT_queryinfo_basic (cmd, QUERY_PSP, DAT_INVALID_PARAMETER); +} + +int DT_queryinfo_case17 (FFT_Cmd_t *cmd) +{ + DT_Mdep_printf ("Description: Verify PSP Querying fails with DAT_INVALID_HANDLE when\n"); + DT_Mdep_printf ("passing an invalid handle to DAT_PSP_QUERY\n"); + return DT_queryinfo_basic (cmd, QUERY_PSP, DAT_INVALID_HANDLE); +} + +/*-------------------------------------------------------------*/ +void DT_queryinfo_test (FFT_Cmd_t *cmd) +{ + int i; + int res; + FFT_Testfunc_t cases_func[] = + { + { DT_queryinfo_case0 }, + { DT_queryinfo_case1 }, + { DT_queryinfo_case2 }, + { DT_queryinfo_case3 }, + { DT_queryinfo_case4 }, + { DT_queryinfo_case5 }, + { DT_queryinfo_case6 }, + { DT_queryinfo_case7 }, + { DT_queryinfo_case8 }, + { DT_queryinfo_case9 }, + { DT_queryinfo_case10 }, + { DT_queryinfo_case11 }, + { DT_queryinfo_case12 }, + { DT_queryinfo_case13 }, + { DT_queryinfo_case14 }, + { DT_queryinfo_case15 }, + { DT_queryinfo_case16 }, + { DT_queryinfo_case17 }, + }; + + for (i=0; i < cmd->size; i++) + { + if (cmd->cases_flag[i]) + { + DT_Mdep_printf ("*********************************************************************\n"); + DT_Mdep_printf ("Function feature: Queryinfo case: %d\n", i + ); + res = cases_func[i].fun (cmd); + if (res==1) + { + DT_Mdep_printf ("Result: PASS\n"); + } + else if (res ==0) + { + DT_Mdep_printf ("Result: FAIL\n"); + } + else if (res == -1) + { + DT_Mdep_printf ("Result: UNSUPP\n"); + } + + DT_Mdep_printf ("*********************************************************************\n"); + } + } + return; +} diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_fft_test.c b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_fft_test.c new file mode 100644 index 00000000..6852b716 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_fft_test.c @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" +#include "dapl_fft_cmd.h" +#include + +void +DT_cs_FFT (FFT_Cmd_t * cmd) +{ + switch (cmd->fft_type) + { + case HWCONN: + { + DT_hwconn_test (cmd); + break; + } + case ENDPOINT: + { + DT_endpoint_test (cmd); + break; + } + case PTAGMGT: + { + DT_pz_test (cmd); + break; + } + case MEMMGT: + { + DT_mem_test (cmd); + break; + } + case CONNMGT: + { + DT_connmgt_test (cmd); + break; + } + case DATAXFER: + { + DT_dataxfer_test (cmd); + break; + } + case DATAXFER_CLIENT: + { + DT_dataxfer_client_test (cmd); + break; + } + case QUERYINFO: + { + DT_queryinfo_test (cmd); + break; + } + case CONNMGT_CLIENT: + case NS: + case ERRHAND: + case UNSUPP: + case STRESS: + case STRESS_CLIENT: + case CQMGT: + { + DT_Mdep_printf ("Not Yet Implemented\n"); + break; + } + default: + { + DT_Mdep_printf ("don't know this test\n"); + break; + } + } +} + diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_fft_util.c b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_fft_util.c new file mode 100644 index 00000000..cbe1d698 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_fft_util.c @@ -0,0 +1,357 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" +#include "dapl_fft_util.h" + +#define DEFAULT_QUEUE_LEN 10 + + +/* function that is called when an assertion fails, printing out the line + * that failed vi DT_Mdep_printf + */ +void DT_assert_fail (char *exp, char *file, char *baseFile, int line) +{ + if (!strcmp (file, baseFile)) + { + DT_Mdep_printf ("%s failed in file %s, line %d\n", exp, file, + line); + } + else + { + DT_Mdep_printf ("%s failed in file %s (included from %s), line %d\n", + exp, file, baseFile, line); + } +} + +/* helper function to open an IA */ +int DT_ia_open (DAT_NAME_PTR dev_name, DAT_IA_HANDLE *ia_handle) +{ + DAT_EVD_HANDLE evd_handle; + evd_handle = DAT_HANDLE_NULL; +#ifdef DYNAMIC_DAT_LOADING + return dat_open (dev_name, DEFAULT_QUEUE_LEN, &evd_handle, ia_handle, + DAT_VERSION_MAJOR, + DAT_VERSION_MINOR, + DAT_THREADSAFE); +#else + return dat_ia_open (dev_name, DEFAULT_QUEUE_LEN, &evd_handle, ia_handle); +#endif //DYNAMIC_DAT_LOADING + +} + +DAT_RETURN +DT_ia_close (DAT_IA_HANDLE ia_handle, DAT_CLOSE_FLAGS flags) +{ +#ifdef DYNAMIC_DAT_LOADING + return dat_close (ia_handle, flags); +#else + return dat_ia_close (ia_handle, flags); +#endif +} + +/* helper function to create an endpoint and its associated EVDs */ +int DT_ep_create (DAT_IA_HANDLE ia_handle, DAT_PZ_HANDLE pz_handle, + DAT_EVD_HANDLE *cr_evd, + DAT_EVD_HANDLE *conn_evd, DAT_EVD_HANDLE *send_evd, + DAT_EVD_HANDLE *recv_evd, DAT_EP_HANDLE *ep_handle) +{ + DAT_RETURN status; + *conn_evd= 0; + *send_evd= 0; + *recv_evd= 0; + *cr_evd= 0; + + status = dat_evd_create (ia_handle, DEFAULT_QUEUE_LEN, DAT_HANDLE_NULL, + DAT_EVD_CR_FLAG, cr_evd); + if (status != DAT_SUCCESS) + { + DT_Mdep_printf ("dat_evd_create failed %s\n", DT_RetToString (status)); + return status; + } + + status = dat_evd_create (ia_handle, DEFAULT_QUEUE_LEN, DAT_HANDLE_NULL, + DAT_EVD_CONNECTION_FLAG, conn_evd); + if (status != DAT_SUCCESS) + { + DT_Mdep_printf ("dat_evd_create failed %s\n", DT_RetToString (status)); + return status; + } + + status = dat_evd_create (ia_handle, DEFAULT_QUEUE_LEN, DAT_HANDLE_NULL, + DAT_EVD_DTO_FLAG | DAT_EVD_RMR_BIND_FLAG, + send_evd); + if (status != DAT_SUCCESS) + { + DT_Mdep_printf ("dat_evd_create failed %s\n", DT_RetToString (status)); + return status; + } + + status = dat_evd_create (ia_handle, DEFAULT_QUEUE_LEN, DAT_HANDLE_NULL, + DAT_EVD_DTO_FLAG, recv_evd); + if (status != DAT_SUCCESS) + { + DT_Mdep_printf ("dat_evd_create failed %s\n", DT_RetToString (status)); + return status; + } + + status = dat_ep_create (ia_handle, pz_handle, *recv_evd, + *send_evd, *conn_evd, NULL, ep_handle); + if (status != DAT_SUCCESS) + { + DT_Mdep_printf ("dat_ep_create failed %s\n", DT_RetToString (status)); + } + return status; +} + +/* function that initializes the connection struct */ +void DT_fft_init_conn_struct (FFT_Connection_t *conn) +{ + conn->ia_handle = 0; + conn->pz_handle = 0; + conn->psp_handle = 0; + conn->ep_handle = 0; + conn->cr_evd = 0; + conn->send_evd = 0; + conn->conn_evd = 0; + conn->recv_evd = 0; + conn->cr_handle = 0; + conn->remote_netaddr = 0; + conn->bpool = 0; + conn->pt_ptr = 0; + conn->connected = false; +} + +/* helper function that simplifies many dat calls for the initiialization of a + * dat "client" + */ +void DT_fft_init_client (FFT_Cmd_t *cmd, FFT_Connection_t *conn) +{ + int res; + DAT_RETURN rc=0; + + /* initialize the struct's members */ + DT_fft_init_conn_struct (conn); + + /* open the IA */ + rc = DT_ia_open (cmd->device_name, &conn->ia_handle); + DT_assert_dat (rc == DAT_SUCCESS); + + /* create a PZ */ + rc = dat_pz_create (conn->ia_handle, &conn->pz_handle); + DT_assert_dat (rc == DAT_SUCCESS); + + /* create an EP and its EVDs */ + rc =DT_ep_create (conn->ia_handle, conn->pz_handle, &conn->cr_evd, + &conn->conn_evd, &conn->send_evd, &conn->recv_evd, + &conn->ep_handle); + DT_assert_dat (rc == DAT_SUCCESS); + + /* if a server name is given, allocate memory for a net address and set it + * up appropriately + */ + if (cmd->server_name && strlen (cmd->server_name)) + { + conn->pt_ptr = DT_Alloc_Per_Test_Data (); + DT_assert (conn->pt_ptr); + DT_MemListInit (conn->pt_ptr); + conn->remote_netaddr = DT_NetAddrAlloc (conn->pt_ptr); + DT_assert (conn->remote_netaddr); + DT_assert (DT_NetAddrLookupHostAddress (conn->remote_netaddr, + cmd->server_name)); + } +cleanup: + return; +} + +/* helper function to break down a client or server created with one of the + * init helper functions + */ +int DT_fft_destroy_conn_struct (FFT_Connection_t *conn) +{ + DAT_RETURN rc = DAT_SUCCESS; + if (conn->ep_handle) + { + if (conn->connected) + { + rc = dat_ep_disconnect (conn->ep_handle, DAT_CLOSE_DEFAULT); + DT_assert_clean (rc == DAT_SUCCESS); + + if (!DT_disco_event_wait ( conn->cr_evd, NULL )) + + { + DT_Mdep_printf ("DT_fft_destroy_conn_struct: bad disconnect event\n"); + } + } + rc = dat_ep_free (conn->ep_handle); + DT_assert_clean (rc == DAT_SUCCESS); + } + if (conn->bpool) + { + DT_Bpool_Destroy (0, conn->bpool); + } + if (conn->psp_handle) + { + rc = dat_psp_free (conn->psp_handle); + DT_assert_clean (rc == DAT_SUCCESS); + } + if (conn->cr_evd) + { + rc = dat_evd_free (conn->cr_evd); + DT_assert_clean (rc == DAT_SUCCESS); + } + if (conn->conn_evd) + { + rc = dat_evd_free (conn->conn_evd); + DT_assert_clean (rc == DAT_SUCCESS); + } + if (conn->send_evd) + { + rc = dat_evd_free (conn->send_evd); + DT_assert_clean (rc == DAT_SUCCESS); + } + if (conn->recv_evd) + { + rc = dat_evd_free (conn->recv_evd); + DT_assert_clean (rc == DAT_SUCCESS); + } + if (conn->remote_netaddr) + { + DT_NetAddrFree (conn->pt_ptr, conn->remote_netaddr); + } + if (conn->pt_ptr) + { + DT_Free_Per_Test_Data (conn->pt_ptr); + } + if (conn->pz_handle) + { + rc = dat_pz_free (conn->pz_handle); + DT_assert_clean (rc == DAT_SUCCESS); + } + if (conn->ia_handle) + { + rc = DT_ia_close (conn->ia_handle, DAT_CLOSE_ABRUPT_FLAG); + DT_assert_clean (rc == DAT_SUCCESS); + } + return rc; +} + +/* helper function to init a dat "server" */ +void DT_fft_init_server (FFT_Cmd_t *cmd, FFT_Connection_t *conn) +{ + int res; + DAT_RETURN rc=0; + + /* init the connection struct's members */ + DT_fft_init_conn_struct (conn); + + /* open the IA */ + rc = DT_ia_open (cmd->device_name, &conn->ia_handle); + DT_assert_dat (rc == DAT_SUCCESS); + + /* create a PZ */ + rc = dat_pz_create (conn->ia_handle, &conn->pz_handle); + DT_assert_dat (rc == DAT_SUCCESS); + + /* create an EP and its EVDs */ + rc =DT_ep_create (conn->ia_handle, conn->pz_handle, &conn->cr_evd, + &conn->conn_evd, &conn->send_evd, &conn->recv_evd, + &conn->ep_handle); + DT_assert_dat (rc == DAT_SUCCESS); + + /* create a PSP */ + rc = dat_psp_create (conn->ia_handle, SERVER_PORT_NUMBER, conn->cr_evd, + DAT_PSP_CONSUMER_FLAG, &conn->psp_handle); + DT_assert_dat (rc == DAT_SUCCESS); + + /* allocate memory for buffers */ + conn->bpool = DT_BpoolAlloc (0, conn->ia_handle, conn->pz_handle, NULL, NULL, + 8192, 2, DAT_OPTIMAL_ALIGNMENT, false, false); + DT_assert (conn->bpool); +cleanup: + return; +} + +/* helper function that allows a server to listen for a connection */ +void DT_fft_listen (FFT_Connection_t *conn) +{ + int res; + DAT_RETURN rc=0; + + /* wait on a CR event via the CR EVD */ + DT_assert_dat (DT_cr_event_wait (conn->cr_evd, &conn->cr_stat) && + DT_cr_check (&conn->cr_stat, conn->psp_handle, SERVER_PORT_NUMBER, + &conn->cr_handle, "DT_fft_listen")); + + /* accept the connection */ + rc =dat_cr_accept (conn->cr_handle, conn->ep_handle, 0, (DAT_PVOID)0); + DT_assert_dat (rc == DAT_SUCCESS); + + /* wait on a conn event via the conn EVD */ + DT_assert (DT_conn_event_wait (conn->ep_handle, conn->conn_evd, + &conn->event_num) == true); + conn->connected = true; +cleanup: + return; +} + +/* helper function that allows a client to connect to a server */ +int DT_fft_connect (FFT_Connection_t *conn) +{ + int wait_count; + int res; + DAT_RETURN rc=0; + + /* try 10 times to connect */ + for (wait_count = 0; wait_count < 10; wait_count++) + { + DT_Mdep_printf ("Connection to server, attempt #%d\n", wait_count+1); + + /* attempt to connect, timeout = 10 secs */ + rc = dat_ep_connect (conn->ep_handle, conn->remote_netaddr, + SERVER_PORT_NUMBER, 10*1000, 0, (DAT_PVOID)0, + DAT_QOS_BEST_EFFORT, DAT_CONNECT_DEFAULT_FLAG); + DT_assert_dat (rc == DAT_SUCCESS); + + /* wait on conn event */ + DT_assert (DT_conn_event_wait (conn->ep_handle, conn->conn_evd, + &conn->event_num) == true); + + /* make sure we weren't rejected by the peer */ + if (conn->event_num == DAT_CONNECTION_EVENT_PEER_REJECTED) + { + DT_Mdep_Sleep (1000); + DT_Mdep_printf ("Connection rejected by peer; retrying\n"); + } + } +cleanup: + if (conn->event_num == DAT_CONNECTION_EVENT_ESTABLISHED) + { + conn->connected = true; + } + /* returns true if connected, false otherwise */ + return (conn->connected); +} diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_fft_util.h b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_fft_util.h new file mode 100644 index 00000000..bd046444 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_fft_util.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#ifndef DAPL_FFT_UTIL_H +#define DAPL_FFT_UTIL_H + +#define DT_assert_dat(x) if(x) ; \ + else { \ + DT_assert_fail(#x, __FILE__, __BASE_FILE__, __LINE__); \ + DT_Mdep_printf("Error = %d, %s\n", rc, DT_RetToString(rc)); \ + res = 0; \ + goto cleanup; \ + } + +#define DT_assert(x) if(x) ; \ + else { \ + DT_assert_fail(#x, __FILE__, __BASE_FILE__, __LINE__); \ + res = 0; \ + goto cleanup; \ + } + +#define DT_assert_clean(x) if(x) ; \ + else { \ + DT_assert_fail(#x, __FILE__, __BASE_FILE__, __LINE__); \ + DT_Mdep_printf("Error = %d, %s\n", rc, DT_RetToString(rc)); \ + return 0; \ + } + +typedef struct +{ + DAT_IA_HANDLE ia_handle; + DAT_PZ_HANDLE pz_handle; + DAT_PSP_HANDLE psp_handle; + DAT_EP_HANDLE ep_handle; + DAT_EVD_HANDLE cr_evd, conn_evd, send_evd, recv_evd; + DAT_EVENT event; + DAT_COUNT count; + DAT_CR_HANDLE cr_handle; + Bpool *bpool; + DAT_CR_ARRIVAL_EVENT_DATA cr_stat; + DAT_EVENT_NUMBER event_num; + DAT_IA_ADDRESS_PTR remote_netaddr; + Per_Test_Data_t *pt_ptr; + bool connected; +} FFT_Connection_t; + +typedef enum + { + QUERY_CNO, + QUERY_CR, + QUERY_EP, + QUERY_EVD, + QUERY_IA, + QUERY_LMR, + QUERY_RMR, + QUERY_PSP, + QUERY_RSP, + QUERY_PZ, +} FFT_query_enum; + +#endif + diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_funcs.h b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_funcs.h new file mode 100644 index 00000000..3833b91e --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_funcs.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#ifndef _DAPL_I +#define _DAPL_I + +#define IN +#define OUT + +/* Interface Prefixes */ +#define DATIB_INTERFACE_PREFIX "ib" + +/* Types of DAPL functions, taken from uDAPL 1.0 */ + + +#define DAT_CALLTYPE + +/********************************************************************** + * Types of user-supplied callbacks + **********************************************************************/ + +/********************************************************************** + * Types of basic functions + **********************************************************************/ + +/********************************************************************** + * Types of Peer-to-Peer Connection Model APIs + *********************************************************************/ + +/********************************************************************** + * Types of Name service APIs + *********************************************************************/ + + +#endif diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_getopt.c b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_getopt.c new file mode 100644 index 00000000..2712f5e5 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_getopt.c @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_getopt.h" +#include "dapl_mdep.h" +#include "dapl_proto.h" + +#define GETOPT_MAGIC 0x04030201 + +#define BADCH '?' +#define BADARG ':' +#define EMSG "" + +/** + * Initialize the getopt fields in preparation for parsing + * a command line. + */ +void +DT_mygetopt_init (mygetopt_t * opts) +{ + opts->magic = GETOPT_MAGIC; + opts->place = EMSG; + opts->opterr = 1; + opts->optind = 1; + opts->optopt = 0; + opts->optarg = 0; +} + +/** + * Parse command line arguments. + * + * Return either the option discovered, or + * (int) -1 when there are no more options + * (int) '?' when an illegal option is found + * (int) ':' when a required option argument is missing. + */ +char +DT_mygetopt_r (int argc, char *const * argv, + const char *ostr, mygetopt_t * opts) +{ + char *p; + char *oli; /* option letter list index */ + if (GETOPT_MAGIC != opts->magic) + { + DT_Mdep_printf ("%s: getopt warning: " + "option argument is not properly initialized.\n", + argc > 0 ? argv[0] : "unknown command"); + DT_mygetopt_init (opts); + } + if (!* (opts->place)) /* update scanning pointer */ + { + if ((opts->optind) >= argc || + * ((opts->place) = argv[ (opts->optind)]) != '-') + { + (opts->place) = EMSG; + return (EOF); + } + if ((opts->place)[0] != '-') + { + /* Invalid 1st argument */ + return (BADCH); + } + if ((opts->place)[1] && *++ (opts->place) == '-') + { + /* found "--" which is an invalid option */ + ++ (opts->optind); + (opts->place) = EMSG; + return (BADCH); + } + } /* option letter okay? */ + opts->optopt = (int) * (opts->place)++; + oli = strchr (ostr, (opts->optopt)); + if (opts->optopt == (int) ':' || ! oli) + { + /* + * if the user didn't specify '-' as an option, assume it means EOF. + */ + if ((opts->optopt) == (int) '-') + { + /* return (EOF); */ + return (BADCH); + } + if (!* (opts->place)) + { + ++ (opts->optind); + } + if ((opts->opterr) && *ostr != ':') + { + p = strchr (*argv, '/'); + if (!p) + { + p = *argv; + } + else + { + ++p; + } + + if (opts->optopt != '?') /* Anything but '?' needs error */ + { + DT_Mdep_printf ("%s: Illegal option -- %c\n", + p, (opts->optopt)); + } + } + return (BADCH); + } + if (*++oli != ':') /* don't need argument */ + { + (opts->optarg) = NULL; + if (!* (opts->place)) + { + ++ (opts->optind); + } + } + else /* need an argument */ + { + if (* (opts->place)) /* no white space */ + { + (opts->optarg) = (opts->place); + } + else + { + if (argc <= ++ (opts->optind)) /* no arg */ + { + (opts->place) = EMSG; + if (*ostr == ':') + { + return (BADARG); + } + p = strchr (*argv, '/'); + if (!p) + { + p = *argv; + } + else + { + ++p; + } + if ((opts->opterr)) + { + DT_Mdep_printf ( + "%s: option requires an argument -- %c\n", + p, (opts->optopt)); + } + return (BADCH); + } + else /* white space */ + { + (opts->optarg) = argv[ (opts->optind)]; + } + } + (opts->place) = EMSG; + ++ (opts->optind); + } + return (opts->optopt); /* dump back option letter */ +} diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_getopt.h b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_getopt.h new file mode 100644 index 00000000..2cc379d7 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_getopt.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#ifndef __DAPL_GETOPT_H__ +#define __DAPL_GETOPT_H__ + +typedef struct +{ + int magic; + char *place; + + int opterr; + int optind; + char optopt; + char *optarg; +} mygetopt_t; +/* function prototypes */ +void +DT_mygetopt_init (mygetopt_t * opts); +char +DT_mygetopt_r (int argc, + char *const * argv, + const char *ostr, + mygetopt_t * opts); +#endif diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_limit.c b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_limit.c new file mode 100644 index 00000000..b273a4b0 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_limit.c @@ -0,0 +1,1529 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" +#include "dapl_limit_cmd.h" + +/* + * Increase the size of an array of handles + */ +static bool +more_handles (DAT_HANDLE **old_ptrptr, /* pointer to current pointer */ + unsigned int *old_count, /* number pointed to */ + unsigned int size) /* size of one datum */ +{ + unsigned int count = *old_count; + DAT_HANDLE *old_handles = *old_ptrptr; + DAT_HANDLE *handle_tmp = DT_Mdep_Malloc (count * 2 * size); + + if (!handle_tmp) + { + DT_Mdep_printf ("Out of memory for more DAT_HANDLEs\n"); + return (false); + } + + memcpy (handle_tmp, old_handles, count*size); + DT_Mdep_Free (old_handles); + *old_ptrptr = handle_tmp; + *old_count = count * 2; + return (true); +} + + +/* + * Limit test workhorse. + * + * This test creates the sequence of DAT objects needed to move + * data back and forth, attempting to find the limits supported + * for the DAT object indicated by 'depth'. For example, if + * depth == LIM_LMR, the test will create a set of {IA,PZ,CNO,EVD,EP} + * before trying to exhaust LMR creation using the {IA,PZ,CNO,EVD,EP} set. + * + * The 'cmd->width' parameter can be used to control how may of these + * parallel DAT object sets we create before stopping to beat upon + * the constructor for the object indicated by 'depth', providing for + * increased (or at least different) stress on the DAPL. + */ +static bool +limit_test ( Limit_Cmd_t *cmd, + Limit_Index depth) +{ + typedef struct obj_set + { + DAT_IA_HANDLE ia_handle; + DAT_EVD_HANDLE ia_async_handle; + DAT_PZ_HANDLE pz_handle; + DAT_CNO_HANDLE cno_handle; + DAT_EVD_HANDLE evd_handle; + DAT_EP_HANDLE ep_handle; + DAT_LMR_HANDLE lmr_handle; + char * lmr_buffer; + DAT_LMR_CONTEXT lmr_context; + DAT_RMR_HANDLE rmr_handle; + DAT_RMR_CONTEXT rmr_context; + } Obj_Set; + + Obj_Set *hdl_sets = (Obj_Set *) NULL; + bool retval = false; + char *module = "LimitTest"; +#if defined (WIN32) + /* + * The Windows compiler will not deal with complex definitions + * in macros, so create a variable here. + */ +#if defined (DAT_OS_WAIT_PROXY_AGENT_NULL) + #undef DAT_OS_WAIT_PROXY_AGENT_NULL +#endif + DAT_OS_WAIT_PROXY_AGENT DAT_OS_WAIT_PROXY_AGENT_NULL = {NULL, NULL}; +#endif + + DAT_RETURN ret; + # define DFLT_QLEN 10 /* a small event queue size */ + # define START_COUNT 1024 /* initial # handles */ + # define DFLT_BUFFSZ 4096 /* default size for buffer */ + # define CONN_QUAL0 0xAffab1e + + /* Allocate 'width' Obj_Sets */ + if (depth && ! (hdl_sets = DT_Mdep_Malloc (sizeof (Obj_Set) * cmd->width))) + { + DT_Mdep_printf ("%s: No memory for handle array!\n", module); + goto clean_up_now; + } + + /* ----------- + * IA handling + */ + if (depth > LIM_IA) + { + /* + * The abuse is not for us this time, just prep Obj_Set. + */ + unsigned int w; + + DT_Mdep_debug (("%s: dat_ia_open X %d\n", module, cmd->width)); + for (w = 0; w < cmd->width; w++) + { + /* Specify that we want to get back an async EVD. */ + hdl_sets[w].ia_async_handle = DAT_HANDLE_NULL; +#ifdef DYNAMIC_DAT_LOADING + ret = dat_open (cmd->device_name, + DFLT_QLEN, + &hdl_sets[w].ia_async_handle, + &hdl_sets[w].ia_handle, + DAT_VERSION_MAJOR, + DAT_VERSION_MINOR, + DAT_THREADSAFE); +#else + ret = dat_ia_open (cmd->device_name, + DFLT_QLEN, + &hdl_sets[w].ia_async_handle, + &hdl_sets[w].ia_handle); +#endif // DYNAMIC_DAT_LOADING + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_ia_open (%s) #%d fails: %s\n", + module, cmd->device_name, + w+1, DT_RetToString (ret)); + /* handle contents undefined on failure */ + hdl_sets[w].ia_async_handle = DAT_HANDLE_NULL; + hdl_sets[w].ia_handle = DAT_HANDLE_NULL; + goto clean_up_now; + } + } + } + else if (depth == LIM_IA) + { + /* + * See how many IAs we can create + */ + typedef struct _ia + { + DAT_IA_HANDLE ia_handle; + DAT_EVD_HANDLE ia_async_handle; + } + OneOpen; + unsigned int count = START_COUNT; + OneOpen *hdlptr = (OneOpen *) + DT_Mdep_Malloc (count * sizeof (*hdlptr)); + + /* IA Exhaustion test loop */ + if (hdlptr) + { + unsigned int w = 0; + unsigned int tmp; + + DT_Mdep_debug (("%s: Exhausting dat_ia_open\n", module)); + for (w = 0; w < cmd->maximum; w++) + { +#ifdef _ONTAP_ + sk_preempt_msec(10); +#endif + if (w == count + && !more_handles ((DAT_HANDLE **) &hdlptr, + &count, + sizeof (*hdlptr))) + { + DT_Mdep_printf ("%s: IAs opened: %d\n", module, w); + retval = true; + break; + } + /* Specify that we want to get back an async EVD. */ + hdlptr[w].ia_async_handle = DAT_HANDLE_NULL; +#ifdef DYNAMIC_DAT_LOADING + ret = dat_open (cmd->device_name, + DFLT_QLEN, + &hdlptr[w].ia_async_handle, + &hdlptr[w].ia_handle, + DAT_VERSION_MAJOR, + DAT_VERSION_MINOR, + DAT_THREADSAFE); +#else + ret = dat_ia_open (cmd->device_name, + DFLT_QLEN, + &hdlptr[w].ia_async_handle, + &hdlptr[w].ia_handle); +#endif // DYNAMIC_DAT_LOADING + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_ia_open (%s) #%d fails: %s\n", + module, cmd->device_name, + w+1, DT_RetToString (ret)); + retval = true; + break; + } + } + + DT_Mdep_printf ("%s: IAs opened: %d\n", module, w); + retval = true; + + /* IA Cleanup loop */ + for (tmp = 0; tmp < w; tmp++) + { +#ifdef _ONTAP_ + sk_preempt_msec(10); +#endif + ret = DT_ia_close (hdlptr[tmp].ia_handle, + DAT_CLOSE_GRACEFUL_FLAG); + + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: DT_ia_close (graceful) fails: %s\n", + module, DT_RetToString (ret)); + retval = false; + ret = DT_ia_close (hdlptr[tmp].ia_handle, + DAT_CLOSE_ABRUPT_FLAG); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: DT_ia_close (abrupt) fails: %s\n", + module, DT_RetToString (ret)); + } + } + } + DT_Mdep_Free (hdlptr); + } + } /* End IA handling */ + + /* ----------- + * PZ handling + */ + if (depth > LIM_PZ) + { + /* + * The abuse is not for us this time, just prep Obj_Set. + */ + unsigned int w; + + DT_Mdep_debug (("%s: dat_pz_create X %d\n", module, cmd->width)); + for (w = 0; w < cmd->width; w++) + { + ret = dat_pz_create (hdl_sets[w].ia_handle, + &hdl_sets[w].pz_handle); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_pz_create #%d fails: %s\n", + module, w+1, DT_RetToString (ret)); + /* handle contents undefined on failure */ + hdl_sets[w].pz_handle = DAT_HANDLE_NULL; + goto clean_up_now; + } + } + } + else if (depth == LIM_PZ) + { + /* + * See how many PZs we can create + */ + unsigned int count = START_COUNT; + DAT_PZ_HANDLE *hdlptr = (DAT_PZ_HANDLE *) + DT_Mdep_Malloc (count * sizeof (*hdlptr)); + + /* PZ Exhaustion test loop */ + if (hdlptr) + { + unsigned int w = 0; + unsigned int tmp; + + DT_Mdep_debug (("%s: Exhausting dat_pz_create\n", module)); + for (w = 0; w < cmd->maximum; w++) + { +#ifdef _ONTAP_ + sk_preempt_msec(10); +#endif + if (w == count + && !more_handles ((DAT_HANDLE **) &hdlptr, + &count, + sizeof (*hdlptr))) + { + DT_Mdep_printf ("%s: PZs created: %d\n", module, w); + retval = true; + break; + } + ret = dat_pz_create (hdl_sets[w % cmd->width].ia_handle, + &hdlptr[w]); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_pz_create #%d fails: %s\n", + module, w+1, DT_RetToString (ret)); + retval = true; + break; + } + } + + DT_Mdep_printf ("%s: PZs created: %d\n", module, w); + retval = true; + + /* PZ Cleanup loop */ + for (tmp = 0; tmp < w; tmp++) + { +#ifdef _ONTAP_ + sk_preempt_msec(10); +#endif + ret = dat_pz_free (hdlptr[tmp]); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_pz_free fails: %s\n", + module, DT_RetToString (ret)); + retval = false; + } + } + DT_Mdep_Free (hdlptr); + } + } /* End PZ handling */ + + /* ----------- + * CNO handling + */ + + if (depth > LIM_CNO) + { + /* + * The abuse is not for us this time, just prep Obj_Set. + */ + unsigned int w; + + DT_Mdep_debug (("%s: dat_cno_create X %d\n", module, cmd->width)); + for (w = 0; w < cmd->width; w++) + { + ret = dat_cno_create (hdl_sets[w].ia_handle, + DAT_OS_WAIT_PROXY_AGENT_NULL, + &hdl_sets[w].cno_handle); + if (DAT_GET_TYPE(ret) == DAT_NOT_IMPLEMENTED) + { + DT_Mdep_printf ("%s: dat_cno_create unimplemented\n", module); + hdl_sets[w].cno_handle = DAT_HANDLE_NULL; + /* ignore this error */ + break; + } + else if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_cno_create #%d fails: %s\n", + module, w+1, DT_RetToString (ret)); + /* handle contents undefined on failure */ + hdl_sets[w].cno_handle = DAT_HANDLE_NULL; + goto clean_up_now; + } + } + } + else if (depth == LIM_CNO) + { + /* + * See how many CNOs we can create + */ + unsigned int count = START_COUNT; + DAT_CNO_HANDLE *hdlptr = (DAT_CNO_HANDLE *) + DT_Mdep_Malloc (count * sizeof (*hdlptr)); + + /* CNO Exhaustion test loop */ + if (hdlptr) + { + unsigned int w = 0; + unsigned int tmp; + + DT_Mdep_debug (("%s: Exhausting dat_cno_create\n", module)); + for (w = 0; w < cmd->maximum; w++) + { +#ifdef _ONTAP_ + sk_preempt_msec(10); +#endif + if (w == count + && !more_handles ((DAT_HANDLE **) &hdlptr, + &count, + sizeof (*hdlptr))) + { + DT_Mdep_printf ("%s: CNOs created: %d\n", module, w); + retval = true; + break; + } + ret = dat_cno_create (hdl_sets[w % cmd->width].ia_handle, + DAT_OS_WAIT_PROXY_AGENT_NULL, + &hdlptr[w]); + if (DAT_GET_TYPE(ret) == DAT_NOT_IMPLEMENTED) + { + DT_Mdep_printf ("%s: dat_cno_create unimplemented\n", + module); + retval = true; + break; + } + else if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_cno_create #%d fails: %s\n", + module, w+1, DT_RetToString (ret)); + retval = true; + break; + } + } + + DT_Mdep_printf ("%s: CNOs created: %d\n", module, w); + retval = true; + + /* CNO Cleanup loop */ + for (tmp = 0; tmp < w; tmp++) + { +#ifdef _ONTAP_ + sk_preempt_msec(10); +#endif + ret = dat_cno_free (hdlptr[tmp]); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_cno_free fails: %s\n", + module, DT_RetToString (ret)); + retval = false; + } + } + DT_Mdep_Free (hdlptr); + } + } /* End CNO handling */ + + /* ----------- + * EVD handling + */ + if (depth > LIM_EVD) + { + /* + * The abuse is not for us this time, just prep Obj_Set. + */ + unsigned int w; + DAT_EVD_FLAGS flags = ( DAT_EVD_DTO_FLAG + /* | DAT_EVD_SOFTWARE_FLAG */ + | DAT_EVD_CONNECTION_FLAG + | DAT_EVD_CR_FLAG + | DAT_EVD_RMR_BIND_FLAG ); /* not ASYNC */ + + DT_Mdep_debug (("%s: dat_evd_create X %d\n", module, cmd->width)); + for (w = 0; w < cmd->width; w++) + { + ret = dat_evd_create (hdl_sets[w].ia_handle, + DFLT_QLEN, + hdl_sets[w].cno_handle, + flags, + &hdl_sets[w].evd_handle); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_evd_create #%d fails: %s\n", + module, w+1, DT_RetToString (ret)); + /* handle contents undefined on failure */ + hdl_sets[w].evd_handle = DAT_HANDLE_NULL; + goto clean_up_now; + } + } + } + else if (depth == LIM_EVD) + { + /* + * See how many EVDs we can create + */ + unsigned int count = START_COUNT; + DAT_EVD_HANDLE *hdlptr = (DAT_EVD_HANDLE *) + DT_Mdep_Malloc (count * sizeof (*hdlptr)); + DAT_EVD_FLAGS flags = ( DAT_EVD_DTO_FLAG + | DAT_EVD_RMR_BIND_FLAG + | DAT_EVD_CONNECTION_FLAG + | DAT_EVD_CR_FLAG); + + /* EVD Exhaustion test loop */ + if (hdlptr) + { + unsigned int w = 0; + unsigned int tmp; + + DT_Mdep_debug (("%s: Exhausting dat_evd_create\n", module)); + for (w = 0; w < cmd->maximum; w++) + { +#ifdef _ONTAP_ + sk_preempt_msec(10); +#endif + if (w == count + && !more_handles ((DAT_HANDLE **) &hdlptr, + &count, + sizeof (*hdlptr))) + { + DT_Mdep_printf ("%s: EVDs created: %d\n", module, w); + retval = true; + break; + } + ret = dat_evd_create (hdl_sets[w % cmd->width].ia_handle, + DFLT_QLEN, + hdl_sets[w % cmd->width].cno_handle, + flags, + &hdlptr[w]); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_evd_create #%d fails: %s\n", + module, w+1, DT_RetToString (ret)); + retval = true; + break; + } + } + + DT_Mdep_printf ("%s: EVDs created: %d\n", module, w); + retval = true; + + /* EVD Cleanup loop */ + for (tmp = 0; tmp < w; tmp++) + { +#ifdef _ONTAP_ + sk_preempt_msec(10); +#endif + ret = dat_evd_free (hdlptr[tmp]); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_evd_free fails: %s\n", + module, DT_RetToString (ret)); + retval = false; + } + } + DT_Mdep_Free (hdlptr); + } + } /* End EVD handling */ + + /* ----------- + * EP handling + */ + if (depth > LIM_EP) + { + /* + * The abuse is not for us this time, just prep Obj_Set. + */ + unsigned int w; + + DT_Mdep_debug (("%s: dat_ep_create X %d\n", module, cmd->width)); + for (w = 0; w < cmd->width; w++) + { + ret = dat_ep_create (hdl_sets[w].ia_handle, + hdl_sets[w].pz_handle, + hdl_sets[w].evd_handle, /* recv */ + hdl_sets[w].evd_handle, /* request */ + hdl_sets[w].evd_handle, /* connect */ + (DAT_EP_ATTR *) NULL, + &hdl_sets[w].ep_handle); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_ep_create #%d fails: %s\n", + module, w+1, DT_RetToString (ret)); + /* handle contents undefined on failure */ + hdl_sets[w].ep_handle = DAT_HANDLE_NULL; + goto clean_up_now; + } + } + } + else if (depth == LIM_EP) + { + /* + * See how many EPs we can create + */ + unsigned int count = START_COUNT; + DAT_EP_HANDLE *hdlptr = (DAT_EP_HANDLE *) + DT_Mdep_Malloc (count * sizeof (*hdlptr)); + + /* EP Exhaustion test loop */ + if (hdlptr) + { + unsigned int w = 0; + unsigned int tmp; + + DT_Mdep_debug (("%s: Exhausting dat_ep_create\n", module)); + for (w = 0; w < cmd->maximum; w++) + { +#ifdef _ONTAP_ + sk_preempt_msec(10); +#endif + if (w == count + && !more_handles ((DAT_HANDLE **) &hdlptr, + &count, + sizeof (*hdlptr))) + { + DT_Mdep_printf ("%s: EPs created: %d\n", module, w); + retval = true; + break; + } + ret = dat_ep_create (hdl_sets[w % cmd->width].ia_handle, + hdl_sets[w % cmd->width].pz_handle, + hdl_sets[w % cmd->width].evd_handle, + hdl_sets[w % cmd->width].evd_handle, + hdl_sets[w % cmd->width].evd_handle, + (DAT_EP_ATTR *) NULL, + &hdlptr[w]); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_ep_create #%d fails: %s\n", + module, w+1, DT_RetToString (ret)); + retval = true; + break; + } + } + + DT_Mdep_printf ("%s: EPs created: %d\n", module, w); + retval = true; + + /* EP Cleanup loop */ + for (tmp = 0; tmp < w; tmp++) + { +#ifdef _ONTAP_ + sk_preempt_msec(10); +#endif + ret = dat_ep_free (hdlptr[tmp]); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_ep_free fails: %s\n", + module, DT_RetToString (ret)); + retval = false; + } + } + DT_Mdep_Free (hdlptr); + } + } /* End EP handling */ + + /* ----------- + * RSP handling + * + * if (depth > LIM_RSP) { + * Since RSPs are not part of the Obj_Set, + * there's nothing to do. + * } else ... + */ + if (depth == LIM_RSP) + { + /* + * See how many RSPs we can create + */ + unsigned int count = START_COUNT; + DAT_RSP_HANDLE *hdlptr = (DAT_RSP_HANDLE *) + DT_Mdep_Malloc (count * sizeof (*hdlptr)); + DAT_EP_HANDLE *epptr = (DAT_EP_HANDLE *) + DT_Mdep_Malloc (count * sizeof (*epptr)); + + /* RSP Exhaustion test loop */ + if (hdlptr) + { + unsigned int w = 0; + unsigned int tmp; + + DT_Mdep_debug (("%s: Exhausting dat_rsp_create\n", module)); + for (w = 0; w < cmd->maximum; w++) + { +#ifdef _ONTAP_ + sk_preempt_msec(10); +#endif + if (w == count) + { + unsigned int count1 = count; + unsigned int count2 = count; + + if (!more_handles ((DAT_HANDLE **) &hdlptr, + &count1, + sizeof (*hdlptr))) + { + DT_Mdep_printf ("%s: RSPs created: %d\n", module, w); + retval = true; + break; + } + if (!more_handles ((DAT_HANDLE **) &epptr, + &count2, + sizeof (*epptr))) + { + DT_Mdep_printf ("%s: RSPs created: %d\n", module, w); + retval = true; + break; + } + + if (count1 != count2) + { + DT_Mdep_printf ("%s: Mismatch in allocation of handle arrays at point %d\n", + module, w); + retval = true; + break; + } + + count = count1; + } + + /* + * Each RSP needs a unique EP, so create one first + */ + ret = dat_ep_create (hdl_sets[w % cmd->width].ia_handle, + hdl_sets[w % cmd->width].pz_handle, + hdl_sets[w % cmd->width].evd_handle, + hdl_sets[w % cmd->width].evd_handle, + hdl_sets[w % cmd->width].evd_handle, + (DAT_EP_ATTR *) NULL, + &epptr[w]); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_ep_create #%d fails: %s testing RSPs\n", + module, w+1, DT_RetToString (ret)); + retval = true; + break; + } + + ret = dat_rsp_create (hdl_sets[w % cmd->width].ia_handle, + CONN_QUAL0 + w, + epptr[w], + hdl_sets[w % cmd->width].evd_handle, + &hdlptr[w]); + if (DAT_GET_TYPE(ret) == DAT_NOT_IMPLEMENTED) + { + DT_Mdep_printf ("%s: dat_rsp_create unimplemented\n", + module); + /* ignore this error */ + retval = true; + break; + } + else if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_rsp_create #%d fails: %s\n", + module, w+1, DT_RetToString (ret)); + /* Cleanup the EP; no-one else will. */ + ret = dat_ep_free (epptr[w]); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_ep_free (internal cleanup @ #%d) fails: %s\n", + module, w+1, DT_RetToString (ret)); + } + retval = true; + break; + } + } + + DT_Mdep_printf ("%s: RSPs created: %d\n", module, w); + retval = true; + + /* RSP Cleanup loop */ + for (tmp = 0; tmp < w; tmp++) + { +#ifdef _ONTAP_ + sk_preempt_msec(10); +#endif + ret = dat_rsp_free (hdlptr[tmp]); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_rsp_free fails: %s\n", + module, DT_RetToString (ret)); + retval = false; + } + /* Free EPs */ + ret = dat_ep_free (epptr[tmp]); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_ep_free fails: %s for RSPs\n", + module, DT_RetToString (ret)); + retval = false; + } + } + DT_Mdep_Free (hdlptr); + } + } /* End RSP handling */ + + /* ----------- + * PSP handling + * + * if (depth > LIM_PSP) { + * Since PSPs are not part of the Obj_Set, + * there's nothing to do. + * } else ... + */ + if (depth == LIM_PSP) + { + /* + * See how many PSPs we can create + */ + unsigned int count = START_COUNT; + DAT_PSP_HANDLE *hdlptr = (DAT_PSP_HANDLE *) + DT_Mdep_Malloc (count * sizeof (*hdlptr)); + + /* PSP Exhaustion test loop */ + if (hdlptr) + { + unsigned int w = 0; + unsigned int tmp; + + DT_Mdep_debug (("%s: Exhausting dat_psp_create\n", module)); + for (w = 0; w < cmd->maximum; w++) + { +#ifdef _ONTAP_ + sk_preempt_msec(10); +#endif + if (w == count + && !more_handles ((DAT_HANDLE **) &hdlptr, + &count, + sizeof (*hdlptr))) + { + DT_Mdep_printf ("%s: PSPs created: %d\n", module, w); + retval = true; + break; + } + ret = dat_psp_create (hdl_sets[w % cmd->width].ia_handle, + CONN_QUAL0 + w, + hdl_sets[w % cmd->width].evd_handle, + DAT_PSP_CONSUMER_FLAG, + &hdlptr[w]); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_psp_create #%d fails: %s\n", + module, w+1, DT_RetToString (ret)); + retval = true; + hdlptr[w] = DAT_HANDLE_NULL; + break; + } + } + + DT_Mdep_printf ("%s: PSPs created: %d\n", module, w); + retval = true; + + /* PSP Cleanup loop */ + for (tmp = 0; tmp < w; tmp++) + { +#ifdef _ONTAP_ + sk_preempt_msec(10); +#endif + ret = dat_psp_free (hdlptr[tmp]); + if (DAT_GET_TYPE(ret) == DAT_NOT_IMPLEMENTED) + { + DT_Mdep_printf ("%s: dat_psp_free unimplemented\n" + "\tNB: Expect EVD+IA cleanup errors!\n", + module); + break; + } + else if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_psp_free fails: %s\n", + module, DT_RetToString (ret)); + retval = false; + } + } + DT_Mdep_Free (hdlptr); + } + } /* End PSP handling */ + + /* ----------- + * LMR handling + */ + if (depth > LIM_LMR) + { + /* + * The abuse is not for us this time, just prep Obj_Set. + */ + unsigned int w; + + DT_Mdep_debug (("%s: dat_lmr_create X %d\n", module, cmd->width)); + for (w = 0; w < cmd->width; w++) + { + DAT_REGION_DESCRIPTION region; + DAT_VLEN reg_size; + DAT_VADDR reg_addr; + + hdl_sets[w].lmr_buffer = DT_Mdep_Malloc (DFLT_BUFFSZ); + if (!hdl_sets[w].lmr_buffer) + { + DT_Mdep_printf ("%s: no memory for LMR buffers\n", module); + goto clean_up_now; + } + memset (®ion, 0, sizeof (region)); + region.for_va = hdl_sets[w].lmr_buffer; + + ret = dat_lmr_create (hdl_sets[w].ia_handle, + DAT_MEM_TYPE_VIRTUAL, + region, + DFLT_BUFFSZ, + hdl_sets[w].pz_handle, + DAT_MEM_PRIV_ALL_FLAG, + &hdl_sets[w].lmr_handle, + &hdl_sets[w].lmr_context, + NULL, /* FIXME */ + ®_size, ®_addr); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_lmr_create #%d fails: %s\n", + module, w+1, DT_RetToString (ret)); + /* handle contents undefined on failure */ + hdl_sets[w].lmr_handle = DAT_HANDLE_NULL; + goto clean_up_now; + } + if ((uintptr_t)reg_addr > (uintptr_t)hdl_sets[w].lmr_buffer + || (reg_size < DFLT_BUFFSZ + ((uintptr_t)reg_addr + - (uintptr_t)hdl_sets[w].lmr_buffer))) + { + DT_Mdep_printf ("%s: dat_lmr_create bogus outputs " + "in: 0x%p, %x out 0x%llx, %llx\n", + module, + hdl_sets[w].lmr_buffer, DFLT_BUFFSZ, + (DAT_UVERYLONG)reg_addr, (DAT_UVERYLONG)reg_size); + goto clean_up_now; + } + } + } + else if (depth == LIM_LMR) + { + /* + * See how many LMRs we can create + */ + unsigned int count = START_COUNT; + Bpool **hdlptr = (Bpool **) + DT_Mdep_Malloc (count * sizeof (*hdlptr)); + + /* LMR Exhaustion test loop */ + if (hdlptr) + { + unsigned int w = 0; + unsigned int tmp; + + DT_Mdep_debug (("%s: Exhausting dat_lmr_create\n", module)); + for (w = 0; w < cmd->maximum; w++) + { +#ifdef _ONTAP_ + sk_preempt_msec(10); +#endif + if (w == count + && !more_handles ((DAT_HANDLE **) &hdlptr, + &count, + sizeof (*hdlptr))) + { + DT_Mdep_printf ("%s: no memory for LMR handles\n", + module); + DT_Mdep_printf ("%s: LMRs created: %d\n", module, w); + retval = true; + break; + } + /* + * Let BpoolAlloc do the hard work; this means that + * we're testing unique memory registrations rather + * than repeatedly binding the same buffer set. + */ + hdlptr[w] = DT_BpoolAlloc ((Per_Test_Data_t *)0, + hdl_sets[w % cmd->width].ia_handle, + hdl_sets[w % cmd->width].pz_handle, + hdl_sets[w % cmd->width].ep_handle, + hdl_sets[w % cmd->width].evd_handle, + DFLT_BUFFSZ, + 1, + DAT_OPTIMAL_ALIGNMENT, + false, + false); + if (!hdlptr[w]) + { + DT_Mdep_printf ("%s: LMRs created: %d\n", module, w); + retval = true; + break; + } + } + + DT_Mdep_printf ("%s: LMRs created: %d\n", module, w); + retval = true; + + /* LMR Cleanup loop */ + for (tmp = 0; tmp <= w; tmp++) + { +#ifdef _ONTAP_ + sk_preempt_msec(10); +#endif + if (hdlptr[tmp]) + { + /* ignore rval - DT_Bpool_Destroy will complain */ + (void) DT_Bpool_Destroy ((Per_Test_Data_t *)0, hdlptr[tmp]); + } + } + DT_Mdep_Free (hdlptr); + } + } /* End LMR handling */ + + /* ----------- + * Posted receive buffer handling + */ + if (depth == LIM_RPOST) + { + /* + * See how many receive buffers we can post (to each EP). + * We are posting the same buffer 'cnt' times, deliberately, + * but that should be OK. + */ + unsigned int count = START_COUNT; + DAT_LMR_TRIPLET *hdlptr = (DAT_LMR_TRIPLET *) + DT_Mdep_Malloc (count * cmd->width * sizeof (*hdlptr)); + + /* Recv-Post Exhaustion test loop */ + if (hdlptr) + { + unsigned int w = 0; + unsigned int i = 0; + unsigned int done = 0; + + DT_Mdep_debug (("%s: Exhausting posting of recv buffers\n", module)); + for (w = 0; w < cmd->maximum && !done; w++) + { +#ifdef _ONTAP_ + sk_preempt_msec(10); +#endif + if (w == count + && !more_handles ((DAT_HANDLE **) &hdlptr, + &count, + cmd->width * sizeof (*hdlptr))) + { + DT_Mdep_printf ("%s: no memory for IOVs \n", + module); + DT_Mdep_printf ("%s: recv buffers posted per EP: %d\n" + "\t\t (total posted: %d)\n", + module, + w, + w * cmd->width); + done = retval = true; + break; + } + for (i = 0; i < cmd->width; i++) + { + DAT_LMR_TRIPLET *iovp = &hdlptr[w * cmd->width + i]; + DAT_DTO_COOKIE cookie; + + iovp->virtual_address = (DAT_VADDR) (uintptr_t) + hdl_sets[i].lmr_buffer; + iovp->segment_length = DFLT_BUFFSZ; + iovp->lmr_context = hdl_sets[i].lmr_context; + cookie.as_64 = (DAT_UINT64)0UL; + cookie.as_ptr = (DAT_PVOID) hdl_sets[i].lmr_buffer; + + DT_Mdep_printf ("%s: dat_ep_post_recv #%d\n", module, + w * cmd->width + i + 1); + ret = dat_ep_post_recv (hdl_sets[i].ep_handle, + 1, + iovp, + cookie, + DAT_COMPLETION_DEFAULT_FLAG); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_ep_post_recv fails: %s\n", + module, DT_RetToString (ret)); + DT_Mdep_printf ("%s: recv buffers posted per EP: %d\n" + "\t\t (total posted: %d)\n", + module, + w, + w * cmd->width + i); + done = retval = true; + break; + } + } /* end for each EP wide */ + } /* end forever (!done) loop */ + + retval = true; + DT_Mdep_printf ("%s: recv buffers posted per EP: %d\n" + "\t\t (total posted: %d)\n", + module, + w, + w * cmd->width); + + /* Rpost Cleanup loop */ + for (i = 0; i < cmd->width; i++) + { + DAT_EVENT event; + + /* + * Disconnecting an unconnected EP should complete + * outstanding recv DTOs in error, and otherwise + * be a no-op. + */ + ret = dat_ep_disconnect (hdl_sets[i].ep_handle, + DAT_CLOSE_ABRUPT_FLAG); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_ep_disconnect (abrupt) fails: %s\n", + module, DT_RetToString (ret)); + retval = false; + } + else + { + /* + * Remove all DTOs. The disconnect above should have + * flushed all posted operations, so this is just a + * clean up. + */ + do + { + ret = dat_evd_dequeue ( hdl_sets[i].evd_handle, + &event); + } while ( DAT_GET_TYPE(ret) != DAT_QUEUE_EMPTY ); + } + + } + DT_Mdep_Free (hdlptr); + } + } /* end depth == LIM_RPOST */ + + /* ----------- + * Test maximum size of LMR allowed + */ + if (depth == LIM_SIZE_LMR) + { + DAT_COUNT last_size = 0; + DAT_COUNT test_size = DFLT_BUFFSZ; + + for (;;) + { +#ifdef _ONTAP_ + sk_preempt_msec(10); +#endif + Bpool *test_bpool = DT_BpoolAlloc ((Per_Test_Data_t *)0, + hdl_sets[0].ia_handle, + hdl_sets[0].pz_handle, + hdl_sets[0].ep_handle, + hdl_sets[0].evd_handle, + test_size, + 1, + DAT_OPTIMAL_ALIGNMENT, + false, + false); + + if (!test_bpool) + { + DT_Mdep_printf ("%s: Largest LMR was 0x%x bytes\n" + "\t (failed attempting 0x%x bytes)\n", + module, last_size, test_size); + retval = true; + break; + } + else if (!DT_Bpool_Destroy ((Per_Test_Data_t *)0, test_bpool)) + { + DT_Mdep_printf ("%s: Largest LMR was 0x%x bytes\n", + module, test_size); + retval = true; + break; + } + + last_size = test_size; + test_size <<= 1; + if (test_size < last_size) + { + /* could conceivably wrap on 32-bit architectures */ + DT_Mdep_printf ("%s: LMR of 0x%x bytes OK - %s\n", + module, last_size, "stopping now."); + retval = true; + break; + } + } /* end forever loop */ + } /* end depth == LIM_SIZE_LMR */ + + DT_Mdep_debug (("%s: Limit Testing Completed - %s\n", + module, + retval ? "Successfully" : "with errors")); + + + /* ---------------------------------------------------------- + * Clean up and go home + */ +clean_up_now: + + DT_Mdep_debug (("%s: Cleaning up ...\n", module)); + + if (depth > LIM_LMR) + { + unsigned int w; + + for (w = 0; w < cmd->width; w++) + { + if (hdl_sets[w].lmr_handle) + { + ret = dat_lmr_free (hdl_sets[w].lmr_handle); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_lmr_free fails: %s\n", + module, DT_RetToString (ret)); + retval = false; + } + } + if ((void *) hdl_sets[w].lmr_buffer) + { + DT_Mdep_Free ((void *) hdl_sets[w].lmr_buffer); + } + } + } /* end LIM_LMR cleanup */ + + /* + * if (depth == LIM_PSP) { + * Since PSPs are not part of the Obj_Set, + * there's no cleanup to do. + * } + * + * if (depth == LIM_RSP) { + * Since RSPs are not part of the Obj_Set, + * there'no cleanup nothing to do. + * } + */ + + if (depth > LIM_EP) + { + unsigned int w; + + for (w = 0; w < cmd->width; w++) + { + if (hdl_sets[w].ep_handle) + { + ret = dat_ep_free (hdl_sets[w].ep_handle); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_ep_free fails: %s\n", + module, DT_RetToString (ret)); + retval = false; + } + } + } + } /* end LIM_EP cleanup */ + + if (depth > LIM_EVD) + { + unsigned int w; + + for (w = 0; w < cmd->width; w++) + { + if (hdl_sets[w].evd_handle) + { + ret = dat_evd_free (hdl_sets[w].evd_handle); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_evd_free fails: %s\n", + module, DT_RetToString (ret)); + retval = false; + } + } + } + } /* end LIM_EVD cleanup */ + + if (depth > LIM_CNO) + { + unsigned int w; + + for (w = 0; w < cmd->width; w++) + { + if (hdl_sets[w].cno_handle) + { + ret = dat_cno_free (hdl_sets[w].cno_handle); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_cno_free fails: %s\n", + module, DT_RetToString (ret)); + retval = false; + } + } + } + } /* end LIM_CNO cleanup */ + + if (depth > LIM_PZ) + { + unsigned int w; + + for (w = 0; w < cmd->width; w++) + { + if (hdl_sets[w].pz_handle) + { + ret = dat_pz_free (hdl_sets[w].pz_handle); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_pz_free fails: %s\n", + module, DT_RetToString (ret)); + retval = false; + } + } + } + } /* end LIM_PZ cleanup */ + + if (depth > LIM_IA) + { + unsigned int w; + + for (w = 0; w < cmd->width; w++) + { + if (hdl_sets[w].ia_handle) + { + /* DT_ia_close cleans up async evd handle, too */ + ret = DT_ia_close (hdl_sets[w].ia_handle, + DAT_CLOSE_GRACEFUL_FLAG); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: DT_ia_close (graceful) error: %s\n", + module, DT_RetToString (ret)); + /* + * Since we take some pains to clean up properly, + * this really is an error. But if we get here, + * we may as well try the largest hammer we have. + */ + retval = false; + ret = DT_ia_close (hdl_sets[w].ia_handle, + DAT_CLOSE_ABRUPT_FLAG); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: DT_ia_close (abrupt) error: %s\n", + module, DT_RetToString (ret)); + } + } + } + } + } /* end LIM_IA cleanup */ + + if (depth && hdl_sets) + { + DT_Mdep_Free (hdl_sets); + } + + DT_Mdep_debug (("%s: testing and cleanup complete.\n", module)); + + return ( retval ); +} + + +/********************************************************************* + * Framework to run through all of the limit tests + */ +void +DT_cs_Limit (Limit_Cmd_t * cmd) +{ + char *star = + "**********************************************************************" ; + + if (cmd->Test_List[ LIM_IA ]) + { + char list[] = + { + "Limitation Test limit_ia\n" + "Description: Test max num of opens for the same physical IA" + } + ; + + DT_Mdep_printf ("%s\n", star); + DT_Mdep_printf ("%s\n", list); + if (!limit_test (cmd, LIM_IA)) + { + goto error; + } + DT_Mdep_printf ("%s\n", star); + } + + if (cmd->Test_List[ LIM_PZ ]) + { + char list[] = + { + "Limitation Test limit_pz\n" + "Description: Test max num of PZs that are supported by an IA" + } + ; + + DT_Mdep_printf ("%s\n", star); + DT_Mdep_printf ("%s\n", list); + if (!limit_test (cmd, LIM_PZ)) + { + goto error; + } + DT_Mdep_printf ("%s\n", star); + } + + if (cmd->Test_List[ LIM_CNO ]) + { + char list[] = + { + "Limitation Test limit_cno\n" + "Description: Test max num of CNOs that are supported by an IA" + } + ; + + DT_Mdep_printf ("%s\n", star); + DT_Mdep_printf ("%s\n", list); + if (!limit_test (cmd, LIM_CNO)) + { + goto error; + } + DT_Mdep_printf ("%s\n", star); + } + + if (cmd->Test_List[ LIM_EVD ]) + { + char list[] = + { + "Limitation Test limit_evd\n" + "Description: Test max num of EVDs that are supported by an IA" + } + ; + + DT_Mdep_printf ("%s\n", star); + DT_Mdep_printf ("%s\n", list); + if (!limit_test (cmd, LIM_EVD)) + { + goto error; + } + DT_Mdep_printf ("%s\n", star); + } + + if (cmd->Test_List[ LIM_EP ]) + { + char list[] = + { + "Limitation Test limit_ep\n" + "Description: Test max num of EPs that are supported by an IA" + } + ; + + DT_Mdep_printf ("%s\n", star); + DT_Mdep_printf ("%s\n", list); + if (!limit_test (cmd, LIM_EP)) + { + goto error; + } + DT_Mdep_printf ("%s\n", star); + } + + if (cmd->Test_List[ LIM_RSP ]) + { + char list[] = + { + "Limitation Test limit_rsp\n" + "Description: Test max num of RSPs that are supported by an IA" + } + ; + + DT_Mdep_printf ("%s\n", star); + DT_Mdep_printf ("%s\n", list); + if (!limit_test (cmd, LIM_RSP)) + { + goto error; + } + DT_Mdep_printf ("%s\n", star); + } + + if (cmd->Test_List[ LIM_PSP ]) + { + char list[] = + { + "Limitation Test limit_psp\n" + "Description: Test max num of PSPs that are supported by an IA" + } + ; + + DT_Mdep_printf ("%s\n", star); + DT_Mdep_printf ("%s\n", list); + if (!limit_test (cmd, LIM_PSP)) + { + goto error; + } + DT_Mdep_printf ("%s\n", star); + } + + if (cmd->Test_List[ LIM_LMR ]) + { + char list[] = + { + "Limitation Test limit_lmr\n" + "Description: Test max num of LMRs that are supported by an IA" + } + ; + + DT_Mdep_printf ("%s\n", star); + DT_Mdep_printf ("%s\n", list); + if (!limit_test (cmd, LIM_LMR)) + { + goto error; + } + DT_Mdep_printf ("%s\n", star); + } + + if (cmd->Test_List[ LIM_RPOST ]) + { + char list[] = + { + "Limitation Test limit_rpost\n" + "Description: Test max num of receive buffers posted to an EP" + } + ; + + DT_Mdep_printf ("%s\n", star); + DT_Mdep_printf ("%s\n", list); + if (!limit_test (cmd, LIM_RPOST)) + { + goto error; + } + DT_Mdep_printf ("%s\n", star); + } + + if (cmd->Test_List[ LIM_SIZE_LMR ]) + { + char list[] = + { + "Limitation Test limit_size_lmr\n" + "Description: Test max size of LMRs that are supported by an IA" + } + ; + + DT_Mdep_printf ("%s\n", star); + DT_Mdep_printf ("%s\n", list); + if (!limit_test (cmd, LIM_SIZE_LMR)) + { + goto error; + } + DT_Mdep_printf ("%s\n", star); + } + + /* More tests TBS ... */ + + return; + +error: + DT_Mdep_printf ("error occurs, can not continue with limit test\n"); + DT_Mdep_printf ("%s\n", star); + return; +} + diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_limit_cmd.c b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_limit_cmd.c new file mode 100644 index 00000000..3fe9347c --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_limit_cmd.c @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_test_data.h" +#include "dapl_mdep.h" +#include "dapl_proto.h" +#include "dapl_limit_cmd.h" + +/* --------------------------------------------------- */ +void +DT_Limit_Cmd_Init (Limit_Cmd_t * cmd) +{ + memset ((void *) cmd, 0, sizeof (Limit_Cmd_t)); + cmd->ReliabilityLevel = DAT_QOS_BEST_EFFORT; + cmd->width = 1; + cmd->maximum = ~0U; +} + +/* --------------------------------------------------- */ +bool +DT_Limit_Cmd_Parse ( Limit_Cmd_t * cmd, + int my_argc, + char **my_argv, + mygetopt_t * opts) +{ + char c; + int i; + + for (;;) + { + c = DT_mygetopt_r (my_argc, my_argv, "dm:w:D:R:", opts); + if (c == EOF) + { + break; + } + switch (c) + { + case 'D': /* device name */ + { + strcpy (cmd->device_name, opts->optarg); + break; + } + case 'R': /* Service Reliability Level */ + { + cmd->ReliabilityLevel = DT_ParseQoS (opts->optarg); + break; + } + case 'd': /* print debug messages */ + { + DT_dapltest_debug++; + cmd->debug = true; + break; + } + case 'm': /* maximum for exhaustion testing */ + { + unsigned int len = (unsigned int)strspn (opts->optarg, "0123456789"); + + if (len == 0 || len != strlen (opts->optarg)) + { + DT_Mdep_printf ("Syntax Error -m option\n"); + DT_Limit_Cmd_Usage (); + return (false); + } + cmd->maximum = atol (opts->optarg); + break; + } + case 'w': /* width (number of {ia,evd,ep,...} sets) */ + { + unsigned int len = (unsigned int)strspn (opts->optarg, "0123456789"); + + if (len == 0 || len != strlen (opts->optarg)) + { + DT_Mdep_printf ("Syntax Error -w option\n"); + DT_Limit_Cmd_Usage (); + return (false); + } + cmd->width = atol (opts->optarg); + break; + } + case '?': + default: + { + DT_Mdep_printf ("Invalid Limit Test Parameter: %c\n", c); + DT_Limit_Cmd_Usage (); + return (false); + } + } + } + if (cmd->device_name[0] == '\0') + { + if (!DT_Mdep_GetDefaultDeviceName (cmd->device_name)) + { + DT_Mdep_printf ("can't get default device name\n"); + DT_Limit_Cmd_Usage (); + return (false); + } + } + + /* + * by default: test all limit tests + * otherwise: parse the remaining limit test arguments + */ + if (opts->optind == my_argc) + { + for (i = 0; i < LIM_NUM_TESTS; i++) + { + cmd->Test_List[i] = 1; + } + } + else + { + for (i = opts->optind; i < my_argc; i++) + { + + if (strcmp (my_argv[i], "limit_ia") == 0) + { + cmd->Test_List[LIM_IA] = 1; + continue; + } + if (strcmp (my_argv[i], "limit_pz") == 0) + { + cmd->Test_List[LIM_PZ] = 1; + continue; + } + if (strcmp (my_argv[i], "limit_cno") == 0) + { + cmd->Test_List[LIM_CNO] = 1; + continue; + } + if (strcmp (my_argv[i], "limit_evd") == 0) + { + cmd->Test_List[LIM_EVD] = 1; + continue; + } + if (strcmp (my_argv[i], "limit_ep") == 0) + { + cmd->Test_List[LIM_EP] = 1; + continue; + } + if (strcmp (my_argv[i], "limit_rsp") == 0) + { + cmd->Test_List[LIM_RSP] = 1; + continue; + } + if (strcmp (my_argv[i], "limit_psp") == 0) + { + cmd->Test_List[LIM_PSP] = 1; + continue; + } + if (strcmp (my_argv[i], "limit_lmr") == 0) + { + cmd->Test_List[LIM_LMR] = 1; + continue; + } + if (strcmp (my_argv[i], "limit_rpost") == 0) + { + cmd->Test_List[LIM_RPOST] = 1; + continue; + } + if (strcmp (my_argv[i], "limit_size_lmr") == 0) + { + cmd->Test_List[LIM_SIZE_LMR] = 1; + continue; + } + + DT_Mdep_printf ("Cannot find this limit test: %s\n", my_argv[i]); + DT_Limit_Cmd_Usage (); + return (false); + + } /* end foreach remaining argv */ + } + + return (true); +} + +/* --------------------------------------------------- */ +void +DT_Limit_Cmd_Usage (void) +{ + DT_Mdep_printf ("USAGE: ---- LIMIT TEST ----\n"); + DT_Mdep_printf ("USAGE: dapltest -T L\n"); + DT_Mdep_printf ("USAGE: [-D ]\n"); + DT_Mdep_printf ("USAGE: [-d] : debug (zero)\n"); + DT_Mdep_printf ("USAGE: [-w ]\n"); + DT_Mdep_printf ("USAGE: [-m ]\n"); + DT_Mdep_printf ("USAGE: [-R ]\n"); + DT_Mdep_printf ("USAGE: (BE == QOS_BEST_EFFORT - Default)\n"); + DT_Mdep_printf ("USAGE: (HT == QOS_HIGH_THROUGHPUT)\n"); + DT_Mdep_printf ("USAGE: (LL == QOS_LOW_LATENCY)\n"); + DT_Mdep_printf ("USAGE: (EC == QOS_ECONOMY)\n"); + DT_Mdep_printf ("USAGE: (PM == QOS_PREMIUM)\n"); + DT_Mdep_printf ("USAGE: [limit_ia [limit_pz] [limit_cno] ... ]\n"); + DT_Mdep_printf ("NOTE: If test is not specified, do all the limit tests\n"); + DT_Mdep_printf ("NOTE: Else, just do the specified tests\n"); + DT_Mdep_printf ("NOTE: Each test is separated by space, the test can be:\n"); + + DT_Mdep_printf ("NOTE: [limit_ia] test max num of open IAs\n"); + DT_Mdep_printf ("NOTE: [limit_pz] test max num of PZs\n"); + DT_Mdep_printf ("NOTE: [limit_cno] test max num of CNOs\n"); + DT_Mdep_printf ("NOTE: [limit_evd] test max num of EVDs\n"); + DT_Mdep_printf ("NOTE: [limit_rsp] test max num of RSPs\n"); + DT_Mdep_printf ("NOTE: [limit_psp] test max num of PSPs\n"); + DT_Mdep_printf ("NOTE: [limit_ep] test max num of EPs\n"); + DT_Mdep_printf ("NOTE: [limit_lmr] test max num of LMRs\n"); + DT_Mdep_printf ("NOTE: [limit_rpost] test max num of recvs posted\n"); + DT_Mdep_printf ("NOTE: [limit_size_lmr] test max size of LMR\n"); +} diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_limit_cmd.h b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_limit_cmd.h new file mode 100644 index 00000000..4d495deb --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_limit_cmd.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#ifndef __DAPL_LIMIT_CMD_H__ +#define __DAPL_LIMIT_CMD_H__ + +#include "dapl_mdep.h" + +typedef enum +{ + LIM_IA, + LIM_PZ, + LIM_CNO, + LIM_EVD, + LIM_EP, + LIM_RSP, + LIM_PSP, + LIM_LMR, + LIM_RPOST, + LIM_SIZE_LMR, + /* add further tests here */ + + LIM_NUM_TESTS /* for array size & limit checks */ +} Limit_Index; + +//------------------------------------- +typedef struct +{ + char device_name[256]; /* -D */ + DAT_QOS ReliabilityLevel; /* -R */ + DAT_UINT32 width; /* -w */ + DAT_UINT32 debug; /* -d */ + DAT_UINT32 maximum; /* -m */ + DAT_UINT32 Test_List[ LIM_NUM_TESTS ]; +} Limit_Cmd_t; + +#endif diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_main.c b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_main.c new file mode 100644 index 00000000..2a1b2083 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_main.c @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_test_data.h" +#include "dapl_mdep.h" +#include "dapl_memlist.h" +#include "dapl_proto.h" + +#include "dapl_transaction_cmd.h" +#include "dapl_performance_cmd.h" +#include "dapl_quit_cmd.h" +#include "dapl_limit_cmd.h" + +DT_Mdep_LockType g_PerfTestLock; + + +/* Main Entry Point */ +int __cdecl +main (int argc, char *argv[]) +{ + return ( dapltest (argc, argv) ); +} + + +/* + * dapltest main program + */ +int +dapltest (int argc, char *argv[]) +{ + Params_t *params_ptr; + Transaction_Cmd_t *Transaction_Cmd; + Performance_Cmd_t *Performance_Cmd; + Quit_Cmd_t *Quit_Cmd; + Limit_Cmd_t *Limit_Cmd; + FFT_Cmd_t *FFT_Cmd; + + /* check memory leaking */ + /* + * DT_Mdep_LockInit(&Alloc_Count_Lock); alloc_count = 0; + */ + +#if defined(WIN32) + /* Cannot be done from DT_Mdep_Init as dapl_init makes some socket + * calls....So need to do this before calling dapl_init */ + WORD wversion = MAKEWORD (2, 2); + WSADATA wsaData; + int wsa_ret = WSAStartup (wversion, &wsaData); + if ( wsa_ret != 0 ) + { DT_Mdep_printf("WinSock Init return err = %u\n", wsa_ret); + return (wsa_ret); + } +#endif + + DT_Mdep_LockInit(&g_PerfTestLock); + +#ifdef GPROF + { + extern void dapl_init (void);dapl_init (); + } +#endif + DT_dapltest_debug = 0; + + params_ptr = (Params_t *) DT_Mdep_Malloc (sizeof (Params_t)); + if (!params_ptr) + { + DT_Mdep_printf ("Cannot allocate memory for Params structure\n"); + return ( 1 ); + } + + DT_Endian_Init (); /* init endian of local machine */ + if ( !DT_Mdep_Init ()) /* init OS, libraries, etc. */ + { + DT_Mdep_printf ("Failed To Load Dat Library\n"); + return 1; + } + /* + * parse command line arguments + */ + if (!DT_Params_Parse (argc, argv, params_ptr)) + { + DT_Mdep_printf ("Command line syntax error\n"); + return 1; + } + switch (params_ptr->test_type) + { + case SERVER_TEST: + { + DT_cs_Server (params_ptr); + break; + } + case TRANSACTION_TEST: + { + Transaction_Cmd = ¶ms_ptr->u.Transaction_Cmd; + DT_cs_Client ( params_ptr, + Transaction_Cmd->dapl_name, + Transaction_Cmd->server_name, + Transaction_Cmd->num_threads * + Transaction_Cmd->eps_per_thread); + break; + } + case PERFORMANCE_TEST: + { + Performance_Cmd = ¶ms_ptr->u.Performance_Cmd; + DT_cs_Client ( params_ptr, + Performance_Cmd->dapl_name, + Performance_Cmd->server_name, + 1); + break; + } + case QUIT_TEST: + { + Quit_Cmd = ¶ms_ptr->u.Quit_Cmd; + DT_cs_Client ( params_ptr, + Quit_Cmd->device_name, + Quit_Cmd->server_name, + 0); + break; + } + case LIMIT_TEST: + { + Limit_Cmd = ¶ms_ptr->u.Limit_Cmd; + DT_cs_Limit (Limit_Cmd); + break; + } + case FFT_TEST: + { + FFT_Cmd = ¶ms_ptr->u.FFT_Cmd; + DT_cs_FFT (FFT_Cmd); + break; + } + } + + /* cleanup */ + + DT_Mdep_End (); + DT_Mdep_Free (params_ptr); +#ifdef GPROF + { + extern void dapl_fini (void);dapl_fini (); + } +#endif + + /* + * check memory leaking DT_Mdep_printf("App allocated Memory left: %d\n", + * alloc_count); DT_Mdep_LockDestroy(&Alloc_Count_Lock); + */ + + DT_Mdep_LockDestroy(&g_PerfTestLock); + + return ( 0 ); +} + + +void +Dapltest_Main_Usage (void) +{ + DT_Mdep_printf ("USAGE:\n"); + DT_Mdep_printf ("USAGE: dapltest -T [test-specific args]\n"); + DT_Mdep_printf ("USAGE: where \n"); + DT_Mdep_printf ("USAGE: S = Run as a server\n"); + DT_Mdep_printf ("USAGE: T = Transaction Test\n"); + DT_Mdep_printf ("USAGE: Q = Quit Test\n"); + DT_Mdep_printf ("USAGE: L = Limit Test\n"); + DT_Mdep_printf ("USAGE: F = FFT Test\n"); + DT_Mdep_printf ("USAGE:\n"); + DT_Mdep_printf ("NOTE:\tRun as server taking defaults (dapltest -T S)\n"); + DT_Mdep_printf ("NOTE: dapltest\n"); + DT_Mdep_printf ("NOTE:\n"); + DT_Mdep_printf ("NOTE:\tdapltest arguments may be supplied in a script file\n"); + DT_Mdep_printf ("NOTE:\tdapltest -f \n"); + DT_Mdep_printf ("USAGE:\n"); +} diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_mdep.c b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_mdep.c new file mode 100644 index 00000000..8f205bf6 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_mdep.c @@ -0,0 +1,943 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_mdep.h" +#include "dapl_proto.h" + + + +#if defined(__linux__) +#include /* needed for pthread_atfork() */ +#include +#include /* needed for getenv() */ +#include /* needed for thread setup */ + +#include +#include +#include +#include +#include +#include +#include +#include /* for printf */ +#include +#include +#include /* for getaddrinfo */ + +/* + * Include files for setting up a network name + */ +#include +#include +#include +#include + +#elif defined(__solaris__) +#include +#include +#include +#include /* needed for getenv() */ +#include /* needed for pthread_atfork() */ +#include /* needed for thread setup */ + +#elif defined(WIN32) || defined(_WIN64) +#include +#else +#error "Undefined Platform" +#endif + +#if defined(__linux__) +static FILE *Stat_Fp = NULL; +# define DT_STAT_FILE "/proc/stat" +#endif + +#include "dapl_test_data.h" /* for alloc_count */ + + +/* + * Machine dependant initialization + */ + +bool +DT_Mdep_Init (void) +{ +#if defined(__linux__) + Stat_Fp = fopen (DT_STAT_FILE, "r"); + if ( NULL == Stat_Fp ) + { + perror ("fopen of " DT_STAT_FILE " failed"); + exit (1); + } +#elif defined(__solaris__) + /* nothing */ +#elif defined(WIN32) + #ifdef DYNAMIC_DAT_LOADING + bool status = false; + HMODULE library_handle; + if ( (library_handle = LoadLibrary(DAT_DLL_LIB)) == NULL ) + { + DT_Mdep_printf("DAT: library load failure\n"); + return status; + } + dat_open = (DAT_IA_OPENV_FUNC)GetProcAddress(library_handle, (LPCSTR)DAT_LIB_OPEN_ENTRY); + dat_close =(DAT_IA_CLOSE_FUNC)GetProcAddress(library_handle, (LPCSTR)DAT_LIB_CLOSE_ENTRY); + if (dat_open != NULL && dat_close != NULL ) + { + status = true; + } + if ( status != true ) + { + DT_Mdep_printf("DAT: Failured to get ProcAddress of dat_open/dat_close\n"); + } + return status; + #else + /* + * Application shouled be explicitly linked to dat.lib + */ + return true; + #endif //DYNAMIC_DAT_LOADING +#else + #error "Undefined Platform" +#endif +} + +/* + * Machine dependant deinitialization + */ + +void +DT_Mdep_End (void) +{ +#if defined(__linux__) + if ( 0 != fclose (Stat_Fp) ) + { + perror ("fclose of " DT_STAT_FILE " failed"); + exit (1); + } +#elif defined(__solaris__) + /* nothing */ +#elif defined(WIN32) + WSACleanup (); +#else + #error "Undefined Platform" +#endif +} + +/* + * Generate name of IB device + */ + +bool +DT_Mdep_GetDefaultDeviceName (char *dapl_name) +{ + strcpy (dapl_name, DT_MdepDeviceName); + return true; +} + +/* + * Sleep specified number of milliseconds + */ + +void +DT_Mdep_Sleep (int msec) +{ +#if defined(__linux__) + struct timespec t; + t.tv_sec = msec / 1000; /* Whole seconds */ + t.tv_nsec = (msec % 1000) * 1000 * 1000; + nanosleep (&t, 0); +#elif defined(__solaris__) + struct timespec t; + t.tv_sec = msec / 1000; /* Whole seconds */ + t.tv_nsec = (msec % 1000) * 1000 * 1000; + nanosleep (&t, 0); +#elif defined(WIN32) + Sleep (msec); +#else + #error "Undefined Platform" +#endif +} + +/* + * Get system statistics including uptime and idle time + */ + +bool +DT_Mdep_GetCpuStat ( + DT_CpuStat *cpu_stat ) +{ +#if defined(__linux__) + + #define DT_CPU_STAT_STR "cpu" + #define DT_CPU_STAT_BUFFER_SIZE 1024 + #define DT_CPU_STAT_DELIMITER " " + + static char buffer[DT_CPU_STAT_BUFFER_SIZE]; + + if ( 0 != fflush (Stat_Fp) ) + { + perror ("fflush of " DT_STAT_FILE " failed"); + exit (1); + } + + for (;;) + { + if ( NULL == fgets (buffer, DT_CPU_STAT_BUFFER_SIZE, Stat_Fp) ) + { + printf (DT_CPU_STAT_STR " not found\n"); + exit (1); + } + + if ( !strncmp (buffer, DT_CPU_STAT_STR, strlen (DT_CPU_STAT_STR) ) ) + { + break; + } + } + + (void) strtok (buffer, DT_CPU_STAT_DELIMITER); + cpu_stat->user = strtoul (strtok (NULL, DT_CPU_STAT_DELIMITER), NULL, 0); + cpu_stat->user += strtoul (strtok (NULL, DT_CPU_STAT_DELIMITER), NULL, 0); + cpu_stat->system = strtoul (strtok (NULL, DT_CPU_STAT_DELIMITER), NULL, 0); + cpu_stat->idle = strtoul (strtok (NULL, DT_CPU_STAT_DELIMITER), NULL, 0); + + rewind (Stat_Fp); + + return true; + +#elif defined(__solaris__) + /* FIXME not implemented */ + return true; +#elif defined(WIN32) + /* FIXME not implemented */ + return true; +#else + #error "Undefined Platform" +#endif +} + +/* + * Get current time in milliseconds (relative to some fixed point) + */ +unsigned long +DT_Mdep_GetTime (void) +{ +#if defined(__linux__) + struct tms ts; + clock_t t = times (&ts); + return (unsigned long) ((DAT_UINT64) t * 1000 / CLK_TCK); +#elif defined(__solaris__) + struct tms ts; + clock_t t = times (&ts); + return (unsigned long) ((DAT_UINT64) t * 1000 / CLK_TCK); +#elif defined(WIN32) + return GetTickCount (); +#else + #error "Undefined Platform" +#endif +} + +double +DT_Mdep_GetCpuMhz ( + void ) +{ +#if defined(__linux__) + #define DT_CPU_MHZ_BUFFER_SIZE 128 + #define DT_CPU_MHZ_MHZ "cpu MHz" + #define DT_CPU_MHZ_DELIMITER ":" + + FILE *fp; + char buffer[DT_CPU_MHZ_BUFFER_SIZE]; + char *mhz_str; + + fp = fopen ("/proc/cpuinfo", "r"); + if ( NULL == fp ) + { + perror ("fopen of /proc/cpuinfo failed"); + exit (1); + } + + for (;;) + { + if ( NULL == fgets (buffer, DT_CPU_MHZ_BUFFER_SIZE, fp) ) + { + printf ("cpu MHZ not found\n"); + exit (1); + } + + if ( !strncmp (buffer, DT_CPU_MHZ_MHZ, strlen (DT_CPU_MHZ_MHZ) ) ) + { + (void) strtok (buffer, DT_CPU_MHZ_DELIMITER); + mhz_str = strtok (NULL, DT_CPU_MHZ_DELIMITER); + + break; + } + } + + if ( 0 != fclose (fp) ) + { + perror ("fclose of /proc/cpuinfo failed"); + exit (1); + } + + return strtod (mhz_str, NULL); +#elif defined(WIN32) + LONG retVal; + HKEY hKey; + DWORD cpuSpeed = 0; + DWORD dataSize = sizeof (DWORD); + + /* For windows need to query the registry to get the CPU + * Information...-SVSV */ + retVal = RegOpenKeyEx (HKEY_LOCAL_MACHINE, + TEXT ("Hardware\\Description\\System\\CentralProcessor\\0"), + 0, + KEY_QUERY_VALUE, + &hKey); + + if (retVal == ERROR_SUCCESS) + { + retVal = RegQueryValueEx (hKey, + TEXT ("~MHz"), NULL, NULL, + (LPBYTE)&cpuSpeed, &dataSize); + + } + + RegCloseKey (hKey); + + return cpuSpeed; +#else + #error "Undefined Platform" +#endif +} + + +unsigned long +DT_Mdep_GetContextSwitchNum (void ) +{ +#if defined(__linux__) + + #define DT_CTXT_STR "ctxt" + #define DT_CTXT_BUFFER_SIZE 1024 + #define DT_CTXT_DELIMITER " " + + static char buffer[DT_CTXT_BUFFER_SIZE]; + char *ctxt_str; + + if ( 0 != fflush (Stat_Fp) ) + { + perror ("fflush of " DT_STAT_FILE " failed"); + exit (1); + } + + for (;;) + { + if ( NULL == fgets (buffer, DT_CTXT_BUFFER_SIZE, Stat_Fp) ) + { + printf (DT_CTXT_STR " not found\n"); + exit (1); + } + + if ( !strncmp (buffer, DT_CTXT_STR, strlen (DT_CTXT_STR) ) ) + { + (void) strtok (buffer, DT_CTXT_DELIMITER); + ctxt_str = strtok (NULL, DT_CTXT_DELIMITER); + + break; + } + } + + rewind (Stat_Fp); + + return strtoul (ctxt_str, NULL, 0); +#elif defined(WIN32) + return 0; +#else + #error "Undefined Platform" +#endif +} + +/* + * Memory allocate and free routines for control blocks (objects) - regular + * memory, always zeroed. + */ +void * +DT_Mdep_Malloc (size_t l_) +{ + void *rval; + + /* + * check memory leaking DT_Mdep_Lock(&Alloc_Count_Lock); alloc_count++; + * DT_Mdep_Unlock(&Alloc_Count_Lock); + */ + +#if defined(__linux__) + rval = malloc (l_); +#elif defined(__solaris__) + rval = malloc (l_); +#elif defined(WIN32) + rval = malloc (l_); +#else + #error "Undefined Platform" +#endif + + if (rval) + { + memset (rval, 0, l_); + } + return ( rval ); +} + +void +DT_Mdep_Free (void *a_) +{ + /* + * check memory leaking DT_Mdep_Lock(&Alloc_Count_Lock); alloc_count--; + * DT_Mdep_Unlock(&Alloc_Count_Lock); + */ + +#if defined(__linux__) + free (a_); +#elif defined(__solaris__) + free (a_); +#elif defined(WIN32) + free (a_); +#else + #error "Undefined Platform" +#endif +} + +/* + * Lock support + * + * Lock object constructor + */ +bool +DT_Mdep_LockInit (DT_Mdep_LockType * lock_ptr) +{ +#if defined(__linux__) + return pthread_mutex_init (lock_ptr, 0) ? false : true; +#elif defined(__solaris__) + return pthread_mutex_init (lock_ptr, 0) ? false : true; +#elif defined(WIN32) + *lock_ptr = CreateMutex (0, FALSE, 0); + return *lock_ptr ? true : false; +#else + #error "Undefined Platform" +#endif +} + +/* + * Lock object destructor + */ +void +DT_Mdep_LockDestroy (DT_Mdep_LockType * lock_ptr) +{ +#if defined(__linux__) + pthread_mutex_destroy (lock_ptr); +#elif defined(__solaris__) + pthread_mutex_destroy (lock_ptr); +#elif defined(WIN32) + CloseHandle (*lock_ptr); +#else + #error "Undefined Platform" +#endif +} + +/* + * Lock + */ +void +DT_Mdep_Lock (DT_Mdep_LockType * lock_ptr) +{ +#if defined(__linux__) + pthread_mutex_lock (lock_ptr); +#elif defined(__solaris__) + pthread_mutex_lock (lock_ptr); +#elif defined(WIN32) + WaitForSingleObject (*lock_ptr, INFINITE); +#else + #error "Undefined Platform" +#endif +} + +/* + * unlock + */ +void +DT_Mdep_Unlock (DT_Mdep_LockType * lock_ptr) +{ +#if defined(__linux__) + pthread_mutex_unlock (lock_ptr); +#elif defined(__solaris__) + pthread_mutex_unlock (lock_ptr); +#elif defined(WIN32) + ReleaseMutex (*lock_ptr); +#else + #error "Undefined Platform" +#endif +} + +/* + * Init Thread Attributes + */ +void +DT_Mdep_Thread_Init_Attributes (Thread * thread_ptr) +{ +#if defined(__linux__) + pthread_attr_init (&thread_ptr->attr); + pthread_attr_setstacksize (&thread_ptr->attr, thread_ptr->stacksize); + /* Create thread in detached state to free resources on termination; + * this precludes doing a pthread_join, but we don't do it + */ + pthread_attr_setdetachstate (&thread_ptr->attr, PTHREAD_CREATE_DETACHED); +#elif defined(__solaris__) + pthread_attr_init (&thread_ptr->attr); + pthread_attr_setstacksize (&thread_ptr->attr, thread_ptr->stacksize); + /* Create thread in detached state to free resources on termination; + * this precludes doing a pthread_join, but we don't do it + */ + pthread_attr_setdetachstate (&thread_ptr->attr, PTHREAD_CREATE_DETACHED); + +#elif defined(WIN32) + /* nothing */ +#else + #error "Undefined Platform" +#endif +} + +/* + * Destroy Thread Attributes + */ +void +DT_Mdep_Thread_Destroy_Attributes (Thread * thread_ptr) +{ +#if defined(__linux__) + pthread_attr_destroy (&thread_ptr->attr); +#elif defined(__solaris__) + pthread_attr_destroy (&thread_ptr->attr); +#elif defined(WIN32) + /* nothing */ +#else + #error "Undefined Platform" +#endif +} + +/* + * Start the thread + */ +bool +DT_Mdep_Thread_Start (Thread * thread_ptr) +{ +#if defined(__linux__) + return pthread_create (&thread_ptr->thread_handle, + &thread_ptr->attr, + DT_Mdep_Thread_Start_Routine, + thread_ptr) == 0; +#elif defined(__solaris__) + return pthread_create (&thread_ptr->thread_handle, + &thread_ptr->attr, + DT_Mdep_Thread_Start_Routine, + thread_ptr) == 0; +#elif defined(WIN32) + thread_ptr->thread_handle = + CreateThread (NULL, + thread_ptr->stacksize, + (LPTHREAD_START_ROUTINE)thread_ptr->function, + thread_ptr->param, + 0, + thread_ptr->threadId); // NULL); + if (thread_ptr->thread_handle == NULL) + { + return false; + } + return true; +#else + #error "Undefined Platform" +#endif +} + +/* + * Thread execution entry point function + */ +DT_Mdep_Thread_Start_Routine_Return_Type +DT_Mdep_Thread_Start_Routine (void *thread_handle) +{ + Thread *thread_ptr; + thread_ptr = (Thread *) thread_handle; + + thread_ptr->function (thread_ptr->param); +#if defined(__linux__) + return 0; +#elif defined(__solaris__) + return 0; +#elif defined(WIN32) + /* nothing */ +#else + #error "Undefined Platform" +#endif +} + +/* + * Thread detach routine. Allows the pthreads + * interface to clean up resources properly at + * thread's end. + */ +void DT_Mdep_Thread_Detach ( int thread_id ) /* AMM */ +{ + +#if defined(__linux__) + + pthread_detach(thread_id); +#elif defined(__solaris__) + pthread_detach( thread_id); +#elif defined(WIN32) + +#else + #error "Undefined Platform" +#endif +} + +/* + * Allows a thread to get its own ID so it + * can pass it to routines wanting to act + * upon themselves. + */ + +int DT_Mdep_Thread_SELF (void) /* AMM */ +{ + +#if defined(__linux__) + + return (pthread_self()); +#elif defined(__solaris__) + + return (pthread_self()); +#elif defined(WIN32) + return 0; +#else + #error "Undefined Platform" +#endif +} + + +/* + * Allow a thread to exit and cleanup resources. + */ + +void DT_Mdep_Thread_EXIT ( void * thread_handle ) /* AMM */ +{ + +#if defined(__linux__) + + pthread_exit( thread_handle ); +#elif defined(__solaris__) + + pthread_exit( thread_handle ); +#elif defined(WIN32) + /* nothing */ +#else + #error "Undefined Platform" +#endif +} + +/* + * DT_Mdep_wait_object_init + * + * Initialize a wait object + * + * Input: + * wait_obj + * + * Returns: + * 0 if successful + * -1 if unsuccessful + */ +int +DT_Mdep_wait_object_init ( + IN DT_WAIT_OBJECT *wait_obj) +{ + +#if defined(__linux__) || defined(__solaris__) + + wait_obj->signaled = DAT_FALSE; + if ( 0 != pthread_cond_init ( &wait_obj->cv, NULL ) ) + { + return (-1); + } + + /* Always returns 0. */ + pthread_mutex_init ( &wait_obj->lock, NULL ); + return 0; +#elif defined(WIN32) + *wait_obj = CreateEvent(NULL,FALSE,FALSE,NULL); + + if ( *wait_obj == NULL ) + { + return -1; + } + + return 0; + + +#else + #error "Undefined Platform" + +#endif + +} + + +/* Wait on the supplied wait object, up to the specified time_out. + * A timeout of DAT_TIMEOUT_INFINITE will wait indefinitely. + * Timeout should be specified in micro seconds. + * + * Functional returns: + * 0 -- another thread invoked dapl_os_wait object_wakeup + * -1 -- someone else is already waiting in this wait + * object. + * only one waiter is allowed at a time. + * -1 -- another thread invoked dapl_os_wait_object_destroy + * -1 -- the specified time limit was reached. + */ + +int +DT_Mdep_wait_object_wait ( + IN DT_WAIT_OBJECT *wait_obj, + IN int timeout_val) +{ +#if defined(__linux__) || defined(__solaris__) + + int dat_status; + int pthread_status; + struct timespec future; + + dat_status = 0; + pthread_status = 0; + + if ( timeout_val != DAT_TIMEOUT_INFINITE ) + { + struct timeval now; + struct timezone tz; + unsigned int microsecs; + + gettimeofday (&now, &tz); + microsecs = now.tv_usec + (timeout_val % 1000000); + if (microsecs > 1000000) + { + now.tv_sec = now.tv_sec + timeout_val / 1000000 + 1; + now.tv_usec = microsecs - 1000000; + } + else + { + now.tv_sec = now.tv_sec + timeout_val / 1000000; + now.tv_usec = microsecs; + } + + /* Convert timeval to timespec */ + future.tv_sec = now.tv_sec; + future.tv_nsec = now.tv_usec * 1000; + + pthread_mutex_lock (&wait_obj->lock); + while ( wait_obj->signaled == DAT_FALSE && pthread_status == 0) + { + pthread_status = pthread_cond_timedwait ( + &wait_obj->cv , &wait_obj->lock , &future ); + + /* + * No need to reset &future if we go around the loop; + * It's an absolute time. + */ + } + /* Reset the signaled status if we were woken up. */ + if (pthread_status == 0) + { + wait_obj->signaled = false; + } + pthread_mutex_unlock (&wait_obj->lock); + } + else + { + pthread_mutex_lock (&wait_obj->lock); + while ( wait_obj->signaled == DAT_FALSE && pthread_status == 0) + { + pthread_status = pthread_cond_wait ( + &wait_obj->cv , &wait_obj->lock ); + } + /* Reset the signaled status if we were woken up. */ + if (pthread_status == 0) + { + wait_obj->signaled = false; + } + pthread_mutex_unlock (&wait_obj->lock); + } + + if (ETIMEDOUT == pthread_status) + { + return (-1); + } + else if ( 0 != pthread_status) + { + return (-1); + } + + return 0; + +#elif defined(WIN32) + + DAT_RETURN status; + DWORD op_status; + + status = DAT_SUCCESS; + + if ( DAT_TIMEOUT_INFINITE == timeout_val ) + { + op_status = WaitForSingleObject(*wait_obj, INFINITE); + } + else + { + /* convert to milliseconds */ + op_status = WaitForSingleObject(*wait_obj, timeout_val/1000); + } + + if (op_status == WAIT_TIMEOUT) + { + status = DAT_CLASS_ERROR | DAT_TIMEOUT_EXPIRED; + } + else if ( op_status == WAIT_FAILED) + { + status = DAT_CLASS_ERROR | DAT_INTERNAL_ERROR; + } + + return status; + +#else + #error "Undefined Platform" + +#endif +} + + +/* + * DT_Mdep_wait_object_wakeup + * + * Wakeup a thread waiting on a wait object + * + * Input: + * wait_obj + * + * Returns: + * 0 if successful + * -1 if not successful + */ +int +DT_Mdep_wait_object_wakeup ( + DT_WAIT_OBJECT *wait_obj ) +{ +#if defined(__linux__) || defined(__solaris__) + + pthread_mutex_lock ( &wait_obj->lock ); + wait_obj->signaled = true; + pthread_mutex_unlock ( &wait_obj->lock ); + if ( 0 != pthread_cond_signal ( &wait_obj->cv ) ) + { + return (-1); + } + + return 0; + +#elif defined(WIN32) + DWORD op_status; + + op_status = SetEvent(*wait_obj); + if ( op_status == 0 ) + { + return DAT_CLASS_ERROR | DAT_INTERNAL_ERROR; + } + + return DAT_SUCCESS; + + +#else + #error "Undefined Platform" + +#endif + +} + + +/* + * DT_Mdep_wait_object_destroy + * + * Destroy a wait object + * + * Input: + * wait_obj + * + * Returns: + * 0 if successful + * -1 if not successful + */ +int +DT_Mdep_wait_object_destroy ( + IN DT_WAIT_OBJECT *wait_obj) +{ +#if defined(__linux__) || defined(__solaris__) + + if ( 0 != pthread_cond_destroy ( &wait_obj->cv ) ) + { + return (-1); + } + if ( 0 != pthread_mutex_destroy ( &wait_obj->lock ) ) + { + return (-1); + } + + return 0; + + +#elif defined(WIN32) + + DWORD op_status; + DAT_RETURN status = DAT_SUCCESS; + + op_status = CloseHandle(*wait_obj); + + if ( op_status == 0 ) + { + status = DAT_CLASS_ERROR | DAT_INTERNAL_ERROR; + } + + return status; + +#else + #error "Undefined Platform" + +#endif + + + +} + diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_mdep.h b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_mdep.h new file mode 100644 index 00000000..8b28870c --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_mdep.h @@ -0,0 +1,333 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#ifndef __DAPL_MDEP_H__ +#define __DAPL_MDEP_H__ + +/* include files */ + +#include + +#if defined (__linux__) +# include +# include +# include +# include +# include +# include +# include +# include + +#ifdef IA64 +# include +#endif + +#elif defined(__solaris__) +# include +# include +# include +# include +# include +# include +#elif defined (WIN32) +# include +# include +# include +# include +# include +# include +#else +# error "Undefined Platform" +#endif + +/* Default Device Name */ +#if defined(__linux__) +#define DT_MdepDeviceName "jni0a" + +#elif defined(__solaris__) +#define DT_MdepDeviceName "jni0a" + +#elif defined(WIN32) +#define DT_MdepDeviceName "ibnic0" +#else +#error "Undefined Platform" +#endif + +/* Boolean */ +#if defined(__linux__) +typedef int bool; +#elif defined(__solaris__) +typedef int bool; +#elif defined (WIN32) +typedef int bool; +#else +#error "Undefined Platform" +#endif + +#define true (1) +#define false (0) + +#ifndef __BASE_FILE__ +#define __BASE_FILE__ __FILE__ +#endif /* WIN32 */ + +#ifndef _INLINE_ +#if defined(__linux__) +#define _INLINE_ __inline__ +#elif defined(WIN32) +#define _INLINE_ __inline +#else +#error "Undefined Platform" +#endif +#endif + +/* Mdep function defines */ + +#define DT_Mdep_spew(N, _X_) \ +{ \ + if (DT_dapltest_debug >= (N)) \ + { \ + DT_Mdep_printf _X_; \ + } \ +} + +#define DT_Mdep_debug(_X_) DT_Mdep_spew(1, _X_) + +#if defined(__linux__) +#define DT_Mdep_printf printf +#define DT_Mdep_vprintf vprintf +#define DT_Mdep_flush() fflush(NULL) + +#elif defined(__solaris__) +#define DT_Mdep_printf printf +#define DT_Mdep_flush() fflush(NULL) + +#elif defined(WIN32) +#define DT_Mdep_printf printf +#define DT_Mdep_flush() fflush(NULL) +#else +#error "Undefined Platform" +#endif + + +/* + * Locks + */ + +#if defined(__linux__) +typedef pthread_mutex_t DT_Mdep_LockType; + +#elif defined(__solaris__) +typedef pthread_mutex_t DT_Mdep_LockType; + +#elif defined(WIN32) +typedef __declspec(align(8)) HANDLE DT_Mdep_LockType; + +#else +#error "Undefined Platform" +#endif + +/* Wait object used for inter thread communication */ + +#if defined(__linux__) +typedef struct +{ + bool signaled; + pthread_cond_t cv; + pthread_mutex_t lock; +} DT_WAIT_OBJECT; + +#elif defined(__solaris__) + +typedef struct +{ + bool signaled; + pthread_cond_t cv; + pthread_mutex_t lock; +} DT_WAIT_OBJECT; + +#elif defined(WIN32) + +typedef __declspec(align(8)) HANDLE DT_WAIT_OBJECT; + +#else + +#endif + +/* + * Thread types + */ +#if defined(__linux__) +typedef pthread_t DT_Mdep_ThreadHandleType; +typedef void (*DT_Mdep_ThreadFunction) (void *param); +typedef void * DT_Mdep_Thread_Start_Routine_Return_Type; +#define DT_MDEP_DEFAULT_STACK_SIZE 65536 + +#elif defined(__solaris__) +typedef pthread_t DT_Mdep_ThreadHandleType; +typedef void (*DT_Mdep_ThreadFunction) (void *param); +typedef void * DT_Mdep_Thread_Start_Routine_Return_Type; +#define DT_MDEP_DEFAULT_STACK_SIZE 65536 + +#elif defined(WIN32) || defined(_WIN64) +typedef __declspec(align(8)) HANDLE DT_Mdep_ThreadHandleType; +typedef void (*DT_Mdep_ThreadFunction) (void *param); +typedef void DT_Mdep_Thread_Start_Routine_Return_Type; +#define DT_MDEP_DEFAULT_STACK_SIZE 65536 + +#else +#error "Undefined Platform" +#endif + +typedef __declspec(align(8)) struct +{ + void (*function) (void *); + void *param; + DT_Mdep_ThreadHandleType thread_handle; + unsigned int stacksize; +#if defined(__solaris__)||defined(__linux__) + pthread_attr_t attr; /* Thread attributes */ +#endif +#if defined (WIN32) + LPDWORD threadId; +#endif +} Thread; + +/* + * System information + * + */ + +typedef struct +{ + unsigned long int system; + unsigned long int user; + unsigned long int idle; +} DT_CpuStat; + +/* + * Timing + */ + +#if defined(__linux__) +typedef unsigned long long int DT_Mdep_TimeStamp; +#elif defined(WIN32) +typedef unsigned __int64 DT_Mdep_TimeStamp; +#else +# error "Undefined Platform" +#endif + +static _INLINE_ DT_Mdep_TimeStamp +DT_Mdep_GetTimeStamp ( void ) +{ +#if defined(__linux__) +#if defined(__GNUC__) && defined(__PENTIUM__) + DT_Mdep_TimeStamp x; + __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x)); + return x; +#else + +#ifdef IA64 + unsigned long x; + + x = get_cycles (); + return x; +#else + #error "Non-Pentium Linux - unimplemented" +#endif +#endif + +#elif defined(WIN32) +#if !defined (WIN64) && !defined (IA64) && !defined (AMD64) + _asm rdtsc +#else +#ifdef AMD64 + return __rdtsc(); +#else + LARGE_INTEGER val; + QueryPerformanceCounter( &val ); + return val.QuadPart; +#endif //endif WIN64 + +#endif //endif WIN64, and IA64 + +#else + #error "Undefined Platform" +#endif +} + +/* + * Define types for Window compatibility + */ +#if defined(WIN32) + +#if !defined(IA64) && !defined(WIN64) +#include +#endif + +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +typedef __int32 int32_t; +typedef unsigned __int32 uint32_t; + + +#define bzero(x, y) memset(x, 0, y) + +#endif + +/* + * Define long format types to be used in *printf format strings. We + * use the C string constant concatenation ability to define 64 bit + * formats, which unfortunatly are non standard in the C compiler + * world. E.g. %llx for gcc, %I64x for Windows + */ +#if defined(WIN32) +#define F64d "%I64d" +#define F64u "%I64u" +#define F64x "%I64x" +#define F64X "%I64X" + +#elif defined(__linux__) + +#define F64d "%lld" +#define F64u "%llu" +#define F64x "%llx" +#define F64X "%llX" +#endif + + +/* + * Define notion of a LONG LONG 0 + */ +#if defined(__linux__) +#define LZERO 0ULL +#elif defined(WIN32) +#define LZERO 0UL +#else +#define LZERO 0 +#endif + +#endif diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_memlist.c b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_memlist.c new file mode 100644 index 00000000..8d7d525d --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_memlist.c @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_memlist.h" +#include "dapl_proto.h" + + +void +DT_MemListInit (Per_Test_Data_t * pt_ptr) +{ + DT_Mdep_LockInit (&pt_ptr->MemListLock); + pt_ptr->MemListHead = 0; +} + +void * +DT_MemListAlloc (Per_Test_Data_t * pt_ptr, char *file, mem_type_e t, int size) +{ + void *buffptr; + MemListEntry_t *entry_ptr; + buffptr = 0; + entry_ptr = 0; + + buffptr = DT_Mdep_Malloc (size); + if (buffptr == 0) + { + return 0; + } + if (pt_ptr == 0) /* not use mem_list */ + { + return buffptr; + } + entry_ptr = (MemListEntry_t *) DT_Mdep_Malloc (sizeof (MemListEntry_t)); + if (entry_ptr == 0) + { + DT_Mdep_Free (buffptr); + return 0; + } + strcpy (entry_ptr->filename, file); + entry_ptr->MemType = t; + entry_ptr->mem_ptr = buffptr; + + DT_Mdep_Lock (&pt_ptr->MemListLock); + entry_ptr->next = pt_ptr->MemListHead; + pt_ptr->MemListHead = entry_ptr; + DT_Mdep_Unlock (&pt_ptr->MemListLock); + + return buffptr; +} + +void +DT_MemListFree (Per_Test_Data_t * pt_ptr, void *ptr) +{ + MemListEntry_t *pre, *cur; + if (pt_ptr == 0) /* not use mem_list */ + { + DT_Mdep_Free (ptr); + return; + } + DT_Mdep_Lock (&pt_ptr->MemListLock); + pre = 0; + cur = pt_ptr->MemListHead; + while (cur) + { + if (cur->mem_ptr == ptr) + { + if (!pre) /* first entry */ + { + pt_ptr->MemListHead = cur->next; + cur->next = 0; + } + else + { + pre->next = cur->next; + cur->next = 0; + } + DT_Mdep_Free (ptr); + DT_Mdep_Free (cur); + goto unlock_and_return; + } + pre = cur; + cur = cur->next; + } +unlock_and_return: + DT_Mdep_Unlock (&pt_ptr->MemListLock); +} + +void +DT_PrintMemList (Per_Test_Data_t * pt_ptr) +{ + char *type[10] = + { + "BPOOL", "BUFF", "PERTESTDATA", "IBNIC", "NETADDRESS", + "TRANSACTIONTEST", "THREAD", "EPCONTEXT" + }; + MemListEntry_t *cur; + + DT_Mdep_Lock (&pt_ptr->MemListLock); + cur = pt_ptr->MemListHead; + if (cur != 0) + { + DT_Mdep_printf ("the allocated memory that have not been returned are:\n"); + } + while (cur) + { + DT_Mdep_printf ("file: dapl_%s, \tMemType:%s\n", + cur->filename, type[cur->MemType]); + cur = cur->next; + } + DT_Mdep_Unlock (&pt_ptr->MemListLock); +} diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_memlist.h b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_memlist.h new file mode 100644 index 00000000..83d9806a --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_memlist.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#ifndef __DAPL_MEMLIST_H__ +#define __DAPL_MEMLIST_H__ + +#include "dapl_mdep.h" +#include "dapl_memlist.h" + +typedef enum +{ + BPOOL, + BUFF, + PERTESTDATA, + IBNIC, + NETADDRESS, + TRANSACTIONTEST, + THREAD, + EPCONTEXT +} mem_type_e; + +struct Mem_list_entry +{ + char filename[50]; + mem_type_e MemType; + void *mem_ptr; + struct Mem_list_entry *next; +}; + +typedef struct Mem_list_entry MemListEntry_t; +#endif diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_netaddr.c b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_netaddr.c new file mode 100644 index 00000000..e88d19a2 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_netaddr.c @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_mdep.h" +#include "dapl_memlist.h" +#include "dapl_proto.h" +#include "dapl_cnxn.h" +#include + + +DAT_IA_ADDRESS_PTR +DT_NetAddrAlloc (Per_Test_Data_t * pt_ptr) +{ + DAT_IA_ADDRESS_PTR netaddr; + + netaddr = (DAT_IA_ADDRESS_PTR) DT_MemListAlloc (pt_ptr, "netaddr", + NETADDRESS, sizeof (DAT_SOCK_ADDR)); + if (!netaddr) + { + DT_Mdep_printf ("dapltest: No Memory to create netaddr!\n"); + } + return netaddr; +} + + +void +DT_NetAddrFree (Per_Test_Data_t * pt_ptr, DAT_IA_ADDRESS_PTR netaddr) +{ + DT_MemListFree (pt_ptr, netaddr); +} + + +bool +DT_NetAddrLookupHostAddress (DAT_IA_ADDRESS_PTR to_netaddr, + DAT_NAME_PTR hostname) +{ + struct addrinfo *target; + int rval; + + rval = getaddrinfo (hostname, NULL, NULL, &target); + if (rval != 0) + { + char *whatzit = "unknown error return"; + + switch (rval) + { + case EAI_FAMILY: + { + whatzit = "unsupported address family"; + break; + } + case EAI_SOCKTYPE: + { + whatzit = "unsupported socket type"; + break; + } + case EAI_BADFLAGS: + { + whatzit = "invalid flags"; + break; + } + case EAI_NONAME: + { + whatzit = "unknown node name"; + break; + } + case EAI_SERVICE: + { + whatzit = "service unavailable"; + break; + } +#if !defined(WIN32) + case EAI_ADDRFAMILY: + { + whatzit = "node has no address in this family"; + break; + } + case EAI_NODATA: + { + whatzit = "node has no addresses defined"; + break; + } +#endif + case EAI_MEMORY: + { + whatzit = "out of memory"; + break; + } + case EAI_FAIL: + { + whatzit = "permanent name server failure"; + break; + } + case EAI_AGAIN: + { + whatzit = "temporary name server failure"; + break; + } +#if !defined(WIN32) + case EAI_SYSTEM: + { + whatzit = "system error"; + break; + } +#endif + } + + DT_Mdep_printf ("getnameinfo (%s) failed (%s)\n", + hostname, whatzit); + return DAT_FALSE; + } + + /* Pull out IP address and print it as a sanity check */ + rval = ((struct sockaddr_in *)target->ai_addr)->sin_addr.s_addr; + DT_Mdep_printf ("Server Name: %s \n", hostname); + DT_Mdep_printf ("Server Net Address: %d.%d.%d.%d\n", + (rval >> 0) & 0xff, + (rval >> 8) & 0xff, + (rval >> 16) & 0xff, + (rval >> 24) & 0xff); + + *to_netaddr = * ((DAT_IA_ADDRESS_PTR) target->ai_addr); + + return ( DAT_TRUE ); +} + diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_params.c b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_params.c new file mode 100644 index 00000000..96516bb4 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_params.c @@ -0,0 +1,296 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_getopt.h" +#include "dapl_test_data.h" +#include "dapl_mdep.h" +#include "dapl_proto.h" + +#include "dapl_server_cmd.h" +#include "dapl_transaction_cmd.h" +#include "dapl_performance_cmd.h" +#include "dapl_quit_cmd.h" +#include "dapl_limit_cmd.h" + +#define MAX_ARGC 500 +#define MAX_ARG_LEN 100 + + +/* Parse command line arguments */ +bool +DT_Params_Parse (int argc, char *argv[], Params_t * params_ptr) +{ + Server_Cmd_t *Server_Cmd; + Transaction_Cmd_t *Transaction_Cmd; + Performance_Cmd_t *Performance_Cmd; + Quit_Cmd_t *Quit_Cmd; + Limit_Cmd_t *Limit_Cmd; + FFT_Cmd_t *FFT_Cmd; + + char *filename; + FILE *fd; + mygetopt_t opts; + char c; + char *cp; + char *sp; + char line[256]; + char *my_argv[MAX_ARGC]; + int my_argc; + int i; + DT_mygetopt_init (&opts); + opts.opterr = 0; /* turn off automatical error handler */ + + fd = 0; + my_argc = 0; + for (i = 0; i < MAX_ARGC; i++) + { + my_argv[i] = NULL; + } + + /* dapltest with no arguments means run as a server with default values */ + if (argc == 1) + { + params_ptr->test_type = SERVER_TEST; + params_ptr->ReliabilityLevel = DAT_QOS_BEST_EFFORT; + Server_Cmd = ¶ms_ptr->u.Server_Cmd; + DT_Server_Cmd_Init (Server_Cmd); + if (!DT_Mdep_GetDefaultDeviceName (Server_Cmd->dapl_name)) + { + DT_Mdep_printf ("can't get default device name\n"); + return false; + } + return true; + } + /* check for a script file */ + if (strncmp (argv[1], "-f", 2) == 0) + { + if (argc == 2) /* dapltest -fdata */ + { + filename = argv[1] + 2; + } + else + { + if (argc == 3 && strcmp (argv[1], "-f") == 0) /* dapltest -f data */ + { + filename = argv[2]; + } + else + { + DT_Mdep_printf ("-f allows no additional options\n"); + goto main_usage; + } + } + + if (!filename || strlen (filename) == 0) + { + DT_Mdep_printf ("Missing with -f option\n"); + goto main_usage; + } + /* read the script file and create a fake argc, argv */ + fd = fopen (filename, "r"); + if (fd == 0) + { + DT_Mdep_printf ("Cannot open script file: %s\n", filename); + goto main_usage; + } + my_argc = 1; + my_argv[0] = DT_Mdep_Malloc (MAX_ARG_LEN); + if (!my_argv[0]) + { + DT_Mdep_printf ("No Memory\n"); + goto error_return; + } + strcpy (my_argv[0], argv[0]); + while (fgets (&line[0], 256, fd)) + { + sp = &line[0]; + for (;;) + { + cp = strtok (sp, " \t\n"); + sp = 0; /* so can continue to parse this string */ + if (!cp) /* no more token found */ + { + break; + } + if (*cp == '#') /* Comment; go to next line. */ + { + break; + } + my_argv[my_argc] = DT_Mdep_Malloc (MAX_ARG_LEN); + if (!my_argv[my_argc]) + { + DT_Mdep_printf ("No Memory\n"); + goto error_return; + } + strcpy (my_argv[my_argc], cp); + my_argc++; + } + } + } + else + { + my_argc = argc; + for (i = 0; i < argc; i++) + { + my_argv[i] = argv[i]; + } + } + +#if 0 + for (i = 0; i < my_argc; i++) + { + DT_Mdep_printf ("ARG %s\n", my_argv[i]); + } + exit (1); +#endif + + /* get test type - which must be the first arg */ + c = DT_mygetopt_r (my_argc, my_argv, "T:", &opts); + if (c != 'T') + { + DT_Mdep_printf ("Must Specify Test (-T) option first\n"); + goto main_usage; + } + if ((opts.optarg == 0) || strlen (opts.optarg) == 0 || *opts.optarg == '-') + { + DT_Mdep_printf ("Must specify test type\n"); + goto main_usage; + } + switch (*opts.optarg) + { + case 'S': /* Server Test */ + { + params_ptr->test_type = SERVER_TEST; + Server_Cmd = ¶ms_ptr->u.Server_Cmd; + DT_Server_Cmd_Init (Server_Cmd); + if (!DT_Server_Cmd_Parse ( Server_Cmd, + my_argc, my_argv, &opts)) + { + goto error_return; + } + params_ptr->ReliabilityLevel = Server_Cmd->ReliabilityLevel; + break; + } + case 'T': /* Transaction Test */ + { + params_ptr->test_type = TRANSACTION_TEST; + Transaction_Cmd = ¶ms_ptr->u.Transaction_Cmd; + DT_Transaction_Cmd_Init (Transaction_Cmd); + if (!DT_Transaction_Cmd_Parse ( Transaction_Cmd, + my_argc, my_argv, &opts)) + { + goto error_return; + } + params_ptr->ReliabilityLevel = Transaction_Cmd->ReliabilityLevel; + break; + } + case 'P': /* Performance Test */ + { + params_ptr->test_type = PERFORMANCE_TEST; + Performance_Cmd = ¶ms_ptr->u.Performance_Cmd; + + if (!DT_Performance_Cmd_Init (Performance_Cmd)) + { + goto error_return; + } + + if (!DT_Performance_Cmd_Parse ( Performance_Cmd, + my_argc, my_argv, &opts)) + { + goto error_return; + } + + params_ptr->ReliabilityLevel = Performance_Cmd->qos; + break; + } + case 'Q': /* Quit server Test */ + { + params_ptr->test_type = QUIT_TEST; + Quit_Cmd = ¶ms_ptr->u.Quit_Cmd; + DT_Quit_Cmd_Init (Quit_Cmd); + if (!DT_Quit_Cmd_Parse ( Quit_Cmd, + my_argc, my_argv, &opts)) + { + goto error_return; + } + params_ptr->ReliabilityLevel = Quit_Cmd->ReliabilityLevel; + break; + } + case 'L': /* Limit Test */ + { + params_ptr->test_type = LIMIT_TEST; + Limit_Cmd = ¶ms_ptr->u.Limit_Cmd; + DT_Limit_Cmd_Init (Limit_Cmd); + if (!DT_Limit_Cmd_Parse (Limit_Cmd, + my_argc, my_argv, &opts)) + { + goto error_return; + } + params_ptr->ReliabilityLevel = Limit_Cmd->ReliabilityLevel; + break; + } + case 'F': + { + params_ptr->test_type = FFT_TEST; + FFT_Cmd = ¶ms_ptr->u.FFT_Cmd; + DT_FFT_Cmd_Init (FFT_Cmd); + if (!DT_FFT_Cmd_Parse (FFT_Cmd, my_argc, my_argv, &opts)) + { + goto error_return; + } + params_ptr->ReliabilityLevel = FFT_Cmd->ReliabilityLevel; + break; + } + default: + { + DT_Mdep_printf ("Invalid Test Type\n"); + goto main_usage; + } + } + + if (fd) + { + for (i = 0; i < my_argc; i++) + { + DT_Mdep_Free (my_argv[i]); + } + fclose (fd); + } + return true; + +main_usage: + Dapltest_Main_Usage (); +error_return: + if (fd) + { + for (i = 0; i < my_argc; i++) + { + DT_Mdep_Free (my_argv[i]); + } + fclose (fd); + } + return false; +} diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_params.h b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_params.h new file mode 100644 index 00000000..d64fe8d7 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_params.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#ifndef __DAPL_PARAMS_H__ +#define __DAPL_PARAMS_H__ + + +#include "dapl_server_cmd.h" +#include "dapl_transaction_cmd.h" +#include "dapl_performance_cmd.h" +#include "dapl_limit_cmd.h" +#include "dapl_quit_cmd.h" +#include "dapl_fft_cmd.h" + +typedef enum +{ + SERVER_TEST, + TRANSACTION_TEST, + PERFORMANCE_TEST, + LIMIT_TEST, + QUIT_TEST, + FFT_TEST +} test_type_e; + +typedef struct +{ + test_type_e test_type; + + union + { + Server_Cmd_t Server_Cmd; + Transaction_Cmd_t Transaction_Cmd; + Performance_Cmd_t Performance_Cmd; + Limit_Cmd_t Limit_Cmd; + Quit_Cmd_t Quit_Cmd; + FFT_Cmd_t FFT_Cmd; + } u; + + /* Needed here due to structure of command processing */ + DAT_QOS ReliabilityLevel; +} Params_t; + +#endif diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_performance_client.c b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_performance_client.c new file mode 100644 index 00000000..7eb8c667 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_performance_client.c @@ -0,0 +1,545 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include + +#include "dapl_bpool.h" +#include "dapl_mdep.h" +#include "dapl_memlist.h" +#include "dapl_performance_cmd.h" +#include "dapl_performance_stats.h" +#include "dapl_performance_test.h" +#include "dapl_proto.h" +#include "dapl_test_data.h" + +#define MAX_CONN_RETRY 8 + +/****************************************************************************/ +void +DT_Performance_Test_Client ( + Per_Test_Data_t *pt_ptr, + DAT_IA_HANDLE *ia_handle, + DAT_IA_ADDRESS_PTR remote_ia_addr) +{ + Performance_Test_t *test_ptr = NULL; + int connected = 1; + + DT_Mdep_debug (("Client: Starting performance test\n")); + + if ( !DT_Performance_Test_Create (pt_ptr, + ia_handle, + remote_ia_addr, + false, + pt_ptr->Server_Info.is_little_endian, + &test_ptr) ) + { + DT_Mdep_debug (("Client: Resource Creation Failed\n")); + connected = 0; + } + else if ( !DT_Performance_Test_Client_Connect (test_ptr) ) + { + DT_Mdep_debug (("Client: Connection Failed\n")); + connected = 0; + } + + if ( connected ) + { + if ( !DT_Performance_Test_Client_Exchange (test_ptr) ) + { + DT_Mdep_debug (("Client: Test Failed\n")); + } + } + + /* If we never connected, then the test will hang here + * because in the destroy of the test it will waits for a + * disconnect event which will never arrive, simply + * because there was never a connection. + */ + + DT_Performance_Test_Destroy (pt_ptr, test_ptr, false); + +#ifdef CM_BUSTED + /***** XXX Chill out a bit to give the kludged CM a chance ... + *****/DT_Mdep_Sleep (5000); +#endif + + DT_Mdep_debug (("Client: Finished performance test\n")); +} + + +/****************************************************************************/ +bool +DT_Performance_Test_Client_Connect ( + Performance_Test_t *test_ptr) +{ + DAT_RETURN ret; + DAT_EVENT_NUMBER event_num; + unsigned int retry_cnt = 0; + + /* + * Client - connect + */ + DT_Mdep_debug (("Client[" F64x "]: Connect on port 0x" F64x "\n", + (DAT_UVERYLONG)test_ptr->base_port, + (DAT_UVERYLONG)test_ptr->ep_context.port)); + +retry: + ret = dat_ep_connect (test_ptr->ep_context.ep_handle, + test_ptr->remote_ia_addr, + test_ptr->ep_context.port, + DAT_TIMEOUT_INFINITE, + 0, + (DAT_PVOID) 0, /* no private data */ + test_ptr->cmd->qos, + DAT_CONNECT_DEFAULT_FLAG); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("Test[" F64x "]: dat_ep_connect error: %s\n", + (DAT_UVERYLONG)test_ptr->base_port, DT_RetToString (ret)); + return false; + } + + /* wait for DAT_CONNECTION_EVENT_ESTABLISHED */ + if (!DT_conn_event_wait (test_ptr->ep_context.ep_handle, + test_ptr->conn_evd_hdl, + &event_num)) + { + if ( event_num == DAT_CONNECTION_EVENT_PEER_REJECTED ) + { + DAT_EVENT event; + DAT_COUNT drained = 0; + + DT_Mdep_Sleep (1000); + DT_Mdep_printf ("Test[" F64x "]: retrying connection...\n", + (DAT_UVERYLONG)test_ptr->base_port); + retry_cnt++; + + dat_ep_reset (test_ptr->ep_context.ep_handle); + do + { + ret = dat_evd_dequeue (test_ptr->recv_evd_hdl, &event); + drained++; + } while (ret != DAT_QUEUE_EMPTY); + + if (drained > 1 && retry_cnt < MAX_CONN_RETRY) + { + DT_Mdep_printf("Reposting!!! %d\n", drained); + + /* + * Post recv and sync buffers + */ + if ( !DT_post_recv_buffer (test_ptr->ep_context.ep_handle, + test_ptr->ep_context.bp, + DT_PERF_SYNC_RECV_BUFFER_ID, + DT_PERF_SYNC_BUFF_SIZE) ) + { + DT_Mdep_printf ("Test[" F64x "]: repost buffer error: \n", + (DAT_UVERYLONG)test_ptr->base_port); + return false; + } + } + + if (retry_cnt < MAX_CONN_RETRY) + { + goto retry; + } + } + /* error message printed by DT_cr_event_wait */ + return false; + } + +#ifdef CM_BUSTED + /***** XXX Chill out a bit to give the kludged CM a chance ... + *****/DT_Mdep_Sleep (5000); +#endif + + DT_Mdep_debug (("Client[" F64x "]: Got Connection\n", + (DAT_UVERYLONG)test_ptr->base_port)); + + return true; +} + + +/****************************************************************************/ +static bool +DT_Performance_Test_Client_Phase1 ( + Performance_Test_t *test_ptr, + Performance_Stats_t *stats ) +{ + DT_Mdep_TimeStamp pre_ts; + DT_Mdep_TimeStamp post_ts; + DT_CpuStat pre_cpu_stat; + DT_CpuStat post_cpu_stat; + unsigned int post_cnt; + unsigned int reap_cnt; + + /* + * measure bandwidth, OPS, and CPU utilization + */ + + if ( !DT_Mdep_GetCpuStat (&pre_cpu_stat) ) + { + return false; + } + + pre_ts = DT_Mdep_GetTimeStamp (); + + /* + * Fill the pipe + */ + + for ( post_cnt = 0; post_cnt < (unsigned int)test_ptr->ep_context.pipeline_len; post_cnt++ ) + { + if ( !DT_performance_post_rdma_op (&test_ptr->ep_context, + test_ptr->reqt_evd_hdl, + stats) ) + { + DT_Mdep_debug (("Test[" F64x "]: Post %i failed\n", + (DAT_UVERYLONG)test_ptr->base_port, + post_cnt)); + return false; + } + } + + /* + * Reap completions and repost + */ + + for ( reap_cnt = 0; reap_cnt < test_ptr->cmd->num_iterations; ) + { + unsigned int cur_reap_cnt; + unsigned int cur_post_cnt; + unsigned int cur_post_i; + + cur_reap_cnt = DT_performance_reap (test_ptr->reqt_evd_hdl, + test_ptr->cmd->mode, + stats); + + if ( 0 == cur_reap_cnt ) + { + DT_Mdep_debug (("Test[" F64x "]: Poll %i failed\n", + (DAT_UVERYLONG)test_ptr->base_port, + reap_cnt)); + return false; + } + + /* repost */ + cur_post_cnt = DT_min (test_ptr->cmd->num_iterations - post_cnt, + cur_reap_cnt); + + for ( cur_post_i = 0; cur_post_i < cur_post_cnt; cur_post_i++) + { + if ( !DT_performance_post_rdma_op (&test_ptr->ep_context, + test_ptr->reqt_evd_hdl, + stats) ) + { + DT_Mdep_debug (("Test[" F64x "]: Post %i failed\n", + (DAT_UVERYLONG)test_ptr->base_port, + post_cnt)); + return false; + } + } + + reap_cnt += cur_reap_cnt; + post_cnt += cur_post_cnt; + } + + /* end time and update stats */ + post_ts = DT_Mdep_GetTimeStamp (); + stats->time_ts = post_ts - pre_ts; + stats->num_ops = test_ptr->cmd->num_iterations; + + if ( !DT_Mdep_GetCpuStat (&post_cpu_stat) ) + { + return false; + } + + /* calculate CPU utilization */ + { + unsigned long int system; + unsigned long int user; + unsigned long int idle; + unsigned long int total; + + system = post_cpu_stat.system - pre_cpu_stat.system; + user = post_cpu_stat.user - pre_cpu_stat.user; + idle = post_cpu_stat.idle - pre_cpu_stat.idle; + + total = system + user + idle; + + if ( 0 == total ) + { + stats->cpu_utilization = 0.0; + } + else + { + stats->cpu_utilization = 1.0 - ((double) idle / (double) total ); + stats->cpu_utilization *= 100; + } + } + + return true; +} + + +/****************************************************************************/ +static bool +DT_Performance_Test_Client_Phase2 ( + Performance_Test_t *test_ptr, + Performance_Stats_t *stats ) +{ + DAT_LMR_TRIPLET *iov; + DAT_RMR_TRIPLET rmr_triplet; + DAT_DTO_COOKIE cookie; + DAT_EVENT event; + DAT_RETURN ret; + Performance_Ep_Context_t *ep_context; + Performance_Test_Op_t *op; + DT_Mdep_TimeStamp pre_ts; + DT_Mdep_TimeStamp post_ts; + unsigned long int bytes; + unsigned int i; + + /* + * measure latency + */ + + ep_context = &test_ptr->ep_context; + op = &ep_context->op; + iov = DT_Bpool_GetIOV (op->bp, 0); + + bytes = op->seg_size * op->num_segs; + + /* Prep the inputs */ + for (i = 0; i < op->num_segs; i++) + { + iov[i].pad = 0U; + iov[i].virtual_address = (DAT_VADDR) (uintptr_t) + DT_Bpool_GetBuffer (op->bp, i); + iov[i].segment_length = op->seg_size; + iov[i].lmr_context = DT_Bpool_GetLMR (op->bp, i); + } + + rmr_triplet.pad = 0U; + rmr_triplet.target_address = (DAT_VADDR) (uintptr_t) op->Rdma_Address; + rmr_triplet.segment_length = op->seg_size * op->num_segs; + rmr_triplet.rmr_context = op->Rdma_Context; + + cookie.as_ptr = NULL; + + for ( i = 0; i < test_ptr->cmd->num_iterations; i++ ) + { + if ( RDMA_WRITE == op->transfer_type ) + { + pre_ts = DT_Mdep_GetTimeStamp (); + + ret = dat_ep_post_rdma_write (ep_context->ep_handle, + op->num_segs, + iov, + cookie, + &rmr_triplet, + DAT_COMPLETION_DEFAULT_FLAG); + } + else + { + pre_ts = DT_Mdep_GetTimeStamp (); + + ret = dat_ep_post_rdma_read (ep_context->ep_handle, + op->num_segs, + iov, + cookie, + &rmr_triplet, + DAT_COMPLETION_DEFAULT_FLAG); + } + + if ( DAT_SUCCESS != ret ) + { + return false; + } + + for (;;) + { + ret = dat_evd_dequeue ( test_ptr->reqt_evd_hdl, + &event); + + post_ts = DT_Mdep_GetTimeStamp (); + + if (DAT_GET_TYPE(ret) == DAT_QUEUE_EMPTY) + { + continue; + } + else if ( DAT_SUCCESS != ret ) + { + DT_Mdep_printf ("Test Error: dapl_event_dequeue failed: %s\n", + DT_RetToString (ret)); + return false; + } + else if (event.event_number == DAT_DTO_COMPLETION_EVENT) + { + DT_performance_stats_record_latency (stats, post_ts - pre_ts); + break; + } + else /* error */ + { + DT_Mdep_printf ( + "Warning: dapl_performance_wait swallowing %s event\n", + DT_EventToSTr (event.event_number)); + + return false; + } + } + } + + return true; +} + + +/****************************************************************************/ +bool +DT_Performance_Test_Client_Exchange ( + Performance_Test_t *test_ptr) +{ + DAT_DTO_COMPLETION_EVENT_DATA dto_stat; + DAT_DTO_COOKIE dto_cookie; + Performance_Stats_t stats; + RemoteMemoryInfo *rmi; + + test_ptr->ep_context.op.bp = + DT_BpoolAlloc (test_ptr->pt_ptr, + test_ptr->ia_handle, + test_ptr->pz_handle, + test_ptr->ep_context.ep_handle, + test_ptr->reqt_evd_hdl, + test_ptr->ep_context.op.seg_size, + test_ptr->ep_context.op.num_segs, + DAT_OPTIMAL_ALIGNMENT, + false, + false); + + if ( !test_ptr->ep_context.op.bp ) + { + DT_Mdep_printf ("Test[" F64x "]: no memory for buffers (RDMA/RD)\n", + (DAT_UVERYLONG)test_ptr->base_port); + return false; + } + + /* + * Recv the other side's info + */ + DT_Mdep_debug (("Test[" F64x "]: Waiting for Sync Msg\n", + (DAT_UVERYLONG)test_ptr->base_port)); + + dto_cookie.as_64 = LZERO; + dto_cookie.as_ptr = + (DAT_PVOID) DT_Bpool_GetBuffer ( + test_ptr->ep_context.bp, + DT_PERF_SYNC_RECV_BUFFER_ID); + if ( !DT_dto_event_wait (test_ptr->recv_evd_hdl, &dto_stat) || + !DT_dto_check ( &dto_stat, + test_ptr->ep_context.ep_handle, + DT_PERF_SYNC_BUFF_SIZE, + dto_cookie, + "Recieve Sync_Msg") ) + { + return false; + } + + /* + * Extract what we need + */ + DT_Mdep_debug (("Test[" F64x "]: Sync Msg Received\n", + (DAT_UVERYLONG)test_ptr->base_port)); + rmi = (RemoteMemoryInfo *) DT_Bpool_GetBuffer (test_ptr->ep_context.bp, + DT_PERF_SYNC_RECV_BUFFER_ID); + + /* + * If the client and server are of different endiannesses, + * we must correct the endianness of the handle and address + * we pass to the other side. The other side cannot (and + * better not) interpret these values. + */ + if (DT_local_is_little_endian != test_ptr->is_remote_little_endian) + { + rmi->rmr_context = DT_EndianMemHandle (rmi->rmr_context); + rmi->mem_address.as_64 =DT_EndianMemAddress (rmi->mem_address.as_64); + } + + test_ptr->ep_context.op.Rdma_Context = rmi->rmr_context; + test_ptr->ep_context.op.Rdma_Address = rmi->mem_address.as_ptr; + + DT_Mdep_spew (3, ("Got RemoteMemInfo [ va=%p, ctx=%x ]\n", + test_ptr->ep_context.op.Rdma_Address, + test_ptr->ep_context.op.Rdma_Context)); + + /* + * Get to work ... + */ + DT_Mdep_debug (("Test[" F64x "]: Begin...\n", + (DAT_UVERYLONG)test_ptr->base_port)); + + DT_performance_stats_init (&stats); + + if ( !DT_Performance_Test_Client_Phase1(test_ptr, &stats) ) + { + return false; + } + + if ( !DT_Performance_Test_Client_Phase2(test_ptr, &stats) ) + { + return false; + } + + DT_Mdep_debug (("Test[" F64x "]: Sending Sync Msg\n", + (DAT_UVERYLONG)test_ptr->base_port)); + + if (!DT_post_send_buffer (test_ptr->ep_context.ep_handle, + test_ptr->ep_context.bp, + DT_PERF_SYNC_SEND_BUFFER_ID, + DT_PERF_SYNC_BUFF_SIZE)) + { + /* error message printed by DT_post_send_buffer */ + return false; + } + + dto_cookie.as_64 = LZERO; + dto_cookie.as_ptr = + (DAT_PVOID) DT_Bpool_GetBuffer ( + test_ptr->ep_context.bp, + DT_PERF_SYNC_SEND_BUFFER_ID); + if (!DT_dto_event_wait (test_ptr->reqt_evd_hdl, &dto_stat) || + !DT_dto_check ( &dto_stat, + test_ptr->ep_context.ep_handle, + DT_PERF_SYNC_BUFF_SIZE, + dto_cookie, + "Client_Sync_Send")) + { + return false; + } + + DT_performance_stats_print (&stats, test_ptr->cmd, test_ptr); + + return true; +} diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_performance_cmd.c b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_performance_cmd.c new file mode 100644 index 00000000..025c14bc --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_performance_cmd.c @@ -0,0 +1,355 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_bpool.h" +#include "dapl_test_data.h" +#include "dapl_mdep.h" +#include "dapl_proto.h" + +/* + * Map Performance_Mode_Type values to readable strings + */ +const char * +DT_PerformanceModeToString (Performance_Mode_Type mode) +{ + if ( BLOCKING_MODE == mode ) + { + return "blocking"; + } + else if ( POLLING_MODE == mode ) + { + return "polling"; + } + else + { + return "error: unkown mode"; + } +} + + +static void +DT_Performance_Cmd_Usage (void) +{ + DT_Mdep_printf ("USAGE: ---- PERFORMANCE TEST ----\n"); + DT_Mdep_printf ("USAGE: dapltest -T P\n"); + DT_Mdep_printf ("USAGE: -s \n"); + DT_Mdep_printf ("USAGE: [-m b|p]\n"); + DT_Mdep_printf ("USAGE: [-D ]\n"); + DT_Mdep_printf ("USAGE: [-d] : debug (zero)\n"); + DT_Mdep_printf ("USAGE: [-i ] : (1, 000)\n"); + DT_Mdep_printf ("USAGE: [-p ]\n"); + DT_Mdep_printf ("USAGE: [-R ]\n"); + DT_Mdep_printf ("USAGE: (BE == QOS_BEST_EFFORT - Default)\n"); + DT_Mdep_printf ("USAGE: (HT == QOS_HIGH_THROUGHPUT)\n"); + DT_Mdep_printf ("USAGE: (LL == QOS_LOW_LATENCY)\n"); + DT_Mdep_printf ("USAGE: (EC == QOS_ECONOMY)\n"); + DT_Mdep_printf ("USAGE: (PM == QOS_PREMIUM)\n"); + DT_Mdep_printf ("USAGE: \n"); + DT_Mdep_printf ("USAGE:\n"); + DT_Mdep_printf ("USAGE: Each OP consists of:\n"); + DT_Mdep_printf ("USAGE: : \"RR\" (RDMA READ)\n"); + DT_Mdep_printf ("USAGE: : \"RW\" (RDMA WRITE)\n"); + DT_Mdep_printf ("USAGE: [seg_size [num_segs] ] : (4096, 1)\n"); +} + +static bool +DT_Performance_Cmd_Parse_Op ( + Performance_Cmd_t * cmd, + int index, + int my_argc, + char **my_argv) +{ + int i; + + /* + * Op Format: [seg_size] [num_segs] + */ + + if ( index == my_argc ) + { + DT_Mdep_printf ("Operation Missing Transfer Type\n"); + return (false); + } + + for ( i = 0; index < my_argc; i++, index++ ) + { + switch ( i ) + { + case 0: + { + if ( 0 == strncmp (my_argv[index], "RR", strlen ("RR")) ) + { + cmd->op.transfer_type = RDMA_READ; + } + else if ( 0 == strncmp (my_argv[index], "RW", strlen ("RW")) ) + { + cmd->op.transfer_type = RDMA_WRITE; + } + else + { + DT_Mdep_printf ("OP type must be \n"); + return (false); + } + break; + } + case 1: + { + cmd->op.seg_size = atoi (my_argv[index]); + break; + } + case 2: + { + cmd->op.num_segs = atoi (my_argv[index]); + break; + } + default: + { + DT_Mdep_printf ("Too many OP args\n"); + return (false); + } + } + } + + return (true); +} + + +static bool +DT_Performance_Cmd_Validate ( + Performance_Cmd_t *cmd) +{ + if ( '\0' == cmd->server_name[0] ) + { + DT_Mdep_printf ("Must specify server_name in command line or scriptfile\n"); + return (false); + } + + if ( '\0' == cmd->dapl_name[0] ) + { + DT_Mdep_printf ("Must specify device_name in command line or scriptfile\n"); + return (false); + } + + if ( 0 == cmd->pipeline_len ) + { + DT_Mdep_printf ("Pipeline size must not be 0\n"); + return (false); + } + + if ( cmd->debug ) + { + DT_Performance_Cmd_Print (cmd); + } + + return true; +} + + +void +DT_Performance_Cmd_Print ( + Performance_Cmd_t *cmd) +{ + DT_Mdep_printf ("-------------------------------------\n"); + DT_Mdep_printf ("PerfCmd.server_name : %s\n", + cmd->server_name); + DT_Mdep_printf ("PerfCmd.dapl_name : %s\n", + cmd->dapl_name); + DT_Mdep_printf ("PerfCmd.mode : %s\n", + (cmd->mode == BLOCKING_MODE) ? "BLOCKING" : "POLLING"); + DT_Mdep_printf ("PerfCmd.num_iterations : %d\n", + cmd->num_iterations); + DT_Mdep_printf ("PerfCmd.pipeline_len : %d\n", + cmd->pipeline_len); + DT_Mdep_printf ("PerfCmd.op.transfer_type : %s\n", + cmd->op.transfer_type == RDMA_READ ? "RDMA_READ" : + cmd->op.transfer_type == RDMA_WRITE ? "RDMA_WRITE" : + "SEND_RECV"); + DT_Mdep_printf ("PerfCmd.op.num_segs : %d\n", + cmd->op.num_segs); + DT_Mdep_printf ("PerfCmd.op.seg_size : %d\n", + cmd->op.seg_size); +} + + +bool +DT_Performance_Cmd_Parse ( + Performance_Cmd_t *cmd, + int my_argc, + char **my_argv, + mygetopt_t *opts) +{ + char c; + unsigned int len; + + for (;;) + { + c = DT_mygetopt_r (my_argc, my_argv, "D:dm:i:p:R:s:", opts); + + if ( EOF == c ) + { + break; + } + + switch ( c ) + { + case 'D': /* device name */ + { + strncpy (cmd->dapl_name, opts->optarg, NAME_SZ); + break; + } + case 'd': /* print debug messages */ + { + DT_dapltest_debug++; + cmd->debug = true; + break; + } + case 'm': /* mode */ + { + if ( !strncmp (opts->optarg, "b", strlen ("b")) ) + { + cmd->mode = BLOCKING_MODE; + } + else if ( !strncmp (opts->optarg, "p", strlen ("p")) ) + { + cmd->mode = POLLING_MODE; + } + else + { + DT_Mdep_printf ("Syntax Error -m option\n"); + DT_Performance_Cmd_Usage (); + return (false); + } + + break; + } + case 'i': /* num iterations */ + { + len = (unsigned int)strspn (opts->optarg, "0123456789"); + if (len == 0 || len != strlen (opts->optarg)) + { + DT_Mdep_printf ("Syntax Error -i option\n"); + DT_Performance_Cmd_Usage (); + return (false); + } + cmd->num_iterations = atol (opts->optarg); + break; + } + case 'p': /* pipline size */ + { + len = (unsigned int)strspn (opts->optarg, "0123456789"); + if (len == 0 || len != strlen (opts->optarg)) + { + DT_Mdep_printf ("Syntax Error -p option\n"); + DT_Performance_Cmd_Usage (); + return (false); + } + cmd->pipeline_len = atol (opts->optarg); + break; + } + case 'R': /* Service Reliability Level */ + { + cmd->qos = DT_ParseQoS (opts->optarg); + break; + } + case 's': /* server name */ + { + if ((opts->optarg == 0) || + strlen (opts->optarg) == 0 || + *opts->optarg == '-') + { + DT_Mdep_printf ("must specify server name\n"); + DT_Performance_Cmd_Usage (); + return (false); + } + + strncpy (cmd->server_name, opts->optarg, NAME_SZ); + break; + } + default: + { + DT_Mdep_printf ("Invalid Performance Test Parameter: %c\n", c); + DT_Performance_Cmd_Usage (); + return (false); + } + } + } + + /* + * now parse the op + */ + if ( !DT_Performance_Cmd_Parse_Op (cmd, opts->optind, my_argc, my_argv) ) + { + DT_Performance_Cmd_Usage (); + return (false); + } + + if ( !DT_Performance_Cmd_Validate (cmd) ) + { + DT_Performance_Cmd_Usage (); + return (false); + } + + return (true); +} + + +bool +DT_Performance_Cmd_Init (Performance_Cmd_t * cmd) +{ + memset (cmd, 0, sizeof (Performance_Cmd_t)); + cmd->dapltest_version = DAPLTEST_VERSION; + cmd->client_is_little_endian = DT_local_is_little_endian; + cmd->qos = DAT_QOS_BEST_EFFORT; + cmd->debug = false; + cmd->num_iterations = 1000; + cmd->pipeline_len = ~0; + + cmd->op.transfer_type = RDMA_WRITE; + cmd->op.seg_size = 4096; + cmd->op.num_segs = 1; + + if ( !DT_Mdep_GetDefaultDeviceName (cmd->dapl_name) ) + { + DT_Mdep_printf ("can't get default device name\n"); + return (false); + } + + return (true); +} + + +void +DT_Performance_Cmd_Endian (Performance_Cmd_t * cmd) +{ + cmd->dapltest_version = DT_Endian32 (cmd->dapltest_version); + cmd->qos = DT_Endian32 (cmd->qos); + cmd->num_iterations = DT_Endian32 (cmd->num_iterations); + cmd->debug = DT_Endian32 (cmd->debug); + + cmd->op.transfer_type = DT_Endian32 (cmd->op.transfer_type); + cmd->op.seg_size = DT_Endian32 (cmd->op.seg_size); + cmd->op.num_segs = DT_Endian32 (cmd->op.num_segs); +} diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_performance_cmd.h b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_performance_cmd.h new file mode 100644 index 00000000..6a0d9b4c --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_performance_cmd.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#ifndef __DAPL_PERFORMANCE_CMD_H__ +#define __DAPL_PERFORMANCE_CMD_H__ + +#include + +#define NAME_SZ 256 + +typedef enum +{ + BLOCKING_MODE, + POLLING_MODE +} Performance_Mode_Type; + +typedef struct +{ + DAT_UINT32 transfer_type; + DAT_UINT32 seg_size; + DAT_UINT32 num_segs; +}Performance_Cmd_Op_t; + +typedef struct +{ + DAT_UINT32 dapltest_version; + DAT_UINT32 client_is_little_endian; + char server_name[NAME_SZ]; /* -s */ + char dapl_name[NAME_SZ]; /* -D */ + DAT_QOS qos; + DAT_UINT32 debug; /* -d */ + Performance_Mode_Type mode; /* -m */ + DAT_UINT32 num_iterations; /* -i */ + DAT_UINT32 pipeline_len; /* -p */ + Performance_Cmd_Op_t op; + DAT_UINT32 use_rsp; /* -r */ + +} Performance_Cmd_t; + +#endif diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_performance_server.c b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_performance_server.c new file mode 100644 index 00000000..53c85393 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_performance_server.c @@ -0,0 +1,411 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include + +#include "dapl_bpool.h" +#include "dapl_mdep.h" +#include "dapl_memlist.h" +#include "dapl_performance_cmd.h" +#include "dapl_performance_test.h" +#include "dapl_proto.h" +#include "dapl_test_data.h" + + +/****************************************************************************/ +void +DT_Performance_Test_Server ( + void *var) +{ + Per_Test_Data_t *pt_ptr = var; + Performance_Test_t *test_ptr = NULL; + + int success = 1; + + DT_Mdep_debug (("Server: Starting performance test\n")); + + if ( !DT_Performance_Test_Create (pt_ptr, + pt_ptr->ps_ptr->ia_handle, + (DAT_IA_ADDRESS_PTR) 0, + true, + pt_ptr->Client_Info.is_little_endian, + &test_ptr) ) + { + DT_Mdep_printf ("Server: Resource Creation Failed\n"); + success = 0; + } + if ( 1 == success ) + { + if (! DT_Performance_Test_Server_Connect (test_ptr) ) + { + success = 0; + DT_Mdep_printf ("Server: Connection Failed\n"); + } + } + + if ( 1 == success ) + { + if ( ! DT_Performance_Test_Server_Exchange (test_ptr) ) + { + success = 0; + DT_Mdep_printf ("Server: Test Failed\n"); + } + } + +#ifdef CM_BUSTED + /***** XXX Chill out a bit to give the kludged CM a chance ... + *****/DT_Mdep_Sleep (5000); +#endif + + + + DT_Performance_Test_Destroy (pt_ptr, test_ptr, true); + + DT_Mdep_printf ("Server: Finished performance test. Detaching.\n"); + + DT_Mdep_Thread_Detach (DT_Mdep_Thread_SELF ()); /* AMM */ + DT_Thread_Destroy (pt_ptr->thread, pt_ptr); /* destroy Master thread */ + + DT_Mdep_Lock (&pt_ptr->ps_ptr->num_clients_lock); + pt_ptr->ps_ptr->num_clients--; + DT_Mdep_Unlock (&pt_ptr->ps_ptr->num_clients_lock); + + DT_PrintMemList (pt_ptr); /* check if we return all space allocated */ + DT_Mdep_LockDestroy (&pt_ptr->Thread_counter_lock); + DT_Mdep_LockDestroy (&pt_ptr->MemListLock); + DT_Free_Per_Test_Data (pt_ptr); + + DT_Mdep_Unlock (&g_PerfTestLock); + DT_Mdep_printf ("Server: Finished performance test. Exiting.\n"); + + DT_Mdep_Thread_EXIT (NULL); +} + + +/****************************************************************************/ +bool +DT_Performance_Test_Server_Connect ( + Performance_Test_t *test_ptr) +{ + DAT_RETURN ret; + bool status; + DAT_RSP_HANDLE rsp_handle; + DAT_PSP_HANDLE psp_handle; + + DAT_CR_ARRIVAL_EVENT_DATA cr_stat; + DAT_CR_HANDLE cr_handle; + DAT_EVENT_NUMBER event_num; + + rsp_handle = DAT_HANDLE_NULL; + psp_handle = DAT_HANDLE_NULL; +#if 0 /* FIXME */ + if (test_ptr->cmd->use_rsp) + { + /* + * Server - create a single-use RSP and + * await a connection for this EP + */ + ret = dat_rsp_create (test_ptr->ia_handle, + test_ptr->ep_context.port, + test_ptr->ep_context.ep_handle, + test_ptr->creq_evd_hdl, + &rsp_handle); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("Test[" F64x "]: dat_rsp_create error: %s\n", + (DAT_UVERYLONG)test_ptr->base_port, DT_RetToString (ret)); + status = false; + goto psp_free; + } + + DT_Mdep_debug (("Server[" F64x "]: Listen on RSP port 0x" F64x "\n", + (DAT_UVERYLONG)test_ptr->base_port, + (DAT_UVERYLONG)test_ptr->ep_context.port)); + + /* wait for the connection request */ + if (!DT_cr_event_wait (test_ptr->conn_evd_hdl, &cr_stat) || + !DT_cr_check ( &cr_stat, + DAT_HANDLE_NULL, + test_ptr->ep_context.port, + &cr_handle, + "Server") ) + { + status = false; + goto psp_free; + } + + /* what, me query? just try to accept the connection */ + ret = dat_cr_accept (cr_handle, + test_ptr->ep_context.ep_handle, + 0, (DAT_PVOID)0 /* no private data */ ); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("Test[" F64x "]: dat_cr_accept error: %s\n", + (DAT_UVERYLONG)test_ptr->base_port, DT_RetToString (ret)); + /* cr_handle consumed on failure */ + status = false; + goto psp_free; + } + + /* wait for DAT_CONNECTION_EVENT_ESTABLISHED */ + if (!DT_conn_event_wait ( test_ptr->ep_context.ep_handle, + test_ptr->conn_evd_hdl, + &event_num)) + { + /* error message printed by DT_conn_event_wait */ + status = false; + goto psp_free; + } + + } + else +#endif /* FIXME */ + { + /* + * Server - use a short-lived PSP instead of an RSP + */ + status = true; + + ret = dat_psp_create (test_ptr->ia_handle, + test_ptr->ep_context.port, + test_ptr->creq_evd_hdl, + DAT_PSP_CONSUMER_FLAG, + &psp_handle); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("Test[" F64x "]: dat_psp_create error: %s\n", + (DAT_UVERYLONG)test_ptr->base_port, DT_RetToString (ret)); + status = false; + psp_handle = DAT_HANDLE_NULL; + return (status); + } + + } + + /* + * Here's where we tell the main server process that + * this thread is ready to wait for a connection request + * from the remote end. + */ + DT_Mdep_wait_object_wakeup (&test_ptr->pt_ptr->synch_wait_object); + + DT_Mdep_debug (("Server[" F64x "]: Listen on PSP port 0x" F64x "\n", + (DAT_UVERYLONG)test_ptr->base_port, + (DAT_UVERYLONG)test_ptr->ep_context.port)); + + /* wait for a connection request */ + if (!DT_cr_event_wait (test_ptr->creq_evd_hdl, &cr_stat) || + !DT_cr_check ( &cr_stat, + psp_handle, + test_ptr->ep_context.port, + &cr_handle, + "Server") ) + { + status = false; + goto psp_free; + } + + /* what, me query? just try to accept the connection */ + ret = dat_cr_accept (cr_handle, + test_ptr->ep_context.ep_handle, + 0, + (DAT_PVOID)0 /* no private data */ ); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("Test[" F64x "]: dat_cr_accept error: %s\n", + (DAT_UVERYLONG)test_ptr->base_port, DT_RetToString (ret)); + /* cr_handle consumed on failure */ + status = false; + goto psp_free; + } + + /* wait for DAT_CONNECTION_EVENT_ESTABLISHED */ + if (!DT_conn_event_wait (test_ptr->ep_context.ep_handle, + test_ptr->conn_evd_hdl, + &event_num ) ) + { + /* error message printed by DT_cr_event_wait */ + status = false; + goto psp_free; + } + + DT_Mdep_debug (("Server[" F64x "]: Accept on port 0x" F64x "\n", + (DAT_UVERYLONG)test_ptr->base_port, + (DAT_UVERYLONG)test_ptr->ep_context.port)); +psp_free: + if ( DAT_HANDLE_NULL != psp_handle ) + { + /* throw away single-use PSP */ + ret = dat_psp_free (psp_handle); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("Test[" F64x "]: dat_psp_free error: %s\n", + (DAT_UVERYLONG)test_ptr->base_port, DT_RetToString (ret)); + status = false; + } + } + if ( DAT_HANDLE_NULL != rsp_handle ) + { + /* throw away single-use PSP */ + ret = dat_rsp_free (rsp_handle); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("Test[" F64x "]: dat_rsp_free error: %s\n", + (DAT_UVERYLONG)test_ptr->base_port, DT_RetToString (ret)); + status = false; + } + } /* end short-lived PSP */ + +#ifdef CM_BUSTED + /***** XXX Chill out a bit to give the kludged CM a chance ... + *****/DT_Mdep_Sleep (5000); +#endif + + return status; +} + + + +/****************************************************************************/ +bool +DT_Performance_Test_Server_Exchange ( + Performance_Test_t *test_ptr) +{ + DAT_DTO_COMPLETION_EVENT_DATA dto_stat; + RemoteMemoryInfo *rmi; + DAT_DTO_COOKIE dto_cookie; + + test_ptr->ep_context.op.bp = + DT_BpoolAlloc (test_ptr->pt_ptr, + test_ptr->ia_handle, + test_ptr->pz_handle, + test_ptr->ep_context.ep_handle, + test_ptr->reqt_evd_hdl, + test_ptr->ep_context.op.seg_size, + test_ptr->ep_context.op.num_segs, + DAT_OPTIMAL_ALIGNMENT, + true, + true); + + if ( !test_ptr->ep_context.op.bp ) + { + DT_Mdep_printf ("Test[" F64x "]: no memory for buffers (RDMA/RD)\n", + (DAT_UVERYLONG)test_ptr->base_port); + return false; + } + + test_ptr->ep_context.op.Rdma_Context = + DT_Bpool_GetRMR (test_ptr->ep_context.op.bp, 0); + test_ptr->ep_context.op.Rdma_Address = + (DAT_PVOID) (uintptr_t) DT_Bpool_GetBuffer (test_ptr->ep_context.op.bp, 0); + + /* + * Prep send buffer with memory information + */ + rmi = (RemoteMemoryInfo *) DT_Bpool_GetBuffer (test_ptr->ep_context.bp, + DT_PERF_SYNC_SEND_BUFFER_ID); + + rmi->rmr_context = test_ptr->ep_context.op.Rdma_Context; + rmi->mem_address.as_64 = (DAT_UINT64) LZERO; + rmi->mem_address.as_ptr =test_ptr->ep_context.op.Rdma_Address; + + if ( rmi->mem_address.as_ptr ) + { + DT_Mdep_spew (3, ("RemoteMemInfo va=" F64x ", ctx=%x\n", + (DAT_UVERYLONG)rmi->mem_address.as_64, + rmi->rmr_context)); + } + + /* + * If the client and server are of different endiannesses, + * we must correct the endianness of the handle and address + * we pass to the other side. The other side cannot (and + * better not) interpret these values. + */ + if (DT_local_is_little_endian != test_ptr->is_remote_little_endian) + { + rmi->rmr_context = DT_EndianMemHandle (rmi->rmr_context); + rmi->mem_address.as_64 =DT_EndianMemAddress (rmi->mem_address.as_64); + } + + /* + * Send our memory info + */ + DT_Mdep_debug (("Test[" F64x "]: Sending Sync Msg\n", + (DAT_UVERYLONG)test_ptr->base_port)); + + /* post the send buffer */ + if (!DT_post_send_buffer (test_ptr->ep_context.ep_handle, + test_ptr->ep_context.bp, + DT_PERF_SYNC_SEND_BUFFER_ID, + DT_PERF_SYNC_BUFF_SIZE)) + { + /* error message printed by DT_post_send_buffer */ + return false; + } + + /* reap the send and verify it */ + dto_cookie.as_64 = LZERO; + dto_cookie.as_ptr = + (DAT_PVOID) DT_Bpool_GetBuffer ( + test_ptr->ep_context.bp, + DT_PERF_SYNC_SEND_BUFFER_ID); + if ( !DT_dto_event_wait (test_ptr->reqt_evd_hdl, &dto_stat) || + !DT_dto_check (&dto_stat, + test_ptr->ep_context.ep_handle, + DT_PERF_SYNC_BUFF_SIZE, + dto_cookie, + "Send Sync_Msg") ) + { + return false; + } + + /* + * Recv the other side's info + */ + DT_Mdep_debug (("Test[" F64x "]: Waiting for Sync Msg\n", + (DAT_UVERYLONG)test_ptr->base_port)); + + dto_cookie.as_64 = LZERO; + dto_cookie.as_ptr = + (DAT_PVOID) DT_Bpool_GetBuffer ( + test_ptr->ep_context.bp, + DT_PERF_SYNC_RECV_BUFFER_ID); + if ( !DT_dto_event_wait (test_ptr->recv_evd_hdl, &dto_stat) || + !DT_dto_check ( &dto_stat, + test_ptr->ep_context.ep_handle, + DT_PERF_SYNC_BUFF_SIZE, + dto_cookie, + "Recieve Sync_Msg") ) + { + return false; + } + + DT_Mdep_debug (("Test[" F64x "]: Received Sync Msg\n", + (DAT_UVERYLONG)test_ptr->base_port)); + + return true; +} diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_performance_stats.c b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_performance_stats.c new file mode 100644 index 00000000..1f42887b --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_performance_stats.c @@ -0,0 +1,389 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_performance_stats.h" +#include "dapl_proto.h" +#include "dapl_test_data.h" + + +void +DT_performance_stats_init ( + Performance_Stats_t *stats) +{ + stats->num_ops = 0; + stats->bytes = 0; + stats->post_ctxt_switch_num = 0; + stats->reap_ctxt_switch_num = 0; + + stats->cpu_utilization = 0.0; + stats->time_ts = 0; + + stats->posts_sans_ctxt.num = 0; + stats->posts_sans_ctxt.total_ts = 0; + stats->posts_sans_ctxt.max_ts = 0; + stats->posts_sans_ctxt.min_ts = ~0; + + stats->posts_with_ctxt.num = 0; + stats->posts_with_ctxt.total_ts = 0; + stats->posts_with_ctxt.max_ts = 0; + stats->posts_with_ctxt.min_ts = ~0; + + stats->reaps_sans_ctxt.num = 0; + stats->reaps_sans_ctxt.total_ts = 0; + stats->reaps_sans_ctxt.max_ts = 0; + stats->reaps_sans_ctxt.min_ts = ~0; + + stats->reaps_with_ctxt.num = 0; + stats->reaps_with_ctxt.total_ts = 0; + stats->reaps_with_ctxt.max_ts = 0; + stats->reaps_with_ctxt.min_ts = ~0; + + stats->latency.num = 0; + stats->latency.total_ts = 0; + stats->latency.max_ts = 0; + stats->latency.min_ts = ~0; +} + + +void +DT_performance_stats_record_post ( + Performance_Stats_t *stats, + unsigned long ctxt_switch_num, + DT_Mdep_TimeStamp ts) +{ + if ( ctxt_switch_num ) + { + stats->posts_with_ctxt.num++; + stats->posts_with_ctxt.total_ts += ts; + stats->posts_with_ctxt.max_ts = + DT_max (stats->posts_with_ctxt.max_ts, ts); + stats->posts_with_ctxt.min_ts = + DT_min (stats->posts_with_ctxt.min_ts, ts); + + stats->post_ctxt_switch_num += ctxt_switch_num; + } + else + { + stats->posts_sans_ctxt.num++; + stats->posts_sans_ctxt.total_ts += ts; + stats->posts_sans_ctxt.max_ts = + DT_max (stats->posts_sans_ctxt.max_ts, ts); + stats->posts_sans_ctxt.min_ts = + DT_min (stats->posts_sans_ctxt.min_ts, ts); + } +} + + +void +DT_performance_stats_record_reap ( + Performance_Stats_t *stats, + unsigned long ctxt_switch_num, + DT_Mdep_TimeStamp ts) +{ + if ( ctxt_switch_num ) + { + stats->reaps_with_ctxt.num++; + stats->reaps_with_ctxt.total_ts += ts; + stats->reaps_with_ctxt.max_ts = + DT_max (stats->reaps_with_ctxt.max_ts, ts); + stats->reaps_with_ctxt.min_ts = + DT_min (stats->reaps_with_ctxt.min_ts, ts); + + stats->reap_ctxt_switch_num += ctxt_switch_num; + } + else + { + stats->reaps_sans_ctxt.num++; + stats->reaps_sans_ctxt.total_ts += ts; + stats->reaps_sans_ctxt.max_ts = + DT_max (stats->reaps_sans_ctxt.max_ts, ts); + stats->reaps_sans_ctxt.min_ts = + DT_min (stats->reaps_sans_ctxt.min_ts, ts); + } +} + + +void +DT_performance_stats_record_latency ( + Performance_Stats_t *stats, + DT_Mdep_TimeStamp ts) +{ + stats->latency.num++; + stats->latency.total_ts += ts; + stats->latency.max_ts = + DT_max (stats->latency.max_ts, ts); + stats->latency.min_ts = + DT_min (stats->latency.min_ts, ts); +} + +void +DT_performance_stats_data_combine ( + Performance_Stats_Data_t *dest, + Performance_Stats_Data_t *src_a, + Performance_Stats_Data_t *src_b) +{ + dest->num = src_a->num + src_b->num; + dest->total_ts = src_a->total_ts + src_b->total_ts; + dest->max_ts = DT_max (src_a->max_ts, src_b->max_ts); + dest->min_ts = DT_min (src_a->min_ts, src_b->min_ts); +} + + +void +DT_performance_stats_combine ( + Performance_Stats_t *dest, + Performance_Stats_t *src_a, + Performance_Stats_t *src_b) +{ + dest->num_ops = + src_a->num_ops + src_b->num_ops; + + dest->bytes = + src_a->bytes + src_b->bytes; + + dest->post_ctxt_switch_num = + src_a->post_ctxt_switch_num + src_b->post_ctxt_switch_num; + + dest->reap_ctxt_switch_num = + src_b->reap_ctxt_switch_num + src_b->reap_ctxt_switch_num; + + dest->cpu_utilization = DT_max (src_a->cpu_utilization, + src_b->cpu_utilization); + dest->time_ts = DT_max (src_a->time_ts, src_b->time_ts); + + DT_performance_stats_data_combine (&dest->posts_sans_ctxt, + &src_a->posts_sans_ctxt, + &src_b->posts_sans_ctxt); + + DT_performance_stats_data_combine (&dest->posts_with_ctxt, + &src_a->posts_with_ctxt, + &src_b->posts_with_ctxt); + + DT_performance_stats_data_combine (&dest->reaps_sans_ctxt, + &src_a->reaps_sans_ctxt, + &src_b->reaps_sans_ctxt); + + DT_performance_stats_data_combine (&dest->reaps_with_ctxt, + &src_a->reaps_with_ctxt, + &src_b->reaps_with_ctxt); + + DT_performance_stats_data_combine (&dest->latency, + &src_a->latency, + &src_b->latency); +} + + +double +DT_performance_stats_data_print ( + Performance_Stats_Data_t *data, + double cpu_mhz) +{ + double average; + + average = (double)data->total_ts / (data->num * cpu_mhz); + + DT_Mdep_printf ("%-32s : %11.04f us\n" + "%-32s : %11.04f us\n" + "%-32s : %11.04f us\n", + " arithmetic mean", + average, + " maximum", + (double)data->max_ts / cpu_mhz, + " minimum", + (double)data->min_ts / cpu_mhz); + + return average; +} + + +void +DT_performance_stats_print ( + Performance_Stats_t *stats, + Performance_Cmd_t *cmd, + Performance_Test_t *test) +{ + double cpu_mhz; + double time_s; + double mbytes; + double ops_per_sec; + double bandwidth; + double latency; + double time_per_post; + double time_per_reap; + + cpu_mhz = DT_Mdep_GetCpuMhz (); + latency = 0; + + time_s = ((double)stats->time_ts / (1000000.0 * cpu_mhz)); + + mbytes = (double) (stats->bytes >> 20 ); + + if ( 0.0 == time_s ) + { + DT_Mdep_printf ("Error determining time\n"); + return; + } + else if ( 0 == stats->num_ops ) + { + DT_Mdep_printf ("Error determining number of operations\n"); + return; + } + else if ( 0.0 == cpu_mhz ) + { + DT_Mdep_printf ("Error determining CPU speed\n"); + return; + } + + ops_per_sec = (double)stats->num_ops / time_s; + bandwidth = mbytes / time_s; + + DT_Mdep_printf ("\n" + "------------------------- Statistics -------------------------\n" + "\n" + "%-32s : %8s\n" + "%-32s : %8s\n" + "%-32s : %8u\n" + "%-32s : %8u bytes\n" + "%-32s : %8u\n" + "%-32s : %8u\n" + "\n", + "Mode", + DT_PerformanceModeToString (cmd->mode), + "Operation Type", + DT_TransferTypeToString (cmd->op.transfer_type), + "Number of Operations", + cmd->num_iterations, + "Segment Size", + cmd->op.seg_size, + "Number of Segments", + cmd->op.num_segs, + "Pipeline Size", + test->ep_context.pipeline_len); + + DT_Mdep_printf ("%-32s : %11.04f sec\n" + "%-32s : %11.04f MB\n" + "%-32s : %11.04f%%\n" + "%-32s : %11.04f ops/sec\n" + "%-32s : %11.04f MB/sec\n", + "Total Time", + time_s, + "Total Data Exchanged", + mbytes, + "CPU Utilization", + stats->cpu_utilization, + "Operation Throughput", + ops_per_sec, + "Bandwidth", + bandwidth); + + DT_Mdep_printf ("\n" + "Latency\n" + "\n"); + + if ( stats->latency.num ) + { + latency = DT_performance_stats_data_print (&stats->latency, cpu_mhz); + } + + DT_Mdep_printf ("\n" + "Time Per Post\n" + "\n" + "%-32s : %8u\n", + " posts without context switches", + stats->posts_sans_ctxt.num); + + if ( stats->posts_sans_ctxt.num ) + { + DT_performance_stats_data_print (&stats->posts_sans_ctxt, cpu_mhz); + } + + DT_Mdep_printf ("\n" + "%-32s : %8u\n", + " posts with context switches", + stats->posts_with_ctxt.num); + + if ( stats->posts_with_ctxt.num ) + { + DT_Mdep_printf ("%-32s : %8u\n", + " number of context switches", + stats->post_ctxt_switch_num); + DT_performance_stats_data_print (&stats->posts_with_ctxt, cpu_mhz); + } + + DT_Mdep_printf ("\n" + "Time Per Reap\n" + "\n" + "%-32s : %8u\n", + " reaps without context switches", + stats->reaps_sans_ctxt.num); + + if ( stats->reaps_sans_ctxt.num ) + { + DT_performance_stats_data_print (&stats->reaps_sans_ctxt, cpu_mhz); + } + + + DT_Mdep_printf ("\n" + "%-32s : %8u\n", + " reaps with context switches", + stats->reaps_with_ctxt.num); + + if ( stats->reaps_with_ctxt.num ) + { + DT_Mdep_printf ("%-32s : %8u\n", + " number of context switches", + stats->reap_ctxt_switch_num); + + DT_performance_stats_data_print (&stats->reaps_with_ctxt, cpu_mhz); + } + + time_per_post = + (int64_t) (stats->posts_sans_ctxt.total_ts + stats->posts_with_ctxt.total_ts) / + (cpu_mhz * (stats->posts_sans_ctxt.num + stats->posts_with_ctxt.num)); + + time_per_reap = + (int64_t) (stats->reaps_sans_ctxt.total_ts + stats->reaps_with_ctxt.total_ts) / + (cpu_mhz * (stats->reaps_sans_ctxt.num + stats->reaps_with_ctxt.num)); + + DT_Mdep_printf ("\n" + "NOTE:\n" + " 1 MB = 1024 KB = 1048576 B \n" + "-------------------------------------------------------------\n" + "raw: %s, %u, %u, %u, %u, %f, %f, %f, %f, %f, %f \n" + "-------------------------------------------------------------\n" + "\n", + DT_TransferTypeToString (cmd->op.transfer_type), + cmd->num_iterations, + cmd->op.seg_size, + cmd->op.num_segs, + test->ep_context.pipeline_len, + stats->cpu_utilization, + ops_per_sec, + bandwidth, + latency, + time_per_post, + time_per_reap); +} diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_performance_stats.h b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_performance_stats.h new file mode 100644 index 00000000..143291f1 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_performance_stats.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#ifndef __DAPL_STATS_H__ +#define __DAPL_STATS_H__ + +#include "dapl_mdep.h" + +#define DT_min(a,b) ((a < b) ? (a) : (b)) +#define DT_max(a,b) ((a > b) ? (a) : (b)) +#define DT_whole(num) ((unsigned int)(num)) +#define DT_hundredths(num) ((unsigned int)(((num) - (unsigned int)(num)) * 100)) + +typedef struct +{ + unsigned int num; + DT_Mdep_TimeStamp total_ts; + DT_Mdep_TimeStamp max_ts; + DT_Mdep_TimeStamp min_ts; +} Performance_Stats_Data_t; + + +typedef struct +{ + unsigned int num_ops; + int64_t bytes; + unsigned int post_ctxt_switch_num; + unsigned int reap_ctxt_switch_num; + double cpu_utilization; + DT_Mdep_TimeStamp time_ts; + Performance_Stats_Data_t posts_sans_ctxt; + Performance_Stats_Data_t posts_with_ctxt; + Performance_Stats_Data_t reaps_sans_ctxt; + Performance_Stats_Data_t reaps_with_ctxt; + Performance_Stats_Data_t latency; +} Performance_Stats_t; + +#endif diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_performance_test.h b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_performance_test.h new file mode 100644 index 00000000..fda5e147 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_performance_test.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#ifndef __DAPL_PERFORMANCE_TEST_H__ +#define __DAPL_PERFORMANCE_TEST_H__ + +#include "dapl_common.h" +#include "dapl_test_data.h" +#include "dapl_mdep.h" +#include "dapl_performance_cmd.h" + + +#define DT_PERF_SYNC_SEND_BUFFER_ID 0 +#define DT_PERF_SYNC_RECV_BUFFER_ID 1 +#define DT_PERF_SYNC_BUFF_SIZE sizeof(RemoteMemoryInfo) +#define DT_PERF_DFLT_EVD_LENGTH 8 + +typedef struct +{ + DT_Transfer_Type transfer_type; + DAT_UINT32 num_segs; + DAT_UINT32 seg_size; + Bpool *bp; + + /* RDMA info */ + DAT_RMR_CONTEXT Rdma_Context; + DAT_PVOID Rdma_Address; +} Performance_Test_Op_t; + +typedef struct +{ + DAT_EP_HANDLE ep_handle; + DAT_EP_ATTR ep_attr; + DAT_CONN_QUAL port; + DAT_COUNT pipeline_len; + Bpool *bp; + Performance_Test_Op_t op; +} Performance_Ep_Context_t; + +typedef struct +{ + Per_Test_Data_t *pt_ptr; + Performance_Cmd_t *cmd; + DAT_IA_ADDRESS_PTR remote_ia_addr; + DAT_BOOLEAN is_remote_little_endian; + DAT_CONN_QUAL base_port; + DAT_IA_ATTR ia_attr; + DAT_IA_HANDLE ia_handle; + DAT_PZ_HANDLE pz_handle; + DAT_CNO_HANDLE cno_handle; + DAT_COUNT reqt_evd_length; + DAT_EVD_HANDLE reqt_evd_hdl; /* request+rmr */ + DAT_COUNT recv_evd_length; + DAT_EVD_HANDLE recv_evd_hdl; /* receive */ + DAT_COUNT conn_evd_length; + DAT_EVD_HANDLE conn_evd_hdl; /* connect */ + DAT_COUNT creq_evd_length; + DAT_EVD_HANDLE creq_evd_hdl; /* "" request */ + Performance_Ep_Context_t ep_context; +} Performance_Test_t; + +#endif diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_performance_util.c b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_performance_util.c new file mode 100644 index 00000000..48db4add --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_performance_util.c @@ -0,0 +1,652 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_bpool.h" +#include "dapl_mdep.h" +#include "dapl_performance_test.h" +#include "dapl_proto.h" + +#define DT_Mdep_GetContextSwitchNum() 0 /* FIXME */ + +/****************************************************************************/ +bool +DT_Performance_Test_Create ( + Per_Test_Data_t *pt_ptr, + DAT_IA_HANDLE *ia_handle, + DAT_IA_ADDRESS_PTR remote_ia_addr, + DAT_BOOLEAN is_server, + DAT_BOOLEAN is_remote_little_endian, + Performance_Test_t **perf_test) +{ + Performance_Test_t *test_ptr; + DAT_COUNT pipeline_len; + DAT_RETURN ret; + + test_ptr = DT_MemListAlloc (pt_ptr, + "transaction_test_t", + TRANSACTIONTEST, + sizeof (Performance_Test_t)); + if ( NULL == test_ptr ) + { + return false; + } + + *perf_test = test_ptr; + + test_ptr->pt_ptr = pt_ptr; + test_ptr->remote_ia_addr = remote_ia_addr; + test_ptr->is_remote_little_endian = is_remote_little_endian; + test_ptr->base_port = (DAT_CONN_QUAL) pt_ptr->Server_Info.first_port_number; + test_ptr->ia_handle = ia_handle; + test_ptr->cmd = &pt_ptr->Params.u.Performance_Cmd; + + ret = dat_ia_query (test_ptr->ia_handle, + NULL, + DAT_IA_ALL, + &test_ptr->ia_attr, + 0, + NULL); + if ( DAT_SUCCESS != ret) + { + DT_Mdep_printf ("Test[" F64x "]: dat_ia_query error: %s\n", + (DAT_UVERYLONG)test_ptr->base_port, DT_RetToString (ret)); + return false; + } + + pipeline_len = DT_min ( + DT_min (test_ptr->cmd->num_iterations, + test_ptr->cmd->pipeline_len), + (DAT_UINT32)DT_min (test_ptr->ia_attr.max_dto_per_ep, + test_ptr->ia_attr.max_evd_qlen)); + + if ( RDMA_READ == test_ptr->cmd->op.transfer_type ) + { + pipeline_len = DT_min (pipeline_len, + test_ptr->ia_attr.max_rdma_read_per_ep); + } + + test_ptr->reqt_evd_length = pipeline_len; + test_ptr->recv_evd_length = DT_PERF_DFLT_EVD_LENGTH; + test_ptr->conn_evd_length = DT_PERF_DFLT_EVD_LENGTH; + test_ptr->creq_evd_length = DT_PERF_DFLT_EVD_LENGTH; + + /* create a protection zone */ + ret = dat_pz_create (test_ptr->ia_handle, &test_ptr->pz_handle); + if ( DAT_SUCCESS != ret) + { + DT_Mdep_printf ("Test[" F64x "]: dat_pz_create error: %s\n", + (DAT_UVERYLONG)test_ptr->base_port, DT_RetToString (ret)); + test_ptr->pz_handle = DAT_HANDLE_NULL; + return false; + } + + /* create 4 EVDs - recv, request+RMR, conn-request, connect */ + ret = dat_evd_create (test_ptr->ia_handle, + test_ptr->recv_evd_length, + test_ptr->cno_handle, + DAT_EVD_DTO_FLAG, + &test_ptr->recv_evd_hdl); /* recv */ + if ( DAT_SUCCESS != ret) + { + DT_Mdep_printf ("Test[" F64x "]: dat_evd_create (recv) error: %s\n", + (DAT_UVERYLONG)test_ptr->base_port, DT_RetToString (ret)); + test_ptr->recv_evd_hdl = DAT_HANDLE_NULL; + return false; + } + + ret = dat_evd_create (test_ptr->ia_handle, + test_ptr->reqt_evd_length, + test_ptr->cno_handle, + DAT_EVD_DTO_FLAG | DAT_EVD_RMR_BIND_FLAG, + &test_ptr->reqt_evd_hdl); /* request + rmr bind */ + if ( DAT_SUCCESS != ret) + { + DT_Mdep_printf ("Test[" F64x "]: dat_evd_create (request) error: %s\n", + (DAT_UVERYLONG)test_ptr->base_port, DT_RetToString (ret)); + test_ptr->reqt_evd_hdl = DAT_HANDLE_NULL; + return false; + } + + + if ( is_server ) + { + /* Client-side doesn't need CR events */ + ret = dat_evd_create (test_ptr->ia_handle, + test_ptr->creq_evd_length, + DAT_HANDLE_NULL, + DAT_EVD_CR_FLAG, + &test_ptr->creq_evd_hdl); /* cr */ + if ( DAT_SUCCESS != ret) + { + DT_Mdep_printf ("Test[" F64x "]: dat_evd_create (cr) error: %s\n", + (DAT_UVERYLONG)test_ptr->base_port, DT_RetToString (ret)); + test_ptr->creq_evd_hdl = DAT_HANDLE_NULL; + return false; + } + } + + ret = dat_evd_create (test_ptr->ia_handle, + test_ptr->conn_evd_length, + DAT_HANDLE_NULL, + DAT_EVD_CONNECTION_FLAG, + &test_ptr->conn_evd_hdl); /* conn */ + if ( DAT_SUCCESS != ret) + { + DT_Mdep_printf ("Test[" F64x "]: dat_evd_create (conn) error: %s\n", + (DAT_UVERYLONG)test_ptr->base_port, DT_RetToString (ret)); + test_ptr->conn_evd_hdl = DAT_HANDLE_NULL; + return false; + } + + /* + * Set up the EP context: + * create the EP + * allocate buffers for remote memory info and sync message + * post the receive buffers + * connect + * set up buffers and remote memory info + * send across our info + * recv the other side's info and extract what we need + */ + test_ptr->ep_context.ep_attr = test_ptr->pt_ptr->ep_attr; + test_ptr->ep_context.ep_attr.max_request_dtos = pipeline_len; + + /* Create EP */ + ret = dat_ep_create (test_ptr->ia_handle, /* IA */ + test_ptr->pz_handle, /* PZ */ + test_ptr->recv_evd_hdl, /* recv */ + test_ptr->reqt_evd_hdl, /* request */ + test_ptr->conn_evd_hdl, /* connect */ + &test_ptr->ep_context.ep_attr, /* EP attrs */ + &test_ptr->ep_context.ep_handle); + if ( DAT_SUCCESS != ret) + { + DT_Mdep_printf ("Test[" F64x "]: dat_ep_create error: %s\n", + (DAT_UVERYLONG)test_ptr->base_port, DT_RetToString (ret)); + test_ptr->ep_context.ep_handle = DAT_HANDLE_NULL; + return false; + } + + /* + * Allocate a buffer pool so we can exchange the + * remote memory info and initialize. + */ + test_ptr->ep_context.bp = DT_BpoolAlloc (test_ptr->pt_ptr, + test_ptr->ia_handle, + test_ptr->pz_handle, + test_ptr->ep_context.ep_handle, + DAT_HANDLE_NULL, /* rmr */ + DT_PERF_SYNC_BUFF_SIZE, + 2, /* 2 RMIs */ + DAT_OPTIMAL_ALIGNMENT, + false, + false); + if ( !test_ptr->ep_context.bp ) + { + DT_Mdep_printf ("Test[" F64x "]: no memory for remote memory buffers\n", + (DAT_UVERYLONG)test_ptr->base_port); + return false; + } + + DT_Mdep_spew (3, ("0: SYNC_SEND %p\n", (DAT_PVOID) DT_Bpool_GetBuffer ( + test_ptr->ep_context.bp, DT_PERF_SYNC_SEND_BUFFER_ID))); + DT_Mdep_spew (3, ("1: SYNC_RECV %p\n", (DAT_PVOID) DT_Bpool_GetBuffer ( + test_ptr->ep_context.bp, DT_PERF_SYNC_RECV_BUFFER_ID))); + + /* + * Post recv and sync buffers + */ + if ( !DT_post_recv_buffer (test_ptr->ep_context.ep_handle, + test_ptr->ep_context.bp, + DT_PERF_SYNC_RECV_BUFFER_ID, + DT_PERF_SYNC_BUFF_SIZE) ) + { + /* error message printed by DT_post_recv_buffer */ + return false; + } + + /* + * Fill in the test_ptr with relevant command info + */ + test_ptr->ep_context.op.transfer_type + = test_ptr->cmd->op.transfer_type; + test_ptr->ep_context.op.num_segs + = test_ptr->cmd->op.num_segs; + test_ptr->ep_context.op.seg_size + = test_ptr->cmd->op.seg_size; + + /* + * Exchange remote memory info: If we're going to participate + * in an RDMA, we need to allocate memory buffers and advertise + * them to the other side. + */ + test_ptr->ep_context.op.Rdma_Context = (DAT_RMR_CONTEXT) 0; + test_ptr->ep_context.op.Rdma_Address = (DAT_PVOID) 0; + test_ptr->ep_context.port = test_ptr->base_port; + test_ptr->ep_context.pipeline_len = pipeline_len; + + return true; +} + + +/****************************************************************************/ +void +DT_Performance_Test_Destroy ( + Per_Test_Data_t *pt_ptr, + Performance_Test_t *test_ptr, + DAT_BOOLEAN is_server) +{ + DAT_RETURN ret; + DAT_EP_HANDLE ep_handle; + + ep_handle = DAT_HANDLE_NULL; + + /* Free the per-op buffers */ + if (test_ptr->ep_context.op.bp) + { + if (!DT_Bpool_Destroy (test_ptr->pt_ptr, + test_ptr->ep_context.op.bp)) + { + DT_Mdep_printf ("Test[" F64x "]: Warning: Bpool destroy fails\n", + (DAT_UVERYLONG)test_ptr->base_port); + /* carry on trying, regardless */ + } + } + + /* Free the remote memory info exchange buffers */ + if (test_ptr->ep_context.bp) + { + if (!DT_Bpool_Destroy (test_ptr->pt_ptr, + test_ptr->ep_context.bp)) + { + DT_Mdep_printf ("Test[" F64x "]: Warning: Bpool destroy fails\n", + (DAT_UVERYLONG)test_ptr->base_port); + /* carry on trying, regardless */ + } + } + + /* + * Disconnect -- we may have left recv buffers posted, if we + * bailed out mid-setup, or ran to completion + * normally, so we use abrupt closure. + */ + if (test_ptr->ep_context.ep_handle) + { + ret = dat_ep_disconnect (test_ptr->ep_context.ep_handle, + DAT_CLOSE_ABRUPT_FLAG); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("Test[" F64x "]: Warning: dat_ep_disconnect error %s\n", + (DAT_UVERYLONG)test_ptr->base_port, + DT_RetToString (ret)); + /* carry on trying, regardless */ + } + else if (!DT_disco_event_wait ( test_ptr->conn_evd_hdl, + &ep_handle)) + { + DT_Mdep_printf ("Test[" F64x "]: bad disconnect event\n", + (DAT_UVERYLONG)test_ptr->base_port); + } + } + + if ( DAT_HANDLE_NULL != ep_handle) + { + /* Destroy the EP */ + ret = dat_ep_free (ep_handle); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("Test[" F64x "]: dat_ep_free error: %s\n", + (DAT_UVERYLONG)test_ptr->base_port, DT_RetToString (ret)); + /* carry on trying, regardless */ + } + } + + /* clean up the EVDs */ + if (test_ptr->conn_evd_hdl) + { + ret = dat_evd_free (test_ptr->conn_evd_hdl); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("Test[" F64x "]: dat_evd_free (conn) error: %s\n", + (DAT_UVERYLONG)test_ptr->base_port, DT_RetToString (ret)); + /* fall through, keep trying */ + } + } + if (is_server) + { + if (test_ptr->creq_evd_hdl) + { + ret = dat_evd_free (test_ptr->creq_evd_hdl); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("Test[" F64x "]: dat_evd_free (creq) error: %s\n", + (DAT_UVERYLONG)test_ptr->base_port, DT_RetToString (ret)); + /* fall through, keep trying */ + } + } + } + if (test_ptr->reqt_evd_hdl) + { + ret = dat_evd_free (test_ptr->reqt_evd_hdl); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("Test[" F64x "]: dat_evd_free (reqt) error: %s\n", + (DAT_UVERYLONG)test_ptr->base_port, DT_RetToString (ret)); + /* fall through, keep trying */ + } + } + if (test_ptr->recv_evd_hdl) + { + ret = dat_evd_free (test_ptr->recv_evd_hdl); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("Test[" F64x "]: dat_evd_free (recv) error: %s\n", + (DAT_UVERYLONG)test_ptr->base_port, DT_RetToString (ret)); + /* fall through, keep trying */ + } + } + +#if 0 /* FIXME */ + /* clean up the CNO */ + if (test_ptr->cmd->use_cno && test_ptr->cno_handle) + { + ret = dat_cno_free (test_ptr->cno_handle); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("Test[" F64x "]: dat_cno_free error: %s\n", + (DAT_UVERYLONG)test_ptr->base_port, DT_RetToString (ret)); + /* fall through, keep trying */ + } + } +#endif /* FIXME */ + + /* clean up the PZ */ + if (test_ptr->pz_handle) + { + ret = dat_pz_free (test_ptr->pz_handle); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("Test[" F64x "]: dat_pz_free error: %s\n", + (DAT_UVERYLONG)test_ptr->base_port, DT_RetToString (ret)); + /* fall through, keep trying */ + } + } + + DT_Mdep_debug (("Test[" F64x "]: cleanup is done\n", + (DAT_UVERYLONG)test_ptr->base_port)); + DT_MemListFree (test_ptr->pt_ptr, test_ptr); +} + + +/****************************************************************************/ +bool +DT_performance_post_rdma_op ( + Performance_Ep_Context_t *ep_context, + DAT_EVD_HANDLE reqt_evd_hdl, + Performance_Stats_t *stats) +{ + unsigned int j; + unsigned long int bytes; + unsigned long pre_ctxt_num; + unsigned long post_ctxt_num; + DT_Mdep_TimeStamp pre_ts; + DT_Mdep_TimeStamp post_ts; + DAT_DTO_COOKIE cookie; + DAT_RETURN ret; + Performance_Test_Op_t *op = &ep_context->op; + DAT_LMR_TRIPLET *iov = DT_Bpool_GetIOV (op->bp, 0); + DAT_RMR_TRIPLET rmr_triplet; + + bytes = op->seg_size * op->num_segs; + + /* Prep the inputs */ + for (j = 0; j < op->num_segs; j++) + { + iov[j].pad = 0U; + iov[j].virtual_address = (DAT_VADDR) (uintptr_t) + DT_Bpool_GetBuffer (op->bp, j); + iov[j].segment_length = op->seg_size; + iov[j].lmr_context = DT_Bpool_GetLMR (op->bp, j); + } + + rmr_triplet.pad = 0U; + rmr_triplet.target_address = (DAT_VADDR) (uintptr_t) op->Rdma_Address; + rmr_triplet.segment_length = op->seg_size * op->num_segs; + rmr_triplet.rmr_context = op->Rdma_Context; + + cookie.as_ptr = NULL; + + if ( RDMA_WRITE == op->transfer_type ) + { + pre_ctxt_num = DT_Mdep_GetContextSwitchNum (); + pre_ts = DT_Mdep_GetTimeStamp (); + + ret = dat_ep_post_rdma_write (ep_context->ep_handle, + op->num_segs, + iov, + cookie, + &rmr_triplet, + DAT_COMPLETION_DEFAULT_FLAG); + + post_ts = DT_Mdep_GetTimeStamp (); + post_ctxt_num = DT_Mdep_GetContextSwitchNum (); + + stats->bytes += bytes; + } + else + { + pre_ctxt_num = DT_Mdep_GetContextSwitchNum (); + pre_ts = DT_Mdep_GetTimeStamp (); + + ret = dat_ep_post_rdma_read (ep_context->ep_handle, + op->num_segs, + iov, + cookie, + &rmr_triplet, + DAT_COMPLETION_DEFAULT_FLAG); + + post_ts = DT_Mdep_GetTimeStamp (); + post_ctxt_num = DT_Mdep_GetContextSwitchNum (); + + stats->bytes += bytes; + } + + if ( DAT_SUCCESS != ret ) + { + return false; + } + + DT_performance_stats_record_post (stats, + post_ctxt_num - pre_ctxt_num, + post_ts - pre_ts); + + return true; +} + +/****************************************************************************/ +unsigned int +DT_performance_reap ( + DAT_EVD_HANDLE evd_handle, + Performance_Mode_Type mode, + Performance_Stats_t *stats) +{ + if ( BLOCKING_MODE == mode ) + { + return DT_performance_wait (evd_handle, stats); + } + else + { + return DT_performance_poll (evd_handle, stats); + } +} + +/****************************************************************************/ +unsigned int +DT_performance_wait ( + DAT_EVD_HANDLE evd_handle, + Performance_Stats_t *stats) +{ + DAT_COUNT i; + DAT_COUNT queue_size; + DAT_RETURN ret; + DAT_EVENT event; + unsigned long pre_ctxt_num; + unsigned long post_ctxt_num; + DT_Mdep_TimeStamp pre_ts; + DT_Mdep_TimeStamp post_ts; + + queue_size = 0; + + pre_ctxt_num = DT_Mdep_GetContextSwitchNum (); + pre_ts = DT_Mdep_GetTimeStamp (); + + ret = dat_evd_wait ( evd_handle, + DAT_TIMEOUT_INFINITE, + 1, + &event, + &queue_size); + + post_ts = DT_Mdep_GetTimeStamp (); + post_ctxt_num = DT_Mdep_GetContextSwitchNum (); + + if ( DAT_SUCCESS != ret ) + { + DT_Mdep_printf ("Test Error: dapl_event_dequeue failed: %s\n", + DT_RetToString (ret)); + return 0; + } + else if (event.event_number == DAT_DTO_COMPLETION_EVENT) + { + DT_performance_stats_record_reap (stats, + post_ctxt_num - pre_ctxt_num, + post_ts - pre_ts); + } + else + { + /* This should not happen. There has been an error if it does. */ + + DT_Mdep_printf ("Warning: dapl_performance_wait swallowing %s event\n", + DT_EventToSTr (event.event_number)); + + return 0; + } + + for ( i = 0; i < queue_size; i++ ) + { + pre_ctxt_num = DT_Mdep_GetContextSwitchNum (); + pre_ts = DT_Mdep_GetTimeStamp (); + + ret = dat_evd_dequeue ( evd_handle, + &event); + + post_ts = DT_Mdep_GetTimeStamp (); + post_ctxt_num = DT_Mdep_GetContextSwitchNum (); + + if (DAT_GET_TYPE(ret) == DAT_QUEUE_EMPTY) + { + continue; + } + else if ( DAT_SUCCESS != ret ) + { + DT_Mdep_printf ("Test Error: dapl_event_dequeue failed: %s\n", + DT_RetToString (ret)); + return 0; + } + else if (event.event_number == DAT_DTO_COMPLETION_EVENT) + { + DT_performance_stats_record_reap (stats, + post_ctxt_num - pre_ctxt_num, + post_ts - pre_ts); + } + else + { + /* This should not happen. There has been an error if it does. */ + + DT_Mdep_printf ("Warning: dapl_performance_wait swallowing %s event\n", + DT_EventToSTr (event.event_number)); + + return 0; + } + } + + return ++queue_size; +} + +/****************************************************************************/ +unsigned int +DT_performance_poll ( + DAT_EVD_HANDLE evd_handle, + Performance_Stats_t *stats) +{ + DAT_RETURN ret; + DAT_EVENT event; + unsigned long pre_ctxt_num; + unsigned long post_ctxt_num; + DT_Mdep_TimeStamp pre_ts; + DT_Mdep_TimeStamp post_ts; + + for (;;) + { + pre_ctxt_num = DT_Mdep_GetContextSwitchNum (); + pre_ts = DT_Mdep_GetTimeStamp (); + + ret = dat_evd_dequeue ( evd_handle, + &event); + + post_ts = DT_Mdep_GetTimeStamp (); + post_ctxt_num = DT_Mdep_GetContextSwitchNum (); + + if (DAT_GET_TYPE(ret) == DAT_QUEUE_EMPTY) + { + continue; + } + else if ( DAT_SUCCESS != ret ) + { + DT_Mdep_printf ("Test Error: dapl_event_dequeue failed: %s\n", + DT_RetToString (ret)); + return 0; + } + else if (event.event_number == DAT_DTO_COMPLETION_EVENT) + { + DT_performance_stats_record_reap (stats, + post_ctxt_num - pre_ctxt_num, + post_ts - pre_ts); + return 1; + } + else + { + /* This should not happen. There has been an error if it does. */ + + DT_Mdep_printf ("Warning: dapl_performance_wait swallowing %s event\n", + DT_EventToSTr (event.event_number)); + + return 0; + } + } + + /*never reached */ + return 0; +} diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_proto.h b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_proto.h new file mode 100644 index 00000000..8a92abf1 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_proto.h @@ -0,0 +1,610 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#ifndef __DAPL_PROTO_H__ +#define __DAPL_PROTO_H__ + +#include +#include +#include +#include +#include +#include "dapl_common.h" +#include "dapl_client_info.h" +#include "dapl_cnxn.h" +#include "dapl_bpool.h" +#include "dapl_client_info.h" +#include "dapl_transaction_stats.h" +#include "dapl_getopt.h" +#include "dapl_limit_cmd.h" +#include "dapl_mdep.h" +#include "dapl_memlist.h" +#include "dapl_params.h" +#include "dapl_performance_stats.h" +#include "dapl_performance_test.h" +#include "dapl_quit_cmd.h" +#include "dapl_server_info.h" +#include "dapl_test_data.h" +#include "dapl_transaction_cmd.h" +#include "dapl_transaction_test.h" +#include "dapl_version.h" +#include "dapl_fft_cmd.h" +#include "dapl_fft_util.h" + +/* + * Prototypes + */ + +/* dapl_bpool.c */ +Bpool * DT_BpoolAlloc (Per_Test_Data_t * pt_ptr, + DAT_IA_HANDLE ia_handle, + DAT_PZ_HANDLE pz_handle, + DAT_EP_HANDLE ep_handle, + DAT_EVD_HANDLE rmr_evd_handle, + DAT_COUNT seg_size, + DAT_COUNT num_segs, + DAT_COUNT alignment, + DAT_BOOLEAN enable_rdma_write, + DAT_BOOLEAN enable_rdma_read); + +bool DT_Bpool_Destroy (Per_Test_Data_t * pt_ptr, + Bpool * bpool_ptr); + +unsigned char *DT_Bpool_GetBuffer (Bpool * bpool_ptr, int index); +DAT_COUNT DT_Bpool_GetBuffSize (Bpool * bpool_ptr, int index); +DAT_LMR_TRIPLET *DT_Bpool_GetIOV (Bpool * bpool_ptr, int index); +DAT_LMR_CONTEXT DT_Bpool_GetLMR (Bpool * bpool_ptr, int index); +DAT_RMR_CONTEXT DT_Bpool_GetRMR (Bpool * bpool_ptr, int index); + +void DT_Bpool_print (Bpool * bpool_ptr); + +/* dapl_cnxn.c */ +int get_ep_connection_state (DAT_EP_HANDLE ep_handle); + +/* dapl_client.c */ +void DT_cs_Client (Params_t * params_ptr, + char *dapl_name, + char *server_name, + DAT_UINT32 total_threads); + +/* dapl_client_info.c */ +void DT_Client_Info_Endian (Client_Info_t * client_info); + +void DT_Client_Info_Print (Client_Info_t * client_info); + +/* dapl_transaction_stats.c */ +void DT_init_transaction_stats (Transaction_Stats_t * transaction_stats, + unsigned int nums); +void DT_transaction_stats_set_ready (Transaction_Stats_t * transaction_stats); + +bool DT_transaction_stats_wait_for_all (Transaction_Stats_t * transaction_stats); + +void DT_update_transaction_stats (Transaction_Stats_t * transaction_stats, + unsigned int num_ops, + unsigned int time_ms, + unsigned int bytes_send, + unsigned int bytes_recv, + unsigned int bytes_rdma_read, + unsigned int bytes_rdma_write); + +void DT_print_transaction_stats (Transaction_Stats_t * transaction_stats, + unsigned int num_threads, + unsigned int num_EPs); + +/* dapl_endian.c */ +void DT_Endian_Init (void); +DAT_UINT32 DT_Endian32 (DAT_UINT32 val); +DAT_UINT64 DT_Endian64 (DAT_UINT64 val); +DAT_UINT32 DT_EndianMemHandle (DAT_UINT32 val); +DAT_UINT64 DT_EndianMemAddress (DAT_UINT64 val); + +/* dapl_main.c */ +int __cdecl main (int argc, char *argv[]); + +int dapltest (int argc, char *argv[]); + +void Dapltest_Main_Usage (void); + +/* dapl_mdep.c */ +bool DT_Mdep_Init (void); +void DT_Mdep_End (void); +bool DT_Mdep_GetDefaultDeviceName (char *dapl_name); +void DT_Mdep_Sleep (int msec); +bool DT_Mdep_GetCpuStat (DT_CpuStat *sys_stat); +unsigned long DT_Mdep_GetTime (void); +double DT_Mdep_GetCpuMhz (void); +unsigned long DT_Mdep_GetContextSwitchNum (void); +void *DT_Mdep_Malloc (size_t l_); +void DT_Mdep_Free (void *a_); +bool DT_Mdep_LockInit (DT_Mdep_LockType * lock_ptr); +void DT_Mdep_LockDestroy (DT_Mdep_LockType * lock_ptr); +void DT_Mdep_Lock (DT_Mdep_LockType * lock_ptr); +void DT_Mdep_Unlock (DT_Mdep_LockType * lock_ptr); +void DT_Mdep_Thread_Init_Attributes (Thread * thread_ptr); +void DT_Mdep_Thread_Destroy_Attributes (Thread * thread_ptr); +bool DT_Mdep_Thread_Start (Thread * thread_ptr); + +void DT_Mdep_Thread_Detach (int thread_id); +int DT_Mdep_Thread_SELF ( void ); +void DT_Mdep_Thread_EXIT ( void * thread_handle ); +int DT_Mdep_wait_object_init ( IN DT_WAIT_OBJECT *wait_obj); +int DT_Mdep_wait_object_wait ( IN DT_WAIT_OBJECT *wait_obj, + IN int timeout_val); +int DT_Mdep_wait_object_wakeup ( IN DT_WAIT_OBJECT *wait_obj); +int DT_Mdep_wait_object_destroy ( IN DT_WAIT_OBJECT *wait_obj); + + +DT_Mdep_Thread_Start_Routine_Return_Type + DT_Mdep_Thread_Start_Routine (void *thread_handle); + +/* dapl_memlist.c */ +void DT_MemListInit (Per_Test_Data_t * pt_ptr); +void *DT_MemListAlloc (Per_Test_Data_t * pt_ptr, + char *file, + mem_type_e t, + int size); +void DT_MemListFree (Per_Test_Data_t * pt_ptr, + void *ptr); +void DT_PrintMemList (Per_Test_Data_t * pt_ptr); + +/* dapl_netaddr.c */ +bool DT_NetAddrLookupHostAddress (DAT_IA_ADDRESS_PTR to_netaddr, + char *hostname); + +DAT_IA_ADDRESS_PTR DT_NetAddrAlloc (Per_Test_Data_t * pt_ptr); + +void DT_NetAddrFree (Per_Test_Data_t * pt_ptr, + DAT_IA_ADDRESS_PTR netaddr); + +/* dapl_params.c */ +bool DT_Params_Parse (int argc, + char *argv[], + Params_t * params_ptr); + +/* dapl_performance_cmd.c */ +const char * DT_PerformanceModeToString (Performance_Mode_Type mode); + +bool DT_Performance_Cmd_Init (Performance_Cmd_t * cmd); + +bool DT_Performance_Cmd_Parse (Performance_Cmd_t * cmd, + int my_argc, + char **my_argv, + mygetopt_t * opts); + +void DT_Performance_Cmd_Print (Performance_Cmd_t * cmd); + +void DT_Performance_Cmd_Endian (Performance_Cmd_t * cmd); + +/* dapl_performance_client.c */ +void DT_Performance_Test_Client (Per_Test_Data_t * pt_ptr, + DAT_IA_HANDLE * ia_handle, + DAT_IA_ADDRESS_PTR remote); + +bool DT_Performance_Test_Client_Connect ( + Performance_Test_t * test_ptr); + +bool DT_Performance_Test_Client_Exchange ( + Performance_Test_t *test_ptr); + +/* dapl_performance_server.c */ +void DT_Performance_Test_Server (void * pt_ptr); + +bool DT_Performance_Test_Server_Connect ( + Performance_Test_t * test_ptr); + +bool DT_Performance_Test_Server_Exchange ( + Performance_Test_t *test_ptr); + +/* dapl_performance_util.c */ +bool DT_Performance_Test_Create (Per_Test_Data_t * pt_ptr, + DAT_IA_HANDLE * ia_handle, + DAT_IA_ADDRESS_PTR remote_ia_addr, + DAT_BOOLEAN is_server, + DAT_BOOLEAN is_remote_little_endian, + Performance_Test_t **perf_test); + +void DT_Performance_Test_Destroy (Per_Test_Data_t * pt_ptr, + Performance_Test_t *test_ptr, + DAT_BOOLEAN is_server); + +bool DT_performance_post_rdma_op (Performance_Ep_Context_t *ep_context, + DAT_EVD_HANDLE reqt_evd_hdl, + Performance_Stats_t *stats); + +unsigned int DT_performance_reap (DAT_EVD_HANDLE evd_handle, + Performance_Mode_Type mode, + Performance_Stats_t *stats); + +unsigned int DT_performance_wait (DAT_EVD_HANDLE evd_handle, + Performance_Stats_t *stats); + +unsigned int DT_performance_poll (DAT_EVD_HANDLE evd_handle, + Performance_Stats_t *stats); + +/* dapl_performance_stats.c */ +void DT_performance_stats_init (Performance_Stats_t * stats); + +void DT_performance_stats_record_post (Performance_Stats_t *stats, + unsigned long ctxt_switch_num, + DT_Mdep_TimeStamp ts); + +void DT_performance_stats_record_reap (Performance_Stats_t *stats, + unsigned long ctxt_switch_num, + DT_Mdep_TimeStamp ts); + +void DT_performance_stats_record_latency (Performance_Stats_t *stats, + DT_Mdep_TimeStamp ts); + +void DT_performance_stats_data_combine (Performance_Stats_Data_t * dest, + Performance_Stats_Data_t * src_a, + Performance_Stats_Data_t * src_b); + +void DT_performance_stats_combine (Performance_Stats_t * dest, + Performance_Stats_t * src_a, + Performance_Stats_t * src_b); + +double DT_performance_stats_data_print (Performance_Stats_Data_t * data, + double cpu_mhz); + +void DT_performance_stats_print (Performance_Stats_t * stats, + Performance_Cmd_t * cmd, + Performance_Test_t * test); + + +/* dapl_server.c */ +void DT_cs_Server (Params_t * params_ptr); + +/* dapl_server_cmd.c */ +void DT_Server_Cmd_Init (Server_Cmd_t * Server_Cmd); + +bool DT_Server_Cmd_Parse (Server_Cmd_t * Server_Cmd, + int my_argc, + char **my_argv, + mygetopt_t * opts); + +void DT_Server_Cmd_Print (Server_Cmd_t * Server_Cmd); + +void DT_Server_Cmd_Usage (void); + +/* dapl_server_info.c */ +void DT_Server_Info_Endian (Server_Info_t * server_info); + +void DT_Server_Info_Print (Server_Info_t * server_info); + +/* dapl_test_data.c */ +Per_Test_Data_t *DT_Alloc_Per_Test_Data (void); + +void DT_Free_Per_Test_Data (Per_Test_Data_t * pt_ptr); + +/* dapl_test_util.c */ +DAT_BOOLEAN DT_query (Per_Test_Data_t *pt_ptr, + DAT_IA_HANDLE ia_handle, + DAT_EP_HANDLE ep_handle); + +DAT_BOOLEAN DT_post_recv_buffer (DAT_EP_HANDLE ep_handle, + Bpool * bp, + int index, + int size); + +DAT_BOOLEAN DT_post_send_buffer (DAT_EP_HANDLE ep_handle, + Bpool * bp, + int index, + int size); + +bool DT_conn_event_wait (DAT_EP_HANDLE ep_handle, + DAT_EVD_HANDLE evd_handle, + DAT_EVENT_NUMBER *event_number); + +bool DT_disco_event_wait ( DAT_EVD_HANDLE evd_handle, + DAT_EP_HANDLE *ep_handle ); + +bool DT_cr_event_wait (DAT_EVD_HANDLE evd_handle, + DAT_CR_ARRIVAL_EVENT_DATA *cr_stat_p); + +bool DT_dto_event_reap (DAT_EVD_HANDLE evd_handle, + bool poll, + DAT_DTO_COMPLETION_EVENT_DATA *dtop); + +bool DT_dto_event_wait (DAT_EVD_HANDLE evd_handle, + DAT_DTO_COMPLETION_EVENT_DATA *dtop); + +bool DT_dto_event_poll (DAT_EVD_HANDLE evd_handle, + DAT_DTO_COMPLETION_EVENT_DATA *dtop); + +bool DT_rmr_event_wait (DAT_EVD_HANDLE evd_handle, + DAT_RMR_BIND_COMPLETION_EVENT_DATA *rmr_ptr); + +bool DT_dto_check ( DAT_DTO_COMPLETION_EVENT_DATA *dto_p, + DAT_EP_HANDLE ep_expected, + DAT_VLEN len_expected, + DAT_DTO_COOKIE cookie_expected, + char *message); + +bool DT_rmr_check ( DAT_RMR_BIND_COMPLETION_EVENT_DATA *rmr_p, + DAT_RMR_HANDLE rmr_expected, + DAT_PVOID cookie_expected, + char *message); + +bool DT_cr_check (DAT_CR_ARRIVAL_EVENT_DATA *cr_stat_p, + DAT_PSP_HANDLE psp_handle_expected, + DAT_CONN_QUAL port_expected, + DAT_CR_HANDLE *cr_handlep, + char *message); + +/* dapl_thread.c */ +void DT_Thread_Init (Per_Test_Data_t * pt_ptr); + +void DT_Thread_End (Per_Test_Data_t * pt_ptr); + +Thread *DT_Thread_Create (Per_Test_Data_t * pt_ptr, + void (*fn) (void *), + void *param, + unsigned int stacksize); + +void DT_Thread_Destroy (Thread * thread_ptr, + Per_Test_Data_t * pt_ptr); + +bool DT_Thread_Start (Thread * thread_ptr); + +/* dapl_quit_cmd.c */ +void DT_Quit_Cmd_Init (Quit_Cmd_t * cmd); + +bool DT_Quit_Cmd_Parse (Quit_Cmd_t * cmd, + int my_argc, + char **my_argv, + mygetopt_t * opts); + +bool DT_Quit_Cmd_Validate (Quit_Cmd_t * cmd); + +void DT_Quit_Cmd_Endian (Quit_Cmd_t * cmd, + bool to_wire); + +void DT_Quit_Cmd_Print (Quit_Cmd_t * cmd); + +void DT_Quit_Cmd_Usage (void); + +/* dapl_transaction_cmd.c */ +void DT_Transaction_Cmd_Init (Transaction_Cmd_t * cmd); + +bool DT_Transaction_Cmd_Parse (Transaction_Cmd_t * cmd, + int my_argc, + char **my_argv, + mygetopt_t * opts); + +void DT_Transaction_Cmd_Print (Transaction_Cmd_t * cmd); + +void DT_Transaction_Cmd_Endian (Transaction_Cmd_t * cmd, + bool to_wire); +/* dapl_transaction_test.c */ +void DT_Transaction_Test_Client (Per_Test_Data_t * pt_ptr, + DAT_IA_HANDLE ia_handle, + DAT_IA_ADDRESS_PTR remote); + +void DT_Transaction_Test_Server (void *params); + +bool DT_Transaction_Create_Test (Per_Test_Data_t * pt_ptr, + DAT_IA_HANDLE * ia_handle, + DAT_BOOLEAN is_server, + unsigned int port_num, + DAT_BOOLEAN remote_is_little_endian, + DAT_IA_ADDRESS_PTR remote_ia_addr); + +void DT_Transaction_Main (void *param); +bool DT_Transaction_Run (Transaction_Test_t * test_ptr); +void DT_Transaction_Validation_Fill (Transaction_Test_t * test_ptr, + unsigned int iteration); +bool DT_Transaction_Validation_Check (Transaction_Test_t * test_ptr, + int iteration); +void DT_Print_Transaction_Test (Transaction_Test_t * test_ptr); +void DT_Print_Transaction_Stats (Transaction_Test_t * test_ptr); + +/* dapl_transaction_util.c */ +bool DT_handle_post_recv_buf (Ep_Context_t * ep_context, + unsigned int num_eps, + int op_indx); + +bool DT_handle_send_op (Ep_Context_t * ep_context, + DAT_EVD_HANDLE reqt_evd_hdl, + unsigned int num_eps, + int op_indx, + bool poll); + +bool DT_handle_recv_op (Ep_Context_t * ep_context, + DAT_EVD_HANDLE recv_evd_hdl, + DAT_EVD_HANDLE reqt_evd_hdl, + unsigned int num_eps, + int op_indx, + bool poll, + bool repost_recv); + +bool DT_handle_rdma_op (Ep_Context_t * ep_context, + DAT_EVD_HANDLE reqt_evd_hdl, + unsigned int num_eps, + DT_Transfer_Type opcode, + int op_indx, + bool poll); + +bool DT_check_params (Per_Test_Data_t *pt_ptr, + unsigned char *module); + +void DT_Test_Error (void); + +/* dapl_util.c */ +const char *DT_RetToString (DAT_RETURN ret_value); + +const char *DT_TransferTypeToString (DT_Transfer_Type type); + +const char *DT_AsyncErr2Str (DAT_EVENT_NUMBER error_code); + +const char *DT_EventToSTr (DAT_EVENT_NUMBER event_code); + +const char *DT_State2Str (DAT_EP_STATE state_code); + +DAT_QOS DT_ParseQoS (char *arg); + +unsigned char *DT_AlignPtr (void * val, unsigned int align); + +DAT_COUNT DT_RoundSize (DAT_COUNT val, DAT_COUNT align); + +/* dapl_limit_cmd.c */ +void DT_Limit_Cmd_Init ( Limit_Cmd_t * cmd); + +bool DT_Limit_Cmd_Parse ( Limit_Cmd_t * cmd, + int my_argc, + char **my_argv, + mygetopt_t * opts); + +void DT_Limit_Cmd_Usage (void); + +/* dapl_limit.c */ +void DT_cs_Limit (Limit_Cmd_t * cmd); + +/* dapl_fft_cmd.c */ +void DT_FFT_Cmd_Init ( FFT_Cmd_t * cmd); + +bool DT_FFT_Cmd_Parse ( FFT_Cmd_t * cmd, + int my_argc, + char **my_argv, + mygetopt_t * opts); + +void DT_FFT_Cmd_Usage (void); + +/* dapl_fft_test.c */ +void DT_cs_FFT ( FFT_Cmd_t * cmd); + +/* dapl_fft_hwconn.c */ +void DT_hwconn_test (FFT_Cmd_t *cmd); +int DT_hwconn_case0 (FFT_Cmd_t *cmd); +int DT_hwconn_case1 (FFT_Cmd_t *cmd); +int DT_hwconn_case2 (FFT_Cmd_t *cmd); +int DT_hwconn_case3 (FFT_Cmd_t *cmd); +int DT_hwconn_case4 (FFT_Cmd_t *cmd); +int DT_hwconn_case5 (FFT_Cmd_t *cmd); +int DT_hwconn_case6 (FFT_Cmd_t *cmd); +int DT_hwconn_case7 (FFT_Cmd_t *cmd); + +/* dapl_fft_endpoint.c */ +void DT_endpoint_test (FFT_Cmd_t *cmd); +int DT_endpoint_generic (FFT_Cmd_t *cmd, + bool destroy_pz_early); +int DT_endpoint_case0 (FFT_Cmd_t *cmd); +int DT_endpoint_case1 (FFT_Cmd_t *cmd); +int DT_endpoint_case2 (FFT_Cmd_t *cmd); +int DT_endpoint_case3 (FFT_Cmd_t *cmd); +int DT_endpoint_case4 (FFT_Cmd_t *cmd); + +/* dapl_fft_pz.c */ +void DT_pz_test (FFT_Cmd_t *cmd); +int DT_pz_case0 (FFT_Cmd_t *cmd); +int DT_pz_case1 (FFT_Cmd_t *cmd); +int DT_pz_case2 (FFT_Cmd_t *cmd); +int DT_pz_case3 (FFT_Cmd_t *cmd); +int DT_pz_case4 (FFT_Cmd_t *cmd); +int DT_pz_case5 (FFT_Cmd_t *cmd); +int DT_pz_case6 (FFT_Cmd_t *cmd); + +/* dapl_fft_util.c */ +void DT_assert_fail (char *exp, char *file, char *baseFile, int line); +int DT_ia_open (DAT_NAME_PTR dev_name, DAT_IA_HANDLE *ia_handle); +DAT_RETURN DT_ia_close (DAT_IA_HANDLE, DAT_CLOSE_FLAGS); +int DT_ep_create (DAT_IA_HANDLE ia_handle, DAT_PZ_HANDLE pz_handle, + DAT_EVD_HANDLE *cr_evd, + DAT_EVD_HANDLE *conn_evd, DAT_EVD_HANDLE *send_evd, + DAT_EVD_HANDLE *recv_evd, DAT_EP_HANDLE *ep_handle); +void DT_fft_init_conn_struct (FFT_Connection_t *conn); +void DT_fft_init_client (FFT_Cmd_t *cmd, FFT_Connection_t *conn); +int DT_fft_destroy_conn_struct (FFT_Connection_t *conn); +void DT_fft_init_server (FFT_Cmd_t *cmd, FFT_Connection_t *conn); +void DT_fft_listen (FFT_Connection_t *conn); +int DT_fft_connect (FFT_Connection_t *conn); + +/* dapl_fft_dataxfer.c */ +int DT_dataxfer_case0 (FFT_Cmd_t *cmd); +int DT_dataxfer_case1 (FFT_Cmd_t *cmd); +int DT_dataxfer_case2 (FFT_Cmd_t *cmd); +int DT_dataxfer_case3 (FFT_Cmd_t *cmd); +int DT_dataxfer_generic (FFT_Cmd_t *cmd, int test_case); +void DT_dataxfer_test (FFT_Cmd_t *cmd); + +/* dapl_fft_dataxfer_client.c */ +int DT_dataxfer_client_generic (FFT_Cmd_t *cmd, int flag); +int DT_dataxfer_client_case0 (FFT_Cmd_t *cmd); +void DT_dataxfer_client_test (FFT_Cmd_t *cmd); + +/* dapl_fft_connmgt.c */ +int DT_connmgt_case0 (FFT_Cmd_t *cmd); +int DT_connmgt_case1 (FFT_Cmd_t *cmd); +void DT_connmgt_test (FFT_Cmd_t *cmd); + +/* dapl_fft_mem.c */ +int DT_mem_generic (FFT_Cmd_t *cmd, int flag); +int DT_mem_case0 (FFT_Cmd_t *cmd); +int DT_mem_case1 (FFT_Cmd_t *cmd); +int DT_mem_case2 (FFT_Cmd_t *cmd); +int DT_mem_case3 (FFT_Cmd_t *cmd); +int DT_mem_case4 (FFT_Cmd_t *cmd); +int DT_mem_case5 (FFT_Cmd_t *cmd); +int DT_mem_case6 (FFT_Cmd_t *cmd); +int DT_mem_case7 (FFT_Cmd_t *cmd); +int DT_mem_case8 (FFT_Cmd_t *cmd); +int DT_mem_case9 (FFT_Cmd_t *cmd); +int DT_mem_case10 (FFT_Cmd_t *cmd); +int DT_mem_case11 (FFT_Cmd_t *cmd); +void DT_mem_test (FFT_Cmd_t *cmd); + +/* dapl_fft_queryinfo.c */ +int DT_queryinfo_basic (FFT_Cmd_t *cmd, + FFT_query_enum object_to_query, + DAT_RETURN result_wanted); +int DT_queryinfo_case0 (FFT_Cmd_t *cmd); +int DT_queryinfo_case1 (FFT_Cmd_t *cmd); +int DT_queryinfo_case2 (FFT_Cmd_t *cmd); +int DT_queryinfo_case3 (FFT_Cmd_t *cmd); +int DT_queryinfo_case4 (FFT_Cmd_t *cmd); +int DT_queryinfo_case5 (FFT_Cmd_t *cmd); +int DT_queryinfo_case6 (FFT_Cmd_t *cmd); +int DT_queryinfo_case7 (FFT_Cmd_t *cmd); +int DT_queryinfo_case8 (FFT_Cmd_t *cmd); +int DT_queryinfo_case9 (FFT_Cmd_t *cmd); +int DT_queryinfo_case10 (FFT_Cmd_t *cmd); +int DT_queryinfo_case11 (FFT_Cmd_t *cmd); +int DT_queryinfo_case12 (FFT_Cmd_t *cmd); +int DT_queryinfo_case13 (FFT_Cmd_t *cmd); +int DT_queryinfo_case14 (FFT_Cmd_t *cmd); +int DT_queryinfo_case15 (FFT_Cmd_t *cmd); +int DT_queryinfo_case16 (FFT_Cmd_t *cmd); +int DT_queryinfo_case17 (FFT_Cmd_t *cmd); +void DT_queryinfo_test (FFT_Cmd_t *cmd); + +#ifdef DYNAMIC_DAT_LOADING +#define DAT_DLL_LIB DAT_DLL_NAME +#define DAT_LIB_OPEN_ENTRY "dat_ia_openv" +#define DAT_LIB_CLOSE_ENTRY "dat_ia_close" +DAT_IA_OPENV_FUNC dat_open; +DAT_IA_CLOSE_FUNC dat_close; +#endif //DYNAMIC_DAT_LOADING + +#endif /* __DAPL_PROTO_H__ */ diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_quit_cmd.c b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_quit_cmd.c new file mode 100644 index 00000000..5580eba2 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_quit_cmd.c @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_getopt.h" +#include "dapl_mdep.h" +#include "dapl_proto.h" +#include "dapl_quit_cmd.h" + +/*--------------------------------------------------------- */ +void +DT_Quit_Cmd_Init (Quit_Cmd_t * cmd) +{ + memset ((void *)cmd, 0, sizeof (Quit_Cmd_t)); + cmd->ReliabilityLevel = DAT_QOS_BEST_EFFORT; +} + +/*--------------------------------------------------------- */ +bool +DT_Quit_Cmd_Parse (Quit_Cmd_t * cmd, + int my_argc, + char **my_argv, + mygetopt_t * opts) +{ + char c; + + for (;;) + { + c = DT_mygetopt_r (my_argc, my_argv, "ds:D:R:", opts); + if (c == EOF) + { + break; + } + switch (c) + { + case 'D': + { + strcpy (cmd->device_name, opts->optarg); + break; + } + case 's': + { + strcpy (cmd->server_name, opts->optarg); + break; + } + case 'd': /* print debug messages */ + { + DT_dapltest_debug++; + cmd->debug = true; + break; + } + case 'R': /* Service Reliability Level */ + { + cmd->ReliabilityLevel= DT_ParseQoS (opts->optarg); + break; + } + case '?': + default: + { + DT_Mdep_printf ("Invalid Quit option: %c\n", opts->optopt); + DT_Quit_Cmd_Usage (); + return (false); + } + } + } + if (cmd->device_name[0] == '\0') + { + if (!DT_Mdep_GetDefaultDeviceName (cmd->device_name)) + { + DT_Mdep_printf ("can't get default device name\n"); + DT_Quit_Cmd_Usage (); + return (false); + } + } + if (!DT_Quit_Cmd_Validate (cmd)) + { + DT_Quit_Cmd_Usage (); + return (false); + } + return (true); +} + +/*------------------------------------------------------------------------------ */ +bool +DT_Quit_Cmd_Validate (Quit_Cmd_t * cmd) +{ + if (cmd->server_name[0] == '\0') + { + DT_Mdep_printf ("Must specify server_name in command line or scriptfile\n"); + return (false); + } + return (true); +} + +/*--------------------------------------------------------- */ +void +DT_Quit_Cmd_Endian (Quit_Cmd_t * cmd, + bool to_wire) +{ + /* do nothing */ +} + +/*--------------------------------------------------------- */ +void +DT_Quit_Cmd_Print (Quit_Cmd_t * cmd) +{ + DT_Mdep_printf ("Quit_Cmd.server_name: %s\n", cmd->server_name); + DT_Mdep_printf ("Quit_Cmd.device_name: %s\n", cmd->device_name); +} + +/*--------------------------------------------------------- */ +void +DT_Quit_Cmd_Usage (void) +{ + DT_Mdep_printf ("USAGE: ---- QUIT TEST ----\n"); + DT_Mdep_printf ("USAGE: dapltest -T Q\n"); + DT_Mdep_printf ("USAGE: -s \n"); + DT_Mdep_printf ("USAGE: [-D ]\n"); + DT_Mdep_printf ("USAGE: [-d] : debug (zero)\n"); + DT_Mdep_printf ("USAGE: [-R ]\n"); + DT_Mdep_printf ("USAGE: (BE == QOS_BEST_EFFORT - Default)\n"); + DT_Mdep_printf ("USAGE: (HT == QOS_HIGH_THROUGHPUT)\n"); + DT_Mdep_printf ("USAGE: (LL == QOS_LOW_LATENCY)\n"); + DT_Mdep_printf ("USAGE: (EC == QOS_ECONOMY)\n"); + DT_Mdep_printf ("USAGE: (PM == QOS_PREMIUM)\n"); +} diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_quit_cmd.h b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_quit_cmd.h new file mode 100644 index 00000000..e78ea5fe --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_quit_cmd.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#ifndef __DAPL_QUIT_CMD_H__ +#define __DAPL_QUIT_CMD_H__ + + +typedef struct +{ + char server_name[256]; /* -s */ + char device_name[256]; /* -D */ + DAT_UINT32 debug; /* -d */ + DAT_QOS ReliabilityLevel; /* -R */ +} Quit_Cmd_t; + +#endif diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_server.c b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_server.c new file mode 100644 index 00000000..13ef24bf --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_server.c @@ -0,0 +1,842 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include + +#include "dapl_bpool.h" +#include "dapl_client_info.h" +#include "dapl_mdep.h" +#include "dapl_memlist.h" +#include "dapl_proto.h" +#include "dapl_server_info.h" +#include "dapl_test_data.h" +#include "dapl_transaction_cmd.h" +#include "dapl_transaction_test.h" +#include "dapl_performance_cmd.h" +#include "dapl_performance_test.h" +#include "dapl_version.h" + +#define DFLT_QLEN 40 /* default event queue length */ + +int send_control_data(unsigned char *buffp, + Per_Server_Data_t *ps_ptr, + Per_Test_Data_t *pt_ptr); + +void +DT_cs_Server (Params_t * params_ptr) +{ + Server_Cmd_t *Server_Cmd = ¶ms_ptr->u.Server_Cmd; + Client_Info_t *Client_Info = NULL; + Transaction_Cmd_t *Transaction_Cmd= NULL; + Performance_Cmd_t *Performance_Cmd= NULL; + Quit_Cmd_t *Quit_Cmd = NULL; + Per_Server_Data_t *ps_ptr = NULL; + Per_Test_Data_t *pt_ptr = NULL; + Started_server_t *temp_list = NULL; + Started_server_t *pre_list = NULL; + unsigned char *buffp = NULL; + unsigned char *module = "DT_cs_Server"; + + DAT_DTO_COOKIE dto_cookie; + DAT_DTO_COMPLETION_EVENT_DATA dto_stat; + DAT_RETURN ret; + + /* Check if device from command line already in use */ + temp_list = DT_started_server_list; + while (temp_list) + { + if (strcmp (temp_list->devicename, Server_Cmd->dapl_name) == 0) + { + DT_Mdep_printf ("NOTICE: server already started for this NIC: %s\n", + Server_Cmd->dapl_name); + return; + } + temp_list = temp_list->next; + } + + /* Alloc memory for server list */ + temp_list = (Started_server_t *) DT_Mdep_Malloc (sizeof (Started_server_t)); + if (temp_list == 0) + { + DT_Mdep_printf ("no memory for server_list\n"); + return; + } + strcpy (temp_list->devicename, Server_Cmd->dapl_name); + temp_list->next = DT_started_server_list; + DT_started_server_list = temp_list; + + if (Server_Cmd->debug) + { + /* Echo our inputs if debugging */ + DT_Server_Cmd_Print (Server_Cmd); + } + + /* Allocate memory for Per_Server_Data */ + ps_ptr = (Per_Server_Data_t *) DT_Mdep_Malloc (sizeof (Per_Server_Data_t)); + if (ps_ptr == 0) + { + DT_Mdep_printf ("no memory for ps_data\n"); + goto server_exit; + } + DT_Mdep_LockInit (&ps_ptr->num_clients_lock); + ps_ptr->NextPortNumber = SERVER_PORT_NUMBER + 1; + ps_ptr->num_clients = 0; + + /* Open the IA */ +#ifdef DYNAMIC_DAT_LOADING + ret = dat_open (Server_Cmd->dapl_name, + DFLT_QLEN, + &ps_ptr->async_evd_hdl, + &ps_ptr->ia_handle, + DAT_VERSION_MAJOR, + DAT_VERSION_MINOR, + DAT_THREADSAFE); +#else + ret = dat_ia_open (Server_Cmd->dapl_name, + DFLT_QLEN, + &ps_ptr->async_evd_hdl, + &ps_ptr->ia_handle); +#endif //DYNAMIC_DAT_LOADING + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: Could not open %s (%s)\n", + module, + Server_Cmd->dapl_name, + DT_RetToString (ret)); + ps_ptr->ia_handle = DAT_HANDLE_NULL; + goto server_exit; + } + DT_Mdep_debug (("%s: IA %s opened\n", module, Server_Cmd->dapl_name)); + + /* Create a PZ */ + ret = dat_pz_create (ps_ptr->ia_handle, &ps_ptr->pz_handle); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_pz_create error: %s\n", + module, + DT_RetToString (ret)); + ps_ptr->pz_handle = DAT_HANDLE_NULL; + goto server_exit; + } + DT_Mdep_debug (("%s: PZ created\n", module)); + + /* Create 4 events - recv, request, connection-request, connect */ + ret = dat_evd_create (ps_ptr->ia_handle, + DFLT_QLEN, + DAT_HANDLE_NULL, + DAT_EVD_DTO_FLAG, + &ps_ptr->recv_evd_hdl); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_evd_create (recv) failed %s\n", + module, DT_RetToString (ret)); + ps_ptr->recv_evd_hdl = DAT_HANDLE_NULL; + goto server_exit; + } + ret = dat_evd_create (ps_ptr->ia_handle, + DFLT_QLEN, + DAT_HANDLE_NULL, + DAT_EVD_DTO_FLAG | DAT_EVD_RMR_BIND_FLAG, + &ps_ptr->reqt_evd_hdl); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_evd_create (send) failed %s\n", + module, DT_RetToString (ret)); + ps_ptr->reqt_evd_hdl = DAT_HANDLE_NULL; + goto server_exit; + } + ret = dat_evd_create (ps_ptr->ia_handle, + DFLT_QLEN, + DAT_HANDLE_NULL, + DAT_EVD_CR_FLAG, + &ps_ptr->creq_evd_hdl); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_evd_create (cr) failed %s\n", + module, DT_RetToString (ret)); + ps_ptr->creq_evd_hdl = DAT_HANDLE_NULL; + goto server_exit; + } + ret = dat_evd_create (ps_ptr->ia_handle, + DFLT_QLEN, + DAT_HANDLE_NULL, + DAT_EVD_CONNECTION_FLAG, + &ps_ptr->conn_evd_hdl); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_evd_create (conn) failed %s\n", + module, DT_RetToString (ret)); + ps_ptr->conn_evd_hdl = DAT_HANDLE_NULL; + goto server_exit; + } + + /* Create the EP */ + ret = dat_ep_create (ps_ptr->ia_handle, /* IA */ + ps_ptr->pz_handle, /* PZ */ + ps_ptr->recv_evd_hdl, /* recv */ + ps_ptr->reqt_evd_hdl, /* request */ + ps_ptr->conn_evd_hdl, /* connect */ + (DAT_EP_ATTR *) NULL, + &ps_ptr->ep_handle); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_ep_create error: %s\n", + module, + DT_RetToString (ret)); + ps_ptr->ep_handle = DAT_HANDLE_NULL; + goto server_exit; + } + DT_Mdep_debug (("%s: EP created\n", module)); + + /* Create PSP */ + ret = dat_psp_create (ps_ptr->ia_handle, + SERVER_PORT_NUMBER, + ps_ptr->creq_evd_hdl, + DAT_PSP_CONSUMER_FLAG, + &ps_ptr->psp_handle); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_psp_create error: %s\n", + module, + DT_RetToString (ret)); + ps_ptr->psp_handle = DAT_HANDLE_NULL; + goto server_exit; + } + DT_Mdep_debug (("%s: PSP created\n", module)); + + /* + * Create two buffers, large enough to hold ClientInfo and the largest + * command we'll use. + */ + ps_ptr->bpool = DT_BpoolAlloc (NULL, + ps_ptr->ia_handle, + ps_ptr->pz_handle, + ps_ptr->ep_handle, + DAT_HANDLE_NULL, /* no RMR */ + DT_RoundSize (sizeof (Transaction_Cmd_t), 8192), + 3, /* num_buffers */ + DAT_OPTIMAL_ALIGNMENT, + false, + false); + if (ps_ptr->bpool == 0) + { + DT_Mdep_printf ("%s: no memory for command buffer pool.\n", module); + goto server_exit; + } + + DT_Mdep_spew (3, ("Recv 0 %p\n", (DAT_PVOID) DT_Bpool_GetBuffer ( + ps_ptr->bpool, 0))); + DT_Mdep_spew (3, ("Recv 1 %p\n", (DAT_PVOID) DT_Bpool_GetBuffer ( + ps_ptr->bpool, 1))); + DT_Mdep_spew (3, ("SrvInfo 2 %p\n", (DAT_PVOID) DT_Bpool_GetBuffer ( + ps_ptr->bpool, 2))); + + /* Initialize the performance test lock in case an incoming test + * is a performance test, so we can allow only one at a time. + * Otherwise, multiple performance tests cause a race condition + * between the server creating a new thread trying to allocate a + * PSP with the same ID as another thread that is either running + * a test on that same ID or hasn't yet destroyed it. Only one + * PSP with a particular ID can exist at a time. It's a + * de-facto shared resource that must be protected. + */ + /************************************************************************ + * Loop accepting connections and acting on them + */ + for (;/* EVER */;) + { + DAT_CR_HANDLE cr_handle; + DAT_CR_ARRIVAL_EVENT_DATA cr_stat; + DAT_EVENT_NUMBER event_num; + + /* Set up the Per_Test_Data */ + pt_ptr = DT_Alloc_Per_Test_Data (); + if (!pt_ptr) + { + DT_Mdep_printf ("%s: no memory for Per_Test_Data\n", module); + goto server_exit; + } + DT_MemListInit (pt_ptr); + DT_Thread_Init (pt_ptr); + pt_ptr->local_is_server = true; + pt_ptr->ps_ptr = ps_ptr; + /* Server_Info, Client_Info, Params set up below */ + + /* Gather whatever info we want about defaults */ + if (!DT_query (pt_ptr, ps_ptr->ia_handle, ps_ptr->ep_handle)) + { + goto server_exit; + } + + /* Post recv buffers for ClientInfo and Transaction_Cmd_t */ + DT_Mdep_debug (("%s: Posting 2 recvs\n", module)); + if (!DT_post_recv_buffer (ps_ptr->ep_handle, + ps_ptr->bpool, + 0, + DT_Bpool_GetBuffSize (ps_ptr->bpool, 0))) + { + DT_Mdep_printf ("%s: cannot post ClientInfo recv buffer\n", module); + goto server_exit; + } + if (!DT_post_recv_buffer (ps_ptr->ep_handle, + ps_ptr->bpool, + 1, + DT_Bpool_GetBuffSize (ps_ptr->bpool, 1))) + { + DT_Mdep_printf ("%s: cannot post Transaction_Cmd_t recv buffer\n", + module); + goto server_exit; + } + + /* message to help automated test scripts know when to start the client */ + DT_Mdep_printf ("Dapltest: Service Point Ready - %s\n", + Server_Cmd->dapl_name); + + DT_Mdep_flush (); + + DT_Mdep_debug (("%s: Waiting for Connection Request\n", module)); + if (!DT_cr_event_wait (ps_ptr->creq_evd_hdl, &cr_stat) || + !DT_cr_check (&cr_stat, + ps_ptr->psp_handle, + SERVER_PORT_NUMBER, + &cr_handle, + module)) + { + + DT_Mdep_printf ("CR Check failed, file %s line %d\n", __FILE__, + __LINE__); + goto server_exit; + } + + DT_Mdep_debug (("%s: Accepting Connection Request\n", module)); + ret = dat_cr_accept (cr_handle, ps_ptr->ep_handle, 0, (DAT_PVOID)0); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_cr_accept error: %s\n", + module, + DT_RetToString (ret)); + goto server_exit; + } + + DT_Mdep_debug (("%s: Awaiting connection ...\n", module)); + if (!DT_conn_event_wait (ps_ptr->ep_handle, ps_ptr->conn_evd_hdl, + &event_num)) + { + DT_Mdep_printf ("%s: error awaiting conn-established event\n", + module); + goto server_exit; + } + + if (DT_dapltest_debug) + { + DT_Mdep_debug (("%s: Connected!\n", module)); + get_ep_connection_state (ps_ptr->ep_handle); + } + + /* Wait for Client_Info */ + dto_cookie.as_64 = LZERO; + dto_cookie.as_ptr = + (DAT_PVOID) (uintptr_t) DT_Bpool_GetBuffer ( ps_ptr->bpool, 0); + DT_Mdep_debug (("%s: Waiting for Client_Info\n", module)); + if (!DT_dto_event_wait (ps_ptr->recv_evd_hdl, &dto_stat) || + !DT_dto_check ( &dto_stat, + ps_ptr->ep_handle, + DT_Bpool_GetBuffSize (ps_ptr->bpool, 0), + dto_cookie, + "Client_Info_Recv")) + { + goto server_exit; + } + DT_Mdep_debug (("%s: Got Client_Info\n", module)); + + /* Extract the Client_Info */ + Client_Info = (Client_Info_t*) DT_Bpool_GetBuffer (ps_ptr->bpool, 0); + DT_Client_Info_Endian (Client_Info); + memcpy ( (void *) (uintptr_t)&pt_ptr->Client_Info, + (const void *)Client_Info, + sizeof (Client_Info_t)); + + /* Wait for client's command info */ + dto_cookie.as_64 = LZERO; + dto_cookie.as_ptr = + (DAT_PVOID) (uintptr_t) DT_Bpool_GetBuffer ( ps_ptr->bpool, 1); + DT_Mdep_debug (("%s: Waiting for Client_Cmd_Info\n", module)); + if (!DT_dto_event_wait (ps_ptr->recv_evd_hdl, &dto_stat) || + !DT_dto_check ( &dto_stat, + ps_ptr->ep_handle, + DT_Bpool_GetBuffSize (ps_ptr->bpool, 1), + dto_cookie, + "Client_Cmd_Recv")) + { + goto server_exit; + } + + /* Extract the client's command info */ + switch (Client_Info->test_type) + { + case TRANSACTION_TEST: + { + Transaction_Cmd = (Transaction_Cmd_t *) + DT_Bpool_GetBuffer (ps_ptr->bpool, 1); + DT_Transaction_Cmd_Endian (Transaction_Cmd, false); + memcpy ( (void *) (uintptr_t)&pt_ptr->Params.u.Transaction_Cmd, + (const void *)Transaction_Cmd, + sizeof (Transaction_Cmd_t)); + break; + } + + case PERFORMANCE_TEST: + { + Performance_Cmd = (Performance_Cmd_t *) + DT_Bpool_GetBuffer (ps_ptr->bpool, 1); + DT_Performance_Cmd_Endian (Performance_Cmd); + memcpy ( (void *) (uintptr_t)&pt_ptr->Params.u.Performance_Cmd, + (const void *)Performance_Cmd, + sizeof (Performance_Cmd_t)); + break; + } + + case QUIT_TEST: + { + Quit_Cmd = (Quit_Cmd_t*)DT_Bpool_GetBuffer (ps_ptr->bpool, 1); + DT_Quit_Cmd_Endian (Quit_Cmd, false); + memcpy ( (void *) (uintptr_t)&pt_ptr->Params.u.Quit_Cmd, + (const void *)Quit_Cmd, + sizeof (Quit_Cmd_t)); + break; + } + + default: + { + DT_Mdep_printf ("Unknown TestType received\n"); + goto server_exit; + break; + } + } + + /* Setup Server Info */ + DT_Mdep_debug (("%s: Send Server_Info\n", module)); + pt_ptr->Server_Info.dapltest_version = DAPLTEST_VERSION; + pt_ptr->Server_Info.is_little_endian = DT_local_is_little_endian; + pt_ptr->Server_Info.first_port_number = ps_ptr->NextPortNumber; + ps_ptr->NextPortNumber += pt_ptr->Client_Info.total_threads; + + /* This had to be done here because the pt_ptr is being fed to + * the thread as its context, and if it isn't properly + * initialized before the thread spawns then the thread may + * incorrectly set up its PSP and the server will be listening + * on the WRONG PORT! + */ + + switch (Client_Info->test_type) + { + case TRANSACTION_TEST: + { + /* create a thread to handle this pt_ptr; */ + DT_Mdep_debug (("%s: Creating Transaction Test Thread\n", module)); + pt_ptr->thread = DT_Thread_Create (pt_ptr, + DT_Transaction_Test_Server, + pt_ptr, + DT_MDEP_DEFAULT_STACK_SIZE); + if (pt_ptr->thread == 0) + { + DT_Mdep_printf ("no memory to create thread\n"); + goto server_exit; + } + break; + } + + case PERFORMANCE_TEST: + { + /* create a thread to handle this pt_ptr; */ + DT_Mdep_debug (("%s: Creating Performance Test Thread\n", module)); + pt_ptr->thread = DT_Thread_Create (pt_ptr, + DT_Performance_Test_Server, + pt_ptr, + DT_MDEP_DEFAULT_STACK_SIZE); + if (pt_ptr->thread == 0) + { + DT_Mdep_printf ("no memory to create thread\n"); + goto server_exit; + } + /* take the performance test lock to serialize */ + DT_Mdep_Lock ( &g_PerfTestLock ); + + break; + } + + case QUIT_TEST: + { + DT_Mdep_debug (("Client Requests Server to Quit\n")); + (void) send_control_data(buffp, ps_ptr, pt_ptr); + goto server_exit; + break; + } + + case LIMIT_TEST: + { + DT_Mdep_debug (("Limit Test is Client-side Only!\n")); + (void) send_control_data(buffp, ps_ptr, pt_ptr); + goto server_exit; + break; + } + + default: + { + DT_Mdep_printf ("Unknown TestType received\n"); + (void) send_control_data(buffp, ps_ptr, pt_ptr); + goto server_exit; + break; + } + } + + /* Start the new test thread */ + DT_Mdep_debug (("%s: Starting Test Thread\n", module)); + if (DT_Thread_Start (pt_ptr->thread) == false) + { + DT_Mdep_debug (("failed to start test thread\n")); + goto server_exit; + } + + buffp = DT_Bpool_GetBuffer (ps_ptr->bpool, 2); /* 3rd buffer */ + memcpy ( (void *)buffp, + (const void *)&pt_ptr->Server_Info, + sizeof (Server_Info_t)); + DT_Server_Info_Endian ((Server_Info_t *) buffp); + + /* Perform obligatory version check */ + if (pt_ptr->Client_Info.dapltest_version != DAPLTEST_VERSION) + { + DT_Mdep_printf ("%s: %s: Server %d, Client %d\n", + module, + "DAPLTEST VERSION MISMATCH", + DAPLTEST_VERSION, + pt_ptr->Client_Info.dapltest_version); + goto server_exit; + } + DT_Mdep_debug (("%s: Version OK!\n", module)); + + DT_Mdep_wait_object_wait ( + &pt_ptr->synch_wait_object, + DAT_TIMEOUT_INFINITE); + + /* Send the Server_Info */ + DT_Mdep_debug (("%s: Send Server_Info\n", module)); + + if (!DT_post_send_buffer ( ps_ptr->ep_handle, + ps_ptr->bpool, + 2, + DT_Bpool_GetBuffSize (ps_ptr->bpool, 2))) + { + DT_Mdep_printf ("%s: cannot send Server_Info\n", module); + goto server_exit; + } + /* reap the send and verify it */ + dto_cookie.as_64 = LZERO; + dto_cookie.as_ptr = + (DAT_PVOID) (uintptr_t) DT_Bpool_GetBuffer ( ps_ptr->bpool, 2); + if (!DT_dto_event_wait (ps_ptr->reqt_evd_hdl, &dto_stat) || + !DT_dto_check ( &dto_stat, + ps_ptr->ep_handle, + DT_Bpool_GetBuffSize (ps_ptr->bpool, 2), + dto_cookie, + "Server_Info_Send")) + { + goto server_exit; + } + + + /* Count this new client and get ready for the next */ + DT_Mdep_Lock (&ps_ptr->num_clients_lock); + ps_ptr->num_clients++; + DT_Mdep_Unlock (&ps_ptr->num_clients_lock); + + /* we passed the pt_ptr to the thread and must now 'forget' it */ + pt_ptr = 0; + +#ifdef CM_BUSTED + DT_Mdep_debug (("%s: Server exiting because provider does not support\n" + " multiple connections to the same service point\n", + module)); + /* Until connections are healthier we run just one test */ + break; +#else + ret = dat_ep_disconnect (ps_ptr->ep_handle, DAT_CLOSE_GRACEFUL_FLAG); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_ep_disconnect fails: %s\n", + module, DT_RetToString (ret)); + goto server_exit; + } + if (!DT_disco_event_wait ( ps_ptr->conn_evd_hdl, NULL)) + { + DT_Mdep_printf ("%s: bad disconnect event\n", module); + goto server_exit; + } + + /* reset the EP to get back into the game */ + dat_ep_reset (ps_ptr->ep_handle); + DT_Mdep_debug (("%s: Waiting for another client...\n", module)); +#endif + + + + + } /* end loop accepting connections */ + + /************************************************************************ + * Finished (or had an error) so clean up and go home + */ +server_exit: + + /* Wait until all of our clients are gone */ + DT_Mdep_debug (("%s: Waiting for clients to all go away...\n", module)); + while (ps_ptr && ps_ptr->num_clients > 0) + { + DT_Mdep_Sleep (100); + } + + /* Clean up the Per_Test_Data (if any) */ + DT_Mdep_debug (("%s: Cleaning up ...\n", module)); + if (pt_ptr) + { + DT_Mdep_LockDestroy (&pt_ptr->Thread_counter_lock); + DT_Mdep_LockDestroy (&pt_ptr->MemListLock); + DT_Free_Per_Test_Data (pt_ptr); + } + + /* Clean up the Per_Server_Data */ + if (ps_ptr) + { + + /* + * disconnect the most recent EP + * + * we also get here on error, hence abrupt closure to + * flush any lingering buffers posted. + */ + if (ps_ptr->ep_handle) + { + ret = dat_ep_disconnect (ps_ptr->ep_handle, + DAT_CLOSE_ABRUPT_FLAG); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_ep_disconnect fails: %s\n", + module, DT_RetToString (ret)); + /* keep trying */ + } + else if (!DT_disco_event_wait ( ps_ptr->conn_evd_hdl, + NULL)) + { + DT_Mdep_printf ("%s: bad disconnect event\n", module); + } + } + + /* Destroy the Bpool */ + if (ps_ptr->bpool) + { + if (!DT_Bpool_Destroy (NULL, ps_ptr->bpool)) + { + DT_Mdep_printf ("%s: error destroying buffer pool\n", module); + /* keep trying */ + } + } + + /* Free the PSP */ + if (ps_ptr->psp_handle) + { + ret = dat_psp_free (ps_ptr->psp_handle); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_psp_free error: %s\n", + module, + DT_RetToString (ret)); + /* keep trying */ + } + } + + /* Free the EP */ + if (ps_ptr->ep_handle) + { + ret = dat_ep_free (ps_ptr->ep_handle); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_ep_free error: %s\n", + module, DT_RetToString (ret)); + /* keep trying */ + } + } + + /* Free the 4 EVDs */ + if (ps_ptr->conn_evd_hdl) + { + ret = dat_evd_free (ps_ptr->conn_evd_hdl); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_evd_free (conn) error: %s\n", + module, DT_RetToString (ret)); + /* keep trying */ + } + } + if (ps_ptr->creq_evd_hdl) + { + ret = dat_evd_free (ps_ptr->creq_evd_hdl); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_evd_free (creq) error: %s\n", + module, DT_RetToString (ret)); + /* keep trying */ + } + } + if (ps_ptr->reqt_evd_hdl) + { + ret = dat_evd_free (ps_ptr->reqt_evd_hdl); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_evd_free (reqt) error: %s\n", + module, DT_RetToString (ret)); + /* keep trying */ + } + } + if (ps_ptr->recv_evd_hdl) + { + ret = dat_evd_free (ps_ptr->recv_evd_hdl); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_evd_free (recv) error: %s\n", + module, DT_RetToString (ret)); + /* keep trying */ + } + } + + /* Free the PZ */ + if (ps_ptr->pz_handle) + { + ret = dat_pz_free (ps_ptr->pz_handle); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_pz_free error: %s\n", + module, DT_RetToString (ret)); + /* keep trying */ + } + } + + /* Close the IA */ + if (ps_ptr->ia_handle) + { + /* DT_ia_close cleans up async evd handle, too */ + ret = DT_ia_close (ps_ptr->ia_handle, DAT_CLOSE_GRACEFUL_FLAG); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: DT_ia_close (graceful) error: %s\n", + module, DT_RetToString (ret)); + ret = DT_ia_close (ps_ptr->ia_handle, DAT_CLOSE_ABRUPT_FLAG); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: DT_ia_close (abrupt) error: %s\n", + module, DT_RetToString (ret)); + } + /* keep trying */ + } + else + { + DT_Mdep_debug (("%s: IA %s closed\n", + module, + Server_Cmd->dapl_name)); + } + } + + /* Destroy the ps_ptr */ + DT_Mdep_LockDestroy (&ps_ptr->num_clients_lock); + DT_Mdep_Free (ps_ptr); + } /* end if ps_ptr */ + + /* Clean up the server list */ + pre_list = 0; + temp_list = DT_started_server_list; + while (temp_list) + { + if (strcmp (temp_list->devicename, Server_Cmd->dapl_name) == 0) + { + if (pre_list == 0) /* first one */ + { + DT_started_server_list = temp_list->next; + } + else + { + pre_list->next = temp_list->next; + } + DT_Mdep_Free (temp_list); + break; + } + pre_list = temp_list; + temp_list = temp_list->next; + } + + DT_Mdep_printf ("%s (%s): Exiting.\n", module, Server_Cmd->dapl_name); +} + + +int +send_control_data( + unsigned char *buffp, + Per_Server_Data_t *ps_ptr, + Per_Test_Data_t *pt_ptr) +{ + unsigned char *module = "send_control_data"; + DAT_DTO_COOKIE dto_cookie; + DAT_DTO_COMPLETION_EVENT_DATA dto_stat; + + buffp = DT_Bpool_GetBuffer (ps_ptr->bpool, 2); /* 3rd buffer */ + memcpy ( (void *)buffp, + (const void *)&pt_ptr->Server_Info, + sizeof (Server_Info_t)); + DT_Server_Info_Endian ((Server_Info_t *) buffp); + + if (!DT_post_send_buffer ( ps_ptr->ep_handle, + ps_ptr->bpool, + 2, + DT_Bpool_GetBuffSize (ps_ptr->bpool, 2))) + { + DT_Mdep_printf ("%s: cannot send Server_Info\n", module); + return 1; + } + /* reap the send and verify it */ + dto_cookie.as_64 = LZERO; + dto_cookie.as_ptr = + (DAT_PVOID) (uintptr_t) DT_Bpool_GetBuffer ( ps_ptr->bpool, 2); + if (!DT_dto_event_wait (ps_ptr->reqt_evd_hdl, &dto_stat) || + !DT_dto_check ( &dto_stat, + ps_ptr->ep_handle, + DT_Bpool_GetBuffSize (ps_ptr->bpool, 2), + dto_cookie, + "Server_Info_Send")) + { + return 1; + } + + return 0; +} diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_server_cmd.c b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_server_cmd.c new file mode 100644 index 00000000..059cbe6e --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_server_cmd.c @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_getopt.h" +#include "dapl_mdep.h" +#include "dapl_proto.h" +#include "dapl_server_cmd.h" + + +void +DT_Server_Cmd_Init (Server_Cmd_t * Server_Cmd) +{ + DT_dapltest_debug = 0; + Server_Cmd->debug = false; + Server_Cmd->dapl_name[0] = '\0'; + Server_Cmd->ReliabilityLevel = DAT_QOS_BEST_EFFORT; +} + + +bool +DT_Server_Cmd_Parse (Server_Cmd_t * Server_Cmd, + int my_argc, + char **my_argv, + mygetopt_t * opts) +{ + char c; + for (;;) + { + c = DT_mygetopt_r (my_argc, my_argv, "dD:R:", opts); + if (c == EOF) + { + break; + } + switch (c) + { + case 'D': + { + strcpy (Server_Cmd->dapl_name, opts->optarg); + break; + } + case 'd': + { + DT_dapltest_debug++; + Server_Cmd->debug = true; + break; + } + case 'R': /* Service Reliability Level */ + { + Server_Cmd->ReliabilityLevel = DT_ParseQoS (opts->optarg); + if (0 == Server_Cmd->ReliabilityLevel) + { + return (false); + } + break; + } + case '?': + default: + { + DT_Mdep_printf ("Invalid Server option: %c\n", opts->optopt); + DT_Server_Cmd_Usage (); + return (false); + } + } + } + if (Server_Cmd->dapl_name == '\0') + { + if (!DT_Mdep_GetDefaultDeviceName (Server_Cmd->dapl_name)) + { + DT_Mdep_printf ("can't get default device name\n"); + DT_Server_Cmd_Usage (); + return (false); + } + } + return (true); +} + + +void +DT_Server_Cmd_Print (Server_Cmd_t * Server_Cmd) +{ + DT_Mdep_printf ("Server_Cmd.debug: %d\n", Server_Cmd->debug); + DT_Mdep_printf ("Server_Cmd.dapl_name: %s\n", Server_Cmd->dapl_name); +} + +void +DT_Server_Cmd_Usage (void) +{ + DT_Mdep_printf ("USAGE: ---- SERVER MODE ----\n"); + DT_Mdep_printf ("USAGE: dapltest -T S\n"); + DT_Mdep_printf ("USAGE: [-D ]\n"); + DT_Mdep_printf ("USAGE: [-d] : debug (zero)\n"); + DT_Mdep_printf ("USAGE: [-R ]\n"); + DT_Mdep_printf ("USAGE: (BE == QOS_BEST_EFFORT - Default)\n"); + DT_Mdep_printf ("USAGE: (HT == QOS_HIGH_THROUGHPUT)\n"); + DT_Mdep_printf ("USAGE: (LL == QOS_LOW_LATENCY)\n"); + DT_Mdep_printf ("USAGE: (EC == QOS_ECONOMY)\n"); + DT_Mdep_printf ("USAGE: (PM == QOS_PREMIUM)\n"); + DT_Mdep_printf ("USAGE: Run as server using default parameters\n"); + DT_Mdep_printf ("USAGE: dapltest\n"); + DT_Mdep_printf ("USAGE:\n"); +} diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_server_cmd.h b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_server_cmd.h new file mode 100644 index 00000000..ee44d9d5 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_server_cmd.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#ifndef __DAPL_SERVER_CMD_H__ +#define __DAPL_SERVER_CMD_H__ + +#include "dapl_mdep.h" + +typedef struct +{ + bool debug; /* -d */ + char dapl_name[256]; /* -D device name */ + DAT_QOS ReliabilityLevel; /* -R */ +} Server_Cmd_t; + +#endif diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_server_info.c b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_server_info.c new file mode 100644 index 00000000..8ce3413b --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_server_info.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_server_info.h" +#include "dapl_proto.h" +#include "dapl_test_data.h" + + +Started_server_t *DT_started_server_list = 0; + +void +DT_Server_Info_Endian (Server_Info_t * server_info) +{ + server_info->dapltest_version = DT_Endian32 (server_info->dapltest_version); + server_info->is_little_endian = DT_Endian32 (server_info->is_little_endian); + server_info->first_port_number= DT_Endian32 (server_info->first_port_number); +} + +void +DT_Server_Info_Print (Server_Info_t * server_info) +{ + DT_Mdep_printf ("-------------------------------------\n"); + DT_Mdep_printf ("Server_Info.dapltest_version : %d\n", + server_info->dapltest_version); + DT_Mdep_printf ("Server_Info.is_little_endian : %d\n", + server_info->is_little_endian); +} diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_server_info.h b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_server_info.h new file mode 100644 index 00000000..aadf2044 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_server_info.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#ifndef __DAPL_SERVER_INFO_H__ +#define __DAPL_SERVER_INFO_H__ + +#include "dapl_mdep.h" +#include + +#pragma pack(1) + +struct started_server +{ + char devicename[80]; + struct started_server *next; +}; + +typedef struct started_server Started_server_t; + +extern Started_server_t *DT_started_server_list; + +#define SERVER_PORT_NUMBER (0xBabb1e) + +typedef struct +{ + DAT_UINT32 dapltest_version; + DAT_UINT32 is_little_endian; + DAT_UINT32 first_port_number; +} Server_Info_t; +#pragma pack() + +#endif diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_test_data.c b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_test_data.c new file mode 100644 index 00000000..20d826d5 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_test_data.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_mdep.h" +#include "dapl_proto.h" +#include "dapl_server_info.h" +#include "dapl_client_info.h" +#include "dapl_transaction_test.h" + +DAT_COUNT DT_dapltest_debug = 0; +bool DT_local_is_little_endian; +/* + * check memory leaking int alloc_count; DT_Mdep_LockType + * Alloc_Count_Lock; + */ + +Per_Test_Data_t * +DT_Alloc_Per_Test_Data (void) +{ + Per_Test_Data_t *pt_ptr; + pt_ptr = 0; + + pt_ptr = DT_Mdep_Malloc (sizeof (Per_Test_Data_t)); + if (!pt_ptr) + { + DT_Mdep_printf ("No Memory to create per_test_data!\n"); + } + + return (pt_ptr); +} + +void +DT_Free_Per_Test_Data (Per_Test_Data_t * pt_ptr) +{ + DT_Mdep_Free (pt_ptr); +} diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_test_data.h b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_test_data.h new file mode 100644 index 00000000..7ec0824b --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_test_data.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#ifndef __DAPL_TEST_DATA_H__ +#define __DAPL_TEST_DATA_H__ + +#include "dapl_bpool.h" +#include "dapl_mdep.h" +#include "dapl_client_info.h" +#include "dapl_transaction_stats.h" +#include "dapl_memlist.h" +#include "dapl_params.h" +#include "dapl_server_info.h" +#include + +extern DAT_COUNT DT_dapltest_debug; +extern bool DT_local_is_little_endian; + +/* This lock allows the client side to run + * in a shell script loop without breaking + * connections. Remove it and due to timing + * problems on the server side occasionally + * the server will reject connections. + */ +extern DT_Mdep_LockType g_PerfTestLock; + +/* + * check memory leaking extern int alloc_count ; extern + * DT_Mdep_LockType Alloc_Count_Lock; + */ + +typedef struct +{ + int NextPortNumber; + int num_clients; + DT_Mdep_LockType num_clients_lock; + DAT_IA_HANDLE ia_handle; + DAT_PZ_HANDLE pz_handle; + DAT_EVD_HANDLE recv_evd_hdl; + DAT_EVD_HANDLE reqt_evd_hdl; + DAT_EVD_HANDLE conn_evd_hdl; + DAT_EVD_HANDLE creq_evd_hdl; + DAT_EVD_HANDLE async_evd_hdl; + DAT_EVD_HANDLE rmr_evd_hdl; + DAT_EP_HANDLE ep_handle; + DAT_PSP_HANDLE psp_handle; + Bpool *bpool; +} Per_Server_Data_t; + +typedef struct +{ + DT_Mdep_LockType MemListLock; + MemListEntry_t *MemListHead; + + DT_Mdep_LockType Thread_counter_lock; + int Thread_counter; + Thread *thread; + + bool local_is_server; + Server_Info_t Server_Info; + Client_Info_t Client_Info; + Params_t Params; + DAT_IA_ATTR ia_attr; + DAT_PROVIDER_ATTR provider_attr; + DAT_EP_ATTR ep_attr; + Per_Server_Data_t *ps_ptr; + Transaction_Stats_t Client_Stats; + + /* synchronize the server with the server's spawned test thread. + * That test thread uses a PSP that only one test at a time can + * use. If we don't synchronize access between the teardown and + * creation of that PSP then the client will fail to connect + * randomly, a symptom that the server is not coordinated with + * its test threads. Remove this at your own peril, or if you + * really want your test client to experience rejection on a + * random but regular basis. + */ + DT_WAIT_OBJECT synch_wait_object; + int Countdown_Counter; + +} Per_Test_Data_t; + +#endif diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_test_util.c b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_test_util.c new file mode 100644 index 00000000..60ba5873 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_test_util.c @@ -0,0 +1,743 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_bpool.h" +#include "dapl_mdep.h" +#include "dapl_proto.h" +#include +#include "dapl_test_data.h" + + +/* ----------------------------------------------------------- + * Gather info about default attributes + */ +DAT_BOOLEAN +DT_query ( Per_Test_Data_t *pt_ptr, + DAT_IA_HANDLE ia_handle, + DAT_EP_HANDLE ep_handle) +{ + unsigned char *module = "DT_query"; + DAT_EVD_HANDLE async_evd_hdl; /* not used */ + DAT_EP_PARAM ep_params; + DAT_RETURN ret; + + /* Query the IA */ + ret = dat_ia_query (ia_handle, + &async_evd_hdl, + DAT_IA_ALL, + &pt_ptr->ia_attr, + DAT_PROVIDER_FIELD_ALL, + &pt_ptr->provider_attr); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_ia_query error: %s\n", + module, + DT_RetToString (ret)); + return ( false ); + } + + /* Query the EP */ + ret = dat_ep_query ( ep_handle, + DAT_EP_FIELD_ALL, + &ep_params); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("%s: dat_ep_query error: %s\n", + module, + DT_RetToString (ret)); + return ( false ); + } + pt_ptr->ep_attr = ep_params.ep_attr; + + /* + * If debugging, print out some interesting attributes + */ + if (DT_dapltest_debug) + { + DAT_SOCK_ADDR6 *ip6_addr; + struct sockaddr_in *ip_addr; + + DT_Mdep_printf ("***** DAPL Characteristics *****\n"); + DT_Mdep_printf ("Provider: %s Version %d.%d DAPL %d.%d\n", + pt_ptr->provider_attr.provider_name, + pt_ptr->provider_attr.provider_version_major, + pt_ptr->provider_attr.provider_version_minor, + pt_ptr->provider_attr.dapl_version_major, + pt_ptr->provider_attr.dapl_version_minor ); + DT_Mdep_printf ("Adapter: %s by %s Version %d.%d\n", + pt_ptr->ia_attr.adapter_name, + pt_ptr->ia_attr.vendor_name, + pt_ptr->ia_attr.hardware_version_major, + pt_ptr->ia_attr.hardware_version_minor ); + DT_Mdep_printf ("Supporting:\n"); + DT_Mdep_printf ("\t%d EPs with %d DTOs and %d RDMA/RDs each\n", + pt_ptr->ia_attr.max_eps, + pt_ptr->ia_attr.max_dto_per_ep, + pt_ptr->ia_attr.max_rdma_read_per_ep ); + DT_Mdep_printf ("\t%d EVDs of up to %d entries " + " (default S/R size is %d/%d)\n", + pt_ptr->ia_attr.max_evds, + pt_ptr->ia_attr.max_evd_qlen, + pt_ptr->ep_attr.max_request_dtos, + pt_ptr->ep_attr.max_recv_dtos ); + DT_Mdep_printf ("\tIOVs of up to %d elements\n", + pt_ptr->ia_attr.max_iov_segments_per_dto ); + DT_Mdep_printf ("\t%d LMRs (and %d RMRs) of up to 0x" F64x " bytes\n", + pt_ptr->ia_attr.max_lmrs, + pt_ptr->ia_attr.max_rmrs, + (DAT_UVERYLONG)pt_ptr->ia_attr.max_lmr_block_size ); + DT_Mdep_printf ("\tMaximum MTU 0x" F64x " bytes, RDMA 0x" F64x " bytes\n", + (DAT_UVERYLONG)pt_ptr->ia_attr.max_mtu_size, + (DAT_UVERYLONG)pt_ptr->ia_attr.max_rdma_size ); + DT_Mdep_printf ("\tMaximum Private data size %d bytes\n", + pt_ptr->provider_attr.max_private_data_size ); + + ip6_addr = (DAT_SOCK_ADDR6 *)pt_ptr->ia_attr.ia_address_ptr; + if (ip6_addr->sin6_family == AF_INET6 ) + { + DT_Mdep_printf ("\tLocal IP address %x:%x:%x:%x:%x:%x:%x:%x:\n", + ip6_addr->sin6_addr.s6_addr[0], + ip6_addr->sin6_addr.s6_addr[1], + ip6_addr->sin6_addr.s6_addr[2], + ip6_addr->sin6_addr.s6_addr[3], + ip6_addr->sin6_addr.s6_addr[4], + ip6_addr->sin6_addr.s6_addr[5], + ip6_addr->sin6_addr.s6_addr[6], + ip6_addr->sin6_addr.s6_addr[7]); + DT_Mdep_printf ("%x:%x:%x:%x:%x:%x:%x:%x\n", + ip6_addr->sin6_addr.s6_addr[8], + ip6_addr->sin6_addr.s6_addr[9], + ip6_addr->sin6_addr.s6_addr[10], + ip6_addr->sin6_addr.s6_addr[11], + ip6_addr->sin6_addr.s6_addr[12], + ip6_addr->sin6_addr.s6_addr[13], + ip6_addr->sin6_addr.s6_addr[14], + ip6_addr->sin6_addr.s6_addr[15]); + } + else if (ip6_addr->sin6_family == AF_INET ) + + { + int rval; + + ip_addr = (struct sockaddr_in *)pt_ptr->ia_attr.ia_address_ptr; + rval = (int) ip_addr->sin_addr.s_addr; + + DT_Mdep_printf ("\tLocal IP address %d.%d.%d.%d\n", + (rval >> 0) & 0xff, + (rval >> 8) & 0xff, + (rval >> 16) & 0xff, + (rval >> 24) & 0xff); + } + + DT_Mdep_printf ("***** ***** ***** ***** ***** *****\n"); + } + + return ( true ); +} + + +/* ----------------------------------------------------------- + * Post a recv buffer + */ +DAT_BOOLEAN +DT_post_recv_buffer (DAT_EP_HANDLE ep_handle, + Bpool * bp, + int index, + int size) +{ + unsigned char *buff = DT_Bpool_GetBuffer (bp, index); + DAT_LMR_TRIPLET *iov = DT_Bpool_GetIOV (bp, index); + DAT_LMR_CONTEXT lmr_c = DT_Bpool_GetLMR (bp, index); + DAT_DTO_COOKIE cookie; + DAT_RETURN ret; + + /* + * Prep the inputs + */ + iov->virtual_address = (DAT_VADDR) (uintptr_t) buff; + iov->segment_length = size; + iov->lmr_context = lmr_c; + cookie.as_64 = (DAT_UINT64)0UL; + cookie.as_ptr = (DAT_PVOID) buff; + + DT_Mdep_spew (3, ("Post-Recv #%d [%p, %x]\n", index, buff, size)); + + /* Post the recv buffer */ + ret = dat_ep_post_recv (ep_handle, + 1, + iov, + cookie, + DAT_COMPLETION_DEFAULT_FLAG); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("Test Error: dat_ep_post_recv failed: %s\n", + DT_RetToString (ret)); + DT_Test_Error (); + return false; + } + return true; +} + + +/* ----------------------------------------------------------- + * Post a send buffer + */ +DAT_BOOLEAN +DT_post_send_buffer (DAT_EP_HANDLE ep_handle, + Bpool * bp, + int index, + int size) +{ + unsigned char *buff = DT_Bpool_GetBuffer (bp, index); + DAT_LMR_TRIPLET *iov = DT_Bpool_GetIOV (bp, index); + DAT_LMR_CONTEXT lmr_c = DT_Bpool_GetLMR (bp, index); + DAT_DTO_COOKIE cookie; + DAT_RETURN ret; + + /* + * Prep the inputs + */ + iov->virtual_address = (DAT_VADDR) (uintptr_t) buff; + iov->segment_length = size; + iov->lmr_context = lmr_c; + cookie.as_64 = (DAT_UINT64)0UL; + cookie.as_ptr = (DAT_PVOID) buff; + + DT_Mdep_spew (3, ("Post-Send #%d [%p, %x]\n", index, buff, size)); + + /* Post the recv buffer */ + ret = dat_ep_post_send (ep_handle, + 1, + iov, + cookie, + DAT_COMPLETION_DEFAULT_FLAG); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("Test Error: dat_ep_post_send failed: %s\n", + DT_RetToString (ret)); + DT_Test_Error (); + return false; + } + return true; +} + + +/* ----------------------------------------------------------- + * Wait for a CR event, returning false on error. + */ +bool +DT_cr_event_wait ( DAT_EVD_HANDLE evd_handle, + DAT_CR_ARRIVAL_EVENT_DATA *cr_stat_p) +{ + int err_cnt; + + err_cnt = 0; + + for (;;) + { + DAT_RETURN ret; + DAT_EVENT event; + DAT_COUNT count; + + ret = dat_evd_wait ( evd_handle, + DAT_TIMEOUT_INFINITE, + 1, + &event, + &count); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("Test Error: dapl_event_wait (CR) failed: %s\n", + DT_RetToString (ret)); + DT_Test_Error (); + /* + * If we get an error due to the client breaking the + * connection early or some transients, just ignore it + * and keep going. If we get a bunch of errors, bail + * out. + */ +/* if ( err_cnt++ < 10 ) */ +/* { */ +/* continue; */ +/* } */ + + break; + } + + if (event.event_number == DAT_CONNECTION_REQUEST_EVENT) + { + /* + * Pass back what we know, if requested. + */ + if (cr_stat_p) + { + *cr_stat_p = event.event_data.cr_arrival_event_data; + } + return (true); + } + + DT_Mdep_printf ("Warning: cr_event_wait swallowing %s event\n", + DT_EventToSTr (event.event_number)); + } + + return (false); +} + + +/* ----------------------------------------------------------- + * Wait for a connection event, returning false on error. + */ +bool +DT_conn_event_wait (DAT_EP_HANDLE ep_handle, + DAT_EVD_HANDLE evd_handle, + DAT_EVENT_NUMBER *event_number) + +{ + for (;;) + { + DAT_RETURN ret; + DAT_EVENT event; + DAT_COUNT count; + + ret = dat_evd_wait (evd_handle, + DAT_TIMEOUT_INFINITE, + 1, + &event, + &count); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("Test Error: dapl_event_wait (CONN) failed: %s\n", + DT_RetToString (ret)); + DT_Test_Error (); + break; + } + *event_number = event.event_number; + if (event.event_number == DAT_CONNECTION_EVENT_PEER_REJECTED + || event.event_number == DAT_CONNECTION_EVENT_NON_PEER_REJECTED + || event.event_number == DAT_CONNECTION_EVENT_ACCEPT_COMPLETION_ERROR + || event.event_number == DAT_CONNECTION_EVENT_DISCONNECTED + || event.event_number == DAT_CONNECTION_EVENT_BROKEN + || event.event_number == DAT_CONNECTION_EVENT_UNREACHABLE + || event.event_number == DAT_CONNECTION_EVENT_TIMED_OUT) + { + DT_Mdep_printf ("Warning: conn_event_wait %s\n", + DT_EventToSTr (event.event_number)); + break; + } + if (event.event_number == DAT_CONNECTION_EVENT_ESTABLISHED) + { + /* + * Could return DAT_CONNECTION_EVENT_DATA and verify: + * event.event_data.connect_event_data.ep_handle + * event.event_data.connect_event_data.private_data_size + * event.event_data.connect_event_data.private_data + */ + return (true); + } + + DT_Mdep_printf ("Warning: conn_event_wait swallowing %s event\n", + DT_EventToSTr (event.event_number)); + } + + return (false); +} + + +/* ----------------------------------------------------------- + * Wait for a disconnection event, returning false on error. + */ +bool +DT_disco_event_wait ( DAT_EVD_HANDLE evd_handle, + DAT_EP_HANDLE *ep_handle ) +{ + for (;;) + { + DAT_RETURN ret; + DAT_EVENT event; + DAT_COUNT count; + + ret = dat_evd_wait (evd_handle, + DAT_TIMEOUT_INFINITE, + 1, + &event, + &count); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("Test Error: dapl_event_wait (DISCONN) failed: %s\n", + DT_RetToString (ret)); + DT_Test_Error (); + break; + } + if (event.event_number == DAT_CONNECTION_EVENT_PEER_REJECTED + || event.event_number == DAT_CONNECTION_EVENT_NON_PEER_REJECTED + || event.event_number == DAT_CONNECTION_EVENT_ACCEPT_COMPLETION_ERROR + || event.event_number == DAT_CONNECTION_EVENT_BROKEN + || event.event_number == DAT_CONNECTION_EVENT_UNREACHABLE + || event.event_number == DAT_CONNECTION_EVENT_TIMED_OUT) + { + DT_Mdep_printf ("Warning: disconn_event_wait %s\n", + DT_EventToSTr (event.event_number)); + break; + } + + + if (event.event_number == DAT_CONNECTION_EVENT_DISCONNECTED) + { + if ( ep_handle != NULL ) + { + *ep_handle = event.event_data.connect_event_data.ep_handle; + } + return (true); + } + + DT_Mdep_printf ("Warning: conn_event_wait swallowing %s event\n", + DT_EventToSTr (event.event_number)); + } + + return (false); +} + + +/* ----------------------------------------------------------- + * Reap a DTO event using a wait or polling, returning false on error. + */ +bool +DT_dto_event_reap (DAT_EVD_HANDLE evd_handle, + bool poll, + DAT_DTO_COMPLETION_EVENT_DATA *dto_statusp) +{ + if (poll) + { + return DT_dto_event_poll (evd_handle, dto_statusp); + } + else + { + return DT_dto_event_wait (evd_handle, dto_statusp); + } +} + + +/* ----------------------------------------------------------- + * Poll for a DTO event, returning false on error. + */ +bool +DT_dto_event_poll (DAT_EVD_HANDLE evd_handle, + DAT_DTO_COMPLETION_EVENT_DATA *dto_statusp) +{ + for (;;) + { + DAT_RETURN ret; + DAT_EVENT event; + + ret = dat_evd_dequeue ( evd_handle, + &event); + + if (DAT_GET_TYPE(ret) == DAT_QUEUE_EMPTY) + { + continue; + } + + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("Test Error: dapl_event_wait (DTO) failed: %s\n", + DT_RetToString (ret)); + DT_Test_Error (); + break; + } + + if (event.event_number == DAT_DTO_COMPLETION_EVENT) + { + /* + * Pass back all the useful bits if requested: + * ep_handle, user_cookie.as_ptr + * status, transfered_length + */ + if (dto_statusp) + { + *dto_statusp = event.event_data.dto_completion_event_data; + } + + return (true); + } + + DT_Mdep_printf ("Warning: dto_event_poll swallowing %s event\n", + DT_EventToSTr (event.event_number)); + } + + return (false); +} + + +/* ----------------------------------------------------------- + * Wait for a DTO event, returning false on error. + */ +bool +DT_dto_event_wait (DAT_EVD_HANDLE evd_handle, + DAT_DTO_COMPLETION_EVENT_DATA *dto_statusp) +{ + for (;;) + { + DAT_RETURN ret; + DAT_EVENT event; + DAT_COUNT count; + + ret = dat_evd_wait ( evd_handle, + DAT_TIMEOUT_INFINITE, + 1, + &event, + &count); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("Test Error: dapl_event_wait (DTO) failed: %s\n", + DT_RetToString (ret)); + DT_Test_Error (); + break; + } + + if (event.event_number == DAT_DTO_COMPLETION_EVENT) + { + /* + * Pass back all the useful bits if requested: + * ep_handle, user_cookie.as_ptr + * status, transfered_length + */ + if (dto_statusp) + { + *dto_statusp = event.event_data.dto_completion_event_data; + } + return (true); + } + + DT_Mdep_printf ("Warning: dto_event_wait swallowing %s event\n", + DT_EventToSTr (event.event_number)); + } + + return (false); +} + + +/* ----------------------------------------------------------- + * Wait for a RMR event, returning false on error. + */ +bool +DT_rmr_event_wait (DAT_EVD_HANDLE evd_handle, + DAT_RMR_BIND_COMPLETION_EVENT_DATA *rmr_statusp) +{ + for (;;) + { + DAT_RETURN ret; + DAT_EVENT event; + DAT_COUNT count; + + ret = dat_evd_wait ( evd_handle, + DAT_TIMEOUT_INFINITE, + 1, + &event, + &count); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("Test Error: dapl_event_wait (RMR) failed: %s\n", + DT_RetToString (ret)); + DT_Test_Error (); + break; + } + + if (event.event_number == DAT_RMR_BIND_COMPLETION_EVENT) + { + /* + * Pass back all the useful bits if requested: + * rmr_handle, user_cookie, status + */ + if (rmr_statusp) + { + *rmr_statusp = event.event_data.rmr_completion_event_data; + } + return (true); + } + + DT_Mdep_printf ("Warning: rmr_event_wait swallowing %s event\n", + DT_EventToSTr (event.event_number)); + } + + return (false); +} + + +/* ----------------------------------------------------------- + * Check a DTO and print some debug info if anything is amiss. + */ +bool +DT_dto_check ( DAT_DTO_COMPLETION_EVENT_DATA *dto_p, + DAT_EP_HANDLE ep_expected, + DAT_VLEN len_expected, + DAT_DTO_COOKIE cookie_expected, + char *message ) +{ + static char *completion_status_msg[]={ + "DAT_DTO_SUCCESS", + "DAT_DTO_ERR_FLUSHED", + "DAT_DTO_ERR_LOCAL_LENGTH", + "DAT_DTO_ERR_LOCAL_EP", + "DAT_DTO_ERR_LOCAL_PROTECTION", + "DAT_DTO_ERR_BAD_RESPONSE", + "DAT_DTO_ERR_REMOTE_ACCESS", + "DAT_DTO_ERR_REMOTE_RESPONDER", + "DAT_DTO_ERR_TRANSPORT", + "DAT_DTO_ERR_RECEIVER_NOT_READY", + "DAT_DTO_ERR_PARTIAL_PACKET", + "DAT_RMR_OPERATION_FAILED" + }; + if ( ( (ep_expected != NULL) && (dto_p->ep_handle != ep_expected) ) + || dto_p->transfered_length != len_expected + || dto_p->user_cookie.as_64 != cookie_expected.as_64 + || dto_p->status != DAT_DTO_SUCCESS ) + { + DT_Mdep_printf ("Test Error: %s-reaping DTO problem, status = %s\n", + message, (completion_status_msg[dto_p->status])); + DT_Test_Error (); + if ( (ep_expected != NULL) && (dto_p->ep_handle != ep_expected) ) + { + DT_Mdep_printf ("\tEndPoint mismatch (got %p wanted %p)\n", + dto_p->ep_handle, + ep_expected); + } + if (dto_p->transfered_length != len_expected) + { + DT_Mdep_printf ( + "\tLength mismatch (xfer 0x" F64x " wanted 0x" F64x ")\n", + (DAT_UVERYLONG)dto_p->transfered_length, + (DAT_UVERYLONG)len_expected); + } + if (dto_p->user_cookie.as_64 != cookie_expected.as_64) + { + DT_Mdep_printf ("\tCookie mismatch (got " F64x " wanted " F64x ")\n", + (DAT_UVERYLONG)dto_p->user_cookie.as_64, + (DAT_UVERYLONG)cookie_expected.as_64); + } + return ( false ); + } + + return ( true ); +} + + +/* ----------------------------------------------------------- + * Check an RMR Bind and print some debug info if anything is amiss. + */ +bool +DT_rmr_check ( DAT_RMR_BIND_COMPLETION_EVENT_DATA *rmr_p, + DAT_RMR_HANDLE rmr_expected, + DAT_PVOID cookie_expected, + char *message) +{ + if ( rmr_p->rmr_handle != rmr_expected + || rmr_p->user_cookie.as_ptr != cookie_expected + || rmr_p->status != DAT_RMR_BIND_SUCCESS ) + { + + DT_Mdep_printf ("Test Error: %s RMR bind problem, status = %s\n", + message, + (rmr_p->status == DAT_RMR_BIND_SUCCESS + ? "OK" : "FAILURE")); + DT_Test_Error (); + if (rmr_p->rmr_handle != rmr_expected) + { + DT_Mdep_printf ("\tRMR handle mismatch (got 0x%p wanted 0x%p)\n", + rmr_p->rmr_handle, + rmr_expected); + } + if (rmr_p->user_cookie.as_ptr != cookie_expected) + { + DT_Mdep_printf ("\tCookie mismatch (got %p wanted %p)\n", + rmr_p->user_cookie.as_ptr, + cookie_expected); + } + return ( false ); + } + + return ( true ); +} + + +/* ----------------------------------------------------------- + * Check a CR and print some debug info if anything is amiss. + */ +bool +DT_cr_check ( DAT_CR_ARRIVAL_EVENT_DATA *cr_stat_p, + DAT_PSP_HANDLE psp_handle_expected, + DAT_CONN_QUAL port_expected, + DAT_CR_HANDLE *cr_handlep, + char *message) +{ + DAT_RETURN ret; + + if (cr_handlep) + { + *cr_handlep = (DAT_CR_HANDLE) 0; + } + + if (cr_stat_p->conn_qual != port_expected || + (psp_handle_expected && + cr_stat_p->sp_handle.psp_handle != psp_handle_expected)) + { + + DT_Mdep_printf ("Test Error: %s CR data problem\n", message); + DT_Test_Error (); + if (cr_stat_p->conn_qual != port_expected) + { + DT_Mdep_printf ("\tCR conn_qual mismatch " + " (got 0x" F64x " wanted 0x" F64x ")\n", + (DAT_UVERYLONG)cr_stat_p->conn_qual, + (DAT_UVERYLONG)port_expected); + } + if (psp_handle_expected && + cr_stat_p->sp_handle.psp_handle != psp_handle_expected) + { + DT_Mdep_printf ("\tPSP mismatch (got 0x%p wanted 0x%p)\n", + cr_stat_p->sp_handle.psp_handle, + psp_handle_expected); + } + if (!cr_stat_p->cr_handle) + { + DT_Mdep_printf ("\tGot NULL cr_handle\n"); + } + else + { + ret = dat_cr_reject (cr_stat_p->cr_handle); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("\tdat_cr_reject error: %s\n", + DT_RetToString (ret)); + } + } + return ( false ); + } + + if (cr_handlep) + { + *cr_handlep = cr_stat_p->cr_handle; + } + return ( true ); +} diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_thread.c b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_thread.c new file mode 100644 index 00000000..466a3548 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_thread.c @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_mdep.h" +#include "dapl_memlist.h" +#include "dapl_proto.h" +/* + * Class Thread + * + * Threads subsystem initialization + */ +void +DT_Thread_Init (Per_Test_Data_t * pt_ptr) +{ + DT_Mdep_LockInit (&pt_ptr->Thread_counter_lock); + pt_ptr->Thread_counter = 0; + + /* + * Initialize the synchronization event in the pt_ptr so it's ready + * to be signalled when the time comes. The countdown counter + * lets me coordinate with all the test threads so that the server + * thread doesn't get notified that the test endpoints are ready + * until they actually are. Only transaction tests use this * + * functionality; if the performance test gets changed to use + * multiple threads on the server side then that code semantic + * will need to be added for final test endpoint setup + * notification or there will continue to be a race condition + * between the main server thread and the server test threads. + */ + DT_Mdep_wait_object_init(&pt_ptr->synch_wait_object); + pt_ptr->Countdown_Counter = 0; + +} + +/* + * Threads subsystem destroying + */ +void +DT_Thread_End (Per_Test_Data_t * pt_ptr) +{ + DT_Mdep_LockDestroy (&pt_ptr->Thread_counter_lock); + + /* + * destroy the wait object created by init. + */ + DT_Mdep_wait_object_destroy ( + &pt_ptr->synch_wait_object ); + +} + +/* + * Thread constructor + * + * NOTE: This routine does NOT create a thread as the name implies. The thread + * is created in DT_Thread_Start (which is counter intuitive) + */ +Thread * +DT_Thread_Create (Per_Test_Data_t * pt_ptr, + void (*fn) (void *), + void *param, + unsigned int stacksize) +{ + Thread *thread_ptr; + thread_ptr = (Thread *) DT_MemListAlloc (pt_ptr, "thread.c", THREAD, sizeof (Thread)); + if (thread_ptr == NULL) + { + return NULL; + } + thread_ptr->param = param; + thread_ptr->function = fn; + thread_ptr->thread_handle = 0; + thread_ptr->stacksize = stacksize; + + DT_Mdep_Lock (&pt_ptr->Thread_counter_lock); + pt_ptr->Thread_counter++; + DT_Mdep_Unlock (&pt_ptr->Thread_counter_lock); + + DT_Mdep_Thread_Init_Attributes (thread_ptr); + + return thread_ptr; +} + +/* + * Thread destructor + */ +void +DT_Thread_Destroy (Thread * thread_ptr, Per_Test_Data_t * pt_ptr) +{ + if (thread_ptr) + { + DT_Mdep_Lock (&pt_ptr->Thread_counter_lock); + pt_ptr->Thread_counter--; + DT_Mdep_Unlock (&pt_ptr->Thread_counter_lock); + + DT_Mdep_Thread_Destroy_Attributes (thread_ptr); + DT_MemListFree (pt_ptr, thread_ptr); + } +} + +/* + * Start thread execution NOTE: This routine DOES create a thread in addition + * to starting it whereas DT_Thread_Create just sets up some data structures. + * (this is counter-intuitive) + */ +bool +DT_Thread_Start (Thread * thread_ptr) +{ + return DT_Mdep_Thread_Start (thread_ptr); +} diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_transaction_cmd.c b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_transaction_cmd.c new file mode 100644 index 00000000..d2518c82 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_transaction_cmd.c @@ -0,0 +1,543 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_bpool.h" +#include "dapl_test_data.h" +#include "dapl_mdep.h" +#include "dapl_proto.h" +#include "dapl_transaction_test.h" + + +static bool +DT_Transaction_Cmd_Parse_Op (Transaction_Cmd_t * cmd, char *arg) +{ + char *c_ptr; + int op; + if (cmd->num_ops >= MAX_OPS) + { + DT_Mdep_printf ("Client: Too Many Ops - Max %d\n", MAX_OPS); + goto error_return; + } + op = cmd->num_ops; + cmd->num_ops++; + + /* set some defaults */ + cmd->op[op].seg_size = 4096; + cmd->op[op].num_segs = 1; + cmd->op[op].reap_send_on_recv = false; + + /* + * packet format: [seg_size] [num_segs] + */ + c_ptr = strtok (arg, " \t"); + if (!c_ptr) + { + DT_Mdep_printf ("OP first arg must \n"); + goto error_return; + } + /* first token is : */ + if (strcmp (c_ptr, "server") == 0) + { + cmd->op[op].server_initiated = true; + } + else + { + if (strcmp (c_ptr, "client") == 0) + { + cmd->op[op].server_initiated = false; + } + else + { + DT_Mdep_printf ("OP first arg must \n"); + goto error_return; + } + } + + c_ptr = strtok (0, " \t"); + if (!c_ptr) + { + DT_Mdep_printf ("OP Second arg must be \n"); + goto error_return; + } + /* second token is : */ + if (strcmp (c_ptr, "RR") == 0) + { + cmd->op[op].transfer_type = RDMA_READ; + } + else + { + if (strcmp (c_ptr, "RW") == 0) + { + cmd->op[op].transfer_type = RDMA_WRITE; + } + else + { + if (strcmp (c_ptr, "SR") == 0) + { + cmd->op[op].transfer_type = SEND_RECV; + } + else + { + DT_Mdep_printf ("OP Second arg must be \n"); + goto error_return; + } + } + } + /* + * there may or may not be additional parameters... [seg_size] [num_segs] + * [-f] + */ + c_ptr = strtok (0, " \t"); + if (c_ptr && strspn (c_ptr, "0123456789") != 0) + { + cmd->op[op].seg_size = atoi (c_ptr); + c_ptr = strtok (0, " \t"); + } + if (c_ptr && strspn (c_ptr, "0123456789") != 0) + { + cmd->op[op].num_segs = atoi (c_ptr); + c_ptr = strtok (0, " \t"); + } + if (c_ptr && strcmp (c_ptr, "-f") == 0) + { + cmd->op[op].reap_send_on_recv = true; + if (cmd->op[op].transfer_type != SEND_RECV) + { + DT_Mdep_printf ("OP: -f only valid on SEND_RECV\n"); + goto error_return; + } + c_ptr = strtok (0, " \t"); + } + if (c_ptr) + { + DT_Mdep_printf ("OP too many args \n"); + goto error_return; + } + return true; + +error_return: + return false; +} + + +void +DT_Transaction_Cmd_Print (Transaction_Cmd_t * cmd) +{ + unsigned int i; + DT_Mdep_printf ("-------------------------------------\n"); + DT_Mdep_printf ("TransCmd.server_name : %s\n", + cmd->server_name); + DT_Mdep_printf ("TransCmd.num_iterations : %d\n", + cmd->num_iterations); + DT_Mdep_printf ("TransCmd.num_threads : %d\n", + cmd->num_threads); + DT_Mdep_printf ("TransCmd.eps_per_thread : %d\n", + cmd->eps_per_thread); + DT_Mdep_printf ("TransCmd.validate : %d\n", + cmd->validate); + DT_Mdep_printf ("TransCmd.dapl_name : %s\n", + cmd->dapl_name); + DT_Mdep_printf ("TransCmd.num_ops : %d\n", + cmd->num_ops); + + for (i = 0; i < cmd->num_ops; i++) + { + DT_Mdep_printf ("TransCmd.op[%d].transfer_type : %s %s\n", + i, + cmd->op[i].transfer_type == 0 ? "RDMA_READ" : + cmd->op[i].transfer_type == 1 ? "RDMA_WRITE" : + "SEND_RECV", + cmd->op[i].server_initiated ? " (server)" : " (client)" ); + DT_Mdep_printf ("TransCmd.op[%d].seg_size : %d\n", + i, + cmd->op[i].seg_size); + DT_Mdep_printf ("TransCmd.op[%d].num_segs : %d\n", + i, + cmd->op[i].num_segs); + DT_Mdep_printf ("TransCmd.op[%d].reap_send_on_recv : %d\n", + i, + cmd->op[i].reap_send_on_recv); + } +} + + +static bool +DT_Transaction_Cmd_Validate (Transaction_Cmd_t * cmd) +{ + unsigned int i; + bool has_server_send; + bool has_client_send; + unsigned int reap_count; + has_server_send = false; + has_client_send = false; + reap_count = 0; + + if (cmd->server_name[0] == '\0') + { + DT_Mdep_printf ("Must specify server_name in command line or scriptfile\n"); + return (false); + } + for (i = 0; i < cmd->num_ops; i++) + { + switch (cmd->op[i].transfer_type) + { + case SEND_RECV: + { + if (cmd->op[i].server_initiated) + { + has_server_send = true; + } + else + { + has_client_send = true; + } + if (cmd->op[i].reap_send_on_recv) + { + if (!cmd->op[i].server_initiated) + { + /* client */ + reap_count++; + } + else + { + /* server */ + if (reap_count > 0) + { + reap_count--; + } + else + { + DT_Mdep_printf ("OP: Unbalanced -f options\n"); + return false; + } + } + } + break; + } + case RDMA_READ: + { + break; + } + case RDMA_WRITE: + { + break; + } + } + } + + if (!has_server_send || !has_client_send) + { + DT_Mdep_printf ("Error: Transaction test requires \n"); + DT_Mdep_printf ("Error: At least one server SR and one client SR Operation\n"); + return false; + } + if (reap_count != 0) + { + DT_Mdep_printf ("OP: Unbalanced -f options\n"); + return false; + } + if (cmd->debug) + { + DT_Transaction_Cmd_Print (cmd); + } + return true; +} + + +static void +DT_Transaction_Cmd_Usage (void) +{ + DT_Mdep_printf ("USAGE: ---- TRANSACTION TEST ----\n"); + DT_Mdep_printf ("USAGE: dapltest -T T\n"); + DT_Mdep_printf ("USAGE: -s \n"); + DT_Mdep_printf ("USAGE: [-D ]\n"); + DT_Mdep_printf ("USAGE: [-d] : debug (zero)\n"); + DT_Mdep_printf ("USAGE: [-i ] : (1, 000)\n"); + DT_Mdep_printf ("USAGE: [-t ] : (1)\n"); + DT_Mdep_printf ("USAGE: [-w ] : (1)\n"); + DT_Mdep_printf ("USAGE: [-V ] : Validate data: (false)\n"); + DT_Mdep_printf ("USAGE: [-P ] : DTO Completion Polling: (false)\n"); + DT_Mdep_printf ("USAGE: [-Q ] : Use CNOs: (false)\n"); + DT_Mdep_printf ("USAGE: [-r ] : Use RSPs: (false)\n"); + DT_Mdep_printf ("USAGE: [-R ]\n"); + DT_Mdep_printf ("USAGE: (BE == QOS_BEST_EFFORT - Default)\n"); + DT_Mdep_printf ("USAGE: (HT == QOS_HIGH_THROUGHPUT)\n"); + DT_Mdep_printf ("USAGE: (LL == QOS_LOW_LATENCY)\n"); + DT_Mdep_printf ("USAGE: (EC == QOS_ECONOMY)\n"); + DT_Mdep_printf ("USAGE: (PM == QOS_PREMIUM)\n"); + DT_Mdep_printf ("USAGE: : \"server\"/\"client\"\n"); + DT_Mdep_printf ("USAGE: : \"SR\" (SEND/RECV)\n"); + DT_Mdep_printf ("USAGE: : \"RR\" (RDMA READ)\n"); + DT_Mdep_printf ("USAGE: : \"RW\" (RDMA WRITE)\n"); + DT_Mdep_printf ("USAGE: [seg_size [num_segs] ] : (4096, 1)\n"); + DT_Mdep_printf ("USAGE: [-f] : Reap sends on recv\n"); + DT_Mdep_printf ("USAGE:\n"); + DT_Mdep_printf ("NOTE: -f is only allowed on \"SR\" OPs\n"); + DT_Mdep_printf ("NOTE: -f must appear in pairs (one client, one server)\n"); + DT_Mdep_printf ( + "NOTE: At least one server SR and one client SR OP are required\n"); + DT_Mdep_printf ( + "NOTE: and use of -V results in the use of three extra OPs\n"); +} + + +void +DT_Transaction_Cmd_Init (Transaction_Cmd_t * cmd) +{ + memset ((void *)cmd, 0, sizeof (Transaction_Cmd_t)); + cmd->dapltest_version = DAPLTEST_VERSION; + cmd->client_is_little_endian = DT_local_is_little_endian; + cmd->num_iterations = 1000; + cmd->num_threads = 1; + cmd->eps_per_thread = 1; + cmd->debug = false; + cmd->validate = false; + cmd->ReliabilityLevel = DAT_QOS_BEST_EFFORT; +} + + +bool +DT_Transaction_Cmd_Parse (Transaction_Cmd_t * cmd, + int my_argc, + char **my_argv, + mygetopt_t * opts) +{ + char c; + unsigned int len; + int i; + char op[100]; + for (;;) + { + c = DT_mygetopt_r (my_argc, my_argv, "rQVPdw:s:D:i:t:v:R:", opts); + if (c == EOF) + { + break; + } + switch (c) + { + case 's': /* server name */ + { + if ((opts->optarg == 0) || strlen (opts->optarg) == 0 + || *opts->optarg == '-') + { + DT_Mdep_printf ("must specify server name\n"); + DT_Transaction_Cmd_Usage (); + return (false); + } + strcpy (cmd->server_name, opts->optarg); + break; + } + case 'D': /* device name */ + { + strcpy (cmd->dapl_name, opts->optarg); + break; + } + + case 'i': /* num iterations */ + { + len = (unsigned int)strspn (opts->optarg, "0123456789"); + if (len == 0 || len != strlen (opts->optarg)) + { + DT_Mdep_printf ("Syntax Error -i option\n"); + DT_Transaction_Cmd_Usage (); + return (false); + } + cmd->num_iterations = atol (opts->optarg); + + break; + } + case 't': /* num threads */ + { + len = (unsigned int)strspn (opts->optarg, "0123456789"); + if (len == 0 || len != strlen (opts->optarg)) + { + DT_Mdep_printf ("Syntax Error -t option\n"); + DT_Transaction_Cmd_Usage (); + return (false); + } + cmd->num_threads = atol (opts->optarg); + break; + } + case 'w': /* num EPs per thread */ + { + len = (unsigned int)strspn (opts->optarg, "0123456789"); + if (len == 0 || len != strlen (opts->optarg)) + { + DT_Mdep_printf ("Syntax Error -w option\n"); + DT_Transaction_Cmd_Usage (); + return (false); + } + cmd->eps_per_thread = atol (opts->optarg); + break; + } + case 'd': /* print debug messages */ + { + DT_dapltest_debug++; + cmd->debug = true; + break; + } + case 'Q': /* funnel EVDs => CNO */ + { + cmd->use_cno = true; + break; + } + case 'r': /* use RSP instead of PSP */ + { + cmd->use_rsp = true; + break; + } + case 'V': /* validate data being sent/received */ + { + cmd->validate = true; + break; + } + case 'P': /* use completion polling */ + { + cmd->poll = true; + break; + } + case 'R': /* Service Reliability Level */ + { + cmd->ReliabilityLevel = DT_ParseQoS (opts->optarg); + break; + } + case '?': + default: + { + DT_Mdep_printf ("Invalid Transaction Test Parameter: %c\n", c); + DT_Transaction_Cmd_Usage (); + return (false); + } + } + } + if (cmd->dapl_name[0] == '\0') + { + if (!DT_Mdep_GetDefaultDeviceName (cmd->dapl_name)) + { + DT_Mdep_printf ("can't get default device name\n"); + DT_Transaction_Cmd_Usage (); + return (false); + } + } + /* + * now parse the transaction ops this is ugly, but it's easier to gather + * each transaction into a single string + */ + for (i = opts->optind; i < my_argc; i++) + { + strcpy (&op[0], my_argv[i]); + while (i < my_argc - 1) + { + i++; + if ((strncmp (my_argv[i], "client", 6) == 0) || + strncmp (my_argv[i], "server", 6) == 0) + { + i--; + break; + } + strcat (op, " "); + strcat (op, my_argv[i]); + } + if (!DT_Transaction_Cmd_Parse_Op (cmd, op)) + { + DT_Transaction_Cmd_Usage (); + return (false); + } + } + + /* + * If we're going to validate the data, we append 3 OPs that + * serve as barriers so that both the client and server can + * validate their entire set of recv transactions without + * interference. + * + * The first op appended serves to notify the client that the + * server is at the rendezvous and will transfer nothing else, + * so the client can validate all recv buffers. The second op + * notifies the server that the client is quiescent, so the + * server can safely validate its recv buffers. The final op + * tells the client that the server is done, and both can + * proceed with the next iteration. + */ + if (cmd->validate) + { + DT_Mdep_printf ("NOTE: Adding OP \"server SR\" - for validation\n"); + memcpy (op, "server SR", strlen ("server SR") + 1); + DT_Transaction_Cmd_Parse_Op (cmd, op); + + DT_Mdep_printf ("NOTE: Adding OP \"client SR\" - for validation\n"); + memcpy (op, "client SR", strlen ("client SR") + 1); + DT_Transaction_Cmd_Parse_Op (cmd, op); + + DT_Mdep_printf ("NOTE: Adding OP \"server SR\" - for validation\n"); + memcpy (op, "server SR", strlen ("server SR") + 1); + DT_Transaction_Cmd_Parse_Op (cmd, op); + } + if (!DT_Transaction_Cmd_Validate (cmd)) + { + DT_Transaction_Cmd_Usage (); + return (false); + } + return (true); +} + + +void +DT_Transaction_Cmd_Endian (Transaction_Cmd_t * cmd, bool to_wire) +{ + unsigned int i; + + cmd->dapltest_version = DT_Endian32 (cmd->dapltest_version); + cmd->num_iterations = DT_Endian32 (cmd->num_iterations); + cmd->num_threads = DT_Endian32 (cmd->num_threads); + cmd->eps_per_thread = DT_Endian32 (cmd->eps_per_thread); + cmd->use_cno = DT_Endian32 (cmd->use_cno); + cmd->use_rsp = DT_Endian32 (cmd->use_rsp); + cmd->debug = DT_Endian32 (cmd->debug); + cmd->validate = DT_Endian32 (cmd->validate); + cmd->ReliabilityLevel = DT_Endian32 (cmd->ReliabilityLevel); + + if (!to_wire) + { + cmd->num_ops = DT_Endian32 (cmd->num_ops); + } + for (i = 0; i < cmd->num_ops; i++) + { + cmd->op[i].server_initiated = DT_Endian32 (cmd->op[i].server_initiated); + cmd->op[i].transfer_type = DT_Endian32 (cmd->op[i].transfer_type); + cmd->op[i].num_segs = DT_Endian32 (cmd->op[i].num_segs); + cmd->op[i].seg_size = DT_Endian32 (cmd->op[i].seg_size); + cmd->op[i].reap_send_on_recv = + DT_Endian32 (cmd->op[i].reap_send_on_recv); + } + if (to_wire) + { + cmd->num_ops = DT_Endian32 (cmd->num_ops); + } +} diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_transaction_cmd.h b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_transaction_cmd.h new file mode 100644 index 00000000..849f50ce --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_transaction_cmd.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#ifndef __DAPL_TRANSACTION_CMD_H__ +#define __DAPL_TRANSACTION_CMD_H__ + +#include "dapl_mdep.h" +#include + +#define MAX_OPS 100 +#define NAME_SZ 256 + +typedef struct +{ + DAT_UINT32 server_initiated; + DAT_UINT32 transfer_type; + DAT_UINT32 num_segs; + DAT_UINT32 seg_size; + DAT_UINT32 reap_send_on_recv; +}Transaction_Cmd_Op_t; + +typedef struct +{ + DAT_UINT32 dapltest_version; + DAT_UINT32 client_is_little_endian; + char server_name[NAME_SZ]; /* -s */ + DAT_UINT32 num_iterations; /* -i */ + DAT_UINT32 num_threads; /* -t */ + DAT_UINT32 eps_per_thread; /* -w */ + DAT_UINT32 use_cno; /* -Q */ + DAT_UINT32 use_rsp; /* -r */ + DAT_UINT32 debug; /* -d */ + DAT_UINT32 validate; /* -V */ + DAT_UINT32 poll; /* -P */ + char dapl_name[NAME_SZ]; /* -D */ + DAT_QOS ReliabilityLevel; + DAT_UINT32 num_ops; + Transaction_Cmd_Op_t op[MAX_OPS]; +} Transaction_Cmd_t; + +#endif diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_transaction_stats.c b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_transaction_stats.c new file mode 100644 index 00000000..65972351 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_transaction_stats.c @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_transaction_stats.h" +#include "dapl_proto.h" +#include "dapl_test_data.h" + +void +DT_init_transaction_stats (Transaction_Stats_t * transaction_stats, unsigned int num) +{ + DT_Mdep_LockInit (&transaction_stats->lock); + + transaction_stats->wait_count = num; + transaction_stats->num_ops = 0; + transaction_stats->time_ms = 0; + transaction_stats->bytes_send = 0; + transaction_stats->bytes_recv = 0; + transaction_stats->bytes_rdma_read = 0; + transaction_stats->bytes_rdma_write = 0; +} + +void +DT_transaction_stats_set_ready (Transaction_Stats_t * transaction_stats) +{ + DT_Mdep_Lock (&transaction_stats->lock); + transaction_stats->wait_count--; + + DT_Mdep_debug (("Received Sync Message from server (%d left)\n", + transaction_stats->wait_count)); + DT_Mdep_Unlock (&transaction_stats->lock); +} + +bool +DT_transaction_stats_wait_for_all (Transaction_Stats_t * transaction_stats) +{ + unsigned int loop_count; + loop_count = 100 * 10; /* 100 * 10ms * 10 = 10 seconds */ + while (transaction_stats->wait_count != 0 && loop_count != 0) + { + DT_Mdep_Sleep (10); + loop_count--; + } + if (loop_count == 0) + { + DT_Mdep_printf ("FAIL: %d Server test connections did not report ready.\n", + transaction_stats->wait_count); + return false; + } + return true; +} + + +/* + * + */ +void +DT_update_transaction_stats (Transaction_Stats_t * transaction_stats, + unsigned int num_ops, + unsigned int time_ms, + unsigned int bytes_send, + unsigned int bytes_recv, + unsigned int bytes_rdma_read, + unsigned int bytes_rdma_write) +{ + DT_Mdep_Lock (&transaction_stats->lock); + + /* look for the longest time... */ + if (time_ms > transaction_stats->time_ms) + { + transaction_stats->time_ms = time_ms; + } + + transaction_stats->num_ops += num_ops; + transaction_stats->bytes_send += bytes_send; + transaction_stats->bytes_recv += bytes_recv; + transaction_stats->bytes_rdma_read += bytes_rdma_read; + transaction_stats->bytes_rdma_write += bytes_rdma_write; + DT_Mdep_Unlock (&transaction_stats->lock); +} + +/* + * + */ +void +DT_print_transaction_stats (Transaction_Stats_t * transaction_stats, + unsigned int num_threads, + unsigned int num_EPs) +{ + double time_s; + double mbytes_send; + double mbytes_recv; + double mbytes_rdma_read; + double mbytes_rdma_write; + int total_ops; + DT_Mdep_Lock (&transaction_stats->lock); + time_s = (double) (transaction_stats->time_ms) / 1000; + if (time_s == 0.0) + { + DT_Mdep_printf ("----- Test completed successfully, but cannot calculate stats as not\n" + "----- enough time has lapsed.\n" + "----- Try running the test with more iterations.\n"); + goto unlock_and_return; + } + mbytes_send = (double) transaction_stats->bytes_send / 1000 / 1000; + mbytes_recv = (double) transaction_stats->bytes_recv / 1000 / 1000; + mbytes_rdma_read = (double) transaction_stats->bytes_rdma_read / 1000 / 1000; + mbytes_rdma_write = (double) transaction_stats->bytes_rdma_write / 1000 / 1000; + total_ops = transaction_stats->num_ops; + + if ( 0 == total_ops ) + { + DT_Mdep_printf ("----- Test completed successfully, but no operations!\n"); + goto unlock_and_return; + } + + DT_Mdep_printf ("----- Stats ---- : %u threads, %u EPs\n", + num_threads, num_EPs); + DT_Mdep_printf ("Total IBWQE : %7d.%02d WQE/Sec\n", + whole (total_ops / time_s), + hundredths (total_ops / time_s)); + DT_Mdep_printf ("Total Time : %7d.%02d sec\n", + whole (time_s), + hundredths (time_s)); + DT_Mdep_printf ("Total Send : %7d.%02d MB - %7d.%02d MB/Sec\n", + whole (mbytes_send), + hundredths (mbytes_send), + whole (mbytes_send / time_s), + hundredths (mbytes_send / time_s)); + DT_Mdep_printf ("Total Recv : %7d.%02d MB - %7d.%02d MB/Sec\n", + whole (mbytes_recv), + hundredths (mbytes_recv), + whole (mbytes_recv / time_s), + hundredths (mbytes_recv / time_s)); + DT_Mdep_printf ("Total RDMA Read : %7d.%02d MB - %7d.%02d MB/Sec\n", + whole (mbytes_rdma_read), + hundredths (mbytes_rdma_read), + whole (mbytes_rdma_read / time_s), + hundredths (mbytes_rdma_read / time_s)); + DT_Mdep_printf ("Total RDMA Write : %7d.%02d MB - %7d.%02d MB/Sec\n", + whole (mbytes_rdma_write), + hundredths (mbytes_rdma_write), + whole (mbytes_rdma_write / time_s), + hundredths (mbytes_rdma_write / time_s)); + +unlock_and_return: + DT_Mdep_Unlock (&transaction_stats->lock); +} diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_transaction_stats.h b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_transaction_stats.h new file mode 100644 index 00000000..ed1cb6eb --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_transaction_stats.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#ifndef __DAPL_TRANSACTION_STATS_H__ +#define __DAPL_TRANSACTION_STATS_H__ + +#include "dapl_mdep.h" + +#define whole(num) ((unsigned int)(num)) +#define hundredths(num) ((unsigned int)(((num) - (unsigned int)(num)) * 100)) +#pragma pack(1) +typedef struct +{ + DT_Mdep_LockType lock; + unsigned int wait_count; + unsigned int num_ops; + unsigned int time_ms; + unsigned int bytes_send; + unsigned int bytes_recv; + unsigned int bytes_rdma_read; + unsigned int bytes_rdma_write; +} Transaction_Stats_t; +#pragma pack() +#endif diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_transaction_test.c b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_transaction_test.c new file mode 100644 index 00000000..c358de74 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_transaction_test.c @@ -0,0 +1,1922 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_bpool.h" +#include "dapl_transaction_stats.h" +#include "dapl_test_data.h" +#include "dapl_mdep.h" +#include "dapl_memlist.h" +#include "dapl_proto.h" +#include "dapl_transaction_cmd.h" +#include "dapl_transaction_test.h" +#include + +#define RMI_SEND_BUFFER_ID 0 +#define RMI_RECV_BUFFER_ID 1 +#define SYNC_SEND_BUFFER_ID 2 +#define SYNC_RECV_BUFFER_ID 3 + +/* + * The sync buffers are sent to say "Go!" to the other side. + * This is a handy place to test whether a zero-sized send into + * a zero-sized buffer actually works. If the client side hangs + * in 'Wait for Sync Message' when this is zero, it's a DAPL bug. + */ +#define SYNC_BUFF_SIZE 64 + +#define DFLT_QLEN 8 /* default event queue length */ +#define DFLT_TMO 10 /* default timeout (seconds) */ +#define MAX_CONN_RETRY 8 + +/****************************************************************************/ +void +DT_Transaction_Test_Client (Per_Test_Data_t * pt_ptr, + DAT_IA_HANDLE ia_handle, + DAT_IA_ADDRESS_PTR remote_ia_addr) +{ + Transaction_Cmd_t *cmd = &pt_ptr->Params.u.Transaction_Cmd; + unsigned int i; + + DT_init_transaction_stats (&pt_ptr->Client_Stats, + cmd->num_threads * cmd->eps_per_thread); + + /* Now go set up the client test threads */ + for (i = 0; i < cmd->num_threads; i++) + { + unsigned int port_num = pt_ptr->Server_Info.first_port_number + + i * cmd->eps_per_thread; + + DT_Mdep_debug (("Client: Starting Client side of test\n")); + if (!DT_Transaction_Create_Test (pt_ptr, + ia_handle, + false, + port_num, + pt_ptr->Server_Info.is_little_endian, + remote_ia_addr)) + { + DT_Mdep_printf ("Client: Cannot Create Test!\n"); + break; + } + +#ifdef CM_BUSTED + /***** XXX Chill out a bit to give the kludged CM a chance ... + *****/DT_Mdep_Sleep (5000); +#endif + + } + + /* Wait until end of all threads */ + while (pt_ptr->Thread_counter > 0) + { + DT_Mdep_Sleep (100); + } + + DT_print_transaction_stats (&pt_ptr->Client_Stats, + cmd->num_threads, + cmd->eps_per_thread); +} + + +/****************************************************************************/ +void +DT_Transaction_Test_Server (void *params) +{ + Per_Test_Data_t *pt_ptr = (Per_Test_Data_t *) params; + Transaction_Cmd_t *cmd = &pt_ptr->Params.u.Transaction_Cmd; + unsigned int i; + + pt_ptr->Countdown_Counter = cmd->num_threads; + + for (i = 0; i < cmd->num_threads; i++) + { + unsigned int port_num = pt_ptr->Server_Info.first_port_number + + i * cmd->eps_per_thread; + + if (!DT_Transaction_Create_Test (pt_ptr, + pt_ptr->ps_ptr->ia_handle, + true, + port_num, + pt_ptr->Client_Info.is_little_endian, + (DAT_IA_ADDRESS_PTR) 0)) + { + DT_Mdep_printf ("Server: Cannot Create Test!\n"); + break; + } + +#ifdef CM_BUSTED + /***** XXX Chill out a bit to give the kludged CM a chance ... + *****/DT_Mdep_Sleep (5000); +#endif + + } + + /* Wait until end of all sub-threads */ + while (pt_ptr->Thread_counter > 1) + { + DT_Mdep_Sleep (100); + } + DT_Thread_Destroy (pt_ptr->thread, pt_ptr); /* destroy Master thread */ + + DT_Mdep_Lock (&pt_ptr->ps_ptr->num_clients_lock); + pt_ptr->ps_ptr->num_clients--; + DT_Mdep_Unlock (&pt_ptr->ps_ptr->num_clients_lock); + + /* NB: Server has no pt_ptr->remote_netaddr */ + DT_PrintMemList (pt_ptr); /* check if we return all space allocated */ + DT_Mdep_LockDestroy (&pt_ptr->Thread_counter_lock); + DT_Mdep_LockDestroy (&pt_ptr->MemListLock); + DT_Free_Per_Test_Data (pt_ptr); + DT_Mdep_printf ("Server: Transaction Test Finished for this client\n"); + /* + * check memory leaking DT_Mdep_printf("Server: App allocated Memory Left: + * %d\n", alloc_count); + */ +} + + +/****************************************************************************/ +/* + * DT_Transaction_Create_Test() + * + * Initialize what we can in the test structure. Then fork a thread to do the + * work. + */ + +bool +DT_Transaction_Create_Test (Per_Test_Data_t * pt_ptr, + DAT_IA_HANDLE *ia_handle, + DAT_BOOLEAN is_server, + unsigned int port_num, + DAT_BOOLEAN remote_is_little_endian, + DAT_IA_ADDRESS_PTR remote_ia_addr) +{ + Transaction_Test_t *test_ptr; + + test_ptr = (Transaction_Test_t *) DT_MemListAlloc (pt_ptr, + "transaction_test_t", + TRANSACTIONTEST, + sizeof (Transaction_Test_t)); + if (!test_ptr) + { + DT_Mdep_printf ("No Memory to create transaction test structure!\n"); + return false; + } + + /* Unused fields zeroed by allocator */ + test_ptr->remote_is_little_endian = remote_is_little_endian; + test_ptr->is_server = is_server; + test_ptr->pt_ptr = pt_ptr; + test_ptr->ia_handle = ia_handle; + test_ptr->base_port = (DAT_CONN_QUAL) port_num; + test_ptr->cmd = &pt_ptr->Params.u.Transaction_Cmd; + test_ptr->time_out = DFLT_TMO * 1000; /* DFLT_TMO seconds */ + + /* FIXME more analysis needs to go into determining the minimum */ + /* possible value for DFLT_QLEN. This evd_length value will be */ + /* used for all EVDs. There are a number of dependencies imposed */ + /* by this design (ex. min(cr_evd_len) != min(recv_evd_len) ). */ + /* In the future it may be best to use individual values. */ + test_ptr->evd_length = DT_max ( + DFLT_QLEN, + test_ptr->cmd->eps_per_thread * test_ptr->cmd->num_ops); + + test_ptr->remote_ia_addr = remote_ia_addr; + + test_ptr->thread = DT_Thread_Create (pt_ptr, + DT_Transaction_Main, + test_ptr, + DT_MDEP_DEFAULT_STACK_SIZE); + if (test_ptr->thread == 0) + { + DT_Mdep_printf ("No memory!\n"); + DT_MemListFree (test_ptr->pt_ptr, test_ptr); + return false; + } + DT_Thread_Start (test_ptr->thread); + + return true; +} + + +/****************************************************************************/ +/* + * Main Transaction Test Execution Routine + * + * Both client and server threads start here, with IA already open. + * Each test thread establishes a connection with its counterpart. + * They swap remote memory information (if necessary), then set up + * buffers and local data structures. When ready, the two sides + * synchronize, then testing begins. + */ +void +DT_Transaction_Main (void *param) +{ + Transaction_Test_t *test_ptr = (Transaction_Test_t *) param; + DAT_RETURN ret; + DAT_UINT32 i, j; + bool success = false; + Per_Test_Data_t *pt_ptr; + Thread *thread; + DAT_DTO_COOKIE dto_cookie; + char *private_data_str = "DAPL and RDMA rule! Test 4321."; + DAT_EVENT_NUMBER event_num; + + pt_ptr = test_ptr->pt_ptr; + thread = test_ptr->thread; + + /* create a protection zone */ + ret = dat_pz_create (test_ptr->ia_handle, &test_ptr->pz_handle); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("Test[" F64x "]: dat_pz_create error: %s\n", + (DAT_UVERYLONG)test_ptr->base_port, DT_RetToString (ret)); + test_ptr->pz_handle = DAT_HANDLE_NULL; + goto test_failure; + } + + /* Create a CNO if necessary */ + if (test_ptr->cmd->use_cno) + { + DT_Mdep_printf ("Test[" F64x "]: Warning: CNO use not yet supported (%s)\n", + (DAT_UVERYLONG)test_ptr->base_port, "ignored"); + /* ignored - just fall through */ + } + + /* create 4 EVDs - recv, request+RMR, conn-request, connect */ + ret = dat_evd_create (test_ptr->ia_handle, + test_ptr->evd_length, + test_ptr->cno_handle, + DAT_EVD_DTO_FLAG, + &test_ptr->recv_evd_hdl); /* recv */ + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("Test[" F64x "]: dat_evd_create (recv) error: %s\n", + (DAT_UVERYLONG)test_ptr->base_port, DT_RetToString (ret)); + test_ptr->recv_evd_hdl = DAT_HANDLE_NULL; + goto test_failure; + } + + ret = dat_evd_create (test_ptr->ia_handle, + test_ptr->evd_length, + test_ptr->cno_handle, + DAT_EVD_DTO_FLAG | DAT_EVD_RMR_BIND_FLAG, + &test_ptr->reqt_evd_hdl); /* request + rmr bind */ + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("Test[" F64x "]: dat_evd_create (request) error: %s\n", + (DAT_UVERYLONG)test_ptr->base_port, DT_RetToString (ret)); + test_ptr->reqt_evd_hdl = DAT_HANDLE_NULL; + goto test_failure; + } + + if (pt_ptr->local_is_server) + { + /* Client-side doesn't need CR events */ + ret = dat_evd_create (test_ptr->ia_handle, + test_ptr->evd_length, + DAT_HANDLE_NULL, + DAT_EVD_CR_FLAG, + &test_ptr->creq_evd_hdl); /* cr */ + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("Test[" F64x "]: dat_evd_create (cr) error: %s\n", + (DAT_UVERYLONG)test_ptr->base_port, DT_RetToString (ret)); + test_ptr->creq_evd_hdl = DAT_HANDLE_NULL; + goto test_failure; + } + } + + ret = dat_evd_create (test_ptr->ia_handle, + test_ptr->evd_length, + DAT_HANDLE_NULL, + DAT_EVD_CONNECTION_FLAG, + &test_ptr->conn_evd_hdl); /* conn */ + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("Test[" F64x "]: dat_evd_create (conn) error: %s\n", + (DAT_UVERYLONG)test_ptr->base_port, DT_RetToString (ret)); + test_ptr->conn_evd_hdl = DAT_HANDLE_NULL; + goto test_failure; + } + + /* Allocate per-EP data */ + test_ptr->ep_context = (Ep_Context_t *) + DT_MemListAlloc (pt_ptr, + "transaction_test", + EPCONTEXT, + test_ptr->cmd->eps_per_thread + * sizeof (Ep_Context_t)); + if (!test_ptr->ep_context) + { + DT_Mdep_printf ("Test[" F64x "]: no memory for EP context\n", + (DAT_UVERYLONG)test_ptr->base_port); + goto test_failure; + } + + /* + * Set up the per-EP contexts: + * create the EP + * allocate buffers for remote memory info exchange + * post the receive buffers + * connect + * set up buffers and remote memory info + * send across our info + * recv the other side's info and extract what we need + */ + for (i = 0; i < test_ptr->cmd->eps_per_thread; i++) + { + DAT_EP_ATTR ep_attr; + DAT_UINT32 buff_size = MAX_OPS * sizeof (RemoteMemoryInfo); + + /* + * Adjust default EP attributes to fit the requested test. + * This is simplistic; in that we don't count ops of each + * type and direction, checking EP limits. We just try to + * be sure the EP's WQs are large enough. The "+2" is for + * the RemoteMemInfo and Sync receive buffers. + */ + ep_attr = pt_ptr->ep_attr; + if (ep_attr.max_recv_dtos < (DAT_COUNT)test_ptr->cmd->num_ops + 2) + { + ep_attr.max_recv_dtos = (DAT_COUNT)test_ptr->cmd->num_ops + 2; + } + if (ep_attr.max_request_dtos < (DAT_COUNT)test_ptr->cmd->num_ops + 2) + { + ep_attr.max_request_dtos = test_ptr->cmd->num_ops + 2; + } + + /* Create EP */ + ret = dat_ep_create (test_ptr->ia_handle, /* IA */ + test_ptr->pz_handle, /* PZ */ + test_ptr->recv_evd_hdl, /* recv */ + test_ptr->reqt_evd_hdl, /* request */ + test_ptr->conn_evd_hdl, /* connect */ + &ep_attr, /* EP attrs */ + &test_ptr->ep_context[i].ep_handle); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("Test[" F64x "]: dat_ep_create #%d error: %s\n", + (DAT_UVERYLONG)test_ptr->base_port, i, DT_RetToString (ret)); + test_ptr->ep_context[i].ep_handle = DAT_HANDLE_NULL; + goto test_failure; + } + + /* + * Allocate a buffer pool so we can exchange the + * remote memory info and initialize. + */ + test_ptr->ep_context[i].bp = DT_BpoolAlloc (pt_ptr, + test_ptr->ia_handle, + test_ptr->pz_handle, + test_ptr->ep_context[i].ep_handle, + DAT_HANDLE_NULL, /* rmr */ + buff_size, + 4, + DAT_OPTIMAL_ALIGNMENT, + false, + false); + if (!test_ptr->ep_context[i].bp) + { + DT_Mdep_printf ("Test[" F64x "]: no memory for remote memory buffers\n", + (DAT_UVERYLONG)test_ptr->base_port); + goto test_failure; + } + + DT_Mdep_spew (3, ("0: RMI_SEND %p\n", (DAT_PVOID) DT_Bpool_GetBuffer ( + test_ptr->ep_context[i].bp, 0))); + DT_Mdep_spew (3, ("1: RMI_RECV %p\n", (DAT_PVOID) DT_Bpool_GetBuffer ( + test_ptr->ep_context[i].bp, 1))); + DT_Mdep_spew (3, ("2: SYNC_SEND %p\n", (DAT_PVOID) DT_Bpool_GetBuffer ( + test_ptr->ep_context[i].bp, 2))); + DT_Mdep_spew (3, ("3: SYNC_RECV %p\n", (DAT_PVOID) DT_Bpool_GetBuffer ( + test_ptr->ep_context[i].bp, 3))); + + /* + * Post recv and sync buffers + */ + if (!DT_post_recv_buffer ( test_ptr->ep_context[i].ep_handle, + test_ptr->ep_context[i].bp, + RMI_RECV_BUFFER_ID, + buff_size)) + { + /* error message printed by DT_post_recv_buffer */ + goto test_failure; + } + if (!DT_post_recv_buffer ( test_ptr->ep_context[i].ep_handle, + test_ptr->ep_context[i].bp, + SYNC_RECV_BUFFER_ID, + SYNC_BUFF_SIZE)) + { + /* error message printed by DT_post_recv_buffer */ + goto test_failure; + } + + /* + * Establish the connection + */ + test_ptr->ep_context[i].ia_port = test_ptr->base_port + i; + + if (pt_ptr->local_is_server) + { + if (test_ptr->cmd->use_rsp) + { + /* + * Server - create a single-use RSP and + * await a connection for this EP + */ + + ret = dat_rsp_create (test_ptr->ia_handle, + test_ptr->ep_context[i].ia_port, + test_ptr->ep_context[i].ep_handle, + test_ptr->creq_evd_hdl, + &test_ptr->ep_context[i].rsp_handle); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("Test[" F64x "]: dat_rsp_create #%d error: %s\n", + (DAT_UVERYLONG)test_ptr->base_port, i, DT_RetToString (ret)); + goto test_failure; + } + } + else + { + ret = dat_psp_create (test_ptr->ia_handle, + test_ptr->ep_context[i].ia_port, + test_ptr->creq_evd_hdl, + DAT_PSP_CONSUMER_FLAG, + &test_ptr->ep_context[i].psp_handle); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("Test[" F64x "]: dat_psp_create #%d error: %s\n", + (DAT_UVERYLONG)test_ptr->base_port, i, DT_RetToString (ret)); + goto test_failure; + } + + DT_Mdep_debug (("Server[" F64x "]: Listen #%d on PSP port 0x" F64x "\n", + (DAT_UVERYLONG)test_ptr->base_port, i, + (DAT_UVERYLONG)test_ptr->ep_context[i].ia_port)); + } + } + } + + /* Here's where we tell the server process that this thread is + * ready to wait for connection requests from the remote end. + * Modify the synch wait semantics at your own risk - if these + * signals and waits aren't here, there will be chronic + * connection rejection timing problems. + */ + if (pt_ptr->local_is_server) + { + DT_Mdep_Lock (&pt_ptr->Thread_counter_lock); + pt_ptr->Countdown_Counter--; + /* Deliberate pre-decrement. Post decrement won't + * work here, so don't do it. + */ + if (pt_ptr->Countdown_Counter <= 0 ) + { + DT_Mdep_wait_object_wakeup(&pt_ptr->synch_wait_object); + } + + DT_Mdep_Unlock (&pt_ptr->Thread_counter_lock); + } + + for (i = 0; i < test_ptr->cmd->eps_per_thread; i++) + { + DAT_UINT32 buff_size = MAX_OPS * sizeof (RemoteMemoryInfo); + RemoteMemoryInfo *RemoteMemInfo; + DAT_DTO_COMPLETION_EVENT_DATA dto_stat; + DAT_CR_ARRIVAL_EVENT_DATA cr_stat; + DAT_CR_HANDLE cr_handle; + + /* + * Establish the connection + */ + + if (pt_ptr->local_is_server) + { + DAT_CR_PARAM cr_param; + + if (test_ptr->cmd->use_rsp) + { + + /* wait for the connection request */ + if (!DT_cr_event_wait (test_ptr->creq_evd_hdl, &cr_stat) || + !DT_cr_check ( &cr_stat, + test_ptr->ep_context[i].rsp_handle, + test_ptr->ep_context[i].ia_port, + &cr_handle, + "Server") ) + { + goto test_failure; + } + + ret = dat_cr_query (cr_handle, + DAT_CR_FIELD_ALL, + &cr_param); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("Test[" F64x "]: dat_cr_query #%d error:(%x) %s\n", + (DAT_UVERYLONG)test_ptr->base_port, i, ret, DT_RetToString (ret)); + } + else + { + if ( cr_param.private_data_size == 0 || + strncmp((char *)cr_param.private_data, + private_data_str, + cr_param.private_data_size) != 0 ) + { + DT_Mdep_printf ("--Private Data mismatch!\n"); + } + else + { + DT_Mdep_debug ( ("--Private Data: %d: <%s>\n", + cr_param.private_data_size, + (char *)cr_param.private_data) ); + } + } + + /* what, me query? just try to accept the connection */ + ret = dat_cr_accept (cr_handle, + 0, /* NULL for RSP */ + 0, (DAT_PVOID)0 /* no private data */ ); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("Test[" F64x "]: dat_cr_accept #%d error: %s\n", + (DAT_UVERYLONG)test_ptr->base_port, i, DT_RetToString (ret)); + /* cr_handle consumed on failure */ + goto test_failure; + } + + /* wait for DAT_CONNECTION_EVENT_ESTABLISHED */ + if (!DT_conn_event_wait ( test_ptr->ep_context[i].ep_handle, + test_ptr->conn_evd_hdl, + &event_num)) + { + /* error message printed by DT_conn_event_wait */ + goto test_failure; + } + /* throw away single-use PSP */ + ret = dat_rsp_free (test_ptr->ep_context[i].rsp_handle); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("Test[" F64x "]: dat_rsp_free #%d error: %s\n", + (DAT_UVERYLONG)test_ptr->base_port, i, DT_RetToString (ret)); + goto test_failure; + } + + } + else + { + /* + * Server - use a short-lived PSP instead of an RSP + */ + /* wait for a connection request */ + if (!DT_cr_event_wait (test_ptr->creq_evd_hdl, + &cr_stat) ) + { + DT_Mdep_printf ("Test[" F64x "]: dat_psp_create #%d error: %s\n", + (DAT_UVERYLONG)test_ptr->base_port, i, DT_RetToString (ret)); + goto test_failure; + } + + if ( !DT_cr_check ( &cr_stat, + test_ptr->ep_context[i].psp_handle, + test_ptr->ep_context[i].ia_port, + &cr_handle, + "Server") ) + { + goto test_failure; + } + + ret = dat_cr_query (cr_handle, + DAT_CR_FIELD_ALL, + &cr_param); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("Test[" F64x "]: dat_cr_query #%d error: %s\n", + (DAT_UVERYLONG)test_ptr->base_port, i, DT_RetToString (ret)); + } + else + { + if ( cr_param.private_data_size == 0 || + strncmp((char *)cr_param.private_data, + private_data_str, + cr_param.private_data_size) != 0 ) + { + DT_Mdep_printf ("--Private Data mismatch!\n"); + } + else + { + DT_Mdep_debug ( ("--Private Data: %d: <%s>\n", + cr_param.private_data_size, + (char *)cr_param.private_data) ); + } + } + + + /* what, me query? just try to accept the connection */ + ret = dat_cr_accept (cr_handle, + test_ptr->ep_context[i].ep_handle, + 0, (DAT_PVOID)0 /* no private data */ ); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("Test[" F64x "]: dat_cr_accept #%d error: %s\n", + (DAT_UVERYLONG)test_ptr->base_port, i, DT_RetToString (ret)); + /* cr_handle consumed on failure */ + (void) dat_psp_free (test_ptr->ep_context[i].psp_handle); + goto test_failure; + } + + /* wait for DAT_CONNECTION_EVENT_ESTABLISHED */ + if (!DT_conn_event_wait ( test_ptr->ep_context[i].ep_handle, + test_ptr->conn_evd_hdl, + &event_num)) + { + /* error message printed by DT_cr_event_wait */ + (void) dat_psp_free (&test_ptr->ep_context[i].psp_handle); + goto test_failure; + } + + /* throw away single-use PSP */ + ret = dat_psp_free (test_ptr->ep_context[i].psp_handle); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("Test[" F64x "]: dat_psp_free #%d error: %s\n", + (DAT_UVERYLONG)test_ptr->base_port, i, DT_RetToString (ret)); + goto test_failure; + } + } /* end short-lived PSP */ + + DT_Mdep_debug (("Server[" F64x "]: Accept #%d on port 0x" F64x "\n", + (DAT_UVERYLONG)test_ptr->base_port, i, + (DAT_UVERYLONG)test_ptr->ep_context[i].ia_port)); + } + else + { + /* + * Client - connect + */ + unsigned int retry_cnt = 0; + DAT_UINT32 buff_size = MAX_OPS * sizeof (RemoteMemoryInfo); + + DT_Mdep_debug (("Client[" F64x "]: Connect #%d on port 0x" F64x "\n", + (DAT_UVERYLONG)test_ptr->base_port, i, + (DAT_UVERYLONG)test_ptr->ep_context[i].ia_port)); + +#ifdef CM_BUSTED + /***** XXX Chill out a bit to give the kludged CM a chance ... + *****/DT_Mdep_Sleep (5000); +#endif + +retry: + ret = dat_ep_connect (test_ptr->ep_context[i].ep_handle, + test_ptr->remote_ia_addr, + test_ptr->ep_context[i].ia_port, + DAT_TIMEOUT_INFINITE, + (DAT_COUNT)strlen(private_data_str),private_data_str, + /* 0, (DAT_PVOID) 0, */ /* no private data */ + pt_ptr->Params.ReliabilityLevel, + DAT_CONNECT_DEFAULT_FLAG); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("Test[" F64x "]: dat_ep_connect #%d error: %s (0x%x)\n", + (DAT_UVERYLONG)test_ptr->base_port, i, DT_RetToString (ret), ret); + goto test_failure; + } + + /* wait for DAT_CONNECTION_EVENT_ESTABLISHED */ + if (!DT_conn_event_wait ( test_ptr->ep_context[i].ep_handle, + test_ptr->conn_evd_hdl, + &event_num)) + { + /* error message printed by DT_cr_event_wait */ + if ( event_num == DAT_CONNECTION_EVENT_PEER_REJECTED ) + { + DT_Mdep_Sleep (1000); + /* + * See if any buffers were flushed as a result of + * the REJECT; clean them up and repost if so + */ + { + DAT_EVENT event; + DAT_COUNT drained = 0; + + dat_ep_reset (test_ptr->ep_context[i].ep_handle); + do + { + ret = dat_evd_dequeue ( test_ptr->recv_evd_hdl, + &event); + drained++; + } while (ret != DAT_QUEUE_EMPTY); + + if (drained > 1) + { + /* + * Post recv and sync buffers + */ + if (!DT_post_recv_buffer ( test_ptr->ep_context[i].ep_handle, + test_ptr->ep_context[i].bp, + RMI_RECV_BUFFER_ID, + buff_size)) + { + /* error message printed by DT_post_recv_buffer */ + goto test_failure; + } + if (!DT_post_recv_buffer ( test_ptr->ep_context[i].ep_handle, + test_ptr->ep_context[i].bp, + SYNC_RECV_BUFFER_ID, + SYNC_BUFF_SIZE)) + { + /* error message printed by DT_post_recv_buffer */ + goto test_failure; + } + } + } + DT_Mdep_printf ("Client[" F64x "]: retrying connection...\n", + (DAT_UVERYLONG)test_ptr->base_port); + retry_cnt++; + if (retry_cnt < MAX_CONN_RETRY) + { + goto retry; + } + } + /* error message printed by DT_cr_event_wait */ + goto test_failure; + } + + DT_Mdep_debug (("Client[" F64x "]: Got Connection #%d\n", + (DAT_UVERYLONG)test_ptr->base_port, i)); + } + +#ifdef CM_BUSTED + /***** XXX Chill out a bit to give the kludged CM a chance ... + *****/DT_Mdep_Sleep (5000); +#endif + + /* + * Fill in the test_ptr with relevant command info + */ + for (j = 0; j < test_ptr->cmd->num_ops; j++) + { + test_ptr->ep_context[i].op[j].server_initiated + = test_ptr->cmd->op[j].server_initiated; + test_ptr->ep_context[i].op[j].transfer_type + = test_ptr->cmd->op[j].transfer_type; + test_ptr->ep_context[i].op[j].num_segs + = test_ptr->cmd->op[j].num_segs; + test_ptr->ep_context[i].op[j].seg_size + = test_ptr->cmd->op[j].seg_size; + test_ptr->ep_context[i].op[j].reap_send_on_recv + = test_ptr->cmd->op[j].reap_send_on_recv; + } + + /* + * Exchange remote memory info: If we're going to participate + * in an RDMA, we need to allocate memory buffers and advertise + * them to the other side. + */ + for (j = 0; j < test_ptr->cmd->num_ops; j++) + { + DAT_BOOLEAN us; + + us = (pt_ptr->local_is_server && + test_ptr->ep_context[i].op[j].server_initiated) || + (!pt_ptr->local_is_server && + !test_ptr->ep_context[i].op[j].server_initiated); + + test_ptr->ep_context[i].op[j].Rdma_Context = (DAT_RMR_CONTEXT) 0; + test_ptr->ep_context[i].op[j].Rdma_Address = (DAT_PVOID) 0; + + switch (test_ptr->ep_context[i].op[j].transfer_type) + { + case RDMA_READ: + { + test_ptr->ep_context[i].op[j].bp = + DT_BpoolAlloc (pt_ptr, + test_ptr->ia_handle, + test_ptr->pz_handle, + test_ptr->ep_context[i].ep_handle, + test_ptr->reqt_evd_hdl, + test_ptr->ep_context[i].op[j].seg_size, + test_ptr->ep_context[i].op[j].num_segs, + DAT_OPTIMAL_ALIGNMENT, + false, + !us ? true : false); + if (!test_ptr->ep_context[i].op[j].bp) + { + DT_Mdep_printf ("Test[" F64x "]: no memory for buffers (RDMA/RD)\n", + (DAT_UVERYLONG)test_ptr->base_port); + goto test_failure; + } + if (!us) + { + test_ptr->ep_context[i].op[j].Rdma_Context = + DT_Bpool_GetRMR (test_ptr->ep_context[i].op[j].bp, 0); + test_ptr->ep_context[i].op[j].Rdma_Address = + (DAT_PVOID) (uintptr_t) + DT_Bpool_GetBuffer (test_ptr->ep_context[i].op[j].bp, + 0); + DT_Mdep_spew (3, ("not-us: RDMA/RD [ va=%p, ctxt=%x ]\n", + test_ptr->ep_context[i].op[j].Rdma_Address, + test_ptr->ep_context[i].op[j].Rdma_Context)); + } + break; + } + + case RDMA_WRITE: + { + test_ptr->ep_context[i].op[j].bp = + DT_BpoolAlloc (pt_ptr, + test_ptr->ia_handle, + test_ptr->pz_handle, + test_ptr->ep_context[i].ep_handle, + test_ptr->reqt_evd_hdl, + test_ptr->ep_context[i].op[j].seg_size, + test_ptr->ep_context[i].op[j].num_segs, + DAT_OPTIMAL_ALIGNMENT, + !us ? true : false, + false); + if (!test_ptr->ep_context[i].op[j].bp) + { + DT_Mdep_printf ("Test[" F64x "]: no memory for buffers (RDMA/WR)\n", + (DAT_UVERYLONG)test_ptr->base_port); + goto test_failure; + } + if (!us) + { + test_ptr->ep_context[i].op[j].Rdma_Context = + DT_Bpool_GetRMR (test_ptr->ep_context[i].op[j].bp, 0); + test_ptr->ep_context[i].op[j].Rdma_Address = + (DAT_PVOID) (uintptr_t) + DT_Bpool_GetBuffer (test_ptr->ep_context[i].op[j].bp, + 0); + DT_Mdep_spew (3, ("not-us: RDMA/WR [ va=%p, ctxt=%x ]\n", + test_ptr->ep_context[i].op[j].Rdma_Address, + test_ptr->ep_context[i].op[j].Rdma_Context)); + } + break; + } + + case SEND_RECV: + { + test_ptr->ep_context[i].op[j].bp = + DT_BpoolAlloc (pt_ptr, + test_ptr->ia_handle, + test_ptr->pz_handle, + test_ptr->ep_context[i].ep_handle, + DAT_HANDLE_NULL, /* rmr */ + test_ptr->ep_context[i].op[j].seg_size, + test_ptr->ep_context[i].op[j].num_segs, + DAT_OPTIMAL_ALIGNMENT, + false, + false); + if (!test_ptr->ep_context[i].op[j].bp) + { + DT_Mdep_printf ("Test[" F64x "]: no memory for buffers (S/R)\n", + (DAT_UVERYLONG)test_ptr->base_port); + goto test_failure; + } + + DT_Mdep_spew (3, ("%d: S/R [ va=%p ]\n", j, (DAT_PVOID) + DT_Bpool_GetBuffer ( test_ptr->ep_context[i].op[j].bp, 0))); + break; + } + } + } /* end foreach op */ + + /* + * Prep send buffer with memory information + */ + RemoteMemInfo = (RemoteMemoryInfo *) + DT_Bpool_GetBuffer (test_ptr->ep_context[i].bp, + RMI_SEND_BUFFER_ID); + + for (j = 0; j < test_ptr->cmd->num_ops; j++) + { + RemoteMemInfo[j].rmr_context = + test_ptr->ep_context[i].op[j].Rdma_Context; + RemoteMemInfo[j].mem_address.as_64 = (DAT_UINT64) 0UL; + RemoteMemInfo[j].mem_address.as_ptr = + test_ptr->ep_context[i].op[j].Rdma_Address; + if (RemoteMemInfo[j].mem_address.as_ptr) + { + DT_Mdep_spew (3, ("RemoteMemInfo[%d] va=" F64x ", ctx=%x\n", + j, + (DAT_UVERYLONG)RemoteMemInfo[j].mem_address.as_64, + RemoteMemInfo[j].rmr_context)); + } + /* + * If the client and server are of different endiannesses, + * we must correct the endianness of the handle and address + * we pass to the other side. The other side cannot (and + * better not) interpret these values. + */ + if (DT_local_is_little_endian != test_ptr->remote_is_little_endian) + { + RemoteMemInfo[j].rmr_context = + DT_EndianMemHandle (RemoteMemInfo[j].rmr_context); + RemoteMemInfo[j].mem_address.as_64 = + DT_EndianMemAddress (RemoteMemInfo[j].mem_address.as_64); + } + } /* end foreach op */ + + /* + * Send our memory info (synchronously) + */ + DT_Mdep_debug (("Test[" F64x "]: Sending %s Memory Info\n", + (DAT_UVERYLONG)test_ptr->base_port, + test_ptr->is_server ? "Server" : "Client")); + + /* post the send buffer */ + if (!DT_post_send_buffer (test_ptr->ep_context[i].ep_handle, + test_ptr->ep_context[i].bp, + RMI_SEND_BUFFER_ID, + buff_size)) + { + /* error message printed by DT_post_send_buffer */ + goto test_failure; + } + /* reap the send and verify it */ + dto_cookie.as_64 = LZERO; + dto_cookie.as_ptr = + (DAT_PVOID) DT_Bpool_GetBuffer ( + test_ptr->ep_context[i].bp, + RMI_SEND_BUFFER_ID); + if (!DT_dto_event_wait (test_ptr->reqt_evd_hdl, &dto_stat) || + !DT_dto_check ( &dto_stat, + test_ptr->ep_context[i].ep_handle, + buff_size, + dto_cookie, + test_ptr->is_server ? "Client_Mem_Info_Send" + : "Server_Mem_Info_Send")) + { + goto test_failure; + } + + /* + * Recv the other side's info + */ + DT_Mdep_debug (("Test[" F64x "]: Waiting for %s Memory Info\n", + (DAT_UVERYLONG)test_ptr->base_port, + test_ptr->is_server ? "Client" : "Server")); + dto_cookie.as_64 = LZERO; + dto_cookie.as_ptr = + (DAT_PVOID) DT_Bpool_GetBuffer ( + test_ptr->ep_context[i].bp, + RMI_RECV_BUFFER_ID); + if (!DT_dto_event_wait (test_ptr->recv_evd_hdl, &dto_stat) || + !DT_dto_check ( &dto_stat, + test_ptr->ep_context[i].ep_handle, + buff_size, + dto_cookie, + test_ptr->is_server ? "Client_Mem_Info_Recv" + : "Server_Mem_Info_Recv")) + { + goto test_failure; + } + + /* + * Extract what we need + */ + DT_Mdep_debug (("Test[" F64x "]: Memory Info received \n", + (DAT_UVERYLONG)test_ptr->base_port)); + RemoteMemInfo = (RemoteMemoryInfo *) + DT_Bpool_GetBuffer (test_ptr->ep_context[i].bp, + RMI_RECV_BUFFER_ID); + for (j = 0; j < test_ptr->cmd->num_ops; j++) + { + DAT_BOOLEAN us; + + us = (pt_ptr->local_is_server && + test_ptr->ep_context[i].op[j].server_initiated) || + (!pt_ptr->local_is_server && + !test_ptr->ep_context[i].op[j].server_initiated); + if (us && + (test_ptr->ep_context[i].op[j].transfer_type == RDMA_READ || + test_ptr->ep_context[i].op[j].transfer_type == RDMA_WRITE)) + { + test_ptr->ep_context[i].op[j].Rdma_Context = + RemoteMemInfo[j].rmr_context; + test_ptr->ep_context[i].op[j].Rdma_Address = + RemoteMemInfo[j].mem_address.as_ptr; + DT_Mdep_spew (3, ("Got RemoteMemInfo [ va=%p, ctx=%x ]\n", + test_ptr->ep_context[i].op[j].Rdma_Address, + test_ptr->ep_context[i].op[j].Rdma_Context)); + } + } + } /* end foreach EP context */ + + /* + * Dump out the state of the world if we're debugging + */ + if (test_ptr->cmd->debug) + { + DT_Print_Transaction_Test (test_ptr); + } + + /* + * Finally! Run the test. + */ + success = DT_Transaction_Run (test_ptr); + + /* + * Now clean up and go home + */ +test_failure: + if (test_ptr->ep_context) + { + + /* Foreach EP */ + for (i = 0; i < test_ptr->cmd->eps_per_thread; i++) + { + DAT_EP_HANDLE ep_handle; + + ep_handle = DAT_HANDLE_NULL; + + /* Free the per-op buffers */ + for (j = 0; j < test_ptr->cmd->num_ops; j++) + { + if (test_ptr->ep_context[i].op[j].bp) + { + if (!DT_Bpool_Destroy (pt_ptr, + test_ptr->ep_context[i].op[j].bp)) + { + DT_Mdep_printf ("test[" F64x "]: Warning: Bpool destroy fails\n", + (DAT_UVERYLONG)test_ptr->base_port); + /* carry on trying, regardless */ + } + } + } + + /* Free the remote memory info exchange buffers */ + if (test_ptr->ep_context[i].bp) + { + if (!DT_Bpool_Destroy (pt_ptr, + test_ptr->ep_context[i].bp)) + { + DT_Mdep_printf ("Test[" F64x "]: Warning: Bpool destroy fails\n", + (DAT_UVERYLONG)test_ptr->base_port); + /* carry on trying, regardless */ + } + } + + /* + * Disconnect -- we may have left recv buffers posted, if we + * bailed out mid-setup, or ran to completion + * normally, so we use abrupt closure. + */ + if (test_ptr->ep_context[i].ep_handle) + { + ret = dat_ep_disconnect (test_ptr->ep_context[i].ep_handle, + DAT_CLOSE_ABRUPT_FLAG); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("Test[" F64x "]: Warning: dat_ep_disconnect (%s) " + "#%d error %s\n", + (DAT_UVERYLONG)test_ptr->base_port, + success ? "graceful" : "abrupt", + i, DT_RetToString (ret)); + /* carry on trying, regardless */ + } + } + + /* + * Wait on each of the outstanding EP handles. Some of them + * may be disconnected by the remote side, we are racing + * here. + */ + + if ( success ) /* Ensure DT_Transaction_Run did not return error otherwise may get stuck waiting for disconnect event*/ + { + if (!DT_disco_event_wait ( test_ptr->conn_evd_hdl, + &ep_handle)) + { + DT_Mdep_printf ("Test[" F64x "]: bad disconnect event\n", + (DAT_UVERYLONG)test_ptr->base_port); + } + else + { + /* + * We have successfully obtained a completed EP. We are + * racing with the remote node on disconnects, so we + * don't know which EP this is. Run the list and + * remove it so we don't disconnect a disconnected EP + */ + for (j = 0; j < test_ptr->cmd->eps_per_thread; j++) + { + if ( test_ptr->ep_context[j].ep_handle == ep_handle ) + { + test_ptr->ep_context[j].ep_handle = NULL; + } + } + } + } else /* !success - QP may be in error state */ + ep_handle = test_ptr->ep_context[i].ep_handle; + + /* + * Free the handle returned by the disconnect event. + * With multiple EPs, it may not be the EP we just + * disconnected as we are racing with the remote side + * disconnects. + */ + if ( DAT_HANDLE_NULL != ep_handle) + { + DAT_EVENT event; + /* + * Drain off outstanding DTOs that may have been + * generated by racing disconnects + */ + do + { + ret = dat_evd_dequeue ( test_ptr->recv_evd_hdl, + &event); + } while ( DAT_GET_TYPE(ret) != DAT_QUEUE_EMPTY ); + /* Destroy the EP */ + ret = dat_ep_free (ep_handle); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("Test[" F64x "]: dat_ep_free #%d error: %s\n", + (DAT_UVERYLONG)test_ptr->base_port, i, DT_RetToString (ret)); + /* carry on trying, regardless */ + } + } + } /* end foreach per-EP context */ + + DT_MemListFree (pt_ptr, test_ptr->ep_context); + } + + /* clean up the EVDs */ + if (test_ptr->conn_evd_hdl) + { + ret = dat_evd_free (test_ptr->conn_evd_hdl); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("Test[" F64x "]: dat_evd_free (conn) error: %s\n", + (DAT_UVERYLONG)test_ptr->base_port, DT_RetToString (ret)); + /* fall through, keep trying */ + } + } + if (pt_ptr->local_is_server) + { + if (test_ptr->creq_evd_hdl) + { + ret = dat_evd_free (test_ptr->creq_evd_hdl); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("Test[" F64x "]: dat_evd_free (creq) error: %s\n", + (DAT_UVERYLONG)test_ptr->base_port, DT_RetToString (ret)); + /* fall through, keep trying */ + } + } + } + if (test_ptr->reqt_evd_hdl) + { + ret = dat_evd_free (test_ptr->reqt_evd_hdl); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("Test[" F64x "]: dat_evd_free (reqt) error: %s\n", + (DAT_UVERYLONG)test_ptr->base_port, DT_RetToString (ret)); + /* fall through, keep trying */ + } + } + if (test_ptr->recv_evd_hdl) + { + ret = dat_evd_free (test_ptr->recv_evd_hdl); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("Test[" F64x "]: dat_evd_free (recv) error: %s\n", + (DAT_UVERYLONG)test_ptr->base_port, DT_RetToString (ret)); + /* fall through, keep trying */ + } + } + + /* clean up the CNO */ + if (test_ptr->cmd->use_cno && test_ptr->cno_handle) + { + ret = dat_cno_free (test_ptr->cno_handle); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("Test[" F64x "]: dat_cno_free error: %s\n", + (DAT_UVERYLONG)test_ptr->base_port, DT_RetToString (ret)); + /* fall through, keep trying */ + } + } + + /* clean up the PZ */ + if (test_ptr->pz_handle) + { + ret = dat_pz_free (test_ptr->pz_handle); + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("Test[" F64x "]: dat_pz_free error: %s\n", + (DAT_UVERYLONG)test_ptr->base_port, DT_RetToString (ret)); + /* fall through, keep trying */ + } + } + + DT_Mdep_debug (("Test[" F64x "]: cleanup is done\n", (DAT_UVERYLONG)test_ptr->base_port)); + DT_MemListFree ( pt_ptr, test_ptr ); + DT_Thread_Destroy ( thread, pt_ptr ); + DT_Mdep_Thread_Detach ( DT_Mdep_Thread_SELF() ); /* AMM */ + DT_Mdep_Thread_EXIT(NULL); /* AMM */ +} + + +/* ----------------------------------------------------------------------- + * The actual performance test + */ +bool +DT_Transaction_Run (Transaction_Test_t * test_ptr) +{ + unsigned int op; + unsigned int iteration; + int bytes; + bool ours; + bool success = false; + bool repost_recv; + unsigned int i; + + /* pre-post all receive buffers */ + for (op = 0; op < test_ptr->cmd->num_ops; op++) + { + /* if it is a SEND/RECV, we must post receive buffers */ + if (test_ptr->ep_context[0].op[op].transfer_type == SEND_RECV) + { + ours = (test_ptr->is_server == + test_ptr->ep_context[0].op[op].server_initiated); + if (!ours) + { + if (!DT_handle_post_recv_buf (test_ptr->ep_context, + test_ptr->cmd->eps_per_thread, + op)) + { + goto bail; + } + } + } + } + + /* initialize data if we are validating it */ + if (test_ptr->cmd->validate) + { + DT_Transaction_Validation_Fill (test_ptr, 0); + } + + /* + * Now that we've posted our receive buffers... + * synchronize with the other side. + */ + DT_Mdep_debug (("Test[" F64x "]: Synchronize with the other side\n", + (DAT_UVERYLONG)test_ptr->base_port)); + + + /* + * Each server thread sends a sync message to the corresponding + * client thread. All clients wait until all server threads + * have sent their sync messages. Then all clients send + * sync message. + * + * Since all of the events are directed to the same EVD, + * we do not use DT_dto_check(.) to verify the attributes + * of the sync message event. DT_dto_check(.) requires the + * comsumer to pass the expected EP, but we do not know + * what to expect. DAPL does not guarantee the order of + * completions across EPs. Therfore we only know that + * test_ptr->cmd->eps_per_thread number of completion events + * will be generated but not the order in which they will + * complete. + */ + + if (test_ptr->is_server) + { + /* + * Server + */ + DT_Mdep_debug (("Test[" F64x "]: Send Sync to Client\n", + (DAT_UVERYLONG)test_ptr->base_port)); + for (i = 0; i < test_ptr->cmd->eps_per_thread; i++) + { + if (!DT_post_send_buffer (test_ptr->ep_context[i].ep_handle, + test_ptr->ep_context[i].bp, + SYNC_SEND_BUFFER_ID, + SYNC_BUFF_SIZE)) + { + DT_Mdep_debug (("Test[" F64x "]: Server sync send error\n", + (DAT_UVERYLONG)test_ptr->base_port)); + goto bail; + } + } + for (i = 0; i < test_ptr->cmd->eps_per_thread; i++) + { + DAT_DTO_COMPLETION_EVENT_DATA dto_stat; + + if ( !DT_dto_event_wait (test_ptr->reqt_evd_hdl, &dto_stat) ) + { + DT_Mdep_debug (("Test[" F64x "]: Server sync send error\n", + (DAT_UVERYLONG)test_ptr->base_port)); + + goto bail; + } + } + + DT_Mdep_debug (("Test[" F64x "]: Wait for Sync Message\n", + (DAT_UVERYLONG)test_ptr->base_port)); + for (i = 0; i < test_ptr->cmd->eps_per_thread; i++) + { + DAT_DTO_COMPLETION_EVENT_DATA dto_stat; + + if ( !DT_dto_event_wait (test_ptr->recv_evd_hdl, &dto_stat) ) + { + DT_Mdep_debug (("Test[" F64x "]: Server sync recv error\n", + (DAT_UVERYLONG)test_ptr->base_port)); + goto bail; + } + } + } + else + { + /* + * Client + */ + DT_Mdep_debug (("Test[" F64x "]: Wait for Sync Message\n", + (DAT_UVERYLONG)test_ptr->base_port)); + for (i = 0; i < test_ptr->cmd->eps_per_thread; i++) + { + DAT_DTO_COMPLETION_EVENT_DATA dto_stat; + + if ( !DT_dto_event_wait (test_ptr->recv_evd_hdl, &dto_stat) ) + { + DT_Mdep_debug (("Test[" F64x "]: Client sync recv error\n", + (DAT_UVERYLONG)test_ptr->base_port)); + goto bail; + } + DT_transaction_stats_set_ready (&test_ptr->pt_ptr->Client_Stats); + } + + /* check if it is time for client to send sync */ + if (!DT_transaction_stats_wait_for_all (&test_ptr->pt_ptr->Client_Stats)) + { + goto bail; + } + + DT_Mdep_debug (("Test[" F64x "]: Send Sync Msg\n", (DAT_UVERYLONG)test_ptr->base_port)); + for (i = 0; i < test_ptr->cmd->eps_per_thread; i++) + { + if (!DT_post_send_buffer (test_ptr->ep_context[i].ep_handle, + test_ptr->ep_context[i].bp, + SYNC_SEND_BUFFER_ID, + SYNC_BUFF_SIZE)) + { + DT_Mdep_debug (("Test[" F64x "]: Client sync send error\n", + (DAT_UVERYLONG)test_ptr->base_port)); + goto bail; + } + } + for (i = 0; i < test_ptr->cmd->eps_per_thread; i++) + { + DAT_DTO_COMPLETION_EVENT_DATA dto_stat; + + if ( !DT_dto_event_wait (test_ptr->reqt_evd_hdl, &dto_stat) ) + { + goto bail; + } + } + } + + /* + * Get to work ... + */ + DT_Mdep_debug (("Test[" F64x "]: Begin...\n", (DAT_UVERYLONG)test_ptr->base_port)); + test_ptr->stats.start_time = DT_Mdep_GetTime (); + + for (iteration = 0; + iteration < test_ptr->cmd->num_iterations; + iteration++) + { + + DT_Mdep_debug (("iteration: %d\n", iteration)); + + /* repost unless this is the last iteration */ + repost_recv = (iteration + 1 != test_ptr->cmd->num_iterations); + + for (op = 0; op < test_ptr->cmd->num_ops; op++) + { + ours = (test_ptr->is_server == + test_ptr->ep_context[0].op[op].server_initiated); + bytes = (test_ptr->ep_context[0].op[op].seg_size * + test_ptr->ep_context[0].op[op].num_segs * + test_ptr->cmd->eps_per_thread); + + switch (test_ptr->ep_context[0].op[op].transfer_type) + { + case RDMA_READ: + { + test_ptr->stats.stat_bytes_rdma_read += bytes; + if (ours) + { + DT_Mdep_debug (("Test[" F64x "]: RdmaRead [%d]\n", + (DAT_UVERYLONG)test_ptr->base_port, + op)); + if (!DT_handle_rdma_op (test_ptr->ep_context, + test_ptr->reqt_evd_hdl, + test_ptr->cmd->eps_per_thread, + RDMA_READ, + op, + test_ptr->cmd->poll)) + { + DT_Mdep_printf ("Test[" F64x "]: RdmaRead error[%d]\n", + (DAT_UVERYLONG)test_ptr->base_port, op); + goto bail; + } + } + break; + } + + case RDMA_WRITE: + { + test_ptr->stats.stat_bytes_rdma_write += bytes; + if (ours) + { + DT_Mdep_debug (("Test[" F64x "]: RdmaWrite [%d]\n", + (DAT_UVERYLONG)test_ptr->base_port, + op)); + if (!DT_handle_rdma_op (test_ptr->ep_context, + test_ptr->reqt_evd_hdl, + test_ptr->cmd->eps_per_thread, + RDMA_WRITE, + op, + test_ptr->cmd->poll)) + { + DT_Mdep_printf ("Test[" F64x "]: RdmaWrite error[%d]\n", + (DAT_UVERYLONG)test_ptr->base_port, op); + goto bail; + } + } + break; + } + + case SEND_RECV: + { + if (ours) + { + test_ptr->stats.stat_bytes_send += bytes; + DT_Mdep_debug (("Test[" F64x "]: postsend [%d] \n", + (DAT_UVERYLONG)test_ptr->base_port, op)); + /* send data */ + if (!DT_handle_send_op (test_ptr->ep_context, + test_ptr->reqt_evd_hdl, + test_ptr->cmd->eps_per_thread, + op, + test_ptr->cmd->poll)) + { + goto bail; + } + } + else + { + test_ptr->stats.stat_bytes_recv += bytes; + DT_Mdep_debug (("Test[" F64x "]: RecvWait and Re-Post [%d] \n", + (DAT_UVERYLONG)test_ptr->base_port, op)); + + if (!DT_handle_recv_op (test_ptr->ep_context, + test_ptr->recv_evd_hdl, + test_ptr->reqt_evd_hdl, + test_ptr->cmd->eps_per_thread, + op, + test_ptr->cmd->poll, + repost_recv)) + { + goto bail; + } + } + + /* now before going on, is it time to validate? */ + if (test_ptr->cmd->validate) + { + if (!test_ptr->pt_ptr->local_is_server) /* CLIENT */ + { + /* the client validates on the third to last op */ + if (op == test_ptr->cmd->num_ops - 3) + { + if (!DT_Transaction_Validation_Check (test_ptr, + iteration)) + { + goto bail; + } + DT_Transaction_Validation_Fill (test_ptr, + iteration + 1); + } + } + else /* SERVER */ + { + /* the server validates on the second to last op */ + if (op == test_ptr->cmd->num_ops - 2) + { + if (!DT_Transaction_Validation_Check (test_ptr, + iteration)) + { + goto bail; + } + DT_Transaction_Validation_Fill (test_ptr, + iteration + 1); + } + } + } /* end validate */ + break; + } + } /* end switch for transfer type */ + } /* end loop for each op */ + } /* end loop for iteration */ + + /* end time and print stats */ + test_ptr->stats.end_time = DT_Mdep_GetTime (); + if (!test_ptr->pt_ptr->local_is_server) + { + DT_update_transaction_stats (&test_ptr->pt_ptr->Client_Stats, + test_ptr->cmd->eps_per_thread * test_ptr->cmd->num_ops * + test_ptr->cmd->num_iterations, + test_ptr->stats.end_time - test_ptr->stats.start_time, + test_ptr->stats.stat_bytes_send, + test_ptr->stats.stat_bytes_recv, + test_ptr->stats.stat_bytes_rdma_read, + test_ptr->stats.stat_bytes_rdma_write); + } + DT_Mdep_debug (("Test[" F64x "]: End Successfully\n", (DAT_UVERYLONG)test_ptr->base_port)); + success = true; + +bail: + return ( success ); +} + + +/*------------------------------------------------------------------------------ */ +void +DT_Transaction_Validation_Fill ( Transaction_Test_t * test_ptr, + unsigned int iteration) +{ + bool ours; + unsigned int op; + unsigned int i; + unsigned int j; + unsigned int ind; + unsigned char *buff; + + if (iteration >= test_ptr->cmd->num_iterations) + { + return; + } + DT_Mdep_debug (("Test[" F64x "]: FILL Buffers Iteration %d\n", + (DAT_UVERYLONG)test_ptr->base_port, iteration)); + + /* + * fill all but the last three ops, which + * were added to create barriers for data validation + */ + for (ind = 0; ind < test_ptr->cmd->eps_per_thread; ind++) + { + for (op = 0; op < test_ptr->cmd->num_ops - 3; op++) + { + ours = (test_ptr->is_server == + test_ptr->ep_context[ind].op[op].server_initiated); + + switch (test_ptr->ep_context[ind].op[op].transfer_type) + + { + case RDMA_READ: + { + if (!ours) + { + for (i = 0; + i < test_ptr->ep_context[ind].op[op].num_segs; + i++) + { + + buff = DT_Bpool_GetBuffer ( + test_ptr->ep_context[ind].op[op].bp, i); + for (j = 0; + j < test_ptr->ep_context[ind].op[op].seg_size; + j++) + { + /* Avoid using all zero bits the 1st time */ + buff[j] = (iteration + 1) & 0xFF; + } + } + } + break; + } + + case RDMA_WRITE: + { + if (ours) + { + for (i = 0; + i < test_ptr->ep_context[ind].op[op].num_segs; + i++) + { + + buff = DT_Bpool_GetBuffer ( + test_ptr->ep_context[ind].op[op].bp, i); + for (j = 0; + j < test_ptr->ep_context[ind].op[op].seg_size; + j++) + { + /* Avoid using all zero bits the 1st time */ + buff[j] = (iteration + 1) & 0xFF; + } + } + } + break; + } + + case SEND_RECV: + { + if (ours) + { + for (i = 0; + i < test_ptr->ep_context[ind].op[op].num_segs; + i++) + { + + buff = DT_Bpool_GetBuffer ( + test_ptr->ep_context[ind].op[op].bp, + i); + /***** + DT_Mdep_printf( + "\tFill: wq=%d op=%d seg=%d ptr=[%p, %d]\n", + ind, op, i, buff, j); + *****/ + for (j = 0; + j < test_ptr->ep_context[ind].op[op].seg_size; + j++) + { + /* Avoid using all zero bits the 1st time */ + buff[j] = (iteration + 1) & 0xFF; + } + } + } + break; + } + } /* end switch transfer_type */ + } /* end for each op */ + } /* end for each ep per thread */ +} + + +/*------------------------------------------------------------------------------ */ +bool +DT_Transaction_Validation_Check (Transaction_Test_t * test_ptr, + int iteration) +{ + bool ours; + bool success = true; + unsigned int op; + unsigned int i; + unsigned int j; + unsigned int ind; + unsigned char *buff; + unsigned char expect; + unsigned char got; + + DT_Mdep_debug (("Test[" F64x "]: VALIDATE Buffers Iteration %d\n", + (DAT_UVERYLONG)test_ptr->base_port, + iteration)); + + /* + * fill all but the last three ops, which + * were added to create barriers for data validation + */ + for (ind = 0; ind < test_ptr->cmd->eps_per_thread; ind++) + { + for (op = 0; op < test_ptr->cmd->num_ops - 3; op++) + { + ours = (test_ptr->is_server == + test_ptr->ep_context[ind].op[op].server_initiated); + + switch (test_ptr->ep_context[ind].op[op].transfer_type) + { + case RDMA_READ: + { + if (ours) + { + for (i = 0; + i < test_ptr->ep_context[ind].op[op].num_segs; i++) + { + + buff = DT_Bpool_GetBuffer ( + test_ptr->ep_context[ind].op[op].bp, i); + + for (j = 0; + j < test_ptr->ep_context[ind].op[op].seg_size; + j++) + { + + expect = (iteration + 1) & 0xFF; + got = buff[j]; + if (expect != got) + { + DT_Mdep_printf ( + "Test[" F64x "]: Validation Error :: %d\n", + (DAT_UVERYLONG)test_ptr->base_port, + op); + DT_Mdep_printf ( + "Test[" F64x "]: Expected %x Got %x\n", + (DAT_UVERYLONG)test_ptr->base_port, + expect, + got); + DT_Mdep_spew (3, + ("\twq=%d op=%d seg=%d byte=%d ptr=%p\n", + ind, op, i, j, buff)); + success = false; + break; + } + } + } + } + break; + } + + case RDMA_WRITE: + { + if (!ours) + { + for (i = 0; + i < test_ptr->ep_context[ind].op[op].num_segs; + i++) + { + + buff = DT_Bpool_GetBuffer ( + test_ptr->ep_context[ind].op[op].bp, i); + for (j = 0; + j < test_ptr->ep_context[ind].op[op].seg_size; + j++) + { + + expect = (iteration + 1) & 0xFF; + got = buff[j]; + if (expect != got) + { + DT_Mdep_printf ("Test[" F64x "]: Validation Error :: %d\n", + (DAT_UVERYLONG)test_ptr->base_port, + op); + DT_Mdep_printf ("Test[" F64x "]: Expected %x Got %x\n", + (DAT_UVERYLONG)test_ptr->base_port, + expect, + got); + DT_Mdep_spew (3, + ("\twq=%d op=%d seg=%d byte=%d ptr=%p\n", + ind, op, i, j, buff)); + success = false; + break; + } + } + } + } + break; + } + + case SEND_RECV: + { + if (!ours) + { + for (i = 0; + i < test_ptr->ep_context[ind].op[op].num_segs; + i++) + { + + buff = DT_Bpool_GetBuffer ( + test_ptr->ep_context[ind].op[op].bp, i); + DT_Mdep_spew (3, ( + "\tCheck:wq=%d op=%d seg=%d ptr=[%p, %d]\n", + ind, op, i, buff, + test_ptr->ep_context[ind].op[op].seg_size)); + + for (j = 0; + j < test_ptr->ep_context[ind].op[op].seg_size; + j++) + { + + expect = (iteration + 1) & 0xFF; + got = buff[j]; + if (expect != got) + { + DT_Mdep_printf ( + "Test[" F64x "]: Validation Error :: %d\n", + (DAT_UVERYLONG)test_ptr->base_port, + op); + DT_Mdep_printf ("Test[" F64x "]: Expected %x Got %x\n", + (DAT_UVERYLONG)test_ptr->base_port, + expect, + got); + DT_Mdep_spew (3, + ("\twq=%d op=%d seg=%d byte=%d ptr=%p\n", + ind, op, i, j, buff)); + success = false; + break; + } + } + } + } + break; + } + } /* end switch transfer_type */ + } /* end for each op */ + } /* end for each ep per thread */ + + return ( success ); +} + + +/*------------------------------------------------------------------------------ */ +void +DT_Print_Transaction_Test (Transaction_Test_t * test_ptr) +{ + DT_Mdep_printf ("-------------------------------------\n"); + DT_Mdep_printf ("TransTest.is_server : %d\n", + test_ptr->is_server); + DT_Mdep_printf ("TransTest.remote_little_endian : %d\n", + test_ptr->remote_is_little_endian); + DT_Mdep_printf ("TransTest.base_port : " F64x "\n", + (DAT_UVERYLONG)test_ptr->base_port); + DT_Mdep_printf ("TransTest.pz_handle : %p\n", + test_ptr->pz_handle); + /* statistics */ + DT_Mdep_printf ("TransTest.bytes_send : %d\n", + test_ptr->stats.stat_bytes_send); + DT_Mdep_printf ("TransTest.bytes_recv : %d\n", + test_ptr->stats.stat_bytes_recv); + DT_Mdep_printf ("TransTest.bytes_rdma_read : %d\n", + test_ptr->stats.stat_bytes_rdma_read); + DT_Mdep_printf ("TransTest.bytes_rdma_write : %d\n", + test_ptr->stats.stat_bytes_rdma_write); +} + + +/*------------------------------------------------------------------------------ */ +void +DT_Print_Transaction_Stats (Transaction_Test_t * test_ptr) +{ + double time; + double mbytes_send; + double mbytes_recv; + double mbytes_rdma_read; + double mbytes_rdma_write; + int total_ops; + time = (double) (test_ptr->stats.end_time - test_ptr->stats.start_time) / 1000; + mbytes_send = (double) test_ptr->stats.stat_bytes_send / 1024 / 1024; + mbytes_recv = (double) test_ptr->stats.stat_bytes_recv / 1024 / 1024; + mbytes_rdma_read = (double) test_ptr->stats.stat_bytes_rdma_read / 1024 / 1024; + mbytes_rdma_write = (double) test_ptr->stats.stat_bytes_rdma_write / 1024 / 1024; + total_ops = test_ptr->cmd->num_ops * test_ptr->cmd->num_iterations; + + DT_Mdep_printf ("Test[: " F64x "] ---- Stats ----\n", (DAT_UVERYLONG)test_ptr->base_port); + DT_Mdep_printf ("Iterations : %u\n", test_ptr->cmd->num_iterations); + DT_Mdep_printf ("Ops : %7d.%02d Ops/Sec\n", + whole (total_ops / time), + hundredths (total_ops / time)); + DT_Mdep_printf ("Time : %7d.%02d sec\n", + whole (time), + hundredths (time)); + DT_Mdep_printf ("Sent : %7d.%02d MB - %7d.%02d MB/Sec\n", + whole (mbytes_send), + hundredths (mbytes_send), + whole (mbytes_send / time), + hundredths (mbytes_send / time)); + DT_Mdep_printf ("Recv : %7d.%02d MB - %7d.%02d MB/Sec\n", + whole (mbytes_recv), + hundredths (mbytes_recv), + whole (mbytes_recv / time), + hundredths (mbytes_recv / time)); + DT_Mdep_printf ("RDMA Read : %7d.%02d MB - %7d.%02d MB/Sec\n", + whole (mbytes_rdma_read), + hundredths (mbytes_rdma_read), + whole (mbytes_rdma_read / time), + hundredths (mbytes_rdma_read / time)); + DT_Mdep_printf ("RDMA Write : %7d.%02d MB - %7d.%02d MB/Sec\n", + whole (mbytes_rdma_write), + hundredths (mbytes_rdma_write), + whole (mbytes_rdma_write / time), + hundredths (mbytes_rdma_write / time)); +} + diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_transaction_test.h b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_transaction_test.h new file mode 100644 index 00000000..96baddd7 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_transaction_test.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#ifndef __DAPL_TRANSACTION_TEST_H__ +#define __DAPL_TRANSACTION_TEST_H__ + +#include "dapl_common.h" +#include "dapl_test_data.h" +#include "dapl_transaction_cmd.h" +#include "dapl_mdep.h" + +#pragma pack(1) +typedef struct +{ + DAT_BOOLEAN server_initiated; + DT_Transfer_Type transfer_type; + DAT_UINT32 num_segs; + DAT_UINT32 seg_size; + DAT_BOOLEAN reap_send_on_recv; + Bpool *bp; + + /* RDMA info */ + DAT_RMR_CONTEXT Rdma_Context; + DAT_PVOID Rdma_Address; +} Transaction_Test_Op_t; + +typedef struct +{ + DAT_EP_HANDLE ep_handle; + DAT_EP_ATTR ep_attr; + DAT_CONN_QUAL ia_port; + Bpool *bp; + Transaction_Test_Op_t op[ MAX_OPS ]; + DAT_RSP_HANDLE rsp_handle; + DAT_PSP_HANDLE psp_handle; + +} Ep_Context_t; + +typedef struct +{ + unsigned int stat_bytes_send; + unsigned int stat_bytes_recv; + unsigned int stat_bytes_rdma_read; + unsigned int stat_bytes_rdma_write; + unsigned int start_time; + unsigned int end_time; +} Transaction_Test_Stats_t; + +typedef struct +{ + /* This group set up by DT_Transaction_Create_Test() */ + DAT_BOOLEAN is_server; + DAT_BOOLEAN remote_is_little_endian; + Per_Test_Data_t *pt_ptr; + DAT_IA_HANDLE ia_handle; + Transaction_Cmd_t *cmd; + DAT_IA_ADDRESS_PTR remote_ia_addr; + DAT_CONN_QUAL base_port; + DAT_TIMEOUT time_out; + DAT_COUNT evd_length; + Thread *thread; + + /* This group set up by each thread in DT_Transaction_Main() */ + DAT_PZ_HANDLE pz_handle; + DAT_CNO_HANDLE cno_handle; + DAT_EVD_HANDLE recv_evd_hdl; /* receive */ + DAT_EVD_HANDLE reqt_evd_hdl; /* request+rmr */ + DAT_EVD_HANDLE conn_evd_hdl; /* connect */ + DAT_EVD_HANDLE creq_evd_hdl; /* "" request */ + Ep_Context_t *ep_context; + + /* Statistics set by DT_Transaction_Run() */ + Transaction_Test_Stats_t stats; +} Transaction_Test_t; +#pragma pack() +#endif diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_transaction_util.c b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_transaction_util.c new file mode 100644 index 00000000..2d6e73a7 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_transaction_util.c @@ -0,0 +1,730 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_bpool.h" +#include "dapl_mdep.h" +#include "dapl_proto.h" + +/* ----------------------------------------------------------- + * Post a recv buffer on each of this thread's EPs. + */ +bool +DT_handle_post_recv_buf (Ep_Context_t * ep_context, + unsigned int num_eps, + int op_indx) +{ + unsigned int i, j; + + for (i = 0; i < num_eps; i++) + { + Transaction_Test_Op_t *op = &ep_context[i].op[op_indx]; + DAT_LMR_TRIPLET *iov = DT_Bpool_GetIOV (op->bp, 0); + DAT_DTO_COOKIE cookie; + DAT_RETURN ret; + + /* Prep the inputs */ + for (j = 0; j < op->num_segs; j++) + { + iov[j].pad = 0U; + iov[j].virtual_address = (DAT_VADDR) (uintptr_t) + DT_Bpool_GetBuffer (op->bp, j); + iov[j].segment_length = op->seg_size; + iov[j].lmr_context = DT_Bpool_GetLMR (op->bp, j); + } + cookie.as_64 = + ((((DAT_UINT64) i) << 32) + | (((uintptr_t) DT_Bpool_GetBuffer (op->bp, 0)) & 0xffffffffUL)); + + /* Post the recv */ + ret = dat_ep_post_recv ( ep_context[i].ep_handle, + op->num_segs, + iov, + cookie, + DAT_COMPLETION_DEFAULT_FLAG); + + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("Test Error: dat_ep_post_recv failed: %s\n", + DT_RetToString (ret)); + DT_Test_Error (); + return false; + } + } + + return true; +} + + +/* ----------------------------------------------------------- + * Post a send buffer on each of this thread's EPs. + */ +bool +DT_handle_send_op (Ep_Context_t * ep_context, + DAT_EVD_HANDLE reqt_evd_hdl, + unsigned int num_eps, + int op_indx, + bool poll) +{ + unsigned int i, j; + unsigned char *completion_reaped; + + completion_reaped = DT_Mdep_Malloc (num_eps * sizeof (unsigned char)); + + if (!completion_reaped) + { + return false; + } + + for (i = 0; i < num_eps; i++) + { + Transaction_Test_Op_t *op = &ep_context[i].op[op_indx]; + DAT_LMR_TRIPLET *iov = DT_Bpool_GetIOV (op->bp, 0); + DAT_DTO_COOKIE cookie; + DAT_RETURN ret; + + /* Prep the inputs */ + for (j = 0; j < op->num_segs; j++) + { + iov[j].pad = 0U; + iov[j].virtual_address = (DAT_VADDR) (uintptr_t) + DT_Bpool_GetBuffer (op->bp, j); + iov[j].segment_length = op->seg_size; + iov[j].lmr_context = DT_Bpool_GetLMR (op->bp, j); + } + cookie.as_64 = + ((((DAT_UINT64) i) << 32) + | (((uintptr_t) DT_Bpool_GetBuffer (op->bp, 0)) & 0xffffffffUL)); + + /* Post the send */ + ret = dat_ep_post_send ( ep_context[i].ep_handle, + op->num_segs, + iov, + cookie, + DAT_COMPLETION_DEFAULT_FLAG); + + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("Test Error: dat_ep_post_send failed: %s\n", + DT_RetToString (ret)); + DT_Test_Error (); + DT_Mdep_Free (completion_reaped); + return false; + } + } + + for (i = 0; i < num_eps; i++) + { + Transaction_Test_Op_t *op = &ep_context[i].op[op_indx]; + + if (op->reap_send_on_recv && !op->server_initiated) + { + /* we will reap the send on the recv (Client SR) */ + DT_Mdep_Free (completion_reaped); + return true; + } + } + + bzero ((void *) completion_reaped, sizeof (unsigned char) * num_eps); + + /* reap the send completion */ + for (i = 0; i < num_eps; i++) + { + Transaction_Test_Op_t *op; + DAT_DTO_COMPLETION_EVENT_DATA dto_stat; + DAT_DTO_COOKIE dto_cookie; + unsigned int epnum; + + if (!DT_dto_event_reap (reqt_evd_hdl, poll, &dto_stat)) + { + DT_Mdep_Free (completion_reaped); + return false; + } + + epnum = (uint32_t)(dto_stat.user_cookie.as_64 >> 32); + if (epnum > num_eps) + { + DT_Mdep_printf ("Test Error: Send: Invalid endpoint completion reaped.\n" + "\tEndpoint: 0x%p, Cookie: 0x" F64x ", Length: " F64u "\n", + dto_stat.ep_handle, dto_stat.user_cookie.as_64, + dto_stat.transfered_length); + DT_Test_Error (); + DT_Mdep_Free (completion_reaped); + return false; + } + + op = &ep_context[epnum].op[op_indx]; + + dto_cookie.as_64 = + ((((DAT_UINT64) epnum) << 32) + | (((uintptr_t) DT_Bpool_GetBuffer (op->bp, 0)) & 0xffffffffUL)); + + if (!DT_dto_check (&dto_stat, + ep_context[epnum].ep_handle, + op->num_segs * op->seg_size, + dto_cookie, + "Send")) + { + DT_Mdep_Free (completion_reaped); + return false; + } + + if (completion_reaped[epnum]) + { + DT_Mdep_printf ("Test Error: Send: Secondary completion seen for endpoint 0x%p (%d)\n", + ep_context[epnum].ep_handle, epnum); + DT_Test_Error (); + DT_Mdep_Free (completion_reaped); + return ( false ); + } + completion_reaped[epnum] = 1; + } + + for (i = 0; i < num_eps; i++) + { + if (completion_reaped[i] == 0) + { + DT_Mdep_printf ("Test Error: Send: No completion seen for endpoint 0x%p (#%d)\n", + ep_context[i].ep_handle, i); + DT_Test_Error (); + DT_Mdep_Free (completion_reaped); + return ( false ); + } + } + + DT_Mdep_Free (completion_reaped); + return true; +} + + +/* ----------------------------------------------------------- + * Reap a recv op on each of this thread's EPs, + * then if requested reap the corresponding send ops, + * and re-post all of the recv buffers. + */ +bool +DT_handle_recv_op (Ep_Context_t * ep_context, + DAT_EVD_HANDLE recv_evd_hdl, + DAT_EVD_HANDLE reqt_evd_hdl, + unsigned int num_eps, + int op_indx, + bool poll, + bool repost_recv) +{ + unsigned int i; + unsigned char *recv_completion_reaped; + unsigned char *send_completion_reaped; + + recv_completion_reaped = DT_Mdep_Malloc (num_eps); + if (recv_completion_reaped == NULL) + { + return false; + } + + send_completion_reaped = DT_Mdep_Malloc (num_eps); + if (send_completion_reaped == NULL) + { + DT_Mdep_Free (recv_completion_reaped); + return false; + } + + /* Foreach EP, reap */ + bzero ((void *) recv_completion_reaped, sizeof (unsigned char) * num_eps); + bzero ((void *) send_completion_reaped, sizeof (unsigned char) * num_eps); + for (i = 0; i < num_eps; i++) + { + Transaction_Test_Op_t *op; + DAT_DTO_COMPLETION_EVENT_DATA dto_stat; + DAT_DTO_COOKIE dto_cookie; + unsigned int epnum; + + /* First reap the recv DTO event */ + if (!DT_dto_event_reap (recv_evd_hdl, poll, &dto_stat)) + { + DT_Mdep_Free (recv_completion_reaped); + DT_Mdep_Free (send_completion_reaped); + return false; + } + + epnum = (uint32_t)(dto_stat.user_cookie.as_64 >> 32); + if (epnum > num_eps) + { + DT_Mdep_printf ("Test Error: Receive: Invalid endpoint completion reaped.\n" + "\tEndpoint: 0x%p, Cookie: 0x" F64x ", Length: " F64u "\n", + dto_stat.ep_handle, dto_stat.user_cookie.as_64, + dto_stat.transfered_length); + DT_Test_Error (); + DT_Mdep_Free (recv_completion_reaped); + DT_Mdep_Free (send_completion_reaped); + return false; + } + + op = &ep_context[epnum].op[op_indx]; + dto_cookie.as_64 = + ((((DAT_UINT64) epnum) << 32) + | (((uintptr_t) DT_Bpool_GetBuffer (op->bp, 0)) & 0xffffffffUL)); + + if (!DT_dto_check (&dto_stat, + ep_context[epnum].ep_handle, + op->num_segs * op->seg_size, + dto_cookie, + "Recv")) + { + DT_Mdep_printf ("Test Error: recv DTO problem\n"); + DT_Test_Error (); + DT_Mdep_Free (recv_completion_reaped); + DT_Mdep_Free (send_completion_reaped); + return false; + } + + if (recv_completion_reaped[epnum]) + { + DT_Mdep_printf ("Test Error: Receive: Secondary completion seen for endpoint 0x%p (%d)\n", + ep_context[epnum].ep_handle, epnum); + DT_Test_Error (); + DT_Mdep_Free (recv_completion_reaped); + DT_Mdep_Free (send_completion_reaped); + return ( false ); + } + recv_completion_reaped[epnum] = 1; + + /* + * Check the current op to see whether we are supposed + * to reap the previous send op now. + */ + if (op->reap_send_on_recv && op->server_initiated) + { + if (op_indx <= 0) + /* shouldn't happen, but let's be certain */ + { + DT_Mdep_printf ("Internal Error: reap_send_on_recv" + " but current op == #%d\n", op_indx); + DT_Mdep_Free (recv_completion_reaped); + DT_Mdep_Free (send_completion_reaped); + return false; + } + + if (!DT_dto_event_reap (reqt_evd_hdl, poll, &dto_stat)) + { + DT_Mdep_Free (recv_completion_reaped); + DT_Mdep_Free (send_completion_reaped); + return false; + } + + epnum = (uint32_t)(dto_stat.user_cookie.as_64 >> 32); + if (epnum > num_eps) + { + DT_Mdep_printf ("Test Error: Send (ror): Invalid endpoint completion reaped.\n" + "\tEndpoint: 0x%p, Cookie: 0x" F64x ", Length: "F64u "\n", + dto_stat.ep_handle, dto_stat.user_cookie.as_64, + dto_stat.transfered_length); + DT_Test_Error (); + DT_Mdep_Free (recv_completion_reaped); + DT_Mdep_Free (send_completion_reaped); + return false; + } + + /* + * We're reaping the last transaction, a + * send completion that we skipped when it was sent. + */ + op = &ep_context[epnum].op[op_indx - 1]; + + dto_cookie.as_64 = + ((((DAT_UINT64) epnum) << 32) + | (((uintptr_t) DT_Bpool_GetBuffer (op->bp, 0)) + & 0xffffffffUL)); + + /* + * If we have multiple EPs we can't guarantee the order of + * completions, so disable ep_handle check + */ + if (!DT_dto_check (&dto_stat, + num_eps == 1?ep_context[i].ep_handle: NULL, + op->num_segs * op->seg_size, + dto_cookie, + "Send-reaped-on-recv")) + { + DT_Mdep_printf ("Test Error: send DTO problem\n"); + DT_Test_Error (); + DT_Mdep_Free (recv_completion_reaped); + DT_Mdep_Free (send_completion_reaped); + return false; + } + + if (send_completion_reaped[epnum]) + { + DT_Mdep_printf ("Test Error: Send (ror): Secondary completion seen for endpoint 0x%p (%d)\n", + ep_context[epnum].ep_handle, epnum); + DT_Test_Error (); + DT_Mdep_Free (recv_completion_reaped); + DT_Mdep_Free (send_completion_reaped); + return ( false ); + } + send_completion_reaped[epnum] = 1; + } + } + + for (i = 0; i < num_eps; i++) + { + if (recv_completion_reaped[i] == 0) + { + DT_Mdep_printf ("Test Error: Receive: No completion seen for endpoint 0x%p (#%d)\n", + ep_context[i].ep_handle, i); + DT_Test_Error (); + DT_Mdep_Free (recv_completion_reaped); + DT_Mdep_Free (send_completion_reaped); + return ( false ); + } + } + + if (ep_context[0].op[op_indx].reap_send_on_recv + && ep_context[0].op[op_indx].server_initiated) + { + for (i = 0; i < num_eps; i++) + { + if (send_completion_reaped[i] == 0) + { + DT_Mdep_printf ("Test Error: Send (ror): No completion seen for endpoint 0x%p (#%d)\n", + ep_context[i].ep_handle, i); + DT_Test_Error (); + DT_Mdep_Free (recv_completion_reaped); + DT_Mdep_Free (send_completion_reaped); + return ( false ); + } + } + } + + if (repost_recv) + { + /* repost the receive buffer */ + if (!DT_handle_post_recv_buf (ep_context, num_eps, op_indx)) + { + DT_Mdep_printf ("Test Error: recv re-post problem\n"); + DT_Test_Error (); + DT_Mdep_Free (recv_completion_reaped); + DT_Mdep_Free (send_completion_reaped); + return false; + } + } + + DT_Mdep_Free (recv_completion_reaped); + DT_Mdep_Free (send_completion_reaped); + return true; +} + + +/* ----------------------------------------------------------- + * Initiate an RDMA op (synchronous) on each of this thread's EPs. + */ +bool +DT_handle_rdma_op (Ep_Context_t * ep_context, + DAT_EVD_HANDLE reqt_evd_hdl, + unsigned int num_eps, + DT_Transfer_Type opcode, + int op_indx, + bool poll) +{ + unsigned int i, j; + DAT_RETURN ret; + unsigned char *completion_reaped; + + completion_reaped = DT_Mdep_Malloc (num_eps * sizeof (unsigned char)); + + if (!completion_reaped) + { + return false; + } + + /* Initiate the operation */ + for (i = 0; i < num_eps; i++) + { + Transaction_Test_Op_t *op = &ep_context[i].op[op_indx]; + DAT_LMR_TRIPLET *iov = DT_Bpool_GetIOV (op->bp, 0); + DAT_DTO_COOKIE cookie; + DAT_RMR_TRIPLET rmr_triplet; + + /* Prep the inputs */ + for (j = 0; j < op->num_segs; j++) + { + iov[j].pad = 0U; + iov[j].virtual_address = (DAT_VADDR) (uintptr_t) + DT_Bpool_GetBuffer (op->bp, j); + iov[j].segment_length = op->seg_size; + iov[j].lmr_context = DT_Bpool_GetLMR (op->bp, j); + } + cookie.as_64 = + ((((DAT_UINT64) i) << 32) + | (((uintptr_t) DT_Bpool_GetBuffer (op->bp, 0)) & 0xffffffffUL)); + + rmr_triplet.pad = 0U; + rmr_triplet.target_address = (DAT_VADDR) (uintptr_t) op->Rdma_Address; + rmr_triplet.segment_length = op->seg_size * op->num_segs; + rmr_triplet.rmr_context = op->Rdma_Context; + + DT_Mdep_spew (3, ("Call dat_ep_post_rdma_%s [" F64x ", sz=" F64x ", ctxt=%x]\n", + (opcode == RDMA_WRITE ? "write" : "read"), + rmr_triplet.target_address, + rmr_triplet.segment_length, + rmr_triplet.rmr_context )); + + /* Post the operation */ + if (opcode == RDMA_WRITE) + { + + ret = dat_ep_post_rdma_write (ep_context[i].ep_handle, + op->num_segs, + iov, + cookie, + &rmr_triplet, + DAT_COMPLETION_DEFAULT_FLAG); + + } + else /* opcode == RDMA_READ */ + { + + ret = dat_ep_post_rdma_read ( ep_context[i].ep_handle, + op->num_segs, + iov, + cookie, + &rmr_triplet, + DAT_COMPLETION_DEFAULT_FLAG); + + } + if (ret != DAT_SUCCESS) + { + DT_Mdep_printf ("Test Error: dat_ep_post_rdma_%s failed: %s\n", + (opcode == RDMA_WRITE ? "write" : "read"), + DT_RetToString (ret)); + DT_Test_Error (); + DT_Mdep_Free (completion_reaped); + return ( false ); + } + else + { + DT_Mdep_spew (3, ("Done dat_ep_post_rdma_%s %s\n", + (opcode == RDMA_WRITE ? "write" : "read"), + " () Waiting ...")); + } + } + + bzero ((void *) completion_reaped, sizeof (unsigned char) * num_eps); + /* Wait for it to happen */ + for (i = 0; i < num_eps; i++) + { + Transaction_Test_Op_t *op; + DAT_DTO_COMPLETION_EVENT_DATA dto_stat; + DAT_DTO_COOKIE dto_cookie; + unsigned int epnum; + + if (!DT_dto_event_reap (reqt_evd_hdl, poll, &dto_stat)) + { + DT_Mdep_Free (completion_reaped); + return ( false ); + } + + epnum = (uint32_t)(dto_stat.user_cookie.as_64 >> 32); + if (epnum > num_eps) + { + DT_Mdep_printf ("Test Error: %s: Invalid endpoint completion reaped.\n" + "\tEndpoint: 0x%p, Cookie: 0x" F64x ", Length: " F64u "\n", + opcode == RDMA_WRITE ? "RDMA/WR" : "RDMA/RD", + dto_stat.ep_handle, dto_stat.user_cookie.as_64, + dto_stat.transfered_length); + DT_Test_Error (); + DT_Mdep_Free (completion_reaped); + return false; + } + op = &ep_context[epnum].op[op_indx]; + + dto_cookie.as_64 = + ((((DAT_UINT64) epnum) << 32) + | (((uintptr_t) DT_Bpool_GetBuffer (op->bp, 0)) & 0xffffffffUL)); + + if (!DT_dto_check (&dto_stat, + ep_context[epnum].ep_handle, + op->num_segs * op->seg_size, + dto_cookie, + (opcode == RDMA_WRITE ? "RDMA/WR" : "RDMA/RD"))) + { + DT_Mdep_Free (completion_reaped); + return ( false ); + } + + if (completion_reaped[epnum]) + { + DT_Mdep_printf ("Test Error: %s: Secondary completion seen for endpoint 0x%p (%d)\n", + opcode == RDMA_WRITE ? "RDMA/WR" : "RDMA/RD", + ep_context[epnum].ep_handle, epnum); + DT_Test_Error (); + DT_Mdep_Free (completion_reaped); + return ( false ); + } + completion_reaped[epnum] = 1; + + DT_Mdep_spew (3, ("dat_ep_post_rdma_%s OK\n", + (opcode == RDMA_WRITE ? "RDMA/WR" : "RDMA/RD"))); + } + + for (i = 0; i < num_eps; i++) + { + if (completion_reaped[i] == 0) + { + DT_Mdep_printf ("Test Error: %s: No completion seen for endpoint 0x%p (#%d)\n", + opcode == RDMA_WRITE ? "RDMA/WR" : "RDMA/RD", + ep_context[i].ep_handle, i); + DT_Test_Error (); + DT_Mdep_Free (completion_reaped); + return ( false ); + } + } + + DT_Mdep_Free (completion_reaped); + + return ( true ); +} + + +/* ----------------------------------------------------------- + * Verify whether we (the client side) can support + * the requested 'T' test. + */ +bool +DT_check_params (Per_Test_Data_t *pt_ptr, + unsigned char *module) +{ + Transaction_Cmd_t * cmd = &pt_ptr->Params.u.Transaction_Cmd; + unsigned long num_recvs = 0U; + unsigned long num_sends = 0U; + unsigned long num_rdma_rd = 0U; + unsigned long num_rdma_wr = 0U; + unsigned long max_size = 0U; + unsigned long max_segs = 0U; + bool rval = true; + unsigned int i; + + /* Count up what's requested (including -V appended sync points) */ + for (i = 0; i < cmd->num_ops; i++) + { + unsigned int xfer_size; + + xfer_size = cmd->op[i].num_segs * cmd->op[i].seg_size; + if (xfer_size > max_size) + { + max_size = xfer_size; + } + if (cmd->op[i].num_segs > max_segs) + { + max_segs = cmd->op[i].num_segs; + } + + switch (cmd->op[i].transfer_type) + { + case SEND_RECV: + { + if (cmd->op[i].server_initiated) + { + num_recvs++; + } + else + { + num_sends++; + } + break; + } + + case RDMA_READ: + { + num_rdma_rd++; + break; + } + + case RDMA_WRITE: + { + num_rdma_wr++; + break; + } + } + } + + /* + * Now check the IA and EP attributes, and check for some of the + * more obvious resource problems. This is hardly exhaustive, + * and some things will inevitably fall through to run-time. + * + * We don't compare + * num_rdma_rd > pt_ptr->ia_attr.max_rdma_read_per_ep + * num_rdma_wr > pt_ptr->ia_attr.max_dto_per_ep + * because each thread has its own EPs, and transfers are issued + * synchronously (across a thread's EPs, and ignoring -f, which allows + * a per-EP pipeline depth of at most 2 and applies only to SR ops), + * so dapltest actually attempts almost no pipelining on a single EP. + * But we do check that pre-posted recv buffers will all fit. + */ + if ((DAT_COUNT)num_recvs > pt_ptr->ia_attr.max_dto_per_ep || + (DAT_COUNT)num_sends > pt_ptr->ia_attr.max_dto_per_ep) + { + DT_Mdep_printf ( + "%s: S/R: cannot supply %ld SR ops (maximum: %d)\n", + module, + num_recvs > num_sends ? num_recvs : num_sends, + pt_ptr->ia_attr.max_dto_per_ep); + rval = false; + } + if (max_size > pt_ptr->ia_attr.max_lmr_block_size) + { + DT_Mdep_printf ( + "%s: buffer too large: 0x%lx (maximum: " F64x " bytes)\n", + module, + max_size, + pt_ptr->ia_attr.max_lmr_block_size); + rval = false; + } + if ((DAT_COUNT)max_segs > pt_ptr->ep_attr.max_recv_iov || + (DAT_COUNT)max_segs > pt_ptr->ep_attr.max_request_iov) + { + /* + * In an ideal world, we'd just ask for more segments + * when creating the EPs for the test, rather than + * checking against default EP attributes. + */ + DT_Mdep_printf ( + "%s: cannot use %ld segments (maxima: S %d, R %d)\n", + module, + max_segs, + pt_ptr->ep_attr.max_request_iov, + pt_ptr->ep_attr.max_recv_iov ); + rval = false; + } + + return ( rval ); +} + +/* Empty function in which to set breakpoints. */ +void +DT_Test_Error (void) +{ + ; +} diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_util.c b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_util.c new file mode 100644 index 00000000..8ddf787d --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_util.c @@ -0,0 +1,297 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_mdep.h" +#include "dapl_proto.h" +#include + + + +/* + * Map DAT_RETURN values to readable strings, + * but don't assume the values are zero-based or contiguous. + */ +const char * +DT_RetToString (DAT_RETURN ret_value) +{ + unsigned int i; + static struct + { + const char *name; + DAT_RETURN value; + } dat_errors[] = + { + # define DATxx(x) { # x, x } + DATxx (DAT_SUCCESS), + DATxx (DAT_ABORT), + DATxx (DAT_CONN_QUAL_IN_USE), + DATxx (DAT_INSUFFICIENT_RESOURCES), + DATxx (DAT_INTERNAL_ERROR), + DATxx (DAT_INVALID_HANDLE), + DATxx (DAT_INVALID_PARAMETER), + DATxx (DAT_INVALID_STATE), + DATxx (DAT_LENGTH_ERROR), + DATxx (DAT_MODEL_NOT_SUPPORTED), + DATxx (DAT_PROVIDER_NOT_FOUND), + DATxx (DAT_PRIVILEGES_VIOLATION), + DATxx (DAT_PROTECTION_VIOLATION), + DATxx (DAT_QUEUE_EMPTY), + DATxx (DAT_QUEUE_FULL), + DATxx (DAT_TIMEOUT_EXPIRED), + DATxx (DAT_PROVIDER_ALREADY_REGISTERED), + DATxx (DAT_PROVIDER_IN_USE), + DATxx (DAT_NOT_IMPLEMENTED) + # undef DATxx + }; + # define NUM_ERRORS (sizeof(dat_errors)/sizeof(dat_errors[0])) + + for (i = 0; i < NUM_ERRORS; i++) + { + if (dat_errors[i].value == DAT_GET_TYPE(ret_value)) + { + return ( (dat_errors[i].name)); + } + + } + return ( "Invalid_DAT_RETURN" ); +} + +/* + * Map DAT_RETURN values to readable strings, + * but don't assume the values are zero-based or contiguous. + */ +const char * +DT_TransferTypeToString (DT_Transfer_Type type) +{ + static char *DT_Type[] = + { + "RR", + "RW", + "SR" + }; + + if ( (0 <= type) && (type <= 2) ) + { + return DT_Type[type]; + } + else + { + return "Error: Unkown Transfer Type"; + } +} + + +/* + * Map DAT_ASYNC_ERROR_CODE values to readable strings + */ +const char * +DT_AsyncErr2Str (DAT_EVENT_NUMBER error_code) +{ + unsigned int i; + static struct + { + const char *name; + DAT_RETURN value; + } dat_errors[] = + { + # define DATxx(x) { # x, x } + DATxx (DAT_DTO_COMPLETION_EVENT), + DATxx (DAT_RMR_BIND_COMPLETION_EVENT), + DATxx (DAT_CONNECTION_REQUEST_EVENT), + DATxx (DAT_CONNECTION_EVENT_ESTABLISHED), + DATxx (DAT_CONNECTION_EVENT_PEER_REJECTED), + DATxx (DAT_CONNECTION_EVENT_NON_PEER_REJECTED), + DATxx (DAT_CONNECTION_EVENT_ACCEPT_COMPLETION_ERROR), + DATxx (DAT_CONNECTION_EVENT_DISCONNECTED), + DATxx (DAT_CONNECTION_EVENT_BROKEN), + DATxx (DAT_CONNECTION_EVENT_TIMED_OUT), + DATxx (DAT_ASYNC_ERROR_EVD_OVERFLOW), + DATxx (DAT_ASYNC_ERROR_IA_CATASTROPHIC), + DATxx (DAT_ASYNC_ERROR_EP_BROKEN), + DATxx (DAT_ASYNC_ERROR_TIMED_OUT), + DATxx (DAT_ASYNC_ERROR_PROVIDER_INTERNAL_ERROR), + DATxx (DAT_SOFTWARE_EVENT) + # undef DATxx + }; + # define NUM_ERRORS (sizeof(dat_errors)/sizeof(dat_errors[0])) + + for (i = 0; i < NUM_ERRORS; i++) + { + if (dat_errors[i].value == error_code) + { + return ( dat_errors[i].name ); + } + } + + return ( "Invalid_DAT_EVENT_NUMBER" ); +} + +/* + * Map DAT_EVENT_CODE values to readable strings + */ +const char * +DT_EventToSTr (DAT_EVENT_NUMBER event_code) +{ + unsigned int i; + static struct + { + const char *name; + DAT_RETURN value; + } + dat_events[] = + { + # define DATxx(x) { # x, x } + DATxx (DAT_DTO_COMPLETION_EVENT), + DATxx (DAT_RMR_BIND_COMPLETION_EVENT), + DATxx (DAT_CONNECTION_REQUEST_EVENT), + DATxx (DAT_CONNECTION_EVENT_ESTABLISHED), + DATxx (DAT_CONNECTION_EVENT_PEER_REJECTED), + DATxx (DAT_CONNECTION_EVENT_NON_PEER_REJECTED), + DATxx (DAT_CONNECTION_EVENT_ACCEPT_COMPLETION_ERROR), + DATxx (DAT_CONNECTION_EVENT_DISCONNECTED), + DATxx (DAT_CONNECTION_EVENT_BROKEN), + DATxx (DAT_CONNECTION_EVENT_TIMED_OUT), + DATxx (DAT_CONNECTION_EVENT_UNREACHABLE), + DATxx (DAT_ASYNC_ERROR_EVD_OVERFLOW), + DATxx (DAT_ASYNC_ERROR_IA_CATASTROPHIC), + DATxx (DAT_ASYNC_ERROR_EP_BROKEN), + DATxx (DAT_ASYNC_ERROR_TIMED_OUT), + DATxx (DAT_ASYNC_ERROR_PROVIDER_INTERNAL_ERROR), + DATxx (DAT_SOFTWARE_EVENT) + # undef DATxx + }; + # define NUM_EVENTS (sizeof(dat_events)/sizeof(dat_events[0])) + + for (i = 0; i < NUM_EVENTS; i++) + { + if (dat_events[i].value == event_code) + { + return ( dat_events[i].name ); + } + } + + return ( "Invalid_DAT_EVENT_NUMBER" ); +} + + +/* + * Map DAT_EP_STATE_CODE values to readable strings + */ +const char * +DT_State2Str (DAT_EP_STATE state_code) +{ + unsigned int i; + static struct + { + const char *name; + DAT_RETURN value; + } + dat_state[] = + { + # define DATxx(x) { # x, x } + DATxx (DAT_EP_STATE_UNCONNECTED), + DATxx (DAT_EP_STATE_RESERVED), + DATxx (DAT_EP_STATE_PASSIVE_CONNECTION_PENDING), + DATxx (DAT_EP_STATE_ACTIVE_CONNECTION_PENDING), + DATxx (DAT_EP_STATE_TENTATIVE_CONNECTION_PENDING), + DATxx (DAT_EP_STATE_CONNECTED), + DATxx (DAT_EP_STATE_DISCONNECT_PENDING), + DATxx (DAT_EP_STATE_ERROR) + # undef DATxx + }; + # define NUM_STATES (sizeof(dat_state)/sizeof(dat_state[0])) + + for (i = 0; i < NUM_STATES; i++) + { + if (dat_state[i].value == state_code) + { + return ( dat_state[i].name ); + } + } + + return ( "Invalid_DAT_STATE_NUMBER" ); +} + + +/* + * Parse a QOS argument into a DAT_QOS. + * + * Returns no errors: defaults to best effort. + */ +DAT_QOS +DT_ParseQoS (char *arg) +{ + if (0 == strcmp (arg, "HT")) + { + return ( DAT_QOS_HIGH_THROUGHPUT ); + } + + if (0 == strcmp (arg, "LL")) + { + return ( DAT_QOS_LOW_LATENCY ); + } + + if (0 == strcmp (arg, "EC")) + { + return ( DAT_QOS_ECONOMY ); + } + + if (0 == strcmp (arg, "PM")) + { + return ( DAT_QOS_PREMIUM ); + } + /* + * Default to "BE" so no point in checking further + */ + return ( DAT_QOS_BEST_EFFORT ); +} + + +/* + * A couple of round-up routines (for pointers and counters) + * which both assume a power-of-two 'align' factor, + * and do the correct thing if align == 0. + */ +unsigned char * +DT_AlignPtr (void * val, unsigned int align) +{ + if (align) + { + return ( (unsigned char *) + (((DAT_UVERYLONG)val + ((DAT_UVERYLONG)align) - 1) & ~ (((DAT_UVERYLONG)align) - 1))); + } + return (val); +} + +DAT_COUNT +DT_RoundSize (DAT_COUNT val, DAT_COUNT align) +{ + if (align) + { + return ( ((val + align - 1) & ~ (align - 1)) ); + } + return ( val ); +} diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_version.h b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_version.h new file mode 100644 index 00000000..a625c462 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapl_version.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#ifndef __DAPL_VERSION_H +#define __DAPL_VERSION_H +/* + * Dapltest version number + * + * This should be bumped everytime the "cross-the-wire" behavior changes. + */ + +#define DAPLTEST_VERSION 0x00000005 + +#endif diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapltest.rc b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapltest.rc new file mode 100644 index 00000000..230df9f7 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/dapltest.rc @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2007 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#if DBG +#define VER_FILEDESCRIPTION_STR "DAPL/DAT[1.1] test application (Debug)" +#define VER_INTERNALNAME_STR "dapltestd.exe" +#define VER_ORIGINALFILENAME_STR "dapltestd.exe" +#else +#define VER_FILEDESCRIPTION_STR "DAPL/DAT[1.1] test application" +#define VER_INTERNALNAME_STR "dapltest.exe" +#define VER_ORIGINALFILENAME_STR "dapltest.exe" +#endif + +#include + diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/lat_block.sh b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/lat_block.sh new file mode 100644 index 00000000..572d9ba0 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/lat_block.sh @@ -0,0 +1,22 @@ +#!/bin/sh +# +# Sample client invocation +# +# +me=`basename $0` +case $# in +0) echo Usage: $me '[hostname [size [device]]]' 1>&2 ; exit 1;; +1) host=$1 + device=IbalHca0 + size=4 ;; +2) host=$1 + device=IbalHca0 + size=$2 ;; +3) host=$1 + device=$3 + size=$2 ;; +*) echo Usage: $me '[hostname [size [device]]]' 1>&2 ; exit 1;; +esac + +./dapltest -T P -d -i 1024 -s ${host} -D ${device} \ + -p 1 -m b RW ${size} 1 diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/lat_poll.sh b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/lat_poll.sh new file mode 100644 index 00000000..f79edb11 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/lat_poll.sh @@ -0,0 +1,22 @@ +#!/bin/sh +# +# Sample client invocation +# +# +me=`basename $0` +case $# in +0) echo Usage: $me '[hostname [size [device]]]' 1>&2 ; exit 1;; +1) host=$1 + device=IbalHca0 + size=4 ;; +2) host=$1 + device=IbalHca0 + size=$2 ;; +3) host=$1 + device=$3 + size=$2 ;; +*) echo Usage: $me '[hostname [size [device]]]' 1>&2 ; exit 1;; +esac + +./dapltest -T P -d -i 1024 -s ${host} -D ${device} \ + -p 1 -m p RW ${size} 1 diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/lim.sh b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/lim.sh new file mode 100644 index 00000000..350316ea --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/lim.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +me=`basename $0` + +case $# in +0) device=IbalHca0 ;; +1) device=$1 ;; +*) echo Usage: $me '[device]' 1>&2 ; exit 1;; +esac + +# +# -d debug verbosity +# -w width sets up 'width' sets of IA,PZ,EVD,EP,LMR,RMR,... +# -m maximum provides a bound on exhaustion tests +# +./dapltest -T L -D ${device} -d -w 8 -m 100 limit_ia limit_pz limit_evd \ + limit_ep limit_psp limit_lmr limit_rpost diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/makefile b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/makefile new file mode 100644 index 00000000..d4938551 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\..\..\inc\openib.def diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/makefile.wnd b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/makefile.wnd new file mode 100644 index 00000000..6464da17 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/makefile.wnd @@ -0,0 +1,179 @@ +# +# Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. +# +# This Software is licensed under either one of the following two licenses: +# +# 1) under the terms of the "Common Public License 1.0" a copy of which is +# in the file LICENSE.txt in the root directory. The license is also +# available from the Open Source Initiative, see +# http://www.opensource.org/licenses/cpl.php. +# OR +# +# 2) under the terms of the "The BSD License" a copy of which is in the file +# LICENSE2.txt in the root directory. The license is also available from +# the Open Source Initiative, see +# http://www.opensource.org/licenses/bsd-license.php. +# +# Licensee has the right to choose either one of the above two licenses. +# +# Redistributions of source code must retain both the above copyright +# notice and either one of the license notices. +# +# Redistributions in binary form must reproduce both the above copyright +# notice, either one of the license notices in the documentation +# and/or other materials provided with the distribution. +# + +#********************************************************************* +# +# NMAKE Options (passed by macro) +# +# Option Invoke NMKAE +# ----------------------- ----------------------- +# expilicit linking nmake EXPLCIT_LINK=1 +# +#*********************************************************************/ + + +#********************************************************************* +# +# Dot Directives +# +#*********************************************************************/ + +.SUFFIXES : # clear the .SUFFIXES list +.SUFFIXES : .c # initialize .SUFFIXES list + + +#********************************************************************* +# +# Macros +# +#*********************************************************************/ + +DAT_PATH = ../../../dat + +OBJ_PATH = Obj +TARGET_PATH = Target + +OBJS = $(OBJ_PATH)/dapl_bpool.obj \ + $(OBJ_PATH)/dapl_client.obj \ + $(OBJ_PATH)/dapl_client_info.obj \ + $(OBJ_PATH)/dapl_cnxn.obj \ + $(OBJ_PATH)/dapl_endian.obj \ + $(OBJ_PATH)/dapl_fft_cmd.obj \ + $(OBJ_PATH)/dapl_fft_connmgt.obj \ + $(OBJ_PATH)/dapl_fft_dataxfer.obj \ + $(OBJ_PATH)/dapl_fft_dataxfer_client.obj \ + $(OBJ_PATH)/dapl_fft_endpoint.obj \ + $(OBJ_PATH)/dapl_fft_hwconn.obj \ + $(OBJ_PATH)/dapl_fft_mem.obj \ + $(OBJ_PATH)/dapl_fft_pz.obj \ + $(OBJ_PATH)/dapl_fft_queryinfo.obj \ + $(OBJ_PATH)/dapl_fft_test.obj \ + $(OBJ_PATH)/dapl_fft_util.obj \ + $(OBJ_PATH)/dapl_getopt.obj \ + $(OBJ_PATH)/dapl_limit.obj \ + $(OBJ_PATH)/dapl_limit_cmd.obj \ + $(OBJ_PATH)/dapl_main.obj \ + $(OBJ_PATH)/dapl_mdep.obj \ + $(OBJ_PATH)/dapl_memlist.obj \ + $(OBJ_PATH)/dapl_netaddr.obj \ + $(OBJ_PATH)/dapl_params.obj \ + $(OBJ_PATH)/dapl_performance_client.obj \ + $(OBJ_PATH)/dapl_performance_cmd.obj \ + $(OBJ_PATH)/dapl_performance_server.obj \ + $(OBJ_PATH)/dapl_performance_stats.obj \ + $(OBJ_PATH)/dapl_performance_util.obj \ + $(OBJ_PATH)/dapl_quit_cmd.obj \ + $(OBJ_PATH)/dapl_server.obj \ + $(OBJ_PATH)/dapl_server_cmd.obj \ + $(OBJ_PATH)/dapl_server_info.obj \ + $(OBJ_PATH)/dapl_test_data.obj \ + $(OBJ_PATH)/dapl_test_util.obj \ + $(OBJ_PATH)/dapl_thread.obj \ + $(OBJ_PATH)/dapl_transaction_cmd.obj \ + $(OBJ_PATH)/dapl_transaction_stats.obj \ + $(OBJ_PATH)/dapl_transaction_test.obj \ + $(OBJ_PATH)/dapl_transaction_util.obj \ + $(OBJ_PATH)/dapl_util.obj + +EXEC = dapltest.exe + +# +# Compiler +# + +CC = cl + +INC_FLAGS = \ + /I $(DAT_PATH)/include \ + /I $(DAT_PATH)/common \ + /I $(DAT_PATH)/udat \ + /I $(DAT_PATH)/udat/windows + +CC_FLAGS= \ + /nologo /Zel /Zp1 /Gy /W3 /Gd /QIfdiv- /QIf /QI0f /GB /Gi- /Gm- /GX- \ + /GR- /GF -Z7 /Od /Oi /Oy- $(INC_FLAGS) \ + /DWIN32 /D_X86_ /D__i386__ /D__PENTIUM__ /DDAT_THREADSAFE=DAT_FALSE + +# +# Linker +# + +LINK = link + +LIBS = libc.lib ws2_32.lib advapi32.lib User32.lib $(DAT_PATH)/udat/Debug/udat.lib + +LINK_FLAGS = \ + /nologo /subsystem:console /DEBUG /incremental:yes /machine:I386 $(LIBS) + +#LIBS = ws2_32.lib advapi32.lib $(DAT_PATH)/udat/Target/UDAT.lib + +# if the provider library should be explicitly linked +!IFDEF EXPLICIT_LINK +# in addition to providers listed in the DAT static registry +# the specified provider will be available to the consumer +DAPL_PATH = ../../../dapl +# +# the /INCLUDE option is used to force a symbol reference to the DAPL +# provider library. If there are no references, Windows will not load +# the DAPL library when dapltest is executed. +# +LIBS = $(LIBS) $(DAPL_PATH)/udapl/Debug/dapl.lib /INCLUDE:_dapl_ia_open +!ENDIF + +# +# System Utilities +# + +RM = rm -f + + +#********************************************************************* +# Inference Rules +# +#*********************************************************************/ + +.c{$(OBJ_PATH)}.obj: + $(CC) $(CC_FLAGS) /Fo$@ /c $< + + +#********************************************************************* +# +# Description Blocks +# +#*********************************************************************/ + +all : mkdirs $(EXEC) + +mkdirs: + if not exist "$(OBJ_PATH)" mkdir "$(OBJ_PATH)" + if not exist "$(TARGET_PATH)" mkdir "$(TARGET_PATH)" + +$(EXEC) : $(OBJS) + $(LINK) $(LINK_FLAGS) /out:$(EXEC) $(OBJS) + +clean: + $(RM) $(OBJS) + $(RM) $(EXEC) diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/quit.sh b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/quit.sh new file mode 100644 index 00000000..75c040f0 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/quit.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +me=`basename $0` +case $# in +0) echo Usage: $me '[hostname [device] ]' 1>&2 ; exit 1;; +1) host=$1 + device=IbalHca0 ;; +2) host=$1 + device=$2 ;; +*) echo Usage: $me '[hostname [device] ]' 1>&2 ; exit 1;; +esac + + +# +# -d debug verbosity +# -w width sets up 'width' sets of IA,PZ,EVD,EP,LMR,RMR,... +# -m maximum provides a bound on exhaustion tests +# +./dapltest -T Q -D ${device} -s ${host} diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/regress.sh b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/regress.sh new file mode 100644 index 00000000..9757e1ab --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/regress.sh @@ -0,0 +1,66 @@ +#!/bin/sh +# +# Sample regression client invocation +# + +me=`basename $0` +case $# in +0) echo Usage: $me '[hostname [device] ]' 1>&2 ; exit 1;; +1) host=$1 + device=IbalHca0 ;; +2) host=$1 + device=$2 ;; +*) echo Usage: $me '[hostname [device] ]' 1>&2 ; exit 1;; +esac + + +#==================================================================== +#client1 +#==================================================================== +./dapltest -T T -s ${host} -D ${device} -d -i 10000 -t 1 -w 1 \ + client SR 256 \ + server SR 256 + +#==================================================================== +#client2 +#==================================================================== +./dapltest -T T -s ${host} -D ${device} -d -i 10000 -t 1 -w 1 \ + client SR 256 \ + client RW 4096 \ + server SR 256 + +#==================================================================== +#client3 +#==================================================================== +./dapltest -T T -s ${host} -D ${device} -d -i 10000 -t 1 -w 1 \ + client SR 256 \ + client RR 4096 \ + server SR 256 + +#==================================================================== +#client4 +#==================================================================== +./dapltest -T T -s ${host} -D ${device} -d -i 10000 -t 1 -w 1 \ + client SR 256 \ + client RW 4096 \ + server SR 256 \ + client SR 256 \ + client RR 4096 \ + server SR 256 \ + client SR 4096 \ + server SR 256 + +#==================================================================== +#client5 +#==================================================================== +./dapltest -T T -s ${host} -D ${device} -d -i 10000 -t 4 -w 8 \ + client SR 256 \ + client RW 4096 \ + server SR 256 \ + client SR 256 \ + client RR 4096 \ + server SR 256 \ + client SR 4096 \ + server SR 256 + + diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/srv.sh b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/srv.sh new file mode 100644 index 00000000..45d4b1f1 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dapltest/srv.sh @@ -0,0 +1,15 @@ +#!/bin/sh +# +# Sample server invocation +# +me=`basename $0` +case $# in +0) device=IbalHca0;; +1) device=$1 ;; +*) echo Usage: $me '[device]' 1>&2 ; exit 1;; +esac +# +# +# ./dapltest -T S -d -D ${device} + + ./dapltest -T S -d -D ${device} diff --git a/branches/WOF2-3/ulp/dapl/test/udapl/dirs b/branches/WOF2-3/ulp/dapl/test/udapl/dirs new file mode 100644 index 00000000..fc0447f1 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl/test/udapl/dirs @@ -0,0 +1 @@ +DIRS=dapltest diff --git a/branches/WOF2-3/ulp/dapl2/AUTHORS b/branches/WOF2-3/ulp/dapl2/AUTHORS new file mode 100644 index 00000000..b2c6a581 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/AUTHORS @@ -0,0 +1,17 @@ +This is an incomplete list of people who have contributed to the +DAPL project: + + Caitlin Bestler + Philip Christopher + Jay Danielsen + Arlin Davis + Tom Duffy + Matthew Finlay + Jimmy Hill + James Lentini + Gil Rubin + Steve Sears + Randy Smith + Stan Smith + Anthony Topper + Steve Wise diff --git a/branches/WOF2-3/ulp/dapl2/COPYING b/branches/WOF2-3/ulp/dapl2/COPYING new file mode 100644 index 00000000..35ba3196 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/COPYING @@ -0,0 +1,28 @@ +# +# Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. +# Copyright (c) 2005 Voltaire Inc. All rights reserved. +# Copyright (c) 2005-2010 Intel Corporation. All rights reserved. +# Copyright (c) 2004-2005, Mellanox Technologies, Inc. All rights reserved. +# Copyright (c) 2003 Topspin Corporation. All rights reserved. +# Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. +# +# This Software is licensed under one of the following licenses: +# +# 1) under the terms of the "Common Public License 1.0" a copy of which is +# in the file LICENSE.txt in the root directory. +# +# 2) under the terms of the "The BSD License" a copy of which is in the file +# LICENSE2.txt in the root directory. +# +# 3) under the terms of the "GNU General Public License (GPL) Version 2" a +# copy of which is in the file LICENSE3.txt in the root directory. +# +# 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. +# diff --git a/branches/WOF2-3/ulp/dapl2/ChangeLog b/branches/WOF2-3/ulp/dapl2/ChangeLog new file mode 100644 index 00000000..62225bdc --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/ChangeLog @@ -0,0 +1,5079 @@ +commit f85be199252d12d27c7b7814771a4ca83a43d0c8 +Author: Arlin Davis +Date: Mon Aug 9 14:25:09 2010 -0700 + + common: increase default logging to include warnings + + Signed-off-by: Arlin Davis + +commit 59489448a7918ab2a1a4b9bcac7e4661cdd97a23 +Author: Arlin Davis +Date: Mon Aug 9 14:19:50 2010 -0700 + + common: add more debug levels for cm logging + + DAPL_DBG_TYPE_CM_EST = 0x8000, + DAPL_DBG_TYPE_CM_WARN = 0x10000 + + Add level for connection establishment and events + and for retries/timer events. + + Signed-off-by: Arlin Davis + +commit 70c509bca8409d55ad7c4a248f453956d163778b +Author: Arlin Davis +Date: Mon Aug 2 09:51:30 2010 -0700 + + common: cleanup CR linkings after DTO error on EP + + Add cleanup to remove CR from SP and EP + during DTO errors in dapli_evd_cqe_to_event. + + dapl_sp_remove_ep needs to remove cr_ptr + reference from EP before freeing cr object. + + Signed-off-by: Arlin Davis + +commit 319430b3bbfb8692dd3d21a21633bfee74cf5b7c +Author: Arlin Davis +Date: Mon Aug 2 09:49:23 2010 -0700 + + ucm: cleanup CM debug warning messages + + Signed-off-by: Arlin Davis + +commit 7118731a890e9188bb02dc7a5b21ffd832855e9e +Author: Arlin Davis +Date: Fri Jul 23 15:17:53 2010 -0700 + + scm, ucm: improperly handles pkey check/query in host order + + Convert consumer input to network order before verbs + query pkey check. + + Signed-off-by: Arlin Davis + +commit c5504925b8b98006f421d53475e8ecd55b76f9dd +Author: Arlin Davis +Date: Mon Jul 12 15:57:34 2010 -0700 + + The linux compatability header file _errno.h is moving out of verbs.h. + Include _errno.h in the windows osd header files, similar to how + errno.h is included in the linux osd header files. + + Signed-off-by: Sean Hefty + +commit 455e9d6d0aeb753a9ecb4a130b0b237e1ffd4146 +Author: Arlin Davis +Date: Wed Jun 30 12:03:41 2010 -0700 + + windows: update SOURCES files to link winverbs.lib, which is + needed for common ofa providers. + + Signed-off-by: Sean Hefty + +commit b441934f5e55582ef01a91c01da720334345a452 +Author: Arlin Davis +Date: Thu Jun 17 12:58:22 2010 -0700 + + Release 2.0.29 + + Signed-off-by: Arlin Davis + +commit 6c6a482b8ad33d134f0631019b249bd0fea71007 +Author: Arlin Davis +Date: Thu Jun 17 12:40:21 2010 -0700 + + scm, ucm: add pkey, pkey_index, sl override for QP's + + On a per open basis, add environment variables + DAPL_IB_SL and DAPL_IB_PKEY and use on + connection setup (QP modify) to override default + values of 0 for SL and PKEY index. If pkey is + provided then find the pkey index with + ibv_query_pkey for dev_attr.max_pkeys. + Will be used for RC and UD type QP's. + + Signed-off-by: Arlin Davis + +commit 876942781e9bf72302184f3534a2ddc4068550ac +Author: Arlin Davis +Date: Thu Jun 10 11:40:45 2010 -0700 + + cma: remove dependency on rdma_cma_abi.h + + Signed-off-by: Arlin Davis + +commit b34ea37650b5eefeedfc463345775ff568df259e +Author: Arlin Davis +Date: Wed Jun 2 14:13:05 2010 -0700 + + configure: need a false conditional for verbs attr.link_layer member check + + Signed-off-by: Arlin Davis + +commit 977f11871d3d4e98f602f890ade1c31cf4169c9c +Author: Arlin Davis +Date: Wed Jun 2 10:05:03 2010 -0700 + + ucm: incorrectly freeing port on passive side after reject + + cm_release was incorrectly freeing a client port + assuming it was the server listening port. Move + the listening port cleanup to remove_conn_listner + and only cleanup client ports in cm_release. + + Error Messages indicating problem: + + CM_REQ retry 1 [lid, port, qpn]: 9 ff9a 340085 -> 9 6fa 34004e Time(ms) 1999 > 1600 + DUPLICATE: op REQ st CM_CONNECTED [lid, port, qpn]: 9 6fa 0x0 <- 0x9 ff9a 0x340085 + + Signed-off-by: Arlin Davis + +commit 7aedfb1e9dcb9e2841ebe3496bb9aae33c1f6a5b +Author: Arlin Davis +Date: Wed Jun 2 09:45:42 2010 -0700 + + ucm: modify debug CM output for consistency, all ports, qpn in hex + + Signed-off-by: Arlin Davis + +commit 8e776ff0621cee1824be224b7a32f79e89b0ebc2 +Author: Arlin Davis +Date: Mon May 24 16:44:25 2010 -0700 + + Release 2.0.28 + + Signed-off-by: Arlin Davis + +commit 8fdbd949ef464aa57b13743ab087ea72f035fbc3 +Author: Arlin Davis +Date: Mon May 24 16:28:05 2010 -0700 + + config: add conditional check for new verbs port_attr.link_layer + + Check for link_layer type ETHERNET and set global for GID + configuration on modify QP. + + Signed-off-by: Arlin Davis + +commit 1ce0875fb2ac6120cfee006b48a20a4ec38f599b +Author: Arlin Davis +Date: Mon May 24 10:30:28 2010 -0700 + + dat.conf: update manpage with latest provider information, add examples + + Add information regarding OpenFabrics provider choices + and explain cma, scm, and ucm providers. + + Signed-off-by: Arlin Davis + +commit 9c42d5872feb07f25f003e01263a3062ebc3bdbb +Author: Arlin Davis +Date: Wed May 19 16:38:53 2010 -0700 + + cma, scm: new provider entries for Mellanox RDMA over Ethernet device + + Add options for netdev eth2 and eth3 for cma and for device mlx4_0 port 1 and 2 for scm. + + ofa-v2-cma-roe-eth2 u2.0 nonthreadsafe default libdaplofa.so.2 dapl.2.0 "eth2 0" "" + ofa-v2-cma-roe-eth3 u2.0 nonthreadsafe default libdaplofa.so.2 dapl.2.0 "eth3 0" "" + ofa-v2-scm-roe-mlx4_0-1 u2.0 nonthreadsafe default libdaploscm.so.2 dapl.2.0 "mlx4_0 1" "" + ofa-v2-scm-roe-mlx4_0-2 u2.0 nonthreadsafe default libdaploscm.so.2 dapl.2.0 "mlx4_0 2" "" + + Signed-off-by: Arlin Davis + +commit d947e05317fe7fef19c90f772ec8f458ff52b196 +Author: Arlin Davis +Date: Wed May 19 15:17:58 2010 -0700 + + dapltest: server info devicename is not large enough for dapl_name storage + + Server info device name is a 80 char array but the dapl device name + that is copied is 256 bytes. Increase started_server.devicename definition. + Chalk one up for windows SDK OACR (auto code review). + + Signed-off-by: Sean Hefty + +commit c7a7a886af194cf735ee1eb62d9e14967d51249a +Author: Arlin Davis +Date: Wed May 19 14:48:49 2010 -0700 + + windows: comp_channel.cpp is included by util.c in the openib_common. + + Remove it from device.c in individual providers to avoid + duplicate definitions. + + Line endings were corrected to linux format from windows as part of + the change. + + Signed-off-by: Sean Hefty + +commit bcaa400778d14a977d5cd224056baa0cff06126d +Author: Arlin Davis +Date: Wed May 19 14:45:55 2010 -0700 + + windows: need to include linux directory to pick up _errno.h + + Signed-off-by: Sean Hefty + +commit c616a8549db461e39feed71f0f10228313d17b90 +Author: Arlin Davis +Date: Mon May 17 16:22:30 2010 -0700 + + scm: check for hca object before signaling thread + + There may not be an hca object attached to cm object + when freeing during cleanup. + + Signed-off-by: Arlin Davis + +commit 1dbba72741da267f71903a9f2ec03628f3e8a47a +Author: Arlin Davis +Date: Mon May 17 16:15:21 2010 -0700 + + scm, cma: fini code can be called multiple times and hang via fork + + The providers should protect against forked child exits and + not cleanup until the parent init actually exits. Otherwise, + the child will hang trying to cleanup dapl thread. Modify to + check process id for proper init to fini cleanup and limit + cleanup to parent only. + + Signed-off-by: Arlin Davis + +commit b35cb1b16a9dda349dbb19bce9f9bd4afb7240a4 +Author: Arlin Davis +Date: Fri May 14 16:20:52 2010 -0700 + + scm: add option to use other network devices with environment variable DAPL_SCM_NETDEV + + New environment variable can be used to set the netdev + for sockets to use instead of the default network device + returned using gethostname. + + Signed-off-by: Arlin Davis + +commit cfdf8bb8951b1c19b8e42d58e4ec26070fdc078e +Author: Arlin Davis +Date: Fri May 14 10:27:50 2010 -0700 + + scm: cr_thread occasionally segv's when disconnecting all-to-all MPI static connections + + Note: no valid calltrace for segv on cr_thread because + of state changing in switch statement from another + thread, jumped unknown location. + + Program received signal SIGSEGV, Segmentation fault. + [Switching to Thread 0x41a65940 (LWP 1328)] + 0x00002b2e7d9d5134 in ?? () + + Add cm object locking on all state change/checking. When + freeing CM object wakeup cr_thread to process + state change to CM_FREE. + + Signed-off-by: Arlin Davis + +commit 4b04afc32940ac42fb2a9bc789a537b527d149fe +Author: Arlin Davis +Date: Thu May 13 10:31:17 2010 -0700 + + scm: SOCKOPT ERR Connection timed out on large clusters + + Large scale all to all connections on +1000 cores + the listen backlog is reached and SYN's are dropped + which causes the connect to timeout. Retry connect + on timeout errors. + + Signed-off-by: Arlin Davis + +commit 625369f991982f020c04156f312ecf2ecafd77b3 +Author: Arlin Davis +Date: Mon May 10 12:46:17 2010 -0700 + + ucm: UD mode, active side cm object released to soon, the RTU could be lost. + + Will see following message with DAPL_DBG_TYPE set for Errors & Warnings (0x3): + ucm_recv: NO MATCH op REP 0x120 65487 i0x60005e c0x60005e < 0xd2 19824 0x60006a + + The cm object was released on the active side after the connection + was established, RTU sent. This is a problem if the RTU is lost + and the remote side retries the REPLY. The RTU is never resent. + Keep the cm object until the EP is destroyed. + + Signed-off-by: Arlin Davis + +commit 83eec7f19a7442fe568dea685cee7b02fef2f4d1 +Author: Arlin Davis +Date: Mon May 10 12:35:51 2010 -0700 + + cma, ucm: cleanup issues with dat_ep_free on a connected EP without disconnecting. + + During EP free, disconnecting with ABRUPT close flag, the disconnect should wait + for the DISC event to fire to allow the CM to be properly destroyed upon return. + + The cma must also release the lock when calling the blocking rdma_destroy_id given + the callback thread could attempt to acquire the lock for reference counting. + + Signed-off-by: Arlin Davis + +commit da83172db68d05f54b2c1c77b84ecf86dea0c693 +Author: Arlin Davis +Date: Wed Apr 28 15:37:27 2010 -0700 + + ucm: increase default UCM retry count for connect reply to 15 + + On very large clusters UCM is timing out with retries at 10. + + Signed-off-by: Arlin Davis + +commit 5c710a197bb60268e99e8d1cd7fa26f89b366172 +Author: Arlin Davis +Date: Tue Apr 27 11:20:08 2010 -0700 + + scm: remove modify QP to ERR state during disconnect on UD type QP + + The disconnect on a UD type QP should not modify QP to error + since this is a shared QP. The disconnect should be treated + as a NOP on the UD type QP and only be transitioned during + the QP destroy (dat_ep_free). + + Signed-off-by: Arlin Davis + +commit 64c8009f7ba48c22a6829862447ab5f67c66ba55 +Author: Arlin Davis +Date: Thu Apr 8 16:32:02 2010 -0700 + + windows: remove static paths from dapltest scripts + + signed-off-by: stan smith + +commit 84b78b0b586ee25c7ab78e2c5f7f19a3ce3f21ee +Author: Arlin Davis +Date: Thu Apr 8 09:38:57 2010 -0700 + + common: EP links to EVD, PZ incorrectly released before provider CM objects freed. + + unlink/clear references after ALL CM objects linked to EP are freed. + Otherwise, event processing via CM objects could reference the handles + still linked to EP. After CM objects are freed (blocking) these handles + linked to EP are guaranteed not to refereence from underlying provider. + + Signed-off-by: Arlin Davis + +commit 297e149e7af631663ecc60472a3ee093a7f72059 +Author: Arlin Davis +Date: Wed Apr 7 11:12:21 2010 -0700 + + common: remove unnecessary lmr lkey hashing and duplicate lkey checking + + lmr lkey hashing is too restrictive given the returned lkey could be + the same value for different regions on some rdma devices. Actually, + this checking is really unecesssary and requires considerable overhead + for hashing so just remove hashing of lmr lkey's. Let verbs device + level do the checking and validation. + + Signed-off-by: Arlin Davis + +commit 96fba2ee7a0a1766f200c9486e62aad46d18bb09 +Author: Arlin Davis +Date: Mon Mar 29 12:20:34 2010 -0800 + + ibal: output completion code in deciaml & hex as intended + + sign-off-by: stan smith + +commit 753f7d35c814367f431deeb307e6decd933a8b5a +Author: Arlin Davis +Date: Tue Mar 16 15:02:44 2010 -0800 + + ucm: set timer during RTU_PENDING state change. + + The timer thread may pick up an unitialized timer + value and timeout before the reply was sent. + + Signed-off-by: Arlin Davis + +commit 9fc851021d91b282054cf28b4f83f7e5d376f228 +Author: Arlin Davis +Date: Tue Mar 16 14:47:58 2010 -0800 + + ucm: fix issues with new EP to CM linking changes + + Add EP locking around QP modify + Remove release during disconnect event processing + Add check in cm_free to check state and schedule thread if necessary. + Add some additional debugging + Add processing in disconnect_clean for conn_req timeout + Remove extra CR's + + Signed-off-by: Arlin Davis + +commit a5da5e4dac52366a9fe9efeb9a128bd4511481e2 +Author: Arlin Davis +Date: Tue Mar 16 14:18:06 2010 -0800 + + scm: add EP locking and cm checking to socket cm disconnect + + Signed-off-by: Arlin Davis + +commit 7f733cd1a9acd4b9b270a807673290362050053d +Author: Arlin Davis +Date: Tue Mar 16 09:44:44 2010 -0800 + + scm: new cm_ep linking broke UD mode over socket cm + + Add EP locking around modify_qp for EP state. + Add new dapli_ep_check for debugging EP + Cleanup extra CR's + Change socket errno to dapl_socket_errno() abstraction + + Signed-off-by: Arlin Davis + +commit a528267020972e0c449f240ba72a0cc80a5d372e +Author: Arlin Davis +Date: Tue Mar 16 09:17:01 2010 -0800 + + openib common: add some debug prints to help isolate QP type issues + + Signed-off-by: Arlin Davis + +commit fdfdc439d091c878c74d23b9ac46a3320379199d +Author: Arlin Davis +Date: Tue Mar 16 09:15:12 2010 -0800 + + common: dapl_event_str function missing 2 IB extended events + + Add all IB extended events in event string print function + + Signed-off-by: Arlin Davis + +commit 2bf3eb939e9a584ae0fe2de70f16cdcca8acf014 +Author: Arlin Davis +Date: Tue Mar 16 09:12:11 2010 -0800 + + common: dat_ep_connect should not set timer UD endpoints + + connect for UD type is simply AH resolution and doesn't + need timed. The common code is not designed to handle + multiple timed events on connect requests so just ignore + timing UD AH requests. + + Signed-off-by: Arlin Davis + +commit 73ca06debe4735dfc11f44076a13dde079657b2e +Author: Arlin Davis +Date: Mon Mar 15 10:23:47 2010 -0800 + + ucm: fix error path during accept_usr reply failure + + if accept_usr fails when sending reply the EP was + being linked to CM instead of properly unlinked. + + Signed-off-by: Arlin Davis + +commit 944ef4445faceeb90bb61d4e377274ad0fd6711f +Author: Arlin Davis +Date: Mon Mar 8 13:56:28 2010 -0800 + + ibal: add missing windows makefile + + Signed-off-by: Arlin Davis + +commit 1d53e8eb90e6f74b41e7767e1c71851ff4ec73fd +Author: Arlin Davis +Date: Mon Mar 8 12:53:45 2010 -0800 + + ibal: changes for EP to CM linking and synchronization. + + Windows IBAL changes to allocate and manage CM objects + and to link them to the EP. This will insure the CM + IBAL objects and cm_id's are not destroy before EP. + Remove windows only ibal_cm_handle in EP structure. + + Signed-off-by: Arlin Davis + +commit 4b939076aa32bb52957fcc6791e187c9433d4c24 +Author: Arlin Davis +Date: Wed Feb 24 12:00:07 2010 -0800 + + scm: add support for canceling conn request that times out. + + print warning message during timeout. + + Signed-off-by: Arlin Davis + +commit f38fc04d517ee6c0560b271298293c56cc619522 +Author: Arlin Davis +Date: Wed Feb 24 11:28:04 2010 -0800 + + scm, cma, ucm: consolidate dat event/provider event translation + + Signed-off-by: Arlin Davis + +commit 41739dab38a4be8076ecd9e61b5e175cf91ab322 +Author: Arlin Davis +Date: Wed Feb 24 11:26:25 2010 -0800 + + common: missed linking changes from atomic to acquire/release + + Signed-off-by: Arlin Davis + +commit 7ff4f840bf1150fa2c2f541c93d810622ea9733b +Author: Arlin Davis +Date: Wed Feb 24 10:03:57 2010 -0800 + + common: add CM-EP linking to support mutiple CM's and proper protection during destruction + + Add linking for CM to EP, including reference counting, to insure syncronization + during creation and destruction. A cm_list_head has been added to the EP object to + support multiple CM objects (UD) per EP. If the CM object is linked to an EP it + cannot be destroyed. + + Signed-off-by: Arlin Davis + +commit c9fbd6e7a8131d4077039d5da716b618727d4009 +Author: Arlin Davis +Date: Tue Feb 23 16:26:41 2010 -0800 + + Release 2.0.27-1 + + Signed-off-by: Arlin Davis + +commit 454c27b1f357c7c3070e459b25d12929f86304ca +Author: Arlin Davis +Date: Mon Feb 22 09:42:17 2010 -0800 + + windows: add scm makefile + + Signed-off-by: Arlin Davis + +commit 66ac48d5280bcf0453760c6e22909de6b8519b6d +Author: Arlin Davis +Date: Mon Feb 22 09:41:13 2010 -0800 + + Windows does not require rdma_cma_abi.h, move the include from common code and to OSD file. + + Signed-off-by: stan smith + +commit c05c41c31f01e1ddef91e92998ca66d258fafe3d +Author: Arlin Davis +Date: Fri Feb 19 14:52:01 2010 -0800 + + Windows patch to fix IB_INVALID_HANDLE name collision + + signed-off-by: stan smith + +commit 712e7e5ba71f8a4344dfff481a9be870eefefe25 +Author: Arlin Davis +Date: Mon Feb 8 13:49:35 2010 -0800 + + scm: dat_ep_connect fails on 32bit servers + + memcpy for remote IA address uses incorrect sizeof for a pointer type. + + Signed-off-by: Arlin Davis + +commit 3040fa78d7d22c8f76c88dc77cedde09f016eb67 +Author: Arlin Davis +Date: Fri Feb 5 11:51:16 2010 -0800 + + undefined symbol: dapls_print_cm_list + + call prototype should be dependent on DAPL_COUNTERS. + + Signed-off-by: Arlin Davis + +commit cbeebe422b952d679f49429be8ba045a62d7f4ac +Author: Arlin Davis +Date: Fri Feb 5 11:39:21 2010 -0800 + + Cleanup CM object lock before freeing CM object memory + + Running windows application verifiier for uDAPL validation + for all 3 providers. Cleanup memory lock leaks found + by verifier. + + Signed-off-by: Arlin Davis + +commit 855a8e4aa83fa2e4f7847122415106f49286f4ca +Author: Arlin Davis +Date: Wed Feb 3 16:21:30 2010 -0800 + + destroy verbs completion channels created via ia_open or ep_create. + + Completion channels are created with ia_open for CNO events and + with ep_create in cases where DAT allows EP(qp) to be created with + no EVD(cq) and IB doesn't. These completion channels need to be + destroyed at close along with a CQ for the EP without CQ case. + + Signed-off-by: Arlin Davis + +commit 4da540591148e47dd912851cc7314776f2f7622e +Author: Arlin Davis +Date: Wed Feb 3 11:06:45 2010 -0800 + + Update Copyright file and include the 3 license files in distribution + + Signed-off-by: Arlin Davis + +commit 9011abd4b1470c65bfe81eef5a2f3a81060cec81 +Author: Arlin Davis +Date: Tue Feb 2 14:43:03 2010 -0800 + + When copying private_data out of rdma_cm events, use the + reported private_data_len for the size, and not IB maximums. + This fixes a bug running over the librdmacm on windows, where + DAPL accessed invalid memory. + + Signed-off-by: Sean Hefty + Signed-off-by: Arlin Davis + +commit 5da33bb3b9c230c08492f85d13caa330ce65906e +Author: Sean Hefty +Date: Thu Jan 28 10:19:20 2010 -0800 + + dapl/cma: fix referencing freed address + + DAPL uses a pointer to reference the local and remote addresses + of an endpoint. It expects that those addresses are located + in memory that is always accessible. Typically, for the local + address, the pointer references the address stored with the DAPL + HCA device. However, for the cma provider, it changes this pointer + to reference the address stored with the rdma_cm_id. + + This causes a problem when that endpoint is connected on the + passive side of a connection. When connect requests are given + to DAPL, a new rdma_cm_id is associated with the request. The + DAPL code replaces the current rdma_cm_id associated with a + user's endpoint with the new rdma_cm_id. The old rdma_cm_id is + then deleted. But the endpoint's local address pointer still + references the address stored with the old rdma_cm_id. The + result is that any reference to the address will access freed + memory. + + Fix this by keeping the local address pointer always pointing + to the address associated with the DAPL HCA device. This is about + the best that can be done given the DAPL interface design. + + Signed-off-by: Sean Hefty + +commit 66dbb5f20bf494eb3f5041655b478059165c5f1b +Author: Sean Hefty +Date: Tue Jan 26 15:13:03 2010 -0800 + + dapl: move close device after async thread is done + + using it + + Before calling ibv_close_device, wait for the asynchronous + processing thread to finish using the device. This prevents + a use after free error. + + Signed-off-by: Sean Hefty + +commit 560b235adc799fa710571ca63cbc3e4fa6374ff2 +Author: Arlin Davis +Date: Mon Jan 11 09:03:10 2010 -0800 + + Release 2.0.26-1 + + Signed-off-by: Arlin Davis + +commit 73dfb32ace6aff2fdb21e54689342fd551822286 +Author: Arlin Davis +Date: Tue Dec 22 14:00:33 2009 -0800 + + openib_common: add check for both gid and global routing in RTR + + check for valid gid pointer along with global route setting + during transition to RTR. Add more GID information to + debug print statement in qp modify call. + + Signed-off-by: Arlin Davis + +commit 7aab18fd8ff3f201b0a4b6c76896667b29f103c4 +Author: Arlin Davis +Date: Fri Dec 4 12:31:22 2009 -0800 + + openib_common: remote memory read privilege set multi times + + duplicate setting of read privilege in dapls_convert_privileges + + Signed-off-by: Arlin Davis + +commit 016e2c40b8ac2fe18993e9fb7122ecb9b439e5eb +Author: Arlin Davis +Date: Fri Dec 4 12:25:30 2009 -0800 + + ucm, scm: DAPL_GLOBAL_ROUTING enabled causes segv + + socket cm and ud cm providers support QP modify with is_global + set and GRH. New v2 providers didn't pass GID information + in modify_qp RTR call and incorrectly byte swapped the already + network order GID. Add debug print of GID during global modify. + + Signed-off-by: Arlin Davis + +commit 7b0c596c7b4ad619f65da9f79dcbc4376e651dde +Author: Arlin Davis +Date: Tue Nov 24 22:16:58 2009 -0800 + + Release 2.0.25-1 + + Signed-off-by: Arlin Davis + +commit 3197bffff478ad7ff5eff9220fa0528e42e6b56e +Author: Arlin Davis +Date: Tue Nov 24 22:15:46 2009 -0800 + + winof scm: initialize opt for NODELAY setsockopt + + Signed-off-by: Arlin Davis + +commit 8559ec069329249592f367b5b8f61427cbad0a46 +Author: Arlin Davis +Date: Tue Nov 24 11:29:46 2009 -0800 + + Release 2.0.25 + + Signed-off-by: Arlin Davis + +commit 0983c66cbd9511128c1fa221470c4c983903e420 +Author: Arlin Davis +Date: Tue Nov 24 08:58:44 2009 -0800 + + winof cma: windows definition for EADDRNOTAVAIL missing + + Signed-off-by: stan smith + +commit 4fbbcfa1d7bf7a843b27e351d35f3ffbc2ac4db8 +Author: Arlin Davis +Date: Tue Nov 24 08:54:26 2009 -0800 + + scm: client side setsockopt NODELAY fails if data arrives before setting + + Move setsockopt before connect to avoid race with data. + Seems to fail on windows. Not seen on linux. + + Signed-off-by: Arlin Davis + +commit 9dfa9a06d55101fed0773028ce7ab85330514c67 +Author: Arlin Davis +Date: Wed Nov 18 09:52:40 2009 -0800 + + cma: setup_listener Cannot assign requested address + + Colliding with RDS port of 18634. rdma_cm can return + either EADDRINUSE or EADDRNOTAVAIL if the bind fails. + Add check for either and return proper DAT_CONN_QUAL_IN_USE. + + Signed-off-by: Arlin Davis + +commit 0698fb56d533a5225cbc3a5a4b8ab2e2d56b7502 +Author: Arlin Davis +Date: Wed Nov 18 09:43:38 2009 -0800 + + common: seg fault in dapl_evd_wait with multi-thread application using CNO's. + + If we are dealing with event streams besides a CQ event stream, + be conservative and set producer side locking. Otherwise, no. + Check for CNO is missing, CNO is not considered CQ event stream. + + Signed-off-by: Arlin Davis + +commit 4d26a280572a58248b0796e4d5ed01ea5d67be46 +Author: Arlin Davis +Date: Wed Nov 18 09:37:48 2009 -0800 + + ucm: inbound DREQ/DREP handshake should transition QP. + + During release, when receiving a disconnect request from remote peer + instead of a disconnect call from the client, the QP didn't get properly + set in ERR state and didn't flush the queue during disconnect processing. + + Signed-off-by: Arlin Davis + +commit 87965cd15bbfa38b00ed2d77a4ea5a76f76cf4a3 +Author: Arlin Davis +Date: Mon Nov 2 08:24:53 2009 -0800 + + winof: Remove duplicate include of comp_channel.cpp from cm.c as it is included in opensm_ucb/device.c. + + Signed-off-by: stan smith + +commit 737fa288b72fad19a1fc3e762eb9f2c471ce6ddd +Author: Arlin Davis +Date: Fri Oct 30 13:19:21 2009 -0800 + + Release 2.0.24 + + Signed-off-by: Arlin Davis + +commit 9fe7506ff9ddf1ae6297cfc6a9dd4d6a57e1939e +Author: Arlin Davis +Date: Fri Oct 30 12:57:22 2009 -0800 + + winof: Utilize WinOF version of inet_ntop() for Windows OSes which do not support inet_ntop(). + + Signed-off-by: stan smith + +commit d56c645a2bf234e9e0cf215b112c2aa9d5e01945 +Author: Arlin Davis +Date: Fri Oct 30 07:17:26 2009 -0800 + + ucm: windows build issue with new CQ completion channel + + Signed-off-by: Arlin Davis + +commit 2d2e7e1e185c08542ee31b0e77561a1eeb4bde6c +Author: Arlin Davis +Date: Fri Oct 30 06:35:33 2009 -0800 + + winof: add ucm provider to windows build + + Signed-off-by: Arlin Davis + +commit 94b2206093607214e0a9709651460692e8196e1c +Author: Arlin Davis +Date: Fri Oct 30 06:32:56 2009 -0800 + + winof: add missing build files for ibal, scm + + Signed-off-by: Arlin Davis + +commit 66b76d7a8035b9164b69781d7630a0c77ce1bb5a +Author: Arlin Davis +Date: Wed Oct 28 09:52:50 2009 -0800 + + scm: connection peer resets under heavy load, incorrect event on error + + Under heavy load, we get a peer reset from the remote stack. In this + case retry the socket connection for this QP setup. + + Add debugging with PID's and socket ports to help isolate + these types of socket scaling issues. + + Report correct UD event during error, check remote_ah creation. + + Fix dapl_poll return codes for single event type only. + + Signed-off-by: Arlin Davis + +commit f8108a9bda0200355107fdd6c43cb5885f47d648 +Author: Arlin Davis +Date: Wed Oct 28 09:47:37 2009 -0800 + + ucm: increase default reply and rtu timeout values. + + Signed-off-by: Arlin Davis + +commit 9c13d0d01c78eeb5071e802fbb53811cdb377059 +Author: Arlin Davis +Date: Wed Oct 28 07:48:20 2009 -0800 + + ucm: change some debug message levels and add check for valid UD REPLY during retries. + + Signed-off-by: Arlin Davis + +commit 1c404bb3dcc0a45e21ef3aa973d59714413beae0 +Author: Arlin Davis +Date: Tue Oct 27 10:37:45 2009 -0800 + + ucm: increase timers during subsequent retries + + check/process create_ah errors during connect phase + cleanup some debug messaging. + + Signed-off-by: Arlin Davis + +commit cd8c48586f53e846de4fbe10994b73ba457f6406 +Author: Arlin Davis +Date: Mon Oct 19 10:38:36 2009 -0700 + + ucm, scm: address handles need destroyed when freeing Endpoints with UD QP's. + + Signed-off-by: Arlin Davis + +commit ce19f5744c0dd9461c09d999b309e8f0e2242767 +Author: Arlin Davis +Date: Fri Oct 16 14:42:00 2009 -0700 + + openib_common: ignore pd free errors, clear pd_handle and return. + + some older adapters have some issues + with pd free so just clear handle and return + + Signed-off-by: Arlin Davis + +commit 81f5ac17d9039e2edcd8324f7d5ed5f66fcff9f2 +Author: Arlin Davis +Date: Fri Oct 16 08:52:21 2009 -0700 + + ucm: using UD type QP's, ucm reports wrong reject event when user rejects AH resolution request. + + During rejects, both usr and ucm internal, the qp_type does not get initialized + so the check for UD type QP messages fail on active side and the wrong + event gets generated. Initialize saddr.ib information before sending reject + back to active side. + + Signed-off-by: Arlin Davis + +commit f0214e5a7a81a68819d308cb921eb75f5246207d +Author: Arlin Davis +Date: Fri Oct 16 07:57:25 2009 -0700 + + ucm, scm, cma: Fix CNO support on DTO type EVD's + + EVD wait_object should be used for CNO processing + and not the direct CQ event channels. Add proper + checking for DTO type EVD's with CNO at wait + and wakeup. + + UCM missing support for collective EVD's under a + CNO. Add support to create common channel for + collective EVD's during device open. Add support + in cm_thread to check this channel. Also, + during disconnect, move QP to error to properly + flush queue instead of moving to reset and init. + + Signed-off-by: Arlin Davis + +commit 960950a7d9f5437dd831bd56ca2ad0c06cb4e324 +Author: Arlin Davis +Date: Thu Oct 15 09:19:45 2009 -0700 + + ucm: fix lock init bug in ucm_cm_find + + the lock should be setup as pointer to lock + not lock structure. Cleanup lock and list + in cm_find function and cm_print function. + + Add debug aid by passing process id in + msg resv area. cleanup cr references + and change to cm for consistency. + + Signed-off-by: Arlin Davis + +commit f86fec772f2d82eaf60228d288b295e0b7b86c59 +Author: Arlin Davis +Date: Wed Oct 14 10:03:47 2009 -0700 + + ucm: fix build problem with latest windows ucm changes + + define dapls_thread_signal as inline + + Signed-off-by: Arlin Davis + +commit 87b6c8ba92f3063a35d49bdb49d6cd0a5100a36c +Author: Sean Hefty +Date: Wed Oct 14 09:34:22 2009 -0700 + + Signed-off-by: Sean Hefty + +commit 9fdd8d74f2cba83e9cf513256933f5241495c1da +Author: Sean Hefty +Date: Wed Oct 14 09:34:18 2009 -0700 + + The HCA should not be closed until all resources have been released. + This results in a hang on windows, since closing the device frees + the event processing thread. + + Signed-off-by: Sean Hefty + +commit f9833db469f2d686842bb1d52d1ea53b74fa72a8 +Author: Sean Hefty +Date: Wed Oct 14 09:34:13 2009 -0700 + + Fix build warning when compiling on 32-bit systems. + + Signed-off-by: Sean Hefty + +commit c80515bd4b1bd11a125dc17e3f7db44240ee1fff +Author: Sean Hefty +Date: Wed Oct 14 09:34:07 2009 -0700 + + Trying to deregister the same memory region twice leads to an + application crash on windows. + + Signed-off-by: Sean Hefty + +commit 6aa2c0d901daa9cfca7e771c1df2ead074d230bd +Author: Arlin Davis +Date: Wed Oct 14 07:59:23 2009 -0700 + + dat: reduce debug message level when parsing for location of dat.conf + + Don't output failover to default /etc/dat.conf from + sysconfdir at ERROR level. Reduce to DAT_OS_DBG_TYPE_SR. + + Signed-off-by: Arlin Davis + +commit e4038e078747201b57203f16ba793b7fc22c12f2 +Author: Arlin Davis +Date: Thu Oct 8 16:23:22 2009 -0700 + + ucm: update ucm provider for windows environment + + add dapls_thread_signal abstraction and a new + cm_thread function specific for windows. + + Signed-off-by: Sean Hefty + Signed-off-by: Arlin Davis + +commit d80ce42390eb57b9c4f816b4df063f90bd5699bc +Author: Arlin Davis +Date: Thu Oct 8 16:02:52 2009 -0700 + + ucm: add timer/retry CM logic to the ucm provider + + add reply, rtu and retry count options via + environment variables. Times in msecs. + DAPL_UCM_RETRY 10 + DAPL_UCM_REP_TIME 400 + DAPL_UCM_RTU_TIME 200 + + Add RTU_PENDING and DISC_RECV states + + Add check timer code to the cm_thread + and the option to the select abstaction + to take timeout values in msecs. + DREQ, REQ, and REPLY will all be timed + and retried. + + Split out reply code and disconnect_final + code to better facilitate retry timers. + Add checking for duplicate messages. + + Added new UD extension events for errors. + DAT_IB_UD_CONNECTION_REJECT_EVENT + DAT_IB_UD_CONNECTION_ERROR_EVENT + + Signed-off-by: Arlin Davis + +commit 1186bfc949f4bb7278c30c2c59b7fcb6d5142638 +Author: Arlin Davis +Date: Fri Oct 2 14:49:52 2009 -0700 + + Release 2.0.23 + + Signed-off-by: Arlin Davis + +commit a5f1220cfd96983c9c89a595d80fab7ddcb1a954 +Author: Arlin Davis +Date: Fri Oct 2 14:48:15 2009 -0700 + + cma: cannot reuse the cm_id and qp for new connection, must reallocate a new one. + + When merging common code base the dapls_ib_reinit_ep mistakely + modified QP to reset then init for all providers. Will + not work for rdma_cm (cma provider) since the cm_id cannot + be reused. Add build check for _OPENIB_CMA_ to pull in correct + free and reallocate method for reinit_ep. + + Signed-off-by: Arlin Davis + +commit 7b07435495de0938e59be064fe8642cfd739f1ac +Author: Arlin Davis +Date: Fri Oct 2 13:50:12 2009 -0700 + + scm, cma: update DAPL cm protocol revision with latest address/port changes + + CM protocol changed, roll revision to 6. + The socket cm could be competing with address space if + application is using sockets above to exchange information + like dapltest, and MPI consumers. Adjust port on listen + and connect to reduce the chance of port collision with + application above. + + Signed-off-by: Arlin Davis + +commit 9cc1e76b672f7ff1231b4d113bd4dd1a016d1410 +Author: Arlin Davis +Date: Fri Oct 2 12:47:37 2009 -0700 + + ucm: modify IB address format to align better with sockaddr_in6 + + Restructure the dcm_addr union to map the IB side + closer to sockaddr6 and initialize family to + AF_INET6 to insure callee allocates enough memory + for ucm dat_ia_address type. Put qpn in flowinfo + and gid in sin6_addr. Change the test suites + to print address information based on AF_INET + or AF_INET6 instead of using specific IB address + union from the provider. + + Signed-off-by: Arlin Davis + +commit f50dbe6e82bd471845adf27829b2e07234a0a86a +Author: Sean Hefty +Date: Wed Sep 30 14:29:03 2009 -0700 + + Add definition for getpid similar to that used by the other dtest apps. + + Signed-off-by: Sean Hefty + +commit 51147412fad72c00115b595955760e80ff0be7d5 +Author: Sean Hefty +Date: Wed Sep 30 14:28:57 2009 -0700 + + WinOF provides a common implementation of gettimeofday that should + be used instead. + + Signed-off-by: Sean Hefty + +commit 732fc84cee036126282715ea157bdb619fc11ec7 +Author: Sean Hefty +Date: Wed Sep 30 14:27:50 2009 -0700 + + The completion manager was updated to provide an abstraction that + better mimicked how fd's were used. Update dapl to use this + abstraction, rather than the older completion manager api. + + This helps minimize changes between linux and windows. + + Signed-off-by: Sean Hefty + +commit fc1855b7738838d3865389405f017b87d223f743 +Author: Arlin Davis +Date: Wed Sep 30 14:26:47 2009 -0700 + + dtestcm: remove IB verb definitions + + Remove gid and qp_type references from test app. + Print address infomation in sockaddr and + ucm provider format with qpn and lid. + + Signed-off-by: Arlin Davis + +commit 36a885d4267be7b3c6c1086372d321121ae03dee +Author: Arlin Davis +Date: Wed Sep 30 10:44:14 2009 -0700 + + dtest, dtestx: remove IB verb definitions + + remove gid and qp_type checking from test suite. + Print address infomation in sockaddr and + ucm provider format with qpn and lid. + + Signed-off-by: Arlin Davis + +commit 23445bbbd3a09f7f5e666a000d5c7c3b22dd95b3 +Author: Arlin Davis +Date: Mon Sep 28 10:59:36 2009 -0700 + + scm: tighten up socket options to insure similiar behavior on Windows and Linux. + + Add IPPROTO_TCP to create socket. Specify device IP address + when binding instead of INADDR_ANY and remove setsocketopt + REUSEADDR on the listen socket to avoid any issues with + portability. Don't want duplicate port bindings. + + Signed-off-by: Arlin Davis + +commit b31b64d60abe7c6c1a83484db97176d225076b30 +Author: Arlin Davis +Date: Mon Sep 28 10:46:26 2009 -0700 + + cma: improve serialization of destroy and event processing + + WinOF testing with slightly different scheduler and verbs + showed some issues with cleanup. Add better protection around + destroy and event processing thread. + + Remove destroy flag and add refs counting to conn objects + to block destroy until all references are cleared. Add + locking aroung ref counting and passive and active + event processing. + + Signed-off-by: Arlin Davis + +commit a4adf463695ba75beaa1fe79d514346bf5fe2cb5 +Author: Arlin Davis +Date: Mon Sep 28 10:42:52 2009 -0700 + + scm: improve serialization of destroy and state changes + + WinOF testing with slightly different scheduler and verbs + showed some issues with cleanup. Add better protection around + destroy and move state change before socket send to insure + correct state in multi-thread environment targeting the same + device on send and recv. + + Change DCM_RTU_PENDING to DCM_REP_PENDING and + and add static definition to local routines for better + readability. + + Signed-off-by: Arlin Davis + +commit 29358ccc587db55fe5f5a1b14eed9e0e31f5f02c +Author: Arlin Davis +Date: Thu Sep 17 08:56:06 2009 -0700 + + common: no cleanup/release code for timer thread + + dapl_set_timer() creates a thread to process timers for dat_ep_connect + but provides no mechanism to destroy/exit during dapl library unload. + Timers are initialized in library init code and should be released + in the fini code. Add a dapl_timer_release call to the dapl_fini + function to check state of timer thread and destroy before exiting. + + Signed-off-by: Arlin Davis + +commit e287ce12f5b0108ef83186aae305f25af8cdd02c +Author: Arlin Davis +Date: Thu Sep 17 08:53:29 2009 -0700 + + scm, cma: dapli_thread doesn't always get teminated on library close. + + DAPL doesn't actually wait for the async processing thread to exit before + allowing the library to close. It will wait up to 10 seconds, which under + heavy load isn't enough time. Since the thread is created by an application + level thread, it will continue to run as long as the application runs. But + if the application closes the library, then all library data and code is + invalid, which can result in the thread running something that's not + library code and accessing freed memory. + + With this change, I was able to run mpi ping-pong, 16 ranks on a single + system (scm provider) without crashes 1300 times. + + Signed-off-by: Sean Hefty + +commit 5bffe521c6ad7a5ce10457a5d7b25814522a0cde +Author: Arlin Davis +Date: Wed Sep 9 13:10:35 2009 -0700 + + ucm: tighten up locking with CM processing, state changes + + tighten up locking on CM processing and state changes + and reduce the send completion threshold to 50 from 100 + to replenish the request message faster. + + Signed-off-by: Arlin Davis + +commit e38daa8448bc3b73c53e54ffc9ac47b9cfc2af89 +Author: Arlin Davis +Date: Wed Sep 9 09:44:03 2009 -0700 + + ucm: For UD type QP's, return CR p_data with CONN_EST event on passive side. + + Intel MPI uses the p_data provided with CONN_EST as a reference to the + UD pair and remote rank. The ucm provider was overwriting the CR p_data + with the ACCEPT p_data. Change to save CR p_data but also provide + storage for user provided ACCEPT p_data in case the REPLY is lost + and needs retransmitted. + + p_data size was provided to event processing in network order + instead of host order. + + For new QP's create new address handles and do not use + existing AH's created for the CM. Different PD's are + associated with each. + + Signed-off-by: Arlin Davis + +commit 0bc6a0954bc1a1a61e1b1cbc5c280f69ed168453 +Author: Arlin Davis +Date: Tue Sep 8 09:14:46 2009 -0700 + + ucm: cleanup extra cr/lf + + Signed-off-by: Arlin Davis + +commit 6e7df65a884b4e068135e64dcb3ec660f4c7ab14 +Author: Arlin Davis +Date: Tue Sep 8 09:11:37 2009 -0700 + + ucm: fix issues with UD QP's. + + private data size not in host order when processing + connection events. + + ud extentions event should include original ia_addr + and qpn used during connection and not the IB qpn. + + ucm QP service resource cleanup in wrong order. + + cleanup extra cr/lf device.c + + Signed-off-by: Arlin Davis + +commit e7c3090945c13f80abb929643fc975465afeeb53 +Author: Arlin Davis +Date: Thu Sep 3 10:45:56 2009 -0700 + + winof: Convert windows version of dapl and dat libaries to use private heaps. + + This allows for better support of memory registration caching by upper + level libaries (MPI) that use SecureMemoryCacheCallback. + + It also makes it easier to debug heap corruption issues. + + Signed-off-by: Sean Hefty + +commit bc3c8a34558880c8d09a03e3eb7c3f50d7762c67 +Author: Arlin Davis +Date: Wed Sep 2 14:01:51 2009 -0700 + + dtest, dtestx: modifications for UD QP testing with ucm provider. + + remote_addr is wrong for IP remote address. + + The dtestx requires the server connect back to the client + for the UD test. With the ucm provider you need to provide + the QPN and the LID which you cannot get until the dtest + client starts. So, for now, don't support UD testing + on UCM providers. + + Signed-off-by: Arlin Davis + +commit e4555143ca71ebe18d8c9f027e2e7a5282088a30 +Author: Arlin Davis +Date: Wed Sep 2 13:54:59 2009 -0700 + + scm, ucm: UD QP support was broken when porting to common openib code base. + + create remote_ah was moved out of modify_qp_state function but not + included in the RTU and ACCEPT code for UD QP's. qp type check + should be on daddr not saddr in ucm cm code. + + QP number must be converted to host order before supplying remote_ah, + and qp number to consumer. + + Modify QP state to RTR for UD QP mask setting incorrect. + + Signed-off-by: Arlin Davis + +commit 375d368494bb2f9bb44c82073abc60e01ac28615 +Author: Arlin Davis +Date: Tue Sep 1 13:02:24 2009 -0700 + + cma: cleanup warning with unused local variable, ret, in disconnect + + Signed-off-by: Arlin Davis + +commit 72d1c0c984919809ecd94b2e4ede31ec56668518 +Author: Arlin Davis +Date: Tue Sep 1 12:36:31 2009 -0700 + + cma: remove debug message after rdma_disconnect failure + + DAPL automatically calls rdma_disconnect() when a disconnect request is + received. If the user also calls disconnect, that calls rdma_disconnect() as + well, but the connection has already been disconnected by DAPL and is no longer + valid. The result is that the user's call to rdma_disconnect() will fail. Do + not display an error message if this occurs. + + Locking could be added to prevent calling rdma_disconnect() multiple times, but + since the librdmacm provides synchronization to trap this, we might as well take + advantage of it. + + Signed-off-by: Sean Hefty + +commit 290c568030da6df398a4afb932b5d4f9bd585c26 +Author: Arlin Davis +Date: Tue Sep 1 12:27:43 2009 -0700 + + scm: socket errno check needs O/S dependent wrapper + + Intel MPI checks the uDAPL error code when calling dat_psp_create() to see if + the port number that it provides is in use or not. Convert winsock error codes + to unix errno values. + + This fixes the following error reported by Intel MPI: + 'DAPL provider is not found and fallback device is not enabled' + + Signed-off-by: Sean Hefty + +commit 03b6d1b58ae03058a509c54ffe27147cc44d1851 +Author: Arlin Davis +Date: Tue Sep 1 12:13:16 2009 -0700 + + dapltest: update script files for WinOF + + Cleanup 64-bit paths now that WinOF is always installed into '\Program Files\WinOF'. + + Signed-off-by: Arlin Davis + +commit e38585be89e9fa8f139002a3fe1a82eb86438f93 +Author: Arlin Davis +Date: Tue Sep 1 12:10:21 2009 -0700 + + cma: conditional check for new rdma_cm definition. + + RDMA_CM_EVENT_TIMEWAIT_EXIT is new to OFED 1.4 + add conditional check so dapl can build and run + against older OFED 1.3 stacks + + Signed-off-by: Arlin Davis + +commit 83af586b77aa905b63de6dd6010cd60e91487a9e +Author: Arlin Davis +Date: Thu Aug 20 09:13:43 2009 -0700 + + Release 2.0.22 + + Signed-off-by: Arlin Davis + +commit 48bc0dc95093ccbfe5e01cef4877c128e2caaf77 +Author: Arlin Davis +Date: Thu Aug 20 09:12:47 2009 -0700 + + dapltest: add mdep processor yield and use with dapltest + + Be thread scheduler friendly and release the current thread thus allowing other threads to run. + + Signed off by Stan Smith stan.smith@intel.com + +commit e13f255a06b9d2a2ed4eec9a62f9fe105d0c26d7 +Author: Arlin Davis +Date: Tue Aug 18 10:15:15 2009 -0700 + + ucm: Add new provider using a DAPL based IB-UD cm mechanism for MPI implementations. + + New provider uses it's own CM protocol on top of IB-UD queue pairs. + During device open, this provider creates a UD queue pair and + returns local address information via dat_ia_query. This 24 byte + opaque address must be exchange out-of-band before connecting to a + server via dat_ep_connect. This provider is targeted for MPI + implementations that already exchange address information + during mpi_init phase. + + Future release may provide some ARP mechanism via multicast. + + dtest, dtestx, and dtestcm was modified to report the lid and qpn + information on the server side so you can provide appropriate + destination address information for the client test suite. + + dapltest will not work with this provider. + + Signed-off-by: Arlin Davis + +commit 38d224dd95896c7e60f0bc0ffa52b26ab78f489b +Author: Arlin Davis +Date: Tue Aug 4 20:54:12 2009 -0700 + + Release 2.0.21 + + Signed-off-by: Arlin Davis + +commit ed4999a26043c9c3c73c792b21d24ced1df1553c +Author: Arlin Davis +Date: Tue Aug 4 20:49:09 2009 -0700 + + scm: Fix disconnect. QP's need to move to ERROR state in + order to flush work requests and notify consumer. Moving to + RESET removed all requests but did not notify consumer. + + Signed-off-by: Arlin Davis + +commit 512f1d7a480f06a1fa491d21870e560ad111c4d0 +Author: Arlin Davis +Date: Tue Aug 4 20:48:03 2009 -0700 + + modify dtest.c to cleanup CNO wait code and consolidate into + collect_event() call. After waking up from CNO wait the + consumer must check all EVD's. The EVD's under the CNO + could be dropped if already triggered or could come in any order. + DT_RetToString changed to DT_RetToStr and DT_EventToSTr + changed to DT_EventToStr for consistency. + + Signed-off-by: Arlin Davis + +commit 024e36975d37a1556bf68145e1573f637d269bfc +Author: Arlin Davis +Date: Tue Aug 4 20:47:17 2009 -0700 + + CNO events, once triggered will not be returned during the cno wait. + Check for triggered state before going to sleep in cno_wait. Reset + triggered EVD reference after reporting. + + Signed-off-by: Arlin Davis + +commit 6d6c72a49158d10825929111d6b4df1c6d2bb589 +Author: Arlin Davis +Date: Sun Aug 2 14:21:09 2009 -0700 + + CNO support broken in both CMA and SCM providers. + + CQ thread/callback mechanism was removed by mistake. Still + need indirect DTO callbacks when CNO is attached to EVD's. + + Add CQ event channel to cma provider's thread and add + to select for rdma_cm and async channels. + + For scm provider there is not easy way to add this channel + to the select across sockets on windows. So, for portablity + reasons 2 thread is started to process the ASYNC and + CQ channels for events. + + Must disable EVD (evd_endabled=FALSE) during destroy + to prevent EVD events firing for CNOs and re-arming CQ while + CQ is being destroyed. + + Change dtest to check EVD after CNO timesout. + + Signed-off-by: Arlin Davis + +commit 6fe8bd1d8f44777211e816b72e0b2a6d22900207 +Author: Arlin Davis +Date: Thu Jul 30 08:02:30 2009 -0700 + + common osd: include winsock2.h for IPv6 definitions. + + Signed-off-by: Arlin Davis + +commit bd26383900d18962aeeff54fa59922009091ecfc +Author: Arlin Davis +Date: Wed Jul 29 08:02:15 2009 -0700 + + common osd: include w2tcpip.h for sockaddr_in6 definitions. + + Signed-off-by: Arlin Davis + +commit f25544f14554200a6714accef5f761b0269b5819 +Author: Sean Hefty +Date: Mon Jul 27 15:07:33 2009 -0700 + + DAPL introduced the concept of directly waiting on the CQ for + events by adding a compile time flag and special handling in the common + code. Rather than using the compile time flag and modifying the + common code, let the provider implement the best way to wait for + CQ events. + + This simplifies the code and allows the common openib providers to + optimize for Linux and Windows platforms independently, rather than + assuming a specific implementation for signaling events. + + Signed-off-by: Sean Hefty + +commit 1548405a377d2bd17938df69419e9bcf3364d91a +Author: Arlin Davis +Date: Thu Jul 16 12:41:22 2009 -0700 + + dapltest: Implement a malloc() threshold for the completion reaping. + + change byte vector allocation to stack in functions: + DT_handle_send_op, DT_handle_rdma_op & DT_handle_recv_op. + + When allocation size is under the threshold, use a stack local + allocation instead of malloc/free. Move redundant bzero() to + be called only in the case of using local stack allocation as + DT_Mdep_malloc() already does a bzero(). Consolidate error handling + return and free()check to a single point by using goto. + + Signed-off-by: Stan Smith + +commit f6311ca7295230bf9efbcddc639fa8e1065b1f3d +Author: Arlin Davis +Date: Thu Jul 16 12:32:09 2009 -0700 + + scm: handle connected state when freeing CM objects + + The QP could be freed before being disconnected + so the provider needs process disconnect before freeing + the CM object. The disconnect clean will finish + the destroy process during the disc callback. + + Signed-off-by: Arlin Davis + +commit 4387359106ce398b29847982883016f7fd48b372 +Author: Arlin Davis +Date: Wed Jul 8 12:49:43 2009 -0700 + + scm, dtest: changes for winof gettimeofday and FD_SETSIZE settings. + + scm changes to set FD_SETSIZE with expected value and + prevent windows override. + + dtest: remove gettimeofday implementation for windows + specific implemenation etc\user\gtod.c + + general EOL cleanup + + Signed-off-by: Arlin Davis + +commit 3542a83d8a31f5ac68adf3aa44e3ebf1265068df +Author: Arlin Davis +Date: Mon Jul 6 09:24:07 2009 -0700 + + scm: set TCP_NODELAY sockopt on the server side for sends. + + scm provider sends small messages from both server and client + sides. Set NODELAY on both sides to avoid send delays either + way. + + Signed-off-by: Arlin Davis + +commit 9d591180392856935b9c3befbab2243dd8daf628 +Author: Arlin Davis +Date: Thu Jul 2 14:16:52 2009 -0700 + + windows: remove obsolete files in dapl/udapl source tree + + SOURCES,makefile,udapl.r,udapl_exports.src,udapl_sources.c + + Signed-off-by: Arlin Davis + +commit 85c238ee0a41dd0a4a24b3d422f34674b0183161 +Author: Arlin Davis +Date: Thu Jul 2 14:11:20 2009 -0700 + + dtestcm: add UD type QP option to test + + Add -u for UD type QP's during connection setup. + Will setup UD QPs and provide remote AH + in connect establishment event. Measures + setup/exchange rates. + + Signed-off-by: Arlin Davis + +commit 89a2211526e37b1db58fc0ea663b330bc19125c8 +Author: Arlin Davis +Date: Thu Jul 2 14:07:36 2009 -0700 + + scm: destroy QP called before disconnect + + Handle the case where QP is destroyed before + disconnect processing. Windows supports + reinit_qp during a disconnect call by + destroying the QP and recreating the + QO instead of state change from reset + to init. Call disconnect in destroy + CM code to handle this unexpected state. + + Signed-off-by: Arlin Davis + +commit 6eb35b7d69a896c256b1031337d3353575cd07b4 +Author: Arlin Davis +Date: Thu Jul 2 14:03:12 2009 -0700 + + cma: add support for rdma_cm TIME_WAIT event. + + Nothing to process, simply ack the event. + + Signed-off-by: Arlin Davis + +commit b6c56b3052ecd3e36c32092ee62ff0c724da5ad4 +Author: Arlin Davis +Date: Wed Jul 1 07:58:32 2009 -0700 + + scm: remove old udapl_scm code replaced by openib_scm. + + Signed-off-by: Arlin Davis + +commit 5bbae42a56e1cca678d590ac4c841dd61e839d74 +Author: Arlin Davis +Date: Wed Jul 1 07:53:18 2009 -0700 + + winof: fix build issues after consolidating cma, scm code base. + + Signed-off-by: Arlin Davis + +commit 6bd1d931c4d0d4cbafac383f225140120aee4c51 +Author: Arlin Davis +Date: Wed Jul 1 07:51:59 2009 -0700 + + cma: lock held when exiting as a result of a rdma_create_event_channel failure. + + Signed-off-by: Arlin Davis + +commit b8a14ff1cc257defa2f74373d143600f5f471823 +Author: Sean Hefty +Date: Mon Jun 29 12:34:54 2009 -0700 + + windows: all dlist functions have been moved to the header file. + remove references to dlist.c + + Signed-off-by: Sean Hefty + +commit 1a081a0a467e4773a641e8edc876a7a4d7a30ca8 +Author: Arlin Davis +Date: Mon Jun 29 12:13:48 2009 -0700 + + dtestcm windows: add build infrastructure for new dtestcm test suite + + Signed-off-by: Arlin Davis + +commit c37d7a25dca97011ea76e2a541f936d10ca658e0 +Author: Arlin Davis +Date: Mon Jun 29 08:57:46 2009 -0700 + + openib_common: reorganize provider code base to share common mem, cq, qp, dto functions + + add new openib_common directory with cq, qp, util, dto, mem function calls + and definitions. This basically leaves the unique CM and Device definitions + and functions to the individual providers directory of openib_scm and openib_cma. + + modifications to dapl_cr_accept required. ep->cm_handle is allocated + and managed entirely in provider so dapl common code should not update + ep_handle->cm_handle from the cr->cm_handle automatically. The provider + should determine which cm_handle is required for the accept. + + openib_cma defines _OPENIB_CMA_ and openib_scm defines _OPENIB_SCM_ for provider + specific build needs in common code. + +commit 961a4083ffb646c070137abd33e9ba2ea9482685 +Author: Arlin Davis +Date: Fri Jun 26 14:45:34 2009 -0700 + + scm: fixes and optimizations for connection scaling + + Prioritize accepts on listen ports via FD_READ + process the accepts ahead of other work to avoid + socket half_connection (SYN_RECV) stalls. + + Fix dapl_poll to return DAPL_FD_ERROR on + all event error types. + + Add new state for socket released, but CR + not yet destroyed. This enables scm to release + the socket resources immediately after exchanging + all QP information. Also, add state to str call. + + Only add the CR reference to the EP if it is + RC type. UD has multiple CR's per EP so when + a UD EP disconnect_clean was called, from a + timeout, it destroyed the wrong CR. + + Signed-off-by: Arlin Davis + +commit a60a9e1fce5588cb23f41391b48acf04edd82499 +Author: Arlin Davis +Date: Fri Jun 26 14:31:19 2009 -0700 + + scm: double the default fd_set_size + + Signed-off-by: Arlin Davis + +commit 17d5e1692db4ae1eb09aa919d5607f22851d7ec5 +Author: Arlin Davis +Date: Fri Jun 26 14:28:30 2009 -0700 + + scm: EP reference in CR should be cleared during ep_destroy + + The EP reference in the CR should be set to null + during the EP free call to insure no further + reference back to a mem freed EP. + + Signed-off-by: Arlin Davis + +commit ebb820364cec9d72285c005a0874e7d459a9ff7d +Author: Arlin Davis +Date: Fri Jun 26 14:23:35 2009 -0700 + + dtestx: fix conn establishment event checking + + not catching error cases on client side + when checking for event number and UD type + && should have been || + + Signed-off-by: Arlin Davis + +commit 747b793898042e3011fbad4b2d1285d2c040cb13 +Author: Arlin Davis +Date: Fri Jun 26 14:18:37 2009 -0700 + + dtestcm: new test to measure dapl connection rates. + + new test suite added to measure connection + rates of providers. Used to compare cma, scm, + and other providers under development. + + dtestcm USAGE + + s: server + c: connections (default = 1000) + b: burst rate of conn_reqs (default = 100) + m: multi-listens (set to burst setting ) + v: verbose + w: wait on event (default, polling) + d: delay before accept + h: hostname/address of server, specified on client + P: provider name (default = OpenIB-v2-ib0) + + Signed-off-by: Arlin Davis + +commit d58fbc3a870a060ead882e1d15c6d245cdf39096 +Author: Arlin Davis +Date: Fri Jun 19 20:59:16 2009 -0700 + + Release 2.0.20 + + Signed-off-by: Arlin Davis + +commit beebe0066b47d7bf476925ff280bad2a3db38324 +Author: Arlin Davis +Date: Fri Jun 19 20:52:51 2009 -0700 + + common,scm: add debug capabilities to print in-process CM lists + + Add a new debug bit DAPL_DBG_TYPE_CM_LIST. + If set, the pending CM requests will be + dumped when dat_print_counters is called. + Only provided when built with -DDAPL_COUNTERS + + Add new dapl_cm_state_str() call for state + to string conversion for debug prints. + + Signed-off-by: Arlin Davis + +commit b1c51f1e68993d9306e3ebd48bd3a1f0e9878fa3 +Author: Arlin Davis +Date: Tue Jun 16 09:22:31 2009 -0700 + + scm: disconnect EP before cleaning up orphaned CR's during dat_ep_free + + There is the possibility of dat_ep_free being called + with RC CR's still in connected state. Call disconnect + on the CR before marking for destroy. + + Signed-off-by: Arlin Davis + +commit 531d223455a88c885d6c5f7b1d7e158c1079fbce +Author: Arlin Davis +Date: Wed Jun 10 12:05:17 2009 -0700 + + dapltest: windows scripts updated + + Support added for provider specification and general simplification of internal workings. + + Signed-off-by: Stan Smith + +commit 049d1ea08643d4c4eff761741641d37bb3f01fc1 +Author: Arlin Davis +Date: Wed Jun 10 09:18:09 2009 -0700 + + scm: private data is not handled properly via CR rejects. + + For both RC and UD connect requests, the private + data is not being received on socket and passed + back via the active side REJECT event. + + UD requires new extended reject event type of + DAT_IB_UD_CONNECTION_REJECT_EVENT to distiquish + between RC and UD type rejects. + + cr_thread exit/cleanup processing fixed to insure + all items are off the list before exiting. + + Signed-off-by: Arlin Davis + +commit 3c26870e276a934e2009090e0fca8bdc36c1be67 +Author: Arlin Davis +Date: Wed Jun 10 09:09:56 2009 -0700 + + scm: cleanup orphaned UD CR's when destroying the EP + + UD CR objects are kept active because of direct private data references + from CONN events. The cr->socket is closed and marked inactive but the + object remains allocated and queued on the CR resource list. There can + be multiple CR's associated with a given EP and there is no way to + determine when consumer is finished with event until the dat_ep_free. + Schedule destruction for all CR's associated with this EP during + free call. cr_thread will complete cleanup with state of SCM_DESTROY. + + Signed-off-by: Arlin Davis + +commit 73abd3f58fa7b14241fad98912ef27c7b4fdb47e +Author: Arlin Davis +Date: Wed Jun 10 09:05:32 2009 -0700 + + scm: provider specific query for default UD MTU is wrong. + + Change the provider specific query DAT_IB_TRANSPORT_MTU + to report 2048 for new default MTU size. + + Signed-off-by: Arlin Davis + +commit 27c0d7edc4c931b808a7c5a24bd5aa2625b48aa1 +Author: Arlin Davis +Date: Wed Jun 10 10:06:59 2009 -0700 + + scm: update CM code to shutdown before closing socket + + data could be lost without calling shutdown on the socket + before closing. Update to shutdown and then close. Add + definition for SHUT_RW to SD_BOTH for windows. + + Signed-off-by: Arlin Davis + --- + +commit 536ec3103c15c1fed4367326c9117660345e0eab +Author: Arlin Davis +Date: Thu Jun 4 13:48:18 2009 -0700 + + dapltest: windows script dt-cli.bat updated + + scn should be scm + + Signed-off-by: Arlin Davis + +commit e8991b8f0877b0e2e857717e1140c679e9266abe +Author: Sean Hefty +Date: Thu Jun 4 08:19:12 2009 -0700 + + dapl/windows cma provider: add support for network devices based on index + + The linux cma provider provides support for named network devices, such + as 'ib0' or 'eth0'. This allows the same dapl configuration file to + be used easily across a cluster. + + To allow similar support on Windows, allow users to specify the device + name 'rdma_devN' in the dapl.conf file. The given index, N, is map to a + corresponding IP address that is associated with an RDMA device. + + Signed-off-by: Sean Hefty + +commit 79fa3e7d241f740bc886dd075f24fcbc611306de +Author: Arlin Davis +Date: Thu Jun 4 08:00:29 2009 -0700 + + openib: remove 1st gen provider, replaced with openib_cma and openib_scm + + Signed-off-by: Arlin Davis + +commit 624039247cdc0db7aa040dfbb4dced00f2cf9006 +Author: Arlin Davis +Date: Fri May 29 08:21:10 2009 -0700 + + dapltest: update windows script files + + Enhancement to take DAPL provider name as cmd-line arguement. + + Signed-off-by: Arlin Davis + +commit b93baa07b7bbaeb7a55fa817c354d0c94783d61f +Author: Arlin Davis +Date: Thu May 28 15:30:05 2009 -0700 + + dapltest: update windows batch files in sripts directory + + Signed-off-by: Arlin Davis + +commit 2f185c6b5e464c4fc9e84ad3e90cc2b86aebf9aa +Author: Arlin Davis +Date: Mon May 18 14:00:02 2009 -0700 + + windows_osd/linux_osd: new dapl_os_gettid macro to return thread id + + Change dapl_os_getpid inline to macro on windows and add dapl_os_gettid + macros on linux and windows to return thread id. + + Signed-off-by: Arlin Davis + +commit 984303824cd0c3e248a789066cf665ced8e1ae5b +Author: Arlin Davis +Date: Mon May 18 13:53:59 2009 -0700 + + windows: missing build files for common and udapl sub-directories + + Add dapl/dapl_common_src.c and dapl/dapl_udapl_src.c + + Signed-off-by: Arlin Davis + +commit 3be4ccf9681a975e74a5aa05e3f7912477f342a7 +Author: Arlin Davis +Date: Mon May 18 09:06:19 2009 -0700 + + windows: add build files for openib_scm, remove /Wp64 build option. + + Add build files for windows socket cm and change build + option on windows providers. The new Win7 WDK issues a + depreciated compiler option warning for /Wp64 + (Enable 64-bit porting warnings) + + Signed-off-by: Arlin Davis + +commit 163112cfeb6e409886b3cb7f85da7ce003300d5c +Author: Arlin Davis +Date: Mon May 18 08:50:35 2009 -0700 + + scm: multi-hca CM processing broken. Need cr thread wakeup mechanism per HCA. + + Currently there is only one pipe across all + device opens. This results in some posted CR work + getting delayed or not processed at all. Provide + pipe for each device open and cr thread created + and manage on a per device level. + + Signed-off-by: Arlin Davis + +commit e6e799f623df6ef136ffc5388251d3f3a38c8a91 +Author: Arlin Davis +Date: Fri May 15 11:06:19 2009 -0700 + + dtest: add connection timers on client side + + Add timers for active connections and print + results. Allow polling or wait on conn event. + + Signed-off-by: Arlin Davis + +commit d656bbf619123deaed6e8985e52207e5415f359f +Author: Arlin Davis +Date: Fri May 15 09:48:38 2009 -0700 + + linux_osd: use pthread_self instead of getpid for debug messages + + getpid provides process ids which are not unique. Use unique thread + id's in debug messages to help isolate issues across many device + opens with multiple CM threads. + + Signed-off-by: Arlin Davis + +commit 92bb0d2933d3d1546e18f0479475f3daf5b92052 +Author: Arlin Davis +Date: Fri May 1 10:18:05 2009 -0700 + + windows ibal-scm: dapl/dirs file needs updated to remove ibal-scm + + Signed-off-by: Arlin Davis + +commit 9c37d9d667fb7e8f21841bbec4a84b2c652fffe1 +Author: Arlin Davis +Date: Wed Apr 29 23:13:36 2009 -0700 + + Release 2.0.19 + + Signed-off-by: Arlin Davis + +commit 0ef94459e0a0175233b43b3fcbaaac2596e1042d +Author: Arlin Davis +Date: Wed Apr 29 14:33:28 2009 -0700 + + scm, cma: dat max_lmr_block_size is 32 bit, verbs max_mr_size is 64 bit + + mismatch of device attribute size restricts max_lmr_block_size to 32 bit + value. Add check, if larger then limit to 4G-1 until DAT v2 spec changes. + + Consumers should use max_lmr_virtual_address for actual max + registration block size until attribute interface changes. + + Signed-off-by: Arlin Davis + +commit f91f27eaaab28b13a631adf75b933b7be3afbc0f +Author: Arlin Davis +Date: Wed Apr 29 10:51:03 2009 -0700 + + scm: increase default MTU size from 1024 to 2048 + + Signed-off-by: Arlin Davis + +commit 8d6846056f4c86b6a06346147df55d37c4ba9933 +Author: Arlin Davis +Date: Wed Apr 29 10:49:09 2009 -0700 + + openib_scm, cma: use direct SGE mappings from dat_lmr_triplet to ibv_sge + + no need to rebuild scatter gather list given that DAT v2.0 + is now aligned with verbs ibv_sge. Fix ib_send_op_type_t typedef. + + Signed-off-by: Arlin Davis + +commit c61f75b3412935e7d4a7a1acc9c495dcb4ac7e24 +Author: Arlin Davis +Date: Wed Apr 29 08:39:37 2009 -0700 + + dtest: add flush EVD call after data transfer errors + + Flush and print entries on async, request, and receive + queues after any data transfer error. Will help + identify failing operation during operations + without completion events requested. + Fix -B0 so burst size of 0 works. + + Signed-off-by: Arlin Davis + +commit c88a191c7a408b0fb3dfb418a77a5b3b5afc778e +Author: Arlin Davis +Date: Wed Apr 22 13:16:19 2009 -0700 + + dtest/dapltest: Cleanup code with Lindent + + Signed-off-by: Arlin Davis + +commit 8699a9f1bd2bb45b04b87f887698707ba7b62d0a +Author: Arlin Davis +Date: Tue Apr 21 15:51:24 2009 -0700 + + ibal-scm: remove, obsolete + + Signed-off-by: Arlin Davis + +commit 67ddd6bfba46f1f7a61b772257132f1257d05c96 +Author: Arlin Davis +Date: Tue Apr 21 15:44:15 2009 -0700 + + scm, cma provider: Cleanup code with Lindent + + Signed-off-by: Arlin Davis + +commit d0898091090ff19be7929fed0d14f1ca696d5e53 +Author: Arlin Davis +Date: Tue Apr 21 15:39:01 2009 -0700 + + udapl: Cleanup code with Lindent + + Signed-off-by: Arlin Davis + +commit a688d1cfb52fde256c5bfd95a27f940dd17e7ced +Author: Arlin Davis +Date: Tue Apr 21 15:31:20 2009 -0700 + + dapl common: Cleanup code with Lindent + + Signed-off-by: Arlin Davis + +commit 2bded73c7f68cfb870e432ab3ebae7427d595cbe +Author: Arlin Davis +Date: Tue Apr 21 12:52:29 2009 -0700 + + dat: Cleanup code with Lindent + + Signed-off-by: Arlin Davis + +commit 31e7b9210fc5334ff3be62558e74e3fdf01d6cbd +Author: Arlin Davis +Date: Mon Apr 20 12:28:08 2009 -0700 + + Release 2.0.18 + + Signed-off-by: Arlin Davis + +commit 29bf0a24f54c45d2742026756f31f1a1f26fb6f3 +Author: Arlin Davis +Date: Thu Apr 16 14:35:18 2009 -0700 + + dapltest: reset server listen ports to avoid collisions during long runs + + If server is running continuously the port number increments + from base without reseting between tests. This will + eventually cause collisions in port space. + + Signed-off-by: Arlin Davis + +commit c27af8de0501d132b8152ec8546023cdba212de5 +Author: Sean Hefty +Date: Thu Apr 16 10:21:51 2009 -0700 + + To avoid duplicating port numbers between different tests, the next port + number to use must increment based on the number of endpoints per thread * + the number of threads. + + Signed-off-by: Sean Hefty + +commit 3084310197c20aaa50abe82260fc835786f591f5 +Author: Sean Hefty +Date: Thu Apr 16 10:21:45 2009 -0700 + + dapltest assumes that events across multiple endpoints occur in a specific + order. Since this is a false assumption, avoid this by directing events to + per endpoint EVDs, rather than using shared EVDs. + + Signed-off-by: Sean Hefty + +commit ef87a0a462f4fa07ac252e28d3aeb44af73cc202 +Author: Sean Hefty +Date: Thu Apr 16 10:21:41 2009 -0700 + + Synchronization is missing between removing items from an EVD and queuing + them. Since the removal thread is the user's, but the queuing thread is + not, the synchronization must be provided by DAPL. Hold the evd lock + around any calls to dapls_rbuf_*. + + Signed-off-by: Sean Hefty + +commit f5e86d28f803162ffdf94b41ec7435dec92f728d +Author: Sean Hefty +Date: Thu Apr 16 10:21:26 2009 -0700 + + Communication to the CR thread is done using an internal socket. When a + new connection request is ready for processing, an object is placed on + the CR list, and data is written to the internal socket. The write causes + the CR thread to wake-up and process anything on its cr list. + + If multiple objects are placed on the CR list around the same time, then + the CR thread will read in a single character, but process the entire list. + This results in additional data being left on the internal socket. When + the CR does a select(), it will find more data to read, read the data, but + not have any real work to do. The result is that the thread spins in a + loop checking for changes when none have occurred until all data on the + internal socket has been read. + + Avoid this overhead by reading all data off the internal socket before + processing the CR list. + + Signed-off-by: Sean Hefty + +commit 2ab52e9b1ab37c6eb44206c135e0568a8c2d01fa +Author: Sean Hefty +Date: Thu Apr 16 10:21:13 2009 -0700 + + The dapl connect call takes as input an address (sockaddr) and a port number + as separate input parameters. It modifies the sockaddr address to set the + port number before trying to connect. This leads to a situation in + dapltest with multiple threads that reference the same buffer for their + address, but specify different port numbers, where the different threads + end up trying to connect to the same remote port. + + To solve this, do not modify the caller's address buffer and instead use + a local buffer. This fixes an issue seen running multithreaded tests with + dapltest. + + Signed-off-by: Sean Hefty + +commit 7947026ede478f08b4a7b8cb607f457765bf2afa +Author: Sean Hefty +Date: Thu Apr 16 10:21:03 2009 -0700 + + Windows socket calls should check return values against SOCKET_ERROR to + determine if an error occurred. + + Signed-off-by: Sean Hefty + +commit e66e42fc44c50c8202f7c98f76d799a69aa3f1b6 +Author: Arlin Davis +Date: Fri Apr 10 08:33:41 2009 -0700 + + Build: add new file dapl/openib_cma/linux/openib_osd.h to EXTRA_DIST + + Fix rpmbuild problem with new cma osd include file. + + Signed-off-by: Arlin Davis + +commit acb213adb3268e9bf6999e2bf040d4a71212b701 +Author: Arlin Davis +Date: Fri Apr 10 08:32:24 2009 -0700 + + dapl scm: reduce wait time for thread startup. + + thread startup wait reduce to 2ms to reduce open times. + + Signed-off-by: Arlin Davis + +commit 55459699fa9c0e5fb7e2b17822f0916412c64b35 +Author: Arlin Davis +Date: Fri Apr 10 08:31:22 2009 -0700 + + dapl-scm: getsockopt optlen needs initialized to size of optval + + Signed-off-by: Arlin Davis + +commit d710c5327e05a40796341d16b45a2b098b03f588 +Author: Sean Hefty +Date: Fri Apr 10 08:17:32 2009 -0700 + + The connection request thread adds sockets to a select list unless + the cr->socket is invalid and the cr request state is set to destroy. If the + cr->socket is invalid, but the cr->state is not destroy, then the cr->socket + is added to an FD set for select/poll. This results in select/poll + returning an error when select is called. As a result, the cr thread never + actually blocks during this state. + + Fix this by only destroying a cr based on its state being set to destroy + and skip adding cr->sockets to the FD set when they are invalid. + + Signed-off-by: Sean Hefty + +commit 0be961c432f897d4f92d9a24dcb7c42ad30ea160 +Author: Sean Hefty +Date: Fri Apr 10 08:08:16 2009 -0700 + + Make sure all locks are initialized properly and don't zero their memory + once they are. + + Signed-off-by: Sean Hefty + +commit 9abdc26cd6154aa55588759ba54c9ca69e3fe2b5 +Author: Sean Hefty +Date: Fri Apr 10 08:08:13 2009 -0700 + + The lock functions are defined just a few lines beneath the prototypes + as inline. Remove the duplicate prototypes. + + Signed-off-by: Sean Hefty + +commit 9578c4aeb9878d98374e4b7abc02db182aef82c6 +Author: Sean Hefty +Date: Fri Apr 10 08:08:07 2009 -0700 + + Make sure all locks are initialized and don't zero out their memory once + they are. + + Signed-off-by: Sean Hefty + +commit 97edcbb662b489303ef68c0da02831efaddeed91 +Author: Sean Hefty +Date: Fri Apr 10 08:08:03 2009 -0700 + + The IBAL library allocates a small number of threads for callbacks to the + user. If the user blocks all of the callback threads, no additional + callbacks can be invoked. The DAPL IBAL provider cancels listen requests + from within an IBAL callback, then waits for a second callback to confirm + that the listen has been canceled. If there is a single IBAL callback + thread, or multiple listens are canceled simultaneously, then the provider + can deadlock waiting for a cancel callback that never occurs. + + This problem is seen when running dapltest with multiple threads. + + Signed-off-by: Sean Hefty + +commit 3e56e63bcb68de352edadafdcfcc4cb222c08c7b +Author: Sean Hefty +Date: Fri Apr 10 08:07:57 2009 -0700 + + We need to check the return value from select for errors before checking + the FD sets. An item may be in an FD set but select could have returned + an error. + + Signed-off-by: Sean Hefty + +commit a8a977becaeefe0d7f8e01e01631a11988d2d54e +Author: Sean Hefty +Date: Fri Apr 10 08:07:53 2009 -0700 + + Signed-off-by: Sean Hefty + +commit ecc79cc0a1ae2bdbb3dfd19e15b3b562ac9a2957 +Author: Sean Hefty +Date: Fri Apr 10 08:07:49 2009 -0700 + + Enable building with CQ_WAIT_OBJECTS support to directly wait on CQ + completion channels in the Windows version of the openib_scm provider. + Also minor fixup to use DAPL_DBG_TYPE_UTIL for debug log messages + instead of DAPL_DBG_TYPE_CM. + + Signed-off-by: Sean Hefty + +commit 73728763666a46df5789af93b50db53cdf64afd6 +Author: Sean Hefty +Date: Fri Apr 10 08:07:44 2009 -0700 + + The IBAL-SCM provider will run into an inifinite loop if the check for + cr->socket > SCM_MAX_CONN - 1 fails. The code continues back to the start + of the while loop without moving to the next connection request entry + in the list. + + Signed-off-by: Sean Hefty + +commit 9b1b396539926d36ffacfff04fbe7c081e436b45 +Author: Sean Hefty +Date: Fri Apr 10 08:07:40 2009 -0700 + + next_cr is set just before and inside the check + if ((cr->socket == DAPL_INVALID_SOCKET && cr->state == SCM_DESTROY) + Remove setting it inside the if statement. + + Signed-off-by: Sean Hefty + +commit 7b49a9850f62276bb7bfccb2d85a1e94e311813c +Author: Sean Hefty +Date: Fri Apr 10 08:07:35 2009 -0700 + + Some errors on windows are more easily interpretted in hex than decimal. + + Signed-off-by: Sean Hefty + +commit 08ee072a1396ac2c28983878dbc6b02feb035787 +Author: Sean Hefty +Date: Fri Apr 10 08:07:32 2009 -0700 + + The WinOF HCA driver cannot handle transitioning from RTS -> RESET -> + INIT -> ERROR. Simply delete the QP and re-create it to reinitialize + the endpoint until the bug is fixed. + + Signed-off-by: Sean Hefty + +commit 51ef5d96ce67d6141ec02b2a318f1b6e12be1bcf +Author: Sean Hefty +Date: Fri Apr 10 08:07:23 2009 -0700 + + Signed-off-by: Sean Hefty + +commit a8582be0e1fc89e856f1d0b43a3c1b271295a352 +Author: Sean Hefty +Date: Fri Apr 10 08:07:18 2009 -0700 + + Convert the openib_cma provider to common code between linux and windows. + + Signed-off-by: Sean Hefty + +commit cc2a71dfe0c35a70f6b1ba66070a3a06059a8bb5 +Author: Sean Hefty +Date: Fri Apr 10 08:06:53 2009 -0700 + + Move from using pipes to sockets for internal communication. This + avoids issues with windows only supporting select() on sockets. + + Remove windows specific definition of dapl_dbg_log. + + Update to latest windows libibverbs implementation using completion + channel abstraction to improve windows scalability and simplify + porting where FD's are accessed directly in Linux. + + Signed-off-by: Sean Hefty + +commit b3ad2ed97399a24a869841e17d1314e11c379aae +Author: Arlin Davis +Date: Tue Mar 31 05:41:50 2009 -0800 + + Release 2.0.17 + + Signed-off-by: Arlin Davis + +commit 5d732929f8a90a490994e8e35a3666c3647ad4fe +Author: Arlin Davis +Date: Tue Mar 31 05:22:11 2009 -0800 + + dapl: ia64 build problem on SuSE 11, atomic.h no longer exists. + + Add autotools check for SuSE 11 and include intrinsics.h + + Signed-off-by: Arlin Davis + +commit d7b8654db3a1f4ead16cb2e6d15f0902a322a188 +Author: Arlin Davis +Date: Mon Mar 16 13:23:50 2009 -0800 + + Release 2.0.16 + + Fix changelog year in spec file. + + Signed-off-by: Arlin Davis + +commit 08d9e26a85911f99d47cbb92ec8bccfc7f073be0 +Author: Arlin Davis +Date: Mon Mar 16 13:15:22 2009 -0800 + + Release 2.0.16 + + Signed-off-by: Arlin Davis + +commit 42c97b2a11d63ac6ba8a15fe8c82061e7da6e136 +Author: Arlin Davis +Date: Fri Mar 13 12:39:12 2009 -0800 + + uDAPL: scm provider, remove query gid/lid from connection setup phase + + move lid/gid queries from the connection setup phase + and put them in the open call to avoid overhead + of more fd's during connections. No need + to query during connection setup since uDAPL + binds to specific hca/ports via dat_ia_open. + + Signed-off-by: Arlin Davis + +commit 775394b73980a7bc0af018a33d2a5bb795469c78 +Author: Arlin Davis +Date: Thu Mar 12 12:44:43 2009 -0800 + + Build: missing new linux/osd include file in EXTRA_DIST + + Add dapl/openib_scm/linux/openib_osd.h to EXTRA_DIST + + Signed-off-by: Arlin Davis + +commit 647e288c1c9af5261495a5ed88e6ecbe1daf6d6e +Author: Arlin Davis +Date: Thu Mar 12 12:11:21 2009 -0800 + + Build: spec files missing Requires(post) statements for sed/coreutils + + needed for anaconda install + + Signed-off-by: Arlin Davis + +commit 1f5b3b7cab0785b64e8dab035dd4cd27111497d3 +Author: Arlin Davis +Date: Wed Mar 4 10:04:13 2009 -0800 + + dapl scm: remove unecessary thread when using direct objects + + A thread is created for processing events on devices without + direct event objecti support. Since all openfabrics devices support + direct events there is no need to start a thread. Move this under + + Signed-off-by: Arlin Davis + +commit 66e4236e2c57dbaf860b7c20809b65a4fbbafa6f +Author: Arlin Davis +Date: Tue Mar 3 11:08:12 2009 -0800 + + dtestx: add missing F64u definition for windows + + Signed-off-by: Arlin Davis + +commit d9e771da16ec2b360a222ceccbbca5d088e20ee5 +Author: Arlin Davis +Date: Tue Mar 3 09:25:26 2009 -0800 + + uDAPL common: add 64 bit counters for IA, EP, and EVD's. + + -DDAPL_COUNTERS to build-in counters for cma and scm providers. + New extension calls in dat_ib_extensions.h for counters + dat_print_counters, dat_query_counters + Counters for operations, async errors, and data + Update dtestx (-p) with print and query counter examples + + Signed-off-by: Arlin Davis + +commit 5e6ad3cdaa1d72523ad6b38d8306e0a2d0f1ada6 +Author: Sean Hefty +Date: Tue Feb 17 07:24:27 2009 -0800 + + Modify the openib_scm provider to support both OFED and WinOF releases. + This takes advantage of having a libibverbs compatibility library. + + Signed-off-by: Sean Hefty + +commit 0425c24c3b66e672bba346a1d0946b11c7b8b11e +Author: Stan Smith +Date: Fri Jan 30 09:52:33 2009 -0800 + + Update the dapl.git tree with the latest SVN version of the + ibal-scm provider. + + Signed-off-by: Sean Hefty + +commit 83543b6cca342e25fd6408454f1261ec6835a172 +Author: Stan Smith +Date: Fri Jan 30 09:52:25 2009 -0800 + + Merge SVN IBAL provider code back into the main git tree. + + Signed-off-by: Sean Hefty + +commit be0b6122d0fe4f93afc8cf3ec961702faf82fb44 +Author: Sean Hefty +Date: Fri Jan 30 09:52:11 2009 -0800 + + Changes to dtest to support building on Windows. + + Signed-off-by: Sean Hefty + +commit 9f87610c4b37e4db4d74205c14028582a2f6a79e +Author: Stan Smith +Date: Fri Jan 30 09:48:26 2009 -0800 + + Add return codes to various functions. + Add script (batch file) for Windows testing. + + Signed-off-by: Sean Hefty + +commit 723067550265defdcfe6e00460a4f89f7a81fbf1 +Author: Sean Hefty +Date: Fri Jan 30 09:46:40 2009 -0800 + + Merge OFED and WinOF trees for common dapl code. + + Signed-off-by: Sean Hefty + +commit 5b37e080e1ecc6903b3ab1ac9b0d4c9f8a18b790 +Author: Arlin Davis +Date: Fri Jan 16 08:16:13 2009 -0800 + + dtest/dapltest: use $(top_builddir) for .la files during test builds + + Signed-off-by: Arlin Davis + +commit bd655d4fdd7e63e7fdeed3979926da5582f71e4b +Author: Arlin Davis +Date: Wed Nov 26 07:12:30 2008 -0800 + + Release 2.0.15 + + Signed-off-by: Arlin Davis + +commit 5d5dec42717c963d1644ee3e716459dc5d58e930 +Author: Arlin Davis +Date: Mon Oct 27 08:48:53 2008 -0800 + + dapltest: transaction test moves to cleanup stage before rdma_read processing is complete + + With multiple treads, the transaction server tread can move to cleanup + stage and unregister memory before the remote client process has + completed the rdma read. In lieu of a rewrite to add sync messages + at the end of transaction test phase, just add a delay before cleanup. + + Signed-off-by: Arlin Davis + +commit 101a843e59b881bc131dfd5c2aec7e54d44f35c0 +Author: Arlin Davis +Date: Tue Oct 14 11:56:35 2008 -0700 + + Current static registration (SR) assumes DAT_OVERRIDE or /etc/dat.conf. + Change SR to include sysconfdir. SR file access in the following order: + + - DAT_OVERRIDE + - sysconfdir + - /etc + + if DAT_OVERRIDE is set, assume administration override + and do not failover to other locations. Add debug + messages for each failure and retries. + + Signed-off-by: Arlin Davis + Acked-by: Doug Ledford + +commit c98d2169b839a73d76691acf510dd8976ddc850a +Author: Arlin Davis +Date: Fri Oct 3 08:00:56 2008 -0700 + + Release 2.0.14 + + Signed-off-by: Arlin Davis + +commit c26d0bb065f3734f09058e1e6d26dde4a3738e55 +Author: Arlin Davis +Date: Fri Oct 3 05:40:04 2008 -0700 + + dat.conf: add ofa-v2-iwarp entry for iwarp devices + + Signed-off-by: Arlin Davis + +commit d54c35c8a9ba33a464ca15f4a65b914688e5194d +Author: Arlin Davis +Date: Fri Oct 3 05:30:10 2008 -0700 + + dapl: adjust max_rdma_read_iov to 1 for query on iWARP devices + + iWarp spec allows only one iov on rdma reads + + Signed-off-by: Arlin Davis + +commit 9584df22d0cb3aa5a2a2a04bf427524d17650ef7 +Author: Arlin Davis +Date: Wed Oct 1 08:17:49 2008 -0700 + + dtest: reduce default IOV's during dat_ep_create for iWARP devices + + iWarp adapters tend to have less IOV resources then IB adapters. + + Signed-off-by: Arlin Davis + +commit 8ca9898621acf5b9769d46ea34ee8ca1eecaf2ff +Author: Arlin Davis +Date: Fri Sep 26 12:43:13 2008 -0700 + + dtest: fix 32-bit build issues in dtest and dtestx examples. + + Signed-off-by: Arlin Davis + +commit 42a3a4edf30115a35d9d599b51f8756814e62368 +Author: Arlin Davis +Date: Fri Sep 26 08:48:31 2008 -0700 + + Revert "Release 2.0.14" + + This reverts commit 816d1c3acfb4a457c6b1cc07d657f018312f2a63. + + missed some fixes for package release. + +commit 816d1c3acfb4a457c6b1cc07d657f018312f2a63 +Author: Arlin Davis +Date: Wed Sep 24 12:13:37 2008 -0700 + + Release 2.0.14 + + Signed-off-by: Arlin Davis + +commit c00d858da3113ce5463d408ab5e13e17cc9529e4 +Author: Arlin Davis +Date: Wed Sep 24 08:33:32 2008 -0700 + + build: $(DESTDIR) prepend needed on install hooks for dat.conf + + All install directives that automake creates automatically + have $(DESTDIR) prepended to them so that a make + DESTDIR= install will work. The hand written + install hooks for dat.conf was missing DESTDIR. + + Signed-off-by: Doug Ledford + +commit 860db3be4907c8ff290ce7c6b631b2117f5080bd +Author: Arlin Davis +Date: Wed Sep 24 08:26:28 2008 -0700 + + dapl scm: UD shares EP's which requires serialization + + add locking around the modify_qp state changes to avoid + unnecessary modify_qp calls during multiple resolve + remote AH connection events on a single EP. + + Signed-off-by: Arlin Davis + +commit f2c214647b5ce53e52052d6b6bea3fbace7cc20a +Author: Arlin Davis +Date: Sat Sep 20 16:02:00 2008 -0700 + + dtestx: Add new options to test UD. + + - many to one/many EP remote AH resolution, data flow + - bi-directional EP remote AH resolution, data flow + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit 3c218b5ed65d0b7349a86eb0fe6f6bf57e3eccd6 +Author: Arlin Davis +Date: Sat Sep 20 15:58:59 2008 -0700 + + dapl: fixes for IB UD extensions in common code and socket cm provider. + + - Manage EP states base on attribute service type. + - Allow multiple connections (remote_ah resolution) + and accepts on UD type endpoints. + - Supply private data on CR conn establishment + - Add UD extension conn event type - DAT_IB_UD_PASSIVE_REMOTE_AH + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit 01cdd688ddebec8df6f17f92c3b72a410f50dd6f +Author: Arlin Davis +Date: Sat Sep 20 15:49:40 2008 -0700 + + dapl: add provider specific attribute query option for IB UD MTU size + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit ee3d9ce2389a14c85405dfdff67f04a5f5679e32 +Author: Arlin Davis +Date: Mon Sep 1 15:52:37 2008 -0700 + + Release 2.0.13 + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit f37589927fabf0feb3a09c4c7c03e18df5749fef +Author: Arlin Davis +Date: Mon Sep 1 12:24:49 2008 -0700 + + dapl build: add correct CFLAGS, set non-debug build by default for v2 + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit 280f3aec6d0fa9d7e36f75711471e35333ee34cf +Author: Arlin Davis +Date: Mon Sep 1 12:22:19 2008 -0700 + + dapl providers: fix compiler warnings in cma and scm providers + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit 60c0589a2aba520ae67b1c8eaad5a167edb6fba3 +Author: Arlin Davis +Date: Mon Sep 1 12:20:08 2008 -0700 + + dat: fix compiler warnings in dat common code + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit fb3e368db07d02a3daa1d12d71f62ac4e7a5ef23 +Author: Arlin Davis +Date: Mon Sep 1 12:18:48 2008 -0700 + + dapl: fix compiler warnings in common code + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit 38a53ae75bce5059a84262fe1b40eacf92b22287 +Author: Arlin Davis +Date: Mon Sep 1 12:16:58 2008 -0700 + + dtest/dapltest: fix compiler warnings + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit 45900087764917b354411fdd2b3880473d553ab8 +Author: Arlin Davis +Date: Fri Aug 22 14:51:22 2008 -0700 + + dapl cma: debug message during query needs definition for inet_ntoa + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit 99d46313a03af18771966cf86fcc934d179627b5 +Author: Arlin Davis +Date: Thu Aug 21 12:54:58 2008 -0700 + + Release 2.0.12 + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit 0b2a3fac8d28d5b3c2e1416fa696fe4cbc672f00 +Author: Arlin Davis +Date: Wed Aug 20 18:51:00 2008 -0700 + + dapl scm: fix corner case that delivers duplicate disconnect events + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit 96f6822b90fa880a6c6a64b1e183064a449f7237 +Author: Arlin Davis +Date: Wed Aug 20 18:47:19 2008 -0700 + + dat: include stddef.h for NULL definition in dat_platform_specific.h + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit 283e37c09ad072d69d29e28225e9a6e8bf3f75f0 +Author: Arlin Davis +Date: Wed Aug 20 18:27:08 2008 -0700 + + dapl: add debug messages during async and overflow events + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit 4a7965ac07b7f2ee1deb5b144ed50b30c1749d38 +Author: Arlin Davis +Date: Wed Aug 20 18:24:33 2008 -0700 + + dapltest: add check for duplicate disconnect events in transaction test + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit 7e8986f2c6496851b724a007458881c3248ac998 +Author: Arlin Davis +Date: Wed Aug 20 18:22:42 2008 -0700 + + dtestx: fix stack corruption problem with hostname strcpy + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit ee2a553762abd6ebede99db5d26d1ba1d74ba3cb +Author: Arlin Davis +Date: Thu Aug 14 09:42:57 2008 -0700 + + dapl scm: use correct device attribute for max_rdma_read_out, max_qp_init_rd_atom + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit 142a8e4a99259fa6fe31f74ce6d0dac1017f381b +Author: Arlin Davis +Date: Thu Aug 14 09:19:53 2008 -0700 + + dapl scm: change IB RC qp inline and timer defaults. + + rnr nak can be the result of any operation not just + message send recevier not ready. Timer is much too + large given this case. + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit 36088a92d87e833bae535fcea0c45417dec34e65 +Author: Arlin Davis +Date: Thu Aug 14 09:12:38 2008 -0700 + + dapl scm: add mtu adjustments via environment, default = 1024. + + DAPL_IB_MTU adjusts path mtu setting for RC qp's. Default setting + is min of 1024 and active mtu on IB device. + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit a7dabdc4c1ddc62cc0384d60e8157ee829f12898 +Author: Arlin Davis +Date: Wed Aug 13 14:17:40 2008 -0700 + + dapl scm: change connect and accept to non-blocking to avoid blocking user thread. + + The connect socket that is used to exchange QP information is now non-blocking + and the data exchange is done via the cr thread. New state RTU_PENDING added. + On the passive side there is a new state ACCEPT_DATA used to avoid read blocking + on the user accept call. + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit 7e25c0f21d755cce3aa7aff993fb0baddaafc0e8 +Author: Arlin Davis +Date: Tue Jul 29 08:18:25 2008 -0700 + + dapl scm: update max_rdma_read_iov, max_rdma_write_iov EP attributes during query + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit fd9909618fdfff0eb2c8ce97bff61ea98ec44a8e +Author: Arlin Davis +Date: Sun Jul 20 13:20:45 2008 -0700 + + Release 2.0.11 + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit 0003bb7866af3ba73cc79c703b565a8012439bb1 +Author: Arlin Davis +Date: Sun Jul 20 13:17:22 2008 -0700 + + dtestx: add -d option to test new IB UD extension. + + modify dtestx to connect peer UD QP's and exchange/verify messages as an example for new extension. + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit 9816ac15f98f6e73cf7b371ac6e1e312d4171c0b +Author: Arlin Davis +Date: Sun Jul 20 13:13:09 2008 -0700 + + dapl scm: add support for UD extensions in Openfabrics socket cm provider + + add qp_type in connection information exchange + add new post_send_ud call + changes to connection manager to support qp types beyond RC. + changes to connection events to use new extended event calls. + exchange address handle information during connection phase. + changes to modify_qp to handle both RC and UD types. + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit 927dac5b61e64868089acd49d468b98327e14a1a +Author: Arlin Davis +Date: Sun Jul 20 13:07:34 2008 -0700 + + dapl: add support for UD extensions in common code. + + allow EP create for extended service types. + extend connection event types to include UD AH resolution/exchange. + add new extended connect and connect request upcalls for providers. + - dapls_evd_post_cr_event_ext + - dapls_evd_post_connection_event_ext + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit be3d6a53f3340294697706ce50a05faf151aacc7 +Author: Arlin Davis +Date: Sun Jul 20 12:57:49 2008 -0700 + + dat: New definitions for IB unreliable datagram extension + + Extend EP dat_service_type, with DAT_IB_SERVICE_TYPE_UD + Add IB extension call dat_ib_post_send_ud(). + Add address handle definition for UD calls. + Add IB event definitions to provide remote AH via connect and connect requests + Roll IB extension version to 2.0.2 + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit 8f65d4c96a7e13f7092d82f2f5aad477a61a57c1 +Author: Arlin Davis +Date: Fri Jul 18 07:46:20 2008 -0700 + + dat: allow TYPE_ERR messages to be turned off with DAT_DBG_TYPE + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit 4fefc6bca4e21c9d757923bf13bc93c62dbff17d +Author: Arlin Davis +Date: Wed Jun 25 08:02:11 2008 -0700 + + dapltest: manpage - rdma write example incorrect + + parameter for rdma write should be RW and not WR + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit 68638bde71b529a142c13ac332cd44435cabc896 +Author: Arlin Davis +Date: Mon Jun 23 15:26:30 2008 -0700 + + dapl: remove needless terminating 0 in dto_op_str functions. + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit cb1f2a144ecd375d2143d6e176a6a92a18556d7e +Author: Arlin Davis +Date: Mon Jun 23 10:52:46 2008 -0700 + + Release 2.0.10 + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit d9b3c06ae98ac4d3b264384f6510137166d78cb0 +Author: Arlin Davis +Date: Mon Jun 23 10:35:17 2008 -0700 + + remove reference to doc/dat.conf in makefile.am + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit b052d402e09ac78281a25af2c8fe902fa71f5c6f +Author: Arlin Davis +Date: Thu Jun 19 13:34:49 2008 -0700 + + dapl scm: fix ibv_destroy_cq busy error condition during dat_evd_free. + + Problem surfaced while running Intel MPI 3.1 and mpich2-test suite. + dapli_destroy_cm was incorrectly removing reference to qp_handle in endpoint + and destroy_cq and destroy_pd code was ignoring verbs errors. + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit e466d8e330c45176c5f00efda79ad745bf3f71a4 +Author: Arlin Davis +Date: Wed Jun 18 14:21:28 2008 -0700 + + dapl scm: add stdout logging for uname and gethostbyname errors during open. + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit 8e1f4db702cacdd2b9b95083db54ec38c9d2f5e5 +Author: Arlin Davis +Date: Wed Jun 18 14:19:51 2008 -0700 + + dapl scm: support global routing and set mtu based on active_mtu + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit fc65a08727c59c304dad20337a8bff803f2302c0 +Author: Arlin Davis +Date: Wed Jun 18 13:59:44 2008 -0700 + + dapl scm: Adding socket cm provider for better scalability on large homogeneous clusters. + + Bring socket cm provider back to life with some changes: + + better threading support for exchanging QP information. + Avoid blocking during connect to support dynamic connection + model with MPI implementations. + + consumer control of ack timeout/retries. + + disconnect/reject capabilities via socket exchange. + + version support for wire protocol to insure compatibility + with peer scm provider. Add gids to exchange. + + validated with Intel MPI on a 14,000+ core fabric using IB DDR. + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit 0855af175fec2f1bec8391ebae2a2cdff26a3359 +Author: Arlin Davis +Date: Wed Jun 11 10:43:24 2008 -0700 + + dapl: add opcode to string function to report opcode during failures. + + Need to use cookie opcode during failures in lieu of cqe opcode. + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit ec6296e7f0a843c69231f8284ae780014fa26fbe +Author: Arlin Davis +Date: Mon Jun 16 14:59:43 2008 -0700 + + dapl: remove unused iov buffer allocation on the endpoint + + provider's manage iov space on stack during posting. + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit c678414ced8bc9cbe21b2fc1d54aa2af73ba6528 +Author: Arlin Davis +Date: Mon Jun 16 13:59:11 2008 -0700 + + dapl: endpoint pending request count is wrong + + The code assumes every cookie allocated during posting of + requests gets completed. This incorrect assumption results in + wrong pending count. Remove request_pending field and replace + with direct call, dapl_cb_pending, to provide accurate + data to consumer. + + Add debug print if consumer overruns request queue. + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit c446a3a3f3ecbd91ab583fee35bf613ab10defcd +Author: Arlin Davis +Date: Mon Jun 2 12:40:45 2008 -0700 + + dapl extension: dapli_post_ext should always allocate cookie for requests. + + extension didn't allocate cookie if completion was suppressed which resulted + segfault during provider post call. Provider's expect cookie for wr_id, + even with surpressed completions, to handle events during errors. + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit 2583f07d9d0f55eee14e0b0e6074bc6fd0712177 +Author: Arlin Davis +Date: Tue May 20 14:35:43 2008 -0700 + + Release 2.0.9 + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit 9b38e7b792c48ea63c2078fc6c10bb843d96bd06 +Author: Arlin Davis +Date: Tue May 20 21:56:06 2008 -0700 + + dtest,dtestx,dapltest: fix build issues with Redhat EL5.1 + + need include files/definitions for sleep, getpid, gettimeofday + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit 8084ebf39729bac310447467b518df4248e9e2b6 +Author: Arlin Davis +Date: Tue May 20 14:31:09 2008 -0700 + + dapl: Fix long delays with the cma provider open call when DNS is not configure on server. + + Open call should default to netdev names when resolving local IP address for cma binding to match dat.conf settings. The open code attempts to resolve with IP or Hostname first and if there is no DNS services setup the failover to netdev name resolution is delayed for as much as 20 seconds. + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit 2f603b03f4cebe7c414cbaeecb7155f7bf1fb115 +Author: Arlin Davis +Date: Tue May 20 14:30:05 2008 -0700 + + dapl: change cma provider to use max_rdma_read_in,out from ep_attr instead of HCA max values when connecting. + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit 7a0e5fad6de7c6affc4ba3c608b0c56f4206c48c +Author: Arlin Davis +Date: Wed Apr 30 14:48:21 2008 -0700 + + Release 2.0.8 + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit 561f09ab6f9fd46a6075ecb54ca7693f2b12f311 +Author: Arlin Davis +Date: Wed Apr 30 13:51:41 2008 -0700 + + dapl: fix post_send, post_recv to handle 0 byte's and NULL iov handles + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit 0289daa3fcc4451bace8cc6b6e20ddb7bbade07e +Author: Arlin Davis +Date: Wed Apr 30 13:25:53 2008 -0700 + + dat: udat_sr_parser ia_name will fail on comments, turn down debug message + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit b93b91d48186d100c48f1a479776d56476847607 +Author: Arlin Davis +Date: Tue Apr 29 16:15:44 2008 -0700 + + dat: cleanup error handling with static registry parsing of dat.conf + + change asserts to return codes, add log messages, and + report errors via open instead of asserts during dat + library load. + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit b6b1f152efabe064ab8bdcdeecbd1edd30eb732f +Author: Arlin Davis +Date: Mon Apr 28 10:14:20 2008 -0700 + + dapl: cma provider needs to support lower inline send default for iWARP + + IB and iWARP work best with different defaults. Add transport check + and set default accordingly. 64 for iWARP, 200 for IB. + + DAPL_MAX_INLINE environment variable is still used to override. + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit be32d7d5beeeceac5dbb1974d3217265dc4d5461 +Author: Arlin Davis +Date: Mon Apr 28 09:44:12 2008 -0700 + + dtestx: need to include string.h for memset/strcpy declarations + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit a192465714e7607529303a80d8f9a312e0c7aec6 +Author: Arlin Davis +Date: Mon Apr 28 08:41:05 2008 -0700 + + dapl: add vendor_err with DTO error logging + + DAPL_GET_CQE_VENDOR_ERR added to get vendor_err via cq entry. + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit 6ac657a4e7e5e27254a024fca7fdead569043f9a +Author: Arlin Davis +Date: Fri Apr 25 15:12:34 2008 -0700 + + dapl: add check before destroying cm event channel in release + + library may be loaded and unloaded without calling open + in which case the cm event channel is not created. + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit c1eb23352f44aec6faeef37d8f0c3180f6259cf8 +Author: Arlin Davis +Date: Tue Apr 22 12:55:13 2008 -0700 + + dapl: evd_alloc doesn't check for direct_object_create errors. + + Fix error check in dapls_ib_wait_object_create() and dat_evd_alloc. + When attempting to create large number of evd's that exceed + open files limit the error was not propagated up causing + a segfault. Note: there are 3 FD's required for each EVD + 2 for pipe, and one for cq event_channel. + + Change the error reporting to indicate correct return + code and send to log with non-debug builds. + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit c5c6229b3e7744782cace0ca1f5f1fa89198bd3a +Author: Arlin Davis +Date: Mon Apr 14 13:10:13 2008 -0700 + + dapl: change packaging to modify OFA provider contents of dat.conf instead of file replacement. + + Change the packaging to update only the OFA provider contents in dat.conf. This allows other + dapl providers, other then OFA, to co-exist and configure properly. Adding manpage to explain + syntax of this static configuration file. + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit d32b27d991bc1314eea055ce3f55bb585b11aaac +Author: Arlin Davis +Date: Fri Apr 11 11:37:48 2008 -0700 + + dapl openib_cma: fix hca query to use correct max_rd_atom values + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit ac4ccfd144c01b7f4285b0cecc6218c58d0482a8 +Author: Arlin Davis +Date: Wed Apr 9 17:26:06 2008 -0700 + + dat: add logging by default during library load failures. + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit 1794e94754a1e58fcf214c2802e950124bbd1316 +Author: Arlin Davis +Date: Tue Apr 8 17:32:03 2008 -0700 + + dtest: add private data validation with connect and accept. + + Include code, with build option, to validate private data with + consumer rejects. + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit 46f21284bc05e76e82b9ad6cd9f1dbc9bcde0a28 +Author: Arlin Davis +Date: Tue Apr 8 17:25:11 2008 -0700 + + dapl: add hooks in evd connection callback code to deliver private data with consumer reject. + + PEER rejects can include private data. The common code didn't support delivery + via the connect event data structure. Add the necessary hooks in + dapl_evd_connection_callback function and include checks in openib_cma + provider to check and delivery properly. Also, fix the private data size + check in dapls_ib_reject_connection function. + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit 90e04c6f76dd5cfebd2f2867bfe22e85b0c2f461 +Author: Arlin Davis +Date: Mon Apr 7 15:47:57 2008 -0700 + + dapl: increase reject private data size to avoid odd byte offets. + + remove reject type checking on passive side since it will + always be non-consumer from active side. + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit 353a1c8a00bb2a1380fd7a372973a5a70828da35 +Author: Arlin Davis +Date: Fri Apr 4 16:04:11 2008 -0800 + + dapl: update vendor information for OFA v2 provider. + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit dbf1ea37f43caec61911dea06af801c2f906db0a +Author: Arlin Davis +Date: Fri Apr 4 16:03:03 2008 -0800 + + dapl: add provider vendor revision data in private data with reject + + Add 1 byte header containing provider/vendor major revision + to distinguish between consumer and non-consumer rejects. + Validate size of consumer reject privated data. + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit 0f71b9be594739a1fba7d74929eacd42a8cee392 +Author: Arlin Davis +Date: Thu Apr 3 17:06:27 2008 -0800 + + dapl: add support for logging errors in non-debug build. + + Add debug logging (stdout, syslog) for error cases during + device open, cm, async, and dto operations. Default settings + are ERR for DAPL_DBG_TYPE, and stdout for DAPL_DBG_DEST. + + Change default configuration to build non-debug. + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit bea882ad9b11ac7188628a939f5227e22c914169 +Author: Arlin Davis +Date: Thu Apr 3 16:23:29 2008 -0800 + + dapl: add support for private data in CR reject. + + Private data support via dat_cr_reject was added to + the v2 DAT specification but dapl was never extended + to support at the provider level. + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit b5b096b6b6949fcb9fa711ab4784f41f1bb87525 +Author: Arlin Davis +Date: Tue Apr 1 11:02:37 2008 -0800 + + dapl: calculate private data size based on transport type and cma_hdr overhead + + Need to adjust CM private date size based on different transport types. + Add hca_ptr to dapls_ib_private_data_size call for transport type + validation via verbs device. Add definitions to include iWARP size + of 512 and subtract 36 bytes for cma_hdr overhead. + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit 632af34f0ea15e12b572c656fe2ef561a0ad62b7 +Author: Arlin Davis +Date: Wed Mar 26 17:58:17 2008 -0800 + + Remove improperly licensed GETOPT code from dtest source tree. + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit 88069fdd21f92923388dec7adbde0d1bc334e7c4 +Author: Arlin Davis +Date: Tue Mar 18 15:04:34 2008 -0800 + + remove unnecessary assert from dapl_ep_free. + + dat_ep_free must handle the case where a consumer calls + free in CONNECTED or DISCONNECT_PENDING states. After + free calls disconnect, there may be a pending event, + in which case the providers dapls_ib_qp_free will block + accordingly and handle pending events. + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit b3f020e5cba765077049a8cf61c4ce5009fa1031 +Author: Patrick Marchand Latifi +Date: Fri Mar 14 14:31:40 2008 -0700 + + fix openib_scm compiler warning + + Cast to socklen_t since accept(2) expects an unsigned argument. + + Makes the openib_scm provider now build successfully when using + make VERBS= (the -Werror flag was causing the build + failure) + + Signed-off-by: Patrick Marchand Latifi + +commit 441996f05d3cc8b09c94c166ef736bc50c24de7e +Author: Patrick Marchand Latifi +Date: Fri Mar 14 14:31:34 2008 -0700 + + fix provider-specific compiler warnings + + Initialize ds_array_start_p otherwise the compiler would claim + that this variable could be used with an uninitialized value. + + Makes the uDAPL providers now build successfully when using make + VERBS= (the -Werror flag was causing the build failure) + + Signed-off-by: Patrick Marchand Latifi + +commit 5a710fc43ad004ecb4603db1359abb4a4fcd77e3 +Author: Arlin Davis +Date: Tue Mar 11 09:25:07 2008 -0800 + + uDAPL: fix query to adjust max sge for default inline of 64 bytes + and include missing max_rdma_write_iov ep_attr field + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit e2c6bf57f78dfebc21e168df01e5876202053e08 +Author: Patrick Marchand Latifi +Date: Fri Mar 7 09:39:22 2008 -0800 + + uDAT: fix reuse of va_list in debugging mode + + Make sure we reinitialize the va_list since va_list is undefined + if a function traverses the va_list with va_arg. + + This patch fixes the uDAT debugging case when both stdout and + syslog output is wanted. + + Signed-off-by: Patrick Marchand Latifi + +commit 4c9cd7a7268c0d8afb5b4d9b31537bc50cac18fe +Author: Arlin Davis +Date: Thu Mar 6 15:40:35 2008 -0800 + + Add hostname and process id to debug output to aid + scale-up and out debug. + + Signed-off by: Arlin Davis ardavis@ichips.intel.com + +commit 460aa6f089fcdb34d78af1c8391cbecbcc6b0db3 +Author: Patrick Marchand Latifi +Date: Sat Feb 23 21:03:21 2008 -0800 + + fix reuse of va_list in debugging mode + + Make sure we reinitialize the va_list since va_list is undefined + if a function traverses the va_list with va_arg. + + This patch fixes the debugging case when both stdout and syslog + output is wanted. + + Signed-off-by: Patrick Marchand Latifi + +commit da80af8c76f220508407a2e171c8b28b43b35bf9 +Author: Patrick Marchand Latifi +Date: Tue Feb 19 16:54:45 2008 -0800 + + Fix memory leak in provider specific post send/recv if there's + more than DEFAULT_DS_ENTRIES iovecs. + + Signed-off-by: Patrick Marchand Latifi + +commit d78ee9f95fbe48f71eb247b01c598994edfa4d17 +Author: Patrick Marchand Latifi +Date: Tue Feb 19 03:19:42 2008 -0800 + + Guarantee NUL termination if hostname gets truncated. + + Signed-off-by: Patrick Marchand Latifi + +commit 3484fa0d2b1a5549d83ecc82d89b72bb86f8fe4e +Author: Patrick Marchand Latifi +Date: Tue Feb 19 03:19:37 2008 -0800 + + Make sure we don't leak the hash table if dapl_hca_alloc fails. + + Signed-off-by: Patrick Marchand Latifi + +commit e4ed56be6bd64684564169d89df7ca30faffdb53 +Author: Patrick Marchand Latifi +Date: Tue Feb 19 03:19:32 2008 -0800 + + Fix memory leak. + + Signed-off-by: Patrick Marchand Latifi + +commit 9efd005b185cfd970d2f8c58f05cf2eaae0dcdc8 +Author: Patrick Marchand Latifi +Date: Tue Feb 19 03:19:27 2008 -0800 + + Fix memory leak in error path. + + Signed-off-by: Patrick Marchand Latifi + +commit d971e799bb5385a8c847cf3f863f19854e95c1b2 +Author: Patrick Marchand Latifi +Date: Tue Feb 19 03:19:22 2008 -0800 + + Fix memory leak + + Signed-off-by: Patrick Marchand Latifi + +commit c21f2f455af7934675a58ff825bed6cf54d457c9 +Author: Patrick Marchand Latifi +Date: Tue Feb 19 03:19:17 2008 -0800 + + Fix memory leak. + + Signed-off-by: Patrick Marchand Latifi + +commit ee46aa47e2a4deeded347fe18bd6321db61c6594 +Author: Arlin Davis +Date: Fri Feb 15 10:10:01 2008 -0800 + + Release 2.0.7 + + Signed-off by: Arlin Davis + +commit f0ca504bc2639cb7a48528d45e9026b54dab3e57 +Author: Arlin Davis +Date: Thu Feb 14 09:46:56 2008 -0800 + + uDAT: Make sure we initialize the dictionary entry early enough so that + we can base our cleanup decisions on that variable being + initialized. + + Signed-off-by: Patrick Marchand Latifi + +commit 6b11838043a6012668c7e1a22a869e9e84dc40d6 +Author: Arlin Davis +Date: Thu Feb 14 09:46:18 2008 -0800 + + uDAT: Make sure we stay within bounds when manipulating the ia_name. + + Signed-off-by: Patrick Marchand Latifi + Signed-off by: Arlin Davis + +commit 3eab70b4d34f850661b51dc1b856cd8d672a5cc9 +Author: Arlin Davis +Date: Thu Feb 14 09:44:56 2008 -0800 + + uDAT: Make sure we stay within bounds when manipulating the ia handle. + Fix typo in comment. + + Signed-off-by: Patrick Marchand Latifi + +commit 7fe64f10874667062e067efb7ea8c3d385ae90b7 +Author: Arlin Davis +Date: Thu Feb 14 09:43:39 2008 -0800 + + uDAT: Zero-out memory otherwise we might base our cleanup decisions on + uninitialized memory. + + Signed-off-by: Patrick Marchand Latifi + +commit f510e7e8f5b72a6262a7f8b255926cf96c65b654 +Author: Arlin Davis +Date: Wed Feb 13 20:39:26 2008 -0800 + + Modify default configure options to match rpm spec file + --enable-debug, --enable-ext-type=ib + + Signed-off by: Arlin Davis + +commit 75273f1a5c599777bb43add93f30563689fdbc10 +Author: Arlin Davis +Date: Mon Feb 11 15:43:03 2008 -0800 + + udapl OFA provider: set listen backlog to default cma backlog max. + + Signed-off by: Arlin Davis + +commit 7f173ecd7e18f25bc21a42651603922e7d71f7c7 +Author: Arlin Davis +Date: Mon Feb 11 14:50:33 2008 -0800 + + The OFA dapl provider is checking for incorrect return code + from rdma_bind_addr and rdma_listen calls. This causes an error + to be returned back to the consumer instead of correctly + incrementing the seed port and re-calling the OFA provider + until a valid port is issued. The seed value (1000) is also + incorrect and should start a non-privledged port (1024) to + avoid EPERM errors when seeding the starting port value. + + Signed-off by: Arlin Davis + +commit 7bcb67ba7c9b37d7c122773f542c7f7f718d4a49 +Author: Arlin Davis +Date: Mon Feb 4 16:16:10 2008 -0800 + + Release 2.0.6 - ChangeLog + +commit bead5f36542a8a4c790bda8ecc8dde3e630c15e6 +Author: Arlin Davis +Date: Mon Feb 4 16:14:02 2008 -0800 + + Release 2.0.6 + + Signed-off by: Arlin Davis + +commit 8c5beb870048aca286f7396549771ccb075c5c1b +Author: Arlin Davis +Date: Mon Feb 4 16:12:47 2008 -0800 + + Fix OFED v2 package to build against and target /dat2/include directory. + + Prevous patch missed dat_osd.h, dapltest/dtest incorrect. + + Signed-off by: Arlin Davis + +commit 42a63bb0271f91541e7b3c3967a9a977ef6660ae +Author: Arlin Davis +Date: Mon Feb 4 13:00:45 2008 -0800 + + uDAT/DAPL: Fix package to build against and target /dat2/include directory. + + Signed-off by: Arlin Davis + +commit b3294c738d61f44ae4d0888662bdd6b64f6d6b1f +Author: Arlin Davis +Date: Tue Jan 29 16:34:49 2008 -0800 + + Release 2.0.5 - ChangeLog updated + + Signed-off by: Arlin Davis + +commit 356cf91905d39ade06d76ab9ace6203cd7907d93 +Author: Arlin Davis +Date: Tue Jan 29 16:33:10 2008 -0800 + + libdat: rename libdat.so to libdat2.so to coexist with v1 devel + + Signed-off by: Arlin Davis + +commit d9a9f46ee220ec9c479756acc306ed68060a662f +Author: Arlin Davis +Date: Mon Jan 28 13:55:35 2008 -0800 + + Release 2.0.4 - README + + Signed-off by: Arlin Davis + +commit 533983cec914a7ecc6829934a56f867d7870e301 +Author: Arlin Davis +Date: Mon Jan 28 12:06:03 2008 -0800 + + Release 2.0.4 Changelog + + Signed-off by: Arlin Davis + +commit bfc5bd4b4190c7302b08c3922c17e2131bfbe605 +Author: Arlin Davis +Date: Mon Jan 28 12:04:18 2008 -0800 + + Relase package 2.0.4 + +commit 95935648f81ac5177ae7120b35e55483902b8c64 +Author: Arlin Davis +Date: Wed Jan 23 16:40:48 2008 -0800 + + dapltest does not include definitions for inet_ntoa. + At load time the symbol was resolved but with the + default definition of int, instead of char*, it caused + segfault. Add correct include files in dapl_mdep_user.h + for linux. + + Signed-off by: Arlin Davis + +commit 3c1bb0e56c14c5ad50876820e25933c1f4c3dde4 +Author: Arlin Davis +Date: Wed Jan 23 14:46:30 2008 -0800 + + Add freeaddrinfo to deallocate getaddrinfo buffer. + Cleanup a few printf messages. + + Signed-off by: Arlin Davis + +commit a4a8ad5eb1b15be19b3a343dee71ad3013d3f4bd +Author: Arlin Davis +Date: Wed Jan 23 14:25:21 2008 -0800 + + Fix for uDAPL v2 using extended operation. After extension completion, + the DTO cookie must be checked for type before deallocating to handle + inbound immediate data in receive. The sample dtestx client will fail + when running loopback if the rdma immediate is received from remote + before the rdma immediate request completion fires. + + Bug causes following dtestx client error: + dat_ib_post_rdma_write_immed + returned DAT_INSUFFICIENT_RESOURCES : DAT_RESOURCE_MEMORY + + Signed-off by: Arlin Davis + +commit 6dcf1763c153c27c29ba76bac35be4f6935ddd96 +Author: Arlin Davis +Date: Thu Jan 17 11:30:27 2008 -0800 + + WinOF: update dapltest,dtest directories for windows build + WinOF: add README.windows + + Signed-off by: Stan Smith + Signed-off by: Arlin Davis + +commit 9bececbb32dd31d4a3528e8f000a773e5c593430 +Author: Arlin Davis +Date: Thu Jan 17 11:24:46 2008 -0800 + + WinOF: update dtestx for windows build + + Signed-off by: Stan Smith + Signed-off by: Arlin Davis + +commit 4dc8c5defef0f52da751a1eca4d4f35de911c3c0 +Author: Arlin Davis +Date: Thu Jan 17 11:23:21 2008 -0800 + + WinOF: add build enviroment, cleanup old makefiles + + Signed-off by: Stan Smith + Signed-off by: Arlin Davis + +commit 5a9e035fa33a6307b3d2b370f64639b14dfca87e +Author: Arlin Davis +Date: Tue Jan 15 16:59:34 2008 -0800 + + WinOF: name collision with ibal verbs ib_cm_handle_t + + Signed-off by: Stan Smith + Signed-off by: Arlin Davis + +commit 7c5418a781c1dfdb37b09450b5df40363dce84b4 +Author: Arlin Davis +Date: Tue Jan 15 16:06:10 2008 -0800 + + dtest: dat_evd_query for correct size + + Signed-off by: Arlin Davis + +commit 6de5e635c01e78bde6e153b727926da900677d52 +Author: Arlin Davis +Date: Tue Jan 15 16:03:27 2008 -0800 + + dapltest: WinOF support. + + Signed-off by: Stan Smith + +commit c680e95b96e57bd8b69b1c73e95730854fcea028 +Author: Arlin Davis +Date: Tue Jan 15 14:54:57 2008 -0800 + + openib_cma: fix cleanup issues in destroy_cm_id + add macros to convert SID and PORT + fix init/responder settings in accept + + Signed-off by: Arlin Davis + +commit f8f867e52ffc36a31830dd4003eb2a4b4d265c93 +Author: Arlin Davis +Date: Tue Jan 15 14:49:54 2008 -0800 + + Modifications for WinOF build and endian support for RMR info + + Signed-off by: Stan Smith + Signed-off by: Arlin Davis + +commit 4c1fc48d2825efcffaa8cdf7efbdd2d41aeb56ab +Author: Arlin Davis +Date: Tue Jan 15 14:39:18 2008 -0800 + + WinOF: DAT_API changes, white space and tab cleanup + IBAL provider code added + + Common code: initialize cookie pool buffer + add dapl extension DTO counter + add get_cqe_op_str debug call + remove excess dbg in evd_dequeue + add dbg assert to sp_search_cr + IBAL provider support _VENDOR_IBAL_ + + Signed-off by: Stan Smith + Signed-off by: Arlin Davis + +commit 68f2ad0af3623dec27b1223aeaca6357348eef4b +Author: Arlin Davis +Date: Fri Jan 4 08:32:39 2008 -0800 + + Windows specific - + IBAL support in evd_create + Build IB extensions by default + Common code - + check return status, evd_free, evd_wait + add dapl_event_str function + definitions for dat_os_library_error, dat_os_ungetc + + Signed-off by: Stan Smith + Signed-off by: Arlin Davis + +commit d21f36406408245ac979f0b9594e7d1d0b9a3852 +Author: Arlin Davis +Date: Fri Jan 4 08:32:19 2008 -0800 + + Common code - + Missing DAT_API defs + casting to fix build issues + bitmaps for extension debug + DAPL_BAD_PTR macro + + Signed-off by: Stan Smith + Signed-off by: Arlin Davis + +commit 258678a381c6a0170020c48b0ba627e820abd3e7 +Author: Arlin Davis +Date: Fri Jan 4 08:31:59 2008 -0800 + + Common code - + Add DAT_API definitions for dat_redirection.h, udat_redirection.h + + Signed-off by: Stan Smith + Signed-off by: Arlin Davis + +commit 87d0b46a0c0f25e8828d7425e0173a0304a23f8b +Author: Arlin Davis +Date: Fri Jan 4 08:31:27 2008 -0800 + + Windows specific - + Add dapl_ep fields ibal_cm_handle, recv_disc, sent_disc for IBAL provider + Support for direct object on CQ + INIT and FINI changes + setup dat.conf default path, fix sr parsing + Common code - + Add Stan Smith as contributor + O/S independent dat_os_library_error() + + Signed-off by: Stan Smith + Signed-off by: Arlin Davis + +commit b3ba3dc9743baf3bff243e8969edf3395d1118dd +Author: Arlin Davis +Date: Tue Dec 11 14:44:24 2007 -0800 + + 2/2 uDAPL changes to sync common code base with WinOF + - add DAT_API to specify calling conventions (windows=__stdcall, linux= ) + - cleanup platform specific definitions for windows + - c++ support + - add handle check macros DAT_IA_HANDLE_TO_UL and DAT_UL_TO_IA_HANDLE + +commit 92d7eef38877ad472a91e5e9f88e4e49657716bf +Author: Arlin Davis +Date: Tue Dec 11 14:43:05 2007 -0800 + + 1/2 uDAT changes to sync common code base with WinOF + - add DAT_API to specify calling conventions (windows=__stdcall, linux= ) + - cleanup platform specific definitions for windows + - c++ support + - add handle check macros DAT_IA_HANDLE_TO_UL and DAT_UL_TO_IA_HANDLE + + Signed-off by: Arlin Davis + Signed-off by: Stan Smith + +commit 95764c6da28284d29071cf01d1a09bdcb967a971 +Author: Arlin Davis +Date: Tue Dec 4 13:19:27 2007 -0800 + + - Fix size of evd request queue on creation + - Add query and checking of DTO request queue + + Signed-off by: Arlin Davis + +commit 9bc97e65c1240224d7dc9d6ac9a48e7aed199ee6 +Merge: 11a165a... abb4356... +Author: Arlin Davis +Date: Tue Nov 27 13:31:32 2007 -0800 + + master_dat2.0_merge + +commit abb4356cd765d38cf5cff2dfbdb610b380f944a2 +Author: Arlin Davis +Date: Tue Nov 20 12:10:39 2007 -0800 + + Release 2.0.3 + +commit d2c66eb7363234c5a9fb82aa92df1c132e46477e +Author: Arlin Davis +Date: Tue Nov 20 12:07:58 2007 -0800 + + - Lower default settings (rdma ops, inline sends) for latest iWARP/IB devices + - Add missing ia_query for max_iov_segments_per_rdma_write + - Cleanup CMA code no longer supported by rdma_cm + + Signed-off by: Arlin Davis + +commit 3a3519167bd65bd999424788f139b930b099b405 +Author: Arlin Davis +Date: Mon Nov 19 15:26:44 2007 -0800 + + Change dapltest timers to use gettimeofday instead of get_cycles for better portability. + + Signed-off by: Arlin Davis + +commit 11a165a1868b1748fe476e08fc40af620f961cd2 +Author: Arlin Davis +Date: Wed Oct 31 10:58:51 2007 -0800 + + - DAT/DAPL Version 1.2.3 Release 1 + + Signed-off by: Arlin Davis + +commit bc2d39a78e31c5e9463c8fa16f0ecaf49f75a15f +Author: Arlin Davis +Date: Wed Oct 31 10:55:48 2007 -0800 + + ChangeLog update + +commit 7d3ec3d68a756f895a6c6ba8ed3d7a1d602468e9 +Author: Arlin Davis +Date: Wed Oct 31 10:55:05 2007 -0800 + + - DAT/DAPL Version 2.0.2 Release 1 + + Signed-off by: Arlin Davis + +commit 43931378b9d4f5f721da828623f1e391f32f446b +Author: Arlin Davis +Date: Tue Oct 30 09:06:24 2007 -0800 + + - Add ChangeLog + - update cma provider to report remote and local ports via dat_ep_query. + + Signed-off by: Arlin Davis + +commit a65da8a86ed637bacc32e3518d6c37eeb3b496bf +Author: Arlin Davis +Date: Thu Oct 25 14:37:14 2007 -0700 + + Fix dapltest endian issue with mem_handle, mem_address. + + Signed-off-by: Shirley Ma + +commit 8196f1655fe6088c66dafa6ad8e4474ea8ebe1d9 +Author: Arlin Davis +Date: Thu Oct 25 14:36:12 2007 -0700 + + Fix dapltest endian issue with mem_handle, mem_address. + + Signed-off-by: Shirley Ma + +commit 39667dbb0160d395fb20eb53a1b4e995e2e623dd +Author: Arlin Davis +Date: Tue Oct 16 14:23:17 2007 -0700 + + Fix dtest to build properly with extensions. + + Modify dat.h dat_event to include event_extension_data[8]. + Extend struct dat_event outside of extension build + switch to enable non-extended applications to work + with extended libraries. Otherwise, there is a potential + for the event callee to write back too much event data + and exceed callers non-extended event buffer. + + Signed-off by: Arlin Davis + +commit d7134fb2bcad6f4f68410af997f8791edd788cfb +Author: Arlin Davis +Date: Tue Oct 16 14:10:52 2007 -0700 + + Use inet_ntoa instead of open coding it. IP addresses were being + reversed on PowerPC. + + On PowerPC the timebase ticks at a different frequency to the CPU. + dapltest currently assumes a 1:1 relationship, and gives bogus values + when scaling timebase to real time. + + To fix this, look at the timebase field in /proc/cpuinfo instead. To + keep things consistent with x86, scale that value to MHz. + + Signed-off-by: Anton Blanchard + +commit c6710c291a4f7c0845a4535767d41d66f092fabf +Author: Arlin Davis +Date: Tue Oct 16 14:09:56 2007 -0700 + + Use inet_ntoa instead of open coding it. IP addresses were being + reversed on PowerPC. + + On PowerPC the timebase ticks at a different frequency to the CPU. + dapltest currently assumes a 1:1 relationship, and gives bogus values + when scaling timebase to real time. + + To fix this, look at the timebase field in /proc/cpuinfo instead. To + keep things consistent with x86, scale that value to MHz. + + Signed-off-by: Anton Blanchard + +commit 9446029979a55e6e477fb31cfdf9ce0dc77ffa8f +Author: Arlin Davis +Date: Tue Oct 16 14:02:36 2007 -0700 + + Minor clean-up of cr/lf + + Signed-off by: Arlin Davis + +commit 33fd0628497911df11dea640aea4660e54989ed6 +Author: Arlin Davis +Date: Tue Oct 2 16:01:37 2007 -0700 + + Final changes for 2.0.1-1 package, OFED 1.3 ALPHA + Fix build issue with SLES 10, gcc++ compiler + + Signed-off-by: Jimmy Hill + Signed-off-by: Arlin Davis + +commit bc5f16991d75ff9d09e3e3a3cc8c2d6801a9d61f +Author: Arlin Davis +Date: Tue Oct 2 14:50:02 2007 -0700 + + Final changes for package 1.2.2-1, OFED 1.3 ALPHA + + Signed-off by: Arlin Davis + +commit 52bc16939e87587f8208e775dd061f54196a9acb +Author: Arlin Davis +Date: Tue Oct 2 11:58:46 2007 -0700 + + Change v2 dat.conf provider names to associate with ib net devices + + Signed-off by: Arlin Davis + +commit d22e62f989dd16d503d5430ffe6f55075139e057 +Author: Arlin Davis +Date: Tue Oct 2 11:43:34 2007 -0700 + + Change DT_Mdep_GetTime to use gettimeofday() which has more resolution + than times(). + + Signed-off-by: Anton Blanchard + +commit a64eae5bd36598a5c93010e07869e95599aa8ceb +Author: Arlin Davis +Date: Tue Oct 2 11:41:40 2007 -0700 + + Change v2 dat.conf provider names to associate with ib net devices + + Signed-off by: Arlin Davis + +commit 870764dfad8df0ffe6d3d449e7a8e296cfee8ef5 +Author: Arlin Davis +Date: Tue Oct 2 11:35:21 2007 -0700 + + Change DT_Mdep_GetTime to use gettimeofday() which has more resolution + than times(). + + Signed-off-by: Anton Blanchard + +commit 66bf23e3e53f370c92803f162144947f29ce06d8 +Author: Arlin Davis +Date: Tue Oct 2 11:30:15 2007 -0700 + + Change DT_Mdep_GetTime to use gettimeofday() which has more resolution + than times(). + + Signed-off-by: Anton Blanchard + +commit c220760bbb1f6357b6e187ff6c5e576dd74fd504 +Author: Arlin Davis +Date: Tue Oct 2 10:39:09 2007 -0700 + + Fix dapl to compile as both 32bit and 64bit on PowerPC. Instead of using + the kernel atomic routines, code them explicitely like x86 does. + + Signed-off-by: Anton Blanchard + +commit 9ffdf3722e5a9cde3fd6add5d7b3940a7ea9f71f +Author: Arlin Davis +Date: Fri Sep 28 17:04:54 2007 -0700 + + Clean up packaging, modify dat.conf for v2.0 cma provider name change to ofa + + Signed-off by: Arlin Davis + +commit 493e65b5b47f47e4824f775959fd98e56aeaccc4 +Author: Arlin Davis +Date: Fri Sep 28 17:03:41 2007 -0700 + + Clean up packaging, modify dat.conf for cma provider name change to ofa + + Signed-off by: Arlin Davis + +commit 99f0a0bf0a0d99fee0729fba0fcdf6f3e89e2ec4 +Author: Arlin Davis +Date: Thu Sep 20 12:25:55 2007 -0700 + + Modifications to coexist with 2.0 libraries + - fix RPM specfile, configure.in, 1.2.2 package + - modify dat.conf + + Signed-off by: Arlin Davis + +commit 7ff4a8a8e861b0701b5b2a6fc95e6aa8b36d2662 +Author: Arlin Davis +Date: Thu Sep 20 10:55:19 2007 -0700 + + Modifications to coexist with 1.2 libraries + - cleanup CR-LF in dtestx + - fix RPM specfile, 2.0.1 package + + Signed-off by: Arlin Davis + +commit 230767742b8287490373c09d1bd346337b375b48 +Author: Arlin Davis +Date: Fri Jun 22 11:48:20 2007 -0700 + + Update copyright in specfile + +commit 5294cbe5e58f67d0a98862edea3684fff6e773bb +Author: Arlin Davis +Date: Fri Jun 22 11:47:14 2007 -0700 + + Update Copyright in specfile + +commit 3654c6ef425f94b9f27a593b0b8c1f3d7cc39029 +Author: Arlin Davis +Date: Wed Jun 6 13:20:38 2007 -0700 + + Update specfile to reflect DAT/DAPL 1.2.1 release + +commit babb95eff1bcef88bed46e92c323193d8f039eff +Author: Arlin Davis +Date: Wed Jun 6 11:48:07 2007 -0700 + + More changes to the release notes + +commit 0f299bf1deb9198b2f008c3ffa717bef252b6097 +Author: Arlin Davis +Date: Tue Jun 5 15:56:17 2007 -0700 + + Update release notes + +commit ad70f98a228ade4a863ca349990eaa7ab1e82ec2 +Author: Arlin Davis +Date: Tue Jun 5 15:52:18 2007 -0700 + + Add release notes updated for OFED 1.2 release + +commit f332badb80f0b1d88bf2d70dba0c90afc40f088f +Author: Arlin Davis +Date: Thu May 31 12:43:28 2007 -0700 + + Add provider specific interface to uDAPL for extensions support. + Fix memory leak with extensions, missing cookie deallocation when processing extended DTO events + Remove unnecessary check on dats_set_ia_handle in dat_ia_openv + Clean up specfile and some extra LF's + +commit 4d7e30586402149228a30bea3036466395577ec4 +Author: Arlin Davis +Date: Wed May 16 12:56:39 2007 -0700 + + add iwarp extension include file + +commit d9963cc9984c06f147b92877945e847f657cd512 +Author: Arlin Davis +Date: Wed May 16 12:52:38 2007 -0700 + + clean up some CR's in include files + +commit 80f4e8c4be02bac5d472e1e6c4937079882a0388 +Author: Arlin Davis +Date: Wed May 9 16:21:16 2007 -0700 + + Take out references to specific 1.1 verbs definitions (ibv_comp_channel). + +commit 544fbb873d5320e9606f176c4b71bcba0e257d7d +Author: Arlin Davis +Date: Wed May 9 12:51:53 2007 -0700 + + Bug Fixes: + - 606: Return local and remote ports with dat_ep_query + - 585: Add bonding example to dat.conf + +commit e64079f7b961aa9a672711f0e933a77f3999d302 +Author: Arlin Davis +Date: Mon May 7 15:54:59 2007 -0700 + + Update dapltest to use default device OpenIB-cma + Fix dapltest manpage, example for performance test wrong + +commit 7cda2304a6880371ec2d9451a4f83a7a254bc474 +Author: Arlin Davis +Date: Mon May 7 12:49:18 2007 -0700 + + Fix issues with IB DTO extensions + - debug print_cqe updated for latest IBV definitions + - dapli_evd_cq_to_event modified to handle both post and receive extensions + - dtestx example tested with rdma_write_imm, fetch_add, and cmp_swap + - modify cookie DTO types to support extensions properly + +commit 82a6750d31cd432c7e09298fc98c0e7e74abd012 +Author: Arlin Davis +Date: Fri May 4 17:17:41 2007 -0700 + + Add new dapl functions for 2.0 (stubs for now) + - dapl_ep_post_send_invalidate + - dapl_ep_post_rdma_read_to_rmr + - dapl_ia_ha + - dapl_csp_create, query, free + - dapl_cno_trigger + - dapl_cno_fd_create + - dapl_extensions + + Add new 2.0 parameters to existing API's + - dapl_cr_reject + - dapl_rmr_bind + +commit 8679aaf56c781715adc132a38a731e36194570f1 +Author: Arlin Davis +Date: Thu May 3 09:44:43 2007 -0700 + + update dtestx.c, default provider OpenIB-cma + +commit 527f6d19125e9eec7ecef03a8633626b0043a2f4 +Author: Arlin Davis +Date: Wed May 2 17:27:44 2007 -0700 + + Added IB extensions and dtestx as an example program using + rdma write with immediate and atomic operations + +commit 83ac961b505346708f12d59152146f3b04c8306f +Author: Arlin Davis +Date: Mon Apr 30 10:55:59 2007 -0700 + + Fixes atomic operation build problem with ia64 and RHEL5. + +commit 04da88bb70ee33b249a4cf2f5a92122eeec83e3c +Author: Arlin Davis +Date: Thu Apr 26 17:29:37 2007 -0700 + + Update README and dapltest manpage + +commit 9a951d0a8713657da90568c0613eb48f5010cf1e +Author: Arlin Davis +Date: Tue Apr 3 16:35:17 2007 -0700 + + Cleanup RPM specfile for the dapl package, move to 1.2-1 release. + +commit a93f0ffcd6a46735c97ec34de564a7a91f9fc5c2 +Author: Arlin Davis +Date: Tue Apr 3 14:38:31 2007 -0700 + + Add support for multiple IB devices to dat.conf to support IPoIB HA failover. + +commit 5434b720b36de2f262a02ff9dfccd99953c09e59 +Author: Arlin Davis +Date: Thu Mar 15 10:46:33 2007 -0800 + + Fix ia64 builds on SUSE + +commit b0f9eef1aa7f279802da233480cf6c495e16565b +Author: Arlin Davis +Date: Wed Mar 14 13:29:08 2007 -0800 + + DAT 2.0 support for new DAT_VA_TYPE added to uDAPL and openib-cma provider + +commit 61858b925f4c1a6f9edba6389a5bd601daf936e9 +Author: Arlin Davis +Date: Wed Mar 14 11:08:19 2007 -0800 + + change DAT_VERSION major and minor numbers to 2.0 + +commit 6dcb2e083bda8f2521bd3515b329c5465e1ac724 +Author: Arlin Davis +Date: Wed Mar 14 10:43:56 2007 -0800 + + add provider support to dtest, set default to OpenIB-cma + +commit ff8eb667c1000be6c68ca291e7ed7bd080cb73f4 +Author: Arlin Davis +Date: Tue Mar 13 16:20:20 2007 -0800 + + add provider option to dtest, set default to OpenIB-cma + +commit 76a43cace54567135bac7ae54e336c6595b65fd9 +Author: Arlin Davis +Date: Fri Mar 9 13:09:14 2007 -0800 + + Initial build with DAT 2.0 definitions and IB extensions. IB extensions configurable with --enable-ext-type=ib + +commit 921687efed992e6ab72dfb731687b6816324a024 +Author: Arlin Davis +Date: Thu Mar 8 16:01:29 2007 -0800 + + Update the README + +commit 52ed210ae99b291f72441e71459006b5f2c851ce +Author: Arlin Davis +Date: Wed Mar 7 15:34:41 2007 -0800 + + - Fix bug 408, dapltest compilation failure on 32 bit arch + - Update libdat.spec.in file to build uDAPL RPMs correctly + +commit e3f6aca57a8fa5cbaaf872bf6844feb7d5e1e66c +Author: Arlin Davis +Date: Mon Mar 5 14:15:49 2007 -0800 + + Fix build issues with dtest and dapltest. Define build tree path to dat/include. + +commit f1f829a28e645831c3bcd1eb2d465fcb7a1fd5d8 +Author: Arlin Davis +Date: Wed Feb 28 17:14:55 2007 -0800 + + Add dapltest headers to EXTRA_DIST + Modify dtest to delay before accepting + + Signed-off-by: Vladimir Sokolovsky + Signed-off-by: Arlin Davis + +commit 46b830a4664d5fee2daf1ebdc4e95ecb7c580e80 +Author: Arlin Davis +Date: Mon Feb 26 13:54:15 2007 -0800 + + Adding dtest and dapltest to the build. Manual pages created. + +commit d245664e27148e54469268ad81f41b2a894a131a +Author: Arlin Davis +Date: Fri Jan 19 16:21:30 2007 -0800 + + uDAPL changes to support exchanging and validation of the device responder_resources and the + initiator_depth during connection establishment + +commit 2280f833090aa9f750d5be8f9b06e7e08e642da5 +Author: Arlin Davis +Date: Wed Dec 6 11:49:27 2006 -0800 + + Update cma provider to sync with rdma_ucm changes + +commit 89448545b415b6dff57e3314b020619f6b979ef8 +Author: Arlin Davis +Date: Mon Dec 4 13:54:20 2006 -0800 + + Update autogen to create config directory + +commit 0a917b104eba0aae6c6ef49c7990a2dc7efc759d +Author: Arlin Davis +Date: Tue Nov 7 20:22:05 2006 +0000 + + r10074: Added support for new ib verbs client register event. No extra processing required at the uDAPL + level. + + Fix some issues supporting create qp without recv cq handle or recv qp resources. IB verbs assume a + recv_cq handle and uDAPL dapl_ep_create assumes there is always recv_sge resources specified. + + Fix some timeout and long disconnect delay issues discovered during scale-out testing. Added support + to retry rdma_cm address and route resolution with configuration options. Provide a disconnect call + when receiving the disconnect request to guarantee a disconnect reply and event on the remote side. + The rdma_disconnect was not being called from dat_ep_disconnect() as a result of the state changing + to DISCONNECTED in the event callback. + + Here are the new options (environment variables) with the default setting: + + DAPL_CM_ARP_TIMEOUT_MS 4000 + DAPL_CM_ARP_RETRY_COUNT 15 + DAPL_CM_ROUTE_TIMEOUT_MS 4000 + DAPL_CM_ROUTE_RETRY_COUNT 15 + +commit c73aeb904504a0bc6cce0fb1248af9ba39521395 +Author: Arlin Davis +Date: Thu Oct 12 22:41:33 2006 +0000 + + r9802: Remove Socket CM provider from build and dat.conf configuration. No longer needed nor supported. + +commit b1d94b26610f682cdd43bde2aecf5004e0865422 +Author: Steve Wise +Date: Tue Sep 12 18:15:39 2006 +0000 + + r9442: Update obsolete CLK_TCK to CLOCKS_PER_SEC + Signed-off-by: Steve Wise + Signed-off-by: James Lentini + +commit 99a5dddd07d4c271ebb075b5b0f800101f850a56 +Author: Arlin Davis +Date: Thu Sep 7 18:09:11 2006 +0000 + + r9346: + inadvertently added evdtest to makefile when testing dat_evd_set_unwaitable fix with openib_cma provider + +commit b53a87c856d9754313da9543a1dac5c6f1307085 +Author: Arlin Davis +Date: Wed Sep 6 20:36:09 2006 +0000 + + r9315: + Fill out some unitialized fields in the ia_attr structure + returned by dat_ia_query(). + + Signed-off by: Arlin Davis + Signed-off by: Robert Walsh + +commit b6c4e84399d0aa44c72c6ca870409c3666d7e79b +Author: Arlin Davis +Date: Fri Aug 11 20:44:23 2006 +0000 + + r8895: Update dtest to support multiple segments on rdma write and change makefile to use OpenIB-cma by default. + +commit 4737c63d79b23c3aff329e864dd50e3cffb6a17f +Author: Arlin Davis +Date: Wed Jul 19 17:15:06 2006 +0000 + + r8592: Add support for dat_evd_set_unwaitable on a DTO evd in openib_cma provider + +commit 25fb8c376547de895a170194c09b2d72dfea789d +Author: Arlin Davis +Date: Mon Jul 17 22:59:17 2006 +0000 + + r8565: Added errno reporting (message and return codes) during open to help diagnose create thread issues. + +commit f3a1ed6232ccdee7d193e8e3b9b0013b2bd222af +Author: Anton Blanchard +Date: Mon Jul 17 21:26:03 2006 +0000 + + r8562: Fix some suspicious inline assembly: + - EIEIO_ON_SMP and ISYNC_ON_SMP are in kernel UP build optimisations, we + shouldnt export them to userspace. Replace it with lwsync and isync. + - The comment says its implemenenting cmpxchg64 but in fact its + implementing cmpxchg32. Fix the comment. + + Signed-off-by: Anton Blanchard + Signed-off-by: James Lentini + +commit 63759108a1376b6e45a4491551f71d8cafdcddc1 +Author: James Lentini +Date: Wed Jul 12 14:56:26 2006 +0000 + + r8503: Fix IA64 build problems reported by John Partridge + Signed-off-by: James Lentini + +commit 51362c9781cb65fd8f9a3cb5b7c12c88e4c8527a +Author: Arlin Davis +Date: Thu Jun 22 22:02:56 2006 +0000 + + r8182: Lower the reject debug message level so we don't see warnings + when consumers reject. + Signed-off-by: Arlin Davis + Signed-off-by: James Lentini + +commit f14889bb0cd22e897148ea2f6931a6b4f23143b0 +Author: Arlin Davis +Date: Thu Jun 22 21:13:37 2006 +0000 + + r8181: Added support for active side TIMED_OUT event from a provider. + Signed-off-by: Arlin Davis + Signed-off-by: James Lentini + +commit 14fc704ae20b6a3ad0d433d7de9c02ce99e095b3 +Author: Arlin Davis +Date: Thu Jun 22 20:58:06 2006 +0000 + + r8180: Fix bug in dapls_ib_get_dat_event() call after adding new unreachable event. + Signed-off-by: Arlin Davis + Signed-off-by: James Lentini + +commit 893698c31a0d8e60227806d992485a44375840cb +Author: James Lentini +Date: Mon Jun 19 17:20:45 2006 +0000 + + r8112: Update for new rdma_create_id() function signature. + Signed-off-by: James Lentini + +commit 53483d84b0d02c432d9435d2f8e840cab3ded320 +Author: Arlin Davis +Date: Wed Jun 14 16:17:39 2006 +0000 + + r8008: Set max rdma read per EP attributes + Signed-off-by: Arlin Davis + Signed-off-by: James Lentini + +commit 6cb854cd72d9492ddc1c5da01dbfb24b3f30af83 +Author: Arlin Davis +Date: Mon Jun 12 15:42:50 2006 +0000 + + r7931: Report the proper error and timeout events. + Signed-off-by: Arlin Davis + Signed-off-by: James Lentini + +commit 44a97ff1f599f4bf882a801ead7aa495ea9ba936 +Author: Arlin Davis +Date: Mon Jun 12 14:51:14 2006 +0000 + + r7928: Socket CM fix to guard against using a loopback address + as the local device address. + Signed-off-by: Arlin Davis + Signed-off-by: James Lentini + +commit 152219cf83c61e459fdf3de03d4e83ddba045230 +Author: Arlin Davis +Date: Tue Jun 6 21:46:44 2006 +0000 + + r7755: Use the uCM set_option feature to adjust connect request timeout + and retry values. Also, a fix to disallow any event after a disconnect + event. + Signed-off-by: Arlin Davis + Signed-off-by: James Lentini + +commit 3a0686a2624ed28c7ea37b650415801f1cedbd10 +Author: James Lentini +Date: Wed May 31 19:55:57 2006 +0000 + + r7608: Correct comment. + Signed-off-by: James Lentini + +commit eb760157c90f59183b424ac8e71474fe0b46094c +Author: James Lentini +Date: Thu May 18 21:54:12 2006 +0000 + + r7347: Undo inadvertent change. + Signed-off-by: James Lentini + +commit 27256222b42fecfac8a44b3f82fe2524ecc72de2 +Author: James Lentini +Date: Thu May 18 21:50:27 2006 +0000 + + r7346: Fix for uCMA provider to return the correct event as a result of + rejects. Also, ran into a segv bug with dapl_ep_create when + creating without a conn_evd. + + Signed-off by: Arlin Davis + Signed-off-by: James Lentini + +commit b1b6e16f3e41e123cd347bc78b01e3272076362b +Author: Arlin Davis +Date: Fri May 12 19:50:19 2006 +0000 + + r7141: Update the uDAPL openib_cma provider to work with the new + uCMA event channel interface. + Signed-off-by: Arlin Davis + Signed-off-by: James Lentini + +commit 27f9f0c106662cc7b41bcb747495860a1b6c7133 +Author: Steve Wise +Date: Tue May 2 21:33:35 2006 +0000 + + r6873: Transaction test change to comply with the iWARP MPA protocol's + "Connection Startup Rules". + Signed-off-by: Steve Wise + Signed-off-by: James Lentini + +commit 060d09f974ffbe73672e17641b2f18d3821d31a7 +Author: Arlin Davis +Date: Fri Apr 28 13:44:17 2006 +0000 + + r6736: getaddrinfo() fix for debug builds and some additional debug messages for + connect errors and rejects. + + Signed-off-by: Arlin Davis + Signed-off-by: James Lentini + +commit 4e8b95bbeaf6e5c27de59ef347ec2ef0aa2e5e6b +Author: James Lentini +Date: Wed Apr 19 16:49:34 2006 +0000 + + r6520: Fix compilation warning. + Signed-off-by: James Lentini + +commit 115fcc396164066326f9447d71af798a381d063f +Author: Steve Wise +Date: Wed Apr 19 16:32:01 2006 +0000 + + r6518: Do not always generate an event for an abrupt disconnect. + Signed-off-by: Steve Wise + Signed-off-by: James Lentini + +commit f959bb786cd884bf4d2a5da4d299da6297d65293 +Author: James Lentini +Date: Wed Apr 19 16:30:37 2006 +0000 + + r6517: Generate a disconnect event for providers that do not generate + one automatically. + Signed-off-by: James Lentini + +commit bb467511cf6e217147817ba12bbe800aae97cab5 +Author: James Lentini +Date: Wed Apr 19 16:25:33 2006 +0000 + + r6516: Fix compilation error. + Signed-off-by: James Lentini + +commit 117a9856c269bf08b738a1923c92f5a1949f6cc1 +Author: James Lentini +Date: Mon Apr 10 20:16:44 2006 +0000 + + r6392: Fix for RDMA cm id destruction and debug builds. + Signed-off by: Arlin Davis + Signed-off-by: James Lentini + +commit 5f56b2b7339c17276188464dfff12b1be9e1dbb7 +Author: James Lentini +Date: Thu Apr 6 15:32:47 2006 +0000 + + r6289: Set max_iov_segments_per_rdma_read and max_rdma_read_iov using the correct + attribute. + Signed-off-by: James Lentini + +commit 304f48370adcaa12463c1a7d99e513164b83810c +Author: Steve Wise +Date: Thu Apr 6 15:16:10 2006 +0000 + + r6286: Set the IA attribute max_iov_segments_per_rdma_read and the EP attribute + max_rdma_read_iov based on the openib max_sge_rd device attribute. + Signed-off-by: Steve Wise + Signed-off-by: James Lentini + +commit fe27222d2a00d7c5c4d98f39d2926fe14c7f32bc +Author: James Lentini +Date: Tue Apr 4 18:29:00 2006 +0000 + + r6221: Change the mechanism by which library init and fini functions are specified + Signed-off-by: James Lentini + +commit 5a0598b90ab021cb2115e3791cb38dcfc0347948 +Author: James Lentini +Date: Mon Apr 3 17:29:55 2006 +0000 + + r6182: Remove unused variables. + Signed-off-by: James Lentini + +commit b8084c4edc21b5ac2191ec654a882b65bad0c77d +Author: James Lentini +Date: Mon Apr 3 15:29:30 2006 +0000 + + r6179: Fix dapltest compiler warnings. + Signed-off-by: James Lentini + +commit abdbec194670d72012d481b98b2e6f728e9c5b48 +Author: James Lentini +Date: Mon Apr 3 14:08:48 2006 +0000 + + r6168: Fixed debug prints of 64-bit values and removed compile warnings. + Signed-off-by: James Lentini + +commit 52de2a35e02ddeb15887d0d690b52a4e02812e57 +Author: James Lentini +Date: Tue Mar 21 22:28:10 2006 +0000 + + r5939: Move libdat.spec to libdat.spec.in + Signed-off-by: James Lentini + +commit 6b1a6356a1757ae9b9d1557bd2ae67e0913d04c2 +Author: Arlin Davis +Date: Fri Mar 17 22:02:18 2006 +0000 + + r5879: Add GNU Autotools support and an RPM spec file + Signed-off-by: Arlin Davis + Signed-off-by: James Lentini + +commit 9d00582b8be33add8d3e4173e8311b1a222b0b34 +Author: Arlin Davis +Date: Thu Mar 16 22:40:18 2006 +0000 + + r5871: Fixes a corner case where a CMA event was not acknowledged during + disconnect processing. + + Signed-off-by: Arlin Davis + Signed-off-by: James Lentini + +commit ede1d714a8e7ae99246eb382c1c1165f238cf7c3 +Author: James Lentini +Date: Mon Mar 13 18:15:49 2006 +0000 + + r5789: Reduces some debug output in the async thread and fixes listen + processing of EBUSY. + + Signed-off by: Arlin Davis + Signed-off by: James Lentini + +commit afd558cbdada66e01aa553364b9a126da00dbe65 +Author: Arlin Davis +Date: Wed Mar 8 14:24:26 2006 +0000 + + r5684: Remove unused NO_EP_STATE. + Signed-off-by: Arlin Davis + Signed-off-by: James Lentini + +commit 4c36aca16b9b492a91c0b05002af5fc954f3b44e +Author: James Lentini +Date: Tue Feb 28 15:41:03 2006 +0000 + + r5529: Fix to destroy QPs in all cases and close the HCA. + + Signed-off by: Arlin Davis + Signed-off by: James Lentini + +commit 5874fdb26436c58365a7096b9b68c8e45a51d7a3 +Author: James Lentini +Date: Mon Jan 9 20:17:33 2006 +0000 + + r4855: Make use of dat_evd_wait the default. + Signed-off-by: James Lentini + +commit 254bd0e349bafbd970d6475efcafd7e52f05415e +Author: Arlin Davis +Date: Mon Jan 9 16:59:38 2006 +0000 + + r4852: Fix disconnect event processing and update dtest to validate. + Signed-off-by: Arlin Davis + Signed-off-by: James Lentini + +commit f69d737ee51f6b00a1e6cf8531695a61a322651b +Author: Arlin Davis +Date: Fri Dec 16 02:03:05 2005 +0000 + + r4502: Query for rd_atomic values. + Signed-off-by: Arlin Davis + Signed-off-by: James Lentini + +commit 86566b556920a51f1e538d245674058682012668 +Author: James Lentini +Date: Fri Dec 16 01:57:30 2005 +0000 + + r4501: Allow a network name, network address, or device name in the dat.conf file. + Singed-off-by: Arlin Davis + Signed-off-by: James Lentini + +commit 9e0ca3d4ccb92b9c0337efbadce405076a365f0f +Author: Roland Dreier +Date: Wed Dec 14 20:44:36 2005 +0000 + + r4466: Change libibverbs API for listing all known devices from + ibv_get_devices() to ibv_get_device_list(), and update all + in-tree uses of this API. + + Signed-off-by: Roland Dreier + +commit 73a80143ab7b3f9aad19f84f904f99b489dca6cf +Author: James Lentini +Date: Mon Dec 5 16:37:46 2005 +0000 + + r4308: Fix a gcc 4.0 warning + Signed-off-by: James Lentini + +commit aa8b16b7e83f321eaaa18b38e6c165c2f120bcec +Author: Arlin Davis +Date: Thu Dec 1 15:03:10 2005 +0000 + + r4279: Added CMA API support. + Signed-off-by: Arlin Davis + Signed-off-by: James Lentini + +commit 74d3c32e42ab54f3d6f2eec3d0a66d08f800e075 +Author: James Lentini +Date: Thu Nov 10 21:39:34 2005 +0000 + + r4018: Fixed some problems with the free build openib_scm version and turned + down some debugging and added some debug prints for uAT path records. + Signed-off by: Arlin Davis + Signed-off by: James Lentini + +commit 70a2f23c5604e55f8f76672f78b4bf92f6a79b98 +Author: James Lentini +Date: Mon Oct 31 18:27:13 2005 +0000 + + r3917: Fix printing of debug statements. + Signed off by: Aniruddha Bohra + Signed off by: James Lentini +Date: Wed Oct 26 21:10:26 2005 +0000 + + r3882: uDAPL provider for OpenIB socket CM. + Signed-off by: Arlin Davis + Signed-off by: James Lentini + +commit 42a64ec2ec1d8ec71492bfebba077b006684ce97 +Author: James Lentini +Date: Thu Oct 13 20:45:22 2005 +0000 + + r3774: Fix the async error handling and callback mappings. + Updated TODO list. + Signed-off by: Arlin Davis + Signed-off by: James Lentini + +commit fea8ed1188fbeef8291cfd7e681cd48c06ff5bde +Author: Robert Walsh +Date: Fri Oct 7 21:15:00 2005 +0000 + + r3693: Update some more ignores. + +commit 303147143afa9aa72906246a9f1973e4172f75b8 +Author: Todd Bowman +Date: Thu Oct 6 21:13:32 2005 +0000 + + r3687: Add PPC64 support for udapl + Signed-off-by: Todd Bowman + Signed-off-by: James Lentini + +commit 103c7db321e24a7b5b06c7c26b0e0a65d1dd11ce +Author: Todd Bowman +Date: Thu Oct 6 15:22:08 2005 +0000 + + r3683: Remove the dtest qualifier from the sdp range. + Signed-off-by: Todd Bowman + Signed-off-by: James Lentini + +commit 33fbf9c81ac29492394e419588d856533e7fffb8 +Author: James Lentini +Date: Mon Oct 3 14:59:22 2005 +0000 + + r3637: Support CQ_WAIT_OBJECT with channels and sync with latest verbs. + Signed-off by: Arlin Davis + Signed-off by: James Lentini + +commit f01dac62b08d8f4fd417c336be48fb3bc8cd15c5 +Author: James Lentini +Date: Thu Sep 29 18:13:25 2005 +0000 + + r3619: Makefile fix. + Signed-off-by: James Lentini + +commit 634b199218b775a8ed071c1faea519c4cc4ee4e3 +Author: James Lentini +Date: Wed Sep 28 21:50:13 2005 +0000 + + r3606: Fixes IA64 build problems (atomics) with the latest Redhat EL4.0 update and + adds support for SuSe. + Signed-off by: Arlin Davis + Signed-off by: James Lentini + +commit 3a23c7135905666ff969b86dab3e90f90ac73008 +Author: Robert Walsh +Date: Tue Sep 27 16:59:14 2005 +0000 + + r3567: Setup svn:ignore on a bunch of directories. + +commit d41ea62125636a58e8748871e372810c09865b0a +Author: James Lentini +Date: Thu Sep 22 21:24:38 2005 +0000 + + r3525: Improve dtest and measure RDMA reads + Signed-off by: Arlin Davis + Signed-off-by: James Lentini + +commit 32258d13af6aaf76078ec6ba187d8129a0f70397 +Author: James Lentini +Date: Wed Sep 21 19:54:07 2005 +0000 + + r3513: Temporary workaround for the RDMA read performance anomaly + Signed-off by: Arlin Davis + Signed-off by: James Lentini + +commit 990bdc4320809e0b989c90c24bef361c1bc91c7f +Author: James Lentini +Date: Tue Sep 20 17:00:37 2005 +0000 + + r3494: Moved dapl_evd_modify_cno.c to match SourceForge + Signed-off-by: James Lentini + +commit 4509fb64fdbf99db7bdcaad4d8e3884718184d86 +Author: James Lentini +Date: Tue Sep 20 16:17:59 2005 +0000 + + r3493: Support ib_cm_init_qp_attr(), add cm event processing on a per + device basis, and add copyrights for kDAPL cm work that was + used in uDAPL. + Signed-off by: Arlin Davis + Signed-off by: James Lentini + +commit c1d45137c2e26024142f24207344e3e48a577b83 +Author: Sean Hefty +Date: Thu Sep 15 21:43:21 2005 +0000 + + r3453: Bind communication identifiers to a device to support device removal. + Export per HCA CM devices to userspace. + + Signed-off-by: Sean Hefty + +commit 5146689f1dbbce01cc46e23d749c28828e7e3ca8 +Author: James Lentini +Date: Wed Sep 14 17:44:44 2005 +0000 + + r3432: Request address resolution using ATS. + Signed-off-by: James Lentini + +commit 780b8237f2bf6884cf1abcc11190f97ed5c0a343 +Author: James Lentini +Date: Mon Sep 12 19:14:43 2005 +0000 + + r3378: Added DAPL documentation. + Signed-off-by: James Lentini + +commit 8911b60eb16770d28907c14e45556444317dd276 +Author: James Lentini +Date: Mon Sep 12 19:10:13 2005 +0000 + + r3377: Removed executable premission. + Signed-off-by: James Lentini + +commit dec4d2eafebdfe7e6b495a36dd16bd5a98417e04 +Author: Sean Hefty +Date: Fri Sep 9 21:51:58 2005 +0000 + + r3349: Update DAPL to match the verbs and CM event processing APIs. + Signed-off-by: Sean Hefty + Signed-off-by: James Lentini + +commit d06dcfd25e5d37310d089bcb7f3d3d75fcece75a +Author: Arlin Davis +Date: Tue Sep 6 19:34:46 2005 +0000 + + r3326: Changes to support async events. Also consolidated the uAT,uCM,uCQ threads into one processing thread. + Signed-off-by: Arlin Davis + Signed-off-by: James Lentini + +commit 1dd8c28ce515675ee8df37cc1596bca17587eaf6 +Author: James Lentini +Date: Mon Aug 29 15:07:44 2005 +0000 + + r3232: validate default settings so they don't exceed device maximums + Signed-off by: Arlin Davis + Signed-off by: James Lentini + +commit ac5308b4aac7de79a356439dfec2312faf7705ae +Author: James Lentini +Date: Mon Aug 29 14:15:23 2005 +0000 + + r3227: Support for ibv_query_port, device, and gid. + Signed-off by: Arlin Davis + Signed-off by: James Lentini + +commit ef8c7a3a4896487ff0d37a7d7234746c15fe5cf7 +Author: Sean Hefty +Date: Sun Aug 21 22:30:08 2005 +0000 + + r3143: - Add user specified context to all uCM events. Users will not retrieve + any events associated with the context after destroying the corresponding + cm_id. + - Provide the ib_cm_init_qp_attr() call to userspace clients of the CM. + This call may be used to set QP attributes properly before modifying the QP. + - Fixes some error handling syncrhonization and cleanup issues. + - Performs some minor code cleanup. + - Replaces the ucm_simple test program with a userspace version of cmpost. + - Updates DAPL to the new API. + + Signed-off-by: Sean Hefty + +commit ec0f86d7c55830c6dffded585c04754cc6ac2a83 +Author: James Lentini +Date: Tue Aug 16 14:10:13 2005 +0000 + + r3107: Removed unused debug counter macros + Signed-off-by: James Lentini + +commit 49087ba27bd93769bb64d7ac5c454de1b94005bc +Author: James Lentini +Date: Tue Aug 16 14:07:42 2005 +0000 + + r3106: Implemented debug counters + Signed-off by: Arlin Davis + Signed-off by: James Lentini + +commit f98e3af7dfc56b288cc77a9103b90f8d6a927fc5 +Author: James Lentini +Date: Thu Aug 11 20:23:56 2005 +0000 + + r3072: Update from SourceForge DAPL: use the LMR context in calls to + dapls_hash_remove() + Signed-off-by: James Lentini + +commit 878e524c5cc63a62802d28fdc215a2b69ceb1141 +Author: James Lentini +Date: Thu Aug 11 20:07:06 2005 +0000 + + r3071: Updates from SourceForge DAPL: EVD updates + Signed-off-by: James Lentini + +commit 8dc70f7d972615f40e624d8f1272e5e7c16ba34f +Author: James Lentini +Date: Thu Aug 11 19:57:40 2005 +0000 + + r3070: Update from SourceForge DAPL: set async evd to null in dapli_ia_release_hca + Signed-off-by: James Lentini + +commit f2801ae6caf010d660fe302970dabddc8948e1bf +Author: James Lentini +Date: Thu Aug 11 19:46:39 2005 +0000 + + r3069: Updates from SourceForge DAPL: size EP IOV correctly + Signed-off-by: James Lentini + +commit c87fd235eaf0b3a30e005422f7d347c406c14f2c +Author: James Lentini +Date: Thu Aug 11 19:35:05 2005 +0000 + + r3068: Update from SourceForge DAPL: removed duplicate ia pointer in SP structure and + fixed the spelling of ib_hca_transport_t. + Signed-off-by: James Lentini + +commit a88bebc09a9655e462b3d32dfddec823024eab59 +Author: James Lentin +Date: Thu Aug 11 19:24:56 2005 +0000 + + r3067: Update from SourceForge DAPL: use include guard + Signed-off-by: James Lentin + +commit d2da08920de882a9a266f0606b81150c625fa003 +Author: James Lentini +Date: Thu Aug 11 19:21:56 2005 +0000 + + r3066: Update from SourceForge DAPL: optimization to dapl_ep_query + Signed-off-by: James Lentini + +commit 4ca3b0cbc59227a90b5450eea1ffeeb91826dd6d +Author: James Lentini +Date: Thu Aug 11 18:39:34 2005 +0000 + + r3065: Update from DAPL SourceForge: indicate which handle is invalid + Signed-off-by: James Lentini + +commit 6d8f34137776c32149251bdec493c017b399cd10 +Author: James Lentini +Date: Thu Aug 11 18:35:58 2005 +0000 + + r3064: Update from DAPL SourceForge: set ep param values. + Signed-off-by: James Lentini + +commit 0f35002a1942303ff46cb9a2b70056f9a38aebdb +Author: James Lentini +Date: Thu Aug 11 18:33:47 2005 +0000 + + r3063: Updates from DAPL SourceForge: QP state and connection event fix. + Signed-off-by: James Lentini + +commit 3fc876339693c6f0eed5e57780e5342f301bd95c +Author: James Lentini +Date: Thu Aug 11 18:23:33 2005 +0000 + + r3062: Update from DAPL SourceForge: remove unused DAPL_CNO_PROXY_CALL + Signed-off-by: James Lentini + +commit 70f8e7a2e6bde4e757ddc8c7f59d3a5c6a13adf9 +Author: Hal Rosenstock +Date: Fri Aug 5 17:59:38 2005 +0000 + + r2989: Fix dtest makefile + Signed-off-by: Hal Rosenstock + Signed-off-by: James Lentini + +commit 864695cfef37d84359ada8838ab4cd4f4dafc6bb +Author: James Lentini +Date: Fri Aug 5 17:57:31 2005 +0000 + + r2988: Remove kernel directory. + Signed-off-by: James Lentini + +commit 9c4e246a5baf43cadc6380e91fd5a6e319777278 +Author: James Lentini +Date: Fri Aug 5 17:56:56 2005 +0000 + + r2987: Remove kernel code directory. + Signed-off-by: James Lentini + +commit 26706cb0de471ba47279de0cb949ba5a41de82cc +Author: James Lentini +Date: Fri Aug 5 16:41:12 2005 +0000 + + r2986: Add uDAPL to the trunk + Signed-off-by: James Lentini + +commit 76aa2de7fe38a8595d88669842450084cfa88316 +Author: Roland Dreier +Date: Thu Nov 4 17:54:50 2004 +0000 + + r1139: Copy roland-merge branch to trunk + +commit 3bd72a559dfe22685aae33599c99d021d2ae4aca +Author: Roland Dreier +Date: Tue Jul 20 21:34:32 2004 +0000 + + r502: Move 2.6-only source away from trunk + +commit 4f05b6ed3fd1d14161664c677264846eeb51dba5 +Author: Roland Dreier +Date: Tue Jul 20 21:34:32 2004 +0000 + + r502: Move 2.6-only source away from trunk + +commit 6da8b951c069072a2afc6aba03a3dca2c44db022 +Author: Roland Dreier +Date: Tue Jul 20 01:41:16 2004 +0000 + + r497: Move 2.6-only tree to gen2 diff --git a/branches/WOF2-3/ulp/dapl2/LICENSE.txt b/branches/WOF2-3/ulp/dapl2/LICENSE.txt new file mode 100644 index 00000000..b69ef809 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/LICENSE.txt @@ -0,0 +1,235 @@ +Common Public License 1.0 + +THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS COMMON +PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF +THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. + +1. DEFINITIONS + +"Contribution" means: + + a) in the case of the initial Contributor, the initial code and + documentation distributed under this Agreement, and + + b) in the case of each subsequent Contributor: + + i) changes to the Program, and + + ii) additions to the Program; + + where such changes and/or additions to the Program originate from + and are distributed by that particular Contributor. A Contribution + 'originates' from a Contributor if it was added to the Program by + such Contributor itself or anyone acting on such Contributor's + behalf. Contributions do not include additions to the Program + which: (i) are separate modules of software distributed in + conjunction with the Program under their own license agreement, and + (ii) are not derivative works of the Program. + +"Contributor" means any person or entity that distributes the Program. + +"Licensed Patents " mean patent claims licensable by a Contributor +which are necessarily infringed by the use or sale of its Contribution +alone or when combined with the Program. + +"Program" means the Contributions distributed in accordance with this +Agreement. + +"Recipient" means anyone who receives the Program under this Agreement, +including all Contributors. + +2. GRANT OF RIGHTS + + a) Subject to the terms of this Agreement, each Contributor hereby + grants Recipient a non-exclusive, worldwide, royalty-free copyright + license to reproduce, prepare derivative works of, publicly + display, publicly perform, distribute and sublicense the + Contribution of such Contributor, if any, and such derivative + works, in source code and object code form. + + b) Subject to the terms of this Agreement, each Contributor hereby + grants Recipient a non-exclusive, worldwide, royalty-free patent + license under Licensed Patents to make, use, sell, offer to sell, + import and otherwise transfer the Contribution of such Contributor, + if any, in source code and object code form. This patent license + shall apply to the combination of the Contribution and the Program + if, at the time the Contribution is added by the Contributor, such + addition of the Contribution causes such combination to be covered + by the Licensed Patents. The patent license shall not apply to any + other combinations which include the Contribution. No hardware per + se is licensed hereunder. + + c) Recipient understands that although each Contributor grants the + licenses to its Contributions set forth herein, no assurances are + provided by any Contributor that the Program does not infringe the + patent or other intellectual property rights of any other + entity. Each Contributor disclaims any liability to Recipient for + claims brought by any other entity based on infringement of + intellectual property rights or otherwise. As a condition to + exercising the rights and licenses granted hereunder, each + Recipient hereby assumes sole responsibility to secure any other + intellectual property rights needed, if any. For example, if a + third party patent license is required to allow Recipient to + distribute the Program, it is Recipient's responsibility to acquire + that license before distributing the Program. + + d) Each Contributor represents that to its knowledge it has + sufficient copyright rights in its Contribution, if any, to grant + the copyright license set forth in this Agreement. + +3. REQUIREMENTS + +A Contributor may choose to distribute the Program in object code form +under its own license agreement, provided that: + + a) it complies with the terms and conditions of this Agreement; and + + b) its license agreement: + + i) effectively disclaims on behalf of all Contributors all + warranties and conditions, express and implied, including + warranties or conditions of title and non-infringement, and implied + warranties or conditions of merchantability and fitness for a + particular purpose; + + ii) effectively excludes on behalf of all Contributors all + liability for damages, including direct, indirect, special, + incidental and consequential damages, such as lost profits; + + iii) states that any provisions which differ from this Agreement + are offered by that Contributor alone and not by any other party; + and + + iv) states that source code for the Program is available from such + Contributor, and informs licensees how to obtain it in a reasonable + manner on or through a medium customarily used for software + exchange. + +When the Program is made available in source code form: + + a) it must be made available under this Agreement; and + + b) a copy of this Agreement must be included with each copy of the + Program. + +Contributors may not remove or alter any copyright notices contained +within the Program. + +Each Contributor must identify itself as the originator of its +Contribution, if any, in a manner that reasonably allows subsequent +Recipients to identify the originator of the Contribution. + +4. COMMERCIAL DISTRIBUTION + +Commercial distributors of software may accept certain responsibilities +with respect to end users, business partners and the like. While this +license is intended to facilitate the commercial use of the Program, the +Contributor who includes the Program in a commercial product offering +should do so in a manner which does not create potential liability for +other Contributors. Therefore, if a Contributor includes the Program in +a commercial product offering, such Contributor ("Commercial +Contributor") hereby agrees to defend and indemnify every other +Contributor ("Indemnified Contributor") against any losses, damages and +costs (collectively "Losses") arising from claims, lawsuits and other +legal actions brought by a third party against the Indemnified +Contributor to the extent caused by the acts or omissions of such +Commercial Contributor in connection with its distribution of the +Program in a commercial product offering. The obligations in this +section do not apply to any claims or Losses relating to any actual or +alleged intellectual property infringement. In order to qualify, an +Indemnified Contributor must: a) promptly notify the Commercial +Contributor in writing of such claim, and b) allow the Commercial +Contributor to control, and cooperate with the Commercial Contributor +in, the defense and any related settlement negotiations. The Indemnified +Contributor may participate in any such claim at its own expense. + +For example, a Contributor might include the Program in a commercial +product offering, Product X. That Contributor is then a Commercial +Contributor. If that Commercial Contributor then makes performance +claims, or offers warranties related to Product X, those performance +claims and warranties are such Commercial Contributor's responsibility +alone. Under this section, the Commercial Contributor would have to +defend claims against the other Contributors related to those +performance claims and warranties, and if a court requires any other +Contributor to pay any damages as a result, the Commercial Contributor +must pay those damages. + +5. NO WARRANTY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS +PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY +WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR +FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible +for determining the appropriateness of using and distributing the +Program and assumes all risks associated with its exercise of rights +under this Agreement, including but not limited to the risks and costs +of program errors, compliance with applicable laws, damage to or loss +of data, programs or equipment, and unavailability or interruption of +operations. + +6. DISCLAIMER OF LIABILITY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR +ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING +WITHOUT LIMITATION LOST PROFITS), 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 OR +DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED +HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +7. GENERAL + +If any provision of this Agreement is invalid or unenforceable under +applicable law, it shall not affect the validity or enforceability of +the remainder of the terms of this Agreement, and without further +action by the parties hereto, such provision shall be reformed to the +minimum extent necessary to make such provision valid and enforceable. + +If Recipient institutes patent litigation against a Contributor with +respect to a patent applicable to software (including a cross-claim or +counterclaim in a lawsuit), then any patent licenses granted by that +Contributor to such Recipient under this Agreement shall terminate as +of the date such litigation is filed. In addition, if Recipient +institutes patent litigation against any entity (including a cross- +claim or counterclaim in a lawsuit) alleging that the Program itself +(excluding combinations of the Program with other software or hardware) +infringes such Recipient's patent(s), then such Recipient's rights +granted under Section 2(b) shall terminate as of the date such +litigation is filed. + +All Recipient's rights under this Agreement shall terminate if it fails +to comply with any of the material terms or conditions of this +Agreement and does not cure such failure in a reasonable period of time +after becoming aware of such noncompliance. If all Recipient's rights +under this Agreement terminate, Recipient agrees to cease use and +distribution of the Program as soon as reasonably practicable. However, +Recipient's obligations under this Agreement and any licenses granted +by Recipient relating to the Program shall continue and survive. + +Everyone is permitted to copy and distribute copies of this Agreement, +but in order to avoid inconsistency the Agreement is copyrighted and +may only be modified in the following manner. The Agreement Steward +reserves the right to publish new versions (including revisions) of +this Agreement from time to time. No one other than the Agreement +Steward has the right to modify this Agreement. IBM is the initial +Agreement Steward. IBM may assign the responsibility to serve as the +Agreement Steward to a suitable separate entity. Each new version of +the Agreement will be given a distinguishing version number. The +Program (including Contributions) may always be distributed subject to +the version of the Agreement under which it was received. In addition, +after a new version of the Agreement is published, Contributor may +elect to distribute the Program (including its Contributions) under the +new version. Except as expressly stated in Sections 2(a) and 2(b) +above, Recipient receives no rights or licenses to the intellectual +property of any Contributor under this Agreement, whether expressly, by +implication, estoppel or otherwise. All rights in the Program not +expressly granted under this Agreement are reserved. + +This Agreement is governed by the laws of the State of New York and the +intellectual property laws of the United States of America. No party to +this Agreement will bring a legal action under this Agreement more than +one year after the cause of action arose. Each party waives its rights +to a jury trial in any resulting litigation. + diff --git a/branches/WOF2-3/ulp/dapl2/LICENSE2.txt b/branches/WOF2-3/ulp/dapl2/LICENSE2.txt new file mode 100644 index 00000000..04c18392 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/LICENSE2.txt @@ -0,0 +1,30 @@ +Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + Neither the name of the Network Appliance, Inc. nor the names of + its contributors may be used to endorse or promote products + derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/branches/WOF2-3/ulp/dapl2/LICENSE3.txt b/branches/WOF2-3/ulp/dapl2/LICENSE3.txt new file mode 100644 index 00000000..0ecbca23 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/LICENSE3.txt @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE +Version 2, June 1991 + +Copyright (C) 1989, 1991 Free Software Foundation, Inc. +59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +Everyone is permitted to copy and distribute verbatim copies +of this license document, but changing it is not allowed. + +Preamble + +The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + +When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + +To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + +For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + +We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + +Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + +Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + +The precise terms and conditions for copying, distribution and +modification follow. + +GNU GENERAL PUBLIC LICENSE +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + +1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + +2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + +a) You must cause the modified files to carry prominent notices +stating that you changed the files and the date of any change. + +b) You must cause any work that you distribute or publish, that in +whole or in part contains or is derived from the Program or any +part thereof, to be licensed as a whole at no charge to all third +parties under the terms of this License. + +c) If the modified program normally reads commands interactively +when run, you must cause it, when started running for such +interactive use in the most ordinary way, to print or display an +announcement including an appropriate copyright notice and a +notice that there is no warranty (or else, saying that you provide +a warranty) and that users may redistribute the program under +these conditions, and telling the user how to view a copy of this +License. (Exception: if the Program itself is interactive but +does not normally print such an announcement, your work based on +the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + +3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + +a) Accompany it with the complete corresponding machine-readable +source code, which must be distributed under the terms of Sections +1 and 2 above on a medium customarily used for software interchange; or, + +b) Accompany it with a written offer, valid for at least three +years, to give any third party, for a charge no more than your +cost of physically performing source distribution, a complete +machine-readable copy of the corresponding source code, to be +distributed under the terms of Sections 1 and 2 above on a medium +customarily used for software interchange; or, + +c) Accompany it with the information you received as to the offer +to distribute corresponding source code. (This alternative is +allowed only for noncommercial distribution and only if you +received the program in object code or executable form with such +an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + +4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + +5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + +6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + +7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + +8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + +9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + +10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + +NO WARRANTY + +11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + +12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + +END OF TERMS AND CONDITIONS + +How to Apply These Terms to Your New Programs + +If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + +To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + +Copyright (C) + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + +Gnomovision version 69, Copyright (C) year name of author +Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. +This is free software, and you are welcome to redistribute it +under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + +Yoyodyne, Inc., hereby disclaims all copyright interest in the program +`Gnomovision' (which makes passes at compilers) written by James Hacker. + +, 1 April 1989 +Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/branches/WOF2-3/ulp/dapl2/Makefile.am b/branches/WOF2-3/ulp/dapl2/Makefile.am new file mode 100644 index 00000000..0be62980 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/Makefile.am @@ -0,0 +1,581 @@ +# $Id: $ + +OSFLAGS = -DOS_RELEASE=$(shell expr `uname -r | cut -f1 -d.` \* 65536 + `uname -r | cut -f2 -d.`) +# Check for RedHat, needed for ia64 udapl atomic operations (IA64_FETCHADD syntax) +# and built-in atomics for RedHat EL5 +if OS_RHEL4 +OSFLAGS += -DREDHAT_EL4 +endif + +if OS_RHEL5 +OSFLAGS += -DREDHAT_EL5 +endif + +if OS_SUSE11 +OSFLAGS += -DSUSE_11 +endif + +if EXT_TYPE_IB +XFLAGS = -DDAT_EXTENSIONS +XPROGRAMS = dapl/openib_common/ib_extensions.c +else +XFLAGS = +XPROGRAMS = +endif + +if DEFINE_ATTR_LINK_LAYER +XFLAGS += -DDEFINE_ATTR_LINK_LAYER +endif + +if DEBUG +AM_CFLAGS = -g -Wall -D_GNU_SOURCE -DDAPL_DBG -DDAT_CONF="\"$(sysconfdir)/dat.conf\"" +else +AM_CFLAGS = -g -Wall -D_GNU_SOURCE -DDAT_CONF="\"$(sysconfdir)/dat.conf\"" +endif + +datlibdir = $(libdir) +dapllibofadir = $(libdir) +daplliboscmdir = $(libdir) +daplliboucmdir = $(libdir) + +datlib_LTLIBRARIES = dat/udat/libdat2.la +dapllibofa_LTLIBRARIES = dapl/udapl/libdaplofa.la +daplliboscm_LTLIBRARIES = dapl/udapl/libdaploscm.la +daplliboucm_LTLIBRARIES = dapl/udapl/libdaploucm.la + +dat_udat_libdat2_la_CFLAGS = $(AM_CFLAGS) -D_GNU_SOURCE $(OSFLAGS) $(XFLAGS) \ + -I$(srcdir)/dat/include/ -I$(srcdir)/dat/udat/ \ + -I$(srcdir)/dat/udat/linux -I$(srcdir)/dat/common/ + +dapl_udapl_libdaplofa_la_CFLAGS = $(AM_CFLAGS) -D_GNU_SOURCE $(OSFLAGS) $(XFLAGS) \ + -DOPENIB -DCQ_WAIT_OBJECT \ + -I$(srcdir)/dat/include/ -I$(srcdir)/dapl/include/ \ + -I$(srcdir)/dapl/common -I$(srcdir)/dapl/udapl/linux \ + -I$(srcdir)/dapl/openib_common \ + -I$(srcdir)/dapl/openib_cma \ + -I$(srcdir)/dapl/openib_cma/linux + +dapl_udapl_libdaploscm_la_CFLAGS = $(AM_CFLAGS) -D_GNU_SOURCE $(OSFLAGS) $(XFLAGS) \ + -DOPENIB -DCQ_WAIT_OBJECT \ + -I$(srcdir)/dat/include/ -I$(srcdir)/dapl/include/ \ + -I$(srcdir)/dapl/common -I$(srcdir)/dapl/udapl/linux \ + -I$(srcdir)/dapl/openib_common \ + -I$(srcdir)/dapl/openib_scm \ + -I$(srcdir)/dapl/openib_scm/linux + +dapl_udapl_libdaploucm_la_CFLAGS = $(AM_CFLAGS) -D_GNU_SOURCE $(OSFLAGS) $(XFLAGS) \ + -DOPENIB -DCQ_WAIT_OBJECT \ + -I$(srcdir)/dat/include/ -I$(srcdir)/dapl/include/ \ + -I$(srcdir)/dapl/common -I$(srcdir)/dapl/udapl/linux \ + -I$(srcdir)/dapl/openib_common \ + -I$(srcdir)/dapl/openib_ucm \ + -I$(srcdir)/dapl/openib_ucm/linux + +if HAVE_LD_VERSION_SCRIPT + dat_version_script = -Wl,--version-script=$(srcdir)/dat/udat/libdat2.map + daplofa_version_script = -Wl,--version-script=$(srcdir)/dapl/udapl/libdaplofa.map + daploscm_version_script = -Wl,--version-script=$(srcdir)/dapl/udapl/libdaploscm.map + daploucm_version_script = -Wl,--version-script=$(srcdir)/dapl/udapl/libdaploucm.map +else + dat_version_script = + daplofa_version_script = + daploscm_version_script = + daploucm_version_script = +endif + +# +# uDAT: libdat2.so +# +dat_udat_libdat2_la_SOURCES = dat/udat/udat.c \ + dat/udat/udat_api.c \ + dat/udat/udat_sr_parser.c \ + dat/udat/linux/dat_osd.c \ + dat/common/dat_api.c \ + dat/common/dat_dictionary.c \ + dat/common/dat_strerror.c \ + dat/common/dat_init.c \ + dat/common/dat_dr.c \ + dat/common/dat_sr.c +dat_udat_libdat2_la_LDFLAGS = -version-info 2:0:0 $(dat_version_script) -ldl + +# +# uDAPL OpenFabrics rdma_cm version: libdaplofa.so +# +dapl_udapl_libdaplofa_la_SOURCES = dapl/udapl/dapl_init.c \ + dapl/udapl/dapl_evd_create.c \ + dapl/udapl/dapl_evd_query.c \ + dapl/udapl/dapl_cno_create.c \ + dapl/udapl/dapl_cno_modify_agent.c \ + dapl/udapl/dapl_cno_free.c \ + dapl/udapl/dapl_cno_wait.c \ + dapl/udapl/dapl_cno_query.c \ + dapl/udapl/dapl_lmr_create.c \ + dapl/udapl/dapl_evd_wait.c \ + dapl/udapl/dapl_evd_disable.c \ + dapl/udapl/dapl_evd_enable.c \ + dapl/udapl/dapl_evd_modify_cno.c \ + dapl/udapl/dapl_evd_set_unwaitable.c \ + dapl/udapl/dapl_evd_clear_unwaitable.c \ + dapl/udapl/linux/dapl_osd.c \ + dapl/common/dapl_cookie.c \ + dapl/common/dapl_cr_accept.c \ + dapl/common/dapl_cr_query.c \ + dapl/common/dapl_cr_reject.c \ + dapl/common/dapl_cr_util.c \ + dapl/common/dapl_cr_callback.c \ + dapl/common/dapl_cr_handoff.c \ + dapl/common/dapl_ep_connect.c \ + dapl/common/dapl_ep_create.c \ + dapl/common/dapl_ep_disconnect.c \ + dapl/common/dapl_ep_dup_connect.c \ + dapl/common/dapl_ep_free.c \ + dapl/common/dapl_ep_reset.c \ + dapl/common/dapl_ep_get_status.c \ + dapl/common/dapl_ep_modify.c \ + dapl/common/dapl_ep_post_rdma_read.c \ + dapl/common/dapl_ep_post_rdma_write.c \ + dapl/common/dapl_ep_post_recv.c \ + dapl/common/dapl_ep_post_send.c \ + dapl/common/dapl_ep_query.c \ + dapl/common/dapl_ep_util.c \ + dapl/common/dapl_evd_dequeue.c \ + dapl/common/dapl_evd_free.c \ + dapl/common/dapl_evd_post_se.c \ + dapl/common/dapl_evd_resize.c \ + dapl/common/dapl_evd_util.c \ + dapl/common/dapl_evd_cq_async_error_callb.c \ + dapl/common/dapl_evd_qp_async_error_callb.c \ + dapl/common/dapl_evd_un_async_error_callb.c \ + dapl/common/dapl_evd_connection_callb.c \ + dapl/common/dapl_evd_dto_callb.c \ + dapl/common/dapl_get_consumer_context.c \ + dapl/common/dapl_get_handle_type.c \ + dapl/common/dapl_hash.c \ + dapl/common/dapl_hca_util.c \ + dapl/common/dapl_ia_close.c \ + dapl/common/dapl_ia_open.c \ + dapl/common/dapl_ia_query.c \ + dapl/common/dapl_ia_util.c \ + dapl/common/dapl_llist.c \ + dapl/common/dapl_lmr_free.c \ + dapl/common/dapl_lmr_query.c \ + dapl/common/dapl_lmr_util.c \ + dapl/common/dapl_lmr_sync_rdma_read.c \ + dapl/common/dapl_lmr_sync_rdma_write.c \ + dapl/common/dapl_mr_util.c \ + dapl/common/dapl_provider.c \ + dapl/common/dapl_sp_util.c \ + dapl/common/dapl_psp_create.c \ + dapl/common/dapl_psp_create_any.c \ + dapl/common/dapl_psp_free.c \ + dapl/common/dapl_psp_query.c \ + dapl/common/dapl_pz_create.c \ + dapl/common/dapl_pz_free.c \ + dapl/common/dapl_pz_query.c \ + dapl/common/dapl_pz_util.c \ + dapl/common/dapl_rmr_create.c \ + dapl/common/dapl_rmr_free.c \ + dapl/common/dapl_rmr_bind.c \ + dapl/common/dapl_rmr_query.c \ + dapl/common/dapl_rmr_util.c \ + dapl/common/dapl_rsp_create.c \ + dapl/common/dapl_rsp_free.c \ + dapl/common/dapl_rsp_query.c \ + dapl/common/dapl_cno_util.c \ + dapl/common/dapl_set_consumer_context.c \ + dapl/common/dapl_ring_buffer_util.c \ + dapl/common/dapl_name_service.c \ + dapl/common/dapl_timer_util.c \ + dapl/common/dapl_ep_create_with_srq.c \ + dapl/common/dapl_ep_recv_query.c \ + dapl/common/dapl_ep_set_watermark.c \ + dapl/common/dapl_srq_create.c \ + dapl/common/dapl_srq_free.c \ + dapl/common/dapl_srq_query.c \ + dapl/common/dapl_srq_resize.c \ + dapl/common/dapl_srq_post_recv.c \ + dapl/common/dapl_srq_set_lw.c \ + dapl/common/dapl_srq_util.c \ + dapl/common/dapl_debug.c \ + dapl/common/dapl_ia_ha.c \ + dapl/common/dapl_csp.c \ + dapl/common/dapl_ep_post_send_invalidate.c \ + dapl/common/dapl_ep_post_rdma_read_to_rmr.c \ + dapl/openib_common/mem.c \ + dapl/openib_common/cq.c \ + dapl/openib_common/qp.c \ + dapl/openib_common/util.c \ + dapl/openib_cma/cm.c \ + dapl/openib_cma/device.c $(XPROGRAMS) + +dapl_udapl_libdaplofa_la_LDFLAGS = -version-info 2:0:0 $(daplofa_version_script) \ + -Wl,-init,dapl_init -Wl,-fini,dapl_fini \ + -lpthread -libverbs -lrdmacm + +# +# uDAPL OpenFabrics Socket CM version for IB: libdaplscm.so +# +dapl_udapl_libdaploscm_la_SOURCES = dapl/udapl/dapl_init.c \ + dapl/udapl/dapl_evd_create.c \ + dapl/udapl/dapl_evd_query.c \ + dapl/udapl/dapl_cno_create.c \ + dapl/udapl/dapl_cno_modify_agent.c \ + dapl/udapl/dapl_cno_free.c \ + dapl/udapl/dapl_cno_wait.c \ + dapl/udapl/dapl_cno_query.c \ + dapl/udapl/dapl_lmr_create.c \ + dapl/udapl/dapl_evd_wait.c \ + dapl/udapl/dapl_evd_disable.c \ + dapl/udapl/dapl_evd_enable.c \ + dapl/udapl/dapl_evd_modify_cno.c \ + dapl/udapl/dapl_evd_set_unwaitable.c \ + dapl/udapl/dapl_evd_clear_unwaitable.c \ + dapl/udapl/linux/dapl_osd.c \ + dapl/common/dapl_cookie.c \ + dapl/common/dapl_cr_accept.c \ + dapl/common/dapl_cr_query.c \ + dapl/common/dapl_cr_reject.c \ + dapl/common/dapl_cr_util.c \ + dapl/common/dapl_cr_callback.c \ + dapl/common/dapl_cr_handoff.c \ + dapl/common/dapl_ep_connect.c \ + dapl/common/dapl_ep_create.c \ + dapl/common/dapl_ep_disconnect.c \ + dapl/common/dapl_ep_dup_connect.c \ + dapl/common/dapl_ep_free.c \ + dapl/common/dapl_ep_reset.c \ + dapl/common/dapl_ep_get_status.c \ + dapl/common/dapl_ep_modify.c \ + dapl/common/dapl_ep_post_rdma_read.c \ + dapl/common/dapl_ep_post_rdma_write.c \ + dapl/common/dapl_ep_post_recv.c \ + dapl/common/dapl_ep_post_send.c \ + dapl/common/dapl_ep_query.c \ + dapl/common/dapl_ep_util.c \ + dapl/common/dapl_evd_dequeue.c \ + dapl/common/dapl_evd_free.c \ + dapl/common/dapl_evd_post_se.c \ + dapl/common/dapl_evd_resize.c \ + dapl/common/dapl_evd_util.c \ + dapl/common/dapl_evd_cq_async_error_callb.c \ + dapl/common/dapl_evd_qp_async_error_callb.c \ + dapl/common/dapl_evd_un_async_error_callb.c \ + dapl/common/dapl_evd_connection_callb.c \ + dapl/common/dapl_evd_dto_callb.c \ + dapl/common/dapl_get_consumer_context.c \ + dapl/common/dapl_get_handle_type.c \ + dapl/common/dapl_hash.c \ + dapl/common/dapl_hca_util.c \ + dapl/common/dapl_ia_close.c \ + dapl/common/dapl_ia_open.c \ + dapl/common/dapl_ia_query.c \ + dapl/common/dapl_ia_util.c \ + dapl/common/dapl_llist.c \ + dapl/common/dapl_lmr_free.c \ + dapl/common/dapl_lmr_query.c \ + dapl/common/dapl_lmr_util.c \ + dapl/common/dapl_lmr_sync_rdma_read.c \ + dapl/common/dapl_lmr_sync_rdma_write.c \ + dapl/common/dapl_mr_util.c \ + dapl/common/dapl_provider.c \ + dapl/common/dapl_sp_util.c \ + dapl/common/dapl_psp_create.c \ + dapl/common/dapl_psp_create_any.c \ + dapl/common/dapl_psp_free.c \ + dapl/common/dapl_psp_query.c \ + dapl/common/dapl_pz_create.c \ + dapl/common/dapl_pz_free.c \ + dapl/common/dapl_pz_query.c \ + dapl/common/dapl_pz_util.c \ + dapl/common/dapl_rmr_create.c \ + dapl/common/dapl_rmr_free.c \ + dapl/common/dapl_rmr_bind.c \ + dapl/common/dapl_rmr_query.c \ + dapl/common/dapl_rmr_util.c \ + dapl/common/dapl_rsp_create.c \ + dapl/common/dapl_rsp_free.c \ + dapl/common/dapl_rsp_query.c \ + dapl/common/dapl_cno_util.c \ + dapl/common/dapl_set_consumer_context.c \ + dapl/common/dapl_ring_buffer_util.c \ + dapl/common/dapl_name_service.c \ + dapl/common/dapl_timer_util.c \ + dapl/common/dapl_ep_create_with_srq.c \ + dapl/common/dapl_ep_recv_query.c \ + dapl/common/dapl_ep_set_watermark.c \ + dapl/common/dapl_srq_create.c \ + dapl/common/dapl_srq_free.c \ + dapl/common/dapl_srq_query.c \ + dapl/common/dapl_srq_resize.c \ + dapl/common/dapl_srq_post_recv.c \ + dapl/common/dapl_srq_set_lw.c \ + dapl/common/dapl_srq_util.c \ + dapl/common/dapl_debug.c \ + dapl/common/dapl_ia_ha.c \ + dapl/common/dapl_csp.c \ + dapl/common/dapl_ep_post_send_invalidate.c \ + dapl/common/dapl_ep_post_rdma_read_to_rmr.c \ + dapl/openib_common/mem.c \ + dapl/openib_common/cq.c \ + dapl/openib_common/qp.c \ + dapl/openib_common/util.c \ + dapl/openib_scm/cm.c \ + dapl/openib_scm/device.c $(XPROGRAMS) + +dapl_udapl_libdaploscm_la_LDFLAGS = -version-info 2:0:0 $(daploscm_version_script) \ + -Wl,-init,dapl_init -Wl,-fini,dapl_fini \ + -lpthread -libverbs + +# +# uDAPL OpenFabrics UD CM version for IB: libdaplucm.so +# +dapl_udapl_libdaploucm_la_SOURCES = dapl/udapl/dapl_init.c \ + dapl/udapl/dapl_evd_create.c \ + dapl/udapl/dapl_evd_query.c \ + dapl/udapl/dapl_cno_create.c \ + dapl/udapl/dapl_cno_modify_agent.c \ + dapl/udapl/dapl_cno_free.c \ + dapl/udapl/dapl_cno_wait.c \ + dapl/udapl/dapl_cno_query.c \ + dapl/udapl/dapl_lmr_create.c \ + dapl/udapl/dapl_evd_wait.c \ + dapl/udapl/dapl_evd_disable.c \ + dapl/udapl/dapl_evd_enable.c \ + dapl/udapl/dapl_evd_modify_cno.c \ + dapl/udapl/dapl_evd_set_unwaitable.c \ + dapl/udapl/dapl_evd_clear_unwaitable.c \ + dapl/udapl/linux/dapl_osd.c \ + dapl/common/dapl_cookie.c \ + dapl/common/dapl_cr_accept.c \ + dapl/common/dapl_cr_query.c \ + dapl/common/dapl_cr_reject.c \ + dapl/common/dapl_cr_util.c \ + dapl/common/dapl_cr_callback.c \ + dapl/common/dapl_cr_handoff.c \ + dapl/common/dapl_ep_connect.c \ + dapl/common/dapl_ep_create.c \ + dapl/common/dapl_ep_disconnect.c \ + dapl/common/dapl_ep_dup_connect.c \ + dapl/common/dapl_ep_free.c \ + dapl/common/dapl_ep_reset.c \ + dapl/common/dapl_ep_get_status.c \ + dapl/common/dapl_ep_modify.c \ + dapl/common/dapl_ep_post_rdma_read.c \ + dapl/common/dapl_ep_post_rdma_write.c \ + dapl/common/dapl_ep_post_recv.c \ + dapl/common/dapl_ep_post_send.c \ + dapl/common/dapl_ep_query.c \ + dapl/common/dapl_ep_util.c \ + dapl/common/dapl_evd_dequeue.c \ + dapl/common/dapl_evd_free.c \ + dapl/common/dapl_evd_post_se.c \ + dapl/common/dapl_evd_resize.c \ + dapl/common/dapl_evd_util.c \ + dapl/common/dapl_evd_cq_async_error_callb.c \ + dapl/common/dapl_evd_qp_async_error_callb.c \ + dapl/common/dapl_evd_un_async_error_callb.c \ + dapl/common/dapl_evd_connection_callb.c \ + dapl/common/dapl_evd_dto_callb.c \ + dapl/common/dapl_get_consumer_context.c \ + dapl/common/dapl_get_handle_type.c \ + dapl/common/dapl_hash.c \ + dapl/common/dapl_hca_util.c \ + dapl/common/dapl_ia_close.c \ + dapl/common/dapl_ia_open.c \ + dapl/common/dapl_ia_query.c \ + dapl/common/dapl_ia_util.c \ + dapl/common/dapl_llist.c \ + dapl/common/dapl_lmr_free.c \ + dapl/common/dapl_lmr_query.c \ + dapl/common/dapl_lmr_util.c \ + dapl/common/dapl_lmr_sync_rdma_read.c \ + dapl/common/dapl_lmr_sync_rdma_write.c \ + dapl/common/dapl_mr_util.c \ + dapl/common/dapl_provider.c \ + dapl/common/dapl_sp_util.c \ + dapl/common/dapl_psp_create.c \ + dapl/common/dapl_psp_create_any.c \ + dapl/common/dapl_psp_free.c \ + dapl/common/dapl_psp_query.c \ + dapl/common/dapl_pz_create.c \ + dapl/common/dapl_pz_free.c \ + dapl/common/dapl_pz_query.c \ + dapl/common/dapl_pz_util.c \ + dapl/common/dapl_rmr_create.c \ + dapl/common/dapl_rmr_free.c \ + dapl/common/dapl_rmr_bind.c \ + dapl/common/dapl_rmr_query.c \ + dapl/common/dapl_rmr_util.c \ + dapl/common/dapl_rsp_create.c \ + dapl/common/dapl_rsp_free.c \ + dapl/common/dapl_rsp_query.c \ + dapl/common/dapl_cno_util.c \ + dapl/common/dapl_set_consumer_context.c \ + dapl/common/dapl_ring_buffer_util.c \ + dapl/common/dapl_name_service.c \ + dapl/common/dapl_timer_util.c \ + dapl/common/dapl_ep_create_with_srq.c \ + dapl/common/dapl_ep_recv_query.c \ + dapl/common/dapl_ep_set_watermark.c \ + dapl/common/dapl_srq_create.c \ + dapl/common/dapl_srq_free.c \ + dapl/common/dapl_srq_query.c \ + dapl/common/dapl_srq_resize.c \ + dapl/common/dapl_srq_post_recv.c \ + dapl/common/dapl_srq_set_lw.c \ + dapl/common/dapl_srq_util.c \ + dapl/common/dapl_debug.c \ + dapl/common/dapl_ia_ha.c \ + dapl/common/dapl_csp.c \ + dapl/common/dapl_ep_post_send_invalidate.c \ + dapl/common/dapl_ep_post_rdma_read_to_rmr.c \ + dapl/openib_common/mem.c \ + dapl/openib_common/cq.c \ + dapl/openib_common/qp.c \ + dapl/openib_common/util.c \ + dapl/openib_ucm/cm.c \ + dapl/openib_ucm/device.c $(XPROGRAMS) + +dapl_udapl_libdaploucm_la_LDFLAGS = -version-info 2:0:0 $(daploscm_version_script) \ + -Wl,-init,dapl_init -Wl,-fini,dapl_fini \ + -lpthread -libverbs + +libdatincludedir = $(includedir)/dat2 + +libdatinclude_HEADERS = dat/include/dat2/dat.h \ + dat/include/dat2/dat_error.h \ + dat/include/dat2/dat_platform_specific.h \ + dat/include/dat2/dat_redirection.h \ + dat/include/dat2/dat_registry.h \ + dat/include/dat2/dat_vendor_specific.h \ + dat/include/dat2/udat_config.h \ + dat/include/dat2/udat.h \ + dat/include/dat2/udat_redirection.h \ + dat/include/dat2/udat_vendor_specific.h \ + dat/include/dat2/dat_ib_extensions.h + +man_MANS = man/dtest.1 man/dapltest.1 man/dat.conf.5 + +EXTRA_DIST = dat/common/dat_dictionary.h \ + dat/common/dat_dr.h \ + dat/common/dat_init.h \ + dat/common/dat_sr.h \ + dat/udat/udat_sr_parser.h \ + dat/udat/linux/dat_osd.h \ + dat/include/dat2/dat.h \ + dat/include/dat2/dat_error.h \ + dat/include/dat2/dat_platform_specific.h \ + dat/include/dat2/dat_redirection.h \ + dat/include/dat2/dat_registry.h \ + dat/include/dat2/dat_vendor_specific.h \ + dat/include/dat2/udat_config.h \ + dat/include/dat2/udat.h \ + dat/include/dat2/udat_redirection.h \ + dat/include/dat2/udat_vendor_specific.h \ + dapl/common/dapl_adapter_util.h \ + dapl/common/dapl_cno_util.h \ + dapl/common/dapl_cookie.h \ + dapl/common/dapl_cr_util.h \ + dapl/common/dapl_ep_util.h \ + dapl/common/dapl_evd_util.h \ + dapl/common/dapl_hash.h \ + dapl/common/dapl_hca_util.h \ + dapl/common/dapl_ia_util.h \ + dapl/common/dapl_init.h \ + dapl/common/dapl_lmr_util.h \ + dapl/common/dapl_mr_util.h \ + dapl/common/dapl_name_service.h \ + dapl/common/dapl_provider.h \ + dapl/common/dapl_pz_util.h \ + dapl/common/dapl_ring_buffer_util.h \ + dapl/common/dapl_rmr_util.h \ + dapl/common/dapl_sp_util.h \ + dapl/common/dapl_srq_util.h \ + dapl/common/dapl_timer_util.h \ + dapl/udapl/linux/dapl_osd.h \ + dapl/include/dapl.h \ + dapl/include/dapl_debug.h \ + dapl/include/dapl_ipoib_names.h \ + dapl/include/dapl_vendor.h \ + dapl/openib_common/dapl_ib_dto.h \ + dapl/openib_common/dapl_ib_common.h \ + dapl/openib_cma/dapl_ib_util.h \ + dapl/openib_cma/linux/openib_osd.h \ + dapl/openib_scm/dapl_ib_util.h \ + dapl/openib_scm/linux/openib_osd.h \ + dapl/openib_ucm/dapl_ib_util.h \ + dapl/openib_ucm/linux/openib_osd.h \ + dat/udat/libdat2.map \ + dapl/udapl/libdaplofa.map \ + dapl/udapl/libdaploscm.map \ + dapl/udapl/libdaploucm.map \ + LICENSE.txt \ + LICENSE2.txt \ + LICENSE3.txt \ + dapl.spec.in \ + $(man_MANS) \ + test/dapltest/include/dapl_bpool.h \ + test/dapltest/include/dapl_client_info.h \ + test/dapltest/include/dapl_common.h \ + test/dapltest/include/dapl_execute.h \ + test/dapltest/include/dapl_fft_cmd.h \ + test/dapltest/include/dapl_fft_util.h \ + test/dapltest/include/dapl_getopt.h \ + test/dapltest/include/dapl_global.h \ + test/dapltest/include/dapl_limit_cmd.h \ + test/dapltest/include/dapl_mdep.h \ + test/dapltest/include/dapl_memlist.h \ + test/dapltest/include/dapl_params.h \ + test/dapltest/include/dapl_performance_cmd.h \ + test/dapltest/include/dapl_performance_stats.h \ + test/dapltest/include/dapl_performance_test.h \ + test/dapltest/include/dapl_proto.h \ + test/dapltest/include/dapl_quit_cmd.h \ + test/dapltest/include/dapl_server_cmd.h \ + test/dapltest/include/dapl_server_info.h \ + test/dapltest/include/dapl_tdep.h \ + test/dapltest/include/dapl_tdep_print.h \ + test/dapltest/include/dapl_test_data.h \ + test/dapltest/include/dapl_transaction_cmd.h \ + test/dapltest/include/dapl_transaction_stats.h \ + test/dapltest/include/dapl_transaction_test.h \ + test/dapltest/include/dapl_version.h \ + test/dapltest/mdep/linux/dapl_mdep_user.h + +dist-hook: dapl.spec + cp dapl.spec $(distdir) + +install-exec-hook: + if ! test -d $(DESTDIR)$(sysconfdir); then \ + mkdir -p $(DESTDIR)$(sysconfdir); \ + fi; \ + if test -e $(DESTDIR)$(sysconfdir)/dat.conf; then \ + sed -e '/ofa-v2-.* u2/d' < $(DESTDIR)$(sysconfdir)/dat.conf > /tmp/$$$$ofadapl; \ + cp /tmp/$$$$ofadapl $(DESTDIR)$(sysconfdir)/dat.conf; \ + fi; \ + echo ofa-v2-mlx4_0-1 u2.0 nonthreadsafe default libdaploscm.so.2 dapl.2.0 '"mlx4_0 1" ""' >> $(DESTDIR)$(sysconfdir)/dat.conf; \ + echo ofa-v2-mlx4_0-2 u2.0 nonthreadsafe default libdaploscm.so.2 dapl.2.0 '"mlx4_0 2" ""' >> $(DESTDIR)$(sysconfdir)/dat.conf; \ + echo ofa-v2-ib0 u2.0 nonthreadsafe default libdaplofa.so.2 dapl.2.0 '"ib0 0" ""' >> $(DESTDIR)$(sysconfdir)/dat.conf; \ + echo ofa-v2-ib1 u2.0 nonthreadsafe default libdaplofa.so.2 dapl.2.0 '"ib1 0" ""' >> $(DESTDIR)$(sysconfdir)/dat.conf; \ + echo ofa-v2-mthca0-1 u2.0 nonthreadsafe default libdaploscm.so.2 dapl.2.0 '"mthca0 1" ""' >> $(DESTDIR)$(sysconfdir)/dat.conf; \ + echo ofa-v2-mthca0-2 u2.0 nonthreadsafe default libdaploscm.so.2 dapl.2.0 '"mthca0 2" ""' >> $(DESTDIR)$(sysconfdir)/dat.conf; \ + echo ofa-v2-ipath0-1 u2.0 nonthreadsafe default libdaploscm.so.2 dapl.2.0 '"ipath0 1" ""' >> $(DESTDIR)$(sysconfdir)/dat.conf; \ + echo ofa-v2-ipath0-2 u2.0 nonthreadsafe default libdaploscm.so.2 dapl.2.0 '"ipath0 2" ""' >> $(DESTDIR)$(sysconfdir)/dat.conf; \ + echo ofa-v2-ehca0-2 u2.0 nonthreadsafe default libdaploscm.so.2 dapl.2.0 '"ehca0 1" ""' >> $(DESTDIR)$(sysconfdir)/dat.conf; \ + echo ofa-v2-iwarp u2.0 nonthreadsafe default libdaplofa.so.2 dapl.2.0 '"eth2 0" ""' >> $(DESTDIR)$(sysconfdir)/dat.conf; \ + echo ofa-v2-mlx4_0-1u u2.0 nonthreadsafe default libdaploucm.so.2 dapl.2.0 '"mlx4_0 1" ""' >> $(DESTDIR)$(sysconfdir)/dat.conf; \ + echo ofa-v2-mlx4_0-2u u2.0 nonthreadsafe default libdaploucm.so.2 dapl.2.0 '"mlx4_0 2" ""' >> $(DESTDIR)$(sysconfdir)/dat.conf; \ + echo ofa-v2-mthca0-1u u2.0 nonthreadsafe default libdaploucm.so.2 dapl.2.0 '"mthca0 1" ""' >> $(DESTDIR)$(sysconfdir)/dat.conf; \ + echo ofa-v2-mthca0-2u u2.0 nonthreadsafe default libdaploucm.so.2 dapl.2.0 '"mthca0 2" ""' >> $(DESTDIR)$(sysconfdir)/dat.conf; \ + echo ofa-v2-cma-roe-eth2 u2.0 nonthreadsafe default libdaplofa.so.2 dapl.2.0 '"eth2 0" ""' >> $(DESTDIR)$(sysconfdir)/dat.conf; \ + echo ofa-v2-cma-roe-eth3 u2.0 nonthreadsafe default libdaplofa.so.2 dapl.2.0 '"eth3 0" ""' >> $(DESTDIR)$(sysconfdir)/dat.conf; \ + echo ofa-v2-scm-roe-mlx4_0-1 u2.0 nonthreadsafe default libdaploscm.so.2 dapl.2.0 '"mlx4_0 1" ""' >> $(DESTDIR)$(sysconfdir)/dat.conf; \ + echo ofa-v2-scm-roe-mlx4_0-2 u2.0 nonthreadsafe default libdaploscm.so.2 dapl.2.0 '"mlx4_0 2" ""' >> $(DESTDIR)$(sysconfdir)/dat.conf; + +uninstall-hook: + if test -e $(DESTDIR)$(sysconfdir)/dat.conf; then \ + sed -e '/ofa-v2-.* u2/d' < $(DESTDIR)$(sysconfdir)/dat.conf > /tmp/$$$$ofadapl; \ + cp /tmp/$$$$ofadapl $(DESTDIR)$(sysconfdir)/dat.conf; \ + fi; + +SUBDIRS = . test/dtest test/dapltest diff --git a/branches/WOF2-3/ulp/dapl2/README b/branches/WOF2-3/ulp/dapl2/README new file mode 100644 index 00000000..1fc55a22 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/README @@ -0,0 +1,434 @@ + +========== +1.0 BUILD: +========== + +The default build includes a non-debug version of libdat and libdapl-cma uDAPL provider. It will also builds test suites dtest and dapltest and provides manpages for each. This version requires libibverbs and librdmacm installation, IPoIB installation, and IPoIB configuration with an IP address. + +Building : +---------- +./autogen.sh +./configure +make + +Building debug version: +---------------------- +./autogen.sh +./configure --enable-debug +make + +Build example with OFED 1.2+ prefix (x86_64) +--------------------------------------------- +./autogen.sh +./configure --prefix /usr --sysconf=/etc --libdir /usr/lib64 LDFLAGS=-L/usr/lib64 CPPFLAGS="-I/usr/include" +make + +Installing: +---------- +make install + +Note: The development package installs DAT 2.0 include files under /usr/include/dat2 to co-exist with DAT 1.2 /usr/include/dat + +NOTE: to link these libraries you must either use libtool and +specify the full pathname of the library, or use the `-LLIBDIR' +flag during linking and do at least one of the following: + - add LIBDIR to the `LD_LIBRARY_PATH' environment variable + during execution + - add LIBDIR to the `LD_RUN_PATH' environment variable + during linking + - use the `-Wl,--rpath -Wl,LIBDIR' linker flag + - have your system administrator add LIBDIR to `/etc/ld.so.conf' + +See any operating system documentation about shared libraries for +more information, such as the ld(1) and ld.so(8) manual pages. + +=================== +2.0 CONFIGURATION: +=================== + +sample /etc/dat.conf + +# +# DAT 1.2 and 2.0 configuration file +# +# Each entry should have the following fields: +# +# \ +# +# +# For the uDAPL cma provder, specify as one of the following: +# network address, network hostname, or netdev name and 0 for port +# +# Simple (OpenIB-cma) default with netdev name provided first on list +# to enable use of same dat.conf version on all nodes +# +# Add examples for multiple interfaces and IPoIB HA fail over, and bonding +# +OpenIB-cma u1.2 nonthreadsafe default libdaplcma.so.1 dapl.1.2 "ib0 0" "" +OpenIB-cma-1 u1.2 nonthreadsafe default libdaplcma.so.1 dapl.1.2 "ib1 0" "" +OpenIB-cma-2 u1.2 nonthreadsafe default libdaplcma.so.1 dapl.1.2 "ib2 0" "" +OpenIB-cma-3 u1.2 nonthreadsafe default libdaplcma.so.1 dapl.1.2 "ib3 0" "" +OpenIB-bond u1.2 nonthreadsafe default libdaplcma.so.1 dapl.1.2 "bond0 0" "" +OpenIB-2-cma u2.0 nonthreadsafe default libdaplcma.so.2 dapl.2.0 "ib0 0" "" +OpenIB-2-cma-1 u2.0 nonthreadsafe default libdaplcma.so.2 dapl.2.0 "ib1 0" "" +OpenIB-2-cma-2 u2.0 nonthreadsafe default libdaplcma.so.2 dapl.2.0 "ib2 0" "" +OpenIB-2-cma-3 u2.0 nonthreadsafe default libdaplcma.so.2 dapl.2.0 "ib3 0" "" +OpenIB-2-bond u2.0 nonthreadsafe default libdaplcma.so.2 dapl.2.0 "bond0 0" "" + + +============================= +3.0 Bugs/Known issues +============================= + + + +============================= +4.0 SAMPLE uDAPL APPLICATION: +============================= + +There are 2 sample programs, with manpages, provided with this package. + +(dapl/test/dtest/) + +NAME + dtest - simple uDAPL send/receive and RDMA test + +SYNOPSIS + dtest [-P provider] [-b buf size] [-B burst count][-v] [-c] [-p] [-d] [-s] + + dtest [-P provider] [-b buf size] [-B burst count][-v] [-c] [-p] [-d] [-h HOSTNAME] + +DESCRIPTION + dtest is a simple test used to exercise and verify the uDAPL interfaces. At least two instantia- + tions of the test must be run. One acts as the server and the other the client. The server side of + the test, once invoked listens for connection requests, until timing out or killed. Upon receipt + of a cd connection request, the connection is established, the server and client sides exchange + information necessary to perform RDMA writes and reads. + +OPTIONS + -P=PROVIDER + use PROVIDER to specify uDAPL interface using /etc/dat.conf (default OpenIB-cma) + + -b=BUFFER_SIZE + use buffer size BUFFER_SIZE for RDMA(default 64) + + -B=BURST_COUNT + use busrt count BURST_COUNT for interations (default 10) + + -v, verbose output(default off) + + -c, use consumer notification events (default off) + + -p, use polling (default wait for event) + + -d, delay in seconds before close (default off) + + -s, run as server (default - run as server) + + -h=HOSTNAME + use HOSTNAME to specify server hostname or IP address (default - none) + +EXAMPLES + dtest -P OpenIB-cma -v -s + Starts a server process with debug verbosity using provider OpenIB-cma. + + dtest -P OpenIB-cma -h server1-ib0 + + Starts a client process, using OpenIB-cma provider to connect to hostname server1-ib0. + +SEE ALSO + dapltest(1) + +AUTHORS + Arlin Davis + + +BUGS + +/dapl/test/dapltest/ + +NAME + dapltest - test for the Direct Access Programming Library (DAPL) + +DESCRIPTION + Dapltest is a set of tests developed to exercise, characterize, and verify the DAPL interfaces + during development and porting. At least two instantiations of the test must be run. One acts as + the server, fielding requests and spawning server-side test threads as needed. Other client invo- + cations connect to the server and issue test requests. The server side of the test, once invoked, + listens continuously for client connection requests, until quit or killed. Upon receipt of a con- + nection request, the connection is established, the server and client sides swap version numbers + to verify that they are able to communicate, and the client sends the test request to the server. + If the version numbers match, and the test request is well-formed, the server spawns the threads + needed to run the test before awaiting further connections. + +USAGE + dapltest [ -f script_file_name ] [ -T S|Q|T|P|L ] [ -D device_name ] [ -d ] [ -R HT|LL|EC|PM|BE ] + + With no arguments, dapltest runs as a server using default values, and loops accepting requests + from clients. + + The -f option allows all arguments to be placed in a file, to ease test automation. + + The following arguments are common to all tests: + + [ -T S|Q|T|P|L ] + Test function to be performed: + + S - server loop + + Q - quit, client requests that server wait for any outstanding tests to complete, then + clean up and exit + + T - transaction test, transfers data between client and server + + P - performance test, times DTO operations + + L - limit test, exhausts various resources, runs in client w/o server interaction + Default: S + + [ -D device_name ] + Specifies the interface adapter name as documented in the /etc/dat.conf static configura- + tion file. This name corresponds to the provider library to open. Default: none + + [ -d ] Enables extra debug verbosity, primarily tracing of the various DAPL operations as they + progress. Repeating this parameter increases debug spew. Errors encountered result in the + test spewing some explanatory text and stopping; this flag provides more detail about what + lead up to the error. Default: zero + + [ -R BE ] + Indicate the quality of service (QoS) desired. Choices are: + + HT - high throughput + + LL - low latency + + EC - economy (neither HT nor LL) + + PM - premium + + BE - best effort Default: BE + + Usage - Quit test client + + dapltest [Common_Args] [ -s server_name ] + + Quit testing (-T Q) connects to the server to ask it to clean up and + exit (after it waits for any outstanding test runs to complete). + In addition to being more polite than simply killing the server, + this test exercises the DAPL object teardown code paths. + There is only one argument other than those supported by all tests: + + -s server_name Specifies the name of the server interface. + No default. + + Usage - Transaction test client + + dapltest [Common_Args] [ -s server_name ] + [ -t threads ] [ -w endpoints ] [ -i iterations ] [ -Q ] + [ -V ] [ -P ] OPclient OPserver [ op3, + + Transaction testing (-T T) transfers a variable amount of data between +: + client and server. The data transfer can be described as a sequence of + individual operations; that entire sequence is transferred ’iterations’ + times by each thread over all of its endpoint(s). + + The following parameters determine the behavior of the transaction test: + + -s server_name Specifies the name or IP address of the server interface. + No default. + + [ -t threads ] Specify the number of threads to be used. + Default: 1 + + [ -w endpoints ] Specify the number of connected endpoints per thread. + Default: 1 + + [ -i iterations ] Specify the number of times the entire sequence + of data transfers will be made over each endpoint. + Default: 1000 + + [ -Q ] Funnel completion events into a CNO. + Default: use EVDs + + [ -V ] Validate the data being transferred. + Default: ignore the data + + [ -P ] Turn on DTO completion polling + Default: off + + OP1 OP2 [ OP3, ... ] + A single transaction (OPx) consists of: + + server|client Indicates who initiates the + data transfer. + + SR|RR|RW Indicates the type of transfer: + SR send/recv + RR RDMA read + RW RDMA write + Defaults: none + + [ seg_size [ num_segs ] ] +: + + Indicates the amount and format + of the data to be transferred. + Default: 4096 1 + (i.e., 1 4KB buffer) + + [ -f ] For SR transfers only, indicates + that a client’s send transfer + completion should be reaped when + the next recv completion is reaped. + Sends and receives must be paired + (one client, one server, and in that + order) for this option to be used. + + Restrictions: + + Due to the flow control algorithm used by the transaction test, there + must be at least one SR OP for both the client and the server. + + Requesting data validation (-V) causes the test to automatically append + three OPs to those specified. These additional operations provide + synchronization points during each iteration, at which all user-specified + transaction buffers are checked. These three appended operations satisfy + the "one SR in each direction" requirement. + + The transaction OP list is printed out if -d is supplied. + + Usage - Performance test client + + dapltest [Common_Args] -s server_name [ -m p|b ] + [ -i iterations ] [ -p pipeline ] OP + + Performance testing (-T P) times the transfer of an operation. + The operation is posted ’iterations’ times. + + The following parameters determine the behavior of the transaction test: + + -s server_name Specifies the name or IP address of the server interface. + No default. + + -m b|p Used to choose either blocking (b) or polling (p) + Default: blocking (b) + [ -i iterations ] Specify the number of times the entire sequence + of data transfers will be made over each endpoint. + Default: 1000 + + [ -p pipeline ] Specify the pipline length, valid arguments are in + the range [0,MAX_SEND_DTOS]. If a value greater than + MAX_SEND_DTOS is requested the value will be + adjusted down to MAX_SEND_DTOS. + Default: MAX_SEND_DTOS + + OP Specifies the operation as follow: + + RR|RW Indicates the type of transfer: + RR RDMA read + RW RDMA write + Defaults: none + + [ seg_size [ num_segs ] ] + Indicates the amount and format + of the data to be transferred. + Default: 4096 1 + (i.e., 1 4KB buffer) + + Usage - Limit test client + + Limit testing (-T L) neither requires nor connects to any server + instance. The client runs one or more tests which attempt to + exhaust various resources to determine DAPL limits and exercise + DAPL error paths. If no arguments are given, all tests are run. + + Limit testing creates the sequence of DAT objects needed to + move data back and forth, attempting to find the limits supported + for the DAPL object requested. For example, if the LMR creation + limit is being examined, the test will create a set of + {IA, PZ, CNO, EVD, EP} before trying to run dat_lmr_create() to + failure using that set of DAPL objects. The ’width’ parameter + can be used to control how many of these parallel DAPL object + sets are created before beating upon the requested constructor. + Use of -m limits the number of dat_*_create() calls that will + be attempted, which can be helpful if the DAPL in use supports + essentailly unlimited numbers of some objects. + The limit test arguments are: + + [ -m maximum ] Specify the maximum number of dapl_*_create() + attempts. + Default: run to object creation failure + + [ -w width ] Specify the number of DAPL object sets to + create while initializing. + Default: 1 + + [ limit_ia ] Attempt to exhaust dat_ia_open() + + [ limit_pz ] Attempt to exhaust dat_pz_create() + + [ limit_cno ] Attempt to exhaust dat_cno_create() + + [ limit_evd ] Attempt to exhaust dat_evd_create() + + [ limit_ep ] Attempt to exhaust dat_ep_create() + + [ limit_rsp ] Attempt to exhaust dat_rsp_create() + + [ limit_psp ] Attempt to exhaust dat_psp_create() + + [ limit_lmr ] Attempt to exhaust dat_lmr_create(4KB) + + [ limit_rpost ] Attempt to exhaust dat_ep_post_recv(4KB) + + [ limit_size_lmr ] Probe maximum size dat_lmr_create() + + Default: run all tests + +EXAMPLES + dapltest -T S -d -D OpenIB-cma + + Starts a server process with debug verbosity. + + dapltest -T T -d -s host1-ib0 -D OpenIB-cma -i 100 client SR 4096 2 server SR 4096 2 + + Runs a transaction test, with both sides + sending one buffer with two 4KB segments, + one hundred times. + + dapltest -T P -d -s host1-ib0 -D OpenIB-cma -i 100 SR 4096 2 + + Runs a performance test, with the client + sending one buffer with two 4KB segments, + one hundred times. + + dapltest -T Q -s host1-ib0 -D OpenIB-cma + + Asks the server to clean up and exit. + + dapltest -T L -D OpenIB-cma -d -w 16 -m 1000 + + Runs all of the limit tests, setting up + 16 complete sets of DAPL objects, and + creating at most a thousand instances + when trying to exhaust resources. + + dapltest -T T -V -d -t 2 -w 4 -i 55555 -s linux3 -D OpenIB-cma client RW 4096 1 server RW 2048 4 + client SR 1024 4 server SR 4096 2 client SR 1024 3 -f server SR 2048 1 -f + + Runs a more complicated transaction test, + with two thread using four EPs each, + sending a more complicated buffer pattern + for a larger number of iterations, + validating the data received. + + BUGS (and To Do List) + + Use of CNOs (-Q) is not yet supported. + + Further limit tests could be added. + + + + diff --git a/branches/WOF2-3/ulp/dapl2/README.windows b/branches/WOF2-3/ulp/dapl2/README.windows new file mode 100644 index 00000000..fafdadce --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/README.windows @@ -0,0 +1,190 @@ +[10-17-07] Last update. + +========== +BUILD: +========== + +The default build includes both debug(checked) & non-debug (free) version of +dat2d.dll and dapl2d.dll uDAPL provider, free versions are dat2.dll & dapl2.dll. +Included in the build are test suites dtest (simple DAT example), dtestx +(DAT IB extensions test) and the main DAT/uDAPL tester dapl2test (see dt-svr & +dt-cli, see manual.htm for details). +Additionally, DAT v1.1 and/or DAT v2.0 build environments can be installed; see +manual.htm for details. + +Building a free/non-debug version: +---------------------------------- +Requires Windows Server 2003 DDK & Platform SDK. +From a DDK command window (free build) for a specific architecture +(x86, x64, ia64); + +cd gen1\trunk\ulp\dapl2 +build -wg +Binaries are located in gen1\bin\{kernel|user}\os-arch-folder\... + +Building debug version: +----------------------- +Same as above except the DDK command window is for a Checked build + + +Installing: +----------- + +dat2.dll & dapl.dll --> %SystemRoot% + +=================== +CONFIGURATION: +=================== + +sample C:\dat\dat.conf + +# +# DAT 1.2 configuration file, +# +# Each entry should have the following fields: +# +# \ +# +# +# For openib-cma provider you can specify as either: +# network address, network hostname, or netdev name and 0 for port +# +# +ibnic0v2 u2.0 nonthreadsafe default C:\Windows\dapl2.dll ri.2.0 "IbalHca0 1" "" + + +============================= +Bugs/Known issues +============================= + + + +============================= +4.0 SAMPLE uDAPL APPLICATION: +============================= + +There are 2 sample programs provided with this package. + +(dapl2/test/dtest/) +(dapl2/test/dtestx/) + +NAME + dtest - simple uDAPL send/receive and RDMA test + +SYNOPSIS + dtest [-P provider] [-b buf size] [-B burst count][-v] [-c] [-p] [-d] [-s] + + dtest [-P provider] [-b buf size] [-B burst count][-v] [-c] [-p] [-d] [-h HOSTNAME] + +DESCRIPTION + dtest is a simple test used to exercise and verify the uDAPL interfaces. + At least two instantiations of the test must be run. One acts as the + server and the other the client. The server side of the test listens for + connection requests, until timing out or killed. Upon receipt of a cd + connection request, the connection is established, the server and client + sides exchange information necessary to perform RDMA writes and reads. + +OPTIONS + -P=PROVIDER + use PROVIDER to specify uDAPL interface using C:\DAT\dat.conf + (default ibnic0v2) + + -b=BUFFER_SIZE + use buffer size BUFFER_SIZE for RDMA(default 64) + + -B=BURST_COUNT + use busrt count BURST_COUNT for interations (default 10) + + -v, verbose output(default off) + + -c, use consumer notification events (default off) + + -p, use polling (default wait for event) + + -d, delay in seconds before close (default off) + + -s, run as server (default - run as server) + + -h=HOSTNAME + use HOSTNAME to specify server hostname or IP address (default - none) + +EXAMPLES + dtest -v -s + Starts a server process with debug verbosity using provider ibnic0v2 + + dtest -h server1-ib0 + + Starts a client process, using ibnic0v2 provider to connect to + hostname server1-ib0. + +SEE ALSO + dapltest(1) + +AUTHORS + Arlin Davis + + +BUGS + +/dapl/test/dapltest/ + +NAME + dapltest - test for the Direct Access Programming Library (DAPL) + +DESCRIPTION + Dapltest is a set of tests developed to exercise, characterize, and + verify the DAPL interfaces during development and porting. At least two + instantiations of the test must be run. One acts as the server, fielding + requests and spawning server-side test threads as needed. Other client(s) + connect to the server and issue test requests. The server side of the + test, once invoked, listens continuously for client connection requests + until stopped or killed. Upon receipt of a connection request, the + connection is established, the server and client sides swap version + numbers to verify that they are able to communicate, and the client + sends the test request to the server. If the version numbers match, and + the test request is well-formed, the server spawns the threads + needed to run the test before awaiting further connections. + +USAGE + See manual.htm and or dt-svr.bat & dt-cli.bat. + +EXAMPLES + dapltest -T S -d -D ibnic0v2 + + Starts a server process with debug verbosity. + + dapltest -T T -d -s host1-ib0 -D ibnic0v2 -i 100 client SR 4096 2 \ + server SR 4096 2 + + Runs a transaction test, with both sides sending one buffer with + two 4KB segments, one hundred times. + + dapltest -T P -d -s host1-ib0 -D ibnic0v2 -i 100 SR 4096 2 + + Runs a performance test, with the client sending one buffer with + two 4KB segments, one hundred times. + + dapltest -T Q -s host1-ib0 -D ibnic0v2 + + Asks the server to clean up and exit. + + dapltest -T L -D ibnic0v2 -d -w 16 -m 1000 + + Runs all of the limit tests, setting up 16 complete sets of DAPL + objects, and creating at most a thousand instances when trying to + exhaust resources. + + dapltest -T T -V -d -t 2 -w 4 -i 55555 -s linux3 -D ibnic0v2 \ + client RW 4096 1 server RW 2048 4 client SR 1024 4 server SR 4096 \ + 2 client SR 1024 3 -f server SR 2048 1 -f + + Runs a more complicated transaction test, with two thread using four + EPs each, sending a more complicated buffer pattern for a larger + number of iterations, validating the data received. + + BUGS (and To Do List) + + Use of CNOs (-Q) is not yet supported. + + Further limit tests could be added. + diff --git a/branches/WOF2-3/ulp/dapl2/autogen.sh b/branches/WOF2-3/ulp/dapl2/autogen.sh new file mode 100644 index 00000000..343c5a61 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/autogen.sh @@ -0,0 +1,10 @@ +#! /bin/sh + +set -x +test -d ./config || mkdir ./config +aclocal -I config +libtoolize --force --copy +autoheader +automake --foreign --add-missing --copy +autoconf + diff --git a/branches/WOF2-3/ulp/dapl2/configure.in b/branches/WOF2-3/ulp/dapl2/configure.in new file mode 100644 index 00000000..3ac53f74 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/configure.in @@ -0,0 +1,104 @@ +dnl Process this file with autoconf to produce a configure script. + +AC_PREREQ(2.57) +AC_INIT(dapl, 2.0.30, linux-rdma@vger.kernel.org) +AC_CONFIG_SRCDIR([dat/udat/udat.c]) +AC_CONFIG_AUX_DIR(config) +AM_CONFIG_HEADER(config.h) +AM_INIT_AUTOMAKE(dapl, 2.0.30) + +AM_PROG_LIBTOOL + +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 Checks for programs +AC_PROG_CC + +dnl Checks for libraries +if test "$disable_libcheck" != "yes" +then +AC_CHECK_LIB(ibverbs, ibv_get_device_list, [], + AC_MSG_ERROR([ibv_get_device_list() not found. libdapl requires libibverbs.])) + +AC_CHECK_HEADER(infiniband/verbs.h, [], + AC_MSG_ERROR([ not found. Is libibverbs installed?])) + +AC_CHECK_MEMBER(struct ibv_port_attr.link_layer, + AM_CONDITIONAL(DEFINE_ATTR_LINK_LAYER, test "yes" = "yes"), + AM_CONDITIONAL(DEFINE_ATTR_LINK_LAYER, test "yes" = "no"), + [#include ]) +else + AM_CONDITIONAL(DEFINE_ATTR_LINK_LAYER, test "yes" = "no") +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") + +dnl Support debug mode build - if enable-debug provided the DEBUG variable is set +AC_ARG_ENABLE(debug, +[ --enable-debug Turn on debug mode, default=off], +[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 Support ib_extension build - if enable-ext-type == ib +AC_ARG_ENABLE(ext-type, +[ --enable-ext-type Enable extensions support for library: ib, none, default=ib], + [ if test "x$enableval" = "xib" ; then + ext_type=ib + elif test "x$enableval" = "xnone" ; then + ext_type=none + else + echo + echo "Error!" + echo "Unknown extension type' type" + exit -1 + fi + ],[ext_type=ib]) +AM_CONDITIONAL(EXT_TYPE_IB, test "$ext_type" = "ib") + +dnl Check for Redhat EL release 4 +AC_CACHE_CHECK(Check for RHEL4 system, ac_cv_rhel4, + if test -f /etc/redhat-release && + test -n "`grep -e "release 4" /etc/redhat-release`"; then + ac_cv_rhel4=yes + else + ac_cv_rhel4=no + fi) +AM_CONDITIONAL(OS_RHEL4, test "$ac_cv_rhel4" = "yes") + +dnl Check for Redhat EL release 5 +AC_CACHE_CHECK(Check for RHEL5 system, ac_cv_rhel5, + if test -f /etc/redhat-release && + test -n "`grep -e "release 5" /etc/redhat-release`"; then + ac_cv_rhel5=yes + else + ac_cv_rhel5=no + fi) +AM_CONDITIONAL(OS_RHEL5, test "$ac_cv_rhel5" = "yes") + +dnl Check for SuSE release 11 +AC_CACHE_CHECK(Check for SUSE_11 system, ac_cv_suse11, + if test -f /etc/SuSE-release && + test -n "`grep -e "VERSION = 11" /etc/SuSE-release`"; then + ac_cv_suse11=yes + else + ac_cv_suse11=no + fi) +AM_CONDITIONAL(OS_SUSE11, test "$ac_cv_suse11" = "yes") + +AC_CONFIG_FILES([Makefile test/dtest/Makefile test/dapltest/Makefile dapl.spec]) + +AC_OUTPUT diff --git a/branches/WOF2-3/ulp/dapl2/dapl.spec.in b/branches/WOF2-3/ulp/dapl2/dapl.spec.in new file mode 100644 index 00000000..8872660e --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl.spec.in @@ -0,0 +1,238 @@ +# Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. +# Copyright (c) 2007, Intel Corporation. All rights reserved. +# +# This Software is licensed under one of the following licenses: +# +# 1) under the terms of the "Common Public License 1.0" a copy of which is +# in the file LICENSE.txt in the root directory. The license is also +# available from the Open Source Initiative, see +# http://www.opensource.org/licenses/cpl.php. +# +# 2) under the terms of the "The BSD License" a copy of which is in the file +# LICENSE2.txt in the root directory. The license is also available from +# the Open Source Initiative, see +# http://www.opensource.org/licenses/bsd-license.php. +# +# 3) under the terms of the "GNU General Public License (GPL) Version 2" a +# copy of which is in the file LICENSE3.txt in the root directory. The +# license is also available from the Open Source Initiative, see +# http://www.opensource.org/licenses/gpl-license.php. +# +# Licensee has the right to choose one of the above licenses. +# +# Redistributions of source code must retain the above copyright +# notice and one of the license notices. +# +# Redistributions in binary form must reproduce both the above copyright +# notice, one of the license notices in the documentation +# and/or other materials provided with the distribution. +# +# +# uDAT and uDAPL 2.0 Registry RPM SPEC file +# +# $Id: $ +Name: dapl +Version: @VERSION@ +Release: 1%{?dist} +Summary: A Library for userspace access to RDMA devices using OS Agnostic DAT APIs. + +Group: System Environment/Libraries +License: Dual GPL/BSD/CPL +Url: http://openfabrics.org/ +Source: http://www.openfabrics.org/downloads/%{name}/%{name}-%{version}.tar.gz +BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX) +Requires(post): /sbin/ldconfig +Requires(postun): /sbin/ldconfig +Requires(post): sed +Requires(post): coreutils + +%description +Along with the OpenFabrics kernel drivers, libdat and libdapl provides a userspace +RDMA API that supports DAT 2.0 specification and IB transport extensions for +atomic operations and rdma write with immediate data. + +%package devel +Summary: Development files for the libdat and libdapl libraries +Group: System Environment/Libraries + +%description devel +Header files for libdat and libdapl library. + +%package devel-static +Summary: Static development files for libdat and libdapl library +Group: System Environment/Libraries + +%description devel-static +Static libraries for libdat and libdapl library. + +%package utils +Summary: Test suites for uDAPL library +Group: System Environment/Libraries +Requires: %{name} = %{version}-%{release} + +%description utils +Useful test suites to validate uDAPL library API's. + +%prep +%setup -q + +%build +%configure --enable-ext-type=ib +make %{?_smp_mflags} + +%install +rm -rf %{buildroot} +make DESTDIR=%{buildroot} install +# remove unpackaged files from the buildroot +rm -f %{buildroot}%{_libdir}/*.la +rm -f %{buildroot}%{_sysconfdir}/*.conf + +%clean +rm -rf %{buildroot} + +%post +/sbin/ldconfig +if [ -e %{_sysconfdir}/dat.conf ]; then + sed -e '/ofa-v2-.* u2/d' < %{_sysconfdir}/dat.conf > /tmp/$$ofadapl + mv /tmp/$$ofadapl %{_sysconfdir}/dat.conf +fi +echo ofa-v2-mlx4_0-1 u2.0 nonthreadsafe default libdaploscm.so.2 dapl.2.0 '"mlx4_0 1" ""' >> %{_sysconfdir}/dat.conf +echo ofa-v2-mlx4_0-2 u2.0 nonthreadsafe default libdaploscm.so.2 dapl.2.0 '"mlx4_0 2" ""' >> %{_sysconfdir}/dat.conf +echo ofa-v2-ib0 u2.0 nonthreadsafe default libdaplofa.so.2 dapl.2.0 '"ib0 0" ""' >> %{_sysconfdir}/dat.conf +echo ofa-v2-ib1 u2.0 nonthreadsafe default libdaplofa.so.2 dapl.2.0 '"ib1 0" ""' >> %{_sysconfdir}/dat.conf +echo ofa-v2-mthca0-1 u2.0 nonthreadsafe default libdaploscm.so.2 dapl.2.0 '"mthca0 1" ""' >> %{_sysconfdir}/dat.conf +echo ofa-v2-mthca0-2 u2.0 nonthreadsafe default libdaploscm.so.2 dapl.2.0 '"mthca0 2" ""' >> %{_sysconfdir}/dat.conf +echo ofa-v2-ipath0-1 u2.0 nonthreadsafe default libdaploscm.so.2 dapl.2.0 '"ipath0 1" ""' >> %{_sysconfdir}/dat.conf +echo ofa-v2-ipath0-2 u2.0 nonthreadsafe default libdaploscm.so.2 dapl.2.0 '"ipath0 2" ""' >> %{_sysconfdir}/dat.conf +echo ofa-v2-ehca0-1 u2.0 nonthreadsafe default libdaploscm.so.2 dapl.2.0 '"ehca0 1" ""' >> %{_sysconfdir}/dat.conf +echo ofa-v2-iwarp u2.0 nonthreadsafe default libdaplofa.so.2 dapl.2.0 '"eth2 0" ""' >> %{_sysconfdir}/dat.conf +echo ofa-v2-mlx4_0-1u u2.0 nonthreadsafe default libdaploucm.so.2 dapl.2.0 '"mlx4_0 1" ""' >> %{_sysconfdir}/dat.conf +echo ofa-v2-mlx4_0-2u u2.0 nonthreadsafe default libdaploucm.so.2 dapl.2.0 '"mlx4_0 2" ""' >> %{_sysconfdir}/dat.conf +echo ofa-v2-mthca0-1u u2.0 nonthreadsafe default libdaploucm.so.2 dapl.2.0 '"mthca0 1" ""' >> %{_sysconfdir}/dat.conf +echo ofa-v2-mthca0-2u u2.0 nonthreadsafe default libdaploucm.so.2 dapl.2.0 '"mthca0 2" ""' >> %{_sysconfdir}/dat.conf +echo ofa-v2-cma-roe-eth2 u2.0 nonthreadsafe default libdaplofa.so.2 dapl.2.0 '"eth2 0" ""' >> %{_sysconfdir}/dat.conf +echo ofa-v2-cma-roe-eth3 u2.0 nonthreadsafe default libdaplofa.so.2 dapl.2.0 '"eth3 0" ""' >> %{_sysconfdir}/dat.conf +echo ofa-v2-scm-roe-mlx4_0-1 u2.0 nonthreadsafe default libdaploscm.so.2 dapl.2.0 '"mlx4_0 1" ""' >> %{_sysconfdir}/dat.conf +echo ofa-v2-scm-roe-mlx4_0-2 u2.0 nonthreadsafe default libdaploscm.so.2 dapl.2.0 '"mlx4_0 2" ""' >> %{_sysconfdir}/dat.conf + +%postun +/sbin/ldconfig +if [ -e %{_sysconfdir}/dat.conf ]; then + sed -e '/ofa-v2-.* u2/d' < %{_sysconfdir}/dat.conf > /tmp/$$ofadapl + mv /tmp/$$ofadapl %{_sysconfdir}/dat.conf +fi + +%files +%defattr(-,root,root,-) +%{_libdir}/libda*.so.* +%doc AUTHORS README COPYING ChangeLog LICENSE.txt LICENSE2.txt LICENSE3.txt + +%files devel +%defattr(-,root,root,-) +%{_libdir}/*.so +%dir %{_includedir}/dat2 +%{_includedir}/dat2/* + +%files devel-static +%defattr(-,root,root,-) +%{_libdir}/*.a + +%files utils +%defattr(-,root,root,-) +%{_bindir}/* +%{_mandir}/man1/*.1* +%{_mandir}/man5/*.5* + +%changelog +* Mon Aug 9 2010 Arlin Davis - 2.0.30 +- DAT/DAPL Version 2.0.30 Release 1, OFED 1.5.2 RC4 + +* Thu Jun 17 2010 Arlin Davis - 2.0.29 +- DAT/DAPL Version 2.0.29 Release 1, OFED 1.5.2 RC2 + +* Mon May 24 2010 Arlin Davis - 2.0.28 +- DAT/DAPL Version 2.0.28 Release 1, OFED 1.5.2 RC1 + +* Tue Feb 23 2010 Arlin Davis - 2.0.27 +- DAT/DAPL Version 2.0.27 Release 1, OFED 1.5.1 + +* Tue Jan 11 2010 Arlin Davis - 2.0.26 +- DAT/DAPL Version 2.0.26 Release 1, OFED 1.5, OFED 1.5-RDMAoE + +* Tue Nov 24 2009 Arlin Davis - 2.0.25 +- DAT/DAPL Version 2.0.25 Release 1, OFED 1.5 RC3 + +* Fri Oct 30 2009 Arlin Davis - 2.0.24 +- DAT/DAPL Version 2.0.24 Release 1, OFED 1.5 RC2 + +* Fri Oct 2 2009 Arlin Davis - 2.0.23 +- DAT/DAPL Version 2.0.23 Release 1, OFED 1.5 RC1 + +* Wed Aug 19 2009 Arlin Davis - 2.0.22 +- DAT/DAPL Version 2.0.22 Release 1, OFED 1.5 ALPHA new UCM provider + +* Wed Aug 5 2009 Arlin Davis - 2.0.21 +- DAT/DAPL Version 2.0.21 Release 1, WinOF 2.1, OFED 1.4.1+ + +* Fri Jun 19 2009 Arlin Davis - 2.0.20 +- DAT/DAPL Version 2.0.20 Release 1, OFED 1.4.1 + UD reject/scaling fixes + +* Thu Apr 30 2009 Arlin Davis - 2.0.19 +- DAT/DAPL Version 2.0.19 Release 1, OFED 1.4.1 GA Final + +* Fri Apr 17 2009 Arlin Davis - 2.0.18 +- DAT/DAPL Version 2.0.18 Release 1, OFED 1.4.1 GA + +* Tue Mar 31 2009 Arlin Davis - 2.0.17 +- DAT/DAPL Version 2.0.17 Release 1, OFED 1.4.1 GA + +* Mon Mar 16 2009 Arlin Davis - 2.0.16 +- DAT/DAPL Version 2.0.16 Release 1, OFED 1.4.1 + +* Fri Nov 07 2008 Arlin Davis - 2.0.15 +- DAT/DAPL Version 2.0.15 Release 1, OFED 1.4 GA + +* Fri Oct 03 2008 Arlin Davis - 2.0.14 +- DAT/DAPL Version 2.0.14 Release 1, OFED 1.4 rc3 + +* Mon Sep 01 2008 Arlin Davis - 2.0.13 +- DAT/DAPL Version 2.0.13 Release 1, OFED 1.4 rc1 + +* Thu Aug 21 2008 Arlin Davis - 2.0.12 +- DAT/DAPL Version 2.0.12 Release 1, OFED 1.4 beta + +* Sun Jul 20 2008 Arlin Davis - 2.0.11 +- DAT/DAPL Version 2.0.11 Release 1, IB UD extensions in SCM provider + +* Tue Jun 23 2008 Arlin Davis - 2.0.10 +- DAT/DAPL Version 2.0.10 Release 1, socket CM provider + +* Tue May 20 2008 Arlin Davis - 2.0.9 +- DAT/DAPL Version 2.0.9 Release 1, OFED 1.3.1 GA + +* Thu May 1 2008 Arlin Davis - 2.0.8 +- DAT/DAPL Version 2.0.8 Release 1, OFED 1.3.1 + +* Thu Feb 14 2008 Arlin Davis - 2.0.7 +- DAT/DAPL Version 2.0.7 Release 1, OFED 1.3 GA + +* Mon Feb 04 2008 Arlin Davis - 2.0.6 +- DAT/DAPL Version 2.0.6 Release 1, OFED 1.3 RC4 + +* Tue Jan 29 2008 Arlin Davis - 2.0.5 +- DAT/DAPL Version 2.0.5 Release 1, OFED 1.3 RC3 + +* Thu Jan 17 2008 Arlin Davis - 2.0.4 +- DAT/DAPL Version 2.0.4 Release 1, OFED 1.3 RC2 + +* Tue Nov 20 2007 Arlin Davis - 2.0.3 +- DAT/DAPL Version 2.0.3 Release 1 + +* Tue Oct 30 2007 Arlin Davis - 2.0.2 +- DAT/DAPL Version 2.0.2 Release 1 + +* Tue Sep 18 2007 Arlin Davis - 2.0.1-1 +- OFED 1.3-alpha, co-exist with DAT 1.2 library package. + +* Wed Mar 7 2007 Arlin Davis - 2.0.0.pre +- Initial release of DAT 2.0 APIs, includes IB extensions diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_adapter_util.h b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_adapter_util.h new file mode 100644 index 00000000..92cb9b72 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_adapter_util.h @@ -0,0 +1,289 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dapl_adapter_util.h + * + * PURPOSE: Utility defs & routines for the adapter data structure + * + * $Id: dapl_adapter_util.h 1317 2005-04-25 17:29:42Z jlentini $ + * + **********************************************************************/ + +#ifndef _DAPL_ADAPTER_UTIL_H_ +#define _DAPL_ADAPTER_UTIL_H_ + + +typedef enum async_handler_type +{ + DAPL_ASYNC_UNAFILIATED, + DAPL_ASYNC_CQ_ERROR, + DAPL_ASYNC_CQ_COMPLETION, + DAPL_ASYNC_QP_ERROR +} DAPL_ASYNC_HANDLER_TYPE; + + +int dapls_ib_init (void); + +int dapls_ib_release (void); + +DAT_RETURN dapls_ib_enum_hcas ( + IN const char *vendor, + OUT DAPL_HCA_NAME **hca_names, + OUT DAT_COUNT *total_hca_count); + +DAT_RETURN dapls_ib_get_instance_data( + IN DAPL_HCA_NAME hca_name, + OUT char *instance); + +DAT_RETURN dapls_ib_open_hca ( + IN char *namestr, + IN DAPL_HCA *hca_ptr); + +DAT_RETURN dapls_ib_close_hca ( + IN DAPL_HCA *hca_ptr); + +DAT_RETURN dapls_ib_qp_alloc ( + IN DAPL_IA *ia_ptr, + IN DAPL_EP *ep_ptr, + IN DAPL_EP *ep_ctx_ptr); + +DAT_RETURN dapls_ib_qp_free ( + IN DAPL_IA *ia_ptr, + IN DAPL_EP *ep_ptr); + +DAT_RETURN dapls_ib_qp_modify ( + IN DAPL_IA *ia_ptr, + IN DAPL_EP *ep_ptr, + IN DAT_EP_ATTR *ep_attr); + +DAT_RETURN dapls_ib_connect ( + IN DAT_EP_HANDLE ep_handle, + IN DAT_IA_ADDRESS_PTR remote_ia_address, + IN DAT_CONN_QUAL remote_conn_qual, + IN DAT_COUNT private_data_size, + IN DAT_PVOID private_data); + +DAT_RETURN dapls_ib_disconnect ( + IN DAPL_EP *ep_ptr, + IN DAT_CLOSE_FLAGS close_flags); + +DAT_RETURN dapls_ib_setup_conn_listener ( + IN DAPL_IA *ia_ptr, + IN DAT_UINT64 ServiceID, + IN DAPL_SP *sp_ptr); + +DAT_RETURN dapls_ib_remove_conn_listener ( + IN DAPL_IA *ia_ptr, + IN DAPL_SP *sp_ptr); + +DAT_RETURN dapls_ib_accept_connection ( + IN DAT_CR_HANDLE cr_handle, + IN DAT_EP_HANDLE ep_handle, + IN DAT_COUNT private_data_size, + IN const DAT_PVOID private_data); + +DAT_RETURN dapls_ib_reject_connection ( + IN dp_ib_cm_handle_t cm_handle, + IN int reject_reason, + IN DAT_COUNT private_data_size, + IN const DAT_PVOID private_data); + +DAT_RETURN dapls_ib_setup_async_callback ( + IN DAPL_IA *ia_ptr, + IN DAPL_ASYNC_HANDLER_TYPE handler_type, + IN DAPL_EVD *evd_ptr, + IN ib_async_handler_t callback, + IN void *context); + +DAT_RETURN dapls_ib_cq_alloc ( + IN DAPL_IA *ia_ptr, + IN DAPL_EVD *evd_ptr, + IN DAT_COUNT *cqlen); + +DAT_RETURN dapls_ib_cq_free ( + IN DAPL_IA *ia_ptr, + IN DAPL_EVD *evd_ptr); + +DAT_RETURN dapls_set_cq_notify ( + IN DAPL_IA *ia_ptr, + IN DAPL_EVD *evd_ptr); + +DAT_RETURN dapls_ib_cq_resize ( + IN DAPL_IA *ia_ptr, + IN DAPL_EVD *evd_ptr, + IN DAT_COUNT *cqlen); + +DAT_RETURN dapls_ib_pd_alloc ( + IN DAPL_IA *ia_ptr, + IN DAPL_PZ *pz); + +DAT_RETURN dapls_ib_pd_free ( + IN DAPL_PZ *pz); + +DAT_RETURN dapls_ib_mr_register ( + IN DAPL_IA *ia_ptr, + IN DAPL_LMR *lmr, + IN DAT_PVOID virt_addr, + IN DAT_VLEN length, + IN DAT_MEM_PRIV_FLAGS privileges, + IN DAT_VA_TYPE va_type); + +#if defined(__KDAPL__) +DAT_RETURN dapls_ib_mr_register_physical ( + IN DAPL_IA *ia_ptr, + INOUT DAPL_LMR *lmr, + IN DAT_PADDR phys_addr, + IN DAT_VLEN length, + IN DAT_MEM_PRIV_FLAGS privileges); +#endif /* __KDAPL__ */ + +DAT_RETURN dapls_ib_mr_deregister ( + IN DAPL_LMR *lmr); + +DAT_RETURN dapls_ib_mr_register_shared ( + IN DAPL_IA *ia_ptr, + IN DAPL_LMR *lmr, + IN DAT_MEM_PRIV_FLAGS privileges, + IN DAT_VA_TYPE va_type); + +DAT_RETURN dapls_ib_mw_alloc ( + IN DAPL_RMR *rmr); + +DAT_RETURN dapls_ib_mw_free ( + IN DAPL_RMR *rmr); + +DAT_RETURN dapls_ib_mw_bind ( + IN DAPL_RMR *rmr, + IN DAPL_LMR *lmr, + IN DAPL_EP *ep, + IN DAPL_COOKIE *cookie, + IN DAT_VADDR virtual_address, + IN DAT_VLEN length, + IN DAT_MEM_PRIV_FLAGS mem_priv, + IN DAT_BOOLEAN is_signaled); + +DAT_RETURN dapls_ib_mw_unbind ( + IN DAPL_RMR *rmr, + IN DAPL_EP *ep, + IN DAPL_COOKIE *cookie, + IN DAT_BOOLEAN is_signaled); + +DAT_RETURN dapls_ib_query_hca ( + IN DAPL_HCA *hca_ptr, + OUT DAT_IA_ATTR *ia_attr, + OUT DAT_EP_ATTR *ep_attr, + OUT DAT_SOCK_ADDR6 *ip_addr); + +DAT_RETURN dapls_ib_completion_poll ( + IN DAPL_HCA *hca_ptr, + IN DAPL_EVD *evd_ptr, + IN ib_work_completion_t *cqe_ptr); + +DAT_RETURN dapls_ib_completion_notify ( + IN ib_hca_handle_t hca_handle, + IN DAPL_EVD *evd_ptr, + IN ib_notification_type_t type); + +DAT_DTO_COMPLETION_STATUS dapls_ib_get_dto_status ( + IN ib_work_completion_t *cqe_ptr); + +void dapls_ib_reinit_ep ( + IN DAPL_EP *ep_ptr); + +void dapls_ib_disconnect_clean ( + IN DAPL_EP *ep_ptr, + IN DAT_BOOLEAN passive, + IN const ib_cm_events_t ib_cm_event); + +DAT_RETURN dapls_ib_get_async_event ( + IN ib_error_record_t *cause_ptr, + OUT DAT_EVENT_NUMBER *async_event); + +DAT_EVENT_NUMBER dapls_ib_get_dat_event ( + IN const ib_cm_events_t ib_cm_event, + IN DAT_BOOLEAN active); + +ib_cm_events_t dapls_ib_get_cm_event ( + IN DAT_EVENT_NUMBER dat_event_num); + +DAT_RETURN dapls_ib_cm_remote_addr ( + IN DAT_HANDLE dat_handle, + OUT DAT_SOCK_ADDR6 *remote_ia_address); + +int dapls_ib_private_data_size( + IN DAPL_HCA *hca_ptr); + +void +dapls_query_provider_specific_attr( + IN DAPL_IA *ia_ptr, + IN DAT_PROVIDER_ATTR *attr_ptr ); + +DAT_RETURN +dapls_evd_dto_wakeup ( + IN DAPL_EVD *evd_ptr); + +DAT_RETURN +dapls_evd_dto_wait ( + IN DAPL_EVD *evd_ptr, + IN uint32_t timeout); + +#ifdef DAT_EXTENSIONS +void +dapls_cqe_to_event_extension( + IN DAPL_EP *ep_ptr, + IN DAPL_COOKIE *cookie, + IN ib_work_completion_t *cqe_ptr, + IN DAT_EVENT *event_ptr); +#endif + +/* + * Values for provider DAT_NAMED_ATTR + */ +#define IB_QP_STATE 1 /* QP state change request */ + + +#ifdef IBAPI +#include "dapl_ibapi_dto.h" +#elif VAPI +#include "dapl_vapi_dto.h" +#elif __OPENIB__ +#include "dapl_openib_dto.h" +#elif DUMMY +#include "dapl_dummy_dto.h" +#elif OPENIB +#include "dapl_ib_dto.h" +#else +#include "dapl_ibal_dto.h" +#endif + + +#endif /* _DAPL_ADAPTER_UTIL_H_ */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_cno_util.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_cno_util.c new file mode 100644 index 00000000..2215f29e --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_cno_util.c @@ -0,0 +1,313 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_cno_util.c + * + * PURPOSE: Manage CNO Info structure + * + * $Id:$ + **********************************************************************/ + +#include "dapl_ia_util.h" +#include "dapl_cno_util.h" +#include "dapl_adapter_util.h" + +/* + * dapl_cno_alloc + * + * alloc and initialize an EVD struct + * + * Input: + * ia + * + * Returns: + * cno_ptr, or null on failure. + */ +#if defined(__KDAPL__) +DAPL_CNO *dapl_cno_alloc(IN DAPL_IA * ia_ptr, + IN const DAT_UPCALL_OBJECT * upcall) +#else +DAPL_CNO *dapl_cno_alloc(IN DAPL_IA * ia_ptr, + IN DAT_OS_WAIT_PROXY_AGENT wait_agent) +#endif /* defined(__KDAPL__) */ +{ + DAPL_CNO *cno_ptr; + + cno_ptr = (DAPL_CNO *) dapl_os_alloc(sizeof(DAPL_CNO)); + if (!cno_ptr) { + return NULL; + } + + /* zero the structure */ + dapl_os_memzero(cno_ptr, sizeof(DAPL_CNO)); + + /* + * Initialize the header. + */ + cno_ptr->header.provider = ia_ptr->header.provider; + cno_ptr->header.magic = DAPL_MAGIC_CNO; +#if !defined(__KDAPL__) + cno_ptr->header.handle_type = DAT_HANDLE_TYPE_CNO; +#endif /* defined(__KDAPL__) */ + cno_ptr->header.owner_ia = ia_ptr; + cno_ptr->header.user_context.as_64 = 0; + cno_ptr->header.user_context.as_ptr = NULL; + dapl_llist_init_entry(&cno_ptr->header.ia_list_entry); + dapl_os_lock_init(&cno_ptr->header.lock); + + /* + * Initialize the body + */ + cno_ptr->cno_waiters = 0; + dapl_os_atomic_set(&cno_ptr->cno_ref_count, 0); + cno_ptr->cno_state = DAPL_CNO_STATE_UNTRIGGERED; + cno_ptr->cno_evd_triggered = NULL; +#if defined(__KDAPL__) + cno_ptr->cno_upcall = *upcall; +#else + cno_ptr->cno_wait_agent = wait_agent; +#endif /* defined(__KDAPL__) */ + dapl_os_wait_object_init(&cno_ptr->cno_wait_object); + + return cno_ptr; +} + +/* + * dapl_cno_dealloc + * + * Free the passed in CNO structure. + * + * Input: + * cno_ptr + * + * Output: + * none + * + * Returns: + * none + * + */ +void dapl_cno_dealloc(IN DAPL_CNO * cno_ptr) +{ + dapl_os_assert(cno_ptr->header.magic == DAPL_MAGIC_CNO); + dapl_os_assert(dapl_os_atomic_read(&cno_ptr->cno_ref_count) == 0); + + /* + * deinitialize the header + */ + cno_ptr->header.magic = DAPL_MAGIC_INVALID; /* reset magic to prevent reuse */ + + dapl_os_wait_object_destroy(&cno_ptr->cno_wait_object); + dapl_os_free(cno_ptr, sizeof(DAPL_CNO)); +} + +/* + * dapl_internal_cno_trigger + * + * DAPL Internal routine to trigger the specified CNO. + * Called by the callback of some EVD associated with the CNO. + * + * + * + * Input: + * cno_ptr + * evd_ptr EVD triggering + * + * Output: + * None + * + * Returns: + * None + */ +void dapl_internal_cno_trigger(IN DAPL_CNO * cno_ptr, IN DAPL_EVD * evd_ptr) +{ + DAT_RETURN dat_status; +#if defined(__KDAPL__) + DAT_EVENT event; +#endif /* defined(__KDAPL__) */ + + dat_status = DAT_SUCCESS; + + dapl_os_assert(cno_ptr->header.magic == DAPL_MAGIC_CNO); + /* The spec allows NULL EVDs. kDAPL doesn't have CNOs, they + * are strictly used behind the scenes + */ + dapl_os_assert(evd_ptr == NULL + || evd_ptr->header.magic == DAPL_MAGIC_EVD); + + dapl_os_lock(&cno_ptr->header.lock); + + /* Maybe I should just return, but this really shouldn't happen. */ + dapl_os_assert(cno_ptr->cno_state != DAPL_CNO_STATE_DEAD); + + if (cno_ptr->cno_state == DAPL_CNO_STATE_UNTRIGGERED) { +#if !defined(__KDAPL__) + DAT_OS_WAIT_PROXY_AGENT agent; + + /* Squirrel away wait agent, and delete link. */ + agent = cno_ptr->cno_wait_agent; +#endif /* !defined(__KDAPL__) */ + + /* Separate assignments for windows compiler. */ +#ifndef _WIN32 +#if defined(__KDAPL__) + cno_ptr->cno_upcall = DAT_UPCALL_NULL; +#else + cno_ptr->cno_wait_agent = DAT_OS_WAIT_PROXY_AGENT_NULL; +#endif /* defined(__KDAPL__) */ +#else + cno_ptr->cno_wait_agent.instance_data = NULL; + cno_ptr->cno_wait_agent.proxy_agent_func = NULL; +#endif + + cno_ptr->cno_evd_triggered = evd_ptr; + + /* + * Must set to triggerred and let waiter untrigger to handle + * timeout of waiter. + */ + cno_ptr->cno_state = DAPL_CNO_STATE_TRIGGERED; + if (cno_ptr->cno_waiters > 0) { + dapl_os_wait_object_wakeup(&cno_ptr->cno_wait_object); + } + + dapl_os_unlock(&cno_ptr->header.lock); + + /* Trigger the OS proxy wait agent, if one exists. */ +#if defined(__KDAPL__) + dat_status = dapl_evd_dequeue((DAT_EVD_HANDLE) evd_ptr, &event); + while (dat_status == DAT_SUCCESS) { + if (cno_ptr->cno_upcall.upcall_func != + (DAT_UPCALL_FUNC) NULL) { + cno_ptr->cno_upcall.upcall_func(cno_ptr-> + cno_upcall. + instance_data, + &event, + DAT_FALSE); + } + dat_status = dapl_evd_dequeue((DAT_EVD_HANDLE) evd_ptr, + &event); + } +#else + if (agent.proxy_agent_func != (DAT_AGENT_FUNC) NULL) { + agent.proxy_agent_func(agent.instance_data, + (DAT_EVD_HANDLE) evd_ptr); + } +#endif /* defined(__KDAPL__) */ + } else { + dapl_os_unlock(&cno_ptr->header.lock); +#if defined(__KDAPL__) + dat_status = dapl_evd_dequeue((DAT_EVD_HANDLE) evd_ptr, &event); + while (dat_status == DAT_SUCCESS) { + if (cno_ptr->cno_upcall.upcall_func != + (DAT_UPCALL_FUNC) NULL) { + cno_ptr->cno_upcall.upcall_func(cno_ptr-> + cno_upcall. + instance_data, + &event, + DAT_FALSE); + } + dat_status = dapl_evd_dequeue((DAT_EVD_HANDLE) evd_ptr, + &event); + } +#endif /* defined(__KDAPL__) */ + } + + return; +} + +/* + * dapl_cno_fd_create + * + * DAPL Requirements Version 2.0, 6.3.2.x + * + * creates a CNO instance. Upon creation, there are no + * Event Dispatchers feeding it. os_fd is a File Descriptor in Unix, + * i.e. struct pollfd or an equivalent object in other OSes that is + * always associates with the created CNO. Consumer can multiplex event + * waiting using UNIX poll or select functions. Upon creation, the CNO + * is not associated with any EVDs, has no waiters and has the os_fd + * associated with it. + * + * Input: + * ia_handle + * + * Output: + * file descripter + * cno_handle + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + * DAT_INVALID_HANDLE + * DAT_INVALID_STATE + * DAT_LENGTH_ERROR + * DAT_PROTECTION_VIOLATION + * DAT_PRIVILEGES_VIOLATION + * DAT_MODEL_NOT_SUPPORTED + */ +DAT_RETURN DAT_API dapl_cno_fd_create(IN DAT_IA_HANDLE ia_handle, /* ia_handle */ + OUT DAT_FD * fd, /* file_descriptor */ + OUT DAT_CNO_HANDLE * cno_handle) +{ /* cno_handle */ + return DAT_MODEL_NOT_SUPPORTED; +} + +/* + * dapl_cno_fd_create + * + * DAPL Requirements Version 2.0, 6.3.2.x + * + * Returns the latest EVD that triggered the CNO. + * + * Input: + * cno_handle + * + * Output: + * evd_handle + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + * DAT_MODEL_NOT_SUPPORTED + */ +DAT_RETURN DAT_API +dapl_cno_trigger(IN DAT_CNO_HANDLE cno_handle, OUT DAT_EVD_HANDLE * evd_handle) +{ + return DAT_MODEL_NOT_SUPPORTED; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_cno_util.h b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_cno_util.h new file mode 100644 index 00000000..1cd601f6 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_cno_util.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dapl_cno_util.h + * + * PURPOSE: Utility defs & routines for the cno data structure + * + * $Id:$ + * + **********************************************************************/ + +#ifndef _DAPL_CNO_UTIL_H_ +#define _DAPL_CNO_UTIL_H_ + +#include "dapl.h" + +#if defined(__KDAPL__) +DAPL_CNO * +dapl_cno_alloc ( + IN DAPL_IA *ia_ptr, + IN const DAT_UPCALL_OBJECT *upcall) ; + +#else +DAPL_CNO * +dapl_cno_alloc ( + IN DAPL_IA *ia_ptr, + IN DAT_OS_WAIT_PROXY_AGENT wait_agent) ; + +#endif /* defined(__KDAPL__) */ + +void +dapl_cno_dealloc ( + IN DAPL_CNO *cno_ptr) ; + +void +dapl_internal_cno_trigger( + IN DAPL_CNO *cno_ptr, + IN DAPL_EVD *evd_ptr); + +#endif diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_cookie.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_cookie.c new file mode 100644 index 00000000..990ff663 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_cookie.c @@ -0,0 +1,360 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_cookie.c + * + * PURPOSE: Manage CQE cookie structures + * + * The DAPL spec requires that all a cookies passed to a posting operation + * be returned in the operation's corresponding completion. + * + * Implementing this feature is complicated by the user's ability to + * suppress event generation for specific operations. When these operations + * complete successfully, the provider does not have an easy way to + * deallocate resources devoted to storing context data for these operations. + * + * To support this feature, a pool of memory is allocated up front large + * enough to hold cookie data for the maximum number of operations possible + * on an endpoint. + * + * Two pieces of information are maintained to manage cookie allocation: + * + * head index : index of next unallocated cookie + * tail index : index of last unallocated cookie + * + * Each cookie store its index in this memory pool. + * + * When an event is received, the index stored in the event's cookie will be + * used to update the tail. This will implicitly deallocate all of the cookies + * "between" the old tail and the new tail. + * + * The implementation relies on the following assumptions: + * + * - there can be only 1 thread in dat_ep_post_send(), dat_ep_post_rdma_write(), + * dat_ep_post_rdma_read(), or dat_rmr_bind() at a time, therefore + * dapls_cb_get() does not need to be thread safe when manipulating + * request data structures. + * + * - there can be only 1 thread in dat_ep_post_recv(), therefore + * dapls_cb_get() does not need to be thread safe when manipulating + * receive data structures. + * + * - there can be only 1 thread generating completions for a given EP's request + * opeartions, therefore dapls_cb_put() does not need to be thread safe when + * manipulating request data structures. + * + * - there can be only 1 thread generating completions for a given EP's receive + * opeartions therefore dapls_cb_put() does not need to be thread safe when + * manipulating receive data structures. + * + * - completions are delivered in order + * + * $Id:$ + **********************************************************************/ + +#include "dapl_cookie.h" +#include "dapl_ring_buffer_util.h" + +/********************************************************************* + * * + * Function Prototypes * + * * + *********************************************************************/ + +DAT_RETURN dapls_cb_get(DAPL_COOKIE_BUFFER * buffer, DAPL_COOKIE ** cookie_ptr); + +DAT_RETURN dapls_cb_put(DAPL_COOKIE_BUFFER * buffer, DAPL_COOKIE * cookie); + +/********************************************************************* + * * + * Function Definitions * + * * + *********************************************************************/ + +/* + * dapls_cb_create + * + * Given a DAPL_COOKIE_BUFFER, allocate and initialize memory for + * the data structure. + * + * Input: + * buffer pointer to DAPL_COOKIE_BUFFER + * ep endpoint to associate with cookies + * size number of elements to allocate & manage + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * + */ +DAT_RETURN +dapls_cb_create(IN DAPL_COOKIE_BUFFER * buffer, + IN DAPL_EP * ep, IN DAT_COUNT size) +{ + DAT_COUNT i; + + /* + * allocate one additional entry so that the tail + * can always point at an empty location + */ + size++; + + buffer->pool = dapl_os_alloc(size * sizeof(DAPL_COOKIE)); + if (NULL != buffer->pool) { + buffer->pool_size = size; + dapl_os_atomic_set(&buffer->head, 0); + dapl_os_atomic_set(&buffer->tail, 0); + + for (i = 0; i < size; i++) { + buffer->pool[i].index = i; + buffer->pool[i].ep = ep; + } + + return (DAT_SUCCESS); + } else { + return (DAT_INSUFFICIENT_RESOURCES); + } +} + +/* + * dapls_cb_free + * + * Free the data structure + * + * Input: + * buffer pointer to DAPL_COOKIE_BUFFER + * + * Output: + * none + * + * Returns: + * none + * + */ +void dapls_cb_free(IN DAPL_COOKIE_BUFFER * buffer) +{ + if (NULL != buffer->pool) { + dapl_os_free(buffer->pool, + buffer->pool_size * sizeof(DAPL_COOKIE)); + buffer->pool = NULL; + } +} + +/* + * dapls_cb_get + * + * Remove an entry from the buffer + * + * Input: + * buffer pointer to DAPL_COOKIE_BUFFER + * + * Output: + * cookie_ptr pointer to pointer to cookie + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + * DAT_INSUFFICIENT_RESOURCES + * + */ +DAT_RETURN +dapls_cb_get(IN DAPL_COOKIE_BUFFER * buffer, OUT DAPL_COOKIE ** cookie_ptr) +{ + DAT_RETURN dat_status; + DAT_COUNT new_head; + + dapl_os_assert(NULL != cookie_ptr); + + new_head = (dapl_os_atomic_read(&buffer->head) + 1) % buffer->pool_size; + + if (new_head == dapl_os_atomic_read(&buffer->tail)) { + dat_status = DAT_INSUFFICIENT_RESOURCES; + goto bail; + } else { + dapl_os_atomic_set(&buffer->head, new_head); + *cookie_ptr = &buffer->pool[dapl_os_atomic_read(&buffer->head)]; + dat_status = DAT_SUCCESS; + } + bail: + return dat_status; +} + +/* + * dapls_cb_put + * + * Add entry(s) to the buffer + * + * Input: + * buffer pointer to DAPL_COOKIE_BUFFER + * cookie pointer to cookie + * + * Output: + * entry entry removed from the ring buffer + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_EMPTY + * + */ +DAT_RETURN dapls_cb_put(IN DAPL_COOKIE_BUFFER * buffer, IN DAPL_COOKIE * cookie) +{ + dapl_os_atomic_set(&buffer->tail, cookie->index); + + return DAT_SUCCESS; +} + +/* + * dapls_cb_pending + * + * snapshot of active entries on cookie ring buffer + * + * Input: + * buffer pointer to DAPL_COOKIE_BUFFER + * + * Returns: + * DAT_COUNT number of active/pending cookies + * + */ +extern DAT_COUNT dapls_cb_pending(DAPL_COOKIE_BUFFER * buffer) +{ + DAT_COUNT head, tail; + + head = dapl_os_atomic_read(&buffer->head); + tail = dapl_os_atomic_read(&buffer->tail); + + if (head == tail) + return 0; + else if (head > tail) + return (head - tail); + else + return ((buffer->pool_size - tail) + head); +} + +/* + * dapls_rmr_cookie_alloc + * + * Allocate an RMR Bind cookie + * + * Input: + * buffer pointer to DAPL_COOKIE_BUFFER + * rmr rmr to associate with the cookie + * user_cookie user's cookie data + * + * Output: + * cookie_ptr pointer to pointer to allocated cookie + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_EMPTY + * + */ +DAT_RETURN +dapls_rmr_cookie_alloc(IN DAPL_COOKIE_BUFFER * buffer, + IN DAPL_RMR * rmr, + IN DAT_RMR_COOKIE user_cookie, + OUT DAPL_COOKIE ** cookie_ptr) +{ + DAPL_COOKIE *cookie; + DAT_RETURN dat_status; + + if (DAT_SUCCESS != dapls_cb_get(buffer, &cookie)) { + *cookie_ptr = NULL; + dat_status = + DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); + goto bail; + } + + dat_status = DAT_SUCCESS; + cookie->type = DAPL_COOKIE_TYPE_RMR; + cookie->val.rmr.rmr = rmr; + cookie->val.rmr.cookie = user_cookie; + + *cookie_ptr = cookie; + + bail: + return dat_status; +} + +/* + * dapls_dto_cookie_alloc + * + * Allocate a DTO cookie + * + * Input: + * buffer pointer to DAPL_COOKIE_BUFFER + * type DTO type + * user_cookie user's cookie data + * + * Output: + * cookie_ptr pointer to pointer to allocated cookie + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_EMPTY + * + */ +DAT_RETURN +dapls_dto_cookie_alloc(IN DAPL_COOKIE_BUFFER * buffer, + IN DAPL_DTO_TYPE type, + IN DAT_DTO_COOKIE user_cookie, + OUT DAPL_COOKIE ** cookie_ptr) +{ + DAPL_COOKIE *cookie; + + if (DAT_SUCCESS != dapls_cb_get(buffer, &cookie)) { + *cookie_ptr = NULL; + return DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, + DAT_RESOURCE_MEMORY); + } + + cookie->type = DAPL_COOKIE_TYPE_DTO; + cookie->val.dto.type = type; + cookie->val.dto.cookie = user_cookie; + cookie->val.dto.size = 0; + + *cookie_ptr = cookie; + return DAT_SUCCESS; +} + +void +dapls_cookie_dealloc(IN DAPL_COOKIE_BUFFER * buffer, IN DAPL_COOKIE * cookie) +{ + dapls_cb_put(buffer, cookie); +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_cookie.h b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_cookie.h new file mode 100644 index 00000000..f953b28a --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_cookie.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dapl_cookie.h + * + * PURPOSE: Utility defs & routines for the cookie data structure + * + * $Id:$ + * + **********************************************************************/ + +#ifndef _DAPL_COOKIE_H +#define _DAPL_COOKIE_H_ + +#include "dapl.h" + +extern DAT_RETURN +dapls_cb_create ( + DAPL_COOKIE_BUFFER *buffer, + DAPL_EP *ep, + DAT_COUNT size ); + +extern void +dapls_cb_free ( + DAPL_COOKIE_BUFFER *buffer ); + +extern DAT_COUNT +dapls_cb_pending ( + DAPL_COOKIE_BUFFER *buffer ); + +extern DAT_RETURN +dapls_rmr_cookie_alloc ( + IN DAPL_COOKIE_BUFFER *buffer, + IN DAPL_RMR *rmr, + IN DAT_RMR_COOKIE user_cookie, + OUT DAPL_COOKIE **cookie_ptr ); + +extern DAT_RETURN +dapls_dto_cookie_alloc ( + IN DAPL_COOKIE_BUFFER *buffer, + IN DAPL_DTO_TYPE type, + IN DAT_DTO_COOKIE user_cookie, + OUT DAPL_COOKIE **cookie_ptr ); + +extern void +dapls_cookie_dealloc ( + IN DAPL_COOKIE_BUFFER *buffer, + IN DAPL_COOKIE *cookie ); + +#endif /* _DAPL_COOKIE_H_ */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_cr_accept.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_cr_accept.c new file mode 100644 index 00000000..5df9458b --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_cr_accept.c @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_cr_accept.c + * + * PURPOSE: Connection management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 4 + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_adapter_util.h" +#include "dapl_evd_util.h" + +/* + * dapl_cr_accept + * + * DAPL Requirements Version xxx, 6.4.2.1 + * + * Establish a connection between active remote side requesting Endpoint + * and passic side local Endpoint. + * + * Input: + * cr_handle + * ep_handle + * private_data_size + * private_data + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + * DAT_INVALID_ATTRIBUTE + */ +DAT_RETURN DAT_API +dapl_cr_accept(IN DAT_CR_HANDLE cr_handle, + IN DAT_EP_HANDLE ep_handle, + IN DAT_COUNT private_data_size, IN const DAT_PVOID private_data) +{ + DAPL_EP *ep_ptr; + DAT_RETURN dat_status; + DAPL_CR *cr_ptr; + DAT_EP_STATE entry_ep_state; + DAT_EP_HANDLE entry_ep_handle; + + dapl_dbg_log(DAPL_DBG_TYPE_API, + "dapl_cr_accept (CR %p EP %p, PDsz %d PD %p)\n", + cr_handle, ep_handle, private_data_size, private_data); + + if (DAPL_BAD_HANDLE(cr_handle, DAPL_MAGIC_CR)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_CR); + goto bail; + } + + cr_ptr = (DAPL_CR *) cr_handle; + + /* + * Return an error if we have an ep_handle and the CR already has an + * EP, indicating this is an RSP connection or PSP_PROVIDER_FLAG was + * specified. + */ + if (ep_handle != NULL && + (DAPL_BAD_HANDLE(ep_handle, DAPL_MAGIC_EP) || + cr_ptr->param.local_ep_handle != NULL)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP); + goto bail; + } + + /* Make sure we have an EP handle in one place or another */ + if (ep_handle == NULL && cr_ptr->param.local_ep_handle == NULL) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP); + goto bail; + } + + if ((0 != private_data_size) && (NULL == private_data)) { + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG4); + goto bail; + } + + /* + * ep_handle is NULL if the user specified DAT_PSP_PROVIDER_FLAG + * OR this is an RSP connection; retrieve it from the cr. + */ + if (ep_handle == NULL) { + ep_handle = cr_ptr->param.local_ep_handle; + if (((((DAPL_EP *) ep_handle)->param.ep_state != + DAT_EP_STATE_TENTATIVE_CONNECTION_PENDING) + && (((DAPL_EP *) ep_handle)->param.ep_state != + DAT_EP_STATE_PASSIVE_CONNECTION_PENDING)) + && (((DAPL_EP *) ep_handle)->param.ep_attr.service_type == + DAT_SERVICE_TYPE_RC)) { + return DAT_INVALID_STATE; + } + } else { + /* ensure this EP isn't connected or in use */ + if ((((DAPL_EP *) ep_handle)->param.ep_state != + DAT_EP_STATE_UNCONNECTED) + && (((DAPL_EP *) ep_handle)->param.ep_attr.service_type == + DAT_SERVICE_TYPE_RC)) { + return DAT_INVALID_STATE; + } + } + + ep_ptr = (DAPL_EP *) ep_handle; + + /* + * Verify the attributes of the EP handle before we connect it. Test + * all of the handles to make sure they are currently valid. + * Specifically: + * pz_handle required + * recv_evd_handle optional, but must be valid + * request_evd_handle optional, but must be valid + * connect_evd_handle required + * We do all verification and state change under lock, at which + * point the EP state should protect us from most races. + */ + dapl_os_lock(&ep_ptr->header.lock); + if (ep_ptr->param.pz_handle == NULL + || DAPL_BAD_HANDLE(ep_ptr->param.pz_handle, DAPL_MAGIC_PZ) + /* test connect handle */ + || ep_ptr->param.connect_evd_handle == NULL + || DAPL_BAD_HANDLE(ep_ptr->param.connect_evd_handle, DAPL_MAGIC_EVD) + || !(((DAPL_EVD *) ep_ptr->param.connect_evd_handle)-> + evd_flags & DAT_EVD_CONNECTION_FLAG) + /* test optional completion handles */ + || (ep_ptr->param.recv_evd_handle != DAT_HANDLE_NULL && + (DAPL_BAD_HANDLE + (ep_ptr->param.recv_evd_handle, DAPL_MAGIC_EVD))) + + || (ep_ptr->param.request_evd_handle != DAT_HANDLE_NULL && + (DAPL_BAD_HANDLE + (ep_ptr->param.request_evd_handle, DAPL_MAGIC_EVD)))) { + dapl_os_unlock(&ep_ptr->header.lock); + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP); + goto bail; + } + + /* The qp must be attached by this point! */ + if (ep_ptr->qp_state == DAPL_QP_STATE_UNATTACHED) { + dapl_os_unlock(&ep_ptr->header.lock); + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP); + goto bail; + } + + entry_ep_state = ep_ptr->param.ep_state; + entry_ep_handle = cr_ptr->param.local_ep_handle; + ep_ptr->param.ep_state = DAT_EP_STATE_COMPLETION_PENDING; + ep_ptr->cr_ptr = cr_ptr; + ep_ptr->param.remote_ia_address_ptr = + cr_ptr->param.remote_ia_address_ptr; + cr_ptr->param.local_ep_handle = ep_handle; + + dapl_os_unlock(&ep_ptr->header.lock); + + dat_status = dapls_ib_accept_connection(cr_handle, + ep_handle, + private_data_size, + private_data); + + /* + * If the provider failed, unwind the damage so we are back at + * the initial state. + */ + if (dat_status != DAT_SUCCESS) { + if (DAT_GET_TYPE(dat_status) == DAT_INVALID_ADDRESS) { + /* The remote connection request has disappeared; timeout, + * system error, app termination, perhaps other reasons. + */ + dat_status = + dapls_evd_post_connection_event(ep_ptr->param. + connect_evd_handle, + DAT_CONNECTION_EVENT_ACCEPT_COMPLETION_ERROR, + (DAT_HANDLE) ep_ptr, + 0, 0); + + cr_ptr->header.magic = DAPL_MAGIC_CR_DESTROYED; + } else { + ep_ptr->param.ep_state = entry_ep_state; + cr_ptr->param.local_ep_handle = entry_ep_handle; + ep_ptr->cr_ptr = NULL; + ep_ptr->param.remote_ia_address_ptr = NULL; + } + + /* + * After restoring values above, we now check if we need + * to translate the error + */ + if (DAT_GET_TYPE(dat_status) == DAT_LENGTH_ERROR) { + dat_status = + DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG3); + } + + } else { + /* Make this CR invalid. We need to hang on to it until + * the connection terminates, but it's destroyed from + * the app point of view. + */ + cr_ptr->header.magic = DAPL_MAGIC_CR_DESTROYED; + } + + bail: + return dat_status; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_cr_callback.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_cr_callback.c new file mode 100644 index 00000000..3997b382 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_cr_callback.c @@ -0,0 +1,542 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapls_cr_callback.c + * + * PURPOSE: implements passive side connection callbacks + * + * Description: Accepts asynchronous callbacks from the Communications Manager + * for EVDs that have been specified as the connection_evd. + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_evd_util.h" +#include "dapl_cr_util.h" +#include "dapl_ia_util.h" +#include "dapl_sp_util.h" +#include "dapl_ep_util.h" +#include "dapl_adapter_util.h" + +/* + * Prototypes + */ +DAT_RETURN dapli_connection_request(IN dp_ib_cm_handle_t ib_cm_handle, + IN DAPL_SP * sp_ptr, + IN DAPL_PRIVATE * prd_ptr, + IN int private_data_size, + IN DAPL_EVD * evd_ptr); + +DAPL_EP *dapli_get_sp_ep(IN dp_ib_cm_handle_t ib_cm_handle, + IN DAPL_SP * sp_ptr, + IN DAT_EVENT_NUMBER dat_event_num); + +/* + * dapls_cr_callback + * + * The callback function registered with verbs for passive side of + * connection requests. The interface is specified by cm_api.h + * + * + * Input: + * ib_cm_handle, Handle to CM + * ib_cm_event Specific CM event + * instant_data Private data with DAT ADDRESS header + * context SP pointer + * + * Output: + * None + * + */ +void dapls_cr_callback(IN dp_ib_cm_handle_t ib_cm_handle, IN const ib_cm_events_t ib_cm_event, + IN const void *private_data_ptr, IN const int private_data_size, + IN const void *context) +{ + DAPL_EP *ep_ptr; + DAPL_EVD *evd_ptr; + DAPL_SP *sp_ptr; + DAPL_PRIVATE *prd_ptr; + DAT_EVENT_NUMBER dat_event_num; + DAT_RETURN dat_status; + + dapl_dbg_log(DAPL_DBG_TYPE_CM | DAPL_DBG_TYPE_CALLBACK, + "--> dapl_cr_callback! context: %p event: %x cm_handle %p\n", + context, ib_cm_event, (void *)ib_cm_handle); + + /* + * Passive side of the connection, context is a SP and + * we need to look up the EP. + */ + sp_ptr = (DAPL_SP *) context; + /* + * The context pointer could have been cleaned up in a racing + * CM callback, check to see if we should just exit here + */ + if (sp_ptr->header.magic == DAPL_MAGIC_INVALID) { + return; + } + dapl_os_assert(sp_ptr->header.magic == DAPL_MAGIC_PSP || + sp_ptr->header.magic == DAPL_MAGIC_RSP); + + /* Obtain the event number from the provider layer */ + dat_event_num = dapls_ib_get_dat_event(ib_cm_event, DAT_FALSE); + + /* + * CONNECT_REQUEST events create an event on the PSP + * EVD, which will trigger connection processing. The + * sequence is: + * CONNECT_REQUEST Event to SP + * CONNECTED Event to EP + * DISCONNECT Event to EP + * + * Obtain the EP if required and set an event up on the correct + * EVD. + */ + if (dat_event_num == DAT_CONNECTION_REQUEST_EVENT) { + ep_ptr = NULL; + evd_ptr = sp_ptr->evd_handle; + } else { + /* see if there is an EP connected with this CM handle */ + ep_ptr = dapli_get_sp_ep(ib_cm_handle, sp_ptr, dat_event_num); + + /* if we lost a race with the CM just exit. */ + if (ep_ptr == NULL) { + return; + } + + evd_ptr = (DAPL_EVD *) ep_ptr->param.connect_evd_handle; + /* if something has happened to our EVD, bail. */ + if (evd_ptr == NULL) { + return; + } + } + + prd_ptr = (DAPL_PRIVATE *) private_data_ptr; + + dat_status = DAT_INTERNAL_ERROR; /* init to ERR */ + + switch (dat_event_num) { + case DAT_CONNECTION_REQUEST_EVENT: + { + /* + * Requests arriving on a disabled SP are immediatly rejected + */ + + dapl_os_lock(&sp_ptr->header.lock); + if (sp_ptr->listening == DAT_FALSE) { + dapl_os_unlock(&sp_ptr->header.lock); + dapl_dbg_log(DAPL_DBG_TYPE_CM, + "---> dapls_cr_callback: conn event on down SP\n"); + (void)dapls_ib_reject_connection(ib_cm_handle, + DAT_CONNECTION_EVENT_UNREACHABLE, + 0, NULL); + + return; + } + + if (sp_ptr->header.handle_type == DAT_HANDLE_TYPE_RSP) { + /* + * RSP connections only allow a single connection. Close + * it down NOW so we reject any further connections. + */ + sp_ptr->listening = DAT_FALSE; + } + dapl_os_unlock(&sp_ptr->header.lock); + + /* + * Only occurs on the passive side of a connection + * dapli_connection_request will post the connection + * event if appropriate. + */ + dat_status = dapli_connection_request(ib_cm_handle, + sp_ptr, prd_ptr, private_data_size, evd_ptr); + /* Set evd_ptr = NULL so we don't generate an event below */ + evd_ptr = NULL; + + break; + } + case DAT_CONNECTION_EVENT_ESTABLISHED: + { + /* This is just a notification the connection is now + * established, there isn't any private data to deal with. + * + * Update the EP state and cache a copy of the cm handle, + * then let the user know we are ready to go. + */ + dapl_os_lock(&ep_ptr->header.lock); + if (ep_ptr->header.magic != DAPL_MAGIC_EP || + ep_ptr->param.ep_state != + DAT_EP_STATE_COMPLETION_PENDING) { + /* If someone pulled the plug on the EP or connection, + * just exit + */ + dapl_os_unlock(&ep_ptr->header.lock); + dat_status = DAT_SUCCESS; + /* Set evd_ptr = NULL so we don't generate an event below */ + evd_ptr = NULL; + + break; + } + + ep_ptr->param.ep_state = DAT_EP_STATE_CONNECTED; + dapl_os_unlock(&ep_ptr->header.lock); + + break; + } + case DAT_CONNECTION_EVENT_DISCONNECTED: + { + /* + * EP is now fully disconnected; initiate any post processing + * to reset the underlying QP and get the EP ready for + * another connection + */ + dapl_os_lock(&ep_ptr->header.lock); + if (ep_ptr->param.ep_state == DAT_EP_STATE_DISCONNECTED) { + /* The disconnect has already occurred, we are now + * cleaned up and ready to exit + */ + dapl_os_unlock(&ep_ptr->header.lock); + return; + } + ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECTED; + dapls_ib_disconnect_clean(ep_ptr, DAT_FALSE, + ib_cm_event); + dapl_os_unlock(&ep_ptr->header.lock); + + break; + } + case DAT_CONNECTION_EVENT_NON_PEER_REJECTED: + case DAT_CONNECTION_EVENT_PEER_REJECTED: + case DAT_CONNECTION_EVENT_UNREACHABLE: + { + /* + * After posting an accept the requesting node has + * stopped talking. + */ + dapl_os_lock(&ep_ptr->header.lock); + ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECTED; + dapls_ib_disconnect_clean(ep_ptr, DAT_FALSE, + ib_cm_event); + dapl_os_unlock(&ep_ptr->header.lock); + + break; + } + case DAT_CONNECTION_EVENT_BROKEN: + { + dapl_os_lock(&ep_ptr->header.lock); + ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECTED; + dapls_ib_disconnect_clean(ep_ptr, DAT_FALSE, + ib_cm_event); + dapl_os_unlock(&ep_ptr->header.lock); + + break; + } + default: + { + evd_ptr = NULL; + dapl_os_assert(0); /* shouldn't happen */ + break; + } + } + + if (evd_ptr != NULL) { + dat_status = dapls_evd_post_connection_event(evd_ptr, + dat_event_num, + (DAT_HANDLE) + ep_ptr, 0, NULL); + } + + if (dat_status != DAT_SUCCESS) { + /* The event post failed; take appropriate action. */ + (void)dapls_ib_reject_connection(ib_cm_handle, + DAT_CONNECTION_EVENT_BROKEN, + 0, NULL); + + return; + } +} + +/* + * dapli_connection_request + * + * Process a connection request on the Passive side of a connection. + * Create a CR record and link it on to the SP so we can update it + * and free it later. Create an EP if specified by the PSP flags. + * + * Input: + * ib_cm_handle, + * sp_ptr + * event_ptr + * prd_ptr + * + * Output: + * None + * + * Returns + * DAT_INSUFFICIENT_RESOURCES + * DAT_SUCCESS + * + */ +DAT_RETURN +dapli_connection_request(IN dp_ib_cm_handle_t ib_cm_handle, + IN DAPL_SP * sp_ptr, + IN DAPL_PRIVATE * prd_ptr, IN int private_data_size, + IN DAPL_EVD * evd_ptr) +{ + DAT_RETURN dat_status; + + DAPL_CR *cr_ptr; + DAPL_EP *ep_ptr; + DAPL_IA *ia_ptr; + DAT_SP_HANDLE sp_handle; + + cr_ptr = dapls_cr_alloc(sp_ptr->header.owner_ia); + if (cr_ptr == NULL) { + /* Invoking function will call dapls_ib_cm_reject() */ + return DAT_INSUFFICIENT_RESOURCES; + } + + /* + * Set up the CR + */ + cr_ptr->sp_ptr = sp_ptr; /* maintain sp_ptr in case of reject */ + cr_ptr->param.remote_port_qual = 0; + cr_ptr->ib_cm_handle = ib_cm_handle; +#ifdef IBHOSTS_NAMING + /* + * Special case: pull the remote HCA address from the private data + * prefix. This is a spec violation as it introduces a protocol, but + * some implementations may find it necessary for a time. + */ + cr_ptr->remote_ia_address = prd_ptr->hca_address; +#endif /* IBHOSTS_NAMING */ + cr_ptr->param.remote_ia_address_ptr = + (DAT_IA_ADDRESS_PTR) & cr_ptr->remote_ia_address; + /* + * Copy the remote address and private data out of the private_data + * payload and put them in a local structure + */ + + /* Private data size will be determined by the provider layer */ + cr_ptr->param.private_data = cr_ptr->private_data; + cr_ptr->param.private_data_size = private_data_size; + if (cr_ptr->param.private_data_size > 0) { + dapl_os_memcpy(cr_ptr->private_data, + prd_ptr->private_data, + DAPL_MIN(cr_ptr->param.private_data_size, + DAPL_MAX_PRIVATE_DATA_SIZE)); + } + + /* EP will be NULL unless RSP service point */ + ep_ptr = (DAPL_EP *) sp_ptr->ep_handle; + + if (sp_ptr->psp_flags == DAT_PSP_PROVIDER_FLAG) { + /* + * Never true for RSP connections + * + * Create an EP for the user. If we can't allocate an + * EP we are out of resources and need to tell the + * requestor that we cant help them. + */ + ia_ptr = sp_ptr->header.owner_ia; + ep_ptr = dapl_ep_alloc(ia_ptr, NULL); + if (ep_ptr == NULL) { + dapls_cr_free(cr_ptr); + /* Invoking function will call dapls_ib_cm_reject() */ + return DAT_INSUFFICIENT_RESOURCES; + } + ep_ptr->param.ia_handle = ia_ptr; + ep_ptr->param.local_ia_address_ptr = + (DAT_IA_ADDRESS_PTR) & ia_ptr->hca_ptr->hca_address; + + /* Link the EP onto the IA */ + dapl_ia_link_ep(ia_ptr, ep_ptr); + } + + cr_ptr->param.local_ep_handle = ep_ptr; + + if (ep_ptr != NULL) { + /* Assign valid EP fields: RSP and PSP_PROVIDER_FLAG only */ + if (sp_ptr->psp_flags == DAT_PSP_PROVIDER_FLAG) { + ep_ptr->param.ep_state = + DAT_EP_STATE_TENTATIVE_CONNECTION_PENDING; + } else { + /* RSP */ + dapl_os_assert(sp_ptr->header.handle_type == + DAT_HANDLE_TYPE_RSP); + ep_ptr->param.ep_state = + DAT_EP_STATE_PASSIVE_CONNECTION_PENDING; + } + dapl_ep_link_cm(ep_ptr, ib_cm_handle); + } + + /* link the CR onto the SP so we can pick it up later */ + dapl_sp_link_cr(sp_ptr, cr_ptr); + + /* Post the event. */ + /* assign sp_ptr to union to avoid typecast errors from some compilers */ + sp_handle.psp_handle = (DAT_PSP_HANDLE) sp_ptr; + + dat_status = dapls_evd_post_cr_arrival_event(evd_ptr, + DAT_CONNECTION_REQUEST_EVENT, + sp_handle, + (DAT_IA_ADDRESS_PTR) + & sp_ptr->header.owner_ia-> + hca_ptr->hca_address, + sp_ptr->conn_qual, + (DAT_CR_HANDLE) cr_ptr); + + if (dat_status != DAT_SUCCESS) { + dapls_cr_free(cr_ptr); + (void)dapls_ib_reject_connection(ib_cm_handle, + DAT_CONNECTION_EVENT_BROKEN, + 0, NULL); + + /* Take the CR off the list, we can't use it */ + dapl_os_lock(&sp_ptr->header.lock); + dapl_sp_remove_cr(sp_ptr, cr_ptr); + dapl_os_unlock(&sp_ptr->header.lock); + return DAT_INSUFFICIENT_RESOURCES; + } + + return DAT_SUCCESS; +} + +/* + * dapli_get_sp_ep + * + * Passive side of a connection is now fully established. Clean + * up resources and obtain the EP pointer associated with a CR in + * the SP + * + * Input: + * ib_cm_handle, + * sp_ptr + * connection_event + * + * Output: + * none + * + * Returns + * ep_ptr + * + */ +DAPL_EP *dapli_get_sp_ep(IN dp_ib_cm_handle_t ib_cm_handle, + IN DAPL_SP * sp_ptr, IN DAT_EVENT_NUMBER dat_event_num) +{ + DAPL_CR *cr_ptr; + DAPL_EP *ep_ptr; + + /* + * acquire the lock, we may be racing with other threads here + */ + dapl_os_lock(&sp_ptr->header.lock); + + /* Verify under lock that the SP is still valid */ + if (sp_ptr->header.magic == DAPL_MAGIC_INVALID) { + dapl_os_unlock(&sp_ptr->header.lock); + return NULL; + } + /* + * There are potentially multiple connections in progress. Need to + * go through the list and find the one we are interested + * in. There is no guarantee of order. dapl_sp_search_cr + * leaves the CR on the SP queue. + */ + cr_ptr = dapl_sp_search_cr(sp_ptr, ib_cm_handle); + if (cr_ptr == NULL) { + dapl_os_unlock(&sp_ptr->header.lock); + return NULL; + } + + ep_ptr = (DAPL_EP *) cr_ptr->param.local_ep_handle; + + /* Quick check to ensure our EP is still valid */ + if ((DAPL_BAD_HANDLE(ep_ptr, DAPL_MAGIC_EP))) { + ep_ptr = NULL; + } + + /* The CR record is discarded in all except for the CONNECTED case, + * as it will have no further relevance. + */ + if (dat_event_num != DAT_CONNECTION_EVENT_ESTABLISHED) { + /* Remove the CR from the queue */ + dapl_sp_remove_cr(sp_ptr, cr_ptr); + + if (ep_ptr != NULL) { + ep_ptr->cr_ptr = NULL; + } + + /* + * If this SP has been removed from service, free it + * up after the last CR is removed + */ + if (sp_ptr->listening != DAT_TRUE && sp_ptr->cr_list_count == 0 + && sp_ptr->state != DAPL_SP_STATE_FREE) { + dapl_dbg_log(DAPL_DBG_TYPE_CM, + "--> dapli_get_sp_ep! disconnect dump sp: %p \n", + sp_ptr); + /* Decrement the ref count on the EVD */ + if (sp_ptr->evd_handle) { + dapl_os_atomic_dec(& + ((DAPL_EVD *) sp_ptr-> + evd_handle)->evd_ref_count); + sp_ptr->evd_handle = NULL; + } + sp_ptr->state = DAPL_SP_STATE_FREE; + dapl_os_unlock(&sp_ptr->header.lock); + (void)dapls_ib_remove_conn_listener(sp_ptr->header. + owner_ia, sp_ptr); + dapls_ia_unlink_sp((DAPL_IA *) sp_ptr->header.owner_ia, + sp_ptr); + dapls_sp_free_sp(sp_ptr); + dapls_cr_free(cr_ptr); + goto skip_unlock; + } + + dapl_os_unlock(&sp_ptr->header.lock); + /* free memory outside of the lock */ + dapls_cr_free(cr_ptr); + } else { + dapl_os_unlock(&sp_ptr->header.lock); + } + + skip_unlock: + return ep_ptr; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * c-brace-offset: -4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_cr_handoff.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_cr_handoff.c new file mode 100644 index 00000000..fe1b3b59 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_cr_handoff.c @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_cr_handoff.c + * + * PURPOSE: Connection management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 4 + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" + +/* + * dapl_cr_handoff + * + * DAPL Requirements Version xxx, 6.4.2.4 + * + * Hand the connection request to another Sevice pont specified by the + * Connectin Qualifier. + * + * Input: + * cr_handle + * cr_handoff + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + * DAT_INVALID_PARAMETER + */ +DAT_RETURN DAT_API +dapl_cr_handoff(IN DAT_CR_HANDLE cr_handle, IN DAT_CONN_QUAL cr_handoff) +{ /* handoff */ + return DAT_ERROR(DAT_NOT_IMPLEMENTED, 0); +} diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_cr_query.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_cr_query.c new file mode 100644 index 00000000..7332639d --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_cr_query.c @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_cr_query.c + * + * PURPOSE: Connection management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 4 + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_adapter_util.h" + +/* + * dapl_cr_query + * + * DAPL Requirements Version xxx, 6.4.2.1 + * + * Return Connection Request args + * + * Input: + * cr_handle + * cr_param_mask + * + * Output: + * cr_param + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + * DAT_INVALID_HANDLE + */ +DAT_RETURN DAT_API +dapl_cr_query(IN DAT_CR_HANDLE cr_handle, + IN DAT_CR_PARAM_MASK cr_param_mask, OUT DAT_CR_PARAM * cr_param) +{ + DAPL_CR *cr_ptr; + DAT_RETURN dat_status; + + dapl_dbg_log(DAPL_DBG_TYPE_API, + "dapl_cr_query (%p, %x, %p)\n", + cr_handle, cr_param_mask, cr_param); + + dat_status = DAT_SUCCESS; + if (DAPL_BAD_HANDLE(cr_handle, DAPL_MAGIC_CR)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_CR); + goto bail; + } + + if (NULL == cr_param) { + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG3); + goto bail; + } + + cr_ptr = (DAPL_CR *) cr_handle; + + /* obtain the remote IP address */ + if (cr_param_mask & DAT_CR_FIELD_REMOTE_IA_ADDRESS_PTR) { + dat_status = dapls_ib_cm_remote_addr((DAT_HANDLE) cr_handle, + &cr_ptr-> + remote_ia_address); + } + + /* since the arguments are easily accessible, ignore the mask */ + dapl_os_memcpy(cr_param, &cr_ptr->param, sizeof(DAT_CR_PARAM)); + + bail: + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_cr_reject.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_cr_reject.c new file mode 100644 index 00000000..edac95cc --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_cr_reject.c @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_cr_reject.c + * + * PURPOSE: Connection management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 4 + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_cr_util.h" +#include "dapl_sp_util.h" +#include "dapl_adapter_util.h" + +/* + * dapl_cr_reject + * + * DAPL Requirements Version xxx, 6.4.2.2 + * + * Reject a connection request from the active remote side requesting + * an Endpoint. + * + * Input: + * cr_handle + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + */ +DAT_RETURN DAT_API dapl_cr_reject(IN DAT_CR_HANDLE cr_handle, /* cr_handle */ + IN DAT_COUNT pdata_size, /* private_data_size */ + IN const DAT_PVOID pdata) +{ /* private_data */ + DAPL_CR *cr_ptr; + DAPL_EP *ep_ptr; + DAT_EP_STATE entry_ep_state; + DAT_EP_HANDLE entry_ep_handle; + DAPL_SP *sp_ptr; + DAT_RETURN dat_status; + + dapl_dbg_log(DAPL_DBG_TYPE_API, "dapl_cr_reject (%p)\n", cr_handle); + + if (DAPL_BAD_HANDLE(cr_handle, DAPL_MAGIC_CR)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_CR); + goto bail; + } + + cr_ptr = (DAPL_CR *) cr_handle; + + /* + * Clean up provider created EP if there is one: only if + * DAT_PSP_PROVIDER_FLAG was set on the PSP + */ + ep_ptr = (DAPL_EP *) cr_ptr->param.local_ep_handle; + entry_ep_handle = cr_ptr->param.local_ep_handle; + entry_ep_state = 0; + if (ep_ptr != NULL) { + entry_ep_state = ep_ptr->param.ep_state; + ep_ptr->param.ep_state = DAT_EP_STATE_UNCONNECTED; + cr_ptr->param.local_ep_handle = NULL; + } + + dat_status = dapls_ib_reject_connection(cr_ptr->ib_cm_handle, + IB_CM_REJ_REASON_CONSUMER_REJ, + pdata_size, pdata); + + if (dat_status != DAT_SUCCESS) { + if (ep_ptr != NULL) { + /* Revert our state to the beginning */ + ep_ptr->param.ep_state = entry_ep_state; + cr_ptr->param.local_ep_handle = entry_ep_handle; + cr_ptr->param.local_ep_handle = (DAT_EP_HANDLE) ep_ptr; + } + } else { + /* + * If this EP has been allocated by the provider, clean it up; + * see DAT 1.1 spec, page 100, lines 3-4 (section 6.4.3.1.1.1). + * RSP and user-provided EPs are in the control of the user. + */ + sp_ptr = cr_ptr->sp_ptr; + if (ep_ptr != NULL && + sp_ptr->psp_flags == DAT_PSP_PROVIDER_FLAG) { + (void)dapl_ep_free(ep_ptr); + } + + /* Remove the CR from the queue, then free it */ + dapl_os_lock(&sp_ptr->header.lock); + dapl_sp_remove_cr(sp_ptr, cr_ptr); + dapl_os_unlock(&sp_ptr->header.lock); + + dapls_cr_free(cr_ptr); + } + + bail: + return dat_status; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_cr_util.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_cr_util.c new file mode 100644 index 00000000..5970fa0f --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_cr_util.c @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_cr_util.c + * + * PURPOSE: Manage CR (Connection Request) structure + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_cr_util.h" + +/* + * dapls_cr_create + * + * Create a CR. Part of the passive side of a connection + * + * Input: + * ia_ptr + * + * Returns: + * DAPL_CR + * + */ + +DAPL_CR *dapls_cr_alloc(DAPL_IA * ia_ptr) +{ + DAPL_CR *cr_ptr; + + /* Allocate EP */ + cr_ptr = (DAPL_CR *) dapl_os_alloc(sizeof(DAPL_CR)); + if (cr_ptr == NULL) { + return (NULL); + } + + /* zero the structure */ + dapl_os_memzero(cr_ptr, sizeof(DAPL_CR)); + + /* + * initialize the header + */ + cr_ptr->header.provider = ia_ptr->header.provider; + cr_ptr->header.magic = DAPL_MAGIC_CR; + cr_ptr->header.handle_type = DAT_HANDLE_TYPE_CR; + cr_ptr->header.owner_ia = ia_ptr; + cr_ptr->header.user_context.as_64 = 0; + cr_ptr->header.user_context.as_ptr = NULL; + dapl_llist_init_entry(&cr_ptr->header.ia_list_entry); + dapl_os_lock_init(&cr_ptr->header.lock); + + return (cr_ptr); +} + +/* + * dapls_cr_free + * + * Free the passed in CR structure. + * + * Input: + * entry point pointer + * + * Output: + * none + * + * Returns: + * none + * + */ +void dapls_cr_free(IN DAPL_CR * cr_ptr) +{ + dapl_os_assert(cr_ptr->header.magic == DAPL_MAGIC_CR || + cr_ptr->header.magic == DAPL_MAGIC_CR_DESTROYED); + + cr_ptr->header.magic = DAPL_MAGIC_INVALID; /* reset magic to prevent reuse */ + dapl_os_free(cr_ptr, sizeof(DAPL_CR)); +} diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_cr_util.h b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_cr_util.h new file mode 100644 index 00000000..cec980ff --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_cr_util.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dapl_cr_util.h + * + * PURPOSE: Utility defs & routines for the CR data structure + * + * $Id:$ + * + **********************************************************************/ + +#ifndef _DAPL_CR_UTIL_H_ +#define _DAPL_CR_UTIL_H_ + +#include "dapl.h" + +DAPL_CR * +dapls_cr_alloc ( + DAPL_IA *ia_ptr ); + +void +dapls_cr_free ( + IN DAPL_CR *cr_ptr ); + +void +dapls_cr_callback ( + IN dp_ib_cm_handle_t ib_cm_handle, + IN const ib_cm_events_t ib_cm_event, + IN const void *private_data_ptr, + IN const int private_data_size, + IN const void *context); + +#endif /* _DAPL_CR_UTIL_H_ */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_csp.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_csp.c new file mode 100644 index 00000000..ce7c0152 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_csp.c @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2007 Intel Corporation. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_csp.c + * + * PURPOSE: Connection management + * Description: Interfaces in this file are completely described in + * the DAPL 2.0 API, Chapter 6, section 4 + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_sp_util.h" +#include "dapl_ia_util.h" +#include "dapl_adapter_util.h" + +/* + * dapl_psp_create, dapl_csp_query, dapl_csp_free + * + * uDAPL: User Direct Access Program Library Version 2.0, 6.4.4.2 + * + * The Common Service Point is transport-independent analog of the Public + * Service Point. It allows the Consumer to listen on socket-equivalent for + * requests for connections arriving on a specified IP port instead of + * transport-dependent Connection Qualifier. An IA Address follows the + * platform conventions and provides among others the IP port to listen on. + * An IP port of the Common Service Point advertisement is supported by + * existing Ethernet infrastructure or DAT Name Service. + * + * Input: + * ia_handle + * comm_id + * address + * evd_handle + * csp_handle + * + * Output: + * csp_handle + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + * DAT_CONN_QUAL_IN_USE + * DAT_MODEL_NOT_SUPPORTED + */ +DAT_RETURN DAT_API dapl_csp_create(IN DAT_IA_HANDLE ia_handle, /* ia_handle */ + IN DAT_COMM * comm, /* communicator */ + IN DAT_IA_ADDRESS_PTR addr, /* address */ + IN DAT_EVD_HANDLE evd_handle, /* evd_handle */ + OUT DAT_CSP_HANDLE * csp_handle) +{ /* csp_handle */ + return DAT_MODEL_NOT_SUPPORTED; +} + +DAT_RETURN DAT_API dapl_csp_query(IN DAT_CSP_HANDLE csp_handle, /* csp_handle */ + IN DAT_CSP_PARAM_MASK param_mask, /* csp_param_mask */ + OUT DAT_CSP_PARAM * param) +{ /* csp_param */ + return DAT_MODEL_NOT_SUPPORTED; +} + +DAT_RETURN DAT_API dapl_csp_free(IN DAT_CSP_HANDLE csp_handle) +{ /* csp_handle */ + return DAT_MODEL_NOT_SUPPORTED; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * c-brace-offset: -4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_debug.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_debug.c new file mode 100644 index 00000000..904d0752 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_debug.c @@ -0,0 +1,243 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl.h" +#if !defined(__KDAPL__) +#include +#include +#endif /* __KDAPL__ */ + +DAPL_DBG_TYPE g_dapl_dbg_type; /* initialized in dapl_init.c */ +DAPL_DBG_DEST g_dapl_dbg_dest; /* initialized in dapl_init.c */ + +static char *_ptr_host_ = NULL; +static char _hostname_[128]; + +void dapl_internal_dbg_log(DAPL_DBG_TYPE type, const char *fmt, ...) +{ + va_list args; + + if (_ptr_host_ == NULL) { + gethostname(_hostname_, sizeof(_hostname_)); + _ptr_host_ = _hostname_; + } + + if (type & g_dapl_dbg_type) { + if (DAPL_DBG_DEST_STDOUT & g_dapl_dbg_dest) { + va_start(args, fmt); + fprintf(stdout, "%s:%x: ", _ptr_host_, + dapl_os_getpid()); + dapl_os_vprintf(fmt, args); + va_end(args); + } + + if (DAPL_DBG_DEST_SYSLOG & g_dapl_dbg_dest) { + va_start(args, fmt); + dapl_os_syslog(fmt, args); + va_end(args); + } + } +} + +#ifdef DAPL_COUNTERS + +/* + * The order of this list must match the DAT counter definitions + */ +static char *ia_cntr_names[] = { + "DCNT_IA_PZ_CREATE", + "DCNT_IA_PZ_FREE", + "DCNT_IA_LMR_CREATE", + "DCNT_IA_LMR_FREE", + "DCNT_IA_RMR_CREATE", + "DCNT_IA_RMR_FREE", + "DCNT_IA_PSP_CREATE", + "DCNT_IA_PSP_CREATE_ANY", + "DCNT_IA_PSP_FREE", + "DCNT_IA_RSP_CREATE", + "DCNT_IA_RSP_FREE", + "DCNT_IA_EVD_CREATE", + "DCNT_IA_EVD_FREE", + "DCNT_IA_EP_CREATE", + "DCNT_IA_EP_FREE", + "DCNT_IA_SRQ_CREATE", + "DCNT_IA_SRQ_FREE", + "DCNT_IA_SP_CR", + "DCNT_IA_SP_CR_ACCEPTED", + "DCNT_IA_SP_CR_REJECTED", + "DCNT_IA_MEM_ALLOC", + "DCNT_IA_MEM_ALLOC_DATA", + "DCNT_IA_MEM_FREE", + "DCNT_IA_ASYNC_ERROR", + "DCNT_IA_ASYNC_QP_ERROR", + "DCNT_IA_ASYNC_CQ_ERROR" +}; + +static char *ep_cntr_names[] = { + "DCNT_EP_CONNECT", + "DCNT_EP_DISCONNECT", + "DCNT_EP_POST_SEND", + "DCNT_EP_POST_SEND_DATA", + "DCNT_EP_POST_SEND_UD", + "DCNT_EP_POST_SEND_UD_DATA", + "DCNT_EP_POST_RECV", + "DCNT_EP_POST_RECV_DATA", + "DCNT_EP_POST_WRITE", + "DCNT_EP_POST_WRITE_DATA", + "DCNT_EP_POST_WRITE_IMM", + "DCNT_EP_POST_WRITE_IMM_DATA", + "DCNT_EP_POST_READ", + "DCNT_EP_POST_READ_DATA", + "DCNT_EP_POST_CMP_SWAP", + "DCNT_EP_POST_FETCH_ADD", + "DCNT_EP_RECV", + "DCNT_EP_RECV_DATA", + "DCNT_EP_RECV_UD", + "DCNT_EP_RECV_UD_DATA", + "DCNT_EP_RECV_IMM", + "DCNT_EP_RECV_IMM_DATA", + "DCNT_EP_RECV_RDMA_IMM", + "DCNT_EP_RECV_RDMA_IMM_DATA", +}; + +static char *evd_cntr_names[] = { + "DCNT_EVD_WAIT", + "DCNT_EVD_WAIT_BLOCKED", + "DCNT_EVD_WAIT_NOTIFY", + "DCNT_EVD_DEQUEUE", + "DCNT_EVD_DEQUEUE_FOUND", + "DCNT_EVD_DEQUEUE_NOT_FOUND", + "DCNT_EVD_DEQUEUE_POLL", + "DCNT_EVD_DEQUEUE_POLL_FOUND", + "DCNT_EVD_CONN_CALLBACK", + "DCNT_EVD_DTO_CALLBACK", +}; + +DAT_RETURN dapl_query_counter(DAT_HANDLE dh, + int counter, void *p_cntrs_out, int reset) +{ + int i, max; + DAT_UINT64 *p_cntrs; + DAT_HANDLE_TYPE type = 0; + + dat_get_handle_type(dh, &type); + + switch (type) { + case DAT_HANDLE_TYPE_IA: + max = DCNT_IA_ALL_COUNTERS; + p_cntrs = ((DAPL_IA *) dh)->cntrs; + break; + case DAT_HANDLE_TYPE_EP: + max = DCNT_EP_ALL_COUNTERS; + p_cntrs = ((DAPL_EP *) dh)->cntrs; + break; + case DAT_HANDLE_TYPE_EVD: + max = DCNT_EVD_ALL_COUNTERS; + p_cntrs = ((DAPL_EVD *) dh)->cntrs; + break; + default: + return DAT_INVALID_HANDLE; + } + + for (i = 0; i < max; i++) { + if ((counter == i) || (counter == max)) { + ((DAT_UINT64 *) p_cntrs_out)[i] = p_cntrs[i]; + if (reset) + p_cntrs[i] = 0; + } + } + return DAT_SUCCESS; +} + +char *dapl_query_counter_name(DAT_HANDLE dh, int counter) +{ + DAT_HANDLE_TYPE type = 0; + + dat_get_handle_type(dh, &type); + + switch (type) { + case DAT_HANDLE_TYPE_IA: + if (counter < DCNT_IA_ALL_COUNTERS) + return ia_cntr_names[counter]; + break; + case DAT_HANDLE_TYPE_EP: + if (counter < DCNT_EP_ALL_COUNTERS) + return ep_cntr_names[counter]; + break; + case DAT_HANDLE_TYPE_EVD: + if (counter < DCNT_EVD_ALL_COUNTERS) + return evd_cntr_names[counter]; + break; + default: + return NULL; + } + return NULL; +} + +void dapl_print_counter(DAT_HANDLE dh, int counter, int reset) +{ + int i, max; + DAT_UINT64 *p_cntrs; + DAT_HANDLE_TYPE type = 0; + + dat_get_handle_type(dh, &type); + + switch (type) { + case DAT_HANDLE_TYPE_IA: + max = DCNT_IA_ALL_COUNTERS; + p_cntrs = ((DAPL_IA *) dh)->cntrs; + break; + case DAT_HANDLE_TYPE_EP: + max = DCNT_EP_ALL_COUNTERS; + p_cntrs = ((DAPL_EP *) dh)->cntrs; + break; + case DAT_HANDLE_TYPE_EVD: + max = DCNT_EVD_ALL_COUNTERS; + p_cntrs = ((DAPL_EVD *) dh)->cntrs; + break; + default: + return; + } + + for (i = 0; i < max; i++) { + if ((counter == i) || (counter == max)) { + printf(" %s = " F64u " \n", + dapl_query_counter_name(dh, i), p_cntrs[i]); + if (reset) + p_cntrs[i] = 0; + } + } + + /* Print in process CR's for this IA, if debug type set */ + if ((type == DAT_HANDLE_TYPE_IA) && + (g_dapl_dbg_type & DAPL_DBG_TYPE_CM_LIST)) { + dapls_print_cm_list((DAPL_IA*)dh); + } + return; +} + +#endif /* DAPL_COUNTERS */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_connect.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_connect.c new file mode 100644 index 00000000..0719c03b --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_connect.c @@ -0,0 +1,408 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ep_connect.c + * + * PURPOSE: Endpoint management + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_ep_util.h" +#include "dapl_adapter_util.h" +#include "dapl_evd_util.h" +#include "dapl_timer_util.h" + +/* + * dapl_ep_connect + * + * Request a connection be established between the local Endpoint + * and a remote Endpoint. This operation is used by the active/client + * side of a connection + * + * Input: + * ep_handle + * remote_ia_address + * remote_conn_qual + * timeout + * private_data_size + * privaet_data + * qos + * connect_flags + * + * Output: + * None + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOUCRES + * DAT_INVALID_PARAMETER + * DAT_MODLE_NOT_SUPPORTED + */ +DAT_RETURN DAT_API +dapl_ep_connect(IN DAT_EP_HANDLE ep_handle, + IN DAT_IA_ADDRESS_PTR remote_ia_address, + IN DAT_CONN_QUAL remote_conn_qual, + IN DAT_TIMEOUT timeout, + IN DAT_COUNT private_data_size, + IN const DAT_PVOID private_data, + IN DAT_QOS qos, IN DAT_CONNECT_FLAGS connect_flags) +{ + DAPL_EP *ep_ptr; + DAPL_EP alloc_ep; + DAT_RETURN dat_status; + DAT_COUNT req_hdr_size; + void *private_data_ptr; + + dapl_dbg_log(DAPL_DBG_TYPE_API | DAPL_DBG_TYPE_CM, + "dapl_ep_connect (%p, {%u.%u.%u.%u}, %X, %d, %d, %p, %x, %x)\n", + ep_handle, + remote_ia_address->sa_data[2], + remote_ia_address->sa_data[3], + remote_ia_address->sa_data[4], + remote_ia_address->sa_data[5], + remote_conn_qual, + timeout, + private_data_size, private_data, qos, connect_flags); + + dat_status = DAT_SUCCESS; + ep_ptr = (DAPL_EP *) ep_handle; + + /* + * Verify parameter & state. The connection handle must be good + * at this point. + */ + if (DAPL_BAD_HANDLE(ep_ptr, DAPL_MAGIC_EP)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP); + goto bail; + } + + if (DAPL_BAD_HANDLE(ep_ptr->param.connect_evd_handle, DAPL_MAGIC_EVD)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EVD_CONN); + goto bail; + } + + /* Can't do a connection in 0 time, reject outright */ + if (timeout == 0) { + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG4); + goto bail; + } + DAPL_CNTR(ep_ptr, DCNT_EP_CONNECT); + + /* + * If the endpoint needs a QP, associated the QP with it. + * This needs to be done carefully, in order to: + * * Avoid allocating under a lock. + * * Not step on data structures being altered by + * routines with which we are racing. + * So we: + * * Confirm that a new QP is needed and is not forbidden by the + * current state. + * * Allocate it into a separate EP. + * * Take the EP lock. + * * Reconfirm that the EP is in a state where it needs a QP. + * * Assign the QP and release the lock. + */ + if (ep_ptr->qp_state == DAPL_QP_STATE_UNATTACHED) { + if (ep_ptr->param.pz_handle == NULL + || DAPL_BAD_HANDLE(ep_ptr->param.pz_handle, DAPL_MAGIC_PZ)) + { + dat_status = + DAT_ERROR(DAT_INVALID_STATE, + DAT_INVALID_STATE_EP_NOTREADY); + goto bail; + } + alloc_ep = *ep_ptr; + + dat_status = dapls_ib_qp_alloc(ep_ptr->header.owner_ia, + &alloc_ep, ep_ptr); + if (dat_status != DAT_SUCCESS) { + dat_status = + DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, + DAT_RESOURCE_MEMORY); + goto bail; + } + + dapl_os_lock(&ep_ptr->header.lock); + /* + * PZ shouldn't have changed since we're only racing with + * dapl_cr_accept() + */ + if (ep_ptr->qp_state != DAPL_QP_STATE_UNATTACHED) { + /* Bail, cleaning up. */ + dapl_os_unlock(&ep_ptr->header.lock); + dat_status = dapls_ib_qp_free(ep_ptr->header.owner_ia, + &alloc_ep); + if (dat_status != DAT_SUCCESS) { + dapl_dbg_log(DAPL_DBG_TYPE_WARN, + "ep_connect: ib_qp_free failed with %x\n", + dat_status); + } + dat_status = + DAT_ERROR(DAT_INVALID_STATE, + dapls_ep_state_subtype(ep_ptr)); + goto bail; + } + + ep_ptr->qp_handle = alloc_ep.qp_handle; + ep_ptr->qpn = alloc_ep.qpn; + ep_ptr->qp_state = alloc_ep.qp_state; + + dapl_os_unlock(&ep_ptr->header.lock); + } + + /* + * We do state checks and transitions under lock. + * The only code we're racing against is dapl_cr_accept. + */ + dapl_os_lock(&ep_ptr->header.lock); + + /* + * Verify the attributes of the EP handle before we connect it. Test + * all of the handles to make sure they are currently valid. + * Specifically: + * pz_handle required + * recv_evd_handle optional, but must be valid + * request_evd_handle optional, but must be valid + * connect_evd_handle required + */ + if (ep_ptr->param.pz_handle == NULL + || DAPL_BAD_HANDLE(ep_ptr->param.pz_handle, DAPL_MAGIC_PZ) + /* test connect handle */ + || ep_ptr->param.connect_evd_handle == NULL + || DAPL_BAD_HANDLE(ep_ptr->param.connect_evd_handle, DAPL_MAGIC_EVD) + || !(((DAPL_EVD *) ep_ptr->param.connect_evd_handle)-> + evd_flags & DAT_EVD_CONNECTION_FLAG) + /* test optional completion handles */ + || (ep_ptr->param.recv_evd_handle != DAT_HANDLE_NULL && + (DAPL_BAD_HANDLE + (ep_ptr->param.recv_evd_handle, DAPL_MAGIC_EVD))) + || (ep_ptr->param.request_evd_handle != DAT_HANDLE_NULL + && + (DAPL_BAD_HANDLE + (ep_ptr->param.request_evd_handle, DAPL_MAGIC_EVD)))) { + dapl_os_unlock(&ep_ptr->header.lock); + dat_status = + DAT_ERROR(DAT_INVALID_STATE, DAT_INVALID_STATE_EP_NOTREADY); + goto bail; + } + + /* Check both the EP state and the QP state: if we don't have a QP + * we need to attach one now. + */ + if (ep_ptr->qp_state == DAPL_QP_STATE_UNATTACHED) { + dat_status = dapls_ib_qp_alloc(ep_ptr->header.owner_ia, + ep_ptr, ep_ptr); + + if (dat_status != DAT_SUCCESS) { + dapl_os_unlock(&ep_ptr->header.lock); + dat_status = + DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, + DAT_RESOURCE_TEP); + goto bail; + } + } + + if (ep_ptr->param.ep_state != DAT_EP_STATE_UNCONNECTED && + ep_ptr->param.ep_attr.service_type == DAT_SERVICE_TYPE_RC) { + dapl_os_unlock(&ep_ptr->header.lock); + dat_status = + DAT_ERROR(DAT_INVALID_STATE, + dapls_ep_state_subtype(ep_ptr)); + goto bail; + } + + if (qos != DAT_QOS_BEST_EFFORT || + connect_flags != DAT_CONNECT_DEFAULT_FLAG) { + /* + * At this point we only support one QOS level + */ + dapl_os_unlock(&ep_ptr->header.lock); + dat_status = DAT_ERROR(DAT_MODEL_NOT_SUPPORTED, 0); + goto bail; + } + + /* + * Verify the private data size doesn't exceed the max + * req_hdr_size will evaluate to 0 unless IBHOSTS_NAMING is enabled. + */ + req_hdr_size = (sizeof(DAPL_PRIVATE) - DAPL_MAX_PRIVATE_DATA_SIZE); + + /* transition the state before requesting a connection to avoid + * race conditions + */ + ep_ptr->param.ep_state = DAT_EP_STATE_ACTIVE_CONNECTION_PENDING; + + /* + * At this point we're committed, and done with the endpoint + * except for the connect, so we can drop the lock. + */ + dapl_os_unlock(&ep_ptr->header.lock); + +#ifdef IBHOSTS_NAMING + /* + * Special case: put the remote HCA address into the private data + * prefix. This is a spec violation as it introduces a protocol, but + * some implementations may find it necessary for a time. + * Copy the private data into the EP area so the data is contiguous. + * If the provider needs to pad the buffer with NULLs, it happens at + * the provider layer. + */ + dapl_os_memcpy(&ep_ptr->hca_address, + &ep_ptr->header.owner_ia->hca_ptr->hca_address, + sizeof(DAT_SOCK_ADDR)); + dapl_os_memcpy(ep_ptr->private.private_data, private_data, + private_data_size); + private_data_ptr = (void *)&ep_ptr->private.private_data; +#else + private_data_ptr = private_data; +#endif /* IBHOSTS_NAMING */ + + /* Copy the connection qualifiers */ + dapl_os_memcpy(ep_ptr->param.remote_ia_address_ptr, + remote_ia_address, sizeof(DAT_SOCK_ADDR)); + ep_ptr->param.remote_port_qual = remote_conn_qual; + + dat_status = dapls_ib_connect(ep_handle, + remote_ia_address, + remote_conn_qual, + private_data_size + req_hdr_size, + private_data_ptr); + + if (dat_status != DAT_SUCCESS) { + ep_ptr->param.ep_state = DAT_EP_STATE_UNCONNECTED; + + /* + * Some implementations provide us with an error code that the + * remote destination is unreachable, but DAT doesn't have a + * synchronous error code to communicate this. So the provider + * layer generates an INTERNAL_ERROR with a subtype; when + * this happens, return SUCCESS and generate the event + */ + if (dat_status == DAT_ERROR(DAT_INTERNAL_ERROR, 1)) { + dapls_evd_post_connection_event((DAPL_EVD *) ep_ptr-> + param. + connect_evd_handle, + DAT_CONNECTION_EVENT_UNREACHABLE, + (DAT_HANDLE) ep_ptr, 0, + 0); + dat_status = DAT_SUCCESS; + } + } else { + /* + * Acquire the lock and recheck the state of the EP; this + * thread could have been descheduled after issuing the connect + * request and the EP is now connected. Set up a timer if + * necessary. + */ + dapl_os_lock(&ep_ptr->header.lock); + if (ep_ptr->param.ep_state == + DAT_EP_STATE_ACTIVE_CONNECTION_PENDING + && timeout != DAT_TIMEOUT_INFINITE && + ep_ptr->param.ep_attr.service_type == DAT_SERVICE_TYPE_RC) { + ep_ptr->cxn_timer = + (DAPL_OS_TIMER *) + dapl_os_alloc(sizeof(DAPL_OS_TIMER)); + + dapls_timer_set(ep_ptr->cxn_timer, + dapls_ep_timeout, ep_ptr, timeout); + + dapl_log(DAPL_DBG_TYPE_EP, " dapl_ep_connect timeout = %d us\n", timeout); + } + dapl_os_unlock(&ep_ptr->header.lock); + } + + bail: + dapl_dbg_log(DAPL_DBG_TYPE_RTN | DAPL_DBG_TYPE_CM, + "dapl_ep_connect () returns 0x%x\n", dat_status); + + return dat_status; +} + +/* + * dapl_ep_common_connect + * + * DAPL Requirements Version 2.0, 6.6.x + * + * Requests that a connection be established + * between the local Endpoint and a remote Endpoint specified by the + * remote_ia_address. This operation is used by the active/client side + * Consumer of the Connection establishment model. + * + * EP must be properly configured for this operation. The EP Communicator + * must be specified. As part of the successful completion of this operation, + * the local Endpoint is bound to a local IA Address if it had these assigned + * before. + * + * The local IP Address, port and protocol are passed to the remote side of + * the requested connection and is available to the remote Consumer in the + * Connection Request of the DAT_CONNECTION_REQUEST_EVENT. + * + * The Consumer-provided private_data is passed to the remote side and is + * provided to the remote Consumer in the Connection Request. Consumers + * can encapsulate any local Endpoint attributes that remote Consumers + * need to know as part of an upper-level protocol. + * + * Input: + * ep_handle + * remote_ia_address + * timeout + * private_data_size + * private_date pointer + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + * DAT_INVALID_HANDLE + * DAT_INVALID_STATE + * DAT_MODEL_NOT_SUPPORTED + */ +DAT_RETURN DAT_API dapl_ep_common_connect(IN DAT_EP_HANDLE ep, /* ep_handle */ + IN DAT_IA_ADDRESS_PTR remote_addr, /* remote_ia_address */ + IN DAT_TIMEOUT timeout, /* timeout */ + IN DAT_COUNT pdata_size, /* private_data_size */ + IN const DAT_PVOID pdata) +{ /* private_data */ + return DAT_MODEL_NOT_SUPPORTED; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_create.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_create.c new file mode 100644 index 00000000..e154b8de --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_create.c @@ -0,0 +1,335 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ep_create.c + * + * PURPOSE: Endpoint management + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_ia_util.h" +#include "dapl_ep_util.h" +#include "dapl_adapter_util.h" + +/* + * dapl_ep_create + * + * Create an instance of an Endpoint that is provided to the + * consumer at ep_handle. + * + * Input: + * ia_handle + * pz_handle + * recv_evd_handle (recv DTOs) + * request_evd_handle (xmit DTOs) + * connect_evd_handle + * ep_attrs + * + * Output: + * ep_handle + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + * DAT_INVALID_ATTRIBUTE + * DAT_MODEL_NOT_SUPPORTED + */ +DAT_RETURN DAT_API +dapl_ep_create(IN DAT_IA_HANDLE ia_handle, + IN DAT_PZ_HANDLE pz_handle, + IN DAT_EVD_HANDLE recv_evd_handle, + IN DAT_EVD_HANDLE request_evd_handle, + IN DAT_EVD_HANDLE connect_evd_handle, + IN const DAT_EP_ATTR * ep_attr, OUT DAT_EP_HANDLE * ep_handle) +{ + DAPL_IA *ia_ptr; + DAPL_EP *ep_ptr; + DAT_EP_ATTR ep_attr_limit; + DAPL_EVD *evd_ptr; + DAT_RETURN dat_status; + + dapl_dbg_log(DAPL_DBG_TYPE_API, + "dapl_ep_create (%p, %p, %p, %p, %p, %p, %p)\n", + ia_handle, + pz_handle, + recv_evd_handle, + request_evd_handle, + connect_evd_handle, ep_attr, ep_handle); + + ia_ptr = (DAPL_IA *) ia_handle; + dat_status = DAT_SUCCESS; + + /* + * Verify parameters + */ + if (DAPL_BAD_HANDLE(ia_ptr, DAPL_MAGIC_IA)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_IA); + goto bail; + } + DAPL_CNTR(ia_ptr, DCNT_IA_EP_CREATE); + + /* + * Verify non-required parameters. + * N.B. Assumption: any parameter that can be + * modified by dat_ep_modify() is not strictly + * required when the EP is created + */ + if (pz_handle != DAT_HANDLE_NULL && + DAPL_BAD_HANDLE(pz_handle, DAPL_MAGIC_PZ)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_PZ); + goto bail; + } + + /* If connect handle is !NULL verify handle is good */ + if (connect_evd_handle != DAT_HANDLE_NULL && + (DAPL_BAD_HANDLE(connect_evd_handle, DAPL_MAGIC_EVD) || + !(((DAPL_EVD *) connect_evd_handle)-> + evd_flags & DAT_EVD_CONNECTION_FLAG))) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EVD_CONN); + goto bail; + } + + /* If recv_evd is !NULL, verify handle is good and flags are valid */ + if (recv_evd_handle != DAT_HANDLE_NULL && + (DAPL_BAD_HANDLE(recv_evd_handle, DAPL_MAGIC_EVD) || + !(((DAPL_EVD *) recv_evd_handle)->evd_flags & DAT_EVD_DTO_FLAG))) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EVD_RECV); + goto bail; + } + + /* If req_evd is !NULL, verify handle is good and flags are valid */ + if (request_evd_handle != DAT_HANDLE_NULL && + (DAPL_BAD_HANDLE(request_evd_handle, DAPL_MAGIC_EVD) || + !(((DAPL_EVD *) request_evd_handle)-> + evd_flags & DAT_EVD_DTO_FLAG))) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, + DAT_INVALID_HANDLE_EVD_REQUEST); + goto bail; + } + + if (ep_handle == NULL) { + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG7); + goto bail; + } + if (DAPL_BAD_PTR(ep_attr)) { + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG6); + goto bail; + } + + /* + * Qualify EP Attributes are legal and make sense. Note that if one + * or both of the DTO handles are NULL, then the corresponding + * max_*_dtos must 0 as the user will not be able to post dto ops on + * the respective queue. + */ + if (ep_attr != NULL && ( +#ifndef DAT_EXTENSIONS + ep_attr->service_type != + DAT_SERVICE_TYPE_RC || +#endif + (recv_evd_handle == DAT_HANDLE_NULL + && ep_attr->max_recv_dtos != 0) + || (recv_evd_handle != DAT_HANDLE_NULL + && ep_attr->max_recv_dtos == 0) + || (request_evd_handle == DAT_HANDLE_NULL + && ep_attr->max_request_dtos != 0) + || (request_evd_handle != DAT_HANDLE_NULL + && ep_attr->max_request_dtos == 0) + || (recv_evd_handle != DAT_HANDLE_NULL + && ep_attr->max_recv_iov == 0) + || ep_attr->max_request_iov == 0 + || (DAT_SUCCESS != + dapl_ep_check_recv_completion_flags + (ep_attr->recv_completion_flags)))) { + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG6); + goto bail; + } + + /* Verify the attributes against the transport */ + if (ep_attr != NULL) { + dapl_os_memzero(&ep_attr_limit, sizeof(DAT_EP_ATTR)); + dat_status = dapls_ib_query_hca(ia_ptr->hca_ptr, + NULL, &ep_attr_limit, NULL); + if (dat_status != DAT_SUCCESS) { + goto bail; + } + if (ep_attr->max_mtu_size > ep_attr_limit.max_mtu_size || + ep_attr->max_rdma_size > ep_attr_limit.max_rdma_size || + ep_attr->max_recv_dtos > ep_attr_limit.max_recv_dtos || + ep_attr->max_request_dtos > ep_attr_limit.max_request_dtos + || ep_attr->max_recv_iov > ep_attr_limit.max_recv_iov + || ep_attr->max_request_iov > ep_attr_limit.max_request_iov + || ep_attr->max_rdma_read_in > + ep_attr_limit.max_rdma_read_in + || ep_attr->max_rdma_read_out > + ep_attr_limit.max_rdma_read_out) + { + dat_status = DAT_INVALID_PARAMETER | DAT_INVALID_ARG6; + goto bail; + } + } + + /* + * Verify the completion flags for the EVD and the EP + */ + /* + * XXX FIXME + * XXX Need to make assign the EVD to the right completion type + * XXX depending on the EP attributes. Fail if the types don't + * XXX match, they are mutually exclusive. + */ + evd_ptr = (DAPL_EVD *) recv_evd_handle; + if (evd_ptr != NULL && evd_ptr->completion_type == DAPL_EVD_STATE_INIT) { + if (ep_attr != NULL && + ep_attr->recv_completion_flags == + DAT_COMPLETION_DEFAULT_FLAG) { + evd_ptr->completion_type = DAPL_EVD_STATE_THRESHOLD; + } else { + evd_ptr->completion_type = + ep_attr->recv_completion_flags; + } + } + + evd_ptr = (DAPL_EVD *) request_evd_handle; + if (evd_ptr != NULL && evd_ptr->completion_type == DAPL_EVD_STATE_INIT) { + if (ep_attr != NULL && + ep_attr->recv_completion_flags == + DAT_COMPLETION_DEFAULT_FLAG) { + evd_ptr->completion_type = DAPL_EVD_STATE_THRESHOLD; + } else { + evd_ptr->completion_type = + ep_attr->recv_completion_flags; + } + } + + /* Allocate EP */ + ep_ptr = dapl_ep_alloc(ia_ptr, ep_attr); + if (ep_ptr == NULL) { + dat_status = + DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); + goto bail; + } + + /* + * Fill in the EP + */ + ep_ptr->param.ia_handle = ia_handle; + ep_ptr->param.ep_state = DAT_EP_STATE_UNCONNECTED; + ep_ptr->param.local_ia_address_ptr = + (DAT_IA_ADDRESS_PTR) & ia_ptr->hca_ptr->hca_address; + /* Set the remote address pointer to the end of the EP struct */ + ep_ptr->param.remote_ia_address_ptr = (DAT_IA_ADDRESS_PTR) (ep_ptr + 1); + + ep_ptr->param.pz_handle = pz_handle; + ep_ptr->param.recv_evd_handle = recv_evd_handle; + ep_ptr->param.request_evd_handle = request_evd_handle; + ep_ptr->param.connect_evd_handle = connect_evd_handle; + + /* + * Make sure we handle the NULL DTO EVDs + */ + if (recv_evd_handle == DAT_HANDLE_NULL && ep_attr == NULL) { + ep_ptr->param.ep_attr.max_recv_dtos = 0; + } + + if (request_evd_handle == DAT_HANDLE_NULL && ep_attr == NULL) { + ep_ptr->param.ep_attr.max_request_dtos = 0; + } + + /* + * If the user has specified a PZ handle we allocate a QP for + * this EP; else we defer until it is assigned via ep_modify(). + * As much as possible we try to keep QP creation out of the + * connect path to avoid resource errors in strange places. + */ + if (pz_handle != DAT_HANDLE_NULL) { + /* Take a reference on the PZ handle */ + dapl_os_atomic_inc(&((DAPL_PZ *) pz_handle)->pz_ref_count); + + /* + * Get a QP from the IB provider + */ + dat_status = dapls_ib_qp_alloc(ia_ptr, ep_ptr, ep_ptr); + + if (dat_status != DAT_SUCCESS) { + dapl_os_atomic_dec(&((DAPL_PZ *) pz_handle)-> + pz_ref_count); + dapl_ep_dealloc(ep_ptr); + goto bail; + } + } else { + ep_ptr->qp_state = DAPL_QP_STATE_UNATTACHED; + } + + /* + * Update ref counts. See the spec where the endpoint marks + * a data object as 'in use' + * pz_handle: dat_pz_free, uDAPL Document, 6.6.1.2 + * evd_handles: + * + * N.B. This should really be done by a util routine. + */ + if (connect_evd_handle != DAT_HANDLE_NULL) { + dapl_os_atomic_inc(&((DAPL_EVD *) connect_evd_handle)-> + evd_ref_count); + } + /* Optional handles */ + if (recv_evd_handle != DAT_HANDLE_NULL) { + dapl_os_atomic_inc(&((DAPL_EVD *) recv_evd_handle)-> + evd_ref_count); + } + if (request_evd_handle != DAT_HANDLE_NULL) { + dapl_os_atomic_inc(&((DAPL_EVD *) request_evd_handle)-> + evd_ref_count); + } + + /* Link it onto the IA */ + dapl_ia_link_ep(ia_ptr, ep_ptr); + + *ep_handle = ep_ptr; + + bail: + return dat_status; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_create_with_srq.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_create_with_srq.c new file mode 100644 index 00000000..b85abfd1 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_create_with_srq.c @@ -0,0 +1,355 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ep_create_with_srq.c + * + * PURPOSE: Endpoint management + * Description: Interfaces in this file are completely described in + * the kDAPL 1.2 API, Chapter 6, section 6.5 + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_ia_util.h" +#include "dapl_ep_util.h" +#include "dapl_adapter_util.h" + +/* + * dapl_ep_create_with_srq + * + * uDAPL Version 1.2, 6.6.5 + * + * Create an instance of an Endpoint that is provided to the + * consumer at ep_handle. + * + * Input: + * ia_handle + * pz_handle + * recv_evd_handle (recv DTOs) + * request_evd_handle (xmit DTOs) + * connect_evd_handle + * srq_handle + * ep_attrs + * + * Output: + * ep_handle + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_HANDLE + * DAT_INVALID_PARAMETER + * DAT_INVALID_ATTRIBUTE + * DAT_MODEL_NOT_SUPPORTED + */ +DAT_RETURN DAT_API +dapl_ep_create_with_srq(IN DAT_IA_HANDLE ia_handle, + IN DAT_PZ_HANDLE pz_handle, + IN DAT_EVD_HANDLE recv_evd_handle, + IN DAT_EVD_HANDLE request_evd_handle, + IN DAT_EVD_HANDLE connect_evd_handle, + IN DAT_SRQ_HANDLE srq_handle, + IN const DAT_EP_ATTR * ep_attr, + OUT DAT_EP_HANDLE * ep_handle) +{ + DAPL_IA *ia_ptr; + DAPL_EP *ep_ptr; + DAT_EP_ATTR ep_attr_limit; + DAPL_EVD *evd_ptr; + DAT_RETURN dat_status; + + dat_status = DAT_SUCCESS; + dapl_dbg_log(DAPL_DBG_TYPE_API, + "dapl_ep_create_with_srq (%p, %p, %p, %p, %p, %p, %p %p)\n", + ia_handle, + pz_handle, + recv_evd_handle, + request_evd_handle, + connect_evd_handle, srq_handle, ep_attr, ep_handle); + + ia_ptr = (DAPL_IA *) ia_handle; + + /* + * Verify parameters + */ + if (DAPL_BAD_HANDLE(ia_ptr, DAPL_MAGIC_IA)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_IA); + goto bail; + } + + /* + * Verify non-required parameters. + * N.B. Assumption: any parameter that can be + * modified by dat_ep_modify() is not strictly + * required when the EP is created + */ + if (pz_handle != NULL && DAPL_BAD_HANDLE(pz_handle, DAPL_MAGIC_PZ)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_PZ); + goto bail; + } + + /* If connect handle is !NULL verify handle is good */ + if (connect_evd_handle != DAT_HANDLE_NULL && + (DAPL_BAD_HANDLE(connect_evd_handle, DAPL_MAGIC_EVD) || + !(((DAPL_EVD *) connect_evd_handle)-> + evd_flags & DAT_EVD_CONNECTION_FLAG))) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EVD_CONN); + goto bail; + } + /* If recv_evd is !NULL, verify handle is good and flags are valid */ + if (recv_evd_handle != DAT_HANDLE_NULL && + (DAPL_BAD_HANDLE(recv_evd_handle, DAPL_MAGIC_EVD) || + !(((DAPL_EVD *) recv_evd_handle)->evd_flags & DAT_EVD_DTO_FLAG))) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EVD_RECV); + goto bail; + } + + /* If req_evd is !NULL, verify handle is good and flags are valid */ + if (request_evd_handle != DAT_HANDLE_NULL && + (DAPL_BAD_HANDLE(request_evd_handle, DAPL_MAGIC_EVD) || + !(((DAPL_EVD *) request_evd_handle)-> + evd_flags & DAT_EVD_DTO_FLAG))) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, + DAT_INVALID_HANDLE_EVD_REQUEST); + goto bail; + } + + /* + * Verify the SRQ handle. It is an error to invoke this call with + * a NULL handle + */ + if (DAPL_BAD_HANDLE(srq_handle, DAPL_MAGIC_SRQ)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_SRQ); + goto bail; + } + + if (ep_handle == NULL) { + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG7); + goto bail; + } + + if (DAPL_BAD_PTR(ep_attr)) { + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG6); + goto bail; + } + + /* + * Qualify EP Attributes are legal and make sense. Note that if one + * or both of the DTO handles are NULL, then the corresponding + * max_*_dtos must 0 as the user will not be able to post dto ops on + * the respective queue. + */ + if (ep_attr != NULL && + (ep_attr->service_type != DAT_SERVICE_TYPE_RC || + (recv_evd_handle == DAT_HANDLE_NULL && ep_attr->max_recv_dtos != 0) + || (recv_evd_handle != DAT_HANDLE_NULL + && ep_attr->max_recv_dtos == 0) + || (request_evd_handle == DAT_HANDLE_NULL + && ep_attr->max_request_dtos != 0) + || (request_evd_handle != DAT_HANDLE_NULL + && ep_attr->max_request_dtos == 0) + || ep_attr->max_recv_iov == 0 || ep_attr->max_request_iov == 0 + || (DAT_SUCCESS != + dapl_ep_check_recv_completion_flags(ep_attr-> + recv_completion_flags)))) { + dat_status = DAT_INVALID_PARAMETER | DAT_INVALID_ARG6; + goto bail; + } + + /* Verify the attributes against the transport */ + if (ep_attr != NULL) { + dapl_os_memzero(&ep_attr_limit, sizeof(DAT_EP_ATTR)); + dat_status = dapls_ib_query_hca(ia_ptr->hca_ptr, + NULL, &ep_attr_limit, NULL); + if (dat_status != DAT_SUCCESS) { + goto bail; + } + if (ep_attr->max_mtu_size > ep_attr_limit.max_mtu_size || + ep_attr->max_rdma_size > ep_attr_limit.max_rdma_size || + ep_attr->max_recv_dtos > ep_attr_limit.max_recv_dtos || + ep_attr->max_request_dtos > ep_attr_limit.max_request_dtos + || ep_attr->max_recv_iov > ep_attr_limit.max_recv_iov + || ep_attr->max_request_iov > ep_attr_limit.max_request_iov + || ep_attr->max_rdma_read_in > + ep_attr_limit.max_rdma_read_in + || ep_attr->max_rdma_read_out > + ep_attr_limit.max_rdma_read_out) + { + dat_status = DAT_INVALID_PARAMETER | DAT_INVALID_ARG6; + goto bail; + } + } + + /* + * Verify the completion flags for the EVD and the EP + */ + /* + * XXX FIXME + * XXX Need to make assign the EVD to the right completion type + * XXX depending on the EP attributes. Fail if the types don't + * XXX match, they are mutually exclusive. + */ + evd_ptr = (DAPL_EVD *) recv_evd_handle; + if (evd_ptr != NULL && evd_ptr->completion_type == DAPL_EVD_STATE_INIT) { + if (ep_attr != NULL && + ep_attr->recv_completion_flags == + DAT_COMPLETION_DEFAULT_FLAG) { + evd_ptr->completion_type = DAPL_EVD_STATE_THRESHOLD; + } else { + evd_ptr->completion_type = + ep_attr->recv_completion_flags; + } + } + + evd_ptr = (DAPL_EVD *) request_evd_handle; + if (evd_ptr != NULL && evd_ptr->completion_type == DAPL_EVD_STATE_INIT) { + if (ep_attr != NULL && + ep_attr->recv_completion_flags == + DAT_COMPLETION_DEFAULT_FLAG) { + evd_ptr->completion_type = DAPL_EVD_STATE_THRESHOLD; + } else { + evd_ptr->completion_type = + ep_attr->recv_completion_flags; + } + } + + dat_status = DAT_NOT_IMPLEMENTED; + + /* + * XXX The rest of the EP code is useful in this case too, + * XXX but need to complete the SRQ implementation before + * XXX committing resources + */ + *ep_handle = ep_ptr = NULL; + goto bail; +#ifdef notdef + + /* Allocate EP */ + ep_ptr = dapl_ep_alloc(ia_ptr, ep_attr); + if (ep_ptr == NULL) { + dat_status = + DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); + goto bail; + } + + /* + * Fill in the EP + */ + ep_ptr->param.ia_handle = ia_handle; + ep_ptr->param.ep_state = DAT_EP_STATE_UNCONNECTED; + ep_ptr->param.local_ia_address_ptr = + (DAT_IA_ADDRESS_PTR) & ia_ptr->hca_ptr->hca_address; + /* Set the remote address pointer to the end of the EP struct */ + ep_ptr->param.remote_ia_address_ptr = (DAT_IA_ADDRESS_PTR) (ep_ptr + 1); + + ep_ptr->param.pz_handle = pz_handle; + ep_ptr->param.recv_evd_handle = recv_evd_handle; + ep_ptr->param.request_evd_handle = request_evd_handle; + ep_ptr->param.connect_evd_handle = connect_evd_handle; + + /* + * Make sure we handle the NULL DTO EVDs + */ + if (recv_evd_handle == DAT_HANDLE_NULL && ep_attr == NULL) { + ep_ptr->param.ep_attr.max_recv_dtos = 0; + } + + if (request_evd_handle == DAT_HANDLE_NULL && ep_attr == NULL) { + ep_ptr->param.ep_attr.max_request_dtos = 0; + } + + /* + * If the user has specified a PZ handle we allocate a QP for + * this EP; else we defer until it is assigned via ep_modify(). + * As much as possible we try to keep QP creation out of the + * connect path to avoid resource errors in strange places. + */ + if (pz_handle != DAT_HANDLE_NULL) { + /* Take a reference on the PZ handle */ + dapl_os_atomic_inc(&((DAPL_PZ *) pz_handle)->pz_ref_count); + + /* + * Get a QP from the IB provider + */ + dat_status = dapls_ib_qp_alloc(ia_ptr, ep_ptr, ep_ptr); + + if (dat_status != DAT_SUCCESS) { + dapl_os_atomic_dec(&((DAPL_PZ *) pz_handle)-> + pz_ref_count); + dapl_ep_dealloc(ep_ptr); + goto bail; + } + } else { + ep_ptr->qp_state = DAPL_QP_STATE_UNATTACHED; + } + + /* + * Update ref counts. See the spec where the endpoint marks + * a data object as 'in use' + * pz_handle: dat_pz_free, uDAPL Document, 6.6.1.2 + * evd_handles: + * + * N.B. This should really be done by a util routine. + */ + dapl_os_atomic_inc(&((DAPL_EVD *) connect_evd_handle)->evd_ref_count); + /* Optional handles */ + if (recv_evd_handle != DAT_HANDLE_NULL) { + dapl_os_atomic_inc(&((DAPL_EVD *) recv_evd_handle)-> + evd_ref_count); + } + if (request_evd_handle != DAT_HANDLE_NULL) { + dapl_os_atomic_inc(&((DAPL_EVD *) request_evd_handle)-> + evd_ref_count); + } + + /* Link it onto the IA */ + dapl_ia_link_ep(ia_ptr, ep_ptr); + + *ep_handle = ep_ptr; + +#endif /* notdef */ + + bail: + return dat_status; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_disconnect.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_disconnect.c new file mode 100644 index 00000000..72da6200 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_disconnect.c @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ep_disconnect.c + * + * PURPOSE: Endpoint management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 5 + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_ia_util.h" +#include "dapl_ep_util.h" +#include "dapl_sp_util.h" +#include "dapl_evd_util.h" +#include "dapl_adapter_util.h" + +/* + * dapl_ep_disconnect + * + * DAPL Requirements Version xxx, 6.5.9 + * + * Terminate a connection. + * + * Input: + * ep_handle + * disconnect_flags + * + * Output: + * None + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + */ +DAT_RETURN DAT_API +dapl_ep_disconnect(IN DAT_EP_HANDLE ep_handle, + IN DAT_CLOSE_FLAGS disconnect_flags) +{ + DAPL_EP *ep_ptr; + DAPL_EVD *evd_ptr; + DAT_RETURN dat_status; + + dapl_dbg_log(DAPL_DBG_TYPE_API | DAPL_DBG_TYPE_CM, + "dapl_ep_disconnect (%p, %x)\n", + ep_handle, disconnect_flags); + + ep_ptr = (DAPL_EP *) ep_handle; + + /* + * Verify parameter & state + */ + if (DAPL_BAD_HANDLE(ep_ptr, DAPL_MAGIC_EP)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP); + goto bail; + } + DAPL_CNTR(ep_ptr, DCNT_EP_DISCONNECT); + + /* + * Do the verification of parameters and the state change + * atomically. + */ + dapl_os_lock(&ep_ptr->header.lock); + + /* Disconnecting a disconnected EP is a no-op. */ + if (ep_ptr->param.ep_state == DAT_EP_STATE_DISCONNECTED || + ep_ptr->param.ep_attr.service_type != DAT_SERVICE_TYPE_RC) { + dapl_os_unlock(&ep_ptr->header.lock); + dat_status = DAT_SUCCESS; + goto bail; + } + + /* Check the EP state to ensure we are queiscent. Note that + * we may get called in UNCONNECTED state in order to remove + * RECV requests from the queue prior to destroying an EP. + * See the states in the spec at 6.5.1 Endpont Lifecycle + */ + if (ep_ptr->param.ep_state != DAT_EP_STATE_CONNECTED && + ep_ptr->param.ep_state != DAT_EP_STATE_ACTIVE_CONNECTION_PENDING && + ep_ptr->param.ep_state != DAT_EP_STATE_COMPLETION_PENDING && + ep_ptr->param.ep_state != DAT_EP_STATE_DISCONNECT_PENDING) { + dapl_os_unlock(&ep_ptr->header.lock); + dat_status = + DAT_ERROR(DAT_INVALID_STATE, + dapls_ep_state_subtype(ep_ptr)); + goto bail; + } + + if (ep_ptr->param.ep_state == DAT_EP_STATE_DISCONNECT_PENDING && + disconnect_flags != DAT_CLOSE_ABRUPT_FLAG) { + /* + * If in state DISCONNECT_PENDING then this must be an + * ABRUPT disconnect + */ + dapl_os_unlock(&ep_ptr->header.lock); + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG2); + goto bail; + } + + if (ep_ptr->param.ep_state == DAT_EP_STATE_ACTIVE_CONNECTION_PENDING || + ep_ptr->param.ep_state == DAT_EP_STATE_COMPLETION_PENDING) { + /* + * Beginning or waiting on a connection: abort and reset the + * state + */ + ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECTED; + + dapl_os_unlock(&ep_ptr->header.lock); + /* disconnect and make sure we get no callbacks */ + (void)dapls_ib_disconnect(ep_ptr, DAT_CLOSE_ABRUPT_FLAG); + + /* clean up connection state */ + dapl_sp_remove_ep(ep_ptr); + + evd_ptr = (DAPL_EVD *) ep_ptr->param.connect_evd_handle; + dapls_evd_post_connection_event(evd_ptr, + DAT_CONNECTION_EVENT_DISCONNECTED, + (DAT_HANDLE) ep_ptr, 0, 0); + dat_status = DAT_SUCCESS; + goto bail; + } + + /* + * Transition the EP state to DISCONNECT_PENDING if we are + * CONNECTED. Otherwise we do not get a disconnect event and will be + * stuck in DISCONNECT_PENDING. + * + * If the user specifies a graceful disconnect, the underlying + * provider should complete all DTOs before disconnecting; in IB + * terms, this means setting the QP state to SQD before completing + * the disconnect state transitions. + */ + if (ep_ptr->param.ep_state == DAT_EP_STATE_CONNECTED) { + ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECT_PENDING; + } + dapl_os_unlock(&ep_ptr->header.lock); + dat_status = dapls_ib_disconnect(ep_ptr, disconnect_flags); + + bail: + dapl_dbg_log(DAPL_DBG_TYPE_RTN | DAPL_DBG_TYPE_CM, + "dapl_ep_disconnect (EP %p) returns 0x%x\n", + ep_ptr, dat_status); + + return dat_status; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_dup_connect.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_dup_connect.c new file mode 100644 index 00000000..799cdb46 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_dup_connect.c @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ep_dup_connect.c + * + * PURPOSE: Endpoint management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 5 + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_ep_util.h" +#include "dapl_adapter_util.h" +#include "dapl_timer_util.h" + +/* + * dapl_ep_dup_connect + * + * DAPL Requirements Version xxx, 6.5.8 + * + * Requst that a connection be established between the local Endpoint + * and a remote Endpoint. The remote Endpoint is identified by the + * dup_ep. + * + * Input: + * ep_handle + * ep_dup_handle + * conn_qual + * timeout + * private_data_size + * private_data + * qos + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + * DAT_INVALID_STATE + * DAT_MODEL_NOT_SUPPORTED + */ +DAT_RETURN DAT_API +dapl_ep_dup_connect(IN DAT_EP_HANDLE ep_handle, + IN DAT_EP_HANDLE ep_dup_handle, + IN DAT_TIMEOUT timeout, + IN DAT_COUNT private_data_size, + IN const DAT_PVOID private_data, IN DAT_QOS qos) +{ + DAPL_EP *ep_dup_ptr; + DAT_RETURN dat_status; + DAT_IA_ADDRESS_PTR remote_ia_address_ptr; + DAT_CONN_QUAL remote_conn_qual; + + ep_dup_ptr = (DAPL_EP *) ep_dup_handle; + + /* + * Verify the dup handle, which must be connected. All other + * parameters will be verified by dapl_ep_connect + */ + if (DAPL_BAD_HANDLE(ep_dup_handle, DAPL_MAGIC_EP)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP); + goto bail; + } + + /* Can't do a connection in 0 time, reject outright */ + if (timeout == 0) { + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG3); + goto bail; + } + + /* Check both the EP state and the QP state: if we don't have a QP + * there is a problem. Do this under a lock and pull out + * the connection parameters for atomicity. + */ + dapl_os_lock(&ep_dup_ptr->header.lock); + if (ep_dup_ptr->param.ep_state != DAT_EP_STATE_CONNECTED) { + dapl_os_unlock(&ep_dup_ptr->header.lock); + dat_status = + DAT_ERROR(DAT_INVALID_STATE, + dapls_ep_state_subtype(ep_dup_ptr)); + goto bail; + } + remote_ia_address_ptr = ep_dup_ptr->param.remote_ia_address_ptr; + remote_conn_qual = ep_dup_ptr->param.remote_port_qual; + dapl_os_unlock(&ep_dup_ptr->header.lock); + + dat_status = dapl_ep_connect(ep_handle, + remote_ia_address_ptr, + remote_conn_qual, + timeout, + private_data_size, + private_data, + qos, DAT_CONNECT_DEFAULT_FLAG); + bail: + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_free.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_free.c new file mode 100644 index 00000000..3bfc5417 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_free.c @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ep_free.c + * + * PURPOSE: Endpoint management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 5.4 + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_ia_util.h" +#include "dapl_ep_util.h" +#include "dapl_adapter_util.h" +#include "dapl_ring_buffer_util.h" +#include "dapl_timer_util.h" + +/* + * dapl_ep_free + * + * DAPL Requirements Version xxx, 6.5.3 + * + * Destroy an instance of the Endpoint + * + * Input: + * ep_handle + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + * DAT_INVALID_STATE + */ +DAT_RETURN DAT_API dapl_ep_free(IN DAT_EP_HANDLE ep_handle) +{ + DAPL_EP *ep_ptr; + DAPL_IA *ia_ptr; + DAT_EP_PARAM *param; + dp_ib_cm_handle_t cm_ptr, next_cm_ptr; + ib_qp_state_t save_qp_state; + DAT_RETURN dat_status = DAT_SUCCESS; + + dapl_dbg_log(DAPL_DBG_TYPE_API | DAPL_DBG_TYPE_CM, + "dapl_ep_free (%p)\n", ep_handle); + + ep_ptr = (DAPL_EP *) ep_handle; + param = &ep_ptr->param; + + /* + * Verify parameter & state + */ + if (DAPL_BAD_HANDLE(ep_ptr, DAPL_MAGIC_EP)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP); + goto bail; + } + DAPL_CNTR(ep_ptr->header.owner_ia, DCNT_IA_EP_FREE); + + if (ep_ptr->param.ep_state == DAT_EP_STATE_RESERVED || + ep_ptr->param.ep_state == DAT_EP_STATE_PASSIVE_CONNECTION_PENDING || + ep_ptr->param.ep_state == DAT_EP_STATE_TENTATIVE_CONNECTION_PENDING) + { + dapl_dbg_log(DAPL_DBG_TYPE_WARN, + "--> dapl_ep_free: invalid state: %x, ep %p\n", + ep_ptr->param.ep_state, ep_ptr); + dat_status = DAT_ERROR(DAT_INVALID_STATE, + dapls_ep_state_subtype(ep_ptr)); + goto bail; + } + + ia_ptr = ep_ptr->header.owner_ia; + + /* If we are connected, issue a disconnect. If we are in the + * disconnect_pending state, disconnect with the ABRUPT flag + * set. + */ + + /* + * Invoke ep_disconnect to clean up outstanding connections + */ + (void)dapl_ep_disconnect(ep_ptr, DAT_CLOSE_ABRUPT_FLAG); + + /* Free all CM objects */ + cm_ptr = (dapl_llist_is_empty(&ep_ptr->cm_list_head) + ? NULL : dapl_llist_peek_head(&ep_ptr->cm_list_head)); + while (cm_ptr != NULL) { + dapl_log(DAPL_DBG_TYPE_EP, + "dapl_ep_free: Free CM: EP=%p CM=%p\n", + ep_ptr, cm_ptr); + + next_cm_ptr = dapl_llist_next_entry(&ep_ptr->cm_list_head, + &cm_ptr->list_entry); + dapls_cm_free(cm_ptr); /* blocking call */ + cm_ptr = next_cm_ptr; + } + + /* + * Do verification of parameters and the state change atomically. + */ + dapl_os_lock(&ep_ptr->header.lock); + +#ifdef DAPL_DBG + /* check if event pending and warn, don't assert, state is valid */ + if (ep_ptr->param.ep_state == DAT_EP_STATE_DISCONNECT_PENDING) { + dapl_dbg_log(DAPL_DBG_TYPE_WARN, " dat_ep_free WARNING: " + "EVENT PENDING on ep %p, disconnect " + "and wait before calling dat_ep_free\n", ep_ptr); + } +#endif + + if (ep_ptr->cxn_timer != NULL) { + dapls_timer_cancel(ep_ptr->cxn_timer); + dapl_os_free(ep_ptr->cxn_timer, sizeof(DAPL_OS_TIMER)); + ep_ptr->cxn_timer = NULL; + } + + /* Remove the EP from the IA */ + dapl_ia_unlink_ep(ia_ptr, ep_ptr); + + /* + * Update ref counts. Note the user may have used ep_modify + * to set handles to NULL. Set handles to NULL so this routine + * is idempotent. + */ + if (param->pz_handle != NULL) { + dapl_os_atomic_dec(&((DAPL_PZ *) param->pz_handle)-> + pz_ref_count); + param->pz_handle = NULL; + } + if (param->recv_evd_handle != NULL) { + dapl_os_atomic_dec(&((DAPL_EVD *) param->recv_evd_handle)-> + evd_ref_count); + param->recv_evd_handle = NULL; + } + if (param->request_evd_handle != NULL) { + dapl_os_atomic_dec(&((DAPL_EVD *) param->request_evd_handle)-> + evd_ref_count); + param->request_evd_handle = NULL; + } + if (param->connect_evd_handle != NULL) { + dapl_os_atomic_dec(&((DAPL_EVD *) param->connect_evd_handle)-> + evd_ref_count); + param->connect_evd_handle = NULL; + } + + /* + * Finish tearing everything down. + */ + dapl_dbg_log(DAPL_DBG_TYPE_EP | DAPL_DBG_TYPE_CM, + "dapl_ep_free: Free EP: %x, ep %p qp_state %x qp_handle %x\n", + ep_ptr->param.ep_state, + ep_ptr, ep_ptr->qp_state, ep_ptr->qp_handle); + /* + * Take care of the transport resource. Make a copy of the qp_state + * to prevent race conditions when we exit the lock. + */ + save_qp_state = ep_ptr->qp_state; + ep_ptr->qp_state = DAPL_QP_STATE_UNATTACHED; + dapl_os_unlock(&ep_ptr->header.lock); + + /* Free the QP. If the EP has never been used, the QP is invalid */ + if (save_qp_state != DAPL_QP_STATE_UNATTACHED) { + dat_status = dapls_ib_qp_free(ia_ptr, ep_ptr); + /* This should always succeed, but report to the user if + * there is a problem. The qp_state must be restored so + * they can try it again in the face of EINTR or similar + * where the QP is OK but the call couldn't complete. + */ + if (dat_status != DAT_SUCCESS) { + ep_ptr->qp_state = save_qp_state; + goto bail; + } + } + + /* Free the resource */ + dapl_ep_dealloc(ep_ptr); + + bail: + return dat_status; + +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_get_status.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_get_status.c new file mode 100644 index 00000000..6880f6f0 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_get_status.c @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ep_get_status.c + * + * PURPOSE: Endpoint management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 5 + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_ring_buffer_util.h" +#include "dapl_cookie.h" + +/* + * dapl_ep_get_status + * + * DAPL Requirements Version xxx, 6.5.4 + * + * Provide the consumer with a quick snapshot of the Endpoint. + * The snapshot consists of Endpoint state and DTO information. + * + * Input: + * ep_handle + * + * Output: + * ep_state + * in_dto_idle + * out_dto_idle + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + */ +DAT_RETURN DAT_API +dapl_ep_get_status(IN DAT_EP_HANDLE ep_handle, + OUT DAT_EP_STATE * ep_state, + OUT DAT_BOOLEAN * in_dto_idle, + OUT DAT_BOOLEAN * out_dto_idle) +{ + DAPL_EP *ep_ptr; + DAT_RETURN dat_status; + + dapl_dbg_log(DAPL_DBG_TYPE_API, + "dapl_ep_get_status (%p, %p, %p, %p)\n", + ep_handle, ep_state, in_dto_idle, out_dto_idle); + + ep_ptr = (DAPL_EP *) ep_handle; + dat_status = DAT_SUCCESS; + + /* + * Verify parameter & state + */ + if (DAPL_BAD_HANDLE(ep_ptr, DAPL_MAGIC_EP)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP); + goto bail; + } + + /* + * Gather state info for user + */ + if (ep_state != NULL) { + *ep_state = ep_ptr->param.ep_state; + } + + if (in_dto_idle != NULL) { + *in_dto_idle = dapls_cb_pending(&ep_ptr->recv_buffer); + } + + if (out_dto_idle != NULL) { + *out_dto_idle = dapls_cb_pending(&ep_ptr->req_buffer); + } + + bail: + return dat_status; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_modify.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_modify.c new file mode 100644 index 00000000..9f0095fe --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_modify.c @@ -0,0 +1,642 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ep_modify.c + * + * PURPOSE: Endpoint management + * Description: Interfaces in this file are completely described in + * the DAPL 1.0 API, Chapter 6, section 5 + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_cookie.h" +#include "dapl_ep_util.h" +#include "dapl_adapter_util.h" + +/* + * Internal prototypes + */ + +static _INLINE_ DAT_RETURN +dapli_ep_modify_validate_parameters(IN DAT_EP_HANDLE ep_handle, + IN DAT_EP_PARAM_MASK ep_param_mask, + IN const DAT_EP_PARAM * ep_param, + OUT DAPL_IA ** ia_ptr, + OUT DAPL_EP ** ep_ptr, + OUT DAT_EP_ATTR * ep_attr_ptr); + +/* + * dapl_ep_modify + * + * DAPL Requirements Version xxx, 6.5.6 + * + * Provide the consumer parameters, including attributes and status of + * the Endpoint. + * + * Input: + * ep_handle + * ep_args_mask + * + * Output: + * ep_args + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + * DAT_INVALID_ATTRIBUTE + * DAT_INVALID_STATE + */ +DAT_RETURN DAT_API +dapl_ep_modify(IN DAT_EP_HANDLE ep_handle, + IN DAT_EP_PARAM_MASK ep_param_mask, + IN const DAT_EP_PARAM * ep_param) +{ + DAPL_IA *ia; + DAPL_EP *ep1, *ep2; + DAT_EP_ATTR ep_attr1 = { 0 }, ep_attr2 = { + 0}; + DAPL_EP new_ep, copy_of_old_ep; + DAPL_EP alloc_ep; /* Holder for resources. */ + DAPL_PZ *tmp_pz; + DAPL_EVD *tmp_evd; + DAT_RETURN dat_status; + + /* Flag indicating we've allocated a new one of these. */ + DAT_BOOLEAN qp_allocated = DAT_FALSE; + DAT_BOOLEAN rqst_cb_allocated = DAT_FALSE; + DAT_BOOLEAN recv_cb_allocated = DAT_FALSE; + + /* Flag indicating we've used (assigned to QP) a new one of these. */ + DAT_BOOLEAN qp_used = DAT_FALSE; + DAT_BOOLEAN rqst_cb_used = DAT_FALSE; + DAT_BOOLEAN recv_cb_used = DAT_FALSE; + + dat_status = dapli_ep_modify_validate_parameters(ep_handle, + ep_param_mask, + ep_param, + &ia, &ep1, &ep_attr1); + if (DAT_SUCCESS != dat_status) { + goto bail; + } + + /* + * Setup the alloc_ep with the appropriate parameters (primarily + * for allocating the QP. + */ + alloc_ep = *ep1; + alloc_ep.param.ep_attr = ep_attr1; + if (ep_param_mask & DAT_EP_FIELD_PZ_HANDLE) { + alloc_ep.param.pz_handle = ep_param->pz_handle; + } + + if (ep_param_mask & DAT_EP_FIELD_RECV_EVD_HANDLE) { + alloc_ep.param.recv_evd_handle = ep_param->recv_evd_handle; + } + + if (ep_param_mask & DAT_EP_FIELD_REQUEST_EVD_HANDLE) { + alloc_ep.param.request_evd_handle = + ep_param->request_evd_handle; + } + + if (ep_param_mask & DAT_EP_FIELD_CONNECT_EVD_HANDLE) { + alloc_ep.param.connect_evd_handle = + ep_param->connect_evd_handle; + } + + /* + * Allocate everything that might be needed. + * We allocate separately, and into a different "holding" + * ep, since we a) want the copy of the old ep into the new ep to + * be atomic with the assignment back (under lock), b) want the + * assignment of the allocated materials to be after the copy of the + * old ep into the new ep, and c) don't want the allocation done + * under lock. + */ + dat_status = dapls_cb_create(&alloc_ep.req_buffer, ep1, /* For pointer in buffer bool. */ + ep_attr1.max_request_dtos); + if (DAT_SUCCESS != dat_status) { + goto bail; + } + rqst_cb_allocated = DAT_TRUE; + + dat_status = dapls_cb_create(&alloc_ep.recv_buffer, ep1, /* For pointer in buffer bool. */ + ep_attr1.max_recv_dtos); + if (DAT_SUCCESS != dat_status) { + goto bail; + } + recv_cb_allocated = DAT_TRUE; + + dat_status = dapls_ib_qp_alloc(ia, &alloc_ep, ep1); + if (dat_status != DAT_SUCCESS) { + goto bail; + } + qp_allocated = DAT_TRUE; + + /* + * Now we atomically modify the EP, under lock + * There's a lot of work done here, but there should be no + * allocation or blocking. + */ + dapl_os_lock(&ep1->header.lock); + + /* + * Revalidate parameters; make sure that races haven't + * changed anything important. + */ + dat_status = dapli_ep_modify_validate_parameters(ep_handle, + ep_param_mask, + ep_param, + &ia, &ep2, &ep_attr2); + if (DAT_SUCCESS != dat_status) { + dapl_os_unlock(&ep2->header.lock); + goto bail; + } + + /* + * All of the following should be impossible, if validation + * occurred. But they're important to the logic of this routine, + * so we check. + */ + dapl_os_assert(ep1 == ep2); + dapl_os_assert(ep_attr2.max_recv_dtos == ep_attr1.max_recv_dtos); + dapl_os_assert(ep_attr2.max_request_dtos == ep_attr1.max_request_dtos); + dapl_os_assert(ep_attr2.max_recv_iov == ep_attr1.max_recv_iov); + dapl_os_assert(ep_attr2.max_request_iov == ep_attr1.max_request_iov); + + copy_of_old_ep = *ep2; + + /* + * Setup new ep. + */ + new_ep = *ep2; + new_ep.param.ep_attr = ep_attr2; + + /* + * We can initialize the PZ and EVD handles from the alloc_ep because + * the only thing that could have changed since we setup the alloc_ep + * is stuff changed by dapl_cr_accept, and neither PZ nor EVD is in that + * list. + */ + new_ep.param.pz_handle = alloc_ep.param.pz_handle; + new_ep.param.recv_evd_handle = alloc_ep.param.recv_evd_handle; + new_ep.param.request_evd_handle = alloc_ep.param.request_evd_handle; + new_ep.param.connect_evd_handle = alloc_ep.param.connect_evd_handle; + + /* Deal with each of the allocation fields. */ + if (ep_param_mask & DAT_EP_FIELD_EP_ATTR_MAX_RECV_DTOS + && (ep_param->ep_attr.max_recv_dtos + != ep2->param.ep_attr.max_recv_dtos)) { + new_ep.recv_buffer = alloc_ep.recv_buffer; + recv_cb_used = DAT_TRUE; + } + + if (ep_param_mask & DAT_EP_FIELD_EP_ATTR_MAX_REQUEST_DTOS + && (ep_param->ep_attr.max_request_dtos + != ep2->param.ep_attr.max_request_dtos)) { + new_ep.req_buffer = alloc_ep.req_buffer; + rqst_cb_used = DAT_TRUE; + } + + /* + * We need to change the QP only if there already was a QP + * (leave things the way you found them!) and one of the + * following has changed: send/recv EVD, send/recv reqs/IOV max. + */ + if (DAPL_QP_STATE_UNATTACHED != new_ep.qp_state + && (ep_param_mask + & (DAT_EP_FIELD_EP_ATTR_MAX_REQUEST_IOV + | DAT_EP_FIELD_EP_ATTR_MAX_RECV_IOV + | DAT_EP_FIELD_EP_ATTR_MAX_REQUEST_DTOS + | DAT_EP_FIELD_EP_ATTR_MAX_RECV_DTOS + | DAT_EP_FIELD_RECV_EVD_HANDLE + | DAT_EP_FIELD_REQUEST_EVD_HANDLE))) { + /* + * We shouldn't be racing with connection establishment + * because the parameter validate routine should protect us, + * but it's an important enough point that we assert it. + */ + dapl_os_assert((ep2->param.ep_state + != DAT_EP_STATE_PASSIVE_CONNECTION_PENDING) + && (ep2->param.ep_state + != DAT_EP_STATE_ACTIVE_CONNECTION_PENDING)); + + new_ep.qp_handle = alloc_ep.qp_handle; + new_ep.qpn = alloc_ep.qpn; + } + + /* + * The actual assignment, including modifying QP parameters. + * Modifying QP parameters needs to come first, as if it fails + * we need to exit. + */ + if (DAPL_QP_STATE_UNATTACHED != new_ep.qp_state) { + dat_status = dapls_ib_qp_modify(ia, ep2, &ep_attr2); + if (dat_status != DAT_SUCCESS) { + dapl_os_unlock(&ep2->header.lock); + goto bail; + } + } + *ep2 = new_ep; + + dapl_os_unlock(&ep2->header.lock); + + /* + * Modify reference counts, incrementing new ones + * and then decrementing old ones (so if they're the same + * the refcount never drops to zero). + */ + tmp_pz = (DAPL_PZ *) new_ep.param.pz_handle; + if (NULL != tmp_pz) { + dapl_os_atomic_inc(&tmp_pz->pz_ref_count); + } + + tmp_evd = (DAPL_EVD *) new_ep.param.recv_evd_handle; + if (NULL != tmp_evd) { + dapl_os_atomic_inc(&tmp_evd->evd_ref_count); + } + + tmp_evd = (DAPL_EVD *) new_ep.param.request_evd_handle; + if (NULL != tmp_evd) { + dapl_os_atomic_inc(&tmp_evd->evd_ref_count); + } + + tmp_evd = (DAPL_EVD *) new_ep.param.connect_evd_handle; + if (NULL != tmp_evd) { + dapl_os_atomic_inc(&tmp_evd->evd_ref_count); + } + + /* decreament the old reference counts */ + tmp_pz = (DAPL_PZ *) copy_of_old_ep.param.pz_handle; + if (NULL != tmp_pz) { + dapl_os_atomic_dec(&tmp_pz->pz_ref_count); + } + + tmp_evd = (DAPL_EVD *) copy_of_old_ep.param.recv_evd_handle; + if (NULL != tmp_evd) { + dapl_os_atomic_dec(&tmp_evd->evd_ref_count); + } + + tmp_evd = (DAPL_EVD *) copy_of_old_ep.param.request_evd_handle; + if (NULL != tmp_evd) { + dapl_os_atomic_dec(&tmp_evd->evd_ref_count); + } + + tmp_evd = (DAPL_EVD *) copy_of_old_ep.param.connect_evd_handle; + if (NULL != tmp_evd) { + dapl_os_atomic_dec(&tmp_evd->evd_ref_count); + } + + bail: + if (qp_allocated) { + DAT_RETURN local_dat_status; + if (dat_status != DAT_SUCCESS || !qp_used) { + local_dat_status = dapls_ib_qp_free(ia, &alloc_ep); + } else { + local_dat_status = + dapls_ib_qp_free(ia, ©_of_old_ep); + } + if (local_dat_status != DAT_SUCCESS) { + dapl_dbg_log(DAPL_DBG_TYPE_WARN, + "ep_modify: Failed to free QP; status %x\n", + local_dat_status); + } + } + + if (rqst_cb_allocated) { + if (dat_status != DAT_SUCCESS || !rqst_cb_used) { + dapls_cb_free(&alloc_ep.req_buffer); + } else { + dapls_cb_free(©_of_old_ep.req_buffer); + } + } + + if (recv_cb_allocated) { + if (dat_status != DAT_SUCCESS || !recv_cb_used) { + dapls_cb_free(&alloc_ep.recv_buffer); + } else { + dapls_cb_free(©_of_old_ep.recv_buffer); + } + } + + return dat_status; +} + +/* + * dapli_ep_modify_validate_parameters + * + * Validate parameters + * + * The space for the ep_attr_ptr parameter should be allocated by the + * consumer. Upon success, this parameter will contain the current ep + * attribute values with the requested modifications made. + * + */ + +static DAT_RETURN +dapli_ep_modify_validate_parameters(IN DAT_EP_HANDLE ep_handle, + IN DAT_EP_PARAM_MASK ep_param_mask, + IN const DAT_EP_PARAM * ep_param, + OUT DAPL_IA ** ia_ptr, + OUT DAPL_EP ** ep_ptr, + OUT DAT_EP_ATTR * ep_attr_ptr) +{ + DAPL_IA *ia; + DAPL_EP *ep; + DAT_EP_ATTR ep_attr; + DAT_EP_ATTR ep_attr_limit; + DAT_EP_ATTR ep_attr_request; + DAT_RETURN dat_status; + + *ia_ptr = NULL; + *ep_ptr = NULL; + dat_status = DAT_SUCCESS; + + if (DAPL_BAD_HANDLE(ep_handle, DAPL_MAGIC_EP)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP); + goto bail; + } + + ep = (DAPL_EP *) ep_handle; + ia = ep->header.owner_ia; + + /* + * Verify parameters valid in current EP state + */ + if (ep_param_mask & (DAT_EP_FIELD_IA_HANDLE | + DAT_EP_FIELD_EP_STATE | + DAT_EP_FIELD_LOCAL_IA_ADDRESS_PTR | + DAT_EP_FIELD_LOCAL_PORT_QUAL | + DAT_EP_FIELD_REMOTE_IA_ADDRESS_PTR | + DAT_EP_FIELD_REMOTE_PORT_QUAL)) { + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG2); + goto bail; + } + + /* + * Can only change the PZ handle if we are UNCONNECTED or + * TENTATIVE_CONNECTION_PENDING (psp PROVIDER allocated EP) + */ + if ((ep_param_mask & DAT_EP_FIELD_PZ_HANDLE) && + (ep->param.ep_state != DAT_EP_STATE_UNCONNECTED && + ep->param.ep_state != DAT_EP_STATE_TENTATIVE_CONNECTION_PENDING)) { + dat_status = + DAT_ERROR(DAT_INVALID_STATE, dapls_ep_state_subtype(ep)); + goto bail; + } + + if ((ep_param_mask & (DAT_EP_FIELD_RECV_EVD_HANDLE | + DAT_EP_FIELD_REQUEST_EVD_HANDLE | + DAT_EP_FIELD_CONNECT_EVD_HANDLE | + DAT_EP_FIELD_EP_ATTR_SERVICE_TYPE | + DAT_EP_FIELD_EP_ATTR_MAX_MESSAGE_SIZE | + DAT_EP_FIELD_EP_ATTR_MAX_RDMA_SIZE | + DAT_EP_FIELD_EP_ATTR_QOS | + DAT_EP_FIELD_EP_ATTR_REQUEST_COMPLETION_FLAGS | + DAT_EP_FIELD_EP_ATTR_RECV_COMPLETION_FLAGS | + DAT_EP_FIELD_EP_ATTR_MAX_RECV_DTOS | + DAT_EP_FIELD_EP_ATTR_MAX_REQUEST_DTOS | + DAT_EP_FIELD_EP_ATTR_MAX_RECV_IOV | + DAT_EP_FIELD_EP_ATTR_MAX_REQUEST_IOV)) && + (ep->param.ep_state != DAT_EP_STATE_UNCONNECTED && + ep->param.ep_state != DAT_EP_STATE_RESERVED && + ep->param.ep_state != DAT_EP_STATE_TENTATIVE_CONNECTION_PENDING)) { + dat_status = + DAT_ERROR(DAT_INVALID_STATE, dapls_ep_state_subtype(ep)); + goto bail; + } + + /* + * Validate handles being modified + */ + if (ep_param_mask & DAT_EP_FIELD_PZ_HANDLE) { + if (ep_param->pz_handle != NULL && + DAPL_BAD_HANDLE(ep_param->pz_handle, DAPL_MAGIC_PZ)) { + dat_status = + DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG3); + goto bail; + } + } + + if (ep_param_mask & DAT_EP_FIELD_RECV_EVD_HANDLE) { + if (ep_param->recv_evd_handle != NULL && + (DAPL_BAD_HANDLE(ep_param->recv_evd_handle, DAPL_MAGIC_EVD) + || !((DAPL_EVD *) ep_param->recv_evd_handle)-> + evd_flags & DAT_EVD_DTO_FLAG)) + { + dat_status = + DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG3); + goto bail; + } + } + + if (ep_param_mask & DAT_EP_FIELD_REQUEST_EVD_HANDLE) { + if (ep_param->request_evd_handle != NULL && + DAPL_BAD_HANDLE(ep_param->request_evd_handle, + DAPL_MAGIC_EVD)) { + dat_status = + DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG3); + goto bail; + } + } + + if (ep_param_mask & DAT_EP_FIELD_CONNECT_EVD_HANDLE) { + if (ep_param->connect_evd_handle != NULL && + DAPL_BAD_HANDLE(ep_param->connect_evd_handle, + DAPL_MAGIC_EVD) + && !(((DAPL_EVD *) ep_param->connect_evd_handle)-> + evd_flags & DAT_EVD_CONNECTION_FLAG)) + { + dat_status = + DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG3); + goto bail; + } + } + + /* + * Validate the attributes against the HCA limits + */ + ep_attr = ep->param.ep_attr; + + dapl_os_memzero(&ep_attr_limit, sizeof(DAT_EP_ATTR)); + dat_status = + dapls_ib_query_hca(ia->hca_ptr, NULL, &ep_attr_limit, NULL); + if (dat_status != DAT_SUCCESS) { + goto bail; + } + + ep_attr_request = ep_param->ep_attr; + + if (ep_param_mask & DAT_EP_FIELD_EP_ATTR_SERVICE_TYPE) { + if (ep_attr_request.service_type != DAT_SERVICE_TYPE_RC) { + dat_status = + DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG3); + goto bail; + } + } + + if (ep_param_mask & DAT_EP_FIELD_EP_ATTR_MAX_MESSAGE_SIZE) { + if (ep_attr_request.max_mtu_size > ep_attr_limit.max_mtu_size) { + dat_status = + DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG3); + goto bail; + } else { + ep_attr.max_mtu_size = ep_attr_request.max_mtu_size; + } + } + + /* Do nothing if the DAT_EP_FIELD_EP_ATTR_MAX_RDMA_SIZE flag is */ + /* set. Each RDMA transport/provider may or may not have a limit */ + /* on the size of an RDMA DTO. For InfiniBand, this parameter is */ + /* validated in the implementation of the dapls_ib_qp_modify() */ + /* function. */ + /* */ + /* if ( ep_param_mask & DAT_EP_FIELD_EP_ATTR_MAX_RDMA_SIZE ) */ + /* { */ + /* */ + /* } */ + + if (ep_param_mask & DAT_EP_FIELD_EP_ATTR_QOS) { + /* Do nothing, not defined in the spec yet */ + } + + if (ep_param_mask & DAT_EP_FIELD_EP_ATTR_RECV_COMPLETION_FLAGS) { + dat_status = + dapl_ep_check_recv_completion_flags(ep_attr_request. + recv_completion_flags); + if (dat_status != DAT_SUCCESS) + { + goto bail; + } else { + ep_attr.recv_completion_flags = + ep_attr_request.recv_completion_flags; + } + } + + if (ep_param_mask & DAT_EP_FIELD_EP_ATTR_REQUEST_COMPLETION_FLAGS) { + dat_status = + dapl_ep_check_request_completion_flags(ep_attr_request. + request_completion_flags); + if (dat_status != DAT_SUCCESS) { + goto bail; + } else { + ep_attr.request_completion_flags = + ep_attr_request.request_completion_flags; + } + } + + if (ep_param_mask & DAT_EP_FIELD_EP_ATTR_MAX_RECV_DTOS) { + if (ep_attr_request.max_recv_dtos > ep_attr_limit.max_recv_dtos + || (ep_param->recv_evd_handle == DAT_HANDLE_NULL + && (ep_attr_request.max_recv_dtos > 0))) { + dat_status = + DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG3); + goto bail; + } else { + ep_attr.max_recv_dtos = ep_attr_request.max_recv_dtos; + } + } + + if (ep_param_mask & DAT_EP_FIELD_EP_ATTR_MAX_REQUEST_DTOS) { + if (ep_attr_request.max_request_dtos > + ep_attr_limit.max_request_dtos + || (ep_param->request_evd_handle == DAT_HANDLE_NULL + && (ep_attr_request.max_request_dtos > 0))) { + dat_status = + DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG3); + goto bail; + } else { + ep_attr.max_request_dtos = + ep_attr_request.max_request_dtos; + } + } + + if (ep_param_mask & DAT_EP_FIELD_EP_ATTR_MAX_RECV_IOV) { + if (ep_attr_request.max_recv_iov > ep_attr_limit.max_recv_iov) { + dat_status = + DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG3); + goto bail; + } else { + ep_attr.max_recv_iov = ep_attr_request.max_recv_iov; + } + } + + if (ep_param_mask & DAT_EP_FIELD_EP_ATTR_MAX_REQUEST_IOV) { + if (ep_attr_request.max_request_iov > + ep_attr_limit.max_request_iov) { + dat_status = + DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG3); + goto bail; + } else { + ep_attr.max_request_iov = + ep_attr_request.max_request_iov; + } + } + + if (ep_param_mask & DAT_EP_FIELD_EP_ATTR_MAX_RDMA_READ_IOV) { + if (ep_attr_request.max_rdma_read_iov > + ep_attr_limit.max_rdma_read_iov) { + dat_status = + DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG3); + goto bail; + } else { + ep_attr.max_rdma_read_iov = + ep_attr_request.max_rdma_read_iov; + } + } + + if (ep_param_mask & DAT_EP_FIELD_EP_ATTR_MAX_RDMA_WRITE_IOV) { + if (ep_attr_request.max_rdma_write_iov > + ep_attr_limit.max_rdma_write_iov) { + dat_status = + DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG3); + goto bail; + } else { + ep_attr.max_rdma_write_iov = + ep_attr_request.max_rdma_write_iov; + } + } + + *ia_ptr = ia; + *ep_ptr = ep; + *ep_attr_ptr = ep_attr; + + bail: + return dat_status; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_post_rdma_read.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_post_rdma_read.c new file mode 100644 index 00000000..437cc5a4 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_post_rdma_read.c @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ep_post_rdma_read.c + * + * PURPOSE: Endpoint management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 5 + * + * $Id:$ + **********************************************************************/ + +#include "dapl_ep_util.h" + +/* + * dapl_ep_post_rdma_read + * + * DAPL Requirements Version xxx, 6.5.12 + * + * Request the xfer of all data specified by the remote_iov over the + * connection of ep handle Endpint into the local_iov + * + * Input: + * ep_handle + * num_segments + * local_iov + * user_cookie + * remote_iov + * completion_flags + * + * Output: + * None. + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + * DAT_INVALID_STATE + * DAT_LENGTH_ERROR + * DAT_PROTECTION_VIOLATION + * DAT_PRIVILEGES_VIOLATION + */ +DAT_RETURN DAT_API +dapl_ep_post_rdma_read(IN DAT_EP_HANDLE ep_handle, + IN DAT_COUNT num_segments, + IN DAT_LMR_TRIPLET * local_iov, + IN DAT_DTO_COOKIE user_cookie, + IN const DAT_RMR_TRIPLET * remote_iov, + IN DAT_COMPLETION_FLAGS completion_flags) +{ + + DAT_RETURN dat_status; + + dapl_dbg_log(DAPL_DBG_TYPE_API, + "dapl_ep_post_rdma_read (%p, %d, %p, %p, %p, %x)\n", + ep_handle, + num_segments, + local_iov, + user_cookie.as_64, remote_iov, completion_flags); + + dat_status = dapl_ep_post_send_req(ep_handle, + num_segments, + local_iov, + user_cookie, + remote_iov, + completion_flags, + DAPL_DTO_TYPE_RDMA_READ, + OP_RDMA_READ); + + dapl_dbg_log(DAPL_DBG_TYPE_RTN, + "dapl_ep_post_rdma_read () returns 0x%x\n", dat_status); + + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_post_rdma_read_to_rmr.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_post_rdma_read_to_rmr.c new file mode 100644 index 00000000..ff84db0a --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_post_rdma_read_to_rmr.c @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2007 Intel Corporation. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ep_post_rdma_read_rmr.c + * + * PURPOSE: Endpoint management + * Description: Interfaces in this file are completely described in + * the DAPL 2.0 API, Chapter 6, section 6 + * + * $Id:$ + **********************************************************************/ + +#include "dapl_ep_util.h" + +/* + * dapl_ep_post_rdma_read_to_rmr + * + * DAPL Requirements Version xxx, 6.6.24 + * + * Requests the transfer of all the data specified by the remote_buffer + * over the connection of the ep_handle Endpoint into the local_iov + * specified by the RMR segments. + * + * Input: + * ep_handle + * num_segments + * local_iov + * user_cookie + * completion_flags + * invalidate flag + * RMR context + * + * Output: + * None + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + * DAT_INVALID_HANDLE + * DAT_INVALID_STATE + * DAT_LENGTH_ERROR + * DAT_PROTECTION_VIOLATION + * DAT_PRIVILEGES_VIOLATION + * DAT_MODEL_NOT_SUPPORTED + */ +DAT_RETURN DAT_API dapl_ep_post_rdma_read_to_rmr(IN DAT_EP_HANDLE ep_handle, /* ep_handle */ + IN const DAT_RMR_TRIPLET * local, /* local_iov */ + IN DAT_DTO_COOKIE cookie, /* user_cookie */ + IN const DAT_RMR_TRIPLET * remote, /* remote_iov */ + IN DAT_COMPLETION_FLAGS flags) +{ /* completion_flags */ + return DAT_MODEL_NOT_SUPPORTED; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_post_rdma_write.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_post_rdma_write.c new file mode 100644 index 00000000..b8bea977 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_post_rdma_write.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ep_post_rdma_write.c + * + * PURPOSE: Endpoint management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 5 + * + * $Id:$ + **********************************************************************/ + +#include "dapl_ep_util.h" + +/* + * dapl_ep_post_rdma_write + * + * DAPL Requirements Version xxx, 6.5.13 + * + * Request the xfer of all data specified by the local_iov over the + * connection of ep handle Endpint into the remote_iov + * + * Input: + * ep_handle + * num_segments + * local_iov + * user_cookie + * remote_iov + * compltion_flags + * + * Output: + * None. + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + * DAT_INVALID_STATE + * DAT_LENGTH_ERROR + * DAT_PROTECTION_VIOLATION + * DAT_PRIVILEGES_VIOLATION + */ +DAT_RETURN DAT_API +dapl_ep_post_rdma_write(IN DAT_EP_HANDLE ep_handle, + IN DAT_COUNT num_segments, + IN DAT_LMR_TRIPLET * local_iov, + IN DAT_DTO_COOKIE user_cookie, + IN const DAT_RMR_TRIPLET * remote_iov, + IN DAT_COMPLETION_FLAGS completion_flags) +{ + DAT_RETURN dat_status; + + dapl_dbg_log(DAPL_DBG_TYPE_API, + "dapl_ep_post_rdma_write (%p, %d, %p, %p, %p, %x)\n", + ep_handle, + num_segments, + local_iov, + user_cookie.as_64, remote_iov, completion_flags); + + dat_status = dapl_ep_post_send_req(ep_handle, + num_segments, + local_iov, + user_cookie, + remote_iov, + completion_flags, + DAPL_DTO_TYPE_RDMA_WRITE, + OP_RDMA_WRITE); + + dapl_dbg_log(DAPL_DBG_TYPE_RTN, + "dapl_ep_post_rdma_write () returns 0x%x", dat_status); + + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_post_recv.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_post_recv.c new file mode 100644 index 00000000..fe3a6058 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_post_recv.c @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ep_post_recv.c + * + * PURPOSE: Endpoint management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 5 + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_cookie.h" +#include "dapl_adapter_util.h" + +/* + * dapl_ep_post_recv + * + * DAPL Requirements Version xxx, 6.5.11 + * + * Request to receive data over the connection of ep handle into + * local_iov + * + * Input: + * ep_handle + * num_segments + * local_iov + * user_cookie + * completion_flags + * + * Output: + * None. + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + * DAT_INVALID_STATE + * DAT_PROTECTION_VIOLATION + * DAT_PROVILEGES_VIOLATION + */ +DAT_RETURN DAT_API +dapl_ep_post_recv(IN DAT_EP_HANDLE ep_handle, + IN DAT_COUNT num_segments, + IN DAT_LMR_TRIPLET * local_iov, + IN DAT_DTO_COOKIE user_cookie, + IN DAT_COMPLETION_FLAGS completion_flags) +{ + DAPL_EP *ep_ptr; + DAPL_COOKIE *cookie; + DAT_RETURN dat_status; + + dapl_dbg_log(DAPL_DBG_TYPE_API, + "dapl_ep_post_recv (%p, %d, %p, %p, %x)\n", + ep_handle, + num_segments, + local_iov, user_cookie.as_64, completion_flags); + + if (DAPL_BAD_HANDLE(ep_handle, DAPL_MAGIC_EP)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP); + goto bail; + } + + ep_ptr = (DAPL_EP *) ep_handle; + + /* + * Synchronization ok since this buffer is only used for receive + * requests, which aren't allowed to race with each other. + */ + dat_status = dapls_dto_cookie_alloc(&ep_ptr->recv_buffer, + DAPL_DTO_TYPE_RECV, + user_cookie, &cookie); + if (DAT_SUCCESS != dat_status) { + goto bail; + } + + /* + * Invoke provider specific routine to post DTO + */ + dat_status = + dapls_ib_post_recv(ep_ptr, cookie, num_segments, local_iov); + + if (dat_status != DAT_SUCCESS) { + dapls_cookie_dealloc(&ep_ptr->recv_buffer, cookie); + } + + bail: + dapl_dbg_log(DAPL_DBG_TYPE_RTN, + "dapl_ep_post_recv () returns 0x%x\n", dat_status); + + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_post_send.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_post_send.c new file mode 100644 index 00000000..fc1aade7 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_post_send.c @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ep_post_send.c + * + * PURPOSE: Endpoint management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 5 + * + * $Id: dapl_ep_post_send.c 1364 2005-10-31 18:30:14Z jlentini $ + **********************************************************************/ + +#include "dapl_ep_util.h" + +/* + * dapl_ep_post_send + * + * DAPL Requirements Version xxx, 6.5.10 + * + * Request a transfer of all the data from the local_iov over + * the connection of the ep handle Endpoint to the remote side. + * + * Input: + * ep_handle + * num_segments + * local_iov + * user_cookie + * completion_flags + * + * Output: + * None + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + * DAT_INVALID_STATE + * DAT_PROTECTION_VIOLATION + * DAT_PRIVILEGES_VIOLATION + */ +DAT_RETURN DAT_API +dapl_ep_post_send(IN DAT_EP_HANDLE ep_handle, + IN DAT_COUNT num_segments, + IN DAT_LMR_TRIPLET * local_iov, + IN DAT_DTO_COOKIE user_cookie, + IN DAT_COMPLETION_FLAGS completion_flags) +{ + DAT_RMR_TRIPLET remote_iov = { 0, 0, 0 }; + DAT_RETURN dat_status; + + dapl_dbg_log(DAPL_DBG_TYPE_API, + "dapl_ep_post_send (%p, %d, %p, %p, %x)\n", + ep_handle, + num_segments, + local_iov, user_cookie.as_64, completion_flags); + + dat_status = dapl_ep_post_send_req(ep_handle, + num_segments, + local_iov, + user_cookie, + &remote_iov, + completion_flags, + DAPL_DTO_TYPE_SEND, OP_SEND); + + dapl_dbg_log(DAPL_DBG_TYPE_RTN, + "dapl_ep_post_send () returns 0x%x\n", dat_status); + + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_post_send_invalidate.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_post_send_invalidate.c new file mode 100644 index 00000000..0589b282 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_post_send_invalidate.c @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2007 Intel Corporation. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ep_post_send_invalidate.c + * + * PURPOSE: Endpoint management + * Description: Interfaces in this file are completely described in + * the DAPL 2.0 API, Chapter 6, section 6 + * + * $Id:$ + **********************************************************************/ + +#include "dapl_ep_util.h" + +/* + * dapl_ep_post_send_invalidate + * + * DAPL Requirements Version xxx, 6.6.21 + * + * Requests a transfer of all the data from the local_iov over the connection + * of the ep_handle Endpoint to the remote side and invalidates the Remote + * Memory Region context. + * + * Input: + * ep_handle + * num_segments + * local_iov + * user_cookie + * completion_flags + * invalidate flag + * RMR context + * + * Output: + * None + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + * DAT_INVALID_HANDLE + * DAT_INVALID_STATE + * DAT_PROTECTION_VIOLATION + * DAT_PRIVILEGES_VIOLATION + * DAT_MODEL_NOT_SUPPORTED + */ +DAT_RETURN DAT_API dapl_ep_post_send_with_invalidate(IN DAT_EP_HANDLE ep_handle, /* ep_handle */ + IN DAT_COUNT num_segments, /* num_segments */ + IN DAT_LMR_TRIPLET * local_iov, /* local_iov */ + IN DAT_DTO_COOKIE user_cookie, /* user_cookie */ + IN DAT_COMPLETION_FLAGS flags, /* completion_flags */ + IN DAT_BOOLEAN invalidate_flag, /* invalidate_flag */ + IN DAT_RMR_CONTEXT + rmr_context) +{ /* RMR context */ + return DAT_MODEL_NOT_SUPPORTED; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_query.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_query.c new file mode 100644 index 00000000..f5f548ff --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_query.c @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ep_query.c + * + * PURPOSE: Endpoint management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 5 + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_adapter_util.h" + +/* + * dapl_ep_query + * + * DAPL Requirements Version xxx, 6.5.5 + * + * Provide the consumer parameters, including attributes and status of + * the Endpoint. + * + * Input: + * ep_handle + * ep_param_mask + * + * Output: + * ep_param + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + */ +DAT_RETURN DAT_API +dapl_ep_query(IN DAT_EP_HANDLE ep_handle, + IN DAT_EP_PARAM_MASK ep_param_mask, OUT DAT_EP_PARAM * ep_param) +{ + DAPL_EP *ep_ptr; + DAT_RETURN dat_status; + + dapl_dbg_log(DAPL_DBG_TYPE_API, + "dapl_ep_query (%p, %x, %p)\n", + ep_handle, ep_param_mask, ep_param); + + dat_status = DAT_SUCCESS; + ep_ptr = (DAPL_EP *) ep_handle; + + /* + * Verify parameter & state + */ + if (DAPL_BAD_HANDLE(ep_ptr, DAPL_MAGIC_EP)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP); + goto bail; + } + + if (ep_param == NULL) { + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG3); + goto bail; + } + + /* + * Fill in according to user request + * + * N.B. Just slam all values into the user structure, there + * is nothing to be gained by checking for each bit. + */ + if (ep_param_mask & DAT_EP_FIELD_ALL) { + /* only attempt to get remote IA address if consumer requested it */ + if (ep_param_mask & DAT_EP_FIELD_REMOTE_IA_ADDRESS_PTR) { + if (ep_ptr->param.ep_state == DAT_EP_STATE_CONNECTED) { + /* obtain the remote IP address */ + dat_status = + dapls_ib_cm_remote_addr((DAT_HANDLE) + ep_handle, + &ep_ptr-> + remote_ia_address); + } + ep_ptr->param.remote_ia_address_ptr = + (DAT_IA_ADDRESS_PTR) & ep_ptr->remote_ia_address; + } + *ep_param = ep_ptr->param; + } + + bail: + return dat_status; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_recv_query.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_recv_query.c new file mode 100644 index 00000000..55621c43 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_recv_query.c @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ep_recv_query.c + * + * PURPOSE: Endpoint management + * Description: Interfaces in this file are completely described in + * the DAPL 1.2 API, Chapter 6, section 6.11 + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_ep_util.h" + +/* + * dapl_ep_recv_query + * + * uDAPL Version 1.2, 6.6.11 + * + * Destroy an instance of the Endpoint + * + * Input: + * ep_handle + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + * DAT_INVALID_HANDLE + * DAT_MODEL_NOT_SUPPORTED + */ +DAT_RETURN DAT_API +dapl_ep_recv_query(IN DAT_EP_HANDLE ep_handle, + OUT DAT_COUNT * nbufs_allocate, + OUT DAT_COUNT * bufs_alloc_span) +{ + DAPL_EP *ep_ptr; + DAT_RETURN dat_status; + + dat_status = DAT_SUCCESS; + + dapl_dbg_log(DAPL_DBG_TYPE_API, "dapl_ep_recv_query (%p, %p, %p)\n", + ep_handle, nbufs_allocate, bufs_alloc_span); + + ep_ptr = (DAPL_EP *) ep_handle; + + /* + * Verify parameter & state + */ + if (DAPL_BAD_HANDLE(ep_ptr, DAPL_MAGIC_EP)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP); + goto bail; + } + + dat_status = DAT_ERROR(DAT_NOT_IMPLEMENTED, DAT_NO_SUBTYPE); + + bail: + return dat_status; + +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_reset.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_reset.c new file mode 100644 index 00000000..c5a0506d --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_reset.c @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ep_reset.c + * + * PURPOSE: Endpoint management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 5.13 + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_ia_util.h" +#include "dapl_ep_util.h" +#include "dapl_adapter_util.h" +#include "dapl_ring_buffer_util.h" + +/* + * dapl_ep_reset + * + * DAPL Requirements Version 1.1, 6.5.13 + * + * Reset the QP attached to this Endpoint, transitioning back to the + * INIT state + * + * Input: + * ep_handle + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + * DAT_INVALID_STATE + */ +DAT_RETURN DAT_API dapl_ep_reset(IN DAT_EP_HANDLE ep_handle) +{ + DAPL_EP *ep_ptr; + DAT_RETURN dat_status; + + dat_status = DAT_SUCCESS; + + ep_ptr = (DAPL_EP *) ep_handle; + + /* + * Verify parameter & state + */ + if (DAPL_BAD_HANDLE(ep_ptr, DAPL_MAGIC_EP)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP); + goto bail; + } + + if (ep_ptr->param.ep_state != DAT_EP_STATE_UNCONNECTED + && ep_ptr->param.ep_state != DAT_EP_STATE_DISCONNECTED) { + dat_status = + DAT_ERROR(DAT_INVALID_STATE, + dapls_ep_state_subtype(ep_ptr)); + goto bail; + } + + if (ep_ptr->param.ep_state == DAT_EP_STATE_DISCONNECTED) { + dapls_ib_reinit_ep(ep_ptr); + ep_ptr->param.ep_state = DAT_EP_STATE_UNCONNECTED; + } + + bail: + return dat_status; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_set_watermark.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_set_watermark.c new file mode 100644 index 00000000..3bceed7f --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_set_watermark.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ep_set_watermark.c + * + * PURPOSE: Endpoint management + * Description: Interfaces in this file are completely described in + * the DAPL 1.2 API, Chapter 6, section 6.13 + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_ep_util.h" + +/* + * dapl_ep_set_watermark + * + * DAPL Requirements Version 1.2, 6.6.13 + * + * Sets the watermark values for an EP for generating asynchronous + * events. + * + * Input: + * ep_handle + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + * DAT_INVALID_HANDLE + * DAT_MODEL_NOT_SUPPORTED + */ +DAT_RETURN DAT_API +dapl_ep_set_watermark(IN DAT_EP_HANDLE ep_handle, + IN DAT_COUNT soft_high_watermark, + IN DAT_COUNT hard_high_watermark) +{ + DAPL_EP *ep_ptr; + DAT_RETURN dat_status; + + dat_status = DAT_SUCCESS; + + dapl_dbg_log(DAPL_DBG_TYPE_API, "dapl_ep_set_watermark (%p, %d, %d)\n", + ep_handle, soft_high_watermark, hard_high_watermark); + + ep_ptr = (DAPL_EP *) ep_handle; + + /* + * Verify parameter & state + */ + if (DAPL_BAD_HANDLE(ep_ptr, DAPL_MAGIC_EP)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP); + goto bail; + } + + dat_status = DAT_NOT_IMPLEMENTED; + + bail: + return dat_status; + +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_util.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_util.c new file mode 100644 index 00000000..9aff242c --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_util.c @@ -0,0 +1,615 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ep_util.c + * + * PURPOSE: Manage EP Info structure + * + * $Id:$ + **********************************************************************/ + +#include "dapl_ep_util.h" +#include "dapl_ring_buffer_util.h" +#include "dapl_cookie.h" +#include "dapl_adapter_util.h" +#include "dapl_evd_util.h" +#include "dapl_cr_util.h" /* for callback routine */ + +/* + * Local definitions + */ +/* + * Default number of I/O operations on an end point + */ +#define IB_IO_DEFAULT 16 +/* + * Default number of scatter/gather entries available to a single + * post send/recv + */ +#define IB_IOV_DEFAULT 4 + +/* + * Default number of RDMA operations in progress at a time + */ +#define IB_RDMA_DEFAULT 4 + +extern void dapli_ep_default_attrs(IN DAPL_EP * ep_ptr); + +char *dapl_get_ep_state_str(DAT_EP_STATE state) +{ +#ifdef DAPL_DBG + static char *state_str[DAT_EP_STATE_CONNECTED_MULTI_PATH + 1] = { + "DAT_EP_STATE_UNCONNECTED", /* quiescent state */ + "DAT_EP_STATE_UNCONFIGURED_UNCONNECTED", + "DAT_EP_STATE_RESERVED", + "DAT_EP_STATE_UNCONFIGURED_RESERVED", + "DAT_EP_STATE_PASSIVE_CONNECTION_PENDING", + "DAT_EP_STATE_UNCONFIGURED_PASSIVE", + "DAT_EP_STATE_ACTIVE_CONNECTION_PENDING", + "DAT_EP_STATE_TENTATIVE_CONNECTION_PENDING", + "DAT_EP_STATE_UNCONFIGURED_TENTATIVE", + "DAT_EP_STATE_CONNECTED", + "DAT_EP_STATE_DISCONNECT_PENDING", + "DAT_EP_STATE_DISCONNECTED", + "DAT_EP_STATE_COMPLETION_PENDING", + "DAT_EP_STATE_CONNECTED_SINGLE_PATH", + "DAT_EP_STATE_CONNECTED_MULTI_PATH" + }; + return state_str[state]; +#else + static char buf[12]; + sprintf(buf, "%d", state); + return buf; +#endif +} + +/* + * dapl_ep_alloc + * + * alloc and initialize an EP INFO struct + * + * Input: + * IA INFO struct ptr + * + * Output: + * ep_ptr + * + * Returns: + * none + * + */ +DAPL_EP *dapl_ep_alloc(IN DAPL_IA * ia_ptr, IN const DAT_EP_ATTR * ep_attr) +{ + DAPL_EP *ep_ptr; + + /* Allocate EP */ + ep_ptr = + (DAPL_EP *) dapl_os_alloc(sizeof(DAPL_EP) + sizeof(DAT_SOCK_ADDR)); + if (ep_ptr == NULL) { + goto bail; + } + + /* zero the structure */ + dapl_os_memzero(ep_ptr, sizeof(DAPL_EP) + sizeof(DAT_SOCK_ADDR)); + +#ifdef DAPL_COUNTERS + /* Allocate counters */ + ep_ptr->cntrs = + dapl_os_alloc(sizeof(DAT_UINT64) * DCNT_EP_ALL_COUNTERS); + if (ep_ptr->cntrs == NULL) { + dapl_os_free(ep_ptr, sizeof(DAPL_EP) + sizeof(DAT_SOCK_ADDR)); + return (NULL); + } + dapl_os_memzero(ep_ptr->cntrs, + sizeof(DAT_UINT64) * DCNT_EP_ALL_COUNTERS); +#endif /* DAPL_COUNTERS */ + + /* + * initialize the header + */ + ep_ptr->header.provider = ia_ptr->header.provider; + ep_ptr->header.magic = DAPL_MAGIC_EP; + ep_ptr->header.handle_type = DAT_HANDLE_TYPE_EP; + ep_ptr->header.owner_ia = ia_ptr; + ep_ptr->header.user_context.as_64 = 0; + ep_ptr->header.user_context.as_ptr = NULL; + + dapl_llist_init_entry(&ep_ptr->header.ia_list_entry); + dapl_llist_init_head(&ep_ptr->cm_list_head); + dapl_os_lock_init(&ep_ptr->header.lock); + + /* + * Initialize the body + */ + /* + * Set up default parameters if the user passed in a NULL + */ + if (ep_attr == NULL) { + dapli_ep_default_attrs(ep_ptr); + } else { + ep_ptr->param.ep_attr = *ep_attr; + } + + /* + * IBM OS API specific fields + */ + ep_ptr->qp_handle = IB_INVALID_HANDLE; + ep_ptr->qpn = 0; + ep_ptr->qp_state = DAPL_QP_STATE_UNATTACHED; + + if (DAT_SUCCESS != dapls_cb_create(&ep_ptr->req_buffer, + ep_ptr, + ep_ptr->param.ep_attr. + max_request_dtos)) { + dapl_ep_dealloc(ep_ptr); + ep_ptr = NULL; + goto bail; + } + + if (DAT_SUCCESS != dapls_cb_create(&ep_ptr->recv_buffer, + ep_ptr, + ep_ptr->param.ep_attr.max_recv_dtos)) + { + dapl_ep_dealloc(ep_ptr); + ep_ptr = NULL; + goto bail; + } + + dapls_io_trc_alloc(ep_ptr); + + bail: + return ep_ptr; +} + +/* + * dapl_ep_dealloc + * + * Free the passed in EP structure. + * + * Input: + * entry point pointer + * + * Output: + * none + * + * Returns: + * none + * + */ +void dapl_ep_dealloc(IN DAPL_EP * ep_ptr) +{ + dapl_os_assert(ep_ptr->header.magic == DAPL_MAGIC_EP); + + ep_ptr->header.magic = DAPL_MAGIC_INVALID; /* reset magic to prevent reuse */ + + dapls_cb_free(&ep_ptr->req_buffer); + dapls_cb_free(&ep_ptr->recv_buffer); + + if (NULL != ep_ptr->cxn_timer) { + dapl_os_free(ep_ptr->cxn_timer, sizeof(DAPL_OS_TIMER)); + } + +#ifdef DAPL_COUNTERS + dapl_os_free(ep_ptr->cntrs, sizeof(DAT_UINT64) * DCNT_EP_ALL_COUNTERS); +#endif /* DAPL_COUNTERS */ + + dapl_os_free(ep_ptr, sizeof(DAPL_EP) + sizeof(DAT_SOCK_ADDR)); +} + +/* + * dapl_ep_default_attrs + * + * Set default values in the parameter fields + * + * Input: + * entry point pointer + * + * Output: + * none + * + * Returns: + * none + * + */ +void dapli_ep_default_attrs(IN DAPL_EP * ep_ptr) +{ + DAT_EP_ATTR ep_attr_limit; + DAT_EP_ATTR *ep_attr; + DAT_RETURN dat_status; + + ep_attr = &ep_ptr->param.ep_attr; + /* Set up defaults */ + dapl_os_memzero(ep_attr, sizeof(DAT_EP_ATTR)); + + /* mtu and rdma sizes fixed in IB as per IBTA 1.1, 9.4.3, 9.4.4, 9.7.7. */ + ep_attr->max_mtu_size = 0x80000000; + ep_attr->max_rdma_size = 0x80000000; + + ep_attr->qos = DAT_QOS_BEST_EFFORT; + ep_attr->service_type = DAT_SERVICE_TYPE_RC; + ep_attr->max_recv_dtos = IB_IO_DEFAULT; + ep_attr->max_request_dtos = IB_IO_DEFAULT; + ep_attr->max_recv_iov = IB_IOV_DEFAULT; + ep_attr->max_request_iov = IB_IOV_DEFAULT; + ep_attr->max_rdma_read_in = IB_RDMA_DEFAULT; + ep_attr->max_rdma_read_out = IB_RDMA_DEFAULT; + + /* + * Configure the EP as a standard completion type, which will be + * used by the EVDs. A threshold of 1 is the default state of an + * EVD. + */ + ep_attr->request_completion_flags = DAT_COMPLETION_EVD_THRESHOLD_FLAG; + ep_attr->recv_completion_flags = DAT_COMPLETION_EVD_THRESHOLD_FLAG; + /* + * Unspecified defaults: + * - ep_privileges: No RDMA capabilities + * - num_transport_specific_params: none + * - transport_specific_params: none + * - num_provider_specific_params: 0 + * - provider_specific_params: 0 + */ + + dat_status = dapls_ib_query_hca(ep_ptr->header.owner_ia->hca_ptr, + NULL, &ep_attr_limit, NULL); + /* check against HCA maximums */ + if (dat_status == DAT_SUCCESS) { + ep_ptr->param.ep_attr.max_mtu_size = + DAPL_MIN(ep_ptr->param.ep_attr.max_mtu_size, + ep_attr_limit.max_mtu_size); + ep_ptr->param.ep_attr.max_rdma_size = + DAPL_MIN(ep_ptr->param.ep_attr.max_rdma_size, + ep_attr_limit.max_rdma_size); + ep_ptr->param.ep_attr.max_recv_dtos = + DAPL_MIN(ep_ptr->param.ep_attr.max_recv_dtos, + ep_attr_limit.max_recv_dtos); + ep_ptr->param.ep_attr.max_request_dtos = + DAPL_MIN(ep_ptr->param.ep_attr.max_request_dtos, + ep_attr_limit.max_request_dtos); + ep_ptr->param.ep_attr.max_recv_iov = + DAPL_MIN(ep_ptr->param.ep_attr.max_recv_iov, + ep_attr_limit.max_recv_iov); + ep_ptr->param.ep_attr.max_request_iov = + DAPL_MIN(ep_ptr->param.ep_attr.max_request_iov, + ep_attr_limit.max_request_iov); + ep_ptr->param.ep_attr.max_rdma_read_in = + DAPL_MIN(ep_ptr->param.ep_attr.max_rdma_read_in, + ep_attr_limit.max_rdma_read_in); + ep_ptr->param.ep_attr.max_rdma_read_out = + DAPL_MIN(ep_ptr->param.ep_attr.max_rdma_read_out, + ep_attr_limit.max_rdma_read_out); + } +} + +DAT_RETURN dapl_ep_check_recv_completion_flags(DAT_COMPLETION_FLAGS flags) +{ + + /* + * InfiniBand will not allow signal suppression for RECV completions, + * see the 1.0.1 spec section 10.7.3.1, 10.8.6. + * N.B. SIGNALLED has a different meaning in dapl than it does + * in IB; IB SIGNALLED is the same as DAPL SUPPRESS. DAPL + * SIGNALLED simply means the user will not get awakened when + * an EVD completes, even though the dapl handler is invoked. + */ + + if (flags & DAT_COMPLETION_SUPPRESS_FLAG) { + return DAT_INVALID_PARAMETER; + } + + return DAT_SUCCESS; +} + +DAT_RETURN dapl_ep_check_request_completion_flags(DAT_COMPLETION_FLAGS flags) +{ + return DAT_SUCCESS; +} + +DAT_RETURN +dapl_ep_post_send_req(IN DAT_EP_HANDLE ep_handle, + IN DAT_COUNT num_segments, + IN DAT_LMR_TRIPLET * local_iov, + IN DAT_DTO_COOKIE user_cookie, + IN const DAT_RMR_TRIPLET * remote_iov, + IN DAT_COMPLETION_FLAGS completion_flags, + IN DAPL_DTO_TYPE dto_type, IN int op_type) +{ + DAPL_EP *ep_ptr; + DAPL_COOKIE *cookie; + DAT_RETURN dat_status; + + if (DAPL_BAD_HANDLE(ep_handle, DAPL_MAGIC_EP)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP); + goto bail; + } + + ep_ptr = (DAPL_EP *) ep_handle; + + /* + * Synchronization ok since this buffer is only used for send + * requests, which aren't allowed to race with each other. + */ + dat_status = dapls_dto_cookie_alloc(&ep_ptr->req_buffer, + dto_type, user_cookie, &cookie); + if (dat_status != DAT_SUCCESS) { + dapl_log(DAPL_DBG_TYPE_ERR, + " dapl_post_req resource ERR:" + " dtos pending = %d, max_dtos %d, max_cb %d hd %d tl %d\n", + dapls_cb_pending(&ep_ptr->req_buffer), + ep_ptr->param.ep_attr.max_request_dtos, + ep_ptr->req_buffer.pool_size, + ep_ptr->req_buffer.head, ep_ptr->req_buffer.tail); + + goto bail; + } + + /* + * Invoke provider specific routine to post DTO + */ + dat_status = dapls_ib_post_send(ep_ptr, + op_type, + cookie, + num_segments, + local_iov, + remote_iov, completion_flags); + + if (dat_status != DAT_SUCCESS) { + dapls_cookie_dealloc(&ep_ptr->req_buffer, cookie); + } + + bail: + return dat_status; +} + +/* + * dapli_ep_timeout + * + * If this routine is invoked before a connection occurs, generate an + * event + */ +void dapls_ep_timeout(uintptr_t arg) +{ + DAPL_EP *ep_ptr; + ib_cm_events_t ib_cm_event; + + dapl_dbg_log(DAPL_DBG_TYPE_CM, "--> dapls_ep_timeout! ep %lx\n", arg); + + ep_ptr = (DAPL_EP *) arg; + + /* reset the EP state */ + ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECTED; + + /* Clean up the EP and put the underlying QP into the ERROR state. + * The disconnect_clean interface requires the provided dependent + *cm event number. + */ + ib_cm_event = dapls_ib_get_cm_event(DAT_CONNECTION_EVENT_TIMED_OUT); + dapls_ib_disconnect_clean(ep_ptr, DAT_TRUE, ib_cm_event); + + (void)dapls_evd_post_connection_event((DAPL_EVD *) ep_ptr->param. + connect_evd_handle, + DAT_CONNECTION_EVENT_TIMED_OUT, + (DAT_HANDLE) ep_ptr, 0, 0); +} + +/* + * dapls_ep_state_subtype + * + * Return the INVALID_STATE connection subtype associated with an + * INVALID_STATE on an EP. Strictly for error reporting. + */ +DAT_RETURN_SUBTYPE dapls_ep_state_subtype(IN DAPL_EP * ep_ptr) +{ + DAT_RETURN_SUBTYPE dat_status; + + switch (ep_ptr->param.ep_state) { + case DAT_EP_STATE_UNCONNECTED: + { + dat_status = DAT_INVALID_STATE_EP_UNCONNECTED; + break; + } + case DAT_EP_STATE_RESERVED: + { + dat_status = DAT_INVALID_STATE_EP_RESERVED; + break; + } + case DAT_EP_STATE_PASSIVE_CONNECTION_PENDING: + { + dat_status = DAT_INVALID_STATE_EP_PASSCONNPENDING; + break; + } + case DAT_EP_STATE_ACTIVE_CONNECTION_PENDING: + { + dat_status = DAT_INVALID_STATE_EP_ACTCONNPENDING; + break; + } + case DAT_EP_STATE_TENTATIVE_CONNECTION_PENDING: + { + dat_status = DAT_INVALID_STATE_EP_TENTCONNPENDING; + break; + } + case DAT_EP_STATE_CONNECTED: + { + dat_status = DAT_INVALID_STATE_EP_CONNECTED; + break; + } + case DAT_EP_STATE_DISCONNECT_PENDING: + { + dat_status = DAT_INVALID_STATE_EP_DISCPENDING; + break; + } + case DAT_EP_STATE_DISCONNECTED: + { + dat_status = DAT_INVALID_STATE_EP_DISCONNECTED; + break; + } + case DAT_EP_STATE_COMPLETION_PENDING: + { + dat_status = DAT_INVALID_STATE_EP_COMPLPENDING; + break; + } + + default: + { + dat_status = 0; + break; + } + } + + return dat_status; +} + +#ifdef DAPL_DBG_IO_TRC +/* allocate trace buffer */ +void dapls_io_trc_alloc(DAPL_EP * ep_ptr) +{ + DAT_RETURN dat_status; + int i; + struct io_buf_track *ibt; + + ep_ptr->ibt_dumped = 0; /* bool to control how often we print */ + dat_status = dapls_rbuf_alloc(&ep_ptr->ibt_queue, DBG_IO_TRC_QLEN); + if (dat_status != DAT_SUCCESS) { + goto bail; + } + ibt = + (struct io_buf_track *)dapl_os_alloc(sizeof(struct io_buf_track) * + DBG_IO_TRC_QLEN); + + if (dat_status != DAT_SUCCESS) { + dapls_rbuf_destroy(&ep_ptr->ibt_queue); + goto bail; + } + ep_ptr->ibt_base = ibt; + dapl_os_memzero(ibt, sizeof(struct io_buf_track) * DBG_IO_TRC_QLEN); + + /* add events to free event queue */ + for (i = 0; i < DBG_IO_TRC_QLEN; i++) { + dapls_rbuf_add(&ep_ptr->ibt_queue, ibt++); + } + bail: + return; +} +#endif /* DAPL_DBG_IO_TRC */ + +/* + * Generate a disconnect event on abruct close for older verbs providers + * that do not do it automatically. + */ + +void +dapl_ep_legacy_post_disconnect(DAPL_EP * ep_ptr, + DAT_CLOSE_FLAGS disconnect_flags) +{ + ib_cm_events_t ib_cm_event; + DAPL_CR *cr_ptr; + dp_ib_cm_handle_t cm_ptr; + + /* + * Acquire the lock and make sure we didn't get a callback + * that cleaned up. + */ + dapl_os_lock(&ep_ptr->header.lock); + if (disconnect_flags == DAT_CLOSE_ABRUPT_FLAG && + ep_ptr->param.ep_state == DAT_EP_STATE_DISCONNECT_PENDING) { + /* + * If this is an ABRUPT close, the provider will not generate + * a disconnect message so we do it manually here. Just invoke + * the CM callback as it will clean up the appropriate + * data structures, reset the state, and generate the event + * on the way out. Obtain the provider dependent cm_event to + * pass into the callback for a disconnect. + */ + ib_cm_event = + dapls_ib_get_cm_event(DAT_CONNECTION_EVENT_DISCONNECTED); + + cr_ptr = ep_ptr->cr_ptr; + cm_ptr = (dapl_llist_is_empty(&ep_ptr->cm_list_head) + ? NULL : dapl_llist_peek_head(&ep_ptr->cm_list_head)); + dapl_os_unlock(&ep_ptr->header.lock); + + if (cr_ptr != NULL) { + dapl_dbg_log(DAPL_DBG_TYPE_API | DAPL_DBG_TYPE_CM, + " dapl_ep_disconnect force callback on EP %p CM handle %x\n", + ep_ptr, cr_ptr->ib_cm_handle); + + dapls_cr_callback(cr_ptr->ib_cm_handle, + ib_cm_event, NULL, 0, cr_ptr->sp_ptr); + } else { + dapl_evd_connection_callback(cm_ptr, + ib_cm_event, + NULL, 0, (void *)ep_ptr); + } + } else { + dapl_os_unlock(&ep_ptr->header.lock); + } +} + +/* + * dapl_ep_link_cm + * + * Add linking of provider's CM object to a EP structure + * This enables multiple CM's per EP, and syncronization + * + * Input: + * DAPL_EP *ep_ptr + * dp_ib_cm_handle_t *cm_ptr defined in provider's dapl_util.h + * + * CM objects linked with EP using ->list_entry + * Output: + * none + * + * Returns: + * none + * + */ +void dapl_ep_link_cm(IN DAPL_EP *ep_ptr, IN dp_ib_cm_handle_t cm_ptr) +{ + dapl_os_lock(&ep_ptr->header.lock); + dapls_cm_acquire(cm_ptr); + dapl_llist_add_tail(&ep_ptr->cm_list_head, &cm_ptr->list_entry, cm_ptr); + dapl_os_unlock(&ep_ptr->header.lock); +} + +void dapl_ep_unlink_cm(IN DAPL_EP *ep_ptr, IN dp_ib_cm_handle_t cm_ptr) +{ + dapl_os_lock(&ep_ptr->header.lock); + dapl_llist_remove_entry(&ep_ptr->cm_list_head, &cm_ptr->list_entry); + dapls_cm_release(cm_ptr); + dapl_os_unlock(&ep_ptr->header.lock); +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_util.h b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_util.h new file mode 100644 index 00000000..31d0e233 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ep_util.h @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dapl_ep_util.h + * + * PURPOSE: Utility defs & routines for the EP data structure + * + * $Id:$ + * + **********************************************************************/ + +#ifndef _DAPL_EP_UTIL_H_ +#define _DAPL_EP_UTIL_H_ + +#include "dapl.h" +#include "dapl_adapter_util.h" + +/* function prototypes */ + +extern DAPL_EP * +dapl_ep_alloc ( + IN DAPL_IA *ia, + IN const DAT_EP_ATTR *ep_attr ); + +extern void +dapl_ep_dealloc ( + IN DAPL_EP *ep_ptr ); + +extern DAT_RETURN +dapl_ep_check_recv_completion_flags ( + DAT_COMPLETION_FLAGS flags ); + +extern DAT_RETURN +dapl_ep_check_request_completion_flags ( + DAT_COMPLETION_FLAGS flags ); + +extern DAT_RETURN +dapl_ep_post_send_req ( + IN DAT_EP_HANDLE ep_handle, + IN DAT_COUNT num_segments, + IN DAT_LMR_TRIPLET *local_iov, + IN DAT_DTO_COOKIE user_cookie, + IN const DAT_RMR_TRIPLET *remote_iov, + IN DAT_COMPLETION_FLAGS completion_flags, + IN DAPL_DTO_TYPE dto_type, + IN int op_type ); + +void dapls_ep_timeout (uintptr_t arg ); + +DAT_RETURN_SUBTYPE +dapls_ep_state_subtype( + IN DAPL_EP *ep_ptr ); + +extern void +dapl_ep_legacy_post_disconnect( + DAPL_EP *ep_ptr, + DAT_CLOSE_FLAGS disconnect_flags); + +extern char *dapl_get_ep_state_str(DAT_EP_STATE state); + +extern void dapl_ep_link_cm(IN DAPL_EP *ep_ptr, + IN dp_ib_cm_handle_t cm_ptr); + +extern void dapl_ep_unlink_cm(IN DAPL_EP *ep_ptr, + IN dp_ib_cm_handle_t cm_ptr); + +STATIC _INLINE_ dp_ib_cm_handle_t dapl_get_cm_from_ep(IN DAPL_EP *ep_ptr) +{ + dp_ib_cm_handle_t cm_ptr; + + dapl_os_lock(&ep_ptr->header.lock); + cm_ptr = (dapl_llist_is_empty(&ep_ptr->cm_list_head) + ? NULL : dapl_llist_peek_head(&ep_ptr->cm_list_head)); + dapl_os_unlock(&ep_ptr->header.lock); + + return cm_ptr; +} + +#endif /* _DAPL_EP_UTIL_H_ */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_evd_connection_callb.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_evd_connection_callb.c new file mode 100644 index 00000000..3166702c --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_evd_connection_callb.c @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_evd_connection_callback.c + * + * PURPOSE: implements connection callbacks + * + * Description: Accepts asynchronous callbacks from the Communications Manager + * for EVDs that have been specified as the connection_evd. + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_evd_util.h" +#include "dapl_ep_util.h" +#include "dapl_timer_util.h" + +/* + * dapl_evd_connection_callback + * + * Connection callback function for ACTIVE connection requests; callbacks + * generated by the Connection Manager in response to issuing a + * connect call. + * + * Input: + * ib_cm_handle, + * ib_cm_event + * private_data_ptr + * context (evd) + * cr_pp + * + * Output: + * None + * + */ + +void +dapl_evd_connection_callback(IN dp_ib_cm_handle_t ib_cm_handle, + IN const ib_cm_events_t ib_cm_event, + IN const void *private_data_ptr, + IN const int private_data_size, + IN const void *context) +{ + DAPL_EP *ep_ptr; + DAPL_EVD *evd_ptr; + DAPL_PRIVATE *prd_ptr; + DAT_EVENT_NUMBER dat_event_num; + DAT_RETURN dat_status; + + dapl_dbg_log(DAPL_DBG_TYPE_CM | DAPL_DBG_TYPE_CALLBACK, + "--> dapl_evd_connection_callback: ctxt: %p event: %x cm_handle %p\n", + context, ib_cm_event, (void *)ib_cm_handle); + + /* + * Determine the type of handle passed back to us in the context + * and sort out key parameters. + */ + if (context == NULL + || ((DAPL_HEADER *) context)->magic != DAPL_MAGIC_EP) { + return; + } + + /* + * Active side of the connection, context is an EP and + * PSP is irrelevant. + */ + ep_ptr = (DAPL_EP *) context; + evd_ptr = (DAPL_EVD *) ep_ptr->param.connect_evd_handle; + DAPL_CNTR(evd_ptr, DCNT_EVD_CONN_CALLBACK); + + prd_ptr = (DAPL_PRIVATE *) private_data_ptr; + /* + * All operations effect the EP, so lock it once and unlock + * when necessary + */ + dapl_os_lock(&ep_ptr->header.lock); + + /* + * If a connection timer has been set up on this EP, cancel it now + */ + if (ep_ptr->cxn_timer != NULL) { + dapls_timer_cancel(ep_ptr->cxn_timer); + dapl_os_free(ep_ptr->cxn_timer, sizeof(DAPL_OS_TIMER)); + ep_ptr->cxn_timer = NULL; + } + + /* Obtain the event number from the provider layer */ + dat_event_num = dapls_ib_get_dat_event(ib_cm_event, DAT_FALSE); + + switch (dat_event_num) { + case DAT_CONNECTION_EVENT_ESTABLISHED: + { + /* If we don't have an EP at this point we are very screwed + * up + */ + if (ep_ptr->param.ep_state != + DAT_EP_STATE_ACTIVE_CONNECTION_PENDING) { + /* If someone pulled the plug on the connection, just + * exit + */ + dapl_os_unlock(&ep_ptr->header.lock); + dat_status = DAT_SUCCESS; + break; + } + ep_ptr->param.ep_state = DAT_EP_STATE_CONNECTED; + + if (private_data_size > 0) { + /* copy in the private data */ + dapl_os_memcpy(ep_ptr->private.private_data, + prd_ptr->private_data, + DAPL_MIN(private_data_size, + DAPL_MAX_PRIVATE_DATA_SIZE)); + } + dapl_os_unlock(&ep_ptr->header.lock); + + break; + } + case DAT_CONNECTION_EVENT_PEER_REJECTED: + { + /* peer reject may include private data */ + + if (private_data_size > 0) + dapl_os_memcpy(ep_ptr->private.private_data, + prd_ptr->private_data, + DAPL_MIN(private_data_size, + DAPL_MAX_PRIVATE_DATA_SIZE)); + + dapl_dbg_log(DAPL_DBG_TYPE_CM | DAPL_DBG_TYPE_CALLBACK, + "dapl_evd_connection_callback PEER REJ pd=%p sz=%d\n", + prd_ptr, private_data_size); + } + case DAT_CONNECTION_EVENT_DISCONNECTED: + case DAT_CONNECTION_EVENT_UNREACHABLE: + case DAT_CONNECTION_EVENT_NON_PEER_REJECTED: + { + ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECTED; + dapls_ib_disconnect_clean(ep_ptr, DAT_TRUE, + ib_cm_event); + dapl_os_unlock(&ep_ptr->header.lock); + + break; + } + case DAT_CONNECTION_EVENT_BROKEN: + case DAT_CONNECTION_EVENT_TIMED_OUT: + { + ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECTED; + dapls_ib_disconnect_clean(ep_ptr, DAT_FALSE, + ib_cm_event); + dapl_os_unlock(&ep_ptr->header.lock); + + break; + } + case DAT_CONNECTION_REQUEST_EVENT: + default: + { + dapl_os_unlock(&ep_ptr->header.lock); + evd_ptr = NULL; + + dapl_os_assert(0); /* shouldn't happen */ + break; + } + } + + /* + * Post the event + * If the EP has been freed, the evd_ptr will be NULL + */ + if (evd_ptr != NULL) { + dat_status = dapls_evd_post_connection_event(evd_ptr, dat_event_num, (DAT_HANDLE) ep_ptr, private_data_size, /* CONNECTED or REJECT */ + ep_ptr->private. + private_data); + + if (dat_status != DAT_SUCCESS && + dat_event_num == DAT_CONNECTION_EVENT_ESTABLISHED) { + /* We can't tell the user we are connected, something + * is wrong locally. Just kill the connection and + * reset the state to DISCONNECTED as we don't + * expect a callback on an ABRUPT disconnect. + */ + dapls_ib_disconnect(ep_ptr, DAT_CLOSE_ABRUPT_FLAG); + dapl_os_lock(&ep_ptr->header.lock); + ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECTED; + dapl_os_unlock(&ep_ptr->header.lock); + } + } + + dapl_dbg_log(DAPL_DBG_TYPE_CM | DAPL_DBG_TYPE_CALLBACK, + "dapl_evd_connection_callback () returns\n"); + +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_evd_cq_async_error_callb.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_evd_cq_async_error_callb.c new file mode 100644 index 00000000..258f8f28 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_evd_cq_async_error_callb.c @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_evd_cq_async_error_callback.c + * + * PURPOSE: implements CQ async_callbacks from verbs + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_evd_util.h" + +/* + * dapl_evd_cq_async_error_callback + * + * The callback function registered with verbs for cq async errors + * + * Input: + * ib_cm_handle, + * ib_cm_event + * cause_ptr + * context (evd) + * + * Output: + * None + * + */ + +void +dapl_evd_cq_async_error_callback(IN ib_hca_handle_t ib_hca_handle, + IN ib_cq_handle_t ib_cq_handle, + IN ib_error_record_t * cause_ptr, + IN void *context) +{ + DAPL_EVD *async_evd; + DAPL_EVD *evd; + DAT_RETURN dat_status; + + dapl_dbg_log(DAPL_DBG_TYPE_CALLBACK | DAPL_DBG_TYPE_EXCEPTION, + "dapl_evd_cq_async_error_callback (%p, %p, %p, %p)\n", + ib_hca_handle, ib_cq_handle, cause_ptr, context); + + if (NULL == context) { + dapl_os_panic("NULL == context\n"); + } + + evd = (DAPL_EVD *) context; + async_evd = evd->header.owner_ia->async_error_evd; + DAPL_CNTR(evd->header.owner_ia, DCNT_IA_ASYNC_CQ_ERROR); + + dat_status = dapls_evd_post_async_error_event(async_evd, + DAT_ASYNC_ERROR_EVD_OVERFLOW, + (DAT_IA_HANDLE) + async_evd->header. + owner_ia); + + if (dat_status != DAT_SUCCESS) { + dapl_os_panic("async EVD overflow\n"); + } + + dapl_dbg_log(DAPL_DBG_TYPE_CALLBACK | DAPL_DBG_TYPE_EXCEPTION, + "dapl_evd_cq_async_error_callback () returns\n"); +} diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_evd_dequeue.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_evd_dequeue.c new file mode 100644 index 00000000..7632fe1e --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_evd_dequeue.c @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_evd_dequeue.c + * + * PURPOSE: Event Management + * + * Description: Interfaces in this file are completely described in + * the uDAPL 1.1 API, Chapter 6, section 3 + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_ring_buffer_util.h" +#include "dapl_evd_util.h" + +/* + * dapl_evd_dequeue + * + * DAPL Requirements Version xxx, 6.3.2.7 + * + * Remove first element from an event dispatcher + * + * Input: + * evd_handle + * + * Output: + * event + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + * DAT_INVALID_PARAMETER + * DAT_INVALID_STATE + * DAT_QUEUE_EMPTY + */ + +DAT_RETURN DAT_API dapl_evd_dequeue(IN DAT_EVD_HANDLE evd_handle, + OUT DAT_EVENT * event) +{ + DAPL_EVD *evd_ptr; + DAT_EVENT *local_event; + DAT_RETURN dat_status; + + dapl_dbg_log(DAPL_DBG_TYPE_API, + "dapl_evd_dequeue (%p, %p)\n", evd_handle, event); + + evd_ptr = (DAPL_EVD *) evd_handle; + dat_status = DAT_SUCCESS; + + if (DAPL_BAD_HANDLE(evd_handle, DAPL_MAGIC_EVD)) { + dat_status = DAT_ERROR(DAT_INVALID_HANDLE, 0); + goto bail; + } + + if (event == NULL) { + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG2); + goto bail; + } + DAPL_CNTR(evd_ptr, DCNT_EVD_DEQUEUE); + + /* + * We need to dequeue under lock, as the IB OS Access API + * restricts us from having multiple threads in CQ poll, and the + * DAPL 1.1 API allows multiple threads in dat_evd_dequeue() + */ + dapl_os_lock(&evd_ptr->header.lock); + + /* + * Make sure there are no other waiters and the evd is active. + * Currently this means only the OPEN state is allowed. + */ + if (evd_ptr->evd_state != DAPL_EVD_STATE_OPEN || + evd_ptr->catastrophic_overflow) { + dapl_os_unlock(&evd_ptr->header.lock); + dat_status = DAT_ERROR(DAT_INVALID_STATE, 0); + goto bail; + } + + /* + * Try the EVD rbuf first; poll from the CQ only if that's empty. + * This keeps events in order if dat_evd_wait() has copied events + * from CQ to EVD. + */ + local_event = + (DAT_EVENT *) dapls_rbuf_remove(&evd_ptr->pending_event_queue); + if (local_event != NULL) { + *event = *local_event; + dat_status = dapls_rbuf_add(&evd_ptr->free_event_queue, + local_event); + DAPL_CNTR(evd_ptr, DCNT_EVD_DEQUEUE_FOUND); + + } else if (evd_ptr->ib_cq_handle != IB_INVALID_HANDLE) { + dat_status = dapls_evd_cq_poll_to_event(evd_ptr, event); + DAPL_CNTR(evd_ptr, DCNT_EVD_DEQUEUE_POLL); + } else { + dat_status = DAT_ERROR(DAT_QUEUE_EMPTY, 0); + DAPL_CNTR(evd_ptr, DCNT_EVD_DEQUEUE_NOT_FOUND); + } + + dapl_os_unlock(&evd_ptr->header.lock); + bail: + dapl_dbg_log(DAPL_DBG_TYPE_RTN, + "dapl_evd_dequeue () returns 0x%x\n", dat_status); + + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_evd_dto_callb.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_evd_dto_callb.c new file mode 100644 index 00000000..2e8d70e8 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_evd_dto_callb.c @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_evd_dto_callback.c + * + * PURPOSE: implements DTO callbacks from verbs + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_evd_util.h" +#include "dapl_cno_util.h" +#include "dapl_cookie.h" +#include "dapl_adapter_util.h" + +/********************************************************************* + * * + * Function Prototypes * + * * + *********************************************************************/ + +/********************************************************************* + * * + * Function Definitions * + * * + *********************************************************************/ + +/* + * dapl_evd_dto_callback + * + * Input: + * hca_handle_in, + * cq_handle_in, + * user_context_cq_p + * + * Output: + * none + * + * This is invoked for both DTO and MW bind completions. Strictly + * speaking it is an event callback rather than just a DTO callback. + * + */ + +void +dapl_evd_dto_callback(IN ib_hca_handle_t hca_handle, + IN ib_cq_handle_t cq_handle, IN void *user_context) +{ + DAPL_EVD *evd_ptr; + DAT_RETURN dat_status; + DAPL_EVD_STATE state; + + dapl_dbg_log(DAPL_DBG_TYPE_CALLBACK, + "dapl_evd_dto_callback(%p, %p, %p)\n", + hca_handle, cq_handle, user_context); + + evd_ptr = (DAPL_EVD *) user_context; + DAPL_CNTR(evd_ptr, DCNT_EVD_DTO_CALLBACK); + + dapl_os_assert(hca_handle == + evd_ptr->header.owner_ia->hca_ptr->ib_hca_handle); + dapl_os_assert(evd_ptr->ib_cq_handle == cq_handle); + dapl_os_assert(evd_ptr->header.magic == DAPL_MAGIC_EVD); + + /* Read once. */ + state = *(volatile DAPL_EVD_STATE *)&evd_ptr->evd_state; + + dapl_dbg_log(DAPL_DBG_TYPE_EVD, + "-- dapl_evd_dto_callback: CQ %p, state %x\n", + (void *)evd_ptr->ib_cq_handle, state); + + /* + * This function does not dequeue from the CQ; only the consumer + * can do that. Instead, it wakes up waiters if any exist. + * It rearms the completion only if completions should always occur + * (specifically if a CNO is associated with the EVD and the + * EVD is enabled. + */ + + if (state == DAPL_EVD_STATE_WAITED) { + /* + * If we could, it would be best to avoid this wakeup + * (and the context switch) unless the number of events/CQs + * waiting for the waiter was its threshold. We don't + * currently have the ability to determine that without + * dequeueing the events, and we can't do that for + * synchronization reasons (racing with the waiter waking + * up and dequeuing, sparked by other callbacks). + */ + + /* + * We don't need to worry about taking the lock for the + * wakeup because wakeups are sticky. + */ + dapls_evd_dto_wakeup(evd_ptr); + + } else if (state == DAPL_EVD_STATE_OPEN) { + DAPL_CNO *cno = evd_ptr->cno_ptr; + if (evd_ptr->evd_enabled && (evd_ptr->cno_ptr != NULL)) { + /* + * Re-enable callback, *then* trigger. + * This guarantees we won't miss any events. + */ + dat_status = dapls_ib_completion_notify(hca_handle, + evd_ptr, + IB_NOTIFY_ON_NEXT_COMP); + + if (DAT_SUCCESS != dat_status) { + (void)dapls_evd_post_async_error_event(evd_ptr-> + header. + owner_ia-> + async_error_evd, + DAT_ASYNC_ERROR_PROVIDER_INTERNAL_ERROR, + (DAT_IA_HANDLE) + evd_ptr-> + header. + owner_ia); + } + + dapl_internal_cno_trigger(cno, evd_ptr); + } + } + dapl_dbg_log(DAPL_DBG_TYPE_RTN, "dapl_evd_dto_callback () returns\n"); +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_evd_free.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_evd_free.c new file mode 100644 index 00000000..43f2fee5 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_evd_free.c @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_evd_free.c + * + * PURPOSE: Event management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 3 + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_evd_util.h" +#include "dapl_ia_util.h" +#include "dapl_cno_util.h" /* for __KDAPL__ */ + +/* + * dapl_evd_free + * + * DAPL Requirements Version xxx, 6.3.2.2 + * + * Destroy a specific instance of the Event Dispatcher + * + * Input: + * evd_handle + * + * Output: + * None + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + * DAT_INVALID_STATE + */ +DAT_RETURN DAT_API dapl_evd_free(IN DAT_EVD_HANDLE evd_handle) +{ + DAPL_EVD *evd_ptr; + DAPL_CNO *cno_ptr; + DAT_RETURN dat_status; + + dapl_dbg_log(DAPL_DBG_TYPE_API, "dapl_evd_free (%p)\n", evd_handle); + + dat_status = DAT_SUCCESS; + evd_ptr = (DAPL_EVD *) evd_handle; + + if (DAPL_BAD_HANDLE(evd_handle, DAPL_MAGIC_EVD)) { + dat_status = DAT_ERROR(DAT_INVALID_HANDLE, 0); + goto bail; + } + + DAPL_CNTR(evd_ptr->header.owner_ia, DCNT_IA_EVD_FREE); + + if (dapl_os_atomic_read(&evd_ptr->evd_ref_count) != 0) { + dat_status = + DAT_ERROR(DAT_INVALID_STATE, DAT_INVALID_STATE_EVD_IN_USE); + goto bail; + } + + /* obtain the cno_ptr before the evd is released, which must occur + * before deallocating the CNO + */ + cno_ptr = evd_ptr->cno_ptr; + + dapl_ia_unlink_evd(evd_ptr->header.owner_ia, evd_ptr); + + dat_status = dapls_evd_dealloc(evd_ptr); + if (dat_status != DAT_SUCCESS) { + dapl_ia_link_evd(evd_ptr->header.owner_ia, evd_ptr); + } +#if defined(__KDAPL__) + if (cno_ptr != NULL) { + if (dapl_os_atomic_read(&cno_ptr->cno_ref_count) > 0 + || cno_ptr->cno_waiters > 0) { + dat_status = + DAT_ERROR(DAT_INVALID_STATE, + DAT_INVALID_STATE_EVD_IN_USE); + goto bail; + } + dapl_ia_unlink_cno(cno_ptr->header.owner_ia, cno_ptr); + dapl_cno_dealloc(cno_ptr); + } +#else + if (cno_ptr != NULL) { + if (dapl_os_atomic_read(&cno_ptr->cno_ref_count) == 0 + && cno_ptr->cno_waiters > 0) { + /* + * Last reference on the CNO, trigger a notice. See + * uDAPL 1.1 spec 6.3.2.3 + */ + dapl_internal_cno_trigger(cno_ptr, NULL); + } + } +#endif /* defined(__KDAPL__) */ + + bail: + if (dat_status) + dapl_dbg_log(DAPL_DBG_TYPE_RTN, + "dapl_evd_free () returns 0x%x\n", dat_status); + + return dat_status; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_evd_post_se.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_evd_post_se.c new file mode 100644 index 00000000..52736d0c --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_evd_post_se.c @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_evd_post_se.c + * + * PURPOSE: Event Management + * + * Description: Interfaces in this file are completely defined in + * the uDAPL 1.1 API, Chapter 6, section 3 + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_evd_util.h" +#include "dapl_ia_util.h" + +/* + * dapl_evd_post_se + * + * DAPL Requirements Version xxx, 6.3.2.7 + * + * Post a software event to the Event Dispatcher event queue. + * + * Input: + * evd_handle + * event + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + */ + +DAT_RETURN DAT_API dapl_evd_post_se(DAT_EVD_HANDLE evd_handle, + const DAT_EVENT * event) +{ + DAPL_EVD *evd_ptr; + DAT_RETURN dat_status; + + evd_ptr = (DAPL_EVD *) evd_handle; + dat_status = DAT_SUCCESS; + + if (DAPL_BAD_HANDLE(evd_handle, DAPL_MAGIC_EVD)) { + dat_status = DAT_ERROR(DAT_INVALID_HANDLE, 0); + goto bail; + } + /* Only post to EVDs that are specific to software events */ + if (!(evd_ptr->evd_flags & DAT_EVD_SOFTWARE_FLAG)) { + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG1); + goto bail; + } + + if (!event) { + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG2); + goto bail; + } + if (event->event_number != DAT_SOFTWARE_EVENT) { + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG2); + goto bail; + } + + dat_status = dapls_evd_post_software_event(evd_ptr, + DAT_SOFTWARE_EVENT, + event->event_data. + software_event_data.pointer); + + bail: + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_evd_qp_async_error_callb.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_evd_qp_async_error_callb.c new file mode 100644 index 00000000..a9ea4ffb --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_evd_qp_async_error_callb.c @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_evd_qp_async_error_callback.c + * + * PURPOSE: implements QP callbacks from verbs + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_evd_util.h" +#include "dapl_adapter_util.h" + +/* + * dapl_evd_qp_async_error_callback + * + * The callback function registered with verbs for qp async erros + * + * Input: + * ib_cm_handle, + * ib_cm_event + * cause_ptr + * context (evd) + * + * Output: + * None + * + */ + +void +dapl_evd_qp_async_error_callback(IN ib_hca_handle_t ib_hca_handle, + IN ib_qp_handle_t ib_qp_handle, + IN ib_error_record_t * cause_ptr, + IN void *context) +{ + /* + * This is an affiliated error and hence should be able to + * supply us with exact information on the error type and QP. + * + * However the Mellanox and IBM APIs for registering this callback + * are different. + * + * The IBM API allows consumers to register the callback with + * + * ib_int32_t + * ib_set_qp_async_error_eh_us ( + * ib_hca_handle_t hca_handle, + * ib_qp_async_handler_t handler ) + * + * Notice that this function does not take a context. The context is + * specified per QP in the call to ib_qp_create_us(). + * + * In contrast the Mellanox API requires that the context be specified + * when the funciton is registered: + * + * VAPI_ret_t + * VAPI_set_async_event_handler ( + * IN VAPI_hca_hndl_t hca_hndl, + * IN VAPI_async_event_handler_t handler, + * IN void* private_data ) + * + * Therefore we always specify the context as the asyncronous EVD + * to be compatible with both APIs. + */ + + DAPL_IA *ia_ptr; + DAPL_EP *ep_ptr; + DAPL_EVD *async_evd; + DAT_EVENT_NUMBER async_event; + DAT_RETURN dat_status; + +#ifdef _VENDOR_IBAL_ + dapl_dbg_log(DAPL_DBG_TYPE_ERR, "%s() IB err %s\n", + __FUNCTION__, ib_get_async_event_str(cause_ptr->code)); +#else + dapl_dbg_log(DAPL_DBG_TYPE_ERR, "%s() IB async QP err - ctx=%p\n", + __FUNCTION__, context); +#endif + + ep_ptr = (DAPL_EP *) context; + if (!ep_ptr) { + dapl_dbg_log(DAPL_DBG_TYPE_ERR, "%s() NULL context?\n", + __FUNCTION__); + return; + } + + ia_ptr = ep_ptr->header.owner_ia; + async_evd = (DAPL_EVD *) ia_ptr->async_error_evd; + DAPL_CNTR(ia_ptr, DCNT_IA_ASYNC_QP_ERROR); + + dapl_dbg_log(DAPL_DBG_TYPE_CALLBACK | DAPL_DBG_TYPE_EXCEPTION, + "--> %s: ep %p qp %p (%x) state %d\n", __FUNCTION__, + ep_ptr, + ep_ptr->qp_handle, ep_ptr->qpn, ep_ptr->param.ep_state); + + /* + * Transition to ERROR if we are connected; other states need to + * complete first (e.g. pending states) + */ + if (ep_ptr->param.ep_state == DAT_EP_STATE_CONNECTED) { + ep_ptr->param.ep_state = DAT_EP_STATE_ERROR; + } + + dapl_os_assert(async_evd != NULL); + + dat_status = dapls_ib_get_async_event(cause_ptr, &async_event); + if (dat_status == DAT_SUCCESS) { + /* + * If dapls_ib_get_async_event is not successful, + * an event has been generated by the provide that + * we are not interested in. + */ + (void)dapls_evd_post_async_error_event(async_evd, + async_event, + async_evd->header. + owner_ia); + } + dapl_dbg_log(DAPL_DBG_TYPE_CALLBACK | DAPL_DBG_TYPE_EXCEPTION, + "%s() returns\n", __FUNCTION__); +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_evd_resize.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_evd_resize.c new file mode 100644 index 00000000..762fad42 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_evd_resize.c @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_evd_resize.c + * + * PURPOSE: EVENT management + * + * Description: Interfaces in this file are completely defined in + * the uDAPL 1.1 API, Chapter 6, section 3 + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_evd_util.h" +#include "dapl_ring_buffer_util.h" +#include "dapl_adapter_util.h" + +/* + * dapl_evd_resize + * + * DAPL Requirements Version xxx, 6.3.2.5 + * + * Modify the size of the event queue of an Event Dispatcher + * + * Input: + * evd_handle + * evd_qlen + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_STATE + */ + +DAT_RETURN DAT_API dapl_evd_resize(IN DAT_EVD_HANDLE evd_handle, + IN DAT_COUNT evd_qlen) +{ + DAPL_IA *ia_ptr; + DAPL_EVD *evd_ptr; + DAT_COUNT pend_cnt; + DAT_RETURN dat_status; + + dapl_dbg_log(DAPL_DBG_TYPE_API, "dapl_evd_resize (%p, %d)\n", + evd_handle, evd_qlen); + + if (DAPL_BAD_HANDLE(evd_handle, DAPL_MAGIC_EVD)) { + dat_status = DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE1); + goto bail; + } + + evd_ptr = (DAPL_EVD *) evd_handle; + ia_ptr = evd_ptr->header.owner_ia; + + if (evd_qlen == evd_ptr->qlen) { + dat_status = DAT_SUCCESS; + goto bail; + } + + if (evd_qlen > ia_ptr->hca_ptr->ia_attr.max_evd_qlen) { + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG2); + goto bail; + } + + dapl_os_lock(&evd_ptr->header.lock); + + /* Don't try to resize if we are actively waiting */ + if (evd_ptr->evd_state == DAPL_EVD_STATE_WAITED) { + dapl_os_unlock(&evd_ptr->header.lock); + dat_status = DAT_ERROR(DAT_INVALID_STATE, 0); + goto bail; + } + + pend_cnt = dapls_rbuf_count(&evd_ptr->pending_event_queue); + if (pend_cnt > evd_qlen) { + dapl_os_unlock(&evd_ptr->header.lock); + dat_status = DAT_ERROR(DAT_INVALID_STATE, 0); + goto bail; + } + + dat_status = dapls_ib_cq_resize(evd_ptr->header.owner_ia, + evd_ptr, &evd_qlen); + if (dat_status != DAT_SUCCESS) { + dapl_os_unlock(&evd_ptr->header.lock); + goto bail; + } + + dat_status = dapls_evd_event_realloc(evd_ptr, evd_qlen); + if (dat_status != DAT_SUCCESS) { + dapl_os_unlock(&evd_ptr->header.lock); + goto bail; + } + + dapl_os_unlock(&evd_ptr->header.lock); + + bail: + return dat_status; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_evd_un_async_error_callb.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_evd_un_async_error_callb.c new file mode 100644 index 00000000..8b3f1bb6 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_evd_un_async_error_callb.c @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_evd_un_async_error_callback.c + * + * PURPOSE: implements Unaffiliated callbacks from verbs + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_evd_util.h" +#include "dapl_adapter_util.h" + +/* + * dapl_evd_un_async_error_callback + * + * The callback function registered with verbs for unaffiliated async errors + * + * Input: + * ib_cm_handle, + * ib_cm_event + * cause_ptr + * context (evd) + * + * Output: + * None + * + */ + +void +dapl_evd_un_async_error_callback(IN ib_hca_handle_t ib_hca_handle, + IN ib_error_record_t * cause_ptr, + IN void *context) +{ + DAPL_EVD *async_evd; + DAT_EVENT_NUMBER async_event; + DAT_RETURN dat_status; + + dapl_dbg_log(DAPL_DBG_TYPE_CALLBACK | DAPL_DBG_TYPE_EXCEPTION, + "dapl_evd_un_async_error_callback (%p, %p, %p)\n", + ib_hca_handle, cause_ptr, context); + + if (NULL == context) { + dapl_os_panic("NULL == context\n"); + return; + } + + async_evd = (DAPL_EVD *) context; + DAPL_CNTR(async_evd->header.owner_ia, DCNT_IA_ASYNC_ERROR); + + dat_status = dapls_ib_get_async_event(cause_ptr, &async_event); + + if (dat_status == DAT_SUCCESS) { + /* + * If dapls_ib_get_async_event is not successful, + * an event has been generated by the provider that + * we are not interested in. E.g. LINK_UP. + */ + dapls_evd_post_async_error_event(async_evd, + async_event, + async_evd->header.owner_ia); + } + dapl_dbg_log(DAPL_DBG_TYPE_CALLBACK | DAPL_DBG_TYPE_EXCEPTION, + "dapl_evd_un_async_error_callback () returns\n"); +} diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_evd_util.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_evd_util.c new file mode 100644 index 00000000..40350088 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_evd_util.c @@ -0,0 +1,1522 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_evd_util.c + * + * PURPOSE: Manage EVD Info structure + * + * $Id: dapl_evd_util.c 1410 2006-07-19 17:12:02Z ardavis $ + **********************************************************************/ + +#include "dapl_evd_util.h" +#include "dapl_ia_util.h" +#include "dapl_cno_util.h" +#include "dapl_ring_buffer_util.h" +#include "dapl_adapter_util.h" +#include "dapl_cookie.h" +#include "dapl.h" +#include "dapl_cr_util.h" +#include "dapl_sp_util.h" +#include "dapl_ep_util.h" + +STATIC _INLINE_ void dapli_evd_eh_print_cqe(IN ib_work_completion_t * cqe); + +DAT_RETURN dapli_evd_event_alloc(IN DAPL_EVD * evd_ptr, IN DAT_COUNT qlen); + +char *dapl_event_str(IN DAT_EVENT_NUMBER event_num) +{ +#if defined(DAPL_DBG) + struct dat_event_str { + char *str; + DAT_EVENT_NUMBER num; + }; + static struct dat_event_str events[] = { + {"DAT_DTO_COMPLETION_EVENT", DAT_DTO_COMPLETION_EVENT}, + {"DAT_RMR_BIND_COMPLETION_EVENT", + DAT_RMR_BIND_COMPLETION_EVENT}, + {"DAT_CONNECTION_REQUEST_EVENT", DAT_CONNECTION_REQUEST_EVENT}, + {"DAT_CONNECTION_EVENT_ESTABLISHED", + DAT_CONNECTION_EVENT_ESTABLISHED}, + {"DAT_CONNECTION_EVENT_PEER_REJECTED", + DAT_CONNECTION_EVENT_PEER_REJECTED}, + {"DAT_CONNECTION_EVENT_NON_PEER_REJECTED", + DAT_CONNECTION_EVENT_NON_PEER_REJECTED}, + {"DAT_CONNECTION_EVENT_ACCEPT_COMPLETION_ERROR", + DAT_CONNECTION_EVENT_ACCEPT_COMPLETION_ERROR}, + {"DAT_CONNECTION_EVENT_DISCONNECTED", + DAT_CONNECTION_EVENT_DISCONNECTED}, + {"DAT_CONNECTION_EVENT_BROKEN", DAT_CONNECTION_EVENT_BROKEN}, + {"DAT_CONNECTION_EVENT_TIMED_OUT", + DAT_CONNECTION_EVENT_TIMED_OUT}, + {"DAT_CONNECTION_EVENT_UNREACHABLE", + DAT_CONNECTION_EVENT_UNREACHABLE}, + {"DAT_ASYNC_ERROR_EVD_OVERFLOW", DAT_ASYNC_ERROR_EVD_OVERFLOW}, + {"DAT_ASYNC_ERROR_IA_CATASTROPHIC", + DAT_ASYNC_ERROR_IA_CATASTROPHIC}, + {"DAT_ASYNC_ERROR_EP_BROKEN", DAT_ASYNC_ERROR_EP_BROKEN}, + {"DAT_ASYNC_ERROR_TIMED_OUT", DAT_ASYNC_ERROR_TIMED_OUT}, + {"DAT_ASYNC_ERROR_PROVIDER_INTERNAL_ERROR", + DAT_ASYNC_ERROR_PROVIDER_INTERNAL_ERROR}, + {"DAT_HA_DOWN_TO_1", DAT_HA_DOWN_TO_1}, + {"DAT_HA_UP_TO_MULTI_PATH", DAT_HA_UP_TO_MULTI_PATH}, + {"DAT_SOFTWARE_EVENT", DAT_SOFTWARE_EVENT}, +#ifdef DAT_EXTENSIONS + {"DAT_EXTENSION_EVENT", DAT_EXTENSION_EVENT}, + {"DAT_IB_EXTENSION_RANGE_BASE", DAT_IB_EXTENSION_RANGE_BASE}, + {"DAT_IB_UD_CONNECTION_REQUEST_EVENT", + DAT_IB_EXTENSION_RANGE_BASE + 1}, + {"DAT_IB_UD_CONNECTION_EVENT_ESTABLISHED", + DAT_IB_EXTENSION_RANGE_BASE + 2}, + {"DAT_IB_UD_CONNECTION_REJECT_EVENT", + DAT_IB_EXTENSION_RANGE_BASE + 3}, + {"DAT_IB_UD_CONNECTION_ERROR_EVENT", + DAT_IB_EXTENSION_RANGE_BASE + 4}, + {"DAT_IW_EXTENSION_RANGE_BASE", DAT_IW_EXTENSION_RANGE_BASE}, +#endif /* DAT_EXTENSIONS */ + {NULL, 0}, + }; + int i; + + for (i = 0; events[i].str; i++) { + if (events[i].num == event_num) + return events[i].str; + } + return "Unknown DAT event?"; +#else + static char str[16]; + sprintf(str, "%x", event_num); + return str; +#endif +} + +/* + * dapls_evd_internal_create + * + * actually create the evd. this is called after all parameter checking + * has been performed in dapl_ep_create. it is also called from dapl_ia_open + * to create the default async evd. + * + * Input: + * ia_ptr + * cno_ptr + * qlen + * evd_flags + * + * Output: + * evd_ptr_ptr + * + * Returns: + * none + * + */ + +DAT_RETURN +dapls_evd_internal_create(DAPL_IA * ia_ptr, + DAPL_CNO * cno_ptr, + DAT_COUNT min_qlen, + DAT_EVD_FLAGS evd_flags, DAPL_EVD ** evd_ptr_ptr) +{ + DAPL_EVD *evd_ptr; + DAT_COUNT cq_len; + DAT_RETURN dat_status; + + dat_status = DAT_SUCCESS; + *evd_ptr_ptr = NULL; + cq_len = min_qlen; + + evd_ptr = dapls_evd_alloc(ia_ptr, cno_ptr, evd_flags, min_qlen); + if (!evd_ptr) { + dat_status = + DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); + goto bail; + } + + /* + * If we are dealing with event streams besides a CQ event stream, + * be conservative and set producer side locking. Otherwise, no. + * Note: CNO is not considered CQ event stream. + */ + evd_ptr->evd_producer_locking_needed = + (!(evd_flags & (DAT_EVD_DTO_FLAG | DAT_EVD_RMR_BIND_FLAG)) || + evd_ptr->cno_ptr); + + /* Before we setup any callbacks, transition state to OPEN. */ + evd_ptr->evd_state = DAPL_EVD_STATE_OPEN; + + if (evd_flags & DAT_EVD_ASYNC_FLAG) { + /* + * There is no cq associate with async evd. Set it to invalid + */ + evd_ptr->ib_cq_handle = IB_INVALID_HANDLE; + + } else if (0 != (evd_flags & ~(DAT_EVD_SOFTWARE_FLAG + | DAT_EVD_CONNECTION_FLAG + | DAT_EVD_CR_FLAG))) { +#if defined(_VENDOR_IBAL_) + /* + * The creation of CQ required a PD (PZ) associated with it and + * we do not have a PD here; therefore, the work-around is that we + * will postpone the creation of the cq till the creation of QP which + * this cq will associate with. + */ + evd_ptr->ib_cq_handle = IB_INVALID_HANDLE; +#else + dat_status = dapls_ib_cq_alloc(ia_ptr, evd_ptr, &cq_len); + if (dat_status != DAT_SUCCESS) { + goto bail; + } + + /* Now reset the cq_len in the attributes, it may have changed */ + evd_ptr->qlen = cq_len; + + dat_status = + dapls_ib_setup_async_callback(ia_ptr, + DAPL_ASYNC_CQ_COMPLETION, + evd_ptr, + (ib_async_handler_t) + dapl_evd_dto_callback, + evd_ptr); + if (dat_status != DAT_SUCCESS) { + goto bail; + } + + dat_status = dapls_set_cq_notify(ia_ptr, evd_ptr); + + if (dat_status != DAT_SUCCESS) { + goto bail; + } +#endif /* _VENDOR_IBAL_ */ + } + + /* We now have an accurate count of events, so allocate them into + * the EVD + */ + dat_status = dapli_evd_event_alloc(evd_ptr, cq_len); + if (dat_status != DAT_SUCCESS) { + goto bail; + } + + dapl_ia_link_evd(ia_ptr, evd_ptr); + *evd_ptr_ptr = evd_ptr; + + bail: + if (dat_status != DAT_SUCCESS) { + if (evd_ptr) { + dapls_evd_dealloc(evd_ptr); + } + } + + return dat_status; +} + +/* + * dapls_evd_alloc + * + * alloc and initialize an EVD struct + * + * Input: + * ia + * + * Output: + * evd_ptr + * + * Returns: + * none + * + */ +DAPL_EVD *dapls_evd_alloc(IN DAPL_IA * ia_ptr, + IN DAPL_CNO * cno_ptr, + IN DAT_EVD_FLAGS evd_flags, IN DAT_COUNT qlen) +{ + DAPL_EVD *evd_ptr; + + /* Allocate EVD */ + evd_ptr = (DAPL_EVD *) dapl_os_alloc(sizeof(DAPL_EVD)); + if (!evd_ptr) { + goto bail; + } + + /* zero the structure */ + dapl_os_memzero(evd_ptr, sizeof(DAPL_EVD)); + +#ifdef DAPL_COUNTERS + /* Allocate counters */ + evd_ptr->cntrs = + dapl_os_alloc(sizeof(DAT_UINT64) * DCNT_EVD_ALL_COUNTERS); + if (evd_ptr->cntrs == NULL) { + dapl_os_free(evd_ptr, sizeof(DAPL_EVD)); + return (NULL); + } + dapl_os_memzero(evd_ptr->cntrs, + sizeof(DAT_UINT64) * DCNT_EVD_ALL_COUNTERS); +#endif /* DAPL_COUNTERS */ + + /* + * initialize the header + */ + evd_ptr->header.provider = ia_ptr->header.provider; + evd_ptr->header.magic = DAPL_MAGIC_EVD; + evd_ptr->header.handle_type = DAT_HANDLE_TYPE_EVD; + evd_ptr->header.owner_ia = ia_ptr; + evd_ptr->header.user_context.as_64 = 0; + evd_ptr->header.user_context.as_ptr = NULL; + dapl_llist_init_entry(&evd_ptr->header.ia_list_entry); + dapl_os_lock_init(&evd_ptr->header.lock); + + /* + * Initialize the body + */ + evd_ptr->evd_state = DAPL_EVD_STATE_INITIAL; + evd_ptr->evd_flags = evd_flags; + evd_ptr->evd_enabled = DAT_TRUE; + evd_ptr->evd_waitable = DAT_TRUE; + evd_ptr->evd_producer_locking_needed = 1; /* Conservative value. */ + evd_ptr->ib_cq_handle = IB_INVALID_HANDLE; + dapl_os_atomic_set(&evd_ptr->evd_ref_count, 0); + evd_ptr->catastrophic_overflow = DAT_FALSE; + evd_ptr->qlen = qlen; + evd_ptr->completion_type = DAPL_EVD_STATE_THRESHOLD; /* FIXME: should be DAPL_EVD_STATE_INIT */ + dapl_os_wait_object_init(&evd_ptr->wait_object); + + evd_ptr->cno_active_count = 0; + if (cno_ptr != NULL) { + /* Take a reference count on the CNO */ + dapl_os_atomic_inc(&cno_ptr->cno_ref_count); + } + evd_ptr->cno_ptr = cno_ptr; + + bail: + return evd_ptr; +} + +/* + * dapls_evd_event_alloc + * + * alloc events into an EVD. + * + * Input: + * evd_ptr + * qlen + * + * Output: + * NONE + * + * Returns: + * DAT_SUCCESS + * ERROR + * + */ +DAT_RETURN dapli_evd_event_alloc(IN DAPL_EVD * evd_ptr, IN DAT_COUNT qlen) +{ + DAT_EVENT *event_ptr; + DAT_COUNT i; + DAT_RETURN dat_status; + + dat_status = DAT_SUCCESS; + + /* Allocate EVENTs */ + event_ptr = + (DAT_EVENT *) dapl_os_alloc(evd_ptr->qlen * sizeof(DAT_EVENT)); + if (event_ptr == NULL) { + dat_status = + DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); + goto bail; + } + evd_ptr->events = event_ptr; + + /* allocate free event queue */ + dat_status = dapls_rbuf_alloc(&evd_ptr->free_event_queue, qlen); + if (dat_status != DAT_SUCCESS) { + goto bail; + } + + /* allocate pending event queue */ + dat_status = dapls_rbuf_alloc(&evd_ptr->pending_event_queue, qlen); + if (dat_status != DAT_SUCCESS) { + goto bail; + } + + /* add events to free event queue */ + for (i = 0; i < evd_ptr->qlen; i++) { + dapls_rbuf_add(&evd_ptr->free_event_queue, (void *)event_ptr); + event_ptr++; + } + + evd_ptr->cq_notified = DAT_FALSE; + evd_ptr->cq_notified_when = 0; + evd_ptr->threshold = 0; + + bail: + return dat_status; +} + +/* + * dapls_evd_event_realloc + * + * realloc events into an EVD. + * + * Input: + * evd_ptr + * qlen + * + * Output: + * NONE + * + * Returns: + * DAT_SUCCESS + * ERROR + * + */ +DAT_RETURN dapls_evd_event_realloc(IN DAPL_EVD * evd_ptr, IN DAT_COUNT qlen) +{ + DAT_EVENT *events; + DAT_COUNT old_qlen; + DAT_COUNT i; + intptr_t diff; + DAT_RETURN dat_status; + + /* Allocate EVENTs */ + events = (DAT_EVENT *) dapl_os_realloc(evd_ptr->events, + qlen * sizeof(DAT_EVENT)); + if (NULL == events) { + dat_status = + DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); + goto bail; + } + + diff = events - evd_ptr->events; + evd_ptr->events = events; + + old_qlen = evd_ptr->qlen; + evd_ptr->qlen = qlen; + + /* reallocate free event queue */ + dat_status = dapls_rbuf_realloc(&evd_ptr->free_event_queue, qlen); + if (dat_status != DAT_SUCCESS) { + goto bail; + } + dapls_rbuf_adjust(&evd_ptr->free_event_queue, diff); + + /* reallocate pending event queue */ + dat_status = dapls_rbuf_realloc(&evd_ptr->pending_event_queue, qlen); + if (dat_status != DAT_SUCCESS) { + goto bail; + } + dapls_rbuf_adjust(&evd_ptr->pending_event_queue, diff); + + /* + * add new events to free event queue. + */ + for (i = old_qlen; i < qlen; i++) { + dapls_rbuf_add(&evd_ptr->free_event_queue, (void *)&events[i]); + } + + bail: + return dat_status; +} + +/* + * dapls_evd_dealloc + * + * Free the passed in EVD structure. If an error occurs, this function + * will clean up all of the internal data structures and report the + * error. + * + * Input: + * evd_ptr + * + * Output: + * none + * + * Returns: + * status + * + */ +DAT_RETURN dapls_evd_dealloc(IN DAPL_EVD * evd_ptr) +{ + DAT_RETURN dat_status; + DAPL_IA *ia_ptr; + + dat_status = DAT_SUCCESS; + + dapl_os_assert(evd_ptr->header.magic == DAPL_MAGIC_EVD); + dapl_os_assert(dapl_os_atomic_read(&evd_ptr->evd_ref_count) == 0); + + /* + * Destroy the CQ first, to keep any more callbacks from coming + * up from it. + */ + evd_ptr->evd_enabled = DAT_FALSE; + if (evd_ptr->ib_cq_handle != IB_INVALID_HANDLE) { + ia_ptr = evd_ptr->header.owner_ia; + + dat_status = dapls_ib_cq_free(ia_ptr, evd_ptr); + if (dat_status != DAT_SUCCESS) { + goto bail; + } + } + + /* + * We should now be safe to invalidate the EVD; reset the + * magic to prevent reuse. + */ + evd_ptr->header.magic = DAPL_MAGIC_INVALID; + + /* Release reference on the CNO if it exists */ + if (evd_ptr->cno_ptr != NULL) { + dapl_os_atomic_dec(&evd_ptr->cno_ptr->cno_ref_count); + evd_ptr->cno_ptr = NULL; + } + + /* If the ring buffer allocation failed, then the dapls_rbuf_destroy */ + /* function will detect that the ring buffer's internal data (ex. base */ + /* pointer) are invalid and will handle the situation appropriately */ + dapls_rbuf_destroy(&evd_ptr->free_event_queue); + dapls_rbuf_destroy(&evd_ptr->pending_event_queue); + + if (evd_ptr->events) { + dapl_os_free(evd_ptr->events, + evd_ptr->qlen * sizeof(DAT_EVENT)); + } + + dapl_os_wait_object_destroy(&evd_ptr->wait_object); + +#ifdef DAPL_COUNTERS + dapl_os_free(evd_ptr->cntrs, + sizeof(DAT_UINT64) * DCNT_EVD_ALL_COUNTERS); +#endif /* DAPL_COUNTERS */ + + dapl_os_free(evd_ptr, sizeof(DAPL_EVD)); + + bail: + return dat_status; +} + +STATIC _INLINE_ char *DAPL_GET_DTO_OP_STR(int op) +{ + static char *dto_ops[] = { + "OP_SEND", + "OP_RECEIVE", + "OP_RDMA_WRITE", + "OP_RDMA_READ" + }; + return ((op < 0 || op > 3) ? "Invalid DTO OP?" : dto_ops[op]); +} + +#if !defined(DAPL_GET_CQE_OP_STR) +#define DAPL_GET_CQE_OP_STR(e) "Unknown CEQ OP String?" +#endif +#if !defined(DAPL_GET_CQE_VENDOR_ERR) +#define DAPL_GET_CQE_VENDOR_ERR(e) 0 +#endif + +/* + * dapli_evd_eh_print_cqe + * + * Input: + * cqe_ptr + * + * Output: + * none + * + * Prints out a CQE for debug purposes + * + */ + +void dapli_evd_eh_print_cqe(IN ib_work_completion_t * cqe_ptr) +{ +#ifdef DAPL_DBG + dapl_dbg_log(DAPL_DBG_TYPE_CALLBACK, + "\t >>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<\n"); + dapl_dbg_log(DAPL_DBG_TYPE_CALLBACK, + "\t dapl_evd_dto_callback : CQE \n"); + dapl_dbg_log(DAPL_DBG_TYPE_CALLBACK, + "\t\t work_req_id %lli\n", DAPL_GET_CQE_WRID(cqe_ptr)); + if (DAPL_GET_CQE_STATUS(cqe_ptr) == 0) { + dapl_dbg_log(DAPL_DBG_TYPE_CALLBACK, + "\t\t op_type: %s\n", + DAPL_GET_CQE_OP_STR(cqe_ptr)); + dapl_dbg_log(DAPL_DBG_TYPE_CALLBACK, + "\t\t bytes_num %d\n", + DAPL_GET_CQE_BYTESNUM(cqe_ptr)); + } + dapl_dbg_log(DAPL_DBG_TYPE_CALLBACK, + "\t\t status %d vendor_err 0x%x\n", + DAPL_GET_CQE_STATUS(cqe_ptr), + DAPL_GET_CQE_VENDOR_ERR(cqe_ptr)); + dapl_dbg_log(DAPL_DBG_TYPE_CALLBACK, + "\t >>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<\n"); +#endif + return; +} + +/* + * Event posting code follows. + */ + +/* + * These next two functions (dapli_evd_get_event and dapli_evd_post_event) + * are a pair. They are always called together, from one of the functions + * at the end of this file (dapl_evd_post_*_event). + * + * Note that if producer side locking is enabled, the first one takes the + * EVD lock and the second releases it. + */ + +/* dapli_evd_get_event + * + * Get an event struct from the evd. The caller should fill in the event + * and call dapl_evd_post_event. + * + * If there are no events available, an overflow event is generated to the + * async EVD handler. + * + * If this EVD required producer locking, a successful return implies + * that the lock is held. + * + * Input: + * evd_ptr + * + * Output: + * event + * + */ + +static DAT_EVENT *dapli_evd_get_event(DAPL_EVD * evd_ptr) +{ + DAT_EVENT *event; + + if (evd_ptr->evd_producer_locking_needed) { + dapl_os_lock(&evd_ptr->header.lock); + } + + event = (DAT_EVENT *) dapls_rbuf_remove(&evd_ptr->free_event_queue); + + /* Release the lock if it was taken and the call failed. */ + if (!event && evd_ptr->evd_producer_locking_needed) { + dapl_os_unlock(&evd_ptr->header.lock); + } + + return event; +} + +/* dapli_evd_post_event + * + * Post the to the evd. If possible, invoke the evd's CNO. + * Otherwise post the event on the pending queue. + * + * If producer side locking is required, the EVD lock must be held upon + * entry to this function. + * + * Input: + * evd_ptr + * event + * + * Output: + * none + * + */ + +static void +dapli_evd_post_event(IN DAPL_EVD * evd_ptr, IN const DAT_EVENT * event_ptr) +{ + DAT_RETURN dat_status; + DAPL_CNO *cno_to_trigger = NULL; + + dapl_dbg_log(DAPL_DBG_TYPE_EVD, "%s: %s evd %p state %d\n", + __FUNCTION__, dapl_event_str(event_ptr->event_number), + evd_ptr, evd_ptr->evd_state); + + dat_status = dapls_rbuf_add(&evd_ptr->pending_event_queue, + (void *)event_ptr); + dapl_os_assert(dat_status == DAT_SUCCESS); + + dapl_os_assert(evd_ptr->evd_state == DAPL_EVD_STATE_WAITED + || evd_ptr->evd_state == DAPL_EVD_STATE_OPEN); + + if (evd_ptr->evd_state == DAPL_EVD_STATE_OPEN) { + /* No waiter. Arrange to trigger a CNO if it exists. */ + + if (evd_ptr->evd_enabled) { + cno_to_trigger = evd_ptr->cno_ptr; + } + if (evd_ptr->evd_producer_locking_needed) { + dapl_os_unlock(&evd_ptr->header.lock); + } + } else { + /* + * We're in DAPL_EVD_STATE_WAITED. Take the lock if + * we don't have it, recheck, and signal. + */ + if (!evd_ptr->evd_producer_locking_needed) { + dapl_os_lock(&evd_ptr->header.lock); + } + + if (evd_ptr->evd_state == DAPL_EVD_STATE_WAITED + && (dapls_rbuf_count(&evd_ptr->pending_event_queue) + >= evd_ptr->threshold)) { + dapl_os_unlock(&evd_ptr->header.lock); + + if (evd_ptr->evd_flags & (DAT_EVD_DTO_FLAG | DAT_EVD_RMR_BIND_FLAG)) { + dapls_evd_dto_wakeup(evd_ptr); + } else { + dapl_os_wait_object_wakeup(&evd_ptr->wait_object); + } + + } else { + dapl_os_unlock(&evd_ptr->header.lock); + } + } + + if (cno_to_trigger != NULL) { + dapl_internal_cno_trigger(cno_to_trigger, evd_ptr); + } +} + +/* dapli_evd_post_event_nosignal + * + * Post the to the evd. Do not do any wakeup processing. + * This function should only be called if it is known that there are + * no waiters that it is appropriate to wakeup on this EVD. An example + * of such a situation is during internal dat_evd_wait() processing. + * + * If producer side locking is required, the EVD lock must be held upon + * entry to this function. + * + * Input: + * evd_ptr + * event + * + * Output: + * none + * + */ + +static void +dapli_evd_post_event_nosignal(IN DAPL_EVD * evd_ptr, + IN const DAT_EVENT * event_ptr) +{ + DAT_RETURN dat_status; + + dapl_dbg_log(DAPL_DBG_TYPE_EVD, "%s: Called with event %s\n", + __FUNCTION__, dapl_event_str(event_ptr->event_number)); + + dat_status = dapls_rbuf_add(&evd_ptr->pending_event_queue, + (void *)event_ptr); + dapl_os_assert(dat_status == DAT_SUCCESS); + + dapl_os_assert(evd_ptr->evd_state == DAPL_EVD_STATE_WAITED + || evd_ptr->evd_state == DAPL_EVD_STATE_OPEN); + + if (evd_ptr->evd_producer_locking_needed) { + dapl_os_unlock(&evd_ptr->header.lock); + } +} + +/* dapli_evd_format_overflow_event + * + * format an overflow event for posting + * + * Input: + * evd_ptr + * event_ptr + * + * Output: + * none + * + */ +static void +dapli_evd_format_overflow_event(IN DAPL_EVD * evd_ptr, + OUT DAT_EVENT * event_ptr) +{ + DAPL_IA *ia_ptr; + + ia_ptr = evd_ptr->header.owner_ia; + + event_ptr->evd_handle = (DAT_EVD_HANDLE) evd_ptr; + event_ptr->event_number = DAT_ASYNC_ERROR_EVD_OVERFLOW; + event_ptr->event_data.asynch_error_event_data.dat_handle = + (DAT_HANDLE) ia_ptr; +} + +/* dapli_evd_post_overflow_event + * + * post an overflow event + * + * Input: + * async_evd_ptr + * evd_ptr + * + * Output: + * none + * + */ +static void +dapli_evd_post_overflow_event(IN DAPL_EVD * async_evd_ptr, + IN DAPL_EVD * overflow_evd_ptr) +{ + DAT_EVENT *overflow_event; + + /* The overflow_evd_ptr mght be the same as evd. + * In that case we've got a catastrophic overflow. + */ + dapl_log(DAPL_DBG_TYPE_WARN, + " WARNING: overflow event on EVD %p/n", overflow_evd_ptr); + + if (async_evd_ptr == overflow_evd_ptr) { + async_evd_ptr->catastrophic_overflow = DAT_TRUE; + async_evd_ptr->evd_state = DAPL_EVD_STATE_DEAD; + return; + } + + overflow_event = dapli_evd_get_event(overflow_evd_ptr); + if (!overflow_event) { + /* this is not good */ + overflow_evd_ptr->catastrophic_overflow = DAT_TRUE; + overflow_evd_ptr->evd_state = DAPL_EVD_STATE_DEAD; + return; + } + dapli_evd_format_overflow_event(overflow_evd_ptr, overflow_event); + dapli_evd_post_event(overflow_evd_ptr, overflow_event); + + return; +} + +static DAT_EVENT *dapli_evd_get_and_init_event(IN DAPL_EVD * evd_ptr, + IN DAT_EVENT_NUMBER event_number) +{ + DAT_EVENT *event_ptr; + + event_ptr = dapli_evd_get_event(evd_ptr); + if (NULL == event_ptr) { + dapli_evd_post_overflow_event(evd_ptr->header.owner_ia-> + async_error_evd, evd_ptr); + } else { + event_ptr->evd_handle = (DAT_EVD_HANDLE) evd_ptr; + event_ptr->event_number = event_number; + } + + return event_ptr; +} + +DAT_RETURN +dapls_evd_post_cr_arrival_event(IN DAPL_EVD * evd_ptr, + IN DAT_EVENT_NUMBER event_number, + IN DAT_SP_HANDLE sp_handle, + DAT_IA_ADDRESS_PTR ia_address_ptr, + DAT_CONN_QUAL conn_qual, + DAT_CR_HANDLE cr_handle) +{ + DAT_EVENT *event_ptr; + event_ptr = dapli_evd_get_and_init_event(evd_ptr, event_number); + /* + * Note event lock may be held on successful return + * to be released by dapli_evd_post_event(), if provider side locking + * is needed. + */ + + if (event_ptr == NULL) { + return DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, + DAT_RESOURCE_MEMORY); + } + + event_ptr->event_data.cr_arrival_event_data.sp_handle = sp_handle; + event_ptr->event_data.cr_arrival_event_data.local_ia_address_ptr + = ia_address_ptr; + event_ptr->event_data.cr_arrival_event_data.conn_qual = conn_qual; + event_ptr->event_data.cr_arrival_event_data.cr_handle = cr_handle; + + dapli_evd_post_event(evd_ptr, event_ptr); + + return DAT_SUCCESS; +} + +DAT_RETURN +dapls_evd_post_connection_event(IN DAPL_EVD * evd_ptr, + IN DAT_EVENT_NUMBER event_number, + IN DAT_EP_HANDLE ep_handle, + IN DAT_COUNT private_data_size, + IN DAT_PVOID private_data) +{ + DAT_EVENT *event_ptr; + event_ptr = dapli_evd_get_and_init_event(evd_ptr, event_number); + /* + * Note event lock may be held on successful return + * to be released by dapli_evd_post_event(), if provider side locking + * is needed. + */ + + if (event_ptr == NULL) { + return DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, + DAT_RESOURCE_MEMORY); + } + + event_ptr->event_data.connect_event_data.ep_handle = ep_handle; + event_ptr->event_data.connect_event_data.private_data_size + = private_data_size; + event_ptr->event_data.connect_event_data.private_data = private_data; + + dapli_evd_post_event(evd_ptr, event_ptr); + + return DAT_SUCCESS; +} + +DAT_RETURN +dapls_evd_post_async_error_event(IN DAPL_EVD * evd_ptr, + IN DAT_EVENT_NUMBER event_number, + IN DAT_IA_HANDLE ia_handle) +{ + DAT_EVENT *event_ptr; + event_ptr = dapli_evd_get_and_init_event(evd_ptr, event_number); + /* + * Note event lock may be held on successful return + * to be released by dapli_evd_post_event(), if provider side locking + * is needed. + */ + dapl_log(DAPL_DBG_TYPE_WARN, + " WARNING: async event - %s evd=%p/n", + dapl_event_str(event_number), evd_ptr); + + if (event_ptr == NULL) { + return DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, + DAT_RESOURCE_MEMORY); + } + + event_ptr->event_data.asynch_error_event_data.dat_handle = + (DAT_HANDLE) ia_handle; + + dapli_evd_post_event(evd_ptr, event_ptr); + + return DAT_SUCCESS; +} + +DAT_RETURN +dapls_evd_post_software_event(IN DAPL_EVD * evd_ptr, + IN DAT_EVENT_NUMBER event_number, + IN DAT_PVOID pointer) +{ + DAT_EVENT *event_ptr; + event_ptr = dapli_evd_get_and_init_event(evd_ptr, event_number); + /* + * Note event lock may be held on successful return + * to be released by dapli_evd_post_event(), if provider side locking + * is needed. + */ + + if (event_ptr == NULL) { + return DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, + DAT_RESOURCE_MEMORY); + } + + event_ptr->event_data.software_event_data.pointer = pointer; + + dapli_evd_post_event(evd_ptr, event_ptr); + + return DAT_SUCCESS; +} + +/* + * dapls_evd_post_generic_event + * + * Post a generic event type. Not used by all providers + * + * Input: + * evd_ptr + * event_number + * data + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * + */ +DAT_RETURN +dapls_evd_post_generic_event(IN DAPL_EVD * evd_ptr, + IN DAT_EVENT_NUMBER event_number, + IN DAT_EVENT_DATA * data) +{ + DAT_EVENT *event_ptr; + + event_ptr = dapli_evd_get_and_init_event(evd_ptr, event_number); + /* + * Note event lock may be held on successful return + * to be released by dapli_evd_post_event(), if provider side locking + * is needed. + */ + + if (event_ptr == NULL) { + return DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, + DAT_RESOURCE_MEMORY); + } + + event_ptr->event_data = *data; + + dapli_evd_post_event(evd_ptr, event_ptr); + + return DAT_SUCCESS; +} + +#ifdef DAT_EXTENSIONS +DAT_RETURN +dapls_evd_post_cr_event_ext(IN DAPL_SP * sp_ptr, + IN DAT_EVENT_NUMBER event_number, + IN dp_ib_cm_handle_t ib_cm_handle, + IN DAT_COUNT p_size, + IN DAT_PVOID p_data, IN DAT_PVOID ext_data) +{ + DAPL_CR *cr_ptr; + DAPL_EP *ep_ptr; + DAT_EVENT *event_ptr; + DAT_SP_HANDLE sp_handle; + + dapl_os_lock(&sp_ptr->header.lock); + if (sp_ptr->listening == DAT_FALSE) { + dapl_os_unlock(&sp_ptr->header.lock); + dapl_dbg_log(DAPL_DBG_TYPE_CM, + "---> post_cr_event_ext: conn event on down SP\n"); + (void)dapls_ib_reject_connection(ib_cm_handle, + DAT_CONNECTION_EVENT_UNREACHABLE, + 0, NULL); + return DAT_CONN_QUAL_UNAVAILABLE; + } + + /* + * RSP connections only allow a single connection. Close + * it down NOW so we reject any further connections. + */ + if (sp_ptr->header.handle_type == DAT_HANDLE_TYPE_RSP) + sp_ptr->listening = DAT_FALSE; + + dapl_os_unlock(&sp_ptr->header.lock); + + /* allocate new connect request */ + cr_ptr = dapls_cr_alloc(sp_ptr->header.owner_ia); + if (cr_ptr == NULL) + return DAT_INSUFFICIENT_RESOURCES; + + /* Set up the CR */ + cr_ptr->sp_ptr = sp_ptr; /* maintain sp_ptr in case of reject */ + cr_ptr->param.remote_port_qual = 0; + cr_ptr->ib_cm_handle = ib_cm_handle; + cr_ptr->param.remote_ia_address_ptr = + (DAT_IA_ADDRESS_PTR) & cr_ptr->remote_ia_address; + + /* + * Copy the remote address and private data out of the private_data + */ + cr_ptr->param.private_data = cr_ptr->private_data; + cr_ptr->param.private_data_size = p_size; + if (p_size) + dapl_os_memcpy(cr_ptr->private_data, p_data, p_size); + + /* EP will be NULL unless RSP service point */ + ep_ptr = (DAPL_EP *) sp_ptr->ep_handle; + + if (sp_ptr->psp_flags == DAT_PSP_PROVIDER_FLAG) { + DAPL_IA *ia_ptr; + /* + * Never true for RSP connections + * + * Create an EP for the user. If we can't allocate an + * EP we are out of resources and need to tell the + * requestor that we cant help them. + */ + ia_ptr = sp_ptr->header.owner_ia; + ep_ptr = dapl_ep_alloc(ia_ptr, NULL); + if (ep_ptr == NULL) { + dapls_cr_free(cr_ptr); + /* Invoking function will call dapls_ib_cm_reject() */ + return DAT_INSUFFICIENT_RESOURCES; + } + ep_ptr->param.ia_handle = ia_ptr; + ep_ptr->param.local_ia_address_ptr = + (DAT_IA_ADDRESS_PTR) & ia_ptr->hca_ptr->hca_address; + + /* Link the EP onto the IA */ + dapl_ia_link_ep(ia_ptr, ep_ptr); + } + + cr_ptr->param.local_ep_handle = ep_ptr; + + if (ep_ptr != NULL) { + /* Assign valid EP fields: RSP and PSP_PROVIDER_FLAG only */ + if (sp_ptr->psp_flags == DAT_PSP_PROVIDER_FLAG) { + ep_ptr->param.ep_state = + DAT_EP_STATE_TENTATIVE_CONNECTION_PENDING; + } else { + /* RSP */ + dapl_os_assert(sp_ptr->header.handle_type == + DAT_HANDLE_TYPE_RSP); + ep_ptr->param.ep_state = + DAT_EP_STATE_PASSIVE_CONNECTION_PENDING; + } + dapl_ep_link_cm(ep_ptr, ib_cm_handle); + } + + /* link the CR onto the SP so we can pick it up later */ + dapl_sp_link_cr(sp_ptr, cr_ptr); + + /* assign sp_ptr to union to avoid typecast errors from some compilers */ + sp_handle.psp_handle = (DAT_PSP_HANDLE) sp_ptr; + + /* Post the event. */ + + /* + * Note event lock may be held on successful return + * to be released by dapli_evd_post_event(), if provider side locking + * is needed. + */ + event_ptr = dapli_evd_get_and_init_event(sp_ptr->evd_handle, + event_number); + if (event_ptr == NULL) + return DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, + DAT_RESOURCE_MEMORY); + + event_ptr->event_data.cr_arrival_event_data.sp_handle = sp_handle; + event_ptr->event_data.cr_arrival_event_data.local_ia_address_ptr = + (DAT_IA_ADDRESS_PTR) & sp_ptr->header.owner_ia->hca_ptr-> + hca_address; + event_ptr->event_data.cr_arrival_event_data.conn_qual = + sp_ptr->conn_qual; + event_ptr->event_data.cr_arrival_event_data.cr_handle = + (DAT_HANDLE) cr_ptr; + + dapl_os_memcpy(&event_ptr->event_extension_data[0], ext_data, 64); + + dapli_evd_post_event(sp_ptr->evd_handle, event_ptr); + + return DAT_SUCCESS; +} + +DAT_RETURN +dapls_evd_post_connection_event_ext(IN DAPL_EVD * evd_ptr, + IN DAT_EVENT_NUMBER event_number, + IN DAT_EP_HANDLE ep_handle, + IN DAT_COUNT private_data_size, + IN DAT_PVOID private_data, + IN DAT_PVOID ext_data) +{ + DAT_EVENT *event_ptr; + event_ptr = dapli_evd_get_and_init_event(evd_ptr, event_number); + /* + * Note event lock may be held on successful return + * to be released by dapli_evd_post_event(), if provider side locking + * is needed. + */ + if (event_ptr == NULL) + return DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, + DAT_RESOURCE_MEMORY); + + event_ptr->event_data.connect_event_data.ep_handle = ep_handle; + event_ptr->event_data.connect_event_data.private_data_size + = private_data_size; + event_ptr->event_data.connect_event_data.private_data = private_data; + + dapl_os_memcpy(&event_ptr->event_extension_data[0], ext_data, 64); + + dapli_evd_post_event(evd_ptr, event_ptr); + + return DAT_SUCCESS; +} +#endif + +/* + * dapli_evd_cqe_to_event + * + * Convert a CQE into an event structure. + * + * Input: + * evd_ptr + * cqe_ptr + * + * Output: + * event_ptr + * + * Returns: + * none + * + */ +static void +dapli_evd_cqe_to_event(IN DAPL_EVD * evd_ptr, + IN void *cqe_ptr, OUT DAT_EVENT * event_ptr) +{ + DAPL_EP *ep_ptr; + DAPL_COOKIE *cookie; + DAT_DTO_COMPLETION_STATUS dto_status; + DAPL_COOKIE_BUFFER *buffer; + + /* + * All that can be relied on if the status is bad is the status + * and WRID. + */ + dto_status = dapls_ib_get_dto_status(cqe_ptr); + + cookie = (DAPL_COOKIE *) (uintptr_t) DAPL_GET_CQE_WRID(cqe_ptr); + dapl_os_assert((NULL != cookie)); + + ep_ptr = cookie->ep; + dapl_os_assert((NULL != ep_ptr)); + if (ep_ptr->header.magic != DAPL_MAGIC_EP) { + /* ep may have been freed, just return */ + return; + } + + dapls_io_trc_update_completion(ep_ptr, cookie, dto_status); + + event_ptr->evd_handle = (DAT_EVD_HANDLE) evd_ptr; + + switch (cookie->type) { + case DAPL_COOKIE_TYPE_DTO: + { +#ifdef DAT_EXTENSIONS + /* Extended via request post or message receive */ + if ((cookie->val.dto.type == DAPL_DTO_TYPE_EXTENSION) || + (cookie->val.dto.type == DAPL_DTO_TYPE_RECV && + DAPL_GET_CQE_OPTYPE(cqe_ptr) != OP_RECEIVE)) { + dapls_cqe_to_event_extension(ep_ptr, cookie, + cqe_ptr, + event_ptr); + if (cookie->val.dto.type == DAPL_DTO_TYPE_RECV) + dapls_cookie_dealloc(&ep_ptr-> + recv_buffer, + cookie); + else + dapls_cookie_dealloc(&ep_ptr-> + req_buffer, + cookie); + break; + } +#endif + + if (DAPL_DTO_TYPE_RECV == cookie->val.dto.type) + buffer = &ep_ptr->recv_buffer; + else + buffer = &ep_ptr->req_buffer; + + event_ptr->event_number = DAT_DTO_COMPLETION_EVENT; + event_ptr->event_data.dto_completion_event_data. + ep_handle = cookie->ep; + event_ptr->event_data.dto_completion_event_data. + user_cookie = cookie->val.dto.cookie; + event_ptr->event_data.dto_completion_event_data.status = + dto_status; + + if (cookie->val.dto.type == DAPL_DTO_TYPE_SEND || + cookie->val.dto.type == DAPL_DTO_TYPE_RDMA_WRITE) { + /* Get size from DTO; CQE value may be off. */ + event_ptr->event_data.dto_completion_event_data. + transfered_length = cookie->val.dto.size; + } else { + event_ptr->event_data.dto_completion_event_data. + transfered_length = + DAPL_GET_CQE_BYTESNUM(cqe_ptr); + } + + dapls_cookie_dealloc(buffer, cookie); + break; + } + + case DAPL_COOKIE_TYPE_RMR: + { + event_ptr->event_number = DAT_RMR_BIND_COMPLETION_EVENT; + + event_ptr->event_data.rmr_completion_event_data. + rmr_handle = cookie->val.rmr.rmr; + event_ptr->event_data.rmr_completion_event_data. + user_cookie = cookie->val.rmr.cookie; + if (dto_status == DAT_DTO_SUCCESS) { + event_ptr->event_data.rmr_completion_event_data. + status = DAT_RMR_BIND_SUCCESS; + dapl_os_assert((DAPL_GET_CQE_OPTYPE(cqe_ptr)) == + OP_BIND_MW); + } else { + dapl_dbg_log(DAPL_DBG_TYPE_DTO_COMP_ERR, + " MW bind completion ERROR: %d: op %#x ep: %p\n", + dto_status, + DAPL_GET_CQE_OPTYPE(cqe_ptr), + ep_ptr); + event_ptr->event_data.rmr_completion_event_data. + status = DAT_RMR_OPERATION_FAILED; + dapl_os_atomic_dec(&cookie->val.rmr.rmr->lmr-> + lmr_ref_count); + } + + dapls_cookie_dealloc(&ep_ptr->req_buffer, cookie); + break; + } + default: + { + dapl_os_assert(!"Invalid Operation type"); + break; + } + } /* end switch */ + + /* + * Most error DTO ops result in disconnecting the EP. See + * IBTA Vol 1.1, Chapter 10,Table 68, for expected effect on + * state. + */ + if ((dto_status != DAT_DTO_SUCCESS) && + (dto_status != DAT_DTO_ERR_FLUSHED)) { + DAPL_EVD *evd_ptr; + + /* + * If we are connected, generate disconnect and generate an + * event. We may be racing with other disconnect ops, so we + * need to check. We may also be racing CM connection events, + * requiring us to check for connection pending states too. + */ + dapl_os_lock(&ep_ptr->header.lock); + if (ep_ptr->param.ep_state == DAT_EP_STATE_CONNECTED || + ep_ptr->param.ep_state == + DAT_EP_STATE_ACTIVE_CONNECTION_PENDING + || ep_ptr->param.ep_state == + DAT_EP_STATE_PASSIVE_CONNECTION_PENDING + || ep_ptr->param.ep_state == + DAT_EP_STATE_COMPLETION_PENDING) + { + ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECTED; + dapl_os_unlock(&ep_ptr->header.lock); + dapls_io_trc_dump(ep_ptr, cqe_ptr, dto_status); + + /* Let the other side know we have disconnected */ + (void)dapls_ib_disconnect(ep_ptr, + DAT_CLOSE_ABRUPT_FLAG); + + /* ... and clean up the local side */ + evd_ptr = (DAPL_EVD *) ep_ptr->param.connect_evd_handle; + dapl_sp_remove_ep (ep_ptr); + if (evd_ptr != NULL) { + dapls_evd_post_connection_event(evd_ptr, + DAT_CONNECTION_EVENT_BROKEN, + (DAT_HANDLE) + ep_ptr, 0, 0); + } + } else { + dapl_os_unlock(&ep_ptr->header.lock); + } + + dapl_log(DAPL_DBG_TYPE_ERR, + "DTO completion ERR: status %d, op %s, vendor_err 0x%x - %s\n", + DAPL_GET_CQE_STATUS(cqe_ptr), + DAPL_GET_DTO_OP_STR(cookie->val.dto.type), + DAPL_GET_CQE_VENDOR_ERR(cqe_ptr), + inet_ntoa(((struct sockaddr_in *)&ep_ptr-> + remote_ia_address)->sin_addr)); + } +} + +/* + * dapls_evd_copy_cq + * + * Copy all entries on a CQ associated with the EVD onto that EVD + * Up to caller to handle races, if any. Note that no EVD waiters will + * be awoken by this copy. + * + * Input: + * evd_ptr + * + * Output: + * None + * + * Returns: + * none + * + */ +void dapls_evd_copy_cq(DAPL_EVD * evd_ptr) +{ + ib_work_completion_t cur_cqe; + DAT_RETURN dat_status; + DAT_EVENT *event; + + if (evd_ptr->ib_cq_handle == IB_INVALID_HANDLE) { + /* Nothing to do if no CQ. */ + return; + } + + while (1) { + dat_status = + dapls_ib_completion_poll(evd_ptr->header.owner_ia->hca_ptr, + evd_ptr, &cur_cqe); + + if (dat_status != DAT_SUCCESS) { + break; + } + + /* For debugging. */ + dapli_evd_eh_print_cqe(&cur_cqe); + + /* + * Can use DAT_DTO_COMPLETION_EVENT because dapli_evd_cqe_to_event + * will overwrite. + */ + + event = + dapli_evd_get_and_init_event(evd_ptr, + DAT_DTO_COMPLETION_EVENT); + if (event == NULL) { + /* We've already attempted the overflow post; return. */ + return; + } + + dapli_evd_cqe_to_event(evd_ptr, &cur_cqe, event); + + dapli_evd_post_event_nosignal(evd_ptr, event); + } + + if (DAT_GET_TYPE(dat_status) != DAT_QUEUE_EMPTY) { + dapl_dbg_log(DAPL_DBG_TYPE_EVD, + "dapls_evd_copy_cq: dapls_ib_completion_poll returned 0x%x\n", + dat_status); + dapl_os_assert(!"Bad return from dapls_ib_completion_poll"); + } +} + +/* + * dapls_evd_cq_poll_to_event + * + * Attempt to dequeue a single CQE from a CQ and turn it into + * an event. + * + * Input: + * evd_ptr + * + * Output: + * event + * + * Returns: + * Status of operation + * + */ +DAT_RETURN +dapls_evd_cq_poll_to_event(IN DAPL_EVD * evd_ptr, OUT DAT_EVENT * event) +{ + DAT_RETURN dat_status; + ib_work_completion_t cur_cqe; + + dat_status = dapls_ib_completion_poll(evd_ptr->header.owner_ia->hca_ptr, + evd_ptr, &cur_cqe); + if (dat_status == DAT_SUCCESS) { + /* For debugging. */ + dapli_evd_eh_print_cqe(&cur_cqe); + + dapli_evd_cqe_to_event(evd_ptr, &cur_cqe, event); + } + + return dat_status; +} + +#ifdef DAPL_DBG_IO_TRC +/* + * Update I/O completions in the I/O trace buffer. I/O is posted to + * the buffer, then we find it here using the cookie and mark it + * completed with the completion status + */ +void +dapls_io_trc_update_completion(DAPL_EP * ep_ptr, + DAPL_COOKIE * cookie, + DAT_DTO_COMPLETION_STATUS dto_status) +{ + int i; + static unsigned int c_cnt = 1; + + for (i = 0; i < DBG_IO_TRC_QLEN; i++) { + if (ep_ptr->ibt_base[i].cookie == cookie) { + ep_ptr->ibt_base[i].status = dto_status; + ep_ptr->ibt_base[i].done = c_cnt++; + } + } +} + +/* + * Dump the I/O trace buffers + */ +void +dapls_io_trc_dump(DAPL_EP * ep_ptr, + void *cqe_ptr, DAT_DTO_COMPLETION_STATUS dto_status) +{ + struct io_buf_track *ibt; + int i; + int cnt; + + dapl_os_printf("DISCONNECTING: dto_status = %x\n", dto_status); + dapl_os_printf(" OpType = %x\n", + DAPL_GET_CQE_OPTYPE(cqe_ptr)); + dapl_os_printf(" Bytes = %x\n", + DAPL_GET_CQE_BYTESNUM(cqe_ptr)); + dapl_os_printf(" WRID (cookie) = %llx\n", + DAPL_GET_CQE_WRID(cqe_ptr)); + + if (ep_ptr->ibt_dumped == 0) { + + dapl_os_printf("EP %p (qpn %d) I/O trace buffer\n", + ep_ptr, ep_ptr->qpn); + + ep_ptr->ibt_dumped = 1; + ibt = + (struct io_buf_track *)dapls_rbuf_remove(&ep_ptr-> + ibt_queue); + cnt = DBG_IO_TRC_QLEN; + while (ibt != NULL && cnt > 0) { + dapl_os_printf + ("%2d. %3s (%2d, %d) OP: %x cookie %p wqe %p rmv_target_addr %llx rmv_rmr_context %x\n", + cnt, ibt->done == 0 ? "WRK" : "DON", ibt->status, + ibt->done, ibt->op_type, ibt->cookie, ibt->wqe, + ibt->remote_iov.target_address, + ibt->remote_iov.rmr_context); + for (i = 0; i < 3; i++) { + if (ibt->iov[i].segment_length != 0) { + dapl_os_printf + (" (%4llx, %8x, %8llx)\n", + ibt->iov[i].segment_length, + ibt->iov[i].lmr_context, + ibt->iov[i].virtual_address); + } + } + ibt = + (struct io_buf_track *)dapls_rbuf_remove(&ep_ptr-> + ibt_queue); + cnt--; + } + } +} +#endif /* DAPL_DBG_IO_TRC */ + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_evd_util.h b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_evd_util.h new file mode 100644 index 00000000..e5a7c3f6 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_evd_util.h @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dapl_evd_util.h + * + * PURPOSE: Utility defs & routines for the EVD data structure + * + * $Id:$ + * + **********************************************************************/ + +#ifndef _DAPL_EVD_UTIL_H_ +#define _DAPL_EVD_UTIL_H_ + +#include "dapl.h" + +DAT_RETURN +dapls_evd_internal_create ( + IN DAPL_IA *ia_ptr, + IN DAPL_CNO *cno_ptr, + IN DAT_COUNT min_qlen, + IN DAT_EVD_FLAGS evd_flags, + OUT DAPL_EVD **evd_ptr_ptr) ; + +DAPL_EVD * +dapls_evd_alloc ( + IN DAPL_IA *ia_ptr, + IN DAPL_CNO *cno_ptr, + IN DAT_EVD_FLAGS evd_flags, + IN DAT_COUNT qlen) ; + +DAT_RETURN +dapls_evd_dealloc ( + IN DAPL_EVD *evd_ptr) ; + +DAT_RETURN dapls_evd_event_realloc ( + IN DAPL_EVD *evd_ptr, + IN DAT_COUNT qlen); + +/* + * Each of these functions will retrieve a free event from + * the specified EVD, fill in the elements of that event, and + * post the event back to the EVD. If there is no EVD available, + * an overflow event will be posted to the async EVD associated + * with the EVD. + * + * DAT_INSUFFICIENT_RESOURCES will be returned on overflow, + * DAT_SUCCESS otherwise. + */ + +DAT_RETURN +dapls_evd_post_cr_arrival_event ( + IN DAPL_EVD *evd_ptr, + IN DAT_EVENT_NUMBER event_number, + IN DAT_SP_HANDLE sp_handle, + DAT_IA_ADDRESS_PTR ia_address_ptr, + DAT_CONN_QUAL conn_qual, + DAT_CR_HANDLE cr_handle); + +DAT_RETURN +dapls_evd_post_connection_event ( + IN DAPL_EVD *evd_ptr, + IN DAT_EVENT_NUMBER event_number, + IN DAT_EP_HANDLE ep_handle, + IN DAT_COUNT private_data_size, + IN DAT_PVOID private_data); + +DAT_RETURN +dapls_evd_post_async_error_event ( + IN DAPL_EVD *evd_ptr, + IN DAT_EVENT_NUMBER event_number, + IN DAT_IA_HANDLE ia_handle); + +DAT_RETURN +dapls_evd_post_software_event ( + IN DAPL_EVD *evd_ptr, + IN DAT_EVENT_NUMBER event_number, + IN DAT_PVOID pointer); + +DAT_RETURN +dapls_evd_post_generic_event ( + IN DAPL_EVD *evd_ptr, + IN DAT_EVENT_NUMBER event_number, + IN DAT_EVENT_DATA *data); + +#ifdef DAT_EXTENSIONS +DAT_RETURN +dapls_evd_post_cr_event_ext ( + IN DAPL_SP *sp_ptr, + IN DAT_EVENT_NUMBER event_number, + IN dp_ib_cm_handle_t ib_cm_handle, + IN DAT_COUNT p_size, + IN DAT_PVOID p_data, + IN DAT_PVOID ext_data); + +DAT_RETURN +dapls_evd_post_connection_event_ext ( + IN DAPL_EVD *evd_ptr, + IN DAT_EVENT_NUMBER event_number, + IN DAT_EP_HANDLE ep_handle, + IN DAT_COUNT private_data_size, + IN DAT_PVOID private_data, + IN DAT_PVOID ext_data); +#endif + +/************************************* + * dapl internal callbacks functions * + *************************************/ + +/* connection verb callback */ +extern void dapl_evd_connection_callback ( + IN dp_ib_cm_handle_t ib_cm_handle, + IN const ib_cm_events_t ib_cm_events, + IN const void *private_data_ptr, + IN const int private_data_size, + IN const void * context ); + +/* dto verb callback */ +extern void dapl_evd_dto_callback ( + IN ib_hca_handle_t ib_hca_handle, + IN ib_cq_handle_t ib_cq_handle, + IN void* context); + +/* async verb callbacks */ +extern void dapl_evd_un_async_error_callback ( + IN ib_hca_handle_t ib_hca_handle, + IN ib_error_record_t * cause_ptr, + IN void * context); + +extern void dapl_evd_cq_async_error_callback ( + IN ib_hca_handle_t ib_hca_handle, + IN ib_cq_handle_t ib_cq_handle, + IN ib_error_record_t * cause_ptr, + IN void * context); + +extern void dapl_evd_qp_async_error_callback ( + IN ib_hca_handle_t ib_hca_handle, + IN ib_qp_handle_t ib_qp_handle, + IN ib_error_record_t * cause_ptr, + IN void * context); + +extern void dapls_evd_copy_cq ( + DAPL_EVD *evd_ptr); + +extern DAT_RETURN dapls_evd_cq_poll_to_event ( + IN DAPL_EVD *evd_ptr, + OUT DAT_EVENT *event); + +#endif diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_get_consumer_context.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_get_consumer_context.c new file mode 100644 index 00000000..fe780368 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_get_consumer_context.c @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_get_consumer_context.c + * + * PURPOSE: Interface Adapter management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 2 + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" + +/* + * dapl_get_consumer_context + * + * DAPL Requirements Version xxx, 6.2.2.2 + * + * Gets the consumer context from the specified dat_object + * + * Input: + * dat_handle + * + * Output: + * context + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + */ +DAT_RETURN DAT_API +dapl_get_consumer_context(IN DAT_HANDLE dat_handle, OUT DAT_CONTEXT * context) +{ + DAT_RETURN dat_status; + DAPL_HEADER *header; + + dat_status = DAT_SUCCESS; + + header = (DAPL_HEADER *) dat_handle; + if (((header) == NULL) || + DAPL_BAD_PTR(header) || + (header->magic != DAPL_MAGIC_IA && + header->magic != DAPL_MAGIC_EVD && + header->magic != DAPL_MAGIC_EP && + header->magic != DAPL_MAGIC_LMR && + header->magic != DAPL_MAGIC_RMR && + header->magic != DAPL_MAGIC_PZ && + header->magic != DAPL_MAGIC_PSP && + header->magic != DAPL_MAGIC_RSP && + header->magic != DAPL_MAGIC_CR)) { + dat_status = DAT_ERROR(DAT_INVALID_HANDLE, 0); + goto bail; + } + if (context == NULL || DAPL_BAD_PTR(header)) { + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG2); + goto bail; + } + + *context = header->user_context; + + bail: + return dat_status; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_get_handle_type.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_get_handle_type.c new file mode 100644 index 00000000..ac487602 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_get_handle_type.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_get_handle_type.c + * + * PURPOSE: Interface Adapter management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 2 + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" + +/* + * dapl_get_handle_type + * + * DAPL Requirements Version xxx, 6.2.2.6 + * + * Gets the handle type for the given dat_handle + * + * Input: + * dat_handle + * + * Output: + * handle_type + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + */ + +DAT_RETURN DAT_API +dapl_get_handle_type(IN DAT_HANDLE dat_handle, + OUT DAT_HANDLE_TYPE * handle_type) +{ + DAT_RETURN dat_status; + DAPL_HEADER *header; + + dat_status = DAT_SUCCESS; + + header = (DAPL_HEADER *) dat_handle; + if (((header) == NULL) || + DAPL_BAD_PTR(header) || + (header->magic != DAPL_MAGIC_IA && + header->magic != DAPL_MAGIC_EVD && + header->magic != DAPL_MAGIC_EP && + header->magic != DAPL_MAGIC_LMR && + header->magic != DAPL_MAGIC_RMR && + header->magic != DAPL_MAGIC_PZ && + header->magic != DAPL_MAGIC_PSP && + header->magic != DAPL_MAGIC_RSP && + header->magic != DAPL_MAGIC_CR)) { + dat_status = DAT_ERROR(DAT_INVALID_HANDLE, 0); + goto bail; + } + *handle_type = header->handle_type; + + bail: + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_hash.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_hash.c new file mode 100644 index 00000000..0811d7c8 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_hash.c @@ -0,0 +1,478 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_hash.c + * + * PURPOSE: Hash Table + * Description: + * + * Provides a generic hash table with chaining. + * + * $Id:$ + **********************************************************************/ + +#include "dapl_hash.h" + +/********************************************************************* + * * + * Structures * + * * + *********************************************************************/ + +/* + * A hash table element + */ +typedef struct DAPL_HASH_ELEM { + struct DAPL_HASH_ELEM *next_element; + DAPL_HASH_KEY key; + void *datum; +} DAPL_HASH_ELEM; + +/* + * The hash table + */ +struct dapl_hash_table { + unsigned long num_entries; + unsigned long tbl_size; + DAPL_HASH_ELEM *table; + DAPL_OS_LOCK lock; + /* + * statistics - we tally on insert operations, counting + * the number of entries in the whole hash table, as + * well as the length of chains we walk to insert. This + * ignores empty buckets, giving us data on overall table + * occupancy, as well as max/average chain length for + * the buckets used. If our hash function results in + * hot buckets, this will show it. + */ + uint64_t hash_tbl_inserts; /* total inserts ops */ + uint64_t hash_tbl_max; /* max in entire table */ + uint64_t hash_tbl_total; /* total in table */ + uint64_t hash_chn_max; /* longest chain */ + uint64_t hash_chn_total; /* total non-0 lenghts */ +}; + +/********************************************************************* + * * + * Defines * + * * + *********************************************************************/ + +/* datum value in empty table slots (use 0UL or ~0UL as appropriate) */ +#define NO_DATUM_VALUE ((void *) 0UL) +#define NO_DATUM(value) ((value) == NO_DATUM_VALUE) + +/* Lookup macro (which falls back to function to rehash) */ +#define DAPL_HASHLOOKUP( p_table, in_key, out_datum, bucket_head) \ + do { \ + DAPL_HASH_KEY save_key = in_key; \ + DAPL_HASH_ELEM *element = \ + &((p_table)->table)[DAPL_DOHASH(in_key,(p_table)->tbl_size)]; \ + in_key = save_key; \ + if (NO_DATUM(element->datum)) { \ + (bucket_head) = (void *)0; \ + } else if (element->key == (DAPL_HASH_KEY) (in_key)) { \ + (out_datum) = element->datum; \ + (bucket_head) = (void *)element; \ + } else if (element->next_element) { \ + dapli_hash_rehash(element, \ + (in_key), \ + (void **)&(out_datum), \ + (DAPL_HASH_ELEM **)&(bucket_head)); \ + } else { \ + (bucket_head) = (void *)0; \ + }\ + } while (0) + +/********************************************************************* + * * + * Internal Functions * + * * + *********************************************************************/ + +/* + * Rehash the key (used by add and lookup functions) + * + * Inputs: element element to rehash key + * key, datum datum for key head + * head head for list + */ +static void +dapli_hash_rehash(DAPL_HASH_ELEM * element, + DAPL_HASH_KEY key, void **datum, DAPL_HASH_ELEM ** head) +{ + /* + * assume we looked at the contents of element already, + * and start with the next element. + */ + dapl_os_assert(element->next_element); + dapl_os_assert(!NO_DATUM(element->datum)); + + *head = element; + while (1) { + element = element->next_element; + if (!element) { + break; + } + if (element->key == key) { + *datum = element->datum; + return; + } + } + *head = 0; +} + +/* + * Add a new key to the hash table + * + * Inputs: + * table, key and datum to be added + * allow_dup - DAT_TRUE if dups are allowed + * Outputs: + * report_dup - should you care to know + * Returns: + * DAT_TRUE on success + */ +static DAT_BOOLEAN +dapli_hash_add(DAPL_HASH_TABLEP p_table, + DAPL_HASH_KEY key, + void *datum, DAT_BOOLEAN allow_dup, DAT_BOOLEAN * report_dup) +{ + void *olddatum; + DAPL_HASH_KEY hashValue, save_key = key; + DAPL_HASH_ELEM *found; + DAT_BOOLEAN status = DAT_FALSE; + unsigned int chain_len = 0; + + if (report_dup) { + (*report_dup) = DAT_FALSE; + } + + if (NO_DATUM(datum)) { + /* + * Reserved value used for datum + */ + dapl_dbg_log(DAPL_DBG_TYPE_ERR, + "dapli_hash_add () called with magic NO_DATA value (%p) " + "used as datum!\n", datum); + return DAT_FALSE; + } + + DAPL_HASHLOOKUP(p_table, key, olddatum, found); + if (found) { + /* + * key exists already + */ + if (report_dup) { + *report_dup = DAT_TRUE; + } + + if (!allow_dup) { + dapl_dbg_log(DAPL_DBG_TYPE_ERR, + "dapli_hash_add () called with duplicate key (" + F64x ")\n", key); + return DAT_FALSE; + } + } + + hashValue = DAPL_DOHASH(key, p_table->tbl_size); + key = save_key; + if (NO_DATUM(p_table->table[hashValue].datum)) { + /* + * Empty head - just fill it in + */ + p_table->table[hashValue].key = key; + p_table->table[hashValue].datum = datum; + p_table->table[hashValue].next_element = 0; + p_table->num_entries++; + status = DAT_TRUE; + } else { + DAPL_HASH_ELEM *newelement = (DAPL_HASH_ELEM *) + dapl_os_alloc(sizeof(DAPL_HASH_ELEM)); + /* + * Add an element to the end of the chain + */ + if (newelement) { + DAPL_HASH_ELEM *lastelement; + newelement->key = key; + newelement->datum = datum; + newelement->next_element = 0; + for (lastelement = &p_table->table[hashValue]; + lastelement->next_element; + lastelement = lastelement->next_element) { + /* Walk to the end of the chain */ + chain_len++; + } + lastelement->next_element = newelement; + p_table->num_entries++; + status = DAT_TRUE; + } else { + /* allocation failed - should not happen */ + status = DAT_FALSE; + } + } + + /* + * Tally up our counters. chain_len is one less than current chain + * length. + */ + chain_len++; + p_table->hash_tbl_inserts++; + p_table->hash_tbl_total += p_table->num_entries; + p_table->hash_chn_total += chain_len; + if (p_table->num_entries > p_table->hash_tbl_max) { + p_table->hash_tbl_max = p_table->num_entries; + } + if (chain_len > p_table->hash_chn_max) { + p_table->hash_chn_max = chain_len; + } + + return status; +} + +/* + * Remove element from hash bucket + * + * Inputs: + * element, key to be deleted + * Returns: + * DAT_TRUE on success + */ +static DAT_BOOLEAN +dapl_hash_delete_element(DAPL_HASH_ELEM * element, + DAPL_HASH_KEY key, DAPL_HASH_DATA * p_datum) +{ + DAPL_HASH_ELEM *curelement; + DAPL_HASH_ELEM *lastelement; + + lastelement = NULL; + for (curelement = element; + curelement; + lastelement = curelement, curelement = curelement->next_element) { + if (curelement->key == key) { + if (p_datum) { + *p_datum = curelement->datum; + } + if (lastelement) { + /* + * curelement was malloc'd; free it + */ + lastelement->next_element = + curelement->next_element; + dapl_os_free((void *)curelement, + sizeof(DAPL_HASH_ELEM)); + } else { + /* + * curelement is static list head + */ + DAPL_HASH_ELEM *n = curelement->next_element; + if (n) { + /* + * If there is a next element, copy its contents into the + * head and free the original next element. + */ + curelement->key = n->key; + curelement->datum = n->datum; + curelement->next_element = + n->next_element; + dapl_os_free((void *)n, + sizeof(DAPL_HASH_ELEM)); + } else { + curelement->datum = NO_DATUM_VALUE; + } + } + break; + } + } + + return (curelement != NULL ? DAT_TRUE : DAT_FALSE); +} + +/********************************************************************* + * * + * External Functions * + * * + *********************************************************************/ + +/* + * Create a new hash table with at least 'table_size' hash buckets. + */ +DAT_RETURN +dapls_hash_create(IN DAT_COUNT table_size, OUT DAPL_HASH_TABLE ** pp_table) +{ + DAPL_HASH_TABLE *p_table; + DAT_COUNT table_length = table_size * sizeof(DAPL_HASH_ELEM); + DAT_RETURN dat_status; + DAT_COUNT i; + + dapl_os_assert(pp_table); + dat_status = DAT_SUCCESS; + + /* Allocate hash table */ + p_table = dapl_os_alloc(sizeof(DAPL_HASH_TABLE)); + if (NULL == p_table) { + dat_status = + DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); + goto bail; + } + + /* Init hash table, allocate and init and buckets */ + dapl_os_memzero(p_table, sizeof(DAPL_HASH_TABLE)); + p_table->tbl_size = table_size; + p_table->table = (DAPL_HASH_ELEM *) dapl_os_alloc(table_length); + if (NULL == p_table->table) { + dapl_os_free(p_table, sizeof(DAPL_HASH_TABLE)); + dat_status = + DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); + goto bail; + } + + dapl_os_lock_init(&p_table->lock); + for (i = 0; i < table_size; i++) { + p_table->table[i].datum = NO_DATUM_VALUE; + p_table->table[i].key = 0; + p_table->table[i].next_element = 0; + } + + *pp_table = p_table; + + bail: + return DAT_SUCCESS; +} + +/* + * Destroy a hash table + */ +DAT_RETURN dapls_hash_free(IN DAPL_HASH_TABLE * p_table) +{ + dapl_os_assert(p_table && p_table->table); + + dapl_os_lock_destroy(&p_table->lock); + dapl_os_free(p_table->table, + sizeof(DAPL_HASH_ELEM) * p_table->tbl_size); + dapl_os_free(p_table, sizeof(DAPL_HASH_TABLE)); + + return DAT_SUCCESS; +} + +/* + * Returns the number of elements stored in the table + */ + +DAT_RETURN dapls_hash_size(IN DAPL_HASH_TABLE * p_table, OUT DAT_COUNT * p_size) +{ + dapl_os_assert(p_table && p_size); + + *p_size = p_table->num_entries; + + return DAT_SUCCESS; +} + +/* + * Inserts the specified data into the table with the given key. + * Duplicates are not expected, and return in error, having done nothing. + */ + +DAT_RETURN +dapls_hash_insert(IN DAPL_HASH_TABLE * p_table, + IN DAPL_HASH_KEY key, IN DAPL_HASH_DATA data) +{ + DAT_RETURN dat_status; + + dapl_os_assert(p_table); + dat_status = DAT_SUCCESS; + + dapl_os_lock(&p_table->lock); + if (!dapli_hash_add(p_table, key, data, DAT_FALSE, NULL)) { + dat_status = + DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); + } + dapl_os_unlock(&p_table->lock); + + return dat_status; +} + +/* + * Searches for the given key. If found, + * DAT_SUCCESS is returned and the associated + * data is returned in the DAPL_HASH_DATA + * pointer if that pointer is not NULL. + */ +DAT_RETURN +dapls_hash_search(IN DAPL_HASH_TABLE * p_table, + IN DAPL_HASH_KEY key, OUT DAPL_HASH_DATA * p_data) +{ + DAT_RETURN dat_status; + void *olddatum; + DAPL_HASH_ELEM *found; + + dapl_os_assert(p_table); + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, 0); + + dapl_os_lock(&p_table->lock); + DAPL_HASHLOOKUP(p_table, key, olddatum, found); + dapl_os_unlock(&p_table->lock); + + if (found) { + if (p_data) { + *p_data = olddatum; + } + dat_status = DAT_SUCCESS; + } + + return dat_status; +} + +DAT_RETURN +dapls_hash_remove(IN DAPL_HASH_TABLE * p_table, + IN DAPL_HASH_KEY key, OUT DAPL_HASH_DATA * p_data) +{ + DAT_RETURN dat_status; + DAPL_HASH_KEY hashValue, save_key = key; + + dapl_os_assert(p_table); + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, 0); + + if (p_table->num_entries == 0) { + dapl_dbg_log(DAPL_DBG_TYPE_ERR, + "dapls_hash_remove () called on empty hash table!\n"); + return dat_status; + } + + hashValue = DAPL_DOHASH(key, p_table->tbl_size); + key = save_key; + dapl_os_lock(&p_table->lock); + if (dapl_hash_delete_element(&p_table->table[hashValue], key, p_data)) { + p_table->num_entries--; + dat_status = DAT_SUCCESS; + } + dapl_os_unlock(&p_table->lock); + + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_hash.h b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_hash.h new file mode 100644 index 00000000..8242bf08 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_hash.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dapl_hash.h + * + * PURPOSE: Utility defs & routines for the hash data structure + * + * $Id:$ + **********************************************************************/ + +#ifndef _DAPL_HASH_H_ +#define _DAPL_HASH_H_ + +#include "dapl.h" + + +/********************************************************************* + * * + * Defines * + * * + *********************************************************************/ + +/* + * Hash table size. + * + * Default is small; use the larger sample values for hash tables + * known to be heavily used. The sample values chosen are the + * largest primes below 2^8, 2^9, and 2^10. + */ +#define DAPL_DEF_HASHSIZE 251 +#define DAPL_MED_HASHSIZE 509 +#define DAPL_LRG_HASHSIZE 1021 + +#define DAPL_HASH_TABLE_DEFAULT_CAPACITY DAPL_DEF_HASHSIZE + +/* The hash function */ +#if defined(__KDAPL__) +#define DAPL_DOHASH(key,hashsize) dapl_os_mod64(key,hashsize) +#else +#define DAPL_DOHASH(key,hashsize) ((uint64_t)((key) % (hashsize))) +#endif /* defined(__KDAPL__) */ + + +/********************************************************************* + * * + * Function Prototypes * + * * + *********************************************************************/ + +extern DAT_RETURN +dapls_hash_create( + IN DAT_COUNT capacity, + OUT DAPL_HASH_TABLE **pp_table); + +extern DAT_RETURN +dapls_hash_free( + IN DAPL_HASH_TABLE *p_table); + +extern DAT_RETURN +dapls_hash_size( + IN DAPL_HASH_TABLE *p_table, + OUT DAT_COUNT *p_size); + +extern DAT_RETURN +dapls_hash_insert( + IN DAPL_HASH_TABLE *p_table, + IN DAPL_HASH_KEY key, + IN DAPL_HASH_DATA data); + +extern DAT_RETURN +dapls_hash_search( + IN DAPL_HASH_TABLE *p_table, + IN DAPL_HASH_KEY key, + OUT DAPL_HASH_DATA *p_data); + +extern DAT_RETURN +dapls_hash_remove( + IN DAPL_HASH_TABLE *p_table, + IN DAPL_HASH_KEY key, + OUT DAPL_HASH_DATA *p_data); + + +#endif /* _DAPL_HASH_H_ */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_hca_util.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_hca_util.c new file mode 100644 index 00000000..4a8a4006 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_hca_util.c @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_hca_util.c + * + * PURPOSE: Manage HCA structure + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_adapter_util.h" +#include "dapl_provider.h" +#include "dapl_hca_util.h" + +/* + * dapl_hca_alloc + * + * alloc and initialize an HCA struct + * + * Input: + * name + * port + * + * Output: + * hca_ptr + * + * Returns: + * none + * + */ +DAPL_HCA *dapl_hca_alloc(char *name, char *port) +{ + DAPL_HCA *hca_ptr; + + hca_ptr = dapl_os_alloc(sizeof(DAPL_HCA)); + if (NULL == hca_ptr) { + goto bail; + } + + dapl_os_memzero(hca_ptr, sizeof(DAPL_HCA)); + dapl_os_lock_init(&hca_ptr->lock); + dapl_llist_init_head(&hca_ptr->ia_list_head); + + hca_ptr->name = dapl_os_strdup(name); + if (NULL == hca_ptr->name) { + goto bail; + } + + hca_ptr->ib_hca_handle = IB_INVALID_HANDLE; + hca_ptr->port_num = dapl_os_strtol(port, NULL, 0); + + return (hca_ptr); + + bail: + if (NULL != hca_ptr) + dapl_os_free(hca_ptr, sizeof(DAPL_HCA)); + + return NULL; +} + +/* + * dapl_hca_free + * + * free an IA INFO struct + * + * Input: + * hca_ptr + * + * Output: + * none + * + * Returns: + * none + * + */ +void dapl_hca_free(DAPL_HCA * hca_ptr) +{ + dapl_os_free(hca_ptr->name, dapl_os_strlen(hca_ptr->name) + 1); + dapl_os_free(hca_ptr, sizeof(DAPL_HCA)); +} + +/* + * dapl_hca_link_ia + * + * Add an ia to the HCA structure + * + * Input: + * hca_ptr + * ia_ptr + * + * Output: + * none + * + * Returns: + * none + * + */ +void dapl_hca_link_ia(IN DAPL_HCA * hca_ptr, IN DAPL_IA * ia_ptr) +{ + dapl_os_lock(&hca_ptr->lock); + dapl_llist_add_head(&hca_ptr->ia_list_head, + &ia_ptr->hca_ia_list_entry, ia_ptr); + dapl_os_unlock(&hca_ptr->lock); +} + +/* + * dapl_hca_unlink_ia + * + * Remove an ia from the hca info structure + * + * Input: + * hca_ptr + * ia_ptr + * + * Output: + * none + * + * Returns: + * none + * + */ +void dapl_hca_unlink_ia(IN DAPL_HCA * hca_ptr, IN DAPL_IA * ia_ptr) +{ + dapl_os_lock(&hca_ptr->lock); + /* + * If an error occurred when we were opening the IA it + * will not be linked on the list; don't unlink an unlinked + * list! + */ + if (!dapl_llist_is_empty(&hca_ptr->ia_list_head)) { + dapl_llist_remove_entry(&hca_ptr->ia_list_head, + &ia_ptr->hca_ia_list_entry); + } + dapl_os_unlock(&hca_ptr->lock); +} diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_hca_util.h b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_hca_util.h new file mode 100644 index 00000000..fd006ed6 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_hca_util.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dapl_hca_util.h + * + * PURPOSE: Utility defs & routines for the HCA data structure + * + * $Id:$ + **********************************************************************/ + +#ifndef _DAPL_HCA_UTIL_H_ +#define _DAPL_HCA_UTIL_H_ + +#include "dapl.h" + +DAPL_HCA * +dapl_hca_alloc ( char *name, + char *port ) ; + +void +dapl_hca_free ( DAPL_HCA *hca_ptr ) ; + +void +dapl_hca_link_ia ( + IN DAPL_HCA *hca_ptr, + IN DAPL_IA *ia_info ) ; + +void +dapl_hca_unlink_ia ( + IN DAPL_HCA *hca_ptr, + IN DAPL_IA *ia_info ) ; + + +#endif diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ia_close.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ia_close.c new file mode 100644 index 00000000..75c7bca2 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ia_close.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ia_close.c + * + * PURPOSE: Interface Adapter management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 2 + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_ia_util.h" + +/* + * dapl_ia_close + * + * DAPL Requirements Version xxx, 6.2.1.2 + * + * Close a provider, clean up resources, etc. + * + * Input: + * ia_handle + * + * Output: + * none + * + * Return Values: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + */ +DAT_RETURN DAT_API +dapl_ia_close(IN DAT_IA_HANDLE ia_handle, IN DAT_CLOSE_FLAGS ia_flags) +{ + DAPL_IA *ia_ptr; + DAT_RETURN dat_status; + + dapl_dbg_log(DAPL_DBG_TYPE_API, + "dapl_ia_close (%p, %d)\n", ia_handle, ia_flags); + + ia_ptr = (DAPL_IA *) ia_handle; + + if (DAPL_BAD_HANDLE(ia_ptr, DAPL_MAGIC_IA)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_IA); + goto bail; + } + + if (DAT_CLOSE_ABRUPT_FLAG == ia_flags) { + dat_status = dapl_ia_abrupt_close(ia_ptr); + } else if (DAT_CLOSE_GRACEFUL_FLAG == ia_flags) { + dat_status = dapl_ia_graceful_close(ia_ptr); + } else { + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG2); + } + + bail: + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ia_ha.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ia_ha.c new file mode 100644 index 00000000..b09edbd3 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ia_ha.c @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2007 Intel Corporation. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ia_ha.c + * + * PURPOSE: Interface Adapter High Availability - optional feature + * Description: Described in DAPL 2.0 API, Chapter 5, section 9 + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_provider.h" +#include "dapl_evd_util.h" +#include "dapl_hca_util.h" +#include "dapl_ia_util.h" +#include "dapl_adapter_util.h" + +/* + * dapl_ia_ha + * + * DAPL Requirements Version xxx, 5.9 + * + * Queries for provider HA support + * + * Input: + * ia_handle + * provider name + * + * Output: + * answer + * + * Returns: + * DAT_SUCCESS + * DAT_MODEL_NOT_SUPPORTED + */ + +DAT_RETURN DAT_API dapl_ia_ha(IN DAT_IA_HANDLE ia_handle, /* ia_handle */ + IN const DAT_NAME_PTR provider, /* provider */ + OUT DAT_BOOLEAN * answer) +{ /* answer */ + return DAT_MODEL_NOT_SUPPORTED; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ia_open.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ia_open.c new file mode 100644 index 00000000..edead04d --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ia_open.c @@ -0,0 +1,462 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ia_open.c + * + * PURPOSE: Interface Adapter management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 2 + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_provider.h" +#include "dapl_evd_util.h" +#include "dapl_hca_util.h" +#include "dapl_ia_util.h" +#include "dapl_adapter_util.h" + +/* + * LOCAL PROTOTYPES + */ +#ifdef IBHOSTS_NAMING +void dapli_assign_hca_ip_address(DAPL_HCA * hca_ptr, char *device_name); +#endif /* IBHOSTS_NAMING */ + +void dapli_hca_cleanup(DAPL_HCA * hca_ptr, DAT_BOOLEAN dec_ref); + +/* + * dapl_ia_open + * + * DAPL Requirements Version xxx, 6.2.1.1 + * + * Open a provider and return a handle. The handle enables the user + * to invoke operations on this provider. + * + * The dat_ia_open call is actually part of the DAT registration module. + * That function maps the DAT_NAME parameter of dat_ia_open to a DAT_PROVIDER, + * and calls this function. + * + * Input: + * provider + * async_evd_qlen + * async_evd_handle_ptr + * + * Output: + * async_evd_handle + * ia_handle + * + * Return Values: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + * DAT_INVALID_HANDLE + * DAT_PROVIDER_NOT_FOUND (returned by dat registry if necessary) + */ +DAT_RETURN DAT_API +dapl_ia_open(IN const DAT_NAME_PTR name, + IN DAT_COUNT async_evd_qlen, + INOUT DAT_EVD_HANDLE * async_evd_handle_ptr, + OUT DAT_IA_HANDLE * ia_handle_ptr) +{ + DAT_RETURN dat_status; + DAT_PROVIDER *provider; + DAPL_HCA *hca_ptr; + DAPL_IA *ia_ptr; + DAPL_EVD *evd_ptr; + + dat_status = DAT_SUCCESS; + hca_ptr = NULL; + ia_ptr = NULL; + + dapl_dbg_log(DAPL_DBG_TYPE_API, + "dapl_ia_open (%s, %d, %p, %p)\n", + name, async_evd_qlen, async_evd_handle_ptr, ia_handle_ptr); + + dat_status = dapl_provider_list_search(name, &provider); + if (DAT_SUCCESS != dat_status) { + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG1); + goto bail; + } + + /* ia_handle_ptr and async_evd_handle_ptr cannot be NULL */ + if (ia_handle_ptr == NULL) { + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG4); + goto bail; + } + if (async_evd_handle_ptr == NULL) { + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG3); + goto bail; + } + + /* initialize the caller's OUT param */ + *ia_handle_ptr = DAT_HANDLE_NULL; + + /* get the hca_ptr */ + hca_ptr = (DAPL_HCA *) provider->extension; + + /* + * Open the HCA if it has not been done before. + */ + dapl_os_lock(&hca_ptr->lock); + if (hca_ptr->ib_hca_handle == IB_INVALID_HANDLE) { + /* register with the HW */ + dat_status = dapls_ib_open_hca(hca_ptr->name, hca_ptr); + + if (dat_status != DAT_SUCCESS) { + dapl_dbg_log(DAPL_DBG_TYPE_ERR, + "dapls_ib_open_hca failed %x\n", + dat_status); + dapl_os_unlock(&hca_ptr->lock); + goto bail; + } + + /* + * Obtain the IP address associated with this name and HCA. + */ +#ifdef IBHOSTS_NAMING + dapli_assign_hca_ip_address(hca_ptr, name); +#endif /* IBHOSTS_NAMING */ + + /* + * Obtain IA attributes from the HCA to limit certain + * operations. + * If using DAPL_ATS naming, ib_query_hca will also set the ip + * address. + */ + dat_status = dapls_ib_query_hca(hca_ptr, + &hca_ptr->ia_attr, + NULL, &hca_ptr->hca_address); + if (dat_status != DAT_SUCCESS) { + dapli_hca_cleanup(hca_ptr, DAT_FALSE); + dapl_os_unlock(&hca_ptr->lock); + goto bail; + } + } + + /* Take a reference on the hca_handle */ + dapl_os_atomic_inc(&hca_ptr->handle_ref_count); + dapl_os_unlock(&hca_ptr->lock); + + /* Allocate and initialize ia structure */ + ia_ptr = dapl_ia_alloc(provider, hca_ptr); + if (!ia_ptr) { + dapl_os_lock(&hca_ptr->lock); + dapli_hca_cleanup(hca_ptr, DAT_TRUE); + dapl_os_unlock(&hca_ptr->lock); + dat_status = + DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); + goto bail; + } + + /* we need an async EVD for this IA + * use the one passed in (if non-NULL) or create one + */ + + evd_ptr = (DAPL_EVD *) * async_evd_handle_ptr; + if (evd_ptr) { + if (DAPL_BAD_HANDLE(evd_ptr, DAPL_MAGIC_EVD) || + !(evd_ptr->evd_flags & DAT_EVD_ASYNC_FLAG)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, + DAT_INVALID_HANDLE_EVD_ASYNC); + goto bail; + } + + /* InfiniBand allows only 1 asychronous event handler per HCA */ + /* (see InfiniBand Spec, release 1.1, vol I, section 11.5.2, */ + /* page 559). */ + /* */ + /* We only need to make sure that this EVD's CQ belongs to */ + /* the same HCA as is being opened. */ + + if (evd_ptr->header.owner_ia->hca_ptr->ib_hca_handle != + hca_ptr->ib_hca_handle) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, + DAT_INVALID_HANDLE_EVD_ASYNC); + goto bail; + } + + ia_ptr->cleanup_async_error_evd = DAT_FALSE; + ia_ptr->async_error_evd = evd_ptr; + } else { + /* Verify we have >0 length, and let the provider check the size */ + if (async_evd_qlen <= 0) { + dat_status = + DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG2); + goto bail; + } + dat_status = dapls_evd_internal_create(ia_ptr, NULL, /* CNO ptr */ + async_evd_qlen, + DAT_EVD_ASYNC_FLAG, + &evd_ptr); + if (dat_status != DAT_SUCCESS) { + goto bail; + } + + dapl_os_atomic_inc(&evd_ptr->evd_ref_count); + + dapl_os_lock(&hca_ptr->lock); + if (hca_ptr->async_evd != (DAPL_EVD *) 0) { +#if 0 + /* + * The async EVD for this HCA has already been assigned. + * It's an error to try and assign another one. + * + * However, we need to somehow allow multiple IAs + * off of the same HCA. The right way to do this + * is by dispatching events off the HCA to the appropriate + * IA, but we aren't there yet. So for now we create + * the EVD but don't connect it to anything. + */ + dapl_os_atomic_dec(&evd_ptr->evd_ref_count); + dapl_evd_free(evd_ptr); + dat_status = + DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG4); + goto bail; +#endif + dapl_os_unlock(&hca_ptr->lock); + } else { + hca_ptr->async_evd = evd_ptr; + dapl_os_unlock(&hca_ptr->lock); + + /* Register the handlers associated with the async EVD. */ + dat_status = dapls_ia_setup_callbacks(ia_ptr, evd_ptr); + if (dat_status != DAT_SUCCESS) { + /* Assign the EVD so it gets cleaned up */ + ia_ptr->cleanup_async_error_evd = DAT_TRUE; + ia_ptr->async_error_evd = evd_ptr; + goto bail; + } + } + + ia_ptr->cleanup_async_error_evd = DAT_TRUE; + ia_ptr->async_error_evd = evd_ptr; + } + + dat_status = DAT_SUCCESS; + *ia_handle_ptr = ia_ptr; + *async_evd_handle_ptr = evd_ptr; + + bail: + if (dat_status != DAT_SUCCESS) { + if (ia_ptr) { + /* This will release the async EVD if needed. */ + dapl_ia_close(ia_ptr, DAT_CLOSE_ABRUPT_FLAG); + } + } + + dapl_dbg_log(DAPL_DBG_TYPE_RTN, + "dapl_ia_open () returns 0x%x\n", dat_status); + + return dat_status; +} + +/* + * dapli_hca_cleanup + * + * Clean up partially allocated HCA stuff. Strictly to make cleanup + * simple. + */ +void dapli_hca_cleanup(DAPL_HCA * hca_ptr, DAT_BOOLEAN dec_ref) +{ + dapls_ib_close_hca(hca_ptr); + hca_ptr->ib_hca_handle = IB_INVALID_HANDLE; + if (dec_ref == DAT_TRUE) { + dapl_os_atomic_dec(&hca_ptr->handle_ref_count); + } +} + +#ifdef IBHOSTS_NAMING + +char *dapli_get_adapter_num(char *device_name); + +void dapli_setup_dummy_addr(IN DAPL_HCA * hca_ptr, IN char *hca_name); +/* + * dapli_assign_hca_ip_address + * + * Obtain the IP address of the passed in name, which represents a + * port on the hca. There are three methods here to obtain the + * appropriate IP address, each with their own shortcoming: + * 1) IPOIB_NAMING. Requires the implementation of the IPoIB + * interface defined in include/dapl/ipoib_names.h. This is + * not the recommended interface as IPoIB is limited at + * the point we need to obtain an IP address on the + * passive side of a connection. The code supporting this + * implementation has been removed. + * + * 2) IBHOSTS. An entry exists in DNS and in the /etc/dapl/ibhosts + * file. The immediate drawback here is that we must dictate + * how to name the interface, which is a stated DAPL non-goal. + * In the broader perspective, this method requires us to xmit + * the IP address in the private data of a connection, which has + * other fun problems. This is the default method and is known to + * work, but it has problems. + * + * 3) Obtain the IP address from the driver, which has registered + * the address with the SA for retrieval. + * + * + * Input: + * hca_ptr Pointer to HCA structure + * device_name Name of device as reported by the provider + * + * Output: + * none + * + * Returns: + * char * to string number + */ +void dapli_assign_hca_ip_address(DAPL_HCA * hca_ptr, char *device_name) +{ + char *adapter_num; +#define NAMELEN 128 + struct addrinfo *addr; + char hostname[NAMELEN]; + char *str; + int rc; + + /* + * Obtain the IP address of the adapter. This is a simple + * scheme that creates a name that must appear available to + * DNS, e.g. it must be in the local site DNS or in the local + * /etc/hosts file, etc. + * + * -ib + * + * This scheme obviously doesn't work with adapters from + * multiple vendors, but will suffice in common installations. + */ + + rc = gethostname(hostname, NAMELEN); + + /* guarantee NUL termination if hostname gets truncated */ + hostname[NAMELEN - 1] = '\0'; + + /* + * Strip off domain info if it exists (e.g. mynode.mydomain.com) + */ + for (str = hostname; *str && *str != '.';) { + str++; + } + if (*str == '.') { + *str = '\0'; + } + strcat(hostname, "-ib"); + adapter_num = dapli_get_adapter_num(device_name); + strcat(hostname, adapter_num); + + rc = dapls_osd_getaddrinfo(hostname, &addr); + + if (rc != 0) { + /* Not registered in DNS, provide a dummy value */ + dapli_setup_dummy_addr(hca_ptr, hostname); + } else { + hca_ptr->hca_address = *((DAT_SOCK_ADDR6 *) addr->ai_addr); + dapls_osd_freeaddrinfo(addr); + } +} + +/* + * dapli_stup_dummy_addr + * + * Set up a dummy local address for the HCA. Things are not going + * to work too well if this happens. + * We call this routine if: + * - remote host adapter name is not in DNS + * - IPoIB implementation is not correctly set up + * - Similar nonsense. + * + * Input: + * hca_ptr + * rhost_name Name of remote adapter + * + * Output: + * none + * + * Returns: + * none + */ +void dapli_setup_dummy_addr(IN DAPL_HCA * hca_ptr, IN char *rhost_name) +{ + struct sockaddr_in *si; + + /* Not registered in DNS, provide a dummy value */ + dapl_dbg_log(DAPL_DBG_TYPE_WARN, + "WARNING: <%s> not registered in DNS, using dummy IP value\n", + rhost_name); + si = (struct sockaddr_in *)&hca_ptr->hca_address; + hca_ptr->hca_address.sin6_family = AF_INET; + si->sin_addr.s_addr = 0x01020304; +} + +/* + * dapls_get_adapter_num + * + * Given a device name, return a string of the device number + * + * Input: + * device_name Name of device as reported by the provider + * + * Output: + * none + * + * Returns: + * char * to string number + */ +char *dapli_get_adapter_num(char *device_name) +{ + static char *zero = "0"; + char *p; + + /* + * Optimisticaly simple algorithm: the device number appears at + * the end of the device name string. Device that do not end + * in a number are by default "0". + */ + + for (p = device_name; *p; p++) { + if (isdigit(*p)) { + return p; + } + } + + return zero; +} +#endif /* IBHOSTS_NAMING */ + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ia_query.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ia_query.c new file mode 100644 index 00000000..d530d72d --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ia_query.c @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ia_query.c + * + * PURPOSE: Interface Adapter management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 2 + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_adapter_util.h" +#include "dapl_vendor.h" + +/* + * dapl_ia_query + * + * DAPL Requirements Version xxx, 6.2.1.3 + * + * Provide the consumer with Interface Adapter and Provider parameters. + * + * Input: + * ia_handle + * ia_mask + * provider_mask + * + * Output: + * async_evd_handle + * ia_parameters + * provider_parameters + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + */ +DAT_RETURN DAT_API +dapl_ia_query(IN DAT_IA_HANDLE ia_handle, + OUT DAT_EVD_HANDLE * async_evd_handle, + IN DAT_IA_ATTR_MASK ia_attr_mask, + OUT DAT_IA_ATTR * ia_attr, + IN DAT_PROVIDER_ATTR_MASK provider_attr_mask, + OUT DAT_PROVIDER_ATTR * provider_attr) +{ + DAPL_IA *ia_ptr; + DAT_RETURN dat_status; + struct evd_merge_type { + DAT_BOOLEAN array[6][6]; + } *evd_merge; + DAT_BOOLEAN val; + int i; + int j; + + dapl_dbg_log(DAPL_DBG_TYPE_API, + "dapl_ia_query (%p, %p, 0x%llx, %p, 0x%x, %p)\n", + ia_handle, + async_evd_handle, + ia_attr_mask, ia_attr, provider_attr_mask, provider_attr); + + ia_ptr = (DAPL_IA *) ia_handle; + dat_status = DAT_SUCCESS; + + if (DAPL_BAD_HANDLE(ia_ptr, DAPL_MAGIC_IA)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_IA); + goto bail; + } + + if (NULL != async_evd_handle) { + *async_evd_handle = ia_ptr->async_error_evd; + } + + if (ia_attr_mask & DAT_IA_FIELD_ALL) { + if (NULL == ia_attr) { + dat_status = + DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG4); + goto bail; + } + + /* + * Obtain parameters from the HCA. Protect against multiple + * IAs beating on the HCA at the same time. + */ + dat_status = + dapls_ib_query_hca(ia_ptr->hca_ptr, ia_attr, NULL, NULL); + if (dat_status != DAT_SUCCESS) { + goto bail; + } + } + + if (ia_attr_mask & ~DAT_IA_FIELD_ALL) { + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG3); + goto bail; + } + + if (provider_attr_mask & DAT_PROVIDER_FIELD_ALL) { + if (NULL == provider_attr) { + dat_status = + DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG6); + goto bail; + } + + strncpy(provider_attr->provider_name, + ia_ptr->header.provider->device_name, + DAT_NAME_MAX_LENGTH); + provider_attr->provider_version_major = VN_PROVIDER_MAJOR; + provider_attr->provider_version_minor = VN_PROVIDER_MINOR; + provider_attr->dapl_version_major = DAT_VERSION_MAJOR; + provider_attr->dapl_version_minor = DAT_VERSION_MINOR; + provider_attr->lmr_mem_types_supported = + DAT_MEM_TYPE_VIRTUAL | DAT_MEM_TYPE_LMR; +#if VN_MEM_SHARED_VIRTUAL_SUPPORT > 0 && !defined(__KDAPL__) + provider_attr->lmr_mem_types_supported |= + DAT_MEM_TYPE_SHARED_VIRTUAL; +#endif + provider_attr->iov_ownership_on_return = DAT_IOV_CONSUMER; + provider_attr->dat_qos_supported = DAT_QOS_BEST_EFFORT; + provider_attr->completion_flags_supported = + DAT_COMPLETION_DEFAULT_FLAG; + provider_attr->is_thread_safe = DAT_FALSE; + /* + * N.B. The second part of the following equation will evaluate + * to 0 unless IBHOSTS_NAMING is enabled. + */ + provider_attr->max_private_data_size = + dapls_ib_private_data_size(ia_ptr->hca_ptr) - + (sizeof(DAPL_PRIVATE) - DAPL_MAX_PRIVATE_DATA_SIZE); + provider_attr->supports_multipath = DAT_FALSE; + provider_attr->ep_creator = DAT_PSP_CREATES_EP_NEVER; + provider_attr->optimal_buffer_alignment = DAT_OPTIMAL_ALIGNMENT; + /* The value of pz_support may vary by transport */ + provider_attr->num_provider_specific_attr = 0; + provider_attr->provider_specific_attr = NULL; +#if !defined(__KDAPL__) + provider_attr->pz_support = DAT_PZ_UNIQUE; +#endif /* !KDAPL */ + + /* + * Query for provider specific attributes + */ + dapls_query_provider_specific_attr(ia_ptr, provider_attr); + + /* + * Set up evd_stream_merging_supported options. Note there is + * one bit per allowable combination, using the ordinal + * position of the DAT_EVD_FLAGS as positions in the + * array. e.g. + * [0][0] is DAT_EVD_SOFTWARE_FLAG | DAT_EVD_SOFTWARE_FLAG, + * [0][1] is DAT_EVD_SOFTWARE_FLAG | DAT_EVD_CR_FLAG, and + * [2][4] is DAT_EVD_DTO_FLAG | DAT_EVD_RMR_BIND_FLAG + * + * Most combinations are true, so initialize the array that way. + * Then finish by resetting the bad combinations. + * + * DAT_EVD_ASYNC_FLAG is not supported. InfiniBand only allows + * a single asynchronous event handle per HCA, and the first + * dat_ia_open forces the creation of the only one that can be + * used. We disallow the user from creating an ASYNC EVD here. + */ + + evd_merge = + (struct evd_merge_type *)&provider_attr-> + evd_stream_merging_supported[0][0]; + val = DAT_TRUE; + for (i = 0; i < 6; i++) { + if (i > 4) { + /* ASYNC EVD is 5, so entire row will be 0 */ + val = DAT_FALSE; + } + for (j = 0; j < 5; j++) { + evd_merge->array[i][j] = val; + } + /* Set the ASYNC_EVD column to FALSE */ + evd_merge->array[i][5] = DAT_FALSE; + } + +#ifndef DAPL_MERGE_CM_DTO + /* + * If an implementation supports CM and DTO completions on + * the same EVD then DAPL_MERGE_CM_DTO should be set to + * skip the following code + */ + /* DAT_EVD_DTO_FLAG | DAT_EVD_CONNECTION_FLAG */ + evd_merge->array[2][3] = DAT_FALSE; + /* DAT_EVD_CONNECTION_FLAG | DAT_EVD_DTO_FLAG */ + evd_merge->array[3][2] = DAT_FALSE; +#endif /* DAPL_MERGE_CM_DTO */ + } + + bail: + if (dat_status != DAT_SUCCESS) { + dapl_dbg_log(DAPL_DBG_TYPE_RTN, + "dapl_ia_query () returns 0x%x\n", dat_status); + } + + return dat_status; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ia_util.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ia_util.c new file mode 100644 index 00000000..2208c23b --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ia_util.c @@ -0,0 +1,1140 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ia_util.c + * + * PURPOSE: Manage IA Info structure + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_hca_util.h" +#include "dapl_ia_util.h" +#include "dapl_sp_util.h" +#include "dapl_evd_util.h" +#include "dapl_cno_util.h" +#include "dapl_cr_util.h" +#include "dapl_adapter_util.h" + +/* Internal prototype */ +void dapli_ia_release_hca(DAPL_HCA * hca_ptr); + +/* + * dapl_ia_alloc + * + * alloc and initialize an IA INFO struct + * + * Input: + * none + * + * Output: + * ia_ptr + * + * Returns: + * none + * + */ +DAPL_IA *dapl_ia_alloc(DAT_PROVIDER * provider, DAPL_HCA * hca_ptr) +{ + DAPL_IA *ia_ptr; + + /* Allocate IA */ + ia_ptr = (DAPL_IA *) dapl_os_alloc(sizeof(DAPL_IA)); + if (ia_ptr == NULL) { + return (NULL); + } + + /* zero the structure */ + dapl_os_memzero(ia_ptr, sizeof(DAPL_IA)); + +#ifdef DAPL_COUNTERS + /* Allocate counters */ + ia_ptr->cntrs = + dapl_os_alloc(sizeof(DAT_UINT64) * DCNT_IA_ALL_COUNTERS); + if (ia_ptr->cntrs == NULL) { + dapl_os_free(ia_ptr, sizeof(DAPL_IA)); + return (NULL); + } + dapl_os_memzero(ia_ptr->cntrs, + sizeof(DAT_UINT64) * DCNT_IA_ALL_COUNTERS); +#endif /* DAPL_COUNTERS */ + + /* + * initialize the header + */ + ia_ptr->header.provider = provider; + ia_ptr->header.magic = DAPL_MAGIC_IA; + ia_ptr->header.handle_type = DAT_HANDLE_TYPE_IA; + ia_ptr->header.owner_ia = ia_ptr; + ia_ptr->header.user_context.as_64 = 0; + ia_ptr->header.user_context.as_ptr = NULL; + dapl_llist_init_entry(&ia_ptr->header.ia_list_entry); + dapl_os_lock_init(&ia_ptr->header.lock); + + /* + * initialize the body + */ + ia_ptr->hca_ptr = hca_ptr; + ia_ptr->async_error_evd = NULL; + ia_ptr->cleanup_async_error_evd = DAT_FALSE; + dapl_llist_init_entry(&ia_ptr->hca_ia_list_entry); + dapl_llist_init_head(&ia_ptr->ep_list_head); + dapl_llist_init_head(&ia_ptr->lmr_list_head); + dapl_llist_init_head(&ia_ptr->rmr_list_head); + dapl_llist_init_head(&ia_ptr->pz_list_head); + dapl_llist_init_head(&ia_ptr->evd_list_head); + dapl_llist_init_head(&ia_ptr->cno_list_head); + dapl_llist_init_head(&ia_ptr->rsp_list_head); + dapl_llist_init_head(&ia_ptr->psp_list_head); + + dapl_hca_link_ia(hca_ptr, ia_ptr); + + return (ia_ptr); +} + +/* + * dapl_ia_abrupt_close + * + * Performs an abrupt close of the IA + * + * Input: + * ia_ptr + * + * Output: + * none + * + * Returns: + * status + * + */ + +DAT_RETURN dapl_ia_abrupt_close(IN DAPL_IA * ia_ptr) +{ + DAT_RETURN dat_status; + DAPL_EP *ep_ptr, *next_ep_ptr; + DAPL_LMR *lmr_ptr, *next_lmr_ptr; + DAPL_RMR *rmr_ptr, *next_rmr_ptr; + DAPL_PZ *pz_ptr, *next_pz_ptr; + DAPL_EVD *evd_ptr, *next_evd_ptr; + DAPL_CNO *cno_ptr, *next_cno_ptr; + DAPL_SP *sp_ptr, *next_sp_ptr; /* for PSP and RSP queues */ + DAPL_CR *cr_ptr, *next_cr_ptr; + DAPL_HCA *hca_ptr; + + dat_status = DAT_SUCCESS; + + /* + * clear all the data structures associated with the IA. + * this must be done in order (rmr,rsp) before (ep lmr psp) before + * (pz evd) + * + * Note that in all the following we can leave the loop either + * when we run out of entries, or when we get back to the head + * if we end up skipping an entry. + */ + + rmr_ptr = (dapl_llist_is_empty(&ia_ptr->rmr_list_head) + ? NULL : dapl_llist_peek_head(&ia_ptr->rmr_list_head)); + while (rmr_ptr != NULL) { + next_rmr_ptr = dapl_llist_next_entry(&ia_ptr->rmr_list_head, + &rmr_ptr->header. + ia_list_entry); + dat_status = dapl_rmr_free(rmr_ptr); + if (dat_status != DAT_SUCCESS) { + dapl_dbg_log(DAPL_DBG_TYPE_WARN, + "ia_close(ABRUPT): rmr_free(%p) returns %x\n", + rmr_ptr, dat_status); + } + rmr_ptr = next_rmr_ptr; + } + + sp_ptr = (dapl_llist_is_empty(&ia_ptr->rsp_list_head) + ? NULL : dapl_llist_peek_head(&ia_ptr->rsp_list_head)); + while (sp_ptr != NULL) { + next_sp_ptr = dapl_llist_next_entry(&ia_ptr->rsp_list_head, + &sp_ptr->header. + ia_list_entry); + dat_status = dapl_rsp_free(sp_ptr); + if (dat_status != DAT_SUCCESS) { + dapl_dbg_log(DAPL_DBG_TYPE_WARN, + "ia_close(ABRUPT): rsp_free(%p) returns %x\n", + sp_ptr, dat_status); + } + sp_ptr = next_sp_ptr; + } + + ep_ptr = (dapl_llist_is_empty(&ia_ptr->ep_list_head) + ? NULL : dapl_llist_peek_head(&ia_ptr->ep_list_head)); + while (ep_ptr != NULL) { + next_ep_ptr = dapl_llist_next_entry(&ia_ptr->ep_list_head, + &ep_ptr->header. + ia_list_entry); + /* + * Issue a disconnect if the EP needs it + */ + if (ep_ptr->param.ep_state == DAT_EP_STATE_CONNECTED || + ep_ptr->param.ep_state == DAT_EP_STATE_DISCONNECTED || + ep_ptr->param.ep_state == + DAT_EP_STATE_ACTIVE_CONNECTION_PENDING + || ep_ptr->param.ep_state == DAT_EP_STATE_COMPLETION_PENDING + || ep_ptr->param.ep_state == + DAT_EP_STATE_DISCONNECT_PENDING) { + dat_status = + dapl_ep_disconnect(ep_ptr, DAT_CLOSE_ABRUPT_FLAG); + if (dat_status != DAT_SUCCESS) { + dapl_dbg_log(DAPL_DBG_TYPE_WARN, + "ia_close(ABRUPT): ep_disconnect(%p) returns %x\n", + ep_ptr, dat_status); + } + } + /* force the EP into error state to force flush all posted DTOs. */ + { + DAT_EP_ATTR ep_attr; + DAT_NAMED_ATTR ep_state; + + dapl_os_memzero(&ep_attr, sizeof(DAT_EP_ATTR)); + ep_state.name = (char *)IB_QP_STATE; + ep_state.value = (char *)DAPL_QP_STATE_ERROR; + ep_attr.ep_provider_specific_count = 1; + ep_attr.ep_provider_specific = &ep_state; + + (void)dapls_ib_qp_modify(ia_ptr, ep_ptr, &ep_attr); + } + + dat_status = dapl_ep_free(ep_ptr); + if (dat_status != DAT_SUCCESS) { + dapl_dbg_log(DAPL_DBG_TYPE_WARN, + "ia_close(ABRUPT): ep_free(%p) returns %x\n", + ep_ptr, dat_status); + } + ep_ptr = next_ep_ptr; + } + + lmr_ptr = (dapl_llist_is_empty(&ia_ptr->lmr_list_head) + ? NULL : dapl_llist_peek_head(&ia_ptr->lmr_list_head)); + while (lmr_ptr != NULL) { + next_lmr_ptr = dapl_llist_next_entry(&ia_ptr->lmr_list_head, + &lmr_ptr->header. + ia_list_entry); + dat_status = dapl_lmr_free(lmr_ptr); + if (dat_status != DAT_SUCCESS) { + dapl_dbg_log(DAPL_DBG_TYPE_WARN, + "ia_close(ABRUPT): lmr_free(%p) returns %x\n", + lmr_ptr, dat_status); + } + lmr_ptr = next_lmr_ptr; + } + + sp_ptr = (dapl_llist_is_empty(&ia_ptr->psp_list_head) + ? NULL : dapl_llist_peek_head(&ia_ptr->psp_list_head)); + while (sp_ptr != NULL) { + /* + * Shut down the PSP so we get no further callbacks. There + * should be no competing threads after this. + */ + dat_status = dapls_ib_remove_conn_listener(ia_ptr, sp_ptr); + if (dat_status != DAT_SUCCESS) { + dapl_dbg_log(DAPL_DBG_TYPE_WARN, + "ia_close(ABRUPT): psp cannot remove listener, returns %x\n", + dat_status); + } + + next_sp_ptr = dapl_llist_next_entry(&ia_ptr->psp_list_head, + &sp_ptr->header. + ia_list_entry); + + /* Remove CR's from this PSP and clean them up */ + cr_ptr = dapl_llist_is_empty(&sp_ptr->cr_list_head) ? NULL : + dapl_llist_peek_head(&sp_ptr->cr_list_head); + while (cr_ptr != NULL) { + next_cr_ptr = + dapl_llist_next_entry(&sp_ptr->cr_list_head, + &cr_ptr->header. + ia_list_entry); + /* Remove the CR from the queue & cleanup */ + dapl_os_lock(&sp_ptr->header.lock); + dapl_sp_remove_cr(sp_ptr, cr_ptr); + dapl_os_unlock(&sp_ptr->header.lock); + + dapls_cr_free(cr_ptr); + cr_ptr = next_cr_ptr; + } + + dat_status = dapl_psp_free(sp_ptr); + if (dat_status != DAT_SUCCESS) { + dapl_dbg_log(DAPL_DBG_TYPE_WARN, + "ia_close(ABRUPT): psp_free(%p) returns %x\n", + sp_ptr, dat_status); + } + + sp_ptr = next_sp_ptr; + } + + pz_ptr = (dapl_llist_is_empty(&ia_ptr->pz_list_head) + ? NULL : dapl_llist_peek_head(&ia_ptr->pz_list_head)); + while (pz_ptr != NULL) { + next_pz_ptr = dapl_llist_next_entry(&ia_ptr->pz_list_head, + &pz_ptr->header. + ia_list_entry); + dat_status = dapl_pz_free(pz_ptr); + if (dat_status != DAT_SUCCESS) { + dapl_dbg_log(DAPL_DBG_TYPE_WARN, + "ia_close(ABRUPT): pz_free(%p) returns %x\n", + pz_ptr, dat_status); + } + pz_ptr = next_pz_ptr; + } + + /* + * EVDs are tricky; we want to release all except for the async + * EVD. That EVD needs to stick around until after we close the + * HCA, to accept any async events that occur. So we cycle through + * the list with dapl_llist_next_entry instead of dapl_llist_is_empty. + */ + evd_ptr = (dapl_llist_is_empty(&ia_ptr->evd_list_head) + ? NULL : dapl_llist_peek_head(&ia_ptr->evd_list_head)); + while (evd_ptr != NULL) { + next_evd_ptr = dapl_llist_next_entry(&ia_ptr->evd_list_head, + &evd_ptr->header. + ia_list_entry); + if (evd_ptr == ia_ptr->async_error_evd) { +#if !defined(__KDAPL__) + /* Don't delete the EVD, but break any CNO connections. */ + dapl_evd_disable(evd_ptr); + dapl_evd_modify_cno(evd_ptr, DAT_HANDLE_NULL); +#endif /* __KDAPL__ */ + } else { + /* it isn't the async EVD; delete it. */ + dat_status = dapl_evd_free(evd_ptr); + if (dat_status != DAT_SUCCESS) { + dapl_dbg_log(DAPL_DBG_TYPE_WARN, + "ia_close(ABRUPT): evd_free(%p) returns %x\n", + evd_ptr, dat_status); + } + } + evd_ptr = next_evd_ptr; + } + + cno_ptr = (dapl_llist_is_empty(&ia_ptr->cno_list_head) + ? NULL : dapl_llist_peek_head(&ia_ptr->cno_list_head)); + while (cno_ptr != NULL) { + next_cno_ptr = dapl_llist_next_entry(&ia_ptr->cno_list_head, + &cno_ptr->header. + ia_list_entry); +#if !defined(__KDAPL__) + if (cno_ptr->cno_waiters > 0) { + /* Notify the waiter the IA is going away: see uDAPL 1.1 spec, + * 6.3.2.3 + */ + dapl_internal_cno_trigger(cno_ptr, NULL); + } + /* clean up the CNO */ + dat_status = dapl_cno_free(cno_ptr); + if (dat_status != DAT_SUCCESS) { + dapl_dbg_log(DAPL_DBG_TYPE_WARN, + "ia_close(ABRUPT): cno_free(%p) returns %x\n", + cno_ptr, dat_status); + } +#endif /* __KDAPL__ */ + cno_ptr = next_cno_ptr; + } + + hca_ptr = ia_ptr->hca_ptr; + + /* + * Free the async EVD, shutting down callbacks from the HCA. + */ + if (ia_ptr->async_error_evd && + (DAT_TRUE == ia_ptr->cleanup_async_error_evd)) { + dat_status = dapls_ia_teardown_callbacks(ia_ptr); + + dapl_os_atomic_dec(&ia_ptr->async_error_evd->evd_ref_count); + dat_status = dapl_evd_free(ia_ptr->async_error_evd); + + if (DAT_SUCCESS != dat_status) { + dapl_dbg_log(DAPL_DBG_TYPE_WARN, + "ia_close(ABRUPT): evd_free(%p) returns %x\n", + ia_ptr->async_error_evd, dat_status); + } + + ia_ptr->async_error_evd = NULL; + } + + /* + * Release our reference on the hca_handle. If we are the last + * one, close it + */ + dapli_ia_release_hca(hca_ptr); + + dapls_ia_free(ia_ptr); + + return DAT_SUCCESS; /* Abrupt close can't fail. */ +} + +/* + * dapl_ia_graceful_close + * + * Performs an graceful close of the IA + * + * Input: + * ia_ptr + * + * Output: + * none + * + * Returns: + * status + * + */ + +DAT_RETURN dapl_ia_graceful_close(IN DAPL_IA * ia_ptr) +{ + DAT_RETURN dat_status; + DAT_RETURN cur_dat_status; + DAPL_EVD *evd_ptr; + DAPL_LLIST_ENTRY *entry; + DAPL_HCA *hca_ptr; + + dat_status = DAT_SUCCESS; + + if (!dapl_llist_is_empty(&ia_ptr->rmr_list_head) || + !dapl_llist_is_empty(&ia_ptr->rsp_list_head) || + !dapl_llist_is_empty(&ia_ptr->ep_list_head) || + !dapl_llist_is_empty(&ia_ptr->lmr_list_head) || + !dapl_llist_is_empty(&ia_ptr->psp_list_head) || + !dapl_llist_is_empty(&ia_ptr->pz_list_head)) { + dat_status = + DAT_ERROR(DAT_INVALID_STATE, DAT_INVALID_STATE_IA_IN_USE); + goto bail; + } + + /* if the async evd does not need to be cleaned up */ + /* (ie. it was not created by dapl_ia_open) */ + /* then the evd list should be empty */ + if (DAT_FALSE == ia_ptr->cleanup_async_error_evd) { + if (!dapl_llist_is_empty(&ia_ptr->evd_list_head)) { + dat_status = + DAT_ERROR(DAT_INVALID_STATE, + DAT_INVALID_STATE_IA_IN_USE); + goto bail; + } + } + /* else the async evd should be the only evd in */ + /* the list. */ + else { + evd_ptr = (dapl_llist_is_empty(&ia_ptr->evd_list_head) + ? NULL : dapl_llist_peek_head(&ia_ptr-> + evd_list_head)); + + if (evd_ptr != NULL && + !(evd_ptr->evd_flags & DAT_EVD_ASYNC_FLAG)) { + dat_status = + DAT_ERROR(DAT_INVALID_STATE, + DAT_INVALID_STATE_IA_IN_USE); + goto bail; + } + + entry = ia_ptr->evd_list_head; + + /* if the async evd is not the only element in the list */ + if (entry->blink != entry->flink) { + dat_status = + DAT_ERROR(DAT_INVALID_STATE, + DAT_INVALID_STATE_IA_IN_USE); + goto bail; + } + + /* + * If the async evd has a non-unary ref count (i.e. it's in + * use by someone besides us. + */ + if (dapl_os_atomic_read(&evd_ptr->evd_ref_count) != 1) { + dat_status = + DAT_ERROR(DAT_INVALID_STATE, + DAT_INVALID_STATE_IA_IN_USE); + goto bail; + } + } + + /* + * We've validated the call; now we can start the teardown. + * Because we're in the IA close routine, we're safe from races with DAPL + * consumers on this IA (operate/destroy races are disallowed in + * DAPL). + */ + hca_ptr = ia_ptr->hca_ptr; + + /* Tear down the async EVD if needed, first shutting down callbacks. */ + if (ia_ptr->async_error_evd && + (DAT_TRUE == ia_ptr->cleanup_async_error_evd)) { + cur_dat_status = dapls_ia_teardown_callbacks(ia_ptr); + if (DAT_SUCCESS != cur_dat_status) { + dat_status = cur_dat_status; + } + dapl_os_atomic_dec(&ia_ptr->async_error_evd->evd_ref_count); + cur_dat_status = dapl_evd_free(ia_ptr->async_error_evd); + if (DAT_SUCCESS != cur_dat_status) { + dat_status = cur_dat_status; + } + + ia_ptr->async_error_evd = NULL; + } + + dapli_ia_release_hca(hca_ptr); + + dapls_ia_free(ia_ptr); + + bail: + return dat_status; +} + +/* + * Release a reference on the HCA handle. If it is 0, close the + * handle. Manipulate under lock to prevent races with threads trying to + * open the HCA. + */ +void dapli_ia_release_hca(DAPL_HCA * hca_ptr) +{ + dapl_os_lock(&hca_ptr->lock); + dapl_os_atomic_dec(&hca_ptr->handle_ref_count); + if (dapl_os_atomic_read(&hca_ptr->handle_ref_count) == 0) { + dapls_ib_close_hca(hca_ptr); + hca_ptr->ib_hca_handle = IB_INVALID_HANDLE; + hca_ptr->async_evd = NULL; + } + dapl_os_unlock(&hca_ptr->lock); +} + +/* + * dapls_ia_free + * + * free an IA INFO struct + * + * Input: + * ia_ptr + * + * Output: + * one + * + * Returns: + * none + * + */ +void dapls_ia_free(DAPL_IA * ia_ptr) +{ + dapl_os_assert(ia_ptr->header.magic == DAPL_MAGIC_IA); + + dapl_os_assert(ia_ptr->async_error_evd == NULL); + dapl_os_assert(dapl_llist_is_empty(&ia_ptr->lmr_list_head)); + dapl_os_assert(dapl_llist_is_empty(&ia_ptr->rmr_list_head)); + dapl_os_assert(dapl_llist_is_empty(&ia_ptr->ep_list_head)); + dapl_os_assert(dapl_llist_is_empty(&ia_ptr->evd_list_head)); + dapl_os_assert(dapl_llist_is_empty(&ia_ptr->cno_list_head)); + dapl_os_assert(dapl_llist_is_empty(&ia_ptr->psp_list_head)); + dapl_os_assert(dapl_llist_is_empty(&ia_ptr->rsp_list_head)); + + /* + * deinitialize the header + */ + dapl_hca_unlink_ia(ia_ptr->hca_ptr, ia_ptr); + ia_ptr->header.magic = DAPL_MAGIC_INVALID; /* reset magic to prevent reuse */ + dapl_os_lock_destroy(&ia_ptr->header.lock); + +#ifdef DAPL_COUNTERS + dapl_os_free(ia_ptr->cntrs, sizeof(DAT_UINT64) * DCNT_IA_ALL_COUNTERS); +#endif /* DAPL_COUNTERS */ + + dapl_os_free(ia_ptr, sizeof(DAPL_IA)); +} + +/* + * dapl_ia_link_ep + * + * Add an ep to the IA structure + * + * Input: + * ia_ptr + * ep_ptr + * + * Output: + * none + * + * Returns: + * none + * + */ +void dapl_ia_link_ep(IN DAPL_IA * ia_ptr, IN DAPL_EP * ep_ptr) +{ + dapl_os_lock(&ia_ptr->header.lock); + dapl_llist_add_head(&ia_ptr->ep_list_head, + &ep_ptr->header.ia_list_entry, ep_ptr); + dapl_os_unlock(&ia_ptr->header.lock); +} + +/* + * dapl_ia_unlink_ep + * + * Remove an ep from the ia info structure + * + * Input: + * ia_ptr + * ep_ptr + * + * Output: + * none + * + * Returns: + * none + * + */ +void dapl_ia_unlink_ep(IN DAPL_IA * ia_ptr, IN DAPL_EP * ep_ptr) +{ + dapl_os_lock(&ia_ptr->header.lock); + dapl_llist_remove_entry(&ia_ptr->ep_list_head, + &ep_ptr->header.ia_list_entry); + dapl_os_unlock(&ia_ptr->header.lock); +} + +/* + * dapl_ia_link_srq + * + * Add an srq to the IA structure + * + * Input: + * ia_ptr + * srq_ptr + * + * Output: + * none + * + * Returns: + * none + * + */ +void dapl_ia_link_srq(IN DAPL_IA * ia_ptr, IN DAPL_SRQ * srq_ptr) +{ + dapl_os_lock(&ia_ptr->header.lock); + dapl_llist_add_head(&ia_ptr->srq_list_head, + &srq_ptr->header.ia_list_entry, srq_ptr); + dapl_os_unlock(&ia_ptr->header.lock); +} + +/* + * dapl_ia_unlink_srq + * + * Remove an srq from the ia info structure + * + * Input: + * ia_ptr + * srq_ptr + * + * Output: + * none + * + * Returns: + * none + * + */ +void dapl_ia_unlink_srq(IN DAPL_IA * ia_ptr, IN DAPL_SRQ * srq_ptr) +{ + dapl_os_lock(&ia_ptr->header.lock); + dapl_llist_remove_entry(&ia_ptr->srq_list_head, + &srq_ptr->header.ia_list_entry); + dapl_os_unlock(&ia_ptr->header.lock); +} + +/* + * dapl_ia_link_lmr + * + * Add an lmr to the IA structure + * + * Input: + * ia_ptr + * lmr_ptr + * + * Output: + * none + * + * Returns: + * none + * + */ +void dapl_ia_link_lmr(IN DAPL_IA * ia_ptr, IN DAPL_LMR * lmr_ptr) +{ + dapl_os_lock(&ia_ptr->header.lock); + dapl_llist_add_head(&ia_ptr->lmr_list_head, + &lmr_ptr->header.ia_list_entry, lmr_ptr); + dapl_os_unlock(&ia_ptr->header.lock); +} + +/* + * dapl_ia_unlink_lmr + * + * Remove an lmr from the ia info structure + * + * Input: + * ia_ptr + * lmr_ptr + * + * Output: + * none + * + * Returns: + * none + * + */ +void dapl_ia_unlink_lmr(IN DAPL_IA * ia_ptr, IN DAPL_LMR * lmr_ptr) +{ + dapl_os_lock(&ia_ptr->header.lock); + dapl_llist_remove_entry(&ia_ptr->lmr_list_head, + &lmr_ptr->header.ia_list_entry); + dapl_os_unlock(&ia_ptr->header.lock); +} + +/* + * dapl_ia_link_rmr + * + * Add an rmr to the IA structure + * + * Input: + * ia_ptr + * rmr_ptr + * + * Output: + * none + * + * Returns: + * none + * + */ +void dapl_ia_link_rmr(IN DAPL_IA * ia_ptr, IN DAPL_RMR * rmr_ptr) +{ + dapl_os_lock(&ia_ptr->header.lock); + dapl_llist_add_head(&ia_ptr->rmr_list_head, + &rmr_ptr->header.ia_list_entry, rmr_ptr); + dapl_os_unlock(&ia_ptr->header.lock); +} + +/* + * dapl_ia_unlink_rmr + * + * Remove an rmr from the ia info structure + * + * Input: + * ia_ptr + * rmr_ptr + * + * Output: + * none + * + * Returns: + * none + * + */ +void dapl_ia_unlink_rmr(IN DAPL_IA * ia_ptr, IN DAPL_RMR * rmr_ptr) +{ + dapl_os_lock(&ia_ptr->header.lock); + dapl_llist_remove_entry(&ia_ptr->rmr_list_head, + &rmr_ptr->header.ia_list_entry); + dapl_os_unlock(&ia_ptr->header.lock); +} + +/* + * dapl_ia_link_pz + * + * Add an pz to the IA structure + * + * Input: + * ia_ptr + * pz_ptr + * + * Output: + * none + * + * Returns: + * none + * + */ +void dapl_ia_link_pz(IN DAPL_IA * ia_ptr, IN DAPL_PZ * pz_ptr) +{ + dapl_os_lock(&ia_ptr->header.lock); + dapl_llist_add_head(&ia_ptr->pz_list_head, + &pz_ptr->header.ia_list_entry, pz_ptr); + dapl_os_unlock(&ia_ptr->header.lock); +} + +/* + * dapl_ia_unlink_pz + * + * Remove an pz from the ia info structure + * + * Input: + * ia_ptr + * pz_ptr + * + * Output: + * none + * + * Returns: + * none + * + */ +void dapl_ia_unlink_pz(IN DAPL_IA * ia_ptr, IN DAPL_PZ * pz_ptr) +{ + dapl_os_lock(&ia_ptr->header.lock); + dapl_llist_remove_entry(&ia_ptr->pz_list_head, + &pz_ptr->header.ia_list_entry); + dapl_os_unlock(&ia_ptr->header.lock); +} + +/* + * dapl_ia_link_evd + * + * Add an evd to the IA structure + * + * Input: + * ia_ptr + * evd_ptr + * + * Output: + * none + * + * Returns: + * none + * + */ +void dapl_ia_link_evd(IN DAPL_IA * ia_ptr, IN DAPL_EVD * evd_ptr) +{ + dapl_os_lock(&ia_ptr->header.lock); + dapl_llist_add_head(&ia_ptr->evd_list_head, + &evd_ptr->header.ia_list_entry, evd_ptr); + dapl_os_unlock(&ia_ptr->header.lock); +} + +/* + * dapl_ia_unlink_evd + * + * Remove an evd from the ia info structure + * + * Input: + * ia_ptr + * evd_ptr + * + * Output: + * none + * + * Returns: + * none + * + */ +void dapl_ia_unlink_evd(IN DAPL_IA * ia_ptr, IN DAPL_EVD * evd_ptr) +{ + dapl_os_lock(&ia_ptr->header.lock); + dapl_llist_remove_entry(&ia_ptr->evd_list_head, + &evd_ptr->header.ia_list_entry); + dapl_os_unlock(&ia_ptr->header.lock); +} + +/* + * dapl_ia_link_cno + * + * Add an cno to the IA structure + * + * Input: + * ia_ptr + * cno_ptr + * + * Output: + * none + * + * Returns: + * none + * + */ +void dapl_ia_link_cno(IN DAPL_IA * ia_ptr, IN DAPL_CNO * cno_ptr) +{ + dapl_os_lock(&ia_ptr->header.lock); + dapl_llist_add_head(&ia_ptr->cno_list_head, + &cno_ptr->header.ia_list_entry, cno_ptr); + dapl_os_unlock(&ia_ptr->header.lock); +} + +/* + * dapl_ia_unlink_cno + * + * Remove an cno from the ia info structure + * + * Input: + * ia_ptr + * cno_ptr + * + * Output: + * none + * + * Returns: + * none + * + */ +void dapl_ia_unlink_cno(IN DAPL_IA * ia_ptr, IN DAPL_CNO * cno_ptr) +{ + dapl_os_lock(&ia_ptr->header.lock); + dapl_llist_remove_entry(&ia_ptr->cno_list_head, + &cno_ptr->header.ia_list_entry); + dapl_os_unlock(&ia_ptr->header.lock); +} + +/* + * dapl_ia_link_psp + * + * Add an psp to the IA structure + * + * Input: + * ia_ptr + * sp_ptr + * + * Output: + * none + * + * Returns: + * none + * + */ +void dapl_ia_link_psp(IN DAPL_IA * ia_ptr, IN DAPL_SP * sp_ptr) +{ + dapl_os_lock(&ia_ptr->header.lock); + dapl_llist_add_head(&ia_ptr->psp_list_head, + &sp_ptr->header.ia_list_entry, sp_ptr); + dapl_os_unlock(&ia_ptr->header.lock); +} + +/* + * daps_ia_unlink_sp + * + * Remove an sp from the appropriate ia rsp or psp queue + * + * Input: + * ia_ptr + * sp_ptr + * + * Output: + * none + * + * Returns: + * none + * + */ +void dapls_ia_unlink_sp(IN DAPL_IA * ia_ptr, IN DAPL_SP * sp_ptr) +{ + DAPL_LLIST_HEAD *list_head; + + if (sp_ptr->header.handle_type == DAT_HANDLE_TYPE_PSP) { + list_head = &ia_ptr->psp_list_head; + } else { + dapl_os_assert(sp_ptr->header.handle_type == + DAT_HANDLE_TYPE_RSP); + list_head = &ia_ptr->rsp_list_head; + } + + dapl_os_lock(&ia_ptr->header.lock); + dapl_llist_remove_entry(list_head, &sp_ptr->header.ia_list_entry); + dapl_os_unlock(&ia_ptr->header.lock); +} + +/* + * dapls_ia_sp_search + * + * Find an RSP or PSP on the IA list with a matching conn_qual value + * + * Input: + * ia_ptr + * sp_ptr + * + * Output: + * none + * + * Returns: + * none + * + */ +DAPL_SP *dapls_ia_sp_search(IN DAPL_IA * ia_ptr, + IN DAT_CONN_QUAL conn_qual, IN DAT_BOOLEAN is_psp) +{ + DAPL_SP *sp_ptr; + DAPL_LLIST_HEAD *list_head; + + if (is_psp) { + list_head = &ia_ptr->psp_list_head; + } else { + list_head = &ia_ptr->rsp_list_head; + } + + dapl_os_lock(&ia_ptr->header.lock); + + sp_ptr = (dapl_llist_is_empty(list_head) ? NULL : + dapl_llist_peek_head(list_head)); + + while (sp_ptr != NULL) { + if (sp_ptr->conn_qual == conn_qual) { + break; + } + sp_ptr = dapl_llist_next_entry(list_head, + &sp_ptr->header.ia_list_entry); + } + + dapl_os_unlock(&ia_ptr->header.lock); + + return sp_ptr; +} + +/* + * dapl_ia_link_rsp + * + * Add an rsp to the IA structure + * + * Input: + * ia_ptr + * sp_ptr + * + * Output: + * none + * + * Returns: + * none + * + */ +void dapl_ia_link_rsp(IN DAPL_IA * ia_ptr, IN DAPL_SP * sp_ptr) +{ + dapl_os_lock(&ia_ptr->header.lock); + dapl_llist_add_head(&ia_ptr->rsp_list_head, + &sp_ptr->header.ia_list_entry, sp_ptr); + dapl_os_unlock(&ia_ptr->header.lock); +} + +DAT_RETURN +dapls_ia_setup_callbacks(IN DAPL_IA * ia_ptr, IN DAPL_EVD * async_evd_ptr) +{ + DAT_RETURN dat_status = DAT_SUCCESS; + + /* unaffiliated handler */ + dat_status = + dapls_ib_setup_async_callback(ia_ptr, + DAPL_ASYNC_UNAFILIATED, + NULL, + (ib_async_handler_t) + dapl_evd_un_async_error_callback, + async_evd_ptr); + + if (dat_status != DAT_SUCCESS) { + dapl_dbg_log(DAPL_DBG_TYPE_ERR, + "ib_set_un_async_error_eh failed %d\n", + dat_status); + goto bail; + } + + /* affiliated cq handler */ + dat_status = dapls_ib_setup_async_callback(ia_ptr, + DAPL_ASYNC_CQ_ERROR, + NULL, + (ib_async_handler_t) + dapl_evd_cq_async_error_callback, + async_evd_ptr); + + if (dat_status != DAT_SUCCESS) { + dapl_dbg_log(DAPL_DBG_TYPE_ERR, + "ib_set_cq_async_error_eh failed %d\n", + dat_status); + goto bail; + } + + /* affiliated qp handler */ + dat_status = dapls_ib_setup_async_callback(ia_ptr, + DAPL_ASYNC_QP_ERROR, + NULL, + (ib_async_handler_t) + dapl_evd_qp_async_error_callback, + ia_ptr); + if (dat_status != DAT_SUCCESS) { + dapl_dbg_log(DAPL_DBG_TYPE_ERR, + "ib_set_qp_async_error_eh failed %d\n", + dat_status); + goto bail; + } + + bail: + return dat_status; +} + +DAT_RETURN dapls_ia_teardown_callbacks(IN DAPL_IA * ia_ptr) +{ + DAT_RETURN dat_status = DAT_SUCCESS; + + /* unaffiliated handler */ + dat_status = + dapls_ib_setup_async_callback(ia_ptr, + DAPL_ASYNC_UNAFILIATED, + NULL, (ib_async_handler_t) 0, NULL); + + if (dat_status != DAT_SUCCESS) { + dapl_dbg_log(DAPL_DBG_TYPE_ERR, + "ib_set_un_async_error_eh failed %d\n", + dat_status); + goto bail; + } + + /* affiliated cq handler */ + dat_status = dapls_ib_setup_async_callback(ia_ptr, + DAPL_ASYNC_CQ_ERROR, + NULL, + (ib_async_handler_t) 0, + NULL); + + if (dat_status != DAT_SUCCESS) { + dapl_dbg_log(DAPL_DBG_TYPE_ERR, + "ib_set_cq_async_error_eh failed %d\n", + dat_status); + goto bail; + } + + /* affiliated qp handler */ + dat_status = dapls_ib_setup_async_callback(ia_ptr, + DAPL_ASYNC_QP_ERROR, + NULL, + (ib_async_handler_t) 0, + NULL); + if (dat_status != DAT_SUCCESS) { + dapl_dbg_log(DAPL_DBG_TYPE_ERR, + "ib_set_qp_async_error_eh failed %d\n", + dat_status); + goto bail; + } + + bail: + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ia_util.h b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ia_util.h new file mode 100644 index 00000000..6290cf81 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ia_util.h @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dapl_ia_util.h + * + * PURPOSE: Utility defs & routines for the IA data structure + * + * $Id:$ + **********************************************************************/ + +#ifndef _DAPL_IA_UTIL_H_ +#define _DAPL_IA_UTIL_H_ + +#include "dapl.h" + +DAPL_IA * +dapl_ia_alloc ( + DAT_PROVIDER *provider, + DAPL_HCA *hca_ptr) ; + +DAT_RETURN +dapl_ia_abrupt_close ( + IN DAPL_IA *ia_ptr ) ; + +DAT_RETURN +dapl_ia_graceful_close ( + IN DAPL_IA *ia_ptr ) ; + +void +dapls_ia_free ( DAPL_IA *ia_ptr ) ; + +void +dapl_ia_link_ep ( + IN DAPL_IA *ia_ptr, + IN DAPL_EP *ep_info ) ; + +void +dapl_ia_unlink_ep ( + IN DAPL_IA *ia_ptr, + IN DAPL_EP *ep_info ) ; + +void +dapl_ia_link_srq ( + IN DAPL_IA *ia_ptr, + IN DAPL_SRQ *srq_ptr ) ; + +void +dapl_ia_unlink_srq ( + IN DAPL_IA *ia_ptr, + IN DAPL_SRQ *srq_ptr ) ; + +void +dapl_ia_link_lmr ( + IN DAPL_IA *ia_ptr, + IN DAPL_LMR *lmr_info ) ; + +void +dapl_ia_unlink_lmr ( + IN DAPL_IA *ia_ptr, + IN DAPL_LMR *lmr_info ) ; + +void +dapl_ia_link_rmr ( + IN DAPL_IA *ia_ptr, + IN DAPL_RMR *rmr_info ) ; + +void +dapl_ia_unlink_rmr ( + IN DAPL_IA *ia_ptr, + IN DAPL_RMR *rmr_info ) ; + +void +dapl_ia_link_pz ( + IN DAPL_IA *ia_ptr, + IN DAPL_PZ *pz_info ) ; + +void +dapl_ia_unlink_pz ( + IN DAPL_IA *ia_ptr, + IN DAPL_PZ *pz_info ) ; + +void +dapl_ia_link_evd ( + IN DAPL_IA *ia_ptr, + IN DAPL_EVD *evd_info ) ; + +void +dapl_ia_unlink_evd ( + IN DAPL_IA *ia_ptr, + IN DAPL_EVD *evd_info ) ; + +void +dapl_ia_link_cno ( + IN DAPL_IA *ia_ptr, + IN DAPL_CNO *cno_info ) ; + +void +dapl_ia_unlink_cno ( + IN DAPL_IA *ia_ptr, + IN DAPL_CNO *cno_info ) ; + +void +dapl_ia_link_psp ( + IN DAPL_IA *ia_ptr, + IN DAPL_SP *sp_info ) ; + +void +dapls_ia_unlink_sp ( + IN DAPL_IA *ia_ptr, + IN DAPL_SP *sp_info ) ; + +void +dapl_ia_link_rsp ( + IN DAPL_IA *ia_ptr, + IN DAPL_SP *sp_info ) ; + +DAPL_SP * +dapls_ia_sp_search ( + IN DAPL_IA *ia_ptr, + IN DAT_CONN_QUAL conn_qual, + IN DAT_BOOLEAN is_psp ) ; + +DAT_RETURN +dapls_ia_setup_callbacks ( + IN DAPL_IA *ia_ptr, + IN DAPL_EVD *async_evd_ptr ); + +DAT_RETURN +dapls_ia_teardown_callbacks ( + IN DAPL_IA *ia_ptr ); + +#endif diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_init.h b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_init.h new file mode 100644 index 00000000..0c985411 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_init.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dapl_init.h + * + * PURPOSE: Prototypes for library-interface init and fini functions + * + * $Id:$ + * + **********************************************************************/ + + +#ifndef _DAPL_INIT_H_ +#define _DAPL_INIT_H_ + +extern void DAT_API +DAT_PROVIDER_INIT_FUNC_NAME ( + IN const DAT_PROVIDER_INFO *, + IN const char * ); /* instance data */ + +extern void DAT_API +DAT_PROVIDER_FINI_FUNC_NAME ( + IN const DAT_PROVIDER_INFO * ); + +extern void +dapl_init ( void ) ; + +extern void +dapl_fini ( void ) ; + +#endif diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_llist.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_llist.c new file mode 100644 index 00000000..436444e1 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_llist.c @@ -0,0 +1,343 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_llist.c + * + * PURPOSE: Manage doubly linked lists within the DAPL Reference Implementation + * + * A link list head points to the first member of a linked list, but + * is itself not a member of the list. + * + * +---------------------------------------------+ + * | entry entry entry | + * HEAD -> | +-------+ +-------+ +-------+ | + * +--> | flink | --> | flink | --> | flink | >--+ + * | data | | data | | data | + * +--< | blink | <-- | blink | <-- | blink | <--| + * | +-------+ +-------+ +-------+ | + * | | + * +---------------------------------------------+ + * + * Note: Each of the remove functions takes an assertion failure if + * an element cannot be removed from the list. + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" + +/* + * dapl_llist_init_head() + * + * Purpose: initialize a linked list head + */ +void dapl_llist_init_head(DAPL_LLIST_HEAD * head) +{ + *head = NULL; +} + +/* + * dapl_llist_init_entry() + * + * Purpose: initialize a linked list entry + */ +void dapl_llist_init_entry(DAPL_LLIST_ENTRY * entry) +{ + entry->blink = NULL; + entry->flink = NULL; + entry->data = 0; + entry->list_head = NULL; +} + +/* + * dapl_llist_is_empty() + * + * Purpose: returns TRUE if the linked list is empty + */ +DAT_BOOLEAN dapl_llist_is_empty(DAPL_LLIST_HEAD * head) +{ + return (*head == NULL); +} + +/* + * dapl_llist_add_head() + * + * Purpose: Add an entry to the head of a linked list + */ +void +dapl_llist_add_head(DAPL_LLIST_HEAD * head, + DAPL_LLIST_ENTRY * entry, void *data) +{ + DAPL_LLIST_ENTRY *first; + + /* deal with empty list */ + if (dapl_llist_is_empty(head)) { + entry->flink = entry; + entry->blink = entry; + } else { + first = *head; + entry->flink = first; + entry->blink = first->blink; + first->blink->flink = entry; + first->blink = entry; + } + + *head = entry; + entry->data = data; + entry->list_head = head; +} + +/* + * dapl_llist_add_tail() + * + * Purpose: Add an entry to the tail of a linked list + */ +void +dapl_llist_add_tail(DAPL_LLIST_HEAD * head, + DAPL_LLIST_ENTRY * entry, void *data) +{ + DAPL_LLIST_ENTRY *last; + + /* deal with empty list */ + if (dapl_llist_is_empty(head)) { + *head = entry; + entry->flink = entry; + entry->blink = entry; + } else { + last = (*head)->blink; + entry->flink = last->flink; + entry->blink = last; + last->flink->blink = entry; + last->flink = entry; + } + entry->data = data; + entry->list_head = head; +} + +/* + * dapl_llist_add_entry() + * + * Purpose: Add an entry before an element in the list. Does + * not verify the list or the validity of the entries passed in. + */ +void +dapl_llist_add_entry(DAPL_LLIST_HEAD * head, + DAPL_LLIST_ENTRY * entry, + DAPL_LLIST_ENTRY * new_entry, void *data) +{ + DAPL_LLIST_ENTRY *first; + DAPL_LLIST_ENTRY *prev; + + /* get the head pointer */ + first = *head; + + /* link the entry into the queue */ + prev = entry->blink; + entry->blink = new_entry; + prev->flink = new_entry; + + new_entry->flink = entry; + new_entry->blink = prev; + + new_entry->data = data; + new_entry->list_head = head; + + /* If the old entry was the head of the list, adjust */ + if (first == entry) { + (*head) = new_entry; + } + +} + +/* + * dapl_llist_remove_head() + * + * Purpose: Remove the first entry of a linked list + */ +void *dapl_llist_remove_head(DAPL_LLIST_HEAD * head) +{ + DAPL_LLIST_ENTRY *first; + + dapl_os_assert(!dapl_llist_is_empty(head)); + first = *head; + *head = first->flink; + + first->flink->blink = first->blink; + first->blink->flink = first->flink; + + if (first->flink == first) { + *head = NULL; + } + /* clean up the links for good measure */ + first->flink = NULL; + first->blink = NULL; + first->list_head = NULL; + return (first->data); +} + +/* + * dapl_llist_remove_tail() + * + * Purpose: Remove the last entry of a linked list + */ +void *dapl_llist_remove_tail(DAPL_LLIST_HEAD * head) +{ + DAPL_LLIST_ENTRY *last; + + dapl_os_assert(!dapl_llist_is_empty(head)); + last = (*head)->blink; + + last->blink->flink = last->flink; + last->flink->blink = last->blink; + + if (last->flink == last) { + *head = NULL; + } + /* clean up the links for good measure */ + last->flink = NULL; + last->blink = NULL; + last->list_head = NULL; + + return (last->data); +} + +/* + * dapl_llist_remove_entry() + * + * Purpose: Remove the specified entry from a linked list + */ +void *dapl_llist_remove_entry(DAPL_LLIST_HEAD * head, DAPL_LLIST_ENTRY * entry) +{ + DAPL_LLIST_ENTRY *first; + + dapl_os_assert(!dapl_llist_is_empty(head)); + first = *head; + + /* if it's the first entry, pull it off */ + if (first == entry) { + (*head) = first->flink; + /* if it was the only entry, kill the list */ + if (first->flink == first) { + (*head) = NULL; + } + } +#ifdef VERIFY_LINKED_LIST + else { + DAPL_LLIST_ENTRY *try_entry; + + try_entry = first->flink; + for (;;) { + if (try_entry == first) { + /* not finding the element on the list is a BAD thing */ + dapl_os_assert(0); + break; + } + if (try_entry == entry) { + break; + } + try_entry = try_entry->flink; + } + } +#endif /* VERIFY_LINKED_LIST */ + + dapl_os_assert(entry->list_head == head); + entry->list_head = NULL; + + entry->flink->blink = entry->blink; + entry->blink->flink = entry->flink; + entry->flink = NULL; + entry->blink = NULL; + + return (entry->data); +} + +/* + * dapl_llist_peek_head + */ + +void *dapl_llist_peek_head(DAPL_LLIST_HEAD * head) +{ + DAPL_LLIST_ENTRY *first; + + dapl_os_assert(!dapl_llist_is_empty(head)); + first = *head; + return (first->data); +} + +/* + * dapl_llist_next_entry + * + * Obtain the next entry in the list, return NULL when we get to the + * head + */ + +void *dapl_llist_next_entry(IN DAPL_LLIST_HEAD * head, + IN DAPL_LLIST_ENTRY * cur_ent) +{ + DAPL_LLIST_ENTRY *next; + + dapl_os_assert(!dapl_llist_is_empty(head)); + if (cur_ent == NULL) { + next = *head; + } else { + next = cur_ent->flink; + if (next == *head) { + return NULL; + } + } + return (next->data); +} + +#ifdef DAPL_DBG +/* + * dapl_llist_debug_print_list() + * + * Purpose: Prints the linked list for debugging + */ +void dapl_llist_debug_print_list(DAPL_LLIST_HEAD * head) +{ + DAPL_LLIST_ENTRY *entry; + DAPL_LLIST_ENTRY *first; + first = *head; + if (!first) { + dapl_os_printf("EMPTY_LIST\n"); + return; + } + dapl_os_printf("HEAD %p\n", *head); + dapl_os_printf("Entry %p %p %p %p\n", + first, first->flink, first->blink, first->data); + entry = first->flink; + while (entry != first) { + dapl_os_printf("Entry %p %p %p %p\n", + entry, entry->flink, entry->blink, entry->data); + entry = entry->flink; + } +} + +#endif /* DAPL_DBG */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_lmr_free.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_lmr_free.c new file mode 100644 index 00000000..5f9336f8 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_lmr_free.c @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_lmr_free.c + * + * PURPOSE: Memory management + * + * $Id:$ + **********************************************************************/ + +#include "dapl_lmr_util.h" +#include "dapl_adapter_util.h" +#include "dapl_ia_util.h" + +/* + * dapl_lmr_free + * + * DAPL Requirements Version xxx, 6.6.3.2 + * + * Destroy an instance of the Local Memory Region + * + * Input: + * lmr_handle + * + * Output: + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + * DAT_INVALID_PARAMETER + * DAT_INVALID_STATE + */ + +DAT_RETURN DAT_API dapl_lmr_free(IN DAT_LMR_HANDLE lmr_handle) +{ + DAPL_LMR *lmr; + DAPL_PZ *pz; + DAT_RETURN dat_status; + + dapl_dbg_log(DAPL_DBG_TYPE_API, "dapl_lmr_free (%p)\n", lmr_handle); + + if (DAPL_BAD_HANDLE(lmr_handle, DAPL_MAGIC_LMR)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_LMR); + goto bail; + } + + lmr = (DAPL_LMR *) lmr_handle; + pz = (DAPL_PZ *) lmr->param.pz_handle; + + DAPL_CNTR(pz->header.owner_ia, DCNT_IA_LMR_FREE); + + switch (lmr->param.mem_type) { +#if defined(__KDAPL__) + case DAT_MEM_TYPE_PHYSICAL: +#else + case DAT_MEM_TYPE_SHARED_VIRTUAL: +#endif /* defined(__KDAPL__) */ + /* fall through */ + case DAT_MEM_TYPE_VIRTUAL: + case DAT_MEM_TYPE_LMR: + { + if (0 != dapl_os_atomic_read(&lmr->lmr_ref_count)) { + return DAT_INVALID_STATE; + } + + dat_status = dapls_ib_mr_deregister(lmr); + + if (dat_status == DAT_SUCCESS) { + dapl_os_atomic_dec(&pz->pz_ref_count); + dapl_lmr_dealloc(lmr); + } + break; + } +#if defined(__KDAPL__) + case DAT_MEM_TYPE_PLATFORM: + case DAT_MEM_TYPE_IA: + case DAT_MEM_TYPE_BYPASS: + { + return DAT_ERROR(DAT_NOT_IMPLEMENTED, 0); + } +#endif /* defined(__KDAPL__) */ + default: + { + dat_status = + DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG1); + break; + } + } + bail: + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_lmr_query.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_lmr_query.c new file mode 100644 index 00000000..4ac37ec1 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_lmr_query.c @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_lmr_query.c + * + * PURPOSE: Memory management + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" + +/* + * dapl_lmr_query + * + * Provide the LMR arguments. + * + * Input: + * lmr_handle + * lmr_param_mask + * lmr_param + * + * Output: + * lmr_param + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + * DAT_INVALID_PARAMETER + */ +DAT_RETURN DAT_API +dapl_lmr_query(IN DAT_LMR_HANDLE lmr_handle, + IN DAT_LMR_PARAM_MASK lmr_param_mask, + IN DAT_LMR_PARAM * lmr_param) +{ + DAPL_LMR *lmr; + DAT_RETURN dat_status; + + dapl_dbg_log(DAPL_DBG_TYPE_API, + "dapl_lmr_query (%p, 0x%x, %p)\n", + lmr_handle, lmr_param_mask, lmr_param); + + if (DAPL_BAD_HANDLE(lmr_handle, DAPL_MAGIC_LMR)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_LMR); + goto bail; + } + if (NULL == lmr_param) { + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG3); + goto bail; + } + + dat_status = DAT_SUCCESS; + lmr = (DAPL_LMR *) lmr_handle; + + dapl_os_memcpy(lmr_param, &lmr->param, sizeof(DAT_LMR_PARAM)); + + bail: + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_lmr_sync_rdma_read.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_lmr_sync_rdma_read.c new file mode 100644 index 00000000..9f26377c --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_lmr_sync_rdma_read.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_lmr_sync_rdma_read.c + * + * PURPOSE: Interface Adapter management + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_ia_util.h" + +/* + * dat_lmr_sync_rdma_read + * + * Ensure a region of memory is consistent by locally flushing + * non-coherent cache + * + * Input: + * ia_handle + * local_segments Array of buffer segments + * num_segments Number of segments in local_segments + * + * Output: + * none + * + * Return Values: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + * DAT_INVALID_PARAMETER + */ +DAT_RETURN DAT_API +dapl_lmr_sync_rdma_read(IN DAT_IA_HANDLE ia_handle, + IN const DAT_LMR_TRIPLET * local_segments, + IN DAT_VLEN num_segments) +{ + DAPL_IA *ia_ptr; + DAT_RETURN dat_status; + + dapl_dbg_log(DAPL_DBG_TYPE_API, + "dat_lmr_sync_rdma_read (%p, %p, %ld)\n", + ia_handle, local_segments, num_segments); + + ia_ptr = (DAPL_IA *) ia_handle; + + if (DAPL_BAD_HANDLE(ia_ptr, DAPL_MAGIC_IA)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_IA); + goto bail; + } + + dat_status = dapl_os_sync_rdma_read(local_segments, num_segments); + + bail: + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_lmr_sync_rdma_write.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_lmr_sync_rdma_write.c new file mode 100644 index 00000000..f20df69d --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_lmr_sync_rdma_write.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_lmr_sync_rdma_write.c + * + * PURPOSE: Interface Adapter management + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_ia_util.h" + +/* + * dat_lmr_sync_rdma_write + * + * Ensure a region of memory is consistent by locally flushing + * non-coherent cache + * + * Input: + * ia_handle + * local_segments Array of buffer segments + * num_segments Number of segments in local_segments + * + * Output: + * none + * + * Return Values: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + * DAT_INVALID_PARAMETER + */ +DAT_RETURN DAT_API +dapl_lmr_sync_rdma_write(IN DAT_IA_HANDLE ia_handle, + IN const DAT_LMR_TRIPLET * local_segments, + IN DAT_VLEN num_segments) +{ + DAPL_IA *ia_ptr; + DAT_RETURN dat_status; + + dapl_dbg_log(DAPL_DBG_TYPE_API, + "dat_lmr_sync_rdma_write (%p, %p, %ld)\n", + ia_handle, local_segments, num_segments); + + ia_ptr = (DAPL_IA *) ia_handle; + + if (DAPL_BAD_HANDLE(ia_ptr, DAPL_MAGIC_IA)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_IA); + goto bail; + } + + dat_status = dapl_os_sync_rdma_write(local_segments, num_segments); + + bail: + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_lmr_util.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_lmr_util.c new file mode 100644 index 00000000..40634f16 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_lmr_util.c @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_lmr_util.c + * + * PURPOSE: Memory management support routines + * Description: Support routines for LMR functions + * + * $Id:$ + **********************************************************************/ + +#include "dapl_lmr_util.h" +#include "dapl_ia_util.h" + +DAPL_LMR *dapl_lmr_alloc(IN DAPL_IA * ia, + IN DAT_MEM_TYPE mem_type, + IN DAT_REGION_DESCRIPTION region_desc, + IN DAT_VLEN length, + IN DAT_PZ_HANDLE pz_handle, + IN DAT_MEM_PRIV_FLAGS mem_priv) +{ + DAPL_LMR *lmr; + + /* Allocate LMR */ + lmr = (DAPL_LMR *) dapl_os_alloc(sizeof(DAPL_LMR)); + if (NULL == lmr) { + return (NULL); + } + + /* zero the structure */ + dapl_os_memzero(lmr, sizeof(DAPL_LMR)); + + /* + * initialize the header + */ + lmr->header.provider = ia->header.provider; + lmr->header.magic = DAPL_MAGIC_LMR; + lmr->header.handle_type = DAT_HANDLE_TYPE_LMR; + lmr->header.owner_ia = ia; + lmr->header.user_context.as_64 = 0; + lmr->header.user_context.as_ptr = NULL; + dapl_llist_init_entry(&lmr->header.ia_list_entry); + dapl_ia_link_lmr(ia, lmr); + dapl_os_lock_init(&lmr->header.lock); + + /* + * initialize the body + */ + lmr->param.ia_handle = (DAT_IA_HANDLE) ia; + lmr->param.mem_type = mem_type; + lmr->param.region_desc = region_desc; + lmr->param.length = length; + lmr->param.pz_handle = pz_handle; + lmr->param.mem_priv = mem_priv; + dapl_os_atomic_set(&lmr->lmr_ref_count, 0); + + return (lmr); +} + +void dapl_lmr_dealloc(IN DAPL_LMR * lmr) +{ + lmr->header.magic = DAPL_MAGIC_INVALID; /* reset magic to prevent reuse */ + dapl_ia_unlink_lmr(lmr->header.owner_ia, lmr); + dapl_os_lock_destroy(&lmr->header.lock); + + dapl_os_free((void *)lmr, sizeof(DAPL_LMR)); +} diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_lmr_util.h b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_lmr_util.h new file mode 100644 index 00000000..6b401076 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_lmr_util.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dapl_lmr_util.h + * + * PURPOSE: Utility defs & routines for the LMR data structure + * + * $Id:$ + * + **********************************************************************/ + +#ifndef _DAPL_LMR_UTIL_H_ +#define _DAPL_LMR_UTIL_H_ + +#include "dapl_mr_util.h" + +/********************************************************************* + * * + * Function Prototypes * + * * + *********************************************************************/ + +extern DAPL_LMR * +dapl_lmr_alloc ( + IN DAPL_IA *ia, + IN DAT_MEM_TYPE mem_type, + IN DAT_REGION_DESCRIPTION region_desc, + IN DAT_VLEN length, + IN DAT_PZ_HANDLE pz_handle, + IN DAT_MEM_PRIV_FLAGS mem_priv); + +extern void +dapl_lmr_dealloc ( + IN DAPL_LMR *lmr); + + +#endif /* _DAPL_LMR_UTIL_H_*/ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_mr_util.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_mr_util.c new file mode 100644 index 00000000..f0c9a342 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_mr_util.c @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_mr_util.h" + +/********************************************************************** + * + * MODULE: dapl_mr_util.c + * + * PURPOSE: Common Memory Management functions and data structures + * + * $Id:$ + **********************************************************************/ + +/********************************************************************* + * * + * Function Definitions * + * * + *********************************************************************/ + +/* + * dapl_mr_get_address + * + * Returns the memory address associated with the given memory descriptor + * + * Input: + * desc memory descriptor + * type type of memory represented by desc + * + * Output: + * None + * + */ + +DAT_VADDR +dapl_mr_get_address(IN DAT_REGION_DESCRIPTION desc, IN DAT_MEM_TYPE type) +{ + switch (type) { + case DAT_MEM_TYPE_VIRTUAL: + { + return (DAT_VADDR) (uintptr_t) desc.for_va; + } + case DAT_MEM_TYPE_LMR: + { + DAPL_LMR *lmr; + + lmr = (DAPL_LMR *) desc.for_lmr_handle; + + /* Since this function is recoursive we cannot inline it */ + return dapl_mr_get_address(lmr->param.region_desc, + lmr->param.mem_type); + } +#if defined(__KDAPL__) + case DAT_MEM_TYPE_PHYSICAL: + { + return desc.for_pa; + } +#else + case DAT_MEM_TYPE_SHARED_VIRTUAL: + { + /* multi-cast necessary to convert a pvoid to a DAT_VADDR on + * all architectures + */ + return (DAT_VADDR) (uintptr_t) desc.for_shared_memory. + virtual_address; + } +#endif /* defined(__KDAPL__) */ + default: + { + /* + * The following kDAPL memory types have not been implemented: + * DAT_MEM_TYPE_PLATFORM + * DAT_MEM_TYPE_IA + * DAT_MEM_TYPE_BYPASS + */ + dapl_os_assert(0); + return 0; + } + } +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * c-brace-offset: -4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_mr_util.h b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_mr_util.h new file mode 100644 index 00000000..140fcaa5 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_mr_util.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dapl_mr_util.h + * + * PURPOSE: Utility defs & routines for memory registration functions + * + * $Id:$ + * + **********************************************************************/ + +#ifndef _DAPL_MR_UTIL_H_ +#define _DAPL_MR_UTIL_H_ + +#include "dapl.h" +#include "dapl_hash.h" + + +/********************************************************************* + * * + * Function Prototypes * + * * + *********************************************************************/ + +extern DAT_VADDR +dapl_mr_get_address ( + IN DAT_REGION_DESCRIPTION desc, + IN DAT_MEM_TYPE type); + +STATIC _INLINE_ DAT_BOOLEAN +dapl_mr_bounds_check ( + IN DAT_VADDR addr_a, + IN DAT_VLEN length_a, + IN DAT_VADDR addr_b, + IN DAT_VLEN length_b); + + +/********************************************************************* + * * + * Inline Functions * + * * + *********************************************************************/ + +/* + * dapl_mr_bounds_check + * + * Returns true if region B is contained within region A + * and false otherwise + * + */ + +STATIC _INLINE_ DAT_BOOLEAN +dapl_mr_bounds_check ( + IN DAT_VADDR addr_a, + IN DAT_VLEN length_a, + IN DAT_VADDR addr_b, + IN DAT_VLEN length_b) +{ + if ( (addr_a <= addr_b) && + (addr_b + length_b) <= (addr_a + length_a)) + { + return DAT_TRUE; + } + else + { + return DAT_FALSE; + } +} + +#endif /* _DAPL_MR_UTIL_H_ */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_name_service.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_name_service.c new file mode 100644 index 00000000..84ef4682 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_name_service.c @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_name_service.c + * + * PURPOSE: Provide simple, file base name services in the absence + * of DNS hooks for a particular transport type. If an + * InfiniBand implementation supports IPoIB, this should + * not be used. + * + * Description: Interfaces in this file are completely described in + * dapl_name_service.h + * + * $Id:$ + **********************************************************************/ + +/* + * Include files for setting up a network name + */ +#include "dapl.h" +#include "dapl_name_service.h" + +/* + * Prototypes + */ +#ifdef IBHOSTS_NAMING +DAT_RETURN dapli_ns_create_gid_map(void); + +DAT_RETURN dapli_ns_add_address(IN DAPL_GID_MAP * gme); +#endif /* IBHOSTS_NAMING */ + +/* + * dapls_ns_init + * + * Initialize naming services + * + * Input: + * none + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + */ +DAT_RETURN dapls_ns_init(void) +{ + DAT_RETURN dat_status; + + dat_status = DAT_SUCCESS; +#ifdef IBHOSTS_NAMING + dat_status = dapli_ns_create_gid_map(); +#endif /* IBHOSTS_NAMING */ + + return dat_status; +} + +#ifdef IBHOSTS_NAMING + +#define MAX_GID_ENTRIES 32 +DAPL_GID_MAP g_gid_map_table[MAX_GID_ENTRIES]; + +#ifdef _WIN32 +#define MAP_FILE "c:/WINNT/system32/drivers/etc/ibhosts" +#else +#define MAP_FILE "/etc/dapl/ibhosts" +#endif /* !defined WIN32 */ + +/* + * dapli_ns_create_gid_map() + * + * Read the MAP_FILE to obtain host names and GIDs. + * Create a table containing IP addresses and GIDs which can + * be used for lookups. + * + * This implementation is a simple method providing name services + * when more advanced mechanisms do not exist. The proper way + * to obtain these mappings is to use a name service such as is + * provided by IPoIB on InfiniBand. + * + * Input: + * device_name Name of device as reported by the provider + * + * Output: + * none + * + * Returns: + * char * to string number + */ +DAT_RETURN dapli_ns_create_gid_map(void) +{ + FILE *f; + ib_gid_t gid; + char hostname[128]; + int rc; + struct addrinfo *addr; + struct sockaddr_in *si; + DAPL_GID_MAP gmt; + + f = fopen(MAP_FILE, "r"); + if (f == NULL) { + dapl_dbg_log(DAPL_DBG_TYPE_ERR, + "ERROR: Must have file <%s> for IP/GID mappings\n", + MAP_FILE); + return DAT_ERROR(DAT_INTERNAL_ERROR, 0); + } + + rc = fscanf(f, "%s " F64x " " F64x, hostname, &gid.gid_prefix, + &gid.guid); + while (rc != EOF) { + rc = dapls_osd_getaddrinfo(hostname, &addr); + + if (rc != 0) { + /* + * hostname not registered in DNS, provide a dummy value + */ + dapl_dbg_log(DAPL_DBG_TYPE_WARN, + "WARNING: <%s> not registered in DNS, using dummy IP value\n", + hostname); + /*dapl_os_memcpy(hca_ptr->hca_address.sa_data, "0x01020304", 4); */ + gmt.ip_address = 0x01020304; + } else { + /* + * Load into the ip/gid mapping table + */ + si = (struct sockaddr_in *)addr->ai_addr; + if (AF_INET == addr->ai_addr->sa_family) { + gmt.ip_address = si->sin_addr.s_addr; + } else { + dapl_dbg_log(DAPL_DBG_TYPE_WARN, + "WARNING: <%s> Address family not supported, using dummy IP value\n", + hostname); + gmt.ip_address = 0x01020304; + } + dapls_osd_freeaddrinfo(addr); + } + gmt.gid.gid_prefix = gid.gid_prefix; + gmt.gid.guid = gid.guid; + + dapli_ns_add_address(&gmt); + rc = fscanf(f, "%s " F64x " " F64x, hostname, &gid.gid_prefix, + &gid.guid); + } + + fclose(f); + + return DAT_SUCCESS; +} + +/* + * dapli_ns_add_address + * + * Add a table entry to the gid_map_table. + * + * Input: + * remote_ia_address remote IP address + * gid pointer to output gid + * + * Output: + * gid filled in GID + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + */ +DAT_RETURN dapli_ns_add_address(IN DAPL_GID_MAP * gme) +{ + DAPL_GID_MAP *gmt; + int count; + + gmt = g_gid_map_table; + + for (count = 0, gmt = g_gid_map_table; gmt->ip_address; gmt++) { + count++; + } + + if (count > MAX_GID_ENTRIES) { + return DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, 0); + } + + *gmt = *gme; + + return DAT_SUCCESS; +} + +/* + * dapls_ns_lookup_address + * + * Look up the provided IA_ADDRESS in the gid_map_table. Return + * the gid if found. + * + * Input: + * remote_ia_address remote IP address + * gid pointer to output gid + * + * Output: + * gid filled in GID + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + */ +DAT_RETURN +dapls_ns_lookup_address(IN DAPL_IA * ia_ptr, + IN DAT_IA_ADDRESS_PTR remote_ia_address, + OUT ib_gid_t * gid) +{ + DAPL_GID_MAP *gmt; + struct sockaddr_in *si; + + ia_ptr = ia_ptr; /* unused here */ + + si = (struct sockaddr_in *)remote_ia_address; + + for (gmt = g_gid_map_table; gmt->ip_address; gmt++) { + if (gmt->ip_address == si->sin_addr.s_addr) { + gid->guid = gmt->gid.guid; + gid->gid_prefix = gmt->gid.gid_prefix; + + return DAT_SUCCESS; + } + } + + return DAT_ERROR(DAT_INVALID_PARAMETER, 0); +} + +#endif /* IBHOSTS_NAMING */ + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_name_service.h b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_name_service.h new file mode 100644 index 00000000..2d4725fd --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_name_service.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dapl_name_service.h + * + * PURPOSE: Utility defs & routines supporting name services + * + * $Id:$ + * + **********************************************************************/ + +#ifndef _DAPL_NAME_SERVICE_H_ +#define _DAPL_NAME_SERVICE_H_ + +#include "dapl.h" + +/* + * Prototypes for name service routines + */ + +DAT_RETURN dapls_ns_init (void); + +#ifdef IBHOSTS_NAMING +DAT_RETURN dapls_ns_lookup_address ( + IN DAPL_IA *ia_ptr, + IN DAT_IA_ADDRESS_PTR remote_ia_address, + OUT ib_gid_t *gid); +#else + +/* routine is a no op if not using local name services */ +#define dapls_ns_lookup_address(ia,ria,gid) DAT_SUCCESS + +#endif /* IBHOSTS_NAMING */ + +#endif /* _DAPL_NAME_SERVICE_H_ */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_provider.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_provider.c new file mode 100644 index 00000000..38db8d75 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_provider.c @@ -0,0 +1,453 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_provider.c + * + * PURPOSE: Provider function table + * Description: DAT Interfaces to this provider + * + * $Id:$ + **********************************************************************/ + +#include "dapl_provider.h" + +extern DAT_RETURN dapl_not_implemented(void); + +/********************************************************************* + * * + * Global Data * + * * + *********************************************************************/ + +DAPL_PROVIDER_LIST g_dapl_provider_list; + +/* + * the function table for this provider + */ + +#if defined(__KDAPL__) +DAT_PROVIDER g_dapl_provider_template = { + NULL, + 0, + &dapl_ia_open, + &dapl_ia_query, + &dapl_ia_close, + &dapl_ia_memtype_hint, /* unimplemented */ + + &dapl_set_consumer_context, /* untested */ + &dapl_get_consumer_context, /* untested */ + &dapl_get_handle_type, /* untested */ + + &dapl_cr_query, + &dapl_cr_accept, + &dapl_cr_reject, + &dapl_cr_handoff, + + &dapl_evd_kcreate, + &dapl_evd_kquery, /* untested */ + &dapl_evd_modify_upcall, + &dapl_evd_resize, /* unimplemented */ + &dapl_evd_post_se, /* untested */ + &dapl_evd_dequeue, + &dapl_evd_free, + + &dapl_ep_create, + &dapl_ep_query, + &dapl_ep_modify, /* untested */ + &dapl_ep_connect, + &dapl_ep_dup_connect, /* untested */ + &dapl_ep_disconnect, + &dapl_ep_post_send, + &dapl_ep_post_recv, + &dapl_ep_post_rdma_read, + &dapl_ep_post_rdma_write, + &dapl_ep_get_status, + &dapl_ep_free, + + &dapl_lmr_kcreate, + &dapl_lmr_query, + &dapl_lmr_free, + + &dapl_rmr_create, + &dapl_rmr_query, /* untested */ + &dapl_rmr_bind, + &dapl_rmr_free, + + &dapl_psp_create, + &dapl_psp_query, /* untested */ + &dapl_psp_free, + + &dapl_rsp_create, + &dapl_rsp_query, /* untested */ + &dapl_rsp_free, + + &dapl_pz_create, + &dapl_pz_query, /* untested */ + &dapl_pz_free, + + /* dat-1.1 */ + &dapl_psp_create_any, + &dapl_ep_reset, + + /* dat-1.2 */ + &dapl_lmr_sync_rdma_read, + &dapl_lmr_sync_rdma_write, + + &dapl_ep_create_with_srq, + &dapl_ep_recv_query, + &dapl_ep_set_watermark, + &dapl_srq_create, + &dapl_srq_free, + &dapl_srq_post_recv, + &dapl_srq_query, + &dapl_srq_resize, + &dapl_srq_set_lw +}; +#else +/* + * uDAPL version of the provider jump table + */ +DAT_PROVIDER g_dapl_provider_template = { + NULL, + 0, + &dapl_ia_open, + &dapl_ia_query, + &dapl_ia_close, + + &dapl_set_consumer_context, + &dapl_get_consumer_context, + &dapl_get_handle_type, + + &dapl_cno_create, + &dapl_cno_modify_agent, + &dapl_cno_query, + &dapl_cno_free, + &dapl_cno_wait, + + &dapl_cr_query, + &dapl_cr_accept, + &dapl_cr_reject, + &dapl_cr_handoff, + + &dapl_evd_create, + &dapl_evd_query, + &dapl_evd_modify_cno, + &dapl_evd_enable, + &dapl_evd_disable, + &dapl_evd_wait, + &dapl_evd_resize, + &dapl_evd_post_se, + &dapl_evd_dequeue, + &dapl_evd_free, + + &dapl_ep_create, + &dapl_ep_query, + &dapl_ep_modify, + &dapl_ep_connect, + &dapl_ep_dup_connect, + &dapl_ep_disconnect, + &dapl_ep_post_send, + &dapl_ep_post_recv, + &dapl_ep_post_rdma_read, + &dapl_ep_post_rdma_write, + &dapl_ep_get_status, + &dapl_ep_free, + + &dapl_lmr_create, + &dapl_lmr_query, + &dapl_lmr_free, + + &dapl_rmr_create, + &dapl_rmr_query, + &dapl_rmr_bind, + &dapl_rmr_free, + + &dapl_psp_create, + &dapl_psp_query, + &dapl_psp_free, + + &dapl_rsp_create, + &dapl_rsp_query, + &dapl_rsp_free, + + &dapl_pz_create, + &dapl_pz_query, + &dapl_pz_free, + + &dapl_psp_create_any, + &dapl_ep_reset, + &dapl_evd_set_unwaitable, + &dapl_evd_clear_unwaitable, + + /* dat-1.2 */ + &dapl_lmr_sync_rdma_read, + &dapl_lmr_sync_rdma_write, + + &dapl_ep_create_with_srq, + &dapl_ep_recv_query, + &dapl_ep_set_watermark, + &dapl_srq_create, + &dapl_srq_free, + &dapl_srq_post_recv, + &dapl_srq_query, + &dapl_srq_resize, + &dapl_srq_set_lw, + + /* dat-2.0 */ + &dapl_csp_create, + &dapl_csp_query, + &dapl_csp_free, + &dapl_ep_common_connect, + &dapl_rmr_create_for_ep, + &dapl_ep_post_send_with_invalidate, + &dapl_ep_post_rdma_read_to_rmr, + &dapl_cno_fd_create, + &dapl_cno_trigger, + &dapl_ia_ha +#ifdef DAT_EXTENSIONS + , &dapl_extensions +#endif +}; +#endif /* __KDAPL__ */ + +/********************************************************************* + * * + * Function Prototypes * + * * + *********************************************************************/ + +static DAT_BOOLEAN +dapl_provider_list_key_cmp(const char *name_a, const char *name_b); + +/********************************************************************* + * * + * Function Definitions * + * * + *********************************************************************/ + +DAT_RETURN dapl_provider_list_create(void) +{ + DAT_RETURN status; + + status = DAT_SUCCESS; + + /* create the head node */ + g_dapl_provider_list.head = + dapl_os_alloc(sizeof(DAPL_PROVIDER_LIST_NODE)); + if (NULL == g_dapl_provider_list.head) { + status = + DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); + goto bail; + } + + dapl_os_memzero(g_dapl_provider_list.head, + sizeof(DAPL_PROVIDER_LIST_NODE)); + + /* create the tail node */ + g_dapl_provider_list.tail = + dapl_os_alloc(sizeof(DAPL_PROVIDER_LIST_NODE)); + if (NULL == g_dapl_provider_list.tail) { + status = + DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); + goto bail; + } + + dapl_os_memzero(g_dapl_provider_list.tail, + sizeof(DAPL_PROVIDER_LIST_NODE)); + + g_dapl_provider_list.head->next = g_dapl_provider_list.tail; + g_dapl_provider_list.tail->prev = g_dapl_provider_list.head; + g_dapl_provider_list.size = 0; + + bail: + if (DAT_SUCCESS != status) { + if (NULL != g_dapl_provider_list.head) { + dapl_os_free(g_dapl_provider_list.head, + sizeof(DAPL_PROVIDER_LIST_NODE)); + } + + if (NULL != g_dapl_provider_list.tail) { + dapl_os_free(g_dapl_provider_list.tail, + sizeof(DAPL_PROVIDER_LIST_NODE)); + } + } + + return status; +} + +DAT_RETURN dapl_provider_list_destroy(void) +{ + DAPL_PROVIDER_LIST_NODE *cur_node; + + while (NULL != g_dapl_provider_list.head) { + cur_node = g_dapl_provider_list.head; + g_dapl_provider_list.head = cur_node->next; + + dapl_os_free(cur_node, sizeof(DAPL_PROVIDER_LIST_NODE)); + } + + return DAT_SUCCESS; +} + +DAT_COUNT dapl_provider_list_size(void) +{ + return g_dapl_provider_list.size; +} + +DAT_RETURN +dapl_provider_list_insert(IN const char *name, IN DAT_PROVIDER ** p_data) +{ + DAPL_PROVIDER_LIST_NODE *cur_node, *prev_node, *next_node; + DAT_RETURN status; + unsigned int len; + + status = DAT_SUCCESS; + + cur_node = dapl_os_alloc(sizeof(DAPL_PROVIDER_LIST_NODE)); + + if (NULL == cur_node) { + status = + DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); + goto bail; + } + + len = dapl_os_strlen(name); + + if (DAT_NAME_MAX_LENGTH <= len) { + status = + DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); + goto bail; + } + + /* insert node at end of list to preserve registration order */ + prev_node = g_dapl_provider_list.tail->prev; + next_node = g_dapl_provider_list.tail; + + dapl_os_memcpy(cur_node->name, name, len); + cur_node->name[len] = '\0'; + cur_node->data = g_dapl_provider_template; + cur_node->data.device_name = cur_node->name; + + cur_node->next = next_node; + cur_node->prev = prev_node; + + prev_node->next = cur_node; + next_node->prev = cur_node; + + g_dapl_provider_list.size++; + + if (NULL != p_data) { + *p_data = &cur_node->data; + } + + bail: + if (DAT_SUCCESS != status) { + if (NULL != cur_node) { + dapl_os_free(cur_node, sizeof(DAPL_PROVIDER_LIST_NODE)); + } + } + + return status; +} + +DAT_RETURN +dapl_provider_list_search(IN const char *name, OUT DAT_PROVIDER ** p_data) +{ + DAPL_PROVIDER_LIST_NODE *cur_node; + DAT_RETURN status; + + status = DAT_ERROR(DAT_PROVIDER_NOT_FOUND, DAT_NAME_NOT_REGISTERED); + + for (cur_node = g_dapl_provider_list.head->next; + g_dapl_provider_list.tail != cur_node; cur_node = cur_node->next) { + if (dapl_provider_list_key_cmp(cur_node->name, name)) { + if (NULL != p_data) { + *p_data = &cur_node->data; + } + + status = DAT_SUCCESS; + goto bail; + } + } + + bail: + return status; +} + +DAT_RETURN dapl_provider_list_remove(IN const char *name) +{ + DAPL_PROVIDER_LIST_NODE *cur_node, *prev_node, *next_node; + DAT_RETURN status; + + status = DAT_ERROR(DAT_PROVIDER_NOT_FOUND, DAT_NAME_NOT_REGISTERED); + + for (cur_node = g_dapl_provider_list.head->next; + g_dapl_provider_list.tail != cur_node; cur_node = cur_node->next) { + if (dapl_provider_list_key_cmp(cur_node->name, name)) { + prev_node = cur_node->prev; + next_node = cur_node->next; + + prev_node->next = next_node; + next_node->prev = prev_node; + + dapl_os_free(cur_node, sizeof(DAPL_PROVIDER_LIST_NODE)); + + g_dapl_provider_list.size--; + + status = DAT_SUCCESS; + goto bail; + } + } + + bail: + return status; +} + +DAT_BOOLEAN dapl_provider_list_key_cmp(const char *name_a, const char *name_b) +{ + unsigned int len; + + len = dapl_os_strlen(name_a); + + if (dapl_os_strlen(name_b) != len) { + return DAT_FALSE; + } else if (dapl_os_memcmp(name_a, name_b, len)) { + return DAT_FALSE; + } else { + return DAT_TRUE; + } +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_provider.h b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_provider.h new file mode 100644 index 00000000..32b91df1 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_provider.h @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dapl_provider.h + * + * PURPOSE: Provider function table + * Description: DAT Interfaces to this provider + * + * $Id:$ + **********************************************************************/ + +#ifndef _DAPL_PROVIDER_H_ +#define _DAPL_PROVIDER_H_ + +#include "dapl.h" + + +/********************************************************************* + * * + * Structures * + * * + *********************************************************************/ + +typedef struct DAPL_PROVIDER_LIST_NODE +{ + char name[DAT_NAME_MAX_LENGTH]; + DAT_PROVIDER data; + struct DAPL_PROVIDER_LIST_NODE *next; + struct DAPL_PROVIDER_LIST_NODE *prev; +} DAPL_PROVIDER_LIST_NODE; + + +typedef struct DAPL_PROVIDER_LIST +{ + DAPL_PROVIDER_LIST_NODE *head; + DAPL_PROVIDER_LIST_NODE *tail; + DAT_COUNT size; +} DAPL_PROVIDER_LIST; + + +/********************************************************************* + * * + * Global Data * + * * + *********************************************************************/ + +extern DAPL_PROVIDER_LIST g_dapl_provider_list; +extern DAT_PROVIDER g_dapl_provider_template; +extern int g_dapl_loopback_connection; + + +/********************************************************************* + * * + * Function Prototypes * + * * + *********************************************************************/ + +extern DAT_RETURN +dapl_provider_list_create( void ); + +extern DAT_RETURN +dapl_provider_list_destroy( void ); + +extern DAT_COUNT +dapl_provider_list_size( void ); + +extern DAT_RETURN +dapl_provider_list_insert( + IN const char *name, + OUT DAT_PROVIDER **p_data ); + +extern DAT_RETURN +dapl_provider_list_search( + IN const char *name, + OUT DAT_PROVIDER **p_data ); + +extern DAT_RETURN +dapl_provider_list_remove( + IN const char *name ); + + +#endif /* _DAPL_PROVIDER_H_ */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_psp_create.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_psp_create.c new file mode 100644 index 00000000..adef59f8 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_psp_create.c @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_psp_create.c + * + * PURPOSE: Connection management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 4 + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_sp_util.h" +#include "dapl_ia_util.h" +#include "dapl_adapter_util.h" + +/* + * dapl_psp_create + * + * uDAPL: User Direct Access Program Library Version 1.1, 6.4.1.1 + * + * Create a persistent Public Service Point that can receive multiple + * requests for connections and generate multiple connection request + * instances that will be delivered to the specified Event Dispatcher + * in a notification event. + * + * Input: + * ia_handle + * conn_qual + * evd_handle + * psp_flags + * + * Output: + * psp_handle + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + * DAT_CONN_QUAL_IN_USE + * DAT_MODEL_NOT_SUPPORTED + */ +DAT_RETURN DAT_API +dapl_psp_create(IN DAT_IA_HANDLE ia_handle, + IN DAT_CONN_QUAL conn_qual, + IN DAT_EVD_HANDLE evd_handle, + IN DAT_PSP_FLAGS psp_flags, OUT DAT_PSP_HANDLE * psp_handle) +{ + DAPL_IA *ia_ptr; + DAPL_SP *sp_ptr; + DAPL_EVD *evd_ptr; + DAT_BOOLEAN sp_found; + DAT_RETURN dat_status; + + ia_ptr = (DAPL_IA *) ia_handle; + dat_status = DAT_SUCCESS; + + if (DAPL_BAD_HANDLE(ia_ptr, DAPL_MAGIC_IA)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_IA); + goto bail; + } + if (DAPL_BAD_HANDLE(evd_handle, DAPL_MAGIC_EVD)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EVD_CR); + goto bail; + } + + if (psp_handle == NULL) { + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG5); + goto bail; + } + + evd_ptr = (DAPL_EVD *) evd_handle; + if (!(evd_ptr->evd_flags & DAT_EVD_CR_FLAG)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EVD_CR); + goto bail; + } + + if (psp_flags != DAT_PSP_CONSUMER_FLAG && + psp_flags != DAT_PSP_PROVIDER_FLAG) { + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG4); + goto bail; + } + + DAPL_CNTR(ia_ptr, DCNT_IA_PSP_CREATE); + + /* + * See if we have a quiescent listener to use for this PSP, else + * create one and set it listening + */ + sp_ptr = dapls_ia_sp_search(ia_ptr, conn_qual, DAT_TRUE); + sp_found = DAT_TRUE; + if (sp_ptr == NULL) { + /* Allocate PSP */ + sp_found = DAT_FALSE; + sp_ptr = dapls_sp_alloc(ia_ptr, DAT_TRUE); + if (sp_ptr == NULL) { + dat_status = + DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, + DAT_RESOURCE_MEMORY); + goto bail; + } + } else if (sp_ptr->listening == DAT_TRUE) { + dat_status = DAT_ERROR(DAT_CONN_QUAL_IN_USE, 0); + goto bail; + } + + /* + * Fill out the args for a PSP + */ + sp_ptr->conn_qual = conn_qual; + sp_ptr->evd_handle = evd_handle; + sp_ptr->psp_flags = psp_flags; + sp_ptr->ep_handle = NULL; + + /* + * Take a reference on the EVD handle + */ + dapl_os_atomic_inc(&((DAPL_EVD *) evd_handle)->evd_ref_count); + + /* + * Set up a listener for a connection. Connections can arrive + * even before this call returns! + */ + sp_ptr->state = DAPL_SP_STATE_PSP_LISTENING; + sp_ptr->listening = DAT_TRUE; + + /* + * If this is a new sp we need to add it to the IA queue, and set up + * a conn_listener. + */ + if (sp_found == DAT_FALSE) { + /* Link it onto the IA before enabling it to receive conn + * requests + */ + dapl_ia_link_psp(ia_ptr, sp_ptr); + + dat_status = dapls_ib_setup_conn_listener(ia_ptr, + conn_qual, sp_ptr); + + if (dat_status != DAT_SUCCESS) { + /* + * Have a problem setting up the connection, something + * wrong! Decrements the EVD refcount & release it. + */ + dapl_os_atomic_dec(&((DAPL_EVD *) evd_handle)-> + evd_ref_count); + sp_ptr->evd_handle = NULL; + dapls_ia_unlink_sp(ia_ptr, sp_ptr); + dapls_sp_free_sp(sp_ptr); + + dapl_dbg_log(DAPL_DBG_TYPE_CM, + "--> dapl_psp_create setup_conn_listener failed: %x\n", + dat_status); + + goto bail; + } + } + + /* + * Return handle to the user + */ + *psp_handle = (DAT_PSP_HANDLE) sp_ptr; + + bail: + return dat_status; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * c-brace-offset: -4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_psp_create_any.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_psp_create_any.c new file mode 100644 index 00000000..c9f53e07 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_psp_create_any.c @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_psp_create.c + * + * PURPOSE: Connection management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 4 + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_sp_util.h" +#include "dapl_ia_util.h" +#include "dapl_adapter_util.h" + +/* + * dapl_psp_create_any + * + * uDAPL: User Direct Access Program Library Version 1.1, 6.4.3.3 + * + * Create a persistent Public Service Point that can receive multiple + * requests for connections and generate multiple connection request + * instances that will be delivered to the specified Event Dispatcher + * in a notification event. Differs from dapl_psp_create() in that + * the conn_qual is selected by the implementation and returned to + * the user. + * + * Input: + * ia_handle + * evd_handle + * psp_flags + * + * Output: + * conn_qual + * psp_handle + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_HANDLE + * DAT_INVALID_PARAMETER + * DAT_CONN_QUAL_IN_USE + * DAT_MODEL_NOT_SUPPORTED + */ +DAT_RETURN DAT_API +dapl_psp_create_any(IN DAT_IA_HANDLE ia_handle, + OUT DAT_CONN_QUAL * conn_qual, + IN DAT_EVD_HANDLE evd_handle, + IN DAT_PSP_FLAGS psp_flags, OUT DAT_PSP_HANDLE * psp_handle) +{ + DAPL_IA *ia_ptr; + DAPL_SP *sp_ptr; + DAPL_EVD *evd_ptr; + DAT_RETURN dat_status; + static DAT_CONN_QUAL hint_conn_qual = 1024; /* seed value */ + DAT_CONN_QUAL lcl_conn_qual; + DAT_CONN_QUAL limit_conn_qual; + + ia_ptr = (DAPL_IA *) ia_handle; + dat_status = DAT_SUCCESS; + + if (DAPL_BAD_HANDLE(ia_ptr, DAPL_MAGIC_IA)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_IA); + goto bail; + } + if (DAPL_BAD_HANDLE(evd_handle, DAPL_MAGIC_EVD)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EVD_CR); + goto bail; + } + + if (psp_handle == NULL) { + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG5); + goto bail; + } + if (conn_qual == NULL) { + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG2); + goto bail; + } + + evd_ptr = (DAPL_EVD *) evd_handle; + if (!(evd_ptr->evd_flags & DAT_EVD_CR_FLAG)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EVD_CR); + goto bail; + } + + if (psp_flags != DAT_PSP_CONSUMER_FLAG && + psp_flags != DAT_PSP_PROVIDER_FLAG) { + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG4); + goto bail; + } + + /* Allocate PSP */ + sp_ptr = dapls_sp_alloc(ia_ptr, DAT_TRUE); + if (sp_ptr == NULL) { + dat_status = + DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); + goto bail; + } + + DAPL_CNTR(ia_ptr, DCNT_IA_PSP_CREATE_ANY); + + /* + * Fill out the args for a PSP + */ + sp_ptr->evd_handle = evd_handle; + sp_ptr->psp_flags = psp_flags; + sp_ptr->ep_handle = NULL; + + /* + * Take a reference on the EVD handle + */ + dapl_os_atomic_inc(&((DAPL_EVD *) evd_handle)->evd_ref_count); + + /* Link it onto the IA */ + dapl_ia_link_psp(ia_ptr, sp_ptr); + + /* + * Set up a listener for a connection. Connections can arrive + * even before this call returns! + */ + sp_ptr->state = DAPL_SP_STATE_PSP_LISTENING; + sp_ptr->listening = DAT_TRUE; + + limit_conn_qual = 0; + lcl_conn_qual = hint_conn_qual; + dat_status = ~DAT_SUCCESS; + + while (dat_status != DAT_SUCCESS) { + dat_status = dapls_ib_setup_conn_listener(ia_ptr, + lcl_conn_qual, + sp_ptr); + + lcl_conn_qual++; + + if (dat_status == DAT_CONN_QUAL_IN_USE) { + /* + * If we have a big number of tries and we still haven't + * found a service_ID we can use, bail out with an error, + * something is wrong! + */ + if (limit_conn_qual++ > 100000) { + dat_status = DAT_CONN_QUAL_UNAVAILABLE; + break; + } + } + } + hint_conn_qual = lcl_conn_qual; + + if (dat_status != DAT_SUCCESS) { + /* + * Have a problem setting up the connection, something wrong! + */ + dapl_os_atomic_dec(&((DAPL_EVD *) evd_handle)->evd_ref_count); + sp_ptr->evd_handle = NULL; + dapls_ia_unlink_sp(ia_ptr, sp_ptr); + dapls_sp_free_sp(sp_ptr); + + dapl_os_printf + ("--> dapl_psp_create cannot set up conn listener: %x\n", + dat_status); + + goto bail; + } + + sp_ptr->conn_qual = lcl_conn_qual - 1; + + /* + * Return handle to the user + */ + *conn_qual = sp_ptr->conn_qual; + *psp_handle = (DAT_PSP_HANDLE) sp_ptr; + + bail: + return dat_status; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * c-brace-offset: -4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_psp_free.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_psp_free.c new file mode 100644 index 00000000..9df2db1b --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_psp_free.c @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_psp_free.c + * + * PURPOSE: Connection management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 4 + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_sp_util.h" +#include "dapl_ia_util.h" +#include "dapl_adapter_util.h" + +/* + * dapl_psp_free + * + * uDAPL: User Direct Access Program Library Version 1.1, 6.4.1.2 + * + * Destroy a specific instance of a Service Point. + * + * Input: + * psp_handle + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + */ +DAT_RETURN DAT_API dapl_psp_free(IN DAT_PSP_HANDLE psp_handle) +{ + DAPL_IA *ia_ptr; + DAPL_SP *sp_ptr; + DAT_RETURN dat_status; + DAPL_SP_STATE save_state; + + sp_ptr = (DAPL_SP *) psp_handle; + dat_status = DAT_SUCCESS; + /* + * Verify handle + */ + dapl_dbg_log(DAPL_DBG_TYPE_CM, ">>> dapl_psp_free %p\n", psp_handle); + + if (DAPL_BAD_HANDLE(sp_ptr, DAPL_MAGIC_PSP)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_PSP); + goto bail; + } + + ia_ptr = sp_ptr->header.owner_ia; + + DAPL_CNTR(ia_ptr->header.owner_ia, DCNT_IA_PSP_FREE); + + /* + * Remove the connection listener if it has been established + * and there are no current connections in progress. + * If we defer removing the sp it becomes something of a zombie + * container until the last connection is disconnected, after + * which it will be cleaned up. + */ + dapl_os_lock(&sp_ptr->header.lock); + + sp_ptr->listening = DAT_FALSE; + + /* Release reference on EVD. If an error was encountered in a previous + * free the evd_handle will be NULL + */ + if (sp_ptr->evd_handle) { + dapl_os_atomic_dec(&((DAPL_EVD *) sp_ptr->evd_handle)-> + evd_ref_count); + sp_ptr->evd_handle = NULL; + } + + /* + * Release the base resource if there are no outstanding + * connections; else the last disconnect on this PSP will free it + * up. The PSP is used to contain CR records for each connection, + * which contain information necessary to disconnect. + */ + dapl_dbg_log(DAPL_DBG_TYPE_CM, + ">>> dapl_psp_free: state %d cr_list_count %d\n", + sp_ptr->state, sp_ptr->cr_list_count); + + if ((sp_ptr->state == DAPL_SP_STATE_PSP_LISTENING || + sp_ptr->state == DAPL_SP_STATE_PSP_PENDING) && + sp_ptr->cr_list_count == 0) { + save_state = sp_ptr->state; + sp_ptr->state = DAPL_SP_STATE_FREE; + dapl_os_unlock(&sp_ptr->header.lock); + + dat_status = dapls_ib_remove_conn_listener(ia_ptr, sp_ptr); + if (dat_status != DAT_SUCCESS) { + /* revert to entry state on error */ + sp_ptr->state = save_state; + goto bail; + } + dapls_ia_unlink_sp(ia_ptr, sp_ptr); + dapls_sp_free_sp(sp_ptr); + } else { + /* The PSP is now in the pending state, where it will sit until + * the last connection terminates or the app uses the same + * ServiceID again, which will reactivate it. + */ + sp_ptr->state = DAPL_SP_STATE_PSP_PENDING; + dapl_os_unlock(&sp_ptr->header.lock); + dapl_dbg_log(DAPL_DBG_TYPE_CM, + ">>> dapl_psp_free: PSP PENDING\n"); + } + + bail: + return dat_status; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * c-brace-offset: -4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_psp_query.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_psp_query.c new file mode 100644 index 00000000..d990ebdc --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_psp_query.c @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_psp_query.c + * + * PURPOSE: Connection management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 4 + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" + +/* + * dapl_psp_query + * + * uDAPL: User Direct Access Program Library Version 1.1, 6.4.1.3 + * + * Provide arguments of the public service points + * + * Input: + * psp_handle + * psp_args_mask + * + * Output: + * psp_args + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + */ +DAT_RETURN DAT_API +dapl_psp_query(IN DAT_PSP_HANDLE psp_handle, + IN DAT_PSP_PARAM_MASK psp_args_mask, + OUT DAT_PSP_PARAM * psp_param) +{ + DAPL_SP *sp_ptr; + DAT_RETURN dat_status; + + dat_status = DAT_SUCCESS; + + if (DAPL_BAD_HANDLE(psp_handle, DAPL_MAGIC_PSP) || + ((DAPL_SP *) psp_handle)->listening != DAT_TRUE) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_PSP); + goto bail; + } + + if (NULL == psp_param) { + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG3); + goto bail; + } + + sp_ptr = (DAPL_SP *) psp_handle; + + /* + * Fill in the PSP params + */ + psp_param->ia_handle = sp_ptr->header.owner_ia; + psp_param->conn_qual = sp_ptr->conn_qual; + psp_param->evd_handle = sp_ptr->evd_handle; + psp_param->psp_flags = sp_ptr->psp_flags; + + bail: + return dat_status; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * c-brace-offset: -4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_pz_create.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_pz_create.c new file mode 100644 index 00000000..95a47037 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_pz_create.c @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_pz_create.c + * + * PURPOSE: Memory management + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_pz_util.h" +#include "dapl_adapter_util.h" + +/* + * dapl_pz_create + * + * Create an instance of a protection zone + * + * Input: + * ia_handle + * + * Output: + * pz_handle + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + * DAT_INVLAID_HANDLE + */ +DAT_RETURN DAT_API +dapl_pz_create(IN DAT_IA_HANDLE ia_handle, OUT DAT_PZ_HANDLE * pz_handle) +{ + DAPL_IA *ia; + DAPL_PZ *pz; + DAT_RETURN dat_status; + + dapl_dbg_log(DAPL_DBG_TYPE_API, + "dapl_pz_create (%p, %p)\n", ia_handle, pz_handle); + + dat_status = DAT_SUCCESS; + if (DAPL_BAD_HANDLE(ia_handle, DAPL_MAGIC_IA)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_IA); + goto bail; + } + + if (NULL == pz_handle) { + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG2); + goto bail; + } + + ia = (DAPL_IA *) ia_handle; + + pz = dapl_pz_alloc(ia); + if (NULL == pz) { + dat_status = + DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); + goto bail; + } + DAPL_CNTR(ia, DCNT_IA_PZ_CREATE); + + dat_status = dapls_ib_pd_alloc(ia, pz); + if (DAT_SUCCESS != dat_status) { + dapl_pz_dealloc(pz); + pz = NULL; + } + + *pz_handle = pz; + + bail: + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_pz_free.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_pz_free.c new file mode 100644 index 00000000..6c3970cc --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_pz_free.c @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_pz_free.c + * + * PURPOSE: Memory management + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_pz_util.h" +#include "dapl_adapter_util.h" + +/* + * dapl_pz_free + * + * Remove an instance of a protection zone + * + * Input: + * pz_handle + * + * Output: + * None. + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_STATE + * DAT_INVALID_HANDLE + */ +DAT_RETURN DAT_API dapl_pz_free(IN DAT_PZ_HANDLE pz_handle) +{ + DAPL_PZ *pz; + DAT_RETURN dat_status; + + dapl_dbg_log(DAPL_DBG_TYPE_API, "dapl_pz_free (%p)\n", pz_handle); + + dat_status = DAT_SUCCESS; + if (DAPL_BAD_HANDLE(pz_handle, DAPL_MAGIC_PZ)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_PZ); + goto bail; + } + + pz = (DAPL_PZ *) pz_handle; + + DAPL_CNTR(pz->header.owner_ia, DCNT_IA_PZ_FREE); + + if (0 != dapl_os_atomic_read(&pz->pz_ref_count)) { + dat_status = + DAT_ERROR(DAT_INVALID_STATE, DAT_INVALID_STATE_PZ_IN_USE); + goto bail; + } + + dat_status = dapls_ib_pd_free(pz); + if (DAT_SUCCESS == dat_status) { + dapl_pz_dealloc(pz); + } + + bail: + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_pz_query.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_pz_query.c new file mode 100644 index 00000000..5829af4e --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_pz_query.c @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_pz_query.c + * + * PURPOSE: Memory management + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" + +/* + * dapl_pz_query + * + * Return the ia associated with the protection zone pz + * + * Input: + * pz_handle + * pz_param_mask + * + * Output: + * pz_param + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + * DAT_INVALID_PARAMETER + */ +DAT_RETURN DAT_API +dapl_pz_query(IN DAT_PZ_HANDLE pz_handle, + IN DAT_PZ_PARAM_MASK pz_param_mask, OUT DAT_PZ_PARAM * pz_param) +{ + DAPL_PZ *pz; + DAT_RETURN dat_status; + + dapl_dbg_log(DAPL_DBG_TYPE_API, + "dapl_pz_query (%p, %x, %p)\n", + pz_handle, pz_param_mask, pz_param); + + if (DAPL_BAD_HANDLE(pz_handle, DAPL_MAGIC_PZ)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_PZ); + goto bail; + } + if (NULL == pz_param) { + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG3); + goto bail; + } + + dat_status = DAT_SUCCESS; + pz = (DAPL_PZ *) pz_handle; + + /* Since the DAT_PZ_ARGS values are easily accessible, */ + /* don't bother checking the DAT_PZ_ARGS_MASK value */ + pz_param->ia_handle = (DAT_IA_HANDLE) pz->header.owner_ia; + + bail: + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_pz_util.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_pz_util.c new file mode 100644 index 00000000..ebfb6c8c --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_pz_util.c @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_pz_util.c + * + * PURPOSE: Manage PZ structure + * + * $Id:$ + **********************************************************************/ + +#include "dapl_pz_util.h" +#include "dapl_ia_util.h" + +/* + * dapl_pz_alloc + * + * alloc and initialize an PZ struct + * + * Input: + * none + * + * Output: + * pz_ptr + * + * Returns: + * none + * + */ +DAPL_PZ *dapl_pz_alloc(IN DAPL_IA * ia) +{ + DAPL_PZ *pz; + + /* Allocate PZ */ + pz = (DAPL_PZ *) dapl_os_alloc(sizeof(DAPL_PZ)); + if (NULL == pz) { + return (NULL); + } + + /* zero the structure */ + dapl_os_memzero(pz, sizeof(DAPL_PZ)); + + /* + * initialize the header + */ + pz->header.provider = ia->header.provider; + pz->header.magic = DAPL_MAGIC_PZ; + pz->header.handle_type = DAT_HANDLE_TYPE_PZ; + pz->header.owner_ia = ia; + pz->header.user_context.as_64 = 0; + pz->header.user_context.as_ptr = NULL; + dapl_llist_init_entry(&pz->header.ia_list_entry); + dapl_ia_link_pz(ia, pz); + dapl_os_lock_init(&pz->header.lock); + + /* + * initialize the body + */ + dapl_os_atomic_set(&pz->pz_ref_count, 0); + + return (pz); +} + +/* + * dapl_pz_free + * + * free an PZ struct + * + * Input: + * pz_ptr + * + * Output: + * none + * + * Returns: + * none + * + */ +void dapl_pz_dealloc(IN DAPL_PZ * pz) +{ + pz->header.magic = DAPL_MAGIC_INVALID; /* reset magic to prevent reuse */ + dapl_ia_unlink_pz(pz->header.owner_ia, pz); + dapl_os_lock_destroy(&pz->header.lock); + + dapl_os_free(pz, sizeof(DAPL_PZ)); +} diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_pz_util.h b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_pz_util.h new file mode 100644 index 00000000..c7aa8de8 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_pz_util.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dapl_pz_util.h + * + * PURPOSE: Utility defs & routines for the PZ data structure + * + * $Id:$ + * + **********************************************************************/ + +#ifndef _DAPL_PZ_UTIL_H_ +#define _DAPL_PZ_UTIL_H_ + +#include "dapl.h" + +extern DAPL_PZ * +dapl_pz_alloc ( + IN DAPL_IA *ia); + +extern void +dapl_pz_dealloc ( + IN DAPL_PZ *pz); + +#endif /* _DAPL_PZ_UTIL_H_ */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ring_buffer_util.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ring_buffer_util.c new file mode 100644 index 00000000..54517a93 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ring_buffer_util.c @@ -0,0 +1,317 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ring_buffer_util.c + * + * PURPOSE: Ring buffer management + * Description: Support and management functions for ring buffers + * + * $Id:$ + **********************************************************************/ + +#include "dapl_ring_buffer_util.h" + +/* + * dapls_rbuf_alloc + * + * Given a DAPL_RING_BUFFER, initialize it and provide memory for + * the ringbuf itself. A passed in size will be adjusted to the next + * largest power of two number to simplify management. + * + * Input: + * rbuf pointer to DAPL_RING_BUFFER + * size number of elements to allocate & manage + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * + */ +DAT_RETURN dapls_rbuf_alloc(INOUT DAPL_RING_BUFFER * rbuf, IN DAT_COUNT size) +{ + unsigned int rsize; /* real size */ + + /* The circular buffer must be allocated one too large. + * This eliminates any need for a distinct counter, as + * having the two pointers equal always means "empty" -- never "full" + */ + size++; + + /* Put size on a power of 2 boundary */ + rsize = 1; + while ((DAT_COUNT) rsize < size) { + rsize <<= 1; + } + + rbuf->base = (void *)dapl_os_alloc(rsize * sizeof(void *)); + if (rbuf->base != NULL) { + rbuf->lim = rsize - 1; + dapl_os_atomic_set(&rbuf->head, 0); + dapl_os_atomic_set(&rbuf->tail, 0); + } else { + return DAT_INSUFFICIENT_RESOURCES | DAT_RESOURCE_MEMORY; + } + + return DAT_SUCCESS; +} + +/* + * dapls_rbuf_realloc + * + * Resizes a DAPL_RING_BUFFER. This function is not thread safe; + * adding or removing elements from a ring buffer while resizing + * will have indeterminate results. + * + * Input: + * rbuf pointer to DAPL_RING_BUFFER + * size number of elements to allocate & manage + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_STATE + * DAT_INSUFFICIENT_RESOURCES + * + */ +DAT_RETURN dapls_rbuf_realloc(INOUT DAPL_RING_BUFFER * rbuf, IN DAT_COUNT size) +{ + DAPL_RING_BUFFER new_rbuf; + void *entry; + DAT_RETURN dat_status; + + dat_status = DAT_SUCCESS; + + /* decreasing the size or retaining the old size is not allowed */ + if (size <= rbuf->lim + 1) { + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG2); + goto bail; + } + + /* + * !This is NOT ATOMIC! + * Simple algorithm: Allocate a new ring buffer, take everything + * out of the old one and put it in the new one, and release the + * old base buffer. + */ + dat_status = dapls_rbuf_alloc(&new_rbuf, size); + if (dat_status != DAT_SUCCESS) { + goto bail; + } + + while ((entry = dapls_rbuf_remove(rbuf)) != NULL) { + /* We know entries will fit so ignore the return code */ + (void)dapls_rbuf_add(&new_rbuf, entry); + } + + /* release the old base buffer */ + dapl_os_free(rbuf->base, (rbuf->lim + 1) * sizeof(void *)); + + *rbuf = new_rbuf; + + bail: + return dat_status; +} + +/* + * dapls_rbuf_destroy + * + * Release the buffer and reset pointers to a DAPL_RING_BUFFER + * + * Input: + * rbuf pointer to DAPL_RING_BUFFER + * + * Output: + * none + * + * Returns: + * none + * + */ +void dapls_rbuf_destroy(IN DAPL_RING_BUFFER * rbuf) +{ + if ((NULL == rbuf) || (NULL == rbuf->base)) { + return; + } + + dapl_os_free(rbuf->base, (rbuf->lim + 1) * sizeof(void *)); + rbuf->base = NULL; + rbuf->lim = 0; + + return; +} + +/* + * dapls_rbuf_add + * + * Add an entry to the ring buffer + * + * Input: + * rbuf pointer to DAPL_RING_BUFFER + * entry entry to add + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES (queue full) + * + */ +DAT_RETURN dapls_rbuf_add(IN DAPL_RING_BUFFER * rbuf, IN void *entry) +{ + int pos; + int val; + + while (((dapl_os_atomic_read(&rbuf->head) + 1) & rbuf->lim) != + (dapl_os_atomic_read(&rbuf->tail) & rbuf->lim)) { + pos = dapl_os_atomic_read(&rbuf->head); + val = dapl_os_atomic_assign(&rbuf->head, pos, pos + 1); + if (val == pos) { + pos = (pos + 1) & rbuf->lim; /* verify in range */ + rbuf->base[pos] = entry; + return DAT_SUCCESS; + } + } + + return DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); + +} + +/* + * dapls_rbuf_remove + * + * Remove an entry from the ring buffer + * + * Input: + * rbuf pointer to DAPL_RING_BUFFER + * + * Output: + * entry entry removed from the ring buffer + * + * Returns: + * DAT_SUCCESS + * DAT_QUEUE_EMPTY + + */ +void *dapls_rbuf_remove(IN DAPL_RING_BUFFER * rbuf) +{ + int pos; + int val; + + while (dapl_os_atomic_read(&rbuf->head) != + dapl_os_atomic_read(&rbuf->tail)) { + pos = dapl_os_atomic_read(&rbuf->tail); + val = dapl_os_atomic_assign(&rbuf->tail, pos, pos + 1); + if (val == pos) { + pos = (pos + 1) & rbuf->lim; /* verify in range */ + + return (rbuf->base[pos]); + } + } + + return NULL; + +} + +/* + * dapli_rbuf_count + * + * Return the number of entries in use in the ring buffer + * + * Input: + * rbuf pointer to DAPL_RING_BUFFER + * + * + * Output: + * none + * + * Returns: + * count of entries + * + */ +DAT_COUNT dapls_rbuf_count(IN DAPL_RING_BUFFER * rbuf) +{ + DAT_COUNT count; + int head; + int tail; + + head = dapl_os_atomic_read(&rbuf->head) & rbuf->lim; + tail = dapl_os_atomic_read(&rbuf->tail) & rbuf->lim; + if (head > tail) { + count = head - tail; + } else { + /* add 1 to lim as it is a mask, number of entries - 1 */ + count = (rbuf->lim + 1 - tail + head) & rbuf->lim; + } + + return count; +} + +/* + * dapls_rbuf_adjust + * + * Adjusts the addresses of all elements stored in the + * ring buffer by a constant. This is useful for situations + * in which the memory area for the elements being stored + * has been reallocated (see dapl_evd_realloc() and helper + * functions). + * + * Input: + * rbuf pointer to DAPL_RING_BUFFER + * offset offset to adjust elemnt addresss by, + * used for addresses of type void * + * Output: + * none + * + * Returns: + * none + */ +void dapls_rbuf_adjust(IN DAPL_RING_BUFFER * rbuf, IN intptr_t offset) +{ + int pos; + + pos = dapl_os_atomic_read(&rbuf->head); + while (pos != dapl_os_atomic_read(&rbuf->tail)) { + rbuf->base[pos] = (void *)((char *)rbuf->base[pos] + offset); + pos = (pos + 1) & rbuf->lim; /* verify in range */ + } +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ring_buffer_util.h b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ring_buffer_util.h new file mode 100644 index 00000000..46c82c95 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_ring_buffer_util.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dapl_ring_buffer_util.h + * + * PURPOSE: Utility defs & routines for the ring buffer data structure + * + * $Id:$ + * + **********************************************************************/ + +#ifndef _DAPL_RING_BUFFER_H_ +#define _DAPL_RING_BUFFER_H_ + +#include "dapl.h" + +/* + * Prototypes + */ +DAT_RETURN dapls_rbuf_alloc ( + DAPL_RING_BUFFER *rbuf, + DAT_COUNT size ); + +DAT_RETURN dapls_rbuf_realloc ( + DAPL_RING_BUFFER *rbuf, + DAT_COUNT size ); + +void dapls_rbuf_destroy ( + DAPL_RING_BUFFER *rbuf); + +DAT_RETURN dapls_rbuf_add ( + DAPL_RING_BUFFER *rbuf, + void *entry); + +void * dapls_rbuf_remove ( + DAPL_RING_BUFFER *rbuf); + +DAT_COUNT dapls_rbuf_count ( + DAPL_RING_BUFFER *rbuf ); + +void dapls_rbuf_adjust ( + IN DAPL_RING_BUFFER *rbuf, + IN intptr_t offset); + + +/* + * Simple functions + */ +#define dapls_rbuf_empty(rbuf) (rbuf->head == rbuf->tail) + + +#endif /* _DAPL_RING_BUFFER_H_ */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_rmr_bind.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_rmr_bind.c new file mode 100644 index 00000000..ecb190b7 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_rmr_bind.c @@ -0,0 +1,314 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_rmr_bind.c + * + * PURPOSE: Memory management + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_rmr_util.h" +#include "dapl_ep_util.h" +#include "dapl_cookie.h" +#include "dapl_adapter_util.h" + +/********************************************************************* + * * + * Function Prototypes * + * * + *********************************************************************/ + +STATIC _INLINE_ DAT_RETURN +dapli_rmr_bind_fuse(IN DAPL_RMR * rmr, + IN DAT_LMR_HANDLE lmr_handle, + IN const DAT_LMR_TRIPLET * lmr_triplet, + IN DAT_MEM_PRIV_FLAGS mem_priv, + IN DAPL_EP * ep_ptr, + IN DAT_RMR_COOKIE user_cookie, + IN DAT_COMPLETION_FLAGS completion_flags, + OUT DAT_RMR_CONTEXT * rmr_context); + +STATIC _INLINE_ DAT_RETURN +dapli_rmr_bind_unfuse(IN DAPL_RMR * rmr, + IN DAPL_EP * ep_ptr, + IN DAT_RMR_COOKIE user_cookie, + IN DAT_COMPLETION_FLAGS completion_flags); + +/********************************************************************* + * * + * Function Definitions * + * * + *********************************************************************/ + +DAT_RETURN +dapli_rmr_bind_fuse(IN DAPL_RMR * rmr, + IN DAT_LMR_HANDLE lmr_handle, + IN const DAT_LMR_TRIPLET * lmr_triplet, + IN DAT_MEM_PRIV_FLAGS mem_priv, + IN DAPL_EP * ep_ptr, + IN DAT_RMR_COOKIE user_cookie, + IN DAT_COMPLETION_FLAGS completion_flags, + OUT DAT_RMR_CONTEXT * rmr_context) +{ + DAPL_LMR *lmr; + DAPL_COOKIE *cookie; + DAT_RETURN dat_status; + DAT_BOOLEAN is_signaled; + + lmr = (DAPL_LMR *) lmr_handle; + + /* if the ep in unconnected return an error. IB requires that the */ + /* QP be connected to change a memory window binding since: */ + /* */ + /* - memory window bind operations are WQEs placed on a QP's */ + /* send queue */ + /* */ + /* - QP's only process WQEs on the send queue when the QP is in */ + /* the RTS state */ + if (DAT_EP_STATE_CONNECTED != ep_ptr->param.ep_state) { + dat_status = + DAT_ERROR(DAT_INVALID_STATE, + dapls_ep_state_subtype(ep_ptr)); + goto bail; + } + + if (DAT_FALSE == + dapl_mr_bounds_check(dapl_mr_get_address + (lmr->param.region_desc, lmr->param.mem_type), + lmr->param.length, + lmr_triplet->virtual_address, + lmr_triplet->segment_length)) { + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG2); + goto bail; + } + + /* If the LMR, RMR, and EP are not in the same PZ, there is an error */ + if ((ep_ptr->param.pz_handle != lmr->param.pz_handle) || + (ep_ptr->param.pz_handle != rmr->param.pz_handle)) { + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG4); + goto bail; + } + + if (!dapl_rmr_validate_completion_flag(DAT_COMPLETION_SUPPRESS_FLAG, + ep_ptr->param.ep_attr. + request_completion_flags, + completion_flags) + || + !dapl_rmr_validate_completion_flag(DAT_COMPLETION_UNSIGNALLED_FLAG, + ep_ptr->param.ep_attr. + request_completion_flags, + completion_flags) + || + !dapl_rmr_validate_completion_flag + (DAT_COMPLETION_BARRIER_FENCE_FLAG, + ep_ptr->param.ep_attr.request_completion_flags, + completion_flags)) { + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG4); + goto bail; + } + + dat_status = dapls_rmr_cookie_alloc(&ep_ptr->req_buffer, + rmr, user_cookie, &cookie); + if (DAT_SUCCESS != dat_status) { + goto bail; + } + + is_signaled = + (completion_flags & DAT_COMPLETION_SUPPRESS_FLAG) ? DAT_FALSE : + DAT_TRUE; + + dat_status = dapls_ib_mw_bind(rmr, + lmr, + ep_ptr, + cookie, + lmr_triplet->virtual_address, + lmr_triplet->segment_length, + mem_priv, is_signaled); + if (DAT_SUCCESS != dat_status) { + dapls_cookie_dealloc(&ep_ptr->req_buffer, cookie); + goto bail; + } + + dapl_os_atomic_inc(&lmr->lmr_ref_count); + + /* if the RMR was previously bound */ + if (NULL != rmr->lmr) { + dapl_os_atomic_dec(&rmr->lmr->lmr_ref_count); + } + + rmr->param.mem_priv = mem_priv; + rmr->param.lmr_triplet = *lmr_triplet; + rmr->ep = ep_ptr; + rmr->lmr = lmr; + + if (NULL != rmr_context) { + *rmr_context = rmr->param.rmr_context; + } + + bail: + return dat_status; +} + +DAT_RETURN +dapli_rmr_bind_unfuse(IN DAPL_RMR * rmr, + IN DAPL_EP * ep_ptr, + IN DAT_RMR_COOKIE user_cookie, + IN DAT_COMPLETION_FLAGS completion_flags) +{ + DAPL_COOKIE *cookie; + DAT_RETURN dat_status; + DAT_BOOLEAN is_signaled; + + dat_status = DAT_SUCCESS; + /* + * if the ep in unconnected return an error. IB requires that the + * QP be connected to change a memory window binding since: + * + * - memory window bind operations are WQEs placed on a QP's + * send queue + * + * - QP's only process WQEs on the send queue when the QP is in + * the RTS state + */ + if (DAT_EP_STATE_CONNECTED != ep_ptr->param.ep_state) { + dat_status = + DAT_ERROR(DAT_INVALID_STATE, + dapls_ep_state_subtype(ep_ptr)); + goto bail1; + } + + /* If the RMR and EP are not in the same PZ, there is an error */ + if (ep_ptr->param.pz_handle != rmr->param.pz_handle) { + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG2); + goto bail1; + } + + if (!dapl_rmr_validate_completion_flag(DAT_COMPLETION_SUPPRESS_FLAG, + ep_ptr->param.ep_attr. + request_completion_flags, + completion_flags) + || + !dapl_rmr_validate_completion_flag(DAT_COMPLETION_UNSIGNALLED_FLAG, + ep_ptr->param.ep_attr. + request_completion_flags, + completion_flags) + || + !dapl_rmr_validate_completion_flag + (DAT_COMPLETION_BARRIER_FENCE_FLAG, + ep_ptr->param.ep_attr.request_completion_flags, + completion_flags)) { + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG2); + goto bail1; + } + + dat_status = dapls_rmr_cookie_alloc(&ep_ptr->req_buffer, + rmr, user_cookie, &cookie); + if (DAT_SUCCESS != dat_status) { + goto bail1; + } + + is_signaled = + (completion_flags & DAT_COMPLETION_UNSIGNALLED_FLAG) ? DAT_FALSE : + DAT_TRUE; + + dat_status = dapls_ib_mw_unbind(rmr, ep_ptr, cookie, is_signaled); + if (DAT_SUCCESS != dat_status) { + dapls_cookie_dealloc(&ep_ptr->req_buffer, cookie); + goto bail1; + } + + /* if the RMR was previously bound */ + if (NULL != rmr->lmr) { + dapl_os_atomic_dec(&rmr->lmr->lmr_ref_count); + } + + rmr->param.mem_priv = DAT_MEM_PRIV_NONE_FLAG; + rmr->param.lmr_triplet.lmr_context = 0; + rmr->param.lmr_triplet.virtual_address = 0; + rmr->param.lmr_triplet.segment_length = 0; + rmr->ep = ep_ptr; + rmr->lmr = NULL; + + bail1: + return dat_status; +} + +/* + * dapl_rmr_bind + * + * DAPL Requirements Version xxx, 6.6.4.4 + * + * Bind the RMR to the specified memory region within the LMR and + * provide a new rmr_context value. + * + * Input: + * Output: + */ +DAT_RETURN DAT_API +dapl_rmr_bind(IN DAT_RMR_HANDLE rmr_handle, + IN DAT_LMR_HANDLE lmr_handle, + IN const DAT_LMR_TRIPLET * lmr_triplet, + IN DAT_MEM_PRIV_FLAGS mem_priv, + IN DAT_VA_TYPE va_type, + IN DAT_EP_HANDLE ep_handle, + IN DAT_RMR_COOKIE user_cookie, + IN DAT_COMPLETION_FLAGS completion_flags, + OUT DAT_RMR_CONTEXT * rmr_context) +{ + DAPL_RMR *rmr; + DAPL_EP *ep_ptr; + + if (DAPL_BAD_HANDLE(rmr_handle, DAPL_MAGIC_RMR)) { + return DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_RMR); + } + if (DAPL_BAD_HANDLE(ep_handle, DAPL_MAGIC_EP)) { + return DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP); + } + + rmr = (DAPL_RMR *) rmr_handle; + ep_ptr = (DAPL_EP *) ep_handle; + + /* if the rmr should be bound */ + if (0 != lmr_triplet->segment_length) { + return dapli_rmr_bind_fuse(rmr, + lmr_handle, + lmr_triplet, + mem_priv, + ep_ptr, + user_cookie, + completion_flags, rmr_context); + } else { /* the rmr should be unbound */ + + return dapli_rmr_bind_unfuse(rmr, + ep_ptr, + user_cookie, completion_flags); + } +} diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_rmr_create.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_rmr_create.c new file mode 100644 index 00000000..3811bf93 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_rmr_create.c @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_rmr_create.c + * + * PURPOSE: Memory management + * + * $Id:$ + **********************************************************************/ + +#include "dapl_rmr_util.h" +#include "dapl_adapter_util.h" + +/* + * dapl_rmr_create + * + * Create a remote memory region for the specified protection zone + * + * Input: + * pz_handle + * + * Output: + * rmr_handle + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + */ +DAT_RETURN DAT_API +dapl_rmr_create(IN DAT_PZ_HANDLE pz_handle, OUT DAT_RMR_HANDLE * rmr_handle) +{ + DAPL_PZ *pz; + DAPL_RMR *rmr; + DAT_RETURN dat_status; + + dat_status = DAT_SUCCESS; + + if (DAPL_BAD_HANDLE(pz_handle, DAPL_MAGIC_PZ)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_PZ); + goto bail; + } + + pz = (DAPL_PZ *) pz_handle; + rmr = dapl_rmr_alloc(pz); + + if (rmr == NULL) { + dat_status = + DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); + goto bail; + } + DAPL_CNTR(pz->header.owner_ia, DCNT_IA_RMR_CREATE); + + dat_status = dapls_ib_mw_alloc(rmr); + + if (dat_status != DAT_SUCCESS) { + dapl_rmr_dealloc(rmr); + dat_status = + DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, + DAT_RESOURCE_MEMORY_REGION); + goto bail; + } + + dapl_os_atomic_inc(&pz->pz_ref_count); + + *rmr_handle = rmr; + + bail: + return dat_status; +} + +/* + * dapl_rmr_create_for_ep + * + * DAPL Requirements Version 2.0, 6.7.3.x + * + * Creates an RMR that is specific to a single connection at a time. + * + * This operation is relatively heavy. The created RMR can be bound to a + * memory region within the LMR through a lightweight dat_rmr_bind + * operation for EPs that use the pz_handle that generates rmr_context. + * + * If the operation fails (does not return DAT_SUCCESS), the return values + * of rmr_handle are undefined and Consumers should not use it. + * pz_handle provide Consumers a way to restrict access to an RMR by + * authorized connections only. + * + * + * Input: + * pz_handle + * + * Output: + * rmr_handle + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_HANDLE + * DAT_MODEL_NOT_SUPPORTED + */ +DAT_RETURN DAT_API dapl_rmr_create_for_ep(IN DAT_PZ_HANDLE pz_handle, /* pz_handle */ + OUT DAT_RMR_HANDLE * rmr_handle) +{ /* rmr_handle */ + return DAT_MODEL_NOT_SUPPORTED; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_rmr_free.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_rmr_free.c new file mode 100644 index 00000000..d3abecb8 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_rmr_free.c @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_rmr_free.c + * + * PURPOSE: Memory management + * + * $Id:$ + **********************************************************************/ + +#include "dapl_rmr_util.h" +#include "dapl_adapter_util.h" +#include "dapl_ia_util.h" + +/* + * dapl_rmr_free + * + * Destroy an instance of the Remote Memory Region + * + * Input: + * rmr_handle + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + */ +DAT_RETURN DAT_API dapl_rmr_free(IN DAT_RMR_HANDLE rmr_handle) +{ + DAPL_RMR *rmr; + DAPL_PZ *pz; + DAT_RETURN dat_status; + + dat_status = DAT_SUCCESS; + + if (DAPL_BAD_HANDLE(rmr_handle, DAPL_MAGIC_RMR)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_RMR); + goto bail; + } + + rmr = (DAPL_RMR *) rmr_handle; + pz = (DAPL_PZ *) rmr->param.pz_handle; + DAPL_CNTR(pz->header.owner_ia, DCNT_IA_RMR_FREE); + + /* + * If the user did not perform an unbind op, release + * counts here. + */ + if (rmr->param.lmr_triplet.virtual_address != 0) { + dapl_os_atomic_dec(&rmr->lmr->lmr_ref_count); + rmr->param.lmr_triplet.virtual_address = 0; + } + + dat_status = dapls_ib_mw_free(rmr); + + if (dat_status != DAT_SUCCESS) { + goto bail; + } + + dapl_os_atomic_dec(&rmr->pz->pz_ref_count); + + dapl_rmr_dealloc(rmr); + + bail: + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_rmr_query.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_rmr_query.c new file mode 100644 index 00000000..d18aa84b --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_rmr_query.c @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_rmr_query.c + * + * PURPOSE: Memory management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 6 + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" + +/* + * dapl_rmr_query + * + * DAPL Requirements Version xxx, 6.6.4.3 + * + * Provide the RMR arguments. + * + * Input: + * rmr_handle + * rmr_args_mask + * + * Output: + * rmr_args + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + * DAT_INVALID_PARAMETER + */ +DAT_RETURN DAT_API +dapl_rmr_query(IN DAT_RMR_HANDLE rmr_handle, + IN DAT_RMR_PARAM_MASK rmr_param_mask, + IN DAT_RMR_PARAM * rmr_param) +{ + DAPL_RMR *rmr; + DAT_RETURN dat_status; + + dat_status = DAT_SUCCESS; + + if (DAPL_BAD_HANDLE(rmr_handle, DAPL_MAGIC_RMR)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_RMR); + goto bail; + } + if (NULL == rmr_param) { + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG3); + goto bail; + } + + rmr = (DAPL_RMR *) rmr_handle; + + /* If the RMR is unbound, there is no LMR triplet associated with */ + /* this RMR. If the consumer requests this field, return an error. */ + if ((rmr_param_mask & DAT_RMR_FIELD_LMR_TRIPLET) && (NULL == rmr->lmr)) { + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG2); + goto bail; + } + + dapl_os_memcpy(rmr_param, &rmr->param, sizeof(DAT_RMR_PARAM)); + + bail: + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_rmr_util.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_rmr_util.c new file mode 100644 index 00000000..26214914 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_rmr_util.c @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_rmr_util.h" +#include "dapl_ia_util.h" + +DAPL_RMR *dapl_rmr_alloc(IN DAPL_PZ * pz) +{ + DAPL_RMR *rmr; + + /* Allocate LMR */ + rmr = (DAPL_RMR *) dapl_os_alloc(sizeof(DAPL_RMR)); + if (NULL == rmr) { + return (NULL); + } + + /* zero the structure */ + dapl_os_memzero(rmr, sizeof(DAPL_RMR)); + + /* + * initialize the header + */ + rmr->header.provider = pz->header.provider; + rmr->header.magic = DAPL_MAGIC_RMR; + rmr->header.handle_type = DAT_HANDLE_TYPE_RMR; + rmr->header.owner_ia = pz->header.owner_ia; + rmr->header.user_context.as_64 = 0; + rmr->header.user_context.as_ptr = 0; + dapl_llist_init_entry(&rmr->header.ia_list_entry); + dapl_ia_link_rmr(rmr->header.owner_ia, rmr); + dapl_os_lock_init(&rmr->header.lock); + + /* + * initialize the body + */ + rmr->param.ia_handle = (DAT_IA_HANDLE) pz->header.owner_ia; + rmr->param.pz_handle = (DAT_PZ_HANDLE) pz; + rmr->param.lmr_triplet.lmr_context = 0; + rmr->param.lmr_triplet.virtual_address = 0; + rmr->param.lmr_triplet.segment_length = 0; + + rmr->param.mem_priv = 0; + rmr->pz = pz; + rmr->lmr = NULL; + + return (rmr); +} + +void dapl_rmr_dealloc(IN DAPL_RMR * rmr) +{ + rmr->header.magic = DAPL_MAGIC_INVALID; /* reset magic to prevent reuse */ + + dapl_ia_unlink_rmr(rmr->header.owner_ia, rmr); + dapl_os_lock_destroy(&rmr->header.lock); + + dapl_os_free((void *)rmr, sizeof(DAPL_RMR)); +} diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_rmr_util.h b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_rmr_util.h new file mode 100644 index 00000000..3c2f6301 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_rmr_util.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dapl_rmr_util.h + * + * PURPOSE: Utility defs & routines for the RMR data structure + * + * $Id:$ + * + **********************************************************************/ + +#ifndef _DAPL_RMR_UTIL_H_ +#define _DAPL_RMR_UTIL_H_ + +#include "dapl_mr_util.h" + +/********************************************************************* + * * + * Function Prototypes * + * * + *********************************************************************/ + +extern DAPL_RMR * +dapl_rmr_alloc ( + IN DAPL_PZ *pz); + +extern void +dapl_rmr_dealloc ( + IN DAPL_RMR *rmr); + +STATIC _INLINE_ DAT_BOOLEAN +dapl_rmr_validate_completion_flag ( + IN DAT_COMPLETION_FLAGS mask, + IN DAT_COMPLETION_FLAGS allow, + IN DAT_COMPLETION_FLAGS request); + + +/********************************************************************* + * * + * Inline Functions * + * * + *********************************************************************/ + +STATIC _INLINE_ DAT_BOOLEAN +dapl_rmr_validate_completion_flag ( + IN DAT_COMPLETION_FLAGS mask, + IN DAT_COMPLETION_FLAGS allow, + IN DAT_COMPLETION_FLAGS request) +{ + if ( (mask & request ) && !(mask & allow) ) + { + return DAT_FALSE; + } + else + { + return DAT_TRUE; + } +} + +#endif /* _DAPL_RMR_UTIL_H_*/ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_rsp_create.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_rsp_create.c new file mode 100644 index 00000000..3e36e81d --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_rsp_create.c @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_rsp_create.c + * + * PURPOSE: Connection management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 4 + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_sp_util.h" +#include "dapl_ia_util.h" +#include "dapl_ep_util.h" +#include "dapl_adapter_util.h" + +/* + * dapl_rsp_create + * + * uDAPL: User Direct Access Program Library Version 1.1, 6.4.3.4.1 + * + * Create a Resereved Service Point with the specified Endpoint + * that generates at most one Connection Request that is + * delivered to the specified Event Dispatcher in a notification + * event + * + * Input: + * ia_handle + * conn_qual + * ep_handle + * evd_handle + * + * Output: + * rsp_handle + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + * DAT_INVALID_STATE + * DAT_CONN_QUAL_IN_USE + */ +DAT_RETURN DAT_API +dapl_rsp_create(IN DAT_IA_HANDLE ia_handle, + IN DAT_CONN_QUAL conn_qual, + IN DAT_EP_HANDLE ep_handle, + IN DAT_EVD_HANDLE evd_handle, OUT DAT_RSP_HANDLE * rsp_handle) +{ + DAPL_IA *ia_ptr; + DAPL_SP *sp_ptr; + DAPL_EVD *evd_ptr; + DAPL_EP *ep_ptr; + DAT_BOOLEAN sp_found; + DAT_RETURN dat_status; + + dat_status = DAT_SUCCESS; + ia_ptr = (DAPL_IA *) ia_handle; + + dapl_dbg_log(DAPL_DBG_TYPE_CM, + ">>> dapl_rsp_free conn_qual: %x EP: %p\n", + conn_qual, ep_handle); + + if (DAPL_BAD_HANDLE(ia_ptr, DAPL_MAGIC_IA)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_IA); + goto bail; + } + if (DAPL_BAD_HANDLE(ep_handle, DAPL_MAGIC_EP)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP); + goto bail; + } + if (DAPL_BAD_HANDLE(evd_handle, DAPL_MAGIC_EVD)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EVD_CR); + goto bail; + } + + if (rsp_handle == NULL) { + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG5); + goto bail; + } + + ep_ptr = (DAPL_EP *) ep_handle; + if (ep_ptr->param.ep_state != DAT_EP_STATE_UNCONNECTED) { + dat_status = + DAT_ERROR(DAT_INVALID_STATE, + dapls_ep_state_subtype(ep_ptr)); + goto bail; + } + + evd_ptr = (DAPL_EVD *) evd_handle; + if (!(evd_ptr->evd_flags & DAT_EVD_CR_FLAG)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EVD_CR); + goto bail; + } + + DAPL_CNTR(ia_ptr, DCNT_IA_RSP_CREATE); + + sp_ptr = dapls_ia_sp_search(ia_ptr, conn_qual, DAT_FALSE); + sp_found = DAT_TRUE; + if (sp_ptr == NULL) { + sp_found = DAT_FALSE; + + /* Allocate RSP */ + sp_ptr = dapls_sp_alloc(ia_ptr, DAT_FALSE); + if (sp_ptr == NULL) { + dat_status = + DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, + DAT_RESOURCE_MEMORY); + goto bail; + } + } + + /* + * Fill out the RSP args + */ + sp_ptr->conn_qual = conn_qual; + sp_ptr->evd_handle = evd_handle; + sp_ptr->psp_flags = 0; + sp_ptr->ep_handle = ep_handle; + + /* + * Take a reference on the EVD handle + */ + dapl_os_atomic_inc(&((DAPL_EVD *) evd_handle)->evd_ref_count); + + /* + * Update the EP state indicating the provider now owns it + */ + ep_ptr->param.ep_state = DAT_EP_STATE_RESERVED; + + /* + * Set up a listener for a connection. Connections can arrive + * even before this call returns! + */ + sp_ptr->state = DAPL_SP_STATE_RSP_LISTENING; + sp_ptr->listening = DAT_TRUE; + + if (sp_found == DAT_FALSE) { + /* Link it onto the IA */ + dapl_ia_link_rsp(ia_ptr, sp_ptr); + + dat_status = dapls_ib_setup_conn_listener(ia_ptr, + conn_qual, sp_ptr); + + if (dat_status != DAT_SUCCESS) { + /* + * Have a problem setting up the connection, something + * wrong! Decrements the EVD refcount & release it. Set + * the state to FREE, so we know the call failed. + */ + dapl_os_atomic_dec(&((DAPL_EVD *) evd_handle)-> + evd_ref_count); + sp_ptr->evd_handle = NULL; + sp_ptr->state = DAPL_SP_STATE_FREE; + dapls_ia_unlink_sp(ia_ptr, sp_ptr); + dapls_sp_free_sp(sp_ptr); + + dapl_dbg_log(DAPL_DBG_TYPE_CM, + "--> dapl_rsp_create setup_conn_listener failed: %x\n", + dat_status); + + goto bail; + } + } + + /* + * Return handle to the user + */ + *rsp_handle = (DAT_RSP_HANDLE) sp_ptr; + + bail: + return dat_status; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * c-brace-offset: -4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_rsp_free.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_rsp_free.c new file mode 100644 index 00000000..6d5c4641 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_rsp_free.c @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_rsp_free.c + * + * PURPOSE: Connection management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 4 + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_sp_util.h" +#include "dapl_ia_util.h" +#include "dapl_adapter_util.h" + +/* + * dapl_rsp_free + * + * uDAPL: User Direct Access Program Library Version 1.1, 6.4.3.5 + * + * Destroy a specific instance of a Reserved Service Point. + * + * Input: + * rsp_handle + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + */ +DAT_RETURN DAT_API dapl_rsp_free(IN DAT_RSP_HANDLE rsp_handle) +{ + DAPL_IA *ia_ptr; + DAPL_SP *sp_ptr; + DAPL_EP *ep_ptr; + DAT_RETURN dat_status; + + dat_status = DAT_SUCCESS; + + sp_ptr = (DAPL_SP *) rsp_handle; + /* + * Verify handle + */ + dapl_dbg_log(DAPL_DBG_TYPE_CM, ">>> dapl_rsp_free %p\n", rsp_handle); + if (DAPL_BAD_HANDLE(sp_ptr, DAPL_MAGIC_RSP)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_RSP); + goto bail; + } + + /* ia_ptr = (DAPL_IA *)sp_ptr->header.owner_ia; */ + ia_ptr = sp_ptr->header.owner_ia; + + DAPL_CNTR(ia_ptr, DCNT_IA_RSP_FREE); + + /* + * Remove the connection listener if there are no connections. If + * we defer removing the sp it becomes something of a zombie + * container until disconnection, after which it will be cleaned up. + */ + dapl_os_lock(&sp_ptr->header.lock); + + /* + * Make sure we don't leave a dangling EP. If the state is still + * RESERVED then the RSP still owns it. + */ + ep_ptr = (DAPL_EP *) sp_ptr->ep_handle; + if (ep_ptr != NULL && ep_ptr->param.ep_state == DAT_EP_STATE_RESERVED) { + ep_ptr->param.ep_state = DAT_EP_STATE_UNCONNECTED; + } + sp_ptr->ep_handle = NULL; + + /* Release reference on EVD. If an error was encountered in a previous + * free the evd_handle will be NULL + */ + if (sp_ptr->evd_handle) { + dapl_os_atomic_dec(&((DAPL_EVD *) sp_ptr->evd_handle)-> + evd_ref_count); + sp_ptr->evd_handle = NULL; + } + + /* + * Release the base resource if there are no outstanding connections; + * else the last disconnect on this RSP will free it up. The RSP + * is used to contain CR records for each connection, which + * contain information necessary to disconnect. + * sp_ptr->listening will be DAT_TRUE if there has never been a + * connection event, and DAT_FALSE if a connection attempt resulted + * in a reject. + */ + if (sp_ptr->cr_list_count == 0) { + /* This RSP has never been used. Clean it up */ + sp_ptr->listening = DAT_FALSE; + sp_ptr->state = DAPL_SP_STATE_FREE; + dapl_os_unlock(&sp_ptr->header.lock); + + dat_status = dapls_ib_remove_conn_listener(ia_ptr, sp_ptr); + if (dat_status != DAT_SUCCESS) { + sp_ptr->state = DAPL_SP_STATE_RSP_LISTENING; + goto bail; + } + dapls_ia_unlink_sp(ia_ptr, sp_ptr); + dapls_sp_free_sp(sp_ptr); + } else { + /* The RSP is now in the pending state, where it will sit until + * the connection terminates or the app uses the same + * ServiceID again, which will reactivate it. + */ + sp_ptr->state = DAPL_SP_STATE_RSP_PENDING; + dapl_os_unlock(&sp_ptr->header.lock); + } + + bail: + return dat_status; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * c-brace-offset: -4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_rsp_query.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_rsp_query.c new file mode 100644 index 00000000..dfc8145f --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_rsp_query.c @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_rsp_query.c + * + * PURPOSE: Connection management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 4 + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" + +/* + * dapl_rsp_query + * + * uDAPL: User Direct Access Program Library Version 1.1, 6.4.1.6 + * + * Provide arguments of the reserved service points + * + * Input: + * rsp_handle + * rsp_args_mask + * + * Output: + * rsp_args + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + */ +DAT_RETURN DAT_API +dapl_rsp_query(IN DAT_RSP_HANDLE rsp_handle, + IN DAT_RSP_PARAM_MASK rsp_mask, OUT DAT_RSP_PARAM * rsp_param) +{ + DAPL_SP *sp_ptr; + DAT_RETURN dat_status; + + dat_status = DAT_SUCCESS; + + if (DAPL_BAD_HANDLE(rsp_handle, DAPL_MAGIC_RSP)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_RSP); + goto bail; + } + + if (NULL == rsp_param) { + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG3); + goto bail; + } + + sp_ptr = (DAPL_SP *) rsp_handle; + + /* + * Fill in the RSP params + */ + rsp_param->ia_handle = sp_ptr->header.owner_ia; + rsp_param->conn_qual = sp_ptr->conn_qual; + rsp_param->evd_handle = sp_ptr->evd_handle; + rsp_param->ep_handle = sp_ptr->ep_handle; + + bail: + return dat_status; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * c-brace-offset: -4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_set_consumer_context.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_set_consumer_context.c new file mode 100644 index 00000000..86874b9a --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_set_consumer_context.c @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_set_consumer_context.c + * + * PURPOSE: Interface Adapter management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 2 + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" + +/* + * dapl_set_consumer_context + * + * DAPL Requirements Version xxx, 6.2.2.1 + * + * Set a consumer context in the provided dat_handle + * + * Input: + * dat_handle + * context + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + */ +DAT_RETURN DAT_API +dapl_set_consumer_context(IN DAT_HANDLE dat_handle, IN DAT_CONTEXT context) +{ + DAT_RETURN dat_status; + DAPL_HEADER *header; + + dat_status = DAT_SUCCESS; + + header = (DAPL_HEADER *) dat_handle; + if (((header) == NULL) || + DAPL_BAD_PTR(header) || + (header->magic != DAPL_MAGIC_IA && + header->magic != DAPL_MAGIC_EVD && + header->magic != DAPL_MAGIC_EP && + header->magic != DAPL_MAGIC_LMR && + header->magic != DAPL_MAGIC_RMR && + header->magic != DAPL_MAGIC_PZ && + header->magic != DAPL_MAGIC_PSP && + header->magic != DAPL_MAGIC_RSP && + header->magic != DAPL_MAGIC_CR)) { + dat_status = DAT_ERROR(DAT_INVALID_HANDLE, 0); + goto bail; + } + header->user_context = context; + + bail: + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_sp_util.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_sp_util.c new file mode 100644 index 00000000..ffc50de2 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_sp_util.c @@ -0,0 +1,282 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_sp_util.c + * + * PURPOSE: Manage PSP Info structure + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_ep_util.h" +#include "dapl_sp_util.h" +#include "dapl_cr_util.h" + +/* + * Local definitions + */ + +/* + * dapl_sp_alloc + * + * alloc and initialize a PSP INFO struct + * + * Input: + * IA INFO struct ptr + * + * Output: + * sp_ptr + * + * Returns: + * NULL + * pointer to sp info struct + * + */ +DAPL_SP *dapls_sp_alloc(IN DAPL_IA * ia_ptr, IN DAT_BOOLEAN is_psp) +{ + DAPL_SP *sp_ptr; + + /* Allocate EP */ + sp_ptr = (DAPL_SP *) dapl_os_alloc(sizeof(DAPL_SP)); + if (sp_ptr == NULL) { + return (NULL); + } + + /* zero the structure */ + dapl_os_memzero(sp_ptr, sizeof(DAPL_SP)); + + /* + * initialize the header + */ + sp_ptr->header.provider = ia_ptr->header.provider; + if (is_psp) { + sp_ptr->header.magic = DAPL_MAGIC_PSP; + sp_ptr->header.handle_type = DAT_HANDLE_TYPE_PSP; + } else { + sp_ptr->header.magic = DAPL_MAGIC_RSP; + sp_ptr->header.handle_type = DAT_HANDLE_TYPE_RSP; + } + sp_ptr->header.owner_ia = ia_ptr; + sp_ptr->header.user_context.as_64 = 0; + sp_ptr->header.user_context.as_ptr = NULL; + dapl_llist_init_entry(&sp_ptr->header.ia_list_entry); + dapl_os_lock_init(&sp_ptr->header.lock); + +#if defined(_VENDOR_IBAL_) + dapl_os_wait_object_init(&sp_ptr->wait_object); +#endif + /* + * Initialize the Body (set to NULL above) + */ + dapl_llist_init_head(&sp_ptr->cr_list_head); + + return (sp_ptr); +} + +/* + * dapl_sp_free + * + * Free the passed in PSP structure. + * + * Input: + * entry point pointer + * + * Output: + * none + * + * Returns: + * none + * + */ +void dapls_sp_free_sp(IN DAPL_SP * sp_ptr) +{ + dapl_os_assert(sp_ptr->header.magic == DAPL_MAGIC_PSP || + sp_ptr->header.magic == DAPL_MAGIC_RSP); + dapl_os_assert(dapl_llist_is_empty(&sp_ptr->cr_list_head)); + +#if defined(_VENDOR_IBAL_) + dapl_os_wait_object_destroy(&sp_ptr->wait_object); +#endif + dapl_os_lock(&sp_ptr->header.lock); + sp_ptr->header.magic = DAPL_MAGIC_INVALID; /* reset magic to prevent reuse */ + dapl_os_unlock(&sp_ptr->header.lock); + dapl_os_free(sp_ptr, sizeof(DAPL_SP)); +} + +/* + * dapl_cr_link_cr + * + * Add a cr to a PSP structure + * + * Input: + * sp_ptr + * cr_ptr + * + * Output: + * none + * + * Returns: + * none + * + */ +void dapl_sp_link_cr(IN DAPL_SP * sp_ptr, IN DAPL_CR * cr_ptr) +{ + dapl_os_lock(&sp_ptr->header.lock); + dapl_llist_add_tail(&sp_ptr->cr_list_head, + &cr_ptr->header.ia_list_entry, cr_ptr); + sp_ptr->cr_list_count++; + dapl_os_unlock(&sp_ptr->header.lock); +} + +/* + * dapl_sp_search_cr + * + * Search for a CR on the PSP cr_list with a matching cm_handle. When + * found, remove it from the list and update fields. + * + * Must be called with the sp_ptr lock taken. + * + * Input: + * sp_ptr + * ib_cm_handle + * + * Output: + * none + * + * Returns: + * cr_ptr_fnd Pointer to matching DAPL_CR + * + */ +DAPL_CR *dapl_sp_search_cr(IN DAPL_SP * sp_ptr, + IN dp_ib_cm_handle_t ib_cm_handle) +{ + DAPL_CR *cr_ptr; + DAPL_CR *cr_ptr_fnd; + + if (dapl_llist_is_empty(&sp_ptr->cr_list_head)) { + return NULL; + } + cr_ptr_fnd = NULL; + cr_ptr = (DAPL_CR *) dapl_llist_peek_head(&sp_ptr->cr_list_head); + dapl_os_assert(cr_ptr); + + do { + if (cr_ptr->ib_cm_handle == ib_cm_handle) { + cr_ptr_fnd = cr_ptr; + + break; + } + cr_ptr = cr_ptr->header.ia_list_entry.flink->data; + } while ((void *)cr_ptr != (void *)sp_ptr->cr_list_head->data); + + return cr_ptr_fnd; +} + +/* + * dapl_sp_remove_cr + * + * Remove the CR from the PSP. Done prior to freeing the CR resource. + * + * Must be called with the sp_ptr lock taken. + * + * Input: + * sp_ptr + * cr_ptr + * + * Output: + * none + * + * Returns: + * void + * + */ +void dapl_sp_remove_cr(IN DAPL_SP * sp_ptr, IN DAPL_CR * cr_ptr) +{ + if (dapl_llist_is_empty(&sp_ptr->cr_list_head)) { + dapl_dbg_log(DAPL_DBG_TYPE_ERR, + "**dapl_sp_remove_cr: removing from empty queue! sp %p\n", + sp_ptr); + return; + } + + dapl_llist_remove_entry(&sp_ptr->cr_list_head, + &cr_ptr->header.ia_list_entry); + sp_ptr->cr_list_count--; +} + +/* + * dapl_sp_remove_ep + * + * Remove a CR from a PSP, given an EP. + * + * + * Input: + * ep_ptr + * + * Output: + * none + * + * Returns: + * void + * + */ +void dapl_sp_remove_ep(IN DAPL_EP * ep_ptr) +{ + DAPL_SP *sp_ptr; + DAPL_CR *cr_ptr; + + cr_ptr = ep_ptr->cr_ptr; + + if (cr_ptr != NULL) { + sp_ptr = cr_ptr->sp_ptr; + + dapl_os_lock(&sp_ptr->header.lock); + + /* Remove the CR from the queue */ + dapl_sp_remove_cr(sp_ptr, cr_ptr); + + dapl_os_unlock(&sp_ptr->header.lock); + + ep_ptr->cr_ptr = NULL; + + /* free memory outside of the lock */ + dapls_cr_free(cr_ptr); + + return; + } +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_sp_util.h b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_sp_util.h new file mode 100644 index 00000000..fde8bea6 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_sp_util.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dapl_sp_util.h + * + * PURPOSE: Utility defs & routines for the PSP & RSP data structure + * + * $Id:$ + * + **********************************************************************/ + +#ifndef _DAPL_PSP_UTIL_H_ +#define _DAPL_PSP_UTIL_H_ + +DAPL_SP *dapls_sp_alloc ( + IN DAPL_IA *ia_ptr, + IN DAT_BOOLEAN is_psp ); + +void dapls_sp_free_sp ( + IN DAPL_SP *sp_ptr ); + +void dapl_sp_link_cr ( + IN DAPL_SP *sp_ptr, + IN DAPL_CR *cr_ptr ); + +DAPL_CR *dapl_sp_search_cr ( + IN DAPL_SP *sp_ptr, + IN dp_ib_cm_handle_t ib_cm_handle ); + +void dapl_sp_remove_cr ( + IN DAPL_SP *sp_ptr, + IN DAPL_CR *cr_ptr ); + +void dapl_sp_remove_ep ( + IN DAPL_EP *ep_ptr ); + +#endif /* _DAPL_PSP_UTIL_H_ */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_srq_create.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_srq_create.c new file mode 100644 index 00000000..7631a5eb --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_srq_create.c @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_srq_create.c + * + * PURPOSE: Shared Receive Queue management + * Description: Interfaces in this file are completely described in + * the DAPL 1.2 API, Chapter 6, section 5.1 + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_ia_util.h" +#include "dapl_srq_util.h" +#include "dapl_adapter_util.h" + +/* + * dapl_srq_create + * + * DAPL Version 1.2, 6.5.1 + * + * Create an instance of a Shared Receive Queue that is provided to the + * consumer at srq_handle. + * + * Input: + * ia_handle + * pz_handle + * srq_attr + * + * Output: + * srq_handle + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_HANDLE + * DAT_INVALID_PARAMETER + * ?DAT_INVALID_ATTRIBUTE?? + * DAT_MODEL_NOT_SUPPORTED + */ +DAT_RETURN DAT_API +dapl_srq_create(IN DAT_IA_HANDLE ia_handle, + IN DAT_PZ_HANDLE pz_handle, + IN DAT_SRQ_ATTR * srq_attr, OUT DAT_SRQ_HANDLE * srq_handle) +{ + DAPL_IA *ia_ptr; + DAPL_SRQ *srq_ptr; + DAT_RETURN dat_status; + + dat_status = DAT_SUCCESS; + + dapl_dbg_log(DAPL_DBG_TYPE_API, + "dapl_srq_create (%p, %p, %p, %p)\n", + ia_handle, pz_handle, srq_attr, srq_handle); + + ia_ptr = (DAPL_IA *) ia_handle; + + /* + * Verify parameters + */ + if (DAPL_BAD_HANDLE(ia_ptr, DAPL_MAGIC_IA)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_IA); + goto bail; + } + + DAPL_CNTR(ia_ptr, DCNT_IA_SRQ_CREATE); + + /* + * Verify non-required parameters. + * N.B. Assumption: any parameter that can be + * modified by dat_ep_modify() is not strictly + * required when the EP is created + */ + if (pz_handle != NULL && DAPL_BAD_HANDLE(pz_handle, DAPL_MAGIC_PZ)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_PZ); + goto bail; + } + + if (srq_handle == NULL) { + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG4); + goto bail; + } + if (DAPL_BAD_PTR(srq_attr)) { + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG3); + goto bail; + } + + /* Allocate SRQ */ + srq_ptr = dapl_srq_alloc(ia_ptr, srq_attr); + if (srq_ptr == NULL) { + dat_status = + DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); + goto bail; + } + + srq_ptr->param.ia_handle = (DAT_IA_HANDLE) ia_ptr; + srq_ptr->param.srq_state = DAT_SRQ_STATE_OPERATIONAL; + srq_ptr->param.pz_handle = pz_handle; + + /* + * XXX Allocate provider resource here!!! + */ + /* XXX */ dat_status = DAT_ERROR(DAT_NOT_IMPLEMENTED, DAT_NO_SUBTYPE); + /* XXX */ dapl_srq_dealloc(srq_ptr); + /* XXX */ goto bail; + + /* Link it onto the IA */ + dapl_ia_link_srq(ia_ptr, srq_ptr); + + *srq_handle = srq_ptr; + + bail: + return dat_status; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_srq_free.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_srq_free.c new file mode 100644 index 00000000..d93e1881 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_srq_free.c @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_srq_free.c + * + * PURPOSE: Shared Receive Queue management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 5.5 + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_ia_util.h" +#include "dapl_srq_util.h" +#include "dapl_adapter_util.h" + +/* + * dapl_srq_free + * + * DAPL Version 1.2, 6.5.5 + * + * Destroy an instance of an SRQ + * + * Input: + * srq_handle + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + * DAT_INVALID_STATE + */ +DAT_RETURN DAT_API dapl_srq_free(IN DAT_SRQ_HANDLE srq_handle) +{ + DAPL_SRQ *srq_ptr; + DAPL_IA *ia_ptr; + DAT_SRQ_PARAM *param; + DAT_RETURN dat_status; + + dat_status = DAT_SUCCESS; + + dapl_dbg_log(DAPL_DBG_TYPE_API, "dapl_srq_free (%p)\n", srq_handle); + + srq_ptr = (DAPL_SRQ *) srq_handle; + param = &srq_ptr->param; + + /* + * Verify parameter & state + */ + if (DAPL_BAD_HANDLE(srq_ptr, DAPL_MAGIC_SRQ)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_SRQ); + goto bail; + } + + if (dapl_os_atomic_read(&srq_ptr->srq_ref_count) != 0) { + /* + * The DAPL 1.2 spec says to return DAT_SRQ_IN_USE, which does + * not exist. Have filed the following as an errata. + */ + dat_status = + DAT_ERROR(DAT_INVALID_STATE, DAT_INVALID_STATE_SRQ_IN_USE); + goto bail; + } + + ia_ptr = srq_ptr->header.owner_ia; + + DAPL_CNTR(ia_ptr, DCNT_IA_SRQ_FREE); + + /* + * Do verification of parameters and the state change atomically. + */ + dapl_os_lock(&srq_ptr->header.lock); + + /* Remove the SRQ from the IA */ + dapl_ia_unlink_srq(ia_ptr, srq_ptr); + + dapl_os_unlock(&srq_ptr->header.lock); + + /* + * Finish tearing everything down. + */ + + /* + * Take care of the transport resource + */ + + /* XXX Put provider code here!!! */ + + /* Free the resource */ + dapl_srq_dealloc(srq_ptr); + + bail: + return dat_status; + +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_srq_post_recv.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_srq_post_recv.c new file mode 100644 index 00000000..d46f9bd5 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_srq_post_recv.c @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_srq_post_recv.c + * + * PURPOSE: Shared Receive Queue management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 5.8 + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_cookie.h" +#include "dapl_adapter_util.h" + +/* + * dapl_srq_post_recv + * + * DAPL Requirements Version 1.2, 6.5.8 + * + * Post a receive buffer that can be used by any incoming + * message by any connected EP using the SRQ. Request to receive data + * over a connection of any ep handle into local_iov + * + * Input: + * srq_handle + * num_segments + * local_iov + * user_cookie + * + * Output: + * None. + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + * DAT_INVALID_HANDLE + * DAT_INVALID_STATE + * DAT_PROTECTION_VIOLATION + * DAT_PROVILEGES_VIOLATION + */ +DAT_RETURN DAT_API +dapl_srq_post_recv(IN DAT_SRQ_HANDLE srq_handle, + IN DAT_COUNT num_segments, + IN DAT_LMR_TRIPLET * local_iov, + IN DAT_DTO_COOKIE user_cookie) +{ + DAPL_SRQ *srq_ptr; + DAPL_COOKIE *cookie; + DAT_RETURN dat_status; + + dapl_dbg_log(DAPL_DBG_TYPE_API, + "dapl_srq_post_recv (%p, %d, %p, %p)\n", + srq_handle, num_segments, local_iov, user_cookie.as_64); + + if (DAPL_BAD_HANDLE(srq_handle, DAPL_MAGIC_SRQ)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_SRQ); + goto bail; + } + + srq_ptr = (DAPL_SRQ *) srq_handle; + + /* + * Synchronization ok since this buffer is only used for receive + * requests, which aren't allowed to race with each other. The + * app must syncronize access to the SRQ. + */ + dat_status = dapls_dto_cookie_alloc(&srq_ptr->recv_buffer, + DAPL_DTO_TYPE_RECV, + user_cookie, &cookie); + if (DAT_SUCCESS != dat_status) { + goto bail; + } + + /* + * Take reference before posting to avoid race conditions with + * completions + */ + dapl_os_atomic_inc(&srq_ptr->recv_count); + + /* + * Invoke provider specific routine to post DTO + */ + /* XXX Put code here XXX */ + /* XXX */ dat_status = DAT_ERROR(DAT_NOT_IMPLEMENTED, DAT_NO_SUBTYPE); + + if (dat_status != DAT_SUCCESS) { + dapl_os_atomic_dec(&srq_ptr->recv_count); + dapls_cookie_dealloc(&srq_ptr->recv_buffer, cookie); + } + + bail: + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_srq_query.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_srq_query.c new file mode 100644 index 00000000..af395d49 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_srq_query.c @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_srq_query.c + * + * PURPOSE: Shared Receive Queue management + * + * Description: Interfaces in this file are completely described in + * the DAPL 1.2 API, Chapter 6, section 5.6 + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" + +/* + * dapl_srq_query + * + * DAPL Requirements Version 1.2, 6.5.6 + * + * Return SRQ parameters to the consumer + * + * Input: + * srq_handle + * srq_param_mask + * + * Output: + * srq_param + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + * DAT_INVALID_PARAMETER + */ +DAT_RETURN DAT_API +dapl_srq_query(IN DAT_SRQ_HANDLE srq_handle, + IN DAT_SRQ_PARAM_MASK srq_param_mask, + OUT DAT_SRQ_PARAM * srq_param) +{ + DAPL_SRQ *srq_ptr; + DAT_RETURN dat_status; + + dat_status = DAT_SUCCESS; + + dapl_dbg_log(DAPL_DBG_TYPE_API, + "dapl_srq_query (%p, %x, %p)\n", + srq_handle, srq_param_mask, srq_param); + + if (DAPL_BAD_HANDLE(srq_handle, DAPL_MAGIC_SRQ)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_SRQ); + goto bail; + } + if (srq_param == NULL) { + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG3); + goto bail; + } + + srq_ptr = (DAPL_SRQ *) srq_handle; + + /* + * XXX Need to calculate available_dto_count and outstanding_dto_count + */ + srq_ptr->param.available_dto_count = DAT_VALUE_UNKNOWN; + srq_ptr->param.outstanding_dto_count = DAT_VALUE_UNKNOWN; + + *srq_param = srq_ptr->param; + + bail: + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_srq_resize.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_srq_resize.c new file mode 100644 index 00000000..32386ff0 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_srq_resize.c @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_srq_resize.c + * + * PURPOSE: Shared Receive Queue management + * + * Description: Interfaces in this file are completely defined in + * the uDAPL 1.1 API, Chapter 6, section 5.7 + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_srq_util.h" +#include "dapl_adapter_util.h" + +/* + * dapl_srq_resize + * + * DAPL Requirements Version 1.2, 6.5.7 + * + * Modify the size of the event queue of a Shared Receive Queue + * + * Input: + * srq_handle + * srq_max_recv_dto + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + * DAT_INVALID_PARAMETER + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_STATE + */ + +DAT_RETURN DAT_API +dapl_srq_resize(IN DAT_SRQ_HANDLE srq_handle, IN DAT_COUNT srq_max_recv_dto) +{ + DAPL_IA *ia_ptr; + DAPL_SRQ *srq_ptr; + DAT_RETURN dat_status; + + dat_status = DAT_SUCCESS; + + dapl_dbg_log(DAPL_DBG_TYPE_API, "dapl_srq_resize (%p, %d)\n", + srq_handle, srq_max_recv_dto); + + if (DAPL_BAD_HANDLE(srq_handle, DAPL_MAGIC_SRQ)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_SRQ); + goto bail; + } + + srq_ptr = (DAPL_SRQ *) srq_handle; + ia_ptr = srq_ptr->header.owner_ia; + + /* + * Check for nonsense requests per the spec + */ + if (srq_max_recv_dto <= srq_ptr->param.low_watermark) { + dat_status = DAT_ERROR(DAT_INVALID_STATE, DAT_NO_SUBTYPE); + goto bail; + } + + /* XXX Put implementation here XXX */ + + /* XXX */ dat_status = DAT_ERROR(DAT_NOT_IMPLEMENTED, DAT_NO_SUBTYPE); + + bail: + return dat_status; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_srq_set_lw.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_srq_set_lw.c new file mode 100644 index 00000000..1e4254fd --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_srq_set_lw.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_srq_set_lw.c + * + * PURPOSE: Shared Receive Queue management + * + * Description: Interfaces in this file are completely defined in + * the uDAPL 1.1 API, Chapter 6, section 5.4 + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_srq_util.h" +#include "dapl_adapter_util.h" + +/* + * dapl_srq_set_lw + * + * DAPL Requirements Version 1.2, 6.5.4 + * + * Set the low water mark for an SRQ and arm the SRQ to generate an + * event if it is reached. + * + * Input: + * srq_handle + * srq_max_recv_dto + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + * DAT_INVALID_PARAMETER + * DAT_MODEL_NOT_SUPPORTED + */ + +DAT_RETURN DAT_API +dapl_srq_set_lw(IN DAT_SRQ_HANDLE srq_handle, IN DAT_COUNT low_watermark) +{ + DAPL_SRQ *srq_ptr; + DAT_RETURN dat_status; + + dat_status = DAT_SUCCESS; + + dapl_dbg_log(DAPL_DBG_TYPE_API, "dapl_srq_set_lw (%p, %d)\n", + srq_handle, low_watermark); + + if (DAPL_BAD_HANDLE(srq_handle, DAPL_MAGIC_SRQ)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_SRQ); + goto bail; + } + + srq_ptr = (DAPL_SRQ *) srq_handle; + + /* XXX Put implementation here XXX */ + + /* XXX */ dat_status = DAT_ERROR(DAT_NOT_IMPLEMENTED, DAT_NO_SUBTYPE); + + bail: + return dat_status; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_srq_util.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_srq_util.c new file mode 100644 index 00000000..3b298908 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_srq_util.c @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ep_util.c + * + * PURPOSE: Shared Receive Queue management and support + * + * $Id:$ + **********************************************************************/ + +#include "dapl_srq_util.h" +#include "dapl_ia_util.h" +#include "dapl_cookie.h" + +/* + * dapl_srq_alloc + * + * alloc and initialize an SRQ struct + * + * Input: + * IA INFO struct ptr + * SRQ ATTR ptr + * + * Output: + * none + * + * Returns: + * pointer to srq + * + */ +DAPL_SRQ *dapl_srq_alloc(IN DAPL_IA * ia_ptr, IN const DAT_SRQ_ATTR * srq_attr) +{ + DAPL_SRQ *srq_ptr; + + /* Allocate SRQ */ + srq_ptr = (DAPL_SRQ *) dapl_os_alloc(sizeof(DAPL_SRQ)); + + if (srq_ptr == NULL) { + goto bail; + } + + /* zero the structure */ + dapl_os_memzero(srq_ptr, sizeof(DAPL_SRQ)); + + /* + * initialize the header + */ + srq_ptr->header.provider = ia_ptr->header.provider; + srq_ptr->header.magic = DAPL_MAGIC_SRQ; + srq_ptr->header.handle_type = DAT_HANDLE_TYPE_SRQ; + srq_ptr->header.owner_ia = ia_ptr; + srq_ptr->header.user_context.as_64 = 0; + srq_ptr->header.user_context.as_ptr = NULL; + dapl_os_atomic_set(&srq_ptr->srq_ref_count, 0); + + dapl_llist_init_entry(&srq_ptr->header.ia_list_entry); + dapl_os_lock_init(&srq_ptr->header.lock); + + /* + * Initialize the body. + * XXX Assume srq_attrs is required + */ + srq_ptr->param.max_recv_dtos = srq_attr->max_recv_dtos; + srq_ptr->param.max_recv_iov = srq_attr->max_recv_iov; + srq_ptr->param.low_watermark = srq_attr->low_watermark; + + /* Get a cookie buffer to track outstanding recvs */ + if (DAT_SUCCESS != dapls_cb_create(&srq_ptr->recv_buffer, (DAPL_EP *) srq_ptr, /* just saves the value */ + srq_ptr->param.max_recv_dtos)) { + dapl_srq_dealloc(srq_ptr); + srq_ptr = NULL; + goto bail; + } + + bail: + return srq_ptr; +} + +/* + * dapl_srq_dealloc + * + * Free the passed in SRQ structure. + * + * Input: + * SRQ pointer + * + * Output: + * none + * + * Returns: + * none + * + */ +void dapl_srq_dealloc(IN DAPL_SRQ * srq_ptr) +{ + dapl_os_assert(srq_ptr->header.magic == DAPL_MAGIC_SRQ); + + srq_ptr->header.magic = DAPL_MAGIC_INVALID; /* reset magic to prevent reuse */ + dapl_ia_unlink_srq(srq_ptr->header.owner_ia, srq_ptr); + dapls_cb_free(&srq_ptr->recv_buffer); + dapl_os_lock_destroy(&srq_ptr->header.lock); + + dapl_os_free(srq_ptr, sizeof(DAPL_SRQ)); +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_srq_util.h b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_srq_util.h new file mode 100644 index 00000000..952f7674 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_srq_util.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dapl_srq_util.h + * + * PURPOSE: Utility defs & routines for the SRQ data structure + * + * $Id:$ + * + **********************************************************************/ + +#ifndef _DAPL_SRQ_UTIL_H_ +#define _DAPL_SRQ_UTIL_H_ + +#include "dapl.h" + +/* function prototypes */ + +extern DAPL_SRQ * +dapl_srq_alloc ( + IN DAPL_IA *ia, + IN const DAT_SRQ_ATTR *srq_attr ); + +extern void +dapl_srq_dealloc ( + IN DAPL_SRQ *srq_ptr ); + +#endif /* _DAPL_SRQ_UTIL_H_ */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_timer_util.c b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_timer_util.c new file mode 100644 index 00000000..cccaff16 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_timer_util.c @@ -0,0 +1,365 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_timer_util.c + * + * PURPOSE: DAPL timer management + * Description: Routines to add and cancel timer records. A timer record + * is put on the global timer queue. If the timer thread is + * not running, start it. The timer thread will sleep + * until a timer event or until a process wakes it up + * to notice a new timer is available; we use a DAPL_WAIT_OBJ + * for synchronization. + * + * If a timer is cancelled, it is simlpy removed from the + * queue. The timer may wakeup and notice there is no timer + * record to awaken at this time, so it will reset for the + * next entry. When there are no timer records to manage, + * the timer thread just sleeps until awakened. + * + * This file also contains the timer handler thread, + * embodied in dapls_timer_thread(). + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_timer_util.h" + +#define DAPL_TIMER_INIT 0 +#define DAPL_TIMER_RUN 1 +#define DAPL_TIMER_DESTROY 2 +#define DAPL_TIMER_EXIT 3 + +struct timer_head { + DAPL_LLIST_HEAD timer_list_head; + DAPL_OS_LOCK lock; + DAPL_OS_WAIT_OBJECT wait_object; + DAPL_OS_THREAD timeout_thread_handle; + int state; +} g_daplTimerHead; + +typedef struct timer_head DAPL_TIMER_HEAD; + +void dapls_timer_thread(void *arg); + +void dapls_timer_init() +{ + /* + * Set up the timer thread elements. The timer thread isn't + * started until it is actually needed + */ + g_daplTimerHead.timer_list_head = NULL; + dapl_os_lock_init(&g_daplTimerHead.lock); + dapl_os_wait_object_init(&g_daplTimerHead.wait_object); + g_daplTimerHead.timeout_thread_handle = 0; + g_daplTimerHead.state = DAPL_TIMER_INIT; +} + +void dapls_timer_release() +{ + dapl_os_lock(&g_daplTimerHead.lock); + if (g_daplTimerHead.state != DAPL_TIMER_RUN) { + dapl_os_unlock(&g_daplTimerHead.lock); + return; + } + + g_daplTimerHead.state = DAPL_TIMER_DESTROY; + dapl_os_unlock(&g_daplTimerHead.lock); + while (g_daplTimerHead.state != DAPL_TIMER_EXIT) { + dapl_os_wait_object_wakeup(&g_daplTimerHead.wait_object); + dapl_os_sleep_usec(2000); + } +} + +/* + * dapls_timer_set + * + * Set a timer. The timer will invoke the specified function + * after a number of useconds expires. + * + * Input: + * timer User provided timer structure + * func Function to invoke when timer expires + * data Argument passed to func() + * expires microseconds until timer fires + * + * Returns: + * no return value + * + */ +DAT_RETURN +dapls_timer_set(IN DAPL_OS_TIMER * timer, + IN void (*func) (uintptr_t), + IN void *data, IN DAPL_OS_TIMEVAL expires) +{ + DAPL_OS_TIMER *list_ptr; + DAPL_OS_TIMEVAL cur_time; + DAT_BOOLEAN wakeup_tmo_thread; + + /* + * Start the timer thread the first time we need a timer + */ + if (g_daplTimerHead.timeout_thread_handle == 0) { + dapl_os_thread_create(dapls_timer_thread, + &g_daplTimerHead, + &g_daplTimerHead.timeout_thread_handle); + + while (g_daplTimerHead.state != DAPL_TIMER_RUN) + dapl_os_sleep_usec(2000); + } + + dapl_llist_init_entry(&timer->list_entry); + wakeup_tmo_thread = DAT_FALSE; + dapl_os_get_time(&cur_time); + timer->expires = cur_time + expires; /* calculate future time */ + timer->function = func; + timer->data = data; + + /* + * Put the element on the queue: sorted by wakeup time, eariliest + * first. + */ + dapl_os_lock(&g_daplTimerHead.lock); + + if (g_daplTimerHead.state != DAPL_TIMER_RUN) { + dapl_os_unlock(&g_daplTimerHead.lock); + return DAT_INVALID_STATE; + } + + /* + * Deal with 3 cases due to our list structure: + * 1) list is empty: become the list head + * 2) New timer is sooner than list head: become the list head + * 3) otherwise, sort the timer into the list, no need to wake + * the timer thread up + */ + if (dapl_llist_is_empty(&g_daplTimerHead.timer_list_head)) { + /* Case 1: add entry to head of list */ + dapl_llist_add_head(&g_daplTimerHead.timer_list_head, + (DAPL_LLIST_ENTRY *) & timer->list_entry, + timer); + wakeup_tmo_thread = DAT_TRUE; + } else { + list_ptr = (DAPL_OS_TIMER *) + dapl_llist_peek_head(&g_daplTimerHead.timer_list_head); + + if (timer->expires < list_ptr->expires) { + /* Case 2: add entry to head of list */ + dapl_llist_add_head(&g_daplTimerHead.timer_list_head, + (DAPL_LLIST_ENTRY *) & timer-> + list_entry, timer); + wakeup_tmo_thread = DAT_TRUE; + } else { + /* Case 3: figure out where entry goes in sorted list */ + list_ptr = + dapl_llist_next_entry(&g_daplTimerHead. + timer_list_head, + (DAPL_LLIST_ENTRY *) & + list_ptr->list_entry); + + while (list_ptr != NULL) { + if (timer->expires < list_ptr->expires) { + dapl_llist_add_entry(&g_daplTimerHead. + timer_list_head, + (DAPL_LLIST_ENTRY + *) & list_ptr-> + list_entry, + (DAPL_LLIST_ENTRY + *) & timer-> + list_entry, timer); + break; + + } + list_ptr = + dapl_llist_next_entry(&g_daplTimerHead. + timer_list_head, + (DAPL_LLIST_ENTRY *) & + list_ptr->list_entry); + } + if (list_ptr == NULL) { + /* entry goes to the end of the list */ + dapl_llist_add_tail(&g_daplTimerHead. + timer_list_head, + (DAPL_LLIST_ENTRY *) & + timer->list_entry, timer); + } + } + + } + dapl_os_unlock(&g_daplTimerHead.lock); + + if (wakeup_tmo_thread == DAT_TRUE) { + dapl_os_wait_object_wakeup(&g_daplTimerHead.wait_object); + } + + return DAT_SUCCESS; +} + +/* + * dapls_os_timer_cancel + * + * Cancel a timer. Simply deletes the timer with no function invocations + * + * Input: + * timer User provided timer structure + * + * Returns: + * no return value + */ +void dapls_timer_cancel(IN DAPL_OS_TIMER * timer) +{ + dapl_os_lock(&g_daplTimerHead.lock); + /* + * make sure the entry has not been removed by another thread + */ + if (!dapl_llist_is_empty(&g_daplTimerHead.timer_list_head) && + timer->list_entry.list_head == &g_daplTimerHead.timer_list_head) { + dapl_llist_remove_entry(&g_daplTimerHead.timer_list_head, + (DAPL_LLIST_ENTRY *) & timer-> + list_entry); + } + /* + * If this was the first entry on the queue we could awaken the + * thread and have it reset the list; but it will just wake up + * and find that the timer entry has been removed, then go back + * to sleep, so don't bother. + */ + dapl_os_unlock(&g_daplTimerHead.lock); +} + +/* + * dapls_timer_thread + * + * Core worker thread dealing with all timers. Basic algorithm: + * - Sleep until work shows up + * - Take first element of sorted timer list and wake + * invoke the callback if expired + * - Sleep for the timeout period if not expired + * + * Input: + * timer_head Timer head structure to manage timer lists + * + * Returns: + * no return value + */ +void dapls_timer_thread(void *arg) +{ + DAPL_OS_TIMER *list_ptr; + DAPL_OS_TIMEVAL cur_time; + DAT_RETURN dat_status; + DAPL_TIMER_HEAD *timer_head; + + timer_head = arg; + + dapl_os_lock(&timer_head->lock); + timer_head->state = DAPL_TIMER_RUN; + dapl_os_unlock(&timer_head->lock); + + for (;;) { + if (dapl_llist_is_empty(&timer_head->timer_list_head)) { + dat_status = + dapl_os_wait_object_wait(&timer_head->wait_object, + DAT_TIMEOUT_INFINITE); + } + + /* + * Lock policy: + * While this thread is accessing the timer list, it holds the + * lock. Otherwise, it doesn't. + */ + dapl_os_lock(&timer_head->lock); + while (!dapl_llist_is_empty(&timer_head->timer_list_head)) { + list_ptr = (DAPL_OS_TIMER *) + dapl_llist_peek_head(&g_daplTimerHead. + timer_list_head); + dapl_os_get_time(&cur_time); + + if (list_ptr->expires <= cur_time || + timer_head->state == DAPL_TIMER_DESTROY) { + + /* + * Remove the entry from the list. Sort out how much + * time we need to sleep for the next one + */ + list_ptr = + dapl_llist_remove_head(&timer_head-> + timer_list_head); + dapl_os_unlock(&timer_head->lock); + + /* + * Invoke the user callback + */ + list_ptr->function((uintptr_t) list_ptr->data); + /* timer structure was allocated by caller, we don't + * free it here. + */ + + /* reacquire the lock */ + dapl_os_lock(&timer_head->lock); + } else { + dapl_os_unlock(&timer_head->lock); + dat_status = + dapl_os_wait_object_wait(&timer_head-> + wait_object, + (DAT_TIMEOUT) + (list_ptr-> + expires - + cur_time)); + dapl_os_lock(&timer_head->lock); + } + } + + /* Destroy - all timers triggered and list is empty */ + if (timer_head->state == DAPL_TIMER_DESTROY) { + timer_head->state = DAPL_TIMER_EXIT; + dapl_os_unlock(&timer_head->lock); + break; + } + + /* + * release the lock before going back to the top to sleep + */ + dapl_os_unlock(&timer_head->lock); + + if (dat_status == DAT_INTERNAL_ERROR) { + /* + * XXX What do we do here? + */ + } + } /* for (;;) */ +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_timer_util.h b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_timer_util.h new file mode 100644 index 00000000..02f7069a --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/common/dapl_timer_util.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dapl_timer_util.h + * + * PURPOSE: DAPL timer management + * Description: support for dapl_timer.h + * + * $Id:$ + **********************************************************************/ + +void dapls_timer_init ( void ); +void dapls_timer_release( void ); + +DAT_RETURN dapls_timer_set ( + IN DAPL_OS_TIMER *timer, + IN void (*func) (uintptr_t), + IN void *data, + IN DAPL_OS_TIMEVAL expires ); + +void dapls_timer_cancel ( + IN DAPL_OS_TIMER *timer); diff --git a/branches/WOF2-3/ulp/dapl2/dapl/dapl_common_src.c b/branches/WOF2-3/ulp/dapl2/dapl/dapl_common_src.c new file mode 100644 index 00000000..0e5f7497 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/dapl_common_src.c @@ -0,0 +1,112 @@ +/* + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "common\dapl_cno_util.c" +#include "common\dapl_cookie.c" +#include "common\dapl_cr_accept.c" +#include "common\dapl_cr_callback.c" +#include "common\dapl_cr_handoff.c" +#include "common\dapl_cr_query.c" +#include "common\dapl_cr_reject.c" +#include "common\dapl_cr_util.c" +#include "common\dapl_csp.c" +#include "common\dapl_debug.c" +#include "common\dapl_ep_connect.c" +#include "common\dapl_ep_create.c" +#include "common\dapl_ep_disconnect.c" +#include "common\dapl_ep_dup_connect.c" +#include "common\dapl_ep_free.c" +#include "common\dapl_ep_get_status.c" +#include "common\dapl_ep_modify.c" +#include "common\dapl_ep_post_rdma_read.c" +#include "common\dapl_ep_post_rdma_read_to_rmr.c" +#include "common\dapl_ep_post_rdma_write.c" +#include "common\dapl_ep_post_recv.c" +#include "common\dapl_ep_post_send.c" +#include "common\dapl_ep_post_send_invalidate.c" +#include "common\dapl_ep_query.c" +#include "common\dapl_ep_recv_query.c" +#include "common\dapl_ep_reset.c" +#include "common\dapl_ep_set_watermark.c" +#include "common\dapl_ep_util.c" +#include "common\dapl_evd_connection_callb.c" +#include "common\dapl_evd_cq_async_error_callb.c" +#include "common\dapl_evd_dequeue.c" +#include "common\dapl_evd_dto_callb.c" +#include "common\dapl_evd_free.c" +#include "common\dapl_evd_post_se.c" +#include "common\dapl_evd_qp_async_error_callb.c" +#include "common\dapl_evd_resize.c" +#include "common\dapl_evd_un_async_error_callb.c" +#include "common\dapl_evd_util.c" +#include "common\dapl_get_consumer_context.c" +#include "common\dapl_get_handle_type.c" +#include "common\dapl_hash.c" +#include "common\dapl_hca_util.c" +#include "common\dapl_ia_close.c" +#include "common\dapl_ia_ha.c" +#include "common\dapl_ia_open.c" +#include "common\dapl_ia_query.c" +#include "common\dapl_ia_util.c" +#include "common\dapl_llist.c" +#include "common\dapl_lmr_free.c" +#include "common\dapl_lmr_query.c" +#include "common\dapl_lmr_sync_rdma_read.c" +#include "common\dapl_lmr_sync_rdma_write.c" +#include "common\dapl_lmr_util.c" +#include "common\dapl_mr_util.c" +#include "common\dapl_name_service.c" +#include "common\dapl_provider.c" +#include "common\dapl_psp_create.c" +#include "common\dapl_psp_create_any.c" +#include "common\dapl_psp_free.c" +#include "common\dapl_psp_query.c" +#include "common\dapl_pz_create.c" +#include "common\dapl_pz_free.c" +#include "common\dapl_pz_query.c" +#include "common\dapl_pz_util.c" +#include "common\dapl_ring_buffer_util.c" +#include "common\dapl_rmr_bind.c" +#include "common\dapl_rmr_create.c" +#include "common\dapl_rmr_free.c" +#include "common\dapl_rmr_query.c" +#include "common\dapl_rmr_util.c" +#include "common\dapl_rsp_create.c" +#include "common\dapl_rsp_free.c" +#include "common\dapl_rsp_query.c" +#include "common\dapl_set_consumer_context.c" +#include "common\dapl_sp_util.c" +#include "common\dapl_ep_create_with_srq.c" +#include "common\dapl_srq_create.c" +#include "common\dapl_srq_free.c" +#include "common\dapl_srq_post_recv.c" +#include "common\dapl_srq_query.c" +#include "common\dapl_srq_resize.c" +#include "common\dapl_srq_set_lw.c" +#include "common\dapl_srq_util.c" +#include "common\dapl_timer_util.c" diff --git a/branches/WOF2-3/ulp/dapl2/dapl/dapl_udapl_src.c b/branches/WOF2-3/ulp/dapl2/dapl/dapl_udapl_src.c new file mode 100644 index 00000000..6cd68760 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/dapl_udapl_src.c @@ -0,0 +1,45 @@ +/* + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "udapl\dapl_cno_create.c" +#include "udapl\dapl_cno_free.c" +#include "udapl\dapl_cno_modify_agent.c" +#include "udapl\dapl_cno_query.c" +#include "udapl\dapl_cno_wait.c" +#include "udapl\dapl_evd_clear_unwaitable.c" +#include "udapl\dapl_evd_create.c" +#include "udapl\dapl_evd_disable.c" +#include "udapl\dapl_evd_enable.c" +#include "udapl\dapl_evd_modify_cno.c" +#include "udapl\dapl_evd_query.c" +#include "udapl\dapl_evd_set_unwaitable.c" +#include "udapl\dapl_evd_wait.c" +#include "udapl\dapl_init.c" +#include "udapl\dapl_lmr_create.c" + +#include "udapl\windows\dapl_osd.c" diff --git a/branches/WOF2-3/ulp/dapl2/dapl/dirs b/branches/WOF2-3/ulp/dapl2/dapl/dirs new file mode 100644 index 00000000..daf0ad1a --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/dirs @@ -0,0 +1 @@ +DIRS = ibal openib_common openib_scm openib_cma openib_ucm diff --git a/branches/WOF2-3/ulp/dapl2/dapl/ibal/SOURCES b/branches/WOF2-3/ulp/dapl2/dapl/ibal/SOURCES new file mode 100644 index 00000000..bb1d7925 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/ibal/SOURCES @@ -0,0 +1,56 @@ +!if $(FREEBUILD) +TARGETNAME = dapl2 +!else +TARGETNAME = dapl2d +!endif + +TARGETPATH = ..\..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = DYNLINK +DLLENTRY = _DllMainCRTStartup + +!if $(_NT_TOOLS_VERSION) == 0x700 +DLLDEF=$O\udapl_exports.def +!else +DLLDEF=$(OBJ_PATH)\$O\udapl_exports.def +!endif + +USE_MSVCRT = 1 + +SOURCES=udapl.rc \ + ..\dapl_common_src.c \ + ..\dapl_udapl_src.c \ + dapl_ibal_cm.c \ + dapl_ibal_cq.c \ + dapl_ibal_extensions.c \ + dapl_ibal_name_service.c\ + dapl_ibal_qp.c \ + dapl_ibal_util.c + +INCLUDES = ..\include;..\common;..\..\dat\include;\ + ..\..\dat\udat\windows;..\udapl\windows;\ + ..\..\..\..\inc;..\..\..\..\inc\user;..\..\..\..\inc\user\linux; + +DAPL_OPTS = -DEXPORT_DAPL_SYMBOLS -D_VENDOR_IBAL_ -DDAPL_MERGE_CM_DTO\ + -DDAT_EXTENSIONS + +USER_C_FLAGS=$(USER_C_FLAGS) $(DAPL_OPTS) +!if !$(FREEBUILD) +USER_C_FLAGS=$(USER_C_FLAGS) -DDAPL_DBG #-DDAPL_COUNTERS +!endif + +TARGETLIBS= \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\dat2.lib \ + $(TARGETPATH)\*\complib.lib \ + $(TARGETPATH)\*\ibal.lib +!else + $(TARGETPATH)\*\dat2d.lib \ + $(TARGETPATH)\*\complibd.lib \ + $(TARGETPATH)\*\ibald.lib +!endif + +# FIX ME ASAP +#MSC_WARNING_LEVEL= /W3 +MSC_WARNING_LEVEL= /W1 /wd4113 diff --git a/branches/WOF2-3/ulp/dapl2/dapl/ibal/dapl_ibal_cm.c b/branches/WOF2-3/ulp/dapl2/dapl/ibal/dapl_ibal_cm.c new file mode 100644 index 00000000..e3c12ffe --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/ibal/dapl_ibal_cm.c @@ -0,0 +1,1842 @@ + +/* + * Copyright (c) 2005-2007 Intel Corporation. All rights reserved. + * Copyright (c) 2002, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under the terms of the "Common Public + * License" a copy of which is in the file LICENSE.txt in the root + * directory. The license is also available from the Open Source + * Initiative, see http://www.opensource.org/licenses/cpl.php. + * + */ + +/********************************************************************** + * + * MODULE: dapl_ibal_cm.c + * + * PURPOSE: IB Connection routines for access to IBAL APIs + * + * $Id: dapl_ibal_cm.c 584 2007-02-07 13:12:18Z sleybo $ + * + **********************************************************************/ + +#include "dapl.h" +#include "dapl_adapter_util.h" +#include "dapl_evd_util.h" +#include "dapl_cr_util.h" +#include "dapl_sp_util.h" +#include "dapl_ep_util.h" +#include "dapl_ia_util.h" +#include "dapl_ibal_util.h" +#include "dapl_name_service.h" +#include "dapl_ibal_name_service.h" +#include "dapl_cookie.h" + +#define IB_INFINITE_SERVICE_LEASE 0xFFFFFFFF +#define DAPL_ATS_SERVICE_ID ATS_SERVICE_ID //0x10000CE100415453 +#define DAPL_ATS_NAME ATS_NAME +#define HCA_IPV6_ADDRESS_LENGTH 16 + +/* until dapl_ibal_util.h define of IB_INVALID_HANDLE which overlaps the + * Windows ib_types.h typedef enu ib_api_status_t IB_INVALID_HANDLE is fixed. + */ +#undef IB_INVALID_HANDLE +#define DAPL_IB_INVALID_HANDLE NULL + +int g_dapl_loopback_connection = 0; +extern dapl_ibal_root_t dapl_ibal_root; + +/* + * Prototypes + */ + +char * +dapli_ib_cm_event_str(ib_cm_events_t e) +{ +#ifdef DBG + char *cp; + static char *event_str[13] = { + "IB_CME_CONNECTED", + "IB_CME_DISCONNECTED", + "IB_CME_DISCONNECTED_ON_LINK_DOWN", + "IB_CME_CONNECTION_REQUEST_PENDING", + "IB_CME_CONNECTION_REQUEST_PENDING_PRIVATE_DATA", + "IB_CME_DESTINATION_REJECT", + "IB_CME_DESTINATION_REJECT_PRIVATE_DATA", + "IB_CME_DESTINATION_UNREACHABLE", + "IB_CME_TOO_MANY_CONNECTION_REQUESTS", + "IB_CME_LOCAL_FAILURE", + "IB_CME_REPLY_RECEIVED", + "IB_CME_REPLY_RECEIVED_PRIVATE_DATA", + "IB_CM_LOCAL_FAILURE" + }; + + if (e > IB_CM_LOCAL_FAILURE || e < IB_CME_CONNECTED) + cp = "BAD EVENT"; + else + cp = event_str[e]; + + return cp; +#else + static char num[8]; + sprintf(num,"%d",e); + return num; +#endif +} + + +#if defined(DAPL_DBG) + +void dapli_print_private_data( char *prefix, const uint8_t *pd, int len ) +{ + int i; + + if ( !pd || len <= 0 ) + return; + + dapl_log ( DAPL_DBG_TYPE_CM, "--> %s: private_data(len %d)\n ",prefix,len); + + if (len > IB_MAX_REP_PDATA_SIZE) + { + dapl_log ( DAPL_DBG_TYPE_ERR, + " Private data size(%d) > Max(%d), ignored.\n ", + len,DAPL_MAX_PRIVATE_DATA_SIZE); + len = IB_MAX_REP_PDATA_SIZE; + } + + for ( i = 0 ; i < len; i++ ) + { + dapl_log ( DAPL_DBG_TYPE_CM, "%2x ", pd[i]); + if ( ((i+1) % 5) == 0 ) + dapl_log ( DAPL_DBG_TYPE_CM, "\n "); + } + dapl_log ( DAPL_DBG_TYPE_CM, "\n"); +} +#endif + +/* EP-CM linking support */ +dp_ib_cm_handle_t ibal_cm_alloc(void) +{ + dp_ib_cm_handle_t cm_ptr; + + /* Allocate CM, init lock, and initialize */ + if ((cm_ptr = dapl_os_alloc(sizeof(*cm_ptr))) == NULL) + return NULL; + + (void)dapl_os_memzero(cm_ptr, sizeof(*cm_ptr)); + cm_ptr->ref_count = 1; + + if (dapl_os_lock_init(&cm_ptr->lock)) { + dapl_os_free(cm_ptr, sizeof(*cm_ptr)); + return NULL; + } + + dapl_llist_init_entry((DAPL_LLIST_ENTRY *)&cm_ptr->list_entry); + + return cm_ptr; +} + +/* free CM object resources */ +static void ibal_cm_dealloc(dp_ib_cm_handle_t cm_ptr) +{ + dapl_os_assert(!cm_ptr->ref_count); + dapl_os_lock_destroy(&cm_ptr->lock); + dapl_os_free(cm_ptr, sizeof(*cm_ptr)); +} + +void dapls_cm_acquire(dp_ib_cm_handle_t cm_ptr) +{ + dapl_os_lock(&cm_ptr->lock); + cm_ptr->ref_count++; + dapl_os_unlock(&cm_ptr->lock); +} + +void dapls_cm_release(dp_ib_cm_handle_t cm_ptr) +{ + dapl_os_lock(&cm_ptr->lock); + cm_ptr->ref_count--; + if (cm_ptr->ref_count) { + dapl_os_unlock(&cm_ptr->lock); + return; + } + dapl_os_unlock(&cm_ptr->lock); + ibal_cm_dealloc(cm_ptr); +} + +/* blocking: called from user thread dapl_ep_free() only */ +void dapls_cm_free(dp_ib_cm_handle_t cm_ptr) +{ + dapl_ep_unlink_cm(cm_ptr->ep, cm_ptr); + + /* final reference, alloc */ + dapls_cm_release(cm_ptr); +} + +static void +dapli_ib_cm_apr_cb ( + IN ib_cm_apr_rec_t *p_cm_apr_rec ) +{ + UNUSED_PARAM( p_cm_apr_rec ); + + dapl_dbg_log (DAPL_DBG_TYPE_CM, + "--> DiCAcb: CM callback APR (Alternate Path Request)\n"); +} + +static void +dapli_ib_cm_lap_cb ( + IN ib_cm_lap_rec_t *p_cm_lap_rec ) +{ + UNUSED_PARAM( p_cm_lap_rec ); + + dapl_dbg_log (DAPL_DBG_TYPE_CM, + "--> DiCLcb: CM callback LAP (Load Alternate Path)\n"); +} + +/* + * Connection Disconnect Request callback + * We received a DREQ, return a DREP (disconnect reply). + */ + +static void +dapli_ib_cm_dreq_cb ( + IN ib_cm_dreq_rec_t *p_cm_dreq_rec ) +{ + ib_cm_drep_t cm_drep; + DAPL_EP *ep_ptr; + int bail=10; + dp_ib_cm_handle_t cm_ptr; + + dapl_os_assert (p_cm_dreq_rec); + + ep_ptr = (DAPL_EP * __ptr64) p_cm_dreq_rec->qp_context; + if ( DAPL_BAD_PTR(ep_ptr) ) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "--> %s: BAD_PTR EP %lx\n", __FUNCTION__, ep_ptr); + return; + } + if ( ep_ptr->header.magic != DAPL_MAGIC_EP ) + { + if ( ep_ptr->header.magic == DAPL_MAGIC_INVALID ) + return; + + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "--> %s: EP %p BAD_EP_MAGIC %x != wanted %x\n", + __FUNCTION__, ep_ptr, ep_ptr->header.magic, + DAPL_MAGIC_EP ); + return; + } + cm_ptr = dapl_get_cm_from_ep(ep_ptr); + if (!cm_ptr) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "--> %s: !CM_PTR on EP %p\n", __FUNCTION__, ep_ptr); + return; + } + dapl_os_assert(cm_ptr->ib_cm.h_qp == p_cm_dreq_rec->h_cm_dreq.h_qp); + + dapl_dbg_log (DAPL_DBG_TYPE_CM, + "--> %s() EP %p, %s sent_discreq %s\n", + __FUNCTION__,ep_ptr, + dapl_get_ep_state_str(ep_ptr->param.ep_state), + (ep_ptr->sent_discreq == DAT_TRUE ? "TRUE":"FALSE")); + + dapl_os_lock (&ep_ptr->header.lock); + if ( ep_ptr->param.ep_state == DAT_EP_STATE_DISCONNECTED + /*|| ( ep_ptr->param.ep_state == DAT_EP_STATE_DISCONNECT_PENDING + && ep_ptr->sent_discreq == DAT_TRUE)*/ ) + { + dapl_os_unlock (&ep_ptr->header.lock); + dapl_dbg_log (DAPL_DBG_TYPE_CM, + "--> DiCDcb: EP %lx QP %lx already Disconnected\n", + ep_ptr, ep_ptr->qp_handle); + return; + } + + ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECT_PENDING; + ep_ptr->recv_discreq = DAT_TRUE; + dapl_os_unlock (&ep_ptr->header.lock); + + dapl_os_memzero (&cm_drep, sizeof(ib_cm_drep_t)); + + /* Could fail if we received reply from other side, no need to retry */ + /* Wait for any send ops in process holding reference */ + while (dapls_cb_pending(&ep_ptr->req_buffer) && bail-- > 0 ) + { + dapl_dbg_log (DAPL_DBG_TYPE_CM, + "--> DiCDcb: WAIT for EP=%lx req_count(%d) != 0\n", + ep_ptr, dapls_cb_pending(&ep_ptr->req_buffer)); + dapl_os_sleep_usec (100); + } + + ib_cm_drep (p_cm_dreq_rec->h_cm_dreq, &cm_drep); + + /* CM puts QP in reset state */ + ep_ptr->qp_state = IB_QPS_RESET; + + if (ep_ptr->cr_ptr) + { + /* passive side */ + dapls_cr_callback ( cm_ptr, + IB_CME_DISCONNECTED, + (void * __ptr64) p_cm_dreq_rec->p_dreq_pdata, + IB_DREQ_PDATA_SIZE, + (void *) (((DAPL_CR *) ep_ptr->cr_ptr)->sp_ptr) ); + } + else + { + /* active side */ + dapl_evd_connection_callback ( + cm_ptr, + IB_CME_DISCONNECTED, + (void * __ptr64) + p_cm_dreq_rec->p_dreq_pdata, + IB_DREQ_PDATA_SIZE, + p_cm_dreq_rec->qp_context ); + } +} + +/* + * Connection Disconnect Reply callback + * We sent a DREQ and received a DREP. + */ + +static void +dapli_ib_cm_drep_cb ( + IN ib_cm_drep_rec_t *p_cm_drep_rec ) +{ + DAPL_EP *ep_ptr; + dp_ib_cm_handle_t cm_ptr; + + dapl_os_assert (p_cm_drep_rec != NULL); + + ep_ptr = (DAPL_EP * __ptr64) p_cm_drep_rec->qp_context; + + if (p_cm_drep_rec->cm_status) + { + dapl_dbg_log (DAPL_DBG_TYPE_CM, + "--> %s: DREP cm_status(%s) EP=%p\n", __FUNCTION__, + ib_get_err_str(p_cm_drep_rec->cm_status), ep_ptr); + } + + if ( DAPL_BAD_HANDLE(ep_ptr, DAPL_MAGIC_EP) ) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "--> %s: BAD EP Handle EP=%lx\n", __FUNCTION__,ep_ptr); + return; + } + cm_ptr = dapl_get_cm_from_ep(ep_ptr); + if (!cm_ptr) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "--> %s: !CM_PTR on EP %p\n", __FUNCTION__, ep_ptr); + return; + } + dapl_os_assert(cm_ptr->ib_cm.h_qp == p_cm_drep_rec->h_qp); + + dapl_dbg_log (DAPL_DBG_TYPE_CM, + "--> DiCDpcb: EP %p state %s cm_hdl %p\n",ep_ptr, + dapl_get_ep_state_str(ep_ptr->param.ep_state), + cm_ptr); + + if ( ep_ptr->param.ep_state == DAT_EP_STATE_DISCONNECTED ) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "--> DiCDpcb: EP %lx QP %lx already Disconnected\n", + ep_ptr, ep_ptr->qp_handle); + return; + } + + if (ep_ptr->cr_ptr) + { + /* passive connection side */ + dapls_cr_callback ( cm_ptr, + IB_CME_DISCONNECTED, + (void * __ptr64) p_cm_drep_rec->p_drep_pdata, + IB_DREP_PDATA_SIZE, + (void *) (((DAPL_CR *) ep_ptr->cr_ptr)->sp_ptr) ); + } + else + { + /* active connection side */ + dapl_evd_connection_callback ( + cm_ptr, + IB_CME_DISCONNECTED, + (void * __ptr64) p_cm_drep_rec->p_drep_pdata, + IB_DREP_PDATA_SIZE, + p_cm_drep_rec->qp_context ); + } +} + +/* + * CM reply callback + */ + +static void +dapli_ib_cm_rep_cb ( + IN ib_cm_rep_rec_t *p_cm_rep_rec ) +{ + ib_api_status_t ib_status; + ib_cm_rtu_t cm_rtu; + uint8_t cm_cb_op; + DAPL_PRIVATE *prd_ptr; + DAPL_EP *ep_ptr; + dapl_ibal_ca_t *p_ca; + dp_ib_cm_handle_t cm_ptr; + + dapl_os_assert (p_cm_rep_rec != NULL); + + ep_ptr = (DAPL_EP * __ptr64) p_cm_rep_rec->qp_context; + + if ( DAPL_BAD_HANDLE(ep_ptr, DAPL_MAGIC_EP) ) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> %s: EP %lx invalid or FREED\n", + __FUNCTION__, ep_ptr); + return; + } + cm_ptr = dapl_get_cm_from_ep(ep_ptr); + if (!cm_ptr) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "--> %s: !CM_PTR on EP %p\n", __FUNCTION__, ep_ptr); + return; + } + dapl_os_assert(cm_ptr->ib_cm.h_qp == p_cm_rep_rec->h_cm_rep.h_qp); + + dapl_dbg_log (DAPL_DBG_TYPE_CM, + "--> DiCRpcb: EP %lx local_max_rdma_read_in %d\n", + ep_ptr, p_cm_rep_rec->resp_res); + + p_ca = (dapl_ibal_ca_t *) + ep_ptr->header.owner_ia->hca_ptr->ib_hca_handle; + + dapl_os_memzero (&cm_rtu, sizeof ( ib_cm_rtu_t )); + cm_rtu.pfn_cm_apr_cb = dapli_ib_cm_apr_cb; + cm_rtu.pfn_cm_dreq_cb = dapli_ib_cm_dreq_cb; + cm_rtu.p_rtu_pdata = NULL; + cm_rtu.access_ctrl = + IB_AC_LOCAL_WRITE|IB_AC_RDMA_WRITE|IB_AC_MW_BIND|IB_AC_ATOMIC; + if ((ep_ptr->param.ep_attr.max_rdma_read_in > 0) || + (ep_ptr->param.ep_attr.max_rdma_read_out > 0)) + { + cm_rtu.access_ctrl |= IB_AC_RDMA_READ; + } + + cm_rtu.rq_depth = 0; + cm_rtu.sq_depth = 0; + + ib_status = ib_cm_rtu (p_cm_rep_rec->h_cm_rep, &cm_rtu); + + if (ib_status == IB_SUCCESS) + { + cm_cb_op = IB_CME_CONNECTED; + dapl_dbg_log (DAPL_DBG_TYPE_CM, + "--> DiCRpcb: EP %lx Connected req_count %d\n", + ep_ptr, dapls_cb_pending(&ep_ptr->req_buffer)); + } + else + { + cm_cb_op = IB_CME_LOCAL_FAILURE; + } + + prd_ptr = (DAPL_PRIVATE * __ptr64) p_cm_rep_rec->p_rep_pdata; + +#if defined(DAPL_DBG) && 0 + dapli_print_private_data( "DiCRpcb", + prd_ptr->private_data, + IB_MAX_REP_PDATA_SIZE); +#endif + + dapl_evd_connection_callback ( + cm_ptr, + cm_cb_op, + (void *) prd_ptr, + IB_REP_PDATA_SIZE, + (void * __ptr64) p_cm_rep_rec->qp_context); +} + + +static void +dapli_ib_cm_rej_cb ( + IN ib_cm_rej_rec_t *p_cm_rej_rec ) +{ + DAPL_EP *ep_ptr; + ib_cm_events_t cm_event; + dp_ib_cm_handle_t cm_ptr; + + dapl_os_assert (p_cm_rej_rec); + + ep_ptr = (DAPL_EP * __ptr64) p_cm_rej_rec->qp_context; + + if ( DAPL_BAD_HANDLE(ep_ptr, DAPL_MAGIC_EP) ) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> %s: EP %lx invalid or FREED\n", + __FUNCTION__, ep_ptr); + return; + } + cm_ptr = dapl_get_cm_from_ep(ep_ptr); + if (!cm_ptr) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "--> %s: !CM_PTR on EP %p\n", __FUNCTION__, ep_ptr); + return; + } + dapl_os_assert(cm_ptr->ib_cm.h_qp == p_cm_rej_rec->h_qp); + + dapl_dbg_log (DAPL_DBG_TYPE_CM, + "--> DiCRjcb: EP = %lx QP = %lx rej reason = 0x%x\n", + ep_ptr,ep_ptr->qp_handle,CL_NTOH16(p_cm_rej_rec->rej_status)); + + switch (p_cm_rej_rec->rej_status) + { + case IB_REJ_INSUF_RESOURCES: + case IB_REJ_INSUF_QP: + case IB_REJ_INVALID_COMM_ID: + case IB_REJ_INVALID_COMM_INSTANCE: + case IB_REJ_INVALID_PKT_RATE: + case IB_REJ_INVALID_ALT_GID: + case IB_REJ_INVALID_ALT_LID: + case IB_REJ_INVALID_ALT_SL: + case IB_REJ_INVALID_ALT_TRAFFIC_CLASS: + case IB_REJ_INVALID_ALT_PKT_RATE: + case IB_REJ_INVALID_ALT_HOP_LIMIT: + case IB_REJ_INVALID_ALT_FLOW_LBL: + case IB_REJ_INVALID_GID: + case IB_REJ_INVALID_LID: + case IB_REJ_INVALID_SID: + case IB_REJ_INVALID_SL: + case IB_REJ_INVALID_TRAFFIC_CLASS: + case IB_REJ_PORT_REDIRECT: + case IB_REJ_INVALID_MTU: + case IB_REJ_INSUFFICIENT_RESP_RES: + case IB_REJ_INVALID_CLASS_VER: + case IB_REJ_INVALID_FLOW_LBL: + cm_event = IB_CME_DESTINATION_REJECT; + break; + + case IB_REJ_TIMEOUT: + cm_event = IB_CME_DESTINATION_UNREACHABLE; + dapl_dbg_log (DAPL_DBG_TYPE_CM, "--> DiCRjcb: CR TIMEOUT\n"); + break; + + case IB_REJ_USER_DEFINED: + cm_event = IB_CME_DESTINATION_REJECT; + dapl_dbg_log (DAPL_DBG_TYPE_CM, + "--> DiCRjcb: user defined rej reason %s\n", + p_cm_rej_rec->p_ari); + break; + + default: + cm_event = IB_CME_LOCAL_FAILURE; + dapl_dbg_log (DAPL_DBG_TYPE_CM, + "--> DiCRjcb: with unknown status %x\n", + p_cm_rej_rec->rej_status); + break; + } + + /* FIXME - Vu + * We do not take care off the user defined rej reason with additional + * rejection information (p_ari) + */ + + if (ep_ptr->cr_ptr) + { + dapls_cr_callback ( cm_ptr, + cm_event, + (void * __ptr64) p_cm_rej_rec->p_rej_pdata, + IB_REJ_PDATA_SIZE, + (void *) ((DAPL_CR *) ep_ptr->cr_ptr)->sp_ptr); + } + else + { + dapl_evd_connection_callback ( + cm_ptr, + cm_event, + (void * __ptr64) p_cm_rej_rec->p_rej_pdata, + IB_REJ_PDATA_SIZE, + (void * __ptr64) p_cm_rej_rec->qp_context ); + } + +} + + + +static void +dapli_ib_cm_req_cb ( IN ib_cm_req_rec_t *p_cm_req_rec ) +{ + DAPL_SP *sp_ptr; + DAT_SOCK_ADDR6 dest_ia_addr; + dp_ib_cm_handle_t cm_ptr; + + dapl_os_assert (p_cm_req_rec); + + sp_ptr = (DAPL_SP * __ptr64) p_cm_req_rec->context; + + dapl_os_assert (sp_ptr); + + /* + * The context pointer could have been cleaned up in a racing + * CM callback, check to see if we should just exit here + */ + if (sp_ptr->header.magic == DAPL_MAGIC_INVALID) + { + dapl_dbg_log (DAPL_DBG_TYPE_CM, + "%s: BAD-Magic in SP %lx, racing CM callback?\n", + __FUNCTION__, sp_ptr ); + return; + } + + dapl_os_assert ( sp_ptr->header.magic == DAPL_MAGIC_PSP || + sp_ptr->header.magic == DAPL_MAGIC_RSP ); + + /* preserve ibal's connection handle storage so we have a consistent + * pointer value. The reasons this is done dynamically instead of a static + * allocation in an end_point is the pointer value is set in the SP list + * of CR's here and searched for from disconnect callbacks. If the pointer + * value changes, you never find the CR on the sp list... + * EP struct deallocation is where this memory is released or prior in the + * error case. + */ + cm_ptr = ibal_cm_alloc(); + if (!cm_ptr) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "%s: FAILED to alloc IB CM handle storage?\n", + __FUNCTION__); + return; + } + + /* + * Save the cm_srvc_handle to avoid the race condition between + * the return of the ib_cm_listen and the notification of a conn req + */ + if (sp_ptr->cm_srvc_handle != p_cm_req_rec->h_cm_listen) + { + dapl_dbg_log (DAPL_DBG_TYPE_CM | DAPL_DBG_TYPE_CALLBACK, + "--> DiCRqcb: cm_service_handle is changed\n"); + sp_ptr->cm_srvc_handle = p_cm_req_rec->h_cm_listen; + } + + dapl_os_memzero (&dest_ia_addr, sizeof (dest_ia_addr)); + +#ifdef NO_NAME_SERVICE + + { + DAPL_PRIVATE *prd_ptr; + + prd_ptr = (DAPL_PRIVATE *)p_cm_req_rec->p_req_pdata; + + dapl_os_memcpy ((void *)&dest_ia_addr, + (void *)&prd_ptr->hca_address, + sizeof (DAT_SOCK_ADDR6)); + } + +#else + + { + GID dest_gid; + + dapl_os_memzero (&dest_gid, sizeof (dest_gid)); + + dest_gid.guid = p_cm_req_rec->primary_path.dgid.unicast.interface_id; + dest_gid.gid_prefix = p_cm_req_rec->primary_path.dgid.unicast.prefix; + + if (DAT_SUCCESS != dapls_ns_map_ipaddr ( + sp_ptr->header.owner_ia->hca_ptr, + dest_gid, + (DAT_IA_ADDRESS_PTR)&dest_ia_addr)) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "cm_req_cb: SP = %lx failed mapping GID-IPaddr\n", + sp_ptr); + } + } + +#endif /* NO_NAME_SERVICE */ + + /* preserve CR cm handle data */ + dapl_os_memcpy( (void*)&cm_ptr->ib_cm, + (void*)&p_cm_req_rec->h_cm_req, + sizeof(ib_cm_handle_t)); + + /* preserve remote IP address */ + dapl_os_memcpy( (void*)&cm_ptr->dst_ip_addr, + (void*)&dest_ia_addr, + sizeof(dest_ia_addr)); + +#if defined(DAPL_DBG) + { + char ipa[20]; + + //rval = ((struct sockaddr_in *) (&dest_ia_addr))->sin_addr.s_addr; + + dapl_dbg_log (DAPL_DBG_TYPE_CM|DAPL_DBG_TYPE_CALLBACK, + "%s: query SA (CM %lx)->dst_ip_addr: %s\n", + __FUNCTION__,cm_ptr, + dapli_get_ip_addr_str( + (DAT_SOCK_ADDR6*) &cm_ptr->dst_ip_addr, ipa) ); + } +#endif + + /* FIXME - Vu + * We have NOT used/saved the primary and alternative path record + * ie. p_cm_req_rec->p_primary_path and p_cm_req_rec->p_alt_path + * We should cache some fields in path record in the Name Service DB + * such as: dgid, dlid + * Also we do not save resp_res (ie. max_oustanding_rdma_read/atomic) + * rnr_retry_cnt and flow_ctrl fields + */ + dapl_dbg_log (DAPL_DBG_TYPE_CM, + "%s: SP %lx max_rdma_read %d PrivateData %lx\n", + __FUNCTION__, sp_ptr, p_cm_req_rec->resp_res, + p_cm_req_rec->p_req_pdata); + + dapls_cr_callback ( cm_ptr, + IB_CME_CONNECTION_REQUEST_PENDING, + (void * __ptr64) p_cm_req_rec->p_req_pdata, + IB_REQ_PDATA_SIZE, + (void * __ptr64) sp_ptr ); +} + + +static void +dapli_ib_cm_mra_cb ( + IN ib_cm_mra_rec_t *p_cm_mra_rec ) +{ + UNUSED_PARAM( p_cm_mra_rec ); + dapl_dbg_log (DAPL_DBG_TYPE_CM | DAPL_DBG_TYPE_CALLBACK, + "--> DiCMcb: CM callback MRA\n"); +} + +static void +dapli_ib_cm_rtu_cb ( + IN ib_cm_rtu_rec_t *p_cm_rtu_rec ) +{ + DAPL_EP *ep_ptr; + dp_ib_cm_handle_t cm_ptr; + + dapl_os_assert (p_cm_rtu_rec != NULL); + + ep_ptr = (DAPL_EP * __ptr64) p_cm_rtu_rec->qp_context; + + if ( DAPL_BAD_HANDLE(ep_ptr, DAPL_MAGIC_EP) ) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> %s: EP %lx invalid or FREED\n", + __FUNCTION__, ep_ptr); + return; + } + cm_ptr = dapl_get_cm_from_ep(ep_ptr); + if (!cm_ptr) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "--> %s: !CM_PTR on EP %p\n", __FUNCTION__, ep_ptr); + return; + } + dapl_os_assert(cm_ptr->ib_cm.h_qp == p_cm_rtu_rec->h_qp); + + dapl_dbg_log (DAPL_DBG_TYPE_CM | DAPL_DBG_TYPE_CALLBACK, + "--> DiCRucb: EP %lx QP %lx CR %lx\n", + ep_ptr, ep_ptr->qp_handle, ep_ptr->cr_ptr); + + if (ep_ptr->cr_ptr) + { + DAPL_SP *sp_ptr; + + sp_ptr = ((DAPL_CR *) ep_ptr->cr_ptr)->sp_ptr; + + /* passive connection side */ + dapls_cr_callback ( cm_ptr, + IB_CME_CONNECTED, + (void * __ptr64) p_cm_rtu_rec->p_rtu_pdata, + IB_RTU_PDATA_SIZE, + (void *) sp_ptr); + + } + else + { + dapl_evd_connection_callback ( + cm_ptr, + IB_CME_CONNECTED, + (void * __ptr64) p_cm_rtu_rec->p_rtu_pdata, + IB_RTU_PDATA_SIZE, + (void *) ep_ptr); + } +} + +/* + * dapls_ib_cm_remote_addr + * + * Obtain the remote IP address given a connection + * + * Input: + * cr_handle + * + * Output: + * remote_ia_address: where to place the remote address + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + * + */ +DAT_RETURN +dapls_ib_cm_remote_addr ( + IN DAT_HANDLE dat_handle, + OUT DAT_SOCK_ADDR6 *remote_address ) +{ + + DAPL_HEADER *header; + dp_ib_cm_handle_t cm; + char ipa[20]; + char *rtype; + + header = (DAPL_HEADER *)dat_handle; + + if (header->magic == DAPL_MAGIC_EP) + { + cm = dapl_get_cm_from_ep((DAPL_EP *)dat_handle); + rtype = "EP"; + } + else if (header->magic == DAPL_MAGIC_CR) + { + cm = ((DAPL_CR *) dat_handle)->ib_cm_handle; + rtype = "CR"; + } + else + { + dapl_dbg_log ( DAPL_DBG_TYPE_CM, + "%s: hdr->magic %x, dat_handle(%lx)\n", + __FUNCTION__, header->magic, dat_handle ); + return DAT_INVALID_HANDLE; + } + + dapl_os_memcpy( remote_address, &cm->dst_ip_addr, sizeof(DAT_SOCK_ADDR6) ); + + dapl_dbg_log ( DAPL_DBG_TYPE_CM, "%s: returns %s remote Addrs %s\n", + __FUNCTION__, rtype, + dapli_get_ip_addr_str((DAT_SOCK_ADDR6*)remote_address,ipa) ); + + return DAT_SUCCESS; +} + + +/* + * dapls_ib_connect + * + * Initiate a connection with the passive listener on another node + * + * Input: + * ep_handle, + * remote_ia_address, + * remote_conn_qual, + * prd_size size of private data and structure + * prd_prt pointer to private data structure + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + * + */ +DAT_RETURN +dapls_ib_connect ( + IN DAT_EP_HANDLE ep_handle, + IN DAT_IA_ADDRESS_PTR remote_ia_address, + IN DAT_CONN_QUAL remote_conn_qual, + IN DAT_COUNT private_data_size, + IN DAT_PVOID private_data ) +{ + DAPL_EP *ep_ptr; + DAPL_IA *ia_ptr; + ib_api_status_t ib_status; + dapl_ibal_port_t *p_active_port; + dapl_ibal_ca_t *p_ca; + ib_cm_req_t cm_req; + ib_path_rec_t path_rec; + GID dest_GID; + ib_query_req_t query_req; + ib_gid_pair_t gid_pair; + ib_service_record_t service_rec; + int retry_cnt; + DAT_RETURN dat_status; + + ep_ptr = (DAPL_EP *) ep_handle; + ia_ptr = ep_ptr->header.owner_ia; + ep_ptr->cr_ptr = NULL; + retry_cnt = 0; + dat_status = DAT_SUCCESS; + + p_ca = (dapl_ibal_ca_t *) ia_ptr->hca_ptr->ib_hca_handle; + + /* + * We are using the first active port in the list for + * communication. We have to get back here when we decide to support + * fail-over and high-availability. + */ + p_active_port = dapli_ibal_get_port ( p_ca, + (uint8_t)ia_ptr->hca_ptr->port_num ); + + if (NULL == p_active_port) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR,"--> DsC: Port %d not available %d\n", + ia_ptr->hca_ptr->port_num, __LINE__ ); + return (DAT_INVALID_STATE); + } + + dapl_os_memzero (&dest_GID, sizeof (GID)); + dapl_os_memzero (&cm_req, sizeof (ib_cm_req_t)); + dapl_os_memzero (&path_rec, sizeof (ib_path_rec_t)); + dapl_os_memzero (&service_rec, sizeof (ib_service_record_t)); + dapl_os_memzero (&query_req, sizeof (ib_query_req_t)); + dapl_os_memzero (&gid_pair, sizeof (ib_gid_pair_t)); + dapl_os_memzero (&ep_ptr->remote_ia_address, sizeof (DAT_SOCK_ADDR6)); + + dapl_os_memcpy (&ep_ptr->remote_ia_address, + remote_ia_address, + sizeof (ep_ptr->remote_ia_address)); + + +#ifdef NO_NAME_SERVICE + + if (DAT_SUCCESS != + (dat_status = dapls_ns_lookup_address ( + ia_ptr, + remote_ia_address, + &dest_GID ))) + { + /* + * Remote address not in the table, this is a + * strange return code! + */ + dapl_dbg_log ( DAPL_DBG_TYPE_ERR,"--> DsC: exits status = %x\n", dat_status); + return dat_status; + } + + dest_GID.guid = CL_HTON64 (dest_GID.guid); + dest_GID.gid_prefix = CL_HTON64 (dest_GID.gid_prefix); + +#else + + /* + * We query the SA to get the dest_gid with the + * {uDAPL_svc_id, IP-address} as the key to get GID. + */ + if (DAT_SUCCESS != + (dat_status = dapls_ns_map_gid (ia_ptr->hca_ptr, + remote_ia_address, + &dest_GID))) + + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, "--> DsC: fail to map remote_ia_addr " + "(sa_family %d) to gid\n", + remote_ia_address->sa_family); + return dat_status; + } +#endif /* NO_NAME_SERVICE */ + + gid_pair.dest_gid.unicast.interface_id = dest_GID.guid; + gid_pair.dest_gid.unicast.prefix = dest_GID.gid_prefix; + + dapl_dbg_log (DAPL_DBG_TYPE_CM, + "dapls_ib_connect: EP %lx QP %lx SERVER GID{0x" F64x + ", 0x" F64x "}\n", + ep_ptr, ep_ptr->qp_handle, + cl_hton64 (gid_pair.dest_gid.unicast.prefix), + cl_hton64 (gid_pair.dest_gid.unicast.interface_id)); + + gid_pair.src_gid = p_active_port->p_attr->p_gid_table[0]; +/* + if ((gid_pair.src_gid.unicast.interface_id == + gid_pair.dest_gid.unicast.interface_id ) && + (gid_pair.src_gid.unicast.prefix == + gid_pair.dest_gid.unicast.prefix )) + { + path_rec.dgid = gid_pair.dest_gid; + path_rec.sgid = gid_pair.src_gid; + path_rec.slid = path_rec.dlid = p_active_port->p_attr->lid; + path_rec.pkey = p_active_port->p_attr->p_pkey_table[0]; + path_rec.mtu = p_active_port->p_attr->mtu; + path_rec.pkt_life = 18; // 1 sec + path_rec.rate = IB_PATH_RECORD_RATE_10_GBS; + + } + else + { + */ + /* + * Query SA to get the path record from pair of GIDs + */ + dapl_os_memzero (&query_req, sizeof (ib_query_req_t)); + query_req.query_type = IB_QUERY_PATH_REC_BY_GIDS; + query_req.p_query_input = (void *) &gid_pair; + query_req.flags = IB_FLAGS_SYNC; + query_req.timeout_ms = 1 * 1000; /* 1 second */ + query_req.retry_cnt = 3; + /* query SA using this port */ + query_req.port_guid = p_active_port->p_attr->port_guid; + query_req.query_context = (void *) &path_rec; + query_req.pfn_query_cb = dapli_ib_sa_query_cb; + + ib_status = ib_query (dapl_ibal_root.h_al, &query_req, NULL); + + if ((ib_status != IB_SUCCESS) || (!path_rec.dlid)) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR,"--> DsC: EP %lx QP %lx query " + "pair_gids status = %s\n", + ep_ptr, ep_ptr->qp_handle,ib_get_err_str(ib_status)); + return DAT_INVALID_PARAMETER; + } + + //} + + /* + * Tavor has a HW bug that causes bandwidth with 2K MTU to be less than + * with 1K MTU. Cap the MTU based on device ID to compensate for this. + */ + if( (p_ca->p_ca_attr->dev_id == 0x5A44) && + (ib_path_rec_mtu( &path_rec ) > IB_MTU_LEN_1024) ) + { + /* Local endpoint is Tavor - cap MTU to 1K for extra bandwidth. */ + path_rec.mtu &= IB_PATH_REC_SELECTOR_MASK; + path_rec.mtu |= IB_MTU_LEN_1024; + } + + /* + * prepare the Service ID from conn_qual + */ + cm_req.svc_id = remote_conn_qual; + cm_req.p_primary_path = &path_rec; + cm_req.p_alt_path = NULL; + cm_req.h_qp = ep_ptr->qp_handle; + cm_req.qp_type = IB_QPT_RELIABLE_CONN; + cm_req.p_req_pdata = (uint8_t *) private_data; + cm_req.req_length = (uint8_t) + min(private_data_size,IB_MAX_REQ_PDATA_SIZE); + /* cm retry to send this request messages, IB max of 4 bits */ + cm_req.max_cm_retries = 15; /* timer outside of call, s/be infinite */ + /* qp retry to send any wr */ + cm_req.retry_cnt = 5; + /* max num of oustanding RDMA read/atomic support */ + cm_req.resp_res = (uint8_t)ep_ptr->param.ep_attr.max_rdma_read_in; + /* max num of oustanding RDMA read/atomic will use */ + cm_req.init_depth = (uint8_t)ep_ptr->param.ep_attr.max_rdma_read_out; + + /* time wait before retrying a pkt after receiving a RNR NAK */ + cm_req.rnr_nak_timeout = IB_RNR_NAK_TIMEOUT; + + /* + * number of time local QP should retry after receiving RNR NACK before + * reporting an error + */ + cm_req.rnr_retry_cnt = IB_RNR_RETRY_CNT; + + cm_req.remote_resp_timeout = 16; /* 250ms */ + cm_req.local_resp_timeout = 16; /* 250ms */ + + cm_req.flow_ctrl = TRUE; + cm_req.flags = 0; + /* + * We do not use specific data buffer to check for specific connection + */ + cm_req.p_compare_buffer = NULL; + cm_req.compare_offset = 0; + cm_req.compare_length = 0; + + dapl_dbg_log (DAPL_DBG_TYPE_CM, "--> DsConn: EP=%lx QP=%lx rio=%d,%d pl=%d " + "mtu=%d slid=%#x dlid=%#x\n", + ep_ptr, ep_ptr->qp_handle, cm_req.resp_res, + cm_req.init_depth, ib_path_rec_pkt_life(&path_rec), + ib_path_rec_mtu(&path_rec), + cm_req.p_primary_path->slid, + cm_req.p_primary_path->dlid); + + /* + * We do not support peer_to_peer; therefore, we set pfn_cm_req_cb = NULL + */ + cm_req.pfn_cm_req_cb = NULL; + cm_req.pfn_cm_rep_cb = dapli_ib_cm_rep_cb; + cm_req.pfn_cm_rej_cb = dapli_ib_cm_rej_cb; + /* callback when a message received acknowledgement is received */ + cm_req.pfn_cm_mra_cb = dapli_ib_cm_mra_cb; + + ib_status = ib_cm_req (&cm_req); + + if ( ib_status != IB_SUCCESS ) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "--> DsC: EP %lx QP %lx conn_request failed = %s\n", + ep_ptr, ep_ptr->qp_handle, ib_get_err_str(ib_status)); + + return (dapl_ib_status_convert (ib_status)); + } + + return DAT_SUCCESS; +} + + +/* + * dapls_ib_disconnect + * + * Disconnect an EP + * + * Input: + * ep_handle, + * disconnect_flags + * DAT_CLOSE_ABRUPT_FLAG - no callback + * DAT_CLOSE_GRACEFUL_FLAG - callback desired. + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + * + */ +DAT_RETURN +dapls_ib_disconnect ( IN DAPL_EP *ep_ptr, + IN DAT_CLOSE_FLAGS disconnect_flags ) +{ + ib_api_status_t ib_status = IB_SUCCESS; + ib_cm_dreq_t cm_dreq; + dp_ib_cm_handle_t cm_ptr; + + dapl_os_assert(ep_ptr); + + if ( DAPL_BAD_HANDLE(ep_ptr, DAPL_MAGIC_EP) ) + { + dapl_dbg_log (DAPL_DBG_TYPE_CM, + "--> %s: BAD EP Magic EP=%lx\n", __FUNCTION__,ep_ptr); + return DAT_SUCCESS; + } + cm_ptr = dapl_get_cm_from_ep(ep_ptr); + if (!cm_ptr) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "--> %s: !CM_PTR on EP %p\n", __FUNCTION__, ep_ptr); + return DAT_SUCCESS; + } + + dapl_dbg_log (DAPL_DBG_TYPE_CM, + "--> %s() EP %p %s rx_drq %d tx_drq %d Close %s\n", __FUNCTION__, + ep_ptr, dapl_get_ep_state_str(ep_ptr->param.ep_state), + ep_ptr->recv_discreq, ep_ptr->sent_discreq, + (disconnect_flags == DAT_CLOSE_ABRUPT_FLAG ? "Abrupt":"Graceful")); + + if ( disconnect_flags == DAT_CLOSE_ABRUPT_FLAG ) + { + if ( ep_ptr->param.ep_state == DAT_EP_STATE_DISCONNECTED ) + return DAT_SUCCESS; + + if ( ep_ptr->param.ep_state != DAT_EP_STATE_DISCONNECT_PENDING ) + { + dapl_dbg_log(DAPL_DBG_TYPE_CM, + "%s() calling legacy_post_disconnect()\n",__FUNCTION__); + dapl_ep_legacy_post_disconnect(ep_ptr, disconnect_flags); + return DAT_SUCCESS; + } + } + + dapl_os_memzero(&cm_dreq, sizeof(ib_cm_dreq_t)); + + cm_dreq.qp_type = IB_QPT_RELIABLE_CONN; + cm_dreq.h_qp = ep_ptr->qp_handle; + cm_dreq.pfn_cm_drep_cb = dapli_ib_cm_drep_cb; + + /* + * Currently we do not send any disconnect private data to + * the other endpoint because DAT 2.0 does not support it. + */ + cm_dreq.p_dreq_pdata = NULL; + cm_dreq.flags = IB_FLAGS_SYNC; + + /* + * still need to send DREQ (disconnect request)? + */ + if ( (ep_ptr->recv_discreq == DAT_FALSE) + && (ep_ptr->sent_discreq == DAT_FALSE) + && (ep_ptr->qp_state != IB_QPS_RESET) ) + { + ep_ptr->sent_discreq = DAT_TRUE; + ib_status = ib_cm_dreq ( &cm_dreq ); + + if ( ib_status == IB_SUCCESS ) + dapl_dbg_log (DAPL_DBG_TYPE_CM, + "--> DsD: EP %p DREQ SENT\n", ep_ptr); + + /* tolerate INVALID_STATE error as the other side can race ahead and + * generate a DREQ before we do. + */ + if ( ib_status == IB_INVALID_STATE || ib_status == IB_INVALID_HANDLE ) + { + ib_status = IB_SUCCESS; + } + else if (ib_status) + { + dapl_dbg_log(DAPL_DBG_TYPE_ERR, + "%s() EP %p ib_cm_dreq() status %s\n", + __FUNCTION__,ep_ptr,ib_get_err_str(ib_status)); + } + } + return ib_status; +} + + +/* + * dapl_ib_setup_conn_listener + * + * Have the CM set up a connection listener. + * + * Input: + * ibm_hca_handle HCA handle + * qp_handle QP handle + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + * + */ +DAT_RETURN +dapls_ib_setup_conn_listener ( + IN DAPL_IA *ia_ptr, + IN DAT_UINT64 ServiceID, + IN DAPL_SP *sp_ptr ) +{ + ib_api_status_t ib_status; + ib_cm_listen_t cm_listen; + dapl_ibal_ca_t *p_ca; + dapl_ibal_port_t *p_active_port; + + p_ca = (dapl_ibal_ca_t *) ia_ptr->hca_ptr->ib_hca_handle; + + /* + * We are using the first active port in the list for + * communication. We have to get back here when we decide to support + * fail-over and high-availability. + */ + p_active_port = dapli_ibal_get_port( p_ca, + (uint8_t)ia_ptr->hca_ptr->port_num ); + + if (NULL == p_active_port) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR,"%s: SP %lx port %d not available\n", + __FUNCTION__, sp_ptr, ia_ptr->hca_ptr->port_num ); + return (DAT_INVALID_STATE); + } + + if (p_active_port->p_attr->lid == 0) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "--> DsSCL: SP %lx SID 0x" F64x " port %d\n", + sp_ptr, cl_hton64(ServiceID), + p_active_port->p_attr->port_num); + return (DAT_INVALID_STATE); + } + + dapl_dbg_log (DAPL_DBG_TYPE_CM, + "%s: SP %lx port %d GID{0x" F64x ", 0x" F64x "} and SID 0x" F64x "\n", + __FUNCTION__, + sp_ptr, p_active_port->p_attr->port_num, + cl_hton64 (p_active_port->p_attr->p_gid_table[0].unicast.prefix), + cl_hton64 (p_active_port->p_attr->p_gid_table[0].unicast.interface_id), + cl_hton64 (ServiceID)); + + dapl_os_memzero (&cm_listen, sizeof (ib_cm_listen_t)); + + /* + * Listen for all request on this specific CA + */ + cm_listen.ca_guid = (p_ca->p_ca_attr->ca_guid); + cm_listen.svc_id = ServiceID; + cm_listen.qp_type = IB_QPT_RELIABLE_CONN; + + /* + * We do not use specific data buffer to check for specific connection + */ + cm_listen.p_compare_buffer = NULL;//(uint8_t*)&sp_ptr->conn_qual; + cm_listen.compare_offset = 0;//IB_MAX_REQ_PDATA_SIZE - sizeof(DAT_CONN_QUAL); + cm_listen.compare_length = 0;//sizeof(DAT_CONN_QUAL); + + /* + * We can pick a port here for communication and the others are reserved + * for fail-over / high-availability - TBD + */ + cm_listen.port_guid = p_active_port->p_attr->port_guid; + cm_listen.lid = p_active_port->p_attr->lid; + cm_listen.pkey = p_active_port->p_attr->p_pkey_table[0]; + + /* + * Register request or mra callback functions + */ + cm_listen.pfn_cm_req_cb = dapli_ib_cm_req_cb; + + ib_status = ib_cm_listen ( dapl_ibal_root.h_al, + &cm_listen, + (void *) sp_ptr, + &sp_ptr->cm_srvc_handle ); + + if (ib_status != IB_SUCCESS) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "%s: SP %lx SID 0x" F64x " listen failed %s\n", + __FUNCTION__, sp_ptr, cl_hton64 (ServiceID), + ib_get_err_str(ib_status)); + } + + return dapl_ib_status_convert (ib_status); +} + + +/* + * dapl_ib_remove_conn_listener + * + * Have the CM remove a connection listener. + * + * Input: + * ia_handle IA handle + * ServiceID IB Channel Service ID + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + * + */ +DAT_RETURN +dapls_ib_remove_conn_listener ( + IN DAPL_IA *ia_ptr, + IN DAPL_SP *sp_ptr ) +{ + ib_api_status_t ib_status; + DAT_RETURN dat_status = DAT_SUCCESS; + + UNUSED_PARAM( ia_ptr ); + + dapl_os_assert ( sp_ptr ); + + dapl_os_assert ( sp_ptr->header.magic == DAPL_MAGIC_PSP || + sp_ptr->header.magic == DAPL_MAGIC_RSP ); + + dapl_dbg_log ( DAPL_DBG_TYPE_CM, "%s() cm_srvc_handle %lx\n", + __FUNCTION__, sp_ptr->cm_srvc_handle ); + + if (sp_ptr->cm_srvc_handle) + { + ib_status = ib_cm_cancel ( sp_ptr->cm_srvc_handle, + NULL ); + + if (ib_status != IB_SUCCESS) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "--> DsRCL: SP %lx ib_cm_cancel failed(0x%x) %s\n", + sp_ptr, sp_ptr->cm_srvc_handle, + ib_get_err_str(ib_status)); + sp_ptr->cm_srvc_handle = NULL; + return (DAT_INVALID_PARAMETER); + } + + sp_ptr->cm_srvc_handle = NULL; + } + + return dat_status; +} + +/* + * dapls_ib_reject_connection + * + * Perform necessary steps to reject a connection + * + * Input: + * cr_handle + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + * + */ +DAT_RETURN +dapls_ib_reject_connection ( IN dp_ib_cm_handle_t ib_cm_handle, + IN int reject_reason, + IN DAT_COUNT private_data_size, + IN const DAT_PVOID private_data) +{ + ib_api_status_t ib_status; + ib_cm_rej_t cm_rej; + static char *rej_table[] = + { + "INVALID_REJ_REASON", + "INVALID_REJ_REASON", + "INVALID_REJ_REASON", + "INVALID_REJ_REASON", + "INVALID_REJ_REASON", + "IB_CME_DESTINATION_REJECT", + "IB_CME_DESTINATION_REJECT_PRIVATE_DATA", + "IB_CME_DESTINATION_UNREACHABLE", + "IB_CME_TOO_MANY_CONNECTION_REQUESTS", + "IB_CME_LOCAL_FAILURE", + "IB_CM_LOCAL_FAILURE" + }; + +#define REJ_TABLE_SIZE IB_CM_LOCAL_FAILURE + + reject_reason = __min( reject_reason & 0xff, REJ_TABLE_SIZE); + + cm_rej.rej_status = IB_REJ_USER_DEFINED; + cm_rej.p_ari = (ib_ari_t *)&rej_table[reject_reason]; + cm_rej.ari_length = (uint8_t)strlen (rej_table[reject_reason]); + + cm_rej.p_rej_pdata = private_data; + cm_rej.rej_length = private_data_size; + +#if defined(DAPL_DBG) && 0 + dapli_print_private_data("DsRjC",private_data,private_data_size); +#endif + + ib_status = ib_cm_rej(ib_cm_handle->ib_cm, &cm_rej); + + if (ib_status != IB_SUCCESS) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "--> DsRjC: cm_handle %p reject failed %s\n", + ib_cm_handle, ib_get_err_str(ib_status) ); + } + + return ( dapl_ib_status_convert ( ib_status ) ); +} + + + +#if 0 +static void +dapli_query_qp( ib_qp_handle_t qp_handle, ib_qp_attr_t *qpa ) +{ + ib_api_status_t ib_status; + + ib_status = ib_query_qp ( qp_handle, qpa ); + if (ib_status != IB_SUCCESS) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR,"ib_query_qp(%lx) '%s'\n", + qp_handle, ib_get_err_str(ib_status) ); + } + else + { + dapl_dbg_log ( DAPL_DBG_TYPE_CM, "--> QP(%lx) state %s " + "type %d init %d acc %x\n", + qp_handle, + ib_get_port_state_str(qpa->state), + qpa->qp_type, + qpa->init_depth, + qpa->access_ctrl ); + } +} +#endif + + +/* + * dapls_ib_accept_connection + * + * Perform necessary steps to accept a connection + * + * Input: + * cr_handle + * ep_handle + * private_data_size + * private_data + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + * + */ +DAT_RETURN +dapls_ib_accept_connection ( + IN DAT_CR_HANDLE cr_handle, + IN DAT_EP_HANDLE ep_handle, + IN DAT_COUNT private_data_size, + IN const DAT_PVOID private_data ) +{ + DAPL_CR *cr_ptr; + DAPL_EP *ep_ptr; + DAPL_IA *ia_ptr; + DAT_RETURN dat_status; + ib_api_status_t ib_status; + dapl_ibal_ca_t *p_ca; + dapl_ibal_port_t *p_active_port; + ib_cm_rep_t cm_rep; + ib_qp_attr_t qpa; + dp_ib_cm_handle_t cm_ptr; + + cr_ptr = (DAPL_CR *) cr_handle; + ep_ptr = (DAPL_EP *) ep_handle; + ia_ptr = ep_ptr->header.owner_ia; + + if ( ep_ptr->qp_state == DAPL_QP_STATE_UNATTACHED ) + { + /* + * If we are lazy attaching the QP then we may need to + * hook it up here. Typically, we run this code only for + * DAT_PSP_PROVIDER_FLAG + */ + dat_status = dapls_ib_qp_alloc ( ia_ptr, ep_ptr, ep_ptr ); + + if ( dat_status != DAT_SUCCESS) + { + /* This is not a great error code, but all the spec allows */ + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "--> DsIBAC: CR %lx EP %lx alloc QP failed 0x%x\n", + cr_ptr, ep_ptr, dat_status ); + return (dat_status); + } + } + + p_ca = (dapl_ibal_ca_t *) ia_ptr->hca_ptr->ib_hca_handle; + p_active_port = dapli_ibal_get_port ( p_ca, + (uint8_t)ia_ptr->hca_ptr->port_num ); + if (NULL == p_active_port) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "--> DsIBAC: CR %lx EP %lx port %d is not available\n", + cr_ptr, ep_ptr, ia_ptr->hca_ptr->port_num); + return (DAT_INVALID_STATE); + } + + cr_ptr->param.local_ep_handle = ep_handle; + + /* + * assume ownership, in that once the EP is released the dynamic + * memory containing the IBAL CM handle (ib_cm_handle_t) struct will + * be released; see dapl_ep_dealloc(). + */ + + /* EP-CM, save/release CR CM object, use EP CM object already linked */ + cm_ptr = dapl_get_cm_from_ep(ep_ptr); + if (!cm_ptr) { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "--> DsIBAC: CM linking to EP %p not available\n", + ep_ptr); + return (DAT_INVALID_STATE); + } + + /* set remote IP addr fields. IP addr data is deduced from Connection + * Request record (gid/lib) and stashed away for use here. DAPL 1.1 + * had an interface for passing the IP info down, interface went away + * in 2.0? + */ + dapl_os_memcpy( (void*)&ep_ptr->remote_ia_address, + (void*)&cr_ptr->ib_cm_handle->dst_ip_addr, + sizeof(DAT_SOCK_ADDR6) ); + + dapl_os_memcpy( (void*)&cr_ptr->remote_ia_address, + (void*)&ep_ptr->remote_ia_address, + sizeof(DAT_SOCK_ADDR6) ); + +#if defined(DAPL_DBG) + { + char ipa[20]; + + dapl_dbg_log (DAPL_DBG_TYPE_CM|DAPL_DBG_TYPE_CALLBACK, + "%s: EP(%lx) RemoteAddr: %s\n", + __FUNCTION__, ep_ptr, + dapli_get_ip_addr_str( + (DAT_SOCK_ADDR6*)&ep_ptr->remote_ia_address, ipa) ); + } +#endif + + dapl_os_memcpy( (void*)&cm_ptr->dst_ip_addr, + (void*)&cr_ptr->ib_cm_handle->dst_ip_addr, + sizeof(DAT_SOCK_ADDR6) ); + + /* get h_al and connection ID from CR CM object, h_qp already set */ + cm_ptr->ib_cm.cid = cr_ptr->ib_cm_handle->ib_cm.cid; + cm_ptr->ib_cm.h_al = cr_ptr->ib_cm_handle->ib_cm.h_al; + dapls_cm_release(cr_ptr->ib_cm_handle); + + cr_ptr->ib_cm_handle = cm_ptr; /* for dapli_get_sp_ep() upcall */ + + ep_ptr->cr_ptr = cr_ptr; + + dapl_os_memzero ( (void*)&cm_rep, sizeof (ib_cm_rep_t) ); + + cm_rep.h_qp = ep_ptr->qp_handle; + cm_rep.qp_type = IB_QPT_RELIABLE_CONN; + + if (private_data_size > IB_MAX_REP_PDATA_SIZE) { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "--> DsIBAC: private_data_size(%d) > Max(%d)\n", + private_data_size, IB_MAX_REP_PDATA_SIZE); + return DAT_ERROR(DAT_LENGTH_ERROR, DAT_NO_SUBTYPE); + + } + cm_rep.p_rep_pdata = (const uint8_t *)private_data; + cm_rep.rep_length = private_data_size; + +#if defined(DAPL_DBG) && 0 + dapli_print_private_data( "DsIBAC", + (const uint8_t*)private_data, + private_data_size ); +#endif + + cm_rep.pfn_cm_rej_cb = dapli_ib_cm_rej_cb; + cm_rep.pfn_cm_mra_cb = dapli_ib_cm_mra_cb; + cm_rep.pfn_cm_rtu_cb = dapli_ib_cm_rtu_cb; + cm_rep.pfn_cm_lap_cb = dapli_ib_cm_lap_cb; + cm_rep.pfn_cm_dreq_cb = dapli_ib_cm_dreq_cb; + + /* + * FIXME - Vu + * Pay attention to the attributes. + * Some of them are desirably set by DAT consumers + */ + /* + * We enable the qp associate with this connection ep all the access right + * We enable the flow_ctrl, retry till success + * We will limit the access right and flow_ctrl upon DAT consumers + * requirements + */ + cm_rep.access_ctrl = + IB_AC_LOCAL_WRITE|IB_AC_RDMA_WRITE|IB_AC_MW_BIND|IB_AC_ATOMIC; + + if ((ep_ptr->param.ep_attr.max_rdma_read_in > 0) + || (ep_ptr->param.ep_attr.max_rdma_read_out > 0)) + { + cm_rep.access_ctrl |= IB_AC_RDMA_READ; + } + + cm_rep.sq_depth = 0; + cm_rep.rq_depth = 0; + cm_rep.init_depth = (uint8_t)ep_ptr->param.ep_attr.max_rdma_read_out; + cm_rep.flow_ctrl = TRUE; + cm_rep.flags = 0; + cm_rep.failover_accepted = IB_FAILOVER_ACCEPT_UNSUPPORTED; + cm_rep.target_ack_delay = 14; + cm_rep.rnr_nak_timeout = IB_RNR_NAK_TIMEOUT; + cm_rep.rnr_retry_cnt = IB_RNR_RETRY_CNT; + cm_rep.pp_recv_failure = NULL; + cm_rep.p_recv_wr = NULL; + + dapl_dbg_log (DAPL_DBG_TYPE_CM, + "--> DsIBAC: cm_rep: acc %x init %d qp_type %x req_count %d\n", + cm_rep.access_ctrl, cm_rep.init_depth,cm_rep.qp_type, + dapls_cb_pending(&ep_ptr->req_buffer)); + + ib_status = ib_cm_rep ( cm_ptr->ib_cm, &cm_rep ); + + if (ib_status != IB_SUCCESS) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "--> DsIBAC: EP %lx QP %lx CR reply failed '%s'\n", + ep_ptr, ep_ptr->qp_handle, ib_get_err_str(ib_status) ); + } + + return ( dapl_ib_status_convert ( ib_status ) ); +} + + + +/* + * dapls_ib_disconnect_clean + * + * Clean up outstanding connection data. This routine is invoked + * after the final disconnect callback has occurred. Only on the + * ACTIVE side of a connection. + * + * Input: + * ep_ptr DAPL_EP + * + * Output: + * none + * + * Returns: + * void + * + */ +void +dapls_ib_disconnect_clean ( + IN DAPL_EP *ep_ptr, + IN DAT_BOOLEAN active, + IN const ib_cm_events_t ib_cm_event ) +{ + DAPL_IA *ia_ptr; + ib_qp_attr_t qp_attr; + ib_api_status_t ib_status; + + dapl_dbg_log ( DAPL_DBG_TYPE_CM, "%s(%s): cm_event: %s \n", __FUNCTION__, + (active?"A":"P"), dapli_ib_cm_event_str(ib_cm_event)); + + ia_ptr = ep_ptr->header.owner_ia; + + if ( ia_ptr == NULL || ia_ptr->header.magic != DAPL_MAGIC_IA ) + { + dapl_dbg_log ( DAPL_DBG_TYPE_CM, + ">>>DSCONN_CLEAN(%s): cm_event: %s Invalid IA_ptr\n", + (active?"Act":"Pas"),dapli_ib_cm_event_str(ib_cm_event)); + return; + } + dapl_os_assert ( ep_ptr->header.magic == DAPL_MAGIC_EP ); + + ep_ptr->sent_discreq = DAT_FALSE; + ep_ptr->recv_discreq = DAT_FALSE; + + /* + * Query the QP to get the current state */ + ib_status = ib_query_qp ( ep_ptr->qp_handle, &qp_attr ); + + if ( ib_status != IB_SUCCESS ) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + ">>>DSCONN_CLEAN(%s): Query QP failed = %s\n", + (active?"Act":"Pas"),ib_get_err_str(ib_status) ); + return; + } + + ep_ptr->qp_state = qp_attr.state; + + dapl_dbg_log ( DAPL_DBG_TYPE_CM, ">>>DSCONN_CLEAN(%s): cm_event: %d " + "ep_ptr %lx ep_state %s qp_state %#x\n", + (active?"A":"P"), ib_cm_event, ep_ptr, + dapl_get_ep_state_str(ep_ptr->param.ep_state), + ep_ptr->qp_state ); + + if ( ep_ptr->qp_state != IB_QPS_ERROR && + ep_ptr->qp_state != IB_QPS_RESET && + ep_ptr->qp_state != IB_QPS_INIT ) + { + ep_ptr->qp_state = IB_QPS_ERROR; + dapls_modify_qp_state_to_error (ep_ptr->qp_handle); + } +} + + +#ifdef NOT_USED +/* + * dapls_ib_cr_handoff + * + * Hand off the connection request to another service point + * + * Input: + * cr_handle DAT_CR_HANDLE + * handoff_serv_id DAT_CONN_QUAL + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + * + */ +DAT_RETURN +dapls_ib_cr_handoff ( + IN DAT_CR_HANDLE cr_handle, + IN DAT_CONN_QUAL handoff_serv_id ) +{ + DAPL_CR *cr_ptr; + ib_api_status_t ib_status; + + cr_ptr = (DAPL_CR *) cr_handle; + + if (cr_ptr->ib_cm_handle->ib_cm.cid == 0xFFFFFFFF) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "--> DsCH: CR = %lx invalid cm handle\n", cr_ptr); + return DAT_INVALID_PARAMETER; + } + + if (cr_ptr->sp_ptr == DAPL_IB_INVALID_HANDLE) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "--> DsCH: CR = %lx invalid psp handle\n", cr_ptr); + return DAT_INVALID_PARAMETER; + } + + ib_status = ib_cm_handoff (cr_ptr->ib_cm_handle->ib_cm, handoff_serv_id); + + if (ib_status != IB_SUCCESS) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "--> DsCH: CR = %lx handoff failed = %s\n", + cr_ptr, ib_get_err_str(ib_status) ); + + return dapl_ib_status_convert (ib_status); + } + + dapl_dbg_log ( DAPL_DBG_TYPE_CM, + "--> %s(): remove CR %lx from SP %lx Queue\n", + __FUNCTION__, cr_ptr, cr_ptr->sp_ptr); + /* Remove the CR from the queue */ + dapl_sp_remove_cr (cr_ptr->sp_ptr, cr_ptr); + + /* + * If this SP has been removed from service, free it + * up after the last CR is removed + */ + dapl_os_lock (&cr_ptr->sp_ptr->header.lock); + if ( cr_ptr->sp_ptr->listening != DAT_TRUE && + cr_ptr->sp_ptr->cr_list_count == 0 && + cr_ptr->sp_ptr->state != DAPL_SP_STATE_FREE ) + { + dapl_dbg_log (DAPL_DBG_TYPE_CM, + "--> DsCH: CR = %lx disconnect dump SP = %lx \n", + cr_ptr, cr_ptr->sp_ptr); + /* Decrement the ref count on the EVD */ + if (cr_ptr->sp_ptr->evd_handle) + { + dapl_os_atomic_dec (& ((DAPL_EVD *)cr_ptr->sp_ptr->evd_handle)->evd_ref_count); + cr_ptr->sp_ptr->evd_handle = NULL; + } + cr_ptr->sp_ptr->state = DAPL_SP_STATE_FREE; + dapl_os_unlock (&cr_ptr->sp_ptr->header.lock); + (void)dapls_ib_remove_conn_listener ( cr_ptr->sp_ptr->header.owner_ia, + cr_ptr->sp_ptr ); + dapls_ia_unlink_sp ( (DAPL_IA *)cr_ptr->sp_ptr->header.owner_ia, + cr_ptr->sp_ptr ); + dapls_sp_free_sp ( cr_ptr->sp_ptr ); + } + else + { + dapl_os_unlock (&cr_ptr->sp_ptr->header.lock); + } + + /* + * Clean up and dispose of the resource + */ + dapls_cr_free (cr_ptr); + + return (DAT_SUCCESS); +} +#endif + +int +dapls_ib_private_data_size ( + IN DAPL_HCA *hca_ptr) +{ + return IB_MAX_REQ_PDATA_SIZE; +} + + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ + diff --git a/branches/WOF2-3/ulp/dapl2/dapl/ibal/dapl_ibal_cq.c b/branches/WOF2-3/ulp/dapl2/dapl/ibal/dapl_ibal_cq.c new file mode 100644 index 00000000..5bc51af8 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/ibal/dapl_ibal_cq.c @@ -0,0 +1,435 @@ + +/* + * Copyright (c) 2007 Intel Corporation. All rights reserved. + * Copyright (c) 2002, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under the terms of the "Common Public + * License" a copy of which is in the file LICENSE.txt in the root + * directory. The license is also available from the Open Source + * Initiative, see http://www.opensource.org/licenses/cpl.php. + * + */ + +/********************************************************************** + * + * MODULE: dapl_ibal_cq.c + * + * PURPOSE: CQ (Completion Qeueu) access routine using IBAL APIs + * + * $Id$ + * + **********************************************************************/ + +#include "dapl.h" +#include "dapl_adapter_util.h" +#include "dapl_evd_util.h" +#include "dapl_cr_util.h" +#include "dapl_lmr_util.h" +#include "dapl_rmr_util.h" +#include "dapl_cookie.h" +#include "dapl_ring_buffer_util.h" + +#ifndef NO_NAME_SERVICE +#include "dapl_name_service.h" +#endif /* NO_NAME_SERVICE */ + + +static void +dapli_ibal_cq_async_error_callback ( IN ib_async_event_rec_t *p_err_rec ) +{ + DAPL_EVD *evd_ptr = (DAPL_EVD*)((void *)p_err_rec->context); + DAPL_EVD *async_evd_ptr; + DAPL_IA *ia_ptr; + dapl_ibal_ca_t *p_ca; + dapl_ibal_evd_cb_t *evd_cb; + + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "--> DiCqAEC: CQ error %d for EVD context %lx\n", + p_err_rec->code, p_err_rec->context); + + if (DAPL_BAD_HANDLE (evd_ptr, DAPL_MAGIC_EVD)) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "--> DiCqAEC: invalid EVD %lx\n", evd_ptr); + return; + } + + ia_ptr = evd_ptr->header.owner_ia; + async_evd_ptr = ia_ptr->async_error_evd; + if (async_evd_ptr == NULL) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR,"--> DiCqAEC: can't find async_error_evd on %s HCA\n", + (ia_ptr->header.provider)->device_name ); + return; + } + + p_ca = (dapl_ibal_ca_t *) ia_ptr->hca_ptr->ib_hca_handle; + if (p_ca == NULL) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR,"--> DiCqAEC: can't find %s HCA\n", + (ia_ptr->header.provider)->device_name); + return; + } + + /* find CQ error callback using ia_ptr for context */ + evd_cb = dapli_find_evd_cb_by_context ( async_evd_ptr, p_ca ); + if ((evd_cb == NULL) || (evd_cb->pfn_async_cq_err_cb == NULL)) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "--> DiCqAEC: no ERROR cb on %lx found \n", p_ca); + return; + } + + /* maps to dapl_evd_cq_async_error_callback(), context is EVD */ + evd_cb->pfn_async_cq_err_cb( (ib_hca_handle_t)p_ca, + evd_ptr->ib_cq_handle, + (ib_error_record_t*)&p_err_rec->code, + evd_ptr ); + +} + + +/* + * dapli_ibal_cq_competion_callback + * + * Completion callback for a CQ + * + * Input: + * cq_context User context + * + * Output: + * none + * + * Returns: + */ +static void +dapli_ib_cq_completion_cb ( + IN const ib_cq_handle_t h_cq, + IN void *cq_context ) +{ + DAPL_EVD *evd_ptr; + dapl_ibal_ca_t *p_ca; + + evd_ptr = (DAPL_EVD *) cq_context; + + dapl_dbg_log (DAPL_DBG_TYPE_CALLBACK, + "--> DiICCC: cq_completion_cb evd %lx CQ %lx\n", + evd_ptr, evd_ptr->ib_cq_handle); + + dapl_os_assert (evd_ptr != DAT_HANDLE_NULL); + + p_ca = (dapl_ibal_ca_t *) evd_ptr->header.owner_ia->hca_ptr->ib_hca_handle; + + dapl_os_assert( h_cq == evd_ptr->ib_cq_handle ); + + dapl_evd_dto_callback ( (ib_hca_handle_t) p_ca, h_cq, cq_context); +} + + +/* + * dapl_ib_cq_late_alloc + * + * Alloc a CQ + * + * Input: + * ia_handle IA handle + * evd_ptr pointer to EVD struct + * cqlen minimum QLen + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * + */ +DAT_RETURN +dapls_ib_cq_late_alloc ( + IN ib_pd_handle_t pd_handle, + IN DAPL_EVD *evd_ptr ) +{ + ib_cq_create_t cq_create; + ib_api_status_t ib_status; + DAT_RETURN dat_status; + dapl_ibal_ca_t *ibal_ca; + + dat_status = DAT_SUCCESS; + cq_create.size = evd_ptr->qlen; + + ibal_ca = (dapl_ibal_ca_t*)evd_ptr->header.owner_ia->hca_ptr->ib_hca_handle; + + cq_create.h_wait_obj = NULL; + cq_create.pfn_comp_cb = dapli_ib_cq_completion_cb; + + ib_status = ib_create_cq ( + (ib_ca_handle_t)ibal_ca->h_ca, + &cq_create, + evd_ptr /* context */, + dapli_ibal_cq_async_error_callback, + &evd_ptr->ib_cq_handle); + + dat_status = dapl_ib_status_convert (ib_status); + + if ( dat_status != DAT_SUCCESS ) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "--> DsICLA: failed to create CQ for EVD %lx\n",evd_ptr); + goto bail; + } + + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "--> DsCQ_alloc: pd=%lx cq=%lx CQsz=%d EVD->Qln=%d\n", + pd_handle, evd_ptr->ib_cq_handle, + cq_create.size, evd_ptr->qlen); + + /* + * As long as the CQ size is >= the evd size, then things are OK; sez Arlin. + */ + if ( cq_create.size < (uint32_t)evd_ptr->qlen ) + { + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "--> DsCQ_alloc: created CQ size(%d) < evd->qlen(%d)?\n", + cq_create.size, evd_ptr->qlen); + dat_status = dapl_ib_status_convert (IB_INVALID_CQ_SIZE); + } + +bail: + return dat_status; +} + +/* + * dapl_ib_cq_alloc + * + * Alloc a CQ + * + * Input: + * ia_handle IA handle + * evd_ptr pointer to EVD struct + * cqlen minimum QLen + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * + */ + + +/* + * dapl_ib_cq_free + * + * Dealloc a CQ + * + * Input: + * ia_handle IA handle + * evd_ptr pointer to EVD struct + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + * DAT_INSUFFICIENT_RESOURCES + * + */ +DAT_RETURN +dapls_ib_cq_free ( + IN DAPL_IA *ia_ptr, + IN DAPL_EVD *evd_ptr) +{ + ib_api_status_t ib_status; + + if ( ia_ptr == NULL || ia_ptr->header.magic != DAPL_MAGIC_IA ) + { + return DAT_INVALID_HANDLE; + } + + ib_status = ib_destroy_cq (evd_ptr->ib_cq_handle, + /* destroy_callback */ NULL); + + return dapl_ib_status_convert (ib_status); +} + +/* + * dapls_cq_resize + * + * Resize CQ completion notifications + * + * Input: + * ia_handle IA handle + * evd_ptr pointer to EVD struct + * cqlen minimum QLen + * + * Output: + * cqlen may round up for optimal memory boundaries + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + * DAT_INSUFFICIENT_RESOURCES + * + */ + +DAT_RETURN +dapls_ib_cq_resize ( + IN DAPL_IA *ia_ptr, + IN DAPL_EVD *evd_ptr, + IN DAT_COUNT *cqlen ) +{ + ib_api_status_t ib_status = IB_SUCCESS; + + if ( ia_ptr == NULL || ia_ptr->header.magic != DAPL_MAGIC_IA ) + { + return DAT_INVALID_HANDLE; + } + /* + * Resize CQ only if CQ handle is valid, may be delayed waiting + * for PZ allocation with IBAL + */ +#if defined(_VENDOR_IBAL_) + if ( evd_ptr->ib_cq_handle != IB_INVALID_HANDLE ) +#endif /* _VENDOR_IBAL_ */ + { + ib_status = ib_modify_cq ( evd_ptr->ib_cq_handle, + (uint32_t *)cqlen ); + dapl_dbg_log (DAPL_DBG_TYPE_EVD, + "ib_modify_cq ( new cqlen = %d, status=%d ) \n", + *cqlen, ib_status ); + } + return dapl_ib_status_convert (ib_status); +} + + +/* + * dapl_set_cq_notify + * + * Set up CQ completion notifications + * + * Input: + * ia_handle IA handle + * evd_ptr pointer to EVD struct + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + * DAT_INSUFFICIENT_RESOURCES + * + */ +DAT_RETURN +dapls_set_cq_notify ( + IN DAPL_IA *ia_ptr, + IN DAPL_EVD *evd_ptr ) +{ + ib_api_status_t ib_status; + if ( ia_ptr == NULL || ia_ptr->header.magic != DAPL_MAGIC_IA ) + { + return DAT_INVALID_HANDLE; + } + ib_status = ib_rearm_cq ( + evd_ptr->ib_cq_handle, + FALSE /* next event but not solicited event */ ); + + return dapl_ib_status_convert (ib_status); +} + + +/* + * dapls_ib_cqd_create + * + * Set up CQ notification event thread + * + * Input: + * ia_handle HCA handle + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + * DAT_INSUFFICIENT_RESOURCES + * + */ +DAT_RETURN +dapls_ib_cqd_create ( IN DAPL_HCA *p_hca ) +{ + /* + * We do not have CQD concept + */ + p_hca->ib_trans.ib_cqd_handle = IB_INVALID_HANDLE; + + return DAT_SUCCESS; +} + + +/* + * dapl_cqd_destroy + * + * Destroy CQ notification event thread + * + * Input: + * ia_handle IA handle + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + * DAT_INSUFFICIENT_RESOURCES + * + */ +DAT_RETURN +dapls_ib_cqd_destroy ( IN DAPL_HCA *p_hca ) +{ + p_hca->ib_trans.ib_cqd_handle = IB_INVALID_HANDLE; + return (DAT_SUCCESS); +} + + + +DAT_RETURN +dapls_ib_n_completions_notify ( + IN ib_hca_handle_t hca_handle, + IN ib_cq_handle_t cq_handle, + IN uint32_t n_cqes ) +{ + ib_api_status_t ib_status; + UNREFERENCED_PARAMETER(hca_handle); + + ib_status = ib_rearm_n_cq ( + cq_handle, + n_cqes ); + + return dapl_ib_status_convert (ib_status); +} + + +DAT_RETURN +dapls_ib_peek_cq ( + IN ib_cq_handle_t cq_handle, + OUT uint32_t* p_n_cqes) +{ + ib_api_status_t ib_status; + + ib_status = ib_peek_cq ( cq_handle, p_n_cqes ); + + return dapl_ib_status_convert (ib_status); +} + + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ + diff --git a/branches/WOF2-3/ulp/dapl2/dapl/ibal/dapl_ibal_dto.h b/branches/WOF2-3/ulp/dapl2/dapl/ibal/dapl_ibal_dto.h new file mode 100644 index 00000000..4694072c --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/ibal/dapl_ibal_dto.h @@ -0,0 +1,767 @@ + +/* + * 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. + */ + +/* + * Copyright (c) 2007 Intel Corporation. All rights reserved. + * Copyright (c) 2002, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under the terms of the "Common Public + * License" a copy of which is in the file LICENSE.txt in the root + * directory. The license is also available from the Open Source + * Initiative, see http://www.opensource.org/licenses/cpl.php. + * + */ + +/********************************************************************** + * + * MODULE: dapl_ibal_dto.h + * + * PURPOSE: Utility routines for data transfer operations using the + * IBAL APIs + * + * $Id: dapl_ibal_dto.h 33 2005-07-11 19:51:17Z ftillier $ + * + **********************************************************************/ + +#ifndef _DAPL_IBAL_DTO_H +#define _DAPL_IBAL_DTO_H + +#include "dapl_ibal_util.h" + +#ifdef DAT_EXTENSIONS +#include +#endif + +extern DAT_RETURN +dapls_ib_cq_late_alloc ( + IN ib_pd_handle_t pd_handle, + IN DAPL_EVD *evd_ptr); + +#define DAPL_DEFAULT_DS_ENTRIES 8 + +#ifdef NOT_SUPPORTED +extern DAT_RETURN +dapls_ib_post_recv_defered ( + IN DAPL_EP *ep_ptr, + IN DAPL_COOKIE *cookie, + IN DAT_COUNT num_segments, + IN DAT_LMR_TRIPLET *local_iov); // dapl_ibal_util.c +#endif + +static _INLINE_ char * dapls_dto_op_str(int dto); + +/* + * dapls_ib_post_recv + * + * Provider specific Post RECV function + */ +STATIC _INLINE_ DAT_RETURN +dapls_ib_post_recv ( + IN DAPL_EP *ep_ptr, + IN DAPL_COOKIE *cookie, + IN DAT_COUNT num_segments, + IN DAT_LMR_TRIPLET *local_iov) +{ + ib_api_status_t ib_status; + ib_recv_wr_t recv_wr, *failed_wr_p; + ib_local_ds_t ds_array[DAPL_DEFAULT_DS_ENTRIES], *ds_array_p; + DAT_COUNT i, total_len; + +#ifdef NOT_SUPPORTED + if (ep_ptr->qp_state == IB_QPS_INIT) + { + return dapls_ib_post_recv_defered ( ep_ptr, + cookie, + num_segments, + local_iov); + } +#endif + dapl_os_memzero(&recv_wr, sizeof(ib_recv_wr_t)); + recv_wr.wr_id = (DAT_UINT64) cookie; + recv_wr.num_ds = num_segments; + + if( num_segments <= DAPL_DEFAULT_DS_ENTRIES ) + { + ds_array_p = ds_array; + } + else + { + ds_array_p = dapl_os_alloc(num_segments*sizeof(ib_local_ds_t)); + } + recv_wr.ds_array = ds_array_p; + + if (NULL == ds_array_p) + { + return (DAT_INSUFFICIENT_RESOURCES); + } + + for (total_len = i = 0; i < num_segments; i++, ds_array_p++) + { + ds_array_p->length = (uint32_t)local_iov[i].segment_length; + ds_array_p->lkey = htonl(local_iov[i].lmr_context); + ds_array_p->vaddr = local_iov[i].virtual_address; + total_len += ds_array_p->length; + } + + if (cookie != NULL) + { + cookie->val.dto.size = total_len; + + dapl_dbg_log (DAPL_DBG_TYPE_EP, + "--> DsPR: EP = %p QP = %p cookie= %p, num_seg= %d\n", + ep_ptr, ep_ptr->qp_handle, cookie, num_segments); + } + + recv_wr.p_next = NULL; + + ib_status = ib_post_recv( ep_ptr->qp_handle, &recv_wr, &failed_wr_p ); + + if( num_segments > DAPL_DEFAULT_DS_ENTRIES ) + dapl_os_free( recv_wr.ds_array, num_segments * sizeof(ib_local_ds_t) ); + + if (IB_SUCCESS == ib_status) + { + return DAT_SUCCESS; + } + + dapl_dbg_log (DAPL_DBG_TYPE_EP, "--> DsPR: post_recv status %s\n", + ib_get_err_str(ib_status)); + /* + * Moving QP to error state; + */ + (void) dapls_modify_qp_state_to_error ( ep_ptr->qp_handle); + ep_ptr->qp_state = IB_QPS_ERROR; + + return (dapl_ib_status_convert (ib_status)); +} + + +/* + * dapls_ib_post_send + * + * Provider specific Post SEND function + */ +STATIC _INLINE_ DAT_RETURN +dapls_ib_post_send ( + IN DAPL_EP *ep_ptr, + IN ib_send_op_type_t op_type, + IN DAPL_COOKIE *cookie, + IN DAT_COUNT num_segments, + IN DAT_LMR_TRIPLET *local_iov, + IN const DAT_RMR_TRIPLET *remote_iov, + IN DAT_COMPLETION_FLAGS completion_flags) +{ + ib_api_status_t ib_status; + ib_send_wr_t send_wr, *failed_wr_p; + ib_local_ds_t ds_array[DAPL_DEFAULT_DS_ENTRIES], *ds_array_p; + DAT_COUNT i, total_len; + + if (ep_ptr->param.ep_state != DAT_EP_STATE_CONNECTED) + { + ib_qp_attr_t qp_attr; + + ib_query_qp ( ep_ptr->qp_handle, &qp_attr ); + + dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> DsPS: !CONN EP (%p) ep_state=%d " + "QP_state=%d\n", + ep_ptr, ep_ptr->param.ep_state, qp_attr.state ); + + return (DAT_ERROR(DAT_INVALID_STATE,DAT_INVALID_STATE_EP_DISCONNECTED)); + } + + dapl_os_memzero (&send_wr, sizeof(ib_send_wr_t)); + send_wr.wr_type = op_type; + send_wr.num_ds = num_segments; + + if( num_segments <= DAPL_DEFAULT_DS_ENTRIES ) + { + ds_array_p = ds_array; + } + else + { + ds_array_p = dapl_os_alloc( num_segments * sizeof(ib_local_ds_t) ); + } + send_wr.ds_array = ds_array_p; + + if (NULL == ds_array_p) + { + return (DAT_INSUFFICIENT_RESOURCES); + } + + total_len = 0; + + for (i = 0; i < num_segments; i++, ds_array_p++) + { + ds_array_p->length = (uint32_t)local_iov[i].segment_length; + ds_array_p->lkey = htonl(local_iov[i].lmr_context); + ds_array_p->vaddr = local_iov[i].virtual_address; + total_len += ds_array_p->length; + } + + if (cookie != NULL) + { + cookie->val.dto.size = total_len; + + dapl_dbg_log (DAPL_DBG_TYPE_EP, + "--> DsPS: EVD=%p EP=%p QP=%p type=%d, sg=%d " + "ln=%d, ck=%p 0x" F64x "\n", + ep_ptr->param.request_evd_handle, ep_ptr, ep_ptr->qp_handle, + op_type, num_segments, total_len, + cookie, cookie->val.dto.cookie.as_64 ); + } + + send_wr.wr_id = (DAT_UINT64)cookie; + + /* RC for now */ + if (total_len > 0) + { + send_wr.remote_ops.vaddr = remote_iov->virtual_address; + send_wr.remote_ops.rkey = htonl(remote_iov->rmr_context); + } + + send_wr.send_opt = 0; + + send_wr.send_opt |= (DAT_COMPLETION_BARRIER_FENCE_FLAG & + completion_flags) ? IB_SEND_OPT_FENCE : 0; + send_wr.send_opt |= (DAT_COMPLETION_SUPPRESS_FLAG & + completion_flags) ? 0 : IB_SEND_OPT_SIGNALED; + send_wr.send_opt |= (DAT_COMPLETION_SOLICITED_WAIT_FLAG & + completion_flags) ? IB_SEND_OPT_SOLICITED : 0; + + dapl_dbg_log (DAPL_DBG_TYPE_EP, "--> DsPS: EP=%p QP=%p send_opt=0x%x," + "rem_addr=%p, rem_rkey=0x%x completion_flags=0x%x\n", + ep_ptr, ep_ptr->qp_handle, + send_wr.send_opt, (void *)(uintptr_t)send_wr.remote_ops.vaddr, + send_wr.remote_ops.rkey, completion_flags); + + send_wr.p_next = NULL; + + ib_status = ib_post_send( ep_ptr->qp_handle, &send_wr, &failed_wr_p ); + + if( num_segments > DAPL_DEFAULT_DS_ENTRIES ) + dapl_os_free( send_wr.ds_array, num_segments * sizeof(ib_local_ds_t) ); + + if (IB_SUCCESS == ib_status) + return DAT_SUCCESS; + + dapl_dbg_log (DAPL_DBG_TYPE_EP, "--> DsPS: EP=%p post_send status = %s\n", + ep_ptr, ib_get_err_str(ib_status)); + /* + * Moving QP to error state; + */ + (void) dapls_modify_qp_state_to_error ( ep_ptr->qp_handle); + ep_ptr->qp_state = IB_QPS_ERROR; + + return (dapl_ib_status_convert (ib_status)); +} + +/* + * dapls_ib_optional_prv_dat + * + * Allocate space for private data to be used in CR calls + * + * Input: + * cr_ptr CR handle + * event_data data provided by the provider callback function + * cr_pp Pointer for private data + * + * Output: + * cr_pp Area + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * + */ +STATIC _INLINE_ DAT_RETURN +dapls_ib_optional_prv_dat ( + IN DAPL_CR *cr_ptr, + IN const void *event_data, + OUT DAPL_CR **cr_pp) +{ + DAT_RETURN dat_status = DAT_SUCCESS; + DAPL_PRIVATE *p_prv_data = (DAPL_PRIVATE *)event_data; + + if ( ! cr_ptr->param.private_data_size ) + { + cr_ptr->param.private_data_size = sizeof(cr_ptr->private_data); + cr_ptr->param.private_data = cr_ptr->private_data; + dapl_os_memcpy( cr_ptr->private_data, + p_prv_data->private_data, cr_ptr->param.private_data_size ); + *cr_pp = (DAPL_CR *)cr_ptr->param.private_data; + } + return dat_status; +} + + +STATIC _INLINE_ int +dapls_cqe_opcode_convert (ib_work_completion_t *cqe_p) +{ +#ifdef DAPL_DBG + int dop; + switch (((ib_work_completion_t *)cqe_p)->wc_type) + { + case IB_WC_SEND: + dop = (OP_SEND); + break; + + case IB_WC_RDMA_WRITE: + dop = (OP_RDMA_WRITE); + if (cqe_p->recv.conn.recv_opt & IB_RECV_OPT_IMMEDIATE) + dop = (OP_RDMA_WRITE_IMM); + break; + + case IB_WC_RECV: + case IB_WC_RECV_RDMA_WRITE: + dop = (OP_RECEIVE); + if (cqe_p->recv.conn.recv_opt & IB_RECV_OPT_IMMEDIATE) + dop = (OP_RECEIVE_IMM); + break; + + case IB_WC_RDMA_READ: + dop = (OP_RDMA_READ); + break; + + case IB_WC_MW_BIND: + dop = (OP_BIND_MW); + break; + + case IB_WC_FETCH_ADD: + dop = (OP_FETCH_AND_ADD); + break; + + case IB_WC_COMPARE_SWAP: + dop = (OP_COMP_AND_SWAP); + break; + + default : + /* error */ + dapl_dbg_log(DAPL_DBG_TYPE_ERR, "%s() Unknown IB_WC_TYPE %d?\n", + __FUNCTION__, cqe_p->wc_type); + dop = (OP_BAD_OPCODE); + break; + } +#if 0 + dapl_dbg_log(DAPL_DBG_TYPE_ERR, "--> DsCqeCvt %s --> %s\n", + ib_get_wc_type_str(cqe_p->wc_type), + dapls_dto_op_str(dop)); +#endif + return dop; + +#else /* ! DAPL_DBG */ + + switch (((ib_work_completion_t *)cqe_p)->wc_type) + { + case IB_WC_SEND: + return (OP_SEND); + + case IB_WC_RDMA_WRITE: + if (cqe_p->recv.conn.recv_opt & IB_RECV_OPT_IMMEDIATE) + return (OP_RDMA_WRITE_IMM); + return (OP_RDMA_WRITE); + + case IB_WC_RECV: + case IB_WC_RECV_RDMA_WRITE: + if (cqe_p->recv.conn.recv_opt & IB_RECV_OPT_IMMEDIATE) + return (OP_RECEIVE_IMM); + return (OP_RECEIVE); + + case IB_WC_RDMA_READ: + return (OP_RDMA_READ); + + case IB_WC_MW_BIND: + return (OP_BIND_MW); + + case IB_WC_FETCH_ADD: + return (OP_FETCH_AND_ADD); + + case IB_WC_COMPARE_SWAP: + return (OP_COMP_AND_SWAP); + + default : + /* error */ + return (IB_ERROR); + } +#endif +} + +STATIC _INLINE_ char * +dat_dtos_type_str(DAT_DTOS dto) +{ + static char err[20]; + char *ops[] = { + "DAT_DTO_SEND", + "DAT_DTO_RDMA_WRITE", + "DAT_DTO_RDMA_READ", + "DAT_DTO_RECEIVE", + "DAT_DTO_RECEIVE_WITH_INVALIDATE", + "DAT_DTO_BIND_MW", /* DAT 2.0, binds are reported via DTO events */ + "DAT_DTO_LMR_FMR", /* kdat specific */ + "DAT_DTO_LMR_INVALIDATE" /* kdat specific */ + }; + +#ifdef DAT_EXTENSIONS + /* "DAT_DTO_EXTENSION_BASE" used by DAT extensions as a starting point of + * extension DTOs. + */ + char *ext_ops[] = { + "DAT_IB_DTO_RDMA_WRITE_IMMED", + "DAT_IB_DTO_RECV_IMMED", + "DAT_IB_DTO_FETCH_ADD", + "DAT_IB_DTO_CMP_SWAP" + }; + + if (dto >= DAT_DTO_EXTENSION_BASE) + { + dto -= DAT_DTO_EXTENSION_BASE; + return ext_ops[dto]; + } +#endif + return ops[dto]; +} + +/* map Work Completions to DAT WR operations */ +STATIC _INLINE_ DAT_DTOS dapls_cqe_dtos_opcode(ib_work_completion_t *cqe_p) +{ +#ifdef DAPL_DBG + DAT_DTOS dto; + switch (cqe_p->wc_type) { + + case IB_WC_SEND: + dto = (DAT_DTO_SEND); + break; + + case IB_WC_MW_BIND: + dto = (DAT_DTO_BIND_MW); + break; + +#ifdef DAT_EXTENSIONS + case IB_WC_RDMA_WRITE: + dto = (DAT_DTO_RDMA_WRITE); + if (cqe_p->recv.conn.recv_opt & IB_RECV_OPT_IMMEDIATE) + dto = (DAT_IB_DTO_RDMA_WRITE_IMMED); + break; + + case IB_WC_COMPARE_SWAP: + dto = (DAT_IB_DTO_CMP_SWAP); + break; + + case IB_WC_FETCH_ADD: + dto = (DAT_IB_DTO_FETCH_ADD); + break; + + case IB_WC_RDMA_READ: + dto = (DAT_DTO_RDMA_READ); + break; + + case IB_WC_RECV: + case IB_WC_RECV_RDMA_WRITE: + dto = (DAT_DTO_RECEIVE); + if (cqe_p->recv.conn.recv_opt & IB_RECV_OPT_IMMEDIATE) + dto = (DAT_IB_DTO_RECV_IMMED); + break; +#else + case IB_WC_RDMA_READ: + dto = (DAT_DTO_RDMA_READ); + break; + + case IB_WC_RDMA_WRITE: + case IB_WC_RECV_RDMA_WRITE: + dto = (DAT_DTO_RDMA_WRITE); + break; + + case IB_WC_RECV: + dto = (DAT_DTO_RECEIVE); + break; +#endif + default: + dapl_dbg_log(DAPL_DBG_TYPE_ERR, "%s() Unknown IB_WC_TYPE %d?\n", + __FUNCTION__, cqe_p->wc_type); + dto = (0xff); + break; + } +#if 0 + dapl_dbg_log(DAPL_DBG_TYPE_ERR, "--> DsIBDTO %s --> %s\n", + ib_get_wc_type_str(cqe_p->wc_type), + dat_dtos_type_str(dto)); +#endif + return dto; + +#else /* !DAPL_DBG */ + + switch (cqe_p->wc_type) { + + case IB_WC_SEND: + return (DAT_DTO_SEND); + + case IB_WC_MW_BIND: + return (DAT_DTO_BIND_MW); + +#ifdef DAT_EXTENSIONS + case IB_WC_RDMA_WRITE: + if (cqe_p->recv.conn.recv_opt & IB_RECV_OPT_IMMEDIATE) + return (DAT_IB_DTO_RDMA_WRITE_IMMED); + else + return (DAT_DTO_RDMA_WRITE); + + case IB_WC_COMPARE_SWAP: + return (DAT_IB_DTO_CMP_SWAP); + + case IB_WC_FETCH_ADD: + return (DAT_IB_DTO_FETCH_ADD); + + case IB_WC_RDMA_READ: + return (DAT_DTO_RDMA_READ); + + case IB_WC_RECV: + case IB_WC_RECV_RDMA_WRITE: + if (cqe_p->recv.conn.recv_opt & IB_RECV_OPT_IMMEDIATE) + return (DAT_IB_DTO_RECV_IMMED); + else + return (DAT_DTO_RECEIVE); +#else + case IB_WC_RDMA_READ: + return (DAT_DTO_RDMA_READ); + + case IB_WC_RDMA_WRITE: + return (DAT_DTO_RDMA_WRITE); + + case IB_WC_RECV: + case IB_WC_RECV_RDMA_WRITE: + return (DAT_DTO_RECEIVE); +#endif + default: + return (0xff); + } +#endif +} + +#define DAPL_GET_CQE_DTOS_OPTYPE(cqe_p) dapls_cqe_dtos_opcode(cqe_p) + +#define DAPL_GET_CQE_WRID(cqe_p) ((ib_work_completion_t *)cqe_p)->wr_id +#define DAPL_GET_CQE_OPTYPE(cqe_p) dapls_cqe_opcode_convert(cqe_p) +#define DAPL_GET_CQE_BYTESNUM(cqe_p) ((ib_work_completion_t *)cqe_p)->length +#define DAPL_GET_CQE_STATUS(cqe_p) ((ib_work_completion_t *)cqe_p)->status +#define DAPL_GET_CQE_IMMED_DATA(cqe_p) \ + ((ib_work_completion_t*)cqe_p)->recv.conn.immediate_data + +static _INLINE_ char * +dapls_dto_op_str(int op) +{ + /* must match OP_SEND... defs in dapl_ibal_util.h */ + static char *optable[] = + { + "BAD OPcode", + "OP_SEND", + "OP_RDMA_WRITE", + "OP_RDMA_READ", + "OP_COMP_AND_SWAP", // 4 + "OP_FETCH_AND_ADD", // 5 + "OP_RECEIVE_RDMA_WRITE", + "PAD1", + "OP_RECEIVE", // (8) + "OP_BIND_MW", + "OP_RDMA_WRITE_IMM", + "OP_RECEIVE_IMM", + "OP_SEND_IMM" + }; + return ((op < 0 || op > 12) ? "Invalid DTO opcode?" : optable[op]); +} + +static _INLINE_ char * +dapls_cqe_op_str(IN ib_work_completion_t *cqe_ptr) +{ + return dapls_dto_op_str(DAPL_GET_CQE_OPTYPE (cqe_ptr)); +} + +#define DAPL_GET_CQE_OP_STR(cqe) dapls_cqe_op_str(cqe) + + +#ifdef DAT_EXTENSIONS +/* + * dapls_ib_post_ext_send + * + * Provider specific extended Post SEND function for atomics + * OP_COMP_AND_SWAP and OP_FETCH_AND_ADD + */ +STATIC _INLINE_ DAT_RETURN +dapls_ib_post_ext_send ( + IN DAPL_EP *ep_ptr, + IN ib_send_op_type_t op_type, + IN DAPL_COOKIE *cookie, + IN DAT_COUNT num_segs, + IN DAT_LMR_TRIPLET *local_iov, + IN const DAT_RMR_TRIPLET *remote_iov, + IN DAT_UINT32 immed_data, + IN DAT_UINT64 compare_add, + IN DAT_UINT64 swap, + IN DAT_COMPLETION_FLAGS completion_flags) +{ + ib_api_status_t ib_status; + ib_data_segment_t ds_array[DAPL_DEFAULT_DS_ENTRIES], *ds_array_p; + ib_send_wr_t wr, *bad_wr; + DAT_COUNT i, total_len; + + dapl_dbg_log(DAPL_DBG_TYPE_EP, + " post_ext_send: ep %p op %d ck %p numSegs %d\n" + " loc_iov %p rem_iov %p flgs %d\n", + ep_ptr, op_type, cookie, num_segs, local_iov, + remote_iov, completion_flags); + + if (num_segs <= DAPL_DEFAULT_DS_ENTRIES) + ds_array_p = ds_array; + else + ds_array_p = dapl_os_alloc(num_segs*sizeof(ib_data_segment_t)); + + if (NULL == ds_array_p) + { +#ifdef DAPL_DBG + dapl_dbg_log(DAPL_DBG_TYPE_ERR," %s() os_alloc(%d) failed?\n", + __FUNCTION__,(num_segs*sizeof(ib_data_segment_t))); +#endif + return (DAT_INSUFFICIENT_RESOURCES); + } + + /* setup the work request */ + dapl_os_memzero (&wr, sizeof(ib_send_wr_t)); + wr.wr_type = op_type; + wr.wr_id = (uint64_t)(uintptr_t)cookie; + wr.ds_array = ds_array_p; + + total_len = 0; + + for (i = 0; i < num_segs; i++ ) { + if ( !local_iov[i].segment_length ) + continue; + + ds_array_p->vaddr = (uint64_t) local_iov[i].virtual_address; + ds_array_p->length = local_iov[i].segment_length; + ds_array_p->lkey = htonl(local_iov[i].lmr_context); + + dapl_dbg_log(DAPL_DBG_TYPE_EP, + " post_snd: lkey 0x%x va %p len %d\n", + ds_array_p->lkey, ds_array_p->vaddr, + ds_array_p->length ); + + total_len += ds_array_p->length; + wr.num_ds++; + ds_array_p++; + } + + if (cookie != NULL) + cookie->val.dto.size = total_len; + + switch (op_type) { + + case OP_RDMA_WRITE_IMM: + wr.immediate_data = immed_data; + wr.send_opt |= IB_SEND_OPT_IMMEDIATE; + /* fall thru */ + case OP_RDMA_WRITE: + wr.wr_type = WR_RDMA_WRITE; +#if 1 // XXX + if ( immed_data == 0 ) { + dapl_dbg_log(DAPL_DBG_TYPE_EP, + "%s() immediate data == 0?\n",__FUNCTION__); + break; + } +#endif + dapl_dbg_log(DAPL_DBG_TYPE_EP, + " post_ext: OP_RDMA_WRITE_IMM rkey 0x%x va " + "%#016Lx immed=0x%x\n", + remote_iov->rmr_context, + remote_iov->virtual_address, immed_data); + + wr.remote_ops.vaddr = remote_iov->virtual_address; + wr.remote_ops.rkey = htonl(remote_iov->rmr_context); + break; + + case OP_COMP_AND_SWAP: + wr.wr_type = WR_COMPARE_SWAP; + dapl_dbg_log(DAPL_DBG_TYPE_ERR/*DAPL_DBG_TYPE_EP XXX*/, + " post_ext: OP_COMP_AND_SWAP=%llx,%llx rkey 0x%x " + "va %llx\n", + compare_add, swap, remote_iov->rmr_context, + remote_iov->virtual_address); + + wr.remote_ops.vaddr = remote_iov->virtual_address; + wr.remote_ops.rkey = htonl(remote_iov->rmr_context); + wr.remote_ops.atomic1 = compare_add; + wr.remote_ops.atomic2 = swap; + break; + + case OP_FETCH_AND_ADD: + wr.wr_type = WR_FETCH_ADD; + dapl_dbg_log(DAPL_DBG_TYPE_EP, + " post_ext: OP_FETCH_AND_ADD=%lx,%lx rkey 0x%x\n", + remote_iov->virtual_address, compare_add, + remote_iov->rmr_context); + + wr.remote_ops.vaddr = remote_iov->virtual_address; + wr.remote_ops.rkey = htonl(remote_iov->rmr_context); + wr.remote_ops.atomic1 = compare_add; + wr.remote_ops.atomic2 = 0; + break; + + default: + break; + } + + /* set completion flags in work request */ + wr.send_opt |= (DAT_COMPLETION_SUPPRESS_FLAG & + completion_flags) ? 0 : IB_SEND_OPT_SIGNALED; + wr.send_opt |= (DAT_COMPLETION_BARRIER_FENCE_FLAG & + completion_flags) ? IB_SEND_OPT_FENCE : 0; + wr.send_opt |= (DAT_COMPLETION_SOLICITED_WAIT_FLAG & + completion_flags) ? IB_SEND_OPT_SOLICITED : 0; + + dapl_dbg_log(DAPL_DBG_TYPE_EP, " post_snd1: wr_type 0x%x snd_opt 0x%x " + "ds_arry %llx num_ds %d\n", + wr.wr_type, wr.send_opt, wr.ds_array, wr.num_ds); + + ib_status = ib_post_send(ep_ptr->qp_handle, &wr, &bad_wr); + + if (num_segs > DAPL_DEFAULT_DS_ENTRIES) + dapl_os_free(wr.ds_array, num_segs * sizeof(ib_local_ds_t)); + + if ( ib_status == IB_SUCCESS ) + return DAT_SUCCESS; + + dapl_dbg_log (DAPL_DBG_TYPE_EP, + "--> DsPS: EP=%p post_send status = %s\n", + ep_ptr, ib_get_err_str(ib_status)); + /* + * Moving QP to error state; + */ + ib_status = dapls_modify_qp_state_to_error ( ep_ptr->qp_handle); + ep_ptr->qp_state = IB_QPS_ERROR; + + return (dapl_ib_status_convert (ib_status)); +} + +#endif /* DAT_EXTENSIONS */ + +#endif /* _DAPL_IBAL_DTO_H */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/ibal/dapl_ibal_extensions.c b/branches/WOF2-3/ulp/dapl2/dapl/ibal/dapl_ibal_extensions.c new file mode 100644 index 00000000..643125da --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/ibal/dapl_ibal_extensions.c @@ -0,0 +1,326 @@ +/* + * Copyright (c) 2007 Intel Corporation. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ibal_extensions.c + * + * PURPOSE: Extensions routines for OpenIB-windows IBAL provider + * + * $Id: $ + * + **********************************************************************/ + +#include "dapl.h" +#include "dapl_adapter_util.h" +#include "dapl_evd_util.h" +#include "dapl_ibal_util.h" +#include "dapl_ep_util.h" +#include "dapl_cookie.h" +#include + +DAT_RETURN +dapli_post_ext( IN DAT_EP_HANDLE ep_handle, + IN DAT_UINT64 cmp_add, + IN DAT_UINT64 swap, + IN DAT_UINT32 immed_data, + IN DAT_COUNT segments, + IN DAT_LMR_TRIPLET *local_iov, + IN DAT_DTO_COOKIE user_cookie, + IN const DAT_RMR_TRIPLET *remote_iov, + IN int op_type, + IN DAT_COMPLETION_FLAGS flags ); + + +/* + * dapl_extensions + * + * Process extension requests + * + * Input: + * ext_type, + * ... + * + * Output: + * Depends.... + * + * Returns: + * DAT_SUCCESS + * DAT_NOT_IMPLEMENTED + * ..... + * + */ +DAT_RETURN +dapl_extensions(IN DAT_HANDLE dat_handle, + IN DAT_EXTENDED_OP ext_op, + IN va_list args) +{ + DAT_EP_HANDLE ep; + DAT_LMR_TRIPLET *lmr_p; + DAT_DTO_COOKIE cookie; + const DAT_RMR_TRIPLET *rmr_p; + DAT_UINT64 dat_uint64a, dat_uint64b; + DAT_UINT32 dat_uint32; + DAT_COUNT segments = 1; + DAT_COMPLETION_FLAGS comp_flags; + DAT_RETURN status = DAT_NOT_IMPLEMENTED; + + dapl_dbg_log(DAPL_DBG_TYPE_API, + "dapl_extensions(hdl %p operation %d, ...)\n", + dat_handle, ext_op); + + switch ((int)ext_op) + { + + case DAT_IB_RDMA_WRITE_IMMED_OP: + dapl_dbg_log(DAPL_DBG_TYPE_RTN, + " WRITE_IMMED_DATA extension call\n"); + + ep = dat_handle; /* ep_handle */ + segments = va_arg( args, DAT_COUNT); /* num segments */ + lmr_p = va_arg( args, DAT_LMR_TRIPLET*); + cookie = va_arg( args, DAT_DTO_COOKIE); + rmr_p = va_arg( args, const DAT_RMR_TRIPLET*); + dat_uint32 = va_arg( args, DAT_UINT32); /* immed data */ + comp_flags = va_arg( args, DAT_COMPLETION_FLAGS); + + status = dapli_post_ext(ep, 0, 0, dat_uint32, segments, lmr_p, + cookie, rmr_p, OP_RDMA_WRITE_IMM, + comp_flags ); + break; + + case DAT_IB_CMP_AND_SWAP_OP: + dapl_dbg_log(DAPL_DBG_TYPE_RTN, + " CMP_AND_SWAP extension call\n"); + + ep = dat_handle; /* ep_handle */ + dat_uint64a = va_arg( args, DAT_UINT64); /* cmp_value */ + dat_uint64b = va_arg( args, DAT_UINT64); /* swap_value */ + lmr_p = va_arg( args, DAT_LMR_TRIPLET*); + cookie = va_arg( args, DAT_DTO_COOKIE); + rmr_p = va_arg( args, const DAT_RMR_TRIPLET*); + comp_flags = va_arg( args, DAT_COMPLETION_FLAGS); + + status = dapli_post_ext(ep, dat_uint64a, dat_uint64b, + 0, segments, lmr_p, cookie, rmr_p, + OP_COMP_AND_SWAP, comp_flags ); + break; + + case DAT_IB_FETCH_AND_ADD_OP: + dapl_dbg_log(DAPL_DBG_TYPE_RTN, + " FETCH_AND_ADD extension call\n"); + + ep = dat_handle; /* ep_handle */ + dat_uint64a = va_arg( args, DAT_UINT64); /* add value */ + lmr_p = va_arg( args, DAT_LMR_TRIPLET*); + cookie = va_arg( args, DAT_DTO_COOKIE); + rmr_p = va_arg( args, const DAT_RMR_TRIPLET*); + comp_flags = va_arg( args, DAT_COMPLETION_FLAGS); + + status = dapli_post_ext(ep, dat_uint64a, 0, 0, segments, + lmr_p, cookie, rmr_p, + OP_FETCH_AND_ADD, comp_flags ); + + break; + + default: + dapl_dbg_log(DAPL_DBG_TYPE_ERR, + "unsupported extension(%d)\n", (int)ext_op); + } + + return(status); +} + + +DAT_RETURN +dapli_post_ext( IN DAT_EP_HANDLE ep_handle, + IN DAT_UINT64 cmp_add, + IN DAT_UINT64 swap, + IN DAT_UINT32 immed_data, + IN DAT_COUNT segments, + IN DAT_LMR_TRIPLET *local_iov, + IN DAT_DTO_COOKIE user_cookie, + IN const DAT_RMR_TRIPLET *remote_iov, + IN int op_type, + IN DAT_COMPLETION_FLAGS flags ) +{ + DAPL_EP *ep_ptr; + ib_qp_handle_t qp_ptr; + DAPL_COOKIE *cookie; + DAT_RETURN dat_status = DAT_SUCCESS; + + dapl_dbg_log(DAPL_DBG_TYPE_API, + "--> post_ext_op: ep %p cmp_val %x swap_val %x cookie " + "0x%x\n r_iov %p, flags 0x%x op %d segs %d\n", + ep_handle, (unsigned)cmp_add, (unsigned)swap, + (unsigned)user_cookie.as_64, remote_iov, flags, op_type, + segments); + + if (DAPL_BAD_HANDLE(ep_handle, DAPL_MAGIC_EP)) + return(DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP)); + + if ((NULL == remote_iov) || (NULL == local_iov)) + return DAT_INVALID_PARAMETER; + + ep_ptr = (DAPL_EP *) ep_handle; + qp_ptr = ep_ptr->qp_handle; + + /* + * Synchronization ok since this buffer is only used for send + * requests, which aren't allowed to race with each other. + */ + dat_status = dapls_dto_cookie_alloc( + &ep_ptr->req_buffer, + DAPL_DTO_TYPE_EXTENSION, + user_cookie, + &cookie ); + + if ( dat_status != DAT_SUCCESS ) + { +#ifdef DAPL_DBG + dapl_dbg_log(DAPL_DBG_TYPE_ERR,"%s() cookie alloc faulure %x\n", + __FUNCTION__,dat_status); +#endif + goto bail; + } + + /* + * Invoke provider specific routine to post DTO + */ + dat_status = dapls_ib_post_ext_send(ep_ptr, + op_type, + cookie, + segments, /* data segments */ + local_iov, + remote_iov, + immed_data, /* immed data */ + cmp_add, /* compare or add */ + swap, /* swap */ + flags); + + if (dat_status != DAT_SUCCESS) + { + dapls_cookie_dealloc(&ep_ptr->req_buffer, cookie); +#ifdef DAPL_DBG + dapl_dbg_log(DAPL_DBG_TYPE_ERR, + "%s() post_ex_send err %d @ line %d\n", + __FUNCTION__,dat_status,__LINE__); +#endif + } + +bail: + return dat_status; + +} + + +/* + * New provider routine to process extended DTO events + */ +void +dapls_cqe_to_event_extension(IN DAPL_EP *ep_ptr, + IN DAPL_COOKIE *cookie, + IN ib_work_completion_t *cqe_ptr, + IN DAT_EVENT *event_ptr) +{ + uint32_t ibtype; + DAT_DTO_COMPLETION_EVENT_DATA *dto = + &event_ptr->event_data.dto_completion_event_data; + DAT_IB_EXTENSION_EVENT_DATA *ext_data = + (DAT_IB_EXTENSION_EVENT_DATA *) + &event_ptr->event_extension_data[0]; + DAT_DTO_COMPLETION_STATUS dto_status; + + /* Get status from cqe */ + dto_status = dapls_ib_get_dto_status(cqe_ptr); + + dapl_dbg_log(DAPL_DBG_TYPE_EVD, + " cqe_to_event_ext: dto_ptr %p ext_ptr %p status %d\n", + dto, ext_data, dto_status); + + event_ptr->event_number = DAT_IB_DTO_EVENT; + dto->ep_handle = cookie->ep; + dto->user_cookie = cookie->val.dto.cookie; + dto->operation = DAPL_GET_CQE_DTOS_OPTYPE(cqe_ptr); /* new for 2.0 */ + dto->status = ext_data->status = dto_status; + + if (dto_status != DAT_DTO_SUCCESS) + return; + + /* + * Get operation type from CQ work completion entry and + * if extented operation then set extended event data + */ + ibtype = DAPL_GET_CQE_OPTYPE(cqe_ptr); + + switch (ibtype) { + + case OP_RDMA_WRITE_IMM: + dapl_dbg_log (DAPL_DBG_TYPE_EVD, + " cqe_to_event_ext: OP_RDMA_WRITE_IMMED\n"); + + /* type and outbound rdma write transfer size */ + dto->transfered_length = cookie->val.dto.size; + ext_data->type = DAT_IB_RDMA_WRITE_IMMED; + break; + + case OP_RECEIVE_IMM: + dapl_dbg_log (DAPL_DBG_TYPE_EVD, + " cqe_to_event_ext: OP_RECEIVE_RDMA_IMMED\n"); + + /* immed recvd, type and inbound rdma write transfer size */ + dto->transfered_length = DAPL_GET_CQE_BYTESNUM(cqe_ptr); + ext_data->type = DAT_IB_RDMA_WRITE_IMMED_DATA; + ext_data->val.immed.data = DAPL_GET_CQE_IMMED_DATA(cqe_ptr); + break; + + case OP_COMP_AND_SWAP: + dapl_dbg_log (DAPL_DBG_TYPE_EVD, + " cqe_to_event_ext: COMP_AND_SWAP_RESP\n"); + + /* original data is returned in LMR provided with post */ + ext_data->type = DAT_IB_CMP_AND_SWAP; + dto->transfered_length = DAPL_GET_CQE_BYTESNUM(cqe_ptr); + break; + + case OP_FETCH_AND_ADD: + dapl_dbg_log (DAPL_DBG_TYPE_EVD, + " cqe_to_event_ext: FETCH_AND_ADD_RESP\n"); + + /* original data is returned in LMR provided with post */ + ext_data->type = DAT_IB_FETCH_AND_ADD; + dto->transfered_length = DAPL_GET_CQE_BYTESNUM(cqe_ptr); + break; + + default: + /* not extended operation */ + ext_data->status = DAT_IB_OP_ERR; + dto->status = DAT_DTO_ERR_TRANSPORT; + break; + } +} + diff --git a/branches/WOF2-3/ulp/dapl2/dapl/ibal/dapl_ibal_kmod.h b/branches/WOF2-3/ulp/dapl2/dapl/ibal/dapl_ibal_kmod.h new file mode 100644 index 00000000..dde89004 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/ibal/dapl_ibal_kmod.h @@ -0,0 +1,91 @@ + +/* + * Copyright (c) 2002, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under the terms of the "Common Public + * License" a copy of which is in the file LICENSE.txt in the root + * directory. The license is also available from the Open Source + * Initiative, see http://www.opensource.org/licenses/cpl.php. + * + */ + +/********************************************************************** + * + * MODULE: dapl_ibal_kmod.h + * + * PURPOSE: Utility defs & routines for access to Intel IBAL APIs + * + * $Id: dapl_ibal_kmod.h 33 2005-07-11 19:51:17Z ftillier $ + * + **********************************************************************/ + +#ifndef _DAPL_IBAL_KMOD_H_ +#define _DAPL_IBAL_KMOD_H_ + +#include +#include +#include + +#define MVDAPL_DEV_KEY 'm' +#define MVDAPL_GET_ANY_SVID _IO ( MVDAPL_DEV_KEY, psp_get_any_svid ) +#define MVDAPL_MRDB_RECORD_INSERT _IO ( MVDAPL_DEV_KEY, mrdb_record_insert ) +#define MVDAPL_MRDB_RECORD_DEC _IO ( MVDAPL_DEV_KEY, mrdb_record_dec ) +#define MVDAPL_MRDB_RECORD_QUERY _IO ( MVDAPL_DEV_KEY, mrdb_record_query ) +#define MVDAPL_MRDB_RECORD_UPDATE _IO ( MVDAPL_DEV_KEY, mrdb_record_update ) + +typedef enum +{ + psp_get_any_svid, + mrdb_record_insert, + mrdb_record_dec, + mrdb_record_query, + mrdb_record_update, + mvdapl_max_ops +} mvdapl_dev_ops_t; + +typedef struct _mvdapl_user_ctx +{ + cl_spinlock_t oust_mrdb_lock; + cl_qlist_t oust_mrdb_head; +} mvdapl_user_ctx_t; + + +typedef struct _mvdapl_ca_t +{ + cl_spinlock_t mrdb_lock; + cl_qlist_t mrdb_head; + boolean_t initialized; + cl_dev_handle_t mrdb_dev_handle; + ib_net64_t ca_guid; +} mvdapl_ca_t; + + +typedef struct _mvdapl_root +{ + ib_al_handle_t h_al; + intn_t guid_count; + mvdapl_ca_t *mvdapl_ca_tbl; + +} mvdapl_root_t; + +typedef struct _mrdb_record_t +{ + cl_list_item_t next; + ib_lmr_cookie_t key_cookie; + void *mr_handle; + int ib_shmid; + uint32_t ref_count; + boolean_t initialized; + cl_spinlock_t record_lock; +} mrdb_record_t; + + +typedef struct _oust_mrdb_rec +{ + cl_list_item_t next; + mrdb_record_t *p_record; + uint32_t ref_count; +} oust_mrdb_rec_t; + + +#endif /* _DAPL_IBAL_KMOD_H_ */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/ibal/dapl_ibal_mrdb.c b/branches/WOF2-3/ulp/dapl2/dapl/ibal/dapl_ibal_mrdb.c new file mode 100644 index 00000000..68fcf45a --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/ibal/dapl_ibal_mrdb.c @@ -0,0 +1,392 @@ + +/* + * Copyright (c) 2002, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under the terms of the "Common Public + * License" a copy of which is in the file LICENSE.txt in the root + * directory. The license is also available from the Open Source + * Initiative, see http://www.opensource.org/licenses/cpl.php. + * + */ + +/********************************************************************** + * + * MODULE: dapl_ibal_mrdb.c + * + * PURPOSE: Utility routines for access to IBAL APIs + * + * $Id: dapl_ibal_mrdb.c 33 2005-07-11 19:51:17Z ftillier $ + * + **********************************************************************/ + +#include "dapl.h" +#include "dapl_adapter_util.h" +#include "dapl_ibal_kmod.h" +#include "dapl_ibal_mrdb.h" + +DAT_RETURN dapls_mrdb_init ( + IN DAPL_HCA *hca_ptr) +{ + cl_status_t cl_status; + char name[32]; + dapl_ibal_ca_t *p_ca; + + p_ca = (dapl_ibal_ca_t *) hca_ptr->ib_hca_handle; + + if (p_ca == NULL) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> %s: p_ca is NULL\n","DsMI"); + return DAT_INVALID_PARAMETER; + } + + sprintf (name, + "/dev/mvdapl%x", + (uint32_t) cl_ntoh64 (p_ca->p_ca_attr->ca_guid)); + + cl_status = cl_open_device ( (cl_dev_name_t) name, &p_ca->mlnx_device); + + if (cl_status != CL_SUCCESS) + { + /* dapl_dbg_log ( DAPL_DBG_TYPE_UTIL, + "--> DsMI: Init MRDB failed = 0x%x\n", cl_status); */ + p_ca->mlnx_device = 0; + } + + return DAT_SUCCESS; +} + + +DAT_RETURN dapls_mrdb_exit ( + IN DAPL_HCA *hca_ptr) +{ + dapl_ibal_ca_t *p_ca; + + p_ca = (dapl_ibal_ca_t *) hca_ptr->ib_hca_handle; + + if (p_ca == NULL) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> %s: p_ca is NULL\n","DsME"); + return DAT_INVALID_PARAMETER; + } + + if (p_ca->mlnx_device) + { + cl_close_device (p_ca->mlnx_device); + } + + return DAT_SUCCESS; +} + + +DAT_RETURN dapls_mrdb_record_insert ( + IN DAPL_HCA *hca_ptr, + IN DAT_LMR_COOKIE shared_mem_id, + OUT int *p_ib_shmid) +{ + cl_status_t cl_status; + mrdb_rec_insert_ioctl_t ioctl_buf; + uintn_t bytes_ret; + dapl_ibal_ca_t *p_ca; + + p_ca = (dapl_ibal_ca_t *) hca_ptr->ib_hca_handle; + + if (p_ca == NULL) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> %s: p_ca is NULL\n","DsMRI"); + return DAT_INVALID_PARAMETER; + } + + bytes_ret = 0; + cl_memclr (&ioctl_buf, sizeof (ioctl_buf)); + cl_memcpy (ioctl_buf.shared_mem_id, shared_mem_id, IBAL_LMR_COOKIE_SIZE); + + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "--> DsMRI: MVDAPL_MRDB_REC_INSERT mem_cookie %p\n", + shared_mem_id); +#if defined(DAPL_DBG) + { + int i; + char *c = (char *) shared_mem_id; + + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "--> DsMRI: mem_cookie: \n"); + + for ( i = 0; i < IBAL_LMR_COOKIE_SIZE ; i++) + { + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "0x%x ", *(c+i)); + } + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, "\n"); + + } +#endif /* DAPL_DBG */ + + cl_status = cl_ioctl_device ( p_ca->mlnx_device, + MVDAPL_MRDB_RECORD_INSERT, + &ioctl_buf, + sizeof (mrdb_rec_insert_ioctl_t), + &bytes_ret); + if ((cl_status != CL_SUCCESS) || + (ioctl_buf.status == IB_INSUFFICIENT_MEMORY)) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> DsMRI: Failed to IOCTL record_insert 0x%x\n", cl_status); + return DAT_INSUFFICIENT_RESOURCES; + } + + *p_ib_shmid = (int) ioctl_buf.inout_f; + + if (ioctl_buf.status == IB_ERROR) + { + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "--> DsMRI: There is a record with shmid 0x%x\n", + *p_ib_shmid); + return DAT_INVALID_STATE; + } + else + { + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "--> DsMRI: Insert new mrdb record with shmid 0x%x\n", + *p_ib_shmid); + } + + return DAT_SUCCESS; +} + +DAT_RETURN dapls_mrdb_record_dec ( + IN DAPL_HCA *hca_ptr, + IN DAT_LMR_COOKIE shared_mem_id) +{ + cl_status_t cl_status; + mrdb_rec_dec_ioctl_t ioctl_buf; + uintn_t bytes_ret; + dapl_ibal_ca_t *p_ca; + + p_ca = (dapl_ibal_ca_t *) hca_ptr->ib_hca_handle; + + if (p_ca == NULL) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> %s: p_ca is NULL\n","DsMRD"); + return DAT_INVALID_PARAMETER; + } + + bytes_ret = 0; + cl_memclr (&ioctl_buf, sizeof (ioctl_buf)); + cl_memcpy (ioctl_buf.shared_mem_id, shared_mem_id, IBAL_LMR_COOKIE_SIZE); + + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "--> DsMRD: MVDAPL_MRDB_REC_DEC mem_cookie 0x%p\n", + shared_mem_id); +#if defined(DAPL_DBG) + { + int i; + char *c = (char *) shared_mem_id; + + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "--> DsMRD: mem_cookie: \n"); + + for ( i = 0; i < IBAL_LMR_COOKIE_SIZE ; i++) + { + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "0x%x ", *(c+i)); + } + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, "\n"); + + } +#endif /* DAPL_DBG */ + + cl_status = cl_ioctl_device ( p_ca->mlnx_device, + MVDAPL_MRDB_RECORD_DEC, + &ioctl_buf, + sizeof (mrdb_rec_dec_ioctl_t), + &bytes_ret); + if ((cl_status != CL_SUCCESS) || + (ioctl_buf.status != IB_SUCCESS)) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> DsMRD: IOCTL failed 'cause there is no record %s\n", + ib_get_err_str(ioctl_buf.status)); + return DAT_INVALID_STATE; + } + + return DAT_SUCCESS; +} + +DAT_RETURN dapls_mrdb_record_update ( + IN DAPL_HCA *hca_ptr, + IN DAT_LMR_COOKIE shared_mem_id, + IN ib_mr_handle_t mr_handle) +{ + cl_status_t cl_status; + mrdb_rec_update_ioctl_t ioctl_buf; + uintn_t bytes_ret; + dapl_ibal_ca_t *p_ca; + + p_ca = (dapl_ibal_ca_t *) hca_ptr->ib_hca_handle; + + if (p_ca == NULL) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> %s: p_ca is NULL\n","DsMRU"); + return DAT_INVALID_PARAMETER; + } + + bytes_ret = 0; + cl_memclr (&ioctl_buf, sizeof (ioctl_buf)); + cl_memcpy (ioctl_buf.shared_mem_id, shared_mem_id, IBAL_LMR_COOKIE_SIZE); + ioctl_buf.mr_handle = mr_handle; + + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "--> DsMRU: MVDAPL_MRDB_REC_UPDATE mr_handle %p\n", mr_handle); +#if defined(DAPL_DBG) + { + int i; + char *c = (char *) shared_mem_id; + + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "--> DsMRU: mem_cookie: \n"); + + for ( i = 0; i < IBAL_LMR_COOKIE_SIZE ; i++) + { + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "0x%x ", *(c+i)); + } + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, "\n"); + + } +#endif /* DAPL_DBG */ + + cl_status = cl_ioctl_device ( p_ca->mlnx_device, + MVDAPL_MRDB_RECORD_UPDATE, + &ioctl_buf, + sizeof (mrdb_rec_update_ioctl_t), + &bytes_ret); + if ((cl_status != CL_SUCCESS) || + (ioctl_buf.status != IB_SUCCESS)) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> DsMRU: IOCTL update_record failed %s\n", + ib_get_err_str(ioctl_buf.status)); + return DAT_INTERNAL_ERROR; + } + + return DAT_SUCCESS; +} + + +DAT_RETURN dapls_mrdb_record_query ( + IN DAPL_HCA *hca_ptr, + IN DAT_LMR_COOKIE shared_mem_id, + OUT int *p_ib_shmid, + OUT ib_mr_handle_t *p_mr_handle) +{ + cl_status_t cl_status; + mrdb_rec_query_ioctl_t ioctl_buf; + uintn_t bytes_ret; + dapl_ibal_ca_t *p_ca; + + p_ca = (dapl_ibal_ca_t *) hca_ptr->ib_hca_handle; + + if (p_ca == NULL) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> %s: p_ca is NULL\n","DsMRQ"); + return DAT_INVALID_PARAMETER; + } + + bytes_ret = 0; + cl_memclr (&ioctl_buf, sizeof (ioctl_buf)); + + cl_memcpy (ioctl_buf.shared_mem_id, shared_mem_id, IBAL_LMR_COOKIE_SIZE); + + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "--> DsMRQ: MVDAPL_MRDB_REC_QUERY mem_cookie 0x%p\n", + shared_mem_id); + #if defined(DAPL_DBG) + { + int i; + char *c = (char *) shared_mem_id; + + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "--> DsMRQ: mem_cookie: \n"); + + for ( i = 0; i < IBAL_LMR_COOKIE_SIZE ; i++) + { + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "0x%x ", *(c+i)); + } + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, "\n"); + + } + #endif + + cl_status = cl_ioctl_device ( p_ca->mlnx_device, + MVDAPL_MRDB_RECORD_QUERY, + &ioctl_buf, + sizeof (mrdb_rec_query_ioctl_t), + &bytes_ret); + if ((cl_status != CL_SUCCESS) || + (ioctl_buf.status != IB_SUCCESS)) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> DsMRQ: IOCTL query_record failed %s\n", + ib_get_err_str(ioctl_buf.status)); + return DAT_INTERNAL_ERROR; + } + + *p_mr_handle = ioctl_buf.mr_handle; + *p_ib_shmid = (int) ioctl_buf.inout_f; + + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "--> DsMRQ: MVDAPL_MRDB_REC_QUERY mr_handle 0x%p shmid 0x%x\n", + *p_mr_handle, *p_ib_shmid); + + return DAT_SUCCESS; +} + + +DAT_RETURN dapls_ib_get_any_svid ( + IN DAPL_HCA *hca_ptr, + OUT DAT_CONN_QUAL *p_svid) +{ + cl_status_t cl_status; + psp_get_any_svid_ioctl_t ioctl_buf; + uintn_t bytes_ret; + dapl_ibal_ca_t *p_ca; + + p_ca = (dapl_ibal_ca_t *) hca_ptr->ib_hca_handle; + + if (p_ca == NULL) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> %s: p_ca is NULL\n","DsPGAS"); + return DAT_INVALID_PARAMETER; + } + + bytes_ret = 0; + cl_memclr (&ioctl_buf, sizeof (ioctl_buf)); + + cl_status = cl_ioctl_device ( p_ca->mlnx_device, + MVDAPL_GET_ANY_SVID, + &ioctl_buf, + sizeof (psp_get_any_svid_ioctl_t), + &bytes_ret); + if ((cl_status != CL_SUCCESS) || + (ioctl_buf.status != IB_SUCCESS)) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> DsMRQ: IOCTL query_record failed %s\n", + ib_get_err_str(ioctl_buf.status)); + return DAT_INTERNAL_ERROR; + } + + *p_svid = (DAT_CONN_QUAL) ioctl_buf.inout_f; + + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "--> DsPGAS: new ServiceID 0x%x\n", + *p_svid); + + return DAT_SUCCESS; +} + + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ + diff --git a/branches/WOF2-3/ulp/dapl2/dapl/ibal/dapl_ibal_mrdb.h b/branches/WOF2-3/ulp/dapl2/dapl/ibal/dapl_ibal_mrdb.h new file mode 100644 index 00000000..f07e6d24 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/ibal/dapl_ibal_mrdb.h @@ -0,0 +1,52 @@ + +/* + * Copyright (c) 2002, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under the terms of the "Common Public + * License" a copy of which is in the file LICENSE.txt in the root + * directory. The license is also available from the Open Source + * Initiative, see http://www.opensource.org/licenses/cpl.php. + * + */ + +/********************************************************************** + * + * MODULE: dapl_ibal_mrdb.h + * + * PURPOSE: Utility defs & routines for access to Intel IBAL APIs + * + * $Id: dapl_ibal_mrdb.h 33 2005-07-11 19:51:17Z ftillier $ + * + **********************************************************************/ + +#ifndef _DAPL_IBAL_MRDB_H_ +#define _DAPL_IBAL_MRDB_H_ + +#include +#include + +#define MVDAPL_BASE_SHMID 0xF00 +#define MVDAPL_BASE_SVID 0xF +#define MVDAPL_MAX_SHMID 0xFFFFFFFF +#define MVDAPL_MAX_SVID 0xEFFFFFFF + +#define IBAL_LMR_COOKIE_SIZE 40 +typedef char (* ib_lmr_cookie_t)[IBAL_LMR_COOKIE_SIZE]; + +typedef struct _mrdb_record_ioctl +{ + char *shared_mem_id[IBAL_LMR_COOKIE_SIZE]; + void *mr_handle; + ib_net64_t inout_f; + ib_api_status_t status; +} mrdb_record_ioctl_t; + +typedef mrdb_record_ioctl_t mrdb_rec_dec_ioctl_t; +typedef mrdb_record_ioctl_t mrdb_rec_insert_ioctl_t; +typedef mrdb_record_ioctl_t mrdb_rec_query_ioctl_t; +typedef mrdb_record_ioctl_t mrdb_rec_update_ioctl_t; +typedef mrdb_record_ioctl_t psp_get_any_svid_ioctl_t; + + +#endif /* _DAPL_IBAL_MRDB_H_ */ + diff --git a/branches/WOF2-3/ulp/dapl2/dapl/ibal/dapl_ibal_name_service.c b/branches/WOF2-3/ulp/dapl2/dapl/ibal/dapl_ibal_name_service.c new file mode 100644 index 00000000..ac99856f --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/ibal/dapl_ibal_name_service.c @@ -0,0 +1,564 @@ +/* + * Copyright (c) 2007-2008 Intel Corporation. All rights reserved. + * Copyright (c) 2002, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under the terms of the "Common Public + * License" a copy of which is in the file LICENSE.txt in the root + * directory. The license is also available from the Open Source + * Initiative, see http://www.opensource.org/licenses/cpl.php. + * + */ + +/********************************************************************** + * + * MODULE: dapl_ibal_name_service.c + * + * PURPOSE: IP Name service + * + * $Id$ + * + **********************************************************************/ + +#include "dapl.h" +#include "dapl_adapter_util.h" +#include "dapl_evd_util.h" +#include "dapl_cr_util.h" +#include "dapl_sp_util.h" +#include "dapl_ep_util.h" +#include "dapl_ia_util.h" +#include "dapl_ibal_util.h" +#include "dapl_name_service.h" + +#define IB_INFINITE_SERVICE_LEASE 0xFFFFFFFF +#define DAPL_ATS_SERVICE_ID ATS_SERVICE_ID //0x10000CE100415453 +#define DAPL_ATS_NAME ATS_NAME +#define HCA_IPV6_ADDRESS_LENGTH 16 + +extern dapl_ibal_root_t dapl_ibal_root; + + +char * +dapli_get_ip_addr_str(DAT_SOCK_ADDR6 *ipa, char *buf) +{ + int rval; + static char lbuf[24]; + char *str = (buf ? buf : lbuf); + + rval = ((struct sockaddr_in *)ipa)->sin_addr.s_addr; + + sprintf(str, "%d.%d.%d.%d", + (rval >> 0) & 0xff, + (rval >> 8) & 0xff, + (rval >> 16) & 0xff, + (rval >> 24) & 0xff); + return str; +} + + + +void AL_API +dapli_ib_sa_query_cb (IN ib_query_rec_t *p_query_rec ) +{ + ib_api_status_t ib_status; + + if (IB_SUCCESS != p_query_rec->status) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR,"%s: SA query callback failed %s\n", + __FUNCTION__, ib_get_err_str(p_query_rec->status)); + return; + } + + if (!p_query_rec->p_result_mad) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "%s: SA query callback [no mad] @line %d\n", + __FUNCTION__, __LINE__); + return; + } + + switch (p_query_rec->query_type) + { + case IB_QUERY_PATH_REC_BY_GIDS: + { + ib_path_rec_t *p_path_rec; + + p_path_rec = ib_get_query_path_rec (p_query_rec->p_result_mad, 0); + if (p_path_rec) + { + dapl_os_memcpy ((void * __ptr64) p_query_rec->query_context, + (void *) p_path_rec, + sizeof (ib_path_rec_t)); + dapl_dbg_log ( + DAPL_DBG_TYPE_CM | DAPL_DBG_TYPE_CALLBACK, + "sa_query_cb: path {slid: 0x%x, dlid: 0x%x}\n", + p_path_rec->slid, p_path_rec->dlid); + } + else + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR,"%s: return NULL? @line %d\n", + __FUNCTION__, __LINE__); + return; + } + break; + } + + case IB_QUERY_SVC_REC_BY_ID: + { + ib_service_record_t *p_svc_rec; + + p_svc_rec = ib_get_query_svc_rec (p_query_rec->p_result_mad, 0); + if (p_svc_rec) + { + dapl_os_memcpy ((void * __ptr64) p_query_rec->query_context, + (void *) p_svc_rec, + sizeof (ib_service_record_t)); + dapl_dbg_log ( + DAPL_DBG_TYPE_CM | DAPL_DBG_TYPE_CALLBACK, + "%s: SER{0x%I64x, 0x%I64x}\n", __FUNCTION__, + cl_hton64 (p_svc_rec->service_gid.unicast.prefix), + cl_hton64 (p_svc_rec->service_gid.unicast.interface_id)); + } + else + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR,"%s: return NULL? @line %d\n", + __FUNCTION__, __LINE__); + return; + } + break; + + } + + case IB_QUERY_USER_DEFINED: + { + ib_user_query_t *p_user_query; + + p_user_query=(ib_user_query_t * __ptr64) p_query_rec->query_context; + + if (p_user_query) + { + switch (p_user_query->attr_id) + { + case IB_MAD_ATTR_SERVICE_RECORD: + { + ib_service_record_t *p_svc_rec; + + p_svc_rec = ib_get_query_svc_rec ( + p_query_rec->p_result_mad, 0); + if (p_svc_rec) + { + dapl_os_memcpy ((void *) p_user_query->p_attr, + (void *) p_svc_rec, + sizeof (ib_service_record_t)); + dapl_dbg_log ( + DAPL_DBG_TYPE_CM | DAPL_DBG_TYPE_CALLBACK, + "%s: GID{0x" F64x ", 0x" F64x "} record count %d\n", + __FUNCTION__, + cl_hton64(p_svc_rec->service_gid.unicast.prefix), + cl_hton64(p_svc_rec->service_gid.unicast.interface_id), + p_query_rec->result_cnt); + } + else + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "%s: return NULL? @line %d\n", + __FUNCTION__, __LINE__); + return; + } + break; + + } + default: + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "%s: USER_DEFINED %d\n", + p_user_query->attr_id ); + break; + } + } + } + else + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR,"%s: return NULL? @line %d\n", + __FUNCTION__, __LINE__); + return; + } + break; + } + + default: + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR,"%s: unsupportedTYPE %d\n", + __FUNCTION__, p_query_rec->query_type); + break; + } + + } + + if ((ib_status = ib_put_mad (p_query_rec->p_result_mad)) != IB_SUCCESS) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR,"%s: can not free MAD %s\n", + __FUNCTION__, ib_get_err_str(ib_status)); + } +} + + +#ifndef NO_NAME_SERVICE + +DAT_RETURN +dapls_ib_ns_map_gid ( + IN DAPL_HCA *hca_ptr, + IN DAT_IA_ADDRESS_PTR p_ia_address, + OUT GID *p_gid) +{ + ib_user_query_t user_query; + dapl_ibal_ca_t *p_ca; + dapl_ibal_port_t *p_active_port; + ib_service_record_t service_rec; + ib_api_status_t ib_status; + ib_query_req_t query_req; + DAT_SOCK_ADDR6 ipv6_addr; + + p_ca = (dapl_ibal_ca_t *) hca_ptr->ib_hca_handle; + + if (NULL == p_ca) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "--> DsNMG: There is no HCA = %d\n", __LINE__); + return (DAT_INVALID_HANDLE); + } + + /* + * We are using the first active port in the list for + * communication. We have to get back here when we decide to support + * fail-over and high-availability. + */ + p_active_port = dapli_ibal_get_port ( p_ca, (uint8_t)hca_ptr->port_num ); + + if (NULL == p_active_port) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "--> DsNMG: Port %d is not available = %d\n", + hca_ptr->port_num, __LINE__); + return (DAT_INVALID_STATE); + } + + if (p_active_port->p_attr->lid == 0) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, "--> DsNMG: Port %d has no LID " + "assigned; can not operate\n", + p_active_port->p_attr->port_num); + return (DAT_INVALID_STATE); + } + + if (!dapl_os_memcmp (p_ia_address, + &hca_ptr->hca_address, + HCA_IPV6_ADDRESS_LENGTH)) + { + /* We are operating in the LOOPBACK mode */ + p_gid->guid =p_active_port->p_attr->p_gid_table[0].unicast.interface_id; + p_gid->gid_prefix =p_active_port->p_attr->p_gid_table[0].unicast.prefix; + return DAT_SUCCESS; + } + + if (p_active_port->p_attr->link_state != IB_LINK_ACTIVE) + { + /* + * Port is DOWN; can not send or recv messages + */ + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "--> DsNMG: Port %d is DOWN; can not send to fabric\n", + p_active_port->p_attr->port_num); + return (DAT_INVALID_STATE); + } + + dapl_os_memzero (&user_query, sizeof (ib_user_query_t)); + dapl_os_memzero (&service_rec, sizeof (ib_service_record_t)); + dapl_os_memzero (&query_req, sizeof (ib_query_req_t)); + dapl_os_memzero (&ipv6_addr, sizeof (DAT_SOCK_ADDR6)); + + if (p_ia_address->sa_family == AF_INET) + { + dapl_os_memcpy (&ipv6_addr.sin6_addr.s6_addr[12], + &((struct sockaddr_in *)p_ia_address)->sin_addr.s_addr, + 4); +#if defined(DAPL_DBG) || 1 // XXX + { + char ipa[20]; + + dapl_dbg_log (DAPL_DBG_TYPE_CM, "--> DsNMG: Remote ia_address %s\n", + dapli_get_ip_addr_str( + (DAT_SOCK_ADDR6*)p_ia_address, ipa)); + } +#endif + + } + else + { + /* + * Assume IPv6 address + */ + dapl_os_assert (p_ia_address->sa_family == AF_INET6); + dapl_os_memcpy (ipv6_addr.sin6_addr.s6_addr, + ((DAT_SOCK_ADDR6 *)p_ia_address)->sin6_addr.s6_addr, + HCA_IPV6_ADDRESS_LENGTH); +#if defined(DAPL_DBG) || 1 // XXX + { + int i; + uint8_t *tmp = ipv6_addr.sin6_addr.s6_addr; + + dapl_dbg_log ( DAPL_DBG_TYPE_CM, + "--> DsNMG: Remote ia_address - "); + + for ( i = 1; i < HCA_IPV6_ADDRESS_LENGTH; i++) + { + dapl_dbg_log ( DAPL_DBG_TYPE_CM, "%x:", + tmp[i-1] ); + } + dapl_dbg_log ( DAPL_DBG_TYPE_CM, "%x\n", + tmp[i-1] ); + } +#endif + + } + + /* + * query SA for GID + */ + //service_rec.service_id = CL_HTON64 (DAPL_ATS_SERVICE_ID); + dapl_os_memcpy ( service_rec.service_name, + ATS_NAME, + __min(sizeof(ATS_NAME),sizeof(ib_svc_name_t)) ); + dapl_os_memcpy (&service_rec.service_data8[0], + ipv6_addr.sin6_addr.s6_addr, + HCA_IPV6_ADDRESS_LENGTH); + service_rec.service_lease = IB_INFINITE_SERVICE_LEASE; + service_rec.service_pkey = IB_DEFAULT_PKEY; + + user_query.method = IB_MAD_METHOD_GETTABLE; + user_query.attr_id = IB_MAD_ATTR_SERVICE_RECORD; + user_query.comp_mask = IB_SR_COMPMASK_SPKEY | + IB_SR_COMPMASK_SLEASE | + IB_SR_COMPMASK_SNAME | + IB_SR_COMPMASK_SDATA8_0 | + IB_SR_COMPMASK_SDATA8_1 | + IB_SR_COMPMASK_SDATA8_2 | + IB_SR_COMPMASK_SDATA8_3 | + IB_SR_COMPMASK_SDATA8_4 | + IB_SR_COMPMASK_SDATA8_5 | + IB_SR_COMPMASK_SDATA8_6 | + IB_SR_COMPMASK_SDATA8_7 | + IB_SR_COMPMASK_SDATA8_8 | + IB_SR_COMPMASK_SDATA8_9 | + IB_SR_COMPMASK_SDATA8_10 | + IB_SR_COMPMASK_SDATA8_11 | + IB_SR_COMPMASK_SDATA8_12 | + IB_SR_COMPMASK_SDATA8_13 | + IB_SR_COMPMASK_SDATA8_14 | + IB_SR_COMPMASK_SDATA8_15; + + user_query.attr_size = sizeof (ib_service_record_t); + user_query.p_attr = (void *)&service_rec; + + query_req.query_type = IB_QUERY_USER_DEFINED; + query_req.p_query_input = (void *)&user_query; + query_req.flags = IB_FLAGS_SYNC; /* this is a blocking call */ + query_req.timeout_ms = 1 * 1000; /* 1 second */ + query_req.retry_cnt = 5; + /* query SA using this port */ + query_req.port_guid = p_active_port->p_attr->port_guid; + query_req.query_context = (void *) &user_query; + query_req.pfn_query_cb = dapli_ib_sa_query_cb; + + ib_status = ib_query (dapl_ibal_root.h_al, &query_req, NULL); + + if (ib_status != IB_SUCCESS) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR,"ns_map_gid: status %s @line = %d\n", + ib_get_err_str(ib_status), __LINE__); + return (dapl_ib_status_convert (ib_status)); + } + else if (service_rec.service_gid.unicast.interface_id == 0) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "--> %s: query SA found no record\n",__FUNCTION__); + return DAT_INVALID_PARAMETER; + } + + /* + * return the GID + */ + p_gid->guid = service_rec.service_gid.unicast.interface_id; + p_gid->gid_prefix = service_rec.service_gid.unicast.prefix; + + return DAT_SUCCESS; +} + + + +DAT_RETURN +dapls_ib_ns_map_ipaddr ( + IN DAPL_HCA *hca_ptr, + IN GID gid, + OUT DAT_IA_ADDRESS_PTR p_ia_address) +{ + ib_user_query_t user_query; + dapl_ibal_ca_t *p_ca; + dapl_ibal_port_t *p_active_port; + ib_service_record_t service_rec; + ib_api_status_t ib_status; + ib_query_req_t query_req; + + p_ca = (dapl_ibal_ca_t *) hca_ptr->ib_hca_handle; + + if (NULL == p_ca) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "--> DsNMI: There is no HCA = %d\n", __LINE__); + return (DAT_INVALID_HANDLE); + } + + /* + * We are using the first active port in the list for + * communication. We have to get back here when we decide to support + * fail-over and high-availability. + */ + p_active_port = dapli_ibal_get_port ( p_ca, (uint8_t)hca_ptr->port_num ); + + if (NULL == p_active_port) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "--> DsNMI: Port %d is not available = %d\n", + hca_ptr->port_num, __LINE__); + return (DAT_INVALID_STATE); + } + + if (p_active_port->p_attr->lid == 0) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, "--> DsNMI: Port %d has no LID " + "assigned; can not operate\n", + p_active_port->p_attr->port_num); + return (DAT_INVALID_STATE); + } + /*else + { + // + // We are operating in the LOOPBACK mode + // + if ((gid.gid_prefix == + p_active_port->p_attr->p_gid_table[0].unicast.prefix) && + (gid.guid == + p_active_port->p_attr->p_gid_table[0].unicast.interface_id)) + { + dapl_os_memcpy (((DAT_SOCK_ADDR6 *)p_ia_address)->sin6_addr.s6_addr, + hca_ptr->hca_address.sin6_addr.s6_addr, + HCA_IPV6_ADDRESS_LENGTH); + return DAT_SUCCESS; + } + + }*/ + + if (p_active_port->p_attr->link_state != IB_LINK_ACTIVE) + { + /* + * Port is DOWN; can not send or recv messages + */ + dapl_dbg_log ( DAPL_DBG_TYPE_ERR,"--> DsNMI: Port %d is DOWN; " + "can not send/recv to/from fabric\n", + p_active_port->p_attr->port_num); + return (DAT_INVALID_STATE); + } + + dapl_os_memzero (&user_query, sizeof (ib_user_query_t)); + dapl_os_memzero (&service_rec, sizeof (ib_service_record_t)); + dapl_os_memzero (&query_req, sizeof (ib_query_req_t)); + + /* + * query SA for IPAddress + */ + //service_rec.service_id = CL_HTON64 (DAPL_ATS_SERVICE_ID); + dapl_os_memcpy( service_rec.service_name, + ATS_NAME, + __min (sizeof(ATS_NAME), sizeof(ib_svc_name_t))); + service_rec.service_gid.unicast.interface_id = gid.guid; + service_rec.service_gid.unicast.prefix = gid.gid_prefix; + service_rec.service_pkey = IB_DEFAULT_PKEY; + service_rec.service_lease = IB_INFINITE_SERVICE_LEASE; + + user_query.method = IB_MAD_METHOD_GETTABLE; + user_query.attr_id = IB_MAD_ATTR_SERVICE_RECORD; + + user_query.comp_mask = IB_SR_COMPMASK_SGID | + IB_SR_COMPMASK_SPKEY | + IB_SR_COMPMASK_SLEASE | + IB_SR_COMPMASK_SNAME; + + user_query.attr_size = sizeof (ib_service_record_t); + user_query.p_attr = (void *)&service_rec; + + query_req.query_type = IB_QUERY_USER_DEFINED; + query_req.p_query_input = (void *)&user_query; + query_req.flags = IB_FLAGS_SYNC; /* this is a blocking call */ + query_req.timeout_ms = 1 * 1000; /* 1 second */ + query_req.retry_cnt = 5; + /* query SA using this port */ + query_req.port_guid = p_active_port->p_attr->port_guid; + query_req.query_context = (void *) &user_query; + query_req.pfn_query_cb = dapli_ib_sa_query_cb; + + ib_status = ib_query (dapl_ibal_root.h_al, &query_req, NULL); + + if (ib_status != IB_SUCCESS) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "ns_map_ipaddr: exits status %s @line = %d\n", + ib_get_err_str(ib_status), __LINE__); + return (dapl_ib_status_convert (ib_status)); + } + + /* *********************** + * return the IP_address + *************************/ + dapl_os_memcpy ( + (void *) &((struct sockaddr_in *)p_ia_address)->sin_addr.s_net, + (const void *)&service_rec.service_data8[ATS_IPV4_OFFSET], 4); + //HCA_IPV6_ADDRESS_LENGTH); + ((DAT_SOCK_ADDR6 *)p_ia_address)->sin6_family = AF_INET; + + return (DAT_SUCCESS); +} + + +/* + * dapls_ib_ns_create_gid_map() + * + * Register a ServiceRecord containing uDAPL_svc_id, IP address and GID to SA + * Other nodes can look it up by quering the SA + * + * Input: + * hca_ptr HCA device pointer + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + */ +DAT_RETURN +dapls_ib_ns_create_gid_map ( + IN DAPL_HCA *hca_ptr) +{ + UNUSED_PARAM( hca_ptr ); + return (DAT_SUCCESS); +} + + +DAT_RETURN +dapls_ib_ns_remove_gid_map ( + IN DAPL_HCA *hca_ptr) +{ + UNUSED_PARAM( hca_ptr ); + return (DAT_SUCCESS); +} + +#endif /* NO_NAME_SERVICE */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/ibal/dapl_ibal_name_service.h b/branches/WOF2-3/ulp/dapl2/dapl/ibal/dapl_ibal_name_service.h new file mode 100644 index 00000000..d322d71f --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/ibal/dapl_ibal_name_service.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2005-2007 Intel Corporation. All rights reserved. + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dapl_ibal_name_service.h + * + * PURPOSE: Utility defs & routines supporting name services + * + * $Id: dapl_name_service.h 33 2005-07-11 19:51:17Z ftillier $ + * + **********************************************************************/ + +#ifndef _DAPL_IBAL_NAME_SERVICE_H_ +#define _DAPL_IBAL_NAME_SERVICE_H_ 1 + +#include "dapl.h" +#include "dapl_adapter_util.h" + +/* + * Prototypes for name service routines + */ + +/* Return IPv4 address in 'dot' notation. */ + +char * +dapli_get_ip_addr_str ( + IN DAT_SOCK_ADDR6 *ipa, + OUT char *str ); + +/* SA Query callback for locating GID/Path-rec */ +void AL_API +dapli_ib_sa_query_cb ( + IN ib_query_rec_t *p_query_rec ); + + +#ifdef NO_NAME_SERVICE + +DAT_RETURN dapls_ns_lookup_address ( + IN DAPL_IA *ia_ptr, + IN DAT_IA_ADDRESS_PTR remote_ia_address, + OUT GID *gid); + + +#else + +DAT_RETURN dapls_ns_create_gid_map(DAPL_HCA *hca_ptr); + +DAT_RETURN dapls_ns_remove_gid_map(DAPL_HCA *hca_ptr); + +DAT_RETURN dapls_ns_map_gid ( + IN DAPL_HCA *hca_ptr, + IN DAT_IA_ADDRESS_PTR remote_ia_address, + OUT GID *gid); + +DAT_RETURN +dapls_ib_ns_map_gid ( + IN DAPL_HCA *hca_ptr, + IN DAT_IA_ADDRESS_PTR p_ia_address, + OUT GID *p_gid); + +DAT_RETURN dapls_ns_map_ipaddr ( + IN DAPL_HCA *hca_ptr, + IN GID gid, + OUT DAT_IA_ADDRESS_PTR remote_ia_address); + +DAT_RETURN +dapls_ib_ns_map_ipaddr ( + IN DAPL_HCA *hca_ptr, + IN GID gid, + OUT DAT_IA_ADDRESS_PTR p_ia_address); + +#endif /* NO_NAME_SERVICE */ + +#endif /* _DAPL_IBAL_NAME_SERVICE_H_ */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/ibal/dapl_ibal_qp.c b/branches/WOF2-3/ulp/dapl2/dapl/ibal/dapl_ibal_qp.c new file mode 100644 index 00000000..f52f5daf --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/ibal/dapl_ibal_qp.c @@ -0,0 +1,707 @@ + +/* + * Copyright (c) 2005-2007 Intel Corporation. All rights reserved. + * Copyright (c) 2002, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under the terms of the "Common Public + * License" a copy of which is in the file LICENSE.txt in the root + * directory. The license is also available from the Open Source + * Initiative, see http://www.opensource.org/licenses/cpl.php. + * + */ + +/********************************************************************** + * + * MODULE: dapl_ibal_qp.c + * + * PURPOSE: IB QP routines for access to IBAL APIs + * + * $Id: dapl_ibal_qp.c 33 2005-07-11 19:51:17Z ftillier $ + * + **********************************************************************/ + +#include "dapl.h" +#include "dapl_adapter_util.h" +#include "dapl_evd_util.h" +#include "dapl_ibal_util.h" +#include "dapl_ep_util.h" + +#define DAPL_IBAL_QKEY 0 +#define DAPL_IBAL_START_PSN 0 + +extern DAT_RETURN +dapls_ib_cq_late_alloc ( IN ib_pd_handle_t pd_handle, + IN DAPL_EVD *evd_ptr ); + +static void +dapli_ib_qp_async_error_cb( IN ib_async_event_rec_t* p_err_rec ) +{ + DAPL_EP *ep_ptr = (DAPL_EP *)p_err_rec->context; + DAPL_EVD *evd_ptr; + DAPL_IA *ia_ptr; + dapl_ibal_ca_t *p_ca; + dapl_ibal_evd_cb_t *evd_cb; + + dapl_dbg_log (DAPL_DBG_TYPE_ERR,"--> DiQpAEC QP event %s qp ctx %p\n", + ib_get_async_event_str(p_err_rec->code), p_err_rec->context); + dapl_dbg_log (DAPL_DBG_TYPE_ERR,"--> DiQpAEC qp_handle %p qpn %u\n", + ((DAPL_EP *)p_err_rec->context)->qp_handle, + ((DAPL_EP *)p_err_rec->context)->qpn); + + /* + * Verify handles EP, EVD, and hca_handle + */ + if (DAPL_BAD_HANDLE (ep_ptr, DAPL_MAGIC_EP ) || + DAPL_BAD_HANDLE (ep_ptr->param.connect_evd_handle, DAPL_MAGIC_EVD)) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "--> DiQpAEC: invalid EP %p \n", ep_ptr); + return; + } + ia_ptr = ep_ptr->header.owner_ia; + evd_ptr = ia_ptr->async_error_evd; + + if (DAPL_BAD_HANDLE (evd_ptr, DAPL_MAGIC_EVD) || + ! (evd_ptr->evd_flags & DAT_EVD_ASYNC_FLAG)) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "--> DiQpAEC: invalid EVD %p \n", evd_ptr); + return; + } + p_ca = (dapl_ibal_ca_t *) ia_ptr->hca_ptr->ib_hca_handle; + if (p_ca == NULL) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "--> DiQpAEC: can't find %s HCA\n", + (ia_ptr->header.provider)->device_name); + return; + } + + /* find QP error callback using ia_ptr for context */ + evd_cb = dapli_find_evd_cb_by_context (ia_ptr, p_ca); + if ((evd_cb == NULL) || (evd_cb->pfn_async_qp_err_cb == NULL)) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "--> DiQpAEC: no ERROR cb on p_ca %p found\n", p_ca); + return; + } + + dapl_os_lock (&ep_ptr->header.lock); + ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECT_PENDING; + dapl_os_unlock (&ep_ptr->header.lock); + + /* force disconnect, QP error state, to insure DTO's get flushed */ + dapls_ib_disconnect ( ep_ptr, DAT_CLOSE_ABRUPT_FLAG ); + + /* maps to dapl_evd_qp_async_error_callback(), context is EP */ + evd_cb->pfn_async_qp_err_cb( (ib_hca_handle_t)p_ca, + ep_ptr->qp_handle, + (ib_error_record_t*)&p_err_rec->code, + ep_ptr ); +} + +/* + * dapls_ib_qp_alloc + * + * Alloc a QP + * + * Input: + * *ia_ptr pointer to DAPL IA + * *ep_ptr pointer to DAPL EP + * *ep_ctx_ptr pointer to DAPL EP context + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * + */ +DAT_RETURN +dapls_ib_qp_alloc ( + IN DAPL_IA *ia_ptr, + IN DAPL_EP *ep_ptr, + IN DAPL_EP *ep_ctx_ptr) +{ + DAT_EP_ATTR *attr; + DAPL_EVD *recv_evd_ptr, *request_evd_ptr; + DAT_RETURN dat_status; + ib_api_status_t ib_status; + ib_qp_create_t qp_create; + ib_pd_handle_t ib_pd_handle; + ib_cq_handle_t cq_recv; + ib_cq_handle_t cq_send; + dapl_ibal_ca_t *p_ca; + dapl_ibal_port_t *p_active_port; + ib_qp_attr_t qp_attr; + dp_ib_cm_handle_t cm_ptr; + + attr = &ep_ptr->param.ep_attr; + + dapl_os_assert ( ep_ptr->param.pz_handle != NULL ); + + ib_pd_handle = ((DAPL_PZ *)ep_ptr->param.pz_handle)->pd_handle; + dapl_os_assert(ib_pd_handle); + recv_evd_ptr = (DAPL_EVD *) ep_ptr->param.recv_evd_handle; + request_evd_ptr = (DAPL_EVD *) ep_ptr->param.request_evd_handle; + + cq_recv = IB_INVALID_HANDLE; + cq_send = IB_INVALID_HANDLE; + + dapl_os_assert ( recv_evd_ptr != DAT_HANDLE_NULL ); + { + cq_recv = (ib_cq_handle_t) recv_evd_ptr->ib_cq_handle; + + if ((cq_recv == IB_INVALID_HANDLE) && + ( 0 != (recv_evd_ptr->evd_flags & ~DAT_EVD_SOFTWARE_FLAG) )) + { + dat_status = dapls_ib_cq_late_alloc ( ib_pd_handle, recv_evd_ptr); + if (dat_status != DAT_SUCCESS) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "--> %s: failed to create CQ\n","DsQA"); + return (dat_status); + } + + dat_status = dapls_set_cq_notify (ia_ptr, recv_evd_ptr); + + if (dat_status != DAT_SUCCESS) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "--> %s: failed to enable notify CQ\n","DsQA"); + return (dat_status); + } + + cq_recv = (ib_cq_handle_t) recv_evd_ptr->ib_cq_handle; + dapl_dbg_log (DAPL_DBG_TYPE_EP, + "--> DsQA: alloc_recv_CQ = %p\n", cq_recv); + + } + } + + dapl_os_assert ( request_evd_ptr != DAT_HANDLE_NULL ); + { + cq_send = (ib_cq_handle_t) request_evd_ptr->ib_cq_handle; + + if ((cq_send == IB_INVALID_HANDLE) && + ( 0 != (request_evd_ptr->evd_flags & ~DAT_EVD_SOFTWARE_FLAG) )) + { + dat_status = dapls_ib_cq_late_alloc (ib_pd_handle, request_evd_ptr); + if (dat_status != DAT_SUCCESS) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "--> %s: failed to create CQ\n","DsQA"); + return (dat_status); + } + + dat_status = dapls_set_cq_notify (ia_ptr, request_evd_ptr); + + if (dat_status != DAT_SUCCESS) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "--> %s: failed to enable notify CQ\n","DsQA"); + return (dat_status); + } + + cq_send = (ib_cq_handle_t) request_evd_ptr->ib_cq_handle; + dapl_dbg_log (DAPL_DBG_TYPE_EP, + "--> DsQA: alloc_send_CQ = %p\n", cq_send); + } + } + + /* + * Get the CA structure + */ + p_ca = (dapl_ibal_ca_t *) ia_ptr->hca_ptr->ib_hca_handle; + + dapl_os_memzero (&qp_create, sizeof (qp_create)); + qp_create.qp_type = IB_QPT_RELIABLE_CONN; + qp_create.sq_depth = attr->max_request_dtos; + qp_create.rq_depth = attr->max_recv_dtos; + qp_create.sq_sge = attr->max_recv_iov; + qp_create.rq_sge = attr->max_request_iov; + qp_create.h_sq_cq = cq_send; + qp_create.h_rq_cq = cq_recv; + qp_create.sq_signaled = FALSE; + + dapl_dbg_log (DAPL_DBG_TYPE_EP, + "--> DsQA: sqd,iov=%d,%d rqd,iov=%d,%d\n", + attr->max_request_dtos, attr->max_request_iov, + attr->max_recv_dtos, attr->max_recv_iov); + + ib_status = ib_create_qp ( + ib_pd_handle, + &qp_create, + (void *) ep_ctx_ptr /* context */, + dapli_ib_qp_async_error_cb, + &ep_ptr->qp_handle); + + if (ib_status != IB_SUCCESS) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> DsQA: Create QP failed = %s\n", + ib_get_err_str(ib_status)); + return (DAT_INSUFFICIENT_RESOURCES); + } + /* EP-CM linking */ + cm_ptr = ibal_cm_alloc(); + if (!cm_ptr) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> DsQA: Create CM failed\n"); + return (DAT_INSUFFICIENT_RESOURCES); + } + cm_ptr->ib_cm.h_qp = ep_ptr->qp_handle; + cm_ptr->ep = ep_ptr; + dapl_ep_link_cm(ep_ptr, cm_ptr); + + dapl_dbg_log (DAPL_DBG_TYPE_EP, "--> DsQA: EP=%p, tEVD=%p, rEVD=%p QP=%p\n", + ep_ptr, ep_ptr->param.request_evd_handle, + ep_ptr->param.recv_evd_handle, + ep_ptr->qp_handle ); + + ep_ptr->qp_state = IB_QPS_RESET; + + p_active_port = dapli_ibal_get_port(p_ca,(uint8_t)ia_ptr->hca_ptr->port_num); + + if (NULL == p_active_port) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "--> DsQA: Port %d is not available = %d\n", + ia_ptr->hca_ptr->port_num, __LINE__); + return (DAT_INVALID_STATE); + } + + ib_status = dapls_modify_qp_state_to_init ( ep_ptr->qp_handle, + &ep_ptr->param.ep_attr, + p_active_port ); + + if ( ib_status != IB_SUCCESS ) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "--> DsQA: Change QP state to INIT failed = %s\n", + ib_get_err_str(ib_status)); + return (DAT_INVALID_HANDLE); + } + ib_status = ib_query_qp ( ep_ptr->qp_handle, &qp_attr ); + + ep_ptr->qp_state = qp_attr.state; + ep_ptr->qpn = qp_attr.num; + + dapl_dbg_log (DAPL_DBG_TYPE_EP, "--> DsQAQA: EP:%p new_QP %p state %s\n", + ep_ptr, + ep_ptr->qp_handle, + ib_get_port_state_str(ep_ptr->qp_state)); + + return (DAT_SUCCESS); +} + + +/* + * dapls_ib_qp_free + * + * Free a QP + * + * Input: + * *ia_ptr pointer to IA structure + * *ep_ptr pointer to EP structure + * + * Output: + * none + * + * Returns: + * none + * + */ +DAT_RETURN +dapls_ib_qp_free ( + IN DAPL_IA *ia_ptr, + IN DAPL_EP *ep_ptr ) +{ + + ib_qp_handle_t qp_handle; + UNREFERENCED_PARAMETER(ia_ptr); + + dapl_dbg_log (DAPL_DBG_TYPE_EP, "--> DsQF: free %p, state %s\n", + ep_ptr->qp_handle, + ib_get_port_state_str(ep_ptr->qp_state)); + + if (( ep_ptr->qp_handle != IB_INVALID_HANDLE ) && + ( ep_ptr->qp_state != DAPL_QP_STATE_UNATTACHED )) + { + qp_handle = ep_ptr->qp_handle; + ep_ptr->qp_handle = IB_INVALID_HANDLE; + ep_ptr->qp_state = DAPL_QP_STATE_UNATTACHED; + ib_destroy_qp ( qp_handle, NULL /* callback */); + dapl_dbg_log (DAPL_DBG_TYPE_EP, "--> DsQF: freed QP %p\n", + qp_handle ); + } + + return DAT_SUCCESS; +} + + +/* + * dapls_ib_qp_modify + * + * Set the QP to the parameters specified in an EP_PARAM + * + * We can't be sure what state the QP is in so we first obtain the state + * from the driver. The EP_PARAM structure that is provided has been + * sanitized such that only non-zero values are valid. + * + * Input: + * *ia_ptr pointer to DAPL IA + * *ep_ptr pointer to DAPL EP + * *ep_attr pointer to DAT EP attribute + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + * + */ +DAT_RETURN +dapls_ib_qp_modify ( + IN DAPL_IA *ia_ptr, + IN DAPL_EP *ep_ptr, + IN DAT_EP_ATTR *ep_attr ) +{ + ib_qp_attr_t qp_attr; + ib_api_status_t ib_status; + ib_qp_handle_t qp_handle; + ib_qp_state_t qp_state; + ib_qp_mod_t qp_mod; + ib_av_attr_t *p_av_attr; + ib_qp_opts_t *p_qp_opts; + uint32_t *p_sq_depth, *p_rq_depth; + DAT_BOOLEAN need_modify; + DAT_RETURN dat_status; + + qp_handle = ep_ptr->qp_handle; + need_modify = DAT_FALSE; + dat_status = DAT_SUCCESS; + if ( ia_ptr == NULL || ia_ptr->header.magic != DAPL_MAGIC_IA ) + { + dat_status = DAT_INVALID_HANDLE; + goto bail; + } + /* + * Query the QP to get the current state. + */ + ib_status = ib_query_qp ( qp_handle, &qp_attr ); + + if ( ib_status != IB_SUCCESS ) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> DsIQM: Query QP failed = %s\n", + ib_get_err_str(ib_status)); + dat_status = DAT_INTERNAL_ERROR; + goto bail; + } + + qp_state = qp_attr.state; + + dapl_dbg_log (DAPL_DBG_TYPE_EP, "--> DsIQM: modify qp state=%d\n",qp_state); + /* + * Check if we have the right qp_state or not + */ + if ( (qp_state != IB_QPS_RTR ) && (qp_state != IB_QPS_RTS ) ) + { + dapl_dbg_log (DAPL_DBG_TYPE_EP, + "--> DsIQM: postpone to modify qp to EP values later\n"); + dat_status = DAT_SUCCESS; + goto bail; + } + + dapl_os_memzero (&qp_mod, sizeof (ib_qp_mod_t)); + + if (qp_state == IB_QPS_RTR) + { + p_av_attr = &qp_mod.state.rtr.primary_av; + p_qp_opts = &qp_mod.state.rtr.opts; + p_sq_depth = &qp_mod.state.rtr.sq_depth; + p_rq_depth = &qp_mod.state.rtr.rq_depth; + } + else + { + /* + * RTS does not have primary_av field + */ + p_av_attr = &qp_mod.state.rts.alternate_av; + p_qp_opts = &qp_mod.state.rts.opts; + p_sq_depth = &qp_mod.state.rts.sq_depth; + p_rq_depth = &qp_mod.state.rts.rq_depth; + } + + if ( (ep_attr->max_recv_dtos > 0) && + ((DAT_UINT32)ep_attr->max_recv_dtos != qp_attr.rq_depth) ) + { + dapl_dbg_log (DAPL_DBG_TYPE_EP,"--> DsIQM: rq_depth modified (%d,%d)\n", + qp_attr.rq_depth, ep_attr->max_recv_dtos); + + *p_rq_depth = ep_attr->max_recv_dtos; + *p_qp_opts |= IB_MOD_QP_RQ_DEPTH; + need_modify = DAT_TRUE; + } + + if ( (ep_attr->max_request_dtos > 0) && + ((DAT_UINT32)ep_attr->max_request_dtos != qp_attr.sq_depth) ) + { + dapl_dbg_log (DAPL_DBG_TYPE_EP, + "--> DsIQM: sq_depth modified (%d,%d)\n", + qp_attr.sq_depth, ep_attr->max_request_dtos); + + *p_sq_depth = ep_attr->max_request_dtos; + *p_qp_opts |= IB_MOD_QP_SQ_DEPTH; + need_modify = DAT_TRUE; + } + + qp_mod.req_state = qp_state; + + if ( need_modify == DAT_TRUE ) + { + ib_status = ib_modify_qp (qp_handle, &qp_mod); + if ( ib_status != IB_SUCCESS) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> %s: ib_status = %d\n", + "DsIQM", ib_status); + dat_status = DAT_INTERNAL_ERROR; + } + } + +bail: + + return dat_status; +} + + +ib_api_status_t +dapls_modify_qp_state_to_error ( ib_qp_handle_t qp_handle ) +{ + ib_qp_mod_t qp_mod; + ib_api_status_t ib_status; + + dapl_dbg_log (DAPL_DBG_TYPE_EP, "--> DsIQM_Err: QP state change --> Err\n"); + + dapl_os_memzero (&qp_mod, sizeof (ib_qp_mod_t)); + + qp_mod.req_state = IB_QPS_ERROR; + + ib_status = ib_modify_qp (qp_handle, &qp_mod); + + return (ib_status); +} + + +ib_api_status_t +dapls_modify_qp_state_to_reset ( ib_qp_handle_t qp_handle ) +{ + ib_qp_mod_t qp_mod; + ib_api_status_t ib_status; + + dapl_dbg_log (DAPL_DBG_TYPE_EP, "--> DsIQM_RESET: QP state change\n"); + + dapl_os_memzero (&qp_mod, sizeof (ib_qp_mod_t)); + + qp_mod.req_state = IB_QPS_RESET; + + ib_status = ib_modify_qp (qp_handle, &qp_mod); + + return (ib_status); +} + + +ib_api_status_t +dapls_modify_qp_state_to_init ( + IN ib_qp_handle_t qp_handle, + IN DAT_EP_ATTR *p_attr, + IN dapl_ibal_port_t *p_port ) +{ + ib_qp_mod_t qp_mod; + ib_api_status_t ib_status; + + dapl_os_memzero (&qp_mod, sizeof (ib_qp_mod_t)); + + qp_mod.req_state = IB_QPS_INIT; + qp_mod.state.init.primary_port = p_port->p_attr->port_num; + qp_mod.state.init.qkey = DAPL_IBAL_QKEY; + qp_mod.state.init.pkey_index = 0; + qp_mod.state.init.access_ctrl = IB_AC_LOCAL_WRITE | + IB_AC_RDMA_WRITE | + IB_AC_MW_BIND | + IB_AC_ATOMIC; + if ((p_attr->max_rdma_read_in > 0) || (p_attr->max_rdma_read_out > 0)) + { + qp_mod.state.init.access_ctrl |= IB_AC_RDMA_READ; + } + ib_status = ib_modify_qp (qp_handle, &qp_mod); + + dapl_dbg_log (DAPL_DBG_TYPE_EP, "--> DsIQM_INIT: QP(%p) state change, %s\n", + qp_handle, ib_get_err_str(ib_status)); + + return (ib_status); +} + + +ib_api_status_t +dapls_modify_qp_state_to_rtr ( + ib_qp_handle_t qp_handle, + ib_net32_t dest_qp, + ib_lid_t dest_lid, + dapl_ibal_port_t *p_port) +{ + ib_qp_mod_t qp_mod; + ib_api_status_t ib_status; + + dapl_os_memzero (&qp_mod, sizeof (ib_qp_mod_t)); + + qp_mod.req_state = IB_QPS_RTR; + qp_mod.state.rtr.rq_psn = DAPL_IBAL_START_PSN; + qp_mod.state.rtr.dest_qp = dest_qp; + qp_mod.state.rtr.primary_av.port_num = p_port->p_attr->port_num; + qp_mod.state.rtr.primary_av.sl = 0; + qp_mod.state.rtr.primary_av.dlid = dest_lid; + qp_mod.state.rtr.primary_av.grh_valid = 0; /* FALSE */ + qp_mod.state.rtr.primary_av.static_rate = IB_PATH_RECORD_RATE_10_GBS; + qp_mod.state.rtr.primary_av.path_bits = 0; + qp_mod.state.rtr.primary_av.conn.path_mtu = p_port->p_attr->mtu; + qp_mod.state.rtr.primary_av.conn.local_ack_timeout = 7; + qp_mod.state.rtr.primary_av.conn.seq_err_retry_cnt = 7; + qp_mod.state.rtr.primary_av.conn.rnr_retry_cnt = IB_RNR_RETRY_CNT; + qp_mod.state.rtr.resp_res = 4; // in-flight RDMAs + qp_mod.state.rtr.rnr_nak_timeout = IB_RNR_NAK_TIMEOUT; + + ib_status = ib_modify_qp (qp_handle, &qp_mod); + + dapl_dbg_log (DAPL_DBG_TYPE_EP, "--> DsIQM_RTR: QP(%p) state change %s\n", + qp_handle, ib_get_err_str(ib_status)); + + return (ib_status); +} + +ib_api_status_t +dapls_modify_qp_state_to_rts ( ib_qp_handle_t qp_handle ) +{ + ib_qp_mod_t qp_mod; + ib_api_status_t ib_status; + + dapl_os_memzero (&qp_mod, sizeof (ib_qp_mod_t)); + + qp_mod.req_state = IB_QPS_RTS; + qp_mod.state.rts.sq_psn = DAPL_IBAL_START_PSN; + qp_mod.state.rts.retry_cnt = 7; + qp_mod.state.rts.rnr_retry_cnt = IB_RNR_RETRY_CNT; + qp_mod.state.rtr.rnr_nak_timeout = IB_RNR_NAK_TIMEOUT; + qp_mod.state.rts.local_ack_timeout = 7; + qp_mod.state.rts.init_depth = 4; + + ib_status = ib_modify_qp (qp_handle, &qp_mod); + + dapl_dbg_log (DAPL_DBG_TYPE_EP, "--> DsIQM_RTS: QP(%p) state change %s\n", + qp_handle, ib_get_err_str(ib_status)); + + return (ib_status); +} + + +/* + * dapls_ib_reinit_ep + * + * Move the QP to INIT state again. + * + * Input: + * ep_ptr DAPL_EP + * + * Output: + * none + * + * Returns: + * void + * + */ +void +dapls_ib_reinit_ep ( IN DAPL_EP *ep_ptr ) +{ + DAPL_IA *ia_ptr; + ib_api_status_t ib_status; + dapl_ibal_ca_t *p_ca; + dapl_ibal_port_t *p_active_port; + + dapl_dbg_log (DAPL_DBG_TYPE_EP, + "--> DsIQM_REINIT: EP(%p) QP(%p) state change\n", + ep_ptr, ep_ptr->qp_handle ); + + if ( ep_ptr->param.ep_state != DAT_EP_STATE_DISCONNECTED ) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> DsIRE: EP invalid state(%d)\n", + ep_ptr->param.ep_state); + return /*DAT_INVALID_STATE*/; + } + + ia_ptr = ep_ptr->header.owner_ia; + + /* Re-create QP if cleaned up, alloc will return init state */ + if ( ep_ptr->qp_handle == IB_INVALID_HANDLE ) + { + dapl_dbg_log (DAPL_DBG_TYPE_EP, + "--> DsIRE: !EP(%p)->qp_handle, re-create QP\n",ep_ptr); + ib_status = dapls_ib_qp_alloc ( ia_ptr, ep_ptr, ep_ptr ); + if ( ib_status != IB_SUCCESS ) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "--> DsIRE: failed to move qp to RESET status = %s\n", + ib_get_err_str(ib_status)); + } + return /*ib_status*/; + } + + ib_status = dapls_modify_qp_state_to_reset (ep_ptr->qp_handle); + + if ( ib_status != IB_SUCCESS ) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "--> DsIRE: failed to move qp to RESET status = %s\n", + ib_get_err_str(ib_status)); + return /*DAT_INTERNAL_ERROR*/; + } + + ep_ptr->qp_state = IB_QPS_RESET; + + p_ca = (dapl_ibal_ca_t *) ia_ptr->hca_ptr->ib_hca_handle; + p_active_port = dapli_ibal_get_port ( p_ca, + (uint8_t)ia_ptr->hca_ptr->port_num ); + if (NULL == p_active_port) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "--> DsIRE: Port %d is not available = %d\n", + ia_ptr->hca_ptr->port_num, __LINE__); + return /*DAT_INTERNAL_ERROR*/; + } + + /* May fail if QP still RESET and in timewait, keep in reset state */ + ib_status = dapls_modify_qp_state_to_init ( ep_ptr->qp_handle, + &ep_ptr->param.ep_attr, + p_active_port); + if ( ib_status != IB_SUCCESS ) + { + ep_ptr->qp_state = IB_QPS_RESET; + + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "--> DsIRE: failed to move qp to INIT status %s\n", + ib_get_err_str(ib_status)); + return /*DAT_INTERNAL_ERROR*/; + } + ep_ptr->qp_state = IB_QPS_INIT; +} + + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ + diff --git a/branches/WOF2-3/ulp/dapl2/dapl/ibal/dapl_ibal_util.c b/branches/WOF2-3/ulp/dapl2/dapl/ibal/dapl_ibal_util.c new file mode 100644 index 00000000..7f9b819c --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/ibal/dapl_ibal_util.c @@ -0,0 +1,2318 @@ +/* + * Copyright (c) 2005-2007 Intel Corporation. All rights reserved. + * Copyright (c) 2002, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under the terms of the "Common Public + * License" a copy of which is in the file LICENSE.txt in the root + * directory. The license is also available from the Open Source + * Initiative, see http://www.opensource.org/licenses/cpl.php. + * + */ + +/********************************************************************** + * + * MODULE: dapl_ibal_util.c + * + * PURPOSE: Utility routines for access to IBAL APIs + * + * $Id: dapl_ibal_util.c 33 2005-07-11 19:51:17Z ftillier $ + * + **********************************************************************/ + +#include "dapl.h" +#include "dapl_adapter_util.h" +#include "dapl_evd_util.h" +#include "dapl_cr_util.h" +#include "dapl_lmr_util.h" +#include "dapl_rmr_util.h" +#include "dapl_cookie.h" +#include "dapl_ring_buffer_util.h" + +#ifdef DAT_EXTENSIONS +#include +#endif + +#ifndef NO_NAME_SERVICE +#include "dapl_name_service.h" +#endif /* NO_NAME_SERVICE */ + +#include "dapl_ibal_name_service.h" + +#define DAPL_IBAL_MAX_CA 4 +#define DAT_ADAPTER_NAME "InfiniHost (Tavor)" +#define DAT_VENDOR_NAME "Mellanox Technolgy Inc." + +/* + * Root data structure for DAPL_IIBA. + */ +dapl_ibal_root_t dapl_ibal_root; +DAPL_HCA_NAME dapl_ibal_hca_name_array [DAPL_IBAL_MAX_CA] = + {"IbalHca0", "IbalHca1", "IbalHca2", "IbalHca3"}; +ib_net64_t *gp_ibal_ca_guid_tbl = NULL; + +/* + * DAT spec does not tie max_mtu_size with IB MTU + * +static ib_net32_t dapl_ibal_mtu_table[6] = {0, 256, 512, 1024, 2048, 4096}; + */ + +int g_loopback_connection = 0; + + +static cl_status_t +dapli_init_root_ca_list( + IN dapl_ibal_root_t *root ) +{ + cl_status_t status; + + cl_qlist_init (&root->ca_head); + status = cl_spinlock_init (&root->ca_lock); + + if (status == CL_SUCCESS) + { + /* + * Get the time ready to go but don't start here + */ + root->shutdown = FALSE; + root->initialized = TRUE; + } + else + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "--> DiIRCL: cl_spinlock_init returned %d\n", status ); + root->initialized = FALSE; + } + + root->h_al = NULL; + + return (status); +} + + +static cl_status_t +dapli_destroy_root_ca_list( + IN dapl_ibal_root_t *root ) +{ + + root->initialized = FALSE; + + /* + * At this point the lock should not be necessary + */ + if (!cl_is_qlist_empty (&root->ca_head) ) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "--> Destroying nonempty ca list (%s)\n", "DiDRCL"); + } + cl_spinlock_destroy (&root->ca_lock); + + return CL_SUCCESS; +} + + +static void +dapli_shutdown_port_access( + IN dapl_ibal_ca_t *ca ) +{ + dapl_ibal_port_t *p_port; + + TAKE_LOCK( ca->port_lock ); + { + while ( ! cl_is_qlist_empty( &ca->port_head ) ) + { + p_port = (dapl_ibal_port_t *)cl_qlist_remove_head( &ca->port_head ); + RELEASE_LOCK( ca->port_lock ); + { + REMOVE_REFERENCE( &p_port->refs ); + REMOVE_REFERENCE( &p_port->ca->refs ); + + dapl_os_free (p_port, sizeof (dapl_ibal_port_t)); + } + TAKE_LOCK( ca->port_lock ); + } + } + RELEASE_LOCK( ca->port_lock ); +} + + +static void dapli_shutdown_ca_access (void) +{ + dapl_ibal_ca_t *ca; + + if ( dapl_ibal_root.initialized == FALSE ) + { + goto destroy_root; + } + + TAKE_LOCK (dapl_ibal_root.ca_lock); + { + while ( ! cl_is_qlist_empty (&dapl_ibal_root.ca_head) ) + { + ca = (dapl_ibal_ca_t *) + cl_qlist_remove_head (&dapl_ibal_root.ca_head); + + if (ca->p_ca_attr) + { + dapl_os_free (ca->p_ca_attr, sizeof (ib_ca_attr_t)); + } + + + RELEASE_LOCK (dapl_ibal_root.ca_lock); + { + dapli_shutdown_port_access (ca); + REMOVE_REFERENCE (&ca->refs); + } + TAKE_LOCK (dapl_ibal_root.ca_lock); + } + } + RELEASE_LOCK (dapl_ibal_root.ca_lock); + +destroy_root: + /* + * Destroy the root CA list and list lock + */ + dapli_destroy_root_ca_list (&dapl_ibal_root); + + /* + * Signal we're all done and wake any waiter + */ + dapl_ibal_root.shutdown = FALSE; +} + + +dapl_ibal_evd_cb_t * +dapli_find_evd_cb_by_context( + IN void *context, + IN dapl_ibal_ca_t *ca) +{ + dapl_ibal_evd_cb_t *evd_cb = NULL; + + TAKE_LOCK( ca->evd_cb_lock ); + + evd_cb = (dapl_ibal_evd_cb_t *) cl_qlist_head( &ca->evd_cb_head ); + while ( &evd_cb->next != cl_qlist_end( &ca->evd_cb_head ) ) + { + if ( context == evd_cb->context) + { + goto found; + } + + /* + * Try again + */ + evd_cb = (dapl_ibal_evd_cb_t *) cl_qlist_next( &evd_cb->next ); + } + /* + * No joy + */ + evd_cb = NULL; + +found: + + RELEASE_LOCK( ca->evd_cb_lock ); + + return ( evd_cb ); +} + + +static cl_status_t +dapli_init_ca_evd_cb_list( + IN dapl_ibal_ca_t *ca ) +{ + cl_status_t status; + + cl_qlist_init( &ca->evd_cb_head ); + status = cl_spinlock_init( &ca->evd_cb_lock ); + if ( status != CL_SUCCESS ) + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, "--> DiICECL: cl_spinlock_init returned %d\n", status); + return ( status ); +} + + +static cl_status_t +dapli_init_ca_port_list( + IN dapl_ibal_ca_t *ca ) +{ + cl_status_t status; + + cl_qlist_init( &ca->port_head ); + status = cl_spinlock_init( &ca->port_lock ); + if ( status != CL_SUCCESS ) + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "--> DiICPL: cl_spinlock_init returned %d\n", status ); + return ( status ); +} + +dapl_ibal_port_t * +dapli_ibal_get_port ( + IN dapl_ibal_ca_t *p_ca, + IN uint8_t port_num) +{ + cl_list_item_t *p_active_port = NULL; + + TAKE_LOCK (p_ca->port_lock); + for ( p_active_port = cl_qlist_head( &p_ca->port_head ); + p_active_port != cl_qlist_end ( &p_ca->port_head); + p_active_port = cl_qlist_next ( p_active_port ) ) + { + if (((dapl_ibal_port_t *)p_active_port)->p_attr->port_num == port_num) + break; + } + RELEASE_LOCK (p_ca->port_lock); + + return (dapl_ibal_port_t *)p_active_port; +} + + +void +dapli_ibal_ca_async_error_callback( IN ib_async_event_rec_t *p_err_rec ) +{ + dapl_ibal_ca_t *p_ca = (dapl_ibal_ca_t*)((void *)p_err_rec->context); + dapl_ibal_evd_cb_t *evd_cb; + DAPL_IA *ia_ptr; + + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "--> DiCaAEC: CA error %d for context %p\n", + p_err_rec->code, p_err_rec->context); + + if (p_ca == NULL) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, "--> DiCaAEC: invalid p_ca" + "(%p)in async event rec\n",p_ca); + return; + } + + ia_ptr = (DAPL_IA*)p_ca->ia_ptr; + if (ia_ptr == NULL) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "--> DiCaAEC: invalid ia_ptr in %p ca \n", p_ca ); + return; + } + + if (ia_ptr->async_error_evd == NULL) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "--> DiCqAEC: can't find async_error_evd on %s HCA\n", + (ia_ptr->header.provider)->device_name ); + return; + } + + /* find QP error callback using p_ca for context */ + evd_cb = dapli_find_evd_cb_by_context (ia_ptr->async_error_evd, p_ca); + if ((evd_cb == NULL) || (evd_cb->pfn_async_err_cb == NULL)) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + "--> DiCaAEC: no ERROR cb on %p found \n", p_ca); + return; + } + + /* maps to dapl_evd_un_async_error_callback(), context is async_evd */ + evd_cb->pfn_async_err_cb( (ib_hca_handle_t)p_ca, + (ib_error_record_t*)&p_err_rec->code, + ia_ptr->async_error_evd ); + +} + + +static dapl_ibal_port_t * +dapli_alloc_port( + IN dapl_ibal_ca_t *ca, + IN ib_port_attr_t *ib_port ) +{ + dapl_ibal_port_t *p_port = NULL; + + if (ca->h_ca == NULL ) + { + return NULL; + } + + /* + * Allocate the port structure memory. This will also deal with the + * copying ib_port_attr_t including GID and P_Key tables + */ + p_port = dapl_os_alloc ( sizeof(dapl_ibal_port_t ) ); + + if ( p_port ) + { + dapl_os_memzero (p_port, sizeof(dapl_ibal_port_t ) ); + + /* + * We're good to go after initializing reference. + */ + INIT_REFERENCE( &p_port->refs, 1, p_port, NULL /* pfn_destructor */ ); + + p_port->p_attr = ib_port; + } + return ( p_port ); +} + +static void +dapli_add_active_port( + IN dapl_ibal_ca_t *ca ) +{ + dapl_ibal_port_t *p_port; + ib_port_attr_t *p_port_attr; + ib_ca_attr_t *p_ca_attr; + int i; + + p_ca_attr = ca->p_ca_attr; + + dapl_os_assert (p_ca_attr != NULL); + + for (i = 0; i < p_ca_attr->num_ports; i++) + { + p_port_attr = &p_ca_attr->p_port_attr[i]; + + { + p_port = dapli_alloc_port( ca, p_port_attr ); + if ( p_port ) + { + TAKE_REFERENCE (&ca->refs); + + /* + * Record / update attribues + */ + p_port->p_attr = p_port_attr; + + /* + * Remember the parant CA keeping the reference we took above + */ + p_port->ca = ca; + + /* + * We're good to go - Add the new port to the list on the CA + */ + LOCK_INSERT_TAIL( ca->port_lock, ca->port_head, p_port->next ); + } + else + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "--> %s: Could not allocate dapl_ibal_port_t\n", + "DiAAP"); + } + } + dapl_dbg_log( DAPL_DBG_TYPE_UTIL, + "--> DiAAP: Port %d logical link %s lid = %#x\n", + p_port_attr->port_num, + ( p_port_attr->link_state != IB_LINK_ACTIVE + ? "DOWN": "UP" ), + CL_HTON16(p_port_attr->lid) ); + + } /* for loop */ +} + +static dapl_ibal_ca_t * +dapli_alloc_ca( + IN ib_al_handle_t h_al, + IN ib_net64_t ca_guid) +{ + dapl_ibal_ca_t *p_ca; + ib_api_status_t status; + uint32_t attr_size; + + /* + * Allocate the CA structure + */ + p_ca = dapl_os_alloc( sizeof(dapl_ibal_ca_t) ); + dapl_os_memzero (p_ca, sizeof(dapl_ibal_ca_t) ); + + if ( p_ca ) + { + /* + * Now we pass dapli_ibal_ca_async_error_callback as the + * async error callback + */ + status = ib_open_ca( h_al, + ca_guid, + dapli_ibal_ca_async_error_callback, + p_ca, + &p_ca->h_ca ); + if ( status != IB_SUCCESS ) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "--> DiAC: ib_open_ca returned %s\n", + ib_get_err_str(status)); + dapl_os_free (p_ca, sizeof (dapl_ibal_ca_t)); + return (NULL); + } + + /* + * Get port list lock and list head initialized + */ + if (( dapli_init_ca_port_list( p_ca ) != CL_SUCCESS ) || + ( dapli_init_ca_evd_cb_list( p_ca ) != CL_SUCCESS )) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "--> %s: dapli_init_ca_port_list returned failed\n", + "DiAC"); + goto close_and_free_ca; + } + + attr_size = 0; + status = ib_query_ca (p_ca->h_ca, NULL, &attr_size); + if (status != IB_INSUFFICIENT_MEMORY) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "--> DiAC: ib_query_ca returned failed status = %d\n", + status); + goto close_and_free_ca; + } + + p_ca->p_ca_attr = dapl_os_alloc ((int)attr_size); + if (p_ca->p_ca_attr == NULL) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "--> %s: dapli_alloc_ca failed to alloc memory\n", + "DiAC"); + goto close_and_free_ca; + } + + status = ib_query_ca ( + p_ca->h_ca, + p_ca->p_ca_attr, + &attr_size); + if (status != IB_SUCCESS) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "--> ib_query_ca returned failed status = %d\n", + status); + dapl_os_free (p_ca->p_ca_attr, (int)attr_size); + goto close_and_free_ca; + } + + p_ca->ca_attr_size = attr_size; + + INIT_REFERENCE( &p_ca->refs, 1, p_ca, NULL /* pfn_destructor */ ); + + dapli_add_active_port (p_ca); + + /* + * We're good to go + */ + return ( p_ca ); + } + else + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "--> %s: Error allocating CA structure\n","DiAC"); + return ( NULL ); + } + +close_and_free_ca: + /* + * Close the CA. + */ + (void) ib_close_ca ( p_ca->h_ca, NULL /* callback */); + dapl_os_free (p_ca, sizeof (dapl_ibal_ca_t)); + + /* + * If we get here, there was an initialization failure + */ + return ( NULL ); +} + + +static dapl_ibal_ca_t * +dapli_add_ca ( + IN ib_al_handle_t h_al, + IN ib_net64_t ca_guid ) +{ + dapl_ibal_ca_t *p_ca; + + /* + * Allocate a CA structure + */ + p_ca = dapli_alloc_ca( h_al, ca_guid ); + if ( p_ca ) + { + /* + * Add the new CA to the list + */ + LOCK_INSERT_TAIL( dapl_ibal_root.ca_lock, + dapl_ibal_root.ca_head, p_ca->next ); + } + else + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "--> %s: Could not allocate dapl_ibal_ca_t " + " for CA guid " F64x "\n","DiAA",ca_guid); + } + + return ( p_ca ); +} + + +int32_t +dapls_ib_init (void) +{ + ib_api_status_t status; + + /* + * Initialize the root structure + */ + if ( dapli_init_root_ca_list (&dapl_ibal_root) == CL_SUCCESS ) + { + /* + * Register with the access layer + */ + status = ib_open_al (&dapl_ibal_root.h_al); + + if (status == IB_SUCCESS) + { + intn_t guid_count; + + status = ib_get_ca_guids ( dapl_ibal_root.h_al, + NULL, + &(size_t)guid_count ); + if (status != IB_INSUFFICIENT_MEMORY) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "--> %s: ib_get_ca_guids failed = %d\n", + __FUNCTION__,status); + return -1; + } + + if (guid_count == 0) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "--> %s: found NO HCA in the system\n", + __FUNCTION__); + return -1; + } + + if (guid_count > DAPL_IBAL_MAX_CA) + { + guid_count = DAPL_IBAL_MAX_CA; + } + + gp_ibal_ca_guid_tbl = (ib_net64_t*) + dapl_os_alloc ( (int)(guid_count * + sizeof (ib_net64_t)) ); + + if (gp_ibal_ca_guid_tbl == NULL) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, "--> %s() can not alloc " + "gp_ibal_ca_guid_tbl\n", __FUNCTION__); + + return -1; + } + + status = ib_get_ca_guids ( dapl_ibal_root.h_al, + gp_ibal_ca_guid_tbl, + &(size_t)guid_count ); + + + if ( status != IB_SUCCESS ) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "--> %s: ib_get_ca_guids failed '%s'\n", + __FUNCTION__, ib_get_err_str(status) ); + return -1; + } + + dapl_dbg_log ( DAPL_DBG_TYPE_UTIL, + "--> %s: Success open AL & found %d HCA avail,\n", + __FUNCTION__, guid_count); + return 0; + } + else + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "--> %s: ib_open_al() failed '%s'\n", + __FUNCTION__, ib_get_err_str(status) ); + /* + * Undo CA list + */ + dapli_destroy_root_ca_list (&dapl_ibal_root); + } + } + return -1; +} + + +int32_t dapls_ib_release (void) +{ + dapl_ibal_root.shutdown = TRUE; + + dapli_shutdown_ca_access(); + + /* + * If shutdown not complete, wait for it + */ + if (dapl_ibal_root.shutdown) + { + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "--> DsIR: timeout waiting for completion\n"); + } + + if ( dapl_ibal_root.h_al != NULL ) + { + (void) ib_close_al (dapl_ibal_root.h_al); + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, "--> DsIR: ib_close_al() returns\n"); + dapl_ibal_root.h_al = NULL; + } +#ifdef DBG + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, "--> %s: Exit\n",__FUNCTION__); +#endif + + return 0; +} + + +/* + * dapls_ib_enum_hcas + * + * Enumerate all HCAs on the system + * + * Input: + * none + * + * Output: + * hca_names Array of hca names + * total_hca_count + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * + */ +DAT_RETURN +dapls_ib_enum_hcas ( + IN const char *vendor, + OUT DAPL_HCA_NAME **hca_names, + OUT DAT_COUNT *total_hca_count ) +{ + intn_t guid_count; + ib_api_status_t ib_status; + UNREFERENCED_PARAMETER(vendor); + + ib_status = ib_get_ca_guids (dapl_ibal_root.h_al, NULL, &(size_t)guid_count); + if (ib_status != IB_INSUFFICIENT_MEMORY) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "--> DsIEH: ib_get_ca_guids failed '%s'\n", + ib_get_err_str(ib_status) ); + return dapl_ib_status_convert (ib_status); + } + + if (guid_count == 0) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "--> %s: ib_get_ca_guids no HCA in the system\n", + "DsIEH"); + return (DAT_PROVIDER_NOT_FOUND); + } + + if (guid_count > DAPL_IBAL_MAX_CA) + { + guid_count = DAPL_IBAL_MAX_CA; + } + + gp_ibal_ca_guid_tbl = (ib_net64_t *)dapl_os_alloc ((int)(guid_count * sizeof (ib_net64_t)) ); + + if (gp_ibal_ca_guid_tbl == NULL) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "--> %s: can not alloc resources @line%d\n", "DsIEH", + __LINE__); + return (DAT_INSUFFICIENT_RESOURCES); + } + + ib_status = ib_get_ca_guids ( dapl_ibal_root.h_al, + gp_ibal_ca_guid_tbl, + &(size_t)guid_count); + + if (ib_status != IB_SUCCESS) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "--> DsIEH: ib_get_ca_guids failed status = %s\n", + ib_get_err_str(ib_status) ); + return dapl_ib_status_convert (ib_status); + } + + *hca_names = (DAPL_HCA_NAME*) + dapl_os_alloc ((int)(guid_count * sizeof (DAPL_HCA_NAME))); + + if (*hca_names == NULL) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "--> %s: can not alloc resources @line%d\n", + "DsIEH", __LINE__); + return (DAT_INSUFFICIENT_RESOURCES); + } + + dapl_os_memcpy (*hca_names, + dapl_ibal_hca_name_array, + (int)(guid_count * sizeof (DAPL_HCA_NAME)) ); + + *total_hca_count = (DAT_COUNT)guid_count; + + { + int i; + + for (i = 0; i < guid_count; i++) + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, "--> DsIEH: %d) hca_names = %s\n", + i, dapl_ibal_hca_name_array[i]); + } + + return (DAT_SUCCESS); +} + + + +IB_HCA_NAME +dapl_ib_convert_name( + IN char *name) +{ + int i; + + if (gp_ibal_ca_guid_tbl == NULL) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "--> DICN: found no HCA with name %s\n", name ); + return 0; + } + + for (i = 0; i < DAPL_IBAL_MAX_CA; i++) + { + if (strcmp (name, dapl_ibal_hca_name_array[i]) == 0) + { + break; + } + } + + if (i >= DAPL_IBAL_MAX_CA) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "--> DICN: can't find any HCA with name %s\n", name); + return 0; + } + + return (gp_ibal_ca_guid_tbl[i]); +} + + +/* + * dapls_ib_open_hca + * + * Open HCA + * + * Input: + * *hca_name pointer to provider device name + * *ib_hca_handle_p pointer to provide HCA handle + * + * Output: + * none + * + * Return: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * + */ +DAT_RETURN dapls_ib_open_hca ( IN char *hca_name, + IN DAPL_HCA *p_hca ) +{ + dapl_ibal_ca_t *p_ca; + IB_HCA_NAME ca_guid; + + dapl_dbg_log (DAPL_DBG_TYPE_UTIL," open_hca: %s - %p\n", hca_name, p_hca); + + if (gp_ibal_ca_guid_tbl == NULL) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, "--> DsIOH: found no HCA with ca_guid" + F64x "\n", hca_name); + return (DAT_PROVIDER_NOT_FOUND); + } + + ca_guid = dapl_ib_convert_name(hca_name); + + p_ca = dapli_add_ca (dapl_ibal_root.h_al, ca_guid); + + if (p_ca == NULL) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "--> DsIOH: can not create ca for '%s' guid " F64x "\n", + hca_name, ca_guid); + return (DAT_INSUFFICIENT_RESOURCES); + } + + p_hca->ib_hca_handle = (ib_hca_handle_t) p_ca; + p_hca->ib_trans.d_hca = p_hca; // back-link + + /* initialize hca wait object for uAT event */ + dapl_os_wait_object_init(&p_hca->ib_trans.wait_object); + +#if SOCK_CM + { + DAT_RETURN dat_status; + + dat_status = dapli_init_sock_cm(p_hca); + if ( dat_status != DAT_SUCCESS ) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + " %s() failed to init sock_CM\n", __FUNCTION__); + return DAT_INTERNAL_ERROR; + } + + /* initialize cr_list lock */ + dat_status = dapl_os_lock_init(&p_hca->ib_trans.lock); + if (dat_status != DAT_SUCCESS) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, " %s() failed to init lock\n", + __FUNCTION__); + return DAT_INTERNAL_ERROR; + } + + /* initialize CM list for listens on this HCA */ + dapl_llist_init_head((DAPL_LLIST_HEAD*)&p_hca->ib_trans.list); + } +#endif + + return (DAT_SUCCESS); +} + + +/* + * dapls_ib_close_hca + * + * Open HCA + * + * Input: + * ib_hca_handle provide HCA handle + * + * Output: + * none + * + * Return: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * + */ +DAT_RETURN dapls_ib_close_hca ( IN DAPL_HCA *p_hca ) +{ + dapl_ibal_ca_t *p_ca; + + p_ca = (dapl_ibal_ca_t *) p_hca->ib_hca_handle; + +#if SOCK_CM +#endif + /* + * Remove it from the list + */ + TAKE_LOCK (dapl_ibal_root.ca_lock); + { + cl_qlist_remove_item (&dapl_ibal_root.ca_head, &p_ca->next); + } + RELEASE_LOCK (dapl_ibal_root.ca_lock); + + dapli_shutdown_port_access (p_ca); + + /* + * Remove the constructor reference + */ + REMOVE_REFERENCE (&p_ca->refs); + + cl_spinlock_destroy (&p_ca->port_lock); + cl_spinlock_destroy (&p_ca->evd_cb_lock); + + if (p_ca->p_ca_attr) + dapl_os_free (p_ca->p_ca_attr, sizeof (ib_ca_attr_t)); + + (void) ib_close_ca (p_ca->h_ca, NULL /* close_callback */); + + p_hca->ib_hca_handle = IB_INVALID_HANDLE; + dapl_os_free (p_ca, sizeof (dapl_ibal_ca_t)); + + return (DAT_SUCCESS); +} + + + +/* + * dapl_ib_pd_alloc + * + * Alloc a PD + * + * Input: + * ia_handle IA handle + * PZ_ptr pointer to PZEVD struct + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * + */ +DAT_RETURN +dapls_ib_pd_alloc ( + IN DAPL_IA *ia, + IN DAPL_PZ *pz) +{ + ib_api_status_t ib_status; + dapl_ibal_ca_t *p_ca; + + p_ca = (dapl_ibal_ca_t *) ia->hca_ptr->ib_hca_handle; + + ib_status = ib_alloc_pd ( + p_ca->h_ca, + IB_PDT_NORMAL, + ia, + &pz->pd_handle ); + + return dapl_ib_status_convert (ib_status); +} + + +/* + * dapl_ib_pd_free + * + * Free a PD + * + * Input: + * PZ_ptr pointer to PZ struct + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * + */ +DAT_RETURN +dapls_ib_pd_free ( + IN DAPL_PZ *pz) +{ + ib_api_status_t ib_status; + + ib_status = ib_dealloc_pd (pz->pd_handle, /* destroy_callback */ NULL); + + pz->pd_handle = IB_INVALID_HANDLE; + + return dapl_ib_status_convert (ib_status); +} + + +/* + * dapl_ib_mr_register + * + * Register a virtual memory region + * + * Input: + * ia_handle IA handle + * lmr pointer to dapl_lmr struct + * virt_addr virtual address of beginning of mem region + * length length of memory region + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * + */ +DAT_RETURN +dapls_ib_mr_register ( + IN DAPL_IA *ia, + IN DAPL_LMR *lmr, + IN DAT_PVOID virt_addr, + IN DAT_VLEN length, + IN DAT_MEM_PRIV_FLAGS privileges, + IN DAT_VA_TYPE va_type) +{ + ib_api_status_t ib_status; + ib_mr_handle_t mr_handle; + ib_mr_create_t mr_create; + uint32_t l_key, r_key; + + if ( ia == NULL || ia->header.magic != DAPL_MAGIC_IA ) + { + return DAT_INVALID_HANDLE; + } + + /* IBAL does not support */ + if (va_type == DAT_VA_TYPE_ZB) { + dapl_dbg_log(DAPL_DBG_TYPE_ERR, + "--> va_type == DAT_VA_TYPE_ZB: NOT SUPPORTED\n"); + return DAT_ERROR (DAT_NOT_IMPLEMENTED, DAT_NO_SUBTYPE); + } + + mr_create.vaddr = (void *) virt_addr; + mr_create.length = (size_t)length; + mr_create.access_ctrl = dapl_lmr_convert_privileges (privileges); + mr_create.access_ctrl |= IB_AC_MW_BIND; + + if (lmr->param.mem_type == DAT_MEM_TYPE_SHARED_VIRTUAL) + { + ib_status = ib_reg_shmid ( + ((DAPL_PZ *)lmr->param.pz_handle)->pd_handle, + (const uint8_t*)lmr->shmid, + &mr_create, + (uint64_t *)&virt_addr, + &l_key, + &r_key, + &mr_handle); + } + else + { + ib_status = ib_reg_mem ( ((DAPL_PZ *)lmr->param.pz_handle)->pd_handle, + &mr_create, + &l_key, + &r_key, + &mr_handle ); + } + + if (ib_status != IB_SUCCESS) + { + return (dapl_ib_status_convert (ib_status)); + } + + /* DAT/DAPL expects context in host order */ + l_key = cl_ntoh32(l_key); + r_key = cl_ntoh32(r_key); + + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, "--> DsIMR: lmr (%p) lkey = 0x%x " + "r_key= %#x mr_handle %p vaddr 0x%LX len 0x%LX\n", + lmr, l_key, r_key, mr_handle, virt_addr, length); + + lmr->param.lmr_context = l_key; + lmr->param.rmr_context = r_key; + lmr->param.registered_size = length; + lmr->param.registered_address = (DAT_VADDR)virt_addr; + lmr->mr_handle = mr_handle; + + return (DAT_SUCCESS); +} + + +/* + * dapl_ib_mr_deregister + * + * Free a memory region + * + * Input: + * lmr pointer to dapl_lmr struct + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * + */ +DAT_RETURN +dapls_ib_mr_deregister ( + IN DAPL_LMR *lmr) +{ + ib_api_status_t ib_status; + + ib_status = ib_dereg_mr (lmr->mr_handle); + + if (ib_status != IB_SUCCESS) + { + return dapl_ib_status_convert (ib_status); + } + + lmr->param.lmr_context = 0; + lmr->mr_handle = IB_INVALID_HANDLE; + + return (DAT_SUCCESS); +} + + +/* + * dapl_ib_mr_register_shared + * + * Register a virtual memory region + * + * Input: + * ia_handle IA handle + * lmr pointer to dapl_lmr struct + * virt_addr virtual address of beginning of mem region + * length length of memory region + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * + */ +DAT_RETURN +dapls_ib_mr_register_shared ( + IN DAPL_IA *ia, + IN DAPL_LMR *lmr, + IN DAT_MEM_PRIV_FLAGS privileges, + IN DAT_VA_TYPE va_type ) +{ + DAT_VADDR virt_addr; + ib_mr_handle_t mr_handle; + ib_api_status_t ib_status; + ib_mr_handle_t new_mr_handle; + ib_access_t access_ctrl; + uint32_t l_key, r_key; + ib_mr_create_t mr_create; + if ( ia == NULL || ia->header.magic != DAPL_MAGIC_IA ) + { + return DAT_INVALID_HANDLE; + } + + /* IBAL does not support?? */ + if (va_type == DAT_VA_TYPE_ZB) { + dapl_dbg_log(DAPL_DBG_TYPE_ERR, + " va_type == DAT_VA_TYPE_ZB: NOT SUPPORTED\n"); + return DAT_ERROR (DAT_NOT_IMPLEMENTED, DAT_NO_SUBTYPE); + } + + virt_addr = dapl_mr_get_address (lmr->param.region_desc, + lmr->param.mem_type); + + access_ctrl = dapl_lmr_convert_privileges (privileges); + access_ctrl |= IB_AC_MW_BIND; + + mr_create.vaddr = (void *) virt_addr; + mr_create.access_ctrl = access_ctrl; + mr_handle = (ib_mr_handle_t) lmr->mr_handle; + + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "--> DsIMRS: orig mr_handle %p vaddr %p\n", + mr_handle, virt_addr); + + if (lmr->param.mem_type == DAT_MEM_TYPE_SHARED_VIRTUAL) + { + ib_status = ib_reg_shmid ( ((DAPL_PZ *)lmr->param.pz_handle)->pd_handle, + (const uint8_t*)lmr->shmid, + &mr_create, + &virt_addr, + &l_key, + &r_key, + &new_mr_handle ); + } + else + { + + ib_status = ib_reg_shared ( mr_handle, + ((DAPL_PZ *)lmr->param.pz_handle)->pd_handle, + access_ctrl, + /* in/out */(DAT_UINT64 *)&virt_addr, + &l_key, + &r_key, + &new_mr_handle ); + } + + if (ib_status != IB_SUCCESS) + { + return dapl_ib_status_convert (ib_status); + } + /* + * FIXME - Vu + * What if virt_addr as an OUTPUT having the actual virtual address + * assigned to the register region + */ + + /* DAT/DAPL expects context to be in host order */ + l_key = cl_ntoh32(l_key); + r_key = cl_ntoh32(r_key); + + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, "--> DsIMRS: lmr (%p) lkey = 0x%x " + "new mr_handle %p vaddr %p\n", + lmr, l_key, new_mr_handle, virt_addr); + + lmr->param.lmr_context = l_key; + lmr->param.rmr_context = r_key; + lmr->param.registered_address = (DAT_VADDR) (uintptr_t) virt_addr; + lmr->mr_handle = new_mr_handle; + + return (DAT_SUCCESS); +} + + +/* + * dapls_ib_mw_alloc + * + * Bind a protection domain to a memory window + * + * Input: + * rmr Initialized rmr to hold binding handles + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * + */ +DAT_RETURN +dapls_ib_mw_alloc ( IN DAPL_RMR *rmr ) +{ + ib_api_status_t ib_status; + uint32_t r_key; + ib_mw_handle_t mw_handle; + + ib_status = ib_create_mw ( + ((DAPL_PZ *)rmr->param.pz_handle)->pd_handle, + &r_key, + &mw_handle); + + if (ib_status != IB_SUCCESS) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "--> DsIMA: create MW failed = %s\n", + ib_get_err_str(ib_status) ); + return dapl_ib_status_convert (ib_status); + } + + rmr->mw_handle = mw_handle; + rmr->param.rmr_context = (DAT_RMR_CONTEXT) cl_ntoh32(r_key); + + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "--> DsIMA: mw_handle %p r_key = 0x%x\n", + mw_handle, rmr->param.rmr_context); + + return (DAT_SUCCESS); +} + + +/* + * dapls_ib_mw_free + * + * Release bindings of a protection domain to a memory window + * + * Input: + * rmr Initialized rmr to hold binding handles + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * + */ +DAT_RETURN +dapls_ib_mw_free ( + IN DAPL_RMR *rmr) +{ + ib_api_status_t ib_status; + + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "--> DsIMF: mw_handle %p\n", rmr->mw_handle); + + ib_status = ib_destroy_mw (rmr->mw_handle); + + if (ib_status != IB_SUCCESS) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, "--> DsIMF: Free MW failed = %s\n", + ib_get_err_str(ib_status)); + return dapl_ib_status_convert (ib_status); + } + + rmr->param.rmr_context = 0; + rmr->mw_handle = IB_INVALID_HANDLE; + + return (DAT_SUCCESS); +} + +/* + * dapls_ib_mw_bind + * + * Bind a protection domain to a memory window + * + * Input: + * rmr Initialized rmr to hold binding handles + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * + */ +DAT_RETURN +dapls_ib_mw_bind ( + IN DAPL_RMR *rmr, + IN DAPL_LMR *lmr, + IN DAPL_EP *ep, + IN DAPL_COOKIE *cookie, + IN DAT_VADDR virtual_address, + IN DAT_VLEN length, + IN DAT_MEM_PRIV_FLAGS mem_priv, + IN ib_bool_t is_signaled) +{ + ib_api_status_t ib_status; + ib_bind_wr_t bind_wr_prop; + uint32_t new_rkey; + + bind_wr_prop.local_ds.vaddr = virtual_address; + bind_wr_prop.local_ds.length = (uint32_t)length; + bind_wr_prop.local_ds.lkey = cl_hton32(lmr->param.lmr_context); + bind_wr_prop.current_rkey = cl_hton32(rmr->param.rmr_context); + bind_wr_prop.access_ctrl = dapl_rmr_convert_privileges (mem_priv); + bind_wr_prop.send_opt = (is_signaled == TRUE) ? + IB_SEND_OPT_SIGNALED : 0; + bind_wr_prop.wr_id = (uint64_t) ((uintptr_t) cookie); + bind_wr_prop.h_mr = lmr->mr_handle; + + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, "--> DsIMB: mr_handle %p, mw_handle %p " + "vaddr %#I64x length %#I64x\n", + lmr->mr_handle, rmr->mw_handle, virtual_address, length); + + ib_status = ib_bind_mw ( + rmr->mw_handle, + ep->qp_handle, + &bind_wr_prop, + &new_rkey); + + if (ib_status != IB_SUCCESS) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, "--> DsIMB: Bind MW failed = %s\n", + ib_get_err_str(ib_status)); + return (dapl_ib_status_convert (ib_status)); + } + + rmr->param.rmr_context = (DAT_RMR_CONTEXT) cl_ntoh32(new_rkey); + + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "--> DsIMB: new_rkey = 0x%x\n", rmr->param.rmr_context); + + return (DAT_SUCCESS); +} + +/* + * dapls_ib_mw_unbind + * + * Unbind a memory window + * + * Input: + * rmr Initialized rmr to hold binding handles + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * + */ +DAT_RETURN +dapls_ib_mw_unbind ( + IN DAPL_RMR *rmr, + IN DAPL_EP *ep, + IN DAPL_COOKIE *cookie, + IN ib_bool_t is_signaled) +{ + ib_api_status_t ib_status; + ib_bind_wr_t bind_wr_prop; + uint32_t new_rkey; + + bind_wr_prop.local_ds.vaddr = 0; + bind_wr_prop.local_ds.length = 0; + bind_wr_prop.local_ds.lkey = 0; + bind_wr_prop.access_ctrl = 0; + bind_wr_prop.send_opt = (is_signaled == TRUE) ? + IB_SEND_OPT_SIGNALED : 0; + bind_wr_prop.wr_id = (uint64_t) ((uintptr_t) cookie); + + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "--> DsIMU: mw_handle = %p\n", rmr->mw_handle); + + ib_status = ib_bind_mw ( + rmr->mw_handle, + ep->qp_handle, + &bind_wr_prop, + &new_rkey); + + if (ib_status != IB_SUCCESS) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, "--> DsIMU: Unbind MW failed = %s\n", + ib_get_err_str(ib_status)); + return (dapl_ib_status_convert (ib_status)); + } + + rmr->param.rmr_context = (DAT_RMR_CONTEXT) cl_ntoh32(new_rkey); + + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + "--> DsIMU: unbind new_rkey 0x%x\n", rmr->param.rmr_context); + + return (DAT_SUCCESS); +} + + +/* + * dapls_ib_setup_async_callback + * + * Set up an asynchronous callbacks of various kinds + * + * Input: + * ia_handle IA handle + * handler_type type of handler to set up + * callback_handle handle param for completion callbacks + * callback callback routine pointer + * context argument for callback routine + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + * + */ +DAT_RETURN +dapls_ib_setup_async_callback ( + IN DAPL_IA *ia_ptr, + IN DAPL_ASYNC_HANDLER_TYPE handler_type, + IN DAPL_EVD *evd_ptr, + IN ib_async_handler_t callback, + IN void *context ) +{ + dapl_ibal_ca_t *p_ca; + dapl_ibal_evd_cb_t *evd_cb; + + dapl_dbg_log (DAPL_DBG_TYPE_UTIL, + " setup_async_cb: ia %p type %d hdl %p cb %p ctx %p\n", + ia_ptr, handler_type, evd_ptr, callback, context); + + p_ca = (dapl_ibal_ca_t *) ia_ptr->hca_ptr->ib_hca_handle; + + if (p_ca == NULL) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, "--> DsISAC: can't find %s HCA\n", + (ia_ptr->header.provider)->device_name); + return (DAT_INVALID_HANDLE); + } + + if (handler_type != DAPL_ASYNC_CQ_COMPLETION) + { + evd_cb = dapli_find_evd_cb_by_context (context, p_ca); + + if (evd_cb == NULL) + { + /* + * No record for this evd. We allocate one + */ + evd_cb = dapl_os_alloc (sizeof (dapl_ibal_evd_cb_t)); + dapl_os_memzero (evd_cb, sizeof(dapl_ibal_evd_cb_t)); + + if (evd_cb == NULL) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "--> %s: can't alloc res\n","DsISAC"); + return (DAT_INSUFFICIENT_RESOURCES); + } + + evd_cb->context = context; + + /* + * Add the new EVD CB to the list + */ + LOCK_INSERT_TAIL( p_ca->evd_cb_lock, + p_ca->evd_cb_head, + evd_cb->next ); + } + + switch (handler_type) + { + case DAPL_ASYNC_UNAFILIATED: + evd_cb->pfn_async_err_cb = callback; + break; + case DAPL_ASYNC_CQ_ERROR: + evd_cb->pfn_async_cq_err_cb = callback; + break; + case DAPL_ASYNC_QP_ERROR: + evd_cb->pfn_async_qp_err_cb = callback; + break; + default: + break; + } + + } + + return DAT_SUCCESS; +} + + +/* + * dapls_ib_query_gid + * + * Query the hca for the gid of the 1st active port. + * + * Input: + * hca_handl hca handle + * ep_attr attribute of the ep + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + * DAT_INVALID_PARAMETER + */ + +DAT_RETURN +dapls_ib_query_gid( IN DAPL_HCA *hca_ptr, + IN GID *gid ) +{ + dapl_ibal_ca_t *p_ca; + ib_ca_attr_t *p_hca_attr; + ib_api_status_t ib_status; + ib_hca_port_t port_num; + + p_ca = (dapl_ibal_ca_t *) hca_ptr->ib_hca_handle; + + if (p_ca == NULL) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "%s() invalid hca_ptr %p", __FUNCTION__, hca_ptr); + return DAT_INVALID_HANDLE; + } + + ib_status = ib_query_ca ( + p_ca->h_ca, + p_ca->p_ca_attr, + &p_ca->ca_attr_size); + if (ib_status != IB_SUCCESS) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "%s() ib_query_ca returned failed status = %s\n", + ib_get_err_str(ib_status)); + return dapl_ib_status_convert (ib_status); + } + + p_hca_attr = p_ca->p_ca_attr; + port_num = hca_ptr->port_num - 1; + + gid->gid_prefix = p_hca_attr->p_port_attr[port_num].p_gid_table->unicast.prefix; + gid->guid = p_hca_attr->p_port_attr[port_num].p_gid_table->unicast.interface_id; + return DAT_SUCCESS; +} + + +/* + * dapls_ib_query_hca + * + * Query the hca attribute + * + * Input: + * hca_handl hca handle + * ep_attr attribute of the ep + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + */ + +DAT_RETURN dapls_ib_query_hca ( + IN DAPL_HCA *hca_ptr, + OUT DAT_IA_ATTR *ia_attr, + OUT DAT_EP_ATTR *ep_attr, + OUT DAT_SOCK_ADDR6 *ip_addr) +{ + ib_ca_attr_t *p_hca_attr; + dapl_ibal_ca_t *p_ca; + ib_api_status_t ib_status; + ib_hca_port_t port_num; + GID gid; + DAT_SOCK_ADDR6 *p_sock_addr; + DAT_RETURN dat_status = DAT_SUCCESS; + port_num = hca_ptr->port_num; + + p_ca = (dapl_ibal_ca_t *) hca_ptr->ib_hca_handle; + + if (p_ca == NULL) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, "--> %s: invalid handle %p", + "DsIQH", hca_ptr); + return (DAT_INVALID_HANDLE); + } + + ib_status = ib_query_ca ( + p_ca->h_ca, + p_ca->p_ca_attr, + &p_ca->ca_attr_size); + if (ib_status != IB_SUCCESS) + { + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + "--> DsIQH: ib_query_ca returned failed status = %s\n", + ib_get_err_str(ib_status)); + return (dapl_ib_status_convert (ib_status)); + } + + p_hca_attr = p_ca->p_ca_attr; + + if (ip_addr != NULL) + { + p_sock_addr = dapl_os_alloc(sizeof(DAT_SOCK_ADDR6)); + if ( !p_sock_addr ) + { + dat_status = DAT_INSUFFICIENT_RESOURCES; + dapl_dbg_log ( DAPL_DBG_TYPE_ERR, + " Query Hca alloc Err: status %d\n", + dat_status); + return dat_status; + } + dapl_os_memzero(p_sock_addr, sizeof(DAT_SOCK_ADDR6)); + + gid.gid_prefix = p_hca_attr->p_port_attr[port_num-1].p_gid_table->unicast.prefix; + gid.guid = p_hca_attr->p_port_attr[port_num-1].p_gid_table->unicast.interface_id; + + dat_status = dapls_ns_map_ipaddr( hca_ptr, + gid, + (DAT_IA_ADDRESS_PTR)p_sock_addr); + + if ( dat_status != DAT_SUCCESS ) + { + dapl_dbg_log (DAPL_DBG_TYPE_ERR, + " SA Query for local IP failed= %d\n", dat_status ); + /* what to do next ? */ + } + else + { + dapl_dbg_log (DAPL_DBG_TYPE_CM, "SA query GID for IP: "); + dapl_dbg_log ( DAPL_DBG_TYPE_CM, "%0d:%d:%d:%d\n", + (uint8_t)((DAT_IA_ADDRESS_PTR )p_sock_addr)->sa_data[2]&0xff, + (uint8_t)((DAT_IA_ADDRESS_PTR )p_sock_addr)->sa_data[3]&0xff, + (uint8_t)((DAT_IA_ADDRESS_PTR )p_sock_addr)->sa_data[4]&0xff, + (uint8_t)((DAT_IA_ADDRESS_PTR )p_sock_addr)->sa_data[5]&0xff); + } + + hca_ptr->hca_address = *p_sock_addr; + + /* if structure address not from our hca_ptr */ + if ( ip_addr != &hca_ptr->hca_address ) + { + *ip_addr = *p_sock_addr; + } + + dapl_os_free (p_sock_addr, sizeof(DAT_SOCK_ADDR6)); + + } /* ip_addr != NULL */ + + if ( ia_attr != NULL ) + { + dapl_os_memzero( ia_attr->adapter_name, + (int)sizeof(ia_attr->adapter_name )); + dapl_os_memcpy(ia_attr->adapter_name, + DAT_ADAPTER_NAME, + min ( (int)dapl_os_strlen(DAT_ADAPTER_NAME), + (int)(DAT_NAME_MAX_LENGTH)-1 ) ); + + dapl_os_memzero ( ia_attr->vendor_name, + (int)sizeof(ia_attr->vendor_name) ); + dapl_os_memcpy ( ia_attr->vendor_name, + DAT_VENDOR_NAME, + min ( (int)dapl_os_strlen(DAT_VENDOR_NAME), + (int)(DAT_NAME_MAX_LENGTH)-1 ) ); + + /* FIXME : Vu + * this value should be revisited + * It can be set by DAT consumers + */ + ia_attr->ia_address_ptr = (DAT_PVOID)&hca_ptr->hca_address; + ia_attr->hardware_version_major = p_hca_attr->dev_id; + ia_attr->hardware_version_minor = p_hca_attr->revision; + ia_attr->max_eps = p_hca_attr->max_qps; + ia_attr->max_dto_per_ep = p_hca_attr->max_wrs; + ia_attr->max_rdma_read_per_ep = p_hca_attr->max_qp_resp_res; + ia_attr->max_evds = p_hca_attr->max_cqs; + ia_attr->max_evd_qlen = p_hca_attr->max_cqes; + ia_attr->max_iov_segments_per_dto = p_hca_attr->max_sges; + ia_attr->max_lmrs = p_hca_attr->init_regions; + ia_attr->max_lmr_block_size = p_hca_attr->init_region_size; + ia_attr->max_rmrs = p_hca_attr->init_windows; + ia_attr->max_lmr_virtual_address = p_hca_attr->max_addr_handles; + ia_attr->max_rmr_target_address = p_hca_attr->max_addr_handles; + ia_attr->max_pzs = p_hca_attr->max_pds; + /* + * DAT spec does not tie max_mtu_size with IB MTU + * + ia_attr->max_mtu_size = + dapl_ibal_mtu_table[p_hca_attr->p_port_attr->mtu]; + */ + ia_attr->max_mtu_size = + p_hca_attr->p_port_attr->max_msg_size; + ia_attr->max_rdma_size = + p_hca_attr->p_port_attr->max_msg_size; + ia_attr->num_transport_attr = 0; + ia_attr->transport_attr = NULL; + ia_attr->num_vendor_attr = 0; + ia_attr->vendor_attr = NULL; + ia_attr->max_iov_segments_per_rdma_read = p_hca_attr->max_sges; + +#ifdef DAT_EXTENSIONS + ia_attr->extension_supported = DAT_EXTENSION_IB; + ia_attr->extension_version = DAT_IB_EXTENSION_VERSION; +#endif + + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, + " --> DsIMU_qHCA: (ver=%x) ep %d ep_q %d evd %d evd_q %d\n", + ia_attr->hardware_version_major, + ia_attr->max_eps, ia_attr->max_dto_per_ep, + ia_attr->max_evds, ia_attr->max_evd_qlen ); + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, + " --> DsIMU_qHCA: mtu %llu rdma %llu iov %d lmr %d rmr %d" + " rdma_io %d\n", + ia_attr->max_mtu_size, ia_attr->max_rdma_size, + ia_attr->max_iov_segments_per_dto, ia_attr->max_lmrs, + ia_attr->max_rmrs, ia_attr->max_rdma_read_per_ep ); + } + + if ( ep_attr != NULL ) + { + (void) dapl_os_memzero(ep_attr, sizeof(*ep_attr)); + /* + * DAT spec does not tie max_mtu_size with IB MTU + * + ep_attr->max_mtu_size = + dapl_ibal_mtu_table[p_hca_attr->p_port_attr->mtu]; + */ + ep_attr->max_mtu_size = p_hca_attr->p_port_attr->max_msg_size; + ep_attr->max_rdma_size = p_hca_attr->p_port_attr->max_msg_size; + ep_attr->max_recv_dtos = p_hca_attr->max_wrs; + ep_attr->max_request_dtos = p_hca_attr->max_wrs; + ep_attr->max_recv_iov = p_hca_attr->max_sges; + ep_attr->max_request_iov = p_hca_attr->max_sges; + ep_attr->max_rdma_read_in = p_hca_attr->max_qp_resp_res; + ep_attr->max_rdma_read_out= p_hca_attr->max_qp_resp_res; + + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, + " --> DsIMU_qHCA: msg %llu dto %d iov %d rdma i%d,o%d\n", + ep_attr->max_mtu_size, + ep_attr->max_recv_dtos, ep_attr->max_recv_iov, + ep_attr->max_rdma_read_in, ep_attr->max_rdma_read_out); + } + return DAT_SUCCESS; +} + + +DAT_RETURN +dapls_ib_completion_poll ( IN DAPL_HCA *p_hca, + IN DAPL_EVD *p_evd, + IN ib_work_completion_t *cqe_ptr ) +{ + ib_api_status_t ib_status; + ib_work_completion_t *cqe_filled; + + /* + * FIXME - Vu + * Now we only poll for one cqe. We can poll for more than + * one completions later for better. However, this requires + * to change the logic in dapl_evd_dto_callback function + * to process more than one completion. + */ + cqe_ptr->p_next = NULL; + cqe_filled = NULL; + + if ( !p_hca->ib_hca_handle ) + { + return DAT_INVALID_HANDLE; + } + + ib_status = ib_poll_cq (p_evd->ib_cq_handle, &cqe_ptr, &cqe_filled); + + if ( ib_status == IB_INVALID_CQ_HANDLE ) + { + ib_status = IB_NOT_FOUND; + } + + return dapl_ib_status_convert (ib_status); +} + + +DAT_RETURN +dapls_ib_completion_notify ( IN ib_hca_handle_t hca_handle, + IN DAPL_EVD *p_evd, + IN ib_notification_type_t type ) +{ + ib_api_status_t ib_status; + DAT_BOOLEAN solic_notify; + + if ( !hca_handle ) + { + return DAT_INVALID_HANDLE; + } + solic_notify = (type == IB_NOTIFY_ON_SOLIC_COMP) ? DAT_TRUE : DAT_FALSE; + ib_status = ib_rearm_cq ( p_evd->ib_cq_handle, solic_notify ); + + return dapl_ib_status_convert (ib_status); +} + +DAT_RETURN +dapls_evd_dto_wakeup ( + IN DAPL_EVD *evd_ptr) +{ + return dapl_os_wait_object_wakeup(&evd_ptr->wait_object); +} + +DAT_RETURN +dapls_evd_dto_wait ( + IN DAPL_EVD *evd_ptr, + IN uint32_t timeout) +{ + return dapl_os_wait_object_wait(&evd_ptr->wait_object, timeout); +} + +/* + * dapls_ib_get_async_event + * + * Translate an asynchronous event type to the DAT event. + * Note that different providers have different sets of errors. + * + * Input: + * cause_ptr provider event cause + * + * Output: + * async_event DAT mapping of error + * + * Returns: + * DAT_SUCCESS + * DAT_NOT_IMPLEMENTED Caller is not interested this event + */ + +DAT_RETURN dapls_ib_get_async_event( + IN ib_async_event_rec_t *cause_ptr, + OUT DAT_EVENT_NUMBER *async_event) +{ + ib_async_event_t event_id; + DAT_RETURN dat_status; + + dat_status = DAT_SUCCESS; + event_id = cause_ptr->code; + + dapl_dbg_log (DAPL_DBG_TYPE_WARN, "--> DsAE: event_id = %d%d\n", event_id); + + switch (event_id ) + { + case IB_AE_SQ_ERROR: + case IB_AE_SQ_DRAINED: + case IB_AE_RQ_ERROR: + { + *async_event = DAT_ASYNC_ERROR_EP_BROKEN; + break; + } + + /* INTERNAL errors */ + case IB_AE_QP_FATAL: + case IB_AE_CQ_ERROR: + case IB_AE_LOCAL_FATAL: + case IB_AE_WQ_REQ_ERROR: + case IB_AE_WQ_ACCESS_ERROR: + { + *async_event = DAT_ASYNC_ERROR_PROVIDER_INTERNAL_ERROR; + break; + } + + /* CATASTROPHIC errors */ + case IB_AE_FLOW_CTRL_ERROR: + case IB_AE_BUF_OVERRUN: + { + *async_event = DAT_ASYNC_ERROR_IA_CATASTROPHIC; + break; + } + + default: + { + /* + * Errors we are not interested in reporting: + * IB_AE_QP_APM + * IB_AE_PKEY_TRAP + * IB_AE_QKEY_TRAP + * IB_AE_MKEY_TRAP + * IB_AE_PORT_TRAP + * IB_AE_QP_APM_ERROR + * IB_AE_PORT_ACTIVE + * ... + */ + dat_status = DAT_NOT_IMPLEMENTED; + } + + } + + return dat_status; +} + +/* + * dapls_ib_get_dto_status + * + * Return the DAT status of a DTO operation + * + * Input: + * cqe_ptr pointer to completion queue entry + * + * Output: + * none + * + * Returns: + * Value from ib_status_map table above + */ + +DAT_DTO_COMPLETION_STATUS +dapls_ib_get_dto_status( + IN ib_work_completion_t *cqe_ptr) +{ + ib_uint32_t ib_status; + + ib_status = DAPL_GET_CQE_STATUS (cqe_ptr); + + switch (ib_status) + { + case IB_COMP_ST_SUCCESS : + return DAT_DTO_SUCCESS; + + case IB_COMP_ST_LOCAL_LEN_ERR: + return DAT_DTO_ERR_LOCAL_LENGTH; + + case IB_COMP_ST_LOCAL_OP_ERR: + return DAT_DTO_ERR_LOCAL_EP; + + case IB_COMP_ST_LOCAL_PROTECT_ERR: + return DAT_DTO_ERR_LOCAL_PROTECTION; + + case IB_COMP_ST_WR_FLUSHED_ERR: + return DAT_DTO_ERR_FLUSHED; + + case IB_COMP_ST_MW_BIND_ERR: + return DAT_RMR_OPERATION_FAILED; + + case IB_COMP_ST_REM_ACC_ERR: + return DAT_DTO_ERR_REMOTE_ACCESS; + + case IB_COMP_ST_REM_OP_ERR: + return DAT_DTO_ERR_REMOTE_RESPONDER; + + case IB_COMP_ST_RNR_COUNTER: + return DAT_DTO_ERR_RECEIVER_NOT_READY; + + case IB_COMP_ST_TRANSP_COUNTER: + return DAT_DTO_ERR_TRANSPORT; + + case IB_COMP_ST_REM_REQ_ERR: + return DAT_DTO_ERR_REMOTE_RESPONDER; + + case IB_COMP_ST_BAD_RESPONSE_ERR: + return DAT_DTO_ERR_BAD_RESPONSE; + + case IB_COMP_ST_EE_STATE_ERR: + case IB_COMP_ST_EE_CTX_NO_ERR: + return DAT_DTO_ERR_TRANSPORT; + + default: +#ifdef DAPL_DBG + dapl_dbg_log (DAPL_DBG_TYPE_ERR,"%s() unknown IB_COMP_ST %d(0x%x)\n", + __FUNCTION__,ib_status,ib_status); +#endif + return DAT_DTO_FAILURE; + } +} + + +/* + * Map all IBAPI DTO completion codes to the DAT equivelent. + * + * dapls_ib_get_dat_event + * + * Return a DAT connection event given a provider CM event. + * + * N.B. Some architectures combine async and CM events into a + * generic async event. In that case, dapls_ib_get_dat_event() + * and dapls_ib_get_async_event() should be entry points that + * call into a common routine. + * + * Input: + * ib_cm_event event provided to the dapl callback routine + * active switch indicating active or passive connection + * + * Output: + * none + * + * Returns: + * DAT_EVENT_NUMBER of translated provider value + */ + +DAT_EVENT_NUMBER +dapls_ib_get_dat_event ( + IN const ib_cm_events_t ib_cm_event, + IN DAT_BOOLEAN active) +{ + DAT_EVENT_NUMBER dat_event_num = 0; + UNREFERENCED_PARAMETER (active); + + switch ( ib_cm_event) + { + case IB_CME_CONNECTED: + dat_event_num = DAT_CONNECTION_EVENT_ESTABLISHED; + break; + case IB_CME_DISCONNECTED: + dat_event_num = DAT_CONNECTION_EVENT_DISCONNECTED; + break; + case IB_CME_DISCONNECTED_ON_LINK_DOWN: + dat_event_num = DAT_CONNECTION_EVENT_DISCONNECTED; + break; + case IB_CME_CONNECTION_REQUEST_PENDING: + dat_event_num = DAT_CONNECTION_REQUEST_EVENT; + break; + case IB_CME_CONNECTION_REQUEST_PENDING_PRIVATE_DATA: + dat_event_num = DAT_CONNECTION_REQUEST_EVENT; + break; + case IB_CME_DESTINATION_REJECT: + dat_event_num = DAT_CONNECTION_EVENT_NON_PEER_REJECTED; + break; + case IB_CME_DESTINATION_REJECT_PRIVATE_DATA: + dat_event_num = DAT_CONNECTION_EVENT_PEER_REJECTED; + break; + case IB_CME_DESTINATION_UNREACHABLE: + dat_event_num = DAT_CONNECTION_EVENT_UNREACHABLE; + break; + case IB_CME_TOO_MANY_CONNECTION_REQUESTS: + dat_event_num = DAT_CONNECTION_EVENT_NON_PEER_REJECTED; + break; + case IB_CME_LOCAL_FAILURE: + dat_event_num = DAT_CONNECTION_EVENT_BROKEN; + break; + case IB_CME_REPLY_RECEIVED: + case IB_CME_REPLY_RECEIVED_PRIVATE_DATA: + default: + break; + } +#if 0 + dapl_dbg_log (DAPL_DBG_TYPE_CM, + " dapls_ib_get_dat_event: event translation: (%s) " + "ib_event 0x%x dat_event 0x%x\n", + active ? "active" : "passive", + ib_cm_event, + dat_event_num); +#endif + return dat_event_num; +} + + +/* + * dapls_ib_get_dat_event + * + * Return a DAT connection event given a provider CM event. + * + * N.B. Some architectures combine async and CM events into a + * generic async event. In that case, dapls_ib_get_cm_event() + * and dapls_ib_get_async_event() should be entry points that + * call into a common routine. + * + * WARNING: In this implementation, there are multiple CM + * events that map to a single DAT event. Be very careful + * with provider routines that depend on this reverse mapping, + * they may have to accomodate more CM events than they + * 'naturally' would. + * + * Input: + * dat_event_num DAT event we need an equivelent CM event for + * + * Output: + * none + * + * Returns: + * ib_cm_event of translated DAPL value + */ +ib_cm_events_t +dapls_ib_get_cm_event ( + IN DAT_EVENT_NUMBER dat_event_num) +{ + ib_cm_events_t ib_cm_event = 0; + + switch (dat_event_num) + { + case DAT_CONNECTION_EVENT_ESTABLISHED: + ib_cm_event = IB_CME_CONNECTED; + break; + case DAT_CONNECTION_EVENT_DISCONNECTED: + ib_cm_event = IB_CME_DISCONNECTED; + break; + case DAT_CONNECTION_REQUEST_EVENT: + ib_cm_event = IB_CME_CONNECTION_REQUEST_PENDING; + break; + case DAT_CONNECTION_EVENT_NON_PEER_REJECTED: + ib_cm_event = IB_CME_DESTINATION_REJECT; + break; + case DAT_CONNECTION_EVENT_PEER_REJECTED: + ib_cm_event = IB_CME_DESTINATION_REJECT_PRIVATE_DATA; + break; + case DAT_CONNECTION_EVENT_UNREACHABLE: + ib_cm_event = IB_CME_DESTINATION_UNREACHABLE; + break; + case DAT_CONNECTION_EVENT_BROKEN: + ib_cm_event = IB_CME_LOCAL_FAILURE; + break; + default: + break; + } + + return ib_cm_event; +} + + + +/* + * dapls_set_provider_specific_attr + * + * Input: + * attr_ptr Pointer provider specific attributes + * + * Output: + * none + * + * Returns: + * void + */ + +#ifdef DAT_EXTENSIONS +static DAT_NAMED_ATTR ib_attrs[] = { + { + "DAT_EXTENSION_INTERFACE", "TRUE" + }, + { + DAT_IB_ATTR_FETCH_AND_ADD, "TRUE" + }, + { + DAT_IB_ATTR_CMP_AND_SWAP, "TRUE" + }, + { + DAT_IB_ATTR_IMMED_DATA, "TRUE" + }, +}; +#define SPEC_ATTR_SIZE( x ) (sizeof( x ) / sizeof( DAT_NAMED_ATTR)) +#else +static DAT_NAMED_ATTR *ib_attrs = NULL; +#define SPEC_ATTR_SIZE( x ) 0 +#endif + +void dapls_query_provider_specific_attr( + IN DAPL_IA *ia_ptr, + IN DAT_PROVIDER_ATTR *attr_ptr ) +{ + attr_ptr->num_provider_specific_attr = SPEC_ATTR_SIZE(ib_attrs); + attr_ptr->provider_specific_attr = ib_attrs; +} + + +DAT_RETURN dapls_ns_map_gid ( + IN DAPL_HCA *hca_ptr, + IN DAT_IA_ADDRESS_PTR remote_ia_address, + OUT GID *gid) +{ + return (dapls_ib_ns_map_gid (hca_ptr, remote_ia_address, gid)); +} + +DAT_RETURN dapls_ns_map_ipaddr ( + IN DAPL_HCA *hca_ptr, + IN GID gid, + OUT DAT_IA_ADDRESS_PTR remote_ia_address) +{ + return (dapls_ib_ns_map_ipaddr (hca_ptr, gid, remote_ia_address)); +} + + +#ifdef NOT_USED +/* + * dapls_ib_post_recv - defered.until QP ! in init state. + * + * Provider specific Post RECV function + */ + +DAT_RETURN +dapls_ib_post_recv_defered ( + IN DAPL_EP *ep_ptr, + IN DAPL_COOKIE *cookie, + IN DAT_COUNT num_segments, + IN DAT_LMR_TRIPLET *local_iov) +{ + ib_api_status_t ib_status; + ib_recv_wr_t *recv_wr, *rwr; + ib_local_ds_t *ds_array_p; + DAT_COUNT i, total_len; + + if (ep_ptr->qp_state != IB_QPS_INIT) + { + dapl_dbg_log (DAPL_DBG_TYPE_EP, "--> DsPR: BAD QP state(%s), not init? " + "EP %p QP %p cookie %p, num_seg %d\n", + ib_get_port_state_str(ep_ptr->qp_state), ep_ptr, + ep_ptr->qp_handle, cookie, num_segments); + return (DAT_INSUFFICIENT_RESOURCES); + } + + recv_wr = dapl_os_alloc (sizeof(ib_recv_wr_t) + + (num_segments*sizeof(ib_local_ds_t))); + if (NULL == recv_wr) + { + return (DAT_INSUFFICIENT_RESOURCES); + } + + dapl_os_memzero(recv_wr, sizeof(ib_recv_wr_t)); + recv_wr->wr_id = (DAT_UINT64) cookie; + recv_wr->num_ds = num_segments; + + ds_array_p = (ib_local_ds_t*)(recv_wr+1); + + recv_wr->ds_array = ds_array_p; + + //total_len = 0; + + for (total_len = i = 0; i < num_segments; i++, ds_array_p++) + { + ds_array_p->length = (uint32_t)local_iov[i].segment_length; + ds_array_p->lkey = cl_hton32(local_iov[i].lmr_context); + ds_array_p->vaddr = local_iov[i].virtual_address; + total_len += ds_array_p->length; + } + + if (cookie != NULL) + { + cookie->val.dto.size = total_len; + + dapl_dbg_log (DAPL_DBG_TYPE_EP, + "--> DsPR: EP = %p QP = %p cookie= %p, num_seg= %d\n", + ep_ptr, ep_ptr->qp_handle, cookie, num_segments); + } + + recv_wr->p_next = NULL; + + /* find last defered recv work request, link new on the end */ + rwr=ep_ptr->cm_post; + if (rwr == NULL) + { + ep_ptr->cm_post = (void*)recv_wr; + i = 1; + } + else + { + for(i=2; rwr->p_next; rwr=rwr->p_next) i++; + rwr->p_next = recv_wr; + } + + dapl_dbg_log (DAPL_DBG_TYPE_EP, "--> DsPR: %s() EP %p QP %p cookie %p " + "num_seg %d Tdefered %d\n", + __FUNCTION__, ep_ptr, ep_ptr->qp_handle, cookie, num_segments, + i); + + return DAT_SUCCESS; +} +#endif + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ + diff --git a/branches/WOF2-3/ulp/dapl2/dapl/ibal/dapl_ibal_util.h b/branches/WOF2-3/ulp/dapl2/dapl/ibal/dapl_ibal_util.h new file mode 100644 index 00000000..e28bdbe4 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/ibal/dapl_ibal_util.h @@ -0,0 +1,602 @@ + +/* + * Copyright (c) 2005-2007 Intel Corporation. All rights reserved. + * Copyright (c) 2002, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under the terms of the "Common Public + * License" a copy of which is in the file LICENSE.txt in the root + * directory. The license is also available from the Open Source + * Initiative, see http://www.opensource.org/licenses/cpl.php. + * + */ + +/********************************************************************** + * + * MODULE: dapl_ibal_util.h + * + * PURPOSE: Utility defs & routines for access to openib-windows IBAL APIs + * + * $Id: dapl_ibal_util.h 33 2005-07-11 19:51:17Z ftillier $ + * + **********************************************************************/ + +#ifndef _DAPL_IBAL_UTIL_H_ +#define _DAPL_IBAL_UTIL_H_ + +#include +#include +#include +#include + +#ifdef DAT_EXTENSIONS +#include +#endif + +/* + * Typedefs to map IBAL types to more generic 'ib' types + */ +#ifdef SOCK_CM +typedef struct ib_cm_handle *dp_ib_cm_handle_t; +typedef struct ib_cm_handle *ib_cm_srvc_handle_t; +#else + +/* EP-CM linking requires list_entry, protected ref counting */ +typedef struct dapl_ibal_cm +{ + struct dapl_llist_entry list_entry; + DAPL_OS_LOCK lock; + int ref_count; + DAT_SOCK_ADDR6 dst_ip_addr; + ib_cm_handle_t ib_cm; /* h_al, h_qp, cid */ + DAPL_EP *ep; + +} dapl_ibal_cm_t; + +typedef dapl_ibal_cm_t *dp_ib_cm_handle_t; +typedef ib_listen_handle_t ib_cm_srvc_handle_t; + +/* EP-CM linking prototypes */ +extern void dapls_cm_acquire(dp_ib_cm_handle_t cm_ptr); +extern void dapls_cm_release(dp_ib_cm_handle_t cm_ptr); +extern void dapls_cm_free(dp_ib_cm_handle_t cm_ptr); +extern dp_ib_cm_handle_t ibal_cm_alloc(void); + +#endif + +typedef ib_net64_t IB_HCA_NAME; +typedef ib_ca_handle_t ib_hca_handle_t; +typedef DAT_PVOID ib_cqd_handle_t; +typedef ib_async_event_rec_t ib_error_record_t; +typedef ib_wr_type_t ib_send_op_type_t; +typedef ib_wc_t ib_work_completion_t; +typedef uint32_t ib_hca_port_t; +typedef uint32_t ib_uint32_t; +typedef ib_local_ds_t ib_data_segment_t; + +typedef unsigned __int3264 cl_dev_handle_t; + + +typedef void (*ib_async_handler_t)( + IN ib_hca_handle_t ib_hca_handle, + IN ib_error_record_t *err_code, + IN void *context); + +typedef void (*ib_async_qp_handler_t)( + IN ib_hca_handle_t ib_hca_handle, + IN ib_qp_handle_t ib_qp_handle, + IN ib_error_record_t *err_code, + IN void *context); + +typedef void (*ib_async_cq_handler_t)( + IN ib_hca_handle_t ib_hca_handle, + IN ib_cq_handle_t ib_cq_handle, + IN ib_error_record_t *err_code, + IN void *context); + +typedef ib_net64_t ib_guid_t; +typedef ib_net16_t ib_lid_t; +typedef boolean_t ib_bool_t; + +typedef struct _GID +{ + uint64_t gid_prefix; + uint64_t guid; +} GID; + +typedef enum +{ + IB_CME_CONNECTED, + IB_CME_DISCONNECTED, + IB_CME_DISCONNECTED_ON_LINK_DOWN, + IB_CME_CONNECTION_REQUEST_PENDING, + IB_CME_CONNECTION_REQUEST_PENDING_PRIVATE_DATA, + IB_CME_DESTINATION_REJECT, + IB_CME_DESTINATION_REJECT_PRIVATE_DATA, + IB_CME_DESTINATION_UNREACHABLE, + IB_CME_TOO_MANY_CONNECTION_REQUESTS, + IB_CME_LOCAL_FAILURE, + IB_CME_REPLY_RECEIVED, + IB_CME_REPLY_RECEIVED_PRIVATE_DATA, + IB_CM_LOCAL_FAILURE +} ib_cm_events_t; + + +typedef enum +{ + IB_NOTIFY_ON_NEXT_COMP, + IB_NOTIFY_ON_SOLIC_COMP +} ib_notification_type_t; + +typedef struct _ib_hca_name +{ + DAT_NAME_PTR hca_name[DAT_NAME_MAX_LENGTH]; +} ib_hca_name_t; + + +#define IB_INVALID_HANDLE NULL +#define true TRUE +#define false FALSE + +#define IB_MAX_REQ_PDATA_SIZE 92 +#define IB_MAX_REP_PDATA_SIZE 196 +#define IB_MAX_REJ_PDATA_SIZE 148 +#define IB_MAX_DREQ_PDATA_SIZE 220 +#define IB_MAX_DREP_PDATA_SIZE 224 + + +/* Resource Not Ready + 1-6 is an actual retry count which is decremented to zero before + an error condition is set. + 7 is 'magic' in that it implies Infinite retry, just keeps trying. +*/ +#define IB_RNR_RETRY_CNT 7 + +/* +IB 1.2 spec, page 331, table 45, RNR NAK timeout encoding (5-bits) + +00000=655.36ms(milliseconds) +00001=0.01ms +00010=0.02ms +00011=0.03ms +00100=0.04ms +00101=0.06ms +00110=0.08ms +00111=0.12ms + +11100=163.84ms 28d +11101=245.76ms 29d +11110=327.68ms 30d +11111=491.52ms 31d +*/ +#define IB_RNR_NAK_TIMEOUT 0 + + +typedef void +(*dapl_ibal_pfn_destructor_t)( + IN void* context ); + +typedef struct _dapl_ibal_refs +{ + atomic32_t count; // number of references + void* context; // context for destructor + dapl_ibal_pfn_destructor_t destructor; // called when reference goes to zero + +} dapl_ibal_refs_t; + + +typedef struct _dapl_ibal_root +{ + ib_al_handle_t h_al; // handle to Access Layer + cl_spinlock_t ca_lock; // CA list lock + cl_qlist_t ca_head; // list head of CAs + boolean_t shutdown; // when true, driver is shutting down + boolean_t initialized; // when true, lib is initialized + +} dapl_ibal_root_t; + + +typedef struct _dapl_ibal_ca +{ + cl_list_item_t next; // peer CA list + ib_ca_handle_t h_ca; // handle to open CA + ib_ca_attr_t *p_ca_attr; // CA attributes + uint32_t ca_attr_size;// size of ca attribute + dapl_ibal_refs_t refs; // reference counting + cl_spinlock_t port_lock; // port list lock + cl_qlist_t port_head; // port list head for this CA + cl_spinlock_t evd_cb_lock; // EVD async error cb list lock + cl_qlist_t evd_cb_head; // EVD async error cb list head for this CA + cl_dev_handle_t mlnx_device; + DAT_PVOID *ia_ptr; // hook for CA async callbacks +} dapl_ibal_ca_t; + + +typedef struct _dapl_ibal_port +{ + cl_list_item_t next; // peer CA list + dapl_ibal_ca_t *ca; // pointer to parent CA + ib_port_attr_t *p_attr; // port attributes + dapl_ibal_refs_t refs; // reference counting +} dapl_ibal_port_t; + +typedef struct _dapl_ibal_evd_cb +{ + cl_list_item_t next; // peer CA list + ib_async_handler_t pfn_async_err_cb; + ib_async_qp_handler_t pfn_async_qp_err_cb; + ib_async_cq_handler_t pfn_async_cq_err_cb; + void *context; +} dapl_ibal_evd_cb_t; + +/* + * Definitions to map DTO OPs to IBAL Work-Request ops. + */ +#define OP_BAD_OPCODE 0 +#define OP_RDMA_READ WR_RDMA_READ +#define OP_RDMA_WRITE WR_RDMA_WRITE +#define OP_SEND WR_SEND +#define OP_COMP_AND_SWAP WR_COMPARE_SWAP +#define OP_FETCH_AND_ADD WR_FETCH_ADD + +#define OP_RECEIVE 8 /* (8) */ +#define OP_BIND_MW 9 /* no-equivalent */ +#define OP_RDMA_WRITE_IMM 10 /* RDMA_WRITE+Immediate data */ +#define OP_RECEIVE_IMM 11 /* no-equivalent */ + +/* + * Definitions to map QP state + */ +#define IB_QP_STATE_RESET IB_QPS_RESET +#define IB_QP_STATE_INIT IB_QPS_INIT +#define IB_QP_STATE_RTR IB_QPS_RTR +#define IB_QP_STATE_RTS IB_QPS_RTS +#define IB_QP_STATE_SQE IB_QPS_SQERR +#define IB_QP_STATE_SQD IB_QPS_SQD +#define IB_QP_STATE_ERROR IB_QPS_ERROR + +/* + * Definitions to map Memory OPs + */ +#define IB_ACCESS_LOCAL_WRITE IB_AC_LOCAL_WRITE +#define IB_ACCESS_REMOTE_READ IB_AC_RDMA_READ +#define IB_ACCESS_REMOTE_WRITE IB_AC_RDMA_WRITE +#define IB_ACCESS_REMOTE_ATOMIC IB_AC_ATOMIC +#define IB_ACCESS_MEM_WINDOW_BIND IB_AC_MW_BIND + +/* + * CQE status + */ +enum _dapl_comp_status +{ + IB_COMP_ST_SUCCESS = IB_WCS_SUCCESS, + IB_COMP_ST_LOCAL_LEN_ERR = IB_WCS_LOCAL_LEN_ERR, + IB_COMP_ST_LOCAL_OP_ERR = IB_WCS_LOCAL_OP_ERR, + IB_COMP_ST_LOCAL_PROTECT_ERR = IB_WCS_LOCAL_PROTECTION_ERR, + IB_COMP_ST_WR_FLUSHED_ERR = IB_WCS_WR_FLUSHED_ERR, + IB_COMP_ST_MW_BIND_ERR = IB_WCS_MEM_WINDOW_BIND_ERR, + IB_COMP_ST_REM_ACC_ERR = IB_WCS_REM_ACCESS_ERR, + IB_COMP_ST_REM_OP_ERR = IB_WCS_REM_OP_ERR, + IB_COMP_ST_RNR_COUNTER = IB_WCS_RNR_RETRY_ERR, + IB_COMP_ST_TRANSP_COUNTER = IB_WCS_TIMEOUT_RETRY_ERR, + IB_COMP_ST_REM_REQ_ERR = IB_WCS_REM_INVALID_REQ_ERR, + IB_COMP_ST_BAD_RESPONSE_ERR = IB_WCS_UNMATCHED_RESPONSE, + IB_COMP_ST_EE_STATE_ERR, + IB_COMP_ST_EE_CTX_NO_ERR +}; + + +/* + * Macro to check the state of an EP/QP + */ +#define DAPLIB_NEEDS_INIT(ep) ((ep)->qp_state == IB_QPS_ERROR) + + +/* + * Resolve IBAL return codes to their DAPL equivelent. + * Do not return invalid Handles, the user is not able + * to deal with them. + */ +STATIC _INLINE_ DAT_RETURN +dapl_ib_status_convert ( + IN int32_t ib_status) +{ + switch ( ib_status ) + { + case IB_SUCCESS: + { + return DAT_SUCCESS; + } + case IB_INSUFFICIENT_RESOURCES: + case IB_INSUFFICIENT_MEMORY: + case IB_RESOURCE_BUSY: + { + return DAT_INSUFFICIENT_RESOURCES; + } + case IB_INVALID_CA_HANDLE: + case IB_INVALID_CQ_HANDLE: + case IB_INVALID_QP_HANDLE: + case IB_INVALID_PD_HANDLE: + case IB_INVALID_MR_HANDLE: + case IB_INVALID_MW_HANDLE: + case IB_INVALID_AL_HANDLE: + case IB_INVALID_AV_HANDLE: + { + return DAT_INVALID_HANDLE; + } + case IB_INVALID_PKEY: + { + return DAT_PROTECTION_VIOLATION; + } + case IB_INVALID_LKEY: + case IB_INVALID_RKEY: + case IB_INVALID_PERMISSION: + { + return DAT_PRIVILEGES_VIOLATION; + } + case IB_INVALID_MAX_WRS: + case IB_INVALID_MAX_SGE: + case IB_INVALID_CQ_SIZE: + case IB_INVALID_SETTING: + case IB_INVALID_SERVICE_TYPE: + case IB_INVALID_GID: + case IB_INVALID_LID: + case IB_INVALID_GUID: + case IB_INVALID_PARAMETER: + { + return DAT_INVALID_PARAMETER; + } + case IB_INVALID_QP_STATE: + case IB_INVALID_APM_STATE: + case IB_INVALID_PORT_STATE: + case IB_INVALID_STATE: + { + return DAT_INVALID_STATE; + } + case IB_NOT_FOUND: + { + return DAT_QUEUE_EMPTY; + } + case IB_OVERFLOW: + { + return DAT_QUEUE_FULL; + } + case IB_UNSUPPORTED: + { + return DAT_NOT_IMPLEMENTED; + } + case IB_TIMEOUT: + { + return DAT_TIMEOUT_EXPIRED; + } + case IB_CANCELED: + { + return DAT_ABORT; + } + default: + { + return DAT_INTERNAL_ERROR; + } + } +} + +#define TAKE_LOCK( lock ) \ + cl_spinlock_acquire( &(lock) ) + +#define RELEASE_LOCK( lock ) \ + cl_spinlock_release( &(lock) ) + +#define LOCK_INSERT_HEAD( lock, head, item ) \ +{ \ + TAKE_LOCK( lock ); \ + cl_qlist_insert_head( &head, (cl_list_item_t*)(&item) ); \ + RELEASE_LOCK( lock ); \ +} + +#define LOCK_INSERT_TAIL( lock, tail, item ) \ +{ \ + TAKE_LOCK( lock ); \ + cl_qlist_insert_tail( &tail, (cl_list_item_t*)(&item) ); \ + RELEASE_LOCK( lock ); \ +} + +#define INIT_REFERENCE( p_ref, n, con, destruct ) \ +{ \ + (p_ref)->count = n; \ + (p_ref)->context = con; \ + (p_ref)->destructor = destruct; \ +} + +#define TAKE_REFERENCE( p_ref ) \ + cl_atomic_inc( &(p_ref)->count ) + +#define REMOVE_REFERENCE( p_ref ) \ +{ \ + if ( cl_atomic_dec( &(p_ref)->count ) == 0 ) \ + if ( (p_ref)->destructor ) \ + (p_ref)->destructor( (p_ref)->context ); \ +} + +/* + * dapl_llist_entry in dapl.h but dapl.h depends on provider + * typedef's in this file first. move dapl_llist_entry out of dapl.h + */ +struct ib_llist_entry +{ + struct dapl_llist_entry *flink; + struct dapl_llist_entry *blink; + void *data; + struct dapl_llist_entry *list_head; +}; + +#ifdef SOCK_CM + +typedef enum +{ + IB_THREAD_INIT, + IB_THREAD_RUN, + IB_THREAD_CANCEL, + IB_THREAD_EXIT + +} ib_thread_state_t; + +typedef enum scm_state +{ + SCM_INIT, + SCM_LISTEN, + SCM_CONN_PENDING, + SCM_ACCEPTING, + SCM_ACCEPTED, + SCM_REJECTED, + SCM_CONNECTED, + SCM_DISCONNECTED, + SCM_DESTROY + +} SCM_STATE; + +#endif /* SOCK_CM */ + +typedef struct _ib_hca_transport +{ +#ifdef SOCK_CM + int max_inline_send; + ib_thread_state_t cr_state; /* CR thread */ + DAPL_OS_THREAD thread; /* CR thread */ + DAPL_OS_LOCK lock; /* CR serialization */ + struct ib_llist_entry *list; /* Connection Requests */ +#endif + struct dapl_hca *d_hca; + DAPL_OS_WAIT_OBJECT wait_object; + DAPL_ATOMIC handle_ref_count; /* # of ia_opens on handle */ + ib_cqd_handle_t ib_cqd_handle; /* cq domain handle */ + + /* Name service support */ + void *name_service_handle; + +} ib_hca_transport_t; + +/* provider specfic fields for shared memory support */ +typedef uint32_t ib_shm_transport_t; + +#ifdef SOCK_CM + +/* inline send rdma threshold */ +#define INLINE_SEND_DEFAULT 128 + +/* CM mappings use SOCKETS */ + +/* destination info exchanged between dapl, define wire protocol version */ +#define DSCM_VER 2 + +typedef struct _ib_qp_cm +{ + ib_net16_t ver; + ib_net16_t rej; + ib_net16_t lid; + ib_net16_t port; + ib_net32_t qpn; + ib_net32_t p_size; + DAT_SOCK_ADDR6 ia_address; + GID gid; + +} ib_qp_cm_t; + +struct ib_cm_handle +{ + struct ib_llist_entry entry; + DAPL_OS_LOCK lock; + SCM_STATE state; + int socket; + int l_socket; + struct dapl_hca *hca; + DAT_HANDLE sp; + DAT_HANDLE cr; + struct dapl_ep *ep; + ib_qp_cm_t dst; + unsigned char p_data[256]; +}; + +DAT_RETURN dapli_init_sock_cm ( IN DAPL_HCA *hca_ptr ); + +#endif /* SOCK_CM */ + +/* + * Prototype + */ + +extern ib_api_status_t +dapls_modify_qp_state_to_error ( + ib_qp_handle_t qp_handle ); + +extern ib_api_status_t +dapls_modify_qp_state_to_reset ( + ib_qp_handle_t); + +extern ib_api_status_t +dapls_modify_qp_state_to_init ( + ib_qp_handle_t, DAT_EP_ATTR *, dapl_ibal_port_t *); + +extern ib_api_status_t +dapls_modify_qp_state_to_rtr ( + ib_qp_handle_t, ib_net32_t, ib_lid_t, dapl_ibal_port_t *); + +extern ib_api_status_t +dapls_modify_qp_state_to_rts ( + ib_qp_handle_t); + +extern void +dapli_ibal_ca_async_error_callback( + IN ib_async_event_rec_t* p_err_rec ); + +extern dapl_ibal_port_t * +dapli_ibal_get_port ( + IN dapl_ibal_ca_t *p_ca, + IN uint8_t port_num); + +extern int32_t dapls_ib_init (void); +extern int32_t dapls_ib_release (void); + +extern dapl_ibal_evd_cb_t * +dapli_find_evd_cb_by_context( + IN void *context, + IN dapl_ibal_ca_t *ca); + +extern IB_HCA_NAME +dapl_ib_convert_name(IN char *name); + +STATIC _INLINE_ int32_t +dapli_ibal_convert_privileges (IN DAT_MEM_PRIV_FLAGS privileges ) +{ + int32_t value = DAT_MEM_PRIV_NONE_FLAG; + + /* + * if (DAT_MEM_PRIV_LOCAL_READ_FLAG & privileges) + * do nothing + */ + if (DAT_MEM_PRIV_LOCAL_WRITE_FLAG & privileges) + value |= IB_ACCESS_LOCAL_WRITE; + + if (DAT_MEM_PRIV_REMOTE_WRITE_FLAG & privileges) + value |= IB_ACCESS_REMOTE_WRITE; + + if (DAT_MEM_PRIV_REMOTE_READ_FLAG & privileges) + value |= IB_ACCESS_REMOTE_READ; + +#ifdef DAT_EXTENSIONS + if (DAT_IB_MEM_PRIV_REMOTE_ATOMIC & privileges) + value |= IB_ACCESS_REMOTE_ATOMIC; +#endif + +#ifdef DAPL_DBG + if (value == DAT_MEM_PRIV_NONE_FLAG) + { + dapl_dbg_log(DAPL_DBG_TYPE_ERR,"%s() Unknown DAT_MEM_PRIV_ 0x%x\n", + __FUNCTION__,privileges); + } +#endif + return value; +} + +#define dapl_rmr_convert_privileges(p) dapli_ibal_convert_privileges(p) +#define dapl_lmr_convert_privileges(p) dapli_ibal_convert_privileges(p) + +#endif /* _DAPL_IBAL_UTIL_H_ */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/ibal/makefile b/branches/WOF2-3/ulp/dapl2/dapl/ibal/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/ibal/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\..\inc\openib.def diff --git a/branches/WOF2-3/ulp/dapl2/dapl/ibal/udapl.rc b/branches/WOF2-3/ulp/dapl2/dapl/ibal/udapl.rc new file mode 100644 index 00000000..e5fc1ace --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/ibal/udapl.rc @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2007 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#if DBG +#define VER_FILEDESCRIPTION_STR "Direct Access Provider Library v2.0 (IBAL) (Debug)" +#define VER_INTERNALNAME_STR "dapl2d.dll" +#define VER_ORIGINALFILENAME_STR "dapl2d.dll" +#else +#define VER_FILEDESCRIPTION_STR "Direct Access Provider Library v2.0 (IBAL)" +#define VER_INTERNALNAME_STR "dapl2.dll" +#define VER_ORIGINALFILENAME_STR "dapl2.dll" +#endif + +#include diff --git a/branches/WOF2-3/ulp/dapl2/dapl/ibal/udapl_exports.src b/branches/WOF2-3/ulp/dapl2/dapl/ibal/udapl_exports.src new file mode 100644 index 00000000..54b403bc --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/ibal/udapl_exports.src @@ -0,0 +1,14 @@ +#if DBG +LIBRARY dapl2d.dll +#else +LIBRARY dapl2.dll +#endif + + +EXPORTS +dat_provider_init +dat_provider_fini +#ifdef DAT_EXTENSIONS +dapl_extensions +#endif + diff --git a/branches/WOF2-3/ulp/dapl2/dapl/include/dapl.h b/branches/WOF2-3/ulp/dapl2/dapl/include/dapl.h new file mode 100644 index 00000000..8dab61e6 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/include/dapl.h @@ -0,0 +1,1269 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl.h + * + * PURPOSE: defines common data structures for the DAPL reference implemenation + * + * Description: This file describes the working data structures used within + * DAPL RI. + * + * + * $Id: dapl.h 1317 2005-04-25 17:29:42Z jlentini $ + **********************************************************************/ + +#ifndef _DAPL_H_ +#define _DAPL_H_ + +#if defined(__KERNEL__) +#include +#else +#include +#endif /* defined(__KERNEL__) */ +#include +#include "dapl_osd.h" +#include "dapl_debug.h" + + + +/********************************************************************* + * * + * Enumerations * + * * + *********************************************************************/ + +typedef enum dapl_magic +{ + /* magic number values for verification & debug */ + DAPL_MAGIC_IA = 0xCafeF00d, + DAPL_MAGIC_EVD = 0xFeedFace, + DAPL_MAGIC_EP = 0xDeadBabe, + DAPL_MAGIC_LMR = 0xBeefCafe, + DAPL_MAGIC_RMR = 0xABadCafe, + DAPL_MAGIC_PZ = 0xDeafBeef, + DAPL_MAGIC_PSP = 0xBeadeD0c, + DAPL_MAGIC_RSP = 0xFab4Feed, + DAPL_MAGIC_SRQ = 0xC001Babe, + DAPL_MAGIC_CR = 0xBe12Cee1, + DAPL_MAGIC_CR_DESTROYED = 0xB12bDead, + DAPL_MAGIC_CNO = 0xDeadF00d, + DAPL_MAGIC_INVALID = 0xFFFFFFFF +} DAPL_MAGIC; + +typedef enum dapl_evd_state +{ + DAPL_EVD_STATE_TERMINAL, + DAPL_EVD_STATE_INITIAL, + DAPL_EVD_STATE_OPEN, + DAPL_EVD_STATE_WAITED, + DAPL_EVD_STATE_DEAD = 0xDEAD +} DAPL_EVD_STATE; + +typedef enum dapl_evd_completion +{ + DAPL_EVD_STATE_INIT, + DAPL_EVD_STATE_SOLICITED_WAIT, + DAPL_EVD_STATE_THRESHOLD, + DAPL_EVD_STATE_UNSIGNALLED +} DAPL_EVD_COMPLETION; + +typedef enum dapl_cno_state +{ + DAPL_CNO_STATE_UNTRIGGERED, + DAPL_CNO_STATE_TRIGGERED, + DAPL_CNO_STATE_DEAD = 0xDeadFeed, +} DAPL_CNO_STATE; + +typedef enum dapl_qp_state +{ + DAPL_QP_STATE_UNCONNECTED, + DAPL_QP_STATE_RESERVED, + DAPL_QP_STATE_PASSIVE_CONNECTION_PENDING, + DAPL_QP_STATE_ACTIVE_CONNECTION_PENDING, + DAPL_QP_STATE_TENTATIVE_CONNECTION_PENDING, + DAPL_QP_STATE_CONNECTED, + DAPL_QP_STATE_DISCONNECT_PENDING, + DAPL_QP_STATE_ERROR, + DAPL_QP_STATE_NOT_REUSABLE, + DAPL_QP_STATE_FREE +} DAPL_QP_STATE; + + +/********************************************************************* + * * + * Constants * + * * + *********************************************************************/ + +/* + * number of HCAs allowed + */ +#define DAPL_MAX_HCA_COUNT 4 + +/* + * Configures the RMR bind evd restriction + */ + +#define DAPL_RMR_BIND_EVD_RESTRICTION DAT_RMR_EVD_SAME_AS_REQUEST_EVD + +/* + * special qp_state indicating the EP does not have a QP attached yet + */ +#define DAPL_QP_STATE_UNATTACHED 0xFFF0 + +#define DAPL_MAX_PRIVATE_DATA_SIZE 256 + +/********************************************************************* + * * + * Macros * + * * + *********************************************************************/ + +#if defined (sun) || defined(__sun) || defined(_sun_) || defined (__solaris__) +#define DAPL_BAD_PTR(a) ((unsigned long)(a) & 3) +#elif defined(__linux__) +#define DAPL_BAD_PTR(a) ((unsigned long)(a) & 3) +#elif defined(_WIN64) +#define DAPL_BAD_PTR(a) ((unsigned long)((DAT_UINT64)(a)) & 3) +#elif defined(_WIN32) +#define DAPL_BAD_PTR(a) ((unsigned long)((DAT_UINT64)(a)) & 3) +#endif + +/* + * Simple macro to verify a handle is bad. Conditions: + * - pointer is NULL + * - pointer is not word aligned + * - pointer's magic number is wrong + */ + +#define DAPL_BAD_HANDLE(h, magicNum) ( \ + ((h) == NULL) || \ + DAPL_BAD_PTR(h) || \ + (((DAPL_HEADER *)(h))->magic != (magicNum))) + +#define DAPL_MIN(a, b) ((a < b) ? (a) : (b)) +#define DAPL_MAX(a, b) ((a > b) ? (a) : (b)) + +#if NDEBUG > 0 +#define DEBUG_IS_BAD_HANDLE(h, magicNum) (DAPL_BAD_HANDLE(h, magicNum)) +#else +#define DEBUG_IS_BAD_HANDLE(h, magicNum) (0) +#endif + +#define DAT_ERROR(Type, SubType) ((DAT_RETURN)(DAT_CLASS_ERROR | Type | SubType)) + +/********************************************************************* + * * + * Typedefs * + * * + *********************************************************************/ + +typedef struct dapl_llist_entry DAPL_LLIST_ENTRY; +typedef DAPL_LLIST_ENTRY * DAPL_LLIST_HEAD; +typedef struct dapl_ring_buffer DAPL_RING_BUFFER; +typedef struct dapl_cookie_buffer DAPL_COOKIE_BUFFER; + +typedef struct dapl_hash_table DAPL_HASH_TABLE; +typedef struct dapl_hash_table * DAPL_HASH_TABLEP; +typedef DAT_UINT64 DAPL_HASH_KEY; +typedef void * DAPL_HASH_DATA; + +typedef struct dapl_hca DAPL_HCA; + +typedef struct dapl_header DAPL_HEADER; + +typedef struct dapl_ia DAPL_IA; +typedef struct dapl_cno DAPL_CNO; +typedef struct dapl_evd DAPL_EVD; +typedef struct dapl_ep DAPL_EP; +typedef struct dapl_srq DAPL_SRQ; +typedef struct dapl_pz DAPL_PZ; +typedef struct dapl_lmr DAPL_LMR; +typedef struct dapl_rmr DAPL_RMR; +typedef struct dapl_sp DAPL_SP; +typedef struct dapl_cr DAPL_CR; + +typedef struct dapl_cookie DAPL_COOKIE; +typedef struct dapl_dto_cookie DAPL_DTO_COOKIE; +typedef struct dapl_rmr_cookie DAPL_RMR_COOKIE; + +typedef struct dapl_private DAPL_PRIVATE; + + + +/********************************************************************* + * * + * Structures * + * * + *********************************************************************/ + +struct dapl_llist_entry +{ + struct dapl_llist_entry *flink; + struct dapl_llist_entry *blink; + void *data; + DAPL_LLIST_HEAD *list_head; /* for consistency checking */ +}; + +struct dapl_ring_buffer +{ + void **base; /* base of element array */ + DAT_COUNT lim; /* mask, number of entries - 1 */ + DAPL_ATOMIC head; /* head pointer index */ + DAPL_ATOMIC tail; /* tail pointer index */ +}; + +struct dapl_cookie_buffer +{ + DAPL_COOKIE *pool; + DAT_COUNT pool_size; + DAPL_ATOMIC head; + DAPL_ATOMIC tail; +}; + +#ifdef IBAPI +#include "dapl_ibapi_util.h" +#elif VAPI +#include "dapl_vapi_util.h" +#elif __OPENIB__ +#include "dapl_openib_util.h" +#include "dapl_openib_cm.h" +#elif DUMMY +#include "dapl_dummy_util.h" +#elif OPENIB +#include "dapl_ib_util.h" +#else /* windows - IBAL and/or IBAL+Sock_CM */ +#include "dapl_ibal_util.h" +#endif + +struct dapl_hca +{ + DAPL_OS_LOCK lock; + DAPL_LLIST_HEAD ia_list_head; /* list of all open IAs */ + DAPL_ATOMIC handle_ref_count; /* count of ia_opens on handle */ + DAPL_EVD *async_evd; + DAPL_EVD *async_error_evd; + DAT_SOCK_ADDR6 hca_address; /* local address of HCA*/ + char *name; /* provider name */ + ib_hca_handle_t ib_hca_handle; + unsigned long port_num; /* physical port number */ + ib_hca_transport_t ib_trans; /* Values specific transport API */ + /* Memory Subsystem Support */ + DAPL_HASH_TABLE *lmr_hash_table; + /* Limits & useful HCA attributes */ + DAT_IA_ATTR ia_attr; +}; + +/* DAPL Objects always have the following header */ +struct dapl_header +{ + DAT_PROVIDER *provider; /* required by DAT - must be first */ + DAPL_MAGIC magic; /* magic number for verification */ + DAT_HANDLE_TYPE handle_type; /* struct type */ + DAPL_IA *owner_ia; /* ia which owns this stuct */ + DAPL_LLIST_ENTRY ia_list_entry; /* link entry on ia struct */ + DAT_CONTEXT user_context; /* user context - opaque to DAPL */ + DAPL_OS_LOCK lock; /* lock - in header for easier macros */ +}; + +/* DAPL_IA maps to DAT_IA_HANDLE */ +struct dapl_ia +{ + DAPL_HEADER header; + DAPL_HCA *hca_ptr; + DAPL_EVD *async_error_evd; + DAT_BOOLEAN cleanup_async_error_evd; + + DAPL_LLIST_ENTRY hca_ia_list_entry; /* HCAs list of IAs */ + DAPL_LLIST_HEAD ep_list_head; /* EP queue */ + DAPL_LLIST_HEAD lmr_list_head; /* LMR queue */ + DAPL_LLIST_HEAD rmr_list_head; /* RMR queue */ + DAPL_LLIST_HEAD pz_list_head; /* PZ queue */ + DAPL_LLIST_HEAD evd_list_head; /* EVD queue */ + DAPL_LLIST_HEAD cno_list_head; /* CNO queue */ + DAPL_LLIST_HEAD psp_list_head; /* PSP queue */ + DAPL_LLIST_HEAD rsp_list_head; /* RSP queue */ + DAPL_LLIST_HEAD srq_list_head; /* SRQ queue */ +#ifdef DAPL_COUNTERS + void *cntrs; +#endif +}; + +/* DAPL_CNO maps to DAT_CNO_HANDLE */ +struct dapl_cno +{ + DAPL_HEADER header; + + /* A CNO cannot be freed while it is referenced elsewhere. */ + DAPL_ATOMIC cno_ref_count; + DAPL_CNO_STATE cno_state; + + DAT_COUNT cno_waiters; + DAPL_EVD *cno_evd_triggered; +#if defined(__KERNEL__) + DAT_UPCALL_OBJECT cno_upcall; + DAT_UPCALL_POLICY cno_upcall_policy; +#else + DAT_OS_WAIT_PROXY_AGENT cno_wait_agent; +#endif /* defined(__KERNEL__) */ + + DAPL_OS_WAIT_OBJECT cno_wait_object; +}; + +/* DAPL_EVD maps to DAT_EVD_HANDLE */ +struct dapl_evd +{ + DAPL_HEADER header; + + DAPL_EVD_STATE evd_state; + DAT_EVD_FLAGS evd_flags; + DAT_BOOLEAN evd_enabled; /* For attached CNO. */ + DAT_BOOLEAN evd_waitable; /* EVD state. */ + + /* Derived from evd_flags; see dapls_evd_internal_create. */ + DAT_BOOLEAN evd_producer_locking_needed; + + /* Every EVD has a CQ unless it is a SOFTWARE_EVENT only EVD */ + ib_cq_handle_t ib_cq_handle; + + /* An Event Dispatcher cannot be freed while + * it is referenced elsewhere. + */ + DAPL_ATOMIC evd_ref_count; + + /* Set if there has been a catastrophic overflow */ + DAT_BOOLEAN catastrophic_overflow; + + /* the actual events */ + DAT_COUNT qlen; + DAT_EVENT *events; + DAPL_RING_BUFFER free_event_queue; + DAPL_RING_BUFFER pending_event_queue; + + /* CQ Completions are not placed into 'deferred_events' + ** rather they are simply left on the Completion Queue + ** and the fact that there was a notification is flagged. + */ + DAT_BOOLEAN cq_notified; + DAPL_OS_TICKS cq_notified_when; + + DAT_COUNT cno_active_count; + DAPL_CNO *cno_ptr; + + DAPL_OS_WAIT_OBJECT wait_object; + + DAT_COUNT threshold; + DAPL_EVD_COMPLETION completion_type; + +#ifdef DAPL_COUNTERS + void *cntrs; +#endif +}; + +/* DAPL_PRIVATE used to pass private data in a connection */ +struct dapl_private +{ +#ifdef IBHOSTS_NAMING + DAT_SOCK_ADDR6 hca_address; /* local address of HCA*/ +#endif /* IBHOSTS_NAMING */ + unsigned char private_data[DAPL_MAX_PRIVATE_DATA_SIZE]; +}; + +/* uDAPL timer entry, used to queue timeouts */ +struct dapl_timer_entry +{ + DAPL_LLIST_ENTRY list_entry; /* link entry on ia struct */ + DAPL_OS_TIMEVAL expires; + void (*function) (uintptr_t); + void *data; +}; + +#ifdef DAPL_DBG_IO_TRC + +#define DBG_IO_TRC_QLEN 32 /* length of trace buffer */ +#define DBG_IO_TRC_IOV 3 /* iov elements we keep track of */ + +struct io_buf_track +{ + Ib_send_op_type op_type; + DAPL_COOKIE *cookie; + DAT_LMR_TRIPLET iov[DBG_IO_TRC_IOV]; + DAT_RMR_TRIPLET remote_iov; + unsigned int done; /* count to track completion ordering */ + int status; + void *wqe; +}; + +#endif /* DAPL_DBG_IO_TRC */ + +/* DAPL_EP maps to DAT_EP_HANDLE */ +struct dapl_ep +{ + DAPL_HEADER header; + /* What the DAT Consumer asked for */ + DAT_EP_PARAM param; + + /* The RC Queue Pair (IBM OS API) */ + ib_qp_handle_t qp_handle; + unsigned int qpn; /* qp number */ + ib_qp_state_t qp_state; + + /* communications manager handle (IBM OS API) */ + // dp_ib_cm_handle_t cm_handle; + + /* Add support for multiple CM object ownership */ + DAPL_LLIST_HEAD cm_list_head; + + /* store the remote IA address here, reference from the param + * struct which only has a pointer, no storage + */ + DAT_SOCK_ADDR6 remote_ia_address; + + /* For passive connections we maintain a back pointer to the CR */ + void * cr_ptr; + + /* pointer to connection timer, if set */ + struct dapl_timer_entry *cxn_timer; + + /* private data container */ + DAPL_PRIVATE private; + + /* DTO data */ + DAPL_ATOMIC req_count; + DAPL_ATOMIC recv_count; + + DAPL_COOKIE_BUFFER req_buffer; + DAPL_COOKIE_BUFFER recv_buffer; + +#ifdef DAPL_DBG_IO_TRC + int ibt_dumped; + struct io_buf_track *ibt_base; + DAPL_RING_BUFFER ibt_queue; +#endif /* DAPL_DBG_IO_TRC */ +#if defined(_WIN32) || defined(_WIN64) + DAT_BOOLEAN recv_discreq; + DAT_BOOLEAN sent_discreq; +#endif +#ifdef DAPL_COUNTERS + void *cntrs; +#endif +}; + +/* DAPL_SRQ maps to DAT_SRQ_HANDLE */ +struct dapl_srq +{ + DAPL_HEADER header; + DAT_SRQ_PARAM param; + DAPL_ATOMIC srq_ref_count; + DAPL_COOKIE_BUFFER recv_buffer; + DAPL_ATOMIC recv_count; +}; + +/* DAPL_PZ maps to DAT_PZ_HANDLE */ +struct dapl_pz +{ + DAPL_HEADER header; + ib_pd_handle_t pd_handle; + DAPL_ATOMIC pz_ref_count; +}; + +/* DAPL_LMR maps to DAT_LMR_HANDLE */ +struct dapl_lmr +{ + DAPL_HEADER header; + DAT_LMR_PARAM param; + ib_mr_handle_t mr_handle; + DAPL_ATOMIC lmr_ref_count; +#if !defined(__KDAPL__) + char shmid[DAT_LMR_COOKIE_SIZE]; /* shared memory ID */ + ib_shm_transport_t ib_trans; /* provider specific data */ +#endif /* !__KDAPL__ */ +}; + +/* DAPL_RMR maps to DAT_RMR_HANDLE */ +struct dapl_rmr +{ + DAPL_HEADER header; + DAT_RMR_PARAM param; + DAPL_EP *ep; + DAPL_PZ *pz; + DAPL_LMR *lmr; + ib_mw_handle_t mw_handle; +}; + +/* SP types, indicating the state and queue */ +typedef enum dapl_sp_state +{ + DAPL_SP_STATE_FREE, + DAPL_SP_STATE_PSP_LISTENING, + DAPL_SP_STATE_PSP_PENDING, + DAPL_SP_STATE_RSP_LISTENING, + DAPL_SP_STATE_RSP_PENDING +} DAPL_SP_STATE; + +/* DAPL_SP maps to DAT_PSP_HANDLE and DAT_RSP_HANDLE */ +struct dapl_sp +{ + DAPL_HEADER header; + DAPL_SP_STATE state; /* type and queue of the SP */ + + /* PSP/RSP PARAM fields */ + DAT_CONN_QUAL conn_qual; + DAT_EVD_HANDLE evd_handle; + DAT_PSP_FLAGS psp_flags; + DAT_EP_HANDLE ep_handle; + + /* maintenence fields */ + DAT_BOOLEAN listening; /* PSP is registered & active */ + ib_cm_srvc_handle_t cm_srvc_handle; /* Used by Mellanox CM */ + DAPL_LLIST_HEAD cr_list_head; /* CR pending queue */ + DAT_COUNT cr_list_count; /* count of CRs on queue */ +#if defined(_VENDOR_IBAL_) + DAPL_OS_WAIT_OBJECT wait_object; /* cancel & destroy. */ +#endif +}; + +/* DAPL_CR maps to DAT_CR_HANDLE */ +struct dapl_cr +{ + DAPL_HEADER header; + + /* for convenience the data is kept as a DAT_CR_PARAM. + * however, the "local_endpoint" field is always NULL + * so this wastes a pointer. This is probably ok to + * simplify code, espedially dat_cr_query. + */ + DAT_CR_PARAM param; + /* IB specific fields */ + dp_ib_cm_handle_t ib_cm_handle; + + DAT_SOCK_ADDR6 remote_ia_address; + /* Assuming that the maximum private data size is small. + * If it gets large, use of a pointer may be appropriate. + */ + unsigned char private_data[DAPL_MAX_PRIVATE_DATA_SIZE]; + /* + * Need to be able to associate the CR back to the PSP for + * dapl_cr_reject. + */ + DAPL_SP *sp_ptr; +}; + +typedef enum dapl_dto_type +{ + DAPL_DTO_TYPE_SEND, + DAPL_DTO_TYPE_RECV, + DAPL_DTO_TYPE_RDMA_WRITE, + DAPL_DTO_TYPE_RDMA_READ, +#ifdef DAT_EXTENSIONS + DAPL_DTO_TYPE_EXTENSION, +#endif +} DAPL_DTO_TYPE; + +typedef enum dapl_cookie_type +{ + DAPL_COOKIE_TYPE_NULL, + DAPL_COOKIE_TYPE_DTO, + DAPL_COOKIE_TYPE_RMR, +} DAPL_COOKIE_TYPE; + +/* DAPL_DTO_COOKIE used as context for DTO WQEs */ +struct dapl_dto_cookie +{ + DAPL_DTO_TYPE type; + DAT_DTO_COOKIE cookie; + DAT_COUNT size; /* used for SEND and RDMA write */ +}; + +/* DAPL_RMR_COOKIE used as context for bind WQEs */ +struct dapl_rmr_cookie +{ + DAPL_RMR *rmr; + DAT_RMR_COOKIE cookie; +}; + +/* DAPL_COOKIE used as context for WQEs */ +struct dapl_cookie +{ + DAPL_COOKIE_TYPE type; /* Must be first, to define struct. */ + DAPL_EP *ep; + DAT_COUNT index; + union + { + DAPL_DTO_COOKIE dto; + DAPL_RMR_COOKIE rmr; + } val; +}; + +/* + * Private Data operations. Used to obtain the size of the private + * data from the provider layer. + */ +typedef enum dapl_private_data_op +{ + DAPL_PDATA_CONN_REQ = 0, /* connect request */ + DAPL_PDATA_CONN_REP = 1, /* connect reply */ + DAPL_PDATA_CONN_REJ = 2, /* connect reject */ + DAPL_PDATA_CONN_DREQ = 3, /* disconnect request */ + DAPL_PDATA_CONN_DREP = 4, /* disconnect reply */ +} DAPL_PDATA_OP; + + +/* + * Generic HCA name field + */ +#define DAPL_HCA_NAME_MAX_LEN 260 +typedef char DAPL_HCA_NAME[DAPL_HCA_NAME_MAX_LEN+1]; + +#ifdef IBHOSTS_NAMING + +/* + * Simple mapping table to match IP addresses to GIDs. Loaded + * by dapl_init. + */ +typedef struct _dapl_gid_map_table +{ + uint32_t ip_address; + ib_gid_t gid; +} DAPL_GID_MAP; + +#endif /* IBHOSTS_NAMING */ + +/* + * IBTA defined reason for reject message: See IBTA 1.1 specification, + * 12.6.7.2 REJECTION REASON section. + */ +#define IB_CM_REJ_REASON_CONSUMER_REJ 0x001C + + +#if defined(DAPL_DBG_IO_TRC) +/********************************************************************* + * * + * Debug I/O tracing support prototypes * + * * + *********************************************************************/ +/* + * I/O tracing support + */ +void dapls_io_trc_alloc ( + DAPL_EP *ep_ptr); + +void dapls_io_trc_update_completion ( + DAPL_EP *ep_ptr, + DAPL_COOKIE *cookie, + ib_uint32_t ib_status ); + +void dapls_io_trc_dump ( + DAPL_EP *ep_ptr, + ib_work_completion_t *cqe_ptr, + ib_uint32_t ib_status); + +#else /* DAPL_DBG_IO_TRC */ + +#define dapls_io_trc_alloc(a) +#define dapls_io_trc_update_completion(a, b, c) +#define dapls_io_trc_dump(a, b, c) + +#endif /* DAPL_DBG_IO_TRC */ + + +/********************************************************************* + * * + * Function Prototypes * + * * + *********************************************************************/ + +typedef void (*DAPL_CONNECTION_STATE_HANDLER) ( + IN DAPL_EP *, + IN ib_cm_events_t, + IN const void *, + OUT DAT_EVENT *); + +/* + * DAT Mandated functions + */ + +extern DAT_RETURN DAT_API dapl_ia_open ( + IN const DAT_NAME_PTR, /* name */ + IN DAT_COUNT, /* asynch_evd_qlen */ + INOUT DAT_EVD_HANDLE *, /* asynch_evd_handle */ + OUT DAT_IA_HANDLE *); /* ia_handle */ + +extern DAT_RETURN DAT_API dapl_ia_close ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_CLOSE_FLAGS ); /* ia_flags */ + + +extern DAT_RETURN DAT_API dapl_ia_query ( + IN DAT_IA_HANDLE, /* ia handle */ + OUT DAT_EVD_HANDLE *, /* async_evd_handle */ + IN DAT_IA_ATTR_MASK, /* ia_params_mask */ + OUT DAT_IA_ATTR *, /* ia_params */ + IN DAT_PROVIDER_ATTR_MASK, /* provider_params_mask */ + OUT DAT_PROVIDER_ATTR * ); /* provider_params */ + + +/* helper functions */ + +extern DAT_RETURN DAT_API dapl_set_consumer_context ( + IN DAT_HANDLE, /* dat handle */ + IN DAT_CONTEXT); /* context */ + +extern DAT_RETURN DAT_API dapl_get_consumer_context ( + IN DAT_HANDLE, /* dat handle */ + OUT DAT_CONTEXT * ); /* context */ + +extern DAT_RETURN DAT_API dapl_get_handle_type ( + IN DAT_HANDLE, + OUT DAT_HANDLE_TYPE * ); + +/* CNO functions */ + +#if !defined(__KERNEL__) +extern DAT_RETURN DAT_API dapl_cno_create ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_OS_WAIT_PROXY_AGENT, /* agent */ + OUT DAT_CNO_HANDLE *); /* cno_handle */ + +extern DAT_RETURN DAT_API dapl_cno_modify_agent ( + IN DAT_CNO_HANDLE, /* cno_handle */ + IN DAT_OS_WAIT_PROXY_AGENT); /* agent */ + +extern DAT_RETURN DAT_API dapl_cno_query ( + IN DAT_CNO_HANDLE, /* cno_handle */ + IN DAT_CNO_PARAM_MASK, /* cno_param_mask */ + OUT DAT_CNO_PARAM * ); /* cno_param */ + +extern DAT_RETURN DAT_API dapl_cno_free ( + IN DAT_CNO_HANDLE); /* cno_handle */ + +extern DAT_RETURN DAT_API dapl_cno_wait ( + IN DAT_CNO_HANDLE, /* cno_handle */ + IN DAT_TIMEOUT, /* timeout */ + OUT DAT_EVD_HANDLE *); /* evd_handle */ + +extern DAT_RETURN DAT_API dapl_cno_fd_create ( + IN DAT_IA_HANDLE, /* ia_handle */ + OUT DAT_FD *, /* file_descriptor */ + OUT DAT_CNO_HANDLE *); /* cno_handle */ + +extern DAT_RETURN DAT_API dapl_cno_trigger ( + IN DAT_CNO_HANDLE, /* cno_handle */ + OUT DAT_EVD_HANDLE *); /* evd_handle */ + +#endif /* !defined(__KERNEL__) */ + +/* CR Functions */ + +extern DAT_RETURN DAT_API dapl_cr_query ( + IN DAT_CR_HANDLE, /* cr_handle */ + IN DAT_CR_PARAM_MASK, /* cr_args_mask */ + OUT DAT_CR_PARAM * ); /* cwr_args */ + +extern DAT_RETURN DAT_API dapl_cr_accept ( + IN DAT_CR_HANDLE, /* cr_handle */ + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_COUNT, /* private_data_size */ + IN const DAT_PVOID ); /* private_data */ + +extern DAT_RETURN DAT_API dapl_cr_reject ( + IN DAT_CR_HANDLE, /* cr_handle */ + IN DAT_COUNT, /* private_data_size */ + IN const DAT_PVOID ); /* private_data */ + +extern DAT_RETURN DAT_API dapl_cr_handoff ( + IN DAT_CR_HANDLE, /* cr_handle */ + IN DAT_CONN_QUAL); /* handoff */ + +/* EVD Functions */ + +#if defined(__KERNEL__) +extern DAT_RETURN DAT_API dapl_ia_memtype_hint ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_MEM_TYPE, /* mem_type */ + IN DAT_VLEN, /* length */ + IN DAT_MEM_OPT, /* mem_optimization */ + OUT DAT_VLEN *, /* suggested_length */ + OUT DAT_VADDR *); /* suggested_alignment */ + +extern DAT_RETURN DAT_API dapl_evd_kcreate ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_COUNT, /* evd_min_qlen */ + IN DAT_UPCALL_POLICY, /* upcall_policy */ + IN const DAT_UPCALL_OBJECT *, /* upcall */ + IN DAT_EVD_FLAGS, /* evd_flags */ + OUT DAT_EVD_HANDLE * ); /* evd_handle */ + +extern DAT_RETURN DAT_API dapl_evd_kquery ( + IN DAT_EVD_HANDLE, /* evd_handle */ + IN DAT_EVD_PARAM_MASK, /* evd_args_mask */ + OUT DAT_EVD_PARAM * ); /* evd_args */ + +#else +extern DAT_RETURN DAT_API dapl_evd_create ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_COUNT, /* evd_min_qlen */ + IN DAT_CNO_HANDLE, /* cno_handle */ + IN DAT_EVD_FLAGS, /* evd_flags */ + OUT DAT_EVD_HANDLE * ); /* evd_handle */ + +extern DAT_RETURN DAT_API dapl_evd_query ( + IN DAT_EVD_HANDLE, /* evd_handle */ + IN DAT_EVD_PARAM_MASK, /* evd_args_mask */ + OUT DAT_EVD_PARAM * ); /* evd_args */ +#endif /* defined(__KERNEL__) */ + +#if defined(__KERNEL__) +extern DAT_RETURN DAT_API dapl_evd_modify_upcall ( + IN DAT_EVD_HANDLE, /* evd_handle */ + IN DAT_UPCALL_POLICY, /* upcall_policy */ + IN const DAT_UPCALL_OBJECT * ); /* upcall */ + +#else + +extern DAT_RETURN DAT_API dapl_evd_modify_cno ( + IN DAT_EVD_HANDLE, /* evd_handle */ + IN DAT_CNO_HANDLE); /* cno_handle */ +#endif + +extern DAT_RETURN DAT_API dapl_evd_enable ( + IN DAT_EVD_HANDLE); /* evd_handle */ + +extern DAT_RETURN DAT_API dapl_evd_disable ( + IN DAT_EVD_HANDLE); /* evd_handle */ + +#if !defined(__KERNEL__) +extern DAT_RETURN DAT_API dapl_evd_wait ( + IN DAT_EVD_HANDLE, /* evd_handle */ + IN DAT_TIMEOUT, /* timeout */ + IN DAT_COUNT, /* threshold */ + OUT DAT_EVENT *, /* event */ + OUT DAT_COUNT *); /* nmore */ +#endif /* !defined(__KERNEL__) */ + +extern DAT_RETURN DAT_API dapl_evd_resize ( + IN DAT_EVD_HANDLE, /* evd_handle */ + IN DAT_COUNT ); /* evd_qlen */ + +extern DAT_RETURN DAT_API dapl_evd_post_se ( + DAT_EVD_HANDLE, /* evd_handle */ + const DAT_EVENT * ); /* event */ + +extern DAT_RETURN DAT_API dapl_evd_dequeue ( + IN DAT_EVD_HANDLE, /* evd_handle */ + OUT DAT_EVENT * ); /* event */ + +extern DAT_RETURN DAT_API dapl_evd_free ( + IN DAT_EVD_HANDLE ); + +extern DAT_RETURN DAT_API +dapl_evd_set_unwaitable ( + IN DAT_EVD_HANDLE evd_handle ); + +extern DAT_RETURN DAT_API +dapl_evd_clear_unwaitable ( + IN DAT_EVD_HANDLE evd_handle ); + +/* EP functions */ + +extern DAT_RETURN DAT_API dapl_ep_create ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_PZ_HANDLE, /* pz_handle */ + IN DAT_EVD_HANDLE, /* in_dto_completion_evd_handle */ + IN DAT_EVD_HANDLE, /* out_dto_completion_evd_handle */ + IN DAT_EVD_HANDLE, /* connect_evd_handle */ + IN const DAT_EP_ATTR *, /* ep_parameters */ + OUT DAT_EP_HANDLE * ); /* ep_handle */ + +extern DAT_RETURN DAT_API dapl_ep_query ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_EP_PARAM_MASK, /* ep_args_mask */ + OUT DAT_EP_PARAM * ); /* ep_args */ + +extern DAT_RETURN DAT_API dapl_ep_modify ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_EP_PARAM_MASK, /* ep_args_mask */ + IN const DAT_EP_PARAM * ); /* ep_args */ + +extern DAT_RETURN DAT_API dapl_ep_connect ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_IA_ADDRESS_PTR, /* remote_ia_address */ + IN DAT_CONN_QUAL, /* remote_conn_qual */ + IN DAT_TIMEOUT, /* timeout */ + IN DAT_COUNT, /* private_data_size */ + IN const DAT_PVOID, /* private_data */ + IN DAT_QOS, /* quality_of_service */ + IN DAT_CONNECT_FLAGS ); /* connect_flags */ + +extern DAT_RETURN DAT_API dapl_ep_common_connect ( + IN DAT_EP_HANDLE ep, /* ep_handle */ + IN DAT_IA_ADDRESS_PTR remote_addr, /* remote_ia_address */ + IN DAT_TIMEOUT timeout, /* timeout */ + IN DAT_COUNT pdata_size, /* private_data_size */ + IN const DAT_PVOID pdata ); /* private_data */ + +extern DAT_RETURN DAT_API dapl_ep_dup_connect ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_EP_HANDLE, /* ep_dup_handle */ + IN DAT_TIMEOUT, /* timeout*/ + IN DAT_COUNT, /* private_data_size */ + IN const DAT_PVOID, /* private_data */ + IN DAT_QOS); /* quality_of_service */ + +extern DAT_RETURN DAT_API dapl_ep_disconnect ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_CLOSE_FLAGS ); /* close_flags */ + +extern DAT_RETURN DAT_API dapl_ep_post_send ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_COUNT, /* num_segments */ + IN DAT_LMR_TRIPLET *, /* local_iov */ + IN DAT_DTO_COOKIE, /* user_cookie */ + IN DAT_COMPLETION_FLAGS ); /* completion_flags */ + +extern DAT_RETURN DAT_API dapl_ep_post_recv ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_COUNT, /* num_segments */ + IN DAT_LMR_TRIPLET *, /* local_iov */ + IN DAT_DTO_COOKIE, /* user_cookie */ + IN DAT_COMPLETION_FLAGS ); /* completion_flags */ + +extern DAT_RETURN DAT_API dapl_ep_post_rdma_read ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_COUNT, /* num_segments */ + IN DAT_LMR_TRIPLET *, /* local_iov */ + IN DAT_DTO_COOKIE, /* user_cookie */ + IN const DAT_RMR_TRIPLET *, /* remote_iov */ + IN DAT_COMPLETION_FLAGS ); /* completion_flags */ + +extern DAT_RETURN DAT_API dapl_ep_post_rdma_read_to_rmr ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN const DAT_RMR_TRIPLET *,/* local_iov */ + IN DAT_DTO_COOKIE, /* user_cookie */ + IN const DAT_RMR_TRIPLET *,/* remote_iov */ + IN DAT_COMPLETION_FLAGS); /* completion_flags */ + +extern DAT_RETURN DAT_API dapl_ep_post_rdma_write ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_COUNT, /* num_segments */ + IN DAT_LMR_TRIPLET *, /* local_iov */ + IN DAT_DTO_COOKIE, /* user_cookie */ + IN const DAT_RMR_TRIPLET *, /* remote_iov */ + IN DAT_COMPLETION_FLAGS ); /* completion_flags */ + +extern DAT_RETURN DAT_API dapl_ep_post_send_with_invalidate ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_COUNT, /* num_segments */ + IN DAT_LMR_TRIPLET *, /* local_iov */ + IN DAT_DTO_COOKIE, /* user_cookie */ + IN DAT_COMPLETION_FLAGS, /* completion_flags */ + IN DAT_BOOLEAN, /* invalidate_flag */ + IN DAT_RMR_CONTEXT); /* RMR context */ + +extern DAT_RETURN DAT_API dapl_ep_get_status ( + IN DAT_EP_HANDLE, /* ep_handle */ + OUT DAT_EP_STATE *, /* ep_state */ + OUT DAT_BOOLEAN *, /* in_dto_idle */ + OUT DAT_BOOLEAN * ); /* out_dto_idle */ + +extern DAT_RETURN DAT_API dapl_ep_free ( + IN DAT_EP_HANDLE); /* ep_handle */ + +extern DAT_RETURN DAT_API dapl_ep_reset ( + IN DAT_EP_HANDLE); /* ep_handle */ + +extern DAT_RETURN DAT_API dapl_ep_create_with_srq ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_PZ_HANDLE, /* pz_handle */ + IN DAT_EVD_HANDLE, /* recv_evd_handle */ + IN DAT_EVD_HANDLE, /* request_evd_handle */ + IN DAT_EVD_HANDLE, /* connect_evd_handle */ + IN DAT_SRQ_HANDLE, /* srq_handle */ + IN const DAT_EP_ATTR *, /* ep_attributes */ + OUT DAT_EP_HANDLE *); /* ep_handle */ + +extern DAT_RETURN DAT_API dapl_ep_recv_query ( + IN DAT_EP_HANDLE, /* ep_handle */ + OUT DAT_COUNT *, /* nbufs_allocated */ + OUT DAT_COUNT *); /* bufs_alloc_span */ + +extern DAT_RETURN DAT_API dapl_ep_set_watermark ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_COUNT, /* soft_high_watermark */ + IN DAT_COUNT); /* hard_high_watermark */ + +/* LMR functions */ + +#if defined(__KERNEL__) +extern DAT_RETURN DAT_API dapl_lmr_kcreate ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_MEM_TYPE, /* mem_type */ + IN DAT_REGION_DESCRIPTION, /* region_description */ + IN DAT_VLEN, /* length */ + IN DAT_PZ_HANDLE, /* pz_handle */ + IN DAT_MEM_PRIV_FLAGS, /* privileges */ + IN DAT_VA_TYPE, /* va_type */ + IN DAT_MEM_OPT, /* optimization */ + OUT DAT_LMR_HANDLE *, /* lmr_handle */ + OUT DAT_LMR_CONTEXT *, /* lmr_context */ + OUT DAT_RMR_CONTEXT *, /* rmr_context */ + OUT DAT_VLEN *, /* registered_length */ + OUT DAT_VADDR * ); /* registered_address */ +#else +extern DAT_RETURN DAT_API dapl_lmr_create ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_MEM_TYPE, /* mem_type */ + IN DAT_REGION_DESCRIPTION, /* region_description */ + IN DAT_VLEN, /* length */ + IN DAT_PZ_HANDLE, /* pz_handle */ + IN DAT_MEM_PRIV_FLAGS, /* privileges */ + IN DAT_VA_TYPE, /* va_type */ + OUT DAT_LMR_HANDLE *, /* lmr_handle */ + OUT DAT_LMR_CONTEXT *, /* lmr_context */ + OUT DAT_RMR_CONTEXT *, /* rmr_context */ + OUT DAT_VLEN *, /* registered_length */ + OUT DAT_VADDR * ); /* registered_address */ +#endif /* defined(__KERNEL__) */ + +extern DAT_RETURN DAT_API dapl_lmr_query ( + IN DAT_LMR_HANDLE, + IN DAT_LMR_PARAM_MASK, + OUT DAT_LMR_PARAM *); + +extern DAT_RETURN DAT_API dapl_lmr_free ( + IN DAT_LMR_HANDLE); + +extern DAT_RETURN DAT_API dapl_lmr_sync_rdma_read ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN const DAT_LMR_TRIPLET *, /* local_segments */ + IN DAT_VLEN); /* num_segments */ + +extern DAT_RETURN DAT_API dapl_lmr_sync_rdma_write ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN const DAT_LMR_TRIPLET *, /* local_segments */ + IN DAT_VLEN); /* num_segments */ + +/* RMR Functions */ + +extern DAT_RETURN DAT_API dapl_rmr_create ( + IN DAT_PZ_HANDLE, /* pz_handle */ + OUT DAT_RMR_HANDLE *); /* rmr_handle */ + +extern DAT_RETURN DAT_API dapl_rmr_create_for_ep ( + IN DAT_PZ_HANDLE pz_handle, /* pz_handle */ + OUT DAT_RMR_HANDLE *rmr_handle); /* rmr_handle */ + +extern DAT_RETURN DAT_API dapl_rmr_query ( + IN DAT_RMR_HANDLE, /* rmr_handle */ + IN DAT_RMR_PARAM_MASK, /* rmr_args_mask */ + OUT DAT_RMR_PARAM *); /* rmr_args */ + +extern DAT_RETURN DAT_API dapl_rmr_bind ( + IN DAT_RMR_HANDLE, /* rmr_handle */ + IN DAT_LMR_HANDLE, /* lmr_handle */ + IN const DAT_LMR_TRIPLET *, /* lmr_triplet */ + IN DAT_MEM_PRIV_FLAGS, /* mem_priv */ + IN DAT_VA_TYPE, /* va_type */ + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_RMR_COOKIE, /* user_cookie */ + IN DAT_COMPLETION_FLAGS, /* completion_flags */ + INOUT DAT_RMR_CONTEXT * ); /* context */ + +extern DAT_RETURN DAT_API dapl_rmr_free ( + IN DAT_RMR_HANDLE); + +/* PSP Functions */ + +extern DAT_RETURN DAT_API dapl_psp_create ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_CONN_QUAL, /* conn_qual */ + IN DAT_EVD_HANDLE, /* evd_handle */ + IN DAT_PSP_FLAGS, /* psp_flags */ + OUT DAT_PSP_HANDLE * ); /* psp_handle */ + +extern DAT_RETURN DAT_API dapl_psp_create_any ( + IN DAT_IA_HANDLE, /* ia_handle */ + OUT DAT_CONN_QUAL *, /* conn_qual */ + IN DAT_EVD_HANDLE, /* evd_handle */ + IN DAT_PSP_FLAGS, /* psp_flags */ + OUT DAT_PSP_HANDLE *); /* psp_handle */ + +extern DAT_RETURN DAT_API dapl_psp_query ( + IN DAT_PSP_HANDLE, + IN DAT_PSP_PARAM_MASK, + OUT DAT_PSP_PARAM * ); + +extern DAT_RETURN DAT_API dapl_psp_free ( + IN DAT_PSP_HANDLE ); /* psp_handle */ + +/* RSP Functions */ + +extern DAT_RETURN DAT_API dapl_rsp_create ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_CONN_QUAL, /* conn_qual */ + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_EVD_HANDLE, /* evd_handle */ + OUT DAT_RSP_HANDLE * ); /* rsp_handle */ + +extern DAT_RETURN DAT_API dapl_rsp_query ( + IN DAT_RSP_HANDLE, + IN DAT_RSP_PARAM_MASK, + OUT DAT_RSP_PARAM * ); + +extern DAT_RETURN DAT_API dapl_rsp_free ( + IN DAT_RSP_HANDLE ); /* rsp_handle */ + +/* PZ Functions */ + +extern DAT_RETURN DAT_API dapl_pz_create ( + IN DAT_IA_HANDLE, /* ia_handle */ + OUT DAT_PZ_HANDLE * ); /* pz_handle */ + +extern DAT_RETURN DAT_API dapl_pz_query ( + IN DAT_PZ_HANDLE, /* pz_handle */ + IN DAT_PZ_PARAM_MASK, /* pz_args_mask */ + OUT DAT_PZ_PARAM * ); /* pz_args */ + +extern DAT_RETURN DAT_API dapl_pz_free ( + IN DAT_PZ_HANDLE ); /* pz_handle */ + +/* SRQ functions */ + +extern DAT_RETURN DAT_API dapl_srq_create ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_PZ_HANDLE, /* pz_handle */ + IN DAT_SRQ_ATTR *, /* srq_attr */ + OUT DAT_SRQ_HANDLE *); /* srq_handle */ + +extern DAT_RETURN DAT_API dapl_srq_free ( + IN DAT_SRQ_HANDLE); /* srq_handle */ + +extern DAT_RETURN DAT_API dapl_srq_post_recv ( + IN DAT_SRQ_HANDLE, /* srq_handle */ + IN DAT_COUNT, /* num_segments */ + IN DAT_LMR_TRIPLET *, /* local_iov */ + IN DAT_DTO_COOKIE); /* user_cookie */ + +extern DAT_RETURN DAT_API dapl_srq_query ( + IN DAT_SRQ_HANDLE, /* srq_handle */ + IN DAT_SRQ_PARAM_MASK, /* srq_param_mask */ + OUT DAT_SRQ_PARAM *); /* srq_param */ + +extern DAT_RETURN DAT_API dapl_srq_resize ( + IN DAT_SRQ_HANDLE, /* srq_handle */ + IN DAT_COUNT); /* srq_max_recv_dto */ + +extern DAT_RETURN DAT_API dapl_srq_set_lw ( + IN DAT_SRQ_HANDLE, /* srq_handle */ + IN DAT_COUNT); /* low_watermark */ + +/* CSP functions */ +extern DAT_RETURN DAT_API dapl_csp_create ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_COMM *, /* communicator */ + IN DAT_IA_ADDRESS_PTR, /* address */ + IN DAT_EVD_HANDLE, /* evd_handle */ + OUT DAT_CSP_HANDLE *); /* csp_handle */ + +extern DAT_RETURN DAT_API dapl_csp_query ( + IN DAT_CSP_HANDLE, /* csp_handle */ + IN DAT_CSP_PARAM_MASK, /* csp_param_mask */ + OUT DAT_CSP_PARAM *); /* csp_param */ + +extern DAT_RETURN DAT_API dapl_csp_free ( + IN DAT_CSP_HANDLE); /* csp_handle */ + +/* HA functions */ +DAT_RETURN DAT_API dapl_ia_ha ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN const DAT_NAME_PTR, /* provider */ + OUT DAT_BOOLEAN *); /* answer */ + +#ifdef DAT_EXTENSIONS +#include +extern DAT_RETURN DAT_API dapl_extensions ( + IN DAT_HANDLE, /* handle */ + IN DAT_EXTENDED_OP, /* extended op */ + IN va_list); /* argument list */ +#endif + +/* + * DAPL internal utility function prototpyes + */ + +extern void dapl_llist_init_head ( + DAPL_LLIST_HEAD * head); + +extern void dapl_llist_init_entry ( + DAPL_LLIST_ENTRY * entry); + +extern DAT_BOOLEAN dapl_llist_is_empty ( + DAPL_LLIST_HEAD * head); + +extern void dapl_llist_add_head ( + DAPL_LLIST_HEAD * head, + DAPL_LLIST_ENTRY * entry, + void * data); + +extern void dapl_llist_add_tail ( + DAPL_LLIST_HEAD * head, + DAPL_LLIST_ENTRY * entry, + void * data); + +extern void dapl_llist_add_entry ( + DAPL_LLIST_HEAD * head, + DAPL_LLIST_ENTRY * entry, + DAPL_LLIST_ENTRY * new_entry, + void * data); + +extern void * dapl_llist_remove_head ( + DAPL_LLIST_HEAD * head); + +extern void * dapl_llist_remove_tail ( + DAPL_LLIST_HEAD * head); + +extern void * dapl_llist_remove_entry ( + DAPL_LLIST_HEAD * head, + DAPL_LLIST_ENTRY * entry); + +extern void * dapl_llist_peek_head ( + DAPL_LLIST_HEAD * head); + +extern void * dapl_llist_next_entry ( + IN DAPL_LLIST_HEAD *head, + IN DAPL_LLIST_ENTRY *cur_ent); + +extern void dapl_llist_debug_print_list ( + DAPL_LLIST_HEAD * head); + + +#endif diff --git a/branches/WOF2-3/ulp/dapl2/dapl/include/dapl_debug.h b/branches/WOF2-3/ulp/dapl2/dapl/include/dapl_debug.h new file mode 100644 index 00000000..b8281ab1 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/include/dapl_debug.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_debug.h + * + * PURPOSE: defines common deuggging flags & data for the DAPL reference + * implemenation + * + * Description: + * + * + * $Id:$ + **********************************************************************/ + +#ifndef _DAPL_DEBUG_H_ +#define _DAPL_DEBUG_H_ + +/* + * Debug level switches + * + * Use these bits to enable various tracing/debug options. Each bit + * represents debugging in a particular subsystem or area of the code. + * + * The ERR bit should always be on unless someone disables it for a + * reason: The ERR flag is used sparingly and will print useful + * information if it fires. + */ +typedef enum +{ + DAPL_DBG_TYPE_ERR = 0x0001, + DAPL_DBG_TYPE_WARN = 0x0002, + DAPL_DBG_TYPE_EVD = 0x0004, + DAPL_DBG_TYPE_CM = 0x0008, + DAPL_DBG_TYPE_EP = 0x0010, + DAPL_DBG_TYPE_UTIL = 0x0020, + DAPL_DBG_TYPE_CALLBACK = 0x0040, + DAPL_DBG_TYPE_DTO_COMP_ERR = 0x0080, + DAPL_DBG_TYPE_API = 0x0100, + DAPL_DBG_TYPE_RTN = 0x0200, + DAPL_DBG_TYPE_EXCEPTION = 0x0400, + DAPL_DBG_TYPE_SRQ = 0x0800, + DAPL_DBG_TYPE_CNTR = 0x1000, + DAPL_DBG_TYPE_CM_LIST = 0x2000, + DAPL_DBG_TYPE_THREAD = 0x4000, + DAPL_DBG_TYPE_CM_EST = 0x8000, + DAPL_DBG_TYPE_CM_WARN = 0x10000 + +} DAPL_DBG_TYPE; + +typedef enum +{ + DAPL_DBG_DEST_STDOUT = 0x0001, + DAPL_DBG_DEST_SYSLOG = 0x0002, +} DAPL_DBG_DEST; + +extern DAPL_DBG_TYPE g_dapl_dbg_type; +extern DAPL_DBG_DEST g_dapl_dbg_dest; + +extern void dapl_internal_dbg_log(DAPL_DBG_TYPE type, const char *fmt, ...); + +#define dapl_log g_dapl_dbg_type==0 ? (void) 1 : dapl_internal_dbg_log + +#if defined(DAPL_DBG) +#define dapl_dbg_log g_dapl_dbg_type==0 ? (void) 1 : dapl_internal_dbg_log +#else +#define dapl_dbg_log(...) +#endif + +#include + +#ifdef DAPL_COUNTERS + +#define DAPL_CNTR(h_ptr, cntr) ((DAT_UINT64*)h_ptr->cntrs)[cntr]++ +#define DAPL_CNTR_DATA(h_ptr, cntr, data) ((DAT_UINT64*)h_ptr->cntrs)[cntr]+= data + +DAT_RETURN dapl_query_counter(DAT_HANDLE dh, + int counter, + void *p_cntrs_out, + int reset); +char *dapl_query_counter_name(DAT_HANDLE dh, int counter); +void dapl_print_counter(DAT_HANDLE dh, int counter, int reset); + +#else + +#define DAPL_CNTR(handle, cntr) +#define DAPL_CNTR_DATA(handle, cntr, data) + +#endif /* DAPL_COUNTERS */ + +#endif /* _DAPL_DEBUG_H_ */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/include/dapl_ipoib_names.h b/branches/WOF2-3/ulp/dapl2/dapl/include/dapl_ipoib_names.h new file mode 100644 index 00000000..23df8d5c --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/include/dapl_ipoib_names.h @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: ipoib_naming.h + * + * PURPOSE: Defines flags and prototypes for IPoIB API + * + * Description: + * This defines a simple naming interface for discovering + * the IP addresses available to a provider, then a set + * of query mechanisms useful to map an IP address to + * a provider specific address; a GID in InfiniBand. + * + * NOTE: As implementations mature this may not be necessary. + * + * $Id:$ + **********************************************************************/ + +#ifndef _IPOIB_NAMING_H_ +#define _IPOIB_NAMING_H_ + +typedef enum _ipoib_port_num { + HCA_PORT_1= 1, + HCA_PORT_2, + HCA_PORT_ANY +} IPOIB_PORT_NUM; + +typedef struct if_query_info +{ + uint64_t guid; + uint32_t port_num; + uint32_t state; +}IF_QUERY_INFO; + +/*********************************************************************** + * ipoib_enum_if() + * + * PURPOSE + * Returns count of IP interfaces. + * + * ARGUMENTS + * hca_index: index of HCA in the provider library. In general + * terms, the index represents the HCA number, e.g. + * 1 == First HCA, 2 == Second HCA, etc. + * + * port: an enum of + * HCA_PORT_0 + * HCA_PORT_1 + * HCA_PORT_ANY + * HCA_PORT_ANY enum value returns all IP instances assigned to the HCA. + * + * RETURNS + * count of IP interfaces supported on physical port + * + ***********************************************************************/ +int +ipoib_enum_if( + IN uint32_t hca_index, + IN IPOIB_PORT_NUM port); + + +/*********************************************************************** + * ipoib_get_if() + * + * PURPOSE + * Returns array of IP Addresses of all instances. Port parameter may + * restrict instances of interest. + * + * ARGUMENTS + * hca_index: index of HCA in the provider library. + * + * port: IPOIB_PORT_NUM as described above + * + * ip_addr_list: pointer to user-allocated space in which an array of + * IP addresses found for this hca and port will be returned + * + * ip_addr_count: number of returned addresses + * + * RETURNS + * 0 for SUCCESS + * !0 for failure + * + ***********************************************************************/ +int +ipoib_get_if( + IN uint32_t hca_index, + IN IPOIB_PORT_NUM port, + OUT struct sockaddr **ip_addr_list, + OUT int *ip_addr_count); + +/*********************************************************************** + * + * PURPOSE + * Returns a handle to this interface, to be used for subsequent + * operations + * + * ARGUMENTS + * ip_address: input IP address + * + * ipoib_handle: handle to be used in subsequent operations. + * + * RETURNS + * 0 for SUCCESS + * !0 for failure + * + ***********************************************************************/ +int +ipoib_open_if( + IN struct sockaddr *ip_address, + OUT void *ipoib_handle); + +/*********************************************************************** + * ipoib_query_if() + * + * PURPOSE + * if_query_if returns information on local ipoib_handle such as GID, + * Port number, IPoIB state, anything interesting + * + * ARGUMENTS + * ipoib_handle: handle for instance + * + * if_qry_info: info struct. Looks like: + * + * RETURNS + * 0 for SUCCESS + * !0 for failure + * + ***********************************************************************/ +int +ipoib_query_if( + IN void *ipoib_handle, + OUT IF_QUERY_INFO *if_qry_info); + +/*********************************************************************** + * + * + * PURPOSE + * Obtain a GID from an IP Address. Used by the active side of + * a connection. + * + * The behavior of this routine is specified to provide control + * over the underlying implementation. + * Returns immediately if the remote information is available. If + * callback_routine_ptr is NULL then it will block until information is + * available or known to be unavailable. If callback_routine_ptr is + * specified then it will be invoked when remote information is + * available or known to be unavailable. Remote_Addr_info contains + * remote GID information. + * + * ARGUMENTS + * ipoib_handle: handle for instance + * + * remote_ip_address: IP address of remote instance + * + * callback_routine_ptr: routine to invoke for asynch callback. If + * NULL ipoib_getaddrinfo() will block. + * + * context: argument to pass to asynch callback_routine. + * + * Remote_Addr_info: Remote GID + * + * RETURNS + * 0 for SUCCESS + * !0 for failure + * + ***********************************************************************/ +int +ipoib_getaddrinfo( + IN void *ipoib_handle, + IN struct sockaddr *remote_ip_address, + IN void *callback_routine_ptr, + IN void *context, + OUT void *Remote_Addr_info ); + +/*********************************************************************** + * + * + * PURPOSE + * Obtain an IP Address from a GID. Used by the passive side of a + * connection. + * + * The behavior of this routine is specified to provide control over + * the underlying implementation. Returns immediately if the remote + * information is available. If callback_routine_ptr is NULL then it + * will block until information is available or known to be + * unavailable. If callback_routine_ptr is specified then it will be + * invoked when remote information is available or known to be + * unavailable. + * + * ARGUMENTS + * ipoib_handle: handle for instance + * + * remote_gidAddr: Remote GID. It is not defined on how the application + * will obtain this GID from the connection manager. + * + * callback_routine_ptr: + * routine to invoke for async callback. If NULL + * ipoib_getgidinfo() will block. + * + * context: argument to pass to asynch callback_routine. + * + * remote_ip_address: + * IP address of remote instance + * + * RETURNS + * 0 for SUCCESS + * !0 for failure + * + ***********************************************************************/ +int +ipoib_getgidinfo( + IN void *ipoib_handle, + IN GID *remote_gid, + IN void *callback_routine_ptr, + IN void *context, + OUT struct sockaddr *remote_ip_address); + +/*********************************************************************** + * + * PURPOSE + * Release handle. + * + * ARGUMENTS + * ipoib_handle: handle for instance + * + * RETURNS + * 0 for SUCCESS + * !0 for failure + * + ***********************************************************************/ +int +ipoib_close( + IN void *ipoib_handle); + + +#endif /* _IPOIB_NAMING_H_ */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/include/dapl_vendor.h b/branches/WOF2-3/ulp/dapl2/dapl/include/dapl_vendor.h new file mode 100644 index 00000000..f6d3cc01 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/include/dapl_vendor.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_vendor.h + * + * PURPOSE: + * Vendor provides values for their implementation. Most of + * these values are returned in the DAT_IA_ATTR parameter of + * dat_ia_query() + * + * $Id:$ + **********************************************************************/ + +/********************************************************************** + * DAT_IA_ATTR attributes + * + * These values are used in the provider support routine + * dapls_ib_query_hca (). Many of the values there are HW + * specific, the the vendor should look to make sure they are + * appropriate for their implementation. Specifically, + * vendors are encouraged to update transport and vendor + * attributes: the reference implementation sets these to NULL. + */ + +/* + * Product name of the adapter. + * Returned in DAT_IA_ATTR.adapter_name + */ +#define VN_ADAPTER_NAME "Generic OpenFabrics HCA" + + +/* + * Vendor name + * Returned in DAT_IA_ATTR.vendor_name + */ +#define VN_VENDOR_NAME "DAPL OpenFabrics Implementation" + + +/********************************************************************** + * PROVIDER Attributes + * + * These values are used in ./common/dapl_ia_query.c, in dapl_ia_query (). + * The values below are the most common for vendors to change, but + * there are several other values that may be updated once the + * implementation becomes mature. + * + */ + +/* + * Provider Versions + * Returned in DAT_PROVIDER_ATTR.provider_version_major and + * DAT_PROVIDER_ATTR.provider_version_minor + */ + +#define VN_PROVIDER_MAJOR 2 +#define VN_PROVIDER_MINOR 0 + +/* + * Provider support for memory types. The reference implementation + * always supports DAT_MEM_TYPE_VIRTUAL and DAT_MEM_TYPE_LMR, so + * the vendor must indicate if they support DAT_MEM_TYPE_SHARED_VIRTUAL. + * Set this value to '1' if DAT_MEM_TYPE_SHARED_VIRTUAL is supported. + * + * Returned in DAT_PROVIDER_ATTR.lmr_mem_types_supported + */ + +#define VN_MEM_SHARED_VIRTUAL_SUPPORT 1 + + +/********************************************************************** + * + * This value will be assigned to dev_name_prefix in ./udapl/dapl_init.c. + * + * DAT is designed to support multiple DAPL instances simultaneously, + * with different dapl libraries originating from different providers. + * There is always the possibility of name conflicts, so a dat name + * prefix is provided to make a vendor's adapter name unique. This is + * especially true of the IBM Access API, which returns adapter + * names that are simply ordinal numbers (e.g. 0, 1, 2). If + * a vendor doesn't need or want a prefix, it should be left + * as a NULL (use ""). + * + * Values that might be used: + * #define VN_PREFIX "ia" (generic prefix) + * #define VN_PREFIX "jni" (JNI: OS Acces API) + * #define VN_PREFIX "ibm" (IBM: OS Acces API) + * #define VN_PREFIX "" (Mellanox: VAPI) + * #define VN_PREFIX "" (Intel: IB Common API) + */ +#define VN_PREFIX "ia" diff --git a/branches/WOF2-3/ulp/dapl2/dapl/openib_cma/README b/branches/WOF2-3/ulp/dapl2/dapl/openib_cma/README new file mode 100644 index 00000000..2cd4b007 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/openib_cma/README @@ -0,0 +1,40 @@ + +OpenIB uDAPL provider using rdma cma and openib verbs interfaces + +to build: + +cd dapl/udapl +make VERBS=openib_cma clean +make VERBS=openib_cma + + +Modifications to common code: + +- added dapl/openib_cma directory + + dapl/udapl/Makefile + +New files for openib_scm provider + + dapl/openib_cma/dapl_ib_cq.c + dapl/openib_cma/dapl_ib_dto.h + dapl/openib_cma/dapl_ib_mem.c + dapl/openib_cma/dapl_ib_qp.c + dapl/openib_cma/dapl_ib_util.c + dapl/openib_cma/dapl_ib_util.h + dapl/openib_cma/dapl_ib_cm.c + +A simple dapl test just for openib_scm testing... + + test/dtest/dtest.c + test/dtest/makefile + + server: dtest -s + client: dtest -h hostname + +known issues: + + no memory windows support in ibverbs, dat_create_rmr fails. + + + diff --git a/branches/WOF2-3/ulp/dapl2/dapl/openib_cma/SOURCES b/branches/WOF2-3/ulp/dapl2/dapl/openib_cma/SOURCES new file mode 100644 index 00000000..0c3764bb --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/openib_cma/SOURCES @@ -0,0 +1,55 @@ +!if $(FREEBUILD) +TARGETNAME=dapl2-ofa-cma +!else +TARGETNAME=dapl2-ofa-cmad +!endif + +TARGETPATH = ..\..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = DYNLINK +DLLENTRY = _DllMainCRTStartup + +!if $(_NT_TOOLS_VERSION) == 0x700 +DLLDEF=$O\udapl_ofa_cma_exports.def +!else +DLLDEF=$(OBJ_PATH)\$O\udapl_ofa_cma_exports.def +!endif + +USE_MSVCRT = 1 + +SOURCES = \ + udapl.rc \ + ..\dapl_common_src.c \ + ..\dapl_udapl_src.c \ + ..\openib_common.c \ + device.c \ + cm.c + +INCLUDES = ..\include;..\openib_common;..\common;windows;..\..\dat\include;\ + ..\..\dat\udat\windows;..\udapl\windows;..\..\..\..\inc\user\linux;\ + ..\..\..\..\inc;..\..\..\..\inc\user;..\..\..\libibverbs\include;\ + ..\..\..\librdmacm\include + +DAPL_OPTS = -DEXPORT_DAPL_SYMBOLS -DDAT_EXTENSIONS -DOPENIB -DCQ_WAIT_OBJECT #-DDAPL_COUNTERS + +USER_C_FLAGS = $(USER_C_FLAGS) $(DAPL_OPTS) + +!if !$(FREEBUILD) +USER_C_FLAGS = $(USER_C_FLAGS) -DDAPL_DBG +!endif + +TARGETLIBS= \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\dat2.lib \ + $(TARGETPATH)\*\winverbs.lib \ + $(TARGETPATH)\*\libibverbs.lib \ + $(TARGETPATH)\*\librdmacm.lib +!else + $(TARGETPATH)\*\dat2d.lib \ + $(TARGETPATH)\*\winverbsd.lib \ + $(TARGETPATH)\*\libibverbsd.lib \ + $(TARGETPATH)\*\librdmacmd.lib +!endif + +MSC_WARNING_LEVEL = /W1 /wd4113 diff --git a/branches/WOF2-3/ulp/dapl2/dapl/openib_cma/cm.c b/branches/WOF2-3/ulp/dapl2/dapl/openib_cma/cm.c new file mode 100644 index 00000000..c941f743 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/openib_cma/cm.c @@ -0,0 +1,1219 @@ +/* + * Copyright (c) 2005 Voltaire Inc. All rights reserved. + * Copyright (c) 2005-2007 Intel Corporation. All rights reserved. + * Copyright (c) 2004-2005, Mellanox Technologies, Inc. All rights reserved. + * Copyright (c) 2003 Topspin Corporation. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ib_cm.c + * + * PURPOSE: The OFED provider - uCMA, name and route resolution + * + * $Id: $ + * + **********************************************************************/ + +#include "dapl.h" +#include "dapl_adapter_util.h" +#include "dapl_evd_util.h" +#include "dapl_cr_util.h" +#include "dapl_name_service.h" +#include "dapl_ib_util.h" +#include "dapl_ep_util.h" +#include "dapl_vendor.h" +#include "dapl_osd.h" + +extern struct rdma_event_channel *g_cm_events; + +/* local prototypes */ +static struct dapl_cm_id *dapli_req_recv(struct dapl_cm_id *conn, + struct rdma_cm_event *event); +static void dapli_cm_active_cb(struct dapl_cm_id *conn, + struct rdma_cm_event *event); +static void dapli_cm_passive_cb(struct dapl_cm_id *conn, + struct rdma_cm_event *event); +static void dapli_addr_resolve(struct dapl_cm_id *conn); +static void dapli_route_resolve(struct dapl_cm_id *conn); + +/* cma requires 16 bit SID, in network order */ +#define IB_PORT_MOD 32001 +#define IB_PORT_BASE (65535 - IB_PORT_MOD) +#define SID_TO_PORT(SID) \ + (SID > 0xffff ? \ + htons((unsigned short)((SID % IB_PORT_MOD) + IB_PORT_BASE)) :\ + htons((unsigned short)SID)) + +#define PORT_TO_SID(p) ntohs(p) + +/* private data header to validate consumer rejects versus abnormal events */ +struct dapl_pdata_hdr { + DAT_UINT32 version; +}; + +static void dapli_addr_resolve(struct dapl_cm_id *conn) +{ + int ret; +#ifdef DAPL_DBG + struct rdma_addr *ipaddr = &conn->cm_id->route.addr; +#endif + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " addr_resolve: cm_id %p SRC %x DST %x\n", + conn->cm_id, ntohl(((struct sockaddr_in *) + &ipaddr->src_addr)->sin_addr.s_addr), + ntohl(((struct sockaddr_in *) + &ipaddr->dst_addr)->sin_addr.s_addr)); + + ret = rdma_resolve_route(conn->cm_id, conn->route_timeout); + if (ret) { + dapl_log(DAPL_DBG_TYPE_ERR, + " dapl_cma_connect: rdma_resolve_route ERR 0x%x %s\n", + ret, strerror(errno)); + dapl_evd_connection_callback(conn, + IB_CME_LOCAL_FAILURE, + NULL, 0, conn->ep); + } +} + +static void dapli_route_resolve(struct dapl_cm_id *conn) +{ + int ret; +#ifdef DAPL_DBG + struct rdma_addr *ipaddr = &conn->cm_id->route.addr; + struct rdma_ib_addr *ibaddr = &conn->cm_id->route.addr.addr.ibaddr; +#endif + + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " route_resolve: cm_id %p SRC %x DST %x PORT %d\n", + conn->cm_id, ntohl(((struct sockaddr_in *) + &ipaddr->src_addr)->sin_addr.s_addr), + ntohl(((struct sockaddr_in *) + &ipaddr->dst_addr)->sin_addr.s_addr), + ntohs(((struct sockaddr_in *) + &ipaddr->dst_addr)->sin_port)); + + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " route_resolve: SRC GID subnet %016llx id %016llx\n", + (unsigned long long) + ntohll(ibaddr->sgid.global.subnet_prefix), + (unsigned long long) + ntohll(ibaddr->sgid.global.interface_id)); + + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " route_resolve: DST GID subnet %016llx id %016llx\n", + (unsigned long long) + ntohll(ibaddr->dgid.global.subnet_prefix), + (unsigned long long) + ntohll(ibaddr->dgid.global.interface_id)); + + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " route_resolve: cm_id %p pdata %p plen %d rr %d ind %d\n", + conn->cm_id, + conn->params.private_data, + conn->params.private_data_len, + conn->params.responder_resources, + conn->params.initiator_depth); + + ret = rdma_connect(conn->cm_id, &conn->params); + if (ret) { + dapl_log(DAPL_DBG_TYPE_ERR, + " dapl_cma_connect: rdma_connect ERR %d %s\n", + ret, strerror(errno)); + goto bail; + } + return; + + bail: + dapl_evd_connection_callback(conn, + IB_CME_LOCAL_FAILURE, NULL, 0, conn->ep); +} + +dp_ib_cm_handle_t dapls_ib_cm_create(DAPL_EP *ep) +{ + dp_ib_cm_handle_t conn; + struct rdma_cm_id *cm_id; + + /* Allocate CM and initialize lock */ + if ((conn = dapl_os_alloc(sizeof(*conn))) == NULL) + return NULL; + + dapl_os_memzero(conn, sizeof(*conn)); + dapl_os_lock_init(&conn->lock); + dapls_cm_acquire(conn); + + /* create CM_ID, bind to local device, create QP */ + if (rdma_create_id(g_cm_events, &cm_id, (void *)conn, RDMA_PS_TCP)) { + dapls_cm_release(conn); + return NULL; + } + + conn->cm_id = cm_id; + + /* setup timers for address and route resolution */ + conn->arp_timeout = dapl_os_get_env_val("DAPL_CM_ARP_TIMEOUT_MS", + IB_ARP_TIMEOUT); + conn->arp_retries = dapl_os_get_env_val("DAPL_CM_ARP_RETRY_COUNT", + IB_ARP_RETRY_COUNT); + conn->route_timeout = dapl_os_get_env_val("DAPL_CM_ROUTE_TIMEOUT_MS", + IB_ROUTE_TIMEOUT); + conn->route_retries = dapl_os_get_env_val("DAPL_CM_ROUTE_RETRY_COUNT", + IB_ROUTE_RETRY_COUNT); + if (ep != NULL) { + dapl_ep_link_cm(ep, conn); + conn->ep = ep; + conn->hca = ((DAPL_IA *)ep->param.ia_handle)->hca_ptr; + } + + return conn; +} + +static void dapli_cm_dealloc(dp_ib_cm_handle_t conn) { + + dapl_os_assert(!conn->ref_count); + dapl_os_lock_destroy(&conn->lock); + dapl_os_free(conn, sizeof(*conn)); +} + +void dapls_cm_acquire(dp_ib_cm_handle_t conn) +{ + dapl_os_lock(&conn->lock); + conn->ref_count++; + dapl_os_unlock(&conn->lock); +} + +void dapls_cm_release(dp_ib_cm_handle_t conn) +{ + dapl_os_lock(&conn->lock); + conn->ref_count--; + if (conn->ref_count) { + dapl_os_unlock(&conn->lock); + return; + } + dapl_os_unlock(&conn->lock); + dapli_cm_dealloc(conn); +} + +/* BLOCKING: called from dapl_ep_free, EP link will be last ref */ +void dapls_cm_free(dp_ib_cm_handle_t conn) +{ + dapl_log(DAPL_DBG_TYPE_CM, + " cm_free: cm %p ep %p refs=%d\n", + conn, conn->ep, conn->ref_count); + + dapls_cm_release(conn); /* release alloc ref */ + + /* Destroy cm_id, wait until EP is last ref */ + dapl_os_lock(&conn->lock); + if (conn->cm_id) { + struct rdma_cm_id *cm_id = conn->cm_id; + + if (cm_id->qp) + rdma_destroy_qp(cm_id); + conn->cm_id = NULL; + dapl_os_unlock(&conn->lock); + rdma_destroy_id(cm_id); /* blocking, event processing */ + dapl_os_lock(&conn->lock); + } + + /* EP linking is last reference */ + while (conn->ref_count != 1) { + dapl_os_unlock(&conn->lock); + dapl_os_sleep_usec(10000); + dapl_os_lock(&conn->lock); + } + dapl_os_unlock(&conn->lock); + + /* unlink, dequeue from EP. Final ref so release will destroy */ + dapl_ep_unlink_cm(conn->ep, conn); +} + +static struct dapl_cm_id *dapli_req_recv(struct dapl_cm_id *conn, + struct rdma_cm_event *event) +{ + struct dapl_cm_id *new_conn; +#ifdef DAPL_DBG + struct rdma_addr *ipaddr = &event->id->route.addr; +#endif + + if (conn->sp == NULL) { + dapl_dbg_log(DAPL_DBG_TYPE_ERR, + " dapli_rep_recv: on invalid listen " "handle\n"); + return NULL; + } + + /* allocate new cm_id and merge listen parameters */ + new_conn = dapl_os_alloc(sizeof(*new_conn)); + if (new_conn) { + (void)dapl_os_memzero(new_conn, sizeof(*new_conn)); + dapl_os_lock_init(&new_conn->lock); + dapls_cm_acquire(new_conn); + new_conn->cm_id = event->id; /* provided by uCMA */ + event->id->context = new_conn; /* update CM_ID context */ + new_conn->sp = conn->sp; + new_conn->hca = conn->hca; + + /* Get requesters connect data, setup for accept */ + new_conn->params.responder_resources = + DAPL_MIN(event->param.conn.responder_resources, + conn->hca->ib_trans.rd_atom_in); + new_conn->params.initiator_depth = + DAPL_MIN(event->param.conn.initiator_depth, + conn->hca->ib_trans.rd_atom_out); + + new_conn->params.flow_control = event->param.conn.flow_control; + new_conn->params.rnr_retry_count = + event->param.conn.rnr_retry_count; + new_conn->params.retry_count = event->param.conn.retry_count; + + /* save private data */ + if (event->param.conn.private_data_len) { + dapl_os_memcpy(new_conn->p_data, + event->param.conn.private_data, + event->param.conn.private_data_len); + new_conn->params.private_data = new_conn->p_data; + new_conn->params.private_data_len = + event->param.conn.private_data_len; + } + + dapl_dbg_log(DAPL_DBG_TYPE_CM, " passive_cb: " + "REQ: SP %p PORT %d LID %d " + "NEW CONN %p ID %p pdata %p,%d\n", + new_conn->sp, ntohs(((struct sockaddr_in *) + &ipaddr->src_addr)->sin_port), + event->listen_id, new_conn, event->id, + event->param.conn.private_data, + event->param.conn.private_data_len); + + dapl_dbg_log(DAPL_DBG_TYPE_CM, " passive_cb: " + "REQ: IP SRC %x PORT %d DST %x PORT %d " + "rr %d init %d\n", ntohl(((struct sockaddr_in *) + &ipaddr->src_addr)-> + sin_addr.s_addr), + ntohs(((struct sockaddr_in *) + &ipaddr->src_addr)->sin_port), + ntohl(((struct sockaddr_in *) + &ipaddr->dst_addr)->sin_addr.s_addr), + ntohs(((struct sockaddr_in *) + &ipaddr->dst_addr)->sin_port), + new_conn->params.responder_resources, + new_conn->params.initiator_depth); + } + return new_conn; +} + +static void dapli_cm_active_cb(struct dapl_cm_id *conn, + struct rdma_cm_event *event) +{ + DAPL_OS_LOCK *lock = &conn->lock; + ib_cm_events_t ib_cm_event; + const void *pdata = NULL; + + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " active_cb: conn %p id %d event %d\n", + conn, conn->cm_id, event->event); + + /* There is a chance that we can get events after + * the consumer calls disconnect in a pending state + * since the IB CM and uDAPL states are not shared. + * In some cases, IB CM could generate either a DCONN + * or CONN_ERR after the consumer returned from + * dapl_ep_disconnect with a DISCONNECTED event + * already queued. Check state here and bail to + * avoid any events after a disconnect. + */ + if (DAPL_BAD_HANDLE(conn->ep, DAPL_MAGIC_EP)) + return; + + dapl_os_lock(&conn->ep->header.lock); + if (conn->ep->param.ep_state == DAT_EP_STATE_DISCONNECTED) { + dapl_os_unlock(&conn->ep->header.lock); + return; + } + if (event->event == RDMA_CM_EVENT_DISCONNECTED) + conn->ep->param.ep_state = DAT_EP_STATE_DISCONNECTED; + + dapl_os_unlock(&conn->ep->header.lock); + dapl_os_lock(lock); + + switch (event->event) { + case RDMA_CM_EVENT_UNREACHABLE: + case RDMA_CM_EVENT_CONNECT_ERROR: + dapl_log(DAPL_DBG_TYPE_WARN, + "dapl_cma_active: CONN_ERR event=0x%x" + " status=%d %s DST %s, %d\n", + event->event, event->status, + (event->status == -ETIMEDOUT) ? "TIMEOUT" : "", + inet_ntoa(((struct sockaddr_in *) + &conn->cm_id->route.addr.dst_addr)-> + sin_addr), + ntohs(((struct sockaddr_in *) + &conn->cm_id->route.addr.dst_addr)-> + sin_port)); + + /* per DAT SPEC provider always returns UNREACHABLE */ + ib_cm_event = IB_CME_DESTINATION_UNREACHABLE; + break; + case RDMA_CM_EVENT_REJECTED: + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " dapli_cm_active_handler: REJECTED reason=%d\n", + event->status); + + /* valid REJ from consumer will always contain private data */ + if (event->status == 28 && + event->param.conn.private_data_len) { + ib_cm_event = IB_CME_DESTINATION_REJECT_PRIVATE_DATA; + pdata = + (unsigned char *)event->param.conn. + private_data + + sizeof(struct dapl_pdata_hdr); + } else { + ib_cm_event = IB_CME_DESTINATION_REJECT; + dapl_log(DAPL_DBG_TYPE_WARN, + "dapl_cma_active: non-consumer REJ," + " reason=%d, DST %s, %d\n", + event->status, + inet_ntoa(((struct sockaddr_in *) + &conn->cm_id->route.addr. + dst_addr)->sin_addr), + ntohs(((struct sockaddr_in *) + &conn->cm_id->route.addr. + dst_addr)->sin_port)); + } + break; + case RDMA_CM_EVENT_ESTABLISHED: + dapl_log(DAPL_DBG_TYPE_CM_EST, + " CMA ACTIVE CONN: %x -> %s %x\n", + ntohs(((struct sockaddr_in *) + &conn->cm_id->route.addr.src_addr)->sin_port), + inet_ntoa(((struct sockaddr_in *) + &conn->cm_id->route.addr.dst_addr)->sin_addr), + ntohs(((struct sockaddr_in *) + &conn->cm_id->route.addr.dst_addr)->sin_port)); + + /* setup local and remote ports for ep query */ + conn->ep->param.remote_port_qual = + PORT_TO_SID(rdma_get_dst_port(conn->cm_id)); + conn->ep->param.local_port_qual = + PORT_TO_SID(rdma_get_src_port(conn->cm_id)); + + ib_cm_event = IB_CME_CONNECTED; + pdata = event->param.conn.private_data; + break; + case RDMA_CM_EVENT_DISCONNECTED: + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " active_cb: DISC EVENT - EP %p\n",conn->ep); + rdma_disconnect(conn->cm_id); /* required for DREP */ + ib_cm_event = IB_CME_DISCONNECTED; + /* validate EP handle */ + if (DAPL_BAD_HANDLE(conn->ep, DAPL_MAGIC_EP)) + conn = NULL; + break; + default: + dapl_dbg_log(DAPL_DBG_TYPE_ERR, + " dapli_cm_active_cb_handler: Unexpected CM " + "event %d on ID 0x%p\n", event->event, + conn->cm_id); + conn = NULL; + break; + } + + dapl_os_unlock(lock); + if (conn) + dapl_evd_connection_callback(conn, ib_cm_event, pdata, + event->param.conn.private_data_len, conn->ep); +} + +static void dapli_cm_passive_cb(struct dapl_cm_id *conn, + struct rdma_cm_event *event) +{ + ib_cm_events_t ib_cm_event; + struct dapl_cm_id *conn_recv = conn; + const void *pdata = NULL; + + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " passive_cb: conn %p id %d event %d\n", + conn, event->id, event->event); + + dapl_os_lock(&conn->lock); + + switch (event->event) { + case RDMA_CM_EVENT_CONNECT_REQUEST: + /* create new conn object with new conn_id from event */ + conn_recv = dapli_req_recv(conn, event); + ib_cm_event = IB_CME_CONNECTION_REQUEST_PENDING; + pdata = event->param.conn.private_data; + break; + case RDMA_CM_EVENT_UNREACHABLE: + case RDMA_CM_EVENT_CONNECT_ERROR: + dapl_log(DAPL_DBG_TYPE_WARN, + "dapl_cm_passive: CONN_ERR event=0x%x status=%d %s," + " DST %s,%d\n", + event->event, event->status, + (event->status == -ETIMEDOUT) ? "TIMEOUT" : "", + inet_ntoa(((struct sockaddr_in *) + &conn->cm_id->route.addr.dst_addr)-> + sin_addr), ntohs(((struct sockaddr_in *) + &conn->cm_id->route.addr. + dst_addr)->sin_port)); + ib_cm_event = IB_CME_DESTINATION_UNREACHABLE; + break; + case RDMA_CM_EVENT_REJECTED: + /* will alwasys be abnormal NON-consumer from active side */ + dapl_log(DAPL_DBG_TYPE_WARN, + "dapl_cm_passive: non-consumer REJ, reason=%d," + " DST %s, %d\n", + event->status, + inet_ntoa(((struct sockaddr_in *)&conn->cm_id->route.addr.dst_addr)->sin_addr), + ntohs(((struct sockaddr_in *)&conn->cm_id->route.addr.dst_addr)->sin_port)); + ib_cm_event = IB_CME_DESTINATION_REJECT; + break; + case RDMA_CM_EVENT_ESTABLISHED: + dapl_log(DAPL_DBG_TYPE_CM_EST, + " CMA PASSIVE CONN: %x <- %s %x \n", + ntohs(((struct sockaddr_in *) + &conn->cm_id->route.addr.dst_addr)->sin_port), + inet_ntoa(((struct sockaddr_in *) + &conn->cm_id->route.addr.src_addr)->sin_addr), + ntohs(((struct sockaddr_in *) + &conn->cm_id->route.addr.src_addr)->sin_port)); + ib_cm_event = IB_CME_CONNECTED; + break; + case RDMA_CM_EVENT_DISCONNECTED: + rdma_disconnect(conn->cm_id); /* required for DREP */ + ib_cm_event = IB_CME_DISCONNECTED; + /* validate SP handle context */ + if (DAPL_BAD_HANDLE(conn->sp, DAPL_MAGIC_PSP) && + DAPL_BAD_HANDLE(conn->sp, DAPL_MAGIC_RSP)) + conn_recv = NULL; + break; + default: + dapl_dbg_log(DAPL_DBG_TYPE_ERR, " passive_cb: " + "Unexpected CM event %d on ID 0x%p\n", + event->event, conn->cm_id); + conn_recv = NULL; + break; + } + + dapl_os_unlock(&conn->lock); + if (conn_recv) + dapls_cr_callback(conn_recv, ib_cm_event, pdata, + event->param.conn.private_data_len, conn_recv->sp); +} + +/************************ DAPL provider entry points **********************/ + +/* + * dapls_ib_connect + * + * Initiate a connection with the passive listener on another node + * + * Input: + * ep_handle, + * remote_ia_address, + * remote_conn_qual, + * prd_size size of private data and structure + * prd_prt pointer to private data structure + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + * + */ +DAT_RETURN dapls_ib_connect(IN DAT_EP_HANDLE ep_handle, + IN DAT_IA_ADDRESS_PTR r_addr, + IN DAT_CONN_QUAL r_qual, + IN DAT_COUNT p_size, IN void *p_data) +{ + struct dapl_ep *ep_ptr = ep_handle; + struct dapl_cm_id *conn = dapl_get_cm_from_ep(ep_ptr); + int ret; + + dapl_os_assert(conn != NULL); + + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " connect: rSID 0x%llx rPort %d, pdata %p, ln %d\n", + r_qual, ntohs(SID_TO_PORT(r_qual)), p_data, p_size); + + /* rdma conn and cm_id pre-bound; reference via ep_ptr->cm_handle */ + + /* Setup QP/CM parameters and private data in cm_id */ + (void)dapl_os_memzero(&conn->params, sizeof(conn->params)); + conn->params.responder_resources = + ep_ptr->param.ep_attr.max_rdma_read_in; + conn->params.initiator_depth = ep_ptr->param.ep_attr.max_rdma_read_out; + conn->params.flow_control = 1; + conn->params.rnr_retry_count = IB_RNR_RETRY_COUNT; + conn->params.retry_count = IB_RC_RETRY_COUNT; + if (p_size) { + dapl_os_memcpy(conn->p_data, p_data, p_size); + conn->params.private_data = conn->p_data; + conn->params.private_data_len = p_size; + } + + /* copy in remote address, need a copy for retry attempts */ + dapl_os_memcpy(&conn->r_addr, r_addr, sizeof(*r_addr)); + + /* Resolve remote address, src already bound during QP create */ + ((struct sockaddr_in *)&conn->r_addr)->sin_port = SID_TO_PORT(r_qual); + ((struct sockaddr_in *)&conn->r_addr)->sin_family = AF_INET; + + ret = rdma_resolve_addr(conn->cm_id, NULL, + (struct sockaddr *)&conn->r_addr, + conn->arp_timeout); + if (ret) { + dapl_log(DAPL_DBG_TYPE_ERR, + " dapl_cma_connect: rdma_resolve_addr ERR 0x%x %s\n", + ret, strerror(errno)); + return dapl_convert_errno(errno, "rdma_resolve_addr"); + } + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " connect: resolve_addr: cm_id %p -> %s port %d\n", + conn->cm_id, + inet_ntoa(((struct sockaddr_in *)&conn->r_addr)->sin_addr), + ((struct sockaddr_in *)&conn->r_addr)->sin_port); + + return DAT_SUCCESS; +} + +/* + * dapls_ib_disconnect + * + * Disconnect an EP + * + * Input: + * ep_handle, + * disconnect_flags + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * + */ +DAT_RETURN +dapls_ib_disconnect(IN DAPL_EP * ep_ptr, IN DAT_CLOSE_FLAGS close_flags) +{ + struct dapl_cm_id *conn = dapl_get_cm_from_ep(ep_ptr); + + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " disconnect(ep %p, conn %p, id %d flags %x)\n", + ep_ptr, conn, (conn ? conn->cm_id : 0), close_flags); + + if ((conn == NULL) || (conn->cm_id == NULL)) + return DAT_SUCCESS; + + /* no graceful half-pipe disconnect option */ + rdma_disconnect(conn->cm_id); + + /* ABRUPT close, wait for callback and DISCONNECTED state */ + if (close_flags == DAT_CLOSE_ABRUPT_FLAG) { + dapl_os_lock(&ep_ptr->header.lock); + while (ep_ptr->param.ep_state != DAT_EP_STATE_DISCONNECTED) { + dapl_os_unlock(&ep_ptr->header.lock); + dapl_os_sleep_usec(10000); + dapl_os_lock(&ep_ptr->header.lock); + } + dapl_os_unlock(&ep_ptr->header.lock); + } + + /* + * DAT event notification occurs from the callback + * Note: will fire even if DREQ goes unanswered on timeout + */ + return DAT_SUCCESS; +} + +/* + * dapls_ib_disconnect_clean + * + * Clean up outstanding connection data. This routine is invoked + * after the final disconnect callback has occurred. Only on the + * ACTIVE side of a connection. + * + * Input: + * ep_ptr DAPL_EP + * active Indicates active side of connection + * + * Output: + * none + * + * Returns: + * void + * + */ +void +dapls_ib_disconnect_clean(IN DAPL_EP * ep_ptr, + IN DAT_BOOLEAN active, + IN const ib_cm_events_t ib_cm_event) +{ + /* nothing to do */ +} + +/* + * dapl_ib_setup_conn_listener + * + * Have the CM set up a connection listener. + * + * Input: + * ibm_hca_handle HCA handle + * qp_handle QP handle + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INTERNAL_ERROR + * DAT_CONN_QUAL_UNAVAILBLE + * DAT_CONN_QUAL_IN_USE + * + */ +DAT_RETURN +dapls_ib_setup_conn_listener(IN DAPL_IA * ia_ptr, + IN DAT_UINT64 ServiceID, IN DAPL_SP * sp_ptr) +{ + DAT_RETURN dat_status = DAT_SUCCESS; + ib_cm_srvc_handle_t conn; + DAT_SOCK_ADDR6 addr; /* local binding address */ + + /* Allocate CM and initialize lock */ + if ((conn = dapl_os_alloc(sizeof(*conn))) == NULL) + return DAT_INSUFFICIENT_RESOURCES; + + dapl_os_memzero(conn, sizeof(*conn)); + dapl_os_lock_init(&conn->lock); + dapls_cm_acquire(conn); + + /* create CM_ID, bind to local device, create QP */ + if (rdma_create_id + (g_cm_events, &conn->cm_id, (void *)conn, RDMA_PS_TCP)) { + dapls_cm_release(conn); + return (dapl_convert_errno(errno, "rdma_create_id")); + } + + /* open identifies the local device; per DAT specification */ + /* Get family and address then set port to consumer's ServiceID */ + dapl_os_memcpy(&addr, &ia_ptr->hca_ptr->hca_address, sizeof(addr)); + ((struct sockaddr_in *)&addr)->sin_port = SID_TO_PORT(ServiceID); + + if (rdma_bind_addr(conn->cm_id, (struct sockaddr *)&addr)) { + if ((errno == EBUSY) || (errno == EADDRINUSE) || + (errno == EADDRNOTAVAIL)) + dat_status = DAT_CONN_QUAL_IN_USE; + else + dat_status = + dapl_convert_errno(errno, "rdma_bind_addr"); + goto bail; + } + + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " listen(ia_ptr %p SID 0x%llx Port %d sp %p conn %p id %d)\n", + ia_ptr, ServiceID, ntohs(SID_TO_PORT(ServiceID)), + sp_ptr, conn, conn->cm_id); + + sp_ptr->cm_srvc_handle = conn; + conn->sp = sp_ptr; + conn->hca = ia_ptr->hca_ptr; + + dapl_dbg_log(DAPL_DBG_TYPE_EP, + " listen(conn=%p cm_id=%d)\n", + sp_ptr->cm_srvc_handle, conn->cm_id); + + if (rdma_listen(conn->cm_id, 0)) { /* max cma backlog */ + + if ((errno == EBUSY) || (errno == EADDRINUSE) || + (errno == EADDRNOTAVAIL)) + dat_status = DAT_CONN_QUAL_IN_USE; + else + dat_status = + dapl_convert_errno(errno, "rdma_listen"); + goto bail; + } + + /* success */ + return DAT_SUCCESS; + +bail: + rdma_destroy_id(conn->cm_id); + dapls_cm_release(conn); + return dat_status; +} + +/* + * dapl_ib_remove_conn_listener + * + * Have the CM remove a connection listener. + * + * Input: + * ia_handle IA handle + * ServiceID IB Channel Service ID + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_STATE + * + */ +DAT_RETURN +dapls_ib_remove_conn_listener(IN DAPL_IA * ia_ptr, IN DAPL_SP * sp_ptr) +{ + ib_cm_srvc_handle_t conn = sp_ptr->cm_srvc_handle; + + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " remove_listen(ia_ptr %p sp_ptr %p conn %p)\n", + ia_ptr, sp_ptr, conn); + + if (conn != IB_INVALID_HANDLE) { + sp_ptr->cm_srvc_handle = NULL; + if (conn->cm_id) { + rdma_destroy_id(conn->cm_id); + conn->cm_id = NULL; + } + dapls_cm_release(conn); + } + + return DAT_SUCCESS; +} + +/* + * dapls_ib_accept_connection + * + * Perform necessary steps to accept a connection + * + * Input: + * cr_handle + * ep_handle + * private_data_size + * private_data + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INTERNAL_ERROR + * + */ +DAT_RETURN +dapls_ib_accept_connection(IN DAT_CR_HANDLE cr_handle, + IN DAT_EP_HANDLE ep_handle, + IN DAT_COUNT p_size, IN const DAT_PVOID p_data) +{ + DAPL_CR *cr_ptr = (DAPL_CR *) cr_handle; + DAPL_EP *ep_ptr = (DAPL_EP *) ep_handle; + DAPL_IA *ia_ptr = ep_ptr->header.owner_ia; + struct dapl_cm_id *cr_conn = cr_ptr->ib_cm_handle; + struct dapl_cm_id *ep_conn = dapl_get_cm_from_ep(ep_ptr); + int ret; + DAT_RETURN dat_status; + + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " accept(cr %p conn %p, id %p, p_data %p, p_sz=%d)\n", + cr_ptr, cr_conn, cr_conn->cm_id, p_data, p_size); + + /* Obtain size of private data structure & contents */ + if (p_size > IB_MAX_REP_PDATA_SIZE) { + dat_status = DAT_ERROR(DAT_LENGTH_ERROR, DAT_NO_SUBTYPE); + goto bail; + } + + if (ep_ptr->qp_state == DAPL_QP_STATE_UNATTACHED) { + /* + * If we are lazy attaching the QP then we may need to + * hook it up here. Typically, we run this code only for + * DAT_PSP_PROVIDER_FLAG + */ + dat_status = dapls_ib_qp_alloc(ia_ptr, ep_ptr, NULL); + if (dat_status != DAT_SUCCESS) { + dapl_log(DAPL_DBG_TYPE_ERR, + " dapl_cma_accept: qp_alloc ERR %d\n", + dat_status); + goto bail; + } + } + + /* + * Validate device and port in EP cm_id against inbound + * CR cm_id. The pre-allocated EP cm_id is already bound to + * a local device (cm_id and QP) when created. Move the QP + * to the new cm_id only if device and port numbers match. + */ + if (ep_conn->cm_id->verbs == cr_conn->cm_id->verbs && + ep_conn->cm_id->port_num == cr_conn->cm_id->port_num) { + /* move QP to new cr_conn, remove QP ref in EP cm_id */ + cr_conn->cm_id->qp = ep_conn->cm_id->qp; + + /* remove old CM to EP linking, destroy CM object */ + dapl_ep_unlink_cm(ep_ptr, ep_conn); + ep_conn->cm_id->qp = NULL; + ep_conn->ep = NULL; + rdma_destroy_id(ep_conn->cm_id); + dapls_cm_release(ep_conn); + + /* add new CM to EP linking, qp_handle unchanged */ + dapl_ep_link_cm(ep_ptr, cr_conn); + cr_conn->ep = ep_ptr; + } else { + dapl_log(DAPL_DBG_TYPE_ERR, + " dapl_cma_accept: ERR dev(%p!=%p) or" + " port mismatch(%d!=%d)\n", + ep_conn->cm_id->verbs, cr_conn->cm_id->verbs, + ntohs(ep_conn->cm_id->port_num), + ntohs(cr_conn->cm_id->port_num)); + dat_status = DAT_INTERNAL_ERROR; + goto bail; + } + + cr_ptr->param.local_ep_handle = ep_handle; + cr_conn->params.private_data = p_data; + cr_conn->params.private_data_len = p_size; + + ret = rdma_accept(cr_conn->cm_id, &cr_conn->params); + if (ret) { + dapl_log(DAPL_DBG_TYPE_ERR, " dapl_rdma_accept: ERR %d %s\n", + ret, strerror(errno)); + dat_status = dapl_convert_errno(errno, "accept"); + + /* remove new cr_conn EP to CM linking */ + dapl_ep_unlink_cm(ep_ptr, cr_conn); + goto bail; + } + + /* setup local and remote ports for ep query */ + /* Note: port qual in network order */ + ep_ptr->param.remote_port_qual = + PORT_TO_SID(rdma_get_dst_port(cr_conn->cm_id)); + ep_ptr->param.local_port_qual = + PORT_TO_SID(rdma_get_src_port(cr_conn->cm_id)); + + return DAT_SUCCESS; +bail: + rdma_reject(cr_conn->cm_id, NULL, 0); + + /* no EP linking, ok to destroy */ + rdma_destroy_id(cr_conn->cm_id); + dapls_cm_release(cr_conn); + return dat_status; +} + +/* + * dapls_ib_reject_connection + * + * Reject a connection + * + * Input: + * cr_handle + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INTERNAL_ERROR + * + */ +DAT_RETURN +dapls_ib_reject_connection(IN dp_ib_cm_handle_t cm_handle, + IN int reason, + IN DAT_COUNT private_data_size, + IN const DAT_PVOID private_data) +{ + int ret; + int offset = sizeof(struct dapl_pdata_hdr); + struct dapl_pdata_hdr pdata_hdr; + + memset(&pdata_hdr, 0, sizeof pdata_hdr); + pdata_hdr.version = htonl((DAT_VERSION_MAJOR << 24) | + (DAT_VERSION_MINOR << 16) | + (VN_PROVIDER_MAJOR << 8) | + (VN_PROVIDER_MINOR)); + + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " reject: handle %p reason %x, ver=%x, data %p, sz=%d\n", + cm_handle, reason, ntohl(pdata_hdr.version), + private_data, private_data_size); + + if (cm_handle == IB_INVALID_HANDLE) { + dapl_dbg_log(DAPL_DBG_TYPE_ERR, + " reject: invalid handle: reason %d\n", reason); + return DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_CR); + } + + /* setup pdata_hdr and users data, in CR pdata buffer */ + dapl_os_memcpy(cm_handle->p_data, &pdata_hdr, offset); + if (private_data_size) + dapl_os_memcpy(cm_handle->p_data + offset, + private_data, private_data_size); + + /* + * Always some private data with reject so active peer can + * determine real application reject from an abnormal + * application termination + */ + ret = rdma_reject(cm_handle->cm_id, + cm_handle->p_data, offset + private_data_size); + + /* no EP linking, ok to destroy */ + rdma_destroy_id(cm_handle->cm_id); + dapls_cm_release(cm_handle); + return dapl_convert_errno(ret, "reject"); +} + +/* + * dapls_ib_cm_remote_addr + * + * Obtain the remote IP address given a connection + * + * Input: + * cr_handle + * + * Output: + * remote_ia_address: where to place the remote address + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + * + */ +DAT_RETURN +dapls_ib_cm_remote_addr(IN DAT_HANDLE dat_handle, OUT DAT_SOCK_ADDR6 * raddr) +{ + DAPL_HEADER *header; + dp_ib_cm_handle_t conn; + struct rdma_addr *ipaddr; + + dapl_dbg_log(DAPL_DBG_TYPE_EP, + " remote_addr(cm_handle=%p, r_addr=%p)\n", + dat_handle, raddr); + + header = (DAPL_HEADER *) dat_handle; + + if (header->magic == DAPL_MAGIC_EP) + conn = dapl_get_cm_from_ep((DAPL_EP *) dat_handle); + else if (header->magic == DAPL_MAGIC_CR) + conn = ((DAPL_CR *) dat_handle)->ib_cm_handle; + else + return DAT_INVALID_HANDLE; + + /* get remote IP address from cm_id route */ + ipaddr = &conn->cm_id->route.addr; + + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " remote_addr: conn %p id %p SRC %x DST %x PORT %d\n", + conn, conn->cm_id, + ntohl(((struct sockaddr_in *) + &ipaddr->src_addr)->sin_addr.s_addr), + ntohl(((struct sockaddr_in *) + &ipaddr->dst_addr)->sin_addr.s_addr), + ntohs(((struct sockaddr_in *) + &ipaddr->dst_addr)->sin_port)); + + dapl_os_memcpy(raddr, &ipaddr->dst_addr, sizeof(DAT_SOCK_ADDR)); + return DAT_SUCCESS; +} + +/* + * dapls_ib_private_data_size + * + * Return the size of max private data + * + * Input: + * hca_ptr hca pointer, needed for transport type + * + * Output: + * None + * + * Returns: + * maximum private data rdma_cm will supply from transport. + * + */ +int dapls_ib_private_data_size(IN DAPL_HCA * hca_ptr) +{ + return RDMA_MAX_PRIVATE_DATA; +} + +void dapli_cma_event_cb(void) +{ + struct rdma_cm_event *event; + + /* process one CM event, fairness, non-blocking */ + if (!rdma_get_cm_event(g_cm_events, &event)) { + struct dapl_cm_id *conn; + + /* set proper conn from cm_id context */ + if (event->event == RDMA_CM_EVENT_CONNECT_REQUEST) + conn = (struct dapl_cm_id *)event->listen_id->context; + else + conn = (struct dapl_cm_id *)event->id->context; + + dapls_cm_acquire(conn); + + /* destroying cm_id, consumer thread blocking waiting for ACK */ + if (conn->cm_id == NULL) { + dapls_cm_release(conn); + rdma_ack_cm_event(event); + return; + } + + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " cm_event: EVENT=%d ID=%p LID=%p CTX=%p\n", + event->event, event->id, event->listen_id, conn); + + switch (event->event) { + case RDMA_CM_EVENT_ADDR_RESOLVED: + dapli_addr_resolve(conn); + break; + + case RDMA_CM_EVENT_ROUTE_RESOLVED: + dapli_route_resolve(conn); + break; + + case RDMA_CM_EVENT_ADDR_ERROR: + dapl_log(DAPL_DBG_TYPE_WARN, + "dapl_cma_active: CM ADDR ERROR: ->" + " DST %s retry (%d)..\n", + inet_ntoa(((struct sockaddr_in *) + &conn->r_addr)->sin_addr), + conn->arp_retries); + + /* retry address resolution */ + if ((--conn->arp_retries) && + (event->status == -ETIMEDOUT)) { + int ret; + ret = rdma_resolve_addr(conn->cm_id, NULL, + (struct sockaddr *) + &conn->r_addr, + conn->arp_timeout); + if (!ret) + break; + else { + dapl_dbg_log(DAPL_DBG_TYPE_WARN, + " ERROR: rdma_resolve_addr = " + "%d %s\n", + ret, strerror(errno)); + } + } + /* retries exhausted or resolve_addr failed */ + dapl_log(DAPL_DBG_TYPE_ERR, + "dapl_cma_active: ARP_ERR, retries(%d)" + " exhausted -> DST %s,%d\n", + IB_ARP_RETRY_COUNT, + inet_ntoa(((struct sockaddr_in *) + &conn->cm_id->route.addr.dst_addr)-> + sin_addr), + ntohs(((struct sockaddr_in *) + &conn->cm_id->route.addr.dst_addr)-> + sin_port)); + + dapl_evd_connection_callback(conn, + IB_CME_DESTINATION_UNREACHABLE, + NULL, 0, conn->ep); + break; + + case RDMA_CM_EVENT_ROUTE_ERROR: + dapl_log(DAPL_DBG_TYPE_WARN, + "dapl_cma_active: CM ROUTE ERROR: ->" + " DST %s retry (%d)..\n", + inet_ntoa(((struct sockaddr_in *) + &conn->r_addr)->sin_addr), + conn->route_retries); + + /* retry route resolution */ + if ((--conn->route_retries) && + (event->status == -ETIMEDOUT)) + dapli_addr_resolve(conn); + else { + dapl_log(DAPL_DBG_TYPE_ERR, + "dapl_cma_active: PATH_RECORD_ERR," + " retries(%d) exhausted, DST %s,%d\n", + IB_ROUTE_RETRY_COUNT, + inet_ntoa(((struct sockaddr_in *) + &conn->cm_id->route.addr. + dst_addr)->sin_addr), + ntohs(((struct sockaddr_in *) + &conn->cm_id->route.addr. + dst_addr)->sin_port)); + + dapl_evd_connection_callback(conn, + IB_CME_DESTINATION_UNREACHABLE, + NULL, 0, conn->ep); + } + break; + + case RDMA_CM_EVENT_DEVICE_REMOVAL: + dapl_evd_connection_callback(conn, + IB_CME_LOCAL_FAILURE, + NULL, 0, conn->ep); + break; + case RDMA_CM_EVENT_CONNECT_REQUEST: + case RDMA_CM_EVENT_CONNECT_ERROR: + case RDMA_CM_EVENT_UNREACHABLE: + case RDMA_CM_EVENT_REJECTED: + case RDMA_CM_EVENT_ESTABLISHED: + case RDMA_CM_EVENT_DISCONNECTED: + /* passive or active */ + if (conn->sp) + dapli_cm_passive_cb(conn, event); + else + dapli_cm_active_cb(conn, event); + break; + case RDMA_CM_EVENT_CONNECT_RESPONSE: +#ifdef RDMA_CM_EVENT_TIMEWAIT_EXIT + case RDMA_CM_EVENT_TIMEWAIT_EXIT: +#endif + break; + default: + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " cm_event: UNEXPECTED EVENT=%p ID=%p CTX=%p\n", + event->event, event->id, + event->id->context); + break; + } + + /* ack event, unblocks destroy_cm_id in consumer threads */ + rdma_ack_cm_event(event); + dapls_cm_release(conn); + } +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/openib_cma/dapl_ib_util.h b/branches/WOF2-3/ulp/dapl2/dapl/openib_cma/dapl_ib_util.h new file mode 100644 index 00000000..471bd7ff --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/openib_cma/dapl_ib_util.h @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2005-2009 Intel Corporation. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ +/* + * Definitions specific to OpenIB CMA provider. + * Connection manager - rdma_cma, provided in separate library. + */ +#ifndef _DAPL_IB_UTIL_H_ +#define _DAPL_IB_UTIL_H_ +#define _OPENIB_CMA_ + +#include +#include "openib_osd.h" +#include "dapl_ib_common.h" + +#define IB_RC_RETRY_COUNT 7 +#define IB_RNR_RETRY_COUNT 7 +#define IB_CM_RESPONSE_TIMEOUT 23 /* 16 sec */ +#define IB_CM_RETRIES 15 /* 240 sec total default */ +#define IB_ARP_TIMEOUT 4000 /* 4 sec */ +#define IB_ARP_RETRY_COUNT 15 /* 60 sec total */ +#define IB_ROUTE_TIMEOUT 4000 /* 4 sec */ +#define IB_ROUTE_RETRY_COUNT 15 /* 60 sec total */ +#define IB_MAX_AT_RETRY 3 + +/* CMA private data areas, use CMA max with known transport definitions */ +#ifndef RDMA_MAX_PRIVATE_DATA +#if defined(_WIN64) || defined(_WIN32) +#define RDMA_MAX_PRIVATE_DATA 64 +#else +#define RDMA_MAX_PRIVATE_DATA 256 +#endif +#endif + +#define CMA_PDATA_HDR 36 +#define IB_MAX_REQ_PDATA_SIZE DAPL_MIN((92-CMA_PDATA_HDR),RDMA_MAX_PRIVATE_DATA) +#define IB_MAX_REP_PDATA_SIZE DAPL_MIN((196-CMA_PDATA_HDR),RDMA_MAX_PRIVATE_DATA) +#define IB_MAX_REJ_PDATA_SIZE DAPL_MIN((148-CMA_PDATA_HDR),RDMA_MAX_PRIVATE_DATA) +#define IB_MAX_DREQ_PDATA_SIZE DAPL_MIN((220-CMA_PDATA_HDR),RDMA_MAX_PRIVATE_DATA) +#define IB_MAX_DREP_PDATA_SIZE DAPL_MIN((224-CMA_PDATA_HDR),RDMA_MAX_PRIVATE_DATA) +#define IWARP_MAX_PDATA_SIZE DAPL_MIN((512-CMA_PDATA_HDR),RDMA_MAX_PRIVATE_DATA) + +/* DAPL CM objects MUST include list_entry, ref_count, event for EP linking */ +struct dapl_cm_id { + struct dapl_llist_entry list_entry; + struct dapl_llist_entry local_entry; + DAPL_OS_WAIT_OBJECT event; + DAPL_OS_LOCK lock; + int ref_count; + int arp_retries; + int arp_timeout; + int route_retries; + int route_timeout; + struct rdma_cm_id *cm_id; + struct dapl_hca *hca; + struct dapl_sp *sp; + struct dapl_ep *ep; + struct rdma_conn_param params; + DAT_SOCK_ADDR6 r_addr; + int p_len; + unsigned char p_data[256]; /* dapl max private data size */ + ib_cm_msg_t dst; + struct ibv_ah *ah; +}; + +typedef struct dapl_cm_id *dp_ib_cm_handle_t; +typedef struct dapl_cm_id *ib_cm_srvc_handle_t; + +/* ib_hca_transport_t, specific to this implementation */ +typedef struct _ib_hca_transport +{ + struct dapl_llist_entry entry; + int destroy; + struct rdma_cm_id *cm_id; + struct ibv_comp_channel *ib_cq; + ib_cq_handle_t ib_cq_empty; + int max_inline_send; + ib_async_handler_t async_unafiliated; + void *async_un_ctx; + ib_async_cq_handler_t async_cq_error; + ib_async_dto_handler_t async_cq; + ib_async_qp_handler_t async_qp_error; + uint8_t max_cm_timeout; + uint8_t max_cm_retries; + /* device attributes */ + int rd_atom_in; + int rd_atom_out; + struct ibv_context *ib_ctx; + struct ibv_device *ib_dev; + /* dapls_modify_qp_state */ + uint16_t lid; + uint8_t ack_timer; + uint8_t ack_retry; + uint8_t rnr_timer; + uint8_t rnr_retry; + uint8_t global; + uint8_t hop_limit; + uint8_t tclass; + uint8_t mtu; + DAT_NAMED_ATTR named_attr; + uint8_t sl; + uint16_t pkey; + int pkey_idx; +} ib_hca_transport_t; + +/* prototypes */ +void dapli_thread(void *arg); +DAT_RETURN dapli_ib_thread_init(void); +void dapli_ib_thread_destroy(void); +void dapli_cma_event_cb(void); +void dapli_async_event_cb(struct _ib_hca_transport *tp); +void dapli_cq_event_cb(struct _ib_hca_transport *tp); +dp_ib_cm_handle_t dapls_ib_cm_create(DAPL_EP *ep); +void dapls_cm_acquire(dp_ib_cm_handle_t cm); +void dapls_cm_release(dp_ib_cm_handle_t cm); +void dapls_cm_free(dp_ib_cm_handle_t cm_ptr); + +#ifdef DAPL_COUNTERS +STATIC _INLINE_ void dapls_print_cm_list(IN DAPL_IA * ia_ptr) +{ + return; +} +#endif + +#endif /* _DAPL_IB_UTIL_H_ */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/openib_cma/device.c b/branches/WOF2-3/ulp/dapl2/dapl/openib_cma/device.c new file mode 100644 index 00000000..e4ff22eb --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/openib_cma/device.c @@ -0,0 +1,718 @@ +/* + * Copyright (c) 2005-2008 Intel Corporation. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_ib_util.c + * + * PURPOSE: OFED provider - init, open, close, utilities, work thread + * + * $Id:$ + * + **********************************************************************/ + +#ifdef RCSID +static const char rcsid[] = "$Id: $"; +#endif + +#include "openib_osd.h" +#include "dapl.h" +#include "dapl_adapter_util.h" +#include "dapl_ib_util.h" +#include "dapl_osd.h" + +#include + +struct rdma_event_channel *g_cm_events = NULL; +ib_thread_state_t g_ib_thread_state = 0; +DAPL_OS_THREAD g_ib_thread; +DAPL_OS_LOCK g_hca_lock; +struct dapl_llist_entry *g_hca_list; + +#if defined(_WIN64) || defined(_WIN32) +#include + +static COMP_SET ufds; + +static int dapls_os_init(void) +{ + return CompSetInit(&ufds); +} + +static void dapls_os_release(void) +{ + CompSetCleanup(&ufds); +} + +static int dapls_config_cm_channel(struct rdma_event_channel *channel) +{ + channel->channel.Milliseconds = 0; + return 0; +} + +static int dapls_config_verbs(struct ibv_context *verbs) +{ + verbs->channel.Milliseconds = 0; + return 0; +} + +static int dapls_config_comp_channel(struct ibv_comp_channel *channel) +{ + channel->comp_channel.Milliseconds = 0; + return 0; +} + +static int dapls_thread_signal(void) +{ + CompSetCancel(&ufds); + return 0; +} +#else // _WIN64 || WIN32 + +int g_ib_pipe[2]; + +static int dapls_os_init(void) +{ + /* create pipe for waking up work thread */ + return pipe(g_ib_pipe); +} + +static void dapls_os_release(void) +{ + /* close pipe? */ +} + + +static int dapls_config_fd(int fd) +{ + int opts; + + opts = fcntl(fd, F_GETFL); + if (opts < 0 || fcntl(fd, F_SETFL, opts | O_NONBLOCK) < 0) { + dapl_log(DAPL_DBG_TYPE_ERR, + " dapls_config_fd: fcntl on fd %d ERR %d %s\n", + fd, opts, strerror(errno)); + return errno; + } + + return 0; +} + +static int dapls_config_cm_channel(struct rdma_event_channel *channel) +{ + return dapls_config_fd(channel->fd); +} + +static int dapls_config_verbs(struct ibv_context *verbs) +{ + return dapls_config_fd(verbs->async_fd); +} + +static int dapls_config_comp_channel(struct ibv_comp_channel *channel) +{ + return dapls_config_fd(channel->fd); +} + +static int dapls_thread_signal(void) +{ + return write(g_ib_pipe[1], "w", sizeof "w"); +} +#endif + +/* Get IP address using network name, address, or device name */ +static int getipaddr(char *name, char *addr, int len) +{ + struct addrinfo *res; + + /* assume netdev for first attempt, then network and address type */ + if (getipaddr_netdev(name, addr, len)) { + if (getaddrinfo(name, NULL, NULL, &res)) { + dapl_log(DAPL_DBG_TYPE_ERR, + " open_hca: getaddr_netdev ERROR:" + " %s. Is %s configured?\n", + strerror(errno), name); + return 1; + } else { + if (len >= res->ai_addrlen) + memcpy(addr, res->ai_addr, res->ai_addrlen); + else { + freeaddrinfo(res); + return 1; + } + freeaddrinfo(res); + } + } + + dapl_dbg_log( + DAPL_DBG_TYPE_UTIL, + " getipaddr: family %d port %d addr %d.%d.%d.%d\n", + ((struct sockaddr_in *)addr)->sin_family, + ((struct sockaddr_in *)addr)->sin_port, + ((struct sockaddr_in *)addr)->sin_addr.s_addr >> 0 & 0xff, + ((struct sockaddr_in *)addr)->sin_addr.s_addr >> 8 & 0xff, + ((struct sockaddr_in *)addr)->sin_addr.s_addr >> 16 & 0xff, + ((struct sockaddr_in *)addr)->sin_addr. + s_addr >> 24 & 0xff); + + return 0; +} + +/* + * dapls_ib_init, dapls_ib_release + * + * Initialize Verb related items for device open + * + * Input: + * none + * + * Output: + * none + * + * Returns: + * 0 success, -1 error + * + */ +DAT_UINT32 g_parent = 0; +int32_t dapls_ib_init(void) +{ + g_parent = dapl_os_getpid(); + + /* initialize hca_list lock */ + dapl_os_lock_init(&g_hca_lock); + + /* initialize hca list for CQ events */ + dapl_llist_init_head(&g_hca_list); + + if (dapls_os_init()) + return 1; + + return 0; +} + +int32_t dapls_ib_release(void) +{ + /* only parent will cleanup */ + if (dapl_os_getpid() != g_parent) + return 0; + + dapli_ib_thread_destroy(); + if (g_cm_events != NULL) + rdma_destroy_event_channel(g_cm_events); + dapls_os_release(); + return 0; +} + +/* + * dapls_ib_open_hca + * + * Open HCA + * + * Input: + * *hca_name pointer to provider device name + * *ib_hca_handle_p pointer to provide HCA handle + * + * Output: + * none + * + * Return: + * DAT_SUCCESS + * dapl_convert_errno + * + */ +DAT_RETURN dapls_ib_open_hca(IN IB_HCA_NAME hca_name, IN DAPL_HCA * hca_ptr) +{ + struct rdma_cm_id *cm_id = NULL; + union ibv_gid *gid; + int ret; + DAT_RETURN dat_status; + + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, + " open_hca: %s - %p\n", hca_name, hca_ptr); + + /* Setup the global cm event channel */ + dapl_os_lock(&g_hca_lock); + if (g_cm_events == NULL) { + g_cm_events = rdma_create_event_channel(); + if (g_cm_events == NULL) { + dapl_dbg_log(DAPL_DBG_TYPE_ERR, + " open_hca: ERR - RDMA channel %s\n", + strerror(errno)); + dapl_os_unlock(&g_hca_lock); + return DAT_INTERNAL_ERROR; + } + } + dapl_os_unlock(&g_hca_lock); + + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, + " open_hca: RDMA channel created (%p)\n", g_cm_events); + + /* HCA name will be hostname or IP address */ + if (getipaddr((char *)hca_name, + (char *)&hca_ptr->hca_address, + sizeof(DAT_SOCK_ADDR6))) + return DAT_INVALID_ADDRESS; + + /* cm_id will bind local device/GID based on IP address */ + if (rdma_create_id(g_cm_events, &cm_id, + (void *)hca_ptr, RDMA_PS_TCP)) { + dapl_log(DAPL_DBG_TYPE_ERR, + " open_hca: rdma_create ERR %s\n", strerror(errno)); + return DAT_INTERNAL_ERROR; + } + ret = rdma_bind_addr(cm_id, (struct sockaddr *)&hca_ptr->hca_address); + if ((ret) || (cm_id->verbs == NULL)) { + rdma_destroy_id(cm_id); + dapl_log(DAPL_DBG_TYPE_ERR, + " open_hca: rdma_bind ERR %s." + " Is %s configured?\n", strerror(errno), hca_name); + rdma_destroy_id(cm_id); + return DAT_INVALID_ADDRESS; + } + + /* keep reference to IB device and cm_id */ + hca_ptr->ib_trans.cm_id = cm_id; + hca_ptr->ib_hca_handle = cm_id->verbs; + dapls_config_verbs(cm_id->verbs); + hca_ptr->port_num = cm_id->port_num; + hca_ptr->ib_trans.ib_dev = cm_id->verbs->device; + hca_ptr->ib_trans.ib_ctx = cm_id->verbs; + gid = &cm_id->route.addr.addr.ibaddr.sgid; + + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, + " open_hca: ctx=%p port=%d GID subnet %016llx" + " id %016llx\n", cm_id->verbs, cm_id->port_num, + (unsigned long long)ntohll(gid->global.subnet_prefix), + (unsigned long long)ntohll(gid->global.interface_id)); + + /* support for EVD's with CNO's: one channel via thread */ + hca_ptr->ib_trans.ib_cq = + ibv_create_comp_channel(hca_ptr->ib_hca_handle); + if (hca_ptr->ib_trans.ib_cq == NULL) { + dapl_log(DAPL_DBG_TYPE_ERR, + " open_hca: ibv_create_comp_channel ERR %s\n", + strerror(errno)); + rdma_destroy_id(cm_id); + return DAT_INTERNAL_ERROR; + } + if (dapls_config_comp_channel(hca_ptr->ib_trans.ib_cq)) { + rdma_destroy_id(cm_id); + return DAT_INTERNAL_ERROR; + } + + /* set inline max with env or default, get local lid and gid 0 */ + if (hca_ptr->ib_hca_handle->device->transport_type + == IBV_TRANSPORT_IWARP) + hca_ptr->ib_trans.max_inline_send = + dapl_os_get_env_val("DAPL_MAX_INLINE", + INLINE_SEND_IWARP_DEFAULT); + else + hca_ptr->ib_trans.max_inline_send = + dapl_os_get_env_val("DAPL_MAX_INLINE", + INLINE_SEND_IB_DEFAULT); + + /* set CM timer defaults */ + hca_ptr->ib_trans.max_cm_timeout = + dapl_os_get_env_val("DAPL_MAX_CM_RESPONSE_TIME", + IB_CM_RESPONSE_TIMEOUT); + hca_ptr->ib_trans.max_cm_retries = + dapl_os_get_env_val("DAPL_MAX_CM_RETRIES", IB_CM_RETRIES); + + /* set default IB MTU */ + hca_ptr->ib_trans.mtu = dapl_ib_mtu(2048); + + dat_status = dapli_ib_thread_init(); + if (dat_status != DAT_SUCCESS) + return dat_status; + /* + * Put new hca_transport on list for async and CQ event processing + * Wakeup work thread to add to polling list + */ + dapl_llist_init_entry((DAPL_LLIST_ENTRY *) &hca_ptr->ib_trans.entry); + dapl_os_lock(&g_hca_lock); + dapl_llist_add_tail(&g_hca_list, + (DAPL_LLIST_ENTRY *) &hca_ptr->ib_trans.entry, + &hca_ptr->ib_trans.entry); + if (dapls_thread_signal() == -1) + dapl_log(DAPL_DBG_TYPE_UTIL, + " open_hca: thread wakeup error = %s\n", + strerror(errno)); + dapl_os_unlock(&g_hca_lock); + + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, + " open_hca: %s, %s %d.%d.%d.%d INLINE_MAX=%d\n", hca_name, + ((struct sockaddr_in *) + &hca_ptr->hca_address)->sin_family == AF_INET ? + "AF_INET" : "AF_INET6", + ((struct sockaddr_in *) + &hca_ptr->hca_address)->sin_addr.s_addr >> 0 & 0xff, + ((struct sockaddr_in *) + &hca_ptr->hca_address)->sin_addr.s_addr >> 8 & 0xff, + ((struct sockaddr_in *) + &hca_ptr->hca_address)->sin_addr.s_addr >> 16 & 0xff, + ((struct sockaddr_in *) + &hca_ptr->hca_address)->sin_addr.s_addr >> 24 & 0xff, + hca_ptr->ib_trans.max_inline_send); + + return DAT_SUCCESS; +} + +/* + * dapls_ib_close_hca + * + * Open HCA + * + * Input: + * DAPL_HCA provide CA handle + * + * Output: + * none + * + * Return: + * DAT_SUCCESS + * dapl_convert_errno + * + */ +DAT_RETURN dapls_ib_close_hca(IN DAPL_HCA * hca_ptr) +{ + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, " close_hca: %p->%p\n", + hca_ptr, hca_ptr->ib_hca_handle); + + dapl_os_lock(&g_hca_lock); + if (g_ib_thread_state != IB_THREAD_RUN) { + dapl_os_unlock(&g_hca_lock); + goto bail; + } + dapl_os_unlock(&g_hca_lock); + + /* + * Remove hca from async event processing list + * Wakeup work thread to remove from polling list + */ + hca_ptr->ib_trans.destroy = 1; + if (dapls_thread_signal() == -1) + dapl_log(DAPL_DBG_TYPE_UTIL, + " destroy: thread wakeup error = %s\n", + strerror(errno)); + + /* wait for thread to remove HCA references */ + while (hca_ptr->ib_trans.destroy != 2) { + if (dapls_thread_signal() == -1) + dapl_log(DAPL_DBG_TYPE_UTIL, + " destroy: thread wakeup error = %s\n", + strerror(errno)); + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, + " ib_thread_destroy: wait on hca %p destroy\n"); + dapl_os_sleep_usec(1000); + } +bail: + + if (hca_ptr->ib_trans.ib_cq) + ibv_destroy_comp_channel(hca_ptr->ib_trans.ib_cq); + + if (hca_ptr->ib_trans.ib_cq_empty) { + struct ibv_comp_channel *channel; + channel = hca_ptr->ib_trans.ib_cq_empty->channel; + ibv_destroy_cq(hca_ptr->ib_trans.ib_cq_empty); + ibv_destroy_comp_channel(channel); + } + + if (hca_ptr->ib_hca_handle != IB_INVALID_HANDLE) { + if (rdma_destroy_id(hca_ptr->ib_trans.cm_id)) + return (dapl_convert_errno(errno, "ib_close_device")); + hca_ptr->ib_hca_handle = IB_INVALID_HANDLE; + } + + return (DAT_SUCCESS); +} + + +DAT_RETURN dapli_ib_thread_init(void) +{ + DAT_RETURN dat_status; + + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, + " ib_thread_init(%d)\n", dapl_os_getpid()); + + dapl_os_lock(&g_hca_lock); + if (g_ib_thread_state != IB_THREAD_INIT) { + dapl_os_unlock(&g_hca_lock); + return DAT_SUCCESS; + } + + /* uCMA events non-blocking */ + if (dapls_config_cm_channel(g_cm_events)) { + dapl_os_unlock(&g_hca_lock); + return (dapl_convert_errno(errno, "create_thread ERR: cm_fd")); + } + + g_ib_thread_state = IB_THREAD_CREATE; + dapl_os_unlock(&g_hca_lock); + + /* create thread to process inbound connect request */ + dat_status = dapl_os_thread_create(dapli_thread, NULL, &g_ib_thread); + if (dat_status != DAT_SUCCESS) + return (dapl_convert_errno(errno, + "create_thread ERR:" + " check resource limits")); + + /* wait for thread to start */ + dapl_os_lock(&g_hca_lock); + while (g_ib_thread_state != IB_THREAD_RUN) { + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, + " ib_thread_init: waiting for ib_thread\n"); + dapl_os_unlock(&g_hca_lock); + dapl_os_sleep_usec(1000); + dapl_os_lock(&g_hca_lock); + } + dapl_os_unlock(&g_hca_lock); + + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, + " ib_thread_init(%d) exit\n", dapl_os_getpid()); + + return DAT_SUCCESS; +} + +void dapli_ib_thread_destroy(void) +{ + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, + " ib_thread_destroy(%d)\n", dapl_os_getpid()); + /* + * wait for async thread to terminate. + * pthread_join would be the correct method + * but some applications have some issues + */ + + /* destroy ib_thread, wait for termination, if not already */ + dapl_os_lock(&g_hca_lock); + if (g_ib_thread_state != IB_THREAD_RUN) + goto bail; + + g_ib_thread_state = IB_THREAD_CANCEL; + while ((g_ib_thread_state != IB_THREAD_EXIT)) { + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, + " ib_thread_destroy: waiting for ib_thread\n"); + if (dapls_thread_signal() == -1) + dapl_log(DAPL_DBG_TYPE_UTIL, + " destroy: thread wakeup error = %s\n", + strerror(errno)); + dapl_os_unlock(&g_hca_lock); + dapl_os_sleep_usec(2000); + dapl_os_lock(&g_hca_lock); + } +bail: + dapl_os_unlock(&g_hca_lock); + + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, + " ib_thread_destroy(%d) exit\n", dapl_os_getpid()); +} + +#if defined(_WIN64) || defined(_WIN32) +/* work thread for uAT, uCM, CQ, and async events */ +void dapli_thread(void *arg) +{ + struct _ib_hca_transport *hca; + struct _ib_hca_transport *uhca[8]; + COMP_CHANNEL *channel; + int ret, idx, cnt; + + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, " ib_thread(%d,0x%x): ENTER: \n", + dapl_os_getpid(), g_ib_thread); + + dapl_os_lock(&g_hca_lock); + for (g_ib_thread_state = IB_THREAD_RUN; + g_ib_thread_state == IB_THREAD_RUN; + dapl_os_lock(&g_hca_lock)) { + + CompSetZero(&ufds); + CompSetAdd(&g_cm_events->channel, &ufds); + + idx = 0; + hca = dapl_llist_is_empty(&g_hca_list) ? NULL : + dapl_llist_peek_head(&g_hca_list); + + while (hca) { + CompSetAdd(&hca->ib_ctx->channel, &ufds); + CompSetAdd(&hca->ib_cq->comp_channel, &ufds); + uhca[idx++] = hca; + hca = dapl_llist_next_entry(&g_hca_list, + (DAPL_LLIST_ENTRY *) + &hca->entry); + } + cnt = idx; + + dapl_os_unlock(&g_hca_lock); + ret = CompSetPoll(&ufds, INFINITE); + + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, + " ib_thread(%d) poll_event 0x%x\n", + dapl_os_getpid(), ret); + + dapli_cma_event_cb(); + + /* check and process ASYNC events, per device */ + for (idx = 0; idx < cnt; idx++) { + if (uhca[idx]->destroy == 1) { + dapl_os_lock(&g_hca_lock); + dapl_llist_remove_entry(&g_hca_list, + (DAPL_LLIST_ENTRY *) + &uhca[idx]->entry); + dapl_os_unlock(&g_hca_lock); + uhca[idx]->destroy = 2; + } else { + dapli_cq_event_cb(uhca[idx]); + dapli_async_event_cb(uhca[idx]); + } + } + } + + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, " ib_thread(%d) EXIT\n", + dapl_os_getpid()); + g_ib_thread_state = IB_THREAD_EXIT; + dapl_os_unlock(&g_hca_lock); +} +#else // _WIN64 || WIN32 + +/* work thread for uAT, uCM, CQ, and async events */ +void dapli_thread(void *arg) +{ + struct pollfd ufds[__FD_SETSIZE]; + struct _ib_hca_transport *uhca[__FD_SETSIZE] = { NULL }; + struct _ib_hca_transport *hca; + int ret, idx, fds; + char rbuf[2]; + + dapl_dbg_log(DAPL_DBG_TYPE_THREAD, + " ib_thread(%d,0x%x): ENTER: pipe %d ucma %d\n", + dapl_os_getpid(), g_ib_thread, g_ib_pipe[0], + g_cm_events->fd); + + /* Poll across pipe, CM, AT never changes */ + dapl_os_lock(&g_hca_lock); + g_ib_thread_state = IB_THREAD_RUN; + + ufds[0].fd = g_ib_pipe[0]; /* pipe */ + ufds[0].events = POLLIN; + ufds[1].fd = g_cm_events->fd; /* uCMA */ + ufds[1].events = POLLIN; + + while (g_ib_thread_state == IB_THREAD_RUN) { + + /* build ufds after pipe and uCMA events */ + ufds[0].revents = 0; + ufds[1].revents = 0; + idx = 1; + + /* Walk HCA list and setup async and CQ events */ + if (!dapl_llist_is_empty(&g_hca_list)) + hca = dapl_llist_peek_head(&g_hca_list); + else + hca = NULL; + + while (hca) { + + /* uASYNC events */ + ufds[++idx].fd = hca->ib_ctx->async_fd; + ufds[idx].events = POLLIN; + ufds[idx].revents = 0; + uhca[idx] = hca; + + /* CQ events are non-direct with CNO's */ + ufds[++idx].fd = hca->ib_cq->fd; + ufds[idx].events = POLLIN; + ufds[idx].revents = 0; + uhca[idx] = hca; + + dapl_dbg_log(DAPL_DBG_TYPE_THREAD, + " ib_thread(%d) poll_fd: hca[%d]=%p," + " async=%d pipe=%d cm=%d \n", + dapl_os_getpid(), hca, ufds[idx - 1].fd, + ufds[0].fd, ufds[1].fd); + + hca = dapl_llist_next_entry(&g_hca_list, + (DAPL_LLIST_ENTRY *) + &hca->entry); + } + + /* unlock, and setup poll */ + fds = idx + 1; + dapl_os_unlock(&g_hca_lock); + ret = poll(ufds, fds, -1); + if (ret <= 0) { + dapl_dbg_log(DAPL_DBG_TYPE_THREAD, + " ib_thread(%d): ERR %s poll\n", + dapl_os_getpid(), strerror(errno)); + dapl_os_lock(&g_hca_lock); + continue; + } + + dapl_dbg_log(DAPL_DBG_TYPE_THREAD, + " ib_thread(%d) poll_event: " + " async=0x%x pipe=0x%x cm=0x%x \n", + dapl_os_getpid(), ufds[idx].revents, + ufds[0].revents, ufds[1].revents); + + /* uCMA events */ + if (ufds[1].revents == POLLIN) + dapli_cma_event_cb(); + + /* check and process CQ and ASYNC events, per device */ + for (idx = 2; idx < fds; idx++) { + if (ufds[idx].revents == POLLIN) { + dapli_cq_event_cb(uhca[idx]); + dapli_async_event_cb(uhca[idx]); + } + } + + /* check and process user events, PIPE */ + if (ufds[0].revents == POLLIN) { + if (read(g_ib_pipe[0], rbuf, 2) == -1) + dapl_log(DAPL_DBG_TYPE_THREAD, + " cr_thread: pipe rd err= %s\n", + strerror(errno)); + + /* cleanup any device on list marked for destroy */ + for (idx = 3; idx < fds; idx++) { + if (uhca[idx] && uhca[idx]->destroy == 1) { + dapl_os_lock(&g_hca_lock); + dapl_llist_remove_entry( + &g_hca_list, + (DAPL_LLIST_ENTRY*) + &uhca[idx]->entry); + dapl_os_unlock(&g_hca_lock); + uhca[idx]->destroy = 2; + } + } + } + dapl_os_lock(&g_hca_lock); + } + + dapl_dbg_log(DAPL_DBG_TYPE_THREAD, " ib_thread(%d) EXIT\n", + dapl_os_getpid()); + g_ib_thread_state = IB_THREAD_EXIT; + dapl_os_unlock(&g_hca_lock); +} +#endif diff --git a/branches/WOF2-3/ulp/dapl2/dapl/openib_cma/linux/openib_osd.h b/branches/WOF2-3/ulp/dapl2/dapl/openib_cma/linux/openib_osd.h new file mode 100644 index 00000000..a67018b5 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/openib_cma/linux/openib_osd.h @@ -0,0 +1,16 @@ +#ifndef OPENIB_OSD_H +#define OPENIB_OSD_H + +#include +#include +#include + +#if __BYTE_ORDER == __BIG_ENDIAN +#define htonll(x) (x) +#define ntohll(x) (x) +#elif __BYTE_ORDER == __LITTLE_ENDIAN +#define htonll(x) bswap_64(x) +#define ntohll(x) bswap_64(x) +#endif + +#endif // OPENIB_OSD_H diff --git a/branches/WOF2-3/ulp/dapl2/dapl/openib_cma/makefile b/branches/WOF2-3/ulp/dapl2/dapl/openib_cma/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/openib_cma/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\..\inc\openib.def diff --git a/branches/WOF2-3/ulp/dapl2/dapl/openib_cma/udapl.rc b/branches/WOF2-3/ulp/dapl2/dapl/openib_cma/udapl.rc new file mode 100644 index 00000000..c0533298 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/openib_cma/udapl.rc @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2007, 2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#if DBG +#define VER_FILEDESCRIPTION_STR "Direct Access Provider Library v2.0 (OFA rdma-cm) (Debug)" +#define VER_INTERNALNAME_STR "dapl2-ofa-cmad.dll" +#define VER_ORIGINALFILENAME_STR "dapl2-ofa-cmad.dll" +#else +#define VER_FILEDESCRIPTION_STR "Direct Access Provider Library v2.0 (OFA rdma-cm)" +#define VER_INTERNALNAME_STR "dapl2-ofa-cma.dll" +#define VER_ORIGINALFILENAME_STR "dapl2-ofa-cma.dll" +#endif + +#include diff --git a/branches/WOF2-3/ulp/dapl2/dapl/openib_cma/udapl_ofa_cma_exports.src b/branches/WOF2-3/ulp/dapl2/dapl/openib_cma/udapl_ofa_cma_exports.src new file mode 100644 index 00000000..32e74d24 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/openib_cma/udapl_ofa_cma_exports.src @@ -0,0 +1,14 @@ +#if DBG +LIBRARY dapl2-ofa-cmad.dll +#else +LIBRARY dapl2-ofa-cma.dll +#endif + + +EXPORTS +dat_provider_init +dat_provider_fini +#ifdef DAT_EXTENSIONS +dapl_extensions +#endif + diff --git a/branches/WOF2-3/ulp/dapl2/dapl/openib_cma/windows/openib_osd.h b/branches/WOF2-3/ulp/dapl2/dapl/openib_cma/windows/openib_osd.h new file mode 100644 index 00000000..ac392b0f --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/openib_cma/windows/openib_osd.h @@ -0,0 +1,6 @@ +#include +#include +#include + +#define ntohll _byteswap_uint64 +#define htonll _byteswap_uint64 diff --git a/branches/WOF2-3/ulp/dapl2/dapl/openib_common.c b/branches/WOF2-3/ulp/dapl2/dapl/openib_common.c new file mode 100644 index 00000000..336eff96 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/openib_common.c @@ -0,0 +1,6 @@ + +#include "openib_common\mem.c" +#include "openib_common\util.c" +#include "openib_common\cq.c" +#include "openib_common\qp.c" +#include "openib_common\ib_extensions.c" diff --git a/branches/WOF2-3/ulp/dapl2/dapl/openib_common/cq.c b/branches/WOF2-3/ulp/dapl2/dapl/openib_common/cq.c new file mode 100644 index 00000000..c36a7661 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/openib_common/cq.c @@ -0,0 +1,478 @@ +/* + * Copyright (c) 2009 Intel Corporation. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ +#include "openib_osd.h" +#include "dapl.h" +#include "dapl_adapter_util.h" +#include "dapl_lmr_util.h" +#include "dapl_evd_util.h" +#include "dapl_ring_buffer_util.h" + +/* + * Map all verbs DTO completion codes to the DAT equivelent. + * + * Not returned by verbs: DAT_DTO_ERR_PARTIAL_PACKET + */ +static struct ib_status_map { + int ib_status; + DAT_DTO_COMPLETION_STATUS dat_status; +} ib_status_map[] = { +/* 00 */ {IBV_WC_SUCCESS, DAT_DTO_SUCCESS}, +/* 01 */ {IBV_WC_LOC_LEN_ERR, DAT_DTO_ERR_LOCAL_LENGTH}, +/* 02 */ {IBV_WC_LOC_QP_OP_ERR, DAT_DTO_ERR_LOCAL_EP}, +/* 03 */ {IBV_WC_LOC_EEC_OP_ERR, DAT_DTO_ERR_TRANSPORT}, +/* 04 */ {IBV_WC_LOC_PROT_ERR, DAT_DTO_ERR_LOCAL_PROTECTION}, +/* 05 */ {IBV_WC_WR_FLUSH_ERR, DAT_DTO_ERR_FLUSHED}, +/* 06 */ {IBV_WC_MW_BIND_ERR, DAT_RMR_OPERATION_FAILED}, +/* 07 */ {IBV_WC_BAD_RESP_ERR, DAT_DTO_ERR_BAD_RESPONSE}, +/* 08 */ {IBV_WC_LOC_ACCESS_ERR, DAT_DTO_ERR_LOCAL_PROTECTION}, +/* 09 */ {IBV_WC_REM_INV_REQ_ERR, DAT_DTO_ERR_REMOTE_RESPONDER}, +/* 10 */ {IBV_WC_REM_ACCESS_ERR, DAT_DTO_ERR_REMOTE_ACCESS}, +/* 11 */ {IBV_WC_REM_OP_ERR, DAT_DTO_ERR_REMOTE_RESPONDER}, +/* 12 */ {IBV_WC_RETRY_EXC_ERR, DAT_DTO_ERR_TRANSPORT}, +/* 13 */ {IBV_WC_RNR_RETRY_EXC_ERR, DAT_DTO_ERR_RECEIVER_NOT_READY}, +/* 14 */ {IBV_WC_LOC_RDD_VIOL_ERR, DAT_DTO_ERR_LOCAL_PROTECTION}, +/* 15 */ {IBV_WC_REM_INV_RD_REQ_ERR, DAT_DTO_ERR_REMOTE_RESPONDER}, +/* 16 */ {IBV_WC_REM_ABORT_ERR, DAT_DTO_ERR_REMOTE_RESPONDER}, +/* 17 */ {IBV_WC_INV_EECN_ERR, DAT_DTO_ERR_TRANSPORT}, +/* 18 */ {IBV_WC_INV_EEC_STATE_ERR, DAT_DTO_ERR_TRANSPORT}, +/* 19 */ {IBV_WC_FATAL_ERR, DAT_DTO_ERR_TRANSPORT}, +/* 20 */ {IBV_WC_RESP_TIMEOUT_ERR, DAT_DTO_ERR_RECEIVER_NOT_READY}, +/* 21 */ {IBV_WC_GENERAL_ERR, DAT_DTO_ERR_TRANSPORT}, +}; + +/* + * dapls_ib_get_dto_status + * + * Return the DAT status of a DTO operation + * + * Input: + * cqe_ptr pointer to completion queue entry + * + * Output: + * none + * + * Returns: + * Value from ib_status_map table above + */ + +DAT_DTO_COMPLETION_STATUS +dapls_ib_get_dto_status(IN ib_work_completion_t * cqe_ptr) +{ + uint32_t ib_status; + int i; + + ib_status = DAPL_GET_CQE_STATUS(cqe_ptr); + + /* + * Due to the implementation of verbs completion code, we need to + * search the table for the correct value rather than assuming + * linear distribution. + */ + for (i = 0; i <= IBV_WC_GENERAL_ERR; i++) { + if (ib_status == ib_status_map[i].ib_status) { + if (ib_status != IBV_WC_SUCCESS) { + dapl_log(DAPL_DBG_TYPE_DTO_COMP_ERR, + " DTO completion ERROR: %d:" + " op %#x\n", + ib_status, + DAPL_GET_CQE_OPTYPE(cqe_ptr)); + } + return ib_status_map[i].dat_status; + } + } + + return DAT_DTO_FAILURE; +} + +DAT_RETURN dapls_ib_get_async_event(IN ib_error_record_t * err_record, + OUT DAT_EVENT_NUMBER * async_event) +{ + DAT_RETURN dat_status = DAT_SUCCESS; + int err_code = err_record->event_type; + + switch (err_code) { + /* OVERFLOW error */ + case IBV_EVENT_CQ_ERR: + *async_event = DAT_ASYNC_ERROR_EVD_OVERFLOW; + break; + /* INTERNAL errors */ + case IBV_EVENT_DEVICE_FATAL: + *async_event = DAT_ASYNC_ERROR_PROVIDER_INTERNAL_ERROR; + break; + /* CATASTROPHIC errors */ + case IBV_EVENT_PORT_ERR: + *async_event = DAT_ASYNC_ERROR_IA_CATASTROPHIC; + break; + /* BROKEN QP error */ + case IBV_EVENT_SQ_DRAINED: + case IBV_EVENT_QP_FATAL: + case IBV_EVENT_QP_REQ_ERR: + case IBV_EVENT_QP_ACCESS_ERR: + *async_event = DAT_ASYNC_ERROR_EP_BROKEN; + break; + + /* connection completion */ + case IBV_EVENT_COMM_EST: + *async_event = DAT_CONNECTION_EVENT_ESTABLISHED; + break; + + /* TODO: process HW state changes */ + case IBV_EVENT_PATH_MIG: + case IBV_EVENT_PATH_MIG_ERR: + case IBV_EVENT_PORT_ACTIVE: + case IBV_EVENT_LID_CHANGE: + case IBV_EVENT_PKEY_CHANGE: + case IBV_EVENT_SM_CHANGE: + default: + dat_status = DAT_ERROR(DAT_NOT_IMPLEMENTED, 0); + } + return dat_status; +} + +/* + * dapl_ib_cq_alloc + * + * Alloc a CQ + * + * Input: + * ia_handle IA handle + * evd_ptr pointer to EVD struct + * cqlen minimum QLen + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * + */ +DAT_RETURN +dapls_ib_cq_alloc(IN DAPL_IA * ia_ptr, + IN DAPL_EVD * evd_ptr, IN DAT_COUNT * cqlen) +{ + struct ibv_comp_channel *channel; + DAT_RETURN ret; + + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, + "dapls_ib_cq_alloc: evd %p cqlen=%d \n", evd_ptr, *cqlen); + + if (!evd_ptr->cno_ptr) + channel = ibv_create_comp_channel(ia_ptr->hca_ptr->ib_hca_handle); + else + channel = ia_ptr->hca_ptr->ib_trans.ib_cq; + + if (!channel) + return DAT_INSUFFICIENT_RESOURCES; + + evd_ptr->ib_cq_handle = ibv_create_cq(ia_ptr->hca_ptr->ib_hca_handle, + *cqlen, evd_ptr, channel, 0); + + if (evd_ptr->ib_cq_handle == IB_INVALID_HANDLE) { + ret = DAT_INSUFFICIENT_RESOURCES; + goto err; + } + + /* arm cq for events */ + dapls_set_cq_notify(ia_ptr, evd_ptr); + + /* update with returned cq entry size */ + *cqlen = evd_ptr->ib_cq_handle->cqe; + + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, + "dapls_ib_cq_alloc: new_cq %p cqlen=%d \n", + evd_ptr->ib_cq_handle, *cqlen); + + return DAT_SUCCESS; + +err: + if (!evd_ptr->cno_ptr) + ibv_destroy_comp_channel(channel); + return ret; +} + +/* + * dapls_ib_cq_free + * + * destroy a CQ + * + * Input: + * ia_handle IA handle + * evd_ptr pointer to EVD struct + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + * + */ +DAT_RETURN dapls_ib_cq_free(IN DAPL_IA * ia_ptr, IN DAPL_EVD * evd_ptr) +{ + DAT_EVENT event; + ib_work_completion_t wc; + struct ibv_comp_channel *channel; + + if (evd_ptr->ib_cq_handle != IB_INVALID_HANDLE) { + /* pull off CQ and EVD entries and toss */ + while (ibv_poll_cq(evd_ptr->ib_cq_handle, 1, &wc) == 1) ; + while (dapl_evd_dequeue(evd_ptr, &event) == DAT_SUCCESS) ; + + channel = evd_ptr->ib_cq_handle->channel; + if (ibv_destroy_cq(evd_ptr->ib_cq_handle)) + return (dapl_convert_errno(errno, "ibv_destroy_cq")); + if (!evd_ptr->cno_ptr) + ibv_destroy_comp_channel(channel); + evd_ptr->ib_cq_handle = IB_INVALID_HANDLE; + } + return DAT_SUCCESS; +} + +DAT_RETURN +dapls_evd_dto_wakeup(IN DAPL_EVD * evd_ptr) +{ + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, + " cq_object_wakeup: evd=%p\n", evd_ptr); + + /* EVD with CNO; waiting on OS wait object */ + if (evd_ptr->cno_ptr) + dapl_os_wait_object_wakeup(&evd_ptr->wait_object); + + /* otherwise, no wake up mechanism */ + return DAT_SUCCESS; +} + +#if defined(_WIN32) +static int +dapls_wait_comp_channel(IN struct ibv_comp_channel *channel, IN uint32_t timeout) +{ + channel->comp_channel.Milliseconds = + (timeout == DAT_TIMEOUT_INFINITE) ? INFINITE : timeout / 1000; + return 0; +} + +#else // WIN32 + +static int +dapls_wait_comp_channel(IN struct ibv_comp_channel *channel, IN uint32_t timeout) +{ + int status, timeout_ms; + struct pollfd cq_fd = { + .fd = channel->fd, + .events = POLLIN, + .revents = 0 + }; + + /* uDAPL timeout values in usecs */ + timeout_ms = (timeout == DAT_TIMEOUT_INFINITE) ? -1 : timeout / 1000; + status = poll(&cq_fd, 1, timeout_ms); + if (status > 0) + return 0; + else if (status == 0) + return ETIMEDOUT; + else + return status; +} +#endif + +DAT_RETURN +dapls_evd_dto_wait(IN DAPL_EVD * evd_ptr, IN uint32_t timeout) +{ + struct ibv_comp_channel *channel = evd_ptr->ib_cq_handle->channel; + struct ibv_cq *ibv_cq = NULL; + void *context; + int status; + + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, + " cq_object_wait: EVD %p time %d\n", + evd_ptr, timeout); + + status = dapls_wait_comp_channel(channel, timeout); + if (!status) { + if (!ibv_get_cq_event(channel, &ibv_cq, &context)) { + ibv_ack_cq_events(ibv_cq, 1); + } + } + + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, + " cq_object_wait: RET evd %p ibv_cq %p %s\n", + evd_ptr, ibv_cq, strerror(errno)); + + return dapl_convert_errno(status, "cq_wait_object_wait"); +} + +void dapli_cq_event_cb(struct _ib_hca_transport *tp) +{ + /* check all comp events on this device */ + struct dapl_evd *evd = NULL; + struct ibv_cq *ibv_cq = NULL; + + dapl_dbg_log(DAPL_DBG_TYPE_UTIL," dapli_cq_event_cb(%p)\n", tp); + + while (!ibv_get_cq_event(tp->ib_cq, &ibv_cq, (void*)&evd)) { + + if (!DAPL_BAD_HANDLE(evd, DAPL_MAGIC_EVD)) { + /* Both EVD or EVD->CNO event via callback */ + dapl_evd_dto_callback(tp->ib_ctx, + evd->ib_cq_handle, (void*)evd); + } + + ibv_ack_cq_events(ibv_cq, 1); + } +} + +/* + * dapl_ib_cq_resize + * + * Alloc a CQ + * + * Input: + * ia_handle IA handle + * evd_ptr pointer to EVD struct + * cqlen minimum QLen + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + * + */ +DAT_RETURN +dapls_ib_cq_resize(IN DAPL_IA * ia_ptr, + IN DAPL_EVD * evd_ptr, IN DAT_COUNT * cqlen) +{ + ib_cq_handle_t old_cq, new_cq; + DAT_RETURN ret; + + old_cq = evd_ptr->ib_cq_handle; + ret = dapls_ib_cq_alloc(ia_ptr, evd_ptr, cqlen); + if (ret) + goto err; + + new_cq = evd_ptr->ib_cq_handle; + evd_ptr->ib_cq_handle = old_cq; + dapls_ib_cq_free(ia_ptr, evd_ptr); + evd_ptr->ib_cq_handle = new_cq; + return DAT_SUCCESS; + +err: + evd_ptr->ib_cq_handle = old_cq; + return ret; +} + +/* + * dapls_set_cq_notify + * + * Set the CQ notification for next + * + * Input: + * hca_handl hca handle + * DAPL_EVD evd handle + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * dapl_convert_errno + */ +DAT_RETURN dapls_set_cq_notify(IN DAPL_IA * ia_ptr, IN DAPL_EVD * evd_ptr) +{ + if (ibv_req_notify_cq(evd_ptr->ib_cq_handle, 0)) + return (dapl_convert_errno(errno, "notify_cq")); + else + return DAT_SUCCESS; +} + +/* + * dapls_ib_completion_notify + * + * Set the CQ notification type + * + * Input: + * hca_handl hca handle + * evd_ptr evd handle + * type notification type + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * dapl_convert_errno + */ +DAT_RETURN dapls_ib_completion_notify(IN ib_hca_handle_t hca_handle, + IN DAPL_EVD * evd_ptr, + IN ib_notification_type_t type) +{ + if (ibv_req_notify_cq(evd_ptr->ib_cq_handle, type)) + return (dapl_convert_errno(errno, "notify_cq_type")); + else + return DAT_SUCCESS; +} + +/* + * dapls_ib_completion_poll + * + * CQ poll for completions + * + * Input: + * hca_handl hca handle + * evd_ptr evd handle + * wc_ptr work completion + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_QUEUE_EMPTY + * + */ +DAT_RETURN dapls_ib_completion_poll(IN DAPL_HCA * hca_ptr, + IN DAPL_EVD * evd_ptr, + IN ib_work_completion_t * wc_ptr) +{ + int ret; + + ret = ibv_poll_cq(evd_ptr->ib_cq_handle, 1, wc_ptr); + if (ret == 1) + return DAT_SUCCESS; + + return DAT_QUEUE_EMPTY; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/openib_common/dapl_ib_common.h b/branches/WOF2-3/ulp/dapl2/dapl/openib_common/dapl_ib_common.h new file mode 100644 index 00000000..d3cf2e05 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/openib_common/dapl_ib_common.h @@ -0,0 +1,403 @@ +/* + * Copyright (c) 2009 Intel Corporation. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/* + * Definitions common to all OpenIB providers, cma, scm, ucm + */ + +#ifndef _DAPL_IB_COMMON_H_ +#define _DAPL_IB_COMMON_H_ + +#include + +#ifdef DAT_EXTENSIONS +#include +#endif + +#ifndef __cplusplus +#define false 0 +#define true 1 +#endif /*__cplusplus */ + +/* Typedefs to map common DAPL provider types to IB verbs */ +typedef struct ibv_qp *ib_qp_handle_t; +typedef struct ibv_cq *ib_cq_handle_t; +typedef struct ibv_pd *ib_pd_handle_t; +typedef struct ibv_mr *ib_mr_handle_t; +typedef struct ibv_mw *ib_mw_handle_t; +typedef struct ibv_wc ib_work_completion_t; +typedef struct ibv_ah *ib_ah_handle_t; +typedef union ibv_gid *ib_gid_handle_t; + +/* HCA context type maps to IB verbs */ +typedef struct ibv_context *ib_hca_handle_t; +typedef ib_hca_handle_t dapl_ibal_ca_t; + +/* QP info to exchange, wire protocol version for these CM's */ +#define DCM_VER 6 + +/* CM private data areas, same for all operations */ +#define DCM_MAX_PDATA_SIZE 118 + +/* + * UCM DAPL IB/QP address (lid, qp_num, gid) mapping to + * DAT_IA_ADDRESS_PTR, DAT_SOCK_ADDR2 (28 bytes) + * For applications, like MPI, that exchange IA_ADDRESS + * across the fabric before connecting, it eliminates the + * overhead of name and address resolution to the destination's + * CM services. UCM provider uses the following for + * DAT_IA_ADDRESS. Note: family == AF_INET6 to insure proper + * callee storage for address. + */ +union dcm_addr { + DAT_SOCK_ADDR6 so; + struct { + uint16_t family; /* sin6_family */ + uint16_t lid; /* sin6_port */ + uint32_t qpn; /* sin6_flowinfo */ + uint8_t gid[16]; /* sin6_addr */ + uint16_t port; /* sin6_scope_id */ + uint8_t sl; + uint8_t qp_type; + } ib; +}; + +/* 256 bytes total; default max_inline_send, min IB MTU size */ +typedef struct _ib_cm_msg +{ + uint16_t ver; + uint16_t op; + uint16_t sport; /* src cm port */ + uint16_t dport; /* dst cm port */ + uint32_t sqpn; /* src cm qpn */ + uint32_t dqpn; /* dst cm qpn */ + uint16_t p_size; + uint8_t resv[14]; + union dcm_addr saddr; + union dcm_addr daddr; + union dcm_addr saddr_alt; + union dcm_addr daddr_alt; + uint8_t p_data[DCM_MAX_PDATA_SIZE]; + +} ib_cm_msg_t; + +/* CM events */ +typedef enum { + IB_CME_CONNECTED, + IB_CME_DISCONNECTED, + IB_CME_DISCONNECTED_ON_LINK_DOWN, + IB_CME_CONNECTION_REQUEST_PENDING, + IB_CME_CONNECTION_REQUEST_PENDING_PRIVATE_DATA, + IB_CME_CONNECTION_REQUEST_ACKED, + IB_CME_DESTINATION_REJECT, + IB_CME_DESTINATION_REJECT_PRIVATE_DATA, + IB_CME_DESTINATION_UNREACHABLE, + IB_CME_TOO_MANY_CONNECTION_REQUESTS, + IB_CME_LOCAL_FAILURE, + IB_CME_BROKEN, + IB_CME_TIMEOUT +} ib_cm_events_t; + +/* Operation and state mappings */ +typedef int ib_send_op_type_t; +typedef struct ibv_sge ib_data_segment_t; +typedef enum ibv_qp_state ib_qp_state_t; +typedef enum ibv_event_type ib_async_event_type; +typedef struct ibv_async_event ib_error_record_t; + +/* CQ notifications */ +typedef enum +{ + IB_NOTIFY_ON_NEXT_COMP, + IB_NOTIFY_ON_SOLIC_COMP + +} ib_notification_type_t; + +/* other mappings */ +typedef int ib_bool_t; +typedef union ibv_gid GID; +typedef char *IB_HCA_NAME; +typedef uint16_t ib_hca_port_t; + +/* Definitions */ +#define IB_INVALID_HANDLE NULL + +/* inline send rdma threshold */ +#define INLINE_SEND_IWARP_DEFAULT 64 +#define INLINE_SEND_IB_DEFAULT 256 + +/* qkey for UD QP's */ +#define DAT_UD_QKEY 0x78654321 + +/* RC timer - retry count defaults */ +#define DCM_ACK_TIMER 16 /* 5 bits, 4.096us*2^ack_timer. 16== 268ms */ +#define DCM_ACK_RETRY 7 /* 3 bits, 7 * 268ms = 1.8 seconds */ +#define DCM_RNR_TIMER 12 /* 5 bits, 12 =.64ms, 28 =163ms, 31 =491ms */ +#define DCM_RNR_RETRY 7 /* 3 bits, 7 == infinite */ +#define DCM_IB_MTU 2048 + +/* Global routing defaults */ +#define DCM_GLOBAL 0 /* global routing is disabled */ +#define DCM_HOP_LIMIT 0xff +#define DCM_TCLASS 0 + +/* DAPL uCM timers, default queue sizes */ +#define DCM_RETRY_CNT 15 +#define DCM_REP_TIME 800 /* reply timeout in m_secs */ +#define DCM_RTU_TIME 400 /* rtu timeout in m_secs */ +#define DCM_QP_SIZE 500 /* uCM tx, rx qp size */ +#define DCM_CQ_SIZE 500 /* uCM cq size */ + +/* DTO OPs, ordered for DAPL ENUM definitions */ +#define OP_RDMA_WRITE IBV_WR_RDMA_WRITE +#define OP_RDMA_WRITE_IMM IBV_WR_RDMA_WRITE_WITH_IMM +#define OP_SEND IBV_WR_SEND +#define OP_SEND_IMM IBV_WR_SEND_WITH_IMM +#define OP_RDMA_READ IBV_WR_RDMA_READ +#define OP_COMP_AND_SWAP IBV_WR_ATOMIC_CMP_AND_SWP +#define OP_FETCH_AND_ADD IBV_WR_ATOMIC_FETCH_AND_ADD +#define OP_RECEIVE 7 /* internal op */ +#define OP_RECEIVE_IMM 8 /* rdma write with immed, internel op */ +#define OP_RECEIVE_MSG_IMM 9 /* recv msg with immed, internel op */ +#define OP_BIND_MW 10 /* internal op */ +#define OP_SEND_UD 11 /* internal op */ +#define OP_RECV_UD 12 /* internal op */ +#define OP_INVALID 0xff + +/* Definitions to map QP state */ +#define IB_QP_STATE_RESET IBV_QPS_RESET +#define IB_QP_STATE_INIT IBV_QPS_INIT +#define IB_QP_STATE_RTR IBV_QPS_RTR +#define IB_QP_STATE_RTS IBV_QPS_RTS +#define IB_QP_STATE_SQD IBV_QPS_SQD +#define IB_QP_STATE_SQE IBV_QPS_SQE +#define IB_QP_STATE_ERROR IBV_QPS_ERR + +/* Definitions for ibverbs/mthca return codes, should be defined in verbs.h */ +/* some are errno and some are -n values */ + +/** + * ibv_get_device_name - Return kernel device name + * ibv_get_device_guid - Return device's node GUID + * ibv_open_device - Return ibv_context or NULL + * ibv_close_device - Return 0, (errno?) + * ibv_get_async_event - Return 0, -1 + * ibv_alloc_pd - Return ibv_pd, NULL + * ibv_dealloc_pd - Return 0, errno + * ibv_reg_mr - Return ibv_mr, NULL + * ibv_dereg_mr - Return 0, errno + * ibv_create_cq - Return ibv_cq, NULL + * ibv_destroy_cq - Return 0, errno + * ibv_get_cq_event - Return 0 & ibv_cq/context, int + * ibv_poll_cq - Return n & ibv_wc, 0 ok, -1 empty, -2 error + * ibv_req_notify_cq - Return 0 (void?) + * ibv_create_qp - Return ibv_qp, NULL + * ibv_modify_qp - Return 0, errno + * ibv_destroy_qp - Return 0, errno + * ibv_post_send - Return 0, -1 & bad_wr + * ibv_post_recv - Return 0, -1 & bad_wr + */ + +/* async handler for DTO, CQ, QP, and unafiliated */ +typedef void (*ib_async_dto_handler_t)( + IN ib_hca_handle_t ib_hca_handle, + IN ib_error_record_t *err_code, + IN void *context); + +typedef void (*ib_async_cq_handler_t)( + IN ib_hca_handle_t ib_hca_handle, + IN ib_cq_handle_t ib_cq_handle, + IN ib_error_record_t *err_code, + IN void *context); + +typedef void (*ib_async_qp_handler_t)( + IN ib_hca_handle_t ib_hca_handle, + IN ib_qp_handle_t ib_qp_handle, + IN ib_error_record_t *err_code, + IN void *context); + +typedef void (*ib_async_handler_t)( + IN ib_hca_handle_t ib_hca_handle, + IN ib_error_record_t *err_code, + IN void *context); + +typedef enum +{ + IB_THREAD_INIT, + IB_THREAD_CREATE, + IB_THREAD_RUN, + IB_THREAD_CANCEL, + IB_THREAD_EXIT + +} ib_thread_state_t; + +typedef enum dapl_cm_op +{ + DCM_REQ = 1, + DCM_REP, + DCM_REJ_USER, /* user reject */ + DCM_REJ_CM, /* cm reject, no SID */ + DCM_RTU, + DCM_DREQ, + DCM_DREP + +} DAPL_CM_OP; + +typedef enum dapl_cm_state +{ + DCM_INIT, + DCM_LISTEN, + DCM_CONN_PENDING, + DCM_REP_PENDING, + DCM_ACCEPTING, + DCM_ACCEPTING_DATA, + DCM_ACCEPTED, + DCM_REJECTING, + DCM_REJECTED, + DCM_CONNECTED, + DCM_RELEASE, + DCM_DISC_PENDING, + DCM_DISCONNECTED, + DCM_DESTROY, + DCM_RTU_PENDING, + DCM_DISC_RECV, + DCM_FREE, + +} DAPL_CM_STATE; + +/* provider specfic fields for shared memory support */ +typedef uint32_t ib_shm_transport_t; + +/* prototypes */ +int32_t dapls_ib_init(void); +int32_t dapls_ib_release(void); + +/* util.c */ +enum ibv_mtu dapl_ib_mtu(int mtu); +char *dapl_ib_mtu_str(enum ibv_mtu mtu); +int getipaddr_netdev(char *name, char *addr, int addr_len); +DAT_RETURN getlocalipaddr(char *addr, int addr_len); + +/* qp.c */ +DAT_RETURN dapls_modify_qp_ud(IN DAPL_HCA *hca, IN ib_qp_handle_t qp); +DAT_RETURN dapls_modify_qp_state(IN ib_qp_handle_t qp_handle, + IN ib_qp_state_t qp_state, + IN uint32_t qpn, + IN uint16_t lid, + IN ib_gid_handle_t gid); +ib_ah_handle_t dapls_create_ah( IN DAPL_HCA *hca, + IN ib_pd_handle_t pd, + IN ib_qp_handle_t qp, + IN uint16_t lid, + IN ib_gid_handle_t gid); + +/* inline functions */ +STATIC _INLINE_ IB_HCA_NAME dapl_ib_convert_name (IN char *name) +{ + /* use ascii; name of local device */ + return dapl_os_strdup(name); +} + +STATIC _INLINE_ void dapl_ib_release_name (IN IB_HCA_NAME name) +{ + return; +} + +/* + * Convert errno to DAT_RETURN values + */ +STATIC _INLINE_ DAT_RETURN +dapl_convert_errno( IN int err, IN const char *str ) +{ + if (!err) return DAT_SUCCESS; + +#if DAPL_DBG + if ((err != EAGAIN) && (err != ETIMEDOUT)) + dapl_dbg_log (DAPL_DBG_TYPE_ERR," %s %s\n", str, strerror(err)); +#endif + + switch( err ) + { + case EOVERFLOW : return DAT_LENGTH_ERROR; + case EACCES : return DAT_PRIVILEGES_VIOLATION; + case EPERM : return DAT_PROTECTION_VIOLATION; + case EINVAL : return DAT_INVALID_HANDLE; + case EISCONN : return DAT_INVALID_STATE | DAT_INVALID_STATE_EP_CONNECTED; + case ECONNREFUSED : return DAT_INVALID_STATE | DAT_INVALID_STATE_EP_NOTREADY; + case ETIMEDOUT : return DAT_TIMEOUT_EXPIRED; + case ENETUNREACH: return DAT_INVALID_ADDRESS | DAT_INVALID_ADDRESS_UNREACHABLE; + case EADDRINUSE : return DAT_CONN_QUAL_IN_USE; + case EALREADY : return DAT_INVALID_STATE | DAT_INVALID_STATE_EP_ACTCONNPENDING; + case ENOMEM : return DAT_INSUFFICIENT_RESOURCES; + case EAGAIN : return DAT_QUEUE_EMPTY; + case EINTR : return DAT_INTERRUPTED_CALL; + case EAFNOSUPPORT : return DAT_INVALID_ADDRESS | DAT_INVALID_ADDRESS_MALFORMED; + case EFAULT : + default : return DAT_INTERNAL_ERROR; + } + } + +STATIC _INLINE_ char * dapl_cm_state_str(IN int st) +{ + static char *state[] = { + "CM_INIT", + "CM_LISTEN", + "CM_CONN_PENDING", + "CM_REP_PENDING", + "CM_ACCEPTING", + "CM_ACCEPTING_DATA", + "CM_ACCEPTED", + "CM_REJECTING", + "CM_REJECTED", + "CM_CONNECTED", + "CM_RELEASE", + "CM_DISC_PENDING", + "CM_DISCONNECTED", + "CM_DESTROY", + "CM_RTU_PENDING", + "CM_DISC_RECV", + "CM_FREE" + }; + return ((st < 0 || st > 16) ? "Invalid CM state?" : state[st]); +} + +STATIC _INLINE_ char * dapl_cm_op_str(IN int op) +{ + static char *ops[] = { + "INVALID", + "REQ", + "REP", + "REJ_USER", + "REJ_CM", + "RTU", + "DREQ", + "DREP", + }; + return ((op < 1 || op > 7) ? "Invalid OP?" : ops[op]); +} + +#endif /* _DAPL_IB_COMMON_H_ */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/openib_common/dapl_ib_dto.h b/branches/WOF2-3/ulp/dapl2/dapl/openib_common/dapl_ib_dto.h new file mode 100644 index 00000000..b93565c6 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/openib_common/dapl_ib_dto.h @@ -0,0 +1,504 @@ +/* + * Copyright (c) 2009 Intel Corporation. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ +#ifndef _DAPL_IB_DTO_H_ +#define _DAPL_IB_DTO_H_ + +#include "dapl_ib_util.h" + +#ifdef DAT_EXTENSIONS +#include +#endif + +STATIC _INLINE_ int dapls_cqe_opcode(ib_work_completion_t *cqe_p); + +#define CQE_WR_TYPE_UD(id) \ + (((DAPL_COOKIE *)(uintptr_t)id)->ep->qp_handle->qp_type == IBV_QPT_UD) + +/* + * dapls_ib_post_recv + * + * Provider specific Post RECV function + */ +STATIC _INLINE_ DAT_RETURN +dapls_ib_post_recv ( + IN DAPL_EP *ep_ptr, + IN DAPL_COOKIE *cookie, + IN DAT_COUNT segments, + IN DAT_LMR_TRIPLET *local_iov ) +{ + struct ibv_recv_wr wr; + struct ibv_recv_wr *bad_wr; + ib_data_segment_t *ds = (ib_data_segment_t *)local_iov; + DAT_COUNT i, total_len; + int ret; + + dapl_dbg_log(DAPL_DBG_TYPE_EP, + " post_rcv: ep %p cookie %p segs %d l_iov %p\n", + ep_ptr, cookie, segments, local_iov); + + /* setup work request */ + total_len = 0; + wr.next = 0; + wr.num_sge = segments; + wr.wr_id = (uint64_t)(uintptr_t)cookie; + wr.sg_list = ds; + + if (cookie != NULL) { + for (i = 0; i < segments; i++) { + dapl_dbg_log(DAPL_DBG_TYPE_EP, + " post_rcv: l_key 0x%x va %p len %d\n", + ds->lkey, ds->addr, ds->length ); + total_len += ds->length; + ds++; + } + cookie->val.dto.size = total_len; + } + + ret = ibv_post_recv(ep_ptr->qp_handle, &wr, &bad_wr); + + if (ret) + return(dapl_convert_errno(errno,"ibv_recv")); + + DAPL_CNTR(ep_ptr, DCNT_EP_POST_RECV); + DAPL_CNTR_DATA(ep_ptr, DCNT_EP_POST_RECV_DATA, total_len); + + return DAT_SUCCESS; +} + +/* + * dapls_ib_post_send + * + * Provider specific Post SEND function + */ +STATIC _INLINE_ DAT_RETURN +dapls_ib_post_send ( + IN DAPL_EP *ep_ptr, + IN ib_send_op_type_t op_type, + IN DAPL_COOKIE *cookie, + IN DAT_COUNT segments, + IN DAT_LMR_TRIPLET *local_iov, + IN const DAT_RMR_TRIPLET *remote_iov, + IN DAT_COMPLETION_FLAGS completion_flags) +{ + struct ibv_send_wr wr; + struct ibv_send_wr *bad_wr; + ib_data_segment_t *ds = (ib_data_segment_t *)local_iov; + ib_hca_transport_t *ibt_ptr = + &ep_ptr->header.owner_ia->hca_ptr->ib_trans; + DAT_COUNT i, total_len; + int ret; + + dapl_dbg_log(DAPL_DBG_TYPE_EP, + " post_snd: ep %p op %d ck %p sgs", + "%d l_iov %p r_iov %p f %d\n", + ep_ptr, op_type, cookie, segments, local_iov, + remote_iov, completion_flags); + +#ifdef DAT_EXTENSIONS + if (ep_ptr->qp_handle->qp_type != IBV_QPT_RC) + return(DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP)); +#endif + /* setup the work request */ + wr.next = 0; + wr.opcode = op_type; + wr.num_sge = segments; + wr.send_flags = 0; + wr.wr_id = (uint64_t)(uintptr_t)cookie; + wr.sg_list = ds; + total_len = 0; + + if (cookie != NULL) { + for (i = 0; i < segments; i++ ) { + dapl_dbg_log(DAPL_DBG_TYPE_EP, + " post_snd: lkey 0x%x va %p len %d\n", + ds->lkey, ds->addr, ds->length ); + total_len += ds->length; + ds++; + } + cookie->val.dto.size = total_len; + } + + if (wr.num_sge && + (op_type == OP_RDMA_WRITE || op_type == OP_RDMA_READ)) { + wr.wr.rdma.remote_addr = remote_iov->virtual_address; + wr.wr.rdma.rkey = remote_iov->rmr_context; + dapl_dbg_log(DAPL_DBG_TYPE_EP, + " post_snd_rdma: rkey 0x%x va %#016Lx\n", + wr.wr.rdma.rkey, wr.wr.rdma.remote_addr); + } + + + /* inline data for send or write ops */ + if ((total_len <= ibt_ptr->max_inline_send) && + ((op_type == OP_SEND) || (op_type == OP_RDMA_WRITE))) + wr.send_flags |= IBV_SEND_INLINE; + + /* set completion flags in work request */ + wr.send_flags |= (DAT_COMPLETION_SUPPRESS_FLAG & + completion_flags) ? 0 : IBV_SEND_SIGNALED; + wr.send_flags |= (DAT_COMPLETION_BARRIER_FENCE_FLAG & + completion_flags) ? IBV_SEND_FENCE : 0; + wr.send_flags |= (DAT_COMPLETION_SOLICITED_WAIT_FLAG & + completion_flags) ? IBV_SEND_SOLICITED : 0; + + dapl_dbg_log(DAPL_DBG_TYPE_EP, + " post_snd: op 0x%x flags 0x%x sglist %p, %d\n", + wr.opcode, wr.send_flags, wr.sg_list, wr.num_sge); + + ret = ibv_post_send(ep_ptr->qp_handle, &wr, &bad_wr); + + if (ret) + return(dapl_convert_errno(errno,"ibv_send")); + +#ifdef DAPL_COUNTERS + switch (op_type) { + case OP_SEND: + DAPL_CNTR(ep_ptr, DCNT_EP_POST_SEND); + DAPL_CNTR_DATA(ep_ptr, DCNT_EP_POST_SEND_DATA,total_len); + break; + case OP_RDMA_WRITE: + DAPL_CNTR(ep_ptr, DCNT_EP_POST_WRITE); + DAPL_CNTR_DATA(ep_ptr, DCNT_EP_POST_WRITE_DATA,total_len); + break; + case OP_RDMA_READ: + DAPL_CNTR(ep_ptr, DCNT_EP_POST_READ); + DAPL_CNTR_DATA(ep_ptr, DCNT_EP_POST_READ_DATA,total_len); + break; + default: + break; + } +#endif /* DAPL_COUNTERS */ + + dapl_dbg_log(DAPL_DBG_TYPE_EP," post_snd: returned\n"); + return DAT_SUCCESS; +} + +/* map Work Completions to DAPL WR operations */ +STATIC _INLINE_ DAT_DTOS dapls_cqe_dtos_opcode(ib_work_completion_t *cqe_p) +{ + switch (cqe_p->opcode) { + + case IBV_WC_SEND: +#ifdef DAT_EXTENSIONS + if (CQE_WR_TYPE_UD(cqe_p->wr_id)) + return (DAT_IB_DTO_SEND_UD); + else +#endif + return (DAT_DTO_SEND); + case IBV_WC_RDMA_READ: + return (DAT_DTO_RDMA_READ); + case IBV_WC_BIND_MW: + return (DAT_DTO_BIND_MW); +#ifdef DAT_EXTENSIONS + case IBV_WC_RDMA_WRITE: + if (cqe_p->wc_flags & IBV_WC_WITH_IMM) + return (DAT_IB_DTO_RDMA_WRITE_IMMED); + else + return (DAT_DTO_RDMA_WRITE); + case IBV_WC_COMP_SWAP: + return (DAT_IB_DTO_CMP_SWAP); + case IBV_WC_FETCH_ADD: + return (DAT_IB_DTO_FETCH_ADD); + case IBV_WC_RECV_RDMA_WITH_IMM: + return (DAT_IB_DTO_RECV_IMMED); +#else + case IBV_WC_RDMA_WRITE: + return (DAT_DTO_RDMA_WRITE); +#endif + case IBV_WC_RECV: +#ifdef DAT_EXTENSIONS + if (CQE_WR_TYPE_UD(cqe_p->wr_id)) + return (DAT_IB_DTO_RECV_UD); + else if (cqe_p->wc_flags & IBV_WC_WITH_IMM) + return (DAT_IB_DTO_RECV_MSG_IMMED); + else +#endif + return (DAT_DTO_RECEIVE); + default: + return (0xff); + } +} +#define DAPL_GET_CQE_DTOS_OPTYPE(cqe_p) dapls_cqe_dtos_opcode(cqe_p) + + +#ifdef DAT_EXTENSIONS +/* + * dapls_ib_post_ext_send + * + * Provider specific extended Post SEND function for atomics + * OP_COMP_AND_SWAP and OP_FETCH_AND_ADD + */ +STATIC _INLINE_ DAT_RETURN +dapls_ib_post_ext_send ( + IN DAPL_EP *ep_ptr, + IN ib_send_op_type_t op_type, + IN DAPL_COOKIE *cookie, + IN DAT_COUNT segments, + IN DAT_LMR_TRIPLET *local_iov, + IN const DAT_RMR_TRIPLET *remote_iov, + IN DAT_UINT32 immed_data, + IN DAT_UINT64 compare_add, + IN DAT_UINT64 swap, + IN DAT_COMPLETION_FLAGS completion_flags, + IN DAT_IB_ADDR_HANDLE *remote_ah) +{ + struct ibv_send_wr wr; + struct ibv_send_wr *bad_wr; + ib_data_segment_t *ds = (ib_data_segment_t *)local_iov; + DAT_COUNT i, total_len; + int ret; + + dapl_dbg_log(DAPL_DBG_TYPE_EP, + " post_ext_snd: ep %p op %d ck %p sgs", + "%d l_iov %p r_iov %p f %d\n", + ep_ptr, op_type, cookie, segments, local_iov, + remote_iov, completion_flags, remote_ah); + + /* setup the work request */ + wr.next = 0; + wr.opcode = op_type; + wr.num_sge = segments; + wr.send_flags = 0; + wr.wr_id = (uint64_t)(uintptr_t)cookie; + wr.sg_list = ds; + total_len = 0; + + if (cookie != NULL) { + for (i = 0; i < segments; i++ ) { + dapl_dbg_log(DAPL_DBG_TYPE_EP, + " post_snd: lkey 0x%x va %p len %d\n", + ds->lkey, ds->addr, ds->length ); + total_len += ds->length; + ds++; + } + cookie->val.dto.size = total_len; + } + + switch (op_type) { + case OP_RDMA_WRITE_IMM: + /* OP_RDMA_WRITE)IMMED has direct IB wr_type mapping */ + dapl_dbg_log(DAPL_DBG_TYPE_EP, + " post_ext: rkey 0x%x va %#016Lx immed=0x%x\n", + remote_iov?remote_iov->rmr_context:0, + remote_iov?remote_iov->virtual_address:0, + immed_data); + + wr.imm_data = immed_data; + if (wr.num_sge) { + wr.wr.rdma.remote_addr = remote_iov->virtual_address; + wr.wr.rdma.rkey = remote_iov->rmr_context; + } + break; + case OP_COMP_AND_SWAP: + /* OP_COMP_AND_SWAP has direct IB wr_type mapping */ + dapl_dbg_log(DAPL_DBG_TYPE_EP, + " post_ext: OP_COMP_AND_SWAP=%lx," + "%lx rkey 0x%x va %#016Lx\n", + compare_add, swap, remote_iov->rmr_context, + remote_iov->virtual_address); + + wr.wr.atomic.compare_add = compare_add; + wr.wr.atomic.swap = swap; + wr.wr.atomic.remote_addr = remote_iov->virtual_address; + wr.wr.atomic.rkey = remote_iov->rmr_context; + break; + case OP_FETCH_AND_ADD: + /* OP_FETCH_AND_ADD has direct IB wr_type mapping */ + dapl_dbg_log(DAPL_DBG_TYPE_EP, + " post_ext: OP_FETCH_AND_ADD=%lx," + "%lx rkey 0x%x va %#016Lx\n", + compare_add, remote_iov->rmr_context, + remote_iov->virtual_address); + + wr.wr.atomic.compare_add = compare_add; + wr.wr.atomic.remote_addr = remote_iov->virtual_address; + wr.wr.atomic.rkey = remote_iov->rmr_context; + break; + case OP_SEND_UD: + /* post must be on EP with service_type of UD */ + if (ep_ptr->qp_handle->qp_type != IBV_QPT_UD) + return(DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP)); + + dapl_dbg_log(DAPL_DBG_TYPE_EP, + " post_ext: OP_SEND_UD ah=%p" + " qp_num=0x%x\n", + remote_ah->ah, remote_ah->qpn); + + wr.opcode = OP_SEND; + wr.wr.ud.ah = remote_ah->ah; + wr.wr.ud.remote_qpn = remote_ah->qpn; + wr.wr.ud.remote_qkey = DAT_UD_QKEY; + break; + default: + break; + } + + /* set completion flags in work request */ + wr.send_flags |= (DAT_COMPLETION_SUPPRESS_FLAG & + completion_flags) ? 0 : IBV_SEND_SIGNALED; + wr.send_flags |= (DAT_COMPLETION_BARRIER_FENCE_FLAG & + completion_flags) ? IBV_SEND_FENCE : 0; + wr.send_flags |= (DAT_COMPLETION_SOLICITED_WAIT_FLAG & + completion_flags) ? IBV_SEND_SOLICITED : 0; + + dapl_dbg_log(DAPL_DBG_TYPE_EP, + " post_snd: op 0x%x flags 0x%x sglist %p, %d\n", + wr.opcode, wr.send_flags, wr.sg_list, wr.num_sge); + + ret = ibv_post_send(ep_ptr->qp_handle, &wr, &bad_wr); + + if (ret) + return( dapl_convert_errno(errno,"ibv_send") ); + +#ifdef DAPL_COUNTERS + switch (op_type) { + case OP_RDMA_WRITE_IMM: + DAPL_CNTR(ep_ptr, DCNT_EP_POST_WRITE_IMM); + DAPL_CNTR_DATA(ep_ptr, + DCNT_EP_POST_WRITE_IMM_DATA, total_len); + break; + case OP_COMP_AND_SWAP: + DAPL_CNTR(ep_ptr, DCNT_EP_POST_CMP_SWAP); + break; + case OP_FETCH_AND_ADD: + DAPL_CNTR(ep_ptr, DCNT_EP_POST_FETCH_ADD); + break; + case OP_SEND_UD: + DAPL_CNTR(ep_ptr, DCNT_EP_POST_SEND_UD); + DAPL_CNTR_DATA(ep_ptr, DCNT_EP_POST_SEND_UD_DATA, total_len); + break; + default: + break; + } +#endif /* DAPL_COUNTERS */ + + dapl_dbg_log(DAPL_DBG_TYPE_EP," post_snd: returned\n"); + return DAT_SUCCESS; +} +#endif + +STATIC _INLINE_ DAT_RETURN +dapls_ib_optional_prv_dat( + IN DAPL_CR *cr_ptr, + IN const void *event_data, + OUT DAPL_CR **cr_pp) +{ + return DAT_SUCCESS; +} + + +/* map Work Completions to DAPL WR operations */ +STATIC _INLINE_ int dapls_cqe_opcode(ib_work_completion_t *cqe_p) +{ +#ifdef DAPL_COUNTERS + DAPL_COOKIE *cookie = (DAPL_COOKIE *)(uintptr_t)cqe_p->wr_id; +#endif /* DAPL_COUNTERS */ + + switch (cqe_p->opcode) { + case IBV_WC_SEND: + if (CQE_WR_TYPE_UD(cqe_p->wr_id)) + return(OP_SEND_UD); + else + return (OP_SEND); + case IBV_WC_RDMA_WRITE: + if (cqe_p->wc_flags & IBV_WC_WITH_IMM) + return (OP_RDMA_WRITE_IMM); + else + return (OP_RDMA_WRITE); + case IBV_WC_RDMA_READ: + return (OP_RDMA_READ); + case IBV_WC_COMP_SWAP: + return (OP_COMP_AND_SWAP); + case IBV_WC_FETCH_ADD: + return (OP_FETCH_AND_ADD); + case IBV_WC_BIND_MW: + return (OP_BIND_MW); + case IBV_WC_RECV: + if (CQE_WR_TYPE_UD(cqe_p->wr_id)) { + DAPL_CNTR(cookie->ep, DCNT_EP_RECV_UD); + DAPL_CNTR_DATA(cookie->ep, DCNT_EP_RECV_UD_DATA, + cqe_p->byte_len); + return (OP_RECV_UD); + } + else if (cqe_p->wc_flags & IBV_WC_WITH_IMM) { + DAPL_CNTR(cookie->ep, DCNT_EP_RECV_IMM); + DAPL_CNTR_DATA(cookie->ep, DCNT_EP_RECV_IMM_DATA, + cqe_p->byte_len); + return (OP_RECEIVE_IMM); + } else { + DAPL_CNTR(cookie->ep, DCNT_EP_RECV); + DAPL_CNTR_DATA(cookie->ep, DCNT_EP_RECV_DATA, + cqe_p->byte_len); + return (OP_RECEIVE); + } + case IBV_WC_RECV_RDMA_WITH_IMM: + DAPL_CNTR(cookie->ep, DCNT_EP_RECV_RDMA_IMM); + DAPL_CNTR_DATA(cookie->ep, DCNT_EP_RECV_RDMA_IMM_DATA, + cqe_p->byte_len); + return (OP_RECEIVE_IMM); + default: + return (OP_INVALID); + } +} + +#define DAPL_GET_CQE_OPTYPE(cqe_p) dapls_cqe_opcode(cqe_p) +#define DAPL_GET_CQE_WRID(cqe_p) ((ib_work_completion_t*)cqe_p)->wr_id +#define DAPL_GET_CQE_STATUS(cqe_p) ((ib_work_completion_t*)cqe_p)->status +#define DAPL_GET_CQE_VENDOR_ERR(cqe_p) ((ib_work_completion_t*)cqe_p)->vendor_err +#define DAPL_GET_CQE_BYTESNUM(cqe_p) ((ib_work_completion_t*)cqe_p)->byte_len +#define DAPL_GET_CQE_IMMED_DATA(cqe_p) ((ib_work_completion_t*)cqe_p)->imm_data + +STATIC _INLINE_ char * dapls_dto_op_str(int op) +{ + static char *optable[] = + { + "OP_RDMA_WRITE", + "OP_RDMA_WRITE_IMM", + "OP_SEND", + "OP_SEND_IMM", + "OP_RDMA_READ", + "OP_COMP_AND_SWAP", + "OP_FETCH_AND_ADD", + "OP_RECEIVE", + "OP_RECEIVE_MSG_IMM", + "OP_RECEIVE_RDMA_IMM", + "OP_BIND_MW" + "OP_SEND_UD" + "OP_RECV_UD" + }; + return ((op < 0 || op > 12) ? "Invalid CQE OP?" : optable[op]); +} + +static _INLINE_ char * +dapls_cqe_op_str(IN ib_work_completion_t *cqe_ptr) +{ + return dapls_dto_op_str(DAPL_GET_CQE_OPTYPE(cqe_ptr)); +} + +#define DAPL_GET_CQE_OP_STR(cqe) dapls_cqe_op_str(cqe) + +#endif /* _DAPL_IB_DTO_H_ */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/openib_common/ib_extensions.c b/branches/WOF2-3/ulp/dapl2/dapl/openib_common/ib_extensions.c new file mode 100644 index 00000000..3c418e1a --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/openib_common/ib_extensions.c @@ -0,0 +1,360 @@ +/* + * Copyright (c) 2007-2009 Intel Corporation. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ +#include "dapl.h" +#include "dapl_adapter_util.h" +#include "dapl_evd_util.h" +#include "dapl_ib_util.h" +#include "dapl_ep_util.h" +#include "dapl_cookie.h" +#include + +DAT_RETURN +dapli_post_ext(IN DAT_EP_HANDLE ep_handle, + IN DAT_UINT64 cmp_add, + IN DAT_UINT64 swap, + IN DAT_UINT32 immed_data, + IN DAT_COUNT segments, + IN DAT_LMR_TRIPLET * local_iov, + IN DAT_DTO_COOKIE user_cookie, + IN const DAT_RMR_TRIPLET * remote_iov, + IN int op_type, + IN DAT_COMPLETION_FLAGS flags, IN DAT_IB_ADDR_HANDLE * ah); + +/* + * dapl_extensions + * + * Process extension requests + * + * Input: + * ext_type, + * ... + * + * Output: + * Depends.... + * + * Returns: + * DAT_SUCCESS + * DAT_NOT_IMPLEMENTED + * ..... + * + */ +DAT_RETURN +dapl_extensions(IN DAT_HANDLE dat_handle, + IN DAT_EXTENDED_OP ext_op, IN va_list args) +{ + DAT_EP_HANDLE ep; + DAT_IB_ADDR_HANDLE *ah = NULL; + DAT_LMR_TRIPLET *lmr_p; + DAT_DTO_COOKIE cookie; + const DAT_RMR_TRIPLET *rmr_p; + DAT_UINT64 dat_uint64a, dat_uint64b; + DAT_UINT32 dat_uint32; + DAT_COUNT segments = 1; + DAT_COMPLETION_FLAGS comp_flags; + DAT_RETURN status = DAT_NOT_IMPLEMENTED; + + dapl_dbg_log(DAPL_DBG_TYPE_API, + "dapl_extensions(hdl %p operation %d, ...)\n", + dat_handle, ext_op); + + switch ((int)ext_op) { + + case DAT_IB_RDMA_WRITE_IMMED_OP: + dapl_dbg_log(DAPL_DBG_TYPE_RTN, + " WRITE_IMMED_DATA extension call\n"); + + ep = dat_handle; /* ep_handle */ + segments = va_arg(args, DAT_COUNT); /* num segments */ + lmr_p = va_arg(args, DAT_LMR_TRIPLET *); + cookie = va_arg(args, DAT_DTO_COOKIE); + rmr_p = va_arg(args, const DAT_RMR_TRIPLET *); + dat_uint32 = va_arg(args, DAT_UINT32); /* immed data */ + comp_flags = va_arg(args, DAT_COMPLETION_FLAGS); + + status = dapli_post_ext(ep, 0, 0, dat_uint32, segments, lmr_p, + cookie, rmr_p, OP_RDMA_WRITE_IMM, + comp_flags, ah); + break; + + case DAT_IB_CMP_AND_SWAP_OP: + dapl_dbg_log(DAPL_DBG_TYPE_RTN, + " CMP_AND_SWAP extension call\n"); + + ep = dat_handle; /* ep_handle */ + dat_uint64a = va_arg(args, DAT_UINT64); /* cmp_value */ + dat_uint64b = va_arg(args, DAT_UINT64); /* swap_value */ + lmr_p = va_arg(args, DAT_LMR_TRIPLET *); + cookie = va_arg(args, DAT_DTO_COOKIE); + rmr_p = va_arg(args, const DAT_RMR_TRIPLET *); + comp_flags = va_arg(args, DAT_COMPLETION_FLAGS); + + status = dapli_post_ext(ep, dat_uint64a, dat_uint64b, + 0, segments, lmr_p, cookie, rmr_p, + OP_COMP_AND_SWAP, comp_flags, ah); + break; + + case DAT_IB_FETCH_AND_ADD_OP: + dapl_dbg_log(DAPL_DBG_TYPE_RTN, + " FETCH_AND_ADD extension call\n"); + + ep = dat_handle; /* ep_handle */ + dat_uint64a = va_arg(args, DAT_UINT64); /* add value */ + lmr_p = va_arg(args, DAT_LMR_TRIPLET *); + cookie = va_arg(args, DAT_DTO_COOKIE); + rmr_p = va_arg(args, const DAT_RMR_TRIPLET *); + comp_flags = va_arg(args, DAT_COMPLETION_FLAGS); + + status = dapli_post_ext(ep, dat_uint64a, 0, 0, segments, + lmr_p, cookie, rmr_p, + OP_FETCH_AND_ADD, comp_flags, ah); + break; + + case DAT_IB_UD_SEND_OP: + dapl_dbg_log(DAPL_DBG_TYPE_RTN, + " UD post_send extension call\n"); + + ep = dat_handle; /* ep_handle */ + segments = va_arg(args, DAT_COUNT); /* segments */ + lmr_p = va_arg(args, DAT_LMR_TRIPLET *); + ah = va_arg(args, DAT_IB_ADDR_HANDLE *); + cookie = va_arg(args, DAT_DTO_COOKIE); + comp_flags = va_arg(args, DAT_COMPLETION_FLAGS); + + status = dapli_post_ext(ep, 0, 0, 0, segments, + lmr_p, cookie, NULL, + OP_SEND_UD, comp_flags, ah); + break; + +#ifdef DAPL_COUNTERS + case DAT_QUERY_COUNTERS_OP: + { + int cntr, reset; + DAT_UINT64 *p_cntr_out; + + dapl_dbg_log(DAPL_DBG_TYPE_RTN, + " Query counter extension call\n"); + + cntr = va_arg(args, int); + p_cntr_out = va_arg(args, DAT_UINT64 *); + reset = va_arg(args, int); + + status = dapl_query_counter(dat_handle, cntr, + p_cntr_out, reset); + break; + } + case DAT_PRINT_COUNTERS_OP: + { + int cntr, reset; + + dapl_dbg_log(DAPL_DBG_TYPE_RTN, + " Print counter extension call\n"); + + cntr = va_arg(args, int); + reset = va_arg(args, int); + + dapl_print_counter(dat_handle, cntr, reset); + status = DAT_SUCCESS; + break; + } +#endif /* DAPL_COUNTERS */ + + default: + dapl_dbg_log(DAPL_DBG_TYPE_ERR, + "unsupported extension(%d)\n", (int)ext_op); + } + + return (status); +} + +DAT_RETURN +dapli_post_ext(IN DAT_EP_HANDLE ep_handle, + IN DAT_UINT64 cmp_add, + IN DAT_UINT64 swap, + IN DAT_UINT32 immed_data, + IN DAT_COUNT segments, + IN DAT_LMR_TRIPLET * local_iov, + IN DAT_DTO_COOKIE user_cookie, + IN const DAT_RMR_TRIPLET * remote_iov, + IN int op_type, + IN DAT_COMPLETION_FLAGS flags, IN DAT_IB_ADDR_HANDLE * ah) +{ + DAPL_EP *ep_ptr; + ib_qp_handle_t qp_ptr; + DAPL_COOKIE *cookie = NULL; + DAT_RETURN dat_status = DAT_SUCCESS; + + dapl_dbg_log(DAPL_DBG_TYPE_API, + " post_ext_op: ep %p cmp_val %d " + "swap_val %d cookie 0x%x, r_iov %p, flags 0x%x, ah %p\n", + ep_handle, (unsigned)cmp_add, (unsigned)swap, + (unsigned)user_cookie.as_64, remote_iov, flags, ah); + + if (DAPL_BAD_HANDLE(ep_handle, DAPL_MAGIC_EP)) + return (DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP)); + + ep_ptr = (DAPL_EP *) ep_handle; + qp_ptr = ep_ptr->qp_handle; + + /* + * Synchronization ok since this buffer is only used for send + * requests, which aren't allowed to race with each other. + */ + dat_status = dapls_dto_cookie_alloc(&ep_ptr->req_buffer, + DAPL_DTO_TYPE_EXTENSION, + user_cookie, &cookie); + if (dat_status != DAT_SUCCESS) + goto bail; + + /* + * Take reference before posting to avoid race conditions with + * completions + */ + dapl_os_atomic_inc(&ep_ptr->req_count); + + /* + * Invoke provider specific routine to post DTO + */ + dat_status = dapls_ib_post_ext_send(ep_ptr, op_type, cookie, segments, /* data segments */ + local_iov, remote_iov, immed_data, /* immed data */ + cmp_add, /* compare or add */ + swap, /* swap */ + flags, ah); + + if (dat_status != DAT_SUCCESS) { + dapl_os_atomic_dec(&ep_ptr->req_count); + dapls_cookie_dealloc(&ep_ptr->req_buffer, cookie); + } + + bail: + return dat_status; + +} + +/* + * New provider routine to process extended DTO events + */ +void +dapls_cqe_to_event_extension(IN DAPL_EP * ep_ptr, + IN DAPL_COOKIE * cookie, + IN ib_work_completion_t * cqe_ptr, + IN DAT_EVENT * event_ptr) +{ + uint32_t ibtype; + DAT_DTO_COMPLETION_EVENT_DATA *dto = + &event_ptr->event_data.dto_completion_event_data; + DAT_IB_EXTENSION_EVENT_DATA *ext_data = (DAT_IB_EXTENSION_EVENT_DATA *) + & event_ptr->event_extension_data[0]; + DAT_DTO_COMPLETION_STATUS dto_status; + + /* Get status from cqe */ + dto_status = dapls_ib_get_dto_status(cqe_ptr); + + dapl_dbg_log(DAPL_DBG_TYPE_EVD, + " cqe_to_event_ext: dto_ptr %p ext_ptr %p status %d\n", + dto, ext_data, dto_status); + + event_ptr->event_number = DAT_IB_DTO_EVENT; + dto->ep_handle = cookie->ep; + dto->user_cookie = cookie->val.dto.cookie; + dto->operation = DAPL_GET_CQE_DTOS_OPTYPE(cqe_ptr); /* new for 2.0 */ + dto->status = ext_data->status = dto_status; + + if (dto_status != DAT_DTO_SUCCESS) + return; + + /* + * Get operation type from CQ work completion entry and + * if extented operation then set extended event data + */ + ibtype = DAPL_GET_CQE_OPTYPE(cqe_ptr); + + switch (ibtype) { + + case OP_RDMA_WRITE_IMM: + dapl_dbg_log(DAPL_DBG_TYPE_EVD, + " cqe_to_event_ext: OP_RDMA_WRITE_IMMED\n"); + + /* type and outbound rdma write transfer size */ + dto->transfered_length = cookie->val.dto.size; + ext_data->type = DAT_IB_RDMA_WRITE_IMMED; + break; + case OP_RECEIVE_IMM: + dapl_dbg_log(DAPL_DBG_TYPE_EVD, + " cqe_to_event_ext: OP_RECEIVE_RDMA_IMMED\n"); + + /* immed recvd, type and inbound rdma write transfer size */ + dto->transfered_length = DAPL_GET_CQE_BYTESNUM(cqe_ptr); + ext_data->type = DAT_IB_RDMA_WRITE_IMMED_DATA; + ext_data->val.immed.data = DAPL_GET_CQE_IMMED_DATA(cqe_ptr); + break; + case OP_RECEIVE_MSG_IMM: + dapl_dbg_log(DAPL_DBG_TYPE_EVD, + " cqe_to_event_ext: OP_RECEIVE_MSG_IMMED\n"); + + /* immed recvd, type and inbound recv message transfer size */ + dto->transfered_length = DAPL_GET_CQE_BYTESNUM(cqe_ptr); + ext_data->type = DAT_IB_RECV_IMMED_DATA; + ext_data->val.immed.data = DAPL_GET_CQE_IMMED_DATA(cqe_ptr); + break; + case OP_COMP_AND_SWAP: + dapl_dbg_log(DAPL_DBG_TYPE_EVD, + " cqe_to_event_ext: COMP_AND_SWAP_RESP\n"); + + /* original data is returned in LMR provided with post */ + ext_data->type = DAT_IB_CMP_AND_SWAP; + dto->transfered_length = DAPL_GET_CQE_BYTESNUM(cqe_ptr); + break; + case OP_FETCH_AND_ADD: + dapl_dbg_log(DAPL_DBG_TYPE_EVD, + " cqe_to_event_ext: FETCH_AND_ADD_RESP\n"); + + /* original data is returned in LMR provided with post */ + ext_data->type = DAT_IB_FETCH_AND_ADD; + dto->transfered_length = DAPL_GET_CQE_BYTESNUM(cqe_ptr); + break; + case OP_SEND_UD: + dapl_dbg_log(DAPL_DBG_TYPE_EVD, " cqe_to_event_ext: UD_SEND\n"); + + /* type and outbound send transfer size */ + ext_data->type = DAT_IB_UD_SEND; + dto->transfered_length = cookie->val.dto.size; + break; + case OP_RECV_UD: + dapl_dbg_log(DAPL_DBG_TYPE_EVD, " cqe_to_event_ext: UD_RECV\n"); + + /* type and inbound recv message transfer size */ + ext_data->type = DAT_IB_UD_RECV; + dto->transfered_length = DAPL_GET_CQE_BYTESNUM(cqe_ptr); + break; + + default: + /* not extended operation */ + ext_data->status = DAT_IB_OP_ERR; + dto->status = DAT_DTO_ERR_TRANSPORT; + break; + } +} diff --git a/branches/WOF2-3/ulp/dapl2/dapl/openib_common/mem.c b/branches/WOF2-3/ulp/dapl2/dapl/openib_common/mem.c new file mode 100644 index 00000000..ddf85a4c --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/openib_common/mem.c @@ -0,0 +1,365 @@ +/* + * Copyright (c) 2005-2007 Intel Corporation. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ +#include "dapl.h" +#include "dapl_adapter_util.h" +#include "dapl_lmr_util.h" + +/* + * dapls_convert_privileges + * + * Convert LMR privileges to provider + * + * Input: + * DAT_MEM_PRIV_FLAGS + * + * Output: + * none + * + * Returns: + * ibv_access_flags + * + */ +STATIC _INLINE_ int dapls_convert_privileges(IN DAT_MEM_PRIV_FLAGS privileges) +{ + int access = 0; + + /* + * if (DAT_MEM_PRIV_LOCAL_READ_FLAG & privileges) do nothing + */ + if (DAT_MEM_PRIV_LOCAL_WRITE_FLAG & privileges) + access |= IBV_ACCESS_LOCAL_WRITE; + if (DAT_MEM_PRIV_REMOTE_WRITE_FLAG & privileges) + access |= IBV_ACCESS_REMOTE_WRITE; + if (DAT_MEM_PRIV_REMOTE_READ_FLAG & privileges) + access |= IBV_ACCESS_REMOTE_READ; +#ifdef DAT_EXTENSIONS + if (DAT_IB_MEM_PRIV_REMOTE_ATOMIC & privileges) + access |= IBV_ACCESS_REMOTE_ATOMIC; +#endif + + return access; +} + +/* + * dapl_ib_pd_alloc + * + * Alloc a PD + * + * Input: + * ia_handle IA handle + * pz pointer to PZ struct + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * + */ +DAT_RETURN dapls_ib_pd_alloc(IN DAPL_IA * ia_ptr, IN DAPL_PZ * pz) +{ + /* get a protection domain */ + pz->pd_handle = ibv_alloc_pd(ia_ptr->hca_ptr->ib_hca_handle); + if (!pz->pd_handle) + return (dapl_convert_errno(ENOMEM, "alloc_pd")); + + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, + " pd_alloc: pd_handle=%p\n", pz->pd_handle); + + return DAT_SUCCESS; +} + +/* + * dapl_ib_pd_free + * + * Free a PD + * + * Input: + * ia_handle IA handle + * PZ_ptr pointer to PZ struct + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_STATE + * + */ +DAT_RETURN dapls_ib_pd_free(IN DAPL_PZ * pz) +{ + if (pz->pd_handle != IB_INVALID_HANDLE) { + ibv_dealloc_pd(pz->pd_handle); + pz->pd_handle = IB_INVALID_HANDLE; + } + return DAT_SUCCESS; +} + +/* + * dapl_ib_mr_register + * + * Register a virtual memory region + * + * Input: + * ia_handle IA handle + * lmr pointer to dapl_lmr struct + * virt_addr virtual address of beginning of mem region + * length length of memory region + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * + */ +DAT_RETURN +dapls_ib_mr_register(IN DAPL_IA * ia_ptr, + IN DAPL_LMR * lmr, + IN DAT_PVOID virt_addr, + IN DAT_VLEN length, + IN DAT_MEM_PRIV_FLAGS privileges, IN DAT_VA_TYPE va_type) +{ + ib_pd_handle_t ib_pd_handle; + struct ibv_device *ibv_dev = ia_ptr->hca_ptr->ib_hca_handle->device; + + ib_pd_handle = ((DAPL_PZ *) lmr->param.pz_handle)->pd_handle; + + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, + " mr_register: ia=%p, lmr=%p va=%p ln=%d pv=0x%x\n", + ia_ptr, lmr, virt_addr, length, privileges); + + /* TODO: shared memory */ + if (lmr->param.mem_type == DAT_MEM_TYPE_SHARED_VIRTUAL) { + dapl_dbg_log(DAPL_DBG_TYPE_ERR, + " mr_register_shared: NOT IMPLEMENTED\n"); + return DAT_ERROR(DAT_NOT_IMPLEMENTED, DAT_NO_SUBTYPE); + } + + /* iWARP only support */ + if ((va_type == DAT_VA_TYPE_ZB) && + (ibv_dev->transport_type != IBV_TRANSPORT_IWARP)) { + dapl_dbg_log(DAPL_DBG_TYPE_ERR, + " va_type == DAT_VA_TYPE_ZB: NOT SUPPORTED\n"); + return DAT_ERROR(DAT_NOT_IMPLEMENTED, DAT_NO_SUBTYPE); + } + + /* local read is default on IB */ + lmr->mr_handle = + ibv_reg_mr(((DAPL_PZ *) lmr->param.pz_handle)->pd_handle, + virt_addr, length, dapls_convert_privileges(privileges)); + + if (!lmr->mr_handle) + return (dapl_convert_errno(ENOMEM, "reg_mr")); + + lmr->param.lmr_context = lmr->mr_handle->lkey; + lmr->param.rmr_context = lmr->mr_handle->rkey; + lmr->param.registered_size = length; + lmr->param.registered_address = (DAT_VADDR) (uintptr_t) virt_addr; + + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, + " mr_register: mr=%p addr=%p pd %p ctx %p " + "lkey=0x%x rkey=0x%x priv=%x\n", + lmr->mr_handle, lmr->mr_handle->addr, + lmr->mr_handle->pd, lmr->mr_handle->context, + lmr->mr_handle->lkey, lmr->mr_handle->rkey, + length, dapls_convert_privileges(privileges)); + + return DAT_SUCCESS; +} + +/* + * dapl_ib_mr_deregister + * + * Free a memory region + * + * Input: + * lmr pointer to dapl_lmr struct + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_STATE + * + */ +DAT_RETURN dapls_ib_mr_deregister(IN DAPL_LMR * lmr) +{ + if (lmr->mr_handle != IB_INVALID_HANDLE) { + if (ibv_dereg_mr(lmr->mr_handle)) + return (dapl_convert_errno(errno, "dereg_pd")); + lmr->mr_handle = IB_INVALID_HANDLE; + } + return DAT_SUCCESS; +} + +/* + * dapl_ib_mr_register_shared + * + * Register a virtual memory region + * + * Input: + * ia_ptr IA handle + * lmr pointer to dapl_lmr struct + * privileges + * va_type + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * + */ +DAT_RETURN +dapls_ib_mr_register_shared(IN DAPL_IA * ia_ptr, + IN DAPL_LMR * lmr, + IN DAT_MEM_PRIV_FLAGS privileges, + IN DAT_VA_TYPE va_type) +{ + dapl_dbg_log(DAPL_DBG_TYPE_ERR, + " mr_register_shared: NOT IMPLEMENTED\n"); + + return DAT_ERROR(DAT_NOT_IMPLEMENTED, DAT_NO_SUBTYPE); +} + +/* + * dapls_ib_mw_alloc + * + * Bind a protection domain to a memory window + * + * Input: + * rmr Initialized rmr to hold binding handles + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * + */ +DAT_RETURN dapls_ib_mw_alloc(IN DAPL_RMR * rmr) +{ + + dapl_dbg_log(DAPL_DBG_TYPE_ERR, " mw_alloc: NOT IMPLEMENTED\n"); + + return DAT_ERROR(DAT_NOT_IMPLEMENTED, DAT_NO_SUBTYPE); +} + +/* + * dapls_ib_mw_free + * + * Release bindings of a protection domain to a memory window + * + * Input: + * rmr Initialized rmr to hold binding handles + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_STATE + * + */ +DAT_RETURN dapls_ib_mw_free(IN DAPL_RMR * rmr) +{ + dapl_dbg_log(DAPL_DBG_TYPE_ERR, " mw_free: NOT IMPLEMENTED\n"); + + return DAT_ERROR(DAT_NOT_IMPLEMENTED, DAT_NO_SUBTYPE); +} + +/* + * dapls_ib_mw_bind + * + * Bind a protection domain to a memory window + * + * Input: + * rmr Initialized rmr to hold binding handles + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER; + * DAT_INSUFFICIENT_RESOURCES + * + */ +DAT_RETURN +dapls_ib_mw_bind(IN DAPL_RMR * rmr, + IN DAPL_LMR * lmr, + IN DAPL_EP * ep, + IN DAPL_COOKIE * cookie, + IN DAT_VADDR virtual_address, + IN DAT_VLEN length, + IN DAT_MEM_PRIV_FLAGS mem_priv, IN DAT_BOOLEAN is_signaled) +{ + dapl_dbg_log(DAPL_DBG_TYPE_ERR, " mw_bind: NOT IMPLEMENTED\n"); + + return DAT_ERROR(DAT_NOT_IMPLEMENTED, DAT_NO_SUBTYPE); +} + +/* + * dapls_ib_mw_unbind + * + * Unbind a protection domain from a memory window + * + * Input: + * rmr Initialized rmr to hold binding handles + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER; + * DAT_INVALID_STATE; + * DAT_INSUFFICIENT_RESOURCES + * + */ +DAT_RETURN +dapls_ib_mw_unbind(IN DAPL_RMR * rmr, + IN DAPL_EP * ep, + IN DAPL_COOKIE * cookie, IN DAT_BOOLEAN is_signaled) +{ + dapl_dbg_log(DAPL_DBG_TYPE_ERR, " mw_unbind: NOT IMPLEMENTED\n"); + + return DAT_ERROR(DAT_NOT_IMPLEMENTED, DAT_NO_SUBTYPE); +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/openib_common/qp.c b/branches/WOF2-3/ulp/dapl2/dapl/openib_common/qp.c new file mode 100644 index 00000000..179eef0e --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/openib_common/qp.c @@ -0,0 +1,614 @@ +/* + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ +#include "dapl.h" +#include "dapl_adapter_util.h" +#include "dapl_ep_util.h" + +/* + * dapl_ib_qp_alloc + * + * Alloc a QP + * + * Input: + * *ep_ptr pointer to EP INFO + * ib_hca_handle provider HCA handle + * ib_pd_handle provider protection domain handle + * cq_recv provider recv CQ handle + * cq_send provider send CQ handle + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INTERNAL_ERROR + * + */ +DAT_RETURN +dapls_ib_qp_alloc(IN DAPL_IA * ia_ptr, + IN DAPL_EP * ep_ptr, IN DAPL_EP * ep_ctx_ptr) +{ + DAT_EP_ATTR *attr; + DAPL_EVD *rcv_evd, *req_evd; + ib_cq_handle_t rcv_cq, req_cq; + ib_pd_handle_t ib_pd_handle; + struct ibv_qp_init_attr qp_create; +#ifdef _OPENIB_CMA_ + dp_ib_cm_handle_t conn; +#endif + dapl_dbg_log(DAPL_DBG_TYPE_EP, + " qp_alloc: ia_ptr %p ep_ptr %p ep_ctx_ptr %p\n", + ia_ptr, ep_ptr, ep_ctx_ptr); + + attr = &ep_ptr->param.ep_attr; + ib_pd_handle = ((DAPL_PZ *) ep_ptr->param.pz_handle)->pd_handle; + rcv_evd = (DAPL_EVD *) ep_ptr->param.recv_evd_handle; + req_evd = (DAPL_EVD *) ep_ptr->param.request_evd_handle; + + /* + * DAT allows usage model of EP's with no EVD's but IB does not. + * Create a CQ with zero entries under the covers to support and + * catch any invalid posting. + */ + if (rcv_evd != DAT_HANDLE_NULL) + rcv_cq = rcv_evd->ib_cq_handle; + else if (!ia_ptr->hca_ptr->ib_trans.ib_cq_empty) + rcv_cq = ia_ptr->hca_ptr->ib_trans.ib_cq_empty; + else { + struct ibv_comp_channel *channel; + + channel = ibv_create_comp_channel(ia_ptr->hca_ptr->ib_hca_handle); + if (!channel) + return (dapl_convert_errno(ENOMEM, "create_cq")); + + /* Call IB verbs to create CQ */ + rcv_cq = ibv_create_cq(ia_ptr->hca_ptr->ib_hca_handle, + 0, NULL, channel, 0); + + if (rcv_cq == IB_INVALID_HANDLE) { + ibv_destroy_comp_channel(channel); + return (dapl_convert_errno(ENOMEM, "create_cq")); + } + + ia_ptr->hca_ptr->ib_trans.ib_cq_empty = rcv_cq; + } + if (req_evd != DAT_HANDLE_NULL) + req_cq = req_evd->ib_cq_handle; + else + req_cq = ia_ptr->hca_ptr->ib_trans.ib_cq_empty; + + /* + * IMPLEMENTATION NOTE: + * uDAPL allows consumers to post buffers on the EP after creation + * and before a connect request (outbound and inbound). This forces + * a binding to a device during the hca_open call and requires the + * consumer to predetermine which device to listen on or connect from. + * This restriction eliminates any option of listening or connecting + * over multiple devices. uDAPL should add API's to resolve addresses + * and bind to the device at the approriate time (before connect + * and after CR arrives). Discovery should happen at connection time + * based on addressing and not on static configuration during open. + */ + +#ifdef _OPENIB_CMA_ + /* Allocate CM and initialize lock */ + if ((conn = dapls_ib_cm_create(ep_ptr)) == NULL) + return (dapl_convert_errno(ENOMEM, "cm_create")); + + /* open identifies the local device; per DAT specification */ + if (rdma_bind_addr(conn->cm_id, + (struct sockaddr *)&ia_ptr->hca_ptr->hca_address)) { + dapls_cm_free(conn); + return (dapl_convert_errno(EAFNOSUPPORT, "rdma_bind_addr")); + } +#endif + /* Setup attributes and create qp */ + dapl_os_memzero((void *)&qp_create, sizeof(qp_create)); + qp_create.send_cq = req_cq; + qp_create.cap.max_send_wr = attr->max_request_dtos; + qp_create.cap.max_send_sge = attr->max_request_iov; + qp_create.cap.max_inline_data = + ia_ptr->hca_ptr->ib_trans.max_inline_send; + qp_create.qp_type = IBV_QPT_RC; + qp_create.qp_context = (void *)ep_ptr; + +#ifdef DAT_EXTENSIONS + if (attr->service_type == DAT_IB_SERVICE_TYPE_UD) { +#ifdef _OPENIB_CMA_ + return (DAT_NOT_IMPLEMENTED); +#endif + qp_create.qp_type = IBV_QPT_UD; + if (attr->max_message_size > + (128 << ia_ptr->hca_ptr->ib_trans.mtu)) { + return (DAT_INVALID_PARAMETER | DAT_INVALID_ARG6); + } + } +#endif + + /* ibv assumes rcv_cq is never NULL, set to req_cq */ + if (rcv_cq == NULL) { + qp_create.recv_cq = req_cq; + qp_create.cap.max_recv_wr = 0; + qp_create.cap.max_recv_sge = 0; + } else { + qp_create.recv_cq = rcv_cq; + qp_create.cap.max_recv_wr = attr->max_recv_dtos; + qp_create.cap.max_recv_sge = attr->max_recv_iov; + } + +#ifdef _OPENIB_CMA_ + if (rdma_create_qp(conn->cm_id, ib_pd_handle, &qp_create)) { + dapls_cm_free(conn); + return (dapl_convert_errno(errno, "rdma_create_qp")); + } + ep_ptr->qp_handle = conn->cm_id->qp; + ep_ptr->qp_state = IBV_QPS_INIT; + + ep_ptr->param.local_port_qual = rdma_get_src_port(conn->cm_id); +#else + ep_ptr->qp_handle = ibv_create_qp(ib_pd_handle, &qp_create); + if (!ep_ptr->qp_handle) + return (dapl_convert_errno(ENOMEM, "create_qp")); + + /* Setup QP attributes for INIT state on the way out */ + if (dapls_modify_qp_state(ep_ptr->qp_handle, + IBV_QPS_INIT, 0, 0, 0) != DAT_SUCCESS) { + ibv_destroy_qp(ep_ptr->qp_handle); + ep_ptr->qp_handle = IB_INVALID_HANDLE; + return DAT_INTERNAL_ERROR; + } +#endif + dapl_dbg_log(DAPL_DBG_TYPE_EP, + " qp_alloc: qpn %p type %d sq %d,%d rq %d,%d\n", + ep_ptr->qp_handle->qp_num, ep_ptr->qp_handle->qp_type, + qp_create.cap.max_send_wr, qp_create.cap.max_send_sge, + qp_create.cap.max_recv_wr, qp_create.cap.max_recv_sge); + + return DAT_SUCCESS; +} + +/* + * dapl_ib_qp_free + * + * Free a QP + * + * Input: + * ia_handle IA handle + * *ep_ptr pointer to EP INFO + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * dapl_convert_errno + * + */ +DAT_RETURN dapls_ib_qp_free(IN DAPL_IA * ia_ptr, IN DAPL_EP * ep_ptr) +{ +#ifdef _OPENIB_CMA_ + dp_ib_cm_handle_t cm_ptr = dapl_get_cm_from_ep(ep_ptr); + + dapl_os_lock(&ep_ptr->header.lock); + if (cm_ptr && cm_ptr->cm_id->qp) { + rdma_destroy_qp(cm_ptr->cm_id); + cm_ptr->cm_id->qp = NULL; + ep_ptr->qp_handle = NULL; + } +#else + dapl_os_lock(&ep_ptr->header.lock); + if (ep_ptr->qp_handle != NULL) { + /* force error state to flush queue, then destroy */ + dapls_modify_qp_state(ep_ptr->qp_handle, IBV_QPS_ERR, 0,0,0); + + if (ibv_destroy_qp(ep_ptr->qp_handle)) { + dapl_log(DAPL_DBG_TYPE_ERR, + " qp_free: ibv_destroy_qp error - %s\n", + strerror(errno)); + } + ep_ptr->qp_handle = NULL; + } +#endif + dapl_os_unlock(&ep_ptr->header.lock); + return DAT_SUCCESS; +} + +/* + * dapl_ib_qp_modify + * + * Set the QP to the parameters specified in an EP_PARAM + * + * The EP_PARAM structure that is provided has been + * sanitized such that only non-zero values are valid. + * + * Input: + * ib_hca_handle HCA handle + * qp_handle QP handle + * ep_attr Sanitized EP Params + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + * + */ +DAT_RETURN +dapls_ib_qp_modify(IN DAPL_IA * ia_ptr, + IN DAPL_EP * ep_ptr, IN DAT_EP_ATTR * attr) +{ + struct ibv_qp_attr qp_attr; + + if (ep_ptr->qp_handle == IB_INVALID_HANDLE) + return DAT_INVALID_PARAMETER; + + /* + * EP state, qp_handle state should be an indication + * of current state but the only way to be sure is with + * a user mode ibv_query_qp call which is NOT available + */ + + /* move to error state if necessary */ + if ((ep_ptr->qp_state == IB_QP_STATE_ERROR) && + (ep_ptr->qp_handle->state != IBV_QPS_ERR)) { + return (dapls_modify_qp_state(ep_ptr->qp_handle, + IBV_QPS_ERR, 0, 0, 0)); + } + + /* + * Check if we have the right qp_state to modify attributes + */ + if ((ep_ptr->qp_handle->state != IBV_QPS_RTR) && + (ep_ptr->qp_handle->state != IBV_QPS_RTS)) + return DAT_INVALID_STATE; + + /* Adjust to current EP attributes */ + dapl_os_memzero((void *)&qp_attr, sizeof(qp_attr)); + qp_attr.cap.max_send_wr = attr->max_request_dtos; + qp_attr.cap.max_recv_wr = attr->max_recv_dtos; + qp_attr.cap.max_send_sge = attr->max_request_iov; + qp_attr.cap.max_recv_sge = attr->max_recv_iov; + + dapl_dbg_log(DAPL_DBG_TYPE_EP, + "modify_qp: qp %p sq %d,%d, rq %d,%d\n", + ep_ptr->qp_handle, + qp_attr.cap.max_send_wr, qp_attr.cap.max_send_sge, + qp_attr.cap.max_recv_wr, qp_attr.cap.max_recv_sge); + + if (ibv_modify_qp(ep_ptr->qp_handle, &qp_attr, IBV_QP_CAP)) { + dapl_dbg_log(DAPL_DBG_TYPE_ERR, + "modify_qp: modify ep %p qp %p failed\n", + ep_ptr, ep_ptr->qp_handle); + return (dapl_convert_errno(errno, "modify_qp_state")); + } + + return DAT_SUCCESS; +} + +/* + * dapls_ib_reinit_ep + * + * Move the QP to INIT state again. + * + * Input: + * ep_ptr DAPL_EP + * + * Output: + * none + * + * Returns: + * void + * + */ +#if defined(_WIN32) || defined(_WIN64) || defined(_OPENIB_CMA_) +void dapls_ib_reinit_ep(IN DAPL_EP * ep_ptr) +{ + dp_ib_cm_handle_t cm_ptr, next_cm_ptr; + + /* work around bug in low level driver - 3/24/09 */ + /* RTS -> RESET -> INIT -> ERROR QP transition crashes system */ + if (ep_ptr->qp_handle != IB_INVALID_HANDLE) { + dapls_ib_qp_free(ep_ptr->header.owner_ia, ep_ptr); + + /* free any CM object's created */ + cm_ptr = (dapl_llist_is_empty(&ep_ptr->cm_list_head) + ? NULL : dapl_llist_peek_head(&ep_ptr->cm_list_head)); + while (cm_ptr != NULL) { + next_cm_ptr = dapl_llist_next_entry(&ep_ptr->cm_list_head, + &cm_ptr->list_entry); + dapls_cm_free(cm_ptr); + cm_ptr = next_cm_ptr; + } + dapls_ib_qp_alloc(ep_ptr->header.owner_ia, ep_ptr, ep_ptr); + } +} +#else // _WIN32 || _WIN64 +void dapls_ib_reinit_ep(IN DAPL_EP * ep_ptr) +{ + if (ep_ptr->qp_handle != IB_INVALID_HANDLE && + ep_ptr->qp_handle->qp_type != IBV_QPT_UD) { + /* move to RESET state and then to INIT */ + dapls_modify_qp_state(ep_ptr->qp_handle, IBV_QPS_RESET,0,0,0); + dapls_modify_qp_state(ep_ptr->qp_handle, IBV_QPS_INIT,0,0,0); + } +} +#endif // _WIN32 || _WIN64 + +/* + * Generic QP modify for init, reset, error, RTS, RTR + * For UD, create_ah on RTR, qkey on INIT + * CM msg provides QP attributes, info in network order + */ +DAT_RETURN +dapls_modify_qp_state(IN ib_qp_handle_t qp_handle, + IN ib_qp_state_t qp_state, + IN uint32_t qpn, + IN uint16_t lid, + IN ib_gid_handle_t gid) +{ + struct ibv_qp_attr qp_attr; + enum ibv_qp_attr_mask mask = IBV_QP_STATE; + DAPL_EP *ep_ptr = (DAPL_EP *) qp_handle->qp_context; + DAPL_IA *ia_ptr = ep_ptr->header.owner_ia; + int ret; + + dapl_os_memzero((void *)&qp_attr, sizeof(qp_attr)); + qp_attr.qp_state = qp_state; + + switch (qp_state) { + case IBV_QPS_RTR: + dapl_dbg_log(DAPL_DBG_TYPE_EP, + " QPS_RTR: type %d qpn 0x%x gid %p (%d) lid 0x%x" + " port %d ep %p qp_state %d \n", + qp_handle->qp_type, ntohl(qpn), gid, + ia_ptr->hca_ptr->ib_trans.global, + ntohs(lid), ia_ptr->hca_ptr->port_num, + ep_ptr, ep_ptr->qp_state); + + mask |= IBV_QP_AV | + IBV_QP_PATH_MTU | + IBV_QP_DEST_QPN | + IBV_QP_RQ_PSN | + IBV_QP_MAX_DEST_RD_ATOMIC | IBV_QP_MIN_RNR_TIMER; + + qp_attr.dest_qp_num = ntohl(qpn); + qp_attr.rq_psn = 1; + qp_attr.path_mtu = ia_ptr->hca_ptr->ib_trans.mtu; + qp_attr.max_dest_rd_atomic = + ep_ptr->param.ep_attr.max_rdma_read_out; + qp_attr.min_rnr_timer = + ia_ptr->hca_ptr->ib_trans.rnr_timer; + + /* address handle. RC and UD */ + qp_attr.ah_attr.dlid = ntohs(lid); + if (gid && ia_ptr->hca_ptr->ib_trans.global) { + dapl_dbg_log(DAPL_DBG_TYPE_EP, + " QPS_RTR: GID Subnet 0x" F64x " ID 0x" F64x "\n", + (unsigned long long)htonll(gid->global.subnet_prefix), + (unsigned long long)htonll(gid->global.interface_id)); + + qp_attr.ah_attr.is_global = 1; + qp_attr.ah_attr.grh.dgid.global.subnet_prefix = + gid->global.subnet_prefix; + qp_attr.ah_attr.grh.dgid.global.interface_id = + gid->global.interface_id; + qp_attr.ah_attr.grh.hop_limit = + ia_ptr->hca_ptr->ib_trans.hop_limit; + qp_attr.ah_attr.grh.traffic_class = + ia_ptr->hca_ptr->ib_trans.tclass; + } + qp_attr.ah_attr.sl = ia_ptr->hca_ptr->ib_trans.sl; + qp_attr.ah_attr.src_path_bits = 0; + qp_attr.ah_attr.port_num = ia_ptr->hca_ptr->port_num; + + /* UD: already in RTR, RTS state */ + if (qp_handle->qp_type == IBV_QPT_UD) { + mask = IBV_QP_STATE; + if (ep_ptr->qp_state == IBV_QPS_RTR || + ep_ptr->qp_state == IBV_QPS_RTS) + return DAT_SUCCESS; + } + break; + case IBV_QPS_RTS: + if (qp_handle->qp_type == IBV_QPT_RC) { + mask |= IBV_QP_SQ_PSN | + IBV_QP_TIMEOUT | + IBV_QP_RETRY_CNT | + IBV_QP_RNR_RETRY | IBV_QP_MAX_QP_RD_ATOMIC; + qp_attr.timeout = + ia_ptr->hca_ptr->ib_trans.ack_timer; + qp_attr.retry_cnt = + ia_ptr->hca_ptr->ib_trans.ack_retry; + qp_attr.rnr_retry = + ia_ptr->hca_ptr->ib_trans.rnr_retry; + qp_attr.max_rd_atomic = + ep_ptr->param.ep_attr.max_rdma_read_out; + } + /* RC and UD */ + qp_attr.qp_state = IBV_QPS_RTS; + qp_attr.sq_psn = 1; + + dapl_dbg_log(DAPL_DBG_TYPE_EP, + " QPS_RTS: psn %x rd_atomic %d ack %d " + " retry %d rnr_retry %d ep %p qp_state %d\n", + qp_attr.sq_psn, qp_attr.max_rd_atomic, + qp_attr.timeout, qp_attr.retry_cnt, + qp_attr.rnr_retry, ep_ptr, + ep_ptr->qp_state); + + if (qp_handle->qp_type == IBV_QPT_UD) { + /* already RTS, multi remote AH's on QP */ + if (ep_ptr->qp_state == IBV_QPS_RTS) + return DAT_SUCCESS; + else + mask = IBV_QP_STATE | IBV_QP_SQ_PSN; + } + break; + case IBV_QPS_INIT: + mask |= IBV_QP_PKEY_INDEX | IBV_QP_PORT; + if (qp_handle->qp_type == IBV_QPT_RC) { + mask |= IBV_QP_ACCESS_FLAGS; + qp_attr.qp_access_flags = + IBV_ACCESS_LOCAL_WRITE | + IBV_ACCESS_REMOTE_WRITE | + IBV_ACCESS_REMOTE_READ | + IBV_ACCESS_REMOTE_ATOMIC | + IBV_ACCESS_MW_BIND; + } + + if (qp_handle->qp_type == IBV_QPT_UD) { + /* already INIT, multi remote AH's on QP */ + if (ep_ptr->qp_state == IBV_QPS_INIT) + return DAT_SUCCESS; + mask |= IBV_QP_QKEY; + qp_attr.qkey = DAT_UD_QKEY; + } + + qp_attr.pkey_index = ia_ptr->hca_ptr->ib_trans.pkey_idx; + qp_attr.port_num = ia_ptr->hca_ptr->port_num; + + dapl_dbg_log(DAPL_DBG_TYPE_EP, + " QPS_INIT: pi %x port %x acc %x qkey 0x%x\n", + qp_attr.pkey_index, qp_attr.port_num, + qp_attr.qp_access_flags, qp_attr.qkey); + break; + default: + break; + } + + ret = ibv_modify_qp(qp_handle, &qp_attr, mask); + if (ret == 0) { + ep_ptr->qp_state = qp_state; + return DAT_SUCCESS; + } else { + return (dapl_convert_errno(errno, "modify_qp_state")); + } +} + +/* Modify UD type QP from init, rtr, rts, info network order */ +DAT_RETURN +dapls_modify_qp_ud(IN DAPL_HCA *hca, IN ib_qp_handle_t qp) +{ + struct ibv_qp_attr qp_attr; + + /* modify QP, setup and prepost buffers */ + dapl_os_memzero((void *)&qp_attr, sizeof(qp_attr)); + qp_attr.qp_state = IBV_QPS_INIT; + qp_attr.pkey_index = hca->ib_trans.pkey_idx; + qp_attr.port_num = hca->port_num; + qp_attr.qkey = DAT_UD_QKEY; + if (ibv_modify_qp(qp, &qp_attr, + IBV_QP_STATE | + IBV_QP_PKEY_INDEX | + IBV_QP_PORT | + IBV_QP_QKEY)) { + dapl_log(DAPL_DBG_TYPE_ERR, + " modify_ud_qp INIT: ERR %s\n", strerror(errno)); + return (dapl_convert_errno(errno, "modify_qp")); + } + dapl_os_memzero((void *)&qp_attr, sizeof(qp_attr)); + qp_attr.qp_state = IBV_QPS_RTR; + if (ibv_modify_qp(qp, &qp_attr,IBV_QP_STATE)) { + dapl_log(DAPL_DBG_TYPE_ERR, + " modify_ud_qp RTR: ERR %s\n", strerror(errno)); + return (dapl_convert_errno(errno, "modify_qp")); + } + dapl_os_memzero((void *)&qp_attr, sizeof(qp_attr)); + qp_attr.qp_state = IBV_QPS_RTS; + qp_attr.sq_psn = 1; + if (ibv_modify_qp(qp, &qp_attr, + IBV_QP_STATE | IBV_QP_SQ_PSN)) { + dapl_log(DAPL_DBG_TYPE_ERR, + " modify_ud_qp RTS: ERR %s\n", strerror(errno)); + return (dapl_convert_errno(errno, "modify_qp")); + } + return DAT_SUCCESS; +} + +/* Create address handle for remote QP, info in network order */ +ib_ah_handle_t +dapls_create_ah(IN DAPL_HCA *hca, + IN ib_pd_handle_t pd, + IN ib_qp_handle_t qp, + IN uint16_t lid, + IN ib_gid_handle_t gid) +{ + struct ibv_qp_attr qp_attr; + ib_ah_handle_t ah; + + if (qp->qp_type != IBV_QPT_UD) { + dapl_log(DAPL_DBG_TYPE_ERR, + " create_ah ERR: QP_type != UD\n"); + return NULL; + } + + dapl_os_memzero((void *)&qp_attr, sizeof(qp_attr)); + qp_attr.qp_state = IBV_QP_STATE; + + /* address handle. RC and UD */ + qp_attr.ah_attr.dlid = ntohs(lid); + if (gid != NULL) { + dapl_log(DAPL_DBG_TYPE_CM, "dapl_create_ah: with GID\n"); + qp_attr.ah_attr.is_global = 1; + qp_attr.ah_attr.grh.dgid.global.subnet_prefix = + ntohll(gid->global.subnet_prefix); + qp_attr.ah_attr.grh.dgid.global.interface_id = + ntohll(gid->global.interface_id); + qp_attr.ah_attr.grh.hop_limit = hca->ib_trans.hop_limit; + qp_attr.ah_attr.grh.traffic_class = hca->ib_trans.tclass; + } + qp_attr.ah_attr.sl = hca->ib_trans.sl; + qp_attr.ah_attr.src_path_bits = 0; + qp_attr.ah_attr.port_num = hca->port_num; + + dapl_log(DAPL_DBG_TYPE_CM, + " dapls_create_ah: port %x lid %x pd %p ctx %p handle 0x%x\n", + hca->port_num,qp_attr.ah_attr.dlid, pd, pd->context, pd->handle); + + /* UD: create AH for remote side */ + ah = ibv_create_ah(pd, &qp_attr.ah_attr); + if (!ah) { + dapl_log(DAPL_DBG_TYPE_ERR, + " create_ah: ERR %s\n", strerror(errno)); + return NULL; + } + + dapl_log(DAPL_DBG_TYPE_CM, + " dapls_create_ah: AH %p for lid %x\n", + ah, qp_attr.ah_attr.dlid); + + return ah; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/openib_common/util.c b/branches/WOF2-3/ulp/dapl2/dapl/openib_common/util.c new file mode 100644 index 00000000..2345da57 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/openib_common/util.c @@ -0,0 +1,724 @@ +/* + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ +#include "dapl.h" +#include "dapl_adapter_util.h" +#include "dapl_ib_util.h" +#include "dapl_osd.h" + +#include + +int g_dapl_loopback_connection = 0; + +#if defined(_WIN64) || defined(_WIN32) +#include "..\..\..\..\..\etc\user\comp_channel.cpp" +#include + +int getipaddr_netdev(char *name, char *addr, int addr_len) +{ + IWVProvider *prov; + WV_DEVICE_ADDRESS devaddr; + struct addrinfo *res, *ai; + HRESULT hr; + int index; + + if (strncmp(name, "rdma_dev", 8)) { + return EINVAL; + } + + index = atoi(name + 8); + + hr = WvGetObject(&IID_IWVProvider, (LPVOID *) &prov); + if (FAILED(hr)) { + return hr; + } + + hr = getaddrinfo("..localmachine", NULL, NULL, &res); + if (hr) { + goto release; + } + + for (ai = res; ai; ai = ai->ai_next) { + hr = prov->lpVtbl->TranslateAddress(prov, ai->ai_addr, &devaddr); + if (SUCCEEDED(hr) && (ai->ai_addrlen <= addr_len) && (index-- == 0)) { + memcpy(addr, ai->ai_addr, ai->ai_addrlen); + goto free; + } + } + hr = ENODEV; + +free: + freeaddrinfo(res); +release: + prov->lpVtbl->Release(prov); + return hr; +} + +#else // _WIN64 || WIN32 + +/* Get IP address using network device name */ +int getipaddr_netdev(char *name, char *addr, int addr_len) +{ + struct ifreq ifr; + int skfd, ret, len; + + /* Fill in the structure */ + snprintf(ifr.ifr_name, IFNAMSIZ, "%s", name); + ifr.ifr_hwaddr.sa_family = ARPHRD_INFINIBAND; + + /* Create a socket fd */ + skfd = socket(PF_INET, SOCK_STREAM, 0); + ret = ioctl(skfd, SIOCGIFADDR, &ifr); + if (ret) + goto bail; + + switch (ifr.ifr_addr.sa_family) { +#ifdef AF_INET6 + case AF_INET6: + len = sizeof(struct sockaddr_in6); + break; +#endif + case AF_INET: + default: + len = sizeof(struct sockaddr); + break; + } + + if (len <= addr_len) + memcpy(addr, &ifr.ifr_addr, len); + else + ret = EINVAL; + + bail: + close(skfd); + return ret; +} +#endif + +enum ibv_mtu dapl_ib_mtu(int mtu) +{ + switch (mtu) { + case 256: + return IBV_MTU_256; + case 512: + return IBV_MTU_512; + case 1024: + return IBV_MTU_1024; + case 2048: + return IBV_MTU_2048; + case 4096: + return IBV_MTU_4096; + default: + return IBV_MTU_1024; + } +} + +char *dapl_ib_mtu_str(enum ibv_mtu mtu) +{ + switch (mtu) { + case IBV_MTU_256: + return "256"; + case IBV_MTU_512: + return "512"; + case IBV_MTU_1024: + return "1024"; + case IBV_MTU_2048: + return "2048"; + case IBV_MTU_4096: + return "4096"; + default: + return "1024"; + } +} + +DAT_RETURN getlocalipaddr(char *addr, int addr_len) +{ + struct sockaddr_in *sin; + struct addrinfo *res, hint, *ai; + int ret; + char hostname[256]; + char *netdev = getenv("DAPL_SCM_NETDEV"); + + /* use provided netdev instead of default hostname */ + if (netdev != NULL) { + ret = getipaddr_netdev(netdev, addr, addr_len); + if (ret) { + dapl_log(DAPL_DBG_TYPE_ERR, + " getlocalipaddr: DAPL_SCM_NETDEV provided %s" + " but not configured on system? ERR = %s\n", + netdev, strerror(ret)); + return dapl_convert_errno(ret, "getlocalipaddr"); + } else + return DAT_SUCCESS; + } + + if (addr_len < sizeof(*sin)) { + return DAT_INTERNAL_ERROR; + } + + ret = gethostname(hostname, 256); + if (ret) + return dapl_convert_errno(ret, "gethostname"); + + memset(&hint, 0, sizeof hint); + hint.ai_flags = AI_PASSIVE; + hint.ai_family = AF_INET; + hint.ai_socktype = SOCK_STREAM; + hint.ai_protocol = IPPROTO_TCP; + + ret = getaddrinfo(hostname, NULL, &hint, &res); + if (ret) { + dapl_log(DAPL_DBG_TYPE_ERR, + " getaddrinfo ERR: %d %s\n", ret, gai_strerror(ret)); + return DAT_INVALID_ADDRESS; + } + + ret = DAT_INVALID_ADDRESS; + for (ai = res; ai; ai = ai->ai_next) { + sin = (struct sockaddr_in *)ai->ai_addr; + if (*((uint32_t *) & sin->sin_addr) != htonl(0x7f000001)) { + *((struct sockaddr_in *)addr) = *sin; + ret = DAT_SUCCESS; + break; + } + } + + freeaddrinfo(res); + return ret; +} + +/* + * dapls_ib_query_hca + * + * Query the hca attribute + * + * Input: + * hca_handl hca handle + * ia_attr attribute of the ia + * ep_attr attribute of the ep + * ip_addr ip address of DET NIC + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + */ + +DAT_RETURN dapls_ib_query_hca(IN DAPL_HCA * hca_ptr, + OUT DAT_IA_ATTR * ia_attr, + OUT DAT_EP_ATTR * ep_attr, + OUT DAT_SOCK_ADDR6 * ip_addr) +{ + struct ibv_device_attr dev_attr; + struct ibv_port_attr port_attr; + + if (hca_ptr->ib_hca_handle == NULL) { + dapl_dbg_log(DAPL_DBG_TYPE_ERR, " query_hca: BAD handle\n"); + return (DAT_INVALID_HANDLE); + } + + /* local IP address of device, set during ia_open */ + if (ip_addr != NULL) + memcpy(ip_addr, &hca_ptr->hca_address, sizeof(DAT_SOCK_ADDR6)); + + if (ia_attr == NULL && ep_attr == NULL) + return DAT_SUCCESS; + + /* query verbs for this device and port attributes */ + if (ibv_query_device(hca_ptr->ib_hca_handle, &dev_attr) || + ibv_query_port(hca_ptr->ib_hca_handle, + hca_ptr->port_num, &port_attr)) + return (dapl_convert_errno(errno, "ib_query_hca")); + + if (ia_attr != NULL) { + (void)dapl_os_memzero(ia_attr, sizeof(*ia_attr)); + ia_attr->adapter_name[DAT_NAME_MAX_LENGTH - 1] = '\0'; + ia_attr->vendor_name[DAT_NAME_MAX_LENGTH - 1] = '\0'; + ia_attr->ia_address_ptr = + (DAT_IA_ADDRESS_PTR) & hca_ptr->hca_address; + + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, + " query_hca: %s %s \n", + ibv_get_device_name(hca_ptr->ib_trans.ib_dev), + inet_ntoa(((struct sockaddr_in *) + &hca_ptr->hca_address)->sin_addr)); + + ia_attr->hardware_version_major = dev_attr.hw_ver; + /* ia_attr->hardware_version_minor = dev_attr.fw_ver; */ + ia_attr->max_eps = dev_attr.max_qp; + ia_attr->max_dto_per_ep = dev_attr.max_qp_wr; + ia_attr->max_rdma_read_in = dev_attr.max_qp_rd_atom; + ia_attr->max_rdma_read_out = dev_attr.max_qp_init_rd_atom; + ia_attr->max_rdma_read_per_ep_in = dev_attr.max_qp_rd_atom; + ia_attr->max_rdma_read_per_ep_out = + dev_attr.max_qp_init_rd_atom; + ia_attr->max_rdma_read_per_ep_in_guaranteed = DAT_TRUE; + ia_attr->max_rdma_read_per_ep_out_guaranteed = DAT_TRUE; + ia_attr->max_evds = dev_attr.max_cq; + ia_attr->max_evd_qlen = dev_attr.max_cqe; + ia_attr->max_iov_segments_per_dto = dev_attr.max_sge; + ia_attr->max_lmrs = dev_attr.max_mr; + /* 32bit attribute from 64bit, 4G-1 limit, DAT v2 needs fix */ + ia_attr->max_lmr_block_size = + (dev_attr.max_mr_size >> 32) ? ~0 : dev_attr.max_mr_size; + ia_attr->max_rmrs = dev_attr.max_mw; + ia_attr->max_lmr_virtual_address = dev_attr.max_mr_size; + ia_attr->max_rmr_target_address = dev_attr.max_mr_size; + ia_attr->max_pzs = dev_attr.max_pd; + ia_attr->max_message_size = port_attr.max_msg_sz; + ia_attr->max_rdma_size = port_attr.max_msg_sz; + /* iWARP spec. - 1 sge for RDMA reads */ + if (hca_ptr->ib_hca_handle->device->transport_type + == IBV_TRANSPORT_IWARP) + ia_attr->max_iov_segments_per_rdma_read = 1; + else + ia_attr->max_iov_segments_per_rdma_read = + dev_attr.max_sge; + ia_attr->max_iov_segments_per_rdma_write = dev_attr.max_sge; + ia_attr->num_transport_attr = 0; + ia_attr->transport_attr = NULL; + ia_attr->num_vendor_attr = 0; + ia_attr->vendor_attr = NULL; +#ifdef DAT_EXTENSIONS + ia_attr->extension_supported = DAT_EXTENSION_IB; + ia_attr->extension_version = DAT_IB_EXTENSION_VERSION; +#endif + /* save key device attributes for CM exchange */ + hca_ptr->ib_trans.rd_atom_in = dev_attr.max_qp_rd_atom; + hca_ptr->ib_trans.rd_atom_out = dev_attr.max_qp_init_rd_atom; + + hca_ptr->ib_trans.mtu = DAPL_MIN(port_attr.active_mtu, + hca_ptr->ib_trans.mtu); + hca_ptr->ib_trans.ack_timer = + DAPL_MAX(dev_attr.local_ca_ack_delay, + hca_ptr->ib_trans.ack_timer); + + /* set MTU in transport specific named attribute */ + hca_ptr->ib_trans.named_attr.name = "DAT_IB_TRANSPORT_MTU"; + hca_ptr->ib_trans.named_attr.value = + dapl_ib_mtu_str(hca_ptr->ib_trans.mtu); + + if (hca_ptr->ib_hca_handle->device->transport_type != IBV_TRANSPORT_IB) + goto skip_ib; + + /* set SL, PKEY values, defaults = 0 */ + hca_ptr->ib_trans.pkey_idx = 0; + hca_ptr->ib_trans.pkey = htons(dapl_os_get_env_val("DAPL_IB_PKEY", 0)); + hca_ptr->ib_trans.sl = dapl_os_get_env_val("DAPL_IB_SL", 0); + + /* index provided, get pkey; pkey provided, get index */ + if (hca_ptr->ib_trans.pkey) { + int i; uint16_t pkey = 0; + for (i=0; i < dev_attr.max_pkeys; i++) { + if (ibv_query_pkey(hca_ptr->ib_hca_handle, + hca_ptr->port_num, + i, &pkey)) { + i = dev_attr.max_pkeys; + break; + } + if (pkey == hca_ptr->ib_trans.pkey) { + hca_ptr->ib_trans.pkey_idx = i; + break; + } + } + if (i == dev_attr.max_pkeys) { + dapl_log(DAPL_DBG_TYPE_ERR, + " ERR: new pkey(0x%x), query (%s)" + " err or key !found, using default pkey_idx=0\n", + ntohs(hca_ptr->ib_trans.pkey), strerror(errno)); + } + } +skip_ib: + +#ifdef DEFINE_ATTR_LINK_LAYER +#ifndef _OPENIB_CMA_ + if (port_attr.link_layer == IBV_LINK_LAYER_ETHERNET) + hca_ptr->ib_trans.global = 1; + + dapl_log(DAPL_DBG_TYPE_UTIL, + " query_hca: port.link_layer = 0x%x\n", + port_attr.link_layer); +#endif +#endif + dapl_log(DAPL_DBG_TYPE_UTIL, + " query_hca: (%x.%x) eps %d, sz %d evds %d," + " sz %d mtu %d - pkey %x p_idx %d sl %d\n", + ia_attr->hardware_version_major, + ia_attr->hardware_version_minor, + ia_attr->max_eps, ia_attr->max_dto_per_ep, + ia_attr->max_evds, ia_attr->max_evd_qlen, + 128 << hca_ptr->ib_trans.mtu, + ntohs(hca_ptr->ib_trans.pkey), + hca_ptr->ib_trans.pkey_idx, + hca_ptr->ib_trans.sl); + + dapl_log(DAPL_DBG_TYPE_UTIL, + " query_hca: msg %llu rdma %llu iov %d lmr %d rmr %d" + " ack_time %d mr %u\n", + ia_attr->max_message_size, ia_attr->max_rdma_size, + ia_attr->max_iov_segments_per_dto, + ia_attr->max_lmrs, ia_attr->max_rmrs, + hca_ptr->ib_trans.ack_timer, + ia_attr->max_lmr_block_size); + } + + if (ep_attr != NULL) { + (void)dapl_os_memzero(ep_attr, sizeof(*ep_attr)); + ep_attr->max_message_size = port_attr.max_msg_sz; + ep_attr->max_rdma_size = port_attr.max_msg_sz; + ep_attr->max_recv_dtos = dev_attr.max_qp_wr; + ep_attr->max_request_dtos = dev_attr.max_qp_wr; + ep_attr->max_recv_iov = dev_attr.max_sge; + ep_attr->max_request_iov = dev_attr.max_sge; + ep_attr->max_rdma_read_in = dev_attr.max_qp_rd_atom; + ep_attr->max_rdma_read_out = dev_attr.max_qp_init_rd_atom; + ep_attr->max_rdma_read_iov = dev_attr.max_sge; + ep_attr->max_rdma_write_iov = dev_attr.max_sge; + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, + " query_hca: MAX msg %llu mtu %d qsz %d iov %d" + " rdma i%d,o%d\n", + ep_attr->max_message_size, + 128 << hca_ptr->ib_trans.mtu, + ep_attr->max_recv_dtos, + ep_attr->max_recv_iov, + ep_attr->max_rdma_read_in, + ep_attr->max_rdma_read_out); + } + return DAT_SUCCESS; +} + +/* + * dapls_ib_setup_async_callback + * + * Set up an asynchronous callbacks of various kinds + * + * Input: + * ia_handle IA handle + * handler_type type of handler to set up + * callback_handle handle param for completion callbacks + * callback callback routine pointer + * context argument for callback routine + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + * + */ +DAT_RETURN dapls_ib_setup_async_callback(IN DAPL_IA * ia_ptr, + IN DAPL_ASYNC_HANDLER_TYPE + handler_type, IN DAPL_EVD * evd_ptr, + IN ib_async_handler_t callback, + IN void *context) +{ + ib_hca_transport_t *hca_ptr; + + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, + " setup_async_cb: ia %p type %d handle %p cb %p ctx %p\n", + ia_ptr, handler_type, evd_ptr, callback, context); + + hca_ptr = &ia_ptr->hca_ptr->ib_trans; + switch (handler_type) { + case DAPL_ASYNC_UNAFILIATED: + hca_ptr->async_unafiliated = (ib_async_handler_t) callback; + hca_ptr->async_un_ctx = context; + break; + case DAPL_ASYNC_CQ_ERROR: + hca_ptr->async_cq_error = (ib_async_cq_handler_t) callback; + break; + case DAPL_ASYNC_CQ_COMPLETION: + hca_ptr->async_cq = (ib_async_dto_handler_t) callback; + break; + case DAPL_ASYNC_QP_ERROR: + hca_ptr->async_qp_error = (ib_async_qp_handler_t) callback; + break; + default: + break; + } + return DAT_SUCCESS; +} + +void dapli_async_event_cb(struct _ib_hca_transport *hca) +{ + struct ibv_async_event event; + + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, " async_event(%p)\n", hca); + + if (hca->destroy) + return; + + if (!ibv_get_async_event(hca->ib_ctx, &event)) { + + switch (event.event_type) { + case IBV_EVENT_CQ_ERR: + { + struct dapl_ep *evd_ptr = + event.element.cq->cq_context; + + dapl_log(DAPL_DBG_TYPE_ERR, + "dapl async_event CQ (%p) ERR %d\n", + evd_ptr, event.event_type); + + /* report up if async callback still setup */ + if (hca->async_cq_error) + hca->async_cq_error(hca->ib_ctx, + event.element.cq, + &event, + (void *)evd_ptr); + break; + } + case IBV_EVENT_COMM_EST: + { + /* Received msgs on connected QP before RTU */ + dapl_log(DAPL_DBG_TYPE_UTIL, + " async_event COMM_EST(%p) rdata beat RTU\n", + event.element.qp); + + break; + } + case IBV_EVENT_QP_FATAL: + case IBV_EVENT_QP_REQ_ERR: + case IBV_EVENT_QP_ACCESS_ERR: + case IBV_EVENT_QP_LAST_WQE_REACHED: + case IBV_EVENT_SRQ_ERR: + case IBV_EVENT_SRQ_LIMIT_REACHED: + case IBV_EVENT_SQ_DRAINED: + { + struct dapl_ep *ep_ptr = + event.element.qp->qp_context; + + dapl_log(DAPL_DBG_TYPE_ERR, + "dapl async_event QP (%p) ERR %d\n", + ep_ptr, event.event_type); + + /* report up if async callback still setup */ + if (hca->async_qp_error) + hca->async_qp_error(hca->ib_ctx, + ep_ptr->qp_handle, + &event, + (void *)ep_ptr); + break; + } + case IBV_EVENT_PATH_MIG: + case IBV_EVENT_PATH_MIG_ERR: + case IBV_EVENT_DEVICE_FATAL: + case IBV_EVENT_PORT_ACTIVE: + case IBV_EVENT_PORT_ERR: + case IBV_EVENT_LID_CHANGE: + case IBV_EVENT_PKEY_CHANGE: + case IBV_EVENT_SM_CHANGE: + { + dapl_log(DAPL_DBG_TYPE_WARN, + "dapl async_event: DEV ERR %d\n", + event.event_type); + + /* report up if async callback still setup */ + if (hca->async_unafiliated) + hca->async_unafiliated(hca->ib_ctx, + &event, + hca->async_un_ctx); + break; + } + case IBV_EVENT_CLIENT_REREGISTER: + /* no need to report this event this time */ + dapl_log(DAPL_DBG_TYPE_UTIL, + " async_event: IBV_CLIENT_REREGISTER\n"); + break; + + default: + dapl_log(DAPL_DBG_TYPE_WARN, + "dapl async_event: %d UNKNOWN\n", + event.event_type); + break; + + } + ibv_ack_async_event(&event); + } +} + +/* + * dapls_set_provider_specific_attr + * + * Input: + * attr_ptr Pointer provider specific attributes + * + * Output: + * none + * + * Returns: + * void + */ +DAT_NAMED_ATTR ib_attrs[] = { + { + "DAT_IB_TRANSPORT_MTU", "2048"} + , +#ifdef DAT_EXTENSIONS + { + "DAT_EXTENSION_INTERFACE", "TRUE"} + , + { + DAT_IB_ATTR_FETCH_AND_ADD, "TRUE"} + , + { + DAT_IB_ATTR_CMP_AND_SWAP, "TRUE"} + , + { + DAT_IB_ATTR_IMMED_DATA, "TRUE"} + , +#ifndef _OPENIB_CMA_ + { + DAT_IB_ATTR_UD, "TRUE"} + , +#endif +#ifdef DAPL_COUNTERS + { + DAT_ATTR_COUNTERS, "TRUE"} + , +#endif /* DAPL_COUNTERS */ +#endif +}; + +#define SPEC_ATTR_SIZE( x ) (sizeof( x ) / sizeof( DAT_NAMED_ATTR)) + +void dapls_query_provider_specific_attr(IN DAPL_IA * ia_ptr, + IN DAT_PROVIDER_ATTR * attr_ptr) +{ + attr_ptr->num_provider_specific_attr = SPEC_ATTR_SIZE(ib_attrs); + attr_ptr->provider_specific_attr = ib_attrs; + + /* set MTU to actual settings */ + ib_attrs[0].value = ia_ptr->hca_ptr->ib_trans.named_attr.value; +} + +/* + * Map all socket CM event codes to the DAT equivelent. Common to all providers + */ +#define DAPL_IB_EVENT_CNT 13 + +static struct ib_cm_event_map { + const ib_cm_events_t ib_cm_event; + DAT_EVENT_NUMBER dat_event_num; +} ib_cm_event_map[DAPL_IB_EVENT_CNT] = { +/* 00 */ {IB_CME_CONNECTED, + DAT_CONNECTION_EVENT_ESTABLISHED}, +/* 01 */ {IB_CME_DISCONNECTED, + DAT_CONNECTION_EVENT_DISCONNECTED}, +/* 02 */ {IB_CME_DISCONNECTED_ON_LINK_DOWN, + DAT_CONNECTION_EVENT_DISCONNECTED}, +/* 03 */ {IB_CME_CONNECTION_REQUEST_PENDING, + DAT_CONNECTION_REQUEST_EVENT}, +/* 04 */ {IB_CME_CONNECTION_REQUEST_PENDING_PRIVATE_DATA, + DAT_CONNECTION_REQUEST_EVENT}, +/* 05 */ {IB_CME_CONNECTION_REQUEST_ACKED, + DAT_CONNECTION_EVENT_ESTABLISHED}, +/* 06 */ {IB_CME_DESTINATION_REJECT, + DAT_CONNECTION_EVENT_NON_PEER_REJECTED}, +/* 07 */ {IB_CME_DESTINATION_REJECT_PRIVATE_DATA, + DAT_CONNECTION_EVENT_PEER_REJECTED}, +/* 08 */ {IB_CME_DESTINATION_UNREACHABLE, + DAT_CONNECTION_EVENT_UNREACHABLE}, +/* 09 */ {IB_CME_TOO_MANY_CONNECTION_REQUESTS, + DAT_CONNECTION_EVENT_NON_PEER_REJECTED}, +/* 10 */ {IB_CME_BROKEN, + DAT_CONNECTION_EVENT_BROKEN}, +/* 11 */ {IB_CME_TIMEOUT, + DAT_CONNECTION_EVENT_TIMED_OUT}, +/* 12 */ {IB_CME_LOCAL_FAILURE, /* always last */ + DAT_CONNECTION_EVENT_BROKEN} +}; + +/* + * dapls_ib_get_cm_event + * + * Return a DAT connection event given a provider CM event. + * + * Input: + * dat_event_num DAT event we need an equivelent CM event for + * + * Output: + * none + * + * Returns: + * ib_cm_event of translated DAPL value + */ +DAT_EVENT_NUMBER +dapls_ib_get_dat_event(IN const ib_cm_events_t ib_cm_event, + IN DAT_BOOLEAN active) +{ + DAT_EVENT_NUMBER dat_event_num; + int i; + + active = active; + + if (ib_cm_event > IB_CME_LOCAL_FAILURE) + return (DAT_EVENT_NUMBER) 0; + + dat_event_num = 0; + for (i = 0; i < DAPL_IB_EVENT_CNT; i++) { + if (ib_cm_event == ib_cm_event_map[i].ib_cm_event) { + dat_event_num = ib_cm_event_map[i].dat_event_num; + break; + } + } + dapl_dbg_log(DAPL_DBG_TYPE_CALLBACK, + "dapls_ib_get_dat_event: event translate(%s) ib=0x%x dat=0x%x\n", + active ? "active" : "passive", ib_cm_event, dat_event_num); + + return dat_event_num; +} + +/* + * dapls_ib_get_dat_event + * + * Return a DAT connection event given a provider CM event. + * + * Input: + * ib_cm_event event provided to the dapl callback routine + * active switch indicating active or passive connection + * + * Output: + * none + * + * Returns: + * DAT_EVENT_NUMBER of translated provider value + */ +ib_cm_events_t dapls_ib_get_cm_event(IN DAT_EVENT_NUMBER dat_event_num) +{ + ib_cm_events_t ib_cm_event; + int i; + + ib_cm_event = 0; + for (i = 0; i < DAPL_IB_EVENT_CNT; i++) { + if (dat_event_num == ib_cm_event_map[i].dat_event_num) { + ib_cm_event = ib_cm_event_map[i].ib_cm_event; + break; + } + } + return ib_cm_event; +} diff --git a/branches/WOF2-3/ulp/dapl2/dapl/openib_scm/SOURCES b/branches/WOF2-3/ulp/dapl2/dapl/openib_scm/SOURCES new file mode 100644 index 00000000..d4470dee --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/openib_scm/SOURCES @@ -0,0 +1,52 @@ +!if $(FREEBUILD) +TARGETNAME=dapl2-ofa-scm +!else +TARGETNAME=dapl2-ofa-scmd +!endif + +TARGETPATH = ..\..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = DYNLINK +DLLENTRY = _DllMainCRTStartup + +!if $(_NT_TOOLS_VERSION) == 0x700 +DLLDEF=$O\udapl_ofa_scm_exports.def +!else +DLLDEF=$(OBJ_PATH)\$O\udapl_ofa_scm_exports.def +!endif + +USE_MSVCRT = 1 + +SOURCES = \ + udapl.rc \ + ..\dapl_common_src.c \ + ..\dapl_udapl_src.c \ + ..\openib_common.c \ + device.c \ + cm.c + +INCLUDES = ..\include;..\openib_common\;..\common;windows;..\..\dat\include;\ + ..\..\dat\udat\windows;..\udapl\windows;..\..\..\..\inc\user\linux;\ + ..\..\..\..\inc;..\..\..\..\inc\user;..\..\..\libibverbs\include + +DAPL_OPTS = -DEXPORT_DAPL_SYMBOLS -DDAT_EXTENSIONS -DSOCK_CM -DOPENIB -DCQ_WAIT_OBJECT + +USER_C_FLAGS = $(USER_C_FLAGS) $(DAPL_OPTS) + +!if !$(FREEBUILD) +USER_C_FLAGS = $(USER_C_FLAGS) -DDAPL_DBG +!endif + +TARGETLIBS= \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\dat2.lib \ + $(TARGETPATH)\*\winverbs.lib \ + $(TARGETPATH)\*\libibverbs.lib +!else + $(TARGETPATH)\*\dat2d.lib \ + $(TARGETPATH)\*\winverbsd.lib \ + $(TARGETPATH)\*\libibverbsd.lib +!endif + +MSC_WARNING_LEVEL = /W1 /wd4113 diff --git a/branches/WOF2-3/ulp/dapl2/dapl/openib_scm/cm.c b/branches/WOF2-3/ulp/dapl2/dapl/openib_scm/cm.c new file mode 100644 index 00000000..24065cef --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/openib_scm/cm.c @@ -0,0 +1,1927 @@ +/* + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/*************************************************************************** + * + * Module: uDAPL + * + * Filename: dapl_ib_cm.c + * + * Author: Arlin Davis + * + * Created: 3/10/2005 + * + * Description: + * + * The uDAPL openib provider - connection management + * + **************************************************************************** + * Source Control System Information + * + * $Id: $ + * + * Copyright (c) 2005 Intel Corporation. All rights reserved. + * + **************************************************************************/ + +#if defined(_WIN32) +#define FD_SETSIZE 1024 +#define DAPL_FD_SETSIZE FD_SETSIZE +#endif + +#include "dapl.h" +#include "dapl_adapter_util.h" +#include "dapl_evd_util.h" +#include "dapl_cr_util.h" +#include "dapl_name_service.h" +#include "dapl_ib_util.h" +#include "dapl_ep_util.h" +#include "dapl_osd.h" + +/* forward declarations */ +static DAT_RETURN +dapli_socket_connect(DAPL_EP * ep_ptr, + DAT_IA_ADDRESS_PTR r_addr, + DAT_CONN_QUAL r_qual, DAT_COUNT p_size, DAT_PVOID p_data); + +#ifdef DAPL_DBG +/* Check for EP linking to IA and proper connect state */ +void dapli_ep_check(DAPL_EP *ep) +{ + DAPL_IA *ia_ptr = ep->header.owner_ia; + DAPL_EP *ep_ptr, *next_ep_ptr; + int found = 0; + + dapl_os_lock(&ia_ptr->header.lock); + ep_ptr = (dapl_llist_is_empty (&ia_ptr->ep_list_head) + ? NULL : dapl_llist_peek_head (&ia_ptr->ep_list_head)); + + while (ep_ptr != NULL) { + next_ep_ptr = + dapl_llist_next_entry(&ia_ptr->ep_list_head, + &ep_ptr->header.ia_list_entry); + if (ep == ep_ptr) { + found++; + if ((ep->cr_ptr && ep->param.ep_state + != DAT_EP_STATE_COMPLETION_PENDING) || + (!ep->cr_ptr && ep->param.ep_state + != DAT_EP_STATE_ACTIVE_CONNECTION_PENDING)) + goto err; + else + goto match; + } + ep_ptr = next_ep_ptr; + } +err: + dapl_log(DAPL_DBG_TYPE_ERR, + " dapli_ep_check ERR: %s %s ep=%p state=%d magic=0x%x\n", + ep->cr_ptr ? "PASSIVE":"ACTIVE", + found ? "WRONG_STATE":"NOT_FOUND" , + ep, ep->param.ep_state, ep->header.magic); +match: + dapl_os_unlock(&ia_ptr->header.lock); + return; +} +#else +#define dapli_ep_check(ep) +#endif + +#if defined(_WIN32) || defined(_WIN64) +enum DAPL_FD_EVENTS { + DAPL_FD_READ = 0x1, + DAPL_FD_WRITE = 0x2, + DAPL_FD_ERROR = 0x4 +}; + +static int dapl_config_socket(DAPL_SOCKET s) +{ + unsigned long nonblocking = 1; + int ret, opt = 1; + + ret = ioctlsocket(s, FIONBIO, &nonblocking); + + /* no delay for small packets */ + if (!ret) + ret = setsockopt(s, IPPROTO_TCP, TCP_NODELAY, + (char *)&opt, sizeof(opt)); + return ret; +} + +static int dapl_connect_socket(DAPL_SOCKET s, struct sockaddr *addr, + int addrlen) +{ + int err; + + err = connect(s, addr, addrlen); + if (err == SOCKET_ERROR) + err = WSAGetLastError(); + return (err == WSAEWOULDBLOCK) ? EAGAIN : err; +} + +struct dapl_fd_set { + struct fd_set set[3]; +}; + +static struct dapl_fd_set *dapl_alloc_fd_set(void) +{ + return dapl_os_alloc(sizeof(struct dapl_fd_set)); +} + +static void dapl_fd_zero(struct dapl_fd_set *set) +{ + FD_ZERO(&set->set[0]); + FD_ZERO(&set->set[1]); + FD_ZERO(&set->set[2]); +} + +static int dapl_fd_set(DAPL_SOCKET s, struct dapl_fd_set *set, + enum DAPL_FD_EVENTS event) +{ + FD_SET(s, &set->set[(event == DAPL_FD_READ) ? 0 : 1]); + FD_SET(s, &set->set[2]); + return 0; +} + +static enum DAPL_FD_EVENTS dapl_poll(DAPL_SOCKET s, enum DAPL_FD_EVENTS event) +{ + struct fd_set rw_fds; + struct fd_set err_fds; + struct timeval tv; + int ret; + + FD_ZERO(&rw_fds); + FD_ZERO(&err_fds); + FD_SET(s, &rw_fds); + FD_SET(s, &err_fds); + + tv.tv_sec = 0; + tv.tv_usec = 0; + + if (event == DAPL_FD_READ) + ret = select(1, &rw_fds, NULL, &err_fds, &tv); + else + ret = select(1, NULL, &rw_fds, &err_fds, &tv); + + if (ret == 0) + return 0; + else if (ret == SOCKET_ERROR) + return DAPL_FD_ERROR; + else if (FD_ISSET(s, &rw_fds)) + return event; + else + return DAPL_FD_ERROR; +} + +static int dapl_select(struct dapl_fd_set *set) +{ + int ret; + + dapl_dbg_log(DAPL_DBG_TYPE_CM, " dapl_select: sleep\n"); + ret = select(0, &set->set[0], &set->set[1], &set->set[2], NULL); + dapl_dbg_log(DAPL_DBG_TYPE_CM, " dapl_select: wakeup\n"); + + if (ret == SOCKET_ERROR) + dapl_dbg_log(DAPL_DBG_TYPE_THREAD, + " dapl_select: error 0x%x\n", WSAGetLastError()); + + return ret; +} + +static int dapl_socket_errno(void) +{ + int err; + + err = WSAGetLastError(); + switch (err) { + case WSAEACCES: + case WSAEADDRINUSE: + return EADDRINUSE; + case WSAECONNRESET: + return ECONNRESET; + default: + return err; + } +} +#else // _WIN32 || _WIN64 +enum DAPL_FD_EVENTS { + DAPL_FD_READ = POLLIN, + DAPL_FD_WRITE = POLLOUT, + DAPL_FD_ERROR = POLLERR +}; + +static int dapl_config_socket(DAPL_SOCKET s) +{ + int ret, opt = 1; + + /* non-blocking */ + ret = fcntl(s, F_GETFL); + if (ret >= 0) + ret = fcntl(s, F_SETFL, ret | O_NONBLOCK); + + /* no delay for small packets */ + if (!ret) + ret = setsockopt(s, IPPROTO_TCP, TCP_NODELAY, + (char *)&opt, sizeof(opt)); + return ret; +} + +static int dapl_connect_socket(DAPL_SOCKET s, struct sockaddr *addr, + int addrlen) +{ + int ret; + + ret = connect(s, addr, addrlen); + + return (errno == EINPROGRESS) ? EAGAIN : ret; +} + +struct dapl_fd_set { + int index; + struct pollfd set[DAPL_FD_SETSIZE]; +}; + +static struct dapl_fd_set *dapl_alloc_fd_set(void) +{ + return dapl_os_alloc(sizeof(struct dapl_fd_set)); +} + +static void dapl_fd_zero(struct dapl_fd_set *set) +{ + set->index = 0; +} + +static int dapl_fd_set(DAPL_SOCKET s, struct dapl_fd_set *set, + enum DAPL_FD_EVENTS event) +{ + if (set->index == DAPL_FD_SETSIZE - 1) { + dapl_log(DAPL_DBG_TYPE_ERR, + "SCM ERR: cm_thread exceeded FD_SETSIZE %d\n", + set->index + 1); + return -1; + } + + set->set[set->index].fd = s; + set->set[set->index].revents = 0; + set->set[set->index++].events = event; + return 0; +} + +static enum DAPL_FD_EVENTS dapl_poll(DAPL_SOCKET s, enum DAPL_FD_EVENTS event) +{ + struct pollfd fds; + int ret; + + fds.fd = s; + fds.events = event; + fds.revents = 0; + ret = poll(&fds, 1, 0); + dapl_log(DAPL_DBG_TYPE_THREAD, " dapl_poll: fd=%d ret=%d, evnts=0x%x\n", + s, ret, fds.revents); + if (ret == 0) + return 0; + else if (ret < 0 || (fds.revents & (POLLERR | POLLHUP | POLLNVAL))) + return DAPL_FD_ERROR; + else + return event; +} + +static int dapl_select(struct dapl_fd_set *set) +{ + int ret; + + dapl_dbg_log(DAPL_DBG_TYPE_THREAD, " dapl_select: sleep, fds=%d\n", set->index); + ret = poll(set->set, set->index, -1); + dapl_dbg_log(DAPL_DBG_TYPE_THREAD, " dapl_select: wakeup, ret=0x%x\n", ret); + return ret; +} + +#define dapl_socket_errno() errno +#endif + +static void dapli_cm_thread_signal(dp_ib_cm_handle_t cm_ptr) +{ + if (cm_ptr->hca) + send(cm_ptr->hca->ib_trans.scm[1], "w", sizeof "w", 0); +} + +static void dapli_cm_free(dp_ib_cm_handle_t cm_ptr) +{ + dapl_os_lock(&cm_ptr->lock); + cm_ptr->state = DCM_FREE; + dapl_os_unlock(&cm_ptr->lock); + dapli_cm_thread_signal(cm_ptr); +} + +static void dapli_cm_dealloc(dp_ib_cm_handle_t cm_ptr) +{ + dapl_os_assert(!cm_ptr->ref_count); + + if (cm_ptr->socket != DAPL_INVALID_SOCKET) { + shutdown(cm_ptr->socket, SHUT_RDWR); + closesocket(cm_ptr->socket); + } + if (cm_ptr->ah) + ibv_destroy_ah(cm_ptr->ah); + + dapl_os_lock_destroy(&cm_ptr->lock); + dapl_os_wait_object_destroy(&cm_ptr->event); + dapl_os_free(cm_ptr, sizeof(*cm_ptr)); +} + +void dapls_cm_acquire(dp_ib_cm_handle_t cm_ptr) +{ + dapl_os_lock(&cm_ptr->lock); + cm_ptr->ref_count++; + dapl_os_unlock(&cm_ptr->lock); +} + +void dapls_cm_release(dp_ib_cm_handle_t cm_ptr) +{ + dapl_os_lock(&cm_ptr->lock); + cm_ptr->ref_count--; + if (cm_ptr->ref_count) { + dapl_os_unlock(&cm_ptr->lock); + return; + } + dapl_os_unlock(&cm_ptr->lock); + dapli_cm_dealloc(cm_ptr); +} + +static dp_ib_cm_handle_t dapli_cm_alloc(DAPL_EP *ep_ptr) +{ + dp_ib_cm_handle_t cm_ptr; + + /* Allocate CM, init lock, and initialize */ + if ((cm_ptr = dapl_os_alloc(sizeof(*cm_ptr))) == NULL) + return NULL; + + (void)dapl_os_memzero(cm_ptr, sizeof(*cm_ptr)); + if (dapl_os_lock_init(&cm_ptr->lock)) + goto bail; + + if (dapl_os_wait_object_init(&cm_ptr->event)) { + dapl_os_lock_destroy(&cm_ptr->lock); + goto bail; + } + dapl_llist_init_entry((DAPL_LLIST_ENTRY *)&cm_ptr->list_entry); + dapl_llist_init_entry((DAPL_LLIST_ENTRY *)&cm_ptr->local_entry); + + cm_ptr->msg.ver = htons(DCM_VER); + cm_ptr->socket = DAPL_INVALID_SOCKET; + dapls_cm_acquire(cm_ptr); + + /* Link EP and CM */ + if (ep_ptr != NULL) { + dapl_ep_link_cm(ep_ptr, cm_ptr); /* ref++ */ + cm_ptr->ep = ep_ptr; + cm_ptr->hca = ((DAPL_IA *)ep_ptr->param.ia_handle)->hca_ptr; + } + return cm_ptr; +bail: + dapl_os_free(cm_ptr, sizeof(*cm_ptr)); + return NULL; +} + +/* queue socket for processing CM work */ +static void dapli_cm_queue(dp_ib_cm_handle_t cm_ptr) +{ + /* add to work queue for cr thread processing */ + dapl_os_lock(&cm_ptr->hca->ib_trans.lock); + dapls_cm_acquire(cm_ptr); + dapl_llist_add_tail(&cm_ptr->hca->ib_trans.list, + (DAPL_LLIST_ENTRY *)&cm_ptr->local_entry, cm_ptr); + dapl_os_unlock(&cm_ptr->hca->ib_trans.lock); + dapli_cm_thread_signal(cm_ptr); +} + +/* called with local LIST lock */ +static void dapli_cm_dequeue(dp_ib_cm_handle_t cm_ptr) +{ + /* Remove from work queue, cr thread processing */ + dapl_llist_remove_entry(&cm_ptr->hca->ib_trans.list, + (DAPL_LLIST_ENTRY *)&cm_ptr->local_entry); + dapls_cm_release(cm_ptr); +} + +/* BLOCKING: called from dapl_ep_free, EP link will be last ref */ +void dapls_cm_free(dp_ib_cm_handle_t cm_ptr) +{ + dapl_log(DAPL_DBG_TYPE_CM, + " cm_free: cm %p %s ep %p refs=%d\n", + cm_ptr, dapl_cm_state_str(cm_ptr->state), + cm_ptr->ep, cm_ptr->ref_count); + + /* free from internal workq, wait until EP is last ref */ + dapl_os_lock(&cm_ptr->lock); + cm_ptr->state = DCM_FREE; + while (cm_ptr->ref_count != 1) { + dapli_cm_thread_signal(cm_ptr); + dapl_os_unlock(&cm_ptr->lock); + dapl_os_sleep_usec(10000); + dapl_os_lock(&cm_ptr->lock); + } + dapl_os_unlock(&cm_ptr->lock); + + /* unlink, dequeue from EP. Final ref so release will destroy */ + dapl_ep_unlink_cm(cm_ptr->ep, cm_ptr); +} + +/* + * ACTIVE/PASSIVE: called from CR thread or consumer via ep_disconnect + * or from ep_free. + */ +DAT_RETURN dapli_socket_disconnect(dp_ib_cm_handle_t cm_ptr) +{ + DAT_UINT32 disc_data = htonl(0xdead); + + dapl_os_lock(&cm_ptr->lock); + if (cm_ptr->state != DCM_CONNECTED || + cm_ptr->state == DCM_DISCONNECTED) { + dapl_os_unlock(&cm_ptr->lock); + return DAT_SUCCESS; + } + cm_ptr->state = DCM_DISCONNECTED; + dapl_os_unlock(&cm_ptr->lock); + + /* send disc date, close socket, schedule destroy */ + send(cm_ptr->socket, (char *)&disc_data, sizeof(disc_data), 0); + + /* disconnect events for RC's only */ + if (cm_ptr->ep->param.ep_attr.service_type == DAT_SERVICE_TYPE_RC) { + dapl_os_lock(&cm_ptr->ep->header.lock); + dapls_modify_qp_state(cm_ptr->ep->qp_handle, IBV_QPS_ERR, 0,0,0); + dapl_os_unlock(&cm_ptr->ep->header.lock); + if (cm_ptr->ep->cr_ptr) { + dapls_cr_callback(cm_ptr, + IB_CME_DISCONNECTED, + NULL, 0, cm_ptr->sp); + } else { + dapl_evd_connection_callback(cm_ptr, + IB_CME_DISCONNECTED, + NULL, 0, cm_ptr->ep); + } + } + + /* release from workq */ + dapli_cm_free(cm_ptr); + + /* scheduled destroy via disconnect clean in callback */ + return DAT_SUCCESS; +} + +/* + * ACTIVE: socket connected, send QP information to peer + */ +static void dapli_socket_connected(dp_ib_cm_handle_t cm_ptr, int err) +{ + int len, exp; + struct iovec iov[2]; + struct dapl_ep *ep_ptr = cm_ptr->ep; + + if (err) { + dapl_log(DAPL_DBG_TYPE_ERR, + " CONN_PENDING: %s ERR %s -> %s %d - %s\n", + err == -1 ? "POLL" : "SOCKOPT", + err == -1 ? strerror(dapl_socket_errno()) : strerror(err), + inet_ntoa(((struct sockaddr_in *) + &cm_ptr->addr)->sin_addr), + ntohs(((struct sockaddr_in *) + &cm_ptr->addr)->sin_port), + err == ETIMEDOUT ? "RETRYING...":"ABORTING"); + + /* retry a timeout */ + if (err == ETIMEDOUT) { + closesocket(cm_ptr->socket); + cm_ptr->socket = DAPL_INVALID_SOCKET; + dapli_socket_connect(cm_ptr->ep, (DAT_IA_ADDRESS_PTR)&cm_ptr->addr, + ntohs(((struct sockaddr_in *)&cm_ptr->addr)->sin_port) - 1000, + ntohs(cm_ptr->msg.p_size), &cm_ptr->msg.p_data); + dapl_ep_unlink_cm(cm_ptr->ep, cm_ptr); + dapli_cm_free(cm_ptr); + return; + } + + goto bail; + } + + dapl_os_lock(&cm_ptr->lock); + cm_ptr->state = DCM_REP_PENDING; + dapl_os_unlock(&cm_ptr->lock); + + /* send qp info and pdata to remote peer */ + exp = sizeof(ib_cm_msg_t) - DCM_MAX_PDATA_SIZE; + iov[0].iov_base = (void *)&cm_ptr->msg; + iov[0].iov_len = exp; + if (cm_ptr->msg.p_size) { + iov[1].iov_base = cm_ptr->msg.p_data; + iov[1].iov_len = ntohs(cm_ptr->msg.p_size); + len = writev(cm_ptr->socket, iov, 2); + } else { + len = writev(cm_ptr->socket, iov, 1); + } + + if (len != (exp + ntohs(cm_ptr->msg.p_size))) { + int err = dapl_socket_errno(); + dapl_log(DAPL_DBG_TYPE_ERR, + " CONN_PENDING len ERR 0x%x %s, wcnt=%d(%d) -> %s\n", + err, strerror(err), len, + exp + ntohs(cm_ptr->msg.p_size), + inet_ntoa(((struct sockaddr_in *) + ep_ptr->param. + remote_ia_address_ptr)->sin_addr)); + goto bail; + } + + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " CONN_PENDING: sending SRC lid=0x%x," + " qpn=0x%x, psize=%d\n", + ntohs(cm_ptr->msg.saddr.ib.lid), + ntohl(cm_ptr->msg.saddr.ib.qpn), + ntohs(cm_ptr->msg.p_size)); + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " CONN_PENDING: SRC GID subnet %016llx id %016llx\n", + (unsigned long long) + htonll(*(uint64_t*)&cm_ptr->msg.saddr.ib.gid[0]), + (unsigned long long) + htonll(*(uint64_t*)&cm_ptr->msg.saddr.ib.gid[8])); + return; + +bail: + /* mark CM object for cleanup */ + dapli_cm_free(cm_ptr); + dapl_evd_connection_callback(NULL, IB_CME_LOCAL_FAILURE, NULL, 0, ep_ptr); +} + +/* + * ACTIVE: Create socket, connect, defer exchange QP information to CR thread + * to avoid blocking. + */ +static DAT_RETURN +dapli_socket_connect(DAPL_EP * ep_ptr, + DAT_IA_ADDRESS_PTR r_addr, + DAT_CONN_QUAL r_qual, DAT_COUNT p_size, DAT_PVOID p_data) +{ + dp_ib_cm_handle_t cm_ptr; + int ret; + socklen_t sl; + DAPL_IA *ia_ptr = ep_ptr->header.owner_ia; + DAT_RETURN dat_ret = DAT_INSUFFICIENT_RESOURCES; + + dapl_dbg_log(DAPL_DBG_TYPE_EP, " connect: r_qual %d p_size=%d\n", + r_qual, p_size); + + cm_ptr = dapli_cm_alloc(ep_ptr); + if (cm_ptr == NULL) + return dat_ret; + + /* create, connect, sockopt, and exchange QP information */ + if ((cm_ptr->socket = + socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == DAPL_INVALID_SOCKET) { + int err = dapl_socket_errno(); + dapl_log(DAPL_DBG_TYPE_ERR, + " connect: socket create ERR 0x%x %s\n", + err, strerror(err)); + goto bail; + } + + ret = dapl_config_socket(cm_ptr->socket); + if (ret < 0) { + dapl_log(DAPL_DBG_TYPE_ERR, + " connect: config socket %d RET %d ERR 0x%x %s\n", + cm_ptr->socket, ret, + dapl_socket_errno(), strerror(dapl_socket_errno())); + dat_ret = DAT_INTERNAL_ERROR; + goto bail; + } + + /* save remote address */ + dapl_os_memcpy(&cm_ptr->addr, r_addr, sizeof(*r_addr)); + +#ifdef DAPL_DBG + /* DBG: Active PID [0], PASSIVE PID [2]*/ + *(uint16_t*)&cm_ptr->msg.resv[0] = htons((uint16_t)dapl_os_getpid()); + *(uint16_t*)&cm_ptr->msg.resv[2] = ((struct sockaddr_in *)&cm_ptr->addr)->sin_port; +#endif + ((struct sockaddr_in *)&cm_ptr->addr)->sin_port = htons(r_qual + 1000); + ret = dapl_connect_socket(cm_ptr->socket, (struct sockaddr *)&cm_ptr->addr, + sizeof(cm_ptr->addr)); + if (ret && ret != EAGAIN) { + dapl_log(DAPL_DBG_TYPE_ERR, + " connect: dapl_connect_socket RET %d ERR 0x%x %s\n", + ret, dapl_socket_errno(), + strerror(dapl_socket_errno())); + dat_ret = DAT_INVALID_ADDRESS; + goto bail; + } + + /* REQ: QP info in msg.saddr, IA address in msg.daddr, and pdata */ + cm_ptr->hca = ia_ptr->hca_ptr; + cm_ptr->msg.op = ntohs(DCM_REQ); + cm_ptr->msg.saddr.ib.qpn = htonl(ep_ptr->qp_handle->qp_num); + cm_ptr->msg.saddr.ib.qp_type = ep_ptr->qp_handle->qp_type; + cm_ptr->msg.saddr.ib.lid = ia_ptr->hca_ptr->ib_trans.lid; + dapl_os_memcpy(&cm_ptr->msg.saddr.ib.gid[0], + &ia_ptr->hca_ptr->ib_trans.gid, 16); + + /* get local address information from socket */ + sl = sizeof(cm_ptr->msg.daddr.so); + if (getsockname(cm_ptr->socket, (struct sockaddr *)&cm_ptr->msg.daddr.so, &sl)) { + int err = dapl_socket_errno(); + dapl_log(DAPL_DBG_TYPE_ERR, + " connect getsockname ERROR: 0x%x %s -> %s r_qual %d\n", + err, strerror(err), + inet_ntoa(((struct sockaddr_in *)r_addr)->sin_addr), + (unsigned int)r_qual);; + } + + if (p_size) { + cm_ptr->msg.p_size = htons(p_size); + dapl_os_memcpy(cm_ptr->msg.p_data, p_data, p_size); + } + + /* connected or pending, either way results via async event */ + if (ret == 0) + dapli_socket_connected(cm_ptr, 0); + else + cm_ptr->state = DCM_CONN_PENDING; + + dapl_dbg_log(DAPL_DBG_TYPE_EP, " connect: p_data=%p %p\n", + cm_ptr->msg.p_data, cm_ptr->msg.p_data); + + dapl_dbg_log(DAPL_DBG_TYPE_EP, + " connect: %s r_qual %d pending, p_sz=%d, %d %d ...\n", + inet_ntoa(((struct sockaddr_in *)&cm_ptr->addr)->sin_addr), + (unsigned int)r_qual, ntohs(cm_ptr->msg.p_size), + cm_ptr->msg.p_data[0], cm_ptr->msg.p_data[1]); + + /* queue up on work thread */ + dapli_cm_queue(cm_ptr); + return DAT_SUCCESS; +bail: + dapl_log(DAPL_DBG_TYPE_ERR, + " connect ERROR: -> %s r_qual %d\n", + inet_ntoa(((struct sockaddr_in *)r_addr)->sin_addr), + (unsigned int)r_qual); + + /* Never queued, destroy */ + dapls_cm_release(cm_ptr); + return dat_ret; +} + +/* + * ACTIVE: exchange QP information, called from CR thread + */ +static void dapli_socket_connect_rtu(dp_ib_cm_handle_t cm_ptr) +{ + DAPL_EP *ep_ptr = cm_ptr->ep; + int len, exp = sizeof(ib_cm_msg_t) - DCM_MAX_PDATA_SIZE; + ib_cm_events_t event = IB_CME_LOCAL_FAILURE; + socklen_t sl; + + /* read DST information into cm_ptr, overwrite SRC info */ + dapl_dbg_log(DAPL_DBG_TYPE_EP, " connect_rtu: recv peer QP data\n"); + + len = recv(cm_ptr->socket, (char *)&cm_ptr->msg, exp, 0); + if (len != exp || ntohs(cm_ptr->msg.ver) != DCM_VER) { + int err = dapl_socket_errno(); + dapl_log(DAPL_DBG_TYPE_WARN, + " CONN_RTU read: sk %d ERR 0x%x, rcnt=%d, v=%d -> %s PORT L-%x R-%x PID L-%x R-%x\n", + cm_ptr->socket, err, len, ntohs(cm_ptr->msg.ver), + inet_ntoa(((struct sockaddr_in *)&cm_ptr->addr)->sin_addr), + ntohs(((struct sockaddr_in *)&cm_ptr->msg.daddr.so)->sin_port), + ntohs(((struct sockaddr_in *)&cm_ptr->addr)->sin_port), + ntohs(*(uint16_t*)&cm_ptr->msg.resv[0]), + ntohs(*(uint16_t*)&cm_ptr->msg.resv[2])); + + /* Retry; corner case where server tcp stack resets under load */ + if (err == ECONNRESET) { + closesocket(cm_ptr->socket); + cm_ptr->socket = DAPL_INVALID_SOCKET; + dapli_socket_connect(cm_ptr->ep, (DAT_IA_ADDRESS_PTR)&cm_ptr->addr, + ntohs(((struct sockaddr_in *)&cm_ptr->addr)->sin_port) - 1000, + ntohs(cm_ptr->msg.p_size), &cm_ptr->msg.p_data); + dapl_ep_unlink_cm(cm_ptr->ep, cm_ptr); + dapli_cm_free(cm_ptr); + return; + } + goto bail; + } + + /* keep the QP, address info in network order */ + + /* save remote address information, in msg.daddr */ + dapl_os_memcpy(&cm_ptr->addr, + &cm_ptr->msg.daddr.so, + sizeof(union dcm_addr)); + + /* save local address information from socket */ + sl = sizeof(cm_ptr->addr); + getsockname(cm_ptr->socket,(struct sockaddr *)&cm_ptr->addr, &sl); + + dapl_dbg_log(DAPL_DBG_TYPE_EP, + " CONN_RTU: DST %s %d lid=0x%x," + " qpn=0x%x, qp_type=%d, psize=%d\n", + inet_ntoa(((struct sockaddr_in *) + &cm_ptr->msg.daddr.so)->sin_addr), + ntohs(((struct sockaddr_in *) + &cm_ptr->msg.daddr.so)->sin_port), + ntohs(cm_ptr->msg.saddr.ib.lid), + ntohl(cm_ptr->msg.saddr.ib.qpn), + cm_ptr->msg.saddr.ib.qp_type, + ntohs(cm_ptr->msg.p_size)); + + /* validate private data size before reading */ + if (ntohs(cm_ptr->msg.p_size) > DCM_MAX_PDATA_SIZE) { + dapl_log(DAPL_DBG_TYPE_ERR, + " CONN_RTU read: psize (%d) wrong -> %s\n", + ntohs(cm_ptr->msg.p_size), + inet_ntoa(((struct sockaddr_in *) + ep_ptr->param. + remote_ia_address_ptr)->sin_addr)); + goto bail; + } + + /* read private data into cm_handle if any present */ + dapl_dbg_log(DAPL_DBG_TYPE_EP," CONN_RTU: read private data\n"); + exp = ntohs(cm_ptr->msg.p_size); + if (exp) { + len = recv(cm_ptr->socket, cm_ptr->msg.p_data, exp, 0); + if (len != exp) { + int err = dapl_socket_errno(); + dapl_log(DAPL_DBG_TYPE_ERR, + " CONN_RTU read pdata: ERR 0x%x %s, rcnt=%d -> %s\n", + err, strerror(err), len, + inet_ntoa(((struct sockaddr_in *) + ep_ptr->param. + remote_ia_address_ptr)->sin_addr)); + goto bail; + } + } + + /* check for consumer or protocol stack reject */ + if (ntohs(cm_ptr->msg.op) == DCM_REP) + event = IB_CME_CONNECTED; + else if (ntohs(cm_ptr->msg.op) == DCM_REJ_USER) + event = IB_CME_DESTINATION_REJECT_PRIVATE_DATA; + else + event = IB_CME_DESTINATION_REJECT; + + if (event != IB_CME_CONNECTED) { + dapl_log(DAPL_DBG_TYPE_CM, + " CONN_RTU: reject from %s %x\n", + inet_ntoa(((struct sockaddr_in *) + &cm_ptr->msg.daddr.so)->sin_addr), + ntohs(((struct sockaddr_in *) + &cm_ptr->msg.daddr.so)->sin_port)); + goto bail; + } + + /* modify QP to RTR and then to RTS with remote info */ + dapl_os_lock(&ep_ptr->header.lock); + if (dapls_modify_qp_state(ep_ptr->qp_handle, + IBV_QPS_RTR, + cm_ptr->msg.saddr.ib.qpn, + cm_ptr->msg.saddr.ib.lid, + (ib_gid_handle_t)cm_ptr->msg.saddr.ib.gid) != DAT_SUCCESS) { + dapl_log(DAPL_DBG_TYPE_ERR, + " CONN_RTU: QPS_RTR ERR %s (%d,%d,%x,%x,%x) -> %s %x\n", + strerror(errno), ep_ptr->qp_handle->qp_type, + ep_ptr->qp_state, ep_ptr->qp_handle->qp_num, + ntohl(cm_ptr->msg.saddr.ib.qpn), + ntohs(cm_ptr->msg.saddr.ib.lid), + inet_ntoa(((struct sockaddr_in *) + &cm_ptr->msg.daddr.so)->sin_addr), + ntohs(((struct sockaddr_in *) + &cm_ptr->msg.daddr.so)->sin_port)); + dapl_os_unlock(&ep_ptr->header.lock); + goto bail; + } + if (dapls_modify_qp_state(ep_ptr->qp_handle, + IBV_QPS_RTS, + cm_ptr->msg.saddr.ib.qpn, + cm_ptr->msg.saddr.ib.lid, + NULL) != DAT_SUCCESS) { + dapl_log(DAPL_DBG_TYPE_ERR, + " CONN_RTU: QPS_RTS ERR %s (%d,%d,%x,%x,%x) -> %s %x\n", + strerror(errno), ep_ptr->qp_handle->qp_type, + ep_ptr->qp_state, ep_ptr->qp_handle->qp_num, + ntohl(cm_ptr->msg.saddr.ib.qpn), + ntohs(cm_ptr->msg.saddr.ib.lid), + inet_ntoa(((struct sockaddr_in *) + &cm_ptr->msg.daddr.so)->sin_addr), + ntohs(((struct sockaddr_in *) + &cm_ptr->msg.daddr.so)->sin_port)); + dapl_os_unlock(&ep_ptr->header.lock); + goto bail; + } + dapl_os_unlock(&ep_ptr->header.lock); + dapl_dbg_log(DAPL_DBG_TYPE_EP, " connect_rtu: send RTU\n"); + + /* complete handshake after final QP state change, Just ver+op */ + dapl_os_lock(&cm_ptr->lock); + cm_ptr->state = DCM_CONNECTED; + dapl_os_unlock(&cm_ptr->lock); + + cm_ptr->msg.op = ntohs(DCM_RTU); + if (send(cm_ptr->socket, (char *)&cm_ptr->msg, 4, 0) == -1) { + int err = dapl_socket_errno(); + dapl_log(DAPL_DBG_TYPE_ERR, + " CONN_RTU: write ERR = 0x%x %s\n", + err, strerror(err)); + goto bail; + } + /* post the event with private data */ + event = IB_CME_CONNECTED; + dapl_dbg_log(DAPL_DBG_TYPE_EP, " ACTIVE: connected!\n"); + +#ifdef DAT_EXTENSIONS +ud_bail: + if (cm_ptr->msg.saddr.ib.qp_type == IBV_QPT_UD) { + DAT_IB_EXTENSION_EVENT_DATA xevent; + ib_pd_handle_t pd_handle = + ((DAPL_PZ *)ep_ptr->param.pz_handle)->pd_handle; + + if (event == IB_CME_CONNECTED) { + cm_ptr->ah = dapls_create_ah(cm_ptr->hca, pd_handle, + ep_ptr->qp_handle, + cm_ptr->msg.saddr.ib.lid, + NULL); + if (cm_ptr->ah) { + /* post UD extended EVENT */ + xevent.status = 0; + xevent.type = DAT_IB_UD_REMOTE_AH; + xevent.remote_ah.ah = cm_ptr->ah; + xevent.remote_ah.qpn = ntohl(cm_ptr->msg.saddr.ib.qpn); + dapl_os_memcpy(&xevent.remote_ah.ia_addr, + &ep_ptr->remote_ia_address, + sizeof(union dcm_addr)); + event = DAT_IB_UD_CONNECTION_EVENT_ESTABLISHED; + + dapl_log(DAPL_DBG_TYPE_CM, + " CONN_RTU: UD AH %p for lid 0x%x" + " qpn 0x%x\n", + cm_ptr->ah, + ntohs(cm_ptr->msg.saddr.ib.lid), + ntohl(cm_ptr->msg.saddr.ib.qpn)); + + } else + event = DAT_IB_UD_CONNECTION_ERROR_EVENT; + + } else if (event == IB_CME_LOCAL_FAILURE) { + event = DAT_IB_UD_CONNECTION_ERROR_EVENT; + } else + event = DAT_IB_UD_CONNECTION_REJECT_EVENT; + + dapls_evd_post_connection_event_ext( + (DAPL_EVD *) ep_ptr->param.connect_evd_handle, + event, + (DAT_EP_HANDLE) ep_ptr, + (DAT_COUNT) exp, + (DAT_PVOID *) cm_ptr->msg.p_data, + (DAT_PVOID *) &xevent); + + /* cleanup and release from local list */ + dapli_cm_free(cm_ptr); + + } else +#endif + { + dapli_ep_check(cm_ptr->ep); + dapl_evd_connection_callback(cm_ptr, event, cm_ptr->msg.p_data, + DCM_MAX_PDATA_SIZE, ep_ptr); + } + dapl_log(DAPL_DBG_TYPE_CM_EST, + " SCM ACTIVE CONN: %x -> %s %x\n", + ntohs(((struct sockaddr_in *) &cm_ptr->addr)->sin_port), + inet_ntoa(((struct sockaddr_in *) &cm_ptr->msg.daddr.so)->sin_addr), + ntohs(((struct sockaddr_in *) &cm_ptr->msg.daddr.so)->sin_port)-1000); + return; + +bail: + +#ifdef DAT_EXTENSIONS + if (cm_ptr->msg.saddr.ib.qp_type == IBV_QPT_UD) + goto ud_bail; +#endif + /* close socket, and post error event */ + dapl_os_lock(&cm_ptr->lock); + cm_ptr->state = DCM_REJECTED; + dapl_os_unlock(&cm_ptr->lock); + + dapl_evd_connection_callback(NULL, event, cm_ptr->msg.p_data, + DCM_MAX_PDATA_SIZE, ep_ptr); + dapli_cm_free(cm_ptr); +} + +/* + * PASSIVE: Create socket, listen, accept, exchange QP information + */ +DAT_RETURN +dapli_socket_listen(DAPL_IA * ia_ptr, DAT_CONN_QUAL serviceID, DAPL_SP * sp_ptr) +{ + struct sockaddr_in addr; + ib_cm_srvc_handle_t cm_ptr = NULL; + DAT_RETURN dat_status = DAT_SUCCESS; + int opt = 1; + + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " setup listen(ia_ptr %p ServiceID %d sp_ptr %p)\n", + ia_ptr, serviceID, sp_ptr); + + cm_ptr = dapli_cm_alloc(NULL); + if (cm_ptr == NULL) + return DAT_INSUFFICIENT_RESOURCES; + + cm_ptr->sp = sp_ptr; + cm_ptr->hca = ia_ptr->hca_ptr; + + /* bind, listen, set sockopt, accept, exchange data */ + if ((cm_ptr->socket = + socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == DAPL_INVALID_SOCKET) { + int err = dapl_socket_errno(); + dapl_log(DAPL_DBG_TYPE_ERR, + " listen: socket create: ERR 0x%x %s\n", + err, strerror(err)); + dat_status = DAT_INSUFFICIENT_RESOURCES; + goto bail; + } + + setsockopt(cm_ptr->socket, SOL_SOCKET, SO_REUSEADDR, (char*)&opt, sizeof(opt)); + addr.sin_port = htons(serviceID + 1000); + addr.sin_family = AF_INET; + addr.sin_addr = ((struct sockaddr_in *) &ia_ptr->hca_ptr->hca_address)->sin_addr; + + if ((bind(cm_ptr->socket, (struct sockaddr *)&addr, sizeof(addr)) < 0) + || (listen(cm_ptr->socket, 128) < 0)) { + int err = dapl_socket_errno(); + dapl_log(DAPL_DBG_TYPE_CM, + " listen: ERROR 0x%x %s on port %d\n", + err, strerror(err), serviceID + 1000); + if (err == EADDRINUSE) + dat_status = DAT_CONN_QUAL_IN_USE; + else + dat_status = DAT_CONN_QUAL_UNAVAILABLE; + goto bail; + } + + /* set cm_handle for this service point, save listen socket */ + sp_ptr->cm_srvc_handle = cm_ptr; + dapl_os_memcpy(&cm_ptr->addr, &addr, sizeof(addr)); + + /* queue up listen socket to process inbound CR's */ + cm_ptr->state = DCM_LISTEN; + dapli_cm_queue(cm_ptr); + + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " setup listen: port %d cr %p s_fd %d\n", + serviceID + 1000, cm_ptr, cm_ptr->socket); + + return dat_status; +bail: + /* Never queued, destroy here */ + dapls_cm_release(cm_ptr); + return dat_status; +} + +/* + * PASSIVE: accept socket + */ +static void dapli_socket_accept(ib_cm_srvc_handle_t cm_ptr) +{ + dp_ib_cm_handle_t acm_ptr; + int ret, len, opt = 1; + socklen_t sl; + + /* + * Accept all CR's on this port to avoid half-connection (SYN_RCV) + * stalls with many to one connection storms + */ + do { + /* Allocate accept CM and initialize */ + if ((acm_ptr = dapli_cm_alloc(NULL)) == NULL) + return; + + acm_ptr->sp = cm_ptr->sp; + acm_ptr->hca = cm_ptr->hca; + + len = sizeof(union dcm_addr); + acm_ptr->socket = accept(cm_ptr->socket, + (struct sockaddr *) + &acm_ptr->msg.daddr.so, + (socklen_t *) &len); + if (acm_ptr->socket == DAPL_INVALID_SOCKET) { + int err = dapl_socket_errno(); + dapl_log(DAPL_DBG_TYPE_ERR, + " ACCEPT: ERR 0x%x %s on FD %d l_cr %p\n", + err, strerror(err), cm_ptr->socket, cm_ptr); + dapls_cm_release(acm_ptr); + return; + } + dapl_dbg_log(DAPL_DBG_TYPE_CM, " accepting from %s %x\n", + inet_ntoa(((struct sockaddr_in *) + &acm_ptr->msg.daddr.so)->sin_addr), + ntohs(((struct sockaddr_in *) + &acm_ptr->msg.daddr.so)->sin_port)); + + /* no delay for small packets */ + ret = setsockopt(acm_ptr->socket, IPPROTO_TCP, TCP_NODELAY, + (char *)&opt, sizeof(opt)); + if (ret) { + int err = dapl_socket_errno(); + dapl_log(DAPL_DBG_TYPE_ERR, + " ACCEPT: NODELAY setsockopt:" + " RET %d ERR 0x%x %s\n", + ret, err, strerror(err)); + } + + /* get local address information from socket */ + sl = sizeof(acm_ptr->addr); + getsockname(acm_ptr->socket, (struct sockaddr *)&acm_ptr->addr, &sl); + acm_ptr->state = DCM_ACCEPTING; + dapli_cm_queue(acm_ptr); + + } while (dapl_poll(cm_ptr->socket, DAPL_FD_READ) == DAPL_FD_READ); +} + +/* + * PASSIVE: receive peer QP information, private data, post cr_event + */ +static void dapli_socket_accept_data(ib_cm_srvc_handle_t acm_ptr) +{ + int len, exp = sizeof(ib_cm_msg_t) - DCM_MAX_PDATA_SIZE; + void *p_data = NULL; + + dapl_dbg_log(DAPL_DBG_TYPE_EP, " socket accepted, read QP data\n"); + + /* read in DST QP info, IA address. check for private data */ + len = recv(acm_ptr->socket, (char *)&acm_ptr->msg, exp, 0); + if (len != exp || ntohs(acm_ptr->msg.ver) != DCM_VER) { + int err = dapl_socket_errno(); + dapl_log(DAPL_DBG_TYPE_ERR, + " ACCEPT read: ERR 0x%x %s, rcnt=%d, ver=%d\n", + err, strerror(err), len, ntohs(acm_ptr->msg.ver)); + goto bail; + } + + /* keep the QP, address info in network order */ + + /* validate private data size before reading */ + exp = ntohs(acm_ptr->msg.p_size); + if (exp > DCM_MAX_PDATA_SIZE) { + dapl_log(DAPL_DBG_TYPE_ERR, + " accept read: psize (%d) wrong\n", + acm_ptr->msg.p_size); + goto bail; + } + + /* read private data into cm_handle if any present */ + if (exp) { + len = recv(acm_ptr->socket, acm_ptr->msg.p_data, exp, 0); + if (len != exp) { + int err = dapl_socket_errno(); + dapl_log(DAPL_DBG_TYPE_ERR, + " accept read pdata: ERR 0x%x %s, rcnt=%d\n", + err, strerror(err), len); + goto bail; + } + p_data = acm_ptr->msg.p_data; + } + dapl_os_lock(&acm_ptr->lock); + acm_ptr->state = DCM_ACCEPTING_DATA; + dapl_os_unlock(&acm_ptr->lock); + + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " ACCEPT: DST %s %x lid=0x%x, qpn=0x%x, psz=%d\n", + inet_ntoa(((struct sockaddr_in *) + &acm_ptr->msg.daddr.so)->sin_addr), + ntohs(((struct sockaddr_in *) + &acm_ptr->msg.daddr.so)->sin_port), + ntohs(acm_ptr->msg.saddr.ib.lid), + ntohl(acm_ptr->msg.saddr.ib.qpn), exp); + +#ifdef DAT_EXTENSIONS + if (acm_ptr->msg.saddr.ib.qp_type == IBV_QPT_UD) { + DAT_IB_EXTENSION_EVENT_DATA xevent; + + /* post EVENT, modify_qp created ah */ + xevent.status = 0; + xevent.type = DAT_IB_UD_CONNECT_REQUEST; + + dapls_evd_post_cr_event_ext(acm_ptr->sp, + DAT_IB_UD_CONNECTION_REQUEST_EVENT, + acm_ptr, + (DAT_COUNT) exp, + (DAT_PVOID *) acm_ptr->msg.p_data, + (DAT_PVOID *) &xevent); + } else +#endif + /* trigger CR event and return SUCCESS */ + dapls_cr_callback(acm_ptr, + IB_CME_CONNECTION_REQUEST_PENDING, + p_data, exp, acm_ptr->sp); + return; +bail: + /* mark for destroy, active will see socket close as rej */ + dapli_cm_free(acm_ptr); + return; +} + +/* + * PASSIVE: consumer accept, send local QP information, private data, + * queue on work thread to receive RTU information to avoid blocking + * user thread. + */ +static DAT_RETURN +dapli_socket_accept_usr(DAPL_EP * ep_ptr, + DAPL_CR * cr_ptr, DAT_COUNT p_size, DAT_PVOID p_data) +{ + DAPL_IA *ia_ptr = ep_ptr->header.owner_ia; + dp_ib_cm_handle_t cm_ptr = cr_ptr->ib_cm_handle; + ib_cm_msg_t local; + struct iovec iov[2]; + int len, exp = sizeof(ib_cm_msg_t) - DCM_MAX_PDATA_SIZE; + DAT_RETURN ret = DAT_INTERNAL_ERROR; + socklen_t sl; + + if (p_size > DCM_MAX_PDATA_SIZE) { + dapl_log(DAPL_DBG_TYPE_ERR, + " accept_usr: psize(%d) too large\n", p_size); + return DAT_LENGTH_ERROR; + } + + /* must have a accepted socket */ + if (cm_ptr->socket == DAPL_INVALID_SOCKET) { + dapl_log(DAPL_DBG_TYPE_ERR, + " accept_usr: cm socket invalid\n"); + goto bail; + } + + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " ACCEPT_USR: remote lid=0x%x" + " qpn=0x%x qp_type %d, psize=%d\n", + ntohs(cm_ptr->msg.saddr.ib.lid), + ntohl(cm_ptr->msg.saddr.ib.qpn), + cm_ptr->msg.saddr.ib.qp_type, + ntohs(cm_ptr->msg.p_size)); + +#ifdef DAT_EXTENSIONS + if (cm_ptr->msg.saddr.ib.qp_type == IBV_QPT_UD && + ep_ptr->qp_handle->qp_type != IBV_QPT_UD) { + dapl_log(DAPL_DBG_TYPE_ERR, + " ACCEPT_USR: ERR remote QP is UD," + ", but local QP is not\n"); + ret = (DAT_INVALID_HANDLE | DAT_INVALID_HANDLE_EP); + goto bail; + } +#endif + + /* modify QP to RTR and then to RTS with remote info already read */ + dapl_os_lock(&ep_ptr->header.lock); + if (dapls_modify_qp_state(ep_ptr->qp_handle, + IBV_QPS_RTR, + cm_ptr->msg.saddr.ib.qpn, + cm_ptr->msg.saddr.ib.lid, + (ib_gid_handle_t)cm_ptr->msg.saddr.ib.gid) != DAT_SUCCESS) { + dapl_log(DAPL_DBG_TYPE_ERR, + " ACCEPT_USR: QPS_RTR ERR %s -> %s\n", + strerror(errno), + inet_ntoa(((struct sockaddr_in *) + &cm_ptr->msg.daddr.so)->sin_addr)); + dapl_os_unlock(&ep_ptr->header.lock); + goto bail; + } + if (dapls_modify_qp_state(ep_ptr->qp_handle, + IBV_QPS_RTS, + cm_ptr->msg.saddr.ib.qpn, + cm_ptr->msg.saddr.ib.lid, + NULL) != DAT_SUCCESS) { + dapl_log(DAPL_DBG_TYPE_ERR, + " ACCEPT_USR: QPS_RTS ERR %s -> %s\n", + strerror(errno), + inet_ntoa(((struct sockaddr_in *) + &cm_ptr->msg.daddr.so)->sin_addr)); + dapl_os_unlock(&ep_ptr->header.lock); + goto bail; + } + dapl_os_unlock(&ep_ptr->header.lock); + + /* save remote address information */ + dapl_os_memcpy(&ep_ptr->remote_ia_address, + &cm_ptr->msg.daddr.so, + sizeof(union dcm_addr)); + + /* send our QP info, IA address, pdata. Don't overwrite dst data */ + local.ver = htons(DCM_VER); + local.op = htons(DCM_REP); + local.saddr.ib.qpn = htonl(ep_ptr->qp_handle->qp_num); + local.saddr.ib.qp_type = ep_ptr->qp_handle->qp_type; + local.saddr.ib.lid = ia_ptr->hca_ptr->ib_trans.lid; + dapl_os_memcpy(&local.saddr.ib.gid[0], + &ia_ptr->hca_ptr->ib_trans.gid, 16); + + /* Get local address information from socket */ + sl = sizeof(local.daddr.so); + getsockname(cm_ptr->socket, (struct sockaddr *)&local.daddr.so, &sl); + +#ifdef DAPL_DBG + /* DBG: Active PID [0], PASSIVE PID [2] */ + *(uint16_t*)&cm_ptr->msg.resv[2] = htons((uint16_t)dapl_os_getpid()); + dapl_os_memcpy(local.resv, cm_ptr->msg.resv, 4); +#endif + cm_ptr->hca = ia_ptr->hca_ptr; + dapl_os_lock(&cm_ptr->lock); + cm_ptr->state = DCM_ACCEPTED; + dapl_os_unlock(&cm_ptr->lock); + + /* Link CM to EP, already queued on work thread */ + dapl_ep_link_cm(ep_ptr, cm_ptr); + cm_ptr->ep = ep_ptr; + + local.p_size = htons(p_size); + iov[0].iov_base = (void *)&local; + iov[0].iov_len = exp; + + if (p_size) { + iov[1].iov_base = p_data; + iov[1].iov_len = p_size; + len = writev(cm_ptr->socket, iov, 2); + } else + len = writev(cm_ptr->socket, iov, 1); + + if (len != (p_size + exp)) { + int err = dapl_socket_errno(); + dapl_log(DAPL_DBG_TYPE_ERR, + " ACCEPT_USR: ERR 0x%x %s, wcnt=%d -> %s\n", + err, strerror(err), len, + inet_ntoa(((struct sockaddr_in *) + &cm_ptr->msg.daddr.so)->sin_addr)); + dapl_ep_unlink_cm(ep_ptr, cm_ptr); + cm_ptr->ep = NULL; + goto bail; + } + + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " ACCEPT_USR: local lid=0x%x qpn=0x%x psz=%d\n", + ntohs(local.saddr.ib.lid), + ntohl(local.saddr.ib.qpn), ntohs(local.p_size)); + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " ACCEPT_USR: local GID subnet %016llx id %016llx\n", + (unsigned long long) + htonll(*(uint64_t*)&local.saddr.ib.gid[0]), + (unsigned long long) + htonll(*(uint64_t*)&local.saddr.ib.gid[8])); + + dapl_dbg_log(DAPL_DBG_TYPE_EP, " PASSIVE: accepted!\n"); + + return DAT_SUCCESS; +bail: + /* schedule cleanup from workq */ + dapli_cm_free(cm_ptr); + return ret; +} + +/* + * PASSIVE: read RTU from active peer, post CONN event + */ +static void dapli_socket_accept_rtu(dp_ib_cm_handle_t cm_ptr) +{ + int len; + ib_cm_events_t event = IB_CME_CONNECTED; + + /* complete handshake after final QP state change, VER and OP */ + len = recv(cm_ptr->socket, (char *)&cm_ptr->msg, 4, 0); + if (len != 4 || ntohs(cm_ptr->msg.op) != DCM_RTU) { + dapl_log(DAPL_DBG_TYPE_ERR, + " ACCEPT_RTU: rcv ERR, rcnt=%d op=%x <- %s\n", + len, ntohs(cm_ptr->msg.op), + inet_ntoa(((struct sockaddr_in *) + &cm_ptr->msg.daddr.so)->sin_addr)); + event = IB_CME_DESTINATION_REJECT; + goto bail; + } + + /* save state and reference to EP, queue for disc event */ + dapl_os_lock(&cm_ptr->lock); + cm_ptr->state = DCM_CONNECTED; + dapl_os_unlock(&cm_ptr->lock); + + /* final data exchange if remote QP state is good to go */ + dapl_dbg_log(DAPL_DBG_TYPE_EP, " PASSIVE: connected!\n"); + +#ifdef DAT_EXTENSIONS +ud_bail: + if (cm_ptr->msg.saddr.ib.qp_type == IBV_QPT_UD) { + DAT_IB_EXTENSION_EVENT_DATA xevent; + + ib_pd_handle_t pd_handle = + ((DAPL_PZ *)cm_ptr->ep->param.pz_handle)->pd_handle; + + if (event == IB_CME_CONNECTED) { + cm_ptr->ah = dapls_create_ah(cm_ptr->hca, pd_handle, + cm_ptr->ep->qp_handle, + cm_ptr->msg.saddr.ib.lid, + NULL); + if (cm_ptr->ah) { + /* post EVENT, modify_qp created ah */ + xevent.status = 0; + xevent.type = DAT_IB_UD_PASSIVE_REMOTE_AH; + xevent.remote_ah.ah = cm_ptr->ah; + xevent.remote_ah.qpn = ntohl(cm_ptr->msg.saddr.ib.qpn); + dapl_os_memcpy(&xevent.remote_ah.ia_addr, + &cm_ptr->msg.daddr.so, + sizeof(union dcm_addr)); + event = DAT_IB_UD_CONNECTION_EVENT_ESTABLISHED; + } else + event = DAT_IB_UD_CONNECTION_ERROR_EVENT; + } else + event = DAT_IB_UD_CONNECTION_ERROR_EVENT; + + dapl_log(DAPL_DBG_TYPE_CM, + " CONN_RTU: UD AH %p for lid 0x%x qpn 0x%x\n", + cm_ptr->ah, ntohs(cm_ptr->msg.saddr.ib.lid), + ntohl(cm_ptr->msg.saddr.ib.qpn)); + + dapls_evd_post_connection_event_ext( + (DAPL_EVD *) + cm_ptr->ep->param.connect_evd_handle, + event, + (DAT_EP_HANDLE) cm_ptr->ep, + (DAT_COUNT) ntohs(cm_ptr->msg.p_size), + (DAT_PVOID *) cm_ptr->msg.p_data, + (DAT_PVOID *) &xevent); + + /* cleanup and release from local list, still on EP list */ + dapli_cm_free(cm_ptr); + + } else +#endif + { + dapli_ep_check(cm_ptr->ep); + dapls_cr_callback(cm_ptr, event, NULL, 0, cm_ptr->sp); + } + dapl_log(DAPL_DBG_TYPE_CM_EST, + " SCM PASSIVE CONN: %x <- %s %x\n", + cm_ptr->sp->conn_qual, + inet_ntoa(((struct sockaddr_in *) &cm_ptr->msg.daddr.so)->sin_addr), + ntohs(((struct sockaddr_in *) &cm_ptr->msg.daddr.so)->sin_port)); + return; + +bail: +#ifdef DAT_EXTENSIONS + if (cm_ptr->msg.saddr.ib.qp_type == IBV_QPT_UD) + goto ud_bail; +#endif + dapl_os_lock(&cm_ptr->lock); + cm_ptr->state = DCM_REJECTED; + dapl_os_unlock(&cm_ptr->lock); + + dapls_cr_callback(cm_ptr, event, NULL, 0, cm_ptr->sp); + dapli_cm_free(cm_ptr); +} + +/* + * dapls_ib_connect + * + * Initiate a connection with the passive listener on another node + * + * Input: + * ep_handle, + * remote_ia_address, + * remote_conn_qual, + * prd_size size of private data and structure + * prd_prt pointer to private data structure + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + * + */ +DAT_RETURN +dapls_ib_connect(IN DAT_EP_HANDLE ep_handle, + IN DAT_IA_ADDRESS_PTR remote_ia_address, + IN DAT_CONN_QUAL remote_conn_qual, + IN DAT_COUNT private_data_size, IN void *private_data) +{ + DAPL_EP *ep_ptr = (DAPL_EP *) ep_handle; + + dapl_dbg_log(DAPL_DBG_TYPE_EP, + " connect(ep_handle %p ....)\n", ep_handle); + + return (dapli_socket_connect(ep_ptr, remote_ia_address, + remote_conn_qual, + private_data_size, private_data)); +} + +/* + * dapls_ib_disconnect + * + * Disconnect an EP + * + * Input: + * ep_handle, + * disconnect_flags + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + */ +DAT_RETURN +dapls_ib_disconnect(IN DAPL_EP * ep_ptr, IN DAT_CLOSE_FLAGS close_flags) +{ + dp_ib_cm_handle_t cm_ptr = dapl_get_cm_from_ep(ep_ptr); + + dapl_os_lock(&ep_ptr->header.lock); + if (ep_ptr->param.ep_state == DAT_EP_STATE_DISCONNECTED || + ep_ptr->param.ep_attr.service_type != DAT_SERVICE_TYPE_RC || + cm_ptr == NULL) { + dapl_os_unlock(&ep_ptr->header.lock); + return DAT_SUCCESS; + } + dapl_os_unlock(&ep_ptr->header.lock); + return (dapli_socket_disconnect(cm_ptr)); +} + +/* + * dapls_ib_disconnect_clean + * + * Clean up outstanding connection data. This routine is invoked + * after the final disconnect callback has occurred. Only on the + * ACTIVE side of a connection. It is also called if dat_ep_connect + * times out using the consumer supplied timeout value. + * + * Input: + * ep_ptr DAPL_EP + * active Indicates active side of connection + * + * Output: + * none + * + * Returns: + * void + * + */ +void +dapls_ib_disconnect_clean(IN DAPL_EP * ep_ptr, + IN DAT_BOOLEAN active, + IN const ib_cm_events_t ib_cm_event) +{ + if (ib_cm_event == IB_CME_TIMEOUT) { + dp_ib_cm_handle_t cm_ptr; + + if ((cm_ptr = dapl_get_cm_from_ep(ep_ptr)) == NULL) + return; + + dapl_log(DAPL_DBG_TYPE_WARN, + "dapls_ib_disc_clean: CONN_TIMEOUT ep %p cm %p %s\n", + ep_ptr, cm_ptr, dapl_cm_state_str(cm_ptr->state)); + + /* schedule release of socket and local resources */ + dapli_cm_free(cm_ptr); + } +} + +/* + * dapl_ib_setup_conn_listener + * + * Have the CM set up a connection listener. + * + * Input: + * ibm_hca_handle HCA handle + * qp_handle QP handle + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INTERNAL_ERROR + * DAT_CONN_QUAL_UNAVAILBLE + * DAT_CONN_QUAL_IN_USE + * + */ +DAT_RETURN +dapls_ib_setup_conn_listener(IN DAPL_IA * ia_ptr, + IN DAT_UINT64 ServiceID, IN DAPL_SP * sp_ptr) +{ + return (dapli_socket_listen(ia_ptr, ServiceID, sp_ptr)); +} + +/* + * dapl_ib_remove_conn_listener + * + * Have the CM remove a connection listener. + * + * Input: + * ia_handle IA handle + * ServiceID IB Channel Service ID + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_STATE + * + */ +DAT_RETURN +dapls_ib_remove_conn_listener(IN DAPL_IA * ia_ptr, IN DAPL_SP * sp_ptr) +{ + ib_cm_srvc_handle_t cm_ptr = sp_ptr->cm_srvc_handle; + + /* free cm_srvc_handle, release will cleanup */ + if (cm_ptr != NULL) { + /* cr_thread will free */ + sp_ptr->cm_srvc_handle = NULL; + dapli_cm_free(cm_ptr); + } + return DAT_SUCCESS; +} + +/* + * dapls_ib_accept_connection + * + * Perform necessary steps to accept a connection + * + * Input: + * cr_handle + * ep_handle + * private_data_size + * private_data + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INTERNAL_ERROR + * + */ +DAT_RETURN +dapls_ib_accept_connection(IN DAT_CR_HANDLE cr_handle, + IN DAT_EP_HANDLE ep_handle, + IN DAT_COUNT p_size, IN const DAT_PVOID p_data) +{ + DAPL_CR *cr_ptr; + DAPL_EP *ep_ptr; + + dapl_dbg_log(DAPL_DBG_TYPE_EP, + "dapls_ib_accept_connection(cr %p ep %p prd %p,%d)\n", + cr_handle, ep_handle, p_data, p_size); + + cr_ptr = (DAPL_CR *) cr_handle; + ep_ptr = (DAPL_EP *) ep_handle; + + /* allocate and attach a QP if necessary */ + if (ep_ptr->qp_state == DAPL_QP_STATE_UNATTACHED) { + DAT_RETURN status; + status = dapls_ib_qp_alloc(ep_ptr->header.owner_ia, + ep_ptr, ep_ptr); + if (status != DAT_SUCCESS) + return status; + } + return (dapli_socket_accept_usr(ep_ptr, cr_ptr, p_size, p_data)); +} + +/* + * dapls_ib_reject_connection + * + * Reject a connection + * + * Input: + * cr_handle + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INTERNAL_ERROR + * + */ +DAT_RETURN +dapls_ib_reject_connection(IN dp_ib_cm_handle_t cm_ptr, + IN int reason, + IN DAT_COUNT psize, IN const DAT_PVOID pdata) +{ + struct iovec iov[2]; + + dapl_dbg_log(DAPL_DBG_TYPE_EP, + " reject(cm %p reason %x, pdata %p, psize %d)\n", + cm_ptr, reason, pdata, psize); + + if (psize > DCM_MAX_PDATA_SIZE) + return DAT_LENGTH_ERROR; + + /* write reject data to indicate reject */ + cm_ptr->msg.op = htons(DCM_REJ_USER); + cm_ptr->msg.p_size = htons(psize); + + iov[0].iov_base = (void *)&cm_ptr->msg; + iov[0].iov_len = sizeof(ib_cm_msg_t) - DCM_MAX_PDATA_SIZE; + if (psize) { + iov[1].iov_base = pdata; + iov[1].iov_len = psize; + writev(cm_ptr->socket, iov, 2); + } else { + writev(cm_ptr->socket, iov, 1); + } + + /* release and cleanup CM object */ + dapli_cm_free(cm_ptr); + return DAT_SUCCESS; +} + +/* + * dapls_ib_cm_remote_addr + * + * Obtain the remote IP address given a connection + * + * Input: + * cr_handle + * + * Output: + * remote_ia_address: where to place the remote address + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + * + */ +DAT_RETURN +dapls_ib_cm_remote_addr(IN DAT_HANDLE dat_handle, + OUT DAT_SOCK_ADDR6 * remote_ia_address) +{ + DAPL_HEADER *header; + dp_ib_cm_handle_t conn; + + dapl_dbg_log(DAPL_DBG_TYPE_EP, + "dapls_ib_cm_remote_addr(dat_handle %p, ....)\n", + dat_handle); + + header = (DAPL_HEADER *) dat_handle; + + if (header->magic == DAPL_MAGIC_EP) + conn = dapl_get_cm_from_ep((DAPL_EP *) dat_handle); + else if (header->magic == DAPL_MAGIC_CR) + conn = ((DAPL_CR *) dat_handle)->ib_cm_handle; + else + return DAT_INVALID_HANDLE; + + dapl_os_memcpy(remote_ia_address, + &conn->msg.daddr.so, sizeof(DAT_SOCK_ADDR6)); + + return DAT_SUCCESS; +} + +int dapls_ib_private_data_size( + IN DAPL_HCA *hca_ptr) +{ + return DCM_MAX_PDATA_SIZE; +} + +/* outbound/inbound CR processing thread to avoid blocking applications */ +void cr_thread(void *arg) +{ + struct dapl_hca *hca_ptr = arg; + dp_ib_cm_handle_t cr, next_cr; + int opt, ret; + socklen_t opt_len; + char rbuf[2]; + struct dapl_fd_set *set; + enum DAPL_FD_EVENTS event; + + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, " cr_thread: ENTER hca %p\n", hca_ptr); + set = dapl_alloc_fd_set(); + if (!set) + goto out; + + dapl_os_lock(&hca_ptr->ib_trans.lock); + hca_ptr->ib_trans.cr_state = IB_THREAD_RUN; + + while (1) { + dapl_fd_zero(set); + dapl_fd_set(hca_ptr->ib_trans.scm[0], set, DAPL_FD_READ); + + if (!dapl_llist_is_empty(&hca_ptr->ib_trans.list)) + next_cr = dapl_llist_peek_head(&hca_ptr->ib_trans.list); + else + next_cr = NULL; + + while (next_cr) { + cr = next_cr; + next_cr = dapl_llist_next_entry(&hca_ptr->ib_trans.list, + (DAPL_LLIST_ENTRY *) + &cr->local_entry); + dapls_cm_acquire(cr); /* hold thread ref */ + dapl_os_lock(&cr->lock); + if (cr->state == DCM_FREE || + hca_ptr->ib_trans.cr_state != IB_THREAD_RUN) { + dapl_log(DAPL_DBG_TYPE_CM, + " CM FREE: %p ep=%p st=%s sck=%d refs=%d\n", + cr, cr->ep, dapl_cm_state_str(cr->state), + cr->socket, cr->ref_count); + + if (cr->socket != DAPL_INVALID_SOCKET) { + shutdown(cr->socket, SHUT_RDWR); + closesocket(cr->socket); + cr->socket = DAPL_INVALID_SOCKET; + } + dapl_os_unlock(&cr->lock); + dapls_cm_release(cr); /* release alloc ref */ + dapli_cm_dequeue(cr); /* release workq ref */ + dapls_cm_release(cr); /* release thread ref */ + continue; + } + + event = (cr->state == DCM_CONN_PENDING) ? + DAPL_FD_WRITE : DAPL_FD_READ; + + if (dapl_fd_set(cr->socket, set, event)) { + dapl_log(DAPL_DBG_TYPE_ERR, + " cr_thread: fd_set ERR st=%d fd %d" + " -> %s\n", cr->state, cr->socket, + inet_ntoa(((struct sockaddr_in *) + &cr->msg.daddr.so)->sin_addr)); + dapl_os_unlock(&cr->lock); + dapls_cm_release(cr); /* release ref */ + continue; + } + dapl_os_unlock(&cr->lock); + dapl_os_unlock(&hca_ptr->ib_trans.lock); + + ret = dapl_poll(cr->socket, event); + + dapl_dbg_log(DAPL_DBG_TYPE_THREAD, + " poll ret=0x%x %s sck=%d\n", + ret, dapl_cm_state_str(cr->state), + cr->socket); + + /* data on listen, qp exchange, and on disc req */ + dapl_os_lock(&cr->lock); + if ((ret == DAPL_FD_READ) || + (cr->state != DCM_CONN_PENDING && ret == DAPL_FD_ERROR)) { + if (cr->socket != DAPL_INVALID_SOCKET) { + switch (cr->state) { + case DCM_LISTEN: + dapl_os_unlock(&cr->lock); + dapli_socket_accept(cr); + break; + case DCM_ACCEPTING: + dapl_os_unlock(&cr->lock); + dapli_socket_accept_data(cr); + break; + case DCM_ACCEPTED: + dapl_os_unlock(&cr->lock); + dapli_socket_accept_rtu(cr); + break; + case DCM_REP_PENDING: + dapl_os_unlock(&cr->lock); + dapli_socket_connect_rtu(cr); + break; + case DCM_CONNECTED: + dapl_os_unlock(&cr->lock); + dapli_socket_disconnect(cr); + break; + default: + dapl_os_unlock(&cr->lock); + break; + } + } else + dapl_os_unlock(&cr->lock); + + /* ASYNC connections, writable, readable, error; check status */ + } else if (ret == DAPL_FD_WRITE || + (cr->state == DCM_CONN_PENDING && + ret == DAPL_FD_ERROR)) { + + opt = 0; + opt_len = sizeof(opt); + ret = getsockopt(cr->socket, SOL_SOCKET, + SO_ERROR, (char *)&opt, + &opt_len); + dapl_os_unlock(&cr->lock); + if (!ret && !opt) + dapli_socket_connected(cr, opt); + else + dapli_socket_connected(cr, opt ? opt : dapl_socket_errno()); + } else + dapl_os_unlock(&cr->lock); + + dapls_cm_release(cr); /* release ref */ + dapl_os_lock(&hca_ptr->ib_trans.lock); + } + + /* set to exit and all resources destroyed */ + if ((hca_ptr->ib_trans.cr_state != IB_THREAD_RUN) && + (dapl_llist_is_empty(&hca_ptr->ib_trans.list))) + break; + + dapl_os_unlock(&hca_ptr->ib_trans.lock); + dapl_select(set); + + /* if pipe used to wakeup, consume */ + while (dapl_poll(hca_ptr->ib_trans.scm[0], + DAPL_FD_READ) == DAPL_FD_READ) { + if (recv(hca_ptr->ib_trans.scm[0], rbuf, 2, 0) == -1) + dapl_log(DAPL_DBG_TYPE_THREAD, + " cr_thread: read pipe error = %s\n", + strerror(errno)); + } + dapl_os_lock(&hca_ptr->ib_trans.lock); + + /* set to exit and all resources destroyed */ + if ((hca_ptr->ib_trans.cr_state != IB_THREAD_RUN) && + (dapl_llist_is_empty(&hca_ptr->ib_trans.list))) + break; + } + + dapl_os_unlock(&hca_ptr->ib_trans.lock); + dapl_os_free(set, sizeof(struct dapl_fd_set)); +out: + hca_ptr->ib_trans.cr_state = IB_THREAD_EXIT; + dapl_dbg_log(DAPL_DBG_TYPE_THREAD, " cr_thread(hca %p) exit\n", hca_ptr); +} + + +#ifdef DAPL_COUNTERS +/* Debug aid: List all Connections in process and state */ +void dapls_print_cm_list(IN DAPL_IA *ia_ptr) +{ + /* Print in process CR's for this IA, if debug type set */ + int i = 0; + dp_ib_cm_handle_t cr, next_cr; + + dapl_os_lock(&ia_ptr->hca_ptr->ib_trans.lock); + if (!dapl_llist_is_empty((DAPL_LLIST_HEAD*) + &ia_ptr->hca_ptr->ib_trans.list)) + next_cr = dapl_llist_peek_head((DAPL_LLIST_HEAD*) + &ia_ptr->hca_ptr->ib_trans.list); + else + next_cr = NULL; + + printf("\n DAPL IA CONNECTIONS IN PROCESS:\n"); + while (next_cr) { + cr = next_cr; + next_cr = dapl_llist_next_entry((DAPL_LLIST_HEAD*) + &ia_ptr->hca_ptr->ib_trans.list, + (DAPL_LLIST_ENTRY*)&cr->local_entry); + + printf( " CONN[%d]: sp %p ep %p sock %d %s %s %s %s %s %s PORT L-%x R-%x PID L-%x R-%x\n", + i, cr->sp, cr->ep, cr->socket, + cr->msg.saddr.ib.qp_type == IBV_QPT_RC ? "RC" : "UD", + dapl_cm_state_str(cr->state), dapl_cm_op_str(ntohs(cr->msg.op)), + ntohs(cr->msg.op) == DCM_REQ ? /* local address */ + inet_ntoa(((struct sockaddr_in *)&cr->msg.daddr.so)->sin_addr) : + inet_ntoa(((struct sockaddr_in *)&cr->addr)->sin_addr), + cr->sp ? "<-" : "->", + ntohs(cr->msg.op) == DCM_REQ ? /* remote address */ + inet_ntoa(((struct sockaddr_in *)&cr->addr)->sin_addr) : + inet_ntoa(((struct sockaddr_in *)&cr->msg.daddr.so)->sin_addr), + + ntohs(cr->msg.op) == DCM_REQ ? /* local port */ + ntohs(((struct sockaddr_in *)&cr->msg.daddr.so)->sin_port) : + ntohs(((struct sockaddr_in *)&cr->addr)->sin_port), + + ntohs(cr->msg.op) == DCM_REQ ? /* remote port */ + ntohs(((struct sockaddr_in *)&cr->addr)->sin_port) : + ntohs(((struct sockaddr_in *)&cr->msg.daddr.so)->sin_port), + + cr->sp ? ntohs(*(uint16_t*)&cr->msg.resv[2]) : ntohs(*(uint16_t*)&cr->msg.resv[0]), + cr->sp ? ntohs(*(uint16_t*)&cr->msg.resv[0]) : ntohs(*(uint16_t*)&cr->msg.resv[2])); + + i++; + } + printf("\n"); + dapl_os_unlock(&ia_ptr->hca_ptr->ib_trans.lock); +} +#endif diff --git a/branches/WOF2-3/ulp/dapl2/dapl/openib_scm/dapl_ib_util.h b/branches/WOF2-3/ulp/dapl2/dapl/openib_scm/dapl_ib_util.h new file mode 100644 index 00000000..4bb1a4a6 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/openib_scm/dapl_ib_util.h @@ -0,0 +1,129 @@ +/* + * 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. + */ + +#ifndef _DAPL_IB_UTIL_H_ +#define _DAPL_IB_UTIL_H_ +#define _OPENIB_SCM_ + +#include +#include "openib_osd.h" +#include "dapl_ib_common.h" + +/* DAPL CM objects MUST include list_entry, ref_count, event for EP linking */ +struct ib_cm_handle +{ + struct dapl_llist_entry list_entry; + struct dapl_llist_entry local_entry; + DAPL_OS_WAIT_OBJECT event; + DAPL_OS_LOCK lock; + int ref_count; + int state; + DAPL_SOCKET socket; + struct dapl_hca *hca; + struct dapl_sp *sp; + struct dapl_ep *ep; + ib_cm_msg_t msg; + struct ibv_ah *ah; + DAT_SOCK_ADDR6 addr; +}; + +typedef struct ib_cm_handle *dp_ib_cm_handle_t; +typedef dp_ib_cm_handle_t ib_cm_srvc_handle_t; + +/* Definitions */ +#define IB_INVALID_HANDLE NULL + +/* inline send rdma threshold */ +#define INLINE_SEND_DEFAULT 200 + +/* RC timer - retry count defaults */ +#define SCM_ACK_TIMER 16 /* 5 bits, 4.096us*2^ack_timer. 16== 268ms */ +#define SCM_ACK_RETRY 7 /* 3 bits, 7 * 268ms = 1.8 seconds */ +#define SCM_RNR_TIMER 12 /* 5 bits, 12 =.64ms, 28 =163ms, 31 =491ms */ +#define SCM_RNR_RETRY 7 /* 3 bits, 7 == infinite */ +#define SCM_IB_MTU 2048 + +/* Global routing defaults */ +#define SCM_GLOBAL 0 /* global routing is disabled */ +#define SCM_HOP_LIMIT 0xff +#define SCM_TCLASS 0 + +/* ib_hca_transport_t, specific to this implementation */ +typedef struct _ib_hca_transport +{ + struct dapl_llist_entry entry; + int destroy; + union ibv_gid gid; + struct ibv_device *ib_dev; + struct ibv_context *ib_ctx; + ib_cq_handle_t ib_cq_empty; + DAPL_OS_LOCK cq_lock; + int max_inline_send; + ib_thread_state_t cq_state; + DAPL_OS_THREAD cq_thread; + struct ibv_comp_channel *ib_cq; + int cr_state; + DAPL_OS_THREAD thread; + DAPL_OS_LOCK lock; + struct dapl_llist_entry *list; + ib_async_handler_t async_unafiliated; + void *async_un_ctx; + ib_async_cq_handler_t async_cq_error; + ib_async_dto_handler_t async_cq; + ib_async_qp_handler_t async_qp_error; + int rd_atom_in; + int rd_atom_out; + uint16_t lid; + uint8_t ack_timer; + uint8_t ack_retry; + uint8_t rnr_timer; + uint8_t rnr_retry; + uint8_t global; + uint8_t hop_limit; + uint8_t tclass; + uint8_t mtu; + DAT_NAMED_ATTR named_attr; + DAPL_SOCKET scm[2]; + uint8_t sl; + uint16_t pkey; + int pkey_idx; + +} ib_hca_transport_t; + +/* prototypes */ +void cr_thread(void *arg); +int dapli_cq_thread_init(struct dapl_hca *hca_ptr); +void dapli_cq_thread_destroy(struct dapl_hca *hca_ptr); +void dapli_async_event_cb(struct _ib_hca_transport *tp); +void dapli_cq_event_cb(struct _ib_hca_transport *tp); +void dapls_cm_acquire(dp_ib_cm_handle_t cm_ptr); +void dapls_cm_release(dp_ib_cm_handle_t cm_ptr); +void dapls_cm_free(dp_ib_cm_handle_t cm_ptr); + +#ifdef DAPL_COUNTERS +void dapls_print_cm_list(IN DAPL_IA *ia_ptr); +#endif + +#endif /* _DAPL_IB_UTIL_H_ */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/openib_scm/device.c b/branches/WOF2-3/ulp/dapl2/dapl/openib_scm/device.c new file mode 100644 index 00000000..4c50f034 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/openib_scm/device.c @@ -0,0 +1,773 @@ +/* + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/*************************************************************************** + * + * Module: uDAPL + * + * Filename: dapl_ib_util.c + * + * Author: Arlin Davis + * + * Created: 3/10/2005 + * + * Description: + * + * The uDAPL openib provider - init, open, close, utilities + * + **************************************************************************** + * Source Control System Information + * + * $Id: $ + * + * Copyright (c) 2005 Intel Corporation. All rights reserved. + * + **************************************************************************/ +#ifdef RCSID +static const char rcsid[] = "$Id: $"; +#endif + +#include "openib_osd.h" +#include "dapl.h" +#include "dapl_adapter_util.h" +#include "dapl_ib_util.h" +#include "dapl_osd.h" + +#include + +ib_thread_state_t g_ib_thread_state = 0; +DAPL_OS_THREAD g_ib_thread; +DAPL_OS_LOCK g_hca_lock; +struct dapl_llist_entry *g_hca_list; + +void dapli_thread(void *arg); +DAT_RETURN dapli_ib_thread_init(void); +void dapli_ib_thread_destroy(void); + +#if defined(_WIN64) || defined(_WIN32) +#include + +static COMP_SET ufds; + +static int dapls_os_init(void) +{ + return CompSetInit(&ufds); +} + +static void dapls_os_release(void) +{ + CompSetCleanup(&ufds); +} + +static int dapls_config_verbs(struct ibv_context *verbs) +{ + verbs->channel.Milliseconds = 0; + return 0; +} + +static int dapls_config_comp_channel(struct ibv_comp_channel *channel) +{ + channel->comp_channel.Milliseconds = 0; + return 0; +} + +static int dapls_thread_signal(void) +{ + CompSetCancel(&ufds); + return 0; +} +#else // _WIN64 || WIN32 +int g_ib_pipe[2]; + +static int dapls_os_init(void) +{ + /* create pipe for waking up work thread */ + return pipe(g_ib_pipe); +} + +static void dapls_os_release(void) +{ + /* close pipe? */ +} + +static int dapls_config_fd(int fd) +{ + int opts; + + opts = fcntl(fd, F_GETFL); + if (opts < 0 || fcntl(fd, F_SETFL, opts | O_NONBLOCK) < 0) { + dapl_log(DAPL_DBG_TYPE_ERR, + " dapls_config_fd: fcntl on fd %d ERR %d %s\n", + fd, opts, strerror(errno)); + return errno; + } + + return 0; +} + +static int dapls_config_verbs(struct ibv_context *verbs) +{ + return dapls_config_fd(verbs->async_fd); +} + +static int dapls_config_comp_channel(struct ibv_comp_channel *channel) +{ + return dapls_config_fd(channel->fd); +} + +static int dapls_thread_signal(void) +{ + return write(g_ib_pipe[1], "w", sizeof "w"); +} +#endif + + +static int32_t create_cr_pipe(IN DAPL_HCA * hca_ptr) +{ + DAPL_SOCKET listen_socket; + struct sockaddr_in addr; + socklen_t addrlen = sizeof(addr); + int ret; + + listen_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (listen_socket == DAPL_INVALID_SOCKET) + return 1; + + memset(&addr, 0, sizeof addr); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(0x7f000001); + ret = bind(listen_socket, (struct sockaddr *)&addr, sizeof addr); + if (ret) + goto err1; + + ret = getsockname(listen_socket, (struct sockaddr *)&addr, &addrlen); + if (ret) + goto err1; + + ret = listen(listen_socket, 0); + if (ret) + goto err1; + + hca_ptr->ib_trans.scm[1] = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (hca_ptr->ib_trans.scm[1] == DAPL_INVALID_SOCKET) + goto err1; + + ret = connect(hca_ptr->ib_trans.scm[1], + (struct sockaddr *)&addr, sizeof(addr)); + if (ret) + goto err2; + + hca_ptr->ib_trans.scm[0] = accept(listen_socket, NULL, NULL); + if (hca_ptr->ib_trans.scm[0] == DAPL_INVALID_SOCKET) + goto err2; + + closesocket(listen_socket); + return 0; + + err2: + closesocket(hca_ptr->ib_trans.scm[1]); + err1: + closesocket(listen_socket); + return 1; +} + +static void destroy_cr_pipe(IN DAPL_HCA * hca_ptr) +{ + closesocket(hca_ptr->ib_trans.scm[0]); + closesocket(hca_ptr->ib_trans.scm[1]); +} + + +/* + * dapls_ib_init, dapls_ib_release + * + * Initialize Verb related items for device open + * + * Input: + * none + * + * Output: + * none + * + * Returns: + * 0 success, -1 error + * + */ +DAT_UINT32 g_parent = 0; +int32_t dapls_ib_init(void) +{ + g_parent = dapl_os_getpid(); + + /* initialize hca_list */ + dapl_os_lock_init(&g_hca_lock); + dapl_llist_init_head(&g_hca_list); + + if (dapls_os_init()) + return 1; + + return 0; +} + +int32_t dapls_ib_release(void) +{ + /* only parent init will cleanup */ + if (dapl_os_getpid() != g_parent) + return 0; + + dapli_ib_thread_destroy(); + dapls_os_release(); + return 0; +} + +/* + * dapls_ib_open_hca + * + * Open HCA + * + * Input: + * *hca_name pointer to provider device name + * *ib_hca_handle_p pointer to provide HCA handle + * + * Output: + * none + * + * Return: + * DAT_SUCCESS + * dapl_convert_errno + * + */ +DAT_RETURN dapls_ib_open_hca(IN IB_HCA_NAME hca_name, IN DAPL_HCA * hca_ptr) +{ + struct ibv_device **dev_list; + struct ibv_port_attr port_attr; + int i; + DAT_RETURN dat_status; + + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, + " open_hca: %s - %p\n", hca_name, hca_ptr); + + /* get the IP address of the device */ + dat_status = getlocalipaddr((char *)&hca_ptr->hca_address, + sizeof(DAT_SOCK_ADDR6)); + if (dat_status != DAT_SUCCESS) + return dat_status; + +#ifdef DAPL_DBG + /* DBG: unused port, set process id, lower 16 bits of pid */ + ((struct sockaddr_in *)&hca_ptr->hca_address)->sin_port = + htons((uint16_t)dapl_os_getpid()); +#endif + /* Get list of all IB devices, find match, open */ + dev_list = ibv_get_device_list(NULL); + if (!dev_list) { + dapl_dbg_log(DAPL_DBG_TYPE_ERR, + " open_hca: ibv_get_device_list() failed\n", + hca_name); + return DAT_INTERNAL_ERROR; + } + + for (i = 0; dev_list[i]; ++i) { + hca_ptr->ib_trans.ib_dev = dev_list[i]; + if (!strcmp(ibv_get_device_name(hca_ptr->ib_trans.ib_dev), + hca_name)) + goto found; + } + + dapl_log(DAPL_DBG_TYPE_ERR, + " open_hca: device %s not found\n", hca_name); + goto err; + +found: + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, " open_hca: Found dev %s %016llx\n", + ibv_get_device_name(hca_ptr->ib_trans.ib_dev), + (unsigned long long) + ntohll(ibv_get_device_guid(hca_ptr->ib_trans.ib_dev))); + + hca_ptr->ib_hca_handle = ibv_open_device(hca_ptr->ib_trans.ib_dev); + if (!hca_ptr->ib_hca_handle) { + dapl_log(DAPL_DBG_TYPE_ERR, + " open_hca: dev open failed for %s, err=%s\n", + ibv_get_device_name(hca_ptr->ib_trans.ib_dev), + strerror(errno)); + goto err; + } + hca_ptr->ib_trans.ib_ctx = hca_ptr->ib_hca_handle; + dapls_config_verbs(hca_ptr->ib_hca_handle); + + /* get lid for this hca-port, network order */ + if (ibv_query_port(hca_ptr->ib_hca_handle, + (uint8_t) hca_ptr->port_num, &port_attr)) { + dapl_log(DAPL_DBG_TYPE_ERR, + " open_hca: get lid ERR for %s, err=%s\n", + ibv_get_device_name(hca_ptr->ib_trans.ib_dev), + strerror(errno)); + goto err; + } else { + hca_ptr->ib_trans.lid = htons(port_attr.lid); + } + + /* get gid for this hca-port, network order */ + if (ibv_query_gid(hca_ptr->ib_hca_handle, + (uint8_t) hca_ptr->port_num, + 0, &hca_ptr->ib_trans.gid)) { + dapl_log(DAPL_DBG_TYPE_ERR, + " open_hca: query GID ERR for %s, err=%s\n", + ibv_get_device_name(hca_ptr->ib_trans.ib_dev), + strerror(errno)); + goto err; + } + + /* set RC tunables via enviroment or default */ + hca_ptr->ib_trans.max_inline_send = + dapl_os_get_env_val("DAPL_MAX_INLINE", INLINE_SEND_DEFAULT); + hca_ptr->ib_trans.ack_retry = + dapl_os_get_env_val("DAPL_ACK_RETRY", SCM_ACK_RETRY); + hca_ptr->ib_trans.ack_timer = + dapl_os_get_env_val("DAPL_ACK_TIMER", SCM_ACK_TIMER); + hca_ptr->ib_trans.rnr_retry = + dapl_os_get_env_val("DAPL_RNR_RETRY", SCM_RNR_RETRY); + hca_ptr->ib_trans.rnr_timer = + dapl_os_get_env_val("DAPL_RNR_TIMER", SCM_RNR_TIMER); + hca_ptr->ib_trans.global = + dapl_os_get_env_val("DAPL_GLOBAL_ROUTING", SCM_GLOBAL); + hca_ptr->ib_trans.hop_limit = + dapl_os_get_env_val("DAPL_HOP_LIMIT", SCM_HOP_LIMIT); + hca_ptr->ib_trans.tclass = + dapl_os_get_env_val("DAPL_TCLASS", SCM_TCLASS); + hca_ptr->ib_trans.mtu = + dapl_ib_mtu(dapl_os_get_env_val("DAPL_IB_MTU", SCM_IB_MTU)); + + + /* EVD events without direct CQ channels, CNO support */ + hca_ptr->ib_trans.ib_cq = + ibv_create_comp_channel(hca_ptr->ib_hca_handle); + if (hca_ptr->ib_trans.ib_cq == NULL) { + dapl_log(DAPL_DBG_TYPE_ERR, + " open_hca: ibv_create_comp_channel ERR %s\n", + strerror(errno)); + goto bail; + } + dapls_config_comp_channel(hca_ptr->ib_trans.ib_cq); + + dat_status = dapli_ib_thread_init(); + if (dat_status != DAT_SUCCESS) { + dapl_log(DAPL_DBG_TYPE_ERR, + " open_hca: failed to init cq thread lock\n"); + goto bail; + } + /* + * Put new hca_transport on list for async and CQ event processing + * Wakeup work thread to add to polling list + */ + dapl_llist_init_entry((DAPL_LLIST_ENTRY *)&hca_ptr->ib_trans.entry); + dapl_os_lock(&g_hca_lock); + dapl_llist_add_tail(&g_hca_list, + (DAPL_LLIST_ENTRY *) &hca_ptr->ib_trans.entry, + &hca_ptr->ib_trans.entry); + if (dapls_thread_signal() == -1) + dapl_log(DAPL_DBG_TYPE_UTIL, + " open_hca: thread wakeup error = %s\n", + strerror(errno)); + dapl_os_unlock(&g_hca_lock); + + /* initialize cr_list lock */ + dat_status = dapl_os_lock_init(&hca_ptr->ib_trans.lock); + if (dat_status != DAT_SUCCESS) { + dapl_log(DAPL_DBG_TYPE_ERR, + " open_hca: failed to init cr_list lock\n"); + goto bail; + } + + /* initialize CM list for listens on this HCA */ + dapl_llist_init_head(&hca_ptr->ib_trans.list); + + /* initialize pipe, user level wakeup on select */ + if (create_cr_pipe(hca_ptr)) { + dapl_log(DAPL_DBG_TYPE_ERR, + " open_hca: failed to init cr pipe - %s\n", + strerror(errno)); + goto bail; + } + + /* create thread to process inbound connect request */ + hca_ptr->ib_trans.cr_state = IB_THREAD_INIT; + dat_status = dapl_os_thread_create(cr_thread, + (void *)hca_ptr, + &hca_ptr->ib_trans.thread); + if (dat_status != DAT_SUCCESS) { + dapl_log(DAPL_DBG_TYPE_ERR, + " open_hca: failed to create thread\n"); + goto bail; + } + + /* wait for thread */ + while (hca_ptr->ib_trans.cr_state != IB_THREAD_RUN) { + dapl_os_sleep_usec(1000); + } + + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, + " open_hca: devname %s, port %d, hostname_IP %s\n", + ibv_get_device_name(hca_ptr->ib_trans.ib_dev), + hca_ptr->port_num, inet_ntoa(((struct sockaddr_in *) + &hca_ptr->hca_address)-> + sin_addr)); + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, + " open_hca: LID 0x%x GID Subnet 0x" F64x " ID 0x" F64x + "\n", ntohs(hca_ptr->ib_trans.lid), (unsigned long long) + htonll(hca_ptr->ib_trans.gid.global.subnet_prefix), + (unsigned long long)htonll(hca_ptr->ib_trans.gid.global. + interface_id)); + + ibv_free_device_list(dev_list); + return dat_status; + + bail: + ibv_close_device(hca_ptr->ib_hca_handle); + hca_ptr->ib_hca_handle = IB_INVALID_HANDLE; + err: + ibv_free_device_list(dev_list); + return DAT_INTERNAL_ERROR; +} + +/* + * dapls_ib_close_hca + * + * Open HCA + * + * Input: + * DAPL_HCA provide CA handle + * + * Output: + * none + * + * Return: + * DAT_SUCCESS + * dapl_convert_errno + * + */ +DAT_RETURN dapls_ib_close_hca(IN DAPL_HCA * hca_ptr) +{ + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, " close_hca: %p\n", hca_ptr); + + dapl_os_lock(&g_hca_lock); + if (g_ib_thread_state != IB_THREAD_RUN) { + dapl_os_unlock(&g_hca_lock); + goto out; + } + dapl_os_unlock(&g_hca_lock); + + /* destroy cr_thread and lock */ + hca_ptr->ib_trans.cr_state = IB_THREAD_CANCEL; + send(hca_ptr->ib_trans.scm[1], "w", sizeof "w", 0); + while (hca_ptr->ib_trans.cr_state != IB_THREAD_EXIT) { + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, + " close_hca: waiting for cr_thread\n"); + send(hca_ptr->ib_trans.scm[1], "w", sizeof "w", 0); + dapl_os_sleep_usec(1000); + } + dapl_os_lock_destroy(&hca_ptr->ib_trans.lock); + destroy_cr_pipe(hca_ptr); /* no longer need pipe */ + + /* + * Remove hca from async event processing list + * Wakeup work thread to remove from polling list + */ + hca_ptr->ib_trans.destroy = 1; + if (dapls_thread_signal() == -1) + dapl_log(DAPL_DBG_TYPE_UTIL, + " destroy: thread wakeup error = %s\n", + strerror(errno)); + + /* wait for thread to remove HCA references */ + while (hca_ptr->ib_trans.destroy != 2) { + if (dapls_thread_signal() == -1) + dapl_log(DAPL_DBG_TYPE_UTIL, + " destroy: thread wakeup error = %s\n", + strerror(errno)); + dapl_os_sleep_usec(1000); + } + +out: + if (hca_ptr->ib_trans.ib_cq) + ibv_destroy_comp_channel(hca_ptr->ib_trans.ib_cq); + + if (hca_ptr->ib_trans.ib_cq_empty) { + struct ibv_comp_channel *channel; + channel = hca_ptr->ib_trans.ib_cq_empty->channel; + ibv_destroy_cq(hca_ptr->ib_trans.ib_cq_empty); + ibv_destroy_comp_channel(channel); + } + + if (hca_ptr->ib_hca_handle != IB_INVALID_HANDLE) { + if (ibv_close_device(hca_ptr->ib_hca_handle)) + return (dapl_convert_errno(errno, "ib_close_device")); + hca_ptr->ib_hca_handle = IB_INVALID_HANDLE; + } + return (DAT_SUCCESS); +} + +DAT_RETURN dapli_ib_thread_init(void) +{ + DAT_RETURN dat_status; + + dapl_os_lock(&g_hca_lock); + if (g_ib_thread_state != IB_THREAD_INIT) { + dapl_os_unlock(&g_hca_lock); + return DAT_SUCCESS; + } + + g_ib_thread_state = IB_THREAD_CREATE; + dapl_os_unlock(&g_hca_lock); + + /* create thread to process inbound connect request */ + dat_status = dapl_os_thread_create(dapli_thread, NULL, &g_ib_thread); + if (dat_status != DAT_SUCCESS) + return (dapl_convert_errno(errno, + "create_thread ERR:" + " check resource limits")); + + /* wait for thread to start */ + dapl_os_lock(&g_hca_lock); + while (g_ib_thread_state != IB_THREAD_RUN) { + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, + " ib_thread_init: waiting for ib_thread\n"); + dapl_os_unlock(&g_hca_lock); + dapl_os_sleep_usec(1000); + dapl_os_lock(&g_hca_lock); + } + dapl_os_unlock(&g_hca_lock); + + return DAT_SUCCESS; +} + +void dapli_ib_thread_destroy(void) +{ + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, + " ib_thread_destroy(%d)\n", dapl_os_getpid()); + /* + * wait for async thread to terminate. + * pthread_join would be the correct method + * but some applications have some issues + */ + + /* destroy ib_thread, wait for termination, if not already */ + dapl_os_lock(&g_hca_lock); + if (g_ib_thread_state != IB_THREAD_RUN) + goto bail; + + g_ib_thread_state = IB_THREAD_CANCEL; + while (g_ib_thread_state != IB_THREAD_EXIT) { + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, + " ib_thread_destroy: waiting for ib_thread\n"); + if (dapls_thread_signal() == -1) + dapl_log(DAPL_DBG_TYPE_UTIL, + " destroy: thread wakeup error = %s\n", + strerror(errno)); + dapl_os_unlock(&g_hca_lock); + dapl_os_sleep_usec(2000); + dapl_os_lock(&g_hca_lock); + } +bail: + dapl_os_unlock(&g_hca_lock); + + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, + " ib_thread_destroy(%d) exit\n", dapl_os_getpid()); +} + + +#if defined(_WIN64) || defined(_WIN32) +/* work thread for uAT, uCM, CQ, and async events */ +void dapli_thread(void *arg) +{ + struct _ib_hca_transport *hca; + struct _ib_hca_transport *uhca[8]; + int ret, idx, cnt; + + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, " ib_thread(%d,0x%x): ENTER: \n", + dapl_os_getpid(), g_ib_thread); + + dapl_os_lock(&g_hca_lock); + for (g_ib_thread_state = IB_THREAD_RUN; + g_ib_thread_state == IB_THREAD_RUN; + dapl_os_lock(&g_hca_lock)) { + + CompSetZero(&ufds); + idx = 0; + hca = dapl_llist_is_empty(&g_hca_list) ? NULL : + dapl_llist_peek_head(&g_hca_list); + + while (hca) { + CompSetAdd(&hca->ib_ctx->channel, &ufds); + CompSetAdd(&hca->ib_cq->comp_channel, &ufds); + uhca[idx++] = hca; + hca = dapl_llist_next_entry(&g_hca_list, + (DAPL_LLIST_ENTRY *) + &hca->entry); + } + cnt = idx; + + dapl_os_unlock(&g_hca_lock); + ret = CompSetPoll(&ufds, INFINITE); + + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, + " ib_thread(%d) poll_event 0x%x\n", + dapl_os_getpid(), ret); + + + /* check and process ASYNC events, per device */ + for (idx = 0; idx < cnt; idx++) { + if (uhca[idx]->destroy == 1) { + dapl_os_lock(&g_hca_lock); + dapl_llist_remove_entry(&g_hca_list, + (DAPL_LLIST_ENTRY *) + &uhca[idx]->entry); + dapl_os_unlock(&g_hca_lock); + uhca[idx]->destroy = 2; + } else { + dapli_cq_event_cb(uhca[idx]); + dapli_async_event_cb(uhca[idx]); + } + } + } + + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, " ib_thread(%d) EXIT\n", + dapl_os_getpid()); + g_ib_thread_state = IB_THREAD_EXIT; + dapl_os_unlock(&g_hca_lock); +} +#else // _WIN64 || WIN32 + +/* work thread for uAT, uCM, CQ, and async events */ +void dapli_thread(void *arg) +{ + struct pollfd ufds[__FD_SETSIZE]; + struct _ib_hca_transport *uhca[__FD_SETSIZE] = { NULL }; + struct _ib_hca_transport *hca; + int ret, idx, fds; + char rbuf[2]; + + dapl_dbg_log(DAPL_DBG_TYPE_THREAD, + " ib_thread(%d,0x%x): ENTER: pipe %d \n", + dapl_os_getpid(), g_ib_thread, g_ib_pipe[0]); + + /* Poll across pipe, CM, AT never changes */ + dapl_os_lock(&g_hca_lock); + g_ib_thread_state = IB_THREAD_RUN; + + ufds[0].fd = g_ib_pipe[0]; /* pipe */ + ufds[0].events = POLLIN; + + while (g_ib_thread_state == IB_THREAD_RUN) { + + /* build ufds after pipe and uCMA events */ + ufds[0].revents = 0; + idx = 0; + + /* Walk HCA list and setup async and CQ events */ + if (!dapl_llist_is_empty(&g_hca_list)) + hca = dapl_llist_peek_head(&g_hca_list); + else + hca = NULL; + + while (hca) { + + /* uASYNC events */ + ufds[++idx].fd = hca->ib_ctx->async_fd; + ufds[idx].events = POLLIN; + ufds[idx].revents = 0; + uhca[idx] = hca; + + /* CQ events are non-direct with CNO's */ + ufds[++idx].fd = hca->ib_cq->fd; + ufds[idx].events = POLLIN; + ufds[idx].revents = 0; + uhca[idx] = hca; + + dapl_dbg_log(DAPL_DBG_TYPE_THREAD, + " ib_thread(%d) poll_fd: hca[%d]=%p," + " async=%d pipe=%d \n", + dapl_os_getpid(), hca, ufds[idx - 1].fd, + ufds[0].fd); + + hca = dapl_llist_next_entry(&g_hca_list, + (DAPL_LLIST_ENTRY *) + &hca->entry); + } + + /* unlock, and setup poll */ + fds = idx + 1; + dapl_os_unlock(&g_hca_lock); + ret = poll(ufds, fds, -1); + if (ret <= 0) { + dapl_dbg_log(DAPL_DBG_TYPE_THREAD, + " ib_thread(%d): ERR %s poll\n", + dapl_os_getpid(), strerror(errno)); + dapl_os_lock(&g_hca_lock); + continue; + } + + dapl_dbg_log(DAPL_DBG_TYPE_THREAD, + " ib_thread(%d) poll_event: " + " async=0x%x pipe=0x%x \n", + dapl_os_getpid(), ufds[idx].revents, + ufds[0].revents); + + /* check and process CQ and ASYNC events, per device */ + for (idx = 1; idx < fds; idx++) { + if (ufds[idx].revents == POLLIN) { + dapli_cq_event_cb(uhca[idx]); + dapli_async_event_cb(uhca[idx]); + } + } + + /* check and process user events, PIPE */ + if (ufds[0].revents == POLLIN) { + if (read(g_ib_pipe[0], rbuf, 2) == -1) + dapl_log(DAPL_DBG_TYPE_THREAD, + " cr_thread: pipe rd err= %s\n", + strerror(errno)); + + /* cleanup any device on list marked for destroy */ + for (idx = 1; idx < fds; idx++) { + if (uhca[idx] && uhca[idx]->destroy == 1) { + dapl_os_lock(&g_hca_lock); + dapl_llist_remove_entry( + &g_hca_list, + (DAPL_LLIST_ENTRY*) + &uhca[idx]->entry); + dapl_os_unlock(&g_hca_lock); + uhca[idx]->destroy = 2; + } + } + } + dapl_os_lock(&g_hca_lock); + } + + dapl_dbg_log(DAPL_DBG_TYPE_THREAD, " ib_thread(%d) EXIT\n", + dapl_os_getpid()); + g_ib_thread_state = IB_THREAD_EXIT; + dapl_os_unlock(&g_hca_lock); +} +#endif diff --git a/branches/WOF2-3/ulp/dapl2/dapl/openib_scm/linux/openib_osd.h b/branches/WOF2-3/ulp/dapl2/dapl/openib_scm/linux/openib_osd.h new file mode 100644 index 00000000..a0151886 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/openib_scm/linux/openib_osd.h @@ -0,0 +1,21 @@ +#ifndef OPENIB_OSD_H +#define OPENIB_OSD_H + +#include +#include + +#if __BYTE_ORDER == __BIG_ENDIAN +#define htonll(x) (x) +#define ntohll(x) (x) +#elif __BYTE_ORDER == __LITTLE_ENDIAN +#define htonll(x) bswap_64(x) +#define ntohll(x) bswap_64(x) +#endif + +#define DAPL_SOCKET int +#define DAPL_INVALID_SOCKET -1 +#define DAPL_FD_SETSIZE 16384 + +#define closesocket close + +#endif // OPENIB_OSD_H diff --git a/branches/WOF2-3/ulp/dapl2/dapl/openib_scm/makefile b/branches/WOF2-3/ulp/dapl2/dapl/openib_scm/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/openib_scm/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\..\inc\openib.def diff --git a/branches/WOF2-3/ulp/dapl2/dapl/openib_scm/udapl.rc b/branches/WOF2-3/ulp/dapl2/dapl/openib_scm/udapl.rc new file mode 100644 index 00000000..85502564 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/openib_scm/udapl.rc @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2007, 2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#if DBG +#define VER_FILEDESCRIPTION_STR "Direct Access Provider Library v2.0 (OFA socket-cm) (Debug)" +#define VER_INTERNALNAME_STR "dapl2-ofa-scmd.dll" +#define VER_ORIGINALFILENAME_STR "dapl2-ofa-scmd.dll" +#else +#define VER_FILEDESCRIPTION_STR "Direct Access Provider Library v2.0 (OFA socket-cm)" +#define VER_INTERNALNAME_STR "dapl2-ofa-scm.dll" +#define VER_ORIGINALFILENAME_STR "dapl2-ofa-scm.dll" +#endif + +#include diff --git a/branches/WOF2-3/ulp/dapl2/dapl/openib_scm/udapl_ofa_scm_exports.src b/branches/WOF2-3/ulp/dapl2/dapl/openib_scm/udapl_ofa_scm_exports.src new file mode 100644 index 00000000..cc1a7a37 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/openib_scm/udapl_ofa_scm_exports.src @@ -0,0 +1,14 @@ +#if DBG +LIBRARY dapl2-ofa-scmd.dll +#else +LIBRARY dapl2-ofa-scm.dll +#endif + + +EXPORTS +dat_provider_init +dat_provider_fini +#ifdef DAT_EXTENSIONS +dapl_extensions +#endif + diff --git a/branches/WOF2-3/ulp/dapl2/dapl/openib_scm/windows/openib_osd.h b/branches/WOF2-3/ulp/dapl2/dapl/openib_scm/windows/openib_osd.h new file mode 100644 index 00000000..0745107f --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/openib_scm/windows/openib_osd.h @@ -0,0 +1,39 @@ +#ifndef OPENIB_OSD_H +#define OPENIB_OSD_H + +#if defined(FD_SETSIZE) && FD_SETSIZE != 1024 +#undef FD_SETSIZE +#undef DAPL_FD_SETSIZE +#endif + +#define FD_SETSIZE 1024 /* Set before including winsock2 - see select help */ +#define DAPL_FD_SETSIZE FD_SETSIZE + +#include +#include +#include +#include + +#define ntohll _byteswap_uint64 +#define htonll _byteswap_uint64 + +#define DAPL_SOCKET SOCKET +#define DAPL_INVALID_SOCKET INVALID_SOCKET +#define SHUT_RDWR SD_BOTH + +/* allow casting to WSABUF */ +struct iovec +{ + u_long iov_len; + char FAR* iov_base; +}; + +static int writev(DAPL_SOCKET s, struct iovec *vector, int count) +{ + int len, ret; + + ret = WSASend(s, (WSABUF *) vector, count, &len, 0, NULL, NULL); + return ret ? ret : len; +} + +#endif // OPENIB_OSD_H diff --git a/branches/WOF2-3/ulp/dapl2/dapl/openib_ucm/README b/branches/WOF2-3/ulp/dapl2/dapl/openib_ucm/README new file mode 100644 index 00000000..239dfe69 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/openib_ucm/README @@ -0,0 +1,40 @@ + +OpenIB uDAPL provider using socket-based CM, in leiu of uCM/uAT, to setup QP/channels. + +to build: + +cd dapl/udapl +make VERBS=openib_scm clean +make VERBS=openib_scm + + +Modifications to common code: + +- added dapl/openib_scm directory + + dapl/udapl/Makefile + +New files for openib_scm provider + + dapl/openib/dapl_ib_cq.c + dapl/openib/dapl_ib_dto.h + dapl/openib/dapl_ib_mem.c + dapl/openib/dapl_ib_qp.c + dapl/openib/dapl_ib_util.c + dapl/openib/dapl_ib_util.h + dapl/openib/dapl_ib_cm.c + +A simple dapl test just for openib_scm testing... + + test/dtest/dtest.c + test/dtest/makefile + + server: dtest -s + client: dtest -h hostname + +known issues: + + no memory windows support in ibverbs, dat_create_rmr fails. + + + diff --git a/branches/WOF2-3/ulp/dapl2/dapl/openib_ucm/SOURCES b/branches/WOF2-3/ulp/dapl2/dapl/openib_ucm/SOURCES new file mode 100644 index 00000000..381afa23 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/openib_ucm/SOURCES @@ -0,0 +1,48 @@ +!if $(FREEBUILD) +TARGETNAME=dapl2-ofa-ucm +!else +TARGETNAME=dapl2-ofa-ucmd +!endif + +TARGETPATH = ..\..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = DYNLINK +DLLENTRY = _DllMainCRTStartup + +!if $(_NT_TOOLS_VERSION) == 0x700 +DLLDEF=$O\udapl_ofa_ucm_exports.def +!else +DLLDEF=$(OBJ_PATH)\$O\udapl_ofa_ucm_exports.def +!endif + +USE_MSVCRT = 1 + +SOURCES = udapl.rc ..\dapl_common_src.c ..\dapl_udapl_src.c ..\openib_common.c \ + device.c cm.c + +INCLUDES = ..\include;..\openib_common\;..\common;windows;..\..\dat\include;\ + ..\..\dat\udat\windows;..\udapl\windows;\ + ..\..\..\..\inc;..\..\..\..\inc\user;..\..\..\libibverbs\include;\ + ..\..\..\..\inc\user\linux; + +DAPL_OPTS = -DEXPORT_DAPL_SYMBOLS -DDAT_EXTENSIONS -DOPENIB -DCQ_WAIT_OBJECT + +USER_C_FLAGS = $(USER_C_FLAGS) $(DAPL_OPTS) + +!if !$(FREEBUILD) +USER_C_FLAGS = $(USER_C_FLAGS) -DDAPL_DBG +!endif + +TARGETLIBS= \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\dat2.lib \ + $(TARGETPATH)\*\winverbs.lib \ + $(TARGETPATH)\*\libibverbs.lib +!else + $(TARGETPATH)\*\dat2d.lib \ + $(TARGETPATH)\*\winverbsd.lib \ + $(TARGETPATH)\*\libibverbsd.lib +!endif + +MSC_WARNING_LEVEL = /W1 /wd4113 diff --git a/branches/WOF2-3/ulp/dapl2/dapl/openib_ucm/cm.c b/branches/WOF2-3/ulp/dapl2/dapl/openib_ucm/cm.c new file mode 100644 index 00000000..c5c125a4 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/openib_ucm/cm.c @@ -0,0 +1,2166 @@ +/* + * Copyright (c) 2009 Intel Corporation. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl.h" +#include "dapl_adapter_util.h" +#include "dapl_evd_util.h" +#include "dapl_cr_util.h" +#include "dapl_name_service.h" +#include "dapl_ib_util.h" +#include "dapl_ep_util.h" +#include "dapl_osd.h" + + +#if defined(_WIN32) +#include +#else // _WIN32 +enum DAPL_FD_EVENTS { + DAPL_FD_READ = POLLIN, + DAPL_FD_WRITE = POLLOUT, + DAPL_FD_ERROR = POLLERR +}; + +struct dapl_fd_set { + int index; + struct pollfd set[DAPL_FD_SETSIZE]; +}; + +static struct dapl_fd_set *dapl_alloc_fd_set(void) +{ + return dapl_os_alloc(sizeof(struct dapl_fd_set)); +} + +static void dapl_fd_zero(struct dapl_fd_set *set) +{ + set->index = 0; +} + +static int dapl_fd_set(DAPL_SOCKET s, struct dapl_fd_set *set, + enum DAPL_FD_EVENTS event) +{ + if (set->index == DAPL_FD_SETSIZE - 1) { + dapl_log(DAPL_DBG_TYPE_ERR, + "SCM ERR: cm_thread exceeded FD_SETSIZE %d\n", + set->index + 1); + return -1; + } + + set->set[set->index].fd = s; + set->set[set->index].revents = 0; + set->set[set->index++].events = event; + return 0; +} + +static enum DAPL_FD_EVENTS dapl_poll(DAPL_SOCKET s, enum DAPL_FD_EVENTS event) +{ + struct pollfd fds; + int ret; + + fds.fd = s; + fds.events = event; + fds.revents = 0; + ret = poll(&fds, 1, 0); + dapl_log(DAPL_DBG_TYPE_CM, " dapl_poll: fd=%d ret=%d, evnts=0x%x\n", + s, ret, fds.revents); + if (ret == 0) + return 0; + else if (fds.revents & (POLLERR | POLLHUP | POLLNVAL)) + return DAPL_FD_ERROR; + else + return fds.revents; +} + +static int dapl_select(struct dapl_fd_set *set, int time_ms) +{ + int ret; + + dapl_dbg_log(DAPL_DBG_TYPE_CM, " dapl_select: sleep, fds=%d\n", + set->index); + ret = poll(set->set, set->index, time_ms); + dapl_dbg_log(DAPL_DBG_TYPE_CM, " dapl_select: wakeup, ret=0x%x\n", ret); + return ret; +} +#endif + +/* forward declarations */ +static int ucm_reply(dp_ib_cm_handle_t cm); +static void ucm_accept(ib_cm_srvc_handle_t cm, ib_cm_msg_t *msg); +static void ucm_connect_rtu(dp_ib_cm_handle_t cm, ib_cm_msg_t *msg); +static void ucm_accept_rtu(dp_ib_cm_handle_t cm, ib_cm_msg_t *msg); +static int ucm_send(ib_hca_transport_t *tp, ib_cm_msg_t *msg, DAT_PVOID p_data, DAT_COUNT p_size); +static void ucm_disconnect_final(dp_ib_cm_handle_t cm); +DAT_RETURN dapli_cm_disconnect(dp_ib_cm_handle_t cm); +DAT_RETURN dapli_cm_connect(DAPL_EP *ep, dp_ib_cm_handle_t cm); + +#define UCM_SND_BURST 50 + +/* Service ids - port space */ +static uint16_t ucm_get_port(ib_hca_transport_t *tp, uint16_t port) +{ + int i = 0; + + dapl_os_lock(&tp->plock); + /* get specific ID */ + if (port) { + if (tp->sid[port] == 0) { + tp->sid[port] = 1; + i = port; + } + goto done; + } + + /* get any free ID */ + for (i = 0xffff; i > 0; i--) { + if (tp->sid[i] == 0) { + tp->sid[i] = 1; + break; + } + } +done: + dapl_os_unlock(&tp->plock); + return i; +} + +static void ucm_free_port(ib_hca_transport_t *tp, uint16_t port) +{ + dapl_os_lock(&tp->plock); + tp->sid[port] = 0; + dapl_os_unlock(&tp->plock); +} + +static void ucm_check_timers(dp_ib_cm_handle_t cm, int *timer) +{ + DAPL_OS_TIMEVAL time; + + dapl_os_lock(&cm->lock); + dapl_os_get_time(&time); + switch (cm->state) { + case DCM_REP_PENDING: + *timer = cm->hca->ib_trans.cm_timer; + /* wait longer each retry */ + if ((time - cm->timer)/1000 > + (cm->hca->ib_trans.rep_time << cm->retries)) { + dapl_log(DAPL_DBG_TYPE_CM_WARN, + " CM_REQ retry %p %d [lid, port, qpn]:" + " %x %x %x -> %x %x %x Time(ms) %llu > %d\n", + cm, cm->retries+1, ntohs(cm->msg.saddr.ib.lid), + ntohs(cm->msg.sport), ntohl(cm->msg.saddr.ib.qpn), + ntohs(cm->msg.daddr.ib.lid), ntohs(cm->msg.dport), + ntohl(cm->msg.dqpn), (time - cm->timer)/1000, + cm->hca->ib_trans.rep_time << cm->retries); + cm->retries++; + dapl_os_unlock(&cm->lock); + dapli_cm_connect(cm->ep, cm); + return; + } + break; + case DCM_RTU_PENDING: + *timer = cm->hca->ib_trans.cm_timer; + if ((time - cm->timer)/1000 > + (cm->hca->ib_trans.rtu_time << cm->retries)) { + dapl_log(DAPL_DBG_TYPE_CM_WARN, + " CM_REPLY retry %d [lid, port, qpn]:" + " %x %x %x -> %x %x %x r_pid %x (%x) Time(ms) %llu > %d\n", + cm->retries+1, + ntohs(cm->msg.saddr.ib.lid), + ntohs(cm->msg.sport), + ntohl(cm->msg.saddr.ib.qpn), + ntohs(cm->msg.daddr.ib.lid), + ntohs(cm->msg.dport), + ntohl(cm->msg.daddr.ib.qpn), + ntohl(*(DAT_UINT32*)cm->msg.resv), + ntohl(*(DAT_UINT32*)cm->msg.resv), + (time - cm->timer)/1000, + cm->hca->ib_trans.rtu_time << cm->retries); + cm->retries++; + dapl_os_unlock(&cm->lock); + ucm_reply(cm); + return; + } + break; + case DCM_DISC_PENDING: + *timer = cm->hca->ib_trans.cm_timer; + /* wait longer each retry */ + if ((time - cm->timer)/1000 > + (cm->hca->ib_trans.rtu_time << cm->retries)) { + dapl_log(DAPL_DBG_TYPE_CM_WARN, + " CM_DREQ retry %d [lid, port, qpn]:" + " %x %x %x -> %x %x %x r_pid %x (%x) Time(ms) %llu > %d\n", + cm->retries+1, + ntohs(cm->msg.saddr.ib.lid), + ntohs(cm->msg.sport), + ntohl(cm->msg.saddr.ib.qpn), + ntohs(cm->msg.daddr.ib.lid), + ntohs(cm->msg.dport), + ntohl(cm->msg.dqpn), + ntohl(*(DAT_UINT32*)cm->msg.resv), + ntohl(*(DAT_UINT32*)cm->msg.resv), + (time - cm->timer)/1000, + cm->hca->ib_trans.rtu_time << cm->retries); + cm->retries++; + dapl_os_unlock(&cm->lock); + dapli_cm_disconnect(cm); + return; + } + break; + default: + break; + } + dapl_os_unlock(&cm->lock); +} + +/* SEND CM MESSAGE PROCESSING */ + +/* Get CM UD message from send queue, called with s_lock held */ +static ib_cm_msg_t *ucm_get_smsg(ib_hca_transport_t *tp) +{ + ib_cm_msg_t *msg = NULL; + int ret, polled = 0, hd = tp->s_hd; + + hd++; +retry: + if (hd == tp->qpe) + hd = 0; + + if (hd == tp->s_tl) + msg = NULL; + else { + msg = &tp->sbuf[hd]; + tp->s_hd = hd; /* new hd */ + } + + /* if empty, process some completions */ + if ((msg == NULL) && (!polled)) { + struct ibv_wc wc; + + /* process completions, based on UCM_SND_BURST */ + ret = ibv_poll_cq(tp->scq, 1, &wc); + if (ret < 0) { + dapl_log(DAPL_DBG_TYPE_WARN, + " get_smsg: cq %p %s\n", + tp->scq, strerror(errno)); + } + /* free up completed sends, update tail */ + if (ret > 0) { + tp->s_tl = (int)wc.wr_id; + dapl_log(DAPL_DBG_TYPE_CM, + " get_smsg: wr_cmp (%d) s_tl=%d\n", + wc.status, tp->s_tl); + } + polled++; + goto retry; + } + return msg; +} + +/* RECEIVE CM MESSAGE PROCESSING */ + +static int ucm_post_rmsg(ib_hca_transport_t *tp, ib_cm_msg_t *msg) +{ + struct ibv_recv_wr recv_wr, *recv_err; + struct ibv_sge sge; + + recv_wr.next = NULL; + recv_wr.sg_list = &sge; + recv_wr.num_sge = 1; + recv_wr.wr_id = (uint64_t)(uintptr_t) msg; + sge.length = sizeof(ib_cm_msg_t) + sizeof(struct ibv_grh); + sge.lkey = tp->mr_rbuf->lkey; + sge.addr = (uintptr_t)((char *)msg - sizeof(struct ibv_grh)); + + return (ibv_post_recv(tp->qp, &recv_wr, &recv_err)); +} + +static int ucm_reject(ib_hca_transport_t *tp, ib_cm_msg_t *msg) +{ + ib_cm_msg_t smsg; + + /* setup op, rearrange the src, dst cm and addr info */ + (void)dapl_os_memzero(&smsg, sizeof(smsg)); + smsg.ver = htons(DCM_VER); + smsg.op = htons(DCM_REJ_CM); + smsg.dport = msg->sport; + smsg.dqpn = msg->sqpn; + smsg.sport = msg->dport; + smsg.sqpn = msg->dqpn; + + dapl_os_memcpy(&smsg.daddr, &msg->saddr, sizeof(union dcm_addr)); + + /* no dst_addr IB info in REQ, init lid, gid, get type from saddr */ + smsg.saddr.ib.lid = tp->addr.ib.lid; + smsg.saddr.ib.qp_type = msg->saddr.ib.qp_type; + dapl_os_memcpy(&smsg.saddr.ib.gid[0], + &tp->addr.ib.gid, 16); + + dapl_os_memcpy(&smsg.saddr, &msg->daddr, sizeof(union dcm_addr)); + + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " CM reject -> LID %x, QPN %x PORT %x\n", + ntohs(smsg.daddr.ib.lid), + ntohl(smsg.dqpn), ntohs(smsg.dport)); + + return (ucm_send(tp, &smsg, NULL, 0)); +} + +static void ucm_process_recv(ib_hca_transport_t *tp, + ib_cm_msg_t *msg, + dp_ib_cm_handle_t cm) +{ + dapl_os_lock(&cm->lock); + switch (cm->state) { + case DCM_LISTEN: /* passive */ + dapl_os_unlock(&cm->lock); + ucm_accept(cm, msg); + break; + case DCM_RTU_PENDING: /* passive */ + dapl_os_unlock(&cm->lock); + ucm_accept_rtu(cm, msg); + break; + case DCM_REP_PENDING: /* active */ + dapl_os_unlock(&cm->lock); + ucm_connect_rtu(cm, msg); + break; + case DCM_CONNECTED: /* active and passive */ + /* DREQ, change state and process */ + if (ntohs(msg->op) == DCM_DREQ) { + cm->state = DCM_DISC_RECV; + dapl_os_unlock(&cm->lock); + dapli_cm_disconnect(cm); + break; + } + /* active: RTU was dropped, resend */ + if (ntohs(msg->op) == DCM_REP) { + dapl_log(DAPL_DBG_TYPE_CM_WARN, + " RESEND RTU: op %s st %s [lid, port, qpn]:" + " %x %x %x -> %x %x %x\n", + dapl_cm_op_str(ntohs(msg->op)), + dapl_cm_state_str(cm->state), + ntohs(msg->saddr.ib.lid), + ntohs(msg->sport), + ntohl(msg->saddr.ib.qpn), + ntohs(msg->daddr.ib.lid), + ntohs(msg->dport), + ntohl(msg->daddr.ib.qpn)); + + cm->msg.op = htons(DCM_RTU); + ucm_send(&cm->hca->ib_trans, &cm->msg, NULL, 0); + } + dapl_os_unlock(&cm->lock); + break; + case DCM_DISC_PENDING: /* active and passive */ + /* DREQ or DREP, finalize */ + dapl_os_unlock(&cm->lock); + ucm_disconnect_final(cm); + break; + case DCM_DISCONNECTED: + case DCM_FREE: + /* DREQ dropped, resend */ + if (ntohs(msg->op) == DCM_DREQ) { + dapl_log(DAPL_DBG_TYPE_CM_WARN, + " RESEND DREP: op %s st %s [lid, port, qpn]:" + " %x %x %x -> %x %x %x\n", + dapl_cm_op_str(ntohs(msg->op)), + dapl_cm_state_str(cm->state), + ntohs(msg->saddr.ib.lid), + ntohs(msg->sport), + ntohl(msg->saddr.ib.qpn), + ntohs(msg->daddr.ib.lid), + ntohs(msg->dport), + ntohl(msg->daddr.ib.qpn)); + cm->msg.op = htons(DCM_DREP); + ucm_send(&cm->hca->ib_trans, &cm->msg, NULL, 0); + + } else if (ntohs(msg->op) != DCM_DREP){ + /* DREP ok to ignore, any other print warning */ + dapl_log(DAPL_DBG_TYPE_WARN, + " ucm_recv: UNEXPECTED MSG on cm %p" + " <- op %s, st %s spsp %x sqpn %x\n", + cm, dapl_cm_op_str(ntohs(msg->op)), + dapl_cm_state_str(cm->state), + ntohs(msg->sport), ntohl(msg->sqpn)); + } + dapl_os_unlock(&cm->lock); + break; + default: + dapl_log(DAPL_DBG_TYPE_WARN, + " ucm_recv: UNKNOWN state" + " <- op %s, %s spsp %x sqpn %x\n", + dapl_cm_op_str(ntohs(msg->op)), + dapl_cm_state_str(cm->state), + ntohs(msg->sport), ntohl(msg->sqpn)); + dapl_os_unlock(&cm->lock); + break; + } +} + +/* Find matching CM object for this receive message, return CM reference, timer */ +dp_ib_cm_handle_t ucm_cm_find(ib_hca_transport_t *tp, ib_cm_msg_t *msg) +{ + dp_ib_cm_handle_t cm, next, found = NULL; + struct dapl_llist_entry **list; + DAPL_OS_LOCK *lock; + int listenq = 0; + + /* conn list first, duplicate requests for DCM_REQ */ + list = &tp->list; + lock = &tp->lock; + +retry_listenq: + dapl_os_lock(lock); + if (!dapl_llist_is_empty(list)) + next = dapl_llist_peek_head(list); + else + next = NULL; + + while (next) { + cm = next; + next = dapl_llist_next_entry(list, + (DAPL_LLIST_ENTRY *)&cm->local_entry); + if (cm->state == DCM_DESTROY || cm->state == DCM_FREE) + continue; + + /* CM sPORT + QPN, match is good enough for listenq */ + if (listenq && + cm->msg.sport == msg->dport && + cm->msg.sqpn == msg->dqpn) { + found = cm; + break; + } + /* connectq, check src and dst, check duplicate conn_reqs */ + if (!listenq && + cm->msg.sport == msg->dport && cm->msg.sqpn == msg->dqpn && + cm->msg.dport == msg->sport && cm->msg.dqpn == msg->sqpn && + cm->msg.daddr.ib.lid == msg->saddr.ib.lid) { + if (ntohs(msg->op) != DCM_REQ) { + found = cm; + break; + } else { + /* duplicate; bail and throw away */ + dapl_os_unlock(lock); + dapl_log(DAPL_DBG_TYPE_CM_WARN, + " DUPLICATE: cm %p op %s st %s [lid, port, qpn]:" + " %x %x %x <- %x %x %x\n", cm, + dapl_cm_op_str(ntohs(msg->op)), + dapl_cm_state_str(cm->state), + ntohs(msg->daddr.ib.lid), + ntohs(msg->dport), + ntohl(msg->daddr.ib.qpn), + ntohs(msg->saddr.ib.lid), + ntohs(msg->sport), + ntohl(msg->saddr.ib.qpn)); + + return NULL; + } + } + } + dapl_os_unlock(lock); + + /* no duplicate request on connq, check listenq for new request */ + if (ntohs(msg->op) == DCM_REQ && !listenq && !found) { + listenq = 1; + list = &tp->llist; + lock = &tp->llock; + goto retry_listenq; + } + + /* not match on listenq for valid request, send reject */ + if (ntohs(msg->op) == DCM_REQ && !found) { + dapl_log(DAPL_DBG_TYPE_WARN, + " ucm_recv: NO LISTENER for %s %x %x i%x c%x" + " < %x %x %x, sending reject\n", + dapl_cm_op_str(ntohs(msg->op)), + ntohs(msg->daddr.ib.lid), ntohs(msg->dport), + ntohl(msg->daddr.ib.qpn), ntohl(msg->sqpn), + ntohs(msg->saddr.ib.lid), ntohs(msg->sport), + ntohl(msg->saddr.ib.qpn)); + + ucm_reject(tp, msg); + } + + if (!found) { + dapl_log(DAPL_DBG_TYPE_CM, + " ucm_recv: NO MATCH op %s %x %x i%x c%x" + " < %x %x %x\n", + dapl_cm_op_str(ntohs(msg->op)), + ntohs(msg->daddr.ib.lid), ntohs(msg->dport), + ntohl(msg->daddr.ib.qpn), ntohl(msg->sqpn), + ntohs(msg->saddr.ib.lid), ntohs(msg->sport), + ntohl(msg->saddr.ib.qpn)); + } + + return found; +} + +/* Get rmsgs from CM completion queue, 10 at a time */ +static void ucm_recv(ib_hca_transport_t *tp) +{ + struct ibv_wc wc[10]; + ib_cm_msg_t *msg; + dp_ib_cm_handle_t cm; + int i, ret, notify = 0; + struct ibv_cq *ibv_cq = NULL; + DAPL_HCA *hca; + + /* POLLIN on channel FD */ + ret = ibv_get_cq_event(tp->rch, &ibv_cq, (void *)&hca); + if (ret == 0) { + ibv_ack_cq_events(ibv_cq, 1); + } +retry: + ret = ibv_poll_cq(tp->rcq, 10, wc); + if (ret <= 0) { + if (!ret && !notify) { + ibv_req_notify_cq(tp->rcq, 0); + notify = 1; + goto retry; + } + return; + } else + notify = 0; + + for (i = 0; i < ret; i++) { + msg = (ib_cm_msg_t*) (uintptr_t) wc[i].wr_id; + + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " ucm_recv: wc status=%d, ln=%d id=%p sqp=%x\n", + wc[i].status, wc[i].byte_len, + (void*)wc[i].wr_id, wc[i].src_qp); + + /* validate CM message, version */ + if (ntohs(msg->ver) != DCM_VER) { + dapl_log(DAPL_DBG_TYPE_WARN, + " ucm_recv: UNKNOWN msg %p, ver %d\n", + msg, msg->ver); + ucm_post_rmsg(tp, msg); + continue; + } + if (!(cm = ucm_cm_find(tp, msg))) { + ucm_post_rmsg(tp, msg); + continue; + } + + /* match, process it */ + ucm_process_recv(tp, msg, cm); + ucm_post_rmsg(tp, msg); + } + + /* finished this batch of WC's, poll and rearm */ + goto retry; +} + +/* ACTIVE/PASSIVE: build and send CM message out of CM object */ +static int ucm_send(ib_hca_transport_t *tp, ib_cm_msg_t *msg, DAT_PVOID p_data, DAT_COUNT p_size) +{ + ib_cm_msg_t *smsg = NULL; + struct ibv_send_wr wr, *bad_wr; + struct ibv_sge sge; + int len, ret = -1; + uint16_t dlid = ntohs(msg->daddr.ib.lid); + + /* Get message from send queue, copy data, and send */ + dapl_os_lock(&tp->slock); + if ((smsg = ucm_get_smsg(tp)) == NULL) + goto bail; + + len = (sizeof(*msg) - DCM_MAX_PDATA_SIZE); + dapl_os_memcpy(smsg, msg, len); + if (p_size) { + smsg->p_size = ntohs(p_size); + dapl_os_memcpy(&smsg->p_data, p_data, p_size); + } + + wr.next = NULL; + wr.sg_list = &sge; + wr.num_sge = 1; + wr.opcode = IBV_WR_SEND; + wr.wr_id = (unsigned long)tp->s_hd; + wr.send_flags = (wr.wr_id % UCM_SND_BURST) ? 0 : IBV_SEND_SIGNALED; + if (len <= tp->max_inline_send) + wr.send_flags |= IBV_SEND_INLINE; + + sge.length = len + p_size; + sge.lkey = tp->mr_sbuf->lkey; + sge.addr = (uintptr_t)smsg; + + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " ucm_send: op %s ln %d lid %x c_qpn %x rport %s\n", + dapl_cm_op_str(ntohs(smsg->op)), + sge.length, htons(smsg->daddr.ib.lid), + htonl(smsg->dqpn), htons(smsg->dport)); + + /* empty slot, then create AH */ + if (!tp->ah[dlid]) { + tp->ah[dlid] = + dapls_create_ah(tp->hca, tp->pd, tp->qp, + htons(dlid), NULL); + if (!tp->ah[dlid]) + goto bail; + } + + wr.wr.ud.ah = tp->ah[dlid]; + wr.wr.ud.remote_qpn = ntohl(smsg->dqpn); + wr.wr.ud.remote_qkey = DAT_UD_QKEY; + + ret = ibv_post_send(tp->qp, &wr, &bad_wr); +bail: + dapl_os_unlock(&tp->slock); + return ret; +} + +/* ACTIVE/PASSIVE: CM objects */ +static void dapli_cm_dealloc(dp_ib_cm_handle_t cm) { + + dapl_os_assert(!cm->ref_count); + dapl_os_lock_destroy(&cm->lock); + dapl_os_wait_object_destroy(&cm->event); + dapl_os_free(cm, sizeof(*cm)); +} + +void dapls_cm_acquire(dp_ib_cm_handle_t cm) +{ + dapl_os_lock(&cm->lock); + cm->ref_count++; + dapl_os_unlock(&cm->lock); +} + +void dapls_cm_release(dp_ib_cm_handle_t cm) +{ + dapl_os_lock(&cm->lock); + cm->ref_count--; + if (cm->ref_count) { + dapl_os_unlock(&cm->lock); + return; + } + /* client, release local conn id port */ + if (!cm->sp && cm->msg.sport) + ucm_free_port(&cm->hca->ib_trans, ntohs(cm->msg.sport)); + + /* clean up any UD address handles */ + if (cm->ah) { + ibv_destroy_ah(cm->ah); + cm->ah = NULL; + } + dapl_os_unlock(&cm->lock); + dapli_cm_dealloc(cm); +} + +dp_ib_cm_handle_t dapls_ib_cm_create(DAPL_EP *ep) +{ + dp_ib_cm_handle_t cm; + + /* Allocate CM, init lock, and initialize */ + if ((cm = dapl_os_alloc(sizeof(*cm))) == NULL) + return NULL; + + (void)dapl_os_memzero(cm, sizeof(*cm)); + if (dapl_os_lock_init(&cm->lock)) + goto bail; + + if (dapl_os_wait_object_init(&cm->event)) { + dapl_os_lock_destroy(&cm->lock); + goto bail; + } + dapls_cm_acquire(cm); + + cm->msg.ver = htons(DCM_VER); + *(DAT_UINT32*)cm->msg.resv = htonl(dapl_os_getpid()); /* exchange PID for debugging */ + + /* ACTIVE: init source address QP info from local EP */ + if (ep) { + DAPL_HCA *hca = ep->header.owner_ia->hca_ptr; + + cm->msg.sport = htons(ucm_get_port(&hca->ib_trans, 0)); + if (!cm->msg.sport) { + dapl_os_wait_object_destroy(&cm->event); + dapl_os_lock_destroy(&cm->lock); + goto bail; + } + /* link CM object to EP */ + dapl_ep_link_cm(ep, cm); + cm->hca = hca; + cm->ep = ep; + + /* IB info in network order */ + cm->msg.sqpn = htonl(hca->ib_trans.qp->qp_num); /* ucm */ + cm->msg.saddr.ib.qpn = htonl(ep->qp_handle->qp_num); /* ep */ + cm->msg.saddr.ib.qp_type = ep->qp_handle->qp_type; + cm->msg.saddr.ib.lid = hca->ib_trans.addr.ib.lid; + dapl_os_memcpy(&cm->msg.saddr.ib.gid[0], + &hca->ib_trans.addr.ib.gid, 16); + } + return cm; +bail: + dapl_os_free(cm, sizeof(*cm)); + return NULL; +} + +/* schedule destruction of CM object */ +void dapli_cm_free(dp_ib_cm_handle_t cm) +{ + dapl_log(DAPL_DBG_TYPE_CM, + " dapli_cm_free: cm %p %s ep %p refs=%d\n", + cm, dapl_cm_state_str(cm->state), + cm->ep, cm->ref_count); + + dapl_os_lock(&cm->lock); + cm->state = DCM_FREE; + dapls_thread_signal(&cm->hca->ib_trans.signal); + dapl_os_unlock(&cm->lock); +} + +/* Blocking, ONLY called from dat_ep_free */ +void dapls_cm_free(dp_ib_cm_handle_t cm) +{ + dapl_log(DAPL_DBG_TYPE_CM, + " dapl_cm_free: cm %p %s ep %p refs=%d\n", + cm, dapl_cm_state_str(cm->state), + cm->ep, cm->ref_count); + + /* free from internal workq, wait until EP is last ref */ + dapl_os_lock(&cm->lock); + if (cm->state != DCM_FREE) + cm->state = DCM_FREE; + + while (cm->ref_count != 1) { + dapl_os_unlock(&cm->lock); + dapls_thread_signal(&cm->hca->ib_trans.signal); + dapl_os_sleep_usec(10000); + dapl_os_lock(&cm->lock); + } + dapl_os_unlock(&cm->lock); + + /* unlink, dequeue from EP. Final ref so release will destroy */ + dapl_ep_unlink_cm(cm->ep, cm); +} + +/* ACTIVE/PASSIVE: queue up connection object on CM list */ +static void dapli_queue_conn(dp_ib_cm_handle_t cm) +{ + /* add to work queue, list, for cm thread processing */ + dapl_llist_init_entry((DAPL_LLIST_ENTRY *)&cm->local_entry); + dapl_os_lock(&cm->hca->ib_trans.lock); + dapls_cm_acquire(cm); + dapl_llist_add_tail(&cm->hca->ib_trans.list, + (DAPL_LLIST_ENTRY *)&cm->local_entry, cm); + dapl_os_unlock(&cm->hca->ib_trans.lock); + dapls_thread_signal(&cm->hca->ib_trans.signal); +} + +/* PASSIVE: queue up listen object on listen list */ +static void dapli_queue_listen(dp_ib_cm_handle_t cm) +{ + /* add to work queue, llist, for cm thread processing */ + dapl_llist_init_entry((DAPL_LLIST_ENTRY *)&cm->local_entry); + dapl_os_lock(&cm->hca->ib_trans.llock); + dapls_cm_acquire(cm); + dapl_llist_add_tail(&cm->hca->ib_trans.llist, + (DAPL_LLIST_ENTRY *)&cm->local_entry, cm); + dapl_os_unlock(&cm->hca->ib_trans.llock); +} + +static void dapli_dequeue_listen(dp_ib_cm_handle_t cm) +{ + DAPL_HCA *hca = cm->hca; + + dapl_os_lock(&hca->ib_trans.llock); + dapl_llist_remove_entry(&hca->ib_trans.llist, + (DAPL_LLIST_ENTRY *)&cm->local_entry); + dapls_cm_release(cm); + dapl_os_unlock(&hca->ib_trans.llock); +} + +/* called with local LIST and CM object lock */ +static void dapli_cm_dequeue(dp_ib_cm_handle_t cm) +{ + /* Remove from work queue, cr thread processing */ + dapl_llist_remove_entry(&cm->hca->ib_trans.list, + (DAPL_LLIST_ENTRY *)&cm->local_entry); + dapls_cm_release(cm); +} + +static void ucm_disconnect_final(dp_ib_cm_handle_t cm) +{ + /* no EP attachment or not RC, nothing to process */ + if (cm->ep == NULL || + cm->ep->param.ep_attr.service_type != DAT_SERVICE_TYPE_RC) + return; + + dapl_os_lock(&cm->lock); + if (cm->state == DCM_DISCONNECTED) { + dapl_os_unlock(&cm->lock); + return; + } + + cm->state = DCM_DISCONNECTED; + dapl_os_unlock(&cm->lock); + + if (cm->sp) + dapls_cr_callback(cm, IB_CME_DISCONNECTED, NULL, 0, cm->sp); + else + dapl_evd_connection_callback(cm, IB_CME_DISCONNECTED, NULL, 0, cm->ep); + +} + +/* + * called from consumer thread via ep_disconnect/ep_free or + * from cm_thread when receiving DREQ + */ +DAT_RETURN dapli_cm_disconnect(dp_ib_cm_handle_t cm) +{ + int finalize = 1; + int wakeup = 0; + + dapl_os_lock(&cm->lock); + switch (cm->state) { + case DCM_CONNECTED: + /* CONSUMER: move to err state to flush, if not UD */ + if (cm->ep->qp_handle->qp_type != IBV_QPT_UD) + dapls_modify_qp_state(cm->ep->qp_handle, IBV_QPS_ERR,0,0,0); + + /* send DREQ, event after DREP or DREQ timeout */ + cm->state = DCM_DISC_PENDING; + cm->msg.op = htons(DCM_DREQ); + finalize = 0; /* wait for DREP, wakeup timer after DREQ sent */ + wakeup = 1; + break; + case DCM_DISC_PENDING: + /* DREQ timeout, resend until retries exhausted */ + cm->msg.op = htons(DCM_DREQ); + if (cm->retries >= cm->hca->ib_trans.retries) { + dapl_log(DAPL_DBG_TYPE_ERR, + " CM_DREQ: RETRIES EXHAUSTED:" + " %x %x %x -> %x %x %x\n", + htons(cm->msg.saddr.ib.lid), + htonl(cm->msg.saddr.ib.qpn), + htons(cm->msg.sport), + htons(cm->msg.daddr.ib.lid), + htonl(cm->msg.dqpn), + htons(cm->msg.dport)); + finalize = 1; + } + break; + case DCM_DISC_RECV: + /* CM_THREAD: move to err state to flush, if not UD */ + if (cm->ep->qp_handle->qp_type != IBV_QPT_UD) + dapls_modify_qp_state(cm->ep->qp_handle, IBV_QPS_ERR,0,0,0); + + /* DREQ received, send DREP and schedule event, finalize */ + cm->msg.op = htons(DCM_DREP); + break; + case DCM_DISCONNECTED: + dapl_os_unlock(&cm->lock); + return DAT_SUCCESS; + default: + dapl_log(DAPL_DBG_TYPE_WARN, + " disconnect UNKNOWN state: ep %p cm %p %s %s" + " %x %x %x %s %x %x %x r_pid %x (%x)\n", + cm->ep, cm, + cm->msg.saddr.ib.qp_type == IBV_QPT_RC ? "RC" : "UD", + dapl_cm_state_str(cm->state), + ntohs(cm->msg.saddr.ib.lid), + ntohs(cm->msg.sport), + ntohl(cm->msg.saddr.ib.qpn), + cm->sp ? "<-" : "->", + ntohs(cm->msg.daddr.ib.lid), + ntohs(cm->msg.dport), + ntohl(cm->msg.daddr.ib.qpn), + ntohs(cm->msg.op) == DCM_REQ ? 0 : ntohl(*(DAT_UINT32*)cm->msg.resv), + ntohs(cm->msg.op) == DCM_REQ ? 0 : ntohl(*(DAT_UINT32*)cm->msg.resv)); + + dapl_os_unlock(&cm->lock); + return DAT_SUCCESS; + } + + dapl_os_get_time(&cm->timer); /* reply expected */ + ucm_send(&cm->hca->ib_trans, &cm->msg, NULL, 0); + dapl_os_unlock(&cm->lock); + + if (wakeup) + dapls_thread_signal(&cm->hca->ib_trans.signal); + + if (finalize) + ucm_disconnect_final(cm); + + return DAT_SUCCESS; +} + +/* + * ACTIVE: get remote CM SID server info from r_addr. + * send, or resend CM msg via UD CM QP + */ +DAT_RETURN +dapli_cm_connect(DAPL_EP *ep, dp_ib_cm_handle_t cm) +{ + dapl_log(DAPL_DBG_TYPE_EP, + " connect: lid %x i_qpn %x lport %x p_sz=%d -> " + " lid %x c_qpn %x rport %x\n", + htons(cm->msg.saddr.ib.lid), htonl(cm->msg.saddr.ib.qpn), + htons(cm->msg.sport), htons(cm->msg.p_size), + htons(cm->msg.daddr.ib.lid), htonl(cm->msg.dqpn), + htons(cm->msg.dport)); + + dapl_os_lock(&cm->lock); + if (cm->state != DCM_REP_PENDING) { + dapl_os_unlock(&cm->lock); + return DAT_INVALID_STATE; + } + + if (cm->retries == cm->hca->ib_trans.retries) { + dapl_log(DAPL_DBG_TYPE_ERR, + " CM_REQ: RETRIES EXHAUSTED:" + " 0x%x %x 0x%x -> 0x%x %x 0x%x\n", + htons(cm->msg.saddr.ib.lid), + htonl(cm->msg.saddr.ib.qpn), + htons(cm->msg.sport), + htons(cm->msg.daddr.ib.lid), + htonl(cm->msg.dqpn), + htons(cm->msg.dport)); + + dapl_os_unlock(&cm->lock); + +#ifdef DAPL_COUNTERS + /* called from check_timers in cm_thread, cm lock held */ + if (g_dapl_dbg_type & DAPL_DBG_TYPE_CM_LIST) { + dapl_os_unlock(&cm->hca->ib_trans.lock); + dapls_print_cm_list(ep->header.owner_ia); + dapl_os_lock(&cm->hca->ib_trans.lock); + } +#endif + dapl_evd_connection_callback(cm, + IB_CME_DESTINATION_UNREACHABLE, + NULL, 0, ep); + + return DAT_ERROR(DAT_INVALID_ADDRESS, + DAT_INVALID_ADDRESS_UNREACHABLE); + } + dapl_os_unlock(&cm->lock); + + cm->msg.op = htons(DCM_REQ); + dapl_os_get_time(&cm->timer); /* reply expected */ + if (ucm_send(&cm->hca->ib_trans, &cm->msg, + &cm->msg.p_data, ntohs(cm->msg.p_size))) + goto bail; + + /* first time through, link EP and CM, put on work queue */ + if (!cm->retries) { + dapli_queue_conn(cm); + } + return DAT_SUCCESS; + +bail: + dapl_log(DAPL_DBG_TYPE_WARN, + " connect: ERR %s -> cm_lid %x cm_qpn %x r_psp %x p_sz=%d\n", + strerror(errno), htons(cm->msg.daddr.ib.lid), + htonl(cm->msg.dqpn), htons(cm->msg.dport), + htonl(cm->msg.p_size)); + + dapli_cm_free(cm); + return DAT_INSUFFICIENT_RESOURCES; +} + +/* + * ACTIVE: exchange QP information, called from CR thread + */ +static void ucm_connect_rtu(dp_ib_cm_handle_t cm, ib_cm_msg_t *msg) +{ + DAPL_EP *ep = cm->ep; + ib_cm_events_t event = IB_CME_CONNECTED; + + dapl_os_lock(&cm->lock); + if (cm->state != DCM_REP_PENDING) { + dapl_log(DAPL_DBG_TYPE_WARN, + " CONN_RTU: UNEXPECTED state:" + " op %s, st %s <- lid %x sqpn %x sport %x\n", + dapl_cm_op_str(ntohs(msg->op)), + dapl_cm_state_str(cm->state), + ntohs(msg->saddr.ib.lid), ntohl(msg->saddr.ib.qpn), + ntohs(msg->sport)); + dapl_os_unlock(&cm->lock); + return; + } + + /* save remote address information to EP and CM */ + dapl_os_memcpy(&ep->remote_ia_address, + &msg->saddr, sizeof(union dcm_addr)); + dapl_os_memcpy(&cm->msg.daddr, + &msg->saddr, sizeof(union dcm_addr)); + + /* validate private data size, and copy if necessary */ + if (msg->p_size) { + if (ntohs(msg->p_size) > DCM_MAX_PDATA_SIZE) { + dapl_log(DAPL_DBG_TYPE_WARN, + " CONN_RTU: invalid p_size %d:" + " st %s <- lid %x sqpn %x spsp %x\n", + ntohs(msg->p_size), + dapl_cm_state_str(cm->state), + ntohs(msg->saddr.ib.lid), + ntohl(msg->saddr.ib.qpn), + ntohs(msg->sport)); + dapl_os_unlock(&cm->lock); + goto bail; + } + dapl_os_memcpy(cm->msg.p_data, + msg->p_data, ntohs(msg->p_size)); + } + + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " CONN_RTU: DST lid=%x," + " iqp=%x, qp_type=%d, port=%x psize=%d\n", + ntohs(cm->msg.daddr.ib.lid), + ntohl(cm->msg.daddr.ib.qpn), cm->msg.daddr.ib.qp_type, + ntohs(msg->sport), ntohs(msg->p_size)); + + if (ntohs(msg->op) == DCM_REP) + event = IB_CME_CONNECTED; + else if (ntohs(msg->op) == DCM_REJ_USER) + event = IB_CME_DESTINATION_REJECT_PRIVATE_DATA; + else + event = IB_CME_DESTINATION_REJECT; + + if (event != IB_CME_CONNECTED) { + dapl_log(DAPL_DBG_TYPE_CM, + " ACTIVE: CM_REQ REJECTED:" + " cm %p op %s, st %s dlid %x iqp %x port %x <-" + " slid %x iqp %x port %x\n", cm, + dapl_cm_op_str(ntohs(msg->op)), + dapl_cm_state_str(cm->state), + ntohs(msg->daddr.ib.lid), ntohl(msg->daddr.ib.qpn), + ntohs(msg->dport), ntohs(msg->saddr.ib.lid), + ntohl(msg->saddr.ib.qpn), ntohs(msg->sport)); + + cm->state = DCM_REJECTED; + dapl_os_unlock(&cm->lock); + +#ifdef DAT_EXTENSIONS + if (cm->msg.daddr.ib.qp_type == IBV_QPT_UD) + goto ud_bail; + else +#endif + goto bail; + } + dapl_os_unlock(&cm->lock); + + /* modify QP to RTR and then to RTS with remote info */ + dapl_os_lock(&cm->ep->header.lock); + if (dapls_modify_qp_state(cm->ep->qp_handle, + IBV_QPS_RTR, + cm->msg.daddr.ib.qpn, + cm->msg.daddr.ib.lid, + (ib_gid_handle_t)cm->msg.daddr.ib.gid) != DAT_SUCCESS) { + dapl_log(DAPL_DBG_TYPE_ERR, + " CONN_RTU: QPS_RTR ERR %s <- lid %x iqp %x\n", + strerror(errno), ntohs(cm->msg.daddr.ib.lid), + ntohl(cm->msg.daddr.ib.qpn)); + dapl_os_unlock(&cm->ep->header.lock); + event = IB_CME_LOCAL_FAILURE; + goto bail; + } + if (dapls_modify_qp_state(cm->ep->qp_handle, + IBV_QPS_RTS, + cm->msg.daddr.ib.qpn, + cm->msg.daddr.ib.lid, + NULL) != DAT_SUCCESS) { + dapl_log(DAPL_DBG_TYPE_ERR, + " CONN_RTU: QPS_RTS ERR %s <- lid %x iqp %x\n", + strerror(errno), ntohs(cm->msg.daddr.ib.lid), + ntohl(cm->msg.daddr.ib.qpn)); + dapl_os_unlock(&cm->ep->header.lock); + event = IB_CME_LOCAL_FAILURE; + goto bail; + } + dapl_os_unlock(&cm->ep->header.lock); + + /* Send RTU, no private data */ + cm->msg.op = htons(DCM_RTU); + + dapl_os_lock(&cm->lock); + cm->state = DCM_CONNECTED; + dapl_os_unlock(&cm->lock); + + if (ucm_send(&cm->hca->ib_trans, &cm->msg, NULL, 0)) + goto bail; + + /* init cm_handle and post the event with private data */ + dapl_dbg_log(DAPL_DBG_TYPE_EP, " ACTIVE: connected!\n"); + +#ifdef DAT_EXTENSIONS +ud_bail: + if (cm->msg.daddr.ib.qp_type == IBV_QPT_UD) { + DAT_IB_EXTENSION_EVENT_DATA xevent; + uint16_t lid = ntohs(cm->msg.daddr.ib.lid); + + /* post EVENT, modify_qp, AH already created, ucm msg */ + xevent.status = 0; + xevent.type = DAT_IB_UD_REMOTE_AH; + xevent.remote_ah.qpn = ntohl(cm->msg.daddr.ib.qpn); + xevent.remote_ah.ah = dapls_create_ah(cm->hca, + cm->ep->qp_handle->pd, + cm->ep->qp_handle, + htons(lid), + NULL); + if (xevent.remote_ah.ah == NULL) { + dapl_log(DAPL_DBG_TYPE_ERR, + " active UD RTU: ERR create_ah" + " for qpn 0x%x lid 0x%x\n", + xevent.remote_ah.qpn, lid); + event = IB_CME_LOCAL_FAILURE; + goto bail; + } + cm->ah = xevent.remote_ah.ah; /* keep ref to destroy */ + + dapl_os_memcpy(&xevent.remote_ah.ia_addr, + &cm->msg.daddr, + sizeof(union dcm_addr)); + + /* remote ia_addr reference includes ucm qpn, not IB qpn */ + ((union dcm_addr*) + &xevent.remote_ah.ia_addr)->ib.qpn = cm->msg.dqpn; + + dapl_dbg_log(DAPL_DBG_TYPE_EP, + " ACTIVE: UD xevent ah %p qpn %x lid %x\n", + xevent.remote_ah.ah, xevent.remote_ah.qpn, lid); + dapl_dbg_log(DAPL_DBG_TYPE_EP, + " ACTIVE: UD xevent ia_addr qp_type %d" + " lid 0x%x qpn 0x%x gid 0x"F64x" 0x"F64x" \n", + ((union dcm_addr*) + &xevent.remote_ah.ia_addr)->ib.qp_type, + ntohs(((union dcm_addr*) + &xevent.remote_ah.ia_addr)->ib.lid), + ntohl(((union dcm_addr*) + &xevent.remote_ah.ia_addr)->ib.qpn), + ntohll(*(uint64_t*)&cm->msg.daddr.ib.gid[0]), + ntohll(*(uint64_t*)&cm->msg.daddr.ib.gid[8])); + + if (event == IB_CME_CONNECTED) + event = DAT_IB_UD_CONNECTION_EVENT_ESTABLISHED; + else { + xevent.type = DAT_IB_UD_CONNECT_REJECT; + event = DAT_IB_UD_CONNECTION_REJECT_EVENT; + } + + dapls_evd_post_connection_event_ext( + (DAPL_EVD *)cm->ep->param.connect_evd_handle, + event, + (DAT_EP_HANDLE)ep, + (DAT_COUNT)ntohs(cm->msg.p_size), + (DAT_PVOID *)cm->msg.p_data, + (DAT_PVOID *)&xevent); + } else +#endif + { + dapl_evd_connection_callback(cm, + IB_CME_CONNECTED, + cm->msg.p_data, ntohs(cm->msg.p_size), cm->ep); + } + dapl_log(DAPL_DBG_TYPE_CM_EST, + " UCM_ACTIVE_CONN %d [lid port qpn] %x %x %x -> %x %x %x\n", + cm->retries, ntohs(cm->msg.saddr.ib.lid), + ntohs(cm->msg.sport), ntohl(cm->msg.saddr.ib.qpn), + ntohs(cm->msg.daddr.ib.lid), ntohs(cm->msg.dport), + ntohl(cm->msg.dqpn)); + return; +bail: + dapl_evd_connection_callback(NULL, event, cm->msg.p_data, ntohs(cm->msg.p_size), cm->ep); + dapli_cm_free(cm); +} + +/* + * PASSIVE: Accept on listen CM PSP. + * create new CM object for this CR, + * receive peer QP information, private data, + * and post cr_event + */ +static void ucm_accept(ib_cm_srvc_handle_t cm, ib_cm_msg_t *msg) +{ + dp_ib_cm_handle_t acm; + + /* Allocate accept CM and setup passive references */ + if ((acm = dapls_ib_cm_create(NULL)) == NULL) { + dapl_log(DAPL_DBG_TYPE_WARN, " accept: ERR cm_create\n"); + return; + } + + /* dest CM info from CR msg, source CM info from listen */ + acm->sp = cm->sp; + acm->hca = cm->hca; + acm->msg.op = msg->op; + acm->msg.dport = msg->sport; + acm->msg.dqpn = msg->sqpn; + acm->msg.sport = cm->msg.sport; + acm->msg.sqpn = cm->msg.sqpn; + acm->msg.p_size = msg->p_size; + + /* CR saddr is CM daddr info, need EP for local saddr */ + dapl_os_memcpy(&acm->msg.daddr, &msg->saddr, sizeof(union dcm_addr)); + + dapl_log(DAPL_DBG_TYPE_CM, + " accept: DST port=%x lid=%x, iqp=%x, psize=%d\n", + ntohs(acm->msg.dport), ntohs(acm->msg.daddr.ib.lid), + htonl(acm->msg.daddr.ib.qpn), htons(acm->msg.p_size)); + + /* validate private data size before reading */ + if (ntohs(msg->p_size) > DCM_MAX_PDATA_SIZE) { + dapl_log(DAPL_DBG_TYPE_WARN, " accept: psize (%d) wrong\n", + ntohs(msg->p_size)); + goto bail; + } + + /* read private data into cm_handle if any present */ + if (msg->p_size) + dapl_os_memcpy(acm->msg.p_data, + msg->p_data, ntohs(msg->p_size)); + + acm->state = DCM_ACCEPTING; + dapli_queue_conn(acm); + +#ifdef DAT_EXTENSIONS + if (acm->msg.daddr.ib.qp_type == IBV_QPT_UD) { + DAT_IB_EXTENSION_EVENT_DATA xevent; + + /* post EVENT, modify_qp created ah */ + xevent.status = 0; + xevent.type = DAT_IB_UD_CONNECT_REQUEST; + + dapls_evd_post_cr_event_ext(acm->sp, + DAT_IB_UD_CONNECTION_REQUEST_EVENT, + acm, + (DAT_COUNT)ntohs(acm->msg.p_size), + (DAT_PVOID *)acm->msg.p_data, + (DAT_PVOID *)&xevent); + } else +#endif + /* trigger CR event and return SUCCESS */ + dapls_cr_callback(acm, + IB_CME_CONNECTION_REQUEST_PENDING, + acm->msg.p_data, ntohs(msg->p_size), acm->sp); + return; + +bail: + /* schedule work thread cleanup */ + dapli_cm_free(acm); + return; +} + +/* + * PASSIVE: read RTU from active peer, post CONN event + */ +static void ucm_accept_rtu(dp_ib_cm_handle_t cm, ib_cm_msg_t *msg) +{ + dapl_os_lock(&cm->lock); + if ((ntohs(msg->op) != DCM_RTU) || (cm->state != DCM_RTU_PENDING)) { + dapl_log(DAPL_DBG_TYPE_WARN, + " accept_rtu: UNEXPECTED op, state:" + " op %s, st %s <- lid %x iqp %x sport %x\n", + dapl_cm_op_str(ntohs(msg->op)), + dapl_cm_state_str(cm->state), + ntohs(msg->saddr.ib.lid), ntohl(msg->saddr.ib.qpn), + ntohs(msg->sport)); + dapl_os_unlock(&cm->lock); + goto bail; + } + cm->state = DCM_CONNECTED; + dapl_os_unlock(&cm->lock); + + /* final data exchange if remote QP state is good to go */ + dapl_dbg_log(DAPL_DBG_TYPE_CM, " PASSIVE: connected!\n"); + +#ifdef DAT_EXTENSIONS + if (cm->msg.saddr.ib.qp_type == IBV_QPT_UD) { + DAT_IB_EXTENSION_EVENT_DATA xevent; + uint16_t lid = ntohs(cm->msg.daddr.ib.lid); + + /* post EVENT, modify_qp, AH already created, ucm msg */ + xevent.status = 0; + xevent.type = DAT_IB_UD_PASSIVE_REMOTE_AH; + xevent.remote_ah.qpn = ntohl(cm->msg.daddr.ib.qpn); + xevent.remote_ah.ah = dapls_create_ah(cm->hca, + cm->ep->qp_handle->pd, + cm->ep->qp_handle, + htons(lid), + NULL); + if (xevent.remote_ah.ah == NULL) { + dapl_log(DAPL_DBG_TYPE_ERR, + " passive UD RTU: ERR create_ah" + " for qpn 0x%x lid 0x%x\n", + xevent.remote_ah.qpn, lid); + goto bail; + } + cm->ah = xevent.remote_ah.ah; /* keep ref to destroy */ + dapl_os_memcpy(&xevent.remote_ah.ia_addr, + &cm->msg.daddr, + sizeof(union dcm_addr)); + + /* remote ia_addr reference includes ucm qpn, not IB qpn */ + ((union dcm_addr*) + &xevent.remote_ah.ia_addr)->ib.qpn = cm->msg.dqpn; + + dapl_dbg_log(DAPL_DBG_TYPE_EP, + " PASSIVE: UD xevent ah %p qpn %x lid %x\n", + xevent.remote_ah.ah, xevent.remote_ah.qpn, lid); + dapl_dbg_log(DAPL_DBG_TYPE_EP, + " PASSIVE: UD xevent ia_addr qp_type %d" + " lid 0x%x qpn 0x%x gid 0x"F64x" 0x"F64x" \n", + ((union dcm_addr*) + &xevent.remote_ah.ia_addr)->ib.qp_type, + ntohs(((union dcm_addr*) + &xevent.remote_ah.ia_addr)->ib.lid), + ntohl(((union dcm_addr*) + &xevent.remote_ah.ia_addr)->ib.qpn), + ntohll(*(uint64_t*)&cm->msg.daddr.ib.gid[0]), + ntohll(*(uint64_t*)&cm->msg.daddr.ib.gid[8])); + + dapls_evd_post_connection_event_ext( + (DAPL_EVD *)cm->ep->param.connect_evd_handle, + DAT_IB_UD_CONNECTION_EVENT_ESTABLISHED, + (DAT_EP_HANDLE)cm->ep, + (DAT_COUNT)ntohs(cm->msg.p_size), + (DAT_PVOID *)cm->msg.p_data, + (DAT_PVOID *)&xevent); + } else { +#endif + dapls_cr_callback(cm, IB_CME_CONNECTED, NULL, 0, cm->sp); + } + dapl_log(DAPL_DBG_TYPE_CM_EST, + " UCM_PASSIVE_CONN %d [lid port qpn] %x %x %x <- %x %x %x\n", + cm->retries, ntohs(cm->msg.saddr.ib.lid), + ntohs(cm->msg.sport), ntohl(cm->msg.saddr.ib.qpn), + ntohs(cm->msg.daddr.ib.lid), ntohs(cm->msg.dport), + ntohl(cm->msg.dqpn)); + return; +bail: + dapls_cr_callback(cm, IB_CME_LOCAL_FAILURE, NULL, 0, cm->sp); + dapli_cm_free(cm); +} + +/* + * PASSIVE: user accepted, send reply message with pdata + */ +static int ucm_reply(dp_ib_cm_handle_t cm) +{ + dapl_os_lock(&cm->lock); + if (cm->state != DCM_RTU_PENDING) { + dapl_log(DAPL_DBG_TYPE_ERR, + " CM_REPLY: wrong state %s", + dapl_cm_state_str(cm->state)); + dapl_os_unlock(&cm->lock); + return -1; + } + + if (cm->retries == cm->hca->ib_trans.retries) { + dapl_log(DAPL_DBG_TYPE_ERR, + " CM_REPLY: RETRIES EXHAUSTED (lid port qpn)" + " %x %x %x -> %x %x %x\n", + htons(cm->msg.saddr.ib.lid), + htons(cm->msg.sport), + htonl(cm->msg.saddr.ib.qpn), + htons(cm->msg.daddr.ib.lid), + htons(cm->msg.dport), + htonl(cm->msg.daddr.ib.qpn)); + + dapl_os_unlock(&cm->lock); +#ifdef DAPL_COUNTERS + /* called from check_timers in cm_thread, cm lock held */ + if (g_dapl_dbg_type & DAPL_DBG_TYPE_CM_LIST) { + dapl_os_unlock(&cm->hca->ib_trans.lock); + dapls_print_cm_list(dapl_llist_peek_head(&cm->hca->ia_list_head)); + dapl_os_lock(&cm->hca->ib_trans.lock); + } +#endif +#ifdef DAT_EXTENSIONS + if (cm->msg.saddr.ib.qp_type == IBV_QPT_UD) { + DAT_IB_EXTENSION_EVENT_DATA xevent; + + /* post REJECT event with CONN_REQ p_data */ + xevent.status = 0; + xevent.type = DAT_IB_UD_CONNECT_ERROR; + + dapls_evd_post_connection_event_ext( + (DAPL_EVD *)cm->ep->param.connect_evd_handle, + DAT_IB_UD_CONNECTION_ERROR_EVENT, + (DAT_EP_HANDLE)cm->ep, + (DAT_COUNT)ntohs(cm->msg.p_size), + (DAT_PVOID *)cm->msg.p_data, + (DAT_PVOID *)&xevent); + } else +#endif + dapls_cr_callback(cm, IB_CME_LOCAL_FAILURE, + NULL, 0, cm->sp); + return -1; + } + dapl_os_get_time(&cm->timer); /* RTU expected */ + dapl_os_unlock(&cm->lock); + if (ucm_send(&cm->hca->ib_trans, &cm->msg, cm->p_data, cm->p_size)) + return -1; + + return 0; +} + + +/* + * PASSIVE: consumer accept, send local QP information, private data, + * queue on work thread to receive RTU information to avoid blocking + * user thread. + */ +DAT_RETURN +dapli_accept_usr(DAPL_EP *ep, DAPL_CR *cr, DAT_COUNT p_size, DAT_PVOID p_data) +{ + DAPL_IA *ia = ep->header.owner_ia; + dp_ib_cm_handle_t cm = cr->ib_cm_handle; + + if (p_size > DCM_MAX_PDATA_SIZE) + return DAT_LENGTH_ERROR; + + dapl_os_lock(&cm->lock); + if (cm->state != DCM_ACCEPTING) { + dapl_os_unlock(&cm->lock); + return DAT_INVALID_STATE; + } + dapl_os_unlock(&cm->lock); + + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " ACCEPT_USR: remote lid=%x" + " iqp=%x qp_type %d, psize=%d\n", + ntohs(cm->msg.daddr.ib.lid), + ntohl(cm->msg.daddr.ib.qpn), cm->msg.daddr.ib.qp_type, + p_size); + + dapl_dbg_log(DAPL_DBG_TYPE_CM, + " ACCEPT_USR: remote GID subnet %016llx id %016llx\n", + (unsigned long long) + htonll(*(uint64_t*)&cm->msg.daddr.ib.gid[0]), + (unsigned long long) + htonll(*(uint64_t*)&cm->msg.daddr.ib.gid[8])); + +#ifdef DAT_EXTENSIONS + if (cm->msg.daddr.ib.qp_type == IBV_QPT_UD && + ep->qp_handle->qp_type != IBV_QPT_UD) { + dapl_log(DAPL_DBG_TYPE_ERR, + " ACCEPT_USR: ERR remote QP is UD," + ", but local QP is not\n"); + return (DAT_INVALID_HANDLE | DAT_INVALID_HANDLE_EP); + } +#endif + + /* modify QP to RTR and then to RTS with remote info already read */ + dapl_os_lock(&ep->header.lock); + if (dapls_modify_qp_state(ep->qp_handle, + IBV_QPS_RTR, + cm->msg.daddr.ib.qpn, + cm->msg.daddr.ib.lid, + (ib_gid_handle_t)cm->msg.daddr.ib.gid) != DAT_SUCCESS) { + dapl_log(DAPL_DBG_TYPE_ERR, + " ACCEPT_USR: QPS_RTR ERR %s -> lid %x qpn %x\n", + strerror(errno), ntohs(cm->msg.daddr.ib.lid), + ntohl(cm->msg.daddr.ib.qpn)); + dapl_os_unlock(&ep->header.lock); + goto bail; + } + if (dapls_modify_qp_state(ep->qp_handle, + IBV_QPS_RTS, + cm->msg.daddr.ib.qpn, + cm->msg.daddr.ib.lid, + NULL) != DAT_SUCCESS) { + dapl_log(DAPL_DBG_TYPE_ERR, + " ACCEPT_USR: QPS_RTS ERR %s -> lid %x qpn %x\n", + strerror(errno), ntohs(cm->msg.daddr.ib.lid), + ntohl(cm->msg.daddr.ib.qpn)); + dapl_os_unlock(&ep->header.lock); + goto bail; + } + dapl_os_unlock(&ep->header.lock); + + /* save remote address information */ + dapl_os_memcpy(&ep->remote_ia_address, + &cm->msg.saddr, sizeof(union dcm_addr)); + + /* setup local QP info and type from EP, copy pdata, for reply */ + cm->msg.op = htons(DCM_REP); + cm->msg.saddr.ib.qpn = htonl(ep->qp_handle->qp_num); + cm->msg.saddr.ib.qp_type = ep->qp_handle->qp_type; + cm->msg.saddr.ib.lid = cm->hca->ib_trans.addr.ib.lid; + dapl_os_memcpy(&cm->msg.saddr.ib.gid[0], + &cm->hca->ib_trans.addr.ib.gid, 16); + + /* + * UD: deliver p_data with REQ and EST event, keep REQ p_data in + * cm->msg.p_data and save REPLY accept data in cm->p_data for retries + */ + cm->p_size = p_size; + dapl_os_memcpy(&cm->p_data, p_data, p_size); + + /* save state and setup valid reference to EP, HCA */ + dapl_ep_link_cm(ep, cm); + cm->ep = ep; + cm->hca = ia->hca_ptr; + + dapl_os_lock(&cm->lock); + dapl_os_get_time(&cm->timer); /* RTU expected */ + cm->state = DCM_RTU_PENDING; + dapl_os_unlock(&cm->lock); + + if (ucm_reply(cm)) { + dapl_ep_unlink_cm(ep, cm); + goto bail; + } + dapl_dbg_log(DAPL_DBG_TYPE_CM, " PASSIVE: accepted!\n"); + dapls_thread_signal(&cm->hca->ib_trans.signal); + return DAT_SUCCESS; +bail: + dapli_cm_free(cm); + return DAT_INTERNAL_ERROR; +} + + +/* + * dapls_ib_connect + * + * Initiate a connection with the passive listener on another node + * + * Input: + * ep_handle, + * remote_ia_address, + * remote_conn_qual, + * prd_size size of private data and structure + * prd_prt pointer to private data structure + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + * + */ +DAT_RETURN +dapls_ib_connect(IN DAT_EP_HANDLE ep_handle, + IN DAT_IA_ADDRESS_PTR r_addr, + IN DAT_CONN_QUAL r_psp, + IN DAT_COUNT p_size, IN void *p_data) +{ + DAPL_EP *ep = (DAPL_EP *)ep_handle; + dp_ib_cm_handle_t cm; + + /* create CM object, initialize SRC info from EP */ + cm = dapls_ib_cm_create(ep); + if (cm == NULL) + return DAT_INSUFFICIENT_RESOURCES; + + /* remote hca and port: lid, gid, network order */ + dapl_os_memcpy(&cm->msg.daddr, r_addr, sizeof(union dcm_addr)); + + /* remote uCM information, comes from consumer provider r_addr */ + cm->msg.dport = htons((uint16_t)r_psp); + cm->msg.dqpn = cm->msg.daddr.ib.qpn; + cm->msg.daddr.ib.qpn = 0; /* don't have a remote qpn until reply */ + + if (p_size) { + cm->msg.p_size = htons(p_size); + dapl_os_memcpy(&cm->msg.p_data, p_data, p_size); + } + + cm->state = DCM_REP_PENDING; + + /* build connect request, send to remote CM based on r_addr info */ + return (dapli_cm_connect(ep, cm)); +} + +/* + * dapls_ib_disconnect + * + * Disconnect an EP + * + * Input: + * ep_handle, + * disconnect_flags + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + */ +DAT_RETURN +dapls_ib_disconnect(IN DAPL_EP *ep_ptr, IN DAT_CLOSE_FLAGS close_flags) +{ + dp_ib_cm_handle_t cm_ptr = dapl_get_cm_from_ep(ep_ptr); + + dapl_os_lock(&ep_ptr->header.lock); + if (ep_ptr->param.ep_state == DAT_EP_STATE_DISCONNECTED || + ep_ptr->param.ep_attr.service_type != DAT_SERVICE_TYPE_RC || + cm_ptr == NULL) { + dapl_os_unlock(&ep_ptr->header.lock); + return DAT_SUCCESS; + } + dapl_os_unlock(&ep_ptr->header.lock); + + dapli_cm_disconnect(cm_ptr); + + /* ABRUPT close, wait for callback and DISCONNECTED state */ + if (close_flags == DAT_CLOSE_ABRUPT_FLAG) { + dapl_os_lock(&ep_ptr->header.lock); + while (ep_ptr->param.ep_state != DAT_EP_STATE_DISCONNECTED) { + dapl_os_unlock(&ep_ptr->header.lock); + dapl_os_sleep_usec(10000); + dapl_os_lock(&ep_ptr->header.lock); + } + dapl_os_unlock(&ep_ptr->header.lock); + } + + return DAT_SUCCESS; +} + +/* + * dapls_ib_disconnect_clean + * + * Clean up outstanding connection data. This routine is invoked + * after the final disconnect callback has occurred. Only on the + * ACTIVE side of a connection. It is also called if dat_ep_connect + * times out using the consumer supplied timeout value. + * + * Input: + * ep_ptr DAPL_EP + * active Indicates active side of connection + * + * Output: + * none + * + * Returns: + * void + * + */ +void +dapls_ib_disconnect_clean(IN DAPL_EP *ep, + IN DAT_BOOLEAN active, + IN const ib_cm_events_t ib_cm_event) +{ + if (ib_cm_event == IB_CME_TIMEOUT) { + dp_ib_cm_handle_t cm_ptr; + + if ((cm_ptr = dapl_get_cm_from_ep(ep)) == NULL) + return; + + dapl_log(DAPL_DBG_TYPE_WARN, + "dapls_ib_disc_clean: CONN_TIMEOUT ep %p cm %p %s\n", + ep, cm_ptr, dapl_cm_state_str(cm_ptr->state)); + + /* schedule release of socket and local resources */ + dapli_cm_free(cm_ptr); + } +} + +/* + * dapl_ib_setup_conn_listener + * + * Have the CM set up a connection listener. + * + * Input: + * ibm_hca_handle HCA handle + * qp_handle QP handle + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INTERNAL_ERROR + * DAT_CONN_QUAL_UNAVAILBLE + * DAT_CONN_QUAL_IN_USE + * + */ +DAT_RETURN +dapls_ib_setup_conn_listener(IN DAPL_IA *ia, + IN DAT_UINT64 sid, + IN DAPL_SP *sp) +{ + ib_cm_srvc_handle_t cm = NULL; + + dapl_dbg_log(DAPL_DBG_TYPE_EP, + " listen(ia %p ServiceID %x sp %p)\n", + ia, sid, sp); + + /* reserve local port, then allocate CM object */ + if (!ucm_get_port(&ia->hca_ptr->ib_trans, (uint16_t)sid)) { + dapl_dbg_log(DAPL_DBG_TYPE_WARN, + " listen: ERROR %s on conn_qual %x\n", + strerror(errno), sid); + return DAT_CONN_QUAL_IN_USE; + } + + /* cm_create will setup saddr for listen server */ + if ((cm = dapls_ib_cm_create(NULL)) == NULL) + return DAT_INSUFFICIENT_RESOURCES; + + /* LISTEN: init DST address and QP info to local CM server info */ + cm->sp = sp; + cm->hca = ia->hca_ptr; + cm->msg.sport = htons((uint16_t)sid); + cm->msg.sqpn = htonl(ia->hca_ptr->ib_trans.qp->qp_num); + cm->msg.saddr.ib.qp_type = IBV_QPT_UD; + cm->msg.saddr.ib.lid = ia->hca_ptr->ib_trans.addr.ib.lid; + dapl_os_memcpy(&cm->msg.saddr.ib.gid[0], + &cm->hca->ib_trans.addr.ib.gid, 16); + + /* save cm_handle reference in service point */ + sp->cm_srvc_handle = cm; + + /* queue up listen socket to process inbound CR's */ + cm->state = DCM_LISTEN; + dapli_queue_listen(cm); + + return DAT_SUCCESS; +} + + +/* + * dapl_ib_remove_conn_listener + * + * Have the CM remove a connection listener. + * + * Input: + * ia_handle IA handle + * ServiceID IB Channel Service ID + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_STATE + * + */ +DAT_RETURN +dapls_ib_remove_conn_listener(IN DAPL_IA *ia, IN DAPL_SP *sp) +{ + ib_cm_srvc_handle_t cm = sp->cm_srvc_handle; + + /* free cm_srvc_handle and port, and mark CM for cleanup */ + if (cm) { + dapl_dbg_log(DAPL_DBG_TYPE_EP, + " remove_listener(ia %p sp %p cm %p psp=%x)\n", + ia, sp, cm, ntohs(cm->msg.dport)); + + sp->cm_srvc_handle = NULL; + dapli_dequeue_listen(cm); + ucm_free_port(&cm->hca->ib_trans, ntohs(cm->msg.sport)); + dapls_cm_release(cm); /* last ref, dealloc */ + } + return DAT_SUCCESS; +} + +/* + * dapls_ib_accept_connection + * + * Perform necessary steps to accept a connection + * + * Input: + * cr_handle + * ep_handle + * private_data_size + * private_data + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INTERNAL_ERROR + * + */ +DAT_RETURN +dapls_ib_accept_connection(IN DAT_CR_HANDLE cr_handle, + IN DAT_EP_HANDLE ep_handle, + IN DAT_COUNT p_size, + IN const DAT_PVOID p_data) +{ + DAPL_CR *cr = (DAPL_CR *)cr_handle; + DAPL_EP *ep = (DAPL_EP *)ep_handle; + + dapl_dbg_log(DAPL_DBG_TYPE_EP, + " accept_connection(cr %p ep %p prd %p,%d)\n", + cr, ep, p_data, p_size); + + /* allocate and attach a QP if necessary */ + if (ep->qp_state == DAPL_QP_STATE_UNATTACHED) { + DAT_RETURN status; + status = dapls_ib_qp_alloc(ep->header.owner_ia, + ep, ep); + if (status != DAT_SUCCESS) + return status; + } + return (dapli_accept_usr(ep, cr, p_size, p_data)); +} + +/* + * dapls_ib_reject_connection + * + * Reject a connection + * + * Input: + * cr_handle + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INTERNAL_ERROR + * + */ +DAT_RETURN +dapls_ib_reject_connection(IN dp_ib_cm_handle_t cm, + IN int reason, + IN DAT_COUNT psize, IN const DAT_PVOID pdata) +{ + dapl_dbg_log(DAPL_DBG_TYPE_EP, + " reject(cm %p reason %x, pdata %p, psize %d)\n", + cm, reason, pdata, psize); + + if (psize > DCM_MAX_PDATA_SIZE) + return DAT_LENGTH_ERROR; + + /* cr_thread will destroy CR, update saddr lid, gid, qp_type info */ + dapl_os_lock(&cm->lock); + dapl_log(DAPL_DBG_TYPE_CM, + " PASSIVE: REJECTING CM_REQ:" + " cm %p op %s, st %s slid %x iqp %x port %x ->" + " dlid %x iqp %x port %x\n", cm, + dapl_cm_op_str(ntohs(cm->msg.op)), + dapl_cm_state_str(cm->state), + ntohs(cm->hca->ib_trans.addr.ib.lid), + ntohl(cm->msg.saddr.ib.qpn), + ntohs(cm->msg.sport), ntohs(cm->msg.daddr.ib.lid), + ntohl(cm->msg.daddr.ib.qpn), ntohs(cm->msg.dport)); + + cm->state = DCM_REJECTED; + cm->msg.saddr.ib.lid = cm->hca->ib_trans.addr.ib.lid; + cm->msg.saddr.ib.qp_type = cm->msg.daddr.ib.qp_type; + dapl_os_memcpy(&cm->msg.saddr.ib.gid[0], + &cm->hca->ib_trans.addr.ib.gid, 16); + cm->msg.op = htons(DCM_REJ_USER); + + if (ucm_send(&cm->hca->ib_trans, &cm->msg, pdata, psize)) { + dapl_log(DAPL_DBG_TYPE_WARN, + " cm_reject: send ERR: %s\n", strerror(errno)); + dapl_os_unlock(&cm->lock); + return DAT_INTERNAL_ERROR; + } + dapl_os_unlock(&cm->lock); + dapli_cm_free(cm); + return DAT_SUCCESS; +} + +/* + * dapls_ib_cm_remote_addr + * + * Obtain the remote IP address given a connection + * + * Input: + * cr_handle + * + * Output: + * remote_ia_address: where to place the remote address + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + * + */ +DAT_RETURN +dapls_ib_cm_remote_addr(IN DAT_HANDLE dat_handle, + OUT DAT_SOCK_ADDR6 * remote_ia_address) +{ + DAPL_HEADER *header; + dp_ib_cm_handle_t cm; + + dapl_dbg_log(DAPL_DBG_TYPE_EP, + "dapls_ib_cm_remote_addr(dat_handle %p, ....)\n", + dat_handle); + + header = (DAPL_HEADER *) dat_handle; + + if (header->magic == DAPL_MAGIC_EP) + cm = dapl_get_cm_from_ep((DAPL_EP *) dat_handle); + else if (header->magic == DAPL_MAGIC_CR) + cm = ((DAPL_CR *) dat_handle)->ib_cm_handle; + else + return DAT_INVALID_HANDLE; + + dapl_os_memcpy(remote_ia_address, + &cm->msg.daddr, sizeof(DAT_SOCK_ADDR6)); + + return DAT_SUCCESS; +} + +int dapls_ib_private_data_size( + IN DAPL_HCA *hca_ptr) +{ + return DCM_MAX_PDATA_SIZE; +} + +#if defined(_WIN32) || defined(_WIN64) + +void cm_thread(void *arg) +{ + struct dapl_hca *hca = arg; + dp_ib_cm_handle_t cm, next; + DWORD time_ms; + + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, " cm_thread: ENTER hca %p\n", hca); + dapl_os_lock(&hca->ib_trans.lock); + for (hca->ib_trans.cm_state = IB_THREAD_RUN; + hca->ib_trans.cm_state == IB_THREAD_RUN || + !dapl_llist_is_empty(&hca->ib_trans.list); + dapl_os_lock(&hca->ib_trans.lock)) { + + time_ms = INFINITE; + CompSetZero(&hca->ib_trans.signal.set); + CompSetAdd(&hca->ib_hca_handle->channel, &hca->ib_trans.signal.set); + CompSetAdd(&hca->ib_trans.rch->comp_channel, &hca->ib_trans.signal.set); + CompSetAdd(&hca->ib_trans.ib_cq->comp_channel, &hca->ib_trans.signal.set); + + next = dapl_llist_is_empty(&hca->ib_trans.list) ? NULL : + dapl_llist_peek_head(&hca->ib_trans.list); + + while (next) { + cm = next; + next = dapl_llist_next_entry(&hca->ib_trans.list, + (DAPL_LLIST_ENTRY *)&cm->local_entry); + dapls_cm_acquire(cm); /* hold thread ref */ + dapl_os_lock(&cm->lock); + if (cm->state == DCM_FREE || + hca->ib_trans.cm_state != IB_THREAD_RUN) { + dapl_os_unlock(&cm->lock); + dapl_log(DAPL_DBG_TYPE_CM, + " CM FREE: %p ep=%p st=%s refs=%d\n", + cm, cm->ep, dapl_cm_state_str(cm->state), + cm->ref_count); + + dapls_cm_release(cm); /* release alloc ref */ + dapli_cm_dequeue(cm); /* release workq ref */ + dapls_cm_release(cm); /* release thread ref */ + continue; + } + dapl_os_unlock(&cm->lock); + ucm_check_timers(cm, &time_ms); + dapls_cm_release(cm); /* release thread ref */ + } + + dapl_os_unlock(&hca->ib_trans.lock); + + hca->ib_hca_handle->channel.Milliseconds = time_ms; + hca->ib_trans.rch->comp_channel.Milliseconds = time_ms; + hca->ib_trans.ib_cq->comp_channel.Milliseconds = time_ms; + CompSetPoll(&hca->ib_trans.signal.set, time_ms); + + hca->ib_hca_handle->channel.Milliseconds = 0; + hca->ib_trans.rch->comp_channel.Milliseconds = 0; + hca->ib_trans.ib_cq->comp_channel.Milliseconds = 0; + + ucm_recv(&hca->ib_trans); + ucm_async_event(hca); + dapli_cq_event_cb(&hca->ib_trans); + } + + dapl_os_unlock(&hca->ib_trans.lock); + hca->ib_trans.cm_state = IB_THREAD_EXIT; + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, " cm_thread(hca %p) exit\n", hca); +} + +#else // _WIN32 || _WIN64 + +void cm_thread(void *arg) +{ + struct dapl_hca *hca = arg; + dp_ib_cm_handle_t cm, next; + struct dapl_fd_set *set; + char rbuf[2]; + int time_ms; + + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, " cm_thread: ENTER hca %p\n", hca); + set = dapl_alloc_fd_set(); + if (!set) + goto out; + + dapl_os_lock(&hca->ib_trans.lock); + hca->ib_trans.cm_state = IB_THREAD_RUN; + + while (1) { + time_ms = -1; /* reset to blocking */ + dapl_fd_zero(set); + dapl_fd_set(hca->ib_trans.signal.scm[0], set, DAPL_FD_READ); + dapl_fd_set(hca->ib_hca_handle->async_fd, set, DAPL_FD_READ); + dapl_fd_set(hca->ib_trans.rch->fd, set, DAPL_FD_READ); + dapl_fd_set(hca->ib_trans.ib_cq->fd, set, DAPL_FD_READ); + + if (!dapl_llist_is_empty(&hca->ib_trans.list)) + next = dapl_llist_peek_head(&hca->ib_trans.list); + else + next = NULL; + + while (next) { + cm = next; + next = dapl_llist_next_entry( + &hca->ib_trans.list, + (DAPL_LLIST_ENTRY *)&cm->local_entry); + dapls_cm_acquire(cm); /* hold thread ref */ + dapl_os_lock(&cm->lock); + if (cm->state == DCM_FREE || + hca->ib_trans.cm_state != IB_THREAD_RUN) { + dapl_os_unlock(&cm->lock); + dapl_log(DAPL_DBG_TYPE_CM, + " CM FREE: %p ep=%p st=%s refs=%d\n", + cm, cm->ep, dapl_cm_state_str(cm->state), + cm->ref_count); + + dapls_cm_release(cm); /* release alloc ref */ + dapli_cm_dequeue(cm); /* release workq ref */ + dapls_cm_release(cm); /* release thread ref */ + continue; + } + dapl_os_unlock(&cm->lock); + ucm_check_timers(cm, &time_ms); + dapls_cm_release(cm); /* release thread ref */ + } + + /* set to exit and all resources destroyed */ + if ((hca->ib_trans.cm_state != IB_THREAD_RUN) && + (dapl_llist_is_empty(&hca->ib_trans.list))) + break; + + dapl_os_unlock(&hca->ib_trans.lock); + dapl_select(set, time_ms); + + /* Process events: CM, ASYNC, NOTIFY THREAD */ + if (dapl_poll(hca->ib_trans.rch->fd, + DAPL_FD_READ) == DAPL_FD_READ) { + ucm_recv(&hca->ib_trans); + } + if (dapl_poll(hca->ib_hca_handle->async_fd, + DAPL_FD_READ) == DAPL_FD_READ) { + ucm_async_event(hca); + } + if (dapl_poll(hca->ib_trans.ib_cq->fd, + DAPL_FD_READ) == DAPL_FD_READ) { + dapli_cq_event_cb(&hca->ib_trans); + } + while (dapl_poll(hca->ib_trans.signal.scm[0], + DAPL_FD_READ) == DAPL_FD_READ) { + recv(hca->ib_trans.signal.scm[0], rbuf, 2, 0); + } + dapl_os_lock(&hca->ib_trans.lock); + + /* set to exit and all resources destroyed */ + if ((hca->ib_trans.cm_state != IB_THREAD_RUN) && + (dapl_llist_is_empty(&hca->ib_trans.list))) + break; + } + + dapl_os_unlock(&hca->ib_trans.lock); + free(set); +out: + hca->ib_trans.cm_state = IB_THREAD_EXIT; + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, " cm_thread(hca %p) exit\n", hca); +} +#endif + +#ifdef DAPL_COUNTERS +static char _ctr_host_[128]; +/* Debug aid: List all Connections in process and state */ +void dapls_print_cm_list(IN DAPL_IA *ia_ptr) +{ + /* Print in process CM's for this IA, if debug type set */ + int i = 0; + dp_ib_cm_handle_t cm, next_cm; + struct dapl_llist_entry **list; + DAPL_OS_LOCK *lock; + + /* LISTEN LIST */ + list = &ia_ptr->hca_ptr->ib_trans.llist; + lock = &ia_ptr->hca_ptr->ib_trans.llock; + + dapl_os_lock(lock); + if (!dapl_llist_is_empty((DAPL_LLIST_HEAD*)list)) + next_cm = dapl_llist_peek_head((DAPL_LLIST_HEAD*)list); + else + next_cm = NULL; + + gethostname(_ctr_host_, sizeof(_ctr_host_)); + printf("\n [%s:%x] DAPL IA LISTEN/CONNECTIONS IN PROCESS:\n", + _ctr_host_ , dapl_os_getpid()); + + while (next_cm) { + cm = next_cm; + next_cm = dapl_llist_next_entry((DAPL_LLIST_HEAD*)list, + (DAPL_LLIST_ENTRY*)&cm->local_entry); + + printf( " LISTEN[%d]: sp %p %s uCM_QP: %x %x %x l_pid %x (%x)\n", + i, cm->sp, dapl_cm_state_str(cm->state), + ntohs(cm->msg.saddr.ib.lid), ntohs(cm->msg.sport), + ntohl(cm->msg.sqpn), ntohl(*(DAT_UINT32*)cm->msg.resv), + ntohl(*(DAT_UINT32*)cm->msg.resv)); + i++; + } + dapl_os_unlock(lock); + + /* CONNECTION LIST */ + list = &ia_ptr->hca_ptr->ib_trans.list; + lock = &ia_ptr->hca_ptr->ib_trans.lock; + + dapl_os_lock(lock); + if (!dapl_llist_is_empty((DAPL_LLIST_HEAD*)list)) + next_cm = dapl_llist_peek_head((DAPL_LLIST_HEAD*)list); + else + next_cm = NULL; + + while (next_cm) { + cm = next_cm; + next_cm = dapl_llist_next_entry((DAPL_LLIST_HEAD*)list, + (DAPL_LLIST_ENTRY*)&cm->local_entry); + + printf( " CONN[%d]: ep %p cm %p %s %s" + " %x %x %x %s %x %x %x r_pid %x (%x)\n", + i, cm->ep, cm, + cm->msg.saddr.ib.qp_type == IBV_QPT_RC ? "RC" : "UD", + dapl_cm_state_str(cm->state), + ntohs(cm->msg.saddr.ib.lid), + ntohs(cm->msg.sport), + ntohl(cm->msg.saddr.ib.qpn), + cm->sp ? "<-" : "->", + ntohs(cm->msg.daddr.ib.lid), + ntohs(cm->msg.dport), + ntohl(cm->msg.daddr.ib.qpn), + ntohs(cm->msg.op) == DCM_REQ ? 0 : ntohl(*(DAT_UINT32*)cm->msg.resv), + ntohs(cm->msg.op) == DCM_REQ ? 0 : ntohl(*(DAT_UINT32*)cm->msg.resv)); + i++; + } + printf("\n"); + dapl_os_unlock(lock); +} +#endif diff --git a/branches/WOF2-3/ulp/dapl2/dapl/openib_ucm/dapl_ib_util.h b/branches/WOF2-3/ulp/dapl2/dapl/openib_ucm/dapl_ib_util.h new file mode 100644 index 00000000..25ce963e --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/openib_ucm/dapl_ib_util.h @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2009 Intel Corporation. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#ifndef _DAPL_IB_UTIL_H_ +#define _DAPL_IB_UTIL_H_ +#define _OPENIB_SCM_ + +#include +#include "openib_osd.h" +#include "dapl_ib_common.h" + +/* DAPL CM objects MUST include list_entry, ref_count, event for EP linking */ +struct ib_cm_handle +{ + struct dapl_llist_entry list_entry; + struct dapl_llist_entry local_entry; + DAPL_OS_WAIT_OBJECT event; + DAPL_OS_LOCK lock; + DAPL_OS_TIMEVAL timer; + int ref_count; + int state; + int retries; + struct dapl_hca *hca; + struct dapl_sp *sp; + struct dapl_ep *ep; + struct ibv_ah *ah; + uint16_t p_size; /* accept p_data, for retries */ + uint8_t p_data[DCM_MAX_PDATA_SIZE]; + ib_cm_msg_t msg; +}; + +typedef struct ib_cm_handle *dp_ib_cm_handle_t; +typedef dp_ib_cm_handle_t ib_cm_srvc_handle_t; + +/* Definitions */ +#define IB_INVALID_HANDLE NULL + +/* ib_hca_transport_t, specific to this implementation */ +typedef struct _ib_hca_transport +{ + struct ibv_device *ib_dev; + struct dapl_hca *hca; + struct ibv_context *ib_ctx; + struct ibv_comp_channel *ib_cq; + ib_cq_handle_t ib_cq_empty; + int destroy; + int cm_state; + DAPL_OS_THREAD thread; + DAPL_OS_LOCK lock; /* connect list */ + struct dapl_llist_entry *list; + DAPL_OS_LOCK llock; /* listen list */ + struct dapl_llist_entry *llist; + ib_async_handler_t async_unafiliated; + void *async_un_ctx; + ib_async_cq_handler_t async_cq_error; + ib_async_dto_handler_t async_cq; + ib_async_qp_handler_t async_qp_error; + union dcm_addr addr; /* lid, port, qp_num, gid */ + int max_inline_send; + int rd_atom_in; + int rd_atom_out; + uint8_t ack_timer; + uint8_t ack_retry; + uint8_t rnr_timer; + uint8_t rnr_retry; + uint8_t global; + uint8_t hop_limit; + uint8_t tclass; + uint8_t mtu; + DAT_NAMED_ATTR named_attr; + struct dapl_thread_signal signal; + int cqe; + int qpe; + int retries; + int cm_timer; + int rep_time; + int rtu_time; + DAPL_OS_LOCK slock; + int s_hd; + int s_tl; + struct ibv_pd *pd; + struct ibv_cq *scq; + struct ibv_cq *rcq; + struct ibv_qp *qp; + struct ibv_mr *mr_rbuf; + struct ibv_mr *mr_sbuf; + ib_cm_msg_t *sbuf; + ib_cm_msg_t *rbuf; + struct ibv_comp_channel *rch; + struct ibv_ah **ah; + DAPL_OS_LOCK plock; + uint8_t *sid; /* Sevice IDs, port space, bitarray? */ + uint8_t sl; + uint16_t pkey; + int pkey_idx; + +} ib_hca_transport_t; + +/* prototypes */ +void cm_thread(void *arg); +void ucm_async_event(struct dapl_hca *hca); +void dapli_cq_event_cb(struct _ib_hca_transport *tp); +void dapls_cm_acquire(dp_ib_cm_handle_t cm_ptr); +void dapls_cm_release(dp_ib_cm_handle_t cm_ptr); +void dapls_cm_free(dp_ib_cm_handle_t cm_ptr); + +#ifdef DAPL_COUNTERS +void dapls_print_cm_list(IN DAPL_IA *ia_ptr); +#endif + +#endif /* _DAPL_IB_UTIL_H_ */ + diff --git a/branches/WOF2-3/ulp/dapl2/dapl/openib_ucm/device.c b/branches/WOF2-3/ulp/dapl2/dapl/openib_ucm/device.c new file mode 100644 index 00000000..1959c767 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/openib_ucm/device.c @@ -0,0 +1,672 @@ +/* + * Copyright (c) 2009 Intel Corporation. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "openib_osd.h" +#include "dapl.h" +#include "dapl_adapter_util.h" +#include "dapl_ib_util.h" +#include "dapl_osd.h" + +#include + +static void ucm_service_destroy(IN DAPL_HCA *hca); +static int ucm_service_create(IN DAPL_HCA *hca); + +#if defined (_WIN32) +#include + +static int32_t create_os_signal(IN DAPL_HCA * hca_ptr) +{ + return CompSetInit(&hca_ptr->ib_trans.signal.set); +} + +static void destroy_os_signal(IN DAPL_HCA * hca_ptr) +{ + CompSetCleanup(&hca_ptr->ib_trans.signal.set); +} + +static int dapls_config_verbs(struct ibv_context *verbs) +{ + verbs->channel.Milliseconds = 0; + return 0; +} + +static int dapls_config_comp_channel(struct ibv_comp_channel *channel) +{ + channel->comp_channel.Milliseconds = 0; + return 0; +} + +#else // _WIN32 + +static int32_t create_os_signal(IN DAPL_HCA * hca_ptr) +{ + DAPL_SOCKET listen_socket; + struct sockaddr_in addr; + socklen_t addrlen = sizeof(addr); + int ret; + + listen_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (listen_socket == DAPL_INVALID_SOCKET) + return 1; + + memset(&addr, 0, sizeof addr); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(0x7f000001); + ret = bind(listen_socket, (struct sockaddr *)&addr, sizeof addr); + if (ret) + goto err1; + + ret = getsockname(listen_socket, (struct sockaddr *)&addr, &addrlen); + if (ret) + goto err1; + + ret = listen(listen_socket, 0); + if (ret) + goto err1; + + hca_ptr->ib_trans.signal.scm[1] = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (hca_ptr->ib_trans.signal.scm[1] == DAPL_INVALID_SOCKET) + goto err1; + + ret = connect(hca_ptr->ib_trans.signal.scm[1], + (struct sockaddr *)&addr, sizeof(addr)); + if (ret) + goto err2; + + hca_ptr->ib_trans.signal.scm[0] = accept(listen_socket, NULL, NULL); + if (hca_ptr->ib_trans.signal.scm[0] == DAPL_INVALID_SOCKET) + goto err2; + + closesocket(listen_socket); + return 0; + + err2: + closesocket(hca_ptr->ib_trans.signal.scm[1]); + err1: + closesocket(listen_socket); + return 1; +} + +static void destroy_os_signal(IN DAPL_HCA * hca_ptr) +{ + closesocket(hca_ptr->ib_trans.signal.scm[0]); + closesocket(hca_ptr->ib_trans.signal.scm[1]); +} + +static int dapls_config_fd(int fd) +{ + int opts; + + opts = fcntl(fd, F_GETFL); + if (opts < 0 || fcntl(fd, F_SETFL, opts | O_NONBLOCK) < 0) { + dapl_log(DAPL_DBG_TYPE_ERR, + " dapls_config_fd: fcntl on fd %d ERR %d %s\n", + fd, opts, strerror(errno)); + return errno; + } + + return 0; +} + +static int dapls_config_verbs(struct ibv_context *verbs) +{ + return dapls_config_fd(verbs->async_fd); +} + +static int dapls_config_comp_channel(struct ibv_comp_channel *channel) +{ + return dapls_config_fd(channel->fd); +} + +#endif + +/* + * dapls_ib_init, dapls_ib_release + * + * Initialize Verb related items for device open + * + * Input: + * none + * + * Output: + * none + * + * Returns: + * 0 success, -1 error + * + */ +int32_t dapls_ib_init(void) +{ + return 0; +} + +int32_t dapls_ib_release(void) +{ + return 0; +} + +/* + * dapls_ib_open_hca + * + * Open HCA + * + * Input: + * *hca_name pointer to provider device name + * *ib_hca_handle_p pointer to provide HCA handle + * + * Output: + * none + * + * Return: + * DAT_SUCCESS + * dapl_convert_errno + * + */ +DAT_RETURN dapls_ib_open_hca(IN IB_HCA_NAME hca_name, IN DAPL_HCA * hca_ptr) +{ + struct ibv_device **dev_list; + struct ibv_port_attr port_attr; + int i; + DAT_RETURN dat_status; + + /* Get list of all IB devices, find match, open */ + dev_list = ibv_get_device_list(NULL); + if (!dev_list) { + dapl_dbg_log(DAPL_DBG_TYPE_ERR, + " open_hca: ibv_get_device_list() failed\n", + hca_name); + return DAT_INTERNAL_ERROR; + } + + for (i = 0; dev_list[i]; ++i) { + hca_ptr->ib_trans.ib_dev = dev_list[i]; + if (!strcmp(ibv_get_device_name(hca_ptr->ib_trans.ib_dev), + hca_name)) + goto found; + } + + dapl_log(DAPL_DBG_TYPE_ERR, + " open_hca: device %s not found\n", hca_name); + goto err; + +found: + + hca_ptr->ib_hca_handle = ibv_open_device(hca_ptr->ib_trans.ib_dev); + if (!hca_ptr->ib_hca_handle) { + dapl_log(DAPL_DBG_TYPE_ERR, + " open_hca: dev open failed for %s, err=%s\n", + ibv_get_device_name(hca_ptr->ib_trans.ib_dev), + strerror(errno)); + goto err; + } + hca_ptr->ib_trans.ib_ctx = hca_ptr->ib_hca_handle; + dapls_config_verbs(hca_ptr->ib_hca_handle); + + /* get lid for this hca-port, network order */ + if (ibv_query_port(hca_ptr->ib_hca_handle, + (uint8_t)hca_ptr->port_num, &port_attr)) { + dapl_log(DAPL_DBG_TYPE_ERR, + " open_hca: get lid ERR for %s, err=%s\n", + ibv_get_device_name(hca_ptr->ib_trans.ib_dev), + strerror(errno)); + goto err; + } else { + hca_ptr->ib_trans.addr.ib.lid = htons(port_attr.lid); + } + + /* get gid for this hca-port, network order */ + if (ibv_query_gid(hca_ptr->ib_hca_handle, + (uint8_t) hca_ptr->port_num, 0, + (union ibv_gid *)&hca_ptr->ib_trans.addr.ib.gid)) { + dapl_log(DAPL_DBG_TYPE_ERR, + " open_hca: query GID ERR for %s, err=%s\n", + ibv_get_device_name(hca_ptr->ib_trans.ib_dev), + strerror(errno)); + goto err; + } + + /* set RC tunables via enviroment or default */ + hca_ptr->ib_trans.max_inline_send = + dapl_os_get_env_val("DAPL_MAX_INLINE", INLINE_SEND_IB_DEFAULT); + hca_ptr->ib_trans.ack_retry = + dapl_os_get_env_val("DAPL_ACK_RETRY", DCM_ACK_RETRY); + hca_ptr->ib_trans.ack_timer = + dapl_os_get_env_val("DAPL_ACK_TIMER", DCM_ACK_TIMER); + hca_ptr->ib_trans.rnr_retry = + dapl_os_get_env_val("DAPL_RNR_RETRY", DCM_RNR_RETRY); + hca_ptr->ib_trans.rnr_timer = + dapl_os_get_env_val("DAPL_RNR_TIMER", DCM_RNR_TIMER); + hca_ptr->ib_trans.global = + dapl_os_get_env_val("DAPL_GLOBAL_ROUTING", DCM_GLOBAL); + hca_ptr->ib_trans.hop_limit = + dapl_os_get_env_val("DAPL_HOP_LIMIT", DCM_HOP_LIMIT); + hca_ptr->ib_trans.tclass = + dapl_os_get_env_val("DAPL_TCLASS", DCM_TCLASS); + hca_ptr->ib_trans.mtu = + dapl_ib_mtu(dapl_os_get_env_val("DAPL_IB_MTU", DCM_IB_MTU)); + + /* initialize CM list, LISTEN, SND queue, PSP array, locks */ + if ((dapl_os_lock_init(&hca_ptr->ib_trans.lock)) != DAT_SUCCESS) + goto err; + + if ((dapl_os_lock_init(&hca_ptr->ib_trans.llock)) != DAT_SUCCESS) + goto err; + + if ((dapl_os_lock_init(&hca_ptr->ib_trans.slock)) != DAT_SUCCESS) + goto err; + + if ((dapl_os_lock_init(&hca_ptr->ib_trans.plock)) != DAT_SUCCESS) + goto err; + + /* EVD events without direct CQ channels, CNO support */ + hca_ptr->ib_trans.ib_cq = + ibv_create_comp_channel(hca_ptr->ib_hca_handle); + if (hca_ptr->ib_trans.ib_cq == NULL) { + dapl_log(DAPL_DBG_TYPE_ERR, + " open_hca: ibv_create_comp_channel ERR %s\n", + strerror(errno)); + goto bail; + } + dapls_config_comp_channel(hca_ptr->ib_trans.ib_cq); + + /* initialize CM and listen lists on this HCA uCM QP */ + dapl_llist_init_head(&hca_ptr->ib_trans.list); + dapl_llist_init_head(&hca_ptr->ib_trans.llist); + + /* create uCM qp services */ + if (ucm_service_create(hca_ptr)) + goto bail; + + if (create_os_signal(hca_ptr)) { + dapl_log(DAPL_DBG_TYPE_ERR, + " open_hca: failed to init cr pipe - %s\n", + strerror(errno)); + goto bail; + } + + /* create thread to process inbound connect request */ + hca_ptr->ib_trans.cm_state = IB_THREAD_INIT; + dat_status = dapl_os_thread_create(cm_thread, + (void *)hca_ptr, + &hca_ptr->ib_trans.thread); + if (dat_status != DAT_SUCCESS) { + dapl_log(DAPL_DBG_TYPE_ERR, + " open_hca: failed to create thread\n"); + goto bail; + } + + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, + " open_hca: devname %s, ctx %p port %d, hostname_IP %s\n", + ibv_get_device_name(hca_ptr->ib_trans.ib_dev), + hca_ptr->ib_hca_handle, + hca_ptr->port_num, + inet_ntoa(((struct sockaddr_in *) + &hca_ptr->hca_address)->sin_addr)); + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, + " open_hca: QPN 0x%x LID 0x%x GID Subnet 0x" F64x "" + " ID 0x" F64x "\n", + ntohl(hca_ptr->ib_trans.addr.ib.qpn), + ntohs(hca_ptr->ib_trans.addr.ib.lid), + (unsigned long long) + ntohll(*(uint64_t*)&hca_ptr->ib_trans.addr.ib.gid[0]), + (unsigned long long) + ntohll(*(uint64_t*)&hca_ptr->ib_trans.addr.ib.gid[8])); + + /* save LID, GID, QPN, PORT address information, for ia_queries */ + /* Set AF_INET6 to insure callee address storage of 28 bytes */ + hca_ptr->ib_trans.hca = hca_ptr; + hca_ptr->ib_trans.addr.ib.family = AF_INET6; + hca_ptr->ib_trans.addr.ib.qp_type = IBV_QPT_UD; + memcpy(&hca_ptr->hca_address, + &hca_ptr->ib_trans.addr, + sizeof(union dcm_addr)); + + ibv_free_device_list(dev_list); + + /* wait for cm_thread */ + while (hca_ptr->ib_trans.cm_state != IB_THREAD_RUN) + dapl_os_sleep_usec(1000); + + return dat_status; + +bail: + ucm_service_destroy(hca_ptr); + ibv_close_device(hca_ptr->ib_hca_handle); + hca_ptr->ib_hca_handle = IB_INVALID_HANDLE; + +err: + ibv_free_device_list(dev_list); + return DAT_INTERNAL_ERROR; +} + +/* + * dapls_ib_close_hca + * + * Open HCA + * + * Input: + * DAPL_HCA provide CA handle + * + * Output: + * none + * + * Return: + * DAT_SUCCESS + * dapl_convert_errno + * + */ +DAT_RETURN dapls_ib_close_hca(IN DAPL_HCA * hca_ptr) +{ + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, " close_hca: %p\n", hca_ptr); + + if (hca_ptr->ib_trans.cm_state == IB_THREAD_RUN) { + hca_ptr->ib_trans.cm_state = IB_THREAD_CANCEL; + dapls_thread_signal(&hca_ptr->ib_trans.signal); + while (hca_ptr->ib_trans.cm_state != IB_THREAD_EXIT) { + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, + " close_hca: waiting for cr_thread\n"); + dapls_thread_signal(&hca_ptr->ib_trans.signal); + dapl_os_sleep_usec(1000); + } + } + + dapl_os_lock_destroy(&hca_ptr->ib_trans.lock); + dapl_os_lock_destroy(&hca_ptr->ib_trans.llock); + destroy_os_signal(hca_ptr); + ucm_service_destroy(hca_ptr); + + if (hca_ptr->ib_trans.ib_cq) + ibv_destroy_comp_channel(hca_ptr->ib_trans.ib_cq); + + if (hca_ptr->ib_trans.ib_cq_empty) { + struct ibv_comp_channel *channel; + channel = hca_ptr->ib_trans.ib_cq_empty->channel; + ibv_destroy_cq(hca_ptr->ib_trans.ib_cq_empty); + ibv_destroy_comp_channel(channel); + } + + if (hca_ptr->ib_hca_handle != IB_INVALID_HANDLE) { + if (ibv_close_device(hca_ptr->ib_hca_handle)) + return (dapl_convert_errno(errno, "ib_close_device")); + hca_ptr->ib_hca_handle = IB_INVALID_HANDLE; + } + + return (DAT_SUCCESS); +} + +/* Create uCM endpoint services, allocate remote_ah's array */ +static void ucm_service_destroy(IN DAPL_HCA *hca) +{ + ib_hca_transport_t *tp = &hca->ib_trans; + int msg_size = sizeof(ib_cm_msg_t); + + if (tp->mr_sbuf) + ibv_dereg_mr(tp->mr_sbuf); + + if (tp->mr_rbuf) + ibv_dereg_mr(tp->mr_rbuf); + + if (tp->qp) + ibv_destroy_qp(tp->qp); + + if (tp->scq) + ibv_destroy_cq(tp->scq); + + if (tp->rcq) + ibv_destroy_cq(tp->rcq); + + if (tp->rch) + ibv_destroy_comp_channel(tp->rch); + + if (tp->ah) { + int i; + + for (i = 0;i < 0xffff; i++) { + if (tp->ah[i]) + ibv_destroy_ah(tp->ah[i]); + } + dapl_os_free(tp->ah, (sizeof(*tp->ah) * 0xffff)); + } + + if (tp->pd) + ibv_dealloc_pd(tp->pd); + + if (tp->sid) + dapl_os_free(tp->sid, (sizeof(*tp->sid) * 0xffff)); + + if (tp->rbuf) + dapl_os_free(tp->rbuf, (msg_size * tp->qpe)); + + if (tp->sbuf) + dapl_os_free(tp->sbuf, (msg_size * tp->qpe)); +} + +static int ucm_service_create(IN DAPL_HCA *hca) +{ + struct ibv_qp_init_attr qp_create; + ib_hca_transport_t *tp = &hca->ib_trans; + struct ibv_recv_wr recv_wr, *recv_err; + struct ibv_sge sge; + int i, mlen = sizeof(ib_cm_msg_t); + int hlen = sizeof(struct ibv_grh); /* hdr included with UD recv */ + + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, " ucm_create: \n"); + + /* setup CM timers and queue sizes */ + tp->retries = dapl_os_get_env_val("DAPL_UCM_RETRY", DCM_RETRY_CNT); + tp->rep_time = dapl_os_get_env_val("DAPL_UCM_REP_TIME", DCM_REP_TIME); + tp->rtu_time = dapl_os_get_env_val("DAPL_UCM_RTU_TIME", DCM_RTU_TIME); + tp->cm_timer = DAPL_MIN(tp->rep_time,tp->rtu_time); + tp->qpe = dapl_os_get_env_val("DAPL_UCM_QP_SIZE", DCM_QP_SIZE); + tp->cqe = dapl_os_get_env_val("DAPL_UCM_CQ_SIZE", DCM_CQ_SIZE); + tp->pd = ibv_alloc_pd(hca->ib_hca_handle); + if (!tp->pd) + goto bail; + + dapl_log(DAPL_DBG_TYPE_UTIL, + " create_service: pd %p ctx %p handle 0x%x\n", + tp->pd, tp->pd->context, tp->pd->handle); + + tp->rch = ibv_create_comp_channel(hca->ib_hca_handle); + if (!tp->rch) + goto bail; + + tp->scq = ibv_create_cq(hca->ib_hca_handle, tp->cqe, hca, NULL, 0); + if (!tp->scq) + goto bail; + + tp->rcq = ibv_create_cq(hca->ib_hca_handle, tp->cqe, hca, tp->rch, 0); + if (!tp->rcq) + goto bail; + + if(ibv_req_notify_cq(tp->rcq, 0)) + goto bail; + + dapl_os_memzero((void *)&qp_create, sizeof(qp_create)); + qp_create.qp_type = IBV_QPT_UD; + qp_create.send_cq = tp->scq; + qp_create.recv_cq = tp->rcq; + qp_create.cap.max_send_wr = qp_create.cap.max_recv_wr = tp->qpe; + qp_create.cap.max_send_sge = qp_create.cap.max_recv_sge = 1; + qp_create.cap.max_inline_data = tp->max_inline_send; + qp_create.qp_context = (void *)hca; + + tp->qp = ibv_create_qp(tp->pd, &qp_create); + if (!tp->qp) + goto bail; + + tp->ah = (ib_ah_handle_t*) dapl_os_alloc(sizeof(ib_ah_handle_t) * 0xffff); + tp->sid = (uint8_t*) dapl_os_alloc(sizeof(uint8_t) * 0xffff); + tp->rbuf = (void*) dapl_os_alloc((mlen + hlen) * tp->qpe); + tp->sbuf = (void*) dapl_os_alloc(mlen * tp->qpe); + + if (!tp->ah || !tp->rbuf || !tp->sbuf || !tp->sid) + goto bail; + + (void)dapl_os_memzero(tp->ah, (sizeof(ib_ah_handle_t) * 0xffff)); + (void)dapl_os_memzero(tp->sid, (sizeof(uint8_t) * 0xffff)); + tp->sid[0] = 1; /* resv slot 0, 0 == no ports available */ + (void)dapl_os_memzero(tp->rbuf, ((mlen + hlen) * tp->qpe)); + (void)dapl_os_memzero(tp->sbuf, (mlen * tp->qpe)); + + tp->mr_sbuf = ibv_reg_mr(tp->pd, tp->sbuf, + (mlen * tp->qpe), + IBV_ACCESS_LOCAL_WRITE); + if (!tp->mr_sbuf) + goto bail; + + tp->mr_rbuf = ibv_reg_mr(tp->pd, tp->rbuf, + ((mlen + hlen) * tp->qpe), + IBV_ACCESS_LOCAL_WRITE); + if (!tp->mr_rbuf) + goto bail; + + /* modify UD QP: init, rtr, rts */ + if ((dapls_modify_qp_ud(hca, tp->qp)) != DAT_SUCCESS) + goto bail; + + /* post receive buffers, setup head, tail pointers */ + recv_wr.next = NULL; + recv_wr.sg_list = &sge; + recv_wr.num_sge = 1; + sge.length = mlen + hlen; + sge.lkey = tp->mr_rbuf->lkey; + + for (i = 0; i < tp->qpe; i++) { + recv_wr.wr_id = + (uintptr_t)((char *)&tp->rbuf[i] + + sizeof(struct ibv_grh)); + sge.addr = (uintptr_t) &tp->rbuf[i]; + if (ibv_post_recv(tp->qp, &recv_wr, &recv_err)) + goto bail; + } + + /* save qp_num as part of ia_address, network order */ + tp->addr.ib.qpn = htonl(tp->qp->qp_num); + return 0; +bail: + dapl_log(DAPL_DBG_TYPE_ERR, + " ucm_create_services: ERR %s\n", strerror(errno)); + ucm_service_destroy(hca); + return -1; +} + +void ucm_async_event(struct dapl_hca *hca) +{ + struct ibv_async_event event; + struct _ib_hca_transport *tp = &hca->ib_trans; + + dapl_log(DAPL_DBG_TYPE_WARN, " async_event(%p)\n", hca); + + if (!ibv_get_async_event(hca->ib_hca_handle, &event)) { + + switch (event.event_type) { + case IBV_EVENT_CQ_ERR: + { + struct dapl_ep *evd_ptr = + event.element.cq->cq_context; + + dapl_log(DAPL_DBG_TYPE_ERR, + "dapl async_event CQ (%p) ERR %d\n", + evd_ptr, event.event_type); + + /* report up if async callback still setup */ + if (tp->async_cq_error) + tp->async_cq_error(hca->ib_hca_handle, + event.element.cq, + &event, (void *)evd_ptr); + break; + } + case IBV_EVENT_COMM_EST: + { + /* Received msgs on connected QP before RTU */ + dapl_log(DAPL_DBG_TYPE_UTIL, + " async_event COMM_EST(%p) rdata beat RTU\n", + event.element.qp); + + break; + } + case IBV_EVENT_QP_FATAL: + case IBV_EVENT_QP_REQ_ERR: + case IBV_EVENT_QP_ACCESS_ERR: + case IBV_EVENT_QP_LAST_WQE_REACHED: + case IBV_EVENT_SRQ_ERR: + case IBV_EVENT_SRQ_LIMIT_REACHED: + case IBV_EVENT_SQ_DRAINED: + { + struct dapl_ep *ep_ptr = + event.element.qp->qp_context; + + dapl_log(DAPL_DBG_TYPE_ERR, + "dapl async_event QP (%p) ERR %d\n", + ep_ptr, event.event_type); + + /* report up if async callback still setup */ + if (tp->async_qp_error) + tp->async_qp_error(hca->ib_hca_handle, + ep_ptr->qp_handle, + &event, (void *)ep_ptr); + break; + } + case IBV_EVENT_PATH_MIG: + case IBV_EVENT_PATH_MIG_ERR: + case IBV_EVENT_DEVICE_FATAL: + case IBV_EVENT_PORT_ACTIVE: + case IBV_EVENT_PORT_ERR: + case IBV_EVENT_LID_CHANGE: + case IBV_EVENT_PKEY_CHANGE: + case IBV_EVENT_SM_CHANGE: + { + dapl_log(DAPL_DBG_TYPE_WARN, + "dapl async_event: DEV ERR %d\n", + event.event_type); + + /* report up if async callback still setup */ + if (tp->async_unafiliated) + tp->async_unafiliated(hca->ib_hca_handle, + &event, + tp->async_un_ctx); + break; + } + case IBV_EVENT_CLIENT_REREGISTER: + /* no need to report this event this time */ + dapl_log(DAPL_DBG_TYPE_UTIL, + " async_event: IBV_CLIENT_REREGISTER\n"); + break; + + default: + dapl_log(DAPL_DBG_TYPE_WARN, + "dapl async_event: %d UNKNOWN\n", + event.event_type); + break; + + } + ibv_ack_async_event(&event); + } +} + diff --git a/branches/WOF2-3/ulp/dapl2/dapl/openib_ucm/linux/openib_osd.h b/branches/WOF2-3/ulp/dapl2/dapl/openib_ucm/linux/openib_osd.h new file mode 100644 index 00000000..fe60aa09 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/openib_ucm/linux/openib_osd.h @@ -0,0 +1,37 @@ +#ifndef OPENIB_OSD_H +#define OPENIB_OSD_H + +#include +#include + +#if __BYTE_ORDER == __BIG_ENDIAN +#define htonll(x) (x) +#define ntohll(x) (x) +#elif __BYTE_ORDER == __LITTLE_ENDIAN +#define htonll(x) bswap_64(x) +#define ntohll(x) bswap_64(x) +#endif +#ifndef STATIC +#define STATIC static +#endif /* STATIC */ +#ifndef _INLINE_ +#define _INLINE_ __inline__ +#endif /* _INLINE_ */ + +#define DAPL_SOCKET int +#define DAPL_INVALID_SOCKET -1 +#define DAPL_FD_SETSIZE 16 + +#define closesocket close + +struct dapl_thread_signal +{ + DAPL_SOCKET scm[2]; +}; + +STATIC _INLINE_ void dapls_thread_signal(struct dapl_thread_signal *signal) +{ + send(signal->scm[1], "w", sizeof "w", 0); +} + +#endif // OPENIB_OSD_H diff --git a/branches/WOF2-3/ulp/dapl2/dapl/openib_ucm/makefile b/branches/WOF2-3/ulp/dapl2/dapl/openib_ucm/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/openib_ucm/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\..\inc\openib.def diff --git a/branches/WOF2-3/ulp/dapl2/dapl/openib_ucm/udapl.rc b/branches/WOF2-3/ulp/dapl2/dapl/openib_ucm/udapl.rc new file mode 100644 index 00000000..908376e3 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/openib_ucm/udapl.rc @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2007, 2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#if DBG +#define VER_FILEDESCRIPTION_STR "Direct Access Provider Library v2.0 (OFA socket-cm) (Debug)" +#define VER_INTERNALNAME_STR "dapl2-ofa-ucmd.dll" +#define VER_ORIGINALFILENAME_STR "dapl2-ofa-ucmd.dll" +#else +#define VER_FILEDESCRIPTION_STR "Direct Access Provider Library v2.0 (OFA socket-cm)" +#define VER_INTERNALNAME_STR "dapl2-ofa-ucm.dll" +#define VER_ORIGINALFILENAME_STR "dapl2-ofa-ucm.dll" +#endif + +#include diff --git a/branches/WOF2-3/ulp/dapl2/dapl/openib_ucm/udapl_ofa_ucm_exports.src b/branches/WOF2-3/ulp/dapl2/dapl/openib_ucm/udapl_ofa_ucm_exports.src new file mode 100644 index 00000000..d74b7bb3 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/openib_ucm/udapl_ofa_ucm_exports.src @@ -0,0 +1,14 @@ +#if DBG +LIBRARY dapl2-ofa-ucmd.dll +#else +LIBRARY dapl2-ofa-ucm.dll +#endif + + +EXPORTS +dat_provider_init +dat_provider_fini +#ifdef DAT_EXTENSIONS +dapl_extensions +#endif + diff --git a/branches/WOF2-3/ulp/dapl2/dapl/openib_ucm/windows/openib_osd.h b/branches/WOF2-3/ulp/dapl2/dapl/openib_ucm/windows/openib_osd.h new file mode 100644 index 00000000..73220dcb --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/openib_ucm/windows/openib_osd.h @@ -0,0 +1,46 @@ +#ifndef OPENIB_OSD_H +#define OPENIB_OSD_H + +#ifndef FD_SETSIZE +#define FD_SETSIZE 1024 /* Set before including winsock2 - see select help */ +#define DAPL_FD_SETSIZE FD_SETSIZE +#endif + +#include +#include +#include +#include +#include + +#define ntohll _byteswap_uint64 +#define htonll _byteswap_uint64 + +#define DAPL_SOCKET SOCKET +#define DAPL_INVALID_SOCKET INVALID_SOCKET + +/* allow casting to WSABUF */ +struct iovec +{ + u_long iov_len; + char FAR* iov_base; +}; + +static int writev(DAPL_SOCKET s, struct iovec *vector, int count) +{ + int len, ret; + + ret = WSASend(s, (WSABUF *) vector, count, &len, 0, NULL, NULL); + return ret ? ret : len; +} + +struct dapl_thread_signal +{ + COMP_SET set; +}; + +static void dapls_thread_signal(struct dapl_thread_signal *signal) +{ + CompSetCancel(&signal->set); +} + +#endif // OPENIB_OSD_H diff --git a/branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_cno_create.c b/branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_cno_create.c new file mode 100644 index 00000000..a214c338 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_cno_create.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_cno_create.c + * + * PURPOSE: Consumer Notification Object creation + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 3.2.1 + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_cno_util.h" +#include "dapl_ia_util.h" + +/* + * dapl_cno_create + * + * DAPL Requirements Version xxx, 6.3.4.1 + * + * Create a consumer notification object instance + * + * Input: + * ia_handle + * wait_agent + * cno_handle + * + * Output: + * cno_handle + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_HANDLE + * DAT_INVALID_PARAMETER + */ +DAT_RETURN DAT_API dapl_cno_create(IN DAT_IA_HANDLE ia_handle, /* ia_handle */ + IN DAT_OS_WAIT_PROXY_AGENT wait_agent, /* agent */ + OUT DAT_CNO_HANDLE * cno_handle) +{ /* cno_handle */ + DAPL_IA *ia_ptr; + DAPL_CNO *cno_ptr; + DAT_RETURN dat_status; + + ia_ptr = (DAPL_IA *) ia_handle; + cno_ptr = NULL; + dat_status = DAT_SUCCESS; + + if (DAPL_BAD_HANDLE(ia_handle, DAPL_MAGIC_IA)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_IA); + goto bail; + } + + cno_ptr = dapl_cno_alloc(ia_ptr, wait_agent); + + if (!cno_ptr) { + dat_status = + DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); + goto bail; + } + + cno_ptr->cno_state = DAPL_CNO_STATE_UNTRIGGERED; + + dapl_ia_link_cno(ia_ptr, cno_ptr); + + *cno_handle = cno_ptr; + + bail: + if (dat_status != DAT_SUCCESS && cno_ptr != NULL) { + dapl_cno_dealloc(cno_ptr); + } + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_cno_free.c b/branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_cno_free.c new file mode 100644 index 00000000..572fb98a --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_cno_free.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_cno_free.c + * + * PURPOSE: Consumer Notification Object destruction + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 3.2.2 + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_ia_util.h" +#include "dapl_cno_util.h" + +/* + * dapl_cno_free + * + * DAPL Requirements Version xxx, 6.3.2.2 + * + * Destroy a consumer notification object instance + * + * Input: + * cno_handle + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + * DAT_INVALID_STATE + */ +DAT_RETURN DAT_API dapl_cno_free(IN DAT_CNO_HANDLE cno_handle) +{ /* cno_handle */ + DAPL_CNO *cno_ptr; + DAT_RETURN dat_status; + + dat_status = DAT_SUCCESS; + cno_ptr = (DAPL_CNO *) cno_handle; + + if (DAPL_BAD_HANDLE(cno_handle, DAPL_MAGIC_CNO)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_CNO); + goto bail; + } + + if (dapl_os_atomic_read(&cno_ptr->cno_ref_count) != 0 + || cno_ptr->cno_waiters != 0) { + dat_status = + DAT_ERROR(DAT_INVALID_STATE, DAT_INVALID_STATE_CNO_IN_USE); + goto bail; + } + + dapl_ia_unlink_cno(cno_ptr->header.owner_ia, cno_ptr); + dapl_cno_dealloc(cno_ptr); + + bail: + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_cno_modify_agent.c b/branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_cno_modify_agent.c new file mode 100644 index 00000000..887e9845 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_cno_modify_agent.c @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_cno_modify_agent.c + * + * PURPOSE: Modify the wait proxy agent associted with the CNO + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 3.2.4 + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" + +/* + * dapl_cno_modify_agent + * + * DAPL Requirements Version xxx, 6.3.2.4 + * + * Modify the wait proxy agent associted with the CNO + * + * Input: + * cno_handle + * prx_agent + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + * DAT_INVALID_PARAMETER + */ +DAT_RETURN DAT_API dapl_cno_modify_agent(IN DAT_CNO_HANDLE cno_handle, /* cno_handle */ + IN DAT_OS_WAIT_PROXY_AGENT prx_agent) +{ /* agent */ + DAPL_CNO *cno_ptr; + DAT_RETURN dat_status; + + dat_status = DAT_SUCCESS; + if (DAPL_BAD_HANDLE(cno_handle, DAPL_MAGIC_CNO)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_CNO); + goto bail; + } + + cno_ptr = (DAPL_CNO *) cno_handle; + dapl_os_lock(&cno_ptr->header.lock); + cno_ptr->cno_wait_agent = prx_agent; + dapl_os_unlock(&cno_ptr->header.lock); + + bail: + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_cno_query.c b/branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_cno_query.c new file mode 100644 index 00000000..5112e337 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_cno_query.c @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_cno_query.c + * + * PURPOSE: Return the consumer parameters of the CNO + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 3.2.5 + * + * $Id: dapl_cno_query.c 1301 2005-03-24 05:58:55Z jlentini $ + **********************************************************************/ + +#include "dapl.h" + +/* + * dapl_cno_query + * + * DAPL Requirements Version xxx, 6.3.2.5 + * + * Return the consumer parameters of the CNO + * + * Input: + * cno_handle + * cno_param_mask + * cno_param + * + * Output: + * cno_param + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + * DAT_INVALID_PARAMETER + */ +DAT_RETURN DAT_API dapl_cno_query(IN DAT_CNO_HANDLE cno_handle, /* cno_handle */ + IN DAT_CNO_PARAM_MASK cno_param_mask, /* cno_param_mask */ + OUT DAT_CNO_PARAM * cno_param) + +{ /* cno_param */ + DAPL_CNO *cno_ptr; + DAT_RETURN dat_status; + + dat_status = DAT_SUCCESS; + + if (DAPL_BAD_HANDLE(cno_handle, DAPL_MAGIC_CNO)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_CNO); + goto bail; + } + + if (NULL == cno_param) { + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG3); + goto bail; + } + + cno_ptr = (DAPL_CNO *) cno_handle; + cno_param->ia_handle = cno_ptr->header.owner_ia; + cno_param->proxy_type = DAT_PROXY_TYPE_AGENT; + cno_param->proxy.agent = cno_ptr->cno_wait_agent; + + bail: + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_cno_wait.c b/branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_cno_wait.c new file mode 100644 index 00000000..6bbd249b --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_cno_wait.c @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_cno_wait.c + * + * PURPOSE: Wait for a consumer notification event + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 3.2.3 + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" + +/* + * dapl_cno_wait + * + * DAPL Requirements Version xxx, 6.3.2.3 + * + * Wait for a consumer notification event + * + * Input: + * cno_handle + * timeout + * evd_handle + * + * Output: + * evd_handle + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + * DAT_QUEUE_EMPTY + * DAT_INVALID_PARAMETER + */ +DAT_RETURN DAT_API dapl_cno_wait(IN DAT_CNO_HANDLE cno_handle, /* cno_handle */ + IN DAT_TIMEOUT timeout, /* agent */ + OUT DAT_EVD_HANDLE * evd_handle) +{ /* ia_handle */ + DAPL_CNO *cno_ptr; + DAT_RETURN dat_status; + + if (DAPL_BAD_HANDLE(cno_handle, DAPL_MAGIC_CNO)) { + dat_status = DAT_INVALID_HANDLE | DAT_INVALID_HANDLE_CNO; + goto bail; + } + + dat_status = DAT_SUCCESS; + + cno_ptr = (DAPL_CNO *) cno_handle; + + if (cno_ptr->cno_state == DAPL_CNO_STATE_DEAD) { + dat_status = + DAT_ERROR(DAT_INVALID_STATE, DAT_INVALID_STATE_CNO_DEAD); + goto bail; + } + + dapl_os_lock(&cno_ptr->header.lock); + if (cno_ptr->cno_state == DAPL_CNO_STATE_TRIGGERED) { + cno_ptr->cno_state = DAPL_CNO_STATE_UNTRIGGERED; + *evd_handle = cno_ptr->cno_evd_triggered; + cno_ptr->cno_evd_triggered = NULL; + dapl_os_unlock(&cno_ptr->header.lock); + goto bail; + } + + while (cno_ptr->cno_state == DAPL_CNO_STATE_UNTRIGGERED + && DAT_GET_TYPE(dat_status) != DAT_TIMEOUT_EXPIRED) { + cno_ptr->cno_waiters++; + dapl_os_unlock(&cno_ptr->header.lock); + dat_status = dapl_os_wait_object_wait(&cno_ptr->cno_wait_object, + timeout); + dapl_os_lock(&cno_ptr->header.lock); + cno_ptr->cno_waiters--; + } + + if (cno_ptr->cno_state == DAPL_CNO_STATE_DEAD) { + dat_status = + DAT_ERROR(DAT_INVALID_STATE, DAT_INVALID_STATE_CNO_DEAD); + } else if (dat_status == DAT_SUCCESS) { + /* + * After the first triggering, this will be a valid handle. + * If we're racing with wakeups of other CNO waiters, + * that's ok. + */ + dapl_os_assert(cno_ptr->cno_state == DAPL_CNO_STATE_TRIGGERED); + cno_ptr->cno_state = DAPL_CNO_STATE_UNTRIGGERED; + *evd_handle = cno_ptr->cno_evd_triggered; + cno_ptr->cno_evd_triggered = NULL; + } else if (DAT_GET_TYPE(dat_status) == DAT_TIMEOUT_EXPIRED) { + cno_ptr->cno_state = DAPL_CNO_STATE_UNTRIGGERED; + *evd_handle = NULL; + dat_status = DAT_QUEUE_EMPTY; + } else { + /* + * The only other reason we could have made it out of + * the loop is an interrupted system call. + */ + dapl_os_assert(DAT_GET_TYPE(dat_status) == + DAT_INTERRUPTED_CALL); + } + dapl_os_unlock(&cno_ptr->header.lock); + + bail: + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_evd_clear_unwaitable.c b/branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_evd_clear_unwaitable.c new file mode 100644 index 00000000..ab24c043 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_evd_clear_unwaitable.c @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_evd_clear_unwaitable.c + * + * PURPOSE: EVENT management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 3.4.8 + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" + +/* + * dapl_evd_clear_unwaitable + * + * DAPL Requirements Version 1.1, 6.3.4.8 + * + * Transition the Event Dispatcher into a waitable state + * + * Input: + * evd_handle + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + */ +DAT_RETURN DAT_API dapl_evd_clear_unwaitable(IN DAT_EVD_HANDLE evd_handle) +{ + DAPL_EVD *evd_ptr; + DAT_RETURN dat_status; + + evd_ptr = (DAPL_EVD *) evd_handle; + dat_status = DAT_SUCCESS; + + if (DAPL_BAD_HANDLE(evd_handle, DAPL_MAGIC_EVD)) + { + dat_status = DAT_ERROR(DAT_INVALID_HANDLE, 0); + goto bail; + } + dapl_os_lock(&evd_ptr->header.lock); + evd_ptr->evd_waitable = DAT_TRUE; + dapl_os_unlock(&evd_ptr->header.lock); + + dat_status = DAT_SUCCESS; + + bail: + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_evd_create.c b/branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_evd_create.c new file mode 100644 index 00000000..548c2aee --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_evd_create.c @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_evd_create.c + * + * PURPOSE: EVENT management + * + * Description: Interfaces in this file are completely defined in + * the uDAPL 1.1 API, Chapter 6, section 3 + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_evd_util.h" + +/* + * dapl_evd_create + * + * DAPL Requirements Version xxx, 6.3.2.1 + * + * Create and instance of Event Dispatcher. + * + * Input: + * ia_handle + * cno_handle + * evd_min_qlen + * evd_flags + * + * Output: + * evd_handle + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + */ + +/* ** REVISIT ** + * + * Selecting the cqe handing domain must still be done. + * We *probably* want one per hca, but we could have one + * per provider or one per consumer. + */ +/* Note that if there already is a cq, it is not deleted + * even if it is not required. However, it will not be armed. + */ + +DAT_RETURN DAT_API dapl_evd_create(IN DAT_IA_HANDLE ia_handle, + IN DAT_COUNT evd_min_qlen, + IN DAT_CNO_HANDLE cno_handle, + IN DAT_EVD_FLAGS evd_flags, + OUT DAT_EVD_HANDLE * evd_handle) +{ + DAPL_IA *ia_ptr; + DAPL_EVD *evd_ptr; + DAPL_CNO *cno_ptr; + DAT_RETURN dat_status; + DAT_PROVIDER_ATTR provider_attr; + int i; + int j; + int flag_mask[6]; + + dapl_dbg_log(DAPL_DBG_TYPE_API, + "dapl_evd_create (%p, %d, %p, 0x%x, %p)\n", + ia_handle, + evd_min_qlen, cno_handle, evd_flags, evd_handle); + + ia_ptr = (DAPL_IA *) ia_handle; + cno_ptr = (DAPL_CNO *) cno_handle; + evd_ptr = NULL; + *evd_handle = NULL; + dat_status = DAT_SUCCESS; + + if (DAPL_BAD_HANDLE(ia_handle, DAPL_MAGIC_IA)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_IA); + goto bail; + } + + DAPL_CNTR(ia_ptr, DCNT_IA_EVD_CREATE); + + if (evd_min_qlen <= 0) { + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG2); + goto bail; + } + if (evd_min_qlen > ia_ptr->hca_ptr->ia_attr.max_evd_qlen) { + dat_status = + DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_TEVD); + goto bail; + } + + if (cno_handle != DAT_HANDLE_NULL + && DAPL_BAD_HANDLE(cno_handle, DAPL_MAGIC_CNO)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_CNO); + goto bail; + } + + /* + * Check the merging attributes to ensure the combination of + * flags requested is supported. + */ + dapl_ia_query(ia_handle, NULL, + 0, NULL, DAT_PROVIDER_FIELD_ALL, &provider_attr); + + /* Set up an array of flags to compare against; the EVD bits are + * a sparse array that need to be mapped to the merging flags + */ + flag_mask[0] = DAT_EVD_SOFTWARE_FLAG; + flag_mask[1] = DAT_EVD_CR_FLAG; + flag_mask[2] = DAT_EVD_DTO_FLAG; + flag_mask[3] = DAT_EVD_CONNECTION_FLAG; + flag_mask[4] = DAT_EVD_RMR_BIND_FLAG; + flag_mask[5] = DAT_EVD_ASYNC_FLAG; + + for (i = 0; i < 6; i++) { + if (flag_mask[i] & evd_flags) { + for (j = 0; j < 6; j++) { + if (flag_mask[j] & evd_flags) { + if (provider_attr. + evd_stream_merging_supported[i][j] + == DAT_FALSE) { + dat_status = + DAT_ERROR + (DAT_INVALID_PARAMETER, + DAT_INVALID_ARG4); + goto bail; + } + } + } /* end for j */ + } + } /* end for i */ + + dat_status = dapls_evd_internal_create(ia_ptr, + cno_ptr, + evd_min_qlen, + evd_flags, &evd_ptr); + if (dat_status != DAT_SUCCESS) { + goto bail; + } + + evd_ptr->evd_state = DAPL_EVD_STATE_OPEN; + + *evd_handle = (DAT_EVD_HANDLE) evd_ptr; + + bail: + if (dat_status != DAT_SUCCESS) { + if (evd_ptr) { + dapl_evd_free(evd_ptr); + } + } + + dapl_dbg_log(DAPL_DBG_TYPE_RTN, + "dapl_evd_create () returns 0x%x\n", dat_status); + + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_evd_disable.c b/branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_evd_disable.c new file mode 100644 index 00000000..78f1b0e1 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_evd_disable.c @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_evd_disable.c + * + * PURPOSE: EVENT management + * + * Description: Interfaces in this file are completely defined in + * the uDAPL 1.1 API, Chapter 6, section 3 + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" + +/* + * dapl_evd_disable + * + * DAPL Requirements Version xxx, 6.3.2.5 + * + * Modify the size of the event queue of an Event Dispatcher + * + * Input: + * evd_handle + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + */ + +DAT_RETURN DAT_API dapl_evd_disable(IN DAT_EVD_HANDLE evd_handle) +{ + DAPL_EVD *evd_ptr; + DAT_RETURN dat_status; + + evd_ptr = (DAPL_EVD *) evd_handle; + dat_status = DAT_SUCCESS; + + if (DAPL_BAD_HANDLE(evd_handle, DAPL_MAGIC_EVD)) + { + dat_status = DAT_ERROR(DAT_INVALID_HANDLE, 0); + goto bail; + } + + evd_ptr->evd_enabled = DAT_FALSE; + + bail: + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_evd_enable.c b/branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_evd_enable.c new file mode 100644 index 00000000..b5991c74 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_evd_enable.c @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_evd_enable.c + * + * PURPOSE: EVENT management + * + * Description: Interfaces in this file are completely defined in + * the uDAPL 1.1 API, Chapter 6, section 3 + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_adapter_util.h" + +/* + * dapl_evd_enable + * + * DAPL Requirements Version xxx, 6.3.2.5 + * + * Modify the size of the event queue of an Event Dispatcher + * + * Input: + * evd_handle + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + */ + +DAT_RETURN DAT_API dapl_evd_enable(IN DAT_EVD_HANDLE evd_handle) +{ + DAPL_EVD *evd_ptr; + DAT_RETURN dat_status; + + evd_ptr = (DAPL_EVD *) evd_handle; + dat_status = DAT_SUCCESS; + + if (DAPL_BAD_HANDLE(evd_handle, DAPL_MAGIC_EVD)) + { + dat_status = DAT_ERROR(DAT_INVALID_HANDLE, 0); + goto bail; + } + + evd_ptr->evd_enabled = DAT_TRUE; + + /* We need to enable the callback handler if there is a CNO. */ + if (evd_ptr->cno_ptr != NULL && + evd_ptr->ib_cq_handle != IB_INVALID_HANDLE) { + dat_status = + dapls_ib_completion_notify(evd_ptr->header.owner_ia-> + hca_ptr->ib_hca_handle, evd_ptr, + IB_NOTIFY_ON_NEXT_COMP); + + /* FIXME report error */ + dapl_os_assert(dat_status == DAT_SUCCESS); + } + + bail: + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_evd_modify_cno.c b/branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_evd_modify_cno.c new file mode 100644 index 00000000..955a835d --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_evd_modify_cno.c @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_evd_modify_cno.c + * + * PURPOSE: Event Management + * + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 3 + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_adapter_util.h" + +/* + * dapl_evd_modify_cno + * + * DAPL Requirements Version xxx, 6.3.2.4 + * + * Modify the CNO associated with the EVD + * + * Input: + * evd_handle + * cno_handle + * + * Output: + * none + * + * Returns: + * DAT_SUCCSSS + * DAT_INVALID_HANDLE + */ + +DAT_RETURN DAT_API dapl_evd_modify_cno(IN DAT_EVD_HANDLE evd_handle, + IN DAT_CNO_HANDLE cno_handle) + +{ + DAPL_EVD *evd_ptr; + DAPL_CNO *cno_ptr; + DAPL_CNO *old_cno_ptr; + DAT_RETURN dat_status; + + evd_ptr = (DAPL_EVD *) evd_handle; + cno_ptr = (DAPL_CNO *) cno_handle; + dat_status = DAT_SUCCESS; + + if (DAPL_BAD_HANDLE(evd_handle, DAPL_MAGIC_EVD)) { + dat_status = DAT_ERROR(DAT_INVALID_HANDLE, 0); + goto bail; + } + if (cno_handle != NULL && DAPL_BAD_HANDLE(cno_handle, DAPL_MAGIC_CNO)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_CNO); + goto bail; + } + dapl_os_lock(&evd_ptr->header.lock); + old_cno_ptr = evd_ptr->cno_ptr; + evd_ptr->cno_ptr = cno_ptr; + dapl_os_unlock(&evd_ptr->header.lock); + if (cno_ptr) { + dapl_os_atomic_inc(&(cno_ptr->cno_ref_count)); + } + if (old_cno_ptr) { + dapl_os_atomic_dec(&(old_cno_ptr->cno_ref_count)); + } + + /* We need to enable the callback handler if the EVD is enabled. */ + if (evd_ptr->evd_enabled && + cno_handle != DAT_HANDLE_NULL && + evd_ptr->ib_cq_handle != IB_INVALID_HANDLE) { + dat_status = + dapls_ib_completion_notify(evd_ptr->header.owner_ia-> + hca_ptr->ib_hca_handle, evd_ptr, + IB_NOTIFY_ON_NEXT_COMP); + + /* FIXME report error */ + dapl_os_assert(dat_status == DAT_SUCCESS); + } + + bail: + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_evd_query.c b/branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_evd_query.c new file mode 100644 index 00000000..09abcad1 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_evd_query.c @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_evd_query.c + * + * PURPOSE: Event management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 3 + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" + +/* + * dapl_evd_query + * + * DAPL Requirements Version xxx, 6.3.2.3 + * + * Provides the consumer with arguments of the Event Dispatcher. + * + * Input: + * evd_handle + * evd_mask + * + * Output: + * evd_param + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + */ +DAT_RETURN DAT_API +dapl_evd_query(IN DAT_EVD_HANDLE evd_handle, + IN DAT_EVD_PARAM_MASK evd_param_mask, + OUT DAT_EVD_PARAM * evd_param) +{ + DAPL_EVD *evd_ptr; + DAT_RETURN dat_status; + + dat_status = DAT_SUCCESS; + + if (NULL == evd_param) { + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG3); + goto bail; + } + + /* Note: the spec. allows for events to be directed to a NULL EVD */ + /* with handle of type DAT_HANDLE_NULL. See 6.3.1 */ + if (DAT_HANDLE_NULL == evd_handle) { + dapl_os_memzero(evd_param, sizeof(DAT_EVD_PARAM)); + } else { + if (DAPL_BAD_HANDLE(evd_handle, DAPL_MAGIC_EVD)) { + dat_status = DAT_ERROR(DAT_INVALID_HANDLE, 0); + goto bail; + } + + evd_ptr = (DAPL_EVD *) evd_handle; + + /* + * We may be racing against the thread safe modify + * calls here (dat_evd_{enable,disable,{set,clear}_unwaitable}). + * They are thread safe, so our reads need to be atomic with + * regard to those calls. The below is ok (a single bit + * read counts as atomic; if it's in transition you'll get one + * of the correct values) but we'll need to be careful + * about reading the state variable atomically when we add + * in waitable/unwaitable. + */ + evd_param->evd_state = + (evd_ptr-> + evd_enabled ? DAT_EVD_STATE_ENABLED : + DAT_EVD_STATE_DISABLED); + evd_param->evd_state |= + (evd_ptr-> + evd_waitable ? DAT_EVD_STATE_WAITABLE : + DAT_EVD_STATE_UNWAITABLE); + evd_param->ia_handle = evd_ptr->header.owner_ia; + evd_param->evd_qlen = evd_ptr->qlen; + evd_param->cno_handle = (DAT_CNO_HANDLE) evd_ptr->cno_ptr; + evd_param->evd_flags = evd_ptr->evd_flags; + } + + bail: + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_evd_set_unwaitable.c b/branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_evd_set_unwaitable.c new file mode 100644 index 00000000..718e4336 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_evd_set_unwaitable.c @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_evd_set_unwaitable.c + * + * PURPOSE: EVENT management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 3.4.7 + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_adapter_util.h" + +/* + * dapl_evd_set_unwaitable + * + * DAPL Requirements Version 1.1, 6.3.4.7 + * + * Transition the Event Dispatcher into an unwaitable state + * + * Input: + * evd_handle + * + * Output: + * none + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_HANDLE + */ +DAT_RETURN DAT_API dapl_evd_set_unwaitable(IN DAT_EVD_HANDLE evd_handle) +{ + DAPL_EVD *evd_ptr; + DAT_RETURN dat_status; + + evd_ptr = (DAPL_EVD *) evd_handle; + dat_status = DAT_SUCCESS; + + if (DAPL_BAD_HANDLE(evd_handle, DAPL_MAGIC_EVD)) + { + dat_status = DAT_ERROR(DAT_INVALID_HANDLE, 0); + goto bail; + } + dapl_os_lock(&evd_ptr->header.lock); + evd_ptr->evd_waitable = DAT_FALSE; + dapl_os_unlock(&evd_ptr->header.lock); + + /* + * If this evd is waiting, wake it up. There is an obvious race + * condition here where we may wakeup the waiter before it goes to + * sleep; but the wait_object allows this and will do the right + * thing. + */ + if (evd_ptr->evd_state == DAPL_EVD_STATE_WAITED) { + if (evd_ptr->evd_flags & (DAT_EVD_DTO_FLAG | DAT_EVD_RMR_BIND_FLAG)) + dapls_evd_dto_wakeup(evd_ptr); + else + dapl_os_wait_object_wakeup(&evd_ptr->wait_object); + } + bail: + return dat_status; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_evd_wait.c b/branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_evd_wait.c new file mode 100644 index 00000000..79afb0de --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_evd_wait.c @@ -0,0 +1,271 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_evd_wait.c + * + * PURPOSE: EVENT management + * + * Description: Interfaces in this file are completely defined in + * the uDAPL 1.1 API specification + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include "dapl_evd_util.h" +#include "dapl_ring_buffer_util.h" +#include "dapl_adapter_util.h" + +/* + * dapl_evd_wait + * + * UDAPL Requirements Version xxx, + * + * Wait, up to specified timeout, for notification event on EVD. + * Then return first available event. + * + * Input: + * evd_handle + * timeout + * + * Output: + * event + * + * Returns: + * DAT_SUCCESS + * DAT_INVALID_PARAMETER + * DAT_INVALID_STATE + */ + +DAT_RETURN DAT_API dapl_evd_wait(IN DAT_EVD_HANDLE evd_handle, + IN DAT_TIMEOUT time_out, + IN DAT_COUNT threshold, + OUT DAT_EVENT * event, OUT DAT_COUNT * nmore) +{ + DAPL_EVD *evd_ptr; + DAT_RETURN dat_status; + DAT_EVENT *local_event; + DAT_BOOLEAN notify_requested = DAT_FALSE; + DAT_BOOLEAN waitable; + DAPL_EVD_STATE evd_state; + + dapl_dbg_log(DAPL_DBG_TYPE_API, + "dapl_evd_wait (%p, %d, %d, %p, %p)\n", + evd_handle, time_out, threshold, event, nmore); + + evd_ptr = (DAPL_EVD *) evd_handle; + dat_status = DAT_SUCCESS; + + if (DAPL_BAD_HANDLE(evd_ptr, DAPL_MAGIC_EVD)) { + /* + * We return directly rather than bailing because + * bailing attempts to update the evd, and we don't have + * one. + */ + dat_status = DAT_ERROR(DAT_INVALID_HANDLE, 0); + goto bail; + } + if (!event) { + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG4); + goto bail; + } + if (!nmore) { + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG5); + goto bail; + } + if (threshold <= 0 || + (threshold > 1 + && evd_ptr->completion_type != DAPL_EVD_STATE_THRESHOLD) + || threshold > evd_ptr->qlen) { + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG3); + goto bail; + } + if (evd_ptr->catastrophic_overflow) { + dat_status = DAT_ERROR(DAT_INVALID_STATE, 0); + goto bail; + } + DAPL_CNTR(evd_ptr, DCNT_EVD_WAIT); + + dapl_dbg_log(DAPL_DBG_TYPE_EVD, + "dapl_evd_wait: EVD %p, CQ %p\n", + evd_ptr, (void *)evd_ptr->ib_cq_handle); + + /* + * Make sure there are no other waiters and the evd is active. + * Currently this means only the OPEN state is allowed. + * Do this atomically. We need to take a lock to synchronize + * with dapl_evd_dequeue(), but the atomic transition allows + * non-locking synchronization with dapl_evd_query() and + * dapl_evd_{query,enable,disable,{set,clear}_unwaitable}. + */ + + dapl_os_lock(&evd_ptr->header.lock); + waitable = evd_ptr->evd_waitable; + + dapl_os_assert(sizeof(DAT_COUNT) == sizeof(DAPL_EVD_STATE)); + evd_state = evd_ptr->evd_state; + if (evd_ptr->evd_state == DAPL_EVD_STATE_OPEN) + evd_ptr->evd_state = DAPL_EVD_STATE_WAITED; + + if (evd_state != DAPL_EVD_STATE_OPEN) { + /* Bogus state, bail out */ + dat_status = DAT_ERROR(DAT_INVALID_STATE, 0); + goto bail; + } + + if (!waitable) { + /* This EVD is not waitable, reset the state and bail */ + if (evd_ptr->evd_state == DAPL_EVD_STATE_WAITED) + evd_ptr->evd_state = evd_state; + + dat_status = + DAT_ERROR(DAT_INVALID_STATE, + DAT_INVALID_STATE_EVD_UNWAITABLE); + goto bail; + } + + /* + * We now own the EVD, even though we don't have the lock anymore, + * because we're in the WAITED state. + */ + + evd_ptr->threshold = threshold; + + for (;;) { + /* + * Ideally we'd just check the number of entries on the CQ, but + * we don't have a way to do that. Because we have to set *nmore + * at some point in this routine, we'll need to do this copy + * sometime even if threshold == 1. + * + * For connection evd or async evd, the function checks and + * return right away if the ib_cq_handle associate with these evd + * equal to IB_INVALID_HANDLE + */ + dapl_os_unlock(&evd_ptr->header.lock); + dapls_evd_copy_cq(evd_ptr); + dapl_os_lock(&evd_ptr->header.lock); + + if (dapls_rbuf_count(&evd_ptr->pending_event_queue) >= + threshold) { + break; + } + + /* + * Do not enable the completion notification if this evd is not + * a DTO_EVD or RMR_BIND_EVD + */ + if ((!notify_requested) && + (evd_ptr->evd_flags & (DAT_EVD_DTO_FLAG | DAT_EVD_RMR_BIND_FLAG))) { + dat_status = + dapls_ib_completion_notify(evd_ptr->header. + owner_ia->hca_ptr-> + ib_hca_handle, evd_ptr, + (evd_ptr-> + completion_type == + DAPL_EVD_STATE_SOLICITED_WAIT) + ? IB_NOTIFY_ON_SOLIC_COMP + : + IB_NOTIFY_ON_NEXT_COMP); + + DAPL_CNTR(evd_ptr, DCNT_EVD_WAIT_NOTIFY); + /* FIXME report error */ + dapl_os_assert(dat_status == DAT_SUCCESS); + + notify_requested = DAT_TRUE; + + /* Try again. */ + continue; + } + + /* + * Unused by poster; it has no way to tell how many + * items are on the queue without copying them over to the + * EVD queue, and we're the only ones allowed to dequeue + * from the CQ for synchronization/locking reasons. + */ + evd_ptr->threshold = threshold; + + DAPL_CNTR(evd_ptr, DCNT_EVD_WAIT_BLOCKED); + dapl_os_unlock(&evd_ptr->header.lock); + + if ((!evd_ptr->cno_ptr) && + (evd_ptr->evd_flags & (DAT_EVD_DTO_FLAG | DAT_EVD_RMR_BIND_FLAG))) { + dat_status = dapls_evd_dto_wait(evd_ptr, time_out); + } else { + dat_status = dapl_os_wait_object_wait(&evd_ptr->wait_object, time_out); + } + + dapl_os_lock(&evd_ptr->header.lock); + + /* + * FIXME: if the thread loops around and waits again + * the time_out value needs to be updated. + */ + + notify_requested = DAT_FALSE; /* We've used it up. */ + + /* See if we were awakened by evd_set_unwaitable */ + if (!evd_ptr->evd_waitable) { + dat_status = DAT_ERROR(DAT_INVALID_STATE, 0); + } + + if (dat_status != DAT_SUCCESS) { + /* + * If the status is DAT_TIMEOUT, we'll break out of the + * loop, *not* dequeue an event (because dat_status + * != DAT_SUCCESS), set *nmore (as we should for timeout) + * and return DAT_TIMEOUT. + */ + break; + } + } + + evd_ptr->evd_state = DAPL_EVD_STATE_OPEN; + + if (dat_status == DAT_SUCCESS) { + local_event = dapls_rbuf_remove(&evd_ptr->pending_event_queue); + *event = *local_event; + dapls_rbuf_add(&evd_ptr->free_event_queue, local_event); + } + + /* + * Valid if dat_status == DAT_SUCCESS || dat_status == DAT_TIMEOUT + * Undefined otherwise, so ok to set it. + */ + *nmore = dapls_rbuf_count(&evd_ptr->pending_event_queue); + + bail: + dapl_os_unlock(&evd_ptr->header.lock); + if (dat_status) { + dapl_dbg_log(DAPL_DBG_TYPE_RTN, + "dapl_evd_wait () returns 0x%x\n", dat_status); + } + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_init.c b/branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_init.c new file mode 100644 index 00000000..605ab803 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_init.c @@ -0,0 +1,307 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_init.c + * + * PURPOSE: Interface Adapter management + * Description: Interfaces in this file are completely described in + * the DAPL 1.1 API, Chapter 6, section 2 + * + * $Id:$ + **********************************************************************/ + +#include "dapl.h" +#include /* Provider API function prototypes */ +#include "dapl_hca_util.h" +#include "dapl_init.h" +#include "dapl_provider.h" +#include "dapl_mr_util.h" +#include "dapl_osd.h" +#include "dapl_adapter_util.h" +#include "dapl_name_service.h" +#include "dapl_timer_util.h" +#include "dapl_vendor.h" + +/* + * dapl_init + * + * initialize this provider + * includes initialization of all global variables + * as well as registering all supported IAs with the dat registry + * + * This function needs to be called once when the provider is loaded. + * + * Input: + * none + * + * Output: + * none + * + * Return Values: + */ +void dapl_init(void) +{ + DAT_RETURN dat_status; + + /* set up debug type */ + g_dapl_dbg_type = dapl_os_get_env_val("DAPL_DBG_TYPE", + DAPL_DBG_TYPE_ERR | DAPL_DBG_TYPE_WARN); + /* set up debug destination */ + g_dapl_dbg_dest = dapl_os_get_env_val("DAPL_DBG_DEST", + DAPL_DBG_DEST_STDOUT); + + /* open log file on first logging call if necessary */ + if (g_dapl_dbg_dest & DAPL_DBG_DEST_SYSLOG) + openlog("libdapl", LOG_ODELAY | LOG_PID | LOG_CONS, LOG_USER); + + dapl_log(DAPL_DBG_TYPE_UTIL, "dapl_init: dbg_type=0x%x,dbg_dest=0x%x\n", + g_dapl_dbg_type, g_dapl_dbg_dest); + + /* See if the user is on a loopback setup */ + g_dapl_loopback_connection = dapl_os_get_env_bool("DAPL_LOOPBACK"); + + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, "DAPL: %s Setting Loopback\n", + g_dapl_loopback_connection ? "" : "NOT"); + + /* initialize verbs library */ + dapls_ib_init(); + + /* initialize the timer */ + dapls_timer_init(); + + /* Set up name services */ + dat_status = dapls_ns_init(); + if (DAT_SUCCESS != dat_status) { + dapl_dbg_log(DAPL_DBG_TYPE_ERR, + "dapls_ns_init failed %d\n", dat_status); + goto bail; + } + + /* initialize the provider list */ + dat_status = dapl_provider_list_create(); + + if (DAT_SUCCESS != dat_status) { + dapl_dbg_log(DAPL_DBG_TYPE_ERR, + "dapl_provider_list_create failed %d\n", + dat_status); + goto bail; + } + + return; + + bail: + dapl_dbg_log(DAPL_DBG_TYPE_ERR, "ERROR: dapl_init failed\n"); + return; +} + +/* + * dapl_fini + * + * finalize this provider + * includes freeing of all global variables + * as well as deregistering all supported IAs from the dat registry + * + * This function needs to be called once when the provider is loaded. + * + * Input: + * none + * + * Output: + * none + * + * Return Values: + */ +void dapl_fini(void) +{ + DAT_RETURN dat_status; + + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, "DAPL: ENTER (dapl_fini)\n"); + + dat_status = dapl_provider_list_destroy(); + if (DAT_SUCCESS != dat_status) { + dapl_dbg_log(DAPL_DBG_TYPE_ERR, + "dapl_provider_list_destroy failed %d\n", + dat_status); + } + + dapls_ib_release(); + dapls_timer_release(); + + dapl_dbg_log(DAPL_DBG_TYPE_UTIL, "DAPL: Exit (dapl_fini)\n"); + + if (g_dapl_dbg_dest & DAPL_DBG_DEST_SYSLOG) + closelog(); + + return; +} + +/* + * + * This function is called by the registry to initialize a provider + * + * The instance data string is expected to have the following form: + * + * + * + */ +void DAT_API +DAT_PROVIDER_INIT_FUNC_NAME(IN const DAT_PROVIDER_INFO * provider_info, + IN const char *instance_data) +{ + DAT_PROVIDER *provider; + DAPL_HCA *hca_ptr; + DAT_RETURN dat_status; + char *data; + char *name; + char *port; + unsigned int len; + unsigned int i; + + data = NULL; + provider = NULL; + hca_ptr = NULL; + +#if defined(_WIN32) || defined(_WIN64) + /* initialize DAPL library here as when called from DLL context in DLLmain() + * the IB (ibal) call hangs. + */ + dapl_init(); +#endif + + dat_status = + dapl_provider_list_insert(provider_info->ia_name, &provider); + if (DAT_SUCCESS != dat_status) { + dapl_dbg_log(DAPL_DBG_TYPE_ERR, + "dat_provider_list_insert failed: %x\n", + dat_status); + goto bail; + } + + data = dapl_os_strdup(instance_data); + if (NULL == data) { + goto bail; + } + + len = dapl_os_strlen(data); + + for (i = 0; i < len; i++) { + if (' ' == data[i]) { + data[i] = '\0'; + break; + } + } + + /* if the instance data did not have a valid format */ + if (i == len) { + goto bail; + } + + name = data; + port = data + (i + 1); + + hca_ptr = dapl_hca_alloc(name, port); + if (NULL == hca_ptr) { + dapl_dbg_log(DAPL_DBG_TYPE_ERR, + "%s() dapl_hca_alloc failed?\n"); + goto bail; + } + + provider->extension = hca_ptr; + dat_status = dat_registry_add_provider(provider, provider_info); + if (DAT_SUCCESS != dat_status) { + dapl_dbg_log(DAPL_DBG_TYPE_ERR, + "dat_registry_add_provider failed: %x\n", + dat_status); + } + + bail: + if (NULL != data) { + dapl_os_free(data, len + 1); + } + + if (DAT_SUCCESS != dat_status) { + if (NULL != provider) { + (void)dapl_provider_list_remove(provider_info->ia_name); + } + + if (NULL != hca_ptr) { + dapl_hca_free(hca_ptr); + } + } +} + +/* + * + * This function is called by the registry to de-initialize a provider + * + */ +void DAT_API +DAT_PROVIDER_FINI_FUNC_NAME(IN const DAT_PROVIDER_INFO * provider_info) +{ + DAT_PROVIDER *provider; + DAT_RETURN dat_status; + + dat_status = + dapl_provider_list_search(provider_info->ia_name, &provider); + if (DAT_SUCCESS != dat_status) { + dapl_dbg_log(DAPL_DBG_TYPE_ERR, + "dat_registry_add_provider failed: %x\n", + dat_status); + return; + } + + dat_status = dat_registry_remove_provider(provider, provider_info); + if (DAT_SUCCESS != dat_status) { + dapl_dbg_log(DAPL_DBG_TYPE_ERR, + "dat_registry_add_provider failed: %x\n", + dat_status); + } + + /* + * free HCA memory + */ + dapl_hca_free(provider->extension); + + (void)dapl_provider_list_remove(provider_info->ia_name); + +#if defined(_WIN32) || defined(_WIN64) + /* cleanup DAPL library - relocated here from OSD DLL context as the IBAL + * calls hung in the DLL context? + */ + dapl_fini(); +#endif +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_lmr_create.c b/branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_lmr_create.c new file mode 100644 index 00000000..f1d50164 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/udapl/dapl_lmr_create.c @@ -0,0 +1,419 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_lmr_create.c + * + * PURPOSE: Memory management + * + * $Id:$ + **********************************************************************/ + +#include "dapl_lmr_util.h" +#include "dapl_adapter_util.h" +#include "dapl_vendor.h" + +/********************************************************************* + * * + * Function Prototypes * + * * + *********************************************************************/ + +STATIC _INLINE_ DAT_RETURN +dapli_lmr_create_virtual(IN DAPL_IA * ia, + IN DAT_PVOID virt_addr, + IN DAT_VLEN length, + IN DAPL_PZ * pz, + IN DAT_MEM_PRIV_FLAGS privileges, + IN DAT_VA_TYPE va_type, + OUT DAT_LMR_HANDLE * lmr_handle, + OUT DAT_LMR_CONTEXT * lmr_context, + OUT DAT_RMR_CONTEXT * rmr_context, + OUT DAT_VLEN * registered_length, + OUT DAT_VADDR * registered_address); + +STATIC _INLINE_ DAT_RETURN +dapli_lmr_create_lmr(IN DAPL_IA * ia, + IN DAPL_LMR * original_lmr, + IN DAPL_PZ * pz, + IN DAT_MEM_PRIV_FLAGS privileges, + IN DAT_VA_TYPE va_type, + OUT DAT_LMR_HANDLE * lmr_handle, + OUT DAT_LMR_CONTEXT * lmr_context, + OUT DAT_RMR_CONTEXT * rmr_context, + OUT DAT_VLEN * registered_length, + OUT DAT_VADDR * registered_address); + +STATIC _INLINE_ DAT_RETURN +dapli_lmr_create_shared(IN DAPL_IA * ia, + IN DAT_REGION_DESCRIPTION reg_desc, + IN DAT_VLEN length, + IN DAPL_PZ * pz, + IN DAT_MEM_PRIV_FLAGS privileges, + IN DAT_VA_TYPE va_type, + OUT DAT_LMR_HANDLE * lmr_handle, + OUT DAT_LMR_CONTEXT * lmr_context, + OUT DAT_RMR_CONTEXT * rmr_context, + OUT DAT_VLEN * registered_length, + OUT DAT_VADDR * registered_address); + +/********************************************************************* + * * + * Function Definitions * + * * + *********************************************************************/ + +DAT_RETURN +dapli_lmr_create_virtual(IN DAPL_IA * ia, + IN DAT_PVOID virt_addr, + IN DAT_VLEN length, + IN DAPL_PZ * pz, + IN DAT_MEM_PRIV_FLAGS privileges, + IN DAT_VA_TYPE va_type, + OUT DAT_LMR_HANDLE * lmr_handle, + OUT DAT_LMR_CONTEXT * lmr_context, + OUT DAT_RMR_CONTEXT * rmr_context, + OUT DAT_VLEN * registered_length, + OUT DAT_VADDR * registered_address) +{ + DAPL_LMR *lmr; + DAT_REGION_DESCRIPTION reg_desc; + DAT_RETURN dat_status; + + reg_desc.for_va = virt_addr; + dat_status = DAT_SUCCESS; + + lmr = dapl_lmr_alloc(ia, + DAT_MEM_TYPE_VIRTUAL, + reg_desc, length, (DAT_PZ_HANDLE) pz, privileges); + + if (NULL == lmr) { + dat_status = + DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); + goto bail; + } + + dat_status = dapls_ib_mr_register(ia, + lmr, + virt_addr, + length, privileges, va_type); + + if (DAT_SUCCESS != dat_status) { + dapl_lmr_dealloc(lmr); + goto bail; + } + + dapl_os_atomic_inc(&pz->pz_ref_count); + *lmr_handle = (DAT_LMR_HANDLE) lmr; + + if (NULL != lmr_context) { + *lmr_context = lmr->param.lmr_context; + } + if (NULL != rmr_context) { + *rmr_context = lmr->param.rmr_context; + } + if (NULL != registered_length) { + *registered_length = lmr->param.registered_size; + } + if (NULL != registered_address) { + *registered_address = lmr->param.registered_address; + } + + bail: + return dat_status; +} + +DAT_RETURN +dapli_lmr_create_lmr(IN DAPL_IA * ia, + IN DAPL_LMR * original_lmr, + IN DAPL_PZ * pz, + IN DAT_MEM_PRIV_FLAGS privileges, + IN DAT_VA_TYPE va_type, + OUT DAT_LMR_HANDLE * lmr_handle, + OUT DAT_LMR_CONTEXT * lmr_context, + OUT DAT_RMR_CONTEXT * rmr_context, + OUT DAT_VLEN * registered_length, + OUT DAT_VADDR * registered_address) +{ + DAPL_LMR *lmr; + DAT_REGION_DESCRIPTION reg_desc; + DAT_RETURN dat_status; + + dapl_dbg_log(DAPL_DBG_TYPE_API, + "dapl_lmr_create_lmr (%p, %p, %p, %x, %x, %p, %p, %p, %p)\n", + ia, + original_lmr, + pz, privileges, va_type, + lmr_handle, + lmr_context, registered_length, registered_address); + + reg_desc.for_lmr_handle = (DAT_LMR_HANDLE) original_lmr; + + lmr = dapl_lmr_alloc(ia, + DAT_MEM_TYPE_LMR, + reg_desc, + original_lmr->param.length, + (DAT_PZ_HANDLE) pz, privileges); + + if (NULL == lmr) { + dat_status = + DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); + goto bail; + } + + dat_status = dapls_ib_mr_register_shared(ia, lmr, privileges, va_type); + + if (DAT_SUCCESS != dat_status) { + dapl_lmr_dealloc(lmr); + goto bail; + } + + dapl_os_atomic_inc(&pz->pz_ref_count); + *lmr_handle = (DAT_LMR_HANDLE) lmr; + + if (NULL != lmr_context) { + *lmr_context = lmr->param.lmr_context; + } + if (NULL != rmr_context) { + *rmr_context = lmr->param.rmr_context; + } + if (NULL != registered_length) { + *registered_length = lmr->param.registered_size; + } + if (NULL != registered_address) { + *registered_address = lmr->param.registered_address; + } + + bail: + return dat_status; +} + +DAT_RETURN +dapli_lmr_create_shared(IN DAPL_IA * ia, + IN DAT_REGION_DESCRIPTION reg_desc, + IN DAT_VLEN length, + IN DAPL_PZ * pz, + IN DAT_MEM_PRIV_FLAGS privileges, + IN DAT_VA_TYPE va_type, + OUT DAT_LMR_HANDLE * lmr_handle, + OUT DAT_LMR_CONTEXT * lmr_context, + OUT DAT_RMR_CONTEXT * rmr_context, + OUT DAT_VLEN * registered_length, + OUT DAT_VADDR * registered_address) +{ + DAPL_LMR *lmr; + DAT_RETURN dat_status; + + dat_status = DAT_SUCCESS; + + dapl_dbg_log(DAPL_DBG_TYPE_API, + "dapl_lmr_create_shared_virtual (ia=%p len=%x pz=%p priv=%x)\n", + ia, length, pz, privileges); + + lmr = dapl_lmr_alloc(ia, DAT_MEM_TYPE_LMR, reg_desc, length, /* length is meaningless */ + (DAT_PZ_HANDLE) pz, privileges); + + if (NULL == lmr) { + dat_status = + DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); + goto bail; + } + + /* + * Added for the shared memory support - - - + * Save the region description. We need to copy the shared + * memory id because the region_desc only contains a pointer + * to it. + */ + dapl_os_memcpy(&lmr->shmid, + reg_desc.for_shared_memory.shared_memory_id, + sizeof(lmr->shmid)); + lmr->param.region_desc = reg_desc; + lmr->param.length = length; + lmr->param.mem_type = DAT_MEM_TYPE_SHARED_VIRTUAL; + lmr->param.region_desc.for_shared_memory.shared_memory_id = &lmr->shmid; + + dat_status = dapls_ib_mr_register_shared(ia, lmr, privileges, va_type); + if (dat_status != DAT_SUCCESS) { + dapl_lmr_dealloc(lmr); + dat_status = + DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, + DAT_RESOURCE_MEMORY_REGION); + goto bail; + } + + dapl_os_atomic_inc(&pz->pz_ref_count); + *lmr_handle = (DAT_LMR_HANDLE) lmr; + + if (NULL != lmr_context) { + *lmr_context = (DAT_LMR_CONTEXT) lmr->param.lmr_context; + } + if (NULL != rmr_context) { + *rmr_context = (DAT_LMR_CONTEXT) lmr->param.rmr_context; + } + if (NULL != registered_length) { + *registered_length = lmr->param.length; + } + if (NULL != registered_address) { + *registered_address = (DAT_VADDR) (uintptr_t) + lmr->param.region_desc.for_shared_memory.virtual_address; + } + bail: + + return dat_status; +} + +/* + * dapl_lmr_create + * + * Register a memory region with an Interface Adaptor. + * + * Input: + * ia_handle + * mem_type + * region_description + * length + * pz_handle + * privileges + * + * Output: + * lmr_handle + * lmr_context + * registered_length + * registered_address + * + * Returns: + * DAT_SUCCESS + * DAT_INSUFFICIENT_RESOURCES + * DAT_INVALID_PARAMETER + * DAT_INVALID_HANDLE + * DAT_INVALID_STATE + * DAT_MODEL_NOT_SUPPORTED + * + */ +DAT_RETURN DAT_API +dapl_lmr_create(IN DAT_IA_HANDLE ia_handle, + IN DAT_MEM_TYPE mem_type, + IN DAT_REGION_DESCRIPTION region_description, + IN DAT_VLEN length, + IN DAT_PZ_HANDLE pz_handle, + IN DAT_MEM_PRIV_FLAGS privileges, + IN DAT_VA_TYPE va_type, + OUT DAT_LMR_HANDLE * lmr_handle, + OUT DAT_LMR_CONTEXT * lmr_context, + OUT DAT_RMR_CONTEXT * rmr_context, + OUT DAT_VLEN * registered_length, + OUT DAT_VADDR * registered_address) +{ + DAPL_IA *ia; + DAPL_PZ *pz; + DAT_RETURN dat_status; + + if (DAPL_BAD_HANDLE(ia_handle, DAPL_MAGIC_IA)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_IA); + goto bail; + } + if (DAPL_BAD_HANDLE(pz_handle, DAPL_MAGIC_PZ)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_PZ); + goto bail; + } + if (NULL == lmr_handle) { + dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG7); + goto bail; + } + + ia = (DAPL_IA *) ia_handle; + pz = (DAPL_PZ *) pz_handle; + + DAPL_CNTR(ia, DCNT_IA_LMR_CREATE); + + switch (mem_type) { + case DAT_MEM_TYPE_VIRTUAL: + { + dat_status = + dapli_lmr_create_virtual(ia, + region_description.for_va, + length, pz, privileges, + va_type, lmr_handle, + lmr_context, rmr_context, + registered_length, + registered_address); + break; + } + case DAT_MEM_TYPE_LMR: + { + DAPL_LMR *lmr; + + if (DAPL_BAD_HANDLE + (region_description.for_lmr_handle, + DAPL_MAGIC_LMR)) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, + DAT_INVALID_HANDLE_LMR); + goto bail; + } + + lmr = (DAPL_LMR *) region_description.for_lmr_handle; + + dat_status = + dapli_lmr_create_lmr(ia, lmr, pz, privileges, + va_type, lmr_handle, + lmr_context, rmr_context, + registered_length, + registered_address); + break; + } + case DAT_MEM_TYPE_SHARED_VIRTUAL: + { +#if (VN_MEM_SHARED_VIRTUAL_SUPPORT > 0) + dat_status = + dapli_lmr_create_shared(ia, region_description, + length, pz, privileges, + va_type, lmr_handle, + lmr_context, rmr_context, + registered_length, + registered_address); +#else + dat_status = + DAT_ERROR(DAT_NOT_IMPLEMENTED, DAT_NO_SUBTYPE); +#endif + break; + } + default: + { + dat_status = + DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG2); + break; + } + } + + bail: + return dat_status; +} diff --git a/branches/WOF2-3/ulp/dapl2/dapl/udapl/linux/dapl_osd.c b/branches/WOF2-3/ulp/dapl2/dapl/udapl/linux/dapl_osd.c new file mode 100644 index 00000000..78d7735e --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/udapl/linux/dapl_osd.c @@ -0,0 +1,599 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_osd.c + * + * PURPOSE: Operating System Dependent layer + * Description: + * Provide OS dependent functions with a canonical DAPL + * interface. Designed to be portable and hide OS specific quirks + * of common functions. + * + * + * $Id:$ + **********************************************************************/ + +#include "dapl_osd.h" +#include "dapl.h" +#include "dapl_hca_util.h" +#include "dapl_ia_util.h" +#include "dapl_rmr_util.h" +#include "dapl_lmr_util.h" +#include "dapl_pz_util.h" +#include "dapl_ep_util.h" +#include "dapl_cr_util.h" +#include "dapl_evd_util.h" +#include "dapl_sp_util.h" +#include "dapl_adapter_util.h" +#include "dapl_provider.h" +#include "dapl_hash.h" +#include "dapl_timer_util.h" +#include "dapl_debug.h" + +#include +#include /* needed for getenv() */ +#include /* needed for pthread_atfork() */ +#include /* needed for thread setup */ + +static void dapls_osd_fork_cleanup(void); + +/* + * dapl_osd_init + * + * Do Linux initialization: + * - Set up fork handler to clean up DAPL resources in the child + * process after a fork(). + * + * Input: + * none + * + * Returns: + * DAT_SUCCESS + */ +void dapl_os_init() +{ + int status; + + /* + * Set up fork control + */ + status = pthread_atfork(NULL, NULL, dapls_osd_fork_cleanup); + if (status != 0) { + dapl_os_printf("WARNING: pthread_atfork %d\n", status); + } +} + +/* + * dapl_os_get_time + * + * Return 64 bit value of current time in microseconds. + * + * Input: + * loc User location to place current time + * + * Returns: + * DAT_SUCCESS + */ + +DAT_RETURN dapl_os_get_time(OUT DAPL_OS_TIMEVAL * loc) +{ + struct timeval tv; + struct timezone tz; + + gettimeofday(&tv, &tz); + *loc = ((DAT_UINT64) (tv.tv_sec) * 1000000L) + (DAT_UINT64) tv.tv_usec; + + return DAT_SUCCESS; +} + +/* + * dapl_os_get__env_bool + * + * Return boolean value of passed in environment variable: 1 if present, + * 0 if not + * + * Input: + * + * + * Returns: + * TRUE or FALSE + */ +int dapl_os_get_env_bool(char *env_str) +{ + char *env_var; + + env_var = getenv(env_str); + if (env_var != NULL) { + return 1; + } + + return 0; +} + +/* + * dapl_os_get_env_val + * + * Update val to value of passed in environment variable if present + * + * Input: + * env_str + * def_val default value if environment variable does not exist + * + * Returns: + * TRUE or FALSE + */ +int dapl_os_get_env_val(char *env_str, int def_val) +{ + char *env_var; + + env_var = getenv(env_str); + if (env_var != NULL) { + def_val = strtol(env_var, NULL, 0); + } + + return def_val; +} + +/* + * Wait object routines + */ + +/* + * dapl_os_wait_object_init + * + * Initialize a wait object + * + * Input: + * wait_obj + * + * Returns: + * DAT_SUCCESS + * DAT_INTERNAL_ERROR + */ +DAT_RETURN dapl_os_wait_object_init(IN DAPL_OS_WAIT_OBJECT * wait_obj) +{ + wait_obj->signaled = DAT_FALSE; + if (0 != pthread_cond_init(&wait_obj->cv, NULL)) { + return DAT_ERROR(DAT_INTERNAL_ERROR, 0); + } + + /* Always returns 0. */ + pthread_mutex_init(&wait_obj->lock, NULL); + + return DAT_SUCCESS; +} + +/* Wait on the supplied wait object, up to the specified time_out. + * A timeout of DAT_TIMEOUT_INFINITE will wait indefinitely. + * Timeout should be specified in micro seconds. + * + * Functional returns: + * DAT_SUCCESS -- another thread invoked dapl_os_wait object_wakeup + * DAT_INVALID_STATE -- someone else is already waiting in this wait + * object. + * only one waiter is allowed at a time. + * DAT_ABORT -- another thread invoked dapl_os_wait_object_destroy + * DAT_TIMEOUT -- the specified time limit was reached. + */ + +DAT_RETURN +dapl_os_wait_object_wait(IN DAPL_OS_WAIT_OBJECT * wait_obj, + IN DAT_TIMEOUT timeout_val) +{ + DAT_RETURN dat_status; + int pthread_status; + struct timespec future; + + dat_status = DAT_SUCCESS; + pthread_status = 0; + + if (timeout_val != DAT_TIMEOUT_INFINITE) { + struct timeval now; + struct timezone tz; + unsigned int microsecs; + + gettimeofday(&now, &tz); +#define USEC_PER_SEC 1000000 + microsecs = now.tv_usec + timeout_val; + now.tv_sec = now.tv_sec + microsecs / USEC_PER_SEC; + now.tv_usec = microsecs % USEC_PER_SEC; + + /* Convert timeval to timespec */ + future.tv_sec = now.tv_sec; + future.tv_nsec = now.tv_usec * 1000; + + pthread_mutex_lock(&wait_obj->lock); + while (wait_obj->signaled == DAT_FALSE && pthread_status == 0) { + pthread_status = + pthread_cond_timedwait(&wait_obj->cv, + &wait_obj->lock, &future); + + /* + * No need to reset &future if we go around the loop; + * It's an absolute time. + */ + } + /* Reset the signaled status if we were woken up. */ + if (pthread_status == 0) { + wait_obj->signaled = DAT_FALSE; + } + pthread_mutex_unlock(&wait_obj->lock); + } else { + pthread_mutex_lock(&wait_obj->lock); + while (wait_obj->signaled == DAT_FALSE && pthread_status == 0) { + pthread_status = + pthread_cond_wait(&wait_obj->cv, &wait_obj->lock); + } + /* Reset the signaled status if we were woken up. */ + if (pthread_status == 0) { + wait_obj->signaled = DAT_FALSE; + } + pthread_mutex_unlock(&wait_obj->lock); + } + + if (ETIMEDOUT == pthread_status) { + dat_status = DAT_ERROR(DAT_TIMEOUT_EXPIRED, 0); + } else if (EINTR == pthread_status) { + dat_status = DAT_ERROR(DAT_INTERRUPTED_CALL, 0); + } else if (0 != pthread_status) { + dat_status = DAT_ERROR(DAT_INTERNAL_ERROR, 0); + } + + return dat_status; +} + +/* + * dapl_os_wait_object_wakeup + * + * Wakeup a thread waiting on a wait object + * + * Input: + * wait_obj + * + * Returns: + * DAT_SUCCESS + * DAT_INTERNAL_ERROR + */ +DAT_RETURN dapl_os_wait_object_wakeup(IN DAPL_OS_WAIT_OBJECT * wait_obj) +{ + pthread_mutex_lock(&wait_obj->lock); + wait_obj->signaled = DAT_TRUE; + pthread_mutex_unlock(&wait_obj->lock); + if (0 != pthread_cond_signal(&wait_obj->cv)) { + return DAT_ERROR(DAT_INTERNAL_ERROR, 0); + } + + return DAT_SUCCESS; +} + +/* + * dapl_os_wait_object_destroy + * + * Destroy a wait object + * + * Input: + * wait_obj + * + * Returns: + * DAT_SUCCESS + * DAT_INTERNAL_ERROR + */ +DAT_RETURN dapl_os_wait_object_destroy(IN DAPL_OS_WAIT_OBJECT * wait_obj) +{ + if (0 != pthread_cond_destroy(&wait_obj->cv)) { + return DAT_ERROR(DAT_INTERNAL_ERROR, 0); + } + if (0 != pthread_mutex_destroy(&wait_obj->lock)) { + return DAT_ERROR(DAT_INTERNAL_ERROR, 0); + } + + return DAT_SUCCESS; +} + +/* + * dapls_osd_fork_cleanup + * + * Update val to value of passed in environment variable if present + * + * Input: + * env_str + * val Updated if environment variable exists + * + * Returns: + * TRUE or FALSE + */ +void dapls_osd_fork_cleanup(void) +{ + DAPL_PROVIDER_LIST_NODE *cur_node; + DAPL_HCA *hca_ptr; + DAPL_IA *ia_ptr; + DAPL_LMR *lmr_ptr; + DAPL_RMR *rmr_ptr; + DAPL_PZ *pz_ptr; + DAPL_CR *cr_ptr; + DAPL_EP *ep_ptr; + DAPL_EVD *evd_ptr; + DAT_EP_PARAM *param; + DAPL_SP *sp_ptr; + + while (NULL != g_dapl_provider_list.head) { + cur_node = g_dapl_provider_list.head; + g_dapl_provider_list.head = cur_node->next; + + hca_ptr = (DAPL_HCA *) cur_node->data.extension; + + /* + * Walk the list of IA ptrs & clean up. This is purposely + * a destructive list walk, we really don't want to preserve + * any of it. + */ + while (!dapl_llist_is_empty(&hca_ptr->ia_list_head)) { + ia_ptr = (DAPL_IA *) + dapl_llist_peek_head(&hca_ptr->ia_list_head); + + /* + * The rest of the cleanup code is similar to dapl_ia_close, + * the big difference is that we don't release IB resources, + * only memory; the underlying IB subsystem doesn't deal + * with fork at all, so leave IB handles alone. + */ + while (!dapl_llist_is_empty(&ia_ptr->rmr_list_head)) { + rmr_ptr = (DAPL_RMR *) + dapl_llist_peek_head(&ia_ptr-> + rmr_list_head); + if (rmr_ptr->param.lmr_triplet. + virtual_address != 0) { + dapl_os_atomic_dec(&rmr_ptr->lmr-> + lmr_ref_count); + rmr_ptr->param.lmr_triplet. + virtual_address = 0; + } + dapl_os_atomic_dec(&rmr_ptr->pz->pz_ref_count); + dapl_ia_unlink_rmr(rmr_ptr->header.owner_ia, + rmr_ptr); + dapl_rmr_dealloc(rmr_ptr); + } + + while (!dapl_llist_is_empty(&ia_ptr->rsp_list_head)) { + sp_ptr = (DAPL_SP *) + dapl_llist_peek_head(&ia_ptr-> + rsp_list_head); + dapl_os_atomic_dec(& + ((DAPL_EVD *) sp_ptr-> + evd_handle)->evd_ref_count); + dapls_ia_unlink_sp(ia_ptr, sp_ptr); + dapls_sp_free_sp(sp_ptr); + } + + while (!dapl_llist_is_empty(&ia_ptr->ep_list_head)) { + ep_ptr = (DAPL_EP *) + dapl_llist_peek_head(&ia_ptr->ep_list_head); + param = &ep_ptr->param; + if (param->pz_handle != NULL) { + dapl_os_atomic_dec(& + ((DAPL_PZ *) param-> + pz_handle)-> + pz_ref_count); + } + if (param->recv_evd_handle != NULL) { + dapl_os_atomic_dec(& + ((DAPL_EVD *) param-> + recv_evd_handle)-> + evd_ref_count); + } + if (param->request_evd_handle) { + dapl_os_atomic_dec(& + ((DAPL_EVD *) param-> + request_evd_handle)-> + evd_ref_count); + } + if (param->connect_evd_handle != NULL) { + dapl_os_atomic_dec(& + ((DAPL_EVD *) param-> + connect_evd_handle)-> + evd_ref_count); + } + + /* ...and free the resource */ + dapl_ia_unlink_ep(ia_ptr, ep_ptr); + dapl_ep_dealloc(ep_ptr); + } + + while (!dapl_llist_is_empty(&ia_ptr->lmr_list_head)) { + lmr_ptr = (DAPL_LMR *) + dapl_llist_peek_head(&ia_ptr-> + lmr_list_head); + + (void)dapls_hash_remove(lmr_ptr->header. + owner_ia->hca_ptr-> + lmr_hash_table, + lmr_ptr->param. + lmr_context, NULL); + + pz_ptr = (DAPL_PZ *) lmr_ptr->param.pz_handle; + dapl_os_atomic_dec(&pz_ptr->pz_ref_count); + dapl_ia_unlink_lmr(lmr_ptr->header.owner_ia, + lmr_ptr); + dapl_lmr_dealloc(lmr_ptr); + } + + while (!dapl_llist_is_empty(&ia_ptr->psp_list_head)) { + sp_ptr = (DAPL_SP *) + dapl_llist_peek_head(&ia_ptr-> + psp_list_head); + while (!dapl_llist_is_empty + (&sp_ptr->cr_list_head)) { + cr_ptr = (DAPL_CR *) + dapl_llist_peek_head(&sp_ptr-> + cr_list_head); + dapl_sp_remove_cr(sp_ptr, cr_ptr); + dapls_cr_free(cr_ptr); + } + + dapls_ia_unlink_sp(ia_ptr, sp_ptr); + dapl_os_atomic_dec(& + ((DAPL_EVD *) sp_ptr-> + evd_handle)->evd_ref_count); + dapls_sp_free_sp(sp_ptr); + } + + while (!dapl_llist_is_empty(&ia_ptr->pz_list_head)) { + pz_ptr = (DAPL_PZ *) + dapl_llist_peek_head(&ia_ptr->pz_list_head); + dapl_ia_unlink_pz(pz_ptr->header.owner_ia, + pz_ptr); + dapl_pz_dealloc(pz_ptr); + } + + while (!dapl_llist_is_empty(&ia_ptr->evd_list_head)) { + evd_ptr = (DAPL_EVD *) + dapl_llist_peek_head(&ia_ptr-> + evd_list_head); + dapl_ia_unlink_evd(evd_ptr->header.owner_ia, + evd_ptr); + /* reset the cq_handle to avoid having it removed */ + evd_ptr->ib_cq_handle = IB_INVALID_HANDLE; + dapls_evd_dealloc(evd_ptr); + } + + dapl_hca_unlink_ia(ia_ptr->hca_ptr, ia_ptr); + /* asycn error evd was taken care of above, reset the pointer */ + ia_ptr->async_error_evd = NULL; + dapls_ia_free(ia_ptr); + } /* end while ( ia_ptr != NULL ) */ + + dapl_os_free(cur_node, sizeof(DAPL_PROVIDER_LIST_NODE)); + } /* end while (NULL != g_dapl_provider_list.head) */ +} + +/* + * Structure to contain all elements of a thread in order to enable a + * local routine to intercept and do some necessary initialization. + */ +struct thread_draft { + void (*func) (void *); /* start routine */ + void *data; /* argument to start routine */ +}; + +void dapli_thread_init(struct thread_draft *thread_draft); + +/* + * dapls_os_thread_create + * + * Create a thread for dapl + * + * Input: + * func function to invoke thread + * f_arg argument to pass to function + * + * Output + * thread_id handle for thread + * + * Returns: + * DAT_SUCCESS + */ +DAT_RETURN +dapl_os_thread_create(IN void (*func) (void *), + IN void *data, OUT DAPL_OS_THREAD * thread_id) +{ + pthread_attr_t thread_attr; + struct thread_draft *thread_draft; + int status; + + /* + * Get default set of thread attributes + */ + status = pthread_attr_init(&thread_attr); + if (status != 0) { + return DAT_ERROR(DAT_INTERNAL_ERROR, 0); + } + + /* Create dapl threads as detached from this process */ + status = pthread_attr_setdetachstate(&thread_attr, + PTHREAD_CREATE_DETACHED); + if (status != 0) { + return DAT_ERROR(DAT_INTERNAL_ERROR, 0); + } + + thread_draft = dapl_os_alloc(sizeof(struct thread_draft)); + + thread_draft->func = func; + thread_draft->data = data; + + /* Create the thread. Observe that we first invoke a local + * routine to set up OS parameters, before invoking the user + * specified routine. + */ + status = pthread_create(thread_id, + &thread_attr, + (void *(*)(void *))dapli_thread_init, + (void *)thread_draft); + + /* clean up resources */ + (void)pthread_attr_destroy(&thread_attr); + + if (status != 0) { + return DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, 0); + } + + return DAT_SUCCESS; +} + +/* + * dapli_thread_init + * + * Need to mask all signals from this thread in order to be a good + * citizen. Signals will arrive randomly and will be processed by + * whatever thread is running unless they are specifically blocked; and + * this should be a user thread, not a dapl thread + */ + +void dapli_thread_init(struct thread_draft *thread_draft) +{ + sigset_t sigset; + void (*func) (void *); + void *data; + + sigfillset(&sigset); + pthread_sigmask(SIG_BLOCK, &sigset, NULL); + + func = thread_draft->func; + data = thread_draft->data; + dapl_os_free(thread_draft, sizeof(struct thread_draft)); + + (*func) (data); +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/udapl/linux/dapl_osd.h b/branches/WOF2-3/ulp/dapl2/dapl/udapl/linux/dapl_osd.h new file mode 100644 index 00000000..cb61cae6 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/udapl/linux/dapl_osd.h @@ -0,0 +1,586 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dapl_osd.h + * + * PURPOSE: Operating System Dependent layer + * Description: + * Provide OS dependent data structures & functions with + * a canonical DAPL interface. Designed to be portable + * and hide OS specific quirks of common functions. + * + * $Id:$ + **********************************************************************/ + +#ifndef _DAPL_OSD_H_ +#define _DAPL_OSD_H_ + +/* + * This file is defined for Linux systems only, including it on any + * other build will cause an error + */ +#ifndef __linux__ +#error UNDEFINED OS TYPE +#endif /* __linux__ */ + +#if !defined (__i386__) && !defined (__ia64__) && !defined(__x86_64__) && !defined(__PPC__) && !defined(__PPC64__) +#error UNDEFINED ARCH +#endif + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for printf */ +#include +#include +#include /* for getaddrinfo */ +#include + +#include /* for IOCTL's */ + +#include "dapl_debug.h" + +/* + * Include files for setting up a network name + */ +#include /* for socket(2) */ +#include /* for struct ifreq */ +#include /* for ARPHRD_ETHER */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#if !defined(SUSE_11) && !defined(REDHAT_EL5) && defined(__ia64__) +#include +#endif + +#if defined(SUSE_11) && defined(__ia64__) +#include +#include +#endif + +/* Useful debug definitions */ +#ifndef STATIC +#define STATIC static +#endif /* STATIC */ +#ifndef _INLINE_ +#define _INLINE_ __inline__ +#endif /* _INLINE_ */ + +#define LINUX_VERSION(a,b) (((a) << 16) + (b)) + +void dapl_os_init ( void ); /* initialization function */ + +#define dapl_os_panic(...) \ + do { \ + fprintf(stderr, "PANIC in %s:%i:%s\n", __FILE__, __LINE__, __func__); \ + fprintf(stderr, __VA_ARGS__); \ + exit(1); \ + } while(0) + +#define dapl_ip_addr6(sockaddr) (((struct sockaddr_in6 *)sockaddr)->sin6_addr.s6_addr32) + +/* + * Atomic operations + */ + +typedef volatile DAT_COUNT DAPL_ATOMIC; + +/* atomic function prototypes */ +STATIC _INLINE_ void /* DAT_COUNT */ +dapl_os_atomic_inc ( + INOUT DAPL_ATOMIC *v); + +STATIC _INLINE_ void /* DAT_COUNT */ +dapl_os_atomic_dec ( + INOUT DAPL_ATOMIC *v); + +STATIC _INLINE_ DAT_COUNT +dapl_os_atomic_assign ( + INOUT DAPL_ATOMIC *v, + IN DAT_COUNT match_value, + IN DAT_COUNT new_value ); + +#define dapl_os_atomic_read(v) (*v) +#define dapl_os_atomic_set(v,i) (*v = i) + +int dapl_os_get_env_bool ( + char *env_str ); + +int dapl_os_get_env_val ( + char *env_str, + int def_val ); + + + +/* atomic functions */ + +/* dapl_os_atomic_inc + * + * get the current value of '*v', and then increment it. + * + * This is equivalent to an IB atomic fetch and add of 1, + * except that a DAT_COUNT might be 32 bits, rather than 64 + * and it occurs in local memory. + */ + +STATIC _INLINE_ void +dapl_os_atomic_inc ( + INOUT DAPL_ATOMIC *v) +{ +#ifdef __ia64__ + DAT_COUNT old_value; +#if defined(REDHAT_EL5) + old_value = __sync_fetch_and_add(v, 1); +#elif !defined(REDHAT_EL4) && (OS_RELEASE >= LINUX_VERSION(2,6)) + IA64_FETCHADD(old_value,v,1,4,rel); +#else + IA64_FETCHADD(old_value,v,1,4); +#endif +#elif defined(__PPC__) || defined(__PPC64__) + int tmp; + + __asm__ __volatile__( + "1: lwarx %0,0,%2\n\ + addic %0,%0,1\n\ + stwcx. %0,0,%2\n\ + bne- 1b" + : "=&r" (tmp), "+m" (v) + : "r" (&v) + : "cc"); +#else /* !__ia64__ */ + __asm__ __volatile__ ( + "lock;" "incl %0" + :"=m" (*v) + :"m" (*v)); +#endif + return; +} + + +/* dapl_os_atomic_dec + * + * decrement the current value of '*v'. No return value is required. + */ + +STATIC _INLINE_ void +dapl_os_atomic_dec ( + INOUT DAPL_ATOMIC *v) +{ +#ifdef __ia64__ + DAT_COUNT old_value; +#if defined(REDHAT_EL5) + old_value = __sync_fetch_and_sub(v, 1); +#elif !defined(REDHAT_EL4) && (OS_RELEASE >= LINUX_VERSION(2,6)) + IA64_FETCHADD(old_value,v,-1,4,rel); +#else + IA64_FETCHADD(old_value,v,-1,4); +#endif +#elif defined (__PPC__) || defined(__PPC64__) + int tmp; + + __asm__ __volatile__( + "1: lwarx %0,0,%2\n\ + addic %0,%0,-1\n\ + stwcx. %0,0,%2\n\ + bne- 1b" + : "=&r" (tmp), "+m" (v) + : "r" (&v) + : "cc"); +#else /* !__ia64__ */ + __asm__ __volatile__ ( + "lock;" "decl %0" + :"=m" (*v) + :"m" (*v)); +#endif + return; +} + + +/* dapl_os_atomic_assign + * + * assign 'new_value' to '*v' if the current value + * matches the provided 'match_value'. + * + * Make no assignment if there is no match. + * + * Return the current value in any case. + * + * This matches the IBTA atomic operation compare & swap + * except that it is for local memory and a DAT_COUNT may + * be only 32 bits, rather than 64. + */ + +STATIC _INLINE_ DAT_COUNT +dapl_os_atomic_assign ( + INOUT DAPL_ATOMIC *v, + IN DAT_COUNT match_value, + IN DAT_COUNT new_value ) +{ + DAT_COUNT current_value; + + /* + * Use the Pentium compare and exchange instruction + */ + +#ifdef __ia64__ +#if defined(REDHAT_EL5) + current_value = __sync_val_compare_and_swap(v,match_value,new_value); +#elif defined(REDHAT_EL4) + current_value = ia64_cmpxchg("acq",v,match_value,new_value,4); +#else + current_value = ia64_cmpxchg(acq,v,match_value,new_value,4); +#endif /* __ia64__ */ +#elif defined(__PPC__) || defined(__PPC64__) + __asm__ __volatile__ ( +" lwsync\n\ +1: lwarx %0,0,%2 # __cmpxchg_u32\n\ + cmpw 0,%0,%3\n\ + bne- 2f\n\ + stwcx. %4,0,%2\n\ + bne- 1b\n\ + isync\n\ +2:" + : "=&r" (current_value), "=m" (*v) + : "r" (v), "r" (match_value), "r" (new_value), "m" (*v) + : "cc", "memory"); +#else + __asm__ __volatile__ ( + "lock; cmpxchgl %1, %2" + : "=a" (current_value) + : "q" (new_value), "m" (*v), "0" (match_value) + : "memory"); +#endif + return current_value; +} + +/* + * Thread Functions + */ +typedef pthread_t DAPL_OS_THREAD; + +DAT_RETURN +dapl_os_thread_create ( + IN void (*func) (void *), + IN void *data, + OUT DAPL_OS_THREAD *thread_id ); + +STATIC _INLINE_ void +dapl_os_sleep_usec(int usec) +{ + struct timespec sleep, remain; + + sleep.tv_sec = 0; + sleep.tv_nsec = usec * 1000; + nanosleep(&sleep, &remain); +} + +/* + * Lock Functions + */ + +typedef pthread_mutex_t DAPL_OS_LOCK; + +/* function prototypes */ +STATIC _INLINE_ DAT_RETURN +dapl_os_lock_init ( + IN DAPL_OS_LOCK *m); + +STATIC _INLINE_ DAT_RETURN +dapl_os_lock ( + IN DAPL_OS_LOCK *m); + +STATIC _INLINE_ DAT_RETURN +dapl_os_unlock ( + IN DAPL_OS_LOCK *m); + +STATIC _INLINE_ DAT_RETURN +dapl_os_lock_destroy ( + IN DAPL_OS_LOCK *m); + +/* lock functions */ +STATIC _INLINE_ DAT_RETURN +dapl_os_lock_init ( + IN DAPL_OS_LOCK *m) +{ + /* pthread_mutex_init always returns 0 */ + pthread_mutex_init (m, NULL); + + return DAT_SUCCESS; +} + +STATIC _INLINE_ DAT_RETURN +dapl_os_lock ( + IN DAPL_OS_LOCK *m) +{ + if (0 == pthread_mutex_lock (m)) + { + return DAT_SUCCESS; + } + else + { + return DAT_CLASS_ERROR | DAT_INTERNAL_ERROR; + } +} + +STATIC _INLINE_ DAT_RETURN +dapl_os_unlock ( + IN DAPL_OS_LOCK *m) +{ + if (0 == pthread_mutex_unlock (m)) + { + return DAT_SUCCESS; + } + else + { + return DAT_CLASS_ERROR | DAT_INTERNAL_ERROR; + } +} + +STATIC _INLINE_ DAT_RETURN +dapl_os_lock_destroy ( + IN DAPL_OS_LOCK *m) +{ + if (0 == pthread_mutex_destroy (m)) + { + return DAT_SUCCESS; + } + else + { + return DAT_CLASS_ERROR | DAT_INTERNAL_ERROR; + } +} + + +/* + * Wait Objects + */ + +/* + * The wait object invariant: Presuming a call to dapl_os_wait_object_wait + * occurs at some point, there will be at least one wakeup after each call + * to dapl_os_wait_object_signal. I.e. Signals are not ignored, though + * they may be coallesced. + */ + +typedef struct +{ + DAT_BOOLEAN signaled; + pthread_cond_t cv; + pthread_mutex_t lock; +} DAPL_OS_WAIT_OBJECT; + +/* function prototypes */ +DAT_RETURN +dapl_os_wait_object_init ( + IN DAPL_OS_WAIT_OBJECT *wait_obj); + +DAT_RETURN +dapl_os_wait_object_wait ( + IN DAPL_OS_WAIT_OBJECT *wait_obj, + IN DAT_TIMEOUT timeout_val); + +DAT_RETURN +dapl_os_wait_object_wakeup ( + IN DAPL_OS_WAIT_OBJECT *wait_obj); + +DAT_RETURN +dapl_os_wait_object_destroy ( + IN DAPL_OS_WAIT_OBJECT *wait_obj); + +/* + * Memory Functions + */ + +/* function prototypes */ +STATIC _INLINE_ void *dapl_os_alloc (int size); + +STATIC _INLINE_ void *dapl_os_realloc (void *ptr, int size); + +STATIC _INLINE_ void dapl_os_free (void *ptr, int size); + +STATIC _INLINE_ void * dapl_os_memzero (void *loc, int size); + +STATIC _INLINE_ void * dapl_os_memcpy (void *dest, const void *src, int len); + +STATIC _INLINE_ int dapl_os_memcmp (const void *mem1, const void *mem2, int len); + +/* memory functions */ + + +STATIC _INLINE_ void *dapl_os_alloc (int size) +{ + return malloc (size); +} + +STATIC _INLINE_ void *dapl_os_realloc (void *ptr, int size) +{ + return realloc(ptr, size); +} + +STATIC _INLINE_ void dapl_os_free (void *ptr, int size) +{ + free (ptr); +} + +STATIC _INLINE_ void * dapl_os_memzero (void *loc, int size) +{ + return memset (loc, 0, size); +} + +STATIC _INLINE_ void * dapl_os_memcpy (void *dest, const void *src, int len) +{ + return memcpy (dest, src, len); +} + +STATIC _INLINE_ int dapl_os_memcmp (const void *mem1, const void *mem2, int len) +{ + return memcmp (mem1, mem2, len); +} + +/* + * Memory coherency functions + * For i386 Linux, there are no coherency issues so we just return success. + */ +STATIC _INLINE_ DAT_RETURN +dapl_os_sync_rdma_read ( + IN const DAT_LMR_TRIPLET *local_segments, + IN DAT_VLEN num_segments) +{ + return DAT_SUCCESS; +} + +STATIC _INLINE_ DAT_RETURN +dapl_os_sync_rdma_write ( + IN const DAT_LMR_TRIPLET *local_segments, + IN DAT_VLEN num_segments) +{ + return DAT_SUCCESS; +} + + +/* + * String Functions + */ + +STATIC _INLINE_ unsigned int dapl_os_strlen(const char *str) +{ + return strlen(str); +} + +STATIC _INLINE_ char * dapl_os_strdup(const char *str) +{ + return strdup(str); +} + + +/* + * Timer Functions + */ + +typedef DAT_UINT64 DAPL_OS_TIMEVAL; +typedef struct dapl_timer_entry DAPL_OS_TIMER; +typedef unsigned long long int DAPL_OS_TICKS; + +/* function prototypes */ +DAT_RETURN dapl_os_get_time (DAPL_OS_TIMEVAL *); + + +/* + * + * Name Service Helper functions + * + */ +#if defined(IBHOSTS_NAMING) || defined(CM_BUSTED) +#define dapls_osd_getaddrinfo(name, addr_ptr) getaddrinfo(name,NULL,NULL,addr_ptr) +#define dapls_osd_freeaddrinfo(addr) freeaddrinfo (addr) + +#endif /* IBHOSTS_NAMING */ + +/* + * *printf format helpers. We use the C string constant concatenation + * ability to define 64 bit formats, which unfortunatly are non standard + * in the C compiler world. E.g. %llx for gcc, %I64x for Windows + */ +#include +#define F64d "%"PRId64 +#define F64u "%"PRIu64 +#define F64x "%"PRIx64 +#define F64X "%"PRIX64 + + +/* + * Conversion Functions + */ + +STATIC _INLINE_ long int +dapl_os_strtol(const char *nptr, char **endptr, int base) +{ + return strtol(nptr, endptr, base); +} + + +/* + * Helper Functions + */ + + +#define dapl_os_assert(expression) assert(expression) +#define dapl_os_printf(...) printf(__VA_ARGS__) +#define dapl_os_vprintf(fmt,args) vprintf(fmt,args) +#define dapl_os_syslog(fmt,args) vsyslog(LOG_USER|LOG_WARNING,fmt,args) + +#define dapl_os_getpid (DAT_UINT32)getpid +#define dapl_os_gettid (DAT_UINT32)pthread_self + +#endif /* _DAPL_OSD_H_ */ + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/udapl/windows/dapl_osd.c b/branches/WOF2-3/ulp/dapl2/dapl/udapl/windows/dapl_osd.c new file mode 100644 index 00000000..eb409cdf --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/udapl/windows/dapl_osd.c @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dapl_osd.c + * + * PURPOSE: Operating System Dependent layer + * Description: + * Provide OS dependent functions with a canonical DAPL + * interface. Designed to be portable and hide OS specific quirks + * of common functions. + * + * + * $Id: dapl_osd.c 33 2005-07-11 19:51:17Z ftillier $ + **********************************************************************/ + +/* + * MUST have the Microsoft Platform SDK installed for Windows to build + * and work properly + */ +#include "dapl.h" +#include "dapl_init.h" +#include "dapl_osd.h" +#include +#include /* needed for getenv() */ + +HANDLE heap; + +/* + * DllMain + * + * Primary Windows entry point + * + * Input: + * hDllHandle handle to DLL module + * fdwReason reason for calling function + * lpReserved reserved + * + * Returns: + * DAT_SUCCESS + */ + +BOOL WINAPI +DllMain ( + IN HINSTANCE hDllHandle, + IN DWORD fdwReason, + IN LPVOID lpReserved ) +{ + UNREFERENCED_PARAMETER(lpReserved); + + switch( fdwReason ) + { + case DLL_PROCESS_ATTACH: + heap = HeapCreate(0, 0, 0); + if (heap == NULL) { + return FALSE; + } + /* + * We don't attach/detach threads that need any sort + * of initialization, so disable this ability to optimize + * the working set size of the DLL. Also allows us to + * remove two case statemens: + * DLL_THREAD_DETACH and DLL_THREAD_ATTACH + */ + if ( (DisableThreadLibraryCalls( hDllHandle )) != 0) + { +#if 0 + /* + * Relocated to [dapl_init.c] ..._PROVIDER_INIT() as when called + * from here calls to dapl_init/dapls_ib_init/ib_open_al() hang + * in the DLL call context. + */ + dapl_init (); +#endif + } + else + { + DWORD err = GetLastError(); + dapl_os_printf("DAPL Init Failed with code %u\n", err); + } + break; + + case DLL_PROCESS_DETACH: + /* + * Do library cleanup + */ +#if 0 + /* + * Relocated to [dapl_init.c] ..._PROVIDER_FINI() as the call to + * dapl_fini/dapls_ib_release/ib_close_al() hangs in this DLL call + * context. + */ + dapl_fini (); +#endif + HeapDestroy(heap); + break; + } + return TRUE; +} + + +#ifdef NOT_USED +/* + * dapl_osd_init + * + * Do Windows specific initialization: + * - nothing at this time + * + * Input: + * none + * + * Returns: + * none + */ +void +dapl_osd_init ( ) +{ + return; +} +#endif + +/* + * dapl_os_get_time + * + * Return 64 bit value of current time in microseconds. + * + * Input: + * loc User location to place current time + * + * Returns: + * DAT_SUCCESS + */ + +DAT_RETURN +dapl_os_get_time ( + OUT DAPL_OS_TIMEVAL * loc) +{ + struct _timeb tb; + + _ftime ( &tb ); + + *loc = ((DAT_UINT64) (tb.time * 1000000L) + (DAT_UINT64) tb.millitm * 1000); + + return DAT_SUCCESS; +} + + +/* + * dapl_os_get_bool_env + * + * Return boolean value of passed in environment variable: 1 if present, + * 0 if not + * + * Input: + * + * + * Returns: + * TRUE or FALSE + */ +int +dapl_os_get_env_bool ( + char *env_str ) +{ + char *env_var; + + env_var = getenv (env_str); + if (env_var != NULL) + { + return 1; + } + return 0; +} + + +/* + * dapl_os_get_val_env + * + * Update val to value of passed in environment variable if present + * + * Input: + * env_str + * def_val default value if environment variable does not exist + * + * Returns: + * TRUE or FALSE + */ +int +dapl_os_get_env_val ( + char *env_str, + int def_val ) +{ + char *env_var; + + env_var = getenv (env_str); + if ( env_var != NULL ) + { + def_val = strtol (env_var, NULL, 0); + } + + return def_val; +} + + +/* + * dapls_os_thread_create + * + * Create a thread for dapl + * + * Input: + * func function to invoke thread + * data argument to pass to function + * + * Output + * thread_id handle for thread + * + * Returns: + * DAT_SUCCESS + */ +DAT_RETURN +dapl_os_thread_create ( + IN void (*func) (void *), + IN void *data, + OUT DAPL_OS_THREAD *thread_id ) +{ + + *thread_id = CreateThread( + NULL, /* &thread security attrs */ + 8 * 1024, /* initial thread stack size */ + (LPTHREAD_START_ROUTINE)func, /* &thread function */ + data, /* argument for new thread */ + 0, /* creation flags */ + NULL); /* thread ID (ignore) */ + + if ( *thread_id == NULL ) + { + return DAT_ERROR (DAT_INSUFFICIENT_RESOURCES, 0); + } + + return DAT_SUCCESS; +} + + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dapl/udapl/windows/dapl_osd.h b/branches/WOF2-3/ulp/dapl2/dapl/udapl/windows/dapl_osd.h new file mode 100644 index 00000000..4b9ecbf8 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dapl/udapl/windows/dapl_osd.h @@ -0,0 +1,533 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dapl_osd.h + * + * PURPOSE: Operating System Dependent layer + * Description: + * Provide OS dependent data structures & functions with + * a canonical DAPL interface. Designed to be portable + * and hide OS specific quirks of common functions. + * + * $Id: dapl_osd.h 33 2005-07-11 19:51:17Z ftillier $ + **********************************************************************/ + +#ifndef _DAPL_OSD_H_ +#define _DAPL_OSD_H_ + +/* + * This file is defined for Windows systems only, including it on any + * other build will cause an error + */ +#if !defined(_WIN32) && !defined(_WIN64) +#error UNDEFINED OS TYPE +#endif /* WIN32 */ + +#include +#include +#include <_errno.h> +#pragma warning ( push, 3 ) +#include +#include +#include +#include +#include +#include +#include +#pragma warning ( pop ) + +#include "dapl_debug.h" + +/* Export Header */ +#ifdef EXPORT_DAPL_SYMBOLS /* 1 when building DAPL DLL, 0 for clients */ +#define DAPL_EXPORT __declspec( dllexport ) +#else +#define DAPL_EXPORT __declspec( dllimport ) +#endif + +/* Useful debug definitions */ +#ifndef STATIC +#define STATIC static +#endif /* STATIC */ + +#ifndef _INLINE_ +#define _INLINE_ __inline +#endif /* _INLINE_ */ + +#define dapl_os_panic(str) \ + { \ + fprintf(stderr, "PANIC in %s:%i:%s\n", __FILE__, __LINE__); \ + fprintf(stderr, str); \ + exit(1); \ + } + +#define openlog(...) +#define closelog(...) + +/* + * Atomic operations + */ + +typedef volatile DAT_COUNT DAPL_ATOMIC; + +/* atomic function prototypes */ +STATIC __inline DAT_COUNT +dapl_os_atomic_inc ( + INOUT DAPL_ATOMIC *v); + +STATIC __inline DAT_COUNT +dapl_os_atomic_dec ( + INOUT DAPL_ATOMIC *v); + +STATIC __inline DAT_COUNT +dapl_os_atomic_assign ( + INOUT DAPL_ATOMIC *v, + IN DAT_COUNT match_value, + IN DAT_COUNT new_value ); + +#define dapl_os_atomic_read(v) (*v) +#define dapl_os_atomic_set(v,i) (*v = i) + +int dapl_os_get_env_bool ( + char *env_str ); + +int dapl_os_get_env_val ( + char *env_str, + int def_val ); + + +/* atomic functions */ + +/* dapl_os_atomic_inc + * + * get the current value of '*v', and then increment it. + * + * This is equivalent to an IB atomic fetch and add of 1, + * except that a DAT_COUNT might be 32 bits, rather than 64 + * and it occurs in local memory. + */ + +STATIC __inline DAT_COUNT +dapl_os_atomic_inc ( + INOUT DAPL_ATOMIC *v) +{ + return InterlockedIncrement( v ); +} + + +/* dapl_os_atomic_dec + * + * decrement the current value of '*v'. No return value is required. + */ + +STATIC __inline DAT_COUNT +dapl_os_atomic_dec ( + INOUT DAPL_ATOMIC *v) +{ + return InterlockedDecrement( v ); +} + + +/* dapl_os_atomic_assign + * + * assign 'new_value' to '*v' if the current value + * matches the provided 'match_value'. + * + * Make no assignment if there is no match. + * + * Return the current value in any case. + * + * This matches the IBTA atomic operation compare & swap + * except that it is for local memory and a DAT_COUNT may + * be only 32 bits, rather than 64. + */ + +STATIC __inline DAT_COUNT +dapl_os_atomic_assign ( + INOUT DAPL_ATOMIC *v, + IN DAT_COUNT match_value, + IN DAT_COUNT new_value ) +{ + return InterlockedCompareExchange((LPLONG)v, + new_value, + match_value); +} + + +/* + * Thread Functions + */ +typedef HANDLE DAPL_OS_THREAD; + +DAT_RETURN +dapl_os_thread_create ( + IN void (*func) (void *), + IN void *data, + OUT DAPL_OS_THREAD *thread_id ); + + +/* + * Lock Functions + */ +typedef HANDLE DAPL_OS_LOCK; + +/* function prototypes */ +/* lock functions */ +STATIC __inline DAT_RETURN +dapl_os_lock_init ( + IN DAPL_OS_LOCK *m) +{ + *m = CreateMutex (0, FALSE, 0); + + return *m ? DAT_SUCCESS : (DAT_CLASS_ERROR | DAT_INSUFFICIENT_RESOURCES); +} + +STATIC __inline DAT_RETURN +dapl_os_lock ( + IN DAPL_OS_LOCK *m) +{ + WaitForSingleObject (*m, INFINITE); + + return DAT_SUCCESS; +} + +STATIC __inline DAT_RETURN +dapl_os_unlock ( + IN DAPL_OS_LOCK *m) +{ + ReleaseMutex (*m); + + return DAT_SUCCESS; +} + +STATIC __inline DAT_RETURN +dapl_os_lock_destroy ( + IN DAPL_OS_LOCK *m) +{ + CloseHandle (*m); + + return DAT_SUCCESS; +} + + +/* + * Wait Objects + */ + +/* + * The wait object invariant: Presuming a call to dapl_os_wait_object_wait + * occurs at some point, there will be at least one wakeup after each call + * to dapl_os_wait_object_signal. I.e. Signals are not ignored, though + * they may be coallesced. + */ + +/* wait_object functions */ + +typedef HANDLE DAPL_OS_WAIT_OBJECT; + +/* Initialize a wait object to an empty state + */ + +STATIC __inline DAT_RETURN +dapl_os_wait_object_init ( + IN DAPL_OS_WAIT_OBJECT *wait_obj) +{ + *wait_obj = CreateEvent(NULL,FALSE,FALSE,NULL); + + if ( *wait_obj == NULL ) + { + return DAT_CLASS_ERROR | DAT_INTERNAL_ERROR; + } + + return DAT_SUCCESS; +} + + +/* Wait on the supplied wait object, up to the specified time_out, + * and reacquiring it after the wait ends. + * A timeout of DAT_TIMEOUT_INFINITE will wait indefinitely. + * Timeout should be specified in micro seconds. + * + * Functional returns: + * DAT_SUCCESS -- another thread invoked dapl_os_wait object_wakeup + * DAT_INVALID_STATE -- someone else is already waiting in this wait + * object. + * only one waiter is allowed at a time. + * DAT_ABORT -- another thread invoked dapl_os_wait_object_destroy + * DAT_TIMEOUT -- the specified time limit was reached. + */ + +STATIC __inline DAT_RETURN +dapl_os_wait_object_wait ( + IN DAPL_OS_WAIT_OBJECT *wait_obj, + IN DAT_TIMEOUT timeout_val) +{ + DAT_RETURN status; + DWORD op_status; + + status = DAT_SUCCESS; + + if ( DAT_TIMEOUT_INFINITE == timeout_val ) + { + op_status = WaitForSingleObject(*wait_obj, INFINITE); + } + else + { + /* convert to milliseconds */ + op_status = WaitForSingleObject(*wait_obj, timeout_val/1000); + } + + if (op_status == WAIT_TIMEOUT) + { + status = DAT_CLASS_ERROR | DAT_TIMEOUT_EXPIRED; + } + else if ( op_status == WAIT_FAILED) + { + status = DAT_CLASS_ERROR | DAT_INTERNAL_ERROR; + } + + return status; +} + +STATIC __inline DAT_RETURN +dapl_os_wait_object_wakeup ( + IN DAPL_OS_WAIT_OBJECT *wait_obj) +{ + DWORD op_status; + + op_status = SetEvent(*wait_obj); + if ( op_status == 0 ) + { + return DAT_CLASS_ERROR | DAT_INTERNAL_ERROR; + } + + return DAT_SUCCESS; +} + +STATIC __inline DAT_RETURN +dapl_os_wait_object_destroy ( + IN DAPL_OS_WAIT_OBJECT *wait_obj) +{ + DWORD op_status; + DAT_RETURN status = DAT_SUCCESS; + + op_status = CloseHandle(*wait_obj); + + if ( op_status == 0 ) + { + status = DAT_CLASS_ERROR | DAT_INTERNAL_ERROR; + } + + return status; +} + + +/* + * Memory Functions + */ + +extern HANDLE heap; + +/* function prototypes */ +STATIC __inline void *dapl_os_alloc (int size); + +STATIC __inline void *dapl_os_realloc (void *ptr, int size); + +STATIC __inline void dapl_os_free (void *ptr, int size); + +STATIC __inline void * dapl_os_memzero (void *loc, int size); + +STATIC __inline void * dapl_os_memcpy (void *dest, const void *src, int len); + +STATIC __inline int dapl_os_memcmp (const void *mem1, const void *mem2, int len); + +/* + * Memory coherency functions + * For i386/x86_64 Windows, there are no coherency issues - just return success. + */ +STATIC __inline DAT_RETURN +dapl_os_sync_rdma_read ( + IN const DAT_LMR_TRIPLET *local_segments, + IN DAT_VLEN num_segments) +{ + return DAT_SUCCESS; +} + +STATIC __inline DAT_RETURN +dapl_os_sync_rdma_write ( + IN const DAT_LMR_TRIPLET *local_segments, + IN DAT_VLEN num_segments) +{ + return DAT_SUCCESS; +} + + +/* memory functions */ + + +STATIC __inline void *dapl_os_alloc (int size) +{ + return HeapAlloc(heap, 0, size); +} + +STATIC __inline void *dapl_os_realloc (void *ptr, int size) +{ + return HeapReAlloc(heap, 0, ptr, size); +} + +STATIC __inline void dapl_os_free (void *ptr, int size) +{ + UNREFERENCED_PARAMETER(size); + HeapFree(heap, 0, ptr); +} + +STATIC __inline void * dapl_os_memzero (void *loc, int size) +{ + return memset (loc, 0, size); +} + +STATIC __inline void * dapl_os_memcpy (void *dest, const void *src, int len) +{ + return memcpy (dest, src, len); +} + +STATIC __inline int dapl_os_memcmp (const void *mem1, const void *mem2, int len) +{ + return memcmp (mem1, mem2, len); +} + + +STATIC __inline unsigned int dapl_os_strlen(const char *str) +{ + return ((unsigned int)strlen(str)); +} + +STATIC __inline char * dapl_os_strdup(const char *str) +{ + char *dup; + + dup = dapl_os_alloc(strlen(str) + 1); + if (!dup) + return NULL; + strcpy(dup, str); + return dup; +} + + +/* + * Timer Functions + */ + +typedef DAT_UINT64 DAPL_OS_TIMEVAL; +typedef struct dapl_timer_entry DAPL_OS_TIMER; +typedef unsigned long DAPL_OS_TICKS; + +/* function prototypes */ + +/* + * Sleep for the number of micro seconds specified by the invoking + * function + */ +STATIC __inline void dapl_os_sleep_usec (int sleep_time) +{ + Sleep(sleep_time/1000); // convert to milliseconds +} + +STATIC __inline DAPL_OS_TICKS dapl_os_get_ticks (void); + +STATIC __inline int dapl_os_ticks_to_seconds (DAPL_OS_TICKS ticks); + +DAT_RETURN dapl_os_get_time (DAPL_OS_TIMEVAL *); +/* timer functions */ + +STATIC __inline DAPL_OS_TICKS dapl_os_get_ticks (void) +{ + return GetTickCount (); +} + +STATIC __inline int dapl_os_ticks_to_seconds (DAPL_OS_TICKS ticks) +{ + ticks = ticks; + /* NOT YET IMPLEMENTED IN USER-SPACE */ + return 0; +} + + +/* + * + * Name Service Helper functions + * + */ +#ifdef IBHOSTS_NAMING +#define dapls_osd_getaddrinfo(name, addr_ptr) getaddrinfo(name,NULL,NULL,addr_ptr) +#define dapls_osd_freeaddrinfo(addr) freeaddrinfo (addr) + +#endif /* IBHOSTS_NAMING */ + +/* + * *printf format helpers. We use the C string constant concatenation + * ability to define 64 bit formats, which unfortunatly are non standard + * in the C compiler world. E.g. %llx for gcc, %I64x for Windows + */ +#define F64d "%I64d" +#define F64u "%I64u" +#define F64x "%I64x" +#define F64X "%I64X" + +/* + * Conversion Functions + */ + +STATIC __inline long int +dapl_os_strtol(const char *nptr, char **endptr, int base) +{ + return strtol(nptr, endptr, base); +} + +#define dapl_os_getpid (DAT_UINT32)GetCurrentProcessId +#define dapl_os_gettid (DAT_UINT32)GetCurrentThreadId + +/* + * Debug Helper Functions + */ + +#define dapl_os_assert(expression) CL_ASSERT(expression) + +#define dapl_os_printf printf +#define dapl_os_vprintf(fmt,args) vprintf(fmt,args) +#define dapl_os_syslog(fmt,args) /* XXX Need log routine call */ + +#endif /* _DAPL_OSD_H_ */ + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dat/common/dat_api.c b/branches/WOF2-3/ulp/dapl2/dat/common/dat_api.c new file mode 100644 index 00000000..781c9a65 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dat/common/dat_api.c @@ -0,0 +1,1077 @@ +/* + * Copyright (c) 2002-2006, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under all of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 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. + * + * Neither the name of Network Appliance, Inc. nor the names of other DAT + * Collaborative contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + */ + +/********************************************************************** + * + * MODULE: dat_api.c + * + * PURPOSE: DAT Provider and Consumer registry functions. + * Also provide small integers for IA_HANDLES + * + * $Id: dat_api.c 1326 2005-05-20 22:25:31Z jlentini $ + **********************************************************************/ + +#include +#include +#include "dat_osd.h" +#include "dat_init.h" + +/* + * structure to deal with IA handles + */ +typedef struct { + DAT_OS_LOCK handle_lock; + unsigned long handle_max; + void **handle_array; +} DAT_HANDLE_VEC; + +/* + * Number of IA Handle entries allocated at a time. + */ +#define DAT_HANDLE_ENTRY_STEP 64 + +static DAT_HANDLE_VEC g_hv; + +/*********************************************************************** + * Function: dats_handle_init + * + * Initialize a handle_vector. Happens when the module initializes + ***********************************************************************/ +DAT_RETURN dats_handle_vector_init(void) +{ + DAT_RETURN dat_status; + unsigned long i; + + dat_status = DAT_SUCCESS; + + g_hv.handle_max = DAT_HANDLE_ENTRY_STEP; + + dat_status = dat_os_lock_init(&g_hv.handle_lock); + if (DAT_SUCCESS != dat_status) { + return dat_status; + } + + g_hv.handle_array = + dat_os_alloc(sizeof(void *) * DAT_HANDLE_ENTRY_STEP); + if (g_hv.handle_array == NULL) { + dat_status = + DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); + goto bail; + } + + for (i = 0; i < g_hv.handle_max; i++) { + g_hv.handle_array[i] = NULL; + } + + bail: + return dat_status; +} + +/*********************************************************************** + * Function: dats_set_ia_handle + * + * Install an ia_handle into a handle vector and return a small + * integer. + ***********************************************************************/ +DAT_IA_HANDLE dats_set_ia_handle(IN DAT_IA_HANDLE ia_handle) +{ + unsigned long i; + void **h; + + dat_os_lock(&g_hv.handle_lock); + + /* + * Don't give out handle zero since that is DAT_HANDLE_NULL! + */ + for (i = 1; i < g_hv.handle_max; i++) { + if (g_hv.handle_array[i] == NULL) { + g_hv.handle_array[i] = ia_handle; + + dat_os_unlock(&g_hv.handle_lock); + + dat_os_dbg_print(DAT_OS_DBG_TYPE_PROVIDER_API, + "dat_set_handle %p to %d\n", ia_handle, + i); + return DAT_UL_TO_IA_HANDLE(i); + } + } + + /* Didn't find an entry, grow the list & try again */ + dat_os_dbg_print(DAT_OS_DBG_TYPE_PROVIDER_API, + "Growing the handle array from %d to %d\n", + g_hv.handle_max, + g_hv.handle_max + DAT_HANDLE_ENTRY_STEP); + + /* reallocate the handle array */ + h = dat_os_alloc(sizeof(void *) * + (g_hv.handle_max + DAT_HANDLE_ENTRY_STEP)); + if (h == NULL) { + dat_os_unlock(&g_hv.handle_lock); + return DAT_UL_TO_IA_HANDLE(-1); + } + /* copy old data to new area & free old memory */ + memcpy((void *)h, (void *)g_hv.handle_array, + sizeof(void *) * g_hv.handle_max); + dat_os_free(g_hv.handle_array, sizeof(void *) * g_hv.handle_max); + g_hv.handle_array = h; + + /* Initialize the new entries */ + for (i = g_hv.handle_max; i < g_hv.handle_max + DAT_HANDLE_ENTRY_STEP; + i++) { + g_hv.handle_array[i] = NULL; + } + i = g_hv.handle_max; + g_hv.handle_array[i] = ia_handle; + g_hv.handle_max += DAT_HANDLE_ENTRY_STEP; + dat_os_unlock(&g_hv.handle_lock); + + dat_os_dbg_print(DAT_OS_DBG_TYPE_PROVIDER_API, + "dat_set_handle x %p to %d\n", ia_handle, i); + + return DAT_UL_TO_IA_HANDLE(i); +} + +/*********************************************************************** + * Function: dats_get_ia_handle( + * + * Get a handle from a handle vector and return it in an OUT parameter + ***********************************************************************/ +DAT_RETURN +dats_get_ia_handle(IN DAT_IA_HANDLE handle, OUT DAT_IA_HANDLE * ia_handle_p) +{ + DAT_RETURN dat_status; + + if (DAT_IA_HANDLE_TO_UL(handle) >= g_hv.handle_max) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_IA); + goto bail; + } + *ia_handle_p = g_hv.handle_array[DAT_IA_HANDLE_TO_UL(handle)]; + + if (*ia_handle_p == NULL) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_IA); + goto bail; + } + dat_status = DAT_SUCCESS; + + bail: + dat_os_dbg_print(DAT_OS_DBG_TYPE_PROVIDER_API, + "dat_get_ia_handle from %d to %p\n", + handle, *ia_handle_p); + + return dat_status; +} + +/*********************************************************************** + * Function: dats_is_ia_handle + * + * Unlike other handles, a DAT_IA_HANDLE is a small integer. Therefore, + * we must be able to distinguish between a DAT_IA_HANDLE and other + * types of handles (which are actually pointers). + * + * The current implementation assumes that any value for which an IA + * handle exists is a DAT_IA_HANDLE. Unfortunately this will result in + * false positives. In particular it may identify a NULL pointer as IA + * handle 0. An implementation that does not have this deficiency would + * be preferable. + * + ***********************************************************************/ +DAT_RETURN dats_is_ia_handle(IN DAT_HANDLE dat_handle) +{ + unsigned long handle = DAT_IA_HANDLE_TO_UL((DAT_IA_HANDLE) dat_handle); + + if (g_hv.handle_max <= handle) { + return DAT_FALSE; + } else if (NULL == g_hv.handle_array[handle]) { + return DAT_FALSE; + } else { + return DAT_TRUE; + } +} + +/*********************************************************************** + * Function: dats_free_ia_handle + * + * Free a handle in a handle vector + ***********************************************************************/ +DAT_RETURN dats_free_ia_handle(IN DAT_IA_HANDLE handle) +{ + DAT_RETURN dat_status; + + if (DAT_IA_HANDLE_TO_UL(handle) >= g_hv.handle_max) { + dat_status = + DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_IA); + goto bail; + } + g_hv.handle_array[DAT_IA_HANDLE_TO_UL(handle)] = NULL; + dat_status = DAT_SUCCESS; + + dat_os_dbg_print(DAT_OS_DBG_TYPE_PROVIDER_API, + "dats_free_ia_handle %d\n", handle); + + bail: + return dat_status; +} + +/********************************************************************** + * API definitions for common API entry points + **********************************************************************/ +DAT_RETURN DAT_API dat_ia_query(IN DAT_IA_HANDLE ia_handle, + OUT DAT_EVD_HANDLE * async_evd_handle, + IN DAT_IA_ATTR_MASK ia_attr_mask, + OUT DAT_IA_ATTR * ia_attr, + IN DAT_PROVIDER_ATTR_MASK provider_attr_mask, + OUT DAT_PROVIDER_ATTR * provider_attr) +{ + DAT_IA_HANDLE dapl_ia_handle; + DAT_RETURN dat_status; + + dat_status = dats_get_ia_handle(ia_handle, &dapl_ia_handle); + if (dat_status == DAT_SUCCESS) { + dat_status = DAT_IA_QUERY(dapl_ia_handle, + async_evd_handle, + ia_attr_mask, + ia_attr, + provider_attr_mask, provider_attr); + } + + return dat_status; +} + +DAT_RETURN DAT_API dat_set_consumer_context(IN DAT_HANDLE dat_handle, + IN DAT_CONTEXT context) +{ + if (dats_is_ia_handle(dat_handle)) { + DAT_IA_HANDLE dapl_ia_handle; + DAT_RETURN dat_status; + + dat_status = dats_get_ia_handle((DAT_IA_HANDLE) dat_handle, + &dapl_ia_handle); + + /* failure to map the handle is unlikely but possible */ + /* in a mult-threaded environment */ + if (DAT_SUCCESS == dat_status) { + return DAT_ERROR(DAT_INVALID_HANDLE, + DAT_INVALID_HANDLE1); + } + + dat_handle = dapl_ia_handle; + } + + return DAT_SET_CONSUMER_CONTEXT(dat_handle, context); +} + +DAT_RETURN DAT_API dat_get_consumer_context(IN DAT_HANDLE dat_handle, + OUT DAT_CONTEXT * context) +{ + if (dats_is_ia_handle(dat_handle)) { + DAT_IA_HANDLE dapl_ia_handle; + DAT_RETURN dat_status; + + dat_status = dats_get_ia_handle((DAT_IA_HANDLE) dat_handle, + &dapl_ia_handle); + + /* failure to map the handle is unlikely but possible */ + /* in a mult-threaded environment */ + if (DAT_SUCCESS == dat_status) { + return DAT_ERROR(DAT_INVALID_HANDLE, + DAT_INVALID_HANDLE1); + } + + dat_handle = dapl_ia_handle; + } + + return DAT_GET_CONSUMER_CONTEXT(dat_handle, context); +} + +DAT_RETURN DAT_API dat_get_handle_type(IN DAT_HANDLE dat_handle, + OUT DAT_HANDLE_TYPE * type) +{ + if (dats_is_ia_handle(dat_handle)) { + DAT_IA_HANDLE dapl_ia_handle; + DAT_RETURN dat_status; + + dat_status = dats_get_ia_handle((DAT_IA_HANDLE) dat_handle, + &dapl_ia_handle); + + /* failure to map the handle is unlikely but possible */ + /* in a mult-threaded environment */ + if (DAT_SUCCESS == dat_status) { + return DAT_ERROR(DAT_INVALID_HANDLE, + DAT_INVALID_HANDLE1); + } + + dat_handle = dapl_ia_handle; + } + + return DAT_GET_HANDLE_TYPE(dat_handle, type); +} + +DAT_RETURN DAT_API dat_cr_query(IN DAT_CR_HANDLE cr_handle, + IN DAT_CR_PARAM_MASK cr_param_mask, + OUT DAT_CR_PARAM * cr_param) +{ + if (cr_handle == NULL) { + return DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_CR); + } + return DAT_CR_QUERY(cr_handle, cr_param_mask, cr_param); +} + +DAT_RETURN DAT_API dat_cr_accept(IN DAT_CR_HANDLE cr_handle, + IN DAT_EP_HANDLE ep_handle, + IN DAT_COUNT private_data_size, + IN const DAT_PVOID private_data) +{ + if (cr_handle == NULL) { + return DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_CR); + } + return DAT_CR_ACCEPT(cr_handle, + ep_handle, private_data_size, private_data); +} + +DAT_RETURN DAT_API dat_cr_reject(IN DAT_CR_HANDLE cr_handle, + IN DAT_COUNT private_data_size, + IN const DAT_PVOID private_data) +{ + if (cr_handle == NULL) { + return DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_CR); + } + return DAT_CR_REJECT(cr_handle, private_data_size, private_data); +} + +DAT_RETURN DAT_API dat_evd_resize(IN DAT_EVD_HANDLE evd_handle, + IN DAT_COUNT evd_min_qlen) +{ + if (evd_handle == NULL) { + return DAT_ERROR(DAT_INVALID_HANDLE, + DAT_INVALID_HANDLE_EVD_REQUEST); + } + return DAT_EVD_RESIZE(evd_handle, evd_min_qlen); +} + +DAT_RETURN DAT_API dat_evd_post_se(IN DAT_EVD_HANDLE evd_handle, + IN const DAT_EVENT * event) +{ + if (evd_handle == NULL) { + return DAT_ERROR(DAT_INVALID_HANDLE, + DAT_INVALID_HANDLE_EVD_REQUEST); + } + return DAT_EVD_POST_SE(evd_handle, event); +} + +DAT_RETURN DAT_API dat_evd_dequeue(IN DAT_EVD_HANDLE evd_handle, + OUT DAT_EVENT * event) +{ + if (evd_handle == NULL) { + return DAT_ERROR(DAT_INVALID_HANDLE, + DAT_INVALID_HANDLE_EVD_REQUEST); + } + return DAT_EVD_DEQUEUE(evd_handle, event); +} + +DAT_RETURN DAT_API dat_evd_free(IN DAT_EVD_HANDLE evd_handle) +{ + if (evd_handle == NULL) { + return DAT_ERROR(DAT_INVALID_HANDLE, + DAT_INVALID_HANDLE_EVD_REQUEST); + } + return DAT_EVD_FREE(evd_handle); +} + +DAT_RETURN DAT_API dat_evd_query(IN DAT_EVD_HANDLE evd_handle, + IN DAT_EVD_PARAM_MASK evd_param_mask, + OUT DAT_EVD_PARAM * evd_param) +{ + if (evd_handle == NULL) { + return DAT_ERROR(DAT_INVALID_HANDLE, + DAT_INVALID_HANDLE_EVD_REQUEST); + } + return DAT_EVD_QUERY(evd_handle, evd_param_mask, evd_param); +} + +DAT_RETURN DAT_API dat_ep_create(IN DAT_IA_HANDLE ia_handle, + IN DAT_PZ_HANDLE pz_handle, + IN DAT_EVD_HANDLE recv_completion_evd_handle, + IN DAT_EVD_HANDLE + request_completion_evd_handle, + IN DAT_EVD_HANDLE connect_evd_handle, + IN const DAT_EP_ATTR * ep_attributes, + OUT DAT_EP_HANDLE * ep_handle) +{ + DAT_IA_HANDLE dapl_ia_handle; + DAT_RETURN dat_status; + + dat_status = dats_get_ia_handle(ia_handle, &dapl_ia_handle); + if (dat_status == DAT_SUCCESS) { + dat_status = DAT_EP_CREATE(dapl_ia_handle, + pz_handle, + recv_completion_evd_handle, + request_completion_evd_handle, + connect_evd_handle, + ep_attributes, ep_handle); + } + + return dat_status; +} + +DAT_RETURN DAT_API dat_ep_query(IN DAT_EP_HANDLE ep_handle, + IN DAT_EP_PARAM_MASK ep_param_mask, + OUT DAT_EP_PARAM * ep_param) +{ + if (ep_handle == NULL) { + return DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP); + } + return DAT_EP_QUERY(ep_handle, ep_param_mask, ep_param); +} + +DAT_RETURN DAT_API dat_ep_modify(IN DAT_EP_HANDLE ep_handle, + IN DAT_EP_PARAM_MASK ep_param_mask, + IN const DAT_EP_PARAM * ep_param) +{ + if (ep_handle == NULL) { + return DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP); + } + return DAT_EP_MODIFY(ep_handle, ep_param_mask, ep_param); +} + +DAT_RETURN DAT_API dat_ep_connect(IN DAT_EP_HANDLE ep_handle, + IN DAT_IA_ADDRESS_PTR remote_ia_address, + IN DAT_CONN_QUAL remote_conn_qual, + IN DAT_TIMEOUT timeout, + IN DAT_COUNT private_data_size, + IN const DAT_PVOID private_data, + IN DAT_QOS quality_of_service, + IN DAT_CONNECT_FLAGS connect_flags) +{ + if (ep_handle == NULL) { + return DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP); + } + return DAT_EP_CONNECT(ep_handle, + remote_ia_address, + remote_conn_qual, + timeout, + private_data_size, + private_data, quality_of_service, connect_flags); +} + +DAT_RETURN DAT_API dat_ep_common_connect(IN DAT_EP_HANDLE ep_handle, + IN DAT_IA_ADDRESS_PTR + remote_ia_address, + IN DAT_TIMEOUT timeout, + IN DAT_COUNT private_data_size, + IN const DAT_PVOID private_data) +{ + if (ep_handle == NULL) { + return DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP); + } + return DAT_EP_COMMON_CONNECT(ep_handle, + remote_ia_address, + timeout, private_data_size, private_data); +} + +DAT_RETURN DAT_API dat_ep_dup_connect(IN DAT_EP_HANDLE ep_handle, + IN DAT_EP_HANDLE ep_dup_handle, + IN DAT_TIMEOUT timeout, + IN DAT_COUNT private_data_size, + IN const DAT_PVOID private_data, + IN DAT_QOS quality_of_service) +{ + if (ep_handle == NULL) { + return DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP); + } + return DAT_EP_DUP_CONNECT(ep_handle, + ep_dup_handle, + timeout, + private_data_size, + private_data, quality_of_service); +} + +DAT_RETURN DAT_API dat_ep_disconnect(IN DAT_EP_HANDLE ep_handle, + IN DAT_CLOSE_FLAGS close_flags) +{ + if (ep_handle == NULL) { + return DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP); + } + return DAT_EP_DISCONNECT(ep_handle, close_flags); +} + +DAT_RETURN DAT_API dat_ep_post_send(IN DAT_EP_HANDLE ep_handle, + IN DAT_COUNT num_segments, + IN DAT_LMR_TRIPLET * local_iov, + IN DAT_DTO_COOKIE user_cookie, + IN DAT_COMPLETION_FLAGS completion_flags) +{ + if (ep_handle == NULL) { + return DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP); + } + return DAT_EP_POST_SEND(ep_handle, + num_segments, + local_iov, user_cookie, completion_flags); +} + +DAT_RETURN DAT_API dat_ep_post_send_with_invalidate(IN DAT_EP_HANDLE ep_handle, + IN DAT_COUNT num_segments, + IN DAT_LMR_TRIPLET * + local_iov, + IN DAT_DTO_COOKIE + user_cookie, + IN DAT_COMPLETION_FLAGS + completion_flags, + IN DAT_BOOLEAN + invalidate_flag, + IN DAT_RMR_CONTEXT + rmr_context) +{ + if (ep_handle == NULL) { + return DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP); + } + return DAT_EP_POST_SEND_WITH_INVALIDATE(ep_handle, + num_segments, + local_iov, + user_cookie, + completion_flags, + invalidate_flag, rmr_context); +} + +DAT_RETURN DAT_API dat_ep_post_recv(IN DAT_EP_HANDLE ep_handle, + IN DAT_COUNT num_segments, + IN DAT_LMR_TRIPLET * local_iov, + IN DAT_DTO_COOKIE user_cookie, + IN DAT_COMPLETION_FLAGS completion_flags) +{ + if (ep_handle == NULL) { + return DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP); + } + return DAT_EP_POST_RECV(ep_handle, + num_segments, + local_iov, user_cookie, completion_flags); +} + +DAT_RETURN DAT_API dat_ep_post_rdma_read(IN DAT_EP_HANDLE ep_handle, + IN DAT_COUNT num_segments, + IN DAT_LMR_TRIPLET * local_iov, + IN DAT_DTO_COOKIE user_cookie, + IN const DAT_RMR_TRIPLET * remote_iov, + IN DAT_COMPLETION_FLAGS + completion_flags) +{ + if (ep_handle == NULL) { + return DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP); + } + return DAT_EP_POST_RDMA_READ(ep_handle, + num_segments, + local_iov, + user_cookie, remote_iov, completion_flags); +} + +DAT_RETURN DAT_API dat_ep_post_rdma_read_to_rmr(IN DAT_EP_HANDLE ep_handle, + IN const DAT_RMR_TRIPLET * + local_iov, + IN DAT_DTO_COOKIE user_cookie, + IN const DAT_RMR_TRIPLET * + remote_iov, + IN DAT_COMPLETION_FLAGS + completion_flags) +{ + if (ep_handle == NULL) { + return DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP); + } + return DAT_EP_POST_RDMA_READ_TO_RMR(ep_handle, + local_iov, + user_cookie, + remote_iov, completion_flags); +} + +DAT_RETURN DAT_API dat_ep_post_rdma_write(IN DAT_EP_HANDLE ep_handle, + IN DAT_COUNT num_segments, + IN DAT_LMR_TRIPLET * local_iov, + IN DAT_DTO_COOKIE user_cookie, + IN const DAT_RMR_TRIPLET * remote_iov, + IN DAT_COMPLETION_FLAGS + completion_flags) +{ + if (ep_handle == NULL) { + return DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP); + } + return DAT_EP_POST_RDMA_WRITE(ep_handle, + num_segments, + local_iov, + user_cookie, + remote_iov, completion_flags); +} + +DAT_RETURN DAT_API dat_ep_get_status(IN DAT_EP_HANDLE ep_handle, + OUT DAT_EP_STATE * ep_state, + OUT DAT_BOOLEAN * recv_idle, + OUT DAT_BOOLEAN * request_idle) +{ + if (ep_handle == NULL) { + return DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP); + } + return DAT_EP_GET_STATUS(ep_handle, ep_state, recv_idle, request_idle); +} + +DAT_RETURN DAT_API dat_ep_free(IN DAT_EP_HANDLE ep_handle) +{ + if (ep_handle == NULL) { + return DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP); + } + return DAT_EP_FREE(ep_handle); +} + +DAT_RETURN DAT_API dat_ep_reset(IN DAT_EP_HANDLE ep_handle) +{ + if (ep_handle == NULL) { + return DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP); + } + return DAT_EP_RESET(ep_handle); +} + +DAT_RETURN DAT_API dat_lmr_free(IN DAT_LMR_HANDLE lmr_handle) +{ + if (lmr_handle == NULL) { + return DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_LMR); + } + return DAT_LMR_FREE(lmr_handle); +} + +DAT_RETURN DAT_API dat_rmr_create(IN DAT_PZ_HANDLE pz_handle, + OUT DAT_RMR_HANDLE * rmr_handle) +{ + if (pz_handle == NULL) { + return DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_PZ); + } + return DAT_RMR_CREATE(pz_handle, rmr_handle); +} + +DAT_RETURN DAT_API dat_rmr_create_for_ep(IN DAT_PZ_HANDLE pz_handle, + OUT DAT_RMR_HANDLE * rmr_handle) +{ + if (pz_handle == NULL) { + return DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_PZ); + } + return DAT_RMR_CREATE_FOR_EP(pz_handle, rmr_handle); +} +DAT_RETURN DAT_API dat_rmr_query(IN DAT_RMR_HANDLE rmr_handle, + IN DAT_RMR_PARAM_MASK rmr_param_mask, + OUT DAT_RMR_PARAM * rmr_param) +{ + if (rmr_handle == NULL) { + return DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_RMR); + } + return DAT_RMR_QUERY(rmr_handle, rmr_param_mask, rmr_param); +} + +DAT_RETURN DAT_API dat_rmr_bind(IN DAT_RMR_HANDLE rmr_handle, + IN DAT_LMR_HANDLE lmr_handle, + IN const DAT_LMR_TRIPLET * lmr_triplet, + IN DAT_MEM_PRIV_FLAGS mem_priv, + IN DAT_VA_TYPE va_type, + IN DAT_EP_HANDLE ep_handle, + IN DAT_RMR_COOKIE user_cookie, + IN DAT_COMPLETION_FLAGS completion_flags, + OUT DAT_RMR_CONTEXT * context) +{ + if (rmr_handle == NULL) { + return DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_RMR); + } + return DAT_RMR_BIND(rmr_handle, + lmr_handle, + lmr_triplet, + mem_priv, + va_type, + ep_handle, user_cookie, completion_flags, context); +} + +DAT_RETURN DAT_API dat_rmr_free(IN DAT_RMR_HANDLE rmr_handle) +{ + if (rmr_handle == NULL) { + return DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_RMR); + } + return DAT_RMR_FREE(rmr_handle); +} + +DAT_RETURN DAT_API dat_lmr_sync_rdma_read(IN DAT_IA_HANDLE ia_handle, + IN const DAT_LMR_TRIPLET * + local_segments, + IN DAT_VLEN num_segments) +{ + DAT_IA_HANDLE dapl_ia_handle; + DAT_RETURN dat_status; + + dat_status = dats_get_ia_handle(ia_handle, &dapl_ia_handle); + if (dat_status == DAT_SUCCESS) { + dat_status = DAT_LMR_SYNC_RDMA_READ(dapl_ia_handle, + local_segments, + num_segments); + + } + + return dat_status; +} + +DAT_RETURN DAT_API dat_lmr_sync_rdma_write(IN DAT_IA_HANDLE ia_handle, + IN const DAT_LMR_TRIPLET * + local_segments, + IN DAT_VLEN num_segments) +{ + DAT_IA_HANDLE dapl_ia_handle; + DAT_RETURN dat_status; + + dat_status = dats_get_ia_handle(ia_handle, &dapl_ia_handle); + if (dat_status == DAT_SUCCESS) { + dat_status = DAT_LMR_SYNC_RDMA_WRITE(dapl_ia_handle, + local_segments, + num_segments); + } + + return dat_status; +} + +DAT_RETURN DAT_API dat_psp_create(IN DAT_IA_HANDLE ia_handle, + IN DAT_CONN_QUAL conn_qual, + IN DAT_EVD_HANDLE evd_handle, + IN DAT_PSP_FLAGS psp_flags, + OUT DAT_PSP_HANDLE * psp_handle) +{ + DAT_IA_HANDLE dapl_ia_handle; + DAT_RETURN dat_status; + + dat_status = dats_get_ia_handle(ia_handle, &dapl_ia_handle); + if (dat_status == DAT_SUCCESS) { + dat_status = DAT_PSP_CREATE(dapl_ia_handle, + conn_qual, + evd_handle, psp_flags, psp_handle); + } + + return dat_status; +} + +DAT_RETURN DAT_API dat_psp_create_any(IN DAT_IA_HANDLE ia_handle, + OUT DAT_CONN_QUAL * conn_qual, + IN DAT_EVD_HANDLE evd_handle, + IN DAT_PSP_FLAGS psp_flags, + OUT DAT_PSP_HANDLE * psp_handle) +{ + DAT_IA_HANDLE dapl_ia_handle; + DAT_RETURN dat_status; + + dat_status = dats_get_ia_handle(ia_handle, &dapl_ia_handle); + if (dat_status == DAT_SUCCESS) { + dat_status = DAT_PSP_CREATE_ANY(dapl_ia_handle, + conn_qual, + evd_handle, + psp_flags, psp_handle); + } + + return dat_status; +} + +DAT_RETURN DAT_API dat_psp_query(IN DAT_PSP_HANDLE psp_handle, + IN DAT_PSP_PARAM_MASK psp_param_mask, + OUT DAT_PSP_PARAM * psp_param) +{ + if (psp_handle == NULL) { + return DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_PSP); + } + return DAT_PSP_QUERY(psp_handle, psp_param_mask, psp_param); +} + +DAT_RETURN DAT_API dat_psp_free(IN DAT_PSP_HANDLE psp_handle) +{ + if (psp_handle == NULL) { + return DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_PSP); + } + return DAT_PSP_FREE(psp_handle); +} + +DAT_RETURN DAT_API dat_csp_create(IN DAT_IA_HANDLE ia_handle, + IN DAT_COMM * comm, + IN DAT_IA_ADDRESS_PTR address, + IN DAT_EVD_HANDLE evd_handle, + OUT DAT_CSP_HANDLE * csp_handle) +{ + DAT_IA_HANDLE dapl_ia_handle; + DAT_RETURN dat_status; + + dat_status = dats_get_ia_handle(ia_handle, &dapl_ia_handle); + if (dat_status == DAT_SUCCESS) { + dat_status = DAT_CSP_CREATE(dapl_ia_handle, + comm, + address, evd_handle, csp_handle); + } + return dat_status; +} + +DAT_RETURN DAT_API dat_csp_query(IN DAT_CSP_HANDLE csp_handle, + IN DAT_CSP_PARAM_MASK csp_param_mask, + OUT DAT_CSP_PARAM * csp_param) +{ + if (csp_handle == NULL) { + return DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_CSP); + } + return DAT_CSP_QUERY(csp_handle, csp_param_mask, csp_param); +} + +DAT_RETURN DAT_API dat_csp_free(IN DAT_CSP_HANDLE csp_handle) +{ + if (csp_handle == NULL) { + return DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_CSP); + } + return DAT_CSP_FREE(csp_handle); +} + +DAT_RETURN DAT_API dat_rsp_create(IN DAT_IA_HANDLE ia_handle, + IN DAT_CONN_QUAL conn_qual, + IN DAT_EP_HANDLE ep_handle, + IN DAT_EVD_HANDLE evd_handle, + OUT DAT_RSP_HANDLE * rsp_handle) +{ + DAT_IA_HANDLE dapl_ia_handle; + DAT_RETURN dat_status; + + dat_status = dats_get_ia_handle(ia_handle, &dapl_ia_handle); + if (dat_status == DAT_SUCCESS) { + dat_status = DAT_RSP_CREATE(dapl_ia_handle, + conn_qual, + ep_handle, evd_handle, rsp_handle); + } + + return dat_status; +} + +DAT_RETURN DAT_API dat_rsp_query(IN DAT_RSP_HANDLE rsp_handle, + IN DAT_RSP_PARAM_MASK rsp_param_mask, + OUT DAT_RSP_PARAM * rsp_param) +{ + if (rsp_handle == NULL) { + return DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_RSP); + } + return DAT_RSP_QUERY(rsp_handle, rsp_param_mask, rsp_param); +} + +DAT_RETURN DAT_API dat_rsp_free(IN DAT_RSP_HANDLE rsp_handle) +{ + if (rsp_handle == NULL) { + return DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_RSP); + } + return DAT_RSP_FREE(rsp_handle); +} + +DAT_RETURN DAT_API dat_pz_create(IN DAT_IA_HANDLE ia_handle, + OUT DAT_PZ_HANDLE * pz_handle) +{ + DAT_IA_HANDLE dapl_ia_handle; + DAT_RETURN dat_status; + + dat_status = dats_get_ia_handle(ia_handle, &dapl_ia_handle); + if (dat_status == DAT_SUCCESS) { + dat_status = DAT_PZ_CREATE(dapl_ia_handle, pz_handle); + } + + return dat_status; +} + +DAT_RETURN DAT_API dat_pz_query(IN DAT_PZ_HANDLE pz_handle, + IN DAT_PZ_PARAM_MASK pz_param_mask, + OUT DAT_PZ_PARAM * pz_param) +{ + if (pz_handle == NULL) { + return DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_PZ); + } + return DAT_PZ_QUERY(pz_handle, pz_param_mask, pz_param); +} + +DAT_RETURN DAT_API dat_pz_free(IN DAT_PZ_HANDLE pz_handle) +{ + if (pz_handle == NULL) { + return DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_PZ); + } + return DAT_PZ_FREE(pz_handle); +} + +DAT_RETURN DAT_API dat_ep_create_with_srq(IN DAT_IA_HANDLE ia_handle, + IN DAT_PZ_HANDLE pz_handle, + IN DAT_EVD_HANDLE recv_evd_handle, + IN DAT_EVD_HANDLE request_evd_handle, + IN DAT_EVD_HANDLE connect_evd_handle, + IN DAT_SRQ_HANDLE srq_handle, + IN const DAT_EP_ATTR * ep_attributes, + OUT DAT_EP_HANDLE * ep_handle) +{ + DAT_IA_HANDLE dapl_ia_handle; + DAT_RETURN dat_status; + + dat_status = dats_get_ia_handle(ia_handle, &dapl_ia_handle); + if (dat_status == DAT_SUCCESS) { + dat_status = DAT_EP_CREATE_WITH_SRQ(dapl_ia_handle, + pz_handle, + recv_evd_handle, + request_evd_handle, + connect_evd_handle, + srq_handle, + ep_attributes, ep_handle); + } + + return dat_status; +} + +DAT_RETURN DAT_API dat_ep_recv_query(IN DAT_EP_HANDLE ep_handle, + OUT DAT_COUNT * nbufs_allocated, + OUT DAT_COUNT * bufs_alloc_span) +{ + if (ep_handle == NULL) { + return DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP); + } + return DAT_EP_RECV_QUERY(ep_handle, nbufs_allocated, bufs_alloc_span); +} + +DAT_RETURN DAT_API dat_ep_set_watermark(IN DAT_EP_HANDLE ep_handle, + IN DAT_COUNT soft_high_watermark, + IN DAT_COUNT hard_high_watermark) +{ + if (ep_handle == NULL) { + return DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP); + } + return DAT_EP_SET_WATERMARK(ep_handle, + soft_high_watermark, hard_high_watermark); +} + +/* SRQ functions */ + +DAT_RETURN DAT_API dat_srq_create(IN DAT_IA_HANDLE ia_handle, + IN DAT_PZ_HANDLE pz_handle, + IN DAT_SRQ_ATTR * srq_attr, + OUT DAT_SRQ_HANDLE * srq_handle) +{ + DAT_IA_HANDLE dapl_ia_handle; + DAT_RETURN dat_status; + + dat_status = dats_get_ia_handle(ia_handle, &dapl_ia_handle); + if (dat_status == DAT_SUCCESS) { + dat_status = DAT_SRQ_CREATE(dapl_ia_handle, + pz_handle, srq_attr, srq_handle); + } + + return dat_status; +} + +DAT_RETURN DAT_API dat_srq_free(IN DAT_SRQ_HANDLE srq_handle) +{ + return DAT_SRQ_FREE(srq_handle); +} + +DAT_RETURN DAT_API dat_srq_post_recv(IN DAT_SRQ_HANDLE srq_handle, + IN DAT_COUNT num_segments, + IN DAT_LMR_TRIPLET * local_iov, + IN DAT_DTO_COOKIE user_cookie) +{ + if (srq_handle == NULL) { + return DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_SRQ); + } + return DAT_SRQ_POST_RECV(srq_handle, + num_segments, local_iov, user_cookie); +} + +DAT_RETURN DAT_API dat_srq_query(IN DAT_SRQ_HANDLE srq_handle, + IN DAT_SRQ_PARAM_MASK srq_param_mask, + OUT DAT_SRQ_PARAM * srq_param) +{ + if (srq_handle == NULL) { + return DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_SRQ); + } + return DAT_SRQ_QUERY(srq_handle, srq_param_mask, srq_param); +} + +DAT_RETURN DAT_API dat_srq_resize(IN DAT_SRQ_HANDLE srq_handle, + IN DAT_COUNT srq_max_recv_dto) +{ + if (srq_handle == NULL) { + return DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_SRQ); + } + return DAT_SRQ_RESIZE(srq_handle, srq_max_recv_dto); +} + +DAT_RETURN DAT_API dat_srq_set_lw(IN DAT_SRQ_HANDLE srq_handle, + IN DAT_COUNT low_watermark) +{ + if (srq_handle == NULL) { + return DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_SRQ); + } + return DAT_SRQ_SET_LW(srq_handle, low_watermark); +} + +#ifdef DAT_EXTENSIONS + +extern int g_dat_extensions; + +DAT_RETURN DAT_API dat_extension_op(IN DAT_HANDLE handle, + IN DAT_EXTENDED_OP ext_op, IN ...) +{ + DAT_RETURN status; + DAT_IA_HANDLE dapl_handle; + va_list args; + + /* If not IA handle then just passthrough */ + if (dats_get_ia_handle(handle, &dapl_handle) != DAT_SUCCESS) { + dapl_handle = handle; + } + + /* verify provider extension support */ + if (!g_dat_extensions) { + return DAT_ERROR(DAT_NOT_IMPLEMENTED, 0); + } + + /* extension will validate the handle based on op */ + va_start(args, ext_op); + status = DAT_HANDLE_EXTENDEDOP(dapl_handle, ext_op, args); + va_end(args); + + return status; +} +#endif + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dat/common/dat_dictionary.c b/branches/WOF2-3/ulp/dapl2/dat/common/dat_dictionary.c new file mode 100644 index 00000000..6716ff63 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dat/common/dat_dictionary.c @@ -0,0 +1,420 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dat_dictionary.c + * + * PURPOSE: dictionary data structure + * + * $Id: dat_dictionary.c,v 1.17 2005/05/20 22:24:01 jlentini Exp $ + **********************************************************************/ + +#include "dat_dictionary.h" + +/********************************************************************* + * * + * Structures * + * * + *********************************************************************/ + +typedef struct DAT_DICTIONARY_NODE { + DAT_PROVIDER_INFO key; + DAT_DICTIONARY_DATA data; + struct DAT_DICTIONARY_NODE *prev; + struct DAT_DICTIONARY_NODE *next; +} DAT_DICTIONARY_NODE; + +struct DAT_DICTIONARY { + DAT_DICTIONARY_NODE *head; + DAT_DICTIONARY_NODE *tail; + DAT_COUNT size; +}; + +/********************************************************************* + * * + * Function Declarations * + * * + *********************************************************************/ + +static DAT_RETURN +dat_dictionary_key_dup(const DAT_PROVIDER_INFO * old_key, + DAT_PROVIDER_INFO * new_key); + +static DAT_BOOLEAN +dat_dictionary_key_is_equal(const DAT_PROVIDER_INFO * key_a, + const DAT_PROVIDER_INFO * key_b); + +/********************************************************************* + * * + * External Functions * + * * + *********************************************************************/ + +/*********************************************************************** + * Function: dat_dictionary_create + ***********************************************************************/ + +DAT_RETURN dat_dictionary_create(OUT DAT_DICTIONARY ** pp_dictionary) +{ + DAT_DICTIONARY *p_dictionary; + DAT_RETURN status; + + dat_os_assert(NULL != pp_dictionary); + + status = DAT_SUCCESS; + + /* create the dictionary */ + p_dictionary = dat_os_alloc(sizeof(DAT_DICTIONARY)); + if (NULL == p_dictionary) { + status = + DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); + goto bail; + } + + dat_os_memset(p_dictionary, '\0', sizeof(DAT_DICTIONARY)); + + /* create the head node */ + p_dictionary->head = dat_os_alloc(sizeof(DAT_DICTIONARY_NODE)); + if (NULL == p_dictionary->head) { + status = + DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); + goto bail; + } + + dat_os_memset(p_dictionary->head, '\0', sizeof(DAT_DICTIONARY_NODE)); + + /* create the tail node */ + p_dictionary->tail = dat_os_alloc(sizeof(DAT_DICTIONARY_NODE)); + if (NULL == p_dictionary->tail) { + status = + DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); + goto bail; + } + + dat_os_memset(p_dictionary->tail, '\0', sizeof(DAT_DICTIONARY_NODE)); + + p_dictionary->head->next = p_dictionary->tail; + p_dictionary->tail->prev = p_dictionary->head; + + *pp_dictionary = p_dictionary; + + bail: + if (DAT_SUCCESS != status) { + if (NULL != p_dictionary) { + if (NULL != p_dictionary->head) { + dat_os_free(p_dictionary->head, + sizeof(DAT_DICTIONARY_NODE)); + } + + if (NULL != p_dictionary->tail) { + dat_os_free(p_dictionary->tail, + sizeof(DAT_DICTIONARY_NODE)); + } + + dat_os_free(p_dictionary, sizeof(DAT_DICTIONARY)); + } + } + + return status; +} + +/*********************************************************************** + * Function: dat_dictionary_destroy + ***********************************************************************/ + +DAT_RETURN dat_dictionary_destroy(IN DAT_DICTIONARY * p_dictionary) +{ + DAT_DICTIONARY_NODE *cur_node; + + dat_os_assert(NULL != p_dictionary); + + while (NULL != p_dictionary->head) { + cur_node = p_dictionary->head; + p_dictionary->head = cur_node->next; + + dat_os_free(cur_node, sizeof(DAT_DICTIONARY_NODE)); + } + + dat_os_free(p_dictionary, sizeof(DAT_DICTIONARY)); + + return DAT_SUCCESS; +} + +/*********************************************************************** + * Function: dat_dictionary_size + ***********************************************************************/ + +DAT_RETURN +dat_dictionary_size(IN DAT_DICTIONARY * p_dictionary, OUT DAT_COUNT * p_size) +{ + dat_os_assert(NULL != p_dictionary); + dat_os_assert(NULL != p_size); + + *p_size = p_dictionary->size; + + return DAT_SUCCESS; +} + +/*********************************************************************** + * Function: dat_dictionary_entry_create + ***********************************************************************/ + +DAT_RETURN dat_dictionary_entry_create(OUT DAT_DICTIONARY_ENTRY * p_entry) +{ + DAT_DICTIONARY_NODE *node; + DAT_RETURN dat_status; + + dat_os_assert(NULL != p_entry); + + dat_status = DAT_SUCCESS; + + node = dat_os_alloc(sizeof(DAT_DICTIONARY_NODE)); + if (NULL == node) { + dat_status = + DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); + goto bail; + } + + *p_entry = node; + + bail: + return dat_status; +} + +/*********************************************************************** + * Function: dat_dictionary_entry_destroy + ***********************************************************************/ + +DAT_RETURN dat_dictionary_entry_destroy(OUT DAT_DICTIONARY_ENTRY entry) +{ + dat_os_free(entry, sizeof(DAT_DICTIONARY_NODE)); + return DAT_SUCCESS; +} + +/*********************************************************************** + * Function: dat_dictionary_insert + ***********************************************************************/ + +DAT_RETURN +dat_dictionary_insert(IN DAT_DICTIONARY * p_dictionary, + IN DAT_DICTIONARY_ENTRY entry, + IN const DAT_PROVIDER_INFO * key, + IN DAT_DICTIONARY_DATA data) +{ + DAT_RETURN dat_status; + DAT_DICTIONARY_NODE *cur_node, *prev_node, *next_node; + + dat_os_assert(NULL != p_dictionary); + dat_os_assert(NULL != entry); + + cur_node = entry; + + if (DAT_SUCCESS == dat_dictionary_search(p_dictionary, key, NULL)) { + dat_status = DAT_ERROR(DAT_PROVIDER_ALREADY_REGISTERED, 0); + goto bail; + } + + dat_status = dat_dictionary_key_dup(key, &cur_node->key); + if (DAT_SUCCESS != dat_status) { + goto bail; + } + + /* insert node at end of list to preserve registration order */ + prev_node = p_dictionary->tail->prev; + next_node = p_dictionary->tail; + + cur_node->data = data; + cur_node->next = next_node; + cur_node->prev = prev_node; + + prev_node->next = cur_node; + next_node->prev = cur_node; + + p_dictionary->size++; + + bail: + return dat_status; +} + +/*********************************************************************** + * Function: dat_dictionary_search + ***********************************************************************/ + +DAT_RETURN +dat_dictionary_search(IN DAT_DICTIONARY * p_dictionary, + IN const DAT_PROVIDER_INFO * key, + OUT DAT_DICTIONARY_DATA * p_data) +{ + DAT_DICTIONARY_NODE *cur_node; + DAT_RETURN status; + + dat_os_assert(NULL != p_dictionary); + + status = DAT_ERROR(DAT_PROVIDER_NOT_FOUND, DAT_NAME_NOT_REGISTERED); + + for (cur_node = p_dictionary->head->next; + p_dictionary->tail != cur_node; cur_node = cur_node->next) { + if (DAT_TRUE == + dat_dictionary_key_is_equal(&cur_node->key, key)) { + if (NULL != p_data) { + *p_data = cur_node->data; + } + + status = DAT_SUCCESS; + goto bail; + } + } + + bail: + return status; +} + +/*********************************************************************** + * Function: dat_dictionary_enumerate + ***********************************************************************/ + +DAT_RETURN +dat_dictionary_enumerate(IN DAT_DICTIONARY * p_dictionary, + IN DAT_DICTIONARY_DATA array[], + IN DAT_COUNT array_size) +{ + DAT_DICTIONARY_NODE *cur_node; + DAT_COUNT i; + DAT_RETURN status; + + dat_os_assert(NULL != p_dictionary); + dat_os_assert(NULL != array); + + status = DAT_SUCCESS; + + if (array_size < p_dictionary->size) { + status = DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, 0); + goto bail; + } + + for (cur_node = p_dictionary->head->next, i = 0; + p_dictionary->tail != cur_node; cur_node = cur_node->next, i++) { + array[i] = cur_node->data; + } + + bail: + return status; +} + +/*********************************************************************** + * Function: dat_dictionary_remove + ***********************************************************************/ + +DAT_RETURN +dat_dictionary_remove(IN DAT_DICTIONARY * p_dictionary, + IN DAT_DICTIONARY_ENTRY * p_entry, + IN const DAT_PROVIDER_INFO * key, + OUT DAT_DICTIONARY_DATA * p_data) +{ + DAT_DICTIONARY_NODE *cur_node, *prev_node, *next_node; + DAT_RETURN status; + + dat_os_assert(NULL != p_dictionary); + dat_os_assert(NULL != p_entry); + + status = DAT_ERROR(DAT_PROVIDER_NOT_FOUND, DAT_NAME_NOT_REGISTERED); + + for (cur_node = p_dictionary->head->next; + p_dictionary->tail != cur_node; cur_node = cur_node->next) { + if (DAT_TRUE == + dat_dictionary_key_is_equal(&cur_node->key, key)) { + if (NULL != p_data) { + *p_data = cur_node->data; + } + + prev_node = cur_node->prev; + next_node = cur_node->next; + + prev_node->next = next_node; + next_node->prev = prev_node; + + *p_entry = cur_node; + + p_dictionary->size--; + + status = DAT_SUCCESS; + goto bail; + } + } + + bail: + return status; +} + +/********************************************************************* + * * + * Internal Function Definitions * + * * + *********************************************************************/ + +/*********************************************************************** + * Function: dat_dictionary_key_create + ***********************************************************************/ + +DAT_RETURN +dat_dictionary_key_dup(const DAT_PROVIDER_INFO * old_key, + DAT_PROVIDER_INFO * new_key) +{ + dat_os_assert(NULL != old_key); + dat_os_assert(NULL != new_key); + + dat_os_strncpy(new_key->ia_name, old_key->ia_name, DAT_NAME_MAX_LENGTH); + new_key->dapl_version_major = old_key->dapl_version_major; + new_key->dapl_version_minor = old_key->dapl_version_minor; + new_key->is_thread_safe = old_key->is_thread_safe; + + return DAT_SUCCESS; +} + +/*********************************************************************** + * Function: dat_dictionary_key_is_equal + ***********************************************************************/ + +DAT_BOOLEAN +dat_dictionary_key_is_equal(const DAT_PROVIDER_INFO * key_a, + const DAT_PROVIDER_INFO * key_b) +{ + if ((dat_os_strlen(key_a->ia_name) == dat_os_strlen(key_b->ia_name)) && + (!dat_os_strncmp + (key_a->ia_name, key_b->ia_name, dat_os_strlen(key_a->ia_name))) + && (key_a->dapl_version_major == key_b->dapl_version_major) + && (key_a->dapl_version_minor == key_b->dapl_version_minor) + && (key_a->is_thread_safe == key_b->is_thread_safe)) { + return DAT_TRUE; + } else { + return DAT_FALSE; + } +} diff --git a/branches/WOF2-3/ulp/dapl2/dat/common/dat_dictionary.h b/branches/WOF2-3/ulp/dapl2/dat/common/dat_dictionary.h new file mode 100644 index 00000000..b496266d --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dat/common/dat_dictionary.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dat_dictionary.h + * + * PURPOSE: dictionary data structure + * + * $Id: dat_dictionary.h,v 1.10 2005/03/24 05:58:27 jlentini Exp $ + **********************************************************************/ + +#ifndef _DAT_DICTIONARY_H_ +#define _DAT_DICTIONARY_H_ + + +#include "dat_osd.h" + + +/********************************************************************* + * * + * Typedefs * + * * + *********************************************************************/ + +typedef struct DAT_DICTIONARY DAT_DICTIONARY; +typedef void * DAT_DICTIONARY_DATA; +typedef void * DAT_DICTIONARY_ENTRY; + + +/********************************************************************* + * * + * Function Prototypes * + * * + *********************************************************************/ + +extern DAT_RETURN +dat_dictionary_create ( + OUT DAT_DICTIONARY **pp_dictionary); + +extern DAT_RETURN +dat_dictionary_destroy ( + IN DAT_DICTIONARY *p_dictionary); + +extern DAT_RETURN +dat_dictionary_size ( + IN DAT_DICTIONARY *p_dictionary, + OUT DAT_COUNT *p_size); + +extern DAT_RETURN +dat_dictionary_entry_create ( + OUT DAT_DICTIONARY_ENTRY *p_entry); + +extern DAT_RETURN +dat_dictionary_entry_destroy ( + IN DAT_DICTIONARY_ENTRY entry); + +extern DAT_RETURN +dat_dictionary_insert ( + IN DAT_DICTIONARY *p_dictionary, + IN DAT_DICTIONARY_ENTRY entry, + IN const DAT_PROVIDER_INFO *key, + IN DAT_DICTIONARY_DATA data); + +extern DAT_RETURN +dat_dictionary_search ( + IN DAT_DICTIONARY *p_dictionary, + IN const DAT_PROVIDER_INFO *key, + OUT DAT_DICTIONARY_DATA *p_data); + +extern DAT_RETURN +dat_dictionary_enumerate ( + IN DAT_DICTIONARY *p_dictionary, + IN DAT_DICTIONARY_DATA array[], + IN DAT_COUNT array_size); + + +extern DAT_RETURN +dat_dictionary_remove ( + IN DAT_DICTIONARY *p_dictionary, + IN DAT_DICTIONARY_ENTRY *p_entry, + IN const DAT_PROVIDER_INFO *key, + OUT DAT_DICTIONARY_DATA *p_data); + +#endif diff --git a/branches/WOF2-3/ulp/dapl2/dat/common/dat_dr.c b/branches/WOF2-3/ulp/dapl2/dat/common/dat_dr.c new file mode 100644 index 00000000..0460e814 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dat/common/dat_dr.c @@ -0,0 +1,327 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dat_dr.c + * + * PURPOSE: dynamic registry implementation + * + * $Id: dat_dr.c,v 1.17 2005/03/24 05:58:27 jlentini Exp $ + **********************************************************************/ + +#include +#include "dat_dr.h" +#include "dat_dictionary.h" + +/********************************************************************* + * * + * Global Variables * + * * + *********************************************************************/ + +static DAT_OS_LOCK g_dr_lock; +static DAT_DICTIONARY *g_dr_dictionary = NULL; + +/********************************************************************* + * * + * External Functions * + * * + *********************************************************************/ + +//*********************************************************************** +// Function: dat_dr_init +//*********************************************************************** + +DAT_RETURN dat_dr_init(void) +{ + DAT_RETURN status; + + status = dat_os_lock_init(&g_dr_lock); + if (DAT_SUCCESS != status) { + return status; + } + + status = dat_dictionary_create(&g_dr_dictionary); + if (DAT_SUCCESS != status) { + return status; + } + + return DAT_SUCCESS; +} + +//*********************************************************************** +// Function: dat_dr_fini +//*********************************************************************** + +DAT_RETURN dat_dr_fini(void) +{ + DAT_RETURN status; + + status = dat_os_lock_destroy(&g_dr_lock); + if (DAT_SUCCESS != status) { + return status; + } + + status = dat_dictionary_destroy(g_dr_dictionary); + if (DAT_SUCCESS != status) { + return status; + } + + return DAT_SUCCESS; +} + +//*********************************************************************** +// Function: dat_dr_insert +//*********************************************************************** + +DAT_RETURN +dat_dr_insert(IN const DAT_PROVIDER_INFO * info, IN DAT_DR_ENTRY * entry) +{ + DAT_RETURN status; + DAT_DICTIONARY_ENTRY dict_entry = NULL; + DAT_DR_ENTRY *data; + + data = dat_os_alloc(sizeof(DAT_DR_ENTRY)); + if (NULL == data) { + status = + DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); + goto bail; + } + + *data = *entry; + + status = dat_dictionary_entry_create(&dict_entry); + if (DAT_SUCCESS != status) { + goto bail; + } + + dat_os_lock(&g_dr_lock); + + status = dat_dictionary_insert(g_dr_dictionary, + dict_entry, + info, (DAT_DICTIONARY_DATA *) data); + + dat_os_unlock(&g_dr_lock); + + bail: + if (DAT_SUCCESS != status) { + if (NULL != data) { + dat_os_free(data, sizeof(DAT_DR_ENTRY)); + } + + if (NULL != dict_entry) { + (void)dat_dictionary_entry_destroy(dict_entry); + } + } + + return status; +} + +//*********************************************************************** +// Function: dat_dr_remove +//*********************************************************************** + +DAT_RETURN dat_dr_remove(IN const DAT_PROVIDER_INFO * info) +{ + DAT_DICTIONARY_ENTRY dict_entry; + DAT_RETURN status; + DAT_DICTIONARY_DATA data; + + dict_entry = NULL; + dat_os_lock(&g_dr_lock); + + status = dat_dictionary_search(g_dr_dictionary, info, &data); + + if (DAT_SUCCESS != status) { + /* return status from dat_dictionary_search() */ + goto bail; + } + + if (0 != ((DAT_DR_ENTRY *) data)->ref_count) { + status = DAT_ERROR(DAT_PROVIDER_IN_USE, 0); + goto bail; + } + + status = dat_dictionary_remove(g_dr_dictionary, + &dict_entry, info, &data); + if (DAT_SUCCESS != status) { + /* return status from dat_dictionary_remove() */ + goto bail; + } + + dat_os_free(data, sizeof(DAT_DR_ENTRY)); + + bail: + dat_os_unlock(&g_dr_lock); + + if (NULL != dict_entry) { + (void)dat_dictionary_entry_destroy(dict_entry); + } + + return status; +} + +//*********************************************************************** +// Function: dat_dr_provider_open +//*********************************************************************** + +DAT_RETURN +dat_dr_provider_open(IN const DAT_PROVIDER_INFO * info, + OUT DAT_IA_OPEN_FUNC * p_ia_open_func) +{ + DAT_RETURN status; + DAT_DICTIONARY_DATA data; + + dat_os_lock(&g_dr_lock); + status = dat_dictionary_search(g_dr_dictionary, info, &data); + dat_os_unlock(&g_dr_lock); + + if (DAT_SUCCESS == status) { + ((DAT_DR_ENTRY *) data)->ref_count++; + *p_ia_open_func = ((DAT_DR_ENTRY *) data)->ia_open_func; + } + + return status; +} + +//*********************************************************************** +// Function: dat_dr_provider_close +//*********************************************************************** + +DAT_RETURN dat_dr_provider_close(IN const DAT_PROVIDER_INFO * info) +{ + DAT_RETURN status; + DAT_DICTIONARY_DATA data; + + dat_os_lock(&g_dr_lock); + status = dat_dictionary_search(g_dr_dictionary, info, &data); + dat_os_unlock(&g_dr_lock); + + if (DAT_SUCCESS == status) { + ((DAT_DR_ENTRY *) data)->ref_count--; + } + + return status; +} + +//*********************************************************************** +// Function: dat_dr_size +//*********************************************************************** + +DAT_RETURN dat_dr_size(OUT DAT_COUNT * size) +{ + return dat_dictionary_size(g_dr_dictionary, size); +} + +//*********************************************************************** +// Function: dat_dr_list +//*********************************************************************** + +DAT_RETURN +dat_dr_list(IN DAT_COUNT max_to_return, + OUT DAT_COUNT * entries_returned, + OUT DAT_PROVIDER_INFO * (dat_provider_list[])) +{ + DAT_DR_ENTRY **array; + DAT_COUNT array_size; + DAT_COUNT i; + DAT_RETURN status; + + array = NULL; + status = DAT_SUCCESS; + + /* The dictionary size may increase between the call to */ + /* dat_dictionary_size() and dat_dictionary_enumerate(). */ + /* Therefore we loop until a successful enumeration is made. */ + *entries_returned = 0; + for (;;) { + status = dat_dictionary_size(g_dr_dictionary, &array_size); + if (status != DAT_SUCCESS) { + goto bail; + } + + if (array_size == 0) { + status = DAT_SUCCESS; + goto bail; + } + + array = dat_os_alloc(array_size * sizeof(DAT_DR_ENTRY *)); + if (array == NULL) { + status = + DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, + DAT_RESOURCE_MEMORY); + goto bail; + } + + dat_os_lock(&g_dr_lock); + + status = dat_dictionary_enumerate(g_dr_dictionary, + (DAT_DICTIONARY_DATA *) array, + array_size); + + dat_os_unlock(&g_dr_lock); + + if (DAT_SUCCESS == status) { + break; + } else { + dat_os_free(array, array_size * sizeof(DAT_DR_ENTRY *)); + array = NULL; + continue; + } + } + + for (i = 0; (i < max_to_return) && (i < array_size); i++) { + if (NULL == dat_provider_list[i]) { + status = + DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG3); + goto bail; + } + + *dat_provider_list[i] = array[i]->info; + } + + *entries_returned = i; + + bail: + if (NULL != array) { + dat_os_free(array, array_size * sizeof(DAT_DR_ENTRY *)); + } + + return status; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dat/common/dat_dr.h b/branches/WOF2-3/ulp/dapl2/dat/common/dat_dr.h new file mode 100644 index 00000000..30122525 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dat/common/dat_dr.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dat_dr.h + * + * PURPOSE: dynamic registry interface declarations + * + * $Id: dat_dr.h,v 1.12 2005/03/24 05:58:27 jlentini Exp $ + **********************************************************************/ + +#ifndef __DAT_DR_H__ +#define __DAT_DR_H__ + + +#include "dat_osd.h" +#include /* Provider API function prototypes */ + + +/********************************************************************* + * * + * Strucutres * + * * + *********************************************************************/ + +typedef struct +{ + DAT_COUNT ref_count; + DAT_IA_OPEN_FUNC ia_open_func; + DAT_PROVIDER_INFO info; +} DAT_DR_ENTRY; + + +/********************************************************************* + * * + * Function Declarations * + * * + *********************************************************************/ + +extern DAT_RETURN +dat_dr_init ( void ); + +extern DAT_RETURN +dat_dr_fini ( void ); + +extern DAT_RETURN +dat_dr_insert ( + IN const DAT_PROVIDER_INFO *info, + IN DAT_DR_ENTRY *entry ); + +extern DAT_RETURN +dat_dr_remove ( + IN const DAT_PROVIDER_INFO *info ); + + +extern DAT_RETURN +dat_dr_provider_open ( + IN const DAT_PROVIDER_INFO *info, + OUT DAT_IA_OPEN_FUNC *p_ia_open_func ); + +extern DAT_RETURN +dat_dr_provider_close ( + IN const DAT_PROVIDER_INFO *info); + +extern DAT_RETURN +dat_dr_size ( + OUT DAT_COUNT *size); + +extern DAT_RETURN +dat_dr_list ( + IN DAT_COUNT max_to_return, + OUT DAT_COUNT *entries_returned, + OUT DAT_PROVIDER_INFO * (dat_provider_list[]) ); + +#endif diff --git a/branches/WOF2-3/ulp/dapl2/dat/common/dat_init.c b/branches/WOF2-3/ulp/dapl2/dat/common/dat_init.c new file mode 100644 index 00000000..71a56a08 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dat/common/dat_init.c @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dat_init.c + * + * PURPOSE: DAT registry implementation for uDAPL + * Description: init and fini functions for DAT module. + * + * $Id: dat_init.c,v 1.18 2005/03/24 05:58:27 jlentini Exp $ + **********************************************************************/ + +#include +#include "dat_init.h" +#include "dat_dr.h" +#include "dat_osd.h" + +#ifndef DAT_NO_STATIC_REGISTRY +#include "dat_sr.h" +#endif + +/********************************************************************* + * * + * Global Variables * + * * + *********************************************************************/ + +/* + * Ideally, the following two rules could be enforced: + * + * - The DAT Registry's initialization function is executed before that + * of any DAT Providers and hence all calls into the registry occur + * after the registry module is initialized. + * + * - The DAT Registry's deinitialization function is executed after that + * of any DAT Providers and hence all calls into the registry occur + * before the registry module is deinitialized. + * + * However, on many platforms few guarantees are provided regarding the + * order in which module initialization and deinitialization functions + * are invoked. + * + * To understand why these rules are difficult to enforce using only + * features common to all platforms, consider the Linux platform. The order + * in which Linux shared libraries are loaded into a process's address space + * is undefined. When a DAT consumer explicitly links to DAT provider + * libraries, the order in which library initialization and deinitialization + * functions are invoked becomes important. In this scenario, a DAPL provider + * may call dat_registry_add_provider() before the registry has been + * initialized. + * + * We assume that modules are loaded with a single thread. Given + * this assumption, we can use a simple state variable to determine + * the state of the DAT registry. + */ + +static DAT_MODULE_STATE g_module_state = DAT_MODULE_STATE_UNINITIALIZED; + +//*********************************************************************** +// Function: dat_module_get_state +//*********************************************************************** + +DAT_MODULE_STATE dat_module_get_state(void) +{ + return g_module_state; +} + +//*********************************************************************** +// Function: dat_init +//*********************************************************************** + +void dat_init(void) +{ + if (DAT_MODULE_STATE_UNINITIALIZED == g_module_state) { + /* + * update the module state flag immediately in case there + * is a recursive call to dat_init(). + */ + g_module_state = DAT_MODULE_STATE_INITIALIZING; + + dat_os_dbg_init(); + + dats_handle_vector_init(); + + dat_os_dbg_print(DAT_OS_DBG_TYPE_GENERIC, + "DAT Registry: Started (dat_init)\n"); + +#ifndef DAT_NO_STATIC_REGISTRY + dat_sr_init(); +#endif + dat_dr_init(); + + g_module_state = DAT_MODULE_STATE_INITIALIZED; + } +} + +//*********************************************************************** +// Function: dat_fini +//*********************************************************************** + +void dat_fini(void) +{ + if (DAT_MODULE_STATE_INITIALIZED == g_module_state) { + g_module_state = DAT_MODULE_STATE_DEINITIALIZING; + + dat_dr_fini(); +#ifndef DAT_NO_STATIC_REGISTRY + dat_sr_fini(); +#endif + + dat_os_dbg_print(DAT_OS_DBG_TYPE_GENERIC, + "DAT Registry: Stopped (dat_fini)\n"); + + g_module_state = DAT_MODULE_STATE_DEINITIALIZED; + } +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dat/common/dat_init.h b/branches/WOF2-3/ulp/dapl2/dat/common/dat_init.h new file mode 100644 index 00000000..4596b017 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dat/common/dat_init.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dat_init.h + * + * PURPOSE: DAT registry global data + * + * $Id: dat_init.h,v 1.16 2005/03/24 05:58:27 jlentini Exp $ + **********************************************************************/ + +#ifndef _DAT_INIT_H_ +#define _DAT_INIT_H_ + +#include "dat_osd.h" + +/********************************************************************* + * * + * Enumerations * + * * + *********************************************************************/ + +typedef enum +{ + DAT_MODULE_STATE_UNINITIALIZED, + DAT_MODULE_STATE_INITIALIZING, + DAT_MODULE_STATE_INITIALIZED, + DAT_MODULE_STATE_DEINITIALIZING, + DAT_MODULE_STATE_DEINITIALIZED +} DAT_MODULE_STATE; + +/********************************************************************* + * * + * Function Prototypes * + * * + *********************************************************************/ + +DAT_MODULE_STATE +dat_module_get_state ( void ) ; + +#if defined(_MSC_VER) || defined(_WIN64) || defined(_WIN32) +/* NT. MSC compiler, Win32/64 platform */ +void +dat_init ( void ); + +void +dat_fini ( void ); + +#else /* GNU C */ + +void +dat_init ( void ) __attribute__ ((constructor)); + +void +dat_fini ( void ) __attribute__ ((destructor)); +#endif + +extern DAT_RETURN +dats_handle_vector_init ( void ); + +extern DAT_IA_HANDLE +dats_set_ia_handle ( + IN DAT_IA_HANDLE ia_handle); + +extern DAT_RETURN +dats_get_ia_handle( + IN DAT_IA_HANDLE handle, + OUT DAT_IA_HANDLE *ia_handle_p); + +extern DAT_BOOLEAN +dats_is_ia_handle ( + IN DAT_HANDLE dat_handle); + +extern DAT_RETURN +dats_free_ia_handle( + IN DAT_IA_HANDLE handle); + +#endif diff --git a/branches/WOF2-3/ulp/dapl2/dat/common/dat_sr.c b/branches/WOF2-3/ulp/dapl2/dat/common/dat_sr.c new file mode 100644 index 00000000..95b9333a --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dat/common/dat_sr.c @@ -0,0 +1,447 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dat_sr.c + * + * PURPOSE: static registry implementation + * + * $Id: dat_sr.c,v 1.17 2005/03/24 05:58:27 jlentini Exp $ + **********************************************************************/ + +#include "dat_sr.h" + +#include "dat_dictionary.h" +#include "udat_sr_parser.h" + +/********************************************************************* + * * + * Global Variables * + * * + *********************************************************************/ + +static DAT_OS_LOCK g_sr_lock; +static DAT_DICTIONARY *g_sr_dictionary = NULL; + +/********************************************************************* + * * + * External Functions * + * * + *********************************************************************/ + +//*********************************************************************** +// Function: dat_sr_init +//*********************************************************************** + +DAT_RETURN dat_sr_init(void) +{ + DAT_RETURN status; + + status = dat_os_lock_init(&g_sr_lock); + if (DAT_SUCCESS != status) { + return status; + } + + status = dat_dictionary_create(&g_sr_dictionary); + if (DAT_SUCCESS != status) { + return status; + } + + /* + * Since DAT allows providers to be loaded by either the static + * registry or explicitly through OS dependent methods, do not + * return an error if no providers are loaded via the static registry. + */ + + (void)dat_sr_load(); + + return DAT_SUCCESS; +} + +//*********************************************************************** +// Function: dat_sr_fini +//*********************************************************************** + +extern DAT_RETURN dat_sr_fini(void) +{ + DAT_RETURN status; + + status = dat_os_lock_destroy(&g_sr_lock); + if (DAT_SUCCESS != status) { + return status; + } + + status = dat_dictionary_destroy(g_sr_dictionary); + if (DAT_SUCCESS != status) { + return status; + } + + return DAT_SUCCESS; +} + +//*********************************************************************** +// Function: dat_sr_insert +//*********************************************************************** + +extern DAT_RETURN +dat_sr_insert(IN const DAT_PROVIDER_INFO * info, IN DAT_SR_ENTRY * entry) +{ + DAT_RETURN status; + DAT_SR_ENTRY *data; + DAT_OS_SIZE lib_path_size; + DAT_OS_SIZE lib_path_len; + DAT_OS_SIZE ia_params_size; + DAT_OS_SIZE ia_params_len; + DAT_DICTIONARY_ENTRY dict_entry; + DAT_DICTIONARY_DATA prev_data; + + if (NULL == (data = dat_os_alloc(sizeof(DAT_SR_ENTRY)))) { + status = + DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); + goto bail; + } + + dat_os_memset(data, '\0', sizeof(DAT_SR_ENTRY)); + + lib_path_len = strlen(entry->lib_path); + lib_path_size = (lib_path_len + 1) * sizeof(char); + + if (NULL == (data->lib_path = dat_os_alloc(lib_path_size))) { + status = + DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); + goto bail; + } + + dat_os_strncpy(data->lib_path, entry->lib_path, lib_path_len); + data->lib_path[lib_path_len] = '\0'; + + ia_params_len = strlen(entry->ia_params); + ia_params_size = (ia_params_len + 1) * sizeof(char); + + if (NULL == (data->ia_params = dat_os_alloc(ia_params_size))) { + status = + DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); + goto bail; + } + + dat_os_strncpy(data->ia_params, entry->ia_params, ia_params_len); + data->ia_params[ia_params_len] = '\0'; + + data->info = entry->info; + data->lib_handle = entry->lib_handle; + data->ref_count = entry->ref_count; + data->next = NULL; + + dict_entry = NULL; + status = dat_dictionary_entry_create(&dict_entry); + if (DAT_SUCCESS != status) { + goto bail; + } + + dat_os_lock(&g_sr_lock); + + status = dat_dictionary_search(g_sr_dictionary, info, &prev_data); + if (DAT_SUCCESS == status) { + /* We already have a dictionary entry, so we don't need a new one. + * This means there are multiple duplicate names in dat.conf, + * but presumably they have different paths. Simply link the + * new entry at the end of the chain of like-named entries. + */ + (void)dat_dictionary_entry_destroy(dict_entry); + dict_entry = NULL; + + /* Find the next available slot in this chain */ + while (NULL != ((DAT_SR_ENTRY *) prev_data)->next) { + prev_data = ((DAT_SR_ENTRY *) prev_data)->next; + } + dat_os_assert(NULL != prev_data); + ((DAT_SR_ENTRY *) prev_data)->next = data; + } else { + status = dat_dictionary_insert(g_sr_dictionary, + dict_entry, + info, + (DAT_DICTIONARY_DATA *) data); + } + + dat_os_unlock(&g_sr_lock); + + bail: + if (DAT_SUCCESS != status) { + if (NULL != data) { + if (NULL != data->lib_path) { + dat_os_free(data->lib_path, lib_path_size); + } + + if (NULL != data->ia_params) { + dat_os_free(data->ia_params, ia_params_size); + } + + dat_os_free(data, sizeof(DAT_SR_ENTRY)); + } + + if (NULL != dict_entry) { + (void)dat_dictionary_entry_destroy(dict_entry); + } + } + + return status; +} + +//*********************************************************************** +// Function: dat_sr_size +//*********************************************************************** + +extern DAT_RETURN dat_sr_size(OUT DAT_COUNT * size) +{ + return dat_dictionary_size(g_sr_dictionary, size); +} + +//*********************************************************************** +// Function: dat_sr_list +//*********************************************************************** + +extern DAT_RETURN +dat_sr_list(IN DAT_COUNT max_to_return, + OUT DAT_COUNT * entries_returned, + OUT DAT_PROVIDER_INFO * (dat_provider_list[])) +{ + DAT_SR_ENTRY **array; + DAT_COUNT array_size; + DAT_COUNT i; + DAT_RETURN status; + + array = NULL; + status = DAT_SUCCESS; + + /* The dictionary size may increase between the call to */ + /* dat_dictionary_size() and dat_dictionary_enumerate(). */ + /* Therefore we loop until a successful enumeration is made. */ + *entries_returned = 0; + for (;;) { + status = dat_dictionary_size(g_sr_dictionary, &array_size); + if (DAT_SUCCESS != status) { + goto bail; + } + + if (array_size == 0) { + status = DAT_SUCCESS; + goto bail; + } + + array = dat_os_alloc(array_size * sizeof(DAT_SR_ENTRY *)); + if (array == NULL) { + status = + DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, + DAT_RESOURCE_MEMORY); + goto bail; + } + + dat_os_lock(&g_sr_lock); + + status = dat_dictionary_enumerate(g_sr_dictionary, + (DAT_DICTIONARY_DATA *) array, + array_size); + + dat_os_unlock(&g_sr_lock); + + if (DAT_SUCCESS == status) { + break; + } else { + dat_os_free(array, array_size * sizeof(DAT_SR_ENTRY *)); + array = NULL; + continue; + } + } + + for (i = 0; (i < max_to_return) && (i < array_size); i++) { + if (NULL == dat_provider_list[i]) { + status = + DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG3); + goto bail; + } + + *dat_provider_list[i] = array[i]->info; + } + + *entries_returned = i; + + bail: + if (NULL != array) { + dat_os_free(array, array_size * sizeof(DAT_SR_ENTRY *)); + } + + return status; +} + +//*********************************************************************** +// Function: dat_sr_provider_open +//*********************************************************************** + +extern DAT_RETURN dat_sr_provider_open(IN const DAT_PROVIDER_INFO * info) +{ + DAT_RETURN status; + DAT_SR_ENTRY *data; + DAT_DICTIONARY_DATA dict_data; + + dat_os_lock(&g_sr_lock); + + status = dat_dictionary_search(g_sr_dictionary, info, &dict_data); + + if (DAT_SUCCESS == status) { + data = (DAT_SR_ENTRY *) dict_data; + while (data != NULL) { + if (0 == data->ref_count) { + /* + * Try to open the path. If it fails, try the next + * path in the chain. Only the first successful library + * open matters, the others will be unused. + */ + dat_os_dbg_print(DAT_OS_DBG_TYPE_SR, + "DAT Registry: IA %s, trying to load library %s\n", + data->info.ia_name, + data->lib_path); + + status = dat_os_library_load(data->lib_path, + &data->lib_handle); + + if (status == DAT_SUCCESS) { +#ifdef DAT_DBG + dat_os_dbg_print(DAT_OS_DBG_TYPE_SR, + "DAT2 Registry: IA %s, loaded library %s\n", + data->info.ia_name, + data->lib_path); +#endif + data->ref_count++; + data->init_func = + dat_os_library_sym(data->lib_handle, + DAT_PROVIDER_INIT_FUNC_STR); + data->fini_func = + dat_os_library_sym(data->lib_handle, + DAT_PROVIDER_FINI_FUNC_STR); + /* Warning: DAT and DAPL libraries not ext compatible */ +#ifdef DAT_EXTENSIONS + { + void *fncptr; + + fncptr = + dat_os_library_sym(data-> + lib_handle, + "dapl_extensions"); + + if ((dat_os_library_error() != + NULL) + || (fncptr == NULL)) { + dat_os_dbg_print + (DAT_OS_DBG_TYPE_SR, + "DAT Registry: WARNING: library %s, " + "extended DAT expected extended uDAPL: %s\n", + data->lib_path, + strerror(errno)); + } + } +#endif + if (NULL != data->init_func) { + (*data->init_func) (&data->info, + data-> + ia_params); + } else { + dat_os_dbg_print + (DAT_OS_DBG_TYPE_SR, + "DAT Registry: Cannot find library init func (%s)\n", + DAT_PROVIDER_INIT_FUNC_STR); + } + + /* exit after we find the first valid entry */ + break; + } else { + dat_os_dbg_print(DAT_OS_DBG_TYPE_SR, + "DAT Registry: static registry unable to " + "load library %s\n", + data->lib_path); + } + } else { + data->ref_count++; + break; + } + data = data->next; + } + } + + dat_os_unlock(&g_sr_lock); + + return status; +} + +//*********************************************************************** +// Function: dat_sr_provider_close +//*********************************************************************** + +extern DAT_RETURN dat_sr_provider_close(IN const DAT_PROVIDER_INFO * info) +{ + DAT_RETURN status; + DAT_SR_ENTRY *data; + DAT_DICTIONARY_DATA dict_data; + + dat_os_lock(&g_sr_lock); + + status = dat_dictionary_search(g_sr_dictionary, info, &dict_data); + + if (DAT_SUCCESS == status) { + data = (DAT_SR_ENTRY *) dict_data; + while (data != NULL) { + if (1 == data->ref_count) { + dat_os_dbg_print(DAT_OS_DBG_TYPE_SR, + "DAT Registry: IA %s, unloading library %s\n", + data->info.ia_name, + data->lib_path); + + if (NULL != data->fini_func) { + (*data->fini_func) (&data->info); + } + + status = + dat_os_library_unload(data->lib_handle); + if (status == DAT_SUCCESS) { + data->ref_count--; + } + break; + } else if (data->ref_count > 0) { + data->ref_count--; + break; + } + data = data->next; + } + } + + dat_os_unlock(&g_sr_lock); + + return status; +} diff --git a/branches/WOF2-3/ulp/dapl2/dat/common/dat_sr.h b/branches/WOF2-3/ulp/dapl2/dat/common/dat_sr.h new file mode 100644 index 00000000..86be8a08 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dat/common/dat_sr.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dat_sr.h + * + * PURPOSE: static registry (SR) inteface declarations + * + * $Id: dat_sr.h,v 1.12 2005/03/24 05:58:28 jlentini Exp $ + **********************************************************************/ + +#ifndef _DAT_SR_H_ +#define _DAT_SR_H_ + + +#include +#include + +#include "dat_osd.h" + +/********************************************************************* + * * + * Strucutres * + * * + *********************************************************************/ + +typedef struct DAT_SR_ENTRY +{ + DAT_PROVIDER_INFO info; + char * lib_path; + char * ia_params; + DAT_OS_LIBRARY_HANDLE lib_handle; + DAT_PROVIDER_INIT_FUNC init_func; + DAT_PROVIDER_FINI_FUNC fini_func; + DAT_COUNT ref_count; + struct DAT_SR_ENTRY *next; +} DAT_SR_ENTRY; + + +/********************************************************************* + * * + * Function Declarations * + * * + *********************************************************************/ + +extern DAT_RETURN +dat_sr_init ( void ); + +extern DAT_RETURN +dat_sr_fini ( void ); + +extern DAT_RETURN +dat_sr_insert ( + IN const DAT_PROVIDER_INFO *info, + IN DAT_SR_ENTRY *entry ); + +extern DAT_RETURN +dat_sr_size ( + OUT DAT_COUNT *size); + +extern DAT_RETURN +dat_sr_list ( + IN DAT_COUNT max_to_return, + OUT DAT_COUNT *entries_returned, + OUT DAT_PROVIDER_INFO * (dat_provider_list[]) ); + +extern DAT_RETURN +dat_sr_provider_open ( + IN const DAT_PROVIDER_INFO *info ); + +extern DAT_RETURN +dat_sr_provider_close ( + IN const DAT_PROVIDER_INFO *info ); + + +#endif diff --git a/branches/WOF2-3/ulp/dapl2/dat/common/dat_strerror.c b/branches/WOF2-3/ulp/dapl2/dat/common/dat_strerror.c new file mode 100644 index 00000000..4480bef5 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dat/common/dat_strerror.c @@ -0,0 +1,611 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dat_strerror.c + * + * PURPOSE: Convert DAT_RETURN values to humman readable string + * + * $Id: dat_strerror.c,v 1.10 2005/03/24 05:58:28 jlentini Exp $ + **********************************************************************/ + +#ifdef __KDAPL__ +#include +#else /*__UDAPL__*/ +#include +#endif /* __UDAPL__ */ + +/********************************************************************* + * * + * Internal Function Declarations * + * * + *********************************************************************/ + +static DAT_RETURN +dat_strerror_major(IN DAT_RETURN value, OUT const char **message); + +static DAT_RETURN +dat_strerror_minor(IN DAT_RETURN value, OUT const char **message); + +/********************************************************************* + * * + * Internal Function Definitions * + * * + *********************************************************************/ + +static DAT_RETURN +dat_strerror_major(IN DAT_RETURN value, OUT const char **message) +{ + switch (DAT_GET_TYPE(value)) { + case DAT_SUCCESS: + { + *message = "DAT_SUCCESS"; + return DAT_SUCCESS; + } + case DAT_ABORT: + { + *message = "DAT_ABORT"; + return DAT_SUCCESS; + } + case DAT_CONN_QUAL_IN_USE: + { + *message = "DAT_CONN_QUAL_IN_USE"; + return DAT_SUCCESS; + } + case DAT_INSUFFICIENT_RESOURCES: + { + *message = "DAT_INSUFFICIENT_RESOURCES"; + return DAT_SUCCESS; + } + case DAT_INTERNAL_ERROR: + { + *message = "DAT_INTERNAL_ERROR"; + return DAT_SUCCESS; + } + case DAT_INVALID_HANDLE: + { + *message = "DAT_INVALID_HANDLE"; + return DAT_SUCCESS; + } + case DAT_INVALID_PARAMETER: + { + *message = "DAT_INVALID_PARAMETER"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE: + { + *message = "DAT_INVALID_STATE"; + return DAT_SUCCESS; + } + case DAT_LENGTH_ERROR: + { + *message = "DAT_LENGTH_ERROR"; + return DAT_SUCCESS; + } + case DAT_MODEL_NOT_SUPPORTED: + { + *message = "DAT_MODEL_NOT_SUPPORTED"; + return DAT_SUCCESS; + } + case DAT_PROVIDER_NOT_FOUND: + { + *message = "DAT_PROVIDER_NOT_FOUND"; + return DAT_SUCCESS; + } + case DAT_PRIVILEGES_VIOLATION: + { + *message = "DAT_PRIVILEGES_VIOLATION"; + return DAT_SUCCESS; + } + case DAT_PROTECTION_VIOLATION: + { + *message = "DAT_PROTECTION_VIOLATION"; + return DAT_SUCCESS; + } + case DAT_QUEUE_EMPTY: + { + *message = "DAT_QUEUE_EMPTY"; + return DAT_SUCCESS; + } + case DAT_QUEUE_FULL: + { + *message = "DAT_QUEUE_FULL"; + return DAT_SUCCESS; + } + case DAT_TIMEOUT_EXPIRED: + { + *message = "DAT_TIMEOUT_EXPIRED"; + return DAT_SUCCESS; + } + case DAT_PROVIDER_ALREADY_REGISTERED: + { + *message = "DAT_PROVIDER_ALREADY_REGISTERED"; + return DAT_SUCCESS; + } + case DAT_PROVIDER_IN_USE: + { + *message = "DAT_PROVIDER_IN_USE"; + return DAT_SUCCESS; + } + case DAT_INVALID_ADDRESS: + { + *message = "DAT_INVALID_ADDRESS"; + return DAT_SUCCESS; + } + case DAT_INTERRUPTED_CALL: + { + *message = "DAT_INTERRUPTED_CALL"; + return DAT_SUCCESS; + } + case DAT_NOT_IMPLEMENTED: + { + *message = "DAT_NOT_IMPLEMENTED"; + return DAT_SUCCESS; + } + default: + { + *message = "unknown error"; + return DAT_INVALID_PARAMETER; + } + } +} + +static DAT_RETURN +dat_strerror_minor(IN DAT_RETURN value, OUT const char **message) +{ + switch (DAT_GET_SUBTYPE(value)) { + + case DAT_NO_SUBTYPE: /* NO subtype */ + { + *message = ""; + return DAT_SUCCESS; + } + case DAT_SUB_INTERRUPTED: + { + *message = "DAT_SUB_INTERRUPTED"; + return DAT_SUCCESS; + } + case DAT_RESOURCE_MEMORY: + { + *message = "DAT_RESOURCE_MEMORY"; + return DAT_SUCCESS; + } + case DAT_RESOURCE_DEVICE: + { + *message = "DAT_RESOURCE_DEVICE"; + return DAT_SUCCESS; + } + case DAT_RESOURCE_TEP: + { + *message = "DAT_RESOURCE_TEP"; + return DAT_SUCCESS; + } + case DAT_RESOURCE_TEVD: + { + *message = "DAT_RESOURCE_TEVD"; + return DAT_SUCCESS; + } + case DAT_RESOURCE_PROTECTION_DOMAIN: + { + *message = "DAT_RESOURCE_PROTECTION_DOMAIN"; + return DAT_SUCCESS; + } + case DAT_RESOURCE_MEMORY_REGION: + { + *message = "DAT_RESOURCE_MEMORY_REGION"; + return DAT_SUCCESS; + } + case DAT_RESOURCE_ERROR_HANDLER: + { + *message = "DAT_RESOURCE_ERROR_HANDLER"; + return DAT_SUCCESS; + } + case DAT_RESOURCE_CREDITS: + { + *message = "DAT_RESOURCE_CREDITS"; + return DAT_SUCCESS; + } + case DAT_INVALID_HANDLE_IA: + { + *message = "DAT_INVALID_HANDLE_IA"; + return DAT_SUCCESS; + } + case DAT_INVALID_HANDLE_EP: + { + *message = "DAT_INVALID_HANDLE_EP"; + return DAT_SUCCESS; + } + case DAT_INVALID_HANDLE_LMR: + { + *message = "DAT_INVALID_HANDLE_LMR"; + return DAT_SUCCESS; + } + case DAT_INVALID_HANDLE_RMR: + { + *message = "DAT_INVALID_HANDLE_RMR"; + return DAT_SUCCESS; + } + case DAT_INVALID_HANDLE_PZ: + { + *message = "DAT_INVALID_HANDLE_PZ"; + return DAT_SUCCESS; + } + case DAT_INVALID_HANDLE_PSP: + { + *message = "DAT_INVALID_HANDLE_PSP"; + return DAT_SUCCESS; + } + case DAT_INVALID_HANDLE_RSP: + { + *message = "DAT_INVALID_HANDLE_RSP"; + return DAT_SUCCESS; + } + case DAT_INVALID_HANDLE_CR: + { + *message = "DAT_INVALID_HANDLE_CR"; + return DAT_SUCCESS; + } + case DAT_INVALID_HANDLE_CNO: + { + *message = "DAT_INVALID_HANDLE_CNO"; + return DAT_SUCCESS; + } + case DAT_INVALID_HANDLE_EVD_CR: + { + *message = "DAT_INVALID_HANDLE_EVD_CR"; + return DAT_SUCCESS; + } + case DAT_INVALID_HANDLE_EVD_REQUEST: + { + *message = "DAT_INVALID_HANDLE_EVD_REQUEST"; + return DAT_SUCCESS; + } + case DAT_INVALID_HANDLE_EVD_RECV: + { + *message = "DAT_INVALID_HANDLE_EVD_RECV"; + return DAT_SUCCESS; + } + case DAT_INVALID_HANDLE_EVD_CONN: + { + *message = "DAT_INVALID_HANDLE_EVD_CONN"; + return DAT_SUCCESS; + } + case DAT_INVALID_HANDLE_EVD_ASYNC: + { + *message = "DAT_INVALID_HANDLE_EVD_ASYNC"; + return DAT_SUCCESS; + } + case DAT_INVALID_ARG1: + { + *message = "DAT_INVALID_ARG1"; + return DAT_SUCCESS; + } + case DAT_INVALID_ARG2: + { + *message = "DAT_INVALID_ARG2"; + return DAT_SUCCESS; + } + case DAT_INVALID_ARG3: + { + *message = "DAT_INVALID_ARG3"; + return DAT_SUCCESS; + } + case DAT_INVALID_ARG4: + { + *message = "DAT_INVALID_ARG4"; + return DAT_SUCCESS; + } + case DAT_INVALID_ARG5: + { + *message = "DAT_INVALID_ARG5"; + return DAT_SUCCESS; + } + case DAT_INVALID_ARG6: + { + *message = "DAT_INVALID_ARG6"; + return DAT_SUCCESS; + } + case DAT_INVALID_ARG7: + { + *message = "DAT_INVALID_ARG7"; + return DAT_SUCCESS; + } + case DAT_INVALID_ARG8: + { + *message = "DAT_INVALID_ARG8"; + return DAT_SUCCESS; + } + case DAT_INVALID_ARG9: + { + *message = "DAT_INVALID_ARG9"; + return DAT_SUCCESS; + } + case DAT_INVALID_ARG10: + { + *message = "DAT_INVALID_ARG10"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_EP_UNCONNECTED: + { + *message = "DAT_INVALID_STATE_EP_UNCONNECTED"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_EP_ACTCONNPENDING: + { + *message = "DAT_INVALID_STATE_EP_ACTCONNPENDING"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_EP_PASSCONNPENDING: + { + *message = "DAT_INVALID_STATE_EP_PASSCONNPENDING"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_EP_TENTCONNPENDING: + { + *message = "DAT_INVALID_STATE_EP_TENTCONNPENDING"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_EP_CONNECTED: + { + *message = "DAT_INVALID_STATE_EP_CONNECTED"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_EP_DISCONNECTED: + { + *message = "DAT_INVALID_STATE_EP_DISCONNECTED"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_EP_RESERVED: + { + *message = "DAT_INVALID_STATE_EP_RESERVED"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_EP_COMPLPENDING: + { + *message = "DAT_INVALID_STATE_EP_COMPLPENDING"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_EP_DISCPENDING: + { + *message = "DAT_INVALID_STATE_EP_DISCPENDING"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_EP_PROVIDERCONTROL: + { + *message = "DAT_INVALID_STATE_EP_PROVIDERCONTROL"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_EP_NOTREADY: + { + *message = "DAT_INVALID_STATE_EP_NOTREADY"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_CNO_IN_USE: + { + *message = "DAT_INVALID_STATE_CNO_IN_USE"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_CNO_DEAD: + { + *message = "DAT_INVALID_STATE_CNO_DEAD"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_EVD_OPEN: + { + *message = "DAT_INVALID_STATE_EVD_OPEN"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_EVD_ENABLED: + { + *message = "DAT_INVALID_STATE_EVD_ENABLED"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_EVD_DISABLED: + { + *message = "DAT_INVALID_STATE_EVD_DISABLED"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_EVD_WAITABLE: + { + *message = "DAT_INVALID_STATE_EVD_WAITABLE"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_EVD_UNWAITABLE: + { + *message = "DAT_INVALID_STATE_EVD_UNWAITABLE"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_EVD_IN_USE: + { + *message = "DAT_INVALID_STATE_EVD_IN_USE"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_EVD_CONFIG_NOTIFY: + { + *message = "DAT_INVALID_STATE_EVD_CONFIG_NOTIFY"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_EVD_CONFIG_SOLICITED: + { + *message = "DAT_INVALID_STATE_EVD_CONFIG_SOLICITED"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_EVD_CONFIG_THRESHOLD: + { + *message = "DAT_INVALID_STATE_EVD_CONFIG_THRESHOLD"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_EVD_WAITER: + { + *message = "DAT_INVALID_STATE_EVD_WAITER"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_EVD_ASYNC: + { + *message = "DAT_INVALID_STATE_EVD_ASYNC"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_IA_IN_USE: + { + *message = "DAT_INVALID_STATE_IA_IN_USE"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_LMR_IN_USE: + { + *message = "DAT_INVALID_STATE_LMR_IN_USE"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_LMR_FREE: + { + *message = "DAT_INVALID_STATE_LMR_FREE"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_PZ_IN_USE: + { + *message = "DAT_INVALID_STATE_PZ_IN_USE"; + return DAT_SUCCESS; + } + case DAT_INVALID_STATE_PZ_FREE: + { + *message = "DAT_INVALID_STATE_PZ_FREE"; + return DAT_SUCCESS; + } + case DAT_PRIVILEGES_READ: + { + *message = "DAT_PRIVILEGES_READ"; + return DAT_SUCCESS; + } + case DAT_PRIVILEGES_WRITE: + { + *message = "DAT_PRIVILEGES_WRITE"; + return DAT_SUCCESS; + } + case DAT_PRIVILEGES_RDMA_READ: + { + *message = "DAT_PRIVILEGES_RDMA_READ"; + return DAT_SUCCESS; + } + case DAT_PRIVILEGES_RDMA_WRITE: + { + *message = "DAT_PRIVILEGES_RDMA_WRITE"; + return DAT_SUCCESS; + } + case DAT_PROTECTION_READ: + { + *message = "DAT_PROTECTION_READ"; + return DAT_SUCCESS; + } + case DAT_PROTECTION_WRITE: + { + *message = "DAT_PROTECTION_WRITE"; + return DAT_SUCCESS; + } + case DAT_PROTECTION_RDMA_READ: + { + *message = "DAT_PROTECTION_RDMA_READ"; + return DAT_SUCCESS; + } + case DAT_PROTECTION_RDMA_WRITE: + { + *message = "DAT_PROTECTION_RDMA_WRITE"; + return DAT_SUCCESS; + } + case DAT_INVALID_ADDRESS_UNSUPPORTED: + { + *message = "DAT_INVALID_ADDRESS_UNSUPPORTED"; + return DAT_SUCCESS; + } + case DAT_INVALID_ADDRESS_UNREACHABLE: + { + *message = "DAT_INVALID_ADDRESS_UNREACHABLE"; + return DAT_SUCCESS; + } + case DAT_INVALID_ADDRESS_MALFORMED: + { + *message = "DAT_INVALID_ADDRESS_MALFORMED"; + return DAT_SUCCESS; + } + case DAT_NAME_NOT_REGISTERED: + { + *message = "DAT_NAME_NOT_REGISTERED"; + return DAT_SUCCESS; + } + case DAT_MAJOR_NOT_FOUND: + { + *message = "DAT_MAJOR_NOT_FOUND"; + return DAT_SUCCESS; + } + case DAT_MINOR_NOT_FOUND: + { + *message = "DAT_MINOR_NOT_FOUND"; + return DAT_SUCCESS; + } + case DAT_THREAD_SAFETY_NOT_FOUND: + { + *message = "DAT_THREAD_SAFETY_NOT_FOUND"; + return DAT_SUCCESS; + } + default: + { + *message = "unknown minor error"; + return DAT_INVALID_PARAMETER; + } + } +} + +/********************************************************************* + * * + * External Function Definitions * + * * + *********************************************************************/ + +DAT_RETURN DAT_API +dat_strerror(IN DAT_RETURN value, + OUT const char **major_message, OUT const char **minor_message) +{ + /* + * The DAT specification contains a note to implementers + * suggesting that the consumer's DAT_RETURN value be used + * as an index into a table of text strings. However, + * the DAT_RETURN values are not consecutive. Therefore this + * implementation does not follow the suggested implementation. + */ + + if (DAT_SUCCESS != dat_strerror_major(value, major_message)) { + return DAT_INVALID_PARAMETER; + } else if (minor_message != NULL) { + if (DAT_SUCCESS != dat_strerror_minor(value, minor_message)) { + return DAT_INVALID_PARAMETER; + } + } + + return DAT_SUCCESS; +} diff --git a/branches/WOF2-3/ulp/dapl2/dat/dirs b/branches/WOF2-3/ulp/dapl2/dat/dirs new file mode 100644 index 00000000..90c97ac8 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dat/dirs @@ -0,0 +1 @@ +DIRS=udat diff --git a/branches/WOF2-3/ulp/dapl2/dat/include/dat2/dat.h b/branches/WOF2-3/ulp/dapl2/dat/include/dat2/dat.h new file mode 100644 index 00000000..cf0b7ec1 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dat/include/dat2/dat.h @@ -0,0 +1,1379 @@ +/* + * Copyright (c) 2002-2006, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under all of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * Redistributions of source code must retain both 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. + * + * Neither the name of Network Appliance, Inc. nor the names of other DAT + * Collaborative contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + */ + +/*************************************************************** + * + * HEADER: dat.h + * + * PURPOSE: defines the common DAT API for uDAPL and kDAPL. + * + * Description: Header file for "DAPL: Direct Access Programming + * Library, Version: 2.0" + * + * Mapping rules: + * All global symbols are prepended with DAT_ or dat_ + * All DAT objects have an 'api' tag which, such as 'EP' or 'LMR' + * The method table is in the provider definition structure. + * + * + ***************************************************************/ +#ifndef _DAT_H_ +#define _DAT_H_ + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Generic DAT types */ + +typedef char * DAT_NAME_PTR; /* Format for ia_name and attributes */ +#define DAT_NAME_MAX_LENGTH 256 + +/* + * Used for provider, vendor, transport, hardware-specific attributes + * definitions. + */ + +typedef struct dat_named_attr +{ + const char * name; /* Name of attribute */ + const char * value; /* Value of attribute */ +} DAT_NAMED_ATTR; + +typedef enum dat_boolean +{ + DAT_FALSE = 0, + DAT_TRUE = 1 +} DAT_BOOLEAN; + +#ifdef DAT_EXTENSIONS +#define DAT_IB_EXTENSION 1 +#define DAT_IW_EXTENSION 2 +#endif /* DAT_EXTENSIONS */ + +typedef DAT_UINT32 DAT_HA_LB; +#define DAT_HA_LB_NONE (DAT_HA_LB)0 +#define DAT_HA_LB_INTERCOMM (DAT_HA_LB)1 +#define DAT_HA_LB_INTRACOMM (DAT_HA_LB)2 + +typedef union dat_context +{ + DAT_PVOID as_ptr; + DAT_UINT64 as_64; + DAT_UVERYLONG as_index; +} DAT_CONTEXT; + +typedef DAT_CONTEXT DAT_DTO_COOKIE; +typedef DAT_CONTEXT DAT_RMR_COOKIE; + +typedef enum dat_completion_flags +{ + /* Completes with notification */ + DAT_COMPLETION_DEFAULT_FLAG = 0x00, + /* Completions suppressed if successful */ + DAT_COMPLETION_SUPPRESS_FLAG = 0x01, + /* Sender controlled notification for recv completion */ + DAT_COMPLETION_SOLICITED_WAIT_FLAG = 0x02, + /* Completions with unsignaled notifications */ + DAT_COMPLETION_UNSIGNALLED_FLAG = 0x04, + /* Do not start processing until all previous RDMA reads complete. */ + DAT_COMPLETION_BARRIER_FENCE_FLAG = 0x08, + /* Only valid for uDAPL as EP attribute for Recv Completion flags. + * Waiter unblocking is controlled by the Threshold value of + * dat_evd_wait. UNSIGNALLED for RECV is not allowed when EP has + * this attribute. */ + DAT_COMPLETION_EVD_THRESHOLD_FLAG = 0x10, + /* Only valid for kDAPL + * Do not start processing LMR invalidate until all + * previously posted DTOs to the EP Request Queue + * have been completed. + * The value for LMR Invalidate Fence does not + * conflict with uDAPL so it can be extended + * to uDAPL usage later. + */ + DAT_COMPLETION_LMR_INVALIDATE_FENCE_FLAG = 0x20 +} DAT_COMPLETION_FLAGS; + + +typedef DAT_UINT32 DAT_TIMEOUT; /* microseconds */ + +/* timeout = infinity */ +#define DAT_TIMEOUT_INFINITE ((DAT_TIMEOUT) ~0) + +/* dat handles */ +typedef DAT_PVOID DAT_HANDLE; +typedef DAT_HANDLE DAT_CR_HANDLE; +typedef DAT_HANDLE DAT_EP_HANDLE; +typedef DAT_HANDLE DAT_EVD_HANDLE; +typedef DAT_HANDLE DAT_IA_HANDLE; +typedef DAT_HANDLE DAT_LMR_HANDLE; +typedef DAT_HANDLE DAT_PSP_HANDLE; +typedef DAT_HANDLE DAT_PZ_HANDLE; +typedef DAT_HANDLE DAT_RMR_HANDLE; +typedef DAT_HANDLE DAT_RSP_HANDLE; +typedef DAT_HANDLE DAT_SRQ_HANDLE; +typedef DAT_HANDLE DAT_CSP_HANDLE; + +typedef enum dat_dtos +{ + DAT_DTO_SEND, + DAT_DTO_RDMA_WRITE, + DAT_DTO_RDMA_READ, + DAT_DTO_RECEIVE, + DAT_DTO_RECEIVE_WITH_INVALIDATE, + DAT_DTO_BIND_MW, /* DAT 2.0 review, binds are reported via DTO events */ + DAT_DTO_LMR_FMR, /* kdat specific */ + DAT_DTO_LMR_INVALIDATE /* kdat specific */ +#ifdef DAT_EXTENSIONS + ,DAT_DTO_EXTENSION_BASE /* To be used by DAT extensions + as a starting point of extension DTOs */ +#endif /* DAT_EXTENSIONS */ +} DAT_DTOS; + + +/* dat NULL handles */ +#define DAT_HANDLE_NULL ((DAT_HANDLE)NULL) + +typedef DAT_SOCK_ADDR* DAT_IA_ADDRESS_PTR; + +typedef DAT_UINT64 DAT_CONN_QUAL; +typedef DAT_UINT64 DAT_PORT_QUAL; + +/* QOS definitions */ +typedef enum dat_qos +{ + DAT_QOS_BEST_EFFORT = 0x00, + DAT_QOS_HIGH_THROUGHPUT = 0x01, + DAT_QOS_LOW_LATENCY = 0x02, + /* not low latency, nor high throughput */ + DAT_QOS_ECONOMY = 0x04, + /* both low latency and high throughput */ + DAT_QOS_PREMIUM = 0x08 +} DAT_QOS; + +/* + * FLAGS + */ + +/* for backward compatibility */ +#define DAT_CONNECT_MULTIPATH_REQUESTED_FLAG DAT_CONNECT_MULTIPATH_FLAG + +typedef enum dat_connect_flags +{ + DAT_CONNECT_DEFAULT_FLAG = 0x00, + DAT_CONNECT_MULTIPATH_REQUESTED_FLAG = 0x01, + DAT_CONNECT_MULTIPATH_REQUIRED_FLAG = 0x02 +} DAT_CONNECT_FLAGS; + +typedef enum dat_close_flags +{ + DAT_CLOSE_ABRUPT_FLAG = 0x00, + DAT_CLOSE_GRACEFUL_FLAG = 0x01 +} DAT_CLOSE_FLAGS; + +#define DAT_CLOSE_DEFAULT DAT_CLOSE_ABRUPT_FLAG + +typedef enum dat_evd_flags +{ + DAT_EVD_SOFTWARE_FLAG = 0x001, + DAT_EVD_CR_FLAG = 0x010, + DAT_EVD_DTO_FLAG = 0x020, + DAT_EVD_CONNECTION_FLAG = 0x040, + DAT_EVD_RMR_BIND_FLAG = 0x080, + DAT_EVD_ASYNC_FLAG = 0x100, + + /* DAT events only, no software events */ + DAT_EVD_DEFAULT_FLAG = 0x1F0 +#ifdef DAT_EXTENSIONS +/* To be used by DAT extensions as a starting point for extended evd flags */ + ,DAT_EVD_EXTENSION_BASE = 0x200 +#endif /* DAT_EXTENSIONS */ +} DAT_EVD_FLAGS; + +typedef enum dat_psp_flags +{ + DAT_PSP_CONSUMER_FLAG = 0x00, /* Consumer creates an Endpoint */ + DAT_PSP_PROVIDER_FLAG = 0x01 /* Provider creates an Endpoint */ +} DAT_PSP_FLAGS; + +/* + * Memory Buffers + * + * Both LMR and RMR triplets specify 64-bit addresses in the local host's byte + * order, even when that exceeds the size of a DAT_PVOID for the host + * architecture. + */ + +/* + * Both LMR and RMR Triplets specify 64-bit addresses in the local host + * order, even when that exceeds the size of a void pointer for the host + * architecture. The DAT_VADDR type that represents addresses is in the + * native byte-order of the local host. Helper macros that allow Consumers + * to convert DAT_VADDR into various orders that might be useful for + * inclusion of RMR Triplets into a payload of a message follow. + * + * DAT defines the following macros to convert the fields on an RMR Triplet + * to defined byte orders to allow their export by the Consumer over wire + * protocols. DAT does not define how the two peers decide which byte should be + * used. + * + * DAT_LMRC_TO_LSB(lmrc) returns the supplied LMR Context in ls-byte + * order. + * DAT_LMRC_TO_MSB(lmrc) returns the supplied LMR Context in ms-byte + * order. + * DAT_RMRC_TO_LSB(rmrc) returns the supplied RMR Context in ls-byte + * order. + * DAT_RMRC_TO_MSB(rmrc) returns the supplied RMR Context in ms-byte + * order. + * DAT_VADDR_TO_LSB(vaddr) returns the supplied Virtual Address in ls-byte + * order. + * DAT_VADDR_TO_MSB(vaddr) returns the supplied Virtual Address in + * ms-byte order. + * DAT_VLEN_TO_LSB(vlen) returns the supplied length in ls-byte order. + * DAT_VLEN_TO_MSB(vlen) returns the supplied length in ms-byte order. + * + * Consumers are free to use 64-bit or 32-bit arithmetic for local or remote + * memory address and length manipulation in their preferred byte-order. Only the + * LMR and RMR Triplets passed to a Provider as part of a Posted DTO are + * required to be in 64-bit address and local host order formats. Providers shall + * convert RMR_Triplets to a Transport-required wire format. + * + * For the best performance, Consumers should align each buffer segment to + * the boundary specified by the dat_optimal_alignment. + */ +typedef DAT_UINT32 DAT_LMR_CONTEXT; +typedef DAT_UINT32 DAT_RMR_CONTEXT; + +typedef DAT_UINT64 DAT_VLEN; +typedef DAT_UINT64 DAT_VADDR; +typedef DAT_UINT32 DAT_SEG_LENGTH; /* The maximum data segment length */ + +typedef struct dat_provider_attr DAT_PROVIDER_ATTR; +typedef struct dat_evd_param DAT_EVD_PARAM; +typedef struct dat_lmr_param DAT_LMR_PARAM; +typedef enum dat_lmr_param_mask DAT_LMR_PARAM_MASK; + +/* It is legal for the Consumer to specify zero for segment_length + * of the dat_lmr_triplet. When 0 is specified for the + * segment_length then the other two elements of the + * dat_lmr_triplet are irrelevant and can be invalid. + */ + +typedef struct dat_lmr_triplet +{ + DAT_VADDR virtual_address;/* 64-bit address */ + DAT_SEG_LENGTH segment_length; /* 32-bit length */ + DAT_LMR_CONTEXT lmr_context; /* 32-bit lmr_context */ +} DAT_LMR_TRIPLET; + +typedef struct dat_rmr_triplet +{ + DAT_VADDR virtual_address;/* 64-bit address */ + DAT_SEG_LENGTH segment_length; /* 32-bit length */ + DAT_RMR_CONTEXT rmr_context; /* 32-bit rmr_context */ +} DAT_RMR_TRIPLET; + +/* Memory privileges */ + +typedef enum dat_mem_priv_flags +{ + DAT_MEM_PRIV_NONE_FLAG = 0x00, + DAT_MEM_PRIV_LOCAL_READ_FLAG = 0x01, + DAT_MEM_PRIV_REMOTE_READ_FLAG = 0x02, + DAT_MEM_PRIV_LOCAL_WRITE_FLAG = 0x10, + DAT_MEM_PRIV_REMOTE_WRITE_FLAG = 0x20, + DAT_MEM_PRIV_ALL_FLAG = 0x33 +#ifdef DAT_EXTENSIONS +/* To be used by DAT extensions as a starting + point of extension memory privileges */ + ,DAT_MEM_PRIV_EXTENSION_BASE = 0x40 +#endif /* DAT_EXTENSIONS */ + +} DAT_MEM_PRIV_FLAGS; + +/* For backward compatibility with DAT-1.0, memory privileges values are + * supported + */ +#define DAT_MEM_PRIV_READ_FLAG (DAT_MEM_PRIV_LOCAL_READ_FLAG | DAT_MEM_PRIV_REMOTE_READ_FLAG) +#define DAT_MEM_PRIV_WRITE_FLAG (DAT_MEM_PRIV_LOCAL_WRITE_FLAG | DAT_MEM_PRIV_REMOTE_WRITE_FLAG) + +/* LMR VA types */ +typedef enum dat_va_type +{ + DAT_VA_TYPE_VA = 0x0, + DAT_VA_TYPE_ZB = 0x1 +} DAT_VA_TYPE; + +/* RMR Arguments & RMR Arguments Mask */ + +/* DAPL 2.0 addition */ +/* Defines RMR protection scope */ +typedef enum dat_rmr_scope +{ + DAT_RMR_SCOPE_EP, /* bound to at most one EP at a time. */ + DAT_RMR_SCOPE_PZ, /* bound to a Protection Zone */ + DAT_RMR_SCOPE_ANY /* Supports all types */ +} DAT_RMR_SCOPE; + +typedef struct dat_rmr_param +{ + DAT_IA_HANDLE ia_handle; + DAT_PZ_HANDLE pz_handle; + DAT_LMR_TRIPLET lmr_triplet; + DAT_MEM_PRIV_FLAGS mem_priv; + DAT_RMR_CONTEXT rmr_context; + DAT_RMR_SCOPE rmr_scope; + DAT_VA_TYPE va_type; +} DAT_RMR_PARAM; + +typedef enum dat_rmr_param_mask +{ + DAT_RMR_FIELD_IA_HANDLE = 0x01, + DAT_RMR_FIELD_PZ_HANDLE = 0x02, + DAT_RMR_FIELD_LMR_TRIPLET = 0x04, + DAT_RMR_FIELD_MEM_PRIV = 0x08, + DAT_RMR_FIELD_RMR_CONTEXT = 0x10, + DAT_RMR_FIELD_RMR_SCOPE = 0x20, + DAT_RMR_FIELD_VA_TYPE = 0x40, + + DAT_RMR_FIELD_ALL = 0x7F +} DAT_RMR_PARAM_MASK; + +/* Provider attributes */ + +typedef enum dat_iov_ownership +{ + /* Not a modification by the Provider; the Consumer can use anytime. */ + DAT_IOV_CONSUMER = 0x0, + /* Provider does not modify returned IOV DTO on completion. */ + DAT_IOV_PROVIDER_NOMOD = 0x1, + /* Provider can modify IOV DTO on completion; can't trust it. */ + DAT_IOV_PROVIDER_MOD = 0x2 +} DAT_IOV_OWNERSHIP; + +typedef enum dat_ep_creator_for_psp +{ + DAT_PSP_CREATES_EP_NEVER, /* Provider never creates Endpoint. */ + DAT_PSP_CREATES_EP_IFASKED, /* Provider creates Endpoint if asked. */ + DAT_PSP_CREATES_EP_ALWAYS /* Provider always creates Endpoint. */ +} DAT_EP_CREATOR_FOR_PSP; + +/* General Interface Adapter attributes. These apply to both udat and kdat. */ + +/* To support backwards compatibility for DAPL-1.0 */ +#define max_rdma_read_per_ep max_rdma_read_per_ep_in +#define DAT_IA_FIELD_IA_MAX_DTO_PER_OP DAT_IA_FIELD_IA_MAX_DTO_PER_EP_IN + +/* To support backwards compatibility for DAPL-1.0 & DAPL-1.1 */ +#define max_mtu_size max_message_size + +/* Query for provider IA extension support */ +typedef enum dat_extension +{ + DAT_EXTENSION_NONE,/* no extension supported. */ + DAT_EXTENSION_IB, /* IB extension. */ + DAT_EXTENSION_IW /* iWARP extension. */ +} DAT_EXTENSION; + +typedef struct dat_ia_attr DAT_IA_ATTR; + +/* To support backwards compatibility for DAPL-1.0 & DAPL-1.1 */ +#define DAT_IA_FIELD_IA_MAX_MTU_SIZE DAT_IA_FIELD_IA_MAX_MESSAGE_SIZE + +typedef DAT_UINT64 DAT_IA_ATTR_MASK; + +#define DAT_IA_FIELD_IA_ADAPTER_NAME UINT64_C(0x000000001) +#define DAT_IA_FIELD_IA_VENDOR_NAME UINT64_C(0x000000002) +#define DAT_IA_FIELD_IA_HARDWARE_MAJOR_VERSION UINT64_C(0x000000004) +#define DAT_IA_FIELD_IA_HARDWARE_MINOR_VERSION UINT64_C(0x000000008) +#define DAT_IA_FIELD_IA_FIRMWARE_MAJOR_VERSION UINT64_C(0x000000010) +#define DAT_IA_FIELD_IA_FIRMWARE_MINOR_VERSION UINT64_C(0x000000020) +#define DAT_IA_FIELD_IA_ADDRESS_PTR UINT64_C(0x000000040) +#define DAT_IA_FIELD_IA_MAX_EPS UINT64_C(0x000000080) +#define DAT_IA_FIELD_IA_MAX_DTO_PER_EP UINT64_C(0x000000100) +#define DAT_IA_FIELD_IA_MAX_RDMA_READ_PER_EP_IN UINT64_C(0x000000200) +#define DAT_IA_FIELD_IA_MAX_RDMA_READ_PER_EP_OUT UINT64_C(0x000000400) +#define DAT_IA_FIELD_IA_MAX_EVDS UINT64_C(0x000000800) +#define DAT_IA_FIELD_IA_MAX_EVD_QLEN UINT64_C(0x000001000) +#define DAT_IA_FIELD_IA_MAX_IOV_SEGMENTS_PER_DTO UINT64_C(0x000002000) +#define DAT_IA_FIELD_IA_MAX_LMRS UINT64_C(0x000004000) +#define DAT_IA_FIELD_IA_MAX_LMR_BLOCK_SIZE UINT64_C(0x000008000) +#define DAT_IA_FIELD_IA_MAX_LMR_VIRTUAL_ADDRESS UINT64_C(0x000010000) +#define DAT_IA_FIELD_IA_MAX_PZS UINT64_C(0x000020000) +#define DAT_IA_FIELD_IA_MAX_MESSAGE_SIZE UINT64_C(0x000040000) +#define DAT_IA_FIELD_IA_MAX_RDMA_SIZE UINT64_C(0x000080000) +#define DAT_IA_FIELD_IA_MAX_RMRS UINT64_C(0x000100000) +#define DAT_IA_FIELD_IA_MAX_RMR_TARGET_ADDRESS UINT64_C(0x000200000) +#define DAT_IA_FIELD_IA_MAX_SRQS UINT64_C(0x000400000) +#define DAT_IA_FIELD_IA_MAX_EP_PER_SRQ UINT64_C(0x000800000) +#define DAT_IA_FIELD_IA_MAX_RECV_PER_SRQ UINT64_C(0x001000000) +#define DAT_IA_FIELD_IA_MAX_IOV_SEGMENTS_PER_RDMA_READ UINT64_C(0x002000000) +#define DAT_IA_FIELD_IA_MAX_IOV_SEGMENTS_PER_RDMA_WRITE UINT64_C(0x004000000) +#define DAT_IA_FIELD_IA_MAX_RDMA_READ_IN UINT64_C(0x008000000) +#define DAT_IA_FIELD_IA_MAX_RDMA_READ_OUT UINT64_C(0x010000000) +#define DAT_IA_FIELD_IA_MAX_RDMA_READ_PER_EP_IN_GUARANTEED UINT64_C(0x020000000) +#define DAT_IA_FIELD_IA_MAX_RDMA_READ_PER_EP_OUT_GUARANTEED UINT64_C(0x040000000) +#define DAT_IA_FIELD_IA_ZB_SUPPORTED UINT64_C(0x080000000) +#define DAT_IA_FIELD_IA_EXTENSIONS_SUPPORTED UINT64_C(0x100000000) + +/* To support backwards compatibility for DAPL-1.0 & DAPL-1.1 */ +#define DAT_IA_ALL DAT_IA_FIELD_ALL +#define DAT_IA_FIELD_NONE UINT64_C(0x0) + +/* Endpoint attributes */ + +typedef enum dat_service_type +{ + DAT_SERVICE_TYPE_RC /* reliable connections */ +#ifdef DAT_EXTENSIONS + ,DAT_SERVICE_TYPE_EXTENSION_BASE /* To be used by DAT extensions + as a starting point of extension services */ +#endif /* DAT_EXTENSIONS */ +} DAT_SERVICE_TYPE; + +typedef struct dat_ep_attr +{ + DAT_SERVICE_TYPE service_type; + DAT_SEG_LENGTH max_message_size; + DAT_SEG_LENGTH max_rdma_size; + DAT_QOS qos; + DAT_COMPLETION_FLAGS recv_completion_flags; + DAT_COMPLETION_FLAGS request_completion_flags; + DAT_COUNT max_recv_dtos; + DAT_COUNT max_request_dtos; + DAT_COUNT max_recv_iov; + DAT_COUNT max_request_iov; + DAT_COUNT max_rdma_read_in; + DAT_COUNT max_rdma_read_out; + DAT_COUNT srq_soft_hw; + DAT_COUNT max_rdma_read_iov; + DAT_COUNT max_rdma_write_iov; + DAT_COUNT ep_transport_specific_count; + DAT_NAMED_ATTR * ep_transport_specific; + DAT_COUNT ep_provider_specific_count; + DAT_NAMED_ATTR * ep_provider_specific; +} DAT_EP_ATTR; + +/* Endpoint Parameters */ + +/* For backwards compatibility */ +#define DAT_EP_STATE_ERROR DAT_EP_STATE_DISCONNECTED + +typedef enum dat_ep_state +{ + DAT_EP_STATE_UNCONNECTED, /* quiescent state */ + DAT_EP_STATE_UNCONFIGURED_UNCONNECTED, + DAT_EP_STATE_RESERVED, + DAT_EP_STATE_UNCONFIGURED_RESERVED, + DAT_EP_STATE_PASSIVE_CONNECTION_PENDING, + DAT_EP_STATE_UNCONFIGURED_PASSIVE, + DAT_EP_STATE_ACTIVE_CONNECTION_PENDING, + DAT_EP_STATE_TENTATIVE_CONNECTION_PENDING, + DAT_EP_STATE_UNCONFIGURED_TENTATIVE, + DAT_EP_STATE_CONNECTED, + DAT_EP_STATE_DISCONNECT_PENDING, + DAT_EP_STATE_DISCONNECTED, + DAT_EP_STATE_COMPLETION_PENDING, + DAT_EP_STATE_CONNECTED_SINGLE_PATH, + DAT_EP_STATE_CONNECTED_MULTI_PATH +} DAT_EP_STATE; + +typedef struct dat_ep_param +{ + DAT_IA_HANDLE ia_handle; + DAT_EP_STATE ep_state; + DAT_COMM comm; + DAT_IA_ADDRESS_PTR local_ia_address_ptr; + DAT_PORT_QUAL local_port_qual; + DAT_IA_ADDRESS_PTR remote_ia_address_ptr; + DAT_PORT_QUAL remote_port_qual; + DAT_PZ_HANDLE pz_handle; + DAT_EVD_HANDLE recv_evd_handle; + DAT_EVD_HANDLE request_evd_handle; + DAT_EVD_HANDLE connect_evd_handle; + DAT_SRQ_HANDLE srq_handle; + DAT_EP_ATTR ep_attr; +} DAT_EP_PARAM; + +typedef DAT_UINT64 DAT_EP_PARAM_MASK; +#define DAT_EP_FIELD_IA_HANDLE UINT64_C(0x00000001) +#define DAT_EP_FIELD_EP_STATE UINT64_C(0x00000002) +#define DAT_EP_FIELD_COMM UINT64_C(0x00000004) +#define DAT_EP_FIELD_LOCAL_IA_ADDRESS_PTR UINT64_C(0x00000008) +#define DAT_EP_FIELD_LOCAL_PORT_QUAL UINT64_C(0x00000010) +#define DAT_EP_FIELD_REMOTE_IA_ADDRESS_PTR UINT64_C(0x00000020) +#define DAT_EP_FIELD_REMOTE_PORT_QUAL UINT64_C(0x00000040) +#define DAT_EP_FIELD_PZ_HANDLE UINT64_C(0x00000080) +#define DAT_EP_FIELD_RECV_EVD_HANDLE UINT64_C(0x00000100) +#define DAT_EP_FIELD_REQUEST_EVD_HANDLE UINT64_C(0x00000200) +#define DAT_EP_FIELD_CONNECT_EVD_HANDLE UINT64_C(0x00000400) +#define DAT_EP_FIELD_SRQ_HANDLE UINT64_C(0x00000800) + /* Remainder of values from EP_ATTR, 0x00001000 and up */ +#define DAT_EP_FIELD_EP_ATTR_SERVICE_TYPE UINT64_C(0x00001000) +#define DAT_EP_FIELD_EP_ATTR_MAX_MESSAGE_SIZE UINT64_C(0x00002000) +#define DAT_EP_FIELD_EP_ATTR_MAX_RDMA_SIZE UINT64_C(0x00004000) +#define DAT_EP_FIELD_EP_ATTR_QOS UINT64_C(0x00008000) +#define DAT_EP_FIELD_EP_ATTR_RECV_COMPLETION_FLAGS UINT64_C(0x00010000) +#define DAT_EP_FIELD_EP_ATTR_REQUEST_COMPLETION_FLAGS UINT64_C(0x00020000) +#define DAT_EP_FIELD_EP_ATTR_MAX_RECV_DTOS UINT64_C(0x00040000) +#define DAT_EP_FIELD_EP_ATTR_MAX_REQUEST_DTOS UINT64_C(0x00080000) +#define DAT_EP_FIELD_EP_ATTR_MAX_RECV_IOV UINT64_C(0x00100000) +#define DAT_EP_FIELD_EP_ATTR_MAX_REQUEST_IOV UINT64_C(0x00200000) +#define DAT_EP_FIELD_EP_ATTR_MAX_RDMA_READ_IN UINT64_C(0x00400000) +#define DAT_EP_FIELD_EP_ATTR_MAX_RDMA_READ_OUT UINT64_C(0x00800000) +#define DAT_EP_FIELD_EP_ATTR_SRQ_SOFT_HW UINT64_C(0x01000000) +#define DAT_EP_FIELD_EP_ATTR_MAX_RDMA_READ_IOV UINT64_C(0x02000000) +#define DAT_EP_FIELD_EP_ATTR_MAX_RDMA_WRITE_IOV UINT64_C(0x04000000) +#define DAT_EP_FIELD_EP_ATTR_NUM_TRANSPORT_ATTR UINT64_C(0x08000000) +#define DAT_EP_FIELD_EP_ATTR_TRANSPORT_SPECIFIC_ATTR UINT64_C(0x10000000) +#define DAT_EP_FIELD_EP_ATTR_NUM_PROVIDER_ATTR UINT64_C(0x20000000) +#define DAT_EP_FIELD_EP_ATTR_PROVIDER_SPECIFIC_ATTR UINT64_C(0x40000000) +#define DAT_EP_FIELD_EP_ATTR_ALL UINT64_C(0x7FFFF000) + +#define DAT_EP_FIELD_ALL UINT64_C(0x7FFFFFFF) + +#define DAT_WATERMARK_INFINITE ((DAT_COUNT)~0) +#define DAT_HW_DEFAULT DAT_WATERMARK_INFINITE +#define DAT_SRQ_LW_DEFAULT 0x0 + +typedef enum dat_srq_state +{ + DAT_SRQ_STATE_OPERATIONAL, + DAT_SRQ_STATE_ERROR +} DAT_SRQ_STATE; + +#define DAT_VALUE_UNKNOWN (((DAT_COUNT) ~0)-1) + +typedef struct dat_srq_attr +{ + DAT_COUNT max_recv_dtos; + DAT_COUNT max_recv_iov; + DAT_COUNT low_watermark; +} DAT_SRQ_ATTR; + +typedef struct dat_srq_param +{ + DAT_IA_HANDLE ia_handle; + DAT_SRQ_STATE srq_state; + DAT_PZ_HANDLE pz_handle; + DAT_COUNT max_recv_dtos; + DAT_COUNT max_recv_iov; + DAT_COUNT low_watermark; + DAT_COUNT available_dto_count; + DAT_COUNT outstanding_dto_count; +} DAT_SRQ_PARAM; + +typedef enum dat_srq_param_mask +{ + DAT_SRQ_FIELD_IA_HANDLE = 0x001, + DAT_SRQ_FIELD_SRQ_STATE = 0x002, + DAT_SRQ_FIELD_PZ_HANDLE = 0x004, + DAT_SRQ_FIELD_MAX_RECV_DTO = 0x008, + DAT_SRQ_FIELD_MAX_RECV_IOV = 0x010, + DAT_SRQ_FIELD_LOW_WATERMARK = 0x020, + DAT_SRQ_FIELD_AVAILABLE_DTO_COUNT = 0x040, + DAT_SRQ_FIELD_OUTSTANDING_DTO_COUNT = 0x080, + + DAT_SRQ_FIELD_ALL = 0x0FF +} DAT_SRQ_PARAM_MASK; + +/* PZ Parameters */ + +typedef struct dat_pz_param +{ + DAT_IA_HANDLE ia_handle; +} DAT_PZ_PARAM; + +typedef enum dat_pz_param_mask +{ + DAT_PZ_FIELD_IA_HANDLE = 0x01, + + DAT_PZ_FIELD_ALL = 0x01 +} DAT_PZ_PARAM_MASK; + +/* PSP Parameters */ + +typedef struct dat_psp_param +{ + DAT_IA_HANDLE ia_handle; + DAT_CONN_QUAL conn_qual; + DAT_EVD_HANDLE evd_handle; + DAT_PSP_FLAGS psp_flags; +} DAT_PSP_PARAM; + +typedef enum dat_psp_param_mask +{ + DAT_PSP_FIELD_IA_HANDLE = 0x01, + DAT_PSP_FIELD_CONN_QUAL = 0x02, + DAT_PSP_FIELD_EVD_HANDLE = 0x04, + DAT_PSP_FIELD_PSP_FLAGS = 0x08, + + DAT_PSP_FIELD_ALL = 0x0F +} DAT_PSP_PARAM_MASK; + +/* RSP Parameters */ + +typedef struct dat_rsp_param +{ + DAT_IA_HANDLE ia_handle; + DAT_CONN_QUAL conn_qual; + DAT_EVD_HANDLE evd_handle; + DAT_EP_HANDLE ep_handle; +} DAT_RSP_PARAM; + +typedef enum dat_rsp_param_mask +{ + DAT_RSP_FIELD_IA_HANDLE = 0x01, + DAT_RSP_FIELD_CONN_QUAL = 0x02, + DAT_RSP_FIELD_EVD_HANDLE = 0x04, + DAT_RSP_FIELD_EP_HANDLE = 0x08, + + DAT_RSP_FIELD_ALL = 0x0F +} DAT_RSP_PARAM_MASK; + +/* CSP Parameters */ +typedef struct dat_csp_param +{ + DAT_IA_HANDLE ia_handle; + DAT_COMM *comm; + DAT_IA_ADDRESS_PTR address_ptr; + DAT_EVD_HANDLE evd_handle; +} DAT_CSP_PARAM; + +typedef enum dat_csp_param_mask +{ + DAT_CSP_FIELD_IA_HANDLE = 0x01, + DAT_CSP_FIELD_COMM = 0x02, + DAT_CSP_FIELD_IA_ADDRESS = 0x04, + DAT_CSP_FIELD_EVD_HANDLE = 0x08, + + DAT_CSP_FIELD_ALL = 0x0F +} DAT_CSP_PARAM_MASK; + +/* Connection Request Parameters. + * + * The Connection Request does not provide Remote Endpoint attributes. + * If a local Consumer needs this information, the remote Consumer should + * encode it into Private Data. + */ + +typedef struct dat_cr_param +{ + /* Remote IA whose Endpoint requested the connection. */ + DAT_IA_ADDRESS_PTR remote_ia_address_ptr; + + /* Port qualifier of the remote Endpoint of the requested connection.*/ + DAT_PORT_QUAL remote_port_qual; + + /* Size of the Private Data. */ + DAT_COUNT private_data_size; + + /* Pointer to the Private Data passed by remote side in the Connection + * Request. + */ + DAT_PVOID private_data; + /* The local Endpoint provided by the Service Point for the requested + * connection. It is the only Endpoint that can accept a Connection + * Request on this Service Point. The value DAT_HANDLE_NULL + * represents that there is no associated local Endpoint for the + * requested connection. + */ + DAT_EP_HANDLE local_ep_handle; +} DAT_CR_PARAM; + +typedef enum dat_cr_param_mask +{ + DAT_CR_FIELD_REMOTE_IA_ADDRESS_PTR = 0x01, + DAT_CR_FIELD_REMOTE_PORT_QUAL = 0x02, + DAT_CR_FIELD_PRIVATE_DATA_SIZE = 0x04, + DAT_CR_FIELD_PRIVATE_DATA = 0x08, + DAT_CR_FIELD_LOCAL_EP_HANDLE = 0x10, + + DAT_CR_FIELD_ALL = 0x1F +} DAT_CR_PARAM_MASK; + +/************************** Events ******************************/ + +/* Completion status flags */ + + /* DTO completion status */ + + /* For backwards compatibility */ +#define DAT_DTO_LENGTH_ERROR DAT_DTO_ERR_LOCAL_LENGTH +#define DAT_DTO_FAILURE DAT_DTO_ERR_FLUSHED + +typedef enum dat_dto_completion_status +{ + DAT_DTO_SUCCESS = 0, + DAT_DTO_ERR_FLUSHED = 1, + DAT_DTO_ERR_LOCAL_LENGTH = 2, + DAT_DTO_ERR_LOCAL_EP = 3, + DAT_DTO_ERR_LOCAL_PROTECTION = 4, + DAT_DTO_ERR_BAD_RESPONSE = 5, + DAT_DTO_ERR_REMOTE_ACCESS = 6, + DAT_DTO_ERR_REMOTE_RESPONDER = 7, + DAT_DTO_ERR_TRANSPORT = 8, + DAT_DTO_ERR_RECEIVER_NOT_READY = 9, + DAT_DTO_ERR_PARTIAL_PACKET = 10, + DAT_RMR_OPERATION_FAILED = 11, + DAT_DTO_ERR_LOCAL_MM_ERROR = 12 /* kdat specific */ +} DAT_DTO_COMPLETION_STATUS; + + /* RMR completion status */ + + /* For backwards compatibility */ +#define DAT_RMR_BIND_SUCCESS DAT_DTO_SUCCESS +#define DAT_RMR_BIND_FAILURE DAT_DTO_ERR_FLUSHED + +/* RMR completion status */ +#define DAT_RMR_BIND_COMPLETION_STATUS DAT_DTO_COMPLETION_STATUS + +/* Completion group structs (six total) */ + +/* DTO completion event data */ +/* transfered_length is not defined if status is not DAT_SUCCESS */ +/* invalidate_flag and rmr_context are not defined if status is not DAT_SUCCESS */ + +typedef struct dat_dto_completion_event_data +{ + DAT_EP_HANDLE ep_handle; + DAT_DTO_COOKIE user_cookie; + DAT_DTO_COMPLETION_STATUS status; + DAT_SEG_LENGTH transfered_length; + DAT_DTOS operation; + DAT_RMR_CONTEXT rmr_context; +} DAT_DTO_COMPLETION_EVENT_DATA; + + /* RMR bind completion event data */ +typedef struct dat_rmr_bind_completion_event_data +{ + DAT_RMR_HANDLE rmr_handle; + DAT_RMR_COOKIE user_cookie; + DAT_RMR_BIND_COMPLETION_STATUS status; +} DAT_RMR_BIND_COMPLETION_EVENT_DATA; + +typedef union dat_sp_handle +{ + DAT_RSP_HANDLE rsp_handle; + DAT_PSP_HANDLE psp_handle; + DAT_CSP_HANDLE csp_handle; +} DAT_SP_HANDLE; + + /* Connection Request Arrival event data */ +typedef struct dat_cr_arrival_event_data +{ + /* Handle to the Service Point that received the Connection Request + * from the remote side. If the Service Point was Reserved, sp_handle is + * DAT_HANDLE_NULL because the reserved Service Point is + * automatically destroyed upon generating this event. Can be PSP, + * CSP, or RSP. + */ + DAT_SP_HANDLE sp_handle; + + /* Address of the IA on which the Connection Request arrived. */ + DAT_IA_ADDRESS_PTR local_ia_address_ptr; + + /* Connection Qualifier of the IA on which the Service Point received a + * Connection Request. + */ + DAT_CONN_QUAL conn_qual; + + /* The Connection Request instance created by a Provider for the + * arrived Connection Request. Consumers can find out private_data + * passed by a remote Consumer from cr_handle. It is up to a Consumer + * to dat_cr_accept or dat_cr_reject of the Connection Request. + */ + DAT_CR_HANDLE cr_handle; + + /* The binary indicator whether the arrived privata data was trancated + * or not. + * The default value of 0 means not truncation of received private data. */ + DAT_BOOLEAN truncate_flag; + +} DAT_CR_ARRIVAL_EVENT_DATA; + + + /* Connection event data */ +typedef struct dat_connection_event_data +{ + DAT_EP_HANDLE ep_handle; + DAT_COUNT private_data_size; + DAT_PVOID private_data; +} DAT_CONNECTION_EVENT_DATA; + +/* Async Error event data */ + +/* For unaffiliated asynchronous event dat_handle is ia_handle. For + * Endpoint affiliated asynchronous event dat_handle is ep_handle. For + * EVD affiliated asynchronous event dat_handle is evd_handle. For SRQ + * affiliated asynchronous event dat_handle is srq_handle. For Memory + * affiliated asynchronous event dat_handle is either lmr_handle, + * rmr_handle or pz_handle. + */ +typedef struct dat_asynch_error_event_data +{ + DAT_HANDLE dat_handle; /* either IA, EP, EVD, SRQ, */ + /* LMR, RMR, or PZ handle */ + DAT_COUNT reason; /* object specific */ +} DAT_ASYNCH_ERROR_EVENT_DATA; + +/* The reason is object type specific and its values are defined below. */ +typedef enum ia_async_error_reason +{ + DAT_IA_CATASTROPHIC_ERROR, + DAT_IA_OTHER_ERROR +} DAT_IA_ASYNC_ERROR_REASON; + +typedef enum ep_async_error_reason +{ + DAT_EP_TRANSFER_TO_ERROR, + DAT_EP_OTHER_ERROR, + DAT_SRQ_SOFT_HIGH_WATERMARK_EVENT +} DAT_EP_ASYNC_ERROR_REASON; + +typedef enum evd_async_error_reason +{ + DAT_EVD_OVERFLOW_ERROR, + DAT_EVD_OTHER_ERROR +} DAT_EVD_ASYNC_ERROR_REASON; + +typedef enum srq_async_error_reason +{ + DAT_SRQ_TRANSFER_TO_ERROR, + DAT_SRQ_OTHER_ERROR, + DAT_SRQ_LOW_WATERMARK_EVENT +} DAT_SRQ_ASYNC_ERROR_REASON; + +typedef enum lmr_async_error_reason +{ + DAT_LMR_OTHER_ERROR +} DAT_LMR_ASYNC_ERROR_REASON; + +typedef enum rmr_async_error_reason +{ + DAT_RMR_OTHER_ERROR +} DAT_RMR_ASYNC_ERROR_REASON; + +typedef enum pz_async_error_reason +{ + DAT_PZ_OTHER_ERROR +} DAT_PZ_ASYNC_ERROR_REASON; + +/* Software event data */ +typedef struct dat_software_event_data +{ + DAT_PVOID pointer; +} DAT_SOFTWARE_EVENT_DATA; + +typedef enum dat_event_number +{ + DAT_DTO_COMPLETION_EVENT = 0x00001, + DAT_RMR_BIND_COMPLETION_EVENT = 0x01001, + DAT_CONNECTION_REQUEST_EVENT = 0x02001, + DAT_CONNECTION_EVENT_ESTABLISHED = 0x04001, + DAT_CONNECTION_EVENT_PEER_REJECTED = 0x04002, + DAT_CONNECTION_EVENT_NON_PEER_REJECTED = 0x04003, + DAT_CONNECTION_EVENT_ACCEPT_COMPLETION_ERROR = 0x04004, + DAT_CONNECTION_EVENT_DISCONNECTED = 0x04005, + DAT_CONNECTION_EVENT_BROKEN = 0x04006, + DAT_CONNECTION_EVENT_TIMED_OUT = 0x04007, + DAT_CONNECTION_EVENT_UNREACHABLE = 0x04008, + DAT_ASYNC_ERROR_EVD_OVERFLOW = 0x08001, + DAT_ASYNC_ERROR_IA_CATASTROPHIC = 0x08002, + DAT_ASYNC_ERROR_EP_BROKEN = 0x08003, + DAT_ASYNC_ERROR_TIMED_OUT = 0x08004, + DAT_ASYNC_ERROR_PROVIDER_INTERNAL_ERROR = 0x08005, + DAT_HA_DOWN_TO_1 = 0x08101, + DAT_HA_UP_TO_MULTI_PATH = 0x08102, + + DAT_SOFTWARE_EVENT = 0x10001 +#ifdef DAT_EXTENSIONS + ,DAT_EXTENSION_EVENT = 0x20000, + DAT_IB_EXTENSION_RANGE_BASE = 0x40000, + DAT_IW_EXTENSION_RANGE_BASE = 0x80000 +#endif /* DAT_EXTENSIONS */ + +} DAT_EVENT_NUMBER; + +/* Union for event Data */ + +typedef union dat_event_data +{ + DAT_DTO_COMPLETION_EVENT_DATA dto_completion_event_data; + DAT_RMR_BIND_COMPLETION_EVENT_DATA rmr_completion_event_data; + DAT_CR_ARRIVAL_EVENT_DATA cr_arrival_event_data; + DAT_CONNECTION_EVENT_DATA connect_event_data; + DAT_ASYNCH_ERROR_EVENT_DATA asynch_error_event_data; + DAT_SOFTWARE_EVENT_DATA software_event_data; +} DAT_EVENT_DATA; + +/* Event struct that holds all event information */ + +typedef struct dat_event +{ + DAT_EVENT_NUMBER event_number; + DAT_EVD_HANDLE evd_handle; + DAT_EVENT_DATA event_data; + DAT_UINT64 event_extension_data[8]; +} DAT_EVENT; + +/* Provider/registration info */ + +typedef struct dat_provider_info +{ + char ia_name[DAT_NAME_MAX_LENGTH]; + DAT_UINT32 dapl_version_major; + DAT_UINT32 dapl_version_minor; + DAT_BOOLEAN is_thread_safe; +} DAT_PROVIDER_INFO; + +/*************************************************************** + * + * FUNCTION PROTOTYPES + ***************************************************************/ + +/* + * IA functions + * + * Note that there are actual 'dat_ia_open' and 'dat_ia_close' + * functions, it is not just a re-directing #define. That is + * because the functions may have to ensure that the provider + * library is loaded before it can call it, and may choose to + * unload the library after the last close. + */ + +extern DAT_RETURN DAT_API dat_ia_openv ( + IN const DAT_NAME_PTR, /* provider */ + IN DAT_COUNT, /* asynch_evd_min_qlen */ + INOUT DAT_EVD_HANDLE *, /* asynch_evd_handle */ + OUT DAT_IA_HANDLE *, /* ia_handle */ + IN DAT_UINT32, /* dat major version number */ + IN DAT_UINT32, /* dat minor version number */ + IN DAT_BOOLEAN); /* dat thread safety */ + +#define dat_ia_open(name, qlen, async_evd, ia) \ + dat_ia_openv((name), (qlen), (async_evd), (ia), \ + DAT_VERSION_MAJOR, DAT_VERSION_MINOR, \ + DAT_THREADSAFE) + +extern DAT_RETURN DAT_API dat_ia_query ( + IN DAT_IA_HANDLE, /* ia_handle */ + OUT DAT_EVD_HANDLE *, /* async_evd_handle */ + IN DAT_IA_ATTR_MASK, /* ia_attr_mask */ + OUT DAT_IA_ATTR *, /* ia_attr */ + IN DAT_PROVIDER_ATTR_MASK, /* provider_attr_mask */ + OUT DAT_PROVIDER_ATTR * ); /* provider_attr */ + +extern DAT_RETURN DAT_API dat_ia_close ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_CLOSE_FLAGS ); /* close_flags */ + +/* helper functions */ + +extern DAT_RETURN DAT_API dat_set_consumer_context ( + IN DAT_HANDLE, /* dat_handle */ + IN DAT_CONTEXT); /* context */ + +extern DAT_RETURN DAT_API dat_get_consumer_context ( + IN DAT_HANDLE, /* dat_handle */ + OUT DAT_CONTEXT * ); /* context */ + +extern DAT_RETURN DAT_API dat_get_handle_type ( + IN DAT_HANDLE, /* dat_handle */ + OUT DAT_HANDLE_TYPE * ); /* handle_type */ + +/* CR functions */ + +extern DAT_RETURN DAT_API dat_cr_query ( + IN DAT_CR_HANDLE, /* cr_handle */ + IN DAT_CR_PARAM_MASK, /* cr_param_mask */ + OUT DAT_CR_PARAM * ); /* cr_param */ + +extern DAT_RETURN DAT_API dat_cr_accept ( + IN DAT_CR_HANDLE, /* cr_handle */ + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_COUNT, /* private_data_size */ + IN const DAT_PVOID ); /* private_data */ + +extern DAT_RETURN DAT_API dat_cr_reject ( + IN DAT_CR_HANDLE, /* cr_handle */ + IN DAT_COUNT, /* private_data_size */ + IN const DAT_PVOID ); /* private_data */ + +/* For DAT-1.1 and above, this function is defined for both uDAPL and + * kDAPL. For DAT-1.0, it is only defined for uDAPL. + */ +extern DAT_RETURN DAT_API dat_cr_handoff ( + IN DAT_CR_HANDLE, /* cr_handle */ + IN DAT_CONN_QUAL); /* handoff */ + +/* EVD functions */ + +extern DAT_RETURN DAT_API dat_evd_resize ( + IN DAT_EVD_HANDLE, /* evd_handle */ + IN DAT_COUNT ); /* evd_min_qlen */ + +extern DAT_RETURN DAT_API dat_evd_post_se ( + IN DAT_EVD_HANDLE, /* evd_handle */ + IN const DAT_EVENT * ); /* event */ + +extern DAT_RETURN DAT_API dat_evd_dequeue ( + IN DAT_EVD_HANDLE, /* evd_handle */ + OUT DAT_EVENT * ); /* event */ + +extern DAT_RETURN DAT_API dat_evd_query ( + IN DAT_EVD_HANDLE, /* evd_handle */ + IN DAT_EVD_PARAM_MASK, /* evd_param_mask */ + OUT DAT_EVD_PARAM * ); /* evd_param */ + +extern DAT_RETURN DAT_API dat_evd_free ( + IN DAT_EVD_HANDLE ); /* evd_handle */ + +/* EP functions */ + +extern DAT_RETURN DAT_API dat_ep_create ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_PZ_HANDLE, /* pz_handle */ + IN DAT_EVD_HANDLE, /* recv_completion_evd_handle */ + IN DAT_EVD_HANDLE, /* request_completion_evd_handle */ + IN DAT_EVD_HANDLE, /* connect_evd_handle */ + IN const DAT_EP_ATTR *, /* ep_attributes */ + OUT DAT_EP_HANDLE * ); /* ep_handle */ + +extern DAT_RETURN DAT_API dat_ep_query ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_EP_PARAM_MASK, /* ep_param_mask */ + OUT DAT_EP_PARAM * ); /* ep_param */ + +extern DAT_RETURN DAT_API dat_ep_modify ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_EP_PARAM_MASK, /* ep_param_mask */ + IN const DAT_EP_PARAM * ); /* ep_param */ + +extern DAT_RETURN DAT_API dat_ep_connect ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_IA_ADDRESS_PTR, /* remote_ia_address */ + IN DAT_CONN_QUAL, /* remote_conn_qual */ + IN DAT_TIMEOUT, /* timeout */ + IN DAT_COUNT, /* private_data_size */ + IN const DAT_PVOID, /* private_data */ + IN DAT_QOS, /* quality_of_service */ + IN DAT_CONNECT_FLAGS ); /* connect_flags */ + +extern DAT_RETURN DAT_API dat_ep_dup_connect ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_EP_HANDLE, /* ep_dup_handle */ + IN DAT_TIMEOUT, /* timeout */ + IN DAT_COUNT, /* private_data_size */ + IN const DAT_PVOID, /* private_data */ + IN DAT_QOS); /* quality_of_service */ + +extern DAT_RETURN DAT_API dat_ep_common_connect ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_IA_ADDRESS_PTR, /* remote_ia_address */ + IN DAT_TIMEOUT, /* timeout */ + IN DAT_COUNT, /* private_data_size */ + IN const DAT_PVOID ); /* private_data */ + +extern DAT_RETURN DAT_API dat_ep_disconnect ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_CLOSE_FLAGS ); /* close_flags */ + +extern DAT_RETURN DAT_API dat_ep_post_send ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_COUNT, /* num_segments */ + IN DAT_LMR_TRIPLET *, /* local_iov */ + IN DAT_DTO_COOKIE, /* user_cookie */ + IN DAT_COMPLETION_FLAGS ); /* completion_flags */ + +extern DAT_RETURN DAT_API dat_ep_post_send_with_invalidate ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_COUNT, /* num_segments */ + IN DAT_LMR_TRIPLET *, /* local_iov */ + IN DAT_DTO_COOKIE, /* user_cookie */ + IN DAT_COMPLETION_FLAGS, /* completion_flags */ + IN DAT_BOOLEAN, /* invalidate_flag */ + IN DAT_RMR_CONTEXT ); /* RMR to invalidate */ + +extern DAT_RETURN DAT_API dat_ep_post_recv ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_COUNT, /* num_segments */ + IN DAT_LMR_TRIPLET *, /* local_iov */ + IN DAT_DTO_COOKIE, /* user_cookie */ + IN DAT_COMPLETION_FLAGS ); /* completion_flags */ + +extern DAT_RETURN DAT_API dat_ep_post_rdma_read ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_COUNT, /* num_segments */ + IN DAT_LMR_TRIPLET *, /* local_iov */ + IN DAT_DTO_COOKIE, /* user_cookie */ + IN const DAT_RMR_TRIPLET *,/* remote_iov */ + IN DAT_COMPLETION_FLAGS ); /* completion_flags */ + +extern DAT_RETURN DAT_API dat_ep_post_rdma_read_to_rmr ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN const DAT_RMR_TRIPLET *, /* local_iov */ + IN DAT_DTO_COOKIE, /* user_cookie */ + IN const DAT_RMR_TRIPLET *,/* remote_iov */ + IN DAT_COMPLETION_FLAGS ); /* completion_flags */ + +extern DAT_RETURN DAT_API dat_ep_post_rdma_write ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_COUNT, /* num_segments */ + IN DAT_LMR_TRIPLET *, /* local_iov */ + IN DAT_DTO_COOKIE, /* user_cookie */ + IN const DAT_RMR_TRIPLET *,/* remote_iov */ + IN DAT_COMPLETION_FLAGS ); /* completion_flags */ + +extern DAT_RETURN DAT_API dat_ep_get_status ( + IN DAT_EP_HANDLE, /* ep_handle */ + OUT DAT_EP_STATE *, /* ep_state */ + OUT DAT_BOOLEAN *, /* recv_idle */ + OUT DAT_BOOLEAN * ); /* request_idle */ + +extern DAT_RETURN DAT_API dat_ep_free ( + IN DAT_EP_HANDLE); /* ep_handle */ + +extern DAT_RETURN DAT_API dat_ep_reset ( + IN DAT_EP_HANDLE); /* ep_handle */ + +extern DAT_RETURN DAT_API dat_ep_create_with_srq ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_PZ_HANDLE, /* pz_handle */ + IN DAT_EVD_HANDLE, /* recv_evd_handle */ + IN DAT_EVD_HANDLE, /* request_evd_handle */ + IN DAT_EVD_HANDLE, /* connect_evd_handle */ + IN DAT_SRQ_HANDLE, /* srq_handle */ + IN const DAT_EP_ATTR *, /* ep_attributes */ + OUT DAT_EP_HANDLE *); /* ep_handle */ + +extern DAT_RETURN DAT_API dat_ep_recv_query ( + IN DAT_EP_HANDLE, /* ep_handle */ + OUT DAT_COUNT *, /* nbufs_allocated */ + OUT DAT_COUNT *); /* bufs_alloc_span */ + +extern DAT_RETURN DAT_API dat_ep_set_watermark ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_COUNT, /* soft_high_watermark */ + IN DAT_COUNT); /* hard_high_watermark */ + +/* LMR functions */ + +extern DAT_RETURN DAT_API dat_lmr_free ( + IN DAT_LMR_HANDLE); /* lmr_handle */ + +/* Non-coherent memory functions */ + +extern DAT_RETURN DAT_API dat_lmr_sync_rdma_read ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN const DAT_LMR_TRIPLET *, /* local_segments */ + IN DAT_VLEN); /* num_segments */ + +extern DAT_RETURN DAT_API dat_lmr_sync_rdma_write ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN const DAT_LMR_TRIPLET *, /* local_segments */ + IN DAT_VLEN); /* num_segments */ + +/* RMR functions */ + +extern DAT_RETURN DAT_API dat_rmr_create ( + IN DAT_PZ_HANDLE, /* pz_handle */ + OUT DAT_RMR_HANDLE *); /* rmr_handle */ + +extern DAT_RETURN DAT_API dat_rmr_create_for_ep ( + IN DAT_PZ_HANDLE, /* pz_handle */ + OUT DAT_RMR_HANDLE *); /* rmr_handle */ + +extern DAT_RETURN DAT_API dat_rmr_query ( + IN DAT_RMR_HANDLE, /* rmr_handle */ + IN DAT_RMR_PARAM_MASK, /* rmr_param_mask */ + OUT DAT_RMR_PARAM *); /* rmr_param */ + +extern DAT_RETURN DAT_API dat_rmr_bind ( + IN DAT_RMR_HANDLE, /* rmr_handle */ + IN DAT_LMR_HANDLE, /* lmr_handle */ + IN const DAT_LMR_TRIPLET *,/* lmr_triplet */ + IN DAT_MEM_PRIV_FLAGS, /* mem_priv */ + IN DAT_VA_TYPE, /* va_type */ + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_RMR_COOKIE, /* user_cookie */ + IN DAT_COMPLETION_FLAGS, /* completion_flags */ + OUT DAT_RMR_CONTEXT * ); /* context */ + +extern DAT_RETURN DAT_API dat_rmr_free ( + IN DAT_RMR_HANDLE); /* rmr_handle */ + +/* PSP functions */ + +extern DAT_RETURN DAT_API dat_psp_create ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_CONN_QUAL, /* conn_qual */ + IN DAT_EVD_HANDLE, /* evd_handle */ + IN DAT_PSP_FLAGS, /* psp_flags */ + OUT DAT_PSP_HANDLE * ); /* psp_handle */ + +extern DAT_RETURN DAT_API dat_psp_create_any ( + IN DAT_IA_HANDLE, /* ia_handle */ + OUT DAT_CONN_QUAL *, /* conn_qual */ + IN DAT_EVD_HANDLE, /* evd_handle */ + IN DAT_PSP_FLAGS, /* psp_flags */ + OUT DAT_PSP_HANDLE * ); /* psp_handle */ + +extern DAT_RETURN DAT_API dat_psp_query ( + IN DAT_PSP_HANDLE, /* psp_handle */ + IN DAT_PSP_PARAM_MASK, /* psp_param_mask */ + OUT DAT_PSP_PARAM * ); /* psp_param */ + +extern DAT_RETURN DAT_API dat_psp_free ( + IN DAT_PSP_HANDLE ); /* psp_handle */ + +/* RSP functions */ + +extern DAT_RETURN DAT_API dat_rsp_create ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_CONN_QUAL, /* conn_qual */ + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_EVD_HANDLE, /* evd_handle */ + OUT DAT_RSP_HANDLE * ); /* rsp_handle */ + +extern DAT_RETURN DAT_API dat_rsp_query ( + IN DAT_RSP_HANDLE, /* rsp_handle */ + IN DAT_RSP_PARAM_MASK, /* rsp_param_mask */ + OUT DAT_RSP_PARAM * ); /* rsp_param */ + +extern DAT_RETURN DAT_API dat_rsp_free ( + IN DAT_RSP_HANDLE ); /* rsp_handle */ + +/* CSP functions */ + +extern DAT_RETURN DAT_API dat_csp_create ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_COMM *, /* communicator */ + IN DAT_IA_ADDRESS_PTR, /* address */ + IN DAT_EVD_HANDLE, /* evd_handle */ + OUT DAT_CSP_HANDLE * ); /* csp_handle */ + +extern DAT_RETURN DAT_API dat_csp_query ( + IN DAT_CSP_HANDLE, /* csp_handle */ + IN DAT_CSP_PARAM_MASK, /* csp_param_mask */ + OUT DAT_CSP_PARAM * ); /* csp_param */ + +extern DAT_RETURN DAT_API dat_csp_free ( + IN DAT_CSP_HANDLE ); /* csp_handle */ + +/* PZ functions */ + +extern DAT_RETURN DAT_API dat_pz_create ( + IN DAT_IA_HANDLE, /* ia_handle */ + OUT DAT_PZ_HANDLE * ); /* pz_handle */ + +extern DAT_RETURN DAT_API dat_pz_query ( + IN DAT_PZ_HANDLE, /* pz_handle */ + IN DAT_PZ_PARAM_MASK, /* pz_param_mask */ + OUT DAT_PZ_PARAM *); /* pz_param */ + +extern DAT_RETURN DAT_API dat_pz_free ( + IN DAT_PZ_HANDLE ); /* pz_handle */ + +/* SRQ functions */ + +extern DAT_RETURN DAT_API dat_srq_create ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_PZ_HANDLE, /* pz_handle */ + IN DAT_SRQ_ATTR *, /* srq_attr */ + OUT DAT_SRQ_HANDLE *); /* srq_handle */ + +extern DAT_RETURN DAT_API dat_srq_free ( + IN DAT_SRQ_HANDLE); /* srq_handle */ + +extern DAT_RETURN DAT_API dat_srq_post_recv ( + IN DAT_SRQ_HANDLE, /* srq_handle */ + IN DAT_COUNT, /* num_segments */ + IN DAT_LMR_TRIPLET *, /* local_iov */ + IN DAT_DTO_COOKIE); /* user_cookie */ + +extern DAT_RETURN DAT_API dat_srq_query ( + IN DAT_SRQ_HANDLE, /* srq_handle */ + IN DAT_SRQ_PARAM_MASK, /* srq_param_mask */ + OUT DAT_SRQ_PARAM *); /* srq_param */ + +extern DAT_RETURN DAT_API dat_srq_resize ( + IN DAT_SRQ_HANDLE, /* srq_handle */ + IN DAT_COUNT); /* srq_max_recv_dto */ + +extern DAT_RETURN DAT_API dat_srq_set_lw ( + IN DAT_SRQ_HANDLE, /* srq_handle */ + IN DAT_COUNT); /* low_watermark */ + +#ifdef DAT_EXTENSIONS +typedef int DAT_EXTENDED_OP; +extern DAT_RETURN DAT_API dat_extension_op( + IN DAT_HANDLE, /* handle */ + IN DAT_EXTENDED_OP, /* operation */ + IN ... ); /* args */ +#endif + +/* + * DAT registry functions. + * + * Note the dat_ia_open and dat_ia_close functions are linked to + * registration code which "redirects" to the appropriate provider. + */ +extern DAT_RETURN DAT_API dat_registry_list_providers ( + IN DAT_COUNT, /* max_to_return */ + OUT DAT_COUNT *, /* entries_returned */ + OUT DAT_PROVIDER_INFO *(dat_provider_list[]) ); /* dat_provider_list */ + +/* + * DAT error functions. + */ +extern DAT_RETURN DAT_API dat_strerror ( + IN DAT_RETURN, /* dat function return */ + OUT const char ** , /* major message string */ + OUT const char ** ); /* minor message string */ + +#ifdef __cplusplus +} +#endif + +#endif /* _DAT_H_ */ + diff --git a/branches/WOF2-3/ulp/dapl2/dat/include/dat2/dat_error.h b/branches/WOF2-3/ulp/dapl2/dat/include/dat2/dat_error.h new file mode 100644 index 00000000..251e6c4f --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dat/include/dat2/dat_error.h @@ -0,0 +1,380 @@ +/* + * Copyright (c) 2002-2006, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under all of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * Redistributions of source code must retain both 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. + * + * Neither the name of Network Appliance, Inc. nor the names of other DAT + * Collaborative contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + */ + +/*********************************************************** + * + * HEADER: dat_error.h + * + * PURPOSE: DAT return codes + * + * Description: Header file for "DAPL: Direct Access Programming + * Library, Version: 2.0" + * + * Mapping rules: + * Error types are compound types, as mapped out below. + * + *********************************************************/ + +#ifndef _DAT_ERROR_H_ +#define _DAT_ERROR_H_ + +/* + * + * All return codes are actually a 3-way tuple: + * + * type: DAT_RETURN_CLASS DAT_RETURN_TYPE DAT_RETURN_SUBTYPE + * bits: 31-30 29-16 15-0 + * + * 3 2 1 + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | C | DAT_RETURN_TYPE | DAT_RETURN_SUBTYPE | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + */ + +/* + * Class Bits + */ +#define DAT_CLASS_ERROR 0x80000000 +#define DAT_CLASS_WARNING 0x40000000 +#define DAT_CLASS_SUCCESS 0x00000000 +/* + * DAT Error bits + */ +#define DAT_TYPE_MASK 0x3fff0000 /* mask for DAT_TYPE_STATUS bits */ +#define DAT_SUBTYPE_MASK 0x0000FFFF /* mask for DAT_SUBTYPE_STATUS bits */ + +/* + * Determining the success of an operation is best done with a macro; + * each of these returns a boolean value. + */ +#define DAT_IS_WARNING(status) ((DAT_UINT32)(status) & DAT_CLASS_WARNING) + +#define DAT_GET_TYPE(status) ((DAT_UINT32)(status) & DAT_TYPE_MASK) +#define DAT_GET_SUBTYPE(status) ((DAT_UINT32)(status) & DAT_SUBTYPE_MASK) + +/* + * DAT return types. The ERROR bit is enabled for these definitions + */ +typedef enum dat_return_type +{ + /* The operation was successful. */ + DAT_SUCCESS = 0x00000000, + + /* The operation was aborted because IA was closed or EVD was * + * destroyed. */ + DAT_ABORT = 0x00010000, + + /* The specified Connection Qualifier was in use. */ + DAT_CONN_QUAL_IN_USE = 0x00020000, + + /* The operation failed due to resource limitations. */ + DAT_INSUFFICIENT_RESOURCES = 0x00030000, + + /* Provider internal error. This error can be returned by any * + * operation when the Provider has detected an internal error.* + * This error does not mask any error caused by the Consumer. */ + DAT_INTERNAL_ERROR = 0x00040000, + + /* One of the DAT handles was invalid. */ + DAT_INVALID_HANDLE = 0x00050000, + + /* One of the parameters was invalid. */ + DAT_INVALID_PARAMETER = 0x00060000, + + /* One of the parameters was invalid for this operation. There* + * are Event Streams associated with the Event Dispatcher * + * feeding it. */ + DAT_INVALID_STATE = 0x00070000, + + /* The size of the receiving buffer is too small for sending * + * buffer data. The size of the local buffer is too small for* + * the data of the remote buffer. */ + DAT_LENGTH_ERROR = 0x00080000, + + /* The requested Model was not supported by the Provider. */ + DAT_MODEL_NOT_SUPPORTED = 0x00090000, + + /* The specified IA name was not found in the list of * + * registered Providers. */ + DAT_PROVIDER_NOT_FOUND = 0x000A0000, + + /* Protection violation for local or remote memory access * + * Protection Zone mismatch between an LMR of one of the * + * local_iov segments and the local Endpoint. */ + DAT_PRIVILEGES_VIOLATION = 0x000B0000, + + /* Privileges violation for local or remote memory access. One* + * of the LMRs used in local_iov was either invalid or did not* + * have local read privileges. */ + DAT_PROTECTION_VIOLATION = 0x000C0000, + + /* The operation timed out without a notification. */ + DAT_QUEUE_EMPTY = 0x000D0000, + + /* The Event Dispatcher queue is full. */ + DAT_QUEUE_FULL = 0x000E0000, + + /* The operation timed out. uDAPL ONLY */ + DAT_TIMEOUT_EXPIRED = 0x000F0000, + + /* The provider name was already registered */ + DAT_PROVIDER_ALREADY_REGISTERED = 0x00100000, + + /* The provider is "in-use" and cannot be closed at this time */ + DAT_PROVIDER_IN_USE = 0x00110000, + + /* The requested remote address is not valid or not reachable */ + DAT_INVALID_ADDRESS = 0x00120000, + + /* [Unix only] dat_evd_wait or dat_cno_wait has been * + * interrupted. */ + DAT_INTERRUPTED_CALL = 0x00130000, + + /* No Connection Qualifiers are available */ + DAT_CONN_QUAL_UNAVAILABLE = 0x00140000, + + /* kDAPL reserved LMR */ + DAT_RESERVED_LMR = 0x00150000, /* kdapl only */ + + /* The specified IP Port was in use. */ + DAT_PORT_IN_USE = 0x00160000, + /* The specified COMM not supported. */ + DAT_COMM_NOT_SUPPORTED = 0x00170000, + +#ifdef DAT_EXTENSIONS + /* The DAT extensions support. */ + DAT_EXTENSION_BASE = 0x10000000, + /* range 0x10000000 - 0x3FFF0000 is reserved for extensions */ +#endif /* DAT_EXTENSIONS */ + + /* Provider does not support the operation yet. */ + DAT_NOT_IMPLEMENTED = 0x3FFF0000 +} DAT_RETURN_TYPE; + +typedef DAT_UINT32 DAT_RETURN; + +/* Backward compatibility with DAT 1.0 */ +#define DAT_NAME_NOT_FOUND DAT_PROVIDER_NOT_FOUND + +/* + * DAT_RETURN_SUBTYPE listing + */ + +typedef enum dat_return_subtype +{ + /* First element is no subtype */ + DAT_NO_SUBTYPE, + /* ABORT sub types */ + /* call was interrupted by a signal, or otherwise */ + DAT_SUB_INTERRUPTED, + + /* DAT_CONN_QUAL_IN_USE has no subtypes */ + + /* INSUFFICIENT_RESOURCES subtypes */ + DAT_RESOURCE_MEMORY, + DAT_RESOURCE_DEVICE, + DAT_RESOURCE_TEP, /* transport endpoint, e.g. QP */ + DAT_RESOURCE_TEVD, /* transport EVD, e.g. CQ */ + DAT_RESOURCE_PROTECTION_DOMAIN, + DAT_RESOURCE_MEMORY_REGION, /* HCA memory for LMR or RMR */ + DAT_RESOURCE_ERROR_HANDLER, + DAT_RESOURCE_CREDITS, /* e.g outstanding RDMA Read credit as target */ + DAT_RESOURCE_SRQ, + + /* DAT_INTERNAL_ERROR has no subtypes */ + + /* INVALID_HANDLE subtypes */ + + DAT_INVALID_HANDLE_IA, + DAT_INVALID_HANDLE_EP, + DAT_INVALID_HANDLE_LMR, + DAT_INVALID_HANDLE_RMR, + DAT_INVALID_HANDLE_PZ, + DAT_INVALID_HANDLE_PSP, + DAT_INVALID_HANDLE_RSP, + DAT_INVALID_HANDLE_CR, + DAT_INVALID_HANDLE_CNO, + DAT_INVALID_HANDLE_EVD_CR, + DAT_INVALID_HANDLE_EVD_REQUEST, + DAT_INVALID_HANDLE_EVD_RECV, + DAT_INVALID_HANDLE_EVD_CONN, + DAT_INVALID_HANDLE_EVD_ASYNC, + DAT_INVALID_HANDLE_SRQ, + DAT_INVALID_HANDLE_CSP, + DAT_INVALID_HANDLE1, + DAT_INVALID_HANDLE2, + DAT_INVALID_HANDLE3, + DAT_INVALID_HANDLE4, + DAT_INVALID_HANDLE5, + DAT_INVALID_HANDLE6, + DAT_INVALID_HANDLE7, + DAT_INVALID_HANDLE8, + DAT_INVALID_HANDLE9, + DAT_INVALID_HANDLE10, + + /* DAT_INVALID_PARAMETER subtypes */ + DAT_INVALID_ARG1, + DAT_INVALID_ARG2, + DAT_INVALID_ARG3, + DAT_INVALID_ARG4, + DAT_INVALID_ARG5, + DAT_INVALID_ARG6, + DAT_INVALID_ARG7, + DAT_INVALID_ARG8, + DAT_INVALID_ARG9, + DAT_INVALID_ARG10, + + /* DAT_INVALID_EP_STATE subtypes */ + DAT_INVALID_STATE_EP_UNCONNECTED, + DAT_INVALID_STATE_EP_ACTCONNPENDING, + DAT_INVALID_STATE_EP_PASSCONNPENDING, + DAT_INVALID_STATE_EP_TENTCONNPENDING, + DAT_INVALID_STATE_EP_CONNECTED, + DAT_INVALID_STATE_EP_DISCONNECTED, + DAT_INVALID_STATE_EP_RESERVED, + DAT_INVALID_STATE_EP_COMPLPENDING, + DAT_INVALID_STATE_EP_DISCPENDING, + DAT_INVALID_STATE_EP_PROVIDERCONTROL, + DAT_INVALID_STATE_EP_NOTREADY, + DAT_INVALID_STATE_EP_RECV_WATERMARK, + DAT_INVALID_STATE_EP_PZ, + DAT_INVALID_STATE_EP_EVD_REQUEST, + DAT_INVALID_STATE_EP_EVD_RECV, + DAT_INVALID_STATE_EP_EVD_CONNECT, + DAT_INVALID_STATE_EP_UNCONFIGURED, + DAT_INVALID_STATE_EP_UNCONFRESERVED, + DAT_INVALID_STATE_EP_UNCONFPASSIVE, + DAT_INVALID_STATE_EP_UNCONFTENTATIVE, + DAT_INVALID_STATE_CNO_IN_USE, + DAT_INVALID_STATE_CNO_DEAD, + + /* EVD states. Enabled/Disabled, Waitable/Unwaitable, * + * and Notify/Solicited/Threshold are 3 orthogonal * + * bands of EVD state.The Threshold one is uDAPL specific. */ + DAT_INVALID_STATE_EVD_OPEN, + /* EVD can be either in enabled or disabled but not both * + * or neither at the same time */ + DAT_INVALID_STATE_EVD_ENABLED, + DAT_INVALID_STATE_EVD_DISABLED, + /* EVD can be either in waitable or unwaitable but not * + * both or neither at the same time */ + DAT_INVALID_STATE_EVD_WAITABLE, + DAT_INVALID_STATE_EVD_UNWAITABLE, + /* Do not release an EVD if it is in use */ + DAT_INVALID_STATE_EVD_IN_USE, + + /* EVD can be either in notify or solicited or threshold * + * but not any pair, or all, or none at the same time. * + * The threshold one is for uDAPL only */ + DAT_INVALID_STATE_EVD_CONFIG_NOTIFY, + DAT_INVALID_STATE_EVD_CONFIG_SOLICITED, + DAT_INVALID_STATE_EVD_CONFIG_THRESHOLD, + DAT_INVALID_STATE_EVD_WAITER, + DAT_INVALID_STATE_EVD_ASYNC, /* Async EVD required */ + DAT_INVALID_STATE_IA_IN_USE, + DAT_INVALID_STATE_LMR_IN_USE, + DAT_INVALID_STATE_LMR_FREE, + DAT_INVALID_STATE_PZ_IN_USE, + DAT_INVALID_STATE_PZ_FREE, + + /* DAT_INVALID_STATE_SRQ subtypes */ + DAT_INVALID_STATE_SRQ_OPERATIONAL, + DAT_INVALID_STATE_SRQ_ERROR, + DAT_INVALID_STATE_SRQ_IN_USE, + + /* DAT_LENGTH_ERROR has no subtypes */ + + /* DAT_MODEL_NOT_SUPPORTED has no subtypes */ + + /* DAT_PRIVILEGES_VIOLATION subtypes */ + DAT_PRIVILEGES_READ, + DAT_PRIVILEGES_WRITE, + DAT_PRIVILEGES_RDMA_READ, + DAT_PRIVILEGES_RDMA_WRITE, + + /* DAT_PROTECTION_VIOLATION subtypes */ + DAT_PROTECTION_READ, + DAT_PROTECTION_WRITE, + DAT_PROTECTION_RDMA_READ, + DAT_PROTECTION_RDMA_WRITE, + + /* DAT_QUEUE_EMPTY has no subtypes */ + + /* DAT_QUEUE_FULL has no subtypes */ + + /* DAT_TIMEOUT_EXPIRED has no subtypes */ + + /* DAT_PROVIDER_ALREADY_REGISTERED has no subtypes */ + + /* DAT_PROVIDER_IN_USE has no subtypes */ + + /* DAT_INVALID_ADDRESS subtypes */ + + /* Unsupported addresses - those that are not Malformed, but * + * are incorrect for use in DAT (regardless of local routing * + * capabilities): IPv6 Multicast Addresses (ff/8) IPv4 * + * Broadcast/Multicast Addresses */ + + DAT_INVALID_ADDRESS_UNSUPPORTED, + /* Unreachable addresses - A Provider might know that certain * + * addresses are unreachable immediately. One example would be * + * an IPv6 addresses on an IPv4-only system. This can also be * + * returned if it is known that there is no route to the host. * + * A Provider is not obligated to check for this condition. */ + DAT_INVALID_ADDRESS_UNREACHABLE, + /* Malformed addresses -- these cannot be valid in any context.* + * Those listed in RFC1884 section 2.3 as "Reserved" or * + * "Unassigned". */ + DAT_INVALID_ADDRESS_MALFORMED, + + /* DAT_INTERRUPTED_CALL has no subtypes */ + + /* DAT_CONN_QUAL_UNAVAILABLE has no subtypes */ + + /* DAT_PROVIDER_NOT_FOUND subtypes. Erratta to the 1.1 spec */ + + DAT_NAME_NOT_REGISTERED, + DAT_MAJOR_NOT_FOUND, + DAT_MINOR_NOT_FOUND, + DAT_THREAD_SAFETY_NOT_FOUND +} DAT_RETURN_SUBTYPE; + +#endif /* _DAT_ERROR_H_ */ diff --git a/branches/WOF2-3/ulp/dapl2/dat/include/dat2/dat_ib_extensions.h b/branches/WOF2-3/ulp/dapl2/dat/include/dat2/dat_ib_extensions.h new file mode 100644 index 00000000..a32a4ed1 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dat/include/dat2/dat_ib_extensions.h @@ -0,0 +1,510 @@ +/* + * Copyright (c) 2007 Intel Corporation. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dat_ib_extensions.h + * + * PURPOSE: extensions to the DAT API for IB transport specific services + * NOTE: Prototyped IB extension support in openib-cma 1.2 provider. + * Applications MUST recompile with new dat.h definitions + * and include this file. + * + * Description: Header file for "uDAPL: User Direct Access Programming + * Library, Version: 2.0" + * + * Mapping rules: + * All global symbols are prepended with "DAT_" or "dat_" + * All DAT objects have an 'api' tag which, such as 'ep' or 'lmr' + * The method table is in the provider definition structure. + * + * + **********************************************************************/ +#ifndef _DAT_IB_EXTENSIONS_H_ +#define _DAT_IB_EXTENSIONS_H_ + +/* + * Provider specific attribute strings for extension support + * returned with dat_ia_query() and + * DAT_PROVIDER_ATTR_MASK == DAT_PROVIDER_FIELD_PROVIDER_SPECIFIC_ATTR + * + * DAT_NAMED_ATTR name == extended operations and version, + * version_value = version number of extension API + */ + +/* 2.0.1 - Initial IB extension support, atomic and immed data + * dat_ib_post_fetch_and_add() + * dat_ib_post_cmp_and_swap() + * dat_ib_post_rdma_write_immed() + * + * 2.0.2 - Add UD support, post send and remote_ah via connect events + * dat_ib_post_send_ud() + * + * 2.0.3 - Add query/print counter support for IA, EP, and EVD's + * dat_query_counters(), dat_print_counters() + * + * 2.0.4 - Add DAT_IB_UD_CONNECTION_REJECT_EVENT extended UD event + * 2.0.5 - Add DAT_IB_UD extended UD connection error events + * + */ +#define DAT_IB_EXTENSION_VERSION 205 /* 2.0.5 */ +#define DAT_ATTR_COUNTERS "DAT_COUNTERS" +#define DAT_IB_ATTR_FETCH_AND_ADD "DAT_IB_FETCH_AND_ADD" +#define DAT_IB_ATTR_CMP_AND_SWAP "DAT_IB_CMP_AND_SWAP" +#define DAT_IB_ATTR_IMMED_DATA "DAT_IB_IMMED_DATA" +#define DAT_IB_ATTR_UD "DAT_IB_UD" + +/* + * Definition for extended EVENT numbers, DAT_IB_EXTENSION_BASE_RANGE + * is used by these extensions as a starting point for extended event numbers + * + * DAT_IB_DTO_EVENT - All extended data transfers - req/recv evd + * DAT_IB_AH_EVENT - address handle resolution - connect evd + */ +typedef enum dat_ib_event_number +{ + DAT_IB_DTO_EVENT = DAT_IB_EXTENSION_RANGE_BASE, + DAT_IB_UD_CONNECTION_REQUEST_EVENT, + DAT_IB_UD_CONNECTION_EVENT_ESTABLISHED, + DAT_IB_UD_CONNECTION_REJECT_EVENT, + DAT_IB_UD_CONNECTION_ERROR_EVENT + +} DAT_IB_EVENT_NUMBER; + +/* + * Extension operations + */ +typedef enum dat_ib_op +{ + DAT_IB_FETCH_AND_ADD_OP, + DAT_IB_CMP_AND_SWAP_OP, + DAT_IB_RDMA_WRITE_IMMED_OP, + DAT_IB_UD_SEND_OP, + DAT_QUERY_COUNTERS_OP, + DAT_PRINT_COUNTERS_OP + +} DAT_IB_OP; + +/* + * The DAT_IB_EXT_TYPE enum specifies the type of extension operation that just + * completed. All IB extended completion types both, DTO and NON-DTO, are + * reported in the extended operation type with the single DAT_IB_DTO_EVENT type. + * The specific extended DTO operation is reported with a DAT_IB_DTOS type in the + * operation field of the base DAT_EVENT structure. All other extended events are + * identified by unique DAT_IB_EVENT_NUMBER types. + */ +typedef enum dat_ib_ext_type +{ + DAT_IB_FETCH_AND_ADD, // 0 + DAT_IB_CMP_AND_SWAP, // 1 + DAT_IB_RDMA_WRITE_IMMED, // 2 + DAT_IB_RDMA_WRITE_IMMED_DATA, // 3 + DAT_IB_RECV_IMMED_DATA, // 4 + DAT_IB_UD_CONNECT_REQUEST, // 5 + DAT_IB_UD_REMOTE_AH, // 6 + DAT_IB_UD_PASSIVE_REMOTE_AH, // 7 + DAT_IB_UD_SEND, // 8 + DAT_IB_UD_RECV, // 9 + DAT_IB_UD_CONNECT_REJECT, // 10 + DAT_IB_UD_CONNECT_ERROR, // 11 + +} DAT_IB_EXT_TYPE; + +/* + * Extension event status + */ +typedef enum dat_ib_status +{ + DAT_OP_SUCCESS = DAT_SUCCESS, + DAT_IB_OP_ERR, + +} DAT_IB_STATUS; + + +/* + * Definitions for additional extension type RETURN codes above + * standard DAT types. Included with standard DAT_TYPE_STATUS + * bits using a DAT_EXTENSION BASE as a starting point. + */ +typedef enum dat_ib_return +{ + DAT_IB_ERR = DAT_EXTENSION_BASE, + +} DAT_IB_RETURN; + +/* + * Definition for extended IB DTO operations, DAT_DTO_EXTENSION_BASE + * is used by DAT extensions as a starting point of extension DTOs + */ +typedef enum dat_ib_dtos +{ + DAT_IB_DTO_RDMA_WRITE_IMMED = DAT_DTO_EXTENSION_BASE, + DAT_IB_DTO_RECV_IMMED, + DAT_IB_DTO_FETCH_ADD, + DAT_IB_DTO_CMP_SWAP, + DAT_IB_DTO_RECV_MSG_IMMED, + DAT_IB_DTO_SEND_UD, + DAT_IB_DTO_RECV_UD, + DAT_IB_DTO_RECV_UD_IMMED, + +} DAT_IB_DTOS; + +/* + * Definitions for additional extension handle types beyond + * standard DAT handle. New Bit definitions MUST start at + * DAT_HANDLE_TYPE_EXTENSION_BASE + */ +typedef enum dat_ib_handle_type +{ + DAT_IB_HANDLE_TYPE_EXT = DAT_HANDLE_TYPE_EXTENSION_BASE, + +} DAT_IB_HANDLE_TYPE; + +/* + * The DAT_IB_EVD_EXTENSION_FLAGS enum specifies the EVD extension flags that + * do not map directly to existing DAT_EVD_FLAGS. This new EVD flag has been + * added to identify an extended EVD that does not fit the existing stream + * types. + */ +typedef enum dat_ib_evd_extension_flags +{ + DAT_IB_EVD_EXTENSION_FLAG = DAT_EVD_EXTENSION_BASE, + +} DAT_IB_EVD_EXTENSION_FLAGS; + +/* + * Definition for memory privilege extension flags. + * New privileges required for new atomic DTO type extensions. + * New Bit definitions MUST start at DAT_MEM_PRIV_EXTENSION + */ +typedef enum dat_ib_mem_priv_flags +{ + DAT_IB_MEM_PRIV_REMOTE_ATOMIC = DAT_MEM_PRIV_EXTENSION_BASE, + +} DAT_IB_MEM_PRIV_FLAGS; + +/* + * Definition for IB address handle, unreliable datagram. + */ +typedef struct dat_ib_addr_handle +{ + struct ibv_ah *ah; + DAT_UINT32 qpn; + DAT_SOCK_ADDR6 ia_addr; + +} DAT_IB_ADDR_HANDLE; + +/* + * Definitions for extended event data: + * When dat_event->event_number >= DAT_IB_EXTENSION_BASE_RANGE + * then dat_event->extension_data == DAT_IB_EXT_EVENT_DATA type + * and ((DAT_IB_EXT_EVENT_DATA*)dat_event->extension_data)->type + * specifies extension data values. + * NOTE: DAT_IB_EXT_EVENT_DATA cannot exceed 64 bytes as defined by + * "DAT_UINT64 extension_data[8]" in DAT_EVENT (dat.h) + */ +typedef struct dat_ib_immed_data +{ + DAT_UINT32 data; + +} DAT_IB_IMMED_DATA; + +/* + * Definitions for extended event data: + * When dat_event->event_number >= DAT_IB_EXTENSION_BASE_RANGE + * then dat_event->extension_data == DAT_EXTENSION_EVENT_DATA type + * and ((DAT_EXTENSION_EVENT_DATA*)dat_event->extension_data)->type + * specifies extension data values. + * NOTE: DAT_EXTENSION_EVENT_DATA cannot exceed 64 bytes as defined by + * "DAT_UINT64 extension_data[8]" in DAT_EVENT (dat.h) + * + * Provide UD address handles via extended connect establishment. + * ia_addr provided with extended conn events for reference. + */ +typedef struct dat_ib_extension_event_data +{ + DAT_IB_EXT_TYPE type; + DAT_IB_STATUS status; + union { + DAT_IB_IMMED_DATA immed; + } val; + DAT_IB_ADDR_HANDLE remote_ah; + +} DAT_IB_EXTENSION_EVENT_DATA; + +/* + * Definitions for additional extension handle types beyond + * standard DAT handle. New Bit definitions MUST start at + * DAT_HANDLE_TYPE_EXTENSION_BASE + */ +typedef enum dat_ib_service_type +{ + DAT_IB_SERVICE_TYPE_UD = DAT_SERVICE_TYPE_EXTENSION_BASE, + +} DAT_IB_SERVICE_TYPE; + +/* + * Definitions for 64-bit IA Counters + */ +typedef enum dat_ia_counters +{ + DCNT_IA_PZ_CREATE, + DCNT_IA_PZ_FREE, + DCNT_IA_LMR_CREATE, + DCNT_IA_LMR_FREE, + DCNT_IA_RMR_CREATE, + DCNT_IA_RMR_FREE, + DCNT_IA_PSP_CREATE, + DCNT_IA_PSP_CREATE_ANY, + DCNT_IA_PSP_FREE, + DCNT_IA_RSP_CREATE, + DCNT_IA_RSP_FREE, + DCNT_IA_EVD_CREATE, + DCNT_IA_EVD_FREE, + DCNT_IA_EP_CREATE, + DCNT_IA_EP_FREE, + DCNT_IA_SRQ_CREATE, + DCNT_IA_SRQ_FREE, + DCNT_IA_SP_CR, + DCNT_IA_SP_CR_ACCEPTED, + DCNT_IA_SP_CR_REJECTED, + DCNT_IA_MEM_ALLOC, + DCNT_IA_MEM_ALLOC_DATA, + DCNT_IA_MEM_FREE, + DCNT_IA_ASYNC_ERROR, + DCNT_IA_ASYNC_QP_ERROR, + DCNT_IA_ASYNC_CQ_ERROR, + DCNT_IA_ALL_COUNTERS, /* MUST be last */ + +} DAT_IA_COUNTERS; + +/* + * Definitions for 64-bit EP Counters + */ +typedef enum dat_ep_counters +{ + DCNT_EP_CONNECT, + DCNT_EP_DISCONNECT, + DCNT_EP_POST_SEND, + DCNT_EP_POST_SEND_DATA, + DCNT_EP_POST_SEND_UD, + DCNT_EP_POST_SEND_UD_DATA, + DCNT_EP_POST_RECV, + DCNT_EP_POST_RECV_DATA, + DCNT_EP_POST_WRITE, + DCNT_EP_POST_WRITE_DATA, + DCNT_EP_POST_WRITE_IMM, + DCNT_EP_POST_WRITE_IMM_DATA, + DCNT_EP_POST_READ, + DCNT_EP_POST_READ_DATA, + DCNT_EP_POST_CMP_SWAP, + DCNT_EP_POST_FETCH_ADD, + DCNT_EP_RECV, + DCNT_EP_RECV_DATA, + DCNT_EP_RECV_UD, + DCNT_EP_RECV_UD_DATA, + DCNT_EP_RECV_IMM, + DCNT_EP_RECV_IMM_DATA, + DCNT_EP_RECV_RDMA_IMM, + DCNT_EP_RECV_RDMA_IMM_DATA, + DCNT_EP_ALL_COUNTERS, /* MUST be last */ + +} DAT_EP_COUNTERS; + +/* + * Definitions for 64-bit EVD Counters + */ +typedef enum dat_evd_counters +{ + DCNT_EVD_WAIT, + DCNT_EVD_WAIT_BLOCKED, + DCNT_EVD_WAIT_NOTIFY, + DCNT_EVD_DEQUEUE, + DCNT_EVD_DEQUEUE_FOUND, + DCNT_EVD_DEQUEUE_NOT_FOUND, + DCNT_EVD_DEQUEUE_POLL, + DCNT_EVD_DEQUEUE_POLL_FOUND, + DCNT_EVD_CONN_CALLBACK, + DCNT_EVD_DTO_CALLBACK, + DCNT_EVD_ALL_COUNTERS, /* MUST be last */ + +} DAT_EVD_COUNTERS; + +/* Extended RETURN and EVENT STATUS string helper functions */ + +/* DAT_EXT_RETURN error to string */ +static __inline__ DAT_RETURN DAT_API +dat_strerror_extension ( + IN DAT_IB_RETURN value, + OUT const char **message ) +{ + switch( DAT_GET_TYPE(value) ) { + case DAT_IB_ERR: + *message = "DAT_IB_ERR"; + return DAT_SUCCESS; + default: + /* standard DAT return type */ + return(dat_strerror(value, message, NULL)); + } +} + +/* DAT_EXT_STATUS error to string */ +static __inline__ DAT_RETURN DAT_API +dat_strerror_ext_status ( + IN DAT_IB_STATUS value, + OUT const char **message ) +{ + switch(value) { + case 0: + *message = " "; + return DAT_SUCCESS; + case DAT_IB_OP_ERR: + *message = "DAT_IB_OP_ERR"; + return DAT_SUCCESS; + default: + *message = "unknown extension status"; + return DAT_INVALID_PARAMETER; + } +} + +/* + * Extended IB transport specific APIs + * redirection via DAT extension function + */ + +/* + * This asynchronous call is modeled after the InfiniBand atomic + * Fetch and Add operation. The add_value is added to the 64 bit + * value stored at the remote memory location specified in remote_iov + * and the result is stored in the local_iov. + */ +#define dat_ib_post_fetch_and_add(ep, add_val, lbuf, cookie, rbuf, flgs) \ + dat_extension_op( ep, \ + DAT_IB_FETCH_AND_ADD_OP, \ + (add_val), \ + (lbuf), \ + (cookie), \ + (rbuf), \ + (flgs)) + +/* + * This asynchronous call is modeled after the InfiniBand atomic + * Compare and Swap operation. The cmp_value is compared to the 64 bit + * value stored at the remote memory location specified in remote_iov. + * If the two values are equal, the 64 bit swap_value is stored in + * the remote memory location. In all cases, the original 64 bit + * value stored in the remote memory location is copied to the local_iov. + */ +#define dat_ib_post_cmp_and_swap(ep, cmp_val, swap_val, lbuf, cookie, rbuf, flgs) \ + dat_extension_op( ep, \ + DAT_IB_CMP_AND_SWAP_OP, \ + (cmp_val), \ + (swap_val), \ + (lbuf), \ + (cookie), \ + (rbuf), \ + (flgs)) + +/* + * RDMA Write with IMMEDIATE: + * + * This asynchronous call is modeled after the InfiniBand rdma write with + * immediate data operation. Event completion for the request completes as an + * DAT_EXTENSION with extension type set to DAT_DTO_EXTENSION_IMMED_DATA. + * Event completion on the remote endpoint completes as receive DTO operation + * type of DAT_EXTENSION with operation set to DAT_DTO_EXTENSION_IMMED_DATA. + * The immediate data will be provided in the extented DTO event data structure. + * + * Note to Consumers: the immediate data will consume a receive + * buffer at the Data Sink. + * + * Other extension flags: + * n/a + */ +#define dat_ib_post_rdma_write_immed(ep, size, lbuf, cookie, rbuf, idata, flgs) \ + dat_extension_op( ep, \ + DAT_IB_RDMA_WRITE_IMMED_OP, \ + (size), \ + (lbuf), \ + (cookie), \ + (rbuf), \ + (idata), \ + (flgs)) + +/* + * Unreliable datagram: msg send + * + * This asynchronous call is modeled after the InfiniBand UD message send + * Event completion for the request completes as an + * DAT_EXTENSION with extension type set to DAT_DTO_EXTENSION_UD_SEND. + * Event completion on the remote endpoint completes as receive DTO operation + * type of DAT_EXTENSION with operation set to DAT_DTO_EXTENSION_UD_RECV. + * + * Other extension flags: + * n/a + */ +#define dat_ib_post_send_ud(ep, segments, lbuf, ah_ptr, cookie, flgs) \ + dat_extension_op( ep, \ + DAT_IB_UD_SEND_OP, \ + (segments), \ + (lbuf), \ + (ah_ptr), \ + (cookie), \ + (flgs)) + + +/* + * Query counter(s): + * Provide IA, EP, or EVD and call will return appropriate counters + * DAT_HANDLE dat_handle, enum cntr, *DAT_UINT64 p_cntrs_out, int reset + * + * use _ALL_COUNTERS to query all + */ +#define dat_query_counters(dat_handle, cntr, p_cntrs_out, reset) \ + dat_extension_op( dat_handle, \ + DAT_QUERY_COUNTERS_OP, \ + (cntr), \ + (p_cntrs_out), \ + (reset)) +/* + * Print counter(s): + * Provide IA, EP, or EVD and call will print appropriate counters + * DAT_HANDLE dat_handle, int cntr, int reset + * + * use _ALL_COUNTERS to print all + */ +#define dat_print_counters(dat_handle, cntr, reset) \ + dat_extension_op( dat_handle, \ + DAT_PRINT_COUNTERS_OP, \ + (cntr), \ + (reset)) + +#endif /* _DAT_IB_EXTENSIONS_H_ */ + diff --git a/branches/WOF2-3/ulp/dapl2/dat/include/dat2/dat_iw_extensions.h b/branches/WOF2-3/ulp/dapl2/dat/include/dat2/dat_iw_extensions.h new file mode 100644 index 00000000..59de0b33 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dat/include/dat2/dat_iw_extensions.h @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2002-2006, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ +/********************************************************************** + * + * HEADER: dat_iw_extensions.h + * + * PURPOSE: extensions to the DAT API for iWARP transport specific services + * NOTE: + * Applications MUST recompile with new dat.h definitions + * and include this file. + * + * Description: Header file for "uDAPL: User Direct Access Programming + * Library, Version: 2.0" + * + * Mapping rules: + * All global symbols are prepended with "DAT_" or "dat_" + * All DAT objects have an 'api' tag which, such as 'ep' or 'lmr' + * The method table is in the provider definition structure. + * + * + **********************************************************************/ +#ifndef _DAT_IW_EXTENSIONS_H_ +#define _DAT_IW_EXTENSIONS_H_ + +/* + * Provider specific attribute strings for extension support + * returned with dat_ia_query() and + * DAT_PROVIDER_ATTR_MASK == DAT_PROVIDER_FIELD_PROVIDER_SPECIFIC_ATTR + * + * DAT_NAMED_ATTR name == extended operations and version, + * version_value = version number of extension API + */ +#define DAT_EXTENSION_ATTR "DAT_EXTENSION_INTERFACE" +#define DAT_EXTENSION_ATTR_VERSION "DAT_EXTENSION_VERSION" +#define DAT_EXTENSION_ATTR_VERSION_VALUE "2.0.1" +#define DAT_IW_ATTR_SSP "DAT_IW_ATTR_SSP" + + +/* + * The iWARP extension supports Socket Service Points + * These enable establishing a TCP connection first, then converting + * it to RDMA usage. + */ +typedef enum dat_handle_iw_ext_type { + DAT_IW_HANDLE_TYPE_SSP = DAT_HANDLE_TYPE_EXTENSION_BASE, +} DAT_HANDLE_IW_EXT_TYPE; +typedef DAT_HANDLE DAT_IW_SSP_HANDLE; + +typedef enum dat_iw_ssp_state +{ + DAT_IW_SSP_STATE_OPERATIONAL, + DAT_IW_SSP_STATE_NON_OPERATIONAL +} DAT_IW_SSP_STATE; + +/* The Socket ID is a local identifier for the socket. It is used for Socket + * based connection model. The format of the DAT_IW_SOCKET follows the native + * sockets programming practice of each target Operating System. The Consumer must + * follow normal sockets programming procedures provided by the host platform. + * + * This include assumes that a socket handle is an int unless we are in + * Linux Kernel code, in which case it is a struct socket pointer. This + * distinction could be moved either to a distinct file (for iWARP specific, + * platform specific types) or to dat_platform_specific.h (where the fact + * that it was iWARP specific would be awkward). The coin flip was heads, + * so the awkwardness of platform specific typing is in the iWARP specific + * file instead. + */ +#if defined(__linux__) && defined(__KERNEL__) +typyedef struct socket *DAT_IW_SOCKET; +#else +typedef int DAT_IW_SOCKET; +#endif + +typedef struct dat_iw_ssp_param +{ + DAT_IA_HANDLE ia_handle; + DAT_IW_SOCKET socket_id; + DAT_EVD_HANDLE evd_handle; + DAT_EP_HANDLE ep_handle; + DAT_IW_SSP_STATE ssp_state; +} DAT_IW_SSP_PARAM; + +typedef enum dat_iw_ssp_param_mask +{ + DAT_IW_SSP_FIELD_IA_HANDLE = 0x01, + DAT_IW_SSP_FIELD_SOCKET_ID = 0x02, + DAT_IW_SSP_FIELD_EVD_HANDLE = 0x04, + DAT_IW_SSP_FIELD_EP_HANDLE = 0x08, + DAT_IW_SSP_FIELD_SSP_STATE = 0x10, + DAT_IW_SSP_FIELD_ALL = 0x1F +} DAT_IW_SSP_PARAM_MASK; + + +/* + * Extension operations + */ +typedef enum dat_iw_op +{ + DAT_IW_SSP_CREATE_OP, + DAT_IW_SSP_FREE_OP, + DAT_IW_SSP_QUERY_OP, + DAT_IW_SOCKET_CONNECT_OP +} DAT_IW_OP; + +/* + * Extended IW transport specific APIs + * redirection via DAT extension function + */ + +/* dat_iw_ssp_create creates an iWARP Socket Service Point given an + * already connected Socket + */ + +#define dat_iw_ssp_create (ia,socket_id,ep_handle,evd_handle,\ + final_sm_msg,final_sm_msg_len,ssp_handle) \ + dat_extension_op (ia,DAT_IW_SSP_CREATE_OP,ia,socket_id, \ + ep_handle,evd_handle,final_sm_msg, \ + final_sm_msg_len,ssp_handle) + +/* dat_iw_ssp_free destroys the specified instance of an SSP + */ +#define dat_iw_ssp_free (ssp_handle) \ + dat_extension_op (ssp_handle,DAT_IW_SSP_FREE_OP) + +/* dat_iw_ssq_query obtains the SSP_PARAMs for an ssp + */ +#define dat_iw_ssp_query (ssp_handle,ssp_param_mask,ssp_param) \ + dat_extension_op (ssp_handle,DAT_IW_SSP_QUERY_OP, \ + ssp_param_maks,ssp_param) + +/* dat_iw_socket_connect initates a connection using an SSP + */ +#define dat_iw_socket_connect (ep_handle,socket_id,timeout, \ + private_data_size,private_data) \ + dat_extension_op (ep_handle,DAT_IW_SOCKET_CONNECT_OP,\ + socket_id,timeout,private_data_size,\ + private_data) + +#endif /* _DAT_IW_EXTENSIONS_H_ */ + diff --git a/branches/WOF2-3/ulp/dapl2/dat/include/dat2/dat_platform_specific.h b/branches/WOF2-3/ulp/dapl2/dat/include/dat2/dat_platform_specific.h new file mode 100644 index 00000000..ba4cfbca --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dat/include/dat2/dat_platform_specific.h @@ -0,0 +1,274 @@ +/* + * Copyright (c) 2002-2006, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under all of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * Redistributions of source code must retain both 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. + * + * Neither the name of Network Appliance, Inc. nor the names of other DAT + * Collaborative contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + */ + +/*************************************************************** + * + * HEADER: dat_platform_specific.h + * + * PURPOSE: defines Platform-specific types. + * + * Description: Header file for "DAPL: Direct Access Programming + * Library, Version: 2.0" + * + * Mapping rules: + * + ***************************************************************/ + +#ifndef _DAT_PLATFORM_SPECIFIC_H_ +#define _DAT_PLATFORM_SPECIFIC_H_ + +/* OS, processor, compiler type definitions. Add OSes as needed. */ + +/* + * This captures the alignment for the bus transfer from the HCA/IB chip + * to the main memory. + */ +#ifndef DAT_OPTIMAL_ALIGNMENT +#define DAT_OPTIMAL_ALIGNMENT 256 /* Performance optimal alignment */ +#endif /* DAT_OPTIMAL_ALIGNMENT */ + +/* Assume all OSes use sockaddr, for address family: IPv4 == AF_INET, + * IPv6 == AF_INET6. Use of "namelen" field indicated. + * + * The Interface Adapter Address names an Interface Adapter local or + * remote, that is used for connection management and Name + * Service. The format of the dat_ia_address_ptr follows the normal + * socket programming practice of struct sockaddr *. DAT supports both + * IPv4 and IPv6 address families. Allocation and initialization of + * DAT IA address structures must follow normal Sockets programming + * procedures. The underlying type of the DAT IA address is the native + * struct sockaddr for each target operating system. In all cases, + * storage appropriate for the address family in use by the target + * Provider must be allocated. For instance, when IPv6 addressing is + * in use, this should be allocated as struct sockaddr_net6. The + * sockaddr sa_family and, if present, sa_len fields must be + * initialized appropriately, as well as the address information. + * When passed across the DAPL API this storage is cast to the + * DAT_IA_ADDRESS_PTR type. It is the responsibility of the callee to + * verify that the sockaddr contains valid data for the requested + * operation. It is always the responsibility of the caller to manage + * the storage. + * + * uDAPL code example for Linux (kdapl would be similar): + * + * #include + * #include + * #include + * #include + * + * struct sockaddr_in6 addr; + * DAT_IA_ADDRESS_PTR ia_addr; + * + * // Note: linux pton requires explicit encoding of IPv4 in IPv6 + * + * addr.sin6_family = AF_INET6; + * if (inet_pton(AF_INET6, "0:0:0:0:0:FFFF:192.168.0.1", + * &addr.sin6_addr) <= 0) + * return(-1); // Bad address or no address family support + * + * // initialize other necessary fields such as port, flow, etc + * + * ia_addr = (DAT_IA_ADDRESS_PTR) &addr; + * dat_ep_connect(ep_handle, ia_addr, conn_qual, timeout, 0, NULL, + * qos, DAT_CONNECT_DEFAULT_FLAG); + * + */ + +/* Solaris begins */ +#if defined (sun) || defined(__sun) || defined(_sun_) || defined (__solaris__) + +#include +#include /* needed for UINT64_C() macro */ + +typedef uint32_t DAT_UINT32; /* Unsigned host order, 32 bits */ +typedef uint64_t DAT_UINT64; /* unsigned host order, 64 bits */ +typedef unsigned long long DAT_UVERYLONG; /* unsigned longest native to compiler */ + +typedef void * DAT_PVOID; +typedef int DAT_COUNT; + +#define DAT_IA_HANDLE_TO_UL(a) (unsigned long)(a) +#define DAT_UL_TO_IA_HANDLE(a) (DAT_IA_HANDLE)(a) + +#include +#include +typedef struct sockaddr DAT_SOCK_ADDR; /* Socket address header native to OS */ +typedef struct sockaddr_in6 DAT_SOCK_ADDR6; /* Socket address header native to OS */ + +#define DAT_AF_INET AF_INET +#define DAT_AF_INET6 AF_INET6 + +typedef DAT_UINT64 DAT_PADDR; + +#define DAT_API +#define DAT_EXPORT extern + +/* Solaris ends */ + + +/* Linux begins */ +#elif defined(__linux__) /* Linux */ +#if defined(__KERNEL__) +#include +#else +#include +#include +#endif /* defined(__KERNEL__) */ + +typedef u_int32_t DAT_UINT32; /* unsigned host order, 32 bits */ +typedef u_int64_t DAT_UINT64; /* unsigned host order, 64 bits */ +typedef unsigned long long DAT_UVERYLONG; /* unsigned longest native to compiler */ + +typedef void * DAT_PVOID; +typedef int DAT_COUNT; +typedef DAT_UINT64 DAT_PADDR; + +#ifndef UINT64_C +#define UINT64_C(c) c ## ULL +#endif /* UINT64_C */ + +#define DAT_IA_HANDLE_TO_UL(a) (unsigned long)(a) +#define DAT_UL_TO_IA_HANDLE(a) (DAT_IA_HANDLE)(a) + +#if defined(__KERNEL__) +#include +#include +#include +#else +#include +#endif /* defined(__KERNEL__) */ + +typedef struct dat_comm { + int domain; + int type; + int protocol; +} DAT_COMM; + +typedef int DAT_FD; /* DAT File Descriptor */ + +typedef struct sockaddr DAT_SOCK_ADDR; /* Socket address header native to OS */ +typedef struct sockaddr_in6 DAT_SOCK_ADDR6; /* Socket address header native to OS */ +#define DAT_AF_INET AF_INET +#define DAT_AF_INET6 AF_INET6 + +#define DAT_API +#define DAT_EXPORT extern + +/* Linux ends */ + +/* Win32/64 begins */ +#elif defined(_MSC_VER) || defined(_WIN32) || defined(_WIN64) +/* NT. MSC compiler, Win32/64 platform */ + +#include +#include + +typedef unsigned __int32 DAT_UINT32; /* Unsigned host order, 32 bits */ +typedef unsigned __int64 DAT_UINT64; /* unsigned host order, 64 bits */ +typedef unsigned long DAT_UVERYLONG; /* unsigned longest native to compiler */ + +#if defined(_WIN64) +#define DAT_IA_HANDLE_TO_UL(a) (unsigned long)((DAT_UINT64)(a)) +#define DAT_UL_TO_IA_HANDLE(a) (DAT_IA_HANDLE)((DAT_UINT64)(a)) +#else // _WIN32 +#define DAT_IA_HANDLE_TO_UL(a) (unsigned long)(a) +#define DAT_UL_TO_IA_HANDLE(a) (DAT_IA_HANDLE)(a) +#endif + +typedef void * DAT_PVOID; +typedef int DAT_COUNT; +typedef DAT_UINT64 DAT_PADDR; + +typedef struct dat_comm { + int domain; + int type; + int protocol; +} DAT_COMM; + +typedef int DAT_FD; /* DAT File Descriptor */ + +typedef struct sockaddr DAT_SOCK_ADDR; /* Sock addr header native to OS */ +typedef struct sockaddr_in6 DAT_SOCK_ADDR6;/* Sock addr header native to OS */ + +#ifndef UINT64_C +#define UINT64_C(c) c ## i64 +#endif /* UINT64_C */ + +#define DAT_AF_INET AF_INET +#define DAT_AF_INET6 AF_INET6 + +#if defined(EXPORT_DAT_SYMBOLS) +#define DAT_EXPORT __declspec(dllexport) +#else +#define DAT_EXPORT __declspec(dllimport) +#endif + +#define DAT_API __stdcall + +#ifndef __inline__ +#define __inline__ __inline +#endif + +#ifndef INLINE +#define INLINE __inline +#endif + +#if defined(__KDAPL__) +/* must have the DDK for this definition */ +typedef PHYSICAL_ADDRESS DAT_PADDR; +#endif /* __KDAPL__ */ + +/* Windoze ends */ + + +#else +#error dat_platform_specific.h : OS type not defined +#endif + +#ifndef IN +#define IN +#endif +#ifndef OUT +#define OUT +#endif +#ifndef INOUT +#define INOUT +#endif + +#endif /* _DAT_PLATFORM_SPECIFIC_H_ */ diff --git a/branches/WOF2-3/ulp/dapl2/dat/include/dat2/dat_redirection.h b/branches/WOF2-3/ulp/dapl2/dat/include/dat2/dat_redirection.h new file mode 100644 index 00000000..ea61eff9 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dat/include/dat2/dat_redirection.h @@ -0,0 +1,858 @@ +/* + * Copyright (c) 2002-2006, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under all of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * Redistributions of source code must retain both 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. + * + * Neither the name of Network Appliance, Inc. nor the names of other DAT + * Collaborative contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + */ + +/**************************************************************** + * + * HEADER: dat_redirection.h + * + * PURPOSE: Defines the common redirection macros + * + * Description: Macros to invoke DAPL functions from the dat_registry + * + * Mapping rules: + * All global symbols are prepended with DAT_ or dat_ + * All DAT objects have an 'api' tag which, such as 'ep' or 'lmr' + * The method table is in the provider definition structure. + * + **********************************************************/ +#ifndef _DAT_REDIRECTION_H_ +#define _DAT_REDIRECTION_H_ + +typedef struct dat_provider DAT_PROVIDER; + +#ifndef DAT_HANDLE_TO_PROVIDER + +/* A utility macro to fetch the Provider Library for any object + * + * An alternate version could be defined for single library systems. + * it would look something like: + * extern const struct dat_ia my_single_ia_provider; + * #define DAT_HANDLE_TO_PROVIDER(ignore) &my_single_ia_provider + * + * This would allow a good compiler to avoid indirection overhead when + * making function calls. + */ + +#define DAT_HANDLE_TO_PROVIDER(handle) (*(DAT_PROVIDER **)(handle)) +#endif + +#define DAT_IA_QUERY(ia, evd, ia_msk, ia_ptr, p_msk, p_ptr) \ + (*DAT_HANDLE_TO_PROVIDER (ia)->ia_query_func) (\ + (ia), \ + (evd), \ + (ia_msk), \ + (ia_ptr), \ + (p_msk), \ + (p_ptr)) + +#define DAT_SET_CONSUMER_CONTEXT(handle, context) \ + (*DAT_HANDLE_TO_PROVIDER (handle)->set_consumer_context_func) (\ + (handle), \ + (context)) + +#define DAT_GET_CONSUMER_CONTEXT(handle, context) \ + (*DAT_HANDLE_TO_PROVIDER (handle)->get_consumer_context_func) (\ + (handle), \ + (context)) + +#define DAT_GET_HANDLE_TYPE(handle, handle_type) \ + (*DAT_HANDLE_TO_PROVIDER (handle)->get_handle_type_func) (\ + (handle), \ + (handle_type)) + +#define DAT_CR_QUERY(cr, mask, param) \ + (*DAT_HANDLE_TO_PROVIDER (cr)->cr_query_func) (\ + (cr), \ + (mask), \ + (param)) + +#define DAT_CR_ACCEPT(cr, ep, size, pdata) \ + (*DAT_HANDLE_TO_PROVIDER (cr)->cr_accept_func) (\ + (cr), \ + (ep), \ + (size), \ + (pdata)) + +#define DAT_CR_REJECT(cr, size, pdata) \ + (*DAT_HANDLE_TO_PROVIDER (cr)->cr_reject_func) (\ + (cr), \ + (size), \ + (pdata)) + +#define DAT_CR_HANDOFF(cr,qual) \ + (*DAT_HANDLE_TO_PROVIDER(cr)->cr_handoff_func)(\ + (cr), \ + (qual)) + +#define DAT_EVD_QUERY(evd, mask, param) \ + (*DAT_HANDLE_TO_PROVIDER (evd)->evd_query_func) (\ + (evd), \ + (mask), \ + (param)) + +#define DAT_EVD_RESIZE(evd, qsize) \ + (*DAT_HANDLE_TO_PROVIDER (evd)->evd_resize_func) (\ + (evd), \ + (qsize)) + +#define DAT_EVD_POST_SE(evd, event) \ + (*DAT_HANDLE_TO_PROVIDER (evd)->evd_post_se_func) (\ + (evd), \ + (event)) + +#define DAT_EVD_DEQUEUE(evd, event) \ + (*DAT_HANDLE_TO_PROVIDER (evd)->evd_dequeue_func) (\ + (evd), \ + (event)) + +#define DAT_EVD_FREE(evd)\ + (*DAT_HANDLE_TO_PROVIDER (evd)->evd_free_func) (\ + (evd)) + +#define DAT_EP_CREATE(ia, pz, in_evd, out_evd, connect_evd, attr, ep) \ + (*DAT_HANDLE_TO_PROVIDER (ia)->ep_create_func) (\ + (ia), \ + (pz), \ + (in_evd), \ + (out_evd), \ + (connect_evd), \ + (attr), \ + (ep)) + +#define DAT_EP_CREATE_WITH_SRQ(ia, pz, in_evd, out_evd, \ + connect_evd, srq, attr, ep) \ + (*DAT_HANDLE_TO_PROVIDER (ia)->ep_create_with_srq_func) (\ + (ia), \ + (pz), \ + (in_evd), \ + (out_evd), \ + (connect_evd), \ + (srq), \ + (attr), \ + (ep)) + +#define DAT_EP_QUERY(ep, mask, param) \ + (*DAT_HANDLE_TO_PROVIDER (ep)->ep_query_func) (\ + (ep), \ + (mask), \ + (param)) + +#define DAT_EP_MODIFY(ep, mask, param) \ + (*DAT_HANDLE_TO_PROVIDER (ep)->ep_modify_func) (\ + (ep), \ + (mask), \ + (param)) + +#define DAT_EP_CONNECT(ep, ia_addr, conn_qual, \ + timeout, psize, pdata, qos, flags) \ + (*DAT_HANDLE_TO_PROVIDER (ep)->ep_connect_func) (\ + (ep), \ + (ia_addr), \ + (conn_qual), \ + (timeout), \ + (psize), \ + (pdata), \ + (qos), \ + (flags)) + +#define DAT_EP_COMMON_CONNECT(ep, addr, timeout, psize, pdata) \ + (*DAT_HANDLE_TO_PROVIDER(ep)->ep_common_connect_func)(\ + (ep), \ + (addr), \ + (timeout), \ + (psize), \ + (pdata)) + +#define DAT_EP_DUP_CONNECT(ep, dup, timeout, psize, pdata, qos) \ + (*DAT_HANDLE_TO_PROVIDER (ep)->ep_dup_connect_func) (\ + (ep), \ + (dup), \ + (timeout), \ + (psize), \ + (pdata), \ + (qos)) + +#define DAT_EP_DISCONNECT(ep, flags) \ + (*DAT_HANDLE_TO_PROVIDER(ep)->ep_disconnect_func) (\ + (ep), \ + (flags)) + +#define DAT_EP_POST_SEND(ep, size, lbuf, cookie, flags) \ + (*DAT_HANDLE_TO_PROVIDER (ep)->ep_post_send_func) (\ + (ep), \ + (size), \ + (lbuf), \ + (cookie), \ + (flags)) + +#define DAT_EP_POST_SEND_WITH_INVALIDATE( \ + ep,size,lbuf,cookie,flags,inv_flag,rmr_context) \ + (*DAT_HANDLE_TO_PROVIDER(ep)-> \ + ep_post_send_with_invalidate_func)(\ + (ep), \ + (size), \ + (lbuf), \ + (cookie), \ + (flags), \ + (inv_flag), \ + (rmr_context)) + +#define DAT_EP_POST_RECV(ep, size, lbuf, cookie, flags) \ + (*DAT_HANDLE_TO_PROVIDER (ep)->ep_post_recv_func) (\ + (ep), \ + (size), \ + (lbuf), \ + (cookie), \ + (flags)) + +#define DAT_EP_POST_RDMA_READ(ep, size, lbuf, cookie, rbuf, flags) \ + (*DAT_HANDLE_TO_PROVIDER (ep)->ep_post_rdma_read_func) (\ + (ep), \ + (size), \ + (lbuf), \ + (cookie), \ + (rbuf), \ + (flags)) + +#define DAT_EP_POST_RDMA_READ_TO_RMR(ep, lbuf, cookie, rbuf, flags) \ + (*DAT_HANDLE_TO_PROVIDER(ep)->ep_post_rdma_read_to_rmr_func)(\ + (ep), \ + (lbuf), \ + (cookie), \ + (rbuf), \ + (flags)) + +#define DAT_EP_POST_RDMA_WRITE(ep, size, lbuf, cookie, rbuf, flags) \ + (*DAT_HANDLE_TO_PROVIDER (ep)->ep_post_rdma_write_func) (\ + (ep), \ + (size), \ + (lbuf), \ + (cookie), \ + (rbuf), \ + (flags)) + +#define DAT_EP_GET_STATUS(ep, ep_state, recv_idle, request_idle) \ + (*DAT_HANDLE_TO_PROVIDER (ep)->ep_get_status_func) (\ + (ep), \ + (ep_state), \ + (recv_idle), \ + (request_idle)) + +#define DAT_EP_FREE(ep)\ + (*DAT_HANDLE_TO_PROVIDER (ep)->ep_free_func) (\ + (ep)) + +#define DAT_EP_RESET(ep)\ + (*DAT_HANDLE_TO_PROVIDER (ep)->ep_reset_func) (\ + (ep)) + +#define DAT_EP_RECV_QUERY(ep, nbuf_alloc, buf_span)\ + (*DAT_HANDLE_TO_PROVIDER (ep)->ep_recv_query_func) (\ + (ep), \ + (nbuf_alloc), \ + (buf_span)) + +#define DAT_EP_SET_WATERMARK(ep, soft_wm, hard_wm)\ + (*DAT_HANDLE_TO_PROVIDER (ep)->ep_set_watermark_func) (\ + (ep), \ + (soft_wm), \ + (hard_wm)) + +#define DAT_LMR_QUERY(lmr, mask, param)\ + (*DAT_HANDLE_TO_PROVIDER (lmr)->lmr_query_func) (\ + (lmr), \ + (mask), \ + (param)) + +#define DAT_LMR_FREE(lmr)\ + (*DAT_HANDLE_TO_PROVIDER (lmr)->lmr_free_func) (\ + (lmr)) + +#define DAT_LMR_SYNC_RDMA_READ(ia, lbuf, size)\ + (*DAT_HANDLE_TO_PROVIDER (ia)->lmr_sync_rdma_read_func) (\ + (ia), \ + (lbuf), \ + (size)) + +#define DAT_LMR_SYNC_RDMA_WRITE(ia, lbuf, size)\ + (*DAT_HANDLE_TO_PROVIDER (ia)->lmr_sync_rdma_write_func) (\ + (ia), \ + (lbuf), \ + (size)) + +#define DAT_RMR_CREATE(pz, rmr) \ + (*DAT_HANDLE_TO_PROVIDER (pz)->rmr_create_func) (\ + (pz), \ + (rmr)) + +#define DAT_RMR_CREATE_FOR_EP(pz, rmr) \ + (*DAT_HANDLE_TO_PROVIDER (pz)->rmr_create_for_ep_func) (\ + (pz), \ + (rmr)) + +#define DAT_RMR_QUERY(rmr, mask, param) \ + (*DAT_HANDLE_TO_PROVIDER (rmr)->rmr_query_func) (\ + (rmr), \ + (mask), \ + (param)) + +#define DAT_RMR_BIND(rmr, lmr, lmr_triplet, mem_priv, \ + va_type, ep, cookie, flags, context) \ + (*DAT_HANDLE_TO_PROVIDER (rmr)->rmr_bind_func) (\ + (rmr), \ + (lmr), \ + (lmr_triplet), \ + (mem_priv), \ + (va_type), \ + (ep), \ + (cookie), \ + (flags), \ + (context)) + +#define DAT_RMR_FREE(rmr)\ + (*DAT_HANDLE_TO_PROVIDER (rmr)->rmr_free_func) (\ + (rmr)) + +#define DAT_PSP_CREATE(ia, conn_qual, evd, flags, handle) \ + (*DAT_HANDLE_TO_PROVIDER (ia)->psp_create_func) (\ + (ia), \ + (conn_qual), \ + (evd), \ + (flags), \ + (handle)) + +#define DAT_PSP_CREATE_ANY(ia, conn_qual, evd, flags, handle) \ + (*DAT_HANDLE_TO_PROVIDER (ia)->psp_create_any_func) (\ + (ia), \ + (conn_qual), \ + (evd), \ + (flags), \ + (handle)) + +#define DAT_PSP_QUERY(psp, mask, param) \ + (*DAT_HANDLE_TO_PROVIDER (psp)->psp_query_func) (\ + (psp), \ + (mask), \ + (param)) + +#define DAT_PSP_FREE(psp)\ + (*DAT_HANDLE_TO_PROVIDER (psp)->psp_free_func) (\ + (psp)) + +#define DAT_RSP_CREATE(ia, conn_qual, ep, evd, handle) \ + (*DAT_HANDLE_TO_PROVIDER (ia)->rsp_create_func) (\ + (ia), \ + (conn_qual), \ + (ep), \ + (evd), \ + (handle)) + +#define DAT_RSP_QUERY(rsp, mask, param) \ + (*DAT_HANDLE_TO_PROVIDER (rsp)->rsp_query_func) (\ + (rsp), \ + (mask), \ + (param)) + +#define DAT_RSP_FREE(rsp)\ + (*DAT_HANDLE_TO_PROVIDER (rsp)->rsp_free_func) (\ + (rsp)) + +#define DAT_CSP_CREATE(ia, comm, addr, evd, handle) \ + (*DAT_HANDLE_TO_PROVIDER(ia)->csp_create_func)(\ + (ia),\ + (comm),\ + (addr),\ + (evd),\ + (handle)) + +#define DAT_CSP_QUERY(csp, mask, param) \ + (*DAT_HANDLE_TO_PROVIDER(csp)->csp_query_func)(\ + (csp),\ + (mask),\ + (param)) + +#define DAT_CSP_FREE(csp)\ + (*DAT_HANDLE_TO_PROVIDER(csp)->csp_free_func)(\ + (csp)) + +#define DAT_PZ_CREATE(ia, pz) \ + (*DAT_HANDLE_TO_PROVIDER (ia)->pz_create_func) (\ + (ia), \ + (pz)) + +#define DAT_PZ_QUERY(pz, mask, param) \ + (*DAT_HANDLE_TO_PROVIDER (pz)->pz_query_func) (\ + (pz), \ + (mask), \ + (param)) + +#define DAT_PZ_FREE(pz) \ + (*DAT_HANDLE_TO_PROVIDER (pz)->pz_free_func) (\ + (pz)) + +#define DAT_SRQ_CREATE(ia, pz, attr, srq) \ + (*DAT_HANDLE_TO_PROVIDER (ia)->srq_create_func) (\ + (ia), \ + (pz), \ + (attr), \ + (srq)) + +#define DAT_SRQ_SET_LW(srq, lw) \ + (*DAT_HANDLE_TO_PROVIDER (srq)->srq_set_lw_func) (\ + (srq), \ + (lw)) + +#define DAT_SRQ_FREE(srq) \ + (*DAT_HANDLE_TO_PROVIDER (srq)->srq_free_func) (\ + (srq)) + +#define DAT_SRQ_QUERY(srq, mask, param) \ + (*DAT_HANDLE_TO_PROVIDER (srq)->srq_query_func) (\ + (srq), \ + (mask), \ + (param)) + +#define DAT_SRQ_RESIZE(srq, qsize) \ + (*DAT_HANDLE_TO_PROVIDER (srq)->srq_resize_func) (\ + (srq), \ + (qsize)) + +#define DAT_SRQ_POST_RECV(srq, size, lbuf, cookie) \ + (*DAT_HANDLE_TO_PROVIDER (srq)->srq_post_recv_func) (\ + (srq), \ + (size), \ + (lbuf), \ + (cookie)) + +#define DAT_IA_HA_RELATED (ia, name, answer) \ + (*DAT_HANDLE_TO_PROVIDER(ia)->ia_ha_related) (\ + (ia), \ + (name), \ + (answer)) + +#ifdef DAT_EXTENSIONS +#define DAT_HANDLE_EXTENDEDOP(handle, op, args) \ + (*DAT_HANDLE_TO_PROVIDER (handle)->handle_extendedop_func) (\ + (handle), \ + (op), \ + (args)) +#endif + +/*************************************************************** + * + * FUNCTION PROTOTYPES + ****************************************************************/ + +typedef DAT_RETURN (DAT_API *DAT_IA_OPEN_FUNC) ( + IN const DAT_NAME_PTR, /* provider */ + IN DAT_COUNT, /* asynch_evd_min_qlen */ + INOUT DAT_EVD_HANDLE *, /* asynch_evd_handle */ + OUT DAT_IA_HANDLE *); /* ia_handle */ + +typedef DAT_RETURN (DAT_API *DAT_IA_OPENV_FUNC) ( + IN const DAT_NAME_PTR, /* provider */ + IN DAT_COUNT, /* asynch_evd_min_qlen */ + INOUT DAT_EVD_HANDLE *, /* asynch_evd_handle */ + OUT DAT_IA_HANDLE *, /* ia_handle */ + IN DAT_UINT32, /* dat_major_version number */ + IN DAT_UINT32, /* dat_minor_version number */ + IN DAT_BOOLEAN); /* dat_thread_safety */ + +typedef DAT_RETURN (DAT_API *DAT_IA_CLOSE_FUNC) ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_CLOSE_FLAGS ); /* close_flags */ + +typedef DAT_RETURN (DAT_API *DAT_IA_QUERY_FUNC) ( + IN DAT_IA_HANDLE, /* ia_handle */ + OUT DAT_EVD_HANDLE *, /* async_evd_handle */ + IN DAT_IA_ATTR_MASK, /* ia_attr_mask */ + OUT DAT_IA_ATTR *, /* ia_attr */ + IN DAT_PROVIDER_ATTR_MASK, /* provider_attr_mask */ + OUT DAT_PROVIDER_ATTR * ); /* provider_attr */ + +/* helper functions */ + +typedef DAT_RETURN (DAT_API *DAT_SET_CONSUMER_CONTEXT_FUNC) ( + IN DAT_HANDLE, /* dat_handle */ + IN DAT_CONTEXT); /* context */ + +typedef DAT_RETURN (DAT_API *DAT_GET_CONSUMER_CONTEXT_FUNC) ( + IN DAT_HANDLE, /* dat_handle */ + OUT DAT_CONTEXT * ); /* context */ + +typedef DAT_RETURN (DAT_API *DAT_GET_HANDLE_TYPE_FUNC) ( + IN DAT_HANDLE, /* dat_handle */ + OUT DAT_HANDLE_TYPE * ); /* dat_handle_type */ + +/* CR functions */ + +typedef DAT_RETURN (DAT_API *DAT_CR_QUERY_FUNC) ( + IN DAT_CR_HANDLE, /* cr_handle */ + IN DAT_CR_PARAM_MASK, /* cr_param_mask */ + OUT DAT_CR_PARAM * ); /* cr_param */ + +typedef DAT_RETURN (DAT_API *DAT_CR_ACCEPT_FUNC) ( + IN DAT_CR_HANDLE, /* cr_handle */ + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_COUNT, /* private_data_size */ + IN const DAT_PVOID ); /* private_data */ + +typedef DAT_RETURN (DAT_API *DAT_CR_REJECT_FUNC) ( + IN DAT_CR_HANDLE, /* cr_handle */ + IN DAT_COUNT, /* private_data_size */ + IN const DAT_PVOID ); /* private_data */ + +/* For DAT-1.1 this function is defined for both uDAPL and kDAPL. + * For DAT-1.0 it was only defined for uDAPL. + */ + +typedef DAT_RETURN (DAT_API *DAT_CR_HANDOFF_FUNC) ( + IN DAT_CR_HANDLE, /* cr_handle */ + IN DAT_CONN_QUAL); /* handoff */ + +/* EVD functions */ + +typedef DAT_RETURN (DAT_API *DAT_EVD_RESIZE_FUNC) ( + IN DAT_EVD_HANDLE, /* evd_handle */ + IN DAT_COUNT ); /* evd_min_qlen */ + +typedef DAT_RETURN (DAT_API *DAT_EVD_POST_SE_FUNC) ( + IN DAT_EVD_HANDLE, /* evd_handle */ + IN const DAT_EVENT * ); /* event */ + +typedef DAT_RETURN (DAT_API *DAT_EVD_DEQUEUE_FUNC) ( + IN DAT_EVD_HANDLE, /* evd_handle */ + OUT DAT_EVENT * ); /* event */ + +typedef DAT_RETURN (DAT_API *DAT_EVD_FREE_FUNC) ( + IN DAT_EVD_HANDLE ); /* evd_handle */ + +typedef DAT_RETURN (DAT_API *DAT_EVD_QUERY_FUNC) ( + IN DAT_EVD_HANDLE, /* evd_handle */ + IN DAT_EVD_PARAM_MASK, /* evd_param_mask */ + OUT DAT_EVD_PARAM * ); /* evd_param */ + +/* EP functions */ + +typedef DAT_RETURN (DAT_API *DAT_EP_CREATE_FUNC) ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_PZ_HANDLE, /* pz_handle */ + IN DAT_EVD_HANDLE, /* recv_completion_evd_handle */ + IN DAT_EVD_HANDLE, /* request_completion_evd_handle */ + IN DAT_EVD_HANDLE, /* connect_evd_handle */ + IN const DAT_EP_ATTR *, /* ep_attributes */ + OUT DAT_EP_HANDLE * ); /* ep_handle */ + +typedef DAT_RETURN (DAT_API *DAT_EP_CREATE_WITH_SRQ_FUNC) ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_PZ_HANDLE, /* pz_handle */ + IN DAT_EVD_HANDLE, /* recv_completion_evd_handle */ + IN DAT_EVD_HANDLE, /* request_completion_evd_handle */ + IN DAT_EVD_HANDLE, /* connect_evd_handle */ + IN DAT_SRQ_HANDLE, /* srq_handle */ + IN const DAT_EP_ATTR *, /* ep_attributes */ + OUT DAT_EP_HANDLE * ); /* ep_handle */ + +typedef DAT_RETURN (DAT_API *DAT_EP_QUERY_FUNC) ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_EP_PARAM_MASK, /* ep_param_mask */ + OUT DAT_EP_PARAM * ); /* ep_param */ + +typedef DAT_RETURN (DAT_API *DAT_EP_MODIFY_FUNC) ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_EP_PARAM_MASK, /* ep_param_mask */ + IN const DAT_EP_PARAM * ); /* ep_param */ + +typedef DAT_RETURN (DAT_API *DAT_EP_CONNECT_FUNC) ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_IA_ADDRESS_PTR, /* remote_ia_address */ + IN DAT_CONN_QUAL, /* remote_conn_qual */ + IN DAT_TIMEOUT, /* timeout */ + IN DAT_COUNT, /* private_data_size */ + IN const DAT_PVOID, /* private_data */ + IN DAT_QOS, /* quality_of_service */ + IN DAT_CONNECT_FLAGS ); /* connect_flags */ + +typedef DAT_RETURN (DAT_API *DAT_EP_COMMON_CONNECT_FUNC) ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_IA_ADDRESS_PTR, /* remote_ia_address */ + IN DAT_TIMEOUT, /* timeout */ + IN DAT_COUNT, /* private_data_size */ + IN const DAT_PVOID ); /* private_data */ + +typedef DAT_RETURN (DAT_API *DAT_EP_DUP_CONNECT_FUNC) ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_EP_HANDLE, /* ep_dup_handle */ + IN DAT_TIMEOUT, /* timeout */ + IN DAT_COUNT, /* private_data_size */ + IN const DAT_PVOID, /* private_data */ + IN DAT_QOS); /* quality_of_service */ + +typedef DAT_RETURN (DAT_API *DAT_EP_DISCONNECT_FUNC) ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_CLOSE_FLAGS ); /* close_flags */ + +typedef DAT_RETURN (DAT_API *DAT_EP_POST_SEND_FUNC) ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_COUNT, /* num_segments */ + IN DAT_LMR_TRIPLET *, /* local_iov */ + IN DAT_DTO_COOKIE, /* user_cookie */ + IN DAT_COMPLETION_FLAGS ); /* completion_flags */ + +typedef DAT_RETURN (DAT_API *DAT_EP_POST_SEND_WITH_INVALIDATE_FUNC) ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_COUNT, /* num_segments */ + IN DAT_LMR_TRIPLET *, /* local_iov */ + IN DAT_DTO_COOKIE, /* user_cookie */ + IN DAT_COMPLETION_FLAGS, /* completion_flags */ + IN DAT_BOOLEAN, /* invalidate_flag */ + IN DAT_RMR_CONTEXT ); /* RMR context */ + +typedef DAT_RETURN (DAT_API *DAT_EP_POST_RECV_FUNC) ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_COUNT, /* num_segments */ + IN DAT_LMR_TRIPLET *, /* local_iov */ + IN DAT_DTO_COOKIE, /* user_cookie */ + IN DAT_COMPLETION_FLAGS ); /* completion_flags */ + +typedef DAT_RETURN (DAT_API *DAT_EP_POST_RDMA_READ_FUNC) ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_COUNT, /* num_segments */ + IN DAT_LMR_TRIPLET *, /* local_iov */ + IN DAT_DTO_COOKIE, /* user_cookie */ + IN const DAT_RMR_TRIPLET *,/* remote_iov */ + IN DAT_COMPLETION_FLAGS ); /* completion_flags */ + +typedef DAT_RETURN (DAT_API *DAT_EP_POST_RDMA_READ_TO_RMR_FUNC) ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN const DAT_RMR_TRIPLET *, /* local_iov */ + IN DAT_DTO_COOKIE, /* user_cookie */ + IN const DAT_RMR_TRIPLET *,/* remote_iov */ + IN DAT_COMPLETION_FLAGS ); /* completion_flags */ + +typedef DAT_RETURN (DAT_API *DAT_EP_POST_RDMA_WRITE_FUNC) ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_COUNT, /* num_segments */ + IN DAT_LMR_TRIPLET *, /* local_iov */ + IN DAT_DTO_COOKIE, /* user_cookie */ + IN const DAT_RMR_TRIPLET *,/* remote_iov */ + IN DAT_COMPLETION_FLAGS ); /* completion_flags */ + +typedef DAT_RETURN (DAT_API *DAT_EP_GET_STATUS_FUNC) ( + IN DAT_EP_HANDLE, /* ep_handle */ + OUT DAT_EP_STATE *, /* ep_state */ + OUT DAT_BOOLEAN *, /* recv_idle */ + OUT DAT_BOOLEAN * ); /* request_idle */ + +typedef DAT_RETURN (DAT_API *DAT_EP_FREE_FUNC) ( + IN DAT_EP_HANDLE); /* ep_handle */ + +typedef DAT_RETURN (DAT_API *DAT_EP_RESET_FUNC) ( + IN DAT_EP_HANDLE); /* ep_handle */ + +typedef DAT_RETURN (DAT_API *DAT_EP_RECV_QUERY_FUNC) ( + IN DAT_EP_HANDLE, /* ep_handle */ + OUT DAT_COUNT *, /* nbufs_allocated */ + OUT DAT_COUNT *); /* bufs_alloc_span */ + +typedef DAT_RETURN (DAT_API *DAT_EP_SET_WATERMARK_FUNC) ( + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_COUNT, /* ep_soft_high_watermark*/ + IN DAT_COUNT ); /* ep_hard_high_watermark*/ + +/* LMR functions */ + +typedef DAT_RETURN (DAT_API *DAT_LMR_FREE_FUNC) ( + IN DAT_LMR_HANDLE ); /* lmr_handle */ + +typedef DAT_RETURN (DAT_API *DAT_LMR_SYNC_RDMA_READ_FUNC) ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN const DAT_LMR_TRIPLET *,/* local segments */ + IN DAT_VLEN ); /* num_segments */ + +typedef DAT_RETURN (DAT_API *DAT_LMR_SYNC_RDMA_WRITE_FUNC) ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN const DAT_LMR_TRIPLET *, /* local_segments */ + IN DAT_VLEN ); /* num_segments */ + +/* RMR functions */ + +typedef DAT_RETURN (DAT_API *DAT_RMR_CREATE_FUNC) ( + IN DAT_PZ_HANDLE, /* pz_handle */ + OUT DAT_RMR_HANDLE *); /* rmr_handle */ + +typedef DAT_RETURN (DAT_API *DAT_RMR_CREATE_FOR_EP_FUNC) ( + IN DAT_PZ_HANDLE, /* pz_handle */ + OUT DAT_RMR_HANDLE *); /* rmr_handle */ + +typedef DAT_RETURN (DAT_API *DAT_RMR_QUERY_FUNC) ( + IN DAT_RMR_HANDLE, /* rmr_handle */ + IN DAT_RMR_PARAM_MASK, /* rmr_param_mask */ + OUT DAT_RMR_PARAM *); /* rmr_param */ + +typedef DAT_RETURN (DAT_API *DAT_RMR_BIND_FUNC) ( + IN DAT_RMR_HANDLE, /* rmr_handle */ + IN DAT_LMR_HANDLE, /* lmr_handle */ + IN const DAT_LMR_TRIPLET *,/* lmr_triplet */ + IN DAT_MEM_PRIV_FLAGS, /* mem_priv */ + IN DAT_VA_TYPE, /* va_type */ + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_RMR_COOKIE, /* user_cookie */ + IN DAT_COMPLETION_FLAGS, /* completion_flags */ + OUT DAT_RMR_CONTEXT * ); /* context */ + +typedef DAT_RETURN (DAT_API *DAT_RMR_FREE_FUNC) ( + IN DAT_RMR_HANDLE); /* rmr_handle */ + +/* PSP functions */ + +typedef DAT_RETURN (DAT_API *DAT_PSP_CREATE_FUNC) ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_CONN_QUAL, /* conn_qual */ + IN DAT_EVD_HANDLE, /* evd_handle */ + IN DAT_PSP_FLAGS, /* psp_flags */ + OUT DAT_PSP_HANDLE * ); /* psp_handle */ + +typedef DAT_RETURN (DAT_API *DAT_PSP_CREATE_ANY_FUNC) ( + IN DAT_IA_HANDLE, /* ia_handle */ + OUT DAT_CONN_QUAL *, /* conn_qual */ + IN DAT_EVD_HANDLE, /* evd_handle */ + IN DAT_PSP_FLAGS, /* psp_flags */ + OUT DAT_PSP_HANDLE * ); /* psp_handle */ + +typedef DAT_RETURN (DAT_API *DAT_PSP_QUERY_FUNC) ( + IN DAT_PSP_HANDLE, /* psp_handle */ + IN DAT_PSP_PARAM_MASK, /* psp_param_mask */ + OUT DAT_PSP_PARAM * ); /* psp_param */ + +typedef DAT_RETURN (DAT_API *DAT_PSP_FREE_FUNC) ( + IN DAT_PSP_HANDLE ); /* psp_handle */ + +/* RSP functions */ + +typedef DAT_RETURN (DAT_API *DAT_RSP_CREATE_FUNC) ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_CONN_QUAL, /* conn_qual */ + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_EVD_HANDLE, /* evd_handle */ + OUT DAT_RSP_HANDLE * ); /* rsp_handle */ + +typedef DAT_RETURN (DAT_API *DAT_RSP_QUERY_FUNC) ( + IN DAT_RSP_HANDLE, /* rsp_handle */ + IN DAT_RSP_PARAM_MASK, /* rsp_param_mask */ + OUT DAT_RSP_PARAM * ); /* rsp_param */ + +typedef DAT_RETURN (DAT_API *DAT_RSP_FREE_FUNC) ( + IN DAT_RSP_HANDLE ); /* rsp_handle */ + + /* CSP functions functions - DAT 2.0 */ + +typedef DAT_RETURN (DAT_API *DAT_CSP_CREATE_FUNC) ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_COMM *, /* communicator */ + IN DAT_IA_ADDRESS_PTR, /* address */ + IN DAT_EVD_HANDLE, /* evd_handle */ + OUT DAT_CSP_HANDLE * ); /* csp_handle */ + +typedef DAT_RETURN (DAT_API *DAT_CSP_QUERY_FUNC) ( + IN DAT_CSP_HANDLE, /* csp_handle */ + IN DAT_CSP_PARAM_MASK, /* csp_param_mask */ + OUT DAT_CSP_PARAM * ); /* csp_param */ + +typedef DAT_RETURN (DAT_API *DAT_CSP_FREE_FUNC) ( + IN DAT_CSP_HANDLE ); /* csp_handle */ + +/* PZ functions */ + +typedef DAT_RETURN (DAT_API *DAT_PZ_CREATE_FUNC) ( + IN DAT_IA_HANDLE, /* ia_handle */ + OUT DAT_PZ_HANDLE * ); /* pz_handle */ + +typedef DAT_RETURN (DAT_API *DAT_PZ_QUERY_FUNC) ( + IN DAT_PZ_HANDLE, /* pz_handle */ + IN DAT_PZ_PARAM_MASK, /* pz_param_mask */ + OUT DAT_PZ_PARAM *); /* pz_param */ + +typedef DAT_RETURN (DAT_API *DAT_PZ_FREE_FUNC) ( + IN DAT_PZ_HANDLE ); /* pz_handle */ + +/* SRQ functions */ + +typedef DAT_RETURN (DAT_API *DAT_SRQ_CREATE_FUNC) ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_PZ_HANDLE, /* pz_handle */ + IN DAT_SRQ_ATTR *, /* srq_attributes */ + OUT DAT_SRQ_HANDLE *); /* srq_handle */ + +typedef DAT_RETURN (DAT_API *DAT_SRQ_SET_LW_FUNC) ( + IN DAT_SRQ_HANDLE, /* srq_handle */ + IN DAT_COUNT ); /* srq_low_watermark */ + +typedef DAT_RETURN (DAT_API *DAT_SRQ_FREE_FUNC) ( + IN DAT_SRQ_HANDLE); /* srq_handle */ + +typedef DAT_RETURN (DAT_API *DAT_SRQ_QUERY_FUNC) ( + IN DAT_SRQ_HANDLE, /* srq_handle */ + IN DAT_SRQ_PARAM_MASK, /* srq_param_mask */ + OUT DAT_SRQ_PARAM *); /* srq_param */ + +typedef DAT_RETURN (DAT_API *DAT_SRQ_RESIZE_FUNC) ( + IN DAT_SRQ_HANDLE, /* srq_handle */ + IN DAT_COUNT ); /* srq_queue_length */ + +typedef DAT_RETURN (DAT_API *DAT_SRQ_POST_RECV_FUNC) ( + IN DAT_SRQ_HANDLE, /* srq_handle */ + IN DAT_COUNT, /* num_segments */ + IN DAT_LMR_TRIPLET *, /* local_iov */ + IN DAT_DTO_COOKIE ); /* user_cookie */ + +typedef DAT_RETURN (DAT_API *DAT_IA_HA_RELATED_FUNC) ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN const DAT_NAME_PTR, /* provider */ + OUT DAT_BOOLEAN *); /* answer */ + +#ifdef DAT_EXTENSIONS +#include +typedef DAT_RETURN (DAT_API *DAT_HANDLE_EXTENDEDOP_FUNC)( + IN DAT_HANDLE, /* handle */ + IN DAT_EXTENDED_OP, /* extended op */ + IN va_list); /* argument list */ +#endif /* DAT_EXTENSIONS */ + +#endif /* _DAT_REDIRECTION_H_ */ diff --git a/branches/WOF2-3/ulp/dapl2/dat/include/dat2/dat_registry.h b/branches/WOF2-3/ulp/dapl2/dat/include/dat2/dat_registry.h new file mode 100644 index 00000000..2c0edcbd --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dat/include/dat2/dat_registry.h @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2002-2006, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under all of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * Redistributions of source code must retain both 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. + * + * Neither the name of Network Appliance, Inc. nor the names of other DAT + * Collaborative contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + */ + +/**************************************************************** + * + * HEADER: dat_registry.h + * + * PURPOSE: DAT registration API signatures + * + * Description: Header file for "DAPL: Direct Access Programming + * Library, Version: 2.0" + * + * Contains registration external reference signatures + * for dat registry functions. This file is *only* + * included by providers, not consumers. + * + * Mapping rules: + * All global symbols are prepended with DAT_ or dat_ + * All DAT objects have an 'api' tag which, such as 'ep' or 'lmr' + * The method table is in the provider definition structure. + * + **********************************************************/ +#ifndef _DAT_REGISTRY_H_ +#define _DAT_REGISTRY_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#if defined(_UDAT_H_) +#include +#elif defined(_KDAT_H_) +#include +#else +#error Must include udat.h or kdat.h +#endif + +/* + * dat registration API. + * + * Technically the dat_ia_open is part of the registration API. This + * is so the registration module can map the device name to a provider + * structure and then call the provider dat_ia_open function. + * dat_is_close is also part of the registration API so that the + * registration code can be aware when an ia is no longer in use. + * + */ + +extern DAT_RETURN DAT_API dat_registry_add_provider ( + IN const DAT_PROVIDER *, /* provider */ + IN const DAT_PROVIDER_INFO* ); /* provider info */ + +extern DAT_RETURN DAT_API dat_registry_remove_provider ( + IN const DAT_PROVIDER *, /* provider */ + IN const DAT_PROVIDER_INFO* ); /* provider info */ + +/* + * Provider initialization APIs. + * + * Providers that support being automatically loaded by the Registry must + * implement these APIs and export them as public symbols. + */ + +#define DAT_PROVIDER_INIT_FUNC_NAME dat_provider_init +#define DAT_PROVIDER_FINI_FUNC_NAME dat_provider_fini + +#define DAT_PROVIDER_INIT_FUNC_STR "dat_provider_init" +#define DAT_PROVIDER_FINI_FUNC_STR "dat_provider_fini" + +typedef void ( DAT_API *DAT_PROVIDER_INIT_FUNC) ( + IN const DAT_PROVIDER_INFO *, /* provider info */ + IN const char *); /* instance data */ + +typedef void ( DAT_API *DAT_PROVIDER_FINI_FUNC) ( + IN const DAT_PROVIDER_INFO *); /* provider info */ + +typedef enum dat_ha_relationship +{ + DAT_HA_FALSE, /* two IAs are not related */ + DAT_HA_TRUE, /* two IAs are related */ + DAT_HA_UNKNOWN, /* relationship is not known */ + DAT_HA_CONFLICTING, /* 2 IAs do not agree on the relationship */ + DAT_HA_EXTENSION_BASE +} DAT_HA_RELATIONSHIP; + +extern DAT_RETURN DAT_API dat_registry_providers_related ( + IN const DAT_NAME_PTR, + IN const DAT_NAME_PTR, + OUT DAT_HA_RELATIONSHIP * ); + +#ifdef __cplusplus +} +#endif + +#endif /* _DAT_REGISTRY_H_ */ diff --git a/branches/WOF2-3/ulp/dapl2/dat/include/dat2/dat_vendor_specific.h b/branches/WOF2-3/ulp/dapl2/dat/include/dat2/dat_vendor_specific.h new file mode 100644 index 00000000..844fc7e4 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dat/include/dat2/dat_vendor_specific.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2002-2006, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under all of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * Redistributions of source code must retain both the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/*************************************************************** + * + * HEADER: dat_vendor_specific.h + * + * PURPOSE: + * + * Description: Header file for "DAPL: Direct Access Programming + * Library, Version: 2.0" + * + * Mapping rules: + * + ***************************************************************/ + +#ifndef _DAT_VENDOR_SPECIFIC_H_ +#define _DAT_VENDOR_SPECIFIC_H_ + + + +/* Vendor-specific extensions */ + +#if defined(_AMMASSO) + +#elif defined(_BROADCOM) + +#elif defined(_CISCO) + +#elif defined(_IBM) + +#elif defined(_INTEL) + +#elif defined(_JNI) + +#elif defined(_MELLANOX) + +#elif defined(_MYRINET) + +#elif defined(_NETEFFECT) + +#elif defined(_QLOGIC) + +#elif defined(_SILVERSTORM) + +#elif defined(_VOLTAIRE) + +#endif + +#endif /* _DAT_VENDOR_SPECIFIC_H_ */ diff --git a/branches/WOF2-3/ulp/dapl2/dat/include/dat2/kdat.h b/branches/WOF2-3/ulp/dapl2/dat/include/dat2/kdat.h new file mode 100644 index 00000000..704c1cb5 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dat/include/dat2/kdat.h @@ -0,0 +1,487 @@ +/* + * Copyright (c) 2002-2006, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under all of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * Redistributions of source code must retain both 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. + * + * Neither the name of Network Appliance, Inc. nor the names of other DAT + * Collaborative contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + */ + +/**************************************************************** + * + * HEADER: kdat.h + * + * PURPOSE: defines the kernel DAT API + * + * Description: Header file for "kDAPL: Kernel Direct Access Programming + * Library, Version: 2.0" + * Mapping rules: + * All global symbols are prepended with DAT_ or dat_ + * All DAT objects have an 'api' tag which, such as 'ep' or 'lmr' + * The method table is in the provider definition structure. + * + * + * + ***************************************************************/ + +#ifndef _KDAT_H_ +#define _KDAT_H_ + +#include + +#include + +#if 1 +#define EXPORT_SYMBOL_NOVERS(sym) EXPORT_SYMBOL(sym) +#endif + +typedef enum dat_mem_type +{ + /* Shared between udat and kdat */ + DAT_MEM_TYPE_VIRTUAL = 0x00, + DAT_MEM_TYPE_LMR = 0x01, + /* kdat specific */ + DAT_MEM_TYPE_PHYSICAL = 0x10, + DAT_MEM_TYPE_PLATFORM = 0x20, + DAT_MEM_TYPE_IA = 0x40, + DAT_MEM_TYPE_BYPASS = 0x80, + DAT_MEM_TYPE_PHYSICAL_VAR_PAGES = 0x100 +} DAT_MEM_TYPE; + +/* dat handle types */ +typedef enum dat_handle_type +{ + DAT_HANDLE_TYPE_CR, + DAT_HANDLE_TYPE_EP, + DAT_HANDLE_TYPE_EVD, + DAT_HANDLE_TYPE_IA, + DAT_HANDLE_TYPE_LMR, + DAT_HANDLE_TYPE_PSP, + DAT_HANDLE_TYPE_PZ, + DAT_HANDLE_TYPE_RMR, + DAT_HANDLE_TYPE_RSP, + DAT_HANDLE_TYPE_SRQ, + DAT_HANDLE_TYPE_CSP +#ifdef DAT_EXTENSIONS + ,DAT_HANDLE_TYPE_EXTENSION_BASE +#endif +} DAT_HANDLE_TYPE; + +typedef enum dat_evd_param_mask +{ + DAT_EVD_FIELD_IA_HANDLE = 0x01, + DAT_EVD_FIELD_EVD_QLEN = 0x02, + DAT_EVD_FIELD_UPCALL_POLICY = 0x04, + DAT_EVD_FIELD_UPCALL = 0x08, + DAT_EVD_FIELD_EVD_FLAGS = 0x10, + DAT_EVD_FIELD_ALL = 0x1F +} DAT_EVD_PARAM_MASK; + +typedef DAT_UINT64 DAT_PROVIDER_ATTR_MASK; + +#include + +typedef DAT_CONTEXT DAT_LMR_COOKIE; + +/* Upcall support */ + +typedef enum dat_upcall_policy +{ + DAT_UPCALL_DISABLE = 0, /* support no_upcalls */ + DAT_UPCALL_SINGLE_INSTANCE = 1, /* support only one upcall */ + DAT_UPCALL_MANY = 100, /* support multiple upcalls */ + DAT_UPCALL_TEARDOWN = -1 /* support no upcalls & return * + * after all in progress * + * UpCalls return */ + ,DAT_UPCALL_NORIFY = 2 /* support single upcall with * + * notification only */ +} DAT_UPCALL_POLICY; + +typedef void (*DAT_UPCALL_FUNC)( + DAT_PVOID, /* instance_data */ + const DAT_EVENT *, /* event */ + DAT_BOOLEAN); /* more_events */ + +typedef struct dat_upcall_object +{ + DAT_PVOID instance_data; + DAT_UPCALL_FUNC upcall_func; +} DAT_UPCALL_OBJECT; + +/* Define NULL upcall */ + +#define DAT_UPCALL_NULL \ + (DAT_UPCALL_OBJECT) { (DAT_PVOID) NULL, \ + (DAT_UPCALL_FUNC) NULL} + +#define DAT_UPCALL_SAME ((DAT_UPCALL_OBJECT *) NULL) + + /* kDAT Upcall Invocation Policy */ +typedef enum dat_upcall_flag +{ + DAT_UPCALL_INVOC_NEW = 0, /* invoke on a new event arrival */ + DAT_UPCALL_INVOC_ANY = 1 /* invoke on any event on EVD */ +} DAT_UPCALL_FLAG; + +struct dat_evd_param +{ + DAT_IA_HANDLE ia_handle; + DAT_COUNT evd_qlen; + DAT_UPCALL_POLICY upcall_policy; + DAT_UPCALL_OBJECT upcall; + DAT_EVD_FLAGS evd_flags; +}; + +/* + * Memory types + * + * Specifying memory type for LMR create. A Consumer must use a single + * value when registering memory. The union of any of these + * flags is used in the Provider parameters to indicate what memory + * type Provider supports for LMR memory creation. + */ + +/* memory data types */ +#define DAT_MEM_OPT DAT_MEM_OPTIMIZE_FLAGS + +typedef enum dat_mem_optimize_flags +{ + DAT_MEM_OPTIMIZE_DONT_CARE = 0x00, + DAT_MEM_OPTIMIZE_IA = 0x01, + DAT_MEM_OPTIMIZE_MIN_EXPOSURE = 0x02, + DAT_MEM_OPTIMIZE_EXACT_EXPOSURE = 0x04 +} DAT_MEM_OPTIMIZE_FLAGS; + +typedef struct dat_physical_var_pages +{ + DAT_VLEN page_size; + void* pages; +} DAT_PHYSICAL_VAR_PAGES; + +typedef union dat_region_description +{ + DAT_PVOID for_va; + DAT_LMR_HANDLE for_lmr_handle; + void * for_platform; /* For kdapl only + for platform and bypass */ + DAT_PHYSICAL_VAR_PAGES for_array; /* for kdapl only */ + DAT_PADDR *for_physical; /* for kdapl only */ + /* array of physical pages of the same size */ + DAT_PADDR for_ia; /* for kdapl only */ +} DAT_REGION_DESCRIPTION; + +/* LMR Arguments */ +typedef struct dat_lmr_state +{ + DAT_BOOLEAN fmr_support; + DAT_BOOLEAN bound; +} DAT_LMR_STATE; + +struct dat_lmr_param +{ + DAT_IA_HANDLE ia_handle; + DAT_MEM_TYPE mem_type; + DAT_REGION_DESCRIPTION region_desc; + DAT_VLEN length; + DAT_PZ_HANDLE pz_handle; + DAT_MEM_PRIV_FLAGS mem_priv; + DAT_VA_TYPE va_type; + DAT_LMR_CONTEXT lmr_context; + DAT_RMR_CONTEXT rmr_context; + DAT_VLEN registered_size; + DAT_VADDR registered_address; + DAT_LMR_STATE lmr_state; /* kDAPL only */ +}; + +/* LMR Arguments Mask */ + +enum dat_lmr_param_mask +{ + DAT_LMR_FIELD_IA_HANDLE = 0x001, + DAT_LMR_FIELD_MEM_TYPE = 0x002, + DAT_LMR_FIELD_REGION_DESC = 0x004, + DAT_LMR_FIELD_LENGTH = 0x008, + DAT_LMR_FIELD_PZ_HANDLE = 0x010, + DAT_LMR_FIELD_MEM_PRIV = 0x020, + DAT_LMR_FIELD_VA_TYPE = 0x040, + DAT_LMR_FIELD_LMR_CONTEXT = 0x080, + DAT_LMR_FIELD_RMR_CONTEXT = 0x100, + DAT_LMR_FIELD_REGISTERED_SIZE = 0x200, + DAT_LMR_FIELD_REGISTERED_ADDRESS = 0x400, + DAT_LMR_FIELD_LMR_STATE = 0x800, + + DAT_LMR_FIELD_ALL = 0xFFF +}; + + /* kDAPL 1.3 addition */ + /* Defines LMR protection scope */ +typedef enum dat_lmr_scope +{ + DAT_LMR_SCOPE_EP, /* bound to at most one EP at a time. */ + DAT_LMR_SCOPE_PZ, /* bound to a Protection Zone */ + DAT_LMR_SCOPE_ANY /* Supports all types */ +} DAT_LMR_SCOPE; + +struct dat_ia_attr +{ + char adapter_name[DAT_NAME_MAX_LENGTH]; + char vendor_name[DAT_NAME_MAX_LENGTH]; + DAT_UINT32 hardware_version_major; + DAT_UINT32 hardware_version_minor; + DAT_UINT32 firmware_version_major; + DAT_UINT32 firmware_version_minor; + DAT_IA_ADDRESS_PTR ia_address_ptr; + DAT_COUNT max_eps; + DAT_COUNT max_dto_per_ep; + DAT_COUNT max_rdma_read_per_ep_in; + DAT_COUNT max_rdma_read_per_ep_out; + DAT_COUNT max_evds; + DAT_COUNT max_evd_qlen; + DAT_COUNT max_iov_segments_per_dto; + DAT_COUNT max_lmrs; + DAT_SEG_LENGTH max_lmr_block_size; + DAT_VADDR max_lmr_virtual_address; + DAT_COUNT max_pzs; + DAT_SEG_LENGTH max_message_size; + DAT_SEG_LENGTH max_rdma_size; + DAT_COUNT max_rmrs; + DAT_VADDR max_rmr_target_address; + DAT_COUNT max_srqs; + DAT_COUNT max_ep_per_srq; + DAT_COUNT max_recv_per_srq; + DAT_COUNT max_iov_segments_per_rdma_read; + DAT_COUNT max_iov_segments_per_rdma_write; + DAT_COUNT max_rdma_read_in; + DAT_COUNT max_rdma_read_out; + DAT_BOOLEAN max_rdma_read_per_ep_in_guaranteed; + DAT_BOOLEAN max_rdma_read_per_ep_out_guaranteed; + DAT_BOOLEAN zb_supported; + DAT_BOOLEAN reserved_lmr_supported; +#ifdef DAT_EXTENSIONS + DAT_EXTENSION extension_supported; + DAT_COUNT extension_version; +#endif /* DAT_EXTENSIONS */ + DAT_COUNT num_transport_attr; + DAT_NAMED_ATTR *transport_attr; + DAT_COUNT num_vendor_attr; + DAT_NAMED_ATTR *vendor_attr; +}; + +#define DAT_IA_FIELD_IA_RESERVED_LMR_SUPPORTED UINT64_C(0x100000000) +#ifdef DAT_EXTENSIONS +#define DAT_IA_FIELD_IA_EXTENSION UINT64_C(0x200000000) +#define DAT_IA_FIELD_IA_EXTENSION_VERSION UINT64_C(0x400000000) +#endif /* DAT_EXTENSIONS */ + +#define DAT_IA_FIELD_IA_NUM_TRANSPORT_ATTR UINT64_C(0x800000000) +#define DAT_IA_FIELD_IA_TRANSPORT_ATTR UINT64_C(0x1000000000) +#define DAT_IA_FIELD_IA_NUM_VENDOR_ATTR UINT64_C(0x2000000000) +#define DAT_IA_FIELD_IA_VENDOR_ATTR UINT64_C(0x4000000000) +#define DAT_IA_FIELD_ALL UINT64_C(0x7FFFFFFFFF) + +#define DAT_EVENT_NULL ((DAT_EVENT) NULL) + +/* General Provider attributes. kdat specific. */ + +#include + +/* Provider should support merging of all event stream types. Provider + * attribute specify support for merging different event stream types. + * It is a 2D binary matrix where each row and column represents an event + * stream type. Each binary entry is 1 if the event streams of its raw + * and column can fed the same EVD, and 0 otherwise. The order of event + * streams in row and column is the same as in the definition of + * DAT_EVD_FLAGS: index 0 - Software Event, 1- Connection Request, + * 2 - DTO Completion, 3 - Connection event, 4 - RMR Bind Completion, + * 5 - Asynchronous event. By definition each diagonal entry is 1. + * Consumer allocates an array for it and passes it IN as a pointer + * for the array that Provider fills. Provider must fill the array + * that Consumer passes. + */ + +struct dat_provider_attr +{ + char provider_name[DAT_NAME_MAX_LENGTH]; + DAT_UINT32 provider_version_major; + DAT_UINT32 provider_version_minor; + DAT_UINT32 dapl_version_major; + DAT_UINT32 dapl_version_minor; + DAT_MEM_TYPE lmr_mem_types_supported; + DAT_IOV_OWNERSHIP iov_ownership_on_return; + DAT_QOS dat_qos_supported; + DAT_COMPLETION_FLAGS completion_flags_supported; + DAT_BOOLEAN is_thread_safe; + DAT_COUNT max_private_data_size; + DAT_BOOLEAN supports_multipath; + DAT_EP_CREATOR_FOR_PSP ep_creator; + DAT_UPCALL_POLICY upcall_policy; + DAT_UINT32 optimal_buffer_alignment; + const DAT_BOOLEAN evd_stream_merging_supported[6][6]; + DAT_BOOLEAN srq_supported; + DAT_COUNT srq_watermarks_supported; + DAT_BOOLEAN srq_ep_pz_difference_supported; + DAT_COUNT srq_info_supported; + DAT_COUNT ep_recv_info_supported; + DAT_BOOLEAN lmr_sync_req; + DAT_BOOLEAN dto_async_return_guaranteed; + DAT_BOOLEAN rdma_write_for_rdma_read_req; + DAT_BOOLEAN rdma_read_lmr_rmr_context_exposure; + DAT_RMR_SCOPE rmr_scope_supported; + DAT_BOOLEAN is_interrupt_safe; + DAT_BOOLEAN fmr_supported; + DAT_LMR_SCOPE lmr_for_fmr_scope_supported; + DAT_BOOLEAN ha_supported; + DAT_HA_LB ha_loadbalancing; + + DAT_COUNT num_provider_specific_attr; + DAT_NAMED_ATTR * provider_specific_attr; +}; + + +#define DAT_PROVIDER_FIELD_PROVIDER_NAME UINT64_C(0x000000001) +#define DAT_PROVIDER_FIELD_PROVIDER_VERSION_MAJOR UINT64_C(0x000000002) +#define DAT_PROVIDER_FIELD_PROVIDER_VERSION_MINOR UINT64_C(0x000000004) +#define DAT_PROVIDER_FIELD_DAPL_VERSION_MAJOR UINT64_C(0x000000008) +#define DAT_PROVIDER_FIELD_DAPL_VERSION_MINOR UINT64_C(0x000000010) +#define DAT_PROVIDER_FIELD_LMR_MEM_TYPE_SUPPORTED UINT64_C(0x000000020) +#define DAT_PROVIDER_FIELD_IOV_OWNERSHIP UINT64_C(0x000000040) +#define DAT_PROVIDER_FIELD_DAT_QOS_SUPPORTED UINT64_C(0x000000080) +#define DAT_PROVIDER_FIELD_COMPLETION_FLAGS_SUPPORTED UINT64_C(0x000000100) +#define DAT_PROVIDER_FIELD_IS_THREAD_SAFE UINT64_C(0x000000200) +#define DAT_PROVIDER_FIELD_MAX_PRIVATE_DATA_SIZE UINT64_C(0x000000400) +#define DAT_PROVIDER_FIELD_SUPPORTS_MULTIPATH UINT64_C(0x000000800) +#define DAT_PROVIDER_FIELD_EP_CREATOR UINT64_C(0x000001000) +#define DAT_PROVIDER_FIELD_UPCALL_POLICY UINT64_C(0x000002000) +#define DAT_PROVIDER_FIELD_OPTIMAL_BUFFER_ALIGNMENT UINT64_C(0x000004000) +#define DAT_PROVIDER_FIELD_EVD_STREAM_MERGING_SUPPORTED UINT64_C(0x000008000) +#define DAT_PROVIDER_FIELD_SRQ_SUPPORTED UINT64_C(0x000010000) +#define DAT_PROVIDER_FIELD_SRQ_WATERMARKS_SUPPORTED UINT64_C(0x000020000) +#define DAT_PROVIDER_FIELD_SRQ_EP_PZ_DIFFERENCE_SUPPORTED UINT64_C(0x000040000) +#define DAT_PROVIDER_FIELD_SRQ_INFO_SUPPORTED UINT64_C(0x000080000) +#define DAT_PROVIDER_FIELD_EP_RECV_INFO_SUPPORTED UINT64_C(0x000100000) +#define DAT_PROVIDER_FIELD_LMR_SYNC_REQ UINT64_C(0x000200000) +#define DAT_PROVIDER_FIELD_DTO_ASYNC_RETURN_GUARANTEED UINT64_C(0x000400000) +#define DAT_PROVIDER_FIELD_RDMA_WRITE_FOR_RDMA_READ_REQ UINT64_C(0x000800000) +#define DAT_PROVIDER_FIELD_RDMA_READ_LMR_RMR_CONTEXT_EXPOSURE UINT64_C(0x001000000) +#define DAT_PROVIDER_FIELD_RMR_SCOPE_SUPPORTED UINT64_C(0x002000000) +#define DAT_PROVIDER_FIELD_IS_INTERRUPT_SAFE UINT64_C(0x004000000) +#define DAT_PROVIDER_FIELD_FMR_SUPPORTED UINT64_C(0x008000000) +#define DAT_PROVIDER_FIELD_LMR_FOR_FMR_SCOPE UINT64_C(0x010000000) +#define DAT_PROVIDER_FIELD_HA_SUPPORTED UINT64_C(0x020000000) +#define DAT_PROVIDER_FIELD_HA_LB UINT64_C(0x040000000) +#define DAT_PROVIDER_FIELD_NUM_PROVIDER_SPECIFIC_ATTR UINT64_C(0x080000000) +#define DAT_PROVIDER_FIELD_PROVIDER_SPECIFIC_ATTR UINT64_C(0x100000000) + +#define DAT_PROVIDER_FIELD_ALL UINT64_C(0x1FFFFFFFF) +#define DAT_PROVIDER_FIELD_NONE UINT64_C(0x0) + +/**********************************************************************/ + +/* + * Kernel DAT function call definitions, + */ + +extern DAT_RETURN dat_lmr_kcreate ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_MEM_TYPE, /* mem_type */ + IN DAT_REGION_DESCRIPTION, /* region_description */ + IN DAT_VLEN, /* length */ + IN DAT_PZ_HANDLE, /* pz_handle */ + IN DAT_MEM_PRIV_FLAGS, /* privileges */ + IN DAT_VA_TYPE, /* va_type */ + IN DAT_MEM_OPTIMIZE_FLAGS, /* mem_optimization */ + OUT DAT_LMR_HANDLE *, /* lmr_handle */ + OUT DAT_LMR_CONTEXT *, /* lmr_context */ + OUT DAT_RMR_CONTEXT *, /* rmr_context */ + OUT DAT_VLEN *, /* registered_length */ + OUT DAT_VADDR * ); /* registered_address */ + +extern DAT_RETURN dat_ia_memtype_hint ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_MEM_TYPE, /* mem_type */ + IN DAT_VLEN, /* length */ + IN DAT_MEM_OPTIMIZE_FLAGS, /* mem_optimization */ + OUT DAT_VLEN *, /* preferred_length */ + OUT DAT_VADDR * ); /* preferred_alignment */ + +extern DAT_RETURN dat_lmr_query ( + IN DAT_LMR_HANDLE, /* lmr_handle */ + IN DAT_LMR_PARAM_MASK, /* lmr_param_mask */ + OUT DAT_LMR_PARAM *); /* lmr_param */ + +extern DAT_RETURN dat_lmr_allocate ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_PZ_HANDLE, /* pz_handle */ + IN DAT_COUNT, /* max # of physical pages */ + IN DAT_LMR_SCOPE, /* scope of lmr */ + OUT DAT_LMR_HANDLE * ); /*lmr handle */ + +extern DAT_RETURN dat_lmr_fmr ( + IN DAT_LMR_HANDLE, /* lmr_handle */ + IN DAT_MEM_TYPE, /* mem_type */ + IN DAT_REGION_DESCRIPTION, /* region_description */ + IN DAT_VLEN, /* number of pages */ + IN DAT_MEM_PRIV_FLAGS, /* mem_privileges */ + IN DAT_VA_TYPE, /* va_type */ + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_LMR_COOKIE, /* user_cookie */ + IN DAT_COMPLETION_FLAGS, /* completion_flags */ + OUT DAT_LMR_CONTEXT, /* lmr_context */ + OUT DAT_RMR_CONTEXT ); /* rmr_context */ + +extern DAT_RETURN dat_lmr_invalidate ( + IN DAT_LMR_HANDLE, /* lmr_handle */ + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_LMR_COOKIE, /* user_cookie */ + IN DAT_COMPLETION_FLAGS ); /* completion_flags */ + +extern DAT_RETURN dat_ia_reserved_lmr ( + IN DAT_IA_HANDLE, /* ia_handle */ + OUT DAT_LMR_HANDLE *, /* reserved_lmr_handle */ + OUT DAT_LMR_CONTEXT * ); /* reserved_lmr_context */ + +extern DAT_RETURN dat_evd_kcreate ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_COUNT, /* evd_min_qlen */ + IN DAT_UPCALL_POLICY, /* upcall_policy */ + IN const DAT_UPCALL_OBJECT *, /* upcall */ + IN DAT_EVD_FLAGS, /* evd_flags */ + OUT DAT_EVD_HANDLE * ); /* evd_handle */ + +extern DAT_RETURN dat_evd_modify_upcall ( + IN DAT_EVD_HANDLE, /* evd_handle */ + IN DAT_UPCALL_POLICY, /* upcall_policy */ + IN const DAT_UPCALL_OBJECT* , /* upcall */ + IN DAT_UPCALL_FLAG ); /* upcall invocation policy */ + +#endif /* _KDAT_H_ */ diff --git a/branches/WOF2-3/ulp/dapl2/dat/include/dat2/kdat_config.h b/branches/WOF2-3/ulp/dapl2/dat/include/dat2/kdat_config.h new file mode 100644 index 00000000..855a629a --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dat/include/dat2/kdat_config.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2002-2006, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under all of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * Redistributions of source code must retain both 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. + * + * Neither the name of Network Appliance, Inc. nor the names of other DAT + * Collaborative contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + */ + +/*************************************************************** + * + * HEADER: kdat_config.h + * + * PURPOSE: provides kDAPL configuration information. + * + * Description: Header file for "kDAPL: Kernel Direct Access Programming + * Library, Version: 2.0" + * + ***************************************************************/ +#ifndef _KDAT_CONFIG_H_ +#define _KDAT_CONFIG_H_ + +#define DAT_VERSION_MAJOR 1 +#define DAT_VERSION_MINOR 2 + +/* + * The official header files will default DAT_THREADSAFE to DAT_TRUE. If + * your project does not wish to use this default, you must ensure that + * DAT_THREADSAFE will be set to DAT_FALSE. This may be done by an + * explicit #define in a common project header file that is included + * before any DAT header files, or through command line directives to the + * compiler (presumably controlled by the make environment). + */ + +/* + * A site, project or platform may consider setting an alternate default + * via their make rules, but are discouraged from doing so by editing + * the official header files. + */ + +/* + * The Reference Implementation is not Thread Safe. The Reference + * Implementation has chosen to go with the first method and define it + * explicitly in the header file. + */ + +#define DAT_THREADSAFE DAT_FALSE + +#ifndef DAT_THREADSAFE +#define DAT_THREADSAFE DAT_TRUE +#endif /* DAT_THREADSAFE */ + +#endif /* _KDAT_CONFIG_H_ */ diff --git a/branches/WOF2-3/ulp/dapl2/dat/include/dat2/kdat_redirection.h b/branches/WOF2-3/ulp/dapl2/dat/include/dat2/kdat_redirection.h new file mode 100644 index 00000000..d7e56287 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dat/include/dat2/kdat_redirection.h @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2002-2006, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under all of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * Redistributions of source code must retain both 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. + * + * Neither the name of Network Appliance, Inc. nor the names of other DAT + * Collaborative contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + */ + +/**************************************************************** + * + * HEADER: kdat_redirection.h + * + * PURPOSE: Kernel DAT macro definitions + * + * Description: Macros to invoke DAPL functions from the dat_registry + * + * Mapping rules: + * All global symbols are prepended with DAT_ or dat_ + * All DAT objects have an 'api' tag which, such as 'ep' or 'lmr' + * The method table is in the provider definition structure. + * + **********************************************************/ + +#ifndef _KDAT_REDIRECTION_H_ +#define _KDAT_REDIRECTION_H_ + +/* ia_memtype_hint macro */ + +#define DAT_IA_MEMTYPE_HINT(ia, mem_type, len, mem_opt, pref_len, pref_align) \ + (*DAT_HANDLE_TO_PROVIDER(ia)->ia_memtype_hint_func)(\ + (ia), \ + (mem_type), \ + (len), \ + (mem_opt), \ + (pref_len), \ + (pref_align)) + +/* evd_modify_upcall macro */ + +#define DAT_EVD_MODIFY_UPCALL(evd, policy, upcall, flag) \ + (*DAT_HANDLE_TO_PROVIDER(evd)->evd_modify_upcall_func)(\ + (evd), \ + (policy), \ + (upcall), \ + (flag)) + +/* evd_create macro */ +#define DAT_EVD_KCREATE(ia,qlen,policy,upcall,flags,handle) \ + (*DAT_HANDLE_TO_PROVIDER(ia)->evd_kcreate_func)(\ + (ia), \ + (qlen), \ + (policy), \ + (upcall), \ + (flags), \ + (handle)) + +/* lmr_kcreate macro */ +#define DAT_LMR_KCREATE(ia,mtype,reg_desc,len,pz,priv,mem_opt,\ + va_type,lmr,lmr_context,rmr_context,reg_len,reg_addr) \ + (*DAT_HANDLE_TO_PROVIDER(ia)->lmr_kcreate_func)(\ + (ia), \ + (mtype), \ + (reg_desc), \ + (len), \ + (pz), \ + (priv), \ + (mem_opt), \ + (va_type), \ + (lmr), \ + (lmr_context), \ + (rmr_context), \ + (reg_len), \ + (reg_addr)) + +#define DAT_LMR_ALLOCATE(ia,pz,size,scope,lmr) \ + (*DAT_HANDLE_TO_PROVIDER(ia)->lmr_allocate_func)(\ + (ia), \ + (pz), \ + (size), \ + (scope), \ + (lmr)) + +#define DAT_LMR_FMR(lmr,mtype,reg_desc,length,priv,\ + va_type,ep,cookie,flags,lmr_context,rmr_context) \ + (*DAT_HANDLE_TO_PROVIDER(lmr)->lmr_fmr_func)(\ + (lmr),\ + (mtype),\ + (reg_desc),\ + (length),\ + (priv),\ + (va_type),\ + (ep),\ + (cookie),\ + (flags),\ + (lmr_context),\ + (rmr_context)) + +#define DAT_LMR_INVALIDATE(lmr, ep,cookie,flags) \ + (*DAT_HANDLE_TO_PROVIDER(lmr)->lmr_invalidate_func)(\ + (lmr),\ + (ep),\ + (cookie),\ + (flags)) + +#define DAT_IA_RESERVED_LMR(ia, lmr, lmr_context) \ + (*DAT_HANDLE_TO_PROVIDER(ia)->ia_reserved_lmr_func)(\ + (ia),\ + (lmr),\ + (lmr_context)) + +/*************************************************************** + * FUNCTION PROTOTYPES + * + * Kernel DAT function call definitions, + * + ****************************************************************/ + +typedef DAT_RETURN (*DAT_LMR_KCREATE_FUNC) ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_MEM_TYPE, /* mem_type */ + IN DAT_REGION_DESCRIPTION, /* region_description */ + IN DAT_VLEN, /* length */ + IN DAT_PZ_HANDLE, /* pz_handle */ + IN DAT_MEM_PRIV_FLAGS, /* privileges */ + IN DAT_VA_TYPE, /* va_type */ + IN DAT_MEM_OPTIMIZE_FLAGS, /* mem_optimization */ + OUT DAT_LMR_HANDLE *, /* lmr_handle */ + OUT DAT_LMR_CONTEXT *, /* lmr_context */ + OUT DAT_RMR_CONTEXT *, /* rmr_context */ + OUT DAT_VLEN *, /* registered_length */ + OUT DAT_VADDR * ); /* registered_address */ + + +typedef DAT_RETURN (*DAT_IA_MEMTYPE_HINT_FUNC) ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_MEM_TYPE, /* mem_type */ + IN DAT_VLEN, /* length */ + IN DAT_MEM_OPTIMIZE_FLAGS, /* mem_optimization */ + OUT DAT_VLEN *, /* preferred_length */ + OUT DAT_VADDR * ); /* preferred_alignment */ + +typedef DAT_RETURN (*DAT_LMR_QUERY_FUNC) ( + IN DAT_LMR_HANDLE, /* lmr_handle */ + IN DAT_LMR_PARAM_MASK, /* lmr_param_mask */ + OUT DAT_LMR_PARAM *); /* lmr_param */ + +typedef DAT_RETURN (*DAT_LMR_ALLOCATE_FUNC) ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_PZ_HANDLE, /* pz_handle */ + IN DAT_COUNT, /* max number of physical pages */ + IN DAT_LMR_SCOPE, /* scope of LMR */ + OUT DAT_LMR_HANDLE ); /* lmr_handle */ + +typedef DAT_RETURN (*DAT_LMR_FMR_FUNC) ( + IN DAT_LMR_HANDLE, /* lmr_handle */ + IN DAT_MEM_TYPE, /* mem_type */ + IN const DAT_REGION_DESCRIPTION, /* region_description */ + IN DAT_VLEN, /* number of pages */ + IN DAT_MEM_PRIV_FLAGS, /* mem_privileges */ + IN DAT_VA_TYPE, /* va_type */ + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_LMR_COOKIE, /* user_cookie */ + IN DAT_COMPLETION_FLAGS, /* completion_flags */ + OUT DAT_LMR_CONTEXT * , /* lmr_context */ + OUT DAT_RMR_CONTEXT * ); /* rmr_context */ + +typedef DAT_RETURN (*DAT_LMR_INVALIDATE_FUNC) ( + IN DAT_LMR_HANDLE, /* lmr_handle */ + IN DAT_EP_HANDLE, /* ep_handle */ + IN DAT_LMR_COOKIE, /* user_cookie */ + IN DAT_COMPLETION_FLAGS ); /* completion_flags */ + +typedef DAT_RETURN (*DAT_EVD_KCREATE_FUNC) ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_COUNT, /* evd_min_qlen */ + IN DAT_UPCALL_POLICY, /* upcall_policy */ + IN const DAT_UPCALL_OBJECT *, /* upcall */ + IN DAT_EVD_FLAGS, /* evd_flags */ + OUT DAT_EVD_HANDLE * ); /* evd_handle */ + +typedef DAT_RETURN (*DAT_EVD_MODIFY_UPCALL_FUNC) ( + IN DAT_EVD_HANDLE, /* evd_handle */ + IN DAT_UPCALL_POLICY, /* upcall_policy */ + IN const DAT_UPCALL_OBJECT *, /* upcall */ + IN DAT_UPCALL_FLAG ); /* upcall invocation flag */ + +typedef DAT_RETURN (*DAT_IA_RESERVED_LMR_FUNC) ( + IN DAT_IA_HANDLE, /* ia_handle */ + OUT DAT_LMR_HANDLE *, /* lmr_handle */ + OUT DAT_LMR_CONTEXT * ); /* lmr_context */ + +#include + +struct dat_provider +{ + const char * device_name; + DAT_PVOID extension; + + DAT_IA_OPEN_FUNC ia_open_func; + DAT_IA_QUERY_FUNC ia_query_func; + DAT_IA_CLOSE_FUNC ia_close_func; + DAT_IA_MEMTYPE_HINT_FUNC ia_memtype_hint_func; /* kdat only */ + + DAT_SET_CONSUMER_CONTEXT_FUNC set_consumer_context_func; + DAT_GET_CONSUMER_CONTEXT_FUNC get_consumer_context_func; + DAT_GET_HANDLE_TYPE_FUNC get_handle_type_func; + + DAT_CR_QUERY_FUNC cr_query_func; + DAT_CR_ACCEPT_FUNC cr_accept_func; + DAT_CR_REJECT_FUNC cr_reject_func; + DAT_CR_HANDOFF_FUNC cr_handoff_func; + + DAT_EVD_KCREATE_FUNC evd_kcreate_func; + DAT_EVD_QUERY_FUNC evd_query_func; + + DAT_EVD_MODIFY_UPCALL_FUNC evd_modify_upcall_func; /* kdat only */ + + DAT_EVD_RESIZE_FUNC evd_resize_func; + DAT_EVD_POST_SE_FUNC evd_post_se_func; + DAT_EVD_DEQUEUE_FUNC evd_dequeue_func; + DAT_EVD_FREE_FUNC evd_free_func; + + DAT_EP_CREATE_FUNC ep_create_func; + DAT_EP_QUERY_FUNC ep_query_func; + DAT_EP_MODIFY_FUNC ep_modify_func; + DAT_EP_CONNECT_FUNC ep_connect_func; + DAT_EP_DUP_CONNECT_FUNC ep_dup_connect_func; + DAT_EP_DISCONNECT_FUNC ep_disconnect_func; + DAT_EP_POST_SEND_FUNC ep_post_send_func; + DAT_EP_POST_RECV_FUNC ep_post_recv_func; + DAT_EP_POST_RDMA_READ_FUNC ep_post_rdma_read_func; + DAT_EP_POST_RDMA_WRITE_FUNC ep_post_rdma_write_func; + DAT_EP_GET_STATUS_FUNC ep_get_status_func; + DAT_EP_FREE_FUNC ep_free_func; + + DAT_LMR_KCREATE_FUNC lmr_kcreate_func; + DAT_LMR_QUERY_FUNC lmr_query_func; + DAT_LMR_FREE_FUNC lmr_free_func; + + DAT_RMR_CREATE_FUNC rmr_create_func; + DAT_RMR_QUERY_FUNC rmr_query_func; + DAT_RMR_BIND_FUNC rmr_bind_func; + DAT_RMR_FREE_FUNC rmr_free_func; + + DAT_PSP_CREATE_FUNC psp_create_func; + DAT_PSP_QUERY_FUNC psp_query_func; + DAT_PSP_FREE_FUNC psp_free_func; + + DAT_RSP_CREATE_FUNC rsp_create_func; + DAT_RSP_QUERY_FUNC rsp_query_func; + DAT_RSP_FREE_FUNC rsp_free_func; + + DAT_PZ_CREATE_FUNC pz_create_func; + DAT_PZ_QUERY_FUNC pz_query_func; + DAT_PZ_FREE_FUNC pz_free_func; + + /* dat-1.1 */ + DAT_PSP_CREATE_ANY_FUNC psp_create_any_func; /* dat-1.1 */ + DAT_EP_RESET_FUNC ep_reset_func; /* dat-1.1 */ + + /* dat-1.2 */ + DAT_LMR_SYNC_RDMA_READ_FUNC lmr_sync_rdma_read_func; + DAT_LMR_SYNC_RDMA_WRITE_FUNC lmr_sync_rdma_write_func; + + DAT_EP_CREATE_WITH_SRQ_FUNC ep_create_with_srq_func; + DAT_EP_RECV_QUERY_FUNC ep_recv_query_func; + DAT_EP_SET_WATERMARK_FUNC ep_set_watermark_func; + DAT_SRQ_CREATE_FUNC srq_create_func; + DAT_SRQ_FREE_FUNC srq_free_func; + DAT_SRQ_POST_RECV_FUNC srq_post_recv_func; + DAT_SRQ_QUERY_FUNC srq_query_func; + DAT_SRQ_RESIZE_FUNC srq_resize_func; + DAT_SRQ_SET_LW_FUNC srq_set_lw_func; + +/* DAT 2.0 functions */ + DAT_CSP_CREATE_FUNC csp_create_func; + DAT_CSP_QUERY_FUNC csp_query_func; + DAT_CSP_FREE_FUNC csp_free_func; + + DAT_EP_COMMON_CONNECT_FUNC ep_common_connect_func; + DAT_RMR_CREATE_FOR_EP_FUNC rmr_create_for_ep_func; + + DAT_EP_POST_SEND_WITH_INVALIDATE_FUNC ep_post_send_with_invalidate_func; + DAT_EP_POST_RDMA_READ_TO_RMR_FUNC ep_post_rdma_read_to_rmr_func; + + /* kDAT 2.0 functions */ + DAT_LMR_ALLOCATE_FUNC lmr_allocate_func; + DAT_LMR_FMR_FUNC lmr_fmr_func; + DAT_LMR_INVALIDATE_FUNC lmr_invalidate_func; + DAT_IA_RESERVED_LMR_FUNC ia_reserved_lmr_func; + +#ifdef DAT_EXTENSIONS + DAT_HANDLE_EXTENDEDOP_FUNC handle_extendedop_func; +#endif + + DAT_IA_HA_RELATED_FUNC ia_ha_related_func; +}; + +#endif /* _KDAT_REDIRECTION_H_ */ diff --git a/branches/WOF2-3/ulp/dapl2/dat/include/dat2/kdat_vendor_specific.h b/branches/WOF2-3/ulp/dapl2/dat/include/dat2/kdat_vendor_specific.h new file mode 100644 index 00000000..3a89d198 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dat/include/dat2/kdat_vendor_specific.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2002-2006, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under all of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * Redistributions of source code must retain both 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. + * + * Neither the name of Network Appliance, Inc. nor the names of other DAT + * Collaborative contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + */ + +/*************************************************************** + * + * HEADER: kdat_vendor_specific.h + * + * PURPOSE: Vendor defined macros & support. + * + * Description: Header file for "kDAPL: Kernel Direct Access Programming + * Library, Version: 2.0" + * + ***************************************************************/ +#ifndef _KDAT_VENDOR_SPECIFIC_H_ +#define _KDAT_VENDOR_SPECIFIC_H_ + +#include + +/* Vendor-specific extensions */ + +#if defined(_AMMASSO) + +#elif defined(_BROADCOM) + +#elif defined(_CISCO) + +#elif defined(_IBM) + +#elif defined(_INTEL) + +#elif defined(_JNI) + +#elif defined(_MELLANOX) + +#elif defined(_MYRINET) + +#elif defined(_NETEFFECT) + +#elif defined(_QLOGIC) + +#elif defined(_SILVERSTORM) + +#elif defined(_VOLTAIRE) + +#endif + +#endif /* _KDAT_VENDOR_SPECIFIC_H_ */ diff --git a/branches/WOF2-3/ulp/dapl2/dat/include/dat2/udat.h b/branches/WOF2-3/ulp/dapl2/dat/include/dat2/udat.h new file mode 100644 index 00000000..4ea491e5 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dat/include/dat2/udat.h @@ -0,0 +1,503 @@ +/* + * Copyright (c) 2002-2006, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under all of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * Redistributions of source code must retain both 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. + * + * Neither the name of Network Appliance, Inc. nor the names of other DAT + * Collaborative contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + */ + +/**************************************************************** + * + * HEADER: udat.h + * + * PURPOSE: defines the user DAT API + * + * Description: Header file for "uDAPL: User Direct Access Programming + * Library, Version: 2.0" + * + * Mapping rules: + * All global symbols are prepended with DAT_ or dat_ + * All DAT objects have an 'api' tag which, such as 'ep' or 'lmr' + * The method table is in the provider definition structure. + * + ***************************************************************/ + +#ifndef _UDAT_H_ +#define _UDAT_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +typedef enum dat_mem_type +{ + /* Shared between udat and kdat */ + DAT_MEM_TYPE_VIRTUAL = 0x00, + DAT_MEM_TYPE_LMR = 0x01, + /* udat specific */ + DAT_MEM_TYPE_SHARED_VIRTUAL = 0x02 +} DAT_MEM_TYPE; + +/* dat handle types */ +typedef enum dat_handle_type +{ + DAT_HANDLE_TYPE_CR, + DAT_HANDLE_TYPE_EP, + DAT_HANDLE_TYPE_EVD, + DAT_HANDLE_TYPE_IA, + DAT_HANDLE_TYPE_LMR, + DAT_HANDLE_TYPE_PSP, + DAT_HANDLE_TYPE_PZ, + DAT_HANDLE_TYPE_RMR, + DAT_HANDLE_TYPE_RSP, + DAT_HANDLE_TYPE_CNO, + DAT_HANDLE_TYPE_SRQ, + DAT_HANDLE_TYPE_CSP +#ifdef DAT_EXTENSIONS + ,DAT_HANDLE_TYPE_EXTENSION_BASE +#endif +} DAT_HANDLE_TYPE; + +/* EVD state consists of three orthogonal substates. One for + * enabled/disabled,one for waitable/unwaitable, and one for + * configuration. Within each substate the values are mutually + * exclusive. + */ +typedef enum dat_evd_state +{ + DAT_EVD_STATE_ENABLED = 0x01, + DAT_EVD_STATE_DISABLED = 0x02, + DAT_EVD_STATE_WAITABLE = 0x04, + DAT_EVD_STATE_UNWAITABLE = 0x08, + DAT_EVD_STATE_CONFIG_NOTIFY = 0x10, + DAT_EVD_STATE_CONFIG_SOLICITED = 0x20, + DAT_EVD_STATE_CONFIG_THRESHOLD = 0x30 +} DAT_EVD_STATE; + +typedef enum dat_evd_param_mask +{ + DAT_EVD_FIELD_IA_HANDLE = 0x01, + DAT_EVD_FIELD_EVD_QLEN = 0x02, + DAT_EVD_FIELD_EVD_STATE = 0x04, + DAT_EVD_FIELD_CNO = 0x08, + DAT_EVD_FIELD_EVD_FLAGS = 0x10, + DAT_EVD_FIELD_ALL = 0x1F +} DAT_EVD_PARAM_MASK; + +typedef DAT_UINT64 DAT_PROVIDER_ATTR_MASK; + +enum dat_lmr_param_mask +{ + DAT_LMR_FIELD_IA_HANDLE = 0x001, + DAT_LMR_FIELD_MEM_TYPE = 0x002, + DAT_LMR_FIELD_REGION_DESC = 0x004, + DAT_LMR_FIELD_LENGTH = 0x008, + DAT_LMR_FIELD_PZ_HANDLE = 0x010, + DAT_LMR_FIELD_MEM_PRIV = 0x020, + DAT_LMR_FIELD_VA_TYPE = 0x040, + DAT_LMR_FIELD_LMR_CONTEXT = 0x080, + DAT_LMR_FIELD_RMR_CONTEXT = 0x100, + DAT_LMR_FIELD_REGISTERED_SIZE = 0x200, + DAT_LMR_FIELD_REGISTERED_ADDRESS = 0x400, + + DAT_LMR_FIELD_ALL = 0x7FF +}; + +#include + +typedef DAT_HANDLE DAT_CNO_HANDLE; + +struct dat_evd_param +{ + DAT_IA_HANDLE ia_handle; + DAT_COUNT evd_qlen; + DAT_EVD_STATE evd_state; + DAT_CNO_HANDLE cno_handle; + DAT_EVD_FLAGS evd_flags; +}; + +#define DAT_LMR_COOKIE_SIZE 40 /* size of DAT_LMR_COOKIE in bytes */ +typedef char (* DAT_LMR_COOKIE)[DAT_LMR_COOKIE_SIZE]; + +/* Format for OS wait proxy agent function */ + +typedef void (DAT_API *DAT_AGENT_FUNC) +( + DAT_PVOID, /* instance data */ + DAT_EVD_HANDLE /* Event Dispatcher*/ +); + +/* Definition */ + +typedef struct dat_os_wait_proxy_agent +{ + DAT_PVOID instance_data; + DAT_AGENT_FUNC proxy_agent_func; +} DAT_OS_WAIT_PROXY_AGENT; + +/* Define NULL Proxy agent */ + +#define DAT_OS_WAIT_PROXY_AGENT_NULL \ + (DAT_OS_WAIT_PROXY_AGENT) { \ + (DAT_PVOID) NULL, \ + (DAT_AGENT_FUNC) NULL} + +/* Flags */ + +/* The value specified by the uDAPL Consumer for dat_ia_open to indicate + * that no async EVD should be created for the opening instance of an IA. + * The same IA has been open before that has the only async EVD to + * handle async errors for all open instances of the IA. + */ + +#define DAT_EVD_ASYNC_EXISTS (DAT_EVD_HANDLE) 0x1 + +/* + * The value returned by the dat_ia_query for the case when there is no + * async EVD for the IA instance. The Consumer specified the value of + * DAT_EVD_ASYNC_EXISTS for the async_evd_handle for dat_ia_open. + */ + +#define DAT_EVD_OUT_OF_SCOPE (DAT_EVD_HANDLE) 0x2 + +/* + * Memory types + * + * Specifying memory type for LMR create. A Consumer must use a single + * value when registering memory. The union of any of these + * flags is used in the Provider parameters to indicate what memory + * type Provider supports for LMR memory creation. + */ + +/* For udapl only */ + +typedef struct dat_shared_memory +{ + DAT_PVOID virtual_address; + DAT_LMR_COOKIE shared_memory_id; +} DAT_SHARED_MEMORY; + +typedef union dat_region_description +{ + DAT_PVOID for_va; + DAT_LMR_HANDLE for_lmr_handle; + DAT_SHARED_MEMORY for_shared_memory; /* For udapl only */ +} DAT_REGION_DESCRIPTION; + +/* LMR Arguments */ + +struct dat_lmr_param +{ + DAT_IA_HANDLE ia_handle; + DAT_MEM_TYPE mem_type; + DAT_REGION_DESCRIPTION region_desc; + DAT_VLEN length; + DAT_PZ_HANDLE pz_handle; + DAT_MEM_PRIV_FLAGS mem_priv; + DAT_VA_TYPE va_type; + DAT_LMR_CONTEXT lmr_context; + DAT_RMR_CONTEXT rmr_context; + DAT_VLEN registered_size; + DAT_VADDR registered_address; +}; + +typedef enum dat_proxy_type +{ + DAT_PROXY_TYPE_NONE = 0x0, + DAT_PROXY_TYPE_AGENT = 0x1, + DAT_PROXY_TYPE_FD = 0x2 +} DAT_PROXY_TYPE; + +typedef struct dat_cno_param +{ + DAT_IA_HANDLE ia_handle; + DAT_PROXY_TYPE proxy_type; + union { + DAT_OS_WAIT_PROXY_AGENT agent; + DAT_FD fd; + DAT_PVOID none; + } proxy; +} DAT_CNO_PARAM; + +typedef enum dat_cno_param_mask +{ + DAT_CNO_FIELD_IA_HANDLE = 0x1, + DAT_CNO_FIELD_PROXY_TYPE = 0x2, + DAT_CNO_FIELD_PROXY = 0x3, + DAT_CNO_FIELD_ALL = 0x4 +} DAT_CNO_PARAM_MASK; + +struct dat_ia_attr +{ + char adapter_name[DAT_NAME_MAX_LENGTH]; + char vendor_name[DAT_NAME_MAX_LENGTH]; + DAT_UINT32 hardware_version_major; + DAT_UINT32 hardware_version_minor; + DAT_UINT32 firmware_version_major; + DAT_UINT32 firmware_version_minor; + DAT_IA_ADDRESS_PTR ia_address_ptr; + DAT_COUNT max_eps; + DAT_COUNT max_dto_per_ep; + DAT_COUNT max_rdma_read_per_ep_in; + DAT_COUNT max_rdma_read_per_ep_out; + DAT_COUNT max_evds; + DAT_COUNT max_evd_qlen; + DAT_COUNT max_iov_segments_per_dto; + DAT_COUNT max_lmrs; + DAT_SEG_LENGTH max_lmr_block_size; + DAT_VADDR max_lmr_virtual_address; + DAT_COUNT max_pzs; + DAT_SEG_LENGTH max_message_size; + DAT_SEG_LENGTH max_rdma_size; + DAT_COUNT max_rmrs; + DAT_VADDR max_rmr_target_address; + DAT_COUNT max_srqs; + DAT_COUNT max_ep_per_srq; + DAT_COUNT max_recv_per_srq; + DAT_COUNT max_iov_segments_per_rdma_read; + DAT_COUNT max_iov_segments_per_rdma_write; + DAT_COUNT max_rdma_read_in; + DAT_COUNT max_rdma_read_out; + DAT_BOOLEAN max_rdma_read_per_ep_in_guaranteed; + DAT_BOOLEAN max_rdma_read_per_ep_out_guaranteed; + DAT_BOOLEAN zb_supported; + DAT_EXTENSION extension_supported; + DAT_COUNT extension_version; + DAT_COUNT num_transport_attr; + DAT_NAMED_ATTR *transport_attr; + DAT_COUNT num_vendor_attr; + DAT_NAMED_ATTR *vendor_attr; +}; + + +#define DAT_IA_FIELD_IA_EXTENSION UINT64_C(0x100000000) +#define DAT_IA_FIELD_IA_EXTENSION_VERSION UINT64_C(0x200000000) + +#define DAT_IA_FIELD_IA_NUM_TRANSPORT_ATTR UINT64_C(0x400000000) +#define DAT_IA_FIELD_IA_TRANSPORT_ATTR UINT64_C(0x800000000) +#define DAT_IA_FIELD_IA_NUM_VENDOR_ATTR UINT64_C(0x1000000000) +#define DAT_IA_FIELD_IA_VENDOR_ATTR UINT64_C(0x2000000000) +#define DAT_IA_FIELD_ALL UINT64_C(0x3FFFFFFFFF) + +/* General Provider attributes. udat specific. */ + +typedef enum dat_pz_support +{ + DAT_PZ_UNIQUE, + DAT_PZ_SHAREABLE +} DAT_PZ_SUPPORT; + +#include + +/* Provider should support merging of all event stream types. Provider + * attribute specify support for merging different event stream types. + * It is a 2D binary matrix where each row and column represents an event + * stream type. Each binary entry is 1 if the event streams of its raw + * and column can fed the same EVD, and 0 otherwise. The order of event + * streams in row and column is the same as in the definition of + * DAT_EVD_FLAGS: index 0 - Software Event, 1- Connection Request, + * 2 - DTO Completion, 3 - Connection event, 4 - RMR Bind Completion, + * 5 - Asynchronous event. By definition each diagonal entry is 1. + * Consumer allocates an array for it and passes it IN as a pointer + * for the array that Provider fills. Provider must fill the array + * that Consumer passes. + */ + +struct dat_provider_attr +{ + char provider_name[DAT_NAME_MAX_LENGTH]; + DAT_UINT32 provider_version_major; + DAT_UINT32 provider_version_minor; + DAT_UINT32 dapl_version_major; + DAT_UINT32 dapl_version_minor; + DAT_MEM_TYPE lmr_mem_types_supported; + DAT_IOV_OWNERSHIP iov_ownership_on_return; + DAT_QOS dat_qos_supported; + DAT_COMPLETION_FLAGS completion_flags_supported; + DAT_BOOLEAN is_thread_safe; + DAT_COUNT max_private_data_size; + DAT_BOOLEAN supports_multipath; + DAT_EP_CREATOR_FOR_PSP ep_creator; + DAT_PZ_SUPPORT pz_support; + DAT_UINT32 optimal_buffer_alignment; + const DAT_BOOLEAN evd_stream_merging_supported[6][6]; + DAT_BOOLEAN srq_supported; + DAT_COUNT srq_watermarks_supported; + DAT_BOOLEAN srq_ep_pz_difference_supported; + DAT_COUNT srq_info_supported; + DAT_COUNT ep_recv_info_supported; + DAT_BOOLEAN lmr_sync_req; + DAT_BOOLEAN dto_async_return_guaranteed; + DAT_BOOLEAN rdma_write_for_rdma_read_req; + DAT_BOOLEAN rdma_read_lmr_rmr_context_exposure; + DAT_RMR_SCOPE rmr_scope_supported; + DAT_BOOLEAN is_signal_safe; + DAT_BOOLEAN ha_supported; + DAT_HA_LB ha_loadbalancing; + DAT_COUNT num_provider_specific_attr; + DAT_NAMED_ATTR * provider_specific_attr; +}; + +#define DAT_PROVIDER_FIELD_PROVIDER_NAME UINT64_C(0x00000001) +#define DAT_PROVIDER_FIELD_PROVIDER_VERSION_MAJOR UINT64_C(0x00000002) +#define DAT_PROVIDER_FIELD_PROVIDER_VERSION_MINOR UINT64_C(0x00000004) +#define DAT_PROVIDER_FIELD_DAPL_VERSION_MAJOR UINT64_C(0x00000008) +#define DAT_PROVIDER_FIELD_DAPL_VERSION_MINOR UINT64_C(0x00000010) +#define DAT_PROVIDER_FIELD_LMR_MEM_TYPE_SUPPORTED UINT64_C(0x00000020) +#define DAT_PROVIDER_FIELD_IOV_OWNERSHIP UINT64_C(0x00000040) +#define DAT_PROVIDER_FIELD_DAT_QOS_SUPPORTED UINT64_C(0x00000080) +#define DAT_PROVIDER_FIELD_COMPLETION_FLAGS_SUPPORTED UINT64_C(0x00000100) +#define DAT_PROVIDER_FIELD_IS_THREAD_SAFE UINT64_C(0x00000200) +#define DAT_PROVIDER_FIELD_MAX_PRIVATE_DATA_SIZE UINT64_C(0x00000400) +#define DAT_PROVIDER_FIELD_SUPPORTS_MULTIPATH UINT64_C(0x00000800) +#define DAT_PROVIDER_FIELD_EP_CREATOR UINT64_C(0x00001000) +#define DAT_PROVIDER_FIELD_PZ_SUPPORT UINT64_C(0x00002000) +#define DAT_PROVIDER_FIELD_OPTIMAL_BUFFER_ALIGNMENT UINT64_C(0x00004000) +#define DAT_PROVIDER_FIELD_EVD_STREAM_MERGING_SUPPORTED UINT64_C(0x00008000) +#define DAT_PROVIDER_FIELD_SRQ_SUPPORTED UINT64_C(0x00010000) +#define DAT_PROVIDER_FIELD_SRQ_WATERMARKS_SUPPORTED UINT64_C(0x00020000) +#define DAT_PROVIDER_FIELD_SRQ_EP_PZ_DIFFERENCE_SUPPORTED UINT64_C(0x00040000) +#define DAT_PROVIDER_FIELD_SRQ_INFO_SUPPORTED UINT64_C(0x00080000) +#define DAT_PROVIDER_FIELD_EP_RECV_INFO_SUPPORTED UINT64_C(0x00100000) +#define DAT_PROVIDER_FIELD_LMR_SYNC_REQ UINT64_C(0x00200000) +#define DAT_PROVIDER_FIELD_DTO_ASYNC_RETURN_GUARANTEED UINT64_C(0x00400000) +#define DAT_PROVIDER_FIELD_RDMA_WRITE_FOR_RDMA_READ_REQ UINT64_C(0x00800000) +#define DAT_PROVIDER_FIELD_RDMA_READ_LMR_RMR_CONTEXT_EXPOSURE UINT64_C(0x01000000) +#define DAT_PROVIDER_FIELD_RMR_SCOPE_SUPPORTED UINT64_C(0x02000000) +#define DAT_PROVIDER_FIELD_IS_SIGNAL_SAFE UINT64_C(0x04000000) +#define DAT_PROVIDER_FIELD_HA_SUPPORTED UINT64_C(0x08000000) +#define DAT_PROVIDER_FIELD_HA_LB UINT64_C(0x10000000) +#define DAT_PROVIDER_FIELD_NUM_PROVIDER_SPECIFIC_ATTR UINT64_C(0x20000000) +#define DAT_PROVIDER_FIELD_PROVIDER_SPECIFIC_ATTR UINT64_C(0x40000000) + +#define DAT_PROVIDER_FIELD_ALL UINT64_C(0x7FFFFFFF) +#define DAT_PROVIDER_FIELD_NONE UINT64_C(0x0) + +/**************************************************************/ + +/* + * User DAT function call definitions, + */ + +extern DAT_RETURN DAT_API dat_lmr_create ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_MEM_TYPE, /* mem_type */ + IN DAT_REGION_DESCRIPTION, /* region_description */ + IN DAT_VLEN, /* length */ + IN DAT_PZ_HANDLE, /* pz_handle */ + IN DAT_MEM_PRIV_FLAGS, /* privileges */ + IN DAT_VA_TYPE, /* va_type */ + OUT DAT_LMR_HANDLE *, /* lmr_handle */ + OUT DAT_LMR_CONTEXT *, /* lmr_context */ + OUT DAT_RMR_CONTEXT *, /* rmr_context */ + OUT DAT_VLEN *, /* registered_length */ + OUT DAT_VADDR * ); /* registered_address */ + +extern DAT_RETURN DAT_API dat_lmr_query ( + IN DAT_LMR_HANDLE, /* lmr_handle */ + IN DAT_LMR_PARAM_MASK, /* lmr_param_mask */ + OUT DAT_LMR_PARAM * ); /* lmr_param */ + +/* Event Functions */ + +extern DAT_RETURN DAT_API dat_evd_create ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_COUNT, /* evd_min_qlen */ + IN DAT_CNO_HANDLE, /* cno_handle */ + IN DAT_EVD_FLAGS, /* evd_flags */ + OUT DAT_EVD_HANDLE * ); /* evd_handle */ + +extern DAT_RETURN DAT_API dat_evd_modify_cno ( + IN DAT_EVD_HANDLE, /* evd_handle */ + IN DAT_CNO_HANDLE); /* cno_handle */ + +extern DAT_RETURN DAT_API dat_cno_create ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_OS_WAIT_PROXY_AGENT,/* agent */ + OUT DAT_CNO_HANDLE *); /* cno_handle */ + +extern DAT_RETURN DAT_API dat_cno_modify_agent ( + IN DAT_CNO_HANDLE, /* cno_handle */ + IN DAT_OS_WAIT_PROXY_AGENT);/* agent */ + +extern DAT_RETURN DAT_API dat_cno_query ( + IN DAT_CNO_HANDLE, /* cno_handle */ + IN DAT_CNO_PARAM_MASK, /* cno_param_mask */ + OUT DAT_CNO_PARAM * ); /* cno_param */ + +extern DAT_RETURN DAT_API dat_cno_free ( + IN DAT_CNO_HANDLE); /* cno_handle */ + +extern DAT_RETURN DAT_API dat_cno_wait ( + IN DAT_CNO_HANDLE, /* cno_handle */ + IN DAT_TIMEOUT, /* timeout */ + OUT DAT_EVD_HANDLE *); /* evd_handle */ + +extern DAT_RETURN DAT_API dat_evd_enable ( + IN DAT_EVD_HANDLE); /* evd_handle */ + +extern DAT_RETURN DAT_API dat_evd_wait ( + IN DAT_EVD_HANDLE, /* evd_handle */ + IN DAT_TIMEOUT, /* timeout */ + IN DAT_COUNT, /* threshold */ + OUT DAT_EVENT *, /* event */ + OUT DAT_COUNT * ); /* n_more_events */ + +extern DAT_RETURN DAT_API dat_evd_disable ( + IN DAT_EVD_HANDLE); /* evd_handle */ + +extern DAT_RETURN DAT_API dat_evd_set_unwaitable ( + IN DAT_EVD_HANDLE); /* evd_handle */ + +extern DAT_RETURN DAT_API dat_evd_clear_unwaitable ( + IN DAT_EVD_HANDLE); /* evd_handle */ + +extern DAT_RETURN DAT_API dat_cno_fd_create ( + IN DAT_IA_HANDLE, /* ia_handle */ + OUT DAT_FD *, /* file descriptor */ + OUT DAT_CNO_HANDLE * ); /* cno_handle */ + +extern DAT_RETURN DAT_API dat_cno_trigger ( + IN DAT_CNO_HANDLE, /* cno_handle */ + OUT DAT_EVD_HANDLE * ); /* evd_handle */ + +#ifdef __cplusplus +} +#endif + +#endif /* _UDAT_H_ */ diff --git a/branches/WOF2-3/ulp/dapl2/dat/include/dat2/udat_config.h b/branches/WOF2-3/ulp/dapl2/dat/include/dat2/udat_config.h new file mode 100644 index 00000000..eb92f140 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dat/include/dat2/udat_config.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2002-2006, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under all of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * Redistributions of source code must retain both 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. + * + * Neither the name of Network Appliance, Inc. nor the names of other DAT + * Collaborative contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + */ + +/*************************************************************** + * + * HEADER: udat_config.h + * + * PURPOSE: provides uDAPL configuration information. + * + * Description: Header file for "uDAPL: User Direct Access Programming + * Library, Version: 2.0" + * + ***************************************************************/ +#ifndef _UDAT_CONFIG_H_ +#define _UDAT_CONFIG_H_ + +#define DAT_VERSION_MAJOR 2 +#define DAT_VERSION_MINOR 0 + +/* + * The official header files will default DAT_THREADSAFE to DAT_TRUE. If + * your project does not wish to use this default, you must ensure that + * DAT_THREADSAFE will be set to DAT_FALSE. This may be done by an + * explicit #define in a common project header file that is included + * before any DAT header files, or through command line directives to the + * compiler (presumably controlled by the make environment). + */ + +/* + * A site, project or platform may consider setting an alternate default + * via their make rules, but are discouraged from doing so by editing + * the official header files. + */ + +/* + * The Reference Implementation is not Thread Safe. The Reference + * Implementation has chosen to go with the first method and define it + * explicitly in the header file. + */ +#define DAT_THREADSAFE DAT_FALSE + +#ifndef DAT_THREADSAFE +#define DAT_THREADSAFE DAT_TRUE +#endif /* DAT_THREADSAFE */ + +/* + * Enable DAT Extensions + */ +#ifndef DAT_EXTENSIONS +#define DAT_EXTENSIONS 1 +#endif + +#endif /* _UDAT_CONFIG_H_ */ diff --git a/branches/WOF2-3/ulp/dapl2/dat/include/dat2/udat_redirection.h b/branches/WOF2-3/ulp/dapl2/dat/include/dat2/udat_redirection.h new file mode 100644 index 00000000..f1804170 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dat/include/dat2/udat_redirection.h @@ -0,0 +1,356 @@ +/* + * Copyright (c) 2002-2006, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under all of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * Redistributions of source code must retain both 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. + * + * Neither the name of Network Appliance, Inc. nor the names of other DAT + * Collaborative contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + */ + +/**************************************************************** + * + * HEADER: udat_redirection.h + * + * PURPOSE: User DAT macro definitions + * + * Description: Macros to invoke DAPL functions from the dat_registry + * + * Mapping rules: + * All global symbols are prepended with DAT_ or dat_ + * All DAT objects have an 'api' tag which, such as 'ep' or 'lmr' + * The method table is in the provider definition structure. + * + **********************************************************/ +#ifndef _UDAT_REDIRECTION_H_ +#define _UDAT_REDIRECTION_H_ + + +#define DAT_LMR_CREATE(ia, mem_type, reg_desc, len, pz, priv, va_type, \ + lmr, lmr_context, rmr_context, reg_len, reg_addr) \ + (*DAT_HANDLE_TO_PROVIDER(ia)->lmr_create_func)(\ + (ia), \ + (mem_type), \ + (reg_desc), \ + (len), \ + (pz), \ + (priv), \ + (va_type), \ + (lmr), \ + (lmr_context), \ + (rmr_context), \ + (reg_len), \ + (reg_addr)) + +#define DAT_EVD_CREATE(ia, qlen, cno, flags, handle) \ + (*DAT_HANDLE_TO_PROVIDER(ia)->evd_create_func)(\ + (ia), \ + (qlen), \ + (cno), \ + (flags), \ + (handle)) + +#define DAT_EVD_ENABLE(evd) \ + (*DAT_HANDLE_TO_PROVIDER(evd)->evd_enable_func)(\ + (evd)) + +#define DAT_EVD_WAIT(evd, timeout, threshold, event, nmore) \ + (*DAT_HANDLE_TO_PROVIDER(evd)->evd_wait_func)(\ + (evd), \ + (timeout), \ + (threshold), \ + (event), \ + (nmore)) + +#define DAT_EVD_DISABLE(evd) \ + (*DAT_HANDLE_TO_PROVIDER(evd)->evd_disable_func)(\ + (evd)) + +#define DAT_EVD_SET_UNWAITABLE(evd) \ + (*DAT_HANDLE_TO_PROVIDER(evd)->evd_set_unwaitable_func)(\ + (evd)) + +#define DAT_EVD_CLEAR_UNWAITABLE(evd) \ + (*DAT_HANDLE_TO_PROVIDER(evd)->evd_clear_unwaitable_func)(\ + (evd)) + +#define DAT_EVD_MODIFY_CNO(evd, cno) \ + (*DAT_HANDLE_TO_PROVIDER(evd)->evd_modify_cno_func)(\ + (evd), \ + (cno)) + +#define DAT_CNO_CREATE(ia, proxy, cno) \ + (*DAT_HANDLE_TO_PROVIDER(ia)->cno_create_func)(\ + (ia), \ + (proxy), \ + (cno)) + +#define DAT_CNO_FD_CREATE(ia, fd, cno) \ + (*DAT_HANDLE_TO_PROVIDER(ia)->cno_fd_create_func)(\ + (ia), \ + (fd), \ + (cno)) + +#define DAT_CNO_TRIGGER(cno, evd) \ + (*DAT_HANDLE_TO_PROVIDER(cno)->cno_trigger_func)(\ + (cno), \ + (evd)) + + +#define DAT_CNO_MODIFY_AGENT(cno, proxy) \ + (*DAT_HANDLE_TO_PROVIDER(cno)->cno_modify_agent_func)(\ + (cno), \ + (proxy)) + +#define DAT_CNO_QUERY(cno, mask, param) \ + (*DAT_HANDLE_TO_PROVIDER(cno)->cno_query_func)(\ + (cno), \ + (mask), \ + (param)) + +#define DAT_CNO_FREE(cno) \ + (*DAT_HANDLE_TO_PROVIDER(cno)->cno_free_func)(\ + (cno)) + +#define DAT_CNO_WAIT(cno,timeout,evd) \ + (*DAT_HANDLE_TO_PROVIDER(cno)->cno_wait_func)(\ + (cno), \ + (timeout), \ + (evd)) + +/*************************************************************** + * FUNCTION PROTOTYPES + * + * User DAT function call definitions, + * + ****************************************************************/ + +typedef DAT_RETURN (DAT_API *DAT_LMR_CREATE_FUNC) ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_MEM_TYPE, /* mem_type */ + IN DAT_REGION_DESCRIPTION, /* region_description */ + IN DAT_VLEN, /* length */ + IN DAT_PZ_HANDLE, /* pz_handle */ + IN DAT_MEM_PRIV_FLAGS, /* privileges */ + IN DAT_VA_TYPE, /* va_type */ + OUT DAT_LMR_HANDLE *, /* lmr_handle */ + OUT DAT_LMR_CONTEXT *, /* lmr_context */ + OUT DAT_RMR_CONTEXT *, /* rmr_context */ + OUT DAT_VLEN *, /* registered_length */ + OUT DAT_VADDR * ); /* registered_address */ + +typedef DAT_RETURN (DAT_API *DAT_LMR_QUERY_FUNC) ( + IN DAT_LMR_HANDLE, /* lmr_handle */ + IN DAT_LMR_PARAM_MASK, /* lmr_param_mask */ + OUT DAT_LMR_PARAM *); /* lmr_param */ + +/* Event functions */ + +typedef DAT_RETURN (DAT_API *DAT_EVD_CREATE_FUNC) ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_COUNT, /* evd_min_qlen */ + IN DAT_CNO_HANDLE, /* cno_handle */ + IN DAT_EVD_FLAGS, /* evd_flags */ + OUT DAT_EVD_HANDLE * ); /* evd_handle */ + +typedef DAT_RETURN (DAT_API *DAT_EVD_MODIFY_CNO_FUNC) ( + IN DAT_EVD_HANDLE, /* evd_handle */ + IN DAT_CNO_HANDLE); /* cno_handle */ + +typedef DAT_RETURN (DAT_API *DAT_CNO_CREATE_FUNC) ( + IN DAT_IA_HANDLE, /* ia_handle */ + IN DAT_OS_WAIT_PROXY_AGENT,/* agent */ + OUT DAT_CNO_HANDLE *); /* cno_handle */ + +typedef DAT_RETURN (DAT_API *DAT_CNO_FD_CREATE_FUNC) ( + IN DAT_IA_HANDLE, /* ia_handle */ + OUT DAT_FD *, /* file_descriptor */ + OUT DAT_CNO_HANDLE *); /* cno_handle */ + +typedef DAT_RETURN (DAT_API *DAT_CNO_TRIGGER_FUNC) ( + IN DAT_CNO_HANDLE, /* cno_handle */ + OUT DAT_EVD_HANDLE *); /* trigger */ + +typedef DAT_RETURN (DAT_API *DAT_CNO_MODIFY_AGENT_FUNC) ( + IN DAT_CNO_HANDLE, /* cno_handle */ + IN DAT_OS_WAIT_PROXY_AGENT);/* agent */ + +typedef DAT_RETURN (DAT_API *DAT_CNO_QUERY_FUNC) ( + IN DAT_CNO_HANDLE, /* cno_handle */ + IN DAT_CNO_PARAM_MASK, /* cno_param_mask */ + OUT DAT_CNO_PARAM * ); /* cno_param */ + +typedef DAT_RETURN (DAT_API *DAT_CNO_FREE_FUNC) ( + IN DAT_CNO_HANDLE); /* cno_handle */ + +typedef DAT_RETURN (DAT_API *DAT_CNO_WAIT_FUNC) ( + IN DAT_CNO_HANDLE, /* cno_handle */ + IN DAT_TIMEOUT, /* timeout */ + OUT DAT_EVD_HANDLE *); /* evd_handle */ + +typedef DAT_RETURN (DAT_API *DAT_EVD_ENABLE_FUNC) ( + IN DAT_EVD_HANDLE); /* evd_handle */ + +typedef DAT_RETURN (DAT_API *DAT_EVD_WAIT_FUNC) ( + IN DAT_EVD_HANDLE, /* evd_handle */ + IN DAT_TIMEOUT, /* Timeout */ + IN DAT_COUNT, /* Threshold */ + OUT DAT_EVENT *, /* event */ + OUT DAT_COUNT * ); /* N more events */ + +typedef DAT_RETURN (DAT_API *DAT_EVD_DISABLE_FUNC) ( + IN DAT_EVD_HANDLE); /* evd_handle */ + +typedef DAT_RETURN (DAT_API *DAT_EVD_SET_UNWAITABLE_FUNC) ( + IN DAT_EVD_HANDLE); /* evd_handle */ + +typedef DAT_RETURN (DAT_API *DAT_EVD_CLEAR_UNWAITABLE_FUNC) ( + IN DAT_EVD_HANDLE); /* evd_handle */ + + +#include + +struct dat_provider +{ + const char * device_name; + DAT_PVOID extension; + + DAT_IA_OPEN_FUNC ia_open_func; + DAT_IA_QUERY_FUNC ia_query_func; + DAT_IA_CLOSE_FUNC ia_close_func; + + DAT_SET_CONSUMER_CONTEXT_FUNC set_consumer_context_func; + DAT_GET_CONSUMER_CONTEXT_FUNC get_consumer_context_func; + DAT_GET_HANDLE_TYPE_FUNC get_handle_type_func; + + DAT_CNO_CREATE_FUNC cno_create_func; /* udat only */ + DAT_CNO_MODIFY_AGENT_FUNC cno_modify_agent_func; /* udat only */ + DAT_CNO_QUERY_FUNC cno_query_func; /* udat only */ + DAT_CNO_FREE_FUNC cno_free_func; /* udat only */ + DAT_CNO_WAIT_FUNC cno_wait_func; /* udat only */ + + DAT_CR_QUERY_FUNC cr_query_func; + DAT_CR_ACCEPT_FUNC cr_accept_func; + DAT_CR_REJECT_FUNC cr_reject_func; + DAT_CR_HANDOFF_FUNC cr_handoff_func; + + DAT_EVD_CREATE_FUNC evd_create_func; + DAT_EVD_QUERY_FUNC evd_query_func; + + DAT_EVD_MODIFY_CNO_FUNC evd_modify_cno_func; /* udat only */ + DAT_EVD_ENABLE_FUNC evd_enable_func; /* udat only */ + DAT_EVD_DISABLE_FUNC evd_disable_func; /* udat only */ + DAT_EVD_WAIT_FUNC evd_wait_func; /* udat only */ + + DAT_EVD_RESIZE_FUNC evd_resize_func; + DAT_EVD_POST_SE_FUNC evd_post_se_func; + DAT_EVD_DEQUEUE_FUNC evd_dequeue_func; + DAT_EVD_FREE_FUNC evd_free_func; + + DAT_EP_CREATE_FUNC ep_create_func; + DAT_EP_QUERY_FUNC ep_query_func; + DAT_EP_MODIFY_FUNC ep_modify_func; + DAT_EP_CONNECT_FUNC ep_connect_func; + DAT_EP_DUP_CONNECT_FUNC ep_dup_connect_func; + DAT_EP_DISCONNECT_FUNC ep_disconnect_func; + DAT_EP_POST_SEND_FUNC ep_post_send_func; + DAT_EP_POST_RECV_FUNC ep_post_recv_func; + DAT_EP_POST_RDMA_READ_FUNC ep_post_rdma_read_func; + DAT_EP_POST_RDMA_WRITE_FUNC ep_post_rdma_write_func; + DAT_EP_GET_STATUS_FUNC ep_get_status_func; + DAT_EP_FREE_FUNC ep_free_func; + + DAT_LMR_CREATE_FUNC lmr_create_func; + DAT_LMR_QUERY_FUNC lmr_query_func; + + DAT_LMR_FREE_FUNC lmr_free_func; + + DAT_RMR_CREATE_FUNC rmr_create_func; + DAT_RMR_QUERY_FUNC rmr_query_func; + DAT_RMR_BIND_FUNC rmr_bind_func; + DAT_RMR_FREE_FUNC rmr_free_func; + + DAT_PSP_CREATE_FUNC psp_create_func; + DAT_PSP_QUERY_FUNC psp_query_func; + DAT_PSP_FREE_FUNC psp_free_func; + + DAT_RSP_CREATE_FUNC rsp_create_func; + DAT_RSP_QUERY_FUNC rsp_query_func; + DAT_RSP_FREE_FUNC rsp_free_func; + + DAT_PZ_CREATE_FUNC pz_create_func; + DAT_PZ_QUERY_FUNC pz_query_func; + DAT_PZ_FREE_FUNC pz_free_func; + + /* dat-1.1 */ + DAT_PSP_CREATE_ANY_FUNC psp_create_any_func; /* dat-1.1 */ + DAT_EP_RESET_FUNC ep_reset_func; /* dat-1.1 */ + + /* udat-1.1 */ + DAT_EVD_SET_UNWAITABLE_FUNC evd_set_unwaitable_func; /* udat-1.1 */ + DAT_EVD_CLEAR_UNWAITABLE_FUNC evd_clear_unwaitable_func; /* udat-1.1 */ + /* dat-1.2 */ + DAT_LMR_SYNC_RDMA_READ_FUNC lmr_sync_rdma_read_func; + DAT_LMR_SYNC_RDMA_WRITE_FUNC lmr_sync_rdma_write_func; + + DAT_EP_CREATE_WITH_SRQ_FUNC ep_create_with_srq_func; + DAT_EP_RECV_QUERY_FUNC ep_recv_query_func; + DAT_EP_SET_WATERMARK_FUNC ep_set_watermark_func; + DAT_SRQ_CREATE_FUNC srq_create_func; + DAT_SRQ_FREE_FUNC srq_free_func; + DAT_SRQ_POST_RECV_FUNC srq_post_recv_func; + DAT_SRQ_QUERY_FUNC srq_query_func; + DAT_SRQ_RESIZE_FUNC srq_resize_func; + DAT_SRQ_SET_LW_FUNC srq_set_lw_func; + + /* DAT 2.0 functions */ + DAT_CSP_CREATE_FUNC csp_create_func; + DAT_CSP_QUERY_FUNC csp_query_func; + DAT_CSP_FREE_FUNC csp_free_func; + + DAT_EP_COMMON_CONNECT_FUNC ep_common_connect_func; + + DAT_RMR_CREATE_FOR_EP_FUNC rmr_create_for_ep_func; + DAT_EP_POST_SEND_WITH_INVALIDATE_FUNC ep_post_send_with_invalidate_func; + DAT_EP_POST_RDMA_READ_TO_RMR_FUNC ep_post_rdma_read_to_rmr_func; + + DAT_CNO_FD_CREATE_FUNC cno_fd_create_func; + DAT_CNO_TRIGGER_FUNC cno_trigger_func; + + DAT_IA_HA_RELATED_FUNC ia_ha_related_func; + +#ifdef DAT_EXTENSIONS + DAT_HANDLE_EXTENDEDOP_FUNC handle_extendedop_func; +#endif /* DAT_EXTENSIONS */ +}; + +#endif /* _UDAT_REDIRECTION_H_ */ diff --git a/branches/WOF2-3/ulp/dapl2/dat/include/dat2/udat_vendor_specific.h b/branches/WOF2-3/ulp/dapl2/dat/include/dat2/udat_vendor_specific.h new file mode 100644 index 00000000..dd955f8b --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dat/include/dat2/udat_vendor_specific.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2002-2006, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under all of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * Redistributions of source code must retain both 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. + * + * Neither the name of Network Appliance, Inc. nor the names of other DAT + * Collaborative contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + */ + +/*************************************************************** + * + * HEADER: udat_vendor_specific.h + * + * PURPOSE: Vendor defined macros & support. + * + * Description: Header file for "uDAPL: User Direct Access Programming + * Library, Version: 2.0" + * + ***************************************************************/ +#ifndef _UDAT_VENDOR_SPECIFIC_H_ +#define _UDAT_VENDOR_SPECIFIC_H_ + +#include + +/* Vendor-specific extensions */ + +#if defined(_AMMASSO) + +#elif defined(_BROADCOM) + +#elif defined(_CISCO) + +#elif defined(_IBM) + +#elif defined(_INTEL) + +#elif defined(_JNI) + +#elif defined(_MELLANOX) + +#elif defined(_MYRINET) + +#elif defined(_NETEFFECT) + +#elif defined(_QLOGIC) + +#elif defined(_SILVERSTORM) + +#elif defined(_VOLTAIRE) + +#endif + +#endif /* _UDAT_VENDOR_SPECIFIC_H_ */ diff --git a/branches/WOF2-3/ulp/dapl2/dat/udat/SOURCES b/branches/WOF2-3/ulp/dapl2/dat/udat/SOURCES new file mode 100644 index 00000000..4cddf721 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dat/udat/SOURCES @@ -0,0 +1,36 @@ +!if $(FREEBUILD) +TARGETNAME=dat2 +!else +TARGETNAME=dat2d +!endif +TARGETPATH=..\..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE=DYNLINK +DLLENTRY=_DllMainCRTStartup +!if $(_NT_TOOLS_VERSION) == 0x700 +DLLDEF=$O\udat_exports.def +!else +DLLDEF=$(OBJ_PATH)\$O\udat_exports.def +!endif +USE_MSVCRT=1 + +SOURCES=udat.rc \ + udat.c \ + udat_api.c \ + udat_sr_parser.c \ + udat_sources.c + +INCLUDES=windows;..\common;..\include;..\..\..\..\inc\user\linux; +RCOPTIONS=/I..\..\..\..\inc; + +# FIX ME!!! XXX specifically the 4113 warning prior to testing. +#MSC_WARNING_LEVEL= /W3 + +MSC_WARNING_LEVEL= /W1 /wd4113 + +DAT_OPTS= $(DAT_OPTS) -DEXPORT_DAT_SYMBOLS -DDAT_EXTENSIONS=1 + +USER_C_FLAGS=$(USER_C_FLAGS) $(DAT_OPTS) $(MSC_WARNING_LEVEL) + +TARGETLIBS= \ + $(SDK_LIB_PATH)\kernel32.lib + diff --git a/branches/WOF2-3/ulp/dapl2/dat/udat/linux/dat-registry-1.1.spec b/branches/WOF2-3/ulp/dapl2/dat/udat/linux/dat-registry-1.1.spec new file mode 100644 index 00000000..690726f4 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dat/udat/linux/dat-registry-1.1.spec @@ -0,0 +1,106 @@ +# Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. +# +# This Software is licensed under one of the following licenses: +# +# 1) under the terms of the "Common Public License 1.0" a copy of which is +# in the file LICENSE.txt in the root directory. The license is also +# available from the Open Source Initiative, see +# http://www.opensource.org/licenses/cpl.php. +# +# 2) under the terms of the "The BSD License" a copy of which is in the file +# LICENSE2.txt in the root directory. The license is also available from +# the Open Source Initiative, see +# http://www.opensource.org/licenses/bsd-license.php. +# +# 3) under the terms of the "GNU General Public License (GPL) Version 2" a +# copy of which is in the file LICENSE3.txt in the root directory. The +# license is also available from the Open Source Initiative, see +# http://www.opensource.org/licenses/gpl-license.php. +# +# Licensee has the right to choose one of the above licenses. +# +# Redistributions of source code must retain the above copyright +# notice and one of the license notices. +# +# Redistributions in binary form must reproduce both the above copyright +# notice, one of the license notices in the documentation +# and/or other materials provided with the distribution. +# +# +# DAT Registry RPM SPEC file +# + +%define make_dir udat + +# Defining these to nothing overrides the stupid automatic RH9 +# functionality of making "debuginfo" RPMs. + +%define debug_package %{nil} +%define __check_files %{nil} +%define dual_arch 0 + +%ifarch x86_64 +%define dual_arch 1 +%endif + +# +# Preamble +# + +Summary: DAT Registry +Name: dat-registry +Version: 1.1 +Release: 0 +Vendor: Dat Collaborative +Exclusiveos: Linux +License: BSD and CPL +Group: System/Libraries +Source: %{name}-%{version}.tgz +URL: http://www.datcollaborative.org +BuildRoot: /var/tmp/%{name}-%{version} + +%description +This package contains the DAT Registry. + +# +# Preparation +# + +%prep +%setup -n dat + +# +# Build +# + +%build +cd %{make_dir} +make + +# +# Install +# + +%install +if [ -d %{buildroot} ]; then rm -rf %{buildroot}; fi +mkdir -p %{buildroot}/usr/include/dat +mkdir -p %{buildroot}/usr/lib +%if %{dual_arch} +mkdir -p %{buildroot}/usr/lib64 +%endif +cd %{make_dir} +make install PREFIX=%{buildroot} + +# +# Files +# + +%files +%defattr(-,root,root) +/usr/include/dat +/usr/lib/libdat.so +/usr/lib/libdat.a +%if %{dual_arch} +/usr/lib64/libdat.so +/usr/lib64/libdat.a +%endif diff --git a/branches/WOF2-3/ulp/dapl2/dat/udat/linux/dat_osd.c b/branches/WOF2-3/ulp/dapl2/dat/udat/linux/dat_osd.c new file mode 100644 index 00000000..28ac9fa8 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dat/udat/linux/dat_osd.c @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dat_osd.c + * + * PURPOSE: Operating System Dependent layer + * Description: + * Provide OS dependent functions with a canonical DAPL + * interface. Designed to be portable and hide OS specific quirks + * of common functions. + * + * $Id: dat_osd.c,v 1.14 2005/04/25 17:29:41 jlentini Exp $ + **********************************************************************/ + +#include "dat_osd.h" + + +/********************************************************************* + * * + * Constants * + * * + *********************************************************************/ + +#define DAT_DBG_TYPE_ENV "DAT_DBG_TYPE" +#define DAT_DBG_DEST_ENV "DAT_DBG_DEST" + + +/********************************************************************* + * * + * Enumerations * + * * + *********************************************************************/ + +typedef int DAT_OS_DBG_DEST; + +typedef enum +{ + DAT_OS_DBG_DEST_STDOUT = 0x1, + DAT_OS_DBG_DEST_SYSLOG = 0x2, + DAT_OS_DBG_DEST_ALL = 0x3 +} DAT_OS_DBG_DEST_TYPE; + + +/********************************************************************* + * * + * Global Variables * + * * + *********************************************************************/ + +static DAT_OS_DBG_TYPE_VAL g_dbg_type = DAT_OS_DBG_TYPE_ERROR; +static DAT_OS_DBG_DEST g_dbg_dest = DAT_OS_DBG_DEST_STDOUT; + + +/*********************************************************************** + * Function: dat_os_dbg_init + ***********************************************************************/ + +void +dat_os_dbg_init ( void ) +{ + char *dbg_type; + char *dbg_dest; + + if ( NULL != (dbg_type = dat_os_getenv (DAT_DBG_TYPE_ENV)) ) + { + g_dbg_type = dat_os_strtol (dbg_type, NULL, 0); + } + + if ( NULL != (dbg_dest = dat_os_getenv (DAT_DBG_DEST_ENV)) ) + { + g_dbg_dest = dat_os_strtol (dbg_dest, NULL, 0); + } +} + + +/*********************************************************************** + * Function: dat_os_dbg_print + ***********************************************************************/ + +void +dat_os_dbg_print ( + DAT_OS_DBG_TYPE_VAL type, + const char * fmt, + ...) +{ + if (type & g_dbg_type) + { + va_list args; + + if ( DAT_OS_DBG_DEST_STDOUT & g_dbg_dest ) + { + va_start (args, fmt); + vfprintf (stdout, fmt, args); + fflush (stdout); + va_end (args); + } + + if ( DAT_OS_DBG_DEST_SYSLOG & g_dbg_dest ) + { + va_start (args, fmt); + vsyslog (LOG_USER | LOG_DEBUG, fmt, args); + va_end (args); + } + } +} + + +/*********************************************************************** + * Function: dat_os_library_load + ***********************************************************************/ + +DAT_RETURN +dat_os_library_load ( + const char *library_path, + DAT_OS_LIBRARY_HANDLE *library_handle_ptr) +{ + DAT_OS_LIBRARY_HANDLE library_handle; + + if ( NULL != (library_handle = dlopen (library_path, RTLD_NOW | RTLD_GLOBAL)) ) + { + if ( NULL != library_handle_ptr ) + { + *library_handle_ptr = library_handle; + } + + return DAT_SUCCESS; + } + else + { + dat_os_dbg_print (DAT_OS_DBG_TYPE_ERROR, + "DAT: library load failure: %s\n", + dlerror ()); + return DAT_INTERNAL_ERROR; + } +} + + +/*********************************************************************** + * Function: dat_os_library_unload + ***********************************************************************/ + +DAT_RETURN +dat_os_library_unload ( + const DAT_OS_LIBRARY_HANDLE library_handle) +{ + if ( 0 != dlclose (library_handle) ) + { + return DAT_INTERNAL_ERROR; + } + else + { + return DAT_SUCCESS; + } +} diff --git a/branches/WOF2-3/ulp/dapl2/dat/udat/linux/dat_osd.h b/branches/WOF2-3/ulp/dapl2/dat/udat/linux/dat_osd.h new file mode 100644 index 00000000..40b5b1ca --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dat/udat/linux/dat_osd.h @@ -0,0 +1,415 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dat_osd.h + * + * PURPOSE: Operating System Dependent layer + * Description: + * Provide OS dependent data structures & functions with + * a canonical DAT interface. Designed to be portable + * and hide OS specific quirks of common functions. + * + * $Id: dat_osd.h,v 1.18 2005/03/24 05:58:36 jlentini Exp $ + **********************************************************************/ + +#ifndef _DAT_OSD_H_ +#define _DAT_OSD_H_ + +/* + * This file is defined for Linux systems only, including it on any + * other build will cause an error + */ +#ifndef __linux__ +#error "UNDEFINED OS TYPE" +#endif /* __linux__ */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef STATIC +#define STATIC static +#endif /* STATIC */ + +#ifndef INLINE +#define INLINE __inline__ +#endif /* INLINE */ + + +/********************************************************************* + * * + * Debuging * + * * + *********************************************************************/ + +#define dat_os_assert(expr) assert(expr) + +typedef int DAT_OS_DBG_TYPE_VAL; + +typedef enum +{ + DAT_OS_DBG_TYPE_ERROR = 0x1, + DAT_OS_DBG_TYPE_GENERIC = 0x2, + DAT_OS_DBG_TYPE_SR = 0x4, + DAT_OS_DBG_TYPE_DR = 0x8, + DAT_OS_DBG_TYPE_PROVIDER_API = 0x10, + DAT_OS_DBG_TYPE_CONSUMER_API = 0x20, + DAT_OS_DBG_TYPE_ALL = 0xff +} DAT_OS_DBG_TYPE; + +extern void +dat_os_dbg_init ( void ); + +extern void +dat_os_dbg_print ( + DAT_OS_DBG_TYPE_VAL type, + const char * fmt, + ...); + + +/********************************************************************* + * * + * Utility Functions * + * * + *********************************************************************/ + +#define DAT_ERROR(Type, SubType) ((DAT_RETURN)(DAT_CLASS_ERROR | Type | SubType)) +#define dat_os_library_error() dlerror() + +typedef size_t DAT_OS_SIZE; +typedef void * DAT_OS_LIBRARY_HANDLE; + +extern DAT_RETURN +dat_os_library_load ( + const char *library_path, + DAT_OS_LIBRARY_HANDLE *library_handle_ptr ); + +STATIC INLINE void * +dat_os_library_sym ( + DAT_OS_LIBRARY_HANDLE library_handle, + char *sym) +{ + return dlsym (library_handle, sym); +} + +extern DAT_RETURN +dat_os_library_unload ( + const DAT_OS_LIBRARY_HANDLE library_handle ); + +STATIC INLINE char * +dat_os_getenv ( + const char *name) +{ + return getenv (name); +} + +STATIC INLINE long int +dat_os_strtol ( + const char *nptr, + char **endptr, + int base) +{ + return strtol (nptr, endptr, base); +} + +STATIC INLINE DAT_OS_SIZE +dat_os_strlen ( + const char *s ) +{ + return strlen (s); +} + +STATIC INLINE int +dat_os_strncmp ( + const char *s1, + const char *s2, + DAT_OS_SIZE n) +{ + return strncmp (s1, s2, n); +} + +STATIC INLINE void * +dat_os_strncpy ( + char *dest, + const char *src, + DAT_OS_SIZE len) +{ + return strncpy (dest, src, len); +} + +STATIC INLINE DAT_BOOLEAN +dat_os_isblank ( + int c) +{ + if ( (' ' == c) || ('\t' == c) ) + { + return DAT_TRUE; + } + else + { + return DAT_FALSE; + } +} + +STATIC INLINE DAT_BOOLEAN +dat_os_isdigit ( + int c) +{ + if ( isdigit (c) ) + { + return DAT_TRUE; + } + else + { + return DAT_FALSE; + } +} + +STATIC INLINE void +dat_os_usleep ( + unsigned long usec) +{ + usleep (usec); +} + + +/********************************************************************* + * * + * Memory Functions * + * * + *********************************************************************/ + +STATIC INLINE void * +dat_os_alloc ( + int size) +{ + return malloc (size); +} + +STATIC INLINE void +dat_os_free ( + void *ptr, + int size) +{ + free (ptr); +} + +STATIC INLINE void * +dat_os_memset (void *loc, int c, DAT_OS_SIZE size) +{ + return memset (loc, c, size); +} + + +/********************************************************************* + * * + * File I/O * + * * + *********************************************************************/ + +typedef FILE DAT_OS_FILE; +typedef fpos_t DAT_OS_FILE_POS; + + +STATIC INLINE DAT_OS_FILE * +dat_os_fopen ( + const char * path) +{ + /* always open files in read only mode*/ + return fopen (path, "r"); +} + +STATIC INLINE DAT_RETURN +dat_os_fgetpos ( + DAT_OS_FILE *file, + DAT_OS_FILE_POS *pos) +{ + if ( 0 == fgetpos (file, pos) ) + { + return DAT_SUCCESS; + } + else + { + return DAT_INTERNAL_ERROR; + } +} + +STATIC INLINE DAT_RETURN +dat_os_fsetpos ( + DAT_OS_FILE *file, + DAT_OS_FILE_POS *pos) +{ + if ( 0 == fsetpos (file, pos) ) + { + return DAT_SUCCESS; + } + else + { + return DAT_INTERNAL_ERROR; + } +} + +/* dat_os_fgetc() returns EOF on error or end of file. */ +STATIC INLINE int +dat_os_fgetc ( + DAT_OS_FILE *file) +{ + return fgetc (file); +} + +/* dat_os_ungetc() returns EOF on error or char 'c'. + * Push char 'c' back into specified stream for subsequent read. + */ +STATIC INLINE int +dat_os_ungetc ( + DAT_OS_FILE *file, int c) +{ + return ungetc(c, file); +} + +/* dat_os_fgetc() returns EOF on error or end of file. */ +STATIC INLINE int +dat_os_fputc ( + DAT_OS_FILE *file, int c) +{ + return fputc (c, file); +} + +/* dat_os_fread returns the number of bytes read from the file. */ +STATIC INLINE DAT_OS_SIZE +dat_os_fread ( + DAT_OS_FILE *file, + char *buf, + DAT_OS_SIZE len) +{ + return fread (buf, sizeof (char), len, file); +} + +STATIC INLINE DAT_RETURN +dat_os_fclose ( + DAT_OS_FILE *file) +{ + if ( 0 == fclose (file) ) + { + return DAT_SUCCESS; + } + else + { + return DAT_INTERNAL_ERROR; + } +} + + +/********************************************************************* + * * + * Locks * + * * + *********************************************************************/ + +typedef pthread_mutex_t DAT_OS_LOCK; + + +/* lock functions */ +STATIC INLINE DAT_RETURN +dat_os_lock_init ( + IN DAT_OS_LOCK *m) +{ + /* pthread_mutex_init always returns 0 */ + pthread_mutex_init (m, NULL); + + return DAT_SUCCESS; +} + +STATIC INLINE DAT_RETURN +dat_os_lock ( + IN DAT_OS_LOCK *m) +{ + if (0 == pthread_mutex_lock (m)) + { + return DAT_SUCCESS; + } + else + { + return DAT_INTERNAL_ERROR; + } +} + +STATIC INLINE DAT_RETURN +dat_os_unlock ( + IN DAT_OS_LOCK *m) +{ + if (0 == pthread_mutex_unlock (m)) + { + return DAT_SUCCESS; + } + else + { + return DAT_INTERNAL_ERROR; + } +} + +STATIC INLINE DAT_RETURN +dat_os_lock_destroy ( + IN DAT_OS_LOCK *m) +{ + if (0 == pthread_mutex_destroy (m)) + { + return DAT_SUCCESS; + } + else + { + return DAT_INTERNAL_ERROR; + } +} + + +#endif /* _DAT_OSD_H_ */ + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ + diff --git a/branches/WOF2-3/ulp/dapl2/dat/udat/makefile b/branches/WOF2-3/ulp/dapl2/dat/udat/makefile new file mode 100644 index 00000000..e26e1c04 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dat/udat/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\..\inc\openib.def diff --git a/branches/WOF2-3/ulp/dapl2/dat/udat/udat.c b/branches/WOF2-3/ulp/dapl2/dat/udat/udat.c new file mode 100644 index 00000000..03edcf9c --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dat/udat/udat.c @@ -0,0 +1,409 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: udat.c + * + * PURPOSE: DAT Provider and Consumer registry functions. + * + * $Id: udat.c,v 1.22 2005/03/24 05:58:35 jlentini Exp $ + **********************************************************************/ + +#include +#include /* Provider API function prototypes */ + +#include "dat_dr.h" +#include "dat_init.h" +#include "dat_osd.h" +#ifndef DAT_NO_STATIC_REGISTRY +#include "dat_sr.h" +#endif + +#define UDAT_IS_BAD_POINTER(p) ( NULL == (p) ) + +/********************************************************************* + * * + * Internal Function Declarations * + * * + *********************************************************************/ + +DAT_BOOLEAN udat_check_state(void); + +/********************************************************************* + * * + * External Function Definitions * + * * + *********************************************************************/ + +/* + * Use a global to get an unresolved when run with pre-extension library + */ +int g_dat_extensions = 0; + +/* + * + * Provider API + * + */ + +/*********************************************************************** + * Function: dat_registry_add_provider + ***********************************************************************/ + +DAT_RETURN DAT_API +dat_registry_add_provider(IN const DAT_PROVIDER * provider, + IN const DAT_PROVIDER_INFO * provider_info) +{ + DAT_DR_ENTRY entry; + + dat_os_dbg_print(DAT_OS_DBG_TYPE_PROVIDER_API, + "DAT Registry: %s (%s,%x:%x,%x)\n", __FUNCTION__, + provider_info->ia_name, + provider_info->dapl_version_major, + provider_info->dapl_version_minor, + provider_info->is_thread_safe); + + if (UDAT_IS_BAD_POINTER(provider)) { + return DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG1); + } + + if (UDAT_IS_BAD_POINTER(provider_info)) { + return DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG2); + } + + if (DAT_FALSE == udat_check_state()) { + return DAT_ERROR(DAT_INVALID_STATE, 0); + } + + entry.ref_count = 0; + entry.ia_open_func = provider->ia_open_func; + entry.info = *provider_info; + + return dat_dr_insert(provider_info, &entry); +} + +//*********************************************************************** +// Function: dat_registry_remove_provider +//*********************************************************************** + +DAT_RETURN DAT_API +dat_registry_remove_provider(IN const DAT_PROVIDER * provider, + IN const DAT_PROVIDER_INFO * provider_info) +{ + dat_os_dbg_print(DAT_OS_DBG_TYPE_PROVIDER_API, + "DAT Registry: dat_registry_remove_provider () called\n"); + + if (UDAT_IS_BAD_POINTER(provider)) { + return DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG1); + } + + if (DAT_FALSE == udat_check_state()) { + return DAT_ERROR(DAT_INVALID_STATE, 0); + } + + return dat_dr_remove(provider_info); +} + +/* + * + * Consumer API + * + */ + +/*********************************************************************** + * Function: dat_ia_open + ***********************************************************************/ + +DAT_RETURN DAT_API +dat_ia_openv(IN const DAT_NAME_PTR name, + IN DAT_COUNT async_event_qlen, + INOUT DAT_EVD_HANDLE * async_event_handle, + OUT DAT_IA_HANDLE * ia_handle, + IN DAT_UINT32 dapl_major, + IN DAT_UINT32 dapl_minor, IN DAT_BOOLEAN thread_safety) +{ + DAT_IA_OPEN_FUNC ia_open_func; + DAT_PROVIDER_INFO info; + DAT_OS_SIZE len; + DAT_RETURN dat_status; + + dat_os_dbg_print(DAT_OS_DBG_TYPE_CONSUMER_API, + "DAT Registry: dat_ia_openv (%s,%x:%x,%x) called\n", + name, dapl_major, dapl_minor, thread_safety); + + if (UDAT_IS_BAD_POINTER(name)) { + return DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG1); + } + + len = dat_os_strlen(name); + + if (DAT_NAME_MAX_LENGTH <= len) { + return DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG1); + } + + if (UDAT_IS_BAD_POINTER(ia_handle)) { + return DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_IA); + } + + if (DAT_FALSE == udat_check_state()) { + return DAT_ERROR(DAT_INVALID_STATE, 0); + } + + dat_os_strncpy(info.ia_name, name, len + 1); + + info.dapl_version_major = dapl_major; + info.dapl_version_minor = dapl_minor; + info.is_thread_safe = thread_safety; + + /* + * Since DAT allows providers to be loaded by either the static + * registry or explicitly through OS dependent methods, do not + * return an error if no providers are loaded via the static registry. + * Don't even bother calling the static registry if DAT is compiled + * with no static registry support. + */ + +#ifndef DAT_NO_STATIC_REGISTRY + (void)dat_sr_provider_open(&info); +#endif + + dat_status = dat_dr_provider_open(&info, &ia_open_func); + if (dat_status != DAT_SUCCESS) { + dat_os_dbg_print(DAT_OS_DBG_TYPE_CONSUMER_API, + "DAT Registry: dat_ia_open () provider information " + "for IA name %s not found in dynamic registry\n", + name); + + return dat_status; + } + + dat_status = (*ia_open_func) (name, + async_event_qlen, + async_event_handle, ia_handle); + if (dat_status == DAT_SUCCESS) { + *ia_handle = (DAT_IA_HANDLE) dats_set_ia_handle(*ia_handle); + } + + /* + * See if provider supports extensions + */ + if (dat_status == DAT_SUCCESS) { + DAT_IA_ATTR ia_attr; + + if (dat_ia_query(*ia_handle, + NULL, + DAT_IA_ALL, + &ia_attr, 0, NULL) == DAT_SUCCESS) { + if (ia_attr.extension_supported) { + dat_os_dbg_print(DAT_OS_DBG_TYPE_CONSUMER_API, + "DAT Registry: dat_ia_open () " + "Extensions (Type=%d, ver=%d) supported!\n", + ia_attr.extension_supported, + ia_attr.extension_version); + g_dat_extensions = 1; + } + } + } + return dat_status; +} + +/************************************************************************ + * Function: dat_ia_close + ***********************************************************************/ + +DAT_RETURN DAT_API +dat_ia_close(IN DAT_IA_HANDLE ia_handle, IN DAT_CLOSE_FLAGS ia_flags) +{ + DAT_PROVIDER *provider; + DAT_PROVIDER_ATTR provider_attr; + DAT_IA_HANDLE dapl_ia_handle; + DAT_RETURN dat_status; + const char *ia_name; + + dat_os_dbg_print(DAT_OS_DBG_TYPE_CONSUMER_API, + "DAT Registry: dat_ia_close () called\n"); + + dat_status = dats_get_ia_handle(ia_handle, &dapl_ia_handle); + if (dat_status != DAT_SUCCESS) { + return DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_IA); + } + + if (DAT_FALSE == udat_check_state()) { + return DAT_ERROR(DAT_INVALID_STATE, 0); + } + + provider = DAT_HANDLE_TO_PROVIDER(dapl_ia_handle); + ia_name = provider->device_name; + + if (DAT_SUCCESS != (dat_status = dat_ia_query(ia_handle, + NULL, + 0, + NULL, + DAT_PROVIDER_FIELD_ALL, + &provider_attr))) { + dat_os_dbg_print(DAT_OS_DBG_TYPE_CONSUMER_API, + "DAT Registry: query function for %s provider failed\n", + ia_name); + } else if (DAT_SUCCESS != (dat_status = + (*provider->ia_close_func) (dapl_ia_handle, + ia_flags))) { + dat_os_dbg_print(DAT_OS_DBG_TYPE_CONSUMER_API, + "DAT Registry: close function for %s provider failed\n", + ia_name); + } else { + DAT_PROVIDER_INFO info; + DAT_OS_SIZE len; + + len = dat_os_strlen(ia_name); + + dat_os_assert(len < DAT_NAME_MAX_LENGTH); + + dat_os_strncpy(info.ia_name, ia_name, len + 1); + + info.dapl_version_major = provider_attr.dapl_version_major; + info.dapl_version_minor = provider_attr.dapl_version_minor; + info.is_thread_safe = provider_attr.is_thread_safe; + + dat_status = dat_dr_provider_close(&info); + if (DAT_SUCCESS != dat_status) { + dat_os_dbg_print(DAT_OS_DBG_TYPE_CONSUMER_API, + "DAT Registry: dynamic registry unable to close " + "provider for IA name %s\n", ia_name); + } + + /* Remove the handle from the handle table */ + (void)dats_free_ia_handle(ia_handle); + +#ifndef DAT_NO_STATIC_REGISTRY + dat_status = dat_sr_provider_close(&info); + if (DAT_SUCCESS != dat_status) { + dat_os_dbg_print(DAT_OS_DBG_TYPE_CONSUMER_API, + "DAT Registry: static registry unable to close " + "provider for IA name %s\n", ia_name); + } +#endif + } + + return dat_status; +} + +//*********************************************************************** +// Function: dat_registry_list_providers +//*********************************************************************** + +DAT_RETURN DAT_API +dat_registry_list_providers(IN DAT_COUNT max_to_return, + OUT DAT_COUNT * entries_returned, + OUT DAT_PROVIDER_INFO * (dat_provider_list[])) +{ + DAT_RETURN dat_status; + + dat_status = DAT_SUCCESS; + dat_os_dbg_print(DAT_OS_DBG_TYPE_CONSUMER_API, + "DAT Registry: dat_registry_list_providers () called\n"); + + if (DAT_FALSE == udat_check_state()) { + return DAT_ERROR(DAT_INVALID_STATE, 0); + } + + if ((UDAT_IS_BAD_POINTER(entries_returned))) { + return DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG2); + } + + if (0 != max_to_return && (UDAT_IS_BAD_POINTER(dat_provider_list))) { + return DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG3); + } + + if (0 == max_to_return) { + /* the user is allowed to call with max_to_return set to zero. + * in which case we simply return (in *entries_returned) the + * number of providers currently installed. We must also + * (per spec) return an error + */ +#ifndef DAT_NO_STATIC_REGISTRY + (void)dat_sr_size(entries_returned); +#else + (void)dat_dr_size(entries_returned); +#endif + return DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG1); + } else { +#ifndef DAT_NO_STATIC_REGISTRY + dat_status = dat_sr_list(max_to_return, + entries_returned, dat_provider_list); +#else + dat_status = dat_dr_list(max_to_return, + entries_returned, dat_provider_list); +#endif + } + return dat_status; +} + +/********************************************************************* + * * + * Internal Function Definitions * + * * + *********************************************************************/ + +//*********************************************************************** +// Function: udat_check_state +//*********************************************************************** + +/* + * This function returns TRUE if the DAT registry is in a state capable + * of handling DAT API calls and false otherwise. + */ + +DAT_BOOLEAN udat_check_state(void) +{ + DAT_MODULE_STATE state; + DAT_BOOLEAN status; + + state = dat_module_get_state(); + + if (DAT_MODULE_STATE_UNINITIALIZED == state) { + dat_init(); + status = DAT_TRUE; + } else if (DAT_MODULE_STATE_DEINITIALIZED == state) { + status = DAT_FALSE; + } else { + status = DAT_TRUE; + } + + return status; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dat/udat/udat.rc b/branches/WOF2-3/ulp/dapl2/dat/udat/udat.rc new file mode 100644 index 00000000..8fa97f0f --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dat/udat/udat.rc @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2007 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#if DBG +#define VER_FILEDESCRIPTION_STR "Direct Access Transport Library v2.0 (Debug)" +#define VER_INTERNALNAME_STR "dat2d.dll" +#define VER_ORIGINALFILENAME_STR "dat2d.dll" +#else +#define VER_FILEDESCRIPTION_STR "Direct Access Transport Library v2.0" +#define VER_INTERNALNAME_STR "dat2.dll" +#define VER_ORIGINALFILENAME_STR "dat2.dll" +#endif + +#include diff --git a/branches/WOF2-3/ulp/dapl2/dat/udat/udat_api.c b/branches/WOF2-3/ulp/dapl2/dat/udat/udat_api.c new file mode 100644 index 00000000..5948a4fe --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dat/udat/udat_api.c @@ -0,0 +1,260 @@ +/* + * Copyright (c) 2002-2006, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under all of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 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. + * + * Neither the name of Network Appliance, Inc. nor the names of other DAT + * Collaborative contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + */ + +/********************************************************************** + * + * MODULE: udat.c + * + * PURPOSE: DAT Provider and Consumer registry functions. + * + * $Id: udat_api.c 1301 2005-03-24 05:58:55Z jlentini $ + **********************************************************************/ + +#include +#include +#include "dat_osd.h" +#include "dat_init.h" + +#define UDAT_IS_BAD_HANDLE(h) ( NULL == (p) ) + +DAT_RETURN DAT_API dat_lmr_create(IN DAT_IA_HANDLE ia_handle, + IN DAT_MEM_TYPE mem_type, + IN DAT_REGION_DESCRIPTION region_description, + IN DAT_VLEN length, + IN DAT_PZ_HANDLE pz_handle, + IN DAT_MEM_PRIV_FLAGS privileges, + IN DAT_VA_TYPE va_type, + OUT DAT_LMR_HANDLE * lmr_handle, + OUT DAT_LMR_CONTEXT * lmr_context, + OUT DAT_RMR_CONTEXT * rmr_context, + OUT DAT_VLEN * registered_length, + OUT DAT_VADDR * registered_address) +{ + DAT_IA_HANDLE dapl_ia_handle; + DAT_RETURN dat_status; + + dat_status = dats_get_ia_handle(ia_handle, &dapl_ia_handle); + if (dat_status == DAT_SUCCESS) { + dat_status = DAT_LMR_CREATE(dapl_ia_handle, + mem_type, + region_description, + length, + pz_handle, + privileges, + va_type, + lmr_handle, + lmr_context, + rmr_context, + registered_length, + registered_address); + } + + return dat_status; +} + +DAT_RETURN DAT_API dat_evd_create(IN DAT_IA_HANDLE ia_handle, + IN DAT_COUNT evd_min_qlen, + IN DAT_CNO_HANDLE cno_handle, + IN DAT_EVD_FLAGS evd_flags, + OUT DAT_EVD_HANDLE * evd_handle) +{ + DAT_IA_HANDLE dapl_ia_handle; + DAT_RETURN dat_status; + + dat_status = dats_get_ia_handle(ia_handle, &dapl_ia_handle); + if (dat_status == DAT_SUCCESS) { + dat_status = DAT_EVD_CREATE(dapl_ia_handle, + evd_min_qlen, + cno_handle, evd_flags, evd_handle); + } + + return dat_status; +} + +DAT_RETURN DAT_API dat_evd_modify_cno(IN DAT_EVD_HANDLE evd_handle, + IN DAT_CNO_HANDLE cno_handle) +{ + if (evd_handle == NULL) { + return DAT_ERROR(DAT_INVALID_HANDLE, + DAT_INVALID_HANDLE_EVD_REQUEST); + } + return DAT_EVD_MODIFY_CNO(evd_handle, cno_handle); +} + +DAT_RETURN DAT_API dat_cno_create(IN DAT_IA_HANDLE ia_handle, + IN DAT_OS_WAIT_PROXY_AGENT agent, + OUT DAT_CNO_HANDLE * cno_handle) +{ + DAT_IA_HANDLE dapl_ia_handle; + DAT_RETURN dat_status; + + dat_status = dats_get_ia_handle(ia_handle, &dapl_ia_handle); + if (dat_status == DAT_SUCCESS) { + dat_status = DAT_CNO_CREATE(dapl_ia_handle, agent, cno_handle); + } + + return dat_status; +} + +DAT_RETURN DAT_API dat_cno_fd_create(IN DAT_IA_HANDLE ia_handle, + OUT DAT_FD * fd, + OUT DAT_CNO_HANDLE * cno_handle) +{ + DAT_IA_HANDLE dapl_ia_handle; + DAT_RETURN dat_status; + + dat_status = dats_get_ia_handle(ia_handle, &dapl_ia_handle); + if (dat_status == DAT_SUCCESS) { + dat_status = DAT_CNO_FD_CREATE(dapl_ia_handle, + (DAT_FD *) fd, cno_handle); + } + + return dat_status; +} + +DAT_RETURN DAT_API dat_cno_modify_agent(IN DAT_CNO_HANDLE cno_handle, + IN DAT_OS_WAIT_PROXY_AGENT agent) +{ + if (cno_handle == NULL) { + return DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_CNO); + } + return DAT_CNO_MODIFY_AGENT(cno_handle, agent); +} + +DAT_RETURN DAT_API dat_cno_query(IN DAT_CNO_HANDLE cno_handle, + IN DAT_CNO_PARAM_MASK cno_param_mask, + OUT DAT_CNO_PARAM * cno_param) +{ + return DAT_CNO_QUERY(cno_handle, cno_param_mask, cno_param); +} + +DAT_RETURN DAT_API dat_cno_free(IN DAT_CNO_HANDLE cno_handle) +{ + if (cno_handle == NULL) { + return DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_CNO); + } + return DAT_CNO_FREE(cno_handle); +} + +DAT_RETURN DAT_API dat_cno_wait(IN DAT_CNO_HANDLE cno_handle, + IN DAT_TIMEOUT timeout, + OUT DAT_EVD_HANDLE * evd_handle) +{ + if (cno_handle == NULL) { + return DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_CNO); + } + return DAT_CNO_WAIT(cno_handle, timeout, evd_handle); +} + +DAT_RETURN DAT_API dat_evd_enable(IN DAT_EVD_HANDLE evd_handle) +{ + if (evd_handle == NULL) { + return DAT_ERROR(DAT_INVALID_HANDLE, + DAT_INVALID_HANDLE_EVD_REQUEST); + } + return DAT_EVD_ENABLE(evd_handle); +} + +DAT_RETURN DAT_API dat_evd_wait(IN DAT_EVD_HANDLE evd_handle, + IN DAT_TIMEOUT Timeout, + IN DAT_COUNT Threshold, + OUT DAT_EVENT * event, + OUT DAT_COUNT * n_more_events) +{ + if (evd_handle == NULL) { + return DAT_ERROR(DAT_INVALID_HANDLE, + DAT_INVALID_HANDLE_EVD_REQUEST); + } + return DAT_EVD_WAIT(evd_handle, + Timeout, Threshold, event, n_more_events); +} + +DAT_RETURN DAT_API dat_evd_disable(IN DAT_EVD_HANDLE evd_handle) +{ + if (evd_handle == NULL) { + return DAT_ERROR(DAT_INVALID_HANDLE, + DAT_INVALID_HANDLE_EVD_REQUEST); + } + return DAT_EVD_DISABLE(evd_handle); +} + +DAT_RETURN DAT_API dat_evd_set_unwaitable(IN DAT_EVD_HANDLE evd_handle) +{ + if (evd_handle == NULL) { + return DAT_ERROR(DAT_INVALID_HANDLE, + DAT_INVALID_HANDLE_EVD_REQUEST); + } + return DAT_EVD_SET_UNWAITABLE(evd_handle); +} + +DAT_RETURN DAT_API dat_evd_clear_unwaitable(IN DAT_EVD_HANDLE evd_handle) +{ + if (evd_handle == NULL) { + return DAT_ERROR(DAT_INVALID_HANDLE, + DAT_INVALID_HANDLE_EVD_REQUEST); + } + return DAT_EVD_CLEAR_UNWAITABLE(evd_handle); +} + +DAT_RETURN DAT_API dat_cr_handoff(IN DAT_CR_HANDLE cr_handle, + IN DAT_CONN_QUAL handoff) +{ + if (cr_handle == NULL) { + return DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_CR); + } + return DAT_CR_HANDOFF(cr_handle, handoff); +} + +DAT_RETURN DAT_API dat_lmr_query(IN DAT_LMR_HANDLE lmr_handle, + IN DAT_LMR_PARAM_MASK lmr_param_mask, + OUT DAT_LMR_PARAM * lmr_param) +{ + if (lmr_handle == NULL) { + return DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_LMR); + } + return DAT_LMR_QUERY(lmr_handle, lmr_param_mask, lmr_param); +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ diff --git a/branches/WOF2-3/ulp/dapl2/dat/udat/udat_exports.src b/branches/WOF2-3/ulp/dapl2/dat/udat/udat_exports.src new file mode 100644 index 00000000..32b29ff7 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dat/udat/udat_exports.src @@ -0,0 +1,59 @@ +#if DBG +LIBRARY dat2d.dll +#else +LIBRARY dat2.dll +#endif + +EXPORTS +dat_cno_create +dat_cno_query +dat_cno_wait +dat_cno_free +dat_cr_accept +dat_cr_reject +dat_cr_query +dat_ep_create +dat_ep_free +dat_ep_post_recv +dat_ep_post_rdma_read +dat_ep_post_rdma_write +dat_ep_post_send +dat_ep_reset +dat_ep_connect +dat_ep_disconnect +dat_ep_get_status +dat_ep_query +dat_evd_create +dat_evd_query +dat_evd_free +dat_evd_wait +dat_evd_dequeue +dat_ia_close +dat_ia_openv +dat_ia_query +dat_lmr_create +dat_lmr_free +dat_lmr_query +dat_psp_create +dat_psp_free +dat_psp_query +dat_pz_create +dat_pz_free +dat_pz_query +dat_registry_add_provider +dat_registry_remove_provider +dat_registry_list_providers +dat_rmr_bind +dat_rmr_create +dat_rmr_free +dat_rmr_query +dat_rsp_create +dat_rsp_free +dat_rsp_query +dat_strerror +dat_get_handle_type +dats_get_ia_handle +#ifdef DAT_EXTENSIONS +dat_extension_op +#endif + diff --git a/branches/WOF2-3/ulp/dapl2/dat/udat/udat_sources.c b/branches/WOF2-3/ulp/dapl2/dat/udat/udat_sources.c new file mode 100644 index 00000000..264ab4f7 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dat/udat/udat_sources.c @@ -0,0 +1,11 @@ +/* + * Include all files that are not in children directories. + */ + +#include "../common/dat_api.c" +#include "../common/dat_dictionary.c" +#include "../common/dat_dr.c" +#include "../common/dat_init.c" +#include "../common/dat_sr.c" +#include "../common/dat_strerror.c" +#include "windows/dat_osd.c" diff --git a/branches/WOF2-3/ulp/dapl2/dat/udat/udat_sr_parser.c b/branches/WOF2-3/ulp/dapl2/dat/udat/udat_sr_parser.c new file mode 100644 index 00000000..3b5caef0 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dat/udat/udat_sr_parser.c @@ -0,0 +1,1216 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dat_sr_parser.c + * + * PURPOSE: static registry parser + * + * $Id: udat_sr_parser.c,v 1.6 2005/03/24 05:58:36 jlentini Exp $ + **********************************************************************/ + +#include +#include "udat_sr_parser.h" +#include "dat_sr.h" + +/********************************************************************* + * * + * Constants * + * * + *********************************************************************/ + +#define DAT_SR_CONF_ENV "DAT_OVERRIDE" +#if defined(_WIN32) || defined(_WIN64) +#define DAT_SR_CONF_DEFAULT "C:\\DAT\\dat.conf" +#else +#define DAT_SR_CONF_DEFAULT "/etc/dat.conf" +#endif + +#define DAT_SR_TOKEN_THREADSAFE "threadsafe" +#define DAT_SR_TOKEN_NONTHREADSAFE "nonthreadsafe" +#define DAT_SR_TOKEN_DEFAULT "default" +#define DAT_SR_TOKEN_NONDEFAULT "nondefault" + +#define DAT_SR_CHAR_NEWLINE '\n' +#define DAT_SR_CHAR_COMMENT '#' +#define DAT_SR_CHAR_QUOTE '"' +#define DAT_SR_CHAR_BACKSLASH '\\' + +/********************************************************************* + * * + * Enumerations * + * * + *********************************************************************/ + +typedef enum { + DAT_SR_TOKEN_STRING, /* text field (both quoted or unquoted) */ + DAT_SR_TOKEN_EOR, /* end of record (newline) */ + DAT_SR_TOKEN_EOF /* end of file */ +} DAT_SR_TOKEN_TYPE; + +typedef enum { + DAT_SR_API_UDAT, + DAT_SR_API_KDAT +} DAT_SR_API_TYPE; + +/********************************************************************* + * * + * Structures * + * * + *********************************************************************/ + +typedef struct { + DAT_SR_TOKEN_TYPE type; + char *value; /* valid if type is DAT_SR_TOKEN_STRING */ + DAT_OS_SIZE value_len; +} DAT_SR_TOKEN; + +typedef struct DAT_SR_STACK_NODE { + DAT_SR_TOKEN token; + struct DAT_SR_STACK_NODE *next; +} DAT_SR_STACK_NODE; + +typedef struct { + DAT_UINT32 major; + DAT_UINT32 minor; +} DAT_SR_VERSION; + +typedef struct { + char *id; + DAT_SR_VERSION version; +} DAT_SR_PROVIDER_VERSION; + +typedef struct { + DAT_SR_API_TYPE type; + DAT_SR_VERSION version; +} DAT_SR_API_VERSION; + +typedef struct { + char *ia_name; + DAT_SR_API_VERSION api_version; + DAT_BOOLEAN is_thread_safe; + DAT_BOOLEAN is_default; + char *lib_path; + DAT_SR_PROVIDER_VERSION provider_version; + char *ia_params; + char *platform_params; +} DAT_SR_CONF_ENTRY; + +/********************************************************************* + * * + * Internal Function Declarations * + * * + *********************************************************************/ + +static DAT_RETURN dat_sr_load_entry(DAT_SR_CONF_ENTRY * entry); + +static DAT_BOOLEAN dat_sr_is_valid_entry(DAT_SR_CONF_ENTRY * entry); + +static char *dat_sr_type_to_str(DAT_SR_TOKEN_TYPE type); + +static DAT_RETURN dat_sr_parse_eof(DAT_OS_FILE * file); + +static DAT_RETURN dat_sr_parse_entry(DAT_OS_FILE * file); + +static DAT_RETURN +dat_sr_parse_ia_name(DAT_OS_FILE * file, DAT_SR_CONF_ENTRY * entry); + +static DAT_RETURN +dat_sr_parse_api(DAT_OS_FILE * file, DAT_SR_CONF_ENTRY * entry); + +static DAT_RETURN +dat_sr_parse_thread_safety(DAT_OS_FILE * file, DAT_SR_CONF_ENTRY * entry); + +static DAT_RETURN +dat_sr_parse_default(DAT_OS_FILE * file, DAT_SR_CONF_ENTRY * entry); + +static DAT_RETURN +dat_sr_parse_lib_path(DAT_OS_FILE * file, DAT_SR_CONF_ENTRY * entry); + +static DAT_RETURN +dat_sr_parse_provider_version(DAT_OS_FILE * file, DAT_SR_CONF_ENTRY * entry); + +static DAT_RETURN +dat_sr_parse_ia_params(DAT_OS_FILE * file, DAT_SR_CONF_ENTRY * entry); + +static DAT_RETURN +dat_sr_parse_platform_params(DAT_OS_FILE * file, DAT_SR_CONF_ENTRY * entry); + +static DAT_RETURN +dat_sr_parse_eoe(DAT_OS_FILE * file, DAT_SR_CONF_ENTRY * entry); + +static DAT_RETURN +dat_sr_convert_api(char *str, DAT_SR_API_VERSION * api_version); + +static DAT_RETURN +dat_sr_convert_thread_safety(char *str, DAT_BOOLEAN * is_thread_safe); + +static DAT_RETURN dat_sr_convert_default(char *str, DAT_BOOLEAN * is_default); + +static DAT_RETURN +dat_sr_convert_provider_version(char *str, + DAT_SR_PROVIDER_VERSION * provider_version); + +static DAT_RETURN dat_sr_get_token(DAT_OS_FILE * file, DAT_SR_TOKEN * token); + +static DAT_RETURN dat_sr_put_token(DAT_OS_FILE * file, DAT_SR_TOKEN * token); + +static DAT_RETURN dat_sr_read_token(DAT_OS_FILE * file, DAT_SR_TOKEN * token); + +static DAT_RETURN +dat_sr_read_str(DAT_OS_FILE * file, + DAT_SR_TOKEN * token, DAT_OS_SIZE token_len); + +static DAT_RETURN +dat_sr_read_quoted_str(DAT_OS_FILE * file, + DAT_SR_TOKEN * token, + DAT_OS_SIZE token_len, DAT_COUNT num_escape_seq); + +static void dat_sr_read_comment(DAT_OS_FILE * file); + +/********************************************************************* + * * + * Global Variables * + * * + *********************************************************************/ + +static DAT_SR_STACK_NODE *g_token_stack = NULL; + +/********************************************************************* + * * + * External Function Definitions * + * * + *********************************************************************/ + +/*********************************************************************** + * Function: dat_sr_load + ***********************************************************************/ + +DAT_RETURN dat_sr_load(void) +{ + char *sr_path; + DAT_OS_FILE *sr_file; + + sr_path = dat_os_getenv(DAT_SR_CONF_ENV); + + /* environment override */ + if ((sr_path != NULL) && ((sr_file = dat_os_fopen(sr_path)) == NULL)) { + dat_os_dbg_print(DAT_OS_DBG_TYPE_ERROR, + "DAT Registry: DAT_OVERRIDE, " + "bad filename - %s, aborting\n", sr_path); + goto bail; + } + + if (sr_path == NULL) { + +#ifdef DAT_CONF + sr_path = DAT_CONF; +#else + sr_path = DAT_SR_CONF_DEFAULT; +#endif + sr_file = dat_os_fopen(sr_path); + if (sr_file == NULL) { +#ifdef DAT_CONF + dat_os_dbg_print(DAT_OS_DBG_TYPE_SR, + "DAT Registry: sysconfdir, " + "bad filename - %s, retry default at %s\n", + sr_path, DAT_SR_CONF_DEFAULT); + /* try default after sysconfdir fails */ + sr_path = DAT_SR_CONF_DEFAULT; + sr_file = dat_os_fopen(sr_path); + if (sr_file == NULL) { +#endif + dat_os_dbg_print(DAT_OS_DBG_TYPE_ERROR, + "DAT Registry: default, " + "bad filename - %s, aborting\n", + sr_path); + goto bail; +#ifdef DAT_CONF + } +#endif + } + } + + dat_os_dbg_print(DAT_OS_DBG_TYPE_GENERIC, + "DAT Registry: using config file %s\n", sr_path); + + for (;;) { + if (DAT_SUCCESS == dat_sr_parse_eof(sr_file)) { + break; + } else if (DAT_SUCCESS == dat_sr_parse_entry(sr_file)) { + continue; + } else { + dat_os_dbg_print(DAT_OS_DBG_TYPE_ERROR, + "DAT Registry: ERROR parsing - %s\n", + sr_path); + goto cleanup; + } + } + + if (0 != dat_os_fclose(sr_file)) { + dat_os_dbg_print(DAT_OS_DBG_TYPE_ERROR, + "DAT Registry: ERROR closing - %s\n", sr_path); + goto bail; + } + + return DAT_SUCCESS; + + cleanup: + dat_os_fclose(sr_file); + bail: + return DAT_INTERNAL_ERROR; + +} + +/********************************************************************* + * * + * Internal Function Definitions * + * * + *********************************************************************/ + +/*********************************************************************** + * Function: dat_sr_is_valid_entry + ***********************************************************************/ + +DAT_BOOLEAN dat_sr_is_valid_entry(DAT_SR_CONF_ENTRY * entry) +{ + if ((DAT_SR_API_UDAT == entry->api_version.type) && (entry->is_default)) { + return DAT_TRUE; + } else { + return DAT_FALSE; + } +} + +/*********************************************************************** + * Function: dat_sr_load_entry + ***********************************************************************/ + +DAT_RETURN dat_sr_load_entry(DAT_SR_CONF_ENTRY * conf_entry) +{ + DAT_SR_ENTRY entry; + + if (DAT_NAME_MAX_LENGTH < (strlen(conf_entry->ia_name) + 1)) { + dat_os_dbg_print(DAT_OS_DBG_TYPE_SR, + "DAT Registry: ia name %s is longer than " + "DAT_NAME_MAX_LENGTH (%i)\n", + conf_entry->ia_name, DAT_NAME_MAX_LENGTH); + + return DAT_INSUFFICIENT_RESOURCES; + } + + dat_os_strncpy(entry.info.ia_name, conf_entry->ia_name, + DAT_NAME_MAX_LENGTH); + entry.info.dapl_version_major = conf_entry->api_version.version.major; + entry.info.dapl_version_minor = conf_entry->api_version.version.minor; + entry.info.is_thread_safe = conf_entry->is_thread_safe; + entry.lib_path = conf_entry->lib_path; + entry.ia_params = conf_entry->ia_params; + entry.lib_handle = NULL; + entry.ref_count = 0; + + dat_os_dbg_print(DAT_OS_DBG_TYPE_SR, + "DAT Registry: loading provider for %s\n", + conf_entry->ia_name); + + return dat_sr_insert(&entry.info, &entry); +} + +/*********************************************************************** + * Function: dat_sr_type_to_str + ***********************************************************************/ + +char *dat_sr_type_to_str(DAT_SR_TOKEN_TYPE type) +{ + static char *str_array[] = { "string", "eor", "eof" }; + + if ((type < 0) || (2 < type)) { + return "error: invalid token type"; + } + + return str_array[type]; +} + +/*********************************************************************** + * Function: dat_sr_parse_eof + ***********************************************************************/ + +DAT_RETURN dat_sr_parse_eof(DAT_OS_FILE * file) +{ + DAT_SR_TOKEN token; + + if (DAT_SUCCESS != dat_sr_get_token(file, &token)) { + return DAT_INTERNAL_ERROR; + } + + if (DAT_SR_TOKEN_EOF == token.type) { + return DAT_SUCCESS; + } else { + dat_sr_put_token(file, &token); + return DAT_INTERNAL_ERROR; + } +} + +/*********************************************************************** + * Function: dat_sr_parse_ia_name + ***********************************************************************/ + +DAT_RETURN dat_sr_parse_entry(DAT_OS_FILE * file) +{ + DAT_SR_CONF_ENTRY entry; + DAT_RETURN status; + + dat_os_memset(&entry, 0, sizeof(DAT_SR_CONF_ENTRY)); + + if ((DAT_SUCCESS == dat_sr_parse_ia_name(file, &entry)) && + (DAT_SUCCESS == dat_sr_parse_api(file, &entry)) && + (DAT_SUCCESS == dat_sr_parse_thread_safety(file, &entry)) && + (DAT_SUCCESS == dat_sr_parse_default(file, &entry)) && + (DAT_SUCCESS == dat_sr_parse_lib_path(file, &entry)) && + (DAT_SUCCESS == dat_sr_parse_provider_version(file, &entry)) && + (DAT_SUCCESS == dat_sr_parse_ia_params(file, &entry)) && + (DAT_SUCCESS == dat_sr_parse_platform_params(file, &entry)) && + (DAT_SUCCESS == dat_sr_parse_eoe(file, &entry))) { + dat_os_dbg_print(DAT_OS_DBG_TYPE_SR, + "\n" + "DAT Registry: entry \n" + " ia_name %s\n" + " api_version\n" + " type 0x%X\n" + " major.minor %d.%d\n" + " is_thread_safe %d\n" + " is_default %d\n" + " lib_path %s\n" + " provider_version\n" + " id %s\n" + " major.minor %d.%d\n" + " ia_params %s\n" + "\n", + entry.ia_name, + entry.api_version.type, + entry.api_version.version.major, + entry.api_version.version.minor, + entry.is_thread_safe, + entry.is_default, + entry.lib_path, + entry.provider_version.id, + entry.provider_version.version.major, + entry.provider_version.version.minor, + entry.ia_params); + + if (DAT_TRUE == dat_sr_is_valid_entry(&entry)) { + /* + * The static registry configuration file may have multiple + * entries with the same IA name. The first entry will be + * installed in the static registry causing subsequent attempts + * to register the same IA name to fail. Therefore the return code + * from dat_sr_load_entry() is ignored. + */ + (void)dat_sr_load_entry(&entry); + } + + status = DAT_SUCCESS; + } else { /* resync */ + + DAT_SR_TOKEN token; + + /* + * The static registry format is specified in the DAT specification. + * While the registry file's contents may change between revisions of + * the specification, there is no way to determine the specification + * version to which the configuration file conforms. If an entry is + * found that does not match the expected format, the entry is discarded + * and the parsing of the file continues. There is no way to determine if + * the entry was an error or an entry confirming to an alternate version + * of specification. + */ + + for (;;) { + if (DAT_SUCCESS != dat_sr_get_token(file, &token)) { + status = DAT_INTERNAL_ERROR; + break; + } + + if (DAT_SR_TOKEN_STRING != token.type) { + status = DAT_SUCCESS; + break; + } else { + dat_os_free(token.value, + (sizeof(char) * + dat_os_strlen(token.value)) + 1); + continue; + } + } + } + + /* free resources */ + if (NULL != entry.ia_name) { + dat_os_free(entry.ia_name, + sizeof(char) * (dat_os_strlen(entry.ia_name) + 1)); + } + if (NULL != entry.lib_path) { + dat_os_free(entry.lib_path, + sizeof(char) * (dat_os_strlen(entry.lib_path) + 1)); + } + + if (NULL != entry.provider_version.id) { + dat_os_free(entry.provider_version.id, + sizeof(char) * + (dat_os_strlen(entry.provider_version.id) + 1)); + } + + if (NULL != entry.ia_params) { + dat_os_free(entry.ia_params, + sizeof(char) * (dat_os_strlen(entry.ia_params) + + 1)); + } + + return status; +} + +/*********************************************************************** + * Function: dat_sr_parse_ia_name + ***********************************************************************/ + +DAT_RETURN dat_sr_parse_ia_name(DAT_OS_FILE * file, DAT_SR_CONF_ENTRY * entry) +{ + DAT_SR_TOKEN token; + + if (DAT_SUCCESS != dat_sr_get_token(file, &token)) + goto bail; + + if (DAT_SR_TOKEN_STRING != token.type) { + dat_sr_put_token(file, &token); + goto bail; + } + entry->ia_name = token.value; + return DAT_SUCCESS; + + bail: + return DAT_INTERNAL_ERROR; +} + +/*********************************************************************** + * Function: dat_sr_parse_ia_name + ***********************************************************************/ + +DAT_RETURN dat_sr_parse_api(DAT_OS_FILE * file, DAT_SR_CONF_ENTRY * entry) +{ + DAT_SR_TOKEN token; + + if (DAT_SUCCESS != dat_sr_get_token(file, &token)) + goto bail; + + if (DAT_SR_TOKEN_STRING != token.type) + goto cleanup; + + if (DAT_SUCCESS != dat_sr_convert_api(token.value, &entry->api_version)) + goto cleanup; + + dat_os_free(token.value, + (sizeof(char) * dat_os_strlen(token.value)) + 1); + return DAT_SUCCESS; + + cleanup: + dat_sr_put_token(file, &token); + bail: + dat_os_dbg_print(DAT_OS_DBG_TYPE_ERROR, + " ERR: corrupt dat.conf entry field:" + " api_ver, file offset=%ld\n", ftell(file)); + return DAT_INTERNAL_ERROR; +} + +/*********************************************************************** + * Function: dat_sr_parse_thread_safety + ***********************************************************************/ + +static DAT_RETURN +dat_sr_parse_thread_safety(DAT_OS_FILE * file, DAT_SR_CONF_ENTRY * entry) +{ + DAT_SR_TOKEN token; + + if (DAT_SUCCESS != dat_sr_get_token(file, &token)) + goto bail; + + if (DAT_SR_TOKEN_STRING != token.type) + goto cleanup; + + if (DAT_SUCCESS != + dat_sr_convert_thread_safety(token.value, &entry->is_thread_safe)) + goto cleanup; + + dat_os_free(token.value, + (sizeof(char) * dat_os_strlen(token.value)) + 1); + return DAT_SUCCESS; + + cleanup: + dat_sr_put_token(file, &token); + bail: + dat_os_dbg_print(DAT_OS_DBG_TYPE_ERROR, + " ERR: corrupt dat.conf entry field:" + " thread_safety, file offset=%ld\n", ftell(file)); + return DAT_INTERNAL_ERROR; +} + +/*********************************************************************** + * Function: dat_sr_parse_default + ***********************************************************************/ + +DAT_RETURN dat_sr_parse_default(DAT_OS_FILE * file, DAT_SR_CONF_ENTRY * entry) +{ + DAT_SR_TOKEN token; + + if (DAT_SUCCESS != dat_sr_get_token(file, &token)) + goto bail; + + if (DAT_SR_TOKEN_STRING != token.type) + goto cleanup; + + if (DAT_SUCCESS != + dat_sr_convert_default(token.value, &entry->is_default)) + goto cleanup; + + dat_os_free(token.value, + (sizeof(char) * dat_os_strlen(token.value)) + 1); + return DAT_SUCCESS; + + cleanup: + dat_sr_put_token(file, &token); + bail: + dat_os_dbg_print(DAT_OS_DBG_TYPE_ERROR, + " ERR: corrupt dat.conf entry field:" + " default section, file offset=%ld\n", ftell(file)); + return DAT_INTERNAL_ERROR; +} + +/*********************************************************************** + * Function: dat_sr_parse_lib_path + ***********************************************************************/ + +DAT_RETURN dat_sr_parse_lib_path(DAT_OS_FILE * file, DAT_SR_CONF_ENTRY * entry) +{ + DAT_SR_TOKEN token; + + if (DAT_SUCCESS != dat_sr_get_token(file, &token)) + goto bail; + + if (DAT_SR_TOKEN_STRING != token.type) { + dat_sr_put_token(file, &token); + goto bail; + } + entry->lib_path = token.value; + return DAT_SUCCESS; + + bail: + dat_os_dbg_print(DAT_OS_DBG_TYPE_ERROR, + " ERR: corrupt dat.conf entry field:" + " lib_path, file offset=%ld\n", ftell(file)); + return DAT_INTERNAL_ERROR; +} + +/*********************************************************************** + * Function: dat_sr_parse_provider_version + ***********************************************************************/ + +DAT_RETURN +dat_sr_parse_provider_version(DAT_OS_FILE * file, DAT_SR_CONF_ENTRY * entry) +{ + DAT_SR_TOKEN token; + + if (DAT_SUCCESS != dat_sr_get_token(file, &token)) + goto bail; + + if (DAT_SR_TOKEN_STRING != token.type) + goto cleanup; + + if (DAT_SUCCESS != + dat_sr_convert_provider_version(token.value, + &entry->provider_version)) + goto cleanup; + + dat_os_free(token.value, + (sizeof(char) * dat_os_strlen(token.value)) + 1); + return DAT_SUCCESS; + + cleanup: + dat_sr_put_token(file, &token); + bail: + dat_os_dbg_print(DAT_OS_DBG_TYPE_ERROR, + " ERR: corrupt dat.conf entry field:" + " provider_ver, file offset=%ld\n", ftell(file)); + return DAT_INTERNAL_ERROR; +} + +/*********************************************************************** + * Function: dat_sr_parse_ia_params + ***********************************************************************/ + +DAT_RETURN dat_sr_parse_ia_params(DAT_OS_FILE * file, DAT_SR_CONF_ENTRY * entry) +{ + DAT_SR_TOKEN token; + + if (DAT_SUCCESS != dat_sr_get_token(file, &token)) + goto bail; + + if (DAT_SR_TOKEN_STRING != token.type) { + dat_sr_put_token(file, &token); + goto bail; + } + + entry->ia_params = token.value; + return DAT_SUCCESS; + + bail: + dat_os_dbg_print(DAT_OS_DBG_TYPE_ERROR, + " ERR: corrupt dat.conf entry field:" + " ia_params, file offset=%ld\n", ftell(file)); + return DAT_INTERNAL_ERROR; +} + +/*********************************************************************** + * Function: dat_sr_parse_platform_params + ***********************************************************************/ + +DAT_RETURN +dat_sr_parse_platform_params(DAT_OS_FILE * file, DAT_SR_CONF_ENTRY * entry) +{ + DAT_SR_TOKEN token; + + if (DAT_SUCCESS != dat_sr_get_token(file, &token)) + goto bail; + + if (DAT_SR_TOKEN_STRING != token.type) { + dat_sr_put_token(file, &token); + goto bail; + } + + entry->platform_params = token.value; + return DAT_SUCCESS; + + bail: + dat_os_dbg_print(DAT_OS_DBG_TYPE_ERROR, + " ERR: corrupt dat.conf entry field:" + " platform_params, file offset=%ld\n", ftell(file)); + return DAT_INTERNAL_ERROR; +} + +/*********************************************************************** + * Function: dat_sr_parse_eoe + ***********************************************************************/ + +DAT_RETURN dat_sr_parse_eoe(DAT_OS_FILE * file, DAT_SR_CONF_ENTRY * entry) +{ + DAT_SR_TOKEN token; + + if (DAT_SUCCESS != dat_sr_get_token(file, &token)) + goto bail; + + if ((DAT_SR_TOKEN_EOF != token.type) && + (DAT_SR_TOKEN_EOR != token.type)) { + dat_sr_put_token(file, &token); + goto bail; + } + + return DAT_SUCCESS; + + bail: + dat_os_dbg_print(DAT_OS_DBG_TYPE_ERROR, + " ERR: corrupt dat.conf entry field:" + " EOR, EOF, file offset=%ld\n", ftell(file)); + return DAT_INTERNAL_ERROR; +} + +/*********************************************************************** + * Function: dat_sr_convert_api + ***********************************************************************/ + +DAT_RETURN dat_sr_convert_api(char *str, DAT_SR_API_VERSION * api_version) +{ + int i; + int minor_i; + + if (dat_os_strlen(str) <= 0) + return DAT_INTERNAL_ERROR; + + if ('u' == str[0]) { + api_version->type = DAT_SR_API_UDAT; + } else if ('k' == str[0]) { + api_version->type = DAT_SR_API_KDAT; + } else { + return DAT_INTERNAL_ERROR; + } + + for (i = 1 /* move past initial [u|k] */ ; '\0' != str[i]; i++) { + if ('.' == str[i]) { + break; + } else if (DAT_TRUE != dat_os_isdigit(str[i])) { + return DAT_INTERNAL_ERROR; + } + } + + api_version->version.major = + (DAT_UINT32) dat_os_strtol(str + 1, NULL, 10); + + /* move past '.' */ + minor_i = ++i; + + for (; '\0' != str[i]; i++) { + if (DAT_TRUE != dat_os_isdigit(str[i])) { + return DAT_INTERNAL_ERROR; + } + } + + api_version->version.minor = + (DAT_UINT32) dat_os_strtol(str + minor_i, NULL, 10); + + if ('\0' != str[i]) { + return DAT_INTERNAL_ERROR; + } + + return DAT_SUCCESS; +} + +/*********************************************************************** + * Function: dat_sr_convert_thread_safety + ***********************************************************************/ + +static DAT_RETURN +dat_sr_convert_thread_safety(char *str, DAT_BOOLEAN * is_thread_safe) +{ + if (!dat_os_strncmp(str, + DAT_SR_TOKEN_THREADSAFE, + dat_os_strlen(DAT_SR_TOKEN_THREADSAFE))) { + *is_thread_safe = DAT_TRUE; + return DAT_SUCCESS; + } else if (!dat_os_strncmp(str, + DAT_SR_TOKEN_NONTHREADSAFE, + dat_os_strlen(DAT_SR_TOKEN_NONTHREADSAFE))) { + *is_thread_safe = DAT_FALSE; + return DAT_SUCCESS; + } else { + return DAT_INTERNAL_ERROR; + } +} + +/*********************************************************************** + * Function: dat_sr_convert_default + ***********************************************************************/ + +static DAT_RETURN dat_sr_convert_default(char *str, DAT_BOOLEAN * is_default) +{ + if (!dat_os_strncmp(str, + DAT_SR_TOKEN_DEFAULT, + dat_os_strlen(DAT_SR_TOKEN_DEFAULT))) { + *is_default = DAT_TRUE; + return DAT_SUCCESS; + } else if (!dat_os_strncmp(str, + DAT_SR_TOKEN_NONDEFAULT, + dat_os_strlen(DAT_SR_TOKEN_NONDEFAULT))) { + *is_default = DAT_FALSE; + return DAT_SUCCESS; + } else { + return DAT_INTERNAL_ERROR; + } +} + +/*********************************************************************** + * Function: dat_sr_convert_provider_version + ***********************************************************************/ + +DAT_RETURN +dat_sr_convert_provider_version(char *str, + DAT_SR_PROVIDER_VERSION * provider_version) +{ + DAT_RETURN status; + int i; + int decimal_i; + + if ((dat_os_strlen(str) <= 0) || (NULL != provider_version->id)) + return DAT_INTERNAL_ERROR; + + status = DAT_SUCCESS; + + for (i = 0; '\0' != str[i]; i++) { + if ('.' == str[i]) { + break; + } + } + + /* if no id value was found */ + if (0 == i) { + status = DAT_INTERNAL_ERROR; + goto exit; + } + + if (NULL == + (provider_version->id = dat_os_alloc(sizeof(char) * (i + 1)))) { + status = + DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); + goto exit; + } + + dat_os_strncpy(provider_version->id, str, i); + provider_version->id[i] = '\0'; + + /* move past '.' */ + decimal_i = ++i; + + for (; '\0' != str[i]; i++) { + if ('.' == str[i]) { + break; + } else if (DAT_TRUE != dat_os_isdigit(str[i])) { + status = DAT_INTERNAL_ERROR; + goto exit; + } + } + + /* if no version value was found */ + if (decimal_i == i) { + status = DAT_INTERNAL_ERROR; + goto exit; + } + + provider_version->version.major = (DAT_UINT32) + dat_os_strtol(str + decimal_i, NULL, 10); + + /* move past '.' */ + decimal_i = ++i; + + for (; '\0' != str[i]; i++) { + if (DAT_TRUE != dat_os_isdigit(str[i])) { + status = DAT_INTERNAL_ERROR; + goto exit; + } + } + + /* if no version value was found */ + if (decimal_i == i) { + status = DAT_INTERNAL_ERROR; + goto exit; + } + + provider_version->version.minor = (DAT_UINT32) + dat_os_strtol(str + decimal_i, NULL, 10); + + if ('\0' != str[i]) { + status = DAT_INTERNAL_ERROR; + goto exit; + } + + exit: + if (DAT_SUCCESS != status) { + if (NULL != provider_version->id) { + dat_os_free(provider_version->id, + sizeof(char) * + (dat_os_strlen(provider_version->id) + 1)); + provider_version->id = NULL; + } + } + + return status; +} + +/*********************************************************************** + * Function: dat_sr_get_token + ***********************************************************************/ + +DAT_RETURN dat_sr_get_token(DAT_OS_FILE * file, DAT_SR_TOKEN * token) +{ + if (NULL == g_token_stack) { + return dat_sr_read_token(file, token); + } else { + DAT_SR_STACK_NODE *top; + + top = g_token_stack; + + *token = top->token; + g_token_stack = top->next; + + dat_os_free(top, sizeof(DAT_SR_STACK_NODE)); + + return DAT_SUCCESS; + } +} + +/*********************************************************************** + * Function: dat_sr_put_token + ***********************************************************************/ + +DAT_RETURN dat_sr_put_token(DAT_OS_FILE * file, DAT_SR_TOKEN * token) +{ + DAT_SR_STACK_NODE *top; + + if (NULL == (top = dat_os_alloc(sizeof(DAT_SR_STACK_NODE)))) { + return DAT_INSUFFICIENT_RESOURCES | DAT_RESOURCE_MEMORY; + } + + top->token = *token; + top->next = g_token_stack; + g_token_stack = top; + + return DAT_SUCCESS; +} + +/*********************************************************************** + * Function: dat_sr_read_token + ***********************************************************************/ + +DAT_RETURN dat_sr_read_token(DAT_OS_FILE * file, DAT_SR_TOKEN * token) +{ + DAT_OS_FILE_POS pos; + DAT_OS_SIZE token_len; + DAT_COUNT num_escape_seq; + DAT_BOOLEAN is_quoted_str; + DAT_BOOLEAN is_prev_char_backslash; + + /* + * The DAT standard does not specify a maximum size for quoted strings. + * Therefore the tokenizer must be able to read in a token of arbitrary + * size. Instead of allocating a fixed length buffer, the tokenizer first + * scans the input a single character at a time looking for the begining + * and end of the token. Once the these positions are found, the entire + * token is read into memory. By using this algorithm,the implementation + * does not place an arbitrary maximum on the token size. + */ + + token_len = 0; + num_escape_seq = 0; + is_quoted_str = DAT_FALSE; + is_prev_char_backslash = DAT_FALSE; + + for (;;) { + DAT_OS_FILE_POS cur_pos; + int c; + + /* if looking for start of the token */ + if (0 == token_len) { + if (DAT_SUCCESS != dat_os_fgetpos(file, &cur_pos)) { + return DAT_INTERNAL_ERROR; + } + } + + c = dat_os_fgetc(file); + + /* if looking for start of the token */ + if (0 == token_len) { + if (EOF == c) { + token->type = DAT_SR_TOKEN_EOF; + token->value = NULL; + token->value_len = 0; + goto success; + } else if (DAT_SR_CHAR_NEWLINE == c) { + token->type = DAT_SR_TOKEN_EOR; + token->value = NULL; + token->value_len = 0; + goto success; + } else if (dat_os_isblank(c)) { + continue; + } else if (DAT_SR_CHAR_COMMENT == c) { + dat_sr_read_comment(file); + continue; + } else { + if (DAT_SR_CHAR_QUOTE == c) { + is_quoted_str = DAT_TRUE; + } + + pos = cur_pos; + token_len++; + } + } else { /* looking for the end of the token */ + + if (EOF == c) { + break; + } else if (DAT_SR_CHAR_NEWLINE == c) { + /* put back the newline */ + dat_os_fputc(file, c); + break; + } else if (!is_quoted_str && dat_os_isblank(c)) { + break; + } else { + token_len++; + + if ((DAT_SR_CHAR_QUOTE == c) + && !is_prev_char_backslash) { + break; + } else if ((DAT_SR_CHAR_BACKSLASH == c) + && !is_prev_char_backslash) { + is_prev_char_backslash = DAT_TRUE; + num_escape_seq++; + } else { + is_prev_char_backslash = DAT_FALSE; + } + } + } + } + + /* the token was a string */ + if (DAT_SUCCESS != dat_os_fsetpos(file, &pos)) { + return DAT_INTERNAL_ERROR; + } + + if (is_quoted_str) { + if (DAT_SUCCESS != dat_sr_read_quoted_str(file, + token, + token_len, + num_escape_seq)) { + return DAT_INTERNAL_ERROR; + } + } else { + if (DAT_SUCCESS != dat_sr_read_str(file, token, token_len)) { + return DAT_INTERNAL_ERROR; + } + } + + success: + dat_os_dbg_print(DAT_OS_DBG_TYPE_SR, + "\n" + "DAT Registry: token\n" + " type %s\n" + " value <%s>\n" + "\n", + dat_sr_type_to_str(token->type), + ((DAT_SR_TOKEN_STRING == + token->type) ? token->value : "")); + + return DAT_SUCCESS; +} + +/*********************************************************************** + * Function: dat_sr_read_str + ***********************************************************************/ + +DAT_RETURN +dat_sr_read_str(DAT_OS_FILE * file, DAT_SR_TOKEN * token, DAT_OS_SIZE token_len) +{ + token->type = DAT_SR_TOKEN_STRING; + token->value_len = sizeof(char) * (token_len + 1); /* +1 for null termination */ + if (NULL == (token->value = dat_os_alloc(token->value_len))) { + return DAT_INSUFFICIENT_RESOURCES | DAT_RESOURCE_MEMORY; + } + + if (token_len != dat_os_fread(file, token->value, token_len)) { + dat_os_free(token->value, token->value_len); + token->value = NULL; + + return DAT_INTERNAL_ERROR; + } + + token->value[token->value_len - 1] = '\0'; + + return DAT_SUCCESS; +} + +/*********************************************************************** + * Function: dat_sr_read_quoted_str + ***********************************************************************/ + +DAT_RETURN +dat_sr_read_quoted_str(DAT_OS_FILE * file, + DAT_SR_TOKEN * token, + DAT_OS_SIZE token_len, DAT_COUNT num_escape_seq) +{ + DAT_OS_SIZE str_len; + DAT_OS_SIZE i; + DAT_OS_SIZE j; + int c; + DAT_RETURN status; + DAT_BOOLEAN is_prev_char_backslash; + + str_len = token_len - 2; /* minus 2 " characters */ + is_prev_char_backslash = DAT_FALSE; + status = DAT_SUCCESS; + + token->type = DAT_SR_TOKEN_STRING; + /* +1 for null termination */ + token->value_len = sizeof(char) * (str_len - num_escape_seq + 1); + + if (NULL == (token->value = dat_os_alloc(token->value_len))) { + status = DAT_INSUFFICIENT_RESOURCES | DAT_RESOURCE_MEMORY; + goto exit; + } + + /* throw away " */ + if (DAT_SR_CHAR_QUOTE != dat_os_fgetc(file)) { + status = DAT_INTERNAL_ERROR; + goto exit; + } + + for (i = 0, j = 0; i < str_len; i++) { + c = dat_os_fgetc(file); + + if (EOF == c) { + status = DAT_INTERNAL_ERROR; + goto exit; + } else if ((DAT_SR_CHAR_BACKSLASH == c) + && !is_prev_char_backslash) { + is_prev_char_backslash = DAT_TRUE; + } else { + token->value[j] = (char)c; + j++; + + is_prev_char_backslash = DAT_FALSE; + } + } + + /* throw away " */ + if (DAT_SR_CHAR_QUOTE != dat_os_fgetc(file)) { + status = DAT_INTERNAL_ERROR; + goto exit; + } + + token->value[token->value_len - 1] = '\0'; + + exit: + if (DAT_SUCCESS != status) { + if (NULL != token->value) { + dat_os_free(token->value, token->value_len); + token->value = NULL; + } + } + + return status; +} + +/*********************************************************************** + * Function: dat_sr_read_comment + ***********************************************************************/ + +void dat_sr_read_comment(DAT_OS_FILE * file) +{ + int c; + + /* read up to an EOR or EOF to move past the comment */ + do { + c = dat_os_fgetc(file); + } while ((DAT_SR_CHAR_NEWLINE != c) && (EOF != c)); + + /* put back the newline */ + dat_os_ungetc(file, c); +} diff --git a/branches/WOF2-3/ulp/dapl2/dat/udat/udat_sr_parser.h b/branches/WOF2-3/ulp/dapl2/dat/udat/udat_sr_parser.h new file mode 100644 index 00000000..82a027a7 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dat/udat/udat_sr_parser.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dat_sr_parser.h + * + * PURPOSE: static registry (SR) parser inteface declarations + * + * $Id: udat_sr_parser.h,v 1.4 2005/03/24 05:58:36 jlentini Exp $ + **********************************************************************/ + +#ifndef _DAT_SR_PARSER_H_ +#define _DAT_SR_PARSER_H_ + + +#include "dat_osd.h" + + +/********************************************************************* + * * + * Function Declarations * + * * + *********************************************************************/ + +/* + * The static registry exports the same interface regardless of + * platform. The particular implementation of dat_sr_load() is + * found with other platform dependent sources. + */ + +extern DAT_RETURN +dat_sr_load (void); + + +#endif /* _DAT_SR_PARSER_H_ */ diff --git a/branches/WOF2-3/ulp/dapl2/dat/udat/windows/dat_osd.c b/branches/WOF2-3/ulp/dapl2/dat/udat/windows/dat_osd.c new file mode 100644 index 00000000..37f30876 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dat/udat/windows/dat_osd.c @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * MODULE: dat_osd.c + * + * PURPOSE: Operating System Dependent layer + * Description: + * Provide OS dependent functions with a canonical DAPL + * interface. Designed to be portable and hide OS specific quirks + * of common functions. + * + * $Id: dat_osd.c 33 2005-07-11 19:51:17Z ftillier $ + **********************************************************************/ + +#include "dat_osd.h" +#include "dat_init.h" + + +/********************************************************************* + * * + * Constants * + * * + *********************************************************************/ + +#define DAT_DBG_LEVEL_ENV "DAT_DBG_LEVEL" +#define DAT_DBG_DEST_ENV "DAT_DBG_DEST" + + +/********************************************************************* + * * + * Enumerations * + * * + *********************************************************************/ + +typedef int DAT_OS_DBG_DEST; + +typedef enum +{ + DAT_OS_DBG_DEST_STDOUT = 0x1, +} DAT_OS_DBG_DEST_TYPE; + + +/********************************************************************* + * * + * Global Variables * + * * + *********************************************************************/ + +static DAT_OS_DBG_TYPE_VAL g_dbg_type = DAT_OS_DBG_TYPE_ERROR; +static DAT_OS_DBG_DEST g_dbg_dest = DAT_OS_DBG_DEST_STDOUT; + + +/*********************************************************************** + * Function: dat_os_dbg_set_level + ***********************************************************************/ + +void +dat_os_dbg_init ( void ) +{ + char *dbg_type; + char *dbg_dest; + + dbg_type = dat_os_getenv (DAT_DBG_LEVEL_ENV); + if ( dbg_type != NULL ) + { + g_dbg_type = dat_os_strtol(dbg_type, NULL, 0); + } + + dbg_dest = dat_os_getenv (DAT_DBG_DEST_ENV); + if ( dbg_dest != NULL ) + { + g_dbg_dest = dat_os_strtol(dbg_dest, NULL, 0); + } +} + + +/*********************************************************************** + * Function: dat_os_dbg_print + ***********************************************************************/ + +void +dat_os_dbg_print ( + DAT_OS_DBG_TYPE_VAL type, + const char * fmt, + ...) +{ + if ( (DAT_OS_DBG_TYPE_ERROR == type) || (type & g_dbg_type) ) + { + va_list args; + + if ( DAT_OS_DBG_DEST_STDOUT & g_dbg_dest ) + { + va_start(args, fmt); + vfprintf(stdout, fmt, args); + fflush(stdout); + va_end(args); + } + /* no syslog() susport in Windows */ + } +} + +HANDLE heap; + +BOOL APIENTRY +DllMain( + IN HINSTANCE h_module, + IN DWORD ul_reason_for_call, + IN LPVOID lp_reserved ) +{ + extern DAT_BOOLEAN udat_check_state ( void ); + + UNREFERENCED_PARAMETER( lp_reserved ); + + switch( ul_reason_for_call ) + { + case DLL_PROCESS_ATTACH: + heap = HeapCreate(0, 0, 0); + if (heap == NULL) + return FALSE; + DisableThreadLibraryCalls( h_module ); + udat_check_state(); + break; + + case DLL_PROCESS_DETACH: + dat_fini(); + HeapDestroy(heap); + } + + return TRUE; +} + +char * +dat_os_library_error(void) +{ + DWORD rc; + LPVOID lpMsgBuf; + + if (errno == 0) + return NULL; + + // consider formatmessage()? + rc = GetLastError(); + + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + rc, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &lpMsgBuf, + 0, NULL ); + + //LocalFree(lpMsgBuf); error condition - will exit anyway. + + return (char*)lpMsgBuf; +} + +#ifndef INLINE_LIB_LOAD + +DAT_RETURN +dat_os_library_load ( const char *library_path, + DAT_OS_LIBRARY_HANDLE *library_handle_ptr ) +{ + DAT_OS_LIBRARY_HANDLE library_handle; + DAT_RETURN rc = DAT_SUCCESS; + + if ( NULL != (library_handle = LoadLibrary(library_path)) ) + { + if ( NULL != library_handle_ptr ) + { + *library_handle_ptr = library_handle; + } + } + else + { + dat_os_dbg_print(DAT_OS_DBG_TYPE_ERROR, + "DAT: library %s load failure\n",library_path); + rc = DAT_INTERNAL_ERROR; + } + return rc; +} +#endif diff --git a/branches/WOF2-3/ulp/dapl2/dat/udat/windows/dat_osd.h b/branches/WOF2-3/ulp/dapl2/dat/udat/windows/dat_osd.h new file mode 100644 index 00000000..e661ba32 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dat/udat/windows/dat_osd.h @@ -0,0 +1,430 @@ +/* + * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under either one of the following two licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * OR + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * Licensee has the right to choose either one of the above two licenses. + * + * Redistributions of source code must retain both the above copyright + * notice and either one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, either one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +/********************************************************************** + * + * HEADER: dat_osd.h + * + * PURPOSE: Operating System Dependent layer + * Description: + * Provide OS dependent data structures & functions with + * a canonical DAPL interface. Designed to be portable + * and hide OS specific quirks of common functions. + * + * $Id: dat_osd.h 33 2005-07-11 19:51:17Z ftillier $ + **********************************************************************/ + +#ifndef _DAT_OSD_H_ +#define _DAT_OSD_H_ + +/* + * This file is defined for Windows systems only, including it on any + * other build will cause an error + */ +#if !defined(WIN32) && !defined(WIN64) +#error "UNDEFINED OS TYPE" +#endif /* WIN32/64 */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include <_errno.h> + +#ifndef STATIC +#define STATIC static +#endif /* STATIC */ + +#ifndef INLINE +#define INLINE __inline +#endif /* INLINE */ + +#ifndef __inline__ +#define __inline__ __inline +#endif /* __inline */ + +/********************************************************************* + * * + * Debuging * + * * + *********************************************************************/ + +#define dat_os_assert(expr) assert(expr) + +typedef int DAT_OS_DBG_TYPE_VAL; + +typedef enum +{ + DAT_OS_DBG_TYPE_ERROR = 0x1, + DAT_OS_DBG_TYPE_GENERIC = 0x2, + DAT_OS_DBG_TYPE_SR = 0x4, + DAT_OS_DBG_TYPE_DR = 0x8, + DAT_OS_DBG_TYPE_PROVIDER_API = 0x10, + DAT_OS_DBG_TYPE_CONSUMER_API = 0x20, + DAT_OS_DBG_TYPE_ALL = 0xff +} DAT_OS_DBG_TYPE_TYPE; + +extern void +dat_os_dbg_init ( void ); + +extern void +dat_os_dbg_print ( + DAT_OS_DBG_TYPE_VAL type, + const char * fmt, + ...); + + +/********************************************************************* + * * + * Utility Functions * + * * + *********************************************************************/ + +#define DAT_ERROR(Type,SubType) ((DAT_RETURN)(DAT_CLASS_ERROR | Type | SubType)) + +typedef size_t DAT_OS_SIZE; +typedef HMODULE DAT_OS_LIBRARY_HANDLE; + +#ifdef INLINE_LIB_LOAD + +STATIC INLINE DAT_RETURN +dat_os_library_load ( + const char *library_path, + DAT_OS_LIBRARY_HANDLE *library_handle_ptr) +{ + DAT_OS_LIBRARY_HANDLE library_handle; + + if ( NULL != (library_handle = LoadLibrary(library_path)) ) + { + if ( NULL != library_handle_ptr ) + { + *library_handle_ptr = library_handle; + } + return DAT_SUCCESS; + } + else + { + dat_os_dbg_print(DAT_OS_DBG_TYPE_ERROR, + "DAT: library load failure\n"); + return DAT_INTERNAL_ERROR; + } +} +#else + +DAT_RETURN +dat_os_library_load ( + const char *library_path, + DAT_OS_LIBRARY_HANDLE *library_handle_ptr); + +#endif + +extern char *dat_os_library_error(void); + +#ifdef WIN32_LEAN_AND_MEAN +#define dat_os_library_sym GetProcAddress +#else +STATIC INLINE +dat_os_library_sym ( + DAT_OS_LIBRARY_HANDLE library_handle, + const char *sym) +{ + return GetProcAddress(library_handle, (LPCSTR)sym); +} +#endif /* WIN32_LEAN_AND_MEAN */ + +STATIC INLINE DAT_RETURN +dat_os_library_unload ( + const DAT_OS_LIBRARY_HANDLE library_handle) +{ + if ( 0 == FreeLibrary(library_handle) ) + { + return DAT_INTERNAL_ERROR; + } + else + { + return DAT_SUCCESS; + } +} + +STATIC INLINE char * +dat_os_getenv ( + const char *name) +{ + return getenv(name); +} + +STATIC INLINE long int +dat_os_strtol ( + const char *nptr, + char **endptr, + int base) +{ + return strtol(nptr, endptr, base); +} + +STATIC INLINE DAT_OS_SIZE +dat_os_strlen ( + const char *s ) +{ + return strlen(s); +} + +STATIC INLINE int +dat_os_strncmp ( + const char *s1, + const char *s2, + DAT_OS_SIZE n) +{ + return strncmp(s1, s2, n); +} + +STATIC INLINE void * +dat_os_strncpy ( + char *dest, + const char *src, + DAT_OS_SIZE len) +{ + return strncpy (dest, src, len); +} + +STATIC INLINE DAT_BOOLEAN +dat_os_isblank( + int c) +{ + if ( (' ' == c) || ('\t' == c) ) { return DAT_TRUE; } + else { return DAT_FALSE; } +} + +STATIC INLINE DAT_BOOLEAN +dat_os_isdigit( + int c) +{ + if ( isdigit(c) ) { return DAT_TRUE; } + else { return DAT_FALSE; } +} + +STATIC INLINE void +dat_os_usleep( + unsigned long usec) +{ + Sleep(usec/1000); +} + + +/********************************************************************* + * * + * Memory Functions * + * * + *********************************************************************/ + +extern HANDLE heap; + +STATIC INLINE void * +dat_os_alloc ( + int size) +{ + return HeapAlloc(heap, 0, size); +} + +STATIC INLINE void +dat_os_free ( + void *ptr, + int size) +{ + UNREFERENCED_PARAMETER(size); + HeapFree(heap, 0, ptr); +} + +STATIC INLINE void * +dat_os_memset (void *loc, int c, DAT_OS_SIZE size) +{ + return memset (loc, c, size); +} + + +/********************************************************************* + * * + * File I/O * + * * + *********************************************************************/ + +typedef FILE DAT_OS_FILE; +typedef fpos_t DAT_OS_FILE_POS; + + +STATIC INLINE DAT_OS_FILE * +dat_os_fopen ( + const char * path) +{ + /* always open files in read only mode*/ + return fopen(path, "r"); +} + +STATIC INLINE DAT_RETURN +dat_os_fgetpos ( + DAT_OS_FILE *file, + DAT_OS_FILE_POS *pos) +{ + if ( 0 == fgetpos(file, pos) ) + { + return DAT_SUCCESS; + } + else + { + return DAT_INTERNAL_ERROR; + } +} + +STATIC INLINE DAT_RETURN +dat_os_fsetpos ( + DAT_OS_FILE *file, + DAT_OS_FILE_POS *pos) +{ + if ( 0 == fsetpos(file, pos) ) + { + return DAT_SUCCESS; + } + else + { + return DAT_INTERNAL_ERROR; + } +} + +/* dat_os_fgetc() returns EOF on error or end of file. */ +STATIC INLINE int +dat_os_fgetc ( + DAT_OS_FILE *file) +{ + return fgetc(file); +} + +/* dat_os_ungetc() returns EOF on error or char 'c'. + * Push char 'c' back into specified stream for subsequent read. + */ +STATIC INLINE int +dat_os_ungetc ( + DAT_OS_FILE *file, int c) +{ + return ungetc(c, file); +} + +/* dat_os_fputc() returns EOF on error or char 'c'. */ +STATIC INLINE int +dat_os_fputc ( + DAT_OS_FILE *file, int c) +{ + return fputc(c, file); +} + +/* dat_os_fread returns the number of bytes read from the file. */ +STATIC INLINE DAT_OS_SIZE +dat_os_fread ( + DAT_OS_FILE *file, + char *buf, + DAT_OS_SIZE len) +{ + return fread(buf, sizeof(char), len, file); +} + +STATIC INLINE DAT_RETURN +dat_os_fclose ( + DAT_OS_FILE *file) +{ + if ( 0 == fclose(file) ) + { + return DAT_SUCCESS; + } + else + { + return DAT_INTERNAL_ERROR; + } +} + + +/********************************************************************* + * * + * Locks * + * * + *********************************************************************/ + +typedef HANDLE DAT_OS_LOCK; + +/* lock functions */ +STATIC INLINE DAT_RETURN +dat_os_lock_init ( + IN DAT_OS_LOCK *m) +{ + *m = CreateMutex (0, FALSE, 0); + if (*(HANDLE *)m == NULL) + { + return DAT_INTERNAL_ERROR; + } + return DAT_SUCCESS; +} + +STATIC INLINE DAT_RETURN +dat_os_lock ( + IN DAT_OS_LOCK *m) +{ + WaitForSingleObject(*m, INFINITE); + + return DAT_SUCCESS; +} + +STATIC INLINE DAT_RETURN +dat_os_unlock ( + IN DAT_OS_LOCK *m) +{ + ReleaseMutex (*m); + + return DAT_SUCCESS; +} + +STATIC INLINE DAT_RETURN +dat_os_lock_destroy ( + IN DAT_OS_LOCK *m) +{ + CloseHandle (*m); + + return DAT_SUCCESS; +} + + +#endif /* _DAT_OSD_H_ */ + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ + diff --git a/branches/WOF2-3/ulp/dapl2/dat/udat/windows/dat_osd_sr.h b/branches/WOF2-3/ulp/dapl2/dat/udat/windows/dat_osd_sr.h new file mode 100644 index 00000000..e64a743c --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dat/udat/windows/dat_osd_sr.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2002, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under the terms of the "IBM Common Public + * License 1.0" a copy of which is in the file LICENSE.txt in the + * root directory. The license is also available from the Open Source + * Initiative, see http://www.opensource.org/licenses/ibmpl.html. + * + */ + +/********************************************************************** + * + * MODULE: dat_osd_sr.h + * + * PURPOSE: static registry (SR) platform specific inteface declarations + * + * $Id: dat_osd_sr.h 33 2005-07-11 19:51:17Z ftillier $ + **********************************************************************/ + +#ifndef _DAT_OSD_SR_H_ +#define _DAT_OSD_SR_H_ + + +#include "dat_osd.h" + + +/********************************************************************* + * * + * Function Declarations * + * * + *********************************************************************/ + +/* + * The static registry exports the same interface regardless of + * platform. The particular implementation of dat_sr_load() is + * found with other platform dependent sources. + */ + +extern DAT_RETURN +dat_sr_load (void); + + +#endif /* _DAT_OSD_SR_H_ */ diff --git a/branches/WOF2-3/ulp/dapl2/dirs b/branches/WOF2-3/ulp/dapl2/dirs new file mode 100644 index 00000000..21aa2261 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/dirs @@ -0,0 +1,4 @@ +DIRS=\ + dat \ + dapl \ + test diff --git a/branches/WOF2-3/ulp/dapl2/doc/dapl_coding_style.txt b/branches/WOF2-3/ulp/dapl2/doc/dapl_coding_style.txt new file mode 100644 index 00000000..74e44f1d --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/doc/dapl_coding_style.txt @@ -0,0 +1,264 @@ +####################################################################### +# # +# DAPL Coding style reference # +# # +# Steve Sears # +# sjs2 at users.sourceforge.net # +# # +# 12/13/2002 # +# # +####################################################################### + +====================================================================== +Introduction +====================================================================== + +The purpose of this document is to establish the coding style adopted by +the team implementing the DAPL reference implementation. The rules +presented here were arrived at by consensus, they are intended to +provide consistency of implementation and make it intuitive to work with +the source code. + +====================================================================== +Source code conventions +====================================================================== + +1. Brackets + + Brackets should follow C99 conventions and declare a block. The + following convention is followed: + + if (x) + { + statement; + statement; + } + + The following bracket styles are to be avoided: + + K&R style: + + if (x) { /* DON'T DO THIS */ + statement; + } + + GNU style: + + if (x) /* DON'T DO THIS */ + { + statement; + } + + Statements are always indented from brackets. + + Brackets are always used for any statement in order to avoid dangling + clause bugs. E.g. + + RIGHT: + if ( x ) + { + j = 0; + } + + WRONG: + if ( x ) + j = 0; + +2. Indents + + Indents are always 4, tabs 8. A tab may serve as a double + indent. Many of the reference implementation file have an emacs + format statement at the bottom. + +3. Comments + + Comments are always full C style comments, and never C++ + style. Comments take the form: + + /* + * comment + */ + +4. Variable Declarations + + Variables are always declared on their own line, we do not declare + multiple variables on the same line. + + Variables are never initialized in their declaration, they are + initialized in the body of the code. + +5. Function Declarations + + The return type of a function is declared on a separate line from the + function name. + + Parameters each receive a line and should be clearly labeled as IN + or OUT or INOUT. Parameter declarations begin one tab stop from the + margin. + + For example: + + DAT_RETURN + dapl_function ( + IN DAT_IA_HANDLE ia_handle, + OUT DAT_EP_HANDLE *ep_handle ) + { + ... function body ... + } + +5. White space + + Don't be afraid of white space, the goal is to make the code readable + and maintainable. We use white space: + + - One space following function names or conditional expressions. It + might be better to say one space before any open parenthesis. + + - Suggestion: One space following open parens and one space before + closing parens. Not all of the code follows this convention, use + your best judgment. + + Example: + + foo ( x1, x2 ); + +6. Conditional code + + We generally try to avoid conditional compilation, but there are + certain places where it cannot be avoided. Whenever possible, move + the conditional code into a macro or otherwise work to put it into an + include file that can be used by the platform (e.g. Linux or Windows + osd files), or by the underlying provider (e.g. IBM Torrent or + Mellanox Tavor). + + Conditionals should be descriptive, and the associated #endif should + contain the declaration. E.g. + + #ifdef THIS_IS_AN_EXAMPLE + + /* code */ + + #endif /* THIS_IS_AN_EXAMPLE */ + + You may change the ending comment if a #else clause is present. E.g. + + #ifdef THIS_IS_AN_EXAMPLE + /* code */ + + #else + /* other code */ + + #endif /* !THIS_IS_AN_EXAMPLE */ + + +====================================================================== +Naming conventions +====================================================================== + +1. Variable Names + + Variable names for DAPL data structures generally follow their type + and should be the same in all source files. A few examples: + + Handles + DAT_IA_HANDLE ia_handle + DAT_EP_HANDLE ep_handle + + Pointers + + DAPL_IA *ia_ptr; + DAPL_EP *ep_ptr; + +2. Return Code Names + + There are at least two different subsystems supported in the DAPL + reference implementation. In order to bring sanity to the error + space, return codes are named and used for their appropriate + subsystem. E.g. + + ib_status: InfiniBand status return code + dat_status: DAT/DAPL return code + +3. Function Names + + Function names describe the scope to which they apply. There are + essentially three names in the reference implementation: + + dapl_* Name of an exported function visible externally. + These functions have a 1 to 1 correspondence to + their DAT counterparts. + + dapls_* Name of a function that is called from more than one + source file, but is limited to a subsystem. + + dapli_* Local function, internal to a file. Should always be + of type STATIC. + + +====================================================================== +Util files +====================================================================== + +The Reference implementation is organized such that a single, exported +function is located in its' own file. If you are trying to find the DAPL +function to create and End Point, it will be found in the dapl version +of the DAT function in the spec. E.g. + +dapl_ep_create() is found in dapl_ep_create.c +dapl_evd_free() is found in dapl_evd_free.c + +It is often the case that the implementation must interact with data +structures or call into other subsystems. All utility functions for a +subsystem are gathered into the appropriate "util" file. + +For example, dapl_ep_create must allocate a DAPL_EP structure. The +routine to allocate and initialize memory is found in the +dapl_ep_util.c file and is named dapl_ep_alloc(). Appropriate routines +for the util file are + + - Alloc + - Free + - Assign defaults + - linking routines + - Check restrictions + - Perform operations on a data structure. + +The idea of a util file is an object oriented idea for a non OO +language. It encourages a clean implementation. + +For each util.c file, there is also a util.h file. The purpose of the +util include file is to define the prototypes for the util file, and to +supply any local flags or values necessary to the subsystem. + +====================================================================== +Include files, prototypes +====================================================================== + +Include files are organized according to subsystem and/or OS +platform. The include directory contains files that are global to the +entire source set. Prototypes are found in include files that pertain to +the data they support. + +Commenting on the DAPL Reference Implementation tree: + + dapl/common + dapl/include + Contains global dapl data structures, symbols, and + prototypes + dapl/tavor + Contains tavor prototypes and symbols + dapl/torrent + Contains torrent prototypes and symbols + dapl/udapl + Contains include files to support udapl specific files + dapl/udapl/linux + Contains osd files for Linux + dapl/udapl/windows + Contains osd files for Windows + +For completeness, the dat files described by the DAT Specification are +in the tree under the dat/ subdirectory, + + dat/include/dat/ + + diff --git a/branches/WOF2-3/ulp/dapl2/doc/dapl_end_point_design.txt b/branches/WOF2-3/ulp/dapl2/doc/dapl_end_point_design.txt new file mode 100644 index 00000000..d351d961 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/doc/dapl_end_point_design.txt @@ -0,0 +1,1129 @@ +####################################################################### +# # +# DAPL End Point Management Design # +# # +# Steve Sears # +# sjs2 at users.sourceforge.net # +# # +# 10/04/2002 # +# Updates # +# 02/06/04 # +# 10/07/04 # +# # +####################################################################### + + +====================================================================== +Referenced Documents +====================================================================== + +uDAPL: User Direct Access Programming Library, Version 1.1. Published +05/08/2003. http://www.datcollaborative.org/uDAPL_050803.pdf. +Referred to in this document as the "DAT Specification". + +InfiniBand Access Application Programming Interface Specification, +Version 1.2, 4/15/2002. In DAPL SourceForge repository at +doc/api/access_api.pdf. Referred to in this document as the "IBM +Access API Specification". + +InfiniBand Architecture Specification Volume 1, Release 1.0.a Referred +to in this document at the "InfiniBand Spec". + +====================================================================== +Introduction to EndPoints +====================================================================== + +An EndPoint is the fundamental channel abstraction for the DAT API. An +application communicates and exchanges data using an EndPoint. Most of +the time EndPoints are explicitly allocated, but there is an exception +whereby a connection event can yield an EndPoint as a side effect; this +is not supported by all transports or implementations, but it is +supported in the InfiniBand reference implementation. + +Each DAT API function is implemented in a file named + + dapl_.c + +There is a simple mapping provided by the dat library that maps dat_* to +dapl_*. For example, dat_pz_create is implemented in dapl_pz_create.c. +Other examples: + + DAT DAPL Found in + ------------ --------------- ------------------ + dat_ep_create dapl_ep_create dapl_ep_create.c + dat_ep_query dapl_ep_query dapl_ep_query.c + +There are very few exceptions to this naming convention, the Reference +Implementation tried to be consistent. + +There are also dapl__util.{h,c} files for each object. For +example, there are dapl_pz_util.h and dapl_pz_util.c files which contain +common helper functions specific to the 'pz' subsystem. The use of util +files follows the convention used elsewhere in the DAPL reference +implementation. These files contain common object creation and +destruction code, link list manipulation, other helper functions. + +This implementation has a simple naming convention designed to alert +someone reading the source code to the nature and scope of a +function. The convention is in the function name, such that: + + dapl_ Primary entry from a dat_ function, e.g. + dapl_ep_create(), which mirrors dat_ep_create(). + dapls_ The 's' restricts it to the subsystem, e.g. the + 'ep' subsystem. dapls_ functions are not exposed + externally, but are internal to dapl. + dapli_ The 'i' restricts the function to the file where it + is declared. These functions are always 'static' C + functions. + +This convention is not followed as consistently as we would like, but is +common in the reference implementation. + +1. End Points (EPs) +------------------------- + +DAPL End Points provide a channel abstraction necessary to transmit and +receive data. EPs interact with Service Points, either Public Service +Points or Reserved Service Points, to establish a connection from one +provider to another. + +The primary EP entry points in the DAT API as they relate to DAPL are +listed in the following table: + + dat_ep_create + dat_ep_query + dat_ep_modify + dat_ep_connect + dat_ep_dup_connect + dat_ep_disconnect + dat_ep_post_send + dat_ep_post_recv + dat_ep_post_rdma_read + dat_ep_post_rdma_write + dat_ep_get_status + dat_ep_reset + dat_ep_free + +Additionally, the following connection functions interact with +EndPoints: + dat_psp_create + dat_psp_query + dat_psp_free + dat_rsp_create + dat_rsp_query + dat_rsp_free + dat_cr_accept + dat_cr_reject + dat_cr_query + dat_cr_handoff + +The reference implementation maps the EndPoint abstraction onto an +InfiniBand Queue Pair (QP). + +The DAPL_EP structure is used to maintain the state and components of +the EP object and the underlying QP. As will be explained below, keeping +track of the QP state is critical for successful operation. Access to +the DAPL_EP fields are done atomically. + + +====================================================================== +Goals +====================================================================== + +Initial goals +------------- +-- Implement all of the dat_ep_* calls described in the DAT + Specification. + +-- Implement connection calls described in the DAT Specification with + the following exception: + - dat_cr_handoff. This is best done with kernel mediation, and is + therefore out of scope for the reference implementation. + +-- The implementation should be as portable as possible, to facilitate + HCA Vendors efforts to implement vendor-specific versions of DAPL. + +-- The implementation must be able to work during ongoing development + of provider software agents, drivers, etc. + +Later goals +----------- +-- Examine various possible performance optimizations. This document + lists potential performance improvements, but the specific + performance improvements implemented should be guided by customer + requirements. + +============================================ +Requirements, constraints, and design inputs +============================================ + +The EndPoint is the base channel abstraction. An Endpoint must be +established before data can be exchanged with a remote node. The +EndPoint is mapped to the underlying InfiniBand QP channel abstraction. +When a connection is initiated, the InfiniBand Connection Manager will +be solicited. The implementation is constrained by the capabilities and +behavior of the underlying InfiniBand facilities. + +Note that transports other than InfiniBand may not need to rely on +Connection Managers or other infrastructure, this is an artifact of +this transport. + +An EP is not an exact match to an InfiniBand QP, the differences +introduce constraints that are not obvious. There are three primary +areas of conflict between the DAPL and InfiniBand models: + +1) EP and QP creation differences +2) Provider provided EPs on passive side of connections +3) Connection timeouts + +-- EP and QP creation + +The most obvious difference between an EP and a QP is the presence of a +memory handle when the object is created. InfiniBand requires a +Protection Domain (PD) be specified when a QP is created; in the DAPL +world, a Protection Zone (PZ) maps to an InfiniBand Protection Domain. +DAPL does not require a PZ to be present when an EP is created, and that +introduces two problems: + +1) If a PZ is NULL when an EP is created, a QP will not be bound to + the EP until dat_ep_modify() is used to assign it later. A PZ is + required before RECV requests can be posted and before a connection + can be established. + +2) If a DAPL user changes the PZ on an EP before it is connected, + DAPL must release the current QP and create a new one with a + new Protection Domain. + +-- Provider provided EPs on connection + +The second area where the DAPL and IB models conflict is a direct result +of the requirement to specify a Protection Domain when a QP is created. + +DAPL allows a PSP to be created in such a way that an EP will +automatically be provided to the user when a connection occurs. This is +not critical to the DAPL model but in fact does provide some convenience +to the user. InfiniBand provides a similar mechanism, but with an +important difference: InfiniBand requires the user to supply the +Protection Domain for the passive connection endpoint that will be +supplied to all QPs created as a result of connection requests; DAPL +mandates a NULL PZ and requires the user to change the PZ before using +the EP. + +The reference implementation creates an 'empty' EP when the user +specifies the DAT_PSP_PROVIDER flag; it is empty in the sense that a QP +is not attached to the EP. Before the user can dat_cr_accept the +connection, the EP must be modified to have a PZ bound to it, which in +turn will cause a QP to be bound to the EP. + +To keep track of the current state of the EP, the DAPL_EP structure +has a qp_state field. The type of this field is specific to the +provider and the states are provider-specified states for a particular +transport, with the addition of a single state from dapl: +DAPL_QP_STATE_UNATTACHED, indicating that no QP has been bound to the +EP. The qp_state field is an open enumerator, containing a single DAPL +state in addition states specified by the provider. +DAPL_QP_STATE_UNATTACHED is randomly defined to be 0xFFF0, a +value selected strictly because it has the property that it will not +collide with provider states; if this is not true, this value must be +changed such that it is unique. + +The common layer of DAPL only looks at this single value for qp_state, +it cannot be aware of states that are unique to the provider. However, +the provider layer is free to update this field and may use it as a +cache for current QP state. The field must be updated when a QP (or +other endpoint resource) is bound to the EP. + +DAPL 1.2 provides DAT level states that will make this obsolete, but it +exists in pre DAPL 1.2 code. + + +-- Connection Timeouts + +The third difference in the DAPL and InfiniBand models has to do with +timeouts on connections. InfiniBand does not provide a way to specify a +connection timeout, so it will wait indefinitely for a connection to +occur. dat_ep_connect supports a timeout value providing the user with +control over how long they are willing to wait for a connection to +occur. + +DAPL maintains a timer thread to watch over pending connections. A +shared timer queue has a sorted list of timeout values. If a timeout +is requested, dapl_ep_connect() will invoke dapls_timer_set(), which +will add a timer record to the sorted list of timeouts. The timeout +thread is started lazily: that is, it isn't started until a timeout is +requested. Once a timeout has been requested, the thread will continue +to exist until the application terminates. + +The timer record is actually a part of the DAPL_EP structure, so there +are no extra memory allocations required for timeouts. dapls_timer_set() +will initialize the timer record and insert it into the sorted queue at +the appropriate place. If this is the first record, or is inserted +before the first record (which will be the 'next' timeout to expire), +the timer thread will be awakened so it can recalculate how long it must +sleep until the timeout occurs. + +When a timeout does occur, the timeout code will cancel the connection +request by invoking the provider routine dapls_ib_disconnect_clean(). +This allows the software module with explicit knowledge of the provider +to take appropriate action and cancel the connection attempt. As a side +effect, the EP will be placed into the UNCONNECTED state, and the QP +will be in the ERROR state. A side effect of this state change is that +all DTOs will be flushed. The provider must support a mechanism to +completely cancel a connection request. + + +====================================================================== +DAPL EP Subsystem Design +====================================================================== + +In section 6.5.1 of the DAT Specification there is a UML state +transition diagram for an EndPoint which goes over the transitions and +states during the lifetime of an EP. It is nearly impossible to read. +The reference implementation is faithful to the DAT Spec and is +believed to be correct. + +This description of the EP will follow from creation to connection to +termination. It will also discuss the source code organization as this +is part of the design expression. + +-- EP and QP creation + +The preamble to creating an EP requires us to verify the attributes +specified by the user. If a user were to specify max_recv_dtos as 0, for +example, the EP would not be useful in any regard. If the user does not +provide EP attrs, the DAPL layer will supply a set of common defaults +resulting in a reasonable EP. The defaults are set up in +dapli_ep_default_attrs(), and the default values are given at the top of +dapl_ep_util.c. Non-InfiniBand transports will want to examine these +values to make sure they are 'reasonable'. This simplistic mechanism may +change in the future. + +A number of handles are bound to the EP, so a reference count is taken +on each of them. All reference counts in the DAPL system are incremented +or decremented using atomic operations; it is important to always use +the OS dependent atomic routines and not substitute a lock, as it will +not be observed elsewhere in the system and will have unpredictable +results. + +Reference counts are taken if there are non NULL values on any of: + pz_handle + connect_evd_handle + recv_evd_handle + request_evd_handle + +The purpose of reference counts should be obvious: to prevent premature +release of resources that are still being used. + +As has been discussed above, each EP is bound to a QP before it can be +connected. If a valid PZ is provided at creation time then a QP is bound +to the EP immediately. If the user later uses ep_modify() to change the +PZ, the QP will be destroyed and a new one created with the appropriate +Protection Domain. + +Finally, an EP is an IA resource and is linked onto the EP chain of the +superior IA. EPs linked onto an IA are assumed to be complete, so this +is the final step of EP creation. + +After an EP is created, the ep_state will be DAT_EP_STATE_UNCONNECTED +and the qp_state will either be DAPL_QP_STATE_UNATTACHED or assigned by +the provider layer (e.g.IB_QP_STATE_INIT). The qp_state indicates the QP +binding and the current state of the QP. + +A qp_state of DAPL_QP_STATE_UNATTACHED indicates there is no QP bound +to this EP. This is a result of a NULL PZ when dat_ep_create() was +invoked, and which has been explained in detail above. The user must +call dat_ep_modify() and install a valid PZ before the EP can be used. + +When an InfiniBand QP is created it is in the RESET state, which is +specified in the InfiniBand Spec, section 10.3. However, DAPL creates +the EP in the UNCONNECTED state and requires an unconnected EP to be +able to queue RECV requests before a connection occurs. The InfiniBand +spec allows RECV requests to be queued on an QP if the QP is in the INIT +state, so after creating a QP the DAPL provider code must transition it +to the INIT state. + +There is a mapping between the DAPL EP state and the InfiniBand QP +state. DAPL_QP_STATE_UNATTACHED indicates the underlying QP is in the +INIT state. This is critical: RECV DTOs can be posted on an EP in the +UNATTACHED state, so the underlying QP must be in the appropriate state +to allow this to happen. + +There is an obvious design tradeoff in transitioning the QP +state. Immediately moving the state to INIT takes extra time at creation +but allows immediate posting of RECV operations; however, it will +involve a more complex tear down procedure if the QP must be replaced as +a side effect of a dat_ep_modify operation. The alternative would be to +delay transitioning the QP to INIT until a post operation is invoked, +but that requires a run time check for every post operation. This design +assumes users will infrequently cause a QP to be replaced after it is +created and prefer to pay the state transition penalty at creation time. + +-- EP Query and Modify operations + +Because all of the ep_param data are kept up to date in the dapl_ep +structure, and because they use the complete DAT specified structure, a +query operation is trivial; a simple assignment from the internal +structure to the user parameter. uDAPL allows the implementation to +either return the fields specified by the user, or to return more than +the user requested; the reference implementation does the latter. It is +simpler and faster to copy the entire structure rather than to determine +which of all of the possible fields the user requested. + +dat_ep_query() requires the implementation to report the address of the +remote node, if the EP is connected. This is different from standard +InfiniBand, if only because of the difference in name space. InfiniBand +has the information on the remote LID, but it does not have the remote +IP address, which is what DAT specifies. The reference implementation +makes use of a lookup/name-service called ATS ( Address Translation +Service), which is built using the InfiniBand Subnet Administrator. ATS +is InfiniBand only, other transports will use a different mechanism. + +A driver will register itself and one or more IP addresses with ATS +at some point before a connection can be made. How the addresses are +provided to the driver, or how this is managed by the driver is not +specified. The ATS proposal is available from the DAT Collaborative. + +When dat_ep_query() is invoked on a connected EP, it will request the +remote address from the provider layer. The provider layer will use +whatever means are necessary to obtain the IP address of the other end of +the connection. The results are placed into a buffer that is part of the +EP structure. Finally, the address of the EP structure is placed into +the ep_param.remote_ia_address_ptr field. + +The ep_modify operation will modify the fields in the DAT_PARAM +structure. There are some fields that cannot be updated, and there are +others that can only be updated if the EP is in the correct state. The +uDAPL spec outlines the EP states permitting ep modifications, but +generally they are DAT_EP_STATE_UNCONNECTED and +DAT_EP_STATE_PASSIVE_CONNECTION_PENDING. + +When replacing EVD handles it is a simple matter of releasing a +reference on the previous handle and taking a new reference on the new +handle. The Reference Implementation manages resource tracking using +reference counts, which guarantees a particular handle will not be +released prematurely. Reference counts are checked in the free routines +of various objects. + +As has been mentioned previously, if the PZ handle is changed then the +QP must be released, if already assigned, and a new QP must be created +to bind to this EP. + +There are some fields in the DAT_PARAM structure that are related to the +underlying hardware implementation. For these values DAPL will do a +fresh query of the QP, rather than depend on stale values. Even so, the +values returned are 'best effort' as a competing thread may change +certain values before the requesting thread has the opportunity to read +them. Applications should protect against this. + +Finally, the underlying provider is invoked to update the QP with new +values, but only if some of the attributes have been changed. As is +true of most of the implementation, we only invoke the provider code +when necessary. + +====================================================================== +Connections +====================================================================== + +There are of course two sides to a connection, and in the DAPL model +there is an Active and a Passive side. For clarity, the Passive side +is a server waiting for a connection, and the Active side is a client +requesting a connection from the Passive server. We will discuss each +of these in turn. + +Connections happen in the InfiniBand world by using a Connection Manager +(CM) interface. Those unfamiliar with the IB model of addressing and +management agents may want to familiarize themselves with these aspects +of the IB spec before proceeding in this document. Be warned that the +connection section of the IB spec is the most ambiguous portion of the +spec. + +First, let's walk through a primitive diagram of a connection: + + +SERVER (passive) CLIENT (active) +--------------- --------------- +1. dapl_psp_create + or dapl_rsp_create + [ now listening ] + +2. dapl_ep_connect + <------------- +3. dapls_cr_callback + DAT_CONNECTION_REQUEST_EVENT + [ Create and post a DAT_CONNECTION_REQUEST_EVENT event ] + +4. Event code processing + +5. Create an EP if necessary + (according to the flags + when the PSP was created) + +6. dapl_cr_accept or dapl_cr_reject + -------------> +7. dapl_evd_connection_callback + DAT_CONNECTION_EVENT_ESTABLISHED + [ Create and post a + DAT_CONNECTION_EVENT_ESTABLISHED + event ] + +8. <------------- RTU + +9. dapls_cr_callback + DAT_CONNECTION_EVENT_ESTABLISHED + [ Create and post a DAT_CONNECTION_EVENT_ESTABLISHED + event ] + +10. ...processing... + +11. Either side issues a dat_ep_disconnect + +12. dapls_cr_callback + DAT_CONNECTION_EVENT_DISCONNECTED + + [ Create and post a + DAT_CONNECTION_EVENT_DISCONNECTED + event ] + +13. dapl_evd_connection_callback + DAT_CONNECTION_EVENT_DISCONNECTED + [ Create and post a + DAT_CONNECTION_EVENT_DISCONNECTED + event ] + + +In the above diagram, time is numbered in the left hand column and is +represented vertically. + +We will continue our discussion of connections using the above diagram, +following a sequential order for connection establishment. + +There are in fact two types of service points detailed in the uDAPL +specification. We will limit our discussion to PSPs for convenience, but +there are only minor differences between PSPs and RSPs. + +The reader should observe that all passive-side connection events will +be received by dapls_cr_callback(), and all active side connection +events occur through dapl_evd_connection_callback(). At one point during +the implementation these routines were combined as they are very +similar, but there are subtle differences causing them to remain +separate. + +Progressing through the series of events as outlined in the diagram +above: + +1. dapl_psp_create + + When a PSP is created, the final act will be to set it listening for + connections from remote nodes. It is important to realize that a + connection may in fact arrive from a remote node before the routine + setting up a listener has returned to dapl_psp_create; as soon as + dapls_ib_setup_conn_listener() is invoked connection callbacks may + arrive. To reduce race conditions this routine must be called as the + last practical operation when creating a PSP. + + dapls_ib_setup_conn_listener() is provider specific. The key insight + is that the DAPL connection qualifier (conn_qual) will become the + InfiniBand Service ID. The passive side of the connection is now + listening for connection requests. It should be obvious that the + conn_qual must be unique. + + InfiniBand allows a 64 bit connection qualifier, which is supported + by the DAT spec. IP based networks may be limited to 16 bits, so + provider implementations may want to return an error if it exceeds + the maximum allowable by the transport. + +2. dapl_ep_connect + + The active side initiates a connection with dapl_ep_connect, which + will transition the EP into DAT_EP_STATE_ACTIVE_CONNECTION_PENDING. + Again, connections are in the domain of the providers' Connection + Manager and the mechanics are very much provider specific. The key + points are that a DAT_IA_ADDRESS_PTR must be translated to a GID + before a connection initiation can occur. This is discussed below. + + InfiniBand supports different amounts of private data on various + connection functions. Other transports allow variable sizes of + private data with no practical limit.The DAPL connection code does + not enforce a fixed amount of private data, but rather makes + available to the user all it has available, as specified by + DAPL_MAX_PRIVATE_DATA_SIZE. + + Private data will be stored in a fixed buffer as part of the + connection record, which is the primary reason to limit the size. + + To assist development on new transports that do not have a full + connection infrastructure in place, there are a couple of compile time + flags that will include certain code: CM_BUSTED and + IBOSTS_NAMING. These are discussed below in more detail, but + essentially: + + CM_BUSTED: fakes a connection on both sides of the wire, does not + transmit any private data. + + IBHOSTS_NAMING: provides a simple IP_ADDRESS to LID translation + mechanism in a text file, which is read when the dapl library + loads. Private data is exchanged in this case, but it includes a + header that contains the remote IP address. Technically, this defines + a protocol and is in violation of the DAT spec, but it has proved + useful in development. + +3. dapls_cr_callback + + The connection sequence is entirely event driven. An operation is + posted, then an asynchronous event will occur some time later. The + event may cause other actions to occur which may result in still + more events. + + dapls_ib_setup_conn_listener() registered for a callback for + connection events, and we now receive a DAT event for a connection + request. The provider layer will translate the native event type to + a DAT event. + + An upcall is invoked on the server side of the connection with an + event of type DAT_CONNECTION_REQUEST_EVENT. This is a unique event + in the callback code as it is the only case when an EP is not + already in play; in all other cases, it is possible to look up the + relevant EP for an operation. + + Code exists to make sure the relevant connection object, the PSP or + RSP, is actually in a useful state and ready to be connected + to. One of the critical differences between a PSP and an RSP is + that an RSP is a one-shot connection object; once a connection + occurs, no other connections can be made to it. + + There is a small difference in the InfiniBand and DAPL connection + models here as well. DAPL may disable a PSP at any time without + affecting current connections. When you tear down an InfiniBand + service endpoint, all of the connections are torn down too. Because + of this difference, when a DAPL app frees a PSP, only a state + change is made. The underlying service point is still available and + technically capable of receiving connections. If a connection + request arrives when the PSP is in this state, a rejection message + is sent such that the requesting node believes no service point is + listening. + + Once the connection has been examined, it will continue with the + connection protocol. The EP will move to a CONNECTION_PENDING + state. + + The connection request will cause a CR record to be allocated, + which holds all of the important connection request + information. The CR record will be linked onto the PSP structure + for retrieval in the future when other requests arrive. + + The astute reader of the spec will observe that there is not a + dapl_cr_create call: CR records are created as part of a connection + attempt on the passive side of the connection. A CR is created now + and set up. A point that will become important later, caps for + emphasis: + + A CR WILL EXIST FOR THE LIFE OF A CONNECTION; THEY ARE DESTROYED AT + DISCONNECT TIME. + + In the connection request processing a CR and an EVENT are created, + the event will be posted along with the connection information just + received. + + Private data is also copied into the CR record. Private data + arrived with the connection request and is not a permanent + resource, so it is copied into the dapl space to be used at a later + time. Different transports have varying capabilities on the size of + private data, so a call to the provider is invoked to determine how + big it actually is. There is an upper bound on the amount of + private data the implementation will deal with, set at + DAPL_MAX_PRIVATE_DATA_SIZE (256 bytes at this writing). + +4. Event code processing + + The final stage in a connection request is to generate an event on + a connection EVD using dapls_evd_post_cr_arrival_event(). + +5. Create an EP if necessary + + When the app processes a connection event, it needs to respond. If + the PSP is configured to create an EP automatically, the callback + code has already done it; creating an EP with no attached QP. Else, + the user must provide an EP to make the connection. + + (4) and (5) are all done in user mode. The only interesting thing is + that when the user calls dat_cr_accept(), a ready EP must be + provided. If the EP was supplied by the PSP in the callback, it + must have a PZ associated with it and whatever other attributes + need to be set. + +6. dapl_cr_accept or dapl_cr_reject + + For discussion purposes, we will follow the accept + path. dapl_cr_reject says you are done and there will be no further + events to deal with. + + Assuming it accepts the connection for our example, the dapl code + will verify that an EP is in place and will deal with private data + that can be transmitted in a cr_accept call. The underlying + provider is invoked to complete this leg of the protocol. + +7. dapl_evd_connection_callback + + An EVD callback is always a response to a connection oriented + request. As such, an EP is always present, and in fact is passed + into the upcall as the 'context' argument. + + Connection requests may take an arbitrary amount of time, so the EP + is always checked for a running timer when the upcall is made. As + has been discussed above, if a timer expires before an upcall + occurs, the connection must be completely canceled such that there + is no upcall. + + The event signifying completion of the connection is + DAT_CONNECTION_EVENT_ESTABLISHED, and it will move the EP to the + CONNECTED state and post this event on the connection EVD. Private + data will be copied to an area in the EP structure, which is + persistent. + + At this point, the EP is connected and the application is free to + post DTOs. + +8i. RTU + + This item is labeled "8i" as it is internal to the InfiniBand + implementation, it is not initiated by dapl. The final leg of a + connection is an RTU sent from the initiating node to the server + node, indicating the connection has been made successfully. + + Other transports may have a different connection protocol. + +9. dapls_cr_callback + + When the RTU arrives, an upcall is invoked with a + DAT_CONNECTION_EVENT_ESTABLISHED event, which will be posted to the + connection EVD event queue. The EP is moved to the CONNECTED + state. + + There is no private data for dapl to deal with, even though some + transports may provide private data at each step of a connection. + + The connection activity is occurring on a separate channel than the + EP, so this is inherently a racy operation. The correct + application will always post RECV buffers on an EP before + initiating a connection sequence, as it is entirely possible for + DTOs to arrive *before* the final connection event arrives. + + The architecturally interesting feature of this exchange occurs + because of differences in the InfiniBand and the DAT connection + models, which are briefly outlined here. + + InfiniBand maintains the original connecting objects throughout the + life of the connection. That is, we originally get a callback event + associated with the Service (DAT PSP) that is listening for + connection events. A QP will be connected but the callback event + will still be received on the Service. Later, a callback event will + occur for a DISCONNECT, and again the Service will be the object of + the connection. In the DAPL implementation, the Service will + provide the PSP that is registered as listening on that connection + qualifier. + + The difference is that DAT has a PSP receive a connection event, + but subsequently hands all connection events off to an EP. After a + dat_cr_accept is issued, all connection/disconnection events occur + on the EP. DAT more closely follows the IP connection model. + + To support the DAT model, a CR is maintained through the life of + the connection. There is exactly one CR per connection, but any + number of CRs may exist for any given PSP. CRs are maintained on a + linked list pointed to by the PSP structure. A lookup routine will + match the cm_handle, unique for each connection, with the + appropriate CR. This allows us to find the appropriate EP which + will be used to create an event to be posted to the user. + +* dat_psp_destroy + + It should be understood that the PSP will maintain all of the CR + records, and hence the PSP must persist until the final disconnect. + In the DAT model there is no association between a PSP and a + connected QP, so there is no reason not to destroy a PSP before the + final disconnect. + + Because of the model mismatch we must preserve the PSP until the + final disconnect. If the user invokes dat_psp_destroy(), all of the + associations maintained by the PSP will be severed; but the PSP + structure itself remains as a container for the CR records. The PSP + structure maintains a simple count of CR records so we can easily + determine the final disconnect and release memory. Once a + disconnect event is received for a specific cm_handle, no further + events will be received and it is safe to discard the CR record. + +10. ...processing... + + This is just a place holder to show that applications actually do + something after making a connection. They might not too... + +11. Either side issues a dat_ep_disconnect + + dat_ep_disconnect() can be initiated by either side of a + connection. There are two kinds of disconnect flags that can be + passed in, but the final result is largely the same. + + DAT_CLOSE_ABRUPT_FLAG will cause the connection to be immediately + terminated. In InfiniBand terms, the QP is immediately moved to the + ERROR state, and after some time it will be moved to the RESET + state. + + DAT_CLOSE_GRACEFUL_FLAG will allow in-progress DTOs to complete. + The underlying implementation will first transition the QP to the + SQE state, before going to RESET. + + Both cases are handled by the underlying CM, there is no extra work + for DAPL. + +12. dapls_cr_callback + + A disconnect will arrive on the passive side of the connection + through dapls_cr_callback() with connection event + DAT_CONNECTION_EVENT_DISCONNECTED. With this event the EP lookup + code will free the CR associated with the connection, and may free + the PSP if it is no longer listening, indicating it has been freed + by the application. + + The callback will create and post a + DAT_CONNECTION_EVENT_DISCONNECTED event for the application. + +13. dapl_evd_connection_callback + + The active side of the connection will receive + DAT_CONNECTION_EVENT_DISCONNECTED as the connection event for + dapl_evd_connection_callback(), and will create and post a + DAT_CONNECTION_EVENT_DISCONNECTED event. Other than transitioning + the EP to the DISCONNECTED state, there is no further processing. + + +Observe that there are a number of exception conditions resulting in a +disconnect of the EP, most of which will generate unique DAT events +for the application to deal with. + + +* Addressing and Naming + + The DAT Spec calls for a DAT_IA_ADDRESS_PTR to be an IP address, + either IPv4 or IPv6. It is in fact a struct sockaddr in most + systems. The dapl structures typically use IPv6 data types to + accommodate the largest possible addresses, but most implementations + use IPv4 formatted addresses. + + InfiniBand uses a transport specific address known as a LID, which + typically is dynamically assigned by a Subnet Manager. Each HCA + also has a global address, similar to an Ethernet MAC address, + known as a GUID. ATS, mentioned above, is a mechanism using + InfiniBand infrastructure to map from GUID/LID to IP addresses. It + is not necessary for transports that use IP addresses natively, + such as Ethernet devices. + + If a new implementation does not yet have a name service + infrastructure, the DAPL implementation provides a simple name + service facility under the #ifdef NO_NAME_SERVICE. This depends on + two things: valid IP addresses registered and available to standard + DNS system calls such as gethostbyname(); and a name/GID mapping + file. + + IP addresses may be set up by system administrators or by a local + power-user simply by editing the values into the /etc/hosts file. + Setting IP addresses up in this manner is beyond the scope of this + document. + + A simple mapping of names to GIDs is maintained in the ibhosts + file, currently located at /etc/dapl/ibhosts. The format of + the file is: + + 0x 0x + + For example: + + dat-linux3-ib0p0 0xfe80000000000000 0x0001730000003d11 + dat-linux3-ib0p1 0xfe80000000000000 0x0001730000003d11 + dat-linux3-ib1 0xfe80000000000000 0x0001730000003d52 + dat-linux5-ib0 0xfe80000000000000 0x0001730000003d91 + + And for each hostname, there must be an entry in the /etc/hosts file + similar to: + + dat_linux3-ib0a 198.165.10.11 + dat_linux3-ib0b 198.165.10.12 + dat_linux3-ib1a 198.165.10.21 + dat_linux5-ib0a 198.165.10.31 + + + In this example we have adopted the convention of naming each + InfiniBand interface by using the form + + -ib[port_number] + + In the above example we can see that the machine dat_linux3 has three + InfiniBand interfaces, which in this case we have named two ports on + the first HCA and another port on a second. Utilizing standard DNS + naming, the conventions used for identifying individual ports is + completely up to the administrator. + + The GID Prefix and GUID are obtained from the HCA and map a port on + the HCA: together they form the GID that is required by a CM to + connect with the remote node. + + The simple name service builds an internal table after processing + the ibhosts file which contains IP addresses and GIDs. It will use + the standard getaddrinfo() function to obtain IP address + information. + + When an application invoked dat_ep_connect(), the + DAT_IA_ADDRESS_PTR will be compared in the table for a match and + the destination GID established if found. If the address is not + found then the user must first add the name to the ibhosts file. + + With a valid GID for the destination node, the underlying CM is + invoked to make a connection. + +* Connection Management + + Getting a working CM has taken some time, in fact the DAPL project + was nearly complete by the time a CM was available. In order to + make progress, a connection hack was introduced that allows + specific connections to take place. This is noted in the code by + the CM_BUSTED #def. + + CM_BUSTED takes the place of a CM and will manually transition a QP + through the various states to connect: INIT->RTR->RTS. It will also + disconnect the connection, although the Torrent implementation + simply destroys the QP and recreates a new one rather than + transitioning through the typical disconnect states (which didn't + work on early IB implementations). + + CM_BUSTED makes some assumptions about the remote end of the + connection as no real information is exchanged. The ibapi + implementation assumes both HCAs have the same LID, which implies + there is no SM running. The vapi implementation assumes the LIDs + are 0 and 1. Depending on the hardware, the LID value may in fact + not make any difference. This code does not set the Global Route + Header (GRH), which would cause the InfiniBand chip to be carefully + checking LID information. + + The QP number is assumed to be identical on both ends of the + connection, or differing by 1 if this is a loopback. There is an + environment variable that will be read at initialization time if + you are configured with a loopback, this value is checked when + setting up a QP. The obvious downside to this scheme is that + applications must stay synchronized in their QP usage or the + initial exchange will fail as they are not truly connected. + + Add to this the limitation that HCAs must be connected in + Point-to-Point topology or in a loopback. Without a GRH it will not + work in a fabric. Again, using an SM will not work when CM_BUSTED + is enabled. + + Despite these shortcomings, CM_BUSTED has proven very useful and + will remain in the code for a while in order to aid development + groups with new hardware and software. It is a hack to be sure, but + it is relatively well isolated. + + +-- Notes on Disconnecting + +An EP can only be disconnected if it is connected or unconnected; you +cannot disconnect 'in progress' connections. An 'in progress +connection may in fact time out, but the DAT Spec does not allow you +to 'kill' it. DAPL will use the CM interface to disconnect from the +remote node; this of course results in an asynchronous callback +notifying the application the disconnect is complete. + +Disconnecting an unconnected EP is currently the only way to remove +pending RECV operations from the EP. The DAPL spec notes that all +DTOs must be removed from an EP before it can be deallocated, yet +there is no explicit interface to remove pending RECV DTOs. The user +will disconnect an unconnected EP to force the pending operations off +of the queue, resulting in DTO callbacks indicating an error. The +underlying InfiniBand implementation will cause the correct behavior +to result. When doing this operation the DAT_CLOSE flag is ignored, +DAPL will instruct the provider layer to abruptly disconnect the QP. + +As has been noted previously, specifying DAT_CLOSE_ABRUPT_FLAG as the +disconnect completion flag will cause the CM implementation to +transition the QP to the ERROR state to abort all operations, and then +transition to the RESET state; if the flag is DAT_CLOSE_GRACEFUL_FLAG, +the CM will first move to the SQE state and allow all pending I/O's to +drain before moving to the RESET state. In either case, DAPL only +needs to know that the QP is now in the RESET state, as it will need +to be transitioned to the INIT state before it can be used again. + +====================================================================== +Data Transfer Operations (DTOs) +====================================================================== + +The DTO code is a straightforward translation of the DAT_LMR_TRIPLET +to an InfiniBand work request. Unfortunately, IB does not specify what +a work request looks like so this tends to be very vendor specific +code. Each provider will supply a routine for this operation. + +InfiniBand allows the DTO to attach a unique 64 bit work_req_id to +each work request. The DAPL implementation will install a pointer to a +DAPL_DTO_COOKIE in this field. Observe that a DAPL_DTO_COOKIE is not +the same as the user DAT_DTO_COOKIE; indeed, the former has a pointer +field pointing to the latter. Different values will be placed in the +cookie, according to the type of operation it is and the type of data +required by its completion event. This is a simple scheme to bind DAPL +data to the DTO and associated completion callback. Each DTO has a +unique cookie associated with it. + +Observe that an InfiniBand work_request remains under control of the +user, and when a post operation occurs the underlying implementation +will copy data out of the work_request into a hardware based +structure. Further, no application can perform a DTO operation on the +same EP at the same time according to the thread guarantees mandated +by the specification. This allows us to provide a recv_iov and a +send_iov in the EP structure for all DTO operations, eliminating any +malloc operations from this critical path. + +The underlying provider implementation will invoke +dapl_evd_dto_callback() upon completion of DTO operations. +dapl_evd_dto_callback() is the asynchronous completion for a DTO and +will create and post an event for the user. Much of this callback is +concerned with managing error completions. + + +====================================================================== +Data Structure +====================================================================== + +The main data structure for an EndPoint is the dapl_ep structure, +defined in include/dapl.h. The reference implementation uses the +InfiniBand QP to maintain hardware state, providing a relatively +simple mapping. + +/* DAPL_EP maps to DAT_EP_HANDLE */ +struct dapl_ep +{ + DAPL_HEADER header; + /* What the DAT Consumer asked for */ + DAT_EP_PARAM param; + + /* The RC Queue Pair (IBM OS API) */ + ib_qp_handle_t qp_handle; + unsigned int qpn; /* qp number */ + ib_qp_state_t qp_state; + + /* communications manager handle (IBM OS API) */ + ib_cm_handle_t cm_handle; + /* store the remote IA address here, reference from the param + * struct which only has a pointer, no storage + */ + DAT_SOCK_ADDR6 remote_ia_address; + + /* For passive connections we maintain a back pointer to the CR */ + void * cr_ptr; + + /* pointer to connection timer, if set */ + struct dapl_timer_entry *cxn_timer; + + /* private data container */ + DAPL_PRIVATE private; + + /* DTO data */ + DAPL_ATOMIC req_count; + DAPL_ATOMIC recv_count; + + DAPL_COOKIE_BUFFER req_buffer; + DAPL_COOKIE_BUFFER recv_buffer; + + ib_data_segment_t *recv_iov; + DAT_COUNT recv_iov_num; + + ib_data_segment_t *send_iov; + DAT_COUNT send_iov_num; +#ifdef DAPL_DBG_IO_TRC + int ibt_dumped; + struct io_buf_track *ibt_base; + DAPL_RING_BUFFER ibt_queue; +#endif /* DAPL_DBG_IO_TRC */ +}; + +The simple explanation of the fields in the dapl_ep structure follows: + +header: The dapl object header, common to all dapl objects. + It contains a lock field, links to appropriate lists, and + handles specifying the IA domain it is a part of. + +param: The bulk of the EP attributes called out in the DAT + specification and are maintained in the DAT_EP_PARAM + structure. All internal references to these fields + use this structure. + +qp_handle: Handle to the underlying InfiniBand provider implementation + for a QP. All EPs are mapped to an InfiniBand QP. + +qpn: Number of the QP as returned by the underlying provider + implementation. Primarily useful for debugging. + +qp_state: Current state of the QP. The values of this field indicate + if a QP is bound to the EP, and the current state of a + QP. + +cm_handle: Handle to the IB provider's CMA (Connection Manager Agent). + Used for CM operations used to connect and disconnect. + +remote_ia_address: + Remote IP address of the connection. Only valid after the user + has asked for it. + +cr_ptr: Attaches the EP to the appropriate CR. Assigned on the passive + side of a connection in cr_accept. It is used when an abrupt + disconnect is invoked by the app, and we need to 'fake' a + callback. It is also used in clean up of an EP and removing + connection elements from the associated PSP. + +cxn_timer: Pointer to a timer entry, used as a token to set and remove + timers. + +private: Local Private data area on the active side of a connection. + +req_count: Count of outstanding request DTO operations, including memory + ops. Atomically incremented/decremented. + +recv_count:Count of outstanding receive DTO operations. Atomically + incremented/decremented. + +req_buffer:Ring buffer of request cookies. + +recv_buffer: + Ring buffer of receive cookies. + +recv_iov: Storage for provider receive work request. + +recv_iov_num: + Maximum number of receive IOVs. Number is obtained from + the provider in a query. + +send_iov: Storage for provider send work request. + +send_iov_num: + Maximum number of send IOVs. Number is obtained from the + provider in a query. + +ibt_dumped:DTO debugging aid. Boolean value to control how often DTO + tracing data is printed. + +ibt_base: DTO debugging aid. Base address of DTO ring buffer containing + information on DTO processing. + +ibt_queue: Ring buffer containing information n DTO processing. + + +** Debug + +The Reference Implementation includes a trace facility that allows a +developer to see all DTO operations, specifically to catch those that +are not completing as expected. The DAPL_DBG_IO_TRC conditional will +enable this code. + +A simple ring buffer is used to account for all outstanding DTO +traffic. The buffer may be dumped when DTOs are not getting +completions, with enough data to aid the developer to determine where +things went wrong. + +It is implemented as a ring buffer as there are often bugs in this +part of a provider's implementation which do not manifest until +intensive data exchange has occurred for many hours. diff --git a/branches/WOF2-3/ulp/dapl2/doc/dapl_environ.txt b/branches/WOF2-3/ulp/dapl2/doc/dapl_environ.txt new file mode 100644 index 00000000..17aabd19 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/doc/dapl_environ.txt @@ -0,0 +1,42 @@ + DAPL Environment Guide v. 0.01 + ------------------------------ + +The following environment variables affect the behavior of the DAPL +provider library: + + +DAPL_DBG_TYPE +------------- + + Value specifies which parts of the registry will print debugging + information, valid values are + + DAPL_DBG_TYPE_ERR = 0x0001 + DAPL_DBG_TYPE_WARN = 0x0002 + DAPL_DBG_TYPE_EVD = 0x0004 + DAPL_DBG_TYPE_CM = 0x0008 + DAPL_DBG_TYPE_EP = 0x0010 + DAPL_DBG_TYPE_UTIL = 0x0020 + DAPL_DBG_TYPE_CALLBACK = 0x0040 + DAPL_DBG_TYPE_DTO_COMP_ERR = 0x0080 + DAPL_DBG_TYPE_API = 0x0100 + DAPL_DBG_TYPE_RTN = 0x0200 + DAPL_DBG_TYPE_EXCEPTION = 0x0400 + + or any combination of these. For example you can use 0xC to get both + EVD and CM output. + + Example setenv DAPL_DBG_TYPE 0xC + + +DAPL_DBG_DEST +------------- + + Value sets the output destination, valid values are + + DAPL_DBG_DEST_STDOUT = 0x1 + DAPL_DBG_DEST_SYSLOG = 0x2 + DAPL_DBG_DEST_ALL = 0x3 + + For example, 0x3 will output to both stdout and the syslog. + diff --git a/branches/WOF2-3/ulp/dapl2/doc/dapl_event_design.txt b/branches/WOF2-3/ulp/dapl2/doc/dapl_event_design.txt new file mode 100644 index 00000000..247c7ef5 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/doc/dapl_event_design.txt @@ -0,0 +1,875 @@ + DAPL Event Subsystem Design v. 0.96 + ----------------------------------- + +================= +Table of Contents +================= + +* Table of Contents +* Referenced Documents +* Goals + + Initial Goals + + Later Goals +* Requirements, constraints, and design inputs + + DAT Specification Constraints + + Object and routine functionality, in outline + + Detailed object and routine specification + + Synchronization + + IBM Access API constraints + + Nature of DAPL Event Streams in IBM Access API. + + Nature of access to CQs + + Operating System (Pthread) Constraints + + Performance model + + A note on context switches +* DAPL Event Subsystem Design + + OS Proxy Wait Object + + Definition + + Suggested Usage + + Event Storage + + Synchronization + + EVD Synchronization: Locking vs. Producer/Consumer queues + + EVD Synchronization: Waiter vs. Callback + + CNO Synchronization + + Inter-Object Synchronization + + CQ -> CQEH Assignments + + CQ Callbacks + + Dynamic Resizing of EVDs + + Structure and pseudo-code + + EVD + + CNO +* Future directions + + Performance improvements: Reducing context switches + + Performance improvements: Reducing copying of event data + + Performance improvements: Reducing locking + + Performance improvements: Reducing atomic operations + + Performance improvements: Incrementing concurrency. + +==================== +Referenced Documents +==================== + +uDAPL: User Direct Access Programming Library, Version 1.0. Published +6/21/2002. http://www.datcollaborative.org/uDAPL_062102.pdf. +Referred to in this document as the "DAT Specification". + +InfiniBand Access Application Programming Interface Specification, +Version 1.2, 4/15/2002. In DAPL SourceForge repository at +doc/api/access_api.pdf. Referred to in this document as the "IBM +Access API Specification". + +===== +Goals +===== + +Initial goals +------------- +-- Implement the dat_evd_* calls described in the DAT Specification (except + for dat_evd_resize). + +-- The implementation should be as portable as possible, to facilitate + HCA Vendors efforts to implement vendor-specific versions of DAPL. + +Later goals +----------- +-- Examine various possible performance optimizations. This document + lists potential performance improvements, but the specific + performance improvements implemented should be guided by customer + requirements. + +-- Implement the dat_cno_* calls described in the DAT 1.0 spec + +-- Implement OS Proxy Wait Objects. + +-- Implement dat_evd_resize + +Non-goals +--------- +-- Thread safe implementation + +============================================ +Requirements, constraints, and design inputs +============================================ + +DAT Specification Constraints +----------------------------- + +-- Object and routine functionality, in outline + +The following section summarizes the requirements of the DAT +Specification in a form that is simpler to follow for purposes of +implementation. This section presumes the reader has read the DAT +Specification with regard to events. + +Events are delivered to DAPL through Event Streams. Each Event Stream +targets a specific Event Descriptor (EVD); multiple Event Streams may +target the same EVD. The Event Stream<->EVD association is +effectively static; it may not be changed after the time at which +events start being delivered. The DAT Consumer always retrieves +events from EVDs. EVDs are intended to be 1-to-1 associated with the +"native" event convergence object on the underlying transport. For +InfiniBand, this would imply a 1-to-1 association between EVDs and +CQs. + +EVDs may optionally have an associated Consumer Notification Object +(CNO). Multiple EVDs may target the same CNO, and the EVD<->CNO +association may be dynamically altered. The DAT Consumer may wait for +events on either EVDs or CNOs; if there is no waiter on an EVD and it +is enabled, its associated CNO is triggered on event arrival. An EVD +may have only a single waiter; a CNO may have multiple waiters. +Triggering of a CNO is "sticky"; if there is no waiter on a CNO when +it is triggered, the next CNO waiter will return immediately. + +CNOs may have an associated OS Proxy Wait Object, which is signaled +when the CNO is triggered. + +-- Detailed object and routine specification + +Individual events may be "signaling" or "non-signaling", depending +on the interaction of: + * Receive completion endpoint attributes + * Request completion endpoint attributes + * dat_ep_post_send completion flags + * dat_ep_post_recv completion flags +The nature of this interaction is outside the scope of this document; +see the DAT Specification 1.0 (or, failing that, clarifications in a +later version of the DAT Specification). + +A call to dat_evd_dequeue returns successfully if there are events on +the EVD to dequeue. A call to dat_evd_wait blocks if there are fewer +events present on the EVD than the value of the "threshold" parameter +passed in the call. Such a call to dat_evd_wait will be awoken by the +first signaling event arriving on the EVD that raises the EVD's event +count to >= the threshold value specified by dat_evd_wait(). + +If a signaling event arrives on an EVD that does not have a waiter, +and that EVD is enabled, the CNO associated with the EVD will be +triggered. + +A CNO has some number of associated waiters, and an optional +associated OS Proxy Wait Object. When a CNO is triggered, two things +happen independently: + * The OS Proxy Wait Object associated with the CNO, if any, is + signaled, given the handle of an EVD associated with the CNO + that has an event on it, and disassociated from the CNO. + * If: + * there is one or more waiters associated with the + CNO, one of the waiters is unblocked and given the + handle of an EVD associated with the CNO that has an + event on it. + * there are no waiters associated with the CNO, the + CNO is placed in the triggered state. + +When a thread waits on a CNO, if: + * The CNO is in the untriggered state, the waiter goes to + sleep pending the CNO being triggered. + * The CNO is in the triggered state, the waiter returns + immediately with the handle of an EVD associated with the + CNO that has an event on it, and the CNO is moved to the + untriggered state. + +Note specifically that the signaling of the OS Proxy Wait Object is +independent of the CNO moving into the triggered state or not; it +occurs based on the state transition from Not-Triggered to Triggered. +Signaling the OS Proxy Wait Object only occurs when a CNO is +triggered. In contrast, waiters on a CNO are unblocked whenever the +CNO is in the triggered *state*, and that state is sticky. + +Note also that which EVD is returned to the caller in a CNO wait is +not specified; it may be any EVD associated with the CNO on which an +event arrival might have triggered the CNO. This includes the +possibility that the EVD returned to the caller may not have any +events on it, if the dat_cno_wait() caller raced with a separate +thread doing a dat_evd_dequeue(). + +The DAT Specification is silent as to what behavior is to be expected +from an EVD after an overflow error has occurred on it. Thus this +design will also be silent on that issue. + +The DAT Specification has minimal requirements on inter-Event Stream +ordering of events. Specifically, any connection events must precede +(in consumption order) any DTO Events for the same endpoint. +Similarly, any successful disconnection events must follow any DTO +Events for an endpoint. + +-- Synchronization + +Our initial implementation is not thread safe. This means that we do +not need to protect against the possibility of multiple simultaneous +user calls occurring on the same object (EVD, CNO, EP, etc.); that is +the responsibility of the DAT Consumer. + +However, there are synchronization guards that we do need to protect +against because the DAT Consumer cannot. Specifically, since the user +cannot control the timing of callbacks from the IBM Access API +Implementation, we need to protect against possible collisions between +user calls and such callbacks. We also need to make sure that such +callbacks do not conflict with one another in some fashion, possibly +by assuring that they are single-threaded. + +In addition, for the sake of simplicity in the user interface, I have +defined "not thread safe" as "It is the DAT Consumer's responsibility +to make sure that all calls against an individual object do not +conflict". This does, however, suggest that the DAPL library needs to +protect against calls to different objects that may result in +collisions "under the covers" (e.g. a call on an EVD vs. a call on its +associated CNO). + +So our synchronization requirements for this implementation are: + + Protection against collisions between user calls and IBM + Access API callbacks. + + Avoidance of or protection against collisions between + different IBM Access API callbacks. + + Protection against collisions between user calls targeted at + different DAT objects. + +IBM Access API constraints +-------------------------- + +-- Nature of DAPL Event Streams in IBM Access API + +DAPL Event Streams are delivered through the IBM Access API in two fashions: + + Delivery of a completion to a CQ. + + A callback is made directly to a previously registered DAPL + function with parameters describing the event. +(Software events are not delivered through the IBM Access API). + +The delivery of a completion to a CQ may spark a call to a previously +registered callback depending on the attributes of the CQ and the +reason for the completion. Event Streams that fall into this class +are: + + Send data transport operation + + Receive data transport operation + + RMR bind + +The Event Streams that are delivered directly through a IBM Access API +callback include: + + Connection request arrival + + Connection resolution (establishment or rejection) + + Disconnection + + Asynchronous errors + +Callbacks associated with CQs are further structured by a member of a +particular CQ Event Handling (CQEH) domain (specified at CQ creation +time). All CQ callbacks within a CQEH domain are serviced by the same +thread, and hence will not collide. + +In addition, all connection-related callbacks are serviced by the same +thread, and will not collide. Similarly, all asynchronous error +callbacks are serviced by the same thread, and will not collide. +Collisions between any pair of a CQEH domain, a connection callback, +and an asynchronous error callback are possible. + +-- Nature of access to CQs + +The only probe operation the IBM Access API allows on CQs is +dequeuing. The only notification operation the IBM Access API +supports for CQs is calling a previously registered callback. + +Specifically, the IB Consumer may not query the number of completions +on the CQ; the only way to find out the number of completions on a CQ +is through dequeuing them all. It is not possible to block waiting +on a CQ for the next completion to arrive, with or without a +threshold parameter. + +Operating System Constraints +---------------------------- + +The initial platform for implementation of DAPL is RedHat Linux 7.2 on +Intel hardware. On this platform, inter-thread synchronization is +provided by a POSIX Pthreads implementation. From the viewpoint of +DAPL, the details of the Pthreads interface are platform specific. +However, Pthreads is a very widely used threading library, common on +almost all Unix variants (though not used on the different variations +of Microsoft Windows(tm)). In addition, RedHat Linux 7.2 provides +POSIX thread semaphore operations (e.g. see sem_init(3)), which are +not normally considered part of pthreads. + +Microsoft Windows(tm) provides many synchronization primitives, +including mutual exclusion locks, and semaphores. + +DAPL defines an internal API (not exposed to the consumer), though +which it accesses Operating Systems Dependent services; this is called +the OSD API. It is intended that this layer contain all operating +system dependencies, and that porting DAPL to a new operating system +should only require changes to this layer. + +We have chosen to define the synchronization interfaces established at +this layer in terms of two specific objects: mutexes and sempahores w/ +timeout on waiting. Mutexes provide mutual exclusion in a way that is +common to all known operating systems. The functionality of +semaphores also exists on most known operating systems, though the +sempahores provided by POSIX do not provide timeout capabilities. +This is for three reasons. First, in contrast to Condition Variables +(the native pthreads waiting/signalling object), operations on +sempahores do not require use of other synchronization variables +(i.e. mutexes). Second, it is fairly easy to emulate sempahores using +condition variables, and it is not simple to emulate condition +variables using semaphores. And third, there are some anticipated +platforms for DAPL that implement condition variables in relation to +some types of locks but not others, and hence constrain appropriate +implementation choices for a potential DAPL interface modeled after +condition variables. + +Implementation of the DAPL OS Wait Objects will initially be based on +condition variables (requiring the use of an internal lock) since +POSIX semaphores do not provide a needed timeout capability. However, +if improved performance is required, a helper thread could be created +that arranges to signal waiting semaphores when timeouts have +expired. This is a potential future (or vendor) optimization. + +Performance Model +----------------- +One constraint on the DAPL Event Subsystem implementation is that it +should perform as well as possible. We define "as well as possible" +by listing the characteristics of this subsystem that will affect its +performance most strongly. In approximate order of importance, these +are: + + The number of context switches on critical path + + The amount of copying on the critical path. + + The base cost of locking (assuming no contention) on the + critical path. This is proportional to the number of locks + taken. + + The amount of locking contention expected. We make a + simplifying assumption and take this as the number of cycles + for which we expect to hold locks on the critical path. + + The number of "atomic" bus operations executed (these take + more cycles than normal operations, as they require locking + the bus). + +We obviously wish to minimize all of these costs. + +-- A note on context switches + +In general, it's difficult to minimize context switches in a user +space library directly communicating with a hardware board. This is +because context switches, by their nature, have to go through the +operating system, but the information about which thread to wake up +and whether to wake it up is generally in user space. In addition, +the IBM Access API delivers all Event Streams as callbacks in user +context (as opposed to, for example, allowing a thread to block within +the API waiting for a wakeup). For this reason, the default sequence +of events for a wakeup generated from the hardware is: + * Hardware interrupts the main processor. + * Interrupt thread schedules a user-level IBM Access API + provider service thread parked in the kernel. + * Provider service thread wakes up the sleeping user-level + event DAT implementation thread. +This implies that any wakeup will involve three context switches. +This could be reduced by one if there were a way for user threads to +block in the kernel, we might skip the user-level provider thread. + +=========================== +DAPL Event Subsystem Design +=========================== + + +OS Proxy Wait Object +-------------------- + +The interface and nature of the OS Proxy Wait Object is specified in +the uDAPL v. 1.0 header files as a DAT_OS_WAIT_PROXY_AGENT via the +following defines: + +typedef void (*DAT_AGENT_FUNC) + ( + DAT_PVOID, /* instance data */ + DAT_EVD_HANDLE /* Event Dispatcher*/ + ); + +typedef struct dat_os_wait_proxy_agent + { + DAT_PVOID instance_data; + DAT_AGENT_FUNC proxy_agent_func; + } DAT_OS_WAIT_PROXY_AGENT; + +In other words, an OS Proxy Wait Object is a (function, data) pair, +and signalling the OS Proxy Wait Object is a matter of calling the +function on the data and an EVD handle associated with the CNO. +The nature of that function and its associated data is completely up +to the uDAPL consumer. + +Event Storage +------------- + +The data associated with an Event (the type, the EVD, and any type +specific data required) must be stored between event production and +event consumption. If storage is not provided by the underlying +Verbs, that data must be stored in the EVD itself. This may require +an extra copy (one at event production and one at event consumption). + +Event Streams associated purely with callbacks (i.e. IB events that +are not mediated by CQs) or user calls (i.e. software events) don't +have any storage allocated for them by the underlying verbs and hence +must store their data in the EVD. + +Event Streams that are associated with CQs have the possibility of +leaving the information associated with the CQ between the time the +event is produced and the time it is consumed. However, even in this +case, if the user calls dat_evd_wait with a threshold argument, the +events information must be copied to storage in the CQ. This is +because it is not possible to determine how many completions there are +on a CQ without dequeuing them, and that determination must be made by +the CQ notification callback in order to decide whether to wakeup a +dat_evd_wait() waiter. Note that this determination must be made +dynamically based on the arguments to dat_evd_wait(). + +Further, leaving events from Event Streams associated with the CQs "in +the CQs" until event consumption raises issues about in what order +events should be dequeued if there are multiple event streams entering +an EVD. Should the CQ events be dequeued first, or should the events +stored in the EVD be dequeued first? In general this is a complex +question; the uDAPL spec does not put many restrictions on event +order, but the major one that it does place is to restrict connection +events associated with a QP to be dequeued before DTOs associated with +that QP, and disconnection events after. Unfortunately, if we adopt +the policy of always dequeueing CQ events first, followed by EVD +events, this means that in situations where CQ events have been copied +to the EVD, CQ events may be received on the EVD out of order. + +However, leaving events from Event Streams associated with CQs allows +us to avoid enabling CQ callbacks in cases where there is no waiter +associated with the EVDs. This can be a potentially large savings of +gratuitous context switches. + +For the initial implementation, we will leave all event information +associated with CQs until dequeued by the consumer. All other event +information will be put in storage on the EVD itself. We will always +dequeue from the EVD first and the CQ second, to handle ordering among +CQ events in cases in which CQ events have been copied to the EVD. + + +Synchronization +--------------- + +-- EVD synchronization: Locking vs. Producer/Consumer queues. + +In the current code, two circular producer/consumer queues are used +for non-CQ event storage (one holds free events, one holds posted +events). Event producers "consume" events from the free queue, and +produce events onto the posted event queue. Event consumers consume +events from the posted event queue, and "produce" events onto the free +queue. In what follows, we discuss synchronization onto the posted +event queue, but since the usage of the queues is symmetric, all of +what we say also applies to the free event queue (just in the reverse +polarity). + +The reason for using these circular queues is to allow synchronization +between producer and consumer without locking in some situations. +Unfortunately, a circular queue is only an effective method of +synchronization if we can guarantee that there are only two accessors +to it at a given time: one producer, and one consumer. The model will +not work if there are multiple producers, or if there are multiple +consumers (though obviously a subsidiary lock could be used to +single-thread either the producers or the consumers). + +There are several difficulties with guaranteeing the producers and +consumers will each be single threaded in accessing the EVD: + * Constraints of the IB specification and IBM Access API + (differing sources for event streams without guarantees of + IB provider synchronization between them) make it difficult + to avoid multiple producers. + * The primitives used for the producer/consumer queue are not + as widely accepted as locks, and may render the design less + portable. + +We will take locks when needed when producing events. The details of +this plan are described below. + +This reasoning is described in more detail below to inform judgments +about future performance improvements. + +* EVD producer synchronization + +The producers fall into two classes: + * Callbacks announcing IA associated events such as connection + requests, connections, disconnections, DT ops, RMR bind, + etc. + * User calls posting a software event onto the EVD. + +It is the users responsibility to protect against simultaneous +postings of software events onto the same EVD. Similarly, the CQEH +mechanism provided by the IBM Access API allows us to avoid collisions +between IBM Access API callbacks associated with CQs. However, we +must protect against software events colliding with IBM Access API +callbacks, and against non-CQ associated IB verb callbacks (connection +events and asynchronous errors) colliding with CQ associated IBM +Access API callbacks, or with other non-CQ associated IBM Access API +callbacks (i.e. a connection callback colliding with an asynchronous +error callback). + +Note that CQ related callbacks do not act as producers on the circular +list; instead they leave the event information on the CQ until +dequeue; see "Event Storage" above. However, there are certain +situations in which it is necessary for the consumer to determine the +number of events on the EVD. The only way that IB provides to do this +is to dequeue the CQEs from the CQ and count them. In these +situations, the consumer will also act as an event producer for the +EVD event storage, copying all event information from the CQ to the +EVD. + +Based on the above, the only case in which we may do without locking +on the producer side is when all Event Streams of all of the following +types may be presumed to be single threaded: + * Software events + * Non-CQ associated callbacks + * Consumer's within dat_evd_wait + +We use a lock on the producer side of the EVD whenever we have +multiple threads of producers. + +* EVD Consumer synchronization + +It is the consumer's responsibility to avoid multiple callers into +dat_evd_wait and dat_evd_dequeue. For this reason, there is no +requirement for a lock on the consumer side. + +* CQ synchronization + +We simplify synchronization on the CQ by identifying the CQ consumer +with the EVD consumer. In other words, we prohibit any thread other +than a user thread in dat_evd_wait() or dat_evd_dequeue() from +dequeueing events from the CQ. This means that we can rely on the +uDAPL spec guarantee that only a single thread will be in the +dat_evd_wait() or dat_evd_dequeue() on a single CQ at a time. It has +the negative cost that (because there is no way to probe for the +number of entries on a CQ without dequeueing) the thread blocked in +dat_evd_wait() with a threshold argument greater than 1 will be woken +up on each notification on that CQ, in order to dequeue entries from +the CQ and determine if the threshold value has been reached. + +-- EVD Synchronization: Waiter vs. Callback + +Our decision to restrict dequeueing from the IB CQ to the user thread +(rather than the notification callback thread) means that +re-requesting notifications must also be done from that thread. This +leads to a subtle requirement for synchronization: the request for +notification (ib_completion_notify) must be atomic with the wait on +the condition variable by the user thread (atomic in the sense that +locks must be held to force the signalling from any such notification +to occur after the sleep on the condition variable). Otherwise it is +possible for the notification requested by the ib_completion_notify +call to occur before the return from that call. The signal done by +that notify will be ignored, and no further notifications will be +enabled, resulting in the thread sleep waiting forever. The CQE +associated with the notification might be noticed upon return from the +notify request, but that CQE might also have been reaped by a previous +call. + +-- CNO Synchronization + +In order to protect data items that are changed during CNO signalling +(OS Proxy Wait Object, EVD associated with triggering, CNO state), it +is necessary to use locking when triggering and waiting on a CNO. + +Note that the synchronization between trigerrer and waiter on CNO must +take into account the possibility of the waiter returning from the +wait because of a timeout. I.e. it must handle the possibility that, +even though the waiter was detected and the OS Wait Object signalled +under an atomic lock, there would be no waiter on the OS Wait Object +when it was signalled. To handle this case, we make the job of the +triggerer to be setting the state to triggered and signalling the OS +Wait Object; all other manipulation is done by the waiter. + +-- Inter-Object Synchronization + +By the requirements specified above, the DAPL implementation is +responsible for avoiding collisions between DAT Consumer calls on +different DAT objects, even in a non-thread safe implementation. +Luckily, no such collisions exist in this implementation; all exported +DAPL Event Subsystem calls involve operations only on the objects to +which they are targeted. No inter-object synchronization is +required. + +The one exception to this is the posting of a software event on an EVD +associated with a CNO; this may result in triggering the CNO. +However, this case was dealt with above in the discussion of +synchronizing between event producers and consumers; the posting of a +software event is a DAPL API call, but it's also a event producer. + +To avoid lock hierarchy issues between EVDs and CNOs and minimize lock +contention, we arrange not to hold the EVD lock when triggering the +CNO. That is the only context in which we would naturally attempt to +hold both locks. + +-- CQ -> CQEH Assignments + +For the initial implementation, we will assign all CQs to the same +CQEH. This is for simplicity and efficient use of threading +resources; we do not want to dedicate a thread per CQ (where the +number of CQs may grow arbitrarily high), and we have no way of +knowing which partitioning of CQs is best for the DAPL consumer. + +CQ Callbacks +------------ + +The responsibility of a CQ callback is to wakeup any waiters +associated with the CQ--no data needs to be dequeued/delivered, since +that is always done by the consumer. Therefore, CQ callbacks must be +enabled when: + * Any thread is in dat_evd_wait() on the EVD associated with + the CQ. + * The EVD is enabled and has a non-null CNO. (An alternative + design would be to have waiters on a CNO enable callbacks on + all CQs associated with all EVDs associated with the CNO, + but this choice does not scale well as the number of EVDs + associated with a CNO increases). + +Dynamic Resizing of EVDs +------------------------ + +dat_evd_resize() creates a special problem for the implementor, as it +requires that the storage allocated in the EVD be changed in size as +events may be arriving. If a lock is held by all operations that use +the EVD, implementation of dat_evd_resize() is trivial; it substitutes +a new storage mechanism for the old one, copying over all current +events, all under lock. + +However, we wish to avoid universal locking for the initial +implementation. This puts the implementation of dat_evd_resize() into +a tar pit. Because of the DAT Consumer requirements for a non-thread +safe DAPL Implementation, there will be no danger of conflict with +Event Consumers. However, if an Event Producer is in process of +adding an event to the circular list when the resize occurs, that +event may be lost or overwrite freed memory. + +If we are willing to make the simplifying decision that any EVD that +has non-CQ events on it will always do full producer side locking, we +can solve this problem relatively easily. Resizing of the underlying +CQ can be done via ib_cq_resize(), which we can assume available +because of the IB spec. Resizing of the EVD storage may be done under +lock, and there will be no collisions with other uses of the EVD as +all other uses of the EVD must either take the lock or are prohibitted +by the uDAPL spec. + +dat_evd_resize() has not yet been implemented in the DAPL Event +subsystem. + +Structure and pseudo-code +------------------------- + +-- EVD + +All EVDs will have associated with them: + + a lock + + A DAPL OS Wait Object + + An enabled/disabled bit + + A CNO pointer (may be null) + + A state (no_waiter, waiter, dead) + + A threshold count + + An event list + + A CQ (optional, but common) + +Posting an event to the EVD (presumably from a callback) will involve: +^ + Checking for valid state +|lock A + Putting the event on the event list +| ^lock B + Signal the DAPL OS Wait Object, if appropriate +v v (waiter & signaling event & over threshold) + + Trigger the CNO if appropriate (enabled & signaling + event & no waiter). Note that the EVD lock is not + held for this operation to avoid holding multiple locks. + +("lock A" is used if producer side locking is needed. "lock B" is +used if producer side locking is not needed. Regardless, the lock is +only held to confirm that the EVD is in the WAITED state, not for +the wakeup). + +Waiting on an EVD will include: + + Loop: + + Copy all elements from CQ to EVD + + If we have enough, break + + If we haven't enabled the CQ callback + + Enable it + + Continue + + Sleep on DAPL OS Wait Object + + Dequeue and return an event + +The CQ callback will include: + + If there's a waiter: + + Signal it + + Otherwise, if the evd is in the OPEN state, there's + a CNO, and the EVD is enabled: + + Reenable completion + + Trigger CNO + +Setting the enable/disable state of the EVD or setting the associated +CNO will simply set the bits and enable the completion if needed (if a +CNO trigger is implied); no locking is required. + +-- CNO + +All CNOs will have associated with them: + + A lock + + A DAPL OS Wait Object + + A state (triggered, untriggered, dead) + + A waiter count + + An EVD handle (last event which triggered the CNO) + + An OS Proxy Wait Object pointer (may be null) + +Triggering a CNO will involve: + ^ + If the CNO state is untriggerred: + | + Set it to triggered + | + Note the OS Proxy wait object and zero it. + | + If there are any waiters associated with the CNO, + | signal them. + v + Signal the OS proxy wait object if noted + +Waiting on a CNO will involve: + ^ + While the state is not triggered and the timeout has not occurred: + | + Increment the CNO waiter count + lock + Wait on the DAPL OS Wait Object + | + Decrement the CNO waiter count + v + If the state is trigerred, note fact&EVD and set to untrigerred. + + Return EVD and success if state was trigerred + + Return timeout otherwise + +Setting the OS Proxy Wait Object on a CNO, under lock, checks for a +valid state and sets the OS Proxy Wait Object. + + +============== +Known Problems +============== + +-- Because many event streams are actually delivered to EVDs by + callbacks, we cannot in general make any guarantees about the order + in which those event streams arrive; we are at the mercy of the + thread scheduler. Thus we cannot hold to the guarantee given by + the uDAPL 1.0 specification that within a particular EVD, + connection events on a QP will always be before successful DTO + operations on that QP. + + Because we have chosen to dequeue EVD events first and CQ events + second, we will also not be able to guarantee that all successful + DTO events will be received before a disconnect event. Ability to + probe the CQ for its number of entries would solve this problem. + + +================= +Future Directions +================= + +This section includes both functionality enhancements, and a series of +performance improvements. I mark these performance optimizations with +the following flags: + * VerbMod: Requires modifications to the IB Verbs/the IBM + Access API to be effective. + * VerbInteg: Requires integration between the DAPL + implementation and the IB Verbs implementation and IB device + driver. + +Functionality Enhancements +-------------------------- + +-- dat_evd_resize() may be implemented by forcing producer side + locking whenever an event producer may occur asynchronously with + calls to dat_evd_resize() (i.e. when there are non-CQ event streams + associated with the EVD). See the details under "Dynamic Resizing + of EVDs" above. + +-- [VerbMod] If we ahd a verbs modification allowing us to probe for + the current number of entries on a CQ, we could: + * Avoid waking up a dat_evd_wait(threshold>1) thread until + there were enough events for it. + * Avoid copying events from the CQ to the EVD to satisfy the + requirements of the "*nmore" out argument to dat_evd_wait(), + as well as the non-unary threshold argument. + * Implement the "all successful DTO operation events before + disconnect event" uDAPL guarantee (because we would no + longer have to copy CQ events to an EVD, and hence dequeue + first from the EVD and then from the CQ. + This optimization also is relevant for two of the performance + improvements cases below (Reducing context switches, and reducing + copies). + + +Performance improvements: Reducing context switches +--------------------------------------------------- +-- [VerbMod] If we had a verbs modification allowing us to probe for + the current size of a CQ, we could avoid waking up a + dat_evd_wait(threshhold>1) thread until there were enough events + for it. See the Functionality Enhancement entry covering this + possibility. + +-- [VerbMod] If we had a verbs modification allowing threads to wait + for completions to occur on CQs (presumably in the kernel in some + efficient manner), we could optimize the case of + dat_evd_wait(...,threshold=1,...) on EVDs with only a single CQ + associated Event Stream. In this case, we could avoid the extra + context switch into the user callback thread; instead, the user + thread waiting on the EVD would be woken up by the kernel directly. + +-- [VerbMod] If we had the above verbs modification with a threshold + argument on CQs, we could implement the threshold=n case. + +-- [VerbInteg] In general, It would be useful to provide ways for + threads blocked on EVDs or CNOs to sleep in the hardware driver, + and for the driver interrupt thread to determine if they should be + awoken rather than handing that determination off to another, + user-level thread. This would allow us to reduce by one the number + of context switches required for waking up the various blocked + threads. + +-- If an EVD has only a single Event Stream coming into it that is + only associated with one work queue (send or receive), it may be + possible to create thresholding by marking only ever nth WQE on + the associated send or receive WQ to signal a completion. The + difficulty with this is that the threshold is specified when + waiting on an EVD, and requesting completion signaling is + specified when posting a WQE; those two events may not in general + be synchronized enough for this strategy. It is probably + worthwhile letting the consumer implement this strategy directly if + they so choose, by specifying the correct flags on EP and DTO so + that the CQ events are only signaling on every nth completion. + They could then use dat_evd_wait() with a threshold of 1. + +Performance improvements: Reducing copying of event data +-------------------------------------------------------- +-- [VerbMod] If we had the ability to query a CQ for the number of + completions on it, we could avoid the cost of copying event data from the + CQ to the EVD. This is a duplicate of the second entry under + "Functionality Enhancements" above. + +Performance improvements: Reducing locking +------------------------------------------ +-- dat_evd_dequeue() may be modified to not take any locks. + +-- If there is no waiter associated with an EVD and there is only a + single event producer, we may avoid taking any locks in producing + events onto that EVD. This must be done carefully to handle the + case of racing with a waiter waiting on the EVD as we deliver the + event. + +-- If there is no waiter associated with an EVD, and we create a + producer/consumer queue per event stream with a central counter + modified with atomic operations, we may avoid locking on the EVD. + +-- It may be possible, though judicious use of atomic operations, to + avoid locking when triggering a CNO unless there is a waiter on the + CNO. This has not been done to keep the initial design simple. + +Performance improvements: Reducing atomic operations +---------------------------------------------------- +-- We could combine the EVD circular lists, to avoid a single atomic + operation on each production and each consumption of an event. In + this model, event structures would not move from list to list; + whether or not they had valid information on them would simply + depend on where they were on the lists. + +-- We may avoid the atomic increments on the circular queues (which + have a noticeable performance cost on the bus) if all accesses to an + EVD take locks. + + +Performance improvements: Increasing concurrency +------------------------------------------------ +-- When running on a multi-CPU platform, it may be appropriate to + assign CQs to several separate CQEHs, to increase the concurrency + of execution of CQ callbacks. However, note that consumer code is + never run within a CQ callback, so those callbacks should take very + little time per callback. This plan would only make sense in + situations where there were very many CQs, all of which were + active, and for whatever reason (high threshold, polling, etc) + user threads were usually not woken up by the execution of a + provider CQ callback. + + diff --git a/branches/WOF2-3/ulp/dapl2/doc/dapl_ibm_api_variations.txt b/branches/WOF2-3/ulp/dapl2/doc/dapl_ibm_api_variations.txt new file mode 100644 index 00000000..764e552b --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/doc/dapl_ibm_api_variations.txt @@ -0,0 +1,34 @@ + + DAPL Variations from IBM OS Access API + -------------------------------------- + +The DAPL reference implementation is targetted at the IBM OS Access +API (see doc/api/IBM_access_api.pdf). However, in the course of +developing the reference implementation it has become necessary to +alter or enhance this API specification in minor ways. This document +describes the ways in which the Access API has been altered to +accomodate the needs of the reference implementation. + +Note that this document is a work in progress/a place holder; it does +not yet contain all of the API variations used by the reference +implementation. It is intended that it will be brought up to date +before the final release of the DAPL reference implementation. + +The variations from the IBM OS Access API are listed below. + +-- Thread safety + +The IBM OS Access API specifies: + +"Implementation of the Access APIs should ensure that multiple threads + can call the APIs, provided they do not access the same InfiniBand + entity (such as a queue pair or a completion queue)." + +This has been extended in two ways: + * It is safe for multiple threads to call into the API + accessing the same HCA. + * Threads calling ib_post_send_req on a particular QP do not + conflict with threads calling ib_post_rcv_req on the same + QP. I.e. while there cannot be multiple threads in + ib_post_send_req or ib_post_rcv_req on the same QP, there + may be one thread in each routine simultaneously. diff --git a/branches/WOF2-3/ulp/dapl2/doc/dapl_memory_management_design.txt b/branches/WOF2-3/ulp/dapl2/doc/dapl_memory_management_design.txt new file mode 100644 index 00000000..09ff153e --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/doc/dapl_memory_management_design.txt @@ -0,0 +1,173 @@ +####################################################################### +# # +# DAPL Memory Management Design # +# # +# James Lentini # +# jlentini at users.sourceforge.net # +# # +# Created 05/06/2002 # +# Updated 08/22/2002 # +# # +####################################################################### + + +Contents +------- +0. Introduction +1. Protection Zones (PZs) +2. Local Memory Regions (LMRs) +3. Remote Memory Regions (RMRs) + + +0. Introduction +--------------- + + The memory management subsystem allows consumers to register and +unregister memory regions. The DAT API distinguishes between local +and remote memory areas. The former server as local buffers for DTO +operations while the later are used for RDMA operations. + +Each DAT function is implemented in a file named dapl_.c. +For example, dat_pz_create is implemented in dapl_pz_create.c. There +are also dapl__util.{h,c} files for each object. For +example, there are dapl_pz_util.h and dapl_pz_util.c files. The +use of util files follows the convention used elsewhere in the DAPL +reference provider. These files contain common object creation and +destruction code. + + +1. Protection Zones (PZs) +------------------------- + + DAPL protection zones provide consumers with a means to associate +various DAPL objects with one another. The association can then be +validated before allowing these objects to be manipulated. The DAT +functions related to PZs are: + +dat_pz_create +dat_pz_free +dat_pz_query + +These are implemented in the DAPL reference provider by + +dapl_pz_create +dapl_pz_free +dapl_pz_query + +The reference implementation maps the DAPL PZ concept onto Infiniband +protections domains (PDs). + +The DAT_PZ_HANDLE value returned to DAT consumers is a pointer to a +DAPL_PZ data structure. The DAPL_PZ structure is used to represent all +PZ objects. Code that manipulates this structure should atomically +increment and decrement the ref_count member to track the number of +objects referencing the PZ. + + +2. Local Memory Regions (LMRs) +------------------------------ + + DAPL local memory regions represent a memory area on the host +system that the consumer wishes to access via local DTO operations. +The DAT functions related to LMRs are: + +dat_lmr_create +dat_lmr_free +dat_lmr_query + +These are implemented in + +dapl_lmr_create +dapl_lmr_free +dapl_lmr_query + +In the reference implementation, DAPL LMRs are mapped onto +Infiniband memory regions (MRs). + +LMR creation produces two values: a DAT_LMR_CONTEXT and a +DAT_LRM_HANDLE. + +The DAT_LMR_CONTEXT value is used to uniquely identify the LMR +when posting data transfer operations. These values map directly +to Infiniband L_KEYs. + +Since some DAT functions need to translate a DAT_LMR_CONTEXT value +into a DAT_LMR_HANDLE (ex. dat_rmr_bind), a dictionary data structure +is used to associate DAT_LMR_CONTEXT values with their corresponding +DAT_LMR_HANDLE. Each time a new LMR is created, the DAT_LMR_HANDLE +should be inserted into the dictionary with the associated +DAT_LMR_CONTEXT as the key. + +A hash table was chosen to implement this data structure. Since the +L_KEY values are being used by the CA hardware for indexing purposes, +there distribution is expected to be uniform and hence ideal for hashing. + +The DAT_LMR_HANDLE value returned to DAT consumers is a pointer to +a DAPL_LMR data structure. The DAPL_LMR structure is used to represent +all LMR objects. The ref_count member should be used to track objects +associated with a given LMR. + +The DAT API exposes the DAT_LMR_CONTEXT to consumers to allow +for sharing of memory registrations between multiple address spaces. +The mechanism by which such a feature would be implemented does not +yet exist. Consumers may be able to take advantage of this +feature on future transports. + + +3. Remote Memory Regions (RMRs) +------------------------------- + + DAPL remote memory regions represent a memory area on the host +system to which the consumer wishes to allow RMDA operations. The +related DAT functions are + +dat_rmr_create +dat_rmr_free +dat_rmr_query +dat_rmr_bind + +which are implemented in + +dapl_rmr_create +dapl_rmr_free +dapl_rmr_query +dapl_rmr_bind + +The reference provider maps RMR objects onto Infiniband memory +windows. + +The DAT_RMR_HANDLE value returned to DAT consumers is a pointer to +a DAPL_RMR data structure. The DAPL_RMR structure is used to represent +all RMR objects. + +The API for binding a LMR to a RMR has the following function +signature: + +DAT_RETURN +dapl_rmr_bind ( + IN DAT_RMR_HANDLE rmr_handle, + IN const DAT_LMR_TRIPLET *lmr_triplet, + IN DAT_MEM_PRIV_FLAGS mem_priv, + IN DAT_EP_HANDLE ep_handle, + IN DAT_RMR_COOKIE user_cookie, + IN DAT_COMPLETION_FLAGS completion_flags, + OUT DAT_RMR_CONTEXT *rmr_context ) + +where a DAT_LMR_TRIPLET is defined as: + +typedef struct dat_lmr_triplet + { + DAT_LMR_CONTEXT lmr_context; + DAT_UINT32 pad; + DAT_VADDR virtual_address; + DAT_VLEN segment_length; + } DAT_LMR_TRIPLET; + +In the case of IB, the DAT_LMR_CONTEXT value is a L_KEY. +As described in the IB spec, the Bind Memory Window verb +takes both a L_KEY and Memory Region Handle among other +parameters. Therefore a data structure must be used to +map a DAT_LMR_CONTEXT (L_KEY) value to a DAPL_LMR so +that the needed memory region handle can be retrieved. +The LMR hash table described above is used for this +purpose. diff --git a/branches/WOF2-3/ulp/dapl2/doc/dapl_patch.txt b/branches/WOF2-3/ulp/dapl2/doc/dapl_patch.txt new file mode 100644 index 00000000..5bc5f9d2 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/doc/dapl_patch.txt @@ -0,0 +1,83 @@ +####################################################################### +# # +# DAPL Patch Guide # +# # +# James Lentini # +# jlentini at users.sourceforge.net # +# # +# Created 03/30/2005 # +# Version 1.0 # +# # +####################################################################### + + +Overview +-------- + +The DAPL Reference Implementation (RI) Team welcomes code contributions +and bug fixes from RI users. This document describes the format for +submitting patches to the project. + +Directions +---------- + +When implementing a new feature or bug fix, please remember to: + ++ Use the project coding style, described in doc/dapl_coding_style.txt ++ Remember that the RI supports multiple platforms and transports. If + your modification is not applicable to all platforms and transports, + please ensure that the implement does not affect these other + configurations. + +When creating the patch: + ++ Create the patch using a unified diff as follows: + diff -Naur old-code new-code > patch ++ Create the patch from the root of the CVS tree. + +When submitting the patch: + ++ Compose an email message containing a brief description of the patch, + a signed-off by line, and the patch. ++ Have the text "[PATCH]" at the start of the subject line ++ Send the message to dapl-devel@lists.sourceforge.net + +Example +------- + +Here is an example patch message: + +------------------------------------------------------------ +Date: 30 Mar 2005 11:49:45 -0500 +From: Jane Doe +To: dapl-devel@lists.sourceforge.net +Subject: [PATCH] fixed status returns + +Here's a patch to fix the status return value in +dats_handle_vector_init(). + +Signed-off-by: Jane Doe + +--- dat/common/dat_api.c~ 2005-03-30 11:58:40.838968000 -0500 ++++ dat/common/dat_api.c 2005-03-28 12:33:29.502076000 -0500 +@@ -70,16 +70,15 @@ + { + DAT_RETURN dat_status; + int i; +- int status; + + dat_status = DAT_SUCCESS; + + g_hv.handle_max = DAT_HANDLE_ENTRY_STEP; + +- status = dat_os_lock_init (&g_hv.handle_lock); +- if ( DAT_SUCCESS != status ) ++ dat_status = dat_os_lock_init (&g_hv.handle_lock); ++ if ( DAT_SUCCESS != dat_status ) + { +- return status; ++ return dat_status; + } + + g_hv.handle_array = dat_os_alloc (sizeof(void *) * DAT_HANDLE_ENTRY_STEP); +------------------------------------------------------------ diff --git a/branches/WOF2-3/ulp/dapl2/doc/dapl_registry_design.txt b/branches/WOF2-3/ulp/dapl2/doc/dapl_registry_design.txt new file mode 100644 index 00000000..7215cc0b --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/doc/dapl_registry_design.txt @@ -0,0 +1,631 @@ + DAT Registry Subsystem Design v. 0.90 + ------------------------------------- + +================= +Table of Contents +================= + +* Table of Contents +* Referenced Documents +* Introduction +* Goals +* Provider API +* Consumer API +* Registry Design + + Registry Database + + Provider API pseudo-code + + Consumer API pseudo-code + + Platform Specific API pseudo-code + +==================== +Referenced Documents +==================== + +uDAPL: User Direct Access Programming Library, Version 1.0. Published +6/21/2002. http://www.datcollaborative.org/uDAPL_062102.pdf. Referred +to in this document as the "DAT Specification". + +============ +Introduction +============ + +The DAT architecture supports the use of multiple DAT providers within +a single consumer application. Consumers implicitly select a provider +using the Interface Adapter name parameter passed to dat_ia_open(). + +The subsystem that maps Interface Adapter names to provider +implementations is known as the DAT registry. When a consumer calls +dat_ia_open(), the appropriate provider is found and notified of the +consumer's request to access the IA. After this point, all DAT API +calls acting on DAT objects are automatically directed to the +appropriate provider entry points. + +A persistent, administratively configurable database is used to store +mappings from IA names to provider information. This provider +information includes: the file system path to the provider library +object, version information, and thread safety information. The +location and format of the registry is platform dependent. This +database is know as the Static Registry (SR). The process of adding a +provider entry is termed Static Registration. + +Within each DAT consumer, there is a per-process database that +maps from ia_name -> provider information. When dat_ia_open() is +called, the provider library is loaded, the ia_open_func is found, and +the ia_open_func is called. + +===== +Goals +===== + +-- Implement the registration mechanism described in the uDAPL + Specification. + +-- The DAT registry should be thread safe. + +-- On a consumer's performance critical data transfer path, the DAT + registry should not require any significant overhead. + +-- The DAT registry should not limit the number of IAs or providers + supported. + +-- The user level registry should be tolerant of arbitrary library + initialization orders and support calls from library initialization + functions. + +============ +Provider API +============ + +Provider libraries must register themselves with the DAT registry. +Along with the Interface Adapter name they wish to map, they must +provide a routines vector containing provider-specific implementations +of all DAT APIs. If a provider wishes to service multiple Interface +Adapter names with the same DAT APIs, it must register each name +separately with the DAT registry. The Provider API is not exposed to +consumers. + +The user level registry must ensure that the Provider API may be +called from a library's initialization function. Therefore the +registry must not rely on a specific library initialization order. + + DAT_RETURN + dat_registry_add_provider( + IN DAT_PROVIDER *provider ) + +Description: Allows the provider to add a mapping. It will return an +error if the Interface Adapter name already exists. + + DAT_RETURN + dat_registry_remove_provider( + IN DAT_PROVIDER *provider ) + +Description: Allows the Provider to remove a mapping. It will return +an error if the mapping does not already exist. + +============ +Consumer API +============ + +Consumers that wish to use a provider library call the DAT registry to +map Interface Adapter names to provider libraries. The consumer API is +exposed to both consumers and providers. + + DAT_RETURN + dat_ia_open ( + IN const DAT_NAME device_name, + IN DAT_COUNT async_event_qlen, + INOUT DAT_EVD_HANDLE *async_event_handle, + OUT DAT_IA_HANDLE *ia_handle ) + +Description: Upon success, this function returns an DAT_IA_HANDLE to +the consumer. This handle, while opaque to the consumer, provides +direct access to the provider supplied library. To support this +feature, all DAT_HANDLEs must be pointers to a pointer to a +DAT_PROVIDER structure. + + DAT_RETURN + dat_ia_close ( + IN DAT_IA_HANDLE ia_handle ) + +Description: Closes the Interface Adapter. + + DAT_RETURN + dat_registry_list_providers( + IN DAT_COUNT max_to_return, + OUT DAT_COUNT *entries_returned, + OUT DAT_PROVIDER_INFO *(dat_provider_list[]) ) + +Description: Lists the current mappings. + +=============== +Registry Design +=============== + +There are three separate portions of the DAT registry system: + +* Registry Database + +* Provider API + +* Consumer API + +We address each of these areas in order. The final section will +describe any necessary platform specific functions. + +Registry Database +----------------- + +Static Registry +................ + +The Static Registry is a persistent database containing provider +information keyed by Interface Adapter name. The Static Registry will +be examined once when the DAT library is loaded. + +There is no synchronization mechanism protecting access to the Static +Registry. Multiple readers and writers may concurrently access the +Static Registry and as a result there is no guarantee that the +database will be in a consistent format at any given time. DAT +consumers should be aware of this and not run DAT programs when the +registry is being modified (for example, when a new provider is being +installed). However, the DAT library must be robust enough to recognize +an inconsistent Static Registry and ignore invalid entries. + +Information in the Static Registry will be used to initialize the +registry database. The registry will refuse to load libraries for DAT +API versions different than its DAT API version. Switching API +versions will require switching versions of the registry library (the +library explicitly placed on the link line of DAPL programs) as well +as the header files included by the program. + +Set DAT_NO_STATIC_REGISTRY at compile time if you wish to compile +DAT without a static registry. + +UNIX Registry Format +..................... + +The UNIX registry will be a plain text file with the following +properties: + * All characters after # on a line are ignored (comments). + * Lines on which there are no characters other than whitespace + and comments are considered blank lines and are ignored. + * Non-blank lines must have seven whitespace separated fields. + These fields may contain whitespace if the field is quoted + with double quotes. Within fields quoated with double quotes, + the following are valid escape sequences: + + \\ backslash + \" quote + + * Each non-blank line will contain the following fields: + + - The IA Name. + - The API version of the library: + [k|u]major.minor where "major" and "minor" are both integers + in decimal format. Examples: "k1.0", "u1.0", and "u1.1". + - Whether the library is thread-safe: + [threadsafe|nonthreadsafe] + - Whether this is the default section: [default|nondefault] + - The path name for the library image to be loaded. + - The version of the driver: major.minor, for example, "5.13". + +The format of any remaining fields on the line is dependent on the API +version of the library specified on that line. For API versions 1.0 +and 1.1 (both kDAPL and uDAPL), there is only a single additional +field, which is: + + - An optional string with instance data, which will be passed to + the loaded library as its run-time arguments. + +This file format is described by the following grammar: + + -> | + -> + [|] | + [| -> string + -> [k|u]decimal.decimal + -> [threadsafe|nonthreadsafe] + -> [default|nondefault] + -> string + -> decimal.decimal + -> string + -> end of file + -> newline + +The location of this file may be specified by setting the environment +variable DAT_CONF. If DAT_CONF is not set, the default location will +be /etc/dat.conf. + +Windows Registry Format +....................... + +Standardization of the Windows registry format is not complete at this +time. + +Registry Database Data Structures +................................. + +The Registry Database is implemented as a dictionary data structure that +stores (key, value) pairs. + +Initially the dictionary will be implemented as a linked list. This +will allow for an arbitrary number of mappings within the resource +limits of a given system. Although the search algorithm will have O(n) +worst case time when n elements are stored in the data structure, we +do not anticipate this to be an issue. We believe that the number of +IA names and providers will remain relatively small (on the order of +10). If performance is found to be an issue, the dictionary can be +re-implemented using another data structure without changing the +Registry Database API. + +The dictionary uses IA name strings as keys and stores pointers to a +DAT_REGISTRY_ENTRY structure, which contains the following +information: + + - provider library path string, library_path + - DAT_OS_LIBRARY_HANDLE, library_handle + - IA parameter string, ia_params + - DAT_IA_OPEN_FUNC function pointer, ia_open_func + - thread safety indicator, is_thread_safe + - reference counter, ref_count + +The entire registry database data structure is protected by a single +lock. All threads that wish to query/modify the database must posses +this lock. Serializing access in this manner is not expected to have a +detrimental effect on performance as contention is expected to be +minimal. + +An important property of the registry is that entries may be inserted +into the registry, but no entries are ever removed. The contents of +the static registry are used to populate the initially empty registry +database. Since these mapping are by definition persistent, no +mechanism is provided to remove them from the registry database. + +NOTE: There is currently no DAT interface to set a provider's IA +specific parameters. A solution for this problem has been proposed for +uDAPL 1.1. + +Registry Database API +..................... + +The static variable Dat_Registry_Db is used to store information about +the Registry Database and has the following members: + + - lock + - dictionary + +The Registry Database is accessed via the following internal API: + +Algorithm: dat_registry_init + Input: void + Output: DAT_RETURN +{ + initialize Dat_Registry_Db + + dat_os_sr_load() +} + +Algorithm: dat_registry_insert + Input: IN const DAT_STATIC_REGISTRY_ENTRY sr_entry + Output: DAT_RETURN +{ + dat_os_lock(&Dat_Registry_Db.lock) + + create and initialize DAT_REGISTRY_ENTRY structure + + dat_dictionary_add(&Dat_Registry_Db.dictionary, &entry) + + dat_os_unlock(&Dat_Registry_Db.lock) +} + +Algorithm: dat_registry_search + Input: IN const DAT_NAME_PTR ia_name + IN DAT_REGISTRY_ENTRY **entry + Output: DAT_RETURN +{ + dat_os_lock(&Dat_Registry_Db.lock) + + entry gets dat_dictionary_search(&Dat_Registry_Db.dictionary, &ia_name) + + dat_os_unlock(&Dat_Registry_Db.lock) +} + +Algorithm: dat_registry_list + Input: IN DAT_COUNT max_to_return + OUT DAT_COUNT *entries_returned + OUT DAT_PROVIDER_INFO *(dat_provider_list[]) + Output: DAT_RETURN +{ + dat_os_lock(&Dat_Registry_Db.lock) + + size = dat_dictionary_size(Dat_Registry_Db.dictionary) + + for ( i = 0, j = 0; + (i < max_to_return) && (j < size); + i++, j++ ) + { + initialize dat_provider_list[i] w/ j-th element in dictionary + } + + dat_os_unlock(&Dat_Registry_Db.lock) + + *entries_returned = i; +} + +Provider API pseudo-code +------------------------ + ++ dat_registry_add_provider() + +Algorithm: dat_registry_add_provider + Input: IN DAT_PROVIDER *provider + Output: DAT_RETURN +{ + dat_init() + + dat_registry_search(provider->device_name, &entry) + + if IA name is not found then dat_registry_insert(new entry) + + if entry.ia_open_func is not NULL return an error + + entry.ia_open_func = provider->ia_open_func +} + ++ dat_registry_remove_provider() + +Algorithm: dat_registry_remove_provider + Input: IN DAT_PROVIDER *provider + Output: DAT_RETURN +{ + dat_init() + + dat_registry_search(provider->device_name, &entry) + + if IA name is not found return an error + + entry.ia_open_func = NULL +} + +Consumer API pseudo-code +------------------------ + +* dat_ia_open() + +This function looks up the specified IA name in the ia_dictionary, +loads the provider library, retrieves a function pointer to the +provider's IA open function from the provider_dictionary, and calls +the providers IA open function. + +Algorithm: dat_ia_open + Input: IN const DAT_NAME_PTR name + IN DAT_COUNT async_event_qlen + INOUT DAT_EVD_HANDLE *async_event_handle + OUT DAT_IA_HANDLE *ia_handle + Output: DAT_RETURN + +{ + dat_registry_search(name, &entry) + + if the name is not found return an error + + dat_os_library_load(entry.library_path, &entry.library_handle) + + if the library fails to load return an error + + if the entry's ia_open_func is invalid + { + dl_os_library_unload(entry.library_handle) + return an error + } + + (*ia_open_func) (name, + async_event_qlen, + async_event_handle, + ia_handle); +} + +* dat_ia_close() + +Algorithm: dat_ia_close + Input: IN DAT_IA_HANDLE ia_handle + IN DAT_CLOSE_FLAGS ia_flags + Output: DAT_RETURN +{ + provider = DAT_HANDLE_TO_PROVIDER(ia_handle) + + (*provider->ia_close_func) (ia_handle, ia_flags) + + dat_registry_search(provider->device_name, &entry) + + dat_os_library_unload(entry.library_handle) +} + ++ dat_registry_list_providers() + +Algorithm: dat_registry_list_providers + Input: IN DAT_COUNT max_to_return + OUT DAT_COUNT *entries_returned + OUT DAT_PROVIDER_INFO *(dat_provider_list[]) + Output: DAT_RETURN +{ + validate parameters + + dat_registry_list(max_to_return, entries_returned, dat_provider_list) +} + +Platform Specific API pseudo-code +-------------------------------- + +Below are descriptions of platform specific functions required by the +DAT Registry. These descriptions are for Linux. + +Each entry in the static registry is represented by an OS specific +structure, DAT_OS_STATIC_REGISTRY_ENTRY. On Linux, this structure will +have the following members: + + - IA name string + - API version + - thread safety + - default section + - library path string + - driver version + - IA parameter string + +The tokenizer will return a DAT_OS_SR_TOKEN structure +containing: + + - DAT_OS_SR_TOKEN_TYPE value + - string with the fields value + +The tokenizer will ignore all white space and comments. The tokenizer +will also translate any escape sequences found in a string. + +Algorithm: dat_os_sr_load + Input: n/a + Output: DAT_RETURN +{ + if DAT_CONF environment variable is set + static_registry_file = contents of DAT_CONF + else + static_registry_file = /etc/dat.conf + + sr_fd = dat_os_open(static_registry_file) + + forever + { + initialize DAT_OS_SR_ENTRY entry + + do + { + // discard blank lines + dat_os_token_next(sr_fd, &token) + } while token is newline + + if token type is EOF then break // all done + // else the token must be a string + + entry.ia_name = token.value + + dat_os_token_next(sr_fd, &token) + + if token type is EOF then break // all done + else if token type is not string then + { + // an error has occurred + dat_os_token_sync(sr_fd) + continue + } + else if ( dat_os_convert_api(token.value, &entry.api) fails ) + { + // an error has occurred + dat_os_token_sync(sr_fd) + continue + } + + dat_os_token_next(sr_fd, &token) + + if token type is EOF then break // all done + else if token type is not string then + { + // an error has occurred + dat_os_token_sync(sr_fd) + continue + } + else if ( dat_os_convert_thread_safety(token.value, &entry.thread_safety) fails ) + { + // an error has occurred + dat_os_token_sync(sr_fd) + continue + } + + dat_os_token_next(sr_fd, &token) + + if token type is EOF then break // all done + else if token type is not string then + { + // an error has occurred + dat_os_token_sync(sr_fd) + continue + } + else if ( dat_os_convert_default(token.value, &entry.default) fails ) + { + // an error has occurred + dat_os_token_sync(sr_fd) + continue + } + + dat_os_token_next(sr_fd, &token) + + if token type is EOF then break // all done + else if token type is not string then + { + // an error has occurred + dat_os_token_sync(sr_fd) + continue + } + + entry.lib_path = token.value + + dat_os_token_next(sr_fd, &token) + + if token type is EOF then break // all done + else if token type is not string then + { + // an error has occurred + dat_os_token_sync(sr_fd) + continue + } + else if ( dat_os_convert_driver_version(token.value, &entry.driver_version) fails ) + { + // an error has occurred + dat_os_token_sync(sr_fd) + continue + } + + dat_os_token_next(sr_fd, &token) + + if token type is EOF then break // all done + else if token type is not string then + { + // an error has occurred + dat_os_token_sync(sr_fd) + continue + } + + entry.ia_params = token.value + + dat_os_token_next(sr_fd, &token) + + if token type is EOF then break // all done + else if token type is not newline then + { + // an error has occurred + dat_os_token_sync(sr_fd) + continue + } + + if ( dat_os_sr_is_valid(entry) ) + { + dat_registry_insert(entry) + } + } + + dat_os_close(sr_fd) +} + +Algorithm: dat_os_library_load + Input: IN const DAT_NAME_PTR *library_path + OUT DAT_LIBRARY_HANDLE *library_handle + Output: DAT_RETURN +{ + *library_handle = dlopen(library_path); +} + +Algorithm: dat_os_library_unload + Input: IN const DAT_LIBRARY_HANDLE library_handle + Output: DAT_RETURN +{ + dlclose(library_handle) +} diff --git a/branches/WOF2-3/ulp/dapl2/doc/dapl_shared_memory_design.txt b/branches/WOF2-3/ulp/dapl2/doc/dapl_shared_memory_design.txt new file mode 100644 index 00000000..f4f35240 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/doc/dapl_shared_memory_design.txt @@ -0,0 +1,876 @@ +####################################################################### +# # +# DAPL Shared Memory Design # +# # +# James Lentini # +# jlentini at users.sourceforge.net # +# # +# Created 09/17/2002 # +# Updated 01/21/2005 # +# Version 0.04 # +# # +####################################################################### + + +Contents +-------- +0. Introduction +1. Referenced Documents +2. Requirements +3. Interface +4. Implementation Options + + +Introduction +------------ + +This document describes the design of shared memory registration for +the DAPL reference implementation (RI). + +Implementing shared memory support completely within the DAPL RI +would not be an ideal solution. A more robust and efficient +implementation can be acheived by HCA vendors that integrate a DAT +provider into their software stack. Therefore the RI will not contain +an implementation of this feature. + + +Referenced Documents +-------------------- + +kDAPL: Kernel Direct Access Programming Library, Version 1.2. +uDAPL: User Direct Access Programming Library, Version 1.2. +Available in the DAPL SourceForge repository at +[doc/api/kDAPL_spec.pdf] and [doc/api/uDAPL_spec.pdf]. Collectively +referred to in this document as the "DAT Specification". + +InfiniBand Access Application Programming Interface Specification, +Version 1.2, 4/15/2002. Available in the DAPL SourceForge repository +at [doc/api/IBM_access_api.pdf]. Referred to in this document as the +"IBM Access API Specification". + +Mellanox IB-Verbs API (VAPI) Mellanox Software Programmers Interface +for InfiniBand Verbs. Available in the DAPL SourceForge repository +at [doc/api/MellanoxVerbsAPI.pdf]. Referred to in this document as the +"VAPI API Specification". + +InfiniBand Architecture Specification, Volumes 1 and 2, Release +1.2, Available from http://www.infinibandta.org/ +Referred to in this document as the "Infiniband Specification". + + +Requirements +------------ + +The DAT shared memory model can be characterized as a peer-to-peer +model since the order in which consumers register a region is not +dictated by the programming interface. + +The DAT API function used to register shared memory is: + +DAT_RETURN +dat_lmr_create ( + IN DAT_IA_HANDLE ia_handle, + IN DAT_MEM_TYPE mem_type, + IN DAT_REGION_DESCRIPTION region_description, + IN DAT_VLEN length, + IN DAT_PZ_HANDLE pz_handle, + IN DAT_MEM_PRIV_FLAGS mem_privileges, + OUT DAT_LMR_HANDLE *lmr_handle, + OUT DAT_LMR_CONTEXT *lmr_context, + OUT DAT_RMR_CONTEXT *rmr_context, + OUT DAT_VLEN *registered_length, + OUT DAT_VADDR *registered_address ); + +where a DAT_REGION_DESCRIPTION is defined as: + +typedef union dat_region_description +{ + DAT_PVOID for_va; + DAT_LMR_HANDLE for_lmr_handle; + DAT_SHARED_MEMORY for_shared_memory; +} DAT_REGION_DESCRIPTION; + +In the case of a shared memory registration the DAT consumer will set +the DAT_MEM_TYPE flag to DAT_MEM_TYPE_SHARED_VIRTUAL and place a +cookie in the DAT_REGION_DESCRIPTION union's DAT_SHARED_MEMORY +member. The DAT_SHARED_MEMORY type is defined as follows: + +typedef struct dat_shared_memory +{ + DAT_PVOID virtual_address; + DAT_LMR_COOKIE shared_memory_id; +} DAT_SHARED_MEMORY; + +Unlike the DAT peer-to-peer model, the Infiniband shared memory model +requires a master-slave relationship. A memory region must first be +registered using the Register Memory Region verb with subsequent +registrations made using the Register Shared Memory Region verb. + +The later is implemented in the IBM OS Access API as: + +ib_int32_t +ib_mr_shared_register_us( + ib_hca_handle_t hca_handle, + ib_mr_handle_t *mr_handle, /* IN-OUT: could be changed */ + ib_pd_handle_t pd_handle, /* IN */ + ib_uint32_t access_control, /* IN */ + ib_uint32_t *l_key, /* OUT */ + ib_uint32_t *r_key, /* OUT: if remote access needed */ + ib_uint8_t **va ); /* IN-OUT: virt. addr. to register */ + +The important parameter is the memory region handle which must be the +same as an already registered region. + +Two requirements are implied by this difference between the DAT and +Infiniband models. First, DAPL implementations need a way to determine +the first registration of a shared region. Second implementations must +map DAT_LMR_COOKIE values to memory region handles both within and +across processes. To satisfy the above requirements DAPL must maintain +this information in a system wide database. + +The difficulty of implementing such a database at the DAT provider +level is the reason the RI's shared memory code is meant to be +temporary. Such a database is much better suited as part of the HCA +vendor's software stack, specifically as part of their HCA driver. + +If DAPL was based on a master-slave model like InfiniBand, the +implementation of shared memory would be straight +forward. Specifically the complexity is a result of the consumer being +responsible for specifying the DAT_LMR_COOKIE values. If the DAPL +spec. were changed to allow the provider and not the consumer to +specify the DAT_LMR_COOKIE value, the implementation of this feature +would be greatly simplified. Since the DAPL API already requires +consumers to communicate the DAT_LMR_COOKIE values between processes, +such a change places minimal additional requirements on the +consumer. The dapl_lmr_query call could easily be adapted to allow the +consumer to query the provider for a given LMR's DAT_LMR_COOKIE +value. The only spec changes needed would be to add a DAT_LMR_COOKIE +member to the DAT_LMR_PARAM structure and a DAT_LMR_FIELD_LMR_COOKIE +constant to the DAT_LMR_PARAM_MASK enumeration. A provider could then +store the given LMR's memory region handle in this value, greatly +simplifying the implementation of shared memory in DAPL. + + +Interface +--------- + +To allow the database implementation to easily change, the RI would use +a well defined interface between the memory subsystem and the +database. Conceptually the database would contain a single table with +the following columns: + +[ LMR Cookie ][ MR Handle ][ Reference Count ][ Initialized ] + +where the LMR Cookie column is the primary key. + +The following functions would be used to access the database: + +DAT_RETURN +dapls_mrdb_init ( + void ); + + Called by dapl_init(.) to perform any necessary database + initialization. + +DAT_RETURN +dapls_mrdb_exit ( + void ); + + Called by dapl_fini(.) to perform any necessary database cleanup. + +DAT_RETURN +dapls_mrdb_record_insert ( + IN DAPL_LMR_COOKIE cookie ); + + If there is no record for the specified cookie, an empty record is + added with a reference count of 1 and the initialized field is set to + false. If a record already exists, the function returns an error. + +DAT_RETURN +dapls_mrdb_record_update ( + IN DAPL_LMR_COOKIE cookie, + IN ib_mr_handle_t mr_handle ); + + If there is a record for the specified cookie, the MR handle field is + set to the specified mr_handle value and the initialized field is set + to true. Otherwise an error is returned. + +DAT_RETURN +dapls_mrdb_record_query ( + IN DAPL_LMR_COOKIE cookie, + OUT ib_mr_handle_t *mr_handle ); + + If there is a record for the specified cookie and the initialized + field is true, the MR handle field is returned and the reference + count field is incremented. Otherwise an error is returned. + +DAT_RETURN +dapls_mrdb_record_dec ( + IN DAPL_LMR_COOKIE cookie ); + + If there is a record for the specified cookie, the reference count + field is decremented. If the reference count is zero after the + decrement, the record is removed from the database. Otherwise an + error is returned. + +The generic algorithms for creating and destroying a shared memory +region are: + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: CreateShared + Inputs: + ia_handle + pz_handle + address + length + lmr_cookie + privileges + Outputs: + lmr_handle + lmr_context + registered_address + registered_length + +forever +{ + if dapls_mrdb_record_insert(cookie) is successful + { + if dapl_lmr_create_virtual is not successful + dapls_mrdb_record_dec(cookie) + return error + + else if dapls_mrdb_record_update(cookie, lmr->mr_handle) is not successful + dapls_mrdb_record_dec(cookie) + return error + + else break + } + else if dapls_mrdb_record_query(cookie, mr_handle) is successful + { + if ib_mrdb_shared_register_us is not successful + dapls_mrdb_record_dec(cookie) + return error + + else break + } +} + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: FreeShared + Inputs: + lmr + Outputs: + +if dapls_ib_mr_deregister(lmr) is successful + dapls_mrdb_record_dec(lmr->cookie) + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + +Implementation Options +---------------------- + +As described above the crucial functionality needed to implement +shared memory support is a system wide database for mapping LMR +cookies to memory region handles. The following designs represent some +of the options for implementing such a database. Adding a database +increases the complexity of DAPL from both an implementor and user's +perspective. These designs should be evaluated on the degree to which +they minimize the additional complexity while still providing a robust +solution. + + + File System Database + -------------------- + +Employing a database that is already part of the system would be +ideal. One option on Linux is to use the file system. An area of the +file system could be set aside for the creation of files to represent +each LMR cookie. The area of the file system could be specified +through a hard coded value, an environment variable, or a +configuration file. A good candidate would be a DAPL subdirectory of +/tmp. + +Exclusive file creation is available through the creat(2) system call +in Linux. The standard I/O interface (fopen(3), etc.) does not support +this feature making porting difficult. However porting to other +environments is not a goal of this design since the entire scheme is +only a temporary solution. + +Determining when to delete the files is a difficult problem. A +reference count is required to properly remove a file once all the +memory regions it represents are deregistered. The synchronization +mechanism necessary for maintaining the reference count is not easily +implemented. As an alternative, a script could be provided to clean up +the database by removing all the files. The script would need to be +run before any DAPL consumers were started to ensure a clean +database. The disadvantage of using a script is that no DAPL instances +can be running when it is used. Another option would be to store the +process ID (PID) of the process that created the file as part of the +file's contents. Upon finding a record for a given LMR cookie value, a +DAPL instance could determine if there was a process with the same PID +in the system. To accomplish this the kill(2) system call could be +used (ex. kill(pid, 0) ). This method of validating the record assumes +that all DAPL instances can signal one another and that the PID values +do not wrap before the check is made. + +Another difficulty with this solution is choosing an accessible +portion of the file system. The area must have permissions that allow +all processes using DAPL to access and modify its contents. System +administrators are typically reluctant to allow areas without any +access controls. Typically such areas are on a dedicated file system +of a minimal size to ensure that malicious or malfunctioning software +does not monopolize the system's storage capacity. Since very little +information will be stored in each file it is unlikely that DAPL would +need a large amount of storage space even if a large number of shared +memory regions were in use. However since a file is needed for each +shared region, a large number of shared registrations may lead to the +consumption of all a file system's inodes. Again since this solution +is meant to be only temporary this constraint may be acceptable. + +There is also the possibility for database corruption should a process +crash or deadlock at an inopportune time. If a process creates file x +and then crashes all other processes waiting for the memory handle to +be written to x will fail. + +The database interface could be implemented as follows: + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: dapls_mrdb_init + Inputs: + + Outputs: + +return success + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: dapls_mrdb_exit + Inputs: + + Outputs: + +return success + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: dapls_mrdb_record_insert + Inputs: + cookie + Outputs: + +file_name = convert cookie to valid file name + +fd = exclusively create file_name +if fd is invalid + return failure + +if close fd fails + return failure + +return success + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: dapls_mrdb_record_update + Inputs: + cookie + mr_handle + Outputs: + +file_name = convert cookie to valid file name + +fd = open file_name +if fd is invalid + return failure + +if write mr_handle to file_name fails + return failure + +if close fd fails + return failure + +return success + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: dapls_mrdb_record_query + Inputs: + cookie + + Outputs: + mr_handle + +file_name = convert cookie to valid file name + +fd = open file_name +if fd is invalid + return failure + +if read mr_handle from file_name fails + return failure + +if close fd fails + return failure + +return success + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: dapls_mrdb_record_dec + Inputs: + cookie + Outputs: + +return success + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + + Daemon Database + --------------- + +The database could be maintained by a separate daemon process. +The DAPL instances would act as clients of the daemon server and +communicate with the daemon through the various IPC mechanisms +available on Linux: Unix sockets, TCP/IP sockets, System V message +queues, FIFOs, or RPCs. + +As with the file system based database, process crashes can potentially +cause database corruption. + +While the portability of this implementation will depend on the chosen +IPC mechanism, this approach will be at best Unix centric and possibly +Linux specific. + +The database interface could be implemented as follows: + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: dapls_mrdb_init + Inputs: + + Outputs: + +initialize IPC mechanism + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: dapls_mrdb_exit + Inputs: + + Outputs: + +shutdown IPC mechanism + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: dapls_mrdb_record_insert + Inputs: + cookie + Outputs: + +if send insert message for cookie fails + return error + +if receive insert response message fails + return error + +if insert success + return success +else return error + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: dapls_mrdb_record_update + Inputs: + cookie + mr_handle + + Outputs: + +if send update message for cookie and mr_handle fails + return error +else return success + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: dapls_mrdb_record_query + Inputs: + cookie + + Outputs: + mr_handle + +if send query message for cookie fails + return error + +else if receive query response message with mr_handle fails + return error + +else return success + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: dapls_mrdb_record_dec + Inputs: + cookie + Outputs: + +if send decrement message for cookie fails + return error +else return success + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + + Shared Memory Database + ---------------------- + +The database could be maintained in an area of memory shared by all +DAPL instances running on a system. Linux supports the System V shared +memory functions shmget(2), shmctl(2), shmat(2), and shmdt(2). A hard +coded key_t value could be used so that each DAPL instance attached to +the same piece of shared memory. The size of the database would be +constrained by the size of the shared memory region. Synchronization +could be achieved by using atomic operations targeting memory in the +shared region. + +Such a design would suffer from the corruption problems described +above. If a process crashed there would be no easy way to clean up its +locks and roll back the database to a consistent state. + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: dapls_mrdb_init + Inputs: + + Outputs: + +attach shared region + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: dapls_mrdb_exit + Inputs: + + Outputs: + +detach shared region + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: dapls_mrdb_record_insert + Inputs: + cookie + Outputs: + +lock database + +if db does not contain cookie + add record for cookie + +unlock database + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: dapls_mrdb_record_update + Inputs: + cookie + mr_handle + Outputs: + +lock database + +if db contains cookie + update record's mr_handle + +unlock database + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: dapls_mrdb_record_query + Inputs: + cookie + + Outputs: + mr_handle + +lock database + +if db contains cookie + set mr_handle to record's value + increment record's reference count + +unlock database + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: dapls_mrdb_record_dec + Inputs: + cookie + Outputs: + +lock database + +if db contains cookie + decrement record's reference count + + if reference count is 0 + remove record + +unlock database + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + + Kernel Module Database + ---------------------- + +If the DAT library were integrated with an HCA vendor's software +stack, the database could be managed by the HCA driver. Placing the +database in the kernel would alleviate the synchronization problems +posed by multiple processes. Since memory registration operations +already involve a transition into the kernel, no extra overhead would +be incurred by this design. + +The RI could include a kernel module with this functionality as a +temporary solution. The module could identify itself as a character +device driver and communicate with user level processes through an +ioctl(2). The driver could also create an entry in the proc file +system to display the database's contents for diagnostic purposes. + +A major benefit of a kernel based implementation is that the database +can remain consistent even in the presence of application +errors. Since DAPL instances communicate with the driver by means of +ioctl(2) calls on a file, the driver can be arrange to be informed +when the file is closed and perform any necessary actions. The driver +is guaranteed to be notified of a close regardless of the manner in +which the process exits. + +The database could be implemented as a dictionary using the LMR cookie +values as keys. + +The following pseudo-code describes the functions needed by the kernel +module and the database interface. + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: KernelModuleInit + Inputs: + + Outputs: + +dictionary = create_dictionary() +create_proc_entry() +create_character_device_entry() + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: KernelModuleExit + Inputs: + + Outputs: + +remove_character_device_entry() +remove_proc_entry() +fee_dictionary(dictionary) + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: DeviceOpen + Inputs: + file + + Outputs: + +dev_data = allocate device data + +file->private_data = dev_data + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: DeviceClose + Inputs: + file + + Outputs: + +dev_data = file->private_data + +for each record in dev_data +{ + RecordDecIoctl +} + +deallocate dev_data + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: RecordInsertIoctl + Inputs: + file + cookie + + Outputs: + +lock dictionary + +if cookie is not in dictionary + insert cookie into dictionary + + +unlock dictionary + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: RecordUpdateIoctl + Inputs: + file + cookie + mr_handle + + Outputs: + +dev_data = file->private_data + +lock dictionary + +if cookie is in dictionary + add record reference to dev_data + update mr_handle + +unlock dictionary + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: RecordQueryIoctl + Inputs: + file + cookie + + Outputs: + mr_handle + +dev_data = file->private_data + +lock dictionary + +if cookie is in dictionary + add record reference to dev_data + retrieve mr_handle + +unlock dictionary + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: RecordDecIoctl + Inputs: + file + cookie + + Outputs: + +dev_data = file->private_data +remove record reference from dev_data + +lock dictionary + +if cookie is in dictionary + decrement reference count + if reference count is 0 + remove record + +unlock dictionary + + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: dapls_mrdb_init + Inputs: + + Outputs: + +fd = open device file + +if fd is invalid + return error +else + return success + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: dapls_mrdb_exit + Inputs: + + Outputs: + +close fd + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: dapls_mrdb_record_insert + Inputs: + cookie + Outputs: + +ioctl on fd + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: dapls_mrdb_record_update + Inputs: + cookie + mr_handle + Outputs: + +ioctl on fd + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: dapls_mrdb_record_query + Inputs: + cookie + + Outputs: + mr_handle + +ioctl on fd + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Function: dapls_mrdb_record_dec + Inputs: + cookie + Outputs: + +ioctl on fd + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ diff --git a/branches/WOF2-3/ulp/dapl2/doc/dapl_vendor_specific_changes.txt b/branches/WOF2-3/ulp/dapl2/doc/dapl_vendor_specific_changes.txt new file mode 100644 index 00000000..19bbbf89 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/doc/dapl_vendor_specific_changes.txt @@ -0,0 +1,394 @@ + Suggested Vendor-Specific Changes v. 0.92 + ----------------------------------------- + +================= +Table of Contents +================= + +* Table of Contents +* Introduction +* Referenced documents +* Functionality Changes + + Missing Functionality + + dat_evd_resize + + Ordering guarantees on connect/disconnect. + + Shared memory + + dat_cr_handoff +* Performance optimizations + + Reduction of context switches + [Many interrelated optimizations] + + Reducing copying of data + + Avoidance of s/g list copy on posting + + Avoidance of event data copy from CQ to EVD + + Elimination of locks + + Eliminating subroutine calls + + +============ +Introduction +============ + +This document is a list of functionality enhancements and +optimizations hardware vendors porting uDAPL may want to consider as +part of their port. The functionality enhancements mentioned in this +document are situations in which HCA Vendors, with their access to +driver and verb-level source code, and their reduced portability +concerns, are in a much better position than the reference +implementation to implement portions of the uDAPL v. 1.0 +specification. (Additional areas in which the reference +implementation, because of a lack of time or resources, did not fully +implement the uDAPL 1.0 specification are not addressed in this file; +see the file doc/dapl_unimplemented_functionality.txt, forthcoming). +Vendors should be guided in their implementation of these +functionality enhancements by their customers need for the features +involved. + +The optimizations suggested in this document have been identified by +the uDAPL Reference Implementation team as areas in which performance +may be improved by "breaching" the IB Verbs API boundary. They are +inappropriate for the reference implementation (which has portability +as one of its primary goals) but may be appropriate for a HCA-specific +port of uDAPL. Note that no expected performance gain is attached to +the suggested optimizations. This is intentional. Vendors should be +guided in their performance improvements by performance evaluations +done in the context of a representative workload, and the expected +benefit from a particular optimization weighed against the cost in +code complexity and scheduling, before the improvement is implemented. +This document is intended to seed that process; it is not intended to +be a roadmap for that process. + +We divide functionality changes into two categories + * Areas in which functionality is lacking in the reference + implementation. + * Areas in which the functionality is present in the reference + implementation, but needs improvement. + +We divide performance improvements into three types: + * Reducing context switches + * Reducing copying of data (*) + * Eliminating subroutine calls + +(*) Note that the data referred to in "reducing copying of data" is +the meta data describing an operation (e.g. scatter/gather list or +event information), not the actual data to be transferred. No data +transfer copies are required within the uDAPL reference +implementation. + +==================== +Referenced Documents +==================== + +uDAPL: User Direct Access Programming Library, Version 1.0. Published +6/21/2002. http://www.datcollaborative.org/uDAPL_062102.pdf. +Referred to in this document as the "DAT Specification". + +InfiniBand Access Application Programming Interface Specification, +Version 1.2, 4/15/2002. In DAPL SourceForge repository at +doc/api/access_api.pdf. Referred to in this document as the "IBM +Access API Specification". + +uDAPL Reference Implementation Event System Design. In DAPL +SourceForge repository at doc/dapl_event_design.txt. + +uDAPL Reference Implementation Shared Memory Design. In DAPL +SourceForge repository at doc/dapl_shared_memory_design.txt. + +uDAPL list of unimplmented functionality. In DAPL SourceForge +repository at doc/dapl_unimplemented_funcitonality.txt (forthcoming). + +=========================================== +Suggested Vendor Functionality Enhancements +=========================================== + +Missing Functionality +--------------------- +-- dat_evd_resize + +The uDAPL event system does not currently implement dat_evd_resize. +The primary reason for this is that it is not currently possible to +identify EVDs with the CQs that back them. Hence uDAPL must keep a +separate list of events, and any changes to the size of that event +list would require careful synchronization with all users of that EVD +(see the uDAPL Event System design for more details). If the various +vendor specific optimizations in this document were implemented that +eliminated the requirement for the EVD to keep its own event list, +dat_evd_resize might be easily implemented by a call or calls to +ib_cq_resize. + +-- Ordering guarantees on connect/disconnect. + +The DAPL 1.1 specification specifies that if an EVD combines event +streams for connection events and DTO events for the same endpoint, +there is an ordering guarantee: the connection event on the AP occurs +before any DTO events, and the disconnection event occurs after all +successful DTO events. Since DTO events are provided by the IBM OS +Access API through ib_completion_poll (in response to consumer +request) and connection events are provided through callbacks (which +may race with consumer requests) there is no trivial way to implement +this functionality. The functionality may be implemented through +under the table synchronizations between EVD and EP; specifically: + * The first time a DTO event is seen on an endpoint, if the + connection event has not yet arrived it is created and + delivered ahead of that DTO event. + * When a connection event is seen on an endpoint, if a + connection event has already been created for that endpoint + it is silently discarded. + * When a disconnection event is seen on an endpoint, it is + "held" until either: a) all expected DTO events for that + endpoint have completed, or b) a DTO marked as "flushed by + disconnect" is received. At that point it is delivered. + +Because of the complexity and performance overhead of implementating +this feature, the DAPL 1.1 reference implementation has chosen to take +the second approach allowed by the 1.1 specification: disallowing +integration of connection and data transfer events on the same EVD. +This fineses the problem, is in accordance with the specification, and +is more closely aligned with the ITWG IT-API currently in development, +which only allows a single event stream type for each simple EVD. +However, other vendors may choose to implement the functionality +described above in order to support more integration of event streams. + +-- Shared memory implementation + +The difficulties involved in the dapl shared memory implementation are +fully described in doc/dapl_shared_memory_design.txt. To briefly +recap: + +The uDAPL spec describes a peer-to-peer shared memory model; all uDAPL +instances indicate that they want to share registration resources for +a section of memory do so by providing the same cookie. No uDAPL +instance is unique; all register their memory in the same way, and no +communication between the instances is required. + +In contrast, the IB shared memory interface requires the first process +to register the memory to do so using the standard memory registration +verbs. All other processes after that must use the shared memory +registration verb, and provide to that verb the memory region handle +returned from the initial call. This means that the first process to +register the memory must communicate the memory region handle it +receives to all the other processes who wish to share this memory. +This is a master-slave model of shared memory registration; the +initial process (the master), is unique in its role, and it must tell +the slaves how to register the memory after it. + +To translate between these two models, the uDAPL implementation +requires some mapping between the shared cookie and the memory region +handle. This mapping must be exclusive and must have inserts occur +atomically with lookups (so that only one process can set the memory +region handle; the others retrieve it). It must also track the +deregistration of the shared memory, and the exiting of the processes +registering the shared memory; when all processes have deregistered +(possibly by exitting) it must remove the mapping from cookie to +memory region handle. + +This mapping must obviously be shared between all uDAPL +implementations on a given host. Implementing such a shared mapping +is problematic in a pure user-space implementation (as the reference +implementation is) but is expected to be relatively easy in vendor +supplied uDAFS implementations, which will presumably include a +kernel/device driver component. For this reason, we have chosen to +leave this functionality unimplemented in the reference implementation. + +-- Implementation of dat_cr_handoff + +Given that the change of service point involves a change in associated +connection qualifier, which has been advertised at the underlying +Verbs/driver level, it is not clear how to implement this function +cleanly within the reference implementation. We thus choose to defer +it for implementation by the hardware vendors. + +========================= +Performance Optimizations +========================= + + +Reduction of context switches +----------------------------- +Currently, three context switches are required on the standard +uDAPL notification path. These are: + * Invocation of the hardware interrupt handler in the kernel. + Through this method the hardware notifies the CPU of + completion queue entries for operations that have requested + notification. + * Unblocking of the per-process IB provider service thread + blocked within the driver. This thread returns to + user-space within its process, where it causes + * Unblocking of the user thread blocked within the uDAPL entry + point (dat_evd_wait() or dat_cno_wait()). + +There are several reasons for the high number of context switches, +specifically: + * The fact that the IB interface delivers notifications + through callbacks rather than through unblocking waiting + threads; this does not match uDAPL's blocking interface. + * The fact that the IB interface for blocking on a CQ doesn't + have a threshhold. If it did, we could often convert a + dat_evd_wait() into a wait on that CQ. + * The lack of a parallel concept to the CNO within IB. + +These are all areas in which closer integration between the IB +verbs/driver and uDAPL could allow the user thread to wait within the +driver. This would allow the hardware interrupt thread to directly +unblock the user thread, saving a context switch. + +A specific listing of the optimizations considered here are: + * Allow blocking on an IB CQ. This would allow removal of the + excess context switch for dat_evd_wait() in cases where + there is a 1-to-1 correspondence between an EVD and a CQ and + no threshold was passed to dat_evd_wait(). + * Allow blocking on an IB CQ to take a threshold argument. + This would allow removal of the excess context switch for + dat_evd_wait() in cases where there is a 1-to-1 + correspondence between an EVD and a CQ regardless of the + threshold value. + * Give the HCA device driver knowledge of and access to the + implementation of the uDAPL EVD, and implement dat_evd_wait() + as an ioctl blocking within the device driver. This would + allow removal of the excess context switch in all cases for + a dat_evd_wait(). + * Give the HCA device driver knowledge of and access to the + implementation of the uDAPL CNO, and implement dat_cno_wait() + as an ioctl blocking within the device driver. This would + allow removal of the excess context switch in all cases for + a dat_cno_wait(), and could improve performance for blocking + on OS Proxy Wait Objects related to the uDAPL CNO. + +See the DAPL Event Subsystem Design (doc/dapl_event_design.txt) for +more details on this class of optimization. + +======================== +Reducing Copying of Data +======================== + +There are two primary places in which a closer integration between the +IB verbs/driver and the uDAPL implementation could reducing copying +costs: + +-- Avoidance of s/g list copy on posting + +Currently there are two copies involved in posting a data transfer +request in uDAPL: + * From the user context to uDAPL. This copy is required + because the scatter/gather list formats for uDAPL and IB + differ; a copy is required to change formats. + * From uDAPL to the WQE. This copy is required because IB + specifies that all user parameters are owned by the user + upon return from the IB call, and therefore IB must keep its + own copy for use during the data transfer operation. + +If the uDAPL data transfer dispatch operations were implemented +directly on the IB hardware, these copies could be combined. + +-- Avoidance of Event data copy from CQ to EVD + +Currently there are two copies of data involved in receiving an event +in a standard data transfer operation: + * From the CQ on which the IB completion occurs to an event + structure held within the uDAPL EVD. This is because the IB + verbs provide no way to discover how many elements have been + posted to a CQ. This copy is not + required for dat_evd_dequeue. However, dat_evd_wait + requires this copy in order to correctly implement the + threshhold argument; the callback must know when to wakeup + the waiting thread. In addition, copying all CQ entries + (not just the one to be returned) is necessary before + returning from dat_evd_wait in order to set the *nmore OUT + parameter. + * From the EVD into the event structure provided in the + dat_evd_wait() call. This copy is required because of the + DAT specification, which requires a user-provided event + structure to the dat_evd_wait() call in which the event + information will be returned. If dat_evd_wait() were + instead, for example, to hand back a pointer to the already + allocated event structure, that would eventually require the + event subsystem to allocate more event structures. This is + avoided in the critical path. + +A tighter integration between the IB verbs/driver and the uDAPL +implementation would allow the avoidance of the first copy. +Specifically, providing a way to get information as to the number of +completions on a CQ would allow avoidance of that copy. + +See the uDAPL Event Subsystem Design for more details on this class of +optimization. + +==================== +Elimination of Locks +==================== + +Currently there is only a single lock used on the critical path in the +reference implementation, in dat_evd_wait() and dat_evd_dequeue(). +This lock is in place because the ib_completion_poll() routine is not +defined as thread safe, and both dat_evd_wait() and dat_evd_dequeue() +are. If there was some way for a vendor to make ib_completion_poll() +thread safe without a lock (e.g. if the appropriate hardware/software +interactions were naturally safe against races), and certain other +modifications made to the code, the lock might be removed. + +The modifications required are: + * Making racing consumers from DAPL ring buffers thread safe. + This is possible, but somewhat tricky; the key is to make + the interaction with the producer occur through a count of + elements on the ring buffer (atomically incremented and + decremented), but to dequeue elements with a separate atomic + pointer increment. The atomic modification of the element + count synchronizes with the producer and acquires the right + to do an atomic pointer increment to get the actual data. + The atomic pointer increment synchronizes with the other + consumers and actually gets the buffer data. + * The optimization described above for avoiding copies from + the CQ to the DAPL EVD Event storage queue. Without this + optimization a potential race between dat_evd_dequeue() and + dat_evd_wait() exists where dat_evd_dequeue will return an + element advanced in the event stream from the one returned + from dat_evd_wait(): + + dat_evd_dequeue() called + + EVD state checked; ok for + dat_evd_dequeue() + dat_evd_wait() called + + State changed to reserve EVD + for dat_evd_wait() + + Partial copy of CQ to EVD Event store + + Dequeue of CQE from CQ + + Completion of copy of CQ to EVD Event store + + Return of first CQE copied to EVD Event store. + + Return of thie CQE from the middle + of the copied stream. + + + If no copy occurs, dat_evd_wait() and dat_evd_dequeue() may + race, but if all operations on which they may race (access + to the EVD Event Queue and access to the CQ) are thread + safe, this race will cause no problems. + +============================ +Eliminating Subroutine Calls +============================ + +This area is the simplest, as there are many DAPL calls on the +critical path that are very thin veneers on top of their IB +equivalents. All of these calls are canidates for being merged with +those IB equivalents. In cases where there are other optimizations +that may be acheived with the call described above (e.g. within the +event subsystem, the data transfer operation posting code), that call +is not mentioned here: + * dat_pz_create + * dat_pz_free + * dat_pz_query + * dat_lmr_create + * dat_lmr_free + * dat_lmr_query + * dat_rmr_create + * dat_rmr_free + * dat_rmr_query + * dat_rmr_bind + + diff --git a/branches/WOF2-3/ulp/dapl2/doc/dat_environ.txt b/branches/WOF2-3/ulp/dapl2/doc/dat_environ.txt new file mode 100644 index 00000000..7c32037e --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/doc/dat_environ.txt @@ -0,0 +1,45 @@ + DAT Environment Guide v. 0.01 + ----------------------------- + +The following environment variables affect the behavior of the DAT +library: + + +DAT_OVERRIDE +------------ + Value used as the static registry configuration file, overriding the + default location, /etc/dat.conf + + Example: setenv DAT_OVERRIDE /path/to/my/private.conf + + +DAT_DBG_TYPE +------------ + + Value specifies which parts of the registry will print debugging + information, valid values are + + DAT_OS_DBG_TYPE_ERROR = 0x1 + DAT_OS_DBG_TYPE_GENERIC = 0x2 + DAT_OS_DBG_TYPE_SR = 0x4 + DAT_OS_DBG_TYPE_DR = 0x8 + DAT_OS_DBG_TYPE_PROVIDER_API = 0x10 + DAT_OS_DBG_TYPE_CONSUMER_API = 0x20 + DAT_OS_DBG_TYPE_ALL = 0xff + + or any combination of these. For example you can use 0xC to get both + static and dynamic registry output. + + Example setenv DAT_DBG_TYPE 0xC + +DAT_DBG_DEST +------------ + + Value sets the output destination, valid values are + + DAT_OS_DBG_DEST_STDOUT = 0x1 + DAT_OS_DBG_DEST_SYSLOG = 0x2 + DAT_OS_DBG_DEST_ALL = 0x3 + + For example, 0x3 will output to both stdout and the syslog. + diff --git a/branches/WOF2-3/ulp/dapl2/doc/uDAPL_release_notes.txt b/branches/WOF2-3/ulp/dapl2/doc/uDAPL_release_notes.txt new file mode 100644 index 00000000..4d15a8b4 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/doc/uDAPL_release_notes.txt @@ -0,0 +1,926 @@ + + Release Notes for + Gamma 3.3 and OFED 1.2 DAPL Release + June 2007 + + + DAPL GAMMA 3.3/OFED 1.2 RELEASE NOTES + + This release of the DAPL reference implementation + is timed to coincide with OFED release 1.2 of the + Open Fabrics (www.openfabrics.org) software stack. + + NEW SINCE Gamma 3.2 and OFED 1.1 + + * New Features + + 1. Added dtest and dapltest to the openfabrics build and utils rpm. + Includes manpages. + 2. Added following enviroment variables to configure connection management + timers (default settings) for larger clusters: + + DAPL_CM_ARP_TIMEOUT_MS 4000 + DAPL_CM_ARP_RETRY_COUNT 15 + DAPL_CM_ROUTE_TIMEOUT_MS 4000 + DAPL_CM_ROUTE_RETRY_COUNT 15 + + * Bug Fixes + + + Added support for new ib verbs client register event. No extra + processing required at the uDAPL level. + + Fix some issues supporting create qp without recv cq handle or + recv qp resources. IB verbs assume a recv_cq handle and uDAPL + dapl_ep_create assumes there is always recv_sge resources specified. + + Fix some timeout and long disconnect delay issues discovered during + scale-out testing. Added support to retry rdma_cm address and route + resolution with configuration options. Provide a disconnect call + when receiving the disconnect request to guarantee a disconnect reply + and event on the remote side. The rdma_disconnect was not being called + from dat_ep_disconnect() as a result of the state changing + to DISCONNECTED in the event callback. + + Changes to support exchanging and validation of the device + responder_resources and the initiator_depth during conn establishment + + Fix some build issues with dapltest on 32 bit arch, and on ia64 SUSE arch + + Add support for multiple IB devices to dat.conf to support IPoIB HA failover + + Fix atomic operation build problem with ia64 and RHEL5. + + Add support to return local and remote port information with dat_ep_query + + Cleanup RPM specfile for the dapl package, move to 1.2-1 release. + + NEW SINCE Gamma 3.1 and OFED 1.0 + + * BUG FIXES + + + Update obsolete CLK_TCK to CLOCKS_PER_SEC + + Fill out some unitialized fields in the ia_attr structure returned by + dat_ia_query(). + + Update dtest to support multiple segments on rdma write and change + makefile to use OpenIB-cma by default. + + Add support for dat_evd_set_unwaitable on a DTO evd in openib_cma + provider + + Added errno reporting (message and return codes) during open to help + diagnose create thread issues. + + Fix some suspicious inline assembly EIEIO_ON_SMP and ISYNC_ON_SMP + + Fix IA64 build problems + + Lower the reject debug message level so we don't see warnings when + consumers reject. + + Added support for active side TIMED_OUT event from a provider. + + Fix bug in dapls_ib_get_dat_event() call after adding new unreachable + event. + + Update for new rdma_create_id() function signature. + + Set max rdma read per EP attributes + + Report the proper error and timeout events. + + Socket CM fix to guard against using a loopback address as the local + device address. + + Use the uCM set_option feature to adjust connect request timeout + retry values. + + Fix to disallow any event after a disconnect event. + + * OFED 1.1 uDAPL source build instructions: + + cd /usr/local/ofed/src/openib-1.1/src/userspace/dapl + + # NON_DEBUG build configuration + + ./configure --disable-libcheck --prefix /usr/local/ofed + --libdir /usr/local/ofed/lib64 LDFLAGS=-L/usr/local/ofed/lib64 + CPPFLAGS="-I../libibverbs/include -I../librdmacm/include" + + # build and install + + make + make install + + # DEBUG build configuration + + ./configure --disable-libcheck --enable-debug --prefix /usr/local/ofed + --libdir /usr/local/ofed/lib64 LDFLAGS=-L/usr/local/ofed/lib64 + CPPFLAGS="-I../libibverbs/include -I../librdmacm/include" + + # build and install + + make + make install + + # DEBUG messages: set environment variable DAPL_DBG_TYPE, default + mapping is 0x0003 + + DAPL_DBG_TYPE_ERR = 0x0001, + DAPL_DBG_TYPE_WARN = 0x0002, + DAPL_DBG_TYPE_EVD = 0x0004, + DAPL_DBG_TYPE_CM = 0x0008, + DAPL_DBG_TYPE_EP = 0x0010, + DAPL_DBG_TYPE_UTIL = 0x0020, + DAPL_DBG_TYPE_CALLBACK = 0x0040, + DAPL_DBG_TYPE_DTO_COMP_ERR= 0x0080, + DAPL_DBG_TYPE_API = 0x0100, + DAPL_DBG_TYPE_RTN = 0x0200, + DAPL_DBG_TYPE_EXCEPTION = 0x0400, + DAPL_DBG_TYPE_SRQ = 0x0800, + DAPL_DBG_TYPE_CNTR = 0x1000 + + + Note: The udapl provider library libdaplscm.so is untested and + unsupported, thus customers should not use it. + It will be removed in the next OFED release. + + DAPL GAMMA 3.1 RELEASE NOTES + + This release of the DAPL reference implementation + is timed to coincide with the first release of the + Open Fabrics (www.openfabrics.org) software stack. + This release adds support for this new stack, which + is now the native Linux RDMA stack. + + This release also adds a new licensing option. In + addition to the Common Public License and BSD License, + the code can now be licensed under the terms of the GNU + General Public License (GPL) version 2. + + NEW SINCE Gamma 3.0 + + - GPL v2 added as a licensing option + - OpenFabrics (aka OpenIB) gen2 verbs support + - dapltest support for Solaris 10 + + * BUG FIXES + + + Fixed a disconnect event processing race + + Fix to destroy all QPs on IA close + + Removed compiler warnings + + Removed unused variables + + And many more... + + DAPL GAMMA 3.0 RELEASE NOTES + + This is the first release based on version 1.2 of the spec. There + are some components, such a shared receive queues (SRQs), which + are not implemented yet. + + Once again there were numerous bug fixes submitted by the + DAPL community. + + NEW SINCE Beta 2.06 + + - DAT 1.2 headers + - DAT_IA_HANDLEs implemented as small integers + - Changed default device name to be "ia0a" + - Initial support for Linux 2.6.X kernels + - Updates to the OpenIB gen 1 provider + + * BUG FIXES + + + Updated Makefile for differentiation between OS releases. + + Updated atomic routines to use appropriate API + + Removed unnecessary assert from atomic_dec. + + Fixed bugs when freeing a PSP. + + Fixed error codes returned by the DAT static registry. + + Kernel updates for dat_strerror. + + Cleaned up the transport layer/adapter interface to use DAPL + types rather than transport types. + + Fixed ring buffer reallocation. + + Removed old test/udapl/dapltest directory. + + Fixed DAT_IA_HANDLE translation (from pointer to int and + vice versa) on 64-bit platforms. + + DAP BETA 2.06 RELEASE NOTES + + We are not planning any further releases of the Beta series, + which are based on the 1.1 version of the spec. There may be + further releases for bug fixes, but we anticipate the DAPL + community to move to the new 1.2 version of the spec and the + changes mandated in the reference implementation. + + The biggest item in this release is the first inclusion of the + OpenIB Gen 1 provider, an item generating a lot of interest in + the IB community. This implementation has graciously been + provided by the Mellanox team. The kdapl implementation is in + progress, and we imagine work will soon begin on Gen 2. + + There are also a handful of bug fixes available, as well as a long + awaited update to the endpoint design document. + + NEW SINCE Beta 2.05 + + - OpenIB gen 1 provider support has been added + - Added dapls_evd_post_generic_event(), routine to post generic + event types as requested by some providers. Also cleaned up + error reporting. + - Updated the endpoint design document in the doc/ directory. + + * BUG FIXES + + + Cleaned up memory leak on close by freeing the HCA structure; + + Removed bogus #defs for rdtsc calls on IA64. + + Changed daptest thread types to use internal types for + portability & correctness + + Various 64 bit enhancements & updates + + Fixes to conformance test that were defining CONN_QUAL twice + and using it in different ways + + Cleaned up private data handling in ep_connect & provider + support: we now avoid extra copy in connect code; reduced + stack requirements by using private_data structure in the EP; + removed provider variable. + + Fixed problem in the dat conformance test where cno_wait would + attempt to dereference a timer value and SEGV. + + Removed old vestiges of depricated POLLING_COMPLETIONS + conditionals. + + DAPL BETA 2.05 RELEASE NOTES + + This was to be a very minor release, the primary change was + going to be the new wording of the DAT license as contained in + the header for all source files. But the interest and + development occurring in DAPL provided some extra bug fixes, and + some new functionality that has been requested for a while. + + First, you may notice that every single source file was + changed. If you read the release notes from DAPL BETA 2.04, you + were warned this would happen. There was a legal issue with the + wording in the header, the end result was that every source file + was required to change the word 'either of' to 'both'. We've + been putting this change off as long as possible, but we wanted + to do it in a clean drop before we start working on DAT 1.2 + changes in the reference implementation, just to keep things + reasonably sane. + + kdapltest has enabled three of the subtests supported by + dapltest. The Performance test in particular has been very + useful to dapltest in getting minima and maxima. The Limit test + pushes the limits by allocating the maximum number of specific + resources. And the FFT tests are also available. + + Most vendors have supported shared memory regions for a while, + several of which have asked the reference implementation team to + provide a common implementation. Shared memory registration has + been tested on ibapi, and compiled into vapi. Both InfiniBand + providers have the restriction that a memory region must be + created before it can be shared; not all RDMA APIs are this way, + several allow you to declare a memory region shared when it is + registered. Hence, details of the implementation are hidden in + the provider layer, rather than forcing other APIs to do + something strange. + + This release also contains some changes that will allow dapl to + work on Opteron processors, as well as some preliminary support + for Power PC architecture. These features are not well tested + and may be incomplete at this time. + + Finally, we have been asked several times over the course of the + project for a canonical interface between the common and + provider layers. This release includes a dummy provider to meet + that need. Anyone should be able to download the release and do + a: + make VERBS=DUMMY + + And have a cleanly compiled dapl library. This will be useful + both to those porting new transport providers, as well as those + going to new machines. + + The DUMMY provider has been compiled on both Linux and Windows + machines. + + + NEW SINCE Beta 2.4 + - kdapltest enhancements: + * Limit subtests now work + * Performance subtests now work. + * FFT tests now work. + + - The VAPI headers have been refreshed by Mellanox + + - Initial Opteron and PPC support. + + - Atomic data types now have consistent treatment, allowing us to + use native data types other than integers. The Linux kdapl + uses atomic_t, allowing dapl to use the kernel macros and + eliminate the assembly code in dapl_osd.h + + - The license language was updated per the direction of the + DAT Collaborative. This two word change affected the header + of every file in the tree. + + - SHARED memory regions are now supported. + + - Initial support for the TOPSPIN provider. + + - Added a dummy provider, essentially the NULL provider. It's + purpose is to aid in porting and to clarify exactly what is + expected in a provider implementation. + + - Removed memory allocation from the DTO path for VAPI + + - cq_resize will now allow the CQ to be resized smaller. Not all + providers support this, but it's a provider problem, not a + limitation of the common code. + + * BUG FIXES + + + Removed spurious lock in dapl_evd_connection_callb.c that + would have caused a deadlock. + + The Async EVD was getting torn down too early, potentially + causing lost errors. Has been moved later in the teardown + process. + + kDAPL replaced mem_map_reserve() with newer SetPageReserved() + for better Linux integration. + + kdapltest no longer allocate large print buffers on the stack, + is more careful to ensure buffers don't overflow. + + Put dapl_os_dbg_print() under DAPL_DBG conditional, it is + supposed to go away in a production build. + + dapltest protocol version has been bumped to reflect the + change in the Service ID. + + Corrected several instances of routines that did not adhere + to the DAT 1.1 error code scheme. + + Cleaned up vapi ib_reject_connection to pass DAT types rather + than provider specific types. Also cleaned up naming interface + declarations and their use in vapi_cm.c; fixed incorrect + #ifdef for naming. + + Initialize missing uDAPL provider attr, pz_support. + + Changes for better layering: first, moved + dapl_lmr_convert_privileges to the provider layer as memory + permissions are clearly transport specific and are not always + defined in an integer bitfield; removed common routines for + lmr and rmr. Second, move init and release setup/teardown + routines into adapter_util.h, which defined the provider + interface. + + Cleaned up the HCA name cruft that allowed different types + of names such as strings or ints to be dealt with in common + code; but all names are presented by the dat_registry as + strings, so pushed conversions down to the provider + level. Greatly simplifies names. + + Changed deprecated true/false to DAT_TRUE/DAT_FALSE. + + Removed old IB_HCA_NAME type in favor of char *. + + Fixed race condition in kdapltest's use of dat_evd_dequeue. + + Changed cast for SERVER_PORT_NUMBER to DAT_CONN_QUAL as it + should be. + + Small code reorg to put the CNO into the EVD when it is + allocated, which simplifies things. + + Removed gratuitous ib_hca_port_t and ib_send_op_type_t types, + replaced with standard int. + + Pass a pointer to cqe debug routine, not a structure. Some + clean up of data types. + + kdapl threads now invoke reparent_to_init() on exit to allow + threads to get cleaned up. + + + + DAPL BETA 2.04 RELEASE NOTES + + The big changes for this release involve a more strict adherence + to the original dapl architecture. Originally, only InfiniBand + providers were available, so allowing various data types and + event codes to show through into common code wasn't a big deal. + + But today, there are an increasing number of providers available + on a number of transports. Requiring an IP iWarp provider to + match up to InfiniBand events is silly, for example. + + Restructuring the code allows more flexibility in providing an + implementation. + + There are also a large number of bug fixes available in this + release, particularly in kdapl related code. + + Be warned that the next release will change every file in the + tree as we move to the newly approved DAT license. This is a + small change, but all files are affected. + + Future releases will also support to the soon to be ratified DAT + 1.2 specification. + + This release has benefited from many bug reports and fixes from + a number of individuals and companies. On behalf of the DAPL + community, thank you! + + + NEW SINCE Beta 2.3 + + - Made several changes to be more rigorous on the layering + design of dapl. The intent is to make it easier for non + InfiniBand transports to use dapl. These changes include: + + * Revamped the ib_hca_open/close code to use an hca_ptr + rather than an ib_handle, giving the transport layer more + flexibility in assigning transport handles and resources. + + * Removed the CQD calls, they are specific to the IBM API; + folded this functionality into the provider open/close calls. + + * Moved VAPI, IBAPI transport specific items into a transport + structure placed inside of the HCA structure. Also updated + routines using these fields to use the new location. Cleaned + up provider knobs that have been exposed for too long. + + * Changed a number of provider routines to use DAPL structure + pointers rather than exposing provider handles & values. Moved + provider specific items out of common code, including provider + data types (e.g. ib_uint32_t). + + * Pushed provider completion codes and type back into the + provider layer. We no longer use EVD or CM completion types at + the common layer, instead we obtain the appropriate DAT type + from the provider and process only DAT types. + + * Change private_data handling such that we can now accommodate + variable length private data. + + - Remove DAT 1.0 cruft from the DAT header files. + + - Better spec compliance in headers and various routines. + + - Major updates to the VAPI implementation from + Mellanox. Includes initial kdapl implementation + + - Move kdapl platform specific support for hash routines into + OSD file. + + - Cleanups to make the code more readable, including comments + and certain variable and structure names. + + - Fixed CM_BUSTED code so that it works again: very useful for + new dapl ports where infrastructure is lacking. Also made + some fixes for IBHOSTS_NAMING conditional code. + + - Added DAPL_MERGE_CM_DTO as a compile time switch to support + EVD stream merging of CM and DTO events. Default is off. + + - 'Quit' test ported to kdapltest + + - uDAPL now builds on Linux 2.6 platform (SuSE 9.1). + + - kDAPL now builds for a larger range of Linux kernels, but + still lacks 2.6 support. + + - Added shared memory ID to LMR structure. Shared memory is + still not fully supported in the reference implementation, but + the common code will appear soon. + + * Bug fixes + - Various Makefiles fixed to use the correct dat registry + library in its new location (as of Beta 2.03) + - Simple reorg of dat headers files to be consistent with + the spec. + - fixed bug in vapi_dto.h recv macro where we could have an + uninitialized pointer. + - Simple fix in dat_dr.c to initialize a variable early in the + routine before errors occur. + - Removed private data pointers from a CONNECTED event, as + there should be no private data here. + - dat_strerror no longer returns an uninitialized pointer if + the error code is not recognized. + - dat_dup_connect() will reject 0 timeout values, per the + spec. + - Removed unused internal_hca_names parameter from + ib_enum_hcas() interface. + - Use a temporary DAT_EVENT for kdapl up-calls rather than + making assumptions about the current event queue. + - Relocated some platform dependent code to an OSD file. + - Eliminated several #ifdefs in .c files. + - Inserted a missing unlock() on an error path. + - Added bounds checking on size of private data to make sure + we don't overrun the buffer + - Fixed a kdapltest problem that caused a machine to panic if + the user hit ^C + - kdapltest now uses spin locks more appropriate for their + context, e.g. spin_lock_bh or spin_lock_irq. Under a + conditional. + - Fixed kdapltest loops that drain EVDs so they don't go into + endless loops. + - Fixed bug in dapl_llist_add_entry link list code. + - Better error reporting from provider code. + - Handle case of user trying to reap DTO completions on an + EP that has been freed. + - No longer hold lock when ep_free() calls into provider layer + - Fixed cr_accept() to not have an extra copy of + private_data. + - Verify private_data pointers before using them, avoid + panic. + - Fixed memory leak in kdapltest where print buffers were not + getting reclaimed. + + + + DAPL BETA 2.03 RELEASE NOTES + + There are some prominent features in this release: + 1) dapltest/kdapltest. The dapltest test program has been + rearchitected such that a kernel version is now available + to test with kdapl. The most obvious change is a new + directory structure that more closely matches other core + dapl software. But there are a large number of changes + throughout the source files to accommodate both the + differences in udapl/kdapl interfaces, but also more mundane + things such as printing. + + The new dapltest is in the tree at ./test/dapltest, while the + old remains at ./test/udapl/dapltest. For this release, we + have maintained both versions. In a future release, perhaps + the next release, the old dapltest directory will be + removed. Ongoing development will only occur in the new tree. + + 2) DAT 1.1 compliance. The DAT Collaborative has been busy + finalizing the 1.1 revision of the spec. The header files + have been reviewed and posted on the DAT Collaborative web + site, they are now in full compliance. + + The reference implementation has been at a 1.1 level for a + while. The current implementation has some features that will + be part of the 1.2 DAT specification, but only in places + where full compatibility can be maintained. + + 3) The DAT Registry has undergone some positive changes for + robustness and support of more platforms. It now has the + ability to support several identical provider names + simultaneously, which enables the same dat.conf file to + support multiple platforms. The registry will open each + library and return when successful. For example, a dat.conf + file may contain multiple provider names for ex0a, each + pointing to a different library that may represent different + platforms or vendors. This simplifies distribution into + different environments by enabling the use of common + dat.conf files. + + In addition, there are a large number of bug fixes throughout + the code. Bug reports and fixes have come from a number of + companies. + + Also note that the Release notes are cleaned up, no longer + containing the complete text of previous releases. + + * EVDs no longer support DTO and CONNECTION event types on the + same EVD. NOTE: The problem is maintaining the event ordering + between two channels such that no DTO completes before a + connection is received; and no DTO completes after a + disconnect is received. For 90% of the cases this can be made + to work, but the remaining 10% will cause serious performance + degradation to get right. + + NEW SINCE Beta 2.2 + + * DAT 1.1 spec compliance. This includes some new types, error + codes, and moving structures around in the header files, + among other things. Note the Class bits of dat_error.h have + returned to a #define (from an enum) to cover the broadest + range of platforms. + + * Several additions for robustness, including handle and + pointer checking, better argument checking, state + verification, etc. Better recovery from error conditions, + and some assert()s have been replaced with 'if' statements to + handle the error. + + * EVDs now maintain the actual queue length, rather than the + requested amount. Both the DAT spec and IB (and other + transports) allow the underlying implementation to provide + more CQ entries than requested. + + Requests for the same number of entries contained by an EVD + return immediate success. + + * kDAPL enhancements: + - module parameters & OS support calls updated to work with + more recent Linux kernels. + - kDAPL build options changes to match the Linux kernel, vastly + reducing the size and making it more robust. + - kDAPL unload now works properly + - kDAPL takes a reference on the provider driver when it + obtains a verbs vector, to prevent an accidental unload + - Cleaned out all of the uDAPL cruft from the linux/osd files. + + * New dapltest (see above). + + * Added a new I/O trace facility, enabling a developer to debug + all I/O that are in progress or recently completed. Default + is OFF in the build. + + * 0 timeout connections now refused, per the spec. + + * Moved the remaining uDAPL specific files from the common/ + directory to udapl/. Also removed udapl files from the kdapl + build. + + * Bug fixes + - Better error reporting from provider layer + - Fixed race condition on reference counts for posting DTO + ops. + - Use DAT_COMPLETION_SUPPRESS_FLAG to suppress successful + completion of dapl_rmr_bind (instead of + DAT_COMPLEITON_UNSIGNALLED, which is for non-notification + completion). + - Verify psp_flags value per the spec + - Bug in psp_create_any() checking psp_flags fixed + - Fixed type of flags in ib_disconnect from + DAT_COMPLETION_FLAGS to DAT_CLOSE_FLAGS + - Removed hard coded check for ASYNC_EVD. Placed all EVD + prevention in evd_stream_merging_supported array, and + prevent ASYNC_EVD from being created by an app. + - ep_free() fixed to comply with the spec + - Replaced various printfs with dbg_log statements + - Fixed kDAPL interaction with the Linux kernel + - Corrected phy_register protottype + - Corrected kDAPL wait/wakeup synchronization + - Fixed kDAPL evd_kcreate() such that it no longer depends + on uDAPL only code. + - dapl_provider.h had wrong guard #def: changed DAT_PROVIDER_H + to DAPL_PROVIDER_H + - removed extra (and bogus) call to dapls_ib_completion_notify() + in evd_kcreate.c + - Inserted missing error code assignment in + dapls_rbuf_realloc() + - When a CONNECTED event arrives, make sure we are ready for + it, else something bad may have happened to the EP and we + just return; this replaces an explicit check for a single + error condition, replacing it with the general check for the + state capable of dealing with the request. + - Better context pointer verification. Removed locks around + call to ib_disconnect on an error path, which would result + in a deadlock. Added code for BROKEN events. + - Brought the vapi code more up to date: added conditional + compile switches, removed obsolete __ActivePort, deal + with 0 length DTO + - Several dapltest fixes to bring the code up to the 1.1 + specification. + - Fixed mismatched dalp_os_dbg_print() #else dapl_Dbg_Print(); + the latter was replaced with the former. + - ep_state_subtype() now includes UNCONNECTED. + - Added some missing ibapi error codes. + + + + NEW SINCE Beta 2.1 + + * Changes for Erratta and 1.1 Spec + - Removed DAT_NAME_NOT_FOUND, per DAT erratta + - EVD's with DTO and CONNECTION flags set no longer valid. + - Removed DAT_IS_SUCCESS macro + - Moved provider attribute structures from vendor files to udat.h + and kdat.h + - kdapl UPCALL_OBJECT now passed by reference + + * Completed dat_strerr return strings + + * Now support interrupted system calls + + * dapltest now used dat_strerror for error reporting. + + * Large number of files were formatted to meet project standard, + very cosmetic changes but improves readability and + maintainability. Also cleaned up a number of comments during + this effort. + + * dat_registry and RPM file changes (contributed by Steffen Persvold): + - Renamed the RPM name of the registry to be dat-registry + (renamed the .spec file too, some cvs add/remove needed) + - Added the ability to create RPMs as normal user (using + temporal paths), works on SuSE, Fedora, and RedHat. + - 'make rpm' now works even if you didn't build first. + - Changed to using the GNU __attribute__((constructor)) and + __attribute__((destructor)) on the dat_init functions, dat_init + and dat_fini. The old -init and -fini options to LD makes + applications crash on some platforms (Fedora for example). + - Added support for 64 bit platforms. + - Added code to allow multiple provider names in the registry, + primarily to support ia32 and ia64 libraries simultaneously. + Provider names are now kept in a list, the first successful + library open will be the provider. + + * Added initial infrastructure for DAPL_DCNTR, a feature that + will aid in debug and tuning of a dapl implementation. Partial + implementation only at this point. + + * Bug fixes + - Prevent debug messages from crashing dapl in EVD completions by + verifying the error code to ensure data is valid. + - Verify CNO before using it to clean up in evd_free() + - CNO timeouts now return correct error codes, per the spec. + - cr_accept now complies with the spec concerning connection + requests that go away before the accept is invoked. + - Verify valid EVD before posting connection evens on active side + of a connection. EP locking also corrected. + - Clean up of dapltest Makefile, no longer need to declare + DAT_THREADSAFE + - Fixed check of EP states to see if we need to disconnect an + IA is closed. + - ep_free() code reworked such that we can properly close a + connection pending EP. + - Changed disconnect processing to comply with the spec: user will + see a BROKEN event, not DISCONNECTED. + - If we get a DTO error, issue a disconnect to let the CM and + the user know the EP state changed to disconnect; checked IBA + spec to make sure we disconnect on correct error codes. + - ep_disconnect now properly deals with abrupt disconnects on the + active side of a connection. + - PSP now created in the correct state for psp_create_any(), making + it usable. + - dapl_evd_resize() now returns correct status, instead of always + DAT_NOT_IMPLEMENTED. + - dapl_evd_modify_cno() does better error checking before invoking + the provider layer, avoiding bugs. + - Simple change to allow dapl_evd_modify_cno() to set the CNO to + NULL, per the spec. + - Added required locking around call to dapl_sp_remove_cr. + + - Fixed problems related to dapl_ep_free: the new + disconnect(abrupt) allows us to do a more immediate teardown of + connections, removing the need for the MAGIC_EP_EXIT magic + number/state, which has been removed. Mmuch cleanup of paths, + and made more robust. + - Made changes to meet the spec, uDAPL 1.1 6.3.2.3: CNO is + triggered if there are waiters when the last EVD is removed + or when the IA is freed. + - Added code to deal with the provider synchronously telling us + a connection is unreachable, and generate the appropriate + event. + - Changed timer routine type from unsigned long to uintptr_t + to better fit with machine architectures. + - ep.param data now initialized in ep_create, not ep_alloc. + - Or Gerlitz provided updates to Mellanox files for evd_resize, + fw attributes, many others. Also implemented changes for correct + sizes on REP side of a connection request. + + + + NEW SINCE Beta 2.0 + + * dat_echo now DAT 1.1 compliant. Various small enhancements. + + * Revamped atomic_inc/dec to be void, the return value was never + used. This allows kdapl to use Linux kernel equivalents, and + is a small performance advantage. + + * kDAPL: dapl_evd_modify_upcall implemented and tested. + + * kDAPL: physical memory registration implemented and tested. + + * uDAPL now builds cleanly for non-debug versions. + + * Default RDMA credits increased to 8. + + * Default ACK_TIMEOUT now a reasonable value (2 sec vs old 2 + months). + + * Cleaned up dat_error.h, now 1.1 compliant in comments. + + * evd_resize initial implementation. Untested. + + * Bug fixes + - __KDAPL__ is defined in kdat_config.h, so apps don't need + to define it. + - Changed include file ordering in kdat.h to put kdat_config.h + first. + - resolved connection/tear-down race on the client side. + - kDAPL timeouts now scaled properly; fixed 3 orders of + magnitude difference. + - kDAPL EVD callbacks now get invoked for all completions; old + code would drop them in heavy utilization. + - Fixed error path in kDAPL evd creation, so we no longer + leak CNOs. + - create_psp_any returns correct error code if it can't create + a connection qualifier. + - lock fix in ibapi disconnect code. + - kDAPL INFINITE waits now work properly (non connection + waits) + - kDAPL driver unload now works properly + - dapl_lmr_[k]create now returns 1.1 error codes + - ibapi routines now return DAT 1.1 error codes + + + + NEW SINCE Beta 1.10 + + * kDAPL is now part of the DAPL distribution. See the release + notes above. + + The kDAPL 1.1 spec is now contained in the doc/ subdirectory. + + * Several files have been moved around as part of the kDAPL + checkin. Some files that were previously in udapl/ are now + in common/, some in common are now in udapl/. The goal was + to make sure files are properly located and make sense for + the build. + + * Source code formatting changes for consistency. + + * Bug fixes + - dapl_evd_create() was comparing the wrong bit combinations, + allowing bogus EVDs to be created. + - Removed code that swallowed zero length I/O requests, which + are allowed by the spec and are useful to applications. + - Locking in dapli_get_sp_ep was asymmetric; fixed it so the + routine will take and release the lock. Cosmetic change. + - dapl_get_consuemr_context() will now verify the pointer + argument 'context' is not NULL. + + + OBTAIN THE CODE + + To obtain the tree for your local machine you can check it + out of the source repository using CVS tools. CVS is common + on Unix systems and available as freeware on Windows machines. + The command to anonymously obtain the source code from + Source Forge (with no password) is: + + cvs -d:pserver:anonymous@cvs.dapl.sourceforge.net:/cvsroot/dapl login + cvs -z3 -d:pserver:anonymous@cvs.dapl.sourceforge.net:/cvsroot/dapl co . + + When prompted for a password, simply press the Enter key. + + Source Forge also contains explicit directions on how to become + a developer, as well as how to use different CVS commands. You may + also browse the source code using the URL: + + http://svn.sourceforge.net/viewvc/dapl/trunk/ + + SYSTEM REQUIREMENTS + + This project has been implemented on Red Hat Linux 7.3, SuSE + SLES 8, 9, and 10, Windows 2000, RHEL 3.0, 4.0 and 5.0 and a few + other Linux distrubutions. The structure of the code is designed + to allow other operating systems to easily be adapted. + + The DAPL team has used Mellanox Tavor based InfiniBand HCAs for + development, and continues with this platform. Our HCAs use the + IB verbs API submitted by IBM. Mellanox has contributed an + adapter layer using their VAPI verbs API. Either platform is + available to any group considering DAPL work. The structure of + the uDAPL source allows other provider API sets to be easily + integrated. + + The development team uses any one of three topologies: two HCAs + in a single machine; a single HCA in each of two machines; and + most commonly, a switch. Machines connected to a switch may have + more than one HCA. + + The DAPL Plugfest revealed that switches and HCAs available from + most vendors will interoperate with little trouble, given the + most recent releases of software. The dapl reference team makes + no recommendation on HCA or switch vendors. + + Explicit machine configurations are available upon request. + + IN THE TREE + + The DAPL tree contains source code for the uDAPL and kDAPL + implementations, and also includes tests and documentation. + + Included documentation has the base level API of the + providers: OpenFabrics, IBM Access, and Mellanox Verbs API. Also + included are a growing number of DAPL design documents which + lead the reader through specific DAPL subsystems. More + design documents are in progress and will appear in the tree in + the near future. + + A small number of test applications and a unit test framework + are also included. dapltest is the primary testing application + used by the DAPL team, it is capable of simulating a variety of + loads and exercises a large number of interfaces. Full + documentation is included for each of the tests. + + Recently, the dapl conformance test has been added to the source + repository. The test provides coverage of the most common + interfaces, doing both positive and negative testing. Vendors + providing DAPL implementation are strongly encouraged to run + this set of tests. + + MAKEFILE NOTES + + There are a number #ifdef's in the code that were necessary + during early development. They are disappearing as we + have time to take advantage of features and work available from + newer releases of provider software. These #ifdefs are not + documented as the intent is to remove them as soon as possible. + + CONTRIBUTIONS + + As is common to Source Forge projects, there are a small number + of developers directly associated with the source tree and having + privileges to change the tree. Requested updates, changes, bug + fixes, enhancements, or contributions should be sent to + James Lentini at jlentinit@netapp.com for review. We welcome your + contributions and expect the quality of the project will + improve thanks to your help. + + The core DAPL team is: + + James Lentini + Arlin Davis + Steve Sears + + ... with contributions from a number of excellent engineers in + various companies contributing to the open source effort. + + + ONGOING WORK + + Not all of the DAPL spec is implemented at this time. + Functionality such as shared memory will probably not be + implemented by the reference implementation (there is a write up + on this in the doc/ area), and there are yet various cases where + work remains to be done. And of course, not all of the + implemented functionality has been tested yet. The DAPL team + continues to develop and test the tree with the intent of + completing the specification and delivering a robust and useful + implementation. + + +The DAPL Team + diff --git a/branches/WOF2-3/ulp/dapl2/man/dapltest.1 b/branches/WOF2-3/ulp/dapl2/man/dapltest.1 new file mode 100644 index 00000000..c1c46829 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/man/dapltest.1 @@ -0,0 +1,390 @@ +." Text automatically generated by txt2man +.TH dapltest 1 "February 23, 2007" "uDAPL 1.2" "USER COMMANDS" + +.SH NAME +\fB +\fBdapltest \fP- test for the Direct Access Programming Library (DAPL) +\fB +.SH DESCRIPTION + +Dapltest is a set of tests developed to exercise, characterize, +and verify the DAPL interfaces during development and porting. +At least two instantiations of the test must be run. One acts +as the server, fielding requests and spawning server-side test +threads as needed. Other client invocations connect to the server +and issue test requests. The server side of the test, once invoked, +listens continuously for client connection requests, until quit or +killed. Upon receipt of a connection request, the connection is +established, the server and client sides swap version numbers to +verify that they are able to communicate, and the client sends +the test request to the server. If the version numbers match, +and the test request is well-formed, the server spawns the threads +needed to run the test before awaiting further connections. +.SH USAGE + +dapltest [ -f script_file_name ] +[ -T S|Q|T|P|L ] [ -D device_name ] [ -d ] [ -R HT|LL|EC|PM|BE ] +.PP +With no arguments, dapltest runs as a server using default values, +and loops accepting requests from clients. + +The -f option allows all arguments to be placed in a file, to ease +test automation. + +The following arguments are common to all tests: +.TP +.B +[ -T S|Q|T|P|L ] +Test function to be performed: +.RS +.TP +.B +S +- server loop +.TP +.B +Q +- quit, client requests that server +wait for any outstanding tests to +complete, then clean up and exit +.TP +.B +T +- transaction test, transfers data between +client and server +.TP +.B +P +- performance test, times DTO operations +.TP +.B +L +- limit test, exhausts various resources, +runs in client w/o server interaction +Default: S +.RE +.TP +.B +[ -D device_name ] +Specifies the interface adapter name as documented in +the /etc/dat.conf static configuration file. This name +corresponds to the provider library to open. +Default: none +.TP +.B +[ -d ] +Enables extra debug verbosity, primarily tracing +of the various DAPL operations as they progress. +Repeating this parameter increases debug spew. +Errors encountered result in the test spewing some +explanatory text and stopping; this flag provides +more detail about what lead up to the error. +Default: zero +.TP +.B +[ -R BE ] +Indicate the quality of service (QoS) desired. +Choices are: +.RS +.TP +.B +HT +- high throughput +.TP +.B +LL +- low latency +.TP +.B +EC +- economy (neither HT nor LL) +.TP +.B +PM +- premium +.TP +.B +BE +- best effort +Default: BE +.RE +.RE +.PP +.B +Usage - Quit test client +.PP +.nf +.fam C + dapltest [Common_Args] [ -s server_name ] + + Quit testing (-T Q) connects to the server to ask it to clean up and + exit (after it waits for any outstanding test runs to complete). + In addition to being more polite than simply killing the server, + this test exercises the DAPL object teardown code paths. + There is only one argument other than those supported by all tests: + + -s server_name Specifies the name of the server interface. + No default. + + +.fam T +.fi +.B +Usage - Transaction test client +.PP +.nf +.fam C + dapltest [Common_Args] [ -s server_name ] + [ -t threads ] [ -w endpoints ] [ -i iterations ] [ -Q ] + [ -V ] [ -P ] OPclient OPserver [ op3, + + Transaction testing (-T T) transfers a variable amount of data between + client and server. The data transfer can be described as a sequence of + individual operations; that entire sequence is transferred 'iterations' + times by each thread over all of its endpoint(s). + + The following parameters determine the behavior of the transaction test: + + -s server_name Specifies the name or IP address of the server interface. + No default. + + [ -t threads ] Specify the number of threads to be used. + Default: 1 + + [ -w endpoints ] Specify the number of connected endpoints per thread. + Default: 1 + + [ -i iterations ] Specify the number of times the entire sequence + of data transfers will be made over each endpoint. + Default: 1000 + + [ -Q ] Funnel completion events into a CNO. + Default: use EVDs + + [ -V ] Validate the data being transferred. + Default: ignore the data + + [ -P ] Turn on DTO completion polling + Default: off + + OP1 OP2 [ OP3, \.\.\. ] + A single transaction (OPx) consists of: + + server|client Indicates who initiates the + data transfer. + + SR|RR|RW Indicates the type of transfer: + SR send/recv + RR RDMA read + RW RDMA write + Defaults: none + + [ seg_size [ num_segs ] ] + Indicates the amount and format + of the data to be transferred. + Default: 4096 1 + (i.e., 1 4KB buffer) + + [ -f ] For SR transfers only, indicates + that a client's send transfer + completion should be reaped when + the next recv completion is reaped. + Sends and receives must be paired + (one client, one server, and in that + order) for this option to be used. + + Restrictions: + + Due to the flow control algorithm used by the transaction test, there + must be at least one SR OP for both the client and the server. + + Requesting data validation (-V) causes the test to automatically append + three OPs to those specified. These additional operations provide + synchronization points during each iteration, at which all user-specified + transaction buffers are checked. These three appended operations satisfy + the "one SR in each direction" requirement. + + The transaction OP list is printed out if -d is supplied. + +.fam T +.fi +.B +Usage - Performance test client +.PP +.nf +.fam C + dapltest [Common_Args] -s server_name [ -m p|b ] + [ -i iterations ] [ -p pipeline ] OP + + Performance testing (-T P) times the transfer of an operation. + The operation is posted 'iterations' times. + + The following parameters determine the behavior of the transaction test: + + -s server_name Specifies the name or IP address of the server interface. + No default. + + -m b|p Used to choose either blocking (b) or polling (p) + Default: blocking (b) + + [ -i iterations ] Specify the number of times the entire sequence + of data transfers will be made over each endpoint. + Default: 1000 + + [ -p pipeline ] Specify the pipline length, valid arguments are in + the range [0,MAX_SEND_DTOS]. If a value greater than + MAX_SEND_DTOS is requested the value will be + adjusted down to MAX_SEND_DTOS. + Default: MAX_SEND_DTOS + + OP Specifies the operation as follow: + + RR|RW Indicates the type of transfer: + RR RDMA read + RW RDMA write + Defaults: none + + [ seg_size [ num_segs ] ] + Indicates the amount and format + of the data to be transferred. + Default: 4096 1 + (i.e., 1 4KB buffer) +.fam T +.RE +.RE +.PP +.B +Usage - Limit test client +.PP +.nf +.fam C + Limit testing (-T L) neither requires nor connects to any server + instance. The client runs one or more tests which attempt to + exhaust various resources to determine DAPL limits and exercise + DAPL error paths. If no arguments are given, all tests are run. + + Limit testing creates the sequence of DAT objects needed to + move data back and forth, attempting to find the limits supported + for the DAPL object requested. For example, if the LMR creation + limit is being examined, the test will create a set of + {IA, PZ, CNO, EVD, EP} before trying to run dat_lmr_create() to + failure using that set of DAPL objects. The 'width' parameter + can be used to control how many of these parallel DAPL object + sets are created before beating upon the requested constructor. + Use of -m limits the number of dat_*_create() calls that will + be attempted, which can be helpful if the DAPL in use supports + essentailly unlimited numbers of some objects. + + The limit test arguments are: + + [ -m maximum ] Specify the maximum number of dapl_*_create() + attempts. + Default: run to object creation failure + + [ -w width ] Specify the number of DAPL object sets to + create while initializing. + Default: 1 + + [ limit_ia ] Attempt to exhaust dat_ia_open() + + [ limit_pz ] Attempt to exhaust dat_pz_create() + + [ limit_cno ] Attempt to exhaust dat_cno_create() + + [ limit_evd ] Attempt to exhaust dat_evd_create() + + [ limit_ep ] Attempt to exhaust dat_ep_create() + + [ limit_rsp ] Attempt to exhaust dat_rsp_create() + + [ limit_psp ] Attempt to exhaust dat_psp_create() + + [ limit_lmr ] Attempt to exhaust dat_lmr_create(4KB) + + [ limit_rpost ] Attempt to exhaust dat_ep_post_recv(4KB) + + [ limit_size_lmr ] Probe maximum size dat_lmr_create() + +.nf +.fam C + Default: run all tests + + +.fam T +.fi +.SH EXAMPLES + +dapltest -T S -d -D OpenIB-cma +.PP +.nf +.fam C + Starts a server process with debug verbosity. + +.fam T +.fi +dapltest -T T -d -s host1-ib0 -D OpenIB-cma -i 100 client SR 4096 2 server SR 4096 2 +.PP +.nf +.fam C + Runs a transaction test, with both sides + sending one buffer with two 4KB segments, + one hundred times. + +.fam T +.fi +dapltest -T P -d -s host1-ib0 -D OpenIB-cma -i 100 RW 4096 2 +.PP +.nf +.fam C + Runs a performance test, with the client + sending one buffer with two 4KB segments, + one hundred times. + +.fam T +.fi +dapltest -T Q -s host1-ib0 -D OpenIB-cma +.PP +.nf +.fam C + Asks the server to clean up and exit. + +.fam T +.fi +dapltest -T L -D OpenIB-cma -d -w 16 -m 1000 +.PP +.nf +.fam C + Runs all of the limit tests, setting up + 16 complete sets of DAPL objects, and + creating at most a thousand instances + when trying to exhaust resources. + +.fam T +.fi +dapltest -T T -V -d -t 2 -w 4 -i 55555 -s linux3 -D OpenIB-cma +client RW 4096 1 server RW 2048 4 +client SR 1024 4 server SR 4096 2 +client SR 1024 3 -f server SR 2048 1 -f +.PP +.nf +.fam C + Runs a more complicated transaction test, + with two thread using four EPs each, + sending a more complicated buffer pattern + for a larger number of iterations, + validating the data received. + + +.fam T +.fi +.RE +.TP +.B +BUGS +(and To Do List) +.PP +.nf +.fam C + Use of CNOs (-Q) is not yet supported. + + Further limit tests could be added. diff --git a/branches/WOF2-3/ulp/dapl2/man/dat.conf.5 b/branches/WOF2-3/ulp/dapl2/man/dat.conf.5 new file mode 100644 index 00000000..e64ec814 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/man/dat.conf.5 @@ -0,0 +1,108 @@ +.TH "DAT.CONF" "5" "25 March 2008" "" "" +.SH NAME +dat.conf \- configuration file for static registration of user-level DAT rdma providers +.SH "DESCRIPTION" +.PP +The DAT (direct access transport) architecture supports the use of +multiple DAT providers within a single consumer application. +Consumers implicitly select a provider using the Interface Adapter +name parameter passed to dat_ia_open(). +.PP +The subsystem that maps Interface Adapter names to provider +implementations is known as the DAT registry. When a consumer calls +dat_ia_open(), the appropriate provider is found and notified of the +consumer's request to access the IA. After this point, all DAT API +calls acting on DAT objects are automatically directed to the +appropriate provider entry points. +.PP +A persistent, administratively configurable database is used to store +mappings from IA names to provider information. This provider +information includes: the file system path to the provider library +object, version information, and thread safety information. The +location and format of the registry is platform dependent. This +database is known as the Static Registry (SR) and is provided via +entries in the \fIdat.conf\fR file. The process of adding a provider +entry is termed Static Registration. +.PP +.SH "Registry File Format" +\br + * All characters after # on a line are ignored (comments). + * Lines on which there are no characters other than whitespace + and comments are considered blank lines and are ignored. + * Non-blank lines must have seven whitespace separated fields. + These fields may contain whitespace if the field is quoted + with double quotes. Within fields quoated with double quotes, + the backslash or qoute are valid escape sequences: + * Each non-blank line will contain the following fields: + - The IA Name. + - The API version of the library: + [k|u]major.minor where "major" and "minor" are both integers + in decimal format. User-level examples: "u1.2", and "u2.0". + - Whether the library is thread-safe: [threadsafe|nonthreadsafe] + - Whether this is the default section: [default|nondefault] + - The library image, version included, to be loaded. + - The vendor id and version of DAPL provider: id.major.minor + - ia params, IA specific parameters - device name and port + - platform params, (not used) +.PP +.SH OpenFabrics RDMA providers: +\br + Provider options for both 1.2 and 2.0, each using different CM services + + 1. cma - OpenFabrics rdma_cm - uses rdma_cm services for connections + - requires IPoIB and SA/SM services for IB + - netdev used for device name, without port designation (ia_params) + - Supports any transport rdma_cm supports including IB, iWARP, RoCEE + - libdaplcma.so (1.2), libdaplofa (2.0) + + 2. scm - uDAPL socket based CM - exchanges CM information over sockets + - eliminates the need for rdma_cm, IPoIB, and SA for IB + - verbs device used for device name with port designation (ia_param) + - Supports IB, RoCEE. Doesn't support iWARP + - libdaplscm.so (1.2), libdaploscm (2.0) + + 3. ucm - uDAPL unreliable IB CM - exchanges CM information via IB UD QP's + - eliminates the need for sockets or rdma_cm + - verbs device used for device name with port designation (ia_param) + - Supports IB only, no name service. + - libdaplucm.so (1.2), libdaploucm (2.0) +.PP +.SH Example entries for each OpenFabrics provider +\br + + 1. cma - OpenFarbrics rdma_cm (v1.2 and v2.0 examples) + + OpenIB-cma u1.2 nonthreadsafe default libdaplcma.so.1 dapl.1.2 "ib0 0" "" + ofa-v2-ib0 u2.0 nonthreadsafe default libdaplofa.so.2 dapl.2.0 "ib0 0" "" + ofa-v2-iwarp u2.0 nonthreadsafe default libdaplofa.so.2 dapl.2.0 "eth2 0" "" + ofa-v2-cma-roe-eth2 u2.0 nonthreadsafe default libdaplofa.so.2 dapl.2.0 "eth2 0" "" + ofa-v2-cma-roe-eth3 u2.0 nonthreadsafe default libdaplofa.so.2 dapl.2.0 "eth3 0" "" + + NOTE: The OpenFabrics CMA providers use to specify the device with one of the following: + network address, network hostname, or netdev name; along with port number. + + 2. scm - uDAPL socket based CM (v1.2 and v2.0 examples) + + OpenIB-mlx4_0-1 u1.2 nonthreadsafe default libdaplscm.so.1 dapl.1.2 "mlx4_0 1" "" + OpenIB-ipath0-1 u1.2 nonthreadsafe default libdaplscm.so.1 dapl.1.2 "ipath0 1" "" + ofa-v2-mlx4_0-1 u2.0 nonthreadsafe default libdaploscm.so.2 dapl.2.0 "mlx4_0 1" "" + ofa-v2-mlx4_0-2 u2.0 nonthreadsafe default libdaploscm.so.2 dapl.2.0 "mlx4_0 2" "" + ofa-v2-mlx4_1-1 u2.0 nonthreadsafe default libdaploscm.so.2 dapl.2.0 "mlx4_1 1" "" + ofa-v2-ehca0-1 u2.0 nonthreadsafe default libdaploscm.so.2 dapl.2.0 "ehca0 1" "" + ofa-v2-scm-roe-mlx4_0-1 u2.0 nonthreadsafe default libdaploscm.so.2 dapl.2.0 "mlx4_0 1" "" + + 3. ucm - uDAPL unreliable IB CM (not supported in 1.2, v2.0 examples) + + ofa-v2-mlx4_0-1u u2.0 nonthreadsafe default libdaploucm.so.2 dapl.2.0 "mlx4_0 1" "" + ofa-v2-mlx4_0-2u u2.0 nonthreadsafe default libdaploucm.so.2 dapl.2.0 "mlx4_0 2" "" + ofa-v2-ipath0-1u u2.0 nonthreadsafe default libdaploucm.so.2 dapl.2.0 "ipath0 1" "" + ofa-v2-ehca0-1u u2.0 nonthreadsafe default libdaploucm.so.2 dapl.2.0 "ehca0 1" "" + + Note: OpenIB- and ofa-v2- IA names are unique mappings, reserved for OpenFabrics providers. +.PP +The default location for this configuration file is /etc/dat.conf. +.PP +The file location may be overridden with the environment variable DAT_OVERRIDE=/your_own_directory/your_dat.conf. +.PP +.SH "SEE ALSO" rdma_cm verbs socket +.PP diff --git a/branches/WOF2-3/ulp/dapl2/man/dtest.1 b/branches/WOF2-3/ulp/dapl2/man/dtest.1 new file mode 100644 index 00000000..1e227e50 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/man/dtest.1 @@ -0,0 +1,78 @@ +.TH dtest 1 "February 23, 2007" "uDAPL 1.2" "USER COMMANDS" + +.SH NAME +dtest \- simple uDAPL send/receive and RDMA test + +.SH SYNOPSIS +.B dtest +[\-P provider] [\-b buf size] [\-B burst count][\-v] [\-c] [\-p] [\-d]\fB [-s]\fR + +.B dtest +[\-P provider] [\-b buf size] [\-B burst count][\-v] [\-c] [\-p] [\-d]\fB [-h HOSTNAME]\fR + +.SH DESCRIPTION +.PP +dtest is a simple test used to exercise and verify the uDAPL interfaces. +At least two instantiations of the test must be run. One acts as the server +and the other the client. The server side of the test, once invoked listens +for connection requests, until timing out or killed. Upon receipt of a cd +connection request, the connection is established, the server and client +sides exchange information necessary to perform RDMA writes and reads. + +.SH OPTIONS + +.PP +.TP +\fB\-P\fR=\fIPROVIDER\fR +use \fIPROVIDER\fR to specify uDAPL interface using /etc/dat.conf (default OpenIB-cma) +.TP +\fB\-b\fR=\fIBUFFER_SIZE\fR +use buffer size \fIBUFFER_SIZE\fR for RDMA(default 64) +.TP +\fB\-B\fR=\fIBURST_COUNT\fR +use busrt count \fIBURST_COUNT\fR for interations (default 10) +.TP +\fB\-v\fR, verbose output(default off) +.TP +\fB\-c\fR, use consumer notification events (default off) +.TP +\fB\-p\fR, use polling (default wait for event) +.TP +\fB\-d\fR, delay in seconds before close (default off) +.TP +\fB\-s\fR, run as server (default - run as server) +.TP +\fB\-h\fR=\fIHOSTNAME\fR +use \fIHOSTNAME\fR to specify server hostname or IP address (default - none) + +.SH EXAMPLES + +dtest -P OpenIB-cma -v -s +.PP +.nf +.fam C + Starts a server process with debug verbosity using provider OpenIB-cma. + +.fam T +.fi +dtest -P OpenIB-cma -h server1-ib0 +.PP +.nf +.fam C + Starts a client process, using OpenIB-cma provider to connect to hostname server1-ib0. + +.fam T + +.SH SEE ALSO +.BR dapltest(1) + +.SH AUTHORS +.TP +Arlin Davis +.RI < ardavis@ichips.intel.com > + +.SH BUGS + + + + diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/Makefile.am b/branches/WOF2-3/ulp/dapl2/test/dapltest/Makefile.am new file mode 100644 index 00000000..bfc25338 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/Makefile.am @@ -0,0 +1,67 @@ +if EXT_TYPE_IB +XFLAGS = -DDAT_EXTENSIONS +else +XFLAGS = +endif + +AM_CFLAGS = -g -Wall -D_GNU_SOURCE + +dapltest_CFLAGS = $(AM_FLAGS) $(XFLAGS) + +INCLUDES = -I include \ + -I mdep/linux \ + -I $(srcdir)/../../dat/include + +bin_PROGRAMS = dapltest + +dapltest_SOURCES = \ + cmd/dapl_main.c \ + cmd/dapl_params.c \ + cmd/dapl_fft_cmd.c \ + cmd/dapl_getopt.c \ + cmd/dapl_limit_cmd.c \ + cmd/dapl_netaddr.c \ + cmd/dapl_performance_cmd.c \ + cmd/dapl_qos_util.c \ + cmd/dapl_quit_cmd.c \ + cmd/dapl_server_cmd.c \ + cmd/dapl_transaction_cmd.c \ + test/dapl_bpool.c \ + test/dapl_client.c \ + test/dapl_client_info.c \ + test/dapl_cnxn.c \ + test/dapl_execute.c \ + test/dapl_fft_connmgt.c \ + test/dapl_fft_endpoint.c \ + test/dapl_fft_hwconn.c \ + test/dapl_fft_mem.c \ + test/dapl_fft_pz.c \ + test/dapl_fft_queryinfo.c \ + test/dapl_fft_test.c \ + test/dapl_fft_util.c \ + test/dapl_limit.c \ + test/dapl_memlist.c \ + test/dapl_performance_client.c \ + test/dapl_performance_server.c \ + test/dapl_performance_stats.c \ + test/dapl_performance_util.c \ + test/dapl_quit_util.c \ + test/dapl_server.c \ + test/dapl_server_info.c \ + test/dapl_test_data.c \ + test/dapl_test_util.c \ + test/dapl_thread.c \ + test/dapl_transaction_stats.c \ + test/dapl_transaction_test.c \ + test/dapl_transaction_util.c \ + test/dapl_util.c \ + common/dapl_endian.c \ + common/dapl_global.c \ + common/dapl_performance_cmd_util.c \ + common/dapl_quit_cmd_util.c \ + common/dapl_transaction_cmd_util.c \ + udapl/udapl_tdep.c \ + mdep/linux/dapl_mdep_user.c + +dapltest_LDADD = $(top_builddir)/dat/udat/libdat2.la +dapltest_LDFLAGS = -lpthread diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/README b/branches/WOF2-3/ulp/dapl2/test/dapltest/README new file mode 100644 index 00000000..98f66569 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/README @@ -0,0 +1,293 @@ + +NAME + + dapltest - test for the Direct Access Programming Library (DAPL) + +DESCRIPTION + + Dapltest is a set of tests developed to exercise, characterize, + and verify the DAPL interfaces during development and porting. + At least two instantiations of the test must be run. One acts + as the server, fielding requests and spawning server-side test + threads as needed. Other client invocations connect to the + server and issue test requests. + + The server side of the test, once invoked, listens continuously + for client connection requests, until quit or killed. Upon + receipt of a connection request, the connection is established, + the server and client sides swap version numbers to verify that + they are able to communicate, and the client sends the test + request to the server. If the version numbers match, and the + test request is well-formed, the server spawns the threads + needed to run the test before awaiting further connections. + +USAGE + + dapltest [ -f script_file_name ] + [ -T S|Q|T|P|L ] [ -D device_name ] [ -d ] [ -R HT|LL|EC|PM|BE ] + + With no arguments, dapltest runs as a server using default values, + and loops accepting requests from clients. The -f option allows + all arguments to be placed in a file, to ease test automation. + The following arguments are common to all tests: + + [ -T S|Q|T|P|L ] Test function to be performed: + S - server loop + Q - quit, client requests that server + wait for any outstanding tests to + complete, then clean up and exit + T - transaction test, transfers data between + client and server + P - performance test, times DTO operations + L - limit test, exhausts various resources, + runs in client w/o server interaction + Default: S + + [ -D device_name ] Specifies the name of the device (interface adapter). + Default: host-specific, look for DT_MdepDeviceName + in dapl_mdep.h + + [ -d ] Enables extra debug verbosity, primarily tracing + of the various DAPL operations as they progress. + Repeating this parameter increases debug spew. + Errors encountered result in the test spewing some + explanatory text and stopping; this flag provides + more detail about what lead up to the error. + Default: zero + + [ -R BE ] Indicate the quality of service (QoS) desired. + Choices are: + HT - high throughput + LL - low latency + EC - economy (neither HT nor LL) + PM - premium + BE - best effort + Default: BE + +USAGE - Quit test client + + dapltest [Common_Args] [ -s server_name ] + + Quit testing (-T Q) connects to the server to ask it to clean up and + exit (after it waits for any outstanding test runs to complete). + In addition to being more polite than simply killing the server, + this test exercises the DAPL object teardown code paths. + There is only one argument other than those supported by all tests: + + -s server_name Specifies the name of the server interface. + No default. + + +USAGE - Transaction test client + + dapltest [Common_Args] [ -s server_name ] + [ -t threads ] [ -w endpoints ] [ -i iterations ] [ -Q ] + [ -V ] [ -P ] OPclient OPserver [ op3, + + Transaction testing (-T T) transfers a variable amount of data between + client and server. The data transfer can be described as a sequence of + individual operations; that entire sequence is transferred 'iterations' + times by each thread over all of its endpoint(s). + + The following parameters determine the behavior of the transaction test: + + -s server_name Specifies the name of the server interface. + No default. + + [ -t threads ] Specify the number of threads to be used. + Default: 1 + + [ -w endpoints ] Specify the number of connected endpoints per thread. + Default: 1 + + [ -i iterations ] Specify the number of times the entire sequence + of data transfers will be made over each endpoint. + Default: 1000 + + [ -Q ] Funnel completion events into a CNO. + Default: use EVDs + + [ -V ] Validate the data being transferred. + Default: ignore the data + + [ -P ] Turn on DTO completion polling + Default: off + + OP1 OP2 [ OP3, ... ] + A single transaction (OPx) consists of: + + server|client Indicates who initiates the + data transfer. + + SR|RR|RW Indicates the type of transfer: + SR send/recv + RR RDMA read + RW RDMA write + Defaults: none + + [ seg_size [ num_segs ] ] + Indicates the amount and format + of the data to be transferred. + Default: 4096 1 + (i.e., 1 4KB buffer) + + [ -f ] For SR transfers only, indicates + that a client's send transfer + completion should be reaped when + the next recv completion is reaped. + Sends and receives must be paired + (one client, one server, and in that + order) for this option to be used. + + Restrictions: + + Due to the flow control algorithm used by the transaction test, there + must be at least one SR OP for both the client and the server. + + Requesting data validation (-V) causes the test to automatically append + three OPs to those specified. These additional operations provide + synchronization points during each iteration, at which all user-specified + transaction buffers are checked. These three appended operations satisfy + the "one SR in each direction" requirement. + + The transaction OP list is printed out if -d is supplied. + +USAGE - Performance test client + + dapltest [Common_Args] -s server_name [ -m p|b ] + [ -i iterations ] [ -p pipeline ] OP + + Performance testing (-T P) times the transfer of an operation. + The operation is posted 'iterations' times. + + The following parameters determine the behavior of the transaction test: + + -s server_name Specifies the name of the server interface. + No default. + + -m b|p Used to choose either blocking (b) or polling (p) + Default: blocking (b) + + [ -i iterations ] Specify the number of times the entire sequence + of data transfers will be made over each endpoint. + Default: 1000 + + [ -p pipeline ] Specify the pipline length, valid arguments are in + the range [0,MAX_SEND_DTOS]. If a value greater than + MAX_SEND_DTOS is requested the value will be + adjusted down to MAX_SEND_DTOS. + Default: MAX_SEND_DTOS + + OP + An operation consists of: + + RR|RW Indicates the type of transfer: + RR RDMA read + RW RDMA write + Default: none + + [ seg_size [ num_segs ] ] + Indicates the amount and format + of the data to be transferred. + Default: 4096 1 + (i.e., 1 4KB buffer) + +USAGE - Limit test client + + Limit testing (-T L) neither requires nor connects to any server + instance. The client runs one or more tests which attempt to + exhaust various resources to determine DAPL limits and exercise + DAPL error paths. If no arguments are given, all tests are run. + + Limit testing creates the sequence of DAT objects needed to + move data back and forth, attempting to find the limits supported + for the DAPL object requested. For example, if the LMR creation + limit is being examined, the test will create a set of + {IA, PZ, CNO, EVD, EP} before trying to run dat_lmr_create() to + failure using that set of DAPL objects. The 'width' parameter + can be used to control how many of these parallel DAPL object + sets are created before beating upon the requested constructor. + Use of -m limits the number of dat_*_create() calls that will + be attempted, which can be helpful if the DAPL in use supports + essentailly unlimited numbers of some objects. + + The limit test arguments are: + + [ -m maximum ] Specify the maximum number of dapl_*_create() + attempts. + Default: run to object creation failure + + [ -w width ] Specify the number of DAPL object sets to + create while initializing. + Default: 1 + + [ limit_ia ] Attempt to exhaust dat_ia_open() + + [ limit_pz ] Attempt to exhaust dat_pz_create() + + [ limit_cno ] Attempt to exhaust dat_cno_create() + + [ limit_evd ] Attempt to exhaust dat_evd_create() + + [ limit_ep ] Attempt to exhaust dat_ep_create() + + [ limit_rsp ] Attempt to exhaust dat_rsp_create() + + [ limit_psp ] Attempt to exhaust dat_psp_create() + + [ limit_lmr ] Attempt to exhaust dat_lmr_create(4KB) + + [ limit_rpost ] Attempt to exhaust dat_ep_post_recv(4KB) + + [ limit_size_lmr ] Probe maximum size dat_lmr_create() + + Default: run all tests + + +EXAMPLES + + dapltest -T S -d -D jni0a + + Starts a server process with debug verbosity. + + dapltest -T T -d -s linux3 -D jni0a -i 100 \ + client SR 4096 2 server SR 4096 2 + + Runs a transaction test, with both sides + sending one buffer with two 4KB segments, + one hundred times. + + dapltest -T P -d -s linux3 -D JniIbdd0 -i 100 SR 4096 2 + + Runs a performance test, with the client + sending one buffer with two 4KB segments, + one hundred times. + + dapltest -T Q -s linux3 -D jni0a + + Asks the server to clean up and exit. + + dapltest -T L -D jni0a -d -w 16 -m 1000 + + Runs all of the limit tests, setting up + 16 complete sets of DAPL objects, and + creating at most a thousand instances + when trying to exhaust resources. + + dapltest -T T -V -d -t 2 -w 4 -i 55555 -s linux3 -D jni0a \ + client RW 4096 1 server RW 2048 4 \ + client SR 1024 4 server SR 4096 2 \ + client SR 1024 3 -f server SR 2048 1 -f + + Runs a more complicated transaction test, + with two thread using four EPs each, + sending a more complicated buffer pattern + for a larger number of iterations, + validating the data received. + + +BUGS (and To Do List) + + Use of CNOs (-Q) is not yet supported. + + Further limit tests could be added. diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/cmd/dapl_fft_cmd.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/cmd/dapl_fft_cmd.c new file mode 100644 index 00000000..a604e936 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/cmd/dapl_fft_cmd.c @@ -0,0 +1,325 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" + +//--------------------------------------------------------------------------- +void DT_FFT_Cmd_Init(FFT_Cmd_t * cmd) +{ + int i; + memset((void *)cmd, 0, sizeof(FFT_Cmd_t)); + cmd->fft_type = NONE; + cmd->device_name[0] = '\0'; + cmd->server_name[0] = '\0'; + for (i = 0; i < MAXCASES; i++) { + cmd->cases_flag[i] = false; + } + cmd->size = 0; + cmd->num_iter = 1000; + cmd->num_threads = 10; + cmd->num_vis = 500; + cmd->ReliabilityLevel = DAT_QOS_BEST_EFFORT; +} + +//------------------------------------------------------------------------------ +bool DT_FFT_Cmd_Parse(FFT_Cmd_t * cmd, + int my_argc, char **my_argv, mygetopt_t * opts) +{ + int c; + int i, caseNum; + unsigned int len; + + for (;;) { + c = DT_mygetopt_r(my_argc, my_argv, "D:f:s:i:t:v:R:", opts); + if (c == EOF) { + break; + } + switch (c) { + case 'D': //device name + { + strcpy(cmd->device_name, opts->optarg); + break; + } + case 's': //server name + { + strcpy(cmd->server_name, opts->optarg); + break; + } + case 'i': // num iterations + { + len = strspn(opts->optarg, "0123456789"); + if (len == 0 || len != strlen(opts->optarg)) { + DT_Mdep_printf + ("Syntax Error -i option\n"); + DT_FFT_Cmd_Usage(); + return (false); + } + cmd->num_iter = atoi(opts->optarg); + break; + } + case 't': // num threads + { + len = strspn(opts->optarg, "0123456789"); + if (len == 0 || len != strlen(opts->optarg)) { + DT_Mdep_printf + ("Syntax Error -t option\n"); + DT_FFT_Cmd_Usage(); + return (false); + } + cmd->num_threads = atoi(opts->optarg); + break; + } + case 'v': // num vis + { + len = strspn(opts->optarg, "0123456789"); + if (len == 0 || len != strlen(opts->optarg)) { + DT_Mdep_printf + ("Syntax Error -v option\n"); + DT_FFT_Cmd_Usage(); + return (false); + } + cmd->num_vis = atoi(opts->optarg); + break; + } + case 'f': //function feature + { + if (strcmp(opts->optarg, "hwconn") == 0) { + cmd->fft_type = HWCONN; + cmd->size = 4; //4 cases for hwconn + break; + } +#if 0 // not yet implemented + else if (strcmp(opts->optarg, "cqmgt") == 0) { + cmd->fft_type = CQMGT; + cmd->size = 10; //10 cases for cqmgt + break; + } +#endif + else if (strcmp(opts->optarg, "endpoint") == 0) { + cmd->fft_type = ENDPOINT; + cmd->size = 3; //13 cases for endpoint + break; + } else if (strcmp(opts->optarg, "pz") == 0) { + cmd->fft_type = PTAGMGT; + cmd->size = 3; //10 cases for Ptagmgt + break; + } else if (strcmp(opts->optarg, "mem") == 0) { + cmd->fft_type = MEMMGT; + cmd->size = 5; //12 cases for Memmgt + break; + } else if (strcmp(opts->optarg, "connmgt") == 0) { + cmd->fft_type = CONNMGT; + cmd->size = 2; //16 cases for connmgt + break; + } +#if 0 // not yet implemented + else if (strcmp(opts->optarg, "connmgt_client") + == 0) { + cmd->fft_type = CONNMGT_CLIENT; + cmd->size = 16; //16 cases for connmgt_client + break; + } +#endif + else if (strcmp(opts->optarg, "queryinfo") == 0) { + cmd->fft_type = QUERYINFO; +#ifndef __KDAPLTEST__ + cmd->size = 18; //18 cases for UDAPL queryinfo +#else + cmd->size = 16; //16 cases for KDAPL queryinfo +#endif + break; + } +#if 0 // not yet implemented + else if (strcmp(opts->optarg, "ns") == 0) { + cmd->fft_type = NS; + cmd->size = 10; //10 cases for ns + break; + } else if (strcmp(opts->optarg, "errhand") == 0) { + cmd->fft_type = ERRHAND; + cmd->size = 2; //2 cases for errhand + break; + } else if (strcmp(opts->optarg, "unsupp") == 0) { + cmd->fft_type = UNSUPP; + cmd->size = 2; //2 cases for unsupp + break; + } else if (strcmp(opts->optarg, "stress") == 0) { + cmd->fft_type = STRESS; + cmd->size = 6; //6 cases for stress + break; + } else if (strcmp(opts->optarg, "stress_client") + == 0) { + cmd->fft_type = STRESS_CLIENT; + cmd->size = 6; //6 cases for stress_client + break; + } +#endif + else { + DT_Mdep_printf + ("don't know this function feature: %s\n", + opts->optarg); + DT_FFT_Cmd_Usage(); + return (false); + } + } + case 'R': // Service Reliability Level + { + cmd->ReliabilityLevel = + DT_ParseQoS(opts->optarg); + if (0 == cmd->ReliabilityLevel) { + DT_Mdep_printf + ("Invalid FFT Test Parameter: %c\n", + c); + DT_FFT_Cmd_Usage(); + return (false); + } + break; + } + + case '?': + default: + { + DT_Mdep_printf + ("Invalid FFT Test Parameter: %c\n", c); + DT_FFT_Cmd_Usage(); + return (false); + } + } + } + if (cmd->device_name[0] == '\0') { + if (!DT_Mdep_GetDefaultDeviceName(cmd->device_name)) { + DT_Mdep_printf("can't get default device name\n"); + DT_FFT_Cmd_Usage(); + return (false); + } + } + + if (cmd->fft_type == NONE) { + DT_Mdep_printf + ("must define the function feature with -f to test\n"); + DT_FFT_Cmd_Usage(); + return (false); + } + if (cmd->server_name[0] == '\0' && + (cmd->fft_type == CONNMGT_CLIENT || cmd->fft_type == DATAXFER_CLIENT + || cmd->fft_type == UNSUPP || cmd->fft_type == STRESS_CLIENT)) { + DT_Mdep_printf("must define the server name with -s option\n"); + DT_FFT_Cmd_Usage(); + return (false); + } + + if (cmd->server_name[0] == '\0' && cmd->fft_type == NS) { + DT_Mdep_printf("\ + Must specify host name or host IP address with -s option to be tested\n"); + DT_FFT_Cmd_Usage(); + return (false); + } + //now parse the test cases + if (opts->optind == my_argc) //default: test all cases + { + for (i = 0; i < cmd->size; i++) { + cmd->cases_flag[i] = true; + } + return true; + } + //test specified cases + i = opts->optind; + while (i < my_argc) { + if (strlen(my_argv[i]) < 5 + || strncmp(my_argv[i], "case", 4) != 0) { + DT_Mdep_printf("test cases format is not correct: %s\n", + my_argv[i]); + DT_FFT_Cmd_Usage(); + return (false); + } + len = strspn(my_argv[i] + 4, "0123456789"); + if (len == 0 || len != strlen(my_argv[i] + 4)) { + DT_Mdep_printf("must specify case number: %s\n", + my_argv[i]); + DT_FFT_Cmd_Usage(); + return (false); + } + caseNum = atoi(my_argv[i] + 4); + if (caseNum < 0 || caseNum >= cmd->size) { + DT_Mdep_printf + ("test case number must be within range : 0 -- %d\n", + cmd->size - 1); + DT_FFT_Cmd_Usage(); + return (false); + } + cmd->cases_flag[caseNum] = true; + i++; + } + return (true); +} + +//-------------------------------------------------------------- +void DT_FFT_Cmd_Usage(void) +{ + char usage[] = { + "dapltest -T F [-D ] -f [-i ] \n" + "[-t ] [-v ] [-s ] [case0] [case1] [...]\n" + "USAGE: [-D ]\n" + "USAGE: -f \n" + "USAGE: hwconn\n" + "USAGE: endpoint\n" + "USAGE: pz\n" + "USAGE: mem\n" + "USAGE: connmgt\n" + "USAGE: queryinfo\n" +#if 0 // not yet implemented + "USAGE: connmgt_client (not yet implemented)\n" + "USAGE: cqmgt (not yet implemented)\n" + "USAGE: ns (not yet implemented)\n" + "USAGE: errhand (not yet implemented)\n" + "USAGE: unsupp (not yet implemented)\n" + "USAGE: stress (not yet implemented)\n" + "USAGE: stress_client (not yet implemented)\n" +#endif + "USAGE: -i : itreration time for stress test\n" + "USAGE: -t : number of threads for stress test\n" + "USAGE: -v : number of vis for stress test\n" + "USAGE: -s \n" + "USAGE: server host name or ip address\n" + "USAGE: [-R ]\n" + "USAGE: (BE == QOS_BEST_EFFORT - Default )\n" + "USAGE: (HT == QOS_HIGH_THROUGHPUT))\n" + "USAGE: (LL == QOS_LOW_LATENCY)\n" + "USAGE: (EC == QOS_ECONOMY)\n" + "USAGE: (PM == QOS_PREMIUM)\n" + "NOTE: iter_num is just for stress_client test, default 100000\n" + "NOTE: Server_name must be specified for connmgt_client, \n" + " NS and unsupp function feature.\n" + "NOTE: if test cases are not specified, test all cases in that function\n" + " feature. else just test the specified cases\n" + }; + + DT_Mdep_printf("USAGE: -------FFT TEST------------\n"); + DT_Mdep_printf("%s\n", usage); +} diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/cmd/dapl_getopt.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/cmd/dapl_getopt.c new file mode 100644 index 00000000..293ab67b --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/cmd/dapl_getopt.c @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" + +#define GETOPT_MAGIC 0x04030201 + +#define BADCH (int)'?' +#define BADARG (int)':' +#define EMSG "" + +/** + * Initialize the getopt fields in preparation for parsing + * a command line. + */ +void DT_mygetopt_init(mygetopt_t * opts) +{ + opts->magic = GETOPT_MAGIC; + opts->place = EMSG; + opts->opterr = 1; + opts->optind = 1; + opts->optopt = 0; + opts->optarg = 0; +} + +/** + * Parse command line arguments. + * + * Return either the option discovered, or + * (int) -1 when there are no more options + * (int) '?' when an illegal option is found + * (int) ':' when a required option argument is missing. + */ +int +DT_mygetopt_r(int argc, char *const *argv, const char *ostr, mygetopt_t * opts) +{ + char *p; + char *oli; /* option letter list index */ + if (GETOPT_MAGIC != opts->magic) { + DT_Mdep_printf("%s: getopt warning: " + "option argument is not properly initialized.\n", + argc > 0 ? argv[0] : "unknown command"); + DT_mygetopt_init(opts); + } + if (!*(opts->place)) { /* update scanning pointer */ + if ((opts->optind) >= argc || + *((opts->place) = argv[(opts->optind)]) != '-') { + (opts->place) = EMSG; + return (EOF); + } + if ((opts->place)[0] != '-') { + /* Invalid 1st argument */ + return (BADCH); + } + if ((opts->place)[1] && *++(opts->place) == '-') { + /* found "--" which is an invalid option */ + ++(opts->optind); + (opts->place) = EMSG; + return (BADCH); + } + } /* option letter okay? */ + opts->optopt = (int)*(opts->place)++; + oli = strchr(ostr, (opts->optopt)); + if (opts->optopt == (int)':' || !oli) { + /* + * if the user didn't specify '-' as an option, assume it means EOF. + */ + if ((opts->optopt) == (int)'-') { + /* return (EOF); */ + return (BADCH); + } + if (!*(opts->place)) { + ++(opts->optind); + } + if ((opts->opterr) && *ostr != ':') { + p = strchr(*argv, '/'); + if (!p) { + p = *argv; + } else { + ++p; + } + + if (opts->optopt != '?') { /* Anything but '?' needs error */ + DT_Mdep_printf("%s: Illegal option -- %c\n", + p, (opts->optopt)); + } + } + return (BADCH); + } + if (*++oli != ':') { /* don't need argument */ + (opts->optarg) = NULL; + if (!*(opts->place)) { + ++(opts->optind); + } + } else { /* need an argument */ + + if (*(opts->place)) { /* no white space */ + (opts->optarg) = (opts->place); + } else { + if (argc <= ++(opts->optind)) { /* no arg */ + (opts->place) = EMSG; + if (*ostr == ':') { + return (BADARG); + } + p = strchr(*argv, '/'); + if (!p) { + p = *argv; + } else { + ++p; + } + if ((opts->opterr)) { + DT_Mdep_printf + ("%s: option requires an argument -- %c\n", + p, (opts->optopt)); + } + return (BADCH); + } else { /* white space */ + + (opts->optarg) = argv[(opts->optind)]; + } + } + (opts->place) = EMSG; + ++(opts->optind); + } + return (opts->optopt); /* dump back option letter */ +} diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/cmd/dapl_limit_cmd.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/cmd/dapl_limit_cmd.c new file mode 100644 index 00000000..69b8b7c9 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/cmd/dapl_limit_cmd.c @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" + +/* --------------------------------------------------- */ +void DT_Limit_Cmd_Init(Limit_Cmd_t * cmd) +{ + memset((void *)cmd, 0, sizeof(Limit_Cmd_t)); + cmd->ReliabilityLevel = DAT_QOS_BEST_EFFORT; + cmd->width = 1; + cmd->maximum = ~0U; +} + +/* --------------------------------------------------- */ +bool +DT_Limit_Cmd_Parse(Limit_Cmd_t * cmd, + int my_argc, char **my_argv, mygetopt_t * opts) +{ + int c; + int i; + + for (;;) { + c = DT_mygetopt_r(my_argc, my_argv, "dm:w:D:R:", opts); + if (c == EOF) { + break; + } + switch (c) { + case 'D': /* device name */ + { + strcpy(cmd->device_name, opts->optarg); + break; + } + case 'R': /* Service Reliability Level */ + { + cmd->ReliabilityLevel = + DT_ParseQoS(opts->optarg); + break; + } + case 'd': /* print debug messages */ + { + DT_dapltest_debug++; + cmd->debug = true; + break; + } + case 'm': /* maximum for exhaustion testing */ + { + unsigned int len = + strspn(opts->optarg, "0123456789"); + + if (len == 0 || len != strlen(opts->optarg)) { + DT_Mdep_printf + ("Syntax Error -m option\n"); + DT_Limit_Cmd_Usage(); + return (false); + } + cmd->maximum = atol(opts->optarg); + break; + } + case 'w': /* width (number of {ia,evd,ep,...} sets) */ + { + unsigned int len = + strspn(opts->optarg, "0123456789"); + + if (len == 0 || len != strlen(opts->optarg)) { + DT_Mdep_printf + ("Syntax Error -w option\n"); + DT_Limit_Cmd_Usage(); + return (false); + } + cmd->width = atol(opts->optarg); + break; + } + case '?': + default: + { + DT_Mdep_printf + ("Invalid Limit Test Parameter: %c\n", c); + DT_Limit_Cmd_Usage(); + return (false); + } + } + } + if (cmd->device_name[0] == '\0') { + if (!DT_Mdep_GetDefaultDeviceName(cmd->device_name)) { + DT_Mdep_printf("can't get default device name\n"); + DT_Limit_Cmd_Usage(); + return (false); + } + } + + /* + * by default: test all limit tests + * otherwise: parse the remaining limit test arguments + */ + if (opts->optind == my_argc) { + for (i = 0; i < LIM_NUM_TESTS; i++) { + cmd->Test_List[i] = 1; + } + } else { + for (i = opts->optind; i < my_argc; i++) { + + if (strcmp(my_argv[i], "limit_ia") == 0) { + cmd->Test_List[LIM_IA] = 1; + continue; + } + if (strcmp(my_argv[i], "limit_pz") == 0) { + cmd->Test_List[LIM_PZ] = 1; + continue; + } +#ifndef __KDAPLTEST__ + if (strcmp(my_argv[i], "limit_cno") == 0) { + cmd->Test_List[LIM_CNO] = 1; + continue; + } +#endif + if (strcmp(my_argv[i], "limit_evd") == 0) { + cmd->Test_List[LIM_EVD] = 1; + continue; + } + if (strcmp(my_argv[i], "limit_ep") == 0) { + cmd->Test_List[LIM_EP] = 1; + continue; + } + if (strcmp(my_argv[i], "limit_rsp") == 0) { + cmd->Test_List[LIM_RSP] = 1; + continue; + } + if (strcmp(my_argv[i], "limit_psp") == 0) { + cmd->Test_List[LIM_PSP] = 1; + continue; + } + if (strcmp(my_argv[i], "limit_lmr") == 0) { + cmd->Test_List[LIM_LMR] = 1; + continue; + } + if (strcmp(my_argv[i], "limit_rpost") == 0) { + cmd->Test_List[LIM_RPOST] = 1; + continue; + } + if (strcmp(my_argv[i], "limit_size_lmr") == 0) { + cmd->Test_List[LIM_SIZE_LMR] = 1; + continue; + } + + DT_Mdep_printf("Cannot find this limit test: %s\n", + my_argv[i]); + DT_Limit_Cmd_Usage(); + return (false); + + } /* end foreach remaining argv */ + } + + return (true); +} + +/* --------------------------------------------------- */ +void DT_Limit_Cmd_Usage(void) +{ + DT_Mdep_printf("USAGE: ---- LIMIT TEST ----\n"); + DT_Mdep_printf("USAGE: dapltest -T L\n"); + DT_Mdep_printf("USAGE: [-D ]\n"); + DT_Mdep_printf("USAGE: [-d] : debug (zero)\n"); + DT_Mdep_printf("USAGE: [-w ]\n"); + DT_Mdep_printf + ("USAGE: [-m ]\n"); + DT_Mdep_printf("USAGE: [-R ]\n"); + DT_Mdep_printf + ("USAGE: (BE == QOS_BEST_EFFORT - Default)\n"); + DT_Mdep_printf("USAGE: (HT == QOS_HIGH_THROUGHPUT)\n"); + DT_Mdep_printf("USAGE: (LL == QOS_LOW_LATENCY)\n"); + DT_Mdep_printf("USAGE: (EC == QOS_ECONOMY)\n"); + DT_Mdep_printf("USAGE: (PM == QOS_PREMIUM)\n"); + DT_Mdep_printf + ("USAGE: [limit_ia [limit_pz] [limit_evd] ... ]\n"); + DT_Mdep_printf + ("NOTE: If test is not specified, do all the limit tests\n"); + DT_Mdep_printf("NOTE: Else, just do the specified tests\n"); + DT_Mdep_printf + ("NOTE: Each test is separated by space, the test can be:\n"); + + DT_Mdep_printf("NOTE: [limit_ia] test max num of open IAs\n"); + DT_Mdep_printf("NOTE: [limit_pz] test max num of PZs\n"); +#ifndef __KDAPLTEST__ + DT_Mdep_printf("NOTE: [limit_cno] test max num of CNOs\n"); +#endif + DT_Mdep_printf("NOTE: [limit_evd] test max num of EVDs\n"); + DT_Mdep_printf("NOTE: [limit_rsp] test max num of RSPs\n"); + DT_Mdep_printf("NOTE: [limit_psp] test max num of PSPs\n"); + DT_Mdep_printf("NOTE: [limit_ep] test max num of EPs\n"); + DT_Mdep_printf("NOTE: [limit_lmr] test max num of LMRs\n"); + DT_Mdep_printf + ("NOTE: [limit_rpost] test max num of recvs posted\n"); + DT_Mdep_printf("NOTE: [limit_size_lmr] test max size of LMR\n"); +} diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/cmd/dapl_main.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/cmd/dapl_main.c new file mode 100644 index 00000000..9ac6f120 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/cmd/dapl_main.c @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" + +/* Main Entry Point */ +int main(int argc, char *argv[]) +{ + return (dapltest(argc, argv)); +} + +/* + * dapltest main program + */ +int dapltest(int argc, char *argv[]) +{ + Params_t *params_ptr; + DAT_RETURN rc = DAT_SUCCESS; + + /* check memory leaking */ + /* + * DT_Mdep_LockInit(&Alloc_Count_Lock); alloc_count = 0; + */ + +#if defined(_WIN32) || defined(_WIN64) + { + /* Cannot be done from DT_Mdep_Init as dapl_init makes some socket + * calls....So need to do this before calling dapl_init */ + WSADATA wsaData; + int i; + + i = WSAStartup(MAKEWORD(2, 2), &wsaData); + if (i != 0) { + printf("%s WSAStartup(2.2) failed? (0x%x)\n", argv[0], + i); + exit(1); + } + } +#endif + +#ifdef GPROF + { + extern void dapl_init(void); + dapl_init(); + } +#endif + DT_dapltest_debug = 0; + + params_ptr = (Params_t *) DT_Mdep_Malloc(sizeof(Params_t)); + if (!params_ptr) { + DT_Mdep_printf("Cannot allocate memory for Params structure\n"); + return (1); + } + + DT_Tdep_Init(); /* init (kdapl/udapl)test-dependent code */ + DT_Endian_Init(); /* init endian of local machine */ + DT_Mdep_Init(); /* init OS, libraries, etc. */ + + params_ptr->local_is_little_endian = DT_local_is_little_endian; + + /* + * parse command line arguments + */ + if (!DT_Params_Parse(argc, argv, params_ptr)) { + DT_Mdep_printf("Command line syntax error\n"); + return 1; + } + params_ptr->cpu_mhz = DT_Mdep_GetCpuMhz(); + /* call the test-dependent code for invoking the actual test */ + rc = DT_Tdep_Execute_Test(params_ptr); + + /* cleanup */ + + DT_Mdep_End(); + DT_Mdep_Free(params_ptr); + DT_Tdep_End(); +#ifdef GPROF + { + extern void dapl_fini(void); + dapl_fini(); + } +#endif + + /* + * check memory leaking DT_Mdep_printf("App allocated Memory left: %d\n", + * alloc_count); DT_Mdep_LockDestroy(&Alloc_Count_Lock); + */ + + return (rc); +} + +void Dapltest_Main_Usage(void) +{ + DT_Mdep_printf("USAGE:\n"); + DT_Mdep_printf + ("USAGE: dapltest -T [-D IA_name] [test-specific args]\n"); + DT_Mdep_printf("USAGE: where \n"); + DT_Mdep_printf("USAGE: S = Run as a server\n"); + DT_Mdep_printf("USAGE: T = Transaction Test\n"); + DT_Mdep_printf("USAGE: Q = Quit Test\n"); + DT_Mdep_printf("USAGE: P = Performance Test\n"); + DT_Mdep_printf("USAGE: L = Limit Test\n"); + DT_Mdep_printf("USAGE: F = FFT Test\n"); + DT_Mdep_printf("USAGE:\n"); + DT_Mdep_printf + ("USAGE: -D Interface_Adapter {default ibnic0v2}\n"); + DT_Mdep_printf("USAGE:\n"); + DT_Mdep_printf + ("NOTE:\tRun as server taking defaults (dapltest -T S [-D ibnic0v2])\n"); + DT_Mdep_printf("NOTE: dapltest\n"); + DT_Mdep_printf("NOTE:\n"); + DT_Mdep_printf + ("NOTE:\tdapltest arguments may be supplied in a script file\n"); + DT_Mdep_printf("NOTE:\tdapltest -f \n"); + DT_Mdep_printf("USAGE:\n"); +} diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/cmd/dapl_netaddr.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/cmd/dapl_netaddr.c new file mode 100644 index 00000000..e54dec94 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/cmd/dapl_netaddr.c @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" + +DAT_IA_ADDRESS_PTR DT_NetAddrAlloc(Per_Test_Data_t * pt_ptr) +{ + DAT_IA_ADDRESS_PTR netaddr; + + netaddr = (DAT_IA_ADDRESS_PTR) DT_Mdep_Malloc(sizeof(DAT_SOCK_ADDR)); + if (!netaddr) { + DT_Mdep_printf("dapltest: No Memory to create netaddr!\n"); + } + return netaddr; +} + +void DT_NetAddrFree(Per_Test_Data_t * pt_ptr, DAT_IA_ADDRESS_PTR netaddr) +{ + DT_Mdep_Free(netaddr); +} + +bool +DT_NetAddrLookupHostAddress(DAT_IA_ADDRESS_PTR to_netaddr, + DAT_NAME_PTR hostname) +{ + struct addrinfo *target; + int rval; + + rval = getaddrinfo(hostname, NULL, NULL, &target); + if (rval != 0) { + char *whatzit = "unknown error return"; + + switch (rval) { + case EAI_FAMILY: + { + whatzit = "unsupported address family"; + break; + } + case EAI_SOCKTYPE: + { + whatzit = "unsupported socket type"; + break; + } + case EAI_BADFLAGS: + { + whatzit = "invalid flags"; + break; + } + case EAI_NONAME: + { + whatzit = "unknown node name"; + break; + } + case EAI_SERVICE: + { + whatzit = "service unavailable"; + break; + } +#if !defined(WIN32) && defined(__USE_GNU) + case EAI_ADDRFAMILY: + { + whatzit = "node has no address in this family"; + break; + } + case EAI_NODATA: + { + whatzit = "node has no addresses defined"; + break; + } +#endif + case EAI_MEMORY: + { + whatzit = "out of memory"; + break; + } + case EAI_FAIL: + { + whatzit = "permanent name server failure"; + break; + } + case EAI_AGAIN: + { + whatzit = "temporary name server failure"; + break; + } +#if !defined(WIN32) + case EAI_SYSTEM: + { + whatzit = "system error"; + break; + } +#endif + } + + DT_Mdep_printf("getaddrinfo (%s) failed (%s)\n", + hostname, whatzit); + return DAT_FALSE; + } + + /* Pull out IP address and print it as a sanity check */ + DT_Mdep_printf("Server Name: %s \n", hostname); + DT_Mdep_printf("Server Net Address: %s\n", + inet_ntoa(((struct sockaddr_in *)target->ai_addr)-> + sin_addr)); + + *to_netaddr = *((DAT_IA_ADDRESS_PTR) target->ai_addr); + freeaddrinfo(target); + + return (DAT_TRUE); +} diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/cmd/dapl_params.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/cmd/dapl_params.c new file mode 100644 index 00000000..9d5e510f --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/cmd/dapl_params.c @@ -0,0 +1,281 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" + +#define MAX_ARGC 500 +#define MAX_ARG_LEN 100 + +/* Parse command line arguments */ +bool DT_Params_Parse(int argc, char *argv[], Params_t * params_ptr) +{ + Server_Cmd_t *Server_Cmd; + Transaction_Cmd_t *Transaction_Cmd; + Quit_Cmd_t *Quit_Cmd; + Limit_Cmd_t *Limit_Cmd; + Performance_Cmd_t *Performance_Cmd; + FFT_Cmd_t *FFT_Cmd; + + char *filename; + FILE *fd; + mygetopt_t opts; + int c; + char *cp; + char *sp; + char line[256]; + char *my_argv[MAX_ARGC]; + int my_argc; + int i; + DT_mygetopt_init(&opts); + opts.opterr = 0; /* turn off automatical error handler */ + + fd = 0; + my_argc = 0; + for (i = 0; i < MAX_ARGC; i++) { + my_argv[i] = NULL; + } + + /* dapltest with no arguments means run as a server with default values */ + if (argc == 1) { + params_ptr->test_type = SERVER_TEST; + params_ptr->ReliabilityLevel = DAT_QOS_BEST_EFFORT; + Server_Cmd = ¶ms_ptr->u.Server_Cmd; + DT_Server_Cmd_Init(Server_Cmd); + if (!DT_Mdep_GetDefaultDeviceName(Server_Cmd->dapl_name)) { + DT_Mdep_printf("can't get default device name\n"); + return false; + } + return true; + } + /* check for a script file */ + if (strncmp(argv[1], "-f", 2) == 0) { + if (argc == 2) { /* dapltest -fdata */ + filename = argv[1] + 2; + } else { + if (argc == 3 && strcmp(argv[1], "-f") == 0) { /* dapltest -f data */ + filename = argv[2]; + } else { + DT_Mdep_printf + ("-f allows no additional options\n"); + goto main_usage; + } + } + + if (!filename || strlen(filename) == 0) { + DT_Mdep_printf + ("Missing with -f option\n"); + goto main_usage; + } + /* read the script file and create a fake argc, argv */ + fd = fopen(filename, "r"); + if (fd == 0) { + DT_Mdep_printf("Cannot open script file: %s\n", + filename); + goto main_usage; + } + my_argc = 1; + my_argv[0] = DT_Mdep_Malloc(MAX_ARG_LEN); + if (!my_argv[0]) { + DT_Mdep_printf("No Memory\n"); + goto error_return; + } + strcpy(my_argv[0], argv[0]); + while (fgets(&line[0], 256, fd)) { + sp = &line[0]; + for (;;) { + cp = strtok(sp, " \t\n"); + sp = 0; /* so can continue to parse this string */ + if (!cp) { /* no more token found */ + break; + } + if (*cp == '#') { /* Comment; go to next line. */ + break; + } + my_argv[my_argc] = DT_Mdep_Malloc(MAX_ARG_LEN); + if (!my_argv[my_argc]) { + DT_Mdep_printf("No Memory\n"); + goto error_return; + } + strcpy(my_argv[my_argc], cp); + my_argc++; + } + } + } else { + my_argc = argc; + for (i = 0; i < argc; i++) { + my_argv[i] = argv[i]; + } + } + +#if 0 + for (i = 0; i < my_argc; i++) { + DT_Mdep_printf("ARG %s\n", my_argv[i]); + } + exit(1); +#endif + + /* get test type - which must be the first arg */ + c = DT_mygetopt_r(my_argc, my_argv, "T:", &opts); + if (c != 'T') { + DT_Mdep_printf("Must Specify Test (-T) option first\n"); + goto main_usage; + } + if ((opts.optarg == 0) || strlen(opts.optarg) == 0 + || *opts.optarg == '-') { + DT_Mdep_printf("Must specify test type\n"); + goto main_usage; + } + switch (*opts.optarg) { + case 'S': /* Server Test */ + { + params_ptr->test_type = SERVER_TEST; + Server_Cmd = ¶ms_ptr->u.Server_Cmd; + DT_Server_Cmd_Init(Server_Cmd); + if (!DT_Server_Cmd_Parse(Server_Cmd, + my_argc, my_argv, &opts)) { + goto error_return; + } + params_ptr->ReliabilityLevel = + Server_Cmd->ReliabilityLevel; + params_ptr->debug = Server_Cmd->debug; + break; + } + case 'T': /* Transaction Test */ + { + params_ptr->test_type = TRANSACTION_TEST; + Transaction_Cmd = ¶ms_ptr->u.Transaction_Cmd; + DT_Transaction_Cmd_Init(Transaction_Cmd); + if (!DT_Transaction_Cmd_Parse(Transaction_Cmd, + my_argc, my_argv, &opts)) + { + goto error_return; + } + params_ptr->ReliabilityLevel = + Transaction_Cmd->ReliabilityLevel; + params_ptr->debug = Transaction_Cmd->debug; + DT_NetAddrLookupHostAddress(¶ms_ptr->server_netaddr, + Transaction_Cmd-> + server_name); + break; + } + case 'Q': /* Quit server Test */ + { + params_ptr->test_type = QUIT_TEST; + Quit_Cmd = ¶ms_ptr->u.Quit_Cmd; + DT_Quit_Cmd_Init(Quit_Cmd); + if (!DT_Quit_Cmd_Parse(Quit_Cmd, + my_argc, my_argv, &opts)) { + goto error_return; + } + params_ptr->ReliabilityLevel = + Quit_Cmd->ReliabilityLevel; + params_ptr->debug = Quit_Cmd->debug; + DT_NetAddrLookupHostAddress(¶ms_ptr->server_netaddr, + Quit_Cmd->server_name); + break; + } + case 'L': /* Limit Test */ + { + params_ptr->test_type = LIMIT_TEST; + Limit_Cmd = ¶ms_ptr->u.Limit_Cmd; + DT_Limit_Cmd_Init(Limit_Cmd); + if (!DT_Limit_Cmd_Parse + (Limit_Cmd, my_argc, my_argv, &opts)) { + goto error_return; + } + params_ptr->ReliabilityLevel = + Limit_Cmd->ReliabilityLevel; + params_ptr->debug = Limit_Cmd->debug; + break; + } + case 'P': /* Performance Test */ + { + params_ptr->test_type = PERFORMANCE_TEST; + Performance_Cmd = ¶ms_ptr->u.Performance_Cmd; + + if (!DT_Performance_Cmd_Init(Performance_Cmd)) { + goto error_return; + } + + if (!DT_Performance_Cmd_Parse(Performance_Cmd, + my_argc, my_argv, &opts)) + { + goto error_return; + } + + params_ptr->ReliabilityLevel = Performance_Cmd->qos; + params_ptr->debug = Performance_Cmd->debug; + DT_NetAddrLookupHostAddress(¶ms_ptr->server_netaddr, + Performance_Cmd-> + server_name); + break; + } + case 'F': + { + params_ptr->test_type = FFT_TEST; + FFT_Cmd = ¶ms_ptr->u.FFT_Cmd; + DT_FFT_Cmd_Init(FFT_Cmd); + if (!DT_FFT_Cmd_Parse(FFT_Cmd, my_argc, my_argv, &opts)) { + goto error_return; + } + params_ptr->ReliabilityLevel = + FFT_Cmd->ReliabilityLevel; + DT_NetAddrLookupHostAddress(¶ms_ptr->server_netaddr, + FFT_Cmd->server_name); + params_ptr->debug = false; + break; + } + + default: + { + DT_Mdep_printf("Invalid Test Type\n"); + goto main_usage; + } + } + + if (fd) { + for (i = 0; i < my_argc; i++) { + DT_Mdep_Free(my_argv[i]); + } + fclose(fd); + } + return true; + + main_usage: + Dapltest_Main_Usage(); + error_return: + if (fd) { + for (i = 0; i < my_argc; i++) { + DT_Mdep_Free(my_argv[i]); + } + fclose(fd); + } + return false; +} diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/cmd/dapl_performance_cmd.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/cmd/dapl_performance_cmd.c new file mode 100644 index 00000000..5f9b9f1e --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/cmd/dapl_performance_cmd.c @@ -0,0 +1,297 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" + +static void DT_Performance_Cmd_Usage(void) +{ + DT_Mdep_printf("USAGE: ---- PERFORMANCE TEST ----\n"); + DT_Mdep_printf("USAGE: dapltest -T P\n"); + DT_Mdep_printf("USAGE: -s \n"); + DT_Mdep_printf("USAGE: [-m b|p]\n"); + DT_Mdep_printf("USAGE: [-D ]\n"); + DT_Mdep_printf("USAGE: [-d] : debug (zero)\n"); + DT_Mdep_printf + ("USAGE: [-i ] : (1, 000)\n"); + DT_Mdep_printf("USAGE: [-p ]\n"); + DT_Mdep_printf("USAGE: [-R ]\n"); + DT_Mdep_printf + ("USAGE: (BE == QOS_BEST_EFFORT - Default)\n"); + DT_Mdep_printf("USAGE: (HT == QOS_HIGH_THROUGHPUT)\n"); + DT_Mdep_printf("USAGE: (LL == QOS_LOW_LATENCY)\n"); + DT_Mdep_printf("USAGE: (EC == QOS_ECONOMY)\n"); + DT_Mdep_printf("USAGE: (PM == QOS_PREMIUM)\n"); + DT_Mdep_printf("USAGE: \n"); + DT_Mdep_printf("USAGE:\n"); + DT_Mdep_printf("USAGE: Each OP consists of:\n"); + DT_Mdep_printf("USAGE: : \"RR\" (RDMA READ)\n"); + DT_Mdep_printf("USAGE: : \"RW\" (RDMA WRITE)\n"); + DT_Mdep_printf("USAGE: [seg_size [num_segs] ] : (4096, 1)\n"); +} + +static bool +DT_Performance_Cmd_Parse_Op(Performance_Cmd_t * cmd, + int index, int my_argc, char **my_argv) +{ + int i; + + /* + * Op Format: [seg_size] [num_segs] + */ + + if (index == my_argc) { + DT_Mdep_printf("Operation Missing Transfer Type\n"); + return (false); + } + + for (i = 0; index < my_argc; i++, index++) { + switch (i) { + case 0: + { + if (0 == + strncmp(my_argv[index], "RR", + strlen("RR"))) { + cmd->op.transfer_type = RDMA_READ; + } else if (0 == + strncmp(my_argv[index], "RW", + strlen("RW"))) { + cmd->op.transfer_type = RDMA_WRITE; + } else { + DT_Mdep_printf + ("OP type must be \n"); + return (false); + } + break; + } + case 1: + { + cmd->op.seg_size = atoi(my_argv[index]); + break; + } + case 2: + { + cmd->op.num_segs = atoi(my_argv[index]); + break; + } + default: + { + DT_Mdep_printf("Too many OP args\n"); + return (false); + } + } + } + + return (true); +} + +static bool DT_Performance_Cmd_Validate(Performance_Cmd_t * cmd) +{ + if ('\0' == cmd->server_name[0]) { + DT_Mdep_printf + ("Must specify server_name in command line or scriptfile\n"); + return (false); + } + + if ('\0' == cmd->dapl_name[0]) { + DT_Mdep_printf + ("Must specify device_name in command line or scriptfile\n"); + return (false); + } + + if (0 == cmd->pipeline_len) { + DT_Mdep_printf("Pipeline size must not be 0\n"); + return (false); + } + + if (cmd->debug) { + DT_Performance_Cmd_Print(cmd); + } + + return true; +} + +bool +DT_Performance_Cmd_Parse(Performance_Cmd_t * cmd, + int my_argc, char **my_argv, mygetopt_t * opts) +{ + int c; + unsigned int len; + + for (;;) { + c = DT_mygetopt_r(my_argc, my_argv, "D:dm:i:p:R:s:", opts); + + if (EOF == c) { + break; + } + + switch (c) { + case 'D': /* device name */ + { + strncpy(cmd->dapl_name, opts->optarg, NAME_SZ); + break; + } + case 'd': /* print debug messages */ + { + DT_dapltest_debug++; + cmd->debug = true; + break; + } + case 'm': /* mode */ + { + if (!strncmp(opts->optarg, "b", strlen("b"))) { + cmd->mode = BLOCKING_MODE; + } else + if (!strncmp + (opts->optarg, "p", strlen("p"))) { + cmd->mode = POLLING_MODE; + } else { + DT_Mdep_printf + ("Syntax Error -m option\n"); + DT_Performance_Cmd_Usage(); + return (false); + } + + break; + } + case 'i': /* num iterations */ + { + len = strspn(opts->optarg, "0123456789"); + if (len == 0 || len != strlen(opts->optarg)) { + DT_Mdep_printf + ("Syntax Error -i option\n"); + DT_Performance_Cmd_Usage(); + return (false); + } + cmd->num_iterations = atol(opts->optarg); + break; + } + case 'p': /* pipline size */ + { + len = strspn(opts->optarg, "0123456789"); + if (len == 0 || len != strlen(opts->optarg)) { + DT_Mdep_printf + ("Syntax Error -p option\n"); + DT_Performance_Cmd_Usage(); + return (false); + } + cmd->pipeline_len = atol(opts->optarg); + break; + } + case 'R': /* Service Reliability Level */ + { + cmd->qos = DT_ParseQoS(opts->optarg); + break; + } + case 's': /* server name */ + { + if ((opts->optarg == 0) || + strlen(opts->optarg) == 0 || + *opts->optarg == '-') { + DT_Mdep_printf + ("must specify server name\n"); + DT_Performance_Cmd_Usage(); + return (false); + } + + strncpy(cmd->server_name, opts->optarg, + NAME_SZ); + break; + } + default: + { + DT_Mdep_printf + ("Invalid Performance Test Parameter: %c\n", + c); + DT_Performance_Cmd_Usage(); + return (false); + } + } + } + + /* + * now parse the op + */ + if (!DT_Performance_Cmd_Parse_Op(cmd, opts->optind, my_argc, my_argv)) { + DT_Performance_Cmd_Usage(); + return (false); + } + + if (!DT_Performance_Cmd_Validate(cmd)) { + DT_Performance_Cmd_Usage(); + return (false); + } + + return (true); +} + +bool DT_Performance_Cmd_Init(Performance_Cmd_t * cmd) +{ + memset(cmd, 0, sizeof(Performance_Cmd_t)); + cmd->dapltest_version = DAPLTEST_VERSION; + cmd->client_is_little_endian = DT_local_is_little_endian; + cmd->qos = DAT_QOS_BEST_EFFORT; + cmd->debug = false; + cmd->num_iterations = 1000; + cmd->pipeline_len = ~0; + + cmd->op.transfer_type = RDMA_WRITE; + cmd->op.seg_size = 4096; + cmd->op.num_segs = 1; + + if (!DT_Mdep_GetDefaultDeviceName(cmd->dapl_name)) { + DT_Mdep_printf("can't get default device name\n"); + return (false); + } + + return (true); +} + +void DT_Performance_Cmd_Print(Performance_Cmd_t * cmd) +{ + DT_Mdep_printf("-------------------------------------\n"); + DT_Mdep_printf("PerfCmd.server_name : %s\n", + cmd->server_name); + DT_Mdep_printf("PerfCmd.dapl_name : %s\n", + cmd->dapl_name); + DT_Mdep_printf("PerfCmd.mode : %s\n", + (cmd->mode == BLOCKING_MODE) ? "BLOCKING" : "POLLING"); + DT_Mdep_printf("PerfCmd.num_iterations : %d\n", + cmd->num_iterations); + DT_Mdep_printf("PerfCmd.pipeline_len : %d\n", + cmd->pipeline_len); + DT_Mdep_printf("PerfCmd.op.transfer_type : %s\n", + cmd->op.transfer_type == RDMA_READ ? "RDMA_READ" : + cmd->op.transfer_type == RDMA_WRITE ? "RDMA_WRITE" : + "SEND_RECV"); + DT_Mdep_printf("PerfCmd.op.num_segs : %d\n", + cmd->op.num_segs); + DT_Mdep_printf("PerfCmd.op.seg_size : %d\n", + cmd->op.seg_size); +} diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/cmd/dapl_qos_util.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/cmd/dapl_qos_util.c new file mode 100644 index 00000000..42995dc5 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/cmd/dapl_qos_util.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" + +/* + * Parse a QOS argument into a DAT_QOS. + * + * Returns no errors: defaults to best effort. + */ +DAT_QOS DT_ParseQoS(char *arg) +{ + if (0 == strcmp(arg, "HT")) { + return (DAT_QOS_HIGH_THROUGHPUT); + } + + if (0 == strcmp(arg, "LL")) { + return (DAT_QOS_LOW_LATENCY); + } + + if (0 == strcmp(arg, "EC")) { + return (DAT_QOS_ECONOMY); + } + + if (0 == strcmp(arg, "PM")) { + return (DAT_QOS_PREMIUM); + } + /* + * Default to "BE" so no point in checking further + */ + return (DAT_QOS_BEST_EFFORT); +} diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/cmd/dapl_quit_cmd.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/cmd/dapl_quit_cmd.c new file mode 100644 index 00000000..d8536a7f --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/cmd/dapl_quit_cmd.c @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" + +/*--------------------------------------------------------- */ +void DT_Quit_Cmd_Init(Quit_Cmd_t * cmd) +{ + memset((void *)cmd, 0, sizeof(Quit_Cmd_t)); + cmd->ReliabilityLevel = DAT_QOS_BEST_EFFORT; +} + +/*--------------------------------------------------------- */ +bool +DT_Quit_Cmd_Parse(Quit_Cmd_t * cmd, + int my_argc, char **my_argv, mygetopt_t * opts) +{ + int c; + + for (;;) { + c = DT_mygetopt_r(my_argc, my_argv, "ds:D:R:", opts); + if (c == EOF) { + break; + } + switch (c) { + case 'D': + { + strcpy(cmd->device_name, opts->optarg); + break; + } + case 's': + { + strcpy(cmd->server_name, opts->optarg); + break; + } + case 'd': /* print debug messages */ + { + DT_dapltest_debug++; + cmd->debug = true; + break; + } + case 'R': /* Service Reliability Level */ + { + cmd->ReliabilityLevel = + DT_ParseQoS(opts->optarg); + break; + } + case '?': + default: + { + DT_Mdep_printf("Invalid Quit option: %c\n", + opts->optopt); + DT_Quit_Cmd_Usage(); + return (false); + } + } + } + if (cmd->device_name[0] == '\0') { + if (!DT_Mdep_GetDefaultDeviceName(cmd->device_name)) { + DT_Mdep_printf("can't get default device name\n"); + DT_Quit_Cmd_Usage(); + return (false); + } + } + if (!DT_Quit_Cmd_Validate(cmd)) { + DT_Quit_Cmd_Usage(); + return (false); + } + return (true); +} + +/*------------------------------------------------------------------------------ */ +bool DT_Quit_Cmd_Validate(Quit_Cmd_t * cmd) +{ + if (cmd->server_name[0] == '\0') { + DT_Mdep_printf + ("Must specify server_name in command line or scriptfile\n"); + return (false); + } + return (true); +} + +/*--------------------------------------------------------- */ +void DT_Quit_Cmd_Usage(void) +{ + DT_Mdep_printf("USAGE: ---- QUIT TEST ----\n"); + DT_Mdep_printf("USAGE: dapltest -T Q\n"); + DT_Mdep_printf("USAGE: -s \n"); + DT_Mdep_printf("USAGE: [-D ]\n"); + DT_Mdep_printf("USAGE: [-d] : debug (zero)\n"); + DT_Mdep_printf("USAGE: [-R ]\n"); + DT_Mdep_printf + ("USAGE: (BE == QOS_BEST_EFFORT - Default)\n"); + DT_Mdep_printf("USAGE: (HT == QOS_HIGH_THROUGHPUT)\n"); + DT_Mdep_printf("USAGE: (LL == QOS_LOW_LATENCY)\n"); + DT_Mdep_printf("USAGE: (EC == QOS_ECONOMY)\n"); + DT_Mdep_printf("USAGE: (PM == QOS_PREMIUM)\n"); +} + +/*--------------------------------------------------------- */ +void DT_Quit_Cmd_Print(Quit_Cmd_t * cmd) +{ + DT_Mdep_printf("Quit_Cmd.server_name: %s\n", cmd->server_name); + DT_Mdep_printf("Quit_Cmd.device_name: %s\n", cmd->device_name); +} diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/cmd/dapl_server_cmd.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/cmd/dapl_server_cmd.c new file mode 100644 index 00000000..5859471d --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/cmd/dapl_server_cmd.c @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" + +void DT_Server_Cmd_Init(Server_Cmd_t * Server_Cmd) +{ + DT_dapltest_debug = 0; + Server_Cmd->debug = false; + Server_Cmd->dapl_name[0] = '\0'; + Server_Cmd->ReliabilityLevel = DAT_QOS_BEST_EFFORT; +} + +bool +DT_Server_Cmd_Parse(Server_Cmd_t * Server_Cmd, + int my_argc, char **my_argv, mygetopt_t * opts) +{ + int c; + for (;;) { + c = DT_mygetopt_r(my_argc, my_argv, "dD:R:", opts); + if (c == EOF) { + break; + } + switch (c) { + case 'D': + { + strcpy(Server_Cmd->dapl_name, opts->optarg); + break; + } + case 'd': + { + DT_dapltest_debug++; + Server_Cmd->debug = true; + break; + } + case 'R': /* Service Reliability Level */ + { + Server_Cmd->ReliabilityLevel = + DT_ParseQoS(opts->optarg); + if (0 == Server_Cmd->ReliabilityLevel) { + return (false); + } + break; + } + case '?': + default: + { + DT_Mdep_printf("Invalid Server option: %c\n", + opts->optopt); + DT_Server_Cmd_Usage(); + return (false); + } + } + } + if (Server_Cmd->dapl_name == '\0') { + if (!DT_Mdep_GetDefaultDeviceName(Server_Cmd->dapl_name)) { + DT_Mdep_printf("can't get default device name\n"); + DT_Server_Cmd_Usage(); + return (false); + } + } + return (true); +} + +void DT_Server_Cmd_Usage(void) +{ + DT_Mdep_printf("USAGE: ---- SERVER MODE ----\n"); + DT_Mdep_printf("USAGE: dapltest -T S\n"); + DT_Mdep_printf("USAGE: [-D ]\n"); + DT_Mdep_printf("USAGE: [-d] : debug (zero)\n"); + DT_Mdep_printf("USAGE: [-R ]\n"); + DT_Mdep_printf + ("USAGE: (BE == QOS_BEST_EFFORT - Default)\n"); + DT_Mdep_printf("USAGE: (HT == QOS_HIGH_THROUGHPUT)\n"); + DT_Mdep_printf("USAGE: (LL == QOS_LOW_LATENCY)\n"); + DT_Mdep_printf("USAGE: (EC == QOS_ECONOMY)\n"); + DT_Mdep_printf("USAGE: (PM == QOS_PREMIUM)\n"); + DT_Mdep_printf("USAGE: Run as server using default parameters\n"); + DT_Mdep_printf("USAGE: dapltest\n"); + DT_Mdep_printf("USAGE:\n"); +} + +void DT_Server_Cmd_Print(Server_Cmd_t * Server_Cmd) +{ + DT_Mdep_printf("Server_Cmd.debug: %d\n", Server_Cmd->debug); + DT_Mdep_printf("Server_Cmd.dapl_name: %s\n", Server_Cmd->dapl_name); +} diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/cmd/dapl_test_data.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/cmd/dapl_test_data.c new file mode 100644 index 00000000..5f13cc37 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/cmd/dapl_test_data.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" + +DAT_COUNT DT_dapltest_debug = 0; +/* + * check memory leaking int alloc_count; DT_Mdep_LockType + * Alloc_Count_Lock; + */ + +Per_Test_Data_t *DT_Alloc_Per_Test_Data(void) +{ + Per_Test_Data_t *pt_ptr; + pt_ptr = 0; + + pt_ptr = DT_Mdep_Malloc(sizeof(Per_Test_Data_t)); + if (!pt_ptr) { + DT_Mdep_printf("No Memory to create per_test_data!\n"); + } + + return (pt_ptr); +} + +void DT_Free_Per_Test_Data(Per_Test_Data_t * pt_ptr) +{ + DT_Mdep_Free(pt_ptr); +} diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/cmd/dapl_transaction_cmd.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/cmd/dapl_transaction_cmd.c new file mode 100644 index 00000000..5bdcab8c --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/cmd/dapl_transaction_cmd.c @@ -0,0 +1,453 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" + +static bool DT_Transaction_Cmd_Parse_Op(Transaction_Cmd_t * cmd, char *arg) +{ + char *c_ptr; + int op; + if (cmd->num_ops >= MAX_OPS) { + DT_Mdep_printf("Client: Too Many Ops - Max %d\n", MAX_OPS); + goto error_return; + } + op = cmd->num_ops; + cmd->num_ops++; + + /* set some defaults */ + cmd->op[op].seg_size = 4096; + cmd->op[op].num_segs = 1; + cmd->op[op].reap_send_on_recv = false; + + /* + * packet format: [seg_size] [num_segs] + */ + c_ptr = strtok(arg, " \t"); + if (!c_ptr) { + DT_Mdep_printf("OP first arg must \n"); + goto error_return; + } + /* first token is : */ + if (strcmp(c_ptr, "server") == 0) { + cmd->op[op].server_initiated = true; + } else { + if (strcmp(c_ptr, "client") == 0) { + cmd->op[op].server_initiated = false; + } else { + DT_Mdep_printf("OP first arg must \n"); + goto error_return; + } + } + + c_ptr = strtok(0, " \t"); + if (!c_ptr) { + DT_Mdep_printf("OP Second arg must be \n"); + goto error_return; + } + /* second token is : */ + if (strcmp(c_ptr, "RR") == 0) { + cmd->op[op].transfer_type = RDMA_READ; + } else { + if (strcmp(c_ptr, "RW") == 0) { + cmd->op[op].transfer_type = RDMA_WRITE; + } else { + if (strcmp(c_ptr, "SR") == 0) { + cmd->op[op].transfer_type = SEND_RECV; + } else { + DT_Mdep_printf + ("OP Second arg must be \n"); + goto error_return; + } + } + } + /* + * there may or may not be additional parameters... [seg_size] [num_segs] + * [-f] + */ + c_ptr = strtok(0, " \t"); + if (c_ptr && strspn(c_ptr, "0123456789") != 0) { + cmd->op[op].seg_size = atoi(c_ptr); + c_ptr = strtok(0, " \t"); + } + if (c_ptr && strspn(c_ptr, "0123456789") != 0) { + cmd->op[op].num_segs = atoi(c_ptr); + c_ptr = strtok(0, " \t"); + } + if (c_ptr && strcmp(c_ptr, "-f") == 0) { + cmd->op[op].reap_send_on_recv = true; + if (cmd->op[op].transfer_type != SEND_RECV) { + DT_Mdep_printf("OP: -f only valid on SEND_RECV\n"); + goto error_return; + } + c_ptr = strtok(0, " \t"); + } + if (c_ptr) { + DT_Mdep_printf("OP too many args \n"); + goto error_return; + } + return true; + + error_return: + return false; +} + +static bool DT_Transaction_Cmd_Validate(Transaction_Cmd_t * cmd) +{ + unsigned int i; + bool has_server_send; + bool has_client_send; + unsigned int reap_count; + has_server_send = false; + has_client_send = false; + reap_count = 0; + + if (cmd->server_name[0] == '\0') { + DT_Mdep_printf + ("Must specify server_name in command line or scriptfile\n"); + return (false); + } + for (i = 0; i < cmd->num_ops; i++) { + switch (cmd->op[i].transfer_type) { + case SEND_RECV: + { + if (cmd->op[i].server_initiated) { + has_server_send = true; + } else { + has_client_send = true; + } + if (cmd->op[i].reap_send_on_recv) { + if (!cmd->op[i].server_initiated) { + /* client */ + reap_count++; + } else { + /* server */ + if (reap_count > 0) { + reap_count--; + } else { + DT_Mdep_printf + ("OP: Unbalanced -f options\n"); + return false; + } + } + } + break; + } + case RDMA_READ: + { + break; + } + case RDMA_WRITE: + { + break; + } + } + } + + if (!has_server_send || !has_client_send) { + DT_Mdep_printf("Error: Transaction test requires \n"); + DT_Mdep_printf + ("Error: At least one server SR and one client SR Operation\n"); + return false; + } + if (reap_count != 0) { + DT_Mdep_printf("OP: Unbalanced -f options\n"); + return false; + } + if (cmd->debug) { + DT_Transaction_Cmd_Print(cmd); + } + return true; +} + +static void DT_Transaction_Cmd_Usage(void) +{ + DT_Mdep_printf("USAGE: ---- TRANSACTION TEST ----\n"); + DT_Mdep_printf("USAGE: dapltest -T T\n"); + DT_Mdep_printf("USAGE: -s \n"); + DT_Mdep_printf("USAGE: [-D ]\n"); + DT_Mdep_printf("USAGE: [-d] : debug (zero)\n"); + DT_Mdep_printf + ("USAGE: [-i ] : (1, 000)\n"); + DT_Mdep_printf("USAGE: [-t ] : (1)\n"); + DT_Mdep_printf("USAGE: [-w ] : (1)\n"); + DT_Mdep_printf("USAGE: [-V ] : Validate data: (false)\n"); + DT_Mdep_printf + ("USAGE: [-P ] : DTO Completion Polling: (false)\n"); + DT_Mdep_printf("USAGE: [-r ] : Use RSPs: (false)\n"); + DT_Mdep_printf("USAGE: [-R ]\n"); + DT_Mdep_printf + ("USAGE: (BE == QOS_BEST_EFFORT - Default)\n"); + DT_Mdep_printf("USAGE: (HT == QOS_HIGH_THROUGHPUT)\n"); + DT_Mdep_printf("USAGE: (LL == QOS_LOW_LATENCY)\n"); + DT_Mdep_printf("USAGE: (EC == QOS_ECONOMY)\n"); + DT_Mdep_printf("USAGE: (PM == QOS_PREMIUM)\n"); + DT_Mdep_printf("USAGE: : \"server\"/\"client\"\n"); + DT_Mdep_printf("USAGE: : \"SR\" (SEND/RECV)\n"); + DT_Mdep_printf("USAGE: : \"RR\" (RDMA READ)\n"); + DT_Mdep_printf("USAGE: : \"RW\" (RDMA WRITE)\n"); + DT_Mdep_printf("USAGE: [seg_size [num_segs] ] : (4096, 1)\n"); + DT_Mdep_printf + ("USAGE: [-f] : Reap sends on recv\n"); + DT_Mdep_printf("USAGE:\n"); + DT_Mdep_printf("NOTE: -f is only allowed on \"SR\" OPs\n"); + DT_Mdep_printf + ("NOTE: -f must appear in pairs (one client, one server)\n"); + DT_Mdep_printf + ("NOTE: At least one server SR and one client SR OP are required\n"); + DT_Mdep_printf + ("NOTE: and use of -V results in the use of three extra OPs\n"); +} + +void DT_Transaction_Cmd_Init(Transaction_Cmd_t * cmd) +{ + memset((void *)cmd, 0, sizeof(Transaction_Cmd_t)); + cmd->dapltest_version = DAPLTEST_VERSION; + cmd->client_is_little_endian = DT_local_is_little_endian; + cmd->num_iterations = 1000; + cmd->num_threads = 1; + cmd->eps_per_thread = 1; + cmd->debug = false; + cmd->validate = false; + cmd->ReliabilityLevel = DAT_QOS_BEST_EFFORT; +} + +bool +DT_Transaction_Cmd_Parse(Transaction_Cmd_t * cmd, + int my_argc, char **my_argv, mygetopt_t * opts) +{ + int c; + unsigned int len; + int i; + char op[100]; + for (;;) { + c = DT_mygetopt_r(my_argc, my_argv, "rQVPdw:s:D:i:t:v:R:", + opts); + if (c == EOF) { + break; + } + switch (c) { + case 's': /* server name */ + { + if ((opts->optarg == 0) + || strlen(opts->optarg) == 0 + || *opts->optarg == '-') { + DT_Mdep_printf + ("must specify server name\n"); + DT_Transaction_Cmd_Usage(); + return (false); + } + strcpy(cmd->server_name, opts->optarg); + break; + } + case 'D': /* device name */ + { + strcpy(cmd->dapl_name, opts->optarg); + break; + } + + case 'i': /* num iterations */ + { + len = strspn(opts->optarg, "0123456789"); + if (len == 0 || len != strlen(opts->optarg)) { + DT_Mdep_printf + ("Syntax Error -i option\n"); + DT_Transaction_Cmd_Usage(); + return (false); + } + cmd->num_iterations = atol(opts->optarg); + + break; + } + case 't': /* num threads */ + { + len = strspn(opts->optarg, "0123456789"); + if (len == 0 || len != strlen(opts->optarg)) { + DT_Mdep_printf + ("Syntax Error -t option\n"); + DT_Transaction_Cmd_Usage(); + return (false); + } + cmd->num_threads = atol(opts->optarg); + break; + } + case 'w': /* num EPs per thread */ + { + len = strspn(opts->optarg, "0123456789"); + if (len == 0 || len != strlen(opts->optarg)) { + DT_Mdep_printf + ("Syntax Error -w option\n"); + DT_Transaction_Cmd_Usage(); + return (false); + } + cmd->eps_per_thread = atol(opts->optarg); + break; + } + case 'd': /* print debug messages */ + { + DT_dapltest_debug++; + cmd->debug = true; + break; + } + case 'r': /* use RSP instead of PSP */ + { + cmd->use_rsp = true; + break; + } + case 'V': /* validate data being sent/received */ + { + cmd->validate = true; + break; + } + case 'P': /* use completion polling */ + { + cmd->poll = true; + break; + } + case 'R': /* Service Reliability Level */ + { + cmd->ReliabilityLevel = + DT_ParseQoS(opts->optarg); + break; + } + case '?': + default: + { + DT_Mdep_printf + ("Invalid Transaction Test Parameter: %c\n", + c); + DT_Transaction_Cmd_Usage(); + return (false); + } + } + } + if (cmd->dapl_name[0] == '\0') { + if (!DT_Mdep_GetDefaultDeviceName(cmd->dapl_name)) { + DT_Mdep_printf("can't get default device name\n"); + DT_Transaction_Cmd_Usage(); + return (false); + } + } + /* + * now parse the transaction ops this is ugly, but it's easier to gather + * each transaction into a single string + */ + for (i = opts->optind; i < my_argc; i++) { + strcpy(&op[0], my_argv[i]); + while (i < my_argc - 1) { + i++; + if ((strncmp(my_argv[i], "client", 6) == 0) || + strncmp(my_argv[i], "server", 6) == 0) { + i--; + break; + } + strcat(op, " "); + strcat(op, my_argv[i]); + } + if (!DT_Transaction_Cmd_Parse_Op(cmd, op)) { + DT_Transaction_Cmd_Usage(); + return (false); + } + } + + /* + * If we're going to validate the data, we append 3 OPs that + * serve as barriers so that both the client and server can + * validate their entire set of recv transactions without + * interference. + * + * The first op appended serves to notify the client that the + * server is at the rendezvous and will transfer nothing else, + * so the client can validate all recv buffers. The second op + * notifies the server that the client is quiescent, so the + * server can safely validate its recv buffers. The final op + * tells the client that the server is done, and both can + * proceed with the next iteration. + */ + if (cmd->validate) { + DT_Mdep_printf + ("NOTE: Adding OP \"server SR\" - for validation\n"); + memcpy(op, "server SR", strlen("server SR") + 1); + DT_Transaction_Cmd_Parse_Op(cmd, op); + + DT_Mdep_printf + ("NOTE: Adding OP \"client SR\" - for validation\n"); + memcpy(op, "client SR", strlen("client SR") + 1); + DT_Transaction_Cmd_Parse_Op(cmd, op); + + DT_Mdep_printf + ("NOTE: Adding OP \"server SR\" - for validation\n"); + memcpy(op, "server SR", strlen("server SR") + 1); + DT_Transaction_Cmd_Parse_Op(cmd, op); + } + if (!DT_Transaction_Cmd_Validate(cmd)) { + DT_Transaction_Cmd_Usage(); + return (false); + } + return (true); +} + +void DT_Transaction_Cmd_Print(Transaction_Cmd_t * cmd) +{ + unsigned int i; + DT_Mdep_printf("-------------------------------------\n"); + DT_Mdep_printf("TransCmd.server_name : %s\n", + cmd->server_name); + DT_Mdep_printf("TransCmd.num_iterations : %d\n", + cmd->num_iterations); + DT_Mdep_printf("TransCmd.num_threads : %d\n", + cmd->num_threads); + DT_Mdep_printf("TransCmd.eps_per_thread : %d\n", + cmd->eps_per_thread); + DT_Mdep_printf("TransCmd.validate : %d\n", + cmd->validate); + DT_Mdep_printf("TransCmd.dapl_name : %s\n", + cmd->dapl_name); + DT_Mdep_printf("TransCmd.num_ops : %d\n", + cmd->num_ops); + + for (i = 0; i < cmd->num_ops; i++) { + DT_Mdep_printf("TransCmd.op[%d].transfer_type : %s %s\n", + i, + cmd->op[i].transfer_type == 0 ? "RDMA_READ" : + cmd->op[i].transfer_type == 1 ? "RDMA_WRITE" : + "SEND_RECV", + cmd->op[i]. + server_initiated ? " (server)" : " (client)"); + DT_Mdep_printf("TransCmd.op[%d].seg_size : %d\n", i, + cmd->op[i].seg_size); + DT_Mdep_printf("TransCmd.op[%d].num_segs : %d\n", i, + cmd->op[i].num_segs); + DT_Mdep_printf("TransCmd.op[%d].reap_send_on_recv : %d\n", i, + cmd->op[i].reap_send_on_recv); + } +} diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/common/dapl_endian.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/common/dapl_endian.c new file mode 100644 index 00000000..d93fbb92 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/common/dapl_endian.c @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" + +void DT_Endian_Init(void) +{ + int endian; + endian = 1; + DT_local_is_little_endian = *((unsigned char *)(&endian)) == 1; +} + +/* + * Big/Little Endian conversion functions + */ + +#define c1a32 ((DAT_UINT32)0x00FF00FF) +#define c1b32 ((DAT_UINT32)0xFF00FF00) +#define c2a32 ((DAT_UINT32)0x0000FFFF) +#define c2b32 ((DAT_UINT32)0xFFFF0000) +#define c164 ((DAT_UINT64)0x00FF00FF) +#define c1a64 (c164 | (c164 << 32)) +#define c1b64 (c1a64 << 8) +#define c264 ((DAT_UINT64)0x0000FFFF) +#define c2a64 (c264 | (c264 << 32)) +#define c2b64 (c2a64 << 16) +#define c3a64 ((DAT_UINT64)0xFFFFFFFF) +#define c3b64 (c3a64 << 32) + +DAT_UINT32 DT_Endian32(DAT_UINT32 val) +{ + if (DT_local_is_little_endian) { + return val; + } + val = ((val & c1a32) << 8) | ((val & c1b32) >> 8); + val = ((val & c2a32) << 16) | ((val & c2b32) >> 16); + return (val); +} + +DAT_UINT64 DT_Endian64(DAT_UINT64 val) +{ + if (DT_local_is_little_endian) { + return val; + } + val = ((val & c1a64) << 8) | ((val & c1b64) >> 8); + val = ((val & c2a64) << 16) | ((val & c2b64) >> 16); + val = ((val & c3a64) << 32) | ((val & c3b64) >> 32); + return (val); +} + +DAT_UINT32 DT_EndianMemHandle(DAT_UINT32 val) +{ + if (DT_local_is_little_endian) + return val; + val = ((val & c1a32) << 8) | ((val & c1b32) >> 8); + val = ((val & c2a32) << 16) | ((val & c2b32) >> 16); + return (val); +} + +DAT_UINT64 DT_EndianMemAddress(DAT_UINT64 val) +{ + DAT_UINT64 val64; + + if (DT_local_is_little_endian) + return val; + val64 = val; + val64 = ((val64 & c1a64) << 8) | ((val64 & c1b64) >> 8); + val64 = ((val64 & c2a64) << 16) | ((val64 & c2b64) >> 16); + val64 = ((val64 & c3a64) << 32) | ((val64 & c3b64) >> 32); + return val64; +} diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/common/dapl_global.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/common/dapl_global.c new file mode 100644 index 00000000..ecd61e7e --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/common/dapl_global.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" + +bool DT_local_is_little_endian; +DAT_COUNT DT_dapltest_debug = 0; diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/common/dapl_performance_cmd_util.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/common/dapl_performance_cmd_util.c new file mode 100644 index 00000000..5321809f --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/common/dapl_performance_cmd_util.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" + +void DT_Performance_Cmd_Endian(Performance_Cmd_t * cmd) +{ + cmd->dapltest_version = DT_Endian32(cmd->dapltest_version); + cmd->qos = DT_Endian32(cmd->qos); + cmd->num_iterations = DT_Endian32(cmd->num_iterations); + cmd->debug = DT_Endian32(cmd->debug); + + cmd->op.transfer_type = DT_Endian32(cmd->op.transfer_type); + cmd->op.seg_size = DT_Endian32(cmd->op.seg_size); + cmd->op.num_segs = DT_Endian32(cmd->op.num_segs); +} + +/* + * * Map Performance_Mode_Type values to readable strings + * */ +const char *DT_PerformanceModeToString(Performance_Mode_Type mode) +{ + if (BLOCKING_MODE == mode) { + return "blocking"; + } else if (POLLING_MODE == mode) { + return "polling"; + } else { + return "error: unkown mode"; + } +} diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/common/dapl_quit_cmd_util.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/common/dapl_quit_cmd_util.c new file mode 100644 index 00000000..b629ae02 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/common/dapl_quit_cmd_util.c @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" + +/*--------------------------------------------------------- */ +void DT_Quit_Cmd_Endian(Quit_Cmd_t * cmd, bool to_wire) +{ + /* do nothing */ +} diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/common/dapl_transaction_cmd_util.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/common/dapl_transaction_cmd_util.c new file mode 100644 index 00000000..30301b1c --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/common/dapl_transaction_cmd_util.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" + +void DT_Transaction_Cmd_Endian(Transaction_Cmd_t * cmd, bool to_wire) +{ + unsigned int i; + + cmd->dapltest_version = DT_Endian32(cmd->dapltest_version); + cmd->num_iterations = DT_Endian32(cmd->num_iterations); + cmd->num_threads = DT_Endian32(cmd->num_threads); + cmd->eps_per_thread = DT_Endian32(cmd->eps_per_thread); + cmd->use_rsp = DT_Endian32(cmd->use_rsp); + cmd->debug = DT_Endian32(cmd->debug); + cmd->validate = DT_Endian32(cmd->validate); + cmd->ReliabilityLevel = DT_Endian32(cmd->ReliabilityLevel); + + if (!to_wire) { + cmd->num_ops = DT_Endian32(cmd->num_ops); + } + for (i = 0; i < cmd->num_ops; i++) { + cmd->op[i].server_initiated = + DT_Endian32(cmd->op[i].server_initiated); + cmd->op[i].transfer_type = + DT_Endian32(cmd->op[i].transfer_type); + cmd->op[i].num_segs = DT_Endian32(cmd->op[i].num_segs); + cmd->op[i].seg_size = DT_Endian32(cmd->op[i].seg_size); + cmd->op[i].reap_send_on_recv = + DT_Endian32(cmd->op[i].reap_send_on_recv); + } + if (to_wire) { + cmd->num_ops = DT_Endian32(cmd->num_ops); + } +} diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/configure.in b/branches/WOF2-3/ulp/dapl2/test/dapltest/configure.in new file mode 100644 index 00000000..c6b5a266 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/configure.in @@ -0,0 +1,26 @@ +dnl Process this file with autoconf to produce a configure script. + +AC_PREREQ(2.57) +AC_INIT(dapltest2, 1.2.1, dapl-devel@lists.sourceforge.net) +AC_CONFIG_SRCDIR([$top_srcdir/dapl/test/dapltest/cmd/dapl_main.c]) +AC_CONFIG_AUX_DIR(config) +AM_CONFIG_HEADER(config.h) +AM_INIT_AUTOMAKE(dapltest2, 1.2.1) + +AM_PROG_LIBTOOL + +dnl Checks for programs +AC_PROG_CC + +dnl Checks for libraries +if test "$disable_libcheck" != "yes" +then +AC_CHECK_LIB(pthread, pthread_attr_init, [], + AC_MSG_ERROR([pthread_attr_init() not found, dapltset requires pthreads])) +fi + +dnl Checks for header files. + +AC_CONFIG_FILES([Makefile]) + +AC_OUTPUT diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/dirs b/branches/WOF2-3/ulp/dapl2/test/dapltest/dirs new file mode 100644 index 00000000..f3b2bb0b --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/dirs @@ -0,0 +1 @@ +dirs = windows diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/dt_cmd.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/dt_cmd.c new file mode 100644 index 00000000..ea07f161 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/dt_cmd.c @@ -0,0 +1,12 @@ + +#include "cmd/dapl_main.c" +#include "cmd/dapl_params.c" +#include "cmd/dapl_fft_cmd.c" +#include "cmd/dapl_getopt.c" +#include "cmd/dapl_limit_cmd.c" +#include "cmd/dapl_netaddr.c" +#include "cmd/dapl_performance_cmd.c" +#include "cmd/dapl_qos_util.c" +#include "cmd/dapl_quit_cmd.c" +#include "cmd/dapl_server_cmd.c" +#include "cmd/dapl_transaction_cmd.c" diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/dt_common.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/dt_common.c new file mode 100644 index 00000000..bd939e53 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/dt_common.c @@ -0,0 +1,5 @@ +#include "common/dapl_endian.c" +#include "common/dapl_global.c" +#include "common/dapl_performance_cmd_util.c" +#include "common/dapl_quit_cmd_util.c" +#include "common/dapl_transaction_cmd_util.c" diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/dt_mdep.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/dt_mdep.c new file mode 100644 index 00000000..d4a92336 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/dt_mdep.c @@ -0,0 +1,2 @@ + +#include "mdep/windows/dapl_mdep_user.c" diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/dt_test.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/dt_test.c new file mode 100644 index 00000000..d63dbba7 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/dt_test.c @@ -0,0 +1,32 @@ +#include "test/dapl_bpool.c" +#include "test/dapl_client.c" +#include "test/dapl_client_info.c" +#include "test/dapl_cnxn.c" +#include "test/dapl_execute.c" +#include "test/dapl_fft_connmgt.c" +#include "test/dapl_fft_endpoint.c" +#include "test/dapl_fft_hwconn.c" +#include "test/dapl_fft_mem.c" +#include "test/dapl_fft_pz.c" +#include "test/dapl_fft_queryinfo.c" +#include "test/dapl_fft_test.c" +#include "test/dapl_fft_util.c" +#include "test/dapl_limit.c" +#include "test/dapl_memlist.c" +#include "test/dapl_performance_client.c" +#include "test/dapl_performance_server.c" +#include "test/dapl_performance_stats.c" +#include "test/dapl_performance_util.c" +#include "test/dapl_quit_util.c" +#include "test/dapl_server.c" +#include "test/dapl_server_info.c" +#include "test/dapl_test_data.c" +#include "test/dapl_test_util.c" +#include "test/dapl_thread.c" +#include "test/dapl_transaction_stats.c" +#include "test/dapl_transaction_test.c" +#include "test/dapl_transaction_util.c" +#include "test/dapl_util.c" +#if defined(DAT_EXPORT_SYMBOLS) +#error DAT_EXPORT? +#endif diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/dt_udapl.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/dt_udapl.c new file mode 100644 index 00000000..274be4e0 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/dt_udapl.c @@ -0,0 +1,2 @@ + +#include "udapl/udapl_tdep.c" diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_bpool.h b/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_bpool.h new file mode 100644 index 00000000..33ba4854 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_bpool.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#ifndef __DAPL_BPOOL_H__ +#define __DAPL_BPOOL_H__ + +#include "dapl_proto.h" + +typedef struct Bpool_tag Bpool; +/* + * struct Bpool + */ + +struct Bpool_tag +{ + unsigned char *alloc_ptr; + DAT_UINT32 alloc_size; + DAT_PZ_HANDLE pz_handle; + DAT_COUNT seg_size; + DAT_COUNT num_segs; /* num segments */ + unsigned char *buffer_start; /* Start of buffer area */ + DAT_VLEN buffer_size; /* Size of data buffer (rounded) */ + DAT_VADDR reg_addr; /* start of registered area */ + DAT_VLEN reg_size; /* size of registered area */ + DAT_EP_HANDLE ep_handle; /* EP area is registered to */ + DAT_LMR_HANDLE lmr_handle; /* local access */ + DAT_LMR_CONTEXT lmr_context; + DAT_LMR_TRIPLET*tripl_start; /* local IOV */ + DAT_BOOLEAN enable_rdma_write; /* remote access */ + DAT_BOOLEAN enable_rdma_read; + DAT_RMR_HANDLE rmr_handle; + DAT_RMR_CONTEXT rmr_context; + DAT_EVD_HANDLE rmr_evd_handle; +}; +#endif diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_client_info.h b/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_client_info.h new file mode 100644 index 00000000..6431f8df --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_client_info.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#ifndef __DAPL_CLIENT_INFO_H__ +#define __DAPL_CLIENT_INFO_H__ + +#include "dapl_proto.h" + +#pragma pack (2) + +typedef struct +{ + DAT_UINT32 dapltest_version; + DAT_UINT32 is_little_endian; + DAT_UINT32 test_type; + DAT_UINT32 total_threads; +} Client_Info_t; +#pragma pack () + +#endif diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_common.h b/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_common.h new file mode 100644 index 00000000..df3e0009 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_common.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#ifndef __DAPL_COMMON_H__ +#define __DAPL_COMMON_H__ + +#include "dapl_proto.h" + +typedef enum +{ + RDMA_READ, + RDMA_WRITE, + SEND_RECV +} DT_Transfer_Type; + + +#pragma pack(1) +typedef struct +{ + DAT_RMR_CONTEXT rmr_context; + DAT_CONTEXT mem_address; +} RemoteMemoryInfo; +#pragma pack() + + +#endif /* __DAPL_COMMON_H__ */ diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_execute.h b/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_execute.h new file mode 100644 index 00000000..eb2d54a2 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_execute.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#ifndef _DAPL_EXECUTE_H_ +#define _DAPL_EXECUTE_H_ + +#include "dapl_proto.h" +#include "dapl_params.h" + +DAT_RETURN +DT_Execute_Test ( Params_t *params_ptr ) ; + +#endif diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_fft_cmd.h b/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_fft_cmd.h new file mode 100644 index 00000000..0989a2e7 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_fft_cmd.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#ifndef __DAPL_FFT_CMD_H__ +#define __DAPL_FFT_CMD_H__ + +#include "dapl_proto.h" + +#define MAXCASES 100 + +typedef enum +{ + NONE, + HWCONN, + CQMGT, + ENDPOINT, + PTAGMGT, + MEMMGT, + CONNMGT, + CONNMGT_CLIENT, + DATAXFER, + DATAXFER_CLIENT, + QUERYINFO, + NS, + ERRHAND, + UNSUPP, + STRESS, + STRESS_CLIENT, +} FFT_Type_e; + + +typedef struct +{ + FFT_Type_e fft_type; + char device_name[256]; //-D + char server_name[256]; + bool cases_flag[MAXCASES]; + int size; + int num_iter; //-i + int num_threads; //-t + int num_vis; //-v + DAT_QOS ReliabilityLevel; //-R +} FFT_Cmd_t; + +#endif diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_fft_util.h b/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_fft_util.h new file mode 100644 index 00000000..17675cf4 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_fft_util.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#ifndef DAPL_FFT_UTIL_H +#define DAPL_FFT_UTIL_H + +#include "dapl_proto.h" +#include "dapl_test_data.h" + +#define DT_assert_dat(test_num, x) if(x) ; \ + else { \ + DT_assert_fail(test_num, #x, __FILE__, __BASE_FILE__, __LINE__); \ + DT_Tdep_PT_Printf(test_num,"Error = %d, %s\n", rc, DT_RetToString(rc)); \ + res = 0; \ + goto cleanup; \ + } + +#define DT_assert(test_num, x) if(x) ; \ + else { \ + DT_assert_fail(test_num, #x, __FILE__, __BASE_FILE__, __LINE__); \ + res = 0; \ + goto cleanup; \ + } + +#define DT_assert_clean(test_num, x) if(x) ; \ + else { \ + DT_assert_fail(test_num, #x, __FILE__, __BASE_FILE__, __LINE__); \ + DT_Tdep_PT_Printf(test_num,"Error = %d, %s\n", rc, DT_RetToString(rc)); \ + return 0; \ + } + +typedef struct +{ + DAT_IA_HANDLE ia_handle; + DAT_PZ_HANDLE pz_handle; + DAT_PSP_HANDLE psp_handle; + DAT_EP_HANDLE ep_handle; + DAT_EVD_HANDLE cr_evd, conn_evd, send_evd, recv_evd; + DAT_EVENT event; + DAT_COUNT count; + DAT_CR_HANDLE cr_handle; + Bpool *bpool; + DAT_CR_ARRIVAL_EVENT_DATA cr_stat; + DAT_EVENT_NUMBER event_num; + DAT_IA_ADDRESS_PTR remote_netaddr; + Per_Test_Data_t *pt_ptr; + bool connected; +} FFT_Connection_t; + +typedef enum +{ + QUERY_CNO, + QUERY_CR, + QUERY_EP, + QUERY_EVD, + QUERY_IA, + QUERY_LMR, + QUERY_RMR, + QUERY_PSP, + QUERY_RSP, + QUERY_PZ, +} FFT_query_enum; + +typedef struct +{ + int (*fun) (Params_t *params_ptr, FFT_Cmd_t* cmd); +} FFT_Testfunc_t; + +#endif + diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_getopt.h b/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_getopt.h new file mode 100644 index 00000000..e8874b67 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_getopt.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#ifndef __DAPL_GETOPT_H__ +#define __DAPL_GETOPT_H__ + +typedef struct +{ + int magic; + char *place; + + int opterr; + int optind; + int optopt; + char *optarg; +} mygetopt_t; +/* function prototypes */ +void +DT_mygetopt_init (mygetopt_t * opts); +int +DT_mygetopt_r (int argc, + char *const * argv, + const char *ostr, + mygetopt_t * opts); +#endif diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_global.h b/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_global.h new file mode 100644 index 00000000..562404f0 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_global.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#ifndef __DAPL_GLOBAL_H__ +#define __DAPL_GLOBAL_H__ + +#include "dapl_proto.h" + +extern DAT_COUNT DT_dapltest_debug; +extern bool DT_local_is_little_endian; + +#endif diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_limit_cmd.h b/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_limit_cmd.h new file mode 100644 index 00000000..03bc7739 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_limit_cmd.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#ifndef __DAPL_LIMIT_CMD_H__ +#define __DAPL_LIMIT_CMD_H__ + +#include "dapl_proto.h" + +typedef enum +{ + LIM_IA, + LIM_PZ, +#ifndef __KDAPLTEST__ + LIM_CNO, +#endif + LIM_EVD, + LIM_EP, + LIM_RSP, + LIM_PSP, + LIM_LMR, + LIM_RPOST, + LIM_SIZE_LMR, + /* add further tests here */ + + LIM_NUM_TESTS /* for array size & limit checks */ +} Limit_Index; + +//------------------------------------- +#pragma pack (2) +typedef struct +{ + char device_name[256]; /* -D */ + DAT_QOS ReliabilityLevel; /* -R */ + DAT_UINT32 width; /* -w */ + DAT_UINT32 debug; /* -d */ + DAT_UINT32 maximum; /* -m */ + DAT_UINT32 Test_List[ LIM_NUM_TESTS ]; +} Limit_Cmd_t; + +#pragma pack () + +#endif diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_mdep.h b/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_mdep.h new file mode 100644 index 00000000..72f4aec3 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_mdep.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#ifndef __DAPL_MDEP_H__ +#define __DAPL_MDEP_H__ + +#ifdef __KERNEL__ +#include "dapl_mdep_kernel.h" +#else +#include "dapl_mdep_user.h" +#endif + +#endif diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_memlist.h b/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_memlist.h new file mode 100644 index 00000000..b383610b --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_memlist.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#ifndef __DAPL_MEMLIST_H__ +#define __DAPL_MEMLIST_H__ + +#include "dapl_proto.h" + +typedef enum +{ + BPOOL, + BUFF, + PERTESTDATA, + NIC, + NETADDRESS, + TRANSACTIONTEST, + THREAD, + EPCONTEXT +} mem_type_e; + +struct Mem_list_entry +{ + char filename[50]; + mem_type_e MemType; + void *mem_ptr; + struct Mem_list_entry *next; +}; + +typedef struct Mem_list_entry MemListEntry_t; +#endif diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_params.h b/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_params.h new file mode 100644 index 00000000..dc500b78 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_params.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#ifndef __DAPL_PARAMS_H__ +#define __DAPL_PARAMS_H__ + +#include "dapl_proto.h" +#include "dapl_server_cmd.h" +#include "dapl_transaction_cmd.h" +#include "dapl_performance_cmd.h" +#include "dapl_limit_cmd.h" +#include "dapl_quit_cmd.h" +#include "dapl_fft_cmd.h" + +typedef enum +{ + SERVER_TEST, + TRANSACTION_TEST, + PERFORMANCE_TEST, + LIMIT_TEST, + QUIT_TEST, + FFT_TEST +} test_type_e; + +typedef struct +{ + test_type_e test_type; + + union + { + Server_Cmd_t Server_Cmd; + Transaction_Cmd_t Transaction_Cmd; + Performance_Cmd_t Performance_Cmd; + Limit_Cmd_t Limit_Cmd; + Quit_Cmd_t Quit_Cmd; + FFT_Cmd_t FFT_Cmd; + } u; + + /* Needed here due to structure of command processing */ + DAT_QOS ReliabilityLevel; + DAT_SOCK_ADDR server_netaddr; + void * phead; + bool local_is_little_endian; + bool debug; + double cpu_mhz; +} Params_t; + +#endif diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_performance_cmd.h b/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_performance_cmd.h new file mode 100644 index 00000000..93fb3215 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_performance_cmd.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#ifndef __DAPL_PERFORMANCE_CMD_H__ +#define __DAPL_PERFORMANCE_CMD_H__ + +#include "dapl_proto.h" + +#define NAME_SZ 256 + +typedef enum +{ + BLOCKING_MODE, + POLLING_MODE +} Performance_Mode_Type; + +#pragma pack (2) +typedef struct +{ + DAT_UINT32 transfer_type; + DAT_UINT32 seg_size; + DAT_UINT32 num_segs; +} Performance_Cmd_Op_t; + +typedef struct +{ + DAT_UINT32 dapltest_version; + DAT_UINT32 client_is_little_endian; + char server_name[NAME_SZ]; /* -s */ + char dapl_name[NAME_SZ]; /* -D */ + DAT_QOS qos; + DAT_UINT32 debug; /* -d */ + Performance_Mode_Type mode; /* -m */ + DAT_UINT32 num_iterations; /* -i */ + DAT_UINT32 pipeline_len; /* -p */ + Performance_Cmd_Op_t op; + DAT_UINT32 use_rsp; /* -r */ + +} Performance_Cmd_t; +#pragma pack () + +#endif diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_performance_stats.h b/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_performance_stats.h new file mode 100644 index 00000000..44c117ca --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_performance_stats.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#ifndef __DAPL_STATS_H__ +#define __DAPL_STATS_H__ + +#include "dapl_proto.h" + +#define DT_min(a, b) ((a < b) ? (a) : (b)) +#define DT_max(a, b) ((a > b) ? (a) : (b)) +#define DT_whole(num) ((unsigned int)(num)) +#define DT_hundredths(num) ((unsigned int)(((num) - (unsigned int)(num)) * 100)) + +typedef struct +{ + unsigned int num; + DT_Mdep_TimeStamp total_ts; + DT_Mdep_TimeStamp max_ts; + DT_Mdep_TimeStamp min_ts; +} Performance_Stats_Data_t; + + +typedef struct +{ + unsigned int num_ops; + int64_t bytes; + unsigned int post_ctxt_switch_num; + unsigned int reap_ctxt_switch_num; + double cpu_utilization; + DT_Mdep_TimeStamp time_ts; + Performance_Stats_Data_t posts_sans_ctxt; + Performance_Stats_Data_t posts_with_ctxt; + Performance_Stats_Data_t reaps_sans_ctxt; + Performance_Stats_Data_t reaps_with_ctxt; + Performance_Stats_Data_t latency; +} Performance_Stats_t; + +#endif diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_performance_test.h b/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_performance_test.h new file mode 100644 index 00000000..82040a2f --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_performance_test.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#ifndef __DAPL_PERFORMANCE_TEST_H__ +#define __DAPL_PERFORMANCE_TEST_H__ + +#include "dapl_proto.h" +#include "dapl_tdep.h" +#include "dapl_common.h" +#include "dapl_test_data.h" +#include "dapl_performance_cmd.h" + + +#define DT_PERF_SYNC_SEND_BUFFER_ID 0 +#define DT_PERF_SYNC_RECV_BUFFER_ID 1 +#define DT_PERF_SYNC_BUFF_SIZE sizeof (RemoteMemoryInfo) +#define DT_PERF_DFLT_EVD_LENGTH 8 + + +typedef struct +{ + DT_Transfer_Type transfer_type; + DAT_UINT32 num_segs; + DAT_UINT32 seg_size; + Bpool *bp; + + /* RDMA info */ + DAT_RMR_CONTEXT Rdma_Context; + DAT_VADDR Rdma_Address; +} Performance_Test_Op_t; + +typedef struct +{ + DAT_EP_HANDLE ep_handle; + DAT_EP_ATTR ep_attr; + DAT_CONN_QUAL port; + DAT_COUNT pipeline_len; + Bpool *bp; + Performance_Test_Op_t op; +} Performance_Ep_Context_t; + +typedef struct +{ + Per_Test_Data_t *pt_ptr; + Performance_Cmd_t *cmd; + DAT_IA_ADDRESS_PTR remote_ia_addr; + DAT_BOOLEAN is_remote_little_endian; + DAT_CONN_QUAL base_port; + DAT_IA_ATTR ia_attr; + DAT_IA_HANDLE ia_handle; + DAT_PZ_HANDLE pz_handle; + DAT_CNO_HANDLE cno_handle; + DAT_COUNT reqt_evd_length; + DAT_EVD_HANDLE reqt_evd_hdl; /* request+rmr */ + DAT_COUNT recv_evd_length; + DAT_EVD_HANDLE recv_evd_hdl; /* receive */ + DAT_COUNT conn_evd_length; + DAT_EVD_HANDLE conn_evd_hdl; /* connect */ + DAT_COUNT creq_evd_length; + DAT_EVD_HANDLE creq_evd_hdl; /* "" request */ + Performance_Ep_Context_t ep_context; +} Performance_Test_t; + +#endif diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_proto.h b/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_proto.h new file mode 100644 index 00000000..fb5a293b --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_proto.h @@ -0,0 +1,667 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#ifndef __DAPL_PROTO_H__ +#define __DAPL_PROTO_H__ + +#ifdef __KERNEL__ +#include +#else +#include + +#include +#include +#include +#include +#endif + +#include "dapl_mdep.h" +#include "dapl_tdep_print.h" +#include "dapl_bpool.h" +#include "dapl_client_info.h" +#include "dapl_common.h" +#include "dapl_client_info.h" +#include "dapl_execute.h" +#include "dapl_getopt.h" +#include "dapl_global.h" +#include "dapl_fft_cmd.h" +#include "dapl_fft_util.h" +#include "dapl_limit_cmd.h" +#include "dapl_memlist.h" +#include "dapl_params.h" +#include "dapl_performance_stats.h" +#include "dapl_performance_test.h" +#include "dapl_quit_cmd.h" +#include "dapl_server_info.h" +#include "dapl_tdep.h" +#include "dapl_test_data.h" +#include "dapl_transaction_cmd.h" +#include "dapl_transaction_test.h" +#include "dapl_transaction_stats.h" +#include "dapl_version.h" + +#define DAT_ERROR(Type,SubType) ((DAT_RETURN)(DAT_CLASS_ERROR | Type | SubType)) + +/* + * Prototypes + */ + +/* dapl_bpool.c */ +Bpool * DT_BpoolAlloc (Per_Test_Data_t * pt_ptr, + DT_Tdep_Print_Head* phead, + DAT_IA_HANDLE ia_handle, + DAT_PZ_HANDLE pz_handle, + DAT_EP_HANDLE ep_handle, + DAT_EVD_HANDLE rmr_evd_handle, + DAT_COUNT seg_size, + DAT_COUNT num_segs, + DAT_COUNT alignment, + DAT_BOOLEAN enable_rdma_write, + DAT_BOOLEAN enable_rdma_read); + +bool DT_Bpool_Destroy (Per_Test_Data_t * pt_ptr, + DT_Tdep_Print_Head *phead, + Bpool * bpool_ptr); + +unsigned char *DT_Bpool_GetBuffer (Bpool * bpool_ptr, int index); +DAT_COUNT DT_Bpool_GetBuffSize (Bpool * bpool_ptr, int index); +DAT_LMR_TRIPLET *DT_Bpool_GetIOV (Bpool * bpool_ptr, int index); +DAT_LMR_CONTEXT DT_Bpool_GetLMR (Bpool * bpool_ptr, int index); +DAT_RMR_CONTEXT DT_Bpool_GetRMR (Bpool * bpool_ptr, int index); + +void DT_Bpool_print (DT_Tdep_Print_Head* phead, Bpool *bpool_ptr); + +/* dapl_cnxn.c */ +int get_ep_connection_state (DT_Tdep_Print_Head* phead, + DAT_EP_HANDLE ep_handle); + +/* dapl_client.c */ +DAT_RETURN DT_cs_Client (Params_t * params_ptr, + char *dapl_name, + char *server_name, + DAT_UINT32 total_threads); + +/* dapl_client_info.c */ +void DT_Client_Info_Endian (Client_Info_t * client_info); + +void DT_Client_Info_Print (DT_Tdep_Print_Head *phead, + Client_Info_t * client_info); + +/* dapl_transaction_stats.c */ +void DT_init_transaction_stats (Transaction_Stats_t * transaction_stats, + unsigned int nums); +void DT_transaction_stats_set_ready (DT_Tdep_Print_Head* phead, + Transaction_Stats_t* transaction_stats); + +void DT_transaction_stats2_set_ready (DT_Tdep_Print_Head* phead, + Transaction_Stats_t* transaction_stats); + +bool DT_transaction_stats_wait_for_all (DT_Tdep_Print_Head* phead, + Transaction_Stats_t* transaction_stats); + +bool DT_transaction_stats2_wait_for_all (DT_Tdep_Print_Head* phead, + Transaction_Stats_t* transaction_stats); + +void DT_update_transaction_stats (Transaction_Stats_t * transaction_stats, + unsigned int num_ops, + unsigned int time_ms, + unsigned int bytes_send, + unsigned int bytes_recv, + unsigned int bytes_rdma_read, + unsigned int bytes_rdma_write); + +void DT_print_transaction_stats (DT_Tdep_Print_Head* phead, + Transaction_Stats_t* transaction_stats, + unsigned int num_threads, + unsigned int num_EPs); + +/* dapl_endian.c */ +void DT_Endian_Init (void); +DAT_UINT32 DT_Endian32 (DAT_UINT32 val); +DAT_UINT64 DT_Endian64 (DAT_UINT64 val); +DAT_UINT32 DT_EndianMemHandle (DAT_UINT32 val); +DAT_UINT64 DT_EndianMemAddress (DAT_UINT64 val); + +/* dapl_getopt.c */ +void DT_mygetopt_init (mygetopt_t * opts); + +int DT_mygetopt_r (int argc, + char *const * argv, + const char *ostr, + mygetopt_t * opts); + +/* dapl_main.c */ +int main (int argc, char *argv[]); + +int dapltest (int argc, char *argv[]); + +void Dapltest_Main_Usage (void); + +/* dapl_mdep.c */ +void DT_Mdep_Init (void); +void DT_Mdep_End (void); +bool DT_Mdep_GetDefaultDeviceName (char *dapl_name); +void DT_Mdep_Sleep (int msec); +void DT_Mdep_Schedule (void); +bool DT_Mdep_GetCpuStat (DT_CpuStat *sys_stat); +unsigned long DT_Mdep_GetTime (void); +double DT_Mdep_GetCpuMhz (void); +unsigned long DT_Mdep_GetContextSwitchNum (void); +void *DT_Mdep_Malloc (size_t l_); +void DT_Mdep_Free (void *a_); +bool DT_Mdep_LockInit (DT_Mdep_LockType * lock_ptr); +void DT_Mdep_LockDestroy (DT_Mdep_LockType * lock_ptr); +void DT_Mdep_Lock (DT_Mdep_LockType * lock_ptr); +void DT_Mdep_Unlock (DT_Mdep_LockType * lock_ptr); +void DT_Mdep_Thread_Init_Attributes (Thread * thread_ptr); +void DT_Mdep_Thread_Destroy_Attributes (Thread * thread_ptr); +bool DT_Mdep_Thread_Start (Thread * thread_ptr); + +void DT_Mdep_Thread_Detach (DT_Mdep_ThreadHandleType thread_id); +DT_Mdep_ThreadHandleType DT_Mdep_Thread_SELF ( void ); +void DT_Mdep_Thread_EXIT ( void * thread_handle ); +int DT_Mdep_wait_object_init ( IN DT_WAIT_OBJECT *wait_obj); +int DT_Mdep_wait_object_wait ( + IN DT_WAIT_OBJECT *wait_obj, + IN int timeout_val); +int DT_Mdep_wait_object_wakeup ( IN DT_WAIT_OBJECT *wait_obj); +int DT_Mdep_wait_object_destroy ( IN DT_WAIT_OBJECT *wait_obj); + + +DT_Mdep_Thread_Start_Routine_Return_Type + DT_Mdep_Thread_Start_Routine (void *thread_handle); + +/* dapl_memlist.c */ +void DT_MemListInit (Per_Test_Data_t * pt_ptr); +void *DT_MemListAlloc (Per_Test_Data_t * pt_ptr, + char *file, + mem_type_e t, + int size); +void DT_MemListFree (Per_Test_Data_t * pt_ptr, + void *ptr); +void DT_PrintMemList (Per_Test_Data_t * pt_ptr); + +/* dapl_netaddr.c */ +bool DT_NetAddrLookupHostAddress (DAT_IA_ADDRESS_PTR to_netaddr, + char *hostname); + +DAT_IA_ADDRESS_PTR DT_NetAddrAlloc (Per_Test_Data_t * pt_ptr); + +void DT_NetAddrFree (Per_Test_Data_t * pt_ptr, + DAT_IA_ADDRESS_PTR netaddr); + +/* dapl_params.c */ +bool DT_Params_Parse (int argc, + char *argv[], + Params_t * params_ptr); + +/* dapl_performance_cmd.c */ +const char * DT_PerformanceModeToString (Performance_Mode_Type mode); + +bool DT_Performance_Cmd_Init (Performance_Cmd_t * cmd); + +bool DT_Performance_Cmd_Parse (Performance_Cmd_t * cmd, + int my_argc, + char **my_argv, + mygetopt_t * opts); + +void DT_Performance_Cmd_Print (Performance_Cmd_t * cmd); +void DT_Performance_Cmd_PT_Print (DT_Tdep_Print_Head* phead, + Performance_Cmd_t * cmd); + +void DT_Performance_Cmd_Endian (Performance_Cmd_t * cmd); + +/* dapl_performance_client.c */ +DAT_RETURN DT_Performance_Test_Client ( Params_t *params_ptr, + Per_Test_Data_t * pt_ptr, + DAT_IA_HANDLE * ia_handle, + DAT_IA_ADDRESS_PTR remote); + +bool DT_Performance_Test_Client_Connect ( + DT_Tdep_Print_Head *phead, + Performance_Test_t * test_ptr); + +bool DT_Performance_Test_Client_Exchange ( + Params_t *params_ptr, + DT_Tdep_Print_Head *phead, + Performance_Test_t *test_ptr ); + +/* dapl_performance_server.c */ +void DT_Performance_Test_Server (void * pt_ptr); + +bool DT_Performance_Test_Server_Connect ( + DT_Tdep_Print_Head *phead, + Performance_Test_t * test_ptr); + +bool DT_Performance_Test_Server_Exchange ( + DT_Tdep_Print_Head *phead, + Performance_Test_t *test_ptr); + +/* dapl_performance_util.c */ +bool DT_Performance_Test_Create (Per_Test_Data_t * pt_ptr, + DAT_IA_HANDLE * ia_handle, + DAT_IA_ADDRESS_PTR remote_ia_addr, + DAT_BOOLEAN is_server, + DAT_BOOLEAN is_remote_little_endian, + Performance_Test_t **perf_test); + +void DT_Performance_Test_Destroy (Per_Test_Data_t * pt_ptr, + Performance_Test_t *test_ptr, + DAT_BOOLEAN is_server); + +bool DT_performance_post_rdma_op (Performance_Ep_Context_t *ep_context, + DAT_EVD_HANDLE reqt_evd_hdl, + Performance_Stats_t *stats); + +unsigned int DT_performance_reap (DT_Tdep_Print_Head* phead, + DAT_EVD_HANDLE evd_handle, + Performance_Mode_Type mode, + Performance_Stats_t *stats); + +unsigned int DT_performance_wait (DT_Tdep_Print_Head* phead, + DAT_EVD_HANDLE evd_handle, + Performance_Stats_t *stats); + +unsigned int DT_performance_poll (DT_Tdep_Print_Head* phead, + DAT_EVD_HANDLE evd_handle, + Performance_Stats_t *stats); + +/* dapl_performance_stats.c */ +void DT_performance_stats_init (Performance_Stats_t * stats); + +void DT_performance_stats_record_post (Performance_Stats_t *stats, + unsigned long ctxt_switch_num, + DT_Mdep_TimeStamp ts); + +void DT_performance_stats_record_reap (Performance_Stats_t *stats, + unsigned long ctxt_switch_num, + DT_Mdep_TimeStamp ts); + +void DT_performance_stats_record_latency (Performance_Stats_t *stats, + DT_Mdep_TimeStamp ts); + +void DT_performance_stats_data_combine (Performance_Stats_Data_t * dest, + Performance_Stats_Data_t * src_a, + Performance_Stats_Data_t * src_b); + +void DT_performance_stats_combine (Performance_Stats_t * dest, + Performance_Stats_t * src_a, + Performance_Stats_t * src_b); + +double DT_performance_stats_data_print (DT_Tdep_Print_Head* phead, + Performance_Stats_Data_t* data, + double cpu_mhz); + +void DT_performance_stats_print (Params_t * params_ptr, + DT_Tdep_Print_Head* phead, + Performance_Stats_t * stats, + Performance_Cmd_t * cmd, + Performance_Test_t * test); + + +/* dapl_server.c */ +void DT_cs_Server (Params_t * params_ptr); + +/* dapl_server_cmd.c */ +void DT_Server_Cmd_Init (Server_Cmd_t * Server_Cmd); + +bool DT_Server_Cmd_Parse (Server_Cmd_t * Server_Cmd, + int my_argc, + char **my_argv, + mygetopt_t * opts); + +void DT_Server_Cmd_Print (Server_Cmd_t * Server_Cmd); +void DT_Server_Cmd_PT_Print (DT_Tdep_Print_Head* phead, + Server_Cmd_t * Server_Cmd); + +void DT_Server_Cmd_Usage (void); + +/* dapl_server_info.c */ +void DT_Server_Info_Endian (Server_Info_t * server_info); + +void DT_Server_Info_Print (DT_Tdep_Print_Head* phead, + Server_Info_t * server_info); + +/* dapl_test_data.c */ +Per_Test_Data_t *DT_Alloc_Per_Test_Data (DT_Tdep_Print_Head* phead); + +void DT_Free_Per_Test_Data (Per_Test_Data_t * pt_ptr); + +/* dapl_test_util.c */ +DAT_BOOLEAN DT_query (Per_Test_Data_t *pt_ptr, + DAT_IA_HANDLE ia_handle, + DAT_EP_HANDLE ep_handle); + +DAT_BOOLEAN DT_post_recv_buffer (DT_Tdep_Print_Head* phead, + DAT_EP_HANDLE ep_handle, + Bpool * bp, + int index, + int size); + +DAT_BOOLEAN DT_post_send_buffer (DT_Tdep_Print_Head* phead, + DAT_EP_HANDLE ep_handle, + Bpool * bp, + int index, + int size); + +bool DT_conn_event_wait (DT_Tdep_Print_Head* phead, + DAT_EP_HANDLE ep_handle, + DAT_EVD_HANDLE evd_handle, + DAT_EVENT_NUMBER *event_number); + +bool DT_disco_event_wait ( DT_Tdep_Print_Head* phead, + DAT_EVD_HANDLE evd_handle, + DAT_EP_HANDLE *ep_handle ); + +bool DT_cr_event_wait (DT_Tdep_Print_Head* phead, + DAT_EVD_HANDLE evd_handle, + DAT_CR_ARRIVAL_EVENT_DATA *cr_stat_p); + +bool DT_dto_event_reap (DT_Tdep_Print_Head* phead, + DAT_EVD_HANDLE evd_handle, + bool poll, + DAT_DTO_COMPLETION_EVENT_DATA *dtop); + +bool DT_dto_event_wait (DT_Tdep_Print_Head* phead, + DAT_EVD_HANDLE evd_handle, + DAT_DTO_COMPLETION_EVENT_DATA *dtop); + +bool DT_dto_event_poll (DT_Tdep_Print_Head* phead, + DAT_EVD_HANDLE evd_handle, + DAT_DTO_COMPLETION_EVENT_DATA *dtop); + +bool DT_rmr_event_wait (DT_Tdep_Print_Head* phead, + DAT_EVD_HANDLE evd_handle, + DAT_RMR_BIND_COMPLETION_EVENT_DATA *rmr_ptr); + +bool DT_dto_check ( DT_Tdep_Print_Head* phead, + DAT_DTO_COMPLETION_EVENT_DATA *dto_p, + DAT_EP_HANDLE ep_expected, + DAT_COUNT len_expected, + DAT_DTO_COOKIE cookie_expected, + char *message); + +bool DT_rmr_check ( DT_Tdep_Print_Head* phead, + DAT_RMR_BIND_COMPLETION_EVENT_DATA*rmr_p, + DAT_RMR_HANDLE rmr_expected, + DAT_PVOID cookie_expected, + char *message); + +bool DT_cr_check (DT_Tdep_Print_Head* phead, + DAT_CR_ARRIVAL_EVENT_DATA *cr_stat_p, + DAT_PSP_HANDLE psp_handle_expected, + DAT_CONN_QUAL port_expected, + DAT_CR_HANDLE *cr_handlep, + char *message); + +/* dapl_thread.c */ +void DT_Thread_Init (Per_Test_Data_t * pt_ptr); + +void DT_Thread_End (Per_Test_Data_t * pt_ptr); + +Thread *DT_Thread_Create (Per_Test_Data_t * pt_ptr, + void (*fn) (void *), + void *param, + unsigned int stacksize); + +void DT_Thread_Destroy (Thread * thread_ptr, + Per_Test_Data_t * pt_ptr); + +bool DT_Thread_Start (Thread * thread_ptr); + +/* dapl_quit_cmd.c */ +void DT_Quit_Cmd_Init (Quit_Cmd_t * cmd); + +bool DT_Quit_Cmd_Parse (Quit_Cmd_t * cmd, + int my_argc, + char **my_argv, + mygetopt_t * opts); + +bool DT_Quit_Cmd_Validate (Quit_Cmd_t * cmd); + +void DT_Quit_Cmd_Endian (Quit_Cmd_t * cmd, + bool to_wire); + +void DT_Quit_Cmd_Print (Quit_Cmd_t * cmd); +void DT_Quit_Cmd_PT_Print (DT_Tdep_Print_Head *phead, Quit_Cmd_t * cmd); + +void DT_Quit_Cmd_Usage (void); + +/* dapl_transaction_cmd.c */ +void DT_Transaction_Cmd_Init (Transaction_Cmd_t * cmd); + +bool DT_Transaction_Cmd_Parse (Transaction_Cmd_t * cmd, + int my_argc, + char **my_argv, + mygetopt_t * opts); + +void DT_Transaction_Cmd_Print (Transaction_Cmd_t * cmd); +void DT_Transaction_Cmd_PT_Print (DT_Tdep_Print_Head* phead, + Transaction_Cmd_t * cmd); + +void DT_Transaction_Cmd_Endian (Transaction_Cmd_t * cmd, + bool to_wire); +/* dapl_transaction_test.c */ +DAT_RETURN DT_Transaction_Test_Client (Per_Test_Data_t * pt_ptr, + DAT_IA_HANDLE ia_handle, + DAT_IA_ADDRESS_PTR remote); + +void DT_Transaction_Test_Server (void *params); + +bool DT_Transaction_Create_Test (Per_Test_Data_t * pt_ptr, + DAT_IA_HANDLE * ia_handle, + DAT_BOOLEAN is_server, + unsigned int port_num, + DAT_BOOLEAN remote_is_little_endian, + DAT_IA_ADDRESS_PTR remote_ia_addr); + +void DT_Transaction_Main (void *param); +bool DT_Transaction_Run (DT_Tdep_Print_Head* phead, + Transaction_Test_t * test_ptr); +void DT_Transaction_Validation_Fill (DT_Tdep_Print_Head* phead, + Transaction_Test_t * test_ptr, + unsigned int iteration); +bool DT_Transaction_Validation_Check (DT_Tdep_Print_Head* phead, + Transaction_Test_t * test_ptr, + int iteration); +void DT_Print_Transaction_Test (DT_Tdep_Print_Head* phead, + Transaction_Test_t* test_ptr); +void DT_Print_Transaction_Stats (DT_Tdep_Print_Head* phead, + Transaction_Test_t* test_ptr); + +/* dapl_transaction_util.c */ +bool DT_handle_post_recv_buf (DT_Tdep_Print_Head* phead, + Ep_Context_t * ep_context, + unsigned int num_eps, + int op_indx); + +bool DT_handle_send_op (DT_Tdep_Print_Head* phead, + Ep_Context_t * ep_context, + unsigned int num_eps, + int op_indx, + bool poll); + +bool DT_handle_recv_op (DT_Tdep_Print_Head* phead, + Ep_Context_t * ep_context, + unsigned int num_eps, + int op_indx, + bool poll, + bool repost_recv); + +bool DT_handle_rdma_op (DT_Tdep_Print_Head* phead, + Ep_Context_t * ep_context, + unsigned int num_eps, + DT_Transfer_Type opcode, + int op_indx, + bool poll); + +bool DT_check_params (Per_Test_Data_t *pt_ptr, + char *module); + +void DT_Test_Error (void); + +/* dapl_util.c */ +const char *DT_RetToString (DAT_RETURN ret_value); + +const char *DT_TransferTypeToString (DT_Transfer_Type type); + +const char *DT_AsyncErr2Str (DAT_EVENT_NUMBER error_code); + +const char *DT_EventToSTr (DAT_EVENT_NUMBER event_code); + +const char *DT_State2Str (DAT_EP_STATE state_code); + +DAT_QOS DT_ParseQoS (char *arg); + +unsigned char *DT_AlignPtr (void * val, DAT_COUNT align); + +DAT_COUNT DT_RoundSize (DAT_COUNT val, DAT_COUNT align); + +/* dapl_limit_cmd.c */ +void DT_Limit_Cmd_Init ( Limit_Cmd_t * cmd); + +bool DT_Limit_Cmd_Parse ( Limit_Cmd_t * cmd, + int my_argc, + char **my_argv, + mygetopt_t * opts); + +void DT_Limit_Cmd_Usage (void); + +/* dapl_limit.c */ +DAT_RETURN DT_cs_Limit (Params_t *params, Limit_Cmd_t * cmd); + +/* dapl_fft_cmd.c */ +void DT_FFT_Cmd_Init ( FFT_Cmd_t * cmd); + +bool DT_FFT_Cmd_Parse ( FFT_Cmd_t * cmd, + int my_argc, + char **my_argv, + mygetopt_t * opts); + +void DT_FFT_Cmd_Usage (void); + +/* dapl_fft_test.c */ +DAT_RETURN DT_cs_FFT (Params_t *params, FFT_Cmd_t * cmd); + +/* dapl_fft_hwconn.c */ +void DT_hwconn_test (Params_t *params_ptr, FFT_Cmd_t *cmd); +int DT_hwconn_case0 (Params_t *params_ptr, FFT_Cmd_t *cmd); +int DT_hwconn_case1 (Params_t *params_ptr, FFT_Cmd_t *cmd); +int DT_hwconn_case2 (Params_t *params_ptr, FFT_Cmd_t *cmd); +int DT_hwconn_case3 (Params_t *params_ptr, FFT_Cmd_t *cmd); +int DT_hwconn_case4 (Params_t *params_ptr, FFT_Cmd_t *cmd); +int DT_hwconn_case5 (Params_t *params_ptr, FFT_Cmd_t *cmd); +int DT_hwconn_case6 (Params_t *params_ptr, FFT_Cmd_t *cmd); +int DT_hwconn_case7 (Params_t *params_ptr, FFT_Cmd_t *cmd); + +/* dapl_fft_endpoint.c */ +void DT_endpoint_test (Params_t *params_ptr, FFT_Cmd_t *cmd); +int DT_endpoint_generic (Params_t *params_ptr, FFT_Cmd_t *cmd, + bool destroy_pz_early); +int DT_endpoint_case0 (Params_t *params_ptr, FFT_Cmd_t *cmd); +int DT_endpoint_case1 (Params_t *params_ptr, FFT_Cmd_t *cmd); +int DT_endpoint_case2 (Params_t *params_ptr, FFT_Cmd_t *cmd); +int DT_endpoint_case3 (Params_t *params_ptr, FFT_Cmd_t *cmd); +int DT_endpoint_case4 (Params_t *params_ptr, FFT_Cmd_t *cmd); + +/* dapl_fft_pz.c */ +void DT_pz_test (Params_t *params_ptr, FFT_Cmd_t *cmd); +int DT_pz_case0 (Params_t *params_ptr, FFT_Cmd_t *cmd); +int DT_pz_case1 (Params_t *params_ptr, FFT_Cmd_t *cmd); +int DT_pz_case2 (Params_t *params_ptr, FFT_Cmd_t *cmd); +int DT_pz_case3 (Params_t *params_ptr, FFT_Cmd_t *cmd); +int DT_pz_case4 (Params_t *params_ptr, FFT_Cmd_t *cmd); +int DT_pz_case5 (Params_t *params_ptr, FFT_Cmd_t *cmd); +int DT_pz_case6 (Params_t *params_ptr, FFT_Cmd_t *cmd); + +/* dapl_fft_util.c */ +void DT_assert_fail (DT_Tdep_Print_Head* phead, + char *exp, + char *file, + char *baseFile, + int line); +int DT_ia_open (DAT_NAME_PTR dev_name, DAT_IA_HANDLE *ia_handle); +int DT_ep_create (Params_t *params_ptr, + DAT_IA_HANDLE ia_handle, + DAT_PZ_HANDLE pz_handle, + DAT_EVD_HANDLE *cr_evd, + DAT_EVD_HANDLE *conn_evd, + DAT_EVD_HANDLE *send_evd, + DAT_EVD_HANDLE *recv_evd, + DAT_EP_HANDLE *ep_handle); +void DT_fft_init_conn_struct (FFT_Connection_t *conn); +void DT_fft_init_client (Params_t *params_ptr, + FFT_Cmd_t *cmd, + FFT_Connection_t *conn); +int DT_fft_destroy_conn_struct (Params_t *params_ptr, FFT_Connection_t *conn); +void DT_fft_init_server (Params_t *params_ptr, FFT_Cmd_t *cmd, + FFT_Connection_t *conn); +void DT_fft_listen (Params_t *params_ptr, FFT_Connection_t *conn); +int DT_fft_connect (Params_t *params_ptr, FFT_Connection_t *conn); + +/* dapl_fft_connmgt.c */ +int DT_connmgt_case0 (Params_t *params_ptr, FFT_Cmd_t *cmd); +int DT_connmgt_case1 (Params_t *params_ptr, FFT_Cmd_t *cmd); +void DT_connmgt_test (Params_t *params_ptr, FFT_Cmd_t *cmd); + +/* dapl_fft_mem.c */ +int DT_mem_generic (Params_t *params_ptr, FFT_Cmd_t *cmd, int flag); +int DT_mem_case0 (Params_t *params_ptr, FFT_Cmd_t *cmd); +int DT_mem_case1 (Params_t *params_ptr, FFT_Cmd_t *cmd); +int DT_mem_case2 (Params_t *params_ptr, FFT_Cmd_t *cmd); +int DT_mem_case3 (Params_t *params_ptr, FFT_Cmd_t *cmd); +int DT_mem_case4 (Params_t *params_ptr, FFT_Cmd_t *cmd); +void DT_mem_test (Params_t *params_ptr, FFT_Cmd_t *cmd); + +/* dapl_fft_queryinfo.c */ +int DT_queryinfo_basic (Params_t *params_ptr, FFT_Cmd_t *cmd, + FFT_query_enum object_to_query, + DAT_RETURN result_wanted); +int DT_queryinfo_case0 (Params_t *params_ptr, FFT_Cmd_t *cmd); +int DT_queryinfo_case1 (Params_t *params_ptr, FFT_Cmd_t *cmd); +int DT_queryinfo_case2 (Params_t *params_ptr, FFT_Cmd_t *cmd); +int DT_queryinfo_case3 (Params_t *params_ptr, FFT_Cmd_t *cmd); +int DT_queryinfo_case4 (Params_t *params_ptr, FFT_Cmd_t *cmd); +int DT_queryinfo_case5 (Params_t *params_ptr, FFT_Cmd_t *cmd); +int DT_queryinfo_case6 (Params_t *params_ptr, FFT_Cmd_t *cmd); +int DT_queryinfo_case7 (Params_t *params_ptr, FFT_Cmd_t *cmd); +int DT_queryinfo_case8 (Params_t *params_ptr, FFT_Cmd_t *cmd); +int DT_queryinfo_case9 (Params_t *params_ptr, FFT_Cmd_t *cmd); +int DT_queryinfo_case10 (Params_t *params_ptr, FFT_Cmd_t *cmd); +int DT_queryinfo_case11 (Params_t *params_ptr, FFT_Cmd_t *cmd); +int DT_queryinfo_case12 (Params_t *params_ptr, FFT_Cmd_t *cmd); +int DT_queryinfo_case13 (Params_t *params_ptr, FFT_Cmd_t *cmd); +int DT_queryinfo_case14 (Params_t *params_ptr, FFT_Cmd_t *cmd); +int DT_queryinfo_case15 (Params_t *params_ptr, FFT_Cmd_t *cmd); +int DT_queryinfo_case16 (Params_t *params_ptr, FFT_Cmd_t *cmd); +int DT_queryinfo_case17 (Params_t *params_ptr, FFT_Cmd_t *cmd); +void DT_queryinfo_test (Params_t *params_ptr, FFT_Cmd_t *cmd); + +#endif /* __DAPL_PROTO_H__ */ diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_quit_cmd.h b/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_quit_cmd.h new file mode 100644 index 00000000..8aba24e1 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_quit_cmd.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#ifndef __DAPL_QUIT_CMD_H__ +#define __DAPL_QUIT_CMD_H__ + +#pragma pack (2) +typedef struct +{ + char server_name[256]; /* -s */ + char device_name[256]; /* -D */ + DAT_UINT32 debug; /* -d */ + DAT_QOS ReliabilityLevel; /* -R */ +} Quit_Cmd_t; +#pragma pack () + +#endif diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_server_cmd.h b/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_server_cmd.h new file mode 100644 index 00000000..244103a8 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_server_cmd.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#ifndef __DAPL_SERVER_CMD_H__ +#define __DAPL_SERVER_CMD_H__ + +#pragma pack (2) + +typedef struct +{ + bool debug; /* -d */ + char dapl_name[256]; /* -D device name */ + DAT_QOS ReliabilityLevel; /* -R */ +} Server_Cmd_t; +#pragma pack () + +#endif diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_server_info.h b/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_server_info.h new file mode 100644 index 00000000..898f9cc4 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_server_info.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#ifndef __DAPL_SERVER_INFO_H__ +#define __DAPL_SERVER_INFO_H__ + +#include "dapl_proto.h" + +#pragma pack (2) + +struct started_server +{ + char devicename[256]; + struct started_server *next; +}; + +typedef struct started_server Started_server_t; + +extern Started_server_t *DT_started_server_list; + +#define SERVER_PORT_NUMBER ((DAT_CONN_QUAL)0xB0de) + +typedef struct +{ + DAT_UINT32 dapltest_version; + DAT_UINT32 is_little_endian; + DAT_UINT32 first_port_number; +} Server_Info_t; +#pragma pack () + +#endif diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_tdep.h b/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_tdep.h new file mode 100644 index 00000000..ccddce5c --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_tdep.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#ifndef _DAPL_TDEP_H_ +#define _DAPL_TDEP_H_ + +#include "dapl_proto.h" + +#ifdef __KDAPL__ +typedef DAT_HANDLE DAT_CNO_HANDLE; +#endif + +/* function prototypes */ +void +DT_Tdep_Init ( void ) ; + +void +DT_Tdep_End ( void ) ; + +DAT_RETURN +DT_Tdep_Execute_Test ( Params_t *params_ptr ) ; + +DAT_RETURN +DT_Tdep_lmr_create (DAT_IA_HANDLE ia_handle, + DAT_MEM_TYPE mem_type, + DAT_REGION_DESCRIPTION region, + DAT_VLEN len, + DAT_PZ_HANDLE pz_handle, + DAT_MEM_PRIV_FLAGS priv_flag, + DAT_LMR_HANDLE *lmr_handle_ptr, + DAT_LMR_CONTEXT *lmr_context_ptr, + DAT_RMR_CONTEXT *rmr_context_ptr, + DAT_VLEN *reg_size_ptr, + DAT_VADDR *reg_addr_ptr); + +DAT_RETURN +DT_Tdep_evd_create (DAT_IA_HANDLE ia_handle, + DAT_COUNT evd_min_qlen, + DAT_CNO_HANDLE cno_handle, + DAT_EVD_FLAGS evd_flags, + DAT_EVD_HANDLE *evd_handle_ptr); + +DAT_RETURN +DT_Tdep_evd_free (DAT_EVD_HANDLE evd_handle); + +DAT_RETURN +DT_Tdep_evd_wait (DAT_EVD_HANDLE evd_handle, + DAT_TIMEOUT timeout, + DAT_EVENT *event); +DAT_RETURN +DT_Tdep_evd_dequeue (DAT_EVD_HANDLE evd_handle, + DAT_EVENT *event); + +#endif diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_tdep_print.h b/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_tdep_print.h new file mode 100644 index 00000000..0a1a1b07 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_tdep_print.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#ifndef _DAPL_TDEP_PRINT_H_ +#define _DAPL_TDEP_PRINT_H_ + +#define DT_Tdep_PT_Debug(N, _X_) \ +do { \ + if (DT_dapltest_debug >= (N)) \ + { \ + DT_Tdep_PT_Printf _X_; \ + } \ +} while (0) + +#ifdef __KERNEL__ +typedef struct Tdep_Print_Entry_Tag +{ + struct Tdep_Print_Entry_Tag *next; + char buffer[PRINT_MAX]; +} Tdep_Print_Entry; + +typedef struct DT_Tdep_Print_Head_Tag +{ + int instance; + struct DT_Tdep_Print_Head_Tag *next; + Tdep_Print_Entry *head; + Tdep_Print_Entry *tail; + DT_Mdep_LockType lock; + DT_WAIT_OBJECT wait_object; +} DT_Tdep_Print_Head; + + +void DT_Tdep_PT_Printf (DT_Tdep_Print_Head *phead, const char * fmt, ...); + +#else + +typedef void * DT_Tdep_Print_Head; +void DT_Tdep_PT_Printf (DT_Tdep_Print_Head *phead, const char * fmt, ...); + +#endif +#endif diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_test_data.h b/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_test_data.h new file mode 100644 index 00000000..4ac00209 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_test_data.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#ifndef __DAPL_TEST_DATA_H__ +#define __DAPL_TEST_DATA_H__ + +#include "dapl_proto.h" +#include "dapl_bpool.h" +#include "dapl_client_info.h" +#include "dapl_transaction_stats.h" +#include "dapl_memlist.h" +#include "dapl_params.h" +#include "dapl_server_info.h" + +/* This lock allows the client side to run + * in a shell script loop without breaking + * connections. Remove it and due to timing + * problems on the server side occasionally + * the server will reject connections. + */ +extern DT_Mdep_LockType g_PerfTestLock; + +/* + * check memory leaking extern int alloc_count ; extern + * DT_Mdep_LockType Alloc_Count_Lock; + */ + +typedef struct +{ + int NextPortNumber; + int num_clients; + DT_Mdep_LockType num_clients_lock; + DAT_IA_HANDLE ia_handle; + DAT_PZ_HANDLE pz_handle; + DAT_EVD_HANDLE recv_evd_hdl; + DAT_EVD_HANDLE reqt_evd_hdl; + DAT_EVD_HANDLE conn_evd_hdl; + DAT_EVD_HANDLE creq_evd_hdl; + DAT_EVD_HANDLE async_evd_hdl; + DAT_EVD_HANDLE rmr_evd_hdl; + DAT_EP_HANDLE ep_handle; + DAT_PSP_HANDLE psp_handle; + Bpool *bpool; +} Per_Server_Data_t; + +typedef struct +{ + DT_Mdep_LockType MemListLock; + MemListEntry_t *MemListHead; + + DT_Mdep_LockType Thread_counter_lock; + int Thread_counter; + Thread *thread; + + bool local_is_server; + Server_Info_t Server_Info; + Client_Info_t Client_Info; + Params_t Params; + DAT_IA_ATTR ia_attr; + DAT_PROVIDER_ATTR provider_attr; + DAT_EP_ATTR ep_attr; + Per_Server_Data_t *ps_ptr; + Transaction_Stats_t Client_Stats; + + /* synchronize the server with the server's spawned test thread. + * That test thread uses a PSP that only one test at a time can + * use. If we don't synchronize access between the teardown and + * creation of that PSP then the client will fail to connect + * randomly, a symptom that the server is not coordinated with + * its test threads. Remove this at your own peril, or if you + * really want your test client to experience rejection on a + * random but regular basis. + */ + DT_WAIT_OBJECT synch_wait_object; + int Countdown_Counter; + +} Per_Test_Data_t; + +#endif diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_transaction_cmd.h b/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_transaction_cmd.h new file mode 100644 index 00000000..afd59c01 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_transaction_cmd.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#ifndef __DAPL_TRANSACTION_CMD_H__ +#define __DAPL_TRANSACTION_CMD_H__ + +#include "dapl_proto.h" + +#define MAX_OPS 100 +#define NAME_SZ 256 + +#pragma pack (2) +typedef struct +{ + DAT_UINT32 server_initiated; + DAT_UINT32 transfer_type; + DAT_UINT32 num_segs; + DAT_UINT32 seg_size; + DAT_UINT32 reap_send_on_recv; +} Transaction_Cmd_Op_t; + +typedef struct +{ + DAT_UINT32 dapltest_version; + DAT_UINT32 client_is_little_endian; + char server_name[NAME_SZ]; /* -s */ + DAT_UINT32 num_iterations; /* -i */ + DAT_UINT32 num_threads; /* -t */ + DAT_UINT32 eps_per_thread; /* -w */ + DAT_UINT32 use_cno; /* NOT USED - remove and bump version*/ + DAT_UINT32 use_rsp; /* -r */ + DAT_UINT32 debug; /* -d */ + DAT_UINT32 validate; /* -V */ + DAT_UINT32 poll; /* -P */ + char dapl_name[NAME_SZ]; /* -D */ + DAT_QOS ReliabilityLevel; + DAT_UINT32 num_ops; + Transaction_Cmd_Op_t op[MAX_OPS]; +} Transaction_Cmd_t; +#pragma pack () + +#endif diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_transaction_stats.h b/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_transaction_stats.h new file mode 100644 index 00000000..3fd3a957 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_transaction_stats.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#ifndef __DAPL_TRANSACTION_STATS_H__ +#define __DAPL_TRANSACTION_STATS_H__ + +#include "dapl_proto.h" + +#define whole(num) ((unsigned int)(num)) +#define hundredths(num) ((unsigned int)(((num) - (unsigned int)(num)) * 100)) + +typedef struct +{ + DT_Mdep_LockType lock; + unsigned int wait_count; + unsigned int num_ops; + unsigned int time_ms; + unsigned int bytes_send; + unsigned int bytes_recv; + unsigned int bytes_rdma_read; + unsigned int bytes_rdma_write; +} Transaction_Stats_t; +#endif diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_transaction_test.h b/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_transaction_test.h new file mode 100644 index 00000000..7401cdf6 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_transaction_test.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#ifndef __DAPL_TRANSACTION_TEST_H__ +#define __DAPL_TRANSACTION_TEST_H__ + +#include "dapl_proto.h" +#include "dapl_common.h" +#include "dapl_test_data.h" +#include "dapl_transaction_cmd.h" + +typedef struct +{ + DAT_BOOLEAN server_initiated; + DT_Transfer_Type transfer_type; + DAT_UINT32 num_segs; + DAT_UINT32 seg_size; + DAT_BOOLEAN reap_send_on_recv; + Bpool *bp; + + /* RDMA info */ + DAT_RMR_CONTEXT Rdma_Context; + DAT_VADDR Rdma_Address; +} Transaction_Test_Op_t; + +typedef struct +{ + DAT_EP_HANDLE ep_handle; + DAT_EP_ATTR ep_attr; + DAT_CONN_QUAL ia_port; + Bpool *bp; + Transaction_Test_Op_t op[ MAX_OPS ]; + DAT_RSP_HANDLE rsp_handle; + DAT_PSP_HANDLE psp_handle; + DAT_EVD_HANDLE recv_evd_hdl; /* receive */ + DAT_EVD_HANDLE reqt_evd_hdl; /* request+rmr */ + DAT_EVD_HANDLE conn_evd_hdl; /* connect */ + DAT_EVD_HANDLE creq_evd_hdl; /* "" request */ + +} Ep_Context_t; + +typedef struct +{ + unsigned int stat_bytes_send; + unsigned int stat_bytes_recv; + unsigned int stat_bytes_rdma_read; + unsigned int stat_bytes_rdma_write; + unsigned int start_time; + unsigned int end_time; +} Transaction_Test_Stats_t; + +typedef struct +{ + /* This group set up by DT_Transaction_Create_Test() */ + DAT_BOOLEAN is_server; + DAT_BOOLEAN remote_is_little_endian; + Per_Test_Data_t *pt_ptr; + DAT_IA_HANDLE ia_handle; + Transaction_Cmd_t *cmd; + DAT_IA_ADDRESS_PTR remote_ia_addr; + DAT_CONN_QUAL base_port; + DAT_TIMEOUT time_out; + DAT_COUNT evd_length; + Thread *thread; + + /* This group set up by each thread in DT_Transaction_Main() */ + DAT_PZ_HANDLE pz_handle; + Ep_Context_t *ep_context; + + /* Statistics set by DT_Transaction_Run() */ + Transaction_Test_Stats_t stats; +} Transaction_Test_t; + +#endif diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_version.h b/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_version.h new file mode 100644 index 00000000..20222504 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/include/dapl_version.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#ifndef __DAPL_VERSION_H +#define __DAPL_VERSION_H +/* + * Dapltest version number + * + * This should be bumped everytime the "cross-the-wire" behavior changes. + */ + +#define DAPLTEST_VERSION 0x00000006 + +#endif diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/mdep/linux/dapl_mdep_kernel.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/mdep/linux/dapl_mdep_kernel.c new file mode 100644 index 00000000..e2c6da31 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/mdep/linux/dapl_mdep_kernel.c @@ -0,0 +1,347 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" +#include "kdapl_tdep.h" +#include +#ifndef UPCALL_FROM_IRQ +#include /* for spin_lock_bh */ +#endif /* UPCALL_FROM_IRQ */ + +#include /* Getting Statistics */ +#include /* Definitions of smp_num_cpus and cpu_logical_map(cpu) */ +#include /* jiffies */ +#include + +/* + * Sleep specified number of milliseconds + */ + +void DT_Mdep_Sleep(int msec) +{ + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(msec * HZ / 1000); +} + +void DT_Mdep_Schedule(void) +{ + schedule(); +} + +/* + * Get system statistics including uptime and idle time + */ + +bool DT_Mdep_GetCpuStat(DT_CpuStat * cpu_stat) +{ + unsigned long i, nice = 0; + unsigned long jif = jiffies; + int cpu, num_of_cpus; + cpu_stat->user = 0; + cpu_stat->system = 0; + cpu_stat->idle = 0; + num_of_cpus = 0; + cpu = 0; + + // code for vanila 2.4 kernel +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)) && !defined RHAS3 + for (i = 0; i < smp_num_cpus; i++) { + cpu = cpu_logical_map(i); + cpu_stat->user += (unsigned long)kstat.per_cpu_user[cpu]; + nice += (unsigned long)kstat.per_cpu_nice[cpu]; + cpu_stat->system += (unsigned long)kstat.per_cpu_system[cpu]; + } + // kernel 2.4 AS3.0 +#elif (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)) && defined RHAS3 + cpu_stat->user = kstat_sum(accumulated_time.u_usec); + cpu_stat->system = kstat_sum(accumulated_time.s_usec); + nice = kstat_sum(accumulated_time.n_usec); + // kernel 2.6 +#elif LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0) + for (i = 0; i < NR_CPUS; i++) { + if (cpu_possible(i)) { + cpu_stat->system += kstat_cpu(i).cpustat.system; + cpu_stat->user += kstat_cpu(i).cpustat.user; + nice += kstat_cpu(i).cpustat.nice; + num_of_cpus = +1; + } + } +#endif + cpu_stat->idle = + (unsigned long)(jif * num_of_cpus - + (cpu_stat->user + nice + cpu_stat->system)); + return true; +} + +/* + * Get current time in milliseconds (relative to some fixed point) + */ +unsigned long DT_Mdep_GetTime(void) +{ + struct timeval tv; + + do_gettimeofday(&tv); + return ((unsigned long)(tv.tv_sec) * 1000L) + + (unsigned long)(tv.tv_usec) / 1000; +} + +#if 0 +unsigned long DT_Mdep_GetContextSwitchNum(void) +{ + return nr_context_switches(); +} +#endif + +/* + * Memory allocate and free routines for control blocks (objects) - regular + * memory, always zeroed. + */ +void *DT_Mdep_Malloc(size_t l_) +{ + void *rval; + + /* + * check memory leaking DT_Mdep_Lock(&Alloc_Count_Lock); alloc_count++; + * DT_Mdep_Unlock(&Alloc_Count_Lock); + */ + + rval = kmalloc(l_, GFP_ATOMIC); + + if (rval) { + memset(rval, 0, l_); + } + return (rval); +} + +void DT_Mdep_Free(void *a_) +{ + /* + * check memory leaking DT_Mdep_Lock(&Alloc_Count_Lock); alloc_count--; + * DT_Mdep_Unlock(&Alloc_Count_Lock); + */ + + kfree(a_); +} + +/* + * Lock support + * + * Lock object constructor + */ +bool DT_Mdep_LockInit(DT_Mdep_LockType * lock_ptr) +{ + spin_lock_init(lock_ptr); + return true; +} + +/* + * Lock object destructor + */ +void DT_Mdep_LockDestroy(DT_Mdep_LockType * lock_ptr) +{ + /* nothing */ +} + +/* + * Locks + * + */ +void DT_Mdep_Lock(DT_Mdep_LockType * lock_ptr) +{ + SPINLOCK(lock_ptr); +} + +/* + * unlock + */ +void DT_Mdep_Unlock(DT_Mdep_LockType * lock_ptr) +{ + SPINUNLOCK(lock_ptr); +} + +/* + * Init Thread Attributes + */ +void DT_Mdep_Thread_Init_Attributes(Thread * thread_ptr) +{ + /* nothing */ +} + +/* + * Destroy Thread Attributes + */ +void DT_Mdep_Thread_Destroy_Attributes(Thread * thread_ptr) +{ + /* nothing */ +} + +/* + * Start the thread + */ +bool DT_Mdep_Thread_Start(Thread * thread_ptr) +{ + thread_ptr->thread_handle = kernel_thread((void *) + DT_Mdep_Thread_Start_Routine, + (void *)thread_ptr, 0); + return (thread_ptr->thread_handle); +} + +/* + * Thread execution entry point function + */ +DT_Mdep_Thread_Start_Routine_Return_Type +DT_Mdep_Thread_Start_Routine(void *thread_handle) +{ + Thread *thread_ptr; + thread_ptr = (Thread *) thread_handle; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) + reparent_to_init(); +#else + daemonize(__func__); +#endif + thread_ptr->function(thread_ptr->param); + return 0; +} + +/* + * Thread detach routine. Allows the pthreads + * interface to clean up resources properly at + * thread's end. + */ +void DT_Mdep_Thread_Detach(int thread_id) +{ /* AMM */ + /* nothing */ +} + +/* + * Allows a thread to get its own ID so it + * can pass it to routines wanting to act + * upon themselves. + */ + +int DT_Mdep_Thread_SELF(void) +{ /* AMM */ + /* nothing */ + return (0); +} + +/* + * Allow a thread to exit and cleanup resources. + */ + +void DT_Mdep_Thread_EXIT(void *thread_handle) +{ /* AMM */ + /* nothing */ +} + +/* + * DT_Mdep_wait_object_init + * + * Initialize a wait object + * + * Input: + * wait_obj + * + * Returns: + * 0 if successful + * -1 if unsuccessful + */ +int DT_Mdep_wait_object_init(IN DT_WAIT_OBJECT * wait_obj) +{ + init_waitqueue_head(wait_obj); + return 0; +} + +/* Wait on the supplied wait object, up to the specified time_out. + * A timeout of DAT_TIMEOUT_INFINITE will wait indefinitely. + * Timeout should be specified in micro seconds. + * + * Functional returns: + * 0 -- another thread invoked dapl_os_wait object_wakeup + * -1 -- someone else is already waiting in this wait + * object. + * only one waiter is allowed at a time. + * -1 -- another thread invoked dapl_os_wait_object_destroy + * -1 -- the specified time limit was reached. + */ + +int DT_Mdep_wait_object_wait(IN DT_WAIT_OBJECT * wait_obj, IN int timeout_val) +{ + int expire; + int dat_status; + + dat_status = DAT_SUCCESS; + if (DAT_TIMEOUT_INFINITE == timeout_val) { + interruptible_sleep_on(wait_obj); + } else { + expire = timeout_val * HZ / 1000000; + while (expire) { + current->state = TASK_INTERRUPTIBLE; + expire = schedule_timeout(expire); + } + dat_status = DAT_TIMEOUT_EXPIRED; + } + return dat_status; +} + +/* + * DT_Mdep_wait_object_wakeup + * + * Wakeup a thread waiting on a wait object + * + * Input: + * wait_obj + * + * Returns: + * 0 if successful + * -1 if not successful + */ +int DT_Mdep_wait_object_wakeup(DT_WAIT_OBJECT * wait_obj) +{ + wake_up_interruptible(wait_obj); + return 0; +} + +/* + * DT_Mdep_wait_object_destroy + * + * Destroy a wait object + * + * Input: + * wait_obj + * + * Returns: + * 0 if successful + * -1 if not successful + */ +int DT_Mdep_wait_object_destroy(IN DT_WAIT_OBJECT * wait_obj) +{ + return 0; +} diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/mdep/linux/dapl_mdep_kernel.h b/branches/WOF2-3/ulp/dapl2/test/dapltest/mdep/linux/dapl_mdep_kernel.h new file mode 100644 index 00000000..c0734e94 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/mdep/linux/dapl_mdep_kernel.h @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#ifndef __DAPL_KERNEL_MDEP_H__ +#define __DAPL_KERNEL_MDEP_H__ + +/* include files */ + +# include +# include +# include +# include +# include +# include +# include +# include +# include "kdapl_ioctl.h" +#ifndef UPCALL_FROM_IRQ +#include /* for spin_lock_bh */ +#endif /* UPCALL_FROM_IRQ */ + +/* Default Device Name */ +#define DT_MdepDeviceName "ia0a" + +/* Boolean */ +typedef int bool; + +#define true (1) +#define false (0) + +#ifndef __BASE_FILE__ +#define __BASE_FILE__ __FILE__ +#endif + +#ifndef _INLINE_ +#define _INLINE_ __inline__ +#endif + +/* + * Locks + */ + +typedef spinlock_t DT_Mdep_LockType; + +/* + * If UPCALL_FROM_IRQ is defined, the provider will invoke upcalls + * directly from IRQ. Most providers invoke upcalls from the Linux + * BH handler, the default here. + * + * Locks must be adapted to match the actual upcall context! + */ +#ifdef UPCALL_FROM_IRQ +#define SPINLOCK(lp) spin_lock_irq (lp); +#define SPINUNLOCK(lp) spin_unlock_irq (lp); +#else +#define SPINLOCK(lp) spin_lock_bh (lp); +#define SPINUNLOCK(lp) spin_unlock_bh (lp); +#endif + + +/* Wait object used for inter thread communication */ + +typedef wait_queue_head_t DT_WAIT_OBJECT; + +/* + * Thread types + */ +typedef int DT_Mdep_ThreadHandleType; +typedef void (*DT_Mdep_ThreadFunction) (void *param); +typedef void * DT_Mdep_Thread_Start_Routine_Return_Type; +#define DT_MDEP_DEFAULT_STACK_SIZE 65536 + +typedef struct +{ + void (*function) (void *); + void *param; + DT_Mdep_ThreadHandleType thread_handle; + unsigned int stacksize; +} Thread; + +/* + * System information + * + */ + +typedef struct +{ + unsigned long int system; + unsigned long int user; + unsigned long int idle; +} DT_CpuStat; + +/* + * Timing + */ + +typedef unsigned long long int DT_Mdep_TimeStamp; + +static _INLINE_ DT_Mdep_TimeStamp +DT_Mdep_GetTimeStamp ( void ) +{ +#if defined(__GNUC__) && defined(__PENTIUM__) + DT_Mdep_TimeStamp x; + __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x)); + return x; +#else + +#ifdef __ia64__ + unsigned long x; + + x = get_cycles (); + return x; +#else +#error "Non-Pentium Linux - unimplemented" +#endif +#endif + +} + +#ifndef __ia64__ +typedef int * intptr_t; +typedef unsigned long uintptr_t; +#endif + +#define bzero(x, y) memset(x, 0, y) + +/* + * Define long format types to be used in *printf format strings. We + * use the C string constant concatenation ability to define 64 bit + * formats, which unfortunatly are non standard in the C compiler + * world. E.g. %llx for gcc, %I64x for Windows + */ +#ifdef __x86_64__ +#define F64d "%ld" +#define F64u "%lu" +#define F64x "%lx" +#define F64X "%lX" +#else +#define F64d "%lld" +#define F64u "%llu" +#define F64x "%llx" +#define F64X "%llX" +#endif + +/* + * Define notion of a LONG LONG 0 + */ +#define LZERO 0ULL + +/* Mdep function defines */ + +#define DT_Mdep_flush() +#endif diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/mdep/linux/dapl_mdep_user.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/mdep/linux/dapl_mdep_user.c new file mode 100644 index 00000000..d2b45bd8 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/mdep/linux/dapl_mdep_user.c @@ -0,0 +1,546 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_mdep.h" +#include "dapl_proto.h" + +#include /* needed for pthread_atfork() */ +#include +#include /* needed for getenv() */ +#include /* needed for thread setup */ + +#include +#include +#include +#include +#include +#include +#include +#include /* for printf */ +#include +#include +#include /* for getaddrinfo */ + +/* + * Include files for setting up a network name + */ +#include +#include +#include +#include + +static FILE *Stat_Fp = NULL; +# define DT_STAT_FILE "/proc/stat" + +#include "dapl_test_data.h" /* for alloc_count */ + +/* + * Machine dependant initialization + */ + +void DT_Mdep_Init(void) +{ + Stat_Fp = fopen(DT_STAT_FILE, "r"); + if (NULL == Stat_Fp) { + perror("fopen of " DT_STAT_FILE " failed"); + exit(1); + } +} + +/* + * Machine dependant deinitialization + */ + +void DT_Mdep_End(void) +{ + if (0 != fclose(Stat_Fp)) { + perror("fclose of " DT_STAT_FILE " failed"); + exit(1); + } +} + +/* + * Generate name of IB device + */ + +bool DT_Mdep_GetDefaultDeviceName(char *dapl_name) +{ + strcpy(dapl_name, DT_MdepDeviceName); + return true; +} + +/* + * Sleep specified number of milliseconds + */ + +void DT_Mdep_Sleep(int msec) +{ + struct timespec t; + t.tv_sec = msec / 1000; /* Whole seconds */ + t.tv_nsec = (msec % 1000) * 1000 * 1000; + nanosleep(&t, 0); +} + +void DT_Mdep_Schedule(void) +{ + /* nothing here */ +} + +/* + * Get system statistics including uptime and idle time + */ + +bool DT_Mdep_GetCpuStat(DT_CpuStat * cpu_stat) +{ + +#define DT_CPU_STAT_STR "cpu" +#define DT_CPU_STAT_BUFFER_SIZE 1024 +#define DT_CPU_STAT_DELIMITER " " + + static char buffer[DT_CPU_STAT_BUFFER_SIZE]; + + cpu_stat->user = 0; + cpu_stat->system = 0; + cpu_stat->idle = 0; + + if (0 != fflush(Stat_Fp)) { + perror("fflush of " DT_STAT_FILE " failed"); + exit(1); + } + + for (;;) { + if (NULL == fgets(buffer, DT_CPU_STAT_BUFFER_SIZE, Stat_Fp)) { + printf(DT_CPU_STAT_STR " not found\n"); + exit(1); + } + + if (!strncmp(buffer, DT_CPU_STAT_STR, strlen(DT_CPU_STAT_STR))) { + break; + } + } + + (void)strtok(buffer, DT_CPU_STAT_DELIMITER); + cpu_stat->user = strtoul(strtok(NULL, DT_CPU_STAT_DELIMITER), NULL, 0); + cpu_stat->user += strtoul(strtok(NULL, DT_CPU_STAT_DELIMITER), NULL, 0); + cpu_stat->system = + strtoul(strtok(NULL, DT_CPU_STAT_DELIMITER), NULL, 0); + cpu_stat->idle = strtoul(strtok(NULL, DT_CPU_STAT_DELIMITER), NULL, 0); + + rewind(Stat_Fp); + + return true; +} + +/* + * Get current time in milliseconds (relative to some fixed point) + */ +unsigned long DT_Mdep_GetTime(void) +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_sec * 1000 + tv.tv_usec / 1000; +} + +#ifdef RDTSC_TIMERS +double DT_Mdep_GetCpuMhz(void) +{ +#define DT_TSC_BUFFER_SIZE 128 +#if defined (__PPC__) || defined (__PPC64__) +#define DT_TSC_RATE "timebase" +#define DT_TSC_BASE 1000000.0 +#else +#define DT_TSC_RATE "cpu MHz" +#define DT_TSC_BASE 1.0 +#endif +#define DT_TSC_DELIMITER ":" + + FILE *fp; + char buffer[DT_TSC_BUFFER_SIZE]; + char *mhz_str; + + fp = fopen("/proc/cpuinfo", "r"); + if (NULL == fp) { + perror("fopen of /proc/cpuinfo failed"); + exit(1); + } + + for (;;) { + if (NULL == fgets(buffer, DT_TSC_BUFFER_SIZE, fp)) { + printf("cpu MHZ not found\n"); + exit(1); + } + + if (!strncmp(buffer, DT_TSC_RATE, strlen(DT_TSC_RATE))) { + (void)strtok(buffer, DT_TSC_DELIMITER); + mhz_str = strtok(NULL, DT_TSC_DELIMITER); + + break; + } + } + + if (0 != fclose(fp)) { + perror("fclose of /proc/cpuinfo failed"); + exit(1); + } + + return strtod(mhz_str, NULL) / DT_TSC_BASE; +} +#else /* !RDTSC_TIMERS */ + +double DT_Mdep_GetCpuMhz(void) +{ + return 1; +} +#endif + +unsigned long DT_Mdep_GetContextSwitchNum(void) +{ + +#define DT_CTXT_STR "ctxt" +#define DT_CTXT_BUFFER_SIZE 1024 +#define DT_CTXT_DELIMITER " " + + static char buffer[DT_CTXT_BUFFER_SIZE]; + char *ctxt_str; + + if (0 != fflush(Stat_Fp)) { + perror("fflush of " DT_STAT_FILE " failed"); + exit(1); + } + + for (;;) { + if (NULL == fgets(buffer, DT_CTXT_BUFFER_SIZE, Stat_Fp)) { + printf(DT_CTXT_STR " not found\n"); + exit(1); + } + + if (!strncmp(buffer, DT_CTXT_STR, strlen(DT_CTXT_STR))) { + (void)strtok(buffer, DT_CTXT_DELIMITER); + ctxt_str = strtok(NULL, DT_CTXT_DELIMITER); + + break; + } + } + + rewind(Stat_Fp); + + return strtoul(ctxt_str, NULL, 0); +} + +/* + * Memory allocate and free routines for control blocks (objects) - regular + * memory, always zeroed. + */ +void *DT_Mdep_Malloc(size_t l_) +{ + void *rval; + + /* + * check memory leaking DT_Mdep_Lock(&Alloc_Count_Lock); alloc_count++; + * DT_Mdep_Unlock(&Alloc_Count_Lock); + */ + + rval = malloc(l_); + + if (rval) { + memset(rval, 0, l_); + } + return (rval); +} + +void DT_Mdep_Free(void *a_) +{ + /* + * check memory leaking DT_Mdep_Lock(&Alloc_Count_Lock); alloc_count--; + * DT_Mdep_Unlock(&Alloc_Count_Lock); + */ + + free(a_); +} + +/* + * Lock support + * + * Lock object constructor + */ +bool DT_Mdep_LockInit(DT_Mdep_LockType * lock_ptr) +{ + return pthread_mutex_init(lock_ptr, 0) ? false : true; +} + +/* + * Lock object destructor + */ +void DT_Mdep_LockDestroy(DT_Mdep_LockType * lock_ptr) +{ + pthread_mutex_destroy(lock_ptr); +} + +/* + * Lock + */ +void DT_Mdep_Lock(DT_Mdep_LockType * lock_ptr) +{ + pthread_mutex_lock(lock_ptr); +} + +/* + * unlock + */ +void DT_Mdep_Unlock(DT_Mdep_LockType * lock_ptr) +{ + pthread_mutex_unlock(lock_ptr); +} + +/* + * Init Thread Attributes + */ +void DT_Mdep_Thread_Init_Attributes(Thread * thread_ptr) +{ + pthread_attr_init(&thread_ptr->attr); + pthread_attr_setstacksize(&thread_ptr->attr, thread_ptr->stacksize); + /* Create thread in detached state to free resources on termination; + * this precludes doing a pthread_join, but we don't do it + */ + pthread_attr_setdetachstate(&thread_ptr->attr, PTHREAD_CREATE_DETACHED); +} + +/* + * Destroy Thread Attributes + */ +void DT_Mdep_Thread_Destroy_Attributes(Thread * thread_ptr) +{ + pthread_attr_destroy(&thread_ptr->attr); +} + +/* + * Start the thread + */ +bool DT_Mdep_Thread_Start(Thread * thread_ptr) +{ + return pthread_create(&thread_ptr->thread_handle, + &thread_ptr->attr, + DT_Mdep_Thread_Start_Routine, thread_ptr) == 0; +} + +/* + * Thread execution entry point function + */ +DT_Mdep_Thread_Start_Routine_Return_Type +DT_Mdep_Thread_Start_Routine(void *thread_handle) +{ + Thread *thread_ptr; + thread_ptr = (Thread *) thread_handle; + + thread_ptr->function(thread_ptr->param); + return 0; +} + +/* + * Thread detach routine. Allows the pthreads + * interface to clean up resources properly at + * thread's end. + */ +void DT_Mdep_Thread_Detach(DT_Mdep_ThreadHandleType thread_id) +{ /* AMM */ + pthread_detach(thread_id); +} + +/* + * Allows a thread to get its own ID so it + * can pass it to routines wanting to act + * upon themselves. + */ + +DT_Mdep_ThreadHandleType DT_Mdep_Thread_SELF(void) +{ /* AMM */ + return (pthread_self()); +} + +/* + * Allow a thread to exit and cleanup resources. + */ + +void DT_Mdep_Thread_EXIT(void *thread_handle) +{ /* AMM */ + pthread_exit(thread_handle); +} + +/* + * DT_Mdep_wait_object_init + * + * Initialize a wait object + * + * Input: + * wait_obj + * + * Returns: + * 0 if successful + * -1 if unsuccessful + */ +int DT_Mdep_wait_object_init(IN DT_WAIT_OBJECT * wait_obj) +{ + + wait_obj->signaled = DAT_FALSE; + if (0 != pthread_cond_init(&wait_obj->cv, NULL)) { + return (-1); + } + + /* Always returns 0. */ + pthread_mutex_init(&wait_obj->lock, NULL); + return 0; +} + +/* Wait on the supplied wait object, up to the specified time_out. + * A timeout of DAT_TIMEOUT_INFINITE will wait indefinitely. + * Timeout should be specified in micro seconds. + * + * Functional returns: + * 0 -- another thread invoked dapl_os_wait object_wakeup + * -1 -- someone else is already waiting in this wait + * object. + * only one waiter is allowed at a time. + * -1 -- another thread invoked dapl_os_wait_object_destroy + * -1 -- the specified time limit was reached. + */ + +int DT_Mdep_wait_object_wait(IN DT_WAIT_OBJECT * wait_obj, IN int timeout_val) +{ + int dat_status; + int pthread_status; + struct timespec future; + + dat_status = 0; + pthread_status = 0; + + if (timeout_val != DAT_TIMEOUT_INFINITE) { + struct timeval now; + struct timezone tz; + unsigned int microsecs; + + gettimeofday(&now, &tz); + microsecs = now.tv_usec + (timeout_val % 1000000); + if (microsecs > 1000000) { + now.tv_sec = now.tv_sec + timeout_val / 1000000 + 1; + now.tv_usec = microsecs - 1000000; + } else { + now.tv_sec = now.tv_sec + timeout_val / 1000000; + now.tv_usec = microsecs; + } + + /* Convert timeval to timespec */ + future.tv_sec = now.tv_sec; + future.tv_nsec = now.tv_usec * 1000; + + pthread_mutex_lock(&wait_obj->lock); + while (wait_obj->signaled == DAT_FALSE && pthread_status == 0) { + pthread_status = + pthread_cond_timedwait(&wait_obj->cv, + &wait_obj->lock, &future); + + /* + * No need to reset &future if we go around the loop; + * It's an absolute time. + */ + } + /* Reset the signaled status if we were woken up. */ + if (pthread_status == 0) { + wait_obj->signaled = false; + } + pthread_mutex_unlock(&wait_obj->lock); + } else { + pthread_mutex_lock(&wait_obj->lock); + while (wait_obj->signaled == DAT_FALSE && pthread_status == 0) { + pthread_status = + pthread_cond_wait(&wait_obj->cv, &wait_obj->lock); + } + /* Reset the signaled status if we were woken up. */ + if (pthread_status == 0) { + wait_obj->signaled = false; + } + pthread_mutex_unlock(&wait_obj->lock); + } + + if (ETIMEDOUT == pthread_status) { + return (-1); + } else if (0 != pthread_status) { + return (-1); + } + + return 0; +} + +/* + * DT_Mdep_wait_object_wakeup + * + * Wakeup a thread waiting on a wait object + * + * Input: + * wait_obj + * + * Returns: + * 0 if successful + * -1 if not successful + */ +int DT_Mdep_wait_object_wakeup(DT_WAIT_OBJECT * wait_obj) +{ + pthread_mutex_lock(&wait_obj->lock); + wait_obj->signaled = true; + pthread_mutex_unlock(&wait_obj->lock); + if (0 != pthread_cond_signal(&wait_obj->cv)) { + return (-1); + } + + return 0; +} + +/* + * DT_Mdep_wait_object_destroy + * + * Destroy a wait object + * + * Input: + * wait_obj + * + * Returns: + * 0 if successful + * -1 if not successful + */ +int DT_Mdep_wait_object_destroy(IN DT_WAIT_OBJECT * wait_obj) +{ + if (0 != pthread_cond_destroy(&wait_obj->cv)) { + return (-1); + } + if (0 != pthread_mutex_destroy(&wait_obj->lock)) { + return (-1); + } + + return 0; +} diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/mdep/linux/dapl_mdep_user.h b/branches/WOF2-3/ulp/dapl2/test/dapltest/mdep/linux/dapl_mdep_user.h new file mode 100644 index 00000000..772f2dd2 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/mdep/linux/dapl_mdep_user.h @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#ifndef __DAPL_MDEP_USER_H__ +#define __DAPL_MDEP_USER_H__ + +/* include files */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* inet_ntoa */ +#include +#include +#include + +/* Default Device Name */ +#define DT_MdepDeviceName "ofa-v2-ib0" + +/* Boolean */ +typedef int bool; + +#define true (1) +#define false (0) + +#ifndef __BASE_FILE__ +#define __BASE_FILE__ __FILE__ +#endif + +#ifndef _INLINE_ +#define _INLINE_ __inline__ +#endif + +/* + * Locks + */ + +typedef pthread_mutex_t DT_Mdep_LockType; + +/* Wait object used for inter thread communication */ + +typedef struct +{ + bool signaled; + pthread_cond_t cv; + pthread_mutex_t lock; +} DT_WAIT_OBJECT; + +/* + * Thread types + */ +typedef pthread_t DT_Mdep_ThreadHandleType; +typedef void (*DT_Mdep_ThreadFunction) (void *param); +typedef void * DT_Mdep_Thread_Start_Routine_Return_Type; +#define DT_MDEP_DEFAULT_STACK_SIZE 65536 + +typedef struct +{ + void (*function) (void *); + void *param; + DT_Mdep_ThreadHandleType thread_handle; + unsigned int stacksize; + pthread_attr_t attr; /* Thread attributes */ +} Thread; + +/* + * System information + * + */ + +typedef struct +{ + unsigned long int system; + unsigned long int user; + unsigned long int idle; +} DT_CpuStat; + +/* + * Timing + */ +#ifdef RDTSC_TIMERS +typedef unsigned long long int DT_Mdep_TimeStamp; + +static _INLINE_ DT_Mdep_TimeStamp +DT_Mdep_GetTimeStamp ( void ) +{ +#if defined(__GNUC__) && defined(__i386__) + DT_Mdep_TimeStamp x; + __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x)); + return x; +#else +#ifdef __ia64__ + unsigned long ret; + __asm__ __volatile__ ("mov %0=ar.itc" : "=r"(ret)); + return ret; +#else +#if defined(__PPC__) || defined(__PPC64__) + unsigned int tbl, tbu0, tbu1; + do { + __asm__ __volatile__ ("mftbu %0" : "=r"(tbu0)); + __asm__ __volatile__ ("mftb %0" : "=r"(tbl)); + __asm__ __volatile__ ("mftbu %0" : "=r"(tbu1)); + } while (tbu0 != tbu1); + return (((unsigned long long)tbu0) << 32) | tbl; +#else +#if defined(__x86_64__) + unsigned int __a,__d; + asm volatile("rdtsc" : "=a" (__a), "=d" (__d)); + return ((unsigned long)__a) | (((unsigned long)__d)<<32); +#else +#error "Linux CPU architecture - unimplemented" +#endif +#endif +#endif +#endif +} +#else /* !RDTSC_TIMERS */ +/* + * Get timestamp, microseconds, (relative to some fixed point) + */ +typedef double DT_Mdep_TimeStamp; + +static _INLINE_ DT_Mdep_TimeStamp +DT_Mdep_GetTimeStamp ( void ) +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return (tv.tv_sec * 1000000 + tv.tv_usec); +} +#endif + + +/* + * Define long format types to be used in *printf format strings. We + * use the C string constant concatenation ability to define 64 bit + * formats, which unfortunatly are non standard in the C compiler + * world. E.g. %llx for gcc, %I64x for Windows + */ + +#if defined(__x86_64__) || defined(__ia64__) +#define F64d "%ld" +#define F64u "%lu" +#define F64x "%lx" +#define F64X "%lX" +#else +#define F64d "%lld" +#define F64u "%llu" +#define F64x "%llx" +#define F64X "%llX" +#endif +/* + * Define notion of a LONG LONG 0 + */ +#define LZERO 0ULL + +/* Mdep function defines */ +#define DT_Mdep_Debug(N, _X_) \ +do { \ + if (DT_dapltest_debug >= (N)) \ + { \ + DT_Mdep_printf _X_; \ + } \ +} while (0) +#define DT_Mdep_printf printf + +#define DT_Mdep_flush() fflush(NULL) + +/* + * Release processor to reschedule + */ +#define DT_Mdep_yield pthread_yield + +#endif diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/mdep/solaris/dapl_mdep_user.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/mdep/solaris/dapl_mdep_user.c new file mode 100644 index 00000000..fc52861c --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/mdep/solaris/dapl_mdep_user.c @@ -0,0 +1,466 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_mdep.h" +#include "dapl_proto.h" + +#include +#include +#include +#include /* needed for getenv() */ +#include /* needed for pthread_atfork() */ +#include /* needed for thread setup */ + +#include "dapl_test_data.h" /* for alloc_count */ + + +/* + * Machine dependant initialization + */ + +void +DT_Mdep_Init (void) +{ + /* nothing */ +} + +/* + * Machine dependant deinitialization + */ + +void +DT_Mdep_End (void) +{ + /* nothing */ +} + +/* + * Generate name of IB device + */ + +bool +DT_Mdep_GetDefaultDeviceName (char *dapl_name) +{ + strcpy (dapl_name, DT_MdepDeviceName); + return true; +} + +/* + * Sleep specified number of milliseconds + */ + +void +DT_Mdep_Sleep (int msec) +{ + struct timespec t; + t.tv_sec = msec / 1000; /* Whole seconds */ + t.tv_nsec = (msec % 1000) * 1000 * 1000; + nanosleep (&t, 0); +} + +void +DT_Mdep_Schedule (void) +{ + /* void */ +} +/* + * Get system statistics including uptime and idle time + */ + +bool +DT_Mdep_GetCpuStat ( + DT_CpuStat *cpu_stat ) +{ + /* FIXME not implemented */ + return true; +} + +/* + * Get current time in milliseconds (relative to some fixed point) + */ +unsigned long +DT_Mdep_GetTime (void) +{ + struct tms ts; + clock_t t = times (&ts); + return (unsigned long) ((DAT_UINT64) t * 1000 / CLK_TCK); +} + +double +DT_Mdep_GetCpuMhz ( + void ) +{ + #error "Undefined Platform" +} + + +unsigned long +DT_Mdep_GetContextSwitchNum (void ) +{ + #error "Undefined Platform" +} + +/* + * Memory allocate and free routines for control blocks (objects) - regular + * memory, always zeroed. + */ +void * +DT_Mdep_Malloc (size_t l_) +{ + void *rval; + + /* + * check memory leaking DT_Mdep_Lock(&Alloc_Count_Lock); alloc_count++; + * DT_Mdep_Unlock(&Alloc_Count_Lock); + */ + + rval = malloc (l_); + + if (rval) + { + memset (rval, 0, l_); + } + return ( rval ); +} + +void +DT_Mdep_Free (void *a_) +{ + /* + * check memory leaking DT_Mdep_Lock(&Alloc_Count_Lock); alloc_count--; + * DT_Mdep_Unlock(&Alloc_Count_Lock); + */ + + free (a_); +} + +/* + * Lock support + * + * Lock object constructor + */ +bool +DT_Mdep_LockInit (DT_Mdep_LockType * lock_ptr) +{ + return pthread_mutex_init (lock_ptr, 0) ? false : true; +} + +/* + * Lock object destructor + */ +void +DT_Mdep_LockDestroy (DT_Mdep_LockType * lock_ptr) +{ + pthread_mutex_destroy (lock_ptr); +} + +/* + * Lock + */ +void +DT_Mdep_Lock (DT_Mdep_LockType * lock_ptr) +{ + pthread_mutex_lock (lock_ptr); +} + +/* + * unlock + */ +void +DT_Mdep_Unlock (DT_Mdep_LockType * lock_ptr) +{ + pthread_mutex_unlock (lock_ptr); +} + +/* + * Init Thread Attributes + */ +void +DT_Mdep_Thread_Init_Attributes (Thread * thread_ptr) +{ + pthread_attr_init (&thread_ptr->attr); + pthread_attr_setstacksize (&thread_ptr->attr, thread_ptr->stacksize); + /* Create thread in detached state to free resources on termination; + * this precludes doing a pthread_join, but we don't do it + */ + pthread_attr_setdetachstate (&thread_ptr->attr, PTHREAD_CREATE_DETACHED); +} + +/* + * Destroy Thread Attributes + */ +void +DT_Mdep_Thread_Destroy_Attributes (Thread * thread_ptr) +{ + pthread_attr_destroy (&thread_ptr->attr); +} + +/* + * Start the thread + */ +bool +DT_Mdep_Thread_Start (Thread * thread_ptr) +{ + return pthread_create (&thread_ptr->thread_handle, + &thread_ptr->attr, + DT_Mdep_Thread_Start_Routine, + thread_ptr) == 0; +} + +/* + * Thread execution entry point function + */ +DT_Mdep_Thread_Start_Routine_Return_Type +DT_Mdep_Thread_Start_Routine (void *thread_handle) +{ + Thread *thread_ptr; + thread_ptr = (Thread *) thread_handle; + + thread_ptr->function (thread_ptr->param); + return 0; +} + +/* + * Thread detach routine. Allows the pthreads + * interface to clean up resources properly at + * thread's end. + */ +void DT_Mdep_Thread_Detach ( int thread_id ) /* AMM */ +{ + pthread_detach ( thread_id); +} + +/* + * Allows a thread to get its own ID so it + * can pass it to routines wanting to act + * upon themselves. + */ + +int DT_Mdep_Thread_SELF (void) /* AMM */ +{ + + return (pthread_self ()); +} + + +/* + * Allow a thread to exit and cleanup resources. + */ + +void DT_Mdep_Thread_EXIT ( void * thread_handle ) /* AMM */ +{ + pthread_exit ( thread_handle ); +} + +/* + * DT_Mdep_wait_object_init + * + * Initialize a wait object + * + * Input: + * wait_obj + * + * Returns: + * 0 if successful + * -1 if unsuccessful + */ +int +DT_Mdep_wait_object_init ( + IN DT_WAIT_OBJECT *wait_obj) +{ + + wait_obj->signaled = DAT_FALSE; + if ( 0 != pthread_cond_init ( &wait_obj->cv, NULL ) ) + { + return (-1); + } + + /* Always returns 0. */ + pthread_mutex_init ( &wait_obj->lock, NULL ); + return 0; +} + + +/* Wait on the supplied wait object, up to the specified time_out. + * A timeout of DAT_TIMEOUT_INFINITE will wait indefinitely. + * Timeout should be specified in micro seconds. + * + * Functional returns: + * 0 -- another thread invoked dapl_os_wait object_wakeup + * -1 -- someone else is already waiting in this wait + * object. + * only one waiter is allowed at a time. + * -1 -- another thread invoked dapl_os_wait_object_destroy + * -1 -- the specified time limit was reached. + */ + +int +DT_Mdep_wait_object_wait ( + IN DT_WAIT_OBJECT *wait_obj, + IN int timeout_val) +{ + + int dat_status; + int pthread_status; + struct timespec future; + + dat_status = 0; + pthread_status = 0; + + if ( timeout_val != DAT_TIMEOUT_INFINITE ) + { + struct timeval now; + struct timezone tz; + unsigned int microsecs; + + gettimeofday (&now, &tz); + microsecs = now.tv_usec + (timeout_val % 1000000); + if (microsecs > 1000000) + { + now.tv_sec = now.tv_sec + timeout_val / 1000000 + 1; + now.tv_usec = microsecs - 1000000; + } + else + { + now.tv_sec = now.tv_sec + timeout_val / 1000000; + now.tv_usec = microsecs; + } + + /* Convert timeval to timespec */ + future.tv_sec = now.tv_sec; + future.tv_nsec = now.tv_usec * 1000; + + pthread_mutex_lock (&wait_obj->lock); + while ( wait_obj->signaled == DAT_FALSE && pthread_status == 0) + { + pthread_status = pthread_cond_timedwait ( + &wait_obj->cv, &wait_obj->lock, &future ); + + /* + * No need to reset &future if we go around the loop; + * It's an absolute time. + */ + } + /* Reset the signaled status if we were woken up. */ + if (pthread_status == 0) + { + wait_obj->signaled = false; + } + pthread_mutex_unlock (&wait_obj->lock); + } + else + { + pthread_mutex_lock (&wait_obj->lock); + while ( wait_obj->signaled == DAT_FALSE && pthread_status == 0) + { + pthread_status = pthread_cond_wait ( + &wait_obj->cv, &wait_obj->lock ); + } + /* Reset the signaled status if we were woken up. */ + if (pthread_status == 0) + { + wait_obj->signaled = false; + } + pthread_mutex_unlock (&wait_obj->lock); + } + + if (ETIMEDOUT == pthread_status) + { + return (-1); + } + else if ( 0 != pthread_status) + { + return (-1); + } + + return 0; +} + + +/* + * DT_Mdep_wait_object_wakeup + * + * Wakeup a thread waiting on a wait object + * + * Input: + * wait_obj + * + * Returns: + * 0 if successful + * -1 if not successful + */ +int +DT_Mdep_wait_object_wakeup ( + DT_WAIT_OBJECT *wait_obj ) +{ + pthread_mutex_lock ( &wait_obj->lock ); + wait_obj->signaled = true; + pthread_mutex_unlock ( &wait_obj->lock ); + if ( 0 != pthread_cond_signal ( &wait_obj->cv ) ) + { + return (-1); + } + + return 0; + +} + + +/* + * DT_Mdep_wait_object_destroy + * + * Destroy a wait object + * + * Input: + * wait_obj + * + * Returns: + * 0 if successful + * -1 if not successful + */ +int +DT_Mdep_wait_object_destroy ( + IN DT_WAIT_OBJECT *wait_obj) +{ + + if ( 0 != pthread_cond_destroy ( &wait_obj->cv ) ) + { + return (-1); + } + if ( 0 != pthread_mutex_destroy ( &wait_obj->lock ) ) + { + return (-1); + } + + return 0; + + +} + diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/mdep/solaris/dapl_mdep_user.h b/branches/WOF2-3/ulp/dapl2/test/dapltest/mdep/solaris/dapl_mdep_user.h new file mode 100644 index 00000000..0ed3992f --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/mdep/solaris/dapl_mdep_user.h @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#ifndef __DAPL_MDEP_H__ +#define __DAPL_MDEP_H__ + +/* include files */ + +#include + +# include +# include +# include +# include +# include +# include + +/* Default Device Name */ +#define DT_MdepDeviceName "ia0a" + +/* Boolean */ +typedef int bool; + +#define true (1) +#define false (0) + +#ifndef __BASE_FILE__ +#define __BASE_FILE__ __FILE__ +#endif + +#ifndef _INLINE_ +#error "Must Define _INLINE_ +#endif + +/* Mdep function defines */ + +#define DT_Mdep_spew(N, _X_) \ +do { \ + if (DT_dapltest_debug >= (N)) \ + { \ + DT_Mdep_printf _X_; \ + } \ +} while (0) + +#define DT_Mdep_debug(_X_) DT_Mdep_spew(1, _X_) + +#define DT_Mdep_printf printf +#define DT_Mdep_flush() fflush(NULL) + +/* + * Release processor to reschedule + */ +#define DT_Mdep_yield pthread_yield + +/* + * Locks + */ + +typedef pthread_mutex_t DT_Mdep_LockType; + +/* Wait object used for inter thread communication */ + +typedef struct +{ + bool signaled; + pthread_cond_t cv; + pthread_mutex_t lock; +} DT_WAIT_OBJECT; + +/* + * Thread types + */ +typedef pthread_t DT_Mdep_ThreadHandleType; +typedef void (*DT_Mdep_ThreadFunction) (void *param); +typedef void * DT_Mdep_Thread_Start_Routine_Return_Type; +#define DT_MDEP_DEFAULT_STACK_SIZE 65536 + +typedef struct +{ + void (*function) (void *); + void *param; + DT_Mdep_ThreadHandleType thread_handle; + unsigned int stacksize; + pthread_attr_t attr; /* Thread attributes */ +} Thread; + +/* + * System information + * + */ + +typedef struct +{ + unsigned long int system; + unsigned long int user; + unsigned long int idle; +} DT_CpuStat; + +/* + * Timing + */ + +# error "Must Define DT_Mdep_TimeStamp" + +static _INLINE_ DT_Mdep_TimeStamp +DT_Mdep_GetTimeStamp ( void ) +{ +#error "Must implement DT_Mdep_TimeStamp" +} + +/* + * Define long format types to be used in *printf format strings. We + * use the C string constant concatenation ability to define 64 bit + * formats, which unfortunatly are non standard in the C compiler + * world. E.g. %llx for gcc, %I64x for Windows + */ + +#error "Must Define F64d" +#error "Must Define F64u" +#error "Must Define F64x" +#error "Must Define F64X" + +/* + * Define notion of a LONG LONG 0 + */ +#define LZERO 0 + +#endif diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/mdep/windows/dapl_mdep_user.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/mdep/windows/dapl_mdep_user.c new file mode 100644 index 00000000..afc12d37 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/mdep/windows/dapl_mdep_user.c @@ -0,0 +1,436 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_mdep.h" +#include "dapl_proto.h" + +#include + +#include "dapl_test_data.h" /* for alloc_count */ + +/* + * Machine dependant initialization + */ + +void +DT_Mdep_Init (void) +{ + /* Initialize winsic2 */ + /* + * Needs to be done in main(), it's too late here. + */ + // WORD wv = MAKEWORD (1, 1); + // WSADATA wsaData; + // WSAStartup (wv, &wsaData); +} + +/* + * Machine dependant deinitialization + */ + +void +DT_Mdep_End (void) +{ + WSACleanup (); +} + +/* + * Generate name of IB device + */ + +bool +DT_Mdep_GetDefaultDeviceName (char *dapl_name) +{ + strcpy (dapl_name, DT_MdepDeviceName); + return true; +} + +/* + * Sleep specified number of milliseconds + */ + +void +DT_Mdep_Sleep (int msec) +{ + Sleep (msec); +} + +/* + * Get system statistics including uptime and idle time + */ +void +DT_Mdep_Schedule (void) +{ + /* nothing here */ +} + +bool +DT_Mdep_GetCpuStat ( + DT_CpuStat *cpu_stat ) +{ + /* FIXME not implemented */ + return true; +} + +/* + * Get current time in milliseconds (relative to some fixed point) + */ +unsigned long +DT_Mdep_GetTime (void) +{ + return GetTickCount (); +} + +double +DT_Mdep_GetCpuMhz ( + void ) +{ + LONG retVal; + HKEY hKey; + DWORD cpuSpeed = 0; + DWORD dataSize = sizeof (DWORD); + + /* For windows need to query the registry to get the CPU + * Information...-SVSV */ + retVal = RegOpenKeyEx (HKEY_LOCAL_MACHINE, + TEXT ("Hardware\\Description\\System\\CentralProcessor\\0"), + 0, + KEY_QUERY_VALUE, + &hKey); + + if (retVal == ERROR_SUCCESS) + { + retVal = RegQueryValueEx (hKey, + TEXT ("~MHz"), NULL, NULL, + (LPBYTE)&cpuSpeed, &dataSize); + + } + + RegCloseKey (hKey); + + return cpuSpeed; +} + + +unsigned long +DT_Mdep_GetContextSwitchNum (void) +{ + return 0; +} + +/* + * Memory allocate and free routines for control blocks (objects) - regular + * memory, always zeroed. + */ +void * +DT_Mdep_Malloc (size_t l_) +{ + void *rval; + + /* + * check memory leaking DT_Mdep_Lock(&Alloc_Count_Lock); alloc_count++; + * DT_Mdep_Unlock(&Alloc_Count_Lock); + */ + + rval = malloc (l_); + + if (rval) + { + memset (rval, 0, l_); + } + return ( rval ); +} + +void +DT_Mdep_Free (void *a_) +{ + /* + * check memory leaking DT_Mdep_Lock(&Alloc_Count_Lock); alloc_count--; + * DT_Mdep_Unlock(&Alloc_Count_Lock); + */ + + free (a_); +} + +/* + * Lock support + * + * Lock object constructor + */ +bool +DT_Mdep_LockInit (DT_Mdep_LockType * lock_ptr) +{ + *lock_ptr = CreateMutex (0, FALSE, 0); + return *lock_ptr ? true : false; +} + +/* + * Lock object destructor + */ +void +DT_Mdep_LockDestroy (DT_Mdep_LockType * lock_ptr) +{ + CloseHandle (*lock_ptr); +} + +/* + * Lock + */ +void +DT_Mdep_Lock (DT_Mdep_LockType * lock_ptr) +{ + WaitForSingleObject (*lock_ptr, INFINITE); +} + +/* + * unlock + */ +void +DT_Mdep_Unlock (DT_Mdep_LockType * lock_ptr) +{ + ReleaseMutex (*lock_ptr); +} + +/* + * Init Thread Attributes + */ +void +DT_Mdep_Thread_Init_Attributes (Thread * thread_ptr) +{ + /* nothing */ +} + +/* + * Destroy Thread Attributes + */ +void +DT_Mdep_Thread_Destroy_Attributes (Thread * thread_ptr) +{ + /* nothing */ +} + +/* + * Start the thread + */ +bool +DT_Mdep_Thread_Start (Thread * thread_ptr) +{ + thread_ptr->thread_handle = + CreateThread (NULL, + 0, + (LPTHREAD_START_ROUTINE)DT_Mdep_Thread_Start_Routine, + thread_ptr, + 0, + NULL); + if (thread_ptr->thread_handle == NULL) + { + return false; + } + return true; +} + +/* + * Thread execution entry point function + */ +DT_Mdep_Thread_Start_Routine_Return_Type +DT_Mdep_Thread_Start_Routine (void *thread_handle) +{ + Thread *thread_ptr; + thread_ptr = (Thread *) thread_handle; + + thread_ptr->function (thread_ptr->param); +} + +/* + * Thread detach routine. Allows the pthreads + * interface to clean up resources properly at + * thread's end. + */ +void DT_Mdep_Thread_Detach (DT_Mdep_ThreadHandleType thread_id ) /* AMM */ +{ +} + +/* + * Allows a thread to get its own ID so it + * can pass it to routines wanting to act + * upon themselves. + */ + +DT_Mdep_ThreadHandleType DT_Mdep_Thread_SELF (void) /* AMM */ +{ + return 0; +} + + +/* + * Allow a thread to exit and cleanup resources. + */ + +void DT_Mdep_Thread_EXIT ( void * thread_handle ) /* AMM */ +{ + + /* nothing */ +} + +/* + * DT_Mdep_wait_object_init + * + * Initialize a wait object + * + * Input: + * wait_obj + * + * Returns: + * 0 if successful + * -1 if unsuccessful + */ +int +DT_Mdep_wait_object_init ( + IN DT_WAIT_OBJECT *wait_obj) +{ + + *wait_obj = CreateEvent (NULL, FALSE, FALSE, NULL); + + if ( *wait_obj == NULL ) + { + return -1; + } + + return 0; + + +} + + +/* Wait on the supplied wait object, up to the specified time_out. + * A timeout of DAT_TIMEOUT_INFINITE will wait indefinitely. + * Timeout should be specified in micro seconds. + * + * Functional returns: + * 0 -- another thread invoked dapl_os_wait object_wakeup + * -1 -- someone else is already waiting in this wait + * object. + * only one waiter is allowed at a time. + * -1 -- another thread invoked dapl_os_wait_object_destroy + * -1 -- the specified time limit was reached. + */ + +int +DT_Mdep_wait_object_wait ( + IN DT_WAIT_OBJECT *wait_obj, + IN int timeout_val) +{ + + DAT_RETURN status; + DWORD op_status; + + status = DAT_SUCCESS; + + if ( DAT_TIMEOUT_INFINITE == timeout_val ) + { + op_status = WaitForSingleObject (*wait_obj, INFINITE); + } + else + { + /* convert to milliseconds */ + op_status = WaitForSingleObject (*wait_obj, timeout_val/1000); + } + + if (op_status == WAIT_TIMEOUT) + { + status = DAT_CLASS_ERROR | DAT_TIMEOUT_EXPIRED; + } + else if ( op_status == WAIT_FAILED) + { + status = DAT_CLASS_ERROR | DAT_INTERNAL_ERROR; + } + + return status; +} + + +/* + * DT_Mdep_wait_object_wakeup + * + * Wakeup a thread waiting on a wait object + * + * Input: + * wait_obj + * + * Returns: + * 0 if successful + * -1 if not successful + */ +int +DT_Mdep_wait_object_wakeup ( + DT_WAIT_OBJECT *wait_obj ) +{ + DWORD op_status; + + op_status = SetEvent (*wait_obj); + if ( op_status == 0 ) + { + return DAT_CLASS_ERROR | DAT_INTERNAL_ERROR; + } + + return DAT_SUCCESS; +} + + +/* + * DT_Mdep_wait_object_destroy + * + * Destroy a wait object + * + * Input: + * wait_obj + * + * Returns: + * 0 if successful + * -1 if not successful + */ +int +DT_Mdep_wait_object_destroy ( + IN DT_WAIT_OBJECT *wait_obj) +{ + + DWORD op_status; + DAT_RETURN status = DAT_SUCCESS; + + op_status = CloseHandle (*wait_obj); + + if ( op_status == 0 ) + { + status = DAT_CLASS_ERROR | DAT_INTERNAL_ERROR; + } + + return status; +} + diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/mdep/windows/dapl_mdep_user.h b/branches/WOF2-3/ulp/dapl2/test/dapltest/mdep/windows/dapl_mdep_user.h new file mode 100644 index 00000000..d551dd03 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/mdep/windows/dapl_mdep_user.h @@ -0,0 +1,190 @@ + +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#ifndef __DAPL_MDEP_USER_H__ +#define __DAPL_MDEP_USER_H__ + +/* include files */ + +#include + +#ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif + +# include +# include +# include +# include +# include +# include + +/* Default Device Name */ +#define DT_MdepDeviceName "ibnic0v2" + +/* Boolean */ +typedef int bool; + +#define true (1) +#define false (0) + +#ifndef __BASE_FILE__ +#define __BASE_FILE__ __FILE__ +#endif + +#ifndef _INLINE_ +#define _INLINE_ __inline +#endif + +/* Mdep function defines */ + +#define DT_Mdep_spew(N, _X_) \ +do { \ + if (DT_dapltest_debug >= (N)) \ + { \ + DT_Mdep_printf _X_; \ + } \ +} while (0) + +#define DT_Mdep_debug(_X_) DT_Mdep_spew(1, _X_) + +#define DT_Mdep_printf printf +#define DT_Mdep_flush() fflush(NULL) + +/* + * Release processor to reschedule + */ +#define DT_Mdep_yield() Sleep(0) + +/* + * Locks + */ + +typedef HANDLE DT_Mdep_LockType; +/* Wait object used for inter thread communication */ + +typedef HANDLE DT_WAIT_OBJECT; + +/* + * Thread types + */ +typedef HANDLE DT_Mdep_ThreadHandleType; +typedef void (*DT_Mdep_ThreadFunction) (void *param); +typedef void DT_Mdep_Thread_Start_Routine_Return_Type; + +#define DT_MDEP_DEFAULT_STACK_SIZE 65536 + +typedef struct +{ + void (*function) (void *); + void *param; + DT_Mdep_ThreadHandleType thread_handle; + unsigned int stacksize; +} Thread; + +/* + * System information + * + */ + +typedef struct +{ + unsigned long int system; + unsigned long int user; + unsigned long int idle; +} DT_CpuStat; + +/* + * Timing + */ +#if defined(_WIN64) && !defined(ReadTimeStampCounter) + +static _INLINE_ _ReadTimeStampCounter(void) +{ + LARGE_INTEGER val; + QueryPerformanceCounter( &val ); + return val.QuadPart; +} +#define ReadTimeStampCounter _ReadTimeStampCounter +#endif + +typedef unsigned __int64 DT_Mdep_TimeStamp; + +static _INLINE_ DT_Mdep_TimeStamp +DT_Mdep_GetTimeStamp ( void ) +{ +#if !defined (_WIN64) && !defined (IA64) + _asm rdtsc +#else + +#ifndef ReadTimeStampCounter + +#define ReadTimeStampCounter() __rdtsc() + + DWORD64 + __rdtsc (VOID); + +#endif + + return (DT_Mdep_TimeStamp) ReadTimeStampCounter(); + +#endif //endif !_WIN64, and !IA64 +} + +/* + * Define types for Window compatibility + */ + +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +typedef __int32 int32_t; +typedef unsigned __int32 uint32_t; + + +#define bzero(x, y) memset(x, 0, y) + +/* + * Define long format types to be used in *printf format strings. We + * use the C string constant concatenation ability to define 64 bit + * formats, which unfortunatly are non standard in the C compiler + * world. E.g. %llx for gcc, %I64x for Windows + */ +#define F64d "%I64d" +#define F64u "%I64u" +#define F64x "%I64x" +#define F64X "%I64X" + +/* + * Define notion of a LONG LONG 0 + */ +#define LZERO 0UL + +#endif /* __DAPL_MDEP_USER_H__ */ diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/scripts/cl.sh b/branches/WOF2-3/ulp/dapl2/test/dapltest/scripts/cl.sh new file mode 100644 index 00000000..9a8d64f6 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/scripts/cl.sh @@ -0,0 +1,58 @@ +#!/bin/sh +# +# Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. +# +# This Software is licensed under one of the following licenses: +# +# 1) under the terms of the "Common Public License 1.0" a copy of which is +# in the file LICENSE.txt in the root directory. The license is also +# available from the Open Source Initiative, see +# http://www.opensource.org/licenses/cpl.php. +# +# 2) under the terms of the "The BSD License" a copy of which is in the file +# LICENSE2.txt in the root directory. The license is also available from +# the Open Source Initiative, see +# http://www.opensource.org/licenses/bsd-license.php. +# +# 3) under the terms of the "GNU General Public License (GPL) Version 2" a +# copy of which is in the file LICENSE3.txt in the root directory. The +# license is also available from the Open Source Initiative, see +# http://www.opensource.org/licenses/gpl-license.php. +# +# Licensee has the right to choose one of the above licenses. +# +# Redistributions of source code must retain the above copyright +# notice and one of the license notices. +# +# Redistributions in binary form must reproduce both the above copyright +# notice, one of the license notices in the documentation +# and/or other materials provided with the distribution. +# +# Sample client invocation +# +# +me=`basename $0` +case $# in +0) host=dat-linux3 + device=0 ;; +1) host=$1 + device=0 ;; +2) host=$1 + device=$2 ;; +*) echo Usage: $me '[hostname [device] ]' 1>&2 ; exit 1;; +esac +# +# +# ./dapltest -T T -V -d -t 2 -w 2 -i 1000111 -s ${host} -D ${device} \ +# client RW 4096 1 server RW 2048 4 \ +# client RR 1024 2 server RR 2048 2 \ +# client SR 1024 3 -f server SR 256 3 -f + + ./dapltest -T T -P -d -t 2 -w 2 -i 1024 -s ${host} -D ${device} \ + client RW 4096 1 server RW 2048 4 \ + client RR 1024 2 server RR 2048 2 \ + client SR 1024 3 -f server SR 256 3 -f + +#dapltest -T T -d -s ${host} -D ${device} -i 10000 -t 1 -w 1 \ +# client SR 256 \ +# server SR 256 diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/scripts/dt-cli.bat b/branches/WOF2-3/ulp/dapl2/test/dapltest/scripts/dt-cli.bat new file mode 100644 index 00000000..441b9751 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/scripts/dt-cli.bat @@ -0,0 +1,367 @@ +@echo off +rem +rem Sample DAPLtest client Usage: dt-cli.bat provider hostname testname [-D] +rem + +SETLOCAL + +rem cmd.exe /V:on (delayed environment variable expansion) is required! +rem restart with /V:on if necessary +set F=on +set F=off +if not "!F!" == "off" ( + %comspec% /E:on /V:on /C %0 %1 %2 %3 %4 + if ERRORLEVEL 2 (exit /B %ERRORLEVEL%) else (exit /B 0) +) + +rem set DAT_OVERRIDE=D:\dapl2\dat.conf +rem favor DAT 2.0 (dapl2test.exe) over DAT 1.1 (dapltest.exe) + +set DT=dapl2test.exe +%DT% -h > Nul 2>&1 +if not "%ERRORLEVEL%" == "1" ( + echo %0: ERR - %DT% not in exec path? + exit /B %ERRORLEVEL% +) +rem To debug dapl2test - use dapl2testd.exe with ibnic0v2d + +rem setup DAPL provider name: translate shorthand name or use name from dat.conf. +rem if DAPL provider name is incorrect, DAPL will fail correctly. + +if "%1" == "" goto usage +if "%1" == "ibal" set D=ibnic0v2 +if "%1" == "ibal0" set D=ibnic0v2 +if "%1" == "ibal1" set D=ibnic1v2 +if "%1" == "scm" set D=ibnic0v2-scm +if "%1" == "cma" set D=ibnic0v2-cma +if "%D%" == "" set D=%1 + +rem DaplTest server hostname +if "%2" == "" goto usage +set S=%2 + +rem Which test ? +if "%3" == "" goto usage +set T=%3 + +set LPS=5 + +rem Enable DEBUG? + +if "%4" == "-D" (set X=0xffff) else set X= +if not "%X%" == "" ( + set DAT_OS_DBG_TYPE=%X% + set DAT_DBG_TYPE=%X% + set DAT_DBG_LEVEL=%X% + set DAPL_DBG_LEVEL=%X% + set DAPL_DBG_TYPE=%X% +) else ( +rem set DAT_DBG_TYPE=0x1 +rem set DAT_DBG_LEVEL=1 +) + +if "%4" == "-Q" ( set QUIET=1 ) else ( set QUIET=0 ) + +rem %DT% -T T -V -t 2 -w 2 -i 1000111 -s %S% -D %D% +rem client RW 4096 1 server RW 2048 4 +rem client RR 1024 2 server RR 2048 2 +rem client SR 1024 3 -f server SR 256 3 -f + +rem %DT% -T T -P -t 1 -w 1 -i 1024 -s %S% -D %D% +rem client RW 4096 1 server RW 2048 4 +rem server RR 1024 2 client RR 2048 2 +rem client SR 1024 3 -f server SR 256 3 -f + +if "%T%" == "bench" ( + echo %T%: Threads[1] Endpoints[1] transactions[RW, RR, SR], 64K iterations + set STIME=!DATE! !TIME! + %DT% -T T -P -t 1 -w 1 -i 65536 -s %S% -D %D% client RW 4096 4 server RW 2048 4 server RR 4096 2 client RR 4096 2 client SR 1024 2 -f server SR 1024 2 -f + set ETIME=!DATE! !TIME! + goto xit +) + +if "%T%" == "conn" ( + rem Connectivity test - client sends one buffer with one 4KB segments, one time. + rem add '-d' for debug output. + echo Simple Connectivity test + set CMD=%DT% -T T -s %S% -D %D% -i 1 -t 1 -w 1 client SR 4096 server SR 4096 + goto xcmd +) + +if "%T%" == "trans" ( + echo %T%: Transaction test - 8192 iterations, 1 thread, SR 4KB buffers + set CMD=%DT% -T T -s %S% -D %D% -i 8192 -t 1 -w 1 client SR 4096 server SR 4096 + goto xcmd +) + +if "%T%" == "transm" ( + echo %T%: Multiple RW, RR, SR transactions, 4096 iterations + set CMD=%DT% -T T -P -t 1 -w 1 -i 4096 -s %S% -D %D% client RW 4096 1 server RW 2048 4 server RR 1024 2 client RR 2048 2 client SR 1024 3 -f server SR 256 3 -f + goto xcmd +) + +if "%T%" == "transt" ( + echo %T%: Threads[4] Transaction test - 4096 iterations, 1 thread, SR 4KB buffers + set CMD=%DT% -T T -s %S% -D %D% -i 4096 -t 4 -w 1 client SR 8192 3 server SR 8192 3 + goto xcmd +) + +if "%T%" == "transme" ( + echo %T%: 1 Thread Endpoints[4] transactions [RW, RR, SR], 4096 iterations + set CMD=%DT% -T T -P -t 1 -w 4 -i 4096 -s %S% -D %D% client RW 4096 1 server RW 2048 4 server RR 1024 2 client RR 2048 2 client SR 1024 3 -f server SR 256 3 -f + goto xcmd +) + +if "%T%" == "transmet" ( + echo %T%: Threads[2] Endpoints[4] transactions[RW, RR, SR], 4096 iterations + set CMD=%DT% -T T -P -t 2 -w 4 -i 4096 -s %S% -D %D% client RW 4096 1 server RW 2048 4 server RR 1024 2 client RR 2048 2 client SR 1024 3 -f server SR 256 3 -f + goto xcmd +) + +if "%T%" == "transmete" ( + echo %T%: Threads[4] Endpoints[4] transactions[RW, RR, SR], 8192 iterations + set CMD=%DT% -T T -P -t 2 -w 4 -i 8192 -s %S% -D %D% client RW 4096 1 server RW 2048 4 server RR 1024 2 client RR 2048 2 client SR 1024 3 -f server SR 256 3 -f + goto xcmd +) + +if "%T%" == "EPA" ( + set STIME=!DATE! !TIME! + FOR /L %%j IN (2,1,5) DO ( + FOR /L %%i IN (1,1,5) DO ( + echo %T%: Multi: Threads[%%j] Endpoints[%%i] Send/Recv test - 4096 iterations, 3 8K segs + %DT% -T T -s %S% -D %D% -i 4096 -t %%j -w %%i client SR 8192 3 server SR 8192 3 + if ERRORLEVEL 1 exit /B %ERRORLEVEL% + echo %T%: Multi: Threads[%%j] Endpoints[%%i] Send/Recv test - 4096 iterations, 3 8K segs + timeout /T 3 + ) + ) + set ETIME=!DATE! !TIME! + goto xit +) + +if "%T%" == "EP" ( + set TH=4 + set EP=3 + echo %T%: Multi: Threads[!TH!] endpoints[!EP!] Send/Recv test - 4096 iterations, 3 8K segs + set CMD=%DT% -T T -s %S% -D %D% -i 4096 -t !TH! -w !EP! client SR 8192 3 server SR 8192 3 + goto xcmd +) + +if "%T%" == "threads" ( + echo %T%: Multi Threaded[6] Send/Recv test - 4096 iterations, 3 8K segs + set CMD=%DT% -T T -s %S% -D %D% -i 4096 -t 6 -w 1 client SR 8192 3 server SR 8192 3 + goto xcmd +) + +if "%T%" == "threadsm" ( + set TH=5 + set EP=3 + echo %T%: Multi: Threads[!TH!] endpoints[!EP!] Send/Recv test - 4096 iterations, 3 8K segs + set CMD=%DT% -T T -s %S% -D %D% -i 4096 -t !TH! -w !EP! client SR 8192 3 server SR 8192 3 + goto xcmd +) + +if "%T%" == "perf" ( + rem echo Performance test + set CMD=%DT% -T P %DBG% -s %S% -D %D% -i 2048 RW 4096 2 + goto xcmd +) + +if "%T%" == "rdma-read" ( + echo %T% 4 32K segs + set CMD=%DT% -T P -s %S% -D %D% -i 4096 RR 32768 4 + goto xcmd +) + +if "%T%" == "rdma-write" ( + echo %T% 4 32K segs + set CMD=%DT% -T P -s %S% -D %D% -i 4096 RW 32768 4 + goto xcmd +) + +if "%T%" == "bw" ( + echo bandwidth 4096 iterations of 2 65K mesgs + set CMD=%DT% -T P -s %S% -D %D% -i 4096 -p 16 -m p RW 65536 2 + goto xcmd +) + +if "%T%" == "latb" ( + echo latency test - block for completion events + set CMD=%DT% -T P -s %S% -D %D% -i 8192 -p 1 -m b RW 4 1 + goto xcmd +) + +if "%T%" == "latp" ( + echo latency test - poll completion events + set CMD=%DT% -T P -s %S% -D %D% -i 8192 -p 1 -m p RW 4 1 + goto xcmd +) + +if "%T%" == "lim" ( + echo Resource limit tests + set STIME=!DATE! !TIME! + %DT% -T L -D %D% -w 8 -m 100 limit_ia + %DT% -T L -D %D% -w 8 -m 100 limit_pz + %DT% -T L -D %D% -w 8 -m 100 limit_evd + %DT% -T L -D %D% -w 8 -m 100 limit_ep + %DT% -T L -D %D% -w 8 -m 100 limit_psp + %DT% -T L -D %D% -w 8 -m 100 limit_lmr + %DT% -T L -D %D% -w 8 -m 15 limit_rpost + set ETIME=!DATE! !TIME! + goto xit +) + +if "%T%" == "regression" ( + rem run dapl regression tests - usage: dt-cli provider svr-IPaddr regression {loopCnt} + if "%X%" == "" ( + if not "%4" == "" set LPS=%4 + ) else ( + if not "%5" == "" set LPS=%5 + ) + echo %T% testing in !LPS! Loops + REM rdma-write, read, perf + set RT=trans perf threads threadsm transm transt transme transmet transmete rdma-write rdma-read bw EP + set STIME=!DATE! !TIME! + FOR /L %%i IN (1,1,!LPS!) DO ( + for %%r in ( !RT! ) do ( + echo loop %%i - start test %%r + call %0 %1 %2 %%r + if !ERRORLEVEL! GTR 1 ( + echo Error !ERRORLEVEL! in regression test %%r + exit /B !ERRORLEVEL! + ) + echo loop %%i - Completed test %%r + if not "%%r" == "EP" timeout /T 3 + ) + echo + + echo Finished %T% loop %%i of !LPS! + if %%i LSS !LPS! timeout /T 8 + ) + set ETIME=!DATE! !TIME! + goto xit +) + +if "%T%" == "interop" ( + REM test units from Nov-'07 OFA interop event. usage dt-cli server-IPaddr interop {LoopCount} + if "%X%" == "" ( + if not "%4" == "" set LPS=%4 + ) else ( + if not "%5" == "" set LPS=%5 + ) + echo %T% testing in !LPS! Loops + REM test units from Nov-'07 OFA interop event + set STIME=!DATE! !TIME! + FOR /L %%i IN (1,1,!LPS!) DO ( + echo %DT% -T T -s %S% -D %D% -i 4096 -t 1 -w 1 -R BE client SR 256 1 server SR 256 1 + %DT% -T T -s %S% -D %D% -i 4096 -t 1 -w 1 -R BE client SR 256 1 server SR 256 1 + if ERRORLEVEL 1 exit /B %ERRORLEVEL% + timeout /T 3 + echo %DT% -T T -s %S% -D %D% -i 100 -t 1 -w 1 -V -P -R BE client SR 1024 3 -f server SR 1536 2 -f + %DT% -T T -s %S% -D %D% -i 100 -t 1 -w 1 -V -P -R BE client SR 1024 3 -f server SR 1536 2 -f + if ERRORLEVEL 1 exit /B %ERRORLEVEL% + timeout /T 3 + echo %DT% -T T -s %S% -D %D% -i 100 -t 1 -w 1 -V -P -R BE client SR 1024 1 server SR 1024 1 + %DT% -T T -s %S% -D %D% -i 100 -t 1 -w 1 -V -P -R BE client SR 1024 1 server SR 1024 1 + if ERRORLEVEL 1 exit /B %ERRORLEVEL% + timeout /T 3 + echo %DT% -T T -s %S% -D %D% -i 100 -t 1 -w 10 -V -P -R BE client SR 1024 3 server SR 1536 2 + %DT% -T T -s %S% -D %D% -i 100 -t 1 -w 10 -V -P -R BE client SR 1024 3 server SR 1536 2 + if ERRORLEVEL 1 exit /B %ERRORLEVEL% + timeout /T 3 + echo %DT% -T T -s %S% -D %D% -i 100 -t 1 -w 1 -V -P -R BE client SR 256 1 server RW 4096 1 server SR 256 1 + %DT% -T T -s %S% -D %D% -i 100 -t 1 -w 1 -V -P -R BE client SR 256 1 server RW 4096 1 server SR 256 1 + if ERRORLEVEL 1 exit /B %ERRORLEVEL% + timeout /T 3 + echo %DT% -T T -s %S% -D %D% -i 100 -t 1 -w 1 -V -P -R BE client SR 256 1 server RR 4096 1 server SR 256 1 + %DT% -T T -s %S% -D %D% -i 100 -t 1 -w 1 -V -P -R BE client SR 256 1 server RR 4096 1 server SR 256 1 + if ERRORLEVEL 1 exit /B %ERRORLEVEL% + timeout /T 3 + echo %DT% -T T -s %S% -D %D% -i 100 -t 4 -w 8 -V -P -R BE client SR 256 1 server RR 4096 1 server SR 256 1 client SR 256 1 server RR 4096 1 server SR 256 1 + %DT% -T T -s %S% -D %D% -i 100 -t 4 -w 8 -V -P -R BE client SR 256 1 server RR 4096 1 server SR 256 1 client SR 256 1 server RR 4096 1 server SR 256 1 + if ERRORLEVEL 1 exit /B %ERRORLEVEL% + timeout /T 3 + echo %DT% -T P -s %S% -D %D% -i 1024 -p 64 -m p RW 8192 2 + %DT% -T P -s %S% -D %D% -i 1024 -p 64 -m p RW 8192 2 + if ERRORLEVEL 1 exit /B %ERRORLEVEL% + timeout /T 3 + echo %DT% -T P -s %S% -D %D% -i 1024 -p 64 -m p RW 4096 2 + %DT% -T P -s %S% -D %D% -i 1024 -p 64 -m p RW 4096 2 + if ERRORLEVEL 1 exit /B %ERRORLEVEL% + timeout /T 3 + echo %DT% -T P -s %S% -D %D% -i 1024 -p 64 -m p RW 4096 1 + %DT% -T P -s %S% -D %D% -i 1024 -p 64 -m p RW 4096 1 + if ERRORLEVEL 1 exit /B %ERRORLEVEL% + timeout /T 3 + echo %DT% -T T -s %S% -D %D% -i 100 -t 1 -w 10 -V -P -R BE client SR 1024 3 server SR 1536 2 + %DT% -T T -s %S% -D %D% -i 100 -t 1 -w 10 -V -P -R BE client SR 1024 3 server SR 1536 2 + if ERRORLEVEL 1 exit /B %ERRORLEVEL% + echo %%i %T% loops of !LPS! completed. + if %%i LSS !LPS! timeout /T 8 + ) + set ETIME=!DATE! !TIME! + goto xit +) + +if "%T%" == "stop" ( + %DT% -T Q -s %S% -D %D% + goto rxt +) + +:usage + +echo. +echo usage: dt-cli dapl-provider dt-svr-hostname [testname [-D]] +echo. +echo where: +echo. +echo dapl-provider: ibal, scm, cma or %SystemDrive%\DAT\dat.conf DAPL-provider name. +echo. +echo dt-svr-hostname - IPv4 hostanme where the DaplTest server is running +echo. +echo testname +echo stop - request DAPLtest server to exit. +echo conn - simple connection test with limited data transfer +echo EP - Multiple EndPoints(7) and Threads(5) Transactions +echo EPA - Increment EndPoints[1..5] while increasing threads[1-5] +echo trans - single transaction test +echo transm - transaction test: multiple transactions [RW SND, RDMA] +echo transt - transaction test: multi-threaded +echo transme - transaction test: multi-endpoints per thread +echo transmet - transaction test: multi-endpoints per thread, multiple threads +echo transmete - transaction test: multi threads == endpoints +echo perf - Performance test +echo threads - multi-threaded single transaction test. +echo threadsm - multi: threads and endpoints, single transaction test. +echo rdma-write - RDMA write +echo rdma-read - RDMA read +echo bw - bandwidth +echo latb - latency tests, blocking for events +echo latp - latency tests, polling for events +echo lim - limit tests. +echo regression {loopCnt,default=%LPS%} - regression + stress. +echo interop {loopCnt,default=%LPS%} - 2007 OFA interoperability event tests. +goto rxt + +rem Execute the single daplest Command (CMD), observe -Q switch +:xcmd + set STIME=!DATE! !TIME! + if %QUIET% EQU 1 ( + %CMD% > nul + ) else ( + %CMD% + ) + set ETIME=!DATE! !TIME! + + rem fall thru... + +:xit + +if !ERRORLEVEL! EQU 0 ( + echo. + echo %0 %* + echo Start %STIME% + echo End %ETIME% +) +:rxt +ENDLOCAL +exit /B !ERRORLEVEL! diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/scripts/dt-svr.bat b/branches/WOF2-3/ulp/dapl2/test/dapltest/scripts/dt-svr.bat new file mode 100644 index 00000000..9974d235 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/scripts/dt-svr.bat @@ -0,0 +1,62 @@ +@echo off +rem +rem DAPLtest server - usage: dt-svr dapl-provider [ -D [dbg-bit-mask] ] +rem +SETLOCAL + +rem set DAT_OVERRIDE=C:\DAT\dat.conf +set DT=dapl2test.exe + +%DT% -h > Nul 2>&1 +if not "%ERRORLEVEL%" == "1" ( + echo %0: ERR - %DT% not in exec path? + exit /B %ERRORLEVEL% +) +rem To debug dapl2test - use dapl2testd.exe with ibnic0v2d + +rem which Dapl provider? + +if "%1" == "" ( + echo usage: dt-svr dapl-provider [ -D [dbg-bit-mask] ] + echo. + echo Where: dapl-provider can be [ ibal, scm, cma or %SystemDrive%\DAT\dat.conf provider name ] + exit /B 1 +) + +if "%1" == "ibal" set DEV=ibnic0v2 +if "%1" == "scm" set DEV=ibnic0v2-scm +if "%1" == "cma" set DEV=ibnic0v2-cma +if "%DEV%" == "" set DEV=%1 + +rem '-D' enables full debug output? +rem '-D hex-bit-mask' enables selective debug output - see manual.htm for details. +if "%2" == "-D" ( + if "%3" == "" ( + set X=0xfffff + ) else ( + set X=%3 + ) +) else ( set X= ) + +if not "%X%" == "" ( + set DAT_OS_DBG_TYPE=%X% + set DAT_DBG_LEVEL=%X% + set DAT_DBG_TYPE=%X% + set DAPL_DBG_TYPE=%X% + set DAPL_DBG_LEVEL=%X% +) else ( + set DAT_DBG_TYPE=1 +) + +rem start a dapltest server on the local node - server is waiting for +rem dapltest 'client' to issue dapltest commands (dt-cli.bat). +rem Client runs 'dt-cli provider IP-addr stop' to shutdown this dapltest server. + +echo %DT% -T S -d -D %DEV% + +%DT% -T S -D %DEV% + +echo %0 - %DT% [%DEV%] server exit... + +ENDLOCAL +exit /B %ERRORLEVEL% diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/scripts/kregress.sh b/branches/WOF2-3/ulp/dapl2/test/dapltest/scripts/kregress.sh new file mode 100644 index 00000000..8e5dfc99 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/scripts/kregress.sh @@ -0,0 +1,112 @@ +#!/bin/sh +# +# Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. +# +# This Software is licensed under one of the following licenses: +# +# 1) under the terms of the "Common Public License 1.0" a copy of which is +# in the file LICENSE.txt in the root directory. The license is also +# available from the Open Source Initiative, see +# http://www.opensource.org/licenses/cpl.php. +# +# 2) under the terms of the "The BSD License" a copy of which is in the file +# LICENSE2.txt in the root directory. The license is also available from +# the Open Source Initiative, see +# http://www.opensource.org/licenses/bsd-license.php. +# +# 3) under the terms of the "GNU General Public License (GPL) Version 2" a +# copy of which is in the file LICENSE3.txt in the root directory. The +# license is also available from the Open Source Initiative, see +# http://www.opensource.org/licenses/gpl-license.php. +# +# Licensee has the right to choose one of the above licenses. +# +# Redistributions of source code must retain the above copyright +# notice and one of the license notices. +# +# Redistributions in binary form must reproduce both the above copyright +# notice, one of the license notices in the documentation +# and/or other materials provided with the distribution. +# +# Sample regression client invocation +# + +me=`basename $0` +case $# in +0) host=dat-linux3 + device=0 ;; +1) host=$1 + device=0 ;; +2) host=$1 + device=$2 ;; +*) echo Usage: $me '[hostname [device] ]' 1>&2 ; exit 1;; +esac + + +#==================================================================== +#client1 +#==================================================================== +./kdapltest -T T -s ${host} -D ${device} -i 10000 -t 1 -w 1 \ + client SR 256 \ + server SR 256 + +#==================================================================== +#client2 +#==================================================================== +./kdapltest -T T -s ${host} -D ${device} -i 10000 -t 1 -w 1 \ + client SR 256 \ + server RW 4096 \ + server SR 256 + +#==================================================================== +#client3 +#==================================================================== +./kdapltest -T T -s ${host} -D ${device} -i 10000 -t 1 -w 1 \ + client SR 256 \ + server RR 4096 \ + server SR 256 + +#==================================================================== +#client4 +#==================================================================== +./kdapltest -T T -s ${host} -D ${device} -i 10000 -t 1 -w 1 \ + client SR 256 \ + server RW 4096 \ + server SR 256 \ + client SR 256 \ + server RW 4096 \ + server SR 256 \ + client SR 4096 \ + server SR 256 + +#==================================================================== +#client5 +#==================================================================== +#./kdapltest -T T -s ${host} -D ${device} -i 10000 -t 1 -w 8 \ +# client SR 256 \ +# server RW 4096 \ +# server SR 256 \ +# client SR 256 \ +# server RW 4096 \ +# server SR 256 \ +# client SR 4096 \ +# server SR 256 + +#==================================================================== +#client6 +#==================================================================== +#./kdapltest -T T -s ${host} -D ${device} -i 10000 -t 4 -w 8 \ +# client SR 256 \ +# server RW 4096 \ +# server SR 256 \ +# client SR 256 \ +# server RW 4096 \ +# server SR 256 \ +# client SR 4096 \ +# server SR 256 +# + +#==================================================================== +# Quit the server +#==================================================================== +./kdapltest -T Q -s ${host} -D ${device} diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/scripts/ksrv.sh b/branches/WOF2-3/ulp/dapl2/test/dapltest/scripts/ksrv.sh new file mode 100644 index 00000000..9727e6c4 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/scripts/ksrv.sh @@ -0,0 +1,43 @@ +#!/bin/sh +# +# Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. +# +# This Software is licensed under one of the following licenses: +# +# 1) under the terms of the "Common Public License 1.0" a copy of which is +# in the file LICENSE.txt in the root directory. The license is also +# available from the Open Source Initiative, see +# http://www.opensource.org/licenses/cpl.php. +# +# 2) under the terms of the "The BSD License" a copy of which is in the file +# LICENSE2.txt in the root directory. The license is also available from +# the Open Source Initiative, see +# http://www.opensource.org/licenses/bsd-license.php. +# +# 3) under the terms of the "GNU General Public License (GPL) Version 2" a +# copy of which is in the file LICENSE3.txt in the root directory. The +# license is also available from the Open Source Initiative, see +# http://www.opensource.org/licenses/gpl-license.php. +# +# Licensee has the right to choose one of the above licenses. +# +# Redistributions of source code must retain the above copyright +# notice and one of the license notices. +# +# Redistributions in binary form must reproduce both the above copyright +# notice, one of the license notices in the documentation +# and/or other materials provided with the distribution. +# +# Sample server invocation +# +me=`basename $0` +case $# in +0) device=0;; +1) device=$1 ;; +*) echo Usage: $me '[device]' 1>&2 ; exit 1;; +esac +# +# +# ./kdapltest -T S -d -D ${device} + + ./kdapltest -T S -D ${device} diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/scripts/lim.sh b/branches/WOF2-3/ulp/dapl2/test/dapltest/scripts/lim.sh new file mode 100644 index 00000000..09b938b6 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/scripts/lim.sh @@ -0,0 +1,44 @@ +#!/bin/sh +# +# Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. +# +# This Software is licensed under one of the following licenses: +# +# 1) under the terms of the "Common Public License 1.0" a copy of which is +# in the file LICENSE.txt in the root directory. The license is also +# available from the Open Source Initiative, see +# http://www.opensource.org/licenses/cpl.php. +# +# 2) under the terms of the "The BSD License" a copy of which is in the file +# LICENSE2.txt in the root directory. The license is also available from +# the Open Source Initiative, see +# http://www.opensource.org/licenses/bsd-license.php. +# +# 3) under the terms of the "GNU General Public License (GPL) Version 2" a +# copy of which is in the file LICENSE3.txt in the root directory. The +# license is also available from the Open Source Initiative, see +# http://www.opensource.org/licenses/gpl-license.php. +# +# Licensee has the right to choose one of the above licenses. +# +# Redistributions of source code must retain the above copyright +# notice and one of the license notices. +# +# Redistributions in binary form must reproduce both the above copyright +# notice, one of the license notices in the documentation +# and/or other materials provided with the distribution. + +me=`basename $0` + +case $# in +0) device=JniIbdd0 ;; +1) device=$1 ;; +*) echo Usage: $me '[device]' 1>&2 ; exit 1;; +esac + +# +# -d debug verbosity +# -w width sets up 'width' sets of IA,PZ,EVD,EP,LMR,RMR,... +# -m maximum provides a bound on exhaustion tests +# +./dapltest -T L -D ${device} -d -w 8 -m 137 diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/scripts/regress.sh b/branches/WOF2-3/ulp/dapl2/test/dapltest/scripts/regress.sh new file mode 100644 index 00000000..7659257f --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/scripts/regress.sh @@ -0,0 +1,112 @@ +#!/bin/sh +# +# Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. +# +# This Software is licensed under one of the following licenses: +# +# 1) under the terms of the "Common Public License 1.0" a copy of which is +# in the file LICENSE.txt in the root directory. The license is also +# available from the Open Source Initiative, see +# http://www.opensource.org/licenses/cpl.php. +# +# 2) under the terms of the "The BSD License" a copy of which is in the file +# LICENSE2.txt in the root directory. The license is also available from +# the Open Source Initiative, see +# http://www.opensource.org/licenses/bsd-license.php. +# +# 3) under the terms of the "GNU General Public License (GPL) Version 2" a +# copy of which is in the file LICENSE3.txt in the root directory. The +# license is also available from the Open Source Initiative, see +# http://www.opensource.org/licenses/gpl-license.php. +# +# Licensee has the right to choose one of the above licenses. +# +# Redistributions of source code must retain the above copyright +# notice and one of the license notices. +# +# Redistributions in binary form must reproduce both the above copyright +# notice, one of the license notices in the documentation +# and/or other materials provided with the distribution. +# +# Sample regression client invocation +# + +me=`basename $0` +case $# in +0) host=dat-linux3 + device=0 ;; +1) host=$1 + device=0 ;; +2) host=$1 + device=$2 ;; +*) echo Usage: $me '[hostname [device] ]' 1>&2 ; exit 1;; +esac + + +#==================================================================== +#client1 +#==================================================================== +./dapltest -T T -s ${host} -D ${device} -i 10000 -t 1 -w 1 \ + client SR 256 \ + server SR 256 + +#==================================================================== +#client2 +#==================================================================== +./dapltest -T T -s ${host} -D ${device} -i 10000 -t 1 -w 1 \ + client SR 256 \ + server RW 4096 \ + server SR 256 + +#==================================================================== +#client3 +#==================================================================== +./dapltest -T T -s ${host} -D ${device} -i 10000 -t 1 -w 1 \ + client SR 256 \ + server RR 4096 \ + server SR 256 + +#==================================================================== +#client4 +#==================================================================== +./dapltest -T T -s ${host} -D ${device} -i 10000 -t 1 -w 1 \ + client SR 256 \ + server RW 4096 \ + server SR 256 \ + client SR 256 \ + server RW 4096 \ + server SR 256 \ + client SR 4096 \ + server SR 256 + +#==================================================================== +#client5 +#==================================================================== +./dapltest -T T -s ${host} -D ${device} -i 10000 -t 1 -w 8 \ + client SR 256 \ + server RW 4096 \ + server SR 256 \ + client SR 256 \ + server RW 4096 \ + server SR 256 \ + client SR 4096 \ + server SR 256 + +#==================================================================== +#client6 +#==================================================================== +./dapltest -T T -s ${host} -D ${device} -i 10000 -t 4 -w 8 \ + client SR 256 \ + server RW 4096 \ + server SR 256 \ + client SR 256 \ + server RW 4096 \ + server SR 256 \ + client SR 4096 \ + server SR 256 + + +#==================================================================== +# Quit the server +#==================================================================== +./dapltest -T Q -s ${host} -D ${device} diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/scripts/srv.sh b/branches/WOF2-3/ulp/dapl2/test/dapltest/scripts/srv.sh new file mode 100644 index 00000000..78e8f631 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/scripts/srv.sh @@ -0,0 +1,43 @@ +#!/bin/sh +# +# Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. +# +# This Software is licensed under one of the following licenses: +# +# 1) under the terms of the "Common Public License 1.0" a copy of which is +# in the file LICENSE.txt in the root directory. The license is also +# available from the Open Source Initiative, see +# http://www.opensource.org/licenses/cpl.php. +# +# 2) under the terms of the "The BSD License" a copy of which is in the file +# LICENSE2.txt in the root directory. The license is also available from +# the Open Source Initiative, see +# http://www.opensource.org/licenses/bsd-license.php. +# +# 3) under the terms of the "GNU General Public License (GPL) Version 2" a +# copy of which is in the file LICENSE3.txt in the root directory. The +# license is also available from the Open Source Initiative, see +# http://www.opensource.org/licenses/gpl-license.php. +# +# Licensee has the right to choose one of the above licenses. +# +# Redistributions of source code must retain the above copyright +# notice and one of the license notices. +# +# Redistributions in binary form must reproduce both the above copyright +# notice, one of the license notices in the documentation +# and/or other materials provided with the distribution. +# +# Sample server invocation +# +me=`basename $0` +case $# in +0) device=0;; +1) device=$1 ;; +*) echo Usage: $me '[device]' 1>&2 ; exit 1;; +esac +# +# +# ./dapltest -T S -d -D ${device} + + ./dapltest -T S -D ${device} diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_bpool.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_bpool.c new file mode 100644 index 00000000..e06f2fc2 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_bpool.c @@ -0,0 +1,359 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" + +/* flag to prevent usage of Memory Windows as they are not supported in mthca */ +static DAT_BOOLEAN enable_memory_windows = DAT_FALSE; + +/*****************************************************************************/ +/* + * Allocate buffer pool (data buffers) + * + * Caller wants to allocate buffers of bytes, + * with each buffer aligned as requested. The caller is free to + * use the buffers separately, or as one contiguous segment, so + * we allocate IOV entries enough to support either usage. + */ +Bpool *DT_BpoolAlloc(Per_Test_Data_t * pt_ptr, + DT_Tdep_Print_Head * phead, + DAT_IA_HANDLE ia_handle, + DAT_PZ_HANDLE pz_handle, + DAT_EP_HANDLE ep_handle, + DAT_EVD_HANDLE rmr_evd_handle, + DAT_COUNT seg_size, + DAT_COUNT num_segs, + DAT_COUNT alignment, + DAT_BOOLEAN enable_rdma_write, + DAT_BOOLEAN enable_rdma_read) +{ + char *module = "DT_BpoolAlloc"; + unsigned char *alloc_ptr = 0; + Bpool *bpool_ptr = 0; + DAT_COUNT alloc_size; + DAT_REGION_DESCRIPTION region; + DAT_RETURN ret; + + /* We'll hand out aligned buffers, compensate here */ + seg_size = DT_RoundSize(seg_size, alignment); + alloc_size = seg_size * num_segs + alignment; + + alloc_ptr = (unsigned char *)DT_MemListAlloc(pt_ptr, "bpool", BUFF, + alloc_size); + if (!alloc_ptr) { + DT_Tdep_PT_Printf(phead, "No Memory to create bpool buffer!\n"); + goto err; + } + + bpool_ptr = + (Bpool *) DT_MemListAlloc(pt_ptr, "bpool", BPOOL, sizeof(Bpool) + + num_segs * sizeof(DAT_LMR_TRIPLET)); + if (!bpool_ptr) { + DT_Tdep_PT_Printf(phead, "No Memory to create Bpool!\n"); + goto err; + } + + bpool_ptr->alloc_ptr = alloc_ptr; + bpool_ptr->alloc_size = alloc_size; + bpool_ptr->pz_handle = pz_handle; + bpool_ptr->num_segs = num_segs; + bpool_ptr->ep_handle = ep_handle; + bpool_ptr->buffer_size = seg_size * num_segs; + bpool_ptr->buffer_start = DT_AlignPtr(alloc_ptr, alignment); + bpool_ptr->tripl_start = (DAT_LMR_TRIPLET *) (bpool_ptr + 1); + bpool_ptr->seg_size = seg_size; + bpool_ptr->enable_rdma_write = enable_rdma_write; + bpool_ptr->enable_rdma_read = enable_rdma_read; + bpool_ptr->rmr_evd_handle = rmr_evd_handle; + + DT_Tdep_PT_Debug(3, + (phead, + "lmr_create [%p, " F64x "]\n", + bpool_ptr->buffer_start, bpool_ptr->buffer_size)); + + memset(®ion, 0, sizeof(region)); + region.for_va = bpool_ptr->buffer_start; + ret = DT_Tdep_lmr_create(ia_handle, + DAT_MEM_TYPE_VIRTUAL, + region, + bpool_ptr->buffer_size, + pz_handle, + DAT_MEM_PRIV_ALL_FLAG, + &bpool_ptr->lmr_handle, + &bpool_ptr->lmr_context, + &bpool_ptr->rmr_context, + &bpool_ptr->reg_size, &bpool_ptr->reg_addr); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, "%s: dat_lmr_create failed %s\n", + module, DT_RetToString(ret)); + goto err; + } + /* verify that the outputs are reasonable */ + if (((uintptr_t) bpool_ptr->reg_addr > + (uintptr_t) bpool_ptr->buffer_start) + || (bpool_ptr->reg_size < + bpool_ptr->buffer_size + ((uintptr_t) bpool_ptr->buffer_start - + (uintptr_t) bpool_ptr->reg_addr))) { + DT_Tdep_PT_Printf(phead, + "%s: dat_lmr_create bogus" "in: 0x%p, " F64x + " out 0x" F64x ", " F64x "\n", module, + bpool_ptr->buffer_start, + bpool_ptr->buffer_size, bpool_ptr->reg_addr, + bpool_ptr->reg_size); + goto err; + } + + DT_Tdep_PT_Debug(3, (phead, + "lmr_create OK [0x" F64x ", " F64x ", lctx=%x]\n", + bpool_ptr->reg_addr, + bpool_ptr->reg_size, bpool_ptr->lmr_context)); + + /* Enable RDMA if requested */ + if (enable_memory_windows && (enable_rdma_write || enable_rdma_read)) { + DAT_LMR_TRIPLET iov; + DAT_RMR_COOKIE cookie; + DAT_MEM_PRIV_FLAGS mflags; + DAT_RMR_BIND_COMPLETION_EVENT_DATA rmr_stat; + + /* create the RMR */ + ret = dat_rmr_create(pz_handle, &bpool_ptr->rmr_handle); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_rmr_create failed %s\n", + module, DT_RetToString(ret)); + goto err; + } + + /* bind the RMR */ + iov.virtual_address = bpool_ptr->reg_addr; + iov.segment_length = bpool_ptr->reg_size; + iov.lmr_context = bpool_ptr->lmr_context; + cookie.as_64 = (DAT_UINT64) 0UL; + cookie.as_ptr = (DAT_PVOID) (uintptr_t) bpool_ptr->reg_addr; + mflags = (enable_rdma_write + && enable_rdma_read ? DAT_MEM_PRIV_ALL_FLAG + : (enable_rdma_write ? DAT_MEM_PRIV_WRITE_FLAG + : (enable_rdma_read ? DAT_MEM_PRIV_READ_FLAG : + 0))); + + DT_Tdep_PT_Debug(3, (phead, "rmr_bind [" F64x ", " F64x "]\n", + bpool_ptr->reg_addr, bpool_ptr->reg_size)); + + ret = dat_rmr_bind(bpool_ptr->rmr_handle, + bpool_ptr->lmr_handle, + &iov, + mflags, + DAT_VA_TYPE_VA, + bpool_ptr->ep_handle, + cookie, + DAT_COMPLETION_DEFAULT_FLAG, + &bpool_ptr->rmr_context); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, "%s: dat_rmr_bind failed %s\n", + module, DT_RetToString(ret)); + goto err; + } + + DT_Tdep_PT_Debug(3, (phead, "rmr_bind-wait\n")); + + /* await the bind result */ + if (!DT_rmr_event_wait(phead, + bpool_ptr->rmr_evd_handle, + &rmr_stat) || + !DT_rmr_check(phead, + &rmr_stat, + bpool_ptr->rmr_handle, + (DAT_PVOID) (uintptr_t) bpool_ptr->reg_addr, + "Bpool")) { + goto err; + } + + DT_Tdep_PT_Debug(3, + (phead, "rmr_bound [OK Rctx=%x]\n", + bpool_ptr->rmr_context)); + } + + /* + * Finally! Return the newly created Bpool. + */ + return (bpool_ptr); + + /* ********************************* + * Whoops - clean up and return NULL + */ + err: + if (bpool_ptr) { + if (bpool_ptr->rmr_handle) { + ret = dat_rmr_free(bpool_ptr->rmr_handle); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_rmr_free failed %s\n", + module, DT_RetToString(ret)); + } + } + if (bpool_ptr->lmr_handle) { + ret = dat_lmr_free(bpool_ptr->lmr_handle); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_lmr_free failed %s\n", + module, DT_RetToString(ret)); + } + } + DT_MemListFree(pt_ptr, bpool_ptr); + } + if (alloc_ptr) { + DT_MemListFree(pt_ptr, alloc_ptr); + } + + return (0); +} + +/*****************************************************************************/ +bool +DT_Bpool_Destroy(Per_Test_Data_t * pt_ptr, + DT_Tdep_Print_Head * phead, Bpool * bpool_ptr) +{ + char *module = "DT_Bpool_Destroy"; + bool rval = true; + + if (bpool_ptr) { + if (bpool_ptr->alloc_ptr) { + if (bpool_ptr->rmr_handle) { + DAT_LMR_TRIPLET iov; + DAT_RMR_COOKIE cookie; + DAT_RETURN ret; + + iov.virtual_address = bpool_ptr->reg_addr; + iov.segment_length = 0; /* un-bind */ + iov.lmr_context = bpool_ptr->lmr_context; + cookie.as_64 = (DAT_UINT64) 0UL; + cookie.as_ptr = + (DAT_PVOID) (uintptr_t) bpool_ptr->reg_addr; + + /* + * Do not attempt to unbind here. The remote node + * is going through the same logic and may disconnect + * before an unbind completes. Any bind/unbind + * operation requires a CONNECTED QP to complete, + * a disconnect will cause problems. Unbind is + * a simple optimization to allow rebinding of + * an RMR, doing an rmr_free will pull the plug + * and cleanup properly. + */ + ret = dat_rmr_free(bpool_ptr->rmr_handle); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_rmr_free failed %s\n", + module, + DT_RetToString(ret)); + rval = false; + } + } + + if (bpool_ptr->lmr_handle) { + DAT_RETURN ret = + dat_lmr_free(bpool_ptr->lmr_handle); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_lmr_free failed %s\n", + module, + DT_RetToString(ret)); + rval = false; + } + } + DT_MemListFree(pt_ptr, bpool_ptr->alloc_ptr); + } + DT_MemListFree(pt_ptr, bpool_ptr); + } + + return (rval); +} + +/*****************************************************************************/ +unsigned char *DT_Bpool_GetBuffer(Bpool * bpool_ptr, int index) +{ + return (bpool_ptr->buffer_start + index * bpool_ptr->seg_size); +} + +/*****************************************************************************/ +DAT_COUNT DT_Bpool_GetBuffSize(Bpool * bpool_ptr, int index) +{ + return (bpool_ptr->seg_size); +} + +/*****************************************************************************/ +DAT_LMR_TRIPLET *DT_Bpool_GetIOV(Bpool * bpool_ptr, int index) +{ + return (bpool_ptr->tripl_start + index); +} + +/*****************************************************************************/ +DAT_LMR_CONTEXT DT_Bpool_GetLMR(Bpool * bpool_ptr, int index) +{ + return (bpool_ptr->lmr_context); +} + +/*****************************************************************************/ +DAT_RMR_CONTEXT DT_Bpool_GetRMR(Bpool * bpool_ptr, int index) +{ + return (bpool_ptr->rmr_context); +} + +/*****************************************************************************/ +void DT_Bpool_print(DT_Tdep_Print_Head * phead, Bpool * bpool_ptr) +{ + DT_Tdep_PT_Printf(phead, "BPOOL %p\n", bpool_ptr); + DT_Tdep_PT_Printf(phead, + "BPOOL alloc_ptr %p\n", bpool_ptr->alloc_ptr); + DT_Tdep_PT_Printf(phead, + "BPOOL alloc_size %x\n", + (int)bpool_ptr->alloc_size); + DT_Tdep_PT_Printf(phead, + "BPOOL pz_handle %p\n", bpool_ptr->pz_handle); + DT_Tdep_PT_Printf(phead, + "BPOOL num_segs %x\n", + (int)bpool_ptr->num_segs); + DT_Tdep_PT_Printf(phead, + "BPOOL seg_size %x\n", + (int)bpool_ptr->seg_size); + DT_Tdep_PT_Printf(phead, + "BPOOL tripl_start %p\n", bpool_ptr->tripl_start); + DT_Tdep_PT_Printf(phead, + "BPOOL buffer_start %p\n", bpool_ptr->buffer_start); + DT_Tdep_PT_Printf(phead, + "BPOOL buffer_size %x\n", + (int)bpool_ptr->buffer_size); + DT_Tdep_PT_Printf(phead, + "BPOOL rdma_write %x\n", + (int)bpool_ptr->enable_rdma_write); + DT_Tdep_PT_Printf(phead, + "BPOOL rdmaread %x\n", + (int)bpool_ptr->enable_rdma_read); +} diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_client.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_client.c new file mode 100644 index 00000000..91ebd7dc --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_client.c @@ -0,0 +1,559 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" + +#if defined(DFLT_QLEN) +#undef DFLT_QLEN +#endif + +#define DFLT_QLEN 8 /* default event queue length */ +#define MAX_CONN_RETRY 8 + +/* + * Client control routine Connect to the server, send the command across. + * Then start the client-side of the test - creating threads as needed + */ +DAT_RETURN +DT_cs_Client(Params_t * params_ptr, + char *dapl_name, char *server_name, DAT_UINT32 total_threads) +{ + Per_Test_Data_t *pt_ptr = NULL; + DAT_IA_HANDLE ia_handle = DAT_HANDLE_NULL; + DAT_PZ_HANDLE pz_handle = DAT_HANDLE_NULL; + DAT_EVD_HANDLE recv_evd_hdl = DAT_HANDLE_NULL; + DAT_EVD_HANDLE reqt_evd_hdl = DAT_HANDLE_NULL; + DAT_EVD_HANDLE conn_evd_hdl = DAT_HANDLE_NULL; + DAT_EVD_HANDLE async_evd_hdl = DAT_HANDLE_NULL; + DAT_EP_HANDLE ep_handle = DAT_HANDLE_NULL; + Server_Info_t *sinfo = NULL; + Transaction_Cmd_t *Transaction_Cmd = NULL; + Quit_Cmd_t *Quit_Cmd = NULL; + Performance_Cmd_t *Performance_Cmd = NULL; + Bpool *bpool = NULL; + DAT_IA_ADDRESS_PTR server_netaddr = NULL; + char *module = "DT_cs_Client"; + unsigned int did_connect = 0; + unsigned int retry_cnt = 0; + DAT_DTO_COOKIE dto_cookie; + + DAT_DTO_COMPLETION_EVENT_DATA dto_stat; + DAT_EVENT_NUMBER event_num; + unsigned char *buffp; + DAT_RETURN ret, rc; + DT_Tdep_Print_Head *phead; + + phead = params_ptr->phead; + + dto_cookie.as_64 = LZERO; + + DT_Tdep_PT_Printf(phead, "%s: Starting Test ... \n", module); + DT_Mdep_Schedule(); + /* Set up the Per_Test_Data */ + pt_ptr = DT_Alloc_Per_Test_Data(phead); + if (!pt_ptr) { + DT_Tdep_PT_Printf(phead, "%s: no memory for Per_Test_Data\n", + module); + return DAT_INSUFFICIENT_RESOURCES; + } + DT_MemListInit(pt_ptr); /* init MemlistLock and memListHead */ + DT_Thread_Init(pt_ptr); /* init ThreadLock and threadcount */ + pt_ptr->local_is_server = false; + pt_ptr->Client_Info.dapltest_version = DAPLTEST_VERSION; + pt_ptr->Client_Info.is_little_endian = DT_local_is_little_endian; + pt_ptr->Client_Info.test_type = params_ptr->test_type; + pt_ptr->Client_Info.total_threads = total_threads; + memcpy((void *)(uintptr_t) & pt_ptr->Params, + (const void *)params_ptr, sizeof(Params_t)); + + /* Allocate and fill in the Server's address */ + server_netaddr = ¶ms_ptr->server_netaddr; + + /* Open the IA */ + ret = dat_ia_open(dapl_name, DFLT_QLEN, &async_evd_hdl, &ia_handle); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: Could not open %s (%s)\n", + module, dapl_name, DT_RetToString(ret)); + ia_handle = DAT_HANDLE_NULL; + goto client_exit; + } + DT_Tdep_PT_Debug(1, (phead, "%s: IA %s opened\n", module, dapl_name)); + + /* Create a PZ */ + ret = dat_pz_create(ia_handle, &pz_handle); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_pz_create error: %s\n", + module, DT_RetToString(ret)); + pz_handle = DAT_HANDLE_NULL; + goto client_exit; + } + + /* Create 3 events - recv, request, connect */ + + ret = DT_Tdep_evd_create(ia_handle, + DFLT_QLEN, + NULL, DAT_EVD_DTO_FLAG, &recv_evd_hdl); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_evd_create (recv) failed %s\n", + module, DT_RetToString(ret)); + recv_evd_hdl = DAT_HANDLE_NULL; + goto client_exit; + } + ret = DT_Tdep_evd_create(ia_handle, + DFLT_QLEN, + NULL, + DAT_EVD_DTO_FLAG | DAT_EVD_RMR_BIND_FLAG, + &reqt_evd_hdl); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_evd_create (send) failed %s\n", + module, DT_RetToString(ret)); + reqt_evd_hdl = DAT_HANDLE_NULL; + goto client_exit; + } + ret = DT_Tdep_evd_create(ia_handle, + DFLT_QLEN, + NULL, DAT_EVD_CONNECTION_FLAG, &conn_evd_hdl); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_evd_create (conn) failed %s\n", + module, DT_RetToString(ret)); + conn_evd_hdl = DAT_HANDLE_NULL; + goto client_exit; + } + + /* Create an EP */ + ret = dat_ep_create(ia_handle, /* IA */ + pz_handle, /* PZ */ + recv_evd_hdl, /* recv */ + reqt_evd_hdl, /* request */ + conn_evd_hdl, /* connect */ + (DAT_EP_ATTR *) NULL, &ep_handle); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_ep_create error: %s\n", + module, DT_RetToString(ret)); + ep_handle = DAT_HANDLE_NULL; + goto client_exit; + } + DT_Tdep_PT_Debug(1, (phead, "%s: EP created\n", module)); + + /* + * Gather whatever info we want about defaults, + * and check that we can handle the requested parameters. + */ + if (!DT_query(pt_ptr, ia_handle, ep_handle) || + !DT_check_params(pt_ptr, module)) { + ret = DAT_INSUFFICIENT_RESOURCES; + goto client_exit; + } + + bpool = DT_BpoolAlloc(pt_ptr, phead, ia_handle, pz_handle, ep_handle, DAT_HANDLE_NULL, /* no RMR */ + DT_RoundSize(sizeof(Transaction_Cmd_t), 8192), 3, /* num_buffers */ + DAT_OPTIMAL_ALIGNMENT, false, false); + if (bpool == 0) { + DT_Tdep_PT_Printf(phead, + "%s: no memory for command buffer pool.\n", + module); + ret = + DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); + goto client_exit; + } + + DT_Tdep_PT_Debug(3, (phead, + "RecvSrvInfo 0 %p\n", + (DAT_PVOID) DT_Bpool_GetBuffer(bpool, 0))); + DT_Tdep_PT_Debug(3, (phead, + "SndCliInfo 1 %p\n", + (DAT_PVOID) DT_Bpool_GetBuffer(bpool, 1))); + DT_Tdep_PT_Debug(3, (phead, + "SndCommand 2 %p\n", + (DAT_PVOID) DT_Bpool_GetBuffer(bpool, 2))); + + /* Post recv buffer for Server_Info (1st buffer in pool) */ + DT_Tdep_PT_Debug(1, (phead, "%s: Posting 1 recv buffer\n", module)); + retry_repost: + if (!DT_post_recv_buffer(phead, + ep_handle, + bpool, 0, DT_Bpool_GetBuffSize(bpool, 0))) { + DT_Tdep_PT_Printf(phead, + "%s: cannot post Server_Info recv buffer.\n", + module); + ret = DAT_INSUFFICIENT_RESOURCES; + goto client_exit; + } + + DT_Tdep_PT_Debug(1, (phead, "%s: Connect Endpoint\n", module)); + retry: + ret = dat_ep_connect(ep_handle, server_netaddr, SERVER_PORT_NUMBER, DAT_TIMEOUT_INFINITE, 0, (DAT_PVOID) 0, /* no private data */ + params_ptr->ReliabilityLevel, + DAT_CONNECT_DEFAULT_FLAG); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: Cannot connect Endpoint %s\n", + module, DT_RetToString(ret)); + goto client_exit; + } + + DT_Tdep_PT_Debug(1, (phead, "%s: Await connection ...\n", module)); + if (!DT_conn_event_wait(phead, ep_handle, conn_evd_hdl, &event_num)) { + if (event_num == DAT_CONNECTION_EVENT_PEER_REJECTED) { + DAT_EVENT event; + DAT_COUNT drained = 0; + + DT_Mdep_Sleep(1000); + DT_Tdep_PT_Printf(phead, + "%s: retrying connection...\n", + module); + retry_cnt++; + /* + * See if any buffers were flushed as a result of + * the REJECT; clean them up and repost if so + */ + dat_ep_reset(ep_handle); + do { + rc = DT_Tdep_evd_dequeue(recv_evd_hdl, &event); + drained++; + } while (DAT_GET_TYPE(rc) != DAT_QUEUE_EMPTY); + + if (drained > 1 && retry_cnt < MAX_CONN_RETRY) { + DT_Tdep_PT_Printf(phead, "Reposting!!! %d\n", + drained); + goto retry_repost; + } else if (retry_cnt < MAX_CONN_RETRY) { + goto retry; + } + } + ret = DAT_INSUFFICIENT_RESOURCES; + DT_Tdep_PT_Printf(phead, "%s: bad connection event\n", module); + goto client_exit; + } + + did_connect++; + if (DT_dapltest_debug) { + DT_Tdep_PT_Debug(1, (phead, "%s: Connected!\n", module)); + get_ep_connection_state(phead, ep_handle); + } +#ifdef CM_BUSTED + /***** XXX Chill out a bit to give the kludged CM a chance ... + *****/ DT_Mdep_Sleep(1000); +#endif + + /* Send Client_Info (using 2nd buffer in the pool) */ + DT_Tdep_PT_Debug(1, (phead, "%s: Sending Client_Info\n", module)); + buffp = DT_Bpool_GetBuffer(bpool, 1); + memcpy((void *)buffp, + (const void *)&pt_ptr->Client_Info, sizeof(Client_Info_t)); + DT_Client_Info_Endian((Client_Info_t *) buffp); + if (!DT_post_send_buffer(phead, + ep_handle, + bpool, 1, DT_Bpool_GetBuffSize(bpool, 1))) { + DT_Tdep_PT_Printf(phead, "%s: cannot send Client_Info\n", + module); + ret = DAT_INSUFFICIENT_RESOURCES; + goto client_exit; + } + /* reap the send and verify it */ + dto_cookie.as_ptr = + (DAT_PVOID) (uintptr_t) DT_Bpool_GetBuffer(bpool, 1); + DT_Tdep_PT_Debug(1, + (phead, "%s: Sent Client_Info - awaiting completion\n", + module)); + if (!DT_dto_event_wait(phead, reqt_evd_hdl, &dto_stat) + || !DT_dto_check(phead, &dto_stat, ep_handle, + DT_Bpool_GetBuffSize(bpool, 1), dto_cookie, + "Client_Info_Send")) { + ret = DAT_INSUFFICIENT_RESOURCES; + goto client_exit; + } + + /* Set up the Command (using 3rd buffer in pool) */ + DT_Tdep_PT_Debug(1, (phead, "%s: Sending Command\n", module)); + buffp = DT_Bpool_GetBuffer(bpool, 2); + switch (pt_ptr->Client_Info.test_type) { + case TRANSACTION_TEST: + { + Transaction_Cmd = &pt_ptr->Params.u.Transaction_Cmd; + memcpy((void *)buffp, + (const void *)Transaction_Cmd, + sizeof(Transaction_Cmd_t)); + DT_Transaction_Cmd_Endian((Transaction_Cmd_t *) buffp, + true); + break; + } + + case QUIT_TEST: + { + Quit_Cmd = &pt_ptr->Params.u.Quit_Cmd; + memcpy((void *)buffp, + (const void *)Quit_Cmd, sizeof(Quit_Cmd_t)); + DT_Quit_Cmd_Endian((Quit_Cmd_t *) buffp, true); + break; + } + + case PERFORMANCE_TEST: + { + Performance_Cmd = &pt_ptr->Params.u.Performance_Cmd; + memcpy((void *)buffp, + (const void *)Performance_Cmd, + sizeof(Performance_Cmd_t)); + DT_Performance_Cmd_Endian((Performance_Cmd_t *) buffp); + break; + } + default: + { + DT_Tdep_PT_Printf(phead, "Unknown Test Type\n"); + ret = DAT_INVALID_PARAMETER; + goto client_exit; + } + } + + /* Send the Command buffer */ + if (!DT_post_send_buffer(phead, + ep_handle, + bpool, 2, DT_Bpool_GetBuffSize(bpool, 2))) { + DT_Tdep_PT_Printf(phead, "%s: cannot send Command\n", module); + ret = DAT_INSUFFICIENT_RESOURCES; + goto client_exit; + } + /* reap the send and verify it */ + dto_cookie.as_64 = LZERO; + dto_cookie.as_ptr = + (DAT_PVOID) (uintptr_t) DT_Bpool_GetBuffer(bpool, 2); + DT_Tdep_PT_Debug(1, + (phead, "%s: Sent Command - awaiting completion\n", + module)); + if (!DT_dto_event_wait(phead, reqt_evd_hdl, &dto_stat) + || !DT_dto_check(phead, &dto_stat, ep_handle, + DT_Bpool_GetBuffSize(bpool, 2), dto_cookie, + "Client_Cmd_Send")) { + ret = DAT_INSUFFICIENT_RESOURCES; + goto client_exit; + } + + /************************************************************************/ + dto_cookie.as_64 = LZERO; + dto_cookie.as_ptr = + (DAT_PVOID) (uintptr_t) DT_Bpool_GetBuffer(bpool, 0); + DT_Tdep_PT_Debug(1, (phead, "%s: Waiting for Server_Info\n", module)); + if (!DT_dto_event_wait(phead, recv_evd_hdl, &dto_stat) || + !DT_dto_check(phead, + &dto_stat, + ep_handle, + DT_Bpool_GetBuffSize(bpool, 0), + dto_cookie, "Server_Info_Recv")) { + ret = DAT_INSUFFICIENT_RESOURCES; + goto client_exit; + } + + DT_Tdep_PT_Debug(1, (phead, "%s: Server_Info Received\n", module)); + sinfo = (Server_Info_t *) DT_Bpool_GetBuffer(bpool, 0); + DT_Server_Info_Endian(sinfo); + memcpy((void *)(uintptr_t) & pt_ptr->Server_Info, + (const void *)sinfo, sizeof(Server_Info_t)); + + /* Perform obligatory version check */ + if (pt_ptr->Server_Info.dapltest_version != DAPLTEST_VERSION) { + DT_Tdep_PT_Printf(phead, + "%s: DAPLTEST VERSION MISMATCH: Server %d, Client %d\n", + module, + pt_ptr->Server_Info.dapltest_version, + DAPLTEST_VERSION); + ret = DAT_MODEL_NOT_SUPPORTED; + goto client_exit; + } + DT_Tdep_PT_Debug(1, (phead, "%s: Version OK!\n", module)); + + /* Dump out what we know, if requested */ + if (DT_dapltest_debug) { + DT_Server_Info_Print(phead, &pt_ptr->Server_Info); + DT_Client_Info_Print(phead, &pt_ptr->Client_Info); + } + + /* Onward to running the actual test requested */ + switch (pt_ptr->Client_Info.test_type) { + case TRANSACTION_TEST: + { + if (Transaction_Cmd->debug) { + DT_Transaction_Cmd_PT_Print(phead, + Transaction_Cmd); + } + ret = DT_Transaction_Test_Client(pt_ptr, + ia_handle, + server_netaddr); + break; + } + + case QUIT_TEST: + { + DT_Quit_Cmd_PT_Print(phead, Quit_Cmd); + ret = DAT_SUCCESS; + break; + } + + case PERFORMANCE_TEST: + { + if (Performance_Cmd->debug) { + DT_Performance_Cmd_PT_Print(phead, + Performance_Cmd); + } + + ret = DT_Performance_Test_Client(params_ptr, + pt_ptr, + ia_handle, + server_netaddr); + break; + } + } + + /********************************************************************* + * Done - clean up and go home + * ret == function DAT_RETURN return code + */ + client_exit: + DT_Tdep_PT_Debug(1, (phead, "%s: Cleaning Up ...\n", module)); + + /* Disconnect the EP */ + if (ep_handle) { + /* + * graceful attempt might fail because we got here due to + * some error above, so we may as well try harder. + */ + rc = dat_ep_disconnect(ep_handle, DAT_CLOSE_ABRUPT_FLAG); + if (rc != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_ep_disconnect (abrupt) error: %s\n", + module, DT_RetToString(rc)); + } else if (did_connect && + !DT_disco_event_wait(phead, conn_evd_hdl, NULL)) { + DT_Tdep_PT_Printf(phead, "%s: bad disconnect event\n", + module); + } + } + + /* Free the bpool (if any) */ + DT_Bpool_Destroy(pt_ptr, phead, bpool); + + /* Free the EP */ + if (ep_handle) { + DAT_EVENT event; + /* + * Drain off outstanding DTOs that may have been + * generated by racing disconnects + */ + do { + rc = DT_Tdep_evd_dequeue(recv_evd_hdl, &event); + } while (rc == DAT_SUCCESS); + + rc = dat_ep_free(ep_handle); + if (rc != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_ep_free error: %s\n", + module, DT_RetToString(rc)); + /* keep going */ + } + } + + /* Free the 3 EVDs */ + if (conn_evd_hdl) { + rc = DT_Tdep_evd_free(conn_evd_hdl); + if (rc != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_evd_free (conn) error: %s\n", + module, DT_RetToString(rc)); + /* keep going */ + } + } + if (reqt_evd_hdl) { + rc = DT_Tdep_evd_free(reqt_evd_hdl); + if (rc != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_evd_free (reqt) error: %s\n", + module, DT_RetToString(rc)); + /* keep going */ + } + } + if (recv_evd_hdl) { + rc = DT_Tdep_evd_free(recv_evd_hdl); + if (rc != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_evd_free (recv) error: %s\n", + module, DT_RetToString(rc)); + /* keep going */ + } + } + + /* Free the PZ */ + if (pz_handle) { + rc = dat_pz_free(pz_handle); + if (rc != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_pz_free error: %s\n", + module, DT_RetToString(rc)); + /* keep going */ + } + } + + /* Close the IA */ + if (ia_handle) { + /* dat_ia_close cleans up async evd handle, too */ + rc = dat_ia_close(ia_handle, DAT_CLOSE_GRACEFUL_FLAG); + if (rc != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_ia_close (graceful) error: %s\n", + module, DT_RetToString(rc)); + rc = dat_ia_close(ia_handle, DAT_CLOSE_ABRUPT_FLAG); + if (rc != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_ia_close (abrupt) error: %s\n", + module, DT_RetToString(rc)); + } + /* keep going */ + } else { + DT_Tdep_PT_Debug(1, + (phead, "%s: IA %s closed\n", module, + dapl_name)); + } + } + + /* Free the Per_Test_Data */ + DT_Mdep_LockDestroy(&pt_ptr->Thread_counter_lock); + DT_PrintMemList(pt_ptr); /* check if we return all space allocated */ + DT_Mdep_LockDestroy(&pt_ptr->MemListLock); + DT_Free_Per_Test_Data(pt_ptr); + + DT_Tdep_PT_Printf(phead, + "%s: ========== End of Work -- Client Exiting\n", + module); + return ret; +} diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_client_info.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_client_info.c new file mode 100644 index 00000000..f060bbcc --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_client_info.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" + +void DT_Client_Info_Endian(Client_Info_t * client_info) +{ + client_info->dapltest_version = + DT_Endian32(client_info->dapltest_version); + client_info->is_little_endian = + DT_Endian32(client_info->is_little_endian); + client_info->test_type = DT_Endian32(client_info->test_type); + client_info->total_threads = DT_Endian32(client_info->total_threads); +} + +void +DT_Client_Info_Print(DT_Tdep_Print_Head * phead, Client_Info_t * client_info) +{ + DT_Tdep_PT_Printf(phead, "-------------------------------------\n"); + DT_Tdep_PT_Printf(phead, + "Client_Info.dapltest_version : %d\n", + client_info->dapltest_version); + DT_Tdep_PT_Printf(phead, + "Client_Info.is_little_endian : %d\n", + client_info->is_little_endian); + DT_Tdep_PT_Printf(phead, + "Client_Info.test_type : %d\n", + client_info->test_type); +} diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_cnxn.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_cnxn.c new file mode 100644 index 00000000..36d538ce --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_cnxn.c @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" + +/****************************************************************************/ +int get_ep_connection_state(DT_Tdep_Print_Head * phead, DAT_EP_HANDLE ep_handle) +{ + DAT_EP_STATE ep_state; + DAT_BOOLEAN in_dto_idle; + DAT_BOOLEAN out_dto_idle; + DAT_RETURN ret; + char *recv_status = "Idle"; + char *req_status = "Idle"; + + ret = dat_ep_get_status(ep_handle, &ep_state, &in_dto_idle, + &out_dto_idle); + if (ret != 0) { + DT_Tdep_PT_Printf(phead, + "DAT_ERROR: Can't get Connection State %s\n", + DT_RetToString(ret)); + } else { + if (in_dto_idle == 0) { + recv_status = "Active"; + } + if (out_dto_idle == 0) { + req_status = "Active"; + } + + DT_Tdep_PT_Printf(phead, + "DAT_STATE: %s\n", DT_State2Str(ep_state)); + DT_Tdep_PT_Printf(phead, + "DAT_STATE: Inbound DTO Status: %s \n", + recv_status); + DT_Tdep_PT_Printf(phead, + "DAT_STATE: Outbound DTO Status: %s\n", + req_status); + } + + return 0; +} diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_execute.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_execute.c new file mode 100644 index 00000000..c117b2aa --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_execute.c @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" + +#include "dapl_transaction_cmd.h" +#include "dapl_performance_cmd.h" +#include "dapl_quit_cmd.h" +#include "dapl_limit_cmd.h" + +DAT_RETURN DT_Execute_Test(Params_t * params_ptr) +{ + DAT_RETURN rc = DAT_SUCCESS; + Transaction_Cmd_t *Transaction_Cmd; + Quit_Cmd_t *Quit_Cmd; + Limit_Cmd_t *Limit_Cmd; + Performance_Cmd_t *Performance_Cmd; + FFT_Cmd_t *FFT_Cmd; + + /* re init global data - for kdapltest, we are now in the kernel */ + DT_local_is_little_endian = params_ptr->local_is_little_endian; + DT_dapltest_debug = params_ptr->debug; + + switch (params_ptr->test_type) { + case SERVER_TEST: + { + DT_cs_Server(params_ptr); + break; + } + case TRANSACTION_TEST: + { + Transaction_Cmd = ¶ms_ptr->u.Transaction_Cmd; + rc = DT_cs_Client(params_ptr, + Transaction_Cmd->dapl_name, + Transaction_Cmd->server_name, + Transaction_Cmd->num_threads * + Transaction_Cmd->eps_per_thread); + break; + } + case QUIT_TEST: + { + Quit_Cmd = ¶ms_ptr->u.Quit_Cmd; + (void)DT_cs_Client(params_ptr, + Quit_Cmd->device_name, + Quit_Cmd->server_name, 0); + break; + } + case LIMIT_TEST: + { + Limit_Cmd = ¶ms_ptr->u.Limit_Cmd; + rc = DT_cs_Limit(params_ptr, Limit_Cmd); + break; + } + case PERFORMANCE_TEST: + { + Performance_Cmd = ¶ms_ptr->u.Performance_Cmd; + rc = DT_cs_Client(params_ptr, + Performance_Cmd->dapl_name, + Performance_Cmd->server_name, 1); + break; + } + + case FFT_TEST: + { + FFT_Cmd = ¶ms_ptr->u.FFT_Cmd; + rc = DT_cs_FFT(params_ptr, FFT_Cmd); + break; + } + } + return rc; +} diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_fft_connmgt.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_fft_connmgt.c new file mode 100644 index 00000000..c1c9e600 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_fft_connmgt.c @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" + +int DT_connmgt_case0(Params_t * params_ptr, FFT_Cmd_t * cmd) +{ + FFT_Connection_t conn; + int res = 1; + DAT_RETURN rc = 0; + DT_Tdep_Print_Head *phead; + phead = params_ptr->phead; + + DT_Tdep_PT_Printf(phead, "\ + Description: Ensure time in dat_evd_wait works correctly\n"); + + DT_fft_init_server(params_ptr, cmd, &conn); + DT_assert(phead, NULL != conn.ia_handle); + rc = DT_Tdep_evd_wait(conn.cr_evd, 10000, &conn.event); + DT_assert_dat(phead, DAT_GET_TYPE(rc) == DAT_TIMEOUT_EXPIRED); + + cleanup: + rc = DT_fft_destroy_conn_struct(params_ptr, &conn); + DT_assert_clean(phead, rc == DAT_SUCCESS); + + return res; +} + +int DT_connmgt_case1(Params_t * params_ptr, FFT_Cmd_t * cmd) +{ + FFT_Connection_t conn; + int res = 1; + DAT_RETURN rc; + DT_Tdep_Print_Head *phead; + phead = params_ptr->phead; + + DT_Tdep_PT_Printf(phead, "\ + Description: Attempt to use timeout of 0 in dat_evd_wait\n"); + + DT_fft_init_server(params_ptr, cmd, &conn); + DT_assert(phead, NULL != conn.ia_handle); + + rc = DT_Tdep_evd_wait(conn.cr_evd, 0, &conn.event); + DT_assert_dat(phead, DAT_GET_TYPE(rc) == DAT_TIMEOUT_EXPIRED); + + cleanup: + rc = DT_fft_destroy_conn_struct(params_ptr, &conn); + DT_assert_clean(phead, rc == DAT_SUCCESS); + return res; + +} + +void DT_connmgt_test(Params_t * params_ptr, FFT_Cmd_t * cmd) +{ + int i; + int res; + DT_Tdep_Print_Head *phead; + FFT_Testfunc_t cases_func[] = { + {DT_connmgt_case0}, + {DT_connmgt_case1}, + }; + phead = params_ptr->phead; + for (i = 0; i < cmd->size; i++) { + if (cmd->cases_flag[i]) { + if (cmd->cases_flag[i]) { + + DT_Tdep_PT_Printf(phead, "\ + *********************************************************************\n"); + DT_Tdep_PT_Printf(phead, "\ + Function feature: Connect Management (Server side) case: %d\n", i); + res = cases_func[i].fun(params_ptr, cmd); + if (res == 1) { + DT_Tdep_PT_Printf(phead, + "Result: PASS\n"); + } else if (res == 0) { + DT_Tdep_PT_Printf(phead, + "Result: FAIL\n"); + } else if (res == -1) { + DT_Tdep_PT_Printf(phead, + "Result: use other test tool\n"); + } else if (res == -2) { + DT_Tdep_PT_Printf(phead, + "Result: not support or next stage to develop\n"); + } + + DT_Tdep_PT_Printf(phead, "\ + *********************************************************************\n"); + } + } + } +} diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_fft_dataxfer.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_fft_dataxfer.c new file mode 100644 index 00000000..d14071f0 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_fft_dataxfer.c @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" + +/*--------------------------------------------------------*/ +int DT_dataxfer_generic(DT_Tdep_Print_Head * phead, FFT_Cmd_t * cmd, + int test_case) +{ + FFT_Connection_t conn; + DAT_RETURN rc = 0; + int res = 1; + DT_fft_init_server(phead, cmd, &conn); + DT_assert(phead, NULL != conn.ia_handle); + + DT_fft_listen(phead, &conn); + + switch (test_case) { + case 0: + { + DT_Tdep_PT_Printf(phead, "Posting null send buffer\n"); + rc = DT_post_send_buffer(phead, 0, conn.bpool, 0, + DT_Bpool_GetBuffSize(conn. + bpool, + 0)); + DT_assert_dat(phead, + DAT_GET_TYPE(rc) == DAT_INVALID_HANDLE); + break; + } + case 1: + { + DT_Tdep_PT_Printf(phead, + "Call evd wait with null evd\n"); + rc = dat_evd_wait(0, DAT_TIMEOUT_INFINITE, 1, + &conn.event, &conn.count); + DT_assert_dat(phead, + DAT_GET_TYPE(rc) == DAT_INVALID_HANDLE); + break; + } + case 2: + { + DT_Tdep_PT_Printf(phead, + "Call evd wait with empty send queue\n"); + rc = dat_evd_wait(conn.send_evd, 10 * 1000000, 1, + &conn.event, &conn.count); + DT_assert_dat(phead, + DAT_GET_TYPE(rc) == DAT_TIMEOUT_EXPIRED); + break; + } + case 3: + { + DT_Tdep_PT_Printf(phead, "Posting null recv buffer\n"); + rc = DT_post_recv_buffer(phead, 0, conn.bpool, 0, + DT_Bpool_GetBuffSize(conn. + bpool, + 0)); + DT_assert_dat(phead, + DAT_GET_TYPE(rc) == DAT_INVALID_HANDLE); + break; + } + } + cleanup: + DT_assert_clean(phead, DT_fft_destroy_conn_struct(phead, &conn)); + return res; +} + +int DT_dataxfer_case0(DT_Tdep_Print_Head * phead, FFT_Cmd_t * cmd) +{ + DT_Tdep_PT_Printf(phead, "\ + Description: Call dat_ep_post_send with null ep_handle.\n"); + return DT_dataxfer_generic(phead, cmd, 0); +} + +int DT_dataxfer_case1(DT_Tdep_Print_Head * phead, FFT_Cmd_t * cmd) +{ + DT_Tdep_PT_Printf(phead, "\ + Description: Call dat_evd_wait with null evd.\n"); + return DT_dataxfer_generic(phead, cmd, 1); +} + +int DT_dataxfer_case2(DT_Tdep_Print_Head * phead, FFT_Cmd_t * cmd) +{ + DT_Tdep_PT_Printf(phead, "\ + Description: Call dat_evd_wait with null evd.\n"); + return DT_dataxfer_generic(phead, cmd, 2); +} + +int DT_dataxfer_case3(DT_Tdep_Print_Head * phead, FFT_Cmd_t * cmd) +{ + DT_Tdep_PT_Printf(phead, "\ + Description: Call dat_evd_wait with null evd.\n"); + return DT_dataxfer_generic(phead, cmd, 3); +} + +/*-------------------------------------------------------------*/ +void DT_dataxfer_test(DT_Tdep_Print_Head * phead, FFT_Cmd_t * cmd) +{ + int i; + int res; + FFT_Testfunc_t cases_func[] = { + {DT_dataxfer_case0}, + {DT_dataxfer_case1}, + {DT_dataxfer_case2}, + {DT_dataxfer_case3}, + }; + + for (i = 0; i < cmd->size; i++) { + if (cmd->cases_flag[i]) { + DT_Tdep_PT_Printf(phead, "\ + *********************************************************************\n"); + DT_Tdep_PT_Printf(phead, "\ + Function feature: Protection Zone management case: %d\n", i); + res = cases_func[i].fun(phead, cmd); + if (res == 1) { + DT_Tdep_PT_Printf(phead, "Result: PASS\n"); + } else if (res == 0) { + DT_Tdep_PT_Printf(phead, "Result: FAIL\n"); + } else if (res == -1) { + DT_Tdep_PT_Printf(phead, + "Result: use other test tool\n"); + } else if (res == -2) { + DT_Tdep_PT_Printf(phead, + "Result: not support or next stage to develop\n"); + } + + DT_Tdep_PT_Printf(phead, "\ + *********************************************************************\n"); + } + } + return; +} diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_fft_dataxfer_client.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_fft_dataxfer_client.c new file mode 100644 index 00000000..f31bb55e --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_fft_dataxfer_client.c @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" + +#define CONN_STATE 1 +#define TIMEOUT_TEST 2 +#define DATAXFER_TEST 3 + +int DT_dataxfer_client_generic(DT_Tdep_Print_Head * phead, + FFT_Cmd_t * cmd, int flag) +{ + int res = 1; + FFT_Connection_t conn; + DAT_RETURN rc = 0; + + DT_fft_init_client(phead, cmd, &conn); + DT_assert_dat(phead, conn.ia_handle != NULL) + + DT_assert(phead, DT_fft_connect(phead, &conn)); + + if (flag == CONN_STATE) { + res = 1; + goto cleanup; + } else if (flag == TIMEOUT_TEST) { + + } else if (flag == DATAXFER_TEST) { + conn.bpool = DT_BpoolAlloc(0, + phead, + conn.ia_handle, + conn.pz_handle, + NULL, + NULL, + 4096, + 2, + DAT_OPTIMAL_ALIGNMENT, false, false); + DT_assert(phead, conn.bpool != 0); + rc = DT_post_send_buffer(phead, conn.ep_handle, conn.bpool, 0, + DT_Bpool_GetBuffSize(conn.bpool, 0)); + DT_assert_dat(phead, rc == DAT_SUCCESS); + rc = dat_evd_wait(conn.send_evd, 10 * 1000000, 1, &conn.event, + &conn.count); + DT_assert_dat(phead, rc == DAT_SUCCESS); + res = 1; + goto cleanup; + } + // cleanup + cleanup: + + if (conn.ep_handle) { + // disconnect + DT_Tdep_PT_Printf(phead, "Disconnect\n"); + rc = dat_ep_disconnect(conn.ep_handle, DAT_CLOSE_ABRUPT_FLAG); + DT_assert_clean(phead, rc == DAT_SUCCESS); + } + rc = DT_fft_destroy_conn_struct(phead, &conn); + DT_assert_clean(phead, rc == DAT_SUCCESS); + + return res; +} + +int DT_dataxfer_client_case0(DT_Tdep_Print_Head * phead, FFT_Cmd_t * cmd) +{ + DT_Tdep_PT_Printf(phead, "\ + Description: This is a helper case on the client side for dataxfer case0.\n"); + return DT_dataxfer_client_generic(phead, cmd, CONN_STATE); +} + +void DT_dataxfer_client_test(DT_Tdep_Print_Head * phead, FFT_Cmd_t * cmd) +{ + int i; + int res; + FFT_Testfunc_t cases_func[] = { + {DT_dataxfer_client_case0}, + }; + + for (i = 0; i < cmd->size; i++) { + if (cmd->cases_flag[i]) { + DT_Tdep_PT_Printf(phead, "\ + *********************************************************************\n"); + DT_Tdep_PT_Printf(phead, "\ + Function feature: Dataxfer client case: %d\n", i); + res = cases_func[i].fun(phead, cmd); + if (res == 1) { + DT_Tdep_PT_Printf(phead, "Result: PASS\n"); + } else if (res == 0) { + DT_Tdep_PT_Printf(phead, "Result: FAIL\n"); + } else if (res == -1) { + + DT_Tdep_PT_Printf(phead, + "Result: use other test tool\n"); + } else if (res == -2) { + DT_Tdep_PT_Printf(phead, + "Result: not support or next stage to develop\n"); + } + + DT_Tdep_PT_Printf(phead, "\ + *********************************************************************\n"); + } + } + return; +} diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_fft_endpoint.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_fft_endpoint.c new file mode 100644 index 00000000..81e2c983 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_fft_endpoint.c @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" + +#define CQENTRYCOUNT 100 +#define BUFFSIZE 1024 +#define DEFAULT_QUEUE_LEN 10 + +int DT_endpoint_generic(Params_t * params_ptr, + FFT_Cmd_t * cmd, bool destroy_pz_early) +{ + char *dev_name; + DAT_IA_HANDLE ia_handle; + DAT_PZ_HANDLE pz_handle; + DAT_EP_HANDLE ep_handle; + DAT_EVD_HANDLE evd_handle; + DAT_EVD_HANDLE conn_evd_handle; + DAT_EVD_HANDLE send_evd_handle; + DAT_EVD_HANDLE recv_evd_handle; + DAT_RETURN rc, wanted; + int res; + DT_Tdep_Print_Head *phead; + + res = 1; + ia_handle = NULL; + pz_handle = NULL; + ep_handle = NULL; + evd_handle = NULL; + conn_evd_handle = NULL; + send_evd_handle = NULL; + recv_evd_handle = NULL; + dev_name = cmd->device_name; + evd_handle = DAT_HANDLE_NULL; + phead = params_ptr->phead; + + rc = dat_ia_open((const DAT_NAME_PTR)dev_name, + DEFAULT_QUEUE_LEN, &evd_handle, &ia_handle); + DT_assert_dat(phead, rc == DAT_SUCCESS); + + rc = dat_pz_create(ia_handle, &pz_handle); + DT_assert_dat(phead, rc == DAT_SUCCESS); + + if (destroy_pz_early) { + if (pz_handle) { + rc = dat_pz_free(pz_handle); + DT_assert_dat(phead, rc == DAT_SUCCESS); + } + } + + rc = DT_Tdep_evd_create(ia_handle, DEFAULT_QUEUE_LEN, NULL, + DAT_EVD_DTO_FLAG | DAT_EVD_RMR_BIND_FLAG, + &send_evd_handle); + DT_assert_dat(phead, rc == DAT_SUCCESS); + + rc = DT_Tdep_evd_create(ia_handle, DEFAULT_QUEUE_LEN, NULL, + DAT_EVD_DTO_FLAG, &recv_evd_handle); + DT_assert_dat(phead, rc == DAT_SUCCESS); + + rc = DT_Tdep_evd_create(ia_handle, DEFAULT_QUEUE_LEN, NULL, + DAT_EVD_CONNECTION_FLAG, &conn_evd_handle); + DT_assert_dat(phead, rc == DAT_SUCCESS); + + rc = dat_ep_create(ia_handle, pz_handle, recv_evd_handle, + send_evd_handle, conn_evd_handle, NULL, &ep_handle); + if (destroy_pz_early) { + wanted = DAT_INVALID_HANDLE; + } else { + wanted = DAT_SUCCESS; + } + DT_assert_dat(phead, DAT_GET_TYPE(rc) == wanted); + + cleanup: + if (ep_handle) { + rc = dat_ep_free(ep_handle); + DT_assert_clean(phead, rc == DAT_SUCCESS); + } + + if (send_evd_handle) { + rc = DT_Tdep_evd_free(send_evd_handle); + DT_assert_clean(phead, rc == DAT_SUCCESS); + } + + if (recv_evd_handle) { + rc = DT_Tdep_evd_free(recv_evd_handle); + DT_assert_clean(phead, rc == DAT_SUCCESS); + } + + if (conn_evd_handle) { + rc = DT_Tdep_evd_free(conn_evd_handle); + DT_assert_clean(phead, rc == DAT_SUCCESS); + } + + if (!destroy_pz_early && pz_handle) { + rc = dat_pz_free(pz_handle); + DT_assert_clean(phead, rc == DAT_SUCCESS); + } + + if (ia_handle) { + rc = dat_ia_close(ia_handle, DAT_CLOSE_ABRUPT_FLAG); + DT_assert_clean(phead, rc == DAT_SUCCESS); + } + return res; +} + +int DT_endpoint_case0(Params_t * params_ptr, FFT_Cmd_t * cmd) +{ + + DT_Tdep_Print_Head *phead; + phead = params_ptr->phead; + DT_Tdep_PT_Printf(phead, "\ + Description: Test if we can normally create endpoint and destory it.\n"); + DT_Tdep_PT_Printf(phead, "\ + The endpoint is not associated with a CQ\n"); + return DT_endpoint_generic(params_ptr, cmd, false); /* destroy pz early */ +} + +int DT_endpoint_case1(Params_t * params_ptr, FFT_Cmd_t * cmd) +{ + + DT_Tdep_Print_Head *phead; + phead = params_ptr->phead; + DT_Tdep_PT_Printf(phead, "\ + Description: try to create endpoint with pz already destroyed\n"); + return DT_endpoint_generic(params_ptr, cmd, true); /* destroy pz early */ +} + +int DT_endpoint_case2(Params_t * params_ptr, FFT_Cmd_t * cmd) +{ + char *dev_name; + DAT_IA_HANDLE ia_handle; + DAT_EP_HANDLE ep_handle; + DAT_EVD_HANDLE send_evd, conn_evd, recv_evd, cr_evd; + DAT_PZ_HANDLE pz_handle; + DAT_EVENT event; + Bpool *bpool; + int res; + DAT_RETURN rc; + DT_Tdep_Print_Head *phead; + phead = params_ptr->phead; + DT_Tdep_PT_Printf(phead, "\ + Description: try to destroy ep with descriptor still in working queue\n"); + res = 1; + bpool = 0; + pz_handle = 0; + ia_handle = 0; + ep_handle = 0; + send_evd = 0; + conn_evd = 0; + recv_evd = 0; + cr_evd = 0; + dev_name = cmd->device_name; + + rc = DT_ia_open(dev_name, &ia_handle); + DT_assert_dat(phead, rc == DAT_SUCCESS); + rc = dat_pz_create(ia_handle, &pz_handle); + DT_assert_dat(phead, rc == DAT_SUCCESS); + rc = DT_ep_create(params_ptr, + ia_handle, + pz_handle, + &cr_evd, &conn_evd, &send_evd, &recv_evd, &ep_handle); + DT_assert_dat(phead, rc == DAT_SUCCESS); + bpool = + DT_BpoolAlloc(0, phead, ia_handle, pz_handle, NULL, NULL, 4096, 1, + DAT_OPTIMAL_ALIGNMENT, false, false); + DT_assert(phead, bpool != 0); + DT_assert(phead, DT_post_recv_buffer(phead, + ep_handle, + bpool, 0, 4096) == true); + if (ep_handle) { + rc = dat_ep_free(ep_handle); + DT_assert_dat(phead, rc == DAT_SUCCESS); + } + + /* + * Remove all DTOs. The disconnect above may have + * flushed all posted operations, so this is just a + * clean up. + */ + do { + rc = DT_Tdep_evd_dequeue(recv_evd, &event); + } while (rc == DAT_SUCCESS); + cleanup: + if (bpool) { + rc = DT_Bpool_Destroy(0, phead, bpool); + DT_assert_clean(phead, rc != false); + } + if (pz_handle) { + rc = dat_pz_free(pz_handle); + DT_assert_clean(phead, rc == DAT_SUCCESS); + } + if (ia_handle) { + rc = dat_ia_close(ia_handle, DAT_CLOSE_ABRUPT_FLAG); + DT_assert_clean(phead, rc == DAT_SUCCESS); + } + return res; + +} + +/*-------------------------------------------------------------*/ +void DT_endpoint_test(Params_t * params_ptr, FFT_Cmd_t * cmd) +{ + int i; + int res; + DT_Tdep_Print_Head *phead; + FFT_Testfunc_t cases_func[] = { + {DT_endpoint_case0}, + {DT_endpoint_case1}, + {DT_endpoint_case2}, + }; + + phead = params_ptr->phead; + for (i = 0; i < cmd->size; i++) { + if (cmd->cases_flag[i]) { + DT_Tdep_PT_Printf(phead, "\ + *********************************************************************\n"); + DT_Tdep_PT_Printf(phead, "\ + Function feature: EndPoint management case: %d\n", i); + res = cases_func[i].fun(params_ptr, cmd); + if (res == 1) { + DT_Tdep_PT_Printf(phead, "Result: PASS\n"); + } else if (res == 0) { + DT_Tdep_PT_Printf(phead, "Result: FAIL\n"); + } else if (res == -1) { + DT_Tdep_PT_Printf(phead, + "Result: use other test tool\n"); + } else if (res == -2) { + DT_Tdep_PT_Printf(phead, + "Result: not support or next stage to develop\n"); + } + + DT_Tdep_PT_Printf(phead, "\ + *********************************************************************\n"); + } + } + return; +} diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_fft_hwconn.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_fft_hwconn.c new file mode 100644 index 00000000..ccde7332 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_fft_hwconn.c @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" + +/*--------------------------------------------------------*/ +int DT_hwconn_case0(Params_t * params_ptr, FFT_Cmd_t * cmd) +{ + char *dev_name; + DAT_IA_HANDLE nic_handle; + DAT_EVD_HANDLE evd_handle; + DAT_RETURN rc; + int res = 1; + DT_Tdep_Print_Head *phead; + phead = params_ptr->phead; + + DT_Tdep_PT_Printf(phead, "\ + Description: Test if we can normally Open NIC and then close it\n"); + + dev_name = cmd->device_name; + nic_handle = 0; + evd_handle = DAT_HANDLE_NULL; + + rc = dat_ia_open((const DAT_NAME_PTR)dev_name, 10, &evd_handle, + &nic_handle); + DT_assert_dat(phead, rc == DAT_SUCCESS); + + rc = dat_ia_close(nic_handle, DAT_CLOSE_ABRUPT_FLAG); + DT_assert_dat(phead, rc == DAT_SUCCESS); + cleanup: + + return res; +} + +/*--------------------------------------------------------*/ +int DT_hwconn_case1(Params_t * params_ptr, FFT_Cmd_t * cmd) +{ + DAT_IA_HANDLE nic_handle; + DAT_RETURN rc; + DAT_EVD_HANDLE evd_handle; + char dev_name[100]; + int i; + DT_Tdep_Print_Head *phead; + phead = params_ptr->phead; + + DT_Tdep_PT_Printf(phead, + "Description: try to open NIC with incorrect device name\n"); + DT_Tdep_PT_Printf(phead, + " (just num, one letter, multiple letter, num_letter\n"); + DT_Tdep_PT_Printf(phead, + "letter_num). You alse can do this test manually\n"); + DT_Tdep_PT_Printf(phead, + "dapltest -T F -D -f hwconn \n"); + + for (i = 0; i < 5; i++) { + if (i == 0) { + sprintf(dev_name, "%s", "40"); /* just number */ + } else if (i == 1) { + sprintf(dev_name, "%s", "x"); /* just letter */ + } else if (i == 2) { + sprintf(dev_name, "%s", "xsdf"); /* multiple letter */ + } else if (i == 3) { + sprintf(dev_name, "%s", "x34"); /* letter_number */ + } else if (i == 4) { + sprintf(dev_name, "%s", "34df"); /* number_letter */ + } + + evd_handle = DAT_HANDLE_NULL; + rc = dat_ia_open((const DAT_NAME_PTR)dev_name, 10, &evd_handle, + &nic_handle); + if (DAT_GET_TYPE(rc) != DAT_PROVIDER_NOT_FOUND) { + const char *major_msg, *minor_msg; + + DT_Tdep_PT_Printf(phead, " \ + fff not get expected result when open NIC with device name: %s\n", dev_name); + dat_strerror(rc, &major_msg, &minor_msg); + DT_Tdep_PT_Printf(phead, "ERROR: %s (%s)\n", major_msg, + minor_msg); + + if (rc == DAT_SUCCESS) { + rc = dat_ia_close(nic_handle, + DAT_CLOSE_ABRUPT_FLAG); + DT_assert_clean(phead, rc == DAT_SUCCESS); + } + return 0; + } + } + return 1; +} + +/*--------------------------------------------------------*/ +int DT_hwconn_case2(Params_t * params_ptr, FFT_Cmd_t * cmd) +{ + DAT_IA_HANDLE nic_handle; + DAT_RETURN rc; + int res = 1; + DT_Tdep_Print_Head *phead; + phead = params_ptr->phead; + + DT_Tdep_PT_Printf(phead, "\ + Description: Try to close nic with Nic handle is null (NIC not open)\n"); + nic_handle = 0; + rc = dat_ia_close(nic_handle, DAT_CLOSE_ABRUPT_FLAG); + DT_assert_dat(phead, DAT_GET_TYPE(rc) == DAT_INVALID_HANDLE); + + cleanup: + return res; +} + +/*--------------------------------------------------------*/ +int DT_hwconn_case3(Params_t * params_ptr, FFT_Cmd_t * cmd) +{ + FFT_Connection_t conn; + DAT_RETURN rc; + int res; + DT_Tdep_Print_Head *phead; + phead = params_ptr->phead; + + DT_Tdep_PT_Printf(phead, + "Description: Test if we can close NIC when the created \n"); + DT_Tdep_PT_Printf(phead, "endpoint has not been destroyed.\n"); + DT_Tdep_PT_Printf(phead, + "The problem for this case is that once the hca is closed, \n"); + DT_Tdep_PT_Printf(phead, + "there is no way to destroy the endpoint's resources\n"); + DT_Tdep_PT_Printf(phead, + "thus the test leaks a small amount of memory\n"); + + res = 1; + + DT_fft_init_client(params_ptr, cmd, &conn); + + /* try to close nic when vi have not destroyed */ + if (conn.ia_handle) { + rc = dat_ia_close(conn.ia_handle, DAT_CLOSE_ABRUPT_FLAG); + if (rc != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "Warning: dat_ia_close fails %s, reboot for cleanup\n", + DT_RetToString(rc)); + return 0; + } + } else { + res = 0; + } + /* if nic is closed, it is impossible to destory vi and ptag */ + //DT_fft_destroy_conn_struct(&conn); + return res; + +} + +/*-------------------------------------------------------------*/ +void DT_hwconn_test(Params_t * params_ptr, FFT_Cmd_t * cmd) +{ + int i; + int res; + DT_Tdep_Print_Head *phead; + + FFT_Testfunc_t cases_func[] = { + {DT_hwconn_case0}, + {DT_hwconn_case1}, + {DT_hwconn_case2}, + {DT_hwconn_case3}, + }; + + phead = params_ptr->phead; + for (i = 0; i < cmd->size; i++) { + if (cmd->cases_flag[i]) { + DT_Tdep_PT_Printf(phead, "\ + *********************************************************************\n"); + DT_Tdep_PT_Printf(phead, "\ + Function feature: Hardware connection case: %d\n", i); + res = cases_func[i].fun(params_ptr, cmd); + if (res == 1) { + DT_Tdep_PT_Printf(phead, "Result: PASS\n"); + } else if (res == 0) { + DT_Tdep_PT_Printf(phead, "Result: FAIL\n"); + } else if (res == -1) { + DT_Tdep_PT_Printf(phead, + "Result: use other test tool\n"); + } else if (res == -2) { + DT_Tdep_PT_Printf(phead, + "Result: next stage to develop\n"); + } + + DT_Tdep_PT_Printf(phead, "\ + *********************************************************************\n"); + } + } + return; +} diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_fft_mem.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_fft_mem.c new file mode 100644 index 00000000..4a89d4e2 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_fft_mem.c @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" + +#define CQENTRYCOUNT 100 +#define BUFFSIZE 1024 + +/*--------------------------------------------------------*/ +int DT_mem_generic(Params_t * params_ptr, FFT_Cmd_t * cmd, int flag) +{ + DAT_RETURN rc, expect; + FFT_Connection_t conn; + DAT_REGION_DESCRIPTION region; + DAT_VLEN reg_size; + DAT_LMR_HANDLE lmr_handle; + DAT_LMR_CONTEXT lmr_context; + DAT_VADDR reg_addr; + unsigned char *alloc_ptr; + int res; + DAT_VLEN buffer_size; + DAT_IA_HANDLE ia_handle; + DAT_PZ_HANDLE pz_handle; + DT_Tdep_Print_Head *phead; + phead = params_ptr->phead; + rc = 0; + expect = 0; + res = 1; + lmr_handle = 0; + lmr_context = 0; + reg_addr = 0; + alloc_ptr = 0; + ia_handle = 0; + pz_handle = 0; + + DT_fft_init_client(params_ptr, cmd, &conn); + DT_assert(phead, NULL != conn.ia_handle); + + if (flag == 2) { + buffer_size = 0; + alloc_ptr = 0; + } else { + buffer_size = BUFFSIZE * sizeof(unsigned char); + alloc_ptr = + (unsigned char *)DT_Mdep_Malloc((size_t) buffer_size); + DT_assert(phead, alloc_ptr); + } + + memset(®ion, 0, sizeof(region)); + region.for_va = alloc_ptr; + + ia_handle = conn.ia_handle; + + if (flag != 3) { + pz_handle = conn.pz_handle; + } + + if (flag != 4) { + DT_Tdep_PT_Printf(phead, "Registering memory\n"); + rc = DT_Tdep_lmr_create(ia_handle, DAT_MEM_TYPE_VIRTUAL, region, buffer_size, conn.pz_handle, DAT_MEM_PRIV_ALL_FLAG, &lmr_handle, &lmr_context, NULL, /* FIXME */ + ®_size, ®_addr); + if (flag == 2) { + expect = DAT_LENGTH_ERROR; + } else { + expect = DAT_SUCCESS; + } + DT_assert_dat(phead, DAT_GET_TYPE(rc) == expect); + } + if (flag == 1) { + if (lmr_handle) { + rc = dat_lmr_free(lmr_handle); + DT_assert_dat(phead, rc == DAT_SUCCESS); + } + lmr_handle = 0; + + rc = DT_Tdep_lmr_create(conn.ia_handle, DAT_MEM_TYPE_VIRTUAL, region, buffer_size, conn.pz_handle, DAT_MEM_PRIV_ALL_FLAG, &lmr_handle, &lmr_context, NULL, /* FIXME */ + ®_size, ®_addr); + DT_assert_dat(phead, rc == DAT_SUCCESS); + } + + cleanup: + if (lmr_handle) { + rc = dat_lmr_free(lmr_handle); + DT_assert_clean(phead, rc == DAT_SUCCESS); + } + if (alloc_ptr) { + DT_Mdep_Free(alloc_ptr); + } + rc = DT_fft_destroy_conn_struct(params_ptr, &conn); + DT_assert_clean(phead, rc == DAT_SUCCESS); + + return res; + +} + +int DT_mem_case0(Params_t * params_ptr, FFT_Cmd_t * cmd) +{ + DT_Tdep_Print_Head *phead; + phead = params_ptr->phead; + DT_Tdep_PT_Printf(phead, "\ + Description: Test if we can register typical size of memory\n"); + DT_Tdep_PT_Printf(phead, "\ + then deregister it.\n"); + return DT_mem_generic(params_ptr, cmd, 0); +} + +/*--------------------------------------------------------*/ +int DT_mem_case1(Params_t * params_ptr, FFT_Cmd_t * cmd) +{ + DT_Tdep_Print_Head *phead; + phead = params_ptr->phead; + DT_Tdep_PT_Printf(phead, "\ + Description: Test if we can register typical size of memory\n"); + DT_Tdep_PT_Printf(phead, "\ + deregister, then register it again.\n"); + return DT_mem_generic(params_ptr, cmd, 1); +} + +/*--------------------------------------------------------*/ +int DT_mem_case2(Params_t * params_ptr, FFT_Cmd_t * cmd) +{ + DT_Tdep_Print_Head *phead; + phead = params_ptr->phead; + DT_Tdep_PT_Printf(phead, "\ + Description: Try to register memory with memory size 0\n"); + return DT_mem_generic(params_ptr, cmd, 2); +} + +/*--------------------------------------------------------*/ +int DT_mem_case3(Params_t * params_ptr, FFT_Cmd_t * cmd) +{ + DT_Tdep_Print_Head *phead; + phead = params_ptr->phead; + DT_Tdep_PT_Printf(phead, "\ + Description: Try to register memory with null pz\n"); + return DT_mem_generic(params_ptr, cmd, 3); +} + +/*--------------------------------------------------------*/ +int DT_mem_case4(Params_t * params_ptr, FFT_Cmd_t * cmd) +{ + DT_Tdep_Print_Head *phead; + phead = params_ptr->phead; + DT_Tdep_PT_Printf(phead, "\ + Description: Try to deregister memory with null lmr_handle\n"); + return DT_mem_generic(params_ptr, cmd, 4); +} + +/*-------------------------------------------------------------*/ +void DT_mem_test(Params_t * params_ptr, FFT_Cmd_t * cmd) +{ + int i; + int res; + DT_Tdep_Print_Head *phead; + + FFT_Testfunc_t cases_func[] = { + {DT_mem_case0}, + {DT_mem_case1}, + {DT_mem_case2}, + {DT_mem_case3}, + {DT_mem_case4}, + }; + + phead = params_ptr->phead; + for (i = 0; i < cmd->size; i++) { + if (cmd->cases_flag[i]) { + DT_Tdep_PT_Printf(phead, "\ + *********************************************************************\n"); + DT_Tdep_PT_Printf(phead, "\ + Function feature: Memory register/deregister case: %d\n", i); + res = cases_func[i].fun(params_ptr, cmd); + if (res == 1) { + DT_Tdep_PT_Printf(phead, "Result: PASS\n"); + } else if (res == 0) { + DT_Tdep_PT_Printf(phead, "Result: FAIL\n"); + } else if (res == -1) { + DT_Tdep_PT_Printf(phead, + "Result: use other test tool\n"); + } else if (res == -2) { + DT_Tdep_PT_Printf(phead, + "Result: not support or next stage to develop\n"); + } + + DT_Tdep_PT_Printf(phead, "\ + *********************************************************************\n"); + } + } + return; +} diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_fft_pz.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_fft_pz.c new file mode 100644 index 00000000..77f818b9 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_fft_pz.c @@ -0,0 +1,247 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" + +#define CQENTRYCOUNT 100 +#define BUFFSIZE 1024 + +/*--------------------------------------------------------*/ +int DT_pz_case0(Params_t * params_ptr, FFT_Cmd_t * cmd) +{ + char *dev_name; + DAT_IA_HANDLE ia_handle; + DAT_PZ_HANDLE pz_handle; + DAT_EVD_HANDLE evd_handle; + DAT_RETURN rc; + int res; + DT_Tdep_Print_Head *phead; + phead = params_ptr->phead; + + DT_Tdep_PT_Printf(phead, "\ + Description: Test if we can normally create pz and destroy it.\n"); + + res = 1; + ia_handle = 0; + pz_handle = 0; + evd_handle = DAT_HANDLE_NULL; + dev_name = cmd->device_name; + + rc = DT_ia_open(dev_name, &ia_handle); + DT_assert_dat(phead, rc == DAT_SUCCESS); + rc = dat_pz_create(ia_handle, &pz_handle); + DT_assert_dat(phead, rc == DAT_SUCCESS); + + cleanup: + if (pz_handle) { + rc = dat_pz_free(pz_handle); + DT_assert_dat(phead, rc == DAT_SUCCESS); + } + if (ia_handle) { + rc = dat_ia_close(ia_handle, DAT_CLOSE_ABRUPT_FLAG); + DT_assert_dat(phead, rc == DAT_SUCCESS); + } + return res; +} + +/*--------------------------------------------------------*/ +int DT_pz_case1(Params_t * params_ptr, FFT_Cmd_t * cmd) +{ + char *dev_name; + DAT_IA_HANDLE ia_handle; + DAT_PZ_HANDLE pz_handle; + DAT_EP_HANDLE ep_handle; + DAT_EVD_HANDLE conn_evd, send_evd, recv_evd, cr_evd; + DAT_RETURN rc; + int res; + DT_Tdep_Print_Head *phead; + phead = params_ptr->phead; + + DT_Tdep_PT_Printf(phead, "\ + Description: try to destroy pz with vi still associated with it\n"); + + res = 1; + ia_handle = 0; + pz_handle = 0; + ep_handle = 0; + conn_evd = 0; + send_evd = 0; + recv_evd = 0; + cr_evd = 0; + dev_name = cmd->device_name; + + rc = DT_ia_open(dev_name, &ia_handle); + DT_assert_dat(phead, rc == DAT_SUCCESS); + + rc = dat_pz_create(ia_handle, &pz_handle); + DT_assert_dat(phead, rc == DAT_SUCCESS); + + rc = DT_ep_create(params_ptr, + ia_handle, + pz_handle, + &cr_evd, &conn_evd, &send_evd, &recv_evd, &ep_handle); + DT_assert_dat(phead, rc == DAT_SUCCESS); + + if (pz_handle) { + rc = dat_pz_free(pz_handle); + DT_assert_dat(phead, DAT_GET_TYPE(rc) == DAT_INVALID_STATE); + } + + cleanup: + /* corrrect order */ + if (ep_handle) { + rc = dat_ep_free(ep_handle); + DT_assert_clean(phead, rc == DAT_SUCCESS); + } + if (conn_evd) { + rc = DT_Tdep_evd_free(conn_evd); + DT_assert_clean(phead, rc == DAT_SUCCESS); + } + if (send_evd) { + rc = DT_Tdep_evd_free(send_evd); + DT_assert_clean(phead, rc == DAT_SUCCESS); + } + if (recv_evd) { + rc = DT_Tdep_evd_free(recv_evd); + DT_assert_clean(phead, rc == DAT_SUCCESS); + } + if (pz_handle) { + rc = dat_pz_free(pz_handle); + DT_assert_clean(phead, rc == DAT_SUCCESS); + } + + if (ia_handle) { + rc = dat_ia_close(ia_handle, DAT_CLOSE_ABRUPT_FLAG); + DT_assert_clean(phead, rc == DAT_SUCCESS); + } + + return res; +} + +/*--------------------------------------------------------*/ +int DT_pz_case2(Params_t * params_ptr, FFT_Cmd_t * cmd) +{ + char *dev_name; + DAT_IA_HANDLE ia_handle; + DAT_PZ_HANDLE pz_handle; + Bpool *bpool; + DAT_RETURN rc; + int res; + DT_Tdep_Print_Head *phead; + phead = params_ptr->phead; + + DT_Tdep_PT_Printf(phead, "\ + Description: try to destroy pz with registered memory still\n"); + DT_Tdep_PT_Printf(phead, "\ + associated with it\n"); + + res = 1; + ia_handle = 0; + pz_handle = 0; + bpool = 0; + dev_name = cmd->device_name; + + rc = DT_ia_open(dev_name, &ia_handle); + DT_assert_dat(phead, rc == DAT_SUCCESS); + + rc = dat_pz_create(ia_handle, &pz_handle); + DT_assert_dat(phead, rc == DAT_SUCCESS); + + /* allocate and register bpool */ + bpool = DT_BpoolAlloc(0, phead, ia_handle, pz_handle, NULL, + NULL, BUFFSIZE, 1, DAT_OPTIMAL_ALIGNMENT, + false, false); + DT_assert(phead, bpool != 0); + + if (pz_handle) { + rc = dat_pz_free(pz_handle); + DT_assert_dat(phead, DAT_GET_TYPE(rc) == DAT_INVALID_STATE); + } + + cleanup: + + /* deregister and free bpool */ + if (DT_Bpool_Destroy(0, phead, bpool) == false) { + DT_Tdep_PT_Printf(phead, + "Warning: Destroy bpool fails, reboot for cleanup\n"); + return 0; + } + if (pz_handle) { + rc = dat_pz_free(pz_handle); + DT_assert_clean(phead, rc == DAT_SUCCESS); + } + + if (ia_handle) { + rc = dat_ia_close(ia_handle, DAT_CLOSE_ABRUPT_FLAG); + DT_assert_clean(phead, rc == DAT_SUCCESS); + } + + return res; +} + +/*-------------------------------------------------------------*/ +void DT_pz_test(Params_t * params_ptr, FFT_Cmd_t * cmd) +{ + int i; + int res; + DT_Tdep_Print_Head *phead; + + FFT_Testfunc_t cases_func[] = { + {DT_pz_case0}, + {DT_pz_case1}, + {DT_pz_case2}, + }; + + phead = params_ptr->phead; + for (i = 0; i < cmd->size; i++) { + if (cmd->cases_flag[i]) { + DT_Tdep_PT_Printf(phead, "\ + *********************************************************************\n"); + DT_Tdep_PT_Printf(phead, "\ + Function feature: Protection Zone management case: %d\n", i); + res = cases_func[i].fun(params_ptr, cmd); + if (res == 1) { + DT_Tdep_PT_Printf(phead, "Result: PASS\n"); + } else if (res == 0) { + DT_Tdep_PT_Printf(phead, "Result: FAIL\n"); + } else if (res == -1) { + DT_Tdep_PT_Printf(phead, + "Result: use other test tool\n"); + } else if (res == -2) { + DT_Tdep_PT_Printf(phead, + "Result: not support or next stage to develop\n"); + } + + DT_Tdep_PT_Printf(phead, "\ + *********************************************************************\n"); + } + } + return; +} diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_fft_queryinfo.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_fft_queryinfo.c new file mode 100644 index 00000000..5bbee36f --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_fft_queryinfo.c @@ -0,0 +1,596 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" + +#define CQENTRYCOUNT 100 +#define BUFFSIZE 1024 +#define DEFAULT_QUEUE_LEN 10 + +#if defined(WIN32) +static DAT_OS_WAIT_PROXY_AGENT NULLPROXY = { + (DAT_PVOID) NULL, (DAT_AGENT_FUNC) NULL +}; +#endif + +int DT_queryinfo_basic(Params_t * params_ptr, + FFT_Cmd_t * cmd, + FFT_query_enum object_to_query, DAT_RETURN result_wanted) +{ + char *dev_name; + DAT_IA_HANDLE ia_handle; + DAT_IA_ATTR ia_attributes; + DAT_PROVIDER_ATTR provider_attributes; + DAT_EVD_HANDLE evd_handle; + DAT_EVD_HANDLE conn_evd_handle; + DAT_EVD_HANDLE cr_evd_handle; + DAT_EVD_HANDLE send_evd_handle; + DAT_EVD_HANDLE recv_evd_handle; + DAT_EP_HANDLE ep_handle; + DAT_EP_PARAM ep_param; + DAT_CNO_HANDLE cno_handle; +#ifndef __KDAPLTEST__ + DAT_CNO_PARAM cno_param; +#endif + DAT_EVD_PARAM evd_param; + DAT_PSP_HANDLE psp_handle; + DAT_PSP_PARAM psp_param; + DAT_RSP_HANDLE rsp_handle; + DAT_RSP_PARAM rsp_param; + DAT_PZ_HANDLE pz_handle; + DAT_PZ_PARAM pz_param; + DAT_LMR_HANDLE lmr_handle; + DAT_LMR_PARAM lmr_param; + DAT_LMR_CONTEXT lmr_context; + DAT_RMR_HANDLE rmr_handle; + DAT_RMR_PARAM rmr_param; + DAT_REGION_DESCRIPTION region; + DAT_VLEN reg_size; + DAT_VADDR reg_addr; + DAT_VLEN buffer_size; + unsigned char *alloc_ptr; + DT_Tdep_Print_Head *phead; + + DAT_RETURN rc; + int res = 1; + buffer_size = BUFFSIZE * sizeof(unsigned char); + phead = params_ptr->phead; + reg_addr = 0; + alloc_ptr = 0; + + ia_handle = NULL; + pz_handle = NULL; + ep_handle = NULL; + lmr_handle = NULL; + rmr_handle = NULL; + pz_handle = NULL; + psp_handle = NULL; + rsp_handle = NULL; + cno_handle = NULL; + evd_handle = DAT_HANDLE_NULL; + conn_evd_handle = DAT_HANDLE_NULL; + cr_evd_handle = DAT_HANDLE_NULL; + recv_evd_handle = DAT_HANDLE_NULL; + send_evd_handle = DAT_HANDLE_NULL; + dev_name = cmd->device_name; + + /* All functions require an ia_handle to be created */ + rc = dat_ia_open((const DAT_NAME_PTR)dev_name, + DEFAULT_QUEUE_LEN, &evd_handle, &ia_handle); + DT_assert_dat(phead, rc == DAT_SUCCESS); + + /* These functions require a pz_handle to be created */ + if ((object_to_query == QUERY_EVD) || + (object_to_query == QUERY_RMR) || + (object_to_query == QUERY_LMR) || + (object_to_query == QUERY_EP) || + (object_to_query == QUERY_RSP) || (object_to_query == QUERY_PZ)) { + rc = dat_pz_create(ia_handle, &pz_handle); + DT_assert_dat(phead, rc == DAT_SUCCESS); + } + + /* These functions require a ep_handle to be created */ + if ((object_to_query == QUERY_EP) || (object_to_query == QUERY_RSP)) { + rc = DT_Tdep_evd_create(ia_handle, + DEFAULT_QUEUE_LEN, + cno_handle, + DAT_EVD_DTO_FLAG | + DAT_EVD_RMR_BIND_FLAG, + &send_evd_handle); + DT_assert_dat(phead, rc == DAT_SUCCESS); + + rc = DT_Tdep_evd_create(ia_handle, + DEFAULT_QUEUE_LEN, + cno_handle, + DAT_EVD_DTO_FLAG, &recv_evd_handle); + DT_assert_dat(phead, rc == DAT_SUCCESS); + + rc = DT_Tdep_evd_create(ia_handle, + DEFAULT_QUEUE_LEN, + cno_handle, + DAT_EVD_CONNECTION_FLAG, + &conn_evd_handle); + DT_assert_dat(phead, rc == DAT_SUCCESS); + + rc = dat_ep_create(ia_handle, + pz_handle, + recv_evd_handle, + send_evd_handle, + conn_evd_handle, NULL, &ep_handle); + DT_assert_dat(phead, rc == DAT_SUCCESS); + } + + /* These functions require a CR EVD to be created. */ + if ((object_to_query == QUERY_PSP) || (object_to_query == QUERY_RSP)) { + rc = DT_Tdep_evd_create(ia_handle, + DEFAULT_QUEUE_LEN, + cno_handle, + DAT_EVD_CR_FLAG, &cr_evd_handle); + DT_assert_dat(phead, rc == DAT_SUCCESS); + } + + /* Test dat_ia_query function */ + if (object_to_query == QUERY_IA) { + if (result_wanted == DAT_SUCCESS) { + rc = dat_ia_query(ia_handle, + &evd_handle, + DAT_IA_ALL, + &ia_attributes, + DAT_PROVIDER_FIELD_ALL, + &provider_attributes); + } else if (result_wanted == DAT_INVALID_PARAMETER) { + /* + * The only way to get an invalid parameter is to + * NULL out ia_attr and for the DAT_IA_ATTR_MASK to + * have values + */ + rc = dat_ia_query(ia_handle, + &evd_handle, + DAT_IA_ALL, + NULL, + DAT_PROVIDER_FIELD_ALL, + &provider_attributes); + } else if (result_wanted == DAT_INVALID_HANDLE) { + rc = dat_ia_query(evd_handle, + &evd_handle, + DAT_IA_ALL, + &ia_attributes, + DAT_PROVIDER_FIELD_ALL, + &provider_attributes); + } + } + + /* Test dat_cno_query function */ + else if (object_to_query == QUERY_CNO) { + +#ifndef __KDAPLTEST__ +#if defined(WIN32) + rc = dat_cno_create(ia_handle, NULLPROXY, &cno_handle); +#else + rc = dat_cno_create(ia_handle, + DAT_OS_WAIT_PROXY_AGENT_NULL, &cno_handle); +#endif + + DT_assert_dat(phead, rc == DAT_SUCCESS); + + if (result_wanted == DAT_SUCCESS) { + rc = dat_cno_query(cno_handle, + DAT_CNO_FIELD_ALL, &cno_param); + } else if (result_wanted == DAT_INVALID_PARAMETER) { + rc = dat_cno_query(cno_handle, DAT_CNO_FIELD_ALL, NULL); + } else if (result_wanted == DAT_INVALID_HANDLE) { + rc = dat_cno_query(ia_handle, + DAT_CNO_FIELD_ALL, &cno_param); + } +#endif + } + /* Test dat_evd_query function */ + else if (object_to_query == QUERY_EVD) { + if (result_wanted == DAT_SUCCESS) { + rc = dat_evd_query(evd_handle, + DAT_EVD_FIELD_ALL, &evd_param); + } else if (result_wanted == DAT_INVALID_PARAMETER) { + rc = dat_evd_query(evd_handle, DAT_EVD_FIELD_ALL, NULL); + } else if (result_wanted == DAT_INVALID_HANDLE) { + rc = dat_evd_query(ia_handle, + DAT_EVD_FIELD_ALL, &evd_param); + } + } + + /* Test dat_psp_query function */ + else if (object_to_query == QUERY_PSP) { + rc = dat_psp_create(ia_handle, + SERVER_PORT_NUMBER, + cr_evd_handle, + DAT_PSP_PROVIDER_FLAG, &psp_handle); + DT_assert_dat(phead, rc == DAT_SUCCESS); + if (result_wanted == DAT_SUCCESS) { + rc = dat_psp_query(psp_handle, + DAT_PSP_FIELD_ALL, &psp_param); + } else if (result_wanted == DAT_INVALID_PARAMETER) { + rc = dat_psp_query(psp_handle, DAT_PSP_FIELD_ALL, NULL); + } else if (result_wanted == DAT_INVALID_HANDLE) { + rc = dat_psp_query(evd_handle, + DAT_PSP_FIELD_ALL, &psp_param); + } + } + + /* Test dat_rsp_query function */ + else if (object_to_query == QUERY_RSP) { + rc = dat_rsp_create(ia_handle, + SERVER_PORT_NUMBER, + ep_handle, cr_evd_handle, &rsp_handle); + DT_assert_dat(phead, rc == DAT_SUCCESS); + rc = dat_rsp_query(rsp_handle, DAT_RSP_FIELD_ALL, &rsp_param); + } + + /* Test dat_cr_query function */ + else if (object_to_query == QUERY_CR) { + /* This query is tested in the conmgt test */ + res = -1; + } + + /* Test dat_ep_query function */ + else if (object_to_query == QUERY_EP) { + rc = dat_ep_query(ep_handle, DAT_EP_FIELD_ALL, &ep_param); + } + + /* Test dat_pz_query function */ + else if (object_to_query == QUERY_PZ) { + rc = dat_pz_query(pz_handle, DAT_PZ_FIELD_ALL, &pz_param); + } + + /* Test dat_lmr_query function */ + else if (object_to_query == QUERY_LMR) { + alloc_ptr = + (unsigned char *)DT_Mdep_Malloc((size_t) buffer_size); + DT_assert(phead, alloc_ptr); + memset(®ion, 0, sizeof(region)); + region.for_va = alloc_ptr; + rc = DT_Tdep_lmr_create(ia_handle, DAT_MEM_TYPE_VIRTUAL, region, buffer_size, pz_handle, DAT_MEM_PRIV_ALL_FLAG, &lmr_handle, &lmr_context, NULL, /* FIXME */ + ®_size, ®_addr); + DT_assert_dat(phead, rc == DAT_SUCCESS); + rc = dat_lmr_query(lmr_handle, DAT_LMR_FIELD_ALL, &lmr_param); + } + + /* Test dat_rmr_query function */ + else if (object_to_query == QUERY_RMR) { + rc = dat_rmr_create(pz_handle, &rmr_handle); + DT_assert_dat(phead, rc == DAT_SUCCESS); + /* We don't bind the RMR to anything, so don't ask for the + * LMR_TRIPLET flag + */ + rc = dat_rmr_query(rmr_handle, + DAT_RMR_FIELD_ALL - + DAT_RMR_FIELD_LMR_TRIPLET, &rmr_param); + } + + DT_assert_dat(phead, DAT_GET_TYPE(rc) == result_wanted); + + cleanup: + if (rsp_handle) { + rc = dat_rsp_free(rsp_handle); + DT_assert_clean(phead, rc == DAT_SUCCESS); + } + + if (ep_handle) { + rc = dat_ep_free(ep_handle); + DT_assert_clean(phead, rc == DAT_SUCCESS); + } + + if (send_evd_handle) { + rc = DT_Tdep_evd_free(send_evd_handle); + DT_assert_clean(phead, rc == DAT_SUCCESS); + } + + if (recv_evd_handle) { + rc = DT_Tdep_evd_free(recv_evd_handle); + DT_assert_clean(phead, rc == DAT_SUCCESS); + } + + if (conn_evd_handle) { + rc = DT_Tdep_evd_free(conn_evd_handle); + DT_assert_clean(phead, rc == DAT_SUCCESS); + } + + if (lmr_handle) { + rc = dat_lmr_free(lmr_handle); + DT_assert_clean(phead, rc == DAT_SUCCESS); + } + + if (rmr_handle) { + rc = dat_rmr_free(rmr_handle); + DT_assert_clean(phead, rc == DAT_SUCCESS); + } +#ifndef __KDAPLTEST__ + if (cno_handle) { + rc = dat_cno_free(cno_handle); + DT_assert_clean(phead, rc == DAT_SUCCESS); + } +#endif + if (psp_handle) { + rc = dat_psp_free(psp_handle); + DT_assert_clean(phead, rc == DAT_SUCCESS); + } + + if (cr_evd_handle) { + rc = DT_Tdep_evd_free(cr_evd_handle); + DT_assert_clean(phead, rc == DAT_SUCCESS); + } + + if (pz_handle) { + rc = dat_pz_free(pz_handle); + DT_assert_clean(phead, rc == DAT_SUCCESS); + } + + if (ia_handle) { + rc = dat_ia_close(ia_handle, DAT_CLOSE_ABRUPT_FLAG); + DT_assert_clean(phead, rc == DAT_SUCCESS); + } + + return res; +} + +int DT_queryinfo_case0(Params_t * params_ptr, FFT_Cmd_t * cmd) +{ + DT_Tdep_Print_Head *phead; + phead = params_ptr->phead; + DT_Tdep_PT_Printf(phead, + "Description: Verify IA Querying information is successful using\nDAT_IA_QUERY.\n"); + return DT_queryinfo_basic(params_ptr, cmd, QUERY_IA, DAT_SUCCESS); +} + +int DT_queryinfo_case1(Params_t * params_ptr, FFT_Cmd_t * cmd) +{ + DT_Tdep_Print_Head *phead; + phead = params_ptr->phead; + DT_Tdep_PT_Printf(phead, + "Description: Verify CNO Querying information is successful using\nDAT_CNO_QUERY.\n"); + return DT_queryinfo_basic(params_ptr, cmd, QUERY_CNO, DAT_SUCCESS); +} + +int DT_queryinfo_case2(Params_t * params_ptr, FFT_Cmd_t * cmd) +{ + DT_Tdep_Print_Head *phead; + phead = params_ptr->phead; + DT_Tdep_PT_Printf(phead, + "Description: Verify EVD Querying information is successful using\nDAT_EVD_QUERY.\n"); + return DT_queryinfo_basic(params_ptr, cmd, QUERY_EVD, DAT_SUCCESS); +} + +int DT_queryinfo_case3(Params_t * params_ptr, FFT_Cmd_t * cmd) +{ + DT_Tdep_Print_Head *phead; + phead = params_ptr->phead; + DT_Tdep_PT_Printf(phead, + "Description: Verify PSP Querying information is successful using\nDAT_PSP_QUERY.\n"); + return DT_queryinfo_basic(params_ptr, cmd, QUERY_PSP, DAT_SUCCESS); +} + +int DT_queryinfo_case4(Params_t * params_ptr, FFT_Cmd_t * cmd) +{ + DT_Tdep_Print_Head *phead; + phead = params_ptr->phead; + DT_Tdep_PT_Printf(phead, + "Description: Verify RSP Querying information is successful using\nDAT_RSP_QUERY.\n"); + return DT_queryinfo_basic(params_ptr, cmd, QUERY_RSP, DAT_SUCCESS); +} + +int DT_queryinfo_case5(Params_t * params_ptr, FFT_Cmd_t * cmd) +{ + DT_Tdep_Print_Head *phead; + phead = params_ptr->phead; + DT_Tdep_PT_Printf(phead, + "Description: Verify CR Querying information is successful using\nDAT_CR_QUERY.\n"); + return DT_queryinfo_basic(params_ptr, cmd, QUERY_CR, DAT_SUCCESS); +} + +int DT_queryinfo_case6(Params_t * params_ptr, FFT_Cmd_t * cmd) +{ + DT_Tdep_Print_Head *phead; + phead = params_ptr->phead; + DT_Tdep_PT_Printf(phead, + "Description: Verify EP Querying information is successful using\nDAT_EP_QUERY.\n"); + return DT_queryinfo_basic(params_ptr, cmd, QUERY_EP, DAT_SUCCESS); +} + +int DT_queryinfo_case7(Params_t * params_ptr, FFT_Cmd_t * cmd) +{ + DT_Tdep_Print_Head *phead; + phead = params_ptr->phead; + DT_Tdep_PT_Printf(phead, + "Description: Verify PZ Querying information is successful using\n"); + DT_Tdep_PT_Printf(phead, "DAT_PZ_QUERY\n"); + return DT_queryinfo_basic(params_ptr, cmd, QUERY_PZ, DAT_SUCCESS); +} + +int DT_queryinfo_case8(Params_t * params_ptr, FFT_Cmd_t * cmd) +{ + DT_Tdep_Print_Head *phead; + phead = params_ptr->phead; + DT_Tdep_PT_Printf(phead, + "Description: Verify LMR Querying information is successful using\n"); + DT_Tdep_PT_Printf(phead, "DAT_LMR_QUERY\n"); + return DT_queryinfo_basic(params_ptr, cmd, QUERY_LMR, DAT_SUCCESS); +} + +int DT_queryinfo_case9(Params_t * params_ptr, FFT_Cmd_t * cmd) +{ + DT_Tdep_Print_Head *phead; + phead = params_ptr->phead; + DT_Tdep_PT_Printf(phead, + "Description: Verify RMR Querying information is successful using\n"); + DT_Tdep_PT_Printf(phead, "DAT_RMR_QUERY\n"); + return DT_queryinfo_basic(params_ptr, cmd, QUERY_RMR, DAT_SUCCESS); +} + +int DT_queryinfo_case10(Params_t * params_ptr, FFT_Cmd_t * cmd) +{ + DT_Tdep_Print_Head *phead; + phead = params_ptr->phead; + DT_Tdep_PT_Printf(phead, + "Description: Verify IA Querying fails with DAT_INVALID_PARAMETER when\n"); + DT_Tdep_PT_Printf(phead, "passing a bad parameter to DAT_IA_QUERY\n"); + return DT_queryinfo_basic(params_ptr, cmd, QUERY_IA, + DAT_INVALID_PARAMETER); +} + +int DT_queryinfo_case11(Params_t * params_ptr, FFT_Cmd_t * cmd) +{ + DT_Tdep_Print_Head *phead; + phead = params_ptr->phead; + DT_Tdep_PT_Printf(phead, + "Description: Verify IA Querying fails with DAT_INVALID_HANDLE when\n"); + DT_Tdep_PT_Printf(phead, "passing an invalid handle to DAT_IA_QUERY\n"); + return DT_queryinfo_basic(params_ptr, cmd, QUERY_IA, + DAT_INVALID_HANDLE); +} + +int DT_queryinfo_case12(Params_t * params_ptr, FFT_Cmd_t * cmd) +{ + DT_Tdep_Print_Head *phead; + phead = params_ptr->phead; + DT_Tdep_PT_Printf(phead, + "Description: Verify CNO Querying fails with DAT_INVALID_PARAMETER when\n"); + DT_Tdep_PT_Printf(phead, "passing a bad parameter to DAT_CNO_QUERY\n"); + return DT_queryinfo_basic(params_ptr, cmd, QUERY_CNO, + DAT_INVALID_PARAMETER); +} + +int DT_queryinfo_case13(Params_t * params_ptr, FFT_Cmd_t * cmd) +{ + DT_Tdep_Print_Head *phead; + phead = params_ptr->phead; + DT_Tdep_PT_Printf(phead, + "Description: Verify CNO Querying fails with DAT_INVALID_HANDLE when\n"); + DT_Tdep_PT_Printf(phead, + "passing an invalid handle to DAT_CNO_QUERY\n"); + return DT_queryinfo_basic(params_ptr, cmd, QUERY_CNO, + DAT_INVALID_HANDLE); +} + +int DT_queryinfo_case14(Params_t * params_ptr, FFT_Cmd_t * cmd) +{ + DT_Tdep_Print_Head *phead; + phead = params_ptr->phead; + DT_Tdep_PT_Printf(phead, + "Description: Verify EVD Querying fails with DAT_INVALID_PARAMETER when\n"); + DT_Tdep_PT_Printf(phead, "passing a bad parameter to DAT_EVD_QUERY\n"); + return DT_queryinfo_basic(params_ptr, cmd, QUERY_EVD, + DAT_INVALID_PARAMETER); +} + +int DT_queryinfo_case15(Params_t * params_ptr, FFT_Cmd_t * cmd) +{ + DT_Tdep_Print_Head *phead; + phead = params_ptr->phead; + DT_Tdep_PT_Printf(phead, + "Description: Verify EVD Querying fails with DAT_INVALID_HANDLE when\n"); + DT_Tdep_PT_Printf(phead, + "passing an invalid handle to DAT_EVD_QUERY\n"); + return DT_queryinfo_basic(params_ptr, cmd, QUERY_EVD, + DAT_INVALID_HANDLE); +} + +int DT_queryinfo_case16(Params_t * params_ptr, FFT_Cmd_t * cmd) +{ + DT_Tdep_Print_Head *phead; + phead = params_ptr->phead; + DT_Tdep_PT_Printf(phead, + "Description: Verify PSP Querying fails with DAT_INVALID_PARAMETER when\n"); + DT_Tdep_PT_Printf(phead, "passing a bad parameter to DAT_PSP_QUERY\n"); + return DT_queryinfo_basic(params_ptr, cmd, QUERY_PSP, + DAT_INVALID_PARAMETER); +} + +int DT_queryinfo_case17(Params_t * params_ptr, FFT_Cmd_t * cmd) +{ + DT_Tdep_Print_Head *phead; + phead = params_ptr->phead; + DT_Tdep_PT_Printf(phead, + "Description: Verify PSP Querying fails with DAT_INVALID_HANDLE when\n"); + DT_Tdep_PT_Printf(phead, + "passing an invalid handle to DAT_PSP_QUERY\n"); + return DT_queryinfo_basic(params_ptr, cmd, QUERY_PSP, + DAT_INVALID_HANDLE); +} + +/*-------------------------------------------------------------*/ +void DT_queryinfo_test(Params_t * params_ptr, FFT_Cmd_t * cmd) +{ + int i; + int res; + DT_Tdep_Print_Head *phead; + FFT_Testfunc_t cases_func[] = { + {DT_queryinfo_case0}, + {DT_queryinfo_case1}, + {DT_queryinfo_case2}, + {DT_queryinfo_case3}, + {DT_queryinfo_case4}, + {DT_queryinfo_case5}, + {DT_queryinfo_case6}, + {DT_queryinfo_case7}, + {DT_queryinfo_case8}, + {DT_queryinfo_case9}, + {DT_queryinfo_case10}, + {DT_queryinfo_case11}, +#ifndef __KDAPLTEST__ + {DT_queryinfo_case12}, + {DT_queryinfo_case13}, +#endif + {DT_queryinfo_case14}, + {DT_queryinfo_case15}, + {DT_queryinfo_case16}, + {DT_queryinfo_case17}, + }; + + phead = params_ptr->phead; + for (i = 0; i < cmd->size; i++) { + if (cmd->cases_flag[i]) { + DT_Tdep_PT_Printf(phead, + "*********************************************************************\n"); + DT_Tdep_PT_Printf(phead, + "Function feature: Queryinfo case: %d\n", + i); + res = cases_func[i].fun(params_ptr, cmd); + if (res == 1) { + DT_Tdep_PT_Printf(phead, "Result: PASS\n"); + } else if (res == 0) { + DT_Tdep_PT_Printf(phead, "Result: FAIL\n"); + } else if (res == -1) { + DT_Tdep_PT_Printf(phead, "Result: UNSUPP\n"); + } + + DT_Tdep_PT_Printf(phead, + "*********************************************************************\n"); + } + } + return; +} diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_fft_test.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_fft_test.c new file mode 100644 index 00000000..1ef1a87a --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_fft_test.c @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" + +DAT_RETURN DT_cs_FFT(Params_t * params_ptr, FFT_Cmd_t * cmd) +{ + DT_Tdep_Print_Head *phead; + DAT_RETURN rc = DAT_SUCCESS; + + phead = params_ptr->phead; + + switch (cmd->fft_type) { + case HWCONN: + { + DT_hwconn_test(params_ptr, cmd); + break; + } + case ENDPOINT: + { + DT_endpoint_test(params_ptr, cmd); + break; + } + case PTAGMGT: + { + DT_pz_test(params_ptr, cmd); + break; + } + case MEMMGT: + { + DT_mem_test(params_ptr, cmd); + break; + } + case CONNMGT: + { + DT_connmgt_test(params_ptr, cmd); + break; + } + case QUERYINFO: + { + DT_queryinfo_test(params_ptr, cmd); + break; + } +#if 0 // not yet implemented + case CONNMGT_CLIENT: + case NS: + case ERRHAND: + case UNSUPP: + case STRESS: + case STRESS_CLIENT: + case CQMGT: + { + DT_Tdep_PT_Printf(phead, "Not Yet Implemented\n"); + break; + } +#endif + default: + { + DT_Tdep_PT_Printf(phead, "don't know this test\n"); + rc = DAT_INVALID_PARAMETER; + break; + } + } + return rc; +} diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_fft_util.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_fft_util.c new file mode 100644 index 00000000..eeb32998 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_fft_util.c @@ -0,0 +1,360 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" + +#define DEFAULT_QUEUE_LEN 10 + +/* function that is called when an assertion fails, printing out the line + * that failed vi DT_Tdep_PT_Printf + */ +void DT_assert_fail(DT_Tdep_Print_Head * phead, char *exp, char *file, + char *baseFile, int line) +{ + if (!strcmp(file, baseFile)) { + DT_Tdep_PT_Printf(phead, + "%s failed in file %s, line %d\n", + exp, file, line); + } else { + DT_Tdep_PT_Printf(phead, + "%s failed in file %s (included from %s), line %d\n", + exp, file, baseFile, line); + } +} + +/* helper function to open an IA */ +int DT_ia_open(DAT_NAME_PTR dev_name, DAT_IA_HANDLE * ia_handle) +{ + DAT_EVD_HANDLE evd_handle; + evd_handle = DAT_HANDLE_NULL; + return dat_ia_open(dev_name, DEFAULT_QUEUE_LEN, &evd_handle, ia_handle); +} + +/* helper function to create an endpoint and its associated EVDs */ +int DT_ep_create(Params_t * params_ptr, + DAT_IA_HANDLE ia_handle, + DAT_PZ_HANDLE pz_handle, + DAT_EVD_HANDLE * cr_evd, + DAT_EVD_HANDLE * conn_evd, + DAT_EVD_HANDLE * send_evd, + DAT_EVD_HANDLE * recv_evd, DAT_EP_HANDLE * ep_handle) +{ + DAT_RETURN status; + DT_Tdep_Print_Head *phead; + *conn_evd = 0; + *send_evd = 0; + *recv_evd = 0; + *cr_evd = 0; + phead = params_ptr->phead; + + status = + DT_Tdep_evd_create(ia_handle, DEFAULT_QUEUE_LEN, DAT_HANDLE_NULL, + DAT_EVD_CR_FLAG, cr_evd); + if (status != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, "dat_evd_create failed %s\n", + DT_RetToString(status)); + return status; + } + + status = + DT_Tdep_evd_create(ia_handle, DEFAULT_QUEUE_LEN, DAT_HANDLE_NULL, + DAT_EVD_CONNECTION_FLAG, conn_evd); + if (status != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, "dat_evd_create failed %s\n", + DT_RetToString(status)); + return status; + } + + status = + DT_Tdep_evd_create(ia_handle, DEFAULT_QUEUE_LEN, DAT_HANDLE_NULL, + DAT_EVD_DTO_FLAG | DAT_EVD_RMR_BIND_FLAG, + send_evd); + if (status != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, "dat_evd_create failed %s\n", + DT_RetToString(status)); + return status; + } + + status = + DT_Tdep_evd_create(ia_handle, DEFAULT_QUEUE_LEN, DAT_HANDLE_NULL, + DAT_EVD_DTO_FLAG, recv_evd); + if (status != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, "dat_evd_create failed %s\n", + DT_RetToString(status)); + return status; + } + + status = dat_ep_create(ia_handle, pz_handle, *recv_evd, + *send_evd, *conn_evd, NULL, ep_handle); + if (status != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, "dat_ep_create failed %s\n", + DT_RetToString(status)); + } + return status; +} + +/* function that initializes the connection struct */ +void DT_fft_init_conn_struct(FFT_Connection_t * conn) +{ + conn->ia_handle = 0; + conn->pz_handle = 0; + conn->psp_handle = 0; + conn->ep_handle = 0; + conn->cr_evd = 0; + conn->send_evd = 0; + conn->conn_evd = 0; + conn->recv_evd = 0; + conn->cr_handle = 0; + conn->remote_netaddr = 0; + conn->bpool = 0; + conn->pt_ptr = 0; + conn->connected = false; +} + +/* helper function that simplifies many dat calls for the initiialization of a + * dat "client" + */ +void DT_fft_init_client(Params_t * params_ptr, FFT_Cmd_t * cmd, + FFT_Connection_t * conn) +{ + int res; + DAT_RETURN rc = 0; + DT_Tdep_Print_Head *phead; + phead = params_ptr->phead; + + /* initialize the struct's members */ + DT_fft_init_conn_struct(conn); + + /* open the IA */ + rc = DT_ia_open(cmd->device_name, &conn->ia_handle); + if (rc != DAT_SUCCESS) { + /* make sure the handle has an invalid value */ + conn->ia_handle = NULL; + } + DT_assert_dat(phead, rc == DAT_SUCCESS); + + /* create a PZ */ + rc = dat_pz_create(conn->ia_handle, &conn->pz_handle); + DT_assert_dat(phead, rc == DAT_SUCCESS); + + /* create an EP and its EVDs */ + rc = DT_ep_create(params_ptr, + conn->ia_handle, + conn->pz_handle, + &conn->cr_evd, + &conn->conn_evd, + &conn->send_evd, &conn->recv_evd, &conn->ep_handle); + DT_assert_dat(phead, rc == DAT_SUCCESS); + + /* if a server name is given, allocate memory for a net address and set it + * up appropriately + */ + if (cmd->server_name && strlen(cmd->server_name)) { + conn->remote_netaddr = ¶ms_ptr->server_netaddr; + } + cleanup: + return; +} + +/* helper function to break down a client or server created with one of the + * init helper functions + */ +int DT_fft_destroy_conn_struct(Params_t * params_ptr, FFT_Connection_t * conn) +{ + DAT_RETURN rc = DAT_SUCCESS; + DT_Tdep_Print_Head *phead; + phead = params_ptr->phead; + + if (conn->ep_handle) { + if (conn->connected) { + rc = dat_ep_disconnect(conn->ep_handle, + DAT_CLOSE_DEFAULT); + DT_assert_clean(phead, rc == DAT_SUCCESS); + + if (!DT_disco_event_wait(phead, conn->cr_evd, NULL)) + { + DT_Tdep_PT_Printf(phead, + "DT_fft_destroy_conn_struct: bad disconnect event\n"); + } + } + rc = dat_ep_free(conn->ep_handle); + DT_assert_clean(phead, rc == DAT_SUCCESS); + } + if (conn->bpool) { + DT_Bpool_Destroy(0, phead, conn->bpool); + } + if (conn->psp_handle) { + rc = dat_psp_free(conn->psp_handle); + DT_assert_clean(phead, rc == DAT_SUCCESS); + } + if (conn->cr_evd) { + rc = DT_Tdep_evd_free(conn->cr_evd); + DT_assert_clean(phead, rc == DAT_SUCCESS); + } + if (conn->conn_evd) { + rc = DT_Tdep_evd_free(conn->conn_evd); + DT_assert_clean(phead, rc == DAT_SUCCESS); + } + if (conn->send_evd) { + rc = DT_Tdep_evd_free(conn->send_evd); + DT_assert_clean(phead, rc == DAT_SUCCESS); + } + if (conn->recv_evd) { + rc = DT_Tdep_evd_free(conn->recv_evd); + DT_assert_clean(phead, rc == DAT_SUCCESS); + } + if (conn->pt_ptr) { + DT_Free_Per_Test_Data(conn->pt_ptr); + } + if (conn->pz_handle) { + rc = dat_pz_free(conn->pz_handle); + DT_assert_clean(phead, rc == DAT_SUCCESS); + } + if (conn->ia_handle) { + rc = dat_ia_close(conn->ia_handle, DAT_CLOSE_ABRUPT_FLAG); + DT_assert_clean(phead, rc == DAT_SUCCESS); + } + return rc; +} + +/* helper function to init a dat "server" */ +void DT_fft_init_server(Params_t * params_ptr, FFT_Cmd_t * cmd, + FFT_Connection_t * conn) +{ + int res; + DAT_RETURN rc = 0; + DT_Tdep_Print_Head *phead; + phead = params_ptr->phead; + + /* init the connection struct's members */ + DT_fft_init_conn_struct(conn); + + /* open the IA */ + rc = DT_ia_open(cmd->device_name, &conn->ia_handle); + DT_assert_dat(phead, rc == DAT_SUCCESS); + + /* create a PZ */ + rc = dat_pz_create(conn->ia_handle, &conn->pz_handle); + DT_assert_dat(phead, rc == DAT_SUCCESS); + + /* create an EP and its EVDs */ + rc = DT_ep_create(params_ptr, + conn->ia_handle, + conn->pz_handle, + &conn->cr_evd, + &conn->conn_evd, + &conn->send_evd, &conn->recv_evd, &conn->ep_handle); + DT_assert_dat(phead, rc == DAT_SUCCESS); + + /* create a PSP */ + rc = dat_psp_create(conn->ia_handle, SERVER_PORT_NUMBER, conn->cr_evd, + DAT_PSP_CONSUMER_FLAG, &conn->psp_handle); + DT_assert_dat(phead, rc == DAT_SUCCESS); + + /* allocate memory for buffers */ + conn->bpool = + DT_BpoolAlloc(0, phead, conn->ia_handle, conn->pz_handle, NULL, + NULL, 8192, 2, DAT_OPTIMAL_ALIGNMENT, false, false); + DT_assert(phead, conn->bpool); + cleanup: + return; +} + +/* helper function that allows a server to listen for a connection */ +void DT_fft_listen(Params_t * params_ptr, FFT_Connection_t * conn) +{ + int res; + DAT_RETURN rc = 0; + DT_Tdep_Print_Head *phead; + phead = params_ptr->phead; + + /* wait on a CR event via the CR EVD */ + DT_assert_dat(phead, + DT_cr_event_wait(phead, conn->cr_evd, &conn->cr_stat) + && DT_cr_check(phead, &conn->cr_stat, conn->psp_handle, + SERVER_PORT_NUMBER, &conn->cr_handle, + "DT_fft_listen")); + + /* accept the connection */ + rc = dat_cr_accept(conn->cr_handle, conn->ep_handle, 0, (DAT_PVOID) 0); + DT_assert_dat(phead, rc == DAT_SUCCESS); + + /* wait on a conn event via the conn EVD */ + DT_assert(phead, + DT_conn_event_wait(phead, + conn->ep_handle, + conn->conn_evd, &conn->event_num) == true); + conn->connected = true; + cleanup: + return; +} + +/* helper function that allows a client to connect to a server */ +int DT_fft_connect(Params_t * params_ptr, FFT_Connection_t * conn) +{ + int wait_count; + int res; + DAT_RETURN rc = 0; + DT_Tdep_Print_Head *phead; + phead = params_ptr->phead; + + /* try 10 times to connect */ + for (wait_count = 0; wait_count < 10; wait_count++) { + DT_Tdep_PT_Printf(phead, "Connection to server, attempt #%d\n", + wait_count + 1); + + /* attempt to connect, timeout = 10 secs */ + rc = dat_ep_connect(conn->ep_handle, conn->remote_netaddr, + SERVER_PORT_NUMBER, 10 * 1000000, 0, + (DAT_PVOID) 0, DAT_QOS_BEST_EFFORT, + DAT_CONNECT_DEFAULT_FLAG); + DT_assert_dat(phead, rc == DAT_SUCCESS); + + /* wait on conn event */ + DT_assert(phead, + DT_conn_event_wait(phead, + conn->ep_handle, + conn->conn_evd, + &conn->event_num) == true); + + /* make sure we weren't rejected by the peer */ + if (conn->event_num == DAT_CONNECTION_EVENT_PEER_REJECTED) { + DT_Mdep_Sleep(1000); + DT_Tdep_PT_Printf(phead, + "Connection rejected by peer; retrying\n"); + } + } + cleanup: + if (conn->event_num == DAT_CONNECTION_EVENT_ESTABLISHED) { + conn->connected = true; + } + /* returns true if connected, false otherwise */ + return (conn->connected); +} diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_limit.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_limit.c new file mode 100644 index 00000000..6b299fab --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_limit.c @@ -0,0 +1,1536 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" + +/* + * Increase the size of an array of handles + */ + +static bool more_handles(DT_Tdep_Print_Head * phead, DAT_HANDLE ** old_ptrptr, /* pointer to current pointer */ + unsigned int *old_count, /* number pointed to */ + unsigned int size) +{ /* size of one datum */ + unsigned int count = *old_count; + DAT_HANDLE *old_handles = *old_ptrptr; + DAT_HANDLE *handle_tmp = DT_Mdep_Malloc(count * 2 * size); + + if (!handle_tmp) { + DT_Tdep_PT_Printf(phead, + "Out of memory for more DAT_HANDLEs\n"); + return (false); + } + + memcpy(handle_tmp, old_handles, count * size); + DT_Mdep_Free(old_handles); + *old_ptrptr = handle_tmp; + *old_count = count * 2; + return (true); +} + +/* + * Limit test workhorse. + * + * This test creates the sequence of DAT objects needed to move + * data back and forth, attempting to find the limits supported + * for the DAT object indicated by 'depth'. For example, if + * depth == LIM_LMR, the test will create a set of {IA,PZ,CNO,EVD,EP} + * before trying to exhaust LMR creation using the {IA,PZ,CNO,EVD,EP} set. + * + * The 'cmd->width' parameter can be used to control how may of these + * parallel DAT object sets we create before stopping to beat upon + * the constructor for the object indicated by 'depth', providing for + * increased (or at least different) stress on the DAPL. + */ +static bool +limit_test(DT_Tdep_Print_Head * phead, Limit_Cmd_t * cmd, Limit_Index depth) +{ + DAT_EVD_HANDLE conn_handle; + typedef struct obj_set { + DAT_IA_HANDLE ia_handle; + DAT_EVD_HANDLE ia_async_handle; + DAT_PZ_HANDLE pz_handle; + DAT_CNO_HANDLE cno_handle; + DAT_EVD_HANDLE evd_handle; + DAT_EP_HANDLE ep_handle; + DAT_LMR_HANDLE lmr_handle; + char *lmr_buffer; + DAT_LMR_CONTEXT lmr_context; + DAT_RMR_HANDLE rmr_handle; + DAT_RMR_CONTEXT rmr_context; + } Obj_Set; + + Obj_Set *hdl_sets = (Obj_Set *) NULL; + bool retval = false; + char *module = "LimitTest"; + +#if defined (WIN32) + /* + * The Windows compiler will not deal with complex definitions + * in macros, so create a variable here. + */ +#if defined (DAT_OS_WAIT_PROXY_AGENT_NULL) +#undef DAT_OS_WAIT_PROXY_AGENT_NULL +#endif + DAT_OS_WAIT_PROXY_AGENT DAT_OS_WAIT_PROXY_AGENT_NULL = { NULL, NULL }; +#endif + + DAT_RETURN ret; + +#ifdef DFLT_QLEN +#undef DFLT_QLEN +#endif + +# define DFLT_QLEN 10 /* a small event queue size */ +# define START_COUNT 1024 /* initial # handles */ +# define DFLT_BUFFSZ 4096 /* default size for buffer */ +# define CONN_QUAL0 0xAffab1e + + /* Allocate 'width' Obj_Sets */ + if (depth && !(hdl_sets = DT_Mdep_Malloc(sizeof(Obj_Set) * cmd->width))) { + DT_Tdep_PT_Printf(phead, "%s: No memory for handle array!\n", + module); + goto clean_up_now; + } + + /* ----------- + * IA handling + */ + if (depth > LIM_IA) { + /* + * The abuse is not for us this time, just prep Obj_Set. + */ + unsigned int w; + + DT_Tdep_PT_Debug(1, (phead, + "%s: dat_ia_open X %d\n", + module, cmd->width)); + for (w = 0; w < cmd->width; w++) { + /* Specify that we want to get back an async EVD. */ + hdl_sets[w].ia_async_handle = DAT_HANDLE_NULL; + ret = dat_ia_open(cmd->device_name, + DFLT_QLEN, + &hdl_sets[w].ia_async_handle, + &hdl_sets[w].ia_handle); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_ia_open (%s) #%d fails: %s\n", + module, cmd->device_name, + w + 1, DT_RetToString(ret)); + /* handle contents undefined on failure */ + hdl_sets[w].ia_async_handle = DAT_HANDLE_NULL; + hdl_sets[w].ia_handle = DAT_HANDLE_NULL; + goto clean_up_now; + } + } + } else if (depth == LIM_IA) { + /* + * See how many IAs we can create + */ + typedef struct _ia { + DAT_IA_HANDLE ia_handle; + DAT_EVD_HANDLE ia_async_handle; + } OneOpen; + unsigned int count = START_COUNT; + OneOpen *hdlptr = (OneOpen *) + DT_Mdep_Malloc(count * sizeof(*hdlptr)); + + /* IA Exhaustion test loop */ + if (hdlptr) { + unsigned int w = 0; + unsigned int tmp; + + DT_Tdep_PT_Debug(1, + (phead, "%s: Exhausting dat_ia_open\n", + module)); + for (w = 0; w < cmd->maximum; w++) { + DT_Mdep_Schedule(); + if (w == count + && !more_handles(phead, + (DAT_HANDLE **) & hdlptr, + &count, sizeof(*hdlptr))) { + DT_Tdep_PT_Printf(phead, + "%s: IAs opened: %d\n", + module, w); + retval = true; + break; + } + /* Specify that we want to get back an async EVD. */ + hdlptr[w].ia_async_handle = DAT_HANDLE_NULL; + ret = dat_ia_open(cmd->device_name, + DFLT_QLEN, + &hdlptr[w].ia_async_handle, + &hdlptr[w].ia_handle); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_ia_open (%s) #%d fails: %s\n", + module, + cmd->device_name, + w + 1, + DT_RetToString(ret)); + retval = true; + break; + } + } + + DT_Tdep_PT_Printf(phead, "%s: IAs opened: %d\n", module, + w); + retval = true; + + /* IA Cleanup loop */ + for (tmp = 0; tmp < w; tmp++) { + DT_Mdep_Schedule(); + ret = dat_ia_close(hdlptr[tmp].ia_handle, + DAT_CLOSE_GRACEFUL_FLAG); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_ia_close (graceful) fails: %s\n", + module, + DT_RetToString(ret)); + retval = false; + ret = + dat_ia_close(hdlptr[tmp].ia_handle, + DAT_CLOSE_ABRUPT_FLAG); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_ia_close (abrupt) fails: %s\n", + module, + DT_RetToString + (ret)); + } + } + } + DT_Mdep_Free(hdlptr); + } + } + + /* End IA handling */ + /* ----------- + * PZ handling + */ + if (depth > LIM_PZ) { + /* + * The abuse is not for us this time, just prep Obj_Set. + */ + unsigned int w; + + DT_Tdep_PT_Debug(1, (phead, + "%s: dat_pz_create X %d\n", + module, cmd->width)); + for (w = 0; w < cmd->width; w++) { + ret = dat_pz_create(hdl_sets[w].ia_handle, + &hdl_sets[w].pz_handle); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_pz_create #%d fails: %s\n", + module, w + 1, + DT_RetToString(ret)); + /* handle contents undefined on failure */ + hdl_sets[w].pz_handle = DAT_HANDLE_NULL; + goto clean_up_now; + } + } + } else if (depth == LIM_PZ) { + /* + * See how many PZs we can create + */ + unsigned int count = START_COUNT; + DAT_PZ_HANDLE *hdlptr = (DAT_PZ_HANDLE *) + DT_Mdep_Malloc(count * sizeof(*hdlptr)); + + /* PZ Exhaustion test loop */ + if (hdlptr) { + unsigned int w = 0; + unsigned int tmp; + + DT_Tdep_PT_Debug(1, (phead, + "%s: Exhausting dat_pz_create\n", + module)); + for (w = 0; w < cmd->maximum; w++) { + DT_Mdep_Schedule(); + if (w == count + && !more_handles(phead, + (DAT_HANDLE **) & hdlptr, + &count, sizeof(*hdlptr))) { + DT_Tdep_PT_Printf(phead, + "%s: PZs created: %d\n", + module, w); + retval = true; + break; + } + ret = + dat_pz_create(hdl_sets[w % cmd->width]. + ia_handle, &hdlptr[w]); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_pz_create #%d fails: %s\n", + module, w + 1, + DT_RetToString(ret)); + retval = true; + break; + } + } + + DT_Tdep_PT_Printf(phead, "%s: PZs created: %d\n", + module, w); + retval = true; + + /* PZ Cleanup loop */ + for (tmp = 0; tmp < w; tmp++) { + DT_Mdep_Schedule(); + ret = dat_pz_free(hdlptr[tmp]); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_pz_free fails: %s\n", + module, + DT_RetToString(ret)); + retval = false; + } + } + DT_Mdep_Free(hdlptr); + } + } + /* End PZ handling */ +#ifndef __KDAPLTEST__ + /* ----------- + * CNO handling + */ + + if (depth > LIM_CNO) { + /* + * The abuse is not for us this time, just prep Obj_Set. + */ + unsigned int w; + + DT_Tdep_PT_Debug(1, (phead, + "%s: dat_cno_create X %d\n", + module, cmd->width)); + for (w = 0; w < cmd->width; w++) { + ret = dat_cno_create(hdl_sets[w].ia_handle, + DAT_OS_WAIT_PROXY_AGENT_NULL, + &hdl_sets[w].cno_handle); + if (DAT_GET_TYPE(ret) == DAT_NOT_IMPLEMENTED) { + DT_Tdep_PT_Printf(phead, + "%s: dat_cno_create unimplemented\n", + module); + hdl_sets[w].cno_handle = DAT_HANDLE_NULL; + /* ignore this error */ + break; + } else if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_cno_create #%d fails: %s\n", + module, w + 1, + DT_RetToString(ret)); + /* handle contents undefined on failure */ + hdl_sets[w].cno_handle = DAT_HANDLE_NULL; + goto clean_up_now; + } + } + } else if (depth == LIM_CNO) { + /* + * See how many CNOs we can create + */ + unsigned int count = START_COUNT; + DAT_CNO_HANDLE *hdlptr = (DAT_CNO_HANDLE *) + DT_Mdep_Malloc(count * sizeof(*hdlptr)); + + /* CNO Exhaustion test loop */ + if (hdlptr) { + unsigned int w = 0; + unsigned int tmp; + + DT_Tdep_PT_Debug(1, (phead, + "%s: Exhausting dat_cno_create\n", + module)); + for (w = 0; w < cmd->maximum; w++) { + DT_Mdep_Schedule(); + if (w == count + && !more_handles(phead, + (DAT_HANDLE **) & hdlptr, + &count, sizeof(*hdlptr))) { + DT_Tdep_PT_Printf(phead, + "%s: CNOs created: %d\n", + module, w); + retval = true; + break; + } + ret = + dat_cno_create(hdl_sets[w % cmd->width]. + ia_handle, + DAT_OS_WAIT_PROXY_AGENT_NULL, + &hdlptr[w]); + if (DAT_GET_TYPE(ret) == DAT_NOT_IMPLEMENTED) { + DT_Tdep_PT_Printf(phead, + "%s: dat_cno_create unimplemented\n", + module); + retval = true; + break; + } else if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_cno_create #%d fails: %s\n", + module, w + 1, + DT_RetToString(ret)); + retval = true; + break; + } + } + + DT_Tdep_PT_Printf(phead, "%s: CNOs created: %d\n", + module, w); + retval = true; + + /* CNO Cleanup loop */ + for (tmp = 0; tmp < w; tmp++) { + DT_Mdep_Schedule(); + ret = dat_cno_free(hdlptr[tmp]); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_cno_free fails: %s\n", + module, + DT_RetToString(ret)); + retval = false; + } + } + DT_Mdep_Free(hdlptr); + } + } /* End CNO handling */ +#endif /* __KDAPLTEST__ */ + + /* ----------- + * EVD handling + */ + if (depth > LIM_EVD) { + /* + * The abuse is not for us this time, just prep Obj_Set. + */ + unsigned int w = 0; + DAT_EVD_FLAGS flags = (DAT_EVD_DTO_FLAG + /* | DAT_EVD_SOFTWARE_FLAG */ + | DAT_EVD_CR_FLAG | DAT_EVD_RMR_BIND_FLAG); /* not ASYNC */ + + DT_Tdep_PT_Debug(1, (phead, + "%s: dat_evd_create X %d\n", + module, cmd->width)); + /* + * First create a connection EVD to be used for EP creation + */ + + ret = DT_Tdep_evd_create(hdl_sets[0].ia_handle, + DFLT_QLEN, + NULL, + DAT_EVD_CONNECTION_FLAG, &conn_handle); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: conn dat_evd_create #%d fails: %s\n", + module, w + 1, DT_RetToString(ret)); + /* handle contents undefined on failure */ + conn_handle = DAT_HANDLE_NULL; + goto clean_up_now; + } + for (w = 0; w < cmd->width; w++) { + ret = DT_Tdep_evd_create(hdl_sets[w].ia_handle, + DFLT_QLEN, + hdl_sets[w].cno_handle, + flags, + &hdl_sets[w].evd_handle); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_evd_create #%d fails: %s\n", + module, w + 1, + DT_RetToString(ret)); + /* handle contents undefined on failure */ + hdl_sets[w].evd_handle = DAT_HANDLE_NULL; + goto clean_up_now; + } + } + } else if (depth == LIM_EVD) { + /* + * See how many EVDs we can create + */ + unsigned int count = START_COUNT; + DAT_EVD_HANDLE *hdlptr = (DAT_EVD_HANDLE *) + DT_Mdep_Malloc(count * sizeof(*hdlptr)); + DAT_EVD_FLAGS flags = (DAT_EVD_DTO_FLAG + | DAT_EVD_RMR_BIND_FLAG + | DAT_EVD_CR_FLAG); + + /* EVD Exhaustion test loop */ + if (hdlptr) { + unsigned int w = 0; + unsigned int tmp; + + DT_Tdep_PT_Debug(1, (phead, + "%s: Exhausting dat_evd_create\n", + module)); + /* + * First create a connection EVD to be used for EP creation + */ + ret = DT_Tdep_evd_create(hdl_sets[0].ia_handle, + DFLT_QLEN, + NULL, + DAT_EVD_CONNECTION_FLAG, + &conn_handle); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: conn dat_evd_create #%d fails: %s\n", + module, w + 1, + DT_RetToString(ret)); + /* handle contents undefined on failure */ + conn_handle = DAT_HANDLE_NULL; + } + for (w = 0; w < cmd->maximum; w++) { + DT_Mdep_Schedule(); + if (w == count + && !more_handles(phead, + (DAT_HANDLE **) & hdlptr, + &count, sizeof(*hdlptr))) { + DT_Tdep_PT_Printf(phead, + "%s: EVDs created: %d\n", + module, w); + retval = true; + break; + } + ret = + DT_Tdep_evd_create(hdl_sets[w % cmd->width]. + ia_handle, DFLT_QLEN, + hdl_sets[w % + cmd->width]. + cno_handle, flags, + &hdlptr[w]); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_evd_create #%d fails: %s\n", + module, w + 1, + DT_RetToString(ret)); + retval = true; + break; + } + } + + DT_Tdep_PT_Printf(phead, "%s: EVDs created: %d\n", + module, w); + retval = true; + + /* EVD Cleanup loop */ + if (conn_handle != DAT_HANDLE_NULL) { + ret = DT_Tdep_evd_free(conn_handle); + conn_handle = DAT_HANDLE_NULL; + } + for (tmp = 0; tmp < w; tmp++) { + DT_Mdep_Schedule(); + ret = DT_Tdep_evd_free(hdlptr[tmp]); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_evd_free fails: %s\n", + module, + DT_RetToString(ret)); + retval = false; + } + } + DT_Mdep_Free(hdlptr); + } + } + + /* End EVD handling */ + /* ----------- + * EP handling + */ + if (depth > LIM_EP) { + /* + * The abuse is not for us this time, just prep Obj_Set. + */ + unsigned int w; + + DT_Tdep_PT_Debug(1, (phead, + "%s: dat_ep_create X %d\n", + module, cmd->width)); + for (w = 0; w < cmd->width; w++) { + ret = dat_ep_create(hdl_sets[w].ia_handle, hdl_sets[w].pz_handle, hdl_sets[w].evd_handle, /* recv */ + hdl_sets[w].evd_handle, /* request */ + conn_handle, /* connect */ + (DAT_EP_ATTR *) NULL, + &hdl_sets[w].ep_handle); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_ep_create #%d fails: %s\n", + module, w + 1, + DT_RetToString(ret)); + /* handle contents undefined on failure */ + hdl_sets[w].ep_handle = DAT_HANDLE_NULL; + goto clean_up_now; + } + } + } else if (depth == LIM_EP) { + /* + * See how many EPs we can create + */ + unsigned int count = START_COUNT; + DAT_EP_HANDLE *hdlptr = (DAT_EP_HANDLE *) + DT_Mdep_Malloc(count * sizeof(*hdlptr)); + + /* EP Exhaustion test loop */ + if (hdlptr) { + unsigned int w = 0; + unsigned int tmp; + + DT_Tdep_PT_Debug(1, + (phead, + "%s: Exhausting dat_ep_create\n", + module)); + for (w = 0; w < cmd->maximum; w++) { + DT_Mdep_Schedule(); + if (w == count + && !more_handles(phead, + (DAT_HANDLE **) & hdlptr, + &count, sizeof(*hdlptr))) { + DT_Tdep_PT_Printf(phead, + "%s: EPs created: %d\n", + module, w); + retval = true; + break; + } + ret = dat_ep_create(hdl_sets[w % cmd->width].ia_handle, hdl_sets[w % cmd->width].pz_handle, hdl_sets[w % cmd->width].evd_handle, hdl_sets[w % cmd->width].evd_handle, conn_handle, /* connect */ + (DAT_EP_ATTR *) NULL, + &hdlptr[w]); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_ep_create #%d fails: %s\n", + module, w + 1, + DT_RetToString(ret)); + retval = true; + break; + } + } + + DT_Tdep_PT_Printf(phead, "%s: EPs created: %d\n", + module, w); + retval = true; + + /* EP Cleanup loop */ + for (tmp = 0; tmp < w; tmp++) { + DT_Mdep_Schedule(); + ret = dat_ep_free(hdlptr[tmp]); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_ep_free fails: %s\n", + module, + DT_RetToString(ret)); + retval = false; + } + } + DT_Mdep_Free(hdlptr); + } + } + + /* End EP handling */ + /* ----------- + * RSP handling + * + * if (depth > LIM_RSP) { + * Since RSPs are not part of the Obj_Set, + * there's nothing to do. + * } else ... + */ + if (depth == LIM_RSP) { + /* + * See how many RSPs we can create + */ + unsigned int count = START_COUNT; + DAT_RSP_HANDLE *hdlptr = (DAT_RSP_HANDLE *) + DT_Mdep_Malloc(count * sizeof(*hdlptr)); + DAT_EP_HANDLE *epptr = (DAT_EP_HANDLE *) + DT_Mdep_Malloc(count * sizeof(*epptr)); + + /* RSP Exhaustion test loop */ + if (hdlptr) { + unsigned int w = 0; + unsigned int tmp; + + DT_Tdep_PT_Debug(1, + (phead, + "%s: Exhausting dat_rsp_create\n", + module)); + for (w = 0; w < cmd->maximum; w++) { + DT_Mdep_Schedule(); + if (w == count) { + unsigned int count1 = count; + unsigned int count2 = count; + + if (!more_handles + (phead, (DAT_HANDLE **) & hdlptr, + &count1, sizeof(*hdlptr))) { + DT_Tdep_PT_Printf(phead, + "%s: RSPs created: %d\n", + module, w); + retval = true; + break; + } + if (!more_handles + (phead, (DAT_HANDLE **) & epptr, + &count2, sizeof(*epptr))) { + DT_Tdep_PT_Printf(phead, + "%s: RSPs created: %d\n", + module, w); + retval = true; + break; + } + + if (count1 != count2) { + DT_Tdep_PT_Printf(phead, + "%s: Mismatch in allocation of handle arrays at point %d\n", + module, w); + retval = true; + break; + } + + count = count1; + } + + /* + * Each RSP needs a unique EP, so create one first + */ + ret = + dat_ep_create(hdl_sets[w % cmd->width]. + ia_handle, + hdl_sets[w % + cmd->width]. + pz_handle, + hdl_sets[w % + cmd->width]. + evd_handle, + hdl_sets[w % + cmd->width]. + evd_handle, conn_handle, + (DAT_EP_ATTR *) NULL, + &epptr[w]); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_ep_create #%d fails: %s testing RSPs\n", + module, w + 1, + DT_RetToString(ret)); + retval = true; + break; + } + + ret = + dat_rsp_create(hdl_sets[w % cmd->width]. + ia_handle, CONN_QUAL0 + w, + epptr[w], + hdl_sets[w % + cmd->width]. + evd_handle, &hdlptr[w]); + if (DAT_GET_TYPE(ret) == DAT_NOT_IMPLEMENTED) { + DT_Tdep_PT_Printf(phead, + "%s: dat_rsp_create unimplemented\n", + module); + /* ignore this error */ + retval = true; + break; + } else if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_rsp_create #%d fails: %s\n", + module, w + 1, + DT_RetToString(ret)); + /* Cleanup the EP; no-one else will. */ + ret = dat_ep_free(epptr[w]); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_ep_free (internal cleanup @ #%d) fails: %s\n", + module, w + 1, + DT_RetToString + (ret)); + } + retval = true; + break; + } + } + + DT_Tdep_PT_Printf(phead, "%s: RSPs created: %d\n", + module, w); + retval = true; + + /* RSP Cleanup loop */ + for (tmp = 0; tmp < w; tmp++) { + DT_Mdep_Schedule(); + ret = dat_rsp_free(hdlptr[tmp]); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_rsp_free fails: %s\n", + module, + DT_RetToString(ret)); + retval = false; + } + /* Free EPs */ + ret = dat_ep_free(epptr[tmp]); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_ep_free fails: %s for RSPs\n", + module, + DT_RetToString(ret)); + retval = false; + } + } + DT_Mdep_Free(hdlptr); + } + } + + /* End RSP handling */ + /* ----------- + * PSP handling + * + * if (depth > LIM_PSP) { + * Since PSPs are not part of the Obj_Set, + * there's nothing to do. + * } else ... + */ + if (depth == LIM_PSP) { + /* + * See how many PSPs we can create + */ + unsigned int count = START_COUNT; + DAT_PSP_HANDLE *hdlptr = (DAT_PSP_HANDLE *) + DT_Mdep_Malloc(count * sizeof(*hdlptr)); + + /* PSP Exhaustion test loop */ + if (hdlptr) { + unsigned int w = 0; + unsigned int tmp; + + DT_Tdep_PT_Debug(1, + (phead, + "%s: Exhausting dat_psp_create\n", + module)); + for (w = 0; w < cmd->maximum; w++) { + DT_Mdep_Schedule(); + if (w == count + && !more_handles(phead, + (DAT_HANDLE **) & hdlptr, + &count, sizeof(*hdlptr))) { + DT_Tdep_PT_Printf(phead, + "%s: PSPs created: %d\n", + module, w); + retval = true; + break; + } + ret = + dat_psp_create(hdl_sets[w % cmd->width]. + ia_handle, CONN_QUAL0 + w, + hdl_sets[w % + cmd->width]. + evd_handle, + DAT_PSP_CONSUMER_FLAG, + &hdlptr[w]); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_psp_create #%d fails: %s\n", + module, w + 1, + DT_RetToString(ret)); + retval = true; + hdlptr[w] = DAT_HANDLE_NULL; + break; + } + } + + DT_Tdep_PT_Printf(phead, "%s: PSPs created: %d\n", + module, w); + retval = true; + + /* PSP Cleanup loop */ + for (tmp = 0; tmp < w; tmp++) { + DT_Mdep_Schedule(); + ret = dat_psp_free(hdlptr[tmp]); + if (DAT_GET_TYPE(ret) == DAT_NOT_IMPLEMENTED) { + DT_Tdep_PT_Printf(phead, + "%s: dat_psp_free unimplemented\n" + "\tNB: Expect EVD+IA cleanup errors!\n", + module); + break; + } else if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_psp_free fails: %s\n", + module, + DT_RetToString(ret)); + retval = false; + } + } + DT_Mdep_Free(hdlptr); + } + } + + /* End PSP handling */ + /* ----------- + * LMR handling + */ + if (depth > LIM_LMR) { + /* + * The abuse is not for us this time, just prep Obj_Set. + */ + unsigned int w; + + DT_Tdep_PT_Debug(1, + (phead, "%s: dat_lmr_create X %d\n", module, + cmd->width)); + for (w = 0; w < cmd->width; w++) { + DAT_REGION_DESCRIPTION region; + DAT_VLEN reg_size; + DAT_VADDR reg_addr; + + hdl_sets[w].lmr_buffer = DT_Mdep_Malloc(DFLT_BUFFSZ); + if (!hdl_sets[w].lmr_buffer) { + DT_Tdep_PT_Printf(phead, + "%s: no memory for LMR buffers\n", + module); + goto clean_up_now; + } + memset(®ion, 0, sizeof(region)); + region.for_va = hdl_sets[w].lmr_buffer; + + ret = DT_Tdep_lmr_create(hdl_sets[w].ia_handle, DAT_MEM_TYPE_VIRTUAL, region, DFLT_BUFFSZ, hdl_sets[w].pz_handle, DAT_MEM_PRIV_ALL_FLAG, &hdl_sets[w].lmr_handle, &hdl_sets[w].lmr_context, NULL, /* FIXME */ + ®_size, ®_addr); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_lmr_create #%d fails: %s\n", + module, w + 1, + DT_RetToString(ret)); + /* handle contents undefined on failure */ + hdl_sets[w].lmr_handle = DAT_HANDLE_NULL; + goto clean_up_now; + } + if ((uintptr_t) reg_addr > + (uintptr_t) hdl_sets[w].lmr_buffer + || (reg_size < + DFLT_BUFFSZ + ((uintptr_t) reg_addr - + (uintptr_t) hdl_sets[w]. + lmr_buffer))) { + DT_Tdep_PT_Printf(phead, + "%s: dat_lmr_create bogus outputs " + "in: 0x%p, %x out 0x%llx, %llx\n", + module, + hdl_sets[w].lmr_buffer, + DFLT_BUFFSZ, reg_addr, + reg_size); + goto clean_up_now; + } + } + } else if (depth == LIM_LMR) { + /* + * See how many LMRs we can create + */ + unsigned int count = START_COUNT; + Bpool **hdlptr = (Bpool **) + DT_Mdep_Malloc(count * sizeof(*hdlptr)); + + /* LMR Exhaustion test loop */ + if (hdlptr) { + unsigned int w = 0; + unsigned int tmp; + + DT_Tdep_PT_Debug(1, + (phead, + "%s: Exhausting dat_lmr_create\n", + module)); + for (w = 0; w < cmd->maximum; w++) { + DT_Mdep_Schedule(); + if (w == count + && !more_handles(phead, + (DAT_HANDLE **) & hdlptr, + &count, sizeof(*hdlptr))) { + DT_Tdep_PT_Printf(phead, + "%s: no memory for LMR handles\n", + module); + DT_Tdep_PT_Printf(phead, + "%s: LMRs created: %d\n", + module, w); + retval = true; + break; + } + /* + * Let BpoolAlloc do the hard work; this means that + * we're testing unique memory registrations rather + * than repeatedly binding the same buffer set. + */ + hdlptr[w] = DT_BpoolAlloc((Per_Test_Data_t *) 0, + phead, + hdl_sets[w % + cmd->width]. + ia_handle, + hdl_sets[w % + cmd->width]. + pz_handle, + hdl_sets[w % + cmd->width]. + ep_handle, + hdl_sets[w % + cmd->width]. + evd_handle, + DFLT_BUFFSZ, 1, + DAT_OPTIMAL_ALIGNMENT, + false, false); + if (!hdlptr[w]) { + DT_Tdep_PT_Printf(phead, + "%s: LMRs created: %d\n", + module, w); + retval = true; + break; + } + } + + DT_Tdep_PT_Printf(phead, "%s: LMRs created: %d\n", + module, w); + retval = true; + + /* LMR Cleanup loop */ + for (tmp = 0; tmp <= w; tmp++) { + DT_Mdep_Schedule(); + if (hdlptr[tmp]) { + /* ignore rval - DT_Bpool_Destroy will complain */ + (void) + DT_Bpool_Destroy((Per_Test_Data_t *) + 0, phead, + hdlptr[tmp]); + } + } + DT_Mdep_Free(hdlptr); + } + } + + /* End LMR handling */ + /* ----------- + * Posted receive buffer handling + */ + if (depth == LIM_RPOST) { + /* + * See how many receive buffers we can post (to each EP). + * We are posting the same buffer 'cnt' times, deliberately, + * but that should be OK. + */ + unsigned int count = START_COUNT; + DAT_LMR_TRIPLET *hdlptr = (DAT_LMR_TRIPLET *) + DT_Mdep_Malloc(count * cmd->width * sizeof(*hdlptr)); + + /* Recv-Post Exhaustion test loop */ + if (hdlptr) { + unsigned int w = 0; + unsigned int i = 0; + unsigned int done = 0; + + DT_Tdep_PT_Debug(1, + (phead, + "%s: Exhausting posting of recv buffers\n", + module)); + for (w = 0; w < cmd->maximum && !done; w++) { + DT_Mdep_Schedule(); + if (w == count + && !more_handles(phead, + (DAT_HANDLE **) & hdlptr, + &count, + cmd->width * + sizeof(*hdlptr))) { + DT_Tdep_PT_Printf(phead, + "%s: no memory for IOVs \n", + module); + DT_Tdep_PT_Printf(phead, + "%s: recv buffers posted per EP: %d\n" + "\t\t (total posted: %d)\n", + module, w, + w * cmd->width); + done = retval = true; + break; + } + for (i = 0; i < cmd->width; i++) { + DAT_LMR_TRIPLET *iovp = + &hdlptr[w * cmd->width + i]; + DAT_DTO_COOKIE cookie; + + iovp->virtual_address = + (DAT_VADDR) (uintptr_t) + hdl_sets[i].lmr_buffer; + iovp->segment_length = DFLT_BUFFSZ; + iovp->lmr_context = + hdl_sets[i].lmr_context; + cookie.as_64 = (DAT_UINT64) 0UL; + cookie.as_ptr = + (DAT_PVOID) hdl_sets[i].lmr_buffer; + + DT_Tdep_PT_Printf(phead, + "%s: dat_ep_post_recv #%d\n", + module, + w * cmd->width + i + + 1); + ret = + dat_ep_post_recv(hdl_sets[i]. + ep_handle, 1, iovp, + cookie, + DAT_COMPLETION_DEFAULT_FLAG); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_ep_post_recv fails: %s\n", + module, + DT_RetToString + (ret)); + DT_Tdep_PT_Printf(phead, + "%s: recv buffers posted per EP: %d\n" + "\t\t (total posted: %d)\n", + module, w, + w * + cmd->width + + i); + done = retval = true; + break; + } + } /* end for each EP wide */ + } /* end forever (!done) loop */ + + retval = true; + DT_Tdep_PT_Printf(phead, + "%s: recv buffers posted per EP: %d\n" + "\t\t (total posted: %d)\n", module, + w, w * cmd->width); + + /* Rpost Cleanup loop */ + for (i = 0; i < cmd->width; i++) { + DAT_EVENT event; + + /* + * Disconnecting an unconnected EP should complete + * outstanding recv DTOs in error, and otherwise + * be a no-op. + */ + ret = dat_ep_reset(hdl_sets[i].ep_handle); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_ep_disconnect (abrupt) fails: %s\n", + module, + DT_RetToString(ret)); + retval = false; + } else { + /* + * Remove all DTOs. The disconnect above should have + * flushed all posted operations, so this is just a + * clean up. + */ + do { + ret = + DT_Tdep_evd_dequeue(hdl_sets + [i]. + evd_handle, + &event); + } while (ret == DAT_SUCCESS); + } + + } + DT_Mdep_Free(hdlptr); + } + } + + /* end depth == LIM_RPOST */ + /* ----------- + * Test maximum size of LMR allowed + */ + if (depth == LIM_SIZE_LMR) { + DAT_COUNT last_size = 0; + DAT_COUNT test_size = DFLT_BUFFSZ; + Bpool *test_bpool; + for (;;) { + DT_Mdep_Schedule(); + test_bpool = DT_BpoolAlloc((Per_Test_Data_t *) 0, + phead, + hdl_sets[0].ia_handle, + hdl_sets[0].pz_handle, + hdl_sets[0].ep_handle, + hdl_sets[0].evd_handle, + test_size, + 1, + DAT_OPTIMAL_ALIGNMENT, + false, false); + + if (!test_bpool) { + DT_Tdep_PT_Printf(phead, + "%s: Largest LMR was 0x%x bytes\n" + "\t (failed attempting 0x%x bytes)\n", + module, last_size, test_size); + retval = true; + break; + } else + if (!DT_Bpool_Destroy + ((Per_Test_Data_t *) 0, phead, test_bpool)) { + DT_Tdep_PT_Printf(phead, + "%s: Largest LMR was 0x%x bytes\n", + module, test_size); + retval = true; + break; + } + + last_size = test_size; + test_size <<= 1; + if (test_size < last_size) { + /* could conceivably wrap on 32-bit architectures */ + DT_Tdep_PT_Printf(phead, + "%s: LMR of 0x%x bytes OK - %s\n", + module, last_size, + "stopping now."); + retval = true; + break; + } + } /* end forever loop */ + } + /* end depth == LIM_SIZE_LMR */ + DT_Tdep_PT_Debug(1, (phead, "%s: Limit Testing Completed - %s\n", + module, retval ? "Successfully" : "with errors")); + + /* ---------------------------------------------------------- + * Clean up and go home + */ + clean_up_now: + + DT_Tdep_PT_Debug(1, (phead, "%s: Cleaning up ...\n", module)); + if (depth > LIM_LMR) { + unsigned int w; + + for (w = 0; w < cmd->width; w++) { + if (hdl_sets[w].lmr_handle) { + ret = dat_lmr_free(hdl_sets[w].lmr_handle); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_lmr_free fails: %s\n", + module, + DT_RetToString(ret)); + retval = false; + } + } + if ((void *)hdl_sets[w].lmr_buffer) { + DT_Mdep_Free((void *)hdl_sets[w].lmr_buffer); + } + } + } + + /* end LIM_LMR cleanup */ + /* + * if (depth == LIM_PSP) { + * Since PSPs are not part of the Obj_Set, + * there's no cleanup to do. + * } + * + * if (depth == LIM_RSP) { + * Since RSPs are not part of the Obj_Set, + * there'no cleanup nothing to do. + * } + */ + if (depth > LIM_EP) { + unsigned int w; + + for (w = 0; w < cmd->width; w++) { + if (hdl_sets[w].ep_handle) { + ret = dat_ep_free(hdl_sets[w].ep_handle); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_ep_free fails: %s\n", + module, + DT_RetToString(ret)); + retval = false; + } + } + } + } + /* end LIM_EP cleanup */ + if (depth > LIM_EVD) { + unsigned int w; + + if (conn_handle != DAT_HANDLE_NULL) { + ret = DT_Tdep_evd_free(conn_handle); + conn_handle = DAT_HANDLE_NULL; + } + for (w = 0; w < cmd->width; w++) { + if (hdl_sets[w].evd_handle) { + ret = DT_Tdep_evd_free(hdl_sets[w].evd_handle); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_evd_free fails: %s\n", + module, + DT_RetToString(ret)); + retval = false; + } + } + } + } + /* end LIM_EVD cleanup */ +#ifndef __KDAPLTEST__ + if (depth > LIM_CNO) { + unsigned int w; + + for (w = 0; w < cmd->width; w++) { + if (hdl_sets[w].cno_handle) { + ret = dat_cno_free(hdl_sets[w].cno_handle); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_cno_free fails: %s\n", + module, + DT_RetToString(ret)); + retval = false; + } + } + } + } /* end LIM_CNO cleanup */ +#endif + + if (depth > LIM_PZ) { + unsigned int w; + + for (w = 0; w < cmd->width; w++) { + if (hdl_sets[w].pz_handle) { + ret = dat_pz_free(hdl_sets[w].pz_handle); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_pz_free fails: %s\n", + module, + DT_RetToString(ret)); + retval = false; + } + } + } + } + /* end LIM_PZ cleanup */ + if (depth > LIM_IA) { + unsigned int w; + + for (w = 0; w < cmd->width; w++) { + if (hdl_sets[w].ia_handle) { + /* dat_ia_close cleans up async evd handle, too */ + ret = dat_ia_close(hdl_sets[w].ia_handle, + DAT_CLOSE_GRACEFUL_FLAG); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_ia_close (graceful) error: %s\n", + module, + DT_RetToString(ret)); + /* + * Since we take some pains to clean up properly, + * this really is an error. But if we get here, + * we may as well try the largest hammer we have. + */ + retval = false; + ret = + dat_ia_close(hdl_sets[w].ia_handle, + DAT_CLOSE_ABRUPT_FLAG); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_ia_close (abrupt) error: %s\n", + module, + DT_RetToString + (ret)); + } + } + } + } + } + /* end LIM_IA cleanup */ + if (depth && hdl_sets) { + DT_Mdep_Free(hdl_sets); + } + + DT_Tdep_PT_Debug(1, + (phead, "%s: testing and cleanup complete.\n", + module)); + + return (retval); +} + +/********************************************************************* + * Framework to run through all of the limit tests + */ +DAT_RETURN DT_cs_Limit(Params_t * params, Limit_Cmd_t * cmd) +{ + DT_Tdep_Print_Head *phead; + char *star = + "**********************************************************************"; + + phead = params->phead; + + if (cmd->Test_List[LIM_IA]) { + char list[] = { + "Limitation Test limit_ia\n" + "Description: Test max num of opens for the same physical IA" + } + ; + + DT_Tdep_PT_Printf(phead, "%s\n", star); + DT_Tdep_PT_Printf(phead, "%s\n", list); + if (!limit_test(phead, cmd, LIM_IA)) { + goto error; + } + DT_Tdep_PT_Printf(phead, "%s\n", star); + } + + if (cmd->Test_List[LIM_PZ]) { + char list[] = { + "Limitation Test limit_pz\n" + "Description: Test max num of PZs that are supported by an IA" + } + ; + + DT_Tdep_PT_Printf(phead, "%s\n", star); + DT_Tdep_PT_Printf(phead, "%s\n", list); + if (!limit_test(phead, cmd, LIM_PZ)) { + goto error; + } + DT_Tdep_PT_Printf(phead, "%s\n", star); + } +#ifndef __KDAPLTEST__ + if (cmd->Test_List[LIM_CNO]) { + char list[] = { + "Limitation Test limit_cno\n" + "Description: Test max num of CNOs that are supported by an IA" + } + ; + + DT_Tdep_PT_Printf(phead, "%s\n", star); + DT_Tdep_PT_Printf(phead, "%s\n", list); + if (!limit_test(phead, cmd, LIM_CNO)) { + goto error; + } + DT_Tdep_PT_Printf(phead, "%s\n", star); + } +#endif + + if (cmd->Test_List[LIM_EVD]) { + char list[] = { + "Limitation Test limit_evd\n" + "Description: Test max num of EVDs that are supported by an IA" + } + ; + + DT_Tdep_PT_Printf(phead, "%s\n", star); + DT_Tdep_PT_Printf(phead, "%s\n", list); + if (!limit_test(phead, cmd, LIM_EVD)) { + goto error; + } + DT_Tdep_PT_Printf(phead, "%s\n", star); + } + + if (cmd->Test_List[LIM_EP]) { + char list[] = { + "Limitation Test limit_ep\n" + "Description: Test max num of EPs that are supported by an IA" + } + ; + + DT_Tdep_PT_Printf(phead, "%s\n", star); + DT_Tdep_PT_Printf(phead, "%s\n", list); + if (!limit_test(phead, cmd, LIM_EP)) { + goto error; + } + DT_Tdep_PT_Printf(phead, "%s\n", star); + } + + if (cmd->Test_List[LIM_RSP]) { + char list[] = { + "Limitation Test limit_rsp\n" + "Description: Test max num of RSPs that are supported by an IA" + } + ; + + DT_Tdep_PT_Printf(phead, "%s\n", star); + DT_Tdep_PT_Printf(phead, "%s\n", list); + if (!limit_test(phead, cmd, LIM_RSP)) { + goto error; + } + DT_Tdep_PT_Printf(phead, "%s\n", star); + } + + if (cmd->Test_List[LIM_PSP]) { + char list[] = { + "Limitation Test limit_psp\n" + "Description: Test max num of PSPs that are supported by an IA" + } + ; + + DT_Tdep_PT_Printf(phead, "%s\n", star); + DT_Tdep_PT_Printf(phead, "%s\n", list); + if (!limit_test(phead, cmd, LIM_PSP)) { + goto error; + } + DT_Tdep_PT_Printf(phead, "%s\n", star); + } + + if (cmd->Test_List[LIM_LMR]) { + char list[] = { + "Limitation Test limit_lmr\n" + "Description: Test max num of LMRs that are supported by an IA" + } + ; + + DT_Tdep_PT_Printf(phead, "%s\n", star); + DT_Tdep_PT_Printf(phead, "%s\n", list); + if (!limit_test(phead, cmd, LIM_LMR)) { + goto error; + } + DT_Tdep_PT_Printf(phead, "%s\n", star); + } + + if (cmd->Test_List[LIM_RPOST]) { + char list[] = { + "Limitation Test limit_rpost\n" + "Description: Test max num of receive buffers posted to an EP" + } + ; + + DT_Tdep_PT_Printf(phead, "%s\n", star); + DT_Tdep_PT_Printf(phead, "%s\n", list); + if (!limit_test(phead, cmd, LIM_RPOST)) { + goto error; + } + DT_Tdep_PT_Printf(phead, "%s\n", star); + } + + if (cmd->Test_List[LIM_SIZE_LMR]) { + char list[] = { + "Limitation Test limit_size_lmr\n" + "Description: Test max size of LMRs that are supported by an IA" + } + ; + + DT_Tdep_PT_Printf(phead, "%s\n", star); + DT_Tdep_PT_Printf(phead, "%s\n", list); + if (!limit_test(phead, cmd, LIM_SIZE_LMR)) { + goto error; + } + DT_Tdep_PT_Printf(phead, "%s\n", star); + } + + /* More tests TBS ... */ + + return DAT_SUCCESS; + + error: + DT_Tdep_PT_Printf(phead, + "error occurs, can not continue with limit test\n"); + DT_Tdep_PT_Printf(phead, "%s\n", star); + return DAT_INSUFFICIENT_RESOURCES; +} diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_memlist.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_memlist.c new file mode 100644 index 00000000..03e8d88a --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_memlist.c @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" + +void DT_MemListInit(Per_Test_Data_t * pt_ptr) +{ + DT_Mdep_LockInit(&pt_ptr->MemListLock); + pt_ptr->MemListHead = 0; +} + +void *DT_MemListAlloc(Per_Test_Data_t * pt_ptr, + char *file, mem_type_e t, int size) +{ + void *buffptr; + MemListEntry_t *entry_ptr; + buffptr = 0; + entry_ptr = 0; + + buffptr = DT_Mdep_Malloc(size); + if (buffptr == 0) { + return 0; + } + if (pt_ptr == 0) { /* not use mem_list */ + return buffptr; + } + entry_ptr = (MemListEntry_t *) DT_Mdep_Malloc(sizeof(MemListEntry_t)); + if (entry_ptr == 0) { + DT_Mdep_Free(buffptr); + return 0; + } + strcpy(entry_ptr->filename, file); + entry_ptr->MemType = t; + entry_ptr->mem_ptr = buffptr; + + DT_Mdep_Lock(&pt_ptr->MemListLock); + entry_ptr->next = pt_ptr->MemListHead; + pt_ptr->MemListHead = entry_ptr; + DT_Mdep_Unlock(&pt_ptr->MemListLock); + + return buffptr; +} + +void DT_MemListFree(Per_Test_Data_t * pt_ptr, void *ptr) +{ + MemListEntry_t *pre, *cur; + if (pt_ptr == 0) { /* not use mem_list */ + DT_Mdep_Free(ptr); + return; + } + DT_Mdep_Lock(&pt_ptr->MemListLock); + pre = 0; + cur = pt_ptr->MemListHead; + while (cur) { + if (cur->mem_ptr == ptr) { + if (!pre) { /* first entry */ + pt_ptr->MemListHead = cur->next; + cur->next = 0; + } else { + pre->next = cur->next; + cur->next = 0; + } + DT_Mdep_Free(ptr); + DT_Mdep_Free(cur); + goto unlock_and_return; + } + pre = cur; + cur = cur->next; + } + unlock_and_return: + DT_Mdep_Unlock(&pt_ptr->MemListLock); +} + +void DT_PrintMemList(Per_Test_Data_t * pt_ptr) +{ + char *type[10] = { + "BPOOL", "BUFF", "PERTESTDATA", "NIC", "NETADDRESS", + "TRANSACTIONTEST", "THREAD", "EPCONTEXT" + }; + DT_Tdep_Print_Head *phead; + MemListEntry_t *cur; + + phead = pt_ptr->Params.phead; + DT_Mdep_Lock(&pt_ptr->MemListLock); + cur = pt_ptr->MemListHead; + if (cur != 0) { + DT_Tdep_PT_Printf(phead, + "the allocated memory that have not been returned are:\n"); + } + while (cur) { + DT_Tdep_PT_Printf(phead, "file: dapl_%s, \tMemType:%s\n", + cur->filename, type[cur->MemType]); + cur = cur->next; + } + DT_Mdep_Unlock(&pt_ptr->MemListLock); +} diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_performance_client.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_performance_client.c new file mode 100644 index 00000000..96d5b47a --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_performance_client.c @@ -0,0 +1,490 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" + +#define MAX_CONN_RETRY 8 + +/****************************************************************************/ +DAT_RETURN +DT_Performance_Test_Client(Params_t * params_ptr, + Per_Test_Data_t * pt_ptr, + DAT_IA_HANDLE * ia_handle, + DAT_IA_ADDRESS_PTR remote_ia_addr) +{ + Performance_Test_t *test_ptr = NULL; + int connected = 1; + DT_Tdep_Print_Head *phead; + DAT_RETURN rc; + + phead = pt_ptr->Params.phead; + + DT_Tdep_PT_Debug(1, (phead, "Client: Starting performance test\n")); + + if (!DT_Performance_Test_Create(pt_ptr, + ia_handle, + remote_ia_addr, + false, + pt_ptr->Server_Info.is_little_endian, + &test_ptr)) { + DT_Tdep_PT_Debug(1, + (phead, "Client: Resource Creation Failed\n")); + connected = 0; + } else if (!DT_Performance_Test_Client_Connect(phead, test_ptr)) { + DT_Tdep_PT_Debug(1, (phead, "Client: Connection Failed\n")); + connected = 0; + } + + if (connected) { + if (!DT_Performance_Test_Client_Exchange + (params_ptr, phead, test_ptr)) { + DT_Tdep_PT_Debug(1, (phead, "Client: Test Failed\n")); + } + } + /* If we never connected, then the test will hang here + * because in the destroy of the test it waits for a + * disconnect event which will never arrive, simply + * because there was never a connection. + */ + + DT_Performance_Test_Destroy(pt_ptr, test_ptr, false); + +#ifdef CM_BUSTED + /***** XXX Chill out a bit to give the kludged CM a chance ... + *****/ DT_Mdep_Sleep(5000); +#endif + + DT_Tdep_PT_Debug(1, (phead, "Client: Finished performance test\n")); + + return (connected ? DAT_SUCCESS : DAT_INSUFFICIENT_RESOURCES); +} + +/****************************************************************************/ +bool +DT_Performance_Test_Client_Connect(DT_Tdep_Print_Head * phead, + Performance_Test_t * test_ptr) +{ + DAT_RETURN ret; + DAT_EVENT_NUMBER event_num; + unsigned int retry_cnt = 0; + + /* + * Client - connect + */ + DT_Tdep_PT_Debug(1, + (phead, + "Client[" F64x "]: Connect on port 0x" F64x "\n", + test_ptr->base_port, test_ptr->ep_context.port)); + + retry: + ret = dat_ep_connect(test_ptr->ep_context.ep_handle, test_ptr->remote_ia_addr, test_ptr->ep_context.port, DAT_TIMEOUT_INFINITE, 0, (DAT_PVOID) 0, /* no private data */ + test_ptr->cmd->qos, DAT_CONNECT_DEFAULT_FLAG); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x "]: dat_ep_connect error: %s\n", + test_ptr->base_port, DT_RetToString(ret)); + return false; + } + + /* wait for DAT_CONNECTION_EVENT_ESTABLISHED */ + if (!DT_conn_event_wait(phead, + test_ptr->ep_context.ep_handle, + test_ptr->conn_evd_hdl, &event_num)) { + if (event_num == DAT_CONNECTION_EVENT_PEER_REJECTED) { + DT_Mdep_Sleep(1000); + DT_Tdep_PT_Printf(phead, + "Test[" F64x + "]: retrying connection...\n", + test_ptr->base_port); + retry_cnt++; + if (retry_cnt < MAX_CONN_RETRY) { + goto retry; + } + } + /* error message printed by DT_cr_event_wait */ + return false; + } +#ifdef CM_BUSTED + /***** XXX Chill out a bit to give the kludged CM a chance ... + *****/ DT_Mdep_Sleep(5000); +#endif + + DT_Tdep_PT_Debug(1, + (phead, "Client[" F64x "]: Got Connection\n", + test_ptr->base_port)); + + return true; +} + +/****************************************************************************/ +static bool +DT_Performance_Test_Client_Phase1(DT_Tdep_Print_Head * phead, + Performance_Test_t * test_ptr, + Performance_Stats_t * stats) +{ + DT_Mdep_TimeStamp pre_ts; + DT_Mdep_TimeStamp post_ts; + DT_CpuStat pre_cpu_stat; + DT_CpuStat post_cpu_stat; + unsigned int post_cnt; + unsigned int reap_cnt; + + /* + * measure bandwidth, OPS, and CPU utilization + */ + + if (!DT_Mdep_GetCpuStat(&pre_cpu_stat)) { + return false; + } + + pre_ts = DT_Mdep_GetTimeStamp(); + + /* + * Fill the pipe + */ + + for (post_cnt = 0; + post_cnt < (unsigned int)test_ptr->ep_context.pipeline_len; + post_cnt++) { + if (!DT_performance_post_rdma_op + (&test_ptr->ep_context, test_ptr->reqt_evd_hdl, stats)) { + DT_Tdep_PT_Debug(1, + (phead, + "Test[" F64x "]: Post %i failed\n", + test_ptr->base_port, post_cnt)); + return false; + } + } + + /* + * Reap completions and repost + */ + + for (reap_cnt = 0; reap_cnt < test_ptr->cmd->num_iterations;) { + unsigned int cur_reap_cnt; + unsigned int cur_post_cnt; + unsigned int cur_post_i; + + cur_reap_cnt = DT_performance_reap(phead, + test_ptr->reqt_evd_hdl, + test_ptr->cmd->mode, stats); + + if (0 == cur_reap_cnt) { + DT_Tdep_PT_Debug(1, + (phead, + "Test[" F64x "]: Poll %i failed\n", + test_ptr->base_port, reap_cnt)); + return false; + } + + /* repost */ + cur_post_cnt = DT_min(test_ptr->cmd->num_iterations - post_cnt, + cur_reap_cnt); + + for (cur_post_i = 0; cur_post_i < cur_post_cnt; cur_post_i++) { + if (!DT_performance_post_rdma_op(&test_ptr->ep_context, + test_ptr->reqt_evd_hdl, + stats)) { + DT_Tdep_PT_Debug(1, + (phead, + "Test[" F64x + "]: Post %i failed\n", + test_ptr->base_port, + post_cnt)); + return false; + } + } + + reap_cnt += cur_reap_cnt; + post_cnt += cur_post_cnt; + } + + /* end time and update stats */ + post_ts = DT_Mdep_GetTimeStamp(); + stats->time_ts = post_ts - pre_ts; + stats->num_ops = test_ptr->cmd->num_iterations; + + if (!DT_Mdep_GetCpuStat(&post_cpu_stat)) { + return false; + } + + /* calculate CPU utilization */ + { + unsigned long int system; + unsigned long int user; + unsigned long int idle; + unsigned long int total; + + system = post_cpu_stat.system - pre_cpu_stat.system; + user = post_cpu_stat.user - pre_cpu_stat.user; + idle = post_cpu_stat.idle - pre_cpu_stat.idle; + + total = system + user + idle; + + if (0 == total) { + stats->cpu_utilization = 0.0; + } else { + stats->cpu_utilization = + (double)1.0 - ((double)idle / (double)total); + stats->cpu_utilization *= 100.0; + } + } + + return true; +} + +/****************************************************************************/ +static bool +DT_Performance_Test_Client_Phase2(DT_Tdep_Print_Head * phead, + Performance_Test_t * test_ptr, + Performance_Stats_t * stats) +{ + DAT_LMR_TRIPLET *iov; + DAT_RMR_TRIPLET rmr_triplet; + DAT_DTO_COOKIE cookie; + DAT_EVENT event; + DAT_RETURN ret; + Performance_Ep_Context_t *ep_context; + Performance_Test_Op_t *op; + DT_Mdep_TimeStamp pre_ts; + DT_Mdep_TimeStamp post_ts; + unsigned long int bytes; + unsigned int i; + + /* + * measure latency + */ + + ep_context = &test_ptr->ep_context; + op = &ep_context->op; + iov = DT_Bpool_GetIOV(op->bp, 0); + + bytes = op->seg_size * op->num_segs; + + /* Prep the inputs */ + for (i = 0; i < op->num_segs; i++) { + iov[i].virtual_address = (DAT_VADDR) (uintptr_t) + DT_Bpool_GetBuffer(op->bp, i); + iov[i].segment_length = op->seg_size; + iov[i].lmr_context = DT_Bpool_GetLMR(op->bp, i); + } + + rmr_triplet.virtual_address = op->Rdma_Address; + rmr_triplet.segment_length = op->seg_size * op->num_segs; + rmr_triplet.rmr_context = op->Rdma_Context; + + cookie.as_ptr = NULL; + + for (i = 0; i < test_ptr->cmd->num_iterations; i++) { + if (RDMA_WRITE == op->transfer_type) { + pre_ts = DT_Mdep_GetTimeStamp(); + + ret = dat_ep_post_rdma_write(ep_context->ep_handle, + op->num_segs, + iov, + cookie, + &rmr_triplet, + DAT_COMPLETION_DEFAULT_FLAG); + } else { + pre_ts = DT_Mdep_GetTimeStamp(); + + ret = dat_ep_post_rdma_read(ep_context->ep_handle, + op->num_segs, + iov, + cookie, + &rmr_triplet, + DAT_COMPLETION_DEFAULT_FLAG); + } + + if (DAT_SUCCESS != ret) { + return false; + } + + for (;;) { + DT_Mdep_Schedule(); + ret = DT_Tdep_evd_dequeue(test_ptr->reqt_evd_hdl, + &event); + + post_ts = DT_Mdep_GetTimeStamp(); + + if (DAT_GET_TYPE(ret) == DAT_QUEUE_EMPTY) { + continue; + } else if (DAT_SUCCESS != ret) { + DT_Tdep_PT_Printf(phead, + "Test Error: dapl_event_dequeue failed: %s\n", + DT_RetToString(ret)); + return false; + } else if (event.event_number == + DAT_DTO_COMPLETION_EVENT) { + DT_performance_stats_record_latency(stats, + post_ts - + pre_ts); + break; + } else { /* error */ + + DT_Tdep_PT_Printf(phead, + "Warning: dapl_performance_wait swallowing %s event\n", + DT_EventToSTr(event. + event_number)); + + return false; + } + } + } + + return true; +} + +/****************************************************************************/ +bool +DT_Performance_Test_Client_Exchange(Params_t * params_ptr, + DT_Tdep_Print_Head * phead, + Performance_Test_t * test_ptr) +{ + DAT_DTO_COMPLETION_EVENT_DATA dto_stat; + DAT_DTO_COOKIE dto_cookie; + Performance_Stats_t stats; + RemoteMemoryInfo *rmi; + + test_ptr->ep_context.op.bp = + DT_BpoolAlloc(test_ptr->pt_ptr, + phead, + test_ptr->ia_handle, + test_ptr->pz_handle, + test_ptr->ep_context.ep_handle, + test_ptr->reqt_evd_hdl, + test_ptr->ep_context.op.seg_size, + test_ptr->ep_context.op.num_segs, + DAT_OPTIMAL_ALIGNMENT, false, false); + + if (!test_ptr->ep_context.op.bp) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x + "]: no memory for buffers (RDMA/RD)\n", + test_ptr->base_port); + return false; + } + + /* + * Recv the other side's info + */ + DT_Tdep_PT_Debug(1, (phead, "Test[" F64x "]: Waiting for Sync Msg\n", + test_ptr->base_port)); + + dto_cookie.as_64 = LZERO; + dto_cookie.as_ptr = + (DAT_PVOID) DT_Bpool_GetBuffer(test_ptr->ep_context.bp, + DT_PERF_SYNC_RECV_BUFFER_ID); + if (!DT_dto_event_wait(phead, test_ptr->recv_evd_hdl, &dto_stat) || + !DT_dto_check(phead, + &dto_stat, + test_ptr->ep_context.ep_handle, + DT_PERF_SYNC_BUFF_SIZE, + dto_cookie, "Received Sync_Msg")) { + return false; + } + + /* + * Extract what we need + */ + DT_Tdep_PT_Debug(1, + (phead, "Test[" F64x "]: Sync Msg Received\n", + test_ptr->base_port)); + rmi = + (RemoteMemoryInfo *) DT_Bpool_GetBuffer(test_ptr->ep_context.bp, + DT_PERF_SYNC_RECV_BUFFER_ID); + + /* + * If the client and server are of different endiannesses, + * we must correct the endianness of the handle and address + * we pass to the other side. The other side cannot (and + * better not) interpret these values. + */ + if (DT_local_is_little_endian != test_ptr->is_remote_little_endian) { + rmi->rmr_context = DT_EndianMemHandle(rmi->rmr_context); + rmi->mem_address.as_64 = + DT_EndianMemAddress(rmi->mem_address.as_64); + } + + test_ptr->ep_context.op.Rdma_Context = rmi->rmr_context; + test_ptr->ep_context.op.Rdma_Address = rmi->mem_address.as_64; + + DT_Tdep_PT_Debug(3, (phead, + "Got RemoteMemInfo [ va=" F64x ", ctx=%x ]\n", + test_ptr->ep_context.op.Rdma_Address, + test_ptr->ep_context.op.Rdma_Context)); + + /* + * Get to work ... + */ + DT_Tdep_PT_Debug(1, + (phead, "Test[" F64x "]: Begin...\n", + test_ptr->base_port)); + + DT_performance_stats_init(&stats); + + if (!DT_Performance_Test_Client_Phase1(phead, test_ptr, &stats)) { + return false; + } + + if (!DT_Performance_Test_Client_Phase2(phead, test_ptr, &stats)) { + return false; + } + + DT_Tdep_PT_Debug(1, + (phead, "Test[" F64x "]: Sending Sync Msg\n", + test_ptr->base_port)); + + if (!DT_post_send_buffer(phead, + test_ptr->ep_context.ep_handle, + test_ptr->ep_context.bp, + DT_PERF_SYNC_SEND_BUFFER_ID, + DT_PERF_SYNC_BUFF_SIZE)) { + /* error message printed by DT_post_send_buffer */ + return false; + } + + dto_cookie.as_64 = LZERO; + dto_cookie.as_ptr = + (DAT_PVOID) DT_Bpool_GetBuffer(test_ptr->ep_context.bp, + DT_PERF_SYNC_SEND_BUFFER_ID); + if (!DT_dto_event_wait(phead, test_ptr->reqt_evd_hdl, &dto_stat) || + !DT_dto_check(phead, + &dto_stat, + test_ptr->ep_context.ep_handle, + DT_PERF_SYNC_BUFF_SIZE, + dto_cookie, "Client_Sync_Send")) { + return false; + } + DT_performance_stats_print(params_ptr, phead, &stats, test_ptr->cmd, + test_ptr); + + return true; +} diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_performance_server.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_performance_server.c new file mode 100644 index 00000000..5083967e --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_performance_server.c @@ -0,0 +1,391 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" + +/****************************************************************************/ +void DT_Performance_Test_Server(void *var) +{ + Per_Test_Data_t *pt_ptr = var; + Performance_Test_t *test_ptr = NULL; + DT_Tdep_Print_Head *phead; + int success = 1; + + phead = pt_ptr->Params.phead; + DT_Tdep_PT_Debug(1, (phead, "Server: Starting performance test\n")); + + if (!DT_Performance_Test_Create(pt_ptr, + pt_ptr->ps_ptr->ia_handle, + (DAT_IA_ADDRESS_PTR) 0, + true, + pt_ptr->Client_Info.is_little_endian, + &test_ptr)) { + DT_Tdep_PT_Printf(phead, "Server: Resource Creation Failed\n"); + success = 0; + } + if (1 == success) { + if (!DT_Performance_Test_Server_Connect(phead, test_ptr)) { + success = 0; + DT_Tdep_PT_Printf(phead, "Server: Connection Failed\n"); + } + } + + if (1 == success) { + if (!DT_Performance_Test_Server_Exchange(phead, test_ptr)) { + success = 0; + DT_Tdep_PT_Printf(phead, "Server: Test Failed\n"); + } + } +#ifdef CM_BUSTED + /***** XXX Chill out a bit to give the kludged CM a chance ... + *****/ DT_Mdep_Sleep(5000); +#endif + + DT_Performance_Test_Destroy(pt_ptr, test_ptr, true); + + DT_Tdep_PT_Printf(phead, + "Server: Finished performance test. Detaching.\n"); + + DT_Mdep_Thread_Detach(DT_Mdep_Thread_SELF()); /* AMM */ + DT_Thread_Destroy(pt_ptr->thread, pt_ptr); /* destroy Master thread */ + + DT_Mdep_Lock(&pt_ptr->ps_ptr->num_clients_lock); + pt_ptr->ps_ptr->num_clients--; + DT_Mdep_Unlock(&pt_ptr->ps_ptr->num_clients_lock); + + DT_PrintMemList(pt_ptr); /* check if we return all space allocated */ + DT_Mdep_LockDestroy(&pt_ptr->Thread_counter_lock); + DT_Mdep_LockDestroy(&pt_ptr->MemListLock); + DT_Free_Per_Test_Data(pt_ptr); + + DT_Mdep_Unlock(&g_PerfTestLock); + DT_Tdep_PT_Printf(phead, + "Server: Finished performance test. Exiting.\n"); + + DT_Mdep_Thread_EXIT(NULL); +} + +/****************************************************************************/ +bool +DT_Performance_Test_Server_Connect(DT_Tdep_Print_Head * phead, + Performance_Test_t * test_ptr) +{ + DAT_RETURN ret; + bool status; + DAT_RSP_HANDLE rsp_handle; + DAT_PSP_HANDLE psp_handle; + + DAT_CR_ARRIVAL_EVENT_DATA cr_stat; + DAT_CR_HANDLE cr_handle; + DAT_EVENT_NUMBER event_num; + + rsp_handle = DAT_HANDLE_NULL; + psp_handle = DAT_HANDLE_NULL; +#if 0 /* FIXME */ + if (test_ptr->cmd->use_rsp) { + /* + * Server - create a single-use RSP and + * await a connection for this EP + */ + ret = dat_rsp_create(test_ptr->ia_handle, + test_ptr->ep_context.port, + test_ptr->ep_context.ep_handle, + test_ptr->creq_evd_hdl, &rsp_handle); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x + "]: dat_rsp_create error: %s\n", + test_ptr->base_port, + DT_RetToString(ret)); + status = false; + goto psp_free; + } + + DT_Tdep_PT_Debug(1, + (phead, + "Server[" F64x "]: Listen on RSP port 0x" F64x + "\n", test_ptr->base_port, + test_ptr->ep_context.port)); + + /* wait for the connection request */ + if (!DT_cr_event_wait(test_ptr->conn_evd_hdl, &cr_stat) || + !DT_cr_check(&cr_stat, + DAT_HANDLE_NULL, + test_ptr->ep_context.port, + &cr_handle, "Server")) { + status = false; + goto psp_free; + } + + /* what, me query? just try to accept the connection */ + ret = dat_cr_accept(cr_handle, + test_ptr->ep_context.ep_handle, + 0, (DAT_PVOID) 0 /* no private data */ ); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x + "]: dat_cr_accept error: %s\n", + test_ptr->base_port, + DT_RetToString(ret)); + /* cr_handle consumed on failure */ + status = false; + goto psp_free; + } + + /* wait for DAT_CONNECTION_EVENT_ESTABLISHED */ + if (!DT_conn_event_wait(test_ptr->ep_context.ep_handle, + test_ptr->conn_evd_hdl, &event_num)) { + /* error message printed by DT_conn_event_wait */ + status = false; + goto psp_free; + } + + } else +#endif /* FIXME */ + { + /* + * Server - use a short-lived PSP instead of an RSP + */ + status = true; + + ret = dat_psp_create(test_ptr->ia_handle, + test_ptr->ep_context.port, + test_ptr->creq_evd_hdl, + DAT_PSP_CONSUMER_FLAG, &psp_handle); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x + "]: dat_psp_create error: %s\n", + test_ptr->base_port, + DT_RetToString(ret)); + status = false; + psp_handle = DAT_HANDLE_NULL; + return (status); + } + + } + + /* + * Here's where we tell the main server process that + * this thread is ready to wait for a connection request + * from the remote end. + */ + DT_Mdep_wait_object_wakeup(&test_ptr->pt_ptr->synch_wait_object); + + DT_Tdep_PT_Debug(1, + (phead, + "Server[" F64x "]: Listen on PSP port 0x" F64x "\n", + test_ptr->base_port, test_ptr->ep_context.port)); + + /* wait for a connection request */ + if (!DT_cr_event_wait(phead, test_ptr->creq_evd_hdl, &cr_stat) || + !DT_cr_check(phead, + &cr_stat, + psp_handle, + test_ptr->ep_context.port, &cr_handle, "Server")) { + status = false; + goto psp_free; + } + + /* what, me query? just try to accept the connection */ + ret = dat_cr_accept(cr_handle, + test_ptr->ep_context.ep_handle, + 0, (DAT_PVOID) 0 /* no private data */ ); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x "]: dat_cr_accept error: %s\n", + test_ptr->base_port, DT_RetToString(ret)); + /* cr_handle consumed on failure */ + status = false; + goto psp_free; + } + + /* wait for DAT_CONNECTION_EVENT_ESTABLISHED */ + if (!DT_conn_event_wait(phead, + test_ptr->ep_context.ep_handle, + test_ptr->conn_evd_hdl, &event_num)) { + /* error message printed by DT_cr_event_wait */ + status = false; + goto psp_free; + } + + DT_Tdep_PT_Debug(1, + (phead, + "Server[" F64x "]: Accept on port 0x" F64x "\n", + test_ptr->base_port, test_ptr->ep_context.port)); + psp_free: + if (DAT_HANDLE_NULL != psp_handle) { + /* throw away single-use PSP */ + ret = dat_psp_free(psp_handle); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x + "]: dat_psp_free error: %s\n", + test_ptr->base_port, + DT_RetToString(ret)); + status = false; + } + } + if (DAT_HANDLE_NULL != rsp_handle) { + /* throw away single-use PSP */ + ret = dat_rsp_free(rsp_handle); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x + "]: dat_rsp_free error: %s\n", + test_ptr->base_port, + DT_RetToString(ret)); + status = false; + } + } + /* end short-lived PSP */ +#ifdef CM_BUSTED + /***** XXX Chill out a bit to give the kludged CM a chance ... + *****/ DT_Mdep_Sleep(5000); +#endif + + return status; +} + +/****************************************************************************/ +bool +DT_Performance_Test_Server_Exchange(DT_Tdep_Print_Head * phead, + Performance_Test_t * test_ptr) +{ + DAT_DTO_COMPLETION_EVENT_DATA dto_stat; + RemoteMemoryInfo *rmi; + DAT_DTO_COOKIE dto_cookie; + + test_ptr->ep_context.op.bp = + DT_BpoolAlloc(test_ptr->pt_ptr, + phead, + test_ptr->ia_handle, + test_ptr->pz_handle, + test_ptr->ep_context.ep_handle, + test_ptr->reqt_evd_hdl, + test_ptr->ep_context.op.seg_size, + test_ptr->ep_context.op.num_segs, + DAT_OPTIMAL_ALIGNMENT, true, true); + + if (!test_ptr->ep_context.op.bp) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x + "]: no memory for buffers (RDMA/RD)\n", + test_ptr->base_port); + return false; + } + + test_ptr->ep_context.op.Rdma_Context = + DT_Bpool_GetRMR(test_ptr->ep_context.op.bp, 0); + test_ptr->ep_context.op.Rdma_Address = (DAT_VADDR) (uintptr_t) + DT_Bpool_GetBuffer(test_ptr->ep_context.op.bp, 0); + + /* + * Prep send buffer with memory information + */ + rmi = (RemoteMemoryInfo *) DT_Bpool_GetBuffer(test_ptr->ep_context.bp, + DT_PERF_SYNC_SEND_BUFFER_ID); + + rmi->rmr_context = test_ptr->ep_context.op.Rdma_Context; + rmi->mem_address.as_64 = test_ptr->ep_context.op.Rdma_Address; + + if (rmi->mem_address.as_ptr) { + DT_Tdep_PT_Debug(3, (phead, + "RemoteMemInfo va=" F64x ", ctx=%x\n", + rmi->mem_address.as_64, rmi->rmr_context)); + } + + /* + * If the client and server are of different endiannesses, + * we must correct the endianness of the handle and address + * we pass to the other side. The other side cannot (and + * better not) interpret these values. + */ + if (DT_local_is_little_endian != test_ptr->is_remote_little_endian) { + rmi->rmr_context = DT_EndianMemHandle(rmi->rmr_context); + rmi->mem_address.as_64 = + DT_EndianMemAddress(rmi->mem_address.as_64); + } + + /* + * Send our memory info + */ + DT_Tdep_PT_Debug(1, + (phead, "Test[" F64x "]: Sending Sync Msg\n", + test_ptr->base_port)); + + /* post the send buffer */ + if (!DT_post_send_buffer(phead, + test_ptr->ep_context.ep_handle, + test_ptr->ep_context.bp, + DT_PERF_SYNC_SEND_BUFFER_ID, + DT_PERF_SYNC_BUFF_SIZE)) { + /* error message printed by DT_post_send_buffer */ + return false; + } + + /* reap the send and verify it */ + dto_cookie.as_64 = LZERO; + dto_cookie.as_ptr = + (DAT_PVOID) DT_Bpool_GetBuffer(test_ptr->ep_context.bp, + DT_PERF_SYNC_SEND_BUFFER_ID); + if (!DT_dto_event_wait(phead, test_ptr->reqt_evd_hdl, &dto_stat) || + !DT_dto_check(phead, + &dto_stat, + test_ptr->ep_context.ep_handle, + DT_PERF_SYNC_BUFF_SIZE, + dto_cookie, "Send Sync_Msg")) { + return false; + } + + /* + * Recv the other side's info + */ + DT_Tdep_PT_Debug(1, (phead, "Test[" F64x "]: Waiting for Sync Msg\n", + test_ptr->base_port)); + + dto_cookie.as_64 = LZERO; + dto_cookie.as_ptr = + (DAT_PVOID) DT_Bpool_GetBuffer(test_ptr->ep_context.bp, + DT_PERF_SYNC_RECV_BUFFER_ID); + if (!DT_dto_event_wait(phead, test_ptr->recv_evd_hdl, &dto_stat) || + !DT_dto_check(phead, + &dto_stat, + test_ptr->ep_context.ep_handle, + DT_PERF_SYNC_BUFF_SIZE, + dto_cookie, "Received Sync_Msg")) { + return false; + } + + DT_Tdep_PT_Debug(1, (phead, "Test[" F64x "]: Received Sync Msg\n", + test_ptr->base_port)); + + return true; +} diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_performance_stats.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_performance_stats.c new file mode 100644 index 00000000..95fa202f --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_performance_stats.c @@ -0,0 +1,374 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" + +void DT_performance_stats_init(Performance_Stats_t * stats) +{ + stats->num_ops = 0; + stats->bytes = 0; + stats->post_ctxt_switch_num = 0; + stats->reap_ctxt_switch_num = 0; + + stats->cpu_utilization = 0.0; + stats->time_ts = 0; + + stats->posts_sans_ctxt.num = 0; + stats->posts_sans_ctxt.total_ts = 0; + stats->posts_sans_ctxt.max_ts = 0; + stats->posts_sans_ctxt.min_ts = ~0; + + stats->posts_with_ctxt.num = 0; + stats->posts_with_ctxt.total_ts = 0; + stats->posts_with_ctxt.max_ts = 0; + stats->posts_with_ctxt.min_ts = ~0; + + stats->reaps_sans_ctxt.num = 0; + stats->reaps_sans_ctxt.total_ts = 0; + stats->reaps_sans_ctxt.max_ts = 0; + stats->reaps_sans_ctxt.min_ts = ~0; + + stats->reaps_with_ctxt.num = 0; + stats->reaps_with_ctxt.total_ts = 0; + stats->reaps_with_ctxt.max_ts = 0; + stats->reaps_with_ctxt.min_ts = ~0; + + stats->latency.num = 0; + stats->latency.total_ts = 0; + stats->latency.max_ts = 0; + stats->latency.min_ts = ~0; +} + +void +DT_performance_stats_record_post(Performance_Stats_t * stats, + unsigned long ctxt_switch_num, + DT_Mdep_TimeStamp ts) +{ + if (ctxt_switch_num) { + stats->posts_with_ctxt.num++; + stats->posts_with_ctxt.total_ts += ts; + stats->posts_with_ctxt.max_ts = + DT_max(stats->posts_with_ctxt.max_ts, ts); + stats->posts_with_ctxt.min_ts = + DT_min(stats->posts_with_ctxt.min_ts, ts); + + stats->post_ctxt_switch_num += ctxt_switch_num; + } else { + stats->posts_sans_ctxt.num++; + stats->posts_sans_ctxt.total_ts += ts; + stats->posts_sans_ctxt.max_ts = + DT_max(stats->posts_sans_ctxt.max_ts, ts); + stats->posts_sans_ctxt.min_ts = + DT_min(stats->posts_sans_ctxt.min_ts, ts); + } +} + +void +DT_performance_stats_record_reap(Performance_Stats_t * stats, + unsigned long ctxt_switch_num, + DT_Mdep_TimeStamp ts) +{ + if (ctxt_switch_num) { + stats->reaps_with_ctxt.num++; + stats->reaps_with_ctxt.total_ts += ts; + stats->reaps_with_ctxt.max_ts = + DT_max(stats->reaps_with_ctxt.max_ts, ts); + stats->reaps_with_ctxt.min_ts = + DT_min(stats->reaps_with_ctxt.min_ts, ts); + + stats->reap_ctxt_switch_num += ctxt_switch_num; + } else { + stats->reaps_sans_ctxt.num++; + stats->reaps_sans_ctxt.total_ts += ts; + stats->reaps_sans_ctxt.max_ts = + DT_max(stats->reaps_sans_ctxt.max_ts, ts); + stats->reaps_sans_ctxt.min_ts = + DT_min(stats->reaps_sans_ctxt.min_ts, ts); + } +} + +void +DT_performance_stats_record_latency(Performance_Stats_t * stats, + DT_Mdep_TimeStamp ts) +{ + stats->latency.num++; + stats->latency.total_ts += ts; + stats->latency.max_ts = DT_max(stats->latency.max_ts, ts); + stats->latency.min_ts = DT_min(stats->latency.min_ts, ts); +} + +void +DT_performance_stats_data_combine(Performance_Stats_Data_t * dest, + Performance_Stats_Data_t * src_a, + Performance_Stats_Data_t * src_b) +{ + dest->num = src_a->num + src_b->num; + dest->total_ts = src_a->total_ts + src_b->total_ts; + dest->max_ts = DT_max(src_a->max_ts, src_b->max_ts); + dest->min_ts = DT_min(src_a->min_ts, src_b->min_ts); +} + +void +DT_performance_stats_combine(Performance_Stats_t * dest, + Performance_Stats_t * src_a, + Performance_Stats_t * src_b) +{ + dest->num_ops = src_a->num_ops + src_b->num_ops; + + dest->bytes = src_a->bytes + src_b->bytes; + + dest->post_ctxt_switch_num = + src_a->post_ctxt_switch_num + src_b->post_ctxt_switch_num; + + dest->reap_ctxt_switch_num = + src_b->reap_ctxt_switch_num + src_b->reap_ctxt_switch_num; + + dest->cpu_utilization = DT_max(src_a->cpu_utilization, + src_b->cpu_utilization); + dest->time_ts = DT_max(src_a->time_ts, src_b->time_ts); + + DT_performance_stats_data_combine(&dest->posts_sans_ctxt, + &src_a->posts_sans_ctxt, + &src_b->posts_sans_ctxt); + + DT_performance_stats_data_combine(&dest->posts_with_ctxt, + &src_a->posts_with_ctxt, + &src_b->posts_with_ctxt); + + DT_performance_stats_data_combine(&dest->reaps_sans_ctxt, + &src_a->reaps_sans_ctxt, + &src_b->reaps_sans_ctxt); + + DT_performance_stats_data_combine(&dest->reaps_with_ctxt, + &src_a->reaps_with_ctxt, + &src_b->reaps_with_ctxt); + + DT_performance_stats_data_combine(&dest->latency, + &src_a->latency, &src_b->latency); +} + +double +DT_performance_stats_data_print(DT_Tdep_Print_Head * phead, + Performance_Stats_Data_t * data, double cpu_mhz) +{ + double average; + + average = (int64_t) data->total_ts / (data->num * cpu_mhz); + + DT_Tdep_PT_Printf(phead, + " Arithmetic mean : %d.%d us\n" + " maximum : %d.%d us\n" + " minimum : %d.%d us\n", + DT_whole(average), DT_hundredths(average), + DT_whole((int64_t) data->max_ts / cpu_mhz), + DT_hundredths((int64_t) data->max_ts / cpu_mhz), + DT_whole((int64_t) data->min_ts / cpu_mhz), + DT_hundredths((int64_t) data->min_ts / cpu_mhz)); + return average; +} + +void +DT_performance_stats_print(Params_t * params_ptr, + DT_Tdep_Print_Head * phead, + Performance_Stats_t * stats, + Performance_Cmd_t * cmd, Performance_Test_t * test) +{ + double cpu_mhz; + double time_s; + double mbytes; + double ops_per_sec; + double bandwidth; + double latency; + double time_per_post; + double time_per_reap; + + cpu_mhz = params_ptr->cpu_mhz; + latency = 0; +#if defined(WIN32) + /* + * The Microsoft compiler is unable to do a 64 bit conversion when + * working with double. time_ts is a 64 bit value, so we + * potentially lose precision, so limit it to the Windows + * platform. Trying to do the operation below without casting + * a 64 bit value to an unsigned int results in the error when + * using Visual C 6.0: + * + * Compiler Error C2520: conversion from unsigned __int64 to + * double not implemented, use signed __int64. + * + * Note that signed __int64 doesn't work either! + */ + time_s = (double)((unsigned int)stats->time_ts / (1000000.0 * cpu_mhz)); +#else + time_s = (double)(stats->time_ts / (1000000.0 * cpu_mhz)); +#endif + mbytes = (double)(1.0 * stats->bytes) / 1024 / 1024; + + if (0.0 == time_s) { + DT_Tdep_PT_Printf(phead, "Error determining time\n"); + return; + } else if (0 == stats->num_ops) { + DT_Tdep_PT_Printf(phead, + "Error determining number of operations\n"); + return; + } else if (0.0 == cpu_mhz) { + DT_Tdep_PT_Printf(phead, "Error determining CPU speed\n"); + return; + } + + ops_per_sec = stats->num_ops / time_s; + bandwidth = mbytes / time_s; + DT_Tdep_PT_Printf(phead, + "------------------------- Statistics -------------------------\n"); + DT_Tdep_PT_Printf(phead, + " Mode : %s\n" + " Operation Type : %s\n" + " Number of Operations : %u\n" + " Segment Size : %u\n" + " Number of Segments : %u \n" + " Pipeline Length : %u\n\n", + DT_PerformanceModeToString(cmd->mode), + DT_TransferTypeToString(cmd->op.transfer_type), + cmd->num_iterations, cmd->op.seg_size, + cmd->op.num_segs, test->ep_context.pipeline_len); + + DT_Tdep_PT_Printf(phead, + " Total Time : %d.%d sec\n" + " Total Data Exchanged : %d.%d MB\n" + " CPU Utilization : %d.%d\n" + " Operation Throughput : %d.%d ops/sec\n" + " Bandwidth : %d.%d MB/sec\n", + DT_whole(time_s), DT_hundredths(time_s), + DT_whole(mbytes), DT_hundredths(mbytes), + DT_whole(stats->cpu_utilization), + DT_hundredths(stats->cpu_utilization), + DT_whole(ops_per_sec), DT_hundredths(ops_per_sec), + DT_whole(bandwidth), DT_hundredths(bandwidth)); + + DT_Tdep_PT_Printf(phead, "\nLatency\n"); + + if (stats->latency.num) { + latency = DT_performance_stats_data_print(phead, + &stats->latency, + cpu_mhz); + } + DT_Tdep_PT_Printf(phead, "\n" + "Time Per Post\n" + " %u posts without context switches\n", + stats->posts_sans_ctxt.num); + + if (stats->posts_sans_ctxt.num) { + DT_performance_stats_data_print(phead, + &stats->posts_sans_ctxt, + cpu_mhz); + } + + DT_Tdep_PT_Printf(phead, "\n" + " %u posts with context switches\n", + stats->posts_with_ctxt.num); + + if (stats->posts_with_ctxt.num) { + DT_Tdep_PT_Printf(phead, " %u number of context switches\n", + stats->post_ctxt_switch_num); + DT_performance_stats_data_print(phead, + &stats->posts_with_ctxt, + cpu_mhz); + } + + DT_Tdep_PT_Printf(phead, "\n" + "Time Per Reap\n" + " %u reaps without context switches\n", + stats->reaps_sans_ctxt.num); + + if (stats->reaps_sans_ctxt.num) { + DT_performance_stats_data_print(phead, + &stats->reaps_sans_ctxt, + cpu_mhz); + } + + DT_Tdep_PT_Printf(phead, "\n" + " %u reaps with context switches\n", + stats->reaps_with_ctxt.num); + + if (stats->reaps_with_ctxt.num) { + DT_Tdep_PT_Printf(phead, "\n" + " %u number of context switches\n", + stats->reap_ctxt_switch_num); + + DT_performance_stats_data_print(phead, + &stats->reaps_with_ctxt, + cpu_mhz); + } + + time_per_post = + (int64_t) (stats->posts_sans_ctxt.total_ts + + stats->posts_with_ctxt.total_ts) / (cpu_mhz * + (stats-> + posts_sans_ctxt. + num + + stats-> + posts_with_ctxt. + num)); + + time_per_reap = + (int64_t) (stats->reaps_sans_ctxt.total_ts + + stats->reaps_with_ctxt.total_ts) / (cpu_mhz * + (stats-> + reaps_sans_ctxt. + num + + stats-> + reaps_with_ctxt. + num)); + + DT_Tdep_PT_Printf(phead, "\nNOTE: 1 MB = 1024 KB = 1048576 B \n"); + DT_Tdep_PT_Printf(phead, + "---------------------------------------------------------------------\n"); + DT_Tdep_PT_Printf(phead, + "raw: %s, %u, %u, %u, %u, %d.%d, %d.%d, %d.%d, %d.%d, %d.%d, %d.%d \n", + DT_TransferTypeToString(cmd->op.transfer_type), + cmd->num_iterations, + cmd->op.seg_size, + cmd->op.num_segs, + test->ep_context.pipeline_len, + DT_whole(stats->cpu_utilization), + DT_hundredths(stats->cpu_utilization), + DT_whole(ops_per_sec), + DT_hundredths(ops_per_sec), + DT_whole(bandwidth), + DT_hundredths(bandwidth), + DT_whole(latency), + DT_hundredths(latency), + DT_whole(time_per_post), + DT_hundredths(time_per_post), + DT_whole(time_per_reap), + DT_hundredths(time_per_reap)); + DT_Tdep_PT_Printf(phead, + "---------------------------------------------------------------------\n"); +} diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_performance_util.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_performance_util.c new file mode 100644 index 00000000..5023be0b --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_performance_util.c @@ -0,0 +1,618 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" + +#define DT_Mdep_GetContextSwitchNum() 0 /* FIXME */ + +/****************************************************************************/ +bool +DT_Performance_Test_Create(Per_Test_Data_t * pt_ptr, + DAT_IA_HANDLE * ia_handle, + DAT_IA_ADDRESS_PTR remote_ia_addr, + DAT_BOOLEAN is_server, + DAT_BOOLEAN is_remote_little_endian, + Performance_Test_t ** perf_test) +{ + Performance_Test_t *test_ptr; + DAT_COUNT pipeline_len; + DAT_RETURN ret; + DT_Tdep_Print_Head *phead; + + phead = pt_ptr->Params.phead; + + test_ptr = DT_MemListAlloc(pt_ptr, + "transaction_test_t", + TRANSACTIONTEST, sizeof(Performance_Test_t)); + if (NULL == test_ptr) { + return false; + } + + *perf_test = test_ptr; + + test_ptr->pt_ptr = pt_ptr; + test_ptr->remote_ia_addr = remote_ia_addr; + test_ptr->is_remote_little_endian = is_remote_little_endian; + test_ptr->base_port = + (DAT_CONN_QUAL) pt_ptr->Server_Info.first_port_number; + test_ptr->ia_handle = ia_handle; + test_ptr->cmd = &pt_ptr->Params.u.Performance_Cmd; + + ret = dat_ia_query(test_ptr->ia_handle, + NULL, DAT_IA_ALL, &test_ptr->ia_attr, 0, NULL); + if (DAT_SUCCESS != ret) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x "]: dat_ia_query error: %s\n", + test_ptr->base_port, DT_RetToString(ret)); + return false; + } + + pipeline_len = DT_min(DT_min(test_ptr->cmd->num_iterations, + test_ptr->cmd->pipeline_len), + DT_min(test_ptr->ia_attr.max_dto_per_ep, + test_ptr->ia_attr.max_evd_qlen)); + + if (RDMA_READ == test_ptr->cmd->op.transfer_type) { + pipeline_len = DT_min(pipeline_len, + test_ptr->ia_attr.max_rdma_read_per_ep); + } + + test_ptr->reqt_evd_length = pipeline_len; + test_ptr->recv_evd_length = DT_PERF_DFLT_EVD_LENGTH; + test_ptr->conn_evd_length = DT_PERF_DFLT_EVD_LENGTH; + test_ptr->creq_evd_length = DT_PERF_DFLT_EVD_LENGTH; + + /* create a protection zone */ + ret = dat_pz_create(test_ptr->ia_handle, &test_ptr->pz_handle); + if (DAT_SUCCESS != ret) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x "]: dat_pz_create error: %s\n", + test_ptr->base_port, DT_RetToString(ret)); + test_ptr->pz_handle = DAT_HANDLE_NULL; + return false; + } + + /* create 4 EVDs - recv, request+RMR, conn-request, connect */ + ret = DT_Tdep_evd_create(test_ptr->ia_handle, test_ptr->recv_evd_length, test_ptr->cno_handle, DAT_EVD_DTO_FLAG, &test_ptr->recv_evd_hdl); /* recv */ + if (DAT_SUCCESS != ret) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x + "]: dat_evd_create (recv) error: %s\n", + test_ptr->base_port, DT_RetToString(ret)); + test_ptr->recv_evd_hdl = DAT_HANDLE_NULL; + return false; + } + + ret = DT_Tdep_evd_create(test_ptr->ia_handle, test_ptr->reqt_evd_length, test_ptr->cno_handle, DAT_EVD_DTO_FLAG | DAT_EVD_RMR_BIND_FLAG, &test_ptr->reqt_evd_hdl); /* request + rmr bind */ + if (DAT_SUCCESS != ret) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x + "]: dat_evd_create (request) error: %s\n", + test_ptr->base_port, DT_RetToString(ret)); + test_ptr->reqt_evd_hdl = DAT_HANDLE_NULL; + return false; + } + + if (is_server) { + /* Client-side doesn't need CR events */ + ret = DT_Tdep_evd_create(test_ptr->ia_handle, test_ptr->creq_evd_length, DAT_HANDLE_NULL, DAT_EVD_CR_FLAG, &test_ptr->creq_evd_hdl); /* cr */ + if (DAT_SUCCESS != ret) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x + "]: dat_evd_create (cr) error: %s\n", + test_ptr->base_port, + DT_RetToString(ret)); + test_ptr->creq_evd_hdl = DAT_HANDLE_NULL; + return false; + } + } + + ret = DT_Tdep_evd_create(test_ptr->ia_handle, test_ptr->conn_evd_length, DAT_HANDLE_NULL, DAT_EVD_CONNECTION_FLAG, &test_ptr->conn_evd_hdl); /* conn */ + if (DAT_SUCCESS != ret) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x + "]: dat_evd_create (conn) error: %s\n", + test_ptr->base_port, DT_RetToString(ret)); + test_ptr->conn_evd_hdl = DAT_HANDLE_NULL; + return false; + } + + /* + * Set up the EP context: + * create the EP + * allocate buffers for remote memory info and sync message + * post the receive buffers + * connect + * set up buffers and remote memory info + * send across our info + * recv the other side's info and extract what we need + */ + test_ptr->ep_context.ep_attr = test_ptr->pt_ptr->ep_attr; + test_ptr->ep_context.ep_attr.max_request_dtos = pipeline_len; + + /* Create EP */ + ret = dat_ep_create(test_ptr->ia_handle, /* IA */ + test_ptr->pz_handle, /* PZ */ + test_ptr->recv_evd_hdl, /* recv */ + test_ptr->reqt_evd_hdl, /* request */ + test_ptr->conn_evd_hdl, /* connect */ + &test_ptr->ep_context.ep_attr, /* EP attrs */ + &test_ptr->ep_context.ep_handle); + if (DAT_SUCCESS != ret) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x "]: dat_ep_create error: %s\n", + test_ptr->base_port, DT_RetToString(ret)); + test_ptr->ep_context.ep_handle = DAT_HANDLE_NULL; + return false; + } + + /* + * Allocate a buffer pool so we can exchange the + * remote memory info and initialize. + */ + test_ptr->ep_context.bp = DT_BpoolAlloc(test_ptr->pt_ptr, phead, test_ptr->ia_handle, test_ptr->pz_handle, test_ptr->ep_context.ep_handle, DAT_HANDLE_NULL, /* rmr */ + DT_PERF_SYNC_BUFF_SIZE, 2, /* 2 RMIs */ + DAT_OPTIMAL_ALIGNMENT, + false, false); + if (!test_ptr->ep_context.bp) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x + "]: no memory for remote memory buffers\n", + test_ptr->base_port); + return false; + } + + DT_Tdep_PT_Debug(3, (phead, + "0: SYNC_SEND %p\n", + (DAT_PVOID) DT_Bpool_GetBuffer(test_ptr-> + ep_context.bp, + DT_PERF_SYNC_SEND_BUFFER_ID))); + DT_Tdep_PT_Debug(3, + (phead, "1: SYNC_RECV %p\n", + (DAT_PVOID) DT_Bpool_GetBuffer(test_ptr->ep_context. + bp, + DT_PERF_SYNC_RECV_BUFFER_ID))); + + /* + * Post recv and sync buffers + */ + if (!DT_post_recv_buffer(phead, + test_ptr->ep_context.ep_handle, + test_ptr->ep_context.bp, + DT_PERF_SYNC_RECV_BUFFER_ID, + DT_PERF_SYNC_BUFF_SIZE)) { + /* error message printed by DT_post_recv_buffer */ + return false; + } + + /* + * Fill in the test_ptr with relevant command info + */ + test_ptr->ep_context.op.transfer_type = test_ptr->cmd->op.transfer_type; + test_ptr->ep_context.op.num_segs = test_ptr->cmd->op.num_segs; + test_ptr->ep_context.op.seg_size = test_ptr->cmd->op.seg_size; + + /* + * Exchange remote memory info: If we're going to participate + * in an RDMA, we need to allocate memory buffers and advertise + * them to the other side. + */ + test_ptr->ep_context.op.Rdma_Context = (DAT_RMR_CONTEXT) 0; + test_ptr->ep_context.op.Rdma_Address = 0; + test_ptr->ep_context.port = test_ptr->base_port; + test_ptr->ep_context.pipeline_len = pipeline_len; + + return true; +} + +/****************************************************************************/ +void +DT_Performance_Test_Destroy(Per_Test_Data_t * pt_ptr, + Performance_Test_t * test_ptr, + DAT_BOOLEAN is_server) +{ + DAT_RETURN ret; + DAT_EP_HANDLE ep_handle; + DT_Tdep_Print_Head *phead; + + phead = pt_ptr->Params.phead; + + ep_handle = DAT_HANDLE_NULL; + + /* Free the per-op buffers */ + if (test_ptr->ep_context.op.bp) { + if (!DT_Bpool_Destroy(test_ptr->pt_ptr, + phead, test_ptr->ep_context.op.bp)) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x + "]: Warning: Bpool destroy fails\n", + test_ptr->base_port); + /* carry on trying, regardless */ + } + } + + /* Free the remote memory info exchange buffers */ + if (test_ptr->ep_context.bp) { + if (!DT_Bpool_Destroy(test_ptr->pt_ptr, + phead, test_ptr->ep_context.bp)) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x + "]: Warning: Bpool destroy fails\n", + test_ptr->base_port); + /* carry on trying, regardless */ + } + } + + /* + * Disconnect -- we may have left recv buffers posted, if we + * bailed out mid-setup, or ran to completion + * normally, so we use abrupt closure. + */ + if (test_ptr->ep_context.ep_handle) { + ret = dat_ep_disconnect(test_ptr->ep_context.ep_handle, + DAT_CLOSE_ABRUPT_FLAG); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x + "]: Warning: dat_ep_disconnect error %s\n", + test_ptr->base_port, + DT_RetToString(ret)); + /* carry on trying, regardless */ + } else if (!DT_disco_event_wait(phead, test_ptr->conn_evd_hdl, + &ep_handle)) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x + "]: bad disconnect event\n", + test_ptr->base_port); + } + } + + if (DAT_HANDLE_NULL != ep_handle) { + /* Destroy the EP */ + ret = dat_ep_free(ep_handle); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x + "]: dat_ep_free error: %s\n", + test_ptr->base_port, + DT_RetToString(ret)); + /* carry on trying, regardless */ + } + } + + /* clean up the EVDs */ + if (test_ptr->conn_evd_hdl) { + ret = DT_Tdep_evd_free(test_ptr->conn_evd_hdl); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x + "]: dat_evd_free (conn) error: %s\n", + test_ptr->base_port, + DT_RetToString(ret)); + /* fall through, keep trying */ + } + } + if (is_server) { + if (test_ptr->creq_evd_hdl) { + ret = DT_Tdep_evd_free(test_ptr->creq_evd_hdl); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x + "]: dat_evd_free (creq) error: %s\n", + test_ptr->base_port, + DT_RetToString(ret)); + /* fall through, keep trying */ + } + } + } + if (test_ptr->reqt_evd_hdl) { + ret = DT_Tdep_evd_free(test_ptr->reqt_evd_hdl); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x + "]: dat_evd_free (reqt) error: %s\n", + test_ptr->base_port, + DT_RetToString(ret)); + /* fall through, keep trying */ + } + } + if (test_ptr->recv_evd_hdl) { + ret = DT_Tdep_evd_free(test_ptr->recv_evd_hdl); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x + "]: dat_evd_free (recv) error: %s\n", + test_ptr->base_port, + DT_RetToString(ret)); + /* fall through, keep trying */ + } + } + + /* clean up the PZ */ + if (test_ptr->pz_handle) { + ret = dat_pz_free(test_ptr->pz_handle); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x + "]: dat_pz_free error: %s\n", + test_ptr->base_port, + DT_RetToString(ret)); + /* fall through, keep trying */ + } + } + + DT_MemListFree(test_ptr->pt_ptr, test_ptr); + DT_Tdep_PT_Debug(1, + (phead, "Test[" F64x "]: cleanup is done\n", + test_ptr->base_port)); + +} + +/****************************************************************************/ +bool +DT_performance_post_rdma_op(Performance_Ep_Context_t * ep_context, + DAT_EVD_HANDLE reqt_evd_hdl, + Performance_Stats_t * stats) +{ + unsigned int j; + unsigned long int bytes; + unsigned long pre_ctxt_num; + unsigned long post_ctxt_num; + DT_Mdep_TimeStamp pre_ts; + DT_Mdep_TimeStamp post_ts; + DAT_DTO_COOKIE cookie; + DAT_RETURN ret; + Performance_Test_Op_t *op = &ep_context->op; + DAT_LMR_TRIPLET *iov = DT_Bpool_GetIOV(op->bp, 0); + DAT_RMR_TRIPLET rmr_triplet; + + bytes = op->seg_size * op->num_segs; + + /* Prep the inputs */ + for (j = 0; j < op->num_segs; j++) { + iov[j].virtual_address = (DAT_VADDR) (uintptr_t) + DT_Bpool_GetBuffer(op->bp, j); + iov[j].segment_length = op->seg_size; + iov[j].lmr_context = DT_Bpool_GetLMR(op->bp, j); + } + + rmr_triplet.virtual_address = op->Rdma_Address; + rmr_triplet.segment_length = op->seg_size * op->num_segs; + rmr_triplet.rmr_context = op->Rdma_Context; + + cookie.as_ptr = NULL; + + if (RDMA_WRITE == op->transfer_type) { + pre_ctxt_num = DT_Mdep_GetContextSwitchNum(); + pre_ts = DT_Mdep_GetTimeStamp(); + + ret = dat_ep_post_rdma_write(ep_context->ep_handle, + op->num_segs, + iov, + cookie, + &rmr_triplet, + DAT_COMPLETION_DEFAULT_FLAG); + + post_ts = DT_Mdep_GetTimeStamp(); + post_ctxt_num = DT_Mdep_GetContextSwitchNum(); + + stats->bytes += bytes; + } else { + pre_ctxt_num = DT_Mdep_GetContextSwitchNum(); + pre_ts = DT_Mdep_GetTimeStamp(); + + ret = dat_ep_post_rdma_read(ep_context->ep_handle, + op->num_segs, + iov, + cookie, + &rmr_triplet, + DAT_COMPLETION_DEFAULT_FLAG); + + post_ts = DT_Mdep_GetTimeStamp(); + post_ctxt_num = DT_Mdep_GetContextSwitchNum(); + + stats->bytes += bytes; + } + + if (DAT_SUCCESS != ret) { + return false; + } + + DT_performance_stats_record_post(stats, + post_ctxt_num - pre_ctxt_num, + post_ts - pre_ts); + + return true; +} + +/****************************************************************************/ +unsigned int +DT_performance_reap(DT_Tdep_Print_Head * phead, + DAT_EVD_HANDLE evd_handle, + Performance_Mode_Type mode, Performance_Stats_t * stats) +{ + if (BLOCKING_MODE == mode) { + return DT_performance_wait(phead, evd_handle, stats); + } else { + return DT_performance_poll(phead, evd_handle, stats); + } +} + +/****************************************************************************/ +unsigned int +DT_performance_wait(DT_Tdep_Print_Head * phead, + DAT_EVD_HANDLE evd_handle, Performance_Stats_t * stats) +{ + DAT_COUNT i; + DAT_COUNT queue_size; + DAT_RETURN ret; + DAT_EVENT event; + unsigned long pre_ctxt_num; + unsigned long post_ctxt_num; + DT_Mdep_TimeStamp pre_ts; + DT_Mdep_TimeStamp post_ts; + + queue_size = 0; + + pre_ctxt_num = DT_Mdep_GetContextSwitchNum(); + pre_ts = DT_Mdep_GetTimeStamp(); + + ret = DT_Tdep_evd_wait(evd_handle, DAT_TIMEOUT_INFINITE, &event); + + post_ts = DT_Mdep_GetTimeStamp(); + post_ctxt_num = DT_Mdep_GetContextSwitchNum(); + + if (DAT_SUCCESS != ret) { + DT_Tdep_PT_Printf(phead, + "Test Error: dapl_event_dequeue failed: %s\n", + DT_RetToString(ret)); + return 0; + } else if (event.event_number == DAT_DTO_COMPLETION_EVENT) { + DT_performance_stats_record_reap(stats, + post_ctxt_num - pre_ctxt_num, + post_ts - pre_ts); + } else { + /* This should not happen. There has been an error if it does. */ + + DT_Tdep_PT_Printf(phead, + "Warning: dapl_performance_wait swallowing %s event\n", + DT_EventToSTr(event.event_number)); + + return 0; + } + + for (i = 0; i < queue_size; i++) { + pre_ctxt_num = DT_Mdep_GetContextSwitchNum(); + pre_ts = DT_Mdep_GetTimeStamp(); + + ret = DT_Tdep_evd_dequeue(evd_handle, &event); + + post_ts = DT_Mdep_GetTimeStamp(); + post_ctxt_num = DT_Mdep_GetContextSwitchNum(); + + if (DAT_GET_TYPE(ret) == DAT_QUEUE_EMPTY) { + continue; + } else if (DAT_SUCCESS != ret) { + DT_Tdep_PT_Printf(phead, + "Test Error: dapl_event_dequeue failed: %s\n", + DT_RetToString(ret)); + return 0; + } else if (event.event_number == DAT_DTO_COMPLETION_EVENT) { + DT_performance_stats_record_reap(stats, + post_ctxt_num - + pre_ctxt_num, + post_ts - pre_ts); + } else { + /* This should not happen. There has been an error if it does. */ + + DT_Tdep_PT_Printf(phead, + "Warning: dapl_performance_wait swallowing %s event\n", + DT_EventToSTr(event.event_number)); + + return 0; + } + } + + return ++queue_size; +} + +/****************************************************************************/ +unsigned int +DT_performance_poll(DT_Tdep_Print_Head * phead, + DAT_EVD_HANDLE evd_handle, Performance_Stats_t * stats) +{ + DAT_RETURN ret; + DAT_EVENT event; + unsigned long pre_ctxt_num; + unsigned long post_ctxt_num; + DT_Mdep_TimeStamp pre_ts; + DT_Mdep_TimeStamp post_ts; + + for (;;) { + pre_ctxt_num = DT_Mdep_GetContextSwitchNum(); + pre_ts = DT_Mdep_GetTimeStamp(); + + ret = DT_Tdep_evd_dequeue(evd_handle, &event); + + post_ts = DT_Mdep_GetTimeStamp(); + post_ctxt_num = DT_Mdep_GetContextSwitchNum(); + + if (DAT_GET_TYPE(ret) == DAT_QUEUE_EMPTY) { + continue; + } else if (DAT_SUCCESS != ret) { + DT_Tdep_PT_Printf(phead, + "Test Error: dapl_event_dequeue failed: %s\n", + DT_RetToString(ret)); + return 0; + } else if (event.event_number == DAT_DTO_COMPLETION_EVENT) { + DT_performance_stats_record_reap(stats, + post_ctxt_num - + pre_ctxt_num, + post_ts - pre_ts); + return 1; + } else { + /* This should not happen. There has been an error if it does. */ + + DT_Tdep_PT_Printf(phead, + "Warning: dapl_performance_wait swallowing %s event\n", + DT_EventToSTr(event.event_number)); + + return 0; + } + } + + /*never reached */ + return 0; +} + +void +DT_Performance_Cmd_PT_Print(DT_Tdep_Print_Head * phead, Performance_Cmd_t * cmd) +{ + DT_Tdep_PT_Printf(phead, "-------------------------------------\n"); + DT_Tdep_PT_Printf(phead, "PerfCmd.server_name : %s\n", + cmd->server_name); + DT_Tdep_PT_Printf(phead, "PerfCmd.dapl_name : %s\n", + cmd->dapl_name); + DT_Tdep_PT_Printf(phead, "PerfCmd.mode : %s\n", + (cmd->mode == + BLOCKING_MODE) ? "BLOCKING" : "POLLING"); + DT_Tdep_PT_Printf(phead, "PerfCmd.num_iterations : %d\n", + cmd->num_iterations); + DT_Tdep_PT_Printf(phead, "PerfCmd.pipeline_len : %d\n", + cmd->pipeline_len); + DT_Tdep_PT_Printf(phead, "PerfCmd.op.transfer_type : %s\n", + cmd->op.transfer_type == + RDMA_READ ? "RDMA_READ" : cmd->op.transfer_type == + RDMA_WRITE ? "RDMA_WRITE" : "SEND_RECV"); + DT_Tdep_PT_Printf(phead, "PerfCmd.op.num_segs : %d\n", + cmd->op.num_segs); + DT_Tdep_PT_Printf(phead, "PerfCmd.op.seg_size : %d\n", + cmd->op.seg_size); +} diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_quit_util.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_quit_util.c new file mode 100644 index 00000000..a0524c4a --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_quit_util.c @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" + +void DT_Quit_Cmd_PT_Print(DT_Tdep_Print_Head * phead, Quit_Cmd_t * cmd) +{ + /* DT_Mdep_printf ("Quit_Cmd.server_name: %s\n", cmd->server_name); + DT_Mdep_printf ("Quit_Cmd.device_name: %s\n", cmd->device_name); + */ + DT_Tdep_PT_Printf(phead, "Quit_Cmd.server_name: %s\n", + cmd->server_name); + DT_Tdep_PT_Printf(phead, "Quit_Cmd.device_name: %s\n", + cmd->device_name); + +} diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_server.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_server.c new file mode 100644 index 00000000..443425c5 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_server.c @@ -0,0 +1,855 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" + +#ifdef DFLT_QLEN +#undef DFLT_QLEN +#endif + +#define DFLT_QLEN 8 /* default event queue length */ + +int send_control_data(DT_Tdep_Print_Head * phead, + unsigned char *buffp, + Per_Server_Data_t * ps_ptr, Per_Test_Data_t * pt_ptr); + +void DT_cs_Server(Params_t * params_ptr) +{ + Server_Cmd_t *Server_Cmd = ¶ms_ptr->u.Server_Cmd; + Client_Info_t *Client_Info = NULL; + Transaction_Cmd_t *Transaction_Cmd = NULL; + Quit_Cmd_t *Quit_Cmd = NULL; + Performance_Cmd_t *Performance_Cmd = NULL; + Per_Server_Data_t *ps_ptr = NULL; + Per_Test_Data_t *pt_ptr = NULL; + Started_server_t *temp_list = NULL; + Started_server_t *pre_list = NULL; + unsigned char *buffp = NULL; + char *module = "DT_cs_Server"; + + DAT_DTO_COOKIE dto_cookie; + DAT_DTO_COMPLETION_EVENT_DATA dto_stat; + DAT_RETURN ret; + DT_Tdep_Print_Head *phead; + + phead = params_ptr->phead; + + /* Check if device from command line already in use */ + temp_list = DT_started_server_list; + while (temp_list) { + if (strcmp(temp_list->devicename, Server_Cmd->dapl_name) == 0) { + DT_Tdep_PT_Printf(phead, + "NOTICE: server already started for this NIC: %s\n", + Server_Cmd->dapl_name); + return; + } + temp_list = temp_list->next; + } + + /* Alloc memory for server list */ + temp_list = + (Started_server_t *) DT_Mdep_Malloc(sizeof(Started_server_t)); + if (temp_list == 0) { + DT_Tdep_PT_Printf(phead, "no memory for server_list\n"); + return; + } + strcpy(temp_list->devicename, Server_Cmd->dapl_name); + temp_list->next = DT_started_server_list; + DT_started_server_list = temp_list; + + if (Server_Cmd->debug) { + /* Echo our inputs if debugging */ + DT_Server_Cmd_PT_Print(phead, Server_Cmd); + } + + /* Allocate memory for Per_Server_Data */ + ps_ptr = + (Per_Server_Data_t *) DT_Mdep_Malloc(sizeof(Per_Server_Data_t)); + if (ps_ptr == 0) { + DT_Tdep_PT_Printf(phead, "no memory for ps_data\n"); + goto server_exit; + } + DT_Mdep_LockInit(&ps_ptr->num_clients_lock); + ps_ptr->NextPortNumber = SERVER_PORT_NUMBER + 1; + ps_ptr->num_clients = 0; + + /* Open the IA */ + ret = dat_ia_open(Server_Cmd->dapl_name, + DFLT_QLEN, + &ps_ptr->async_evd_hdl, &ps_ptr->ia_handle); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: Could not open %s (%s)\n", + module, + Server_Cmd->dapl_name, DT_RetToString(ret)); + ps_ptr->ia_handle = DAT_HANDLE_NULL; + goto server_exit; + } + DT_Tdep_PT_Debug(1, + (phead, "%s: IA %s opened\n", module, + Server_Cmd->dapl_name)); + + /* Create a PZ */ + ret = dat_pz_create(ps_ptr->ia_handle, &ps_ptr->pz_handle); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_pz_create error: %s\n", + module, DT_RetToString(ret)); + ps_ptr->pz_handle = DAT_HANDLE_NULL; + goto server_exit; + } + DT_Tdep_PT_Debug(1, (phead, "%s: PZ created\n", module)); + + /* Create 4 events - recv, request, connection-request, connect */ + ret = DT_Tdep_evd_create(ps_ptr->ia_handle, + DFLT_QLEN, + NULL, DAT_EVD_DTO_FLAG, &ps_ptr->recv_evd_hdl); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_evd_create (recv) failed %s\n", + module, DT_RetToString(ret)); + ps_ptr->recv_evd_hdl = DAT_HANDLE_NULL; + goto server_exit; + } + ret = DT_Tdep_evd_create(ps_ptr->ia_handle, + DFLT_QLEN, + NULL, + DAT_EVD_DTO_FLAG | DAT_EVD_RMR_BIND_FLAG, + &ps_ptr->reqt_evd_hdl); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_evd_create (send) failed %s\n", + module, DT_RetToString(ret)); + ps_ptr->reqt_evd_hdl = DAT_HANDLE_NULL; + goto server_exit; + } + ret = DT_Tdep_evd_create(ps_ptr->ia_handle, + DFLT_QLEN, + NULL, DAT_EVD_CR_FLAG, &ps_ptr->creq_evd_hdl); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_evd_create (cr) failed %s\n", + module, DT_RetToString(ret)); + ps_ptr->creq_evd_hdl = DAT_HANDLE_NULL; + goto server_exit; + } + ret = DT_Tdep_evd_create(ps_ptr->ia_handle, + DFLT_QLEN, + NULL, + DAT_EVD_CONNECTION_FLAG, + &ps_ptr->conn_evd_hdl); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_evd_create (conn) failed %s\n", + module, DT_RetToString(ret)); + ps_ptr->conn_evd_hdl = DAT_HANDLE_NULL; + goto server_exit; + } + + /* Create the EP */ + ret = dat_ep_create(ps_ptr->ia_handle, /* IA */ + ps_ptr->pz_handle, /* PZ */ + ps_ptr->recv_evd_hdl, /* recv */ + ps_ptr->reqt_evd_hdl, /* request */ + ps_ptr->conn_evd_hdl, /* connect */ + (DAT_EP_ATTR *) NULL, &ps_ptr->ep_handle); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_ep_create error: %s\n", + module, DT_RetToString(ret)); + ps_ptr->ep_handle = DAT_HANDLE_NULL; + goto server_exit; + } + DT_Tdep_PT_Debug(1, (phead, "%s: EP created\n", module)); + + /* Create PSP */ + ret = dat_psp_create(ps_ptr->ia_handle, + SERVER_PORT_NUMBER, + ps_ptr->creq_evd_hdl, + DAT_PSP_CONSUMER_FLAG, &ps_ptr->psp_handle); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_psp_create error: %s\n", + module, DT_RetToString(ret)); + ps_ptr->psp_handle = DAT_HANDLE_NULL; + goto server_exit; + } + DT_Tdep_PT_Debug(1, (phead, "%s: PSP created\n", module)); + + /* + * Create two buffers, large enough to hold ClientInfo and the largest + * command we'll use. + */ + ps_ptr->bpool = DT_BpoolAlloc(NULL, phead, ps_ptr->ia_handle, ps_ptr->pz_handle, ps_ptr->ep_handle, DAT_HANDLE_NULL, /* no RMR */ + DT_RoundSize(sizeof(Transaction_Cmd_t), 8192), 3, /* num_buffers */ + DAT_OPTIMAL_ALIGNMENT, false, false); + if (ps_ptr->bpool == 0) { + DT_Tdep_PT_Printf(phead, + "%s: no memory for command buffer pool.\n", + module); + goto server_exit; + } + + DT_Tdep_PT_Debug(3, (phead, + "Recv 0 %p\n", + (DAT_PVOID) DT_Bpool_GetBuffer(ps_ptr->bpool, 0))); + DT_Tdep_PT_Debug(3, (phead, + "Recv 1 %p\n", + (DAT_PVOID) DT_Bpool_GetBuffer(ps_ptr->bpool, 1))); + DT_Tdep_PT_Debug(3, (phead, + "SrvInfo 2 %p\n", + (DAT_PVOID) DT_Bpool_GetBuffer(ps_ptr->bpool, 2))); + + /* Initialize the performance test lock in case an incoming test + * is a performance test, so we can allow only one at a time. + * Otherwise, multiple performance tests cause a race condition + * between the server creating a new thread trying to allocate a + * PSP with the same ID as another thread that is either running + * a test on that same ID or hasn't yet destroyed it. Only one + * PSP with a particular ID can exist at a time. It's a + * de-facto shared resource that must be protected. + */ + /************************************************************************ + * Loop accepting connections and acting on them + */ + for (; /* EVER */ ;) { + DAT_CR_HANDLE cr_handle; + DAT_CR_ARRIVAL_EVENT_DATA cr_stat; + DAT_EVENT_NUMBER event_num; + + /* Set up the Per_Test_Data */ + pt_ptr = DT_Alloc_Per_Test_Data(phead); + if (!pt_ptr) { + DT_Tdep_PT_Printf(phead, + "%s: no memory for Per_Test_Data\n", + module); + goto server_exit; + } + DT_MemListInit(pt_ptr); + DT_Thread_Init(pt_ptr); + pt_ptr->local_is_server = true; + pt_ptr->ps_ptr = ps_ptr; + memcpy((void *)(uintptr_t) & pt_ptr->Params, + (const void *)params_ptr, sizeof(Params_t)); + + /* Server_Info, Client_Info, Params set up below */ + + /* Gather whatever info we want about defaults */ + if (!DT_query(pt_ptr, ps_ptr->ia_handle, ps_ptr->ep_handle)) { + goto server_exit; + } + + /* Post recv buffers for ClientInfo and Transaction_Cmd_t */ + DT_Tdep_PT_Debug(1, (phead, "%s: Posting 2 recvs\n", module)); + if (!DT_post_recv_buffer(phead, + ps_ptr->ep_handle, + ps_ptr->bpool, + 0, + DT_Bpool_GetBuffSize(ps_ptr->bpool, + 0))) { + DT_Tdep_PT_Printf(phead, + "%s: cannot post ClientInfo recv buffer\n", + module); + goto server_exit; + } + if (!DT_post_recv_buffer(phead, + ps_ptr->ep_handle, + ps_ptr->bpool, + 1, + DT_Bpool_GetBuffSize(ps_ptr->bpool, + 1))) { + DT_Tdep_PT_Printf(phead, + "%s: cannot post Transaction_Cmd_t recv buffer\n", + module); + goto server_exit; + } + + /* message to help automated test scripts know when to start the client */ + DT_Tdep_PT_Printf(phead, + "Dapltest: Service Point Ready - %s\n", + Server_Cmd->dapl_name); + + DT_Mdep_flush(); + + DT_Tdep_PT_Debug(1, + (phead, "%s: Waiting for Connection Request\n", + module)); + if (!DT_cr_event_wait(phead, ps_ptr->creq_evd_hdl, &cr_stat) + || !DT_cr_check(phead, &cr_stat, ps_ptr->psp_handle, + SERVER_PORT_NUMBER, &cr_handle, module)) { + + DT_Tdep_PT_Printf(phead, + "CR Check failed, file %s line %d\n", + __FILE__, __LINE__); + goto server_exit; + } + + DT_Tdep_PT_Debug(1, + (phead, "%s: Accepting Connection Request\n", + module)); + ret = + dat_cr_accept(cr_handle, ps_ptr->ep_handle, 0, + (DAT_PVOID) 0); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_cr_accept error: %s\n", + module, DT_RetToString(ret)); + goto server_exit; + } + + DT_Tdep_PT_Debug(1, + (phead, "%s: Awaiting connection ...\n", + module)); + if (!DT_conn_event_wait + (phead, ps_ptr->ep_handle, ps_ptr->conn_evd_hdl, + &event_num)) { + DT_Tdep_PT_Printf(phead, + "%s: error awaiting conn-established event\n", + module); + goto server_exit; + } + + if (DT_dapltest_debug) { + DT_Tdep_PT_Debug(1, + (phead, "%s: Connected!\n", module)); + get_ep_connection_state(phead, ps_ptr->ep_handle); + } + + /* Wait for Client_Info */ + dto_cookie.as_64 = LZERO; + dto_cookie.as_ptr = + (DAT_PVOID) (uintptr_t) DT_Bpool_GetBuffer(ps_ptr->bpool, + 0); + DT_Tdep_PT_Debug(1, + (phead, "%s: Waiting for Client_Info\n", + module)); + if (!DT_dto_event_wait(phead, ps_ptr->recv_evd_hdl, &dto_stat) + || !DT_dto_check(phead, &dto_stat, ps_ptr->ep_handle, + DT_Bpool_GetBuffSize(ps_ptr->bpool, 0), + dto_cookie, "Client_Info_Recv")) { + goto server_exit; + } + DT_Tdep_PT_Debug(1, (phead, "%s: Got Client_Info\n", module)); + + /* Extract the Client_Info */ + Client_Info = + (Client_Info_t *) DT_Bpool_GetBuffer(ps_ptr->bpool, 0); + DT_Client_Info_Endian(Client_Info); + memcpy((void *)(uintptr_t) & pt_ptr->Client_Info, + (const void *)Client_Info, sizeof(Client_Info_t)); + + /* Wait for client's command info */ + dto_cookie.as_64 = LZERO; + dto_cookie.as_ptr = + (DAT_PVOID) (uintptr_t) DT_Bpool_GetBuffer(ps_ptr->bpool, + 1); + DT_Tdep_PT_Debug(1, + (phead, "%s: Waiting for Client_Cmd_Info\n", + module)); + if (!DT_dto_event_wait(phead, ps_ptr->recv_evd_hdl, &dto_stat) + || !DT_dto_check(phead, &dto_stat, ps_ptr->ep_handle, + DT_Bpool_GetBuffSize(ps_ptr->bpool, 1), + dto_cookie, "Client_Cmd_Recv")) { + goto server_exit; + } + + /* Extract the client's command info */ + switch (Client_Info->test_type) { + case TRANSACTION_TEST: + { + Transaction_Cmd = (Transaction_Cmd_t *) + DT_Bpool_GetBuffer(ps_ptr->bpool, 1); + DT_Transaction_Cmd_Endian(Transaction_Cmd, + false); + memcpy((void *)(uintptr_t) & pt_ptr->Params.u. + Transaction_Cmd, + (const void *)Transaction_Cmd, + sizeof(Transaction_Cmd_t)); + break; + } + + case QUIT_TEST: + { + Quit_Cmd = + (Quit_Cmd_t *) DT_Bpool_GetBuffer(ps_ptr-> + bpool, 1); + DT_Quit_Cmd_Endian(Quit_Cmd, false); + memcpy((void *)(uintptr_t) & pt_ptr->Params.u. + Quit_Cmd, (const void *)Quit_Cmd, + sizeof(Quit_Cmd_t)); + break; + } + + case PERFORMANCE_TEST: + { + Performance_Cmd = (Performance_Cmd_t *) + DT_Bpool_GetBuffer(ps_ptr->bpool, 1); + DT_Performance_Cmd_Endian(Performance_Cmd); + memcpy((void *)(uintptr_t) & pt_ptr->Params.u. + Performance_Cmd, + (const void *)Performance_Cmd, + sizeof(Performance_Cmd_t)); + break; + } + + default: + { + DT_Tdep_PT_Printf(phead, + "Unknown TestType received\n"); + goto server_exit; + break; + } + } + + /* Setup Server Info */ + DT_Tdep_PT_Debug(1, (phead, "%s: Send Server_Info\n", module)); + pt_ptr->Server_Info.dapltest_version = DAPLTEST_VERSION; + pt_ptr->Server_Info.is_little_endian = + DT_local_is_little_endian; + /* reset port, don't eat up port space on long runs */ + if (ps_ptr->NextPortNumber >= SERVER_PORT_NUMBER + 1000) + ps_ptr->NextPortNumber = SERVER_PORT_NUMBER + 1; + pt_ptr->Server_Info.first_port_number = ps_ptr->NextPortNumber; + ps_ptr->NextPortNumber += pt_ptr->Client_Info.total_threads; + + /* This had to be done here because the pt_ptr is being fed to + * the thread as its context, and if it isn't properly + * initialized before the thread spawns then the thread may + * incorrectly set up its PSP and the server will be listening + * on the WRONG PORT! + */ + + switch (Client_Info->test_type) { + case TRANSACTION_TEST: + { + /* create a thread to handle this pt_ptr; */ + ps_ptr->NextPortNumber += + (pt_ptr->Params.u.Transaction_Cmd. + eps_per_thread - + 1) * pt_ptr->Client_Info.total_threads; + DT_Tdep_PT_Debug(1, + (phead, + "%s: Creating Transaction Test Thread\n", + module)); + pt_ptr->thread = + DT_Thread_Create(pt_ptr, + DT_Transaction_Test_Server, + pt_ptr, + DT_MDEP_DEFAULT_STACK_SIZE); + if (pt_ptr->thread == 0) { + DT_Tdep_PT_Printf(phead, + "no memory to create thread\n"); + goto server_exit; + } + break; + } + + case QUIT_TEST: + { + DT_Tdep_PT_Debug(1, + (phead, + "Client Requests Server to Quit\n")); + (void)send_control_data(phead, buffp, ps_ptr, + pt_ptr); + goto server_exit; + break; + } + + case LIMIT_TEST: + { + DT_Tdep_PT_Debug(1, + (phead, + "Limit Test is Client-side Only!\n")); + (void)send_control_data(phead, buffp, ps_ptr, + pt_ptr); + goto server_exit; + break; + } + + case PERFORMANCE_TEST: + { + /* create a thread to handle this pt_ptr; */ + DT_Tdep_PT_Debug(1, + (phead, + "%s: Creating Performance Test Thread\n", + module)); + pt_ptr->thread = + DT_Thread_Create(pt_ptr, + DT_Performance_Test_Server, + pt_ptr, + DT_MDEP_DEFAULT_STACK_SIZE); + if (pt_ptr->thread == 0) { + DT_Tdep_PT_Printf(phead, + "no memory to create thread\n"); + goto server_exit; + } + /* take the performance test lock to serialize */ + DT_Mdep_Lock(&g_PerfTestLock); + + break; + } + + case FFT_TEST: + + default: + { + DT_Tdep_PT_Printf(phead, + "Unknown TestType received\n"); + (void)send_control_data(phead, buffp, ps_ptr, + pt_ptr); + goto server_exit; + break; + } + } + + /* Start the new test thread */ + DT_Tdep_PT_Debug(1, + (phead, "%s: Starting Test Thread\n", module)); + if (DT_Thread_Start(pt_ptr->thread) == false) { + DT_Tdep_PT_Debug(1, + (phead, + "failed to start test thread\n")); + goto server_exit; + } + + buffp = DT_Bpool_GetBuffer(ps_ptr->bpool, 2); /* 3rd buffer */ + memcpy((void *)buffp, + (const void *)&pt_ptr->Server_Info, + sizeof(Server_Info_t)); + DT_Server_Info_Endian((Server_Info_t *) buffp); + + /* Perform obligatory version check */ + if (pt_ptr->Client_Info.dapltest_version != DAPLTEST_VERSION) { + DT_Tdep_PT_Printf(phead, + "%s: %s: Server %d, Client %d\n", + module, + "DAPLTEST VERSION MISMATCH", + DAPLTEST_VERSION, + pt_ptr->Client_Info.dapltest_version); + goto server_exit; + } + DT_Tdep_PT_Debug(1, (phead, "%s: Version OK!\n", module)); + + DT_Mdep_wait_object_wait(&pt_ptr->synch_wait_object, + DAT_TIMEOUT_INFINITE); + + /* Send the Server_Info */ + DT_Tdep_PT_Debug(1, (phead, "%s: Send Server_Info\n", module)); + + if (!DT_post_send_buffer(phead, ps_ptr->ep_handle, + ps_ptr->bpool, + 2, + DT_Bpool_GetBuffSize(ps_ptr->bpool, + 2))) { + DT_Tdep_PT_Printf(phead, + "%s: cannot send Server_Info\n", + module); + goto server_exit; + } + /* reap the send and verify it */ + dto_cookie.as_64 = LZERO; + dto_cookie.as_ptr = + (DAT_PVOID) (uintptr_t) DT_Bpool_GetBuffer(ps_ptr->bpool, + 2); + if (!DT_dto_event_wait(phead, ps_ptr->reqt_evd_hdl, &dto_stat) + || !DT_dto_check(phead, &dto_stat, ps_ptr->ep_handle, + DT_Bpool_GetBuffSize(ps_ptr->bpool, 2), + dto_cookie, "Server_Info_Send")) { + goto server_exit; + } + + /* Count this new client and get ready for the next */ + DT_Mdep_Lock(&ps_ptr->num_clients_lock); + ps_ptr->num_clients++; + DT_Mdep_Unlock(&ps_ptr->num_clients_lock); + + /* we passed the pt_ptr to the thread and must now 'forget' it */ + pt_ptr = 0; + +#ifdef CM_BUSTED + DT_Tdep_PT_Debug(1, + (phead, + "%s: Server exiting because provider does not support\n" + " multiple connections to the same service point\n", + module)); + /* Until connections are healthier we run just one test */ + break; +#else + ret = + dat_ep_disconnect(ps_ptr->ep_handle, + DAT_CLOSE_GRACEFUL_FLAG); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_ep_disconnect fails: %s\n", + module, DT_RetToString(ret)); + goto server_exit; + } + if (!DT_disco_event_wait(phead, ps_ptr->conn_evd_hdl, NULL)) { + DT_Tdep_PT_Printf(phead, "%s: bad disconnect event\n", + module); + goto server_exit; + } + + /* reset the EP to get back into the game */ + dat_ep_reset(ps_ptr->ep_handle); + DT_Tdep_PT_Debug(1, + (phead, "%s: Waiting for another client...\n", + module)); +#endif + } /* end loop accepting connections */ + + /************************************************************************ + * Finished (or had an error) so clean up and go home + */ + server_exit: + + /* Wait until all of our clients are gone */ + DT_Tdep_PT_Debug(1, + (phead, "%s: Waiting for clients to all go away...\n", + module)); + while (ps_ptr && ps_ptr->num_clients > 0) { + DT_Mdep_Sleep(100); + } + + /* Clean up the Per_Test_Data (if any) */ + DT_Tdep_PT_Debug(1, (phead, "%s: Cleaning up ...\n", module)); + if (pt_ptr) { + DT_Mdep_LockDestroy(&pt_ptr->Thread_counter_lock); + DT_Mdep_LockDestroy(&pt_ptr->MemListLock); + DT_Free_Per_Test_Data(pt_ptr); + } + + /* Clean up the Per_Server_Data */ + if (ps_ptr) { + /* + * disconnect the most recent EP + * + * we also get here on error, hence abrupt closure to + * flush any lingering buffers posted. + */ + if (ps_ptr->ep_handle) { + ret = dat_ep_disconnect(ps_ptr->ep_handle, + DAT_CLOSE_ABRUPT_FLAG); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_ep_disconnect fails: %s\n", + module, DT_RetToString(ret)); + /* keep trying */ + } else if (!DT_disco_event_wait(phead, + ps_ptr->conn_evd_hdl, + NULL)) { + DT_Tdep_PT_Printf(phead, + "%s: bad disconnect event\n", + module); + } + } + + /* Destroy the Bpool */ + if (ps_ptr->bpool) { + if (!DT_Bpool_Destroy(NULL, phead, ps_ptr->bpool)) { + DT_Tdep_PT_Printf(phead, + "%s: error destroying buffer pool\n", + module); + /* keep trying */ + } + } + + /* Free the PSP */ + if (ps_ptr->psp_handle) { + ret = dat_psp_free(ps_ptr->psp_handle); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_psp_free error: %s\n", + module, DT_RetToString(ret)); + /* keep trying */ + } + } + + /* Free the EP */ + if (ps_ptr->ep_handle) { + ret = dat_ep_free(ps_ptr->ep_handle); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_ep_free error: %s\n", + module, DT_RetToString(ret)); + /* keep trying */ + } + } + + /* Free the 4 EVDs */ + if (ps_ptr->conn_evd_hdl) { + ret = DT_Tdep_evd_free(ps_ptr->conn_evd_hdl); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_evd_free (conn) error: %s\n", + module, DT_RetToString(ret)); + /* keep trying */ + } + } + if (ps_ptr->creq_evd_hdl) { + ret = DT_Tdep_evd_free(ps_ptr->creq_evd_hdl); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_evd_free (creq) error: %s\n", + module, DT_RetToString(ret)); + /* keep trying */ + } + } + if (ps_ptr->reqt_evd_hdl) { + ret = DT_Tdep_evd_free(ps_ptr->reqt_evd_hdl); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_evd_free (reqt) error: %s\n", + module, DT_RetToString(ret)); + /* keep trying */ + } + } + if (ps_ptr->recv_evd_hdl) { + ret = DT_Tdep_evd_free(ps_ptr->recv_evd_hdl); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_evd_free (recv) error: %s\n", + module, DT_RetToString(ret)); + /* keep trying */ + } + } + + /* Free the PZ */ + if (ps_ptr->pz_handle) { + ret = dat_pz_free(ps_ptr->pz_handle); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_pz_free error: %s\n", + module, DT_RetToString(ret)); + /* keep trying */ + } + } + + /* Close the IA */ + if (ps_ptr->ia_handle) { + /* dat_ia_close cleans up async evd handle, too */ + ret = + dat_ia_close(ps_ptr->ia_handle, + DAT_CLOSE_GRACEFUL_FLAG); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_ia_close (graceful) error: %s\n", + module, DT_RetToString(ret)); + ret = + dat_ia_close(ps_ptr->ia_handle, + DAT_CLOSE_ABRUPT_FLAG); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "%s: dat_ia_close (abrupt) error: %s\n", + module, + DT_RetToString(ret)); + } + /* keep trying */ + } else { + DT_Tdep_PT_Debug(1, + (phead, "%s: IA %s closed\n", + module, + Server_Cmd->dapl_name)); + } + } + + /* Destroy the ps_ptr */ + DT_Mdep_LockDestroy(&ps_ptr->num_clients_lock); + DT_Mdep_Free(ps_ptr); + } + + /* end if ps_ptr */ + /* Clean up the server list */ + pre_list = 0; + temp_list = DT_started_server_list; + while (temp_list) { + if (strcmp(temp_list->devicename, Server_Cmd->dapl_name) == 0) { + if (pre_list == 0) { /* first one */ + DT_started_server_list = temp_list->next; + } else { + pre_list->next = temp_list->next; + } + DT_Mdep_Free(temp_list); + break; + } + pre_list = temp_list; + temp_list = temp_list->next; + } + + DT_Tdep_PT_Printf(phead, + "%s (%s): Exiting.\n", module, + Server_Cmd->dapl_name); +} + +int +send_control_data(DT_Tdep_Print_Head * phead, + unsigned char *buffp, + Per_Server_Data_t * ps_ptr, Per_Test_Data_t * pt_ptr) +{ + char *module = "send_control_data"; + DAT_DTO_COOKIE dto_cookie; + DAT_DTO_COMPLETION_EVENT_DATA dto_stat; + + buffp = DT_Bpool_GetBuffer(ps_ptr->bpool, 2); /* 3rd buffer */ + memcpy((void *)buffp, + (const void *)&pt_ptr->Server_Info, sizeof(Server_Info_t)); + DT_Server_Info_Endian((Server_Info_t *) buffp); + + if (!DT_post_send_buffer(phead, ps_ptr->ep_handle, + ps_ptr->bpool, + 2, DT_Bpool_GetBuffSize(ps_ptr->bpool, 2))) { + DT_Tdep_PT_Printf(phead, "%s: cannot send Server_Info\n", + module); + return 1; + } + /* reap the send and verify it */ + dto_cookie.as_64 = LZERO; + dto_cookie.as_ptr = + (DAT_PVOID) (uintptr_t) DT_Bpool_GetBuffer(ps_ptr->bpool, 2); + if (!DT_dto_event_wait(phead, ps_ptr->reqt_evd_hdl, &dto_stat) || + !DT_dto_check(phead, + &dto_stat, + ps_ptr->ep_handle, + DT_Bpool_GetBuffSize(ps_ptr->bpool, 2), + dto_cookie, "Server_Info_Send")) { + return 1; + } + + return 0; +} + +void +DT_Server_Cmd_PT_Print(DT_Tdep_Print_Head * phead, Server_Cmd_t * Server_Cmd) +{ + DT_Tdep_PT_Printf(phead, "Server_Cmd.debug: %d\n", + Server_Cmd->debug); + DT_Tdep_PT_Printf(phead, "Server_Cmd.dapl_name: %s\n", + Server_Cmd->dapl_name); +} diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_server_info.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_server_info.c new file mode 100644 index 00000000..6041ba8e --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_server_info.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" + +Started_server_t *DT_started_server_list = 0; + +void DT_Server_Info_Endian(Server_Info_t * server_info) +{ + server_info->dapltest_version = + DT_Endian32(server_info->dapltest_version); + server_info->is_little_endian = + DT_Endian32(server_info->is_little_endian); + server_info->first_port_number = + DT_Endian32(server_info->first_port_number); +} + +void +DT_Server_Info_Print(DT_Tdep_Print_Head * phead, Server_Info_t * server_info) +{ + DT_Tdep_PT_Printf(phead, "-------------------------------------\n"); + DT_Tdep_PT_Printf(phead, "Server_Info.dapltest_version : %d\n", + server_info->dapltest_version); + DT_Tdep_PT_Printf(phead, "Server_Info.is_little_endian : %d\n", + server_info->is_little_endian); +} diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_test_data.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_test_data.c new file mode 100644 index 00000000..59d5d1a1 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_test_data.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" + +DT_Mdep_LockType g_PerfTestLock; +/* + * check memory leaking int alloc_count; DT_Mdep_LockType + * Alloc_Count_Lock; + */ + +Per_Test_Data_t *DT_Alloc_Per_Test_Data(DT_Tdep_Print_Head * phead) +{ + Per_Test_Data_t *pt_ptr; + pt_ptr = 0; + + pt_ptr = DT_Mdep_Malloc(sizeof(Per_Test_Data_t)); + if (!pt_ptr) { + DT_Tdep_PT_Printf(phead, + "No Memory to create per_test_data!\n"); + } + + return (pt_ptr); +} + +void DT_Free_Per_Test_Data(Per_Test_Data_t * pt_ptr) +{ + DT_Mdep_Free(pt_ptr); +} diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_test_util.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_test_util.c new file mode 100644 index 00000000..f649b282 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_test_util.c @@ -0,0 +1,680 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" + +/* ----------------------------------------------------------- + * Gather info about default attributes + */ +DAT_BOOLEAN +DT_query(Per_Test_Data_t * pt_ptr, + DAT_IA_HANDLE ia_handle, DAT_EP_HANDLE ep_handle) +{ + char *module = "DT_query"; + DAT_EVD_HANDLE async_evd_hdl; /* not used */ + DAT_EP_PARAM ep_params; + DAT_RETURN ret; + DT_Tdep_Print_Head *phead; + + phead = pt_ptr->Params.phead; + + /* Query the IA */ + ret = dat_ia_query(ia_handle, + &async_evd_hdl, + DAT_IA_ALL, + &pt_ptr->ia_attr, + DAT_PROVIDER_FIELD_ALL, &pt_ptr->provider_attr); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, "%s: dat_ia_query error: %s\n", + module, DT_RetToString(ret)); + return (false); + } + + /* Query the EP */ + ret = dat_ep_query(ep_handle, DAT_EP_FIELD_ALL, &ep_params); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, "%s: dat_ep_query error: %s\n", + module, DT_RetToString(ret)); + return (false); + } + pt_ptr->ep_attr = ep_params.ep_attr; + + /* + * If debugging, print out some interesting attributes + */ + if (DT_dapltest_debug) { + DAT_SOCK_ADDR6 *ip6_addr; + struct sockaddr_in *ip_addr; + + DT_Tdep_PT_Printf(phead, + "***** DAPL Characteristics *****\n"); + DT_Tdep_PT_Printf(phead, + "Provider: %s Version %d.%d DAPL %d.%d\n", + pt_ptr->provider_attr.provider_name, + pt_ptr->provider_attr.provider_version_major, + pt_ptr->provider_attr.provider_version_minor, + pt_ptr->provider_attr.dapl_version_major, + pt_ptr->provider_attr.dapl_version_minor); + DT_Tdep_PT_Printf(phead, "Adapter: %s by %s Version %d.%d\n", + pt_ptr->ia_attr.adapter_name, + pt_ptr->ia_attr.vendor_name, + pt_ptr->ia_attr.hardware_version_major, + pt_ptr->ia_attr.hardware_version_minor); + DT_Tdep_PT_Printf(phead, "Supporting:\n"); + DT_Tdep_PT_Printf(phead, + "\t%d EPs with %d DTOs and %d RDMA/RDs each\n", + pt_ptr->ia_attr.max_eps, + pt_ptr->ia_attr.max_dto_per_ep, + pt_ptr->ia_attr.max_rdma_read_per_ep); + DT_Tdep_PT_Printf(phead, + "\t%d EVDs of up to %d entries " + " (default S/R size is %d/%d)\n", + pt_ptr->ia_attr.max_evds, + pt_ptr->ia_attr.max_evd_qlen, + pt_ptr->ep_attr.max_request_dtos, + pt_ptr->ep_attr.max_recv_dtos); + DT_Tdep_PT_Printf(phead, "\tIOVs of up to %d elements\n", + pt_ptr->ia_attr.max_iov_segments_per_dto); + DT_Tdep_PT_Printf(phead, + "\t%d LMRs (and %d RMRs) of up to 0x" F64x + " bytes\n", pt_ptr->ia_attr.max_lmrs, + pt_ptr->ia_attr.max_rmrs, + pt_ptr->ia_attr.max_lmr_block_size); + DT_Tdep_PT_Printf(phead, + "\tMaximum MTU 0x" F64x " bytes, RDMA 0x" F64x + " bytes\n", pt_ptr->ia_attr.max_mtu_size, + pt_ptr->ia_attr.max_rdma_size); + DT_Tdep_PT_Printf(phead, + "\tMaximum Private data size %d bytes\n", + pt_ptr->provider_attr.max_private_data_size); + + ip6_addr = (DAT_SOCK_ADDR6 *) pt_ptr->ia_attr.ia_address_ptr; + if (ip6_addr->sin6_family == AF_INET6) { + DT_Tdep_PT_Printf(phead, + "\tLocal IP address %x:%x:%x:%x:%x:%x:%x:%x:\n", + ip6_addr->sin6_addr.s6_addr[0], + ip6_addr->sin6_addr.s6_addr[1], + ip6_addr->sin6_addr.s6_addr[2], + ip6_addr->sin6_addr.s6_addr[3], + ip6_addr->sin6_addr.s6_addr[4], + ip6_addr->sin6_addr.s6_addr[5], + ip6_addr->sin6_addr.s6_addr[6], + ip6_addr->sin6_addr.s6_addr[7]); + DT_Tdep_PT_Printf(phead, "%x:%x:%x:%x:%x:%x:%x:%x\n", + ip6_addr->sin6_addr.s6_addr[8], + ip6_addr->sin6_addr.s6_addr[9], + ip6_addr->sin6_addr.s6_addr[10], + ip6_addr->sin6_addr.s6_addr[11], + ip6_addr->sin6_addr.s6_addr[12], + ip6_addr->sin6_addr.s6_addr[13], + ip6_addr->sin6_addr.s6_addr[14], + ip6_addr->sin6_addr.s6_addr[15]); + } else if (ip6_addr->sin6_family == AF_INET) + { + ip_addr = + (struct sockaddr_in *)pt_ptr->ia_attr. + ia_address_ptr; + + DT_Tdep_PT_Printf(phead, "\tLocal IP address %s\n", + inet_ntoa(ip_addr->sin_addr)); + } + + DT_Tdep_PT_Printf(phead, + "***** ***** ***** ***** ***** *****\n"); + } + + return (true); +} + +/* ----------------------------------------------------------- + * Post a recv buffer + */ +DAT_BOOLEAN +DT_post_recv_buffer(DT_Tdep_Print_Head * phead, + DAT_EP_HANDLE ep_handle, Bpool * bp, int index, int size) +{ + unsigned char *buff = DT_Bpool_GetBuffer(bp, index); + DAT_LMR_TRIPLET *iov = DT_Bpool_GetIOV(bp, index); + DAT_LMR_CONTEXT lmr_c = DT_Bpool_GetLMR(bp, index); + DAT_DTO_COOKIE cookie; + DAT_RETURN ret; + + /* + * Prep the inputs + */ + iov->virtual_address = (DAT_VADDR) (uintptr_t) buff; + iov->segment_length = size; + iov->lmr_context = lmr_c; + cookie.as_64 = (DAT_UINT64) 0UL; + cookie.as_ptr = (DAT_PVOID) buff; + + DT_Tdep_PT_Debug(3, + (phead, "Post-Recv #%d [%p, %x]\n", index, buff, + size)); + + /* Post the recv buffer */ + ret = dat_ep_post_recv(ep_handle, + 1, iov, cookie, DAT_COMPLETION_DEFAULT_FLAG); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "Test Error: dat_ep_post_recv failed: %s\n", + DT_RetToString(ret)); + DT_Test_Error(); + return false; + } + return true; +} + +/* ----------------------------------------------------------- + * Post a send buffer + */ +DAT_BOOLEAN +DT_post_send_buffer(DT_Tdep_Print_Head * phead, + DAT_EP_HANDLE ep_handle, Bpool * bp, int index, int size) +{ + unsigned char *buff = DT_Bpool_GetBuffer(bp, index); + DAT_LMR_TRIPLET *iov = DT_Bpool_GetIOV(bp, index); + DAT_LMR_CONTEXT lmr_c = DT_Bpool_GetLMR(bp, index); + DAT_DTO_COOKIE cookie; + DAT_RETURN ret; + + /* + * Prep the inputs + */ + iov->virtual_address = (DAT_VADDR) (uintptr_t) buff; + iov->segment_length = size; + iov->lmr_context = lmr_c; + cookie.as_64 = (DAT_UINT64) 0UL; + cookie.as_ptr = (DAT_PVOID) buff; + + DT_Tdep_PT_Debug(3, + (phead, "Post-Send #%d [%p, %x]\n", index, buff, + size)); + + /* Post the recv buffer */ + ret = dat_ep_post_send(ep_handle, + 1, iov, cookie, DAT_COMPLETION_DEFAULT_FLAG); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "Test Error: dat_ep_post_send failed: %s\n", + DT_RetToString(ret)); + DT_Test_Error(); + return false; + } + return true; +} + +/* ----------------------------------------------------------- + * Wait for a CR event, returning false on error. + */ +bool +DT_cr_event_wait(DT_Tdep_Print_Head * phead, + DAT_EVD_HANDLE evd_handle, + DAT_CR_ARRIVAL_EVENT_DATA * cr_stat_p) +{ + int err_cnt; + + err_cnt = 0; + + for (;;) { + DAT_RETURN ret; + DAT_EVENT event; + + ret = + DT_Tdep_evd_wait(evd_handle, DAT_TIMEOUT_INFINITE, &event); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "Test Error: dapl_event_wait (CR) failed: %s\n", + DT_RetToString(ret)); + DT_Test_Error(); + /* + * If we get an error due to the client breaking the + * connection early or some transients, just ignore it + * and keep going. If we get a bunch of errors, bail + * out. + */ + /* if ( err_cnt++ < 10 ) */ + /* { */ + /* continue; */ + /* } */ + + break; + } + + if (event.event_number == DAT_CONNECTION_REQUEST_EVENT) { + /* + * Pass back what we know, if requested. + */ + if (cr_stat_p) { + *cr_stat_p = + event.event_data.cr_arrival_event_data; + } + return (true); + } + + DT_Tdep_PT_Printf(phead, + "Warning: cr_event_wait swallowing %s event\n", + DT_EventToSTr(event.event_number)); + } + + return (false); +} + +/* ----------------------------------------------------------- + * Wait for a connection event, returning false on error. + */ +bool +DT_conn_event_wait(DT_Tdep_Print_Head * phead, + DAT_EP_HANDLE ep_handle, + DAT_EVD_HANDLE evd_handle, DAT_EVENT_NUMBER * event_number) +{ + for (;;) { + DAT_RETURN ret; + DAT_EVENT event; + + ret = + DT_Tdep_evd_wait(evd_handle, DAT_TIMEOUT_INFINITE, &event); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "Test Error: dapl_event_wait (CONN) failed: %s\n", + DT_RetToString(ret)); + DT_Test_Error(); + break; + } + *event_number = event.event_number; + if (event.event_number == DAT_CONNECTION_EVENT_PEER_REJECTED + || event.event_number == + DAT_CONNECTION_EVENT_NON_PEER_REJECTED + || event.event_number == + DAT_CONNECTION_EVENT_ACCEPT_COMPLETION_ERROR + || event.event_number == DAT_CONNECTION_EVENT_DISCONNECTED + || event.event_number == DAT_CONNECTION_EVENT_BROKEN + || event.event_number == DAT_CONNECTION_EVENT_UNREACHABLE + || event.event_number == DAT_CONNECTION_EVENT_TIMED_OUT) { + DT_Tdep_PT_Printf(phead, + "Warning: conn_event_wait %s\n", + DT_EventToSTr(event.event_number)); + break; + } + if (event.event_number == DAT_CONNECTION_EVENT_ESTABLISHED) { + /* + * Could return DAT_CONNECTION_EVENT_DATA and verify: + * event.event_data.connect_event_data.ep_handle + * event.event_data.connect_event_data.private_data_size + * event.event_data.connect_event_data.private_data + */ + return (true); + } + + DT_Tdep_PT_Printf(phead, + "Warning: conn_event_wait swallowing %s event\n", + DT_EventToSTr(event.event_number)); + } + + return (false); +} + +/* ----------------------------------------------------------- + * Wait for a disconnection event, returning false on error. + */ +bool +DT_disco_event_wait(DT_Tdep_Print_Head * phead, + DAT_EVD_HANDLE evd_handle, DAT_EP_HANDLE * ep_handle) +{ + for (;;) { + DAT_RETURN ret; + DAT_EVENT event; + + ret = + DT_Tdep_evd_wait(evd_handle, DAT_TIMEOUT_INFINITE, &event); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "Test Error: dapl_event_wait (DISCONN) failed: %s\n", + DT_RetToString(ret)); + DT_Test_Error(); + break; + } + if (event.event_number == DAT_CONNECTION_EVENT_PEER_REJECTED + || event.event_number == + DAT_CONNECTION_EVENT_NON_PEER_REJECTED + || event.event_number == + DAT_CONNECTION_EVENT_ACCEPT_COMPLETION_ERROR + || event.event_number == DAT_CONNECTION_EVENT_BROKEN + || event.event_number == DAT_CONNECTION_EVENT_UNREACHABLE + || event.event_number == DAT_CONNECTION_EVENT_TIMED_OUT) { + DT_Tdep_PT_Printf(phead, + "Warning: disconn_event_wait %s\n", + DT_EventToSTr(event.event_number)); + break; + } + + if (event.event_number == DAT_CONNECTION_EVENT_DISCONNECTED) { + if (ep_handle != NULL) { + *ep_handle = + event.event_data.connect_event_data. + ep_handle; + } + return (true); + } + + DT_Tdep_PT_Printf(phead, + "Warning: conn_event_wait swallowing %s event\n", + DT_EventToSTr(event.event_number)); + } + + return (false); +} + +/* ----------------------------------------------------------- + * Reap a DTO event using a wait or polling, returning false on error. + */ +bool +DT_dto_event_reap(DT_Tdep_Print_Head * phead, + DAT_EVD_HANDLE evd_handle, + bool poll, DAT_DTO_COMPLETION_EVENT_DATA * dto_statusp) +{ + if (poll) { + return DT_dto_event_poll(phead, evd_handle, dto_statusp); + } else { + return DT_dto_event_wait(phead, evd_handle, dto_statusp); + } +} + +/* ----------------------------------------------------------- + * Poll for a DTO event, returning false on error. + */ +bool +DT_dto_event_poll(DT_Tdep_Print_Head * phead, + DAT_EVD_HANDLE evd_handle, + DAT_DTO_COMPLETION_EVENT_DATA * dto_statusp) +{ + for (;;DT_Mdep_yield()) { + DAT_RETURN ret; + DAT_EVENT event; + + ret = DT_Tdep_evd_dequeue(evd_handle, &event); + + if (DAT_GET_TYPE(ret) == DAT_QUEUE_EMPTY) { + continue; + } + + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "Test Error: dapl_event_wait (DTO) failed: %s\n", + DT_RetToString(ret)); + DT_Test_Error(); + break; + } + + if (event.event_number == DAT_DTO_COMPLETION_EVENT) { + /* + * Pass back all the useful bits if requested: + * ep_handle, user_cookie.as_ptr + * status, transfered_length + */ + if (dto_statusp) { + *dto_statusp = + event.event_data.dto_completion_event_data; + } + + return (true); + } + + DT_Tdep_PT_Printf(phead, + "Warning: dto_event_poll swallowing %s event\n", + DT_EventToSTr(event.event_number)); + } + + return (false); +} + +/* ----------------------------------------------------------- + * Wait for a DTO event, returning false on error. + */ +bool +DT_dto_event_wait(DT_Tdep_Print_Head * phead, + DAT_EVD_HANDLE evd_handle, + DAT_DTO_COMPLETION_EVENT_DATA * dto_statusp) +{ + for (;;) { + DAT_RETURN ret; + DAT_EVENT event; + + ret = + DT_Tdep_evd_wait(evd_handle, DAT_TIMEOUT_INFINITE, &event); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "Test Error: dapl_event_wait (DTO) failed: %s\n", + DT_RetToString(ret)); + DT_Test_Error(); + break; + } + + if (event.event_number == DAT_DTO_COMPLETION_EVENT) { + /* + * Pass back all the useful bits if requested: + * ep_handle, user_cookie.as_ptr + * status, transfered_length + */ + if (dto_statusp) { + *dto_statusp = + event.event_data.dto_completion_event_data; + } + return (true); + } + + DT_Tdep_PT_Printf(phead, + "Warning: dto_event_wait swallowing %s event\n", + DT_EventToSTr(event.event_number)); + } + + return (false); +} + +/* ----------------------------------------------------------- + * Wait for a RMR event, returning false on error. + */ +bool +DT_rmr_event_wait(DT_Tdep_Print_Head * phead, + DAT_EVD_HANDLE evd_handle, + DAT_RMR_BIND_COMPLETION_EVENT_DATA * rmr_statusp) +{ + for (;;) { + DAT_RETURN ret; + DAT_EVENT event; + + ret = + DT_Tdep_evd_wait(evd_handle, DAT_TIMEOUT_INFINITE, &event); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "Test Error: dapl_event_wait (RMR) failed: %s\n", + DT_RetToString(ret)); + DT_Test_Error(); + break; + } + + if (event.event_number == DAT_RMR_BIND_COMPLETION_EVENT) { + /* + * Pass back all the useful bits if requested: + * rmr_handle, user_cookie, status + */ + if (rmr_statusp) { + *rmr_statusp = + event.event_data.rmr_completion_event_data; + } + return (true); + } + + DT_Tdep_PT_Printf(phead, + "Warning: rmr_event_wait swallowing %s event\n", + DT_EventToSTr(event.event_number)); + } + + return (false); +} + +/* ----------------------------------------------------------- + * Check a DTO and print some debug info if anything is amiss. + */ +bool +DT_dto_check(DT_Tdep_Print_Head * phead, + DAT_DTO_COMPLETION_EVENT_DATA * dto_p, + DAT_EP_HANDLE ep_expected, + DAT_COUNT len_expected, + DAT_DTO_COOKIE cookie_expected, char *message) +{ + if (((ep_expected != NULL) && (dto_p->ep_handle != ep_expected)) + || dto_p->transfered_length != len_expected + || dto_p->user_cookie.as_64 != cookie_expected.as_64 + || dto_p->status != DAT_DTO_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "Test Error: %s-reaping DTO problem, status = %s\n", + message, + (dto_p->status == + DAT_DTO_SUCCESS ? "OK" : (dto_p->status == + DAT_DTO_FAILURE ? + "FAILURE" : + "LengthError"))); + DT_Test_Error(); + if ((ep_expected != NULL) && (dto_p->ep_handle != ep_expected)) { + DT_Tdep_PT_Printf(phead, + "\tEndPoint mismatch (got %p wanted %p)\n", + dto_p->ep_handle, ep_expected); + } + if (dto_p->transfered_length != len_expected) { + DT_Tdep_PT_Printf(phead, + "\tLength mismatch (xfer 0x" F64x + " wanted 0x%x)\n", + dto_p->transfered_length, + len_expected); + } + if (dto_p->user_cookie.as_64 != cookie_expected.as_64) { + DT_Tdep_PT_Printf(phead, + "\tCookie mismatch (got " F64x + " wanted " F64x ")\n", + dto_p->user_cookie.as_64, + cookie_expected.as_64); + } + return (false); + } + + return (true); +} + +/* ----------------------------------------------------------- + * Check an RMR Bind and print some debug info if anything is amiss. + */ +bool +DT_rmr_check(DT_Tdep_Print_Head * phead, + DAT_RMR_BIND_COMPLETION_EVENT_DATA * rmr_p, + DAT_RMR_HANDLE rmr_expected, + DAT_PVOID cookie_expected, char *message) +{ + if (rmr_p->rmr_handle != rmr_expected + || rmr_p->user_cookie.as_ptr != cookie_expected + || rmr_p->status != DAT_RMR_BIND_SUCCESS) { + + DT_Tdep_PT_Printf(phead, + "Test Error: %s RMR bind problem, status = %s\n", + message, + (rmr_p->status == + DAT_RMR_BIND_SUCCESS ? "OK" : "FAILURE")); + DT_Test_Error(); + if (rmr_p->rmr_handle != rmr_expected) { + DT_Tdep_PT_Printf(phead, + "\tRMR handle mismatch (got 0x%p wanted 0x%p)\n", + rmr_p->rmr_handle, rmr_expected); + } + if (rmr_p->user_cookie.as_ptr != cookie_expected) { + DT_Tdep_PT_Printf(phead, + "\tCookie mismatch (got %p wanted %p)\n", + rmr_p->user_cookie.as_ptr, + cookie_expected); + } + return (false); + } + + return (true); +} + +/* ----------------------------------------------------------- + * Check a CR and print some debug info if anything is amiss. + */ +bool +DT_cr_check(DT_Tdep_Print_Head * phead, + DAT_CR_ARRIVAL_EVENT_DATA * cr_stat_p, + DAT_PSP_HANDLE psp_handle_expected, + DAT_CONN_QUAL port_expected, + DAT_CR_HANDLE * cr_handlep, char *message) +{ + DAT_RETURN ret; + + if (cr_handlep) { + *cr_handlep = (DAT_CR_HANDLE) 0; + } + + if (cr_stat_p->conn_qual != port_expected || + (psp_handle_expected && + cr_stat_p->sp_handle.psp_handle != psp_handle_expected)) { + + DT_Tdep_PT_Printf(phead, "Test Error: %s CR data problem\n", + message); + DT_Test_Error(); + if (cr_stat_p->conn_qual != port_expected) { + DT_Tdep_PT_Printf(phead, "\tCR conn_qual mismatch " + " (got 0x" F64x " wanted 0x" F64x + ")\n", cr_stat_p->conn_qual, + port_expected); + } + if (psp_handle_expected && + cr_stat_p->sp_handle.psp_handle != psp_handle_expected) { + DT_Tdep_PT_Printf(phead, + "\tPSP mismatch (got 0x%p wanted 0x%p)\n", + cr_stat_p->sp_handle.psp_handle, + psp_handle_expected); + } + if (!cr_stat_p->cr_handle) { + DT_Tdep_PT_Printf(phead, "\tGot NULL cr_handle\n"); + } else { + ret = dat_cr_reject(cr_stat_p->cr_handle, 0, NULL); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "\tdat_cr_reject error: %s\n", + DT_RetToString(ret)); + } + } + return (false); + } + + if (cr_handlep) { + *cr_handlep = cr_stat_p->cr_handle; + } + return (true); +} diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_thread.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_thread.c new file mode 100644 index 00000000..9a56558d --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_thread.c @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" +/* + * Class Thread + * + * Threads subsystem initialization + */ +void DT_Thread_Init(Per_Test_Data_t * pt_ptr) +{ + DT_Mdep_LockInit(&pt_ptr->Thread_counter_lock); + pt_ptr->Thread_counter = 0; + + /* + * Initialize the synchronization event in the pt_ptr so it's ready + * to be signalled when the time comes. The countdown counter + * lets me coordinate with all the test threads so that the server + * thread doesn't get notified that the test endpoints are ready + * until they actually are. Only transaction tests use this * + * functionality; if the performance test gets changed to use + * multiple threads on the server side then that code semantic + * will need to be added for final test endpoint setup + * notification or there will continue to be a race condition + * between the main server thread and the server test threads. + */ + DT_Mdep_wait_object_init(&pt_ptr->synch_wait_object); + pt_ptr->Countdown_Counter = 0; + +} + +/* + * Threads subsystem destroying + */ +void DT_Thread_End(Per_Test_Data_t * pt_ptr) +{ + DT_Mdep_LockDestroy(&pt_ptr->Thread_counter_lock); + + /* + * destroy the wait object created by init. + */ + DT_Mdep_wait_object_destroy(&pt_ptr->synch_wait_object); + +} + +/* + * Thread constructor + * + * NOTE: This routine does NOT create a thread as the name implies. The thread + * is created in DT_Thread_Start (which is counter intuitive) + */ +Thread *DT_Thread_Create(Per_Test_Data_t * pt_ptr, + void (*fn) (void *), + void *param, unsigned int stacksize) +{ + Thread *thread_ptr; + thread_ptr = + (Thread *) DT_MemListAlloc(pt_ptr, "thread.c", THREAD, + sizeof(Thread)); + if (thread_ptr == NULL) { + return NULL; + } + thread_ptr->param = param; + thread_ptr->function = fn; + thread_ptr->thread_handle = 0; + thread_ptr->stacksize = stacksize; + + DT_Mdep_Lock(&pt_ptr->Thread_counter_lock); + pt_ptr->Thread_counter++; + DT_Mdep_Unlock(&pt_ptr->Thread_counter_lock); + + DT_Mdep_Thread_Init_Attributes(thread_ptr); + + return thread_ptr; +} + +/* + * Thread destructor + */ +void DT_Thread_Destroy(Thread * thread_ptr, Per_Test_Data_t * pt_ptr) +{ + if (thread_ptr) { + DT_Mdep_Lock(&pt_ptr->Thread_counter_lock); + pt_ptr->Thread_counter--; + DT_Mdep_Unlock(&pt_ptr->Thread_counter_lock); + + DT_Mdep_Thread_Destroy_Attributes(thread_ptr); + DT_MemListFree(pt_ptr, thread_ptr); + } +} + +/* + * Start thread execution NOTE: This routine DOES create a thread in addition + * to starting it whereas DT_Thread_Create just sets up some data structures. + * (this is counter-intuitive) + */ +bool DT_Thread_Start(Thread * thread_ptr) +{ + return DT_Mdep_Thread_Start(thread_ptr); +} diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_transaction_stats.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_transaction_stats.c new file mode 100644 index 00000000..f9d63778 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_transaction_stats.c @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" + +void +DT_init_transaction_stats(Transaction_Stats_t * transaction_stats, + unsigned int num) +{ + DT_Mdep_LockInit(&transaction_stats->lock); + + transaction_stats->wait_count = num; + transaction_stats->num_ops = 0; + transaction_stats->time_ms = 0; + transaction_stats->bytes_send = 0; + transaction_stats->bytes_recv = 0; + transaction_stats->bytes_rdma_read = 0; + transaction_stats->bytes_rdma_write = 0; +} + +void +DT_transaction_stats_set_ready(DT_Tdep_Print_Head * phead, + Transaction_Stats_t * transaction_stats) +{ + DT_Mdep_Lock(&transaction_stats->lock); + transaction_stats->wait_count--; + + DT_Tdep_PT_Debug(1, + (phead, + "Received Sync Message from server (%d left)\n", + transaction_stats->wait_count)); + DT_Mdep_Unlock(&transaction_stats->lock); +} + +bool +DT_transaction_stats_wait_for_all(DT_Tdep_Print_Head * phead, + Transaction_Stats_t * transaction_stats) +{ + unsigned int loop_count; + loop_count = 100 * 10; /* 100 * 10ms * 10 = 10 seconds */ + while (transaction_stats->wait_count != 0 && loop_count != 0) { + DT_Mdep_Sleep(10); + loop_count--; + } + if (loop_count == 0) { + DT_Tdep_PT_Printf(phead, + "FAIL: %d Server test connections did not report ready.\n", + transaction_stats->wait_count); + return false; + } + return true; +} + +/* + * + */ +void +DT_update_transaction_stats(Transaction_Stats_t * transaction_stats, + unsigned int num_ops, + unsigned int time_ms, + unsigned int bytes_send, + unsigned int bytes_recv, + unsigned int bytes_rdma_read, + unsigned int bytes_rdma_write) +{ + DT_Mdep_Lock(&transaction_stats->lock); + + /* look for the longest time... */ + if (time_ms > transaction_stats->time_ms) { + transaction_stats->time_ms = time_ms; + } + + transaction_stats->num_ops += num_ops; + transaction_stats->bytes_send += bytes_send; + transaction_stats->bytes_recv += bytes_recv; + transaction_stats->bytes_rdma_read += bytes_rdma_read; + transaction_stats->bytes_rdma_write += bytes_rdma_write; + DT_Mdep_Unlock(&transaction_stats->lock); +} + +/* + * + */ +void +DT_print_transaction_stats(DT_Tdep_Print_Head * phead, + Transaction_Stats_t * transaction_stats, + unsigned int num_threads, unsigned int num_EPs) +{ + double time_s; + double mbytes_send; + double mbytes_recv; + double mbytes_rdma_read; + double mbytes_rdma_write; + int total_ops; + DT_Mdep_Lock(&transaction_stats->lock); + time_s = (double)(transaction_stats->time_ms) / 1000; + if (time_s == 0.0) { + DT_Tdep_PT_Printf(phead, + "----- Test completed successfully, but cannot calculate stats as not\n" + "----- enough time has lapsed.\n" + "----- Try running the test with more iterations.\n"); + goto unlock_and_return; + } + mbytes_send = (double)transaction_stats->bytes_send / 1000 / 1000; + mbytes_recv = (double)transaction_stats->bytes_recv / 1000 / 1000; + mbytes_rdma_read = + (double)transaction_stats->bytes_rdma_read / 1000 / 1000; + mbytes_rdma_write = + (double)transaction_stats->bytes_rdma_write / 1000 / 1000; + total_ops = transaction_stats->num_ops; + + if (0 == total_ops) { + DT_Tdep_PT_Printf(phead, + "----- Test completed successfully, but no operations!\n"); + goto unlock_and_return; + } + + DT_Tdep_PT_Printf(phead, "----- Stats ---- : %u threads, %u EPs\n", + num_threads, num_EPs); + DT_Tdep_PT_Printf(phead, "Total WQE : %7d.%02d WQE/Sec\n", + whole(total_ops / time_s), + hundredths(total_ops / time_s)); + DT_Tdep_PT_Printf(phead, "Total Time : %7d.%02d sec\n", + whole(time_s), hundredths(time_s)); + DT_Tdep_PT_Printf(phead, + "Total Send : %7d.%02d MB - %7d.%02d MB/Sec\n", + whole(mbytes_send), hundredths(mbytes_send), + whole(mbytes_send / time_s), + hundredths(mbytes_send / time_s)); + DT_Tdep_PT_Printf(phead, + "Total Recv : %7d.%02d MB - %7d.%02d MB/Sec\n", + whole(mbytes_recv), hundredths(mbytes_recv), + whole(mbytes_recv / time_s), + hundredths(mbytes_recv / time_s)); + DT_Tdep_PT_Printf(phead, + "Total RDMA Read : %7d.%02d MB - %7d.%02d MB/Sec\n", + whole(mbytes_rdma_read), hundredths(mbytes_rdma_read), + whole(mbytes_rdma_read / time_s), + hundredths(mbytes_rdma_read / time_s)); + DT_Tdep_PT_Printf(phead, + "Total RDMA Write : %7d.%02d MB - %7d.%02d MB/Sec\n", + whole(mbytes_rdma_write), + hundredths(mbytes_rdma_write), + whole(mbytes_rdma_write / time_s), + hundredths(mbytes_rdma_write / time_s)); + + unlock_and_return: + DT_Mdep_Unlock(&transaction_stats->lock); +} diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_transaction_test.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_transaction_test.c new file mode 100644 index 00000000..14c14b4c --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_transaction_test.c @@ -0,0 +1,2265 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" + +#define RMI_SEND_BUFFER_ID 0 +#define RMI_RECV_BUFFER_ID 1 +#define SYNC_SEND_BUFFER_ID 2 +#define SYNC_RECV_BUFFER_ID 3 + +/* + * The sync buffers are sent to say "Go!" to the other side. + * This is a handy place to test whether a zero-sized send into + * a zero-sized buffer actually works. If the client side hangs + * in 'Wait for Sync Message' when this is zero, it's a DAPL bug. + */ +#define SYNC_BUFF_SIZE 64 + +#define DFLT_QLEN 8 /* default event queue length */ +#define DFLT_TMO 10 /* default timeout (seconds) */ +#define MAX_CONN_RETRY 8 + +/****************************************************************************/ +DAT_RETURN +DT_Transaction_Test_Client(Per_Test_Data_t * pt_ptr, + DAT_IA_HANDLE ia_handle, + DAT_IA_ADDRESS_PTR remote_ia_addr) +{ + Transaction_Cmd_t *cmd = &pt_ptr->Params.u.Transaction_Cmd; + unsigned int i; + DT_Tdep_Print_Head *phead; + DAT_RETURN rc = DAT_SUCCESS; + + phead = pt_ptr->Params.phead; + + DT_init_transaction_stats(&pt_ptr->Client_Stats, + cmd->num_threads * cmd->eps_per_thread); + + /* Now go set up the client test threads */ + for (i = 0; i < cmd->num_threads; i++) { + unsigned int port_num = pt_ptr->Server_Info.first_port_number + + i * cmd->eps_per_thread; + + DT_Tdep_PT_Debug(1, + (phead, + "Client: Starting Client side of test\n")); + if (!DT_Transaction_Create_Test + (pt_ptr, ia_handle, false, port_num, + pt_ptr->Server_Info.is_little_endian, remote_ia_addr)) { + DT_Tdep_PT_Printf(phead, + "Client: Cannot Create Test!\n"); + rc = DAT_INSUFFICIENT_RESOURCES; + break; + } +#ifdef CM_BUSTED + /***** XXX Chill out a bit to give the kludged CM a chance ... + *****/ DT_Mdep_Sleep(5000); +#endif + + } + + /* Wait until end of all threads */ + while (pt_ptr->Thread_counter > 0) { + DT_Mdep_Sleep(100); + } + + DT_print_transaction_stats(phead, + &pt_ptr->Client_Stats, + cmd->num_threads, cmd->eps_per_thread); + return rc; +} + +/****************************************************************************/ +void DT_Transaction_Test_Server(void *params) +{ + Per_Test_Data_t *pt_ptr = (Per_Test_Data_t *) params; + Transaction_Cmd_t *cmd = &pt_ptr->Params.u.Transaction_Cmd; + unsigned int i; + DT_Tdep_Print_Head *phead; + + phead = pt_ptr->Params.phead; + + pt_ptr->Countdown_Counter = cmd->num_threads; + + for (i = 0; i < cmd->num_threads; i++) { + unsigned int port_num = pt_ptr->Server_Info.first_port_number + + i * cmd->eps_per_thread; + + if (!DT_Transaction_Create_Test(pt_ptr, + pt_ptr->ps_ptr->ia_handle, + true, + port_num, + pt_ptr->Client_Info. + is_little_endian, + (DAT_IA_ADDRESS_PTR) 0)) { + DT_Tdep_PT_Printf(phead, + "Server: Cannot Create Test!\n"); + break; + } +#ifdef CM_BUSTED + /***** XXX Chill out a bit to give the kludged CM a chance ... + *****/ DT_Mdep_Sleep(5000); +#endif + + } + + /* Wait until end of all sub-threads */ + while (pt_ptr->Thread_counter > 1) { + DT_Mdep_Sleep(100); + } + DT_Thread_Destroy(pt_ptr->thread, pt_ptr); /* destroy Master thread */ + + DT_Mdep_Lock(&pt_ptr->ps_ptr->num_clients_lock); + pt_ptr->ps_ptr->num_clients--; + DT_Mdep_Unlock(&pt_ptr->ps_ptr->num_clients_lock); + + /* NB: Server has no pt_ptr->remote_netaddr */ + DT_PrintMemList(pt_ptr); /* check if we return all space allocated */ + DT_Mdep_LockDestroy(&pt_ptr->Thread_counter_lock); + DT_Mdep_LockDestroy(&pt_ptr->MemListLock); + DT_Free_Per_Test_Data(pt_ptr); + DT_Tdep_PT_Printf(phead, + "Server: Transaction Test Finished for this client\n"); + /* + * check memory leaking DT_Tdep_PT_Printf(phead, "Server: App allocated Memory Left: + * %d\n", alloc_count); + */ +} + +/****************************************************************************/ +/* + * DT_Transaction_Create_Test() + * + * Initialize what we can in the test structure. Then fork a thread to do the + * work. + */ + +bool +DT_Transaction_Create_Test(Per_Test_Data_t * pt_ptr, + DAT_IA_HANDLE * ia_handle, + DAT_BOOLEAN is_server, + unsigned int port_num, + DAT_BOOLEAN remote_is_little_endian, + DAT_IA_ADDRESS_PTR remote_ia_addr) +{ + Transaction_Test_t *test_ptr; + DT_Tdep_Print_Head *phead; + + phead = pt_ptr->Params.phead; + + test_ptr = (Transaction_Test_t *) DT_MemListAlloc(pt_ptr, + "transaction_test_t", + TRANSACTIONTEST, + sizeof + (Transaction_Test_t)); + if (!test_ptr) { + DT_Tdep_PT_Printf(phead, + "No Memory to create transaction test structure!\n"); + return false; + } + + /* Unused fields zeroed by allocator */ + test_ptr->remote_is_little_endian = remote_is_little_endian; + test_ptr->is_server = is_server; + test_ptr->pt_ptr = pt_ptr; + test_ptr->ia_handle = ia_handle; + test_ptr->base_port = (DAT_CONN_QUAL) port_num; + test_ptr->cmd = &pt_ptr->Params.u.Transaction_Cmd; + test_ptr->time_out = DFLT_TMO * 1000; /* DFLT_TMO seconds */ + + /* FIXME more analysis needs to go into determining the minimum */ + /* possible value for DFLT_QLEN. This evd_length value will be */ + /* used for all EVDs. There are a number of dependencies imposed */ + /* by this design (ex. min(cr_evd_len) != min(recv_evd_len) ). */ + /* In the future it may be best to use individual values. */ + test_ptr->evd_length = DT_max(DFLT_QLEN, + test_ptr->cmd->eps_per_thread * + test_ptr->cmd->num_ops); + + test_ptr->remote_ia_addr = remote_ia_addr; + + test_ptr->thread = DT_Thread_Create(pt_ptr, + DT_Transaction_Main, + test_ptr, + DT_MDEP_DEFAULT_STACK_SIZE); + if (test_ptr->thread == 0) { + DT_Tdep_PT_Printf(phead, "No memory!\n"); + DT_MemListFree(test_ptr->pt_ptr, test_ptr); + return false; + } + DT_Thread_Start(test_ptr->thread); + + return true; +} + +/****************************************************************************/ +/* + * Main Transaction Test Execution Routine + * + * Both client and server threads start here, with IA already open. + * Each test thread establishes a connection with its counterpart. + * They swap remote memory information (if necessary), then set up + * buffers and local data structures. When ready, the two sides + * synchronize, then testing begins. + */ +void DT_Transaction_Main(void *param) +{ + Transaction_Test_t *test_ptr = (Transaction_Test_t *) param; + DAT_RETURN ret; + DAT_UINT32 i, j; + bool success = false; + Per_Test_Data_t *pt_ptr; + Thread *thread; + DAT_DTO_COOKIE dto_cookie; + char *private_data_str; + DAT_EVENT_NUMBER event_num; + DT_Tdep_Print_Head *phead; + + pt_ptr = test_ptr->pt_ptr; + thread = test_ptr->thread; + phead = pt_ptr->Params.phead; +#ifdef CM_BUSTED + private_data_str = ""; +#else + private_data_str = "DAPL and RDMA rule! Test 4321."; +#endif + + /* create a protection zone */ + ret = dat_pz_create(test_ptr->ia_handle, &test_ptr->pz_handle); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x "]: dat_pz_create error: %s\n", + test_ptr->base_port, DT_RetToString(ret)); + test_ptr->pz_handle = DAT_HANDLE_NULL; + goto test_failure; + } + + /* Allocate per-EP data */ + test_ptr->ep_context = (Ep_Context_t *) + DT_MemListAlloc(pt_ptr, + "transaction_test", + EPCONTEXT, + test_ptr->cmd->eps_per_thread + * sizeof(Ep_Context_t)); + if (!test_ptr->ep_context) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x "]: no memory for EP context\n", + test_ptr->base_port); + goto test_failure; + } + + /* + * Set up the per-EP contexts: + * create the EP + * allocate buffers for remote memory info exchange + * post the receive buffers + * connect + * set up buffers and remote memory info + * send across our info + * recv the other side's info and extract what we need + */ + for (i = 0; i < test_ptr->cmd->eps_per_thread; i++) { + DAT_EP_ATTR ep_attr; + DAT_UINT32 buff_size = MAX_OPS * sizeof(RemoteMemoryInfo); + + /* create 4 EVDs - recv, request+RMR, conn-request, connect */ + ret = + DT_Tdep_evd_create(test_ptr->ia_handle, + test_ptr->evd_length, NULL, + DAT_EVD_DTO_FLAG, + &test_ptr->ep_context[i].recv_evd_hdl); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x + "]: dat_evd_create (recv) error: %s\n", + test_ptr->base_port, + DT_RetToString(ret)); + test_ptr->ep_context[i].recv_evd_hdl = DAT_HANDLE_NULL; + goto test_failure; + } + + ret = + DT_Tdep_evd_create(test_ptr->ia_handle, + test_ptr->evd_length, NULL, + DAT_EVD_DTO_FLAG | DAT_EVD_RMR_BIND_FLAG, + &test_ptr->ep_context[i].reqt_evd_hdl); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x + "]: dat_evd_create (request) error: %s\n", + test_ptr->base_port, + DT_RetToString(ret)); + test_ptr->ep_context[i].reqt_evd_hdl = DAT_HANDLE_NULL; + goto test_failure; + } + + if (pt_ptr->local_is_server) { + /* Client-side doesn't need CR events */ + ret = + DT_Tdep_evd_create(test_ptr->ia_handle, + test_ptr->evd_length, NULL, + DAT_EVD_CR_FLAG, + &test_ptr->ep_context[i]. + creq_evd_hdl); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x + "]: dat_evd_create (cr) error: %s\n", + test_ptr->base_port, + DT_RetToString(ret)); + test_ptr->ep_context[i].creq_evd_hdl = + DAT_HANDLE_NULL; + goto test_failure; + } + } + + ret = + DT_Tdep_evd_create(test_ptr->ia_handle, + test_ptr->evd_length, NULL, + DAT_EVD_CONNECTION_FLAG, + &test_ptr->ep_context[i].conn_evd_hdl); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x + "]: dat_evd_create (conn) error: %s\n", + test_ptr->base_port, + DT_RetToString(ret)); + test_ptr->ep_context[i].conn_evd_hdl = DAT_HANDLE_NULL; + goto test_failure; + } + + /* + * Adjust default EP attributes to fit the requested test. + * This is simplistic; in that we don't count ops of each + * type and direction, checking EP limits. We just try to + * be sure the EP's WQs are large enough. The "+2" is for + * the RemoteMemInfo and Sync receive buffers. + */ + ep_attr = pt_ptr->ep_attr; + if (ep_attr.max_recv_dtos < test_ptr->cmd->num_ops + 2) { + ep_attr.max_recv_dtos = test_ptr->cmd->num_ops + 2; + } + if (ep_attr.max_request_dtos < test_ptr->cmd->num_ops + 2) { + ep_attr.max_request_dtos = test_ptr->cmd->num_ops + 2; + } + + /* Create EP */ + ret = dat_ep_create(test_ptr->ia_handle, /* IA */ + test_ptr->pz_handle, /* PZ */ + test_ptr->ep_context[i].recv_evd_hdl, /* recv */ + test_ptr->ep_context[i].reqt_evd_hdl, /* request */ + test_ptr->ep_context[i].conn_evd_hdl, /* connect */ + &ep_attr, /* EP attrs */ + &test_ptr->ep_context[i].ep_handle); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x + "]: dat_ep_create #%d error: %s\n", + test_ptr->base_port, i, + DT_RetToString(ret)); + test_ptr->ep_context[i].ep_handle = DAT_HANDLE_NULL; + goto test_failure; + } + + /* + * Allocate a buffer pool so we can exchange the + * remote memory info and initialize. + */ + test_ptr->ep_context[i].bp = DT_BpoolAlloc(pt_ptr, phead, test_ptr->ia_handle, test_ptr->pz_handle, test_ptr->ep_context[i].ep_handle, DAT_HANDLE_NULL, /* rmr */ + buff_size, + 4, + DAT_OPTIMAL_ALIGNMENT, + false, false); + if (!test_ptr->ep_context[i].bp) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x + "]: no memory for remote memory buffers\n", + test_ptr->base_port); + goto test_failure; + } + + DT_Tdep_PT_Debug(3, (phead, + "0: RMI_SEND %p\n", + (DAT_PVOID) DT_Bpool_GetBuffer(test_ptr-> + ep_context + [i].bp, + 0))); + DT_Tdep_PT_Debug(3, + (phead, "1: RMI_RECV %p\n", + (DAT_PVOID) DT_Bpool_GetBuffer(test_ptr-> + ep_context[i]. + bp, 1))); + DT_Tdep_PT_Debug(3, + (phead, "2: SYNC_SEND %p\n", + (DAT_PVOID) DT_Bpool_GetBuffer(test_ptr-> + ep_context[i]. + bp, 2))); + DT_Tdep_PT_Debug(3, + (phead, "3: SYNC_RECV %p\n", + (DAT_PVOID) DT_Bpool_GetBuffer(test_ptr-> + ep_context[i]. + bp, 3))); + + /* + * Post recv and sync buffers + */ + if (!DT_post_recv_buffer(phead, + test_ptr->ep_context[i].ep_handle, + test_ptr->ep_context[i].bp, + RMI_RECV_BUFFER_ID, buff_size)) { + /* error message printed by DT_post_recv_buffer */ + goto test_failure; + } + if (!DT_post_recv_buffer(phead, + test_ptr->ep_context[i].ep_handle, + test_ptr->ep_context[i].bp, + SYNC_RECV_BUFFER_ID, SYNC_BUFF_SIZE)) { + /* error message printed by DT_post_recv_buffer */ + goto test_failure; + } + + /* + * Establish the connection + */ + test_ptr->ep_context[i].ia_port = test_ptr->base_port + i; + + if (pt_ptr->local_is_server) { + if (test_ptr->cmd->use_rsp) { + /* + * Server - create a single-use RSP and + * await a connection for this EP + */ + + ret = dat_rsp_create(test_ptr->ia_handle, + test_ptr->ep_context[i]. + ia_port, + test_ptr->ep_context[i]. + ep_handle, + test_ptr->ep_context[i]. + creq_evd_hdl, + &test_ptr->ep_context[i]. + rsp_handle); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x + "]: dat_rsp_create #%d error: %s\n", + test_ptr->base_port, + i, + DT_RetToString(ret)); + goto test_failure; + } + } else { + ret = dat_psp_create(test_ptr->ia_handle, + test_ptr->ep_context[i]. + ia_port, + test_ptr->ep_context[i]. + creq_evd_hdl, + DAT_PSP_CONSUMER_FLAG, + &test_ptr->ep_context[i]. + psp_handle); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x + "]: dat_psp_create #%d error: %s\n", + test_ptr->base_port, + i, + DT_RetToString(ret)); + goto test_failure; + } + + DT_Tdep_PT_Debug(1, + (phead, + "Server[" F64x + "]: Listen #%d on PSP port 0x" + F64x "\n", + test_ptr->base_port, i, + test_ptr->ep_context[i]. + ia_port)); + } + } + } + + /* Here's where we tell the server process that this thread is + * ready to wait for connection requests from the remote end. + * Modify the synch wait semantics at your own risk - if these + * signals and waits aren't here, there will be chronic + * connection rejection timing problems. + */ + if (pt_ptr->local_is_server) { + DT_Mdep_Lock(&pt_ptr->Thread_counter_lock); + pt_ptr->Countdown_Counter--; + /* Deliberate pre-decrement. Post decrement won't + * work here, so don't do it. + */ + if (pt_ptr->Countdown_Counter <= 0) { + DT_Mdep_wait_object_wakeup(&pt_ptr->synch_wait_object); + } + + DT_Mdep_Unlock(&pt_ptr->Thread_counter_lock); + } + + for (i = 0; i < test_ptr->cmd->eps_per_thread; i++) { + DAT_UINT32 buff_size = MAX_OPS * sizeof(RemoteMemoryInfo); + RemoteMemoryInfo *RemoteMemInfo; + DAT_DTO_COMPLETION_EVENT_DATA dto_stat; + DAT_CR_ARRIVAL_EVENT_DATA cr_stat; + DAT_CR_HANDLE cr_handle; + + /* + * Establish the connection + */ + + if (pt_ptr->local_is_server) { + DAT_CR_PARAM cr_param; + + if (test_ptr->cmd->use_rsp) { + + /* wait for the connection request */ + if (!DT_cr_event_wait(phead, + test_ptr->ep_context[i]. + creq_evd_hdl, &cr_stat) + || !DT_cr_check(phead, &cr_stat, + test_ptr->ep_context[i]. + rsp_handle, + test_ptr->ep_context[i]. + ia_port, &cr_handle, + "Server")) { + goto test_failure; + } + + ret = dat_cr_query(cr_handle, + DAT_CR_FIELD_ALL, &cr_param); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x + "]: dat_cr_query #%d error:(%x) %s\n", + test_ptr->base_port, + i, ret, + DT_RetToString(ret)); + } else { + if (strncmp + ((char *)cr_param.private_data, + private_data_str, + strlen(private_data_str)) != 0) { + DT_Tdep_PT_Printf(phead, + "--Private Data mismatch!\n"); + } else { + DT_Tdep_PT_Debug(1, + (phead, + "--Private Data: %d: <%s>\n", + cr_param. + private_data_size, + (char *) + cr_param. + private_data)); + } + } + + /* what, me query? just try to accept the connection */ + ret = dat_cr_accept(cr_handle, 0, /* NULL for RSP */ + 0, + (DAT_PVOID) 0 + /* no private data */ ); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x + "]: dat_cr_accept #%d error: %s\n", + test_ptr->base_port, + i, + DT_RetToString(ret)); + /* cr_handle consumed on failure */ + goto test_failure; + } + + /* wait for DAT_CONNECTION_EVENT_ESTABLISHED */ + if (!DT_conn_event_wait(phead, + test_ptr->ep_context[i]. + ep_handle, + test_ptr->ep_context[i]. + conn_evd_hdl, + &event_num)) { + /* error message printed by DT_conn_event_wait */ + goto test_failure; + } + /* throw away single-use PSP */ + ret = + dat_rsp_free(test_ptr->ep_context[i]. + rsp_handle); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x + "]: dat_rsp_free #%d error: %s\n", + test_ptr->base_port, + i, + DT_RetToString(ret)); + goto test_failure; + } + + } else { + /* + * Server - use a short-lived PSP instead of an RSP + */ + /* wait for a connection request */ + if (!DT_cr_event_wait(phead, + test_ptr->ep_context[i]. + creq_evd_hdl, &cr_stat)) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x + "]: dat_psp_create #%d error: %s\n", + test_ptr->base_port, + i, + DT_RetToString(ret)); + goto test_failure; + } + if (!DT_cr_check(phead, + &cr_stat, + test_ptr->ep_context[i]. + psp_handle, + test_ptr->ep_context[i]. + ia_port, &cr_handle, + "Server")) { + goto test_failure; + } + + ret = dat_cr_query(cr_handle, + DAT_CR_FIELD_ALL, &cr_param); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x + "]: dat_cr_query #%d error: %s\n", + test_ptr->base_port, + i, + DT_RetToString(ret)); + } else { + if (strncmp + ((char *)cr_param.private_data, + private_data_str, + strlen(private_data_str)) != 0) { + DT_Tdep_PT_Printf(phead, + "--Private Data mismatch!\n"); + } else { + DT_Tdep_PT_Debug(1, + (phead, + "--Private Data: %d: <%s>\n", + cr_param. + private_data_size, + (char *) + cr_param. + private_data)); + } + } + + /* what, me query? just try to accept the connection */ + ret = dat_cr_accept(cr_handle, + test_ptr->ep_context[i]. + ep_handle, 0, + (DAT_PVOID) 0 + /* no private data */ ); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x + "]: dat_cr_accept #%d error: %s\n", + test_ptr->base_port, + i, + DT_RetToString(ret)); + /* cr_handle consumed on failure */ + (void)dat_psp_free(test_ptr-> + ep_context[i]. + psp_handle); + goto test_failure; + } + + /* wait for DAT_CONNECTION_EVENT_ESTABLISHED */ + if (!DT_conn_event_wait(phead, + test_ptr->ep_context[i]. + ep_handle, + test_ptr->ep_context[i]. + conn_evd_hdl, + &event_num)) { + /* error message printed by DT_cr_event_wait */ + (void)dat_psp_free(&test_ptr-> + ep_context[i]. + psp_handle); + goto test_failure; + } + + /* throw away single-use PSP */ + ret = + dat_psp_free(test_ptr->ep_context[i]. + psp_handle); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x + "]: dat_psp_free #%d error: %s\n", + test_ptr->base_port, + i, + DT_RetToString(ret)); + goto test_failure; + } + } /* end short-lived PSP */ + + DT_Tdep_PT_Debug(1, + (phead, + "Server[" F64x + "]: Accept #%d on port 0x" F64x "\n", + test_ptr->base_port, i, + test_ptr->ep_context[i].ia_port)); + } else { + /* + * Client - connect + */ + unsigned int retry_cnt = 0; + DAT_UINT32 buff_size = + MAX_OPS * sizeof(RemoteMemoryInfo); + + DT_Tdep_PT_Debug(1, + (phead, + "Client[" F64x + "]: Connect #%d on port 0x" F64x "\n", + test_ptr->base_port, i, + test_ptr->ep_context[i].ia_port)); + +#ifdef CM_BUSTED + /***** XXX Chill out a bit to give the kludged CM a chance ... + *****/ DT_Mdep_Sleep(5000); +#endif + + retry: + ret = dat_ep_connect(test_ptr->ep_context[i].ep_handle, + test_ptr->remote_ia_addr, + test_ptr->ep_context[i].ia_port, + DAT_TIMEOUT_INFINITE, + strlen(private_data_str), + private_data_str, + pt_ptr->Params.ReliabilityLevel, + DAT_CONNECT_DEFAULT_FLAG); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x + "]: dat_ep_connect #%d error: %s (0x%x)\n", + test_ptr->base_port, i, + DT_RetToString(ret), ret); + goto test_failure; + } + + /* wait for DAT_CONNECTION_EVENT_ESTABLISHED */ + if (!DT_conn_event_wait(phead, + test_ptr->ep_context[i]. + ep_handle, + test_ptr->ep_context[i]. + conn_evd_hdl, &event_num)) { + /* error message printed by DT_cr_event_wait */ + if (event_num == + DAT_CONNECTION_EVENT_PEER_REJECTED) { + DT_Mdep_Sleep(1000); + /* + * See if any buffers were flushed as a result of + * the REJECT; clean them up and repost if so + */ + { + DAT_EVENT event; + DAT_COUNT drained = 0; + + dat_ep_reset(test_ptr-> + ep_context[i]. + ep_handle); + do { + ret = + DT_Tdep_evd_dequeue + (test_ptr-> + ep_context[i]. + recv_evd_hdl, + &event); + drained++; + } while (DAT_GET_TYPE(ret) != + DAT_QUEUE_EMPTY); + + if (drained > 1) { + /* + * Post recv and sync buffers + */ + if (!DT_post_recv_buffer + (phead, + test_ptr-> + ep_context[i]. + ep_handle, + test_ptr-> + ep_context[i].bp, + RMI_RECV_BUFFER_ID, + buff_size)) { + /* error message printed by DT_post_recv_buffer */ + goto test_failure; + } + if (!DT_post_recv_buffer + (phead, + test_ptr-> + ep_context[i]. + ep_handle, + test_ptr-> + ep_context[i].bp, + SYNC_RECV_BUFFER_ID, + SYNC_BUFF_SIZE)) { + /* error message printed by DT_post_recv_buffer */ + goto test_failure; + } + } + } + DT_Tdep_PT_Printf(phead, + "Client[" F64x + "]: retrying connection...\n", + test_ptr->base_port); + retry_cnt++; + if (retry_cnt < MAX_CONN_RETRY) { + goto retry; + } + } + /* error message printed by DT_cr_event_wait */ + goto test_failure; + } + + DT_Tdep_PT_Debug(1, + (phead, + "Client[" F64x + "]: Got Connection #%d\n", + test_ptr->base_port, i)); + } + +#ifdef CM_BUSTED + /***** XXX Chill out a bit to give the kludged CM a chance ... + *****/ DT_Mdep_Sleep(5000); +#endif + + /* + * Fill in the test_ptr with relevant command info + */ + for (j = 0; j < test_ptr->cmd->num_ops; j++) { + test_ptr->ep_context[i].op[j].server_initiated + = test_ptr->cmd->op[j].server_initiated; + test_ptr->ep_context[i].op[j].transfer_type + = test_ptr->cmd->op[j].transfer_type; + test_ptr->ep_context[i].op[j].num_segs + = test_ptr->cmd->op[j].num_segs; + test_ptr->ep_context[i].op[j].seg_size + = test_ptr->cmd->op[j].seg_size; + test_ptr->ep_context[i].op[j].reap_send_on_recv + = test_ptr->cmd->op[j].reap_send_on_recv; + } + + /* + * Exchange remote memory info: If we're going to participate + * in an RDMA, we need to allocate memory buffers and advertise + * them to the other side. + */ + for (j = 0; j < test_ptr->cmd->num_ops; j++) { + DAT_BOOLEAN us; + + us = (pt_ptr->local_is_server && + test_ptr->ep_context[i].op[j].server_initiated) || + (!pt_ptr->local_is_server && + !test_ptr->ep_context[i].op[j].server_initiated); + + test_ptr->ep_context[i].op[j].Rdma_Context = + (DAT_RMR_CONTEXT) 0; + test_ptr->ep_context[i].op[j].Rdma_Address = 0; + + switch (test_ptr->ep_context[i].op[j].transfer_type) { + case RDMA_READ: + { + test_ptr->ep_context[i].op[j].bp = + DT_BpoolAlloc(pt_ptr, + phead, + test_ptr->ia_handle, + test_ptr->pz_handle, + test_ptr-> + ep_context[i]. + ep_handle, + test_ptr-> + ep_context[i]. + reqt_evd_hdl, + test_ptr-> + ep_context[i].op[j]. + seg_size, + test_ptr-> + ep_context[i].op[j]. + num_segs, + DAT_OPTIMAL_ALIGNMENT, + false, + !us ? true : false); + if (!test_ptr->ep_context[i].op[j].bp) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x + "]: no memory for buffers (RDMA/RD)\n", + test_ptr-> + base_port); + goto test_failure; + } + if (!us) { + test_ptr->ep_context[i].op[j]. + Rdma_Context = + DT_Bpool_GetRMR(test_ptr-> + ep_context + [i].op[j]. + bp, 0); + test_ptr->ep_context[i].op[j]. + Rdma_Address = + (DAT_VADDR) (uintptr_t) + DT_Bpool_GetBuffer + (test_ptr->ep_context[i]. + op[j].bp, 0); + DT_Tdep_PT_Debug(3, + (phead, + "not-us: RDMA/RD [ va=" + F64x + ", ctxt=%x ]\n", + test_ptr-> + ep_context[i]. + op[j]. + Rdma_Address, + test_ptr-> + ep_context[i]. + op[j]. + Rdma_Context)); + } + break; + } + + case RDMA_WRITE: + { + test_ptr->ep_context[i].op[j].bp = + DT_BpoolAlloc(pt_ptr, + phead, + test_ptr->ia_handle, + test_ptr->pz_handle, + test_ptr-> + ep_context[i]. + ep_handle, + test_ptr-> + ep_context[i]. + reqt_evd_hdl, + test_ptr-> + ep_context[i].op[j]. + seg_size, + test_ptr-> + ep_context[i].op[j]. + num_segs, + DAT_OPTIMAL_ALIGNMENT, + !us ? true : false, + false); + if (!test_ptr->ep_context[i].op[j].bp) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x + "]: no memory for buffers (RDMA/WR)\n", + test_ptr-> + base_port); + goto test_failure; + } + if (!us) { + test_ptr->ep_context[i].op[j]. + Rdma_Context = + DT_Bpool_GetRMR(test_ptr-> + ep_context + [i].op[j]. + bp, 0); + test_ptr->ep_context[i].op[j]. + Rdma_Address = + (DAT_VADDR) (uintptr_t) + DT_Bpool_GetBuffer + (test_ptr->ep_context[i]. + op[j].bp, 0); + DT_Tdep_PT_Debug(3, + (phead, + "not-us: RDMA/WR [ va=" + F64x + ", ctxt=%x ]\n", + test_ptr-> + ep_context[i]. + op[j]. + Rdma_Address, + test_ptr-> + ep_context[i]. + op[j]. + Rdma_Context)); + } + break; + } + + case SEND_RECV: + { + test_ptr->ep_context[i].op[j].bp = DT_BpoolAlloc(pt_ptr, phead, test_ptr->ia_handle, test_ptr->pz_handle, test_ptr->ep_context[i].ep_handle, DAT_HANDLE_NULL, /* rmr */ + test_ptr-> + ep_context + [i]. + op + [j]. + seg_size, + test_ptr-> + ep_context + [i]. + op + [j]. + num_segs, + DAT_OPTIMAL_ALIGNMENT, + false, + false); + if (!test_ptr->ep_context[i].op[j].bp) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x + "]: no memory for buffers (S/R)\n", + test_ptr-> + base_port); + goto test_failure; + } + + DT_Tdep_PT_Debug(3, (phead, + "%d: S/R [ va=%p ]\n", + j, (DAT_PVOID) + DT_Bpool_GetBuffer + (test_ptr-> + ep_context[i]. + op[j].bp, 0))); + break; + } + } + } /* end foreach op */ + + /* + * Prep send buffer with memory information + */ + RemoteMemInfo = (RemoteMemoryInfo *) + DT_Bpool_GetBuffer(test_ptr->ep_context[i].bp, + RMI_SEND_BUFFER_ID); + + for (j = 0; j < test_ptr->cmd->num_ops; j++) { + RemoteMemInfo[j].rmr_context = + test_ptr->ep_context[i].op[j].Rdma_Context; + RemoteMemInfo[j].mem_address.as_64 = + test_ptr->ep_context[i].op[j].Rdma_Address; + if (RemoteMemInfo[j].mem_address.as_64) { + DT_Tdep_PT_Debug(3, (phead, + "RemoteMemInfo[%d] va=" + F64x ", ctx=%x\n", j, + RemoteMemInfo[j]. + mem_address.as_64, + RemoteMemInfo[j]. + rmr_context)); + } + /* + * If the client and server are of different endiannesses, + * we must correct the endianness of the handle and address + * we pass to the other side. The other side cannot (and + * better not) interpret these values. + */ + if (DT_local_is_little_endian != + test_ptr->remote_is_little_endian) { + RemoteMemInfo[j].rmr_context = + DT_EndianMemHandle(RemoteMemInfo[j]. + rmr_context); + RemoteMemInfo[j].mem_address.as_64 = + DT_EndianMemAddress(RemoteMemInfo[j]. + mem_address.as_64); + } + } /* end foreach op */ + + /* + * Send our memory info. The client performs the first send to comply + * with the iWARP MPA protocol's "Connection Startup Rules". + */ + DT_Tdep_PT_Debug(1, + (phead, + "Test[" F64x "]: Sending %s Memory Info\n", + test_ptr->base_port, + test_ptr->is_server ? "Server" : "Client")); + + if (!test_ptr->is_server) { + + /* post the send buffer */ + if (!DT_post_send_buffer(phead, + test_ptr->ep_context[i]. + ep_handle, + test_ptr->ep_context[i].bp, + RMI_SEND_BUFFER_ID, + buff_size)) { + /* error message printed by DT_post_send_buffer */ + goto test_failure; + } + /* reap the send and verify it */ + dto_cookie.as_64 = LZERO; + dto_cookie.as_ptr = + (DAT_PVOID) DT_Bpool_GetBuffer(test_ptr-> + ep_context[i].bp, + RMI_SEND_BUFFER_ID); + if (!DT_dto_event_wait + (phead, test_ptr->ep_context[i].reqt_evd_hdl, + &dto_stat) + || !DT_dto_check(phead, &dto_stat, + test_ptr->ep_context[i].ep_handle, + buff_size, dto_cookie, + test_ptr-> + is_server ? "Client_Mem_Info_Send" + : "Server_Mem_Info_Send")) { + goto test_failure; + } + } + + /* + * Recv the other side's info + */ + DT_Tdep_PT_Debug(1, + (phead, + "Test[" F64x + "]: Waiting for %s Memory Info\n", + test_ptr->base_port, + test_ptr->is_server ? "Client" : "Server")); + dto_cookie.as_64 = LZERO; + dto_cookie.as_ptr = + (DAT_PVOID) DT_Bpool_GetBuffer(test_ptr->ep_context[i].bp, + RMI_RECV_BUFFER_ID); + if (!DT_dto_event_wait + (phead, test_ptr->ep_context[i].recv_evd_hdl, &dto_stat) + || !DT_dto_check(phead, &dto_stat, + test_ptr->ep_context[i].ep_handle, + buff_size, dto_cookie, + test_ptr-> + is_server ? "Client_Mem_Info_Recv" : + "Server_Mem_Info_Recv")) { + goto test_failure; + } + + if (test_ptr->is_server) { + /* post the send buffer */ + if (!DT_post_send_buffer(phead, + test_ptr->ep_context[i]. + ep_handle, + test_ptr->ep_context[i].bp, + RMI_SEND_BUFFER_ID, + buff_size)) { + /* error message printed by DT_post_send_buffer */ + goto test_failure; + } + /* reap the send and verify it */ + dto_cookie.as_64 = LZERO; + dto_cookie.as_ptr = + (DAT_PVOID) DT_Bpool_GetBuffer(test_ptr-> + ep_context[i].bp, + RMI_SEND_BUFFER_ID); + if (!DT_dto_event_wait + (phead, test_ptr->ep_context[i].reqt_evd_hdl, + &dto_stat) + || !DT_dto_check(phead, &dto_stat, + test_ptr->ep_context[i].ep_handle, + buff_size, dto_cookie, + test_ptr-> + is_server ? "Client_Mem_Info_Send" + : "Server_Mem_Info_Send")) { + goto test_failure; + } + } + + /* + * Extract what we need + */ + DT_Tdep_PT_Debug(1, + (phead, + "Test[" F64x "]: Memory Info received \n", + test_ptr->base_port)); + RemoteMemInfo = (RemoteMemoryInfo *) + DT_Bpool_GetBuffer(test_ptr->ep_context[i].bp, + RMI_RECV_BUFFER_ID); + for (j = 0; j < test_ptr->cmd->num_ops; j++) { + DAT_BOOLEAN us; + + us = (pt_ptr->local_is_server && + test_ptr->ep_context[i].op[j].server_initiated) || + (!pt_ptr->local_is_server && + !test_ptr->ep_context[i].op[j].server_initiated); + if (us && + (test_ptr->ep_context[i].op[j].transfer_type == + RDMA_READ + || test_ptr->ep_context[i].op[j].transfer_type == + RDMA_WRITE)) { + test_ptr->ep_context[i].op[j].Rdma_Context = + RemoteMemInfo[j].rmr_context; + test_ptr->ep_context[i].op[j].Rdma_Address = + RemoteMemInfo[j].mem_address.as_64; + DT_Tdep_PT_Debug(3, + (phead, + "Got RemoteMemInfo [ va=" F64x + ", ctx=%x ]\n", + test_ptr->ep_context[i].op[j]. + Rdma_Address, + test_ptr->ep_context[i].op[j]. + Rdma_Context)); + } + } + } /* end foreach EP context */ + + /* + * Dump out the state of the world if we're debugging + */ + if (test_ptr->cmd->debug) { + DT_Print_Transaction_Test(phead, test_ptr); + } + + /* + * Finally! Run the test. + */ + success = DT_Transaction_Run(phead, test_ptr); + + /* + * Now clean up and go home + */ + test_failure: + if (test_ptr->ep_context) { + + /* Foreach EP */ + for (i = 0; i < test_ptr->cmd->eps_per_thread; i++) { + DAT_EP_HANDLE ep_handle; + + ep_handle = DAT_HANDLE_NULL; + + /* Free the per-op buffers */ + for (j = 0; j < test_ptr->cmd->num_ops; j++) { + if (test_ptr->ep_context[i].op[j].bp) { + if (!DT_Bpool_Destroy(pt_ptr, + phead, + test_ptr-> + ep_context[i]. + op[j].bp)) { + DT_Tdep_PT_Printf(phead, + "test[" F64x + "]: Warning: Bpool destroy fails\n", + test_ptr-> + base_port); + /* carry on trying, regardless */ + } + } + } + + /* Free the remote memory info exchange buffers */ + if (test_ptr->ep_context[i].bp) { + if (!DT_Bpool_Destroy(pt_ptr, + phead, + test_ptr->ep_context[i]. + bp)) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x + "]: Warning: Bpool destroy fails\n", + test_ptr->base_port); + /* carry on trying, regardless */ + } + } + + /* + * Disconnect -- we may have left recv buffers posted, if we + * bailed out mid-setup, or ran to completion + * normally, so we use abrupt closure. + */ + if (test_ptr->ep_context[i].ep_handle) { + ret = + dat_ep_disconnect(test_ptr->ep_context[i]. + ep_handle, + DAT_CLOSE_ABRUPT_FLAG); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x + "]: Warning: dat_ep_disconnect (%s) " + "#%d error %s\n", + test_ptr->base_port, + success ? "graceful" : + "abrupt", i, + DT_RetToString(ret)); + /* carry on trying, regardless */ + } + } + + /* + * Wait on each of the outstanding EP handles. Some of them + * may be disconnected by the remote side, we are racing + * here. + */ + + if (success) { /* Ensure DT_Transaction_Run did not return error otherwise may get stuck waiting for disconnect event */ + if (!DT_disco_event_wait(phead, + test_ptr-> + ep_context[i]. + conn_evd_hdl, + &ep_handle)) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x + "]: bad disconnect event\n", + test_ptr->base_port); + } + } + ep_handle = test_ptr->ep_context[i].ep_handle; + + /* + * Free the handle returned by the disconnect event. + * With multiple EPs, it may not be the EP we just + * disconnected as we are racing with the remote side + * disconnects. + */ + if (DAT_HANDLE_NULL != ep_handle) { + DAT_EVENT event; + /* + * Drain off outstanding DTOs that may have been + * generated by racing disconnects + */ + do { + ret = + DT_Tdep_evd_dequeue(test_ptr-> + ep_context[i]. + recv_evd_hdl, + &event); + } while (ret == DAT_SUCCESS); + /* Destroy the EP */ + ret = dat_ep_free(ep_handle); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x + "]: dat_ep_free #%d error: %s\n", + test_ptr->base_port, + i, + DT_RetToString(ret)); + /* carry on trying, regardless */ + } + } + /* clean up the EVDs */ + if (test_ptr->ep_context[i].conn_evd_hdl) { + ret = + DT_Tdep_evd_free(test_ptr->ep_context[i]. + conn_evd_hdl); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x + "]: dat_evd_free (conn) error: %s\n", + test_ptr->base_port, + DT_RetToString(ret)); + } + } + if (pt_ptr->local_is_server) { + if (test_ptr->ep_context[i].creq_evd_hdl) { + ret = + DT_Tdep_evd_free(test_ptr-> + ep_context[i]. + creq_evd_hdl); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x + "]: dat_evd_free (creq) error: %s\n", + test_ptr-> + base_port, + DT_RetToString + (ret)); + } + } + } + if (test_ptr->ep_context[i].reqt_evd_hdl) { + ret = + DT_Tdep_evd_free(test_ptr->ep_context[i]. + reqt_evd_hdl); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x + "]: dat_evd_free (reqt) error: %s\n", + test_ptr->base_port, + DT_RetToString(ret)); + } + } + if (test_ptr->ep_context[i].recv_evd_hdl) { + ret = + DT_Tdep_evd_free(test_ptr->ep_context[i]. + recv_evd_hdl); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x + "]: dat_evd_free (recv) error: %s\n", + test_ptr->base_port, + DT_RetToString(ret)); + } + } + } /* end foreach per-EP context */ + + DT_MemListFree(pt_ptr, test_ptr->ep_context); + } + + /* clean up the PZ */ + if (test_ptr->pz_handle) { + ret = dat_pz_free(test_ptr->pz_handle); + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "Test[" F64x + "]: dat_pz_free error: %s\n", + test_ptr->base_port, + DT_RetToString(ret)); + /* fall through, keep trying */ + } + } + + DT_Tdep_PT_Debug(1, + (phead, "Test[" F64x "]: cleanup is done\n", + test_ptr->base_port)); + DT_MemListFree(pt_ptr, test_ptr); + DT_Thread_Destroy(thread, pt_ptr); + DT_Mdep_Thread_Detach(DT_Mdep_Thread_SELF()); /* AMM */ + DT_Mdep_Thread_EXIT(NULL); /* AMM */ +} + +/* ----------------------------------------------------------------------- + * The actual performance test + */ +bool +DT_Transaction_Run(DT_Tdep_Print_Head * phead, Transaction_Test_t * test_ptr) +{ + unsigned int op; + unsigned int iteration; + int bytes; + bool ours; + bool success = false; + bool repost_recv; + unsigned int i; + + /* pre-post all receive buffers */ + for (op = 0; op < test_ptr->cmd->num_ops; op++) { + /* if it is a SEND/RECV, we must post receive buffers */ + if (test_ptr->ep_context[0].op[op].transfer_type == SEND_RECV) { + ours = (test_ptr->is_server == + test_ptr->ep_context[0].op[op]. + server_initiated); + if (!ours) { + if (!DT_handle_post_recv_buf(phead, + test_ptr-> + ep_context, + test_ptr->cmd-> + eps_per_thread, + op)) { + goto bail; + } + } + } + } + + /* initialize data if we are validating it */ + if (test_ptr->cmd->validate) { + DT_Transaction_Validation_Fill(phead, test_ptr, 0); + } + + /* + * Now that we've posted our receive buffers... + * synchronize with the other side. + */ + DT_Tdep_PT_Debug(1, + (phead, + "Test[" F64x "]: Synchronize with the other side\n", + test_ptr->base_port)); + + /* + * Each server thread sends a sync message to the corresponding + * client thread. All clients wait until all server threads + * have sent their sync messages. Then all clients send + * sync message. + * + * Since all of the events are directed to the same EVD, + * we do not use DT_dto_check(.) to verify the attributes + * of the sync message event. DT_dto_check(.) requires the + * comsumer to pass the expected EP, but we do not know + * what to expect. DAPL does not guarantee the order of + * completions across EPs. Therfore we only know that + * test_ptr->cmd->eps_per_thread number of completion events + * will be generated but not the order in which they will + * complete. + */ + + if (test_ptr->is_server) { + /* + * Server + */ + DT_Tdep_PT_Debug(1, + (phead, + "Test[" F64x "]: Send Sync to Client\n", + test_ptr->base_port)); + for (i = 0; i < test_ptr->cmd->eps_per_thread; i++) { + if (!DT_post_send_buffer(phead, + test_ptr->ep_context[i]. + ep_handle, + test_ptr->ep_context[i].bp, + SYNC_SEND_BUFFER_ID, + SYNC_BUFF_SIZE)) { + DT_Tdep_PT_Debug(1, + (phead, + "Test[" F64x + "]: Server sync send error\n", + test_ptr->base_port)); + goto bail; + } + } + for (i = 0; i < test_ptr->cmd->eps_per_thread; i++) { + DAT_DTO_COMPLETION_EVENT_DATA dto_stat; + + if (!DT_dto_event_wait(phead, + test_ptr->ep_context[i]. + reqt_evd_hdl, &dto_stat)) { + DT_Tdep_PT_Debug(1, + (phead, + "Test[" F64x + "]: Server sync send error\n", + test_ptr->base_port)); + + goto bail; + } + } + + DT_Tdep_PT_Debug(1, + (phead, + "Test[" F64x "]: Wait for Sync Message\n", + test_ptr->base_port)); + for (i = 0; i < test_ptr->cmd->eps_per_thread; i++) { + DAT_DTO_COMPLETION_EVENT_DATA dto_stat; + + if (!DT_dto_event_wait(phead, + test_ptr->ep_context[i]. + recv_evd_hdl, &dto_stat)) { + DT_Tdep_PT_Debug(1, + (phead, + "Test[" F64x + "]: Server sync recv error\n", + test_ptr->base_port)); + goto bail; + } + } + } else { + /* + * Client + */ + DT_Tdep_PT_Debug(1, + (phead, + "Test[" F64x "]: Wait for Sync Message\n", + test_ptr->base_port)); + for (i = 0; i < test_ptr->cmd->eps_per_thread; i++) { + DAT_DTO_COMPLETION_EVENT_DATA dto_stat; + + if (!DT_dto_event_wait(phead, + test_ptr->ep_context[i]. + recv_evd_hdl, &dto_stat)) { + DT_Tdep_PT_Debug(1, + (phead, + "Test[" F64x + "]: Client sync recv error\n", + test_ptr->base_port)); + goto bail; + } + DT_transaction_stats_set_ready(phead, + &test_ptr->pt_ptr-> + Client_Stats); + } + + /* check if it is time for client to send sync */ + if (!DT_transaction_stats_wait_for_all(phead, + &test_ptr->pt_ptr-> + Client_Stats)) { + goto bail; + } + + DT_Tdep_PT_Debug(1, + (phead, "Test[" F64x "]: Send Sync Msg\n", + test_ptr->base_port)); + for (i = 0; i < test_ptr->cmd->eps_per_thread; i++) { + if (!DT_post_send_buffer(phead, + test_ptr->ep_context[i]. + ep_handle, + test_ptr->ep_context[i].bp, + SYNC_SEND_BUFFER_ID, + SYNC_BUFF_SIZE)) { + DT_Tdep_PT_Debug(1, + (phead, + "Test[" F64x + "]: Client sync send error\n", + test_ptr->base_port)); + goto bail; + } + } + for (i = 0; i < test_ptr->cmd->eps_per_thread; i++) { + DAT_DTO_COMPLETION_EVENT_DATA dto_stat; + + if (!DT_dto_event_wait(phead, + test_ptr->ep_context[i]. + reqt_evd_hdl, &dto_stat)) { + goto bail; + } + } + } + + /* + * Get to work ... + */ + DT_Tdep_PT_Debug(1, + (phead, "Test[" F64x "]: Begin...\n", + test_ptr->base_port)); + test_ptr->stats.start_time = DT_Mdep_GetTime(); + + for (iteration = 0; + iteration < test_ptr->cmd->num_iterations; iteration++) { + + DT_Tdep_PT_Debug(1, (phead, "iteration: %d\n", iteration)); + + /* repost unless this is the last iteration */ + repost_recv = (iteration + 1 != test_ptr->cmd->num_iterations); + + for (op = 0; op < test_ptr->cmd->num_ops; op++) { + ours = (test_ptr->is_server == + test_ptr->ep_context[0].op[op]. + server_initiated); + bytes = + (test_ptr->ep_context[0].op[op].seg_size * + test_ptr->ep_context[0].op[op].num_segs * + test_ptr->cmd->eps_per_thread); + + switch (test_ptr->ep_context[0].op[op].transfer_type) { + case RDMA_READ: + { + test_ptr->stats.stat_bytes_rdma_read += + bytes; + if (ours) { + DT_Tdep_PT_Debug(1, + (phead, + "Test[" F64x + "]: RdmaRead [%d]\n", + test_ptr-> + base_port, + op)); + if (!DT_handle_rdma_op + (phead, + test_ptr->ep_context, + test_ptr->cmd-> + eps_per_thread, RDMA_READ, + op, test_ptr->cmd->poll)) { + DT_Tdep_PT_Printf(phead, + "Test[" + F64x + "]: RdmaRead error[%d]\n", + test_ptr-> + base_port, + op); + goto bail; + } + } + break; + } + + case RDMA_WRITE: + { + test_ptr->stats.stat_bytes_rdma_write += + bytes; + if (ours) { + DT_Tdep_PT_Debug(1, + (phead, + "Test[" F64x + "]: RdmaWrite [%d]\n", + test_ptr-> + base_port, + op)); + if (!DT_handle_rdma_op + (phead, + test_ptr->ep_context, + test_ptr->cmd-> + eps_per_thread, RDMA_WRITE, + op, test_ptr->cmd->poll)) { + DT_Tdep_PT_Printf(phead, + "Test[" + F64x + "]: RdmaWrite error[%d]\n", + test_ptr-> + base_port, + op); + goto bail; + } + } + break; + } + + case SEND_RECV: + { + if (ours) { + test_ptr->stats. + stat_bytes_send += bytes; + DT_Tdep_PT_Debug(1, + (phead, + "Test[" F64x + "]: postsend [%d] \n", + test_ptr-> + base_port, + op)); + /* send data */ + if (!DT_handle_send_op(phead, + test_ptr-> + ep_context, + test_ptr-> + cmd-> + eps_per_thread, + op, + test_ptr-> + cmd-> + poll)) { + goto bail; + } + } else { + test_ptr->stats. + stat_bytes_recv += bytes; + DT_Tdep_PT_Debug(1, + (phead, + "Test[" F64x + "]: RecvWait and Re-Post [%d] \n", + test_ptr-> + base_port, + op)); + + if (!DT_handle_recv_op(phead, + test_ptr-> + ep_context, + test_ptr-> + cmd-> + eps_per_thread, + op, + test_ptr-> + cmd-> + poll, + repost_recv)) + { + goto bail; + } + } + + /* now before going on, is it time to validate? */ + if (test_ptr->cmd->validate) { + if (!test_ptr->pt_ptr->local_is_server) { /* CLIENT */ + /* the client validates on the third to last op */ + if (op == + test_ptr->cmd-> + num_ops - 3) { + if (!DT_Transaction_Validation_Check(phead, test_ptr, iteration)) { + goto bail; + } + DT_Transaction_Validation_Fill + (phead, + test_ptr, + iteration + + 1); + } + } else { /* SERVER */ + + /* the server validates on the second to last op */ + if (op == + test_ptr->cmd-> + num_ops - 2) { + if (!DT_Transaction_Validation_Check(phead, test_ptr, iteration)) { + goto bail; + } + DT_Transaction_Validation_Fill + (phead, + test_ptr, + iteration + + 1); + } + } + } /* end validate */ + break; + } + } /* end switch for transfer type */ + } /* end loop for each op */ + } /* end loop for iteration */ + + /* end time and print stats */ + test_ptr->stats.end_time = DT_Mdep_GetTime(); + if (!test_ptr->pt_ptr->local_is_server) { + DT_update_transaction_stats(&test_ptr->pt_ptr->Client_Stats, + test_ptr->cmd->eps_per_thread * + test_ptr->cmd->num_ops * + test_ptr->cmd->num_iterations, + test_ptr->stats.end_time - + test_ptr->stats.start_time, + test_ptr->stats.stat_bytes_send, + test_ptr->stats.stat_bytes_recv, + test_ptr->stats. + stat_bytes_rdma_read, + test_ptr->stats. + stat_bytes_rdma_write); + } + DT_Tdep_PT_Debug(1, + (phead, "Test[" F64x "]: End Successfully\n", + test_ptr->base_port)); + success = true; + + bail: + return (success); +} + +/*------------------------------------------------------------------------------ */ +void +DT_Transaction_Validation_Fill(DT_Tdep_Print_Head * phead, + Transaction_Test_t * test_ptr, + unsigned int iteration) +{ + bool ours; + unsigned int op; + unsigned int i; + unsigned int j; + unsigned int ind; + unsigned char *buff; + + if (iteration >= test_ptr->cmd->num_iterations) { + return; + } + DT_Tdep_PT_Debug(1, + (phead, "Test[" F64x "]: FILL Buffers Iteration %d\n", + test_ptr->base_port, iteration)); + + /* + * fill all but the last three ops, which + * were added to create barriers for data validation + */ + for (ind = 0; ind < test_ptr->cmd->eps_per_thread; ind++) { + for (op = 0; op < test_ptr->cmd->num_ops - 3; op++) { + ours = (test_ptr->is_server == + test_ptr->ep_context[ind].op[op]. + server_initiated); + + switch (test_ptr->ep_context[ind].op[op].transfer_type) + { + case RDMA_READ: + { + if (!ours) { + for (i = 0; + i < + test_ptr->ep_context[ind]. + op[op].num_segs; i++) { + + buff = + DT_Bpool_GetBuffer + (test_ptr-> + ep_context[ind]. + op[op].bp, i); + for (j = 0; + j < + test_ptr-> + ep_context[ind]. + op[op].seg_size; + j++) { + /* Avoid using all zero bits the 1st time */ + buff[j] = + (iteration + + 1) & 0xFF; + } + } + } + break; + } + + case RDMA_WRITE: + { + if (ours) { + for (i = 0; + i < + test_ptr->ep_context[ind]. + op[op].num_segs; i++) { + + buff = + DT_Bpool_GetBuffer + (test_ptr-> + ep_context[ind]. + op[op].bp, i); + for (j = 0; + j < + test_ptr-> + ep_context[ind]. + op[op].seg_size; + j++) { + /* Avoid using all zero bits the 1st time */ + buff[j] = + (iteration + + 1) & 0xFF; + } + } + } + break; + } + + case SEND_RECV: + { + if (ours) { + for (i = 0; + i < + test_ptr->ep_context[ind]. + op[op].num_segs; i++) { + + buff = + DT_Bpool_GetBuffer + (test_ptr-> + ep_context[ind]. + op[op].bp, i); + /***** + DT_Tdep_PT_Printf(phead, + "\tFill: wq=%d op=%d seg=%d ptr=[%p, %d]\n", + ind, op, i, buff, j); + *****/ + for (j = 0; + j < + test_ptr-> + ep_context[ind]. + op[op].seg_size; + j++) { + /* Avoid using all zero bits the 1st time */ + buff[j] = + (iteration + + 1) & 0xFF; + } + } + } + break; + } + } /* end switch transfer_type */ + } /* end for each op */ + } /* end for each ep per thread */ +} + +/*------------------------------------------------------------------------------ */ +bool +DT_Transaction_Validation_Check(DT_Tdep_Print_Head * phead, + Transaction_Test_t * test_ptr, int iteration) +{ + bool ours; + bool success = true; + unsigned int op; + unsigned int i; + unsigned int j; + unsigned int ind; + unsigned char *buff; + unsigned char expect; + unsigned char got; + + DT_Tdep_PT_Debug(1, + (phead, + "Test[" F64x "]: VALIDATE Buffers Iteration %d\n", + test_ptr->base_port, iteration)); + + /* + * fill all but the last three ops, which + * were added to create barriers for data validation + */ + for (ind = 0; ind < test_ptr->cmd->eps_per_thread; ind++) { + for (op = 0; op < test_ptr->cmd->num_ops - 3; op++) { + ours = (test_ptr->is_server == + test_ptr->ep_context[ind].op[op]. + server_initiated); + + switch (test_ptr->ep_context[ind].op[op].transfer_type) { + case RDMA_READ: + { + if (ours) { + for (i = 0; + i < + test_ptr->ep_context[ind]. + op[op].num_segs; i++) { + + buff = + DT_Bpool_GetBuffer + (test_ptr-> + ep_context[ind]. + op[op].bp, i); + + for (j = 0; + j < + test_ptr-> + ep_context[ind]. + op[op].seg_size; + j++) { + + expect = + (iteration + + 1) & 0xFF; + got = buff[j]; + if (expect != + got) { + DT_Tdep_PT_Printf + (phead, + "Test[" + F64x + "]: Validation Error :: %d\n", + test_ptr-> + base_port, + op); + DT_Tdep_PT_Printf + (phead, + "Test[" + F64x + "]: Expected %x Got %x\n", + test_ptr-> + base_port, + expect, + got); + DT_Tdep_PT_Debug + (3, + (phead, + "\twq=%d op=%d seg=%d byte=%d ptr=%p\n", + ind, + op, + i, + j, + buff)); + success + = + false; + break; + } + } + } + } + break; + } + + case RDMA_WRITE: + { + if (!ours) { + for (i = 0; + i < + test_ptr->ep_context[ind]. + op[op].num_segs; i++) { + + buff = + DT_Bpool_GetBuffer + (test_ptr-> + ep_context[ind]. + op[op].bp, i); + for (j = 0; + j < + test_ptr-> + ep_context[ind]. + op[op].seg_size; + j++) { + + expect = + (iteration + + 1) & 0xFF; + got = buff[j]; + if (expect != + got) { + DT_Tdep_PT_Printf + (phead, + "Test[" + F64x + "]: Validation Error :: %d\n", + test_ptr-> + base_port, + op); + DT_Tdep_PT_Printf + (phead, + "Test[" + F64x + "]: Expected %x Got %x\n", + test_ptr-> + base_port, + expect, + got); + DT_Tdep_PT_Debug + (3, + (phead, + "\twq=%d op=%d seg=%d byte=%d ptr=%p\n", + ind, + op, + i, + j, + buff)); + success + = + false; + break; + } + } + } + } + break; + } + + case SEND_RECV: + { + if (!ours) { + for (i = 0; + i < + test_ptr->ep_context[ind]. + op[op].num_segs; i++) { + + buff = + DT_Bpool_GetBuffer + (test_ptr-> + ep_context[ind]. + op[op].bp, i); + DT_Tdep_PT_Debug(3, + (phead, + "\tCheck:wq=%d op=%d seg=%d ptr=[%p, %d]\n", + ind, + op, i, + buff, + test_ptr-> + ep_context + [ind]. + op + [op]. + seg_size)); + + for (j = 0; + j < + test_ptr-> + ep_context[ind]. + op[op].seg_size; + j++) { + + expect = + (iteration + + 1) & 0xFF; + got = buff[j]; + if (expect != + got) { + DT_Tdep_PT_Printf + (phead, + "Test[" + F64x + "]: Validation Error :: %d\n", + test_ptr-> + base_port, + op); + DT_Tdep_PT_Printf + (phead, + "Test[" + F64x + "]: Expected %x Got %x\n", + test_ptr-> + base_port, + expect, + got); + DT_Tdep_PT_Debug + (3, + (phead, + "\twq=%d op=%d seg=%d byte=%d ptr=%p\n", + ind, + op, + i, + j, + buff)); + success + = + false; + break; + } + } + } + } + break; + } + } /* end switch transfer_type */ + } /* end for each op */ + } /* end for each ep per thread */ + + return (success); +} + +/*------------------------------------------------------------------------------ */ +void +DT_Print_Transaction_Test(DT_Tdep_Print_Head * phead, + Transaction_Test_t * test_ptr) +{ + DT_Tdep_PT_Printf(phead, "-------------------------------------\n"); + DT_Tdep_PT_Printf(phead, "TransTest.is_server : %d\n", + test_ptr->is_server); + DT_Tdep_PT_Printf(phead, "TransTest.remote_little_endian : %d\n", + test_ptr->remote_is_little_endian); + DT_Tdep_PT_Printf(phead, + "TransTest.base_port : " F64x "\n", + test_ptr->base_port); + DT_Tdep_PT_Printf(phead, "TransTest.pz_handle : %p\n", + test_ptr->pz_handle); + /* statistics */ + DT_Tdep_PT_Printf(phead, "TransTest.bytes_send : %d\n", + test_ptr->stats.stat_bytes_send); + DT_Tdep_PT_Printf(phead, "TransTest.bytes_recv : %d\n", + test_ptr->stats.stat_bytes_recv); + DT_Tdep_PT_Printf(phead, "TransTest.bytes_rdma_read : %d\n", + test_ptr->stats.stat_bytes_rdma_read); + DT_Tdep_PT_Printf(phead, "TransTest.bytes_rdma_write : %d\n", + test_ptr->stats.stat_bytes_rdma_write); +} + +/*------------------------------------------------------------------------------ */ +void +DT_Print_Transaction_Stats(DT_Tdep_Print_Head * phead, + Transaction_Test_t * test_ptr) +{ + double time; + double mbytes_send; + double mbytes_recv; + double mbytes_rdma_read; + double mbytes_rdma_write; + int total_ops; + time = + (double)(test_ptr->stats.end_time - + test_ptr->stats.start_time) / 1000; + mbytes_send = (double)test_ptr->stats.stat_bytes_send / 1024 / 1024; + mbytes_recv = (double)test_ptr->stats.stat_bytes_recv / 1024 / 1024; + mbytes_rdma_read = + (double)test_ptr->stats.stat_bytes_rdma_read / 1024 / 1024; + mbytes_rdma_write = + (double)test_ptr->stats.stat_bytes_rdma_write / 1024 / 1024; + total_ops = test_ptr->cmd->num_ops * test_ptr->cmd->num_iterations; + + DT_Tdep_PT_Printf(phead, "Test[: " F64x "] ---- Stats ----\n", + test_ptr->base_port); + DT_Tdep_PT_Printf(phead, "Iterations : %u\n", + test_ptr->cmd->num_iterations); + DT_Tdep_PT_Printf(phead, "Ops : %7d.%02d Ops/Sec\n", + whole(total_ops / time), + hundredths(total_ops / time)); + DT_Tdep_PT_Printf(phead, "Time : %7d.%02d sec\n", whole(time), + hundredths(time)); + DT_Tdep_PT_Printf(phead, "Sent : %7d.%02d MB - %7d.%02d MB/Sec\n", + whole(mbytes_send), hundredths(mbytes_send), + whole(mbytes_send / time), + hundredths(mbytes_send / time)); + DT_Tdep_PT_Printf(phead, "Recv : %7d.%02d MB - %7d.%02d MB/Sec\n", + whole(mbytes_recv), hundredths(mbytes_recv), + whole(mbytes_recv / time), + hundredths(mbytes_recv / time)); + DT_Tdep_PT_Printf(phead, "RDMA Read : %7d.%02d MB - %7d.%02d MB/Sec\n", + whole(mbytes_rdma_read), hundredths(mbytes_rdma_read), + whole(mbytes_rdma_read / time), + hundredths(mbytes_rdma_read / time)); + DT_Tdep_PT_Printf(phead, "RDMA Write : %7d.%02d MB - %7d.%02d MB/Sec\n", + whole(mbytes_rdma_write), + hundredths(mbytes_rdma_write), + whole(mbytes_rdma_write / time), + hundredths(mbytes_rdma_write / time)); +} diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_transaction_util.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_transaction_util.c new file mode 100644 index 00000000..14a14ddf --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_transaction_util.c @@ -0,0 +1,747 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" + +#define DT_LOCAL_COMPLETION_VECTOR_SIZE 32 + +/* ----------------------------------------------------------- + * Post a recv buffer on each of this thread's EPs. + */ +bool +DT_handle_post_recv_buf(DT_Tdep_Print_Head * phead, + Ep_Context_t * ep_context, + unsigned int num_eps, int op_indx) +{ + unsigned int i, j; + + for (i = 0; i < num_eps; i++) { + Transaction_Test_Op_t *op = &ep_context[i].op[op_indx]; + DAT_LMR_TRIPLET *iov = DT_Bpool_GetIOV(op->bp, 0); + DAT_DTO_COOKIE cookie; + DAT_RETURN ret; + + /* Prep the inputs */ + for (j = 0; j < op->num_segs; j++) { + iov[j].virtual_address = (DAT_VADDR) (uintptr_t) + DT_Bpool_GetBuffer(op->bp, j); + iov[j].segment_length = op->seg_size; + iov[j].lmr_context = DT_Bpool_GetLMR(op->bp, j); + } + cookie.as_64 = ((((DAT_UINT64) i) << 32) + | (((uintptr_t) DT_Bpool_GetBuffer(op->bp, 0)) & + 0xffffffffUL)); + + /* Post the recv */ + ret = dat_ep_post_recv(ep_context[i].ep_handle, + op->num_segs, + iov, + cookie, DAT_COMPLETION_DEFAULT_FLAG); + + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "Test Error: dat_ep_post_recv failed: %s\n", + DT_RetToString(ret)); + DT_Test_Error(); + return false; + } + } + + return true; +} + +/* ----------------------------------------------------------- + * Post a send buffer on each of this thread's EPs. + */ +bool +DT_handle_send_op(DT_Tdep_Print_Head * phead, + Ep_Context_t * ep_context, + unsigned int num_eps, int op_indx, bool poll) +{ + unsigned int i, j; + unsigned char *completion_reaped; + unsigned char lcomp[DT_LOCAL_COMPLETION_VECTOR_SIZE]; + bool rc = false; + + if (num_eps <= DT_LOCAL_COMPLETION_VECTOR_SIZE) { + completion_reaped = lcomp; + bzero((void *)completion_reaped, + sizeof(unsigned char) * num_eps); + } + else { + completion_reaped = DT_Mdep_Malloc(num_eps * sizeof(unsigned char)); + if (!completion_reaped) { + return false; + } + } + + for (i = 0; i < num_eps; i++) { + Transaction_Test_Op_t *op = &ep_context[i].op[op_indx]; + DAT_LMR_TRIPLET *iov = DT_Bpool_GetIOV(op->bp, 0); + DAT_DTO_COOKIE cookie; + DAT_RETURN ret; + + /* Prep the inputs */ + for (j = 0; j < op->num_segs; j++) { + iov[j].virtual_address = (DAT_VADDR) (uintptr_t) + DT_Bpool_GetBuffer(op->bp, j); + iov[j].segment_length = op->seg_size; + iov[j].lmr_context = DT_Bpool_GetLMR(op->bp, j); + } + cookie.as_64 = ((((DAT_UINT64) i) << 32) + | (((uintptr_t) DT_Bpool_GetBuffer(op->bp, 0)) & + 0xffffffffUL)); + + /* Post the send */ + ret = dat_ep_post_send(ep_context[i].ep_handle, + op->num_segs, + iov, + cookie, DAT_COMPLETION_DEFAULT_FLAG); + + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "Test Error: dat_ep_post_send failed: %s\n", + DT_RetToString(ret)); + DT_Test_Error(); + goto xit; + } + } + + for (i = 0; i < num_eps; i++) { + Transaction_Test_Op_t *op = &ep_context[i].op[op_indx]; + + if (op->reap_send_on_recv && !op->server_initiated) { + /* we will reap the send on the recv (Client SR) */ + rc = true; + goto xit; + } + } + + /* reap the send completion */ + for (i = 0; i < num_eps; i++) { + Transaction_Test_Op_t *op; + DAT_DTO_COMPLETION_EVENT_DATA dto_stat; + DAT_DTO_COOKIE dto_cookie; + unsigned int epnum; + + if (!DT_dto_event_reap + (phead, ep_context[i].reqt_evd_hdl, poll, &dto_stat)) { + goto xit; + } + + epnum = dto_stat.user_cookie.as_64 >> 32; + if (epnum > num_eps) { + DT_Tdep_PT_Printf(phead, + "Test Error: Send: Invalid endpoint completion reaped.\n" + "\tEndpoint: 0x%p, Cookie: 0x" F64x + ", Length: " F64u "\n", + dto_stat.ep_handle, + dto_stat.user_cookie.as_64, + dto_stat.transfered_length); + DT_Test_Error(); + goto xit; + } + + op = &ep_context[epnum].op[op_indx]; + + dto_cookie.as_64 = ((((DAT_UINT64) epnum) << 32) + | + (((uintptr_t) DT_Bpool_GetBuffer(op->bp, 0)) + & 0xffffffffUL)); + + if (!DT_dto_check(phead, + &dto_stat, + ep_context[epnum].ep_handle, + op->num_segs * op->seg_size, + dto_cookie, "Send")) { + goto xit; + } + + if (completion_reaped[epnum]) { + DT_Tdep_PT_Printf(phead, + "Test Error: Send: Secondary completion seen for endpoint 0x%p (%d)\n", + ep_context[epnum].ep_handle, epnum); + DT_Test_Error(); + goto xit; + } + completion_reaped[epnum] = 1; + } + + for (i = 0; i < num_eps; i++) { + if (completion_reaped[i] == 0) { + DT_Tdep_PT_Printf(phead, + "Test Error: Send: No completion seen for endpoint 0x%p (#%d)\n", + ep_context[i].ep_handle, i); + DT_Test_Error(); + goto xit; + } + } + + rc = true; + +xit: + if (completion_reaped != lcomp) + DT_Mdep_Free(completion_reaped); + return rc; +} + +/* ----------------------------------------------------------- + * Reap a recv op on each of this thread's EPs, + * then if requested reap the corresponding send ops, + * and re-post all of the recv buffers. + */ +bool +DT_handle_recv_op(DT_Tdep_Print_Head * phead, + Ep_Context_t * ep_context, + unsigned int num_eps, + int op_indx, bool poll, bool repost_recv) +{ + unsigned int i; + unsigned char *recv_completion_reaped; + unsigned char *send_completion_reaped; + unsigned char rcomp[DT_LOCAL_COMPLETION_VECTOR_SIZE]; + unsigned char lcomp[DT_LOCAL_COMPLETION_VECTOR_SIZE]; + bool rc = false; + + if (num_eps <= DT_LOCAL_COMPLETION_VECTOR_SIZE ) { + recv_completion_reaped = rcomp; + send_completion_reaped = lcomp; + bzero((void *)recv_completion_reaped, + sizeof(unsigned char) * num_eps); + bzero((void *)send_completion_reaped, + sizeof(unsigned char) * num_eps); + } + else { + recv_completion_reaped = DT_Mdep_Malloc(num_eps); + if (recv_completion_reaped == NULL) { + return false; + } + + send_completion_reaped = DT_Mdep_Malloc(num_eps); + if (send_completion_reaped == NULL) { + DT_Mdep_Free(recv_completion_reaped); + return false; + } + } + + /* Foreach EP, reap */ + for (i = 0; i < num_eps; i++) { + Transaction_Test_Op_t *op; + DAT_DTO_COMPLETION_EVENT_DATA dto_stat; + DAT_DTO_COOKIE dto_cookie; + unsigned int epnum; + + /* First reap the recv DTO event */ + if (!DT_dto_event_reap + (phead, ep_context[i].recv_evd_hdl, poll, &dto_stat)) { + goto xit; + } + + epnum = dto_stat.user_cookie.as_64 >> 32; + if (epnum > num_eps) { + DT_Tdep_PT_Printf(phead, + "Test Error: Receive: Invalid endpoint completion reaped.\n" + "\tEndpoint: 0x%p, Cookie: 0x" F64x + ", Length: " F64u "\n", + dto_stat.ep_handle, + dto_stat.user_cookie.as_64, + dto_stat.transfered_length); + DT_Test_Error(); + goto xit; + } + + op = &ep_context[epnum].op[op_indx]; + dto_cookie.as_64 = ((((DAT_UINT64) epnum) << 32) + | + (((uintptr_t) DT_Bpool_GetBuffer(op->bp, 0)) + & 0xffffffffUL)); + + if (!DT_dto_check(phead, + &dto_stat, + ep_context[epnum].ep_handle, + op->num_segs * op->seg_size, + dto_cookie, "Recv")) { + DT_Tdep_PT_Printf(phead, + "Test Error: recv DTO problem\n"); + DT_Test_Error(); + goto xit; + } + + if (recv_completion_reaped[epnum]) { + DT_Tdep_PT_Printf(phead, + "Test Error: Receive: Secondary completion seen for endpoint 0x%p (%d)\n", + ep_context[epnum].ep_handle, epnum); + DT_Test_Error(); + goto xit; + } + recv_completion_reaped[epnum] = 1; + + /* + * Check the current op to see whether we are supposed + * to reap the previous send op now. + */ + if (op->reap_send_on_recv && op->server_initiated) { + if (op_indx <= 0) + /* shouldn't happen, but let's be certain */ + { + DT_Tdep_PT_Printf(phead, + "Internal Error: reap_send_on_recv" + " but current op == #%d\n", + op_indx); + goto xit; + } + + if (!DT_dto_event_reap + (phead, ep_context[i].reqt_evd_hdl, poll, + &dto_stat)) { + goto xit; + } + + epnum = dto_stat.user_cookie.as_64 >> 32; + if (epnum > num_eps) { + DT_Tdep_PT_Printf(phead, + "Test Error: Send (ror): Invalid endpoint completion reaped.\n" + "\tEndpoint: 0x%p, Cookie: 0x" + F64x ", Length: " F64u "\n", + dto_stat.ep_handle, + dto_stat.user_cookie.as_64, + dto_stat.transfered_length); + DT_Test_Error(); + goto xit; + } + + /* + * We're reaping the last transaction, a + * send completion that we skipped when it was sent. + */ + op = &ep_context[epnum].op[op_indx - 1]; + + dto_cookie.as_64 = ((((DAT_UINT64) epnum) << 32) + | + (((uintptr_t) + DT_Bpool_GetBuffer(op->bp, 0)) + & 0xffffffffUL)); + + /* + * If we have multiple EPs we can't guarantee the order of + * completions, so disable ep_handle check + */ + if (!DT_dto_check(phead, + &dto_stat, + num_eps == + 1 ? ep_context[i].ep_handle : NULL, + op->num_segs * op->seg_size, + dto_cookie, "Send-reaped-on-recv")) { + DT_Tdep_PT_Printf(phead, + "Test Error: send DTO problem\n"); + DT_Test_Error(); + goto xit; + } + + if (send_completion_reaped[epnum]) { + DT_Tdep_PT_Printf(phead, + "Test Error: Send (ror): Secondary completion seen for endpoint 0x%p (%d)\n", + ep_context[epnum].ep_handle, + epnum); + DT_Test_Error(); + goto xit; + } + send_completion_reaped[epnum] = 1; + } + } + + for (i = 0; i < num_eps; i++) { + if (recv_completion_reaped[i] == 0) { + DT_Tdep_PT_Printf(phead, + "Test Error: Receive: No completion seen for endpoint 0x%p (#%d)\n", + ep_context[i].ep_handle, i); + DT_Test_Error(); + goto xit; + } + } + + if (ep_context[0].op[op_indx].reap_send_on_recv + && ep_context[0].op[op_indx].server_initiated) { + for (i = 0; i < num_eps; i++) { + if (send_completion_reaped[i] == 0) { + DT_Tdep_PT_Printf(phead, + "Test Error: Send (ror): No completion seen for endpoint 0x%p (#%d)\n", + ep_context[i].ep_handle, i); + DT_Test_Error(); + goto xit; + } + } + } + + if (repost_recv) { + /* repost the receive buffer */ + if (!DT_handle_post_recv_buf + (phead, ep_context, num_eps, op_indx)) { + DT_Tdep_PT_Printf(phead, + "Test Error: recv re-post problem\n"); + DT_Test_Error(); + goto xit; + } + } + rc = true; +xit: + if (send_completion_reaped != lcomp) { + DT_Mdep_Free(recv_completion_reaped); + DT_Mdep_Free(send_completion_reaped); + } + return rc; +} + +/* ----------------------------------------------------------- + * Initiate an RDMA op (synchronous) on each of this thread's EPs. + */ +bool +DT_handle_rdma_op(DT_Tdep_Print_Head * phead, + Ep_Context_t * ep_context, + unsigned int num_eps, + DT_Transfer_Type opcode, int op_indx, bool poll) +{ + unsigned int i, j; + DAT_RETURN ret; + unsigned char *completion_reaped; + unsigned char lcomp[DT_LOCAL_COMPLETION_VECTOR_SIZE]; + bool rc = false; + + if (num_eps <= DT_LOCAL_COMPLETION_VECTOR_SIZE) { + completion_reaped = lcomp; + bzero((void *)completion_reaped, sizeof(unsigned char) * num_eps); + } + else { + completion_reaped = DT_Mdep_Malloc(num_eps * sizeof(unsigned char)); + if (!completion_reaped) { + return false; + } + } + + /* Initiate the operation */ + for (i = 0; i < num_eps; i++) { + Transaction_Test_Op_t *op = &ep_context[i].op[op_indx]; + DAT_LMR_TRIPLET *iov = DT_Bpool_GetIOV(op->bp, 0); + DAT_DTO_COOKIE cookie; + DAT_RMR_TRIPLET rmr_triplet; + + /* Prep the inputs */ + for (j = 0; j < op->num_segs; j++) { + iov[j].virtual_address = (DAT_VADDR) (uintptr_t) + DT_Bpool_GetBuffer(op->bp, j); + iov[j].segment_length = op->seg_size; + iov[j].lmr_context = DT_Bpool_GetLMR(op->bp, j); + } + cookie.as_64 = ((((DAT_UINT64) i) << 32) + | (((uintptr_t) DT_Bpool_GetBuffer(op->bp, 0)) & + 0xffffffffUL)); + + rmr_triplet.virtual_address = + (DAT_VADDR) (uintptr_t) op->Rdma_Address; + rmr_triplet.segment_length = op->seg_size * op->num_segs; + rmr_triplet.rmr_context = op->Rdma_Context; + + DT_Tdep_PT_Debug(3, (phead, + "Call dat_ep_post_rdma_%s [" F64x ", sz=" + F64x ", ctxt=%x]\n", + (opcode == RDMA_WRITE ? "write" : "read"), + rmr_triplet.virtual_address, + rmr_triplet.segment_length, + rmr_triplet.rmr_context)); + + /* Post the operation */ + if (opcode == RDMA_WRITE) { + + ret = dat_ep_post_rdma_write(ep_context[i].ep_handle, + op->num_segs, + iov, + cookie, + &rmr_triplet, + DAT_COMPLETION_DEFAULT_FLAG); + + } else { /* opcode == RDMA_READ */ + + ret = dat_ep_post_rdma_read(ep_context[i].ep_handle, + op->num_segs, + iov, + cookie, + &rmr_triplet, + DAT_COMPLETION_DEFAULT_FLAG); + + } + if (ret != DAT_SUCCESS) { + DT_Tdep_PT_Printf(phead, + "Test Error: dat_ep_post_rdma_%s failed: %s\n", + (opcode == + RDMA_WRITE ? "write" : "read"), + DT_RetToString(ret)); + DT_Test_Error(); + goto err; + } else { + DT_Tdep_PT_Debug(3, (phead, + "Done dat_ep_post_rdma_%s %s\n", + (opcode == + RDMA_WRITE ? "write" : "read"), + " () Waiting ...")); + } + } + + /* Wait for it to happen */ + for (i = 0; i < num_eps; i++) { + Transaction_Test_Op_t *op; + DAT_DTO_COMPLETION_EVENT_DATA dto_stat; + DAT_DTO_COOKIE dto_cookie; + unsigned int epnum; + + if (!DT_dto_event_reap + (phead, ep_context[i].reqt_evd_hdl, poll, &dto_stat)) { + goto err; + } + + epnum = dto_stat.user_cookie.as_64 >> 32; + if (epnum > num_eps) { + DT_Tdep_PT_Printf(phead, + "Test Error: %s: Invalid endpoint completion reaped.\n" + "\tEndpoint: 0x%p, Cookie: 0x" F64x + ", Length: " F64u "\n", + opcode == + RDMA_WRITE ? "RDMA/WR" : "RDMA/RD", + dto_stat.ep_handle, + dto_stat.user_cookie.as_64, + dto_stat.transfered_length); + DT_Test_Error(); + goto err; + } + op = &ep_context[epnum].op[op_indx]; + + dto_cookie.as_64 = ((((DAT_UINT64) epnum) << 32) + | + (((uintptr_t) DT_Bpool_GetBuffer(op->bp, 0)) + & 0xffffffffUL)); + + if (!DT_dto_check(phead, + &dto_stat, + ep_context[epnum].ep_handle, + op->num_segs * op->seg_size, + dto_cookie, + (opcode == + RDMA_WRITE ? "RDMA/WR" : "RDMA/RD"))) { + goto err; + } + + if (completion_reaped[epnum]) { + DT_Tdep_PT_Printf(phead, + "Test Error: %s: Secondary completion seen for endpoint 0x%p (%d)\n", + opcode == + RDMA_WRITE ? "RDMA/WR" : "RDMA/RD", + ep_context[epnum].ep_handle, epnum); + DT_Test_Error(); + goto err; + } + completion_reaped[epnum] = 1; + + DT_Tdep_PT_Debug(3, (phead, + "dat_ep_post_rdma_%s OK\n", + (opcode == + RDMA_WRITE ? "RDMA/WR" : "RDMA/RD"))); + } + + for (i = 0; i < num_eps; i++) { + if (completion_reaped[i] == 0) { + DT_Tdep_PT_Printf(phead, + "Test Error: %s: No completion seen for endpoint 0x%p (#%d)\n", + opcode == + RDMA_WRITE ? "RDMA/WR" : "RDMA/RD", + ep_context[i].ep_handle, i); + DT_Test_Error(); + goto err; + } + } + + rc = true; + +err: + if (completion_reaped != lcomp) + DT_Mdep_Free(completion_reaped); + + return rc; +} + +/* ----------------------------------------------------------- + * Verify whether we (the client side) can support + * the requested 'T' test. + */ +bool DT_check_params(Per_Test_Data_t * pt_ptr, char *module) +{ + Transaction_Cmd_t *cmd = &pt_ptr->Params.u.Transaction_Cmd; + unsigned long num_recvs = 0U; + unsigned long num_sends = 0U; + unsigned long num_rdma_rd = 0U; + unsigned long num_rdma_wr = 0U; + unsigned long max_size = 0U; + unsigned long max_segs = 0U; + bool rval = true; + unsigned int i; + DT_Tdep_Print_Head *phead; + + phead = pt_ptr->Params.phead; + + /* Count up what's requested (including -V appended sync points) */ + for (i = 0; i < cmd->num_ops; i++) { + unsigned int xfer_size; + + xfer_size = cmd->op[i].num_segs * cmd->op[i].seg_size; + if (xfer_size > max_size) { + max_size = xfer_size; + } + if (cmd->op[i].num_segs > max_segs) { + max_segs = cmd->op[i].num_segs; + } + + switch (cmd->op[i].transfer_type) { + case SEND_RECV: + { + if (cmd->op[i].server_initiated) { + num_recvs++; + } else { + num_sends++; + } + break; + } + + case RDMA_READ: + { + num_rdma_rd++; + break; + } + + case RDMA_WRITE: + { + num_rdma_wr++; + break; + } + } + } + + /* + * Now check the IA and EP attributes, and check for some of the + * more obvious resource problems. This is hardly exhaustive, + * and some things will inevitably fall through to run-time. + * + * We don't compare + * num_rdma_rd > pt_ptr->ia_attr.max_rdma_read_per_ep + * num_rdma_wr > pt_ptr->ia_attr.max_dto_per_ep + * because each thread has its own EPs, and transfers are issued + * synchronously (across a thread's EPs, and ignoring -f, which allows + * a per-EP pipeline depth of at most 2 and applies only to SR ops), + * so dapltest actually attempts almost no pipelining on a single EP. + * But we do check that pre-posted recv buffers will all fit. + */ + if (num_recvs > pt_ptr->ia_attr.max_dto_per_ep || + num_sends > pt_ptr->ia_attr.max_dto_per_ep) { + DT_Tdep_PT_Printf(phead, + "%s: S/R: cannot supply %ld SR ops (maximum: %d)\n", + module, + num_recvs > num_sends ? num_recvs : num_sends, + pt_ptr->ia_attr.max_dto_per_ep); + rval = false; + } + if (max_size > pt_ptr->ia_attr.max_lmr_block_size) { + DT_Tdep_PT_Printf(phead, + "%s: buffer too large: 0x%lx (maximum: " F64x + " bytes)\n", module, max_size, + pt_ptr->ia_attr.max_lmr_block_size); + rval = false; + } + if (max_segs > pt_ptr->ep_attr.max_recv_iov || + max_segs > pt_ptr->ep_attr.max_request_iov) { + /* + * In an ideal world, we'd just ask for more segments + * when creating the EPs for the test, rather than + * checking against default EP attributes. + */ + DT_Tdep_PT_Printf(phead, + "%s: cannot use %ld segments (maxima: S %d, R %d)\n", + module, + max_segs, + pt_ptr->ep_attr.max_request_iov, + pt_ptr->ep_attr.max_recv_iov); + rval = false; + } + + return (rval); +} + +/* Empty function in which to set breakpoints. */ +void DT_Test_Error(void) +{ + ; +} + +void +DT_Transaction_Cmd_PT_Print(DT_Tdep_Print_Head * phead, Transaction_Cmd_t * cmd) +{ + unsigned int i; + DT_Tdep_PT_Printf(phead, "-------------------------------------\n"); + DT_Tdep_PT_Printf(phead, "TransCmd.server_name : %s\n", + cmd->server_name); + DT_Tdep_PT_Printf(phead, "TransCmd.num_iterations : %d\n", + cmd->num_iterations); + DT_Tdep_PT_Printf(phead, "TransCmd.num_threads : %d\n", + cmd->num_threads); + DT_Tdep_PT_Printf(phead, "TransCmd.eps_per_thread : %d\n", + cmd->eps_per_thread); + DT_Tdep_PT_Printf(phead, "TransCmd.validate : %d\n", + cmd->validate); + DT_Tdep_PT_Printf(phead, "TransCmd.dapl_name : %s\n", + cmd->dapl_name); + DT_Tdep_PT_Printf(phead, "TransCmd.num_ops : %d\n", + cmd->num_ops); + + for (i = 0; i < cmd->num_ops; i++) { + DT_Tdep_PT_Printf(phead, + "TransCmd.op[%d].transfer_type : %s %s\n", + i, + cmd->op[i].transfer_type == + 0 ? "RDMA_READ" : cmd->op[i].transfer_type == + 1 ? "RDMA_WRITE" : "SEND_RECV", + cmd->op[i]. + server_initiated ? " (server)" : " (client)"); + DT_Tdep_PT_Printf(phead, + "TransCmd.op[%d].seg_size : %d\n", + i, cmd->op[i].seg_size); + DT_Tdep_PT_Printf(phead, + "TransCmd.op[%d].num_segs : %d\n", + i, cmd->op[i].num_segs); + DT_Tdep_PT_Printf(phead, + "TransCmd.op[%d].reap_send_on_recv : %d\n", + i, cmd->op[i].reap_send_on_recv); + } +} diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_util.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_util.c new file mode 100644 index 00000000..39cc1a3b --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/test/dapl_util.c @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" + +/* + * Map DAT_RETURN values to readable strings, + * but don't assume the values are zero-based or contiguous. + */ +const char *DT_RetToString(DAT_RETURN ret_value) +{ + const char *major_msg, *minor_msg; + int sz; + char *errmsg; + + dat_strerror(ret_value, &major_msg, &minor_msg); + + sz = strlen(major_msg) + strlen(minor_msg) + 2; +/* + * FIXME: The callers of this function are not freeing + * the errmsg string. Hence there is a memory leak + * (this function is likely only used on error paths, + * so the consequences may not be that dire). + */ + errmsg = DT_Mdep_Malloc(sz); + strcpy(errmsg, major_msg); + strcat(errmsg, " "); + strcat(errmsg, minor_msg); + + return errmsg; +} + +/* + * Map DAT_RETURN values to readable strings, + * but don't assume the values are zero-based or contiguous. + */ +const char *DT_TransferTypeToString(DT_Transfer_Type type) +{ + static char *DT_Type[] = { + "RR", + "RW", + "SR" + }; + + if ((0 <= type) && (type <= 2)) { + return DT_Type[type]; + } else { + return "Error: Unkown Transfer Type"; + } +} + +/* + * Map DAT_ASYNC_ERROR_CODE values to readable strings + */ +const char *DT_AsyncErr2Str(DAT_EVENT_NUMBER error_code) +{ + unsigned int i; + static struct { + const char *name; + DAT_RETURN value; + } dat_errors[] = { +# define DATxx(x) { # x, x } + DATxx(DAT_DTO_COMPLETION_EVENT), + DATxx(DAT_RMR_BIND_COMPLETION_EVENT), + DATxx(DAT_CONNECTION_REQUEST_EVENT), + DATxx(DAT_CONNECTION_EVENT_ESTABLISHED), + DATxx(DAT_CONNECTION_EVENT_PEER_REJECTED), + DATxx(DAT_CONNECTION_EVENT_NON_PEER_REJECTED), + DATxx(DAT_CONNECTION_EVENT_ACCEPT_COMPLETION_ERROR), + DATxx(DAT_CONNECTION_EVENT_DISCONNECTED), + DATxx(DAT_CONNECTION_EVENT_BROKEN), + DATxx(DAT_CONNECTION_EVENT_TIMED_OUT), + DATxx(DAT_ASYNC_ERROR_EVD_OVERFLOW), + DATxx(DAT_ASYNC_ERROR_IA_CATASTROPHIC), + DATxx(DAT_ASYNC_ERROR_EP_BROKEN), + DATxx(DAT_ASYNC_ERROR_TIMED_OUT), + DATxx(DAT_ASYNC_ERROR_PROVIDER_INTERNAL_ERROR), + DATxx(DAT_SOFTWARE_EVENT) +# undef DATxx + }; +# define NUM_ERRORS (sizeof (dat_errors)/sizeof (dat_errors[0])) + + for (i = 0; i < NUM_ERRORS; i++) { + if (dat_errors[i].value == error_code) { + return (dat_errors[i].name); + } + } + + return ("Invalid_DAT_EVENT_NUMBER"); +} + +/* + * Map DAT_EVENT_CODE values to readable strings + */ +const char *DT_EventToSTr(DAT_EVENT_NUMBER event_code) +{ + unsigned int i; + static struct { + const char *name; + DAT_RETURN value; + } dat_events[] = { +# define DATxx(x) { # x, x } + DATxx(DAT_DTO_COMPLETION_EVENT), + DATxx(DAT_RMR_BIND_COMPLETION_EVENT), + DATxx(DAT_CONNECTION_REQUEST_EVENT), + DATxx(DAT_CONNECTION_EVENT_ESTABLISHED), + DATxx(DAT_CONNECTION_EVENT_PEER_REJECTED), + DATxx(DAT_CONNECTION_EVENT_NON_PEER_REJECTED), + DATxx(DAT_CONNECTION_EVENT_ACCEPT_COMPLETION_ERROR), + DATxx(DAT_CONNECTION_EVENT_DISCONNECTED), + DATxx(DAT_CONNECTION_EVENT_BROKEN), + DATxx(DAT_CONNECTION_EVENT_TIMED_OUT), + DATxx(DAT_CONNECTION_EVENT_UNREACHABLE), + DATxx(DAT_ASYNC_ERROR_EVD_OVERFLOW), + DATxx(DAT_ASYNC_ERROR_IA_CATASTROPHIC), + DATxx(DAT_ASYNC_ERROR_EP_BROKEN), + DATxx(DAT_ASYNC_ERROR_TIMED_OUT), + DATxx(DAT_ASYNC_ERROR_PROVIDER_INTERNAL_ERROR), + DATxx(DAT_SOFTWARE_EVENT) +# undef DATxx + }; +# define NUM_EVENTS (sizeof (dat_events)/sizeof (dat_events[0])) + + for (i = 0; i < NUM_EVENTS; i++) { + if (dat_events[i].value == event_code) { + return (dat_events[i].name); + } + } + + return ("Invalid_DAT_EVENT_NUMBER"); +} + +/* + * Map DAT_EP_STATE_CODE values to readable strings + */ +const char *DT_State2Str(DAT_EP_STATE state_code) +{ + unsigned int i; + static struct { + const char *name; + DAT_RETURN value; + } dat_state[] = { +# define DATxx(x) { # x, x } + DATxx(DAT_EP_STATE_UNCONNECTED), + DATxx(DAT_EP_STATE_RESERVED), + DATxx(DAT_EP_STATE_PASSIVE_CONNECTION_PENDING), + DATxx(DAT_EP_STATE_ACTIVE_CONNECTION_PENDING), + DATxx(DAT_EP_STATE_TENTATIVE_CONNECTION_PENDING), + DATxx(DAT_EP_STATE_CONNECTED), + DATxx(DAT_EP_STATE_DISCONNECT_PENDING), + DATxx(DAT_EP_STATE_ERROR) +# undef DATxx + }; +# define NUM_STATES (sizeof (dat_state)/sizeof (dat_state[0])) + + for (i = 0; i < NUM_STATES; i++) { + if (dat_state[i].value == state_code) { + return (dat_state[i].name); + } + } + + return ("Invalid_DAT_STATE_NUMBER"); +} + +/* + * A couple of round-up routines (for pointers and counters) + * which both assume a power-of-two 'align' factor, + * and do the correct thing if align == 0. + */ +unsigned char *DT_AlignPtr(void *val, DAT_COUNT align) +{ + if (align) { +#if defined(_WIN64) + return ((unsigned char *) + (((uint64_t) val + ((uint64_t) align) - + 1) & ~(((uint64_t) align) - 1))); +#else + return ((unsigned char *) + (((unsigned long)val + ((unsigned long)align) - + 1) & ~(((unsigned long)align) - 1))); +#endif + } + return (val); +} + +DAT_COUNT DT_RoundSize(DAT_COUNT val, DAT_COUNT align) +{ + if (align) { + return (((val + align - 1) & ~(align - 1))); + } + return (val); +} diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/udapl/udapl_tdep.c b/branches/WOF2-3/ulp/dapl2/test/dapltest/udapl/udapl_tdep.c new file mode 100644 index 00000000..af5522cb --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/udapl/udapl_tdep.c @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * + * This Software is licensed under one of the following licenses: + * + * 1) under the terms of the "Common Public License 1.0" a copy of which is + * in the file LICENSE.txt in the root directory. The license is also + * available from the Open Source Initiative, see + * http://www.opensource.org/licenses/cpl.php. + * + * 2) under the terms of the "The BSD License" a copy of which is in the file + * LICENSE2.txt in the root directory. The license is also available from + * the Open Source Initiative, see + * http://www.opensource.org/licenses/bsd-license.php. + * + * 3) under the terms of the "GNU General Public License (GPL) Version 2" a + * copy of which is in the file LICENSE3.txt in the root directory. The + * license is also available from the Open Source Initiative, see + * http://www.opensource.org/licenses/gpl-license.php. + * + * Licensee has the right to choose one of the above licenses. + * + * Redistributions of source code must retain the above copyright + * notice and one of the license notices. + * + * Redistributions in binary form must reproduce both the above copyright + * notice, one of the license notices in the documentation + * and/or other materials provided with the distribution. + */ + +#include "dapl_proto.h" + +void DT_Tdep_Init(void) +{ + DT_Mdep_LockInit(&g_PerfTestLock); /* For kDAPL, this is done in kdapl_module.c */ +} + +void DT_Tdep_End(void) +{ + DT_Mdep_LockDestroy(&g_PerfTestLock); /* For kDAPL, this is done in kdapl_module.c */ +} + +DAT_RETURN DT_Tdep_Execute_Test(Params_t * params_ptr) +{ + return DT_Execute_Test(params_ptr); +} + +DAT_RETURN +DT_Tdep_lmr_create(DAT_IA_HANDLE ia_handle, + DAT_MEM_TYPE mem_type, + DAT_REGION_DESCRIPTION region, + DAT_VLEN len, + DAT_PZ_HANDLE pz_handle, + DAT_MEM_PRIV_FLAGS priv_flag, + DAT_LMR_HANDLE * lmr_handle_ptr, + DAT_LMR_CONTEXT * lmr_context_ptr, + DAT_RMR_CONTEXT * rmr_context_ptr, + DAT_VLEN * reg_size_ptr, DAT_VADDR * reg_addr_ptr) +{ + return dat_lmr_create(ia_handle, + mem_type, + region, + len, + pz_handle, + priv_flag, + DAT_VA_TYPE_VA, + lmr_handle_ptr, + lmr_context_ptr, + rmr_context_ptr, reg_size_ptr, reg_addr_ptr); +} + +DAT_RETURN +DT_Tdep_evd_create(DAT_IA_HANDLE ia_handle, + DAT_COUNT evd_min_qlen, + DAT_CNO_HANDLE cno_handle, + DAT_EVD_FLAGS evd_flags, DAT_EVD_HANDLE * evd_handle_ptr) +{ + return dat_evd_create(ia_handle, + evd_min_qlen, + DAT_HANDLE_NULL, evd_flags, evd_handle_ptr); +} + +DAT_RETURN DT_Tdep_evd_free(DAT_EVD_HANDLE evd_handle) +{ + return dat_evd_free(evd_handle); +} + +DAT_RETURN +DT_Tdep_evd_wait(DAT_EVD_HANDLE evd_handle, + DAT_TIMEOUT timeout, DAT_EVENT * event) +{ + DAT_COUNT count; + + return dat_evd_wait(evd_handle, timeout, 1, event, &count); +} + +void DT_Tdep_PT_Printf(DT_Tdep_Print_Head * phead, const char *fmt, ...) +{ + char buffer[256]; + va_list args; + + va_start(args, fmt); + vsprintf(buffer, fmt, args); + va_end(args); + + printf(buffer); +} + +DAT_RETURN DT_Tdep_evd_dequeue(DAT_EVD_HANDLE evd_handle, DAT_EVENT * event) +{ + return dat_evd_dequeue(evd_handle, event); +} diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/windows/SOURCES b/branches/WOF2-3/ulp/dapl2/test/dapltest/windows/SOURCES new file mode 100644 index 00000000..9aee05b0 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/windows/SOURCES @@ -0,0 +1,33 @@ +!if $(FREEBUILD) +TARGETNAME = dapl2test +!else +TARGETNAME = dapl2testd +!endif + +TARGETPATH = ..\..\..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = PROGRAM +UMTYPE = console +USE_MSVCRT = 1 + +SOURCES = \ + dapltest.rc \ + ..\dt_cmd.c \ + ..\dt_test.c \ + ..\dt_common.c \ + ..\dt_udapl.c \ + ..\dt_mdep.c + +INCLUDES=..\include;..\mdep\windows;..\..\..\dat\include;%DDK_INC_PATH% + +RCOPTIONS=/I..\..\..\..\..\inc; + +!if $(FREEBUILD) +DATLIB = dat2.lib +!else +DATLIB = dat2d.lib +!endif + +TARGETLIBS = $(TARGETPATH)\*\$(DATLIB) $(SDK_LIB_PATH)\ws2_32.lib + +# XXX do this ASAP - MSC_WARNING_LEVEL= /W3 +MSC_WARNING_LEVEL= /W1 diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/windows/dapltest.rc b/branches/WOF2-3/ulp/dapl2/test/dapltest/windows/dapltest.rc new file mode 100644 index 00000000..09fef620 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/windows/dapltest.rc @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2007 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#if DBG +#define VER_FILEDESCRIPTION_STR "DAPL/DAT[2.0] test Application (Debug)" +#define VER_INTERNALNAME_STR "dapl2testd.exe" +#define VER_ORIGINALFILENAME_STR "dapl2testd.exe" + +#else +#define VER_FILEDESCRIPTION_STR "DAPL/DAT[2.0] test Application" +#define VER_INTERNALNAME_STR "dapl2test.exe" +#define VER_ORIGINALFILENAME_STR "dapl2test.exe" + +#endif + +#include diff --git a/branches/WOF2-3/ulp/dapl2/test/dapltest/windows/makefile b/branches/WOF2-3/ulp/dapl2/test/dapltest/windows/makefile new file mode 100644 index 00000000..b931d6c8 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dapltest/windows/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\..\..\inc\openib.def diff --git a/branches/WOF2-3/ulp/dapl2/test/dirs b/branches/WOF2-3/ulp/dapl2/test/dirs new file mode 100644 index 00000000..5317dfbe --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dirs @@ -0,0 +1 @@ +DIRS = dapltest dtest diff --git a/branches/WOF2-3/ulp/dapl2/test/dtest/Makefile.am b/branches/WOF2-3/ulp/dapl2/test/dtest/Makefile.am new file mode 100644 index 00000000..801d704c --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dtest/Makefile.am @@ -0,0 +1,18 @@ +bin_PROGRAMS = dtest dtestcm +dtest_SOURCES = dtest.c +dtest_CFLAGS = -g -Wall -D_GNU_SOURCE + +dtestcm_SOURCES = dtestcm.c +dtestcm_CFLAGS = -g -Wall -D_GNU_SOURCE + +if EXT_TYPE_IB +bin_PROGRAMS += dtestx +dtestx_SOURCES = dtestx.c +dtestx_CFLAGS = -g -Wall -D_GNU_SOURCE -DDAT_EXTENSIONS +dtestx_LDADD = $(top_builddir)/dat/udat/libdat2.la +endif + +INCLUDES = -I $(srcdir)/../../dat/include +dtest_LDADD = $(top_builddir)/dat/udat/libdat2.la +dtestcm_LDADD = $(top_builddir)/dat/udat/libdat2.la + diff --git a/branches/WOF2-3/ulp/dapl2/test/dtest/README b/branches/WOF2-3/ulp/dapl2/test/dtest/README new file mode 100644 index 00000000..34eeeb95 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dtest/README @@ -0,0 +1,19 @@ +simple dapl test just for initial openIB uDAPL testing... + + dtest/dtest.c + dtest/makefile + dtest/dat.conf + +to build (default uDAPL name == IB1, ib device == mthca0, port == 1) + edit makefile and change path (DAT_LIB) to appropriate libdat.so + edit dat.conf and change path to appropriate libdapl.so + cp dat.conf to /etc/dat.conf + +to run: + server: dtest + client: dtest -h hostname + +for verbose uDAPL and uDAT debug: + + export DAPL_DBG_TYPE=0xffff + export DAT_DBG_TYPE=0xffff diff --git a/branches/WOF2-3/ulp/dapl2/test/dtest/configure.in b/branches/WOF2-3/ulp/dapl2/test/dtest/configure.in new file mode 100644 index 00000000..2fca0577 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dtest/configure.in @@ -0,0 +1,21 @@ +dnl Process this file with autoconf to produce a configure script. + +AC_PREREQ(2.57) +AC_INIT(dtest, 2.0 dapl-devel@lists.sourceforge.net) +AC_CONFIG_SRCDIR([$top_srcdir/dapl/test/dtest/dtest.c]) +AC_CONFIG_AUX_DIR(config) +AM_CONFIG_HEADER(config.h) +AM_INIT_AUTOMAKE(dtest, 2.0) + +AM_PROG_LIBTOOL + +dnl Checks for programs +AC_PROG_CC + +dnl Checks for libraries + +dnl Checks for header files. + +AC_CONFIG_FILES([Makefile]) + +AC_OUTPUT diff --git a/branches/WOF2-3/ulp/dapl2/test/dtest/dirs b/branches/WOF2-3/ulp/dapl2/test/dtest/dirs new file mode 100644 index 00000000..a348bea3 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dtest/dirs @@ -0,0 +1 @@ +dirs = windows diff --git a/branches/WOF2-3/ulp/dapl2/test/dtest/dtc.bat b/branches/WOF2-3/ulp/dapl2/test/dtest/dtc.bat new file mode 100644 index 00000000..7c2c0fce --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dtest/dtc.bat @@ -0,0 +1,42 @@ +@echo off +rem +rem Sample dtest2 client invocation - usage: dtc {hostname} +rem + +SETLOCAL + +rem socket CM testing +rem set DAT_OVERRIDE=C:\dapl2\dat.conf +rem set P=ibnic0v2_scm +rem set DT=dtest2.exe + +rem IBAL CM testing +rem set DAT_OVERRIDE=C:\dapl2\dat.conf +rem set P=ibnic0v2 +rem set DT=dtest2.exe +rem set X=0xfffff + +set X= + +if not "%X%" == "" ( + set DAT_DBG_LEVEL=%X% + set DAT_DBG_TYPE=%X% + set DAT_OS_DBG_TYPE=%X% + set DAPL_DBG_TYPE=%X% +) + +IF "%1" == "" ( + set H=10.10.4.201 +) ELSE ( + set H=%1 +) + +echo %DT% -P %P% -h %H% + +%DT% -P %P% -h %H% + +echo %0 - dtest client exit... + +ENDLOCAL + +@echo on diff --git a/branches/WOF2-3/ulp/dapl2/test/dtest/dtest.c b/branches/WOF2-3/ulp/dapl2/test/dtest/dtest.c new file mode 100644 index 00000000..d43a09b3 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dtest/dtest.c @@ -0,0 +1,2107 @@ +/* + * Copyright (c) 2005-2008 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: $ + */ +#include +#include +#include + +#ifdef DAPL_PROVIDER +#undef DAPL_PROVIDER +#endif + +#if defined(_WIN32) || defined(_WIN64) + +#include +#include +#include +#include +#include +#include +#include "..\..\..\..\etc\user\getopt.c" + +#define getpid() ((int)GetCurrentProcessId()) +#define F64x "%I64x" + +#ifdef DBG +#define DAPL_PROVIDER "ibnic0v2d" +#else +#define DAPL_PROVIDER "ibnic0v2" +#endif + +#define ntohll _byteswap_uint64 +#define htonll _byteswap_uint64 + +#else // _WIN32 || _WIN64 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DAPL_PROVIDER "ofa-v2-ib0" + +#define F64x "%"PRIx64"" + +#if __BYTE_ORDER == __BIG_ENDIAN +#define htonll(x) (x) +#define ntohll(x) (x) +#elif __BYTE_ORDER == __LITTLE_ENDIAN +#define htonll(x) bswap_64(x) +#define ntohll(x) bswap_64(x) +#endif + +#endif // _WIN32 || _WIN64 + +/* Debug: 1 == connect & close only, otherwise full-meal deal */ +#define CONNECT_ONLY 0 + +#define MAX_POLLING_CNT 50000 +#define MAX_RDMA_RD 4 +#define MAX_PROCS 1000 + +/* Header files needed for DAT/uDAPL */ +#include "dat2/udat.h" + +/* definitions */ +#define SERVER_CONN_QUAL 45248 +#define DTO_TIMEOUT (1000*1000*5) +#define CNO_TIMEOUT (1000*1000*1) +#define DTO_FLUSH_TIMEOUT (1000*1000*2) +#define CONN_TIMEOUT (1000*1000*100) +#define SERVER_TIMEOUT DAT_TIMEOUT_INFINITE +#define RDMA_BUFFER_SIZE (64) + +/* Global DAT vars */ +static DAT_IA_HANDLE h_ia = DAT_HANDLE_NULL; +static DAT_PZ_HANDLE h_pz = DAT_HANDLE_NULL; +static DAT_EP_HANDLE h_ep = DAT_HANDLE_NULL; +static DAT_PSP_HANDLE h_psp = DAT_HANDLE_NULL; +static DAT_CR_HANDLE h_cr = DAT_HANDLE_NULL; + +static DAT_EVD_HANDLE h_async_evd = DAT_HANDLE_NULL; +static DAT_EVD_HANDLE h_dto_req_evd = DAT_HANDLE_NULL; +static DAT_EVD_HANDLE h_dto_rcv_evd = DAT_HANDLE_NULL; +static DAT_EVD_HANDLE h_cr_evd = DAT_HANDLE_NULL; +static DAT_EVD_HANDLE h_conn_evd = DAT_HANDLE_NULL; +static DAT_CNO_HANDLE h_dto_cno = DAT_HANDLE_NULL; + +/* RDMA buffers */ +static DAT_LMR_HANDLE h_lmr_send = DAT_HANDLE_NULL; +static DAT_LMR_HANDLE h_lmr_recv = DAT_HANDLE_NULL; +static DAT_LMR_CONTEXT lmr_context_send; +static DAT_LMR_CONTEXT lmr_context_recv; +static DAT_RMR_CONTEXT rmr_context_send; +static DAT_RMR_CONTEXT rmr_context_recv; +static DAT_VLEN registered_size_send; +static DAT_VLEN registered_size_recv; +static DAT_VADDR registered_addr_send; +static DAT_VADDR registered_addr_recv; + +/* Initial msg receive buf, RMR exchange, and Rdma-write notification */ +#define MSG_BUF_COUNT 3 +#define MSG_IOV_COUNT 2 +static DAT_RMR_TRIPLET rmr_recv_msg[MSG_BUF_COUNT]; +static DAT_LMR_HANDLE h_lmr_recv_msg = DAT_HANDLE_NULL; +static DAT_LMR_CONTEXT lmr_context_recv_msg; +static DAT_RMR_CONTEXT rmr_context_recv_msg; +static DAT_VLEN registered_size_recv_msg; +static DAT_VADDR registered_addr_recv_msg; + +/* message send buffer */ +static DAT_RMR_TRIPLET rmr_send_msg; +static DAT_LMR_HANDLE h_lmr_send_msg = DAT_HANDLE_NULL; +static DAT_LMR_CONTEXT lmr_context_send_msg; +static DAT_RMR_CONTEXT rmr_context_send_msg; +static DAT_VLEN registered_size_send_msg; +static DAT_VADDR registered_addr_send_msg; +static DAT_EP_ATTR ep_attr; +char hostname[256] = { 0 }; +char provider[64] = DAPL_PROVIDER; +char addr_str[INET_ADDRSTRLEN]; + +/* rdma pointers */ +char *rbuf = NULL; +char *sbuf = NULL; +int status; + +/* timers */ +double start, stop, total_us, total_sec; + +struct dt_time { + double total; + double open; + double reg; + double unreg; + double pzc; + double pzf; + double evdc; + double evdf; + double cnoc; + double cnof; + double epc; + double epf; + double rdma_wr; + double rdma_rd[MAX_RDMA_RD]; + double rdma_rd_total; + double rtt; + double close; + double conn; +}; + +struct dt_time ts; + +/* defaults */ +static int failed = 0; +static int performance_times = 0; +static int connected = 0; +static int burst = 10; +static int server = 1; +static int verbose = 0; +static int polling = 0; +static int poll_count = 0; +static int rdma_wr_poll_count = 0; +static int conn_poll_count = 0; +static int rdma_rd_poll_count[MAX_RDMA_RD] = { 0 }; +static int delay = 0; +static int buf_len = RDMA_BUFFER_SIZE; +static int use_cno = 0; +static int recv_msg_index = 0; +static int burst_msg_posted = 0; +static int burst_msg_index = 0; +static int ucm = 0; +static DAT_SOCK_ADDR6 remote; + +/* forward prototypes */ +const char *DT_RetToStr(DAT_RETURN ret_value); +const char *DT_EventToStr(DAT_EVENT_NUMBER event_code); +void print_usage(void); +double get_time(void); +void init_data(void); + +DAT_RETURN send_msg(void *data, + DAT_COUNT size, + DAT_LMR_CONTEXT context, + DAT_DTO_COOKIE cookie, DAT_COMPLETION_FLAGS flags); + +DAT_RETURN connect_ep(char *hostname, DAT_CONN_QUAL conn_id); +void disconnect_ep(void); +DAT_RETURN register_rdma_memory(void); +DAT_RETURN unregister_rdma_memory(void); +DAT_RETURN create_events(void); +DAT_RETURN destroy_events(void); +DAT_RETURN do_rdma_write_with_msg(void); +DAT_RETURN do_rdma_read_with_msg(void); +DAT_RETURN do_ping_pong_msg(void); + +#define LOGPRINTF if (verbose) printf + +void flush_evds(void) +{ + DAT_EVENT event; + + /* Flush async error queue */ + printf("%d ERR: Checking ASYNC EVD...\n", getpid()); + while (dat_evd_dequeue(h_async_evd, &event) == DAT_SUCCESS) { + printf(" ASYNC EVD ENTRY: handle=%p reason=%d\n", + event.event_data.asynch_error_event_data.dat_handle, + event.event_data.asynch_error_event_data.reason); + } + /* Flush receive queue */ + printf("%d ERR: Checking RECEIVE EVD...\n", getpid()); + while (dat_evd_dequeue(h_dto_rcv_evd, &event) == DAT_SUCCESS) { + printf(" RCV EVD ENTRY: op=%d stat=%d ln=%d ck="F64x"\n", + event.event_data.dto_completion_event_data.operation, + event.event_data.dto_completion_event_data.status, + event.event_data.dto_completion_event_data.transfered_length, + event.event_data.dto_completion_event_data.user_cookie.as_64); + } + /* Flush request queue */ + printf("%d ERR: Checking REQUEST EVD...\n", getpid()); + while (dat_evd_dequeue(h_dto_req_evd, &event) == DAT_SUCCESS) { + printf(" REQ EVD ENTRY: op=%d stat=%d ln=%d ck="F64x"\n", + event.event_data.dto_completion_event_data.operation, + event.event_data.dto_completion_event_data.status, + event.event_data.dto_completion_event_data.transfered_length, + event.event_data.dto_completion_event_data.user_cookie.as_64); + } +} + + +static inline DAT_RETURN +collect_event(DAT_EVD_HANDLE dto_evd, + DAT_EVENT *event, + DAT_TIMEOUT timeout, + int *counter) +{ + DAT_EVD_HANDLE evd = DAT_HANDLE_NULL; + DAT_COUNT nmore; + DAT_RETURN ret = DAT_SUCCESS; + + if (use_cno) { +retry: + /* CNO wait could return EVD's in any order and + * may drop some EVD notification's if already + * triggered. Once woken, simply dequeue the + * Evd the caller wants to collect and return. + * If notification without EVD, retry. + */ + ret = dat_cno_wait(h_dto_cno, CNO_TIMEOUT, &evd); + if (dat_evd_dequeue(dto_evd, event) != DAT_SUCCESS) { + if (ret == DAT_SUCCESS) + printf(" WARNING: CNO notification:" + " without EVD?\n"); + goto retry; + } + ret = DAT_SUCCESS; /* cno timed out, but EVD dequeued */ + + } else if (!polling) { + + /* use wait to dequeue */ + ret = dat_evd_wait(dto_evd, timeout, 1, event, &nmore); + if (ret != DAT_SUCCESS) + fprintf(stderr, + "Error waiting on h_dto_evd %p: %s\n", + dto_evd, DT_RetToStr(ret)); + + } else { + while (dat_evd_dequeue(dto_evd, event) == DAT_QUEUE_EMPTY) + if (counter) + (*counter)++; + } + return (ret); +} + +static void print_ia_address(struct sockaddr *sa) +{ + char str[INET6_ADDRSTRLEN] = {" ??? "}; + + switch(sa->sa_family) { + case AF_INET: + inet_ntop(AF_INET, &((struct sockaddr_in *)sa)->sin_addr, str, INET6_ADDRSTRLEN); + printf("%d Local Address AF_INET - %s port %d\n", getpid(), str, SERVER_CONN_QUAL); + break; + case AF_INET6: + inet_ntop(AF_INET6, &((struct sockaddr_in6 *)sa)->sin6_addr, str, INET6_ADDRSTRLEN); + printf("%d Local Address AF_INET6 - %s flowinfo(QPN)=0x%x, port(LID)=0x%x\n", + getpid(), str, + ntohl(((struct sockaddr_in6 *)sa)->sin6_flowinfo), + ntohs(((struct sockaddr_in6 *)sa)->sin6_port)); + break; + default: + printf("%d Local Address UNKOWN FAMILY - port %d\n", getpid(), SERVER_CONN_QUAL); + } +} + +int main(int argc, char **argv) +{ + int i, c; + DAT_RETURN ret; + DAT_EP_PARAM ep_param; + DAT_IA_ATTR ia_attr; + + /* parse arguments */ + while ((c = getopt(argc, argv, "tscvpq:l:b:d:B:h:P:")) != -1) { + switch (c) { + case 't': + performance_times = 1; + fflush(stdout); + break; + case 's': + server = 1; + fflush(stdout); + break; + case 'c': + use_cno = 1; + printf("%d Creating CNO for DTO EVD's\n", getpid()); + fflush(stdout); + break; + case 'v': + verbose = 1; + printf("%d Verbose\n", getpid()); + fflush(stdout); + break; + case 'p': + polling = 1; + printf("%d Polling\n", getpid()); + fflush(stdout); + break; + case 'q': + /* map UCM qpn into AF_INET6 sin6_flowinfo */ + remote.sin6_family = AF_INET6; + remote.sin6_flowinfo = htonl(strtol(optarg,NULL,0)); + ucm = 1; + server = 0; + break; + case 'l': + /* map UCM lid into AF_INET6 sin6_port */ + remote.sin6_family = AF_INET6; + remote.sin6_port = htons(strtol(optarg,NULL,0)); + ucm = 1; + server = 0; + break; + case 'B': + burst = atoi(optarg); + break; + case 'd': + delay = atoi(optarg); + break; + case 'b': + buf_len = atoi(optarg); + break; + case 'h': + server = 0; + strcpy(hostname, optarg); + break; + case 'P': + strcpy(provider, optarg); + break; + default: + print_usage(); + exit(-12); + } + } + +#if defined(_WIN32) || defined(_WIN64) + { + WSADATA wsaData; + + i = WSAStartup(MAKEWORD(2, 2), &wsaData); + if (i != 0) { + printf("%s WSAStartup(2.2) failed? (0x%x)\n", argv[0], + i); + fflush(stdout); + exit(1); + } + } +#endif + + if (!server) { + printf("%d Running as client - %s\n", getpid(), provider); + } else { + printf("%d Running as server - %s\n", getpid(), provider); + } + fflush(stdout); + + /* allocate send and receive buffers */ + if (((rbuf = malloc(buf_len * (burst+1))) == NULL) || + ((sbuf = malloc(buf_len * (burst+1))) == NULL)) { + perror("malloc"); + exit(1); + } + memset(&ts, 0, sizeof(struct dt_time)); + LOGPRINTF("%d Allocated RDMA buffers (r:%p,s:%p) len %d \n", + getpid(), rbuf, sbuf, buf_len); + + /* dat_ia_open, dat_pz_create */ + h_async_evd = DAT_HANDLE_NULL; + start = get_time(); + ret = dat_ia_open(provider, 8, &h_async_evd, &h_ia); + stop = get_time(); + ts.open += ((stop - start) * 1.0e6); + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d: Error Adaptor open: %s\n", + getpid(), DT_RetToStr(ret)); + exit(1); + } else + LOGPRINTF("%d Opened Interface Adaptor\n", getpid()); + + ret = dat_ia_query(h_ia, 0, DAT_IA_FIELD_ALL, &ia_attr, 0, 0); + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d: Error Adaptor query: %s\n", + getpid(), DT_RetToStr(ret)); + exit(1); + } + print_ia_address(ia_attr.ia_address_ptr); + + /* Create Protection Zone */ + start = get_time(); + LOGPRINTF("%d Create Protection Zone\n", getpid()); + ret = dat_pz_create(h_ia, &h_pz); + stop = get_time(); + ts.pzc += ((stop - start) * 1.0e6); + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d Error creating Protection Zone: %s\n", + getpid(), DT_RetToStr(ret)); + exit(1); + } else + LOGPRINTF("%d Created Protection Zone\n", getpid()); + + /* Register memory */ + LOGPRINTF("%d Register RDMA memory\n", getpid()); + ret = register_rdma_memory(); + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d Error registering RDMA memory: %s\n", + getpid(), DT_RetToStr(ret)); + goto cleanup; + } else + LOGPRINTF("%d Register RDMA memory done\n", getpid()); + + LOGPRINTF("%d Create events\n", getpid()); + ret = create_events(); + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d Error creating events: %s\n", + getpid(), DT_RetToStr(ret)); + goto cleanup; + } else { + LOGPRINTF("%d Create events done\n", getpid()); + } + + /* create EP */ + memset(&ep_attr, 0, sizeof(ep_attr)); + ep_attr.service_type = DAT_SERVICE_TYPE_RC; + ep_attr.max_rdma_size = 0x10000; + ep_attr.qos = 0; + ep_attr.recv_completion_flags = 0; + ep_attr.max_recv_dtos = MSG_BUF_COUNT + (burst * 3); + ep_attr.max_request_dtos = MSG_BUF_COUNT + (burst * 3) + MAX_RDMA_RD; + ep_attr.max_recv_iov = MSG_IOV_COUNT; + ep_attr.max_request_iov = MSG_IOV_COUNT; + ep_attr.max_rdma_read_in = MAX_RDMA_RD; + ep_attr.max_rdma_read_out = MAX_RDMA_RD; + ep_attr.request_completion_flags = DAT_COMPLETION_DEFAULT_FLAG; + ep_attr.ep_transport_specific_count = 0; + ep_attr.ep_transport_specific = NULL; + ep_attr.ep_provider_specific_count = 0; + ep_attr.ep_provider_specific = NULL; + + start = get_time(); + ret = dat_ep_create(h_ia, h_pz, h_dto_rcv_evd, + h_dto_req_evd, h_conn_evd, &ep_attr, &h_ep); + stop = get_time(); + ts.epc += ((stop - start) * 1.0e6); + ts.total += ts.epc; + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d Error dat_ep_create: %s\n", + getpid(), DT_RetToStr(ret)); + goto cleanup; + } else + LOGPRINTF("%d EP created %p \n", getpid(), h_ep); + + /* + * register message buffers, establish connection, and + * exchange DMA RMR information info via messages + */ + ret = connect_ep(hostname, SERVER_CONN_QUAL); + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d Error connect_ep: %s\n", + getpid(), DT_RetToStr(ret)); + goto cleanup; + } else + LOGPRINTF("%d connect_ep complete\n", getpid()); + + /* Query EP for local and remote address information, print */ + ret = dat_ep_query(h_ep, DAT_EP_FIELD_ALL, &ep_param); + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d Error dat_ep_query: %s\n", + getpid(), DT_RetToStr(ret)); + goto cleanup; + } else + LOGPRINTF("%d EP queried %p \n", getpid(), h_ep); +#if defined(_WIN32) + printf("\n%d Query EP: LOCAL addr %s port %lld\n", getpid(), + inet_ntoa(((struct sockaddr_in *) + ep_param.local_ia_address_ptr)->sin_addr), + (ep_param.local_port_qual)); +#else + inet_ntop(AF_INET, + &((struct sockaddr_in *)ep_param.local_ia_address_ptr)-> + sin_addr, addr_str, sizeof(addr_str)); + printf("\n%d Query EP: LOCAL addr %s port " F64x "\n", getpid(), + addr_str, (ep_param.local_port_qual)); +#endif +#if defined(_WIN32) + printf("%d Query EP: REMOTE addr %s port %lld\n", getpid(), + inet_ntoa(((struct sockaddr_in *) + ep_param.local_ia_address_ptr)->sin_addr), + (ep_param.remote_port_qual)); +#else + inet_ntop(AF_INET, + &((struct sockaddr_in *)ep_param.remote_ia_address_ptr)-> + sin_addr, addr_str, sizeof(addr_str)); + printf("%d Query EP: REMOTE addr %s port " F64x "\n", getpid(), + addr_str, (ep_param.remote_port_qual)); +#endif + fflush(stdout); + +#if CONNECT_ONLY +#if defined(_WIN32) || defined(_WIN64) + Sleep(1 * 1000); +#else + sleep(1); +#endif + goto cleanup; +#endif + + /*********** RDMA write data *************/ + ret = do_rdma_write_with_msg(); + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d Error do_rdma_write_with_msg: %s\n", + getpid(), DT_RetToStr(ret)); + goto cleanup; + } else + LOGPRINTF("%d do_rdma_write_with_msg complete\n", getpid()); + + /*********** RDMA read data *************/ + ret = do_rdma_read_with_msg(); + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d Error do_rdma_read_with_msg: %s\n", + getpid(), DT_RetToStr(ret)); + goto cleanup; + } else + LOGPRINTF("%d do_rdma_read_with_msg complete\n", getpid()); + + /*********** PING PING messages ************/ + ret = do_ping_pong_msg(); + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d Error do_ping_pong_msg: %s\n", + getpid(), DT_RetToStr(ret)); + goto cleanup; + } else { + LOGPRINTF("%d do_ping_pong_msg complete\n", getpid()); + goto complete; + } + +cleanup: + flush_evds(); + failed++; +complete: + + /* disconnect and free EP resources */ + if (h_ep != DAT_HANDLE_NULL) { + /* unregister message buffers and tear down connection */ + LOGPRINTF("%d Disconnect and Free EP %p \n", getpid(), h_ep); + disconnect_ep(); + + /* free EP */ + LOGPRINTF("%d Free EP %p \n", getpid(), h_ep); + start = get_time(); + ret = dat_ep_free(h_ep); + stop = get_time(); + ts.epf += ((stop - start) * 1.0e6); + ts.total += ts.epf; + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d Error freeing EP: %s\n", + getpid(), DT_RetToStr(ret)); + } else { + LOGPRINTF("%d Freed EP\n", getpid()); + h_ep = DAT_HANDLE_NULL; + } + } + + /* free EVDs */ + LOGPRINTF("%d destroy events\n", getpid()); + ret = destroy_events(); + if (ret != DAT_SUCCESS) + fprintf(stderr, "%d Error destroy_events: %s\n", + getpid(), DT_RetToStr(ret)); + else + LOGPRINTF("%d destroy events done\n", getpid()); + + ret = unregister_rdma_memory(); + LOGPRINTF("%d unregister_rdma_memory \n", getpid()); + if (ret != DAT_SUCCESS) + fprintf(stderr, "%d Error unregister_rdma_memory: %s\n", + getpid(), DT_RetToStr(ret)); + else + LOGPRINTF("%d unregister_rdma_memory done\n", getpid()); + + /* Free protection domain */ + LOGPRINTF("%d Freeing pz\n", getpid()); + start = get_time(); + ret = dat_pz_free(h_pz); + stop = get_time(); + ts.pzf += ((stop - start) * 1.0e6); + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d Error freeing PZ: %s\n", + getpid(), DT_RetToStr(ret)); + } else { + LOGPRINTF("%d Freed pz\n", getpid()); + h_pz = NULL; + } + + /* close the device */ + LOGPRINTF("%d Closing Interface Adaptor\n", getpid()); + start = get_time(); + ret = dat_ia_close(h_ia, DAT_CLOSE_ABRUPT_FLAG); + stop = get_time(); + ts.close += ((stop - start) * 1.0e6); + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d: Error Adaptor close: %s\n", + getpid(), DT_RetToStr(ret)); + } else + LOGPRINTF("%d Closed Interface Adaptor\n", getpid()); + + /* free rdma buffers */ + free(rbuf); + free(sbuf); + + printf("\n%d: DAPL Test Complete. %s\n\n", + getpid(), failed ? "FAILED" : "PASSED"); + + fflush(stderr); + fflush(stdout); + + if (!performance_times) + exit(0); + + printf("\n%d: DAPL Test Complete.\n\n", getpid()); + printf("%d: Message RTT: Total=%10.2lf usec, %d bursts, itime=%10.2lf" + " usec, pc=%d\n", + getpid(), ts.rtt, burst, ts.rtt / burst, poll_count); + printf("%d: RDMA write: Total=%10.2lf usec, %d bursts, itime=%10.2lf" + " usec, pc=%d\n", + getpid(), ts.rdma_wr, burst, + ts.rdma_wr / burst, rdma_wr_poll_count); + for (i = 0; i < MAX_RDMA_RD; i++) { + printf("%d: RDMA read: Total=%10.2lf usec, %d bursts, " + "itime=%10.2lf usec, pc=%d\n", + getpid(), ts.rdma_rd_total, MAX_RDMA_RD, + ts.rdma_rd[i], rdma_rd_poll_count[i]); + } + printf("%d: open: %10.2lf usec\n", getpid(), ts.open); + printf("%d: close: %10.2lf usec\n", getpid(), ts.close); + printf("%d: PZ create: %10.2lf usec\n", getpid(), ts.pzc); + printf("%d: PZ free: %10.2lf usec\n", getpid(), ts.pzf); + printf("%d: LMR create:%10.2lf usec\n", getpid(), ts.reg); + printf("%d: LMR free: %10.2lf usec\n", getpid(), ts.unreg); + printf("%d: EVD create:%10.2lf usec\n", getpid(), ts.evdc); + printf("%d: EVD free: %10.2lf usec\n", getpid(), ts.evdf); + if (use_cno) { + printf("%d: CNO create: %10.2lf usec\n", getpid(), ts.cnoc); + printf("%d: CNO free: %10.2lf usec\n", getpid(), ts.cnof); + } + printf("%d: EP create: %10.2lf usec\n", getpid(), ts.epc); + printf("%d: EP free: %10.2lf usec\n", getpid(), ts.epf); + if (!server) + printf("%d: connect: %10.2lf usec, poll_cnt=%d\n", + getpid(), ts.conn, conn_poll_count); + printf("%d: TOTAL: %10.2lf usec\n", getpid(), ts.total); + +#if defined(_WIN32) || defined(_WIN64) + WSACleanup(); +#endif + return (0); +} + +double get_time(void) +{ + struct timeval tp; + + gettimeofday(&tp, NULL); + return ((double)tp.tv_sec + (double)tp.tv_usec * 1e-6); +} + +void init_data(void) +{ + memset(rbuf, 'a', buf_len); + memset(sbuf, 'b', buf_len); +} + +DAT_RETURN +send_msg(void *data, + DAT_COUNT size, + DAT_LMR_CONTEXT context, + DAT_DTO_COOKIE cookie, DAT_COMPLETION_FLAGS flags) +{ + DAT_LMR_TRIPLET iov; + DAT_EVENT event; + DAT_RETURN ret; + + iov.lmr_context = context; +#if defined(_WIN32) + iov.virtual_address = (DAT_VADDR) data; +#else + iov.virtual_address = (DAT_VADDR) (unsigned long)data; +#endif + iov.segment_length = size; + + LOGPRINTF("%d calling post_send\n", getpid()); + cookie.as_64 = 0xaaaa; + ret = dat_ep_post_send(h_ep, 1, &iov, cookie, flags); + + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d: ERROR: dat_ep_post_send() %s\n", + getpid(), DT_RetToStr(ret)); + return ret; + } + + if (!(flags & DAT_COMPLETION_SUPPRESS_FLAG)) { + + if (collect_event(h_dto_req_evd, + &event, + DTO_TIMEOUT, + &poll_count) != DAT_SUCCESS) + return (DAT_ABORT); + + /* validate event number, len, cookie, and status */ + if (event.event_number != DAT_DTO_COMPLETION_EVENT) { + fprintf(stderr, "%d: ERROR: DTO event number %s\n", + getpid(), + DT_EventToStr(event.event_number)); + return (DAT_ABORT); + } + + if ((event.event_data.dto_completion_event_data. + transfered_length != size) + || (event.event_data.dto_completion_event_data.user_cookie. + as_64 != 0xaaaa)) { + fprintf(stderr, + "%d: ERROR: DTO len %d or cookie " F64x " \n", + getpid(), + event.event_data.dto_completion_event_data. + transfered_length, + event.event_data.dto_completion_event_data. + user_cookie.as_64); + return (DAT_ABORT); + + } + if (event.event_data.dto_completion_event_data.status != + DAT_SUCCESS) { + fprintf(stderr, "%d: ERROR: DTO event status %s\n", + getpid(), DT_RetToStr(ret)); + return (DAT_ABORT); + } + } + + return DAT_SUCCESS; +} + +DAT_RETURN connect_ep(char *hostname, DAT_CONN_QUAL conn_id) +{ + DAT_IA_ADDRESS_PTR remote_addr = (DAT_IA_ADDRESS_PTR)&remote; + DAT_RETURN ret; + DAT_REGION_DESCRIPTION region; + DAT_EVENT event; + DAT_COUNT nmore; + DAT_LMR_TRIPLET l_iov; + DAT_RMR_TRIPLET r_iov; + DAT_DTO_COOKIE cookie; + int i; + unsigned char *buf; + DAT_CR_PARAM cr_param = { 0 }; + unsigned char pdata[48] = { 0 }; + + /* Register send message buffer */ + LOGPRINTF("%d Registering send Message Buffer %p, len %d\n", + getpid(), &rmr_send_msg, (int)sizeof(DAT_RMR_TRIPLET)); + region.for_va = &rmr_send_msg; + ret = dat_lmr_create(h_ia, + DAT_MEM_TYPE_VIRTUAL, + region, + sizeof(DAT_RMR_TRIPLET), + h_pz, + DAT_MEM_PRIV_LOCAL_WRITE_FLAG, + DAT_VA_TYPE_VA, + &h_lmr_send_msg, + &lmr_context_send_msg, + &rmr_context_send_msg, + ®istered_size_send_msg, + ®istered_addr_send_msg); + + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d Error registering send msg buffer: %s\n", + getpid(), DT_RetToStr(ret)); + return (ret); + } else + LOGPRINTF("%d Registered send Message Buffer %p \n", + getpid(), region.for_va); + + /* Register Receive buffers */ + LOGPRINTF("%d Registering Receive Message Buffer %p\n", + getpid(), rmr_recv_msg); + region.for_va = rmr_recv_msg; + ret = dat_lmr_create(h_ia, + DAT_MEM_TYPE_VIRTUAL, + region, + sizeof(DAT_RMR_TRIPLET) * MSG_BUF_COUNT, + h_pz, + DAT_MEM_PRIV_LOCAL_WRITE_FLAG, + DAT_VA_TYPE_VA, + &h_lmr_recv_msg, + &lmr_context_recv_msg, + &rmr_context_recv_msg, + ®istered_size_recv_msg, + ®istered_addr_recv_msg); + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d Error registering recv msg buffer: %s\n", + getpid(), DT_RetToStr(ret)); + return (ret); + } else + LOGPRINTF("%d Registered Receive Message Buffer %p\n", + getpid(), region.for_va); + + for (i = 0; i < MSG_BUF_COUNT; i++) { + cookie.as_64 = i; + l_iov.lmr_context = lmr_context_recv_msg; +#if defined(_WIN32) + l_iov.virtual_address = (DAT_VADDR) & rmr_recv_msg[i]; +#else + l_iov.virtual_address = + (DAT_VADDR) (unsigned long)&rmr_recv_msg[i]; +#endif + l_iov.segment_length = sizeof(DAT_RMR_TRIPLET); + + LOGPRINTF("%d Posting Receive Message Buffer %p\n", + getpid(), &rmr_recv_msg[i]); + ret = dat_ep_post_recv(h_ep, + 1, + &l_iov, + cookie, DAT_COMPLETION_DEFAULT_FLAG); + + if (ret != DAT_SUCCESS) { + fprintf(stderr, + "%d Error registering recv msg buffer: %s\n", + getpid(), DT_RetToStr(ret)); + return (ret); + } else + LOGPRINTF("%d Registered Receive Message Buffer %p\n", + getpid(), region.for_va); + + } + + /* setup receive rdma buffer to initial string to be overwritten */ + strcpy((char *)rbuf, "blah, blah, blah\n"); + + /* clear event structure */ + memset(&event, 0, sizeof(DAT_EVENT)); + + if (server) { /* SERVER */ + + /* create the service point for server listen */ + LOGPRINTF("%d Creating service point for listen\n", getpid()); + ret = dat_psp_create(h_ia, + conn_id, + h_cr_evd, DAT_PSP_CONSUMER_FLAG, &h_psp); + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d Error dat_psp_create: %s\n", + getpid(), DT_RetToStr(ret)); + return (ret); + } else + LOGPRINTF("%d dat_psp_created for server listen\n", + getpid()); + + printf("%d Server waiting for connect request on port " F64x + "\n", getpid(), conn_id); + + ret = dat_evd_wait(h_cr_evd, SERVER_TIMEOUT, 1, &event, &nmore); + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d Error dat_evd_wait: %s\n", + getpid(), DT_RetToStr(ret)); + return (ret); + } else + LOGPRINTF("%d dat_evd_wait for cr_evd completed\n", + getpid()); + + if (event.event_number != DAT_CONNECTION_REQUEST_EVENT) { + fprintf(stderr, "%d Error unexpected cr event : %s\n", + getpid(), + DT_EventToStr(event.event_number)); + return (DAT_ABORT); + } + if ((event.event_data.cr_arrival_event_data.conn_qual != + SERVER_CONN_QUAL) + || (event.event_data.cr_arrival_event_data.sp_handle. + psp_handle != h_psp)) { + fprintf(stderr, "%d Error wrong cr event data : %s\n", + getpid(), + DT_EventToStr(event.event_number)); + return (DAT_ABORT); + } + + /* use to test rdma_cma timeout logic */ +#if defined(_WIN32) || defined(_WIN64) + if (delay) + Sleep(delay * 1000); +#else + if (delay) + sleep(delay); +#endif + + /* accept connect request from client */ + h_cr = event.event_data.cr_arrival_event_data.cr_handle; + LOGPRINTF("%d Accepting connect request from client\n", + getpid()); + + /* private data - check and send it back */ + dat_cr_query(h_cr, DAT_CSP_FIELD_ALL, &cr_param); + + buf = (unsigned char *)cr_param.private_data; + LOGPRINTF("%d CONN REQUEST Private Data %p[0]=%d [47]=%d\n", + getpid(), buf, buf[0], buf[47]); + for (i = 0; i < 48; i++) { + if (buf[i] != i + 1) { + fprintf(stderr, "%d Error with CONNECT REQUEST" + " private data: %p[%d]=%d s/be %d\n", + getpid(), buf, i, buf[i], i + 1); + dat_cr_reject(h_cr, 0, NULL); + return (DAT_ABORT); + } + buf[i]++; /* change for trip back */ + } + +#ifdef TEST_REJECT_WITH_PRIVATE_DATA + printf("%d REJECT request with 48 bytes of private data\n", + getpid()); + ret = dat_cr_reject(h_cr, 48, cr_param.private_data); + printf("\n%d: DAPL Test Complete. %s\n\n", + getpid(), ret ? "FAILED" : "PASSED"); + exit(0); +#endif + + ret = dat_cr_accept(h_cr, h_ep, 48, cr_param.private_data); + + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d Error dat_cr_accept: %s\n", + getpid(), DT_RetToStr(ret)); + return (ret); + } else + LOGPRINTF("%d dat_cr_accept completed\n", getpid()); + } else { /* CLIENT */ + struct addrinfo *target; + int rval; + + if (ucm) + goto no_resolution; + +#if defined(_WIN32) || defined(_WIN64) + if ((rval = getaddrinfo(hostname, "ftp", NULL, &target)) != 0) { + printf("\n remote name resolution failed! %s\n", + gai_strerror(rval)); + exit(1); + } + rval = ((struct sockaddr_in *)target->ai_addr)->sin_addr.s_addr; +#else + if (getaddrinfo(hostname, NULL, NULL, &target) != 0) { + perror("\n remote name resolution failed!"); + exit(1); + } + rval = ((struct sockaddr_in *)target->ai_addr)->sin_addr.s_addr; +#endif + printf("%d Server Name: %s \n", getpid(), hostname); + printf("%d Server Net Address: %d.%d.%d.%d port " F64x "\n", + getpid(), (rval >> 0) & 0xff, (rval >> 8) & 0xff, + (rval >> 16) & 0xff, (rval >> 24) & 0xff, conn_id); + + remote_addr = (DAT_IA_ADDRESS_PTR)target->ai_addr; /* IP */ +no_resolution: + for (i = 0; i < 48; i++) /* simple pattern in private data */ + pdata[i] = i + 1; + + LOGPRINTF("%d Connecting to server\n", getpid()); + start = get_time(); + ret = dat_ep_connect(h_ep, + remote_addr, + conn_id, + CONN_TIMEOUT, + 48, + (DAT_PVOID) pdata, + 0, DAT_CONNECT_DEFAULT_FLAG); + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d Error dat_ep_connect: %s\n", + getpid(), DT_RetToStr(ret)); + return (ret); + } else + LOGPRINTF("%d dat_ep_connect completed\n", getpid()); + + if (!ucm) + freeaddrinfo(target); + } + + printf("%d Waiting for connect response\n", getpid()); + + if (polling) + while (DAT_GET_TYPE(dat_evd_dequeue(h_conn_evd, &event)) == + DAT_QUEUE_EMPTY) + conn_poll_count++; + else + ret = dat_evd_wait(h_conn_evd, DAT_TIMEOUT_INFINITE, + 1, &event, &nmore); + + if (!server) { + stop = get_time(); + ts.conn += ((stop - start) * 1.0e6); + } + +#ifdef TEST_REJECT_WITH_PRIVATE_DATA + if (event.event_number != DAT_CONNECTION_EVENT_PEER_REJECTED) { + fprintf(stderr, "%d expected conn reject event : %s\n", + getpid(), DT_EventToStr(event.event_number)); + return (DAT_ABORT); + } + /* get the reject private data and validate */ + buf = (unsigned char *)event.event_data.connect_event_data.private_data; + printf("%d Received REJECT with private data %p[0]=%d [47]=%d\n", + getpid(), buf, buf[0], buf[47]); + for (i = 0; i < 48; i++) { + if (buf[i] != i + 2) { + fprintf(stderr, "%d client: Error with REJECT event" + " private data: %p[%d]=%d s/be %d\n", + getpid(), buf, i, buf[i], i + 2); + dat_ep_disconnect(h_ep, DAT_CLOSE_ABRUPT_FLAG); + return (DAT_ABORT); + } + } + printf("\n%d: DAPL Test Complete. PASSED\n\n", getpid()); + exit(0); +#endif + + if (event.event_number != DAT_CONNECTION_EVENT_ESTABLISHED) { + fprintf(stderr, "%d Error unexpected conn event : 0x%x %s\n", + getpid(), event.event_number, + DT_EventToStr(event.event_number)); + return (DAT_ABORT); + } + + /* check private data back from server */ + if (!server) { + buf = + (unsigned char *)event.event_data.connect_event_data. + private_data; + LOGPRINTF("%d CONN Private Data %p[0]=%d [47]=%d\n", getpid(), + buf, buf[0], buf[47]); + for (i = 0; i < 48; i++) { + if (buf[i] != i + 2) { + fprintf(stderr, "%d Error with CONNECT event" + " private data: %p[%d]=%d s/be %d\n", + getpid(), buf, i, buf[i], i + 2); + dat_ep_disconnect(h_ep, DAT_CLOSE_ABRUPT_FLAG); + LOGPRINTF + ("%d waiting for disconnect event...\n", + getpid()); + dat_evd_wait(h_conn_evd, DAT_TIMEOUT_INFINITE, + 1, &event, &nmore); + return (DAT_ABORT); + } + } + } + + printf("\n%d CONNECTED!\n\n", getpid()); + connected = 1; + +#if CONNECT_ONLY + return 0; +#endif + + /* + * Setup our remote memory and tell the other side about it + */ + rmr_send_msg.virtual_address = htonll((DAT_VADDR) (uintptr_t) rbuf); + rmr_send_msg.segment_length = htonl(RDMA_BUFFER_SIZE); + rmr_send_msg.rmr_context = htonl(rmr_context_recv); + + printf("%d Send RMR msg to remote: r_key_ctx=0x%x,va=%p,len=0x%x\n", + getpid(), rmr_context_recv, rbuf, RDMA_BUFFER_SIZE); + + ret = send_msg(&rmr_send_msg, + sizeof(DAT_RMR_TRIPLET), + lmr_context_send_msg, + cookie, DAT_COMPLETION_SUPPRESS_FLAG); + + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d Error send_msg: %s\n", + getpid(), DT_RetToStr(ret)); + return (ret); + } else + LOGPRINTF("%d send_msg completed\n", getpid()); + + /* + * Wait for remote RMR information for RDMA + */ + if (collect_event(h_dto_rcv_evd, + &event, + DTO_TIMEOUT, + &poll_count) != DAT_SUCCESS) + return (DAT_ABORT); + + printf("%d remote RMR data arrived!\n", getpid()); + + if (event.event_number != DAT_DTO_COMPLETION_EVENT) { + fprintf(stderr, "%d Error unexpected DTO event : %s\n", + getpid(), DT_EventToStr(event.event_number)); + return (DAT_ABORT); + } + if ((event.event_data.dto_completion_event_data.transfered_length != + sizeof(DAT_RMR_TRIPLET)) || + (event.event_data.dto_completion_event_data.user_cookie.as_64 != + recv_msg_index)) { + fprintf(stderr, + "ERR recv event: len=%d cookie=" F64x + " expected %d/%d\n", + (int)event.event_data.dto_completion_event_data. + transfered_length, + event.event_data.dto_completion_event_data.user_cookie. + as_64, (int)sizeof(DAT_RMR_TRIPLET), recv_msg_index); + return (DAT_ABORT); + } + + /* swap received RMR msg: network order to host order */ + r_iov = rmr_recv_msg[recv_msg_index]; + rmr_recv_msg[recv_msg_index].rmr_context = ntohl(r_iov.rmr_context); + rmr_recv_msg[recv_msg_index].virtual_address = + ntohll(r_iov.virtual_address); + rmr_recv_msg[recv_msg_index].segment_length = + ntohl(r_iov.segment_length); + + printf("%d Received RMR from remote: " + "r_iov: r_key_ctx=%x,va=" F64x ",len=0x%x\n", + getpid(), rmr_recv_msg[recv_msg_index].rmr_context, + rmr_recv_msg[recv_msg_index].virtual_address, + rmr_recv_msg[recv_msg_index].segment_length); + + recv_msg_index++; + + return (DAT_SUCCESS); +} + +void disconnect_ep(void) +{ + DAT_RETURN ret; + DAT_EVENT event; + DAT_COUNT nmore; + + if (connected) { + + /* + * Only the client needs to call disconnect. The server _should_ be able + * to just wait on the EVD associated with connection events for a + * disconnect request and then exit. + */ + if (!server) { + LOGPRINTF("%d dat_ep_disconnect\n", getpid()); + ret = dat_ep_disconnect(h_ep, DAT_CLOSE_DEFAULT); + if (ret != DAT_SUCCESS) { + fprintf(stderr, + "%d Error dat_ep_disconnect: %s\n", + getpid(), DT_RetToStr(ret)); + } else { + LOGPRINTF("%d dat_ep_disconnect completed\n", + getpid()); + } + } else { + LOGPRINTF("%d Server waiting for disconnect...\n", + getpid()); + } + + ret = + dat_evd_wait(h_conn_evd, DAT_TIMEOUT_INFINITE, 1, &event, + &nmore); + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d Error dat_evd_wait: %s\n", + getpid(), DT_RetToStr(ret)); + } else { + LOGPRINTF("%d dat_evd_wait for h_conn_evd completed\n", + getpid()); + } + } + + /* destroy service point */ + if ((server) && (h_psp != DAT_HANDLE_NULL)) { + ret = dat_psp_free(h_psp); + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d Error dat_psp_free: %s\n", + getpid(), DT_RetToStr(ret)); + } else { + LOGPRINTF("%d dat_psp_free completed\n", getpid()); + } + } + + /* Unregister Send message Buffer */ + if (h_lmr_send_msg != DAT_HANDLE_NULL) { + LOGPRINTF("%d Unregister send message h_lmr %p \n", getpid(), + h_lmr_send_msg); + ret = dat_lmr_free(h_lmr_send_msg); + if (ret != DAT_SUCCESS) { + fprintf(stderr, + "%d Error deregistering send msg mr: %s\n", + getpid(), DT_RetToStr(ret)); + } else { + LOGPRINTF("%d Unregistered send message Buffer\n", + getpid()); + h_lmr_send_msg = NULL; + } + } + + /* Unregister recv message Buffer */ + if (h_lmr_recv_msg != DAT_HANDLE_NULL) { + LOGPRINTF("%d Unregister recv message h_lmr %p \n", getpid(), + h_lmr_recv_msg); + ret = dat_lmr_free(h_lmr_recv_msg); + if (ret != DAT_SUCCESS) { + fprintf(stderr, + "%d Error deregistering recv msg mr: %s\n", + getpid(), DT_RetToStr(ret)); + } else { + LOGPRINTF("%d Unregistered recv message Buffer\n", + getpid()); + h_lmr_recv_msg = NULL; + } + } + return; +} + +DAT_RETURN do_rdma_write_with_msg(void) +{ + DAT_EVENT event; + DAT_LMR_TRIPLET l_iov[MSG_IOV_COUNT]; + DAT_RMR_TRIPLET r_iov; + DAT_DTO_COOKIE cookie; + DAT_RETURN ret; + int i; + + printf("\n %d RDMA WRITE DATA with SEND MSG\n\n", getpid()); + + cookie.as_64 = 0x5555; + + if (recv_msg_index >= MSG_BUF_COUNT) + return (DAT_ABORT); + + /* get RMR information from previously received message */ + r_iov = rmr_recv_msg[recv_msg_index - 1]; + + if (server) + strcpy((char *)sbuf, "server RDMA write data..."); + else + strcpy((char *)sbuf, "client RDMA write data..."); + + for (i = 0; i < MSG_IOV_COUNT; i++) { + l_iov[i].lmr_context = lmr_context_send; + l_iov[i].segment_length = buf_len / MSG_IOV_COUNT; + l_iov[i].virtual_address = (DAT_VADDR) (uintptr_t) + (&sbuf[l_iov[i].segment_length * i]); + + LOGPRINTF("%d rdma_write iov[%d] buf=%p,len=%d\n", + getpid(), i, &sbuf[l_iov[i].segment_length * i], + l_iov[i].segment_length); + } + + start = get_time(); + for (i = 0; i < burst; i++) { + cookie.as_64 = 0x9999; + ret = dat_ep_post_rdma_write(h_ep, // ep_handle + MSG_IOV_COUNT, // num_segments + l_iov, // LMR + cookie, // user_cookie + &r_iov, // RMR + DAT_COMPLETION_SUPPRESS_FLAG); + if (ret != DAT_SUCCESS) { + fprintf(stderr, + "%d: ERROR: dat_ep_post_rdma_write() %s\n", + getpid(), DT_RetToStr(ret)); + return (DAT_ABORT); + } + LOGPRINTF("%d rdma_write # %d completed\n", getpid(), i + 1); + } + + /* + * Send RMR information a 2nd time to indicate completion + * NOTE: already swapped to network order in connect_ep + */ + printf("%d Sending RDMA WRITE completion message\n", getpid()); + + ret = send_msg(&rmr_send_msg, + sizeof(DAT_RMR_TRIPLET), + lmr_context_send_msg, + cookie, DAT_COMPLETION_SUPPRESS_FLAG); + + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d Error send_msg: %s\n", + getpid(), DT_RetToStr(ret)); + return (ret); + } else { + LOGPRINTF("%d send_msg completed\n", getpid()); + } + + /* inbound recv event, send completion's suppressed */ + if (collect_event(h_dto_rcv_evd, + &event, + DTO_TIMEOUT, + &rdma_wr_poll_count) != DAT_SUCCESS) + return (DAT_ABORT); + + stop = get_time(); + ts.rdma_wr = ((stop - start) * 1.0e6); + + /* validate event number and status */ + printf("%d inbound rdma_write; send message arrived!\n", getpid()); + if (event.event_number != DAT_DTO_COMPLETION_EVENT) { + fprintf(stderr, "%d Error unexpected DTO event : %s\n", + getpid(), DT_EventToStr(event.event_number)); + return (DAT_ABORT); + } + + if ((event.event_data.dto_completion_event_data.transfered_length != + sizeof(DAT_RMR_TRIPLET)) + || (event.event_data.dto_completion_event_data.user_cookie.as_64 != + recv_msg_index)) { + fprintf(stderr, + "unexpected event data for receive: len=%d cookie=" F64x + " exp %d/%d\n", + (int)event.event_data.dto_completion_event_data. + transfered_length, + event.event_data.dto_completion_event_data.user_cookie. + as_64, (int)sizeof(DAT_RMR_TRIPLET), recv_msg_index); + + return (DAT_ABORT); + } + + /* swap received RMR msg: network order to host order */ + r_iov = rmr_recv_msg[recv_msg_index]; + rmr_recv_msg[recv_msg_index].virtual_address = + ntohll(rmr_recv_msg[recv_msg_index].virtual_address); + rmr_recv_msg[recv_msg_index].segment_length = + ntohl(rmr_recv_msg[recv_msg_index].segment_length); + rmr_recv_msg[recv_msg_index].rmr_context = + ntohl(rmr_recv_msg[recv_msg_index].rmr_context); + + printf("%d Received RMR from remote: " + "r_iov: r_key_ctx=%x,va=" F64x ",len=0x%x\n", + getpid(), rmr_recv_msg[recv_msg_index].rmr_context, + rmr_recv_msg[recv_msg_index].virtual_address, + rmr_recv_msg[recv_msg_index].segment_length); + + LOGPRINTF("%d inbound rdma_write; send msg event SUCCESS!!\n", + getpid()); + + printf("%d %s RDMA write buffer contains: %s\n", + getpid(), server ? "SERVER:" : "CLIENT:", rbuf); + + recv_msg_index++; + + return (DAT_SUCCESS); +} + +DAT_RETURN do_rdma_read_with_msg(void) +{ + DAT_EVENT event; + DAT_LMR_TRIPLET l_iov; + DAT_RMR_TRIPLET r_iov; + DAT_DTO_COOKIE cookie; + DAT_RETURN ret; + int i; + + printf("\n %d RDMA READ DATA with SEND MSG\n\n", getpid()); + + if (recv_msg_index >= MSG_BUF_COUNT) + return (DAT_ABORT); + + /* get RMR information from previously received message */ + r_iov = rmr_recv_msg[recv_msg_index - 1]; + + /* setup rdma read buffer to initial string to be overwritten */ + strcpy((char *)sbuf, "blah, blah, blah\n"); + + if (server) + strcpy((char *)rbuf, "server RDMA read data..."); + else + strcpy((char *)rbuf, "client RDMA read data..."); + + l_iov.lmr_context = lmr_context_send; + l_iov.virtual_address = (DAT_VADDR) (uintptr_t) sbuf; + l_iov.segment_length = buf_len; + + for (i = 0; i < MAX_RDMA_RD; i++) { + cookie.as_64 = 0x9999; + start = get_time(); + ret = dat_ep_post_rdma_read(h_ep, // ep_handle + 1, // num_segments + &l_iov, // LMR + cookie, // user_cookie + &r_iov, // RMR + DAT_COMPLETION_DEFAULT_FLAG); + if (ret != DAT_SUCCESS) { + fprintf(stderr, + "%d: ERROR: dat_ep_post_rdma_read() %s\n", + getpid(), DT_RetToStr(ret)); + return (DAT_ABORT); + } + + /* RDMA read completion event */ + if (collect_event(h_dto_req_evd, + &event, + DTO_TIMEOUT, + &rdma_rd_poll_count[i]) != DAT_SUCCESS) + return (DAT_ABORT); + + /* validate event number, len, cookie, and status */ + if (event.event_number != DAT_DTO_COMPLETION_EVENT) { + fprintf(stderr, "%d: ERROR: DTO event number %s\n", + getpid(), DT_EventToStr(event.event_number)); + return (DAT_ABORT); + } + if ((event.event_data.dto_completion_event_data. + transfered_length != buf_len) + || (event.event_data.dto_completion_event_data.user_cookie. + as_64 != 0x9999)) { + fprintf(stderr, + "%d: ERROR: DTO len %d or cookie " F64x "\n", + getpid(), + event.event_data.dto_completion_event_data. + transfered_length, + event.event_data.dto_completion_event_data. + user_cookie.as_64); + return (DAT_ABORT); + } + if (event.event_data.dto_completion_event_data.status != + DAT_SUCCESS) { + fprintf(stderr, "%d: ERROR: DTO event status %s\n", + getpid(), DT_RetToStr(ret)); + return (DAT_ABORT); + } + stop = get_time(); + ts.rdma_rd[i] = ((stop - start) * 1.0e6); + ts.rdma_rd_total += ts.rdma_rd[i]; + + LOGPRINTF("%d rdma_read # %d completed\n", getpid(), i + 1); + } + + /* + * Send RMR information a 3rd time to indicate completion + * NOTE: already swapped to network order in connect_ep + */ + printf("%d Sending RDMA read completion message\n", getpid()); + + /* give remote chance to process read completes */ + if (use_cno) { +#if defined(_WIN32) || defined(_WIN64) + Sleep(1000); +#else + sleep(1); +#endif + } + + ret = send_msg(&rmr_send_msg, + sizeof(DAT_RMR_TRIPLET), + lmr_context_send_msg, + cookie, DAT_COMPLETION_SUPPRESS_FLAG); + + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d Error send_msg: %s\n", + getpid(), DT_RetToStr(ret)); + return (ret); + } else { + LOGPRINTF("%d send_msg completed\n", getpid()); + } + + printf("%d Waiting for inbound message....\n", getpid()); + + if (collect_event(h_dto_rcv_evd, + &event, + DTO_TIMEOUT, + &poll_count) != DAT_SUCCESS) + return (DAT_ABORT); + + /* validate event number and status */ + printf("%d inbound rdma_read; send message arrived!\n", getpid()); + if (event.event_number != DAT_DTO_COMPLETION_EVENT) { + fprintf(stderr, "%d Error unexpected DTO event : %s\n", + getpid(), DT_EventToStr(event.event_number)); + return (DAT_ABORT); + } + + if ((event.event_data.dto_completion_event_data.transfered_length != + sizeof(DAT_RMR_TRIPLET)) + || (event.event_data.dto_completion_event_data.user_cookie.as_64 != + recv_msg_index)) { + + fprintf(stderr, + "unexpected event data for receive: len=%d cookie=" F64x + " exp %d/%d\n", + (int)event.event_data.dto_completion_event_data. + transfered_length, + event.event_data.dto_completion_event_data.user_cookie. + as_64, (int)sizeof(DAT_RMR_TRIPLET), recv_msg_index); + + return (DAT_ABORT); + } + + /* swap received RMR msg: network order to host order */ + r_iov = rmr_recv_msg[recv_msg_index]; + rmr_recv_msg[recv_msg_index].virtual_address = + ntohll(rmr_recv_msg[recv_msg_index].virtual_address); + rmr_recv_msg[recv_msg_index].segment_length = + ntohl(rmr_recv_msg[recv_msg_index].segment_length); + rmr_recv_msg[recv_msg_index].rmr_context = + ntohl(rmr_recv_msg[recv_msg_index].rmr_context); + + printf("%d Received RMR from remote: " + "r_iov: r_key_ctx=%x,va=" F64x ",len=0x%x\n", + getpid(), rmr_recv_msg[recv_msg_index].rmr_context, + rmr_recv_msg[recv_msg_index].virtual_address, + rmr_recv_msg[recv_msg_index].segment_length); + + LOGPRINTF("%d inbound rdma_write; send msg event SUCCESS!!\n", + getpid()); + + printf("%d %s RCV RDMA read buffer contains: %s\n", + getpid(), server ? "SERVER:" : "CLIENT:", sbuf); + + recv_msg_index++; + + return (DAT_SUCCESS); +} + +DAT_RETURN do_ping_pong_msg() +{ + DAT_EVENT event; + DAT_DTO_COOKIE cookie; + DAT_LMR_TRIPLET l_iov; + DAT_RETURN ret; + int i; + char *snd_buf; + char *rcv_buf; + + printf("\n %d PING DATA with SEND MSG\n\n", getpid()); + + snd_buf = sbuf; + rcv_buf = rbuf; + + /* pre-post all buffers */ + for (i = 0; i < burst; i++) { + burst_msg_posted++; + cookie.as_64 = i; + l_iov.lmr_context = lmr_context_recv; + l_iov.virtual_address = (DAT_VADDR) (uintptr_t) rcv_buf; + l_iov.segment_length = buf_len; + + LOGPRINTF("%d Pre-posting Receive Message Buffers %p\n", + getpid(), rcv_buf); + + ret = dat_ep_post_recv(h_ep, + 1, + &l_iov, + cookie, DAT_COMPLETION_DEFAULT_FLAG); + + if (ret != DAT_SUCCESS) { + fprintf(stderr, + "%d Error posting recv msg buffer: %s\n", + getpid(), DT_RetToStr(ret)); + return (ret); + } else { + LOGPRINTF("%d Posted Receive Message Buffer %p\n", + getpid(), rcv_buf); + } + + /* next buffer */ + rcv_buf += buf_len; + } +#if defined(_WIN32) || defined(_WIN64) + Sleep(1000); +#else + sleep(1); +#endif + + /* Initialize recv_buf and index to beginning */ + rcv_buf = rbuf; + burst_msg_index = 0; + + /* client ping 0x55, server pong 0xAA in first byte */ + start = get_time(); + for (i = 0; i < burst; i++) { + /* walk the send and recv buffers */ + if (!server) { + *snd_buf = 0x55; + + LOGPRINTF("%d %s SND buffer %p contains: 0x%x len=%d\n", + getpid(), server ? "SERVER:" : "CLIENT:", + snd_buf, *snd_buf, buf_len); + + ret = send_msg(snd_buf, + buf_len, + lmr_context_send, + cookie, DAT_COMPLETION_SUPPRESS_FLAG); + + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d Error send_msg: %s\n", + getpid(), DT_RetToStr(ret)); + return (ret); + } else { + LOGPRINTF("%d send_msg completed\n", getpid()); + } + } + + /* recv message, send completions suppressed */ + if (collect_event(h_dto_rcv_evd, + &event, + DTO_TIMEOUT, + &poll_count) != DAT_SUCCESS) + return (DAT_ABORT); + + + /* start timer after first message arrives on server */ + if (i == 0) { + start = get_time(); + } + /* validate event number and status */ + LOGPRINTF("%d inbound message; message arrived!\n", getpid()); + if (event.event_number != DAT_DTO_COMPLETION_EVENT) { + fprintf(stderr, "%d Error unexpected DTO event : %s\n", + getpid(), DT_EventToStr(event.event_number)); + return (DAT_ABORT); + } + if ((event.event_data.dto_completion_event_data. + transfered_length != buf_len) + || (event.event_data.dto_completion_event_data.user_cookie. + as_64 != burst_msg_index)) { + fprintf(stderr, + "ERR: recv event: len=%d cookie=" F64x + " exp %d/%d\n", + (int)event.event_data.dto_completion_event_data. + transfered_length, + event.event_data.dto_completion_event_data. + user_cookie.as_64, (int)buf_len, + (int)burst_msg_index); + + return (DAT_ABORT); + } + + LOGPRINTF("%d %s RCV buffer %p contains: 0x%x len=%d\n", + getpid(), server ? "SERVER:" : "CLIENT:", + rcv_buf, *rcv_buf, buf_len); + + burst_msg_index++; + + /* If server, change data and send it back to client */ + if (server) { + *snd_buf = 0xaa; + + LOGPRINTF("%d %s SND buffer %p contains: 0x%x len=%d\n", + getpid(), server ? "SERVER:" : "CLIENT:", + snd_buf, *snd_buf, buf_len); + + ret = send_msg(snd_buf, + buf_len, + lmr_context_send, + cookie, DAT_COMPLETION_SUPPRESS_FLAG); + + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d Error send_msg: %s\n", + getpid(), DT_RetToStr(ret)); + return (ret); + } else { + LOGPRINTF("%d send_msg completed\n", getpid()); + } + } + + /* next buffers */ + rcv_buf += buf_len; + snd_buf += buf_len; + } + stop = get_time(); + ts.rtt = ((stop - start) * 1.0e6); + + return (DAT_SUCCESS); +} + +/* Register RDMA Receive buffer */ +DAT_RETURN register_rdma_memory(void) +{ + DAT_RETURN ret; + DAT_REGION_DESCRIPTION region; + + region.for_va = rbuf; + start = get_time(); + ret = dat_lmr_create(h_ia, + DAT_MEM_TYPE_VIRTUAL, + region, + buf_len * (burst+1), + h_pz, + DAT_MEM_PRIV_ALL_FLAG, + DAT_VA_TYPE_VA, + &h_lmr_recv, + &lmr_context_recv, + &rmr_context_recv, + ®istered_size_recv, ®istered_addr_recv); + stop = get_time(); + ts.reg += ((stop - start) * 1.0e6); + ts.total += ts.reg; + + if (ret != DAT_SUCCESS) { + fprintf(stderr, + "%d Error registering Receive RDMA buffer: %s\n", + getpid(), DT_RetToStr(ret)); + return (ret); + } else { + LOGPRINTF("%d Registered Receive RDMA Buffer %p\n", + getpid(), region.for_va); + } + + /* Register RDMA Send buffer */ + region.for_va = sbuf; + ret = dat_lmr_create(h_ia, + DAT_MEM_TYPE_VIRTUAL, + region, + buf_len * (burst + 1), + h_pz, + DAT_MEM_PRIV_ALL_FLAG, + DAT_VA_TYPE_VA, + &h_lmr_send, + &lmr_context_send, + &rmr_context_send, + ®istered_size_send, ®istered_addr_send); + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d Error registering send RDMA buffer: %s\n", + getpid(), DT_RetToStr(ret)); + return (ret); + } else { + LOGPRINTF("%d Registered Send RDMA Buffer %p\n", + getpid(), region.for_va); + } + + return DAT_SUCCESS; +} + +/* + * Unregister RDMA memory + */ +DAT_RETURN unregister_rdma_memory(void) +{ + DAT_RETURN ret; + + /* Unregister Recv Buffer */ + if (h_lmr_recv != DAT_HANDLE_NULL) { + LOGPRINTF("%d Unregister h_lmr %p \n", getpid(), h_lmr_recv); + start = get_time(); + ret = dat_lmr_free(h_lmr_recv); + stop = get_time(); + ts.unreg += ((stop - start) * 1.0e6); + ts.total += ts.unreg; + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d Error deregistering recv mr: %s\n", + getpid(), DT_RetToStr(ret)); + return (ret); + } else { + LOGPRINTF("%d Unregistered Recv Buffer\n", getpid()); + h_lmr_recv = NULL; + } + } + + /* Unregister Send Buffer */ + if (h_lmr_send != DAT_HANDLE_NULL) { + LOGPRINTF("%d Unregister h_lmr %p \n", getpid(), h_lmr_send); + ret = dat_lmr_free(h_lmr_send); + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d Error deregistering send mr: %s\n", + getpid(), DT_RetToStr(ret)); + return (ret); + } else { + LOGPRINTF("%d Unregistered send Buffer\n", getpid()); + h_lmr_send = NULL; + } + } + return DAT_SUCCESS; +} + + /* + * Create CNO, CR, CONN, and DTO events + */ +DAT_RETURN create_events(void) +{ + DAT_RETURN ret; + DAT_EVD_PARAM param; + + /* create CNO */ + if (use_cno) { + start = get_time(); +#if defined(_WIN32) || defined(_WIN64) + { + DAT_OS_WAIT_PROXY_AGENT pa = { NULL, NULL }; + ret = dat_cno_create(h_ia, pa, &h_dto_cno); + } +#else + ret = + dat_cno_create(h_ia, DAT_OS_WAIT_PROXY_AGENT_NULL, + &h_dto_cno); +#endif + stop = get_time(); + ts.cnoc += ((stop - start) * 1.0e6); + ts.total += ts.cnoc; + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d Error dat_cno_create: %s\n", + getpid(), DT_RetToStr(ret)); + return (ret); + } else { + LOGPRINTF("%d cr_evd created, %p\n", getpid(), + h_dto_cno); + } + } + + /* create cr EVD */ + start = get_time(); + ret = + dat_evd_create(h_ia, 10, DAT_HANDLE_NULL, DAT_EVD_CR_FLAG, + &h_cr_evd); + stop = get_time(); + ts.evdc += ((stop - start) * 1.0e6); + ts.total += ts.evdc; + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d Error dat_evd_create: %s\n", + getpid(), DT_RetToStr(ret)); + return (ret); + } else { + LOGPRINTF("%d cr_evd created %p\n", getpid(), h_cr_evd); + } + + /* create conn EVD */ + ret = dat_evd_create(h_ia, + 10, + DAT_HANDLE_NULL, + DAT_EVD_CONNECTION_FLAG, &h_conn_evd); + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d Error dat_evd_create: %s\n", + getpid(), DT_RetToStr(ret)); + return (ret); + } else { + LOGPRINTF("%d con_evd created %p\n", getpid(), h_conn_evd); + } + + /* create dto SND EVD, with CNO if use_cno was set */ + ret = dat_evd_create(h_ia, + (MSG_BUF_COUNT + MAX_RDMA_RD + burst) * 2, + h_dto_cno, DAT_EVD_DTO_FLAG, &h_dto_req_evd); + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d Error dat_evd_create REQ: %s\n", + getpid(), DT_RetToStr(ret)); + return (ret); + } else { + LOGPRINTF("%d dto_req_evd created %p\n", getpid(), + h_dto_req_evd); + } + + /* create dto RCV EVD, with CNO if use_cno was set */ + ret = dat_evd_create(h_ia, + MSG_BUF_COUNT + burst, + h_dto_cno, DAT_EVD_DTO_FLAG, &h_dto_rcv_evd); + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d Error dat_evd_create RCV: %s\n", + getpid(), DT_RetToStr(ret)); + return (ret); + } else { + LOGPRINTF("%d dto_rcv_evd created %p\n", getpid(), + h_dto_rcv_evd); + } + + /* query DTO req EVD and check size */ + ret = dat_evd_query(h_dto_req_evd, DAT_EVD_FIELD_EVD_QLEN, ¶m); + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d Error dat_evd_query request evd: %s\n", + getpid(), DT_RetToStr(ret)); + return (ret); + } else if (param.evd_qlen < (MSG_BUF_COUNT + MAX_RDMA_RD + burst) * 2) { + fprintf(stderr, "%d Error dat_evd qsize too small: %d < %d\n", + getpid(), param.evd_qlen, + (MSG_BUF_COUNT + MAX_RDMA_RD + burst) * 2); + return (ret); + } + + LOGPRINTF("%d dto_req_evd QLEN - requested %d and actual %d\n", + getpid(), (MSG_BUF_COUNT + MAX_RDMA_RD + burst) * 2, + param.evd_qlen); + + return DAT_SUCCESS; +} + +/* + * Destroy CR, CONN, CNO, and DTO events + */ + +DAT_RETURN destroy_events(void) +{ + DAT_RETURN ret; + + /* free cr EVD */ + if (h_cr_evd != DAT_HANDLE_NULL) { + LOGPRINTF("%d Free cr EVD %p \n", getpid(), h_cr_evd); + ret = dat_evd_free(h_cr_evd); + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d Error freeing cr EVD: %s\n", + getpid(), DT_RetToStr(ret)); + return (ret); + } else { + LOGPRINTF("%d Freed cr EVD\n", getpid()); + h_cr_evd = DAT_HANDLE_NULL; + } + } + + /* free conn EVD */ + if (h_conn_evd != DAT_HANDLE_NULL) { + LOGPRINTF("%d Free conn EVD %p \n", getpid(), h_conn_evd); + ret = dat_evd_free(h_conn_evd); + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d Error freeing conn EVD: %s\n", + getpid(), DT_RetToStr(ret)); + return (ret); + } else { + LOGPRINTF("%d Freed conn EVD\n", getpid()); + h_conn_evd = DAT_HANDLE_NULL; + } + } + + /* free RCV dto EVD */ + if (h_dto_rcv_evd != DAT_HANDLE_NULL) { + LOGPRINTF("%d Free RCV dto EVD %p \n", getpid(), h_dto_rcv_evd); + start = get_time(); + ret = dat_evd_free(h_dto_rcv_evd); + stop = get_time(); + ts.evdf += ((stop - start) * 1.0e6); + ts.total += ts.evdf; + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d Error freeing dto EVD: %s\n", + getpid(), DT_RetToStr(ret)); + return (ret); + } else { + LOGPRINTF("%d Freed dto EVD\n", getpid()); + h_dto_rcv_evd = DAT_HANDLE_NULL; + } + } + + /* free REQ dto EVD */ + if (h_dto_req_evd != DAT_HANDLE_NULL) { + LOGPRINTF("%d Free REQ dto EVD %p \n", getpid(), h_dto_req_evd); + ret = dat_evd_free(h_dto_req_evd); + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d Error freeing dto EVD: %s\n", + getpid(), DT_RetToStr(ret)); + return (ret); + } else { + LOGPRINTF("%d Freed dto EVD\n", getpid()); + h_dto_req_evd = DAT_HANDLE_NULL; + } + } + + /* free CNO */ + if (h_dto_cno != DAT_HANDLE_NULL) { + LOGPRINTF("%d Free dto CNO %p \n", getpid(), h_dto_cno); + start = get_time(); + ret = dat_cno_free(h_dto_cno); + stop = get_time(); + ts.cnof += ((stop - start) * 1.0e6); + ts.total += ts.cnof; + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d Error freeing dto CNO: %s\n", + getpid(), DT_RetToStr(ret)); + return (ret); + } else { + LOGPRINTF("%d Freed dto CNO\n", getpid()); + h_dto_cno = DAT_HANDLE_NULL; + } + } + return DAT_SUCCESS; +} + +/* + * Map DAT_RETURN values to readable strings, + * but don't assume the values are zero-based or contiguous. + */ +char errmsg[512] = { 0 }; +const char *DT_RetToStr(DAT_RETURN ret_value) +{ + const char *major_msg, *minor_msg; + + dat_strerror(ret_value, &major_msg, &minor_msg); + + strcpy(errmsg, major_msg); + strcat(errmsg, " "); + strcat(errmsg, minor_msg); + + return errmsg; +} + +/* + * Map DAT_EVENT_CODE values to readable strings + */ +const char *DT_EventToStr(DAT_EVENT_NUMBER event_code) +{ + unsigned int i; + static struct { + const char *name; + DAT_RETURN value; + } dat_events[] = { +# define DATxx(x) { # x, x } + DATxx(DAT_DTO_COMPLETION_EVENT), + DATxx(DAT_RMR_BIND_COMPLETION_EVENT), + DATxx(DAT_CONNECTION_REQUEST_EVENT), + DATxx(DAT_CONNECTION_EVENT_ESTABLISHED), + DATxx(DAT_CONNECTION_EVENT_PEER_REJECTED), + DATxx(DAT_CONNECTION_EVENT_NON_PEER_REJECTED), + DATxx(DAT_CONNECTION_EVENT_ACCEPT_COMPLETION_ERROR), + DATxx(DAT_CONNECTION_EVENT_DISCONNECTED), + DATxx(DAT_CONNECTION_EVENT_BROKEN), + DATxx(DAT_CONNECTION_EVENT_TIMED_OUT), + DATxx(DAT_CONNECTION_EVENT_UNREACHABLE), + DATxx(DAT_ASYNC_ERROR_EVD_OVERFLOW), + DATxx(DAT_ASYNC_ERROR_IA_CATASTROPHIC), + DATxx(DAT_ASYNC_ERROR_EP_BROKEN), + DATxx(DAT_ASYNC_ERROR_TIMED_OUT), + DATxx(DAT_ASYNC_ERROR_PROVIDER_INTERNAL_ERROR), + DATxx(DAT_SOFTWARE_EVENT) +# undef DATxx + }; +# define NUM_EVENTS (sizeof(dat_events)/sizeof(dat_events[0])) + + for (i = 0; i < NUM_EVENTS; i++) { + if (dat_events[i].value == event_code) { + return (dat_events[i].name); + } + } + + return ("Invalid_DAT_EVENT_NUMBER"); +} + +void print_usage(void) +{ + printf("\n DAPL USAGE \n\n"); + printf("s: server\n"); + printf("t: performance times\n"); + printf("c: use cno\n"); + printf("v: verbose\n"); + printf("p: polling\n"); + printf("d: delay before accept\n"); + printf("b: buf length to allocate\n"); + printf("B: burst count, rdma and msgs \n"); + printf("h: hostname/address of server, specified on client\n"); + printf("P: provider name (default = OpenIB-cma)\n"); + printf("l: server lid (required ucm provider)\n"); + printf("q: server qpn (required ucm provider)\n"); + printf("\n"); +} + diff --git a/branches/WOF2-3/ulp/dapl2/test/dtest/dtestcm.c b/branches/WOF2-3/ulp/dapl2/test/dtest/dtestcm.c new file mode 100644 index 00000000..d3762c9c --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dtest/dtestcm.c @@ -0,0 +1,1168 @@ +/* + * Copyright (c) 2009 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: $ + */ +#include +#include +#include + +#ifdef DAPL_PROVIDER +#undef DAPL_PROVIDER +#endif + +#if defined(_WIN32) || defined(_WIN64) + +#include +#include +#include +#include +#include +#include +#include "..\..\..\..\etc\user\getopt.c" + +#define getpid() ((int)GetCurrentProcessId()) +#define F64x "%I64x" +#define F64d "%I64d" + +#ifdef DBG +#define DAPL_PROVIDER "ibnic0v2d" +#else +#define DAPL_PROVIDER "ibnic0v2" +#endif + +#define ntohll _byteswap_uint64 +#define htonll _byteswap_uint64 + +#else // _WIN32 || _WIN64 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DAPL_PROVIDER "ofa-v2-ib0" + +#define F64x "%"PRIx64"" +#define F64d "%"PRId64"" + + +#if __BYTE_ORDER == __BIG_ENDIAN +#define htonll(x) (x) +#define ntohll(x) (x) +#elif __BYTE_ORDER == __LITTLE_ENDIAN +#define htonll(x) bswap_64(x) +#define ntohll(x) bswap_64(x) +#endif + +#endif // _WIN32 || _WIN64 + +#define MAX_POLLING_CNT 50000 + +/* Header files needed for DAT/uDAPL */ +#include "dat2/udat.h" +#include "dat2/dat_ib_extensions.h" + +/* definitions */ +#define SERVER_CONN_QUAL 45248 +#define CONN_TIMEOUT (1000*1000*100) +#define CR_TIMEOUT DAT_TIMEOUT_INFINITE + +/* Global DAT vars */ +static DAT_IA_HANDLE h_ia = DAT_HANDLE_NULL; +static DAT_PZ_HANDLE h_pz = DAT_HANDLE_NULL; +static DAT_EP_HANDLE *h_ep; +static DAT_PSP_HANDLE *h_psp; +static DAT_CR_HANDLE h_cr = DAT_HANDLE_NULL; + +static DAT_EVD_HANDLE h_async_evd = DAT_HANDLE_NULL; +static DAT_EVD_HANDLE h_dto_req_evd = DAT_HANDLE_NULL; +static DAT_EVD_HANDLE h_dto_rcv_evd = DAT_HANDLE_NULL; +static DAT_EVD_HANDLE h_cr_evd = DAT_HANDLE_NULL; +static DAT_EVD_HANDLE h_conn_evd = DAT_HANDLE_NULL; + +static DAT_EP_ATTR ep_attr; +char hostname[256] = { 0 }; +char provider[64] = DAPL_PROVIDER; +char addr_str[INET_ADDRSTRLEN]; + +int status; + +/* timers */ +double start, stop, total_us, total_sec; + +struct dt_time { + double total; + double open; + double reg; + double unreg; + double pzc; + double pzf; + double evdc; + double evdf; + double cnoc; + double cnof; + double epc; + double epf; + double rtt; + double close; + double conn; +}; + +struct dt_time ts; + +/* defaults */ +static int connected = 0; +static int multi_listens = 0; +static int ud_test = 0; +static int server = 1; +static int waiting = 0; +static int verbose = 0; +static int cr_poll_count = 0; +static int conn_poll_count = 0; +static int delay = 0; +static int connections = 1000; +static int burst = 100; +static int port_id = SERVER_CONN_QUAL; +static int ucm = 0; +static DAT_SOCK_ADDR6 remote; + +/* forward prototypes */ +const char *DT_RetToString(DAT_RETURN ret_value); +const char *DT_EventToSTr(DAT_EVENT_NUMBER event_code); +void print_usage(void); +double get_time(void); +DAT_RETURN conn_client(void); +DAT_RETURN conn_server(void); +DAT_RETURN disconnect_eps(void); +DAT_RETURN create_events(void); +DAT_RETURN destroy_events(void); + +#define LOGPRINTF if (verbose) printf + +void flush_evds(void) +{ + DAT_EVENT event; + + /* Flush async error queue */ + printf(" ERR: Checking ASYNC EVD...\n"); + while (dat_evd_dequeue(h_async_evd, &event) == DAT_SUCCESS) { + printf(" ASYNC EVD ENTRY: handle=%p reason=%d\n", + event.event_data.asynch_error_event_data.dat_handle, + event.event_data.asynch_error_event_data.reason); + } +} + +static void print_ia_address(struct sockaddr *sa) +{ + char str[INET6_ADDRSTRLEN] = {" ??? "}; + + switch(sa->sa_family) { + case AF_INET: + inet_ntop(AF_INET, &((struct sockaddr_in *)sa)->sin_addr, str, INET6_ADDRSTRLEN); + printf("%d Local Address AF_INET - %s port %d\n", getpid(), str, SERVER_CONN_QUAL); + break; + case AF_INET6: + inet_ntop(AF_INET6, &((struct sockaddr_in6 *)sa)->sin6_addr, str, INET6_ADDRSTRLEN); + printf("%d Local Address AF_INET6 - %s flowinfo(QPN)=0x%x, port(LID)=0x%x\n", + getpid(), str, + ntohl(((struct sockaddr_in6 *)sa)->sin6_flowinfo), + ntohs(((struct sockaddr_in6 *)sa)->sin6_port)); + break; + default: + printf("%d Local Address UNKOWN FAMILY - port %d\n", getpid(), SERVER_CONN_QUAL); + } +} + +int main(int argc, char **argv) +{ + int i, c, len; + DAT_RETURN ret; + DAT_IA_ATTR ia_attr; + + /* parse arguments */ + while ((c = getopt(argc, argv, "smwvub:c:d:h:P:p:q:l:")) != -1) { + switch (c) { + case 's': + server = 1; + break; + case 'm': + multi_listens = 1; + break; + case 'w': + waiting = 1; + break; + case 'u': + ud_test = 1; + break; + case 'c': + connections = atoi(optarg); + break; + case 'p': + port_id = atoi(optarg); + break; + case 'v': + verbose = 1; + fflush(stdout); + break; + case 'd': + delay = atoi(optarg); + break; + case 'b': + burst = atoi(optarg); + break; + case 'h': + server = 0; + strcpy(hostname, optarg); + break; + case 'P': + strcpy(provider, optarg); + break; + case 'q': + /* map UCM qpn into AF_INET6 sin6_flowinfo */ + remote.sin6_family = AF_INET6; + remote.sin6_flowinfo = htonl(strtol(optarg,NULL,0)); + ucm = 1; + server = 0; + break; + case 'l': + /* map UCM lid into AF_INET6 sin6_port */ + remote.sin6_family = AF_INET6; + remote.sin6_port = htons(strtol(optarg,NULL,0)); + ucm = 1; + server = 0; + break; + default: + print_usage(); + exit(-12); + } + } + +#if defined(_WIN32) || defined(_WIN64) + { + WSADATA wsaData; + + i = WSAStartup(MAKEWORD(2, 2), &wsaData); + if (i != 0) { + printf("%s WSAStartup(2.2) failed? (0x%x)\n", argv[0], + i); + fflush(stdout); + exit(1); + } + } +#endif + + if (!server) { + printf(" Running client on %s with %d %s connections\n", + provider, connections, ud_test ? "UD" : "RC"); + } else { + printf(" Running server on %s with %d %s connections\n", + provider, connections, ud_test ? "UD" : "RC"); + } + fflush(stdout); + + if (burst > connections) + burst = connections; + + + /* allocate EP handles for all connections */ + h_ep = (DAT_EP_HANDLE*)malloc(connections * sizeof(DAT_EP_HANDLE)); + if (h_ep == NULL) { + perror("malloc ep"); + exit(1); + } + memset(h_ep, 0, (burst * sizeof(DAT_PSP_HANDLE))); + + /* allocate PSP handles, check for multi-listens */ + if (multi_listens) + len = burst * sizeof(DAT_PSP_HANDLE); + else + len = sizeof(DAT_PSP_HANDLE); + + h_psp = (DAT_PSP_HANDLE*)malloc(len); + if (h_psp == NULL) { + perror("malloc psp"); + exit(1); + } + memset(h_psp, 0, len); + memset(&ts, 0, sizeof(struct dt_time)); + + /* dat_ia_open, dat_pz_create */ + h_async_evd = DAT_HANDLE_NULL; + start = get_time(); + ret = dat_ia_open(provider, 8, &h_async_evd, &h_ia); + stop = get_time(); + ts.open += ((stop - start) * 1.0e6); + if (ret != DAT_SUCCESS) { + fprintf(stderr, " Error Adaptor open: %s\n", + DT_RetToString(ret)); + exit(1); + } else + LOGPRINTF(" Opened Interface Adaptor\n"); + + /* query for UCM addressing */ + ret = dat_ia_query(h_ia, 0, DAT_IA_FIELD_ALL, &ia_attr, 0, 0); + if (ret != DAT_SUCCESS) { + fprintf(stderr, "%d: Error Adaptor query: %s\n", + getpid(), DT_RetToString(ret)); + exit(1); + } + print_ia_address(ia_attr.ia_address_ptr); + + /* Create Protection Zone */ + start = get_time(); + LOGPRINTF(" Create Protection Zone\n"); + ret = dat_pz_create(h_ia, &h_pz); + stop = get_time(); + ts.pzc += ((stop - start) * 1.0e6); + if (ret != DAT_SUCCESS) { + fprintf(stderr, " Error creating Protection Zone: %s\n", + DT_RetToString(ret)); + exit(1); + } else + LOGPRINTF(" Created Protection Zone\n"); + + LOGPRINTF(" Create events\n"); + ret = create_events(); + if (ret != DAT_SUCCESS) { + fprintf(stderr, " Error creating events: %s\n", + DT_RetToString(ret)); + goto cleanup; + } else { + LOGPRINTF(" Create events done\n"); + } + + /* create EP */ + memset(&ep_attr, 0, sizeof(ep_attr)); + if (ud_test) { + ep_attr.service_type = DAT_IB_SERVICE_TYPE_UD; + ep_attr.max_message_size = 2048; + } else { + ep_attr.service_type = DAT_SERVICE_TYPE_RC; + ep_attr.max_rdma_size = 0x10000; + ep_attr.max_rdma_read_in = 4; + ep_attr.max_rdma_read_out = 4; + } + ep_attr.max_recv_dtos = 1; + ep_attr.max_request_dtos = 1; + ep_attr.max_recv_iov = 1; + ep_attr.max_request_iov = 1; + ep_attr.request_completion_flags = DAT_COMPLETION_DEFAULT_FLAG; + + start = get_time(); + for (i = 0; i < connections; i++) { + ret = dat_ep_create(h_ia, h_pz, h_dto_rcv_evd, + h_dto_req_evd, h_conn_evd, + &ep_attr, &h_ep[i]); + } + stop = get_time(); + ts.epc += ((stop - start) * 1.0e6); + ts.total += ts.epc; + if (ret != DAT_SUCCESS) { + fprintf(stderr, " Error dat_ep_create: %s\n", + DT_RetToString(ret)); + goto cleanup; + } else + LOGPRINTF(" EP created %p \n", h_ep[i]); + + /* create the service point for server listen */ + if (server) { + LOGPRINTF(" Creating server service point(s)\n"); + for (i = 0; i < burst; i++) { + ret = dat_psp_create(h_ia, + port_id+i, + h_cr_evd, + DAT_PSP_CONSUMER_FLAG, + &h_psp[i]); + + if (ret != DAT_SUCCESS) { + fprintf(stderr, " ERR psp_create: %s\n", + DT_RetToString(ret)); + goto cleanup; + } else + LOGPRINTF(" psp_created for listen\n"); + + printf(" Server ready on port %d\n", + port_id+i); + + if (!multi_listens) + break; + } + } + + /* Connect all */ + if (server) + ret = conn_server(); + else + ret = conn_client(); + + if (ret != DAT_SUCCESS) { + fprintf(stderr, " Error %s: %s\n", + server ? "server()" : "client()", + DT_RetToString(ret)); + goto cleanup; + } else + LOGPRINTF(" connect_ep complete\n"); + + connected = 1; + goto complete; + +cleanup: + flush_evds(); + goto bail; +complete: + + /* disconnect and free EP resources */ + if (h_ep[0]) { + /* unregister message buffers and tear down connection */ + LOGPRINTF(" Disconnect EPs\n"); + ret = disconnect_eps(); + if (ret != DAT_SUCCESS) { + fprintf(stderr, " Error disconnect_eps: %s\n", + DT_RetToString(ret)); + goto bail; + } else { + LOGPRINTF(" disconnect_eps complete\n"); + } + } + + /* destroy server service point(s) */ + if ((server) && (h_psp[0] != DAT_HANDLE_NULL)) { + for (i = 0; i < burst; i++) { + ret = dat_psp_free(h_psp[i]); + if (ret != DAT_SUCCESS) { + fprintf(stderr, " Error dat_psp_free: %s\n", + DT_RetToString(ret)); + goto bail; + } else { + LOGPRINTF(" psp_free[%d] complete\n",i); + } + if (!multi_listens) + break; + } + } + + /* free EVDs */ + LOGPRINTF(" destroy events\n"); + ret = destroy_events(); + if (ret != DAT_SUCCESS) { + fprintf(stderr, " Error destroy_events: %s\n", + DT_RetToString(ret)); + goto bail; + } else + LOGPRINTF(" destroy events done\n"); + + + /* Free protection domain */ + LOGPRINTF(" Freeing pz\n"); + start = get_time(); + ret = dat_pz_free(h_pz); + stop = get_time(); + ts.pzf += ((stop - start) * 1.0e6); + if (ret != DAT_SUCCESS) { + fprintf(stderr, " Error freeing PZ: %s\n", + DT_RetToString(ret)); + goto bail; + } else { + LOGPRINTF(" Freed pz\n"); + h_pz = NULL; + } + + /* close the device */ + LOGPRINTF(" Closing Interface Adaptor\n"); + start = get_time(); + ret = dat_ia_close(h_ia, DAT_CLOSE_ABRUPT_FLAG); + stop = get_time(); + ts.close += ((stop - start) * 1.0e6); + if (ret != DAT_SUCCESS) { + fprintf(stderr, " Error Adaptor close: %s\n", + DT_RetToString(ret)); + goto bail; + } else + LOGPRINTF(" Closed Interface Adaptor\n"); + + printf(" DAPL Connection Test Complete.\n"); + printf(" open: %10.2lf usec\n", ts.open); + printf(" close: %10.2lf usec\n", ts.close); + printf(" PZ create: %10.2lf usec\n", ts.pzc); + printf(" PZ free: %10.2lf usec\n", ts.pzf); + printf(" LMR create:%10.2lf usec\n", ts.reg); + printf(" LMR free: %10.2lf usec\n", ts.unreg); + printf(" EVD create:%10.2lf usec\n", ts.evdc); + printf(" EVD free: %10.2lf usec\n", ts.evdf); + printf(" EP create: %10.2lf usec avg\n", ts.epc/connections); + printf(" EP free: %10.2lf usec avg\n", ts.epf/connections); + if (!server) { + printf(" Connections: %8.2lf usec, CPS %7.2lf " + "Total %4.2lf secs, poll_cnt=%u, Num=%d\n", + (double)(ts.conn/connections), + (double)(1/(ts.conn/1000000/connections)), + (double)(ts.conn/1000000), + conn_poll_count, connections); + } + printf(" TOTAL: %4.2lf sec\n", ts.total/1000000); + fflush(stderr); fflush(stdout); +bail: + free(h_ep); + free(h_psp); + +#if defined(_WIN32) || defined(_WIN64) + WSACleanup(); +#endif + return (0); +} + +double get_time(void) +{ + struct timeval tp; + + gettimeofday(&tp, NULL); + return ((double)tp.tv_sec + (double)tp.tv_usec * 1e-6); +} + +DAT_RETURN conn_server() +{ + DAT_RETURN ret; + DAT_EVENT event; + DAT_COUNT nmore; + int i,bi; + unsigned char *buf; + DAT_CR_ARRIVAL_EVENT_DATA *cr_event = + &event.event_data.cr_arrival_event_data; + DAT_CR_PARAM cr_param = { 0 }; + + printf(" Accepting...\n"); + for (i = 0; i < connections; i++) { + + /* poll for CR's */ + if (!waiting) { + cr_poll_count = 0; + while (DAT_GET_TYPE(dat_evd_dequeue(h_cr_evd, &event)) + == DAT_QUEUE_EMPTY) + cr_poll_count++; + } else { + ret = dat_evd_wait(h_cr_evd, CR_TIMEOUT, + 1, &event, &nmore); + if (ret != DAT_SUCCESS) { + fprintf(stderr, + " ERR: CR dat_evd_wait() %s\n", + DT_RetToString(ret)); + return ret; + } + } + + if ((event.event_number != DAT_CONNECTION_REQUEST_EVENT) && + (ud_test && event.event_number != + DAT_IB_UD_CONNECTION_REQUEST_EVENT)) { + fprintf(stderr, " Error unexpected CR event : %s\n", + DT_EventToSTr(event.event_number)); + return (DAT_ABORT); + } + + + /* use to test rdma_cma timeout logic */ +#if defined(_WIN32) || defined(_WIN64) + if (delay) { + printf(" Accept delayed by %d seconds...\n", delay); + Sleep(delay * 1000); + } +#else + if (delay) { + printf(" Accept delayed by %d seconds...\n", delay); + sleep(delay); + } +#endif + /* accept connect request from client */ + h_cr = cr_event->cr_handle; + LOGPRINTF(" Accepting connect request from client\n"); + + /* private data - check and send it back */ + dat_cr_query(h_cr, DAT_CSP_FIELD_ALL, &cr_param); + + buf = (unsigned char *)cr_param.private_data; + LOGPRINTF(" CONN REQUEST Private Data %p[0]=%d [47]=%d\n", + buf, buf[0], buf[47]); + + for (bi = 0; bi < 48; bi++) { + if (buf[bi] != bi + 1) { + fprintf(stderr, " ERR on CONNECT REQUEST" + " private data: %p[%d]=%d s/be %d\n", + buf, bi, buf[bi], bi + 1); + dat_cr_reject(h_cr, 0, NULL); + return (DAT_ABORT); + } + buf[bi]++; /* change for trip back */ + } + +#ifdef TEST_REJECT_WITH_PRIVATE_DATA + printf(" REJECT request with 48 bytes of private data\n"); + ret = dat_cr_reject(h_cr, 48, cr_param.private_data); + printf("\n DAPL Test Complete. %s\n\n", + ret ? "FAILED" : "PASSED"); + exit(0); +#endif + ret = dat_cr_accept(h_cr, h_ep[i], 48, + cr_param.private_data); + + if (ret != DAT_SUCCESS) { + fprintf(stderr, " ERR dat_cr_accept: %s\n", + DT_RetToString(ret)); + return (ret); + } else + LOGPRINTF(" accept[%d] complete\n", i); + + event.event_number = 0; + } + + /* process the RTU, ESTABLISHMENT event */ + printf(" Completing...\n"); + for (i=0;iai_addr)->sin_addr.s_addr; +#else + if (getaddrinfo(hostname, NULL, NULL, &target) != 0) { + perror("\n remote name resolution failed!"); + exit(1); + } + rval = ((struct sockaddr_in *)target->ai_addr)->sin_addr.s_addr; +#endif + printf(" Connecting to Server: %s \n", hostname); + printf(" Address: %d.%d.%d.%d port %d\n", + (rval >> 0) & 0xff, (rval >> 8) & 0xff, + (rval >> 16) & 0xff, (rval >> 24) & 0xff, + port_id); + + raddr = (DAT_IA_ADDRESS_PTR)target->ai_addr; + +no_resolution: + + for (i = 0; i < 48; i++) /* simple pattern in private data */ + pdata[i] = i + 1; + + printf(" Connecting...\n"); + start = get_time(); + for (i = 0; i < connections; i += burst) { + for (ii = 0; ii < burst; ii++) { /* conn_reqs */ + if (multi_listens) + conn_id = port_id + ii; + else + conn_id = port_id; + + ret = dat_ep_connect(h_ep[i+ii], raddr, + conn_id, CONN_TIMEOUT, + 48, (DAT_PVOID) pdata, 0, + DAT_CONNECT_DEFAULT_FLAG); + if (ret != DAT_SUCCESS) { + fprintf(stderr, " ERR dat_ep_connect: %s\n", + DT_RetToString(ret)); + return (ret); + } else + LOGPRINTF(" dat_ep_connect[%d] complete\n", + i+ii); + + } + for (ii = 0; ii < burst; ii++) { /* conn_events */ + if (!waiting) { + conn_poll_count = 0; + while (DAT_GET_TYPE(dat_evd_dequeue( + h_conn_evd, &event)) == + DAT_QUEUE_EMPTY) + conn_poll_count++; + } else { + ret = dat_evd_wait(h_conn_evd, CONN_TIMEOUT, + 1, &event, &nmore); + + if (ret != DAT_SUCCESS) { + fprintf(stderr, + " ERR: CONN evd_wait() %s\n", + DT_RetToString(ret)); + return ret; + } + } + +#ifdef TEST_REJECT_WITH_PRIVATE_DATA + if (event.event_number != + DAT_CONNECTION_EVENT_PEER_REJECTED) { + fprintf(stderr, " expected conn reject " + "event : %s\n", + DT_EventToSTr(event.event_number)); + return (DAT_ABORT); + } + + /* get the reject private data and validate */ + buf = (unsigned char *)conn_event->private_data; + printf(" Recv REJ with pdata %p[0]=%d [47]=%d\n", + buf, buf[0], buf[47]); + for (bi = 0; bi < 48; bi++) { + if (buf[bi] != idx + 2) { + fprintf(stderr, " client: Error" + " with REJECT event private" + " data: %p[%d]=%d s/be %d\n", + buf, bi, + buf[bi], bi + 2); + dat_ep_disconnect(h_ep[i+ii], 0); + return (DAT_ABORT); + } + } + printf("\n Rej Test Done. PASSED\n\n"); + exit(0); +#endif + if ((event.event_number != + DAT_CONNECTION_EVENT_ESTABLISHED) && + (ud_test && event.event_number != + DAT_IB_UD_CONNECTION_EVENT_ESTABLISHED)) { + fprintf(stderr, " Error unexpected conn " + "event : 0x%x %s\n", + event.event_number, + DT_EventToSTr(event.event_number)); + return (DAT_ABORT); + } + + /* check private data back from server */ + buf = (unsigned char *)conn_event->private_data; + + LOGPRINTF(" CONN[%d] Private Data " + "%p[0]=%d [47]=%d\n", + i+ii, buf, buf[0], buf[47]); + + for (bi = 0; bi < 48; bi++) { + if (buf[bi] != bi + 2) { + DAT_COUNT nmore; + fprintf(stderr, " ERR CONN event" + " pdata: %p[%d]=%d s/be %d\n", + buf, bi, buf[bi], + bi + 2); + dat_ep_disconnect(h_ep[i+ii], + DAT_CLOSE_ABRUPT_FLAG); + LOGPRINTF(" waiting for disc...\n"); + dat_evd_wait(h_conn_evd, + DAT_TIMEOUT_INFINITE, + 1, &event, &nmore); + return (DAT_ABORT); + } + } + event.event_number = 0; + } + } + + stop = get_time(); + ts.conn += ((stop - start) * 1.0e6); + + if (!ucm) + freeaddrinfo(target); + + printf("\n ALL %d CONNECTED on Client!\n\n", connections); + + return (DAT_SUCCESS); +} + +/* validate disconnected EP's and free them */ +DAT_RETURN disconnect_eps(void) +{ + DAT_RETURN ret; + DAT_EVENT event; + DAT_COUNT nmore; + int i,ii; + DAT_CONNECTION_EVENT_DATA *conn_event = + &event.event_data.connect_event_data; + + if (!connected) + return DAT_SUCCESS; + + /* UD, no connection to disconnect, just free EP's */ + if (ud_test) { + for (i = 0; i < connections; i++) { + ret = dat_ep_free(h_ep[i]); + if (ret != DAT_SUCCESS) { + fprintf(stderr, + " ERR free EP[%d] %p: %s\n", + i, h_ep[i], DT_RetToString(ret)); + } else { + LOGPRINTF(" Freed EP[%d] %p\n", + i, h_ep[i]); + h_ep[i] = DAT_HANDLE_NULL; + } + } + stop = get_time(); + ts.epf += ((stop - start) * 1.0e6); + ts.total += ts.epf; + return DAT_SUCCESS; + } + + /* + * Only the client needs to call disconnect. The server _should_ be able + * to just wait on the EVD associated with connection events for a + * disconnect request and then exit. + */ + if (!server) { + start = get_time(); + for (i = 0; i < connections; i++) { + LOGPRINTF(" dat_ep_disconnect\n"); + ret = dat_ep_disconnect(h_ep[i], + DAT_CLOSE_DEFAULT); + if (ret != DAT_SUCCESS) { + fprintf(stderr, + " Error disconnect: %s\n", + DT_RetToString(ret)); + return ret; + } else { + LOGPRINTF(" disconnect completed\n"); + } + } + } else { + LOGPRINTF(" Server waiting for disconnect...\n"); + } + + LOGPRINTF(" Wait for Disc event, free EPs as completed\n"); + start = get_time(); + for (i = 0; i < connections; i++) { + event.event_number = 0; + conn_event->ep_handle = NULL; + ret = dat_evd_wait(h_conn_evd, DAT_TIMEOUT_INFINITE, + 1, &event, &nmore); + if (ret != DAT_SUCCESS) { + fprintf(stderr, " Error dat_evd_wait: %s\n", + DT_RetToString(ret)); + return ret; + } else { + LOGPRINTF(" disc event[%d] complete," + " check for valid EP...\n", i); + } + + /* check for valid EP in creation list */ + for (ii = 0; ii < connections; ii++) { + if (h_ep[ii] == conn_event->ep_handle) { + LOGPRINTF(" valid EP[%d] %p !\n", + ii, h_ep[ii]); + ret = dat_ep_free(h_ep[ii]); + if (ret != DAT_SUCCESS) { + fprintf(stderr, + " ERR free EP[%d] %p: %s\n", + i, h_ep[ii], + DT_RetToString(ret)); + } else { + LOGPRINTF(" Freed EP[%d] %p\n", + i, h_ep[ii]); + h_ep[ii] = DAT_HANDLE_NULL; + } + break; + } else { + continue; + } + } + if (ii == connections) { + LOGPRINTF(" %s: invalid EP[%d] %p via DISC event!\n", + server ? "Server" : "Client", + i, conn_event->ep_handle); + return DAT_INVALID_HANDLE; + } + } + /* free EPs */ + stop = get_time(); + ts.epf += ((stop - start) * 1.0e6); + ts.total += ts.epf; + return DAT_SUCCESS; +} + + + /* + * Create CR, CONN, and DTO events + */ +DAT_RETURN create_events(void) +{ + DAT_RETURN ret; + + /* create cr EVD */ + start = get_time(); + ret = dat_evd_create(h_ia, connections, DAT_HANDLE_NULL, + DAT_EVD_CR_FLAG, &h_cr_evd); + stop = get_time(); + ts.evdc += ((stop - start) * 1.0e6); + ts.total += ts.evdc; + if (ret != DAT_SUCCESS) { + fprintf(stderr, " Error dat_evd_create: %s\n", + DT_RetToString(ret)); + return (ret); + } else { + LOGPRINTF(" cr_evd created %p\n", h_cr_evd); + } + + /* create conn EVD */ + ret = dat_evd_create(h_ia, + connections*2, + DAT_HANDLE_NULL, + DAT_EVD_CONNECTION_FLAG, &h_conn_evd); + if (ret != DAT_SUCCESS) { + fprintf(stderr, " Error dat_evd_create: %s\n", + DT_RetToString(ret)); + return (ret); + } else { + LOGPRINTF(" con_evd created %p\n", h_conn_evd); + } + + /* create dto SND EVD */ + ret = dat_evd_create(h_ia, 1, NULL, + DAT_EVD_DTO_FLAG, &h_dto_req_evd); + if (ret != DAT_SUCCESS) { + fprintf(stderr, " Error dat_evd_create REQ: %s\n", + DT_RetToString(ret)); + return (ret); + } else { + LOGPRINTF(" dto_req_evd created %p\n", + h_dto_req_evd); + } + + /* create dto RCV EVD */ + ret = dat_evd_create(h_ia, 1, NULL, + DAT_EVD_DTO_FLAG, &h_dto_rcv_evd); + if (ret != DAT_SUCCESS) { + fprintf(stderr, " Error dat_evd_create RCV: %s\n", + DT_RetToString(ret)); + return (ret); + } else { + LOGPRINTF(" dto_rcv_evd created %p\n", + h_dto_rcv_evd); + } + return DAT_SUCCESS; +} + +/* + * Destroy CR, CONN, CNO, and DTO events + */ + +DAT_RETURN destroy_events(void) +{ + DAT_RETURN ret; + + /* free cr EVD */ + if (h_cr_evd != DAT_HANDLE_NULL) { + LOGPRINTF(" Free cr EVD %p \n", h_cr_evd); + ret = dat_evd_free(h_cr_evd); + if (ret != DAT_SUCCESS) { + fprintf(stderr, " Error freeing cr EVD: %s\n", + DT_RetToString(ret)); + return (ret); + } else { + LOGPRINTF(" Freed cr EVD\n"); + h_cr_evd = DAT_HANDLE_NULL; + } + } + + /* free conn EVD */ + if (h_conn_evd != DAT_HANDLE_NULL) { + LOGPRINTF(" Free conn EVD %p\n", h_conn_evd); + ret = dat_evd_free(h_conn_evd); + if (ret != DAT_SUCCESS) { + fprintf(stderr, " Error freeing conn EVD: %s\n", + DT_RetToString(ret)); + return (ret); + } else { + LOGPRINTF(" Freed conn EVD\n"); + h_conn_evd = DAT_HANDLE_NULL; + } + } + + /* free RCV dto EVD */ + if (h_dto_rcv_evd != DAT_HANDLE_NULL) { + LOGPRINTF(" Free RCV dto EVD %p\n", h_dto_rcv_evd); + start = get_time(); + ret = dat_evd_free(h_dto_rcv_evd); + stop = get_time(); + ts.evdf += ((stop - start) * 1.0e6); + ts.total += ts.evdf; + if (ret != DAT_SUCCESS) { + fprintf(stderr, " Error freeing dto EVD: %s\n", + DT_RetToString(ret)); + return (ret); + } else { + LOGPRINTF(" Freed dto EVD\n"); + h_dto_rcv_evd = DAT_HANDLE_NULL; + } + } + + /* free REQ dto EVD */ + if (h_dto_req_evd != DAT_HANDLE_NULL) { + LOGPRINTF(" Free REQ dto EVD %p\n", h_dto_req_evd); + ret = dat_evd_free(h_dto_req_evd); + if (ret != DAT_SUCCESS) { + fprintf(stderr, " Error freeing dto EVD: %s\n", + DT_RetToString(ret)); + return (ret); + } else { + LOGPRINTF(" Freed dto EVD\n"); + h_dto_req_evd = DAT_HANDLE_NULL; + } + } + + return DAT_SUCCESS; +} + +/* + * Map DAT_RETURN values to readable strings, + * but don't assume the values are zero-based or contiguous. + */ +char errmsg[512] = { 0 }; +const char *DT_RetToString(DAT_RETURN ret_value) +{ + const char *major_msg, *minor_msg; + + dat_strerror(ret_value, &major_msg, &minor_msg); + + strcpy(errmsg, major_msg); + strcat(errmsg, " "); + strcat(errmsg, minor_msg); + + return errmsg; +} + +/* + * Map DAT_EVENT_CODE values to readable strings + */ +const char *DT_EventToSTr(DAT_EVENT_NUMBER event_code) +{ + unsigned int i; + static struct { + const char *name; + DAT_RETURN value; + } dat_events[] = { +# define DATxx(x) { # x, x } + DATxx(DAT_DTO_COMPLETION_EVENT), + DATxx(DAT_RMR_BIND_COMPLETION_EVENT), + DATxx(DAT_CONNECTION_REQUEST_EVENT), + DATxx(DAT_CONNECTION_EVENT_ESTABLISHED), + DATxx(DAT_CONNECTION_EVENT_PEER_REJECTED), + DATxx(DAT_CONNECTION_EVENT_NON_PEER_REJECTED), + DATxx(DAT_CONNECTION_EVENT_ACCEPT_COMPLETION_ERROR), + DATxx(DAT_CONNECTION_EVENT_DISCONNECTED), + DATxx(DAT_CONNECTION_EVENT_BROKEN), + DATxx(DAT_CONNECTION_EVENT_TIMED_OUT), + DATxx(DAT_CONNECTION_EVENT_UNREACHABLE), + DATxx(DAT_ASYNC_ERROR_EVD_OVERFLOW), + DATxx(DAT_ASYNC_ERROR_IA_CATASTROPHIC), + DATxx(DAT_ASYNC_ERROR_EP_BROKEN), + DATxx(DAT_ASYNC_ERROR_TIMED_OUT), + DATxx(DAT_ASYNC_ERROR_PROVIDER_INTERNAL_ERROR), + DATxx(DAT_SOFTWARE_EVENT) +# undef DATxx + }; +# define NUM_EVENTS (sizeof(dat_events)/sizeof(dat_events[0])) + + for (i = 0; i < NUM_EVENTS; i++) { + if (dat_events[i].value == event_code) { + return (dat_events[i].name); + } + } + + return ("Invalid_DAT_EVENT_NUMBER"); +} + +void print_usage(void) +{ + printf("\n DAPL USAGE \n\n"); + printf("s: server\n"); + printf("c: connections (default = 1000)\n"); + printf("v: verbose\n"); + printf("w: wait on event (default, polling)\n"); + printf("d: delay before accept\n"); + printf("h: hostname/address of server, specified on client\n"); + printf("P: provider name (default = OpenIB-v2-ib0)\n"); + printf("\n"); +} + diff --git a/branches/WOF2-3/ulp/dapl2/test/dtest/dtestx.c b/branches/WOF2-3/ulp/dapl2/test/dtest/dtestx.c new file mode 100644 index 00000000..32ffe335 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dtest/dtestx.c @@ -0,0 +1,1360 @@ +/* + * Copyright (c) 2007-2008 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: $ + */ +#include +#include + +#if defined(_WIN32) || defined(_WIN64) +#include +#include +#include +#include +#include +#include +#include "..\..\..\..\etc\user\getopt.c" +#define __BYTE_ORDER __LITTLE_ENDIAN + +#define getpid() ((int)GetCurrentProcessId()) +#define F64x "%I64x" +#define F64u "%I64u" +#define DAPL_PROVIDER "ibnic0v2" +#else +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DAPL_PROVIDER "ofa-v2-ib0" +#define F64x "%"PRIx64"" +#define F64u "%"PRIu64"" + +#endif + +#include "dat2/udat.h" +#include "dat2/dat_ib_extensions.h" + +int disconnect_ep(void); + +#define _OK(status, str) \ +{\ + const char *maj_msg, *min_msg;\ + if (status != DAT_SUCCESS) {\ + dat_strerror(status, &maj_msg, &min_msg);\ + fprintf(stderr, str " returned %s : %s\n", maj_msg, min_msg);\ + dat_ia_close(ia, DAT_CLOSE_DEFAULT);\ + exit(1);\ + } else if (verbose) {\ + printf("dtestx: %s success\n",str);\ + }\ +} + +#define _OK2(status, str)\ +{\ + const char *maj_msg, *min_msg;\ + if (status != DAT_SUCCESS) {\ + dat_strerror(status, &maj_msg, &min_msg);\ + fprintf(stderr, str " returned %s : %s\n", maj_msg, min_msg);\ + dat_ia_close(ia, DAT_CLOSE_DEFAULT);\ + exit(1);\ + } else if (verbose) {\ + printf("dtestx: %s\n",str);\ + }\ +} + +/* byte swap helpers from Complib */ +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define ntoh16(x) (uint16_t)( \ + (((uint16_t)(x) & 0x00FF) << 8) | \ + (((uint16_t)(x) & 0xFF00) >> 8)) +#define hton16(x) ntoh16(x) +#define ntoh32(x) (uint32_t)( \ + (((uint32_t)(x) & 0x000000FF) << 24)| \ + (((uint32_t)(x) & 0x0000FF00) << 8) | \ + (((uint32_t)(x) & 0x00FF0000) >> 8) | \ + (((uint32_t)(x) & 0xFF000000) >> 24)) +#define hton32(x) ntoh32(x) +#define 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)) +#define hton64(x) ntoh64(x) +#elif __BYTE_ORDER == __BIG_ENDIAN +#define hton16(x) (x) +#define ntoh16(x) (x) +#define hton32(x) (x) +#define ntoh32(x) (x) +#define hton64(x) (x) +#define ntoh64(x) (x) +#endif /* __BYTE_ORDER == __BIG_ENDIAN */ + +#define MIN(a, b) ((a < b) ? (a) : (b)) +#define MAX(a, b) ((a > b) ? (a) : (b)) + +#define DTO_TIMEOUT (1000*1000*5) +#define CONN_TIMEOUT (1000*1000*30) +#define SERVER_TIMEOUT (DAT_TIMEOUT_INFINITE) +#define CLIENT_ID 31111 +#define SERVER_ID 31112 +#define BUF_SIZE 256 +#define BUF_SIZE_ATOMIC 8 +#define REG_MEM_COUNT 10 +#define SND_RDMA_BUF_INDEX 0 +#define RCV_RDMA_BUF_INDEX 1 +#define SEND_BUF_INDEX 2 +#define RECV_BUF_INDEX 3 +#define MAX_EP_COUNT 8 + +DAT_VADDR *atomic_buf; +DAT_LMR_HANDLE lmr_atomic; +DAT_LMR_CONTEXT lmr_atomic_context; +DAT_RMR_CONTEXT rmr_atomic_context; +DAT_VLEN reg_atomic_size; +DAT_VADDR reg_atomic_addr; +DAT_LMR_HANDLE lmr[REG_MEM_COUNT * MAX_EP_COUNT]; +DAT_LMR_CONTEXT lmr_context[REG_MEM_COUNT * MAX_EP_COUNT]; +DAT_RMR_TRIPLET rmr[REG_MEM_COUNT * MAX_EP_COUNT]; +DAT_RMR_CONTEXT rmr_context[REG_MEM_COUNT * MAX_EP_COUNT]; +DAT_VLEN reg_size[REG_MEM_COUNT * MAX_EP_COUNT]; +DAT_VADDR reg_addr[REG_MEM_COUNT * MAX_EP_COUNT]; +DAT_RMR_TRIPLET *buf[REG_MEM_COUNT * MAX_EP_COUNT]; +DAT_EP_HANDLE ep[MAX_EP_COUNT]; +DAT_EVD_HANDLE async_evd = DAT_HANDLE_NULL; +DAT_IA_HANDLE ia = DAT_HANDLE_NULL; +DAT_PZ_HANDLE pz = DAT_HANDLE_NULL; +DAT_EVD_HANDLE cr_evd = DAT_HANDLE_NULL; +DAT_EVD_HANDLE con_evd = DAT_HANDLE_NULL; +DAT_EVD_HANDLE dto_evd = DAT_HANDLE_NULL; +DAT_PSP_HANDLE psp = DAT_HANDLE_NULL; +int server = 1; +int remote_host = 0; +int ud_test = 0; +int multi_eps = 0; +int buf_size = BUF_SIZE; +int msg_size = sizeof(DAT_RMR_TRIPLET); +char provider[64] = DAPL_PROVIDER; +char hostname[256] = { 0 }; +DAT_IB_ADDR_HANDLE remote_ah[MAX_EP_COUNT]; +int eps = 1; +int verbose = 0; +int counters = 0; +int counters_ok = 0; +static int ucm = 0; +static DAT_SOCK_ADDR6 remote; + +#define LOGPRINTF if (verbose) printf + +void print_usage(void) +{ + printf("\n dtestx usage \n\n"); + printf("v: verbose\n"); + printf("p: print counters\n"); + printf("u unreliable datagram test\n"); + printf("U: unreliable datagram test, UD endpoint count\n"); + printf("m unreliable datagram test, multiple Server endpoints\n"); + printf("b: buf length to allocate\n"); + printf("h: hostname/address of Server, client and UDP server\n"); + printf("c: Client\n"); + printf("s: Server, default\n"); + printf("P: provider name (default = ofa-v2-ib0)\n"); + printf("\n"); +} + +#if defined(_WIN32) || defined(_WIN64) +static void sleep(int secs) +{ + Sleep(secs * 1000); +} + +#define _WSACleanup() WSACleanup() +#else +#define _WSACleanup() +#endif + +static void print_ia_address(struct sockaddr *sa) +{ + char str[INET6_ADDRSTRLEN] = {" ??? "}; + + switch(sa->sa_family) { + case AF_INET: + inet_ntop(AF_INET, &((struct sockaddr_in *)sa)->sin_addr, str, INET6_ADDRSTRLEN); + printf("%d Local Address AF_INET - %s port %d\n", getpid(), str, SERVER_ID); + break; + case AF_INET6: + inet_ntop(AF_INET6, &((struct sockaddr_in6 *)sa)->sin6_addr, str, INET6_ADDRSTRLEN); + printf("%d Local Address AF_INET6 - %s flowinfo(QPN)=0x%x, port(LID)=0x%x\n", + getpid(), str, + ntohl(((struct sockaddr_in6 *)sa)->sin6_flowinfo), + ntohs(((struct sockaddr_in6 *)sa)->sin6_port)); + break; + default: + printf("%d Local Address UNKOWN FAMILY - port %d\n", getpid(), SERVER_ID); + } +} + +void +send_msg(void *data, + DAT_COUNT size, + DAT_LMR_CONTEXT context, + DAT_DTO_COOKIE cookie, DAT_COMPLETION_FLAGS flags) +{ + DAT_LMR_TRIPLET iov; + DAT_EVENT event; + DAT_COUNT nmore; + DAT_RETURN status; + int i, ep_idx = 0, ah_idx = 0; + DAT_DTO_COMPLETION_EVENT_DATA *dto_event = + &event.event_data.dto_completion_event_data; + + iov.lmr_context = context; + iov.virtual_address = (DAT_VADDR) (uintptr_t) data; + iov.segment_length = (DAT_VLEN) size; + + for (i = 0; i < eps; i++) { + if (ud_test) { + /* + * Client and Server: ep[0] and ah[0] on single + * and ep[i] on multiple (-m) endpoint options. + */ + if (multi_eps) { + ep_idx = i; + ah_idx = server ? 0 : i; + } + printf("%s sending on ep=%p to remote_ah: ah=%p" + " qpn=0x%x addr=%s\n", + server ? "Server" : "Client", ep[ep_idx], + remote_ah[ah_idx].ah, + remote_ah[ah_idx].qpn, + inet_ntoa(((struct sockaddr_in *) + &remote_ah[ah_idx].ia_addr)-> + sin_addr)); + + /* client expects all data in on first EP */ + status = dat_ib_post_send_ud(ep[ep_idx], + 1, + &iov, + &remote_ah[ah_idx], + cookie, flags); + + } else { + status = dat_ep_post_send(ep[0], 1, &iov, + cookie, flags); + } + _OK(status, "dat_ep_post_send"); + + if (!(flags & DAT_COMPLETION_SUPPRESS_FLAG)) { + status = dat_evd_wait(dto_evd, DTO_TIMEOUT, + 1, &event, &nmore); + _OK(status, "dat_evd_wait after dat_ep_post_send"); + + if (event.event_number != DAT_DTO_COMPLETION_EVENT && + ud_test && event.event_number != DAT_IB_DTO_EVENT) { + printf("unexpected event waiting post_send " + "completion - 0x%x\n", + event.event_number); + exit(1); + } + _OK(dto_event->status, "event status for post_send"); + } + } +} + +/* RC - Server only, UD - Server and Client, one per EP */ +void process_cr(int idx) +{ + DAT_EVENT event; + DAT_COUNT nmore; + DAT_RETURN status; + int pdata; + DAT_CR_HANDLE cr = DAT_HANDLE_NULL; + DAT_CONN_QUAL exp_qual = server ? SERVER_ID : CLIENT_ID; + DAT_CR_PARAM cr_param; + DAT_CR_ARRIVAL_EVENT_DATA *cr_event = + &event.event_data.cr_arrival_event_data; + + LOGPRINTF("%s waiting for connect[%d] request\n", + server ? "Server" : "Client", idx); + + status = dat_evd_wait(cr_evd, SERVER_TIMEOUT, 1, &event, &nmore); + _OK(status, "CR dat_evd_wait"); + + if (event.event_number != DAT_CONNECTION_REQUEST_EVENT && + (ud_test && event.event_number != + DAT_IB_UD_CONNECTION_REQUEST_EVENT)) { + printf("unexpected event,!conn req: 0x%x\n", + event.event_number); + exit(1); + } + + if ((cr_event->conn_qual != exp_qual) || + (cr_event->sp_handle.psp_handle != psp)) { + printf("wrong cr event data\n"); + exit(1); + } + + cr = cr_event->cr_handle; + status = dat_cr_query(cr, DAT_CSP_FIELD_ALL, &cr_param); + _OK(status, "dat_cr_query"); + + /* use private data to select EP */ + pdata = ntoh32(*((int *)cr_param.private_data)); + + LOGPRINTF("%s recvd pdata=0x%x, send pdata=0x%x\n", + server ? "Server" : "Client", pdata, + *(int *)cr_param.private_data); + + status = dat_cr_accept(cr, ep[pdata], 4, cr_param.private_data); + _OK(status, "dat_cr_accept"); + + printf("%s accepted CR on EP[%d]=%p\n", + server ? "Server" : "Client", pdata, ep[pdata]); +} + +/* RC - Client and Server: 1, UD - Client: 1 per EP, Server: 2 per EP's */ +void process_conn(int idx) +{ + DAT_EVENT event; + DAT_COUNT nmore; + DAT_RETURN status; + int pdata, exp_event; + DAT_IB_EXTENSION_EVENT_DATA *ext_event = (DAT_IB_EXTENSION_EVENT_DATA *) + & event.event_extension_data[0]; + DAT_CONNECTION_EVENT_DATA *conn_event = + &event.event_data.connect_event_data; + + LOGPRINTF("%s waiting for connect[%d] establishment\n", + server ? "Server" : "Client", idx); + + status = dat_evd_wait(con_evd, CONN_TIMEOUT, 1, &event, &nmore); + _OK(status, "CONN dat_evd_wait"); + + LOGPRINTF("%s got connect[%d] event 0x%x, pdata %p sz=%d\n", + server ? "Server" : "Client", idx, + event.event_number, conn_event->private_data, + conn_event->private_data_size); + + if (ud_test) + exp_event = DAT_IB_UD_CONNECTION_EVENT_ESTABLISHED; + else + exp_event = DAT_CONNECTION_EVENT_ESTABLISHED; + + /* Waiting on CR's or CONN_EST */ + if (event.event_number != exp_event || + (ud_test && event.event_number != + DAT_IB_UD_CONNECTION_EVENT_ESTABLISHED)) { + printf("unexpected event, !conn established: 0x%x\n", + event.event_number); + exit(1); + } + + /* RC or PASSIVE CONN_EST we are done */ + if (!ud_test) + return; + + /* store each remote_ah according to remote EP index */ + pdata = ntoh32(*((int *)conn_event->private_data)); + LOGPRINTF(" Client got private data=0x%x\n", pdata); + + /* UD, get AH for sends. + * NOTE: bi-directional AH resolution results in a CONN_EST + * for both outbound connect and inbound CR. + * Use Active CONN_EST which includes server's CR + * pdata for remote_ah idx to send on and ignore PASSIVE CONN_EST. + * + * DAT_IB_UD_PASSIVE_REMOTE_AH == passive side CONN_EST + * DAT_IB_UD_REMOTE_AH == active side CONN_EST + */ + if (ext_event->type == DAT_IB_UD_REMOTE_AH) { + remote_ah[pdata] = ext_event->remote_ah; + printf("remote_ah[%d]: ah=%p, qpn=0x%x " + "addr=%s\n", + pdata, remote_ah[pdata].ah, + remote_ah[pdata].qpn, inet_ntoa(((struct sockaddr_in *) + &remote_ah[pdata]. + ia_addr)->sin_addr)); + + } else if (ext_event->type != DAT_IB_UD_PASSIVE_REMOTE_AH) { + printf("unexpected UD ext_event type: 0x%x\n", ext_event->type); + exit(1); + } +} + +int connect_ep(char *hostname) +{ + DAT_IA_ADDRESS_PTR remote_addr = (DAT_IA_ADDRESS_PTR)&remote; + DAT_EP_ATTR ep_attr; + DAT_IA_ATTR ia_attr; + DAT_RETURN status; + DAT_REGION_DESCRIPTION region; + DAT_EVENT event; + DAT_COUNT nmore; + DAT_LMR_TRIPLET iov; + DAT_RMR_TRIPLET *r_iov; + DAT_DTO_COOKIE cookie; + DAT_CONN_QUAL conn_qual; + DAT_BOOLEAN in, out; + int i, ii, pdata, ctx; + DAT_PROVIDER_ATTR prov_attrs; + DAT_DTO_COMPLETION_EVENT_DATA *dto_event = + &event.event_data.dto_completion_event_data; + + status = dat_ia_open(provider, 8, &async_evd, &ia); + _OK(status, "dat_ia_open"); + + memset(&prov_attrs, 0, sizeof(prov_attrs)); + status = dat_ia_query(ia, NULL, + DAT_IA_FIELD_ALL, &ia_attr, + DAT_PROVIDER_FIELD_ALL, &prov_attrs); + _OK(status, "dat_ia_query"); + + print_ia_address(ia_attr.ia_address_ptr); + + if (ucm && ud_test) { + printf("%d UD test over UCM provider not supported\n", + getpid()); + exit(1); + } + + /* Print provider specific attributes */ + for (i = 0; i < prov_attrs.num_provider_specific_attr; i++) { + LOGPRINTF(" Provider Specific Attribute[%d] %s=%s\n", + i, prov_attrs.provider_specific_attr[i].name, + prov_attrs.provider_specific_attr[i].value); + + /* check for counter support */ + status = strcmp(prov_attrs.provider_specific_attr[i].name, + "DAT_COUNTERS"); + if (!status) + counters_ok = 1; + } + + /* make sure provider supports counters */ + if ((counters) && (!counters_ok)) { + printf("Disable dat_query_counters:" + " Provider not built with counters\n"); + counters = 0; + } + + status = dat_pz_create(ia, &pz); + _OK(status, "dat_pz_create"); + + status = dat_evd_create(ia, eps * 2, DAT_HANDLE_NULL, DAT_EVD_CR_FLAG, + &cr_evd); + _OK(status, "dat_evd_create CR"); + status = dat_evd_create(ia, eps * 2, DAT_HANDLE_NULL, + DAT_EVD_CONNECTION_FLAG, &con_evd); + _OK(status, "dat_evd_create CR"); + status = dat_evd_create(ia, eps * 10, DAT_HANDLE_NULL, DAT_EVD_DTO_FLAG, + &dto_evd); + _OK(status, "dat_evd_create DTO"); + + memset(&ep_attr, 0, sizeof(ep_attr)); + if (ud_test) { + msg_size += 40; + ep_attr.service_type = DAT_IB_SERVICE_TYPE_UD; + ep_attr.max_message_size = buf_size; + ep_attr.max_rdma_read_in = 0; + ep_attr.max_rdma_read_out = 0; + } else { + ep_attr.service_type = DAT_SERVICE_TYPE_RC; + ep_attr.max_rdma_size = 0x10000; + ep_attr.max_rdma_read_in = 4; + ep_attr.max_rdma_read_out = 4; + } + ep_attr.qos = 0; + ep_attr.recv_completion_flags = 0; + ep_attr.max_recv_dtos = eps * 10; + ep_attr.max_request_dtos = eps * 10; + ep_attr.max_recv_iov = 1; + ep_attr.max_request_iov = 1; + ep_attr.request_completion_flags = DAT_COMPLETION_DEFAULT_FLAG; + ep_attr.ep_transport_specific_count = 0; + ep_attr.ep_transport_specific = NULL; + ep_attr.ep_provider_specific_count = 0; + ep_attr.ep_provider_specific = NULL; + + for (i = 0; i < eps; i++) { + status = dat_ep_create(ia, pz, dto_evd, dto_evd, + con_evd, &ep_attr, &ep[i]); + _OK(status, "dat_ep_create"); + LOGPRINTF(" create_ep[%d]=%p\n", i, ep[i]); + } + + for (i = 0; i < REG_MEM_COUNT * eps; i++) { + buf[i] = (DAT_RMR_TRIPLET *) malloc(buf_size); + region.for_va = buf[i]; + status = dat_lmr_create(ia, + DAT_MEM_TYPE_VIRTUAL, + region, + buf_size, + pz, + DAT_MEM_PRIV_ALL_FLAG | + DAT_IB_MEM_PRIV_REMOTE_ATOMIC, + DAT_VA_TYPE_VA, + &lmr[i], + &lmr_context[i], + &rmr_context[i], + ®_size[i], ®_addr[i]); + _OK(status, "dat_lmr_create"); + } + + /* register atomic return buffer for original data */ + atomic_buf = (DAT_UINT64 *) malloc(BUF_SIZE_ATOMIC); + region.for_va = atomic_buf; + status = dat_lmr_create(ia, + DAT_MEM_TYPE_VIRTUAL, + region, + BUF_SIZE_ATOMIC, + pz, + DAT_MEM_PRIV_ALL_FLAG | + DAT_IB_MEM_PRIV_REMOTE_ATOMIC, + DAT_VA_TYPE_VA, + &lmr_atomic, + &lmr_atomic_context, + &rmr_atomic_context, + ®_atomic_size, ®_atomic_addr); + _OK(status, "dat_lmr_create atomic"); + + for (ii = 0; ii < eps; ii++) { + for (i = RECV_BUF_INDEX; i < REG_MEM_COUNT; i++) { + int ep_idx = 0; + cookie.as_64 = (ii * REG_MEM_COUNT) + i; + iov.lmr_context = lmr_context[(ii * REG_MEM_COUNT) + i]; + iov.virtual_address = + (DAT_VADDR) (uintptr_t) buf[(ii * REG_MEM_COUNT) + + i]; + iov.segment_length = buf_size; + LOGPRINTF(" post_recv (%p) on ep[%d]=%p\n", + buf[(ii * REG_MEM_COUNT) + i], ii, ep[ii]); + /* ep[0], unless testing Server and multi EP's */ + if (server && multi_eps) { + ep_idx = ii; + cookie.as_64 = i; + } + status = dat_ep_post_recv(ep[ep_idx], + 1, + &iov, + cookie, + DAT_COMPLETION_DEFAULT_FLAG); + _OK(status, "dat_ep_post_recv"); + } + } + /* setup receive buffer to initial string to be overwritten */ + strcpy((char *)buf[RCV_RDMA_BUF_INDEX], "blah, blah, blah\n"); + + /* ud can resolve_ah and connect both ways, same EP */ + if (server || (!server && ud_test)) { + if (server) { + conn_qual = SERVER_ID; + strcpy((char *)buf[SND_RDMA_BUF_INDEX], "Server data"); + } else { + conn_qual = CLIENT_ID; + strcpy((char *)buf[SND_RDMA_BUF_INDEX], "Client data"); + } + status = dat_psp_create(ia, + conn_qual, + cr_evd, DAT_PSP_CONSUMER_FLAG, &psp); + _OK(status, "dat_psp_create"); + + /* Server always waits for first CR from Client */ + if (server) + process_cr(0); + + } + + /* ud can resolve_ah and connect both ways */ + if (!server || (server && ud_test)) { + struct addrinfo *target; + + if (ucm) + goto no_resolution; + + if (getaddrinfo(hostname, NULL, NULL, &target) != 0) { + printf("Error getting remote address.\n"); + exit(1); + } + + printf("Remote %s Name: %s \n", + server ? "Client" : "Server", hostname); + printf("Remote %s Net Address: %s\n", + server ? "Client" : "Server", + inet_ntoa(((struct sockaddr_in *) + target->ai_addr)->sin_addr)); + + strcpy((char *)buf[SND_RDMA_BUF_INDEX], "Client written data"); + + remote_addr = (DAT_IA_ADDRESS_PTR)target->ai_addr; /* IP */ +no_resolution: + + /* one Client EP, multiple Server EPs, same conn_qual + * use private data to select EP on Server + */ + for (i = 0; i < eps; i++) { + /* pdata selects Server EP, + * support both muliple Server and single EP's + */ + if (multi_eps) + pdata = hton32(i); + else + pdata = 0; /* just use first EP */ + + status = dat_ep_connect(ep[0], + remote_addr, + (server ? CLIENT_ID : + SERVER_ID), CONN_TIMEOUT, 4, + (DAT_PVOID) & pdata, 0, + DAT_CONNECT_DEFAULT_FLAG); + _OK(status, "dat_ep_connect"); + } + + if (!ucm) + freeaddrinfo(target); + } + + /* UD: process CR's starting with 2nd on server, 1st for client */ + if (ud_test) { + for (i = (server ? 1 : 0); i < eps; i++) + process_cr(i); + } + + /* RC and UD: process CONN EST events */ + for (i = 0; i < eps; i++) + process_conn(i); + + /* UD: CONN EST events for CONN's and CR's */ + if (ud_test) { + for (i = 0; i < eps; i++) + process_conn(i); + } + + printf("Connected! %d endpoints\n", eps); + + /* + * Setup our remote memory and tell the other side about it + * Swap to network order. + */ + r_iov = (DAT_RMR_TRIPLET *) buf[SEND_BUF_INDEX]; + r_iov->rmr_context = hton32(rmr_context[RCV_RDMA_BUF_INDEX]); + r_iov->virtual_address = + hton64((DAT_VADDR) (uintptr_t) buf[RCV_RDMA_BUF_INDEX]); + r_iov->segment_length = hton32(buf_size); + + printf("Send RMR message: r_key_ctx=0x%x,va=" F64x ",len=0x%x\n", + hton32(r_iov->rmr_context), + hton64(r_iov->virtual_address), hton32(r_iov->segment_length)); + + send_msg(buf[SEND_BUF_INDEX], + sizeof(DAT_RMR_TRIPLET), + lmr_context[SEND_BUF_INDEX], + cookie, DAT_COMPLETION_SUPPRESS_FLAG); + + dat_ep_get_status(ep[0], NULL, &in, &out); + printf("EP[0] status: posted buffers: Req=%d, Rcv=%d\n", in, out); + + /* + * Wait for their RMR + */ + for (i = 0, ctx = 0; i < eps; i++, ctx++) { + /* expected cookie, recv buf idx in every mem pool */ + ctx = (ctx % REG_MEM_COUNT) ? ctx : ctx + RECV_BUF_INDEX; + LOGPRINTF("Waiting for remote to send RMR data\n"); + + status = dat_evd_wait(dto_evd, DTO_TIMEOUT, 1, &event, &nmore); + _OK(status, "dat_evd_wait after dat_ep_post_send"); + + if ((event.event_number != DAT_DTO_COMPLETION_EVENT) && + (ud_test && event.event_number != DAT_IB_DTO_EVENT)) { + printf("unexpected event waiting for RMR context " + "- 0x%x\n", event.event_number); + exit(1); + } + _OK(dto_event->status, "event status for post_recv"); + + /* careful when checking cookies: + * Client - receiving multi messages on a single EP + * Server - not receiving on multiple EP's + */ + if (!server || (server && !multi_eps)) { + if (dto_event->transfered_length != msg_size || + dto_event->user_cookie.as_64 != ctx) { + printf("unexpected event data on recv: len=%d" + " cookie=" F64x " expected %d/%d\n", + (int)dto_event->transfered_length, + dto_event->user_cookie.as_64, + msg_size, ctx); + exit(1); + } + /* Server - receiving one message each across many EP's */ + } else { + if (dto_event->transfered_length != msg_size || + dto_event->user_cookie.as_64 != RECV_BUF_INDEX) { + printf("unexpected event data on recv: len=%d" + "cookie=" F64x " expected %d/%d\n", + (int)dto_event->transfered_length, + dto_event->user_cookie.as_64, + msg_size, RECV_BUF_INDEX); + exit(1); + } + } + + /* swap RMR,address info to host order */ + if (!server || (server && !multi_eps)) + r_iov = (DAT_RMR_TRIPLET *) buf[ctx]; + else + r_iov = + (DAT_RMR_TRIPLET *) buf[(i * REG_MEM_COUNT) + + RECV_BUF_INDEX]; + + if (ud_test) + r_iov = (DAT_RMR_TRIPLET *) ((char *)r_iov + 40); + + r_iov->rmr_context = ntoh32(r_iov->rmr_context); + r_iov->virtual_address = ntoh64(r_iov->virtual_address); + r_iov->segment_length = ntoh32(r_iov->segment_length); + + printf("Recv RMR message: r_iov(%p):" + " r_key_ctx=%x,va=" F64x ",len=0x%x on EP=%p\n", + r_iov, r_iov->rmr_context, + r_iov->virtual_address, + r_iov->segment_length, dto_event->ep_handle); + } + return (0); +} + +int disconnect_ep(void) +{ + DAT_RETURN status; + DAT_EVENT event; + DAT_COUNT nmore; + int i; + + if (counters) { /* examples of query and print */ + int ii; + DAT_UINT64 ia_cntrs[DCNT_IA_ALL_COUNTERS]; + + dat_query_counters(ia, DCNT_IA_ALL_COUNTERS, ia_cntrs, 0); + printf(" IA Cntrs:"); + for (ii = 0; ii < DCNT_IA_ALL_COUNTERS; ii++) + printf(" " F64u "", ia_cntrs[ii]); + printf("\n"); + dat_print_counters(ia, DCNT_IA_ALL_COUNTERS, 0); + } + + if (!ud_test) { + status = dat_ep_disconnect(ep[0], DAT_CLOSE_DEFAULT); + _OK2(status, "dat_ep_disconnect"); + + status = dat_evd_wait(con_evd, DAT_TIMEOUT_INFINITE, 1, + &event, &nmore); + _OK(status, "dat_evd_wait"); + } + if (psp) { + status = dat_psp_free(psp); + _OK2(status, "dat_psp_free"); + } + for (i = 0; i < REG_MEM_COUNT * eps; i++) { + status = dat_lmr_free(lmr[i]); + _OK2(status, "dat_lmr_free"); + } + if (lmr_atomic) { + status = dat_lmr_free(lmr_atomic); + _OK2(status, "dat_lmr_free_atomic"); + } + for (i = 0; i < eps; i++) { + if (counters) { /* examples of query and print */ + int ii; + DAT_UINT64 ep_cntrs[DCNT_EP_ALL_COUNTERS]; + + dat_query_counters(ep[i], DCNT_EP_ALL_COUNTERS, + ep_cntrs, 0); + printf(" EP[%d] Cntrs:", i); + for (ii = 0; ii < DCNT_EP_ALL_COUNTERS; ii++) + printf(" " F64u "", ep_cntrs[ii]); + printf("\n"); + dat_print_counters(ep[i], DCNT_EP_ALL_COUNTERS, 0); + } + status = dat_ep_free(ep[i]); + _OK2(status, "dat_ep_free"); + } + if (counters) { /* examples of query and print */ + int ii; + DAT_UINT64 evd_cntrs[DCNT_EVD_ALL_COUNTERS]; + + dat_query_counters(dto_evd, DCNT_EVD_ALL_COUNTERS, + evd_cntrs, 0); + printf(" DTO_EVD Cntrs:"); + for (ii = 0; ii < DCNT_EVD_ALL_COUNTERS; ii++) + printf(" " F64u "", evd_cntrs[ii]); + printf("\n"); + dat_print_counters(dto_evd, DCNT_EVD_ALL_COUNTERS, 0); + + dat_query_counters(con_evd, DCNT_EVD_ALL_COUNTERS, + evd_cntrs, 0); + printf(" CONN_EVD Cntrs:"); + for (ii = 0; ii < DCNT_EVD_ALL_COUNTERS; ii++) + printf(" " F64u "", evd_cntrs[ii]); + printf("\n"); + dat_print_counters(con_evd, DCNT_EVD_ALL_COUNTERS, 0); + + dat_query_counters(cr_evd, DCNT_EVD_ALL_COUNTERS, evd_cntrs, 0); + printf(" CR_EVD Cntrs:"); + for (ii = 0; ii < DCNT_EVD_ALL_COUNTERS; ii++) + printf(" " F64u "", evd_cntrs[ii]); + printf("\n"); + dat_print_counters(cr_evd, DCNT_EVD_ALL_COUNTERS, 0); + } + status = dat_evd_free(dto_evd); + _OK2(status, "dat_evd_free DTO"); + + status = dat_evd_free(con_evd); + _OK2(status, "dat_evd_free CON"); + + status = dat_evd_free(cr_evd); + _OK2(status, "dat_evd_free CR"); + + status = dat_pz_free(pz); + _OK2(status, "dat_pz_free"); + + status = dat_ia_close(ia, DAT_CLOSE_DEFAULT); + _OK2(status, "dat_ia_close"); + + return (0); +} + +int do_immediate() +{ + DAT_EVENT event; + DAT_COUNT nmore; + DAT_LMR_TRIPLET iov; + DAT_RMR_TRIPLET r_iov; + DAT_DTO_COOKIE cookie; + DAT_RETURN status; + DAT_UINT32 immed_data; + DAT_UINT32 immed_data_recv = 0; + DAT_DTO_COMPLETION_EVENT_DATA *dto_event = + &event.event_data.dto_completion_event_data; + DAT_IB_EXTENSION_EVENT_DATA *ext_event = + (DAT_IB_EXTENSION_EVENT_DATA *) & event.event_extension_data[0]; + + printf("\nDoing RDMA WRITE IMMEDIATE DATA\n"); + + if (server) { + immed_data = 0x1111; + } else { + immed_data = 0x7777; + } + + cookie.as_64 = 0x5555; + + /* RMR info already swapped back to host order in connect_ep */ + r_iov = *buf[RECV_BUF_INDEX]; + + iov.lmr_context = lmr_context[SND_RDMA_BUF_INDEX]; + iov.virtual_address = (DAT_VADDR) (uintptr_t) buf[SND_RDMA_BUF_INDEX]; + iov.segment_length = buf_size; + + cookie.as_64 = 0x9999; + + status = dat_ib_post_rdma_write_immed(ep[0], // ep_handle + 1, // segments + &iov, // LMR + cookie, // user_cookie + &r_iov, // RMR + immed_data, + DAT_COMPLETION_DEFAULT_FLAG); + _OK(status, "dat_ib_post_rdma_write_immed"); + + /* + * Collect first event, write completion or inbound recv with immed + */ + status = dat_evd_wait(dto_evd, DTO_TIMEOUT, 1, &event, &nmore); + _OK(status, "dat_evd_wait after dat_ib_post_rdma_write"); + if (event.event_number != DAT_IB_DTO_EVENT) { + printf("unexpected event #0x%x waiting for WR-IMMED #0x%x\n", + event.event_number, DAT_IB_DTO_EVENT); + exit(1); + } + + if (nmore) + printf("%s() nmore %d\n", __FUNCTION__, nmore); + _OK(dto_event->status, "DTO event status"); + if (ext_event->type == DAT_IB_RDMA_WRITE_IMMED) { + if ((dto_event->transfered_length != buf_size) || + (dto_event->user_cookie.as_64 != 0x9999)) { + printf + ("unexpected event data for rdma_write_immed: len=%d " + "cookie=0x%x\n", (int)dto_event->transfered_length, + (int)dto_event->user_cookie.as_64); + exit(1); + } + } else if (ext_event->type == DAT_IB_RDMA_WRITE_IMMED_DATA) { + if ((dto_event->transfered_length != buf_size) || + (dto_event->user_cookie.as_64 != RECV_BUF_INDEX + 1)) { + printf + ("unexpected event data of immediate write: len=%d " + "cookie=" F64x " expected %d/%d\n", + (int)dto_event->transfered_length, + dto_event->user_cookie.as_64, (int)sizeof(int), + RECV_BUF_INDEX + 1); + exit(1); + } + + /* get immediate data from event */ + immed_data_recv = ext_event->val.immed.data; + } else { + printf("unexpected extension type for event - 0x%x, 0x%x\n", + event.event_number, ext_event->type); + exit(1); + } + + /* + * Collect second event, write completion or inbound recv with immed + */ + status = dat_evd_wait(dto_evd, DTO_TIMEOUT, 1, &event, &nmore); + _OK(status, "dat_evd_wait after dat_ib_post_rdma_write"); + if (event.event_number != DAT_IB_DTO_EVENT) { + printf("unexpected event # waiting for WR-IMMED - 0x%x\n", + event.event_number); + exit(1); + } + + _OK(dto_event->status, "event status"); + if (ext_event->type == DAT_IB_RDMA_WRITE_IMMED) { + if ((dto_event->transfered_length != buf_size) || + (dto_event->user_cookie.as_64 != 0x9999)) { + printf + ("unexpected event data for rdma_write_immed: len=%d " + "cookie=0x%x\n", (int)dto_event->transfered_length, + (int)dto_event->user_cookie.as_64); + exit(1); + } + } else if (ext_event->type == DAT_IB_RDMA_WRITE_IMMED_DATA) { + if ((dto_event->transfered_length != buf_size) || + (dto_event->user_cookie.as_64 != RECV_BUF_INDEX + 1)) { + printf + ("unexpected event data of immediate write: len=%d " + "cookie=" F64x " expected %d/%d\n", + (int)dto_event->transfered_length, + dto_event->user_cookie.as_64, (int)sizeof(int), + RECV_BUF_INDEX + 1); + exit(1); + } + + /* get immediate data from event */ + immed_data_recv = ext_event->val.immed.data; + } else { + printf("unexpected extension type for event - 0x%x, 0x%x\n", + event.event_number, ext_event->type); + exit(1); + } + + if ((server) && (immed_data_recv != 0x7777)) { + printf("ERROR: Server: unexpected imm_data_recv 0x%x/0x%x\n", + 0x7777, immed_data_recv); + exit(1); + } else if ((!server) && (immed_data_recv != 0x1111)) { + printf("ERROR: Client: unexpected imm_data_recv 0x%x/0x%x\n", + 0x1111, immed_data_recv); + exit(1); + } + + if (server) + printf("Server received immed_data=0x%x\n", immed_data_recv); + else + printf("Client received immed_data=0x%x\n", immed_data_recv); + + printf("rdma buffer %p contains: %s\n", + buf[RCV_RDMA_BUF_INDEX], (char *)buf[RCV_RDMA_BUF_INDEX]); + + printf("\n RDMA_WRITE_WITH_IMMEDIATE_DATA test - PASSED\n"); + return (0); +} + +int do_cmp_swap() +{ + DAT_DTO_COOKIE cookie; + DAT_RETURN status; + DAT_EVENT event; + DAT_COUNT nmore; + DAT_LMR_TRIPLET l_iov; + DAT_RMR_TRIPLET r_iov; + volatile DAT_UINT64 *target = (DAT_UINT64 *) buf[RCV_RDMA_BUF_INDEX]; + DAT_DTO_COMPLETION_EVENT_DATA *dto_event = + &event.event_data.dto_completion_event_data; + DAT_IB_EXTENSION_EVENT_DATA *ext_event = + (DAT_IB_EXTENSION_EVENT_DATA *) & event.event_extension_data[0]; + + printf("\nDoing CMP and SWAP\n"); + + /* RMR info already swapped back to host order in connect_ep */ + r_iov = *buf[RECV_BUF_INDEX]; + + l_iov.lmr_context = lmr_atomic_context; + l_iov.virtual_address = (DAT_UINT64) (uintptr_t) atomic_buf; + l_iov.segment_length = BUF_SIZE_ATOMIC; + + cookie.as_64 = 3333; + + if (server) { + *target = 0x12345; + sleep(1); + /* Server does not compare and should not swap */ + printf("dtx svr - starting cmp_swap\n"); + status = dat_ib_post_cmp_and_swap(ep[0], + (DAT_UINT64) 0x654321, + (DAT_UINT64) 0x6789A, + &l_iov, + cookie, + &r_iov, + DAT_COMPLETION_DEFAULT_FLAG); + printf("dtx svr - done cmp_swap, chk status\n"); + } else { + *target = 0x54321; + sleep(1); + printf("dtx cli - starting cmp_swap\n"); + /* Client does compare and should swap */ + status = dat_ib_post_cmp_and_swap(ep[0], + (DAT_UINT64) 0x12345, + (DAT_UINT64) 0x98765, + &l_iov, + cookie, + &r_iov, + DAT_COMPLETION_DEFAULT_FLAG); + printf("dtx cli - done cmp_swap, chk status\n"); + } + _OK(status, "dat_ib_post_cmp_and_swap"); + status = dat_evd_wait(dto_evd, DTO_TIMEOUT, 1, &event, &nmore); + _OK(status, "dat_evd_wait for compare and swap"); + if (event.event_number != DAT_IB_DTO_EVENT) { + printf("unexpected event after post_cmp_and_swap: 0x%x\n", + event.event_number); + exit(1); + } + + _OK(dto_event->status, "event status for CMP and SWAP"); + if (ext_event->type != DAT_IB_CMP_AND_SWAP) { + printf("unexpected event data of cmp_swap: type=%d cookie=%d " + "original " F64x "\n", + (int)ext_event->type, + (int)dto_event->user_cookie.as_64, *atomic_buf); + exit(1); + } + + sleep(2); /* wait for other side to complete swap */ + + if (server) { + printf("Server got original data = " F64x ", expected " + "0x54321\n", *atomic_buf); + printf("Client final result (on Server) = " F64x ", expected " + "0x98765\n", *target); + + if (*atomic_buf != 0x54321 || *target != 0x98765) { + printf("ERROR: Server CMP_SWAP\n"); + exit(1); + } + } else { + printf("Client got original data = " F64x ", expected " + "0x12345\n", *atomic_buf); + printf("Server final result (on Client) = 0x" F64x ", expected " + "0x54321\n", *target); + + if (*atomic_buf != 0x12345 || *target != 0x54321) { + printf("ERROR: Client CMP_SWAP\n"); + exit(1); + } + } + printf("\n CMP_SWAP test - PASSED\n"); + return (0); +} + +int do_fetch_add() +{ + DAT_DTO_COOKIE cookie; + DAT_RETURN status; + DAT_EVENT event; + DAT_COUNT nmore; + DAT_LMR_TRIPLET l_iov; + DAT_RMR_TRIPLET r_iov; + volatile DAT_UINT64 *target = (DAT_UINT64 *) buf[RCV_RDMA_BUF_INDEX]; + DAT_DTO_COMPLETION_EVENT_DATA *dto_event = + &event.event_data.dto_completion_event_data; + DAT_IB_EXTENSION_EVENT_DATA *ext_event = + (DAT_IB_EXTENSION_EVENT_DATA *) & event.event_extension_data[0]; + + printf("\nDoing FETCH and ADD\n"); + + /* RMR info already swapped back to host order in connect_ep */ + r_iov = *buf[RECV_BUF_INDEX]; + + l_iov.lmr_context = lmr_atomic_context; + l_iov.virtual_address = (DAT_UINT64) (uintptr_t) atomic_buf; + l_iov.segment_length = BUF_SIZE_ATOMIC; + + cookie.as_64 = 0x7777; + if (server) { + /* Wait for Client to finish cmp_swap */ + while (*target != 0x98765) + sleep(1); + *target = 0x10; + sleep(1); + status = dat_ib_post_fetch_and_add(ep[0], + (DAT_UINT64) 0x100, + &l_iov, + cookie, + &r_iov, + DAT_COMPLETION_DEFAULT_FLAG); + } else { + /* Wait for Server, no swap so nothing to check */ + *target = 0x100; + sleep(1); + status = dat_ib_post_fetch_and_add(ep[0], + (DAT_UINT64) 0x10, + &l_iov, + cookie, + &r_iov, + DAT_COMPLETION_DEFAULT_FLAG); + } + _OK(status, "dat_ib_post_fetch_and_add"); + status = dat_evd_wait(dto_evd, DTO_TIMEOUT, 1, &event, &nmore); + _OK(status, "dat_evd_wait for fetch and add"); + if (event.event_number != DAT_IB_DTO_EVENT) { + printf("unexpected event after post_fetch_and_add: 0x%x\n", + event.event_number); + exit(1); + } + + _OK(dto_event->status, "event status for FETCH and ADD"); + if (ext_event->type != DAT_IB_FETCH_AND_ADD) { + printf("unexpected event data of fetch and add : type=%d " + "cookie=%d original%d\n", + (int)ext_event->type, + (int)dto_event->user_cookie.as_64, (int)*atomic_buf); + exit(1); + } + + if (server) { + printf("Client original data (on Server) = " F64x ", expected " + "0x100\n", *atomic_buf); + } else { + printf("Server original data (on Client) = " F64x ", expected " + "0x10\n", *atomic_buf); + } + + sleep(1); + + if (server) { + status = dat_ib_post_fetch_and_add(ep[0], + (DAT_UINT64) 0x100, + &l_iov, + cookie, + &r_iov, + DAT_COMPLETION_DEFAULT_FLAG); + } else { + status = dat_ib_post_fetch_and_add(ep[0], + (DAT_UINT64) 0x10, + &l_iov, + cookie, + &r_iov, + DAT_COMPLETION_DEFAULT_FLAG); + } + + status = dat_evd_wait(dto_evd, DTO_TIMEOUT, 1, &event, &nmore); + _OK(status, "dat_evd_wait for second fetch and add"); + if (event.event_number != DAT_IB_DTO_EVENT) { + printf("unexpected event after second post_fetch_and_add: " + "0x%x\n", event.event_number); + exit(1); + } + + _OK(dto_event->status, "event status for second FETCH and ADD"); + if (ext_event->type != DAT_IB_FETCH_AND_ADD) { + printf("unexpected event data of second fetch and add : " + "type=%d cookie=%d original%p\n", + (int)ext_event->type, + (int)dto_event->user_cookie.as_64, atomic_buf); + exit(1); + } + + sleep(1); /* wait for other side to complete fetch_add */ + + if (server) { + printf("Server got original data = " F64x ", expected " + "0x200\n", *atomic_buf); + printf("Client final result (on Server) = " F64x ", expected " + "0x30\n", *target); + + if (*atomic_buf != 0x200 || *target != 0x30) { + printf("ERROR: Server FETCH_ADD\n"); + exit(1); + } + } else { + printf("Server side original data = " F64x ", expected " + "0x20\n", *atomic_buf); + printf("Server final result (on Client) = " F64x ", expected " + "0x300\n", *target); + + if (*atomic_buf != 0x20 || *target != 0x300) { + printf("ERROR: Server FETCH_ADD\n"); + exit(1); + } + } + printf("\n FETCH_ADD test - PASSED\n"); + return (0); +} + +int main(int argc, char **argv) +{ + int rc; + + /* parse arguments */ + while ((rc = getopt(argc, argv, "csvumpU:h:b:P:q:l:")) != -1) { + switch (rc) { + case 'u': + ud_test = 1; + eps = MAX_EP_COUNT / 2; + break; + case 'm': + multi_eps = 1; + break; + case 'c': + server = 0; + break; + case 's': + server = 1; + break; + case 'p': + counters = 1; + break; + case 'h': + remote_host = 1; + strcpy(hostname, optarg); + break; + case 'b': + buf_size = atoi(optarg); + break; + case 'U': + ud_test = 1; + eps = MIN(atoi(optarg), MAX_EP_COUNT); + break; + case 'P': + strcpy(provider, optarg); + break; + case 'v': + verbose = 1; + break; + case 'q': + /* map UCM qpn into AF_INET6 sin6_flowinfo */ + remote.sin6_family = AF_INET6; + remote.sin6_flowinfo = htonl(strtol(optarg,NULL,0)); + ucm = 1; + server = 0; + break; + case 'l': + /* map UCM lid into AF_INET6 sin6_port */ + remote.sin6_family = AF_INET6; + remote.sin6_port = htons(strtol(optarg,NULL,0)); + ucm = 1; + server = 0; + break; + default: + print_usage(); + exit(-12); + } + } + +#if defined(_WIN32) || defined(_WIN64) + { + WSADATA wsaData; + int i; + + i = WSAStartup(MAKEWORD(2, 2), &wsaData); + if (i != 0) { + printf("%s WSAStartup(2.2) fail? (0x%x)\n", argv[0], i); + fflush(stdout); + exit(1); + } + } +#endif + /* for non UD tests, -h is always client */ + if (remote_host && !ud_test) + server = 0; + + if (!server) { + printf("\nRunning as Client - %s %s %d endpoint(s)\n", + provider, ud_test ? "UD test" : "", eps); + } else { + printf("\nRunning as Server - %s %s %d endpoint(s)\n", + provider, ud_test ? "UD test" : "", eps); + } + + /* + * connect + */ + if (connect_ep(hostname)) { + _WSACleanup(); + exit(1); + } + if (ud_test) + goto bail; + + if (do_immediate()) { + _WSACleanup(); + exit(1); + } + if (do_cmp_swap()) { + _WSACleanup(); + exit(1); + } + if (do_fetch_add()) { + _WSACleanup(); + exit(1); + } + bail: + rc = disconnect_ep(); + _WSACleanup(); + + if (!rc) + printf("\n IB extension test - %s test PASSED\n\n", + ud_test ? "UD" : "immed/atomic"); + return rc; +} diff --git a/branches/WOF2-3/ulp/dapl2/test/dtest/dts.bat b/branches/WOF2-3/ulp/dapl2/test/dtest/dts.bat new file mode 100644 index 00000000..3e802073 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dtest/dts.bat @@ -0,0 +1,47 @@ +@echo off +rem +rem dtest2 server invocation - usage: dts {-D {0x?}} +rem + +SETLOCAL + +rem Socket CM testing +rem set DAT_OVERRIDE=C:\dapl2\dat.conf +rem set DT=dtest2.exe +rem set P=ibnic0v2_scm + +rem IBAL CM testing +rem set DAT_OVERRIDE=C:\dapl2\dat.conf +set DT=dtest2.exe +set P=ibnic0v2 + + +if "%1" == "-D" ( + if "%2" == "" ( + set X=0xfffff + rem set X=0x48 + ) else ( + set X=%2 + ) +) else ( + set X= +) + +if not "%X%" == "" ( + set DAT_DBG_LEVEL=%X% + set DAT_DBG_TYPE=%X% + set DAT_OS_DBG_TYPE=%X% + set DAPL_DBG_TYPE=%X% + set DAPL_DBG_LEVEL=%X% +) + +echo %DT% -s -P %P% + +%DT% -s -P %P% + +echo %0 - %DT% server exit... + +ENDLOCAL + +@echo on +exit /B diff --git a/branches/WOF2-3/ulp/dapl2/test/dtest/windows/dirs b/branches/WOF2-3/ulp/dapl2/test/dtest/windows/dirs new file mode 100644 index 00000000..e2e8c6be --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dtest/windows/dirs @@ -0,0 +1 @@ +dirs = dtest dtestx dtestcm diff --git a/branches/WOF2-3/ulp/dapl2/test/dtest/windows/dtest/SOURCES b/branches/WOF2-3/ulp/dapl2/test/dtest/windows/dtest/SOURCES new file mode 100644 index 00000000..3921a1a1 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dtest/windows/dtest/SOURCES @@ -0,0 +1,34 @@ +!if $(FREEBUILD) +TARGETNAME = dtest2 +!else +TARGETNAME = dtest2d +!endif + +TARGETPATH = ..\..\..\..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = PROGRAM +UMTYPE = console +USE_MSVCRT = 1 + +SOURCES = \ + dtest.rc \ + dtest.c + +INCLUDES = ..\..\..\..\dat\include;..\..\..\..\..\..\inc;\ + ..\..\..\..\..\..\inc\user;\ + ..\..\..\..\..\..\inc\user\linux; + +RCOPTIONS=/I..\..\..\..\..\..\inc; + +# Set defines particular to the driver. +USER_C_FLAGS = $(USER_C_FLAGS) /DDAT_EXTENSIONS /DFD_SETSIZE=1024 + +!if $(FREEBUILD) +DATLIB = dat2.lib +!else +DATLIB = dat2d.lib +!endif + +TARGETLIBS = $(TARGETPATH)\*\$(DATLIB) $(SDK_LIB_PATH)\ws2_32.lib + +# XXX do this ASAP - MSC_WARNING_LEVEL= /W3 +MSC_WARNING_LEVEL = /W1 diff --git a/branches/WOF2-3/ulp/dapl2/test/dtest/windows/dtest/dtest.c b/branches/WOF2-3/ulp/dapl2/test/dtest/windows/dtest/dtest.c new file mode 100644 index 00000000..58cda911 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dtest/windows/dtest/dtest.c @@ -0,0 +1,4 @@ +#include "..\..\..\..\..\..\etc\user\inet.c" +#include "..\..\..\..\..\..\etc\user\gtod.c" +#include "..\..\dtest.c" + diff --git a/branches/WOF2-3/ulp/dapl2/test/dtest/windows/dtest/dtest.rc b/branches/WOF2-3/ulp/dapl2/test/dtest/windows/dtest/dtest.rc new file mode 100644 index 00000000..4884f754 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dtest/windows/dtest/dtest.rc @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2007 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#if DBG +#define VER_FILEDESCRIPTION_STR "Simple DAPL/DAT svr/cli test Application (Debug)" +#define VER_INTERNALNAME_STR "dtest2d.exe" +#define VER_ORIGINALFILENAME_STR "dtest2d.exe" +#else +#define VER_FILEDESCRIPTION_STR "Simple DAPL/DAT svr/cli test Application" +#define VER_INTERNALNAME_STR "dtest2.exe" +#define VER_ORIGINALFILENAME_STR "dtest2.exe" +#endif + +#include diff --git a/branches/WOF2-3/ulp/dapl2/test/dtest/windows/dtest/makefile b/branches/WOF2-3/ulp/dapl2/test/dtest/windows/dtest/makefile new file mode 100644 index 00000000..5fb2ee8f --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dtest/windows/dtest/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\..\..\..\inc\openib.def diff --git a/branches/WOF2-3/ulp/dapl2/test/dtest/windows/dtestcm/SOURCES b/branches/WOF2-3/ulp/dapl2/test/dtest/windows/dtestcm/SOURCES new file mode 100644 index 00000000..76427a60 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dtest/windows/dtestcm/SOURCES @@ -0,0 +1,34 @@ +!if $(FREEBUILD) +TARGETNAME = dtestcm +!else +TARGETNAME = dtestcmd +!endif + +TARGETPATH = ..\..\..\..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = PROGRAM +UMTYPE = console +USE_MSVCRT = 1 + +SOURCES = \ + dtestcm.rc \ + dtestcm.c + +INCLUDES = ..\..\..\..\dat\include;..\..\..\..\..\..\inc;\ + ..\..\..\..\..\..\inc\user;\ + ..\..\..\..\..\..\inc\user\linux; + +RCOPTIONS=/I..\..\..\..\..\..\inc; + +# Set defines particular to the driver. +USER_C_FLAGS = $(USER_C_FLAGS) /DDAT_EXTENSIONS /DFD_SETSIZE=1024 + +!if $(FREEBUILD) +DATLIB = dat2.lib +!else +DATLIB = dat2d.lib +!endif + +TARGETLIBS = $(TARGETPATH)\*\$(DATLIB) $(SDK_LIB_PATH)\ws2_32.lib + +# XXX do this ASAP - MSC_WARNING_LEVEL= /W3 +MSC_WARNING_LEVEL = /W1 diff --git a/branches/WOF2-3/ulp/dapl2/test/dtest/windows/dtestcm/dtestcm.c b/branches/WOF2-3/ulp/dapl2/test/dtest/windows/dtestcm/dtestcm.c new file mode 100644 index 00000000..f1cb91d7 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dtest/windows/dtestcm/dtestcm.c @@ -0,0 +1,4 @@ +#include "..\..\..\..\..\..\etc\user\gtod.c" +#include "..\..\..\..\..\..\etc\user\inet.c" +#include "..\..\dtestcm.c" + diff --git a/branches/WOF2-3/ulp/dapl2/test/dtest/windows/dtestcm/dtestcm.rc b/branches/WOF2-3/ulp/dapl2/test/dtest/windows/dtestcm/dtestcm.rc new file mode 100644 index 00000000..a1674857 --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dtest/windows/dtestcm/dtestcm.rc @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#if DBG +#define VER_FILEDESCRIPTION_STR "Measure DAPL connection rate scaling (Debug)" +#define VER_INTERNALNAME_STR "dtestcmd.exe" +#define VER_ORIGINALFILENAME_STR "dtestcmd.exe" +#else +#define VER_FILEDESCRIPTION_STR "Measure DAPL connection rate scaling" +#define VER_INTERNALNAME_STR "dtestcm.exe" +#define VER_ORIGINALFILENAME_STR "dtestcm.exe" +#endif + +#include diff --git a/branches/WOF2-3/ulp/dapl2/test/dtest/windows/dtestcm/makefile b/branches/WOF2-3/ulp/dapl2/test/dtest/windows/dtestcm/makefile new file mode 100644 index 00000000..5fb2ee8f --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dtest/windows/dtestcm/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\..\..\..\inc\openib.def diff --git a/branches/WOF2-3/ulp/dapl2/test/dtest/windows/dtestx/SOURCES b/branches/WOF2-3/ulp/dapl2/test/dtest/windows/dtestx/SOURCES new file mode 100644 index 00000000..694efefd --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dtest/windows/dtestx/SOURCES @@ -0,0 +1,32 @@ +!if $(FREEBUILD) +TARGETNAME = dtestx +!else +TARGETNAME = dtestxd +!endif + +TARGETPATH = ..\..\..\..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = PROGRAM +UMTYPE = console +USE_MSVCRT = 1 + +SOURCES = \ + dtestx.rc \ + dtestx.c + +INCLUDES = ..\..\..\..\dat\include;..\..\..\..\..\..\inc;\ + ..\..\..\..\..\..\inc\user;\ + ..\..\..\..\..\..\inc\user\linux; + +# Set defines particular to the driver. +USER_C_FLAGS = $(USER_C_FLAGS) /DDAT_EXTENSIONS /DFD_SETSIZE=1024 + +!if $(FREEBUILD) +DATLIB = dat2.lib +!else +DATLIB = dat2d.lib +!endif + +TARGETLIBS = $(TARGETPATH)\*\$(DATLIB) $(SDK_LIB_PATH)\ws2_32.lib + +# XXX do this ASAP - MSC_WARNING_LEVEL= /W3 +MSC_WARNING_LEVEL = /W1 diff --git a/branches/WOF2-3/ulp/dapl2/test/dtest/windows/dtestx/dtestx.c b/branches/WOF2-3/ulp/dapl2/test/dtest/windows/dtestx/dtestx.c new file mode 100644 index 00000000..3265ddce --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dtest/windows/dtestx/dtestx.c @@ -0,0 +1,2 @@ +#include "..\..\..\..\..\..\etc\user\inet.c" +#include "..\..\dtestx.c" diff --git a/branches/WOF2-3/ulp/dapl2/test/dtest/windows/dtestx/dtestx.rc b/branches/WOF2-3/ulp/dapl2/test/dtest/windows/dtestx/dtestx.rc new file mode 100644 index 00000000..98659e0a --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dtest/windows/dtestx/dtestx.rc @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2007 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#if DBG +#define VER_FILEDESCRIPTION_STR "DAT/DAPL v2.0 extensions cli/svr test (Debug)" +#define VER_INTERNALNAME_STR "dtestxd.exe" +#define VER_ORIGINALFILENAME_STR "dtestxd.exe" +#else +#define VER_FILEDESCRIPTION_STR "DAT/DAPL v2.0 Extensions cli/svr test" +#define VER_INTERNALNAME_STR "dtestx.exe" +#define VER_ORIGINALFILENAME_STR "dtestx.exe" +#endif + +#include diff --git a/branches/WOF2-3/ulp/dapl2/test/dtest/windows/dtestx/makefile b/branches/WOF2-3/ulp/dapl2/test/dtest/windows/dtestx/makefile new file mode 100644 index 00000000..5fb2ee8f --- /dev/null +++ b/branches/WOF2-3/ulp/dapl2/test/dtest/windows/dtestx/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\..\..\..\inc\openib.def diff --git a/branches/WOF2-3/ulp/dirs b/branches/WOF2-3/ulp/dirs new file mode 100644 index 00000000..db366540 --- /dev/null +++ b/branches/WOF2-3/ulp/dirs @@ -0,0 +1,15 @@ +DIRS = \ + opensm \ + dapl2 \ + ipoib \ + ipoib_NDIS6_CM \ + srp \ + wsd \ + qlgcvnic \ + libibverbs \ + libibumad \ + libibmad \ + libibnetdisc \ + librdmacm \ + nd \ + netdirect diff --git a/branches/WOF2-3/ulp/ipoib/dirs b/branches/WOF2-3/ulp/ipoib/dirs new file mode 100644 index 00000000..ed41dcf4 --- /dev/null +++ b/branches/WOF2-3/ulp/ipoib/dirs @@ -0,0 +1,2 @@ +DIRS=\ + kernel diff --git a/branches/WOF2-3/ulp/ipoib/ip_stats.h b/branches/WOF2-3/ulp/ipoib/ip_stats.h new file mode 100644 index 00000000..0182475c --- /dev/null +++ b/branches/WOF2-3/ulp/ipoib/ip_stats.h @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#ifndef _IP_STATS_H_ +#define _IP_STATS_H_ + + +#include + + +/****s* IB Network Drivers/ip_data_stats_t +* NAME +* ip_data_stats_t +* +* DESCRIPTION +* Defines data transfer statistic information for an IP device. +* +* SYNOPSIS +*/ +typedef struct _ip_data_stats +{ + uint64_t bytes; + uint64_t frames; + +} ip_data_stats_t; +/* +* FIELDS +* bytes +* Total number of bytes transfered. +* +* frames +* Total number of frames transfered. +* +* SEE ALSO +* IPoIB, INIC, ip_comp_stats_t, ip_stats_t +*********/ + + +/****s* IB Network Drivers/ip_comp_stats_t +* NAME +* ip_comp_stats_t +* +* DESCRIPTION +* Defines transfer completion statistic information for an IP device. +* +* SYNOPSIS +*/ +typedef struct _ip_comp_stats +{ + uint64_t success; + uint64_t error; + uint64_t dropped; + +} ip_comp_stats_t; +/* +* FIELDS +* success +* Total number of requests transfered successfully. +* +* error +* Total number of requests that failed being transfered. +* +* dropped +* Total number of requests that were dropped. +* +* SEE ALSO +* IPoIB, INIC, ip_data_stats_t, ip_stats_t +*********/ + + +/****s* IB Network Drivers/ip_stats_t +* NAME +* ip_stats_t +* +* DESCRIPTION +* Defines statistic information for an IP device. +* +* SYNOPSIS +*/ +typedef struct _ip_stats +{ + ip_comp_stats_t comp; + ip_data_stats_t ucast; + ip_data_stats_t bcast; + ip_data_stats_t mcast; + +} ip_stats_t; +/* +* FIELDS +* comp +* Request completion statistics. +* +* ucast +* Data statistics for unicast packets +* +* bcast +* Data statistics for broadcast packets +* +* mcast +* Data statistics for multicast packets +* +* SEE ALSO +* IPoIB, INIC, ip_data_stats_t, ip_comp_stats_t +*********/ + + +typedef enum _ip_stat_sel +{ + IP_STAT_SUCCESS, + IP_STAT_ERROR, + IP_STAT_DROPPED, + IP_STAT_UCAST_BYTES, + IP_STAT_UCAST_FRAMES, + IP_STAT_BCAST_BYTES, + IP_STAT_BCAST_FRAMES, + IP_STAT_MCAST_BYTES, + IP_STAT_MCAST_FRAMES + +} ip_stat_sel_t; + +#endif /* _IP_STATS_H_ */ diff --git a/branches/WOF2-3/ulp/ipoib/kernel/SOURCES b/branches/WOF2-3/ulp/ipoib/kernel/SOURCES new file mode 100644 index 00000000..12e93b46 --- /dev/null +++ b/branches/WOF2-3/ulp/ipoib/kernel/SOURCES @@ -0,0 +1,59 @@ +TARGETNAME=ipoib +TARGETPATH=..\..\..\bin\kernel\obj$(BUILD_ALT_DIR) +TARGETTYPE=DRIVER + +!if $(_NT_TOOLS_VERSION) != 0x700 +# WDK build only - transform .inx --> .inf adding date & version stamp. +# see .\makefile.inc +INF_NAME=netipoib +INF_TARGET=..\..\..\bin\kernel\$(O)\$(INF_NAME).inf +NTTARGETFILES=$(INF_TARGET) +!endif + +!if $(FREEBUILD) +ENABLE_EVENT_TRACING=1 +!else +#ENABLE_EVENT_TRACING=1 +!endif + + +SOURCES= ipoib_log.mc \ + ipoib.rc \ + ipoib_driver.c \ + ipoib_adapter.c \ + ipoib_endpoint.c \ + ipoib_port.c \ + ipoib_ibat.c \ + ipoib_xfr_mgr.c \ + ipoib_stat.c + +INCLUDES=..;..\..\..\inc;..\..\..\inc\kernel; + +C_DEFINES=$(C_DEFINES) -DNDIS_MINIPORT_DRIVER -DNDIS_WDM=1 \ + -DDEPRECATE_DDK_FUNCTIONS -DNDIS51_MINIPORT -DNEED_CL_OBJ -DBINARY_COMPATIBLE=0 + +TARGETLIBS= \ + $(TARGETPATH)\*\complib.lib \ + $(DDK_LIB_PATH)\ndis.lib \ + $(DDK_LIB_PATH)\ntstrsafe.lib \ + $(DDK_LIB_PATH)\strsafe.lib + +!if !defined(DDK_TARGET_OS) || "$(DDK_TARGET_OS)"=="Win2K" +# +# The driver is built in the Win2K build environment +# - use the library version of safe strings +# +#TARGETLIBS= $(TARGETLIBS) $(DDK_LIB_PATH)\ntstrsafe.lib +!endif + +!IFDEF ENABLE_EVENT_TRACING + +C_DEFINES = $(C_DEFINES) -DEVENT_TRACING + +RUN_WPP = $(SOURCES) -km -ext: .c .h .C .H \ + -scan:ipoib_debug.h \ + -func:IPOIB_PRINT(LEVEL,FLAGS,(MSG,...)) \ + -func:IPOIB_PRINT_EXIT(LEVEL,FLAGS,(MSG,...)) +!ENDIF + +MSC_WARNING_LEVEL= /W4 diff --git a/branches/WOF2-3/ulp/ipoib/kernel/ipoib.cdf b/branches/WOF2-3/ulp/ipoib/kernel/ipoib.cdf new file mode 100644 index 00000000..eb21da98 --- /dev/null +++ b/branches/WOF2-3/ulp/ipoib/kernel/ipoib.cdf @@ -0,0 +1,13 @@ +[CatalogHeader] +Name=ipoib.cat +PublicVersion=0x0000001 +EncodingType=0x00010001 +CATATTR1=0x10010001:OSAttr:2:6.0 +[CatalogFiles] +netipoib.inf=netipoib.inf +ipoib.sys=ipoib.sys +ibwsd.dll=ibwsd.dll +ibwsd32.dll=ibwsd32.dll +ibndprov.dll=ibndprov.dll +ibndprov32.dll=ibndprov32.dll +ndinstall.exe=ndinstall.exe diff --git a/branches/WOF2-3/ulp/ipoib/kernel/ipoib.rc b/branches/WOF2-3/ulp/ipoib/kernel/ipoib.rc new file mode 100644 index 00000000..6eb63025 --- /dev/null +++ b/branches/WOF2-3/ulp/ipoib/kernel/ipoib.rc @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef _DEBUG_ +#define VER_FILEDESCRIPTION_STR "IP over InfiniBand NDIS 5 Miniport (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "IP over InfiniBand NDIS 5 Miniport" +#endif + +#define VER_INTERNALNAME_STR "ipoib.sys" +#define VER_ORIGINALFILENAME_STR "ipoib.sys" + +#include +#include "ipoib_log.rc" diff --git a/branches/WOF2-3/ulp/ipoib/kernel/ipoib32-xp.cdf b/branches/WOF2-3/ulp/ipoib/kernel/ipoib32-xp.cdf new file mode 100644 index 00000000..faf8ea6f --- /dev/null +++ b/branches/WOF2-3/ulp/ipoib/kernel/ipoib32-xp.cdf @@ -0,0 +1,10 @@ +[CatalogHeader] +Name=ipoib.cat +PublicVersion=0x0000001 +EncodingType=0x00010001 +CATATTR1=0x10010001:OSAttr:2:6.0 +[CatalogFiles] +netipoib.inf=netipoib.inf +ipoib.sys=ipoib.sys +ibndprov.dll=ibndprov.dll +ndinstall.exe=ndinstall.exe diff --git a/branches/WOF2-3/ulp/ipoib/kernel/ipoib32.cdf b/branches/WOF2-3/ulp/ipoib/kernel/ipoib32.cdf new file mode 100644 index 00000000..50225ba6 --- /dev/null +++ b/branches/WOF2-3/ulp/ipoib/kernel/ipoib32.cdf @@ -0,0 +1,11 @@ +[CatalogHeader] +Name=ipoib.cat +PublicVersion=0x0000001 +EncodingType=0x00010001 +CATATTR1=0x10010001:OSAttr:2:6.0 +[CatalogFiles] +netipoib.inf=netipoib.inf +ipoib.sys=ipoib.sys +ibwsd.dll=ibwsd.dll +ibndprov.dll=ibndprov.dll +ndinstall.exe=ndinstall.exe diff --git a/branches/WOF2-3/ulp/ipoib/kernel/ipoib_adapter.c b/branches/WOF2-3/ulp/ipoib/kernel/ipoib_adapter.c new file mode 100644 index 00000000..06433a6d --- /dev/null +++ b/branches/WOF2-3/ulp/ipoib/kernel/ipoib_adapter.c @@ -0,0 +1,1478 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2006 Mellanox Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + +#include "ipoib_adapter.h" +#include "ipoib_port.h" +#include "ipoib_driver.h" +#include "ipoib_debug.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "ipoib_adapter.tmh" +#endif + + +#define ITEM_POOL_START 16 +#define ITEM_POOL_GROW 16 + + +/* IB Link speeds in 100bps */ +#define ONE_X_IN_100BPS 25000000 +#define FOUR_X_IN_100BPS 100000000 +#define TWELVE_X_IN_100BPS 300000000 + + +/* Declarations */ +static void +adapter_construct( + IN ipoib_adapter_t* const p_adapter ); + + +static ib_api_status_t +adapter_init( + IN ipoib_adapter_t* const p_adapter ); + + +static void +__adapter_destroying( + IN cl_obj_t* const p_obj ); + + +static void +__adapter_free( + IN cl_obj_t* const p_obj ); + + +static ib_api_status_t +__ipoib_pnp_reg( + IN ipoib_adapter_t* const p_adapter, + IN ib_pnp_class_t flags ); + + +static void +__ipoib_pnp_dereg( + IN void* context ); + + +static void +__ipoib_adapter_reset( + IN void* context); + + +static ib_api_status_t +__ipoib_pnp_cb( + IN ib_pnp_rec_t *p_pnp_rec ); + + +void +ipoib_join_mcast( + IN ipoib_adapter_t* const p_adapter ); + + +/* Leaves all mcast groups when port goes down. */ +static void +ipoib_clear_mcast( + IN ipoib_port_t* const p_port ); + +NDIS_STATUS +ipoib_get_adapter_guids( + IN NDIS_HANDLE* const h_adapter, + IN OUT ipoib_adapter_t *p_adapter ); + +NDIS_STATUS +ipoib_get_adapter_params( + IN NDIS_HANDLE* const wrapper_config_context, + IN OUT ipoib_adapter_t *p_adapter, + OUT PUCHAR *p_mac, + OUT UINT *p_len); + + +/* Implementation */ +ib_api_status_t +ipoib_create_adapter( + IN NDIS_HANDLE wrapper_config_context, + IN void* const h_adapter, + OUT ipoib_adapter_t** const pp_adapter ) +{ + ipoib_adapter_t *p_adapter; + ib_api_status_t status; + cl_status_t cl_status; + PUCHAR mac; + UINT len; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + p_adapter = cl_zalloc( sizeof(ipoib_adapter_t) ); + if( !p_adapter ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to allocate ipoib_adapter_t (%d bytes)", + sizeof(ipoib_adapter_t)) ); + return IB_INSUFFICIENT_MEMORY; + } + + adapter_construct( p_adapter ); + + p_adapter->h_adapter = h_adapter; + + p_adapter->p_ifc = cl_zalloc( sizeof(ib_al_ifc_t) ); + if( !p_adapter->p_ifc ) + { + __adapter_free( &p_adapter->obj ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ipoib_create_adapter failed to alloc ipoib_ifc_t %d bytes\n", + sizeof(ib_al_ifc_t)) ); + return IB_INSUFFICIENT_MEMORY; + } + + /* Get the CA and port GUID from the bus driver. */ + status = ipoib_get_adapter_guids( h_adapter, p_adapter ); + if( status != NDIS_STATUS_SUCCESS ) + { + __adapter_free( &p_adapter->obj ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ipoib_get_adapter_guids returned 0x%.8X.\n", status) ); + return status; + } + + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, + ("Port %016I64x (CA %016I64x port %d) initializing\n", + p_adapter->guids.port_guid.guid, p_adapter->guids.ca_guid, + p_adapter->guids.port_num) ); + + cl_status = cl_obj_init( &p_adapter->obj, CL_DESTROY_SYNC, + __adapter_destroying, NULL, __adapter_free ); + if( cl_status != CL_SUCCESS ) + { + __adapter_free( &p_adapter->obj ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("cl_obj_init returned %#x\n", cl_status) ); + return IB_ERROR; + } + + /* Read configuration parameters. */ + status = ipoib_get_adapter_params( wrapper_config_context, + p_adapter , &mac, &len); + if( status != NDIS_STATUS_SUCCESS ) + { + cl_obj_destroy( &p_adapter->obj ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ipoib_get_adapter_params returned 0x%.8x.\n", status) ); + return status; + } + + status = adapter_init( p_adapter ); + if( status != IB_SUCCESS ) + { + cl_obj_destroy( &p_adapter->obj ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("adapter_init returned %s.\n", + p_adapter->p_ifc->get_err_str( status )) ); + return status; + } + + ETH_COPY_NETWORK_ADDRESS( p_adapter->params.conf_mac.addr, p_adapter->mac.addr ); + /* If there is a NetworkAddress override in registry, use it */ + if( (len == HW_ADDR_LEN) && (mac != NULL) ) + { + if( ETH_IS_MULTICAST(mac) || ETH_IS_BROADCAST(mac) || + !ETH_IS_LOCALLY_ADMINISTERED(mac) ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_INIT, + ("Overriding NetworkAddress is invalid - " + "%02x-%02x-%02x-%02x-%02x-%02x\n", + mac[0], mac[1], mac[2], + mac[3], mac[4], mac[5]) ); + } + else + { + ETH_COPY_NETWORK_ADDRESS( p_adapter->params.conf_mac.addr, mac ); + } + } + + NdisMGetDeviceProperty(h_adapter, &p_adapter->pdo, NULL, NULL, NULL, NULL); + ASSERT(p_adapter->pdo != NULL); + + p_adapter->p_stat = ipoib_st_dev_add(); + if ( p_adapter->p_stat ) + p_adapter->p_stat->p_adapter = p_adapter; + + *pp_adapter = p_adapter; + + IPOIB_EXIT( IPOIB_DBG_INIT ); + return status; +} + + +ib_api_status_t +ipoib_start_adapter( + IN ipoib_adapter_t* const p_adapter ) +{ + ib_api_status_t status; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + status = __ipoib_pnp_reg( p_adapter, + IB_PNP_FLAG_REG_SYNC | IB_PNP_FLAG_REG_COMPLETE ); + + IPOIB_EXIT( IPOIB_DBG_INIT ); + return status; +} + + +void +ipoib_destroy_adapter( + IN ipoib_adapter_t* const p_adapter ) +{ + PIPOIB_ST_DEVICE p_stat; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + CL_ASSERT( p_adapter ); + + // statistics + p_stat = p_adapter->p_stat; + if ( p_stat ) { + p_stat->p_halt_thread = KeGetCurrentThread(); + p_stat->p_prev_port = p_adapter->p_port; + } + + /* + * Flag the adapter as being removed. We use the IB_PNP_PORT_REMOVE state + * for this purpose. Note that we protect this state change with both the + * mutex and the lock. The mutex provides synchronization as a whole + * between destruction and AL callbacks (PnP, Query, Destruction). + * The lock provides protection + */ + KeWaitForMutexObject( + &p_adapter->mutex, Executive, KernelMode, FALSE, NULL ); + cl_obj_lock( &p_adapter->obj ); + p_adapter->state = IB_PNP_PORT_REMOVE; + + /* + * Clear the pointer to the port object since the object destruction + * will cascade to child objects. This prevents potential duplicate + * destruction (or worse, stale pointer usage). + */ + p_adapter->p_port = NULL; + + cl_obj_unlock( &p_adapter->obj ); + + KeReleaseMutex( &p_adapter->mutex, FALSE ); + + cl_obj_destroy( &p_adapter->obj ); + ipoib_st_dev_rmv( p_stat ); + + IPOIB_EXIT( IPOIB_DBG_INIT ); +} + + +static void +adapter_construct( + IN ipoib_adapter_t* const p_adapter ) +{ + cl_obj_construct( &p_adapter->obj, IPOIB_OBJ_INSTANCE ); + cl_spinlock_construct( &p_adapter->send_stat_lock ); + cl_spinlock_construct( &p_adapter->recv_stat_lock ); + cl_qpool_construct( &p_adapter->item_pool ); + KeInitializeMutex( &p_adapter->mutex, 0 ); + + cl_thread_construct(&p_adapter->destroy_thread); + + cl_vector_construct( &p_adapter->ip_vector ); + + cl_perf_construct( &p_adapter->perf ); + + p_adapter->state = IB_PNP_PORT_ADD; + p_adapter->port_rate = FOUR_X_IN_100BPS; +} + + +static ib_api_status_t +adapter_init( + IN ipoib_adapter_t* const p_adapter ) +{ + cl_status_t cl_status; + ib_api_status_t status; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + cl_status = cl_perf_init( &p_adapter->perf, MaxPerf ); + if( cl_status != CL_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("cl_perf_init returned %#x\n", cl_status) ); + return IB_ERROR; + } + + cl_status = cl_spinlock_init( &p_adapter->send_stat_lock ); + if( cl_status != CL_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("cl_spinlock_init returned %#x\n", cl_status) ); + return IB_ERROR; + } + + cl_status = cl_spinlock_init( &p_adapter->recv_stat_lock ); + if( cl_status != CL_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("cl_spinlock_init returned %#x\n", cl_status) ); + return IB_ERROR; + } + + cl_status = cl_qpool_init( &p_adapter->item_pool, ITEM_POOL_START, 0, + ITEM_POOL_GROW, sizeof(cl_pool_obj_t), NULL, NULL, NULL ); + if( cl_status != CL_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("cl_qpool_init returned %#x\n", cl_status) ); + return IB_ERROR; + } + + + /* We manually manage the size and capacity of the vector. */ + cl_status = cl_vector_init( &p_adapter->ip_vector, 0, + 0, sizeof(net_address_item_t), NULL, NULL, p_adapter ); + if( cl_status != CL_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("cl_vector_init for ip_vector returned %#x\n", + cl_status) ); + return IB_ERROR; + } + + /* Validate the port GUID and generate the MAC address. */ + status = + ipoib_mac_from_guid( p_adapter->guids.port_guid.guid, p_adapter->params.guid_mask, &p_adapter->mac); + if( status != IB_SUCCESS ) + { + if( status == IB_INVALID_GUID_MASK ) + { + IPOIB_PRINT( TRACE_LEVEL_WARNING, IPOIB_DBG_ERROR, + ("Invalid GUID mask received, rejecting it") ); + ipoib_create_log(p_adapter->h_adapter, GUID_MASK_LOG_INDEX, EVENT_IPOIB_WRONG_PARAMETER_WRN); + } + + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ipoib_mac_from_guid returned %s\n", + p_adapter->p_ifc->get_err_str( status )) ); + return status; + } + + /* Open AL. */ + status = p_adapter->p_ifc->open_al( &p_adapter->h_al ); + if( status != IB_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_open_al returned %s\n", + p_adapter->p_ifc->get_err_str( status )) ); + return status; + } + + IPOIB_EXIT( IPOIB_DBG_INIT ); + return status; +} + + +static ib_api_status_t +__ipoib_pnp_reg( + IN ipoib_adapter_t* const p_adapter, + IN ib_pnp_class_t flags ) +{ + ib_api_status_t status; + ib_pnp_req_t pnp_req; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + CL_ASSERT( !p_adapter->h_pnp ); + CL_ASSERT( !p_adapter->registering ); + + p_adapter->registering = TRUE; + + /* Register for PNP events. */ + cl_memclr( &pnp_req, sizeof(pnp_req) ); + pnp_req.pnp_class = IB_PNP_PORT | flags; + /* + * Context is the cl_obj of the adapter to allow passing cl_obj_deref + * to ib_dereg_pnp. + */ + pnp_req.pnp_context = &p_adapter->obj; + pnp_req.pfn_pnp_cb = __ipoib_pnp_cb; + status = p_adapter->p_ifc->reg_pnp( p_adapter->h_al, &pnp_req, &p_adapter->h_pnp ); + if( status != IB_SUCCESS ) + { + p_adapter->registering = FALSE; + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_reg_pnp returned %s\n", + p_adapter->p_ifc->get_err_str( status )) ); + return status; + } + /* + * Reference the adapter on behalf of the PNP registration. + * This allows the destruction to block until the PNP deregistration + * completes. + */ + cl_obj_ref( &p_adapter->obj ); + + IPOIB_EXIT( IPOIB_DBG_INIT ); + return status; +} + + +static void +__adapter_destroying( + IN cl_obj_t* const p_obj ) +{ + ipoib_adapter_t *p_adapter; + KLOCK_QUEUE_HANDLE hdl; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + p_adapter = PARENT_STRUCT( p_obj, ipoib_adapter_t, obj ); + + /* + * The adapter's object will be dereferenced when the deregistration + * completes. No need to lock here since all PnP related API calls + * are driven by NDIS (via the Init/Reset/Destroy paths). + */ + if( p_adapter->h_pnp ) + { + p_adapter->p_ifc->dereg_pnp( p_adapter->h_pnp, cl_obj_deref ); + p_adapter->h_pnp = NULL; + } + + if( p_adapter->packet_filter ) + { + KeAcquireInStackQueuedSpinLock( &g_ipoib.lock, &hdl ); + cl_obj_lock( &p_adapter->obj ); + + ASSERT( cl_qlist_count( &g_ipoib.adapter_list ) ); + cl_qlist_remove_item( &g_ipoib.adapter_list, &p_adapter->entry ); + + p_adapter->packet_filter = 0; + + cl_obj_unlock( &p_adapter->obj ); + KeReleaseInStackQueuedSpinLock( &hdl ); + } + + IPOIB_EXIT( IPOIB_DBG_INIT ); +} + + +static void +__adapter_free( + IN cl_obj_t* const p_obj ) +{ + ipoib_adapter_t *p_adapter; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + p_adapter = PARENT_STRUCT( p_obj, ipoib_adapter_t, obj ); + + if( p_adapter->p_ifc ) + { + if( p_adapter->h_al ) + p_adapter->p_ifc->close_al( p_adapter->h_al ); + + cl_free( p_adapter->p_ifc ); + p_adapter->p_ifc = NULL; + } + + cl_vector_destroy( &p_adapter->ip_vector ); + cl_qpool_destroy( &p_adapter->item_pool ); + cl_spinlock_destroy( &p_adapter->recv_stat_lock ); + cl_spinlock_destroy( &p_adapter->send_stat_lock ); + cl_obj_deinit( p_obj ); + + cl_perf_destroy( &p_adapter->perf, TRUE ); + + cl_free( p_adapter ); + + IPOIB_EXIT( IPOIB_DBG_INIT ); +} + + +static ib_api_status_t +ipoib_query_pkey_index(ipoib_adapter_t *p_adapter) +{ + ib_api_status_t status; + ib_ca_attr_t *ca_attr; + uint32_t ca_size; + uint16_t index = 0; + + /* Query the CA for Pkey table */ + status = p_adapter->p_ifc->query_ca(p_adapter->p_port->ib_mgr.h_ca, NULL, &ca_size); + if(status != IB_INSUFFICIENT_MEMORY) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_query_ca failed\n")); + return status; + } + + ca_attr = (ib_ca_attr_t*)cl_zalloc(ca_size); + if (!ca_attr) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("cl_zalloc can't allocate %d\n",ca_size)); + return IB_INSUFFICIENT_MEMORY; + } + + status = p_adapter->p_ifc->query_ca(p_adapter->p_port->ib_mgr.h_ca, ca_attr,&ca_size); + if( status != IB_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_query_ca returned %s\n", + p_adapter->p_ifc->get_err_str( status )) ); + goto pkey_end; + } + CL_ASSERT(ca_attr->p_port_attr[p_adapter->p_port->port_num -1].p_pkey_table[0] == IB_DEFAULT_PKEY); + for(index = 0; index < ca_attr->p_port_attr[p_adapter->p_port->port_num -1].num_pkeys; index++) + { + if(cl_hton16(p_adapter->guids.port_guid.pkey) == ca_attr->p_port_attr[p_adapter->p_port->port_num -1].p_pkey_table[index]) + break; + } + if(index >= ca_attr->p_port_attr[p_adapter->p_port->port_num -1].num_pkeys) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Pkey table is invalid, index not found\n")); + NdisWriteErrorLogEntry( p_adapter->h_adapter, + EVENT_IPOIB_PARTITION_ERR, 1, p_adapter->guids.port_guid.pkey ); + status = IB_NOT_FOUND; + p_adapter->p_port->pkey_index = PKEY_INVALID_INDEX; + goto pkey_end; + } + + p_adapter->p_port->pkey_index = index; + IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_IB, + ("for PKEY = 0x%04X got index = %d\n",p_adapter->guids.port_guid.pkey,index)); + +pkey_end: + if(ca_attr) + cl_free(ca_attr); + return status; +} + +static ib_api_status_t +__ipoib_pnp_cb( + IN ib_pnp_rec_t *p_pnp_rec ) +{ + ipoib_adapter_t *p_adapter; + ipoib_port_t *p_port; + ib_pnp_event_t old_state; + ib_pnp_port_rec_t *p_port_rec; + ib_api_status_t status = IB_SUCCESS; + + IPOIB_ENTER( IPOIB_DBG_PNP ); + + CL_ASSERT( p_pnp_rec ); + + p_adapter = + PARENT_STRUCT( p_pnp_rec->pnp_context, ipoib_adapter_t, obj ); + + CL_ASSERT( p_adapter ); + + /* Synchronize with destruction */ + KeWaitForMutexObject( + &p_adapter->mutex, Executive, KernelMode, FALSE, NULL ); + cl_obj_lock( &p_adapter->obj ); + old_state = p_adapter->state; + cl_obj_unlock( &p_adapter->obj ); + if( old_state == IB_PNP_PORT_REMOVE ) + { + KeReleaseMutex( &p_adapter->mutex, FALSE ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_PNP, + ("Aborting - Adapter destroying.\n") ); + return IB_NOT_DONE; + } + + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_PNP, + ("p_pnp_rec->pnp_event = 0x%x (%s)\n", + p_pnp_rec->pnp_event, ib_get_pnp_event_str( p_pnp_rec->pnp_event )) ); + + p_port_rec = (ib_pnp_port_rec_t*)p_pnp_rec; + + switch( p_pnp_rec->pnp_event ) + { + case IB_PNP_PORT_ADD: + CL_ASSERT( !p_pnp_rec->context ); + /* Only process our port GUID. */ + if( p_pnp_rec->guid != p_adapter->guids.port_guid.guid ) + { + status = IB_NOT_DONE; + break; + } + + /* Don't process if we're destroying. */ + if( p_adapter->obj.state == CL_DESTROYING ) + { + status = IB_NOT_DONE; + break; + } + + CL_ASSERT( !p_adapter->p_port ); + /* Allocate all IB resources. */ + cl_obj_lock( &p_adapter->obj ); + p_adapter->state = IB_PNP_PORT_ADD; + cl_obj_unlock( &p_adapter->obj ); + status = ipoib_create_port( p_adapter, p_port_rec, &p_port ); + cl_obj_lock( &p_adapter->obj ); + if( status != IB_SUCCESS ) + { + p_adapter->state = old_state; + cl_obj_unlock( &p_adapter->obj ); + p_adapter->hung = TRUE; + break; + } + + p_pnp_rec->context = p_port; + + if ( p_adapter->p_stat ) + p_adapter->p_stat->p_prev_port = p_adapter->p_port; + p_adapter->p_port = p_port; + cl_obj_unlock( &p_adapter->obj ); + break; + + case IB_PNP_PORT_REMOVE: + /* Release all IB resources. */ + CL_ASSERT( p_pnp_rec->context ); + + cl_obj_lock( &p_adapter->obj ); + p_adapter->state = IB_PNP_PORT_REMOVE; + p_port = p_adapter->p_port; + p_adapter->p_port = NULL; + if ( p_adapter->p_stat ) + p_adapter->p_stat->p_prev_port = p_port; + cl_obj_unlock( &p_adapter->obj ); + ipoib_port_destroy( p_port ); + p_pnp_rec->context = NULL; + status = IB_SUCCESS; + break; + + case IB_PNP_PORT_ACTIVE: + /* Join multicast groups and put QP in RTS. */ + CL_ASSERT( p_pnp_rec->context ); + + cl_obj_lock( &p_adapter->obj ); + p_adapter->state = IB_PNP_PORT_INIT; + cl_obj_unlock( &p_adapter->obj ); + ipoib_port_up( p_adapter->p_port, p_port_rec ); + + status = IB_SUCCESS; + break; + + case IB_PNP_PORT_ARMED: + status = IB_SUCCESS; + break; + + case IB_PNP_PORT_INIT: + /* + * Init could happen if the SM brings the port down + * without changing the physical link. + */ + case IB_PNP_PORT_DOWN: + CL_ASSERT( p_pnp_rec->context ); + + cl_obj_lock( &p_adapter->obj ); + old_state = p_adapter->state; + p_adapter->state = IB_PNP_PORT_DOWN; + cl_obj_unlock( &p_adapter->obj ); + status = IB_SUCCESS; + + if( !p_adapter->registering && old_state != IB_PNP_PORT_DOWN ) + { + NdisMIndicateStatus( p_adapter->h_adapter, + NDIS_STATUS_MEDIA_DISCONNECT, NULL, 0 ); + NdisMIndicateStatusComplete( p_adapter->h_adapter ); + + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, + ("Link DOWN!\n") ); + + ipoib_port_down( p_adapter->p_port ); + } + break; + + case IB_PNP_REG_COMPLETE: + if( p_adapter->registering ) + { + p_adapter->registering = FALSE; + cl_obj_lock( &p_adapter->obj ); + old_state = p_adapter->state; + cl_obj_unlock( &p_adapter->obj ); + + if( old_state == IB_PNP_PORT_DOWN ) + { + /* If we were initializing, we might have pended some OIDs. */ + ipoib_resume_oids( p_adapter ); + NdisMIndicateStatus( p_adapter->h_adapter, + NDIS_STATUS_MEDIA_DISCONNECT, NULL, 0 ); + NdisMIndicateStatusComplete( p_adapter->h_adapter ); + } + } + + if( p_adapter->reset && p_adapter->state != IB_PNP_PORT_INIT ) + { + p_adapter->reset = FALSE; + NdisMResetComplete( + p_adapter->h_adapter, NDIS_STATUS_SUCCESS, TRUE ); + } + status = IB_SUCCESS; + break; + + default: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, + ("IPOIB: Received unhandled PnP event 0x%x (%s)\n", + p_pnp_rec->pnp_event, ib_get_pnp_event_str( p_pnp_rec->pnp_event )) ); + /* Fall through. */ + + status = IB_SUCCESS; + + /* We ignore events below if the link is not active. */ + if( p_port_rec->p_port_attr->link_state != IB_LINK_ACTIVE ) + break; + + case IB_PNP_PKEY_CHANGE: + if(p_pnp_rec->pnp_event == IB_PNP_PKEY_CHANGE && + p_adapter->guids.port_guid.pkey != IB_DEFAULT_PKEY) + { + status = ipoib_query_pkey_index(p_adapter); + if(status != IB_SUCCESS) + { + cl_obj_lock( &p_adapter->obj ); + p_adapter->state = IB_PNP_PORT_INIT; + cl_obj_unlock( &p_adapter->obj ); + } + } + + case IB_PNP_SM_CHANGE: + case IB_PNP_GID_CHANGE: + case IB_PNP_LID_CHANGE: + + cl_obj_lock( &p_adapter->obj ); + old_state = p_adapter->state; + switch( old_state ) + { + case IB_PNP_PORT_DOWN: + p_adapter->state = IB_PNP_PORT_INIT; + break; + + default: + p_adapter->state = IB_PNP_PORT_DOWN; + } + cl_obj_unlock( &p_adapter->obj ); + + if( p_adapter->registering ) + break; + + switch( old_state ) + { + case IB_PNP_PORT_ACTIVE: + case IB_PNP_PORT_INIT: + NdisMIndicateStatus( p_adapter->h_adapter, + NDIS_STATUS_MEDIA_DISCONNECT, NULL, 0 ); + NdisMIndicateStatusComplete( p_adapter->h_adapter ); + + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, + ("Link DOWN!\n") ); + + ipoib_port_down( p_adapter->p_port ); + /* Fall through. */ + + case IB_PNP_PORT_DOWN: + cl_obj_lock( &p_adapter->obj ); + p_adapter->state = IB_PNP_PORT_INIT; + cl_obj_unlock( &p_adapter->obj ); + ipoib_port_up( p_adapter->p_port, (ib_pnp_port_rec_t*)p_pnp_rec ); + } + break; + } + + KeReleaseMutex( &p_adapter->mutex, FALSE ); + + IPOIB_EXIT( IPOIB_DBG_PNP ); + return status; +} + + +/* Joins/leaves mcast groups based on currently programmed mcast MACs. */ +void +ipoib_refresh_mcast( + IN ipoib_adapter_t* const p_adapter, + IN mac_addr_t* const p_mac_array, + IN const uint8_t num_macs ) +{ + uint8_t i, j; + ipoib_port_t *p_port = NULL; + + IPOIB_ENTER( IPOIB_DBG_MCAST ); + cl_obj_lock( &p_adapter->obj ); + if( p_adapter->state == IB_PNP_PORT_ACTIVE ) + { + p_port = p_adapter->p_port; + ipoib_port_ref( p_port, ref_refresh_mcast ); + } + cl_obj_unlock( &p_adapter->obj ); + + if( p_port ) + { + /* Purge old entries. */ + for( i = 0; i < p_adapter->mcast_array_size; i++ ) + { + for( j = 0; j < num_macs; j++ ) + { + if( !cl_memcmp( &p_adapter->mcast_array[i], &p_mac_array[j], + sizeof(mac_addr_t) ) ) + { + break; + } + } + if( j != num_macs ) + continue; + + ipoib_port_remove_endpt( p_port, p_adapter->mcast_array[i] ); + } + + /* Add new entries */ + for( i = 0; i < num_macs; i++ ) + { + for( j = 0; j < p_adapter->mcast_array_size; j++ ) + { + if( !cl_memcmp( &p_adapter->mcast_array[j], &p_mac_array[i], + sizeof(mac_addr_t) ) ) + { + break; + } + } + + if( j != p_adapter->mcast_array_size ) + continue; + if ( ( p_mac_array[i].addr[0] == 1 && p_mac_array[i].addr[1] == 0 && p_mac_array[i].addr[2] == 0x5e && + p_mac_array[i].addr[3] == 0 && p_mac_array[i].addr[4] == 0 && p_mac_array[i].addr[5] == 1 ) || + !( p_mac_array[i].addr[0] == 1 && p_mac_array[i].addr[1] == 0 && p_mac_array[i].addr[2] == 0x5e ) + ) + { + ipoib_port_join_mcast( p_port, p_mac_array[i], IB_MC_REC_STATE_FULL_MEMBER ); + } + } + } + + /* Copy the MAC array. */ + NdisMoveMemory( p_adapter->mcast_array, p_mac_array, + num_macs * sizeof(mac_addr_t) ); + p_adapter->mcast_array_size = num_macs; + + if( p_port ) + ipoib_port_deref( p_port, ref_refresh_mcast ); + + IPOIB_EXIT( IPOIB_DBG_MCAST ); +} + + +ib_api_status_t +ipoib_reset_adapter( + IN ipoib_adapter_t* const p_adapter ) +{ + ib_api_status_t status; + ib_pnp_handle_t h_pnp; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + if( p_adapter->reset ) + return IB_INVALID_STATE; + + p_adapter->hung = FALSE; + p_adapter->reset = TRUE; + + if( p_adapter->h_pnp ) + { + h_pnp = p_adapter->h_pnp; + p_adapter->h_pnp = NULL; + status = p_adapter->p_ifc->dereg_pnp( h_pnp, __ipoib_pnp_dereg ); + if( status == IB_SUCCESS ) + status = IB_NOT_DONE; + } + else + { + status = __ipoib_pnp_reg( p_adapter, IB_PNP_FLAG_REG_COMPLETE ); + if( status == IB_SUCCESS ) + p_adapter->hung = FALSE; + } + if (status == IB_NOT_DONE) { + p_adapter->reset = TRUE; + } + else { + p_adapter->reset = FALSE; + } + IPOIB_EXIT( IPOIB_DBG_INIT ); + return status; +} + + +static void +__ipoib_pnp_dereg( + IN void* context ) +{ + ipoib_adapter_t* p_adapter; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + p_adapter = PARENT_STRUCT( context, ipoib_adapter_t, obj ); + + cl_thread_init(&p_adapter->destroy_thread, __ipoib_adapter_reset, (void*)p_adapter, "destroy_thread"); + + IPOIB_ENTER( IPOIB_DBG_INIT ); + +} + +static void +__ipoib_adapter_reset( + IN void* context) +{ + + ipoib_adapter_t *p_adapter; + ipoib_port_t *p_port; + ib_api_status_t status; + ib_pnp_event_t state; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + p_adapter = (ipoib_adapter_t*)context; + + /* Synchronize with destruction */ + KeWaitForMutexObject( + &p_adapter->mutex, Executive, KernelMode, FALSE, NULL ); + + cl_obj_lock( &p_adapter->obj ); + + CL_ASSERT( !p_adapter->h_pnp ); + + if( p_adapter->state != IB_PNP_PORT_REMOVE ) + p_adapter->state = IB_PNP_PORT_ADD; + + state = p_adapter->state; + + /* Destroy the current port instance if it still exists. */ + p_port = p_adapter->p_port; + p_adapter->p_port = NULL; + if ( p_adapter->p_stat ) + p_adapter->p_stat->p_prev_port = p_port; + cl_obj_unlock( &p_adapter->obj ); + + if( p_port ) + ipoib_port_destroy( p_port ); + ASSERT(p_adapter->reset == TRUE); + if( state != IB_PNP_PORT_REMOVE ) + { + status = __ipoib_pnp_reg( p_adapter, IB_PNP_FLAG_REG_COMPLETE ); + if( status != IB_SUCCESS ) + { + p_adapter->reset = FALSE; + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("__ipoib_pnp_reg returned %s\n", + p_adapter->p_ifc->get_err_str( status )) ); + NdisMResetComplete( + p_adapter->h_adapter, NDIS_STATUS_HARD_ERRORS, TRUE ); + } + } + else + { + p_adapter->reset = FALSE; + NdisMResetComplete( + p_adapter->h_adapter, NDIS_STATUS_SUCCESS, TRUE ); + status = IB_SUCCESS; + } + + /* Dereference the adapter since the previous registration is now gone. */ + cl_obj_deref( &p_adapter->obj ); + + KeReleaseMutex( &p_adapter->mutex, FALSE ); + + IPOIB_EXIT( IPOIB_DBG_INIT ); +} + + +void +ipoib_set_rate( + IN ipoib_adapter_t* const p_adapter, + IN const uint8_t link_width, + IN const uint8_t link_speed ) +{ + uint32_t rate; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + /* Set the link speed based on the IB link speed (1x vs 4x, etc). */ + switch( link_speed ) + { + case IB_LINK_SPEED_ACTIVE_2_5: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, + ("Link speed is 2.5Gs\n") ); + rate = IB_LINK_SPEED_ACTIVE_2_5; + break; + + case IB_LINK_SPEED_ACTIVE_5: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, + ("Link speed is 5G\n") ); + rate = IB_LINK_SPEED_ACTIVE_5; + break; + + case IB_LINK_SPEED_ACTIVE_10: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, + ("Link speed is 10G\n") ); + rate = IB_LINK_SPEED_ACTIVE_10; + break; + + default: + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Invalid link speed %d.\n", link_speed) ); + rate = 0; + } + + switch( link_width ) + { + case IB_LINK_WIDTH_ACTIVE_1X: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, + ("Link width is 1X\n") ); + rate *= ONE_X_IN_100BPS; + break; + + case IB_LINK_WIDTH_ACTIVE_4X: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, + ("Link width is 4X\n") ); + rate *= FOUR_X_IN_100BPS; + break; + + case IB_LINK_WIDTH_ACTIVE_12X: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, + ("Link width is 12X\n") ); + rate *= TWELVE_X_IN_100BPS; + break; + + default: + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Invalid link rate (%d).\n", link_width) ); + rate = 0; + } + + p_adapter->port_rate = rate; + IPOIB_EXIT( IPOIB_DBG_INIT ); +} + + +ib_api_status_t +ipoib_set_active( + IN ipoib_adapter_t* const p_adapter ) +{ + ib_pnp_event_t old_state; + uint8_t i; + ib_api_status_t status = IB_SUCCESS; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + cl_obj_lock( &p_adapter->obj ); + old_state = p_adapter->state; + + /* Change the state to indicate that we are now connected and live. */ + if( old_state == IB_PNP_PORT_INIT ) + p_adapter->state = IB_PNP_PORT_ACTIVE; + + cl_obj_unlock( &p_adapter->obj ); + + /* + * If we had a pending OID request for OID_GEN_LINK_SPEED, + * complete it now. + */ + switch( old_state ) + { + case IB_PNP_PORT_ADD: + ipoib_reg_addrs( p_adapter ); + /* Fall through. */ + + case IB_PNP_PORT_REMOVE: + ipoib_resume_oids( p_adapter ); + break; + + default: + if (p_adapter->guids.port_guid.pkey != IB_DEFAULT_PKEY) + { + status = ipoib_query_pkey_index(p_adapter); + if( IB_SUCCESS != status) + { + break; + } + } + /* Join all programmed multicast groups. */ + for( i = 0; i < p_adapter->mcast_array_size; i++ ) + { + ipoib_port_join_mcast( + p_adapter->p_port, p_adapter->mcast_array[i] ,IB_MC_REC_STATE_FULL_MEMBER); + } + + /* Register all existing addresses. */ + ipoib_reg_addrs( p_adapter ); + + ipoib_resume_oids( p_adapter ); + + /* + * Now that we're in the broadcast group, notify that + * we have a link. + */ + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, ("Link UP!\n") ); + NdisWriteErrorLogEntry( p_adapter->h_adapter, + EVENT_IPOIB_PORT_UP + (p_adapter->port_rate/ONE_X_IN_100BPS), + 1, p_adapter->port_rate ); + + if( !p_adapter->reset ) + { + NdisMIndicateStatus( p_adapter->h_adapter, NDIS_STATUS_MEDIA_CONNECT, + NULL, 0 ); + NdisMIndicateStatusComplete( p_adapter->h_adapter ); + } + } + + if( p_adapter->reset ) + { + p_adapter->reset = FALSE; + NdisMResetComplete( + p_adapter->h_adapter, NDIS_STATUS_SUCCESS, TRUE ); + } + + IPOIB_EXIT( IPOIB_DBG_INIT ); + return status; +} + + +/* + * If something goes wrong after the port goes active, e.g. + * - PortInfo query failure + * - MC Join timeout + * - etc + * Mark the port state as down, resume any pended OIDS, etc. + */ +void +ipoib_set_inactive( + IN ipoib_adapter_t* const p_adapter ) +{ + ib_pnp_event_t old_state; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + cl_obj_lock( &p_adapter->obj ); + old_state = p_adapter->state; + if( old_state != IB_PNP_PORT_REMOVE ) + p_adapter->state = IB_PNP_PORT_DOWN; + cl_obj_unlock( &p_adapter->obj ); + + /* + * If we had a pending OID request for OID_GEN_LINK_SPEED, + * complete it now. + */ + if( old_state == IB_PNP_PORT_INIT ) + { + NdisMIndicateStatus( p_adapter->h_adapter, + NDIS_STATUS_MEDIA_DISCONNECT, NULL, 0 ); + NdisMIndicateStatusComplete( p_adapter->h_adapter ); + + ipoib_resume_oids( p_adapter ); + } + + if( p_adapter->reset ) + { + p_adapter->reset = FALSE; + NdisMResetComplete( + p_adapter->h_adapter, NDIS_STATUS_SUCCESS, TRUE ); + } + + IPOIB_EXIT( IPOIB_DBG_INIT ); +} + + +NDIS_STATUS +ipoib_get_recv_stat( + IN ipoib_adapter_t* const p_adapter, + IN const ip_stat_sel_t stat_sel, + IN pending_oid_t* const p_oid_info ) +{ + uint64_t stat; + + IPOIB_ENTER( IPOIB_DBG_STAT ); + + CL_ASSERT( p_adapter ); + + cl_spinlock_acquire( &p_adapter->recv_stat_lock ); + switch( stat_sel ) + { + case IP_STAT_SUCCESS: + stat = p_adapter->recv_stats.comp.success; + break; + + case IP_STAT_ERROR: + stat = p_adapter->recv_stats.comp.error; + break; + + case IP_STAT_DROPPED: + stat = p_adapter->recv_stats.comp.dropped; + break; + + case IP_STAT_UCAST_BYTES: + stat = p_adapter->recv_stats.ucast.bytes; + break; + + case IP_STAT_UCAST_FRAMES: + stat = p_adapter->recv_stats.ucast.frames; + break; + + case IP_STAT_BCAST_BYTES: + stat = p_adapter->recv_stats.bcast.bytes; + break; + + case IP_STAT_BCAST_FRAMES: + stat = p_adapter->recv_stats.bcast.frames; + break; + + case IP_STAT_MCAST_BYTES: + stat = p_adapter->recv_stats.mcast.bytes; + break; + + case IP_STAT_MCAST_FRAMES: + stat = p_adapter->recv_stats.mcast.frames; + break; + + default: + stat = 0; + } + cl_spinlock_release( &p_adapter->recv_stat_lock ); + + *p_oid_info->p_bytes_needed = sizeof(uint64_t); + + if( p_oid_info->buf_len >= sizeof(uint64_t) ) + { + *((uint64_t*)p_oid_info->p_buf) = stat; + *p_oid_info->p_bytes_used = sizeof(uint64_t); + } + else if( p_oid_info->buf_len >= sizeof(uint32_t) ) + { + *((uint32_t*)p_oid_info->p_buf) = (uint32_t)stat; + *p_oid_info->p_bytes_used = sizeof(uint32_t); + } + else + { + *p_oid_info->p_bytes_used = 0; + IPOIB_EXIT( IPOIB_DBG_STAT ); + return NDIS_STATUS_INVALID_LENGTH; + } + + IPOIB_EXIT( IPOIB_DBG_STAT ); + return NDIS_STATUS_SUCCESS; +} + + +void +ipoib_inc_recv_stat( + IN ipoib_adapter_t* const p_adapter, + IN const ip_stat_sel_t stat_sel, + IN const size_t bytes OPTIONAL ) +{ + IPOIB_ENTER( IPOIB_DBG_STAT ); + + cl_spinlock_acquire( &p_adapter->recv_stat_lock ); + switch( stat_sel ) + { + case IP_STAT_ERROR: + p_adapter->recv_stats.comp.error++; + break; + + case IP_STAT_DROPPED: + p_adapter->recv_stats.comp.dropped++; + break; + + case IP_STAT_UCAST_BYTES: + case IP_STAT_UCAST_FRAMES: + p_adapter->recv_stats.comp.success++; + p_adapter->recv_stats.ucast.frames++; + p_adapter->recv_stats.ucast.bytes += bytes; + break; + + case IP_STAT_BCAST_BYTES: + case IP_STAT_BCAST_FRAMES: + p_adapter->recv_stats.comp.success++; + p_adapter->recv_stats.bcast.frames++; + p_adapter->recv_stats.bcast.bytes += bytes; + break; + + case IP_STAT_MCAST_BYTES: + case IP_STAT_MCAST_FRAMES: + p_adapter->recv_stats.comp.success++; + p_adapter->recv_stats.mcast.frames++; + p_adapter->recv_stats.mcast.bytes += bytes; + break; + + default: + break; + } + cl_spinlock_release( &p_adapter->recv_stat_lock ); + + IPOIB_EXIT( IPOIB_DBG_STAT ); +} + +NDIS_STATUS +ipoib_get_send_stat( + IN ipoib_adapter_t* const p_adapter, + IN const ip_stat_sel_t stat_sel, + IN pending_oid_t* const p_oid_info ) +{ + uint64_t stat; + + IPOIB_ENTER( IPOIB_DBG_STAT ); + + CL_ASSERT( p_adapter ); + + cl_spinlock_acquire( &p_adapter->send_stat_lock ); + switch( stat_sel ) + { + case IP_STAT_SUCCESS: + stat = p_adapter->send_stats.comp.success; + break; + + case IP_STAT_ERROR: + stat = p_adapter->send_stats.comp.error; + break; + + case IP_STAT_DROPPED: + stat = p_adapter->send_stats.comp.dropped; + break; + + case IP_STAT_UCAST_BYTES: + stat = p_adapter->send_stats.ucast.bytes; + break; + + case IP_STAT_UCAST_FRAMES: + stat = p_adapter->send_stats.ucast.frames; + break; + + case IP_STAT_BCAST_BYTES: + stat = p_adapter->send_stats.bcast.bytes; + break; + + case IP_STAT_BCAST_FRAMES: + stat = p_adapter->send_stats.bcast.frames; + break; + + case IP_STAT_MCAST_BYTES: + stat = p_adapter->send_stats.mcast.bytes; + break; + + case IP_STAT_MCAST_FRAMES: + stat = p_adapter->send_stats.mcast.frames; + break; + + default: + stat = 0; + } + cl_spinlock_release( &p_adapter->send_stat_lock ); + + *p_oid_info->p_bytes_needed = sizeof(uint64_t); + + if( p_oid_info->buf_len >= sizeof(uint64_t) ) + { + *((uint64_t*)p_oid_info->p_buf) = stat; + *p_oid_info->p_bytes_used = sizeof(uint64_t); + } + else if( p_oid_info->buf_len >= sizeof(uint32_t) ) + { + *((uint32_t*)p_oid_info->p_buf) = (uint32_t)stat; + *p_oid_info->p_bytes_used = sizeof(uint32_t); + } + else + { + *p_oid_info->p_bytes_used = 0; + IPOIB_EXIT( IPOIB_DBG_STAT ); + return NDIS_STATUS_INVALID_LENGTH; + } + + IPOIB_EXIT( IPOIB_DBG_STAT ); + return NDIS_STATUS_SUCCESS; +} + + +void +ipoib_inc_send_stat( + IN ipoib_adapter_t* const p_adapter, + IN const ip_stat_sel_t stat_sel, + IN const size_t bytes OPTIONAL ) +{ + IPOIB_ENTER( IPOIB_DBG_STAT ); + + cl_spinlock_acquire( &p_adapter->send_stat_lock ); + switch( stat_sel ) + { + case IP_STAT_ERROR: + p_adapter->send_stats.comp.error++; + break; + + case IP_STAT_DROPPED: + p_adapter->send_stats.comp.dropped++; + break; + + case IP_STAT_UCAST_BYTES: + case IP_STAT_UCAST_FRAMES: + p_adapter->send_stats.comp.success++; + p_adapter->send_stats.ucast.frames++; + p_adapter->send_stats.ucast.bytes += bytes; + break; + + case IP_STAT_BCAST_BYTES: + case IP_STAT_BCAST_FRAMES: + p_adapter->send_stats.comp.success++; + p_adapter->send_stats.bcast.frames++; + p_adapter->send_stats.bcast.bytes += bytes; + break; + + case IP_STAT_MCAST_BYTES: + case IP_STAT_MCAST_FRAMES: + p_adapter->send_stats.comp.success++; + p_adapter->send_stats.mcast.frames++; + p_adapter->send_stats.mcast.bytes += bytes; + break; + + default: + break; + } + cl_spinlock_release( &p_adapter->send_stat_lock ); + + IPOIB_EXIT( IPOIB_DBG_STAT ); +} diff --git a/branches/WOF2-3/ulp/ipoib/kernel/ipoib_adapter.h b/branches/WOF2-3/ulp/ipoib/kernel/ipoib_adapter.h new file mode 100644 index 00000000..03650035 --- /dev/null +++ b/branches/WOF2-3/ulp/ipoib/kernel/ipoib_adapter.h @@ -0,0 +1,439 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2006 Mellanox Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#ifndef _IPOIB_ADAPTER_H_ +#define _IPOIB_ADAPTER_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ip_stats.h" +#include "ipoib_stat.h" + + +/* + * Definitions + */ +#define MAX_MCAST 32 + +#define IPV4_ADDR_SIZE 4 + +#define PORT_NUM_INDEX_IN_GUID 3 /* 0 based index into big endian GUID to get port number */ + +/* + * Macros + */ +typedef enum {CSUM_DISABLED = 0, CSUM_ENABLED, CSUM_BYPASS} tCsumTypeEn; + +typedef struct _ipoib_params +{ + int32_t rq_depth; + int32_t rq_low_watermark; + int32_t sq_depth; + int32_t send_chksum_offload; //is actually of type tCsumTypeEn + int32_t recv_chksum_offload; //is actually of type tCsumTypeEn + uint32_t sa_timeout; + uint32_t sa_retry_cnt; + uint32_t recv_pool_ratio; + uint32_t payload_mtu; + boolean_t lso; + uint32_t xfer_block_size; + mac_addr_t conf_mac; + uint32_t mc_leave_rescan; + uint32_t guid_mask; + uint32_t bc_join_retry; +} ipoib_params_t; +/* +* FIELDS +* rq_depth +* Number of receive WQEs to allocate. +* +* rq_low_watermark +* Receives are indicated with NDIS_STATUS_RESOURCES when the number of +* receives posted to the RQ falls bellow this value. +* +* sq_depth +* Number of send WQEs to allocate. +* +* send_chksum_offload +* recv_chksum_offload +* Flags to indicate whether to offload send/recv checksums. +* 0 - No hardware cheksum +* 1 - Try to offload if the device support it +* 2 - Always report success (checksum bypass) +* +* wsdp_enabled +* Flag to indicate whether WSDP is enabled for an adapter adapter. +* +* static_lid +* LID to assign to the port if that port is down (not init) and has none. +* This feature allows a LID to be assigned, alowing locally targetted +* traffic to occur even on ports that are not plugged in. +* +* sa_timeout +* Time, in milliseconds, to wait for a response before retransmitting an +* SA query request. +* +* sa_retry_cnt +* Number of times to retry an SA query request. +* +* recv_pool_ratio +* Initial ratio of receive pool size to receive queue depth. +* +* grow_thresh +* Threshold at which to grow the receive pool. Valid values start are +* powers of 2, excluding 1. When zero, grows only when the pool is +* exhausted. Other values indicate fractional values +* (i.e. 2 indicates 1/2, 4 indicates 1/4, etc.) +* +* payload_mtu +* The maximum available size of IPoIB transfer unit. +* It should be lower by size of IPoIB header (==4B) +* For example, if the HCA support 4K MTU, +* upper threshold for payload mtu is 4092B and not 4096B +* lso +* It indicates if there's a support for hardware large/giant send offload +* +*********/ + + +typedef struct _pending_oid +{ + NDIS_OID oid; + PVOID p_buf; + ULONG buf_len; + PULONG p_bytes_used; + PULONG p_bytes_needed; + +} pending_oid_t; + + +typedef struct _ipoib_adapter +{ + cl_obj_t obj; + NDIS_HANDLE h_adapter; + PDEVICE_OBJECT pdo; + ipoib_ifc_data_t guids; + + cl_list_item_t entry; + + ib_al_handle_t h_al; + ib_pnp_handle_t h_pnp; + + ib_pnp_event_t state; + boolean_t hung; + boolean_t reset; + boolean_t registering; + + boolean_t pending_query; + pending_oid_t query_oid; + boolean_t pending_set; + pending_oid_t set_oid; + + struct _ipoib_port *p_port; + + uint32_t port_rate; + + ipoib_params_t params; + cl_spinlock_t recv_stat_lock; + ip_stats_t recv_stats; + cl_spinlock_t send_stat_lock; + ip_stats_t send_stats; + + boolean_t is_primary; + struct _ipoib_adapter *p_primary; + + uint32_t packet_filter; + + mac_addr_t mac; + mac_addr_t mcast_array[MAX_MCAST]; + uint8_t mcast_array_size; + + cl_qpool_t item_pool; + + KMUTEX mutex; + + cl_thread_t destroy_thread; + cl_vector_t ip_vector; + + cl_perf_t perf; + ib_al_ifc_t *p_ifc; + PIPOIB_ST_DEVICE p_stat; + +} ipoib_adapter_t; +/* +* FIELDS +* obj +* Complib object for reference counting and destruction synchronization. +* +* h_adapter +* NDIS adapter handle. +* +* guids +* CA and port GUIDs returned by the bus driver. +* +* entry +* List item for storing all adapters in a list for address translation. +* We add adapters when their packet filter is set to a non-zero value, +* and remove them when their packet filter is cleared. This is needed +* since user-mode removal events are generated after the packet filter +* is cleared, but before the adapter is destroyed. +* +* h_al +* AL handle for all IB resources. +* +* h_pnp +* PNP registration handle for port events. +* +* state +* State of the adapter. IB_PNP_PORT_ADD indicates that the adapter +* is ready to transfer data. +* +* hung +* Boolean flag used to return whether we are hung or not. +* +* p_port +* Pointer to an ipoib_port_t representing all resources for moving data +* on the IB fabric. +* +* rate +* Rate, in 100bps increments, of the link. +* +* params +* Configuration parameters. +* +* pending_query +* Indicates that an query OID request is being processed asynchronously. +* +* query_oid +* Information about the pended query OID request. +* Valid only if pending_query is TRUE. +* +* pending_set +* Indicates that an set OID request is being processed asynchronously. +* +* set_oid +* Information about the pended set OID request. +* Valid only if pending_set is TRUE. +* +* recv_lock +* Spinlock protecting receive processing. +* +* recv_stats +* Receive statistics. +* +* send_lock +* Spinlock protecting send processing. +* +* send_stats +* Send statistics. +* +* is_primary +* Boolean flag to indicate if an adapter is the primary adapter +* of a bundle. +* +* p_primary +* Pointer to the primary adapter for a bundle. +* +* packet_filter +* Packet filter set by NDIS. +* +* mac_addr +* Ethernet MAC address reported to NDIS. +* +* mcast_array +* List of multicast MAC addresses programmed by NDIS. +* +* mcast_array_size +* Number of entries in the multicat MAC address array; +* +* item_pool +* Pool of cl_pool_obj_t structures to use for queueing pending +* packets for transmission. +* +* mutex +* Mutex to synchronized PnP callbacks with destruction. +* +* ip_vector +* Vector of assigned IP addresses. +* +* p_ifc +* Pointer to transport interface. +* +*********/ + + +typedef struct _ats_reg +{ + ipoib_adapter_t *p_adapter; + ib_reg_svc_handle_t h_reg_svc; + +} ats_reg_t; +/* +* FIELDS +* p_adapter +* Pointer to the adapter to which this address is assigned. +* +* h_reg_svc +* Service registration handle. +*********/ + + +typedef struct _net_address_item +{ + ats_reg_t *p_reg; + union _net_address_item_address + { + ULONG as_ulong; + UCHAR as_bytes[IPV4_ADDR_SIZE]; + } address; + +} net_address_item_t; +/* +* FIELDS +* p_reg +* Pointer to the ATS registration assigned to this address. +* +* address +* Union representing the IP address as an unsigned long or as +* an array of bytes. +* +* as_ulong +* The IP address represented as an unsigned long. Windows stores +* IPs this way. +* +* as_bytes +* The IP address represented as an array of bytes. +*********/ + + +ib_api_status_t +ipoib_create_adapter( + IN NDIS_HANDLE wrapper_config_context, + IN void* const h_adapter, + OUT ipoib_adapter_t** const pp_adapter ); + + +ib_api_status_t +ipoib_start_adapter( + IN ipoib_adapter_t* const p_adapter ); + + +void +ipoib_destroy_adapter( + IN ipoib_adapter_t* const p_adapter ); + + +/* Joins/leaves mcast groups based on currently programmed mcast MACs. */ +void +ipoib_refresh_mcast( + IN ipoib_adapter_t* const p_adapter, + IN mac_addr_t* const p_mac_array, + IN const uint8_t num_macs ); +/* +* PARAMETERS +* p_adapter +* Instance whose multicast MAC address list to modify. +* +* p_mac_array +* Array of multicast MAC addresses assigned to the adapter. +* +* num_macs +* Number of MAC addresses in the array. +*********/ + + +NDIS_STATUS +ipoib_get_recv_stat( + IN ipoib_adapter_t* const p_adapter, + IN const ip_stat_sel_t stat_sel, + IN pending_oid_t* const p_oid_info ); + + +void +ipoib_inc_recv_stat( + IN ipoib_adapter_t* const p_adapter, + IN const ip_stat_sel_t stat_sel, + IN const size_t bytes OPTIONAL ); + + +NDIS_STATUS +ipoib_get_send_stat( + IN ipoib_adapter_t* const p_adapter, + IN const ip_stat_sel_t stat_sel, + IN pending_oid_t* const p_oid_info ); + + +void +ipoib_inc_send_stat( + IN ipoib_adapter_t* const p_adapter, + IN const ip_stat_sel_t stat_sel, + IN const size_t bytes OPTIONAL ); + + +void +ipoib_set_rate( + IN ipoib_adapter_t* const p_adapter, + IN const uint8_t link_width, + IN const uint8_t link_speed ); + + +ib_api_status_t +ipoib_set_active( + IN ipoib_adapter_t* const p_adapter ); + +void +ipoib_set_inactive( + IN ipoib_adapter_t* const p_adapter ); + +ib_api_status_t +ipoib_reset_adapter( + IN ipoib_adapter_t* const p_adapter ); + +void +ipoib_reg_addrs( + IN ipoib_adapter_t* const p_adapter ); + +void +ipoib_dereg_addrs( + IN ipoib_adapter_t* const p_adapter ); + +#endif /* _IPOIB_ADAPTER_H_ */ diff --git a/branches/WOF2-3/ulp/ipoib/kernel/ipoib_debug.h b/branches/WOF2-3/ulp/ipoib/kernel/ipoib_debug.h new file mode 100644 index 00000000..93701142 --- /dev/null +++ b/branches/WOF2-3/ulp/ipoib/kernel/ipoib_debug.h @@ -0,0 +1,300 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2006 Mellanox Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#ifndef _IPOIB_DEBUG_H_ +#define _IPOIB_DEBUG_H_ + + +#define __MODULE__ "[IPoIB]" + +#include + + +/* Object types for passing into complib. */ +#define IPOIB_OBJ_INSTANCE 1 +#define IPOIB_OBJ_PORT 2 +#define IPOIB_OBJ_ENDPOINT 3 + + +extern uint32_t g_ipoib_dbg_level; +extern uint32_t g_ipoib_dbg_flags; + + +#if defined(EVENT_TRACING) +// +// Software Tracing Definitions +// +#define WPP_CONTROL_GUIDS \ + WPP_DEFINE_CONTROL_GUID( \ + IPOIBCtlGuid,(3F9BC73D, EB03, 453a, B27B, 20F9A664211A), \ + WPP_DEFINE_BIT(IPOIB_DBG_ERROR) \ + WPP_DEFINE_BIT(IPOIB_DBG_INIT) \ + WPP_DEFINE_BIT(IPOIB_DBG_PNP) \ + WPP_DEFINE_BIT(IPOIB_DBG_SEND) \ + WPP_DEFINE_BIT(IPOIB_DBG_RECV) \ + WPP_DEFINE_BIT(IPOIB_DBG_ENDPT) \ + WPP_DEFINE_BIT(IPOIB_DBG_IB) \ + WPP_DEFINE_BIT(IPOIB_DBG_BUF) \ + WPP_DEFINE_BIT(IPOIB_DBG_MCAST) \ + WPP_DEFINE_BIT(IPOIB_DBG_ALLOC) \ + WPP_DEFINE_BIT(IPOIB_DBG_OID) \ + WPP_DEFINE_BIT(IPOIB_DBG_IOCTL) \ + WPP_DEFINE_BIT(IPOIB_DBG_STAT) \ + WPP_DEFINE_BIT(IPOIB_DBG_OBJ)) + + + +#define WPP_LEVEL_FLAGS_ENABLED(lvl, flags) \ + (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= lvl) +#define WPP_LEVEL_FLAGS_LOGGER(lvl,flags) WPP_LEVEL_LOGGER(flags) +#define WPP_FLAG_ENABLED(flags) \ + (WPP_LEVEL_ENABLED(flags) && \ + WPP_CONTROL(WPP_BIT_ ## flags).Level >= TRACE_LEVEL_VERBOSE) +#define WPP_FLAG_LOGGER(flags) WPP_LEVEL_LOGGER(flags) + +// begin_wpp config +// IPOIB_ENTER(FLAG); +// IPOIB_EXIT(FLAG); +// USEPREFIX(IPOIB_PRINT, "%!STDPREFIX! [IPoIB] :%!FUNC!() :"); +// USEPREFIX(IPOIB_PRINT_EXIT, "%!STDPREFIX! [IPoIB] :%!FUNC!() :"); +// USESUFFIX(IPOIB_PRINT_EXIT, "[IpoIB] :%!FUNC!():]"); +// USESUFFIX(IPOIB_ENTER, " [IPoIB] :%!FUNC!():["); +// USESUFFIX(IPOIB_EXIT, " [IPoIB] :%!FUNC!():]"); +// end_wpp + +#else + +#include + + +/* + * Debug macros + */ +#define IPOIB_DBG_ERR (1 << 0) +#define IPOIB_DBG_INIT (1 << 1) +#define IPOIB_DBG_PNP (1 << 2) +#define IPOIB_DBG_SEND (1 << 3) +#define IPOIB_DBG_RECV (1 << 4) +#define IPOIB_DBG_ENDPT (1 << 5) +#define IPOIB_DBG_IB (1 << 6) +#define IPOIB_DBG_BUF (1 << 7) +#define IPOIB_DBG_MCAST (1 << 8) +#define IPOIB_DBG_ALLOC (1 << 9) +#define IPOIB_DBG_OID (1 << 10) +#define IPOIB_DBG_IOCTL (1 << 11) +#define IPOIB_DBG_STAT (1 << 12) +#define IPOIB_DBG_OBJ (1 << 13) + +#define IPOIB_DBG_ERROR (CL_DBG_ERROR | IPOIB_DBG_ERR) +#define IPOIB_DBG_ALL CL_DBG_ALL + + +#if DBG + +// assignment of _level_ is need to to overcome warning C4127 +#define IPOIB_PRINT(_level_,_flag_,_msg_) \ + { \ + __pragma(warning(suppress:6326)) \ + if( g_ipoib_dbg_level >= (_level_) ) \ + CL_TRACE( _flag_, g_ipoib_dbg_flags, _msg_ ); \ + } + +#define IPOIB_PRINT_EXIT(_level_,_flag_,_msg_) \ + { \ + __pragma(warning(suppress:6326)) \ + if( g_ipoib_dbg_level >= (_level_) ) \ + CL_TRACE( _flag_, g_ipoib_dbg_flags, _msg_ );\ + IPOIB_EXIT(_flag_);\ + } + +#define IPOIB_ENTER(_flag_) \ + { \ + __pragma(warning(suppress:6326)) \ + if( g_ipoib_dbg_level >= TRACE_LEVEL_VERBOSE ) \ + CL_ENTER( _flag_, g_ipoib_dbg_flags ); \ + } + +#define IPOIB_EXIT(_flag_)\ + { \ + __pragma(warning(suppress:6326)) \ + if( g_ipoib_dbg_level >= TRACE_LEVEL_VERBOSE ) \ + CL_EXIT( _flag_, g_ipoib_dbg_flags ); \ + } + +#define IPOIB_TRACE_BYTES( lvl, ptr, len ) \ + { \ + __pragma(warning(suppress:6326)) \ + if( g_ipoib_dbg_level >= (_level_) && \ + (g_ipoib_dbg_flags & (_flag_)) ) \ + { \ + size_t _loop_; \ + for( _loop_ = 0; _loop_ < (len); ++_loop_ ) \ + { \ + cl_dbg_out( "0x%.2X ", ((uint8_t*)(ptr))[_loop_] ); \ + if( (_loop_ + 1)% 16 == 0 ) \ + cl_dbg_out("\n"); \ + else if( (_loop_ % 4 + 1) == 0 ) \ + cl_dbg_out(" "); \ + } \ + cl_dbg_out("\n"); \ + } \ + } + +#else + +#define IPOIB_PRINT(lvl, flags, msg) + +#define IPOIB_PRINT_EXIT(_level_,_flag_,_msg_) + +#define IPOIB_ENTER(_flag_) + +#define IPOIB_EXIT(_flag_) + +#define IPOIB_TRACE_BYTES( lvl, ptr, len ) + +#endif + +#endif //EVENT_TRACING + + +enum ipoib_perf_counters +{ + SendBundle, + SendPackets, + PortSend, + GetEthHdr, + SendMgrQueue, + GetEndpt, + EndptQueue, + QueuePacket, + BuildSendDesc, + SendMgrFilter, + FilterIp, + QueryIp, + SendTcp, + FilterUdp, + QueryUdp, + SendUdp, + FilterDhcp, + FilterArp, + SendGen, + SendCopy, + PostSend, + ProcessFailedSends, + SendCompBundle, + SendCb, + PollSend, + SendComp, + FreeSendBuf, + RearmSend, + PortResume, + RecvCompBundle, + RecvCb, + PollRecv, + FilterRecv, + GetRecvEndpts, + GetEndptByGid, + GetEndptByLid, + EndptInsert, + RecvTcp, + RecvUdp, + RecvDhcp, + RecvArp, + RecvGen, + BuildPktArray, + PreparePkt, + GetNdisPkt, + RecvNdisIndicate, + PutRecvList, + RepostRecv, + GetRecv, + PostRecv, + RearmRecv, + ReturnPacket, + ReturnPutRecv, + ReturnRepostRecv, + ReturnPreparePkt, + ReturnNdisIndicate, + + /* Must be last! */ + MaxPerf + +}; + + +enum ref_cnt_buckets +{ + ref_init = 0, + ref_refresh_mcast, /* only used in refresh_mcast */ + ref_send_packets, /* only in send_packets */ + ref_get_recv, + ref_repost, /* only in __recv_mgr_repost */ + ref_recv_cb, /* only in __recv_cb */ + ref_send_cb, /* only in __send_cb */ + ref_port_up, + ref_get_bcast, + ref_bcast, /* join and create, used as base only */ + ref_join_mcast, + ref_leave_mcast, + ref_endpt_track, /* used when endpt is in port's child list. */ + + ref_array_size, /* Used to size the array of ref buckets. */ + ref_mask = 100, /* Used to differentiate derefs. */ + + ref_failed_recv_wc = 100 + ref_get_recv, + ref_recv_inv_len = 200 + ref_get_recv, + ref_recv_loopback = 300 + ref_get_recv, + ref_recv_filter = 400 + ref_get_recv, + + ref_bcast_get_cb = 100 + ref_get_bcast, + + ref_join_bcast = 100 + ref_bcast, + ref_create_bcast = 200 + ref_bcast, + ref_bcast_inv_state = 300 + ref_bcast, + ref_bcast_req_failed = 400 + ref_bcast, + ref_bcast_error = 500 + ref_bcast, + ref_bcast_join_failed = 600 + ref_bcast, + ref_bcast_create_failed = 700 + ref_bcast, + + ref_mcast_inv_state = 100 + ref_join_mcast, + ref_mcast_req_failed = 200 + ref_join_mcast, + ref_mcast_no_endpt = 300 + ref_join_mcast, + ref_mcast_av_failed = 400 + ref_join_mcast, + ref_mcast_join_failed = 500 + ref_join_mcast, + + ref_port_info_cb = 100 + ref_port_up + +}; + + +#endif /* _IPOIB_DEBUG_H_ */ diff --git a/branches/WOF2-3/ulp/ipoib/kernel/ipoib_driver.c b/branches/WOF2-3/ulp/ipoib/kernel/ipoib_driver.c new file mode 100644 index 00000000..5a27df65 --- /dev/null +++ b/branches/WOF2-3/ulp/ipoib/kernel/ipoib_driver.c @@ -0,0 +1,2597 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2006 Mellanox Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include "limits.h" +#include "ipoib_driver.h" +#include "ipoib_debug.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "ipoib_driver.tmh" +#endif + +#include "ipoib_port.h" +#include "ipoib_ibat.h" +#include +#include +#include +#include +#include "ntstrsafe.h" +#include "strsafe.h" +#include + + + + + +#if defined(NDIS50_MINIPORT) +#define MAJOR_NDIS_VERSION 5 +#define MINOR_NDIS_VERSION 0 +#elif defined (NDIS51_MINIPORT) +#define MAJOR_NDIS_VERSION 5 +#define MINOR_NDIS_VERSION 1 +#else +#error NDIS Version not defined, try defining NDIS50_MINIPORT or NDIS51_MINIPORT +#endif + +PDRIVER_OBJECT g_p_drv_obj; + +static const NDIS_OID SUPPORTED_OIDS[] = +{ + OID_GEN_SUPPORTED_LIST, + OID_GEN_HARDWARE_STATUS, + OID_GEN_MEDIA_SUPPORTED, + OID_GEN_MEDIA_IN_USE, + OID_GEN_MAXIMUM_LOOKAHEAD, + OID_GEN_MAXIMUM_FRAME_SIZE, + OID_GEN_LINK_SPEED, + OID_GEN_TRANSMIT_BUFFER_SPACE, + OID_GEN_RECEIVE_BUFFER_SPACE, + OID_GEN_TRANSMIT_BLOCK_SIZE, + OID_GEN_RECEIVE_BLOCK_SIZE, + OID_GEN_VENDOR_ID, + OID_GEN_VENDOR_DESCRIPTION, + OID_GEN_CURRENT_PACKET_FILTER, + OID_GEN_CURRENT_LOOKAHEAD, + OID_GEN_DRIVER_VERSION, + OID_GEN_MAXIMUM_TOTAL_SIZE, + OID_GEN_PROTOCOL_OPTIONS, + OID_GEN_MAC_OPTIONS, + OID_GEN_MEDIA_CONNECT_STATUS, + OID_GEN_MAXIMUM_SEND_PACKETS, + OID_GEN_NETWORK_LAYER_ADDRESSES, + OID_GEN_VENDOR_DRIVER_VERSION, + OID_GEN_PHYSICAL_MEDIUM, + OID_GEN_XMIT_OK, + OID_GEN_RCV_OK, + OID_GEN_XMIT_ERROR, + OID_GEN_RCV_ERROR, + OID_GEN_RCV_NO_BUFFER, + OID_GEN_DIRECTED_BYTES_XMIT, + OID_GEN_DIRECTED_FRAMES_XMIT, + OID_GEN_MULTICAST_BYTES_XMIT, + OID_GEN_MULTICAST_FRAMES_XMIT, + OID_GEN_BROADCAST_BYTES_XMIT, + OID_GEN_BROADCAST_FRAMES_XMIT, + OID_GEN_DIRECTED_BYTES_RCV, + OID_GEN_DIRECTED_FRAMES_RCV, + OID_GEN_MULTICAST_BYTES_RCV, + OID_GEN_MULTICAST_FRAMES_RCV, + OID_GEN_BROADCAST_BYTES_RCV, + OID_GEN_BROADCAST_FRAMES_RCV, + OID_802_3_PERMANENT_ADDRESS, + OID_802_3_CURRENT_ADDRESS, + OID_802_3_MULTICAST_LIST, + OID_802_3_MAXIMUM_LIST_SIZE, + OID_802_3_MAC_OPTIONS, + OID_802_3_RCV_ERROR_ALIGNMENT, + OID_802_3_XMIT_ONE_COLLISION, + OID_802_3_XMIT_MORE_COLLISIONS, + OID_TCP_TASK_OFFLOAD +}; + +static const unsigned char VENDOR_ID[] = {0x00, 0x06, 0x6A, 0x00}; + +#define VENDOR_DESCRIPTION "Internet Protocol over InfiniBand" + +#define IB_INFINITE_SERVICE_LEASE 0xFFFFFFFF + +//The mask is 8 bit and can't contain more than 6 non-zero bits +#define MAX_GUID_MAX 0xFC + + +/* Global driver debug level */ +uint32_t g_ipoib_dbg_level = TRACE_LEVEL_ERROR; +uint32_t g_ipoib_dbg_flags = 0x00000fff; +ipoib_globals_t g_ipoib = {0}; + +typedef struct _IPOIB_REG_ENTRY +{ + NDIS_STRING RegName; // variable name text + BOOLEAN bRequired; // 1 -> required, 0 -> optional + UINT FieldOffset; // offset in parent struct + UINT FieldSize; // size (in bytes) of the field + UINT Default; // default value to use + UINT Min; // minimum value allowed + UINT Max; // maximum value allowed +} IPOIB_REG_ENTRY, *PIPOIB_REG_ENTRY; + +IPOIB_REG_ENTRY HCARegTable[] = { + // reg value name If Required Offset in parentr struct Field size Default Min Max + {NDIS_STRING_CONST("GUIDMask"), 0, IPOIB_OFFSET(guid_mask), IPOIB_SIZE(guid_mask), 0, 0, MAX_GUID_MAX}, + /* GUIDMask should be the first element */ + {NDIS_STRING_CONST("RqDepth"), 1, IPOIB_OFFSET(rq_depth), IPOIB_SIZE(rq_depth), 512, 128, 1024}, + {NDIS_STRING_CONST("RqLowWatermark"), 0, IPOIB_OFFSET(rq_low_watermark), IPOIB_SIZE(rq_low_watermark), 4, 2, 8}, + {NDIS_STRING_CONST("SqDepth"), 1, IPOIB_OFFSET(sq_depth), IPOIB_SIZE(sq_depth), 512, 128, 1024}, + {NDIS_STRING_CONST("SendChksum"), 1, IPOIB_OFFSET(send_chksum_offload), IPOIB_SIZE(send_chksum_offload),CSUM_ENABLED,CSUM_DISABLED,CSUM_BYPASS}, + {NDIS_STRING_CONST("RecvChksum"), 1, IPOIB_OFFSET(recv_chksum_offload), IPOIB_SIZE(recv_chksum_offload),CSUM_ENABLED,CSUM_DISABLED,CSUM_BYPASS}, + {NDIS_STRING_CONST("SaTimeout"), 1, IPOIB_OFFSET(sa_timeout), IPOIB_SIZE(sa_timeout), 1000, 250, UINT_MAX}, + {NDIS_STRING_CONST("SaRetries"), 1, IPOIB_OFFSET(sa_retry_cnt), IPOIB_SIZE(sa_retry_cnt), 10, 1, UINT_MAX}, + {NDIS_STRING_CONST("RecvRatio"), 1, IPOIB_OFFSET(recv_pool_ratio), IPOIB_SIZE(recv_pool_ratio), 1, 1, 10}, + {NDIS_STRING_CONST("PayloadMtu"), 1, IPOIB_OFFSET(payload_mtu), IPOIB_SIZE(payload_mtu), 2044, 512, 4092}, + {NDIS_STRING_CONST("lso"), 0, IPOIB_OFFSET(lso), IPOIB_SIZE(lso), 0, 0, 1}, + {NDIS_STRING_CONST("MCLeaveRescan"), 1, IPOIB_OFFSET(mc_leave_rescan), IPOIB_SIZE(mc_leave_rescan), 260, 1, 3600}, + {NDIS_STRING_CONST("BCJoinRetry"), 1, IPOIB_OFFSET(bc_join_retry), IPOIB_SIZE(bc_join_retry), 50, 0, 1000} + +}; + +#define IPOIB_NUM_REG_PARAMS (sizeof (HCARegTable) / sizeof(IPOIB_REG_ENTRY)) + + +void +ipoib_create_log( + NDIS_HANDLE h_adapter, + UINT ind, + ULONG eventLogMsgId) + +{ +#define cMaxStrLen 40 +#define cArrLen 3 + + PWCHAR logMsgArray[cArrLen]; + WCHAR strVal[cMaxStrLen]; + NDIS_STRING AdapterInstanceName; + + IPOIB_INIT_NDIS_STRING(&AdapterInstanceName); + if (NdisMQueryAdapterInstanceName(&AdapterInstanceName, h_adapter)!= NDIS_STATUS_SUCCESS ){ + ASSERT(FALSE); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR,IPOIB_DBG_ERROR, ("[IPoIB] Init:Failed to retreive adapter name.\n")); + return; + } + logMsgArray[0] = AdapterInstanceName.Buffer; + + if (RtlStringCbPrintfW(strVal, sizeof(strVal), L"0x%x", HCARegTable[ind].Default) != STATUS_SUCCESS) { + ASSERT(FALSE); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR,IPOIB_DBG_ERROR, + ("[IPoIB] Init: Problem copying string value: exiting\n")); + return; + } + + logMsgArray[0] = AdapterInstanceName.Buffer; + logMsgArray[1] = HCARegTable[ind].RegName.Buffer; + logMsgArray[2] = strVal; + + NdisWriteEventLogEntry(g_p_drv_obj, eventLogMsgId, 0, cArrLen, &logMsgArray, 0, NULL); + +} + + + +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT p_drv_obj, + IN PUNICODE_STRING p_reg_path ); + +VOID +ipoib_unload( + IN PDRIVER_OBJECT p_drv_obj ); + +NDIS_STATUS +ipoib_initialize( + OUT PNDIS_STATUS p_open_err_status, + OUT PUINT p_selected_medium_index, + IN PNDIS_MEDIUM medium_array, + IN UINT medium_array_size, + IN NDIS_HANDLE h_adapter, + IN NDIS_HANDLE wrapper_configuration_context ); + +BOOLEAN +ipoib_check_for_hang( + IN NDIS_HANDLE adapter_context ); + +void +ipoib_halt( + IN NDIS_HANDLE adapter_context ); + +NDIS_STATUS +ipoib_query_info( + IN NDIS_HANDLE adapter_context, + IN NDIS_OID oid, + IN PVOID info_buf, + IN ULONG info_buf_len, + OUT PULONG p_bytes_written, + OUT PULONG p_bytes_needed ); + +NDIS_STATUS +ipoib_reset( + OUT PBOOLEAN p_addressing_reset, + IN NDIS_HANDLE adapter_context ); + +NDIS_STATUS +ipoib_set_info( + IN NDIS_HANDLE adapter_context, + IN NDIS_OID oid, + IN PVOID info_buf, + IN ULONG info_buf_length, + OUT PULONG p_bytes_read, + OUT PULONG p_bytes_needed ); + +void +ipoib_send_packets( + IN NDIS_HANDLE adapter_context, + IN PPNDIS_PACKET packet_array, + IN UINT num_packets ); + +void +ipoib_pnp_notify( + IN NDIS_HANDLE adapter_context, + IN NDIS_DEVICE_PNP_EVENT pnp_event, + IN PVOID info_buf, + IN ULONG info_buf_len ); + +void +ipoib_shutdown( + IN PVOID adapter_context ); + +static void +ipoib_complete_query( + IN ipoib_adapter_t* const p_adapter, + IN pending_oid_t* const p_oid_info, + IN const NDIS_STATUS status, + IN const void* const p_buf, + IN const ULONG buf_len ); + +static NDIS_STATUS +__ipoib_set_net_addr( + IN ipoib_adapter_t * p_adapter, + IN PVOID info_buf, + IN ULONG info_buf_len, + OUT PULONG p_bytes_read, + OUT PULONG p_bytes_needed ); + +static NDIS_STATUS +__ipoib_get_tcp_task_offload( + IN ipoib_adapter_t* p_adapter, + IN pending_oid_t* const p_oid_info ); + +static void +__ipoib_ats_reg_cb( + IN ib_reg_svc_rec_t *p_reg_svc_rec ); + +static void +__ipoib_ats_dereg_cb( + IN void *context ); + +static NTSTATUS +__ipoib_read_registry( + IN UNICODE_STRING* const p_registry_path ); + + +//! Standard Windows Device Driver Entry Point +/*! DriverEntry is the first routine called after a driver is loaded, and +is responsible for initializing the driver. On W2k this occurs when the PnP +Manager matched a PnP ID to one in an INF file that references this driver. +Any not success return value will cause the driver to fail to load. +IRQL = PASSIVE_LEVEL + +@param p_drv_obj Pointer to Driver Object for this device driver +@param p_registry_path Pointer to unicode string containing path to this driver's registry area +@return STATUS_SUCCESS, NDIS_STATUS_BAD_CHARACTERISTICS, NDIS_STATUS_BAD_VERSION, +NDIS_STATUS_RESOURCES, or NDIS_STATUS_FAILURE +*/ +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT p_drv_obj, + IN PUNICODE_STRING p_registry_path ) +{ + NDIS_STATUS status; + NDIS_HANDLE ndis_handle; + NDIS_MINIPORT_CHARACTERISTICS characteristics; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + g_p_drv_obj = p_drv_obj; + +#ifdef _DEBUG_ + PAGED_CODE(); +#endif +#if defined(EVENT_TRACING) + WPP_INIT_TRACING(p_drv_obj, p_registry_path); +#endif + status = CL_INIT; + if( !NT_SUCCESS( status ) ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("cl_init failed.\n") ); + return status; + } + + status = NDIS_STATUS_SUCCESS; + ndis_handle = NULL; + + __ipoib_read_registry(p_registry_path); + + KeInitializeSpinLock( &g_ipoib.lock ); + cl_qlist_init( &g_ipoib.adapter_list ); + ipoib_st_init(); + g_stat.drv.obj = p_drv_obj; + + NdisMInitializeWrapper( + &g_ipoib.h_ndis_wrapper, p_drv_obj, p_registry_path, NULL ); + + memset(&characteristics, 0, sizeof(characteristics)); + characteristics.MajorNdisVersion = MAJOR_NDIS_VERSION; + characteristics.MinorNdisVersion = MINOR_NDIS_VERSION; + characteristics.CheckForHangHandler = ipoib_check_for_hang; + characteristics.HaltHandler = ipoib_halt; + characteristics.InitializeHandler = ipoib_initialize; + characteristics.QueryInformationHandler = ipoib_query_info; + characteristics.ResetHandler = ipoib_reset; + characteristics.SetInformationHandler = ipoib_set_info; + + characteristics.ReturnPacketHandler = ipoib_return_packet; + characteristics.SendPacketsHandler = ipoib_send_packets; + +#ifdef NDIS51_MINIPORT + characteristics.PnPEventNotifyHandler = ipoib_pnp_notify; + characteristics.AdapterShutdownHandler = ipoib_shutdown; +#endif + + status = NdisMRegisterMiniport( + g_ipoib.h_ndis_wrapper, &characteristics, sizeof(characteristics) ); + if( status != NDIS_STATUS_SUCCESS ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("NdisMRegisterMiniport failed with status of %d\n", status) ); + NdisTerminateWrapper( g_ipoib.h_ndis_wrapper, NULL ); + CL_DEINIT; + return status; + } + + NdisMRegisterUnloadHandler( g_ipoib.h_ndis_wrapper, ipoib_unload ); + + IPOIB_PRINT_EXIT(TRACE_LEVEL_WARNING, IPOIB_DBG_INIT, + ("=====> DriverEntry exited\n")); + return status; +} + + +static NTSTATUS +__ipoib_read_registry( + IN UNICODE_STRING* const p_registry_path ) +{ + NTSTATUS status; + /* Remember the terminating entry in the table below. */ + RTL_QUERY_REGISTRY_TABLE table[4]; + UNICODE_STRING param_path; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + RtlInitUnicodeString( ¶m_path, NULL ); + param_path.MaximumLength = p_registry_path->Length + + sizeof(L"\\Parameters"); + param_path.Buffer = cl_zalloc( param_path.MaximumLength ); + if( !param_path.Buffer ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to allocate parameters path buffer.\n") ); + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlAppendUnicodeStringToString( ¶m_path, p_registry_path ); + RtlAppendUnicodeToString( ¶m_path, L"\\Parameters" ); + + /* + * Clear the table. This clears all the query callback pointers, + * and sets up the terminating table entry. + */ + cl_memclr( table, sizeof(table) ); + + /* Setup the table entries. */ + table[0].Flags = RTL_QUERY_REGISTRY_DIRECT; + table[0].Name = L"DebugLevel"; + table[0].EntryContext = &g_ipoib_dbg_level; + table[0].DefaultType = REG_DWORD; + table[0].DefaultData = &g_ipoib_dbg_level; + table[0].DefaultLength = sizeof(ULONG); + + table[1].Flags = RTL_QUERY_REGISTRY_DIRECT; + table[1].Name = L"DebugFlags"; + table[1].EntryContext = &g_ipoib_dbg_flags; + table[1].DefaultType = REG_DWORD; + table[1].DefaultData = &g_ipoib_dbg_flags; + table[1].DefaultLength = sizeof(ULONG); + + table[2].Flags = RTL_QUERY_REGISTRY_DIRECT; + table[2].Name = L"bypass_check_bcast_rate"; + table[2].EntryContext = &g_ipoib.bypass_check_bcast_rate; + table[2].DefaultType = REG_DWORD; + table[2].DefaultData = &g_ipoib.bypass_check_bcast_rate; + table[2].DefaultLength = sizeof(ULONG); + + /* Have at it! */ + status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE, + param_path.Buffer, table, NULL, NULL ); + + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("debug level %d debug flags 0x%.8x\n", + g_ipoib_dbg_level, + g_ipoib_dbg_flags)); + +#if DBG + if( g_ipoib_dbg_flags & IPOIB_DBG_ERR ) + g_ipoib_dbg_flags |= CL_DBG_ERROR; +#endif + + cl_free( param_path.Buffer ); + IPOIB_EXIT( IPOIB_DBG_INIT ); + return status; +} + + +VOID +ipoib_unload( + IN PDRIVER_OBJECT p_drv_obj ) +{ + IPOIB_ENTER( IPOIB_DBG_INIT ); + #if defined(EVENT_TRACING) + WPP_CLEANUP(p_drv_obj); + #endif + + UNREFERENCED_PARAMETER( p_drv_obj ); + CL_DEINIT; + IPOIB_EXIT( IPOIB_DBG_INIT ); +} + + + +NDIS_STATUS +ipoib_get_adapter_params( + IN NDIS_HANDLE* const wrapper_config_context, + IN OUT ipoib_adapter_t *p_adapter, + OUT PUCHAR *p_mac, + OUT UINT *p_len) +{ + NDIS_STATUS status; + NDIS_HANDLE h_config; + NDIS_CONFIGURATION_PARAMETER *p_param; + UINT value; + PIPOIB_REG_ENTRY pRegEntry; + UINT i; + PUCHAR structPointer; + int sq_depth_step = 128; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + NdisOpenConfiguration( &status, &h_config, wrapper_config_context ); + if( status != NDIS_STATUS_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("NdisOpenConfiguration returned 0x%.8x\n", status) ); + return status; + } + + // read all the registry values + for (i = 0, pRegEntry = HCARegTable; i < IPOIB_NUM_REG_PARAMS; ++i) + { + // initialize pointer to appropriate place inside 'params' + structPointer = (PUCHAR) &p_adapter->params + pRegEntry[i].FieldOffset; + + // Get the configuration value for a specific parameter. Under NT the + // parameters are all read in as DWORDs. + NdisReadConfiguration( + &status, + &p_param, + h_config, + &pRegEntry[i].RegName, + NdisParameterInteger); + + // If the parameter was present, then check its value for validity. + if (status == NDIS_STATUS_SUCCESS) + { + // Check that param value is not too small or too large + if (p_param->ParameterData.IntegerData < pRegEntry[i].Min || + p_param->ParameterData.IntegerData > pRegEntry[i].Max) + { + value = pRegEntry[i].Default; + ipoib_create_log(p_adapter->h_adapter, i, EVENT_IPOIB_WRONG_PARAMETER_WRN); + IPOIB_PRINT(TRACE_LEVEL_VERBOSE, IPOIB_DBG_INIT, ("Read configuration.Registry %S value is out of range, setting default value= 0x%x\n", pRegEntry[i].RegName.Buffer, value)); + + } + else + { + value = p_param->ParameterData.IntegerData; + IPOIB_PRINT(TRACE_LEVEL_VERBOSE, IPOIB_DBG_INIT, ("Read configuration. Registry %S, Value= 0x%x\n", pRegEntry[i].RegName.Buffer, value)); + } + } + + else + { + value = pRegEntry[i].Default; + status = NDIS_STATUS_SUCCESS; + if (pRegEntry[i].bRequired) + { + ipoib_create_log(p_adapter->h_adapter, i, EVENT_IPOIB_WRONG_PARAMETER_ERR); + IPOIB_PRINT(TRACE_LEVEL_ERROR, IPOIB_DBG_INIT, ("Read configuration.Registry %S value not found, setting default value= 0x%x\n", pRegEntry[i].RegName.Buffer, value)); + } + else + { + ipoib_create_log(p_adapter->h_adapter, i, EVENT_IPOIB_WRONG_PARAMETER_INFO); + IPOIB_PRINT(TRACE_LEVEL_VERBOSE, IPOIB_DBG_INIT, ("Read configuration. Registry %S value not found, Value= 0x%x\n", pRegEntry[i].RegName.Buffer, value)); + } + + } + // + // Store the value in the adapter structure. + // + switch(pRegEntry[i].FieldSize) + { + case 1: + *((PUCHAR) structPointer) = (UCHAR) value; + break; + + case 2: + *((PUSHORT) structPointer) = (USHORT) value; + break; + + case 4: + *((PULONG) structPointer) = (ULONG) value; + break; + + default: + IPOIB_PRINT(TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, ("Bogus field size %d\n", pRegEntry[i].FieldSize)); + break; + } + } + + // Send queue depth needs to be a power of two + //static const INT sq_depth_step = 128; + + if (p_adapter->params.sq_depth % sq_depth_step) { + static const c_sq_ind = 2; + p_adapter->params.sq_depth = sq_depth_step *( + p_adapter->params.sq_depth / sq_depth_step + !!( (p_adapter->params.sq_depth % sq_depth_step) > (sq_depth_step/2) )); + ipoib_create_log(p_adapter->h_adapter, c_sq_ind, EVENT_IPOIB_WRONG_PARAMETER_WRN); + IPOIB_PRINT(TRACE_LEVEL_VERBOSE, IPOIB_DBG_INIT, ("SQ DEPTH value was rounded to the closest acceptable value of 0x%x\n", p_adapter->params.sq_depth )); + + } + + + // Adjusting the low watermark parameter + p_adapter->params.rq_low_watermark = + p_adapter->params.rq_depth / p_adapter->params.rq_low_watermark; + + p_adapter->params.xfer_block_size = (sizeof(eth_hdr_t) + p_adapter->params.payload_mtu); + NdisReadNetworkAddress( &status, p_mac, p_len, h_config ); + if (status != NDIS_STATUS_SUCCESS) { + // Don't rely on NDIS, zero the values + *p_mac = NULL; + *p_len = 0; + } + + NdisCloseConfiguration( h_config ); + + IPOIB_EXIT( IPOIB_DBG_INIT ); + return NDIS_STATUS_SUCCESS; +} + + +NDIS_STATUS +ipoib_get_adapter_guids( + IN NDIS_HANDLE* const h_adapter, + IN OUT ipoib_adapter_t *p_adapter ) +{ + NTSTATUS status; + ib_al_ifc_data_t data; + IO_STACK_LOCATION io_stack, *p_fwd_io_stack; + DEVICE_OBJECT *p_pdo; + IRP *p_irp; + KEVENT event; + IO_STATUS_BLOCK io_status; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + NdisMGetDeviceProperty( h_adapter, &p_pdo, NULL, NULL, NULL, NULL ); + + /* Query for our interface */ + data.size = sizeof(ipoib_ifc_data_t); + data.version = IPOIB_INTERFACE_DATA_VERSION; + data.type = &GUID_IPOIB_INTERFACE_DATA; + data.p_data = &p_adapter->guids; + + io_stack.MinorFunction = IRP_MN_QUERY_INTERFACE; + io_stack.Parameters.QueryInterface.Version = AL_INTERFACE_VERSION; + io_stack.Parameters.QueryInterface.Size = sizeof(ib_al_ifc_t); + io_stack.Parameters.QueryInterface.Interface = + (INTERFACE*)p_adapter->p_ifc; + io_stack.Parameters.QueryInterface.InterfaceSpecificData = &data; + io_stack.Parameters.QueryInterface.InterfaceType = + &GUID_IB_AL_INTERFACE; + + KeInitializeEvent( &event, NotificationEvent, FALSE ); + + /* Build the IRP for the HCA. */ + p_irp = IoBuildSynchronousFsdRequest( IRP_MJ_PNP, p_pdo, + NULL, 0, NULL, &event, &io_status ); + if( !p_irp ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to allocate query interface IRP.\n") ); + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* Copy the request query parameters. */ + p_fwd_io_stack = IoGetNextIrpStackLocation( p_irp ); + p_fwd_io_stack->MinorFunction = IRP_MN_QUERY_INTERFACE; + p_fwd_io_stack->Parameters.QueryInterface = + io_stack.Parameters.QueryInterface; + p_irp->IoStatus.Status = STATUS_NOT_SUPPORTED; + + /* Send the IRP. */ + status = IoCallDriver( p_pdo, p_irp ); + if( status == STATUS_PENDING ) + { + KeWaitForSingleObject( &event, Executive, KernelMode, + FALSE, NULL ); + status = io_status.Status; + } + + if( !NT_SUCCESS( status ) ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Query interface for IPOIB interface returned %08x.\n", status) ); + return status; + } + + /* + * Dereference the interface now so that the bus driver doesn't fail a + * query remove IRP. We will always get unloaded before the bus driver + * since we're a child device. + */ + if (p_adapter->p_ifc) + p_adapter->p_ifc->wdm.InterfaceDereference( + p_adapter->p_ifc->wdm.Context ); + IPOIB_EXIT( IPOIB_DBG_INIT ); + return NDIS_STATUS_SUCCESS; +} + + +//! Initialization function called for each IOC discovered +/* The MiniportInitialize function is a required function that sets up a +NIC (or virtual NIC) for network I/O operations, claims all hardware +resources necessary to the NIC in the registry, and allocates resources +the driver needs to carry out network I/O operations. +IRQL = PASSIVE_LEVEL + +@param p_open_status Pointer to a status field set if this function returns NDIS_STATUS_OPEN_ERROR +@param p_selected_medium_index Pointer to unsigned integer noting index into medium_array for this NIC +@param medium_array Array of mediums for this NIC +@param medium_array_size Number of elements in medium_array +@param h_adapter Handle assigned by NDIS for this NIC +@param wrapper_config_context Handle used for Ndis initialization functions +@return NDIS_STATUS_SUCCESS, NDIS_STATUS_UNSUPPORTED_MEDIA, NDIS_STATUS_RESOURCES, +NDIS_STATUS_NOT_SUPPORTED +*/ +NDIS_STATUS +ipoib_initialize( + OUT PNDIS_STATUS p_open_status, + OUT PUINT p_selected_medium_index, + IN PNDIS_MEDIUM medium_array, + IN UINT medium_array_size, + IN NDIS_HANDLE h_adapter, + IN NDIS_HANDLE wrapper_config_context ) +{ + NDIS_STATUS status; + ib_api_status_t ib_status; + UINT medium_index; + ipoib_adapter_t *p_adapter; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + +#ifdef _DEBUG_ + PAGED_CODE(); +#endif + + UNUSED_PARAM( p_open_status ); + UNUSED_PARAM( wrapper_config_context ); + + /* Search for our medium */ + for( medium_index = 0; medium_index < medium_array_size; ++medium_index ) + { + /* Check to see if we found our medium */ + if( medium_array[medium_index] == NdisMedium802_3 ) + break; + } + + if( medium_index == medium_array_size ) /* Never found it */ + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("No supported media.\n") ); + return NDIS_STATUS_UNSUPPORTED_MEDIA; + } + + *p_selected_medium_index = medium_index; + + /* Create the adapter adapter */ + ib_status = ipoib_create_adapter( wrapper_config_context, h_adapter, &p_adapter ); + if( ib_status != IB_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ipoib_create_adapter returned status %d.\n", ib_status ) ); + return NDIS_STATUS_FAILURE; + } + + /* Allow ten seconds for all SA queries to finish up. */ + NdisMSetAttributesEx( h_adapter, p_adapter, 5, + NDIS_ATTRIBUTE_BUS_MASTER | NDIS_ATTRIBUTE_DESERIALIZE | + NDIS_ATTRIBUTE_USES_SAFE_BUFFER_APIS, + NdisInterfacePNPBus ); + +#if IPOIB_USE_DMA + status = + NdisMInitializeScatterGatherDma( h_adapter, TRUE, p_adapter->params.xfer_block_size ); + if( status != NDIS_STATUS_SUCCESS ) + { + ipoib_destroy_adapter( p_adapter ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("NdisMInitializeScatterGatherDma returned 0x%.8x.\n", status) ); + return status; + } +#endif + + /* Create the adapter adapter */ + ib_status = ipoib_start_adapter( p_adapter ); + if( ib_status != IB_SUCCESS ) + { + NdisWriteErrorLogEntry( h_adapter, + NDIS_ERROR_CODE_HARDWARE_FAILURE, 0 ); + ipoib_destroy_adapter( p_adapter ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ipoib_start_adapter returned status %d.\n", ib_status ) ); + return NDIS_STATUS_FAILURE; + } + + ipoib_ref_ibat(); + + IPOIB_PRINT_EXIT(TRACE_LEVEL_WARNING, IPOIB_DBG_INIT, + ("=====> ipoib_initialize exited\n")); + + return status; +} + + +//! Deallocates resources when the NIC is removed and halts the NIC.. +/* IRQL = DISPATCH_LEVEL + +@param adapter_context The adapter context allocated at start +*/ +void +ipoib_halt( + IN NDIS_HANDLE adapter_context ) +{ + ipoib_adapter_t *p_adapter; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + ipoib_deref_ibat(); + + CL_ASSERT( adapter_context ); + p_adapter = (ipoib_adapter_t*)adapter_context; + + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, + ("Port %016I64x (CA %016I64x port %d) halting\n", + p_adapter->guids.port_guid.guid, p_adapter->guids.ca_guid, + p_adapter->guids.port_num) ); + + ipoib_destroy_adapter( p_adapter ); + + IPOIB_PRINT_EXIT(TRACE_LEVEL_WARNING, IPOIB_DBG_INIT, + ("=====> ipoib_halt exited\n")); +} + + +//! Reports the state of the NIC, or monitors the responsiveness of an underlying device driver. +/* IRQL = DISPATCH_LEVEL + +@param adapter_context The adapter context allocated at start +@return TRUE if the driver determines that its NIC is not operating +*/ +BOOLEAN +ipoib_check_for_hang( + IN NDIS_HANDLE adapter_context ) +{ + ipoib_adapter_t *p_adapter; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + CL_ASSERT( adapter_context ); + p_adapter = (ipoib_adapter_t*)adapter_context; + + if( p_adapter->reset ) + { + IPOIB_EXIT( IPOIB_DBG_INIT ); + return FALSE; + } + if (p_adapter->hung) { + ipoib_resume_oids(p_adapter); + } + + IPOIB_EXIT( IPOIB_DBG_INIT ); + return (p_adapter->hung? TRUE:FALSE); +} + + +//! Returns information about the capabilities and status of the driver and/or its NIC. +/* IRQL = DISPATCH_LEVEL + +@param adapter_context The adapter context allocated at start +@param oid Object ID representing the query operation to be carried out +@param info_buf Buffer containing any input for this query and location for output +@param info_buf_len Number of bytes available in info_buf +@param p_bytes_written Pointer to number of bytes written into info_buf +@param p_bytes_needed Pointer to number of bytes needed to satisfy this oid +@return NDIS_STATUS_SUCCESS, NDIS_STATUS_PENDING, NDIS_STATUS_INVALID_OID, +NDIS_STATUS_INVALID_LENGTH, NDIS_STATUS_NOT_ACCEPTED, NDIS_STATUS_NOT_SUPPORTED, +NDIS_STATUS_RESOURCES +*/ +NDIS_STATUS +ipoib_query_info( + IN NDIS_HANDLE adapter_context, + IN NDIS_OID oid, + IN PVOID info_buf, + IN ULONG info_buf_len, + OUT PULONG p_bytes_written, + OUT PULONG p_bytes_needed ) +{ + ipoib_adapter_t *p_adapter; + NDIS_STATUS status; + USHORT version; + ULONG info; + PVOID src_buf; + ULONG buf_len; + pending_oid_t oid_info; + uint8_t port_num; + + IPOIB_ENTER( IPOIB_DBG_OID ); + + oid_info.oid = oid; + oid_info.p_buf = info_buf; + oid_info.buf_len = info_buf_len; + oid_info.p_bytes_used = p_bytes_written; + oid_info.p_bytes_needed = p_bytes_needed; + + CL_ASSERT( adapter_context ); + p_adapter = (ipoib_adapter_t*)adapter_context; + + CL_ASSERT( p_bytes_written ); + CL_ASSERT( p_bytes_needed ); + CL_ASSERT( !p_adapter->pending_query ); + + status = NDIS_STATUS_SUCCESS; + src_buf = &info; + buf_len = sizeof(info); + + port_num = p_adapter->guids.port_num; + + switch( oid ) + { + /* Required General */ + case OID_GEN_SUPPORTED_LIST: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_SUPPORTED_LIST\n", port_num) ); + src_buf = (PVOID)SUPPORTED_OIDS; + buf_len = sizeof(SUPPORTED_OIDS); + break; + + case OID_GEN_HARDWARE_STATUS: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_HARDWARE_STATUS\n", port_num) ); + cl_obj_lock( &p_adapter->obj ); + switch( p_adapter->state ) + { + case IB_PNP_PORT_ADD: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d returning NdisHardwareStatusInitializing\n", port_num) ); + info = NdisHardwareStatusInitializing; + break; + + case IB_PNP_PORT_ACTIVE: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d returning NdisHardwareStatusReady\n", port_num) ); + info = NdisHardwareStatusReady; + break; + + default: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d returning NdisHardwareStatusNotReady\n", port_num) ); + info = NdisHardwareStatusNotReady; + } + cl_obj_unlock( &p_adapter->obj ); + break; + + case OID_GEN_MEDIA_SUPPORTED: + case OID_GEN_MEDIA_IN_USE: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_MEDIA_SUPPORTED " + "or OID_GEN_MEDIA_IN_USE\n", port_num) ); + info = NdisMedium802_3; + break; + + case OID_GEN_MAXIMUM_FRAME_SIZE: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_MAXIMUM_FRAME_SIZE\n", port_num) ); + info = p_adapter->params.payload_mtu; + break; + + case OID_GEN_LINK_SPEED: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_LINK_SPEED\n", port_num) ); + cl_obj_lock( &p_adapter->obj ); + info = p_adapter->port_rate; + cl_obj_unlock( &p_adapter->obj ); + break; + + case OID_GEN_TRANSMIT_BUFFER_SPACE: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_TRANSMIT_BUFFER_SPACE\n", port_num) ); + info = p_adapter->params.sq_depth * p_adapter->params.xfer_block_size; + break; + + case OID_GEN_RECEIVE_BUFFER_SPACE: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_TRANSMIT_BUFFER_SPACE " + "or OID_GEN_RECEIVE_BUFFER_SPACE\n", port_num) ); + info = p_adapter->params.rq_depth * p_adapter->params.xfer_block_size; + break; + + case OID_GEN_MAXIMUM_LOOKAHEAD: + case OID_GEN_CURRENT_LOOKAHEAD: + case OID_GEN_TRANSMIT_BLOCK_SIZE: + case OID_GEN_RECEIVE_BLOCK_SIZE: + case OID_GEN_MAXIMUM_TOTAL_SIZE: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_MAXIMUM_LOOKAHEAD " + "or OID_GEN_CURRENT_LOOKAHEAD or " + "OID_GEN_TRANSMIT_BLOCK_SIZE or " + "OID_GEN_RECEIVE_BLOCK_SIZE or " + "OID_GEN_MAXIMUM_TOTAL_SIZE\n", port_num) ); + info = p_adapter->params.xfer_block_size; + break; + + case OID_GEN_VENDOR_ID: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_VENDOR_ID\n", port_num) ); + src_buf = (void*)VENDOR_ID; + buf_len = sizeof(VENDOR_ID); + break; + + case OID_GEN_VENDOR_DESCRIPTION: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_VENDOR_DESCRIPTION\n", port_num) ); + src_buf = VENDOR_DESCRIPTION; + buf_len = sizeof(VENDOR_DESCRIPTION); + break; + + case OID_GEN_VENDOR_DRIVER_VERSION: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_VENDOR_DRIVER_VERSION\n", port_num) ); + src_buf = &version; + buf_len = sizeof(version); + //TODO: Figure out what the right version is. + version = 1 << 8 | 1; + break; + + case OID_GEN_PHYSICAL_MEDIUM: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_PHYSICAL_MEDIUM\n", port_num) ); + info = NdisPhysicalMediumUnspecified; + break; + + case OID_GEN_CURRENT_PACKET_FILTER: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_CURRENT_PACKET_FILTER\n", port_num) ); + info = p_adapter->packet_filter; + break; + + case OID_GEN_DRIVER_VERSION: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_DRIVER_VERSION\n", port_num) ); + src_buf = &version; + buf_len = sizeof(version); + version = MAJOR_NDIS_VERSION << 8 | MINOR_NDIS_VERSION; + break; + + case OID_GEN_MAC_OPTIONS: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_MAC_OPTIONS\n", port_num) ); + info = NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA | + NDIS_MAC_OPTION_TRANSFERS_NOT_PEND | + NDIS_MAC_OPTION_NO_LOOPBACK | + NDIS_MAC_OPTION_FULL_DUPLEX; +//TODO: Figure out if we will support priority and VLANs. +// NDIS_MAC_OPTION_8021P_PRIORITY; +//#ifdef NDIS51_MINIPORT +// info |= NDIS_MAC_OPTION_8021Q_VLAN; +//#endif + break; + + case OID_GEN_MEDIA_CONNECT_STATUS: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_MEDIA_CONNECT_STATUS\n", port_num) ); + cl_obj_lock( &p_adapter->obj ); + switch( p_adapter->state ) + { + case IB_PNP_PORT_ADD: + case IB_PNP_PORT_INIT: + /* + * Delay reporting media state until we know whether the port is + * either up or down. + */ + p_adapter->pending_query = TRUE; + p_adapter->query_oid = oid_info; + + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d returning NDIS_STATUS_PENDING\n", port_num) ); + status = NDIS_STATUS_PENDING; + break; + + case IB_PNP_PORT_ACTIVE: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d returning NdisMediaStateConnected\n", port_num) ); + info = NdisMediaStateConnected; + break; + + case IB_PNP_PORT_REMOVE: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d returning NDIS_STATUS_NOT_ACCEPTED\n", port_num) ); + status = NDIS_STATUS_NOT_ACCEPTED; + break; + + default: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d returning NdisMediaStateDisconnected\n", port_num) ); + info = NdisMediaStateDisconnected; + } + cl_obj_unlock( &p_adapter->obj ); + break; + + case OID_GEN_MAXIMUM_SEND_PACKETS: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_MAXIMUM_SEND_PACKETS\n", port_num) ); + info = MINIPORT_MAX_SEND_PACKETS; + break; + + /* Required General Statistics */ + case OID_GEN_XMIT_OK: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_XMIT_OK\n", port_num) ); + src_buf = NULL; + status = ipoib_get_send_stat( p_adapter, IP_STAT_SUCCESS, &oid_info ); + break; + + case OID_GEN_RCV_OK: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_RCV_OK\n", port_num) ); + src_buf = NULL; + status = ipoib_get_recv_stat( p_adapter, IP_STAT_SUCCESS, &oid_info ); + break; + + case OID_GEN_XMIT_ERROR: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_XMIT_ERROR\n", port_num) ); + src_buf = NULL; + status = ipoib_get_send_stat( p_adapter, IP_STAT_ERROR, &oid_info ); + break; + + case OID_GEN_RCV_ERROR: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_RCV_ERROR\n", port_num) ); + src_buf = NULL; + status = ipoib_get_recv_stat( p_adapter, IP_STAT_ERROR, &oid_info ); + break; + + case OID_GEN_RCV_NO_BUFFER: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_RCV_NO_BUFFER\n", port_num) ); + src_buf = NULL; + status = ipoib_get_recv_stat( p_adapter, IP_STAT_DROPPED, &oid_info ); + break; + + case OID_GEN_DIRECTED_BYTES_XMIT: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_DIRECTED_BYTES_XMIT\n", port_num) ); + src_buf = NULL; + status = ipoib_get_send_stat( p_adapter, IP_STAT_UCAST_BYTES, &oid_info ); + break; + + case OID_GEN_DIRECTED_FRAMES_XMIT: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_DIRECTED_FRAMES_XMIT\n", port_num) ); + src_buf = NULL; + status = ipoib_get_send_stat( p_adapter, IP_STAT_UCAST_FRAMES, &oid_info ); + break; + + case OID_GEN_MULTICAST_BYTES_XMIT: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_MULTICAST_BYTES_XMIT\n", port_num) ); + src_buf = NULL; + status = ipoib_get_send_stat( p_adapter, IP_STAT_MCAST_BYTES, &oid_info ); + break; + + case OID_GEN_MULTICAST_FRAMES_XMIT: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_MULTICAST_FRAMES_XMIT\n", port_num) ); + src_buf = NULL; + status = ipoib_get_send_stat( p_adapter, IP_STAT_MCAST_FRAMES, &oid_info ); + break; + + case OID_GEN_BROADCAST_BYTES_XMIT: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_BROADCAST_BYTES_XMIT\n", port_num) ); + src_buf = NULL; + status = ipoib_get_send_stat( p_adapter, IP_STAT_BCAST_BYTES, &oid_info ); + break; + + case OID_GEN_BROADCAST_FRAMES_XMIT: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_BROADCAST_FRAMES_XMIT\n", port_num) ); + src_buf = NULL; + status = ipoib_get_send_stat( p_adapter, IP_STAT_BCAST_FRAMES, &oid_info ); + break; + + case OID_GEN_DIRECTED_BYTES_RCV: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_DIRECTED_BYTES_RCV\n", port_num) ); + src_buf = NULL; + status = ipoib_get_recv_stat( p_adapter, IP_STAT_UCAST_BYTES, &oid_info ); + break; + + case OID_GEN_DIRECTED_FRAMES_RCV: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_DIRECTED_FRAMES_RCV\n", port_num) ); + src_buf = NULL; + status = ipoib_get_recv_stat( p_adapter, IP_STAT_UCAST_FRAMES, &oid_info ); + break; + + case OID_GEN_MULTICAST_BYTES_RCV: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_MULTICAST_BYTES_RCV\n", port_num) ); + src_buf = NULL; + status = ipoib_get_recv_stat( p_adapter, IP_STAT_MCAST_BYTES, &oid_info ); + break; + + case OID_GEN_MULTICAST_FRAMES_RCV: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_MULTICAST_FRAMES_RCV\n", port_num) ); + src_buf = NULL; + status = ipoib_get_recv_stat( p_adapter, IP_STAT_MCAST_FRAMES, &oid_info ); + break; + + case OID_GEN_BROADCAST_BYTES_RCV: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_BROADCAST_BYTES_RCV\n", port_num) ); + src_buf = NULL; + status = ipoib_get_recv_stat( p_adapter, IP_STAT_BCAST_BYTES, &oid_info ); + break; + + case OID_GEN_BROADCAST_FRAMES_RCV: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_BROADCAST_FRAMES_RCV\n", port_num) ); + src_buf = NULL; + status = ipoib_get_recv_stat( p_adapter, IP_STAT_BCAST_FRAMES, &oid_info ); + break; + + /* Required Ethernet operational characteristics */ + case OID_802_3_PERMANENT_ADDRESS: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_802_3_PERMANENT_ADDRESS\n", port_num) ); + src_buf = &p_adapter->mac; + buf_len = sizeof(p_adapter->mac); + break; + + case OID_802_3_CURRENT_ADDRESS: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_802_3_CURRENT_ADDRESS\n", port_num) ); + src_buf = &p_adapter->params.conf_mac; + buf_len = sizeof(p_adapter->params.conf_mac); + break; + + case OID_802_3_MULTICAST_LIST: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_802_3_MULTICAST_LIST\n", port_num) ); + src_buf = p_adapter->mcast_array; + buf_len = p_adapter->mcast_array_size * sizeof(mac_addr_t); + break; + + case OID_802_3_MAXIMUM_LIST_SIZE: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_802_3_MAXIMUM_LIST_SIZE\n", port_num) ); + info = MAX_MCAST; + break; + + case OID_802_3_MAC_OPTIONS: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_802_3_MAC_OPTIONS\n", port_num) ); + info = 0; + break; + + /* Required Ethernet stats */ + case OID_802_3_RCV_ERROR_ALIGNMENT: + case OID_802_3_XMIT_ONE_COLLISION: + case OID_802_3_XMIT_MORE_COLLISIONS: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_802_3_RCV_ERROR_ALIGNMENT or " + "OID_802_3_XMIT_ONE_COLLISION or " + "OID_802_3_XMIT_MORE_COLLISIONS\n", port_num) ); + info = 0; + break; + + case OID_TCP_TASK_OFFLOAD: + src_buf = NULL; + status = __ipoib_get_tcp_task_offload( p_adapter, &oid_info ); + break; + + /* Optional General */ + case OID_GEN_SUPPORTED_GUIDS: +#ifdef NDIS51_MINIPORT + case OID_GEN_VLAN_ID: +#endif + + /* Optional General Stats */ + case OID_GEN_RCV_CRC_ERROR: + case OID_GEN_TRANSMIT_QUEUE_LENGTH: + + /* Optional Ethernet Stats */ + case OID_802_3_XMIT_DEFERRED: + case OID_802_3_XMIT_MAX_COLLISIONS: + case OID_802_3_RCV_OVERRUN: + case OID_802_3_XMIT_UNDERRUN: + case OID_802_3_XMIT_HEARTBEAT_FAILURE: + case OID_802_3_XMIT_TIMES_CRS_LOST: + case OID_802_3_XMIT_LATE_COLLISIONS: + case OID_PNP_CAPABILITIES: + status = NDIS_STATUS_NOT_SUPPORTED; + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received an unsupported oid of 0x%.8X!\n", port_num, oid) ); + break; + + case OID_GEN_PROTOCOL_OPTIONS: + case OID_GEN_NETWORK_LAYER_ADDRESSES: + case OID_GEN_TRANSPORT_HEADER_OFFSET: +#ifdef NDIS51_MINIPORT + case OID_GEN_MACHINE_NAME: + case OID_GEN_RNDIS_CONFIG_PARAMETER: +#endif + default: + status = NDIS_STATUS_INVALID_OID; + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received an invalid oid of 0x%.8X!\n", port_num, oid) ); + break; + } + + /* + * Complete the request as if it was handled asynchronously to maximize + * code reuse for when we really handle the requests asynchronously. + * Note that this requires the QueryInformation entry point to always + * return NDIS_STATUS_PENDING + */ + if( status != NDIS_STATUS_PENDING ) + { + ipoib_complete_query( + p_adapter, &oid_info, status, src_buf, buf_len ); + } + + IPOIB_EXIT( IPOIB_DBG_OID ); + return NDIS_STATUS_PENDING; +} + + +static void +ipoib_complete_query( + IN ipoib_adapter_t* const p_adapter, + IN pending_oid_t* const p_oid_info, + IN const NDIS_STATUS status, + IN const void* const p_buf, + IN const ULONG buf_len ) +{ + NDIS_STATUS oid_status = status; + + IPOIB_ENTER( IPOIB_DBG_OID ); + + CL_ASSERT( status != NDIS_STATUS_PENDING ); + + if( status == NDIS_STATUS_SUCCESS ) + { + if( p_oid_info->buf_len < buf_len ) + { + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Insufficient buffer space. " + "Returning NDIS_STATUS_INVALID_LENGTH.\n") ); + oid_status = NDIS_STATUS_INVALID_LENGTH; + *p_oid_info->p_bytes_needed = buf_len; + *p_oid_info->p_bytes_used = 0; + } + else if( p_oid_info->p_buf ) + { + /* Only copy if we have a distinct source buffer. */ + if( p_buf ) + { + NdisMoveMemory( p_oid_info->p_buf, p_buf, buf_len ); + *p_oid_info->p_bytes_used = buf_len; + } + } + else + { + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Returning NDIS_NOT_ACCEPTED") ); + oid_status = NDIS_STATUS_NOT_ACCEPTED; + } + } + else + { + *p_oid_info->p_bytes_used = 0; + } + + p_adapter->pending_query = FALSE; + + NdisMQueryInformationComplete( p_adapter->h_adapter, oid_status ); + + IPOIB_EXIT( IPOIB_DBG_OID ); +} + + +static NDIS_STATUS +__ipoib_get_tcp_task_offload( + IN ipoib_adapter_t* p_adapter, + IN pending_oid_t* const p_oid_info ) +{ + NDIS_TASK_OFFLOAD_HEADER *p_offload_hdr; + NDIS_TASK_OFFLOAD *p_offload_task; + NDIS_TASK_TCP_IP_CHECKSUM *p_offload_chksum; + + NDIS_TASK_TCP_LARGE_SEND *p_offload_lso; + ULONG buf_len; + + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_TCP_TASK_OFFLOAD\n", + p_adapter->guids.port_num) ); + + buf_len = sizeof(NDIS_TASK_OFFLOAD_HEADER) + + offsetof( NDIS_TASK_OFFLOAD, TaskBuffer ) + + sizeof(NDIS_TASK_TCP_IP_CHECKSUM) + + (p_adapter->params.lso ? + sizeof(NDIS_TASK_OFFLOAD) + sizeof(NDIS_TASK_TCP_LARGE_SEND) + : 0); + + *(p_oid_info->p_bytes_needed) = buf_len; + + if( p_oid_info->buf_len < buf_len ) + return NDIS_STATUS_INVALID_LENGTH; + + p_offload_hdr = (NDIS_TASK_OFFLOAD_HEADER*)p_oid_info->p_buf; + if( p_offload_hdr->Version != NDIS_TASK_OFFLOAD_VERSION ) + return NDIS_STATUS_INVALID_DATA; + + if( p_offload_hdr->EncapsulationFormat.Encapsulation != + IEEE_802_3_Encapsulation ) + { + return NDIS_STATUS_INVALID_DATA; + } + + p_offload_hdr->OffsetFirstTask = sizeof(NDIS_TASK_OFFLOAD_HEADER); + p_offload_task = (NDIS_TASK_OFFLOAD*)(p_offload_hdr + 1); + p_offload_task->Version = NDIS_TASK_OFFLOAD_VERSION; + p_offload_task->Size = sizeof(NDIS_TASK_OFFLOAD); + p_offload_task->Task = TcpIpChecksumNdisTask; + p_offload_task->OffsetNextTask = 0; + p_offload_task->TaskBufferLength = sizeof(NDIS_TASK_TCP_IP_CHECKSUM); + p_offload_chksum = + (NDIS_TASK_TCP_IP_CHECKSUM*)p_offload_task->TaskBuffer; + + p_offload_chksum->V4Transmit.IpOptionsSupported = + p_offload_chksum->V4Transmit.TcpOptionsSupported = + p_offload_chksum->V4Transmit.TcpChecksum = + p_offload_chksum->V4Transmit.UdpChecksum = + p_offload_chksum->V4Transmit.IpChecksum = + !!(p_adapter->params.send_chksum_offload); + + p_offload_chksum->V4Receive.IpOptionsSupported = + p_offload_chksum->V4Receive.TcpOptionsSupported = + p_offload_chksum->V4Receive.TcpChecksum = + p_offload_chksum->V4Receive.UdpChecksum = + p_offload_chksum->V4Receive.IpChecksum = + !!(p_adapter->params.recv_chksum_offload); + + p_offload_chksum->V6Transmit.IpOptionsSupported = FALSE; + p_offload_chksum->V6Transmit.TcpOptionsSupported = FALSE; + p_offload_chksum->V6Transmit.TcpChecksum = FALSE; + p_offload_chksum->V6Transmit.UdpChecksum = FALSE; + + p_offload_chksum->V6Receive.IpOptionsSupported = FALSE; + p_offload_chksum->V6Receive.TcpOptionsSupported = FALSE; + p_offload_chksum->V6Receive.TcpChecksum = FALSE; + p_offload_chksum->V6Receive.UdpChecksum = FALSE; + + + if (p_adapter->params.lso) { + // set the previous pointer to the correct place + p_offload_task->OffsetNextTask = FIELD_OFFSET(NDIS_TASK_OFFLOAD, TaskBuffer) + + p_offload_task->TaskBufferLength; + // set the LSO packet + p_offload_task = (PNDIS_TASK_OFFLOAD) + ((PUCHAR)p_offload_task + p_offload_task->OffsetNextTask); + + p_offload_task->Version = NDIS_TASK_OFFLOAD_VERSION; + p_offload_task->Size = sizeof(NDIS_TASK_OFFLOAD); + p_offload_task->Task = TcpLargeSendNdisTask; + p_offload_task->OffsetNextTask = 0; + p_offload_task->TaskBufferLength = sizeof(NDIS_TASK_TCP_LARGE_SEND); + + p_offload_lso = (PNDIS_TASK_TCP_LARGE_SEND) p_offload_task->TaskBuffer; + + p_offload_lso->Version = 0; + //TODO optimal size: 60000, 64000 or 65536 + //TODO LSO_MIN_SEG_COUNT to be 1 + p_offload_lso->MaxOffLoadSize = LARGE_SEND_OFFLOAD_SIZE; +#define LSO_MIN_SEG_COUNT 2 + p_offload_lso->MinSegmentCount = LSO_MIN_SEG_COUNT; + p_offload_lso->TcpOptions = TRUE; + p_offload_lso->IpOptions = TRUE; + } + + *(p_oid_info->p_bytes_used) = buf_len; + + return NDIS_STATUS_SUCCESS; +} + + +static NDIS_STATUS +__ipoib_set_tcp_task_offload( + IN ipoib_adapter_t* p_adapter, + IN void* const p_info_buf, + IN ULONG* const p_info_len ) +{ + NDIS_TASK_OFFLOAD_HEADER *p_offload_hdr; + NDIS_TASK_OFFLOAD *p_offload_task; + NDIS_TASK_TCP_IP_CHECKSUM *p_offload_chksum; + + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received set for OID_TCP_TASK_OFFLOAD\n", + p_adapter->guids.port_num) ); + + p_offload_hdr = (NDIS_TASK_OFFLOAD_HEADER*)p_info_buf; + + if( *p_info_len < sizeof(NDIS_TASK_OFFLOAD_HEADER) ) + return NDIS_STATUS_INVALID_LENGTH; + + if( p_offload_hdr->Version != NDIS_TASK_OFFLOAD_VERSION ) + return NDIS_STATUS_INVALID_DATA; + + if( p_offload_hdr->Size != sizeof(NDIS_TASK_OFFLOAD_HEADER) ) + return NDIS_STATUS_INVALID_LENGTH; + + if( !p_offload_hdr->OffsetFirstTask ) + return NDIS_STATUS_SUCCESS; + + if( p_offload_hdr->EncapsulationFormat.Encapsulation != + IEEE_802_3_Encapsulation ) + { + return NDIS_STATUS_INVALID_DATA; + } + + p_offload_task = (NDIS_TASK_OFFLOAD*) + (((UCHAR*)p_offload_hdr) + p_offload_hdr->OffsetFirstTask); + + if( *p_info_len < sizeof(NDIS_TASK_OFFLOAD_HEADER) + + offsetof( NDIS_TASK_OFFLOAD, TaskBuffer ) + + sizeof(NDIS_TASK_TCP_IP_CHECKSUM) ) + { + return NDIS_STATUS_INVALID_LENGTH; + } + + if( p_offload_task->Version != NDIS_TASK_OFFLOAD_VERSION ) + return NDIS_STATUS_INVALID_DATA; + p_offload_chksum = + (NDIS_TASK_TCP_IP_CHECKSUM*)p_offload_task->TaskBuffer; + + if( !p_adapter->params.send_chksum_offload && + (p_offload_chksum->V4Transmit.IpOptionsSupported || + p_offload_chksum->V4Transmit.TcpOptionsSupported || + p_offload_chksum->V4Transmit.TcpChecksum || + p_offload_chksum->V4Transmit.UdpChecksum || + p_offload_chksum->V4Transmit.IpChecksum) ) + { + return NDIS_STATUS_NOT_SUPPORTED; + } + + if( !p_adapter->params.recv_chksum_offload && + (p_offload_chksum->V4Receive.IpOptionsSupported || + p_offload_chksum->V4Receive.TcpOptionsSupported || + p_offload_chksum->V4Receive.TcpChecksum || + p_offload_chksum->V4Receive.UdpChecksum || + p_offload_chksum->V4Receive.IpChecksum) ) + { + return NDIS_STATUS_NOT_SUPPORTED; + } + + return NDIS_STATUS_SUCCESS; +} + + +//! Issues a hardware reset to the NIC and/or resets the driver's software state. +/* Tear down the connection and start over again. This is only called when there is a problem. +For example, if a send, query info, or set info had a time out. MiniportCheckForHang will +be called first. +IRQL = DISPATCH_LEVEL + +@param p_addr_resetPointer to BOOLLEAN that is set to TRUE if the NDIS +library should call MiniportSetInformation to restore addressing information to the current values. +@param adapter_context The adapter context allocated at start +@return NDIS_STATUS_SUCCESS, NDIS_STATUS_PENDING, NDIS_STATUS_NOT_RESETTABLE, +NDIS_STATUS_RESET_IN_PROGRESS, NDIS_STATUS_SOFT_ERRORS, NDIS_STATUS_HARD_ERRORS +*/ +NDIS_STATUS +ipoib_reset( + OUT PBOOLEAN p_addr_reset, + IN NDIS_HANDLE adapter_context) +{ + ipoib_adapter_t* p_adapter; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + CL_ASSERT( p_addr_reset ); + CL_ASSERT( adapter_context ); + p_adapter = (ipoib_adapter_t*)adapter_context; + + switch( ipoib_reset_adapter( p_adapter ) ) + { + case IB_NOT_DONE: + IPOIB_EXIT( IPOIB_DBG_INIT ); + return NDIS_STATUS_PENDING; + + case IB_SUCCESS: + IPOIB_EXIT( IPOIB_DBG_INIT ); + *p_addr_reset = TRUE; + return NDIS_STATUS_SUCCESS; + + case IB_INVALID_STATE: + IPOIB_EXIT( IPOIB_DBG_INIT ); + return NDIS_STATUS_RESET_IN_PROGRESS; + + default: + IPOIB_EXIT( IPOIB_DBG_INIT ); + return NDIS_STATUS_HARD_ERRORS; + } +} + + +//! Request changes in the state information that the miniport driver maintains +/* For example, this is used to set multicast addresses and the packet filter. +IRQL = DISPATCH_LEVEL + +@param adapter_context The adapter context allocated at start +@param oid Object ID representing the set operation to be carried out +@param info_buf Buffer containing input for this set and location for any output +@param info_buf_len Number of bytes available in info_buf +@param p_bytes_read Pointer to number of bytes read from info_buf +@param p_bytes_needed Pointer to number of bytes needed to satisfy this oid +@return NDIS_STATUS_SUCCESS, NDIS_STATUS_PENDING, NDIS_STATUS_INVALID_OID, +NDIS_STATUS_INVALID_LENGTH, NDIS_STATUS_INVALID_DATA, NDIS_STATUS_NOT_ACCEPTED, +NDIS_STATUS_NOT_SUPPORTED, NDIS_STATUS_RESOURCES +*/ +NDIS_STATUS +ipoib_set_info( + IN NDIS_HANDLE adapter_context, + IN NDIS_OID oid, + IN PVOID info_buf, + IN ULONG info_buf_len, + OUT PULONG p_bytes_read, + OUT PULONG p_bytes_needed ) +{ + ipoib_adapter_t* p_adapter; + NDIS_STATUS status; + + ULONG buf_len; + uint8_t port_num; + + KLOCK_QUEUE_HANDLE hdl; + + IPOIB_ENTER( IPOIB_DBG_OID ); + + CL_ASSERT( adapter_context ); + p_adapter = (ipoib_adapter_t*)adapter_context; + + CL_ASSERT( p_bytes_read ); + CL_ASSERT( p_bytes_needed ); + CL_ASSERT( !p_adapter->pending_set ); + + status = NDIS_STATUS_SUCCESS; + *p_bytes_needed = 0; + buf_len = sizeof(ULONG); + + port_num = p_adapter->guids.port_num; + + switch( oid ) + { + /* Required General */ + case OID_GEN_CURRENT_PACKET_FILTER: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received set for OID_GEN_CURRENT_PACKET_FILTER\n", port_num)); + if( info_buf_len < sizeof(p_adapter->packet_filter) ) + { + status = NDIS_STATUS_INVALID_LENGTH; + } + else if( !info_buf ) + { + status = NDIS_STATUS_INVALID_DATA; + } + else + { + KeAcquireInStackQueuedSpinLock( &g_ipoib.lock, &hdl ); + cl_obj_lock( &p_adapter->obj ); + switch( p_adapter->state ) + { + case IB_PNP_PORT_ADD: + p_adapter->set_oid.oid = oid; + p_adapter->set_oid.p_buf = info_buf; + p_adapter->set_oid.buf_len = info_buf_len; + p_adapter->set_oid.p_bytes_used = p_bytes_read; + p_adapter->set_oid.p_bytes_needed = p_bytes_needed; + p_adapter->pending_set = TRUE; + status = NDIS_STATUS_PENDING; + break; + + case IB_PNP_PORT_REMOVE: + status = NDIS_STATUS_NOT_ACCEPTED; + break; + + default: + if( !p_adapter->packet_filter && (*(uint32_t*)info_buf) ) + { + cl_qlist_insert_tail( + &g_ipoib.adapter_list, &p_adapter->entry ); + + /* + * Filter was zero, now non-zero. Register IP addresses + * with SA. + */ + ipoib_reg_addrs( p_adapter ); + } + else if( p_adapter->packet_filter && !(*(uint32_t*)info_buf) ) + { + /* + * Filter was non-zero, now zero. Deregister IP addresses. + */ + ipoib_dereg_addrs( p_adapter ); + + ASSERT( cl_qlist_count( &g_ipoib.adapter_list ) ); + cl_qlist_remove_item( + &g_ipoib.adapter_list, &p_adapter->entry ); + } + + p_adapter->packet_filter = *(uint32_t*)info_buf; + } + cl_obj_unlock( &p_adapter->obj ); + KeReleaseInStackQueuedSpinLock( &hdl ); + } + break; + + case OID_GEN_CURRENT_LOOKAHEAD: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received set for OID_GEN_CURRENT_LOOKAHEAD\n", port_num)); + if( info_buf_len < buf_len ) + status = NDIS_STATUS_INVALID_LENGTH; + break; + + case OID_GEN_PROTOCOL_OPTIONS: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received set for OID_GEN_PROTOCOL_OPTIONS\n", port_num)); + if( info_buf_len < buf_len ) + status = NDIS_STATUS_INVALID_LENGTH; + break; + + case OID_GEN_NETWORK_LAYER_ADDRESSES: + status = __ipoib_set_net_addr( p_adapter, info_buf, info_buf_len, p_bytes_read, p_bytes_needed); + break; + +#ifdef NDIS51_MINIPORT + case OID_GEN_MACHINE_NAME: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_OID, + ("Port %d received set for OID_GEN_MACHINE_NAME\n", port_num) ); + break; +#endif + + /* Required Ethernet operational characteristics */ + case OID_802_3_MULTICAST_LIST: + IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_OID, + ("Port %d received set for OID_802_3_MULTICAST_LIST\n", port_num) ); + if( info_buf_len > MAX_MCAST * sizeof(mac_addr_t) ) + { + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d OID_802_3_MULTICAST_LIST - Multicast list full.\n", port_num) ); + status = NDIS_STATUS_MULTICAST_FULL; + *p_bytes_needed = MAX_MCAST * sizeof(mac_addr_t); + } + else if( info_buf_len % sizeof(mac_addr_t) ) + { + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d OID_802_3_MULTICAST_LIST - Invalid input buffer.\n", port_num) ); + status = NDIS_STATUS_INVALID_DATA; + } + else if( !info_buf && info_buf_len ) + { + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d OID_802_3_MULTICAST_LIST - Invalid input buffer.\n", port_num) ); + status = NDIS_STATUS_INVALID_DATA; + } + else + { + ipoib_refresh_mcast( p_adapter, (mac_addr_t*)info_buf, + (uint8_t)(info_buf_len / sizeof(mac_addr_t)) ); + + buf_len = info_buf_len; + /* + * Note that we don't return pending. It will likely take longer + * for our SA transactions to complete than NDIS will give us + * before reseting the adapter. If an SA failure is encountered, + * the adapter will be marked as hung and we will get reset. + */ + status = NDIS_STATUS_SUCCESS; + } + break; + + case OID_TCP_TASK_OFFLOAD: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received set for OID_TCP_TASK_OFFLOAD\n", port_num) ); + + buf_len = info_buf_len; + status = + __ipoib_set_tcp_task_offload( p_adapter, info_buf, &buf_len ); + break; + + /* Optional General */ + case OID_GEN_TRANSPORT_HEADER_OFFSET: +#ifdef NDIS51_MINIPORT + case OID_GEN_RNDIS_CONFIG_PARAMETER: + case OID_GEN_VLAN_ID: +#endif + status = NDIS_STATUS_NOT_SUPPORTED; + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received an unsupported oid of 0x%.8X!\n", port_num, oid)); + break; + + case OID_GEN_SUPPORTED_LIST: + case OID_GEN_HARDWARE_STATUS: + case OID_GEN_MEDIA_SUPPORTED: + case OID_GEN_MEDIA_IN_USE: + case OID_GEN_MAXIMUM_FRAME_SIZE: + case OID_GEN_LINK_SPEED: + case OID_GEN_TRANSMIT_BUFFER_SPACE: + case OID_GEN_RECEIVE_BUFFER_SPACE: + case OID_GEN_MAXIMUM_LOOKAHEAD: + case OID_GEN_TRANSMIT_BLOCK_SIZE: + case OID_GEN_RECEIVE_BLOCK_SIZE: + case OID_GEN_MAXIMUM_TOTAL_SIZE: + case OID_GEN_VENDOR_ID: + case OID_GEN_VENDOR_DESCRIPTION: + case OID_GEN_VENDOR_DRIVER_VERSION: + case OID_GEN_DRIVER_VERSION: + case OID_GEN_MAC_OPTIONS: + case OID_GEN_MEDIA_CONNECT_STATUS: + case OID_GEN_MAXIMUM_SEND_PACKETS: + case OID_GEN_SUPPORTED_GUIDS: + case OID_GEN_PHYSICAL_MEDIUM: + default: + status = NDIS_STATUS_INVALID_OID; + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received an invalid oid of 0x%.8X!\n", port_num, oid)); + break; + } + + if( status == NDIS_STATUS_SUCCESS ) + { + *p_bytes_read = buf_len; + } + else + { + if( status == NDIS_STATUS_INVALID_LENGTH ) + { + if ( !*p_bytes_needed ) + { + *p_bytes_needed = buf_len; + } + } + + *p_bytes_read = 0; + } + + IPOIB_EXIT( IPOIB_DBG_OID ); + return status; +} + + +//! Transfers some number of packets, specified as an array of packet pointers, over the network. +/* For a deserialized driver, these packets are completed asynchronously +using NdisMSendComplete. +IRQL <= DISPATCH_LEVEL + +@param adapter_context Pointer to ipoib_adapter_t structure with per NIC state +@param packet_array Array of packets to send +@param numPackets Number of packets in the array +*/ +void +ipoib_send_packets( + IN NDIS_HANDLE adapter_context, + IN PPNDIS_PACKET packet_array, + IN UINT num_packets ) +{ + ipoib_adapter_t *p_adapter; + ipoib_port_t *p_port; + UINT packet_num; + PERF_DECLARE( SendPackets ); + PERF_DECLARE( PortSend ); + + IPOIB_ENTER( IPOIB_DBG_SEND ); + + cl_perf_start( SendPackets ); + + CL_ASSERT( adapter_context ); + p_adapter = (ipoib_adapter_t*)adapter_context; + + cl_obj_lock( &p_adapter->obj ); + if( p_adapter->state != IB_PNP_PORT_ACTIVE || !p_adapter->p_port ) + { + cl_obj_unlock( &p_adapter->obj ); + for( packet_num = 0; packet_num < num_packets; ++packet_num ) + { + ipoib_inc_send_stat( p_adapter, IP_STAT_DROPPED, 0 ); + NdisMSendCompleteX( p_adapter->h_adapter, + packet_array[packet_num], NDIS_STATUS_ADAPTER_NOT_READY ); + } + IPOIB_EXIT( IPOIB_DBG_SEND ); + return; + } + + p_port = p_adapter->p_port; + ipoib_port_ref( p_port, ref_send_packets ); + cl_obj_unlock( &p_adapter->obj ); + + cl_perf_start( PortSend ); + ipoib_port_send( p_port, packet_array, num_packets ); + cl_perf_stop( &p_port->p_adapter->perf, PortSend ); + ipoib_port_deref( p_port, ref_send_packets ); + + cl_perf_stop( &p_adapter->perf, SendPackets ); + + cl_perf_log( &p_adapter->perf, SendBundle, num_packets ); + + IPOIB_EXIT( IPOIB_DBG_SEND ); +} + + +void +ipoib_pnp_notify( + IN NDIS_HANDLE adapter_context, + IN NDIS_DEVICE_PNP_EVENT pnp_event, + IN PVOID info_buf, + IN ULONG info_buf_len ) +{ + ipoib_adapter_t *p_adapter; + + IPOIB_ENTER( IPOIB_DBG_PNP ); + + UNUSED_PARAM( info_buf ); + UNUSED_PARAM( info_buf_len ); + + p_adapter = (ipoib_adapter_t*)adapter_context; + + IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_PNP, ("Event %d\n", pnp_event) ); + if( pnp_event != NdisDevicePnPEventPowerProfileChanged ) + { + cl_obj_lock( &p_adapter->obj ); + p_adapter->state = IB_PNP_PORT_REMOVE; + cl_obj_unlock( &p_adapter->obj ); + + ipoib_resume_oids( p_adapter ); + if ( p_adapter->p_stat ) + p_adapter->p_stat->n_pnp_irps++; + } + else + if ( p_adapter->p_stat ) + p_adapter->p_stat->n_power_irps++; + + IPOIB_PRINT_EXIT(TRACE_LEVEL_WARNING, IPOIB_DBG_PNP, + ("=====> ipoib_pnp_notify exited, PnP event %d\n", pnp_event)); +} + + +void +ipoib_shutdown( + IN PVOID adapter_context ) +{ + IPOIB_ENTER( IPOIB_DBG_INIT ); + UNUSED_PARAM( adapter_context ); + IPOIB_EXIT( IPOIB_DBG_INIT ); +} + + +void +ipoib_resume_oids( + IN ipoib_adapter_t* const p_adapter ) +{ + ULONG info; + NDIS_STATUS status; + boolean_t pending_query, pending_set; + pending_oid_t query_oid = {0}; + pending_oid_t set_oid = {0}; + KLOCK_QUEUE_HANDLE hdl; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + cl_obj_lock( &p_adapter->obj ); + /* + * Set the status depending on our state. Fail OID requests that + * are pending while we reset the adapter. + */ + switch( p_adapter->state ) + { + case IB_PNP_PORT_ADD: + status = NDIS_STATUS_FAILURE; + break; + + case IB_PNP_PORT_REMOVE: + status = NDIS_STATUS_NOT_ACCEPTED; + break; + + default: + status = NDIS_STATUS_SUCCESS; + } + + pending_query = p_adapter->pending_query; + if( pending_query ) + { + query_oid = p_adapter->query_oid; + p_adapter->pending_query = FALSE; + } + pending_set = p_adapter->pending_set; + if( pending_set ) + { + set_oid = p_adapter->set_oid; + p_adapter->pending_set = FALSE; + } + cl_obj_unlock( &p_adapter->obj ); + + /* + * If we had a pending OID request for OID_GEN_LINK_SPEED, + * complete it now. Note that we hold the object lock since + * NdisMQueryInformationComplete is called at DISPATCH_LEVEL. + */ + if( pending_query ) + { + switch( query_oid.oid ) + { + case OID_GEN_MEDIA_CONNECT_STATUS: + info = NdisMediaStateConnected; + ipoib_complete_query( p_adapter, &query_oid, + status, &info, sizeof(info) ); + break; + + default: + CL_ASSERT( query_oid.oid == OID_GEN_MEDIA_CONNECT_STATUS ); + break; + } + } + + if( pending_set ) + { + switch( set_oid.oid ) + { + case OID_GEN_CURRENT_PACKET_FILTER: + /* Validation already performed in the SetInformation path. */ + + KeAcquireInStackQueuedSpinLock( &g_ipoib.lock, &hdl ); + cl_obj_lock( &p_adapter->obj ); + if( !p_adapter->packet_filter && (*(PULONG)set_oid.p_buf) ) + { + cl_qlist_insert_tail( + &g_ipoib.adapter_list, &p_adapter->entry ); + /* + * Filter was zero, now non-zero. Register IP addresses + * with SA. + */ + ipoib_reg_addrs( p_adapter ); + } + else if( p_adapter->packet_filter && !(*(PULONG)set_oid.p_buf) ) + { + /* Filter was non-zero, now zero. Deregister IP addresses. */ + ipoib_dereg_addrs( p_adapter ); + + ASSERT( cl_qlist_count( &g_ipoib.adapter_list ) ); + cl_qlist_remove_item( + &g_ipoib.adapter_list, &p_adapter->entry ); + } + p_adapter->packet_filter = *(PULONG)set_oid.p_buf; + + cl_obj_unlock( &p_adapter->obj ); + KeReleaseInStackQueuedSpinLock( &hdl ); + + NdisMSetInformationComplete( p_adapter->h_adapter, status ); + break; + + case OID_GEN_NETWORK_LAYER_ADDRESSES: + status = __ipoib_set_net_addr( p_adapter, + p_adapter->set_oid.p_buf, + p_adapter->set_oid.buf_len, + p_adapter->set_oid.p_bytes_used, + p_adapter->set_oid.p_bytes_needed ); + if( status != NDIS_STATUS_PENDING ) + { + NdisMSetInformationComplete( p_adapter->h_adapter, status ); + } + break; + + default: + CL_ASSERT( set_oid.oid && 0 ); + break; + } + } + + IPOIB_EXIT( IPOIB_DBG_INIT ); +} + + +static NDIS_STATUS +__ipoib_set_net_addr( + IN ipoib_adapter_t * p_adapter, + IN PVOID info_buf, + IN ULONG info_buf_len, + OUT PULONG p_bytes_read, + OUT PULONG p_bytes_needed ) +{ + NDIS_STATUS status; + PNETWORK_ADDRESS_LIST p_net_addrs; + PNETWORK_ADDRESS p_net_addr_oid; + PNETWORK_ADDRESS_IP p_ip_addr; + + net_address_item_t *p_addr_item; + + cl_status_t cl_status; + + size_t idx; + LONG i; + ULONG addr_size; + ULONG total_size; + + uint8_t port_num; + + IPOIB_ENTER( IPOIB_DBG_OID ); + + status = NDIS_STATUS_SUCCESS; + port_num = p_adapter->guids.port_num; + + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received set for OID_GEN_NETWORK_LAYER_ADDRESSES\n", + port_num) ); + + if( !info_buf ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Port %d - OID_GEN_NETWORK_LAYER_ADDRESSES - " + "NULL buffer\n", port_num) ); + IPOIB_EXIT( IPOIB_DBG_OID ); + return NDIS_STATUS_INVALID_DATA; + } + + /* + * Must use field offset because the structures define array's of size one + * of a the incorrect type for what is really stored. + */ + if( info_buf_len < FIELD_OFFSET(NETWORK_ADDRESS_LIST, Address) ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Port %d OID_GEN_NETWORK_LAYER_ADDRESSES - " + "bad length of %d, not enough " + "for NETWORK_ADDRESS_LIST (%d)\n", port_num, info_buf_len, + FIELD_OFFSET(NETWORK_ADDRESS_LIST, Address)) ); + *p_bytes_needed = FIELD_OFFSET(NETWORK_ADDRESS_LIST, Address); + IPOIB_EXIT( IPOIB_DBG_OID ); + return NDIS_STATUS_INVALID_LENGTH; + } + + p_net_addrs = (PNETWORK_ADDRESS_LIST)info_buf; + if( p_net_addrs->AddressCount == 0) + { + if( p_net_addrs->AddressType == NDIS_PROTOCOL_ID_TCP_IP ) + { + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_OID, + ("Port %d OID_GEN_NETWORK_LAYER_ADDRESSES - " + "clear TCP/IP addresses\n", port_num) ); + } + else + { + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_OID, + ("Port %d OID_GEN_NETWORK_LAYER_ADDRESSES - " + "Non TCP/IP address type of 0x%.4X on clear\n", + port_num, p_net_addrs->AddressType) ); + IPOIB_EXIT( IPOIB_DBG_OID ); + return NDIS_STATUS_SUCCESS; + } + } + + addr_size = FIELD_OFFSET(NETWORK_ADDRESS, Address) + + NETWORK_ADDRESS_LENGTH_IP; + total_size = FIELD_OFFSET(NETWORK_ADDRESS_LIST, Address) + + addr_size * p_net_addrs->AddressCount; + + if( info_buf_len < total_size ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Port %d OID_GEN_NETWORK_LAYER_ADDRESSES - " + "bad length of %d, %d required for %d addresses\n", + port_num, info_buf_len, total_size, p_net_addrs->AddressCount) ); + *p_bytes_needed = total_size; + IPOIB_EXIT( IPOIB_DBG_OID ); + return NDIS_STATUS_INVALID_LENGTH; + } + + /* Lock lists for duration since SA callbacks can occur on other CPUs */ + cl_obj_lock( &p_adapter->obj ); + + /* Set the capacity of the vector to accomodate all assinged addresses. */ + cl_status = cl_vector_set_capacity( + &p_adapter->ip_vector, p_net_addrs->AddressCount ); + if( cl_status != CL_SUCCESS ) + { + cl_obj_unlock( &p_adapter->obj ); + IPOIB_PRINT(TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Port %d - OID_GEN_NETWORK_LAYER_ADDRESSES - " + "Failed to set IP vector capacity: %#x\n", port_num, + cl_status) ); + IPOIB_EXIT( IPOIB_DBG_OID ); + return NDIS_STATUS_RESOURCES; + } + + *p_bytes_read = total_size; + + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d OID_GEN_NETWORK_LAYER_ADDRESSES - List contains %d addresses\n", + port_num, p_net_addrs->AddressCount)); + + /* First look for addresses we had that should be removed */ + for( idx = 0; idx != cl_vector_get_size( &p_adapter->ip_vector ); idx++ ) + { + p_addr_item = (net_address_item_t*) + cl_vector_get_ptr( &p_adapter->ip_vector, idx ); + p_net_addr_oid = (PNETWORK_ADDRESS)p_net_addrs->Address; + + for( i = 0; i < p_net_addrs->AddressCount; ++i ) + { + + // Here we check that the data stored at 'AddressLength' field is valid; + // otherwise, it can lead to a memory violation (happened when AddressCount was > 1) + if( p_net_addr_oid->AddressLength != NETWORK_ADDRESS_LENGTH_IP) + { + IPOIB_PRINT(TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Port %d OID_GEN_NETWORK_LAYER_ADDRESSES - Address %d is wrong size of %d, " + "should be %d\n", port_num, i, p_net_addr_oid->AddressLength, + NETWORK_ADDRESS_LENGTH_IP)); + ASSERT ( p_net_addr_oid->AddressLength == NETWORK_ADDRESS_LENGTH_IPX ); + break; + } + + ASSERT( p_net_addr_oid->AddressType == NDIS_PROTOCOL_ID_TCP_IP ); + + p_net_addr_oid = (PNETWORK_ADDRESS)((uint8_t *)p_net_addr_oid + + FIELD_OFFSET(NETWORK_ADDRESS, Address) + + p_net_addr_oid->AddressLength) ; + + + + p_ip_addr = (PNETWORK_ADDRESS_IP)p_net_addr_oid->Address; + if( !cl_memcmp( &p_ip_addr->in_addr, + &p_addr_item->address.as_ulong, sizeof(ULONG) ) ) + { + break; + } + } + + if( i == p_net_addrs->AddressCount ) + { + /* Didn't find a match, delete from SA */ + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d OID_GEN_NETWORK_LAYER_ADDRESSES - Deleting Address %d.%d.%d.%d\n", + port_num, + p_addr_item->address.as_bytes[0], + p_addr_item->address.as_bytes[1], + p_addr_item->address.as_bytes[2], + p_addr_item->address.as_bytes[3])); + + if( p_addr_item->p_reg ) + { + if( p_addr_item->p_reg->h_reg_svc ) + { + p_adapter->p_ifc->dereg_svc( + p_addr_item->p_reg->h_reg_svc, __ipoib_ats_dereg_cb ); + } + else + { + cl_free( p_addr_item->p_reg ); + } + p_addr_item->p_reg = NULL; + } + p_addr_item->address.as_ulong = 0; + } + } + + /* Now look for new addresses */ + p_net_addr_oid = (NETWORK_ADDRESS *)p_net_addrs->Address; + idx = 0; + + for( i = 0; i < p_net_addrs->AddressCount; ++i ) + { + + // Here we check that the data stored at 'AddressLength' field is valid; + // otherwise, it can lead to a memory violation (happened when AddressCount was > 1) + if( p_net_addr_oid->AddressLength != NETWORK_ADDRESS_LENGTH_IP) + { + IPOIB_PRINT(TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Port %d OID_GEN_NETWORK_LAYER_ADDRESSES - Address %d is wrong size of %d, " + "should be %d\n", port_num, i, p_net_addr_oid->AddressLength, + NETWORK_ADDRESS_LENGTH_IP)); + ASSERT ( p_net_addr_oid->AddressLength == NETWORK_ADDRESS_LENGTH_IPX ); + break; + + } + + ASSERT( p_net_addr_oid->AddressType == NDIS_PROTOCOL_ID_TCP_IP ); + + p_net_addr_oid = (PNETWORK_ADDRESS)((uint8_t *)p_net_addr_oid + + FIELD_OFFSET(NETWORK_ADDRESS, Address) + + p_net_addr_oid->AddressLength) ; + + + p_ip_addr = (PNETWORK_ADDRESS_IP)p_net_addr_oid->Address; + + /* Size the vector as needed. */ + if( cl_vector_get_size( &p_adapter->ip_vector ) <= idx ) + cl_vector_set_size( &p_adapter->ip_vector, idx + 1 ); + + p_addr_item = (net_address_item_t *) cl_vector_get_ptr( &p_adapter->ip_vector, idx ); + if( !cl_memcmp( &p_ip_addr->in_addr, &p_addr_item->address.as_ulong, + sizeof(ULONG) ) ) + { + idx++; + /* Already have this address - no change needed */ + continue; + } + + /* + * Copy the address information, but don't register yet - the port + * could be down. + */ + if( p_addr_item->p_reg ) + { + /* If in use by some other address, deregister. */ + if( p_addr_item->p_reg->h_reg_svc ) + { + p_adapter->p_ifc->dereg_svc( + p_addr_item->p_reg->h_reg_svc, __ipoib_ats_dereg_cb ); + } + else + { + cl_free( p_addr_item->p_reg ); + } + p_addr_item->p_reg = NULL; + } + memcpy ((void *)&p_addr_item->address.as_ulong, (const void *)&p_ip_addr->in_addr, sizeof(ULONG) ); + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d OID_GEN_NETWORK_LAYER_ADDRESSES - Adding Address %d.%d.%d.%d\n", + port_num, + p_addr_item->address.as_bytes[0], + p_addr_item->address.as_bytes[1], + p_addr_item->address.as_bytes[2], + p_addr_item->address.as_bytes[3]) ); + idx++; + } + + /* Now clear any extra entries that shouldn't be there. */ + while( idx < cl_vector_get_size( &p_adapter->ip_vector ) ) + { + p_addr_item = (net_address_item_t*) + cl_vector_get_ptr( &p_adapter->ip_vector, + cl_vector_get_size( &p_adapter->ip_vector ) - 1 ); + + if( p_addr_item->p_reg ) + { + if( p_addr_item->p_reg->h_reg_svc ) + { + p_adapter->p_ifc->dereg_svc( + p_addr_item->p_reg->h_reg_svc, __ipoib_ats_dereg_cb ); + } + else + { + cl_free( p_addr_item->p_reg ); + } + p_addr_item->p_reg = NULL; + p_addr_item->address.as_ulong = 0; + } + + /* No need to check return value - shrinking always succeeds. */ + cl_vector_set_size( &p_adapter->ip_vector, + cl_vector_get_size( &p_adapter->ip_vector ) - 1 ); + } + + if( p_adapter->state == IB_PNP_PORT_ACTIVE && p_adapter->packet_filter ) + ipoib_reg_addrs( p_adapter ); + + cl_obj_unlock( &p_adapter->obj ); + + IPOIB_EXIT( IPOIB_DBG_OID ); + return NDIS_STATUS_SUCCESS; +} + + +/* Object lock is held when this function is called. */ +void +ipoib_reg_addrs( + IN ipoib_adapter_t* const p_adapter ) +{ + net_address_item_t *p_addr_item; + + size_t idx; + + uint8_t port_num; + + ib_api_status_t ib_status; + ib_reg_svc_req_t ib_service; + ib_gid_t port_gid; + + IPOIB_ENTER( IPOIB_DBG_OID ); + + if(p_adapter->guids.port_guid.pkey != IB_DEFAULT_PKEY) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR,IPOIB_DBG_ERROR, + ("ATS Service available for default pkey only\n")); + return; + } + port_num = p_adapter->guids.port_num; + + /* Setup our service call with things common to all calls */ + cl_memset( &ib_service, 0, sizeof(ib_service) ); + + /* BUGBUG Only register local subnet GID prefix for now */ + ib_gid_set_default( &port_gid, p_adapter->guids.port_guid.guid ); + ib_service.svc_rec.service_gid = port_gid; + + ib_service.svc_rec.service_pkey = IB_DEFAULT_PKEY; + ib_service.svc_rec.service_lease = IB_INFINITE_SERVICE_LEASE; + + /* Must cast here because the service name is an array of unsigned chars but + * strcpy want a pointer to a signed char */ + if ( StringCchCopy( (char *)ib_service.svc_rec.service_name, + sizeof(ib_service.svc_rec.service_name) / sizeof(char), ATS_NAME ) != S_OK) { + ASSERT(FALSE); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR,IPOIB_DBG_ERROR, + ("Problem copying ATS name: exiting\n")); + return; + } + + /* IP Address in question will be put in below */ + ib_service.port_guid = p_adapter->guids.port_guid.guid; + ib_service.timeout_ms = p_adapter->params.sa_timeout; + ib_service.retry_cnt = p_adapter->params.sa_retry_cnt; + + /* Can't set IB_FLAGS_SYNC here because I can't wait at dispatch */ + ib_service.flags = 0; + + /* Service context will be put in below */ + + ib_service.svc_data_mask = IB_SR_COMPMASK_SID | + IB_SR_COMPMASK_SGID | + IB_SR_COMPMASK_SPKEY | + IB_SR_COMPMASK_SLEASE | + IB_SR_COMPMASK_SNAME | + IB_SR_COMPMASK_SDATA8_12 | + IB_SR_COMPMASK_SDATA8_13 | + IB_SR_COMPMASK_SDATA8_14 | + IB_SR_COMPMASK_SDATA8_15; + ib_service.pfn_reg_svc_cb = __ipoib_ats_reg_cb; + + for( idx = 0; idx < cl_vector_get_size( &p_adapter->ip_vector); idx++ ) + { + p_addr_item = (net_address_item_t*) + cl_vector_get_ptr( &p_adapter->ip_vector, idx ); + + if( p_addr_item->p_reg ) + continue; + + p_addr_item->p_reg = cl_zalloc( sizeof(ats_reg_t) ); + if( !p_addr_item->p_reg ) + break; + + p_addr_item->p_reg->p_adapter = p_adapter; + + ib_service.svc_context = p_addr_item->p_reg; + + ib_service.svc_rec.service_id = + ATS_SERVICE_ID & CL_HTON64(0xFFFFFFFFFFFFFF00); + /* ATS service IDs start at 0x10000CE100415453 */ + ib_service.svc_rec.service_id |= ((uint64_t)(idx + 0x53)) << 56; + + cl_memcpy( &ib_service.svc_rec.service_data8[ATS_IPV4_OFFSET], + p_addr_item->address.as_bytes, IPV4_ADDR_SIZE ); + + /* Take a reference for each service request. */ + cl_obj_ref(&p_adapter->obj); + ib_status = p_adapter->p_ifc->reg_svc( + p_adapter->h_al, &ib_service, &p_addr_item->p_reg->h_reg_svc ); + if( ib_status != IB_SUCCESS ) + { + if( ib_status == IB_INVALID_GUID ) + { + /* If this occurs, we log the error but do not fail the OID yet */ + IPOIB_PRINT( TRACE_LEVEL_WARNING, IPOIB_DBG_OID, + ("Port %d OID_GEN_NETWORK_LAYER_ADDRESSES - " + "Failed to register IP Address " + "of %d.%d.%d.%d with error IB_INVALID_GUID\n", + port_num, + p_addr_item->address.as_bytes[0], + p_addr_item->address.as_bytes[1], + p_addr_item->address.as_bytes[2], + p_addr_item->address.as_bytes[3]) ); + } + else + { + /* Fatal error. */ + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Port %d OID_GEN_NETWORK_LAYER_ADDRESSES - Failed to register IP Address " + "of %d.%d.%d.%d with error %s\n", + port_num, + p_addr_item->address.as_bytes[0], + p_addr_item->address.as_bytes[1], + p_addr_item->address.as_bytes[2], + p_addr_item->address.as_bytes[3], + p_adapter->p_ifc->get_err_str( ib_status )) ); + p_adapter->hung = TRUE; + } + cl_obj_deref(&p_adapter->obj); + cl_free( p_addr_item->p_reg ); + p_addr_item->p_reg = NULL; + } + } + + IPOIB_EXIT( IPOIB_DBG_OID ); +} + + +/* Object lock is held when this function is called. */ +void +ipoib_dereg_addrs( + IN ipoib_adapter_t* const p_adapter ) +{ + net_address_item_t *p_addr_item; + + size_t idx; + + IPOIB_ENTER( IPOIB_DBG_OID ); + + for( idx = 0; idx < cl_vector_get_size( &p_adapter->ip_vector); idx++ ) + { + p_addr_item = (net_address_item_t*) + cl_vector_get_ptr( &p_adapter->ip_vector, idx ); + + if( !p_addr_item->p_reg ) + continue; + + if( p_addr_item->p_reg->h_reg_svc ) + { + p_adapter->p_ifc->dereg_svc( + p_addr_item->p_reg->h_reg_svc, __ipoib_ats_dereg_cb ); + } + else + { + cl_free( p_addr_item->p_reg ); + } + p_addr_item->p_reg = NULL; + } + + IPOIB_EXIT( IPOIB_DBG_OID ); +} + + +static void +__ipoib_ats_reg_cb( + IN ib_reg_svc_rec_t *p_reg_svc_rec ) +{ + ats_reg_t *p_reg; + uint8_t port_num; + + IPOIB_ENTER( IPOIB_DBG_OID ); + + CL_ASSERT( p_reg_svc_rec ); + CL_ASSERT( p_reg_svc_rec->svc_context ); + + p_reg = (ats_reg_t*)p_reg_svc_rec->svc_context; + port_num = p_reg->p_adapter->guids.port_num; + + cl_obj_lock( &p_reg->p_adapter->obj ); + + if( p_reg_svc_rec->req_status == IB_SUCCESS && + !p_reg_svc_rec->resp_status ) + { + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d OID_GEN_NETWORK_LAYER_ADDRESSES - Registered IP Address " + "of %d.%d.%d.%d\n", + port_num, + p_reg_svc_rec->svc_rec.service_data8[ATS_IPV4_OFFSET], + p_reg_svc_rec->svc_rec.service_data8[ATS_IPV4_OFFSET+1], + p_reg_svc_rec->svc_rec.service_data8[ATS_IPV4_OFFSET+2], + p_reg_svc_rec->svc_rec.service_data8[ATS_IPV4_OFFSET+3]) ); + } + else if( p_reg_svc_rec->req_status != IB_CANCELED ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_OID, + ("Port %d OID_GEN_NETWORK_LAYER_ADDRESSES - Failed to register IP Address " + "of %d.%d.%d.%d with error %s\n", + port_num, + p_reg_svc_rec->svc_rec.service_data8[ATS_IPV4_OFFSET], + p_reg_svc_rec->svc_rec.service_data8[ATS_IPV4_OFFSET+1], + p_reg_svc_rec->svc_rec.service_data8[ATS_IPV4_OFFSET+2], + p_reg_svc_rec->svc_rec.service_data8[ATS_IPV4_OFFSET+3], + p_reg->p_adapter->p_ifc->get_err_str( p_reg_svc_rec->resp_status )) ); + p_reg->p_adapter->hung = TRUE; + p_reg->h_reg_svc = NULL; + } + + cl_obj_unlock( &p_reg->p_adapter->obj ); + cl_obj_deref(&p_reg->p_adapter->obj); + + IPOIB_EXIT( IPOIB_DBG_OID ); +} + + +static void +__ipoib_ats_dereg_cb( + IN void *context ) +{ + cl_free( context ); +} diff --git a/branches/WOF2-3/ulp/ipoib/kernel/ipoib_driver.h b/branches/WOF2-3/ulp/ipoib/kernel/ipoib_driver.h new file mode 100644 index 00000000..7f2725c2 --- /dev/null +++ b/branches/WOF2-3/ulp/ipoib/kernel/ipoib_driver.h @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2006 Mellanox Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#ifndef _IPOIB_DRIVER_H_ +#define _IPOIB_DRIVER_H_ + + +#include "ipoib_log.h" +#include "ipoib_adapter.h" +#include +#include +#include "ipoib_debug.h" + + +/* + * Definitions + */ +#define MAX_BUNDLE_ID_LENGTH 32 + +/* The maximum number of send packets the MiniportSendPackets function can accept */ +#define MINIPORT_MAX_SEND_PACKETS 200 + +/* MLX4 supports 4K MTU */ +#define IB_MTU 4096 +/* + * Header length as defined by IPoIB spec: + * http://www.ietf.org/internet-drafts/draft-ietf-ipoib-ip-over-infiniband-04.txt + */ + +#define MAX_PAYLOAD_MTU (IB_MTU - sizeof(ipoib_hdr_t)) + +/* + * Only the protocol type is sent as part of the UD payload + * since the rest of the Ethernet header is encapsulated in the + * various IB headers. We report out buffer space as if we + * transmit the ethernet headers. + */ +#define MAX_XFER_BLOCK_SIZE (sizeof(eth_hdr_t) + MAX_PAYLOAD_MTU) + + +typedef struct _ipoib_globals +{ + KSPIN_LOCK lock; + cl_qlist_t adapter_list; + cl_qlist_t bundle_list; + + atomic32_t laa_idx; + + NDIS_HANDLE h_ndis_wrapper; + NDIS_HANDLE h_ibat_dev; + volatile LONG ibat_ref; + uint32_t bypass_check_bcast_rate; + +} ipoib_globals_t; +/* +* FIELDS +* lock +* Spinlock to protect list access. +* +* adapter_list +* List of all adapter instances. Used for address translation support. +* +* bundle_list +* List of all adapter bundles. +* +* laa_idx +* Global counter for generating LAA MACs +* +* h_ibat_dev +* Device handle returned by NdisMRegisterDevice. +*********/ + +extern ipoib_globals_t g_ipoib; + + +typedef struct _ipoib_bundle +{ + cl_list_item_t list_item; + char bundle_id[MAX_BUNDLE_ID_LENGTH]; + cl_qlist_t adapter_list; + +} ipoib_bundle_t; +/* +* FIELDS +* list_item +* List item for storing the bundle in a quick list. +* +* bundle_id +* Bundle identifier. +* +* adapter_list +* List of adapters in the bundle. The adapter at the head is the +* primary adapter of the bundle. +*********/ +void +ipoib_create_log( + NDIS_HANDLE h_adapter, + UINT ind, + ULONG eventLogMsgId); + +#define GUID_MASK_LOG_INDEX 0 + +void +ipoib_resume_oids( + IN ipoib_adapter_t* const p_adapter ); + +#define IPOIB_OFFSET(field) ((UINT)FIELD_OFFSET(ipoib_params_t,field)) +#define IPOIB_SIZE(field) sizeof(((ipoib_params_t*)0)->field) +#define IPOIB_INIT_NDIS_STRING(str) \ + (str)->Length = 0; \ + (str)->MaximumLength = 0; \ + (str)->Buffer = NULL; + + + +#endif /* _IPOIB_DRIVER_H_ */ diff --git a/branches/WOF2-3/ulp/ipoib/kernel/ipoib_endpoint.c b/branches/WOF2-3/ulp/ipoib/kernel/ipoib_endpoint.c new file mode 100644 index 00000000..53903a05 --- /dev/null +++ b/branches/WOF2-3/ulp/ipoib/kernel/ipoib_endpoint.c @@ -0,0 +1,358 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2006 Mellanox Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + +#include "ipoib_endpoint.h" +#include "ipoib_port.h" +#include "ipoib_debug.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "ipoib_endpoint.tmh" +#endif +#include + + +static void +__endpt_destroying( + IN cl_obj_t* p_obj ); + +static void +__endpt_cleanup( + IN cl_obj_t* p_obj ); + +static void +__endpt_free( + IN cl_obj_t* p_obj ); + +static ib_api_status_t +__create_mcast_av( + IN ib_pd_handle_t h_pd, + IN uint8_t port_num, + IN ib_member_rec_t* const p_member_rec, + OUT ib_av_handle_t* const ph_av ); + +static inline ipoib_port_t* +__endpt_parent( + IN ipoib_endpt_t* const p_endpt ); + +static void +__path_query_cb( + IN ib_query_rec_t *p_query_rec ); + +static void +__endpt_resolve( + IN ipoib_endpt_t* const p_endpt ); + + +ipoib_endpt_t* +ipoib_endpt_create( + IN const ib_gid_t* const p_dgid, + IN const net16_t dlid, + IN const net32_t qpn ) +{ + ipoib_endpt_t *p_endpt; + cl_status_t status; + + IPOIB_ENTER( IPOIB_DBG_ENDPT ); + + p_endpt = cl_zalloc( sizeof(ipoib_endpt_t) ); + if( !p_endpt ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to allocate endpoint (%d bytes)\n", + sizeof(ipoib_endpt_t)) ); + return NULL; + } + + cl_obj_construct( &p_endpt->obj, IPOIB_OBJ_ENDPOINT ); + + status = cl_obj_init( &p_endpt->obj, CL_DESTROY_ASYNC, + __endpt_destroying, __endpt_cleanup, __endpt_free ); + + p_endpt->dgid = *p_dgid; + p_endpt->dlid = dlid; + p_endpt->qpn = qpn; + + IPOIB_EXIT( IPOIB_DBG_ENDPT ); + return p_endpt; +} + + +static ib_api_status_t +__create_mcast_av( + IN ib_pd_handle_t h_pd, + IN uint8_t port_num, + IN ib_member_rec_t* const p_member_rec, + OUT ib_av_handle_t* const ph_av ) +{ + ib_av_attr_t av_attr; + uint32_t flow_lbl; + uint8_t hop_lmt; + ib_api_status_t status; + ipoib_endpt_t *p_endpt; + + IPOIB_ENTER( IPOIB_DBG_MCAST ); + + p_endpt = PARENT_STRUCT(ph_av, ipoib_endpt_t, h_av ); + + cl_memclr( &av_attr, sizeof(ib_av_attr_t) ); + av_attr.port_num = port_num; + ib_member_get_sl_flow_hop( p_member_rec->sl_flow_hop, + &av_attr.sl, &flow_lbl, &hop_lmt ); + av_attr.dlid = p_member_rec->mlid; + av_attr.grh_valid = TRUE; + av_attr.grh.hop_limit = hop_lmt; + av_attr.grh.dest_gid = p_member_rec->mgid; + av_attr.grh.src_gid = p_member_rec->port_gid; + av_attr.grh.ver_class_flow = + ib_grh_set_ver_class_flow( 6, p_member_rec->tclass, flow_lbl ); + av_attr.static_rate = p_member_rec->rate & IB_PATH_REC_BASE_MASK; + av_attr.path_bits = 0; + /* port is not attached to endpoint at this point, so use endpt ifc reference */ + status = p_endpt->p_ifc->create_av( h_pd, &av_attr, ph_av ); + + if( status != IB_SUCCESS ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_create_av returned %s\n", + p_endpt->p_ifc->get_err_str( status )) ); + } + + IPOIB_EXIT( IPOIB_DBG_MCAST ); + return status; +} + + +ib_api_status_t +ipoib_endpt_set_mcast( + IN ipoib_endpt_t* const p_endpt, + IN ib_pd_handle_t h_pd, + IN uint8_t port_num, + IN ib_mcast_rec_t* const p_mcast_rec ) +{ + ib_api_status_t status; + + IPOIB_ENTER( IPOIB_DBG_ENDPT ); + + IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_ENDPT, + ("Create av for MAC: %02X-%02X-%02X-%02X-%02X-%02X\n", + p_endpt->mac.addr[0], p_endpt->mac.addr[1], + p_endpt->mac.addr[2], p_endpt->mac.addr[3], + p_endpt->mac.addr[4], p_endpt->mac.addr[5]) ); + + status = __create_mcast_av( h_pd, port_num, p_mcast_rec->p_member_rec, + &p_endpt->h_av ); + if( status != IB_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("__create_mcast_av returned %s\n", + p_endpt->p_ifc->get_err_str( status )) ); + return status; + } + p_endpt->h_mcast = p_mcast_rec->h_mcast; + CL_ASSERT(p_endpt->dlid == 0); + + IPOIB_EXIT( IPOIB_DBG_ENDPT ); + return IB_SUCCESS; +} + + +static void +__endpt_destroying( + IN cl_obj_t* p_obj ) +{ + ipoib_endpt_t *p_endpt; + ipoib_port_t *p_port; + + IPOIB_ENTER( IPOIB_DBG_ENDPT ); + + p_endpt = PARENT_STRUCT( p_obj, ipoib_endpt_t, obj ); + p_port = __endpt_parent( p_endpt ); + + cl_obj_lock( p_obj ); + if( p_endpt->h_query ) + { + p_port->p_adapter->p_ifc->cancel_query( + p_port->p_adapter->h_al, p_endpt->h_query ); + p_endpt->h_query = NULL; + } + + /* Leave the multicast group if it exists. */ + if( p_endpt->h_mcast ) + { + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_ENDPT, + ("Leaving MCast group\n") ); + ipoib_port_ref(p_port, ref_leave_mcast); + p_port->p_adapter->p_ifc->leave_mcast( p_endpt->h_mcast, ipoib_leave_mcast_cb ); + } + + cl_obj_unlock( p_obj ); + + IPOIB_EXIT( IPOIB_DBG_ENDPT ); +} + + +static void +__endpt_cleanup( + IN cl_obj_t* p_obj ) +{ + ipoib_endpt_t *p_endpt; + ipoib_port_t *p_port; + + IPOIB_ENTER( IPOIB_DBG_ENDPT ); + + p_endpt = PARENT_STRUCT( p_obj, ipoib_endpt_t, obj ); + p_port = __endpt_parent( p_endpt ); + + /* Destroy the AV if it exists. */ + if( p_endpt->h_av ) + p_port->p_adapter->p_ifc->destroy_av( p_endpt->h_av ); + + IPOIB_EXIT( IPOIB_DBG_ENDPT ); +} + + +static void +__endpt_free( + IN cl_obj_t* p_obj ) +{ + ipoib_endpt_t *p_endpt; + + IPOIB_ENTER( IPOIB_DBG_ENDPT ); + + p_endpt = PARENT_STRUCT( p_obj, ipoib_endpt_t, obj ); + + cl_obj_deinit( p_obj ); + cl_free( p_endpt ); + + IPOIB_EXIT( IPOIB_DBG_ENDPT ); +} + + +static inline ipoib_port_t* +__endpt_parent( + IN ipoib_endpt_t* const p_endpt ) +{ + return PARENT_STRUCT( p_endpt->rel.p_parent_obj, ipoib_port_t, obj ); +} + + +/* + * This function is called with the port object's send lock held and + * a reference held on the endpoint. If we fail, we release the reference. + */ +NDIS_STATUS +ipoib_endpt_queue( + IN ipoib_endpt_t* const p_endpt ) +{ + ib_api_status_t status; + ipoib_port_t *p_port; + ib_av_attr_t av_attr; + net32_t flow_lbl; + + IPOIB_ENTER( IPOIB_DBG_ENDPT ); + + if( p_endpt->h_av ) + { + IPOIB_EXIT( IPOIB_DBG_ENDPT ); + return NDIS_STATUS_SUCCESS; + } + + if( p_endpt->qpn == CL_HTON32(0x00FFFFFF) ) + { + /* + * Handle a race between the mcast callback and a receive/send. The QP + * is joined to the MC group before the MC callback is received, so it + * can receive packets, and NDIS can try to respond. We need to delay + * a response until the MC callback runs and sets the AV. + */ + ipoib_endpt_deref( p_endpt ); + IPOIB_EXIT( IPOIB_DBG_ENDPT ); + return NDIS_STATUS_PENDING; + } + + /* This is the first packet for this endpoint. Create the AV. */ + p_port = __endpt_parent( p_endpt ); + + cl_memclr( &av_attr, sizeof(ib_av_attr_t) ); + + av_attr.port_num = p_port->port_num; + + ib_member_get_sl_flow_hop( + p_port->ib_mgr.bcast_rec.sl_flow_hop, + &av_attr.sl, + &flow_lbl, + &av_attr.grh.hop_limit + ); + + av_attr.dlid = p_endpt->dlid; + + /* + * We always send the GRH so that we preferably lookup endpoints + * by GID rather than by LID. This allows certain WHQL tests + * such as the 2c_MediaCheck test to succeed since they don't use + * IP. This allows endpoints to be created on the fly for requests + * for which there is no match, something that doesn't work when + * using LIDs only. + */ + av_attr.grh_valid = TRUE; + av_attr.grh.ver_class_flow = ib_grh_set_ver_class_flow( + 6, p_port->ib_mgr.bcast_rec.tclass, flow_lbl ); + av_attr.grh.resv1 = 0; + av_attr.grh.resv2 = 0; + ib_gid_set_default( &av_attr.grh.src_gid, p_port->p_adapter->guids.port_guid.guid ); + av_attr.grh.dest_gid = p_endpt->dgid; + + av_attr.static_rate = p_port->ib_mgr.bcast_rec.rate; + av_attr.path_bits = 0; + + /* Create the AV. */ + status = p_port->p_adapter->p_ifc->create_av( + p_port->ib_mgr.h_pd, &av_attr, &p_endpt->h_av ); + if( status != IB_SUCCESS ) + { + p_port->p_adapter->hung = TRUE; + ipoib_endpt_deref( p_endpt ); + cl_obj_unlock( &p_endpt->obj ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_create_av failed with %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + return NDIS_STATUS_FAILURE; + } + + IPOIB_EXIT( IPOIB_DBG_ENDPT ); + return NDIS_STATUS_SUCCESS; +} diff --git a/branches/WOF2-3/ulp/ipoib/kernel/ipoib_endpoint.h b/branches/WOF2-3/ulp/ipoib/kernel/ipoib_endpoint.h new file mode 100644 index 00000000..ae1f1468 --- /dev/null +++ b/branches/WOF2-3/ulp/ipoib/kernel/ipoib_endpoint.h @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2006 Mellanox Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#ifndef _IPOIB_ENDPOINT_H_ +#define _IPOIB_ENDPOINT_H_ + + +#include +#include +#include +#include +#include +#include "iba/ipoib_ifc.h" +#include +#include "ipoib_debug.h" + + +typedef struct _ipoib_endpt +{ + cl_obj_t obj; + cl_obj_rel_t rel; + cl_map_item_t mac_item; + cl_fmap_item_t gid_item; + cl_map_item_t lid_item; + ib_query_handle_t h_query; + ib_mcast_handle_t h_mcast; + mac_addr_t mac; + ib_gid_t dgid; + net16_t dlid; + net32_t qpn; + ib_av_handle_t h_av; + ib_al_ifc_t *p_ifc; + boolean_t is_in_use; + boolean_t is_mcast_listener; +} ipoib_endpt_t; +/* +* FIELDS +* mac_item +* Map item for storing the endpoint in a map. The key is the +* destination MAC address. +* +* lid_item +* Map item for storing the endpoint in a map. The key is the +* destination LID. +* +* gid_item +* Map item for storing the endpoint in a map. The key is the +* destination GID. +* +* h_query +* Query handle for cancelling SA queries. +* +* h_mcast +* For multicast endpoints, the multicast handle. +* +* mac +* MAC address. +* +* dgid +* Destination GID. +* +* dlid +* Destination LID. The destination LID is only set for endpoints +* that are on the same subnet. It is used as key in the LID map. +* +* qpn +* Destination queue pair number. +* +* h_av +* Address vector for sending data. +* +* expired +* Flag to indicate that the endpoint should be flushed. +* +* p_ifc +* Reference to transport functions, can be used +* while endpoint is not attached to port yet. +* +* NOTES +* If the h_mcast member is set, the endpoint is never expired. +*********/ + + +ipoib_endpt_t* +ipoib_endpt_create( + IN const ib_gid_t* const p_dgid, + IN const net16_t dlid, + IN const net32_t qpn ); + + +ib_api_status_t +ipoib_endpt_set_mcast( + IN ipoib_endpt_t* const p_endpt, + IN ib_pd_handle_t h_pd, + IN uint8_t port_num, + IN ib_mcast_rec_t* const p_mcast_rec ); + + +static inline void +ipoib_endpt_ref( + IN ipoib_endpt_t* const p_endpt ) +{ + CL_ASSERT( p_endpt ); + + cl_obj_ref( &p_endpt->obj ); + /* + * Anytime we reference the endpoint, we're either receiving data + * or trying to send data to that endpoint. Clear the expired flag + * to prevent the AV from being flushed. + */ +} + + +static inline void +ipoib_endpt_deref( + IN ipoib_endpt_t* const p_endpt ) +{ + cl_obj_deref( &p_endpt->obj ); +} + + +NDIS_STATUS +ipoib_endpt_queue( + IN ipoib_endpt_t* const p_endpt ); + + +#endif /* _IPOIB_ENDPOINT_H_ */ diff --git a/branches/WOF2-3/ulp/ipoib/kernel/ipoib_ibat.c b/branches/WOF2-3/ulp/ipoib/kernel/ipoib_ibat.c new file mode 100644 index 00000000..01fc02a8 --- /dev/null +++ b/branches/WOF2-3/ulp/ipoib/kernel/ipoib_ibat.c @@ -0,0 +1,670 @@ +/* + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include "ipoib_driver.h" +#include "ipoib_adapter.h" +#include "ipoib_port.h" +#include "ipoib_debug.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "ipoib_ibat.tmh" +#endif +#include + + +static NTSTATUS +__ipoib_create( + IN DEVICE_OBJECT* const pDevObj, + IN IRP* const pIrp ); + +static NTSTATUS +__ipoib_cleanup( + IN DEVICE_OBJECT* const pDevObj, + IN IRP* const pIrp ); + +static NTSTATUS +__ipoib_close( + IN DEVICE_OBJECT* const pDevObj, + IN IRP* const pIrp ); + +static NTSTATUS +__ipoib_dispatch( + IN DEVICE_OBJECT* const pDevObj, + IN IRP* const pIrp ); + + +static NTSTATUS +__ibat_get_ports( + IN IRP *pIrp, + IN IO_STACK_LOCATION *pIoStack ) +{ + IOCTL_IBAT_PORTS_IN *pIn; + IOCTL_IBAT_PORTS_OUT *pOut; + KLOCK_QUEUE_HANDLE hdl; + cl_list_item_t *pItem; + ipoib_adapter_t *pAdapter; + LONG nPorts; + + IPOIB_ENTER(IPOIB_DBG_IOCTL); + + if( pIoStack->Parameters.DeviceIoControl.InputBufferLength != + sizeof(IOCTL_IBAT_PORTS_IN) ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Invalid input buffer size.\n") ); + return STATUS_INVALID_PARAMETER; + } + + if( pIoStack->Parameters.DeviceIoControl.OutputBufferLength < + sizeof(IOCTL_IBAT_PORTS_OUT) ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Invalid output buffer size.\n") ); + return STATUS_INVALID_PARAMETER; + } + + pIn = pIrp->AssociatedIrp.SystemBuffer; + pOut = pIrp->AssociatedIrp.SystemBuffer; + + if( pIn->Version != IBAT_IOCTL_VERSION ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Invalid version.\n") ); + return STATUS_INVALID_PARAMETER; + } + + KeAcquireInStackQueuedSpinLock( &g_ipoib.lock, &hdl ); + nPorts = (LONG)cl_qlist_count( &g_ipoib.adapter_list ); + switch( nPorts ) + { + case 0: + cl_memclr( pOut->Ports, sizeof(pOut->Ports) ); + /* Fall through */ + case 1: + pOut->Size = sizeof(IOCTL_IBAT_PORTS_OUT); + break; + + default: + pOut->Size = sizeof(IOCTL_IBAT_PORTS_OUT) + + (sizeof(IBAT_PORT_RECORD) * (nPorts - 1)); + break; + } + + pIrp->IoStatus.Information = pOut->Size; + + if( pOut->Size > pIoStack->Parameters.DeviceIoControl.OutputBufferLength ) + { + nPorts = 1 + + (pIoStack->Parameters.DeviceIoControl.OutputBufferLength - + sizeof(IOCTL_IBAT_PORTS_OUT)) / sizeof(IBAT_PORT_RECORD); + + pIrp->IoStatus.Information = sizeof(IOCTL_IBAT_PORTS_OUT) + + ((nPorts - 1) * sizeof(IBAT_PORT_RECORD)); + } + + pOut->NumPorts = 0; + pItem = cl_qlist_head( &g_ipoib.adapter_list ); + while( pOut->NumPorts != nPorts ) + { + pAdapter = CONTAINING_RECORD( pItem, ipoib_adapter_t, entry ); + pOut->Ports[pOut->NumPorts].CaGuid = pAdapter->guids.ca_guid; + pOut->Ports[pOut->NumPorts].PortGuid = pAdapter->guids.port_guid.guid; + pOut->Ports[pOut->NumPorts].PKey = IB_DEFAULT_PKEY; + pOut->Ports[pOut->NumPorts].PortNum = pAdapter->guids.port_num; + pOut->NumPorts++; + + pItem = cl_qlist_next( pItem ); + } + + KeReleaseInStackQueuedSpinLock( &hdl ); + IPOIB_EXIT( IPOIB_DBG_IOCTL ); + return STATUS_SUCCESS; +} + + +static NTSTATUS +__ibat_get_ips( + IN IRP *pIrp, + IN IO_STACK_LOCATION *pIoStack ) +{ + IOCTL_IBAT_IP_ADDRESSES_IN *pIn; + IOCTL_IBAT_IP_ADDRESSES_OUT *pOut; + KLOCK_QUEUE_HANDLE hdl; + cl_list_item_t *pItem; + ipoib_adapter_t *pAdapter; + LONG nIps, maxIps; + size_t idx; + net_address_item_t *pAddr; + UINT64 PortGuid; + + IPOIB_ENTER(IPOIB_DBG_IOCTL); + + if( pIoStack->Parameters.DeviceIoControl.InputBufferLength != + sizeof(IOCTL_IBAT_IP_ADDRESSES_IN) ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Invalid input buffer size.\n") ); + return STATUS_INVALID_PARAMETER; + } + + if( pIoStack->Parameters.DeviceIoControl.OutputBufferLength < + sizeof(IOCTL_IBAT_IP_ADDRESSES_OUT) ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Invalid output buffer size.\n") ); + return STATUS_INVALID_PARAMETER; + } + + pIn = pIrp->AssociatedIrp.SystemBuffer; + pOut = pIrp->AssociatedIrp.SystemBuffer; + + if( pIn->Version != IBAT_IOCTL_VERSION ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Invalid version.\n") ); + return STATUS_INVALID_PARAMETER; + } + + PortGuid = pIn->PortGuid; + + nIps = 0; + pOut->AddressCount = 0; + maxIps = 1 + + ((pIoStack->Parameters.DeviceIoControl.OutputBufferLength - + sizeof(IOCTL_IBAT_IP_ADDRESSES_OUT)) / sizeof(IP_ADDRESS)); + + KeAcquireInStackQueuedSpinLock( &g_ipoib.lock, &hdl ); + for( pItem = cl_qlist_head( &g_ipoib.adapter_list ); + pItem != cl_qlist_end( &g_ipoib.adapter_list ); + pItem = cl_qlist_next( pItem ) ) + { + pAdapter = CONTAINING_RECORD( pItem, ipoib_adapter_t, entry ); + if( PortGuid && pAdapter->guids.port_guid.guid != PortGuid ) + continue; + + cl_obj_lock( &pAdapter->obj ); + nIps += (LONG)cl_vector_get_size( &pAdapter->ip_vector ); + + for( idx = 0; + idx < cl_vector_get_size( &pAdapter->ip_vector ); + idx++ ) + { + if( pOut->AddressCount == maxIps ) + break; + + pAddr = (net_address_item_t*) + cl_vector_get_ptr( &pAdapter->ip_vector, idx ); + + pOut->Address[pOut->AddressCount].IpVersion = 4; + cl_memclr( &pOut->Address[pOut->AddressCount].Address, + sizeof(IP_ADDRESS) ); + cl_memcpy( &pOut->Address[pOut->AddressCount].Address[12], + pAddr->address.as_bytes, IPV4_ADDR_SIZE ); + + pOut->AddressCount++; + } + cl_obj_unlock( &pAdapter->obj ); + } + + pOut->Size = sizeof(IOCTL_IBAT_IP_ADDRESSES_OUT); + if( --nIps ) + pOut->Size += sizeof(IP_ADDRESS) * nIps; + + pIrp->IoStatus.Information = sizeof(IOCTL_IBAT_IP_ADDRESSES_OUT); + if( --maxIps < nIps ) + pIrp->IoStatus.Information += (sizeof(IP_ADDRESS) * maxIps); + else + pIrp->IoStatus.Information += (sizeof(IP_ADDRESS) * nIps); + + KeReleaseInStackQueuedSpinLock( &hdl ); + IPOIB_EXIT( IPOIB_DBG_IOCTL ); + return STATUS_SUCCESS; +} + + +static NTSTATUS +__ibat_mac_to_gid( + IN IRP *pIrp, + IN IO_STACK_LOCATION *pIoStack ) +{ + NTSTATUS status = STATUS_INVALID_PARAMETER; + IOCTL_IBAT_MAC_TO_GID_IN *pIn; + IOCTL_IBAT_MAC_TO_GID_OUT *pOut; + KLOCK_QUEUE_HANDLE hdl; + cl_list_item_t *pItem; + ipoib_adapter_t *pAdapter; + + IPOIB_ENTER(IPOIB_DBG_IOCTL); + + if( pIoStack->Parameters.DeviceIoControl.InputBufferLength != + sizeof(IOCTL_IBAT_MAC_TO_GID_IN) ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Invalid input buffer size.\n") ); + return STATUS_INVALID_PARAMETER; + } + + if( pIoStack->Parameters.DeviceIoControl.OutputBufferLength != + sizeof(IOCTL_IBAT_MAC_TO_GID_OUT) ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Invalid output buffer size.\n") ); + return STATUS_INVALID_PARAMETER; + } + + pIn = pIrp->AssociatedIrp.SystemBuffer; + pOut = pIrp->AssociatedIrp.SystemBuffer; + + if( pIn->Version != IBAT_IOCTL_VERSION ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Invalid version.\n") ); + return STATUS_INVALID_PARAMETER; + } + + KeAcquireInStackQueuedSpinLock( &g_ipoib.lock, &hdl ); + + for( pItem = cl_qlist_head( &g_ipoib.adapter_list ); + pItem != cl_qlist_end( &g_ipoib.adapter_list ); + pItem = cl_qlist_next( pItem ) ) + { + pAdapter = CONTAINING_RECORD( pItem, ipoib_adapter_t, entry ); + if( pIn->PortGuid != pAdapter->guids.port_guid.guid ) + continue; + + /* Found the port - lookup the MAC. */ + cl_obj_lock( &pAdapter->obj ); + if( pAdapter->p_port ) + { + status = ipoib_mac_to_gid( + pAdapter->p_port, *(mac_addr_t*)pIn->DestMac, &pOut->DestGid ); + if( NT_SUCCESS( status ) ) + { + pIrp->IoStatus.Information = + sizeof(IOCTL_IBAT_MAC_TO_GID_OUT); + } + } + cl_obj_unlock( &pAdapter->obj ); + break; + } + + KeReleaseInStackQueuedSpinLock( &hdl ); + + IPOIB_EXIT( IPOIB_DBG_IOCTL ); + return status; +} + + +static NTSTATUS +__ibat_mac_to_path( + IN IRP *pIrp, + IN IO_STACK_LOCATION *pIoStack ) +{ + NTSTATUS status = STATUS_INVALID_PARAMETER; + IOCTL_IBAT_MAC_TO_PATH_IN *pIn; + IOCTL_IBAT_MAC_TO_PATH_OUT *pOut; + KLOCK_QUEUE_HANDLE hdl; + cl_list_item_t *pItem; + ipoib_adapter_t *pAdapter; + + IPOIB_ENTER(IPOIB_DBG_IOCTL); + + if( pIoStack->Parameters.DeviceIoControl.InputBufferLength != + sizeof(IOCTL_IBAT_MAC_TO_PATH_IN) ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Invalid input buffer size.\n") ); + return STATUS_INVALID_PARAMETER; + } + + if( pIoStack->Parameters.DeviceIoControl.OutputBufferLength != + sizeof(IOCTL_IBAT_MAC_TO_PATH_OUT) ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Invalid output buffer size.\n") ); + return STATUS_INVALID_PARAMETER; + } + + pIn = pIrp->AssociatedIrp.SystemBuffer; + pOut = pIrp->AssociatedIrp.SystemBuffer; + + if( pIn->Version != IBAT_IOCTL_VERSION ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Invalid version.\n") ); + return STATUS_INVALID_PARAMETER; + } + + KeAcquireInStackQueuedSpinLock( &g_ipoib.lock, &hdl ); + + for( pItem = cl_qlist_head( &g_ipoib.adapter_list ); + pItem != cl_qlist_end( &g_ipoib.adapter_list ); + pItem = cl_qlist_next( pItem ) ) + { + pAdapter = CONTAINING_RECORD( pItem, ipoib_adapter_t, entry ); + if( pIn->PortGuid != pAdapter->guids.port_guid.guid ) + continue; + + /* Found the port - lookup the MAC. */ + cl_obj_lock( &pAdapter->obj ); + if( pAdapter->p_port ) + { + status = ipoib_mac_to_path( + pAdapter->p_port, *(mac_addr_t*)pIn->DestMac, &pOut->Path ); + + if( NT_SUCCESS( status ) ) + { + pIrp->IoStatus.Information = + sizeof(IOCTL_IBAT_MAC_TO_PATH_OUT); + } + } + cl_obj_unlock( &pAdapter->obj ); + break; + } + + KeReleaseInStackQueuedSpinLock( &hdl ); + + IPOIB_EXIT( IPOIB_DBG_IOCTL ); + return status; +} + + +static NTSTATUS +__ibat_ip_to_port( + IN IRP *pIrp, + IN IO_STACK_LOCATION *pIoStack ) +{ + IOCTL_IBAT_IP_TO_PORT_IN *pIn; + IOCTL_IBAT_IP_TO_PORT_OUT *pOut; + KLOCK_QUEUE_HANDLE hdl; + cl_list_item_t *pItem; + ipoib_adapter_t *pAdapter; + size_t idx; + net_address_item_t *pAddr; + NTSTATUS status = STATUS_NOT_FOUND; + + IPOIB_ENTER(IPOIB_DBG_IOCTL); + + if( pIoStack->Parameters.DeviceIoControl.InputBufferLength != + sizeof(IOCTL_IBAT_IP_TO_PORT_IN) ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Invalid input buffer size.\n") ); + return STATUS_INVALID_PARAMETER; + } + + if( pIoStack->Parameters.DeviceIoControl.OutputBufferLength != + sizeof(IOCTL_IBAT_IP_TO_PORT_OUT) ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Invalid output buffer size.\n") ); + return STATUS_INVALID_PARAMETER; + } + + pIn = pIrp->AssociatedIrp.SystemBuffer; + pOut = pIrp->AssociatedIrp.SystemBuffer; + + if( pIn->Version != IBAT_IOCTL_VERSION ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Invalid version.\n") ); + return STATUS_INVALID_PARAMETER; + } + + if (pIn->Address.IpVersion != 4) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Invalid IP version (%d). Supported only 4\n", pIn->Address.IpVersion) ); + return STATUS_INVALID_PARAMETER; + } + + KeAcquireInStackQueuedSpinLock( &g_ipoib.lock, &hdl ); + for( pItem = cl_qlist_head( &g_ipoib.adapter_list ); + pItem != cl_qlist_end( &g_ipoib.adapter_list ); + pItem = cl_qlist_next( pItem ) ) + { + pAdapter = CONTAINING_RECORD( pItem, ipoib_adapter_t, entry ); + + cl_obj_lock( &pAdapter->obj ); + + for( idx = 0; + idx < cl_vector_get_size( &pAdapter->ip_vector ); + idx++ ) + { + pAddr = (net_address_item_t*) + cl_vector_get_ptr( &pAdapter->ip_vector, idx ); + + if (!memcmp( &pIn->Address.Address[12], pAddr->address.as_bytes, IPV4_ADDR_SIZE)) + { + pOut->Port.CaGuid = pAdapter->guids.ca_guid; + pOut->Port.PortGuid = pAdapter->guids.port_guid.guid; + pOut->Port.PKey = IB_DEFAULT_PKEY; + pOut->Port.PortNum = pAdapter->guids.port_num; + pIrp->IoStatus.Information = sizeof(IOCTL_IBAT_IP_TO_PORT_OUT); + status = STATUS_SUCCESS; + break; + } + } + cl_obj_unlock( &pAdapter->obj ); + if (status == STATUS_SUCCESS) + break; + } + + KeReleaseInStackQueuedSpinLock( &hdl ); + IPOIB_EXIT( IPOIB_DBG_IOCTL ); + return status; +} + +void +ipoib_ref_ibat() +{ + NDIS_STATUS status; + NDIS_STRING DeviceName; + NDIS_STRING DeviceLinkUnicodeString; + PDRIVER_DISPATCH DispatchTable[IRP_MJ_MAXIMUM_FUNCTION+1]; + DEVICE_OBJECT *p_dev_obj; + + IPOIB_ENTER( IPOIB_DBG_IOCTL ); + + if( InterlockedIncrement( &g_ipoib.ibat_ref ) == 1 ) + { + NdisInitUnicodeString( &DeviceName, IBAT_DEV_NAME ); + NdisInitUnicodeString( &DeviceLinkUnicodeString, IBAT_DOS_DEV_NAME ); + + NdisZeroMemory( DispatchTable, sizeof(DispatchTable) ); + + DispatchTable[IRP_MJ_CREATE] = __ipoib_create; + DispatchTable[IRP_MJ_CLEANUP] = __ipoib_cleanup; + DispatchTable[IRP_MJ_CLOSE] = __ipoib_close; + DispatchTable[IRP_MJ_DEVICE_CONTROL] = __ipoib_dispatch; + DispatchTable[IRP_MJ_INTERNAL_DEVICE_CONTROL] = __ipoib_dispatch; + + status = NdisMRegisterDevice( g_ipoib.h_ndis_wrapper, + &DeviceName, &DeviceLinkUnicodeString, &DispatchTable[0], + &p_dev_obj, &g_ipoib.h_ibat_dev ); + if( status != NDIS_STATUS_SUCCESS ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("NdisMRegisterDevice failed with status of %d\n", status) ); + } + } + + IPOIB_EXIT( IPOIB_DBG_IOCTL ); +} + + +void +ipoib_deref_ibat() +{ + IPOIB_ENTER( IPOIB_DBG_IOCTL ); + + if( InterlockedDecrement( &g_ipoib.ibat_ref ) ) + { + IPOIB_EXIT( IPOIB_DBG_IOCTL ); + return; + } + + if( g_ipoib.h_ibat_dev ) + { + NdisMDeregisterDevice( g_ipoib.h_ibat_dev ); + g_ipoib.h_ibat_dev = NULL; + } + + IPOIB_EXIT( IPOIB_DBG_IOCTL ); +} + + +static NTSTATUS +__ipoib_create( + IN DEVICE_OBJECT* const pDevObj, + IN IRP* const pIrp ) +{ + IPOIB_ENTER( IPOIB_DBG_IOCTL ); + + UNREFERENCED_PARAMETER( pDevObj ); + + ipoib_ref_ibat(); + + pIrp->IoStatus.Status = STATUS_SUCCESS; + pIrp->IoStatus.Information = 0; + IoCompleteRequest( pIrp, IO_NO_INCREMENT ); + + IPOIB_EXIT( IPOIB_DBG_IOCTL ); + return STATUS_SUCCESS; +} + + +static NTSTATUS +__ipoib_cleanup( + IN DEVICE_OBJECT* const pDevObj, + IN IRP* const pIrp ) +{ + IPOIB_ENTER( IPOIB_DBG_IOCTL ); + + UNREFERENCED_PARAMETER( pDevObj ); + + ipoib_deref_ibat(); + + pIrp->IoStatus.Status = STATUS_SUCCESS; + pIrp->IoStatus.Information = 0; + IoCompleteRequest( pIrp, IO_NO_INCREMENT ); + + IPOIB_EXIT( IPOIB_DBG_IOCTL ); + return STATUS_SUCCESS; +} + + +static NTSTATUS +__ipoib_close( + IN DEVICE_OBJECT* const pDevObj, + IN IRP* const pIrp ) +{ + IPOIB_ENTER( IPOIB_DBG_IOCTL ); + + UNREFERENCED_PARAMETER( pDevObj ); + + pIrp->IoStatus.Status = STATUS_SUCCESS; + pIrp->IoStatus.Information = 0; + IoCompleteRequest( pIrp, IO_NO_INCREMENT ); + + IPOIB_EXIT( IPOIB_DBG_IOCTL ); + return STATUS_SUCCESS; +} + + +static NTSTATUS +__ipoib_dispatch( + IN DEVICE_OBJECT* const pDevObj, + IN IRP* const pIrp ) +{ + IO_STACK_LOCATION *pIoStack; + NTSTATUS status = STATUS_SUCCESS; + + IPOIB_ENTER( IPOIB_DBG_IOCTL ); + + UNREFERENCED_PARAMETER( pDevObj ); + + pIoStack = IoGetCurrentIrpStackLocation( pIrp ); + + pIrp->IoStatus.Information = 0; + + switch( pIoStack->Parameters.DeviceIoControl.IoControlCode ) + { + case IOCTL_IBAT_PORTS: + IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_IOCTL, + ("IOCTL_IBAT_PORTS received\n") ); + status = __ibat_get_ports( pIrp, pIoStack ); + break; + + case IOCTL_IBAT_IP_ADDRESSES: + IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_IOCTL, + ("IOCTL_IBAT_IP_ADDRESSES received\n" )); + status = __ibat_get_ips( pIrp, pIoStack ); + break; + + case IOCTL_IBAT_MAC_TO_GID: + IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_IOCTL, + ("IOCTL_IBAT_MAC_TO_GID received\n" )); + status = __ibat_mac_to_gid( pIrp, pIoStack ); + break; + + case IOCTL_IBAT_IP_TO_PORT: + IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_IOCTL, + ("IOCTL_IBAT_IP_TO_PORT received\n" )); + status = __ibat_ip_to_port( pIrp, pIoStack ); + break; + + case IOCTL_IBAT_MAC_TO_PATH: + IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_IOCTL, + ("IOCTL_IBAT_MAC_TO_PATH received\n" )); + status = __ibat_mac_to_path( pIrp, pIoStack ); + break; + + default: + IPOIB_PRINT( TRACE_LEVEL_WARNING, IPOIB_DBG_IOCTL, + ("unknow IOCTL code = 0x%x\n", + pIoStack->Parameters.DeviceIoControl.IoControlCode) ); + status = STATUS_INVALID_PARAMETER; + } + + pIrp->IoStatus.Status = status; + IoCompleteRequest( pIrp, IO_NO_INCREMENT ); + + IPOIB_EXIT( IPOIB_DBG_IOCTL ); + return status; +} + + diff --git a/branches/WOF2-3/ulp/ipoib/kernel/ipoib_ibat.h b/branches/WOF2-3/ulp/ipoib/kernel/ipoib_ibat.h new file mode 100644 index 00000000..83d01951 --- /dev/null +++ b/branches/WOF2-3/ulp/ipoib/kernel/ipoib_ibat.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#ifndef _IPOIB_IBAT_H_ +#define _IPOIB_IBAT_H_ + + +void +ipoib_ref_ibat(); + +void +ipoib_deref_ibat(); + + +#endif /* _IPOIB_IBAT_H_ */ diff --git a/branches/WOF2-3/ulp/ipoib/kernel/ipoib_log.mc b/branches/WOF2-3/ulp/ipoib/kernel/ipoib_log.mc new file mode 100644 index 00000000..193e368a --- /dev/null +++ b/branches/WOF2-3/ulp/ipoib/kernel/ipoib_log.mc @@ -0,0 +1,318 @@ +;/*++ +;============================================================================= +;Copyright (c) 2001 Mellanox Technologies +; +;Module Name: +; +; ipoiblog.mc +; +;Abstract: +; +; IPoIB Driver event log messages +; +;Authors: +; +; Yossi Leybovich +; +;Environment: +; +; Kernel Mode . +; +;============================================================================= +;--*/ +; +MessageIdTypedef = NDIS_ERROR_CODE + +SeverityNames = ( + Success = 0x0:STATUS_SEVERITY_SUCCESS + Informational = 0x1:STATUS_SEVERITY_INFORMATIONAL + Warning = 0x2:STATUS_SEVERITY_WARNING + Error = 0x3:STATUS_SEVERITY_ERROR + ) + +FacilityNames = ( + System = 0x0 + RpcRuntime = 0x2:FACILITY_RPC_RUNTIME + RpcStubs = 0x3:FACILITY_RPC_STUBS + Io = 0x4:FACILITY_IO_ERROR_CODE + IPoIB = 0x7:FACILITY_IPOIB_ERROR_CODE + ) + + +MessageId=0x0001 +Facility=IPoIB +Severity=Warning +SymbolicName=EVENT_IPOIB_PORT_DOWN +Language=English +%2: Network controller link is down. +. + +MessageId=0x0002 +Facility=IPoIB +Severity=Informational +SymbolicName=EVENT_IPOIB_PORT_UP +Language=English +%2: Network controller link is up. +. + + +MessageId=0x0003 +Facility=IPoIB +Severity=Informational +SymbolicName=EVENT_IPOIB_PORT_UP1 +Language=English +%2: Network controller link is up at 2.5Gbps. +. + +MessageId=0x0004 +Facility=IPoIB +Severity=Informational +SymbolicName=EVENT_IPOIB_PORT_UP2 +Language=English +%2: Network controller link is up at 5Gbps. +. + +MessageId=0x0006 +Facility=IPoIB +Severity=Informational +SymbolicName=EVENT_IPOIB_PORT_UP3 +Language=English +%2: Network controller link is up at 10Gbps. +. + +MessageId=0x000a +Facility=IPoIB +Severity=Informational +SymbolicName=EVENT_IPOIB_PORT_UP4 +Language=English +%2: Network controller link is up at 20Gps. +. + +MessageId=0x000e +Facility=IPoIB +Severity=Informational +SymbolicName=EVENT_IPOIB_PORT_UP5 +Language=English +%2: Network controller link is up at 30Gps. +. + +MessageId=0x0012 +Facility=IPoIB +Severity=Informational +SymbolicName=EVENT_IPOIB_PORT_UP6 +Language=English +%2: Network controller link is up at 40Gps. +. + +MessageId=0x001a +Facility=IPoIB +Severity=Informational +SymbolicName=EVENT_IPOIB_PORT_UP7 +Language=English +%2: Network controller link is up at 60Gps. +. + +MessageId=0x0032 +Facility=IPoIB +Severity=Informational +SymbolicName=EVENT_IPOIB_PORT_UP8 +Language=English +%2: Network controller link is up at 120Gps. +. + +MessageId=0x0040 +Facility=IPoIB +Severity=Informational +SymbolicName=EVENT_IPOIB_INIT_SUCCESS +Language=English +%2: Driver Initialized succesfully. +. + +MessageId=0x0041 +Facility=IPoIB +Severity=Error +SymbolicName=EVENT_IPOIB_OPEN_CA +Language=English +%2: Failed to open Channel Adapter. +. + +MessageId=0x0042 +Facility=IPoIB +Severity=Error +SymbolicName=EVENT_IPOIB_ALLOC_PD +Language=English +%2: Failed to allocate Protection Domain. +. + +MessageId=0x0043 +Facility=IPoIB +Severity=Error +SymbolicName=EVENT_IPOIB_CREATE_RECV_CQ +Language=English +%2: Failed to create receive Completion Queue. +. + +MessageId=0x0044 +Facility=IPoIB +Severity=Error +SymbolicName=EVENT_IPOIB_CREATE_SEND_CQ +Language=English +%2: Failed to create send Completion Queue. +. + +MessageId=0x0045 +Facility=IPoIB +Severity=Error +SymbolicName=EVENT_IPOIB_CREATE_QP +Language=English +%2: Failed to create Queue Pair. +. + +MessageId=0x0046 +Facility=IPoIB +Severity=Error +SymbolicName=EVENT_IPOIB_QUERY_QP +Language=English +%2: Failed to get Queue Pair number. +. + +MessageId=0x0047 +Facility=IPoIB +Severity=Error +SymbolicName=EVENT_IPOIB_REG_PHYS +Language=English +%2: Failed to create DMA Memory Region. +. + +MessageId=0x0048 +Facility=IPoIB +Severity=Error +SymbolicName=EVENT_IPOIB_RECV_POOL +Language=English +%2: Failed to create receive descriptor pool. +. + +MessageId=0x0049 +Facility=IPoIB +Severity=Error +SymbolicName=EVENT_IPOIB_RECV_PKT_POOL +Language=English +%2: Failed to create NDIS_PACKET pool for receive indications. +. + +MessageId=0x004A +Facility=IPoIB +Severity=Error +SymbolicName=EVENT_IPOIB_RECV_BUF_POOL +Language=English +%2: Failed to create NDIS_BUFFER pool for receive indications. +. + +MessageId=0x004B +Facility=IPoIB +Severity=Error +SymbolicName=EVENT_IPOIB_SEND_PKT_POOL +Language=English +%2: Failed to create NDIS_PACKET pool for send processing. +. + +MessageId=0x004C +Facility=IPoIB +Severity=Error +SymbolicName=EVENT_IPOIB_SEND_BUF_POOL +Language=English +%2: Failed to create NDIS_BUFFER pool for send processing. +. + +MessageId=0x004D +Facility=IPoIB +Severity=Error +SymbolicName=EVENT_IPOIB_RECV_PKT_ARRAY +Language=English +%2: Failed to allocate receive indication array. +. + +MessageId=0x004E +Facility=IPoIB +Severity=Error +SymbolicName=EVENT_IPOIB_PORT_INFO_TIMEOUT +Language=English +%2: Subnet Administrator query for port information timed out. +Make sure the SA is functioning properly. Increasing the number +of retries and retry timeout adapter parameters may solve the +issue. +. + +MessageId=0x004F +Facility=IPoIB +Severity=Error +SymbolicName=EVENT_IPOIB_PORT_INFO_REJECT +Language=English +%2: Subnet Administrator failed the query for port information. +Make sure the SA is functioning properly and compatible. +. + +MessageId=0x0050 +Facility=IPoIB +Severity=Error +SymbolicName=EVENT_IPOIB_QUERY_PORT_INFO +Language=English +%2: Subnet Administrator query for port information failed. +. + +MessageId=0x0055 +Facility=IPoIB +Severity=Error +SymbolicName=EVENT_IPOIB_BCAST_GET +Language=English +%2: Subnet Administrator failed query for broadcast group information. +. + +MessageId=0x0056 +Facility=IPoIB +Severity=Error +SymbolicName=EVENT_IPOIB_BCAST_JOIN +Language=English +%2: Subnet Administrator failed request to joing broadcast group. +. + +MessageId=0x0057 +Facility=IPoIB +Severity=Error +SymbolicName=EVENT_IPOIB_BCAST_RATE +Language=English +%2: The local port rate is too slow for the existing broadcast MC group. +. + +MessageId=0x0058 +Facility=IPoIB +Severity=Error +SymbolicName=EVENT_IPOIB_WRONG_PARAMETER_ERR +Language=English +%2: Incorrect value or non-existing registry for the required IPoIB parameter %3, overriding it by default value: %4 +. + +MessageId=0x0059 +Facility=IPoIB +Severity=Warning +SymbolicName=EVENT_IPOIB_WRONG_PARAMETER_WRN +Language=English +%2: Incorrect value or non-existing registry entry for the required IPoIB parameter %3, overriding it by default value: %4 +. + +MessageId=0x005A +Facility=IPoIB +Severity=Informational +SymbolicName=EVENT_IPOIB_WRONG_PARAMETER_INFO +Language=English +%2: Incorrect value or non-existing registry for the optional IPoIB parameter %3, overriding it by default value: %4 +. + +MessageId=0x005B +Facility=IPoIB +Severity=Error +SymbolicName=EVENT_IPOIB_PARTITION_ERR +Language=English +%2: Pkey index not found for partition , change switch pkey configuration. +. + diff --git a/branches/WOF2-3/ulp/ipoib/kernel/ipoib_port.c b/branches/WOF2-3/ulp/ipoib/kernel/ipoib_port.c new file mode 100644 index 00000000..4a8290bf --- /dev/null +++ b/branches/WOF2-3/ulp/ipoib/kernel/ipoib_port.c @@ -0,0 +1,6526 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2006 Mellanox Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + +#include "ipoib_port.h" +#include "ipoib_adapter.h" +#include "ipoib_debug.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "ipoib_port.tmh" +#endif +#include + + +/* Amount of physical memory to register. */ +#define MEM_REG_SIZE 0xFFFFFFFFFFFFFFFF + +/* Number of work completions to chain for send and receive polling. */ +#define MAX_SEND_WC 8 +#define MAX_RECV_WC 16 + + +ib_gid_t bcast_mgid_template = { + 0xff, /* multicast field */ + 0x12, /* scope (to be filled in) */ + 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 */ +}; + + +#ifdef _DEBUG_ +/* Handy pointer for debug use. */ +ipoib_port_t *gp_ipoib_port; +#endif + +static void __port_mcast_garbage_dpc(KDPC *p_gc_dpc,void *context,void *s_arg1, void *s_arg2); +static void __port_do_mcast_garbage(ipoib_port_t* const p_port ); + + +/****************************************************************************** +* +* Declarations +* +******************************************************************************/ +static void +__port_construct( + IN ipoib_port_t* const p_port ); + +static ib_api_status_t +__port_init( + IN ipoib_port_t* const p_port, + IN ipoib_adapter_t* const p_adapter, + IN ib_pnp_port_rec_t* const p_pnp_rec ); + +static void +__port_destroying( + IN cl_obj_t* const p_obj ); + +static void +__port_cleanup( + IN cl_obj_t* const p_obj ); + +static void +__port_free( + IN cl_obj_t* const p_obj ); + + +/****************************************************************************** +* +* IB resource manager operations +* +******************************************************************************/ +static void +__ib_mgr_construct( + IN ipoib_port_t* const p_port ); + +static ib_api_status_t +__ib_mgr_init( + IN ipoib_port_t* const p_port ); + +static void +__ib_mgr_destroy( + IN ipoib_port_t* const p_port ); + +static void +__qp_event( + IN ib_async_event_rec_t *p_event_rec ); + +static void +__cq_event( + IN ib_async_event_rec_t *p_event_rec ); + +static ib_api_status_t +__ib_mgr_activate( + IN ipoib_port_t* const p_port ); + +/****************************************************************************** +* +* Buffer manager operations. +* +******************************************************************************/ +static void +__buf_mgr_construct( + IN ipoib_port_t* const p_port ); + +static ib_api_status_t +__buf_mgr_init( + IN ipoib_port_t* const p_port ); + +static void +__buf_mgr_destroy( + IN ipoib_port_t* const p_port ); + +static cl_status_t +__recv_ctor( + IN void* const p_object, + IN void* context, + OUT cl_pool_item_t** const pp_pool_item ); + +#if !IPOIB_INLINE_RECV +static void +__recv_dtor( + IN const cl_pool_item_t* const p_pool_item, + IN void *context ); +#endif /* IPOIB_INLINE_RECV */ + +static inline ipoib_send_desc_t* +__buf_mgr_get_send( + IN ipoib_port_t* const p_port ); + +static inline void +__buf_mgr_put_send( + IN ipoib_port_t* const p_port, + IN ipoib_send_desc_t* const p_desc ); + +static inline ipoib_recv_desc_t* +__buf_mgr_get_recv( + IN ipoib_port_t* const p_port ); + +static inline void +__buf_mgr_put_recv( + IN ipoib_port_t* const p_port, + IN ipoib_recv_desc_t* const p_desc, + IN NDIS_PACKET* const p_packet OPTIONAL ); + +static inline void +__buf_mgr_put_recv_list( + IN ipoib_port_t* const p_port, + IN cl_qlist_t* const p_list ); + +static inline NDIS_PACKET* +__buf_mgr_get_ndis_pkt( + IN ipoib_port_t* const p_port, + IN ipoib_recv_desc_t* const p_desc ); + + +/****************************************************************************** +* +* Receive manager operations. +* +******************************************************************************/ +static void +__recv_mgr_construct( + IN ipoib_port_t* const p_port ); + +static ib_api_status_t +__recv_mgr_init( + IN ipoib_port_t* const p_port ); + +static void +__recv_mgr_destroy( + IN ipoib_port_t* const p_port ); + +/* Posts receive buffers to the receive queue. */ +static ib_api_status_t +__recv_mgr_repost( + IN ipoib_port_t* const p_port ); + +static void +__recv_cb( + IN const ib_cq_handle_t h_cq, + IN void *cq_context ); + +static void +__recv_get_endpts( + IN ipoib_port_t* const p_port, + IN ipoib_recv_desc_t* const p_desc, + IN ib_wc_t* const p_wc, + OUT ipoib_endpt_t** const pp_src, + OUT ipoib_endpt_t** const pp_dst ); + +static int32_t +__recv_mgr_filter( + IN ipoib_port_t* const p_port, + IN ib_wc_t* const p_done_wc_list, + OUT cl_qlist_t* const p_done_list, + OUT cl_qlist_t* const p_bad_list ); + +static ib_api_status_t +__recv_gen( + IN const ipoib_pkt_t* const p_ipoib, + OUT eth_pkt_t* const p_eth, + IN ipoib_endpt_t* const p_src, + IN ipoib_endpt_t* const p_dst ); + +static ib_api_status_t +__recv_dhcp( + IN ipoib_port_t* const p_port, + IN const ipoib_pkt_t* const p_ipoib, + OUT eth_pkt_t* const p_eth, + IN ipoib_endpt_t* const p_src, + IN ipoib_endpt_t* const p_dst ); + +static ib_api_status_t +__recv_arp( + IN ipoib_port_t* const p_port, + IN ib_wc_t* const p_wc, + IN const ipoib_pkt_t* const p_ipoib, + OUT eth_pkt_t* const p_eth, + IN ipoib_endpt_t** const p_src, + IN ipoib_endpt_t* const p_dst ); + +static ib_api_status_t +__recv_mgr_prepare_pkt( + IN ipoib_port_t* const p_port, + IN ipoib_recv_desc_t* const p_desc, + OUT NDIS_PACKET** const pp_packet ); + +static uint32_t +__recv_mgr_build_pkt_array( + IN ipoib_port_t* const p_port, + IN int32_t shortage, + OUT cl_qlist_t* const p_done_list, + OUT int32_t* const p_discarded ); + +/****************************************************************************** +* +* Send manager operations. +* +******************************************************************************/ +static void +__send_mgr_construct( + IN ipoib_port_t* const p_port ); + +static void +__send_mgr_destroy( + IN ipoib_port_t* const p_port ); + +static NDIS_STATUS +__send_gen( + IN ipoib_port_t* const p_port, + IN ipoib_send_desc_t* const p_desc, + IN INT lso_data_index); + +static NDIS_STATUS +__send_mgr_filter_ip( + IN ipoib_port_t* const p_port, + IN const eth_hdr_t* const p_eth_hdr, + IN NDIS_BUFFER* p_buf, + IN size_t buf_len, + IN OUT ipoib_send_desc_t* const p_desc ); + +static NDIS_STATUS +__send_mgr_filter_igmp_v2( + IN ipoib_port_t* const p_port, + IN const ip_hdr_t* const p_ip_hdr, + IN size_t iph_options_size, + IN NDIS_BUFFER* p_buf, + IN size_t buf_len ); + +static NDIS_STATUS +__send_mgr_filter_udp( + IN ipoib_port_t* const p_port, + IN const ip_hdr_t* const p_ip_hdr, + IN NDIS_BUFFER* p_buf, + IN size_t buf_len, + IN OUT ipoib_send_desc_t* const p_desc ); + +static NDIS_STATUS +__send_mgr_filter_dhcp( + IN ipoib_port_t* const p_port, + IN const udp_hdr_t* const p_udp_hdr, + IN NDIS_BUFFER* p_buf, + IN size_t buf_len, + IN OUT ipoib_send_desc_t* const p_desc ); + +static NDIS_STATUS +__send_mgr_filter_arp( + IN ipoib_port_t* const p_port, + IN const eth_hdr_t* const p_eth_hdr, + IN NDIS_BUFFER* p_buf, + IN size_t buf_len, + IN OUT ipoib_send_desc_t* const p_desc ); + +static void +__process_failed_send( + IN ipoib_port_t* const p_port, + IN ipoib_send_desc_t* const p_desc, + IN const NDIS_STATUS status ); + +static void +__send_cb( + IN const ib_cq_handle_t h_cq, + IN void *cq_context ); + +static NDIS_STATUS GetLsoHeaderSize( + IN ipoib_port_t* const pPort, + IN PNDIS_BUFFER CurrBuffer, + IN LsoData *pLsoData, + OUT uint16_t *pSize, + OUT INT *IndexOfData, + IN ipoib_hdr_t *ipoib_hdr + ); + +/****************************************************************************** +* +* Endpoint manager operations +* +******************************************************************************/ +static void +__endpt_mgr_construct( + IN ipoib_port_t* const p_port ); + +static ib_api_status_t +__endpt_mgr_init( + IN ipoib_port_t* const p_port ); + +static void +__endpt_mgr_destroy( + IN ipoib_port_t* const p_port ); + +/****f* IPoIB/__endpt_mgr_remove_all +* NAME +* __endpt_mgr_remove_all +* +* DESCRIPTION +* Removes all enpoints from the port, dereferencing them to initiate +* destruction. +* +* SYNOPSIS +*/ +static void +__endpt_mgr_remove_all( + IN ipoib_port_t* const p_port ); +/* +********/ + +static void +__endpt_mgr_remove( + IN ipoib_port_t* const p_port, + IN ipoib_endpt_t* const p_endpt ); + +static void +__endpt_mgr_reset_all( + IN ipoib_port_t* const p_port ); + +static inline NDIS_STATUS +__endpt_mgr_ref( + IN ipoib_port_t* const p_port, + IN const mac_addr_t mac, + OUT ipoib_endpt_t** const pp_endpt ); + +static inline NDIS_STATUS +__endpt_mgr_get_gid_qpn( + IN ipoib_port_t* const p_port, + IN const mac_addr_t mac, + OUT ib_gid_t* const p_gid, + OUT UNALIGNED net32_t* const p_qpn ); + +static inline ipoib_endpt_t* +__endpt_mgr_get_by_gid( + IN ipoib_port_t* const p_port, + IN const ib_gid_t* const p_gid ); + +static inline ipoib_endpt_t* +__endpt_mgr_get_by_lid( + IN ipoib_port_t* const p_port, + IN const net16_t lid ); + +static inline ib_api_status_t +__endpt_mgr_insert_locked( + IN ipoib_port_t* const p_port, + IN const mac_addr_t mac, + IN ipoib_endpt_t* const p_endpt ); + +static inline ib_api_status_t +__endpt_mgr_insert( + IN ipoib_port_t* const p_port, + IN const mac_addr_t mac, + IN ipoib_endpt_t* const p_endpt ); + +static ib_api_status_t +__endpt_mgr_add_local( + IN ipoib_port_t* const p_port, + IN ib_port_info_t* const p_port_info ); + +static ib_api_status_t +__endpt_mgr_add_bcast( + IN ipoib_port_t* const p_port, + IN ib_mcast_rec_t *p_mcast_rec ); + +/****************************************************************************** +* +* MCast operations. +* +******************************************************************************/ +static ib_api_status_t +__port_get_bcast( + IN ipoib_port_t* const p_port ); + +static ib_api_status_t +__port_join_bcast( + IN ipoib_port_t* const p_port, + IN ib_member_rec_t* const p_member_rec ); + +static ib_api_status_t +__port_create_bcast( + IN ipoib_port_t* const p_port ); + + + +static void +__bcast_get_cb( + IN ib_query_rec_t *p_query_rec ); + + +static void +__bcast_cb( + IN ib_mcast_rec_t *p_mcast_rec ); + + +static void +__mcast_cb( + IN ib_mcast_rec_t *p_mcast_rec ); + +void +__leave_error_mcast_cb( + IN void *context ); + + +static int +__gid_cmp( + IN const void* const p_key1, + IN const void* const p_key2 ) +{ + return cl_memcmp( p_key1, p_key2, sizeof(ib_gid_t) ); +} + + +inline void ipoib_port_ref( ipoib_port_t * p_port, int type ) +{ + cl_obj_ref( &p_port->obj ); +#if DBG + cl_atomic_inc( &p_port->ref[type % ref_mask] ); + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_OBJ, + ("ref type %d ref_cnt %d\n", type, p_port->obj.ref_cnt) ); +#else + UNREFERENCED_PARAMETER(type); +#endif +} + + +inline void ipoib_port_deref(ipoib_port_t * p_port, int type) +{ +#if DBG + cl_atomic_dec( &p_port->ref[type % ref_mask] ); + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_OBJ, + ("deref type %d ref_cnt %d\n", type, p_port->obj.ref_cnt) ); +#else + UNREFERENCED_PARAMETER(type); +#endif + cl_obj_deref( &p_port->obj ); + +} + +/* function returns pointer to payload that is going after IP header. +* asssuming that payload and IP header are in the same buffer +*/ +static void* GetIpPayloadPtr(const ip_hdr_t* const p_ip_hdr) +{ + return (void*)((uint8_t*)p_ip_hdr + 4*(p_ip_hdr->ver_hl & 0xf)); +} + +/****************************************************************************** +* +* Implementation +* +******************************************************************************/ +ib_api_status_t +ipoib_create_port( + IN ipoib_adapter_t* const p_adapter, + IN ib_pnp_port_rec_t* const p_pnp_rec, + OUT ipoib_port_t** const pp_port ) +{ + ib_api_status_t status; + ipoib_port_t *p_port; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + CL_ASSERT( !p_adapter->p_port ); + + p_port = cl_zalloc( sizeof(ipoib_port_t) + + (sizeof(ipoib_hdr_t) * (p_adapter->params.sq_depth - 1)) ); + if( !p_port ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to allocate ipoib_port_t (%d bytes)\n", + sizeof(ipoib_port_t)) ); + return IB_INSUFFICIENT_MEMORY; + } + +#ifdef _DEBUG_ + gp_ipoib_port = p_port; +#endif + + __port_construct( p_port ); + + status = __port_init( p_port, p_adapter, p_pnp_rec ); + if( status != IB_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ipoib_port_init returned %s.\n", + p_adapter->p_ifc->get_err_str( status )) ); + __port_cleanup( &p_port->obj ); + __port_free( &p_port->obj ); + return status; + } + + *pp_port = p_port; + IPOIB_EXIT( IPOIB_DBG_INIT ); + return IB_SUCCESS; +} + + +void +ipoib_port_destroy( + IN ipoib_port_t* const p_port ) +{ + IPOIB_ENTER( IPOIB_DBG_INIT ); + + CL_ASSERT( p_port ); + CL_ASSERT( p_port->p_adapter ); + CL_ASSERT( !p_port->p_adapter->p_port ); + + cl_obj_destroy( &p_port->obj ); + + IPOIB_EXIT( IPOIB_DBG_INIT ); +} + + +static void +__port_construct( + IN ipoib_port_t* const p_port ) +{ + IPOIB_ENTER( IPOIB_DBG_INIT ); + + p_port->state = IB_QPS_RESET; + + cl_obj_construct( &p_port->obj, IPOIB_OBJ_PORT ); + cl_spinlock_construct( &p_port->send_lock ); + cl_spinlock_construct( &p_port->recv_lock ); + __ib_mgr_construct( p_port ); + __buf_mgr_construct( p_port ); + + __recv_mgr_construct( p_port ); + __send_mgr_construct( p_port ); + + __endpt_mgr_construct( p_port ); + + p_port->pPoWorkItem = NULL; + + KeInitializeEvent( &p_port->sa_event, NotificationEvent, TRUE ); + KeInitializeEvent( &p_port->leave_mcast_event, NotificationEvent, TRUE ); + + IPOIB_EXIT( IPOIB_DBG_INIT ); +} + + +static ib_api_status_t +__port_init( + IN ipoib_port_t* const p_port, + IN ipoib_adapter_t* const p_adapter, + IN ib_pnp_port_rec_t* const p_pnp_rec ) +{ + cl_status_t cl_status; + ib_api_status_t status; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + p_port->port_num = p_pnp_rec->p_port_attr->port_num; + p_port->p_adapter = p_adapter; + + p_port->pPoWorkItem = IoAllocateWorkItem(p_adapter->pdo); + if( p_port->pPoWorkItem == NULL ) { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, ("IoAllocateWorkItem returned NULL\n") ); + return IB_ERROR; + } + + cl_status = cl_spinlock_init( &p_port->send_lock ); + if( cl_status != CL_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("cl_spinlock_init returned %#x\n", cl_status) ); + return IB_ERROR; + } + + cl_status = cl_spinlock_init( &p_port->recv_lock ); + if( cl_status != CL_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("cl_spinlock_init returned %#x\n", cl_status) ); + return IB_ERROR; + } + + /* Initialize the IB resource manager. */ + status = __ib_mgr_init( p_port ); + if( status != IB_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("__ib_mgr_init returned %s\n", + p_adapter->p_ifc->get_err_str( status )) ); + return status; + } + + /* Initialize the buffer manager. */ + status = __buf_mgr_init( p_port ); + if( status != IB_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("__buf_mgr_init returned %s\n", + p_adapter->p_ifc->get_err_str( status )) ); + return status; + } + + /* Initialize the receive manager. */ + status = __recv_mgr_init( p_port ); + if( status != IB_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("__recv_mgr_init returned %s\n", + p_adapter->p_ifc->get_err_str( status )) ); + return status; + } + + /* Initialize the endpoint manager. */ + status = __endpt_mgr_init( p_port ); + if( status != IB_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("__endpt_mgr_init returned %s\n", + p_adapter->p_ifc->get_err_str( status )) ); + return status; + } + + /* Initialize multicast garbage collector timer and DPC object */ + KeInitializeDpc(&p_port->gc_dpc,(PKDEFERRED_ROUTINE)__port_mcast_garbage_dpc,p_port); + KeInitializeTimerEx(&p_port->gc_timer,SynchronizationTimer); + + /* We only ever destroy from the PnP callback thread. */ + cl_status = cl_obj_init( &p_port->obj, CL_DESTROY_SYNC, + __port_destroying, __port_cleanup, __port_free ); + +#if DBG + cl_atomic_inc( &p_port->ref[ref_init] ); + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_OBJ, + ("ref type %d ref_cnt %d\n", ref_init, p_port->obj.ref_cnt) ); +#endif + + if( cl_status != CL_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("cl_obj_init returned %#x\n", cl_status) ); + return IB_ERROR; + } + + cl_status = cl_obj_insert_rel( &p_port->rel, &p_adapter->obj, &p_port->obj ); + if( cl_status != CL_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("cl_obj_insert_rel returned %#x\n", cl_status) ); + cl_obj_destroy( &p_port->obj ); + return IB_ERROR; + } + +#if DBG + cl_atomic_inc( &p_port->ref[ref_init] ); + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_OBJ, + ("ref type %d ref_cnt %d\n", ref_init, p_port->obj.ref_cnt) ); +#endif + + IPOIB_EXIT( IPOIB_DBG_INIT ); + return IB_SUCCESS; +} + + +static void +__port_destroying( + IN cl_obj_t* const p_obj ) +{ + ipoib_port_t *p_port; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + CL_ASSERT( p_obj ); + + p_port = PARENT_STRUCT( p_obj, ipoib_port_t, obj ); + + ipoib_port_down( p_port ); + + __endpt_mgr_remove_all( p_port ); + + ipoib_port_resume( p_port ); + + IPOIB_EXIT( IPOIB_DBG_INIT ); +} + + +static void +__port_cleanup( + IN cl_obj_t* const p_obj ) +{ + ipoib_port_t *p_port; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + CL_ASSERT( p_obj ); + + p_port = PARENT_STRUCT( p_obj, ipoib_port_t, obj ); + + /* Wait for all sends and receives to get flushed. */ + while( p_port->send_mgr.depth || p_port->recv_mgr.depth ) + cl_thread_suspend( 0 ); + + /* Destroy the send and receive managers before closing the CA. */ + __ib_mgr_destroy( p_port ); + + IPOIB_EXIT( IPOIB_DBG_INIT ); +} + + +static void +__port_free( + IN cl_obj_t* const p_obj ) +{ + ipoib_port_t *p_port; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + CL_ASSERT( p_obj ); + + p_port = PARENT_STRUCT( p_obj, ipoib_port_t, obj ); + + KeCancelTimer(&p_port->gc_timer); + KeFlushQueuedDpcs(); + __endpt_mgr_destroy( p_port ); + __recv_mgr_destroy( p_port ); + __send_mgr_destroy( p_port ); + __buf_mgr_destroy( p_port ); + + cl_spinlock_destroy( &p_port->send_lock ); + cl_spinlock_destroy( &p_port->recv_lock ); + + cl_obj_deinit( p_obj ); + + IoFreeWorkItem( p_port->pPoWorkItem ); + cl_free( p_port ); + + IPOIB_EXIT( IPOIB_DBG_INIT ); +} + + + +/****************************************************************************** +* +* IB resource manager implementation. +* +******************************************************************************/ +static void +__ib_mgr_construct( + IN ipoib_port_t* const p_port ) +{ + IPOIB_ENTER( IPOIB_DBG_INIT ); + + cl_memclr( &p_port->ib_mgr, sizeof(ipoib_ib_mgr_t) ); + + IPOIB_EXIT( IPOIB_DBG_INIT ); +} + + +static ib_api_status_t +__ib_mgr_init( + IN ipoib_port_t* const p_port ) +{ + ib_api_status_t status; + ib_cq_create_t cq_create; + ib_qp_create_t qp_create; + ib_phys_create_t phys_create; + ib_phys_range_t phys_range; + uint64_t vaddr; + net32_t rkey; + ib_qp_attr_t qp_attr; + ib_ca_attr_t * p_ca_attr; + uint32_t attr_size; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + /* Open the CA. */ + status = p_port->p_adapter->p_ifc->open_ca( + p_port->p_adapter->h_al, p_port->p_adapter->guids.ca_guid, + NULL, p_port, &p_port->ib_mgr.h_ca ); + if( status != IB_SUCCESS ) + { + NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter, + EVENT_IPOIB_OPEN_CA, 1, status ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_open_ca returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + return status; + } + + /* Allocate the PD. */ + status = p_port->p_adapter->p_ifc->alloc_pd( + p_port->ib_mgr.h_ca, IB_PDT_UD, p_port, &p_port->ib_mgr.h_pd ); + if( status != IB_SUCCESS ) + { + NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter, + EVENT_IPOIB_ALLOC_PD, 1, status ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_alloc_pd returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + return status; + } + + /* Allocate receive CQ. */ + cq_create.size = p_port->p_adapter->params.rq_depth; + cq_create.pfn_comp_cb = __recv_cb; + cq_create.h_wait_obj = NULL; + + status = p_port->p_adapter->p_ifc->create_cq( + p_port->ib_mgr.h_ca, &cq_create, p_port, + __cq_event, &p_port->ib_mgr.h_recv_cq ); + if( status != IB_SUCCESS ) + { + NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter, + EVENT_IPOIB_CREATE_RECV_CQ, 1, status ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_create_cq returned %s.\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + return status; + } + + /* Allocate send CQ. */ + cq_create.size = p_port->p_adapter->params.sq_depth; + cq_create.pfn_comp_cb = __send_cb; + + status = p_port->p_adapter->p_ifc->create_cq( + p_port->ib_mgr.h_ca, &cq_create, p_port, + __cq_event, &p_port->ib_mgr.h_send_cq ); + if( status != IB_SUCCESS ) + { + NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter, + EVENT_IPOIB_CREATE_SEND_CQ, 1, status ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_create_cq returned %s.\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + return status; + } + + /* Allocate the QP. */ + cl_memclr( &qp_create, sizeof(qp_create) ); + qp_create.qp_type = IB_QPT_UNRELIABLE_DGRM; + qp_create.rq_depth = p_port->p_adapter->params.rq_depth; + qp_create.rq_sge = 2; /* To support buffers spanning pages. */ + qp_create.h_rq_cq = p_port->ib_mgr.h_recv_cq; + qp_create.sq_depth = p_port->p_adapter->params.sq_depth; + + //Figure out the right number of SGE entries for sends. + /* Get the size of the CA attribute structure. */ + status = p_port->p_adapter->p_ifc->query_ca( p_port->ib_mgr.h_ca, NULL, &attr_size ); + if( status != IB_INSUFFICIENT_MEMORY ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_query_ca failed with status %s.\n", p_port->p_adapter->p_ifc->get_err_str(status)) ); + return status; + } + + /* Allocate enough space to store the attribute structure. */ + p_ca_attr = cl_malloc( attr_size ); + if( !p_ca_attr ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("cl_malloc failed to allocate p_ca_attr!\n") ); + return IB_INSUFFICIENT_RESOURCES; + } + + /* Query the CA attributes. */ + status = p_port->p_adapter->p_ifc->query_ca(p_port->ib_mgr.h_ca, p_ca_attr, &attr_size ); + if( status != IB_SUCCESS ) + { + cl_free( p_ca_attr ); + + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_query_ca failed with status %s.\n", p_port->p_adapter->p_ifc->get_err_str(status)) ); + return status; + } +#define UD_QP_USED_SGE 3 + qp_create.sq_sge = MAX_SEND_SGE < p_ca_attr->max_sges ? MAX_SEND_SGE : (p_ca_attr->max_sges - UD_QP_USED_SGE); + if (!p_ca_attr->ipoib_csum) { + //checksum is not supported by device + //user must specify BYPASS to explicitly cancel checksum calculation + if (p_port->p_adapter->params.send_chksum_offload == CSUM_ENABLED) + p_port->p_adapter->params.send_chksum_offload = CSUM_DISABLED; + if (p_port->p_adapter->params.recv_chksum_offload == CSUM_ENABLED) + p_port->p_adapter->params.recv_chksum_offload = CSUM_DISABLED; + } + cl_free( p_ca_attr ); + + qp_create.h_sq_cq = p_port->ib_mgr.h_send_cq; + qp_create.sq_signaled = TRUE; + status = p_port->p_adapter->p_ifc->create_qp( + p_port->ib_mgr.h_pd, &qp_create, p_port, + __qp_event, &p_port->ib_mgr.h_qp ); + if( status != IB_SUCCESS ) + { + NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter, + EVENT_IPOIB_CREATE_QP, 1, status ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_create_qp returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + return status; + } + /* Query the QP so we can get our QPN. */ + status = p_port->p_adapter->p_ifc->query_qp( + p_port->ib_mgr.h_qp, &qp_attr ); + if( status != IB_SUCCESS ) + { + NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter, + EVENT_IPOIB_QUERY_QP, 1, status ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_query_qp returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + return status; + } + p_port->ib_mgr.qpn = qp_attr.num; + + /* Register all of physical memory */ + phys_create.length = MEM_REG_SIZE; + phys_create.num_ranges = 1; + phys_create.range_array = &phys_range; + phys_create.buf_offset = 0; + phys_create.hca_page_size = PAGE_SIZE; + phys_create.access_ctrl = IB_AC_LOCAL_WRITE; + phys_range.base_addr = 0; + phys_range.size = MEM_REG_SIZE; + vaddr = 0; + status = p_port->p_adapter->p_ifc->reg_phys( + p_port->ib_mgr.h_pd, &phys_create, &vaddr, + &p_port->ib_mgr.lkey, &rkey, &p_port->ib_mgr.h_mr ); + if( status != IB_SUCCESS ) + { + NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter, + EVENT_IPOIB_REG_PHYS, 1, status ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_reg_phys returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + return status; + } + + IPOIB_EXIT( IPOIB_DBG_INIT ); + return IB_SUCCESS; +} + + +static void +__ib_mgr_destroy( + IN ipoib_port_t* const p_port ) +{ + ib_api_status_t status; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + if( p_port->ib_mgr.h_ca ) + { + status = + p_port->p_adapter->p_ifc->close_ca( p_port->ib_mgr.h_ca, NULL ); + CL_ASSERT( status == IB_SUCCESS ); + p_port->ib_mgr.h_ca = NULL; + } + + IPOIB_EXIT( IPOIB_DBG_INIT ); +} + + + +/****************************************************************************** +* +* Buffer manager implementation. +* +******************************************************************************/ +static void +__buf_mgr_construct( + IN ipoib_port_t* const p_port ) +{ + IPOIB_ENTER( IPOIB_DBG_INIT ); + + cl_qpool_construct( &p_port->buf_mgr.recv_pool ); + + p_port->buf_mgr.h_packet_pool = NULL; + p_port->buf_mgr.h_buffer_pool = NULL; + + ExInitializeNPagedLookasideList( &p_port->buf_mgr.send_buf_list, + NULL, NULL, 0, MAX_XFER_BLOCK_SIZE, 'bipi', 0 ); + + p_port->buf_mgr.h_send_pkt_pool = NULL; + p_port->buf_mgr.h_send_buf_pool = NULL; + + IPOIB_EXIT( IPOIB_DBG_INIT ); +} + + +static ib_api_status_t +__buf_mgr_init( + IN ipoib_port_t* const p_port ) +{ + cl_status_t cl_status; + NDIS_STATUS ndis_status; + ipoib_params_t *p_params; + + IPOIB_ENTER(IPOIB_DBG_INIT ); + + CL_ASSERT( p_port ); + CL_ASSERT( p_port->p_adapter ); + + p_params = &p_port->p_adapter->params; + + /* Allocate the receive descriptor pool */ + cl_status = cl_qpool_init( &p_port->buf_mgr.recv_pool, + p_params->rq_depth * p_params->recv_pool_ratio, +#if IPOIB_INLINE_RECV + 0, 0, sizeof(ipoib_recv_desc_t), __recv_ctor, NULL, p_port ); +#else /* IPOIB_INLINE_RECV */ + 0, 0, sizeof(ipoib_recv_desc_t), __recv_ctor, __recv_dtor, p_port ); +#endif /* IPOIB_INLINE_RECV */ + if( cl_status != CL_SUCCESS ) + { + NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter, + EVENT_IPOIB_RECV_POOL, 1, cl_status ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("cl_qpool_init for recvs returned %#x\n", + cl_status) ); + return IB_INSUFFICIENT_MEMORY; + } + + /* Allocate the NDIS buffer and packet pools for receive indication. */ + NdisAllocatePacketPool( &ndis_status, &p_port->buf_mgr.h_packet_pool, + p_params->rq_depth, PROTOCOL_RESERVED_SIZE_IN_PACKET ); + if( ndis_status != NDIS_STATUS_SUCCESS ) + { + NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter, + EVENT_IPOIB_RECV_PKT_POOL, 1, ndis_status ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("NdisAllocatePacketPool returned %08X\n", ndis_status) ); + return IB_INSUFFICIENT_RESOURCES; + } + + NdisAllocateBufferPool( &ndis_status, &p_port->buf_mgr.h_buffer_pool, + p_params->rq_depth ); + if( ndis_status != NDIS_STATUS_SUCCESS ) + { + NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter, + EVENT_IPOIB_RECV_BUF_POOL, 1, ndis_status ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("NdisAllocateBufferPool returned %08X\n", ndis_status) ); + return IB_INSUFFICIENT_RESOURCES; + } + + /* Allocate the NDIS buffer and packet pools for send formatting. */ + NdisAllocatePacketPool( &ndis_status, &p_port->buf_mgr.h_send_pkt_pool, + 1, PROTOCOL_RESERVED_SIZE_IN_PACKET ); + if( ndis_status != NDIS_STATUS_SUCCESS ) + { + NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter, + EVENT_IPOIB_SEND_PKT_POOL, 1, ndis_status ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("NdisAllocatePacketPool returned %08X\n", ndis_status) ); + return IB_INSUFFICIENT_RESOURCES; + } + + NdisAllocateBufferPool( &ndis_status, + &p_port->buf_mgr.h_send_buf_pool, 1 ); + if( ndis_status != NDIS_STATUS_SUCCESS ) + { + NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter, + EVENT_IPOIB_SEND_BUF_POOL, 1, ndis_status ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("NdisAllocateBufferPool returned %08X\n", ndis_status) ); + return IB_INSUFFICIENT_RESOURCES; + } + + IPOIB_EXIT( IPOIB_DBG_INIT ); + return IB_SUCCESS; +} + + +static void +__buf_mgr_destroy( + IN ipoib_port_t* const p_port ) +{ + IPOIB_ENTER(IPOIB_DBG_INIT ); + + CL_ASSERT( p_port ); + + /* Destroy the send packet and buffer pools. */ + if( p_port->buf_mgr.h_send_buf_pool ) + NdisFreeBufferPool( p_port->buf_mgr.h_send_buf_pool ); + if( p_port->buf_mgr.h_send_pkt_pool ) + NdisFreePacketPool( p_port->buf_mgr.h_send_pkt_pool ); + + /* Destroy the receive packet and buffer pools. */ + if( p_port->buf_mgr.h_buffer_pool ) + NdisFreeBufferPool( p_port->buf_mgr.h_buffer_pool ); + if( p_port->buf_mgr.h_packet_pool ) + NdisFreePacketPool( p_port->buf_mgr.h_packet_pool ); + + /* Free the receive and send descriptors. */ + cl_qpool_destroy( &p_port->buf_mgr.recv_pool ); + + /* Free the lookaside list of scratch buffers. */ + ExDeleteNPagedLookasideList( &p_port->buf_mgr.send_buf_list ); + + IPOIB_EXIT( IPOIB_DBG_INIT ); +} + + +static cl_status_t +__recv_ctor( + IN void* const p_object, + IN void* context, + OUT cl_pool_item_t** const pp_pool_item ) +{ + ipoib_recv_desc_t *p_desc; + ipoib_port_t *p_port; + uint32_t ds0_len; + + IPOIB_ENTER( IPOIB_DBG_ALLOC ); + + CL_ASSERT( p_object ); + CL_ASSERT( context ); + + p_desc = (ipoib_recv_desc_t*)p_object; + p_port = (ipoib_port_t*)context; + + /* Setup the work request. */ + p_desc->wr.ds_array = p_desc->local_ds; + p_desc->wr.wr_id = (uintn_t)p_desc; + +#if IPOIB_INLINE_RECV + /* Sanity check on the receive buffer layout */ + CL_ASSERT( (void*)&p_desc->buf.eth.pkt.type == + (void*)&p_desc->buf.ib.pkt.type ); + CL_ASSERT( sizeof(recv_buf_t) == sizeof(ipoib_pkt_t) + sizeof(ib_grh_t) ); + + /* Setup the local data segment. */ + p_desc->local_ds[0].vaddr = cl_get_physaddr( &p_desc->buf ); + p_desc->local_ds[0].lkey = p_port->ib_mgr.lkey; + ds0_len = + PAGE_SIZE - ((uint32_t)p_desc->local_ds[0].vaddr & (PAGE_SIZE - 1)); + if( ds0_len >= sizeof(recv_buf_t) ) + { + /* The whole buffer is within a page. */ + p_desc->local_ds[0].length = ds0_len; + p_desc->wr.num_ds = 1; + } + else + { + /* The buffer crosses page boundaries. */ + p_desc->local_ds[0].length = ds0_len; + p_desc->local_ds[1].vaddr = cl_get_physaddr( + ((uint8_t*)&p_desc->buf) + ds0_len ); + p_desc->local_ds[1].lkey = p_port->ib_mgr.lkey; + p_desc->local_ds[1].length = sizeof(recv_buf_t) - ds0_len; + p_desc->wr.num_ds = 2; + } +#else /* IPOIB_INLINE_RECV */ + /* Allocate the receive buffer. */ + p_desc->p_buf = (recv_buf_t*)cl_zalloc( sizeof(recv_buf_t) ); + if( !p_desc->p_buf ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to allocate receive buffer.\n") ); + return CL_INSUFFICIENT_MEMORY; + } + + /* Sanity check on the receive buffer layout */ + CL_ASSERT( (void*)&p_desc->p_buf->eth.pkt.type == + (void*)&p_desc->p_buf->ib.pkt.type ); + + /* Setup the local data segment. */ + p_desc->local_ds[0].vaddr = cl_get_physaddr( p_desc->p_buf ); + p_desc->local_ds[0].length = sizeof(ipoib_pkt_t) + sizeof(ib_grh_t); + p_desc->local_ds[0].lkey = p_port->ib_mgr.lkey; +#endif /* IPOIB_INLINE_RECV */ + + *pp_pool_item = &p_desc->item; + + IPOIB_EXIT( IPOIB_DBG_ALLOC ); + return CL_SUCCESS; +} + + +#if !IPOIB_INLINE_RECV +static void +__recv_dtor( + IN const cl_pool_item_t* const p_pool_item, + IN void *context ) +{ + ipoib_recv_desc_t *p_desc; + + IPOIB_ENTER( IPOIB_DBG_ALLOC ); + + UNUSED_PARAM( context ); + + p_desc = PARENT_STRUCT( p_pool_item, ipoib_recv_desc_t, item ); + + if( p_desc->p_buf ) + cl_free( p_desc->p_buf ); + + IPOIB_EXIT( IPOIB_DBG_ALLOC ); +} +#endif + + +static inline ipoib_recv_desc_t* +__buf_mgr_get_recv( + IN ipoib_port_t* const p_port ) +{ + ipoib_recv_desc_t *p_desc; + IPOIB_ENTER( IPOIB_DBG_RECV ); + p_desc = (ipoib_recv_desc_t*)cl_qpool_get( &p_port->buf_mgr.recv_pool ); + /* Reference the port object for the send. */ + if( p_desc ) + { + ipoib_port_ref( p_port, ref_get_recv ); + CL_ASSERT( p_desc->wr.wr_id == (uintn_t)p_desc ); +#if IPOIB_INLINE_RECV + CL_ASSERT( p_desc->local_ds[0].vaddr == + cl_get_physaddr( &p_desc->buf ) ); +#else /* IPOIB_INLINE_RECV */ + CL_ASSERT( p_desc->local_ds[0].vaddr == + cl_get_physaddr( p_desc->p_buf ) ); + CL_ASSERT( p_desc->local_ds[0].length == + (sizeof(ipoib_pkt_t) + sizeof(ib_grh_t)) ); +#endif /* IPOIB_INLINE_RECV */ + CL_ASSERT( p_desc->local_ds[0].lkey == p_port->ib_mgr.lkey ); + } + IPOIB_EXIT( IPOIB_DBG_RECV ); + return p_desc; +} + + +static inline void +__buf_mgr_put_recv( + IN ipoib_port_t* const p_port, + IN ipoib_recv_desc_t* const p_desc, + IN NDIS_PACKET* const p_packet OPTIONAL ) +{ + NDIS_BUFFER *p_buf; + + IPOIB_ENTER(IPOIB_DBG_RECV ); + + if( p_packet ) + { + /* Unchain the NDIS buffer. */ + NdisUnchainBufferAtFront( p_packet, &p_buf ); + CL_ASSERT( p_buf ); + /* Return the NDIS packet and NDIS buffer to their pools. */ + NdisDprFreePacketNonInterlocked( p_packet ); + NdisFreeBuffer( p_buf ); + } + + /* Return the descriptor to its pools. */ + cl_qpool_put( &p_port->buf_mgr.recv_pool, &p_desc->item ); + + /* + * Dereference the port object since the receive is no longer outstanding. + */ + ipoib_port_deref( p_port, ref_get_recv ); + IPOIB_EXIT( IPOIB_DBG_RECV ); +} + + +static inline void +__buf_mgr_put_recv_list( + IN ipoib_port_t* const p_port, + IN cl_qlist_t* const p_list ) +{ + //IPOIB_ENTER( IPOIB_DBG_RECV ); + cl_qpool_put_list( &p_port->buf_mgr.recv_pool, p_list ); + //IPOIB_EXIT( IPOIB_DBG_RECV ); +} + + +static inline NDIS_PACKET* +__buf_mgr_get_ndis_pkt( + IN ipoib_port_t* const p_port, + IN ipoib_recv_desc_t* const p_desc ) +{ + NDIS_STATUS status; + NDIS_PACKET *p_packet; + NDIS_BUFFER *p_buffer; + + IPOIB_ENTER( IPOIB_DBG_RECV ); + + NdisDprAllocatePacketNonInterlocked( &status, &p_packet, + p_port->buf_mgr.h_packet_pool ); + if( status != NDIS_STATUS_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to allocate NDIS_PACKET: %08x\n", status) ); + return NULL; + } + + IPOIB_PORT_FROM_PACKET( p_packet ) = p_port; + IPOIB_RECV_FROM_PACKET( p_packet ) = p_desc; + + NdisAllocateBuffer( &status, &p_buffer, +#if IPOIB_INLINE_RECV + p_port->buf_mgr.h_buffer_pool, &p_desc->buf.eth.pkt, p_desc->len ); +#else /* IPOIB_INLINE_RECV */ + p_port->buf_mgr.h_buffer_pool, &p_desc->p_buf->eth.pkt, p_desc->len ); +#endif /* IPOIB_INLINE_RECV */ + if( status != NDIS_STATUS_SUCCESS ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to allocate NDIS_BUFFER: %08x\n", status) ); + NdisDprFreePacketNonInterlocked( p_packet ); + return NULL; + } + + NdisChainBufferAtFront( p_packet, p_buffer ); + NDIS_SET_PACKET_HEADER_SIZE( p_packet, sizeof(eth_hdr_t) ); + + IPOIB_EXIT( IPOIB_DBG_RECV ); + return p_packet; +} + +/****************************************************************************** +* +* Receive manager implementation. +* +******************************************************************************/ +static void +__recv_mgr_construct( + IN ipoib_port_t* const p_port ) +{ + IPOIB_ENTER( IPOIB_DBG_INIT ); + + cl_qlist_init( &p_port->recv_mgr.done_list ); + + p_port->recv_mgr.recv_pkt_array = NULL; + + IPOIB_EXIT( IPOIB_DBG_INIT ); +} + + +static ib_api_status_t +__recv_mgr_init( + IN ipoib_port_t* const p_port ) +{ + IPOIB_ENTER( IPOIB_DBG_INIT ); + + /* Allocate the NDIS_PACKET pointer array for indicating receives. */ + p_port->recv_mgr.recv_pkt_array = cl_malloc( + sizeof(NDIS_PACKET*) * p_port->p_adapter->params.rq_depth ); + if( !p_port->recv_mgr.recv_pkt_array ) + { + NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter, + EVENT_IPOIB_RECV_PKT_ARRAY, 0 ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("cl_malloc for PNDIS_PACKET array failed.\n") ); + return IB_INSUFFICIENT_MEMORY; + } + + IPOIB_EXIT( IPOIB_DBG_INIT ); + return IB_SUCCESS; +} + + +static void +__recv_mgr_destroy( + IN ipoib_port_t* const p_port ) +{ + IPOIB_ENTER( IPOIB_DBG_INIT ); + + CL_ASSERT( cl_is_qlist_empty( &p_port->recv_mgr.done_list ) ); + CL_ASSERT( !p_port->recv_mgr.depth ); + + if( p_port->recv_mgr.recv_pkt_array ) + cl_free( p_port->recv_mgr.recv_pkt_array ); + + IPOIB_EXIT( IPOIB_DBG_INIT ); +} + + +/* + * Posts receive buffers to the receive queue and returns the number + * of receives needed to bring the RQ to its low water mark. Note + * that the value is signed, and can go negative. All tests must + * be for > 0. + */ +static int32_t +__recv_mgr_repost( + IN ipoib_port_t* const p_port ) +{ + ipoib_recv_desc_t *p_head = NULL, *p_tail = NULL, *p_next; + ib_api_status_t status; + ib_recv_wr_t *p_failed; + PERF_DECLARE( GetRecv ); + PERF_DECLARE( PostRecv ); + + IPOIB_ENTER( IPOIB_DBG_RECV ); + + CL_ASSERT( p_port ); + cl_obj_lock( &p_port->obj ); + if( p_port->state != IB_QPS_RTS ) + { + cl_obj_unlock( &p_port->obj ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_RECV, + ("Port in invalid state. Not reposting.\n") ); + return 0; + } + ipoib_port_ref( p_port, ref_repost ); + cl_obj_unlock( &p_port->obj ); + + while( p_port->recv_mgr.depth < p_port->p_adapter->params.rq_depth ) + { + /* Pull receives out of the pool and chain them up. */ + cl_perf_start( GetRecv ); + p_next = __buf_mgr_get_recv( p_port ); + cl_perf_stop( &p_port->p_adapter->perf, GetRecv ); + if( !p_next ) + { + IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_RECV, + ("Out of receive descriptors! recv queue depath 0x%x\n",p_port->recv_mgr.depth) ); + break; + } + + if( !p_tail ) + { + p_tail = p_next; + p_next->wr.p_next = NULL; + } + else + { + p_next->wr.p_next = &p_head->wr; + } + + p_head = p_next; + + p_port->recv_mgr.depth++; + } + + if( p_head ) + { + cl_perf_start( PostRecv ); + status = p_port->p_adapter->p_ifc->post_recv( + p_port->ib_mgr.h_qp, &p_head->wr, &p_failed ); + cl_perf_stop( &p_port->p_adapter->perf, PostRecv ); + + if( status != IB_SUCCESS ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ip_post_recv returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + /* return the descriptors to the pool */ + while( p_failed ) + { + p_head = PARENT_STRUCT( p_failed, ipoib_recv_desc_t, wr ); + p_failed = p_failed->p_next; + + __buf_mgr_put_recv( p_port, p_head, NULL ); + p_port->recv_mgr.depth--; + } + } + } + + ipoib_port_deref( p_port, ref_repost ); + IPOIB_EXIT( IPOIB_DBG_RECV ); + return p_port->p_adapter->params.rq_low_watermark - p_port->recv_mgr.depth; +} + + +void +ipoib_return_packet( + IN NDIS_HANDLE adapter_context, + IN NDIS_PACKET *p_packet ) +{ + cl_list_item_t *p_item; + ipoib_port_t *p_port; + ipoib_recv_desc_t *p_desc; + ib_api_status_t status = IB_NOT_DONE; + int32_t shortage; + PERF_DECLARE( ReturnPacket ); + PERF_DECLARE( ReturnPutRecv ); + PERF_DECLARE( ReturnRepostRecv ); + PERF_DECLARE( ReturnPreparePkt ); + PERF_DECLARE( ReturnNdisIndicate ); + + IPOIB_ENTER( IPOIB_DBG_RECV ); + + UNUSED_PARAM( adapter_context ); + CL_ASSERT( p_packet ); + + cl_perf_start( ReturnPacket ); + + /* Get the port and descriptor from the packet. */ + p_port = IPOIB_PORT_FROM_PACKET( p_packet ); + p_desc = IPOIB_RECV_FROM_PACKET( p_packet ); + + cl_spinlock_acquire( &p_port->recv_lock ); + + cl_perf_start( ReturnPutRecv ); + __buf_mgr_put_recv( p_port, p_desc, p_packet ); + cl_perf_stop( &p_port->p_adapter->perf, ReturnPutRecv ); + + /* Repost buffers. */ + cl_perf_start( ReturnRepostRecv ); + shortage = __recv_mgr_repost( p_port ); + cl_perf_stop( &p_port->p_adapter->perf, ReturnRepostRecv ); + + for( p_item = cl_qlist_remove_head( &p_port->recv_mgr.done_list ); + p_item != cl_qlist_end( &p_port->recv_mgr.done_list ); + p_item = cl_qlist_remove_head( &p_port->recv_mgr.done_list ) ) + { + p_desc = (ipoib_recv_desc_t*)p_item; + + cl_perf_start( ReturnPreparePkt ); + status = __recv_mgr_prepare_pkt( p_port, p_desc, &p_packet ); + cl_perf_stop( &p_port->p_adapter->perf, ReturnPreparePkt ); + if( status == IB_SUCCESS ) + { + if( shortage > 0 ) + NDIS_SET_PACKET_STATUS( p_packet, NDIS_STATUS_RESOURCES ); + else + NDIS_SET_PACKET_STATUS( p_packet, NDIS_STATUS_SUCCESS ); + + cl_spinlock_release( &p_port->recv_lock ); + cl_perf_start( ReturnNdisIndicate ); + NdisMIndicateReceivePacket( p_port->p_adapter->h_adapter, + &p_packet, 1 ); + cl_perf_stop( &p_port->p_adapter->perf, ReturnNdisIndicate ); + cl_spinlock_acquire( &p_port->recv_lock ); + + if( shortage > 0 ) + { + cl_perf_start( ReturnPutRecv ); + __buf_mgr_put_recv( p_port, p_desc, p_packet ); + cl_perf_stop( &p_port->p_adapter->perf, ReturnPutRecv ); + + /* Repost buffers. */ + cl_perf_start( ReturnRepostRecv ); + shortage = __recv_mgr_repost( p_port ); + cl_perf_stop( &p_port->p_adapter->perf, ReturnRepostRecv ); + } + } + else if( status != IB_NOT_DONE ) + { + IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_RECV, + ("__recv_mgr_prepare_pkt returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + /* Return the item to the head of the list. */ + cl_qlist_insert_head( &p_port->recv_mgr.done_list, p_item ); + break; + } + } + cl_spinlock_release( &p_port->recv_lock ); + cl_perf_stop( &p_port->p_adapter->perf, ReturnPacket ); + + IPOIB_EXIT( IPOIB_DBG_RECV ); +} + +static BOOLEAN +__recv_cb_internal( + IN const ib_cq_handle_t h_cq, + IN void *cq_context, + IN uint32_t *p_recv_cnt + ); + + +static void +__iopoib_WorkItem( + IN DEVICE_OBJECT* p_dev_obj, + IN void* context ) +{ + + ipoib_port_t *p_port = ( ipoib_port_t* ) context; + BOOLEAN WorkToDo = TRUE; + KIRQL irql; + uint32_t recv_cnt = 0; + uint32_t total_recv_cnt = 0; + + UNREFERENCED_PARAMETER(p_dev_obj); + + while (WorkToDo && total_recv_cnt < 512) { + irql = KeRaiseIrqlToDpcLevel(); + WorkToDo = __recv_cb_internal(NULL, p_port, &recv_cnt); + KeLowerIrql(irql); + total_recv_cnt += recv_cnt; + } + + if (WorkToDo) { + IoQueueWorkItem( p_port->pPoWorkItem, __iopoib_WorkItem, DelayedWorkQueue, p_port); + } else { + // Release the reference count that was incremented when queued the work item. + ipoib_port_deref( p_port, ref_recv_cb ); + } +} + + +static BOOLEAN +__recv_cb_internal( + IN const ib_cq_handle_t h_cq, + IN void *cq_context, + IN uint32_t* p_recv_cnt) +{ + ipoib_port_t *p_port; + ib_api_status_t status; + ib_wc_t wc[MAX_RECV_WC], *p_free, *p_wc; + int32_t pkt_cnt, recv_cnt = 0, shortage, discarded; + cl_qlist_t done_list, bad_list; + size_t i; + BOOLEAN WorkToDo = FALSE; + + PERF_DECLARE( RecvCompBundle ); + PERF_DECLARE( RecvCb ); + PERF_DECLARE( PollRecv ); + PERF_DECLARE( RepostRecv ); + PERF_DECLARE( FilterRecv ); + PERF_DECLARE( BuildPktArray ); + PERF_DECLARE( RecvNdisIndicate ); + PERF_DECLARE( RearmRecv ); + PERF_DECLARE( PutRecvList ); + + IPOIB_ENTER( IPOIB_DBG_RECV ); + + cl_perf_clr( RecvCompBundle ); + + cl_perf_start( RecvCb ); + + p_port = (ipoib_port_t*)cq_context; + + cl_qlist_init( &done_list ); + cl_qlist_init( &bad_list ); + + ipoib_port_ref( p_port, ref_recv_cb ); + for( i = 0; i < MAX_RECV_WC; i++ ) + wc[i].p_next = &wc[i + 1]; + wc[MAX_RECV_WC - 1].p_next = NULL; + + /* + * We'll be accessing the endpoint map so take a reference + * on it to prevent modifications. + */ + cl_obj_lock( &p_port->obj ); + cl_atomic_inc( &p_port->endpt_rdr ); + cl_obj_unlock( &p_port->obj ); + + do + { + /* If we get here, then the list of WCs is intact. */ + p_free = wc; + + cl_perf_start( PollRecv ); + status = p_port->p_adapter->p_ifc->poll_cq( + p_port->ib_mgr.h_recv_cq, &p_free, &p_wc ); + cl_perf_stop( &p_port->p_adapter->perf, PollRecv ); + CL_ASSERT( status == IB_SUCCESS || status == IB_NOT_FOUND ); + + /* Look at the payload now and filter ARP and DHCP packets. */ + cl_perf_start( FilterRecv ); + recv_cnt += __recv_mgr_filter( p_port, p_wc, &done_list, &bad_list ); + cl_perf_stop( &p_port->p_adapter->perf, FilterRecv ); + + } while( (!p_free) && (recv_cnt < 128)); + + *p_recv_cnt = (uint32_t)recv_cnt; + + /* We're done looking at the endpoint map, release the reference. */ + cl_atomic_dec( &p_port->endpt_rdr ); + + cl_perf_log( &p_port->p_adapter->perf, RecvCompBundle, recv_cnt ); + + cl_spinlock_acquire( &p_port->recv_lock ); + + /* Update our posted depth. */ + p_port->recv_mgr.depth -= recv_cnt; + + /* Return any discarded receives to the pool */ + cl_perf_start( PutRecvList ); + __buf_mgr_put_recv_list( p_port, &bad_list ); + cl_perf_stop( &p_port->p_adapter->perf, PutRecvList ); + + do + { + /* Repost ASAP so we don't starve the RQ. */ + cl_perf_start( RepostRecv ); + shortage = __recv_mgr_repost( p_port ); + cl_perf_stop( &p_port->p_adapter->perf, RepostRecv ); + + cl_perf_start( BuildPktArray ); + /* Notify NDIS of any and all possible receive buffers. */ + pkt_cnt = __recv_mgr_build_pkt_array( + p_port, shortage, &done_list, &discarded ); + cl_perf_stop( &p_port->p_adapter->perf, BuildPktArray ); + + /* Only indicate receives if we actually had any. */ + if( discarded && shortage > 0 ) + { + /* We may have thrown away packets, and have a shortage */ + cl_perf_start( RepostRecv ); + __recv_mgr_repost( p_port ); + cl_perf_stop( &p_port->p_adapter->perf, RepostRecv ); + } + + if( !pkt_cnt ) + break; + + cl_spinlock_release( &p_port->recv_lock ); + + cl_perf_start( RecvNdisIndicate ); + NdisMIndicateReceivePacket( p_port->p_adapter->h_adapter, + p_port->recv_mgr.recv_pkt_array, pkt_cnt ); + cl_perf_stop( &p_port->p_adapter->perf, RecvNdisIndicate ); + + /* + * Cap the number of receives to put back to what we just indicated + * with NDIS_STATUS_RESOURCES. + */ + if( shortage > 0 ) + { + if( pkt_cnt < shortage ) + shortage = pkt_cnt; + + /* Return all but the last packet to the pool. */ + cl_spinlock_acquire( &p_port->recv_lock ); + while( shortage-- > 1 ) + { + __buf_mgr_put_recv( p_port, + IPOIB_RECV_FROM_PACKET( p_port->recv_mgr.recv_pkt_array[shortage] ), + p_port->recv_mgr.recv_pkt_array[shortage] ); + } + cl_spinlock_release( &p_port->recv_lock ); + + /* + * Return the last packet as if NDIS returned it, so that we repost + * and report any other pending receives. + */ + ipoib_return_packet( NULL, p_port->recv_mgr.recv_pkt_array[0] ); + } + cl_spinlock_acquire( &p_port->recv_lock ); + + } while( pkt_cnt ); + cl_spinlock_release( &p_port->recv_lock ); + + if (p_free ) { + /* + * Rearm after filtering to prevent contention on the enpoint maps + * and eliminate the possibility of having a call to + * __endpt_mgr_insert find a duplicate. + */ + ASSERT(WorkToDo == FALSE); + cl_perf_start( RearmRecv ); + status = p_port->p_adapter->p_ifc->rearm_cq( + p_port->ib_mgr.h_recv_cq, FALSE ); + cl_perf_stop( &p_port->p_adapter->perf, RearmRecv ); + CL_ASSERT( status == IB_SUCCESS ); + + } else { + if (h_cq) { + // increment reference to ensure no one release the object while work iteam is queued + ipoib_port_ref( p_port, ref_recv_cb ); + IoQueueWorkItem( p_port->pPoWorkItem, __iopoib_WorkItem, DelayedWorkQueue, p_port); + WorkToDo = FALSE; + } else { + WorkToDo = TRUE; + } + } + ipoib_port_deref( p_port, ref_recv_cb ); + cl_perf_stop( &p_port->p_adapter->perf, RecvCb ); + + IPOIB_EXIT( IPOIB_DBG_RECV ); + return WorkToDo; +} + + +static void +__recv_cb( + IN const ib_cq_handle_t h_cq, + IN void *cq_context ) +{ + uint32_t recv_cnt; + + __recv_cb_internal(h_cq, cq_context, &recv_cnt); +} + + +static void +__recv_get_endpts( + IN ipoib_port_t* const p_port, + IN ipoib_recv_desc_t* const p_desc, + IN ib_wc_t* const p_wc, + OUT ipoib_endpt_t** const pp_src, + OUT ipoib_endpt_t** const pp_dst ) +{ + ib_api_status_t status; + mac_addr_t mac; + PERF_DECLARE( GetEndptByGid ); + PERF_DECLARE( GetEndptByLid ); + PERF_DECLARE( EndptInsert ); + + IPOIB_ENTER( IPOIB_DBG_RECV ); + + /* Setup our shortcut pointers based on whether GRH is valid. */ + if( p_wc->recv.ud.recv_opt & IB_RECV_OPT_GRH_VALID ) + { + /* Lookup the source endpoints based on GID. */ + cl_perf_start( GetEndptByGid ); + *pp_src = +#if IPOIB_INLINE_RECV + __endpt_mgr_get_by_gid( p_port, &p_desc->buf.ib.grh.src_gid ); +#else /* IPOIB_INLINE_RECV */ + __endpt_mgr_get_by_gid( p_port, &p_desc->p_buf->ib.grh.src_gid ); +#endif /* IPOIB_INLINE_RECV */ + cl_perf_stop( &p_port->p_adapter->perf, GetEndptByGid ); + + /* + * Lookup the destination endpoint based on GID. + * This is used along with the packet filter to determine + * whether to report this to NDIS. + */ + cl_perf_start( GetEndptByGid ); + *pp_dst = +#if IPOIB_INLINE_RECV + __endpt_mgr_get_by_gid( p_port, &p_desc->buf.ib.grh.dest_gid ); +#else /* IPOIB_INLINE_RECV */ + __endpt_mgr_get_by_gid( p_port, &p_desc->p_buf->ib.grh.dest_gid ); +#endif /* IPOIB_INLINE_RECV */ + cl_perf_stop( &p_port->p_adapter->perf, GetEndptByGid ); + + /* + * Create the source endpoint if it does not exist. Note that we + * can only do this for globally routed traffic since we need the + * information from the GRH to generate the MAC. + */ + if( !*pp_src ) + { + status = ipoib_mac_from_guid( +#if IPOIB_INLINE_RECV + p_desc->buf.ib.grh.src_gid.unicast.interface_id, p_port->p_adapter->params.guid_mask, &mac ); +#else /* IPOIB_INLINE_RECV */ + p_desc->p_buf->ib.grh.src_gid.unicast.interface_id, p_port->p_adapter->params.guid_mask, &mac ); +#endif /* IPOIB_INLINE_RECV */ + if( status != IB_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ipoib_mac_from_guid returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + return; + } + + /* Create the endpoint. */ +#if IPOIB_INLINE_RECV + *pp_src = ipoib_endpt_create( &p_desc->buf.ib.grh.src_gid, +#else /* IPOIB_INLINE_RECV */ + *pp_src = ipoib_endpt_create( &p_desc->p_buf->ib.grh.src_gid, +#endif /* IPOIB_INLINE_RECV */ + p_wc->recv.ud.remote_lid, p_wc->recv.ud.remote_qp ); + if( !*pp_src ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ipoib_endpt_create failed\n") ); + return; + } + cl_perf_start( EndptInsert ); + cl_obj_lock( &p_port->obj ); + status = __endpt_mgr_insert( p_port, mac, *pp_src ); + if( status != IB_SUCCESS ) + { + cl_obj_unlock( &p_port->obj ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("__endpt_mgr_insert returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + *pp_src = NULL; + return; + } + cl_obj_unlock( &p_port->obj ); + cl_perf_stop( &p_port->p_adapter->perf, EndptInsert ); + } + } + else + { + /* + * Lookup the remote endpoint based on LID. Note that only + * unicast traffic can be LID routed. + */ + cl_perf_start( GetEndptByLid ); + *pp_src = __endpt_mgr_get_by_lid( p_port, p_wc->recv.ud.remote_lid ); + cl_perf_stop( &p_port->p_adapter->perf, GetEndptByLid ); + *pp_dst = p_port->p_local_endpt; + CL_ASSERT( *pp_dst ); + } + + if( *pp_src && !ipoib_is_voltaire_router_gid( &(*pp_src)->dgid ) && + (*pp_src)->qpn != p_wc->recv.ud.remote_qp ) + { + /* Update the QPN for the endpoint. */ + IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_RECV, + ("Updating QPN for MAC: %02X-%02X-%02X-%02X-%02X-%02X\n", + (*pp_src )->mac.addr[0], (*pp_src )->mac.addr[1], + (*pp_src )->mac.addr[2], (*pp_src )->mac.addr[3], + (*pp_src )->mac.addr[4], (*pp_src )->mac.addr[5]) ); + (*pp_src)->qpn = p_wc->recv.ud.remote_qp; + } + + if( *pp_src && *pp_dst ) + { + IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_RECV, + ("Recv:\n" + "\tsrc MAC: %02X-%02X-%02X-%02X-%02X-%02X\n" + "\tdst MAC: %02X-%02X-%02X-%02X-%02X-%02X\n", + (*pp_src )->mac.addr[0], (*pp_src )->mac.addr[1], + (*pp_src )->mac.addr[2], (*pp_src )->mac.addr[3], + (*pp_src )->mac.addr[4], (*pp_src )->mac.addr[5], + (*pp_dst )->mac.addr[0], (*pp_dst )->mac.addr[1], + (*pp_dst )->mac.addr[2], (*pp_dst )->mac.addr[3], + (*pp_dst )->mac.addr[4], (*pp_dst )->mac.addr[5]) ); + } + + IPOIB_EXIT( IPOIB_DBG_RECV ); +} + + +static int32_t +__recv_mgr_filter( + IN ipoib_port_t* const p_port, + IN ib_wc_t* const p_done_wc_list, + OUT cl_qlist_t* const p_done_list, + OUT cl_qlist_t* const p_bad_list ) +{ + ipoib_recv_desc_t *p_desc; + ib_wc_t *p_wc; + ipoib_pkt_t *p_ipoib; + eth_pkt_t *p_eth; + ipoib_endpt_t *p_src, *p_dst; + ib_api_status_t status; + uint32_t len; + int32_t recv_cnt = 0; + PERF_DECLARE( GetRecvEndpts ); + PERF_DECLARE( RecvGen ); + PERF_DECLARE( RecvTcp ); + PERF_DECLARE( RecvUdp ); + PERF_DECLARE( RecvDhcp ); + PERF_DECLARE( RecvArp ); + + IPOIB_ENTER( IPOIB_DBG_RECV ); + + for( p_wc = p_done_wc_list; p_wc; p_wc = p_wc->p_next ) + { + CL_ASSERT( p_wc->status != IB_WCS_SUCCESS || p_wc->wc_type == IB_WC_RECV ); + p_desc = (ipoib_recv_desc_t*)(uintn_t)p_wc->wr_id; + recv_cnt++; + + if( p_wc->status != IB_WCS_SUCCESS ) + { + if( p_wc->status != IB_WCS_WR_FLUSHED_ERR ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed completion %s (vendor specific %#x)\n", + p_port->p_adapter->p_ifc->get_wc_status_str( p_wc->status ), + (int)p_wc->vendor_specific) ); + ipoib_inc_recv_stat( p_port->p_adapter, IP_STAT_ERROR, 0 ); + } + else + { + IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_RECV, + ("Flushed completion %s\n", + p_port->p_adapter->p_ifc->get_wc_status_str( p_wc->status )) ); + ipoib_inc_recv_stat( p_port->p_adapter, IP_STAT_DROPPED, 0 ); + } + cl_qlist_insert_tail( p_bad_list, &p_desc->item.list_item ); + /* Dereference the port object on behalf of the failed receive. */ + ipoib_port_deref( p_port, ref_failed_recv_wc ); + continue; + } + + len = p_wc->length - sizeof(ib_grh_t); + + if( len < sizeof(ipoib_hdr_t) ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Received ETH packet < min size\n") ); + ipoib_inc_recv_stat( p_port->p_adapter, IP_STAT_ERROR, 0 ); + cl_qlist_insert_tail( p_bad_list, &p_desc->item.list_item ); + ipoib_port_deref( p_port, ref_recv_inv_len ); + continue; + } + + if((len - sizeof(ipoib_hdr_t)) > p_port->p_adapter->params.payload_mtu) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Received ETH packet > payload MTU (%d)\n", + p_port->p_adapter->params.payload_mtu) ); + ipoib_inc_recv_stat( p_port->p_adapter, IP_STAT_ERROR, 0 ); + cl_qlist_insert_tail( p_bad_list, &p_desc->item.list_item ); + ipoib_port_deref( p_port, ref_recv_inv_len ); + continue; + + } + /* Successful completion. Get the receive information. */ + p_desc->ndis_csum.Value = ( (p_wc->recv.ud.recv_opt & IB_RECV_OPT_CSUM_MASK ) >> 8 ); + cl_perf_start( GetRecvEndpts ); + __recv_get_endpts( p_port, p_desc, p_wc, &p_src, &p_dst ); + cl_perf_stop( &p_port->p_adapter->perf, GetRecvEndpts ); + +#if IPOIB_INLINE_RECV + p_ipoib = &p_desc->buf.ib.pkt; + p_eth = &p_desc->buf.eth.pkt; +#else /* IPOIB_INLINE_RECV */ + p_ipoib = &p_desc->p_buf->ib.pkt; + p_eth = &p_desc->p_buf->eth.pkt; +#endif /*IPOIB_INLINE_RECV */ + + if( p_src ) + { + /* Don't report loopback traffic - we requested SW loopback. */ + if( !cl_memcmp( &p_port->p_adapter->params.conf_mac, + &p_src->mac, sizeof(p_port->p_adapter->params.conf_mac) ) ) + { + /* + * "This is not the packet you're looking for" - don't update + * receive statistics, the packet never happened. + */ + cl_qlist_insert_tail( p_bad_list, &p_desc->item.list_item ); + /* Dereference the port object on behalf of the failed recv. */ + ipoib_port_deref( p_port, ref_recv_loopback ); + continue; + } + } + + switch( p_ipoib->hdr.type ) + { + case ETH_PROT_TYPE_IP: + if( len < (sizeof(ipoib_hdr_t) + sizeof(ip_hdr_t)) ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Received IP packet < min size\n") ); + status = IB_INVALID_SETTING; + break; + } + + if( p_ipoib->type.ip.hdr.offset || + p_ipoib->type.ip.hdr.prot != IP_PROT_UDP ) + { + /* Unfiltered. Setup the ethernet header and report. */ + cl_perf_start( RecvTcp ); + status = __recv_gen( p_ipoib, p_eth, p_src, p_dst ); + cl_perf_stop( &p_port->p_adapter->perf, RecvTcp ); + break; + } + + /* First packet of a UDP transfer. */ + if( len < + (sizeof(ipoib_hdr_t) + sizeof(ip_hdr_t) + sizeof(udp_hdr_t)) ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Received UDP packet < min size\n") ); + status = IB_INVALID_SETTING; + break; + } + + /* Check if DHCP conversion is required. */ + if( (p_ipoib->type.ip.prot.udp.hdr.dst_port == DHCP_PORT_SERVER && + p_ipoib->type.ip.prot.udp.hdr.src_port == DHCP_PORT_CLIENT) || + (p_ipoib->type.ip.prot.udp.hdr.dst_port == DHCP_PORT_CLIENT && + p_ipoib->type.ip.prot.udp.hdr.src_port == DHCP_PORT_SERVER) || + (p_ipoib->type.ip.prot.udp.hdr.dst_port == DHCP_PORT_PROXY_SERVER && + p_ipoib->type.ip.prot.udp.hdr.src_port == DHCP_PORT_CLIENT) || + (p_ipoib->type.ip.prot.udp.hdr.dst_port == DHCP_PORT_CLIENT && + p_ipoib->type.ip.prot.udp.hdr.src_port == DHCP_PORT_PROXY_SERVER) ) + { + if( len < (sizeof(ipoib_hdr_t) + sizeof(ip_hdr_t) + + sizeof(udp_hdr_t) + DHCP_MIN_SIZE) ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Received DHCP < min size\n") ); + status = IB_INVALID_SETTING; + break; + } + if ((p_ipoib->type.ip.hdr.ver_hl & 0x0f) != 5 ) { + // If there are IP options in this message, we are in trouble in any case + status = IB_INVALID_SETTING; + break; + } + /* UDP packet with BOOTP ports in src/dst port numbers. */ + cl_perf_start( RecvDhcp ); + status = __recv_dhcp( p_port, p_ipoib, p_eth, p_src, p_dst ); + cl_perf_stop( &p_port->p_adapter->perf, RecvDhcp ); + } + else + { + /* Unfiltered. Setup the ethernet header and report. */ + cl_perf_start( RecvUdp ); + status = __recv_gen( p_ipoib, p_eth, p_src, p_dst ); + cl_perf_stop( &p_port->p_adapter->perf, RecvUdp ); + } + break; + + case ETH_PROT_TYPE_ARP: + if( len < (sizeof(ipoib_hdr_t) + sizeof(ipoib_arp_pkt_t)) ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Received ARP < min size\n") ); + status = IB_INVALID_SETTING; + break; + } + cl_perf_start( RecvArp ); + status = __recv_arp( p_port, p_wc, p_ipoib, p_eth, &p_src, p_dst ); + cl_perf_stop( &p_port->p_adapter->perf, RecvArp ); + len = sizeof(ipoib_hdr_t) + sizeof(arp_pkt_t); + break; + + default: + /* Unfiltered. Setup the ethernet header and report. */ + cl_perf_start( RecvGen ); + status = __recv_gen( p_ipoib, p_eth, p_src, p_dst ); + cl_perf_stop( &p_port->p_adapter->perf, RecvGen ); + } + + if( status != IB_SUCCESS ) + { + /* Update stats. */ + ipoib_inc_recv_stat( p_port->p_adapter, IP_STAT_ERROR, 0 ); + cl_qlist_insert_tail( p_bad_list, &p_desc->item.list_item ); + /* Dereference the port object on behalf of the failed receive. */ + ipoib_port_deref( p_port, ref_recv_filter ); + } + else + { + p_desc->len = + len + sizeof(eth_hdr_t) - sizeof(ipoib_hdr_t); + if( p_dst->h_mcast) + { + if( p_dst->dgid.multicast.raw_group_id[10] == 0xFF && + p_dst->dgid.multicast.raw_group_id[11] == 0xFF && + p_dst->dgid.multicast.raw_group_id[12] == 0xFF && + p_dst->dgid.multicast.raw_group_id[13] == 0xFF ) + { + p_desc->type = PKT_TYPE_BCAST; + } + else + { + p_desc->type = PKT_TYPE_MCAST; + } + } + else + { + p_desc->type = PKT_TYPE_UCAST; + + } + cl_qlist_insert_tail( p_done_list, &p_desc->item.list_item ); + } + } + + IPOIB_EXIT( IPOIB_DBG_RECV ); + return recv_cnt; +} + + +static ib_api_status_t +__recv_gen( + IN const ipoib_pkt_t* const p_ipoib, + OUT eth_pkt_t* const p_eth, + IN ipoib_endpt_t* const p_src, + IN ipoib_endpt_t* const p_dst ) +{ + IPOIB_ENTER( IPOIB_DBG_RECV ); + + if( !p_src || !p_dst ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Received packet with no matching endpoints.\n") ); + return IB_NOT_DONE; + } + + /* + * Fill in the ethernet header. Note that doing so will overwrite + * the IPoIB header, so start by moving the information from the IPoIB + * header. + */ + p_eth->hdr.type = p_ipoib->hdr.type; + p_eth->hdr.src = p_src->mac; + p_eth->hdr.dst = p_dst->mac; + + if ( p_eth->hdr.dst.addr[0] == 1 && + p_eth->hdr.type == ETH_PROT_TYPE_IP && + p_eth->hdr.dst.addr[2] == 0x5E) + { + p_eth->hdr.dst.addr[1] = 0; + p_eth->hdr.dst.addr[3] = p_eth->hdr.dst.addr[3] & 0x7f; + } + if (p_dst->h_mcast) + p_dst->is_in_use = TRUE; + + IPOIB_EXIT( IPOIB_DBG_RECV ); + return IB_SUCCESS; +} + + +static ib_api_status_t +__recv_dhcp( + IN ipoib_port_t* const p_port, + IN const ipoib_pkt_t* const p_ipoib, + OUT eth_pkt_t* const p_eth, + IN ipoib_endpt_t* const p_src, + IN ipoib_endpt_t* const p_dst ) +{ + ib_api_status_t status; + dhcp_pkt_t *p_dhcp; + uint8_t *p_option; + uint8_t *p_cid = NULL; + uint8_t msg = 0; + + IPOIB_ENTER( IPOIB_DBG_RECV ); + + UNUSED_PARAM( p_port ); + + /* Create the ethernet header. */ + status = __recv_gen( p_ipoib, p_eth, p_src, p_dst ); + if( status != IB_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("__recv_gen returned %s.\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + return status; + } + + /* Fixup the payload. */ + p_dhcp = &p_eth->type.ip.prot.udp.dhcp; + if( p_dhcp->op != DHCP_REQUEST && p_dhcp->op != DHCP_REPLY ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Invalid DHCP op code.\n") ); + return IB_INVALID_SETTING; + } + + /* + * Find the client identifier option, making sure to skip + * the "magic cookie". + */ + p_option = &p_dhcp->options[0]; + if ( *(uint32_t *)p_option != DHCP_COOKIE ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("DHCP cookie corrupted.\n") ); + return IB_INVALID_PARAMETER; + } + + p_option = &p_dhcp->options[DHCP_COOKIE_SIZE]; + while( *p_option != DHCP_OPT_END && p_option < &p_dhcp->options[312] ) + { + switch( *p_option ) + { + case DHCP_OPT_PAD: + p_option++; + break; + + case DHCP_OPT_MSG: + msg = p_option[2]; + p_option += 3; + break; + + case DHCP_OPT_CLIENT_ID: + p_cid = p_option; + /* Fall through. */ + + default: + /* + * All other options have a length byte following the option code. + * Offset by the length to get to the next option. + */ + p_option += (p_option[1] + 2); + } + } + + switch( msg ) + { + /* message from client */ + case DHCPDISCOVER: + case DHCPREQUEST: + case DHCPDECLINE: + case DHCPRELEASE: + case DHCPINFORM: + if( !p_cid ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to find required Client-identifier option.\n") ); + return IB_INVALID_SETTING; + } + if( p_dhcp->htype != DHCP_HW_TYPE_IB ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Invalid hardware address type.\n") ); + return IB_INVALID_SETTING; + } + break; + /* message from DHCP server */ + case DHCPOFFER: + case DHCPACK: + case DHCPNAK: + break; + + default: + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Invalide message type.\n") ); + return IB_INVALID_PARAMETER; + } + p_eth->type.ip.prot.udp.hdr.chksum = 0; + p_dhcp->htype = DHCP_HW_TYPE_ETH; + p_dhcp->hlen = HW_ADDR_LEN; + + if( p_cid ) /* from client */ + { + /* Validate that the length and type of the option is as required. */ + if( p_cid[1] != 21 ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Client-identifier length not 21 as required.\n") ); + return IB_INVALID_SETTING; + } + if( p_cid[2] != DHCP_HW_TYPE_IB ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Client-identifier type is wrong.\n") ); + return IB_INVALID_SETTING; + } + /* + * Copy the GID value from the option so that we can make aligned + * accesses to the contents. + * Recover CID to standard type. + */ + p_cid[1] = sizeof (ib_net64_t) + 1;// CID length + p_cid[2] = DHCP_HW_TYPE_ETH;// CID type + RtlMoveMemory( &p_cid[3], &p_cid[15], sizeof (ib_net64_t) ); + RtlFillMemory(&p_cid[11], 12, 0); + + RtlCopyMemory( p_dhcp->chaddr, &p_src->mac, sizeof(p_src->mac) ); + RtlFillMemory( &p_dhcp->chaddr[sizeof(p_src->mac)], + ( sizeof(p_dhcp->chaddr) - sizeof(p_src->mac) ), 0 ); + } + IPOIB_EXIT( IPOIB_DBG_RECV ); + return status; +} + + +static ib_api_status_t +__recv_arp( + IN ipoib_port_t* const p_port, + IN ib_wc_t* const p_wc, + IN const ipoib_pkt_t* const p_ipoib, + OUT eth_pkt_t* const p_eth, + IN ipoib_endpt_t** const pp_src, + IN ipoib_endpt_t* const p_dst ) +{ + ib_api_status_t status; + arp_pkt_t *p_arp; + const ipoib_arp_pkt_t *p_ib_arp; + ib_gid_t gid; + mac_addr_t mac; + ipoib_hw_addr_t null_hw = {0}; + + IPOIB_ENTER( IPOIB_DBG_RECV ); + + if( !p_dst ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Unknown destination endpoint\n") ); + return IB_INVALID_SETTING; + } + + p_ib_arp = &p_ipoib->type.arp; + p_arp = &p_eth->type.arp; + + if( p_ib_arp->hw_type != ARP_HW_TYPE_IB ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ARP hardware type is not IB\n") ); + return IB_INVALID_SETTING; + } + + if( p_ib_arp->hw_size != sizeof(ipoib_hw_addr_t) ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ARP hardware address size is not sizeof(ipoib_hw_addr_t)\n") ); + return IB_INVALID_SETTING; + } + + if( p_ib_arp->prot_type != ETH_PROT_TYPE_IP ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ARP protocal type not IP\n") ); + return IB_INVALID_SETTING; + } + + /* + * If we don't have a source, lookup the endpoint specified in the payload. + */ + if( !*pp_src ) + *pp_src = __endpt_mgr_get_by_gid( p_port, &p_ib_arp->src_hw.gid ); + + /* + * If the endpoint exists for the GID, make sure + * the dlid and qpn match the arp. + */ + if( *pp_src ) + { + if( cl_memcmp( &(*pp_src)->dgid, &p_ib_arp->src_hw.gid, + sizeof(ib_gid_t) ) ) + { + /* + * GIDs for the endpoint are different. The ARP must + * have been proxied. Dereference it. + */ + *pp_src = NULL; + } + else if( (*pp_src)->dlid && + (*pp_src)->dlid != p_wc->recv.ud.remote_lid ) + { + /* Out of date! Destroy the endpoint and replace it. */ + __endpt_mgr_remove( p_port, *pp_src ); + *pp_src = NULL; + } + else if ( ! ((*pp_src)->dlid)) { + /* Out of date! Destroy the endpoint and replace it. */ + __endpt_mgr_remove( p_port, *pp_src ); + *pp_src = NULL; + } + else if( ipoib_is_voltaire_router_gid( &(*pp_src)->dgid ) ) + { + if( (*pp_src)->qpn != + (p_ib_arp->src_hw.flags_qpn & CL_HTON32(0x00FFFFFF)) && + p_wc->recv.ud.remote_qp != + (p_ib_arp->src_hw.flags_qpn & CL_HTON32(0x00FFFFFF)) ) + { + /* Out of date! Destroy the endpoint and replace it. */ + __endpt_mgr_remove( p_port, *pp_src ); + *pp_src = NULL; + } + } + else if( (*pp_src)->qpn != p_wc->recv.ud.remote_qp ) + { + /* Out of date! Destroy the endpoint and replace it. */ + __endpt_mgr_remove( p_port, *pp_src ); + *pp_src = NULL; + } + } + + /* Do we need to create an endpoint for this GID? */ + if( !*pp_src ) + { + /* Copy the src GID to allow aligned access */ + cl_memcpy( &gid, &p_ib_arp->src_hw.gid, sizeof(ib_gid_t) ); + status = ipoib_mac_from_guid( gid.unicast.interface_id, p_port->p_adapter->params.guid_mask, &mac ); + if (status == IB_INVALID_GUID_MASK) + { + IPOIB_PRINT( TRACE_LEVEL_WARNING, IPOIB_DBG_ERROR, + ("Invalid GUID mask received, rejecting it") ); + ipoib_create_log(p_port->p_adapter->h_adapter, GUID_MASK_LOG_INDEX, EVENT_IPOIB_WRONG_PARAMETER_WRN); + } + else if( status != IB_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ipoib_mac_from_guid returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + return status; + } + /* + * Create the endpoint. + */ + *pp_src = ipoib_endpt_create( &p_ib_arp->src_hw.gid, + p_wc->recv.ud.remote_lid, (p_ib_arp->src_hw.flags_qpn & CL_HTON32(0x00FFFFFF)) ); + + if( !*pp_src ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ipoib_endpt_create failed\n") ); + return status; + } + + cl_obj_lock( &p_port->obj ); + status = __endpt_mgr_insert( p_port, mac, *pp_src ); + if( status != IB_SUCCESS ) + { + cl_obj_unlock( &p_port->obj ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("__endpt_mgr_insert return %s \n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + return status; + } + + cl_obj_unlock( &p_port->obj ); + } + + CL_ASSERT( !cl_memcmp( + &(*pp_src)->dgid, &p_ib_arp->src_hw.gid, sizeof(ib_gid_t) ) ); + CL_ASSERT( ipoib_is_voltaire_router_gid( &(*pp_src)->dgid ) || + (*pp_src)->qpn == + (p_ib_arp->src_hw.flags_qpn & CL_HTON32(0x00FFFFFF)) ); + /* Now swizzle the data. */ + p_arp->hw_type = ARP_HW_TYPE_ETH; + p_arp->hw_size = sizeof(mac_addr_t); + p_arp->src_hw = (*pp_src)->mac; + p_arp->src_ip = p_ib_arp->src_ip; + + if( cl_memcmp( &p_ib_arp->dst_hw, &null_hw, sizeof(ipoib_hw_addr_t) ) ) + { + if( cl_memcmp( &p_dst->dgid, &p_ib_arp->dst_hw.gid, sizeof(ib_gid_t) ) ) + { + /* + * We received bcast ARP packet that means + * remote port lets everyone know it was changed IP/MAC + * or just activated + */ + + /* Guy: TODO: Check why this check fails in case of Voltaire IPR */ + + if ( !ipoib_is_voltaire_router_gid( &(*pp_src)->dgid ) && + !ib_gid_is_multicast( (const ib_gid_t*)&p_dst->dgid ) ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ARP: is not ARP MCAST\n") ); + return IB_INVALID_SETTING; + } + + p_arp->dst_hw = p_port->p_local_endpt->mac; + p_dst->mac = p_port->p_local_endpt->mac; + /* + * we don't care what receiver ip addr is, + * as long as OS' ARP table is global ??? + */ + p_arp->dst_ip = (net32_t)0; + } + else /* we've got reply to our ARP request */ + { + p_arp->dst_hw = p_dst->mac; + p_arp->dst_ip = p_ib_arp->dst_ip; + CL_ASSERT( p_dst->qpn == + (p_ib_arp->dst_hw.flags_qpn & CL_HTON32(0x00FFFFFF)) ); + } + } + else /* we got ARP reqeust */ + { + cl_memclr( &p_arp->dst_hw, sizeof(mac_addr_t) ); + p_arp->dst_ip = p_ib_arp->dst_ip; + } + + /* + * Create the ethernet header. Note that this is done last so that + * we have a chance to create a new endpoint. + */ + status = __recv_gen( p_ipoib, p_eth, *pp_src, p_dst ); + if( status != IB_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("__recv_gen returned %s.\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + return status; + } + + IPOIB_EXIT( IPOIB_DBG_RECV ); + return IB_SUCCESS; +} + + +static ib_api_status_t +__recv_mgr_prepare_pkt( + IN ipoib_port_t* const p_port, + IN ipoib_recv_desc_t* const p_desc, + OUT NDIS_PACKET** const pp_packet ) +{ + NDIS_STATUS status; + uint32_t pkt_filter; + ip_stat_sel_t type; + NDIS_TCP_IP_CHECKSUM_PACKET_INFO chksum; + + PERF_DECLARE( GetNdisPkt ); + + IPOIB_ENTER( IPOIB_DBG_RECV ); + + pkt_filter = p_port->p_adapter->packet_filter; + /* Check the packet filter. */ + switch( p_desc->type ) + { + default: + case PKT_TYPE_UCAST: + if( pkt_filter & NDIS_PACKET_TYPE_PROMISCUOUS || + pkt_filter & NDIS_PACKET_TYPE_ALL_FUNCTIONAL || + pkt_filter & NDIS_PACKET_TYPE_SOURCE_ROUTING || + pkt_filter & NDIS_PACKET_TYPE_DIRECTED ) + { + /* OK to report. */ + type = IP_STAT_UCAST_BYTES; + status = NDIS_STATUS_SUCCESS; + } + else + { + type = IP_STAT_DROPPED; + status = NDIS_STATUS_FAILURE; + } + break; + case PKT_TYPE_BCAST: + if( pkt_filter & NDIS_PACKET_TYPE_PROMISCUOUS || + pkt_filter & NDIS_PACKET_TYPE_BROADCAST ) + { + /* OK to report. */ + type = IP_STAT_BCAST_BYTES; + status = NDIS_STATUS_SUCCESS; + } + else + { + type = IP_STAT_DROPPED; + status = NDIS_STATUS_FAILURE; + } + break; + case PKT_TYPE_MCAST: + if( pkt_filter & NDIS_PACKET_TYPE_PROMISCUOUS || + pkt_filter & NDIS_PACKET_TYPE_ALL_MULTICAST || + pkt_filter & NDIS_PACKET_TYPE_MULTICAST ) + { + /* OK to report. */ + type = IP_STAT_MCAST_BYTES; + status = NDIS_STATUS_SUCCESS; + } + else + { + type = IP_STAT_DROPPED; + status = NDIS_STATUS_FAILURE; + } + break; + } + + if( status != NDIS_STATUS_SUCCESS ) + { + ipoib_inc_recv_stat( p_port->p_adapter, type, 0 ); + /* Return the receive descriptor to the pool. */ + __buf_mgr_put_recv( p_port, p_desc, NULL ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_RECV, + ("Packet filter doesn't match receive. Dropping.\n") ); + /* + * Return IB_NOT_DONE since the packet has been completed, + * but has not consumed an array entry. + */ + return IB_NOT_DONE; + } + + cl_perf_start( GetNdisPkt ); + *pp_packet = __buf_mgr_get_ndis_pkt( p_port, p_desc ); + cl_perf_stop( &p_port->p_adapter->perf, GetNdisPkt ); + if( !*pp_packet ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("__buf_mgr_get_ndis_pkt failed\n") ); + return IB_INSUFFICIENT_RESOURCES; + } + + chksum.Value = 0; + switch (p_port->p_adapter->params.recv_chksum_offload) { + case CSUM_DISABLED: + NDIS_PER_PACKET_INFO_FROM_PACKET( *pp_packet, TcpIpChecksumPacketInfo ) = + (void*)(uintn_t)chksum.Value; + break; + case CSUM_ENABLED: + /* Get the checksums directly from packet information. */ + /* In this case, no one of cheksum's cat get false value */ + /* If hardware checksum failed or wasn't calculated, NDIS will recalculate it again */ + NDIS_PER_PACKET_INFO_FROM_PACKET( *pp_packet, TcpIpChecksumPacketInfo ) = + (void*)(uintn_t)(p_desc->ndis_csum.Value); + break; + case CSUM_BYPASS: + /* Flag the checksums as having been calculated. */ + chksum.Receive.NdisPacketTcpChecksumSucceeded = TRUE; + chksum.Receive.NdisPacketUdpChecksumSucceeded = TRUE; + chksum.Receive.NdisPacketIpChecksumSucceeded = TRUE; + NDIS_PER_PACKET_INFO_FROM_PACKET( *pp_packet, TcpIpChecksumPacketInfo ) = + (void*)(uintn_t)chksum.Value; + break; + default: + ASSERT(FALSE); + NDIS_PER_PACKET_INFO_FROM_PACKET( *pp_packet, TcpIpChecksumPacketInfo ) = + (void*)(uintn_t)chksum.Value; + } + ipoib_inc_recv_stat( p_port->p_adapter, type, p_desc->len ); + + IPOIB_EXIT( IPOIB_DBG_RECV ); + return IB_SUCCESS; +} + + +static uint32_t +__recv_mgr_build_pkt_array( + IN ipoib_port_t* const p_port, + IN int32_t shortage, + OUT cl_qlist_t* const p_done_list, + OUT int32_t* const p_discarded ) +{ + cl_list_item_t *p_item; + ipoib_recv_desc_t *p_desc; + uint32_t i = 0; + ib_api_status_t status; + PERF_DECLARE( PreparePkt ); + + IPOIB_ENTER( IPOIB_DBG_RECV ); + + *p_discarded = 0; + + /* Move any existing receives to the head to preserve ordering. */ + cl_qlist_insert_list_head( p_done_list, &p_port->recv_mgr.done_list ); + p_item = cl_qlist_remove_head( p_done_list ); + while( p_item != cl_qlist_end( p_done_list ) ) + { + p_desc = (ipoib_recv_desc_t*)p_item; + + cl_perf_start( PreparePkt ); + status = __recv_mgr_prepare_pkt( p_port, p_desc, + &p_port->recv_mgr.recv_pkt_array[i] ); + cl_perf_stop( &p_port->p_adapter->perf, PreparePkt ); + if( status == IB_SUCCESS ) + { + CL_ASSERT( p_port->recv_mgr.recv_pkt_array[i] ); + if( shortage-- > 0 ) + { + NDIS_SET_PACKET_STATUS( + p_port->recv_mgr.recv_pkt_array[i], NDIS_STATUS_RESOURCES ); + } + else + { + NDIS_SET_PACKET_STATUS( + p_port->recv_mgr.recv_pkt_array[i], NDIS_STATUS_SUCCESS ); + } + i++; + } + else if( status == IB_NOT_DONE ) + { + (*p_discarded)++; + } + else + { + IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_RECV, + ("__recv_mgr_prepare_pkt returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + /* Put all completed receives on the port's done list. */ + cl_qlist_insert_tail( &p_port->recv_mgr.done_list, p_item ); + cl_qlist_insert_list_tail( &p_port->recv_mgr.done_list, p_done_list ); + break; + } + + p_item = cl_qlist_remove_head( p_done_list ); + } + + IPOIB_EXIT( IPOIB_DBG_RECV ); + return i; +} + + + + +/****************************************************************************** +* +* Send manager implementation. +* +******************************************************************************/ +static void +__send_mgr_construct( + IN ipoib_port_t* const p_port ) +{ + IPOIB_ENTER( IPOIB_DBG_SEND ); + p_port->send_mgr.depth = 0; + cl_qlist_init( &p_port->send_mgr.pending_list ); + IPOIB_EXIT( IPOIB_DBG_SEND ); +} + + +static void +__pending_list_destroy( + IN ipoib_port_t* const p_port ) +{ + cl_list_item_t *p_item; + NDIS_PACKET *p_packet; + + cl_spinlock_acquire( &p_port->send_lock ); + /* Complete any pending packets. */ + for( p_item = cl_qlist_remove_head( &p_port->send_mgr.pending_list ); + p_item != cl_qlist_end( &p_port->send_mgr.pending_list ); + p_item = cl_qlist_remove_head( &p_port->send_mgr.pending_list ) ) + { + p_packet = IPOIB_PACKET_FROM_LIST_ITEM( p_item ); + NdisMSendCompleteX( p_port->p_adapter->h_adapter, p_packet, + NDIS_STATUS_RESET_IN_PROGRESS ); + } + cl_spinlock_release( &p_port->send_lock ); +} + +static void +__send_mgr_destroy( + IN ipoib_port_t* const p_port ) +{ + IPOIB_ENTER( IPOIB_DBG_SEND ); + __pending_list_destroy(p_port); + + IPOIB_EXIT( IPOIB_DBG_SEND ); +} + + +static NDIS_STATUS +__send_mgr_filter( + IN ipoib_port_t* const p_port, + IN const eth_hdr_t* const p_eth_hdr, + IN NDIS_BUFFER* const p_buf, + IN size_t buf_len, + IN OUT ipoib_send_desc_t* const p_desc ) +{ + NDIS_STATUS status; + + PERF_DECLARE( FilterIp ); + PERF_DECLARE( FilterArp ); + PERF_DECLARE( SendGen ); + + IPOIB_ENTER( IPOIB_DBG_SEND ); + + /* + * We already checked the ethernet header length, so we know it's safe + * to decrement the buf_len without underflowing. + */ + buf_len -= sizeof(eth_hdr_t); + + switch( p_eth_hdr->type ) + { + case ETH_PROT_TYPE_IP: + cl_perf_start( FilterIp ); + status = __send_mgr_filter_ip( + p_port, p_eth_hdr, p_buf, buf_len, p_desc ); + cl_perf_stop( &p_port->p_adapter->perf, FilterIp ); + break; + + case ETH_PROT_TYPE_ARP: + cl_perf_start( FilterArp ); + status = __send_mgr_filter_arp( + p_port, p_eth_hdr, p_buf, buf_len, p_desc ); + cl_perf_stop( &p_port->p_adapter->perf, FilterArp ); + break; + + default: + /* + * The IPoIB spec doesn't define how to send non IP or ARP packets. + * Just send the payload and hope for the best. + */ + cl_perf_start( SendGen ); + status = __send_gen( p_port, p_desc, 0 ); + cl_perf_stop( &p_port->p_adapter->perf, SendGen ); + break; + } + + IPOIB_EXIT( IPOIB_DBG_SEND ); + return status; +} + + +static NDIS_STATUS +__send_copy( + IN ipoib_port_t* const p_port, + IN ipoib_send_desc_t* const p_desc ) +{ + NDIS_PACKET *p_packet; + NDIS_BUFFER *p_buf; + NDIS_STATUS status; + UINT tot_len, bytes_copied = 0; + + IPOIB_ENTER( IPOIB_DBG_SEND ); + + p_desc->p_buf = + ExAllocateFromNPagedLookasideList( &p_port->buf_mgr.send_buf_list ); + if( !p_desc->p_buf ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to allocate buffer for packet copy.\n") ); + return NDIS_STATUS_RESOURCES; + } + + NdisAllocatePacket( &status, &p_packet, p_port->buf_mgr.h_send_pkt_pool ); + if( status != NDIS_STATUS_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_WARNING, IPOIB_DBG_SEND, + ("Failed to allocate NDIS_PACKET for copy.\n") ); + return status; + } + + NdisAllocateBuffer( &status, &p_buf, p_port->buf_mgr.h_send_buf_pool, + p_desc->p_buf, p_port->p_adapter->params.xfer_block_size ); + if( status != NDIS_STATUS_SUCCESS ) + { + NdisFreePacket( p_packet ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_WARNING, IPOIB_DBG_SEND, + ("Failed to allocate NDIS_BUFFER for copy.\n") ); + return status; + } + + NdisChainBufferAtFront( p_packet, p_buf ); + + NdisQueryPacketLength( p_desc->p_pkt, &tot_len ); + + /* Setup the work request. */ + p_desc->local_ds[1].vaddr = cl_get_physaddr( + ((uint8_t*)p_desc->p_buf) + sizeof(eth_hdr_t) ); + p_desc->local_ds[1].length = tot_len - sizeof(eth_hdr_t); + p_desc->local_ds[1].lkey = p_port->ib_mgr.lkey; + p_desc->wr.num_ds = 2; + + /* Copy the packet. */ + NdisCopyFromPacketToPacketSafe( p_packet, bytes_copied, tot_len, + p_desc->p_pkt, bytes_copied, &bytes_copied, + NormalPagePriority ); + + /* Free our temp packet now that the data is copied. */ + NdisUnchainBufferAtFront( p_packet, &p_buf ); + NdisFreeBuffer( p_buf ); + NdisFreePacket( p_packet ); + + if( bytes_copied != tot_len ) + { + /* Something went wrong. Drop the packet. */ + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to copy full packet: %d of %d bytes copied.\n", + bytes_copied, tot_len) ); + return NDIS_STATUS_RESOURCES; + } + + IPOIB_EXIT( IPOIB_DBG_SEND ); + return NDIS_STATUS_SUCCESS; +} + + +#if !IPOIB_USE_DMA +/* Send using the MDL's page information rather than the SGL. */ +static ib_api_status_t +__send_gen( + IN ipoib_port_t* const p_port, + IN ipoib_send_desc_t* const p_desc ) +{ + uint32_t i, j = 1; + ULONG offset; + MDL *p_mdl; + UINT num_pages, tot_len; + ULONG buf_len; + PPFN_NUMBER page_array; + boolean_t hdr_done = FALSE; + ib_api_status_t status; + + IPOIB_ENTER( IPOIB_DBG_SEND ); + + NdisQueryPacket( p_desc->p_pkt, &num_pages, NULL, &p_mdl, + &tot_len ); + + if( !p_mdl ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("No buffers associated with packet.\n") ); + return IB_ERROR; + } + + /* Remember that one of the DS entries is reserved for the IPoIB header. */ + if( num_pages >= MAX_SEND_SGE ) + { + IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_SEND, + ("Too many buffers to fit in WR ds_array. Copying data.\n") ); + status = __send_copy( p_port, p_desc ); + IPOIB_EXIT( IPOIB_DBG_SEND ); + return status; + } + + CL_ASSERT( tot_len > sizeof(eth_hdr_t) ); + CL_ASSERT( tot_len <= p_port->p_adapter->params.xfer_block_size ); + /* + * Assume that the ethernet header is always fully contained + * in the first page of the first MDL. This makes for much + * simpler code. + */ + offset = MmGetMdlByteOffset( p_mdl ) + sizeof(eth_hdr_t); + CL_ASSERT( offset <= PAGE_SIZE ); + + while( tot_len ) + { + buf_len = MmGetMdlByteCount( p_mdl ); + page_array = MmGetMdlPfnArray( p_mdl ); + CL_ASSERT( page_array ); + i = 0; + if( !hdr_done ) + { + CL_ASSERT( buf_len >= sizeof(eth_hdr_t) ); + /* Skip the ethernet header. */ + buf_len -= sizeof(eth_hdr_t); + CL_ASSERT( buf_len <= p_port->p_adapter->params.payload_mtu ); + if( buf_len ) + { + /* The ethernet header is a subset of this MDL. */ + CL_ASSERT( i == 0 ); + if( offset < PAGE_SIZE ) + { + p_desc->local_ds[j].lkey = p_port->ib_mgr.lkey; + p_desc->local_ds[j].vaddr = (page_array[i] << PAGE_SHIFT); + /* Add the byte offset since we're on the 1st page. */ + p_desc->local_ds[j].vaddr += offset; + if( offset + buf_len > PAGE_SIZE ) + { + p_desc->local_ds[j].length = PAGE_SIZE - offset; + buf_len -= p_desc->local_ds[j].length; + } + else + { + p_desc->local_ds[j].length = buf_len; + buf_len = 0; + } + /* This data segment is done. Move to the next. */ + j++; + } + /* This page is done. Move to the next. */ + i++; + } + /* Done handling the ethernet header. */ + hdr_done = TRUE; + } + + /* Finish this MDL */ + while( buf_len ) + { + p_desc->local_ds[j].lkey = p_port->ib_mgr.lkey; + p_desc->local_ds[j].vaddr = (page_array[i] << PAGE_SHIFT); + /* Add the first page's offset if we're on the first page. */ + if( i == 0 ) + p_desc->local_ds[j].vaddr += MmGetMdlByteOffset( p_mdl ); + + if( i == 0 && (MmGetMdlByteOffset( p_mdl ) + buf_len) > PAGE_SIZE ) + { + /* Buffers spans pages. */ + p_desc->local_ds[j].length = + PAGE_SIZE - MmGetMdlByteOffset( p_mdl ); + buf_len -= p_desc->local_ds[j].length; + /* This page is done. Move to the next. */ + i++; + } + else + { + /* Last page of the buffer. */ + p_desc->local_ds[j].length = buf_len; + buf_len = 0; + } + /* This data segment is done. Move to the next. */ + j++; + } + + tot_len -= MmGetMdlByteCount( p_mdl ); + if( !tot_len ) + break; + + NdisGetNextBuffer( p_mdl, &p_mdl ); + if( !p_mdl ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to get next buffer.\n") ); + return IB_ERROR; + } + } + + /* Set the number of data segments. */ + p_desc->wr.num_ds = j; + + IPOIB_EXIT( IPOIB_DBG_SEND ); + return IB_SUCCESS; +} + +#else + +static NDIS_STATUS +__send_gen( + IN ipoib_port_t* const p_port, + IN ipoib_send_desc_t* const p_desc, + IN INT lso_data_index) +{ + ib_api_status_t status; + SCATTER_GATHER_LIST *p_sgl; + uint32_t i, j = 1; + uint32_t offset = sizeof(eth_hdr_t); + PERF_DECLARE( SendCopy ); + + IPOIB_ENTER( IPOIB_DBG_SEND ); + + p_sgl = NDIS_PER_PACKET_INFO_FROM_PACKET( p_desc->p_pkt, + ScatterGatherListPacketInfo ); + if( !p_sgl ) + { + ASSERT( p_sgl ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to get SGL from packet.\n") ); + return NDIS_STATUS_FAILURE; + } + + /* Remember that one of the DS entries is reserved for the IPoIB header. */ + if( ( p_sgl->NumberOfElements >= MAX_SEND_SGE && + p_sgl->Elements[0].Length > sizeof(eth_hdr_t)) || + ( p_sgl->NumberOfElements > MAX_SEND_SGE && + p_sgl->Elements[0].Length <= sizeof(eth_hdr_t)) ) + { + IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_SEND, + ("Too many buffers to fit in WR ds_array. Copying data.\n") ); + cl_perf_start( SendCopy ); + status = __send_copy( p_port, p_desc ); + cl_perf_stop( &p_port->p_adapter->perf, SendCopy ); + IPOIB_EXIT( IPOIB_DBG_SEND ); + return status; + } + + /* + * Skip the ethernet header. It is either the first element, + * or part of it. + */ + i = 0; + if (lso_data_index) { //we have an LSO packet + i = lso_data_index; + j = 0; + } + else while( offset ) + { + if( p_sgl->Elements[i].Length <= offset ) + { + offset -= p_sgl->Elements[i++].Length; + } + else + { + p_desc->local_ds[j].vaddr = + p_sgl->Elements[i].Address.QuadPart + offset; + p_desc->local_ds[j].length = + p_sgl->Elements[i].Length - offset; + p_desc->local_ds[j].lkey = p_port->ib_mgr.lkey; + i++; + j++; + break; + } + } + /* Now fill in the rest of the local data segments. */ + while( i < p_sgl->NumberOfElements ) + { + p_desc->local_ds[j].vaddr = p_sgl->Elements[i].Address.QuadPart; + p_desc->local_ds[j].length = p_sgl->Elements[i].Length; + p_desc->local_ds[j].lkey = p_port->ib_mgr.lkey; + i++; + j++; + } + + /* Set the number of data segments. */ + p_desc->wr.num_ds = j; + + IPOIB_EXIT( IPOIB_DBG_SEND ); + return NDIS_STATUS_SUCCESS; +} +#endif + + +static NDIS_STATUS +__send_mgr_filter_ip( + IN ipoib_port_t* const p_port, + IN const eth_hdr_t* const p_eth_hdr, + IN NDIS_BUFFER* p_buf, + IN size_t buf_len, + IN OUT ipoib_send_desc_t* const p_desc ) +{ + NDIS_STATUS status; + ip_hdr_t *p_ip_hdr; + + PERF_DECLARE( QueryIp ); + PERF_DECLARE( SendTcp ); + PERF_DECLARE( FilterUdp ); + + IPOIB_ENTER( IPOIB_DBG_SEND ); + + if( !buf_len ) + { + cl_perf_start( QueryIp ); + NdisGetNextBuffer( p_buf, &p_buf ); + if( !p_buf ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to get IP header buffer.\n") ); + return NDIS_STATUS_FAILURE; + } + NdisQueryBufferSafe( p_buf, &p_ip_hdr, &buf_len, NormalPagePriority ); + if( !p_ip_hdr ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to query IP header buffer.\n") ); + return NDIS_STATUS_FAILURE; + } + cl_perf_stop( &p_port->p_adapter->perf, QueryIp ); + } + else + { + p_ip_hdr = (ip_hdr_t*)(p_eth_hdr + 1); + } + if( buf_len < sizeof(ip_hdr_t) ) + { + /* This buffer is done for. Get the next buffer. */ + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Buffer too small for IP packet.\n") ); + return NDIS_STATUS_BUFFER_TOO_SHORT; + } + + if( p_ip_hdr->offset || + p_ip_hdr->prot != IP_PROT_UDP ) + { + /* Check if this packet is IGMP */ + if ( p_ip_hdr->prot == IP_PROT_IGMP ) + { + /* + In igmp packet I saw that iph arrive in 2 NDIS_BUFFERs: + 1. iph + 2. ip options + So to get the IGMP packet we need to skip the ip options NDIS_BUFFER + */ + size_t iph_size_in_bytes = (p_ip_hdr->ver_hl & 0xf) * 4; + size_t iph_options_size = iph_size_in_bytes - buf_len; + buf_len -= sizeof(ip_hdr_t);//without ipheader + + /* + Could be a case that arrived igmp packet not from type IGMPv2 , + but IGMPv1 or IGMPv3. + We anyway pass it to __send_mgr_filter_igmp_v2(). + */ + __send_mgr_filter_igmp_v2(p_port, p_ip_hdr, iph_options_size, p_buf, buf_len); + } + /* Not a UDP packet. */ + cl_perf_start( SendTcp ); + status = __send_gen( p_port, p_desc,0 ); + cl_perf_stop( &p_port->p_adapter->perf, SendTcp ); + IPOIB_EXIT( IPOIB_DBG_SEND ); + return status; + } + + buf_len -= sizeof(ip_hdr_t); + + cl_perf_start( FilterUdp ); + status = __send_mgr_filter_udp( + p_port, p_ip_hdr, p_buf, buf_len, p_desc ); + cl_perf_stop( &p_port->p_adapter->perf, FilterUdp ); + + IPOIB_EXIT( IPOIB_DBG_SEND ); + return status; +} + +static NDIS_STATUS +__send_mgr_filter_igmp_v2( + IN ipoib_port_t* const p_port, + IN const ip_hdr_t* const p_ip_hdr, + IN size_t iph_options_size, + IN NDIS_BUFFER* p_buf, + IN size_t buf_len ) +{ + igmp_v2_hdr_t *p_igmp_v2_hdr = NULL; + NDIS_STATUS endpt_status; + ipoib_endpt_t* p_endpt = NULL; + mac_addr_t fake_mcast_mac; + + IPOIB_ENTER( IPOIB_DBG_SEND ); + + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_MCAST, + ("buf_len = %d,iph_options_size = %d\n",(int)buf_len,(int)iph_options_size ) ); + + if( !buf_len ) + { + // To get the IGMP packet we need to skip the ip options NDIS_BUFFER (if exists) + while ( iph_options_size ) + { + NdisGetNextBuffer( p_buf, &p_buf ); + if( !p_buf ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to get IGMPv2 header buffer.\n") ); + return NDIS_STATUS_FAILURE; + } + NdisQueryBufferSafe( p_buf, &p_igmp_v2_hdr, &buf_len, NormalPagePriority ); + if( !p_igmp_v2_hdr ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to query IGMPv2 header buffer.\n") ); + return NDIS_STATUS_FAILURE; + } + iph_options_size-=buf_len; + } + + NdisGetNextBuffer( p_buf, &p_buf ); + if( !p_buf ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to get IGMPv2 header buffer.\n") ); + return NDIS_STATUS_FAILURE; + } + NdisQueryBufferSafe( p_buf, &p_igmp_v2_hdr, &buf_len, NormalPagePriority ); + if( !p_igmp_v2_hdr ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to query IGMPv2 header buffer.\n") ); + return NDIS_STATUS_FAILURE; + } + } + else + { + /* assuming ip header and options are in the same packet */ + p_igmp_v2_hdr = GetIpPayloadPtr(p_ip_hdr); + } + /* Get the IGMP header length. */ + if( buf_len < sizeof(igmp_v2_hdr_t) ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Buffer not large enough for IGMPv2 packet.\n") ); + return NDIS_STATUS_BUFFER_TOO_SHORT; + } + + // build fake mac from igmp packet group address + fake_mcast_mac.addr[0] = 1; + fake_mcast_mac.addr[1] = ((unsigned char*)&p_igmp_v2_hdr->group_address)[0] & 0x0f; + fake_mcast_mac.addr[2] = 0x5E; + fake_mcast_mac.addr[3] = ((unsigned char*)&p_igmp_v2_hdr->group_address)[1]; + fake_mcast_mac.addr[4] = ((unsigned char*)&p_igmp_v2_hdr->group_address)[2]; + fake_mcast_mac.addr[5] = ((unsigned char*)&p_igmp_v2_hdr->group_address)[3]; + + switch ( p_igmp_v2_hdr->type ) + { + case IGMP_V2_MEMBERSHIP_REPORT: + /* + This mean that some body open listener on this group + Change type of mcast endpt to SEND_RECV endpt. So mcast garbage collector + will not delete this mcast endpt. + */ + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_MCAST, + ("Catched IGMP_V2_MEMBERSHIP_REPORT message\n") ); + endpt_status = __endpt_mgr_ref( p_port, fake_mcast_mac, &p_endpt ); + if ( p_endpt ) + { + cl_obj_lock( &p_port->obj ); + p_endpt->is_mcast_listener = TRUE; + cl_obj_unlock( &p_port->obj ); + ipoib_endpt_deref( p_endpt ); + } + break; + + case IGMP_V2_LEAVE_GROUP: + /* + This mean that somebody CLOSE listener on this group . + Change type of mcast endpt to SEND_ONLY endpt. So mcast + garbage collector will delete this mcast endpt next time. + */ + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_MCAST, + ("Catched IGMP_V2_LEAVE_GROUP message\n") ); + endpt_status = __endpt_mgr_ref( p_port, fake_mcast_mac, &p_endpt ); + if ( p_endpt ) + { + cl_obj_lock( &p_port->obj ); + p_endpt->is_mcast_listener = FALSE; + p_endpt->is_in_use = FALSE; + cl_obj_unlock( &p_port->obj ); + ipoib_endpt_deref( p_endpt ); + } + + __port_do_mcast_garbage(p_port); + + break; + + default: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_MCAST, + ("Send Unknown IGMP message: 0x%x \n", p_igmp_v2_hdr->type ) ); + break; + } + + IPOIB_EXIT( IPOIB_DBG_SEND ); + return NDIS_STATUS_SUCCESS; +} + +static NDIS_STATUS +__send_mgr_filter_udp( + IN ipoib_port_t* const p_port, + IN const ip_hdr_t* const p_ip_hdr, + IN NDIS_BUFFER* p_buf, + IN size_t buf_len, + IN OUT ipoib_send_desc_t* const p_desc ) +{ + ib_api_status_t status; + udp_hdr_t *p_udp_hdr; + PERF_DECLARE( QueryUdp ); + PERF_DECLARE( SendUdp ); + PERF_DECLARE( FilterDhcp ); + + IPOIB_ENTER( IPOIB_DBG_SEND ); + + if (p_ip_hdr->offset > 0) { + /* This is a fragmented part of UDP packet + * Only first packet will contain UDP header in such case + * So, return if offset > 0 + */ + cl_perf_start( SendUdp ); + status = __send_gen( p_port, p_desc,0 ); + cl_perf_stop( &p_port->p_adapter->perf, SendUdp ); + IPOIB_EXIT( IPOIB_DBG_SEND ); + return status; + } + + if( !buf_len ) + { + cl_perf_start( QueryUdp ); + NdisGetNextBuffer( p_buf, &p_buf ); + if( !p_buf ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to get UDP header buffer.\n") ); + return NDIS_STATUS_FAILURE; + } + NdisQueryBufferSafe( p_buf, &p_udp_hdr, &buf_len, NormalPagePriority ); + if( !p_udp_hdr ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to query UDP header buffer.\n") ); + return NDIS_STATUS_FAILURE; + } + cl_perf_stop( &p_port->p_adapter->perf, QueryUdp ); + } + else + { + p_udp_hdr = (udp_hdr_t*)GetIpPayloadPtr(p_ip_hdr); + } + + if( buf_len < sizeof(udp_hdr_t) ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Buffer not large enough for UDP packet.\n") ); + return NDIS_STATUS_BUFFER_TOO_SHORT; + } + + /* Get the UDP header and check the destination port numbers. */ + if( (p_udp_hdr->src_port != DHCP_PORT_CLIENT || + p_udp_hdr->dst_port != DHCP_PORT_SERVER) && + (p_udp_hdr->src_port != DHCP_PORT_SERVER || + p_udp_hdr->dst_port != DHCP_PORT_CLIENT) ) + { + /* Not a DHCP packet. */ + cl_perf_start( SendUdp ); + status = __send_gen( p_port, p_desc,0 ); + cl_perf_stop( &p_port->p_adapter->perf, SendUdp ); + IPOIB_EXIT( IPOIB_DBG_SEND ); + return status; + } + + buf_len -= sizeof(udp_hdr_t); + + /* Allocate our scratch buffer. */ + p_desc->p_buf = (send_buf_t*) + ExAllocateFromNPagedLookasideList( &p_port->buf_mgr.send_buf_list ); + if( !p_desc->p_buf ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to query DHCP packet buffer.\n") ); + return NDIS_STATUS_RESOURCES; + } + /* Copy the IP and UDP headers. */ + cl_memcpy( &p_desc->p_buf->ip.hdr, p_ip_hdr , sizeof(ip_hdr_t) ); + cl_memcpy( + &p_desc->p_buf->ip.prot.udp.hdr, p_udp_hdr, sizeof(udp_hdr_t) ); + + cl_perf_start( FilterDhcp ); + status = __send_mgr_filter_dhcp( + p_port, p_udp_hdr, p_buf, buf_len, p_desc ); + cl_perf_stop( &p_port->p_adapter->perf, FilterDhcp ); + + IPOIB_EXIT( IPOIB_DBG_SEND ); + return status; +} + +unsigned short ipchksum(unsigned short *ip, int len) +{ + unsigned long sum = 0; + + len >>= 1; + while (len--) { + sum += *(ip++); + if (sum > 0xFFFF) + sum -= 0xFFFF; + } + return (unsigned short)((~sum) & 0x0000FFFF); +} + +static NDIS_STATUS +__send_mgr_filter_dhcp( + IN ipoib_port_t* const p_port, + IN const udp_hdr_t* const p_udp_hdr, + IN NDIS_BUFFER* p_buf, + IN size_t buf_len, + IN OUT ipoib_send_desc_t* const p_desc ) +{ + dhcp_pkt_t *p_dhcp; + dhcp_pkt_t *p_ib_dhcp; + uint8_t *p_option, *p_cid = NULL; + uint8_t msg = 0; + size_t len; + ib_gid_t gid; + + IPOIB_ENTER( IPOIB_DBG_SEND ); + + if( !buf_len ) + { + NdisGetNextBuffer( p_buf, &p_buf ); + if( !p_buf ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to get DHCP buffer.\n") ); + return NDIS_STATUS_FAILURE; + } + NdisQueryBufferSafe( p_buf, &p_dhcp, &buf_len, NormalPagePriority ); + if( !p_dhcp ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to query DHCP buffer.\n") ); + return NDIS_STATUS_FAILURE; + } + } + else + { + p_dhcp = (dhcp_pkt_t*)(p_udp_hdr + 1); + } + + if( buf_len < DHCP_MIN_SIZE ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Buffer not large enough for DHCP packet.\n") ); + return NDIS_STATUS_BUFFER_TOO_SHORT; + } + + p_ib_dhcp = &p_desc->p_buf->ip.prot.udp.dhcp; + cl_memcpy( p_ib_dhcp, p_dhcp, buf_len ); + + /* Now scan through the options looking for the client identifier. */ + p_option = &p_ib_dhcp->options[4]; + while( *p_option != DHCP_OPT_END && p_option < &p_ib_dhcp->options[312] ) + { + switch( *p_option ) + { + case DHCP_OPT_PAD: + p_option++; + break; + + case DHCP_OPT_MSG: + msg = p_option[2]; + p_option += 3; + break; + + case DHCP_OPT_CLIENT_ID: + p_cid = p_option; + /* Fall through. */ + + default: + /* + * All other options have a length byte following the option code. + * Offset by the length to get to the next option. + */ + p_option += (p_option[1] + 2); + } + } + + switch( msg ) + { + /* Client messages */ + case DHCPDISCOVER: + case DHCPREQUEST: + p_ib_dhcp->flags |= DHCP_FLAGS_BROADCAST; + /* Fall through */ + case DHCPDECLINE: + case DHCPRELEASE: + case DHCPINFORM: + /* Fix up the client identifier option */ + if( p_cid ) + { + /* do we need to replace it ? len eq ETH MAC sz 'and' MAC is mine */ + if( p_cid[1] == HW_ADDR_LEN+1 && !cl_memcmp( &p_cid[3], + &p_port->p_adapter->params.conf_mac.addr, HW_ADDR_LEN ) ) + { + /* Make sure there's room to extend it. 23 is the size of + * the CID option for IPoIB. + */ + if( buf_len + 23 - p_cid[1] > sizeof(dhcp_pkt_t) ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Can't convert CID to IPoIB format.\n") ); + return NDIS_STATUS_RESOURCES; + } + /* Move the existing options down, and add a new CID option */ + len = p_option - ( p_cid + p_cid[1] + 2 ); + p_option = p_cid + p_cid[1] + 2; + RtlMoveMemory( p_cid, p_option, len ); + + p_cid += len; + p_cid[0] = DHCP_OPT_CLIENT_ID; + p_cid[1] = 21; + p_cid[2] = DHCP_HW_TYPE_IB; + } + else + { + ASSERT(FALSE); // Do we ever reach here? does it work correct? + p_cid[2] = DHCP_HW_TYPE_IB; + } + } + else + { + /* + * Make sure there's room to extend it. 23 is the size of + * the CID option for IPoIB. + */ + if( buf_len + 23 > sizeof(dhcp_pkt_t) ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Can't convert CID to IPoIB format.\n") ); + return NDIS_STATUS_RESOURCES; + } + + p_cid = p_option; + p_option = p_cid + 23; + p_option[0] = DHCP_OPT_END; + p_cid[0] = DHCP_OPT_CLIENT_ID; + p_cid[1] = 21; + p_cid[2] = DHCP_HW_TYPE_IB; + } + + CL_ASSERT( p_cid[1] == 21 ); + p_cid[23]= DHCP_OPT_END; + ib_gid_set_default( &gid, p_port->p_adapter->guids.port_guid.guid ); + cl_memcpy( &p_cid[7], &gid, sizeof(ib_gid_t) ); + cl_memcpy( &p_cid[3], &p_port->ib_mgr.qpn, sizeof(p_port->ib_mgr.qpn) ); + p_ib_dhcp->htype = DHCP_HW_TYPE_IB; + + /* update lengths to include any change we made */ + p_desc->p_buf->ip.hdr.length = cl_ntoh16( sizeof(ip_hdr_t) + sizeof(udp_hdr_t) + sizeof(dhcp_pkt_t) ); + p_desc->p_buf->ip.prot.udp.hdr.length = cl_ntoh16( sizeof(udp_hdr_t) + sizeof(dhcp_pkt_t) ); + + /* update crc in ip header */ + p_desc->p_buf->ip.hdr.chksum = 0; + p_desc->p_buf->ip.hdr.chksum = ipchksum((unsigned short*) &p_desc->p_buf->ip.hdr, sizeof(ip_hdr_t)); + break; + + /* Server messages. */ + case DHCPOFFER: + case DHCPACK: + case DHCPNAK: + /* don't touch server messages */ + break; + + default: + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Invalide message type.\n") ); + return NDIS_STATUS_INVALID_DATA; + } + /* no chksum for udp */ + p_desc->p_buf->ip.prot.udp.hdr.chksum = 0; + p_desc->local_ds[1].vaddr = cl_get_physaddr( p_desc->p_buf ); + p_desc->local_ds[1].length = sizeof(ip_hdr_t) + sizeof(udp_hdr_t) + sizeof(dhcp_pkt_t); + p_desc->local_ds[1].lkey = p_port->ib_mgr.lkey; + p_desc->wr.num_ds = 2; + IPOIB_EXIT( IPOIB_DBG_SEND ); + return NDIS_STATUS_SUCCESS; +} + + +static NDIS_STATUS +__send_mgr_filter_arp( + IN ipoib_port_t* const p_port, + IN const eth_hdr_t* const p_eth_hdr, + IN NDIS_BUFFER* p_buf, + IN size_t buf_len, + IN OUT ipoib_send_desc_t* const p_desc ) +{ + arp_pkt_t *p_arp; + ipoib_arp_pkt_t *p_ib_arp; + NDIS_STATUS status; + mac_addr_t null_hw = {0}; + + IPOIB_ENTER( IPOIB_DBG_SEND ); + + if( !buf_len ) + { + NdisGetNextBuffer( p_buf, &p_buf ); + if( !p_buf ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to get ARP buffer.\n") ); + return NDIS_STATUS_FAILURE; + } + NdisQueryBufferSafe( p_buf, &p_arp, &buf_len, NormalPagePriority ); + if( !p_arp ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to get query ARP buffer.\n") ); + return NDIS_STATUS_FAILURE; + } + } + else + { + p_arp = (arp_pkt_t*)(p_eth_hdr + 1); + } + + /* Single buffer ARP packet. */ + if( buf_len < sizeof(arp_pkt_t) ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Buffer too short for ARP.\n") ); + return NDIS_STATUS_BUFFER_TOO_SHORT; + } + + if( p_arp->prot_type != ETH_PROT_TYPE_IP ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Unsupported protocol type.\n") ); + return NDIS_STATUS_INVALID_DATA; + } + + /* Allocate our scratch buffer. */ + p_desc->p_buf = (send_buf_t*) + ExAllocateFromNPagedLookasideList( &p_port->buf_mgr.send_buf_list ); + if( !p_desc->p_buf ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to query ARP packet buffer.\n") ); + return NDIS_STATUS_RESOURCES; + } + p_ib_arp = (ipoib_arp_pkt_t*)p_desc->p_buf; + + /* Convert the ARP payload. */ + p_ib_arp->hw_type = ARP_HW_TYPE_IB; + p_ib_arp->prot_type = p_arp->prot_type; + p_ib_arp->hw_size = sizeof(ipoib_hw_addr_t); + p_ib_arp->prot_size = p_arp->prot_size; + p_ib_arp->op = p_arp->op; + p_ib_arp->src_hw.flags_qpn = p_port->ib_mgr.qpn; + ib_gid_set_default( &p_ib_arp->src_hw.gid, + p_port->p_adapter->guids.port_guid.guid ); + p_ib_arp->src_ip = p_arp->src_ip; + if( cl_memcmp( &p_arp->dst_hw, &null_hw, sizeof(mac_addr_t) ) ) + { + /* Get the endpoint referenced by the dst_hw address. */ + status = __endpt_mgr_get_gid_qpn( p_port, p_arp->dst_hw, + &p_ib_arp->dst_hw.gid, &p_ib_arp->dst_hw.flags_qpn ); + if( status != NDIS_STATUS_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed lookup of destination HW address\n") ); + return status; + } + } + else + { + cl_memclr( &p_ib_arp->dst_hw, sizeof(ipoib_hw_addr_t) ); + } + p_ib_arp->dst_ip = p_arp->dst_ip; + + p_desc->local_ds[1].vaddr = cl_get_physaddr( p_ib_arp ); + p_desc->local_ds[1].length = sizeof(ipoib_arp_pkt_t); + p_desc->local_ds[1].lkey = p_port->ib_mgr.lkey; + p_desc->wr.num_ds = 2; + + IPOIB_EXIT( IPOIB_DBG_SEND ); + return NDIS_STATUS_SUCCESS; +} + + +static inline NDIS_STATUS +__send_mgr_get_eth_hdr( + IN NDIS_PACKET* const p_packet, + OUT NDIS_BUFFER** const pp_buf, + OUT eth_hdr_t** const pp_eth_hdr, + OUT UINT* p_buf_len ) +{ + UINT tot_len; + + IPOIB_ENTER( IPOIB_DBG_SEND ); + + NdisGetFirstBufferFromPacketSafe( + p_packet, pp_buf, pp_eth_hdr, p_buf_len, &tot_len, NormalPagePriority ); + + if( !*pp_eth_hdr ) + { + /* Failed to get first buffer. */ + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("NdisMGetFirstBufferSafe failed.\n") ); + return NDIS_STATUS_FAILURE; + } + + if( *p_buf_len < sizeof(eth_hdr_t) ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("First buffer in packet smaller than eth_hdr_t: %d.\n", + *p_buf_len) ); + return NDIS_STATUS_BUFFER_TOO_SHORT; + } + + IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_SEND, + ("Ethernet header:\n" + "\tsrc MAC: %02X-%02X-%02X-%02X-%02X-%02X\n" + "\tdst MAC: %02X-%02X-%02X-%02X-%02X-%02X\n" + "\tprotocol type: %04X\n", + (*pp_eth_hdr)->src.addr[0], (*pp_eth_hdr)->src.addr[1], + (*pp_eth_hdr)->src.addr[2], (*pp_eth_hdr)->src.addr[3], + (*pp_eth_hdr)->src.addr[4], (*pp_eth_hdr)->src.addr[5], + (*pp_eth_hdr)->dst.addr[0], (*pp_eth_hdr)->dst.addr[1], + (*pp_eth_hdr)->dst.addr[2], (*pp_eth_hdr)->dst.addr[3], + (*pp_eth_hdr)->dst.addr[4], (*pp_eth_hdr)->dst.addr[5], + cl_ntoh16( (*pp_eth_hdr)->type )) ); + + return NDIS_STATUS_SUCCESS; +} + + +static inline NDIS_STATUS +__send_mgr_queue( + IN ipoib_port_t* const p_port, + IN eth_hdr_t* const p_eth_hdr, + OUT ipoib_endpt_t** const pp_endpt ) +{ + NDIS_STATUS status; + + PERF_DECLARE( GetEndpt ); + + IPOIB_ENTER( IPOIB_DBG_SEND ); + + /* Check the send queue and pend the request if not empty. */ + if( cl_qlist_count( &p_port->send_mgr.pending_list ) ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_WARNING, IPOIB_DBG_SEND, + ("Pending list not empty.\n") ); + return NDIS_STATUS_PENDING; + } + + /* Check the send queue and pend the request if not empty. */ + if( p_port->send_mgr.depth == p_port->p_adapter->params.sq_depth ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_WARNING, IPOIB_DBG_SEND, + ("No available WQEs.\n") ); + return NDIS_STATUS_PENDING; + } + + cl_perf_start( GetEndpt ); + status = __endpt_mgr_ref( p_port, p_eth_hdr->dst, pp_endpt ); + cl_perf_stop( &p_port->p_adapter->perf, GetEndpt ); + + if( status == NDIS_STATUS_NO_ROUTE_TO_DESTINATION && + ETH_IS_MULTICAST( p_eth_hdr->dst.addr ) ) + { + if( ipoib_port_join_mcast( p_port, p_eth_hdr->dst, + IB_MC_REC_STATE_FULL_MEMBER) == IB_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_SEND, + ("Multicast Mac - trying to join.\n") ); + return NDIS_STATUS_PENDING; + } + } + else if ( status == NDIS_STATUS_SUCCESS && + ETH_IS_MULTICAST( p_eth_hdr->dst.addr ) && + !ETH_IS_BROADCAST( p_eth_hdr->dst.addr ) ) + { + CL_ASSERT( (*pp_endpt) ); + CL_ASSERT((*pp_endpt)->h_mcast != NULL); + (*pp_endpt)->is_in_use = TRUE; + } + + IPOIB_EXIT( IPOIB_DBG_SEND ); + return status; +} + + +static NDIS_STATUS +__build_send_desc( + IN ipoib_port_t* const p_port, + IN eth_hdr_t* const p_eth_hdr, + IN NDIS_BUFFER* const p_buf, + IN const size_t buf_len, + IN OUT ipoib_send_desc_t* const p_desc ) +{ + NDIS_STATUS status; + int32_t hdr_idx; + PNDIS_PACKET_EXTENSION PktExt; + PNDIS_TCP_IP_CHECKSUM_PACKET_INFO pChecksumPktInfo; //NDIS 5.1 + ULONG mss; + LsoData TheLsoData; + INT IndexOfData = 0; + ULONG PhysBufCount; + ULONG PacketLength; + PNDIS_BUFFER FirstBuffer; + uint16_t lso_header_size; + + + PERF_DECLARE( SendMgrFilter ); + + IPOIB_ENTER( IPOIB_DBG_SEND ); + + /* Format the send descriptor. */ + cl_perf_start( SendMgrFilter ); + + PktExt = NDIS_PACKET_EXTENSION_FROM_PACKET(p_desc->p_pkt); + pChecksumPktInfo = (PNDIS_TCP_IP_CHECKSUM_PACKET_INFO)&PktExt->NdisPacketInfo[TcpIpChecksumPacketInfo]; + mss = PtrToUlong(PktExt->NdisPacketInfo[TcpLargeSendPacketInfo]); + //TODO: optimization: we already got total length from NdisGetFirstBufferFromPacketSafe before + NdisQueryPacket(p_desc->p_pkt, (PUINT)&PhysBufCount, NULL, &FirstBuffer,(PUINT)&PacketLength); + + /* Format the send descriptor. */ + hdr_idx = cl_atomic_inc( &p_port->hdr_idx ); + hdr_idx &= (p_port->p_adapter->params.sq_depth - 1); + ASSERT( hdr_idx < p_port->p_adapter->params.sq_depth ); + p_port->hdr[hdr_idx].type = p_eth_hdr->type; + p_port->hdr[hdr_idx].resv = 0; + + if (mss) + { + memset(&TheLsoData, 0, sizeof TheLsoData ); + status = GetLsoHeaderSize( + p_port, + FirstBuffer, + &TheLsoData, + &lso_header_size, + &IndexOfData, + &p_port->hdr[hdr_idx] + + ); + if ((status != NDIS_STATUS_SUCCESS ) || + (TheLsoData.FullBuffers != TheLsoData.UsedBuffers)) { + ASSERT(FALSE); + + IPOIB_PRINT(TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, ("<-- Throwing this packet\n")); + + //NdisReleaseSpinLock(&Port->SendLock); + //MP_ASSERT_NDIS_PACKET_TYPE(Packet); + //SendComplete(Port, Packet, NDIS_STATUS_INVALID_PACKET); + //NdisAcquireSpinLock(&Port->SendLock); + //IPOIB_PRINT_EXIT + return status; + } + ASSERT(lso_header_size > 0); + p_desc->wr.dgrm.ud.mss = mss; + p_desc->wr.dgrm.ud.header = TheLsoData.LsoBuffers[0].pData; + p_desc->wr.dgrm.ud.hlen = lso_header_size; + // Tell NDIS how much we will send. + PktExt->NdisPacketInfo[TcpLargeSendPacketInfo] = UlongToPtr(PacketLength); + p_desc->wr.send_opt |= (IB_SEND_OPT_TX_IP_CSUM | IB_SEND_OPT_TX_TCP_UDP_CSUM) | IB_SEND_OPT_SIGNALED; + __send_gen(p_port, p_desc, IndexOfData); + p_desc->wr.wr_type = WR_LSO; + } else { + + /* Setup the first local data segment (used for the IPoIB header). */ + p_desc->local_ds[0].vaddr = cl_get_physaddr( &p_port->hdr[hdr_idx] ); + p_desc->local_ds[0].length = sizeof(ipoib_hdr_t); + p_desc->local_ds[0].lkey = p_port->ib_mgr.lkey; + + status = __send_mgr_filter( + p_port, p_eth_hdr, p_buf, buf_len, p_desc); + cl_perf_stop( &p_port->p_adapter->perf, SendMgrFilter ); + if( status != NDIS_STATUS_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("__send_mgr_filter returned 0x%08X.\n", status) ); + return status; + } + p_desc->wr.wr_type = WR_SEND; + p_desc->wr.send_opt = IB_SEND_OPT_SIGNALED; + } + + + + /* Setup the work request. */ + p_desc->wr.p_next = NULL; + p_desc->wr.wr_id = (uintn_t)p_desc->p_pkt; + + if(p_port->p_adapter->params.send_chksum_offload && + (pChecksumPktInfo->Transmit.NdisPacketChecksumV4 || pChecksumPktInfo->Transmit.NdisPacketChecksumV6)) + { + // Set transimition checksum offloading + if (pChecksumPktInfo->Transmit.NdisPacketIpChecksum) + { + p_desc->wr.send_opt |= IB_SEND_OPT_TX_IP_CSUM; + } + if(pChecksumPktInfo->Transmit.NdisPacketTcpChecksum || + pChecksumPktInfo->Transmit.NdisPacketUdpChecksum ) + { + p_desc->wr.send_opt |= IB_SEND_OPT_TX_TCP_UDP_CSUM; + } + } + + p_desc->wr.ds_array = p_desc->local_ds; + + p_desc->wr.dgrm.ud.remote_qp = p_desc->p_endpt1->qpn; + p_desc->wr.dgrm.ud.remote_qkey = p_port->ib_mgr.bcast_rec.qkey; + p_desc->wr.dgrm.ud.h_av = p_desc->p_endpt1->h_av; + p_desc->wr.dgrm.ud.pkey_index = p_port->pkey_index; + p_desc->wr.dgrm.ud.rsvd = NULL; + + /* Store context in our reserved area of the packet. */ + IPOIB_PORT_FROM_PACKET( p_desc->p_pkt ) = p_port; + IPOIB_ENDPT_FROM_PACKET( p_desc->p_pkt ) = p_desc->p_endpt1; + IPOIB_SEND_FROM_PACKET( p_desc->p_pkt ) = p_desc->p_buf; + + IPOIB_EXIT( IPOIB_DBG_SEND ); + return NDIS_STATUS_SUCCESS; +} + + +static inline void +__process_failed_send( + IN ipoib_port_t* const p_port, + IN ipoib_send_desc_t* const p_desc, + IN const NDIS_STATUS status ) +{ + IPOIB_ENTER( IPOIB_DBG_SEND ); + + /* Complete the packet. */ + NdisMSendCompleteX( p_port->p_adapter->h_adapter, + p_desc->p_pkt, status ); + ipoib_inc_send_stat( p_port->p_adapter, IP_STAT_ERROR, 0 ); + /* Deref the endpoint. */ + if( p_desc->p_endpt1 ) + ipoib_endpt_deref( p_desc->p_endpt1 ); + + if( p_desc->p_buf ) + { + ExFreeToNPagedLookasideList( + &p_port->buf_mgr.send_buf_list, p_desc->p_buf ); + } + + IPOIB_EXIT( IPOIB_DBG_SEND ); +} + + +void +ipoib_port_send( + IN ipoib_port_t* const p_port, + IN NDIS_PACKET **p_packet_array, + IN uint32_t num_packets ) +{ + NDIS_STATUS status; + ib_api_status_t ib_status; + ipoib_send_desc_t desc; + uint32_t i; + eth_hdr_t *p_eth_hdr; + NDIS_BUFFER *p_buf; + UINT buf_len; + + PERF_DECLARE( GetEthHdr ); + PERF_DECLARE( BuildSendDesc ); + PERF_DECLARE( QueuePacket ); + PERF_DECLARE( SendMgrQueue ); + PERF_DECLARE( PostSend ); + PERF_DECLARE( ProcessFailedSends ); + + IPOIB_ENTER( IPOIB_DBG_SEND ); + + + cl_obj_lock( &p_port->obj ); + if( p_port->state != IB_QPS_RTS ) + { + cl_obj_unlock( &p_port->obj ); + for( i = 0; i < num_packets; ++i ) + { + ipoib_inc_send_stat( p_port->p_adapter, IP_STAT_DROPPED, 0 ); + /* Complete the packet. */ + NdisMSendCompleteX( p_port->p_adapter->h_adapter, + p_packet_array[i], NDIS_STATUS_ADAPTER_NOT_READY ); + + } + + IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_SEND, + ("Invalid state - Aborting.\n") ); + return; + } + cl_obj_unlock( &p_port->obj ); + + + cl_spinlock_acquire( &p_port->send_lock ); + for( i = 0; i < num_packets; i++ ) + { + desc.p_pkt = p_packet_array[i]; + desc.p_endpt1 = NULL; + desc.p_buf = NULL; + + /* Get the ethernet header so we can find the endpoint. */ + cl_perf_start( GetEthHdr ); + status = __send_mgr_get_eth_hdr( + p_packet_array[i], &p_buf, &p_eth_hdr, &buf_len ); + cl_perf_stop( &p_port->p_adapter->perf, GetEthHdr ); + if( status != NDIS_STATUS_SUCCESS ) + { + cl_perf_start( ProcessFailedSends ); + __process_failed_send( p_port, &desc, status ); + cl_perf_stop( &p_port->p_adapter->perf, ProcessFailedSends ); + continue; + } + + cl_perf_start( SendMgrQueue ); + + if ( ETH_IS_MULTICAST( p_eth_hdr->dst.addr ) && + p_eth_hdr->type == ETH_PROT_TYPE_IP && + !ETH_IS_BROADCAST( p_eth_hdr->dst.addr ) ) + { + ip_hdr_t *p_ip_hdr; + NDIS_BUFFER *p_ip_hdr_buf; + UINT ip_hdr_buf_len; + + // Extract the ip hdr + if(buf_len >= sizeof(ip_hdr_t)+ sizeof(eth_hdr_t)) + { + p_ip_hdr = (ip_hdr_t*)(p_eth_hdr + 1); + ip_hdr_buf_len = sizeof(ip_hdr_t); + } + else + { + NdisGetNextBuffer( p_buf, &p_ip_hdr_buf ); + if( !p_ip_hdr_buf ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to get IP header buffer.\n") ); + goto h_end; + } + + NdisQueryBufferSafe( p_ip_hdr_buf, &p_ip_hdr, &ip_hdr_buf_len, NormalPagePriority ); + if( !p_ip_hdr ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to query IP header buffer.\n") ); + goto h_end; + } + } + + if( ip_hdr_buf_len < sizeof(ip_hdr_t) ) + { + /* This buffer is done for. Get the next buffer. */ + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Buffer too small for IP packet.\n") ); + goto h_end; + } + + p_eth_hdr->dst.addr[1] = ((unsigned char*)&p_ip_hdr->dst_ip)[0] & 0x0f; + p_eth_hdr->dst.addr[3] = ((unsigned char*)&p_ip_hdr->dst_ip)[1]; + } +h_end: + status = __send_mgr_queue( p_port, p_eth_hdr, &desc.p_endpt1 ); + cl_perf_stop( &p_port->p_adapter->perf, SendMgrQueue ); + if( status == NDIS_STATUS_PENDING ) + { + /* Queue all remaining packets. */ + cl_perf_start( QueuePacket ); + while( i < num_packets ) + { + cl_qlist_insert_tail( &p_port->send_mgr.pending_list, + IPOIB_LIST_ITEM_FROM_PACKET( p_packet_array[i++] ) ); + } + cl_perf_stop( &p_port->p_adapter->perf, QueuePacket ); + break; + } + if( status != NDIS_STATUS_SUCCESS ) + { + ASSERT( status == NDIS_STATUS_NO_ROUTE_TO_DESTINATION ); + /* + * Complete the send as if we sent it - WHQL tests don't like the + * sends to fail. + */ + cl_perf_start( ProcessFailedSends ); + __process_failed_send( p_port, &desc, NDIS_STATUS_SUCCESS ); + cl_perf_stop( &p_port->p_adapter->perf, ProcessFailedSends ); + continue; + } + + cl_perf_start( BuildSendDesc ); + status = __build_send_desc( p_port, p_eth_hdr, p_buf, buf_len, &desc ); + cl_perf_stop( &p_port->p_adapter->perf, BuildSendDesc ); + if( status != NDIS_STATUS_SUCCESS ) + { + cl_perf_start( ProcessFailedSends ); + __process_failed_send( p_port, &desc, status ); + cl_perf_stop( &p_port->p_adapter->perf, ProcessFailedSends ); + continue; + } + + /* Post the WR. */ + cl_perf_start( PostSend ); + ib_status = p_port->p_adapter->p_ifc->post_send( p_port->ib_mgr.h_qp, &desc.wr, NULL ); + cl_perf_stop( &p_port->p_adapter->perf, PostSend ); + if( ib_status != IB_SUCCESS ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_post_send returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( ib_status )) ); + cl_perf_start( ProcessFailedSends ); + __process_failed_send( p_port, &desc, NDIS_STATUS_FAILURE ); + cl_perf_stop( &p_port->p_adapter->perf, ProcessFailedSends ); + /* Flag the adapter as hung since posting is busted. */ + p_port->p_adapter->hung = TRUE; + continue; + } + + cl_atomic_inc( &p_port->send_mgr.depth ); + } + cl_spinlock_release( &p_port->send_lock ); + + IPOIB_EXIT( IPOIB_DBG_SEND ); +} + + +void +ipoib_port_resume( + IN ipoib_port_t* const p_port ) +{ + NDIS_STATUS status; + ib_api_status_t ib_status; + cl_list_item_t *p_item; + ipoib_send_desc_t desc; + eth_hdr_t *p_eth_hdr; + NDIS_BUFFER *p_buf; + UINT buf_len; + + PERF_DECLARE( GetEndpt ); + PERF_DECLARE( BuildSendDesc ); + PERF_DECLARE( ProcessFailedSends ); + PERF_DECLARE( PostSend ); + + IPOIB_ENTER( IPOIB_DBG_SEND ); + + + cl_obj_lock( &p_port->obj ); + if( p_port->state != IB_QPS_RTS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_WARNING, IPOIB_DBG_SEND, + ("Invalid state - Aborting.\n") ); + cl_obj_unlock( &p_port->obj ); + return; + } + cl_obj_unlock( &p_port->obj ); + + cl_spinlock_acquire( &p_port->send_lock ); + + for( p_item = cl_qlist_head( &p_port->send_mgr.pending_list ); + p_item != cl_qlist_end( &p_port->send_mgr.pending_list ); + p_item = cl_qlist_head( &p_port->send_mgr.pending_list ) ) + { + /* Check the send queue and pend the request if not empty. */ + if( p_port->send_mgr.depth == p_port->p_adapter->params.sq_depth ) + { + IPOIB_PRINT( TRACE_LEVEL_WARNING, IPOIB_DBG_SEND, + ("No available WQEs.\n") ); + break; + } + + desc.p_pkt = IPOIB_PACKET_FROM_LIST_ITEM( + cl_qlist_remove_head( &p_port->send_mgr.pending_list ) ); + desc.p_endpt1 = NULL; + desc.p_buf = NULL; + + /* Get the ethernet header so we can find the endpoint. */ + status = __send_mgr_get_eth_hdr( + desc.p_pkt, &p_buf, &p_eth_hdr, &buf_len ); + if( status != NDIS_STATUS_SUCCESS ) + { + cl_perf_start( ProcessFailedSends ); + __process_failed_send( p_port, &desc, status ); + cl_perf_stop( &p_port->p_adapter->perf, ProcessFailedSends ); + continue; + } + + cl_perf_start( GetEndpt ); + status = __endpt_mgr_ref( p_port, p_eth_hdr->dst, &desc.p_endpt1 ); + cl_perf_stop( &p_port->p_adapter->perf, GetEndpt ); + if( status == NDIS_STATUS_PENDING ) + { + CL_ASSERT(desc.p_endpt1 == NULL); + cl_qlist_insert_head( &p_port->send_mgr.pending_list, + IPOIB_LIST_ITEM_FROM_PACKET( desc.p_pkt ) ); + break; + } + else if( status != NDIS_STATUS_SUCCESS ) + { + ASSERT( status == NDIS_STATUS_NO_ROUTE_TO_DESTINATION ); + CL_ASSERT(desc.p_endpt1 == NULL); + + if( ETH_IS_MULTICAST( p_eth_hdr->dst.addr ) ) + { + if( ipoib_port_join_mcast( p_port, p_eth_hdr->dst, + IB_MC_REC_STATE_FULL_MEMBER) == IB_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_SEND, + ("Multicast Mac - trying to join.\n") ); + cl_qlist_insert_head( &p_port->send_mgr.pending_list, + IPOIB_LIST_ITEM_FROM_PACKET( desc.p_pkt ) ); + break; + } + } + + /* + * Complete the send as if we sent it - WHQL tests don't like the + * sends to fail. + */ + cl_perf_start( ProcessFailedSends ); + __process_failed_send( p_port, &desc, NDIS_STATUS_SUCCESS ); + cl_perf_stop( &p_port->p_adapter->perf, ProcessFailedSends ); + continue; + } + + cl_perf_start( BuildSendDesc ); + status = __build_send_desc( p_port, p_eth_hdr, p_buf, buf_len, &desc ); + cl_perf_stop( &p_port->p_adapter->perf, BuildSendDesc ); + if( status != NDIS_STATUS_SUCCESS ) + { + cl_perf_start( ProcessFailedSends ); + __process_failed_send( p_port, &desc, status ); + cl_perf_stop( &p_port->p_adapter->perf, ProcessFailedSends ); + continue; + } + + /* Post the WR. */ + cl_perf_start( PostSend ); + ib_status = p_port->p_adapter->p_ifc->post_send( p_port->ib_mgr.h_qp, &desc.wr, NULL ); + cl_perf_stop( &p_port->p_adapter->perf, PostSend ); + if( ib_status != IB_SUCCESS ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_post_send returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( ib_status )) ); + cl_perf_start( ProcessFailedSends ); + __process_failed_send( p_port, &desc, NDIS_STATUS_FAILURE ); + cl_perf_stop( &p_port->p_adapter->perf, ProcessFailedSends ); + /* Flag the adapter as hung since posting is busted. */ + p_port->p_adapter->hung = TRUE; + continue; + } + + cl_atomic_inc( &p_port->send_mgr.depth ); + } + cl_spinlock_release( &p_port->send_lock ); + + IPOIB_EXIT( IPOIB_DBG_SEND ); +} + + +static void +__send_cb( + IN const ib_cq_handle_t h_cq, + IN void *cq_context ) +{ + ipoib_port_t *p_port; + ib_api_status_t status; + ib_wc_t wc[MAX_SEND_WC], *p_wc, *p_free; + cl_qlist_t done_list; + NDIS_PACKET *p_packet; + uint32_t length; + ipoib_endpt_t *p_endpt; + send_buf_t *p_send_buf; + ip_stat_sel_t type; + size_t i; + PERF_DECLARE( SendCompBundle ); + PERF_DECLARE( SendCb ); + PERF_DECLARE( PollSend ); + PERF_DECLARE( SendComp ); + PERF_DECLARE( FreeSendBuf ); + PERF_DECLARE( RearmSend ); + PERF_DECLARE( PortResume ); + + IPOIB_ENTER( IPOIB_DBG_SEND ); + + cl_perf_clr( SendCompBundle ); + + cl_perf_start( SendCb ); + + UNUSED_PARAM( h_cq ); + + cl_qlist_init( &done_list ); + + p_port = (ipoib_port_t*)cq_context; + + ipoib_port_ref( p_port, ref_send_cb ); + + for( i = 0; i < MAX_SEND_WC; i++ ) + wc[i].p_next = &wc[i + 1]; + wc[MAX_SEND_WC - 1].p_next = NULL; + + do + { + p_free = wc; + cl_perf_start( PollSend ); + status = p_port->p_adapter->p_ifc->poll_cq( p_port->ib_mgr.h_send_cq, &p_free, &p_wc ); + cl_perf_stop( &p_port->p_adapter->perf, PollSend ); + CL_ASSERT( status == IB_SUCCESS || status == IB_NOT_FOUND ); + + while( p_wc ) + { + cl_perf_start( SendComp ); + CL_ASSERT( p_wc->status != IB_WCS_SUCCESS + || p_wc->wc_type == IB_WC_SEND + || p_wc->wc_type == IB_WC_LSO); + p_packet = (NDIS_PACKET*)(uintn_t)p_wc->wr_id; + CL_ASSERT( p_packet ); + CL_ASSERT( IPOIB_PORT_FROM_PACKET( p_packet ) == p_port ); + + p_endpt = IPOIB_ENDPT_FROM_PACKET( p_packet ); + p_send_buf = IPOIB_SEND_FROM_PACKET( p_packet ); + switch( p_wc->status ) + { + case IB_WCS_SUCCESS: + if( p_endpt->h_mcast ) + { + if( p_endpt->dgid.multicast.raw_group_id[11] == 0xFF && + p_endpt->dgid.multicast.raw_group_id[10] == 0xFF && + p_endpt->dgid.multicast.raw_group_id[12] == 0xFF && + p_endpt->dgid.multicast.raw_group_id[13] == 0xFF ) + { + type = IP_STAT_BCAST_BYTES; + } + else + { + type = IP_STAT_MCAST_BYTES; + } + } + else + { + type = IP_STAT_UCAST_BYTES; + } + NdisQueryPacketLength( p_packet, &length ); + ipoib_inc_send_stat( p_port->p_adapter, type, length ); + NdisMSendComplete( p_port->p_adapter->h_adapter, + p_packet, NDIS_STATUS_SUCCESS ); + break; + + case IB_WCS_WR_FLUSHED_ERR: + IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_SEND, + ("Flushed send completion.\n") ); + ipoib_inc_send_stat( p_port->p_adapter, IP_STAT_DROPPED, 0 ); + NdisMSendCompleteX( p_port->p_adapter->h_adapter, + p_packet, NDIS_STATUS_RESET_IN_PROGRESS ); + break; + + default: + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Send failed with %s (vendor specific %#x)\n", + p_port->p_adapter->p_ifc->get_wc_status_str( p_wc->status ), + (int)p_wc->vendor_specific) ); + ipoib_inc_send_stat( p_port->p_adapter, IP_STAT_ERROR, 0 ); + NdisMSendCompleteX( p_port->p_adapter->h_adapter, + p_packet, NDIS_STATUS_FAILURE ); + break; + } + cl_perf_stop( &p_port->p_adapter->perf, SendComp ); + /* Dereference the enpoint used for the transfer. */ + ipoib_endpt_deref( p_endpt ); + + if( p_send_buf ) + { + cl_perf_start( FreeSendBuf ); + ExFreeToNPagedLookasideList( &p_port->buf_mgr.send_buf_list, + p_send_buf ); + cl_perf_stop( &p_port->p_adapter->perf, FreeSendBuf ); + } + + cl_atomic_dec( &p_port->send_mgr.depth ); + + p_wc = p_wc->p_next; + cl_perf_inc( SendCompBundle ); + } + /* If we didn't use up every WC, break out. */ + } while( !p_free ); + + /* Rearm the CQ. */ + cl_perf_start( RearmSend ); + status = p_port->p_adapter->p_ifc->rearm_cq( p_port->ib_mgr.h_send_cq, FALSE ); + cl_perf_stop( &p_port->p_adapter->perf, RearmSend ); + CL_ASSERT( status == IB_SUCCESS ); + + /* Resume any sends awaiting resources. */ + cl_perf_start( PortResume ); + ipoib_port_resume( p_port ); + cl_perf_stop( &p_port->p_adapter->perf, PortResume ); + + ipoib_port_deref( p_port, ref_send_cb ); + + cl_perf_stop( &p_port->p_adapter->perf, SendCb ); + cl_perf_update_ctr( &p_port->p_adapter->perf, SendCompBundle ); + + IPOIB_EXIT( IPOIB_DBG_SEND ); +} + + +/****************************************************************************** +* +* Endpoint manager implementation +* +******************************************************************************/ +static void +__endpt_mgr_construct( + IN ipoib_port_t* const p_port ) +{ + IPOIB_ENTER( IPOIB_DBG_INIT ); + cl_qmap_init( &p_port->endpt_mgr.mac_endpts ); + cl_qmap_init( &p_port->endpt_mgr.lid_endpts ); + cl_fmap_init( &p_port->endpt_mgr.gid_endpts, __gid_cmp ); + IPOIB_EXIT( IPOIB_DBG_INIT ); +} + + +static ib_api_status_t +__endpt_mgr_init( + IN ipoib_port_t* const p_port ) +{ + IPOIB_ENTER( IPOIB_DBG_INIT ); + UNUSED_PARAM( p_port ); + IPOIB_EXIT( IPOIB_DBG_INIT ); + return IB_SUCCESS; +} + + +static void +__endpt_mgr_destroy( + IN ipoib_port_t* const p_port ) +{ + IPOIB_ENTER( IPOIB_DBG_INIT ); + CL_ASSERT( cl_is_qmap_empty( &p_port->endpt_mgr.mac_endpts ) ); + CL_ASSERT( cl_is_qmap_empty( &p_port->endpt_mgr.lid_endpts ) ); + CL_ASSERT( cl_is_fmap_empty( &p_port->endpt_mgr.gid_endpts ) ); + UNUSED_PARAM( p_port ); + IPOIB_EXIT( IPOIB_DBG_INIT ); +} + + +static void +__endpt_mgr_remove_all( + IN ipoib_port_t* const p_port ) +{ + IPOIB_ENTER( IPOIB_DBG_ENDPT ); + + cl_obj_lock( &p_port->obj ); + /* Wait for all readers to complete. */ + while( p_port->endpt_rdr ) + ; + /* + * We don't need to initiate destruction - this is called only + * from the __port_destroying function, and destruction cascades + * to all child objects. Just clear all the maps. + */ + cl_qmap_remove_all( &p_port->endpt_mgr.mac_endpts ); + cl_qmap_remove_all( &p_port->endpt_mgr.lid_endpts ); + cl_fmap_remove_all( &p_port->endpt_mgr.gid_endpts ); + cl_obj_unlock( &p_port->obj ); + + IPOIB_EXIT( IPOIB_DBG_ENDPT ); +} + + +static void +__endpt_mgr_reset_all( + IN ipoib_port_t* const p_port ) +{ + cl_map_item_t *p_item; + ipoib_endpt_t *p_endpt; + cl_qlist_t mc_list; + uint32_t local_exist = 0; + + + IPOIB_ENTER( IPOIB_DBG_ENDPT ); + + cl_qlist_init( &mc_list ); + + cl_obj_lock( &p_port->obj ); + /* Wait for all readers to complete. */ + while( p_port->endpt_rdr ) + ; + +#if 0 + __endpt_mgr_remove_all(p_port); +#else + + NdisMIndicateStatus( p_port->p_adapter->h_adapter, + NDIS_STATUS_MEDIA_DISCONNECT, NULL, 0 ); + NdisMIndicateStatusComplete( p_port->p_adapter->h_adapter ); + + NdisMIndicateStatus( p_port->p_adapter->h_adapter, + NDIS_STATUS_MEDIA_CONNECT, NULL, 0 ); + NdisMIndicateStatusComplete( p_port->p_adapter->h_adapter ); + + // IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, + // ("Link DOWN!\n") ); + + if( p_port->p_local_endpt ) + { + cl_fmap_remove_item( &p_port->endpt_mgr.gid_endpts, + &p_port->p_local_endpt->gid_item ); + cl_qmap_remove_item( &p_port->endpt_mgr.mac_endpts, + &p_port->p_local_endpt->mac_item ); + if( p_port->p_local_endpt->dlid ) { + cl_qmap_remove_item( &p_port->endpt_mgr.lid_endpts, + &p_port->p_local_endpt->lid_item ); + p_port->p_local_endpt->dlid = 0; + } + + cl_qlist_insert_head( + &mc_list, &p_port->p_local_endpt->mac_item.pool_item.list_item ); + local_exist = 1; + + p_port->p_local_endpt = NULL; + } + + p_item = cl_qmap_head( &p_port->endpt_mgr.mac_endpts ); + while( p_item != cl_qmap_end( &p_port->endpt_mgr.mac_endpts ) ) + { + p_endpt = PARENT_STRUCT( p_item, ipoib_endpt_t, mac_item ); + p_item = cl_qmap_next( p_item ); + if( p_endpt->h_mcast ) + { + /* + * We destroy MC endpoints since they will get recreated + * when the port comes back up and we rejoin the MC groups. + */ + cl_qmap_remove_item( &p_port->endpt_mgr.mac_endpts, + &p_endpt->mac_item ); + cl_fmap_remove_item( &p_port->endpt_mgr.gid_endpts, + &p_endpt->gid_item ); + + cl_qlist_insert_tail( + &mc_list, &p_endpt->mac_item.pool_item.list_item ); + } + else if( p_endpt->h_av ) + { + /* Destroy the AV for all other endpoints. */ + p_port->p_adapter->p_ifc->destroy_av( p_endpt->h_av ); + p_endpt->h_av = NULL; + } + + if( p_endpt->dlid ) + { + cl_qmap_remove_item( &p_port->endpt_mgr.lid_endpts, + &p_endpt->lid_item ); + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_ENDPT, + ("<__endptr_mgr_reset_all: setting p_endpt->dlid to 0\n")); + p_endpt->dlid = 0; + } + + } +#endif + cl_obj_unlock( &p_port->obj ); + + + if(cl_qlist_count( &mc_list ) - local_exist) + { + p_port->mcast_cnt = (uint32_t)cl_qlist_count( &mc_list ) - local_exist; + } + else + { + p_port->mcast_cnt = 0; + KeSetEvent( &p_port->leave_mcast_event, EVENT_INCREMENT, FALSE ); + } + + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_ENDPT,("p_port->mcast_cnt = %d\n", p_port->mcast_cnt - local_exist)); + + /* Destroy all multicast endpoints now that we have released the lock. */ + while( cl_qlist_count( &mc_list ) ) + { + cl_list_item_t *p_item; + p_item = cl_qlist_remove_head( &mc_list ); + p_endpt = PARENT_STRUCT(p_item, ipoib_endpt_t, mac_item.pool_item.list_item); + cl_obj_destroy( &p_endpt->obj); + } + + IPOIB_EXIT( IPOIB_DBG_ENDPT ); +} + + +/* + * Called when updating an endpoint entry in response to an ARP. + * Because receive processing is serialized, and holds a reference + * on the endpoint reader, we wait for all *other* readers to exit before + * removing the item. + */ +static void +__endpt_mgr_remove( + IN ipoib_port_t* const p_port, + IN ipoib_endpt_t* const p_endpt ) +{ + IPOIB_ENTER( IPOIB_DBG_ENDPT ); + + /* This function must be called from the receive path */ + CL_ASSERT(p_port->endpt_rdr > 0); + + cl_obj_lock( &p_port->obj ); + /* Wait for all readers to complete. */ + while( p_port->endpt_rdr > 1 ) + ; + + /* Remove the endpoint from the maps so further requests don't find it. */ + cl_qmap_remove_item( &p_port->endpt_mgr.mac_endpts, &p_endpt->mac_item ); + /* + * The enpoints are *ALWAYS* in both the MAC and GID maps. They are only + * in the LID map if the GID has the same subnet prefix as us. + */ + cl_fmap_remove_item( &p_port->endpt_mgr.gid_endpts, &p_endpt->gid_item ); + + if( p_endpt->dlid ) + { + cl_qmap_remove_item( &p_port->endpt_mgr.lid_endpts, + &p_endpt->lid_item ); + } + + cl_obj_unlock( &p_port->obj ); + + cl_obj_destroy( &p_endpt->obj ); + + IPOIB_EXIT( IPOIB_DBG_ENDPT ); +} + + +NTSTATUS +ipoib_mac_to_gid( + IN ipoib_port_t* const p_port, + IN const mac_addr_t mac, + OUT ib_gid_t* p_gid ) +{ + ipoib_endpt_t* p_endpt; + cl_map_item_t *p_item; + uint64_t key = 0; + + IPOIB_ENTER( IPOIB_DBG_ENDPT ); + + cl_memcpy( &key, &mac, sizeof(mac_addr_t) ); + + cl_obj_lock( &p_port->obj ); + + p_item = cl_qmap_get( &p_port->endpt_mgr.mac_endpts, key ); + if( p_item == cl_qmap_end( &p_port->endpt_mgr.mac_endpts ) ) + { + cl_obj_unlock( &p_port->obj ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed endpoint lookup.\n") ); + return STATUS_INVALID_PARAMETER; + } + + p_endpt = PARENT_STRUCT( p_item, ipoib_endpt_t, mac_item ); + *p_gid = p_endpt->dgid; + + cl_obj_unlock( &p_port->obj ); + + IPOIB_EXIT( IPOIB_DBG_ENDPT ); + return STATUS_SUCCESS; +} + + +NTSTATUS +ipoib_mac_to_path( + IN ipoib_port_t* const p_port, + IN const mac_addr_t mac, + OUT ib_path_rec_t* p_path ) +{ + ipoib_endpt_t* p_endpt; + cl_map_item_t *p_item; + uint64_t key = 0; + uint8_t sl; + net32_t flow_lbl; + uint8_t hop_limit; + uint8_t pkt_life; + + IPOIB_ENTER( IPOIB_DBG_ENDPT ); + + cl_memcpy( &key, &mac, sizeof(mac_addr_t) ); + + cl_obj_lock( &p_port->obj ); + + if( p_port->p_local_endpt == NULL ) + { + cl_obj_unlock( &p_port->obj ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("No local endpoint.\n") ); + return STATUS_INVALID_PARAMETER; + } + + if( mac.addr[0] == 0 && mac.addr[1] == 0 && mac.addr[2] == 0 && + mac.addr[3] == 0 && mac.addr[4] == 0 && mac.addr[5] == 0 ) + { + p_endpt = p_port->p_local_endpt; + } + else + { + p_item = cl_qmap_get( &p_port->endpt_mgr.mac_endpts, key ); + if( p_item == cl_qmap_end( &p_port->endpt_mgr.mac_endpts ) ) + { + cl_obj_unlock( &p_port->obj ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed endpoint lookup.\n") ); + return STATUS_INVALID_PARAMETER; + } + + p_endpt = PARENT_STRUCT( p_item, ipoib_endpt_t, mac_item ); + } + + p_path->service_id = 0; + p_path->dgid = p_endpt->dgid; + p_path->sgid = p_port->p_local_endpt->dgid; + p_path->dlid = p_endpt->dlid; + p_path->slid = p_port->p_local_endpt->dlid; + + ib_member_get_sl_flow_hop( + p_port->ib_mgr.bcast_rec.sl_flow_hop, + &sl, + &flow_lbl, + &hop_limit + ); + + if( p_path->slid == p_path->dlid ) + pkt_life = 0; + else + pkt_life = p_port->ib_mgr.bcast_rec.pkt_life; + + ib_path_rec_init_local( + p_path, + &p_endpt->dgid, + &p_port->p_local_endpt->dgid, + p_endpt->dlid, + p_port->p_local_endpt->dlid, + 1, + p_port->ib_mgr.bcast_rec.pkey, + sl, 0, + IB_PATH_SELECTOR_EXACTLY, p_port->ib_mgr.bcast_rec.mtu, + IB_PATH_SELECTOR_EXACTLY, p_port->ib_mgr.bcast_rec.rate, + IB_PATH_SELECTOR_EXACTLY, pkt_life, + 0 ); + + /* Set global routing information. */ + ib_path_rec_set_hop_flow_raw( p_path, hop_limit, flow_lbl, FALSE ); + p_path->tclass = p_port->ib_mgr.bcast_rec.tclass; + + cl_obj_unlock( &p_port->obj ); + + IPOIB_EXIT( IPOIB_DBG_ENDPT ); + return STATUS_SUCCESS; +} + + +static inline NDIS_STATUS +__endpt_mgr_ref( + IN ipoib_port_t* const p_port, + IN const mac_addr_t mac, + OUT ipoib_endpt_t** const pp_endpt ) +{ + NDIS_STATUS status; + cl_map_item_t *p_item; + uint64_t key; + + PERF_DECLARE( EndptQueue ); + + IPOIB_ENTER( IPOIB_DBG_ENDPT ); + + if( !cl_memcmp( &mac, &p_port->p_adapter->params.conf_mac, sizeof(mac) ) ) + { + /* Discard loopback traffic. */ + IPOIB_PRINT(TRACE_LEVEL_WARNING, IPOIB_DBG_ENDPT, + ("Discarding loopback traffic\n") ); + IPOIB_EXIT( IPOIB_DBG_ENDPT ); + return NDIS_STATUS_NO_ROUTE_TO_DESTINATION; + } + + key = 0; + cl_memcpy( &key, &mac, sizeof(mac_addr_t) ); + + cl_obj_lock( &p_port->obj ); + + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_ENDPT, + ("Look for :\t MAC: %02X-%02X-%02X-%02X-%02X-%02X\n", + mac.addr[0], mac.addr[1], mac.addr[2], + mac.addr[3], mac.addr[4], mac.addr[5]) ); + + p_item = cl_qmap_get( &p_port->endpt_mgr.mac_endpts, key ); + if( p_item == cl_qmap_end( &p_port->endpt_mgr.mac_endpts ) ) + { + cl_obj_unlock( &p_port->obj ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_ENDPT, + ("Failed endpoint lookup.\n") ); + return NDIS_STATUS_NO_ROUTE_TO_DESTINATION; + } + + *pp_endpt = PARENT_STRUCT( p_item, ipoib_endpt_t, mac_item ); + ipoib_endpt_ref( *pp_endpt ); + + cl_obj_unlock( &p_port->obj ); + + cl_perf_start( EndptQueue ); + status = ipoib_endpt_queue( *pp_endpt ); + cl_perf_stop( &p_port->p_adapter->perf, EndptQueue ); + if( status != NDIS_STATUS_SUCCESS ) + *pp_endpt = NULL; + + IPOIB_EXIT( IPOIB_DBG_ENDPT ); + return status; +} + + +static inline NDIS_STATUS +__endpt_mgr_get_gid_qpn( + IN ipoib_port_t* const p_port, + IN const mac_addr_t mac, + OUT ib_gid_t* const p_gid, + OUT UNALIGNED net32_t* const p_qpn ) +{ + UNALIGNED + cl_map_item_t *p_item; + ipoib_endpt_t *p_endpt; + uint64_t key; + + IPOIB_ENTER( IPOIB_DBG_ENDPT ); + + cl_obj_lock( &p_port->obj ); + + key = 0; + cl_memcpy( &key, &mac, sizeof(mac_addr_t) ); + p_item = cl_qmap_get( &p_port->endpt_mgr.mac_endpts, key ); + if( p_item == cl_qmap_end( &p_port->endpt_mgr.mac_endpts ) ) + { + cl_obj_unlock( &p_port->obj ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_ENDPT, + ("Failed endpoint lookup.\n") ); + return NDIS_STATUS_FAILURE; + } + + p_endpt = PARENT_STRUCT( p_item, ipoib_endpt_t, mac_item ); + + *p_gid = p_endpt->dgid; + *p_qpn = p_endpt->qpn; + + cl_obj_unlock( &p_port->obj ); + + IPOIB_EXIT( IPOIB_DBG_ENDPT ); + return NDIS_STATUS_SUCCESS; +} + + +static inline ipoib_endpt_t* +__endpt_mgr_get_by_gid( + IN ipoib_port_t* const p_port, + IN const ib_gid_t* const p_gid ) +{ + cl_fmap_item_t *p_item; + ipoib_endpt_t *p_endpt; + + IPOIB_ENTER( IPOIB_DBG_ENDPT ); + + p_item = cl_fmap_get( &p_port->endpt_mgr.gid_endpts, p_gid ); + if( p_item == cl_fmap_end( &p_port->endpt_mgr.gid_endpts ) ) + p_endpt = NULL; + else + p_endpt = PARENT_STRUCT( p_item, ipoib_endpt_t, gid_item ); + + IPOIB_EXIT( IPOIB_DBG_ENDPT ); + return p_endpt; +} + + +static ipoib_endpt_t* +__endpt_mgr_get_by_lid( + IN ipoib_port_t* const p_port, + IN const net16_t lid ) +{ + cl_map_item_t *p_item; + ipoib_endpt_t *p_endpt; + + IPOIB_ENTER( IPOIB_DBG_ENDPT ); + + p_item = cl_qmap_get( &p_port->endpt_mgr.lid_endpts, lid ); + if( p_item == cl_qmap_end( &p_port->endpt_mgr.lid_endpts ) ) + p_endpt = NULL; + else + p_endpt = PARENT_STRUCT( p_item, ipoib_endpt_t, lid_item ); + + IPOIB_EXIT( IPOIB_DBG_ENDPT ); + return p_endpt; +} + + +inline ib_api_status_t +__endpt_mgr_insert_locked( + IN ipoib_port_t* const p_port, + IN const mac_addr_t mac, + IN ipoib_endpt_t* const p_endpt ) +{ + ib_api_status_t status; + + IPOIB_ENTER( IPOIB_DBG_ENDPT ); + + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_ENDPT, + ("insert :\t MAC: %02X-%02X-%02X-%02X-%02X-%02X\n", + mac.addr[0], mac.addr[1], mac.addr[2], + mac.addr[3], mac.addr[4], mac.addr[5]) ); + + cl_obj_lock( &p_port->obj ); + while( p_port->endpt_rdr ) + { + cl_obj_unlock( &p_port->obj ); + cl_obj_lock( &p_port->obj ); + } + /* __endpt_mgr_insert expects *one* reference to be held when being called. */ + cl_atomic_inc( &p_port->endpt_rdr ); + status= __endpt_mgr_insert( p_port, mac, p_endpt ); + cl_atomic_dec( &p_port->endpt_rdr ); + cl_obj_unlock( &p_port->obj ); + + return status; +} + + +inline ib_api_status_t +__endpt_mgr_insert( + IN ipoib_port_t* const p_port, + IN const mac_addr_t mac, + IN ipoib_endpt_t* const p_endpt ) +{ + uint64_t key; + cl_status_t cl_status; + cl_map_item_t *p_qitem; + cl_fmap_item_t *p_fitem; + + IPOIB_ENTER( IPOIB_DBG_ENDPT ); + + /* Wait for all accesses to the map to complete. */ + while( p_port->endpt_rdr > 1 ) + ; + + /* Link the endpoint to the port. */ + cl_status = cl_obj_insert_rel_parent_locked( + &p_endpt->rel, &p_port->obj, &p_endpt->obj ); + + if( cl_status != CL_SUCCESS ) + { + cl_obj_destroy( &p_endpt->obj ); + return IB_INVALID_STATE; + } + +#if DBG + cl_atomic_inc( &p_port->ref[ref_endpt_track] ); + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_OBJ, + ("ref type %d ref_cnt %d\n", ref_endpt_track, p_port->obj.ref_cnt) ); +#endif + + p_endpt->mac = mac; + key = 0; + cl_memcpy( &key, &mac, sizeof(mac_addr_t) ); + p_qitem = cl_qmap_insert( + &p_port->endpt_mgr.mac_endpts, key, &p_endpt->mac_item ); + CL_ASSERT( p_qitem == &p_endpt->mac_item ); + p_fitem = cl_fmap_insert( + &p_port->endpt_mgr.gid_endpts, &p_endpt->dgid, &p_endpt->gid_item ); + CL_ASSERT( p_fitem == &p_endpt->gid_item ); + if( p_endpt->dlid ) + { + p_qitem = cl_qmap_insert( + &p_port->endpt_mgr.lid_endpts, p_endpt->dlid, &p_endpt->lid_item ); + CL_ASSERT( p_qitem == &p_endpt->lid_item ); + if (p_qitem != &p_endpt->lid_item) { + // Since we failed to insert into the list, make sure it is not removed + p_endpt->dlid =0; + } + } + + IPOIB_EXIT( IPOIB_DBG_ENDPT ); + return IB_SUCCESS; +} + + +static ib_api_status_t +__endpt_mgr_add_bcast( + IN ipoib_port_t* const p_port, + IN ib_mcast_rec_t *p_mcast_rec ) +{ + ib_api_status_t status; + ipoib_endpt_t *p_endpt; + mac_addr_t bcast_mac; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + /* + * Cache the broadcast group properties for creating future mcast groups. + */ + p_port->ib_mgr.bcast_rec = *p_mcast_rec->p_member_rec; + + /* Allocate the broadcast endpoint. */ + p_endpt = ipoib_endpt_create( &p_mcast_rec->p_member_rec->mgid, + 0 , CL_HTON32(0x00FFFFFF) ); + if( !p_endpt ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ipoib_endpt_create failed.\n") ); + return IB_INSUFFICIENT_RESOURCES; + } + /* set reference to transport to be used while is not attached to the port */ + p_endpt->is_mcast_listener = TRUE; + p_endpt->p_ifc = p_port->p_adapter->p_ifc; + status = ipoib_endpt_set_mcast( p_endpt, p_port->ib_mgr.h_pd, + p_port->port_num, p_mcast_rec ); + if( status != IB_SUCCESS ) + { + cl_obj_destroy( &p_endpt->obj ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ipoib_create_mcast_endpt returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + return status; + } + + /* Add the broadcast endpoint to the endpoint map. */ + cl_memset( &bcast_mac, 0xFF, sizeof(bcast_mac) ); + status = __endpt_mgr_insert_locked( p_port, bcast_mac, p_endpt ); + + IPOIB_EXIT( IPOIB_DBG_INIT ); + return status; +} + + +void +ipoib_port_remove_endpt( + IN ipoib_port_t* const p_port, + IN const mac_addr_t mac ) +{ + cl_map_item_t *p_item; + ipoib_endpt_t *p_endpt; + uint64_t key; + + IPOIB_ENTER( IPOIB_DBG_ENDPT ); + + key = 0; + cl_memcpy( &key, &mac, sizeof(mac_addr_t) ); + + /* Remove the endpoint from the maps so further requests don't find it. */ + cl_obj_lock( &p_port->obj ); + /* Wait for all readers to finish */ + while( p_port->endpt_rdr ) + ; + p_item = cl_qmap_remove( &p_port->endpt_mgr.mac_endpts, key ); + /* + * Dereference the endpoint. If the ref count goes to zero, it + * will get freed. + */ + if( p_item != cl_qmap_end( &p_port->endpt_mgr.mac_endpts ) ) + { + p_endpt = PARENT_STRUCT( p_item, ipoib_endpt_t, mac_item ); + /* + * The enpoints are *ALWAYS* in both the MAC and GID maps. They are only + * in the LID map if the GID has the same subnet prefix as us. + */ + cl_fmap_remove_item( + &p_port->endpt_mgr.gid_endpts, &p_endpt->gid_item ); + + if( p_endpt->dlid ) + { + cl_qmap_remove_item( + &p_port->endpt_mgr.lid_endpts, &p_endpt->lid_item ); + p_endpt->dlid = 0; + } + + cl_obj_unlock( &p_port->obj ); + cl_obj_destroy( &p_endpt->obj ); +#if DBG + cl_atomic_dec( &p_port->ref[ref_endpt_track] ); + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_ENDPT, + ("ref type %d ref_cnt %d\n", ref_endpt_track, p_port->obj.ref_cnt) ); +#endif + + } + else + { + cl_obj_unlock( &p_port->obj ); + } + + IPOIB_EXIT( IPOIB_DBG_ENDPT ); +} + +/* + * The sequence for port up is as follows: + * 1. The port goes active. This allows the adapter to send SA queries + * and join the broadcast group (and other groups). + * + * 2. The adapter sends an SA query for the broadcast group. + * + * 3. Upon completion of the query, the adapter joins the broadcast group. + */ + + +/* + * Query the SA for the broadcast group. + */ +void +ipoib_port_up( + IN ipoib_port_t* const p_port, + IN const ib_pnp_port_rec_t* const p_pnp_rec ) +{ + ib_port_info_t *p_port_info; + ib_mad_t *mad_in = NULL; + ib_mad_t *mad_out = NULL; + ib_api_status_t status = IB_INSUFFICIENT_MEMORY; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + cl_obj_lock( &p_port->obj ); + if ( p_port->state == IB_QPS_INIT ) + { + cl_obj_unlock( &p_port->obj ); + status = IB_SUCCESS; + IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, + ("p_port->state = %d - Aborting.\n", p_port->state) ); + goto up_done; + } + else if ( p_port->state == IB_QPS_RTS ) + { + cl_obj_unlock( &p_port->obj ); + cl_obj_lock( &p_port->p_adapter->obj ); + if( p_port->p_adapter->state == IB_PNP_PORT_INIT ) + { + p_port->p_adapter->state = IB_PNP_PORT_ACTIVE; + } + cl_obj_unlock( &p_port->p_adapter->obj ); + status = IB_SUCCESS; + IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, + ("Port init is done. p_port->state = %d.\n", p_port->state ) ); + goto up_done; + } + p_port->state = IB_QPS_INIT; + cl_obj_unlock( &p_port->obj ); + + + /* Wait for all work requests to get flushed. */ + while( p_port->recv_mgr.depth || p_port->send_mgr.depth ) + cl_thread_suspend( 0 ); + + KeResetEvent( &p_port->sa_event ); + + mad_out = (ib_mad_t*)cl_zalloc(256); + if(! mad_out) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("failed to allocate mad mad_out\n")); + goto up_done; + } + mad_in = (ib_mad_t*)cl_zalloc(256); + if(! mad_in) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("failed to allocate mad mad_in\n")); + goto up_done; + } + + mad_in->attr_id = IB_MAD_ATTR_PORT_INFO; + mad_in->method = IB_MAD_METHOD_GET; + mad_in->base_ver = 1; + mad_in->class_ver =1; + mad_in->mgmt_class = IB_MCLASS_SUBN_LID; + + status = p_port->p_adapter->p_ifc->local_mad( + p_port->ib_mgr.h_ca ,p_port->port_num ,mad_in ,mad_out); + + if( status != IB_SUCCESS ) + { + ipoib_set_inactive( p_port->p_adapter ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_local_mad returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + goto up_done; + } + + p_port_info = (ib_port_info_t*)(((ib_smp_t*)mad_out)->data); + p_port->base_lid = p_pnp_rec->p_port_attr->lid; + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, + ("Received port info: link width = %d.\n", + p_port_info->link_width_active) ); + p_port->ib_mgr.rate = + ib_port_info_compute_rate( p_port_info ); + + ipoib_set_rate( p_port->p_adapter, + p_port_info->link_width_active, + ib_port_info_get_link_speed_active( p_port_info ) ); + + status = __port_get_bcast( p_port ); + if (status != IB_SUCCESS) + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + (" __port_get_bcast returned %s\n",p_port->p_adapter->p_ifc->get_err_str( status ))); + +up_done: + if( status != IB_SUCCESS ) + { + if( status != IB_CANCELED ) + { + ipoib_set_inactive( p_port->p_adapter ); + __endpt_mgr_reset_all( p_port ); + } + ASSERT(p_port->state == IB_QPS_INIT || p_port->state == IB_QPS_ERROR); + p_port->state = IB_QPS_ERROR; + KeSetEvent( &p_port->sa_event, EVENT_INCREMENT, FALSE ); + } + + if(mad_out) + cl_free(mad_out); + if(mad_in) + cl_free(mad_in); + + IPOIB_EXIT( IPOIB_DBG_INIT ); +} + + +static ib_api_status_t +__endpt_mgr_add_local( + IN ipoib_port_t* const p_port, + IN ib_port_info_t* const p_port_info ) +{ + ib_api_status_t status; + ib_gid_t gid; + ipoib_endpt_t *p_endpt; + ib_av_attr_t av_attr; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + ib_gid_set_default( &gid, p_port->p_adapter->guids.port_guid.guid ); + p_endpt = ipoib_endpt_create( + &gid, p_port_info->base_lid, p_port->ib_mgr.qpn ); + if( !p_endpt ) + { + p_port->p_adapter->hung = TRUE; + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to create local endpt\n") ); + return IB_INSUFFICIENT_MEMORY; + } + + cl_memclr( &av_attr, sizeof(ib_av_attr_t) ); + av_attr.port_num = p_port->port_num; + av_attr.sl = 0; + IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_ENDPT, + ("<__endpt_mgr_add_local>: av_attr.dlid = p_port_info->base_lid = %d\n",p_port_info->base_lid)); + av_attr.dlid = p_port_info->base_lid; + av_attr.static_rate = p_port->ib_mgr.rate; + av_attr.path_bits = 0; + status = p_port->p_adapter->p_ifc->create_av( + p_port->ib_mgr.h_pd, &av_attr, &p_endpt->h_av ); + if( status != IB_SUCCESS ) + { + cl_obj_destroy( &p_endpt->obj ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_create_av for local endpoint returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + return status; + } + + /* __endpt_mgr_insert expects *one* reference to be held. */ + cl_atomic_inc( &p_port->endpt_rdr ); + status = __endpt_mgr_insert( p_port, p_port->p_adapter->params.conf_mac, p_endpt ); + cl_atomic_dec( &p_port->endpt_rdr ); + if( status != IB_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("__endpt_mgr_insert for local endpoint returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + return status; + } + + p_port->p_local_endpt = p_endpt; + + IPOIB_EXIT( IPOIB_DBG_INIT ); + return status; +} + + + + +static ib_api_status_t +__port_get_bcast( + IN ipoib_port_t* const p_port ) +{ + ib_api_status_t status; + ib_query_req_t query; + ib_user_query_t info; + ib_member_rec_t member_rec; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + info.method = IB_MAD_METHOD_GETTABLE; + info.attr_id = IB_MAD_ATTR_MCMEMBER_RECORD; + info.attr_size = sizeof(ib_member_rec_t); + info.comp_mask = IB_MCR_COMPMASK_MGID; + info.p_attr = &member_rec; + + /* Query requires only the MGID. */ + cl_memclr( &member_rec, sizeof(ib_member_rec_t) ); + member_rec.mgid = bcast_mgid_template; + + member_rec.mgid.raw[4] = (uint8_t) (p_port->p_adapter->guids.port_guid.pkey >> 8) ; + member_rec.mgid.raw[5] = (uint8_t) p_port->p_adapter->guids.port_guid.pkey; + member_rec.pkey = cl_hton16(p_port->p_adapter->guids.port_guid.pkey); + cl_memclr( &query, sizeof(ib_query_req_t) ); + query.query_type = IB_QUERY_USER_DEFINED; + query.p_query_input = &info; + query.port_guid = p_port->p_adapter->guids.port_guid.guid; + query.timeout_ms = p_port->p_adapter->params.sa_timeout; + query.retry_cnt = p_port->p_adapter->params.sa_retry_cnt; + query.query_context = p_port; + query.pfn_query_cb = __bcast_get_cb; + + /* reference the object for the multicast query. */ + ipoib_port_ref( p_port, ref_get_bcast ); + + status = p_port->p_adapter->p_ifc->query( + p_port->p_adapter->h_al, &query, &p_port->ib_mgr.h_query ); + if( status != IB_SUCCESS ) + { + ipoib_port_deref( p_port, ref_get_bcast ); + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_query returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + } + + IPOIB_EXIT( IPOIB_DBG_INIT ); + return status; +} + + +/* Callback for the MCMemberRecord Get query for the IPv4 broadcast group. */ +static void +__bcast_get_cb( + IN ib_query_rec_t *p_query_rec ) +{ + ipoib_port_t *p_port; + ib_member_rec_t *p_mc_req; + ib_api_status_t status; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + p_port = (ipoib_port_t*)p_query_rec->query_context; + + cl_obj_lock( &p_port->obj ); + p_port->ib_mgr.h_query = NULL; + + CL_ASSERT(p_port->state == IB_QPS_INIT || p_port->state == IB_QPS_ERROR); + if( p_port->state != IB_QPS_INIT ) + { + status = IB_CANCELED; + goto done; + } + + status = p_query_rec->status; + + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, + ("status of request %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + + switch( status ) + { + case IB_SUCCESS: + if( p_query_rec->result_cnt ) + { + p_mc_req = (ib_member_rec_t*) + ib_get_query_result( p_query_rec->p_result_mad, 0 ); + + /* Join the broadcast group. */ + status = __port_join_bcast( p_port, p_mc_req ); + break; + } + /* Fall through. */ + + case IB_REMOTE_ERROR: + /* SA failed the query. Broadcast group doesn't exist, create it. */ + status = __port_create_bcast( p_port ); + break; + + case IB_CANCELED: + IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, + ("Instance destroying - Aborting.\n") ); + break; + + default: + NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter, + EVENT_IPOIB_BCAST_GET, 1, p_query_rec->status ); + } +done: + cl_obj_unlock( &p_port->obj ); + + if( status != IB_SUCCESS ) + { + if( status != IB_CANCELED ) + { + ipoib_set_inactive( p_port->p_adapter ); + __endpt_mgr_reset_all( p_port ); + } + p_port->state = IB_QPS_ERROR; + KeSetEvent( &p_port->sa_event, EVENT_INCREMENT, FALSE ); + } + + /* Return the response MAD to AL. */ + if( p_query_rec->p_result_mad ) + p_port->p_adapter->p_ifc->put_mad( p_query_rec->p_result_mad ); + + /* Release the reference taken when issuing the member record query. */ + ipoib_port_deref( p_port, ref_bcast_get_cb ); + + IPOIB_EXIT( IPOIB_DBG_INIT ); +} + + +static ib_api_status_t +__port_join_bcast( + IN ipoib_port_t* const p_port, + IN ib_member_rec_t* const p_member_rec ) +{ + ib_api_status_t status; + ib_mcast_req_t mcast_req; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + /* Check that the rate is realizable for our port. */ + if( p_port->ib_mgr.rate < (p_member_rec->rate & 0x3F) && + (g_ipoib.bypass_check_bcast_rate == 0)) + { + /* + * The MC group rate is higher than our port's rate. Log an error + * and stop. A port transition will drive the retry. + */ + IPOIB_PRINT(TRACE_LEVEL_WARNING, IPOIB_DBG_INIT, + ("Unrealizable join due to rate mismatch.\n") ); + NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter, + EVENT_IPOIB_BCAST_RATE, 2, + (uint32_t)(p_member_rec->rate & 0x3F), + (uint32_t)p_port->ib_mgr.rate ); + return IB_ERROR; + } + + /* Join the broadcast group. */ + cl_memclr( &mcast_req, sizeof(mcast_req) ); + /* Copy the results of the Get to use as parameters. */ + mcast_req.member_rec = *p_member_rec; + /* We specify our port GID for the join operation. */ + mcast_req.member_rec.port_gid.unicast.prefix = IB_DEFAULT_SUBNET_PREFIX; + mcast_req.member_rec.port_gid.unicast.interface_id = + p_port->p_adapter->guids.port_guid.guid; + + mcast_req.mcast_context = p_port; + mcast_req.pfn_mcast_cb = __bcast_cb; + mcast_req.timeout_ms = p_port->p_adapter->params.sa_timeout; + mcast_req.retry_cnt = p_port->p_adapter->params.sa_retry_cnt; + mcast_req.port_guid = p_port->p_adapter->guids.port_guid.guid; + mcast_req.pkey_index = p_port->pkey_index; + + if( ib_member_get_state( mcast_req.member_rec.scope_state ) != + IB_MC_REC_STATE_FULL_MEMBER ) + { + IPOIB_PRINT(TRACE_LEVEL_WARNING, IPOIB_DBG_INIT, + ("Incorrect MC member rec join state in query response.\n") ); + ib_member_set_state( &mcast_req.member_rec.scope_state, + IB_MC_REC_STATE_FULL_MEMBER ); + } + + /* reference the object for the multicast join request. */ + ipoib_port_ref( p_port, ref_join_bcast ); + + status = p_port->p_adapter->p_ifc->join_mcast( + p_port->ib_mgr.h_qp, &mcast_req ); + if( status != IB_SUCCESS ) + { + ipoib_port_deref( p_port, ref_bcast_join_failed ); + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_join_mcast returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + } + IPOIB_EXIT( IPOIB_DBG_INIT ); + return status; +} + + +static ib_api_status_t +__port_create_bcast( + IN ipoib_port_t* const p_port ) +{ + ib_api_status_t status; + ib_mcast_req_t mcast_req; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + /* Join the broadcast group. */ + cl_memclr( &mcast_req, sizeof(mcast_req) ); + mcast_req.create = TRUE; + /* + * Create requires pkey, qkey, SL, flow label, traffic class, joing state + * and port GID. + * + * We specify the MGID since we don't want the SA to generate it for us. + */ + mcast_req.member_rec.mgid = bcast_mgid_template; + mcast_req.member_rec.mgid.raw[4] = (uint8_t) (p_port->p_adapter->guids.port_guid.pkey >> 8); + mcast_req.member_rec.mgid.raw[5] = (uint8_t) p_port->p_adapter->guids.port_guid.pkey; + ib_gid_set_default( &mcast_req.member_rec.port_gid, + p_port->p_adapter->guids.port_guid.guid ); + /* + * IPOIB spec requires that the QKEY have the MSb set so that the QKEY + * from the QP is used rather than the QKEY in the send WR. + */ + mcast_req.member_rec.qkey = + (uint32_t)(uintn_t)p_port | IB_QP_PRIVILEGED_Q_KEY; + mcast_req.member_rec.mtu = + (IB_PATH_SELECTOR_EXACTLY << 6) | IB_MTU_LEN_2048; + + mcast_req.member_rec.pkey = cl_hton16(p_port->p_adapter->guids.port_guid.pkey); + + mcast_req.member_rec.sl_flow_hop = ib_member_set_sl_flow_hop( 0, 0, 0 ); + mcast_req.member_rec.scope_state = + ib_member_set_scope_state( 2, IB_MC_REC_STATE_FULL_MEMBER ); + + mcast_req.mcast_context = p_port; + mcast_req.pfn_mcast_cb = __bcast_cb; + mcast_req.timeout_ms = p_port->p_adapter->params.sa_timeout; + mcast_req.retry_cnt = p_port->p_adapter->params.sa_retry_cnt; + mcast_req.port_guid = p_port->p_adapter->guids.port_guid.guid; + mcast_req.pkey_index = p_port->pkey_index; + + /* reference the object for the multicast join request. */ + ipoib_port_ref( p_port, ref_join_bcast ); + + status = p_port->p_adapter->p_ifc->join_mcast( p_port->ib_mgr.h_qp, &mcast_req ); + if( status != IB_SUCCESS ) + { + ipoib_port_deref( p_port, ref_bcast_create_failed ); + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_join_mcast returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + } + IPOIB_EXIT( IPOIB_DBG_INIT ); + return status; +} + + +void +ipoib_port_down( + IN ipoib_port_t* const p_port ) +{ + ib_api_status_t status; + ib_qp_mod_t qp_mod; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + /* + * Mark our state. This causes all callbacks to abort. + * Note that we hold the receive lock so that we synchronize + * with reposting. We must take the receive lock before the + * object lock since that is the order taken when reposting. + */ + cl_spinlock_acquire( &p_port->recv_lock ); + cl_obj_lock( &p_port->obj ); + p_port->state = IB_QPS_ERROR; + + NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter, + EVENT_IPOIB_PORT_DOWN, 0 ); + + if( p_port->ib_mgr.h_query ) + { + p_port->p_adapter->p_ifc->cancel_query( + p_port->p_adapter->h_al, p_port->ib_mgr.h_query ); + p_port->ib_mgr.h_query = NULL; + } + cl_obj_unlock( &p_port->obj ); + cl_spinlock_release( &p_port->recv_lock ); + + KeWaitForSingleObject( + &p_port->sa_event, Executive, KernelMode, FALSE, NULL ); + + /* garbage collector timer is not needed when link is down */ + KeCancelTimer(&p_port->gc_timer); + KeFlushQueuedDpcs(); + + /* + * Put the QP in the error state. This removes the need to + * synchronize with send/receive callbacks. + */ + CL_ASSERT( p_port->ib_mgr.h_qp ); + cl_memclr( &qp_mod, sizeof(ib_qp_mod_t) ); + qp_mod.req_state = IB_QPS_ERROR; + status = p_port->p_adapter->p_ifc->modify_qp( p_port->ib_mgr.h_qp, &qp_mod ); + if( status != IB_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_modify_qp to error state returned %s.\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + p_port->p_adapter->hung = TRUE; + return; + } + + KeResetEvent(&p_port->leave_mcast_event); + + /* Reset all endpoints so we don't flush our ARP cache. */ + __endpt_mgr_reset_all( p_port ); + + KeWaitForSingleObject( + &p_port->leave_mcast_event, Executive, KernelMode, FALSE, NULL ); + + __pending_list_destroy(p_port); + + cl_obj_lock( &p_port->p_adapter->obj ); + ipoib_dereg_addrs( p_port->p_adapter ); + cl_obj_unlock( &p_port->p_adapter->obj ); + + IPOIB_EXIT( IPOIB_DBG_INIT ); +} + + +static void +__bcast_cb( + IN ib_mcast_rec_t *p_mcast_rec ) +{ + ipoib_port_t *p_port; + ib_api_status_t status; + LARGE_INTEGER gc_due_time; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + p_port = (ipoib_port_t*)p_mcast_rec->mcast_context; + + cl_obj_lock( &p_port->obj ); + + ASSERT(p_port->state == IB_QPS_INIT || p_port->state == IB_QPS_ERROR); + if( p_port->state != IB_QPS_INIT ) + { + cl_obj_unlock( &p_port->obj ); + if( p_mcast_rec->status == IB_SUCCESS ) + { + ipoib_port_ref(p_port, ref_leave_mcast); + p_port->p_adapter->p_ifc->leave_mcast( p_mcast_rec->h_mcast, __leave_error_mcast_cb ); + } + KeSetEvent( &p_port->sa_event, EVENT_INCREMENT, FALSE ); + ipoib_port_deref( p_port, ref_bcast_inv_state ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, + ("Invalid state - Aborting.\n") ); + return; + } + status = p_mcast_rec->status; + if( status != IB_SUCCESS ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Multicast join for broadcast group returned %s.\n", + p_port->p_adapter->p_ifc->get_err_str( p_mcast_rec->status )) ); + if( status == IB_REMOTE_ERROR ) + { + /* + * Either: + * - the join failed because the group no longer exists + * - the create failed because the group already exists + * + * Kick off a new Get query to the SA to restart the join process + * from the top. Note that as an optimization, it would be + * possible to distinguish between the join and the create. + * If the join fails, try the create. If the create fails, start + * over with the Get. + */ + /* TODO: Assert is a place holder. Can we ever get here if the + state isn't IB_PNP_PORT_ADD or PORT_DOWN or PORT_INIT? */ + CL_ASSERT( p_port->p_adapter->state == IB_PNP_PORT_ADD || + p_port->p_adapter->state == IB_PNP_PORT_DOWN || + p_port->p_adapter->state == IB_PNP_PORT_INIT ); + if(++p_port->bc_join_retry_cnt < p_port->p_adapter->params.bc_join_retry) + { + status = __port_get_bcast( p_port ); + } + else + { + NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter, + EVENT_IPOIB_BCAST_JOIN, 1, p_mcast_rec->status ); + p_port->bc_join_retry_cnt = 0; + } + } + else + { + NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter, + EVENT_IPOIB_BCAST_JOIN, 1, p_mcast_rec->status ); + } + + cl_obj_unlock( &p_port->obj ); + if( status != IB_SUCCESS ) + { + ipoib_set_inactive( p_port->p_adapter ); + __endpt_mgr_reset_all( p_port ); + ASSERT(p_port->state == IB_QPS_INIT || p_port->state == IB_QPS_ERROR); + p_port->state = IB_QPS_ERROR; + KeSetEvent( &p_port->sa_event, EVENT_INCREMENT, FALSE ); + } + ipoib_port_deref( p_port, ref_bcast_req_failed ); + IPOIB_EXIT( IPOIB_DBG_INIT ); + return; + } + p_port->bc_join_retry_cnt = 0; + + while( p_port->endpt_rdr ) + { + cl_obj_unlock( &p_port->obj ); + cl_obj_lock( &p_port->obj ); + } + + if(! p_port->p_local_endpt) + { + ib_port_info_t port_info; + cl_memclr(&port_info, sizeof(port_info)); + port_info.base_lid = p_port->base_lid; + status = __endpt_mgr_add_local( p_port, &port_info ); + if( status != IB_SUCCESS ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("__endpt_mgr_add_local returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + cl_obj_unlock( &p_port->obj ); + goto err; + } + } + + cl_obj_unlock( &p_port->obj ); + + status = __endpt_mgr_add_bcast( p_port, p_mcast_rec ); + if( status != IB_SUCCESS ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("__endpt_mgr_add_bcast returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + ipoib_port_ref(p_port, ref_leave_mcast); + status = p_port->p_adapter->p_ifc->leave_mcast( p_mcast_rec->h_mcast, __leave_error_mcast_cb ); + CL_ASSERT( status == IB_SUCCESS ); + goto err; + } + + /* Get the QP ready for action. */ + status = __ib_mgr_activate( p_port ); + if( status != IB_SUCCESS ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("__ib_mgr_activate returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + +err: + /* Flag the adapter as hung. */ + p_port->p_adapter->hung = TRUE; + ASSERT(p_port->state == IB_QPS_INIT || p_port->state == IB_QPS_ERROR); + p_port->state = IB_QPS_ERROR; + KeSetEvent( &p_port->sa_event, EVENT_INCREMENT, FALSE ); + ipoib_port_deref( p_port, ref_bcast_error ); + IPOIB_EXIT( IPOIB_DBG_INIT ); + return; + } + + cl_obj_lock( &p_port->obj ); + /* Only change the state if we're still in INIT. */ + ASSERT( p_port->state == IB_QPS_INIT || p_port->state == IB_QPS_ERROR); + if (p_port->state == IB_QPS_INIT) { + p_port->state = IB_QPS_RTS; + } + cl_obj_unlock( &p_port->obj ); + + /* Prepost receives. */ + cl_spinlock_acquire( &p_port->recv_lock ); + __recv_mgr_repost( p_port ); + cl_spinlock_release( &p_port->recv_lock ); + + /* Notify the adapter that we now have an active connection. */ + status = ipoib_set_active( p_port->p_adapter ); + if( status != IB_SUCCESS ) + { + ib_qp_mod_t qp_mod; + ipoib_set_inactive( p_port->p_adapter ); + KeSetEvent( &p_port->sa_event, EVENT_INCREMENT, FALSE ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, + ("ipoib_set_active returned %s.\n",p_port->p_adapter->p_ifc->get_err_str( status ))); + cl_spinlock_acquire( &p_port->recv_lock ); + cl_obj_lock( &p_port->obj ); + p_port->state = IB_QPS_ERROR; + if( p_port->ib_mgr.h_query ) + { + p_port->p_adapter->p_ifc->cancel_query( + p_port->p_adapter->h_al, p_port->ib_mgr.h_query ); + p_port->ib_mgr.h_query = NULL; + } + cl_obj_unlock( &p_port->obj ); + cl_spinlock_release( &p_port->recv_lock ); + + CL_ASSERT( p_port->ib_mgr.h_qp ); + cl_memclr( &qp_mod, sizeof(ib_qp_mod_t) ); + qp_mod.req_state = IB_QPS_ERROR; + status = p_port->p_adapter->p_ifc->modify_qp( p_port->ib_mgr.h_qp, &qp_mod ); + __endpt_mgr_reset_all( p_port ); + + ipoib_port_deref( p_port, ref_join_bcast ); + return; + } + + /* garbage collector timer is needed when link is active */ + gc_due_time.QuadPart = -(int64_t)(((uint64_t)p_port->p_adapter->params.mc_leave_rescan * 2000000) * 10); + KeSetTimerEx(&p_port->gc_timer,gc_due_time, + (LONG)p_port->p_adapter->params.mc_leave_rescan*1000,&p_port->gc_dpc); + + KeSetEvent( &p_port->sa_event, EVENT_INCREMENT, FALSE ); + ipoib_port_deref( p_port, ref_join_bcast ); + IPOIB_EXIT( IPOIB_DBG_INIT ); +} + + +static void +__qp_event( + IN ib_async_event_rec_t *p_event_rec ) +{ + UNUSED_PARAM( p_event_rec ); + CL_ASSERT( p_event_rec->context ); + ((ipoib_port_t*)p_event_rec->context)->p_adapter->hung = TRUE; +} + + +static void +__cq_event( + IN ib_async_event_rec_t *p_event_rec ) +{ + UNUSED_PARAM( p_event_rec ); + CL_ASSERT( p_event_rec->context ); + ((ipoib_port_t*)p_event_rec->context)->p_adapter->hung = TRUE; +} + + +static ib_api_status_t +__ib_mgr_activate( + IN ipoib_port_t* const p_port ) +{ + ib_api_status_t status; + ib_dgrm_info_t dgrm_info; + ib_qp_mod_t qp_mod; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + /* + * Move the QP to RESET. This allows us to reclaim any + * unflushed receives. + */ + cl_memclr( &qp_mod, sizeof(ib_qp_mod_t) ); + qp_mod.req_state = IB_QPS_RESET; + status = p_port->p_adapter->p_ifc->modify_qp( p_port->ib_mgr.h_qp, &qp_mod ); + if( status != IB_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_modify_qp returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + return status; + } + + /* Move the QP to RTS. */ + dgrm_info.port_guid = p_port->p_adapter->guids.port_guid.guid; + dgrm_info.qkey = p_port->ib_mgr.bcast_rec.qkey; + dgrm_info.pkey_index = p_port->pkey_index; + status = p_port->p_adapter->p_ifc->init_dgrm_svc( p_port->ib_mgr.h_qp, &dgrm_info ); + if( status != IB_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_init_dgrm_svc returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + return status; + } + + /* Rearm the CQs. */ + status = p_port->p_adapter->p_ifc->rearm_cq( p_port->ib_mgr.h_recv_cq, FALSE ); + if( status != IB_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_rearm_cq for recv returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + return status; + } + status = p_port->p_adapter->p_ifc->rearm_cq( p_port->ib_mgr.h_send_cq, FALSE ); + if( status != IB_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_rearm_cq for send returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + return status; + } + + IPOIB_EXIT( IPOIB_DBG_INIT ); + return IB_SUCCESS; +} + + +/* Transition to a passive level thread. */ +ib_api_status_t +ipoib_port_join_mcast( + IN ipoib_port_t* const p_port, + IN const mac_addr_t mac, + IN const uint8_t state) +{ + ib_api_status_t status; + ib_mcast_req_t mcast_req; + ipoib_endpt_t *p_endpt; + + IPOIB_ENTER( IPOIB_DBG_MCAST ); + + switch( __endpt_mgr_ref( p_port, mac, &p_endpt ) ) + { + case NDIS_STATUS_NO_ROUTE_TO_DESTINATION: + break; + + case NDIS_STATUS_SUCCESS: + ipoib_endpt_deref( p_endpt ); + /* Fall through */ + + case NDIS_STATUS_PENDING: + return IB_SUCCESS; + } + + /* + * Issue the mcast request, using the parameters of the broadcast group. + * This allows us to do a create request that should always succeed since + * the required parameters are known. + */ + cl_memclr( &mcast_req, sizeof(mcast_req) ); + mcast_req.create = TRUE; + + /* Copy the settings from the broadcast group. */ + mcast_req.member_rec = p_port->ib_mgr.bcast_rec; + /* Clear fields that aren't specified in the join */ + mcast_req.member_rec.mlid = 0; + ib_member_set_state( &mcast_req.member_rec.scope_state,state); + + if( (mac.addr[0] == 1) && (mac.addr[2] == 0x5E )) + { + /* + * Update the address portion of the MGID with the 28 lower bits of the + * IP address. Since we're given a MAC address, we are using + * 24 lower bits of that network-byte-ordered value (assuming MSb + * is zero) and 4 lsb bits of the first byte of IP address. + */ + mcast_req.member_rec.mgid.raw[12] = mac.addr[1]; + mcast_req.member_rec.mgid.raw[13] = mac.addr[3]; + mcast_req.member_rec.mgid.raw[14] = mac.addr[4]; + mcast_req.member_rec.mgid.raw[15] = mac.addr[5]; + } + else + { + /* Handle non IP mutlicast MAC addresses. */ + /* Update the signature to use the lower 2 bytes of the OpenIB OUI. */ + mcast_req.member_rec.mgid.raw[2] = 0x14; + mcast_req.member_rec.mgid.raw[3] = 0x05; + /* Now copy the MAC address into the last 6 bytes of the GID. */ + cl_memcpy( &mcast_req.member_rec.mgid.raw[10], mac.addr, 6 ); + } + + mcast_req.mcast_context = p_port; + mcast_req.pfn_mcast_cb = __mcast_cb; + mcast_req.timeout_ms = p_port->p_adapter->params.sa_timeout; + mcast_req.retry_cnt = p_port->p_adapter->params.sa_retry_cnt; + mcast_req.port_guid = p_port->p_adapter->guids.port_guid.guid; + mcast_req.pkey_index = p_port->pkey_index; + mcast_req.member_rec.pkey = cl_hton16(p_port->p_adapter->guids.port_guid.pkey); + /* + * Create the endpoint and insert it in the port. Since we don't wait for + * the mcast SA operations to complete before returning from the multicast + * list set OID asynchronously, it is possible for the mcast entry to be + * cleared before the SA interaction completes. In this case, when the + * mcast callback is invoked, it would not find the corresponding endpoint + * and would be undone. + */ + p_endpt = ipoib_endpt_create( + &mcast_req.member_rec.mgid, 0, CL_HTON32(0x00FFFFFF) ); + if( !p_endpt ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ipoib_endpt_create failed.\n") ); + return IB_INSUFFICIENT_MEMORY; + } + + status = __endpt_mgr_insert_locked( p_port, mac, p_endpt ); + if( status != IB_SUCCESS ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("__endpt_mgr_insert_locked returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + return status; + } + + /* reference the object for the multicast join request. */ + ipoib_port_ref( p_port, ref_join_mcast ); + + status = p_port->p_adapter->p_ifc->join_mcast( p_port->ib_mgr.h_qp, &mcast_req ); + if( status != IB_SUCCESS ) + { + ipoib_port_deref( p_port, ref_mcast_join_failed ); + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_join_mcast returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + } + + IPOIB_EXIT( IPOIB_DBG_MCAST ); + return status; +} + + +static void +__mcast_cb( + IN ib_mcast_rec_t *p_mcast_rec ) +{ + ib_api_status_t status; + ipoib_port_t *p_port; + cl_fmap_item_t *p_item; + ipoib_endpt_t *p_endpt; + + IPOIB_ENTER( IPOIB_DBG_MCAST ); + + p_port = (ipoib_port_t*)p_mcast_rec->mcast_context; + + cl_obj_lock( &p_port->obj ); + while( p_port->endpt_rdr ) + { + cl_obj_unlock( &p_port->obj ); + cl_obj_lock( &p_port->obj ); + } + if( p_port->state != IB_QPS_RTS ) + { + cl_obj_unlock( &p_port->obj ); + if( p_mcast_rec->status == IB_SUCCESS ) + + { + ipoib_port_ref(p_port, ref_leave_mcast); + p_port->p_adapter->p_ifc->leave_mcast( p_mcast_rec->h_mcast, __leave_error_mcast_cb ); + } + ipoib_port_deref( p_port, ref_mcast_inv_state ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, + ("Invalid state - Aborting.\n") ); + return; + } + + if( p_mcast_rec->status != IB_SUCCESS ) + { + cl_obj_unlock( &p_port->obj ); + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Multicast join request failed with status %s.\n", + p_port->p_adapter->p_ifc->get_err_str( p_mcast_rec->status )) ); + /* Flag the adapter as hung. */ + p_port->p_adapter->hung =TRUE; + ipoib_port_deref( p_port, ref_mcast_req_failed ); + IPOIB_EXIT( IPOIB_DBG_MCAST ); + return; + } + + p_item = cl_fmap_get( + &p_port->endpt_mgr.gid_endpts, &p_mcast_rec->p_member_rec->mgid ); + if( p_item == cl_fmap_end( &p_port->endpt_mgr.gid_endpts ) ) + { + /* + * The endpoint must have been flushed while the join request + * was outstanding. Just leave the group and return. This + * is not an error. + */ + cl_obj_unlock( &p_port->obj ); + IPOIB_PRINT(TRACE_LEVEL_WARNING, IPOIB_DBG_ERROR, + ("Failed to find endpoint for update.\n") ); + + ipoib_port_ref(p_port, ref_leave_mcast); + p_port->p_adapter->p_ifc->leave_mcast( p_mcast_rec->h_mcast, __leave_error_mcast_cb ); + ipoib_port_deref( p_port, ref_mcast_no_endpt ); + IPOIB_EXIT( IPOIB_DBG_MCAST ); + return; + } + + p_endpt = PARENT_STRUCT( p_item, ipoib_endpt_t, gid_item ); + p_endpt->p_ifc = p_port->p_adapter->p_ifc; + + /* Setup the endpoint for use. */ + status = ipoib_endpt_set_mcast( + p_endpt, p_port->ib_mgr.h_pd, p_port->port_num, p_mcast_rec ); + if( status != IB_SUCCESS ) + { + cl_obj_unlock( &p_port->obj ); + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_MCAST, + ("ipoib_endpt_set_mcast returned %s.\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + /* Flag the adapter as hung. */ + p_port->p_adapter->hung = TRUE; + ipoib_port_deref( p_port, ref_mcast_av_failed ); + IPOIB_EXIT( IPOIB_DBG_MCAST ); + return; + } + + /* + * The endpoint is already in the GID and MAC maps. + * mast endpoint are not used in the LID map. + */ + CL_ASSERT(p_endpt->dlid == 0); + /* set flag that endpoint is use */ + p_endpt->is_in_use = TRUE; + cl_obj_unlock( &p_port->obj ); + + /* Try to send all pending sends. */ + ipoib_port_resume( p_port ); + + ipoib_port_deref( p_port, ref_join_mcast ); + + IPOIB_EXIT( IPOIB_DBG_MCAST ); +} + + +void +ipoib_leave_mcast_cb( + IN void *context ) +{ + ipoib_port_t *p_port; + + IPOIB_ENTER( IPOIB_DBG_MCAST ); + + p_port = (ipoib_port_t*)context; + + IPOIB_PRINT( TRACE_LEVEL_VERBOSE, IPOIB_DBG_MCAST,("p_port->mcast_cnt = %d\n", p_port->mcast_cnt)); + + ipoib_port_deref( p_port, ref_leave_mcast); + cl_atomic_dec( &p_port->mcast_cnt); + + if(0 == p_port->mcast_cnt) + { + KeSetEvent( &p_port->leave_mcast_event, EVENT_INCREMENT, FALSE ); + } + + IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_MCAST, + ("Leave mcast callback deref ipoib_port \n") ); + + IPOIB_EXIT( IPOIB_DBG_MCAST ); +} + + + +void +__leave_error_mcast_cb( + IN void *context ) +{ + ipoib_port_t *p_port; + + IPOIB_ENTER( IPOIB_DBG_MCAST ); + + p_port = (ipoib_port_t*)context; + + ipoib_port_deref( p_port, ref_leave_mcast); + IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_MCAST, + ("Leave mcast callback deref ipoib_port \n") ); + + IPOIB_EXIT( IPOIB_DBG_MCAST ); +} + + +NDIS_STATUS GetLsoHeaderSize( + IN ipoib_port_t* const pPort, + IN PNDIS_BUFFER CurrBuffer, + IN LsoData *pLsoData, + OUT uint16_t *pSize, + OUT INT *IndexOfData, + IN ipoib_hdr_t *ipoib_hdr + ) + { + UINT CurrLength; + PUCHAR pSrc; + PUCHAR pCopiedData = pLsoData->coppied_data; + ip_hdr_t UNALIGNED *IpHdr; + tcp_hdr_t UNALIGNED *TcpHdr; + uint16_t TcpHeaderLen; + uint16_t IpHeaderLen; + uint16_t IpOffset; + INT FullBuffers = 0; + NDIS_STATUS status = NDIS_STATUS_INVALID_PACKET; + // + // This Flag indicates the way we gets the headers + // RegularFlow = we get the headers (ETH+IP+TCP) in the same Buffer + // in sequence. + // +#define IP_OFFSET 14; + boolean_t IsRegularFlow = TRUE; + const uint16_t ETH_OFFSET = IP_OFFSET; + *pSize = 0; + UNUSED_PARAM(pPort); + IpOffset = IP_OFFSET; //(uint16_t)pPort->EncapsulationFormat.EncapsulationHeaderSize; + *IndexOfData = 0; + NdisQueryBufferSafe( CurrBuffer, &pSrc, &CurrLength, NormalPagePriority ); + if (pSrc == NULL) { + IPOIB_PRINT(TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, ("Error processing packets\n")); + return status; + } + // We start by looking for the ethernet and the IP + if (CurrLength < ETH_OFFSET) { + IPOIB_PRINT(TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, ("Error porcessing packets\n")); + return status; + } + //*pSize = *pSize + ETH_OFFSET; + if (CurrLength == ETH_OFFSET) { + ASSERT(FALSE); + IsRegularFlow = FALSE; + memcpy(pCopiedData, pSrc, ETH_OFFSET); + pCopiedData += ETH_OFFSET; + FullBuffers++; + // First buffer was only ethernet + NdisGetNextBuffer( CurrBuffer, &CurrBuffer); + NdisQueryBufferSafe( CurrBuffer, &pSrc, &CurrLength, NormalPagePriority ); + if (pSrc == NULL) { + IPOIB_PRINT(TRACE_LEVEL_VERBOSE, IPOIB_DBG_ERROR, ("Error porcessing packets\n")); + return status; + } + } else { + // This is ETH + IP together (at least) + pLsoData->LsoBuffers[0].pData = pSrc + (ETH_OFFSET - sizeof (ipoib_hdr_t)); + memcpy (pLsoData->LsoBuffers[0].pData, ipoib_hdr, sizeof (ipoib_hdr_t)); + CurrLength -= ETH_OFFSET; + pSrc = pSrc + ETH_OFFSET; + *pSize = *pSize + sizeof (ipoib_hdr_t); + } + // we should now be having at least the size of ethernet data + if (CurrLength < sizeof (ip_hdr_t)) { + IPOIB_PRINT(TRACE_LEVEL_VERBOSE, IPOIB_DBG_ERROR, ("Error porcessing packets\n")); + return status; + } + IpHdr = (ip_hdr_t UNALIGNED*)pSrc; + IpHeaderLen = (uint16_t)IP_HEADER_LENGTH(IpHdr); + ASSERT(IpHdr->prot == PROTOCOL_TCP); + if (CurrLength < IpHeaderLen) { + IPOIB_PRINT(TRACE_LEVEL_VERBOSE, IPOIB_DBG_ERROR, ("Error processing packets\n")); + return status; + } + *pSize = *pSize + IpHeaderLen; + // We now start to find where the TCP header starts + if (CurrLength == IpHeaderLen) { + ASSERT(FALSE); + // two options : + // if(IsRegularFlow = FALSE) ==> ETH and IP seperated in two buffers + // if(IsRegularFlow = TRUE ) ==> ETH and IP in the same buffer + // TCP will start at next buffer + if(IsRegularFlow){ + memcpy(pCopiedData, pSrc-ETH_OFFSET ,ETH_OFFSET+IpHeaderLen); + pCopiedData += (ETH_OFFSET + IpHeaderLen); + } else { + memcpy(pCopiedData, pSrc,IpHeaderLen); + pCopiedData += IpHeaderLen; + } + + FullBuffers++; + IsRegularFlow = FALSE; + NdisGetNextBuffer( CurrBuffer, &CurrBuffer); + NdisQueryBufferSafe( CurrBuffer, &pSrc, &CurrLength, NormalPagePriority ); + + if (pSrc == NULL) { + IPOIB_PRINT(TRACE_LEVEL_VERBOSE, IPOIB_DBG_ERROR, ("Error porcessing packets\n")); + return status; + } + } else { + // if(IsRegularFlow = TRUE ) ==> the ETH and IP and TCP in the same buffer + // if(IsRegularFlow = FLASE ) ==> ETH in one buffer , IP+TCP together in the same buffer + if (IsRegularFlow) { + pLsoData->LsoBuffers[0].Len += IpHeaderLen; + } else { + memcpy(pCopiedData, pSrc, IpHeaderLen); + pCopiedData += IpHeaderLen; + } + + CurrLength -= IpHeaderLen; + pSrc = pSrc + IpHeaderLen; + } + if (CurrLength < sizeof (tcp_hdr_t)) { + IPOIB_PRINT(TRACE_LEVEL_VERBOSE, IPOIB_DBG_ERROR, ("Error porcessing packets\n")); + return status; + } + // We have finaly found the TCP header + TcpHdr = (tcp_hdr_t UNALIGNED *)pSrc; + TcpHeaderLen = TCP_HEADER_LENGTH(TcpHdr); + + ASSERT(TcpHeaderLen == 20); + + if (CurrLength < TcpHeaderLen) { + //IPOIB_PRINT(TRACE_LEVEL_VERBOSE, ETH, ("Error porcessing packets\n")); + return status; + } + *pSize = *pSize + TcpHeaderLen; + if(IsRegularFlow){ + pLsoData->LsoBuffers[0].Len += TcpHeaderLen; + } + else{ + memcpy(pCopiedData, pSrc, TcpHeaderLen); + pCopiedData += TcpHeaderLen; + } + if (CurrLength == TcpHeaderLen) { + FullBuffers++; + pLsoData->UsedBuffers = FullBuffers; + *IndexOfData = FullBuffers ; + } else { + pLsoData->UsedBuffers = FullBuffers + 1; + *IndexOfData = FullBuffers - 1; + } + pLsoData->FullBuffers = FullBuffers; + if (!IsRegularFlow){ + pLsoData->LsoBuffers[0].pData = pLsoData->coppied_data; + pLsoData->LsoBuffers[0].Len = ETH_OFFSET + IpHeaderLen + TcpHeaderLen; + ASSERT(pLsoData->LsoBuffers[0].Len <= LSO_MAX_HEADER); + } + return NDIS_STATUS_SUCCESS; +} + +static void __port_do_mcast_garbage(ipoib_port_t* const p_port) +{ + const mac_addr_t DEFAULT_MCAST_GROUP = {0x01, 0x00, 0x5E, 0x00, 0x00, 0x01}; + /* Do garbage collecting... */ + + cl_map_item_t *p_item; + ipoib_endpt_t *p_endpt; + cl_qlist_t destroy_mc_list; + uint8_t cnt; + const static GC_MAX_LEAVE_NUM = 80; + + cl_qlist_init( &destroy_mc_list ); + + cl_obj_lock( &p_port->obj ); + /* Wait for all readers to finish */ + while( p_port->endpt_rdr ) + { + cl_obj_unlock( &p_port->obj ); + cl_obj_lock( &p_port->obj ); + } + cnt = 0; + p_item = cl_qmap_head( &p_port->endpt_mgr.mac_endpts ); + while( (p_item != cl_qmap_end( &p_port->endpt_mgr.mac_endpts )) && (cnt < GC_MAX_LEAVE_NUM)) + { + p_endpt = PARENT_STRUCT( p_item, ipoib_endpt_t, mac_item ); + p_item = cl_qmap_next( p_item ); + + /* Check if the current endpoint is not a multicast listener */ + + if( p_endpt->h_mcast && + (!p_endpt->is_mcast_listener) && + ( cl_memcmp( &p_endpt->mac, &DEFAULT_MCAST_GROUP, sizeof(mac_addr_t) ) && + (!p_endpt->is_in_use) )) + { + cl_qmap_remove_item( &p_port->endpt_mgr.mac_endpts, + &p_endpt->mac_item ); + cl_fmap_remove_item( &p_port->endpt_mgr.gid_endpts, + &p_endpt->gid_item ); + + if( p_endpt->dlid ) + { + cl_qmap_remove_item( &p_port->endpt_mgr.lid_endpts, + &p_endpt->lid_item ); + p_endpt->dlid = 0; + } + + cl_qlist_insert_tail( + &destroy_mc_list, &p_endpt->mac_item.pool_item.list_item ); + cnt++; + } + else + p_endpt->is_in_use = FALSE; + } + cl_obj_unlock( &p_port->obj ); + + /* Destroy all multicast endpoints now that we have released the lock. */ + while( cl_qlist_count( &destroy_mc_list ) ) + { + p_endpt = PARENT_STRUCT( cl_qlist_remove_head( &destroy_mc_list ), + ipoib_endpt_t, mac_item.pool_item.list_item ); + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_ENDPT, + ("mcast garbage collector: destroying endpoint %02x:%02x:%02x:%02x:%02x:%02x \n", + p_endpt->mac.addr[0], + p_endpt->mac.addr[1], + p_endpt->mac.addr[2], + p_endpt->mac.addr[3], + p_endpt->mac.addr[4], + p_endpt->mac.addr[5]) ); + cl_obj_destroy( &p_endpt->obj ); + } +} + +static void __port_mcast_garbage_dpc(KDPC *p_gc_dpc,void *context,void *s_arg1, void *s_arg2) +{ + ipoib_port_t *p_port = context; + + UNREFERENCED_PARAMETER(p_gc_dpc); + UNREFERENCED_PARAMETER(s_arg1); + UNREFERENCED_PARAMETER(s_arg2); + + __port_do_mcast_garbage(p_port); +} + + diff --git a/branches/WOF2-3/ulp/ipoib/kernel/ipoib_port.h b/branches/WOF2-3/ulp/ipoib/kernel/ipoib_port.h new file mode 100644 index 00000000..c3dcac1b --- /dev/null +++ b/branches/WOF2-3/ulp/ipoib/kernel/ipoib_port.h @@ -0,0 +1,651 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2006 Mellanox Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + +#ifndef _IPOIB_PORT_H_ +#define _IPOIB_PORT_H_ + + +#include +#include +#include +#include +#include +#include "ipoib_endpoint.h" +#include "ipoib_xfr_mgr.h" + + +/* + * Define to place receive buffer inline in receive descriptor. + */ +#define IPOIB_INLINE_RECV 1 + + +/* Max send data segment list size. */ +#define MAX_SEND_SGE 30 //TODO optimize this value + + +/* + * Invalid pkey index + */ +#define PKEY_INVALID_INDEX 0xFFFF + +/* + * Define to control how transfers are done. When defined as 1, causes + * packets to be sent using NDIS DMA facilities (getting the SGL from the + * packet). When defined as 0, uses the NDIS_BUFFER structures as MDLs + * to get the physical page mappings of the buffers. + */ +#define IPOIB_USE_DMA 1 + + +#define IPOIB_PORT_FROM_PACKET( P ) \ + (((ipoib_port_t**)P->MiniportReservedEx)[0]) +#define IPOIB_ENDPT_FROM_PACKET( P ) \ + (((ipoib_endpt_t**)P->MiniportReservedEx)[1]) +#define IPOIB_RECV_FROM_PACKET( P ) \ + (((ipoib_recv_desc_t**)P->MiniportReservedEx)[1]) +#define IPOIB_SEND_FROM_PACKET( P ) \ + (((send_buf_t**)P->MiniportReservedEx)[2]) +#define IPOIB_PACKET_FROM_LIST_ITEM( I ) \ + (PARENT_STRUCT( I, NDIS_PACKET, MiniportReservedEx )) +#define IPOIB_LIST_ITEM_FROM_PACKET( P ) \ + ((cl_list_item_t*)P->MiniportReservedEx) + + +typedef struct _ipoib_ib_mgr +{ + ib_ca_handle_t h_ca; + ib_pd_handle_t h_pd; + ib_cq_handle_t h_recv_cq; + ib_cq_handle_t h_send_cq; + ib_qp_handle_t h_qp; + ib_query_handle_t h_query; + net32_t qpn; + + ib_mr_handle_t h_mr; + net32_t lkey; + + uint8_t rate; + ib_member_rec_t bcast_rec; + +} ipoib_ib_mgr_t; +/* +* FIELDS +* h_ca +* CA handle for all IB resources. +* +* h_pd +* PD handle for all IB resources. +* +* h_recv_cq +* Recv CQ handle. +* +* h_send_cq +* Send CQ handle. +* +* h_qp +* QP handle for data transfers. +* +* h_query +* Query handle for cancelling SA queries. +* +* h_mr +* Registration handle for all of physical memory. Used for +* send/receive buffers to simplify growing the receive pool. +* +* lkey +* LKey for the memory region. +* +* bcast_rec +* Cached information about the broadcast group, used to specify +* parameters used to join other multicast groups. +*********/ + + +#include +/****s* IPoIB Driver/ipoib_hdr_t +* NAME +* ipoib_hdr_t +* +* DESCRIPTION +* IPoIB packet header. +* +* SYNOPSIS +*/ +typedef struct _ipoib_hdr +{ + net16_t type; + net16_t resv; + +} PACK_SUFFIX ipoib_hdr_t; +/* +* FIELDS +* type +* Protocol type. +* +* resv +* Reserved portion of IPoIB header. +*********/ + +typedef struct _ipoib_arp_pkt +{ + net16_t hw_type; + net16_t prot_type; + uint8_t hw_size; + uint8_t prot_size; + net16_t op; + ipoib_hw_addr_t src_hw; + net32_t src_ip; + ipoib_hw_addr_t dst_hw; + net32_t dst_ip; + +} PACK_SUFFIX ipoib_arp_pkt_t; + + +/****s* IPoIB Driver/ipoib_pkt_t +* NAME +* ipoib_pkt_t +* +* DESCRIPTION +* Represents an IPoIB packet with no GRH. +* +* SYNOPSIS +*/ +typedef struct _ipoib_pkt +{ + ipoib_hdr_t hdr; + union _payload + { + uint8_t data[MAX_PAYLOAD_MTU]; + ipoib_arp_pkt_t arp; + ip_pkt_t ip; + + } PACK_SUFFIX type; + +} PACK_SUFFIX ipoib_pkt_t; +/* +* FIELDS +* hdr +* IPoIB header. +* +* type +* Union for different types of payloads. +* +* type.data +* raw packet. +* +* type.ib_arp +* IPoIB ARP packet. +* +* type.arp +* Ethernet ARP packet. +* +* type.ip +* IP packet. +*********/ + + +/****s* IPoIB Driver/recv_buf_t +* NAME +* recv_buf_t +* +* DESCRIPTION +* Represents a receive buffer, including the ethernet header +* used to indicate the receive to the OS. +* +* SYNOPSIS +*/ +typedef union _recv_buf +{ + struct _recv_buf_type_eth + { + uint8_t pad[sizeof(ib_grh_t) + + sizeof(ipoib_hdr_t) - + sizeof(eth_hdr_t)]; + eth_pkt_t pkt; /* data starts at sizeof(grh)+sizeof(eth_hdr) */ + + } PACK_SUFFIX eth; + + struct _recv_buf_type_ib + { + ib_grh_t grh; /* Must be same offset as lcl_rt.ib.pkt */ + ipoib_pkt_t pkt; /* data starts at 10+grh+4 */ + + } PACK_SUFFIX ib; + +} PACK_SUFFIX recv_buf_t; +/* +* FIELDS +* eth.pkt +* Ethernet packet, used to indicate the receive to the OS. +* +* ib.grh +* GRH for a globally routed received packet. +* +* ib.pkt +* IPOIB packet representing a globally routed received packet. +* +* NOTES +* When posting the work request, the address of ib.grh is used. +* +* TODO: Do we need a pad to offset the header so that the data ends up +* aligned on a pointer boundary? +*********/ + +/****s* IPoIB Driver/send_buf_t +* NAME +* send_buf_t +* +* DESCRIPTION +* Represents a send buffer, used to convert packets to IPoIB format. +* +* SYNOPSIS +*/ +typedef union _send_buf +{ + uint8_t data[MAX_PAYLOAD_MTU]; + ipoib_arp_pkt_t arp; + ip_pkt_t ip; + +} PACK_SUFFIX send_buf_t; +/* +* FIELDS +* data +* IP/ARP packet. +* +* NOTES +* TODO: Do we need a pad to offset the header so that the data ends up +* aligned on a pointer boundary? +*********/ +#include + + +typedef struct _ipoib_buf_mgr +{ + cl_qpool_t recv_pool; + + NDIS_HANDLE h_packet_pool; + NDIS_HANDLE h_buffer_pool; + + NPAGED_LOOKASIDE_LIST send_buf_list; + NDIS_HANDLE h_send_pkt_pool; + NDIS_HANDLE h_send_buf_pool; + +} ipoib_buf_mgr_t; +/* +* FIELDS +* recv_pool +* Pool of ipoib_recv_desc_t structures. +* +* h_packet_pool +* NDIS packet pool, used to indicate receives to NDIS. +* +* h_buffer_pool +* NDIS buffer pool, used to indicate receives to NDIS. +* +* send_buf_list +* Lookaside list for dynamically allocating send buffers for send +* that require copies (ARP, DHCP, and any with more physical pages +* than can fit in the local data segments). +*********/ + + +typedef enum _ipoib_pkt_type +{ + PKT_TYPE_UCAST, + PKT_TYPE_BCAST, + PKT_TYPE_MCAST + +} ipoib_pkt_type_t; + + +typedef struct _ipoib_recv_desc +{ + cl_pool_item_t item; /* Must be first. */ + uint32_t len; + ipoib_pkt_type_t type; + ib_recv_wr_t wr; + ib_local_ds_t local_ds[2]; + NDIS_TCP_IP_CHECKSUM_PACKET_INFO ndis_csum; +#if IPOIB_INLINE_RECV + recv_buf_t buf; +#else + recv_buf_t *p_buf; +#endif + +} ipoib_recv_desc_t; +/* +* FIELDS +* item +* Pool item for storing descriptors in a pool. +* +* len +* Length to indicate to NDIS. This is different than the length of the +* received data as some data is IPoIB specific and filtered out. +* +* type +* Type of packet, used in filtering received packets against the packet +* filter. Also used to update stats. +* +* wr +* Receive work request. +* +* local_ds +* Local data segments. The second segment is only used if a buffer +* spans physical pages. +* +* buf +* Buffer for the receive. +* +* NOTES +* The pool item is always first to allow casting form a cl_pool_item_t or +* cl_list_item_t to the descriptor. +*********/ + + +typedef struct _ipoib_send_desc +{ + NDIS_PACKET *p_pkt; + ipoib_endpt_t *p_endpt1; + send_buf_t *p_buf; + ib_send_wr_t wr; + ipoib_hdr_t pkt_hdr; + ib_local_ds_t local_ds[MAX_SEND_SGE]; /* Must be last. */ + +} ipoib_send_desc_t; +/* +* FIELDS +* p_pkt +* Pointer to the NDIS_PACKET associated with the send operation. +* +* p_endpt +* Endpoint for this send. +* +* p_buf +* Buffer for the send, if allocated. +* +* wr +* Send work request. +* +* pkt_hdr +* IPoIB packet header, pointed to by the first local datasegment. +* +* local_ds +* Local data segment array. Placed last to allow allocating beyond the +* end of the descriptor for additional datasegments. +* +* NOTES +* The pool item is always first to allow casting form a cl_pool_item_t or +* cl_list_item_t to the descriptor. +*********/ + + +typedef struct _ipoib_recv_mgr +{ + int32_t depth; + + NDIS_PACKET **recv_pkt_array; + + cl_qlist_t done_list; + +} ipoib_recv_mgr_t; +/* +* FIELDS +* depth +* Current number of WRs posted. +* +* p_head +* Pointer to work completion in descriptor at the head of the QP. +* +* p_tail +* Pointer to the work completion in the descriptor at the tail of the QP. +* +* recv_pkt_array +* Array of pointers to NDIS_PACKET used to indicate receives. +* +* done_list +* List of receive descriptors that need to be indicated to NDIS. +*********/ + + +typedef struct _ipoib_send_mgr +{ + atomic32_t depth; + cl_qlist_t pending_list; + +} ipoib_send_mgr_t; +/* +* FIELDS +* depth +* Current number of WRs posted, used to queue pending requests. +* +* pending_list +* List of NDIS_PACKET structures that are awaiting available WRs to send. +*********/ + + +typedef struct _ipoib_endpt_mgr +{ + cl_qmap_t mac_endpts; + cl_fmap_t gid_endpts; + cl_qmap_t lid_endpts; + +} ipoib_endpt_mgr_t; +/* +* FIELDS +* mac_endpts +* Map of enpoints, keyed by MAC address. +* +* gid_endpts +* Map of enpoints, keyed by GID. +* +* lid_endpts +* Map of enpoints, keyed by LID. Only enpoints on the same subnet +* are inserted in the LID map. +*********/ + + +typedef struct _ipoib_port +{ + cl_obj_t obj; + cl_obj_rel_t rel; + + ib_qp_state_t state; + + cl_spinlock_t recv_lock; + cl_spinlock_t send_lock; + + struct _ipoib_adapter *p_adapter; + uint8_t port_num; + + KEVENT sa_event; + + atomic32_t mcast_cnt; + KEVENT leave_mcast_event; + + ipoib_ib_mgr_t ib_mgr; + + ipoib_buf_mgr_t buf_mgr; + + ipoib_recv_mgr_t recv_mgr; + ipoib_send_mgr_t send_mgr; + + ipoib_endpt_mgr_t endpt_mgr; + + ipoib_endpt_t *p_local_endpt; + +#if DBG + atomic32_t ref[ref_array_size]; +#endif + + atomic32_t endpt_rdr; + + atomic32_t hdr_idx; + uint16_t pkey_index; + KDPC gc_dpc; + KTIMER gc_timer; + uint32_t bc_join_retry_cnt; + ib_net16_t base_lid; + PIO_WORKITEM pPoWorkItem; + ipoib_hdr_t hdr[1]; /* Must be last! */ + +} ipoib_port_t; +/* +* FIELDS +* obj +* Complib object for reference counting, relationships, +* and destruction synchronization. +* +* rel +* Relationship to associate the port with the adapter. +* +* state +* State of the port object. Tracks QP state fairly closely. +* +* recv_lock +* Spinlock to protect receive operations. +* +* send_lock +* Spinlock to protect send operations. +* +* p_adapter +* Parent adapter. Used to get AL handle. +* +* port_num +* Port number of this adapter. +* +* ib_mgr +* IB resource manager. +* +* recv_mgr +* Receive manager. +* +* send_mgr +* Send manager. +* +* endpt_mgr +* Endpoint manager. +*********/ + + +ib_api_status_t +ipoib_create_port( + IN struct _ipoib_adapter* const p_adapter, + IN ib_pnp_port_rec_t* const p_pnp_rec, + OUT ipoib_port_t** const pp_port ); + +void +ipoib_port_destroy( + IN ipoib_port_t* const p_port ); + +void +ipoib_port_up( + IN ipoib_port_t* const p_port, + IN const ib_pnp_port_rec_t* const p_pnp_rec ); + +void +ipoib_port_down( + IN ipoib_port_t* const p_port ); + +ib_api_status_t +ipoib_port_join_mcast( + IN ipoib_port_t* const p_port, + IN const mac_addr_t mac, + IN const uint8_t state ); + + +void +ipoib_leave_mcast_cb( + IN void *context ); + + +void +ipoib_port_remove_endpt( + IN ipoib_port_t* const p_port, + IN const mac_addr_t mac ); + +void +ipoib_port_send( + IN ipoib_port_t* const p_port, + IN NDIS_PACKET **p_packet_array, + IN uint32_t num_packets ); + +void +ipoib_return_packet( + IN NDIS_HANDLE adapter_context, + IN NDIS_PACKET *p_packet ); + +void +ipoib_port_resume( + IN ipoib_port_t* const p_port ); + +NTSTATUS +ipoib_mac_to_gid( + IN ipoib_port_t* const p_port, + IN const mac_addr_t mac, + OUT ib_gid_t* p_gid ); + +NTSTATUS +ipoib_mac_to_path( + IN ipoib_port_t* const p_port, + IN const mac_addr_t mac, + OUT ib_path_rec_t* p_path ); + +inline void ipoib_port_ref( + IN ipoib_port_t * p_port, + IN int type); + +inline void ipoib_port_deref( + IN ipoib_port_t * p_port, + IN int type); + +#if DBG +// This function is only used to monitor send failures +static inline VOID NdisMSendCompleteX( + IN NDIS_HANDLE MiniportAdapterHandle, + IN PNDIS_PACKET Packet, + IN NDIS_STATUS Status + ) { + if (Status != NDIS_STATUS_SUCCESS) { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Sending status other than Success to NDIS\n")); + } + NdisMSendComplete(MiniportAdapterHandle,Packet,Status); +} +#else +#define NdisMSendCompleteX NdisMSendComplete +#endif + +#endif /* _IPOIB_PORT_H_ */ diff --git a/branches/WOF2-3/ulp/ipoib/kernel/ipoib_stat.c b/branches/WOF2-3/ulp/ipoib/kernel/ipoib_stat.c new file mode 100644 index 00000000..29675ebf --- /dev/null +++ b/branches/WOF2-3/ulp/ipoib/kernel/ipoib_stat.c @@ -0,0 +1,37 @@ +#include "ipoib_adapter.h" +#include "ipoib_debug.h" + +#if defined (EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "ipoib_stat.tmh" +#endif + +IPOIB_ST_STAT g_stat; + +void ipoib_st_dev_rmv( PIPOIB_ST_DEVICE p_stat ) +{ + if ( p_stat ) + p_stat->valid = FALSE; +} + +PIPOIB_ST_DEVICE ipoib_st_dev_add() +{ + int i; + + for ( i = 0; i < IPOIB_ST_MAX_DEVICES; ++i ) { + if ( g_stat.dev[i].valid == FALSE ) { + g_stat.dev[i].valid = TRUE; + return &g_stat.dev[i]; + } + } + + return NULL; +} + +void ipoib_st_init() +{ + memset( &g_stat, 0, sizeof(g_stat) ); +} + diff --git a/branches/WOF2-3/ulp/ipoib/kernel/ipoib_stat.h b/branches/WOF2-3/ulp/ipoib/kernel/ipoib_stat.h new file mode 100644 index 00000000..08e83501 --- /dev/null +++ b/branches/WOF2-3/ulp/ipoib/kernel/ipoib_stat.h @@ -0,0 +1,80 @@ +/*++ + +Copyright (c) 2005-2009 Mellanox Technologies. All rights reserved. + +Module Name: + ipoib_stat.h + +Abstract: + Statistics Collector header file + +Revision History: + +Notes: + +--*/ + +#pragma once + +#include + +// +// restrictions +// + +#define IPOIB_ST_MAX_DEVICES 16 + +// +// enums +// + +// +// structures +// + +// device +typedef struct _ipoib_adapter ipoib_adapter_t; +typedef struct _ipoib_port ipoib_port_t; + + +typedef struct _IPOIB_ST_DEVICE +{ + boolean_t valid; // all the structure is valid + ipoib_adapter_t *p_adapter; // current + ipoib_port_t *p_prev_port; // previous value of p_port in p_adapter + PRKTHREAD p_halt_thread; // thread, calling ipoib_halt + int n_power_irps; // NdisDevicePnPEventPowerProfileChanged + int n_pnp_irps; // NdisDevicePnPEventSurpriseRemoved + +} IPOIB_ST_DEVICE, *PIPOIB_ST_DEVICE; + +// driver +typedef struct _IPOIB_ST_DRIVER +{ + PDRIVER_OBJECT obj; + +} IPOIB_ST_DRIVER, *PIPOIB_ST_DRIVER; + +// driver stack + +typedef struct _IPOIB_ST_STAT +{ + IPOIB_ST_DRIVER drv; + IPOIB_ST_DEVICE dev[IPOIB_ST_MAX_DEVICES]; + +} IPOIB_ST_STAT, *PIPOIB_ST_STAT; + +extern IPOIB_ST_STAT g_stat; + +// +// functions +// + +void ipoib_st_dev_rmv( PIPOIB_ST_DEVICE p_stat ); + +PIPOIB_ST_DEVICE ipoib_st_dev_add(); + +void ipoib_st_init(); + + + diff --git a/branches/WOF2-3/ulp/ipoib/kernel/ipoib_xfr_mgr.c b/branches/WOF2-3/ulp/ipoib/kernel/ipoib_xfr_mgr.c new file mode 100644 index 00000000..0fc4f102 --- /dev/null +++ b/branches/WOF2-3/ulp/ipoib/kernel/ipoib_xfr_mgr.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2008 Mellanox Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: ipoib_xfr_mgr.c 3459 2008-11-12 16:48:21Z tzachid $ + */ + + +#include "ipoib_xfr_mgr.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "ipoib_xfr_mgr.tmh" +#endif + + +const ipoib_guid2mac_translation_t guid2mac_table[] = { + {0x30, 0x48, 0xE7}, + {0x05, 0xAD, 0xE7}, + {0x18, 0x8B, 0xE7}, + {0x1A, 0x4B, 0xE7}, + {0x17, 0x08, 0xE7}, + {0x1E, 0x0B, 0xE7}, + + {0x00, 0x00, 0x00}, +}; + diff --git a/branches/WOF2-3/ulp/ipoib/kernel/ipoib_xfr_mgr.h b/branches/WOF2-3/ulp/ipoib/kernel/ipoib_xfr_mgr.h new file mode 100644 index 00000000..b2a4cd55 --- /dev/null +++ b/branches/WOF2-3/ulp/ipoib/kernel/ipoib_xfr_mgr.h @@ -0,0 +1,504 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#ifndef _IPOIB_XFR_MGR_H_ +#define _IPOIB_XFR_MGR_H_ + + +#include +#include +#include +#include +#include +#include +#include + + +#include "ipoib_driver.h" +#include "ip_stats.h" +#include + + +#include +/****s* IPoIB Driver/ipoib_hw_addr_t +* NAME +* ipoib_hw_addr_t +* +* DESCRIPTION +* The ipoib_hw_addr_t structure defines an IPoIB compatible hardware +* address. Values in this structure are stored in network order. +* +* SYNOPSIS +*/ +typedef struct _ipoib_hw_addr +{ + uint32_t flags_qpn; + ib_gid_t gid; + +} PACK_SUFFIX ipoib_hw_addr_t; +/* +* FIELDS +* flags_qpn +* Flags and queue pair number. Use ipoib_addr_get_flags, +* ipoib_addr_set_flags, ipoib_addr_set_qpn, and ipoib_addr_get_qpn +* to manipulate the contents. +* +* gid +* IB GID value. +* +* SEE ALSO +* IPoIB, ipoib_addr_get_flags, ipoib_addr_set_flags, ipoib_addr_set_qpn, +* ipoib_addr_get_qpn +*********/ +#include + +/****s* IPoIB Driver/ipoib_guid2mac_translation_t +* NAME +* ipoib_guid2mac_translation_t +* +* DESCRIPTION +* The ipoib_guid2mac_translation_t structure defines a GUID to MAC translation. +* The structure holds map between known OUI to an appropriate GUID mask. +* +* SYNOPSIS +*/ +typedef struct _ipoib_guid2mac_translation_ +{ + uint8_t second_byte; + uint8_t third_byte; + uint8_t guid_mask; + +} ipoib_guid2mac_translation_t; +/* +* FIELDS +* second_byte +* second byte of OUI (located in lower three bytes of GUID). +* +* third_byte +* third byte of OUI (located in lower three bytes of GUID). +* +* guid_mask +* GUID mask that will be used to generate MAC from the GUID. +* +* SEE ALSO +* IPoIB, ipoib_mac_from_guid_mask +*********/ + +extern const ipoib_guid2mac_translation_t guid2mac_table[]; + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/* + * Address accessors + */ + +static inline uint8_t +ipoib_addr_get_flags( + IN const ipoib_hw_addr_t* const p_addr ) +{ + return (uint8_t)(cl_ntoh32( p_addr->flags_qpn ) >> 24); +} + +static inline void +ipoib_addr_set_flags( + IN ipoib_hw_addr_t* const p_addr, + IN const uint8_t flags ) +{ + p_addr->flags_qpn &= cl_ntoh32( 0xFFFFFF00 ); + p_addr->flags_qpn |= cl_ntoh32( flags ); +} + +static inline net32_t +ipoib_addr_get_qpn( + IN const ipoib_hw_addr_t* const p_addr ) +{ + return cl_ntoh32( cl_ntoh32( p_addr->flags_qpn ) >> 8 ); +} + +static inline void +ipoib_addr_set_qpn( + IN ipoib_hw_addr_t* const p_addr, + IN const net32_t qpn ) +{ + p_addr->flags_qpn = cl_ntoh32( (cl_ntoh32( + p_addr->flags_qpn ) & 0x000000FF ) | (cl_ntoh32( qpn ) << 8) ); +} + + +/****f* IPOIB/ipoib_mac_from_sst_guid +* NAME +* ipoib_mac_from_sst_guid +* +* DESCRIPTION +* Generates an ethernet MAC address given a SilverStorm port GUID. +* +* SYNOPSIS +*/ +static inline ib_api_status_t +ipoib_mac_from_sst_guid( + IN const net64_t port_guid, + OUT mac_addr_t* const p_mac_addr ) +{ + const uint8_t *p_guid = (const uint8_t*)&port_guid; + uint32_t low24; + + /* Port guid is in network byte order. OUI is in lower 3 bytes. */ + ASSERT( p_guid[0] == 0x00 && p_guid[1] == 0x06 && p_guid[2] == 0x6a ); + + /* + * We end up using only the lower 23-bits of the GUID. Trap that + * the 24th (bit 23) through 27th (bit 26) bit aren't set. + */ + if( port_guid & CL_HTON64( 0x0000000007800000 ) ) + return IB_INVALID_GUID; + + low24 = 0x00FFF000 - + ((((uint32_t)cl_ntoh64( port_guid ) & 0x00FFFFFF) - 0x101) * 2); + low24 -= p_guid[3]; /* minus port number */ + + p_mac_addr->addr[0] = p_guid[0]; + p_mac_addr->addr[1] = p_guid[1]; + p_mac_addr->addr[2] = p_guid[2]; + p_mac_addr->addr[3] = (uint8_t)(low24 >> 16); + p_mac_addr->addr[4] = (uint8_t)(low24 >> 8); + p_mac_addr->addr[5] = (uint8_t)low24; + + return IB_SUCCESS; +} +/* +* PARAMETERS +* port_guid +* The port GUID, in network byte order, for which to generate a +* MAC address. +* +* p_mac_addr +* Pointer to a mac address in which to store the results. +* +* RETURN VALUES +* IB_SUCCESS +* The MAC address was successfully converted. +* +* IB_INVALID_GUID +* The port GUID provided was not a known GUID format. +* +* NOTES +* The algorithm to convert portGuid to MAC address is as per DN0074, and +* assumes a 2 port HCA. +* +* SEE ALSO +* IPOIB +*********/ + + +/****f* IPOIB/ipoib_mac_from_mlx_guid +* NAME +* ipoib_mac_from_mlx_guid +* +* DESCRIPTION +* Generates an ethernet MAC address given a Mellanox port GUID. +* +* SYNOPSIS +*/ +static inline ib_api_status_t +ipoib_mac_from_mlx_guid( + IN const net64_t port_guid, + OUT mac_addr_t* const p_mac_addr ) +{ + const uint8_t *p_guid = (const uint8_t*)&port_guid; + uint32_t low24; + net16_t guid_middle; + + /* Port guid is in network byte order. OUI is in lower 3 bytes. */ + ASSERT( p_guid[0] == 0x00 && p_guid[1] == 0x02 && p_guid[2] == 0xc9 ); + + guid_middle = (net16_t)((port_guid & CL_HTON64( 0x000000ffff000000 )) >>24); + + if (guid_middle == 2) { + p_mac_addr->addr[0] = 0; + } else if (guid_middle == 3) { + p_mac_addr->addr[0] = 2; + } else { + return IB_INVALID_GUID; + } + low24 = ((uint32_t)cl_ntoh64( port_guid ) & 0x00FFFFFF); + + p_mac_addr->addr[1] = p_guid[1]; + p_mac_addr->addr[2] = p_guid[2]; + p_mac_addr->addr[3] = (uint8_t)(low24 >> 16); + p_mac_addr->addr[4] = (uint8_t)(low24 >> 8); + p_mac_addr->addr[5] = (uint8_t)low24; + + return IB_SUCCESS; +} +/* +* PARAMETERS +* port_guid +* The port GUID, in network byte order, for which to generate a +* MAC address. +* +* p_mac_addr +* Pointer to a mac address in which to store the results. +* +* RETURN VALUES +* IB_SUCCESS +* The MAC address was successfully converted. +* +* IB_INVALID_GUID +* The port GUID provided was not a known GUID format. +* +*********/ + + +/****f* IPOIB/ipoib_mac_from_voltaire_guid +* NAME +* ipoib_mac_from_voltaire_guid +* +* DESCRIPTION +* Generates an ethernet MAC address given a Voltaire port GUID. +* +* SYNOPSIS +*/ +static inline ib_api_status_t +ipoib_mac_from_voltaire_guid( + IN const net64_t port_guid, + OUT mac_addr_t* const p_mac_addr ) +{ + const uint8_t *p_guid = (const uint8_t*)&port_guid; + + /* Port guid is in network byte order. OUI is in lower 3 bytes. */ + ASSERT( p_guid[0] == 0x00 && p_guid[1] == 0x08 && p_guid[2] == 0xf1 ); + + p_mac_addr->addr[0] = p_guid[0]; + p_mac_addr->addr[1] = p_guid[1]; + p_mac_addr->addr[2] = p_guid[2]; + p_mac_addr->addr[3] = p_guid[4] ^ p_guid[6]; + p_mac_addr->addr[4] = p_guid[5] ^ p_guid[7]; + p_mac_addr->addr[5] = p_guid[5] + p_guid[6] + p_guid[7]; + + return IB_SUCCESS; +} + + +/****f* IPOIB/ipoib_mac_from_guid_mask +* NAME +* ipoib_mac_from_guid_mask +* +* DESCRIPTION +* Generates an ethernet MAC address given general port GUID and a bitwise mask +* +* SYNOPSIS +*/ +static inline ib_api_status_t +ipoib_mac_from_guid_mask( + IN const uint8_t *p_guid, + IN uint32_t guid_mask, + OUT mac_addr_t* const p_mac_addr ) +{ + static const mac_addr_size = HW_ADDR_LEN; + uint8_t i; + int digit_counter = 0; + + // All non-zero bits of guid_mask indicates the number of an appropriate + // byte in port_guid, that will be used in MAC address construction + for (i = 7; guid_mask; guid_mask >>= 1, --i ) + { + if( guid_mask & 1 ) + { + ++digit_counter; + if( digit_counter > mac_addr_size ) + { + //to avoid negative index + return IB_INVALID_GUID_MASK; + } + p_mac_addr->addr[mac_addr_size - digit_counter] = p_guid [i]; + } + } + + // check for the mask validity: it should have 6 non-zero bits + if( digit_counter != mac_addr_size ) + return IB_INVALID_GUID_MASK; + + return IB_SUCCESS; +} +/* +* PARAMETERS +* port_guid +* The port GUID, in network byte order, for which to generate a +* MAC address. +* +* guid_mask +* Each BIT in the mask indicates whether to include the appropriate BYTE +* to the MAC address. Bit 0 corresponds to the less significant BYTE , i.e. +* highest index in the MAC array +* +* p_mac_addr +* Pointer to a mac address in which to store the results. +* +* RETURN VALUES +* IB_SUCCESS +* The MAC address was successfully converted. +* +* IB_INVALID_GUID +* The port GUID provided was not a known GUID format. +* +* SEE ALSO +* IPOIB +*********/ + + +/****f* IPOIB/ipoib_mac_from_guid +* NAME +* ipoib_mac_from_guid +* +* DESCRIPTION +* Generates an ethernet MAC address given a port GUID. +* +* SYNOPSIS +*/ +static inline ib_api_status_t +ipoib_mac_from_guid( + IN const net64_t port_guid, + IN uint32_t guid_mask, + OUT mac_addr_t* const p_mac_addr + ) +{ + ib_api_status_t status = IB_INVALID_GUID; + const uint8_t *p_guid = (const uint8_t*)&port_guid; + uint32_t laa, idx = 0; + + /* Port guid is in network byte order. OUI is in lower 3 bytes. */ + if( p_guid[0] == 0 ) + { + if( p_guid[1] == 0x02 && p_guid[2] == 0xc9 ) + { + status = ipoib_mac_from_mlx_guid( port_guid, p_mac_addr ); + } + else if( p_guid[1] == 0x08 && p_guid[2] == 0xf1 ) + { + status = ipoib_mac_from_voltaire_guid( port_guid, p_mac_addr ); + } + else if( p_guid[1] == 0x06 && p_guid[2] == 0x6a ) + { + status = ipoib_mac_from_sst_guid( port_guid, p_mac_addr ); + } + else + { + while( guid2mac_table[idx].second_byte != 0x00 || + guid2mac_table[idx].third_byte != 0x00 ) + { + if( p_guid[1] == guid2mac_table[idx].second_byte && + p_guid[2] == guid2mac_table[idx].third_byte ) + { + status = ipoib_mac_from_guid_mask(p_guid, guid2mac_table[idx].guid_mask, + p_mac_addr); + break; + } + ++idx; + } + } + + if( status == IB_SUCCESS ) + return status; + } + + if( guid_mask ) + return ipoib_mac_from_guid_mask( p_guid, guid_mask, p_mac_addr ); + + /* Value of zero is reserved. */ + laa = cl_atomic_inc( &g_ipoib.laa_idx ); + + if( !laa ) + return IB_INVALID_GUID; + + p_mac_addr->addr[0] = 2; /* LAA bit */ + p_mac_addr->addr[1] = 0; + p_mac_addr->addr[2] = (uint8_t)(laa >> 24); + p_mac_addr->addr[3] = (uint8_t)(laa >> 16); + p_mac_addr->addr[4] = (uint8_t)(laa >> 8); + p_mac_addr->addr[5] = (uint8_t)laa; + + return IB_SUCCESS; +} +/* +* PARAMETERS +* port_guid +* The port GUID, in network byte order, for which to generate a +* MAC address. +* +* p_mac_addr +* Pointer to a mac address in which to store the results. +* +* RETURN VALUES +* IB_SUCCESS +* The MAC address was successfully converted. +* +* IB_INVALID_GUID +* The port GUID provided was not a known GUID format. +* +* NOTES +* Creates a locally administered address using a global incrementing counter. +* +* SEE ALSO +* IPOIB +*********/ + + +/****f* IPOIB/ipoib_is_voltaire_router_gid +* NAME +* ipoib_is_voltaire_router_gid +* +* DESCRIPTION +* Checks whether the GID belongs to Voltaire IP router +* +* SYNOPSIS +*/ +boolean_t +static inline +ipoib_is_voltaire_router_gid( + IN const ib_gid_t *p_gid ) +{ + static const uint8_t VOLTAIRE_GUID_PREFIX[] = {0, 0x08, 0xf1, 0, 0x1}; + + return !cl_memcmp( &p_gid->unicast.interface_id, VOLTAIRE_GUID_PREFIX, + sizeof(VOLTAIRE_GUID_PREFIX) ); +} + + +#ifdef __cplusplus +} +#endif + +#endif /* _IPOIB_XFR_MGR_H_ */ diff --git a/branches/WOF2-3/ulp/ipoib/kernel/makefile b/branches/WOF2-3/ulp/ipoib/kernel/makefile new file mode 100644 index 00000000..445914cd --- /dev/null +++ b/branches/WOF2-3/ulp/ipoib/kernel/makefile @@ -0,0 +1,13 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +# +# prevent the Build utility from building the driver for later +# version of the operating system than windows 2003 +# +MAXIMUM_NT_TARGET_VERSION=0x502 + +!INCLUDE ..\..\..\inc\openib.def diff --git a/branches/WOF2-3/ulp/ipoib/kernel/makefile.inc b/branches/WOF2-3/ulp/ipoib/kernel/makefile.inc new file mode 100644 index 00000000..4f29f500 --- /dev/null +++ b/branches/WOF2-3/ulp/ipoib/kernel/makefile.inc @@ -0,0 +1,17 @@ + +# Transform .inx file to .inf file adding date + major,min & svn.version stamp +# Output .inf file is copied to the $(INF_TARGET) folder (commonly where .sys file resides). + +_LNG=$(LANGUAGE) + +!IF !DEFINED(_INX) +_INX=. +!ENDIF + +STAMP=stampinf -a $(_BUILDARCH) + +!INCLUDE mod_ver.def + +$(INF_TARGET) : $(_INX)\$(INF_NAME).inx + copy $(_INX)\$(@B).inx $@ + $(STAMP) -f $@ -d * -v $(IB_MAJORVERSION).$(IB_MINORVERSION).$(IB_BUILDVERSION).$(OPENIB_REV) diff --git a/branches/WOF2-3/ulp/ipoib/kernel/netipoib-xp32.inf b/branches/WOF2-3/ulp/ipoib/kernel/netipoib-xp32.inf new file mode 100644 index 00000000..5b4999a1 --- /dev/null +++ b/branches/WOF2-3/ulp/ipoib/kernel/netipoib-xp32.inf @@ -0,0 +1,284 @@ +; OpenFabrics Alliance Internet Protocol over InfiniBand Adapter +; Copyright 2005 SilverStorm Technologies all Rights Reserved. +; Copyright 2006 Mellanox Technologies all Rights Reserved. + +[Version] +Signature = "$Windows NT$" +Class = Net +ClassGUID = {4d36e972-e325-11ce-bfc1-08002be10318} +Provider = %OPENIB% +DriverVer=01/04/2010,2.2.0000.2654 +CatalogFile=ipoib.cat + +[Manufacturer] +%OPENIB% = OPENIB,ntx86,ntamd64,ntia64 + +[ControlFlags] +ExcludeFromSelect = IBA\IPoIB + +[OPENIB] +; empty since we don't support W9x/Me + +[OPENIB.ntx86] +%IpoibDesc% = Ipoib.DDInstall, IBA\IPoIB ; Internet Protocol over InfiniBand Adapter +%IpoibDescP% = Ipoib.DDInstall, IBA\IPoIBP ; Internet Protocol over InfiniBand Adapter with partition key + +[OPENIB.ntamd64] +%IpoibDesc% = Ipoib.DDInstall, IBA\IPoIB ; Internet Protocol over InfiniBand Adapter +%IpoibDescP% = Ipoib.DDInstall, IBA\IPoIBP ; Internet Protocol over InfiniBand Adapter with partition key + +[OPENIB.ntia64] +%IpoibDesc% = Ipoib.DDInstall, IBA\IPoIB ; Internet Protocol over InfiniBand Adapter +%IpoibDescP% = Ipoib.DDInstall, IBA\IPoIBP ; Internet Protocol over InfiniBand Adapter with partition key + +[Ipoib.DDInstall.ntx86] +Characteristics = 0x81 ; NCF_HAS_UI | NCF_VIRTUAL +AddReg = IpoibAddReg +CopyFiles = IpoibCopyFiles +CopyFiles = NdCopyFiles + +[Ipoib.DDInstall.ntamd64] +Characteristics = 0x81 ; NCF_HAS_UI | NCF_VIRTUAL +AddReg = IpoibAddReg +CopyFiles = IpoibCopyFiles +CopyFiles = WsdCopyFiles +CopyFiles = NdCopyFiles +CopyFiles = WOW64CopyFiles + +[Ipoib.DDInstall.ntia64] +Characteristics = 0x81 ; NCF_HAS_UI | NCF_VIRTUAL +AddReg = IpoibAddReg +CopyFiles = IpoibCopyFiles +CopyFiles = WsdCopyFiles +CopyFiles = NdWvCopyFiles +CopyFiles = WOW64IA64CopyFiles + +[Ipoib.DDInstall.ntx86.Services] +AddService = ipoib, 2, IpoibService, IpoibEventLog + +[Ipoib.DDInstall.ntamd64.Services] +AddService = ipoib, 2, IpoibService, IpoibEventLog + +[Ipoib.DDInstall.ntia64.Services] +AddService = ipoib, 2, IpoibService, IpoibEventLog + +[IpoibAddReg] +HKR, ,RDMACapable, %REG_DWORD%, 1 +HKR, Ndi, Service, 0, "ipoib" +HKR, Ndi\Interfaces, UpperRange, 0, "ndis5" +HKR, Ndi\Interfaces, LowerRange, 0, "ethernet" + +HKR, Ndi\Params\RqDepth, ParamDesc, 0, %RQ_DEPTH_STR% +HKR, Ndi\Params\RqDepth, Type, 0, "dword" +HKR, Ndi\Params\RqDepth, Default, 0, "512" +HKR, Ndi\Params\RqDepth, Optional, 0, "0" +HKR, Ndi\Params\RqDepth, Min, 0, "128" +HKR, Ndi\Params\RqDepth, Max, 0, "1024" +HKR, Ndi\Params\RqDepth, Step, 0, "128" + +HKR, Ndi\Params\RqLowWatermark, ParamDesc, 0, %RQ_WATERMARK_STR% +HKR, Ndi\Params\RqLowWatermark, Type, 0, "dword" +HKR, Ndi\Params\RqLowWatermark, Default, 0, "4" +HKR, Ndi\Params\RqLowWatermark, Optional, 0, "0" +HKR, Ndi\Params\RqLowWatermark, Min, 0, "2" +HKR, Ndi\Params\RqLowWatermark, Max, 0, "8" +HKR, Ndi\Params\RqLowWatermark, Step, 0, "1" + +HKR, Ndi\Params\SqDepth, ParamDesc, 0, %SQ_DEPTH_STR% +HKR, Ndi\Params\SqDepth, Type, 0, "dword" +HKR, Ndi\Params\SqDepth, Default, 0, "512" +HKR, Ndi\Params\SqDepth, Optional, 0, "0" +HKR, Ndi\Params\SqDepth, Min, 0, "128" +HKR, Ndi\Params\SqDepth, Max, 0, "1024" +HKR, Ndi\Params\SqDepth, Step, 0, "128" + +HKR, Ndi\Params\SendChksum, ParamDesc, 0, %SQ_CSUM_STR% +HKR, Ndi\Params\SendChksum, Type, 0, "enum" +HKR, Ndi\Params\SendChksum, Default, 0, "1" +HKR, Ndi\Params\SendChksum, Optional, 0, "0" +HKR, Ndi\Params\SendChksum\enum, "0", 0, %DISABLED_STR% +HKR, Ndi\Params\SendChksum\enum, "1", 0, %ENABLED_IF_STR% +HKR, Ndi\Params\SendChksum\enum, "2", 0, %BYPASS_STR% + +HKR, Ndi\Params\RecvChksum, ParamDesc, 0, %RQ_CSUM_STR% +HKR, Ndi\Params\RecvChksum, Type, 0, "enum" +HKR, Ndi\Params\RecvChksum, Default, 0, "1" +HKR, Ndi\Params\RecvChksum, Optional, 0, "0" +HKR, Ndi\Params\RecvChksum\enum, "0", 0, %DISABLED_STR% +HKR, Ndi\Params\RecvChksum\enum, "1", 0, %ENABLED_IF_STR% +HKR, Ndi\Params\RecvChksum\enum, "2", 0, %BYPASS_STR% + +HKR, Ndi\Params\lso, ParamDesc, 0, %LSO_STR% +HKR, Ndi\Params\lso, Type, 0, "enum" +HKR, Ndi\Params\lso, Default, 0, "0" +HKR, Ndi\Params\lso, Optional, 0, "0" +HKR, Ndi\Params\lso\enum, "0", 0, %DISABLED_STR% +HKR, Ndi\Params\lso\enum, "1", 0, %ENABLED_STR% + + +HKR, Ndi\Params\SaTimeout, ParamDesc, 0, %SA_QUERY_TO_STR% +HKR, Ndi\Params\SaTimeout, Type, 0, "dword" +HKR, Ndi\Params\SaTimeout, Default, 0, "1000" +HKR, Ndi\Params\SaTimeout, Optional, 0, "0" +HKR, Ndi\Params\SaTimeout, Min, 0, "500" +HKR, Ndi\Params\SaTimeout, Step, 0, "250" + +HKR, Ndi\Params\SaRetries, ParamDesc, 0, %SA_QUERY_RETRY_STR% +HKR, Ndi\Params\SaRetries, Type, 0, "dword" +HKR, Ndi\Params\SaRetries, Default, 0, "10" +HKR, Ndi\Params\SaRetries, Optional, 0, "0" +HKR, Ndi\Params\SaRetries, Min, 0, "1" + +HKR, Ndi\Params\RecvRatio, ParamDesc, 0, %RECV_RATIO_STR% +HKR, Ndi\Params\RecvRatio, Type, 0, "dword" +HKR, Ndi\Params\RecvRatio, Default, 0, "1" +HKR, Ndi\Params\RecvRatio, Optional, 0, "0" +HKR, Ndi\Params\RecvRatio, Min, 0, "1" +HKR, Ndi\Params\RecvRatio, Max, 0, "10" + +HKR, Ndi\Params\PayloadMtu, ParamDesc, 0, %MTU_STR% +HKR, Ndi\Params\PayloadMtu, Type, 0, "dword" +HKR, Ndi\Params\PayloadMtu, Default, 0, "2044" +HKR, Ndi\Params\PayloadMtu, Min, 0, "512" +HKR, Ndi\Params\PayloadMtu, Max, 0, "4092" + +HKR, Ndi\Params\MCLeaveRescan, ParamDesc, 0, %MC_RESCAN_STR% +HKR, Ndi\Params\MCLeaveRescan, Type, 0, "dword" +HKR, Ndi\Params\MCLeaveRescan, Default, 0, "260" +HKR, Ndi\Params\MCLeaveRescan, Optional, 0, "0" +HKR, Ndi\Params\MCLeaveRescan, Min, 0, "1" +HKR, Ndi\Params\MCLeaveRescan, Max, 0, "3600" + +HKR, Ndi\Params\GUIDMask, ParamDesc, 0, %GUID_MASK_STR% +HKR, Ndi\Params\GUIDMask, Type, 0, "dword" +HKR, Ndi\Params\GUIDMask, Default, 0, "0" +HKR, Ndi\Params\GUIDMask, Optional, 0, "0" +HKR, Ndi\Params\GUIDMask, Min, 0, "0" +HKR, Ndi\Params\GUIDMask, Max, 0, "252" + +HKR, Ndi\Params\BCJoinRetry, ParamDesc, 0, %BC_JOIN_RETRY_STR% +HKR, Ndi\Params\BCJoinRetry, Type, 0, "dword" +HKR, Ndi\Params\BCJoinRetry, Default, 0, "50" +HKR, Ndi\Params\BCJoinRetry, Optional, 0, "0" +HKR, Ndi\Params\BCJoinRetry, Min, 0, "0" +HKR, Ndi\Params\BCJoinRetry, Max, 0, "1000" + + +[IpoibService] +DisplayName = %IpoibServiceDispName% +ServiceType = 1 ;%SERVICE_KERNEL_DRIVER% +StartType = 3 ;%SERVICE_DEMAND_START% +ErrorControl = 1 ;%SERVICE_ERROR_NORMAL% +ServiceBinary = %12%\ipoib.sys +LoadOrderGroup = NDIS +AddReg = Ipoib.ParamsReg + +[Ipoib.ParamsReg] +HKR,"Parameters","DebugLevel",%REG_DWORD_NO_CLOBBER%,0x00000002 +HKR,"Parameters","DebugFlags",%REG_DWORD_NO_CLOBBER%,0x00000fff +HKR,"Parameters","bypass_check_bcast_rate",%REG_DWORD_NO_CLOBBER%,0x00000000 + +[IpoibEventLog] +AddReg = IpoibAddEventLogReg + +[IpoibAddEventLogReg] +HKR, , EventMessageFile, 0x00020000, "%%SystemRoot%%\System32\netevent.dll;%%SystemRoot%%\System32\drivers\ipoib.sys" +HKR, , TypesSupported, 0x00010001, 7 + + +[IpoibCopyFiles] +ipoib.sys,,,2 + +[WsdCopyFiles] +ibwsd.dll,,,0x00000002 + +[NdCopyFiles] +ibndprov.dll,,,0x00000002 +wvndprov.dll,,,0x00000002 +ndinstall.exe,,,0x00000002 + +[NdWvCopyFiles] +wvndprov.dll,,,0x00000002 +ndinstall.exe,,,0x00000002 + +[WOW64CopyFiles] +ibwsd.dll,ibwsd32.dll,,0x00000002 +ibndprov.dll,ibndprov32.dll,,0x00000002 +wvndprov.dll,wvndprov32.dll,,0x00000002 + +[WOW64IA64CopyFiles] +ibwsd.dll,ibwsd32.dll,,0x00000002 +wvndprov.dll,wvndprov32.dll,,0x00000002 + +[SourceDisksNames.x86] +1 = %IcsDisk1%,,,"" + +[SourceDisksNames.amd64] +1 = %IcsDisk1%,,,"" + +[SourceDisksNames.ia64] +1 = %IcsDisk1%,,,"" + +[SourceDisksFiles.x86] +ipoib.sys = 1 +ibndprov.dll = 1 +wvndprov.dll = 1 +ndinstall.exe = 1 + +[SourceDisksFiles.amd64] +ipoib.sys = 1 +ibwsd.dll = 1 +ibwsd32.dll = 1 +ibndprov.dll = 1 +ibndprov32.dll = 1 +wvndprov.dll = 1 +wvndprov32.dll = 1 +ndinstall.exe = 1 + +[SourceDisksFiles.ia64] +ipoib.sys = 1 +ibwsd.dll = 1 +ibwsd32.dll = 1 +wvndprov.dll = 1 +wvndprov32.dll = 1 +ndinstall.exe = 1 + +[DestinationDirs] +IpoibCopyFiles = %DIRID_DRIVERS% +WsdCopyFiles = %DIRID_SYSTEM% +NdCopyFiles = %DIRID_SYSTEM% +NdWvCopyFiles = %DIRID_SYSTEM% +WOW64CopyFiles = %DIRID_SYSTEM_X86% +WOW64IA64CopyFiles = %DIRID_SYSTEM_X86% +DefaultDestDir = %DIRID_SYSTEM% + +[Strings] +OPENIB = "OpenFabrics Alliance" +IpoibDesc = "OpenFabrics IPoIB Adapter" +IpoibDescP = "OpenFabrics IPoIB Adapter Partition" +IpoibServiceDispName = "IPoIB" +IcsDisk1 = "OpenFabrics IPoIB Disk #1" +DIRID_SYSTEM = 11 +DIRID_DRIVERS = 12 +DIRID_SYSTEM_X86 = 16425 +REG_DWORD = 0x00010001 +REG_DWORD_NO_CLOBBER = 0x00010003 + +RQ_DEPTH_STR = "Receive Queue depth" +RQ_WATERMARK_STR = "Receive Queue Low Watermark" +SQ_DEPTH_STR = "Send Queue Depth" +SQ_CSUM_STR = "Send Checksum Offload" +RQ_CSUM_STR = "Recv Checksum Offload" +LSO_STR = "Large Send Offload" +SA_QUERY_TO_STR = "SA Query Timeout (ms)" +SA_QUERY_RETRY_STR = "SA Query Retry Count" +RECV_RATIO_STR = "Receive Pool Ratio" +MTU_STR = "Payload Mtu size" +MC_RESCAN_STR = "MC leave rescan (sec)" +GUID_MASK_STR = "GUID bitwise mask" +BC_JOIN_RETRY_STR = "Number of retries connecting to bc" + +ENABLED_IF_STR = "Enabled (if supported by HW)" +ENABLED_STR = "Enabled" +DISABLED_STR = "Disabled" +BYPASS_STR = "Bypass" diff --git a/branches/WOF2-3/ulp/ipoib/kernel/netipoib.inx b/branches/WOF2-3/ulp/ipoib/kernel/netipoib.inx new file mode 100644 index 00000000..ada77225 --- /dev/null +++ b/branches/WOF2-3/ulp/ipoib/kernel/netipoib.inx @@ -0,0 +1,286 @@ +; OpenFabrics Alliance Internet Protocol over InfiniBand Adapter +; Copyright 2005 SilverStorm Technologies all Rights Reserved. +; Copyright 2006 Mellanox Technologies all Rights Reserved. + +[Version] +Signature = "$Windows NT$" +Class = Net +ClassGUID = {4d36e972-e325-11ce-bfc1-08002be10318} +Provider = %OPENIB% +DriverVer=06/11/2008,1.0.0000.1207 +CatalogFile=ipoib.cat + +[Manufacturer] +%OPENIB% = OPENIB,ntx86,ntamd64,ntia64 + +[ControlFlags] +ExcludeFromSelect = IBA\IPoIB + +[OPENIB] +; empty since we don't support W9x/Me + +[OPENIB.ntx86] +%IpoibDesc% = Ipoib.DDInstall, IBA\IPoIB ; Internet Protocol over InfiniBand Adapter +%IpoibDescP% = Ipoib.DDInstall, IBA\IPoIBP ; Internet Protocol over InfiniBand Adapter with partition key + +[OPENIB.ntamd64] +%IpoibDesc% = Ipoib.DDInstall, IBA\IPoIB ; Internet Protocol over InfiniBand Adapter +%IpoibDescP% = Ipoib.DDInstall, IBA\IPoIBP ; Internet Protocol over InfiniBand Adapter with partition key + +[OPENIB.ntia64] +%IpoibDesc% = Ipoib.DDInstall, IBA\IPoIB ; Internet Protocol over InfiniBand Adapter +%IpoibDescP% = Ipoib.DDInstall, IBA\IPoIBP ; Internet Protocol over InfiniBand Adapter with partition key + +[Ipoib.DDInstall.ntx86] +Characteristics = 0x81 ; NCF_HAS_UI | NCF_VIRTUAL +AddReg = IpoibAddReg +CopyFiles = IpoibCopyFiles +CopyFiles = WsdCopyFiles +CopyFiles = NdCopyFiles + +[Ipoib.DDInstall.ntamd64] +Characteristics = 0x81 ; NCF_HAS_UI | NCF_VIRTUAL +AddReg = IpoibAddReg +CopyFiles = IpoibCopyFiles +CopyFiles = WsdCopyFiles +CopyFiles = NdCopyFiles +CopyFiles = WOW64CopyFiles + +[Ipoib.DDInstall.ntia64] +Characteristics = 0x81 ; NCF_HAS_UI | NCF_VIRTUAL +AddReg = IpoibAddReg +CopyFiles = IpoibCopyFiles +CopyFiles = WsdCopyFiles +CopyFiles = NdWvCopyFiles +CopyFiles = WOW64IA64CopyFiles + +[Ipoib.DDInstall.ntx86.Services] +AddService = ipoib, 2, IpoibService, IpoibEventLog + +[Ipoib.DDInstall.ntamd64.Services] +AddService = ipoib, 2, IpoibService, IpoibEventLog + +[Ipoib.DDInstall.ntia64.Services] +AddService = ipoib, 2, IpoibService, IpoibEventLog + +[IpoibAddReg] +HKR, ,RDMACapable, %REG_DWORD%, 1 +HKR, Ndi, Service, 0, "ipoib" +HKR, Ndi\Interfaces, UpperRange, 0, "ndis5" +HKR, Ndi\Interfaces, LowerRange, 0, "ethernet" + +HKR, Ndi\Params\RqDepth, ParamDesc, 0, %RQ_DEPTH_STR% +HKR, Ndi\Params\RqDepth, Type, 0, "dword" +HKR, Ndi\Params\RqDepth, Default, 0, "512" +HKR, Ndi\Params\RqDepth, Optional, 0, "0" +HKR, Ndi\Params\RqDepth, Min, 0, "128" +HKR, Ndi\Params\RqDepth, Max, 0, "1024" +HKR, Ndi\Params\RqDepth, Step, 0, "128" + +HKR, Ndi\Params\RqLowWatermark, ParamDesc, 0, %RQ_WATERMARK_STR% +HKR, Ndi\Params\RqLowWatermark, Type, 0, "dword" +HKR, Ndi\Params\RqLowWatermark, Default, 0, "4" +HKR, Ndi\Params\RqLowWatermark, Optional, 0, "0" +HKR, Ndi\Params\RqLowWatermark, Min, 0, "2" +HKR, Ndi\Params\RqLowWatermark, Max, 0, "8" +HKR, Ndi\Params\RqLowWatermark, Step, 0, "1" + +HKR, Ndi\Params\SqDepth, ParamDesc, 0, %SQ_DEPTH_STR% +HKR, Ndi\Params\SqDepth, Type, 0, "dword" +HKR, Ndi\Params\SqDepth, Default, 0, "512" +HKR, Ndi\Params\SqDepth, Optional, 0, "0" +HKR, Ndi\Params\SqDepth, Min, 0, "128" +HKR, Ndi\Params\SqDepth, Max, 0, "1024" +HKR, Ndi\Params\SqDepth, Step, 0, "128" + +HKR, Ndi\Params\SendChksum, ParamDesc, 0, %SQ_CSUM_STR% +HKR, Ndi\Params\SendChksum, Type, 0, "enum" +HKR, Ndi\Params\SendChksum, Default, 0, "1" +HKR, Ndi\Params\SendChksum, Optional, 0, "0" +HKR, Ndi\Params\SendChksum\enum, "0", 0, %DISABLED_STR% +HKR, Ndi\Params\SendChksum\enum, "1", 0, %ENABLED_IF_STR% +HKR, Ndi\Params\SendChksum\enum, "2", 0, %BYPASS_STR% + +HKR, Ndi\Params\RecvChksum, ParamDesc, 0, %RQ_CSUM_STR% +HKR, Ndi\Params\RecvChksum, Type, 0, "enum" +HKR, Ndi\Params\RecvChksum, Default, 0, "1" +HKR, Ndi\Params\RecvChksum, Optional, 0, "0" +HKR, Ndi\Params\RecvChksum\enum, "0", 0, %DISABLED_STR% +HKR, Ndi\Params\RecvChksum\enum, "1", 0, %ENABLED_IF_STR% +HKR, Ndi\Params\RecvChksum\enum, "2", 0, %BYPASS_STR% + +HKR, Ndi\Params\lso, ParamDesc, 0, %LSO_STR% +HKR, Ndi\Params\lso, Type, 0, "enum" +HKR, Ndi\Params\lso, Default, 0, "0" +HKR, Ndi\Params\lso, Optional, 0, "0" +HKR, Ndi\Params\lso\enum, "0", 0, %DISABLED_STR% +HKR, Ndi\Params\lso\enum, "1", 0, %ENABLED_STR% + + +HKR, Ndi\Params\SaTimeout, ParamDesc, 0, %SA_QUERY_TO_STR% +HKR, Ndi\Params\SaTimeout, Type, 0, "dword" +HKR, Ndi\Params\SaTimeout, Default, 0, "1000" +HKR, Ndi\Params\SaTimeout, Optional, 0, "0" +HKR, Ndi\Params\SaTimeout, Min, 0, "500" +HKR, Ndi\Params\SaTimeout, Step, 0, "250" + +HKR, Ndi\Params\SaRetries, ParamDesc, 0, %SA_QUERY_RETRY_STR% +HKR, Ndi\Params\SaRetries, Type, 0, "dword" +HKR, Ndi\Params\SaRetries, Default, 0, "10" +HKR, Ndi\Params\SaRetries, Optional, 0, "0" +HKR, Ndi\Params\SaRetries, Min, 0, "1" + +HKR, Ndi\Params\RecvRatio, ParamDesc, 0, %RECV_RATIO_STR% +HKR, Ndi\Params\RecvRatio, Type, 0, "dword" +HKR, Ndi\Params\RecvRatio, Default, 0, "1" +HKR, Ndi\Params\RecvRatio, Optional, 0, "0" +HKR, Ndi\Params\RecvRatio, Min, 0, "1" +HKR, Ndi\Params\RecvRatio, Max, 0, "10" + +HKR, Ndi\Params\PayloadMtu, ParamDesc, 0, %MTU_STR% +HKR, Ndi\Params\PayloadMtu, Type, 0, "dword" +HKR, Ndi\Params\PayloadMtu, Default, 0, "2044" +HKR, Ndi\Params\PayloadMtu, Min, 0, "512" +HKR, Ndi\Params\PayloadMtu, Max, 0, "4092" + +HKR, Ndi\Params\MCLeaveRescan, ParamDesc, 0, %MC_RESCAN_STR% +HKR, Ndi\Params\MCLeaveRescan, Type, 0, "dword" +HKR, Ndi\Params\MCLeaveRescan, Default, 0, "260" +HKR, Ndi\Params\MCLeaveRescan, Optional, 0, "0" +HKR, Ndi\Params\MCLeaveRescan, Min, 0, "1" +HKR, Ndi\Params\MCLeaveRescan, Max, 0, "3600" + +HKR, Ndi\Params\GUIDMask, ParamDesc, 0, %GUID_MASK_STR% +HKR, Ndi\Params\GUIDMask, Type, 0, "dword" +HKR, Ndi\Params\GUIDMask, Default, 0, "0" +HKR, Ndi\Params\GUIDMask, Optional, 0, "0" +HKR, Ndi\Params\GUIDMask, Min, 0, "0" +HKR, Ndi\Params\GUIDMask, Max, 0, "252" + +HKR, Ndi\Params\BCJoinRetry, ParamDesc, 0, %BC_JOIN_RETRY_STR% +HKR, Ndi\Params\BCJoinRetry, Type, 0, "dword" +HKR, Ndi\Params\BCJoinRetry, Default, 0, "50" +HKR, Ndi\Params\BCJoinRetry, Optional, 0, "0" +HKR, Ndi\Params\BCJoinRetry, Min, 0, "0" +HKR, Ndi\Params\BCJoinRetry, Max, 0, "1000" + + +[IpoibService] +DisplayName = %IpoibServiceDispName% +ServiceType = 1 ;%SERVICE_KERNEL_DRIVER% +StartType = 3 ;%SERVICE_DEMAND_START% +ErrorControl = 1 ;%SERVICE_ERROR_NORMAL% +ServiceBinary = %12%\ipoib.sys +LoadOrderGroup = NDIS +AddReg = Ipoib.ParamsReg + +[Ipoib.ParamsReg] +HKR,"Parameters","DebugLevel",%REG_DWORD_NO_CLOBBER%,0x00000002 +HKR,"Parameters","DebugFlags",%REG_DWORD_NO_CLOBBER%,0x00000fff +HKR,"Parameters","bypass_check_bcast_rate",%REG_DWORD_NO_CLOBBER%,0x00000000 + +[IpoibEventLog] +AddReg = IpoibAddEventLogReg + +[IpoibAddEventLogReg] +HKR, , EventMessageFile, 0x00020000, "%%SystemRoot%%\System32\netevent.dll;%%SystemRoot%%\System32\drivers\ipoib.sys" +HKR, , TypesSupported, 0x00010001, 7 + + +[IpoibCopyFiles] +ipoib.sys,,,2 + +[WsdCopyFiles] +ibwsd.dll,,,0x00000002 + +[NdCopyFiles] +ibndprov.dll,,,0x00000002 +wvndprov.dll,,,0x00000002 +ndinstall.exe,,,0x00000002 + +[NdWvCopyFiles] +wvndprov.dll,,,0x00000002 +ndinstall.exe,,,0x00000002 + +[WOW64CopyFiles] +ibwsd.dll,ibwsd32.dll,,0x00000002 +ibndprov.dll,ibndprov32.dll,,0x00000002 +wvndprov.dll,wvndprov32.dll,,0x00000002 + +[WOW64IA64CopyFiles] +ibwsd.dll,ibwsd32.dll,,0x00000002 +wvndprov.dll,wvndprov32.dll,,0x00000002 + +[SourceDisksNames.x86] +1 = %IcsDisk1%,,,"" + +[SourceDisksNames.amd64] +1 = %IcsDisk1%,,,"" + +[SourceDisksNames.ia64] +1 = %IcsDisk1%,,,"" + +[SourceDisksFiles.x86] +ipoib.sys = 1 +ibwsd.dll = 1 +ibndprov.dll = 1 +wvndprov.dll = 1 +ndinstall.exe = 1 + +[SourceDisksFiles.amd64] +ipoib.sys = 1 +ibwsd.dll = 1 +ibwsd32.dll = 1 +ibndprov.dll = 1 +ibndprov32.dll = 1 +wvndprov.dll = 1 +wvndprov32.dll = 1 +ndinstall.exe = 1 + +[SourceDisksFiles.ia64] +ipoib.sys = 1 +ibwsd.dll = 1 +ibwsd32.dll = 1 +wvndprov.dll = 1 +wvndprov32.dll = 1 +ndinstall.exe = 1 + +[DestinationDirs] +IpoibCopyFiles = %DIRID_DRIVERS% +WsdCopyFiles = %DIRID_SYSTEM% +NdCopyFiles = %DIRID_SYSTEM% +NdWvCopyFiles = %DIRID_SYSTEM% +WOW64CopyFiles = %DIRID_SYSTEM_X86% +WOW64IA64CopyFiles = %DIRID_SYSTEM_X86% +DefaultDestDir = %DIRID_SYSTEM% + +[Strings] +OPENIB = "OpenFabrics Alliance" +IpoibDesc = "OpenFabrics IPoIB Adapter" +IpoibDescP = "OpenFabrics IPoIB Adapter Partition" +IpoibServiceDispName = "IPoIB" +IcsDisk1 = "OpenFabrics IPoIB Disk #1" +DIRID_SYSTEM = 11 +DIRID_DRIVERS = 12 +DIRID_SYSTEM_X86 = 16425 +REG_DWORD = 0x00010001 +REG_DWORD_NO_CLOBBER = 0x00010003 + +RQ_DEPTH_STR = "Receive Queue depth" +RQ_WATERMARK_STR = "Receive Queue Low Watermark" +SQ_DEPTH_STR = "Send Queue Depth" +SQ_CSUM_STR = "Send Checksum Offload" +RQ_CSUM_STR = "Recv Checksum Offload" +LSO_STR = "Large Send Offload" +SA_QUERY_TO_STR = "SA Query Timeout (ms)" +SA_QUERY_RETRY_STR = "SA Query Retry Count" +RECV_RATIO_STR = "Receive Pool Ratio" +MTU_STR = "Payload Mtu size" +MC_RESCAN_STR = "MC leave rescan (sec)" +GUID_MASK_STR = "GUID bitwise mask" +BC_JOIN_RETRY_STR = "Number of retries connecting to bc" + +ENABLED_IF_STR = "Enabled (if supported by HW)" +ENABLED_STR = "Enabled" +DISABLED_STR = "Disabled" +BYPASS_STR = "Bypass" diff --git a/branches/WOF2-3/ulp/ipoib/kernel/offload.h b/branches/WOF2-3/ulp/ipoib/kernel/offload.h new file mode 100644 index 00000000..de696c6a --- /dev/null +++ b/branches/WOF2-3/ulp/ipoib/kernel/offload.h @@ -0,0 +1,47 @@ +/*++ + +Copyright (c) 2005-2008 Mellanox Technologies. All rights reserved. + +Module Name: + offload.h + +Abstract: + Task offloading header file + +Revision History: + +Notes: + +--*/ + +// +// Define the maximum size of large TCP packets the driver can offload. +// This sample driver uses shared memory to map the large packets, +// LARGE_SEND_OFFLOAD_SIZE is useless in this case, so we just define +// it as NIC_MAX_PACKET_SIZE. But shipping drivers should define +// LARGE_SEND_OFFLOAD_SIZE if they support LSO, and use it as +// MaximumPhysicalMapping when they call NdisMInitializeScatterGatherDma +// if they use ScatterGather method. If the drivers don't support +// LSO, then MaximumPhysicalMapping is NIC_MAX_PACKET_SIZE. +// + +#define LSO_MAX_HEADER 136 +#define LARGE_SEND_OFFLOAD_SIZE 60000 + +// This struct is being used in order to pass data about the GSO buffers if they +// are present +typedef struct LsoBuffer_ { + PUCHAR pData; + UINT Len; +} LsoBuffer; + +typedef struct LsoData_ { + LsoBuffer LsoBuffers[1]; + UINT UsedBuffers; + UINT FullBuffers; + UINT LsoHeaderSize; + UINT IndexOfData; + UCHAR coppied_data[LSO_MAX_HEADER]; +} LsoData; + + diff --git a/branches/WOF2-3/ulp/ipoib_NDIS6_CM/dirs b/branches/WOF2-3/ulp/ipoib_NDIS6_CM/dirs new file mode 100644 index 00000000..ed41dcf4 --- /dev/null +++ b/branches/WOF2-3/ulp/ipoib_NDIS6_CM/dirs @@ -0,0 +1,2 @@ +DIRS=\ + kernel diff --git a/branches/WOF2-3/ulp/ipoib_NDIS6_CM/ip_stats.h b/branches/WOF2-3/ulp/ipoib_NDIS6_CM/ip_stats.h new file mode 100644 index 00000000..2f93e41c --- /dev/null +++ b/branches/WOF2-3/ulp/ipoib_NDIS6_CM/ip_stats.h @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: ip_stats.h 1611 2006-08-20 14:48:55Z sleybo $ + */ + + +#ifndef _IP_STATS_H_ +#define _IP_STATS_H_ + + +#include + + +/****s* IB Network Drivers/ip_data_stats_t +* NAME +* ip_data_stats_t +* +* DESCRIPTION +* Defines data transfer statistic information for an IP device. +* +* SYNOPSIS +*/ +typedef struct _ip_data_stats +{ + uint64_t bytes; + uint64_t frames; + +} ip_data_stats_t; +/* +* FIELDS +* bytes +* Total number of bytes transfered. +* +* frames +* Total number of frames transfered. +* +* SEE ALSO +* IPoIB, INIC, ip_comp_stats_t, ip_stats_t +*********/ + + +/****s* IB Network Drivers/ip_comp_stats_t +* NAME +* ip_comp_stats_t +* +* DESCRIPTION +* Defines transfer completion statistic information for an IP device. +* +* SYNOPSIS +*/ +typedef struct _ip_comp_stats +{ + uint64_t success; + uint64_t error; + uint64_t dropped; + +} ip_comp_stats_t; +/* +* FIELDS +* success +* Total number of requests transfered successfully. +* +* error +* Total number of requests that failed being transfered. +* +* dropped +* Total number of requests that were dropped. +* +* SEE ALSO +* IPoIB, INIC, ip_data_stats_t, ip_stats_t +*********/ + + +/****s* IB Network Drivers/ip_stats_t +* NAME +* ip_stats_t +* +* DESCRIPTION +* Defines statistic information for an IP device. +* +* SYNOPSIS +*/ +typedef struct _ip_stats +{ + ip_comp_stats_t comp; + ip_data_stats_t ucast; + ip_data_stats_t bcast; + ip_data_stats_t mcast; + +} ip_stats_t; +/* +* FIELDS +* comp +* Request completion statistics. +* +* ucast +* Data statistics for unicast packets +* +* bcast +* Data statistics for broadcast packets +* +* mcast +* Data statistics for multicast packets +* +* SEE ALSO +* IPoIB, INIC, ip_data_stats_t, ip_comp_stats_t +*********/ + + +typedef enum _ip_stat_sel +{ + IP_STAT_SUCCESS, + IP_STAT_ERROR, + IP_STAT_DROPPED, + IP_STAT_UCAST_BYTES, + IP_STAT_UCAST_FRAMES, + IP_STAT_BCAST_BYTES, + IP_STAT_BCAST_FRAMES, + IP_STAT_MCAST_BYTES, + IP_STAT_MCAST_FRAMES + +} ip_stat_sel_t; + +#endif /* _IP_STATS_H_ */ diff --git a/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/SOURCES b/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/SOURCES new file mode 100644 index 00000000..2710aaf4 --- /dev/null +++ b/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/SOURCES @@ -0,0 +1,64 @@ +TARGETNAME=ipoib +TARGETPATH=..\..\..\bin\kernel\obj$(BUILD_ALT_DIR) +TARGETTYPE=DRIVER + +# WDK build - transform .inx --> .inf adding date & version stamp. +# see .\makefile.inc +INF_NAME=netipoib +INF_TARGET=..\..\..\bin\kernel\$(O)\$(INF_NAME).inf +NTTARGETFILES=$(INF_TARGET) + +!if $(FREEBUILD) +ENABLE_EVENT_TRACING=1 +!else +#ENABLE_EVENT_TRACING=1 +!endif + + +SOURCES= ipoib_log.mc \ + ipoib.rc \ + ipoib_driver.cpp \ + ipoib_adapter.cpp \ + ipoib_endpoint.cpp \ + ipoib_port.cpp \ + ipoib_ibat.cpp \ +# ipoib_cm.cpp \ + ipoib_xfr_mgr.cpp \ + ipoib_stat.cpp + +INCLUDES=..;..\..\..\inc;..\..\..\inc\kernel; + +C_DEFINES=$(C_DEFINES) -DNDIS_MINIPORT_DRIVER -DNDIS_WDM=1 \ + -DDEPRECATE_DDK_FUNCTIONS -DNDIS61_MINIPORT=1 -DNEED_CL_OBJ -DBINARY_COMPATIBLE=0 + +TARGETLIBS= \ + $(TARGETPATH)\*\complib.lib \ + $(DDK_LIB_PATH)\ndis.lib \ + $(DDK_LIB_PATH)\ntstrsafe.lib \ + $(DDK_LIB_PATH)\strsafe.lib + +!if !defined(DDK_TARGET_OS) || "$(DDK_TARGET_OS)"=="Win2K" +# +# The driver is built in the Win2K build environment +# - use the library version of safe strings +# +#TARGETLIBS= $(TARGETLIBS) $(DDK_LIB_PATH)\ntstrsafe.lib +!endif + +!IFDEF ENABLE_EVENT_TRACING + +C_DEFINES = $(C_DEFINES) -DEVENT_TRACING + +RUN_WPP = $(SOURCES) -km -ext: .c .cpp .h .C .CPP .H\ + -scan:ipoib_debug.h \ + -func:IPOIB_PRINT(LEVEL,FLAGS,(MSG,...)) \ + -func:IPOIB_PRINT_EXIT(LEVEL,FLAGS,(MSG,...)) +!ENDIF + + +PRECOMPILED_INCLUDE=Precompile.h +PRECOMPILED_PCH=Precompile.pch +PRECOMPILED_CXX=1 + + +MSC_WARNING_LEVEL= /W4 diff --git a/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib.cdf b/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib.cdf new file mode 100644 index 00000000..eb21da98 --- /dev/null +++ b/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib.cdf @@ -0,0 +1,13 @@ +[CatalogHeader] +Name=ipoib.cat +PublicVersion=0x0000001 +EncodingType=0x00010001 +CATATTR1=0x10010001:OSAttr:2:6.0 +[CatalogFiles] +netipoib.inf=netipoib.inf +ipoib.sys=ipoib.sys +ibwsd.dll=ibwsd.dll +ibwsd32.dll=ibwsd32.dll +ibndprov.dll=ibndprov.dll +ibndprov32.dll=ibndprov32.dll +ndinstall.exe=ndinstall.exe diff --git a/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib.rc b/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib.rc new file mode 100644 index 00000000..bc65fe07 --- /dev/null +++ b/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib.rc @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: ipoib.rc 1611 2006-08-20 14:48:55Z sleybo $ + */ + + +#include + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef _DEBUG_ +#define VER_FILEDESCRIPTION_STR "IP over InfiniBand NDIS 6 Miniport (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "IP over InfiniBand NDIS 6 Miniport" +#endif + +#define VER_INTERNALNAME_STR "ipoib.sys" +#define VER_ORIGINALFILENAME_STR "ipoib.sys" + +#include +#include "ipoib_log.rc" diff --git a/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib32.cdf b/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib32.cdf new file mode 100644 index 00000000..50225ba6 --- /dev/null +++ b/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib32.cdf @@ -0,0 +1,11 @@ +[CatalogHeader] +Name=ipoib.cat +PublicVersion=0x0000001 +EncodingType=0x00010001 +CATATTR1=0x10010001:OSAttr:2:6.0 +[CatalogFiles] +netipoib.inf=netipoib.inf +ipoib.sys=ipoib.sys +ibwsd.dll=ibwsd.dll +ibndprov.dll=ibndprov.dll +ndinstall.exe=ndinstall.exe diff --git a/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_adapter.cpp b/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_adapter.cpp new file mode 100644 index 00000000..322b5961 --- /dev/null +++ b/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_adapter.cpp @@ -0,0 +1,1698 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2006 Mellanox Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: ipoib_adapter.c 4506 2009-06-23 14:40:54Z xalex $ + */ + +#include + + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "ipoib_adapter.tmh" +#endif + + +#define ITEM_POOL_START 16 +#define ITEM_POOL_GROW 16 + + +/* IB Link speeds in 100bps */ +#define ONE_X_IN_100BPS 25000000 +#define FOUR_X_IN_100BPS 100000000 +#define TWELVE_X_IN_100BPS 300000000 + + +/* Declarations */ +static void +adapter_construct( + IN ipoib_adapter_t* const p_adapter ); + + +static ib_api_status_t +adapter_init( + IN ipoib_adapter_t* const p_adapter ); + + +static void +__adapter_destroying( + IN cl_obj_t* const p_obj ); + + +static void +__adapter_free( + IN cl_obj_t* const p_obj ); + + +static ib_api_status_t +__ipoib_pnp_reg( + IN ipoib_adapter_t* const p_adapter, + IN ib_pnp_class_t flags ); + + +static void +__ipoib_pnp_dereg( + IN void* context ); + + +static void +__ipoib_adapter_reset( + IN void* context); + + +static ib_api_status_t +__ipoib_pnp_cb( + IN ib_pnp_rec_t *p_pnp_rec ); + + +/* Leaves all mcast groups when port goes down. */ +static void +ipoib_clear_mcast( + IN ipoib_port_t* const p_port ); + +NDIS_STATUS +ipoib_get_adapter_guids( + IN NDIS_HANDLE* const h_adapter, + IN OUT ipoib_adapter_t *p_adapter ); + +NDIS_STATUS +ipoib_get_adapter_params( + IN OUT ipoib_adapter_t *p_adapter, + OUT PUCHAR *p_mac, + OUT UINT *p_len); + + +/* Implementation */ +ib_api_status_t +ipoib_create_adapter( + IN void* const h_adapter, + OUT ipoib_adapter_t** const pp_adapter ) +{ + ipoib_adapter_t *p_adapter; + NDIS_STATUS status; + ib_api_status_t ib_status; + cl_status_t cl_status; + PUCHAR mac; + UINT len; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + p_adapter = (ipoib_adapter_t *) cl_zalloc( sizeof(ipoib_adapter_t) ); + if( !p_adapter ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to allocate ipoib_adapter_t (%d bytes)", + sizeof(ipoib_adapter_t)) ); + return IB_INSUFFICIENT_MEMORY; + } + + adapter_construct( p_adapter ); + + p_adapter->h_adapter = h_adapter; + + p_adapter->p_ifc = (ib_al_ifc_t *) cl_zalloc( sizeof(ib_al_ifc_t) ); + if( !p_adapter->p_ifc ) + { + __adapter_free( &p_adapter->obj ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ipoib_create_adapter failed to alloc ipoib_ifc_t %d bytes\n", + sizeof(ib_al_ifc_t)) ); + return IB_INSUFFICIENT_MEMORY; + } + + /* Get the CA and port GUID from the bus driver. */ + status = ipoib_get_adapter_guids( (NDIS_HANDLE *const) h_adapter, p_adapter ); + if( status != NDIS_STATUS_SUCCESS ) + { + //ASSERT(FALSE); + __adapter_free( &p_adapter->obj ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ipoib_get_adapter_guids returned 0x%.8X.\n", status) ); + return IB_ERROR; + } + + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, + ("Port %016I64x (CA %016I64x port %d) initializing\n", + p_adapter->guids.port_guid.guid, p_adapter->guids.ca_guid, + p_adapter->guids.port_num) ); + + cl_status = cl_obj_init( &p_adapter->obj, CL_DESTROY_SYNC, + __adapter_destroying, NULL, __adapter_free ); + if( cl_status != CL_SUCCESS ) + { + __adapter_free( &p_adapter->obj ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("cl_obj_init returned %#x\n", cl_status) ); + return IB_ERROR; + } + + /* Read configuration parameters. */ + status = ipoib_get_adapter_params( p_adapter , &mac, &len ); + if( status != NDIS_STATUS_SUCCESS ) + { + cl_obj_destroy( &p_adapter->obj ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ipoib_get_adapter_params returned 0x%.8x.\n", status) ); + return IB_ERROR; + } + + ib_status = adapter_init( p_adapter ); + if( ib_status != IB_SUCCESS ) + { + cl_obj_destroy( &p_adapter->obj ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("adapter_init returned %s.\n", + p_adapter->p_ifc->get_err_str( ib_status )) ); + return ib_status; + } + + ETH_COPY_NETWORK_ADDRESS( p_adapter->params.conf_mac.addr, p_adapter->mac.addr ); + /* If there is a NetworkAddress override in registry, use it */ + if( (len == HW_ADDR_LEN) && (mac != NULL) ) + { + if( ETH_IS_MULTICAST(mac) || ETH_IS_BROADCAST(mac) || + !ETH_IS_LOCALLY_ADMINISTERED(mac) ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_INIT, + ("Overriding NetworkAddress is invalid - " + "%02x-%02x-%02x-%02x-%02x-%02x\n", + mac[0], mac[1], mac[2], + mac[3], mac[4], mac[5]) ); + } + else + { + ETH_COPY_NETWORK_ADDRESS( p_adapter->params.conf_mac.addr, mac ); + } + } + + NdisMGetDeviceProperty(h_adapter, &p_adapter->pdo, NULL, NULL, NULL, NULL); + ASSERT(p_adapter->pdo != NULL); + + p_adapter->p_stat = ipoib_st_dev_add(); + if ( p_adapter->p_stat ) + p_adapter->p_stat->p_adapter = p_adapter; + + *pp_adapter = p_adapter; + + IPOIB_EXIT( IPOIB_DBG_INIT ); + return IB_SUCCESS; +} + + +ib_api_status_t +ipoib_start_adapter( + IN ipoib_adapter_t* const p_adapter ) +{ + ib_api_status_t status; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + status = __ipoib_pnp_reg( p_adapter, + IB_PNP_FLAG_REG_SYNC | IB_PNP_FLAG_REG_COMPLETE ); + + IPOIB_EXIT( IPOIB_DBG_INIT ); + return status; +} + + +void +ipoib_destroy_adapter( + IN ipoib_adapter_t* const p_adapter ) +{ + PIPOIB_ST_DEVICE p_stat; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + CL_ASSERT( p_adapter ); + + // statistics + p_stat = p_adapter->p_stat; + if ( p_stat ) { + p_stat->p_halt_thread = KeGetCurrentThread(); + p_stat->p_prev_port = p_adapter->p_port; + } + + /* + * Flag the adapter as being removed. We use the IB_PNP_PORT_REMOVE state + * for this purpose. Note that we protect this state change with both the + * mutex and the lock. The mutex provides synchronization as a whole + * between destruction and AL callbacks (PnP, Query, Destruction). + * The lock provides protection + */ + KeWaitForMutexObject( &p_adapter->mutex, Executive, KernelMode, FALSE, NULL ); + cl_obj_lock( &p_adapter->obj ); + p_adapter->state = IB_PNP_PORT_REMOVE; + + /* + * Clear the pointer to the port object since the object destruction + * will cascade to child objects. This prevents potential duplicate + * destruction (or worse, stale pointer usage). + */ + p_adapter->p_port = NULL; + + cl_obj_unlock( &p_adapter->obj ); + + KeReleaseMutex( &p_adapter->mutex, FALSE ); + + cl_obj_destroy( &p_adapter->obj ); + ipoib_st_dev_rmv( p_stat ); + + IPOIB_EXIT( IPOIB_DBG_INIT ); +} + + +static void +adapter_construct( + IN ipoib_adapter_t* const p_adapter ) +{ + cl_obj_construct( &p_adapter->obj, IPOIB_OBJ_INSTANCE ); + cl_spinlock_construct( &p_adapter->send_stat_lock ); + cl_spinlock_construct( &p_adapter->recv_stat_lock ); + cl_qpool_construct( &p_adapter->item_pool ); + KeInitializeMutex( &p_adapter->mutex, 0 ); + + cl_thread_construct(&p_adapter->destroy_thread); + + cl_vector_construct( &p_adapter->ip_vector ); + + cl_perf_construct( &p_adapter->perf ); + + p_adapter->state = IB_PNP_PORT_ADD; + p_adapter->port_rate = FOUR_X_IN_100BPS; +} + + +static ib_api_status_t +adapter_init( + IN ipoib_adapter_t* const p_adapter ) +{ + cl_status_t cl_status; + ib_api_status_t status; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + cl_status = cl_perf_init( &p_adapter->perf, MaxPerf ); + if( cl_status != CL_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("cl_perf_init returned %#x\n", cl_status) ); + return IB_ERROR; + } + + cl_status = cl_spinlock_init( &p_adapter->send_stat_lock ); + if( cl_status != CL_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("cl_spinlock_init returned %#x\n", cl_status) ); + return IB_ERROR; + } + + cl_status = cl_spinlock_init( &p_adapter->recv_stat_lock ); + if( cl_status != CL_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("cl_spinlock_init returned %#x\n", cl_status) ); + return IB_ERROR; + } + + cl_status = cl_qpool_init( &p_adapter->item_pool, ITEM_POOL_START, 0, + ITEM_POOL_GROW, sizeof(cl_pool_obj_t), NULL, NULL, NULL ); + if( cl_status != CL_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("cl_qpool_init returned %#x\n", cl_status) ); + return IB_ERROR; + } + + + /* We manually manage the size and capacity of the vector. */ + cl_status = cl_vector_init( &p_adapter->ip_vector, 0, + 0, sizeof(net_address_item_t), NULL, NULL, p_adapter ); + if( cl_status != CL_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("cl_vector_init for ip_vector returned %#x\n", + cl_status) ); + return IB_ERROR; + } + + /* Validate the port GUID and generate the MAC address. */ + status = ipoib_mac_from_guid( p_adapter->guids.port_guid.guid, + p_adapter->params.guid_mask, + &p_adapter->mac); + if( status != IB_SUCCESS ) + { + if( status == IB_INVALID_GUID_MASK ) + { + IPOIB_PRINT( TRACE_LEVEL_WARNING, IPOIB_DBG_ERROR, + ("Invalid GUID mask received, rejecting it") ); + ipoib_create_log( p_adapter->h_adapter, + GUID_MASK_LOG_INDEX, + EVENT_IPOIB_WRONG_PARAMETER_WRN ); + } + + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ipoib_mac_from_guid returned %s\n", + p_adapter->p_ifc->get_err_str( status )) ); + return status; + } + + /* Open AL. */ + status = p_adapter->p_ifc->open_al( &p_adapter->h_al ); + if( status != IB_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_open_al returned %s\n", + p_adapter->p_ifc->get_err_str( status )) ); + return status; + } + + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, + ("Shutter Init, state = %d\n", p_adapter->ipoib_state) ); + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_RECV, + ("Shutter Init, state = %d\n", p_adapter->ipoib_state) ); + shutter_init( &p_adapter->recv_shutter ); + + IPOIB_EXIT( IPOIB_DBG_INIT ); + return status; +} + + +static ib_api_status_t +__ipoib_pnp_reg( + IN ipoib_adapter_t* const p_adapter, + IN ib_pnp_class_t flags ) +{ + ib_api_status_t status; + ib_pnp_req_t pnp_req; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + CL_ASSERT( !p_adapter->h_pnp ); + CL_ASSERT( !p_adapter->registering ); + + p_adapter->registering = TRUE; + + /* Register for PNP events. */ + cl_memclr( &pnp_req, sizeof(pnp_req) ); + pnp_req.pnp_class = IB_PNP_PORT | flags; + /* + * Context is the cl_obj of the adapter to allow passing cl_obj_deref + * to ib_dereg_pnp. + */ + pnp_req.pnp_context = &p_adapter->obj; + pnp_req.pfn_pnp_cb = __ipoib_pnp_cb; + status = p_adapter->p_ifc->reg_pnp( p_adapter->h_al, &pnp_req, &p_adapter->h_pnp ); + if( status != IB_SUCCESS ) + { + //ASSERT(FALSE); + p_adapter->registering = FALSE; + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_reg_pnp returned %s\n", + p_adapter->p_ifc->get_err_str( status )) ); + return status; + } + /* + * Reference the adapter on behalf of the PNP registration. + * This allows the destruction to block until the PNP deregistration + * completes. + */ + cl_obj_ref( &p_adapter->obj ); + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_OBJ, + ("[%p] Adapter refcount raised to %d\n", + p_adapter, p_adapter->obj.ref_cnt)); + + IPOIB_EXIT( IPOIB_DBG_INIT ); + return status; +} + + +static void +__adapter_destroying( + IN cl_obj_t* const p_obj ) +{ + ipoib_adapter_t *p_adapter; + KLOCK_QUEUE_HANDLE hdl; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + p_adapter = PARENT_STRUCT( p_obj, ipoib_adapter_t, obj ); + + /* + * The adapter's object will be dereferenced when the deregistration + * completes. No need to lock here since all PnP related API calls + * are driven by NDIS (via the Init/Reset/Destroy paths). + */ + if( p_adapter->h_pnp ) + { + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_OBJ, + ("Adapter[%p] has refcnt= %d\n", p_adapter, p_adapter->obj.ref_cnt)); + p_adapter->p_ifc->dereg_pnp( p_adapter->h_pnp, (ib_pfn_destroy_cb_t) cl_obj_deref ); + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_OBJ, + ("Adapter[%p] refcnt decremented to %d\n", + p_adapter, p_adapter->obj.ref_cnt)); + p_adapter->h_pnp = NULL; + } + + if( p_adapter->packet_filter ) + { + KeAcquireInStackQueuedSpinLock( &g_ipoib.lock, &hdl ); + cl_obj_lock( &p_adapter->obj ); + + ASSERT( cl_qlist_count( &g_ipoib.adapter_list ) ); + cl_qlist_remove_item( &g_ipoib.adapter_list, &p_adapter->entry ); + + p_adapter->packet_filter = 0; + + cl_obj_unlock( &p_adapter->obj ); + KeReleaseInStackQueuedSpinLock( &hdl ); + } + + IPOIB_EXIT( IPOIB_DBG_INIT ); +} + + +static void +__adapter_free( + IN cl_obj_t* const p_obj ) +{ + ipoib_adapter_t *p_adapter; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + p_adapter = PARENT_STRUCT( p_obj, ipoib_adapter_t, obj ); + + if( p_adapter->p_ifc ) + { + if( p_adapter->h_al ) + p_adapter->p_ifc->close_al( p_adapter->h_al ); + + cl_free( p_adapter->p_ifc ); + p_adapter->p_ifc = NULL; + } + + cl_vector_destroy( &p_adapter->ip_vector ); + cl_qpool_destroy( &p_adapter->item_pool ); + cl_spinlock_destroy( &p_adapter->recv_stat_lock ); + cl_spinlock_destroy( &p_adapter->send_stat_lock ); + cl_obj_deinit( p_obj ); + + cl_perf_destroy( &p_adapter->perf, TRUE ); + + cl_free( p_adapter ); + + IPOIB_EXIT( IPOIB_DBG_INIT ); +} + + +static ib_api_status_t +ipoib_query_pkey_index(ipoib_adapter_t *p_adapter) +{ + ib_api_status_t status; + ib_ca_attr_t *ca_attr; + uint32_t ca_size; + uint16_t index = 0; + + /* Query the CA for Pkey table */ + status = p_adapter->p_ifc->query_ca(p_adapter->p_port->ib_mgr.h_ca, NULL, &ca_size); + if(status != IB_INSUFFICIENT_MEMORY) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_query_ca failed\n")); + return status; + } + + ca_attr = (ib_ca_attr_t*)cl_zalloc(ca_size); + if (!ca_attr) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("cl_zalloc can't allocate %d\n",ca_size)); + return IB_INSUFFICIENT_MEMORY; + } + + status = p_adapter->p_ifc->query_ca(p_adapter->p_port->ib_mgr.h_ca, ca_attr,&ca_size); + if( status != IB_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_query_ca returned %s\n", + p_adapter->p_ifc->get_err_str( status )) ); + goto pkey_end; + } + CL_ASSERT(ca_attr->p_port_attr[p_adapter->p_port->port_num -1].p_pkey_table[0] == IB_DEFAULT_PKEY); + for(index = 0; index < ca_attr->p_port_attr[p_adapter->p_port->port_num -1].num_pkeys; index++) + { + if(cl_hton16(p_adapter->guids.port_guid.pkey) == ca_attr->p_port_attr[p_adapter->p_port->port_num -1].p_pkey_table[index]) + break; + } + if(index >= ca_attr->p_port_attr[p_adapter->p_port->port_num -1].num_pkeys) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Pkey table is invalid, index not found\n")); + NdisWriteErrorLogEntry( p_adapter->h_adapter, + EVENT_IPOIB_PARTITION_ERR, 1, p_adapter->guids.port_guid.pkey ); + status = IB_NOT_FOUND; + p_adapter->p_port->pkey_index = PKEY_INVALID_INDEX; + goto pkey_end; + } + + p_adapter->p_port->pkey_index = index; + IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_IB, + ("for PKEY = 0x%04X got index = %d\n",p_adapter->guids.port_guid.pkey,index)); + +pkey_end: + if(ca_attr) + cl_free(ca_attr); + return status; +} + +static inline void __ipoib_get_down( + IN ipoib_adapter_t *p_adapter) +{ + + NDIS_LINK_STATE link_state; + NDIS_STATUS_INDICATION status_indication; + + link_state.Header.Revision = NDIS_LINK_STATE_REVISION_1; + link_state.Header.Type = NDIS_OBJECT_TYPE_DEFAULT; + link_state.Header.Size = sizeof(NDIS_LINK_STATE); + link_state.MediaConnectState = MediaConnectStateDisconnected; + link_state.MediaDuplexState = MediaDuplexStateFull; + link_state.XmitLinkSpeed = + link_state.RcvLinkSpeed = SET_PORT_RATE_BPS( p_adapter->port_rate ); + link_state.PauseFunctions = NdisPauseFunctionsSendAndReceive; + + IPOIB_INIT_NDIS_STATUS_INDICATION(&status_indication, + p_adapter->h_adapter, + NDIS_STATUS_LINK_STATE, + (PVOID)&link_state, + sizeof(link_state)); + + NdisMIndicateStatusEx(p_adapter->h_adapter,&status_indication); + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, + ("Link DOWN!\n") ); + + ipoib_port_down( p_adapter->p_port ); +} + +static ib_api_status_t +__ipoib_pnp_cb( + IN ib_pnp_rec_t *p_pnp_rec ) +{ + ipoib_adapter_t *p_adapter; + ipoib_port_t *p_port; + ib_pnp_event_t old_state; + ib_pnp_port_rec_t *p_port_rec; + ib_api_status_t status = IB_SUCCESS; + NDIS_LINK_STATE link_state; + NDIS_STATUS_INDICATION status_indication; + + IPOIB_ENTER( IPOIB_DBG_PNP ); + + CL_ASSERT( p_pnp_rec ); + NdisZeroMemory(&link_state, sizeof(NDIS_LINK_STATE)); + p_adapter = + PARENT_STRUCT( p_pnp_rec->pnp_context, ipoib_adapter_t, obj ); + + CL_ASSERT( p_adapter ); + + /* Synchronize with destruction */ + KeWaitForMutexObject( + &p_adapter->mutex, Executive, KernelMode, FALSE, NULL ); + cl_obj_lock( &p_adapter->obj ); + old_state = p_adapter->state; + cl_obj_unlock( &p_adapter->obj ); + if( old_state == IB_PNP_PORT_REMOVE ) + { + KeReleaseMutex( &p_adapter->mutex, FALSE ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_PNP, + ("Aborting - Adapter destroying.\n") ); + return IB_NOT_DONE; + } + + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_PNP, + ("p_pnp_rec->pnp_event = 0x%x (%s)\n", + p_pnp_rec->pnp_event, ib_get_pnp_event_str( p_pnp_rec->pnp_event )) ); + + p_port_rec = (ib_pnp_port_rec_t*)p_pnp_rec; + + switch( p_pnp_rec->pnp_event ) + { + case IB_PNP_PORT_ADD: + CL_ASSERT( !p_pnp_rec->context ); + /* Only process our port GUID. */ + if( p_pnp_rec->guid != p_adapter->guids.port_guid.guid ) + { + status = IB_NOT_DONE; + break; + } + + /* Don't process if we're destroying. */ + if( p_adapter->obj.state == CL_DESTROYING ) + { + status = IB_NOT_DONE; + break; + } + + CL_ASSERT( !p_adapter->p_port ); + /* Allocate all IB resources. */ + cl_obj_lock( &p_adapter->obj ); + p_adapter->state = IB_PNP_PORT_ADD; + cl_obj_unlock( &p_adapter->obj ); + status = ipoib_create_port( p_adapter, p_port_rec, &p_port ); + cl_obj_lock( &p_adapter->obj ); + if( status != IB_SUCCESS ) + { + p_adapter->state = old_state; + cl_obj_unlock( &p_adapter->obj ); + p_adapter->hung = TRUE; + break; + } + + p_pnp_rec->context = p_port; + if ( p_adapter->p_stat ) + p_adapter->p_stat->p_prev_port = p_adapter->p_port; + p_adapter->p_port = p_port; + cl_obj_unlock( &p_adapter->obj ); + break; + + case IB_PNP_PORT_REMOVE: + + if (p_adapter->state != IB_PNP_PORT_DOWN) { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + (" Port got IB_PNP_PORT_REMOVE before IB_PNP_PORT_DOWN\n")); + __ipoib_get_down( p_adapter); + } + + /* Release all IB resources. */ + CL_ASSERT( p_pnp_rec->context ); + + cl_obj_lock( &p_adapter->obj ); + p_adapter->state = IB_PNP_PORT_REMOVE; + p_port = p_adapter->p_port; + p_adapter->p_port = NULL; + if ( p_adapter->p_stat ) + p_adapter->p_stat->p_prev_port = p_port; + cl_obj_unlock( &p_adapter->obj ); + ipoib_port_destroy( p_port ); + p_pnp_rec->context = NULL; + status = IB_SUCCESS; + break; + + case IB_PNP_PORT_ACTIVE: + /* Join multicast groups and put QP in RTS. */ + CL_ASSERT( p_pnp_rec->context ); + + cl_obj_lock( &p_adapter->obj ); + p_adapter->state = IB_PNP_PORT_INIT; + cl_obj_unlock( &p_adapter->obj ); + ipoib_port_up( p_adapter->p_port, p_port_rec ); + + status = IB_SUCCESS; + break; + + case IB_PNP_PORT_ARMED: + status = IB_SUCCESS; + break; + + case IB_PNP_PORT_INIT: + /* + * Init could happen if the SM brings the port down + * without changing the physical link. + */ + case IB_PNP_PORT_DOWN: + CL_ASSERT( p_pnp_rec->context ); + + cl_obj_lock( &p_adapter->obj ); + old_state = p_adapter->state; + ASSERT( p_adapter->state != IB_PNP_PORT_REMOVE ); + p_adapter->state = IB_PNP_PORT_DOWN; + cl_obj_unlock( &p_adapter->obj ); + status = IB_SUCCESS; + + if( !p_adapter->registering && old_state != IB_PNP_PORT_DOWN ) + { + __ipoib_get_down( p_adapter ); + } + break; + + case IB_PNP_REG_COMPLETE: + if( p_adapter->registering ) + { + p_adapter->registering = FALSE; + cl_obj_lock( &p_adapter->obj ); + old_state = p_adapter->state; + cl_obj_unlock( &p_adapter->obj ); + + if( old_state == IB_PNP_PORT_DOWN ) + { + /* If we were initializing, we might have pended some OIDs. */ + ipoib_resume_oids( p_adapter ); + + link_state.Header.Revision = NDIS_LINK_STATE_REVISION_1; + link_state.Header.Type = NDIS_OBJECT_TYPE_DEFAULT; + link_state.Header.Size = sizeof(NDIS_LINK_STATE); + link_state.MediaConnectState = MediaConnectStateDisconnected; + link_state.MediaDuplexState = MediaDuplexStateFull; + link_state.XmitLinkSpeed = + link_state.RcvLinkSpeed = SET_PORT_RATE_BPS( p_adapter->port_rate ); + link_state.PauseFunctions = NdisPauseFunctionsSendAndReceive; + + IPOIB_INIT_NDIS_STATUS_INDICATION(&status_indication, + p_adapter->h_adapter, + NDIS_STATUS_LINK_STATE, + (PVOID)&link_state, + sizeof(link_state)); + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_INIT, ("Indicate DISCONNECT\n") ); + NdisMIndicateStatusEx(p_adapter->h_adapter,&status_indication); + } + } + + if( p_adapter->reset && p_adapter->state != IB_PNP_PORT_INIT ) + { + p_adapter->reset = FALSE; + NdisMResetComplete( + p_adapter->h_adapter, NDIS_STATUS_SUCCESS, TRUE ); + } + status = IB_SUCCESS; + break; + + default: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, + ("IPOIB: Received unhandled PnP event 0x%x (%s)\n", + p_pnp_rec->pnp_event, ib_get_pnp_event_str( p_pnp_rec->pnp_event )) ); + /* Fall through. */ + + status = IB_SUCCESS; + + /* We ignore events below if the link is not active. */ + if( p_port_rec->p_port_attr->link_state != IB_LINK_ACTIVE ) + break; + + case IB_PNP_PKEY_CHANGE: + if(p_pnp_rec->pnp_event == IB_PNP_PKEY_CHANGE && + p_adapter->guids.port_guid.pkey != IB_DEFAULT_PKEY) + { + status = ipoib_query_pkey_index(p_adapter); + if(status != IB_SUCCESS) + { + cl_obj_lock( &p_adapter->obj ); + p_adapter->state = IB_PNP_PORT_INIT; + cl_obj_unlock( &p_adapter->obj ); + } + } + + case IB_PNP_SM_CHANGE: + case IB_PNP_GID_CHANGE: + case IB_PNP_LID_CHANGE: + + cl_obj_lock( &p_adapter->obj ); + old_state = p_adapter->state; + switch( old_state ) + { + case IB_PNP_PORT_DOWN: + p_adapter->state = IB_PNP_PORT_INIT; + break; + + default: + p_adapter->state = IB_PNP_PORT_DOWN; + } + cl_obj_unlock( &p_adapter->obj ); + + if( p_adapter->registering ) + break; + + switch( old_state ) + { + case IB_PNP_PORT_ACTIVE: + case IB_PNP_PORT_INIT: + link_state.Header.Revision = NDIS_LINK_STATE_REVISION_1; + link_state.Header.Type = NDIS_OBJECT_TYPE_DEFAULT; + link_state.Header.Size = sizeof(NDIS_LINK_STATE); + link_state.MediaConnectState = MediaConnectStateDisconnected; + link_state.MediaDuplexState = MediaDuplexStateFull; + link_state.XmitLinkSpeed = + link_state.RcvLinkSpeed = SET_PORT_RATE_BPS( p_adapter->port_rate ); + link_state.PauseFunctions = NdisPauseFunctionsSendAndReceive; + + IPOIB_INIT_NDIS_STATUS_INDICATION(&status_indication, + p_adapter->h_adapter, + NDIS_STATUS_LINK_STATE, + (PVOID)&link_state, + sizeof(link_state)); + + NdisMIndicateStatusEx(p_adapter->h_adapter,&status_indication); + + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, + ("Link DOWN!\n") ); + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_INIT, + ("Indicate DISCONNECT\n") ); + + ipoib_port_down( p_adapter->p_port ); + /* Fall through. */ + + case IB_PNP_PORT_DOWN: + cl_obj_lock( &p_adapter->obj ); + p_adapter->state = IB_PNP_PORT_INIT; + cl_obj_unlock( &p_adapter->obj ); + ipoib_port_up( p_adapter->p_port, (ib_pnp_port_rec_t*)p_pnp_rec ); + } + break; + } + + KeReleaseMutex( &p_adapter->mutex, FALSE ); + + IPOIB_EXIT( IPOIB_DBG_PNP ); + return status; +} + + +/* Joins/leaves mcast groups based on currently programmed mcast MACs. */ +void +ipoib_refresh_mcast( + IN ipoib_adapter_t* const p_adapter, + IN mac_addr_t* const p_mac_array, + IN const uint8_t num_macs ) +{ + uint8_t i, j; + ipoib_port_t *p_port = NULL; + + IPOIB_ENTER( IPOIB_DBG_MCAST ); + cl_obj_lock( &p_adapter->obj ); + if( p_adapter->state == IB_PNP_PORT_ACTIVE ) + { + p_port = p_adapter->p_port; + ipoib_port_ref( p_port, ref_refresh_mcast ); + } + cl_obj_unlock( &p_adapter->obj ); + + if( p_port ) + { + /* Purge old entries. */ + for( i = 0; i < p_adapter->mcast_array_size; i++ ) + { + for( j = 0; j < num_macs; j++ ) + { + if( !cl_memcmp( &p_adapter->mcast_array[i], &p_mac_array[j], + sizeof(mac_addr_t) ) ) + { + break; + } + } + if( j != num_macs ) + continue; + + ipoib_port_remove_endpt( p_port, p_adapter->mcast_array[i] ); + } + + /* Add new entries */ + for( i = 0; i < num_macs; i++ ) + { + for( j = 0; j < p_adapter->mcast_array_size; j++ ) + { + if( !cl_memcmp( &p_adapter->mcast_array[j], &p_mac_array[i], + sizeof(mac_addr_t) ) ) + { + break; + } + } + + if( j != p_adapter->mcast_array_size ) + continue; + if ( ( p_mac_array[i].addr[0] == 1 && p_mac_array[i].addr[1] == 0 && p_mac_array[i].addr[2] == 0x5e && + p_mac_array[i].addr[3] == 0 && p_mac_array[i].addr[4] == 0 && p_mac_array[i].addr[5] == 1 ) || + !( p_mac_array[i].addr[0] == 1 && p_mac_array[i].addr[1] == 0 && p_mac_array[i].addr[2] == 0x5e ) + ) + { + + ipoib_port_join_mcast( p_port, p_mac_array[i], IB_MC_REC_STATE_FULL_MEMBER ); + } + } + } + + /* Copy the MAC array. */ + NdisMoveMemory( p_adapter->mcast_array, p_mac_array, + num_macs * sizeof(mac_addr_t) ); + p_adapter->mcast_array_size = num_macs; + + if( p_port ) + ipoib_port_deref( p_port, ref_refresh_mcast ); + + IPOIB_EXIT( IPOIB_DBG_MCAST ); +} + + +ib_api_status_t +ipoib_reset_adapter( + IN ipoib_adapter_t* const p_adapter ) +{ + ib_api_status_t status; + ib_pnp_handle_t h_pnp; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + if( p_adapter->reset ) + return IB_INVALID_STATE; + + p_adapter->hung = FALSE; + p_adapter->reset = TRUE; + + if( p_adapter->h_pnp ) + { + h_pnp = p_adapter->h_pnp; + p_adapter->h_pnp = NULL; + status = p_adapter->p_ifc->dereg_pnp( h_pnp, __ipoib_pnp_dereg ); + if( status == IB_SUCCESS ) + status = IB_NOT_DONE; + } + else + { + status = __ipoib_pnp_reg( p_adapter, IB_PNP_FLAG_REG_COMPLETE ); + if( status == IB_SUCCESS ) + p_adapter->hung = FALSE; + } + if (status == IB_NOT_DONE) { + p_adapter->reset = TRUE; + } + else { + p_adapter->reset = FALSE; + } + IPOIB_EXIT( IPOIB_DBG_INIT ); + return status; +} + + +static void +__ipoib_pnp_dereg( + IN void* context ) +{ + ipoib_adapter_t* p_adapter; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + p_adapter = PARENT_STRUCT( context, ipoib_adapter_t, obj ); + + cl_thread_init(&p_adapter->destroy_thread, __ipoib_adapter_reset, (void*)p_adapter, "destroy_thread"); + + IPOIB_ENTER( IPOIB_DBG_INIT ); + +} + +static void +__ipoib_adapter_reset( + IN void* context) +{ + + ipoib_adapter_t *p_adapter; + ipoib_port_t *p_port; + ib_api_status_t status; + ib_pnp_event_t state; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Got RESET\n") ); + + p_adapter = (ipoib_adapter_t*)context; + + /* Synchronize with destruction */ + KeWaitForMutexObject( + &p_adapter->mutex, Executive, KernelMode, FALSE, NULL ); + + cl_obj_lock( &p_adapter->obj ); + + CL_ASSERT( !p_adapter->h_pnp ); + + if( p_adapter->state != IB_PNP_PORT_REMOVE ) + p_adapter->state = IB_PNP_PORT_ADD; + + state = p_adapter->state; + + /* Destroy the current port instance if it still exists. */ + p_port = p_adapter->p_port; + p_adapter->p_port = NULL; + if ( p_adapter->p_stat ) + p_adapter->p_stat->p_prev_port = p_port; + cl_obj_unlock( &p_adapter->obj ); + + if( p_port ) + ipoib_port_destroy( p_port ); + ASSERT(p_adapter->reset == TRUE); + if( state != IB_PNP_PORT_REMOVE ) + { + status = __ipoib_pnp_reg( p_adapter, IB_PNP_FLAG_REG_COMPLETE ); + if( status != IB_SUCCESS ) + { + p_adapter->reset = FALSE; + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("__ipoib_pnp_reg returned %s\n", + p_adapter->p_ifc->get_err_str( status )) ); + NdisMResetComplete( + p_adapter->h_adapter, NDIS_STATUS_HARD_ERRORS, TRUE ); + } + } + else + { + p_adapter->reset = FALSE; + NdisMResetComplete( + p_adapter->h_adapter, NDIS_STATUS_SUCCESS, TRUE ); + status = IB_SUCCESS; + } + + /* Dereference the adapter since the previous registration is now gone. */ + cl_obj_deref( &p_adapter->obj ); + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_OBJ, + ("Adapter[%p] refcnt decremented to %d\n", p_adapter, p_adapter->obj.ref_cnt)); + + KeReleaseMutex( &p_adapter->mutex, FALSE ); + + IPOIB_EXIT( IPOIB_DBG_INIT ); +} + + +void +ipoib_set_rate( + IN ipoib_adapter_t* const p_adapter, + IN const uint8_t link_width, + IN const uint8_t link_speed ) +{ + uint32_t rate; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + /* Set the link speed based on the IB link speed (1x vs 4x, etc). */ + switch( link_speed ) + { + case IB_LINK_SPEED_ACTIVE_2_5: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, + ("Link speed is 2.5Gs\n") ); + rate = IB_LINK_SPEED_ACTIVE_2_5; + break; + + case IB_LINK_SPEED_ACTIVE_5: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, + ("Link speed is 5G\n") ); + rate = IB_LINK_SPEED_ACTIVE_5; + break; + + case IB_LINK_SPEED_ACTIVE_10: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, + ("Link speed is 10G\n") ); + rate = IB_LINK_SPEED_ACTIVE_10; + break; + + default: + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Invalid link speed %d.\n", link_speed) ); + rate = 0; + } + + switch( link_width ) + { + case IB_LINK_WIDTH_ACTIVE_1X: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, + ("Link width is 1X\n") ); + rate *= ONE_X_IN_100BPS; + break; + + case IB_LINK_WIDTH_ACTIVE_4X: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, + ("Link width is 4X\n") ); + rate *= FOUR_X_IN_100BPS; + break; + + case IB_LINK_WIDTH_ACTIVE_12X: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, + ("Link width is 12X\n") ); + rate *= TWELVE_X_IN_100BPS; + break; + + default: + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Invalid link rate (%d).\n", link_width) ); + rate = 0; + } + + p_adapter->port_rate = rate; + IPOIB_EXIT( IPOIB_DBG_INIT ); +} + + +ib_api_status_t +ipoib_set_active( + IN ipoib_adapter_t* const p_adapter ) +{ + ib_pnp_event_t old_state; + uint8_t i; + ib_api_status_t status = IB_SUCCESS; + NDIS_LINK_STATE link_state; + NDIS_STATUS_INDICATION status_indication; + IPOIB_ENTER( IPOIB_DBG_INIT ); + + NdisZeroMemory(&link_state, sizeof(NDIS_LINK_STATE)); + cl_obj_lock( &p_adapter->obj ); + old_state = p_adapter->state; + + /* Change the state to indicate that we are now connected and live. */ + if( old_state == IB_PNP_PORT_INIT ) + p_adapter->state = IB_PNP_PORT_ACTIVE; + + cl_obj_unlock( &p_adapter->obj ); + + /* + * If we had a pending OID request for OID_GEN_LINK_SPEED, + * complete it now. + */ + switch( old_state ) + { + case IB_PNP_PORT_ADD: + ipoib_reg_addrs( p_adapter ); + /* Fall through. */ + + case IB_PNP_PORT_REMOVE: + ipoib_resume_oids( p_adapter ); + break; + + default: + if (p_adapter->guids.port_guid.pkey != IB_DEFAULT_PKEY) + { + status = ipoib_query_pkey_index(p_adapter); + if( IB_SUCCESS != status) + { + break; + } + } + /* Join all programmed multicast groups. */ + for( i = 0; i < p_adapter->mcast_array_size; i++ ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_MCAST, + ("Calling join mcast from ipoib_set_active\n")); + ipoib_port_join_mcast( p_adapter->p_port, + p_adapter->mcast_array[i], + IB_MC_REC_STATE_FULL_MEMBER ); + } + + /* Register all existing addresses. */ + ipoib_reg_addrs( p_adapter ); + + ipoib_resume_oids( p_adapter ); + + /* + * Now that we're in the broadcast group, notify that + * we have a link. + */ + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, + ("Link UP! in the broadcast group\n") ); + NdisWriteErrorLogEntry( p_adapter->h_adapter, + EVENT_IPOIB_PORT_UP + (p_adapter->port_rate/ONE_X_IN_100BPS), + 1, p_adapter->port_rate ); + + if( !p_adapter->reset ) + { + link_state.Header.Revision = NDIS_LINK_STATE_REVISION_1; + link_state.Header.Type = NDIS_OBJECT_TYPE_DEFAULT; + link_state.Header.Size = sizeof(NDIS_LINK_STATE); + link_state.MediaConnectState = MediaConnectStateConnected; + link_state.MediaDuplexState = MediaDuplexStateFull; + link_state.XmitLinkSpeed = + link_state.RcvLinkSpeed = SET_PORT_RATE_BPS( p_adapter->port_rate ); + link_state.PauseFunctions = NdisPauseFunctionsSendAndReceive; + IPOIB_INIT_NDIS_STATUS_INDICATION(&status_indication, + p_adapter->h_adapter, + NDIS_STATUS_LINK_STATE, + (PVOID)&link_state, + sizeof(link_state)); + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, + ("***************Indicate connect!\n") ); + NdisMIndicateStatusEx(p_adapter->h_adapter,&status_indication); + } + } + + if( p_adapter->reset ) + { + //ASSERT(FALSE); + p_adapter->reset = FALSE; + NdisMResetComplete( + p_adapter->h_adapter, NDIS_STATUS_SUCCESS, TRUE ); + } + + IPOIB_EXIT( IPOIB_DBG_INIT ); + return status; +} + +/* + * If something goes wrong after the port goes active, e.g. + * - PortInfo query failure + * - MC Join timeout + * - etc + * Mark the port state as down, resume any pended OIDS, etc. + */ +void +ipoib_set_inactive( + IN ipoib_adapter_t* const p_adapter ) +{ + ib_pnp_event_t old_state; + NDIS_LINK_STATE link_state; + NDIS_STATUS_INDICATION status_indication; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + NdisZeroMemory(&link_state, sizeof(NDIS_LINK_STATE)); + cl_obj_lock( &p_adapter->obj ); + old_state = p_adapter->state; + if( old_state != IB_PNP_PORT_REMOVE ) + p_adapter->state = IB_PNP_PORT_DOWN; + cl_obj_unlock( &p_adapter->obj ); + + /* + * If we had a pending OID request for OID_GEN_LINK_SPEED, + * complete it now. + */ + if( old_state == IB_PNP_PORT_INIT ) + { + link_state.Header.Revision = NDIS_LINK_STATE_REVISION_1; + link_state.Header.Type = NDIS_OBJECT_TYPE_DEFAULT; + link_state.Header.Size = sizeof(NDIS_LINK_STATE); + link_state.MediaConnectState = MediaConnectStateDisconnected; + link_state.MediaDuplexState = MediaDuplexStateFull; + link_state.XmitLinkSpeed = + link_state.RcvLinkSpeed = SET_PORT_RATE_BPS( p_adapter->port_rate ); + link_state.PauseFunctions = NdisPauseFunctionsSendAndReceive; + + IPOIB_INIT_NDIS_STATUS_INDICATION(&status_indication, + p_adapter->h_adapter, + NDIS_STATUS_LINK_STATE, + (PVOID)&link_state, + sizeof(link_state)); + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, ("Indicate Disconnect!\n") ); + NdisMIndicateStatusEx(p_adapter->h_adapter,&status_indication); + + ipoib_resume_oids( p_adapter ); + } + + if( p_adapter->reset ) + { + p_adapter->reset = FALSE; + NdisMResetComplete( + p_adapter->h_adapter, NDIS_STATUS_SUCCESS, TRUE ); + } + + IPOIB_EXIT( IPOIB_DBG_INIT ); +} + +NDIS_STATUS +ipoib_get_gen_stat( + IN ipoib_adapter_t* const p_adapter, + OUT pending_oid_t* const p_oid_info) +{ + PNDIS_STATISTICS_INFO StatisticsInfo; + + IPOIB_ENTER( IPOIB_DBG_STAT ); + + if (p_oid_info->buf_len < sizeof(StatisticsInfo)) + { + *p_oid_info->p_bytes_needed = sizeof(NDIS_STATISTICS_INFO); + return NDIS_STATUS_INVALID_LENGTH; + } + + StatisticsInfo = (PNDIS_STATISTICS_INFO)p_oid_info->p_buf; + StatisticsInfo->Header.Revision = NDIS_OBJECT_REVISION_1; + StatisticsInfo->Header.Type = NDIS_OBJECT_TYPE_DEFAULT; + StatisticsInfo->Header.Size = sizeof(NDIS_STATISTICS_INFO); + /*StatisticsInfo->SupportedStatistics = + NDIS_STATISTICS_FLAGS_VALID_RCV_DISCARDS | + NDIS_STATISTICS_FLAGS_VALID_RCV_ERROR | + NDIS_STATISTICS_FLAGS_VALID_DIRECTED_FRAMES_RCV | + NDIS_STATISTICS_FLAGS_VALID_MULTICAST_FRAMES_RCV | + NDIS_STATISTICS_FLAGS_VALID_BROADCAST_FRAMES_RCV | + NDIS_STATISTICS_FLAGS_VALID_BYTES_RCV | + NDIS_STATISTICS_FLAGS_VALID_MULTICAST_BYTES_RCV | + NDIS_STATISTICS_FLAGS_VALID_BROADCAST_BYTES_RCV | + NDIS_STATISTICS_FLAGS_VALID_DIRECTED_BYTES_RCV | + NDIS_STATISTICS_FLAGS_VALID_XMIT_DISCARDS | + NDIS_STATISTICS_FLAGS_VALID_XMIT_ERROR | + NDIS_STATISTICS_FLAGS_VALID_DIRECTED_FRAMES_XMIT | + NDIS_STATISTICS_FLAGS_VALID_MULTICAST_FRAMES_XMIT | + NDIS_STATISTICS_FLAGS_VALID_BROADCAST_FRAMES_XMIT | + NDIS_STATISTICS_FLAGS_VALID_BYTES_XMIT | + NDIS_STATISTICS_FLAGS_VALID_DIRECTED_BYTES_XMIT | + NDIS_STATISTICS_FLAGS_VALID_MULTICAST_BYTES_XMIT | + NDIS_STATISTICS_FLAGS_VALID_BROADCAST_BYTES_XMIT; */ + + + StatisticsInfo->SupportedStatistics = + NDIS_STATISTICS_FLAGS_VALID_DIRECTED_FRAMES_RCV | + //The data in the ifHCInUcastPkts member is valid. + NDIS_STATISTICS_FLAGS_VALID_MULTICAST_FRAMES_RCV | + //The data in the ifHCInMulticastPkts member is valid. + NDIS_STATISTICS_FLAGS_VALID_BROADCAST_FRAMES_RCV | + //The data in the ifHCInBroadcastPkts member is valid. + NDIS_STATISTICS_FLAGS_VALID_BYTES_RCV | + //The data in the ifHCInOctets member is valid. + NDIS_STATISTICS_FLAGS_VALID_RCV_DISCARDS | + //The data in the ifInDiscards member is valid. + NDIS_STATISTICS_FLAGS_VALID_RCV_ERROR | + //The data in the ifInErrors member is valid. + NDIS_STATISTICS_FLAGS_VALID_DIRECTED_FRAMES_XMIT | + //The data in the ifHCOutUcastPkts member is valid. + NDIS_STATISTICS_FLAGS_VALID_MULTICAST_FRAMES_XMIT | + //The data in the ifHCOutMulticastPkts member is valid. + NDIS_STATISTICS_FLAGS_VALID_BROADCAST_FRAMES_XMIT | + //The data in the ifHCOutBroadcastPkts member is valid. + NDIS_STATISTICS_FLAGS_VALID_BYTES_XMIT | + //The data in the ifHCOutOctets member is valid. + NDIS_STATISTICS_FLAGS_VALID_XMIT_ERROR | + //The data in the ifOutErrors member is valid. + NDIS_STATISTICS_FLAGS_VALID_XMIT_DISCARDS | + //The data in the ifOutDiscards member is valid. + NDIS_STATISTICS_FLAGS_VALID_DIRECTED_BYTES_RCV | + //The data in the ifHCInUcastOctets member is valid. + NDIS_STATISTICS_FLAGS_VALID_MULTICAST_BYTES_RCV | + //The data in the ifHCInMulticastOctets member is valid. + NDIS_STATISTICS_FLAGS_VALID_BROADCAST_BYTES_RCV | + //The data in the ifHCInBroadcastOctets member is valid. + NDIS_STATISTICS_FLAGS_VALID_DIRECTED_BYTES_XMIT | + //The data in the ifHCOutUcastOctets member is valid. + NDIS_STATISTICS_FLAGS_VALID_MULTICAST_BYTES_XMIT | + //The data in the ifHCOutMulticastOctets member is valid. + NDIS_STATISTICS_FLAGS_VALID_BROADCAST_BYTES_XMIT ; + //The data in the ifHCOutBroadcastOctets member is valid + + cl_spinlock_acquire( &p_adapter->recv_stat_lock ); + StatisticsInfo->ifInDiscards = p_adapter->recv_stats.comp.dropped + + p_adapter->recv_stats.comp.error; + StatisticsInfo->ifInErrors = p_adapter->recv_stats.comp.error; + StatisticsInfo->ifHCInOctets = p_adapter->recv_stats.ucast.bytes + + p_adapter->recv_stats.bcast.bytes + + p_adapter->recv_stats.mcast.bytes; + StatisticsInfo->ifHCInUcastPkts = p_adapter->recv_stats.ucast.frames; + StatisticsInfo->ifHCInMulticastPkts = p_adapter->recv_stats.mcast.frames; + StatisticsInfo->ifHCInBroadcastPkts = p_adapter->recv_stats.bcast.frames; + StatisticsInfo->ifHCInMulticastOctets = p_adapter->recv_stats.mcast.bytes; + StatisticsInfo->ifHCInBroadcastOctets = p_adapter->recv_stats.bcast.bytes; + StatisticsInfo->ifHCInUcastOctets = p_adapter->recv_stats.ucast.bytes; + cl_spinlock_release( &p_adapter->recv_stat_lock ); + + cl_spinlock_acquire( &p_adapter->send_stat_lock ); + StatisticsInfo->ifHCOutOctets = p_adapter->send_stats.ucast.bytes + + p_adapter->send_stats.mcast.bytes + + p_adapter->send_stats.bcast.bytes; + StatisticsInfo->ifHCOutUcastPkts = p_adapter->send_stats.ucast.frames; + StatisticsInfo->ifHCOutMulticastPkts = p_adapter->send_stats.mcast.frames; + StatisticsInfo->ifHCOutBroadcastPkts = p_adapter->send_stats.bcast.frames; + StatisticsInfo->ifOutErrors = p_adapter->send_stats.comp.error; + StatisticsInfo->ifOutDiscards = p_adapter->send_stats.comp.dropped; + StatisticsInfo->ifHCOutUcastOctets = p_adapter->send_stats.ucast.bytes; + StatisticsInfo->ifHCOutMulticastOctets = p_adapter->send_stats.mcast.bytes; + StatisticsInfo->ifHCOutBroadcastOctets = p_adapter->send_stats.bcast.bytes; + cl_spinlock_release( &p_adapter->send_stat_lock ); + + *p_oid_info->p_bytes_used = sizeof(NDIS_STATISTICS_INFO); + + IPOIB_EXIT( IPOIB_DBG_STAT ); + return NDIS_STATUS_SUCCESS; +} + +NDIS_STATUS +ipoib_get_recv_stat( + IN ipoib_adapter_t* const p_adapter, + IN const ip_stat_sel_t stat_sel, + IN pending_oid_t* const p_oid_info ) +{ + uint64_t stat; + + IPOIB_ENTER( IPOIB_DBG_STAT ); + + CL_ASSERT( p_adapter ); + + cl_spinlock_acquire( &p_adapter->recv_stat_lock ); + switch( stat_sel ) + { + case IP_STAT_SUCCESS: + stat = p_adapter->recv_stats.comp.success; + break; + + case IP_STAT_ERROR: + stat = p_adapter->recv_stats.comp.error; + break; + + case IP_STAT_DROPPED: + stat = p_adapter->recv_stats.comp.dropped; + break; + + case IP_STAT_UCAST_BYTES: + stat = p_adapter->recv_stats.ucast.bytes; + break; + + case IP_STAT_UCAST_FRAMES: + stat = p_adapter->recv_stats.ucast.frames; + break; + + case IP_STAT_BCAST_BYTES: + stat = p_adapter->recv_stats.bcast.bytes; + break; + + case IP_STAT_BCAST_FRAMES: + stat = p_adapter->recv_stats.bcast.frames; + break; + + case IP_STAT_MCAST_BYTES: + stat = p_adapter->recv_stats.mcast.bytes; + break; + + case IP_STAT_MCAST_FRAMES: + stat = p_adapter->recv_stats.mcast.frames; + break; + + default: + stat = 0; + } + cl_spinlock_release( &p_adapter->recv_stat_lock ); + + *p_oid_info->p_bytes_needed = sizeof(uint64_t); + + if( p_oid_info->buf_len >= sizeof(uint64_t) ) + { + *((uint64_t*)p_oid_info->p_buf) = stat; + *p_oid_info->p_bytes_used = sizeof(uint64_t); + } + else if( p_oid_info->buf_len >= sizeof(uint32_t) ) + { + *((uint32_t*)p_oid_info->p_buf) = (uint32_t)stat; + *p_oid_info->p_bytes_used = sizeof(uint32_t); + } + else + { + *p_oid_info->p_bytes_used = 0; + IPOIB_EXIT( IPOIB_DBG_STAT ); + return NDIS_STATUS_INVALID_LENGTH; + } + + IPOIB_EXIT( IPOIB_DBG_STAT ); + return NDIS_STATUS_SUCCESS; +} + + +void +ipoib_inc_recv_stat( + IN ipoib_adapter_t* const p_adapter, + IN const ip_stat_sel_t stat_sel, + IN const size_t bytes OPTIONAL, + IN const size_t packets OPTIONAL ) +{ + IPOIB_ENTER( IPOIB_DBG_STAT ); + + cl_spinlock_acquire( &p_adapter->recv_stat_lock ); + switch( stat_sel ) + { + case IP_STAT_ERROR: + p_adapter->recv_stats.comp.error++; + break; + + case IP_STAT_DROPPED: + p_adapter->recv_stats.comp.dropped++; + break; + + case IP_STAT_UCAST_BYTES: + case IP_STAT_UCAST_FRAMES: + p_adapter->recv_stats.comp.success++; + p_adapter->recv_stats.ucast.frames += packets; + p_adapter->recv_stats.ucast.bytes += bytes; + break; + + case IP_STAT_BCAST_BYTES: + case IP_STAT_BCAST_FRAMES: + p_adapter->recv_stats.comp.success++; + p_adapter->recv_stats.bcast.frames += packets; + p_adapter->recv_stats.bcast.bytes += bytes; + break; + + case IP_STAT_MCAST_BYTES: + case IP_STAT_MCAST_FRAMES: + p_adapter->recv_stats.comp.success++; + p_adapter->recv_stats.mcast.frames += packets; + p_adapter->recv_stats.mcast.bytes += bytes; + break; + + default: + break; + } + cl_spinlock_release( &p_adapter->recv_stat_lock ); + + IPOIB_EXIT( IPOIB_DBG_STAT ); +} + +NDIS_STATUS +ipoib_get_send_stat( + IN ipoib_adapter_t* const p_adapter, + IN const ip_stat_sel_t stat_sel, + IN pending_oid_t* const p_oid_info ) +{ + uint64_t stat; + + IPOIB_ENTER( IPOIB_DBG_STAT ); + + CL_ASSERT( p_adapter ); + + cl_spinlock_acquire( &p_adapter->send_stat_lock ); + switch( stat_sel ) + { + case IP_STAT_SUCCESS: + stat = p_adapter->send_stats.comp.success; + break; + + case IP_STAT_ERROR: + stat = p_adapter->send_stats.comp.error; + break; + + case IP_STAT_DROPPED: + stat = p_adapter->send_stats.comp.dropped; + break; + + case IP_STAT_UCAST_BYTES: + stat = p_adapter->send_stats.ucast.bytes; + break; + + case IP_STAT_UCAST_FRAMES: + stat = p_adapter->send_stats.ucast.frames; + break; + + case IP_STAT_BCAST_BYTES: + stat = p_adapter->send_stats.bcast.bytes; + break; + + case IP_STAT_BCAST_FRAMES: + stat = p_adapter->send_stats.bcast.frames; + break; + + case IP_STAT_MCAST_BYTES: + stat = p_adapter->send_stats.mcast.bytes; + break; + + case IP_STAT_MCAST_FRAMES: + stat = p_adapter->send_stats.mcast.frames; + break; + + default: + stat = 0; + } + cl_spinlock_release( &p_adapter->send_stat_lock ); + + *p_oid_info->p_bytes_needed = sizeof(uint64_t); + + if( p_oid_info->buf_len >= sizeof(uint64_t) ) + { + *((uint64_t*)p_oid_info->p_buf) = stat; + *p_oid_info->p_bytes_used = sizeof(uint64_t); + } + else if( p_oid_info->buf_len >= sizeof(uint32_t) ) + { + *((uint32_t*)p_oid_info->p_buf) = (uint32_t)stat; + *p_oid_info->p_bytes_used = sizeof(uint32_t); + } + else + { + *p_oid_info->p_bytes_used = 0; + IPOIB_EXIT( IPOIB_DBG_STAT ); + return NDIS_STATUS_INVALID_LENGTH; + } + + IPOIB_EXIT( IPOIB_DBG_STAT ); + return NDIS_STATUS_SUCCESS; +} + + +void +ipoib_inc_send_stat( + IN ipoib_adapter_t* const p_adapter, + IN const ip_stat_sel_t stat_sel, + IN const size_t bytes OPTIONAL ) +{ + IPOIB_ENTER( IPOIB_DBG_STAT ); + + cl_spinlock_acquire( &p_adapter->send_stat_lock ); + switch( stat_sel ) + { + case IP_STAT_ERROR: + p_adapter->send_stats.comp.error++; + break; + + case IP_STAT_DROPPED: + p_adapter->send_stats.comp.dropped++; + break; + + case IP_STAT_UCAST_BYTES: + case IP_STAT_UCAST_FRAMES: + p_adapter->send_stats.comp.success++; + p_adapter->send_stats.ucast.frames++; + p_adapter->send_stats.ucast.bytes += bytes; + break; + + case IP_STAT_BCAST_BYTES: + case IP_STAT_BCAST_FRAMES: + p_adapter->send_stats.comp.success++; + p_adapter->send_stats.bcast.frames++; + p_adapter->send_stats.bcast.bytes += bytes; + break; + + case IP_STAT_MCAST_BYTES: + case IP_STAT_MCAST_FRAMES: + p_adapter->send_stats.comp.success++; + p_adapter->send_stats.mcast.frames++; + p_adapter->send_stats.mcast.bytes += bytes; + break; + + default: + break; + } + cl_spinlock_release( &p_adapter->send_stat_lock ); + + IPOIB_EXIT( IPOIB_DBG_STAT ); +} diff --git a/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_adapter.h b/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_adapter.h new file mode 100644 index 00000000..2092ba8c --- /dev/null +++ b/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_adapter.h @@ -0,0 +1,510 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2006 Mellanox Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: ipoib_adapter.h 4494 2009-06-22 14:31:08Z xalex $ + */ + + +#ifndef _IPOIB_ADAPTER_H_ +#define _IPOIB_ADAPTER_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ip_stats.h" +#include "ipoib_stat.h" +#include "shutter.h" + + + +/* + * Definitions + */ +#define MAX_MCAST 32 + +#define IPV4_ADDR_SIZE 4 + +#define PORT_NUM_INDEX_IN_GUID 3 /* 0 based index into big endian GUID to get port number */ + +/* + * Macros + */ +typedef enum +{ + CSUM_DISABLED = 0, + CSUM_ENABLED, + CSUM_BYPASS +} csum_flag_t; + +typedef enum _ipoib_state +{ + IPOIB_INIT = -1, + IPOIB_PAUSED, + IPOIB_PAUSING, + IPOIB_RUNNING +} ipoib_state_t; + +typedef struct _ipoib_offloads_cap_ { + boolean_t lso; + boolean_t send_chksum_offload; + boolean_t recv_chksum_offload; +} +ipoib_offloads_cap_t; + + +typedef struct _ipoib_params +{ + int32_t rq_depth; + int32_t rq_low_watermark; + int32_t sq_depth; + csum_flag_t send_chksum_offload; + csum_flag_t recv_chksum_offload; + uint32_t sa_timeout; + uint32_t sa_retry_cnt; + uint32_t recv_pool_ratio; + uint32_t payload_mtu; + boolean_t lso; + uint32_t xfer_block_size; + mac_addr_t conf_mac; + uint32_t mc_leave_rescan; + uint32_t guid_mask; + uint32_t bc_join_retry; + boolean_t cm_enabled; + uint32_t cm_payload_mtu; + uint32_t cm_xfer_block_size; +} ipoib_params_t; +/* +* FIELDS +* rq_depth +* Number of receive WQEs to allocate. +* +* rq_low_watermark +* Receives are indicated with NDIS_STATUS_RESOURCES when the number of +* receives posted to the RQ falls bellow this value. +* +* sq_depth +* Number of send WQEs to allocate. +* +* send_chksum_offload +* recv_chksum_offload +* Flags to indicate whether to offload send/recv checksums. +* 0 - No hardware checksum +* 1 - Try to offload if the device support it +* 2 - Always report success (checksum bypass) +* +* wsdp_enabled +* Flag to indicate whether WSDP is enabled for an adapter adapter. +* +* static_lid +* LID to assign to the port if that port is down (not init) and has none. +* This feature allows a LID to be assigned, alowing locally targetted +* traffic to occur even on ports that are not plugged in. +* +* sa_timeout +* Time, in milliseconds, to wait for a response before retransmitting an +* SA query request. +* +* sa_retry_cnt +* Number of times to retry an SA query request. +* +* recv_pool_ratio +* Initial ratio of receive pool size to receive queue depth. +* +* grow_thresh +* Threshold at which to grow the receive pool. Valid values start are +* powers of 2, excluding 1. When zero, grows only when the pool is +* exhausted. Other values indicate fractional values +* (i.e. 2 indicates 1/2, 4 indicates 1/4, etc.) +* +* payload_mtu +* The maximum available size of IPoIB transfer unit. +* +* If using UD mode: +* It should be decremented by size of IPoIB header (==4B) +* For example, if the HCA support 4K MTU, +* upper threshold for payload mtu is 4092B and not 4096B +* +* If using CM mode: +* MTU will be not limited by 4K threshold. +* UD QP still may be used for different protocols (like ARP). +* For these situations the threshold for the UD QP will take the default +* value +* +* lso +* (TRUE) Indicates support for hardware large/giant send offload +* +*********/ + + +typedef struct _pending_oid +{ + NDIS_OID oid; + PVOID p_buf; + ULONG buf_len; + PULONG p_bytes_used; + PULONG p_bytes_needed; + PNDIS_OID_REQUEST p_pending_oid; +} pending_oid_t; + + +typedef struct _ipoib_adapter +{ + cl_obj_t obj; + NDIS_HANDLE h_adapter; + PDEVICE_OBJECT pdo; + ipoib_ifc_data_t guids; + + cl_list_item_t entry; + + ib_al_handle_t h_al; + ib_pnp_handle_t h_pnp; + + ib_pnp_event_t state; + boolean_t hung; + boolean_t reset; + boolean_t registering; + + boolean_t pending_query; + pending_oid_t query_oid; + boolean_t pending_set; + pending_oid_t set_oid; + + struct _ipoib_port *p_port; + + uint32_t port_rate; + + ipoib_params_t params; + ipoib_offloads_cap_t offload_cap; + cl_spinlock_t recv_stat_lock; + ip_stats_t recv_stats; + cl_spinlock_t send_stat_lock; + ip_stats_t send_stats; + + boolean_t is_primary; + struct _ipoib_adapter *p_primary; + + uint32_t packet_filter; + + mac_addr_t mac; + mac_addr_t mcast_array[MAX_MCAST]; + uint8_t mcast_array_size; + + cl_qpool_t item_pool; + + KMUTEX mutex; + + cl_thread_t destroy_thread; + cl_vector_t ip_vector; + + cl_perf_t perf; + NDIS_HANDLE NdisMiniportDmaHandle; + ipoib_state_t ipoib_state; + ib_al_ifc_t *p_ifc; + + ULONG sg_list_size; + + // statistics + PIPOIB_ST_DEVICE p_stat; + ULONG n_send_NBL; // number of send NBLs, gotten from NDIS + ULONG n_send_NBL_done; // number of send NBLs, completed + + // + shutter_t recv_shutter; + +} ipoib_adapter_t; +/* +* FIELDS +* obj +* Complib object for reference counting and destruction synchronization. +* +* h_adapter +* NDIS adapter handle. +* +* guids +* CA and port GUIDs returned by the bus driver. +* +* entry +* List item for storing all adapters in a list for address translation. +* We add adapters when their packet filter is set to a non-zero value, +* and remove them when their packet filter is cleared. This is needed +* since user-mode removal events are generated after the packet filter +* is cleared, but before the adapter is destroyed. +* +* h_al +* AL handle for all IB resources. +* +* h_pnp +* PNP registration handle for port events. +* +* state +* State of the adapter. IB_PNP_PORT_ADD indicates that the adapter +* is ready to transfer data. +* +* hung +* Boolean flag used to return whether we are hung or not. +* +* p_port +* Pointer to an ipoib_port_t representing all resources for moving data +* on the IB fabric. +* +* rate +* Rate, in 100bps increments, of the link. +* +* params +* Configuration parameters. +* +* pending_query +* Indicates that an query OID request is being processed asynchronously. +* +* query_oid +* Information about the pended query OID request. +* Valid only if pending_query is TRUE. +* +* pending_set +* Indicates that an set OID request is being processed asynchronously. +* +* set_oid +* Information about the pended set OID request. +* Valid only if pending_set is TRUE. +* +* recv_lock +* Spinlock protecting receive processing. +* +* recv_stats +* Receive statistics. +* +* send_lock +* Spinlock protecting send processing. +* +* send_stats +* Send statistics. +* +* is_primary +* Boolean flag to indicate if an adapter is the primary adapter +* of a bundle. +* +* p_primary +* Pointer to the primary adapter for a bundle. +* +* packet_filter +* Packet filter set by NDIS. +* +* mac_addr +* Ethernet MAC address reported to NDIS. +* +* mcast_array +* List of multicast MAC addresses programmed by NDIS. +* +* mcast_array_size +* Number of entries in the multicat MAC address array; +* +* item_pool +* Pool of cl_pool_obj_t structures to use for queueing pending +* packets for transmission. +* +* mutex +* Mutex to synchronized PnP callbacks with destruction. +* +* ip_vector +* Vector of assigned IP addresses. +* +* p_ifc +* Pointer to transport interface. +* +*********/ + + +typedef struct _ats_reg +{ + ipoib_adapter_t *p_adapter; + ib_reg_svc_handle_t h_reg_svc; + +} ats_reg_t; +/* +* FIELDS +* p_adapter +* Pointer to the adapter to which this address is assigned. +* +* h_reg_svc +* Service registration handle. +*********/ + + +typedef struct _net_address_item +{ + ats_reg_t *p_reg; + union _net_address_item_address + { + ULONG as_ulong; + UCHAR as_bytes[IPV4_ADDR_SIZE]; + } address; + +} net_address_item_t; +/* +* FIELDS +* p_reg +* Pointer to the ATS registration assigned to this address. +* +* address +* Union representing the IP address as an unsigned long or as +* an array of bytes. +* +* as_ulong +* The IP address represented as an unsigned long. Windows stores +* IPs this way. +* +* as_bytes +* The IP address represented as an array of bytes. +*********/ + +static inline void ipoib_cnt_inc( PULONG p_cnt) +{ + ++*p_cnt; +} + +ib_api_status_t +ipoib_create_adapter( + IN void* const h_adapter, + OUT ipoib_adapter_t** const pp_adapter ); + + +ib_api_status_t +ipoib_start_adapter( + IN ipoib_adapter_t* const p_adapter ); + + +void +ipoib_destroy_adapter( + IN ipoib_adapter_t* const p_adapter ); + + +/* Joins/leaves mcast groups based on currently programmed mcast MACs. */ +void +ipoib_refresh_mcast( + IN ipoib_adapter_t* const p_adapter, + IN mac_addr_t* const p_mac_array, + IN const uint8_t num_macs ); +/* +* PARAMETERS +* p_adapter +* Instance whose multicast MAC address list to modify. +* +* p_mac_array +* Array of multicast MAC addresses assigned to the adapter. +* +* num_macs +* Number of MAC addresses in the array. +*********/ +NDIS_STATUS +ipoib_get_gen_stat( + IN ipoib_adapter_t* const p_adapter, + OUT pending_oid_t* const p_oid_info ); + +NDIS_STATUS +ipoib_get_recv_stat( + IN ipoib_adapter_t* const p_adapter, + IN const ip_stat_sel_t stat_sel, + IN pending_oid_t* const p_oid_info ); + + +void +ipoib_inc_recv_stat( + IN ipoib_adapter_t* const p_adapter, + IN const ip_stat_sel_t stat_sel, + IN const size_t bytes OPTIONAL, + IN const size_t packets OPTIONAL ); + + +NDIS_STATUS +ipoib_get_send_stat( + IN ipoib_adapter_t* const p_adapter, + IN const ip_stat_sel_t stat_sel, + IN pending_oid_t* const p_oid_info ); + + +void +ipoib_inc_send_stat( + IN ipoib_adapter_t* const p_adapter, + IN const ip_stat_sel_t stat_sel, + IN const size_t bytes OPTIONAL ); + + +void +ipoib_set_rate( + IN ipoib_adapter_t* const p_adapter, + IN const uint8_t link_width, + IN const uint8_t link_speed ); + + +ib_api_status_t +ipoib_set_active( + IN ipoib_adapter_t* const p_adapter ); + +void +ipoib_set_inactive( + IN ipoib_adapter_t* const p_adapter ); + +ib_api_status_t +ipoib_reset_adapter( + IN ipoib_adapter_t* const p_adapter ); + +void +ipoib_reg_addrs( + IN ipoib_adapter_t* const p_adapter ); + +void +ipoib_dereg_addrs( + IN ipoib_adapter_t* const p_adapter ); + +#define IPOIB_INIT_NDIS_STATUS_INDICATION(_pStatusIndication, _M, _St, _Buf, _BufSize) \ + { \ + NdisZeroMemory(_pStatusIndication, sizeof(NDIS_STATUS_INDICATION)); \ + (_pStatusIndication)->Header.Type = NDIS_OBJECT_TYPE_STATUS_INDICATION; \ + (_pStatusIndication)->Header.Revision = NDIS_STATUS_INDICATION_REVISION_1; \ + (_pStatusIndication)->Header.Size = sizeof(NDIS_STATUS_INDICATION); \ + (_pStatusIndication)->SourceHandle = _M; \ + (_pStatusIndication)->StatusCode = _St; \ + (_pStatusIndication)->StatusBuffer = _Buf; \ + (_pStatusIndication)->StatusBufferSize = _BufSize; \ + } + +#define IPOIB_MEDIA_MAX_SPEED 40000000000 + +#define SET_PORT_RATE_BPS(x) (uint64_t(100) * x) + + +#endif /* _IPOIB_ADAPTER_H_ */ diff --git a/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_debug.h b/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_debug.h new file mode 100644 index 00000000..adb5026c --- /dev/null +++ b/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_debug.h @@ -0,0 +1,303 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2006 Mellanox Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: ipoib_debug.h 3719 2009-01-07 12:31:52Z reuven $ + */ + + +#ifndef _IPOIB_DEBUG_H_ +#define _IPOIB_DEBUG_H_ + +#if defined __MODULE__ +#undef __MODULE__ +#endif + +#define __MODULE__ "[IPoIB]" + +#include + + +/* Object types for passing into complib. */ +#define IPOIB_OBJ_INSTANCE 1 +#define IPOIB_OBJ_PORT 2 +#define IPOIB_OBJ_ENDPOINT 3 + + +extern uint32_t g_ipoib_dbg_level; +extern uint32_t g_ipoib_dbg_flags; + + +#if defined(EVENT_TRACING) +// +// Software Tracing Definitions +// +#define WPP_CONTROL_GUIDS \ + WPP_DEFINE_CONTROL_GUID( \ + IPOIBCtlGuid,(3F9BC73D, EB03, 453a, B27B, 20F9A664211A), \ + WPP_DEFINE_BIT(IPOIB_DBG_ERROR) \ + WPP_DEFINE_BIT(IPOIB_DBG_INIT) \ + WPP_DEFINE_BIT(IPOIB_DBG_PNP) \ + WPP_DEFINE_BIT(IPOIB_DBG_SEND) \ + WPP_DEFINE_BIT(IPOIB_DBG_RECV) \ + WPP_DEFINE_BIT(IPOIB_DBG_ENDPT) \ + WPP_DEFINE_BIT(IPOIB_DBG_IB) \ + WPP_DEFINE_BIT(IPOIB_DBG_BUF) \ + WPP_DEFINE_BIT(IPOIB_DBG_MCAST) \ + WPP_DEFINE_BIT(IPOIB_DBG_ALLOC) \ + WPP_DEFINE_BIT(IPOIB_DBG_OID) \ + WPP_DEFINE_BIT(IPOIB_DBG_IOCTL) \ + WPP_DEFINE_BIT(IPOIB_DBG_STAT) \ + WPP_DEFINE_BIT(IPOIB_DBG_OBJ)) + + + +#define WPP_LEVEL_FLAGS_ENABLED(lvl, flags) \ + (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= lvl) +#define WPP_LEVEL_FLAGS_LOGGER(lvl,flags) WPP_LEVEL_LOGGER(flags) +#define WPP_FLAG_ENABLED(flags) \ + (WPP_LEVEL_ENABLED(flags) && \ + WPP_CONTROL(WPP_BIT_ ## flags).Level >= TRACE_LEVEL_VERBOSE) +#define WPP_FLAG_LOGGER(flags) WPP_LEVEL_LOGGER(flags) + +// begin_wpp config +// IPOIB_ENTER(FLAG); +// IPOIB_EXIT(FLAG); +// USEPREFIX(IPOIB_PRINT, "%!STDPREFIX! [IPoIB] :%!FUNC!() :"); +// USEPREFIX(IPOIB_PRINT_EXIT, "%!STDPREFIX! [IPoIB] :%!FUNC!() :"); +// USESUFFIX(IPOIB_PRINT_EXIT, "[IpoIB] :%!FUNC!():]"); +// USESUFFIX(IPOIB_ENTER, " [IPoIB] :%!FUNC!():["); +// USESUFFIX(IPOIB_EXIT, " [IPoIB] :%!FUNC!():]"); +// end_wpp + +#else + +#include + + +/* + * Debug macros + */ +#define IPOIB_DBG_ERR (1 << 0) +#define IPOIB_DBG_INIT (1 << 1) +#define IPOIB_DBG_PNP (1 << 2) +#define IPOIB_DBG_SEND (1 << 3) +#define IPOIB_DBG_RECV (1 << 4) +#define IPOIB_DBG_ENDPT (1 << 5) +#define IPOIB_DBG_IB (1 << 6) +#define IPOIB_DBG_BUF (1 << 7) +#define IPOIB_DBG_MCAST (1 << 8) +#define IPOIB_DBG_ALLOC (1 << 9) +#define IPOIB_DBG_OID (1 << 10) +#define IPOIB_DBG_IOCTL (1 << 11) +#define IPOIB_DBG_STAT (1 << 12) +#define IPOIB_DBG_OBJ (1 << 13) + +#define IPOIB_DBG_ERROR (CL_DBG_ERROR | IPOIB_DBG_ERR) +#define IPOIB_DBG_ALL CL_DBG_ALL + + +#if DBG + +// assignment of _level_ is need to to overcome warning C4127 +#define IPOIB_PRINT(_level_,_flag_,_msg_) \ + { \ + __pragma(warning(suppress:6326)) \ + if( g_ipoib_dbg_level >= (_level_) ) \ + CL_TRACE( _flag_, g_ipoib_dbg_flags, _msg_ ); \ + } + +#define IPOIB_PRINT_EXIT(_level_,_flag_,_msg_) \ + { \ + __pragma(warning(suppress:6326)) \ + if( g_ipoib_dbg_level >= (_level_) ) \ + CL_TRACE( _flag_, g_ipoib_dbg_flags, _msg_ );\ + IPOIB_EXIT(_flag_);\ + } + +#define IPOIB_ENTER(_flag_) \ + { \ + __pragma(warning(suppress:6326)) \ + if( g_ipoib_dbg_level >= TRACE_LEVEL_VERBOSE ) \ + CL_ENTER( _flag_, g_ipoib_dbg_flags ); \ + } + +#define IPOIB_EXIT(_flag_)\ + { \ + __pragma(warning(suppress:6326)) \ + if( g_ipoib_dbg_level >= TRACE_LEVEL_VERBOSE ) \ + CL_EXIT( _flag_, g_ipoib_dbg_flags ); \ + } + +#define IPOIB_TRACE_BYTES( lvl, ptr, len ) \ + { \ + __pragma(warning(suppress:6326)) \ + if( g_ipoib_dbg_level >= (_level_) && \ + (g_ipoib_dbg_flags & (_flag_)) ) \ + { \ + size_t _loop_; \ + for( _loop_ = 0; _loop_ < (len); ++_loop_ ) \ + { \ + cl_dbg_out( "0x%.2X ", ((uint8_t*)(ptr))[_loop_] ); \ + if( (_loop_ + 1)% 16 == 0 ) \ + cl_dbg_out("\n"); \ + else if( (_loop_ % 4 + 1) == 0 ) \ + cl_dbg_out(" "); \ + } \ + cl_dbg_out("\n"); \ + } \ + } + +#else + +#define IPOIB_PRINT(lvl, flags, msg) + +#define IPOIB_PRINT_EXIT(_level_,_flag_,_msg_) + +#define IPOIB_ENTER(_flag_) + +#define IPOIB_EXIT(_flag_) + +#define IPOIB_TRACE_BYTES( lvl, ptr, len ) + +#endif + +#endif //EVENT_TRACING + + +enum ipoib_perf_counters +{ + SendBundle, + SendPackets, + PortSend, + GetEthHdr, + SendMgrQueue, + GetEndpt, + EndptQueue, + QueuePacket, + BuildSendDesc, + SendMgrFilter, + FilterIp, + QueryIp, + SendTcp, + FilterUdp, + QueryUdp, + SendUdp, + FilterDhcp, + FilterArp, + SendGen, + SendCopy, + PostSend, + ProcessFailedSends, + SendCompBundle, + SendCb, + PollSend, + SendComp, + FreeSendBuf, + RearmSend, + PortResume, + RecvCompBundle, + RecvCb, + PollRecv, + FilterRecv, + GetRecvEndpts, + GetEndptByGid, + GetEndptByLid, + EndptInsert, + RecvTcp, + RecvUdp, + RecvDhcp, + RecvArp, + RecvGen, + BuildNBLArray, + PreparePkt, + GetNdisPkt, + RecvNdisIndicate, + PutRecvList, + RepostRecv, + GetRecv, + PostRecv, + RearmRecv, + ReturnPacket, + ReturnPutRecv, + ReturnRepostRecv, + ReturnPreparePkt, + ReturnNdisIndicate, + + /* Must be last! */ + MaxPerf + +}; + + +enum ref_cnt_buckets +{ + ref_init = 0, + ref_refresh_mcast, /* only used in refresh_mcast */ + ref_send_packets, /* only in send_packets */ + ref_get_recv, + ref_repost, /* only in __recv_mgr_repost */ + ref_recv_cb, /* only in __recv_cb */ + ref_send_cb, /* only in __send_cb */ + ref_port_up, + ref_get_bcast, + ref_bcast, /* join and create, used as base only */ + ref_join_mcast, + ref_leave_mcast, + ref_endpt_track, /* used when endpt is in port's child list. */ + + ref_array_size, /* Used to size the array of ref buckets. */ + ref_mask = 100, /* Used to differentiate derefs. */ + + ref_failed_recv_wc = 100 + ref_get_recv, + ref_recv_inv_len = 200 + ref_get_recv, + ref_recv_loopback = 300 + ref_get_recv, + ref_recv_filter = 400 + ref_get_recv, + + ref_bcast_get_cb = 100 + ref_get_bcast, + + ref_join_bcast = 100 + ref_bcast, + ref_create_bcast = 200 + ref_bcast, + ref_bcast_inv_state = 300 + ref_bcast, + ref_bcast_req_failed = 400 + ref_bcast, + ref_bcast_error = 500 + ref_bcast, + ref_bcast_join_failed = 600 + ref_bcast, + ref_bcast_create_failed = 700 + ref_bcast, + + ref_mcast_inv_state = 100 + ref_join_mcast, + ref_mcast_req_failed = 200 + ref_join_mcast, + ref_mcast_no_endpt = 300 + ref_join_mcast, + ref_mcast_av_failed = 400 + ref_join_mcast, + ref_mcast_join_failed = 500 + ref_join_mcast, + + ref_port_info_cb = 100 + ref_port_up + +}; + + +#endif /* _IPOIB_DEBUG_H_ */ diff --git a/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_driver.cpp b/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_driver.cpp new file mode 100644 index 00000000..1d4fc184 --- /dev/null +++ b/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_driver.cpp @@ -0,0 +1,4104 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2006 Mellanox Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: ipoib_driver.c 4506 2009-06-23 14:40:54Z xalex $ + */ + +#include "Precompile.h" + + + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "ipoib_driver.tmh" +#endif + +#include "ipoib_port.h" +#include "ipoib_ibat.h" +#include +#include +#include +#include +#include "ntstrsafe.h" +#include "strsafe.h" +#include + + + +#define MAJOR_DRIVER_VERSION 2 +#define MINOR_DRIVER_VERSION 1 + +#define MAJOR_NDIS_VERSION 6 +#define MINOR_NDIS_VERSION 1 + + +PDRIVER_OBJECT g_p_drv_obj; + + + + +static const NDIS_OID SUPPORTED_OIDS[] = +{ + OID_GEN_SUPPORTED_LIST, + OID_GEN_HARDWARE_STATUS, + OID_GEN_MEDIA_SUPPORTED, + OID_GEN_MEDIA_IN_USE, + OID_GEN_MAXIMUM_LOOKAHEAD, + OID_GEN_MAXIMUM_FRAME_SIZE, + OID_GEN_TRANSMIT_BUFFER_SPACE, + OID_GEN_RECEIVE_BUFFER_SPACE, + OID_GEN_TRANSMIT_BLOCK_SIZE, + OID_GEN_RECEIVE_BLOCK_SIZE, + OID_GEN_VENDOR_ID, + OID_GEN_VENDOR_DESCRIPTION, + OID_GEN_VENDOR_DRIVER_VERSION, + OID_GEN_CURRENT_PACKET_FILTER, + OID_GEN_CURRENT_LOOKAHEAD, + OID_GEN_DRIVER_VERSION, + OID_GEN_MAXIMUM_TOTAL_SIZE, + OID_GEN_MAC_OPTIONS, + OID_GEN_MAXIMUM_SEND_PACKETS, + OID_GEN_XMIT_OK, + OID_GEN_RCV_OK, + OID_GEN_XMIT_ERROR, + OID_GEN_RCV_ERROR, + OID_GEN_RCV_NO_BUFFER, + //OID_GEN_RCV_CRC_ERROR, + //OID_GEN_TRANSMIT_QUEUE_LENGTH, + OID_802_3_PERMANENT_ADDRESS, + OID_802_3_CURRENT_ADDRESS, + OID_802_3_MULTICAST_LIST, + OID_802_3_MAXIMUM_LIST_SIZE, + OID_802_3_RCV_ERROR_ALIGNMENT, + OID_802_3_XMIT_ONE_COLLISION, + OID_802_3_XMIT_MORE_COLLISIONS, + //OID_802_3_XMIT_DEFERRED, + //OID_802_3_XMIT_MAX_COLLISIONS, + //OID_802_3_RCV_OVERRUN, + //OID_802_3_XMIT_UNDERRUN, + //OID_802_3_XMIT_HEARTBEAT_FAILURE, + //OID_802_3_XMIT_TIMES_CRS_LOST, + //OID_802_3_XMIT_LATE_COLLISIONS, + +#if !BUILD_W2K + OID_GEN_PHYSICAL_MEDIUM, +#endif + + OID_TCP_TASK_OFFLOAD, + +/* powermanagement */ + + OID_PNP_CAPABILITIES, + OID_PNP_SET_POWER, + OID_PNP_QUERY_POWER, + OID_PNP_ADD_WAKE_UP_PATTERN, + OID_PNP_REMOVE_WAKE_UP_PATTERN, + OID_PNP_ENABLE_WAKE_UP, + +#if 0 +/* custom oid WMI support */ + OID_CUSTOM_PERF_COUNTERS, + OID_CUSTOM_STRING, +#endif + + OID_GEN_RECEIVE_SCALE_CAPABILITIES, + OID_GEN_RECEIVE_SCALE_PARAMETERS, + + +// +// new and required for NDIS 6 miniports +// + OID_GEN_LINK_PARAMETERS, + OID_GEN_INTERRUPT_MODERATION, + OID_GEN_STATISTICS, + +/* Offload */ + OID_TCP_OFFLOAD_CURRENT_CONFIG, + OID_TCP_OFFLOAD_PARAMETERS, + OID_TCP_OFFLOAD_HARDWARE_CAPABILITIES, + OID_OFFLOAD_ENCAPSULATION, + +#if 0 + +/* Header - Data seperation */ + OID_GEN_HD_SPLIT_PARAMETERS, + OID_GEN_HD_SPLIT_CURRENT_CONFIG, + +/* VLAN */ + OID_ADD_VALN_ID, + OID_DELETE_VLAN_ID, + + +/* Set MAC */ + OID_SET_MAC_ADDRESS +#endif + +}; + +static const unsigned char VENDOR_ID[] = {0x00, 0x06, 0x6A, 0x00}; + +#define VENDOR_DESCRIPTION "Internet Protocol over InfiniBand" + +#define IB_INFINITE_SERVICE_LEASE 0xFFFFFFFF + +//The mask is 8 bit and can't contain more than 6 non-zero bits +#define MAX_GUID_MAX 0xFC + + +/* Global driver debug level */ +uint32_t g_ipoib_dbg_level = TRACE_LEVEL_ERROR; +uint32_t g_ipoib_dbg_flags = 0x00000fff; +ipoib_globals_t g_ipoib = {0}; +NDIS_HANDLE g_IpoibMiniportDriverHandle = NULL; +NDIS_HANDLE g_IpoibDriverContext = NULL; +ULONG g_ipoib_send = 0; +ULONG g_ipoib_send_ack = 0; +ULONG g_ipoib_send_SW = 0; +ULONG g_ipoib_send_SG = 0; +ULONG g_ipoib_send_SW_in_loop = 0; +ULONG g_ipoib_send_SG_pending = 0; +ULONG g_ipoib_send_SG_real = 0; +ULONG g_ipoib_send_SG_failed = 0; +ULONG g_ipoib_send_reset = 0; + +ULONG g_NBL = 0; +ULONG g_NBL_complete = 0; + + +typedef struct _IPOIB_REG_ENTRY +{ + NDIS_STRING RegName; // variable name text + BOOLEAN bRequired; // 1 -> required, 0 -> optional + UINT FieldOffset; // offset in parent struct + UINT FieldSize; // size (in bytes) of the field + UINT Default; // default value to use + UINT Min; // minimum value allowed + UINT Max; // maximum value allowed +} IPOIB_REG_ENTRY, *PIPOIB_REG_ENTRY; + +IPOIB_REG_ENTRY HCARegTable[] = { + // reg value name If Required Offset in parentr struct Field size Default Min Max + {NDIS_STRING_CONST("GUIDMask"), 0, IPOIB_OFFSET(guid_mask), IPOIB_SIZE(guid_mask), 0, 0, MAX_GUID_MAX}, + /* GUIDMask should be the first element */ + {NDIS_STRING_CONST("RqDepth"), 1, IPOIB_OFFSET(rq_depth), IPOIB_SIZE(rq_depth), 512, 128, 1024}, + {NDIS_STRING_CONST("RqLowWatermark"), 0, IPOIB_OFFSET(rq_low_watermark), IPOIB_SIZE(rq_low_watermark), 4, 2, 8}, + {NDIS_STRING_CONST("SqDepth"), 1, IPOIB_OFFSET(sq_depth), IPOIB_SIZE(sq_depth), 512, 128, 1024}, + {NDIS_STRING_CONST("SendChksum"), 1, IPOIB_OFFSET(send_chksum_offload), IPOIB_SIZE(send_chksum_offload),CSUM_ENABLED,CSUM_DISABLED,CSUM_BYPASS}, + {NDIS_STRING_CONST("RecvChksum"), 1, IPOIB_OFFSET(recv_chksum_offload), IPOIB_SIZE(recv_chksum_offload),CSUM_ENABLED,CSUM_DISABLED,CSUM_BYPASS}, + {NDIS_STRING_CONST("SaTimeout"), 1, IPOIB_OFFSET(sa_timeout), IPOIB_SIZE(sa_timeout), 1000, 250, UINT_MAX}, + {NDIS_STRING_CONST("SaRetries"), 1, IPOIB_OFFSET(sa_retry_cnt), IPOIB_SIZE(sa_retry_cnt), 10, 1, UINT_MAX}, + {NDIS_STRING_CONST("RecvRatio"), 1, IPOIB_OFFSET(recv_pool_ratio), IPOIB_SIZE(recv_pool_ratio), 1, 1, 10}, + {NDIS_STRING_CONST("PayloadMtu"), 1, IPOIB_OFFSET(payload_mtu), IPOIB_SIZE(payload_mtu), 2044, 512, MAX_UD_PAYLOAD_MTU}, + {NDIS_STRING_CONST("lso"), 0, IPOIB_OFFSET(lso), IPOIB_SIZE(lso), 0, 0, 1}, + {NDIS_STRING_CONST("MCLeaveRescan"), 1, IPOIB_OFFSET(mc_leave_rescan), IPOIB_SIZE(mc_leave_rescan), 260, 1, 3600}, + {NDIS_STRING_CONST("BCJoinRetry"), 1, IPOIB_OFFSET(bc_join_retry), IPOIB_SIZE(bc_join_retry), 50, 0, 1000}, + {NDIS_STRING_CONST("CmEnabled"), 0, IPOIB_OFFSET(cm_enabled), IPOIB_SIZE(cm_enabled), FALSE, FALSE, TRUE}, + {NDIS_STRING_CONST("CmPayloadMtu"), 1, IPOIB_OFFSET(cm_payload_mtu), IPOIB_SIZE(cm_payload_mtu), MAX_CM_PAYLOAD_MTU, 512, MAX_CM_PAYLOAD_MTU} +}; + +#define IPOIB_NUM_REG_PARAMS (sizeof (HCARegTable) / sizeof(IPOIB_REG_ENTRY)) + + +void +ipoib_create_log( + NDIS_HANDLE h_adapter, + UINT ind, + ULONG eventLogMsgId) + +{ +#define cMaxStrLen 40 +#define cArrLen 3 + + PWCHAR logMsgArray[cArrLen]; + WCHAR strVal[cMaxStrLen]; + NDIS_STRING AdapterInstanceName; + + IPOIB_INIT_NDIS_STRING(&AdapterInstanceName); + if (NdisMQueryAdapterInstanceName(&AdapterInstanceName, h_adapter)!= NDIS_STATUS_SUCCESS ){ + ASSERT(FALSE); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR,IPOIB_DBG_ERROR, ("[IPoIB] Init:Failed to retreive adapter name.\n")); + return; + } + logMsgArray[0] = AdapterInstanceName.Buffer; + + if (RtlStringCbPrintfW(strVal, sizeof(strVal), L"0x%x", HCARegTable[ind].Default) != STATUS_SUCCESS) { + ASSERT(FALSE); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR,IPOIB_DBG_ERROR, + ("[IPoIB] Init: Problem copying string value: exiting\n")); + return; + } + + logMsgArray[0] = AdapterInstanceName.Buffer; + logMsgArray[1] = HCARegTable[ind].RegName.Buffer; + logMsgArray[2] = strVal; + + NdisWriteEventLogEntry(g_p_drv_obj, eventLogMsgId, 0, cArrLen, &logMsgArray, 0, NULL); + +} + + +extern "C" +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT p_drv_obj, + IN PUNICODE_STRING p_reg_path ); + +VOID +ipoib_unload( + IN PDRIVER_OBJECT p_drv_obj ); + +NDIS_STATUS +ipoib_initialize_ex( + IN NDIS_HANDLE h_adapter, + IN NDIS_HANDLE config_context, + IN PNDIS_MINIPORT_INIT_PARAMETERS MiniportInitParameters); + +BOOLEAN +ipoib_check_for_hang( + IN NDIS_HANDLE adapter_context ); + +void +ipoib_halt_ex( + IN NDIS_HANDLE adapter_context, + IN NDIS_HALT_ACTION HaltAction); + +NDIS_STATUS +ipoib_query_info( + IN NDIS_HANDLE adapter_context, + IN OUT PNDIS_OID_REQUEST pNdisRequest); + + + +NDIS_STATUS +ipoib_reset( + IN NDIS_HANDLE adapter_context, + OUT PBOOLEAN p_addr_reset); + +NDIS_STATUS +ipoib_set_info( + IN NDIS_HANDLE adapter_context, + IN OUT PNDIS_OID_REQUEST pNdisRequest); + + +//NDIS60 +void +ipoib_send_net_buffer_list( + IN NDIS_HANDLE adapter_context, + IN PNET_BUFFER_LIST net_buffer_list, + IN NDIS_PORT_NUMBER port_num, + IN ULONG send_flags); + +void +ipoib_pnp_notify( + IN NDIS_HANDLE adapter_context, + IN PNET_DEVICE_PNP_EVENT pnp_event); + +VOID +ipoib_shutdown_ex( + IN NDIS_HANDLE adapter_context, + IN NDIS_SHUTDOWN_ACTION shutdown_action); + + +void +ipoib_cancel_xmit( + IN NDIS_HANDLE adapter_context, + IN PVOID cancel_id ); + + +static NDIS_STATUS +ipoib_complete_query( + IN ipoib_adapter_t* const p_adapter, + IN pending_oid_t* const p_oid_info, + IN const NDIS_STATUS status, + IN const void* const p_buf, + IN const ULONG buf_len ); + +static NDIS_STATUS +__ipoib_set_net_addr( + IN ipoib_adapter_t * p_adapter, + IN PVOID info_buf, + IN ULONG info_buf_len, + OUT PULONG p_bytes_read, + OUT PULONG p_bytes_needed ); + +static NDIS_STATUS +__ipoib_get_tcp_task_offload( + IN ipoib_adapter_t* p_adapter, + OUT pending_oid_t *pNdisRequest); + +static void +__ipoib_ats_reg_cb( + IN ib_reg_svc_rec_t *p_reg_svc_rec ); + +static void +__ipoib_ats_dereg_cb( + IN void *context ); + +static NTSTATUS +__ipoib_read_registry( + IN UNICODE_STRING* const p_registry_path ); + +static NDIS_STATUS +ipoib_set_options( + IN NDIS_HANDLE NdisMiniportDriverHandle, + IN NDIS_HANDLE MiniportDriverContext); + +static NDIS_STATUS +ipoib_oid_handler( + IN NDIS_HANDLE adapter_context, + IN PNDIS_OID_REQUEST pNdisRequest); + +static void +ipoib_cancel_oid_request( + IN NDIS_HANDLE adapter_context, + IN PVOID requestId); + +static NDIS_STATUS +ipoib_pause( + IN NDIS_HANDLE adapter_context, + IN PNDIS_MINIPORT_PAUSE_PARAMETERS pause_parameters); + +static NDIS_STATUS +ipoib_restart( + IN NDIS_HANDLE adapter_context, + IN PNDIS_MINIPORT_RESTART_PARAMETERS restart_parameters); + + + +//! Standard Windows Device Driver Entry Point +/*! DriverEntry is the first routine called after a driver is loaded, and +is responsible for initializing the driver. On W2k this occurs when the PnP +Manager matched a PnP ID to one in an INF file that references this driver. +Any not success return value will cause the driver to fail to load. +IRQL = PASSIVE_LEVEL + +@param p_drv_obj Pointer to Driver Object for this device driver +@param p_registry_path Pointer to unicode string containing path to this driver's registry area +@return STATUS_SUCCESS, NDIS_STATUS_BAD_CHARACTERISTICS, NDIS_STATUS_BAD_VERSION, +NDIS_STATUS_RESOURCES, or NDIS_STATUS_FAILURE +*/ +extern "C" +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT p_drv_obj, + IN PUNICODE_STRING p_registry_path ) +{ + NDIS_STATUS status; + NDIS_MINIPORT_DRIVER_CHARACTERISTICS characteristics; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + g_p_drv_obj = p_drv_obj; + +#ifdef _DEBUG_ + PAGED_CODE(); +#endif +#if defined(EVENT_TRACING) + WPP_INIT_TRACING(p_drv_obj, p_registry_path); +#endif + status = CL_INIT; + if( !NT_SUCCESS( status ) ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("cl_init failed.\n") ); + return status; + } + + __ipoib_read_registry(p_registry_path); + + KeInitializeSpinLock( &g_ipoib.lock ); + cl_qlist_init( &g_ipoib.adapter_list ); + ipoib_st_init(); + g_stat.drv.obj = p_drv_obj; + + NdisZeroMemory(&characteristics, sizeof(characteristics)); + + characteristics.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_DRIVER_CHARACTERISTICS; + characteristics.Header.Size = NDIS_SIZEOF_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_2; + characteristics.Header.Revision = NDIS_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_2; + + characteristics.MajorNdisVersion = MAJOR_NDIS_VERSION; + characteristics.MinorNdisVersion = MINOR_NDIS_VERSION; + characteristics.MajorDriverVersion = MAJOR_DRIVER_VERSION; + characteristics.MinorDriverVersion = MINOR_DRIVER_VERSION; + + characteristics.CheckForHangHandlerEx = ipoib_check_for_hang; + characteristics.HaltHandlerEx = ipoib_halt_ex; + characteristics.InitializeHandlerEx = ipoib_initialize_ex; + characteristics.OidRequestHandler = ipoib_oid_handler; + characteristics.CancelOidRequestHandler = ipoib_cancel_oid_request; + characteristics.ResetHandlerEx = ipoib_reset; + characteristics.DevicePnPEventNotifyHandler = ipoib_pnp_notify; + characteristics.ReturnNetBufferListsHandler = ipoib_return_net_buffer_list; + characteristics.SendNetBufferListsHandler = ipoib_send_net_buffer_list; + + characteristics.SetOptionsHandler = ipoib_set_options; + characteristics.PauseHandler = ipoib_pause; + characteristics.RestartHandler = ipoib_restart; + characteristics.UnloadHandler = ipoib_unload; + characteristics.CancelSendHandler = ipoib_cancel_xmit; + characteristics.ShutdownHandlerEx = ipoib_shutdown_ex; + + status = NdisMRegisterMiniportDriver( + p_drv_obj, p_registry_path,(PNDIS_HANDLE)&g_IpoibDriverContext, &characteristics,&g_IpoibMiniportDriverHandle ); + if( status != NDIS_STATUS_SUCCESS ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("NdisMRegisterMiniportDriver failed with status of %d\n", status) ); + CL_DEINIT; + } + + IPOIB_EXIT( IPOIB_DBG_INIT ); + return status; +} + +static NDIS_STATUS +ipoib_set_options( + IN NDIS_HANDLE NdisMiniportDriverHandle, + IN NDIS_HANDLE MiniportDriverContext + ) +{ + IPOIB_ENTER( IPOIB_DBG_INIT ); + + UNREFERENCED_PARAMETER(NdisMiniportDriverHandle); + UNREFERENCED_PARAMETER(MiniportDriverContext); + + IPOIB_EXIT( IPOIB_DBG_INIT ); + return NDIS_STATUS_SUCCESS; +} + +static NTSTATUS +__ipoib_read_registry( + IN UNICODE_STRING* const p_registry_path ) +{ + NTSTATUS status; + /* Remember the terminating entry in the table below. */ + RTL_QUERY_REGISTRY_TABLE table[4]; + UNICODE_STRING param_path; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + RtlInitUnicodeString( ¶m_path, NULL ); + param_path.MaximumLength = p_registry_path->Length + + sizeof(L"\\Parameters"); + param_path.Buffer = (PWCH) cl_zalloc( param_path.MaximumLength ); + if( !param_path.Buffer ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to allocate parameters path buffer.\n") ); + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlAppendUnicodeStringToString( ¶m_path, p_registry_path ); + RtlAppendUnicodeToString( ¶m_path, L"\\Parameters" ); + + /* + * Clear the table. This clears all the query callback pointers, + * and sets up the terminating table entry. + */ + cl_memclr( table, sizeof(table) ); + + /* Setup the table entries. */ + table[0].Flags = RTL_QUERY_REGISTRY_DIRECT; + table[0].Name = L"DebugLevel"; + table[0].EntryContext = &g_ipoib_dbg_level; + table[0].DefaultType = REG_DWORD; + table[0].DefaultData = &g_ipoib_dbg_level; + table[0].DefaultLength = sizeof(ULONG); + + table[1].Flags = RTL_QUERY_REGISTRY_DIRECT; + table[1].Name = L"DebugFlags"; + table[1].EntryContext = &g_ipoib_dbg_flags; + table[1].DefaultType = REG_DWORD; + table[1].DefaultData = &g_ipoib_dbg_flags; + table[1].DefaultLength = sizeof(ULONG); + + table[2].Flags = RTL_QUERY_REGISTRY_DIRECT; + table[2].Name = L"bypass_check_bcast_rate"; + table[2].EntryContext = &g_ipoib.bypass_check_bcast_rate; + table[2].DefaultType = REG_DWORD; + table[2].DefaultData = &g_ipoib.bypass_check_bcast_rate; + table[2].DefaultLength = sizeof(ULONG); + + /* Have at it! */ + status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE, + param_path.Buffer, table, NULL, NULL ); + + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("debug level %d debug flags 0x%.8x\n", + g_ipoib_dbg_level, + g_ipoib_dbg_flags)); + +#if DBG + if( g_ipoib_dbg_flags & IPOIB_DBG_ERR ) + g_ipoib_dbg_flags |= CL_DBG_ERROR; +#endif + + cl_free( param_path.Buffer ); + IPOIB_EXIT( IPOIB_DBG_INIT ); + return status; +} + + +VOID +ipoib_unload( + IN PDRIVER_OBJECT p_drv_obj ) +{ + IPOIB_ENTER( IPOIB_DBG_INIT ); + UNREFERENCED_PARAMETER(p_drv_obj); + #if defined(EVENT_TRACING) + WPP_CLEANUP(p_drv_obj); + #endif + //NDIS6.0 + NdisMDeregisterMiniportDriver(g_IpoibMiniportDriverHandle); + UNREFERENCED_PARAMETER( p_drv_obj ); + CL_DEINIT; + IPOIB_EXIT( IPOIB_DBG_INIT ); +} + + + +NDIS_STATUS +ipoib_get_adapter_params( + IN OUT ipoib_adapter_t *p_adapter, + OUT PUCHAR *p_mac, + OUT UINT *p_len) +{ + NDIS_STATUS status; + NDIS_HANDLE h_config; + NDIS_CONFIGURATION_OBJECT config_obj; + NDIS_CONFIGURATION_PARAMETER *p_param; + UINT value; + PIPOIB_REG_ENTRY pRegEntry; + UINT i; + PUCHAR structPointer; + + int sq_depth_step = 128; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + config_obj.Header.Type = NDIS_OBJECT_TYPE_CONFIGURATION_OBJECT; + config_obj.Header.Revision = NDIS_CONFIGURATION_OBJECT_REVISION_1; + config_obj.Header.Size = sizeof(NDIS_CONFIGURATION_OBJECT); + config_obj.NdisHandle = p_adapter->h_adapter; + config_obj.Flags = 0; + + status = NdisOpenConfigurationEx( &config_obj, &h_config); + if( status != NDIS_STATUS_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("NdisOpenConfigurationEx returned 0x%.8x\n", status) ); + return status; + } + + // read all the registry values + for (i = 0, pRegEntry = HCARegTable; i < IPOIB_NUM_REG_PARAMS; ++i) + { + // initialize pointer to appropriate place inside 'params' + structPointer = (PUCHAR) &p_adapter->params + pRegEntry[i].FieldOffset; + + // Get the configuration value for a specific parameter. Under NT the + // parameters are all read in as DWORDs. + NdisReadConfiguration( + &status, + &p_param, + h_config, + &pRegEntry[i].RegName, + NdisParameterInteger); + + // If the parameter was present, then check its value for validity. + if (status == NDIS_STATUS_SUCCESS) + { + // Check that param value is not too small or too large + if (p_param->ParameterData.IntegerData < pRegEntry[i].Min || + p_param->ParameterData.IntegerData > pRegEntry[i].Max) + { + value = pRegEntry[i].Default; + ipoib_create_log(p_adapter->h_adapter, i, + EVENT_IPOIB_WRONG_PARAMETER_WRN); + IPOIB_PRINT(TRACE_LEVEL_VERBOSE, IPOIB_DBG_INIT, + ("Read configuration.Registry %S value is out of range, " + "setting default value= 0x%x\n", + pRegEntry[i].RegName.Buffer, value)); + } + else + { + value = p_param->ParameterData.IntegerData; + IPOIB_PRINT(TRACE_LEVEL_VERBOSE, IPOIB_DBG_INIT, + ("Read configuration. Registry %S, Value= 0x%x\n", + pRegEntry[i].RegName.Buffer, value)); + } + } + else + { + value = pRegEntry[i].Default; + status = NDIS_STATUS_SUCCESS; + if (pRegEntry[i].bRequired) + { + ipoib_create_log(p_adapter->h_adapter, i, + EVENT_IPOIB_WRONG_PARAMETER_ERR); + IPOIB_PRINT(TRACE_LEVEL_ERROR, IPOIB_DBG_INIT, + ("Read configuration.Registry %S value not found, setting " + "default value= 0x%x\n", + pRegEntry[i].RegName.Buffer, value)); + } + else + { + ipoib_create_log(p_adapter->h_adapter, i, EVENT_IPOIB_WRONG_PARAMETER_INFO); + IPOIB_PRINT(TRACE_LEVEL_VERBOSE, IPOIB_DBG_INIT, ("Read configuration. Registry %S value not found, Value= 0x%x\n", pRegEntry[i].RegName.Buffer, value)); + } + } + // + // Store the value in the adapter structure. + // + switch(pRegEntry[i].FieldSize) + { + case 1: + *((PUCHAR) structPointer) = (UCHAR) value; + break; + + case 2: + *((PUSHORT) structPointer) = (USHORT) value; + break; + + case 4: + *((PULONG) structPointer) = (ULONG) value; + break; + + default: + IPOIB_PRINT(TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Bogus field size %d\n", pRegEntry[i].FieldSize)); + break; + } + } + + // Send queue depth needs to be a power of two + //static const INT sq_depth_step = 128; + + if (p_adapter->params.sq_depth % sq_depth_step) { + static const c_sq_ind = 2; + p_adapter->params.sq_depth = sq_depth_step * + (p_adapter->params.sq_depth / sq_depth_step + + !!((p_adapter->params.sq_depth % sq_depth_step) > (sq_depth_step/2))); + ipoib_create_log(p_adapter->h_adapter, c_sq_ind, + EVENT_IPOIB_WRONG_PARAMETER_WRN); + IPOIB_PRINT(TRACE_LEVEL_VERBOSE, IPOIB_DBG_INIT, + ("SQ DEPTH value was rounded to the closest acceptable value " + "of 0x%x\n", p_adapter->params.sq_depth )); + } + + // Adjusting the low watermark parameter + p_adapter->params.rq_low_watermark = + p_adapter->params.rq_depth / p_adapter->params.rq_low_watermark; + + /* disable CM if LSO is active */ + if( p_adapter->params.cm_enabled ) + { + p_adapter->params.cm_enabled = !p_adapter->params.lso; + if( !p_adapter->params.cm_enabled ) + { + NdisWriteErrorLogEntry( p_adapter->h_adapter, + EVENT_IPOIB_CONNECTED_MODE_ERR, 1, 0xbadc0de0 ); + } + } + + if( p_adapter->params.cm_enabled ) + { + p_adapter->params.cm_xfer_block_size = + (sizeof(eth_hdr_t) + p_adapter->params.cm_payload_mtu); + } + + p_adapter->params.xfer_block_size = + (sizeof(eth_hdr_t) + p_adapter->params.payload_mtu); + + NdisReadNetworkAddress( &status, (PVOID *) p_mac, p_len, h_config ); + if (status != NDIS_STATUS_SUCCESS) { + // Don't rely on NDIS, zero the values + *p_mac = NULL; + *p_len = 0; + } + + NdisCloseConfiguration( h_config ); + + IPOIB_EXIT( IPOIB_DBG_INIT ); + return NDIS_STATUS_SUCCESS; +} + + +NDIS_STATUS +ipoib_get_adapter_guids( + IN NDIS_HANDLE* const h_adapter, + IN OUT ipoib_adapter_t *p_adapter ) +{ + NTSTATUS status; + ib_al_ifc_data_t data; + IO_STACK_LOCATION io_stack, *p_fwd_io_stack; + DEVICE_OBJECT *p_pdo; + IRP *p_irp; + KEVENT event; + IO_STATUS_BLOCK io_status; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + NdisMGetDeviceProperty( h_adapter, &p_pdo, NULL, NULL, NULL, NULL ); + + /* Query for our interface */ + data.size = sizeof(ipoib_ifc_data_t); + data.version = IPOIB_INTERFACE_DATA_VERSION; + data.type = &GUID_IPOIB_INTERFACE_DATA; + data.p_data = &p_adapter->guids; + + io_stack.MinorFunction = IRP_MN_QUERY_INTERFACE; + io_stack.Parameters.QueryInterface.Version = AL_INTERFACE_VERSION; + io_stack.Parameters.QueryInterface.Size = sizeof(ib_al_ifc_t); + io_stack.Parameters.QueryInterface.Interface = + (INTERFACE*)p_adapter->p_ifc; + io_stack.Parameters.QueryInterface.InterfaceSpecificData = &data; + io_stack.Parameters.QueryInterface.InterfaceType = + &GUID_IB_AL_INTERFACE; + + KeInitializeEvent( &event, NotificationEvent, FALSE ); + + /* Build the IRP for the HCA. */ + p_irp = IoBuildSynchronousFsdRequest( IRP_MJ_PNP, p_pdo, + NULL, 0, NULL, &event, &io_status ); + if( !p_irp ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to allocate query interface IRP.\n") ); + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* Copy the request query parameters. */ + p_fwd_io_stack = IoGetNextIrpStackLocation( p_irp ); + p_fwd_io_stack->MinorFunction = IRP_MN_QUERY_INTERFACE; + p_fwd_io_stack->Parameters.QueryInterface = + io_stack.Parameters.QueryInterface; + p_irp->IoStatus.Status = STATUS_NOT_SUPPORTED; + + /* Send the IRP. */ + status = IoCallDriver( p_pdo, p_irp ); + if( status == STATUS_PENDING ) + { + KeWaitForSingleObject( &event, Executive, KernelMode, + FALSE, NULL ); + status = io_status.Status; + } + + if( !NT_SUCCESS( status ) ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Query interface for IPOIB interface returned %08x.\n", status) ); + return status; + } + + /* + * Dereference the interface now so that the bus driver doesn't fail a + * query remove IRP. We will always get unloaded before the bus driver + * since we're a child device. + */ + if (p_adapter->p_ifc) + p_adapter->p_ifc->wdm.InterfaceDereference( + p_adapter->p_ifc->wdm.Context ); + IPOIB_EXIT( IPOIB_DBG_INIT ); + return NDIS_STATUS_SUCCESS; +} + + +//! Initialization function called for each IOC discovered +/* The MiniportInitialize function is a required function that sets up a +NIC (or virtual NIC) for network I/O operations, claims all hardware +resources necessary to the NIC in the registry, and allocates resources +the driver needs to carry out network I/O operations. +IRQL = PASSIVE_LEVEL + +@param p_open_status Pointer to a status field set if this function returns NDIS_STATUS_OPEN_ERROR +@param p_selected_medium_index Pointer to unsigned integer noting index into medium_array for this NIC +@param medium_array Array of mediums for this NIC +@param medium_array_size Number of elements in medium_array +@param h_adapter Handle assigned by NDIS for this NIC +@param wrapper_config_context Handle used for Ndis initialization functions +@return NDIS_STATUS_SUCCESS, NDIS_STATUS_UNSUPPORTED_MEDIA, NDIS_STATUS_RESOURCES, +NDIS_STATUS_NOT_SUPPORTED +*/ + +/*void foo1(int i) +{ + char temp[5200]; + if (i ==0) return; + cl_msg_out("i = %d\n", i); + foo1(i-1); + +}*/ + +NDIS_STATUS +SetDeviceRegistrationAttributes( + ipoib_adapter_t *p_adapter, + NDIS_HANDLE h_adapter + ) +{ + NDIS_MINIPORT_ADD_DEVICE_REGISTRATION_ATTRIBUTES atr; + NTSTATUS Status; + + NdisZeroMemory(&atr, sizeof(NDIS_MINIPORT_ADD_DEVICE_REGISTRATION_ATTRIBUTES)); + + // + // setting registration attributes + // + atr.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_ADD_DEVICE_REGISTRATION_ATTRIBUTES; + atr.Header.Revision = NDIS_MINIPORT_ADD_DEVICE_REGISTRATION_ATTRIBUTES_REVISION_1; + atr.Header.Size = NDIS_SIZEOF_MINIPORT_ADD_DEVICE_REGISTRATION_ATTRIBUTES_REVISION_1; + + + atr.MiniportAddDeviceContext = (NDIS_HANDLE)p_adapter; + atr.Flags = 0; + + Status = NdisMSetMiniportAttributes(h_adapter, + (PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)&atr); + + return Status; +} + +//NDIS 6.1 +#if 0 +NDIS_STATUS +SetHardwareAssistAttributes( + ipoib_adapter_t *p_adapter, + NDIS_HANDLE h_adapter + ) +{ + NDIS_MINIPORT_ADAPTER_HARDWARE_ASSIST_ATTRIBUTES atr; + NTSTATUS Status; + + NdisZeroMemory(&atr, sizeof(NDIS_MINIPORT_ADAPTER_HARDWARE_ASSIST_ATTRIBUTES)); + + // + // setting registration attributes + // + atr.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_HARDWARE_ASSIST_ATTRIBUTES; + atr.Header.Revision = NDIS_MINIPORT_ADAPTER_HARDWARE_ASSIST_ATTRIBUTES_REVISION_1; + atr.Header.Size = NDIS_SIZEOF_MINIPORT_ADAPTER_HARDWARE_ASSIST_ATTRIBUTES_REVISION_1; + + NDIS_HD_SPLIT_ATTRIBUTES nhsa; + NdisZeroMemory(&nhsa, sizeof(nhsa)); + + nhsa.Header.Type = NDIS_OBJECT_TYPE_HD_SPLIT_ATTRIBUTES; + nhsa.Header.Revision = NDIS_OFFLOAD_REVISION_1; + nhsa.Header.Size = NDIS_SIZEOF_HD_SPLIT_ATTRIBUTES_REVISION_1; + + // BUGBUG: We are just cheating here ... + nhsa.HardwareCapabilities = NDIS_HD_SPLIT_CAPS_SUPPORTS_HEADER_DATA_SPLIT; +#if 0 + ... Only supported on B0 + + NDIS_HD_SPLIT_CAPS_SUPPORTS_IPV4_OPTIONS | + NDIS_HD_SPLIT_CAPS_SUPPORTS_IPV6_EXTENSION_HEADERS | + NDIS_HD_SPLIT_CAPS_SUPPORTS_TCP_OPTIONS; +#endif + + // The bellow should be left zero + if (pPort->Config.HeaderDataSplit) { + nhsa.CurrentCapabilities = NDIS_HD_SPLIT_CAPS_SUPPORTS_HEADER_DATA_SPLIT; + } else { + nhsa.CurrentCapabilities = 0; + } + + nhsa.HDSplitFlags = 0; + nhsa.BackfillSize = 0; + nhsa.MaxHeaderSize = 0; + + atr.HDSplitAttributes = &nhsa; + + Status = NdisMSetMiniportAttributes(h_adapter, + (PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)&atr); + + if (nhsa.HDSplitFlags & NDIS_HD_SPLIT_ENABLE_HEADER_DATA_SPLIT) { + ASSERT(pPort->Config.HeaderDataSplit == TRUE); + pPort->Config.HeaderDataSplit = TRUE; + } + else { + ASSERT(pPort->Config.HeaderDataSplit == FALSE); + pPort->Config.HeaderDataSplit = FALSE; + } + + return Status; +} +#endif + +/*++ +Routine Description: + the routine sets attributes that are associated with a miniport adapter. + +Arguments: + pPort - Pointer to port object + +Return Value: + NDIS_STATUS + +Note: + Should be called in PASSIVE_LEVEL + +--*/ +NDIS_STATUS +SetAdapterRegistrationAttributes( + ipoib_adapter_t *p_adapter, + NDIS_HANDLE h_adapter + ) + { + NDIS_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES atr; + NTSTATUS Status; + + NdisZeroMemory(&atr, sizeof(NDIS_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES)); + + /* setting registration attributes */ + + atr.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES; + atr.Header.Revision = NDIS_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES_REVISION_1; + atr.Header.Size = NDIS_SIZEOF_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES_REVISION_1; + + atr.MiniportAdapterContext = (NDIS_HANDLE)p_adapter; + atr.AttributeFlags = NDIS_MINIPORT_ATTRIBUTES_BUS_MASTER; + atr.CheckForHangTimeInSeconds = 10; + atr.InterfaceType = NdisInterfacePci ; // ???? UH + //TODO NDIS60 PNP or PCI ? + //RegistrationAttributes.InterfaceType = NdisInterfacePNPBus; + + Status = NdisMSetMiniportAttributes(h_adapter, + (PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)&atr); + + return Status; +} + + +/*++ +Routine Description: + the routine sets generic attributes that are associated with a miniport + adapter. + +Arguments: + pPort - Pointer to port object + +Return Value: + NDIS_STATUS + +Note: + Should be called in PASSIVE_LEVEL + +--*/ +NDIS_STATUS +SetGenericAttributes( + ipoib_adapter_t *p_adapter, + NDIS_HANDLE h_adapter + ) +{ + NDIS_STATUS Status; + + NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES gat; + NdisZeroMemory(&gat, sizeof(NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES)); + + /* set up generic attributes */ + + gat.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES; + gat.Header.Revision = NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES_REVISION_1; + gat.Header.Size = sizeof(NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES); + + gat.MediaType = NdisMedium802_3; + gat.MaxXmitLinkSpeed = IPOIB_MEDIA_MAX_SPEED; + gat.MaxRcvLinkSpeed = IPOIB_MEDIA_MAX_SPEED; + gat.XmitLinkSpeed = NDIS_LINK_SPEED_UNKNOWN; + gat.RcvLinkSpeed = NDIS_LINK_SPEED_UNKNOWN; + + gat.MediaConnectState = MediaConnectStateConnected; //TODO NDIS60 Check the current state + gat.MediaDuplexState = MediaDuplexStateFull; + + gat.MtuSize = DEFAULT_PAYLOAD_MTU; + gat.LookaheadSize = MAX_XFER_BLOCK_SIZE; + gat.MacOptions = NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA | + NDIS_MAC_OPTION_TRANSFERS_NOT_PEND | + NDIS_MAC_OPTION_NO_LOOPBACK | + NDIS_MAC_OPTION_FULL_DUPLEX; + //NDIS_MAC_OPTION_8021P_PRIORITY; //TODO NDIS60 + // DT: Enable for Header Data Split WHQL + // | NDIS_MAC_OPTION_8021Q_VLAN; + + gat.SupportedPacketFilters = NDIS_PACKET_TYPE_DIRECTED | + NDIS_PACKET_TYPE_MULTICAST | + //NDIS_PACKET_TYPE_ALL_MULTICAST | + NDIS_PACKET_TYPE_BROADCAST; + + gat.MaxMulticastListSize = MAX_MCAST; + + gat.MacAddressLength = HW_ADDR_LEN; + + NdisMoveMemory(gat.PermanentMacAddress, + p_adapter->mac.addr, + HW_ADDR_LEN); + + NdisMoveMemory(gat.CurrentMacAddress, + p_adapter->params.conf_mac.addr, + HW_ADDR_LEN); + + + gat.PhysicalMediumType = NdisPhysicalMedium802_3; + gat.AccessType = NET_IF_ACCESS_BROADCAST; + + gat.SupportedOidList = (PNDIS_OID)SUPPORTED_OIDS; + gat.SupportedOidListLength = sizeof(SUPPORTED_OIDS); + + + gat.DirectionType = NET_IF_DIRECTION_SENDRECEIVE; + gat.ConnectionType = NET_IF_CONNECTION_DEDICATED; + gat.IfType = IF_TYPE_ETHERNET_CSMACD; + gat.IfConnectorPresent = TRUE; + gat.AccessType = NET_IF_ACCESS_BROADCAST; // NET_IF_ACCESS_BROADCAST for a typical ethernet adapter + + + //TODO NDIS60 is it possible to reduce unsupported statistics + gat.SupportedStatistics = + NDIS_STATISTICS_XMIT_OK_SUPPORTED | + NDIS_STATISTICS_RCV_OK_SUPPORTED | + NDIS_STATISTICS_XMIT_ERROR_SUPPORTED | + NDIS_STATISTICS_RCV_ERROR_SUPPORTED | + NDIS_STATISTICS_RCV_CRC_ERROR_SUPPORTED | + NDIS_STATISTICS_RCV_NO_BUFFER_SUPPORTED | + NDIS_STATISTICS_TRANSMIT_QUEUE_LENGTH_SUPPORTED; + + //SupportedStatistics = NDIS_STATISTICS_XMIT_OK_SUPPORTED | + // NDIS_STATISTICS_GEN_STATISTICS_SUPPORTED; + + + // + // Set power management capabilities + // + gat.PowerManagementCapabilities = NULL; +#if 0 + NDIS_PNP_CAPABILITIES PowerManagementCapabilities; + NdisZeroMemory(&PowerManagementCapabilities, sizeof(NDIS_PNP_CAPABILITIES)); + if (MPIsPoMgmtSupported(pPort)) + { + MPFillPoMgmtCaps(pPort, &PowerManagementCapabilities, &Status, &unUsed); + ASSERT(NT_SUCCESS(Status)); + gat.PowerManagementCapabilities = &PowerManagementCapabilities; + } + else + { + + } +#endif + + // + // Set RSS attributes + // + gat.RecvScaleCapabilities = NULL; +#if 0 + NDIS_RECEIVE_SCALE_CAPABILITIES RssCapabilities; + NdisZeroMemory(&RssCapabilities, sizeof(PNDIS_RECEIVE_SCALE_CAPABILITIES)); + Status = MPFillRssCapabilities(pPort, &RssCapabilities, &unUsed); + if (NT_SUCCESS(Status)) + { + gat.RecvScaleCapabilities = &RssCapabilities; + } + else + { + // + // do not fail the call because of failure to get PM caps + // + Status = NDIS_STATUS_SUCCESS; + gat.RecvScaleCapabilities = NULL; + } +#endif + + Status = NdisMSetMiniportAttributes(h_adapter, + (PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)&gat); + + return Status; +} + + +/*++ +Routine Description: + The routine sets an NDIS_OFFLOAD structure indicates the current offload + capabilities that are provided by the miniport adapter + +Arguments: + pPort - a pointer to port object + offload - reference to NDIS_OFFLOAD object that should be filled + +Return Value: + None. + +--*/ +static +void +OffloadConfig( + ipoib_adapter_t *p_adapter, + NDIS_OFFLOAD *p_offload + ) +{ + + ULONG ulEncapsulation = NDIS_ENCAPSULATION_IEEE_802_3 | NDIS_ENCAPSULATION_IEEE_802_3_P_AND_Q; + + NdisZeroMemory(p_offload, NDIS_SIZEOF_NDIS_OFFLOAD_REVISION_1); + + p_offload->Header.Type = NDIS_OBJECT_TYPE_OFFLOAD; + p_offload->Header.Revision = NDIS_OFFLOAD_REVISION_1; // Should be Revision 1, otherwise NDIS will not work at Win2008 R1 + p_offload->Header.Size = NDIS_SIZEOF_NDIS_OFFLOAD_REVISION_1; + + p_offload->Checksum.IPv4Transmit.Encapsulation = ulEncapsulation; + p_offload->Checksum.IPv4Transmit.IpOptionsSupported = + p_offload->Checksum.IPv4Transmit.TcpOptionsSupported = + p_offload->Checksum.IPv4Transmit.TcpChecksum = + p_offload->Checksum.IPv4Transmit.UdpChecksum = + p_offload->Checksum.IPv4Transmit.IpChecksum =!!(p_adapter->params.send_chksum_offload); + + p_offload->Checksum.IPv4Receive.Encapsulation = ulEncapsulation; + p_offload->Checksum.IPv4Receive.IpOptionsSupported = + p_offload->Checksum.IPv4Receive.TcpOptionsSupported = + p_offload->Checksum.IPv4Receive.TcpChecksum = + p_offload->Checksum.IPv4Receive.UdpChecksum = + p_offload->Checksum.IPv4Receive.IpChecksum = !!(p_adapter->params.recv_chksum_offload); + + + p_offload->Checksum.IPv6Transmit.Encapsulation = ulEncapsulation; + p_offload->Checksum.IPv6Transmit.IpExtensionHeadersSupported = + p_offload->Checksum.IPv6Transmit.TcpOptionsSupported = + p_offload->Checksum.IPv6Transmit.TcpChecksum = + p_offload->Checksum.IPv6Transmit.UdpChecksum = FALSE; + + + p_offload->Checksum.IPv6Receive.Encapsulation = ulEncapsulation; + p_offload->Checksum.IPv6Receive.IpExtensionHeadersSupported = + p_offload->Checksum.IPv6Receive.TcpOptionsSupported = + p_offload->Checksum.IPv6Receive.TcpChecksum = + p_offload->Checksum.IPv6Receive.UdpChecksum = FALSE; + + if (p_adapter->params.lso) + { + p_offload->LsoV1.IPv4.Encapsulation = ulEncapsulation; + p_offload->LsoV1.IPv4.MaxOffLoadSize = LARGE_SEND_OFFLOAD_SIZE; +#define LSO_MIN_SEG_COUNT 2 + p_offload->LsoV1.IPv4.MinSegmentCount = LSO_MIN_SEG_COUNT; + + + p_offload->LsoV1.IPv4.TcpOptions = NDIS_OFFLOAD_SUPPORTED; + p_offload->LsoV1.IPv4.IpOptions = NDIS_OFFLOAD_SUPPORTED; + + p_offload->LsoV2.IPv4.Encapsulation = ulEncapsulation; + p_offload->LsoV2.IPv4.MaxOffLoadSize = LARGE_SEND_OFFLOAD_SIZE; + p_offload->LsoV2.IPv4.MinSegmentCount = LSO_MIN_SEG_COUNT; +#if 0 + p_offload->LsoV2.IPv6.Encapsulation = ulEncapsulation; + p_offload->LsoV2.IPv6.MaxOffLoadSize = LARGE_SEND_OFFLOAD_SIZE; + p_offload->LsoV2.IPv6.MinSegmentCount = LSO_MIN_SEG_COUNT; +#endif + + } else { + p_offload->LsoV1.IPv4.TcpOptions = NDIS_OFFLOAD_NOT_SUPPORTED; + p_offload->LsoV1.IPv4.IpOptions = NDIS_OFFLOAD_NOT_SUPPORTED; + } + + p_offload->LsoV2.IPv6.IpExtensionHeadersSupported = NDIS_OFFLOAD_NOT_SUPPORTED; + p_offload->LsoV2.IPv6.TcpOptionsSupported = NDIS_OFFLOAD_NOT_SUPPORTED; + +} + + +/*++ +Routine Description: + The routine sets an NDIS_OFFLOAD structure that indicates all the task + offload capabilites that are supported by the NIC. These capabilities include + capabilities that are currently disabled by standardized keywords in the registry. + +Arguments: + offload - reference to NDIS_OFFLOAD object that should be filled + +Return Value: + None. + +--*/ +static +void +OffloadCapabilities( + ipoib_adapter_t *p_adapter, + NDIS_OFFLOAD *p_offload + ) +{ + ULONG ulEncapsulation = NDIS_ENCAPSULATION_IEEE_802_3 | NDIS_ENCAPSULATION_IEEE_802_3_P_AND_Q ; + NdisZeroMemory(p_offload, NDIS_SIZEOF_NDIS_OFFLOAD_REVISION_1); + + p_offload->Header.Type = NDIS_OBJECT_TYPE_OFFLOAD; + p_offload->Header.Revision = NDIS_OFFLOAD_REVISION_1; // BUGBUG: do we need to support revision 2? UH 17-May-2008 + p_offload->Header.Size = NDIS_SIZEOF_NDIS_OFFLOAD_REVISION_1; + + p_offload->Checksum.IPv4Transmit.Encapsulation = ulEncapsulation; + p_offload->Checksum.IPv4Transmit.IpOptionsSupported = + p_offload->Checksum.IPv4Transmit.TcpOptionsSupported = + p_offload->Checksum.IPv4Transmit.TcpChecksum = + p_offload->Checksum.IPv4Transmit.UdpChecksum = + p_offload->Checksum.IPv4Transmit.IpChecksum = p_adapter->offload_cap.send_chksum_offload; + + p_offload->Checksum.IPv4Receive.Encapsulation = ulEncapsulation; + p_offload->Checksum.IPv4Receive.IpOptionsSupported = + p_offload->Checksum.IPv4Receive.TcpOptionsSupported = + p_offload->Checksum.IPv4Receive.TcpChecksum = + p_offload->Checksum.IPv4Receive.UdpChecksum = + p_offload->Checksum.IPv4Receive.IpChecksum = p_adapter->offload_cap.recv_chksum_offload; + + + // + // BUGBUG:: + // During a HW bug that didn't handle correctly packets with + // IPv6 Extension Headers -> we set IpExtensionHeadersSupported to TRUE + // + p_offload->Checksum.IPv6Transmit.Encapsulation = ulEncapsulation; + p_offload->Checksum.IPv6Transmit.IpExtensionHeadersSupported = + p_offload->Checksum.IPv6Transmit.TcpOptionsSupported = + p_offload->Checksum.IPv6Transmit.TcpChecksum = + p_offload->Checksum.IPv6Transmit.UdpChecksum = FALSE; + + + p_offload->Checksum.IPv6Receive.Encapsulation = ulEncapsulation; + p_offload->Checksum.IPv6Receive.IpExtensionHeadersSupported = + p_offload->Checksum.IPv6Receive.TcpOptionsSupported = + p_offload->Checksum.IPv6Receive.TcpChecksum = + p_offload->Checksum.IPv6Receive.UdpChecksum = FALSE; + + if (p_adapter->offload_cap.lso) { + + p_offload->LsoV1.IPv4.Encapsulation = ulEncapsulation; + p_offload->LsoV1.IPv4.MaxOffLoadSize = LARGE_SEND_OFFLOAD_SIZE; + p_offload->LsoV1.IPv4.MinSegmentCount = 2; + p_offload->LsoV1.IPv4.TcpOptions = NDIS_OFFLOAD_SUPPORTED; + p_offload->LsoV1.IPv4.IpOptions = NDIS_OFFLOAD_SUPPORTED; + + p_offload->LsoV2.IPv4.Encapsulation = ulEncapsulation; + p_offload->LsoV2.IPv4.MaxOffLoadSize = LARGE_SEND_OFFLOAD_SIZE; + p_offload->LsoV2.IPv4.MinSegmentCount = 2; + + } else { + p_offload->LsoV1.IPv4.TcpOptions = NDIS_OFFLOAD_NOT_SUPPORTED; + p_offload->LsoV1.IPv4.IpOptions = NDIS_OFFLOAD_NOT_SUPPORTED; + + } + + /*p_offload->LsoV2.IPv6.Encapsulation = ulEncapsulation; + p_offload->LsoV2.IPv6.MaxOffLoadSize = LARGE_SEND_OFFLOAD_SIZE; + p_offload->LsoV2.IPv6.MinSegmentCount = 2;*/ + + p_offload->LsoV2.IPv6.IpExtensionHeadersSupported = NDIS_OFFLOAD_NOT_SUPPORTED; + p_offload->LsoV2.IPv6.TcpOptionsSupported = NDIS_OFFLOAD_NOT_SUPPORTED; + +} + + +/*++ +Routine Description: + The routine sets offload attributes that are associated with a miniport + adapter. + +Arguments: + pPort - Pointer to port object + +Return Value: + NDIS_STATUS + +Note: + Should be called in PASSIVE_LEVEL + +--*/ +NDIS_STATUS +SetOffloadAttributes( + ipoib_adapter_t *p_adapter, + NDIS_HANDLE h_adapter + ) +{ + NDIS_STATUS Status; + NDIS_OFFLOAD offload,hwOffload; + //ULONG ulEncapsulation = NDIS_ENCAPSULATION_IEEE_802_3 | NDIS_ENCAPSULATION_IEEE_802_3_P_AND_Q; + + NDIS_MINIPORT_ADAPTER_OFFLOAD_ATTRIBUTES oat; + NdisZeroMemory(&oat, sizeof(NDIS_MINIPORT_ADAPTER_OFFLOAD_ATTRIBUTES)); + + oat.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_OFFLOAD_ATTRIBUTES; + oat.Header.Revision = NDIS_MINIPORT_ADAPTER_OFFLOAD_ATTRIBUTES_REVISION_1; + oat.Header.Size = NDIS_SIZEOF_MINIPORT_ADAPTER_OFFLOAD_ATTRIBUTES_REVISION_1; + + + OffloadConfig(p_adapter, &offload); + + + OffloadCapabilities(p_adapter, &hwOffload); + + oat.DefaultOffloadConfiguration = &offload; + oat.HardwareOffloadCapabilities = &hwOffload; + + Status = NdisMSetMiniportAttributes(h_adapter, + (PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)&oat); + + return Status; +} + + +/*++ + +Routine Description: + An NDIS 6.0 miniport driver must call NdisMSetMiniportAttributes + at least twice. The first call is to register itself with NDIS. + The second call is to register the miniport driver's general + attributes with NDIS. + + NdisMSetMiniportAttributes takes a parameter of type + NDIS_MINIPORT_ADAPTER_ATTRIBUTES, which is a union of several miniport + adapter attributes. Miniport drivers must first call + NdisMSetMiniportAttributes and pass in an + NDIS_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES structure + that contains the pointer to its own context area, attribute flags, + check-for-hang time, and interface type. + + All NDIS 6.0 miniport drivers are deserialized by default. + +Arguments: + pPort - Pointer to port object + +Return Value: + NDIS_STATUS + +Note: + Should be called in PASSIVE_LEVEL + +--*/ +NDIS_STATUS +SetAttributes( + ipoib_adapter_t *p_adapter, + NDIS_HANDLE h_adapter + ) + { + NTSTATUS Status; + + + Status = SetDeviceRegistrationAttributes(p_adapter, h_adapter); + if (Status != NDIS_STATUS_SUCCESS) + { + //ETH_PRINT(TRACE_LEVEL_ERROR, ETH_INIT, "Set device registration failed Error=0x%x\n", Status); + NdisWriteErrorLogEntry( h_adapter, + EVENT_IPOIB_START_UP_DEV_REG_ATTR, 1, Status ); + return Status; + } + + + Status = SetAdapterRegistrationAttributes(p_adapter, h_adapter); + if (Status != NDIS_STATUS_SUCCESS) + { + //ETH_PRINT(TRACE_LEVEL_ERROR, ETH_INIT, "Set adapter attributes failed Error=0x%x\n", Status); + NdisWriteErrorLogEntry( h_adapter, + EVENT_IPOIB_START_UP_ADAPTER_REG_ATTR, 1, Status ); + return Status; + } + + + +#if 0 + if(!pPort->Config.fWHQL) + { + Status = SetHardwareAssistAttributes(pPort); + if (Status != NDIS_STATUS_SUCCESS) + { + //ETH_PRINT(TRACE_LEVEL_ERROR, ETH_INIT, "Set Hardware Assist Attributes failed Error=0x%x\n", Status); + return Status; + } + } +#endif + + Status = SetGenericAttributes(p_adapter, h_adapter); + if (Status != NDIS_STATUS_SUCCESS) + { + //ETH_PRINT(TRACE_LEVEL_ERROR, ETH_INIT, "Set generic attributes failed Error=0x%x\n", Status); + return Status; + } + + return Status; +} + +BOOLEAN +IsValidOffloadConfig(ipoib_adapter_t *p_adapter, PNDIS_OFFLOAD_PARAMETERS pOffloadParam) +{ + BOOLEAN bRet = TRUE; + + UCHAR CheckSumConfig[5]={0}; + CheckSumConfig[0] = pOffloadParam->IPv4Checksum; + CheckSumConfig[1] = pOffloadParam->TCPIPv4Checksum; + CheckSumConfig[2] = pOffloadParam->UDPIPv4Checksum; + CheckSumConfig[3] = pOffloadParam->TCPIPv6Checksum; + CheckSumConfig[4] = pOffloadParam->UDPIPv6Checksum; + + for(int i=0 ; i<5 ; i++) + { + if(CheckSumConfig[i] != NDIS_OFFLOAD_PARAMETERS_NO_CHANGE) + { + switch (CheckSumConfig[i]) { + case NDIS_OFFLOAD_PARAMETERS_TX_RX_DISABLED: + bRet = TRUE; + break; + //return FALSE in any case when NDIS tries to set unsupported value + case NDIS_OFFLOAD_PARAMETERS_TX_ENABLED_RX_DISABLED: + bRet = (BOOLEAN) p_adapter->offload_cap.send_chksum_offload; + break; + case NDIS_OFFLOAD_PARAMETERS_RX_ENABLED_TX_DISABLED: + bRet = (BOOLEAN) p_adapter->offload_cap.recv_chksum_offload; + break; + case NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED: + bRet = (BOOLEAN) (p_adapter->offload_cap.send_chksum_offload && + p_adapter->offload_cap.recv_chksum_offload); + break; + default: + ASSERT (FALSE); + } + + if (!bRet) + return FALSE; + + + for(int j=0 ; j<5 ; j++) + { + if( (CheckSumConfig[j] != 0) && (CheckSumConfig[j] != CheckSumConfig[i]) ) + { + bRet = FALSE; + goto Exit; + } + } + } + } + + + UCHAR OffloadConfig[3]={0}; + OffloadConfig[0] = pOffloadParam->LsoV1; + OffloadConfig[1] = pOffloadParam->LsoV2IPv4; + OffloadConfig[2] = pOffloadParam->LsoV2IPv6; + + if (!p_adapter->offload_cap.lso) { + if ((pOffloadParam->LsoV1 == NDIS_OFFLOAD_PARAMETERS_LSOV1_ENABLED) || + (pOffloadParam->LsoV2IPv4 == NDIS_OFFLOAD_PARAMETERS_LSOV1_ENABLED)) + { + return FALSE; + } + } + + pOffloadParam->LsoV1; + OffloadConfig[1] = pOffloadParam->LsoV2IPv4; + + for(int i=0 ; i<3 ; i++) + { + if(OffloadConfig[i] != NDIS_OFFLOAD_PARAMETERS_NO_CHANGE) + { + for(int j=0 ; j<3 ; j++) + { + if( (OffloadConfig[j] != 0) && (OffloadConfig[j] != OffloadConfig[i]) ) + { + bRet = FALSE; + goto Exit; + } + } + } + } + +Exit: + return bRet; +} + +static +NDIS_STATUS +SetOffloadParameters( + ipoib_adapter_t * p_adapter, + void* const pBuf, + ULONG len + ) +{ + IPOIB_ENTER(IPOIB_DBG_OID); + + ASSERT(pBuf != NULL); + + PNDIS_OFFLOAD_PARAMETERS pOffloadParam = NULL; + PNDIS_OBJECT_HEADER pOffloadHeader = NULL; + NDIS_STATUS Status = NDIS_STATUS_SUCCESS; + bool StatusIndicationFlag = FALSE; + + if (len != NDIS_SIZEOF_OFFLOAD_PARAMETERS_REVISION_2) + { + ASSERT(FALSE); + IPOIB_PRINT(TRACE_LEVEL_ERROR, IPOIB_DBG_OID, + ("Buffer is too small. offloading task requirs %d but the buffer " + "size is: %d \n", NDIS_SIZEOF_OFFLOAD_PARAMETERS_REVISION_2, len)); + Status = NDIS_STATUS_INVALID_LENGTH; + goto Exit; + } + + IPOIB_PRINT(TRACE_LEVEL_VERBOSE, IPOIB_DBG_OID, + ("received set for OID_TCP_TASK_OFFLOAD\n")); + + pOffloadParam = (PNDIS_OFFLOAD_PARAMETERS) pBuf; + pOffloadHeader = &(pOffloadParam->Header); + + if((pOffloadHeader->Type != NDIS_OBJECT_TYPE_DEFAULT) || + (pOffloadHeader->Revision != NDIS_OFFLOAD_PARAMETERS_REVISION_2) || + (pOffloadHeader->Size != NDIS_SIZEOF_OFFLOAD_PARAMETERS_REVISION_2)) + { + ASSERT(FALSE); + IPOIB_PRINT(TRACE_LEVEL_ERROR, IPOIB_DBG_OID, + ("Set offloading task Illegal header\n")); + Status = NDIS_STATUS_INVALID_DATA; + goto Exit; + } + + if ((pOffloadParam->IPsecV1 != NDIS_OFFLOAD_PARAMETERS_NO_CHANGE) || + (pOffloadParam->TcpConnectionIPv4 != NDIS_OFFLOAD_PARAMETERS_NO_CHANGE) || + (pOffloadParam->TcpConnectionIPv6 != NDIS_OFFLOAD_PARAMETERS_NO_CHANGE) || + (pOffloadParam->Flags != 0)) + { + Status = NDIS_STATUS_NOT_SUPPORTED; + goto Exit; + } + + //Eliminate currently unsupported statistic + if ((pOffloadParam->TCPIPv6Checksum != NDIS_OFFLOAD_PARAMETERS_NO_CHANGE) || + (pOffloadParam->UDPIPv6Checksum != NDIS_OFFLOAD_PARAMETERS_NO_CHANGE) || + (pOffloadParam->LsoV2IPv6 != NDIS_OFFLOAD_PARAMETERS_NO_CHANGE)) + { + Status = NDIS_STATUS_NOT_SUPPORTED; + goto Exit; + } + + + BOOLEAN bRet = IsValidOffloadConfig(p_adapter, pOffloadParam); + if(bRet == FALSE) + { + //ASSERT(FALSE); + Status = NDIS_STATUS_NOT_SUPPORTED; + goto Exit; + } + + // Set current offload configuration capabilites + if ((pOffloadParam->IPv4Checksum == NDIS_OFFLOAD_PARAMETERS_TX_ENABLED_RX_DISABLED) || + (pOffloadParam->TCPIPv4Checksum == NDIS_OFFLOAD_PARAMETERS_TX_ENABLED_RX_DISABLED) || + (pOffloadParam->UDPIPv4Checksum == NDIS_OFFLOAD_PARAMETERS_TX_ENABLED_RX_DISABLED)) + { + p_adapter->params.send_chksum_offload = CSUM_ENABLED; + p_adapter->params.recv_chksum_offload = CSUM_DISABLED; + StatusIndicationFlag = TRUE; + } + + else if ((pOffloadParam->IPv4Checksum == NDIS_OFFLOAD_PARAMETERS_RX_ENABLED_TX_DISABLED) || + (pOffloadParam->TCPIPv4Checksum == NDIS_OFFLOAD_PARAMETERS_RX_ENABLED_TX_DISABLED) || + (pOffloadParam->UDPIPv4Checksum == NDIS_OFFLOAD_PARAMETERS_RX_ENABLED_TX_DISABLED)) + { + p_adapter->params.recv_chksum_offload = CSUM_ENABLED; + p_adapter->params.send_chksum_offload = CSUM_DISABLED; + StatusIndicationFlag = TRUE; + } + + else if ((pOffloadParam->IPv4Checksum == NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED ) || + (pOffloadParam->TCPIPv4Checksum == NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED ) || + (pOffloadParam->UDPIPv4Checksum == NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED )) + { + p_adapter->params.send_chksum_offload = CSUM_ENABLED; + p_adapter->params.recv_chksum_offload = CSUM_ENABLED; + StatusIndicationFlag = TRUE; + } + else if ((pOffloadParam->IPv4Checksum == NDIS_OFFLOAD_PARAMETERS_TX_RX_DISABLED ) || + (pOffloadParam->TCPIPv4Checksum == NDIS_OFFLOAD_PARAMETERS_TX_RX_DISABLED ) || + (pOffloadParam->UDPIPv4Checksum == NDIS_OFFLOAD_PARAMETERS_TX_RX_DISABLED )) + { + p_adapter->params.send_chksum_offload = CSUM_DISABLED; + p_adapter->params.recv_chksum_offload = CSUM_DISABLED; + StatusIndicationFlag = TRUE; + } + + + + #if 0 + if(pOffloadParam->TCPIPv6Checksum != NDIS_OFFLOAD_PARAMETERS_NO_CHANGE) + { + UpdateOffloadSeeting(pOffloadParam->TCPIPv6Checksum, pPort->Config.TCPUDPIPv4Chksum); + StatusIndicationFlag = TRUE; + } + + if(pOffloadParam->UDPIPv6Checksum != NDIS_OFFLOAD_PARAMETERS_NO_CHANGE) + { + UpdateOffloadSeeting(pOffloadParam->UDPIPv6Checksum, pPort->Config.TCPUDPIPv4Chksum); + StatusIndicationFlag = TRUE; + } +#endif + + // SetCheksumOffloadingModes(pPort->Config); + + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// + + //////////////////////////// OFFLOAD OFFLOAD //////////////////////////// + if(pOffloadParam->LsoV1 != NDIS_OFFLOAD_PARAMETERS_NO_CHANGE) + { + p_adapter->params.lso = (pOffloadParam->LsoV1 == NDIS_OFFLOAD_PARAMETERS_LSOV1_ENABLED); + StatusIndicationFlag = TRUE; + } + + if(pOffloadParam->LsoV2IPv4 != NDIS_OFFLOAD_PARAMETERS_NO_CHANGE) + { + p_adapter->params.lso = (pOffloadParam->LsoV1 == NDIS_OFFLOAD_PARAMETERS_LSOV2_ENABLED); + StatusIndicationFlag = TRUE; + } +#if 0 + if(pOffloadParam->LsoV2IPv6 != NDIS_OFFLOAD_PARAMETERS_NO_CHANGE) + { + if(pOffloadParam->LsoV2IPv6 == NDIS_OFFLOAD_PARAMETERS_LSOV2_ENABLED) + { + pPort->Config.LsoV2IPv6 = TRUE; + } + else + { + pPort->Config.LsoV2IPv6 = FALSE; + } + + StatusIndicationFlag = TRUE; + } +#endif + + + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// + + + if(StatusIndicationFlag) + { + NDIS_OFFLOAD CurrentOffloadCapapilities; + NDIS_STATUS_INDICATION StatusIndication; + + OffloadConfig(p_adapter, &CurrentOffloadCapapilities); + + + IPOIB_INIT_NDIS_STATUS_INDICATION(&StatusIndication, + p_adapter->h_adapter, + NDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG , + (PVOID)&CurrentOffloadCapapilities, + sizeof(CurrentOffloadCapapilities)); + + NdisMIndicateStatusEx(p_adapter->h_adapter, &StatusIndication); + } + +Exit: + IPOIB_EXIT(IPOIB_DBG_OID); + return Status; +} + +/*++ + +Routine Description: + The routine handles setting of OID_GEN_INTERRUPT_MODERATION. + +Arguments: + InformationBuffer - Pointer to the buffer that contains the data + InformationBufferLength - data length + +Return Value: + NDIS_STAUS + +--*/ +static +NDIS_STATUS +SetInterruptModeration( + PVOID InformationBuffer, + ULONG InformationBufferLength ) +{ + IPOIB_ENTER(IPOIB_DBG_OID); + + NDIS_STATUS Status = NDIS_STATUS_SUCCESS; + + if (InformationBufferLength != sizeof(NDIS_INTERRUPT_MODERATION_PARAMETERS)) + { + Status = NDIS_STATUS_INVALID_LENGTH; + goto Exit; + } + + PNDIS_INTERRUPT_MODERATION_PARAMETERS pInteruptModerationParam = + (PNDIS_INTERRUPT_MODERATION_PARAMETERS)InformationBuffer; + + if ((pInteruptModerationParam->Header.Type != NDIS_OBJECT_TYPE_DEFAULT) || + (pInteruptModerationParam->Header.Revision != NDIS_INTERRUPT_MODERATION_PARAMETERS_REVISION_1) || + (pInteruptModerationParam->Header.Size != NDIS_SIZEOF_INTERRUPT_MODERATION_PARAMETERS_REVISION_1)) + { + Status = NDIS_STATUS_INVALID_DATA; + goto Exit; + } + // + // BUGBUG: Need to handle disabling of interrupt moderation + // UH, 4-Jun-2008 + // +// ASSERT(pInteruptModerationParam->Flags == NDIS_INTERRUPT_MODERATION_CHANGE_NEEDS_RESET); +// ASSERT(pInteruptModerationParam->InterruptModeration == NdisInterruptModerationEnabled); + +Exit: + IPOIB_EXIT(IPOIB_DBG_OID); + return Status; +} + + +NDIS_STATUS +InitNdisScatterGatherDma( + ipoib_adapter_t *p_adapter, + NDIS_HANDLE h_adapter ) +{ + NDIS_STATUS status; + NDIS_SG_DMA_DESCRIPTION DmaDescription; + + NdisZeroMemory(&DmaDescription, sizeof(DmaDescription)); + + DmaDescription.Header.Type = NDIS_OBJECT_TYPE_SG_DMA_DESCRIPTION; + DmaDescription.Header.Revision = NDIS_SG_DMA_DESCRIPTION_REVISION_1; + DmaDescription.Header.Size = sizeof(NDIS_SG_DMA_DESCRIPTION); + DmaDescription.Flags = NDIS_SG_DMA_64_BIT_ADDRESS; + // + // Even if offload is enabled, the packet size for mapping shouldn't change + // + //TODO bug ? + DmaDescription.MaximumPhysicalMapping = LARGE_SEND_OFFLOAD_SIZE + LSO_MAX_HEADER; + + DmaDescription.ProcessSGListHandler = ipoib_process_sg_list; + DmaDescription.SharedMemAllocateCompleteHandler = NULL; + + DmaDescription.Header.Type = NDIS_OBJECT_TYPE_SG_DMA_DESCRIPTION; + DmaDescription.Header.Revision = NDIS_SG_DMA_DESCRIPTION_REVISION_1; + DmaDescription.Header.Size = sizeof(NDIS_SG_DMA_DESCRIPTION);//NDIS_SIZEOF_SG_DMA_DESCRIPTION_REVISION_1; + + DmaDescription.Flags = NDIS_SG_DMA_64_BIT_ADDRESS; + //DmaDescription.MaximumPhysicalMapping = pPort->p_adapter->params.xfer_block_size; + + + status = NdisMRegisterScatterGatherDma( + h_adapter, + &DmaDescription, + &p_adapter->NdisMiniportDmaHandle ); + + if( status != NDIS_STATUS_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("NdisMRegisterScatterGatherDma returned 0x%.8x.\n", status) ); + return status; + + } + //NDIS sets this value before it returns from NdisMRegisterScatterGatherDma. + //Miniport drivers should use this size to preallocate memory for each + // scatter/gather list. + p_adapter->sg_list_size = DmaDescription.ScatterGatherListSize ; + + return status; +} + + + + +/*++ +Routine Description: + + MiniportInitialize handler + +Arguments: + + MiniportAdapterHandle The handle NDIS uses to refer to us + MiniportDriverContext Handle passed to NDIS when we registered the driver + MiniportInitParameters Initialization parameters + +Return Value: + + NDIS_STATUS_SUCCESS unless something goes wrong + +--*/ + +NDIS_STATUS +ipoib_initialize_ex( + IN NDIS_HANDLE h_adapter, + IN NDIS_HANDLE config_context, + IN PNDIS_MINIPORT_INIT_PARAMETERS MiniportInitParameters) +{ + NDIS_STATUS status; + ib_api_status_t ib_status; + ipoib_adapter_t *p_adapter; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + +#if 0 +if(cl_get_time_stamp_sec() < 30) { + cl_dbg_out("Disable/Enable IPoIB adapter to continue running\n"); + return NDIS_STATUS_HARD_ERRORS; +} +#endif + +#ifdef _DEBUG_ + PAGED_CODE(); +#endif + + UNUSED_PARAM( config_context ); + UNUSED_PARAM( MiniportInitParameters ); + + /* Create the adapter adapter */ + ib_status = ipoib_create_adapter( h_adapter, &p_adapter ); + if( ib_status != IB_SUCCESS ) + { + //ASSERT(FALSE); + NdisWriteErrorLogEntry( h_adapter, + EVENT_IPOIB_START_UP_CREATE_ADAPTER, 1, ib_status ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ipoib_create_adapter returned status %d.\n", ib_status ) ); + return NDIS_STATUS_FAILURE; + } + p_adapter->ipoib_state = IPOIB_INIT; + + status = SetAttributes(p_adapter, h_adapter); + if (status != NDIS_STATUS_SUCCESS) { + //ASSERT(FALSE); + ipoib_destroy_adapter( p_adapter ); + return NDIS_STATUS_FAILURE; + } + +#if IPOIB_USE_DMA + status = InitNdisScatterGatherDma(p_adapter, h_adapter); + if( status != NDIS_STATUS_SUCCESS ) + { + ipoib_destroy_adapter( p_adapter ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("InitNdisScatterGatherDma returned status 0x%.8x.\n", status ) ); + return NDIS_STATUS_FAILURE; + } +#endif + /* Create the adapter adapter */ + ib_status = ipoib_start_adapter( p_adapter ); + if( ib_status != IB_SUCCESS ) + { + //ASSERT(FALSE); + NdisWriteErrorLogEntry( h_adapter, + EVENT_IPOIB_START_UP_START_ADAPTER, 1, ib_status ); +#if IPOIB_USE_DMA + NdisMDeregisterScatterGatherDma(p_adapter->NdisMiniportDmaHandle); +#endif + ipoib_destroy_adapter( p_adapter ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ipoib_start_adapter returned status %d.\n", ib_status ) ); + return NDIS_STATUS_FAILURE; + } + + status = SetOffloadAttributes(p_adapter, h_adapter); + if (status != NDIS_STATUS_SUCCESS) + { + NdisWriteErrorLogEntry( h_adapter, + EVENT_IPOIB_START_UP_SET_OFFLOAD_ATTR, 1, status ); +#if IPOIB_USE_DMA + NdisMDeregisterScatterGatherDma(p_adapter->NdisMiniportDmaHandle); +#endif + ipoib_destroy_adapter( p_adapter ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("SetOffloadAttributes returned status 0x%.8x.\n", status ) ); + return NDIS_STATUS_FAILURE; + } + + ipoib_ref_ibat(); + + IPOIB_EXIT( IPOIB_DBG_INIT ); + return status; +} + + +//! Deallocates resources when the NIC is removed and halts the NIC.. +//TODO: Dispatch or Passive ? +/* IRQL = DISPATCH_LEVEL + +@param adapter_context The adapter context allocated at start +*/ +void +ipoib_halt_ex( + IN NDIS_HANDLE adapter_context, + IN NDIS_HALT_ACTION HaltAction ) +{ + ipoib_adapter_t *p_adapter; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + UNUSED_PARAM(HaltAction); + + ipoib_deref_ibat(); + + CL_ASSERT( adapter_context ); + p_adapter = (ipoib_adapter_t*)adapter_context; + + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, + ("Port %016I64x (CA %016I64x port %d) halting\n", + p_adapter->guids.port_guid.guid, p_adapter->guids.ca_guid, + p_adapter->guids.port_num) ); + +#if IPOIB_USE_DMA + if (p_adapter->NdisMiniportDmaHandle != NULL) + { + NdisMDeregisterScatterGatherDma(p_adapter->NdisMiniportDmaHandle); + p_adapter->NdisMiniportDmaHandle = NULL; + } +#endif + + ipoib_destroy_adapter( p_adapter ); + + IPOIB_EXIT( IPOIB_DBG_INIT ); +} + + +//! Reports the state of the NIC, or monitors the responsiveness of an underlying device driver. +/* IRQL = DISPATCH_LEVEL + +@param adapter_context The adapter context allocated at start +@return TRUE if the driver determines that its NIC is not operating +*/ +BOOLEAN +ipoib_check_for_hang( + IN NDIS_HANDLE adapter_context ) +{ + ipoib_adapter_t *p_adapter; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + CL_ASSERT( adapter_context ); + p_adapter = (ipoib_adapter_t*)adapter_context; + + if( p_adapter->reset ) + { + IPOIB_EXIT( IPOIB_DBG_INIT ); + return FALSE; + } + + if (p_adapter->p_port) + { + if (p_adapter->p_port->send_mgr.pending_list.count > 0) + { + ++(p_adapter->p_port->n_no_progress); + if (p_adapter->p_port->n_no_progress >= 4) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR,IPOIB_DBG_ERROR, + ("port got stuck, reseting it !!!\n")); + //CL_ASSERT(FALSE); //????? + p_adapter->hung = TRUE; + } + } + else + { + p_adapter->p_port->n_no_progress = 0; + } + } + + if (p_adapter->hung) { + ipoib_resume_oids(p_adapter); + } + + IPOIB_EXIT( IPOIB_DBG_INIT ); + return (p_adapter->hung? TRUE:FALSE); +} + + +/*++ +Routine Description: + The routine sets an NDIS_OFFLOAD structure indicates the current offload + capabilities that are provided by the miniport adapter + +Arguments: + pPort - a pointer to port object + offload - reference to NDIS_OFFLOAD object that should be filled + +Return Value: + None. + +--*/ +//TODO +#if 0 +static +void +__ipoib_get_offload_config( + ipoib_port_t *pPort, + NDIS_OFFLOAD *p_offload + ) +{ + NDIS_STATUS Status; + ULONG TxChksumOffload = ((MP_GET_PORT_CONFIG(pPort, TxChksumOffload) == TRUE) ? NDIS_OFFLOAD_SET_ON : NDIS_OFFLOAD_SET_OFF); + ULONG RxChksumOffload = ((MP_GET_PORT_CONFIG(pPort, RxChksumOffload) == TRUE) ? NDIS_OFFLOAD_SET_ON : NDIS_OFFLOAD_SET_OFF); + BOOLEAN fLargeSendOffload = MP_GET_PORT_CONFIG(pPort, LargeSendOffload); + ULONG ulEncapsulation = NDIS_ENCAPSULATION_IEEE_802_3 | NDIS_ENCAPSULATION_IEEE_802_3_P_AND_Q; + + NdisZeroMemory(&*p_offload, sizeof(NDIS_OFFLOAD)); + *p_offload.Header.Type = NDIS_OBJECT_TYPE_OFFLOAD; + *p_offload.Header.Revision = NDIS_OFFLOAD_REVISION_1; // BUGBUG: do we need to support revision 2? UH 17-May-2008 + *p_offload.Header.Size = NDIS_SIZEOF_NDIS_OFFLOAD_REVISION_1; + + *p_offload.Checksum.IPv4Transmit.Encapsulation = ulEncapsulation; + *p_offload.Checksum.IPv4Transmit.IpOptionsSupported = TxChksumOffload; + *p_offload.Checksum.IPv4Transmit.TcpOptionsSupported = TxChksumOffload; + *p_offload.Checksum.IPv4Transmit.TcpChecksum = TxChksumOffload; + *p_offload.Checksum.IPv4Transmit.UdpChecksum = NDIS_OFFLOAD_NOT_SUPPORTED; + *p_offload.Checksum.IPv4Transmit.IpChecksum = TxChksumOffload; + + *p_offload.Checksum.IPv4Receive.Encapsulation = ulEncapsulation; + *p_offload.Checksum.IPv4Receive.IpOptionsSupported = RxChksumOffload; + *p_offload.Checksum.IPv4Receive.TcpOptionsSupported = RxChksumOffload; + *p_offload.Checksum.IPv4Receive.TcpChecksum = RxChksumOffload; + *p_offload.Checksum.IPv4Receive.UdpChecksum = NDIS_OFFLOAD_NOT_SUPPORTED; + *p_offload.Checksum.IPv4Receive.IpChecksum = RxChksumOffload; + + *p_offload.Checksum.IPv6Transmit.Encapsulation = ulEncapsulation; + *p_offload.Checksum.IPv6Transmit.IpExtensionHeadersSupported = TxChksumOffload; + *p_offload.Checksum.IPv6Transmit.TcpOptionsSupported = TxChksumOffload; + *p_offload.Checksum.IPv6Transmit.TcpChecksum = TxChksumOffload; + *p_offload.Checksum.IPv6Transmit.UdpChecksum = NDIS_OFFLOAD_NOT_SUPPORTED; + + + *p_offload.Checksum.IPv6Receive.Encapsulation = ulEncapsulation; + *p_offload.Checksum.IPv6Receive.IpExtensionHeadersSupported = RxChksumOffload; + *p_offload.Checksum.IPv6Receive.TcpOptionsSupported = RxChksumOffload; + *p_offload.Checksum.IPv6Receive.TcpChecksum = RxChksumOffload; + *p_offload.Checksum.IPv6Receive.UdpChecksum = NDIS_OFFLOAD_NOT_SUPPORTED; + + if (fLargeSendOffload) + { + *p_offload.LsoV1.IPv4.Encapsulation = ulEncapsulation; + *p_offload.LsoV1.IPv4.MaxOffLoadSize = LARGE_SEND_OFFLOAD_SIZE; + *p_offload.LsoV1.IPv4.MinSegmentCount = 1; + *p_offload.LsoV1.IPv4.TcpOptions = NDIS_OFFLOAD_SUPPORTED; + *p_offload.LsoV1.IPv4.IpOptions = NDIS_OFFLOAD_SUPPORTED; + } +} +#endif + +//! Returns information about the capabilities and status of the driver and/or its NIC. +/* IRQL = DISPATCH_LEVEL + +@param adapter_context The adapter context allocated at start +@param oid Object ID representing the query operation to be carried out +@param info_buf Buffer containing any input for this query and location for output +@param info_buf_len Number of bytes available in info_buf +@param p_bytes_written Pointer to number of bytes written into info_buf +@param p_bytes_needed Pointer to number of bytes needed to satisfy this oid +@return NDIS_STATUS_SUCCESS, NDIS_STATUS_PENDING, NDIS_STATUS_INVALID_OID, +NDIS_STATUS_INVALID_LENGTH, NDIS_STATUS_NOT_ACCEPTED, NDIS_STATUS_NOT_SUPPORTED, +NDIS_STATUS_RESOURCES +*/ + +NDIS_STATUS +ipoib_query_info( + IN NDIS_HANDLE adapter_context, + IN OUT PNDIS_OID_REQUEST pNdisRequest ) + +{ + ipoib_adapter_t *p_adapter; + NDIS_STATUS status; + ULONG version; + ULONG info; + PVOID src_buf; + ULONG buf_len; + pending_oid_t oid_info; + uint8_t port_num; + NDIS_OFFLOAD offload; + + NDIS_INTERRUPT_MODERATION_PARAMETERS InterruptModerationParam; + + + IPOIB_ENTER( IPOIB_DBG_OID ); + + oid_info.oid = pNdisRequest->DATA.QUERY_INFORMATION.Oid; + oid_info.p_buf = pNdisRequest->DATA.QUERY_INFORMATION.InformationBuffer; + oid_info.buf_len = pNdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength; + oid_info.p_bytes_used = (PULONG)&pNdisRequest->DATA.QUERY_INFORMATION.BytesWritten; + oid_info.p_bytes_needed = (PULONG)&pNdisRequest->DATA.QUERY_INFORMATION.BytesNeeded; + oid_info.p_pending_oid = NULL; + + CL_ASSERT( adapter_context ); + p_adapter = (ipoib_adapter_t*)adapter_context; + + CL_ASSERT( oid_info.p_bytes_used ); + CL_ASSERT( oid_info.p_bytes_needed ); + CL_ASSERT( !p_adapter->pending_query ); + + status = NDIS_STATUS_SUCCESS; + src_buf = &info; + buf_len = sizeof(info); + + port_num = p_adapter->guids.port_num; + + switch( oid_info.oid ) + { + /* Required General */ + case OID_GEN_SUPPORTED_LIST: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_SUPPORTED_LIST\n", port_num) ); + src_buf = (PVOID)SUPPORTED_OIDS; + buf_len = sizeof(SUPPORTED_OIDS); + break; + + case OID_GEN_HARDWARE_STATUS: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_HARDWARE_STATUS\n", port_num) ); + + cl_obj_lock( &p_adapter->obj ); + switch( p_adapter->state ) + { + case IB_PNP_PORT_ADD: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d returning NdisHardwareStatusInitializing\n", port_num) ); + info = NdisHardwareStatusInitializing; + break; + + case IB_PNP_PORT_ACTIVE: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d returning NdisHardwareStatusReady\n", port_num) ); + info = NdisHardwareStatusReady; + break; + + default: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d returning NdisHardwareStatusNotReady\n", port_num) ); + info = NdisHardwareStatusNotReady; + } + cl_obj_unlock( &p_adapter->obj ); + break; + + case OID_GEN_MEDIA_SUPPORTED: + case OID_GEN_MEDIA_IN_USE: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_MEDIA_SUPPORTED " + "or OID_GEN_MEDIA_IN_USE\n", port_num) ); + info = NdisMedium802_3; + break; + + case OID_GEN_MAXIMUM_FRAME_SIZE: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_MAXIMUM_FRAME_SIZE\n", port_num) ); + if( p_adapter->params.cm_enabled ) + { + info = p_adapter->params.cm_payload_mtu; + } + else + { + info = p_adapter->params.payload_mtu; + } + break; + + case OID_GEN_TRANSMIT_BUFFER_SPACE: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_TRANSMIT_BUFFER_SPACE\n", + port_num) ); + if( p_adapter->params.cm_enabled ) + info = p_adapter->params.sq_depth + * p_adapter->params.cm_xfer_block_size; + else + info = p_adapter->params.sq_depth + * p_adapter->params.xfer_block_size; + break; + + case OID_GEN_RECEIVE_BUFFER_SPACE: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_TRANSMIT_BUFFER_SPACE " + "or OID_GEN_RECEIVE_BUFFER_SPACE\n", port_num) ); + if( p_adapter->params.cm_enabled ) + info = p_adapter->params.rq_depth + * p_adapter->params.cm_xfer_block_size; + else + info = p_adapter->params.rq_depth + * p_adapter->params.xfer_block_size; + break; + + case OID_GEN_MAXIMUM_LOOKAHEAD: + case OID_GEN_CURRENT_LOOKAHEAD: + case OID_GEN_TRANSMIT_BLOCK_SIZE: + case OID_GEN_RECEIVE_BLOCK_SIZE: + case OID_GEN_MAXIMUM_TOTAL_SIZE: + if( p_adapter->params.cm_enabled ) + info = p_adapter->params.cm_xfer_block_size; + else + info = p_adapter->params.xfer_block_size; + + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for 1 of OID_GEN_MAXIMUM_LOOKAHEAD, " + "_CURRENT_LOOKAHEAD, " + "_TRANSMIT_BLOCK_SIZE, " + "_RECEIVE_BLOCK_SIZE, " + "_GEN_MAXIMUM_TOTAL_SIZE = %d\n", port_num, info) ); + break; + + case OID_GEN_VENDOR_ID: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_VENDOR_ID\n", port_num) ); + src_buf = (void*)VENDOR_ID; + buf_len = sizeof(VENDOR_ID); + break; + + case OID_GEN_VENDOR_DESCRIPTION: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_VENDOR_DESCRIPTION\n", + port_num) ); + src_buf = VENDOR_DESCRIPTION; + buf_len = sizeof(VENDOR_DESCRIPTION); + break; + + case OID_GEN_VENDOR_DRIVER_VERSION: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_VENDOR_DRIVER_VERSION\n", + port_num) ); + src_buf = &version; + buf_len = sizeof(version); + //TODO: Figure out what the right version is. + version = 1 << 8 | 1; + break; + + case OID_GEN_PHYSICAL_MEDIUM: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_PHYSICAL_MEDIUM\n", + port_num) ); + info = NdisPhysicalMediumUnspecified; + break; + + case OID_GEN_CURRENT_PACKET_FILTER: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_CURRENT_PACKET_FILTER\n", + port_num) ); + info = p_adapter->packet_filter; + break; + + case OID_GEN_DRIVER_VERSION: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_DRIVER_VERSION\n", + port_num) ); + src_buf = &version; + buf_len = sizeof(version); + version = MAJOR_NDIS_VERSION << 8 | MINOR_NDIS_VERSION; + break; + + case OID_GEN_MAC_OPTIONS: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_MAC_OPTIONS\n", port_num) ); + info = NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA | + NDIS_MAC_OPTION_TRANSFERS_NOT_PEND | + NDIS_MAC_OPTION_NO_LOOPBACK | + NDIS_MAC_OPTION_FULL_DUPLEX; + //TODO: Figure out if we will support priority and VLANs. + // NDIS_MAC_OPTION_8021P_PRIORITY; + //#ifdef NDIS51_MINIPORT + // info |= NDIS_MAC_OPTION_8021Q_VLAN; + //#endif + break; + + case OID_GEN_MEDIA_CONNECT_STATUS: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_MEDIA_CONNECT_STATUS\n", + port_num) ); + cl_obj_lock( &p_adapter->obj ); + switch( p_adapter->state ) + { + case IB_PNP_PORT_ADD: + case IB_PNP_PORT_INIT: + /* + * Delay reporting media state until we know whether the port is + * either up or down. + */ + p_adapter->pending_query = TRUE; + p_adapter->query_oid = oid_info; + p_adapter->query_oid.p_pending_oid = pNdisRequest; + + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d returning NDIS_STATUS_PENDING\n", port_num) ); + status = NDIS_STATUS_PENDING; + break; + + case IB_PNP_PORT_ACTIVE: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d returning NdisMediaStateConnected\n", port_num) ); + info = NdisMediaStateConnected; + break; + + case IB_PNP_PORT_REMOVE: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d returning NDIS_STATUS_NOT_ACCEPTED\n", port_num) ); + status = NDIS_STATUS_NOT_ACCEPTED; + break; + + default: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d returning NdisMediaStateDisconnected\n", port_num) ); + info = NdisMediaStateDisconnected; + } + cl_obj_unlock( &p_adapter->obj ); + break; + + case OID_GEN_MAXIMUM_SEND_PACKETS: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_MAXIMUM_SEND_PACKETS\n", + port_num) ); + info = MINIPORT_MAX_SEND_PACKETS; + break; + + /* Required General Statistics */ + case OID_GEN_STATISTICS: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_STATISTICS\n", port_num) ); + src_buf = NULL; + buf_len = sizeof(NDIS_STATISTICS_INFO); + if (oid_info.buf_len < buf_len) + { + break; + } + status = ipoib_get_gen_stat(p_adapter, &oid_info ); + break; + + case OID_GEN_XMIT_OK: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_XMIT_OK\n", port_num) ); + src_buf = NULL; + status = ipoib_get_send_stat( p_adapter, IP_STAT_SUCCESS, &oid_info ); + break; + + case OID_GEN_RCV_OK: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_RCV_OK\n", port_num) ); + src_buf = NULL; + status = ipoib_get_recv_stat( p_adapter, IP_STAT_SUCCESS, &oid_info ); + break; + + case OID_GEN_XMIT_ERROR: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_XMIT_ERROR\n", port_num) ); + src_buf = NULL; + status = ipoib_get_send_stat( p_adapter, IP_STAT_ERROR, &oid_info ); + break; + + case OID_GEN_RCV_ERROR: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_RCV_ERROR\n", port_num) ); + src_buf = NULL; + status = ipoib_get_recv_stat( p_adapter, IP_STAT_ERROR, &oid_info ); + break; + + case OID_GEN_RCV_NO_BUFFER: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_RCV_NO_BUFFER\n", port_num) ); + src_buf = NULL; + status = ipoib_get_recv_stat( p_adapter, IP_STAT_DROPPED, &oid_info ); + break; + + case OID_GEN_DIRECTED_BYTES_XMIT: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_DIRECTED_BYTES_XMIT\n", port_num) ); + src_buf = NULL; + status = ipoib_get_send_stat( p_adapter, IP_STAT_UCAST_BYTES, &oid_info ); + break; + + case OID_GEN_DIRECTED_FRAMES_XMIT: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_DIRECTED_FRAMES_XMIT\n", port_num) ); + src_buf = NULL; + status = ipoib_get_send_stat( p_adapter, IP_STAT_UCAST_FRAMES, &oid_info ); + break; + + case OID_GEN_MULTICAST_BYTES_XMIT: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_MULTICAST_BYTES_XMIT\n", port_num) ); + src_buf = NULL; + status = ipoib_get_send_stat( p_adapter, IP_STAT_MCAST_BYTES, &oid_info ); + break; + + case OID_GEN_MULTICAST_FRAMES_XMIT: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_MULTICAST_FRAMES_XMIT\n", port_num) ); + src_buf = NULL; + status = ipoib_get_send_stat( p_adapter, IP_STAT_MCAST_FRAMES, &oid_info ); + break; + + case OID_GEN_BROADCAST_BYTES_XMIT: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_BROADCAST_BYTES_XMIT\n", port_num) ); + src_buf = NULL; + status = ipoib_get_send_stat( p_adapter, IP_STAT_BCAST_BYTES, &oid_info ); + break; + + case OID_GEN_BROADCAST_FRAMES_XMIT: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_BROADCAST_FRAMES_XMIT\n", port_num) ); + src_buf = NULL; + status = ipoib_get_send_stat( p_adapter, IP_STAT_BCAST_FRAMES, &oid_info ); + break; + + case OID_GEN_DIRECTED_BYTES_RCV: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_DIRECTED_BYTES_RCV\n", port_num) ); + src_buf = NULL; + status = ipoib_get_recv_stat( p_adapter, IP_STAT_UCAST_BYTES, &oid_info ); + break; + + case OID_GEN_DIRECTED_FRAMES_RCV: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_DIRECTED_FRAMES_RCV\n", port_num) ); + src_buf = NULL; + status = ipoib_get_recv_stat( p_adapter, IP_STAT_UCAST_FRAMES, &oid_info ); + break; + + case OID_GEN_MULTICAST_BYTES_RCV: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_MULTICAST_BYTES_RCV\n", port_num) ); + src_buf = NULL; + status = ipoib_get_recv_stat( p_adapter, IP_STAT_MCAST_BYTES, &oid_info ); + break; + + case OID_GEN_MULTICAST_FRAMES_RCV: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_MULTICAST_FRAMES_RCV\n", port_num) ); + src_buf = NULL; + status = ipoib_get_recv_stat( p_adapter, IP_STAT_MCAST_FRAMES, &oid_info ); + break; + + case OID_GEN_BROADCAST_BYTES_RCV: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_BROADCAST_BYTES_RCV\n", port_num) ); + src_buf = NULL; + status = ipoib_get_recv_stat( p_adapter, IP_STAT_BCAST_BYTES, &oid_info ); + break; + + case OID_GEN_BROADCAST_FRAMES_RCV: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_BROADCAST_FRAMES_RCV\n", port_num) ); + src_buf = NULL; + status = ipoib_get_recv_stat( p_adapter, IP_STAT_BCAST_FRAMES, &oid_info ); + break; + + /* Required Ethernet operational characteristics */ + case OID_802_3_PERMANENT_ADDRESS: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_802_3_PERMANENT_ADDRESS\n", port_num) ); + src_buf = &p_adapter->mac; + buf_len = sizeof(p_adapter->mac); + break; + + case OID_802_3_CURRENT_ADDRESS: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_802_3_CURRENT_ADDRESS\n", port_num) ); + src_buf = &p_adapter->params.conf_mac; + buf_len = sizeof(p_adapter->params.conf_mac); + break; + + case OID_802_3_MULTICAST_LIST: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_802_3_MULTICAST_LIST\n", port_num) ); + src_buf = p_adapter->mcast_array; + buf_len = p_adapter->mcast_array_size * sizeof(mac_addr_t); + break; + + case OID_802_3_MAXIMUM_LIST_SIZE: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_802_3_MAXIMUM_LIST_SIZE\n", port_num) ); + info = MAX_MCAST; + break; + + case OID_802_3_MAC_OPTIONS: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_802_3_MAC_OPTIONS\n", port_num) ); + info = 0; + break; + + /* Required Ethernet stats */ + case OID_802_3_RCV_ERROR_ALIGNMENT: + case OID_802_3_XMIT_ONE_COLLISION: + case OID_802_3_XMIT_MORE_COLLISIONS: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_802_3_RCV_ERROR_ALIGNMENT or " + "OID_802_3_XMIT_ONE_COLLISION or " + "OID_802_3_XMIT_MORE_COLLISIONS\n", port_num) ); + info = 0; + break; + case OID_TCP_OFFLOAD_HARDWARE_CAPABILITIES: + buf_len = sizeof(NDIS_OFFLOAD); + if (buf_len < oid_info.buf_len) + { + *oid_info.p_bytes_needed = buf_len; + return NDIS_STATUS_BUFFER_TOO_SHORT; + } + + OffloadCapabilities(p_adapter, &offload); + src_buf = &offload; + break; + case OID_GEN_INTERRUPT_MODERATION: + InterruptModerationParam.Header.Type = NDIS_OBJECT_TYPE_DEFAULT; + InterruptModerationParam.Header.Revision = + NDIS_INTERRUPT_MODERATION_PARAMETERS_REVISION_1; + InterruptModerationParam.Header.Size = + NDIS_SIZEOF_INTERRUPT_MODERATION_PARAMETERS_REVISION_1; + InterruptModerationParam.Flags = + NDIS_INTERRUPT_MODERATION_CHANGE_NEEDS_RESET; + InterruptModerationParam.InterruptModeration = + NdisInterruptModerationNotSupported; + buf_len = sizeof(NDIS_INTERRUPT_MODERATION_PARAMETERS); + src_buf = (PVOID) &InterruptModerationParam; + break; + + /* Optional General */ + case OID_GEN_SUPPORTED_GUIDS: +#ifdef NDIS51_MINIPORT + case OID_GEN_VLAN_ID: +#endif + + /* Optional General Stats */ + case OID_GEN_RCV_CRC_ERROR: + case OID_GEN_TRANSMIT_QUEUE_LENGTH: + + /* Optional Ethernet Stats */ + case OID_802_3_XMIT_DEFERRED: + case OID_802_3_XMIT_MAX_COLLISIONS: + case OID_802_3_RCV_OVERRUN: + case OID_802_3_XMIT_UNDERRUN: + case OID_802_3_XMIT_HEARTBEAT_FAILURE: + case OID_802_3_XMIT_TIMES_CRS_LOST: + case OID_802_3_XMIT_LATE_COLLISIONS: + case OID_PNP_CAPABILITIES: + status = NDIS_STATUS_NOT_SUPPORTED; + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received an unsupported Optional oid of 0x%.8X!\n", + port_num, oid_info.oid) ); + break; + + case OID_GEN_PROTOCOL_OPTIONS: + case OID_GEN_NETWORK_LAYER_ADDRESSES: + case OID_GEN_TRANSPORT_HEADER_OFFSET: + case OID_PNP_ENABLE_WAKE_UP: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_GEN_PROTOCOL_OPTIONS or " + "OID_GEN_NETWORK_LAYER_ADDRESSES or " + "OID_GEN_TRANSPORT_HEADER_OFFSET OID_PNP_ENABLE_WAKE_UP\n", + port_num) ); + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Number of OID: 0x%.8X!\n", oid_info.oid) ); + status = NDIS_STATUS_SUCCESS; + break; + + case OID_PNP_QUERY_POWER: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_TCP_TASK_OFFLOAD\n", port_num) ); + // Status is pre-set in this routine to Success + status = NDIS_STATUS_SUCCESS; + break; + + case OID_TCP_OFFLOAD_CURRENT_CONFIG: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for OID_TCP_OFFLOAD_CURRENT_CONFIG\n", + port_num) ); + //ulBytesAvailable = ulInfoLen = sizeof(NDIS_OFFLOAD); + if (oid_info.buf_len < sizeof(NDIS_OFFLOAD)) + { + + *oid_info.p_bytes_needed = sizeof(NDIS_OFFLOAD) ; + return NDIS_STATUS_BUFFER_TOO_SHORT; + } + + OffloadConfig( p_adapter, &offload); + src_buf = &offload; + break; + + case OID_IP6_OFFLOAD_STATS: + case OID_IP4_OFFLOAD_STATS: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query for UNSUPPORTED " + "OID_IP[4,6]_OFFLOAD_STATS\n", port_num) ); + status = NDIS_STATUS_NOT_SUPPORTED; + break; + + case OID_GEN_MACHINE_NAME: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received query OID_GEN_MACHINE_NAME\n", port_num) ); + status = NDIS_STATUS_NOT_SUPPORTED; + break; + + default: + status = NDIS_STATUS_INVALID_OID; + IPOIB_PRINT( TRACE_LEVEL_ERROR,IPOIB_DBG_ERROR, + ("Port %d received an invalid oid of 0x%.8X!\n", + port_num, oid_info.oid) ); + break; + } + + /* + * Complete the request as if it was handled asynchronously to maximize + * code reuse for when we really handle the requests asynchronously. + * Note that this requires the QueryInformation entry point to always + * return NDIS_STATUS_PENDING + */ + if( status != NDIS_STATUS_PENDING ) + { + return ipoib_complete_query( p_adapter, + &oid_info, + status, + src_buf, + buf_len ); + } + + IPOIB_EXIT( IPOIB_DBG_OID ); + return NDIS_STATUS_PENDING; +} + + +static NDIS_STATUS +ipoib_complete_query( + IN ipoib_adapter_t* const p_adapter, + IN pending_oid_t* const p_oid_info, + IN const NDIS_STATUS status, + IN const void* const p_buf, + IN const ULONG buf_len ) +{ + NDIS_STATUS oid_status = status; + + IPOIB_ENTER( IPOIB_DBG_OID ); + + CL_ASSERT( status != NDIS_STATUS_PENDING ); + + if( status == NDIS_STATUS_SUCCESS ) + { + if( p_oid_info->buf_len < buf_len ) + { + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Insufficient buffer space. " + "Returning NDIS_STATUS_INVALID_LENGTH.\n") ); + //oid_status = NDIS_STATUS_INVALID_LENGTH; + oid_status = NDIS_STATUS_BUFFER_TOO_SHORT; + *p_oid_info->p_bytes_needed = buf_len; + *p_oid_info->p_bytes_used = 0; + } + else if( p_oid_info->p_buf ) + { + /* Only copy if we have a distinct source buffer. */ + if( p_buf ) + { + NdisMoveMemory( p_oid_info->p_buf, p_buf, buf_len ); + *p_oid_info->p_bytes_used = buf_len; + } + } + else + { + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Returning NDIS_NOT_ACCEPTED") ); + oid_status = NDIS_STATUS_NOT_ACCEPTED; + } + } + else + { + *p_oid_info->p_bytes_used = 0; + } + + if (p_adapter->query_oid.p_pending_oid) + { + NdisMOidRequestComplete(p_adapter->h_adapter,p_adapter->query_oid.p_pending_oid,oid_status); + p_adapter->query_oid.p_pending_oid = NULL; + } + p_adapter->pending_query = FALSE; + IPOIB_EXIT( IPOIB_DBG_OID ); + return oid_status; +} + +static +NDIS_STATUS +SetOffloadEncapsulation( + void* const pBuf, + ULONG len + ) +{ + ASSERT(pBuf != NULL); + + PNDIS_OFFLOAD_ENCAPSULATION pOffload; + PNDIS_OBJECT_HEADER pOffloadHeader; + + if (len != sizeof(NDIS_OFFLOAD_ENCAPSULATION)) + { + ASSERT(FALSE); + IPOIB_PRINT(TRACE_LEVEL_ERROR, IPOIB_DBG_OID, ("Buffer is too small. offloading task requirs %d but the buffer size is: %d \n", sizeof(NDIS_OFFLOAD_ENCAPSULATION), len)); + return NDIS_STATUS_INVALID_DATA; + } + + pOffload= (PNDIS_OFFLOAD_ENCAPSULATION) pBuf; + pOffloadHeader = &(pOffload->Header); + + if((pOffloadHeader->Type != NDIS_OBJECT_TYPE_OFFLOAD_ENCAPSULATION) || + (pOffloadHeader->Revision != NDIS_OFFLOAD_ENCAPSULATION_REVISION_1) || + (pOffloadHeader->Size != NDIS_SIZEOF_OFFLOAD_ENCAPSULATION_REVISION_1)) + { + ASSERT(FALSE); + IPOIB_PRINT(TRACE_LEVEL_ERROR, IPOIB_DBG_OID, ("Set offloading task Illegal header\n")); + return NDIS_STATUS_INVALID_DATA; + } + + // + // BUGBUG: Need to handle the offload parameter setting + // + return NDIS_STATUS_SUCCESS; +} + + +//! Issues a hardware reset to the NIC and/or resets the driver's software state. +/* Tear down the connection and start over again. This is only called when there is a problem. +For example, if a send, query info, or set info had a time out. MiniportCheckForHang will +be called first. +IRQL = DISPATCH_LEVEL + +@param p_addr_resetPointer to BOOLLEAN that is set to TRUE if the NDIS +library should call MiniportSetInformation to restore addressing information to the current values. +@param adapter_context The adapter context allocated at start +@return NDIS_STATUS_SUCCESS, NDIS_STATUS_PENDING, NDIS_STATUS_NOT_RESETTABLE, +NDIS_STATUS_RESET_IN_PROGRESS, NDIS_STATUS_SOFT_ERRORS, NDIS_STATUS_HARD_ERRORS +*/ +NDIS_STATUS +ipoib_reset( + IN NDIS_HANDLE adapter_context, + OUT PBOOLEAN p_addr_reset) +{ + ipoib_adapter_t* p_adapter; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + CL_ASSERT( p_addr_reset ); + CL_ASSERT( adapter_context ); + p_adapter = (ipoib_adapter_t*)adapter_context; + + switch( ipoib_reset_adapter( p_adapter ) ) + { + case IB_NOT_DONE: + IPOIB_EXIT( IPOIB_DBG_INIT ); + return NDIS_STATUS_PENDING; + + case IB_SUCCESS: + IPOIB_EXIT( IPOIB_DBG_INIT ); + *p_addr_reset = TRUE; + return NDIS_STATUS_SUCCESS; + + case IB_INVALID_STATE: + IPOIB_EXIT( IPOIB_DBG_INIT ); + return NDIS_STATUS_RESET_IN_PROGRESS; + + default: + IPOIB_EXIT( IPOIB_DBG_INIT ); + return NDIS_STATUS_HARD_ERRORS; + } +} + + +//! Request changes in the state information that the miniport driver maintains +/* For example, this is used to set multicast addresses and the packet filter. +IRQL = DISPATCH_LEVEL + +@param adapter_context The adapter context allocated at start +@param oid Object ID representing the set operation to be carried out +@param info_buf Buffer containing input for this set and location for any output +@param info_buf_len Number of bytes available in info_buf +@param p_bytes_read Pointer to number of bytes read from info_buf +@param p_bytes_needed Pointer to number of bytes needed to satisfy this oid +@return NDIS_STATUS_SUCCESS, NDIS_STATUS_PENDING, NDIS_STATUS_INVALID_OID, +NDIS_STATUS_INVALID_LENGTH, NDIS_STATUS_INVALID_DATA, NDIS_STATUS_NOT_ACCEPTED, +NDIS_STATUS_NOT_SUPPORTED, NDIS_STATUS_RESOURCES +*/ +NDIS_STATUS +ipoib_set_info( + IN NDIS_HANDLE adapter_context, + IN OUT PNDIS_OID_REQUEST pNdisRequest) + +{ + ipoib_adapter_t* p_adapter; + NDIS_STATUS status; + + ULONG buf_len; + uint8_t port_num; + + KLOCK_QUEUE_HANDLE hdl; + + IPOIB_ENTER( IPOIB_DBG_OID ); + + CL_ASSERT( adapter_context ); + p_adapter = (ipoib_adapter_t*)adapter_context; + + NDIS_OID oid = pNdisRequest->DATA.SET_INFORMATION.Oid; + PVOID info_buf = pNdisRequest->DATA.SET_INFORMATION.InformationBuffer; + UINT info_buf_len = pNdisRequest->DATA.SET_INFORMATION.InformationBufferLength; + PULONG p_bytes_read = (PULONG)&pNdisRequest->DATA.SET_INFORMATION.BytesRead; + PULONG p_bytes_needed = (PULONG)&pNdisRequest->DATA.SET_INFORMATION.BytesNeeded; + + CL_ASSERT( p_bytes_read ); + CL_ASSERT( p_bytes_needed ); + CL_ASSERT( !p_adapter->pending_set ); + + status = NDIS_STATUS_SUCCESS; + *p_bytes_needed = 0; + buf_len = sizeof(ULONG); + + port_num = p_adapter->guids.port_num; + + cl_obj_lock( &p_adapter->obj ); + + if( p_adapter->state == IB_PNP_PORT_REMOVE ) + { + *p_bytes_read = 0; + cl_obj_unlock( &p_adapter->obj ); + return NDIS_STATUS_NOT_ACCEPTED; + } + + cl_obj_unlock( &p_adapter->obj ); + + switch( oid ) + { + /* Required General */ + case OID_GEN_CURRENT_PACKET_FILTER: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received set for OID_GEN_CURRENT_PACKET_FILTER\n", port_num)); + if( info_buf_len < sizeof(p_adapter->packet_filter) ) + { + status = NDIS_STATUS_INVALID_LENGTH; + } + else if( !info_buf ) + { + status = NDIS_STATUS_INVALID_DATA; + } + else + { + KeAcquireInStackQueuedSpinLock( &g_ipoib.lock, &hdl ); + cl_obj_lock( &p_adapter->obj ); + switch( p_adapter->state ) + { + case IB_PNP_PORT_ADD: + p_adapter->set_oid.oid = oid; + p_adapter->set_oid.p_buf = info_buf; + p_adapter->set_oid.buf_len = info_buf_len; + p_adapter->set_oid.p_bytes_used = p_bytes_read; + p_adapter->set_oid.p_bytes_needed = p_bytes_needed; + p_adapter->set_oid.p_pending_oid = pNdisRequest; + p_adapter->pending_set = TRUE; + status = NDIS_STATUS_PENDING; + break; + + case IB_PNP_PORT_REMOVE: + status = NDIS_STATUS_NOT_ACCEPTED; + break; + + default: + if( !p_adapter->packet_filter && (*(uint32_t*)info_buf) ) + { + cl_qlist_insert_tail( + &g_ipoib.adapter_list, &p_adapter->entry ); + + /* + * Filter was zero, now non-zero. Register IP addresses + * with SA. + */ + ipoib_reg_addrs( p_adapter ); + } + else if( p_adapter->packet_filter && !(*(uint32_t*)info_buf) ) + { + /* + * Filter was non-zero, now zero. Deregister IP addresses. + */ + ipoib_dereg_addrs( p_adapter ); + + ASSERT( cl_qlist_count( &g_ipoib.adapter_list ) ); + cl_qlist_remove_item( + &g_ipoib.adapter_list, &p_adapter->entry ); + } + + p_adapter->packet_filter = *(uint32_t*)info_buf; + } + cl_obj_unlock( &p_adapter->obj ); + KeReleaseInStackQueuedSpinLock( &hdl ); + } + break; + + case OID_GEN_CURRENT_LOOKAHEAD: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received set for OID_GEN_CURRENT_LOOKAHEAD\n", port_num)); + if( info_buf_len < buf_len ) + status = NDIS_STATUS_INVALID_LENGTH; + break; + + case OID_GEN_PROTOCOL_OPTIONS: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received set for OID_GEN_PROTOCOL_OPTIONS\n", port_num)); + if( info_buf_len < buf_len ) + status = NDIS_STATUS_INVALID_LENGTH; + break; + + case OID_GEN_NETWORK_LAYER_ADDRESSES: + status = __ipoib_set_net_addr( p_adapter, info_buf, info_buf_len, p_bytes_read, p_bytes_needed); + break; + +#ifdef NDIS51_MINIPORT + case OID_GEN_MACHINE_NAME: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_OID, + ("Port %d received set for OID_GEN_MACHINE_NAME\n", port_num) ); + break; +#endif + + /* Required Ethernet operational characteristics */ + case OID_802_3_MULTICAST_LIST: + IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_OID, + ("Port %d received set for OID_802_3_MULTICAST_LIST\n", port_num) ); + if( info_buf_len > MAX_MCAST * sizeof(mac_addr_t) ) + { + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d OID_802_3_MULTICAST_LIST - Multicast list full.\n", port_num) ); + status = NDIS_STATUS_MULTICAST_FULL; + *p_bytes_needed = MAX_MCAST * sizeof(mac_addr_t); + } + else if( info_buf_len % sizeof(mac_addr_t) ) + { + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d OID_802_3_MULTICAST_LIST - Invalid input buffer.\n", port_num) ); + status = NDIS_STATUS_INVALID_DATA; + } + else if( !info_buf && info_buf_len ) + { + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d OID_802_3_MULTICAST_LIST - Invalid input buffer.\n", port_num) ); + status = NDIS_STATUS_INVALID_DATA; + } + else + { + ipoib_refresh_mcast( p_adapter, + (mac_addr_t*)info_buf, + (uint8_t)(info_buf_len / sizeof(mac_addr_t)) ); + + buf_len = info_buf_len; + /* + * Note that we don't return pending. It will likely take longer + * for our SA transactions to complete than NDIS will give us + * before reseting the adapter. If an SA failure is encountered, + * the adapter will be marked as hung and we will get reset. + */ + status = NDIS_STATUS_SUCCESS; + } + break; + + case OID_TCP_TASK_OFFLOAD: + ASSERT (FALSE); + IPOIB_PRINT( TRACE_LEVEL_ERROR,IPOIB_DBG_ERROR, + ("Port %d received set for OID_TCP_TASK_OFFLOAD\n", port_num) ); + + buf_len = info_buf_len; + //status = + // __ipoib_set_tcp_task_offload( p_adapter, info_buf, &buf_len ); + break; + + + case OID_TCP_OFFLOAD_PARAMETERS: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received set for OID_TCP_OFFLOAD_PARAMETERS\n", port_num) ); + buf_len = info_buf_len; + status = SetOffloadParameters(p_adapter, info_buf, info_buf_len); + break; + + /* Optional General */ + case OID_GEN_TRANSPORT_HEADER_OFFSET: +#ifdef NDIS51_MINIPORT + case OID_GEN_RNDIS_CONFIG_PARAMETER: + case OID_GEN_VLAN_ID: +#endif + status = NDIS_STATUS_NOT_SUPPORTED; + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received an unsupported oid of 0x%.8X!\n", port_num, oid)); + break; + + case OID_GEN_INTERRUPT_MODERATION: + status = SetInterruptModeration(info_buf, info_buf_len); + break; + + case OID_OFFLOAD_ENCAPSULATION: + status = SetOffloadEncapsulation(info_buf, info_buf_len); + break; + + + case OID_GEN_SUPPORTED_LIST: + //case OID_GEN_HARDWARE_STATUS: + case OID_GEN_MEDIA_SUPPORTED: + case OID_GEN_MEDIA_IN_USE: + case OID_GEN_MAXIMUM_FRAME_SIZE: + case OID_GEN_LINK_SPEED: + case OID_GEN_TRANSMIT_BUFFER_SPACE: + case OID_GEN_RECEIVE_BUFFER_SPACE: + case OID_GEN_MAXIMUM_LOOKAHEAD: + case OID_GEN_TRANSMIT_BLOCK_SIZE: + case OID_GEN_RECEIVE_BLOCK_SIZE: + case OID_GEN_MAXIMUM_TOTAL_SIZE: + case OID_GEN_VENDOR_ID: + case OID_GEN_VENDOR_DESCRIPTION: + case OID_GEN_VENDOR_DRIVER_VERSION: + case OID_GEN_DRIVER_VERSION: + case OID_GEN_MAC_OPTIONS: + case OID_GEN_MEDIA_CONNECT_STATUS: + case OID_GEN_MAXIMUM_SEND_PACKETS: + case OID_GEN_SUPPORTED_GUIDS: + case OID_GEN_PHYSICAL_MEDIUM: + + default: + status = NDIS_STATUS_INVALID_OID; + IPOIB_PRINT( TRACE_LEVEL_ERROR,IPOIB_DBG_ERROR, + ("Port %d received an invalid oid of 0x%.8X!\n", port_num, oid)); + break; + } + + if( status == NDIS_STATUS_SUCCESS ) + { + *p_bytes_read = buf_len; + } + else + { + if( status == NDIS_STATUS_INVALID_LENGTH ) + { + if ( !*p_bytes_needed ) + { + *p_bytes_needed = buf_len; + } + } + + *p_bytes_read = 0; + } + + IPOIB_EXIT( IPOIB_DBG_OID ); + return status; +} + + +static NDIS_STATUS +ipoib_oid_handler( + IN NDIS_HANDLE adapter_context, + IN OUT PNDIS_OID_REQUEST pNdisRequest) +{ + NDIS_REQUEST_TYPE RequestType; + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + + IPOIB_ENTER( IPOIB_DBG_OID ); + + RequestType = pNdisRequest->RequestType; + + switch(RequestType) + { + case NdisRequestSetInformation: + status = ipoib_set_info(adapter_context, pNdisRequest); + break; + + case NdisRequestQueryInformation: + case NdisRequestQueryStatistics: + status = ipoib_query_info(adapter_context, pNdisRequest); + + break; + + default: + status = NDIS_STATUS_NOT_SUPPORTED; + break; + } + IPOIB_EXIT( IPOIB_DBG_OID ); + return status; +} + +/* Transfers some number of packets, specified as an array of packet pointers, + * over the network. + * For a deserialized driver, these packets are completed asynchronously + * using NdisMSendComplete. + * IRQL <= DISPATCH_LEVEL + + @param adapter_context - Pointer to ipoib_adapter_t structure with per NIC state + @param net_buffer_list - Array of packets to send + @param port_num - miniport number. + @param send_flags - NDIS send flags. +*/ +void +ipoib_send_net_buffer_list( + IN NDIS_HANDLE adapter_context, + IN PNET_BUFFER_LIST net_buffer_list, + IN NDIS_PORT_NUMBER port_num, + IN ULONG send_flags ) +{ + ipoib_adapter_t *p_adapter; + ipoib_port_t *p_port; + ULONG send_complete_flags; + PNET_BUFFER_LIST curr_net_buffer_list; + PNET_BUFFER_LIST next_net_buffer_list; + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + + UNREFERENCED_PARAMETER(port_num); + PERF_DECLARE( SendPackets ); + PERF_DECLARE( PortSend ); + + IPOIB_ENTER( IPOIB_DBG_SEND ); + cl_perf_start( SendPackets ); + + CL_ASSERT( adapter_context ); + p_adapter = (ipoib_adapter_t*)adapter_context; + + cl_obj_lock( &p_adapter->obj ); + if( p_adapter->ipoib_state == IPOIB_PAUSING || + p_adapter->ipoib_state == IPOIB_PAUSED) + { + status = NDIS_STATUS_PAUSED; + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Got send during PAUSE, complete with error \n") ); + cl_obj_unlock( &p_adapter->obj ); + goto compl_status; + } + + if( p_adapter->state != IB_PNP_PORT_ACTIVE || !p_adapter->p_port ) + { + cl_obj_unlock( &p_adapter->obj ); + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Got send during port non-active, complete with error \n") ); + status = NDIS_STATUS_FAILURE; + goto compl_status; + } + + p_port = p_adapter->p_port; + ipoib_port_ref( p_port, ref_send_packets ); + cl_obj_unlock( &p_adapter->obj ); + + if (NET_BUFFER_LIST_NEXT_NBL(net_buffer_list) != NULL) { + cl_dbg_out("Recieved a list of NBLS ................\n"); + } + + for (curr_net_buffer_list = net_buffer_list; + curr_net_buffer_list != NULL; + curr_net_buffer_list = next_net_buffer_list) + { + + ++g_NBL; + ipoib_cnt_inc( &p_adapter->n_send_NBL ); + + next_net_buffer_list = NET_BUFFER_LIST_NEXT_NBL(curr_net_buffer_list); + KeMemoryBarrierWithoutFence(); + // Important issue, break the connection between the different nbls + NET_BUFFER_LIST_NEXT_NBL(curr_net_buffer_list) = NULL; + + cl_perf_start( PortSend ); + IPOIB_PRINT( TRACE_LEVEL_VERBOSE, IPOIB_DBG_BUF, + ("Sending NBL=%p, g_NBL=%d, g_NBL_completed=%d \n", + curr_net_buffer_list, g_NBL, g_NBL_complete) ); + + ipoib_port_send( p_port, curr_net_buffer_list, send_flags); + + cl_perf_stop( &p_adapter->perf, PortSend ); + } + ipoib_port_deref( p_port, ref_send_packets ); + + cl_perf_stop( &p_adapter->perf, SendPackets ); + + cl_perf_log( &p_adapter->perf, SendBundle, 1 ); + +compl_status: + if (status != NDIS_STATUS_SUCCESS) + { + + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Got bad status, g_NBL=%d, g_NBL_completed=%d \n", + g_NBL, g_NBL_complete) ); + send_complete_flags = 0; + + for (curr_net_buffer_list = net_buffer_list; + curr_net_buffer_list != NULL; + curr_net_buffer_list = next_net_buffer_list) + { + ++g_NBL; + ipoib_cnt_inc( &p_adapter->n_send_NBL ); + + next_net_buffer_list = NET_BUFFER_LIST_NEXT_NBL(curr_net_buffer_list); + NET_BUFFER_LIST_STATUS(curr_net_buffer_list) = status; + ipoib_inc_send_stat( p_adapter, IP_STAT_DROPPED, 0 ); + } + // Put attention, we complete here the LIST OF NBL at one shot + if (NDIS_TEST_SEND_AT_DISPATCH_LEVEL(send_flags)) + { + ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); + NDIS_SET_SEND_COMPLETE_FLAG(send_complete_flags, + NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL); + } + NdisMSendNetBufferListsCompleteX( p_adapter, + net_buffer_list, + send_complete_flags); + } + IPOIB_EXIT( IPOIB_DBG_SEND ); +} + + +void +ipoib_pnp_notify( + IN NDIS_HANDLE adapter_context, + IN PNET_DEVICE_PNP_EVENT pnp_event) +{ + ipoib_adapter_t *p_adapter; + + IPOIB_ENTER( IPOIB_DBG_PNP ); + + p_adapter = (ipoib_adapter_t*)adapter_context; + + IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_PNP, ("Event %d\n", pnp_event->DevicePnPEvent) ); + if( pnp_event->DevicePnPEvent != NdisDevicePnPEventPowerProfileChanged ) + { + cl_obj_lock( &p_adapter->obj ); + p_adapter->state = IB_PNP_PORT_REMOVE; + cl_obj_unlock( &p_adapter->obj ); + + ipoib_resume_oids( p_adapter ); + if ( p_adapter->p_stat ) + p_adapter->p_stat->n_pnp_irps++; + } + else + if ( p_adapter->p_stat ) + p_adapter->p_stat->n_power_irps++; + + IPOIB_EXIT( IPOIB_DBG_PNP ); +} + + +VOID +ipoib_shutdown_ex( + IN NDIS_HANDLE adapter_context, + IN NDIS_SHUTDOWN_ACTION shutdown_action) +{ + IPOIB_ENTER( IPOIB_DBG_INIT ) ; + UNUSED_PARAM( shutdown_action ); + + ipoib_adapter_t *p_adapter = (ipoib_adapter_t *) adapter_context; + + if (shutdown_action == NdisShutdownPowerOff ) { + ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); + // We need to wait only if this is not a blue screen any way + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, + ("Shutter shut, state = %d\n", p_adapter->ipoib_state)); + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_RECV, + ("Shutter shut, state = %d\n", p_adapter->ipoib_state)); + shutter_shut ( &p_adapter->recv_shutter ); + } + + IPOIB_EXIT( IPOIB_DBG_INIT ); +} + + +void +ipoib_resume_oids( + IN ipoib_adapter_t* const p_adapter ) +{ + ULONG info; + NDIS_STATUS status; + boolean_t pending_query, pending_set; + pending_oid_t query_oid = {0}; + pending_oid_t set_oid = {0}; + KLOCK_QUEUE_HANDLE hdl; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + cl_obj_lock( &p_adapter->obj ); + /* + * Set the status depending on our state. Fail OID requests that + * are pending while we reset the adapter. + */ + switch( p_adapter->state ) + { + case IB_PNP_PORT_ADD: + status = NDIS_STATUS_FAILURE; + break; + + case IB_PNP_PORT_REMOVE: + status = NDIS_STATUS_NOT_ACCEPTED; + break; + + default: + status = NDIS_STATUS_SUCCESS; + } + + pending_query = p_adapter->pending_query; + if( pending_query ) + { + query_oid = p_adapter->query_oid; + p_adapter->pending_query = FALSE; + } + pending_set = p_adapter->pending_set; + if( pending_set ) + { + set_oid = p_adapter->set_oid; + p_adapter->pending_set = FALSE; + } + cl_obj_unlock( &p_adapter->obj ); + + /* + * If we had a pending OID request for OID_GEN_LINK_SPEED, + * complete it now. Note that we hold the object lock since + * NdisMQueryInformationComplete is called at DISPATCH_LEVEL. + */ + if( pending_query ) + { + switch( query_oid.oid ) + { + case OID_GEN_LINK_SPEED: + ipoib_complete_query( p_adapter, &query_oid, + status, &p_adapter->port_rate, sizeof(p_adapter->port_rate) ); + break; + + case OID_GEN_MEDIA_CONNECT_STATUS: + info = NdisMediaStateConnected; + ipoib_complete_query( p_adapter, &query_oid, + status, &info, sizeof(info) ); + break; + + default: + CL_ASSERT( query_oid.oid == OID_GEN_LINK_SPEED || + query_oid.oid == OID_GEN_MEDIA_CONNECT_STATUS ); + break; + } + } + + if( pending_set ) + { + switch( set_oid.oid ) + { + case OID_GEN_CURRENT_PACKET_FILTER: + /* Validation already performed in the SetInformation path. */ + + KeAcquireInStackQueuedSpinLock( &g_ipoib.lock, &hdl ); + cl_obj_lock( &p_adapter->obj ); + if( !p_adapter->packet_filter && (*(PULONG)set_oid.p_buf) ) + { + cl_qlist_insert_tail( + &g_ipoib.adapter_list, &p_adapter->entry ); + /* + * Filter was zero, now non-zero. Register IP addresses + * with SA. + */ + ipoib_reg_addrs( p_adapter ); + } + else if( p_adapter->packet_filter && !(*(PULONG)set_oid.p_buf) ) + { + /* Filter was non-zero, now zero. Deregister IP addresses. */ + ipoib_dereg_addrs( p_adapter ); + + ASSERT( cl_qlist_count( &g_ipoib.adapter_list ) ); + cl_qlist_remove_item( + &g_ipoib.adapter_list, &p_adapter->entry ); + } + p_adapter->packet_filter = *(PULONG)set_oid.p_buf; + + cl_obj_unlock( &p_adapter->obj ); + KeReleaseInStackQueuedSpinLock( &hdl ); + p_adapter->set_oid.p_pending_oid = NULL; + NdisMOidRequestComplete( p_adapter->h_adapter, set_oid.p_pending_oid, status ); + break; + + case OID_GEN_NETWORK_LAYER_ADDRESSES: + status = __ipoib_set_net_addr( p_adapter, + p_adapter->set_oid.p_buf, + p_adapter->set_oid.buf_len, + p_adapter->set_oid.p_bytes_used, + p_adapter->set_oid.p_bytes_needed ); + + if( status != NDIS_STATUS_PENDING ) + { + p_adapter->set_oid.p_pending_oid = NULL; + NdisMOidRequestComplete( p_adapter->h_adapter, set_oid.p_pending_oid, status ); + } + break; + + default: + CL_ASSERT( set_oid.oid && 0 ); + break; + } + } + + IPOIB_EXIT( IPOIB_DBG_INIT ); +} + + +static NDIS_STATUS +__ipoib_set_net_addr( + IN ipoib_adapter_t * p_adapter, + IN PVOID info_buf, + IN ULONG info_buf_len, + OUT PULONG p_bytes_read, + OUT PULONG p_bytes_needed ) +{ + NDIS_STATUS status; + PNETWORK_ADDRESS_LIST p_net_addrs; + PNETWORK_ADDRESS p_net_addr_oid; + PNETWORK_ADDRESS_IP p_ip_addr; + + net_address_item_t *p_addr_item; + + cl_status_t cl_status; + + size_t idx; + LONG i; + ULONG addr_size; + ULONG total_size; + + uint8_t port_num; + + IPOIB_ENTER( IPOIB_DBG_OID ); + + status = NDIS_STATUS_SUCCESS; + port_num = p_adapter->guids.port_num; + + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d received set for OID_GEN_NETWORK_LAYER_ADDRESSES\n", + port_num) ); + + if( !info_buf ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Port %d - OID_GEN_NETWORK_LAYER_ADDRESSES - " + "NULL buffer\n", port_num) ); + IPOIB_EXIT( IPOIB_DBG_OID ); + return NDIS_STATUS_INVALID_DATA; + } + + /* + * Must use field offset because the structures define array's of size one + * of a the incorrect type for what is really stored. + */ + if( info_buf_len < FIELD_OFFSET(NETWORK_ADDRESS_LIST, Address) ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Port %d OID_GEN_NETWORK_LAYER_ADDRESSES - " + "bad length of %d, not enough " + "for NETWORK_ADDRESS_LIST (%d)\n", port_num, info_buf_len, + FIELD_OFFSET(NETWORK_ADDRESS_LIST, Address)) ); + *p_bytes_needed = FIELD_OFFSET(NETWORK_ADDRESS_LIST, Address); + IPOIB_EXIT( IPOIB_DBG_OID ); + return NDIS_STATUS_INVALID_LENGTH; + } + + p_net_addrs = (PNETWORK_ADDRESS_LIST)info_buf; + if( p_net_addrs->AddressCount == 0) + { + if( p_net_addrs->AddressType == NDIS_PROTOCOL_ID_TCP_IP ) + { + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_OID, + ("Port %d OID_GEN_NETWORK_LAYER_ADDRESSES - " + "clear TCP/IP addresses\n", port_num) ); + } + else + { + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_OID, + ("Port %d OID_GEN_NETWORK_LAYER_ADDRESSES - " + "Non TCP/IP address type of 0x%.4X on clear\n", + port_num, p_net_addrs->AddressType) ); + IPOIB_EXIT( IPOIB_DBG_OID ); + return NDIS_STATUS_SUCCESS; + } + } + + addr_size = FIELD_OFFSET(NETWORK_ADDRESS, Address) + + NETWORK_ADDRESS_LENGTH_IP; + total_size = FIELD_OFFSET(NETWORK_ADDRESS_LIST, Address) + + addr_size * p_net_addrs->AddressCount; + + if( info_buf_len < total_size ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Port %d OID_GEN_NETWORK_LAYER_ADDRESSES - " + "bad length of %d, %d required for %d addresses\n", + port_num, info_buf_len, total_size, p_net_addrs->AddressCount) ); + *p_bytes_needed = total_size; + IPOIB_EXIT( IPOIB_DBG_OID ); + return NDIS_STATUS_INVALID_LENGTH; + } + + /* Lock lists for duration since SA callbacks can occur on other CPUs */ + cl_obj_lock( &p_adapter->obj ); + + /* Set the capacity of the vector to accomodate all assinged addresses. */ + cl_status = cl_vector_set_capacity( + &p_adapter->ip_vector, p_net_addrs->AddressCount ); + if( cl_status != CL_SUCCESS ) + { + cl_obj_unlock( &p_adapter->obj ); + IPOIB_PRINT(TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Port %d - OID_GEN_NETWORK_LAYER_ADDRESSES - " + "Failed to set IP vector capacity: %#x\n", port_num, + cl_status) ); + IPOIB_EXIT( IPOIB_DBG_OID ); + return NDIS_STATUS_RESOURCES; + } + + *p_bytes_read = total_size; + + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d OID_GEN_NETWORK_LAYER_ADDRESSES - List contains %d addresses\n", + port_num, p_net_addrs->AddressCount)); + + /* First look for addresses we had that should be removed */ + for( idx = 0; idx != cl_vector_get_size( &p_adapter->ip_vector ); idx++ ) + { + p_addr_item = (net_address_item_t*) + cl_vector_get_ptr( &p_adapter->ip_vector, idx ); + p_net_addr_oid = (PNETWORK_ADDRESS)p_net_addrs->Address; + + for( i = 0; i < p_net_addrs->AddressCount; ++i ) + { + // Here we check that the data stored at 'AddressLength' field is valid; + // otherwise, it can lead to a memory violation (happened when AddressCount was > 1) + if( p_net_addr_oid->AddressLength != NETWORK_ADDRESS_LENGTH_IP) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Port %d OID_GEN_NETWORK_LAYER_ADDRESSES - Address %d is wrong size of %d, " + "should be %d\n", port_num, i, p_net_addr_oid->AddressLength, + NETWORK_ADDRESS_LENGTH_IP)); + ASSERT ( p_net_addr_oid->AddressLength == NETWORK_ADDRESS_LENGTH_IPX ); + break; + } + + ASSERT( p_net_addr_oid->AddressType == NDIS_PROTOCOL_ID_TCP_IP ); + + p_ip_addr = (PNETWORK_ADDRESS_IP)p_net_addr_oid->Address; + if( !cl_memcmp( &p_ip_addr->in_addr, + &p_addr_item->address.as_ulong, sizeof(ULONG) ) ) + { + break; + } + p_net_addr_oid = (PNETWORK_ADDRESS)((uint8_t *)p_net_addr_oid + + FIELD_OFFSET(NETWORK_ADDRESS, Address) + + p_net_addr_oid->AddressLength) ; + } + + if( i == p_net_addrs->AddressCount ) + { + /* Didn't find a match, delete from SA */ + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d OID_GEN_NETWORK_LAYER_ADDRESSES - Deleting Address %d.%d.%d.%d\n", + port_num, + p_addr_item->address.as_bytes[0], + p_addr_item->address.as_bytes[1], + p_addr_item->address.as_bytes[2], + p_addr_item->address.as_bytes[3])); + + if( p_addr_item->p_reg ) + { + if( p_addr_item->p_reg->h_reg_svc ) + { + p_adapter->p_ifc->dereg_svc( + p_addr_item->p_reg->h_reg_svc, __ipoib_ats_dereg_cb ); + } + else + { + cl_free( p_addr_item->p_reg ); + } + p_addr_item->p_reg = NULL; + } + p_addr_item->address.as_ulong = 0; + } + } + + /* Now look for new addresses */ + p_net_addr_oid = (NETWORK_ADDRESS *)p_net_addrs->Address; + idx = 0; + + for( i = 0; i < p_net_addrs->AddressCount; ++i ) + { + + // Here we check that the data stored at 'AddressLength' field is valid; + // otherwise, it can lead to a memory violation (happened when AddressCount was > 1) + if( p_net_addr_oid->AddressLength != NETWORK_ADDRESS_LENGTH_IP) + { + IPOIB_PRINT(TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Port %d OID_GEN_NETWORK_LAYER_ADDRESSES - Address %d is wrong size of %d, " + "should be %d\n", port_num, i, p_net_addr_oid->AddressLength, + NETWORK_ADDRESS_LENGTH_IP)); + ASSERT ( p_net_addr_oid->AddressLength == NETWORK_ADDRESS_LENGTH_IPX ); + break; + + } + + ASSERT( p_net_addr_oid->AddressType == NDIS_PROTOCOL_ID_TCP_IP ); + + p_ip_addr = (PNETWORK_ADDRESS_IP)p_net_addr_oid->Address; + + /* Size the vector as needed. */ + if( cl_vector_get_size( &p_adapter->ip_vector ) <= idx ) + cl_vector_set_size( &p_adapter->ip_vector, idx + 1 ); + + p_addr_item = (net_address_item_t *) cl_vector_get_ptr( &p_adapter->ip_vector, idx ); + if( !cl_memcmp( &p_ip_addr->in_addr, &p_addr_item->address.as_ulong, + sizeof(ULONG) ) ) + { + idx++; + /* Already have this address - no change needed */ + continue; + } + + /* + * Copy the address information, but don't register yet - the port + * could be down. + */ + if( p_addr_item->p_reg ) + { + /* If in use by some other address, deregister. */ + if( p_addr_item->p_reg->h_reg_svc ) + { + p_adapter->p_ifc->dereg_svc( + p_addr_item->p_reg->h_reg_svc, __ipoib_ats_dereg_cb ); + } + else + { + cl_free( p_addr_item->p_reg ); + } + p_addr_item->p_reg = NULL; + } + memcpy ((void *)&p_addr_item->address.as_ulong, (const void *)&p_ip_addr->in_addr, sizeof(ULONG) ); + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d OID_GEN_NETWORK_LAYER_ADDRESSES - Adding Address %d.%d.%d.%d\n", + port_num, + p_addr_item->address.as_bytes[0], + p_addr_item->address.as_bytes[1], + p_addr_item->address.as_bytes[2], + p_addr_item->address.as_bytes[3]) ); + idx++; + p_net_addr_oid = (PNETWORK_ADDRESS)((uint8_t *)p_net_addr_oid + + FIELD_OFFSET(NETWORK_ADDRESS, Address) + + p_net_addr_oid->AddressLength) ; + } + + /* Now clear any extra entries that shouldn't be there. */ + while( idx < cl_vector_get_size( &p_adapter->ip_vector ) ) + { + p_addr_item = (net_address_item_t*) + cl_vector_get_ptr( &p_adapter->ip_vector, + cl_vector_get_size( &p_adapter->ip_vector ) - 1 ); + + if( p_addr_item->p_reg ) + { + if( p_addr_item->p_reg->h_reg_svc ) + { + p_adapter->p_ifc->dereg_svc( + p_addr_item->p_reg->h_reg_svc, __ipoib_ats_dereg_cb ); + } + else + { + cl_free( p_addr_item->p_reg ); + } + p_addr_item->p_reg = NULL; + p_addr_item->address.as_ulong = 0; + } + + /* No need to check return value - shrinking always succeeds. */ + cl_vector_set_size( &p_adapter->ip_vector, + cl_vector_get_size( &p_adapter->ip_vector ) - 1 ); + } + + if( p_adapter->state == IB_PNP_PORT_ACTIVE && p_adapter->packet_filter ) + ipoib_reg_addrs( p_adapter ); + + cl_obj_unlock( &p_adapter->obj ); + + IPOIB_EXIT( IPOIB_DBG_OID ); + return NDIS_STATUS_SUCCESS; +} + + +/* Object lock is held when this function is called. */ +void +ipoib_reg_addrs( + IN ipoib_adapter_t* const p_adapter ) +{ + net_address_item_t *p_addr_item; + + size_t idx; + + uint8_t port_num; + + ib_api_status_t ib_status; + ib_reg_svc_req_t ib_service; + ib_gid_t port_gid; + + IPOIB_ENTER( IPOIB_DBG_OID ); + + if(p_adapter->guids.port_guid.pkey != IB_DEFAULT_PKEY) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR,IPOIB_DBG_ERROR, + ("ATS Service available for default pkey only\n")); + return; + } + port_num = p_adapter->guids.port_num; + + /* Setup our service call with things common to all calls */ + cl_memset( &ib_service, 0, sizeof(ib_service) ); + + /* BUGBUG Only register local subnet GID prefix for now */ + ib_gid_set_default( &port_gid, p_adapter->guids.port_guid.guid ); + ib_service.svc_rec.service_gid = port_gid; + + ib_service.svc_rec.service_pkey = IB_DEFAULT_PKEY; + ib_service.svc_rec.service_lease = IB_INFINITE_SERVICE_LEASE; + + /* Must cast here because the service name is an array of unsigned chars but + * strcpy want a pointer to a signed char */ + if ( StringCchCopy( (char *)ib_service.svc_rec.service_name, + sizeof(ib_service.svc_rec.service_name) / sizeof(char), ATS_NAME ) != S_OK) { + ASSERT(FALSE); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR,IPOIB_DBG_ERROR, + ("Problem copying ATS name: exiting\n")); + return; + } + + /* IP Address in question will be put in below */ + ib_service.port_guid = p_adapter->guids.port_guid.guid; + ib_service.timeout_ms = p_adapter->params.sa_timeout; + ib_service.retry_cnt = p_adapter->params.sa_retry_cnt; + + /* Can't set IB_FLAGS_SYNC here because I can't wait at dispatch */ + ib_service.flags = 0; + + /* Service context will be put in below */ + + ib_service.svc_data_mask = IB_SR_COMPMASK_SID | + IB_SR_COMPMASK_SGID | + IB_SR_COMPMASK_SPKEY | + IB_SR_COMPMASK_SLEASE | + IB_SR_COMPMASK_SNAME | + IB_SR_COMPMASK_SDATA8_12 | + IB_SR_COMPMASK_SDATA8_13 | + IB_SR_COMPMASK_SDATA8_14 | + IB_SR_COMPMASK_SDATA8_15; + ib_service.pfn_reg_svc_cb = __ipoib_ats_reg_cb; + + for( idx = 0; idx < cl_vector_get_size( &p_adapter->ip_vector); idx++ ) + { + p_addr_item = (net_address_item_t*) + cl_vector_get_ptr( &p_adapter->ip_vector, idx ); + + if( p_addr_item->p_reg ) + continue; + + p_addr_item->p_reg = (ats_reg_t *) cl_zalloc( sizeof(ats_reg_t) ); + if( !p_addr_item->p_reg ) + break; + + p_addr_item->p_reg->p_adapter = p_adapter; + + ib_service.svc_context = p_addr_item->p_reg; + + ib_service.svc_rec.service_id = + ATS_SERVICE_ID & CL_HTON64(0xFFFFFFFFFFFFFF00); + /* ATS service IDs start at 0x10000CE100415453 */ + ib_service.svc_rec.service_id |= ((uint64_t)(idx + 0x53)) << 56; + + cl_memcpy( &ib_service.svc_rec.service_data8[ATS_IPV4_OFFSET], + p_addr_item->address.as_bytes, IPV4_ADDR_SIZE ); + + /* Take a reference for each service request. */ + cl_obj_ref(&p_adapter->obj); + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_OBJ, + ("[%p] Adapter refcount raised to %d\n", + p_adapter, p_adapter->obj.ref_cnt)); + ib_status = p_adapter->p_ifc->reg_svc( + p_adapter->h_al, &ib_service, &p_addr_item->p_reg->h_reg_svc ); + if( ib_status != IB_SUCCESS ) + { + if( ib_status == IB_INVALID_GUID ) + { + /* If this occurs, we log the error but do not fail the OID yet */ + IPOIB_PRINT( TRACE_LEVEL_WARNING, IPOIB_DBG_OID, + ("Port %d OID_GEN_NETWORK_LAYER_ADDRESSES - " + "Failed to register IP Address " + "of %d.%d.%d.%d with error IB_INVALID_GUID\n", + port_num, + p_addr_item->address.as_bytes[0], + p_addr_item->address.as_bytes[1], + p_addr_item->address.as_bytes[2], + p_addr_item->address.as_bytes[3]) ); + } + else + { + /* Fatal error. */ + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Port %d OID_GEN_NETWORK_LAYER_ADDRESSES - Failed to " + "register IP Address of %d.%d.%d.%d with error %s\n", + port_num, + p_addr_item->address.as_bytes[0], + p_addr_item->address.as_bytes[1], + p_addr_item->address.as_bytes[2], + p_addr_item->address.as_bytes[3], + p_adapter->p_ifc->get_err_str( ib_status )) ); + p_adapter->hung = TRUE; + } + cl_obj_deref(&p_adapter->obj); + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_OBJ, + ("Adapter[%p] refcnt decremented to %d\n", p_adapter, p_adapter->obj.ref_cnt)); + cl_free( p_addr_item->p_reg ); + p_addr_item->p_reg = NULL; + } + } + + IPOIB_EXIT( IPOIB_DBG_OID ); +} + + +/* Object lock is held when this function is called. */ +void +ipoib_dereg_addrs( + IN ipoib_adapter_t* const p_adapter ) +{ + net_address_item_t *p_addr_item; + + size_t idx; + + IPOIB_ENTER( IPOIB_DBG_OID ); + + for( idx = 0; idx < cl_vector_get_size( &p_adapter->ip_vector); idx++ ) + { + p_addr_item = (net_address_item_t*) + cl_vector_get_ptr( &p_adapter->ip_vector, idx ); + + if( !p_addr_item->p_reg ) + continue; + + if( p_addr_item->p_reg->h_reg_svc ) + { + p_adapter->p_ifc->dereg_svc( + p_addr_item->p_reg->h_reg_svc, __ipoib_ats_dereg_cb ); + } + else + { + cl_free( p_addr_item->p_reg ); + } + p_addr_item->p_reg = NULL; + } + + IPOIB_EXIT( IPOIB_DBG_OID ); +} + + +void +ipoib_cancel_xmit( + IN NDIS_HANDLE adapter_context, + IN PVOID cancel_id ) +{ + + ipoib_adapter_t* const p_adapter = + (ipoib_adapter_t* const )adapter_context; + + if( p_adapter && p_adapter->p_port ) + { + ipoib_port_cancel_xmit( p_adapter->p_port, cancel_id ); + } + + return; + +} + + +static void +__ipoib_ats_reg_cb( + IN ib_reg_svc_rec_t *p_reg_svc_rec ) +{ + ats_reg_t *p_reg; + uint8_t port_num; + + IPOIB_ENTER( IPOIB_DBG_OID ); + + CL_ASSERT( p_reg_svc_rec ); + CL_ASSERT( p_reg_svc_rec->svc_context ); + + p_reg = (ats_reg_t*)p_reg_svc_rec->svc_context; + port_num = p_reg->p_adapter->guids.port_num; + + cl_obj_lock( &p_reg->p_adapter->obj ); + + if( p_reg_svc_rec->req_status == IB_SUCCESS && + !p_reg_svc_rec->resp_status ) + { + IPOIB_PRINT( TRACE_LEVEL_INFORMATION,IPOIB_DBG_OID, + ("Port %d OID_GEN_NETWORK_LAYER_ADDRESSES - Registered IP Address " + "of %d.%d.%d.%d\n", + port_num, + p_reg_svc_rec->svc_rec.service_data8[ATS_IPV4_OFFSET], + p_reg_svc_rec->svc_rec.service_data8[ATS_IPV4_OFFSET+1], + p_reg_svc_rec->svc_rec.service_data8[ATS_IPV4_OFFSET+2], + p_reg_svc_rec->svc_rec.service_data8[ATS_IPV4_OFFSET+3]) ); + } + else if( p_reg_svc_rec->req_status != IB_CANCELED ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_OID, + ("Port %d OID_GEN_NETWORK_LAYER_ADDRESSES - Failed to register IP Address " + "of %d.%d.%d.%d with error %s\n", + port_num, + p_reg_svc_rec->svc_rec.service_data8[ATS_IPV4_OFFSET], + p_reg_svc_rec->svc_rec.service_data8[ATS_IPV4_OFFSET+1], + p_reg_svc_rec->svc_rec.service_data8[ATS_IPV4_OFFSET+2], + p_reg_svc_rec->svc_rec.service_data8[ATS_IPV4_OFFSET+3], + p_reg->p_adapter->p_ifc->get_err_str((ib_api_status_t) p_reg_svc_rec->resp_status )) ); + p_reg->p_adapter->hung = TRUE; + p_reg->h_reg_svc = NULL; + } + + cl_obj_unlock( &p_reg->p_adapter->obj ); + cl_obj_deref(&p_reg->p_adapter->obj); + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_OBJ, + ("Adapter[%p] refcnt decremented to %d\n", + p_reg->p_adapter, p_reg->p_adapter->obj.ref_cnt)); + + IPOIB_EXIT( IPOIB_DBG_OID ); +} + + +static void +__ipoib_ats_dereg_cb( + IN void *context ) +{ + cl_free( context ); +} + +static NDIS_STATUS +ipoib_pause( + IN NDIS_HANDLE adapter_context, + IN PNDIS_MINIPORT_PAUSE_PARAMETERS pause_parameters) +{ + ipoib_adapter_t *p_adapter; + KLOCK_QUEUE_HANDLE hdl; + + UNREFERENCED_PARAMETER(pause_parameters); + IPOIB_ENTER( IPOIB_DBG_INIT ); + + CL_ASSERT(adapter_context); + p_adapter = (ipoib_adapter_t*)adapter_context; + CL_ASSERT(p_adapter->ipoib_state == IPOIB_RUNNING); + + KeAcquireInStackQueuedSpinLock( &g_ipoib.lock, &hdl ); + p_adapter->ipoib_state = IPOIB_PAUSING; + KeReleaseInStackQueuedSpinLock( &hdl ); + + if (p_adapter->p_port) { + cl_spinlock_acquire( &p_adapter->p_port->send_lock ); + ipoib_port_resume(p_adapter->p_port,FALSE); + cl_spinlock_release( &p_adapter->p_port->send_lock ); + } + + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_RECV, + ("Shutter shut, state = %d\n", p_adapter->ipoib_state)); + shutter_shut ( &p_adapter->recv_shutter ); + + KeAcquireInStackQueuedSpinLock( &g_ipoib.lock, &hdl ); + p_adapter->ipoib_state = IPOIB_PAUSED; + KeReleaseInStackQueuedSpinLock( &hdl ); + + IPOIB_EXIT( IPOIB_DBG_INIT ); + return NDIS_STATUS_SUCCESS; +} + +static NDIS_STATUS +ipoib_restart( + IN NDIS_HANDLE adapter_context, + IN PNDIS_MINIPORT_RESTART_PARAMETERS restart_parameters) +{ + ipoib_adapter_t *p_adapter; + KLOCK_QUEUE_HANDLE hdl; + PNDIS_RESTART_ATTRIBUTES NdisRestartAttributes; + PNDIS_RESTART_GENERAL_ATTRIBUTES NdisGeneralAttributes; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + p_adapter = (ipoib_adapter_t*)adapter_context; + + NdisRestartAttributes = restart_parameters->RestartAttributes; + + if (NdisRestartAttributes != NULL) + { + CL_ASSERT(NdisRestartAttributes->Oid == OID_GEN_MINIPORT_RESTART_ATTRIBUTES); + NdisGeneralAttributes = (PNDIS_RESTART_GENERAL_ATTRIBUTES)NdisRestartAttributes->Data; + // + // Check to see if we need to change any attributes + } + + if ( (p_adapter->ipoib_state == IPOIB_PAUSED) || (p_adapter->ipoib_state == IPOIB_INIT) ) { + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_RECV, + ("Shutter Alive, ipoib_state = %d\n", p_adapter->ipoib_state)); + shutter_alive( &p_adapter->recv_shutter ); + } + else { + IPOIB_PRINT( TRACE_LEVEL_WARNING, IPOIB_DBG_RECV, + ("*****Shutter Was not \"Alived\", state = %d*****\n", p_adapter->ipoib_state)); + } + + KeAcquireInStackQueuedSpinLock( &g_ipoib.lock, &hdl ); + p_adapter->ipoib_state = IPOIB_RUNNING; + KeReleaseInStackQueuedSpinLock( &hdl ); + + + IPOIB_EXIT( IPOIB_DBG_INIT ); + return NDIS_STATUS_SUCCESS; +} + +/*++ +Routine Description: + + This function aborts the request pending in the miniport. + +Arguments: + + MiniportAdapterContext Pointer to the adapter structure + RequestId Specify the request to be cancelled. + +Return Value: + +--*/ +static void +ipoib_cancel_oid_request( + IN NDIS_HANDLE adapter_context, + IN PVOID requestId + ) +{ + PNDIS_OID_REQUEST pending_request; + ipoib_adapter_t *p_adapter; + + IPOIB_ENTER( IPOIB_DBG_OID ); + p_adapter = (ipoib_adapter_t*)adapter_context; + + cl_obj_lock( &p_adapter->obj ); + + if ( p_adapter->query_oid.p_pending_oid && + p_adapter->query_oid.p_pending_oid->RequestId == requestId) + { + pending_request = p_adapter->query_oid.p_pending_oid; + p_adapter->query_oid.p_pending_oid = NULL; + p_adapter->pending_query = FALSE; + } + else if(p_adapter->set_oid.p_pending_oid && + p_adapter->set_oid.p_pending_oid->RequestId == requestId) + { + pending_request = p_adapter->set_oid.p_pending_oid; + p_adapter->set_oid.p_pending_oid = NULL; + p_adapter->pending_set = FALSE; + } + else + { + cl_obj_unlock( &p_adapter->obj ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("No Pending OID found\n") ); + return; + } + cl_obj_unlock( &p_adapter->obj ); + + NdisMOidRequestComplete(p_adapter->h_adapter, + pending_request, + NDIS_STATUS_REQUEST_ABORTED); + + IPOIB_EXIT( IPOIB_DBG_OID ); +} diff --git a/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_driver.h b/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_driver.h new file mode 100644 index 00000000..2d5e9219 --- /dev/null +++ b/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_driver.h @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2006 Mellanox Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: ipoib_driver.h 4494 2009-06-22 14:31:08Z xalex $ + */ + + +#ifndef _IPOIB_DRIVER_H_ +#define _IPOIB_DRIVER_H_ + + +#include "ipoib_log.h" +#include "ipoib_adapter.h" +#include +#include +#include "ipoib_debug.h" + + +/* + * Definitions + */ +#define MAX_BUNDLE_ID_LENGTH 32 + +/* The maximum number of send packets the MiniportSendPackets function can accept */ +#define MINIPORT_MAX_SEND_PACKETS 200 + +/* MLX4 supports 4K MTU */ +#define MAX_IB_MTU 4096 +#define DEFAULT_MTU 2048 +/* + * Header length as defined by IPoIB spec: + * http://www.ietf.org/internet-drafts/draft-ietf-ipoib-ip-over-infiniband-04.txt + */ +#define MAX_LSO_PAYLOAD_MTU 65536 +#define MAX_UD_PAYLOAD_MTU (MAX_IB_MTU - sizeof(ipoib_hdr_t)) +#define DEFAULT_PAYLOAD_MTU (DEFAULT_MTU - sizeof(ipoib_hdr_t)) +#define MAX_CM_PAYLOAD_MTU (65520) +#define MAX_WRS_PER_MSG ((MAX_CM_PAYLOAD_MTU/DEFAULT_PAYLOAD_MTU)+1) +/* + * Only the protocol type is sent as part of the UD payload + * since the rest of the Ethernet header is encapsulated in the + * various IB headers. We report out buffer space as if we + * transmit the ethernet headers. + */ +#define MAX_XFER_BLOCK_SIZE (sizeof(eth_hdr_t) + MAX_UD_PAYLOAD_MTU) +#define DATA_OFFSET (sizeof(eth_hdr_t) - sizeof(ipoib_hdr_t)) + +#define IPOIB_CM_FLAG_RC (0x80) +#define IPOIB_CM_FLAG_UC (0x40) +#define IPOIB_CM_FLAG_SVCID (0x10) // OFED set IETF bit this way ( open OFED PR 1121 ) + +#define MAX_SEND_SGE (30) + +/* Amount of physical memory to register. */ +#define MEM_REG_SIZE 0xFFFFFFFFFFFFFFFF + +/* Number of work completions to chain for send and receive polling. */ +#define MAX_SEND_WC 5 +#define MAX_RECV_WC 16 + +typedef struct _ipoib_globals +{ + KSPIN_LOCK lock; + cl_qlist_t adapter_list; + cl_qlist_t bundle_list; + + atomic32_t laa_idx; + + NDIS_HANDLE h_ndis_wrapper; + PDEVICE_OBJECT h_ibat_dev; + NDIS_HANDLE h_ibat_dev_handle; //MSDN: this handle is a required parameter to the + //NdisDeregisterDeviceEx function that the driver calls subsequently + volatile LONG ibat_ref; + uint32_t bypass_check_bcast_rate; + +} ipoib_globals_t; +/* +* FIELDS +* lock +* Spinlock to protect list access. +* +* adapter_list +* List of all adapter instances. Used for address translation support. +* +* bundle_list +* List of all adapter bundles. +* +* laa_idx +* Global counter for generating LAA MACs +* +* h_ibat_dev +* Device handle returned by NdisMRegisterDevice. +*********/ + +extern ipoib_globals_t g_ipoib; +extern NDIS_HANDLE g_IpoibMiniportDriverHandle; + + + +typedef struct _ipoib_bundle +{ + cl_list_item_t list_item; + char bundle_id[MAX_BUNDLE_ID_LENGTH]; + cl_qlist_t adapter_list; + +} ipoib_bundle_t; +/* +* FIELDS +* list_item +* List item for storing the bundle in a quick list. +* +* bundle_id +* Bundle identifier. +* +* adapter_list +* List of adapters in the bundle. The adapter at the head is the +* primary adapter of the bundle. +*********/ +void +ipoib_create_log( + NDIS_HANDLE h_adapter, + UINT ind, + ULONG eventLogMsgId); + +#define GUID_MASK_LOG_INDEX 0 + +void +ipoib_resume_oids( + IN ipoib_adapter_t* const p_adapter ); + +#define IPOIB_OFFSET(field) ((UINT)FIELD_OFFSET(ipoib_params_t,field)) +#define IPOIB_SIZE(field) sizeof(((ipoib_params_t*)0)->field) +#define IPOIB_INIT_NDIS_STRING(str) \ + (str)->Length = 0; \ + (str)->MaximumLength = 0; \ + (str)->Buffer = NULL; + + + +#endif /* _IPOIB_DRIVER_H_ */ diff --git a/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_endpoint.cpp b/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_endpoint.cpp new file mode 100644 index 00000000..1ed68450 --- /dev/null +++ b/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_endpoint.cpp @@ -0,0 +1,1183 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2006 Mellanox Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: ipoib_endpoint.c 4226 2009-04-06 06:01:03Z xalex $ + */ + +#include + + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "ipoib_endpoint.tmh" +#endif +#include +#include + + +static void +__endpt_destroying( + IN cl_obj_t* p_obj ); + +static void +__endpt_cleanup( + IN cl_obj_t* p_obj ); + +static void +__endpt_free( + IN cl_obj_t* p_obj ); + +static ib_api_status_t +__create_mcast_av( + IN ib_pd_handle_t h_pd, + IN uint8_t port_num, + IN ib_member_rec_t* const p_member_rec, + OUT ib_av_handle_t* const ph_av ); + +static inline ipoib_port_t* +__endpt_parent( + IN ipoib_endpt_t* const p_endpt ); + +static void +__path_query_cb( + IN ib_query_rec_t *p_query_rec ); + +static void +__endpt_resolve( + IN ipoib_endpt_t* const p_endpt ); + +static void +__endpt_cm_send_cb( + IN const ib_cq_handle_t h_cq, + IN void *cq_context ); +static void +__endpt_cm_recv_cb( + IN const ib_cq_handle_t h_cq, + IN void *cq_context ); + +static void +__endpt_cm_buf_mgr_construct( + IN endpt_buf_mgr_t * const p_buf_mgr ); +static void +__conn_reply_cb( + IN ib_cm_rep_rec_t *p_cm_rep ); + +static void +__conn_mra_cb( + IN ib_cm_mra_rec_t *p_mra_rec ); + +static void +__conn_rej_cb( + IN ib_cm_rej_rec_t *p_rej_rec ); + +static void +__conn_dreq_cb( + IN ib_cm_dreq_rec_t *p_dreq_rec ); + +#if 0 //CM +static cl_status_t +__cm_recv_desc_ctor( + IN void* const p_object, + IN void* context, + OUT cl_pool_item_t** const pp_pool_item ); + +static void +__cm_recv_desc_dtor( + IN const cl_pool_item_t* const p_pool_item, + IN void *context ); + +static NDIS_PACKET* +__endpt_cm_get_ndis_pkt( + IN ipoib_port_t* const p_port, + IN ipoib_cm_desc_t* const p_desc ); + +static inline ipoib_cm_desc_t* +__endpt_cm_buf_mgr_get_recv( + IN endpt_buf_mgr_t * const p_buf_mgr ); + +static boolean_t +__cm_recv_is_dhcp( + IN const ipoib_pkt_t* const p_ipoib ); + +static ib_api_status_t +__endpt_cm_recv_arp( + IN ipoib_port_t* const p_port, + IN const ipoib_pkt_t* const p_ipoib, + OUT eth_pkt_t* const p_eth, + IN ipoib_endpt_t* const p_src_endpt ); + +static ib_api_status_t +__endpt_cm_recv_udp( + IN ipoib_port_t* const p_port, + IN ib_wc_t* const p_wc, + IN const ipoib_pkt_t* const p_ipoib, + OUT eth_pkt_t* const p_eth, + IN ipoib_endpt_t* const p_src_endpt ); +#endif + +ipoib_endpt_t* +ipoib_endpt_create( + IN const ib_gid_t* const p_dgid, + IN const net16_t dlid, + IN const net32_t qpn ) +{ + ipoib_endpt_t *p_endpt; + cl_status_t status; + + IPOIB_ENTER( IPOIB_DBG_ENDPT ); + + p_endpt = (ipoib_endpt_t *) cl_zalloc( sizeof(ipoib_endpt_t) ); + if( !p_endpt ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to allocate endpoint (%d bytes)\n", + sizeof(ipoib_endpt_t)) ); + return NULL; + } + + cl_obj_construct( &p_endpt->obj, IPOIB_OBJ_ENDPOINT ); + + status = cl_obj_init( &p_endpt->obj, + CL_DESTROY_ASYNC, + __endpt_destroying, + __endpt_cleanup, + __endpt_free ); + + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_ENDPT, + ("Created EndPoint %p DLID: %#x QPN: %#x \n", + p_endpt, cl_ntoh16(dlid), cl_ntoh32(qpn) ) ); + + p_endpt->dgid = *p_dgid; + p_endpt->dlid = dlid; + p_endpt->qpn = qpn; + + IPOIB_EXIT( IPOIB_DBG_ENDPT ); + return p_endpt; +} + + +static ib_api_status_t +__create_mcast_av( + IN ib_pd_handle_t h_pd, + IN uint8_t port_num, + IN ib_member_rec_t* const p_member_rec, + OUT ib_av_handle_t* const ph_av ) +{ + ib_av_attr_t av_attr; + uint32_t flow_lbl; + uint8_t hop_lmt; + ib_api_status_t status; + ipoib_endpt_t *p_endpt; + + IPOIB_ENTER( IPOIB_DBG_MCAST ); + + p_endpt = PARENT_STRUCT(ph_av, ipoib_endpt_t, h_av ); + + cl_memclr( &av_attr, sizeof(ib_av_attr_t) ); + av_attr.port_num = port_num; + ib_member_get_sl_flow_hop( p_member_rec->sl_flow_hop, + &av_attr.sl, &flow_lbl, &hop_lmt ); + av_attr.dlid = p_member_rec->mlid; + av_attr.grh_valid = TRUE; + av_attr.grh.hop_limit = hop_lmt; + av_attr.grh.dest_gid = p_member_rec->mgid; + av_attr.grh.src_gid = p_member_rec->port_gid; + av_attr.grh.ver_class_flow = + ib_grh_set_ver_class_flow( 6, p_member_rec->tclass, flow_lbl ); + av_attr.static_rate = p_member_rec->rate & IB_PATH_REC_BASE_MASK; + av_attr.path_bits = 0; + /* port is not attached to endpoint at this point, so use endpt ifc + reference */ + status = p_endpt->p_ifc->create_av( h_pd, &av_attr, ph_av ); + + if( status != IB_SUCCESS ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_create_av returned %s\n", + p_endpt->p_ifc->get_err_str( status )) ); + } + + IPOIB_EXIT( IPOIB_DBG_MCAST ); + return status; +} + + +ib_api_status_t +ipoib_endpt_set_mcast( + IN ipoib_endpt_t* const p_endpt, + IN ib_pd_handle_t h_pd, + IN uint8_t port_num, + IN ib_mcast_rec_t* const p_mcast_rec ) +{ + ib_api_status_t status; + + IPOIB_ENTER( IPOIB_DBG_ENDPT ); + + IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_ENDPT, + ("Create av for MAC: %02X-%02X-%02X-%02X-%02X-%02X\n", + p_endpt->mac.addr[0], p_endpt->mac.addr[1], + p_endpt->mac.addr[2], p_endpt->mac.addr[3], + p_endpt->mac.addr[4], p_endpt->mac.addr[5]) ); + + status = __create_mcast_av( h_pd, port_num, p_mcast_rec->p_member_rec, + &p_endpt->h_av ); + if( status != IB_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("__create_mcast_av returned %s\n", + p_endpt->p_ifc->get_err_str( status )) ); + return status; + } + p_endpt->h_mcast = p_mcast_rec->h_mcast; + CL_ASSERT(p_endpt->dlid == 0); + + IPOIB_EXIT( IPOIB_DBG_ENDPT ); + return IB_SUCCESS; +} + + +static void +__endpt_destroying( + IN cl_obj_t* p_obj ) +{ + ipoib_endpt_t *p_endpt; + ipoib_port_t *p_port; + + IPOIB_ENTER( IPOIB_DBG_ENDPT ); + + p_endpt = PARENT_STRUCT( p_obj, ipoib_endpt_t, obj ); + p_port = __endpt_parent( p_endpt ); + + cl_obj_lock( p_obj ); + if( p_endpt->h_query ) + { + p_port->p_adapter->p_ifc->cancel_query( p_port->p_adapter->h_al, + p_endpt->h_query ); + p_endpt->h_query = NULL; + } + + /* Leave the multicast group if it exists. */ + if( p_endpt->h_mcast ) + { + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_ENDPT, + ("Leaving MCast group\n") ); + ipoib_port_ref(p_port, ref_leave_mcast); + p_port->p_adapter->p_ifc->leave_mcast( p_endpt->h_mcast, + ipoib_leave_mcast_cb ); + } +#if 0 + else if( p_port->p_adapter->params.cm_enabled ) + { + p_endpt->cm_flag = 0; + CL_ASSERT( endpt_cm_get_state( p_endpt ) == IPOIB_CM_DISCONNECTED ); + } +#endif + + cl_obj_unlock( p_obj ); + + IPOIB_EXIT( IPOIB_DBG_ENDPT ); +} + + +static void +__endpt_cleanup( + IN cl_obj_t* p_obj ) +{ + ipoib_endpt_t *p_endpt; + ipoib_port_t *p_port; + + IPOIB_ENTER( IPOIB_DBG_ENDPT ); + + p_endpt = PARENT_STRUCT( p_obj, ipoib_endpt_t, obj ); + p_port = __endpt_parent( p_endpt ); + + /* Destroy the AV if it exists. */ + if( p_endpt->h_av ) + p_port->p_adapter->p_ifc->destroy_av( p_endpt->h_av ); + + IPOIB_EXIT( IPOIB_DBG_ENDPT ); +} + + +static void +__endpt_free( + IN cl_obj_t* p_obj ) +{ + ipoib_endpt_t *p_endpt; + + IPOIB_ENTER( IPOIB_DBG_ENDPT ); + + p_endpt = PARENT_STRUCT( p_obj, ipoib_endpt_t, obj ); + + cl_obj_deinit( p_obj ); + cl_free( p_endpt ); + + IPOIB_EXIT( IPOIB_DBG_ENDPT ); +} + + +static inline ipoib_port_t* +__endpt_parent( + IN ipoib_endpt_t* const p_endpt ) +{ + return PARENT_STRUCT( p_endpt->rel.p_parent_obj, ipoib_port_t, obj ); +} + +ipoib_port_t* +ipoib_endpt_parent( + IN ipoib_endpt_t* const p_endpt ) +{ + return __endpt_parent( p_endpt ); +} + +/* + * This function is called with the port object's send lock held and + * a reference held on the endpoint. If we fail, we release the reference. + */ +NDIS_STATUS +ipoib_endpt_queue( + IN ipoib_endpt_t* const p_endpt ) +{ + ib_api_status_t status; + ipoib_port_t *p_port; + ib_av_attr_t av_attr; + net32_t flow_lbl; + + IPOIB_ENTER( IPOIB_DBG_ENDPT ); + + if( p_endpt->h_av ) + { + IPOIB_EXIT( IPOIB_DBG_ENDPT ); + return NDIS_STATUS_SUCCESS; + } + + if( p_endpt->qpn == CL_HTON32(0x00FFFFFF) ) + { + /* + * Handle a race between the mcast callback and a receive/send. The QP + * is joined to the MC group before the MC callback is received, so it + * can receive packets, and NDIS can try to respond. We need to delay + * a response until the MC callback runs and sets the AV. + */ + IPOIB_PRINT( TRACE_LEVEL_WARNING, IPOIB_DBG_MCAST , + ("Got the race between the mcast callback and a receive/send\n")); + IPOIB_PRINT( TRACE_LEVEL_WARNING, IPOIB_DBG_SEND , + ("Got the race between the mcast callback and a receive/send\n")); + ipoib_endpt_deref( p_endpt ); + IPOIB_EXIT( IPOIB_DBG_ENDPT ); + return NDIS_STATUS_PENDING; + } + + /* This is the first packet for this endpoint. Create the AV. */ + p_port = __endpt_parent( p_endpt ); + + cl_memclr( &av_attr, sizeof(ib_av_attr_t) ); + + av_attr.port_num = p_port->port_num; + + ib_member_get_sl_flow_hop( p_port->ib_mgr.bcast_rec.sl_flow_hop, + &av_attr.sl, + &flow_lbl, + &av_attr.grh.hop_limit ); + + av_attr.dlid = p_endpt->dlid; + + /* + * We always send the GRH so that we preferably lookup endpoints + * by GID rather than by LID. This allows certain WHQL tests + * such as the 2c_MediaCheck test to succeed since they don't use + * IP. This allows endpoints to be created on the fly for requests + * for which there is no match, something that doesn't work when + * using LIDs only. + */ + av_attr.grh_valid = TRUE; + av_attr.grh.ver_class_flow = ib_grh_set_ver_class_flow( + 6, p_port->ib_mgr.bcast_rec.tclass, flow_lbl ); + av_attr.grh.resv1 = 0; + av_attr.grh.resv2 = 0; + ib_gid_set_default( &av_attr.grh.src_gid, + p_port->p_adapter->guids.port_guid.guid ); + av_attr.grh.dest_gid = p_endpt->dgid; + + av_attr.static_rate = p_port->ib_mgr.bcast_rec.rate; + av_attr.path_bits = 0; + + /* Create the AV. */ + status = p_port->p_adapter->p_ifc->create_av( p_port->ib_mgr.h_pd, + &av_attr, + &p_endpt->h_av ); + if( status != IB_SUCCESS ) + { + p_port->p_adapter->hung = TRUE; + ipoib_endpt_deref( p_endpt ); + cl_obj_unlock( &p_endpt->obj ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_create_av failed with %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + return NDIS_STATUS_FAILURE; + } + + IPOIB_EXIT( IPOIB_DBG_ENDPT ); + return NDIS_STATUS_SUCCESS; +} + +#if 0 + +static void +__endpt_cm_buf_mgr_construct( + IN endpt_buf_mgr_t * const p_buf_mgr ) +{ + IPOIB_ENTER( IPOIB_DBG_INIT ); + + cl_qpool_construct( &p_buf_mgr->recv_pool ); + + p_buf_mgr->h_packet_pool = NULL; + p_buf_mgr->h_buffer_pool = NULL; + + IPOIB_EXIT( IPOIB_DBG_INIT ); +} + +ib_api_status_t +endpt_cm_buf_mgr_init( + IN ipoib_port_t* const p_port ) +{ + cl_status_t cl_status; + NDIS_STATUS ndis_status; + ib_api_status_t ib_status = IB_SUCCESS; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + if( p_port->cm_buf_mgr.pool_init ) + return ib_status; + + cl_qlist_init( &p_port->cm_buf_mgr.posted_list ); + + __endpt_cm_buf_mgr_construct( &p_port->cm_buf_mgr ); + p_port->cm_recv_mgr.rq_depth = + min( (uint32_t)p_port->p_adapter->params.rq_depth * 8, + p_port->p_ca_attrs->max_srq_wrs/2 ); + p_port->cm_recv_mgr.depth = 0; + /* Allocate the receive descriptors pool */ + cl_status = cl_qpool_init( &p_port->cm_buf_mgr.recv_pool, + p_port->cm_recv_mgr.rq_depth , + 0, + 0, + sizeof( ipoib_cm_desc_t ), + __cm_recv_desc_ctor, + __cm_recv_desc_dtor, + p_port ); + + if( cl_status != CL_SUCCESS ) + { + NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter, + EVENT_IPOIB_RECV_POOL, 1, cl_status ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("cl_qpool_init(cm_buf_mgr.recv_pool) returned %#x\n", cl_status) ); + return IB_INSUFFICIENT_MEMORY; + } + + /* Allocate the NDIS buffer and packet pools for receive indication. */ + NdisAllocatePacketPool( &ndis_status, + &p_port->cm_buf_mgr.h_packet_pool, + p_port->cm_recv_mgr.rq_depth, + PROTOCOL_RESERVED_SIZE_IN_PACKET ); + if( ndis_status != NDIS_STATUS_SUCCESS ) + { + NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter, + EVENT_IPOIB_RECV_PKT_POOL, 1, ndis_status ); + + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("NdisAllocatePacketPool returned %08X\n", ndis_status) ); + + ib_status = IB_INSUFFICIENT_RESOURCES; + goto pkt_pool_failed; + } + + NdisAllocateBufferPool( &ndis_status, + &p_port->cm_buf_mgr.h_buffer_pool, + p_port->cm_recv_mgr.rq_depth ); + if( ndis_status != NDIS_STATUS_SUCCESS ) + { + NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter, + EVENT_IPOIB_RECV_BUF_POOL, 1, ndis_status ); + + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("NdisAllocateBufferPool returned %08X\n", ndis_status) ); + + ib_status = IB_INSUFFICIENT_RESOURCES; + goto buf_pool_failed; + } + //NDIS60 + //p_port->cm_recv_mgr.recv_pkt_array = + //cl_zalloc( sizeof(NDIS_PACKET*) * p_port->cm_recv_mgr.rq_depth ); + p_port->cm_recv_mgr.recv_lst_array = + cl_zalloc( sizeof(NET_BUFFER_LIST*) * p_port->cm_recv_mgr.rq_depth ); + + + + if( !p_port->cm_recv_mgr.recv_NBL_array ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("cl_zalloc for cm_recv_mgr NET_BUFFER_LIST array failed.\n") ); + + ib_status = IB_INSUFFICIENT_MEMORY; + goto pkt_array_failed; + } + + p_port->cm_buf_mgr.pool_init = TRUE; + return IB_SUCCESS; + + +pkt_array_failed: + if( p_port->cm_buf_mgr.h_buffer_pool ) + NdisFreeBufferPool( p_port->cm_buf_mgr.h_buffer_pool ); +buf_pool_failed: + if( p_port->cm_buf_mgr.h_packet_pool ) + NdisFreePacketPool( p_port->cm_buf_mgr.h_packet_pool ); +pkt_pool_failed: + cl_qpool_destroy( &p_port->cm_buf_mgr.recv_pool ); + + IPOIB_EXIT( IPOIB_DBG_INIT ); + return ib_status; +} + + +void +endpt_cm_buf_mgr_reset( + IN ipoib_port_t* const p_port ) +{ + cl_list_item_t *p_item; + + if( !p_port->cm_buf_mgr.pool_init ) + return; + + if( cl_qlist_count( &p_port->cm_buf_mgr.posted_list ) ) + { + for( p_item = cl_qlist_remove_head( &p_port->cm_buf_mgr.posted_list ); + p_item != cl_qlist_end( &p_port->cm_buf_mgr.posted_list ); + p_item = cl_qlist_remove_head( &p_port->cm_buf_mgr.posted_list ) ) + { + cl_qpool_put( &p_port->cm_buf_mgr.recv_pool, + &( PARENT_STRUCT( p_item, ipoib_cm_desc_t, list_item ))->item ); + } + } +} + +void +endpt_cm_buf_mgr_destroy( + IN ipoib_port_t* const p_port ) +{ + + IPOIB_ENTER(IPOIB_DBG_INIT ); + + CL_ASSERT( p_port ); + + /* Free the receive descriptors. */ + if( !p_port->cm_buf_mgr.pool_init ) + return; + + endpt_cm_buf_mgr_reset( p_port ); + + p_port->cm_buf_mgr.pool_init = FALSE; + + if( p_port->cm_recv_mgr.recv_NBL_array ) + { + cl_free( p_port->cm_recv_mgr.recv_NBL_array ); + } + + /* Destroy the receive packet and buffer pools. */ + if( p_port->cm_buf_mgr.h_buffer_pool ) + NdisFreeBufferPool( p_port->cm_buf_mgr.h_buffer_pool ); + if( p_port->cm_buf_mgr.h_packet_pool ) + NdisFreePacketPool( p_port->cm_buf_mgr.h_packet_pool ); + + cl_qpool_destroy( &p_port->cm_buf_mgr.recv_pool ); + + IPOIB_EXIT( IPOIB_DBG_INIT ); +} + +static cl_status_t +__cm_recv_desc_ctor( + IN void* const p_object, + IN void* context, + OUT cl_pool_item_t** const pp_pool_item ) +{ + ipoib_cm_desc_t* p_desc; + ipoib_port_t* p_port; + ib_mr_create_t create_mr; + net32_t rkey; + + CL_ASSERT( p_object ); + CL_ASSERT( context ); + + p_desc = (ipoib_cm_desc_t*)p_object; + p_port = (ipoib_port_t*)context; + +#define BUF_ALIGN (16) + + p_desc->alloc_buf_size = + ROUNDUP( p_port->p_adapter->params.cm_xfer_block_size, BUF_ALIGN ); + + p_desc->p_alloc_buf = (uint8_t *)ExAllocatePoolWithTag( + NonPagedPool, p_desc->alloc_buf_size, 'DOMC' ); + + if( p_desc->p_alloc_buf == NULL ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to allocate CM recv buffer size %d bytes.\n", + p_desc->alloc_buf_size ) ); + return CL_INSUFFICIENT_MEMORY; + } + + create_mr.vaddr = p_desc->p_alloc_buf; + create_mr.length = p_desc->alloc_buf_size; + create_mr.access_ctrl = IB_AC_LOCAL_WRITE; + + if( p_port->p_adapter->p_ifc->reg_mem( p_port->ib_mgr.h_pd, + &create_mr, + &p_desc->lkey, + &rkey, + &p_desc->h_mr ) != IB_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to create Memory Region size %d bytes.\n", + p_desc->alloc_buf_size ) ); + goto ctor_failed; + } + p_desc->p_buf = p_desc->p_alloc_buf + (BUF_ALIGN - sizeof( ipoib_hdr_t)); + p_desc->buf_size = p_desc->alloc_buf_size - (BUF_ALIGN - sizeof( ipoib_hdr_t)); + + /* Setup the local data segment. */ + p_desc->local_ds[0].vaddr = (uint64_t)(uintn_t)p_desc->p_buf; + p_desc->local_ds[0].length = p_desc->buf_size; + p_desc->local_ds[0].lkey = p_desc->lkey; + + /* Setup the work request. */ + p_desc->wr.wr_id = (uintn_t)p_desc; + p_desc->wr.ds_array = p_desc->local_ds; + p_desc->wr.num_ds = 1; + + p_desc->type = PKT_TYPE_CM_UCAST; + + *pp_pool_item = &p_desc->item; + + return CL_SUCCESS; + +ctor_failed: + ExFreePoolWithTag( p_desc->p_alloc_buf, 'DOMC' ); + return CL_INSUFFICIENT_MEMORY; +} + +static void +__cm_recv_desc_dtor( + IN const cl_pool_item_t* const p_pool_item, + IN void *context ) +{ + ipoib_cm_desc_t *p_desc; + ipoib_port_t* p_port; + + if( p_pool_item == NULL || context == NULL ) + return; + + p_port = (ipoib_port_t*)context; + p_desc = PARENT_STRUCT( p_pool_item, ipoib_cm_desc_t, item ); + + if( p_desc->h_mr ) + p_port->p_adapter->p_ifc->dereg_mr( p_desc->h_mr ); + + if( p_desc->p_alloc_buf ) + ExFreePoolWithTag( p_desc->p_alloc_buf, 'DOMC' ); +} + + +static NDIS_PACKET* +__endpt_cm_get_ndis_pkt( + IN ipoib_port_t* const p_port, + IN ipoib_cm_desc_t* const p_desc ) +{ + NDIS_STATUS status; + NDIS_PACKET *p_packet; + NDIS_BUFFER *p_buffer; + + IPOIB_ENTER( IPOIB_DBG_RECV ); + + NdisDprAllocatePacketNonInterlocked( &status, &p_packet, + p_port->cm_buf_mgr.h_packet_pool ); + if( status != NDIS_STATUS_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to allocate NDIS_PACKET: %08x\n", status) ); + return NULL; + } + + IPOIB_PORT_FROM_PACKET( p_packet ) = p_port; + IPOIB_RECV_FROM_PACKET( p_packet ) = p_desc; + + NdisAllocateBuffer( + &status, + &p_buffer, + p_port->cm_buf_mgr.h_buffer_pool, + (void *)(p_desc->p_buf - DATA_OFFSET), + p_desc->len + DATA_OFFSET ); + + if( status != NDIS_STATUS_SUCCESS ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to allocate NDIS_BUFFER: %08x\n", status) ); + NdisDprFreePacketNonInterlocked( p_packet ); + return NULL; + } + + NdisChainBufferAtFront( p_packet, p_buffer ); + NDIS_SET_PACKET_HEADER_SIZE( p_packet, sizeof(eth_hdr_t) ); + + IPOIB_EXIT( IPOIB_DBG_RECV ); + return p_packet; +} + +static inline ipoib_cm_desc_t* +__endpt_cm_buf_mgr_get_recv( + IN endpt_buf_mgr_t * const p_buf_mgr ) +{ + ipoib_cm_desc_t *p_desc; + + p_desc = (ipoib_cm_desc_t*)cl_qpool_get( &p_buf_mgr->recv_pool ); + if( p_desc ) + cl_qlist_insert_tail( &p_buf_mgr->posted_list, &p_desc->list_item ); + + return p_desc; +} + +void +endpt_cm_buf_mgr_put_recv( + IN endpt_buf_mgr_t * const p_buf_mgr, + IN ipoib_cm_desc_t* const p_desc ) +{ + + IPOIB_ENTER(IPOIB_DBG_RECV ); + + /* Return the descriptor to it's pool. */ + cl_qlist_remove_item( &p_buf_mgr->posted_list, &p_desc->list_item ); + cl_qpool_put( &p_buf_mgr->recv_pool, &p_desc->item ); + + IPOIB_EXIT( IPOIB_DBG_RECV ); +} + +void +endpt_cm_buf_mgr_put_recv_list( + IN endpt_buf_mgr_t * const p_buf_mgr, + IN cl_qlist_t* const p_list ) +{ + cl_qpool_put_list( &p_buf_mgr->recv_pool, p_list ); +} + +uint32_t +endpt_cm_recv_mgr_build_pkt_array( + IN ipoib_port_t* const p_port, + IN ipoib_endpt_t* const p_endpt, + IN cl_qlist_t* const p_done_list, + IN OUT uint32_t* p_bytes_recv ) +{ + cl_list_item_t *p_item; + ipoib_cm_desc_t *p_desc; + uint32_t i = 0; + NDIS_PACKET *p_packet; + NDIS_TCP_IP_CHECKSUM_PACKET_INFO chksum; + + IPOIB_ENTER( IPOIB_DBG_RECV ); + UNUSED_PARAM( p_endpt ); + + p_item = cl_qlist_remove_head( p_done_list ); + + *p_bytes_recv = 0; + + for( p_item; p_item != cl_qlist_end( p_done_list ); + p_item = cl_qlist_remove_head( p_done_list ) ) + { + p_desc = (ipoib_cm_desc_t*)p_item; + + p_packet = __endpt_cm_get_ndis_pkt( p_port, p_desc ); + if( !p_packet ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to get Packet from descriptor\n" ) ); + endpt_cm_buf_mgr_put_recv( &p_port->cm_buf_mgr, p_desc ); + p_port->cm_recv_mgr.depth--; + continue; + } + chksum.Value = 0; + switch( p_port->p_adapter->params.recv_chksum_offload ) + { + default: + CL_ASSERT( FALSE ); + case CSUM_DISABLED: + case CSUM_ENABLED: + NDIS_PER_PACKET_INFO_FROM_PACKET( p_packet, TcpIpChecksumPacketInfo ) = + (void*)(uintn_t)chksum.Value; + break; + case CSUM_BYPASS: + /* Flag the checksums as having been calculated. */ + chksum.Receive.NdisPacketTcpChecksumSucceeded = TRUE; + chksum.Receive.NdisPacketUdpChecksumSucceeded = TRUE; + chksum.Receive.NdisPacketIpChecksumSucceeded = TRUE; + NDIS_PER_PACKET_INFO_FROM_PACKET( p_packet, TcpIpChecksumPacketInfo ) = + (void*)(uintn_t)chksum.Value; + break; + } + + NDIS_SET_PACKET_STATUS( p_packet, NDIS_STATUS_SUCCESS ); + p_port->cm_recv_mgr.recv_NBL_array[i] = p_packet; + i++; + *p_bytes_recv += p_desc->len; + } + + IPOIB_EXIT( IPOIB_DBG_RECV ); + return i; +} +void +endpt_cm_flush_recv( + IN ipoib_port_t* const p_port, + IN ipoib_endpt_t* const p_endpt ) +{ + ib_api_status_t ib_status = IB_SUCCESS; + ib_qp_mod_t mod_attr; + ib_wc_t wc[MAX_RECV_WC]; + ib_wc_t *p_free_wc; + ib_wc_t *p_done_wc; + ib_wc_t *p_wc; + ipoib_cm_desc_t *p_desc; + + IPOIB_ENTER( IPOIB_DBG_RECV ); + + CL_ASSERT( p_endpt ); + + if( p_endpt->conn.h_recv_qp ) + { + cl_memclr( &mod_attr, sizeof( mod_attr ) ); + mod_attr.req_state = IB_QPS_ERROR; + p_port->p_adapter->p_ifc->modify_qp( p_endpt->conn.h_send_qp, &mod_attr ); + p_port->p_adapter->p_ifc->modify_qp( p_endpt->conn.h_recv_qp, &mod_attr ); + + for( p_free_wc=wc; p_free_wc < &wc[MAX_RECV_WC - 1]; p_free_wc++ ) + p_free_wc->p_next = p_free_wc + 1; + p_free_wc->p_next = NULL; + + do + { + p_free_wc = wc; + ib_status = + p_port->p_adapter->p_ifc->poll_cq( p_endpt->conn.h_recv_cq, + &p_free_wc, &p_done_wc ); + if( ib_status != IB_SUCCESS && + ib_status != IB_NOT_FOUND ) + { + /* connection CQ failed */ + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Poll Recv CQ failed status %#x\n", ib_status ) ); + break; + } + cl_spinlock_acquire( &p_port->recv_lock ); + for( p_wc = p_done_wc; p_wc; p_wc = p_wc->p_next ) + { + p_desc = (ipoib_cm_desc_t *)(uintn_t)p_wc->wr_id; + endpt_cm_buf_mgr_put_recv( &p_port->cm_buf_mgr, p_desc ); + p_port->cm_recv_mgr.depth--; + } + cl_spinlock_release( &p_port->recv_lock ); + } while( !p_free_wc ); + + ib_status = p_port->p_adapter->p_ifc->destroy_qp( p_endpt->conn.h_recv_qp, NULL ); + if( ib_status != IB_SUCCESS ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Destroy Recv QP failed status %#x\n", ib_status ) ); + } + p_endpt->conn.h_recv_qp = NULL; + } + + if( p_endpt->conn.h_send_qp ) + { + ib_status = p_port->p_adapter->p_ifc->destroy_qp( p_endpt->conn.h_send_qp, NULL ); + if( ib_status != IB_SUCCESS ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Destroy Send QP failed status %#x\n", ib_status ) ); + } + p_endpt->conn.h_send_qp = NULL; + } + + IPOIB_EXIT( IPOIB_DBG_RECV ); +} + +int32_t +endpt_cm_recv_mgr_filter( + IN ipoib_endpt_t* const p_endpt, + IN ib_wc_t* const p_done_wc_list, + OUT cl_qlist_t* const p_done_list, + OUT cl_qlist_t* const p_bad_list ) +{ + ib_api_status_t ib_status; + ipoib_cm_desc_t *p_desc; + ib_wc_t *p_wc; + ipoib_pkt_t *p_ipoib; + eth_pkt_t *p_eth; + ipoib_port_t* p_port; + int32_t recv_cnt; + + IPOIB_ENTER( IPOIB_DBG_RECV ); + + p_port = ipoib_endpt_parent( p_endpt ); + + for( p_wc = p_done_wc_list, recv_cnt = 0; p_wc; p_wc = p_wc->p_next ) + { + p_desc = (ipoib_cm_desc_t *)(uintn_t)p_wc->wr_id; + recv_cnt++; + if( p_wc->status != IB_WCS_SUCCESS ) + { + if( p_wc->status != IB_WCS_WR_FLUSHED_ERR ) + { + + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed completion %s (vendor specific %#x)\n", + p_port->p_adapter->p_ifc->get_wc_status_str( p_wc->status ), + (int)p_wc->vendor_specific) ); + } + else + { + IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_RECV, + ("Flushed completion %s\n", + p_port->p_adapter->p_ifc->get_wc_status_str( p_wc->status )) ); + } + + ipoib_inc_recv_stat( p_port->p_adapter, IP_STAT_ERROR, 0, 0 ); + + cl_qlist_remove_item( &p_port->cm_buf_mgr.posted_list, &p_desc->list_item ); + cl_qlist_insert_tail( p_bad_list, &p_desc->item.list_item ); + continue; + } + + /* Successful completion + Setup the ethernet/ip/arp header and queue descriptor for report. */ + ib_status = IB_SUCCESS; + p_ipoib = (ipoib_pkt_t *)((uint8_t*)p_desc->p_buf ); + p_eth = (eth_pkt_t *)((uint8_t*)p_desc->p_buf - DATA_OFFSET ); + + switch( p_ipoib->hdr.type ) + { + case ETH_PROT_TYPE_ARP: + if( p_wc->length < (sizeof(ipoib_hdr_t) + sizeof(ipoib_arp_pkt_t)) ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Received ARP packet too short (wc_len %d)\n", p_wc->length) ); + ib_status = IB_ERROR; + break; + } + ib_status = __endpt_cm_recv_arp( p_port, p_ipoib, p_eth, p_endpt ); + break; + + case ETH_PROT_TYPE_IP: + if( p_wc->length < (sizeof(ipoib_hdr_t) + sizeof(ip_hdr_t)) ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Received IP packet too short (wc_len %d)\n", p_wc->length) ); + ib_status = IB_ERROR; + break; + } + if( p_ipoib->type.ip.hdr.prot == IP_PROT_UDP ) + { + ib_status = __endpt_cm_recv_udp( p_port, + p_wc, + p_ipoib, + p_eth, + p_endpt ); + } + + break; + } + + if( ib_status != IB_SUCCESS ) + { + ipoib_inc_recv_stat( p_port->p_adapter, IP_STAT_ERROR, 0, 0 ); + cl_qlist_insert_tail( p_bad_list, &p_desc->item.list_item ); + continue; + } + + p_eth->hdr.type = p_ipoib->hdr.type; + p_eth->hdr.src = p_endpt->mac; + p_eth->hdr.dst = p_port->p_adapter->mac; + + /* save payload length */ + p_desc->len = p_wc->length; + + cl_qlist_insert_tail( p_done_list, &p_desc->item.list_item ); + } + + IPOIB_EXIT( IPOIB_DBG_RECV ); + return recv_cnt; +} + +ib_api_status_t +endpt_cm_post_recv( + IN ipoib_port_t* const p_port ) +{ + ib_api_status_t ib_status = IB_SUCCESS; + ipoib_cm_desc_t *p_head_desc = NULL; + ipoib_cm_desc_t *p_tail_desc = NULL; + ipoib_cm_desc_t *p_next_desc; + ib_recv_wr_t *p_failed_wc = NULL; + + IPOIB_ENTER( IPOIB_DBG_RECV ); + + while( cl_qpool_count( &p_port->cm_buf_mgr.recv_pool ) > 1 ) + { + /* Pull receives out of the pool and chain them up. */ + p_next_desc = __endpt_cm_buf_mgr_get_recv( + &p_port->cm_buf_mgr ); + if( !p_next_desc ) + { + IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_RECV, + ("Out of receive descriptors! Endpt recv queue depth 0x%x\n", + p_port->cm_recv_mgr.depth ) ); + break; + } + + if( !p_tail_desc ) + { + p_tail_desc = p_next_desc; + p_next_desc->wr.p_next = NULL; + } + else + { + p_next_desc->wr.p_next = &p_head_desc->wr; + } + + p_head_desc = p_next_desc; + + p_port->cm_recv_mgr.depth++; + } + + if( p_head_desc ) + { + ib_status = p_port->p_adapter->p_ifc->post_srq_recv( + p_port->ib_mgr.h_srq, &p_head_desc->wr, &p_failed_wc ); + + if( ib_status != IB_SUCCESS ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ip_post_recv returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( ib_status )) ); + + /* put descriptors back to the pool */ + while( p_failed_wc ) + { + p_head_desc = PARENT_STRUCT( p_failed_wc, ipoib_cm_desc_t, wr ); + p_failed_wc = p_failed_wc->p_next; + endpt_cm_buf_mgr_put_recv( &p_port->cm_buf_mgr, p_head_desc ); + p_port->cm_recv_mgr.depth--; + } + } + } + + + IPOIB_EXIT( IPOIB_DBG_RECV ); + return( ib_status ); +} + +static ib_api_status_t +__endpt_cm_recv_arp( + IN ipoib_port_t* const p_port, + IN const ipoib_pkt_t* const p_ipoib, + OUT eth_pkt_t* const p_eth, + IN ipoib_endpt_t* const p_src_endpt ) +{ + const ipoib_arp_pkt_t *p_ib_arp; + arp_pkt_t *p_arp; + + p_ib_arp = &p_ipoib->type.arp; + p_arp = &p_eth->type.arp; + + if( p_ib_arp->hw_type != ARP_HW_TYPE_IB || + p_ib_arp->hw_size != sizeof(ipoib_hw_addr_t) || + p_ib_arp->prot_type != ETH_PROT_TYPE_IP ) + { + return IB_ERROR; + } + + p_arp->hw_type = ARP_HW_TYPE_ETH; + p_arp->hw_size = sizeof(mac_addr_t); + p_arp->src_hw = p_src_endpt->mac; + p_arp->src_ip = p_ib_arp->src_ip; + p_arp->dst_hw = p_port->p_local_endpt->mac; + p_arp->dst_ip = p_ib_arp->dst_ip; + + return IB_SUCCESS; +} + +static ib_api_status_t +__endpt_cm_recv_udp( + IN ipoib_port_t* const p_port, + IN ib_wc_t* const p_wc, + IN const ipoib_pkt_t* const p_ipoib, + OUT eth_pkt_t* const p_eth, + IN ipoib_endpt_t* const p_src_endpt ) +{ + ib_api_status_t ib_status = IB_SUCCESS; + + if( p_wc->length < + (sizeof(ipoib_hdr_t) + sizeof(ip_hdr_t) + sizeof(udp_hdr_t)) ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Received UDP packet too short\n") ); + return IB_ERROR; + } + if( __cm_recv_is_dhcp( p_ipoib ) ) + { + ib_status = ipoib_recv_dhcp( p_port, + p_ipoib, + p_eth, + p_src_endpt, + p_port->p_local_endpt ); + } + + return ib_status; +} + +static boolean_t +__cm_recv_is_dhcp( + IN const ipoib_pkt_t* const p_ipoib ) +{ + return( (p_ipoib->type.ip.prot.udp.hdr.dst_port == DHCP_PORT_SERVER && + p_ipoib->type.ip.prot.udp.hdr.src_port == DHCP_PORT_CLIENT) || + (p_ipoib->type.ip.prot.udp.hdr.dst_port == DHCP_PORT_CLIENT && + p_ipoib->type.ip.prot.udp.hdr.src_port == DHCP_PORT_SERVER) ); +} +#endif diff --git a/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_endpoint.h b/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_endpoint.h new file mode 100644 index 00000000..6f027a00 --- /dev/null +++ b/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_endpoint.h @@ -0,0 +1,266 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2006 Mellanox Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: ipoib_endpoint.h 4226 2009-04-06 06:01:03Z xalex $ + */ + + +#ifndef _IPOIB_ENDPOINT_H_ +#define _IPOIB_ENDPOINT_H_ + + +#include +#include +#include +#include +#include +#include "iba/ipoib_ifc.h" +#include +#include "ipoib_debug.h" + + +typedef struct _endpt_buf_mgr +{ + cl_qpool_t recv_pool; + NDIS_HANDLE h_packet_pool; + NDIS_HANDLE h_buffer_pool; + cl_qlist_t posted_list; + boolean_t pool_init; +} endpt_buf_mgr_t; + +typedef struct _endpt_recv_mgr +{ + int32_t depth; + int32_t rq_depth; + //NDIS60 + //NDIS_PACKET **recv_NBL_array; + NET_BUFFER_LIST *recv_lst_array; + +} endpt_recv_mgr_t; + + +typedef enum _cm_state +{ + IPOIB_CM_DISCONNECTED, + IPOIB_CM_INIT, + IPOIB_CM_CONNECT, + IPOIB_CM_CONNECTED, + IPOIB_CM_LISTEN, + IPOIB_CM_DREP_SENT, + IPOIB_CM_DREQ_SENT, + IPOIB_CM_REJ_RECVD, + IPOIB_CM_DESTROY +} cm_state_t; + +typedef struct _cm_private_data +{ + ib_net32_t ud_qpn; + ib_net32_t recv_mtu; +} cm_private_data_t; + +typedef struct _endpt_conn +{ + ib_net64_t service_id; + cm_private_data_t private_data; + ib_qp_handle_t h_send_qp; + ib_qp_handle_t h_recv_qp; + ib_qp_handle_t h_work_qp; + ib_cq_handle_t h_send_cq; + ib_cq_handle_t h_recv_cq; + ib_listen_handle_t h_cm_listen; + cm_state_t state; + +} endpt_conn_t; + +typedef struct _ipoib_endpt +{ + cl_obj_t obj; + cl_obj_rel_t rel; + cl_map_item_t mac_item; + cl_fmap_item_t gid_item; + cl_map_item_t lid_item; + cl_fmap_item_t conn_item; + LIST_ENTRY list_item; + ib_query_handle_t h_query; + ib_mcast_handle_t h_mcast; + mac_addr_t mac; + ib_gid_t dgid; + net16_t dlid; + net32_t qpn; + uint8_t cm_flag; + ib_av_handle_t h_av; + endpt_conn_t conn; + + ib_al_ifc_t *p_ifc; + boolean_t is_in_use; + boolean_t is_mcast_listener; +} ipoib_endpt_t; +/* +* FIELDS +* mac_item +* Map item for storing the endpoint in a map. The key is the +* destination MAC address. +* +* lid_item +* Map item for storing the endpoint in a map. The key is the +* destination LID. +* +* gid_item +* Map item for storing the endpoint in a map. The key is the +* destination GID. +* +* h_query +* Query handle for cancelling SA queries. +* +* h_mcast +* For multicast endpoints, the multicast handle. +* +* mac +* MAC address. +* +* dgid +* Destination GID. +* +* dlid +* Destination LID. The destination LID is only set for endpoints +* that are on the same subnet. It is used as key in the LID map. +* +* qpn +* Destination queue pair number. +* +* h_av +* Address vector for sending data. +* +* expired +* Flag to indicate that the endpoint should be flushed. +* +* connection +* for connected mode endpoints +* +* p_ifc +* Reference to transport functions, can be used +* while endpoint is not attached to port yet. +* +* NOTES +* If the h_mcast member is set, the endpoint is never expired. +*********/ + + +ipoib_endpt_t* +ipoib_endpt_create( + IN const ib_gid_t* const p_dgid, + IN const net16_t dlid, + IN const net32_t qpn ); + + +ib_api_status_t +ipoib_endpt_set_mcast( + IN ipoib_endpt_t* const p_endpt, + IN ib_pd_handle_t h_pd, + IN uint8_t port_num, + IN ib_mcast_rec_t* const p_mcast_rec ); + + +static inline void +ipoib_endpt_ref( + IN ipoib_endpt_t* const p_endpt ) +{ + CL_ASSERT( p_endpt ); + + cl_obj_ref( &p_endpt->obj ); +#if DBG + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_OBJ, + ("[%#x] Endpt refcount raised to %d\n", p_endpt, p_endpt->obj.ref_cnt)); +#endif + /* + * Anytime we reference the endpoint, we're either receiving data + * or trying to send data to that endpoint. Clear the expired flag + * to prevent the AV from being flushed. + */ +} + + +static inline void +ipoib_endpt_deref( + IN ipoib_endpt_t* const p_endpt ) +{ + CL_ASSERT(p_endpt->obj.ref_cnt); + cl_obj_deref( &p_endpt->obj ); +#if DBG + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_OBJ, + ("[%#x] Endpt refcount decremented to %d\n", p_endpt, p_endpt->obj.ref_cnt)); +#endif +} + + +NDIS_STATUS +ipoib_endpt_queue( + IN ipoib_endpt_t* const p_endpt ); + +struct _ipoib_port * +ipoib_endpt_parent( + IN ipoib_endpt_t* const p_endpt ); + +inline cm_state_t +endpt_cm_set_state( + IN ipoib_endpt_t* const p_endpt, + IN cm_state_t state ) +{ + return (cm_state_t)InterlockedExchange( + (volatile LONG *)&p_endpt->conn.state, + (LONG)state ); +} + +inline cm_state_t +endpt_cm_get_state( + IN ipoib_endpt_t* const p_endpt ) +{ + return( cm_state_t )InterlockedCompareExchange( + (volatile LONG *)&p_endpt->conn.state, + IPOIB_CM_DISCONNECTED, IPOIB_CM_DISCONNECTED ); +} + +ib_api_status_t +endpt_cm_create_qp( + IN ipoib_endpt_t* const p_endpt, + IN ib_qp_handle_t* const p_h_qp ); + +ib_api_status_t +ipoib_endpt_connect( + IN ipoib_endpt_t* const p_endpt ); + +int32_t +endpt_cm_recv_mgr_filter( + IN ipoib_endpt_t* const p_endpt, + IN ib_wc_t* const p_done_wc_list, + OUT cl_qlist_t* const p_done_list, + OUT cl_qlist_t* const p_bad_list ); + +#endif /* _IPOIB_ENDPOINT_H_ */ diff --git a/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_ibat.cpp b/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_ibat.cpp new file mode 100644 index 00000000..2053b796 --- /dev/null +++ b/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_ibat.cpp @@ -0,0 +1,691 @@ +/* + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: ipoib_ibat.c 4494 2009-06-22 14:31:08Z xalex $ + */ + +#include + + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "ipoib_ibat.tmh" +#endif +#include + +extern PDRIVER_OBJECT g_p_drv_obj; + +static NTSTATUS +__ipoib_create( + IN DEVICE_OBJECT* const pDevObj, + IN IRP* const pIrp ); + +static NTSTATUS +__ipoib_cleanup( + IN DEVICE_OBJECT* const pDevObj, + IN IRP* const pIrp ); + +static NTSTATUS +__ipoib_close( + IN DEVICE_OBJECT* const pDevObj, + IN IRP* const pIrp ); + +static NTSTATUS +__ipoib_dispatch( + IN DEVICE_OBJECT* const pDevObj, + IN IRP* const pIrp ); + + +static NTSTATUS +__ibat_get_ports( + IN IRP *pIrp, + IN IO_STACK_LOCATION *pIoStack ) +{ + IOCTL_IBAT_PORTS_IN *pIn; + IOCTL_IBAT_PORTS_OUT *pOut; + KLOCK_QUEUE_HANDLE hdl; + cl_list_item_t *pItem; + ipoib_adapter_t *pAdapter; + LONG nPorts; + + IPOIB_ENTER(IPOIB_DBG_IOCTL); + + if( pIoStack->Parameters.DeviceIoControl.InputBufferLength != + sizeof(IOCTL_IBAT_PORTS_IN) ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Invalid input buffer size.\n") ); + return STATUS_INVALID_PARAMETER; + } + + if( pIoStack->Parameters.DeviceIoControl.OutputBufferLength < + sizeof(IOCTL_IBAT_PORTS_OUT) ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Invalid output buffer size.\n") ); + return STATUS_INVALID_PARAMETER; + } + + pIn = (IOCTL_IBAT_PORTS_IN *) pIrp->AssociatedIrp.SystemBuffer; + pOut = (IOCTL_IBAT_PORTS_OUT *) pIrp->AssociatedIrp.SystemBuffer; + + if( pIn->Version != IBAT_IOCTL_VERSION ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Invalid version.\n") ); + return STATUS_INVALID_PARAMETER; + } + + KeAcquireInStackQueuedSpinLock( &g_ipoib.lock, &hdl ); + nPorts = (LONG)cl_qlist_count( &g_ipoib.adapter_list ); + switch( nPorts ) + { + case 0: + cl_memclr( pOut->Ports, sizeof(pOut->Ports) ); + /* Fall through */ + case 1: + pOut->Size = sizeof(IOCTL_IBAT_PORTS_OUT); + break; + + default: + pOut->Size = sizeof(IOCTL_IBAT_PORTS_OUT) + + (sizeof(IBAT_PORT_RECORD) * (nPorts - 1)); + break; + } + + pIrp->IoStatus.Information = pOut->Size; + + if( pOut->Size > pIoStack->Parameters.DeviceIoControl.OutputBufferLength ) + { + nPorts = 1 + + (pIoStack->Parameters.DeviceIoControl.OutputBufferLength - + sizeof(IOCTL_IBAT_PORTS_OUT)) / sizeof(IBAT_PORT_RECORD); + + pIrp->IoStatus.Information = sizeof(IOCTL_IBAT_PORTS_OUT) + + ((nPorts - 1) * sizeof(IBAT_PORT_RECORD)); + } + + pOut->NumPorts = 0; + pItem = cl_qlist_head( &g_ipoib.adapter_list ); + while( pOut->NumPorts != nPorts ) + { + pAdapter = CONTAINING_RECORD( pItem, ipoib_adapter_t, entry ); + pOut->Ports[pOut->NumPorts].CaGuid = pAdapter->guids.ca_guid; + pOut->Ports[pOut->NumPorts].PortGuid = pAdapter->guids.port_guid.guid; + pOut->Ports[pOut->NumPorts].PKey = IB_DEFAULT_PKEY; + pOut->Ports[pOut->NumPorts].PortNum = pAdapter->guids.port_num; + pOut->NumPorts++; + + pItem = cl_qlist_next( pItem ); + } + + KeReleaseInStackQueuedSpinLock( &hdl ); + IPOIB_EXIT( IPOIB_DBG_IOCTL ); + return STATUS_SUCCESS; +} + + +static NTSTATUS +__ibat_get_ips( + IN IRP *pIrp, + IN IO_STACK_LOCATION *pIoStack ) +{ + IOCTL_IBAT_IP_ADDRESSES_IN *pIn; + IOCTL_IBAT_IP_ADDRESSES_OUT *pOut; + KLOCK_QUEUE_HANDLE hdl; + cl_list_item_t *pItem; + ipoib_adapter_t *pAdapter; + LONG nIps, maxIps; + size_t idx; + net_address_item_t *pAddr; + UINT64 PortGuid; + + IPOIB_ENTER(IPOIB_DBG_IOCTL); + + if( pIoStack->Parameters.DeviceIoControl.InputBufferLength != + sizeof(IOCTL_IBAT_IP_ADDRESSES_IN) ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Invalid input buffer size.\n") ); + return STATUS_INVALID_PARAMETER; + } + + if( pIoStack->Parameters.DeviceIoControl.OutputBufferLength < + sizeof(IOCTL_IBAT_IP_ADDRESSES_OUT) ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Invalid output buffer size.\n") ); + return STATUS_INVALID_PARAMETER; + } + + pIn = (IOCTL_IBAT_IP_ADDRESSES_IN *) pIrp->AssociatedIrp.SystemBuffer; + pOut = (IOCTL_IBAT_IP_ADDRESSES_OUT *) pIrp->AssociatedIrp.SystemBuffer; + + if( pIn->Version != IBAT_IOCTL_VERSION ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Invalid version.\n") ); + return STATUS_INVALID_PARAMETER; + } + + PortGuid = pIn->PortGuid; + + nIps = 0; + pOut->AddressCount = 0; + maxIps = 1 + + ((pIoStack->Parameters.DeviceIoControl.OutputBufferLength - + sizeof(IOCTL_IBAT_IP_ADDRESSES_OUT)) / sizeof(IP_ADDRESS)); + + KeAcquireInStackQueuedSpinLock( &g_ipoib.lock, &hdl ); + for( pItem = cl_qlist_head( &g_ipoib.adapter_list ); + pItem != cl_qlist_end( &g_ipoib.adapter_list ); + pItem = cl_qlist_next( pItem ) ) + { + pAdapter = CONTAINING_RECORD( pItem, ipoib_adapter_t, entry ); + if( PortGuid && pAdapter->guids.port_guid.guid != PortGuid ) + continue; + + cl_obj_lock( &pAdapter->obj ); + nIps += (LONG)cl_vector_get_size( &pAdapter->ip_vector ); + + for( idx = 0; + idx < cl_vector_get_size( &pAdapter->ip_vector ); + idx++ ) + { + if( pOut->AddressCount == maxIps ) + break; + + pAddr = (net_address_item_t*) + cl_vector_get_ptr( &pAdapter->ip_vector, idx ); + + pOut->Address[pOut->AddressCount].IpVersion = 4; + cl_memclr( &pOut->Address[pOut->AddressCount].Address, + sizeof(IP_ADDRESS) ); + cl_memcpy( &pOut->Address[pOut->AddressCount].Address[12], + pAddr->address.as_bytes, IPV4_ADDR_SIZE ); + + pOut->AddressCount++; + } + cl_obj_unlock( &pAdapter->obj ); + } + + pOut->Size = sizeof(IOCTL_IBAT_IP_ADDRESSES_OUT); + if( --nIps ) + pOut->Size += sizeof(IP_ADDRESS) * nIps; + + pIrp->IoStatus.Information = sizeof(IOCTL_IBAT_IP_ADDRESSES_OUT); + if( --maxIps < nIps ) + pIrp->IoStatus.Information += (sizeof(IP_ADDRESS) * maxIps); + else + pIrp->IoStatus.Information += (sizeof(IP_ADDRESS) * nIps); + + KeReleaseInStackQueuedSpinLock( &hdl ); + IPOIB_EXIT( IPOIB_DBG_IOCTL ); + return STATUS_SUCCESS; +} + + +static NTSTATUS +__ibat_mac_to_gid( + IN IRP *pIrp, + IN IO_STACK_LOCATION *pIoStack ) +{ + NTSTATUS status = STATUS_INVALID_PARAMETER; + IOCTL_IBAT_MAC_TO_GID_IN *pIn; + IOCTL_IBAT_MAC_TO_GID_OUT *pOut; + KLOCK_QUEUE_HANDLE hdl; + cl_list_item_t *pItem; + ipoib_adapter_t *pAdapter; + + IPOIB_ENTER(IPOIB_DBG_IOCTL); + + if( pIoStack->Parameters.DeviceIoControl.InputBufferLength != + sizeof(IOCTL_IBAT_MAC_TO_GID_IN) ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Invalid input buffer size.\n") ); + return STATUS_INVALID_PARAMETER; + } + + if( pIoStack->Parameters.DeviceIoControl.OutputBufferLength != + sizeof(IOCTL_IBAT_MAC_TO_GID_OUT) ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Invalid output buffer size.\n") ); + return STATUS_INVALID_PARAMETER; + } + + pIn = (IOCTL_IBAT_MAC_TO_GID_IN *) pIrp->AssociatedIrp.SystemBuffer; + pOut = (IOCTL_IBAT_MAC_TO_GID_OUT *) pIrp->AssociatedIrp.SystemBuffer; + + if( pIn->Version != IBAT_IOCTL_VERSION ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Invalid version.\n") ); + return STATUS_INVALID_PARAMETER; + } + + KeAcquireInStackQueuedSpinLock( &g_ipoib.lock, &hdl ); + + for( pItem = cl_qlist_head( &g_ipoib.adapter_list ); + pItem != cl_qlist_end( &g_ipoib.adapter_list ); + pItem = cl_qlist_next( pItem ) ) + { + pAdapter = CONTAINING_RECORD( pItem, ipoib_adapter_t, entry ); + if( pIn->PortGuid != pAdapter->guids.port_guid.guid ) + continue; + + /* Found the port - lookup the MAC. */ + cl_obj_lock( &pAdapter->obj ); + if( pAdapter->p_port ) + { + status = ipoib_mac_to_gid( + pAdapter->p_port, *(mac_addr_t*)pIn->DestMac, &pOut->DestGid ); + if( NT_SUCCESS( status ) ) + { + pIrp->IoStatus.Information = + sizeof(IOCTL_IBAT_MAC_TO_GID_OUT); + } + } + cl_obj_unlock( &pAdapter->obj ); + break; + } + + KeReleaseInStackQueuedSpinLock( &hdl ); + + IPOIB_EXIT( IPOIB_DBG_IOCTL ); + return status; +} + + +static NTSTATUS +__ibat_mac_to_path( + IN IRP *pIrp, + IN IO_STACK_LOCATION *pIoStack ) +{ + NTSTATUS status = STATUS_INVALID_PARAMETER; + IOCTL_IBAT_MAC_TO_PATH_IN *pIn; + IOCTL_IBAT_MAC_TO_PATH_OUT *pOut; + KLOCK_QUEUE_HANDLE hdl; + cl_list_item_t *pItem; + ipoib_adapter_t *pAdapter; + + IPOIB_ENTER(IPOIB_DBG_IOCTL); + + if( pIoStack->Parameters.DeviceIoControl.InputBufferLength != + sizeof(IOCTL_IBAT_MAC_TO_PATH_IN) ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Invalid input buffer size.\n") ); + return STATUS_INVALID_PARAMETER; + } + + if( pIoStack->Parameters.DeviceIoControl.OutputBufferLength != + sizeof(IOCTL_IBAT_MAC_TO_PATH_OUT) ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Invalid output buffer size.\n") ); + return STATUS_INVALID_PARAMETER; + } + + pIn = (IOCTL_IBAT_MAC_TO_PATH_IN *) pIrp->AssociatedIrp.SystemBuffer; + pOut = (IOCTL_IBAT_MAC_TO_PATH_OUT *) pIrp->AssociatedIrp.SystemBuffer; + + if( pIn->Version != IBAT_IOCTL_VERSION ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Invalid version.\n") ); + return STATUS_INVALID_PARAMETER; + } + + KeAcquireInStackQueuedSpinLock( &g_ipoib.lock, &hdl ); + + for( pItem = cl_qlist_head( &g_ipoib.adapter_list ); + pItem != cl_qlist_end( &g_ipoib.adapter_list ); + pItem = cl_qlist_next( pItem ) ) + { + pAdapter = CONTAINING_RECORD( pItem, ipoib_adapter_t, entry ); + if( pIn->PortGuid != pAdapter->guids.port_guid.guid ) + continue; + + /* Found the port - lookup the MAC. */ + cl_obj_lock( &pAdapter->obj ); + if( pAdapter->p_port ) + { + status = ipoib_mac_to_path( + pAdapter->p_port, *(mac_addr_t*)pIn->DestMac, &pOut->Path ); + + if( NT_SUCCESS( status ) ) + { + pIrp->IoStatus.Information = + sizeof(IOCTL_IBAT_MAC_TO_PATH_OUT); + } + } + cl_obj_unlock( &pAdapter->obj ); + break; + } + + KeReleaseInStackQueuedSpinLock( &hdl ); + + IPOIB_EXIT( IPOIB_DBG_IOCTL ); + return status; +} + + +static NTSTATUS +__ibat_ip_to_port( + IN IRP *pIrp, + IN IO_STACK_LOCATION *pIoStack ) +{ + IOCTL_IBAT_IP_TO_PORT_IN *pIn; + IOCTL_IBAT_IP_TO_PORT_OUT *pOut; + KLOCK_QUEUE_HANDLE hdl; + cl_list_item_t *pItem; + ipoib_adapter_t *pAdapter; + size_t idx; + net_address_item_t *pAddr; + NTSTATUS status = STATUS_NOT_FOUND; + + IPOIB_ENTER(IPOIB_DBG_IOCTL); + + if( pIoStack->Parameters.DeviceIoControl.InputBufferLength != + sizeof(IOCTL_IBAT_IP_TO_PORT_IN) ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Invalid input buffer size.\n") ); + return STATUS_INVALID_PARAMETER; + } + + if( pIoStack->Parameters.DeviceIoControl.OutputBufferLength != + sizeof(IOCTL_IBAT_IP_TO_PORT_OUT) ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Invalid output buffer size.\n") ); + return STATUS_INVALID_PARAMETER; + } + + pIn = (IOCTL_IBAT_IP_TO_PORT_IN *) pIrp->AssociatedIrp.SystemBuffer; + pOut = (IOCTL_IBAT_IP_TO_PORT_OUT *) pIrp->AssociatedIrp.SystemBuffer; + + if( pIn->Version != IBAT_IOCTL_VERSION ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Invalid version.\n") ); + return STATUS_INVALID_PARAMETER; + } + + if (pIn->Address.IpVersion != 4) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Invalid IP version (%d). Supported only 4\n", pIn->Address.IpVersion) ); + return STATUS_INVALID_PARAMETER; + } + + KeAcquireInStackQueuedSpinLock( &g_ipoib.lock, &hdl ); + for( pItem = cl_qlist_head( &g_ipoib.adapter_list ); + pItem != cl_qlist_end( &g_ipoib.adapter_list ); + pItem = cl_qlist_next( pItem ) ) + { + pAdapter = CONTAINING_RECORD( pItem, ipoib_adapter_t, entry ); + + cl_obj_lock( &pAdapter->obj ); + + for( idx = 0; + idx < cl_vector_get_size( &pAdapter->ip_vector ); + idx++ ) + { + pAddr = (net_address_item_t*) + cl_vector_get_ptr( &pAdapter->ip_vector, idx ); + + if (!memcmp( &pIn->Address.Address[12], pAddr->address.as_bytes, IPV4_ADDR_SIZE)) + { + pOut->Port.CaGuid = pAdapter->guids.ca_guid; + pOut->Port.PortGuid = pAdapter->guids.port_guid.guid; + pOut->Port.PKey = IB_DEFAULT_PKEY; + pOut->Port.PortNum = pAdapter->guids.port_num; + pIrp->IoStatus.Information = sizeof(IOCTL_IBAT_IP_TO_PORT_OUT); + status = STATUS_SUCCESS; + break; + } + } + cl_obj_unlock( &pAdapter->obj ); + if (status == STATUS_SUCCESS) + break; + } + + KeReleaseInStackQueuedSpinLock( &hdl ); + IPOIB_EXIT( IPOIB_DBG_IOCTL ); + return status; +} + +void +ipoib_ref_ibat() +{ + UNICODE_STRING DeviceName; + UNICODE_STRING DeviceLinkUnicodeString; + NDIS_DEVICE_OBJECT_ATTRIBUTES DeviceObjectAttributes; + PDRIVER_DISPATCH DispatchTable[IRP_MJ_MAXIMUM_FUNCTION+1]; + + NDIS_STATUS Status = NDIS_STATUS_SUCCESS; + + IPOIB_ENTER( IPOIB_DBG_IOCTL ); + + if( InterlockedIncrement( &g_ipoib.ibat_ref ) == 1 ) + { + + NdisZeroMemory(DispatchTable, (IRP_MJ_MAXIMUM_FUNCTION+1) * sizeof(PDRIVER_DISPATCH)); + + DispatchTable[IRP_MJ_CREATE] = __ipoib_create; + DispatchTable[IRP_MJ_CLEANUP] = __ipoib_cleanup; + DispatchTable[IRP_MJ_CLOSE] = __ipoib_close; + DispatchTable[IRP_MJ_DEVICE_CONTROL] = __ipoib_dispatch; + DispatchTable[IRP_MJ_INTERNAL_DEVICE_CONTROL] = __ipoib_dispatch; + + + NdisInitUnicodeString( &DeviceName, IBAT_DEV_NAME ); + NdisInitUnicodeString( &DeviceLinkUnicodeString, IBAT_DOS_DEV_NAME ); + + + NdisZeroMemory(&DeviceObjectAttributes, sizeof(NDIS_DEVICE_OBJECT_ATTRIBUTES)); + + DeviceObjectAttributes.Header.Type = NDIS_OBJECT_TYPE_DEFAULT; // type implicit from the context + DeviceObjectAttributes.Header.Revision = NDIS_DEVICE_OBJECT_ATTRIBUTES_REVISION_1; + DeviceObjectAttributes.Header.Size = sizeof(NDIS_DEVICE_OBJECT_ATTRIBUTES); + DeviceObjectAttributes.DeviceName = &DeviceName; + DeviceObjectAttributes.SymbolicName = &DeviceLinkUnicodeString; + DeviceObjectAttributes.MajorFunctions = &DispatchTable[0]; + DeviceObjectAttributes.ExtensionSize = 0; + DeviceObjectAttributes.DefaultSDDLString = NULL; + DeviceObjectAttributes.DeviceClassGuid = 0; + + Status = NdisRegisterDeviceEx( + g_IpoibMiniportDriverHandle, + &DeviceObjectAttributes, + &g_ipoib.h_ibat_dev, + &g_ipoib.h_ibat_dev_handle); + + + + if( Status != NDIS_STATUS_SUCCESS ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("NdisRegisterDeviceEx failed with status of %d\n", Status) ); + } + } + + IPOIB_EXIT( IPOIB_DBG_IOCTL ); +} + + +void +ipoib_deref_ibat() +{ + IPOIB_ENTER( IPOIB_DBG_IOCTL ); + + if( InterlockedDecrement( &g_ipoib.ibat_ref ) ) + { + IPOIB_EXIT( IPOIB_DBG_IOCTL ); + return; + } + + if( g_ipoib.h_ibat_dev ) + { + NdisDeregisterDeviceEx( g_ipoib.h_ibat_dev_handle ); + g_ipoib.h_ibat_dev = NULL; + g_ipoib.h_ibat_dev_handle = NULL; //TODO set here INVALID_HANDLE_VALUE + } + + IPOIB_EXIT( IPOIB_DBG_IOCTL ); +} + + +static NTSTATUS +__ipoib_create( + IN DEVICE_OBJECT* const pDevObj, + IN IRP* const pIrp ) +{ + IPOIB_ENTER( IPOIB_DBG_IOCTL ); + + UNREFERENCED_PARAMETER( pDevObj ); + + ipoib_ref_ibat(); + + pIrp->IoStatus.Status = STATUS_SUCCESS; + pIrp->IoStatus.Information = 0; + IoCompleteRequest( pIrp, IO_NO_INCREMENT ); + + IPOIB_EXIT( IPOIB_DBG_IOCTL ); + return STATUS_SUCCESS; +} + + +static NTSTATUS +__ipoib_cleanup( + IN DEVICE_OBJECT* const pDevObj, + IN IRP* const pIrp ) +{ + IPOIB_ENTER( IPOIB_DBG_IOCTL ); + + UNREFERENCED_PARAMETER( pDevObj ); + + ipoib_deref_ibat(); + + pIrp->IoStatus.Status = STATUS_SUCCESS; + pIrp->IoStatus.Information = 0; + IoCompleteRequest( pIrp, IO_NO_INCREMENT ); + + IPOIB_EXIT( IPOIB_DBG_IOCTL ); + return STATUS_SUCCESS; +} + + +static NTSTATUS +__ipoib_close( + IN DEVICE_OBJECT* const pDevObj, + IN IRP* const pIrp ) +{ + IPOIB_ENTER( IPOIB_DBG_IOCTL ); + + UNREFERENCED_PARAMETER( pDevObj ); + + pIrp->IoStatus.Status = STATUS_SUCCESS; + pIrp->IoStatus.Information = 0; + IoCompleteRequest( pIrp, IO_NO_INCREMENT ); + + IPOIB_EXIT( IPOIB_DBG_IOCTL ); + return STATUS_SUCCESS; +} + + +static NTSTATUS +__ipoib_dispatch( + IN DEVICE_OBJECT* const pDevObj, + IN IRP* const pIrp ) +{ + IO_STACK_LOCATION *pIoStack; + NTSTATUS status = STATUS_SUCCESS; + + IPOIB_ENTER( IPOIB_DBG_IOCTL ); + + UNREFERENCED_PARAMETER( pDevObj ); + + pIoStack = IoGetCurrentIrpStackLocation( pIrp ); + + pIrp->IoStatus.Information = 0; + + switch( pIoStack->Parameters.DeviceIoControl.IoControlCode ) + { + case IOCTL_IBAT_PORTS: + IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_IOCTL, + ("IOCTL_IBAT_PORTS received\n") ); + status = __ibat_get_ports( pIrp, pIoStack ); + break; + + case IOCTL_IBAT_IP_ADDRESSES: + IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_IOCTL, + ("IOCTL_IBAT_IP_ADDRESSES received\n" )); + status = __ibat_get_ips( pIrp, pIoStack ); + break; + + case IOCTL_IBAT_MAC_TO_GID: + IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_IOCTL, + ("IOCTL_IBAT_MAC_TO_GID received\n" )); + status = __ibat_mac_to_gid( pIrp, pIoStack ); + break; + + case IOCTL_IBAT_IP_TO_PORT: + IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_IOCTL, + ("IOCTL_IBAT_IP_TO_PORT received\n" )); + status = __ibat_ip_to_port( pIrp, pIoStack ); + break; + + case IOCTL_IBAT_MAC_TO_PATH: + IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_IOCTL, + ("IOCTL_IBAT_MAC_TO_PATH received\n" )); + status = __ibat_mac_to_path( pIrp, pIoStack ); + break; + + default: + IPOIB_PRINT( TRACE_LEVEL_VERBOSE, IPOIB_DBG_IOCTL, + ("unknow IOCTL code = 0x%x\n", + pIoStack->Parameters.DeviceIoControl.IoControlCode) ); + status = STATUS_INVALID_PARAMETER; + } + + pIrp->IoStatus.Status = status; + IoCompleteRequest( pIrp, IO_NO_INCREMENT ); + + IPOIB_EXIT( IPOIB_DBG_IOCTL ); + return status; +} + + diff --git a/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_ibat.h b/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_ibat.h new file mode 100644 index 00000000..efcb0a6b --- /dev/null +++ b/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_ibat.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: ipoib_ibat.h 1611 2006-08-20 14:48:55Z sleybo $ + */ + + +#ifndef _IPOIB_IBAT_H_ +#define _IPOIB_IBAT_H_ + + +void +ipoib_ref_ibat(); + +void +ipoib_deref_ibat(); + + +#endif /* _IPOIB_IBAT_H_ */ diff --git a/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_log.mc b/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_log.mc new file mode 100644 index 00000000..c10b20b1 --- /dev/null +++ b/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_log.mc @@ -0,0 +1,374 @@ +;/*++ +;============================================================================= +;Copyright (c) 2001 Mellanox Technologies +; +;Module Name: +; +; ipoiblog.mc +; +;Abstract: +; +; IPoIB Driver event log messages +; +;Authors: +; +; Yossi Leybovich +; +;Environment: +; +; Kernel Mode . +; +;============================================================================= +;--*/ +; +MessageIdTypedef = NDIS_ERROR_CODE + +SeverityNames = ( + Success = 0x0:STATUS_SEVERITY_SUCCESS + Informational = 0x1:STATUS_SEVERITY_INFORMATIONAL + Warning = 0x2:STATUS_SEVERITY_WARNING + Error = 0x3:STATUS_SEVERITY_ERROR + ) + +FacilityNames = ( + System = 0x0 + RpcRuntime = 0x2:FACILITY_RPC_RUNTIME + RpcStubs = 0x3:FACILITY_RPC_STUBS + Io = 0x4:FACILITY_IO_ERROR_CODE + IPoIB = 0x7:FACILITY_IPOIB_ERROR_CODE + ) + + +MessageId=0x0001 +Facility=IPoIB +Severity=Warning +SymbolicName=EVENT_IPOIB_PORT_DOWN +Language=English +%2: Network controller link is down. +. + +MessageId=0x0002 +Facility=IPoIB +Severity=Informational +SymbolicName=EVENT_IPOIB_PORT_UP +Language=English +%2: Network controller link is up. +. + + +MessageId=0x0003 +Facility=IPoIB +Severity=Informational +SymbolicName=EVENT_IPOIB_PORT_UP1 +Language=English +%2: Network controller link is up at 2.5Gbps. +. + +MessageId=0x0004 +Facility=IPoIB +Severity=Informational +SymbolicName=EVENT_IPOIB_PORT_UP2 +Language=English +%2: Network controller link is up at 5Gbps. +. + +MessageId=0x0006 +Facility=IPoIB +Severity=Informational +SymbolicName=EVENT_IPOIB_PORT_UP3 +Language=English +%2: Network controller link is up at 10Gbps. +. + +MessageId=0x000a +Facility=IPoIB +Severity=Informational +SymbolicName=EVENT_IPOIB_PORT_UP4 +Language=English +%2: Network controller link is up at 20Gps. +. + +MessageId=0x000e +Facility=IPoIB +Severity=Informational +SymbolicName=EVENT_IPOIB_PORT_UP5 +Language=English +%2: Network controller link is up at 30Gps. +. + +MessageId=0x0012 +Facility=IPoIB +Severity=Informational +SymbolicName=EVENT_IPOIB_PORT_UP6 +Language=English +%2: Network controller link is up at 40Gps. +. + +MessageId=0x001a +Facility=IPoIB +Severity=Informational +SymbolicName=EVENT_IPOIB_PORT_UP7 +Language=English +%2: Network controller link is up at 60Gps. +. + +MessageId=0x0032 +Facility=IPoIB +Severity=Informational +SymbolicName=EVENT_IPOIB_PORT_UP8 +Language=English +%2: Network controller link is up at 120Gps. +. + +MessageId=0x0040 +Facility=IPoIB +Severity=Informational +SymbolicName=EVENT_IPOIB_INIT_SUCCESS +Language=English +%2: Driver Initialized succesfully. +. + +MessageId=0x0041 +Facility=IPoIB +Severity=Error +SymbolicName=EVENT_IPOIB_OPEN_CA +Language=English +%2: Failed to open Channel Adapter. +. + +MessageId=0x0042 +Facility=IPoIB +Severity=Error +SymbolicName=EVENT_IPOIB_ALLOC_PD +Language=English +%2: Failed to allocate Protection Domain. +. + +MessageId=0x0043 +Facility=IPoIB +Severity=Error +SymbolicName=EVENT_IPOIB_CREATE_RECV_CQ +Language=English +%2: Failed to create receive Completion Queue. +. + +MessageId=0x0044 +Facility=IPoIB +Severity=Error +SymbolicName=EVENT_IPOIB_CREATE_SEND_CQ +Language=English +%2: Failed to create send Completion Queue. +. + +MessageId=0x0045 +Facility=IPoIB +Severity=Error +SymbolicName=EVENT_IPOIB_CREATE_QP +Language=English +%2: Failed to create Queue Pair. +. + +MessageId=0x0046 +Facility=IPoIB +Severity=Error +SymbolicName=EVENT_IPOIB_QUERY_QP +Language=English +%2: Failed to get Queue Pair number. +. + +MessageId=0x0047 +Facility=IPoIB +Severity=Error +SymbolicName=EVENT_IPOIB_REG_PHYS +Language=English +%2: Failed to create DMA Memory Region. +. + +MessageId=0x0048 +Facility=IPoIB +Severity=Error +SymbolicName=EVENT_IPOIB_RECV_POOL +Language=English +%2: Failed to create receive descriptor pool. +. + +MessageId=0x0049 +Facility=IPoIB +Severity=Error +SymbolicName=EVENT_IPOIB_RECV_PKT_POOL +Language=English +%2: Failed to create NDIS_PACKET pool for receive indications. +. + +MessageId=0x004A +Facility=IPoIB +Severity=Error +SymbolicName=EVENT_IPOIB_RECV_BUF_POOL +Language=English +%2: Failed to create NDIS_BUFFER pool for receive indications. +. + +MessageId=0x004B +Facility=IPoIB +Severity=Error +SymbolicName=EVENT_IPOIB_SEND_PKT_POOL +Language=English +%2: Failed to create NDIS_PACKET pool for send processing. +. + +MessageId=0x004C +Facility=IPoIB +Severity=Error +SymbolicName=EVENT_IPOIB_SEND_BUF_POOL +Language=English +%2: Failed to create NDIS_BUFFER pool for send processing. +. + +MessageId=0x004D +Facility=IPoIB +Severity=Error +SymbolicName=EVENT_IPOIB_RECV_PKT_ARRAY +Language=English +%2: Failed to allocate receive indication array. +. + +MessageId=0x004E +Facility=IPoIB +Severity=Error +SymbolicName=EVENT_IPOIB_PORT_INFO_TIMEOUT +Language=English +%2: Subnet Administrator query for port information timed out. +Make sure the SA is functioning properly. Increasing the number +of retries and retry timeout adapter parameters may solve the +issue. +. + +MessageId=0x004F +Facility=IPoIB +Severity=Error +SymbolicName=EVENT_IPOIB_PORT_INFO_REJECT +Language=English +%2: Subnet Administrator failed the query for port information. +Make sure the SA is functioning properly and compatible. +. + +MessageId=0x0050 +Facility=IPoIB +Severity=Error +SymbolicName=EVENT_IPOIB_QUERY_PORT_INFO +Language=English +%2: Subnet Administrator query for port information failed. +. + +MessageId=0x0055 +Facility=IPoIB +Severity=Error +SymbolicName=EVENT_IPOIB_BCAST_GET +Language=English +%2: Subnet Administrator failed query for broadcast group information. +. + +MessageId=0x0056 +Facility=IPoIB +Severity=Error +SymbolicName=EVENT_IPOIB_BCAST_JOIN +Language=English +%2: Subnet Administrator failed request to joing broadcast group. +. + +MessageId=0x0057 +Facility=IPoIB +Severity=Error +SymbolicName=EVENT_IPOIB_BCAST_RATE +Language=English +%2: The local port rate is too slow for the existing broadcast MC group. +. + +MessageId=0x0058 +Facility=IPoIB +Severity=Error +SymbolicName=EVENT_IPOIB_WRONG_PARAMETER_ERR +Language=English +%2: Incorrect value or non-existing registry for the required IPoIB parameter %3, overriding it by default value: %4 +. + +MessageId=0x0059 +Facility=IPoIB +Severity=Warning +SymbolicName=EVENT_IPOIB_WRONG_PARAMETER_WRN +Language=English +%2: Incorrect value or non-existing registry entry for the required IPoIB parameter %3, overriding it by default value: %4 +. + +MessageId=0x005A +Facility=IPoIB +Severity=Informational +SymbolicName=EVENT_IPOIB_WRONG_PARAMETER_INFO +Language=English +%2: Incorrect value or non-existing registry for the optional IPoIB parameter %3, overriding it by default value: %4 +. + +MessageId=0x005B +Facility=IPoIB +Severity=Error +SymbolicName=EVENT_IPOIB_PARTITION_ERR +Language=English +%2: Pkey index not found for partition , change switch pkey configuration. +. + +MessageId=0x005C +Facility=IPoIB +Severity=Error +SymbolicName=EVENT_IPOIB_CONNECTED_MODE_ERR +Language=English +%2: Connected Mode failed to initialize, disabled. Interface will use default UD QP transport. +. +MessageId=0x005D +Facility=IPoIB +Severity=Informational +SymbolicName=EVENT_IPOIB_CONNECTED_MODE_UP +Language=English +%2: Connected Mode initialized and operational. +. + +MessageId=0x005E +Facility=IPoIB +Severity=Error +SymbolicName=EVENT_IPOIB_START_UP_DEV_REG_ATTR +Language=English +%2: SetDeviceRegistrationAttributes failed. +. + +MessageId=0x005F +Facility=IPoIB +Severity=Error +SymbolicName=EVENT_IPOIB_START_UP_ADAPTER_REG_ATTR +Language=English +%2: SetAdapterRegistrationAttributes failed. +. + +MessageId=0x0060 +Facility=IPoIB +Severity=Error +SymbolicName=EVENT_IPOIB_START_UP_SET_OFFLOAD_ATTR +Language=English +%2: SetOffloadAttributes failed. +. + +MessageId=0x0061 +Facility=IPoIB +Severity=Error +SymbolicName=EVENT_IPOIB_START_UP_CREATE_ADAPTER +Language=English +%2: ipoib_create_adapter failed. +. + +MessageId=0x0062 +Facility=IPoIB +Severity=Error +SymbolicName=EVENT_IPOIB_START_UP_START_ADAPTER +Language=English +%2: ipoib_start_adapter failed. +. + + diff --git a/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_port.cpp b/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_port.cpp new file mode 100644 index 00000000..aaf598a8 --- /dev/null +++ b/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_port.cpp @@ -0,0 +1,8698 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2006 Mellanox Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: ipoib_port.c 4506 2009-06-23 14:40:54Z xalex $ + */ + +#include "precompile.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "ipoib_port.tmh" +#endif +#include + +#include "wdm.h" +#include + +extern ULONG g_ipoib_send; +extern ULONG g_ipoib_send_ack; +extern ULONG g_ipoib_send_SW; +extern ULONG g_ipoib_send_SG; +extern ULONG g_ipoib_send_SW_in_loop; +extern ULONG g_ipoib_send_SG_pending; +extern ULONG g_ipoib_send_SG_real; +extern ULONG g_ipoib_send_SG_failed; +extern ULONG g_ipoib_send_reset; + + + + + +ib_gid_t bcast_mgid_template = { + 0xff, /* multicast field */ + 0x12, /* scope (to be filled in) */ + 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 */ +}; + + +#ifdef _DEBUG_ +/* Handy pointer for debug use. */ +ipoib_port_t *gp_ipoib_port; +#endif + +static void __port_mcast_garbage_dpc(KDPC *p_gc_dpc,void *context,void *s_arg1, void *s_arg2); +static void __port_do_mcast_garbage(ipoib_port_t* const p_port ); + +#if 0 +#ifndef _IPOIB_DEBUG_NDIS6 +#define _IPOIB_DEBUG_NDIS6 +CL_INLINE void CL_API +cl_qlist_check_validity( + IN cl_qlist_t* const p_list ) +{ + cl_list_item_t *p_item; + size_t cnt = 0; + + /* 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); + while(p_item != cl_qlist_end(p_list)) { + ++cnt; + CL_ASSERT(p_item->p_list == p_list); + p_item = p_item->p_next; + CL_ASSERT (cnt <= p_list->count); + } + CL_ASSERT (cnt == p_list->count); + return; +} +#endif +#endif +/****************************************************************************** +* +* Declarations +* +******************************************************************************/ +static void +__port_construct( + IN ipoib_port_t* const p_port ); + +static ib_api_status_t +__port_init( + IN ipoib_port_t* const p_port, + IN ipoib_adapter_t* const p_adapter, + IN ib_pnp_port_rec_t* const p_pnp_rec ); + +static void +__port_destroying( + IN cl_obj_t* const p_obj ); + +static void +__port_cleanup( + IN cl_obj_t* const p_obj ); + +static void +__port_free( + IN cl_obj_t* const p_obj ); + +static ib_api_status_t +__port_query_ca_attrs( + IN ipoib_port_t* const p_port, + IN ib_ca_attr_t** pp_ca_attrs ); + +static void +__srq_async_event_cb( +IN ib_async_event_rec_t *p_event_rec ); + +/****************************************************************************** +* +* IB resource manager operations +* +******************************************************************************/ +static void +__ib_mgr_construct( + IN ipoib_port_t* const p_port ); + +static ib_api_status_t +__ib_mgr_init( + IN ipoib_port_t* const p_port ); + +static void +__ib_mgr_destroy( + IN ipoib_port_t* const p_port ); + +static void +__qp_event( + IN ib_async_event_rec_t *p_event_rec ); + +static void +__cq_event( + IN ib_async_event_rec_t *p_event_rec ); + +static ib_api_status_t +__ib_mgr_activate( + IN ipoib_port_t* const p_port ); + +/****************************************************************************** +* +* Buffer manager operations. +* +******************************************************************************/ +static void +__buf_mgr_construct( + IN ipoib_port_t* const p_port ); + +static ib_api_status_t +__buf_mgr_init( + IN ipoib_port_t* const p_port ); + +static void +__buf_mgr_destroy( + IN ipoib_port_t* const p_port ); + +static cl_status_t +__recv_ctor( + IN void* const p_object, + IN void* context, + OUT cl_pool_item_t** const pp_pool_item ); + +#if !IPOIB_INLINE_RECV +static void +__recv_dtor( + IN const cl_pool_item_t* const p_pool_item, + IN void *context ); +#endif + +static inline ipoib_send_desc_t* +__buf_mgr_get_send( + IN ipoib_port_t* const p_port ); + +static inline void +__buf_mgr_put_send( + IN ipoib_port_t* const p_port, + IN ipoib_send_desc_t* const p_desc ); + +static inline ipoib_recv_desc_t* +__buf_mgr_get_recv( + IN ipoib_port_t* const p_port ); + +static inline void +__buf_mgr_put_recv( + IN ipoib_port_t* const p_port, + IN ipoib_recv_desc_t* const p_desc, + IN NET_BUFFER_LIST* const p_net_buffer_list OPTIONAL ); + +static inline void +__buf_mgr_put_recv_list( + IN ipoib_port_t* const p_port, + IN cl_qlist_t* const p_list ); + +//NDIS60 +static inline NET_BUFFER_LIST* +__buf_mgr_get_NBL( + IN ipoib_port_t* const p_port, + IN ipoib_recv_desc_t* const p_desc ); + + +/****************************************************************************** +* +* Receive manager operations. +* +******************************************************************************/ +static void +__recv_mgr_construct( + IN ipoib_port_t* const p_port ); + +static ib_api_status_t +__recv_mgr_init( + IN ipoib_port_t* const p_port ); + +static void +__recv_mgr_destroy( + IN ipoib_port_t* const p_port ); + +/* Posts receive buffers to the receive queue. */ +int32_t +__recv_mgr_repost( + IN ipoib_port_t* const p_port ); + +static void +__recv_cb( + IN const ib_cq_handle_t h_cq, + IN void *cq_context ); + +static void +__recv_get_endpts( + IN ipoib_port_t* const p_port, + IN ipoib_recv_desc_t* const p_desc, + IN ib_wc_t* const p_wc, + OUT ipoib_endpt_t** const pp_src, + OUT ipoib_endpt_t** const pp_dst ); + +static int32_t +__recv_mgr_filter( + IN ipoib_port_t* const p_port, + IN ib_wc_t* const p_done_wc_list, + OUT cl_qlist_t* const p_done_list, + OUT cl_qlist_t* const p_bad_list ); + +static ib_api_status_t +__recv_gen( + IN const ipoib_pkt_t* const p_ipoib, + OUT eth_pkt_t* const p_eth, + IN ipoib_endpt_t* const p_src, + IN ipoib_endpt_t* const p_dst ); + +static ib_api_status_t +__recv_dhcp( + IN ipoib_port_t* const p_port, + IN const ipoib_pkt_t* const p_ipoib, + OUT eth_pkt_t* const p_eth, + IN ipoib_endpt_t* const p_src, + IN ipoib_endpt_t* const p_dst ); + +static ib_api_status_t +__recv_arp( + IN ipoib_port_t* const p_port, + IN ib_wc_t* const p_wc, + IN const ipoib_pkt_t* const p_ipoib, + OUT eth_pkt_t* const p_eth, + IN ipoib_endpt_t** const p_src, + IN ipoib_endpt_t* const p_dst ); + +static ib_api_status_t +__recv_mgr_prepare_NBL( + IN ipoib_port_t* const p_port, + IN ipoib_recv_desc_t* const p_desc, + OUT NET_BUFFER_LIST** const pp_net_buffer_list ); + +static uint32_t +__recv_mgr_build_NBL_array( + IN ipoib_port_t* const p_port, + OUT cl_qlist_t* p_done_list, + OUT int32_t* const p_discarded ); + +/****************************************************************************** +* +* Send manager operations. +* +******************************************************************************/ +static void +__send_mgr_construct( + IN ipoib_port_t* const p_port ); + +static ib_api_status_t +__send_mgr_init( + IN ipoib_port_t* const p_port ); + + +static void +__send_mgr_destroy( + IN ipoib_port_t* const p_port ); + +static NDIS_STATUS +__send_gen( + IN ipoib_send_NB_SG * s_buf, + IN INT lso_data_index, + IN UINT lso_header_size OPTIONAL); + +static NDIS_STATUS +__send_mgr_filter_ip( + IN const eth_hdr_t* const p_eth_hdr, + IN MDL* p_mdl, + IN size_t buf_len, + IN OUT ipoib_send_NB_SG* const s_buf); + +static NDIS_STATUS +__send_mgr_filter_igmp_v2( + IN ipoib_port_t* const p_port, + IN const ip_hdr_t* const p_ip_hdr, + IN size_t iph_options_size, + IN MDL* p_mdl, + IN size_t buf_len ); + +static NDIS_STATUS +__send_mgr_filter_udp( + IN const ip_hdr_t* const p_ip_hdr, + IN MDL* p_mdl, + IN size_t buf_len, + IN OUT ipoib_send_NB_SG* const s_buf); + +static NDIS_STATUS +__send_mgr_filter_dhcp( + IN const udp_hdr_t* const p_udp_hdr, + IN MDL* p_mdl, + IN size_t buf_len, + IN OUT ipoib_send_NB_SG* const s_buf ); + +static NDIS_STATUS +__send_mgr_filter_arp( + IN const eth_hdr_t* const p_eth_hdr, + IN MDL* p_mdl, + IN size_t buf_len, + IN OUT ipoib_send_NB_SG* const s_buf ); + +static inline void +__send_complete_net_buffer( + IN ipoib_send_NB_SG *s_buf, + IN NDIS_STATUS status, + IN ULONG compl_flags, + IN boolean_t bLock ); + + +static inline NDIS_STATUS +__send_mgr_queue( + IN ipoib_port_t* const p_port, + IN eth_hdr_t* const p_eth_hdr, + OUT ipoib_endpt_t** const pp_endpt ); + +static NDIS_STATUS +__build_send_desc( + IN eth_hdr_t* const p_eth_hdr, + IN MDL* const p_mdl, + IN const size_t mdl_len, + IN ipoib_send_NB_SG *s_buf); + + +static void +__send_cb( + IN const ib_cq_handle_t h_cq, + IN void *cq_context ); + +static NDIS_STATUS +GetLsoHeaderSize( + IN PNET_BUFFER pNetBuffer, + IN LsoData *pLsoData, + OUT UINT *IndexOfData, + IN ipoib_hdr_t *ipoib_hdr ); + + +static NDIS_STATUS +__build_lso_desc( + IN ipoib_port_t* const p_port, + IN ULONG mss, + IN int32_t hdr_idx, + IN PNDIS_TCP_LARGE_SEND_OFFLOAD_NET_BUFFER_LIST_INFO p_lso_info, + IN NET_BUFFER *p_netbuf); + +//TODO CM Restore +#if 0 + +static NDIS_STATUS +__send_fragments( + IN ipoib_port_t* const p_port, + IN ipoib_send_desc_t* const p_desc, + IN eth_hdr_t* const p_eth_hdr, + IN ip_hdr_t* const p_ip_hdr, + IN uint32_t buf_len, + IN NDIS_BUFFER* p_ndis_buf ); + + +static void +__update_fragment_ip_hdr( +IN ip_hdr_t* const p_ip_hdr, +IN uint16_t fragment_size, +IN uint16_t fragment_offset, +IN BOOLEAN more_fragments ); + +static void +__copy_ip_options( +IN uint8_t* p_buf, +IN uint8_t* p_options, +IN uint32_t options_len, +IN BOOLEAN copy_all ); +#endif +/****************************************************************************** +* +* Endpoint manager operations +* +******************************************************************************/ +static void +__endpt_mgr_construct( + IN ipoib_port_t* const p_port ); + +static ib_api_status_t +__endpt_mgr_init( + IN ipoib_port_t* const p_port ); + +static void +__endpt_mgr_destroy( + IN ipoib_port_t* const p_port ); + +/****f* IPoIB/__endpt_mgr_remove_all +* NAME +* __endpt_mgr_remove_all +* +* DESCRIPTION +* Removes all enpoints from the port, dereferencing them to initiate +* destruction. +* +* SYNOPSIS +*/ +static void +__endpt_mgr_remove_all( + IN ipoib_port_t* const p_port ); +/* +********/ + +static void +__endpt_mgr_remove( + IN ipoib_port_t* const p_port, + IN ipoib_endpt_t* const p_endpt ); + +static void +__endpt_mgr_reset_all( + IN ipoib_port_t* const p_port ); + +static inline NDIS_STATUS +__endpt_mgr_ref( + IN ipoib_port_t* const p_port, + IN const mac_addr_t mac, + OUT ipoib_endpt_t** const pp_endpt ); + +static inline NDIS_STATUS +__endpt_mgr_get_gid_qpn( + IN ipoib_port_t* const p_port, + IN const mac_addr_t mac, + OUT ib_gid_t* const p_gid, + OUT UNALIGNED net32_t* const p_qpn ); + +static inline ipoib_endpt_t* +__endpt_mgr_get_by_gid( + IN ipoib_port_t* const p_port, + IN const ib_gid_t* const p_gid ); + +static inline ipoib_endpt_t* +__endpt_mgr_get_by_lid( + IN ipoib_port_t* const p_port, + IN const net16_t lid ); + +static inline ib_api_status_t +__endpt_mgr_insert_locked( + IN ipoib_port_t* const p_port, + IN const mac_addr_t mac, + IN ipoib_endpt_t* const p_endpt ); + +static inline ib_api_status_t +__endpt_mgr_insert( + IN ipoib_port_t* const p_port, + IN const mac_addr_t mac, + IN ipoib_endpt_t* const p_endpt ); + +static ib_api_status_t +__endpt_mgr_add_local( + IN ipoib_port_t* const p_port, + IN ib_port_info_t* const p_port_info ); + +static ib_api_status_t +__endpt_mgr_add_bcast( + IN ipoib_port_t* const p_port, + IN ib_mcast_rec_t *p_mcast_rec ); + +/****************************************************************************** +* +* MCast operations. +* +******************************************************************************/ +static ib_api_status_t +__port_get_bcast( + IN ipoib_port_t* const p_port ); + +static ib_api_status_t +__port_join_bcast( + IN ipoib_port_t* const p_port, + IN ib_member_rec_t* const p_member_rec ); + +static ib_api_status_t +__port_create_bcast( + IN ipoib_port_t* const p_port ); + + + +static void +__bcast_get_cb( + IN ib_query_rec_t *p_query_rec ); + + +static void +__bcast_cb( + IN ib_mcast_rec_t *p_mcast_rec ); + + +static void +__mcast_cb( + IN ib_mcast_rec_t *p_mcast_rec ); + +void +__leave_error_mcast_cb( + IN void *context ); + + +static int +__gid_cmp( + IN const void* const p_key1, + IN const void* const p_key2 ) +{ + return cl_memcmp( p_key1, p_key2, sizeof(ib_gid_t) ); +} + + +inline void ipoib_port_ref( ipoib_port_t * p_port, int type ) +{ + cl_obj_ref( &p_port->obj ); +#if DBG + cl_atomic_inc( &p_port->ref[type % ref_mask] ); + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_OBJ, + ("Port[%d] refcount raised to %d\n", p_port->port_num, p_port->obj.ref_cnt)); + + if ((p_port->obj.ref_cnt % 20)==0) + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_OBJ, + ("ref type %d ref_cnt %d\n", type, p_port->obj.ref_cnt) ); +#else + UNREFERENCED_PARAMETER(type); +#endif +} + + +inline void ipoib_port_deref(ipoib_port_t * p_port, int type) +{ + cl_obj_deref( &p_port->obj ); +#if DBG + cl_atomic_dec( &p_port->ref[type % ref_mask] ); + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_OBJ, + ("Port[%d] refcount-- to %d\n", p_port->port_num, p_port->obj.ref_cnt)); + + if ((p_port->obj.ref_cnt % 20) == 0) + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_OBJ, + ("deref type %d ref_cnt %d\n", type, p_port->obj.ref_cnt) ); +#else + UNREFERENCED_PARAMETER(type); +#endif +} + +/* function returns pointer to payload that is going after IP header. +* asssuming that payload and IP header are in the same buffer +*/ +static void* GetIpPayloadPtr(const ip_hdr_t* const p_ip_hdr) +{ + return (void*)((uint8_t*)p_ip_hdr + IP_HEADER_LENGTH(p_ip_hdr)); +} + +/****************************************************************************** +* +* Implementation +* +******************************************************************************/ +ib_api_status_t +ipoib_create_port( + IN ipoib_adapter_t* const p_adapter, + IN ib_pnp_port_rec_t* const p_pnp_rec, + OUT ipoib_port_t** const pp_port ) +{ + ib_api_status_t status; + ipoib_port_t *p_port; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + CL_ASSERT( !p_adapter->p_port ); + + p_port = (ipoib_port_t *) cl_zalloc( sizeof(ipoib_port_t) + + (sizeof(ipoib_hdr_t) * (p_adapter->params.sq_depth - 1)) ); + if( !p_port ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to allocate ipoib_port_t (%d bytes)\n", + sizeof(ipoib_port_t)) ); + return IB_INSUFFICIENT_MEMORY; + } + +#ifdef _DEBUG_ + gp_ipoib_port = p_port; +#endif + + __port_construct( p_port ); + + status = __port_init( p_port, p_adapter, p_pnp_rec ); + if( status != IB_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ipoib_port_init returned %s.\n", + p_adapter->p_ifc->get_err_str( status )) ); + __port_cleanup( &p_port->obj ); + __port_free( &p_port->obj ); + return status; + } + + *pp_port = p_port; + IPOIB_EXIT( IPOIB_DBG_INIT ); + return IB_SUCCESS; +} + + +void +ipoib_port_destroy( + IN ipoib_port_t* const p_port ) +{ + IPOIB_ENTER( IPOIB_DBG_INIT ); + + CL_ASSERT( p_port ); + CL_ASSERT( p_port->p_adapter ); + CL_ASSERT( !p_port->p_adapter->p_port ); + + cl_obj_destroy( &p_port->obj ); + + IPOIB_EXIT( IPOIB_DBG_INIT ); +} + + +static void +__port_construct( + IN ipoib_port_t* const p_port ) +{ + IPOIB_ENTER( IPOIB_DBG_INIT ); + + p_port->state = IB_QPS_RESET; + + cl_obj_construct( &p_port->obj, IPOIB_OBJ_PORT ); + cl_spinlock_construct( &p_port->send_lock ); + cl_spinlock_construct( &p_port->recv_lock ); + __ib_mgr_construct( p_port ); + __buf_mgr_construct( p_port ); + + __recv_mgr_construct( p_port ); + __send_mgr_construct( p_port ); + + __endpt_mgr_construct( p_port ); + + p_port->pPoWorkItem = NULL; + + KeInitializeEvent( &p_port->sa_event, NotificationEvent, TRUE ); + KeInitializeEvent( &p_port->leave_mcast_event, NotificationEvent, TRUE ); + + IPOIB_EXIT( IPOIB_DBG_INIT ); +} + + +static ib_api_status_t +__port_init( + IN ipoib_port_t* const p_port, + IN ipoib_adapter_t* const p_adapter, + IN ib_pnp_port_rec_t* const p_pnp_rec ) +{ + cl_status_t cl_status; + ib_api_status_t status; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + p_port->port_num = p_pnp_rec->p_port_attr->port_num; + p_port->p_adapter = p_adapter; + + p_port->pPoWorkItem = IoAllocateWorkItem(p_adapter->pdo); + + if( p_port->pPoWorkItem == NULL ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("IoAllocateWorkItem returned NULL\n") ); + return IB_ERROR; + } + + cl_status = cl_spinlock_init( &p_port->send_lock ); + if( cl_status != CL_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("cl_spinlock_init returned %#x\n", cl_status) ); + return IB_ERROR; + } + + cl_status = cl_spinlock_init( &p_port->recv_lock ); + if( cl_status != CL_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("cl_spinlock_init returned %#x\n", cl_status) ); + return IB_ERROR; + } + + /* Initialize the IB resource manager. */ + status = __ib_mgr_init( p_port ); + if( status != IB_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("__ib_mgr_init returned %s\n", + p_adapter->p_ifc->get_err_str( status )) ); + return status; + } + + /* Initialize the buffer manager. */ + status = __buf_mgr_init( p_port ); + if( status != IB_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("__buf_mgr_init returned %s\n", + p_adapter->p_ifc->get_err_str( status )) ); + return status; + } + + /* Initialize the receive manager. */ + status = __recv_mgr_init( p_port ); + if( status != IB_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("__recv_mgr_init returned %s\n", + p_adapter->p_ifc->get_err_str( status )) ); + return status; + } + + status =__send_mgr_init( p_port ); + if( status != IB_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("__send_mgr_init returned %s\n", + p_adapter->p_ifc->get_err_str( status )) ); + return status; + } + + /* Initialize the endpoint manager. */ + status = __endpt_mgr_init( p_port ); + if( status != IB_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("__endpt_mgr_init returned %s\n", + p_adapter->p_ifc->get_err_str( status )) ); + return status; + } + + /* Initialize multicast garbage collector timer and DPC object */ + KeInitializeDpc(&p_port->gc_dpc,(PKDEFERRED_ROUTINE)__port_mcast_garbage_dpc,p_port); + KeInitializeTimerEx(&p_port->gc_timer,SynchronizationTimer); + + /* We only ever destroy from the PnP callback thread. */ + cl_status = cl_obj_init( &p_port->obj, CL_DESTROY_SYNC, + __port_destroying, __port_cleanup, __port_free ); + +#if 0 + cl_atomic_inc( &p_port->ref[ref_init] ); + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_OBJ, + ("ref type %d ref_cnt %d\n", ref_init, p_port->obj.ref_cnt) ); +#endif + + if( cl_status != CL_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("cl_obj_init returned %#x\n", cl_status) ); + return IB_ERROR; + } + + cl_status = cl_obj_insert_rel( &p_port->rel, &p_adapter->obj, &p_port->obj ); + if( cl_status != CL_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("cl_obj_insert_rel returned %#x\n", cl_status) ); + cl_obj_destroy( &p_port->obj ); + return IB_ERROR; + } + +#if 0 + cl_atomic_inc( &p_port->ref[ref_init] ); + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_OBJ, + ("ref type %d ref_cnt %d\n", ref_init, p_port->obj.ref_cnt) ); +#endif + // The port is started as paused and NDIS calls latter to ipoib_restart. We + // shut the recv_shuter for now and alive it on ipoib_restart. We did + // it in this way since MpInitializeInternal also calls in reset and than + // we need to set the rec ref count to 1 //TODO !!!!!!!!!!1 + // + + if ( p_adapter->ipoib_state == IPOIB_INIT) { + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_RECV, + ("Shutter shut, state = %d\n", p_adapter->ipoib_state)); + shutter_shut ( &p_adapter->recv_shutter ); + } + else { + IPOIB_PRINT( TRACE_LEVEL_WARNING, IPOIB_DBG_RECV, + ("*****Shutter wasn't shut, state = %d*****\n", p_adapter->ipoib_state)); + } + IPOIB_EXIT( IPOIB_DBG_INIT ); + return IB_SUCCESS; +} + + +static void +__port_destroying( + IN cl_obj_t* const p_obj ) +{ + ipoib_port_t *p_port; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + CL_ASSERT( p_obj ); + + p_port = PARENT_STRUCT( p_obj, ipoib_port_t, obj ); + + ipoib_port_down( p_port ); + + __endpt_mgr_remove_all( p_port ); + +#if 0 + if( p_port->p_adapter->params.cm_enabled ) + { + endpt_cm_buf_mgr_destroy( p_port ); + ipoib_port_srq_destroy( p_port ); + p_port->endpt_mgr.thread_is_done = 1; + cl_event_signal( &p_port->endpt_mgr.event ); + } +#endif + cl_spinlock_acquire(&p_port->send_lock); + ipoib_port_resume( p_port, FALSE ); + cl_spinlock_release(&p_port->send_lock); + + IPOIB_EXIT( IPOIB_DBG_INIT ); +} + + +static void +__port_cleanup( + IN cl_obj_t* const p_obj ) +{ + ipoib_port_t *p_port; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + CL_ASSERT( p_obj ); + + p_port = PARENT_STRUCT( p_obj, ipoib_port_t, obj ); + + /* Wait for all sends and receives to get flushed. */ + while( p_port->send_mgr.depth || p_port->recv_mgr.depth ) + cl_thread_suspend( 0 ); + + /* Destroy the send and receive managers before closing the CA. */ + __ib_mgr_destroy( p_port ); + + IPOIB_EXIT( IPOIB_DBG_INIT ); +} + + +static void +__port_free( + IN cl_obj_t* const p_obj ) +{ + ipoib_port_t *p_port; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + CL_ASSERT( p_obj ); + + p_port = PARENT_STRUCT( p_obj, ipoib_port_t, obj ); + + KeCancelTimer(&p_port->gc_timer); + KeFlushQueuedDpcs(); + __endpt_mgr_destroy( p_port ); + __recv_mgr_destroy( p_port ); + __send_mgr_destroy( p_port ); + __buf_mgr_destroy( p_port ); + + cl_spinlock_destroy( &p_port->send_lock ); + cl_spinlock_destroy( &p_port->recv_lock ); + + cl_obj_deinit( p_obj ); + if( p_port->p_ca_attrs ) + { + cl_free ( p_port->p_ca_attrs ); + } + + IoFreeWorkItem( p_port->pPoWorkItem ); + cl_free( p_port ); + + IPOIB_EXIT( IPOIB_DBG_INIT ); +} + + + +/****************************************************************************** +* +* IB resource manager implementation. +* +******************************************************************************/ +static void +__ib_mgr_construct( + IN ipoib_port_t* const p_port ) +{ + cl_memclr( &p_port->ib_mgr, sizeof(ipoib_ib_mgr_t) ); +} + + +static ib_api_status_t +__ib_mgr_init( + IN ipoib_port_t* const p_port ) +{ + ib_api_status_t status; + ib_cq_create_t cq_create; + ib_qp_create_t qp_create; + ib_phys_create_t phys_create; + ib_phys_range_t phys_range; + uint64_t vaddr; + net32_t rkey; + ib_qp_attr_t qp_attr; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + /* Open the CA. */ + status = p_port->p_adapter->p_ifc->open_ca( p_port->p_adapter->h_al, + p_port->p_adapter->guids.ca_guid, + NULL, + p_port, + &p_port->ib_mgr.h_ca ); + if( status != IB_SUCCESS ) + { + NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter, + EVENT_IPOIB_OPEN_CA, 1, status ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_open_ca(port %p) returns %s\n", + p_port, p_port->p_adapter->p_ifc->get_err_str( status )) ); + return status; + } + + status = __port_query_ca_attrs( p_port, &p_port->p_ca_attrs ); + if( status != IB_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Query CA attributes failed\n" ) ); + return status; + } +#if 0 + if( p_port->p_adapter->params.cm_enabled ) + { + uint32_t payload_mtu = __port_attr_to_mtu_size( + p_port->p_ca_attrs->p_port_attr[p_port->port_num - 1].mtu ) + - sizeof(ipoib_hdr_t); + + /* adjust ipoib UD payload MTU to actual port MTU size. */ + p_port->p_adapter->params.payload_mtu = + max( DEFAULT_PAYLOAD_MTU, payload_mtu ); + p_port->p_adapter->params.xfer_block_size = + (sizeof(eth_hdr_t) + p_port->p_adapter->params.payload_mtu); + } +#endif + +#if IPOIB_USE_DMA + /* init DMA only once while running MiniportInitialize */ + if ( !p_port->p_adapter->reset ) + { + ULONG max_phys_mapping; + + if( p_port->p_adapter->params.cm_enabled ) + { + max_phys_mapping = p_port->p_adapter->params.cm_xfer_block_size; + } + else if( p_port->p_adapter->params.lso ) + { + max_phys_mapping = LARGE_SEND_OFFLOAD_SIZE; + } + else + { + max_phys_mapping = p_port->p_adapter->params.xfer_block_size; + } + /*if( NdisMInitializeScatterGatherDma( p_port->p_adapter->h_adapter, + TRUE, max_phys_mapping )!= NDIS_STATUS_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("NdisMInitializeScatterGatherDma failed\n" ) ); + return IB_INSUFFICIENT_RESOURCES; + }*/ + } +#endif + + /* Allocate the PD. */ + status = p_port->p_adapter->p_ifc->alloc_pd( p_port->ib_mgr.h_ca, + IB_PDT_UD, + p_port, + &p_port->ib_mgr.h_pd ); + if( status != IB_SUCCESS ) + { + NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter, + EVENT_IPOIB_ALLOC_PD, 1, status ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_alloc_pd returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + return status; + } + + /* Allocate receive CQ. */ + cq_create.size = p_port->p_adapter->params.rq_depth; + cq_create.pfn_comp_cb = __recv_cb; + cq_create.h_wait_obj = NULL; + + status = p_port->p_adapter->p_ifc->create_cq( p_port->ib_mgr.h_ca, + &cq_create, + p_port, + __cq_event, + &p_port->ib_mgr.h_recv_cq ); + if( status != IB_SUCCESS ) + { + NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter, + EVENT_IPOIB_CREATE_RECV_CQ, 1, status ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_create_cq returned %s.\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + return status; + } + + /* Allocate send CQ. */ + cq_create.size = p_port->p_adapter->params.sq_depth; + cq_create.pfn_comp_cb = __send_cb; + + status = p_port->p_adapter->p_ifc->create_cq( p_port->ib_mgr.h_ca, + &cq_create, + p_port, + __cq_event, + &p_port->ib_mgr.h_send_cq ); + if( status != IB_SUCCESS ) + { + NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter, + EVENT_IPOIB_CREATE_SEND_CQ, 1, status ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_create_cq returned %s.\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + return status; + } + + /* Allocate the QP. */ + cl_memclr( &qp_create, sizeof(qp_create) ); + qp_create.qp_type = IB_QPT_UNRELIABLE_DGRM; + qp_create.rq_depth = p_port->p_adapter->params.rq_depth; + qp_create.rq_sge = 2; /* To support buffers spanning pages. */ + qp_create.h_rq_cq = p_port->ib_mgr.h_recv_cq; + qp_create.sq_depth = p_port->p_adapter->params.sq_depth; + +#define UD_QP_USED_SGE 3 + qp_create.sq_sge = MAX_SEND_SGE < p_port->p_ca_attrs->max_sges ? + MAX_SEND_SGE : ( p_port->p_ca_attrs->max_sges - UD_QP_USED_SGE ); + if ( !p_port->p_ca_attrs->ipoib_csum ) + { + /* checksum is not supported by device + user must specify BYPASS to explicitly cancel checksum calculation */ + if (p_port->p_adapter->params.send_chksum_offload == CSUM_ENABLED) + p_port->p_adapter->params.send_chksum_offload = CSUM_DISABLED; + if (p_port->p_adapter->params.recv_chksum_offload == CSUM_ENABLED) + p_port->p_adapter->params.recv_chksum_offload = CSUM_DISABLED; + } + + + // Now, params struct contains the intersection between the user definition + // and actual HW capabilites + // Remember these values for NDIS OID requests + p_port->p_adapter->offload_cap.lso = !!(p_port->p_adapter->params.lso); + p_port->p_adapter->offload_cap.send_chksum_offload = + !! (p_port->p_adapter->params.send_chksum_offload); + p_port->p_adapter->offload_cap.recv_chksum_offload = + !! (p_port->p_adapter->params.recv_chksum_offload); + + qp_create.h_sq_cq = p_port->ib_mgr.h_send_cq; + qp_create.sq_signaled = FALSE; + + status = p_port->p_adapter->p_ifc->create_qp( p_port->ib_mgr.h_pd, + &qp_create, + p_port, + __qp_event, + &p_port->ib_mgr.h_qp ); + if( status != IB_SUCCESS ) + { + NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter, + EVENT_IPOIB_CREATE_QP, 1, status ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_create_qp returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + return status; + } + /* Query the QP so we can get our QPN. */ + status = p_port->p_adapter->p_ifc->query_qp( p_port->ib_mgr.h_qp, &qp_attr ); + if( status != IB_SUCCESS ) + { + NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter, + EVENT_IPOIB_QUERY_QP, 1, status ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_query_qp returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + return status; + } + p_port->ib_mgr.qpn = qp_attr.num; + + /* Register all of physical memory */ + phys_create.length = MEM_REG_SIZE; + phys_create.num_ranges = 1; + phys_create.range_array = &phys_range; + phys_create.buf_offset = 0; + phys_create.hca_page_size = PAGE_SIZE; + phys_create.access_ctrl = IB_AC_LOCAL_WRITE; + phys_range.base_addr = 0; + phys_range.size = MEM_REG_SIZE; + vaddr = 0; + status = p_port->p_adapter->p_ifc->reg_phys( p_port->ib_mgr.h_pd, + &phys_create, + &vaddr, + &p_port->ib_mgr.lkey, + &rkey, + &p_port->ib_mgr.h_mr ); + if( status != IB_SUCCESS ) + { + NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter, + EVENT_IPOIB_REG_PHYS, 1, status ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_reg_phys returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + return status; + } + + status = ipoib_port_srq_init( p_port ); + if( status != IB_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ipoib_port_srq_init failed %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + /* disable further CM initialization */ + p_port->p_adapter->params.cm_enabled = FALSE; + + NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter, + EVENT_IPOIB_CONNECTED_MODE_ERR, 1, 0xbadc0de1 ); + + } +//CM +#if 0 + if( p_port->p_adapter->params.cm_enabled ) + { + status = endpt_cm_buf_mgr_init( p_port ); + if( status != IB_SUCCESS ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("CM Init buf mgr failed status %#x\n", status ) ); + ipoib_port_srq_destroy( p_port ); + p_port->p_adapter->params.cm_enabled = FALSE; + + NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter, + EVENT_IPOIB_CONNECTED_MODE_ERR, 1, 0xbadc0de2 ); + } + else + { + if ( p_port->p_adapter->params.send_chksum_offload ) + p_port->p_adapter->params.send_chksum_offload = CSUM_DISABLED; + } + } +#endif + IPOIB_EXIT( IPOIB_DBG_INIT ); + return IB_SUCCESS; +} + +static void +__srq_async_event_cb( +IN ib_async_event_rec_t *p_event_rec ) +{ + ipoib_port_t* p_port = + (ipoib_port_t *)p_event_rec->context; + + switch( p_event_rec->code ) + { + case IB_AE_SRQ_LIMIT_REACHED: + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("SRQ ASYNC EVENT CODE %d: %s\n", + p_event_rec->code, "IB_AE_SRQ_LIMIT_REACHED" ) ); + break; + case IB_AE_SRQ_CATAS_ERROR: + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("SRQ ASYNC EVENT CODE %d: %s\n", + p_event_rec->code, "IB_AE_SRQ_CATAS_ERROR" ) ); + /*SRQ is in err state, must reinitialize */ + p_port->p_adapter->hung = TRUE; + break; + case IB_AE_SRQ_QP_LAST_WQE_REACHED: + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("SRQ ASYNC EVENT CODE %d: %s\n", + p_event_rec->code, "IB_AE_SRQ_QP_LAST_WQE_REACHED" ) ); + /*SRQ is in err state, must reinitialize */ + p_port->p_adapter->hung = TRUE; + break; + default: + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ASYNC EVENT CODE ARRIVED %d(%#x)\n", + p_event_rec->code, p_event_rec->code ) ); + } +} + +ib_api_status_t +ipoib_port_srq_init( + IN ipoib_port_t* const p_port ) +{ + ib_api_status_t ib_status; + ib_srq_handle_t h_srq; + ib_srq_attr_t srq_attr; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + if( !p_port->p_adapter->params.cm_enabled ) + return IB_SUCCESS; + + srq_attr.max_sge = min( 2, p_port->p_ca_attrs->max_srq_sges ); + srq_attr.srq_limit = 10; + srq_attr.max_wr = + min( (uint32_t)p_port->p_adapter->params.rq_depth * 8, + p_port->p_ca_attrs->max_srq_wrs/2 ); + + ib_status = p_port->p_adapter->p_ifc->create_srq( + p_port->ib_mgr.h_pd, + &srq_attr, + p_port, + __srq_async_event_cb, + &h_srq ); + if( ib_status != IB_SUCCESS ) + { + NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter, + EVENT_IPOIB_CREATE_QP, 1, ib_status ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_create_srq failed status %s\n", + p_port->p_adapter->p_ifc->get_err_str( ib_status )) ); + return ib_status; + } + p_port->ib_mgr.h_srq = h_srq; + + IPOIB_EXIT( IPOIB_DBG_INIT ); + + return ib_status; +} + +/* __port_query_ca_attrs() + * returns a pointer to allocated memory. + * must be released by caller. + */ +static ib_api_status_t +__port_query_ca_attrs( + IN ipoib_port_t* const p_port, + IN ib_ca_attr_t** pp_ca_attrs ) +{ + ib_api_status_t ib_status; + uint32_t attr_size; + ib_ca_attr_t* p_ca_attrs; + + *pp_ca_attrs = NULL; + + ib_status = + p_port->p_adapter->p_ifc->query_ca( p_port->ib_mgr.h_ca, NULL , &attr_size ); + if( ib_status != IB_INSUFFICIENT_MEMORY ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_query_ca failed status %s\n", + p_port->p_adapter->p_ifc->get_err_str( ib_status )) ); + goto done; + } + CL_ASSERT( attr_size ); + + p_ca_attrs = (ib_ca_attr_t *) cl_zalloc( attr_size ); + if ( p_ca_attrs == NULL ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Allocate %d bytes failed for CA Attributes\n", attr_size )); + ib_status = IB_INSUFFICIENT_MEMORY; + goto done; + } + + ib_status = + p_port->p_adapter->p_ifc->query_ca( p_port->ib_mgr.h_ca, p_ca_attrs , &attr_size ); + if ( ib_status != IB_SUCCESS ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("CA attributes query failed\n") ); + cl_free ( p_ca_attrs ); + goto done; + } + + *pp_ca_attrs = p_ca_attrs; +done: + return ib_status; +} + +void +ipoib_port_srq_destroy( + IN ipoib_port_t* const p_port ) +{ + ib_api_status_t status; + + if( p_port->ib_mgr.h_srq ) + { + status = + p_port->p_adapter->p_ifc->destroy_srq( p_port->ib_mgr.h_srq, NULL ); + CL_ASSERT( status == IB_SUCCESS ); + p_port->ib_mgr.h_srq = NULL; + } +} + +static void +__ib_mgr_destroy( + IN ipoib_port_t* const p_port ) +{ + ib_api_status_t status; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + if( p_port->ib_mgr.h_ca ) + { + status = + p_port->p_adapter->p_ifc->close_ca( p_port->ib_mgr.h_ca, NULL ); + CL_ASSERT( status == IB_SUCCESS ); + p_port->ib_mgr.h_ca = NULL; + } + + IPOIB_EXIT( IPOIB_DBG_INIT ); +} + + + +/****************************************************************************** +* +* Buffer manager implementation. +* +******************************************************************************/ +static void +__buf_mgr_construct( + IN ipoib_port_t* const p_port ) +{ + cl_qpool_construct( &p_port->buf_mgr.recv_pool ); + + p_port->buf_mgr.h_packet_pool = NULL; + p_port->buf_mgr.h_buffer_pool = NULL; + + NdisInitializeNPagedLookasideList( &p_port->buf_mgr.send_buf_list, + NULL, NULL, 0, MAX_LSO_PAYLOAD_MTU, 'bipi', 0 ); + + p_port->buf_mgr.h_send_pkt_pool = NULL; +} + + +static ib_api_status_t +__buf_mgr_init( + IN ipoib_port_t* const p_port ) +{ + cl_status_t cl_status; + ipoib_params_t *p_params; + NET_BUFFER_LIST_POOL_PARAMETERS pool_parameters; + + IPOIB_ENTER(IPOIB_DBG_INIT ); + + CL_ASSERT( p_port ); + CL_ASSERT( p_port->p_adapter ); + + p_params = &p_port->p_adapter->params; + + /* Allocate the receive descriptor pool */ + cl_status = cl_qpool_init( &p_port->buf_mgr.recv_pool, + p_params->rq_depth * p_params->recv_pool_ratio, + 0, + 0, + sizeof(ipoib_recv_desc_t), + __recv_ctor, +#if IPOIB_INLINE_RECV + NULL, +#else + __recv_dtor, +#endif + p_port ); + + if( cl_status != CL_SUCCESS ) + { + NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter, + EVENT_IPOIB_RECV_POOL, 1, cl_status ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("cl_qpool_init for recvs returned %#x\n", + cl_status) ); + return IB_INSUFFICIENT_MEMORY; + } + + /* Allocate the NET BUFFER list pools for receive indication. */ + NdisZeroMemory(&pool_parameters, sizeof(NET_BUFFER_LIST_POOL_PARAMETERS)); + pool_parameters.Header.Type = NDIS_OBJECT_TYPE_DEFAULT; + pool_parameters.Header.Revision = NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1; + pool_parameters.Header.Size = sizeof(pool_parameters); + pool_parameters.ProtocolId = 0; + pool_parameters.ContextSize = 0; + pool_parameters.fAllocateNetBuffer = TRUE; + pool_parameters.PoolTag = 'CRPI'; + pool_parameters.DataSize = 0; + + p_port->buf_mgr.h_packet_pool = NdisAllocateNetBufferListPool( + p_port->p_adapter->h_adapter, + &pool_parameters ); + + if( !p_port->buf_mgr.h_packet_pool ) + { + NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter, + EVENT_IPOIB_RECV_PKT_POOL, 1, NDIS_STATUS_RESOURCES ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("NdisAllocatePacketPool returned %08X\n", (UINT)NDIS_STATUS_RESOURCES) ); + return IB_INSUFFICIENT_RESOURCES; + } + + /* Allocate the NET buffer list pool for send formatting. */ + pool_parameters.PoolTag = 'XTPI'; + + p_port->buf_mgr.h_send_pkt_pool = NdisAllocateNetBufferListPool( + p_port->p_adapter->h_adapter, + &pool_parameters ); + if( !p_port->buf_mgr.h_send_pkt_pool) + { + NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter, + EVENT_IPOIB_SEND_PKT_POOL, 1, NDIS_STATUS_RESOURCES ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("NdisAllocatePacketPool returned %08X\n", + (UINT)NDIS_STATUS_RESOURCES) ); + return IB_INSUFFICIENT_RESOURCES; + } + + IPOIB_EXIT( IPOIB_DBG_INIT ); + return IB_SUCCESS; +} + + +static void +__buf_mgr_destroy( + IN ipoib_port_t* const p_port ) +{ + IPOIB_ENTER(IPOIB_DBG_INIT ); + + CL_ASSERT( p_port ); + + /* Destroy the send packet and buffer pools. + if( p_port->buf_mgr.h_send_buf_pool ) + NdisFreeBufferPool( p_port->buf_mgr.h_send_buf_pool );*/ + if( p_port->buf_mgr.h_send_pkt_pool ) + NdisFreeNetBufferListPool ( p_port->buf_mgr.h_send_pkt_pool ); + + /* Destroy the receive packet and buffer pools. + if( p_port->buf_mgr.h_buffer_pool ) + NdisFreeBufferPool( p_port->buf_mgr.h_buffer_pool );*/ + if( p_port->buf_mgr.h_packet_pool ) + NdisFreeNetBufferListPool ( p_port->buf_mgr.h_packet_pool ); + + /* Free the receive and send descriptors. */ + cl_qpool_destroy( &p_port->buf_mgr.recv_pool ); + + /* Free the lookaside list of scratch buffers. */ + NdisDeleteNPagedLookasideList( &p_port->buf_mgr.send_buf_list ); + + IPOIB_EXIT( IPOIB_DBG_INIT ); +} + + +static cl_status_t +__recv_ctor( + IN void* const p_object, + IN void* context, + OUT cl_pool_item_t** const pp_pool_item ) +{ + ipoib_recv_desc_t *p_desc; + ipoib_port_t *p_port; + +#if IPOIB_INLINE_RECV + uint32_t ds0_len; +#endif + + IPOIB_ENTER( IPOIB_DBG_ALLOC ); + + CL_ASSERT( p_object ); + CL_ASSERT( context ); + + p_desc = (ipoib_recv_desc_t*)p_object; + p_port = (ipoib_port_t*)context; + + /* Setup the work request. */ + p_desc->wr.ds_array = p_desc->local_ds; + p_desc->wr.wr_id = (uintn_t)p_desc; + +#if IPOIB_INLINE_RECV + /* Sanity check on the receive buffer layout */ + CL_ASSERT( (void*)&p_desc->buf.eth.pkt.type == + (void*)&p_desc->buf.ib.pkt.type ); + CL_ASSERT( sizeof(recv_buf_t) == sizeof(ipoib_pkt_t) + sizeof(ib_grh_t) ); + + /* Setup the local data segment. */ + p_desc->local_ds[0].vaddr = cl_get_physaddr( &p_desc->buf ); + p_desc->local_ds[0].lkey = p_port->ib_mgr.lkey; + ds0_len = + PAGE_SIZE - ((uint32_t)p_desc->local_ds[0].vaddr & (PAGE_SIZE - 1)); + if( ds0_len >= sizeof(recv_buf_t) ) + { + /* The whole buffer is within a page. */ + p_desc->local_ds[0].length = ds0_len; + p_desc->wr.num_ds = 1; + } + else + { + /* The buffer crosses page boundaries. */ + p_desc->local_ds[0].length = ds0_len; + p_desc->local_ds[1].vaddr = + cl_get_physaddr( ((uint8_t*)&p_desc->buf) + ds0_len ); + p_desc->local_ds[1].lkey = p_port->ib_mgr.lkey; + p_desc->local_ds[1].length = sizeof(recv_buf_t) - ds0_len; + p_desc->wr.num_ds = 2; + } +#else /* IPOIB_INLINE_RECV */ + /* Allocate the receive buffer. */ + p_desc->p_buf = (recv_buf_t*)cl_zalloc( sizeof(recv_buf_t) ); + if( !p_desc->p_buf ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to allocate receive buffer.\n") ); + return CL_INSUFFICIENT_MEMORY; + } + + /* Sanity check on the receive buffer layout */ + CL_ASSERT( (void*)&p_desc->p_buf->eth.pkt.type == + (void*)&p_desc->p_buf->ib.pkt.type ); + + /* Setup the local data segment. */ + p_desc->local_ds[0].vaddr = cl_get_physaddr( p_desc->p_buf ); + p_desc->local_ds[0].length = sizeof(ipoib_pkt_t) + sizeof(ib_grh_t); + p_desc->local_ds[0].lkey = p_port->ib_mgr.lkey; + p_desc->wr.num_ds = 1; +#endif /* IPOIB_INLINE_RECV */ + + *pp_pool_item = &p_desc->item; + + IPOIB_EXIT( IPOIB_DBG_ALLOC ); + return CL_SUCCESS; +} + + +#if !IPOIB_INLINE_RECV +static void +__recv_dtor( + IN const cl_pool_item_t* const p_pool_item, + IN void *context ) +{ + ipoib_recv_desc_t *p_desc; + + IPOIB_ENTER( IPOIB_DBG_ALLOC ); + + UNUSED_PARAM( context ); + + p_desc = PARENT_STRUCT( p_pool_item, ipoib_recv_desc_t, item ); + + if( p_desc->p_buf ) + cl_free( p_desc->p_buf ); + + IPOIB_EXIT( IPOIB_DBG_ALLOC ); +} +#endif + + +static inline ipoib_recv_desc_t* +__buf_mgr_get_recv( + IN ipoib_port_t* const p_port ) +{ + ipoib_recv_desc_t *p_desc; + IPOIB_ENTER( IPOIB_DBG_RECV ); + p_desc = (ipoib_recv_desc_t*)cl_qpool_get( &p_port->buf_mgr.recv_pool ); + + /* Reference the port object for the send. */ + if( p_desc ) + { + ipoib_port_ref( p_port, ref_get_recv ); + CL_ASSERT( p_desc->wr.wr_id == (uintn_t)p_desc ); +#if IPOIB_INLINE_RECV + CL_ASSERT( p_desc->local_ds[0].vaddr == + cl_get_physaddr( &p_desc->buf ) ); +#else /* IPOIB_INLINE_RECV */ + CL_ASSERT( p_desc->local_ds[0].vaddr == + cl_get_physaddr( p_desc->p_buf ) ); + CL_ASSERT( p_desc->local_ds[0].length == + (sizeof(ipoib_pkt_t) + sizeof(ib_grh_t)) ); +#endif /* IPOIB_INLINE_RECV */ + CL_ASSERT( p_desc->local_ds[0].lkey == p_port->ib_mgr.lkey ); + } + IPOIB_EXIT( IPOIB_DBG_RECV ); + return p_desc; +} + + +//NDIS60 +static inline void +__buf_mgr_put_recv( + IN ipoib_port_t* const p_port, + IN ipoib_recv_desc_t* const p_desc, + IN NET_BUFFER_LIST* const p_net_buffer_list OPTIONAL ) +{ + NET_BUFFER *p_buf = NULL; + MDL *p_mdl = NULL; + IPOIB_ENTER(IPOIB_DBG_RECV ); + + if( p_net_buffer_list ) + { + NET_BUFFER_LIST_NEXT_NBL(p_net_buffer_list) = NULL; + p_buf = NET_BUFFER_LIST_FIRST_NB(p_net_buffer_list); + CL_ASSERT( p_buf ); + p_mdl = NET_BUFFER_FIRST_MDL(p_buf); + CL_ASSERT( p_mdl ); + NdisFreeMdl(p_mdl); + NdisFreeNetBufferList(p_net_buffer_list); + } + + /* Return the descriptor to its pools. */ + cl_qpool_put( &p_port->buf_mgr.recv_pool, &p_desc->item ); + + /* + * Dereference the port object since the receive is no longer outstanding. + */ + ipoib_port_deref( p_port, ref_get_recv ); + IPOIB_EXIT( IPOIB_DBG_RECV ); +} + + +static inline void +__buf_mgr_put_recv_list( + IN ipoib_port_t* const p_port, + IN cl_qlist_t* const p_list ) +{ + cl_qpool_put_list( &p_port->buf_mgr.recv_pool, p_list ); +} + + +static inline NET_BUFFER_LIST* +__buf_mgr_get_NBL( + IN ipoib_port_t* const p_port, + IN ipoib_recv_desc_t* const p_desc ) +{ + NET_BUFFER_LIST *p_net_buffer_list; + MDL *p_mdl; + + IPOIB_ENTER( IPOIB_DBG_RECV ); + + p_mdl = NdisAllocateMdl(p_port->p_adapter->h_adapter, + &p_desc->buf.eth.pkt, + p_desc->len ); + if( !p_mdl ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to allocate MDL\n") ); + return NULL; + } + + p_net_buffer_list = NdisAllocateNetBufferAndNetBufferList( + p_port->buf_mgr.h_packet_pool, + 0, + 0, + p_mdl, + 0, + 0); + + if( !p_net_buffer_list ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to allocate NET_BUFFER_LIST\n") ); + NdisFreeMdl(p_mdl); + return NULL; + } + + NET_BUFFER_LIST_NEXT_NBL(p_net_buffer_list) = NULL; + IPOIB_PORT_FROM_NBL( p_net_buffer_list ) = p_port; + IPOIB_RECV_FROM_NBL( p_net_buffer_list ) = p_desc; + p_net_buffer_list->SourceHandle = p_port->p_adapter->h_adapter; + + IPOIB_EXIT( IPOIB_DBG_RECV ); + return p_net_buffer_list; +} + + +/****************************************************************************** +* +* Receive manager implementation. +* +******************************************************************************/ +static void +__recv_mgr_construct( + IN ipoib_port_t* const p_port ) +{ + cl_qlist_init( &p_port->recv_mgr.done_list ); + p_port->recv_mgr.recv_NBL_array = NULL; +} + + +static ib_api_status_t +__recv_mgr_init( + IN ipoib_port_t* const p_port ) +{ + IPOIB_ENTER( IPOIB_DBG_INIT ); + + /* Allocate the NDIS_PACKET pointer array for indicating receives. */ + p_port->recv_mgr.recv_NBL_array = (NET_BUFFER_LIST **)cl_malloc( + sizeof(NET_BUFFER_LIST*) * p_port->p_adapter->params.rq_depth ); + if( !p_port->recv_mgr.recv_NBL_array ) + { + NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter, + EVENT_IPOIB_RECV_PKT_ARRAY, 0 ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("cl_malloc for PNDIS_PACKET array failed.\n") ); + return IB_INSUFFICIENT_MEMORY; + } + + IPOIB_EXIT( IPOIB_DBG_INIT ); + return IB_SUCCESS; +} + + +static void +__recv_mgr_destroy( + IN ipoib_port_t* const p_port ) +{ + IPOIB_ENTER( IPOIB_DBG_INIT ); + + CL_ASSERT( cl_is_qlist_empty( &p_port->recv_mgr.done_list ) ); + CL_ASSERT( !p_port->recv_mgr.depth ); + + if( p_port->recv_mgr.recv_NBL_array ) + cl_free( p_port->recv_mgr.recv_NBL_array ); + + IPOIB_EXIT( IPOIB_DBG_INIT ); +} + + +/* + * Posts receive buffers to the receive queue and returns the number + * of receives needed to bring the RQ to its low water mark. Note + * that the value is signed, and can go negative. All tests must + * be for > 0. + */ +int32_t +__recv_mgr_repost( + IN ipoib_port_t* const p_port ) +{ + ipoib_recv_desc_t *p_head = NULL, *p_tail = NULL, *p_next; + ib_api_status_t status; + ib_recv_wr_t *p_failed; + PERF_DECLARE( GetRecv ); + PERF_DECLARE( PostRecv ); + + IPOIB_ENTER( IPOIB_DBG_RECV ); + + CL_ASSERT( p_port ); + cl_obj_lock( &p_port->obj ); + if( p_port->state != IB_QPS_RTS ) + { + cl_obj_unlock( &p_port->obj ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_RECV, + ("Port in invalid state. Not reposting.\n") ); + return 0; + } + ipoib_port_ref( p_port, ref_repost ); + cl_obj_unlock( &p_port->obj ); + + while( p_port->recv_mgr.depth < p_port->p_adapter->params.rq_depth ) + { + /* Pull receives out of the pool and chain them up. */ + cl_perf_start( GetRecv ); + p_next = __buf_mgr_get_recv( p_port ); + cl_perf_stop( &p_port->p_adapter->perf, GetRecv ); + if( !p_next ) + { + IPOIB_PRINT(TRACE_LEVEL_VERBOSE, IPOIB_DBG_RECV, + ("Out of receive descriptors! recv queue depth 0x%x\n",p_port->recv_mgr.depth) ); + break; + } + + if( !p_tail ) + { + p_tail = p_next; + p_next->wr.p_next = NULL; + } + else + { + p_next->wr.p_next = &p_head->wr; + } + + p_head = p_next; + + p_port->recv_mgr.depth++; + } + + if( p_head ) + { + cl_perf_start( PostRecv ); + status = p_port->p_adapter->p_ifc->post_recv( + p_port->ib_mgr.h_qp, &p_head->wr, &p_failed ); + cl_perf_stop( &p_port->p_adapter->perf, PostRecv ); + + if( status != IB_SUCCESS ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ip_post_recv returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + /* return the descriptors to the pool */ + while( p_failed ) + { + p_head = PARENT_STRUCT( p_failed, ipoib_recv_desc_t, wr ); + p_failed = p_failed->p_next; + + __buf_mgr_put_recv( p_port, p_head, NULL ); + p_port->recv_mgr.depth--; + } + } + } + + ipoib_port_deref( p_port, ref_repost ); + IPOIB_EXIT( IPOIB_DBG_RECV ); + return p_port->p_adapter->params.rq_low_watermark - p_port->recv_mgr.depth; +} + +inline ULONG __free_received_NBL ( + IN ipoib_port_t *p_port, + IN NET_BUFFER_LIST *p_net_buffer_lists ) +{ + + ipoib_recv_desc_t *p_desc; + NET_BUFFER_LIST *cur_net_buffer_list, *next_net_buffer_list; + LONG NBL_cnt = 0; + + + for (cur_net_buffer_list = p_net_buffer_lists; + cur_net_buffer_list != NULL; + cur_net_buffer_list = next_net_buffer_list) + { + ++NBL_cnt; + next_net_buffer_list = NET_BUFFER_LIST_NEXT_NBL(cur_net_buffer_list); + + /* Get the port and descriptor from the NET_BUFFER_LIST. */ + CL_ASSERT(p_port == IPOIB_PORT_FROM_NBL( cur_net_buffer_list )); + p_desc = IPOIB_RECV_FROM_NBL( cur_net_buffer_list ); + +#if 0 //TODO CM flow + if( p_desc->type == PKT_TYPE_CM_UCAST ) + { + int32_t discarded; + uint32_t NBL_cnt = 0; + + ib_api_status_t status = IB_NOT_DONE; + + + NDIS_BUFFER *p_buf; + + /* Unchain the NDIS buffer. */ + NdisUnchainBufferAtFront( p_packet, &p_buf ); + CL_ASSERT( p_buf ); + /* Return the NDIS packet and NDIS buffer to their pools. */ + NdisDprFreePacketNonInterlocked( p_packet ); + NdisFreeBuffer( p_buf ); + + endpt_cm_buf_mgr_put_recv( &p_port->cm_buf_mgr, (ipoib_cm_desc_t *)p_desc ); + status = endpt_cm_post_recv( p_port ); + if( status != IB_SUCCESS ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Post Recv QP failed\n" ) ); + } + cl_spinlock_release( &p_port->recv_lock ); + return; + } +#endif + + cl_perf_start( ReturnPutRecv ); + __buf_mgr_put_recv( p_port, p_desc, cur_net_buffer_list ); + cl_perf_stop( &p_port->p_adapter->perf, ReturnPutRecv ); + } + return NBL_cnt; +} + +void +ipoib_return_net_buffer_list( + IN NDIS_HANDLE adapter_context, + IN NET_BUFFER_LIST *p_net_buffer_lists, + IN ULONG return_flags) +{ + ipoib_port_t *p_port; + int32_t shortage; + LONG NBL_cnt = 0; + + PERF_DECLARE( ReturnPacket ); + PERF_DECLARE( ReturnPutRecv ); + PERF_DECLARE( ReturnRepostRecv ); + PERF_DECLARE( ReturnPreparePkt ); + PERF_DECLARE( ReturnNdisIndicate ); + + IPOIB_ENTER( IPOIB_DBG_RECV ); + + UNUSED_PARAM( return_flags ); + + p_port = ((ipoib_adapter_t*)adapter_context)->p_port; + CL_ASSERT( p_net_buffer_lists ); + if ( !p_port ) { + ASSERT(p_port); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + (" port pointer; already cleared?\n") ); + return; + } + + cl_perf_start( ReturnPacket ); + cl_spinlock_acquire( &p_port->recv_lock ); + + NBL_cnt = __free_received_NBL( p_port, p_net_buffer_lists ); + + shutter_sub( &p_port->p_adapter->recv_shutter, -NBL_cnt ); + + /* Repost buffers to HW */ + cl_perf_start( ReturnRepostRecv ); + shortage = __recv_mgr_repost( p_port ); + cl_perf_stop( &p_port->p_adapter->perf, ReturnRepostRecv ); + cl_spinlock_release( &p_port->recv_lock ); + cl_perf_stop( &p_port->p_adapter->perf, ReturnPacket ); + + IPOIB_EXIT( IPOIB_DBG_RECV ); +} + +static BOOLEAN +__recv_cb_internal( + IN const ib_cq_handle_t h_cq, + IN void *cq_context, + IN uint32_t* p_recv_cnt ); + + +static void +__iopoib_WorkItem( + IN DEVICE_OBJECT* p_dev_obj, + IN void* context ) +{ + ipoib_port_t *p_port = ( ipoib_port_t* ) context; + BOOLEAN WorkToDo = TRUE; + KIRQL irql; + uint32_t recv_cnt = 0; + uint32_t total_recv_cnt = 0; + + UNREFERENCED_PARAMETER(p_dev_obj); + + while (WorkToDo && total_recv_cnt < 512) { + irql = KeRaiseIrqlToDpcLevel(); + WorkToDo = __recv_cb_internal(NULL, p_port, &recv_cnt); + KeLowerIrql(irql); + total_recv_cnt += recv_cnt; + } + + if (WorkToDo) { + IoQueueWorkItem( p_port->pPoWorkItem, __iopoib_WorkItem, DelayedWorkQueue, p_port); + } else { + // Release the reference count that was incremented when queued the work item. + ipoib_port_deref( p_port, ref_recv_cb ); + } +} + +static BOOLEAN +__recv_cb_internal( + IN const ib_cq_handle_t h_cq, + IN void *cq_context, + IN uint32_t *p_recv_cnt) +{ + ipoib_port_t *p_port; + ib_api_status_t status; + ib_wc_t wc[MAX_RECV_WC], *p_free, *p_wc; + int32_t NBL_cnt, recv_cnt = 0, shortage, discarded; + cl_qlist_t done_list, bad_list; + ULONG recv_complete_flags = 0; + BOOLEAN res; + BOOLEAN WorkToDo = FALSE; + + PERF_DECLARE( RecvCompBundle ); + PERF_DECLARE( RecvCb ); + PERF_DECLARE( PollRecv ); + PERF_DECLARE( RepostRecv ); + PERF_DECLARE( FilterRecv ); + PERF_DECLARE( BuildNBLArray ); + PERF_DECLARE( RecvNdisIndicate ); + PERF_DECLARE( RearmRecv ); + PERF_DECLARE( PutRecvList ); + + IPOIB_ENTER( IPOIB_DBG_RECV ); + + cl_perf_clr( RecvCompBundle ); + + cl_perf_start( RecvCb ); + + NDIS_SET_SEND_COMPLETE_FLAG( recv_complete_flags, + NDIS_RECEIVE_FLAGS_DISPATCH_LEVEL ); + + p_port = (ipoib_port_t*)cq_context; + + cl_qlist_init( &done_list ); + cl_qlist_init( &bad_list ); + + ipoib_port_ref( p_port, ref_recv_cb ); + + for( p_free=wc; p_free < &wc[MAX_RECV_WC - 1]; p_free++ ) + p_free->p_next = p_free + 1; + p_free->p_next = NULL; + + /* + * We'll be accessing the endpoint map so take a reference + * on it to prevent modifications. + */ + cl_obj_lock( &p_port->obj ); + cl_atomic_inc( &p_port->endpt_rdr ); + cl_obj_unlock( &p_port->obj ); + + do + { + /* If we get here, then the list of WCs is intact. */ + p_free = wc; + + cl_perf_start( PollRecv ); + status = p_port->p_adapter->p_ifc->poll_cq( p_port->ib_mgr.h_recv_cq, + &p_free, + &p_wc ); + cl_perf_stop( &p_port->p_adapter->perf, PollRecv ); + CL_ASSERT( status == IB_SUCCESS || status == IB_NOT_FOUND ); + + /* Look at the payload now and filter ARP and DHCP packets. */ + cl_perf_start( FilterRecv ); + recv_cnt += __recv_mgr_filter( p_port, p_wc, &done_list, &bad_list ); + cl_perf_stop( &p_port->p_adapter->perf, FilterRecv ); + + } while( ( !p_free ) && ( recv_cnt < 128 )); + + *p_recv_cnt = (uint32_t)recv_cnt; + + /* We're done looking at the endpoint map, release the reference. */ + cl_atomic_dec( &p_port->endpt_rdr ); + + cl_perf_log( &p_port->p_adapter->perf, RecvCompBundle, recv_cnt ); + + cl_spinlock_acquire( &p_port->recv_lock ); + + /* Update our posted depth. */ + p_port->recv_mgr.depth -= recv_cnt; + + /* Return any discarded receives to the pool */ + cl_perf_start( PutRecvList ); + __buf_mgr_put_recv_list( p_port, &bad_list ); + cl_perf_stop( &p_port->p_adapter->perf, PutRecvList ); + + do + { + //int32_t cnt; + /* Repost ASAP so we don't starve the RQ. */ + cl_perf_start( RepostRecv ); + shortage = __recv_mgr_repost( p_port ); + + if( shortage > 0 ) + { + recv_complete_flags |= NDIS_RECEIVE_FLAGS_RESOURCES; + cl_dbg_out("Got SHORTAGE=%d\n",shortage); + } + + cl_perf_stop( &p_port->p_adapter->perf, RepostRecv ); + + cl_perf_start( BuildNBLArray ); + /* Notify NDIS of any and all possible receive buffers. */ + NBL_cnt = __recv_mgr_build_NBL_array( p_port, &done_list, &discarded); + cl_perf_stop( &p_port->p_adapter->perf, BuildNBLArray ); + + /* Only indicate receives if we actually had any. */ + if( discarded && shortage > 0 ) + { + /* We may have thrown away packets, and have a shortage */ + cl_perf_start( RepostRecv ); + __recv_mgr_repost( p_port ); + cl_perf_stop( &p_port->p_adapter->perf, RepostRecv ); + } + + if( !NBL_cnt ) { + //cl_dbg_out("NBL cnt == 0 :-(\n"); + break; + } + + cl_spinlock_release( &p_port->recv_lock ); + + cl_perf_start( RecvNdisIndicate ); + + if (shortage <= 0) { + + res = shutter_add( &p_port->p_adapter->recv_shutter, NBL_cnt ); + if (res) + { + NdisMIndicateReceiveNetBufferLists( + p_port->p_adapter->h_adapter, + p_port->recv_mgr.recv_NBL_array[0], + NDIS_DEFAULT_PORT_NUMBER, + NBL_cnt, + recv_complete_flags ); + } + else { + __free_received_NBL( p_port, p_port->recv_mgr.recv_NBL_array[0] ); + } + + } else { + /* If shortage >0, we already set the status to + NDIS_RECEIVE_FLAGS_RESOURCES. That is, IPoIB driver regain + ownership of the NET_BUFFER_LIST structures immediately. + */ + res = shutter_add( &p_port->p_adapter->recv_shutter, 1 ); + if (res) { + NdisMIndicateReceiveNetBufferLists( + p_port->p_adapter->h_adapter, + p_port->recv_mgr.recv_NBL_array[0], + NDIS_DEFAULT_PORT_NUMBER, + NBL_cnt, + recv_complete_flags ); + shutter_sub( &p_port->p_adapter->recv_shutter, -1 ); + } + } + + cl_perf_stop( &p_port->p_adapter->perf, RecvNdisIndicate ); + + /* + * Cap the number of receives to put back to what we just indicated + * with NDIS_STATUS_RESOURCES. + */ + if( shortage > 0 ) + { + cl_dbg_out("GOT SHORTAGE <===============\n"); + /* Return all but the last packet to the pool. */ + cl_spinlock_acquire( &p_port->recv_lock ); + //while( shortage-- > 1 ) + while ( NBL_cnt-- > 0) + { + __buf_mgr_put_recv( + p_port, + (ipoib_recv_desc_t *) + IPOIB_RECV_FROM_NBL( p_port->recv_mgr.recv_NBL_array[NBL_cnt] ), + p_port->recv_mgr.recv_NBL_array[NBL_cnt] ); + } + __recv_mgr_repost( p_port ); + cl_spinlock_release( &p_port->recv_lock ); + + /* + * Return the last packet as if NDIS returned it, so that we repost + * and report any other pending receives. + */ + //ipoib_return_net_buffer_list( p_port, p_port->recv_mgr.recv_NBL_array[0],recv_complete_flags ); + } + cl_spinlock_acquire( &p_port->recv_lock ); + + } while( NBL_cnt ); + cl_spinlock_release( &p_port->recv_lock ); + + if (p_free ) + { + /* + * Rearm after filtering to prevent contention on the enpoint maps + * and eliminate the possibility of having a call to + * __endpt_mgr_insert find a duplicate. + */ + ASSERT(WorkToDo == FALSE); + cl_perf_start( RearmRecv ); + + status = + p_port->p_adapter->p_ifc->rearm_cq( p_port->ib_mgr.h_recv_cq, FALSE ); + + cl_perf_stop( &p_port->p_adapter->perf, RearmRecv ); + CL_ASSERT( status == IB_SUCCESS ); + + } else { + if (h_cq) { + // increment reference to ensure no one release the object while work iteam is queued + ipoib_port_ref( p_port, ref_recv_cb ); + IoQueueWorkItem( p_port->pPoWorkItem, __iopoib_WorkItem, DelayedWorkQueue, p_port); + WorkToDo = FALSE; + } else { + WorkToDo = TRUE; + } + } + ipoib_port_deref( p_port, ref_recv_cb ); + cl_perf_stop( &p_port->p_adapter->perf, RecvCb ); + + IPOIB_EXIT( IPOIB_DBG_RECV ); + return WorkToDo; +} + + +static void +__recv_cb( + IN const ib_cq_handle_t h_cq, + IN void *cq_context ) +{ + uint32_t recv_cnt; + + __recv_cb_internal(h_cq, cq_context, &recv_cnt); +} + + +static void +__recv_get_endpts( + IN ipoib_port_t* const p_port, + IN ipoib_recv_desc_t* const p_desc, + IN ib_wc_t* const p_wc, + OUT ipoib_endpt_t** const pp_src, + OUT ipoib_endpt_t** const pp_dst ) +{ + ib_api_status_t status; + mac_addr_t mac; + PERF_DECLARE( GetEndptByGid ); + PERF_DECLARE( GetEndptByLid ); + PERF_DECLARE( EndptInsert ); + + IPOIB_ENTER( IPOIB_DBG_RECV ); + + /* Setup our shortcut pointers based on whether GRH is valid. */ + if( p_wc->recv.ud.recv_opt & IB_RECV_OPT_GRH_VALID ) + { + /* Lookup the source endpoints based on GID. */ + cl_perf_start( GetEndptByGid ); + *pp_src = __endpt_mgr_get_by_gid( p_port, +#if IPOIB_INLINE_RECV + &p_desc->buf.ib.grh.src_gid +#else + &p_desc->p_buf->ib.grh.src_gid +#endif + ); + + cl_perf_stop( &p_port->p_adapter->perf, GetEndptByGid ); + + /* + * Lookup the destination endpoint based on GID. + * This is used along with the packet filter to determine + * whether to report this to NDIS. + */ + cl_perf_start( GetEndptByGid ); + + *pp_dst = __endpt_mgr_get_by_gid( p_port, +#if IPOIB_INLINE_RECV + &p_desc->buf.ib.grh.dest_gid +#else + &p_desc->p_buf->ib.grh.dest_gid +#endif + ); + + cl_perf_stop( &p_port->p_adapter->perf, GetEndptByGid ); + + /* + * Create the source endpoint if it does not exist. Note that we + * can only do this for globally routed traffic since we need the + * information from the GRH to generate the MAC. + */ + if( !*pp_src ) + { + status = ipoib_mac_from_guid( +#if IPOIB_INLINE_RECV + p_desc->buf.ib.grh.src_gid.unicast.interface_id, +#else + p_desc->p_buf->ib.grh.src_gid.unicast.interface_id, +#endif + p_port->p_adapter->params.guid_mask, + &mac ); + + if( status != IB_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ipoib_mac_from_guid returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + return; + } + + /* Create the endpoint. */ + *pp_src = ipoib_endpt_create( +#if IPOIB_INLINE_RECV + &p_desc->buf.ib.grh.src_gid, +#else + &p_desc->p_buf->ib.grh.src_gid, +#endif + p_wc->recv.ud.remote_lid, + p_wc->recv.ud.remote_qp ); + if( !*pp_src ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ipoib_endpt_create failed\n") ); + return; + } + cl_perf_start( EndptInsert ); + cl_obj_lock( &p_port->obj ); + status = __endpt_mgr_insert( p_port, mac, *pp_src ); + if( status != IB_SUCCESS ) + { + cl_obj_unlock( &p_port->obj ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("__endpt_mgr_insert returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + *pp_src = NULL; + return; + } + cl_obj_unlock( &p_port->obj ); + cl_perf_stop( &p_port->p_adapter->perf, EndptInsert ); + } + } + else + { + /* + * Lookup the remote endpoint based on LID. Note that only + * unicast traffic can be LID routed. + */ + cl_perf_start( GetEndptByLid ); + *pp_src = __endpt_mgr_get_by_lid( p_port, p_wc->recv.ud.remote_lid ); + cl_perf_stop( &p_port->p_adapter->perf, GetEndptByLid ); + *pp_dst = p_port->p_local_endpt; + CL_ASSERT( *pp_dst ); + } + + if( *pp_src && !ipoib_is_voltaire_router_gid( &(*pp_src)->dgid ) && + (*pp_src)->qpn != p_wc->recv.ud.remote_qp ) + { + /* Update the QPN for the endpoint. */ + IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_RECV, + ("Updating QPN for MAC: %02X-%02X-%02X-%02X-%02X-%02X\n", + (*pp_src )->mac.addr[0], (*pp_src )->mac.addr[1], + (*pp_src )->mac.addr[2], (*pp_src )->mac.addr[3], + (*pp_src )->mac.addr[4], (*pp_src )->mac.addr[5]) ); +// (*pp_src)->qpn = p_wc->recv.ud.remote_qp; + } + + if( *pp_src && *pp_dst ) + { + IPOIB_PRINT(TRACE_LEVEL_VERBOSE, IPOIB_DBG_RECV, + ("Recv:\n" + "\tsrc MAC: %02X-%02X-%02X-%02X-%02X-%02X\n" + "\tdst MAC: %02X-%02X-%02X-%02X-%02X-%02X\n", + (*pp_src )->mac.addr[0], (*pp_src )->mac.addr[1], + (*pp_src )->mac.addr[2], (*pp_src )->mac.addr[3], + (*pp_src )->mac.addr[4], (*pp_src )->mac.addr[5], + (*pp_dst )->mac.addr[0], (*pp_dst )->mac.addr[1], + (*pp_dst )->mac.addr[2], (*pp_dst )->mac.addr[3], + (*pp_dst )->mac.addr[4], (*pp_dst )->mac.addr[5]) ); + } + + IPOIB_EXIT( IPOIB_DBG_RECV ); +} + + +static int32_t +__recv_mgr_filter( + IN ipoib_port_t* const p_port, + IN ib_wc_t* const p_done_wc_list, + OUT cl_qlist_t* const p_done_list, + OUT cl_qlist_t* const p_bad_list ) +{ + ipoib_recv_desc_t *p_desc; + ib_wc_t *p_wc; + ipoib_pkt_t *p_ipoib; + eth_pkt_t *p_eth; + ipoib_endpt_t *p_src, *p_dst; + ib_api_status_t status; + uint32_t len; + int32_t recv_cnt = 0; + PERF_DECLARE( GetRecvEndpts ); + PERF_DECLARE( RecvGen ); + PERF_DECLARE( RecvTcp ); + PERF_DECLARE( RecvUdp ); + PERF_DECLARE( RecvDhcp ); + PERF_DECLARE( RecvArp ); + + IPOIB_ENTER( IPOIB_DBG_RECV ); + + for( p_wc = p_done_wc_list; p_wc; p_wc = p_wc->p_next ) + { + CL_ASSERT( p_wc->status != IB_WCS_SUCCESS || p_wc->wc_type == IB_WC_RECV ); + p_desc = (ipoib_recv_desc_t*)(uintn_t)p_wc->wr_id; + recv_cnt++; + + if( p_wc->status != IB_WCS_SUCCESS ) + { + if( p_wc->status != IB_WCS_WR_FLUSHED_ERR ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed completion %s (vendor specific %#x)\n", + p_port->p_adapter->p_ifc->get_wc_status_str( p_wc->status ), + (int)p_wc->vendor_specific) ); + ipoib_inc_recv_stat( p_port->p_adapter, IP_STAT_ERROR, 0, 0 ); + } + else + { + IPOIB_PRINT(TRACE_LEVEL_VERBOSE, IPOIB_DBG_RECV, + ("Flushed completion %s\n", + p_port->p_adapter->p_ifc->get_wc_status_str( p_wc->status )) ); + ipoib_inc_recv_stat( p_port->p_adapter, IP_STAT_DROPPED, 0, 0 ); + } + cl_qlist_insert_tail( p_bad_list, &p_desc->item.list_item ); + /* Dereference the port object on behalf of the failed receive. */ + ipoib_port_deref( p_port, ref_failed_recv_wc ); + continue; + } + + len = p_wc->length - sizeof(ib_grh_t); + + if( len < sizeof(ipoib_hdr_t) ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Received ETH packet < min size\n") ); + ipoib_inc_recv_stat( p_port->p_adapter, IP_STAT_ERROR, 0, 0 ); + cl_qlist_insert_tail( p_bad_list, &p_desc->item.list_item ); + ipoib_port_deref( p_port, ref_recv_inv_len ); + continue; + } + + if((len - sizeof(ipoib_hdr_t)) > p_port->p_adapter->params.payload_mtu) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Received ETH packet len %d > payload MTU (%d)\n", + (len - sizeof(ipoib_hdr_t)), + p_port->p_adapter->params.payload_mtu) ); + ipoib_inc_recv_stat( p_port->p_adapter, IP_STAT_ERROR, 0, 0 ); + cl_qlist_insert_tail( p_bad_list, &p_desc->item.list_item ); + ipoib_port_deref( p_port, ref_recv_inv_len ); + continue; + + } + /* Successful completion. Get the receive information. */ + p_desc->ndis_csum.Value = ( ( p_wc->recv.ud.recv_opt & IB_RECV_OPT_CSUM_MASK ) >> 8 ); + p_desc->len = len + 14 - 4 ; + cl_perf_start( GetRecvEndpts ); + __recv_get_endpts( p_port, p_desc, p_wc, &p_src, &p_dst ); + cl_perf_stop( &p_port->p_adapter->perf, GetRecvEndpts ); + +#if IPOIB_INLINE_RECV + p_ipoib = &p_desc->buf.ib.pkt; + p_eth = &p_desc->buf.eth.pkt; +#else + p_ipoib = &p_desc->p_buf->ib.pkt; + p_eth = &p_desc->p_buf->eth.pkt; +#endif + + if( p_src ) + { + /* Don't report loopback traffic - we requested SW loopback. */ + if( !cl_memcmp( &p_port->p_adapter->params.conf_mac, + &p_src->mac, sizeof(p_port->p_adapter->params.conf_mac) ) ) + { + /* + * "This is not the packet you're looking for" - don't update + * receive statistics, the packet never happened. + */ + cl_qlist_insert_tail( p_bad_list, &p_desc->item.list_item ); + /* Dereference the port object on behalf of the failed recv. */ + ipoib_port_deref( p_port, ref_recv_loopback ); + continue; + } + } + + switch( p_ipoib->hdr.type ) + { + case ETH_PROT_TYPE_IP: + if( len < (sizeof(ipoib_hdr_t) + sizeof(ip_hdr_t)) ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Received IP packet < min size\n") ); + status = IB_INVALID_SETTING; + break; + } + + if( p_ipoib->type.ip.hdr.offset || + p_ipoib->type.ip.hdr.prot != IP_PROT_UDP ) + { + /* Unfiltered. Setup the ethernet header and report. */ + cl_perf_start( RecvTcp ); + status = __recv_gen( p_ipoib, p_eth, p_src, p_dst ); + cl_perf_stop( &p_port->p_adapter->perf, RecvTcp ); + break; + } + + /* First packet of a UDP transfer. */ + if( len < + (sizeof(ipoib_hdr_t) + sizeof(ip_hdr_t) + sizeof(udp_hdr_t)) ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Received UDP packet < min size\n") ); + status = IB_INVALID_SETTING; + break; + } + + /* Check if DHCP conversion is required. */ + if( (p_ipoib->type.ip.prot.udp.hdr.dst_port == DHCP_PORT_SERVER && + p_ipoib->type.ip.prot.udp.hdr.src_port == DHCP_PORT_CLIENT) || + (p_ipoib->type.ip.prot.udp.hdr.dst_port == DHCP_PORT_CLIENT && + p_ipoib->type.ip.prot.udp.hdr.src_port == DHCP_PORT_SERVER)|| + (p_ipoib->type.ip.prot.udp.hdr.dst_port == DHCP_PORT_PROXY_SERVER && + p_ipoib->type.ip.prot.udp.hdr.src_port == DHCP_PORT_CLIENT) || + (p_ipoib->type.ip.prot.udp.hdr.dst_port == DHCP_PORT_CLIENT && + p_ipoib->type.ip.prot.udp.hdr.src_port == DHCP_PORT_PROXY_SERVER)) + { + if( len < (sizeof(ipoib_hdr_t) + sizeof(ip_hdr_t) + + sizeof(udp_hdr_t) + DHCP_MIN_SIZE) ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Received DHCP < min size\n") ); + status = IB_INVALID_SETTING; + break; + } + if ((p_ipoib->type.ip.hdr.ver_hl & 0x0f) != 5 ) { + // If there are IP options in this message, we are in + // trouble in any case + status = IB_INVALID_SETTING; + break; + } + /* UDP packet with BOOTP ports in src/dst port numbers. */ + cl_perf_start( RecvDhcp ); + status = __recv_dhcp( p_port, p_ipoib, p_eth, p_src, p_dst ); + cl_perf_stop( &p_port->p_adapter->perf, RecvDhcp ); + } + else + { + /* Unfiltered. Setup the ethernet header and report. */ + cl_perf_start( RecvUdp ); + status = __recv_gen( p_ipoib, p_eth, p_src, p_dst ); + cl_perf_stop( &p_port->p_adapter->perf, RecvUdp ); + } + break; + + case ETH_PROT_TYPE_ARP: + if( len < (sizeof(ipoib_hdr_t) + sizeof(ipoib_arp_pkt_t)) ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Received ARP < min size\n") ); + status = IB_INVALID_SETTING; + break; + } + cl_perf_start( RecvArp ); + status = __recv_arp( p_port, p_wc, p_ipoib, p_eth, &p_src, p_dst ); + cl_perf_stop( &p_port->p_adapter->perf, RecvArp ); + len = sizeof(ipoib_hdr_t) + sizeof(arp_pkt_t); + break; + + default: + /* Unfiltered. Setup the ethernet header and report. */ + cl_perf_start( RecvGen ); + status = __recv_gen( p_ipoib, p_eth, p_src, p_dst ); + cl_perf_stop( &p_port->p_adapter->perf, RecvGen ); + } + + if( status != IB_SUCCESS ) + { + /* Update stats. */ + ipoib_inc_recv_stat( p_port->p_adapter, IP_STAT_ERROR, 0, 0 ); + cl_qlist_insert_tail( p_bad_list, &p_desc->item.list_item ); + /* Dereference the port object on behalf of the failed receive. */ + ipoib_port_deref( p_port, ref_recv_filter ); + } + else + { + ip_stat_sel_t ip_stat; + p_desc->len = len + sizeof(eth_hdr_t) - sizeof(ipoib_hdr_t); + if( p_dst->h_mcast) + { + if( p_dst->dgid.multicast.raw_group_id[10] == 0xFF && + p_dst->dgid.multicast.raw_group_id[11] == 0xFF && + p_dst->dgid.multicast.raw_group_id[12] == 0xFF && + p_dst->dgid.multicast.raw_group_id[13] == 0xFF ) + { + p_desc->type = PKT_TYPE_BCAST; + ip_stat = IP_STAT_BCAST_BYTES; + } + else + { + p_desc->type = PKT_TYPE_MCAST; + ip_stat = IP_STAT_MCAST_BYTES; + } + } + else + { + p_desc->type = PKT_TYPE_UCAST; + ip_stat = IP_STAT_UCAST_BYTES; + + } + cl_qlist_insert_tail( p_done_list, &p_desc->item.list_item ); + ipoib_inc_recv_stat( p_port->p_adapter, ip_stat, len, 1 ); + } + } + + IPOIB_EXIT( IPOIB_DBG_RECV ); + return recv_cnt; +} + + +static ib_api_status_t +__recv_gen( + IN const ipoib_pkt_t* const p_ipoib, + OUT eth_pkt_t* const p_eth, + IN ipoib_endpt_t* const p_src, + IN ipoib_endpt_t* const p_dst ) +{ + IPOIB_ENTER( IPOIB_DBG_RECV ); + + if( !p_src || !p_dst ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Received packet with no matching endpoints.\n") ); + return IB_NOT_DONE; + } + + /* + * Fill in the ethernet header. Note that doing so will overwrite + * the IPoIB header, so start by moving the information from the IPoIB + * header. + */ + p_eth->hdr.type = p_ipoib->hdr.type; + p_eth->hdr.src = p_src->mac; + p_eth->hdr.dst = p_dst->mac; + + if ( p_eth->hdr.dst.addr[0] == 1 && + p_eth->hdr.type == ETH_PROT_TYPE_IP && + p_eth->hdr.dst.addr[2] == 0x5E) + { + p_eth->hdr.dst.addr[1] = 0; + p_eth->hdr.dst.addr[3] = p_eth->hdr.dst.addr[3] & 0x7f; + } + if (p_dst->h_mcast) + p_dst->is_in_use = TRUE; + + IPOIB_EXIT( IPOIB_DBG_RECV ); + return IB_SUCCESS; +} + + +static ib_api_status_t +__recv_dhcp( + IN ipoib_port_t* const p_port, + IN const ipoib_pkt_t* const p_ipoib, + OUT eth_pkt_t* const p_eth, + IN ipoib_endpt_t* const p_src, + IN ipoib_endpt_t* const p_dst ) +{ + ib_api_status_t status; + dhcp_pkt_t *p_dhcp; + uint8_t *p_option; + uint8_t *p_cid = NULL; + uint8_t msg = 0; + + IPOIB_ENTER( IPOIB_DBG_RECV ); + + UNUSED_PARAM( p_port ); + + /* Create the ethernet header. */ + status = __recv_gen( p_ipoib, p_eth, p_src, p_dst ); + if( status != IB_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("__recv_gen returned %s.\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + return status; + } + + /* Fixup the payload. */ + p_dhcp = &p_eth->type.ip.prot.udp.dhcp; + if( p_dhcp->op != DHCP_REQUEST && p_dhcp->op != DHCP_REPLY ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Invalid DHCP op code.\n") ); + return IB_INVALID_SETTING; + } + + /* + * Find the client identifier option, making sure to skip + * the "magic cookie". + */ + p_option = &p_dhcp->options[0]; + if ( *(uint32_t *)p_option != DHCP_COOKIE ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("DHCP cookie corrupted.\n") ); + return IB_INVALID_PARAMETER; + } + + p_option = &p_dhcp->options[DHCP_COOKIE_SIZE]; + while( *p_option != DHCP_OPT_END && p_option < &p_dhcp->options[312] ) + { + switch( *p_option ) + { + case DHCP_OPT_PAD: + p_option++; + break; + + case DHCP_OPT_MSG: + msg = p_option[2]; + p_option += 3; + break; + + case DHCP_OPT_CLIENT_ID: + p_cid = p_option; + /* Fall through. */ + + default: + /* + * All other options have a length byte following the option code. + * Offset by the length to get to the next option. + */ + p_option += (p_option[1] + 2); + } + } + + switch( msg ) + { + /* message from client */ + case DHCPDISCOVER: + case DHCPREQUEST: + case DHCPDECLINE: + case DHCPRELEASE: + case DHCPINFORM: + if( !p_cid ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to find required Client-identifier option.\n") ); + return IB_INVALID_SETTING; + } + if( p_dhcp->htype != DHCP_HW_TYPE_IB ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Invalid hardware address type.\n") ); + return IB_INVALID_SETTING; + } + break; + /* message from DHCP server */ + case DHCPOFFER: + case DHCPACK: + case DHCPNAK: + break; + + default: + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Invalide message type.\n") ); + return IB_INVALID_PARAMETER; + } + p_eth->type.ip.prot.udp.hdr.chksum = 0; + p_dhcp->htype = DHCP_HW_TYPE_ETH; + p_dhcp->hlen = HW_ADDR_LEN; + + if( p_cid ) /* from client */ + { + /* Validate that the length and type of the option is as required. */ + IPOIB_PRINT(TRACE_LEVEL_VERBOSE, IPOIB_DBG_RECV, + ("DHCP CID received is:")); + for (int i=0; i < coIPoIB_CID_TotalLen; ++i) { + IPOIB_PRINT(TRACE_LEVEL_VERBOSE, IPOIB_DBG_RECV, + ("[%d] 0x%x: \n",i, p_cid[i])); + } + if( p_cid[1] != coIPoIB_CID_Len ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Client-identifier length is not equal to %d as required.\n", + coIPoIB_CID_Len) ); + return IB_INVALID_SETTING; + } + if( p_cid[2] != coIPoIB_HwTypeIB) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Client-identifier type is %d <> %d and wrong\n", + p_cid[2], coIPoIB_HwTypeIB) ); + return IB_INVALID_SETTING; + } + /* + * Copy the GID value from the option so that we can make aligned + * accesses to the contents. + * Recover CID to standard type. + */ + p_cid[1] = sizeof (ib_net64_t) + 1;// CID length + p_cid[2] = DHCP_HW_TYPE_ETH;// CID type + //Copy the GUID to the 3-d byte of CID + RtlMoveMemory( &p_cid[3], &p_cid[coIPoIB_CID_TotalLen - sizeof (ib_net64_t)], + sizeof (ib_net64_t) ); + // Clear the rest + RtlFillMemory( &p_cid[3+sizeof (ib_net64_t)], + coIPoIB_CID_TotalLen - 3 -sizeof (ib_net64_t), 0 ); + + RtlCopyMemory( p_dhcp->chaddr, &p_src->mac, sizeof(p_src->mac) ); + RtlFillMemory( &p_dhcp->chaddr[sizeof(p_src->mac)], + ( sizeof(p_dhcp->chaddr) - sizeof(p_src->mac) ), 0 ); + } + IPOIB_EXIT( IPOIB_DBG_RECV ); + return status; +} + + +static ib_api_status_t +__recv_arp( + IN ipoib_port_t* const p_port, + IN ib_wc_t* const p_wc, + IN const ipoib_pkt_t* const p_ipoib, + OUT eth_pkt_t* const p_eth, + IN ipoib_endpt_t** const pp_src, + IN ipoib_endpt_t* const p_dst ) +{ + ib_api_status_t status; + arp_pkt_t *p_arp; + const ipoib_arp_pkt_t *p_ib_arp; + ib_gid_t gid; + mac_addr_t mac; + ipoib_hw_addr_t null_hw = {0}; + uint8_t cm_capable = 0; + + IPOIB_ENTER( IPOIB_DBG_RECV ); + + if( !p_dst ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Unknown destination endpoint\n") ); + return IB_INVALID_SETTING; + } + + p_ib_arp = &p_ipoib->type.arp; + p_arp = &p_eth->type.arp; + + if( p_ib_arp->hw_type != ARP_HW_TYPE_IB ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ARP hardware type is not IB\n") ); + return IB_INVALID_SETTING; + } + + if( p_ib_arp->hw_size != sizeof(ipoib_hw_addr_t) ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ARP hardware address size is not sizeof(ipoib_hw_addr_t)\n") ); + return IB_INVALID_SETTING; + } + + if( p_ib_arp->prot_type != ETH_PROT_TYPE_IP ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ARP protocal type not IP?\n") ); + return IB_INVALID_SETTING; + } + + cm_capable = ipoib_addr_get_flags( &p_ib_arp->src_hw ); + + /* + * If we don't have a source, lookup the endpoint specified in the payload. + */ + if( !*pp_src ) + *pp_src = __endpt_mgr_get_by_gid( p_port, &p_ib_arp->src_hw.gid ); + + /* + * If the endpoint exists for the GID, make sure + * the dlid and qpn match the arp. + */ + if( *pp_src ) + { + if( cl_memcmp( &(*pp_src)->dgid, &p_ib_arp->src_hw.gid, sizeof(ib_gid_t) ) ) + { + /* + * GIDs for the endpoint are different. The ARP must + * have been proxied. Dereference it. + */ + *pp_src = NULL; + } + else if( (*pp_src)->dlid && (*pp_src)->dlid != p_wc->recv.ud.remote_lid ) + { + /* Out of date! Destroy the endpoint and replace it. */ + __endpt_mgr_remove( p_port, *pp_src ); + *pp_src = NULL; + } + else if ( ! ((*pp_src)->dlid)) + { + /* Out of date! Destroy the endpoint and replace it. */ + __endpt_mgr_remove( p_port, *pp_src ); + *pp_src = NULL; + } + else if( ipoib_is_voltaire_router_gid( &(*pp_src)->dgid ) ) + { + if( (*pp_src)->qpn != ipoib_addr_get_qpn( &p_ib_arp->src_hw ) && + p_wc->recv.ud.remote_qp != ipoib_addr_get_qpn( &p_ib_arp->src_hw ) ) + { + /* Out of date! Destroy the endpoint and replace it. */ + __endpt_mgr_remove( p_port, *pp_src ); + *pp_src = NULL; + } + } + else if( (*pp_src)->qpn != p_wc->recv.ud.remote_qp ) + { + /* Out of date! Destroy the endpoint and replace it. */ + __endpt_mgr_remove( p_port, *pp_src ); + *pp_src = NULL; + } + } + + /* Do we need to create an endpoint for this GID? */ + if( !*pp_src ) + { + /* Copy the src GID to allow aligned access */ + cl_memcpy( &gid, &p_ib_arp->src_hw.gid, sizeof(ib_gid_t) ); + status = ipoib_mac_from_guid( gid.unicast.interface_id, + p_port->p_adapter->params.guid_mask, + &mac ); + if (status == IB_INVALID_GUID_MASK) + { + IPOIB_PRINT( TRACE_LEVEL_WARNING, IPOIB_DBG_ERROR, + ("Invalid GUID mask received, rejecting it") ); + ipoib_create_log( p_port->p_adapter->h_adapter, + GUID_MASK_LOG_INDEX, + EVENT_IPOIB_WRONG_PARAMETER_WRN ); + return status; + } + else if( status != IB_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ipoib_mac_from_guid returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + return status; + } + + /* + * Create the endpoint. + */ + *pp_src = ipoib_endpt_create( &p_ib_arp->src_hw.gid, + p_wc->recv.ud.remote_lid, ipoib_addr_get_qpn( &p_ib_arp->src_hw ) ); + + if( !*pp_src ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ipoib_endpt_create failed\n") ); + return status; + } + + cl_obj_lock( &p_port->obj ); + status = __endpt_mgr_insert( p_port, mac, *pp_src ); + if( status != IB_SUCCESS ) + { + cl_obj_unlock( &p_port->obj ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("__endpt_mgr_insert return %s \n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + return status; + } + cl_obj_unlock( &p_port->obj ); + } + + (*pp_src)->cm_flag = cm_capable; + + CL_ASSERT( !cl_memcmp( + &(*pp_src)->dgid, &p_ib_arp->src_hw.gid, sizeof(ib_gid_t) ) ); + CL_ASSERT( ipoib_is_voltaire_router_gid( &(*pp_src)->dgid ) || + (*pp_src)->qpn == ipoib_addr_get_qpn( &p_ib_arp->src_hw ) ); +#if 0 + if( p_port->p_adapter->params.cm_enabled && + p_ib_arp->op == ARP_OP_REQ && + cm_capable == IPOIB_CM_FLAG_RC ) + { + /* if we've got ARP request and RC flag is set, + save SID for connect REQ to be sent in ARP reply + when requestor's path get resolved */ + if( endpt_cm_get_state( (*pp_src) ) == IPOIB_CM_DISCONNECTED ) + { + (*pp_src)->cm_flag = cm_capable; + ipoib_addr_set_sid( + &(*pp_src)->conn.service_id, + ipoib_addr_get_qpn( &p_ib_arp->src_hw ) ); + } + } +#endif +#if 0 //DBG + if( p_port->p_adapter->params.cm_enabled ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, + (" ARP %s from ENDPT[%p] state %d CM cap: %d QPN: %#x MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", + ((p_ib_arp->op == ARP_OP_REQ )? "REQUEST" : "REPLY"), + *pp_src, endpt_cm_get_state( *pp_src ), + ((cm_capable == IPOIB_CM_FLAG_RC)? 1: 0), + cl_ntoh32( ipoib_addr_get_qpn( &p_ib_arp->src_hw ) ), + (*pp_src)->mac.addr[0], (*pp_src)->mac.addr[1], + (*pp_src)->mac.addr[2], (*pp_src)->mac.addr[3], + (*pp_src)->mac.addr[4], (*pp_src)->mac.addr[5] )); + } +#endif + + /* Now swizzle the data. */ + p_arp->hw_type = ARP_HW_TYPE_ETH; + p_arp->hw_size = sizeof(mac_addr_t); + p_arp->src_hw = (*pp_src)->mac; + p_arp->src_ip = p_ib_arp->src_ip; + + if( cl_memcmp( &p_ib_arp->dst_hw, &null_hw, sizeof(ipoib_hw_addr_t) ) ) + { + if( cl_memcmp( &p_dst->dgid, &p_ib_arp->dst_hw.gid, sizeof(ib_gid_t) ) ) + { + /* + * We received bcast ARP packet that means the remote port + * lets everyone know it was changed IP/MAC or just activated + */ + + /* Guy: TODO: Check why this check fails in case of Voltaire IPR */ + + if ( !ipoib_is_voltaire_router_gid( &(*pp_src)->dgid ) && + !ib_gid_is_multicast( (const ib_gid_t*)&p_dst->dgid ) ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ARP: is not ARP MCAST\n") ); + return IB_INVALID_SETTING; + } + + p_arp->dst_hw = p_port->p_local_endpt->mac; + p_dst->mac = p_port->p_local_endpt->mac; + /* + * we don't care what receiver ip addr is, + * as long as OS' ARP table is global ??? + */ + p_arp->dst_ip = (net32_t)0; + } + else /* we've got reply to our ARP request */ + { + p_arp->dst_hw = p_dst->mac; + p_arp->dst_ip = p_ib_arp->dst_ip; + CL_ASSERT( p_dst->qpn == ipoib_addr_get_qpn( &p_ib_arp->dst_hw ) ); + } + } + else /* we got ARP request */ + { + cl_memclr( &p_arp->dst_hw, sizeof(mac_addr_t) ); + p_arp->dst_ip = p_ib_arp->dst_ip; + } + + /* + * Create the ethernet header. Note that this is done last so that + * we have a chance to create a new endpoint. + */ + status = __recv_gen( p_ipoib, p_eth, *pp_src, p_dst ); + + if( status != IB_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("__recv_gen returned %s.\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + return status; + } + + IPOIB_EXIT( IPOIB_DBG_RECV ); + return IB_SUCCESS; +} + + +static ib_api_status_t +__recv_mgr_prepare_NBL( + IN ipoib_port_t* const p_port, + IN ipoib_recv_desc_t* const p_desc, + OUT NET_BUFFER_LIST** const pp_net_buffer_list ) +{ + NDIS_STATUS status; + uint32_t pkt_filter; + NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO chksum; + + PERF_DECLARE( GetNdisPkt ); + + IPOIB_ENTER( IPOIB_DBG_RECV ); + + pkt_filter = p_port->p_adapter->packet_filter; + /* Check the packet filter. */ + switch( p_desc->type ) + { + default: + case PKT_TYPE_UCAST: + + if( pkt_filter & NDIS_PACKET_TYPE_PROMISCUOUS || + pkt_filter & NDIS_PACKET_TYPE_ALL_FUNCTIONAL || + pkt_filter & NDIS_PACKET_TYPE_SOURCE_ROUTING || + pkt_filter & NDIS_PACKET_TYPE_DIRECTED ) + { + /* OK to report. */ + status = NDIS_STATUS_SUCCESS; + IPOIB_PRINT( TRACE_LEVEL_VERBOSE, IPOIB_DBG_RECV, + ("Received UCAST PKT.\n")); + } + else + { + status = NDIS_STATUS_FAILURE; + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Received UCAST PKT with ERROR !!!!\n")); + } + break; + case PKT_TYPE_BCAST: + if( pkt_filter & NDIS_PACKET_TYPE_PROMISCUOUS || + pkt_filter & NDIS_PACKET_TYPE_BROADCAST ) + { + /* OK to report. */ + status = NDIS_STATUS_SUCCESS; + IPOIB_PRINT( TRACE_LEVEL_VERBOSE, IPOIB_DBG_RECV, + ("Received BCAST PKT.\n")); + } + else + { + status = NDIS_STATUS_FAILURE; + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Received BCAST PKT with ERROR!!!! pkt_filter 0x%x\n",pkt_filter)); + } + break; + case PKT_TYPE_MCAST: + if( pkt_filter & NDIS_PACKET_TYPE_PROMISCUOUS || + pkt_filter & NDIS_PACKET_TYPE_ALL_MULTICAST || + pkt_filter & NDIS_PACKET_TYPE_MULTICAST ) + { + /* OK to report. */ + status = NDIS_STATUS_SUCCESS; + IPOIB_PRINT( TRACE_LEVEL_VERBOSE, IPOIB_DBG_RECV, + ("Received UCAST PKT.\n")); + } + else + { + status = NDIS_STATUS_FAILURE; + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Received MCAST PKT with ERROR !!!!\n")); + } + break; + } + + if( status != NDIS_STATUS_SUCCESS ) + { + /* Return the receive descriptor to the pool. */ + __buf_mgr_put_recv( p_port, p_desc, NULL ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Packet filter doesn't match receive. Dropping.\n") ); + /* + * Return IB_NOT_DONE since the packet has been completed, + * but has not consumed an array entry. + */ + return IB_NOT_DONE; + } + + cl_perf_start( GetNdisPkt ); + *pp_net_buffer_list = __buf_mgr_get_NBL( p_port, p_desc ); + cl_perf_stop( &p_port->p_adapter->perf, GetNdisPkt ); + if( !*pp_net_buffer_list ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("__buf_mgr_get_NBL failed\n") ); + return IB_INSUFFICIENT_RESOURCES; + } + + chksum.Value = 0; + + PNET_BUFFER NetBuffer = NET_BUFFER_LIST_FIRST_NB(*pp_net_buffer_list); + NET_BUFFER_DATA_LENGTH(NetBuffer) = p_desc->len; + + switch( p_port->p_adapter->params.recv_chksum_offload ) + { + default: + CL_ASSERT( FALSE ); + case CSUM_DISABLED: + NET_BUFFER_LIST_INFO(*pp_net_buffer_list, TcpIpChecksumNetBufferListInfo) = + (void*)(uintn_t)chksum.Value; + break; + case CSUM_ENABLED: + /* Get the checksums directly from packet information. + * In this case, no one of cheksum's cat get false value + * If hardware checksum failed or wasn't calculated, NDIS will recalculate + * it again + */ + NET_BUFFER_LIST_INFO(*pp_net_buffer_list, TcpIpChecksumNetBufferListInfo) = + (void*)(uintn_t)(p_desc->ndis_csum.Value); + break; + case CSUM_BYPASS: + /* Flag the checksums as having been calculated. */ + chksum.Receive.TcpChecksumSucceeded = + chksum.Receive.UdpChecksumSucceeded = + chksum.Receive.IpChecksumSucceeded = TRUE; + + NET_BUFFER_LIST_INFO(*pp_net_buffer_list, TcpIpChecksumNetBufferListInfo) = + (void*)(uintn_t)chksum.Value; + break; + } + + IPOIB_EXIT( IPOIB_DBG_RECV ); + return IB_SUCCESS; +} + + +static uint32_t +__recv_mgr_build_NBL_array( + IN ipoib_port_t* const p_port, + OUT cl_qlist_t* p_done_list OPTIONAL, + OUT int32_t* const p_discarded ) +{ + cl_list_item_t *p_item; + ipoib_recv_desc_t *p_desc; + uint32_t i = 0; + ib_api_status_t status; + + PERF_DECLARE( PreparePkt ); + + IPOIB_ENTER( IPOIB_DBG_RECV ); + + *p_discarded = 0; + + /* to preserve ordering move existing receives to the head of p_done_list */ + if ( p_done_list ) { + cl_qlist_insert_list_head( p_done_list, &p_port->recv_mgr.done_list ); + } else { + p_done_list = &p_port->recv_mgr.done_list; + } + p_item = cl_qlist_remove_head( p_done_list ); + while( p_item != cl_qlist_end( p_done_list ) ) + { + p_desc = (ipoib_recv_desc_t*)p_item; + + cl_perf_start( PreparePkt ); + status = __recv_mgr_prepare_NBL( p_port, p_desc, + &p_port->recv_mgr.recv_NBL_array[i] ); + cl_perf_stop( &p_port->p_adapter->perf, PreparePkt ); + if( status == IB_SUCCESS ) + { + CL_ASSERT( p_port->recv_mgr.recv_NBL_array[i] ); + + if (i) + { // Link NBLs together + NET_BUFFER_LIST_NEXT_NBL(p_port->recv_mgr.recv_NBL_array[i-1]) = + p_port->recv_mgr.recv_NBL_array[i]; + } + i++; + } + else if( status == IB_NOT_DONE ) + { + (*p_discarded)++; + } + else + { + IPOIB_PRINT(TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("__recv_mgr_prepare_NBL returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + /* Put all completed receives on the port's done list. */ + if ( p_done_list != &p_port->recv_mgr.done_list) { + cl_qlist_insert_tail( &p_port->recv_mgr.done_list, p_item ); + cl_qlist_insert_list_tail( &p_port->recv_mgr.done_list, p_done_list ); + } else { + cl_qlist_insert_head( &p_port->recv_mgr.done_list, p_item ); + } + break; + } + + p_item = cl_qlist_remove_head( p_done_list ); + } + + IPOIB_EXIT( IPOIB_DBG_RECV ); + return i; +} + + + + +/****************************************************************************** +* +* Send manager implementation. +* +******************************************************************************/ +static void +__send_mgr_construct( + IN ipoib_port_t* const p_port ) +{ + IPOIB_ENTER( IPOIB_DBG_SEND ); + p_port->send_mgr.depth = 0; + cl_qlist_init( &p_port->send_mgr.pending_list ); + cl_qpool_construct( &p_port->send_mgr.send_pool ); + p_port->p_desc = NULL; + IPOIB_EXIT( IPOIB_DBG_SEND ); +} + +static ib_api_status_t +__send_mgr_init( + IN ipoib_port_t* const p_port ) +{ + cl_status_t cl_status; + + IPOIB_ENTER(IPOIB_DBG_SEND ); + + CL_ASSERT( p_port ); + + static const size_t cPoolDeltaSize(1024); + static const ULONG MaxNumBuffers(16384); + + /* Allocate the pool for async NETBUF flow (process_sg_list) */ + cl_status = cl_qpool_init( + &p_port->send_mgr.sg_pool, + MaxNumBuffers, + 0, + cPoolDeltaSize, + sizeof(cl_pool_item_t) + p_port->p_adapter->sg_list_size, + NULL, + NULL, + p_port ); + + if( cl_status != CL_SUCCESS ) + { + NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter, + EVENT_IPOIB_RECV_POOL, 1, cl_status ); //TODO EVENT_IPOIB_SEND_POOL + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("cl_qpool_init for sends returned %#x\n", + cl_status) ); + IPOIB_EXIT(IPOIB_DBG_SEND ); + return IB_INSUFFICIENT_MEMORY; + } + + cl_status = cl_qpool_init( &p_port->send_mgr.send_pool, + MaxNumBuffers, + 0, + cPoolDeltaSize, + sizeof(ipoib_send_NB_SG), + NULL, + NULL, + p_port ); + + if( cl_status != CL_SUCCESS ) + { + NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter, + EVENT_IPOIB_RECV_POOL, 1, cl_status ); //TODO EVENT_IPOIB_SEND_POOL + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("cl_qpool_init for sends returned %#x\n", cl_status) ); + cl_qpool_destroy(&p_port->send_mgr.sg_pool); + return IB_INSUFFICIENT_MEMORY; + } + + //This send descriptor can't be allocated on the stack because of boundary + // violation !!! + p_port->p_desc = (ipoib_send_desc_t *) + ExAllocatePoolWithTag(NonPagedPool ,sizeof (ipoib_send_desc_t), 'XMXA'); + if (!p_port->p_desc) { + NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter, + EVENT_IPOIB_RECV_POOL, 1, CL_INSUFFICIENT_MEMORY); //TODO EVENT_IPOIB_SEND_POOL + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Allocation of send descriptor failed\n") ); + cl_qpool_destroy(&p_port->send_mgr.send_pool); + cl_qpool_destroy(&p_port->send_mgr.sg_pool); + return IB_INSUFFICIENT_MEMORY; + } + return IB_SUCCESS; +} + + +static void +__pending_list_destroy( + IN ipoib_port_t* const p_port ) +{ + cl_list_item_t *p_item; + ipoib_send_NB_SG *s_buf; + ULONG send_complete_flags = NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL; + + /* Complete any pending packets. */ + for( p_item = cl_qlist_remove_head( &p_port->send_mgr.pending_list ); + p_item != cl_qlist_end( &p_port->send_mgr.pending_list ); + p_item = cl_qlist_remove_head( &p_port->send_mgr.pending_list ) ) + { + s_buf = (ipoib_send_NB_SG*) (PVOID) p_item; // TODO: Check this casting + ASSERT(s_buf->p_port == p_port); + ASSERT(s_buf->p_nbl); + + //TODO + //__send_complete_net_buffer(s_buf, NDIS_STATUS_RESET_IN_PROGRESS,send_complete_flags,TRUE); + __send_complete_net_buffer(s_buf, NDIS_STATUS_FAILURE,send_complete_flags,TRUE); + } + +} + +static void +__send_mgr_destroy( + IN ipoib_port_t* const p_port ) +{ + IPOIB_ENTER( IPOIB_DBG_SEND ); + //Destroy pending list and put all the send buffers back to pool + //The list should be already destroyed at this point + ASSERT(p_port->send_mgr.pending_list.count == 0); + cl_spinlock_acquire( &p_port->send_lock ); + __pending_list_destroy(p_port); + cl_spinlock_release( &p_port->send_lock ); + + // Now, destroy the send pool + cl_qpool_destroy(&p_port->send_mgr.send_pool); + cl_qpool_destroy(&p_port->send_mgr.sg_pool); + + //Now, free port descriptor + ExFreePoolWithTag(p_port->p_desc, 'XMXA'); + + //Lookaside list will be destroyed in __buf_mgr_destroy + + IPOIB_EXIT( IPOIB_DBG_SEND ); +} + + +static NDIS_STATUS +__send_mgr_filter( + IN const eth_hdr_t* const p_eth_hdr, + IN MDL* const p_mdl, + IN size_t buf_len, + IN OUT ipoib_send_NB_SG *s_buf ) +{ + NDIS_STATUS status; + + PERF_DECLARE( FilterIp ); + PERF_DECLARE( FilterArp ); + PERF_DECLARE( SendGen ); + + IPOIB_ENTER( IPOIB_DBG_SEND ); + + /* + * We already checked the ethernet header length, so we know it's safe + * to decrement the buf_len without underflowing. + */ + ipoib_send_desc_t *p_desc = s_buf->p_port->p_desc; + buf_len -= sizeof(eth_hdr_t); + + switch( p_eth_hdr->type ) + { + case ETH_PROT_TYPE_IP: + cl_perf_start( FilterIp ); + status = __send_mgr_filter_ip( p_eth_hdr, p_mdl, buf_len, s_buf ); + cl_perf_stop( &p_port->p_adapter->perf, FilterIp ); + break; + + case ETH_PROT_TYPE_ARP: + cl_perf_start( FilterArp ); + status = __send_mgr_filter_arp( p_eth_hdr, p_mdl, buf_len, s_buf ); + p_desc->send_dir = SEND_UD_QP; + cl_perf_stop( &p_port->p_adapter->perf, FilterArp ); + break; + + default: + /* + * The IPoIB spec doesn't define how to send non IP or ARP packets. + * Just send the payload and hope for the best. + */ + + p_desc->send_dir = SEND_UD_QP; + cl_perf_start( SendGen ); + status = __send_gen( s_buf, 0, 0 ); + cl_perf_stop( &p_port->p_adapter->perf, SendGen ); + break; + } + + IPOIB_EXIT( IPOIB_DBG_SEND ); + return status; +} + + +// TODO: move the p_desc to be on the send buffer + +ULONG +CopyNetBuffer( + PNET_BUFFER NetBuffer, + PUCHAR pDest + ) +{ + ULONG BytesCopied = 0; + + IPOIB_ENTER(IPOIB_DBG_SEND); + + PUCHAR pSrc = NULL; + + PMDL CurrentMdl = NET_BUFFER_CURRENT_MDL(NetBuffer); + ULONG Offset = NET_BUFFER_CURRENT_MDL_OFFSET(NetBuffer); + ULONG DataLength = NET_BUFFER_DATA_LENGTH(NetBuffer); + + if (DataLength > MAX_LSO_PAYLOAD_MTU) { + ASSERT(FALSE); + IPOIB_PRINT_EXIT(TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Can't copy buffer of %d because of 64K limitation\n", DataLength)); + return 0; + } + + while (CurrentMdl && DataLength > 0) + { + ULONG CurrLength; + NdisQueryMdl(CurrentMdl, &pSrc, &CurrLength, NormalPagePriority); + if (pSrc == NULL) + { + BytesCopied = 0; + break; + } + // + // Current buffer length is greater than the offset to the buffer + // + if (CurrLength > Offset) + { + pSrc += Offset; + CurrLength -= Offset; + + if (CurrLength > DataLength) + { + CurrLength = DataLength; + } + DataLength -= CurrLength; + NdisMoveMemory(pDest, pSrc, CurrLength); + BytesCopied += CurrLength; + + pDest += CurrLength; + pSrc += CurrLength; + Offset = 0; + } + else + { + ASSERT(FALSE); + Offset -= CurrLength; + } + NdisGetNextMdl(CurrentMdl, &CurrentMdl); + } + + if (DataLength > 0) + { + // + // In some cases the size in MDL isn't equal to the buffer size. In such + // a case we need to copy the rest of packet + // +#ifdef _WIN64 + ASSERT((((uint64_t)pSrc % PAGE_SIZE) + DataLength) <= PAGE_SIZE); +#else + ASSERT((((uint32_t)pSrc % PAGE_SIZE) + DataLength) <= PAGE_SIZE); +#endif + NdisMoveMemory(pDest, pSrc, DataLength); + BytesCopied += DataLength; + } + +#if 0 + if ((BytesCopied != 0) && (BytesCopied < NIC_MIN_PACKET_SIZE)) + { + NdisZeroMemory(pDest, NIC_MIN_PACKET_SIZE - BytesCopied); + } +#endif + + // NdisAdjustMdlLength(pMpTxBuf->Mdl, BytesCopied); + // NdisFlushBuffer(pMpTxBuf->Mdl, TRUE); + + //ASSERT(BytesCopied <= pMpTxBuf->BufferSize); + + IPOIB_EXIT(IPOIB_DBG_SEND); + return BytesCopied; +} + + +static NDIS_STATUS +__send_copy( + IN ipoib_port_t* const p_port, + IN ipoib_send_NB_SG * s_buf, + IN UINT lso_header_size) +{ + ULONG tot_len = 0; + + IPOIB_ENTER( IPOIB_DBG_SEND ); + + ipoib_send_desc_t *p_desc = p_port->p_desc; + + ASSERT(s_buf->p_send_buf == NULL); + s_buf->p_send_buf = + (send_buf_t *) NdisAllocateFromNPagedLookasideList( &p_port->buf_mgr.send_buf_list ); + if( !s_buf->p_send_buf ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to allocate buffer for packet copy.\n") ); + return NDIS_STATUS_RESOURCES; + } + tot_len = CopyNetBuffer(s_buf->p_curr_nb, (PUCHAR) s_buf->p_send_buf); + if (tot_len <= lso_header_size) { + ASSERT(tot_len > lso_header_size); + return NDIS_STATUS_FAILURE; + } + //TODO Do not copy the ETH header + /* Setup the work request. */ + int seg_index = lso_header_size ? 0 : 1; + + p_desc->send_wr[0].local_ds[seg_index].vaddr = cl_get_physaddr( + ((uint8_t*)s_buf->p_send_buf) + lso_header_size ); + p_desc->send_wr[0].local_ds[seg_index].length = tot_len - lso_header_size; + p_desc->send_wr[0].local_ds[seg_index].lkey = p_port->ib_mgr.lkey; + p_desc->send_wr[0].wr.num_ds = seg_index+1; + + + IPOIB_EXIT( IPOIB_DBG_SEND ); + return NDIS_STATUS_SUCCESS; +} + +static inline NDIS_STATUS +__send_mgr_get_eth_hdr( + IN PNET_BUFFER p_net_buffer, + OUT MDL** const pp_mdl, + OUT eth_hdr_t** const pp_eth_hdr, + OUT UINT* p_mdl_len) +{ + PUCHAR p_head = NULL; + IPOIB_ENTER( IPOIB_DBG_SEND ); + + *pp_mdl = NET_BUFFER_FIRST_MDL(p_net_buffer); + + NdisQueryMdl(*pp_mdl,&p_head,p_mdl_len,NormalPagePriority); + if( ! p_head ) + { + /* Failed to get first buffer. */ + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("NdisQueryMdl failed.\n") ); + return NDIS_STATUS_FAILURE; + } + + ULONG MdlDataOffset = NET_BUFFER_CURRENT_MDL_OFFSET(p_net_buffer); + *p_mdl_len -= MdlDataOffset; + + if( *p_mdl_len < sizeof(eth_hdr_t) ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("First buffer in packet smaller than eth_hdr_t: %d.\n", *p_mdl_len) ); + return NDIS_STATUS_BUFFER_TOO_SHORT; + } + + *pp_eth_hdr = (eth_hdr_t*)(p_head + MdlDataOffset); + + IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_SEND, + ("Ethernet header:\n" + "\tsrc MAC: %02X-%02X-%02X-%02X-%02X-%02X\n" + "\tdst MAC: %02X-%02X-%02X-%02X-%02X-%02X\n" + "\tprotocol type: %04X\n", + (*pp_eth_hdr)->src.addr[0], (*pp_eth_hdr)->src.addr[1], + (*pp_eth_hdr)->src.addr[2], (*pp_eth_hdr)->src.addr[3], + (*pp_eth_hdr)->src.addr[4], (*pp_eth_hdr)->src.addr[5], + (*pp_eth_hdr)->dst.addr[0], (*pp_eth_hdr)->dst.addr[1], + (*pp_eth_hdr)->dst.addr[2], (*pp_eth_hdr)->dst.addr[3], + (*pp_eth_hdr)->dst.addr[4], (*pp_eth_hdr)->dst.addr[5], + cl_ntoh16( (*pp_eth_hdr)->type )) ); + + return NDIS_STATUS_SUCCESS; +} + + +#if !IPOIB_USE_DMA + +/* Send using the MDL's page information rather than the SGL. */ +static ib_api_status_t +__send_gen( + IN ipoib_port_t* const p_port, + IN ipoib_send_desc_t* const p_desc ) +{ + uint32_t i, j = 1; + ULONG offset; + MDL *p_mdl; + UINT num_pages, tot_len; + ULONG buf_len; + PPFN_NUMBER page_array; + boolean_t hdr_done = FALSE; + ib_api_status_t status; + PNET_BUFFER p_net_buf; + + IPOIB_ENTER( IPOIB_DBG_SEND ); + p_net_buf = NET_BUFFER_LIST_FIRST_NB(p_desc->p_netbuf_list); + NdisQueryBuffer( p_net_buf, &num_pages, NULL, &p_mdl, + &tot_len ); + + if( !p_mdl ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("No buffers associated with packet.\n") ); + return IB_ERROR; + } + + /* Remember that one of the DS entries is reserved for the IPoIB header. */ + if( num_pages >= MAX_SEND_SGE ) + { + IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_SEND, + ("Too many buffers to fit in WR ds_array. Copying data.\n") ); + status = __send_copy( p_port, p_desc ); + IPOIB_EXIT( IPOIB_DBG_SEND ); + return status; + } + + CL_ASSERT( tot_len > sizeof(eth_hdr_t) ); + CL_ASSERT( tot_len <= p_port->p_adapter->params.xfer_block_size ); + /* + * Assume that the ethernet header is always fully contained + * in the first page of the first MDL. This makes for much + * simpler code. + */ + offset = MmGetMdlByteOffset( p_mdl ) + sizeof(eth_hdr_t); + CL_ASSERT( offset <= PAGE_SIZE ); + + while( tot_len ) + { + buf_len = MmGetMdlByteCount( p_mdl ); + page_array = MmGetMdlPfnArray( p_mdl ); + CL_ASSERT( page_array ); + i = 0; + if( !hdr_done ) + { + CL_ASSERT( buf_len >= sizeof(eth_hdr_t) ); + /* Skip the ethernet header. */ + buf_len -= sizeof(eth_hdr_t); + CL_ASSERT( buf_len <= p_port->p_adapter->params.payload_mtu ); + if( buf_len ) + { + /* The ethernet header is a subset of this MDL. */ + CL_ASSERT( i == 0 ); + if( offset < PAGE_SIZE ) + { + p_desc->send_wr[0].local_ds[j].lkey = p_port->ib_mgr.lkey; + p_desc->send_wr[0].local_ds[j].vaddr = (page_array[i] << PAGE_SHIFT); + /* Add the byte offset since we're on the 1st page. */ + p_desc->send_wr[0].local_ds[j].vaddr += offset; + if( offset + buf_len > PAGE_SIZE ) + { + p_desc->send_wr[0].local_ds[j].length = PAGE_SIZE - offset; + buf_len -= p_desc->send_wr[0].local_ds[j].length; + } + else + { + p_desc->send_wr[0].local_ds[j].length = buf_len; + buf_len = 0; + } + /* This data segment is done. Move to the next. */ + j++; + } + /* This page is done. Move to the next. */ + i++; + } + /* Done handling the ethernet header. */ + hdr_done = TRUE; + } + + /* Finish this MDL */ + while( buf_len ) + { + p_desc->send_wr[0].local_ds[j].lkey = p_port->ib_mgr.lkey; + p_desc->send_wr[0].local_ds[j].vaddr = (page_array[i] << PAGE_SHIFT); + /* Add the first page's offset if we're on the first page. */ + if( i == 0 ) + p_desc->send_wr[0].local_ds[j].vaddr += MmGetMdlByteOffset( p_mdl ); + + if( i == 0 && (MmGetMdlByteOffset( p_mdl ) + buf_len) > PAGE_SIZE ) + { + /* Buffers spans pages. */ + p_desc->send_wr[0].local_ds[j].length = + PAGE_SIZE - MmGetMdlByteOffset( p_mdl ); + buf_len -= p_desc->send_wr[0].local_ds[j].length; + /* This page is done. Move to the next. */ + i++; + } + else + { + /* Last page of the buffer. */ + p_desc->send_wr[0].local_ds[j].length = buf_len; + buf_len = 0; + } + /* This data segment is done. Move to the next. */ + j++; + } + + tot_len -= MmGetMdlByteCount( p_mdl ); + if( !tot_len ) + break; + + NdisGetNextBuffer( p_mdl, &p_mdl ); + if( !p_mdl ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to get next buffer.\n") ); + return IB_ERROR; + } + } + + /* Set the number of data segments. */ + p_desc->send_wr[0].wr.num_ds = j; + + IPOIB_EXIT( IPOIB_DBG_SEND ); + return IB_SUCCESS; +} + +#else + + +ULONG g_ipoib_send_mcast = 0; + +// returns true if buffer was sent + +bool +ipoib_process_sg_list_real( + IN PDEVICE_OBJECT pDO, + IN PVOID pIrp, + IN PSCATTER_GATHER_LIST p_sgl, + IN PVOID context ) +{ + NDIS_STATUS status; + ipoib_port_t *p_port; + MDL *p_mdl; + eth_hdr_t *p_eth_hdr; + UINT mdl_len; + bool ret = false; + + ib_send_wr_t *p_wr_failed; + NET_BUFFER_LIST *p_net_buffer_list; + NET_BUFFER *p_netbuf; + boolean_t from_queue; + ib_api_status_t ib_status; + ULONG complete_flags = 0; + ipoib_send_NB_SG *s_buf; + ipoib_send_desc_t *p_desc; + + IPOIB_ENTER( IPOIB_DBG_SEND ); + + ASSERT(p_sgl != NULL); + + UNREFERENCED_PARAMETER(pDO); + UNREFERENCED_PARAMETER(pIrp); + + PERF_DECLARE( SendCopy ); + PERF_DECLARE( BuildSendDesc ); + PERF_DECLARE( GetEthHdr ); + PERF_DECLARE( QueuePacket ); + PERF_DECLARE( SendMgrQueue ); + PERF_DECLARE( PostSend ); + PERF_DECLARE( ProcessFailedSends ); + PERF_DECLARE( GetEndpt ); + + ++g_ipoib_send_SG_real; + + //Read Data from the buffer passed as a context + s_buf = (ipoib_send_NB_SG *)context; + p_net_buffer_list = s_buf->p_nbl; + p_netbuf = s_buf->p_curr_nb; + p_port = s_buf->p_port; + p_desc = p_port->p_desc; + + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_BUF, + ("Processing netbuffer list %p s_buf %p\n", p_net_buffer_list, s_buf) ); + + //TODO Define this function as void if we are not in DBG mode + //cl_qlist_check_validity(&p_port->send_mgr.pending_list); + + NDIS_SET_SEND_COMPLETE_FLAG(complete_flags, + NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL); + + CL_ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); + + p_port->p_desc->p_netbuf_list = p_net_buffer_list; + p_port->p_desc->p_endpt = NULL; + s_buf->p_send_buf = NULL; + p_port->p_desc->num_wrs = 1; + + IPOIB_PRINT( TRACE_LEVEL_VERBOSE, IPOIB_DBG_SEND, + ("\nRECEIVED NB= %p with SG= %p\n********\n", p_netbuf, p_sgl) ); + + /* Get the ethernet header so we can find the endpoint. */ + cl_perf_start( GetEthHdr ); + + status = __send_mgr_get_eth_hdr( p_netbuf, &p_mdl, &p_eth_hdr, &mdl_len ); + + cl_perf_stop( &p_port->p_adapter->perf, GetEthHdr ); + + if( status != NDIS_STATUS_SUCCESS ) + { + cl_perf_start( ProcessFailedSends ); + /* fail net buffer */ + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to get Eth hdr - send inside process SG list\n")); + __send_complete_net_buffer(s_buf, status, complete_flags, TRUE); + + cl_perf_stop( &p_port->p_adapter->perf, ProcessFailedSends ); + ret = true; + goto send_end; + } + + from_queue = (boolean_t)(s_buf->p_sgl != NULL); + + if (from_queue) + { + cl_perf_start( GetEndpt ); + status = __endpt_mgr_ref( p_port, + p_eth_hdr->dst, + &(p_port->p_desc->p_endpt) ); + + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_ENDPT, + ("__endpt_mgr_ref called on EP %p\n", p_port->p_desc->p_endpt)); + + cl_perf_stop( &p_port->p_adapter->perf, GetEndpt ); + if( status == NDIS_STATUS_PENDING ) + { + s_buf->p_sgl = p_sgl; + cl_qlist_insert_head( &p_port->send_mgr.pending_list, + (cl_list_item_t*)s_buf ); + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_MCAST, + ("We insert this item back to the pending list: %p \n", + p_net_buffer_list)); + ret = false; + goto send_end; + } + else if( status != NDIS_STATUS_SUCCESS ) + { + ASSERT( status == NDIS_STATUS_NO_ROUTE_TO_DESTINATION ); + + if( ETH_IS_MULTICAST( p_eth_hdr->dst.addr ) ) + { + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_MCAST, + ("recived a mc packet (from the queue) %p\n", + p_net_buffer_list)); + if( ipoib_port_join_mcast( p_port, p_eth_hdr->dst, + IB_MC_REC_STATE_FULL_MEMBER) == IB_SUCCESS ) + { + s_buf->p_sgl = p_sgl; + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_MCAST, + ("Insert MULTICAST item back to the pending list %p\n", + p_net_buffer_list)); + cl_qlist_insert_head( &p_port->send_mgr.pending_list, + (cl_list_item_t*) s_buf ); + ret = false; + ++g_ipoib_send_SG_pending; + goto send_end; + } + } + + /* + * Complete the send as if we sent it - WHQL tests don't like the + * sends to fail. + */ + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Bad status: packet has not been sent\n")); + cl_perf_start( ProcessFailedSends ); + + __send_complete_net_buffer( s_buf, + NDIS_STATUS_SUCCESS, + complete_flags, + TRUE ); + ret = true; + goto send_end; + } + } + else //We got this Net Buffer and its SG list directly from NDIS + { + ASSERT(s_buf->p_sgl == NULL); + s_buf->p_sgl = p_sgl; + + cl_perf_start( SendMgrQueue ); + if ( ETH_IS_MULTICAST( p_eth_hdr->dst.addr ) && + p_eth_hdr->type == ETH_PROT_TYPE_IP && + !ETH_IS_BROADCAST( p_eth_hdr->dst.addr ) ) + { + ip_hdr_t *p_ip_hdr; + uint8_t *p_tmp; + MDL *p_ip_hdr_mdl; + UINT ip_hdr_mdl_len; + + IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_MCAST, + ("Sent a Multicast NBL=%p\n", p_net_buffer_list) ); + + g_ipoib_send_mcast++; + + if(mdl_len >= sizeof(ip_hdr_t) + sizeof(eth_hdr_t)) + { + p_ip_hdr = (ip_hdr_t*)(p_eth_hdr + 1); + } + else + { + NdisGetNextMdl(p_mdl,&p_ip_hdr_mdl); + // Extract the ip hdr + if( !p_ip_hdr_mdl ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to get IP header buffer.\n") ); + goto mc_end; + } + NdisQueryMdl(p_ip_hdr_mdl,&p_tmp,&ip_hdr_mdl_len,NormalPagePriority); + if( !p_tmp ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to get IP header.\n") ); + goto mc_end; + } + if( ip_hdr_mdl_len < sizeof(ip_hdr_t) ) + { + /* This buffer is done for. Get the next buffer. */ + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Buffer too small for IP packet.\n") ); + goto mc_end; + } + p_ip_hdr = (ip_hdr_t*)(p_tmp + NET_BUFFER_CURRENT_MDL_OFFSET(p_netbuf)); + + } + p_eth_hdr->dst.addr[1] = ((unsigned char*)&p_ip_hdr->dst_ip)[0] & 0x0f; + p_eth_hdr->dst.addr[3] = ((unsigned char*)&p_ip_hdr->dst_ip)[1]; + + } + +mc_end: + ASSERT(s_buf->p_sgl); + + status = __send_mgr_queue( p_port, p_eth_hdr, &(p_port->p_desc->p_endpt) ); + + cl_perf_stop( &p_port->p_adapter->perf, SendMgrQueue ); + if( status == NDIS_STATUS_PENDING ) + { + /* Queue net buffer list. */ + cl_perf_start( QueuePacket ); + + cl_qlist_insert_tail( &p_port->send_mgr.pending_list, (cl_list_item_t*)s_buf ); + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_SEND, ("Inserting %p NB first time to the pending list\n", p_netbuf)); + + cl_perf_stop( &p_port->p_adapter->perf, QueuePacket ); + ++g_ipoib_send_SG_pending; + ret = false; + goto send_end; + } + + if( status != NDIS_STATUS_SUCCESS ) + { + ASSERT( status == NDIS_STATUS_NO_ROUTE_TO_DESTINATION ); + /* + * Complete the send as if we sent it - WHQL tests don't like the + * sends to fail. + */ + //TODO - check previous comment ! + cl_perf_start( ProcessFailedSends ); + __send_complete_net_buffer( s_buf, + NDIS_STATUS_SUCCESS, + complete_flags, + TRUE ); + cl_perf_stop( &p_port->p_adapter->perf, ProcessFailedSends ); + ret = true; + goto send_end; + } + } + cl_perf_start( BuildSendDesc ); + status = __build_send_desc( p_eth_hdr, + p_mdl, + mdl_len, + s_buf ); + + cl_perf_stop( &p_port->p_adapter->perf, BuildSendDesc ); + + if( status != NDIS_STATUS_SUCCESS ) + { +// ASSERT(FALSE); + cl_perf_start( ProcessFailedSends ); + __send_complete_net_buffer(s_buf, NDIS_STATUS_FAILURE, complete_flags, TRUE); + cl_perf_stop( &p_port->p_adapter->perf, ProcessFailedSends ); + ret = true; + goto send_end; + } + + /* Post the WR. */ + cl_perf_start( PostSend ); + IPOIB_PRINT( TRACE_LEVEL_VERBOSE, IPOIB_DBG_SEND, ("sending packet with wr-id =0x%p\n",p_net_buffer_list )); + + ib_status = p_port->p_adapter->p_ifc->post_send( p_port->ib_mgr.h_qp, &(p_port->p_desc->send_wr[0].wr), &p_wr_failed ); + p_port->n_no_progress = 0; // IPoIB can send, reset the failure counter + ret = true; + cl_perf_stop( &p_port->p_adapter->perf, PostSend ); + if( ib_status != IB_SUCCESS ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_post_send returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( ib_status )) ); + cl_perf_start( ProcessFailedSends ); + __send_complete_net_buffer(s_buf, NDIS_STATUS_FAILURE, complete_flags, TRUE); + cl_perf_stop( &p_port->p_adapter->perf, ProcessFailedSends ); + /* Flag the adapter as hung since posting is busted. */ + p_port->p_adapter->hung = TRUE; + } else { + ++g_ipoib_send; + cl_atomic_inc( &p_port->send_mgr.depth ); + } + +send_end: + + IPOIB_EXIT( IPOIB_DBG_SEND ); + + return ret; +} + + +// This routine called during execution of NdisMAllocateNetBufferSGList(). + +void +ipoib_process_sg_list( + IN PDEVICE_OBJECT pDO, + IN PVOID pIrp, + IN PSCATTER_GATHER_LIST p_sgl, + IN PVOID context ) +{ + ipoib_send_NB_SG * s_buf = (ipoib_send_NB_SG *)context; + ipoib_port_t* p_port = s_buf->p_port; + + cl_spinlock_acquire( &p_port->send_lock ); + + ++g_ipoib_send_SG; + if (g_ipoib_send_SG > 2) { + //ASSERT(g_ipoib_send_SG-2 <= g_ipoib_send + g_ipoib_send_mcast+p_port->send_mgr.pending_list.count+ g_ipoib_send_SG_failed); + } + + ipoib_process_sg_list_real( pDO, pIrp, p_sgl, context ); + + if (g_ipoib_send_SG > 1) { + //ASSERT(g_ipoib_send_SG-1 <= g_ipoib_send + g_ipoib_send_mcast+p_port->send_mgr.pending_list.count + g_ipoib_send_SG_failed); + } + cl_spinlock_release( &p_port->send_lock ); +} + + +static NDIS_STATUS +__send_gen( + IN ipoib_send_NB_SG * s_buf, + IN INT lso_data_index, + IN UINT lso_header_size OPTIONAL) +{ + NDIS_STATUS status; + uint32_t i, j = 1; + ULONG DataOffset = 0; + uint32_t offset = sizeof(eth_hdr_t); + + PERF_DECLARE( SendCopy ); + + IPOIB_ENTER( IPOIB_DBG_SEND ); + + PSCATTER_GATHER_LIST p_sgl = s_buf->p_sgl; + + if( !p_sgl ) + { + ASSERT( p_sgl ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to get SGL from packet.\n") ); + return NDIS_STATUS_FAILURE; + } + ipoib_send_desc_t *p_desc = s_buf->p_port->p_desc; + + /* TODO: Copy only essential data + That is, copy only 2 chunks of ETH header if it contained in several + first SG elements. + Copy only N+1-MAX_SEND_SGE, where N is a lenght of SG List + Remember that one of the DS entries is reserved for the IPoIB header. + */ + if( ( p_sgl->NumberOfElements >= MAX_SEND_SGE || + p_sgl->Elements[0].Length < sizeof(eth_hdr_t)) ) + { + IPOIB_PRINT( TRACE_LEVEL_WARNING, IPOIB_DBG_SEND, + ("Too many buffers %d to fit in WR ds_array[%d] \ + Or buffer[0] length %d < Eth header. Copying data.\n", + p_sgl->NumberOfElements, MAX_SEND_SGE, p_sgl->Elements[0].Length ) ); + + if( !s_buf->p_port->p_adapter->params.cm_enabled ) + { + cl_perf_start( SendCopy ); + status = __send_copy( s_buf->p_port, s_buf, lso_header_size ); + cl_perf_stop( &s_buf->p_port->p_adapter->perf, SendCopy ); + } + + status = NDIS_STATUS_RESOURCES; + IPOIB_EXIT( IPOIB_DBG_SEND ); + return status; + } + + /* + * Skip the ethernet header. It is either the first element, + * or part of it. + */ + i = 0; + DataOffset= (ULONG)(NET_BUFFER_CURRENT_MDL_OFFSET(s_buf->p_curr_nb)); + + if( lso_data_index ) + { /* we have an LSO packet */ + i = lso_data_index; + j = 0; + ASSERT( i <= p_sgl->NumberOfElements); + if (i == p_sgl->NumberOfElements) { + + /**************************** + * Handle the case when there is only one SG element ! + ****************************/ + + p_desc->send_wr[0].local_ds[j].vaddr = + p_sgl->Elements[0].Address.QuadPart + lso_header_size; + p_desc->send_wr[0].local_ds[j].length = + p_sgl->Elements[0].Length - lso_header_size; + p_desc->send_wr[0].local_ds[j].lkey = s_buf->p_port->ib_mgr.lkey; + /* Set the number of data segments. */ + p_desc->send_wr[0].wr.num_ds = 1; + return NDIS_STATUS_SUCCESS; + } + } + else while( offset ) + { + if( p_sgl->Elements[i].Length <= offset ) + { + offset -= p_sgl->Elements[i++].Length; + } + else + { + p_desc->send_wr[0].local_ds[j].vaddr = + p_sgl->Elements[i].Address.QuadPart + offset + DataOffset; + p_desc->send_wr[0].local_ds[j].length = + p_sgl->Elements[i].Length - offset - DataOffset; + p_desc->send_wr[0].local_ds[j].lkey = s_buf->p_port->ib_mgr.lkey; + i++; + j++; + break; + } + } + /* Now fill in the rest of the local data segments. */ + while( i < p_sgl->NumberOfElements ) + { + p_desc->send_wr[0].local_ds[j].vaddr = p_sgl->Elements[i].Address.QuadPart; + p_desc->send_wr[0].local_ds[j].length = p_sgl->Elements[i].Length; + p_desc->send_wr[0].local_ds[j].lkey = s_buf->p_port->ib_mgr.lkey; + i++; + j++; + } + + /* Set the number of data segments. */ + p_desc->send_wr[0].wr.num_ds = j; + + IPOIB_EXIT( IPOIB_DBG_SEND ); + return NDIS_STATUS_SUCCESS; +} +#endif + + +static NDIS_STATUS +__send_mgr_filter_ip( + IN const eth_hdr_t* const p_eth_hdr, + IN MDL* p_mdl, + IN size_t buf_len, + IN ipoib_send_NB_SG *s_buf ) +{ + NDIS_STATUS status; + ip_hdr_t *p_ip_hdr; + uint32_t ip_packet_len; + size_t iph_size_in_bytes; + size_t iph_options_size; + + PERF_DECLARE( QueryIp ); + PERF_DECLARE( SendTcp ); + PERF_DECLARE( FilterUdp ); + + IPOIB_ENTER( IPOIB_DBG_SEND ); + + ipoib_send_desc_t *p_desc = s_buf->p_port->p_desc; + if( !buf_len ) + { + cl_perf_start( QueryIp ); + NdisGetNextMdl ( p_mdl, &p_mdl ); + if( !p_mdl ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to get IP header buffer.\n") ); + return NDIS_STATUS_FAILURE; + } + + NdisQueryMdl(p_mdl, &p_ip_hdr, &buf_len, NormalPagePriority); + if( !p_ip_hdr ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to query IP header buffer.\n") ); + return NDIS_STATUS_FAILURE; + } + cl_perf_stop( &p_port->p_adapter->perf, QueryIp ); + } + else + { + p_ip_hdr = (ip_hdr_t*)(p_eth_hdr + 1); + } + + if( buf_len < sizeof(ip_hdr_t) ) + { + /* This buffer is done for. Get the next buffer. */ + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Buffer too small for IP packet.\n") ); + return NDIS_STATUS_BUFFER_TOO_SHORT; + } + + switch( p_ip_hdr->prot ) + { + case IP_PROT_UDP: + cl_perf_start( FilterUdp ); + status = __send_mgr_filter_udp( p_ip_hdr, p_mdl, + (buf_len - sizeof(ip_hdr_t)), s_buf ); + cl_perf_stop( &p_port->p_adapter->perf, FilterUdp ); + if( status == NDIS_STATUS_PENDING ) + { /* not DHCP packet, keep going */ + if( ETH_IS_MULTICAST( p_eth_hdr->dst.addr ) ) + p_desc->send_dir = SEND_UD_QP; + else + p_desc->send_dir = SEND_RC_QP; + break; + } + return status; + + case IP_PROT_TCP: + p_desc->send_dir = SEND_RC_QP; + break; + case IP_PROT_IGMP: + /* + In igmp packet I saw that iph arrive in 2 NDIS_BUFFERs: + 1. iph + 2. ip options + So to get the IGMP packet we need to skip the ip options NDIS_BUFFER + */ + iph_size_in_bytes = (p_ip_hdr->ver_hl & 0xf) * 4; + iph_options_size = iph_size_in_bytes - buf_len; + buf_len -= sizeof(ip_hdr_t);//without ipheader + + /* + Could be a case that arrived igmp packet not from type IGMPv2 , + but IGMPv1 or IGMPv3. + We anyway pass it to __send_mgr_filter_igmp_v2(). + */ + status = __send_mgr_filter_igmp_v2( s_buf->p_port, + p_ip_hdr, + iph_options_size, + p_mdl, + buf_len ); + if( status != NDIS_STATUS_SUCCESS ) + return status; + + case IP_PROT_ICMP: + p_desc->send_dir = SEND_UD_QP; + default: + break; + } + + if( !s_buf->p_port->p_adapter->params.cm_enabled ) + { + p_desc->send_dir = SEND_UD_QP; + goto send_gen; + } + else if( endpt_cm_get_state( p_desc->p_endpt ) != IPOIB_CM_CONNECTED ) + { + p_desc->send_dir = SEND_UD_QP; + } + if( p_desc->send_dir == SEND_UD_QP ) + { + ip_packet_len = cl_ntoh16( p_ip_hdr->length ); + if( ip_packet_len > s_buf->p_port->p_adapter->params.payload_mtu ) + { + //TODO: NDIS60 + #if 0 + status = __send_fragments( p_port, + p_desc, + (eth_hdr_t* const)p_eth_hdr, + (ip_hdr_t* const)p_ip_hdr, + (uint32_t)buf_len, + p_mdl ); + return status; + #endif + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("TODO NDIS6 SEND_UD_QP fragments @ line #%d file %s\n", + __LINE__,__FILE__) ); + ASSERT(FALSE); + } + } + +send_gen: + cl_perf_start( SendTcp ); + status = __send_gen( s_buf, 0, 0 ); + cl_perf_stop( &p_port->p_adapter->perf, SendTcp ); + + IPOIB_EXIT( IPOIB_DBG_SEND ); + return status; +} + +static NDIS_STATUS +__send_mgr_filter_igmp_v2( + IN ipoib_port_t* const p_port, + IN const ip_hdr_t* const p_ip_hdr, + IN size_t iph_options_size, + IN MDL* p_mdl, + IN size_t buf_len ) +{ + igmp_v2_hdr_t *p_igmp_v2_hdr = NULL; + NDIS_STATUS endpt_status; + ipoib_endpt_t* p_endpt = NULL; + mac_addr_t fake_mcast_mac; + + IPOIB_ENTER( IPOIB_DBG_SEND ); + + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_MCAST, + ("buf_len = %d,iph_options_size = %d\n", + (int)buf_len, (int)iph_options_size) ); + + if( !buf_len ) + { + // To get the IGMP packet we need to skip the ip options NDIS_BUFFER + // (if exists) + while ( iph_options_size ) + { + NdisGetNextMdl( p_mdl, &p_mdl ); + if( !p_mdl ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to get IGMPv2 header buffer.\n") ); + return NDIS_STATUS_FAILURE; + } + NdisQueryMdl( p_mdl, &p_igmp_v2_hdr, &buf_len, NormalPagePriority ); + if( !p_igmp_v2_hdr ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to query IGMPv2 header buffer.\n") ); + return NDIS_STATUS_FAILURE; + } + iph_options_size-=buf_len; + } + + NdisGetNextMdl( p_mdl, &p_mdl ); + if( !p_mdl ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to get IGMPv2 header buffer.\n") ); + return NDIS_STATUS_FAILURE; + } + NdisQueryMdl( p_mdl, &p_igmp_v2_hdr, &buf_len, NormalPagePriority ); + if( !p_igmp_v2_hdr ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to query IGMPv2 header buffer.\n") ); + return NDIS_STATUS_FAILURE; + } + } + else + { + /* assuming ip header and options are in the same packet */ + p_igmp_v2_hdr = (igmp_v2_hdr_t *) GetIpPayloadPtr(p_ip_hdr); + } + /* Get the IGMP header length. */ + if( buf_len < sizeof(igmp_v2_hdr_t) ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Buffer not large enough for IGMPv2 packet.\n") ); + return NDIS_STATUS_BUFFER_TOO_SHORT; + } + + // build fake mac from igmp packet group address + fake_mcast_mac.addr[0] = 1; + fake_mcast_mac.addr[1] = ((unsigned char*)&p_igmp_v2_hdr->group_address)[0] & 0x0f; + fake_mcast_mac.addr[2] = 0x5E; + fake_mcast_mac.addr[3] = ((unsigned char*)&p_igmp_v2_hdr->group_address)[1]; + fake_mcast_mac.addr[4] = ((unsigned char*)&p_igmp_v2_hdr->group_address)[2]; + fake_mcast_mac.addr[5] = ((unsigned char*)&p_igmp_v2_hdr->group_address)[3]; + + switch ( p_igmp_v2_hdr->type ) + { + case IGMP_V2_MEMBERSHIP_REPORT: + /* + This mean that some body open listener on this group + Change type of mcast endpt to SEND_RECV endpt. So mcast garbage + collector will not delete this mcast endpt. + */ + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_MCAST, + ("Received IGMP_V2_MEMBERSHIP_REPORT message\n") ); + endpt_status = __endpt_mgr_ref( p_port, fake_mcast_mac, &p_endpt ); + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_ENDPT, + ("__endpt_mgr_ref called for %p\n", p_endpt)); + if ( p_endpt ) + { + cl_obj_lock( &p_port->obj ); + p_endpt->is_mcast_listener = TRUE; + cl_obj_unlock( &p_port->obj ); + ipoib_endpt_deref( p_endpt ); + } + break; + + case IGMP_V2_LEAVE_GROUP: + /* + This mean that somebody CLOSE listener on this group . + Change type of mcast endpt to SEND_ONLY endpt. So mcast + garbage collector will delete this mcast endpt next time. + */ + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_MCAST, + ("Received IGMP_V2_LEAVE_GROUP message\n") ); + endpt_status = __endpt_mgr_ref( p_port, fake_mcast_mac, &p_endpt ); + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_ENDPT, + ("__endpt_mgr_ref called for %p\n", p_endpt)); + if ( p_endpt ) + { + cl_obj_lock( &p_port->obj ); + p_endpt->is_mcast_listener = FALSE; + p_endpt->is_in_use = FALSE; + cl_obj_unlock( &p_port->obj ); + ipoib_endpt_deref( p_endpt ); + } + + __port_do_mcast_garbage(p_port); + + break; + + default: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_MCAST, + ("Send Unknown IGMP message: 0x%x \n", p_igmp_v2_hdr->type ) ); + break; + } + + IPOIB_EXIT( IPOIB_DBG_SEND ); + return NDIS_STATUS_SUCCESS; +} + +static NDIS_STATUS +__send_mgr_filter_udp( + IN const ip_hdr_t* const p_ip_hdr, + IN MDL* p_mdl, + IN size_t buf_len, + IN OUT ipoib_send_NB_SG* s_buf ) +{ + NDIS_STATUS status; + udp_hdr_t *p_udp_hdr; + PERF_DECLARE( QueryUdp ); + PERF_DECLARE( SendUdp ); + PERF_DECLARE( FilterDhcp ); + IPOIB_ENTER( IPOIB_DBG_SEND ); + + if( !buf_len ) + { + cl_perf_start( QueryUdp ); + NdisGetNextMdl( p_mdl, &p_mdl ); + if( !p_mdl ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to get UDP header buffer.\n") ); + return NDIS_STATUS_FAILURE; + } + NdisQueryMdl( p_mdl, &p_udp_hdr, &buf_len, NormalPagePriority ); + if( !p_udp_hdr ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to query UDP header buffer.\n") ); + return NDIS_STATUS_FAILURE; + } + cl_perf_stop( &s_buf->p_port->p_adapter->perf, QueryUdp ); + } + else + { + p_udp_hdr = (udp_hdr_t*)GetIpPayloadPtr(p_ip_hdr); + } + /* Get the UDP header and check the destination port numbers. */ + + if (p_ip_hdr->offset > 0) { + /* This is a fragmented part of UDP packet + * Only first packet will contain UDP header in such case + * So, return if offset > 0 + */ + return NDIS_STATUS_PENDING; + } + + if( buf_len < sizeof(udp_hdr_t) ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Buffer not large enough for UDP packet.\n") ); + return NDIS_STATUS_BUFFER_TOO_SHORT; + } + + if( (p_udp_hdr->src_port != DHCP_PORT_CLIENT || + p_udp_hdr->dst_port != DHCP_PORT_SERVER) && + (p_udp_hdr->src_port != DHCP_PORT_SERVER || + p_udp_hdr->dst_port != DHCP_PORT_CLIENT) ) + { + /* Not a DHCP packet. */ + return NDIS_STATUS_PENDING; + } + + buf_len -= sizeof(udp_hdr_t); + + /* Allocate our scratch buffer. */ + s_buf->p_send_buf = (send_buf_t*) + ExAllocateFromNPagedLookasideList( &s_buf->p_port->buf_mgr.send_buf_list ); + if( !s_buf->p_send_buf ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to query DHCP packet buffer.\n") ); + return NDIS_STATUS_RESOURCES; + } + /* Copy the IP and UDP headers. */ + cl_memcpy( &s_buf->p_send_buf->ip.hdr, p_ip_hdr , sizeof(ip_hdr_t) ); + cl_memcpy( + &s_buf->p_send_buf->ip.prot.udp.hdr, p_udp_hdr, sizeof(udp_hdr_t) ); + + cl_perf_start( FilterDhcp ); + status = __send_mgr_filter_dhcp( p_udp_hdr, p_mdl, buf_len, s_buf ); + cl_perf_stop( &p_port->p_adapter->perf, FilterDhcp ); + + IPOIB_EXIT( IPOIB_DBG_SEND ); + return status; +} + +unsigned short ipchksum(unsigned short *ip, int len) +{ + unsigned long sum = 0; + + len >>= 1; + while (len--) { + sum += *(ip++); + if (sum > 0xFFFF) + sum -= 0xFFFF; + } + return (unsigned short)((~sum) & 0x0000FFFF); +} + +static NDIS_STATUS +__send_mgr_filter_dhcp( + IN const udp_hdr_t* const p_udp_hdr, + IN NDIS_BUFFER* p_mdl, + IN size_t buf_len, + IN OUT ipoib_send_NB_SG* s_buf ) +{ + dhcp_pkt_t *p_dhcp; + dhcp_pkt_t *p_ib_dhcp; + uint8_t *p_option, *p_cid = NULL; + uint8_t msg = 0; + size_t len; + + IPOIB_ENTER( IPOIB_DBG_SEND ); + + ipoib_send_desc_t *p_desc = s_buf->p_port->p_desc; + + if( !buf_len ) + { + NdisGetNextMdl( p_mdl, &p_mdl ); + if( !p_mdl ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to get DHCP buffer.\n") ); + return NDIS_STATUS_FAILURE; + } + NdisQueryMdl( p_mdl, &p_dhcp, &buf_len, NormalPagePriority ); + if( !p_dhcp ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to query DHCP buffer.\n") ); + return NDIS_STATUS_FAILURE; + } + } + else + { + p_dhcp = (dhcp_pkt_t*)(p_udp_hdr + 1); + } + + if( buf_len < DHCP_MIN_SIZE ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Buffer not large enough for DHCP packet.\n") ); + return NDIS_STATUS_BUFFER_TOO_SHORT; + } + + p_ib_dhcp = &s_buf->p_send_buf->ip.prot.udp.dhcp; + cl_memcpy( p_ib_dhcp, p_dhcp, buf_len ); + + /* Now scan through the options looking for the client identifier. */ + p_option = &p_ib_dhcp->options[4]; + while( *p_option != DHCP_OPT_END && p_option < &p_ib_dhcp->options[312] ) + { + switch( *p_option ) + { + case DHCP_OPT_PAD: + p_option++; + break; + + case DHCP_OPT_MSG: + msg = p_option[2]; + p_option += 3; + break; + + case DHCP_OPT_CLIENT_ID: + p_cid = p_option; + /* Fall through. */ + + default: + /* + * All other options have a length byte following the option code. + * Offset by the length to get to the next option. + */ + p_option += (p_option[1] + 2); + } + } + + switch( msg ) + { + /* Client messages */ + case DHCPDISCOVER: + case DHCPREQUEST: + p_ib_dhcp->flags |= DHCP_FLAGS_BROADCAST; + /* Fall through */ + case DHCPDECLINE: + case DHCPRELEASE: + case DHCPINFORM: + /* Fix up the client identifier option */ + if( p_cid ) + { + /* do we need to replace it ? len eq ETH MAC sz 'and' MAC is mine */ + if( p_cid[1] == HW_ADDR_LEN+1 && !cl_memcmp( &p_cid[3], + &s_buf->p_port->p_adapter->params.conf_mac.addr, HW_ADDR_LEN ) ) + { + /* Make sure there's room to extend it. 22 is the size of + * the CID option for IPoIB. (20 is the length, one byte for type + * and the second for length field) + */ + if( buf_len + coIPoIB_CID_TotalLen - p_cid[1] > sizeof(dhcp_pkt_t) ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Can't convert CID to IPoIB format.\n") ); + return NDIS_STATUS_RESOURCES; + } + /* Move the existing options down, and add a new CID option */ + len = p_option - ( p_cid + p_cid[1] + 2 ); + p_option = p_cid + p_cid[1] + 2; + RtlMoveMemory( p_cid, p_option, len ); + + p_cid += len; + p_cid[0] = DHCP_OPT_CLIENT_ID; + p_cid[1] = coIPoIB_CID_Len; + } + } + else + { + /* + * Make sure there's room to extend it. 22 is the size of + * the CID option for IPoIB. + */ + if( buf_len + coIPoIB_CID_TotalLen > sizeof(dhcp_pkt_t) ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Can't convert CID to IPoIB format.\n") ); + return NDIS_STATUS_RESOURCES; + } + + p_cid = p_option; + p_cid[0] = DHCP_OPT_CLIENT_ID; + p_cid[1] = coIPoIB_CID_Len; + } + + CL_ASSERT( p_cid[1] == coIPoIB_CID_Len); + p_cid[coIPoIB_CID_TotalLen]= DHCP_OPT_END; + + // Copy the default prefix for ALL DHCP messages + cl_memcpy( &p_cid[2], &coIBDefaultDHCPPrefix[0], sizeof coIBDefaultDHCPPrefix); + // Copy the GUID into the last 8 bytes of the CID field + cl_memcpy( &p_cid[2+ sizeof(coIBDefaultDHCPPrefix)],&s_buf->p_port->p_adapter->guids.port_guid.guid , + sizeof(s_buf->p_port->p_adapter->guids.port_guid.guid) ); + + p_ib_dhcp->htype = DHCP_HW_TYPE_IB; + + break; + + /* Server messages. */ + case DHCPOFFER: + p_ib_dhcp->htype = 0x20; + p_ib_dhcp->hlen = 0x8; + case DHCPACK: + case DHCPNAK: + /* don't touch server messages */ + break; + + default: + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Invalide message type.\n") ); + return NDIS_STATUS_INVALID_DATA; + } + + s_buf->p_send_buf->ip.hdr.length = cl_ntoh16( sizeof(ip_hdr_t) + sizeof(udp_hdr_t) + sizeof(dhcp_pkt_t) ); + s_buf->p_send_buf->ip.prot.udp.hdr.length = cl_ntoh16( sizeof(udp_hdr_t) + sizeof(dhcp_pkt_t) ); + s_buf->p_send_buf->ip.hdr.chksum = 0; + s_buf->p_send_buf->ip.hdr.chksum = ipchksum((unsigned short*) &s_buf->p_send_buf->ip.hdr, sizeof(ip_hdr_t)); + + + /* no chksum for udp, in a case when HW does not support checksum offload */ + s_buf->p_send_buf->ip.prot.udp.hdr.chksum = 0; + p_desc->send_wr[0].local_ds[1].vaddr = cl_get_physaddr( s_buf->p_send_buf ); + p_desc->send_wr[0].local_ds[1].length = sizeof(ip_hdr_t) + + sizeof(udp_hdr_t) + + sizeof(dhcp_pkt_t); + p_desc->send_wr[0].local_ds[1].lkey = s_buf->p_port->ib_mgr.lkey; + p_desc->send_wr[0].wr.num_ds = 2; + p_desc->send_dir = SEND_UD_QP; + IPOIB_EXIT( IPOIB_DBG_SEND ); + return NDIS_STATUS_SUCCESS; +} + + +static NDIS_STATUS +__send_mgr_filter_arp( + IN const eth_hdr_t* const p_eth_hdr, + IN MDL* p_mdl, + IN size_t buf_len, + IN OUT ipoib_send_NB_SG* s_buf ) +{ + arp_pkt_t *p_arp; + ipoib_arp_pkt_t *p_ib_arp; + NDIS_STATUS status; + mac_addr_t null_hw = {0}; + + IPOIB_ENTER( IPOIB_DBG_SEND ); + + ipoib_send_desc_t *p_desc = s_buf->p_port->p_desc; + + if( !buf_len ) + { + NdisGetNextMdl( p_mdl, &p_mdl ); + if( !p_mdl ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to get ARP buffer.\n") ); + return NDIS_STATUS_FAILURE; + } + NdisQueryMdl( p_mdl, &p_arp, &buf_len, NormalPagePriority ); + if( !p_arp ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to get query ARP buffer.\n") ); + return NDIS_STATUS_FAILURE; + } + } + else + p_arp = (arp_pkt_t*)(p_eth_hdr + 1); + + /* Single buffer ARP packet. */ + if( buf_len < sizeof(arp_pkt_t) ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Buffer too short for ARP.\n") ); + return NDIS_STATUS_BUFFER_TOO_SHORT; + } + + if( p_arp->prot_type != ETH_PROT_TYPE_IP ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Unsupported protocol type.\n") ); + return NDIS_STATUS_INVALID_DATA; + } + + /* Allocate our scratch buffer. */ + ASSERT(s_buf->p_send_buf == NULL); + s_buf->p_send_buf = (send_buf_t*) + NdisAllocateFromNPagedLookasideList( + &s_buf->p_port->buf_mgr.send_buf_list ); + if( !s_buf->p_send_buf ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to query ARP packet buffer.\n") ); + return NDIS_STATUS_RESOURCES; + } + p_ib_arp = (ipoib_arp_pkt_t*)s_buf->p_send_buf; + + /* Convert the ARP payload. */ + p_ib_arp->hw_type = ARP_HW_TYPE_IB; + p_ib_arp->prot_type = p_arp->prot_type; + p_ib_arp->hw_size = sizeof(ipoib_hw_addr_t); + p_ib_arp->prot_size = p_arp->prot_size; + p_ib_arp->op = p_arp->op; + + ipoib_addr_set_qpn( &p_ib_arp->src_hw, s_buf->p_port->ib_mgr.qpn ); +#if 0 + + if( p_port->p_adapter->params.cm_enabled ) + { + ipoib_addr_set_flags( &p_ib_arp->src_hw, IPOIB_CM_FLAG_RC ); + } +#endif + + ib_gid_set_default( &p_ib_arp->src_hw.gid, + s_buf->p_port->p_adapter->guids.port_guid.guid ); + + p_ib_arp->src_ip = p_arp->src_ip; + + if( cl_memcmp( &p_arp->dst_hw, &null_hw, sizeof(mac_addr_t) ) ) + { + /* Get the endpoint referenced by the dst_hw address. */ + net32_t qpn = 0; + status = __endpt_mgr_get_gid_qpn( s_buf->p_port, + p_arp->dst_hw, + &p_ib_arp->dst_hw.gid, + &qpn ); + if( status != NDIS_STATUS_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed lookup of destination HW address\n") ); + return status; + } + ipoib_addr_set_qpn( &p_ib_arp->dst_hw, qpn ); +#if 0 + if( p_arp->op == ARP_OP_REP && + p_port->p_adapter->params.cm_enabled && + p_desc->p_endpt->cm_flag == IPOIB_CM_FLAG_RC ) + { + cm_state_t cm_state; + cm_state = + ( cm_state_t )InterlockedCompareExchange( (volatile LONG *)&p_desc->p_endpt->conn.state, + IPOIB_CM_CONNECT, IPOIB_CM_DISCONNECTED ); + switch( cm_state ) + { + case IPOIB_CM_DISCONNECTED: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, + ("ARP REPLY pending Endpt[%p] QPN %#x MAC %02x:%02x:%02x:%02x:%02x:%02x\n", + p_desc->p_endpt, + cl_ntoh32( ipoib_addr_get_qpn( &p_ib_arp->dst_hw )), + p_desc->p_endpt->mac.addr[0], p_desc->p_endpt->mac.addr[1], + p_desc->p_endpt->mac.addr[2], p_desc->p_endpt->mac.addr[3], + p_desc->p_endpt->mac.addr[4], p_desc->p_endpt->mac.addr[5] ) ); + ipoib_addr_set_sid( &p_desc->p_endpt->conn.service_id, + ipoib_addr_get_qpn( &p_ib_arp->dst_hw ) ); + + NdisFreeToNPagedLookasideList( + &p_port->buf_mgr.send_buf_list, s_buf->p_send_buf ); + cl_qlist_insert_tail( &p_port->send_mgr.pending_list, + IPOIB_LIST_ITEM_FROM_NBL( s_buf->p_send_buf ) ); + NdisInterlockedInsertTailList( &p_port->endpt_mgr.pending_conns, + &p_desc->p_endpt->list_item, + &p_port->endpt_mgr.conn_lock ); + cl_event_signal( &p_port->endpt_mgr.event ); + return NDIS_STATUS_PENDING; + + case IPOIB_CM_CONNECT: + /* queue ARP REP packet until connected */ + NdisFreeToNPagedLookasideList( + &p_port->buf_mgr.send_buf_list, s_buf->p_send_buf ); + cl_qlist_insert_tail( &p_port->send_mgr.pending_list, + IPOIB_LIST_ITEM_FROM_NBL( s_buf->p_nbl ) ); + + return NDIS_STATUS_PENDING; + default: + break; + } + } +#endif + } + else + { + cl_memclr( &p_ib_arp->dst_hw, sizeof(ipoib_hw_addr_t) ); + } + +#if 0 //DBG + if( p_port->p_adapter->params.cm_enabled ) + { + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, + (" ARP %s SEND to ENDPT[%p] State: %d flag: %#x, QPN: %#x MAC %02x:%02x:%02x:%02x:%02x:%02x\n", + ( p_ib_arp->op == ARP_OP_REP ? "REP": "REQ"), p_desc->p_endpt, + endpt_cm_get_state( p_desc->p_endpt ), + p_desc->p_endpt->cm_flag, + cl_ntoh32( ipoib_addr_get_qpn( &p_ib_arp->dst_hw )), + p_desc->p_endpt->mac.addr[0], p_desc->p_endpt->mac.addr[1], + p_desc->p_endpt->mac.addr[2], p_desc->p_endpt->mac.addr[3], + p_desc->p_endpt->mac.addr[4], p_desc->p_endpt->mac.addr[5] )); + } +#endif + + p_ib_arp->dst_ip = p_arp->dst_ip; + + p_desc->send_wr[0].local_ds[1].vaddr = cl_get_physaddr( p_ib_arp ); + p_desc->send_wr[0].local_ds[1].length = sizeof(ipoib_arp_pkt_t); + p_desc->send_wr[0].local_ds[1].lkey = s_buf->p_port->ib_mgr.lkey; + p_desc->send_wr[0].wr.num_ds = 2; + p_desc->send_wr[0].wr.p_next = NULL; + + IPOIB_EXIT( IPOIB_DBG_SEND ); + return NDIS_STATUS_SUCCESS; +} + +static inline NDIS_STATUS +__send_mgr_queue( + IN ipoib_port_t* const p_port, + IN eth_hdr_t* const p_eth_hdr, + OUT ipoib_endpt_t** const pp_endpt ) +{ + NDIS_STATUS status; + + PERF_DECLARE( GetEndpt ); + + IPOIB_ENTER( IPOIB_DBG_SEND ); + + /* Check the send queue and pend the request if not empty. */ + //No need in spinlock, this function is already under lock + if( cl_qlist_count( &p_port->send_mgr.pending_list ) ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_WARNING, IPOIB_DBG_SEND, + ("Pending list not empty p_eth_hdr %p\n",p_eth_hdr) ); + return NDIS_STATUS_PENDING; + } + + /* Check the send queue and pend the request if not empty. */ + if( p_port->send_mgr.depth == p_port->p_adapter->params.sq_depth ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_WARNING, IPOIB_DBG_SEND, + ("No available WQEs.\n") ); + cl_dbg_out("HW is full\n"); + return NDIS_STATUS_PENDING; + } + + cl_perf_start( GetEndpt ); + status = __endpt_mgr_ref( p_port, p_eth_hdr->dst, pp_endpt ); + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_ENDPT,("__endpt_mgr_ref called for %p\n", *pp_endpt)); + cl_perf_stop( &p_port->p_adapter->perf, GetEndpt ); + + if( status == NDIS_STATUS_NO_ROUTE_TO_DESTINATION && + ETH_IS_MULTICAST( p_eth_hdr->dst.addr ) ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_MCAST, + ("Calling join mcast from send_mgr_queue\n")); + if( ipoib_port_join_mcast( p_port, p_eth_hdr->dst, + IB_MC_REC_STATE_FULL_MEMBER) == IB_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_SEND, + ("Multicast Mac - trying to join.\n") ); + return NDIS_STATUS_PENDING; + } + } + else if ( status == NDIS_STATUS_SUCCESS && + ETH_IS_MULTICAST( p_eth_hdr->dst.addr ) && + !ETH_IS_BROADCAST( p_eth_hdr->dst.addr ) ) + { + CL_ASSERT( (*pp_endpt) ); + CL_ASSERT((*pp_endpt)->h_mcast != NULL); + (*pp_endpt)->is_in_use = TRUE; + } + + IPOIB_EXIT( IPOIB_DBG_SEND ); + return status; +} + + +static NDIS_STATUS +__build_send_desc( + IN eth_hdr_t* const p_eth_hdr, + IN MDL* const p_mdl, + IN const size_t mdl_len, + IN ipoib_send_NB_SG *s_buf) +{ + NDIS_STATUS status; + int32_t hdr_idx; + ULONG mss = 0; + + PNDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO p_checksum_list_info = NULL; + PNDIS_TCP_LARGE_SEND_OFFLOAD_NET_BUFFER_LIST_INFO p_lso_info = NULL; + PERF_DECLARE( SendMgrFilter ); + + IPOIB_ENTER( IPOIB_DBG_SEND ); + + ipoib_send_desc_t *p_desc = s_buf->p_port->p_desc; + + /* Store context in our reserved area of the packet. */ + + ASSERT(s_buf == (ipoib_send_NB_SG *) IPOIB_INFO_FROM_NB(s_buf->p_curr_nb)); + s_buf->p_endpt = p_desc->p_endpt; + //TODO IMPORTANT: Send buffer should not be allocated within global struct !!! + // Otherwise, the next send may override its content + //s_buf->p_send_buf= p_desc->p_buf; + + /* Format the send descriptor. */ + PVOID* ppTemp = &NET_BUFFER_LIST_INFO(s_buf->p_nbl, TcpIpChecksumNetBufferListInfo); + p_checksum_list_info = + (PNDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO) ((PULONG)ppTemp); + // Calculate LSO + if( s_buf->p_port->p_adapter->params.lso ) + { + p_lso_info = + (PNDIS_TCP_LARGE_SEND_OFFLOAD_NET_BUFFER_LIST_INFO) (PULONG) &NET_BUFFER_LIST_INFO(s_buf->p_nbl, TcpLargeSendNetBufferListInfo); + ASSERT(p_lso_info); + ULONG LsoType = p_lso_info->Transmit.Type; + + mss = p_lso_info->LsoV1Transmit.MSS; + ULONG PacketLength = NET_BUFFER_DATA_LENGTH(s_buf->p_curr_nb); + if (PacketLength < mss) + { + ASSERT(FALSE); + return NDIS_STATUS_INVALID_PACKET; + } + if(LsoType == NDIS_TCP_LARGE_SEND_OFFLOAD_V2_TYPE) + { + ASSERT(p_lso_info->LsoV2Transmit.Type == NDIS_TCP_LARGE_SEND_OFFLOAD_V2_TYPE); + ASSERT(mss == p_lso_info->LsoV2Transmit.MSS); + ASSERT(p_lso_info->LsoV1Transmit.TcpHeaderOffset == p_lso_info->LsoV2Transmit.TcpHeaderOffset); + } + } + + /* Format the send descriptor. */ + hdr_idx = cl_atomic_inc( &s_buf->p_port->hdr_idx ); + hdr_idx &= (s_buf->p_port->p_adapter->params.sq_depth - 1); + ASSERT( hdr_idx < s_buf->p_port->p_adapter->params.sq_depth ); + + s_buf->p_port->hdr[hdr_idx].type = p_eth_hdr->type; + s_buf->p_port->hdr[hdr_idx].resv = 0; + + //TODO why enter this block for LSO ??? + p_desc->send_wr[0].local_ds[0].vaddr = + cl_get_physaddr( &s_buf->p_port->hdr[hdr_idx] ); + p_desc->send_wr[0].local_ds[0].length = sizeof(ipoib_hdr_t); + p_desc->send_wr[0].local_ds[0].lkey = s_buf->p_port->ib_mgr.lkey; + p_desc->send_wr[0].wr.send_opt = 0; + + //Init send buffer to 0 + s_buf->p_send_buf = NULL; + + + + if (mss && (p_lso_info->LsoV1Transmit.TcpHeaderOffset != 0)) + { //We have LSO packet + ASSERT( mss == (p_lso_info->LsoV1Transmit.MSS & p_lso_info->LsoV2Transmit.MSS)); + //ASSERT ( (mss & (1<<20)) == mss); + status = __build_lso_desc( s_buf->p_port, + mss, + hdr_idx, + p_lso_info, + s_buf->p_curr_nb ); + + if( status != NDIS_STATUS_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("__build_lso_desc returned 0x%08X.\n", status) ); + return status; + } + } + else + { + uint32_t i; + + cl_perf_start( SendMgrFilter ); + status = __send_mgr_filter( p_eth_hdr, p_mdl, mdl_len, s_buf ); + cl_perf_stop( &p_port->p_adapter->perf, SendMgrFilter ); + if( status != NDIS_STATUS_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("__send_mgr_filter returned 0x%08X.\n", status) ); + return status; + } + + if( p_desc->send_dir == SEND_UD_QP ) + { + p_desc->send_qp = s_buf->p_port->ib_mgr.h_qp; // UD QP + for( i = 0; i < p_desc->num_wrs; i++ ) + { + p_desc->send_wr[i].wr.dgrm.ud.remote_qp = p_desc->p_endpt->qpn; + p_desc->send_wr[i].wr.dgrm.ud.remote_qkey = s_buf->p_port->ib_mgr.bcast_rec.qkey; + p_desc->send_wr[i].wr.dgrm.ud.h_av = p_desc->p_endpt->h_av; + p_desc->send_wr[i].wr.dgrm.ud.pkey_index = s_buf->p_port->pkey_index; + p_desc->send_wr[i].wr.dgrm.ud.rsvd = NULL; + p_desc->send_wr[i].wr.send_opt = 0; + + if( s_buf->p_port->p_adapter->params.send_chksum_offload && + p_checksum_list_info && + ( p_checksum_list_info->Transmit.IsIPv4 || + p_checksum_list_info->Transmit.IsIPv6 )) + { + // Set transimition checksum offloading + if( p_checksum_list_info->Transmit.IpHeaderChecksum ) + { + p_desc->send_wr[i].wr.send_opt |= IB_SEND_OPT_TX_IP_CSUM; + } + if( p_checksum_list_info->Transmit.TcpChecksum || p_checksum_list_info->Transmit.UdpChecksum) + { + p_desc->send_wr[i].wr.send_opt |= IB_SEND_OPT_TX_TCP_UDP_CSUM; + } + } + } + } + else // RC QP + { + CL_ASSERT( p_desc->send_dir == SEND_RC_QP ); + p_desc->send_qp = p_desc->p_endpt->conn.h_work_qp; + } + + for( i = 0; i < p_desc->num_wrs; i++ ) + { + p_desc->send_wr[i].wr.wr_type = WR_SEND; + p_desc->send_wr[i].wr.wr_id = 0; + p_desc->send_wr[i].wr.ds_array = &p_desc->send_wr[i].local_ds[0]; + if( i ) + { + p_desc->send_wr[i-1].wr.p_next = &p_desc->send_wr[i].wr; + } + } + + p_desc->send_wr[p_desc->num_wrs - 1].wr.wr_id = (uintn_t)s_buf ; + p_desc->send_wr[p_desc->num_wrs - 1].wr.send_opt |= IB_SEND_OPT_SIGNALED; + p_desc->send_wr[p_desc->num_wrs - 1].wr.p_next = NULL; + } + + IPOIB_EXIT( IPOIB_DBG_SEND ); + return NDIS_STATUS_SUCCESS; +} + + +static NDIS_STATUS +__build_lso_desc( + IN ipoib_port_t* const p_port, + IN ULONG mss, + IN int32_t hdr_idx, + IN PNDIS_TCP_LARGE_SEND_OFFLOAD_NET_BUFFER_LIST_INFO p_lso_info, + IN NET_BUFFER *p_netbuf) +{ + NDIS_STATUS status; + LsoData TheLsoData; + UINT IndexOfData = 0; + + IPOIB_ENTER( IPOIB_DBG_SEND ); + + ipoib_send_NB_SG * s_buf = IPOIB_INFO_FROM_NB(p_netbuf); + ipoib_send_desc_t *p_desc = p_port->p_desc; + + //TODO What if first NB was inserted to pending list ???? + PNET_BUFFER FirstBuffer = NET_BUFFER_LIST_FIRST_NB (s_buf->p_nbl); + ULONG PacketLength = NET_BUFFER_DATA_LENGTH(FirstBuffer); + + memset(&TheLsoData, 0, sizeof TheLsoData ); + status = GetLsoHeaderSize( + FirstBuffer, + &TheLsoData, + &IndexOfData, + &p_port->hdr[hdr_idx] ); + + if ((status != NDIS_STATUS_SUCCESS ) || + (TheLsoData.FullBuffers != TheLsoData.UsedBuffers)) + { + ASSERT(FALSE); + + IPOIB_PRINT(TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, ("<-- Throwing this packet\n")); + + if( status == NDIS_STATUS_SUCCESS ) + { + status = NDIS_STATUS_INVALID_PACKET; + } + return status; + } + ASSERT(TheLsoData.LsoHeaderSize > 0); + // Tell NDIS how much we will send. + //PktExt->NdisPacketInfo[TcpLargeSendPacketInfo] = UlongToPtr(PacketLength); + //p_lso_info->LsoV1TransmitComplete.TcpPayload = PacketLength; + + // Tell NDIS how much we will send. + if(p_lso_info->LsoV1Transmit.Type == NDIS_TCP_LARGE_SEND_OFFLOAD_V1_TYPE) + { + //IPOIB_TCP_PAYLOAD_FROM_NB(p_netbuf) += PacketLength-TheLsoData.LsoHeaderSize; + s_buf->tcp_payload = PacketLength-TheLsoData.LsoHeaderSize; + + } + + p_desc->send_wr[0].wr.dgrm.ud.mss = mss; + p_desc->send_wr[0].wr.dgrm.ud.header = TheLsoData.LsoBuffers[0].pData; + p_desc->send_wr[0].wr.dgrm.ud.hlen = TheLsoData.LsoHeaderSize ;//lso_header_size; + p_desc->send_wr[0].wr.dgrm.ud.remote_qp = p_desc->p_endpt->qpn; + p_desc->send_wr[0].wr.dgrm.ud.remote_qkey = p_port->ib_mgr.bcast_rec.qkey; + p_desc->send_wr[0].wr.dgrm.ud.h_av = p_desc->p_endpt->h_av; + p_desc->send_wr[0].wr.dgrm.ud.pkey_index = p_port->pkey_index; + p_desc->send_wr[0].wr.dgrm.ud.rsvd = NULL; + + p_desc->send_wr[0].wr.wr_id = (uintn_t)s_buf; + p_desc->send_wr[0].wr.ds_array = p_desc->send_wr[0].local_ds; + p_desc->send_wr[0].wr.wr_type = WR_LSO; + p_desc->send_wr[0].wr.send_opt = + (IB_SEND_OPT_TX_IP_CSUM | IB_SEND_OPT_TX_TCP_UDP_CSUM) | IB_SEND_OPT_SIGNALED; + + p_desc->send_wr[0].wr.p_next = NULL; + p_desc->send_qp = p_port->ib_mgr.h_qp; + p_desc->send_dir = SEND_UD_QP; + status = __send_gen( s_buf, IndexOfData, TheLsoData.LsoHeaderSize ); + + IPOIB_EXIT( IPOIB_DBG_SEND ); + return status; +} + + +// max number of physical fragmented buffers +#define MAX_PHYS_BUF_FRAG_ELEMENTS 0x29 +#define MP_FRAG_ELEMENT SCATTER_GATHER_ELEMENT +#define PMP_FRAG_ELEMENT PSCATTER_GATHER_ELEMENT + + +typedef struct _MP_FRAG_LIST { + ULONG NumberOfElements; + ULONG_PTR Reserved; + SCATTER_GATHER_ELEMENT Elements[MAX_PHYS_BUF_FRAG_ELEMENTS]; +} MP_FRAG_LIST, *PMP_FRAG_LIST; + + +void +CreateFragList( + ULONG PhysBufCount, + PNET_BUFFER NetBuff, + ULONG PacketLength, + PMP_FRAG_LIST pFragList ) +{ + ULONG i = 0; + int j=0; + + UINT buf_len = NET_BUFFER_DATA_LENGTH(NetBuff); + PMDL pMdl = NET_BUFFER_CURRENT_MDL(NetBuff); + + ULONG CurrentMdlDataOffset = NET_BUFFER_CURRENT_MDL_OFFSET(NetBuff); + ASSERT(MmGetMdlByteCount(pMdl) >= CurrentMdlDataOffset); + + ASSERT(NetBuff != NULL); +#ifdef DBG + ASSERT(PhysBufCount <= MAX_PHYS_BUF_FRAG_ELEMENTS); +#else + UNREFERENCED_PARAMETER(PhysBufCount); +#endif + + ASSERT(buf_len > 0); + UNREFERENCED_PARAMETER(PacketLength); + + + IPOIB_PRINT( TRACE_LEVEL_VERBOSE, IPOIB_DBG_SEND, + ("CreateFragList: NetBuff %p, Length =0x%x\n", NetBuff, buf_len)); + + while ( (pMdl != NULL) && (buf_len != 0) ) + { + PPFN_NUMBER page_array = MmGetMdlPfnArray(pMdl); + int MdlBufCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(pMdl), MmGetMdlByteCount(pMdl)); + + ULONG offset = MmGetMdlByteOffset(pMdl) + CurrentMdlDataOffset ; + ULONG MdlBytesCount = MmGetMdlByteCount(pMdl) - CurrentMdlDataOffset; + CurrentMdlDataOffset = 0; + + if( MdlBytesCount == 0 ) + { + pMdl = pMdl->Next; + continue; + } + + ASSERT( (buf_len > 0) && (MdlBytesCount > 0) ); + + IPOIB_PRINT( TRACE_LEVEL_VERBOSE, IPOIB_DBG_SEND, + ("CreateFragList: pMdl=%p, MdlBytesCount=x%x, MdlBufCount=0x%x\n", + pMdl, MdlBytesCount, MdlBufCount)); + + if (MdlBytesCount > 0) + { + if( buf_len > MdlBytesCount) + { + buf_len -= MdlBytesCount; + } + else + { + MdlBytesCount = buf_len; + buf_len = 0; + } + // + // In some cases the mdlcount is greater than needed and in the last + // page there is 0 bytes + // + for (j=0; ((j< MdlBufCount) && (MdlBytesCount > 0)); j++) + { + ASSERT(MdlBytesCount > 0); + if (j ==0 ) + { + // First page + // + ULONG64 ul64PageNum = page_array[j]; + pFragList->Elements[i].Address.QuadPart = + (ul64PageNum << PAGE_SHIFT)+ offset; + if( offset + MdlBytesCount > PAGE_SIZE ) + { + // the data slides behind the page boundry + // + ASSERT(PAGE_SIZE > offset); + pFragList->Elements[i].Length = PAGE_SIZE - offset; + MdlBytesCount -= pFragList->Elements[i].Length; + } + else + { + // All the data is hold in one page + // + pFragList->Elements[i].Length = MdlBytesCount; + MdlBytesCount = 0; + } + + IPOIB_PRINT( TRACE_LEVEL_VERBOSE, IPOIB_DBG_SEND, + ("CreateFragList: j == 0, MdlBytesCount=x%x, i = %d, " + "element.length=0x%x \n", + MdlBytesCount, i, pFragList->Elements[i].Length)); + } + else + { + if (page_array[j] == (page_array[j-1] + 1)) + { + + ULONG size = min(PAGE_SIZE, MdlBytesCount); + i -= 1; + pFragList->Elements[i].Length += size; + MdlBytesCount -= size; + } + else + { + // Not first page. so the data always start at the + // begining of the page + // + ULONG64 ul64PageNum = page_array[j]; + pFragList->Elements[i].Address.QuadPart = (ul64PageNum << PAGE_SHIFT); + pFragList->Elements[i].Length = min(PAGE_SIZE, MdlBytesCount); + MdlBytesCount -= pFragList->Elements[i].Length; + } + + IPOIB_PRINT( TRACE_LEVEL_VERBOSE, IPOIB_DBG_SEND, + ( "CreateFragList: j != 0, MdlBytesCount=x%x, i = %d, " + "element.length=0x%x \n", + MdlBytesCount, i, pFragList->Elements[i].Length)); + } + i++; + ASSERT(i <= MAX_PHYS_BUF_FRAG_ELEMENTS); + } + } + pMdl = pMdl->Next; + } + + if (buf_len != 0) + { + // In some cases the size in MDL isn't equal to the buffer size. + // In such a case we need to add the rest of packet to last chunk + // + ASSERT(i > 0); // To prevent array underflow + pFragList->Elements[i-1].Length += buf_len; + IPOIB_PRINT( TRACE_LEVEL_VERBOSE, IPOIB_DBG_SEND, + ( "CreateFragList: buf_len != 0, i = %d, element.length=0x%x \n", + i-1, pFragList->Elements[i-1].Length)); + } + + ASSERT(i <= PhysBufCount); + pFragList->NumberOfElements = i; + +#ifdef DBG + { + ULONG size = 0; + for (i = 0; i < pFragList->NumberOfElements; ++i) + { + size += pFragList->Elements[i].Length; + } + ASSERT(size == PacketLength); + } +#endif +} + + +void +ipoib_port_send( + IN ipoib_port_t* const p_port, + IN NET_BUFFER_LIST *p_net_buffer_list, + IN ULONG send_flags ) +{ + NDIS_STATUS status; + PNET_BUFFER p_netbuf, p_next_netbuf = NULL; + UINT buf_cnt = 0; + ULONG send_complete_flags = 0; + + KIRQL old_irql; + + PERF_DECLARE( GetEthHdr ); + PERF_DECLARE( BuildSendDesc ); + PERF_DECLARE( QueuePacket ); + PERF_DECLARE( SendMgrQueue ); + PERF_DECLARE( PostSend ); + PERF_DECLARE( ProcessFailedSends ); + + IPOIB_ENTER( IPOIB_DBG_SEND ); + + if (NDIS_TEST_SEND_AT_DISPATCH_LEVEL(send_flags)) + { + //TODO Tzachid: make an assert here to validate your IRQL + ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL); + old_irql = DISPATCH_LEVEL; + } else { + NDIS_RAISE_IRQL_TO_DISPATCH(&old_irql); + //ASSERT (KeGetCurrentIrql() == PASSIVE_LEVEL); // Happens + } + NDIS_SET_SEND_COMPLETE_FLAG( send_complete_flags, + NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL ); + cl_obj_lock( &p_port->obj ); + if( p_port->state != IB_QPS_RTS ) + { + cl_obj_unlock( &p_port->obj ); + + IPOIB_PRINT( TRACE_LEVEL_VERBOSE, IPOIB_DBG_SEND, + ("Invalid QP state: not RTS, exiting from port_send\n")); + NET_BUFFER_LIST_STATUS(p_net_buffer_list) = NDIS_STATUS_FAILURE; + ipoib_inc_send_stat( p_port->p_adapter, IP_STAT_DROPPED, 0 ); + + NdisMSendNetBufferListsCompleteX( p_port->p_adapter, + p_net_buffer_list, + send_complete_flags ); + + NDIS_LOWER_IRQL(old_irql, DISPATCH_LEVEL); + + IPOIB_EXIT( IPOIB_DBG_SEND ); + return; + } + cl_obj_unlock( &p_port->obj ); + + cl_spinlock_acquire( &p_port->send_lock ); + // You are already here at dispatch + + // We need to init the status here + // When completing the send, we will set the status NDIS_STATUS_FAILURE if + // AT LEAST one of NBs will fail. + // That is, status can't be updated back to SUCCESS if it previosly was set + // to FAILURE. + NET_BUFFER_LIST_STATUS(p_net_buffer_list) = NDIS_STATUS_SUCCESS; + + for (p_netbuf = NET_BUFFER_LIST_FIRST_NB(p_net_buffer_list); + p_netbuf != NULL; + p_netbuf = NET_BUFFER_NEXT_NB(p_netbuf)) + { + ++g_ipoib_send_SW; + ++buf_cnt; + } + + IPOIB_PRINT( TRACE_LEVEL_VERBOSE, IPOIB_DBG_SEND, + ("Processing netbuffer list: %p buf_cnt = %d\n", p_net_buffer_list, buf_cnt)); + + ASSERT(buf_cnt); + + // Raise reference count of the NBL to the number of its NBs + IPOIB_GET_NET_BUFFER_LIST_REF_COUNT(p_net_buffer_list) = + (PVOID)(ULONG_PTR)buf_cnt; + + for (p_netbuf = NET_BUFFER_LIST_FIRST_NB(p_net_buffer_list); + p_netbuf != NULL; + p_netbuf = p_next_netbuf) + { + p_next_netbuf = NET_BUFFER_NEXT_NB(p_netbuf); + + ipoib_send_NB_SG * s_buf = (ipoib_send_NB_SG*) (PVOID) + (cl_qpool_get(&p_port->send_mgr.send_pool)); + if (s_buf == NULL) + { + ASSERT(FALSE); + NET_BUFFER_LIST_STATUS(p_net_buffer_list) = NDIS_STATUS_RESOURCES; + NdisMSendNetBufferListsCompleteX( p_port->p_adapter, + p_net_buffer_list, + send_complete_flags ); + break; + } + + //Set all the data needed for process_sg_list + s_buf->p_port = p_port; + s_buf->p_sgl = NULL; + s_buf->p_endpt = NULL; + s_buf->p_nbl = p_net_buffer_list; + s_buf->p_curr_nb = p_netbuf; + //TODO remove this line from process_sg_real + s_buf->p_send_buf = NULL; + + //We can also define p_sg_buf as a static member of send_buf, + // But the problem is that we don't know it's size + if (s_buf->p_sg_buf == NULL) + { + s_buf->p_sg_buf = (PVOID) cl_qpool_get(&p_port->send_mgr.sg_pool); + } + + IPOIB_INFO_FROM_NB(p_netbuf) = s_buf; + + IPOIB_PRINT( TRACE_LEVEL_VERBOSE, IPOIB_DBG_SEND, + ("Netbuf to send = %p\n", p_netbuf) ); +#if 0 + CHAR *pTemp = (CHAR *) ExAllocatePoolWithTag(NonPagedPool , p_port->p_adapter->sg_list_size, 'abcd'); + CL_ASSERT(pTemp != NULL); + p_sgl = pTemp; + CreateFragList(NdisQueryNetBufferPhysicalCount(p_netbuf), p_netbuf, NET_BUFFER_DATA_LENGTH(p_netbuf), (PMP_FRAG_LIST) p_sgl); + IPOIB_FROM_QUEUE(p_netbuf) = NULL; + /*IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("[%d] Allocation from scratch: Netbuf = %x, found SGL = %x, PhysBufCnt=%ld, NB LEN = %ld, sg_list_size=%ld\n", + buf_cnt, p_netbuf, p_sgl,NdisQueryNetBufferPhysicalCount(p_netbuf) , + NET_BUFFER_DATA_LENGTH(p_netbuf),p_port->p_adapter->sg_list_size) ); + */ + ipoib_process_sg_list(NULL, NULL, (PSCATTER_GATHER_LIST)p_sgl, p_netbuf); + status = NDIS_STATUS_SUCCESS; +#else + + //cl_qlist_check_validity(&p_port->send_mgr.pending_list); + + cl_spinlock_release( &p_port->send_lock ); + + + ++g_ipoib_send_SW_in_loop; + + status = NdisMAllocateNetBufferSGList( + p_port->p_adapter->NdisMiniportDmaHandle, + p_netbuf, + s_buf, + NDIS_SG_LIST_WRITE_TO_DEVICE, + (PUCHAR )s_buf->p_sg_buf + sizeof(cl_pool_item_t), + p_port->p_adapter->sg_list_size); + + cl_spinlock_acquire( &p_port->send_lock ); +#endif + + if( status != NDIS_STATUS_SUCCESS ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Partial Send @ line #%d\n %s\n",__LINE__,__FILE__) ); + ASSERT(FALSE); + // TODOD: There is a bug here if we have succeeded in sending some + // and failed with the others. + + /* fail net buffer list */ + NET_BUFFER_LIST_STATUS(p_net_buffer_list) = status; + NdisMSendNetBufferListsCompleteX( p_port->p_adapter, + p_net_buffer_list, + send_complete_flags ); + break; + } + } + + cl_spinlock_release( &p_port->send_lock ); + + NDIS_LOWER_IRQL(old_irql, DISPATCH_LEVEL); + + IPOIB_EXIT( IPOIB_DBG_SEND ); +} + +static inline void +__send_complete_net_buffer( + IN ipoib_send_NB_SG *s_buf, + IN NDIS_STATUS status, + IN ULONG compl_flags, + IN boolean_t bLock ) +{ + CL_ASSERT( s_buf ); + + IPOIB_PRINT(TRACE_LEVEL_VERBOSE, IPOIB_DBG_BUF, + ("Processing send completion for NBL %p s_buf %p\n", + s_buf->p_nbl, s_buf)); + + // Free SGL element allocated by NDIS + // We should do it before freeing the whole NBL + NdisMFreeNetBufferSGList( s_buf->p_port->p_adapter->NdisMiniportDmaHandle, + s_buf->p_sgl, + s_buf->p_curr_nb ); + + // No need to delete p_sg_buf at this state, we will destroy the whole list + // at the end of the execution + //NET_BUFFER_LIST_NEXT_NBL(p_desc->p_netbuf_list) = NULL; +#if 0 + if (NET_BUFFER_LIST_STATUS(s_buf->p_nbl) != NDIS_STATUS_FAILURE) + { + //TODO what about other statuses ????? + NET_BUFFER_LIST_STATUS(s_buf->p_nbl) = status; + } +#endif + + NET_BUFFER_LIST_STATUS(s_buf->p_nbl) = status; + + switch (status) + { + case NDIS_STATUS_SUCCESS: + ++g_ipoib_send_ack; + break; + case NDIS_STATUS_RESET_IN_PROGRESS: + ++g_ipoib_send_reset; + break; + case NDIS_STATUS_FAILURE: + ++g_ipoib_send_SG_failed; + break; + case NDIS_STATUS_INVALID_LENGTH: + case NDIS_STATUS_PAUSED: + case NDIS_STATUS_SEND_ABORTED: + case NDIS_STATUS_RESOURCES: + default: + ASSERT(FALSE); + } + + IPOIB_DEC_NET_BUFFER_LIST_REF_COUNT(s_buf->p_nbl); + /* Complete the NBL */ + if (IPOIB_GET_NET_BUFFER_LIST_REF_COUNT(s_buf->p_nbl) == 0) + { + NET_BUFFER_LIST_STATUS(s_buf->p_nbl) = status; + PNDIS_TCP_LARGE_SEND_OFFLOAD_NET_BUFFER_LIST_INFO pLsoInfo = + (PNDIS_TCP_LARGE_SEND_OFFLOAD_NET_BUFFER_LIST_INFO) + (PULONG)&NET_BUFFER_LIST_INFO(s_buf->p_nbl, TcpLargeSendNetBufferListInfo); + if(pLsoInfo->Transmit.Type == NDIS_TCP_LARGE_SEND_OFFLOAD_V1_TYPE) + { + UINT TcpPayLoad = 0; + //TODO optimize this code during MSS/LSO building + for (PNET_BUFFER NetBuffer = NET_BUFFER_LIST_FIRST_NB(s_buf->p_nbl); + NetBuffer != NULL ; + NetBuffer = NET_BUFFER_NEXT_NB(NetBuffer)) + { + + TcpPayLoad += s_buf->tcp_payload; + } + pLsoInfo->LsoV1TransmitComplete.TcpPayload = TcpPayLoad; + } + else if (pLsoInfo->Transmit.Type == NDIS_TCP_LARGE_SEND_OFFLOAD_V2_TYPE) + { + pLsoInfo->LsoV2TransmitComplete.Reserved = 0; + pLsoInfo->LsoV2TransmitComplete.Type = NDIS_TCP_LARGE_SEND_OFFLOAD_V2_TYPE; + } + + if (bLock) + { + cl_spinlock_release( &s_buf->p_port->send_lock ); + NdisMSendNetBufferListsCompleteX( s_buf->p_port->p_adapter, + s_buf->p_nbl, compl_flags ); + cl_spinlock_acquire( &s_buf->p_port->send_lock ); + } else { + NdisMSendNetBufferListsCompleteX( s_buf->p_port->p_adapter, + s_buf->p_nbl, compl_flags ); + } + } + + if( s_buf->p_send_buf ) + { + cl_perf_start( FreeSendBuf ); + NdisFreeToNPagedLookasideList( &s_buf->p_port->buf_mgr.send_buf_list, + s_buf->p_send_buf ); + cl_perf_stop( &p_port->p_adapter->perf, FreeSendBuf ); + } + + /* Dereference the enpoint used for the transfer. */ + if( s_buf->p_endpt ) + { + ipoib_endpt_deref( s_buf->p_endpt ); + } +#if 0 + if (status == NDIS_STATUS_SUCCESS) + { + //++g_ipoib_send_SG_real; + ipoib_inc_send_stat( p_port->p_adapter, IP_STAT_SUCCESS, 0 ); + } else { + ++g_ipoib_send_SG_failed; + ipoib_inc_send_stat( p_port->p_adapter, IP_STAT_ERROR, 0 ); + } +#endif + //Put back into the pool list structure allocated for the NB + cl_qpool_put(&s_buf->p_port->send_mgr.send_pool, (cl_pool_item_t* )s_buf); + + cl_perf_stop( &p_port->p_adapter->perf, SendComp ); +} + + +void +ipoib_port_resume( + IN ipoib_port_t* const p_port, + IN boolean_t b_pending ) +{ + cl_list_item_t *p_item; + ipoib_send_NB_SG *s_buf = NULL; + boolean_t b_good_port_state = TRUE; + + PERF_DECLARE( GetEndpt ); + PERF_DECLARE( BuildSendDesc ); + PERF_DECLARE( ProcessFailedSends ); + PERF_DECLARE( PostSend ); + + IPOIB_ENTER( IPOIB_DBG_SEND ); + + UNUSED_PARAM(b_pending); + + ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); + + cl_obj_lock( &p_port->obj ); + if( p_port->state != IB_QPS_RTS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_SEND, + ("Invalid port state =%d - Flush pending list\n", p_port->state) ); + b_good_port_state = FALSE; + } + cl_obj_unlock( &p_port->obj ); + + if (p_port->send_mgr.pending_list.count <= 0) + return; + + p_item = cl_qlist_remove_head( &p_port->send_mgr.pending_list ); + while (p_item != cl_qlist_end(&p_port->send_mgr.pending_list)) + { + s_buf = (ipoib_send_NB_SG*) (PVOID) p_item; // TODO: Check this casting + + if (!b_good_port_state) + { + // Port is in error state, flush the list + ipoib_inc_send_stat( p_port->p_adapter, IP_STAT_DROPPED, 0 ); + __send_complete_net_buffer( s_buf, NDIS_STATUS_FAILURE, + NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL, FALSE); + } else { + /* Check the send queue and pend the request if not empty. */ + if( p_port->send_mgr.depth == p_port->p_adapter->params.sq_depth ) + { + IPOIB_PRINT( TRACE_LEVEL_WARNING, IPOIB_DBG_SEND, + ("No available WQEs.\n") ); + cl_qlist_insert_head( &p_port->send_mgr.pending_list, p_item ); + break; + } + + bool continue_sending = ipoib_process_sg_list_real(NULL, NULL, (PSCATTER_GATHER_LIST) s_buf->p_sgl, s_buf); + + //cl_qlist_check_validity(&p_port->send_mgr.pending_list); + + if (!continue_sending) + { + ASSERT( cl_is_item_in_qlist(&p_port->send_mgr.pending_list, + (cl_list_item_t*)(PVOID)s_buf) ); + goto Cleanup; + } + } + p_item = cl_qlist_remove_head( &p_port->send_mgr.pending_list ); + } + +Cleanup: + IPOIB_EXIT( IPOIB_DBG_SEND ); +} + + +//TODO: use s_buf-> directly, instead of useless copies + +static void +__send_cb( + IN const ib_cq_handle_t h_cq, + IN void *cq_context ) +{ + ipoib_port_t *p_port; + ib_api_status_t status; + ib_wc_t wc[MAX_SEND_WC], *p_wc, *p_free; + cl_qlist_t done_list; + ipoib_endpt_t *p_endpt; + ip_stat_sel_t type; + NET_BUFFER *p_netbuffer = NULL; + ipoib_send_NB_SG *s_buf; + + PERF_DECLARE( SendCompBundle ); + PERF_DECLARE( SendCb ); + PERF_DECLARE( PollSend ); + PERF_DECLARE( SendComp ); + PERF_DECLARE( FreeSendBuf ); + PERF_DECLARE( RearmSend ); + PERF_DECLARE( PortResume ); + + IPOIB_ENTER( IPOIB_DBG_SEND ); + + ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); + + cl_perf_clr( SendCompBundle ); + + cl_perf_start( SendCb ); + + UNUSED_PARAM( h_cq ); + + cl_qlist_init( &done_list ); + + p_port = (ipoib_port_t*)cq_context; + cl_spinlock_acquire( &p_port->send_lock ); + //cl_qlist_check_validity(&p_port->send_mgr.pending_list); + ipoib_port_ref( p_port, ref_send_cb ); + + for( p_free=wc; p_free < &wc[MAX_SEND_WC - 1]; p_free++ ) + p_free->p_next = p_free + 1; + p_free->p_next = NULL; + + do + { + p_free = wc; + cl_perf_start( PollSend ); + status = p_port->p_adapter->p_ifc->poll_cq( p_port->ib_mgr.h_send_cq, + &p_free, + &p_wc ); + cl_perf_stop( &p_port->p_adapter->perf, PollSend ); + CL_ASSERT( status == IB_SUCCESS || status == IB_NOT_FOUND ); + + while( p_wc ) + { + cl_perf_start( SendComp ); + CL_ASSERT( p_wc->status != IB_WCS_SUCCESS || + p_wc->wc_type == IB_WC_SEND || p_wc->wc_type == IB_WC_LSO); + + s_buf = (ipoib_send_NB_SG*)(uintn_t)p_wc->wr_id; + IPOIB_PRINT(TRACE_LEVEL_VERBOSE, IPOIB_DBG_SEND, + ("Successfull send completion for NBL=0x%p .\n", s_buf->p_nbl )); + CL_ASSERT( s_buf ); + + p_endpt = s_buf->p_endpt; + + NDIS_STATUS status = NDIS_STATUS_FAILURE; + switch( p_wc->status ) + { + + case IB_WCS_SUCCESS: + if( p_endpt->h_mcast ) + { + if( p_endpt->dgid.multicast.raw_group_id[11] == 0xFF && + p_endpt->dgid.multicast.raw_group_id[10] == 0xFF && + p_endpt->dgid.multicast.raw_group_id[12] == 0xFF && + p_endpt->dgid.multicast.raw_group_id[13] == 0xFF ) + { + type = IP_STAT_BCAST_BYTES; + } + else + { + type = IP_STAT_MCAST_BYTES; + } + } + else + { + type = IP_STAT_UCAST_BYTES; + } + + p_netbuffer = s_buf->p_curr_nb; + ipoib_inc_send_stat( p_port->p_adapter, type, + NET_BUFFER_DATA_LENGTH(p_netbuffer) ); + status = NDIS_STATUS_SUCCESS; + break; + + case IB_WCS_WR_FLUSHED_ERR: + IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_SEND, + ("Flushed send completion.\n") ); + ipoib_inc_send_stat( p_port->p_adapter, IP_STAT_DROPPED, 0 ); + status = NDIS_STATUS_RESET_IN_PROGRESS; + + break; + + default: + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Send failed with %s (vendor specific %#x)\n", + p_port->p_adapter->p_ifc->get_wc_status_str( p_wc->status ), + (int)p_wc->vendor_specific) ); + ipoib_inc_send_stat( p_port->p_adapter, IP_STAT_ERROR, 0 ); + status = NDIS_STATUS_FAILURE; + + break; + } + + __send_complete_net_buffer( s_buf, + status, + NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL, + FALSE ); + + cl_atomic_dec( &p_port->send_mgr.depth ); + + p_wc = p_wc->p_next; + cl_perf_inc( SendCompBundle ); + } + /* If we didn't use up every WC, break out. */ + } while( !p_free ); + + + /* Resume any sends awaiting resources. */ + cl_perf_start( PortResume ); + ipoib_port_resume( p_port, TRUE ); + cl_perf_stop( &p_port->p_adapter->perf, PortResume ); + + /* Rearm the CQ. */ + cl_perf_start( RearmSend ); + status = p_port->p_adapter->p_ifc->rearm_cq( p_port->ib_mgr.h_send_cq, FALSE ); + cl_perf_stop( &p_port->p_adapter->perf, RearmSend ); + CL_ASSERT( status == IB_SUCCESS ); + + ipoib_port_deref( p_port, ref_send_cb ); + + cl_perf_stop( &p_port->p_adapter->perf, SendCb ); + cl_perf_update_ctr( &p_port->p_adapter->perf, SendCompBundle ); + //cl_qlist_check_validity(&p_port->send_mgr.pending_list); + cl_spinlock_release( &p_port->send_lock ); + IPOIB_EXIT( IPOIB_DBG_SEND ); +} + + + +/****************************************************************************** +* +* Endpoint manager implementation +* +******************************************************************************/ +static void +__endpt_mgr_construct( + IN ipoib_port_t* const p_port ) +{ + cl_qmap_init( &p_port->endpt_mgr.mac_endpts ); + cl_qmap_init( &p_port->endpt_mgr.lid_endpts ); + cl_fmap_init( &p_port->endpt_mgr.gid_endpts, __gid_cmp ); +} + +//TODO Restore CM +#if 0 +static void +__endpt_cm_mgr_thread( +IN void* p_context ); +#endif + +static ib_api_status_t +__endpt_mgr_init( + IN ipoib_port_t* const p_port ) +{ + IPOIB_ENTER( IPOIB_DBG_INIT ); +#if 0 + if( p_port->p_adapter->params.cm_enabled ) + { + cl_fmap_init( &p_port->endpt_mgr.conn_endpts, __gid_cmp ); + + NdisInitializeListHead( &p_port->endpt_mgr.pending_conns ); + NdisAllocateSpinLock( &p_port->endpt_mgr.conn_lock ); + cl_event_init( &p_port->endpt_mgr.event, FALSE ); + + NdisInitializeListHead( &p_port->endpt_mgr.remove_conns ); + NdisAllocateSpinLock( &p_port->endpt_mgr.remove_lock ); + + cl_thread_init( &p_port->endpt_mgr.h_thread, + __endpt_cm_mgr_thread, + ( const void *)p_port, + "CmEndPtMgr" ); + } +#endif + UNUSED_PARAM(p_port); + IPOIB_EXIT( IPOIB_DBG_INIT ); + return IB_SUCCESS; +} + +//TODO CM Restore +#if 0 +static void +__endpt_cm_mgr_thread( +IN void* p_context ) +{ + ib_api_status_t ib_status; + LIST_ENTRY *p_item; + ipoib_endpt_t *p_endpt; + ipoib_port_t *p_port =( ipoib_port_t *)p_context; + + IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, + ("Starting Port [%d] Endpt CM thread \n", p_port->port_num ) ); + + while( !p_port->endpt_mgr.thread_is_done ) + { + cl_event_wait_on( &p_port->endpt_mgr.event, EVENT_NO_TIMEOUT, FALSE ); + + while( ( p_item = NdisInterlockedRemoveHeadList( + &p_port->endpt_mgr.pending_conns, + &p_port->endpt_mgr.conn_lock) ) != NULL ) + { + + p_endpt = PARENT_STRUCT( p_item, ipoib_endpt_t, list_item ); + if( p_port->endpt_mgr.thread_is_done ) + { + endpt_cm_set_state( p_endpt, IPOIB_CM_DISCONNECTED ); + continue; + } + + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, + ("Endpt[%p] CONNECT REQ to MAC %02x:%02x:%02x:%02x:%02x:%02x\n", + p_endpt, + p_endpt->mac.addr[0], p_endpt->mac.addr[1], + p_endpt->mac.addr[2], p_endpt->mac.addr[3], + p_endpt->mac.addr[4], p_endpt->mac.addr[5] ) ); + + if( !p_endpt->conn.h_send_qp ) + { + ib_status = endpt_cm_create_qp( p_endpt, + &p_endpt->conn.h_send_qp ); + if( ib_status != IB_SUCCESS ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Endpt %p CM create QP failed status %#x\n", + p_endpt, ib_status ) ); + } + else + { + ib_status = ipoib_endpt_connect( p_endpt ); + if( ib_status != IB_SUCCESS && ib_status != IB_PENDING ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Endpt %p conn REQ failed status %#x\n", + p_endpt, ib_status ) ); + } + } + if( ib_status != IB_SUCCESS && ib_status != IB_PENDING ) + { + endpt_cm_set_state( p_endpt, IPOIB_CM_DESTROY ); + endpt_cm_flush_recv( p_port, p_endpt ); + endpt_cm_set_state( p_endpt, IPOIB_CM_DISCONNECTED ); + } + } + + }//while( p_item != NULL ) + + while( ( p_item = NdisInterlockedRemoveHeadList( + &p_port->endpt_mgr.remove_conns, + &p_port->endpt_mgr.remove_lock ) ) != NULL ) + { + p_endpt = PARENT_STRUCT( p_item, ipoib_endpt_t, list_item ); + + endpt_cm_set_state( p_endpt, IPOIB_CM_DESTROY ); + + IPOIB_PRINT( TRACE_LEVEL_WARNING, IPOIB_DBG_INIT, + ("\nDESTROYING Endpt[%p] MAC %02x:%02x:%02x:%02x:%02x:%02x\n", + p_endpt, + p_endpt->mac.addr[0], p_endpt->mac.addr[1], + p_endpt->mac.addr[2], p_endpt->mac.addr[3], + p_endpt->mac.addr[4], p_endpt->mac.addr[5] ) ); + endpt_cm_flush_recv( p_port, p_endpt ); + endpt_cm_set_state( p_endpt, IPOIB_CM_DISCONNECTED ); + cl_obj_destroy( &p_endpt->obj ); + } + } + + p_port->endpt_mgr.thread_is_done++; + NdisFreeSpinLock( &p_port->endpt_mgr.conn_lock ); + + IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, + (" Port [%d] Endpt_mgr thread is done\n", p_port->port_num ) ); +} +#endif + +static void +__endpt_mgr_destroy( + IN ipoib_port_t* const p_port ) +{ + IPOIB_ENTER( IPOIB_DBG_INIT ); + CL_ASSERT( cl_is_qmap_empty( &p_port->endpt_mgr.mac_endpts ) ); + CL_ASSERT( cl_is_qmap_empty( &p_port->endpt_mgr.lid_endpts ) ); + CL_ASSERT( cl_is_fmap_empty( &p_port->endpt_mgr.gid_endpts ) ); + UNUSED_PARAM(p_port); +#if 0 + if( p_port->p_adapter->params.cm_enabled ) + { + CL_ASSERT( cl_is_fmap_empty( &p_port->endpt_mgr.conn_endpts ) ); + } +#endif + IPOIB_EXIT( IPOIB_DBG_INIT ); +} + + +static void +__endpt_mgr_remove_all( + IN ipoib_port_t* const p_port ) +{ + IPOIB_ENTER( IPOIB_DBG_ENDPT ); + + cl_obj_lock( &p_port->obj ); + /* Wait for all readers to complete. */ + while( p_port->endpt_rdr ) + ; + /* + * We don't need to initiate destruction - this is called only + * from the __port_destroying function, and destruction cascades + * to all child objects. Just clear all the maps. + */ + cl_qmap_remove_all( &p_port->endpt_mgr.mac_endpts ); + cl_qmap_remove_all( &p_port->endpt_mgr.lid_endpts ); + cl_fmap_remove_all( &p_port->endpt_mgr.gid_endpts ); + cl_obj_unlock( &p_port->obj ); + + IPOIB_EXIT( IPOIB_DBG_ENDPT ); +} + + +static void +__endpt_mgr_reset_all( + IN ipoib_port_t* const p_port ) +{ + cl_map_item_t *p_item; + cl_fmap_item_t *p_fmap_item; + ipoib_endpt_t *p_endpt; + cl_qlist_t mc_list; + cl_qlist_t conn_list; + uint32_t local_exist = 0; + NDIS_LINK_STATE link_state; + NDIS_STATUS_INDICATION status_indication; + + + IPOIB_ENTER( IPOIB_DBG_ENDPT ); + + cl_qlist_init( &mc_list ); + cl_qlist_init( &conn_list ); + cl_obj_lock( &p_port->obj ); + /* Wait for all readers to complete. */ + while( p_port->endpt_rdr ) + ; + +#if 0 + __endpt_mgr_remove_all(p_port); +#else + link_state.Header.Revision = NDIS_LINK_STATE_REVISION_1; + link_state.Header.Type = NDIS_OBJECT_TYPE_DEFAULT; + link_state.Header.Size = sizeof(NDIS_LINK_STATE); + link_state.MediaConnectState = MediaConnectStateDisconnected; + link_state.MediaDuplexState = MediaDuplexStateFull; + link_state.XmitLinkSpeed = + link_state.RcvLinkSpeed = + SET_PORT_RATE_BPS( p_port->p_adapter->port_rate ); + + IPOIB_INIT_NDIS_STATUS_INDICATION(&status_indication, + p_port->p_adapter->h_adapter, + NDIS_STATUS_LINK_STATE, + (PVOID)&link_state, + sizeof(link_state)); + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, + ("Indicate DISCONNECT!\n") ); + NdisMIndicateStatusEx( p_port->p_adapter->h_adapter, + &status_indication ); + + link_state.MediaConnectState = MediaConnectStateConnected; + IPOIB_INIT_NDIS_STATUS_INDICATION(&status_indication, + p_port->p_adapter->h_adapter, + NDIS_STATUS_LINK_STATE, + (PVOID)&link_state, + sizeof(link_state)); + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, + ("Indicate Connect\n") ); + NdisMIndicateStatusEx( p_port->p_adapter->h_adapter, + &status_indication ); + + + // IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, + // ("Link DOWN!\n") ); + + if( p_port->p_local_endpt ) + { + //TODO: CM RESTORE + //ipoib_port_cancel_listen( p_port, p_port->p_local_endpt ); + + cl_fmap_remove_item( &p_port->endpt_mgr.gid_endpts, + &p_port->p_local_endpt->gid_item ); + cl_qmap_remove_item( &p_port->endpt_mgr.mac_endpts, + &p_port->p_local_endpt->mac_item ); + if( p_port->p_local_endpt->dlid ) + { + cl_qmap_remove_item( &p_port->endpt_mgr.lid_endpts, + &p_port->p_local_endpt->lid_item ); + p_port->p_local_endpt->dlid = 0; + } + + cl_qlist_insert_head( + &mc_list, &p_port->p_local_endpt->mac_item.pool_item.list_item ); + local_exist = 1; + + p_port->p_local_endpt = NULL; + } + + p_item = cl_qmap_head( &p_port->endpt_mgr.mac_endpts ); + while( p_item != cl_qmap_end( &p_port->endpt_mgr.mac_endpts ) ) + { + p_endpt = PARENT_STRUCT( p_item, ipoib_endpt_t, mac_item ); + p_item = cl_qmap_next( p_item ); + if( p_endpt->h_mcast ) + { + /* + * We destroy MC endpoints since they will get recreated + * when the port comes back up and we rejoin the MC groups. + */ + cl_qmap_remove_item( &p_port->endpt_mgr.mac_endpts, + &p_endpt->mac_item ); + cl_fmap_remove_item( &p_port->endpt_mgr.gid_endpts, + &p_endpt->gid_item ); + + cl_qlist_insert_tail( + &mc_list, &p_endpt->mac_item.pool_item.list_item ); + } + /* destroy connected endpoints if any */ + else if( p_port->p_adapter->params.cm_enabled && + endpt_cm_get_state( p_endpt ) != IPOIB_CM_DISCONNECTED ) + { + p_fmap_item = cl_fmap_get( &p_port->endpt_mgr.conn_endpts, &p_endpt->dgid ); + if( p_fmap_item != cl_fmap_end( &p_port->endpt_mgr.conn_endpts ) ) + { + cl_fmap_remove_item( &p_port->endpt_mgr.conn_endpts, + &p_endpt->conn_item ); + } + cl_qmap_remove_item( &p_port->endpt_mgr.mac_endpts, + &p_endpt->mac_item ); + cl_fmap_remove_item( &p_port->endpt_mgr.gid_endpts, + &p_endpt->gid_item ); + + cl_qlist_insert_tail( + &conn_list, &p_endpt->mac_item.pool_item.list_item ); + } + if( p_endpt->h_av ) + { + /* Destroy the AV for all other endpoints. */ + p_port->p_adapter->p_ifc->destroy_av( p_endpt->h_av ); + p_endpt->h_av = NULL; + } + + if( p_endpt->dlid ) + { + cl_qmap_remove_item( &p_port->endpt_mgr.lid_endpts, + &p_endpt->lid_item ); + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_ENDPT, + ("<__endptr_mgr_reset_all: setting p_endpt->dlid to 0\n")); + p_endpt->dlid = 0; + } + + } +#endif + cl_obj_unlock( &p_port->obj ); + + //TODO CM + /*while( cl_qlist_count( &conn_list ) ) + { + endpt_cm_destroy_conn( p_port, + PARENT_STRUCT( cl_qlist_remove_head( &conn_list ), + ipoib_endpt_t, mac_item.pool_item.list_item ) ); + }*/ + + if(cl_qlist_count( &mc_list ) - local_exist) + { + p_port->mcast_cnt = (uint32_t)cl_qlist_count( &mc_list ) - local_exist; + } + else + { + p_port->mcast_cnt = 0; + KeSetEvent( &p_port->leave_mcast_event, EVENT_INCREMENT, FALSE ); + } + + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_ENDPT, + ("p_port->mcast_cnt = %d\n", p_port->mcast_cnt - local_exist)); + + /* Destroy all multicast endpoints now that we have released the lock. */ + while( cl_qlist_count( &mc_list ) ) + { + cl_list_item_t *p_item; + p_item = cl_qlist_remove_head( &mc_list ); + p_endpt = PARENT_STRUCT(p_item, ipoib_endpt_t, + mac_item.pool_item.list_item); + cl_obj_destroy( &p_endpt->obj); + } + + IPOIB_EXIT( IPOIB_DBG_ENDPT ); +} + + +/* + * Called when updating an endpoint entry in response to an ARP. + * Because receive processing is serialized, and holds a reference + * on the endpoint reader, we wait for all *other* readers to exit before + * removing the item. + */ +static void +__endpt_mgr_remove( + IN ipoib_port_t* const p_port, + IN ipoib_endpt_t* const p_endpt ) +{ +#if 0 //CM + cl_fmap_item_t* p_fmap_item; +#endif + IPOIB_ENTER( IPOIB_DBG_ENDPT ); + + /* This function must be called from the receive path */ + CL_ASSERT(p_port->endpt_rdr > 0); + + cl_obj_lock( &p_port->obj ); + /* Wait for all readers to complete. */ + while( p_port->endpt_rdr > 1 ) + ; + + /* Remove the endpoint from the maps so further requests don't find it. */ + cl_qmap_remove_item( &p_port->endpt_mgr.mac_endpts, &p_endpt->mac_item ); + /* + * The enpoints are *ALWAYS* in both the MAC and GID maps. They are only + * in the LID map if the GID has the same subnet prefix as us. + */ + cl_fmap_remove_item( &p_port->endpt_mgr.gid_endpts, &p_endpt->gid_item ); +#if 0 + + if( p_port->p_adapter->params.cm_enabled ) + { + p_fmap_item = cl_fmap_get( &p_port->endpt_mgr.conn_endpts, &p_endpt->dgid ); + + if( p_fmap_item != cl_fmap_end( &p_port->endpt_mgr.conn_endpts ) ) + { + cl_fmap_remove_item( &p_port->endpt_mgr.conn_endpts, + &p_endpt->conn_item ); + } + } +#endif + if( p_endpt->dlid ) + { + cl_qmap_remove_item( &p_port->endpt_mgr.lid_endpts, &p_endpt->lid_item ); + } + + cl_obj_unlock( &p_port->obj ); + cl_obj_destroy( &p_endpt->obj ); + + //TODO CM + //endpt_cm_destroy_conn( p_port, p_endpt ); + + IPOIB_EXIT( IPOIB_DBG_ENDPT ); +} + + +NTSTATUS +ipoib_mac_to_gid( + IN ipoib_port_t* const p_port, + IN const mac_addr_t mac, + OUT ib_gid_t* p_gid ) +{ + ipoib_endpt_t* p_endpt; + cl_map_item_t *p_item; + uint64_t key = 0; + + IPOIB_ENTER( IPOIB_DBG_ENDPT ); + + cl_memcpy( &key, &mac, sizeof(mac_addr_t) ); + + cl_obj_lock( &p_port->obj ); + + p_item = cl_qmap_get( &p_port->endpt_mgr.mac_endpts, key ); + if( p_item == cl_qmap_end( &p_port->endpt_mgr.mac_endpts ) ) + { + cl_obj_unlock( &p_port->obj ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed endpoint lookup.\n") ); + return STATUS_INVALID_PARAMETER; + } + + p_endpt = PARENT_STRUCT( p_item, ipoib_endpt_t, mac_item ); + *p_gid = p_endpt->dgid; + + cl_obj_unlock( &p_port->obj ); + + IPOIB_EXIT( IPOIB_DBG_ENDPT ); + return STATUS_SUCCESS; +} + + +NTSTATUS +ipoib_mac_to_path( + IN ipoib_port_t* const p_port, + IN const mac_addr_t mac, + OUT ib_path_rec_t* p_path ) +{ + ipoib_endpt_t* p_endpt; + cl_map_item_t *p_item; + uint64_t key = 0; + uint8_t sl; + net32_t flow_lbl; + uint8_t hop_limit; + uint8_t pkt_life; + + IPOIB_ENTER( IPOIB_DBG_ENDPT ); + + cl_memcpy( &key, &mac, sizeof(mac_addr_t) ); + + cl_obj_lock( &p_port->obj ); + + if( p_port->p_local_endpt == NULL ) + { + cl_obj_unlock( &p_port->obj ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("No local endpoint.\n") ); + return STATUS_INVALID_PARAMETER; + } + + if( mac.addr[0] == 0 && mac.addr[1] == 0 && mac.addr[2] == 0 && + mac.addr[3] == 0 && mac.addr[4] == 0 && mac.addr[5] == 0 ) + { + p_endpt = p_port->p_local_endpt; + } + else + { + p_item = cl_qmap_get( &p_port->endpt_mgr.mac_endpts, key ); + if( p_item == cl_qmap_end( &p_port->endpt_mgr.mac_endpts ) ) + { + cl_obj_unlock( &p_port->obj ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed endpoint lookup.\n") ); + return STATUS_INVALID_PARAMETER; + } + + p_endpt = PARENT_STRUCT( p_item, ipoib_endpt_t, mac_item ); + } + + p_path->service_id = 0; + p_path->dgid = p_endpt->dgid; + p_path->sgid = p_port->p_local_endpt->dgid; + p_path->dlid = p_endpt->dlid; + p_path->slid = p_port->p_local_endpt->dlid; + + ib_member_get_sl_flow_hop( + p_port->ib_mgr.bcast_rec.sl_flow_hop, + &sl, + &flow_lbl, + &hop_limit + ); + + if( p_path->slid == p_path->dlid ) + pkt_life = 0; + else + pkt_life = p_port->ib_mgr.bcast_rec.pkt_life; + + ib_path_rec_init_local( + p_path, + &p_endpt->dgid, + &p_port->p_local_endpt->dgid, + p_endpt->dlid, + p_port->p_local_endpt->dlid, + 1, + p_port->ib_mgr.bcast_rec.pkey, + sl, 0, + IB_PATH_SELECTOR_EXACTLY, p_port->ib_mgr.bcast_rec.mtu, + IB_PATH_SELECTOR_EXACTLY, p_port->ib_mgr.bcast_rec.rate, + IB_PATH_SELECTOR_EXACTLY, pkt_life, + 0 ); + + /* Set global routing information. */ + ib_path_rec_set_hop_flow_raw( p_path, hop_limit, flow_lbl, FALSE ); + p_path->tclass = p_port->ib_mgr.bcast_rec.tclass; + + cl_obj_unlock( &p_port->obj ); + + IPOIB_EXIT( IPOIB_DBG_ENDPT ); + return STATUS_SUCCESS; +} + + +static inline NDIS_STATUS +__endpt_mgr_ref( + IN ipoib_port_t* const p_port, + IN const mac_addr_t mac, + OUT ipoib_endpt_t** const pp_endpt ) +{ + NDIS_STATUS status; + cl_map_item_t *p_item; + uint64_t key; + + PERF_DECLARE( EndptQueue ); + + IPOIB_ENTER( IPOIB_DBG_ENDPT ); + + if( !cl_memcmp( &mac, &p_port->p_adapter->params.conf_mac, sizeof(mac) ) ) + { + /* Discard loopback traffic. */ + IPOIB_PRINT(TRACE_LEVEL_WARNING, IPOIB_DBG_ENDPT, + ("Discarding loopback traffic\n") ); + IPOIB_EXIT( IPOIB_DBG_ENDPT ); + return NDIS_STATUS_NO_ROUTE_TO_DESTINATION; + } + + key = 0; + cl_memcpy( &key, &mac, sizeof(mac_addr_t) ); + + cl_obj_lock( &p_port->obj ); + + IPOIB_PRINT( TRACE_LEVEL_VERBOSE, IPOIB_DBG_ENDPT, + ("Look for :\t MAC: %02X-%02X-%02X-%02X-%02X-%02X\n", + mac.addr[0], mac.addr[1], mac.addr[2], + mac.addr[3], mac.addr[4], mac.addr[5]) ); + + p_item = cl_qmap_get( &p_port->endpt_mgr.mac_endpts, key ); + if( p_item == cl_qmap_end( &p_port->endpt_mgr.mac_endpts ) ) + { + cl_obj_unlock( &p_port->obj ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_ENDPT, + ("Failed endpoint lookup.\n") ); + return NDIS_STATUS_NO_ROUTE_TO_DESTINATION; + } + + *pp_endpt = PARENT_STRUCT( p_item, ipoib_endpt_t, mac_item ); + ipoib_endpt_ref( *pp_endpt ); + + cl_obj_unlock( &p_port->obj ); + + cl_perf_start( EndptQueue ); + status = ipoib_endpt_queue( *pp_endpt ); + cl_perf_stop( &p_port->p_adapter->perf, EndptQueue ); + if( status != NDIS_STATUS_SUCCESS ) + *pp_endpt = NULL; + + IPOIB_EXIT( IPOIB_DBG_ENDPT ); + return status; +} + + +static inline NDIS_STATUS +__endpt_mgr_get_gid_qpn( + IN ipoib_port_t* const p_port, + IN const mac_addr_t mac, + OUT ib_gid_t* const p_gid, + OUT UNALIGNED net32_t* const p_qpn ) +{ + UNALIGNED + cl_map_item_t *p_item; + ipoib_endpt_t *p_endpt; + uint64_t key; + + IPOIB_ENTER( IPOIB_DBG_ENDPT ); + + cl_obj_lock( &p_port->obj ); + + key = 0; + cl_memcpy( &key, &mac, sizeof(mac_addr_t) ); + p_item = cl_qmap_get( &p_port->endpt_mgr.mac_endpts, key ); + if( p_item == cl_qmap_end( &p_port->endpt_mgr.mac_endpts ) ) + { + cl_obj_unlock( &p_port->obj ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_ENDPT, + ("Failed endpoint lookup.\n") ); + return NDIS_STATUS_FAILURE; + } + + p_endpt = PARENT_STRUCT( p_item, ipoib_endpt_t, mac_item ); + + *p_gid = p_endpt->dgid; + *p_qpn = p_endpt->qpn; + + cl_obj_unlock( &p_port->obj ); + + IPOIB_EXIT( IPOIB_DBG_ENDPT ); + return NDIS_STATUS_SUCCESS; +} + + +static inline ipoib_endpt_t* +__endpt_mgr_get_by_gid( + IN ipoib_port_t* const p_port, + IN const ib_gid_t* const p_gid ) +{ + cl_fmap_item_t *p_item; + ipoib_endpt_t *p_endpt; + + IPOIB_ENTER( IPOIB_DBG_ENDPT ); + + p_item = cl_fmap_get( &p_port->endpt_mgr.gid_endpts, p_gid ); + if( p_item == cl_fmap_end( &p_port->endpt_mgr.gid_endpts ) ) + p_endpt = NULL; + else + p_endpt = PARENT_STRUCT( p_item, ipoib_endpt_t, gid_item ); + + IPOIB_EXIT( IPOIB_DBG_ENDPT ); + return p_endpt; +} + + +static ipoib_endpt_t* +__endpt_mgr_get_by_lid( + IN ipoib_port_t* const p_port, + IN const net16_t lid ) +{ + cl_map_item_t *p_item; + ipoib_endpt_t *p_endpt; + + IPOIB_ENTER( IPOIB_DBG_ENDPT ); + + p_item = cl_qmap_get( &p_port->endpt_mgr.lid_endpts, lid ); + if( p_item == cl_qmap_end( &p_port->endpt_mgr.lid_endpts ) ) + p_endpt = NULL; + else + p_endpt = PARENT_STRUCT( p_item, ipoib_endpt_t, lid_item ); + + IPOIB_EXIT( IPOIB_DBG_ENDPT ); + return p_endpt; +} + + +inline ib_api_status_t +__endpt_mgr_insert_locked( + IN ipoib_port_t* const p_port, + IN const mac_addr_t mac, + IN ipoib_endpt_t* const p_endpt ) +{ + ib_api_status_t status; + + IPOIB_ENTER( IPOIB_DBG_ENDPT ); + + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_ENDPT, + ("insert :\t MAC: %02X-%02X-%02X-%02X-%02X-%02X\n", + mac.addr[0], mac.addr[1], mac.addr[2], + mac.addr[3], mac.addr[4], mac.addr[5]) ); + + cl_obj_lock( &p_port->obj ); + while( p_port->endpt_rdr ) + { + cl_obj_unlock( &p_port->obj ); + cl_obj_lock( &p_port->obj ); + } + /* __endpt_mgr_insert expects *1* reference to be held when being called */ + cl_atomic_inc( &p_port->endpt_rdr ); + status= __endpt_mgr_insert( p_port, mac, p_endpt ); + cl_atomic_dec( &p_port->endpt_rdr ); + cl_obj_unlock( &p_port->obj ); + + return status; +} + + +inline ib_api_status_t +__endpt_mgr_insert( + IN ipoib_port_t* const p_port, + IN const mac_addr_t mac, + IN ipoib_endpt_t* const p_endpt ) +{ + uint64_t key; + cl_status_t cl_status; + cl_map_item_t *p_qitem; + cl_fmap_item_t *p_fitem; + + IPOIB_ENTER( IPOIB_DBG_ENDPT ); + + /* Wait for all accesses to the map to complete. */ + while( p_port->endpt_rdr > 1 ) + ; + + /* Link the endpoint to the port. */ + cl_status = cl_obj_insert_rel_parent_locked( + &p_endpt->rel, &p_port->obj, &p_endpt->obj ); + + if( cl_status != CL_SUCCESS ) + { + cl_obj_destroy( &p_endpt->obj ); + return IB_INVALID_STATE; + } + +#if DBG + cl_atomic_inc( &p_port->ref[ref_endpt_track] ); + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_OBJ, + ("ref type %d ref_cnt %d\n", ref_endpt_track, p_port->obj.ref_cnt) ); +#endif + + p_endpt->mac = mac; + key = 0; + cl_memcpy( &key, &mac, sizeof(mac_addr_t) ); + p_qitem = cl_qmap_insert( &p_port->endpt_mgr.mac_endpts, + key, + &p_endpt->mac_item ); + CL_ASSERT( p_qitem == &p_endpt->mac_item ); + + p_fitem = cl_fmap_insert( &p_port->endpt_mgr.gid_endpts, + &p_endpt->dgid, + &p_endpt->gid_item ); + CL_ASSERT( p_fitem == &p_endpt->gid_item ); + + if( p_endpt->dlid ) + { + p_qitem = cl_qmap_insert( &p_port->endpt_mgr.lid_endpts, + p_endpt->dlid, + &p_endpt->lid_item ); + CL_ASSERT( p_qitem == &p_endpt->lid_item ); + if (p_qitem != &p_endpt->lid_item) + { + // Since we failed to insert into the list, make sure it is not removed + p_endpt->dlid =0; + } + } + + IPOIB_EXIT( IPOIB_DBG_ENDPT ); + return IB_SUCCESS; +} + + +static ib_api_status_t +__endpt_mgr_add_bcast( + IN ipoib_port_t* const p_port, + IN ib_mcast_rec_t *p_mcast_rec ) +{ + ib_api_status_t status; + ipoib_endpt_t *p_endpt; + mac_addr_t bcast_mac; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + /* + * Cache the broadcast group properties for creating future mcast groups. + */ + p_port->ib_mgr.bcast_rec = *p_mcast_rec->p_member_rec; + + /* Allocate the broadcast endpoint. */ + p_endpt = ipoib_endpt_create( &p_mcast_rec->p_member_rec->mgid, + 0, + CL_HTON32(0x00FFFFFF) ); + if( !p_endpt ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ipoib_endpt_create failed.\n") ); + return IB_INSUFFICIENT_RESOURCES; + } + /* set reference to transport to be used while is not attached to the port */ + p_endpt->is_mcast_listener = TRUE; + p_endpt->p_ifc = p_port->p_adapter->p_ifc; + status = ipoib_endpt_set_mcast( p_endpt, + p_port->ib_mgr.h_pd, + p_port->port_num, + p_mcast_rec ); + if( status != IB_SUCCESS ) + { + cl_obj_destroy( &p_endpt->obj ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ipoib_create_mcast_endpt returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + return status; + } + + /* Add the broadcast endpoint to the endpoint map. */ + cl_memset( &bcast_mac, 0xFF, sizeof(bcast_mac) ); + status = __endpt_mgr_insert_locked( p_port, bcast_mac, p_endpt ); + + IPOIB_EXIT( IPOIB_DBG_INIT ); + return status; +} + + +void +ipoib_port_remove_endpt( + IN ipoib_port_t* const p_port, + IN const mac_addr_t mac ) +{ + cl_map_item_t *p_item; + //TODO CM +// cl_fmap_item_t *p_fmap_item; + ipoib_endpt_t *p_endpt; + uint64_t key; + + IPOIB_ENTER( IPOIB_DBG_ENDPT ); + + key = 0; + cl_memcpy( &key, &mac, sizeof(mac_addr_t) ); + + /* Remove the endpoint from the maps so further requests don't find it. */ + cl_obj_lock( &p_port->obj ); + + /* Wait for all readers to finish */ + while( p_port->endpt_rdr ) + ; + p_item = cl_qmap_remove( &p_port->endpt_mgr.mac_endpts, key ); + /* + * Dereference the endpoint. If the ref count goes to zero, it + * will get freed. + */ + if( p_item != cl_qmap_end( &p_port->endpt_mgr.mac_endpts ) ) + { + p_endpt = PARENT_STRUCT( p_item, ipoib_endpt_t, mac_item ); + /* + * The enpoints are *ALWAYS* in both the MAC and GID maps. They are only + * in the LID map if the GID has the same subnet prefix as us. + */ + cl_fmap_remove_item( + &p_port->endpt_mgr.gid_endpts, &p_endpt->gid_item ); +#if 0 + if( p_port->p_adapter->params.cm_enabled ) + { + p_fmap_item = cl_fmap_get( &p_port->endpt_mgr.conn_endpts, + &p_endpt->dgid ); + + if( p_fmap_item != cl_fmap_end( &p_port->endpt_mgr.conn_endpts ) ) + { + cl_fmap_remove_item( &p_port->endpt_mgr.conn_endpts, + &p_endpt->conn_item ); + } + } +#endif + + if( p_endpt->dlid ) + { + cl_qmap_remove_item( + &p_port->endpt_mgr.lid_endpts, &p_endpt->lid_item ); + p_endpt->dlid = 0; + } + + cl_obj_unlock( &p_port->obj ); + cl_obj_destroy( &p_endpt->obj ); + //TODO CM + //endpt_cm_destroy_conn( p_port, p_endpt ); + +#if DBG + cl_atomic_dec( &p_port->ref[ref_endpt_track] ); + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_ENDPT, + ("ref type %d ref_cnt %d\n", ref_endpt_track, p_port->obj.ref_cnt) ); +#endif + } + else + cl_obj_unlock( &p_port->obj ); + + IPOIB_EXIT( IPOIB_DBG_ENDPT ); +} + +/* + * The sequence for port up is as follows: + * 1. The port goes active. This allows the adapter to send SA queries + * and join the broadcast group (and other groups). + * + * 2. The adapter sends an SA query for the broadcast group. + * + * 3. Upon completion of the query, the adapter joins the broadcast group. + */ + + +/* + * Query the SA for the broadcast group. + */ +void +ipoib_port_up( + IN ipoib_port_t* const p_port, + IN const ib_pnp_port_rec_t* const p_pnp_rec ) +{ + ib_port_info_t *p_port_info; + ib_mad_t *mad_in = NULL; + ib_mad_t *mad_out = NULL; + ib_api_status_t status = IB_INSUFFICIENT_MEMORY; + static int cnt = 0; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_INIT, + ("[%d] Entering port_up.\n", ++cnt) ); + p_port->n_no_progress = 0; // Init the send failure counter + + cl_obj_lock( &p_port->obj ); + if ( p_port->state == IB_QPS_INIT ) + { + cl_obj_unlock( &p_port->obj ); + status = IB_SUCCESS; + IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, + ("p_port->state = %d - Aborting.\n", p_port->state) ); + goto up_done; + } + else if ( p_port->state == IB_QPS_RTS ) + { + cl_obj_unlock( &p_port->obj ); + cl_obj_lock( &p_port->p_adapter->obj ); + if( p_port->p_adapter->state == IB_PNP_PORT_INIT ) + { + p_port->p_adapter->state = IB_PNP_PORT_ACTIVE; + } + cl_obj_unlock( &p_port->p_adapter->obj ); + status = IB_SUCCESS; + IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, + ("Port init is done. p_port->state = %d.\n", p_port->state ) ); + goto up_done; + } + p_port->state = IB_QPS_INIT; + cl_obj_unlock( &p_port->obj ); + + + /* Wait for all work requests to get flushed. */ + while( p_port->recv_mgr.depth || p_port->send_mgr.depth ) + cl_thread_suspend( 0 ); + + KeResetEvent( &p_port->sa_event ); + + mad_out = (ib_mad_t *) (ib_mad_t*)cl_zalloc(256); + if(! mad_out) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("failed to allocate mad mad_out\n")); + goto up_done; + } + mad_in = (ib_mad_t *) cl_zalloc(256); + if(! mad_in) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("failed to allocate mad mad_in\n")); + goto up_done; + } + + mad_in->attr_id = IB_MAD_ATTR_PORT_INFO; + mad_in->method = IB_MAD_METHOD_GET; + mad_in->base_ver = 1; + mad_in->class_ver =1; + mad_in->mgmt_class = IB_MCLASS_SUBN_LID; + + status = p_port->p_adapter->p_ifc->local_mad( p_port->ib_mgr.h_ca, + p_port->port_num, + mad_in, + mad_out ); + if( status != IB_SUCCESS ) + { + ipoib_set_inactive( p_port->p_adapter ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_local_mad returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + goto up_done; + } + + p_port_info = (ib_port_info_t*)(((ib_smp_t*)mad_out)->data); + p_port->base_lid = p_pnp_rec->p_port_attr->lid; + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, + ("Received port info: link width = %d.\n", + p_port_info->link_width_active) ); + p_port->ib_mgr.rate = ib_port_info_compute_rate( p_port_info ); + + ipoib_set_rate( p_port->p_adapter, + p_port_info->link_width_active, + ib_port_info_get_link_speed_active( p_port_info ) ); + + status = __port_get_bcast( p_port ); + if (status != IB_SUCCESS) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + (" __port_get_bcast returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( status ))); + } + +up_done: + if( status != IB_SUCCESS ) + { + if( status != IB_CANCELED ) + { + ipoib_set_inactive( p_port->p_adapter ); + __endpt_mgr_reset_all( p_port ); + } + ASSERT(p_port->state == IB_QPS_INIT || p_port->state == IB_QPS_ERROR); + p_port->state = IB_QPS_ERROR; + KeSetEvent( &p_port->sa_event, EVENT_INCREMENT, FALSE ); + } + + if(mad_out) + cl_free(mad_out); + if(mad_in) + cl_free(mad_in); + + IPOIB_EXIT( IPOIB_DBG_INIT ); +} + + +static ib_api_status_t +__endpt_mgr_add_local( + IN ipoib_port_t* const p_port, + IN ib_port_info_t* const p_port_info ) +{ + ib_api_status_t status; + ib_gid_t gid; + ipoib_endpt_t *p_endpt; + ib_av_attr_t av_attr; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + ib_gid_set_default( &gid, p_port->p_adapter->guids.port_guid.guid ); + p_endpt = ipoib_endpt_create( &gid, p_port_info->base_lid, p_port->ib_mgr.qpn ); + if( !p_endpt ) + { + p_port->p_adapter->hung = TRUE; + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to create local endpt\n") ); + return IB_INSUFFICIENT_MEMORY; + } + + cl_memclr( &av_attr, sizeof(ib_av_attr_t) ); + av_attr.port_num = p_port->port_num; + av_attr.sl = 0; + IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_ENDPT, + (" av_attr.dlid = p_port_info->base_lid = %d\n", + cl_ntoh16( p_port_info->base_lid ) )); + av_attr.dlid = p_port_info->base_lid; + av_attr.static_rate = p_port->ib_mgr.rate; + av_attr.path_bits = 0; + status = p_port->p_adapter->p_ifc->create_av( + p_port->ib_mgr.h_pd, &av_attr, &p_endpt->h_av ); + if( status != IB_SUCCESS ) + { + cl_obj_destroy( &p_endpt->obj ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_create_av for local endpoint returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + return status; + } + + /* __endpt_mgr_insert expects *one* reference to be held. */ + cl_atomic_inc( &p_port->endpt_rdr ); + status = __endpt_mgr_insert( p_port, + p_port->p_adapter->params.conf_mac, + p_endpt ); + cl_atomic_dec( &p_port->endpt_rdr ); + if( status != IB_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("__endpt_mgr_insert for local endpoint returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + return status; + } + + p_port->p_local_endpt = p_endpt; + + IPOIB_EXIT( IPOIB_DBG_INIT ); + return status; +} + + +static ib_api_status_t +__port_get_bcast( + IN ipoib_port_t* const p_port ) +{ + ib_api_status_t status; + ib_query_req_t query; + ib_user_query_t info; + ib_member_rec_t member_rec; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + info.method = IB_MAD_METHOD_GETTABLE; + info.attr_id = IB_MAD_ATTR_MCMEMBER_RECORD; + info.attr_size = sizeof(ib_member_rec_t); + info.comp_mask = IB_MCR_COMPMASK_MGID; + info.p_attr = &member_rec; + + /* Query requires only the MGID. */ + cl_memclr( &member_rec, sizeof(ib_member_rec_t) ); + member_rec.mgid = bcast_mgid_template; + + member_rec.mgid.raw[4] = (uint8_t) (p_port->p_adapter->guids.port_guid.pkey >> 8) ; + member_rec.mgid.raw[5] = (uint8_t) p_port->p_adapter->guids.port_guid.pkey; + member_rec.pkey = cl_hton16(p_port->p_adapter->guids.port_guid.pkey); + cl_memclr( &query, sizeof(ib_query_req_t) ); + query.query_type = IB_QUERY_USER_DEFINED; + query.p_query_input = &info; + query.port_guid = p_port->p_adapter->guids.port_guid.guid; + query.timeout_ms = p_port->p_adapter->params.sa_timeout; + query.retry_cnt = p_port->p_adapter->params.sa_retry_cnt; + query.query_context = p_port; + query.pfn_query_cb = __bcast_get_cb; + + /* reference the object for the multicast query. */ + ipoib_port_ref( p_port, ref_get_bcast ); + + status = p_port->p_adapter->p_ifc->query( p_port->p_adapter->h_al, + &query, + &p_port->ib_mgr.h_query ); + if( status != IB_SUCCESS ) + { + ipoib_port_deref( p_port, ref_get_bcast ); +// ASSERT(FALSE); + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_query returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + } + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_query returned SUCCESS\n")); + IPOIB_EXIT( IPOIB_DBG_INIT ); + return status; +} + + +/* Callback for the MCMemberRecord Get query for the IPv4 broadcast group. */ +static void +__bcast_get_cb( + IN ib_query_rec_t *p_query_rec ) +{ + ipoib_port_t *p_port; + ib_member_rec_t *p_mc_req; + ib_api_status_t status; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + p_port = (ipoib_port_t*)p_query_rec->query_context; + + cl_obj_lock( &p_port->obj ); + p_port->ib_mgr.h_query = NULL; + + CL_ASSERT(p_port->state == IB_QPS_INIT || p_port->state == IB_QPS_ERROR); + if( p_port->state != IB_QPS_INIT ) + { + status = IB_CANCELED; + goto done; + } + + status = p_query_rec->status; + + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, + ("status of request %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + + switch( status ) + { + case IB_SUCCESS: + if( p_query_rec->result_cnt ) + { + p_mc_req = (ib_member_rec_t*) + ib_get_query_result( p_query_rec->p_result_mad, 0 ); + + /* Join the broadcast group. */ + status = __port_join_bcast( p_port, p_mc_req ); + break; + } + /* Fall through. */ + + case IB_REMOTE_ERROR: + /* SA failed the query. Broadcast group doesn't exist, create it. */ + status = __port_create_bcast( p_port ); + break; + + case IB_CANCELED: + IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, + ("Instance destroying - Aborting.\n") ); + break; + + default: + NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter, + EVENT_IPOIB_BCAST_GET, 1, p_query_rec->status ); + } +done: + cl_obj_unlock( &p_port->obj ); + + if( status != IB_SUCCESS ) + { + if( status != IB_CANCELED ) + { + ipoib_set_inactive( p_port->p_adapter ); + __endpt_mgr_reset_all( p_port ); + } + p_port->state = IB_QPS_ERROR; + KeSetEvent( &p_port->sa_event, EVENT_INCREMENT, FALSE ); + } + + /* Return the response MAD to AL. */ + if( p_query_rec->p_result_mad ) + p_port->p_adapter->p_ifc->put_mad( p_query_rec->p_result_mad ); + + /* Release the reference taken when issuing the member record query. */ + ipoib_port_deref( p_port, ref_bcast_get_cb ); + + IPOIB_EXIT( IPOIB_DBG_INIT ); +} + + +static ib_api_status_t +__port_join_bcast( + IN ipoib_port_t* const p_port, + IN ib_member_rec_t* const p_member_rec ) +{ + ib_api_status_t status; + ib_mcast_req_t mcast_req; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + /* Check that the rate is realizable for our port. */ + if( p_port->ib_mgr.rate < (p_member_rec->rate & 0x3F) && + (g_ipoib.bypass_check_bcast_rate == 0)) + { + /* + * The MC group rate is higher than our port's rate. Log an error + * and stop. A port transition will drive the retry. + */ + IPOIB_PRINT(TRACE_LEVEL_WARNING, IPOIB_DBG_INIT, + ("Unrealizable join due to rate mismatch.\n") ); + NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter, + EVENT_IPOIB_BCAST_RATE, 2, + (uint32_t)(p_member_rec->rate & 0x3F), + (uint32_t)p_port->ib_mgr.rate ); + return IB_ERROR; + } + + /* Join the broadcast group. */ + cl_memclr( &mcast_req, sizeof(mcast_req) ); + /* Copy the results of the Get to use as parameters. */ + mcast_req.member_rec = *p_member_rec; + /* We specify our port GID for the join operation. */ + mcast_req.member_rec.port_gid.unicast.prefix = IB_DEFAULT_SUBNET_PREFIX; + mcast_req.member_rec.port_gid.unicast.interface_id = + p_port->p_adapter->guids.port_guid.guid; + + mcast_req.mcast_context = p_port; + mcast_req.pfn_mcast_cb = __bcast_cb; + mcast_req.timeout_ms = p_port->p_adapter->params.sa_timeout; + mcast_req.retry_cnt = p_port->p_adapter->params.sa_retry_cnt; + mcast_req.port_guid = p_port->p_adapter->guids.port_guid.guid; + mcast_req.pkey_index = p_port->pkey_index; + + if( ib_member_get_state( mcast_req.member_rec.scope_state ) != + IB_MC_REC_STATE_FULL_MEMBER ) + { + IPOIB_PRINT(TRACE_LEVEL_WARNING, IPOIB_DBG_INIT, + ("Incorrect MC member rec join state in query response.\n") ); + ib_member_set_state( &mcast_req.member_rec.scope_state, + IB_MC_REC_STATE_FULL_MEMBER ); + } + + /* reference the object for the multicast join request. */ + ipoib_port_ref( p_port, ref_join_bcast ); + + status = p_port->p_adapter->p_ifc->join_mcast( + p_port->ib_mgr.h_qp, &mcast_req ); + if( status != IB_SUCCESS ) + { + ipoib_port_deref( p_port, ref_bcast_join_failed ); + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_join_mcast returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + } + IPOIB_EXIT( IPOIB_DBG_INIT ); + return status; +} + + +static ib_api_status_t +__port_create_bcast( + IN ipoib_port_t* const p_port ) +{ + ib_api_status_t status; + ib_mcast_req_t mcast_req; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + /* Join the broadcast group. */ + cl_memclr( &mcast_req, sizeof(mcast_req) ); + mcast_req.create = TRUE; + /* + * Create requires pkey, qkey, SL, flow label, traffic class, joing state + * and port GID. + * + * We specify the MGID since we don't want the SA to generate it for us. + */ + mcast_req.member_rec.mgid = bcast_mgid_template; + mcast_req.member_rec.mgid.raw[4] = (uint8_t) (p_port->p_adapter->guids.port_guid.pkey >> 8); + mcast_req.member_rec.mgid.raw[5] = (uint8_t) p_port->p_adapter->guids.port_guid.pkey; + ib_gid_set_default( &mcast_req.member_rec.port_gid, + p_port->p_adapter->guids.port_guid.guid ); + /* + * IPOIB spec requires that the QKEY have the MSb set so that the QKEY + * from the QP is used rather than the QKEY in the send WR. + */ + mcast_req.member_rec.qkey = + (uint32_t)(uintn_t)p_port | IB_QP_PRIVILEGED_Q_KEY; + mcast_req.member_rec.mtu = + (IB_PATH_SELECTOR_EXACTLY << 6) | IB_MTU_LEN_2048; + + mcast_req.member_rec.pkey = cl_hton16(p_port->p_adapter->guids.port_guid.pkey); + + mcast_req.member_rec.sl_flow_hop = ib_member_set_sl_flow_hop( 0, 0, 0 ); + mcast_req.member_rec.scope_state = + ib_member_set_scope_state( 2, IB_MC_REC_STATE_FULL_MEMBER ); + + mcast_req.mcast_context = p_port; + mcast_req.pfn_mcast_cb = __bcast_cb; + mcast_req.timeout_ms = p_port->p_adapter->params.sa_timeout; + mcast_req.retry_cnt = p_port->p_adapter->params.sa_retry_cnt; + mcast_req.port_guid = p_port->p_adapter->guids.port_guid.guid; + mcast_req.pkey_index = p_port->pkey_index; + + /* reference the object for the multicast join request. */ + ipoib_port_ref( p_port, ref_join_bcast ); + + status = p_port->p_adapter->p_ifc->join_mcast( p_port->ib_mgr.h_qp, &mcast_req ); + if( status != IB_SUCCESS ) + { + ipoib_port_deref( p_port, ref_bcast_create_failed ); + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_join_mcast returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + } + IPOIB_EXIT( IPOIB_DBG_INIT ); + return status; +} + + +void +ipoib_port_down( + IN ipoib_port_t* const p_port ) +{ + ib_api_status_t status; + ib_qp_mod_t qp_mod; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + /* + * Mark our state. This causes all callbacks to abort. + * Note that we hold the receive lock so that we synchronize + * with reposting. We must take the receive lock before the + * object lock since that is the order taken when reposting. + */ + cl_spinlock_acquire( &p_port->recv_lock ); + cl_spinlock_acquire( &p_port->send_lock ); + cl_obj_lock( &p_port->obj ); + p_port->state = IB_QPS_ERROR; + + __pending_list_destroy(p_port); + NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter, + EVENT_IPOIB_PORT_DOWN, 0 ); + + if( p_port->ib_mgr.h_query ) + { + p_port->p_adapter->p_ifc->cancel_query( + p_port->p_adapter->h_al, p_port->ib_mgr.h_query ); + p_port->ib_mgr.h_query = NULL; + } + cl_obj_unlock( &p_port->obj ); + cl_spinlock_release( &p_port->send_lock ); + cl_spinlock_release( &p_port->recv_lock ); + + KeWaitForSingleObject( + &p_port->sa_event, Executive, KernelMode, FALSE, NULL ); + + /* garbage collector timer is not needed when link is down */ + KeCancelTimer(&p_port->gc_timer); + KeFlushQueuedDpcs(); + + /* + * Put the QP in the error state. This removes the need to + * synchronize with send/receive callbacks. + */ + CL_ASSERT( p_port->ib_mgr.h_qp ); + cl_memclr( &qp_mod, sizeof(ib_qp_mod_t) ); + qp_mod.req_state = IB_QPS_ERROR; + status = p_port->p_adapter->p_ifc->modify_qp( p_port->ib_mgr.h_qp, &qp_mod ); + if( status != IB_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_modify_qp to error state returned %s.\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + p_port->p_adapter->hung = TRUE; + return; + } + + KeResetEvent(&p_port->leave_mcast_event); + + /* Reset all endpoints so we don't flush our ARP cache. */ + __endpt_mgr_reset_all( p_port ); + + KeWaitForSingleObject( + &p_port->leave_mcast_event, Executive, KernelMode, FALSE, NULL ); + + cl_obj_lock( &p_port->p_adapter->obj ); + ipoib_dereg_addrs( p_port->p_adapter ); + cl_obj_unlock( &p_port->p_adapter->obj ); + + IPOIB_EXIT( IPOIB_DBG_INIT ); +} + + +static void +__bcast_cb( + IN ib_mcast_rec_t *p_mcast_rec ) +{ + ipoib_port_t *p_port; + ib_api_status_t status; + LARGE_INTEGER gc_due_time; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + + p_port = (ipoib_port_t*)p_mcast_rec->mcast_context; + + cl_obj_lock( &p_port->obj ); + + ASSERT(p_port->state == IB_QPS_INIT || p_port->state == IB_QPS_ERROR); + if( p_port->state != IB_QPS_INIT ) + { + cl_obj_unlock( &p_port->obj ); + if( p_mcast_rec->status == IB_SUCCESS ) + { + ipoib_port_ref(p_port, ref_leave_mcast); + p_port->p_adapter->p_ifc->leave_mcast( p_mcast_rec->h_mcast, + __leave_error_mcast_cb ); + } + KeSetEvent( &p_port->sa_event, EVENT_INCREMENT, FALSE ); + ipoib_port_deref( p_port, ref_bcast_inv_state ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, + ("Invalid state - Aborting.\n") ); + return; + } + status = p_mcast_rec->status; + if( status != IB_SUCCESS ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Multicast join for broadcast group returned %s.\n", + p_port->p_adapter->p_ifc->get_err_str( p_mcast_rec->status )) ); + if( status == IB_REMOTE_ERROR ) + { + /* + * Either: + * - the join failed because the group no longer exists + * - the create failed because the group already exists + * + * Kick off a new Get query to the SA to restart the join process + * from the top. Note that as an optimization, it would be + * possible to distinguish between the join and the create. + * If the join fails, try the create. If the create fails, start + * over with the Get. + */ + /* TODO: Assert is a place holder. Can we ever get here if the + state isn't IB_PNP_PORT_ADD or PORT_DOWN or PORT_INIT? */ + CL_ASSERT( p_port->p_adapter->state == IB_PNP_PORT_ADD || + p_port->p_adapter->state == IB_PNP_PORT_DOWN || + p_port->p_adapter->state == IB_PNP_PORT_INIT ); + if(++p_port->bc_join_retry_cnt < p_port->p_adapter->params.bc_join_retry) + { + status = __port_get_bcast( p_port ); + } + else + { + NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter, + EVENT_IPOIB_BCAST_JOIN, 1, p_mcast_rec->status ); + p_port->bc_join_retry_cnt = 0; + } + } + else + { + NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter, + EVENT_IPOIB_BCAST_JOIN, 1, p_mcast_rec->status ); + } + + cl_obj_unlock( &p_port->obj ); + if( status != IB_SUCCESS ) + { + ipoib_set_inactive( p_port->p_adapter ); + __endpt_mgr_reset_all( p_port ); + ASSERT(p_port->state == IB_QPS_INIT || p_port->state == IB_QPS_ERROR); + p_port->state = IB_QPS_ERROR; + KeSetEvent( &p_port->sa_event, EVENT_INCREMENT, FALSE ); + } + ipoib_port_deref( p_port, ref_bcast_req_failed ); + IPOIB_EXIT( IPOIB_DBG_INIT ); + return; + } + p_port->bc_join_retry_cnt = 0; + + while( p_port->endpt_rdr ) + { + cl_obj_unlock( &p_port->obj ); + cl_obj_lock( &p_port->obj ); + } + + if( !p_port->p_local_endpt ) + { + ib_port_info_t port_info; + cl_memclr(&port_info, sizeof(port_info)); + port_info.base_lid = p_port->base_lid; + status = __endpt_mgr_add_local( p_port, &port_info ); + if( status != IB_SUCCESS ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("__endpt_mgr_add_local returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + cl_obj_unlock( &p_port->obj ); + goto err; + } + } + + cl_obj_unlock( &p_port->obj ); + + status = __endpt_mgr_add_bcast( p_port, p_mcast_rec ); + if( status != IB_SUCCESS ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("__endpt_mgr_add_bcast returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + ipoib_port_ref(p_port, ref_leave_mcast); + status = p_port->p_adapter->p_ifc->leave_mcast( p_mcast_rec->h_mcast, + __leave_error_mcast_cb ); + CL_ASSERT( status == IB_SUCCESS ); + goto err; + } + + /* Get the QP ready for action. */ + status = __ib_mgr_activate( p_port ); + if( status != IB_SUCCESS ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("__ib_mgr_activate returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + +err: + /* Flag the adapter as hung. */ + p_port->p_adapter->hung = TRUE; + ASSERT(p_port->state == IB_QPS_INIT || p_port->state == IB_QPS_ERROR); + p_port->state = IB_QPS_ERROR; + KeSetEvent( &p_port->sa_event, EVENT_INCREMENT, FALSE ); + ipoib_port_deref( p_port, ref_bcast_error ); + IPOIB_EXIT( IPOIB_DBG_INIT ); + return; + } + + cl_obj_lock( &p_port->obj ); + /* Only change the state if we're still in INIT. */ + ASSERT( p_port->state == IB_QPS_INIT || p_port->state == IB_QPS_ERROR); + if (p_port->state == IB_QPS_INIT) + { + p_port->state = IB_QPS_RTS; + } + cl_obj_unlock( &p_port->obj ); + + /* Prepost receives. */ + cl_spinlock_acquire( &p_port->recv_lock ); + __recv_mgr_repost( p_port ); + cl_spinlock_release( &p_port->recv_lock ); + + /* Notify the adapter that we now have an active connection. */ + status = ipoib_set_active( p_port->p_adapter ); + if( status != IB_SUCCESS ) + { + ib_qp_mod_t qp_mod; + ipoib_set_inactive( p_port->p_adapter ); + KeSetEvent( &p_port->sa_event, EVENT_INCREMENT, FALSE ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, + ("ipoib_set_active returned %s.\n",p_port->p_adapter->p_ifc->get_err_str( status ))); + cl_spinlock_acquire( &p_port->recv_lock ); + cl_obj_lock( &p_port->obj ); + p_port->state = IB_QPS_ERROR; + if( p_port->ib_mgr.h_query ) + { + p_port->p_adapter->p_ifc->cancel_query( + p_port->p_adapter->h_al, p_port->ib_mgr.h_query ); + p_port->ib_mgr.h_query = NULL; + } + cl_obj_unlock( &p_port->obj ); + cl_spinlock_release( &p_port->recv_lock ); + + CL_ASSERT( p_port->ib_mgr.h_qp ); + cl_memclr( &qp_mod, sizeof(ib_qp_mod_t) ); + qp_mod.req_state = IB_QPS_ERROR; + status = p_port->p_adapter->p_ifc->modify_qp( p_port->ib_mgr.h_qp, &qp_mod ); + __endpt_mgr_reset_all( p_port ); + + ipoib_port_deref( p_port, ref_join_bcast ); + return; + } +#if IPOIB_CM //CM + if( p_port->p_adapter->params.cm_enabled && + !p_port->p_local_endpt->conn.h_cm_listen ) + { + if( ipoib_port_listen( p_port ) != IB_SUCCESS ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Port CM Listen failed\n" ) ); + /*keep going with UD only */ + p_port->p_adapter->params.cm_enabled = FALSE; + + NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter, + EVENT_IPOIB_CONNECTED_MODE_ERR, 1, 0xbadc0de3 ); + } + } +#endif + /* garbage collector timer is needed when link is active */ + gc_due_time.QuadPart = -(int64_t)(((uint64_t)p_port->p_adapter->params.mc_leave_rescan * 2000000) * 10); + KeSetTimerEx(&p_port->gc_timer,gc_due_time, + (LONG)p_port->p_adapter->params.mc_leave_rescan*1000,&p_port->gc_dpc); + + KeSetEvent( &p_port->sa_event, EVENT_INCREMENT, FALSE ); + ipoib_port_deref( p_port, ref_join_bcast ); + IPOIB_EXIT( IPOIB_DBG_INIT ); +} + + +static void +__qp_event( + IN ib_async_event_rec_t *p_event_rec ) +{ + UNUSED_PARAM( p_event_rec ); + CL_ASSERT( p_event_rec->context ); + ((ipoib_port_t*)p_event_rec->context)->p_adapter->hung = TRUE; +} + + +static void +__cq_event( + IN ib_async_event_rec_t *p_event_rec ) +{ + UNUSED_PARAM( p_event_rec ); + CL_ASSERT( p_event_rec->context ); + ((ipoib_port_t*)p_event_rec->context)->p_adapter->hung = TRUE; +} + + +static ib_api_status_t +__ib_mgr_activate( + IN ipoib_port_t* const p_port ) +{ + ib_api_status_t status; + ib_dgrm_info_t dgrm_info; + ib_qp_mod_t qp_mod; + + IPOIB_ENTER( IPOIB_DBG_INIT ); + /* + * Move the QP to RESET. This allows us to reclaim any + * unflushed receives. + */ + cl_memclr( &qp_mod, sizeof(ib_qp_mod_t) ); + qp_mod.req_state = IB_QPS_RESET; + status = p_port->p_adapter->p_ifc->modify_qp( p_port->ib_mgr.h_qp, &qp_mod ); + if( status != IB_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_modify_qp returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + return status; + } + + /* Move the QP to RTS. */ + dgrm_info.port_guid = p_port->p_adapter->guids.port_guid.guid; + dgrm_info.qkey = p_port->ib_mgr.bcast_rec.qkey; + dgrm_info.pkey_index = p_port->pkey_index; + status = p_port->p_adapter->p_ifc->init_dgrm_svc( p_port->ib_mgr.h_qp, &dgrm_info ); + if( status != IB_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_init_dgrm_svc returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + return status; + } + + /* Rearm the CQs. */ + status = p_port->p_adapter->p_ifc->rearm_cq( p_port->ib_mgr.h_recv_cq, FALSE ); + if( status != IB_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_rearm_cq for recv returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + return status; + } + status = p_port->p_adapter->p_ifc->rearm_cq( p_port->ib_mgr.h_send_cq, FALSE ); + if( status != IB_SUCCESS ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_rearm_cq for send returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + return status; + } + + IPOIB_EXIT( IPOIB_DBG_INIT ); + return IB_SUCCESS; +} + + +/* Transition to a passive level thread. */ + +ib_api_status_t +ipoib_port_join_mcast( + IN ipoib_port_t* const p_port, + IN const mac_addr_t mac, + IN const uint8_t state) +{ + ib_api_status_t status; + ib_mcast_req_t mcast_req; + ipoib_endpt_t *p_endpt; + + IPOIB_ENTER( IPOIB_DBG_MCAST ); + + IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_MCAST, + ("Join Multicast request: \n" + "\tsrc MAC: %02X-%02X-%02X-%02X-%02X-%02X\n", + mac.addr[0], mac.addr[1], + mac.addr[2], mac.addr[3], + mac.addr[4], mac.addr[5])); + + + switch( __endpt_mgr_ref( p_port, mac, &p_endpt ) ) + { + case NDIS_STATUS_NO_ROUTE_TO_DESTINATION: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_MCAST, + ("NDIS_STATUS_NO_ROUTE_TO_DESTINATION\n") ); + break; + + case NDIS_STATUS_SUCCESS: + ipoib_endpt_deref( p_endpt ); + /* Fall through */ + + case NDIS_STATUS_PENDING: + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_MCAST, + (" PENDING\n") ); + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_ENDPT, + ("__endpt_mgr_ref called for %p\n", p_endpt)); + return IB_SUCCESS; + } + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_ENDPT, + ("__endpt_mgr_ref called for %p\n", p_endpt)); + /* + * Issue the mcast request, using the parameters of the broadcast group. + * This allows us to do a create request that should always succeed since + * the required parameters are known. + */ + cl_memclr( &mcast_req, sizeof(mcast_req) ); + mcast_req.create = TRUE; + + /* Copy the settings from the broadcast group. */ + mcast_req.member_rec = p_port->ib_mgr.bcast_rec; + /* Clear fields that aren't specified in the join */ + mcast_req.member_rec.mlid = 0; + ib_member_set_state( &mcast_req.member_rec.scope_state,state); + + if( (mac.addr[0] == 1) && (mac.addr[2] == 0x5E )) + { + /* + * Update the address portion of the MGID with the 28 lower bits of the + * IP address. Since we're given a MAC address, we are using + * 24 lower bits of that network-byte-ordered value (assuming MSb + * is zero) and 4 lsb bits of the first byte of IP address. + */ + mcast_req.member_rec.mgid.raw[12] = mac.addr[1]; + mcast_req.member_rec.mgid.raw[13] = mac.addr[3]; + mcast_req.member_rec.mgid.raw[14] = mac.addr[4]; + mcast_req.member_rec.mgid.raw[15] = mac.addr[5]; + } + else + { + /* Handle non IP mutlicast MAC addresses. */ + /* Update the signature to use the lower 2 bytes of the OpenIB OUI. */ + mcast_req.member_rec.mgid.raw[2] = 0x14; + mcast_req.member_rec.mgid.raw[3] = 0x05; + /* Now copy the MAC address into the last 6 bytes of the GID. */ + cl_memcpy( &mcast_req.member_rec.mgid.raw[10], mac.addr, 6 ); + } + + mcast_req.mcast_context = p_port; + mcast_req.pfn_mcast_cb = __mcast_cb; + mcast_req.timeout_ms = p_port->p_adapter->params.sa_timeout; + mcast_req.retry_cnt = p_port->p_adapter->params.sa_retry_cnt; + mcast_req.port_guid = p_port->p_adapter->guids.port_guid.guid; + mcast_req.pkey_index = p_port->pkey_index; + mcast_req.member_rec.pkey = cl_hton16(p_port->p_adapter->guids.port_guid.pkey); + /* + * Create the endpoint and insert it in the port. Since we don't wait for + * the mcast SA operations to complete before returning from the multicast + * list set OID asynchronously, it is possible for the mcast entry to be + * cleared before the SA interaction completes. In this case, when the + * mcast callback is invoked, it would not find the corresponding endpoint + * and would be undone. + */ + p_endpt = ipoib_endpt_create( &mcast_req.member_rec.mgid, + 0, + CL_HTON32(0x00FFFFFF) ); + if( !p_endpt ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ipoib_endpt_create failed.\n") ); + return IB_INSUFFICIENT_MEMORY; + } + + status = __endpt_mgr_insert_locked( p_port, mac, p_endpt ); + if( status != IB_SUCCESS ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("__endpt_mgr_insert_locked returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + return status; + } + + /* reference the object for the multicast join request. */ + ipoib_port_ref( p_port, ref_join_mcast ); + + status = p_port->p_adapter->p_ifc->join_mcast( p_port->ib_mgr.h_qp, &mcast_req ); + if( status != IB_SUCCESS ) + { + ipoib_port_deref( p_port, ref_mcast_join_failed ); + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("ib_join_mcast returned %s\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + } + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_MCAST, + ("Joined MCAST group with MGID[10:15]= %0x %0x %0x %0x %0x %0x\n", + mcast_req.member_rec.mgid.raw[10], + mcast_req.member_rec.mgid.raw[11], + mcast_req.member_rec.mgid.raw[12], + mcast_req.member_rec.mgid.raw[13], + mcast_req.member_rec.mgid.raw[14], + mcast_req.member_rec.mgid.raw[15]) ); + + IPOIB_EXIT( IPOIB_DBG_MCAST ); + return status; +} + + +static void +__mcast_cb( + IN ib_mcast_rec_t *p_mcast_rec ) +{ + ib_api_status_t status; + ipoib_port_t *p_port; + cl_fmap_item_t *p_item; + ipoib_endpt_t *p_endpt; + + IPOIB_ENTER( IPOIB_DBG_MCAST ); + + p_port = (ipoib_port_t*)p_mcast_rec->mcast_context; + + cl_obj_lock( &p_port->obj ); + while( p_port->endpt_rdr ) + { + cl_obj_unlock( &p_port->obj ); + cl_obj_lock( &p_port->obj ); + } + if( p_port->state != IB_QPS_RTS ) + { + cl_obj_unlock( &p_port->obj ); + if( p_mcast_rec->status == IB_SUCCESS ) + + { + ipoib_port_ref(p_port, ref_leave_mcast); + p_port->p_adapter->p_ifc->leave_mcast( p_mcast_rec->h_mcast, + __leave_error_mcast_cb ); + } + ipoib_port_deref( p_port, ref_mcast_inv_state ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_MCAST, + ("Invalid state - Aborting.\n") ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, + ("Invalid state - Aborting.\n") ); + + cl_spinlock_acquire(&p_port->send_lock); + //ipoib_port_resume(p_port , FALSE); + __pending_list_destroy( p_port ); + cl_spinlock_release(&p_port->send_lock); + return; + } + + if( p_mcast_rec->status != IB_SUCCESS ) + { + cl_obj_unlock( &p_port->obj ); + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Multicast join request failed with status %s.\n", + p_port->p_adapter->p_ifc->get_err_str( p_mcast_rec->status )) ); + /* Flag the adapter as hung. */ + p_port->p_adapter->hung =TRUE; + ipoib_port_deref( p_port, ref_mcast_req_failed ); + IPOIB_EXIT( IPOIB_DBG_MCAST ); + return; + } + + p_item = cl_fmap_get( &p_port->endpt_mgr.gid_endpts, + &p_mcast_rec->p_member_rec->mgid ); + if( p_item == cl_fmap_end( &p_port->endpt_mgr.gid_endpts ) ) + { + /* + * The endpoint must have been flushed while the join request + * was outstanding. Just leave the group and return. This + * is not an error. + */ + cl_obj_unlock( &p_port->obj ); + IPOIB_PRINT(TRACE_LEVEL_WARNING, IPOIB_DBG_ERROR, + ("Failed to find endpoint for update.\n") ); + + ipoib_port_ref(p_port, ref_leave_mcast); + p_port->p_adapter->p_ifc->leave_mcast( p_mcast_rec->h_mcast, + __leave_error_mcast_cb ); + ipoib_port_deref( p_port, ref_mcast_no_endpt ); + IPOIB_EXIT( IPOIB_DBG_MCAST ); + return; + } + + p_endpt = PARENT_STRUCT( p_item, ipoib_endpt_t, gid_item ); + p_endpt->p_ifc = p_port->p_adapter->p_ifc; + + /* Setup the endpoint for use. */ + status = ipoib_endpt_set_mcast( p_endpt, + p_port->ib_mgr.h_pd, + p_port->port_num, + p_mcast_rec ); + if( status != IB_SUCCESS ) + { + cl_obj_unlock( &p_port->obj ); + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_MCAST, + ("ipoib_endpt_set_mcast returned %s.\n", + p_port->p_adapter->p_ifc->get_err_str( status )) ); + /* Flag the adapter as hung. */ + p_port->p_adapter->hung = TRUE; + ipoib_port_deref( p_port, ref_mcast_av_failed ); + IPOIB_EXIT( IPOIB_DBG_MCAST ); + return; + } + + /* + * The endpoint is already in the GID and MAC maps. + * mast endpoint are not used in the LID map. + */ + CL_ASSERT(p_endpt->dlid == 0); + /* set flag that endpoint is use */ + p_endpt->is_in_use = TRUE; + cl_obj_unlock( &p_port->obj ); + + /* Try to send all pending sends. */ + cl_spinlock_acquire( &p_port->send_lock ); + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_MCAST, + ("Calling ipoib_port_resume from mcast_cb, xmit pending sends\n")); + ipoib_port_resume(p_port , FALSE); + cl_spinlock_release( &p_port->send_lock ); + + ipoib_port_deref( p_port, ref_join_mcast ); + + IPOIB_EXIT( IPOIB_DBG_MCAST ); +} + + +void +ipoib_leave_mcast_cb( + IN void *context ) +{ + ipoib_port_t *p_port; + + IPOIB_ENTER( IPOIB_DBG_MCAST ); + + p_port = (ipoib_port_t*)context; + + IPOIB_PRINT( TRACE_LEVEL_VERBOSE, IPOIB_DBG_MCAST, + ("p_port->mcast_cnt %d\n", p_port->mcast_cnt)); + + ipoib_port_deref( p_port, ref_leave_mcast); + //It happens + //ASSERT(p_port->mcast_cnt > 0); + cl_atomic_dec( &p_port->mcast_cnt); + + if(0 == p_port->mcast_cnt) + { + KeSetEvent( &p_port->leave_mcast_event, EVENT_INCREMENT, FALSE ); + } + + IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_MCAST, + ("Leave mcast callback deref ipoib_port \n") ); + + IPOIB_EXIT( IPOIB_DBG_MCAST ); +} + + + +void +__leave_error_mcast_cb( + IN void *context ) +{ + ipoib_port_t *p_port; + + IPOIB_ENTER( IPOIB_DBG_MCAST ); + + p_port = (ipoib_port_t*)context; + + ipoib_port_deref( p_port, ref_leave_mcast); + IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_MCAST, + ("Leave mcast callback deref ipoib_port \n") ); + + IPOIB_EXIT( IPOIB_DBG_MCAST ); +} + +/*++ +Routine Description: + The routine process the packet and returns LSO information + +Arguments: + pNetBuffer - a pointer to the first net buffer object of the packet + TcpHeaderOffset - offset to the begining of the TCP header in the packet + pLsoData - pointer to LsoData object in which the routine returns the LSO information + pHeaderSize - pointer to ULONG object in which the header size is returned + IndexOfData - + +Return Value: + NDIS_STATUS + +NOTE: + called at DISPATCH level +--*/ + +NDIS_STATUS GetLsoHeaderSize( + IN PNET_BUFFER pNetBuffer, + IN LsoData *pLsoData, + OUT UINT *IndexOfData, + IN ipoib_hdr_t *ipoib_hdr + ) +{ + UINT CurrLength; + PUCHAR pSrc; + PUCHAR pCopiedData = pLsoData->coppied_data; + ip_hdr_t UNALIGNED *IpHdr; + tcp_hdr_t UNALIGNED *TcpHdr; + uint16_t TcpHeaderLen; + uint16_t IpHeaderLen; + uint16_t IpOffset; + INT FullBuffers = 0; + PMDL pMDL; + NDIS_STATUS status = NDIS_STATUS_INVALID_PACKET; + + +#define IP_OFFSET 14; + // + // This Flag indicates the way we gets the headers + // RegularFlow = we get the headers (ETH+IP+TCP) in the same Buffer + // in sequence. + // + boolean_t IsRegularFlow = TRUE; + + const uint16_t ETH_OFFSET = IP_OFFSET; + + pLsoData->LsoHeaderSize = 0; + IpOffset = IP_OFFSET; //(uint16_t)pPort->EncapsulationFormat.EncapsulationHeaderSize; + *IndexOfData = 0; + + pMDL = NET_BUFFER_CURRENT_MDL(pNetBuffer); + NdisQueryMdl(pMDL, &pSrc, &CurrLength, NormalPagePriority); + + if (pSrc == NULL) { + IPOIB_PRINT(TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, ("Error processing packets\n")); + return status; + } + + ULONG DataOffset = NET_BUFFER_CURRENT_MDL_OFFSET(pNetBuffer); + pSrc += DataOffset; + CurrLength -= DataOffset; + + // We start by looking for the ethernet and the IP + if (CurrLength < ETH_OFFSET) { + IPOIB_PRINT(TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, ("Error porcessing packets\n")); + return status; + } + + //pLsoData->LsoHeaderSize = pLsoData->LsoHeaderSize + ETH_OFFSET; + if (CurrLength == ETH_OFFSET) { + ASSERT(FALSE); + IsRegularFlow = FALSE; + memcpy(pCopiedData, pSrc, ETH_OFFSET); + pCopiedData += ETH_OFFSET; + FullBuffers++; + // First buffer was only ethernet + pNetBuffer = NET_BUFFER_NEXT_NB(pNetBuffer); + NdisQueryMdl(NET_BUFFER_CURRENT_MDL(pNetBuffer), &pSrc, &CurrLength, NormalPagePriority); + if (pSrc == NULL) { + IPOIB_PRINT(TRACE_LEVEL_VERBOSE, IPOIB_DBG_ERROR, ("Error porcessing packets\n")); + return status; + } + } else { + // This is ETH + IP together (at least) + pLsoData->LsoBuffers[0].pData = pSrc + (ETH_OFFSET - sizeof (ipoib_hdr_t)); + + //IMPORTANT: we de-facto replace ETH header by IPoIB header here + memcpy (pLsoData->LsoBuffers[0].pData, ipoib_hdr, sizeof (ipoib_hdr_t)); + + CurrLength -= ETH_OFFSET; + pSrc = pSrc + ETH_OFFSET; + pLsoData->LsoHeaderSize = pLsoData->LsoHeaderSize + sizeof (ipoib_hdr_t); + } + // we should now be having at least the size of ethernet data + if (CurrLength < sizeof (ip_hdr_t)) { + IPOIB_PRINT(TRACE_LEVEL_VERBOSE, IPOIB_DBG_ERROR, ("Error porcessing packets\n")); + return status; + } + IpHdr = (ip_hdr_t UNALIGNED*)pSrc; + IpHeaderLen = (uint16_t)IP_HEADER_LENGTH(IpHdr); + ASSERT(IpHdr->prot == IP_PROT_TCP); + if (CurrLength < IpHeaderLen) { + IPOIB_PRINT(TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, ("Error processing packets\n")); + return status; + } + pLsoData->LsoHeaderSize = pLsoData->LsoHeaderSize + IpHeaderLen; + // We now start to find where the TCP header starts + if (CurrLength == IpHeaderLen) { + ASSERT(FALSE); + // two options : + // if(IsRegularFlow = FALSE) ==> ETH and IP seperated in two buffers + // if(IsRegularFlow = TRUE ) ==> ETH and IP in the same buffer + // TCP will start at next buffer + if(IsRegularFlow){ + memcpy(pCopiedData, pSrc-ETH_OFFSET ,ETH_OFFSET+IpHeaderLen); + pCopiedData += (ETH_OFFSET + IpHeaderLen); + } else { + memcpy(pCopiedData, pSrc,IpHeaderLen); + pCopiedData += IpHeaderLen; + } + + FullBuffers++; + IsRegularFlow = FALSE; + //NdisGetNextBuffer( CurrBuffer, &CurrBuffer); + //NdisQueryBufferSafe( CurrBuffer, &pSrc, &CurrLength, NormalPagePriority ); + pNetBuffer = NET_BUFFER_NEXT_NB(pNetBuffer); + NdisQueryMdl(NET_BUFFER_CURRENT_MDL(pNetBuffer), &pSrc, &CurrLength, NormalPagePriority); + if (pSrc == NULL) { + IPOIB_PRINT(TRACE_LEVEL_VERBOSE, IPOIB_DBG_ERROR, ("Error porcessing packets\n")); + return status; + } + } else { + // if(IsRegularFlow = TRUE ) ==> the ETH and IP and TCP in the same buffer + // if(IsRegularFlow = FLASE ) ==> ETH in one buffer , IP+TCP together in the same buffer + if (IsRegularFlow) { + pLsoData->LsoBuffers[0].Len += IpHeaderLen; + } else { + memcpy(pCopiedData, pSrc, IpHeaderLen); + pCopiedData += IpHeaderLen; + } + + CurrLength -= IpHeaderLen; + pSrc = pSrc + IpHeaderLen; + } + if (CurrLength < sizeof (tcp_hdr_t)) { + IPOIB_PRINT(TRACE_LEVEL_VERBOSE, IPOIB_DBG_ERROR, ("Error porcessing packets\n")); + return status; + } + // We have finaly found the TCP header + TcpHdr = (tcp_hdr_t UNALIGNED *)pSrc; + TcpHeaderLen = TCP_HEADER_LENGTH(TcpHdr); + + //ASSERT(TcpHeaderLen == 20); + + if (CurrLength < TcpHeaderLen) { + //IPOIB_PRINT(TRACE_LEVEL_VERBOSE, ETH, ("Error porcessing packets\n")); + return status; + } + pLsoData->LsoHeaderSize = pLsoData->LsoHeaderSize + TcpHeaderLen; + if(IsRegularFlow){ + pLsoData->LsoBuffers[0].Len += TcpHeaderLen; + } + else{ + memcpy(pCopiedData, pSrc, TcpHeaderLen); + pCopiedData += TcpHeaderLen; + } + if (CurrLength == TcpHeaderLen) { + FullBuffers++; + pLsoData->UsedBuffers = FullBuffers; + *IndexOfData = FullBuffers ; + } else { + pLsoData->UsedBuffers = FullBuffers + 1; + *IndexOfData = FullBuffers - 1; + } + pLsoData->FullBuffers = FullBuffers; + if (!IsRegularFlow){ + pLsoData->LsoBuffers[0].pData = pLsoData->coppied_data; + pLsoData->LsoBuffers[0].Len = ETH_OFFSET + IpHeaderLen + TcpHeaderLen; + ASSERT(pLsoData->LsoBuffers[0].Len <= LSO_MAX_HEADER); + } + return NDIS_STATUS_SUCCESS; +} + +static void __port_do_mcast_garbage(ipoib_port_t* const p_port) +{ + const mac_addr_t DEFAULT_MCAST_GROUP = {0x01, 0x00, 0x5E, 0x00, 0x00, 0x01}; + /* Do garbage collecting... */ + + cl_map_item_t *p_item; + ipoib_endpt_t *p_endpt; + cl_qlist_t destroy_mc_list; + uint8_t cnt; + const static GC_MAX_LEAVE_NUM = 80; + + cl_qlist_init( &destroy_mc_list ); + + cl_obj_lock( &p_port->obj ); + /* Wait for all readers to finish */ + while( p_port->endpt_rdr ) + { + cl_obj_unlock( &p_port->obj ); + cl_obj_lock( &p_port->obj ); + } + cnt = 0; + p_item = cl_qmap_head( &p_port->endpt_mgr.mac_endpts ); + while( (p_item != cl_qmap_end( &p_port->endpt_mgr.mac_endpts )) && (cnt < GC_MAX_LEAVE_NUM)) + { + p_endpt = PARENT_STRUCT( p_item, ipoib_endpt_t, mac_item ); + p_item = cl_qmap_next( p_item ); + + /* Check if the current endpoint is not a multicast listener */ + + if( p_endpt->h_mcast && + (!p_endpt->is_mcast_listener) && + ( cl_memcmp( &p_endpt->mac, &DEFAULT_MCAST_GROUP, sizeof(mac_addr_t) ) && + (!p_endpt->is_in_use) )) + { + cl_qmap_remove_item( &p_port->endpt_mgr.mac_endpts, + &p_endpt->mac_item ); + cl_fmap_remove_item( &p_port->endpt_mgr.gid_endpts, + &p_endpt->gid_item ); + + if( p_endpt->dlid ) + { + cl_qmap_remove_item( &p_port->endpt_mgr.lid_endpts, + &p_endpt->lid_item ); + p_endpt->dlid = 0; + } + + cl_qlist_insert_tail( + &destroy_mc_list, &p_endpt->mac_item.pool_item.list_item ); + cnt++; + } + else + p_endpt->is_in_use = FALSE; + } + cl_obj_unlock( &p_port->obj ); + + /* Destroy all multicast endpoints now that we have released the lock. */ + while( cl_qlist_count( &destroy_mc_list ) ) + { + p_endpt = PARENT_STRUCT( cl_qlist_remove_head( &destroy_mc_list ), + ipoib_endpt_t, mac_item.pool_item.list_item ); + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_ENDPT, + ("mcast garbage collector: destroying endpoint %02x:%02x:%02x:%02x:%02x:%02x \n", + p_endpt->mac.addr[0], + p_endpt->mac.addr[1], + p_endpt->mac.addr[2], + p_endpt->mac.addr[3], + p_endpt->mac.addr[4], + p_endpt->mac.addr[5]) ); + cl_obj_destroy( &p_endpt->obj ); + } +} + +static void __port_mcast_garbage_dpc(KDPC *p_gc_dpc,void *context,void *s_arg1, void *s_arg2) +{ + ipoib_port_t *p_port = (ipoib_port_t *) context; + + UNREFERENCED_PARAMETER(p_gc_dpc); + UNREFERENCED_PARAMETER(s_arg1); + UNREFERENCED_PARAMETER(s_arg2); + + __port_do_mcast_garbage(p_port); +} + +ipoib_endpt_t* +ipoib_endpt_get_by_gid( + IN ipoib_port_t* const p_port, + IN const ib_gid_t* const p_gid ) +{ + return __endpt_mgr_get_by_gid( p_port, p_gid ); +} + +ipoib_endpt_t* +ipoib_endpt_get_by_lid( + IN ipoib_port_t* const p_port, + IN const net16_t lid ) +{ + return __endpt_mgr_get_by_lid( p_port, lid ); +} + +ib_api_status_t +ipoib_recv_dhcp( + IN ipoib_port_t* const p_port, + IN const ipoib_pkt_t* const p_ipoib, + OUT eth_pkt_t* const p_eth, + IN ipoib_endpt_t* const p_src, + IN ipoib_endpt_t* const p_dst ) +{ + return __recv_dhcp( + p_port, p_ipoib, p_eth, p_src,p_dst ); +} + + +void +ipoib_port_cancel_xmit( + IN ipoib_port_t* const p_port, + IN PVOID cancel_id ) +{ + cl_list_item_t *p_item, *p_next; + ipoib_send_NB_SG *s_buf; + PVOID nbl_id; + cl_qlist_t cancel_list; + IPOIB_ENTER( IPOIB_DBG_SEND ); + + cl_qlist_init( &cancel_list ); + + ASSERT(FALSE); //TODO ???????????????? Do we reach here ???????????? + + cl_spinlock_acquire( &p_port->send_lock ); + + + + for( p_item = cl_qlist_head( &p_port->send_mgr.pending_list ); + p_item != cl_qlist_end( &p_port->send_mgr.pending_list ); + p_item = p_next ) + { + p_next = cl_qlist_next( p_item ); + s_buf = (ipoib_send_NB_SG*) (PVOID) p_item; // TODO: Check this casting + nbl_id = NDIS_GET_NET_BUFFER_LIST_CANCEL_ID( s_buf->p_nbl ); + if( nbl_id == cancel_id ) + { + cl_qlist_remove_item( &p_port->send_mgr.pending_list, p_item ); + NET_BUFFER_LIST_STATUS( s_buf->p_nbl) = NDIS_STATUS_REQUEST_ABORTED ; + cl_qlist_insert_tail( &cancel_list, (cl_list_item_t *) s_buf ); + } + } + cl_spinlock_release( &p_port->send_lock ); + + if( cl_qlist_count( &cancel_list ) ) + { + while( ( p_item = cl_qlist_remove_head( &cancel_list )) + != cl_qlist_end( &cancel_list )) + { + s_buf = (ipoib_send_NB_SG*) (PVOID) p_item; + IPOIB_DEC_NET_BUFFER_LIST_REF_COUNT(s_buf->p_nbl); + + + //TODO don't use DISPATCH LEVEL + __send_complete_net_buffer( s_buf, NDIS_STATUS_SEND_ABORTED, + NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL, TRUE); + } + + } + IPOIB_EXIT( IPOIB_DBG_SEND ); +} + +/* +* Put all fragments into separate WR and chain together. +* The last WR will be set to generate CQ Event. +* lookaside buffer is used for ipoib and ip headers attached to each WR. +* Buffer will be released on last WR send completion. +*/ +#if 0 +static NDIS_STATUS +__send_fragments( +IN ipoib_port_t* const p_port, +IN ipoib_send_desc_t* const p_desc, +IN eth_hdr_t* const p_eth_hdr, +IN ip_hdr_t* const p_ip_hdr, +IN uint32_t buf_len, +IN NDIS_BUFFER* p_ndis_buf ) +{ + uint32_t ds_idx = 1; + uint32_t wr_idx = 0; + uint32_t sgl_idx = 2; //skip eth hdr, ip hdr + uint32_t options_len = 0; + uint8_t* p_options = NULL; + uint8_t* p_buf; + uint32_t frag_offset = 0; + uint32_t next_sge; + uint32_t wr_size = 0; + uint32_t ip_hdr_len = IP_HEADER_LENGTH( p_ip_hdr ); + uint32_t total_ip_len = cl_ntoh16( p_ip_hdr->length ); + + SCATTER_GATHER_LIST *p_sgl; + + IPOIB_ENTER( IPOIB_DBG_SEND ); + + if( IP_DONT_FRAGMENT(p_ip_hdr) ) + return NDIS_STATUS_INVALID_PACKET; + + p_sgl = NDIS_PER_PACKET_INFO_FROM_PACKET( p_desc->p_pkt, ScatterGatherListPacketInfo ); + if( !p_sgl ) + { + ASSERT( p_sgl ); + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to get SGL from packet.\n") ); + return NDIS_STATUS_FAILURE; + } + if( ( p_sgl->NumberOfElements > MAX_SEND_SGE || + p_sgl->Elements[0].Length < sizeof(eth_hdr_t)) ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Too many SG Elements in packet.\n") ); + return NDIS_STATUS_FAILURE; + } + p_buf = (uint8_t *) + ExAllocateFromNPagedLookasideList( &p_port->buf_mgr.send_buf_list ); + if( !p_buf ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to allocate lookaside buffer.\n") ); + return NDIS_STATUS_RESOURCES; + } + s_buf->p_send_buf = (send_buf_t*)p_buf; + + if( buf_len < ip_hdr_len ) + { /* ip options in a separate buffer */ + CL_ASSERT( buf_len == sizeof( ip_hdr_t ) ); + NdisGetNextBuffer( p_ndis_buf, &p_ndis_buf ); + if( !p_ndis_buf ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to get IP options buffer.\n") ); + return NDIS_STATUS_FAILURE; + } + NdisQueryBufferSafe( p_ndis_buf, &p_options, &options_len, NormalPagePriority ); + if( !p_options ) + { + IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Failed to query IP options buffer address.\n") ); + return NDIS_STATUS_FAILURE; + } + cl_memcpy( p_buf, p_ip_hdr, sizeof( ip_hdr_t ) ); + if( p_options && options_len ) + { + __copy_ip_options( &p_buf[sizeof(ip_hdr_t)], + p_options, options_len, TRUE ); + } + wr_size = buf_len + options_len; + sgl_idx++; + } + else + { /*options probably in the same buffer */ + cl_memcpy( p_buf, p_ip_hdr, buf_len ); + options_len = ip_hdr_len - sizeof( ip_hdr_t ); + if( options_len ) + { + p_options = p_buf + sizeof( ip_hdr_t ); + } + frag_offset += ( buf_len - ip_hdr_len ); + wr_size = buf_len; + } + + p_desc->send_wr[wr_idx].local_ds[ds_idx].vaddr = cl_get_physaddr( p_buf ); + p_desc->send_wr[wr_idx].local_ds[ds_idx].lkey = p_port->ib_mgr.lkey; + p_desc->send_wr[wr_idx].local_ds[ds_idx].length = wr_size; + + /* count how much data can be put into the first WR beside IP header. + * other protocols headers possibly supplied in subsequent buffers. + */ + for( sgl_idx; sgl_idx < p_sgl->NumberOfElements; sgl_idx++ ) + { + next_sge = p_sgl->Elements[sgl_idx].Length; + + /* add sgl if it can fit into the same WR + * Note: so far not going to split large SGE between WRs, + * so first fragment could be a smaller size. + */ + if( next_sge <= ( p_port->p_adapter->params.payload_mtu - wr_size ) ) + { + ++ds_idx; + wr_size += next_sge; + frag_offset += next_sge; + p_desc->send_wr[wr_idx].local_ds[ds_idx].vaddr = + p_sgl->Elements[sgl_idx].Address.QuadPart; + p_desc->send_wr[wr_idx].local_ds[ds_idx].length = next_sge; + p_desc->send_wr[wr_idx].local_ds[ds_idx].lkey = p_port->ib_mgr.lkey; + } + else + { + /* fix ip hdr for the first fragment and move on */ + __update_fragment_ip_hdr( (ip_hdr_t* const)p_buf, + (uint16_t)wr_size, IP_FRAGMENT_OFFSET(p_ip_hdr), TRUE ); + + p_desc->send_wr[wr_idx].wr.num_ds = ds_idx + 1; + p_buf += ip_hdr_len; + p_buf += (( buf_len > ip_hdr_len ) ? ( buf_len - ip_hdr_len ): 0); + frag_offset += ( (IP_FRAGMENT_OFFSET(p_ip_hdr)) << 3 ); + ++wr_idx; + ds_idx = 0; + break; + } + } + total_ip_len -= wr_size; + wr_size = 0; + + for( sgl_idx, wr_idx; sgl_idx < p_sgl->NumberOfElements; sgl_idx++ ) + { + uint32_t seg_len; + uint64_t next_sgl_addr; + + if( wr_idx >= ( MAX_WRS_PER_MSG - 1 ) ) + return NDIS_STATUS_RESOURCES; + + next_sge = p_sgl->Elements[sgl_idx].Length; + next_sgl_addr = p_sgl->Elements[sgl_idx].Address.QuadPart; + + while( next_sge ) + { + if( ds_idx == 0 ) + { /* new ipoib + ip header */ + ((ipoib_hdr_t*)p_buf)->type = p_eth_hdr->type; + ((ipoib_hdr_t*)p_buf)->resv = 0; + p_desc->send_wr[wr_idx].local_ds[ds_idx].vaddr = cl_get_physaddr( p_buf ); + p_desc->send_wr[wr_idx].local_ds[ds_idx].lkey = p_port->ib_mgr.lkey; + p_desc->send_wr[wr_idx].local_ds[ds_idx].length = sizeof( ipoib_hdr_t ); + p_buf += sizeof( ipoib_hdr_t ); + ++ds_idx; + + cl_memcpy( p_buf, p_ip_hdr, sizeof( ip_hdr_t ) ); + if( p_options && options_len ) + { + /* copy ip options if needed */ + __copy_ip_options( &p_buf[sizeof(ip_hdr_t)], + p_options, options_len, FALSE ); + } + wr_size = ip_hdr_len; + } + if( ds_idx == 1 ) + { + p_desc->send_wr[wr_idx].local_ds[ds_idx].length = ip_hdr_len; + p_desc->send_wr[wr_idx].local_ds[ds_idx].vaddr = cl_get_physaddr( p_buf ); + p_desc->send_wr[wr_idx].local_ds[ds_idx].lkey = p_port->ib_mgr.lkey; + ++ds_idx; + } + + seg_len = ( next_sge > ( p_port->p_adapter->params.payload_mtu - wr_size ) )? + ( p_port->p_adapter->params.payload_mtu - wr_size ) : next_sge; + + p_desc->send_wr[wr_idx].local_ds[ds_idx].vaddr = next_sgl_addr; + p_desc->send_wr[wr_idx].local_ds[ds_idx].length = seg_len; + p_desc->send_wr[wr_idx].local_ds[ds_idx].lkey = p_port->ib_mgr.lkey; + ++ds_idx; + + wr_size += seg_len; + total_ip_len -= seg_len; + + if( wr_size >= p_port->p_adapter->params.payload_mtu || total_ip_len == 0 ) + { /* fix ip hdr for that fragment */ + __update_fragment_ip_hdr( (ip_hdr_t* const)p_buf, (uint16_t)wr_size, + ((uint16_t)(frag_offset >> 3 )), + (BOOLEAN)(( total_ip_len > 0 ) || IP_MORE_FRAGMENTS( p_ip_hdr)) ); + p_desc->send_wr[wr_idx].wr.num_ds = ds_idx; + if( total_ip_len > 0 ) + { + ++wr_idx; + frag_offset += (wr_size - ip_hdr_len); + wr_size = 0; + ds_idx = 0; + p_buf += ip_hdr_len; + } + } + next_sge -= seg_len; + if( next_sge > 0 ) + { + next_sgl_addr += seg_len; + } + } + } + p_desc->num_wrs += wr_idx; + + IPOIB_EXIT( IPOIB_DBG_SEND ); + return NDIS_STATUS_SUCCESS; +} + + +static void +__update_fragment_ip_hdr( +IN ip_hdr_t* const p_ip_hdr, +IN uint16_t fragment_size, +IN uint16_t fragment_offset, +IN BOOLEAN more_fragments ) +{ + uint16_t* p_hdr = (uint16_t*)p_ip_hdr; + p_ip_hdr->length = cl_hton16( fragment_size ); // bytes + p_ip_hdr->offset = cl_hton16( fragment_offset ); // 8-byte units + if( more_fragments ) + { + IP_SET_MORE_FRAGMENTS( p_ip_hdr ); + } + else + { + IP_SET_LAST_FRAGMENT( p_ip_hdr ); + } + p_ip_hdr->chksum = 0; + p_ip_hdr->chksum = ipchksum( p_hdr, IP_HEADER_LENGTH(p_ip_hdr) ); +} + +static void +__copy_ip_options( +IN uint8_t* p_buf, +IN uint8_t* p_options, +IN uint32_t options_len, +IN BOOLEAN copy_all ) +{ + uint32_t option_length; + uint32_t total_length = 0; + uint32_t copied_length = 0; + uint8_t* p_src = p_options; + uint8_t* p_dst = p_buf; + + if( p_options == NULL || options_len == 0 ) + return; + if( copy_all ) + { + cl_memcpy( p_dst, p_src, options_len ); + return; + } + do + { + if( ( *p_src ) == 0 ) // end of options list + { + total_length++; + break; + } + if( ( *p_src ) == 0x1 ) // no op + { + p_src++; + total_length++; + continue; + } + /*from RFC791: + * This option may be used between options, for example, to align + * the beginning of a subsequent option on a 32 bit boundary. + */ + if( copied_length && (copied_length % 4) ) + { + uint32_t align = 4 - (copied_length % 4); + cl_memset( p_dst, 0x1, (size_t)align ); + p_dst += align; + copied_length += align; + } + option_length = *(p_src + 1); + + if( *p_src & 0x80 ) + { + cl_memcpy( p_dst, p_src, option_length ); + p_dst += option_length; + copied_length += option_length; + } + total_length += option_length; + p_src += option_length; + + }while( total_length < options_len ); + + CL_ASSERT( total_length == options_len ); + CL_ASSERT( copied_length <= 40 ); + + /* padding the rest */ + if( options_len > copied_length ) + { + cl_memclr( p_dst, ( options_len - copied_length ) ); + } + return; +} +#endif diff --git a/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_port.h b/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_port.h new file mode 100644 index 00000000..b646e06a --- /dev/null +++ b/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_port.h @@ -0,0 +1,940 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2006 Mellanox Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: ipoib_port.h 4226 2009-04-06 06:01:03Z xalex $ + */ + + + +#ifndef _IPOIB_PORT_H_ +#define _IPOIB_PORT_H_ + + +#include +#include +#include +#include +#include +#include "ipoib_xfr_mgr.h" +#include "ipoib_endpoint.h" + + +/* + * Define to place receive buffer inline in receive descriptor. + */ +#define IPOIB_INLINE_RECV 1 + +/* + * Invalid pkey index + */ +#define PKEY_INVALID_INDEX 0xFFFF + +/* + * Define to control how transfers are done. When defined as 1, causes + * packets to be sent using NDIS DMA facilities (getting the SGL from the + * packet). When defined as 0, uses the NDIS_BUFFER structures as MDLs + * to get the physical page mappings of the buffers. + */ +#define IPOIB_USE_DMA 1 + +//Used in RECV flow +#define IPOIB_PORT_FROM_NBL( P ) \ + (((ipoib_port_t**)NET_BUFFER_LIST_MINIPORT_RESERVED(P))[1]) + +//Used in RECV flow +#define IPOIB_RECV_FROM_NBL( P ) \ + (((ipoib_recv_desc_t**)NET_BUFFER_LIST_MINIPORT_RESERVED(P))[0]) + +//Used in CM SEND flow - to update +#define IPOIB_LIST_ITEM_FROM_NBL( P ) \ + ((cl_list_item_t*)NET_BUFFER_LIST_MINIPORT_RESERVED(P)) + +//Used in SEND flow +#define IPOIB_INFO_FROM_NB( P ) \ + (((ipoib_send_NB_SG **)NET_BUFFER_MINIPORT_RESERVED(P))[0]) + +//#define IPOIB_TCP_PAYLOAD_FROM_NB( P ) \ +// (((UINT *)NET_BUFFER_MINIPORT_RESERVED(P))[1]) + + +//Used in SEND flow +#define IPOIB_GET_NET_BUFFER_LIST_REF_COUNT(_NetBufferList) \ + ((_NetBufferList)->MiniportReserved[0]) + +#define IPOIB_DEC_NET_BUFFER_LIST_REF_COUNT(_NetBufferList) \ + (*(PULONG)&(_NetBufferList)->MiniportReserved[0])-- + + + +typedef struct _ipoib_ib_mgr +{ + ib_ca_handle_t h_ca; + ib_pd_handle_t h_pd; + ib_cq_handle_t h_recv_cq; + ib_cq_handle_t h_send_cq; + ib_qp_handle_t h_qp; + ib_query_handle_t h_query; + ib_srq_handle_t h_srq; + net32_t qpn; + + ib_mr_handle_t h_mr; + net32_t lkey; + + uint8_t rate; + ib_member_rec_t bcast_rec; + +} ipoib_ib_mgr_t; +/* +* FIELDS +* h_ca +* CA handle for all IB resources. +* +* h_pd +* PD handle for all IB resources. +* +* h_recv_cq +* Recv CQ handle. +* +* h_send_cq +* Send CQ handle. +* +* h_qp +* QP handle for data transfers. +* +* h_query +* Query handle for cancelling SA queries. +* +* h_mr +* Registration handle for all of physical memory. Used for +* send/receive buffers to simplify growing the receive pool. +* +* lkey +* LKey for the memory region. +* +* bcast_rec +* Cached information about the broadcast group, used to specify +* parameters used to join other multicast groups. +*********/ + + +#include +/****s* IPoIB Driver/ipoib_hdr_t +* NAME +* ipoib_hdr_t +* +* DESCRIPTION +* IPoIB packet header. +* +* SYNOPSIS +*/ +typedef struct _ipoib_hdr +{ + net16_t type; + net16_t resv; + +} PACK_SUFFIX ipoib_hdr_t; +/* +* FIELDS +* type +* Protocol type. +* +* resv +* Reserved portion of IPoIB header. +*********/ + +typedef struct _ipoib_arp_pkt +{ + net16_t hw_type; + net16_t prot_type; + uint8_t hw_size; + uint8_t prot_size; + net16_t op; + ipoib_hw_addr_t src_hw; + net32_t src_ip; + ipoib_hw_addr_t dst_hw; + net32_t dst_ip; + +} PACK_SUFFIX ipoib_arp_pkt_t; + + +/****s* IPoIB Driver/ipoib_pkt_t +* NAME +* ipoib_pkt_t +* +* DESCRIPTION +* Represents an IPoIB packet with no GRH. +* +* SYNOPSIS +*/ +typedef struct _ipoib_pkt +{ + ipoib_hdr_t hdr; + union _payload + { + uint8_t data[MAX_UD_PAYLOAD_MTU]; + ipoib_arp_pkt_t arp; + ip_pkt_t ip; + + } PACK_SUFFIX type; + +} PACK_SUFFIX ipoib_pkt_t; +/* +* FIELDS +* hdr +* IPoIB header. +* +* type +* Union for different types of payloads. +* +* type.data +* raw packet. +* +* type.ib_arp +* IPoIB ARP packet. +* +* type.arp +* Ethernet ARP packet. +* +* type.ip +* IP packet. +*********/ + + +/****s* IPoIB Driver/recv_buf_t +* NAME +* recv_buf_t +* +* DESCRIPTION +* Represents a receive buffer, including the ethernet header +* used to indicate the receive to the OS. +* +* SYNOPSIS +*/ +typedef union _recv_buf +{ + struct _recv_buf_type_eth + { + uint8_t pad[sizeof(ib_grh_t) + + sizeof(ipoib_hdr_t) - + sizeof(eth_hdr_t)]; + eth_pkt_t pkt; /* data starts at sizeof(grh)+sizeof(eth_hdr) */ + + } PACK_SUFFIX eth; + + struct _recv_buf_type_ib + { + ib_grh_t grh; /* Must be same offset as lcl_rt.ib.pkt */ + ipoib_pkt_t pkt; /* data starts at 10+grh+4 */ + + } PACK_SUFFIX ib; + +} PACK_SUFFIX recv_buf_t; +/* +* FIELDS +* eth.pkt +* Ethernet packet, used to indicate the receive to the OS. +* +* ib.grh +* GRH for a globally routed received packet. +* +* ib.pkt +* IPOIB packet representing a globally routed received packet. +* +* NOTES +* When posting the work request, the address of ib.grh is used. +* +* TODO: Do we need a pad to offset the header so that the data ends up +* aligned on a pointer boundary? +*********/ + +/****s* IPoIB Driver/send_buf_t +* NAME +* send_buf_t +* +* DESCRIPTION +* Represents a send buffer, used to convert packets to IPoIB format. +* +* SYNOPSIS +*/ +typedef union _send_buf +{ + uint8_t data[MAX_LSO_PAYLOAD_MTU]; + ipoib_arp_pkt_t arp; + ip_pkt_t ip; + +} PACK_SUFFIX send_buf_t; +/* +* FIELDS +* data +* IP/ARP packet. +* +* NOTES +* TODO: Do we need a pad to offset the header so that the data ends up +* aligned on a pointer boundary? +*********/ +#include + + +typedef struct _ipoib_buf_mgr +{ + cl_qpool_t recv_pool; + + NDIS_HANDLE h_packet_pool; + NDIS_HANDLE h_buffer_pool; + + NPAGED_LOOKASIDE_LIST send_buf_list; + NDIS_HANDLE h_send_pkt_pool; + + +} ipoib_buf_mgr_t; +/* +* FIELDS +* recv_pool +* Pool of ipoib_recv_desc_t structures. +* +* h_packet_pool +* NDIS packet pool, used to indicate receives to NDIS. +* +* h_buffer_pool +* NDIS buffer pool, used to indicate receives to NDIS. +* +* send_buf_list +* Lookaside list for dynamically allocating send buffers for send +* that require copies (ARP, DHCP, and any with more physical pages +* than can fit in the local data segments). +*********/ + +typedef enum _ipoib_pkt_type +{ + PKT_TYPE_UCAST, + PKT_TYPE_BCAST, + PKT_TYPE_MCAST, + PKT_TYPE_CM_UCAST + +} ipoib_pkt_type_t; + +typedef struct _ipoib_cm_desc +{ + cl_pool_item_t item; /* Must be first. */ + uint32_t len; + ipoib_pkt_type_t type; + ib_recv_wr_t wr; + ib_local_ds_t local_ds[2]; + cl_list_item_t list_item; + uint8_t* p_alloc_buf; + uint8_t* p_buf; + uint32_t alloc_buf_size; + uint32_t buf_size; + net32_t lkey; + ib_mr_handle_t h_mr; + NDIS_TCP_IP_CHECKSUM_PACKET_INFO ndis_csum; + +} ipoib_cm_desc_t; + +typedef struct _ipoib_recv_desc +{ + cl_pool_item_t item; /* Must be first. */ + uint32_t len; + ipoib_pkt_type_t type; + ib_recv_wr_t wr; + ib_local_ds_t local_ds[2]; + NDIS_TCP_IP_CHECKSUM_PACKET_INFO ndis_csum; +#if IPOIB_INLINE_RECV + recv_buf_t buf; +#else + recv_buf_t *p_buf; +#endif + +} ipoib_recv_desc_t; +/* +* FIELDS +* item +* Pool item for storing descriptors in a pool. +* +* len +* Length to indicate to NDIS. This is different than the length of the +* received data as some data is IPoIB specific and filtered out. +* +* type +* Type of packet, used in filtering received packets against the packet +* filter. Also used to update stats. +* +* wr +* Receive work request. +* +* local_ds +* Local data segments. The second segment is only used if a buffer +* spans physical pages. +* +* buf +* Buffer for the receive. +* +* NOTES +* The pool item is always first to allow casting form a cl_pool_item_t or +* cl_list_item_t to the descriptor. +*********/ + + +typedef struct __ipoib_send_wr +{ + ib_send_wr_t wr; + ib_local_ds_t local_ds[MAX_SEND_SGE]; /* Must be last. */ +} ipoib_send_wr_t; + +typedef enum __send_dir +{ + SEND_UD_QP = 1, + SEND_RC_QP = 2 +} send_dir_t; + +typedef struct _ipoib_send_desc +{ + PNET_BUFFER_LIST p_netbuf_list; + ipoib_endpt_t *p_endpt; + //send_buf_t *p_buf; // This field migrated to ipoib_send_NB_SG class + ib_qp_handle_t send_qp; + send_dir_t send_dir; + uint32_t num_wrs; + ipoib_send_wr_t send_wr[MAX_WRS_PER_MSG]; + +} ipoib_send_desc_t; +/* +* FIELDS +* p_pkt +* Pointer to the NDIS_PACKET associated with the send operation. +* +* p_endpt +* Endpoint for this send. +* +* p_buf +* Buffer for the send, if allocated. +* +* wr +* Send work request. +* +* pkt_hdr +* IPoIB packet header, pointed to by the first local datasegment. +* +* local_ds +* Local data segment array. Placed last to allow allocating beyond the +* end of the descriptor for additional datasegments. +* +* NOTES +* The pool item is always first to allow casting form a cl_pool_item_t or +* cl_list_item_t to the descriptor. +*********/ + + +typedef struct _ipoib_recv_mgr +{ + int32_t depth; + NET_BUFFER_LIST **recv_NBL_array; + cl_qlist_t done_list; + +} ipoib_recv_mgr_t; +/* +* FIELDS +* depth +* Current number of RX WRs posted. +* +* recv_NBL_array +* Array of NBLs (NET_BUFFER_LIST) pointers used to indicate receives. +* +* done_list +* List of receive descriptors (ipoib_desc_t) polled from the RX CQ which +* are used to construct the recv_NBL_array, which is then used to indicated +* received packets to NDIS 6. +*********/ + +#if 0 +class ItemListElement: public cl_list_item_t { + public: + ItemListElement() : p_port(NULL), p_nbl(NULL), p_curr_nbl(NULL) {}; + virtual ~ItemListElement() {}; + + ipoib_port_t *p_port; + PNET_BUFFER_LIST p_nbl; + PNET_BUFFER p_curr_nb; +} + +class ItemList { + //friend PendingListElement; + public: + + ItemList(ULONG size): _size(size), _cnt(0) { + item_array = new ItemListItem(size); + RtlSecureZeroMemory(item_array, sizeof (item_array)); + } + + virtual ~PendingList() { free(item_array); } ; + + ItemListElement * + GetListElement() { + if (_cnt == _size) { + cl_dbg_out("Out of memory!\n"); + return NULL; + } + return item_array[cnt_++]; + } + + void + PutListElement ( /*PendingListElement * list_elem*/) { + //ASSERT(list_elem.p_list == list + RtlSecureZeroMemory(&list_elem[_cnt], sizeof (ItemListElement)); + ASSERT(_cnt > 0); + --_cnt; + + } + + + private: + ULONG _size; + ULONG _cnt; + ItemListItem *item_array; +} + + +static const ULONG ItemListPoolSize(500); +#endif + + + + +typedef struct _ipoib_send_mgr +{ + atomic32_t depth; + cl_qlist_t pending_list; + ipoib_send_desc_t desc; + cl_qpool_t send_pool; + cl_qpool_t sg_pool; + +} ipoib_send_mgr_t; + + + +/* +* FIELDS +* depth +* Current number of WRs posted, used to queue pending requests. +* +* pending_list +* List of NDIS_PACKET structures that are awaiting available WRs to send. +*********/ + + +typedef struct _ipoib_endpt_mgr +{ + cl_qmap_t mac_endpts; + cl_fmap_t gid_endpts; + cl_qmap_t lid_endpts; + cl_fmap_t conn_endpts; + LIST_ENTRY pending_conns; + LIST_ENTRY remove_conns; + NDIS_SPIN_LOCK conn_lock; + NDIS_SPIN_LOCK remove_lock; + cl_thread_t h_thread; + cl_event_t event; + uint32_t thread_is_done; +} ipoib_endpt_mgr_t; +/* +* FIELDS +* mac_endpts +* Map of enpoints, keyed by MAC address. +* +* gid_endpts +* Map of enpoints, keyed by GID. +* +* lid_endpts +* Map of enpoints, keyed by LID. Only enpoints on the same subnet +* are inserted in the LID map. +* +* conn_endpts +* Map of connected endpts, keyed by remote gid. +*********/ + +#pragma warning(disable:4324) // structure padded due to align() +typedef struct _ipoib_port +{ + cl_obj_t obj; + cl_obj_rel_t rel; + + ib_qp_state_t state; + + cl_spinlock_t recv_lock; + cl_spinlock_t send_lock; + + struct _ipoib_adapter *p_adapter; + uint8_t port_num; + + KEVENT sa_event; + + atomic32_t mcast_cnt; + KEVENT leave_mcast_event; + + ipoib_ib_mgr_t ib_mgr; + + ipoib_buf_mgr_t buf_mgr; + + ipoib_recv_mgr_t recv_mgr; + ipoib_send_mgr_t send_mgr; + ipoib_send_desc_t * p_desc; + + ipoib_endpt_mgr_t endpt_mgr; + endpt_buf_mgr_t cm_buf_mgr; + endpt_recv_mgr_t cm_recv_mgr; + + ipoib_endpt_t *p_local_endpt; + ib_ca_attr_t *p_ca_attrs; +#if DBG + atomic32_t ref[ref_array_size]; +#endif + + atomic32_t endpt_rdr; + + atomic32_t hdr_idx; + uint16_t pkey_index; + KDPC gc_dpc; + KTIMER gc_timer; + uint32_t bc_join_retry_cnt; + ib_net16_t base_lid; + LONG n_no_progress; + PIO_WORKITEM pPoWorkItem; + ipoib_hdr_t hdr[1]; /* Must be last! */ + +} ipoib_port_t; +#pragma warning(default:4324) + +/* +* FIELDS +* obj +* Complib object for reference counting, relationships, +* and destruction synchronization. +* +* rel +* Relationship to associate the port with the adapter. +* +* state +* State of the port object. Tracks QP state fairly closely. +* +* recv_lock +* Spinlock to protect receive operations. +* +* send_lock +* Spinlock to protect send operations. +* +* p_adapter +* Parent adapter. Used to get AL handle. +* +* port_num +* Port number of this adapter. +* +* ib_mgr +* IB resource manager. +* +* recv_mgr +* Receive manager. +* +* send_mgr +* Send manager. +* +* endpt_mgr +* Endpoint manager. +*********/ +typedef struct _sgl_context +{ + MDL *p_mdl; + NET_BUFFER_LIST *p_netbuffer_list; + ipoib_port_t *p_port; +}sgl_context_t; + +#if 0 + +class ipoib_send_NB_SG: public cl_pool_item_t{ +public: + + ipoib_send_NB_SG(): p_port(NULL), p_nbl (NULL), p_curr_nb(NULL), p_endpt(NULL), p_send_buf(NULL), p_sgl(NULL) {}; + virtual ~ipoib_send_NB_SG(); +#endif + +typedef struct ipoib_send_NB_SG_t { +//private: //TODO make data private + cl_pool_item_t pool_item; + ipoib_port_t *p_port; + PNET_BUFFER_LIST p_nbl; + PNET_BUFFER p_curr_nb; + ipoib_endpt_t *p_endpt; + send_buf_t *p_send_buf; + PSCATTER_GATHER_LIST p_sgl; + UINT tcp_payload; + PVOID p_sg_buf; +} ipoib_send_NB_SG; + +ib_api_status_t +ipoib_create_port( + IN struct _ipoib_adapter* const p_adapter, + IN ib_pnp_port_rec_t* const p_pnp_rec, + OUT ipoib_port_t** const pp_port ); + +void +ipoib_port_destroy( + IN ipoib_port_t* const p_port ); + +void +ipoib_port_up( + IN ipoib_port_t* const p_port, + IN const ib_pnp_port_rec_t* const p_pnp_rec ); + +void +ipoib_port_down( + IN ipoib_port_t* const p_port ); + +ib_api_status_t +ipoib_port_join_mcast( + IN ipoib_port_t* const p_port, + IN const mac_addr_t mac, + IN const uint8_t state ); + + +void +ipoib_leave_mcast_cb( + IN void *context ); + + +void +ipoib_port_remove_endpt( + IN ipoib_port_t* const p_port, + IN const mac_addr_t mac ); + +void +ipoib_port_send( + IN ipoib_port_t* const p_port, + IN NET_BUFFER_LIST *net_buffer_list, + IN ULONG send_flags ); + +void +ipoib_return_net_buffer_list( + IN NDIS_HANDLE adapter_context, + IN PNET_BUFFER_LIST p_netbuffer_lists, + IN ULONG return_flags); + +void +ipoib_port_resume( + IN ipoib_port_t* const p_port, + IN boolean_t b_pending ); + +NTSTATUS +ipoib_mac_to_gid( + IN ipoib_port_t* const p_port, + IN const mac_addr_t mac, + OUT ib_gid_t* p_gid ); + +NTSTATUS +ipoib_mac_to_path( + IN ipoib_port_t* const p_port, + IN const mac_addr_t mac, + OUT ib_path_rec_t* p_path ); + +void +ipoib_process_sg_list( + IN PDEVICE_OBJECT pDO, + IN PVOID pIrp, + IN PSCATTER_GATHER_LIST pSGList, + IN PVOID Context); + +inline void ipoib_port_ref( + IN ipoib_port_t * p_port, + IN int type); + +inline void ipoib_port_deref( + IN ipoib_port_t * p_port, + IN int type); + +#if 0 +// This function is only used to monitor send failures +static inline VOID NdisMSendCompleteX( + IN NDIS_HANDLE MiniportAdapterHandle, + IN PNDIS_PACKET Packet, + IN NDIS_STATUS Status + ) { + if (Status != NDIS_STATUS_SUCCESS) { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Sending status other than Success to NDIS\n")); + } + NdisMSendComplete(MiniportAdapterHandle,Packet,Status); +} +#else +//#define NdisMSendCompleteX NdisMSendComplete +#endif + +ipoib_endpt_t* +ipoib_endpt_get_by_gid( + IN ipoib_port_t* const p_port, + IN const ib_gid_t* const p_gid ); + +ipoib_endpt_t* +ipoib_endpt_get_by_lid( + IN ipoib_port_t* const p_port, + IN const net16_t lid ); + +ib_api_status_t +ipoib_port_srq_init( + IN ipoib_port_t* const p_port ); + +void +ipoib_port_srq_destroy( + IN ipoib_port_t* const p_port ); + +#if 0 //CM +ib_api_status_t +ipoib_port_listen( + IN ipoib_port_t* const p_port ); + +ib_api_status_t +ipoib_port_cancel_listen( + IN ipoib_port_t* const p_port, + IN ipoib_endpt_t* const p_endpt ) { + UNUSED_PARAM(p_port); + UNUSED_PARAM(p_endpt); + return IB_SUCCESS; +} +#endif + +ib_api_status_t +endpt_cm_buf_mgr_init( + IN ipoib_port_t* const p_port ); + +void +endpt_cm_buf_mgr_destroy( + IN ipoib_port_t* const p_port ); + +void +endpt_cm_buf_mgr_reset( + IN ipoib_port_t* const p_port ); + +void +endpt_cm_buf_mgr_put_recv( + IN endpt_buf_mgr_t * const p_buf_mgr, + IN ipoib_cm_desc_t* const p_desc ); + +void +endpt_cm_buf_mgr_put_recv_list( + IN endpt_buf_mgr_t * const p_buf_mgr, + IN cl_qlist_t* const p_list ); + +uint32_t +endpt_cm_recv_mgr_build_pkt_array( + IN ipoib_port_t* const p_port, + IN ipoib_endpt_t* const p_endpt, + IN cl_qlist_t* const p_done_list, + IN OUT uint32_t* p_bytes_recv ); + +ib_api_status_t +endpt_cm_post_recv( + IN ipoib_port_t* const p_port ); + +/*void +endpt_cm_destroy_conn( + IN ipoib_port_t* const p_port, + IN ipoib_endpt_t* const p_endpt ); +*/ +void +endpt_cm_disconnect( + IN ipoib_port_t* const p_port, + IN ipoib_endpt_t* const p_endpt ); +void +endpt_cm_flush_recv( + IN ipoib_port_t* const p_port, + IN ipoib_endpt_t* const p_endpt ); + +ib_api_status_t +ipoib_recv_dhcp( + IN ipoib_port_t* const p_port, + IN const ipoib_pkt_t* const p_ipoib, + OUT eth_pkt_t* const p_eth, + IN ipoib_endpt_t* const p_src, + IN ipoib_endpt_t* const p_dst ); + +void +ipoib_port_cancel_xmit( + IN ipoib_port_t* const p_port, + IN PVOID cancel_id ); + +static inline uint32_t +__port_attr_to_mtu_size(uint32_t value) +{ + switch (value) + { + default: + case IB_MTU_LEN_2048: + return 2048; + case IB_MTU_LEN_4096: + return 4096; + case IB_MTU_LEN_1024: + return 1024; + case IB_MTU_LEN_512: + return 512; + case IB_MTU_LEN_256: + return 256; + } +} + + + + + +// This function is only used to monitor send failures +extern ULONG g_NBL_complete; +extern ULONG g_NBL; + +static inline VOID NdisMSendNetBufferListsCompleteX( + IN ipoib_adapter_t* p_adapter, + IN PNET_BUFFER_LIST NetBufferLists, + IN ULONG SendCompleteFlags + ) +{ + ++g_NBL_complete; + ipoib_cnt_inc( &p_adapter->n_send_NBL_done ); + +#ifdef DBG + ASSERT(NET_BUFFER_LIST_NEXT_NBL(NetBufferLists) == NULL); + + if (NET_BUFFER_LIST_STATUS(NetBufferLists) != NDIS_STATUS_SUCCESS) { + IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_ALL, + ("NBL completed with error %d to NDIS\n", + NET_BUFFER_LIST_STATUS(NetBufferLists))); + } + IPOIB_PRINT( TRACE_LEVEL_VERBOSE, IPOIB_DBG_SEND, + ("Completing NBL=%x, g_NBL=%d, g_NBL_completed=%d \n", NetBufferLists, g_NBL, g_NBL_complete) ); +#endif + + NdisMSendNetBufferListsComplete(p_adapter->h_adapter,NetBufferLists,SendCompleteFlags); +} + +#endif /* _IPOIB_PORT_H_ */ diff --git a/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_stat.cpp b/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_stat.cpp new file mode 100644 index 00000000..d38934b7 --- /dev/null +++ b/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_stat.cpp @@ -0,0 +1,36 @@ +#include "precompile.h" + +#if defined (EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "ipoib_stat.tmh" +#endif + +IPOIB_ST_STAT g_stat; + +void ipoib_st_dev_rmv( PIPOIB_ST_DEVICE p_stat ) +{ + if ( p_stat ) + p_stat->valid = FALSE; +} + +PIPOIB_ST_DEVICE ipoib_st_dev_add() +{ + int i; + + for ( i = 0; i < IPOIB_ST_MAX_DEVICES; ++i ) { + if ( g_stat.dev[i].valid == FALSE ) { + g_stat.dev[i].valid = TRUE; + return &g_stat.dev[i]; + } + } + + return NULL; +} + +void ipoib_st_init() +{ + memset( &g_stat, 0, sizeof(g_stat) ); +} + diff --git a/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_stat.h b/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_stat.h new file mode 100644 index 00000000..8f2fa274 --- /dev/null +++ b/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_stat.h @@ -0,0 +1,79 @@ +/*++ + +Copyright (c) 2005-2009 Mellanox Technologies. All rights reserved. + +Module Name: + ipoib_stat.h + +Abstract: + Statistics Collector header file + +Revision History: + +Notes: + +--*/ + +#pragma once + +#include + +// +// restrictions +// + +#define IPOIB_ST_MAX_DEVICES 16 + +// +// enums +// + +// +// structures +// + +// device +typedef struct _ipoib_adapter ipoib_adapter_t; +typedef struct _ipoib_port ipoib_port_t; + +typedef struct _IPOIB_ST_DEVICE +{ + boolean_t valid; // all the structure is valid + ipoib_adapter_t *p_adapter; // current + ipoib_port_t *p_prev_port; // previous value of p_port in p_adapter + PRKTHREAD p_halt_thread; // thread, calling ipoib_halt + int n_power_irps; // NdisDevicePnPEventPowerProfileChanged + int n_pnp_irps; // NdisDevicePnPEventSurpriseRemoved + +} IPOIB_ST_DEVICE, *PIPOIB_ST_DEVICE; + +// driver +typedef struct _IPOIB_ST_DRIVER +{ + PDRIVER_OBJECT obj; + +} IPOIB_ST_DRIVER, *PIPOIB_ST_DRIVER; + +// driver stack + +typedef struct _IPOIB_ST_STAT +{ + IPOIB_ST_DRIVER drv; + IPOIB_ST_DEVICE dev[IPOIB_ST_MAX_DEVICES]; + +} IPOIB_ST_STAT, *PIPOIB_ST_STAT; + +extern IPOIB_ST_STAT g_stat; + +// +// functions +// + +void ipoib_st_dev_rmv( PIPOIB_ST_DEVICE p_stat ); + +PIPOIB_ST_DEVICE ipoib_st_dev_add(); + +void ipoib_st_init(); + + + diff --git a/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_xfr_mgr.cpp b/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_xfr_mgr.cpp new file mode 100644 index 00000000..52805dac --- /dev/null +++ b/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_xfr_mgr.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2008 Mellanox Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: ipoib_xfr_mgr.c 3459 2008-11-12 16:48:21Z tzachid $ + */ + + +#include + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "ipoib_xfr_mgr.tmh" +#endif + + +const ipoib_guid2mac_translation_t guid2mac_table[] = { + {0x30, 0x48, 0xE7}, + {0x05, 0xAD, 0xE7}, + {0x18, 0x8B, 0xE7}, + {0x1A, 0x4B, 0xE7}, + {0x17, 0x08, 0xE7}, + {0x1E, 0x0B, 0xE7}, + + {0x03, 0xBA, 0xE7}, + {0x05, 0xAD, 0xE7}, + {0x0D, 0x9D, 0xE7}, + {0x11, 0x0A, 0xE7}, + {0x11, 0x85, 0xE7}, + {0x12, 0x79, 0xE7}, + {0x13, 0x21, 0xE7}, + {0x14, 0x38, 0xE7}, + {0x16, 0x35, 0xE7}, + {0x17, 0x08, 0xE7}, + {0x17, 0xA4, 0xE7}, + {0x18, 0x8B, 0xE7}, + {0x18, 0xFE, 0xE7}, + {0x19, 0xBB, 0xE7}, + {0x1A, 0x4B, 0xE7}, + {0x1B, 0x78, 0xE7}, + {0x1E, 0x0B, 0xE7}, + {0x22, 0x64, 0xE7}, + {0x23, 0x7D, 0xE7}, + {0x25, 0x90, 0xE7}, + {0x30, 0x48, 0xE7}, + {0x80, 0x5F, 0xE7}, + + {0x00, 0x00, 0x00}, +}; + diff --git a/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_xfr_mgr.h b/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_xfr_mgr.h new file mode 100644 index 00000000..9e38b609 --- /dev/null +++ b/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/ipoib_xfr_mgr.h @@ -0,0 +1,513 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: ipoib_xfr_mgr.h 3719 2009-01-07 12:31:52Z reuven $ + */ + + +#ifndef _IPOIB_XFR_MGR_H_ +#define _IPOIB_XFR_MGR_H_ + + +#include +#include +#include +#include +#include +#include +#include + + +#include "ipoib_driver.h" +#include "ip_stats.h" +#include + + +#include +/****s* IPoIB Driver/ipoib_hw_addr_t +* NAME +* ipoib_hw_addr_t +* +* DESCRIPTION +* The ipoib_hw_addr_t structure defines an IPoIB compatible hardware +* address. Values in this structure are stored in network order. +* +* SYNOPSIS +*/ +typedef struct _ipoib_hw_addr +{ + uint32_t flags_qpn; + ib_gid_t gid; + +} PACK_SUFFIX ipoib_hw_addr_t; +/* +* FIELDS +* flags_qpn +* Flags and queue pair number. Use ipoib_addr_get_flags, +* ipoib_addr_set_flags, ipoib_addr_set_qpn, and ipoib_addr_get_qpn +* to manipulate the contents. +* +* gid +* IB GID value. +* +* SEE ALSO +* IPoIB, ipoib_addr_get_flags, ipoib_addr_set_flags, ipoib_addr_set_qpn, +* ipoib_addr_get_qpn +*********/ +#include + +/****s* IPoIB Driver/ipoib_guid2mac_translation_t +* NAME +* ipoib_guid2mac_translation_t +* +* DESCRIPTION +* The ipoib_guid2mac_translation_t structure defines a GUID to MAC translation. +* The structure holds map between known OUI to an appropriate GUID mask. +* +* SYNOPSIS +*/ +typedef struct _ipoib_guid2mac_translation_ +{ + uint8_t second_byte; + uint8_t third_byte; + uint8_t guid_mask; + +} ipoib_guid2mac_translation_t; +/* +* FIELDS +* second_byte +* second byte of OUI (located in lower three bytes of GUID). +* +* third_byte +* third byte of OUI (located in lower three bytes of GUID). +* +* guid_mask +* GUID mask that will be used to generate MAC from the GUID. +* +* SEE ALSO +* IPoIB, ipoib_mac_from_guid_mask +*********/ + +extern const ipoib_guid2mac_translation_t guid2mac_table[]; + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/* + * Address accessors + */ + +static inline uint8_t +ipoib_addr_get_flags( + IN const ipoib_hw_addr_t* const p_addr ) +{ + return (uint8_t)( p_addr->flags_qpn & 0x000000ff); +} + +static inline void +ipoib_addr_set_flags( + IN ipoib_hw_addr_t* const p_addr, + IN const uint8_t flags ) +{ + p_addr->flags_qpn &= ( 0xFFFFFF00 ); + p_addr->flags_qpn |= ( flags ); +} + +static inline net32_t +ipoib_addr_get_qpn( + IN const ipoib_hw_addr_t* const p_addr ) +{ + return( ( p_addr->flags_qpn ) & 0xffffff00 ); +} + +static inline void +ipoib_addr_set_qpn( + IN ipoib_hw_addr_t* const p_addr, + IN const net32_t qpn ) +{ + p_addr->flags_qpn &= ( 0x000000FF ); + p_addr->flags_qpn |= qpn ; +} + +static inline void +ipoib_addr_set_sid( + IN net64_t* const p_sid, + IN const net32_t qpn ) +{ + *p_sid = qpn; + *p_sid <<= 32; + *p_sid |= IPOIB_CM_FLAG_SVCID; +} + +/****f* IPOIB/ipoib_mac_from_sst_guid +* NAME +* ipoib_mac_from_sst_guid +* +* DESCRIPTION +* Generates an ethernet MAC address given a SilverStorm port GUID. +* +* SYNOPSIS +*/ +static inline ib_api_status_t +ipoib_mac_from_sst_guid( + IN const net64_t port_guid, + OUT mac_addr_t* const p_mac_addr ) +{ + const uint8_t *p_guid = (const uint8_t*)&port_guid; + uint32_t low24; + + /* Port guid is in network byte order. OUI is in lower 3 bytes. */ + ASSERT( p_guid[0] == 0x00 && p_guid[1] == 0x06 && p_guid[2] == 0x6a ); + + /* + * We end up using only the lower 23-bits of the GUID. Trap that + * the 24th (bit 23) through 27th (bit 26) bit aren't set. + */ + if( port_guid & CL_HTON64( 0x0000000007800000 ) ) + return IB_INVALID_GUID; + + low24 = 0x00FFF000 - + ((((uint32_t)cl_ntoh64( port_guid ) & 0x00FFFFFF) - 0x101) * 2); + low24 -= p_guid[3]; /* minus port number */ + + p_mac_addr->addr[0] = p_guid[0]; + p_mac_addr->addr[1] = p_guid[1]; + p_mac_addr->addr[2] = p_guid[2]; + p_mac_addr->addr[3] = (uint8_t)(low24 >> 16); + p_mac_addr->addr[4] = (uint8_t)(low24 >> 8); + p_mac_addr->addr[5] = (uint8_t)low24; + + return IB_SUCCESS; +} +/* +* PARAMETERS +* port_guid +* The port GUID, in network byte order, for which to generate a +* MAC address. +* +* p_mac_addr +* Pointer to a mac address in which to store the results. +* +* RETURN VALUES +* IB_SUCCESS +* The MAC address was successfully converted. +* +* IB_INVALID_GUID +* The port GUID provided was not a known GUID format. +* +* NOTES +* The algorithm to convert portGuid to MAC address is as per DN0074, and +* assumes a 2 port HCA. +* +* SEE ALSO +* IPOIB +*********/ + + +/****f* IPOIB/ipoib_mac_from_mlx_guid +* NAME +* ipoib_mac_from_mlx_guid +* +* DESCRIPTION +* Generates an ethernet MAC address given a Mellanox port GUID. +* +* SYNOPSIS +*/ +static inline ib_api_status_t +ipoib_mac_from_mlx_guid( + IN const net64_t port_guid, + OUT mac_addr_t* const p_mac_addr ) +{ + const uint8_t *p_guid = (const uint8_t*)&port_guid; + uint32_t low24; + net16_t guid_middle; + + /* Port guid is in network byte order. OUI is in lower 3 bytes. */ + ASSERT( p_guid[0] == 0x00 && p_guid[1] == 0x02 && p_guid[2] == 0xc9 ); + + guid_middle = (net16_t)((port_guid & CL_HTON64( 0x000000ffff000000 )) >>24); + + if (guid_middle == 2) { + p_mac_addr->addr[0] = 0; + } else if (guid_middle == 3) { + p_mac_addr->addr[0] = 2; + } else { + return IB_INVALID_GUID; + } + low24 = ((uint32_t)cl_ntoh64( port_guid ) & 0x00FFFFFF); + + p_mac_addr->addr[1] = p_guid[1]; + p_mac_addr->addr[2] = p_guid[2]; + p_mac_addr->addr[3] = (uint8_t)(low24 >> 16); + p_mac_addr->addr[4] = (uint8_t)(low24 >> 8); + p_mac_addr->addr[5] = (uint8_t)low24; + + return IB_SUCCESS; +} +/* +* PARAMETERS +* port_guid +* The port GUID, in network byte order, for which to generate a +* MAC address. +* +* p_mac_addr +* Pointer to a mac address in which to store the results. +* +* RETURN VALUES +* IB_SUCCESS +* The MAC address was successfully converted. +* +* IB_INVALID_GUID +* The port GUID provided was not a known GUID format. +* +*********/ + + +/****f* IPOIB/ipoib_mac_from_voltaire_guid +* NAME +* ipoib_mac_from_voltaire_guid +* +* DESCRIPTION +* Generates an ethernet MAC address given a Voltaire port GUID. +* +* SYNOPSIS +*/ +static inline ib_api_status_t +ipoib_mac_from_voltaire_guid( + IN const net64_t port_guid, + OUT mac_addr_t* const p_mac_addr ) +{ + const uint8_t *p_guid = (const uint8_t*)&port_guid; + + /* Port guid is in network byte order. OUI is in lower 3 bytes. */ + ASSERT( p_guid[0] == 0x00 && p_guid[1] == 0x08 && p_guid[2] == 0xf1 ); + + p_mac_addr->addr[0] = p_guid[0]; + p_mac_addr->addr[1] = p_guid[1]; + p_mac_addr->addr[2] = p_guid[2]; + p_mac_addr->addr[3] = p_guid[4] ^ p_guid[6]; + p_mac_addr->addr[4] = p_guid[5] ^ p_guid[7]; + p_mac_addr->addr[5] = p_guid[5] + p_guid[6] + p_guid[7]; + + return IB_SUCCESS; +} + + +/****f* IPOIB/ipoib_mac_from_guid_mask +* NAME +* ipoib_mac_from_guid_mask +* +* DESCRIPTION +* Generates an ethernet MAC address given general port GUID and a bitwise mask +* +* SYNOPSIS +*/ +static inline ib_api_status_t +ipoib_mac_from_guid_mask( + IN const uint8_t *p_guid, + IN uint32_t guid_mask, + OUT mac_addr_t* const p_mac_addr ) +{ + static const mac_addr_size = HW_ADDR_LEN; + uint8_t i; + int digit_counter = 0; + + // All non-zero bits of guid_mask indicates the number of an appropriate + // byte in port_guid, that will be used in MAC address construction + for (i = 7; guid_mask; guid_mask >>= 1, --i ) + { + if( guid_mask & 1 ) + { + ++digit_counter; + if( digit_counter > mac_addr_size ) + { + //to avoid negative index + return IB_INVALID_GUID_MASK; + } + p_mac_addr->addr[mac_addr_size - digit_counter] = p_guid [i]; + } + } + + // check for the mask validity: it should have 6 non-zero bits + if( digit_counter != mac_addr_size ) + return IB_INVALID_GUID_MASK; + + return IB_SUCCESS; +} +/* +* PARAMETERS +* port_guid +* The port GUID, in network byte order, for which to generate a +* MAC address. +* +* guid_mask +* Each BIT in the mask indicates whether to include the appropriate BYTE +* to the MAC address. Bit 0 corresponds to the less significant BYTE , i.e. +* highest index in the MAC array +* +* p_mac_addr +* Pointer to a mac address in which to store the results. +* +* RETURN VALUES +* IB_SUCCESS +* The MAC address was successfully converted. +* +* IB_INVALID_GUID +* The port GUID provided was not a known GUID format. +* +* SEE ALSO +* IPOIB +*********/ + + +/****f* IPOIB/ipoib_mac_from_guid +* NAME +* ipoib_mac_from_guid +* +* DESCRIPTION +* Generates an ethernet MAC address given a port GUID. +* +* SYNOPSIS +*/ +static inline ib_api_status_t +ipoib_mac_from_guid( + IN const net64_t port_guid, + IN uint32_t guid_mask, + OUT mac_addr_t* const p_mac_addr + ) +{ + ib_api_status_t status = IB_INVALID_GUID; + const uint8_t *p_guid = (const uint8_t*)&port_guid; + uint32_t laa, idx = 0; + + /* Port guid is in network byte order. OUI is in lower 3 bytes. */ + if( p_guid[0] == 0 ) + { + if( p_guid[1] == 0x02 && p_guid[2] == 0xc9 ) + { + status = ipoib_mac_from_mlx_guid( port_guid, p_mac_addr ); + } + else if( p_guid[1] == 0x08 && p_guid[2] == 0xf1 ) + { + status = ipoib_mac_from_voltaire_guid( port_guid, p_mac_addr ); + } + else if( p_guid[1] == 0x06 && p_guid[2] == 0x6a ) + { + status = ipoib_mac_from_sst_guid( port_guid, p_mac_addr ); + } + else + { + while( guid2mac_table[idx].second_byte != 0x00 || + guid2mac_table[idx].third_byte != 0x00 ) + { + if( p_guid[1] == guid2mac_table[idx].second_byte && + p_guid[2] == guid2mac_table[idx].third_byte ) + { + status = ipoib_mac_from_guid_mask(p_guid, guid2mac_table[idx].guid_mask, + p_mac_addr); + break; + } + ++idx; + } + } + + if( status == IB_SUCCESS ) + return status; + } + + if( guid_mask ) + return ipoib_mac_from_guid_mask( p_guid, guid_mask, p_mac_addr ); + + /* Value of zero is reserved. */ + laa = cl_atomic_inc( &g_ipoib.laa_idx ); + + if( !laa ) + return IB_INVALID_GUID; + + p_mac_addr->addr[0] = 2; /* LAA bit */ + p_mac_addr->addr[1] = 0; + p_mac_addr->addr[2] = (uint8_t)(laa >> 24); + p_mac_addr->addr[3] = (uint8_t)(laa >> 16); + p_mac_addr->addr[4] = (uint8_t)(laa >> 8); + p_mac_addr->addr[5] = (uint8_t)laa; + + return IB_SUCCESS; +} +/* +* PARAMETERS +* port_guid +* The port GUID, in network byte order, for which to generate a +* MAC address. +* +* p_mac_addr +* Pointer to a mac address in which to store the results. +* +* RETURN VALUES +* IB_SUCCESS +* The MAC address was successfully converted. +* +* IB_INVALID_GUID +* The port GUID provided was not a known GUID format. +* +* NOTES +* Creates a locally administered address using a global incrementing counter. +* +* SEE ALSO +* IPOIB +*********/ + + +/****f* IPOIB/ipoib_is_voltaire_router_gid +* NAME +* ipoib_is_voltaire_router_gid +* +* DESCRIPTION +* Checks whether the GID belongs to Voltaire IP router +* +* SYNOPSIS +*/ +boolean_t +static inline +ipoib_is_voltaire_router_gid( + IN const ib_gid_t *p_gid ) +{ + static const uint8_t VOLTAIRE_GUID_PREFIX[] = {0, 0x08, 0xf1, 0, 0x1}; + + return !cl_memcmp( &p_gid->unicast.interface_id, VOLTAIRE_GUID_PREFIX, + sizeof(VOLTAIRE_GUID_PREFIX) ); +} + + +#ifdef __cplusplus +} +#endif + +#endif /* _IPOIB_XFR_MGR_H_ */ diff --git a/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/makefile b/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/makefile new file mode 100644 index 00000000..72fbf963 --- /dev/null +++ b/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/makefile @@ -0,0 +1,13 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +# +# prevent the Build utility from building the driver for an earlier +# version of the operating system than vista/Win 2008. +# +MINIMUM_NT_TARGET_VERSION=0x600 + +!INCLUDE ..\..\..\inc\openib.def diff --git a/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/makefile.inc b/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/makefile.inc new file mode 100644 index 00000000..4f29f500 --- /dev/null +++ b/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/makefile.inc @@ -0,0 +1,17 @@ + +# Transform .inx file to .inf file adding date + major,min & svn.version stamp +# Output .inf file is copied to the $(INF_TARGET) folder (commonly where .sys file resides). + +_LNG=$(LANGUAGE) + +!IF !DEFINED(_INX) +_INX=. +!ENDIF + +STAMP=stampinf -a $(_BUILDARCH) + +!INCLUDE mod_ver.def + +$(INF_TARGET) : $(_INX)\$(INF_NAME).inx + copy $(_INX)\$(@B).inx $@ + $(STAMP) -f $@ -d * -v $(IB_MAJORVERSION).$(IB_MINORVERSION).$(IB_BUILDVERSION).$(OPENIB_REV) diff --git a/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/netipoib.inx b/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/netipoib.inx new file mode 100644 index 00000000..daefdc29 --- /dev/null +++ b/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/netipoib.inx @@ -0,0 +1,309 @@ +; OpenFabrics Alliance Internet Protocol over InfiniBand Adapter +; Copyright 2005 SilverStorm Technologies all Rights Reserved. +; Copyright 2006 Mellanox Technologies all Rights Reserved. + +[Version] +Signature = "$Windows NT$" +Class = Net +ClassGUID = {4d36e972-e325-11ce-bfc1-08002be10318} +Provider = %OPENIB% +DriverVer=06/11/2008,1.0.0000.1207 +CatalogFile=ipoib.cat + +[Manufacturer] +%OPENIB% = OPENIB,ntx86,ntamd64,ntia64 + +[ControlFlags] +ExcludeFromSelect = IBA\IPoIB + +[OPENIB] +; empty since we don't support W9x/Me + +[OPENIB.ntx86] +%IpoibDesc% = Ipoib.DDInstall, IBA\IPoIB ; Internet Protocol over InfiniBand Adapter +%IpoibDescP% = Ipoib.DDInstall, IBA\IPoIBP ; Internet Protocol over InfiniBand Adapter with partition key + +[OPENIB.ntamd64] +%IpoibDesc% = Ipoib.DDInstall, IBA\IPoIB ; Internet Protocol over InfiniBand Adapter +%IpoibDescP% = Ipoib.DDInstall, IBA\IPoIBP ; Internet Protocol over InfiniBand Adapter with partition key + +[OPENIB.ntia64] +%IpoibDesc% = Ipoib.DDInstall, IBA\IPoIB ; Internet Protocol over InfiniBand Adapter +%IpoibDescP% = Ipoib.DDInstall, IBA\IPoIBP ; Internet Protocol over InfiniBand Adapter with partition key + +[Ipoib.DDInstall.ntx86] +Characteristics = 0x81 ; NCF_HAS_UI | NCF_VIRTUAL +AddReg = IpoibAddReg +CopyFiles = IpoibCopyFiles +CopyFiles = WsdCopyFiles +CopyFiles = NdCopyFiles +*IfType = 6 ; IF_TYPE_ETHERNET_CSMACD +*MediaType = 0 ; NdisMedium802_3 +*PhysicalMediaType = 14 ; NdisPhysicalMedium802_3 + +[Ipoib.DDInstall.ntamd64] +Characteristics = 0x81 ; NCF_HAS_UI | NCF_VIRTUAL +AddReg = IpoibAddReg +CopyFiles = IpoibCopyFiles +CopyFiles = WsdCopyFiles +CopyFiles = NdCopyFiles +CopyFiles = WOW64CopyFiles +*IfType = 6 ; IF_TYPE_ETHERNET_CSMACD +*MediaType = 0 ; NdisMedium802_3 +*PhysicalMediaType = 14 ; NdisPhysicalMedium802_3 + +[Ipoib.DDInstall.ntia64] +Characteristics = 0x81 ; NCF_HAS_UI | NCF_VIRTUAL +AddReg = IpoibAddReg +CopyFiles = IpoibCopyFiles +CopyFiles = WsdCopyFiles +CopyFiles = NdWvCopyFiles +CopyFiles = WOW64IA64CopyFiles +*IfType = 6 ; IF_TYPE_ETHERNET_CSMACD +*MediaType = 0 ; NdisMedium802_3 +*PhysicalMediaType = 14 ; NdisPhysicalMedium802_3 + +[Ipoib.DDInstall.ntx86.Services] +AddService = ipoib, 2, IpoibService, IpoibEventLog + +[Ipoib.DDInstall.ntamd64.Services] +AddService = ipoib, 2, IpoibService, IpoibEventLog + +[Ipoib.DDInstall.ntia64.Services] +AddService = ipoib, 2, IpoibService, IpoibEventLog + +[IpoibAddReg] +HKR, ,RDMACapable, %REG_DWORD%, 1 +HKR, Ndi, Service, 0, "ipoib" +HKR, Ndi\Interfaces, UpperRange, 0, "ndis5" +HKR, Ndi\Interfaces, LowerRange, 0, "ethernet" + +HKR, Ndi\Params\RqDepth, ParamDesc, 0, %RQ_DEPTH_STR% +HKR, Ndi\Params\RqDepth, Type, 0, "dword" +HKR, Ndi\Params\RqDepth, Default, 0, "512" +HKR, Ndi\Params\RqDepth, Optional, 0, "0" +HKR, Ndi\Params\RqDepth, Min, 0, "128" +HKR, Ndi\Params\RqDepth, Max, 0, "1024" +HKR, Ndi\Params\RqDepth, Step, 0, "128" + +HKR, Ndi\Params\RqLowWatermark, ParamDesc, 0, %RQ_WATERMARK_STR% +HKR, Ndi\Params\RqLowWatermark, Type, 0, "dword" +HKR, Ndi\Params\RqLowWatermark, Default, 0, "4" +HKR, Ndi\Params\RqLowWatermark, Optional, 0, "0" +HKR, Ndi\Params\RqLowWatermark, Min, 0, "2" +HKR, Ndi\Params\RqLowWatermark, Max, 0, "8" +HKR, Ndi\Params\RqLowWatermark, Step, 0, "1" + +HKR, Ndi\Params\SqDepth, ParamDesc, 0, %SQ_DEPTH_STR% +HKR, Ndi\Params\SqDepth, Type, 0, "dword" +HKR, Ndi\Params\SqDepth, Default, 0, "512" +HKR, Ndi\Params\SqDepth, Optional, 0, "0" +HKR, Ndi\Params\SqDepth, Min, 0, "128" +HKR, Ndi\Params\SqDepth, Max, 0, "1024" +HKR, Ndi\Params\SqDepth, Step, 0, "128" + +HKR, Ndi\Params\SendChksum, ParamDesc, 0, %SQ_CSUM_STR% +HKR, Ndi\Params\SendChksum, Type, 0, "enum" +HKR, Ndi\Params\SendChksum, Default, 0, "1" +HKR, Ndi\Params\SendChksum, Optional, 0, "0" +HKR, Ndi\Params\SendChksum\enum, "0", 0, %DISABLED_STR% +HKR, Ndi\Params\SendChksum\enum, "1", 0, %ENABLED_IF_STR% +HKR, Ndi\Params\SendChksum\enum, "2", 0, %BYPASS_STR% + +HKR, Ndi\Params\RecvChksum, ParamDesc, 0, %RQ_CSUM_STR% +HKR, Ndi\Params\RecvChksum, Type, 0, "enum" +HKR, Ndi\Params\RecvChksum, Default, 0, "1" +HKR, Ndi\Params\RecvChksum, Optional, 0, "0" +HKR, Ndi\Params\RecvChksum\enum, "0", 0, %DISABLED_STR% +HKR, Ndi\Params\RecvChksum\enum, "1", 0, %ENABLED_IF_STR% +HKR, Ndi\Params\RecvChksum\enum, "2", 0, %BYPASS_STR% + +HKR, Ndi\Params\lso, ParamDesc, 0, %LSO_STR% +HKR, Ndi\Params\lso, Type, 0, "enum" +HKR, Ndi\Params\lso, Default, 0, "0" +HKR, Ndi\Params\lso, Optional, 0, "0" +HKR, Ndi\Params\lso\enum, "0", 0, %DISABLED_STR% +HKR, Ndi\Params\lso\enum, "1", 0, %ENABLED_STR% + + +HKR, Ndi\Params\SaTimeout, ParamDesc, 0, %SA_QUERY_TO_STR% +HKR, Ndi\Params\SaTimeout, Type, 0, "dword" +HKR, Ndi\Params\SaTimeout, Default, 0, "1000" +HKR, Ndi\Params\SaTimeout, Optional, 0, "0" +HKR, Ndi\Params\SaTimeout, Min, 0, "500" +HKR, Ndi\Params\SaTimeout, Step, 0, "250" + +HKR, Ndi\Params\SaRetries, ParamDesc, 0, %SA_QUERY_RETRY_STR% +HKR, Ndi\Params\SaRetries, Type, 0, "dword" +HKR, Ndi\Params\SaRetries, Default, 0, "10" +HKR, Ndi\Params\SaRetries, Optional, 0, "0" +HKR, Ndi\Params\SaRetries, Min, 0, "1" + +HKR, Ndi\Params\RecvRatio, ParamDesc, 0, %RECV_RATIO_STR% +HKR, Ndi\Params\RecvRatio, Type, 0, "dword" +HKR, Ndi\Params\RecvRatio, Default, 0, "1" +HKR, Ndi\Params\RecvRatio, Optional, 0, "0" +HKR, Ndi\Params\RecvRatio, Min, 0, "1" +HKR, Ndi\Params\RecvRatio, Max, 0, "10" + +HKR, Ndi\Params\PayloadMtu, ParamDesc, 0, %MTU_STR% +HKR, Ndi\Params\PayloadMtu, Type, 0, "dword" +HKR, Ndi\Params\PayloadMtu, Default, 0, "2044" +HKR, Ndi\Params\PayloadMtu, Min, 0, "512" +HKR, Ndi\Params\PayloadMtu, Max, 0, "4092" + +HKR, Ndi\Params\MCLeaveRescan, ParamDesc, 0, %MC_RESCAN_STR% +HKR, Ndi\Params\MCLeaveRescan, Type, 0, "dword" +HKR, Ndi\Params\MCLeaveRescan, Default, 0, "260" +HKR, Ndi\Params\MCLeaveRescan, Optional, 0, "0" +HKR, Ndi\Params\MCLeaveRescan, Min, 0, "1" +HKR, Ndi\Params\MCLeaveRescan, Max, 0, "3600" + +HKR, Ndi\Params\GUIDMask, ParamDesc, 0, %GUID_MASK_STR% +HKR, Ndi\Params\GUIDMask, Type, 0, "dword" +HKR, Ndi\Params\GUIDMask, Default, 0, "0" +HKR, Ndi\Params\GUIDMask, Optional, 0, "0" +HKR, Ndi\Params\GUIDMask, Min, 0, "0" +HKR, Ndi\Params\GUIDMask, Max, 0, "252" + +HKR, Ndi\Params\BCJoinRetry, ParamDesc, 0, %BC_JOIN_RETRY_STR% +HKR, Ndi\Params\BCJoinRetry, Type, 0, "dword" +HKR, Ndi\Params\BCJoinRetry, Default, 0, "50" +HKR, Ndi\Params\BCJoinRetry, Optional, 0, "0" +HKR, Ndi\Params\BCJoinRetry, Min, 0, "0" +HKR, Ndi\Params\BCJoinRetry, Max, 0, "1000" + +HKR, Ndi\Params\CmEnabled, ParamDesc, 0, %CONNECTED_MODE_STR% +HKR, Ndi\Params\CmEnabled, Type, 0, "enum" +HKR, Ndi\Params\CmEnabled, Default, 0, "0" +HKR, Ndi\Params\CmEnabled, Optional, 0, "0" +HKR, Ndi\Params\CmEnabled\enum, "0", 0, %DISABLED_STR% +HKR, Ndi\Params\CmEnabled\enum, "1", 0, %ENABLED_STR% + +HKR, Ndi\Params\CmPayloadMtu, ParamDesc, 0, %CONNECTED_MODE_MTU_STR% +HKR, Ndi\Params\CmPayloadMtu, Type, 0, "dword" +HKR, Ndi\Params\CmPayloadMtu, Default, 0, "65520" +HKR, Ndi\Params\CmPayloadMtu, Min, 0, "512" +HKR, Ndi\Params\CmPayloadMtu, Max, 0, "65520" + +[IpoibService] +DisplayName = %IpoibServiceDispName% +ServiceType = 1 ;%SERVICE_KERNEL_DRIVER% +StartType = 3 ;%SERVICE_DEMAND_START% +ErrorControl = 1 ;%SERVICE_ERROR_NORMAL% +ServiceBinary = %12%\ipoib.sys +LoadOrderGroup = NDIS +AddReg = Ipoib.ParamsReg + +[Ipoib.ParamsReg] +HKR,"Parameters","DebugLevel",%REG_DWORD_NO_CLOBBER%,0x00000002 +HKR,"Parameters","DebugFlags",%REG_DWORD_NO_CLOBBER%,0x00000fff +HKR,"Parameters","bypass_check_bcast_rate",%REG_DWORD_NO_CLOBBER%,0x00000000 + +[IpoibEventLog] +AddReg = IpoibAddEventLogReg + +[IpoibAddEventLogReg] +HKR, , EventMessageFile, 0x00020000, "%%SystemRoot%%\System32\netevent.dll;%%SystemRoot%%\System32\drivers\ipoib.sys" +HKR, , TypesSupported, 0x00010001, 7 + + +[IpoibCopyFiles] +ipoib.sys,,,2 + +[WsdCopyFiles] +ibwsd.dll,,,0x00000002 + +[NdCopyFiles] +ibndprov.dll,,,0x00000002 +wvndprov.dll,,,0x00000002 +ndinstall.exe,,,0x00000002 + +[NdWvCopyFiles] +wvndprov.dll,,,0x00000002 +ndinstall.exe,,,0x00000002 + +[WOW64CopyFiles] +ibwsd.dll,ibwsd32.dll,,0x00000002 +ibndprov.dll,ibndprov32.dll,,0x00000002 +wvndprov.dll,wvndprov32.dll,,0x00000002 + +[WOW64IA64CopyFiles] +ibwsd.dll,ibwsd32.dll,,0x00000002 +wvndprov.dll,wvndprov32.dll,,0x00000002 + +[SourceDisksNames.x86] +1 = %IcsDisk1%,,,"" + +[SourceDisksNames.amd64] +1 = %IcsDisk1%,,,"" + +[SourceDisksNames.ia64] +1 = %IcsDisk1%,,,"" + +[SourceDisksFiles.x86] +ipoib.sys = 1 +ibwsd.dll = 1 +ibndprov.dll = 1 +wvndprov.dll = 1 +ndinstall.exe = 1 + +[SourceDisksFiles.amd64] +ipoib.sys = 1 +ibwsd.dll = 1 +ibwsd32.dll = 1 +ibndprov.dll = 1 +ibndprov32.dll = 1 +wvndprov.dll = 1 +wvndprov32.dll = 1 +ndinstall.exe = 1 + +[SourceDisksFiles.ia64] +ipoib.sys = 1 +ibwsd.dll = 1 +ibwsd32.dll = 1 +wvndprov.dll = 1 +wvndprov32.dll = 1 +ndinstall.exe = 1 + +[DestinationDirs] +IpoibCopyFiles = %DIRID_DRIVERS% +WsdCopyFiles = %DIRID_SYSTEM% +NdCopyFiles = %DIRID_SYSTEM% +NdWvCopyFiles = %DIRID_SYSTEM% +WOW64CopyFiles = %DIRID_SYSTEM_X86% +WOW64IA64CopyFiles = %DIRID_SYSTEM_X86% +DefaultDestDir = %DIRID_SYSTEM% + +[Strings] +OPENIB = "OpenFabrics Alliance" +IpoibDesc = "OpenFabrics IPoIB Adapter" +IpoibDescP = "OpenFabrics IPoIB Adapter Partition" +IpoibServiceDispName = "IPoIB" +IcsDisk1 = "OpenFabrics IPoIB Disk #1" +DIRID_SYSTEM = 11 +DIRID_DRIVERS = 12 +DIRID_SYSTEM_X86 = 16425 +REG_DWORD = 0x00010001 +REG_DWORD_NO_CLOBBER = 0x00010003 + +RQ_DEPTH_STR = "Receive Queue depth" +RQ_WATERMARK_STR = "Receive Queue Low Watermark" +SQ_DEPTH_STR = "Send Queue Depth" +SQ_CSUM_STR = "Send Checksum Offload" +RQ_CSUM_STR = "Recv Checksum Offload" +LSO_STR = "Large Send Offload" +SA_QUERY_TO_STR = "SA Query Timeout (ms)" +SA_QUERY_RETRY_STR = "SA Query Retry Count" +RECV_RATIO_STR = "Receive Pool Ratio" +MTU_STR = "Payload Mtu size" +MC_RESCAN_STR = "MC leave rescan (sec)" +GUID_MASK_STR = "GUID bitwise mask" +BC_JOIN_RETRY_STR = "Number of retries connecting to bc" + +ENABLED_IF_STR = "Enabled (if supported by HW)" +ENABLED_STR = "Enabled" +DISABLED_STR = "Disabled" +BYPASS_STR = "Bypass" +CONNECTED_MODE_STR = "Connected mode" +CONNECTED_MODE_MTU_STR = "Connected Mode Payload Mtu size" diff --git a/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/offload.h b/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/offload.h new file mode 100644 index 00000000..de696c6a --- /dev/null +++ b/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/offload.h @@ -0,0 +1,47 @@ +/*++ + +Copyright (c) 2005-2008 Mellanox Technologies. All rights reserved. + +Module Name: + offload.h + +Abstract: + Task offloading header file + +Revision History: + +Notes: + +--*/ + +// +// Define the maximum size of large TCP packets the driver can offload. +// This sample driver uses shared memory to map the large packets, +// LARGE_SEND_OFFLOAD_SIZE is useless in this case, so we just define +// it as NIC_MAX_PACKET_SIZE. But shipping drivers should define +// LARGE_SEND_OFFLOAD_SIZE if they support LSO, and use it as +// MaximumPhysicalMapping when they call NdisMInitializeScatterGatherDma +// if they use ScatterGather method. If the drivers don't support +// LSO, then MaximumPhysicalMapping is NIC_MAX_PACKET_SIZE. +// + +#define LSO_MAX_HEADER 136 +#define LARGE_SEND_OFFLOAD_SIZE 60000 + +// This struct is being used in order to pass data about the GSO buffers if they +// are present +typedef struct LsoBuffer_ { + PUCHAR pData; + UINT Len; +} LsoBuffer; + +typedef struct LsoData_ { + LsoBuffer LsoBuffers[1]; + UINT UsedBuffers; + UINT FullBuffers; + UINT LsoHeaderSize; + UINT IndexOfData; + UCHAR coppied_data[LSO_MAX_HEADER]; +} LsoData; + + diff --git a/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/precompile.h b/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/precompile.h new file mode 100644 index 00000000..b331ad00 --- /dev/null +++ b/branches/WOF2-3/ulp/ipoib_NDIS6_CM/kernel/precompile.h @@ -0,0 +1,26 @@ + +#ifndef __precomp_h +#define __precomp_h + +#include "ipoib_xfr_mgr.h" +#include "limits.h" + + +#include "ipoib_log.h" +#include "ipoib_adapter.h" +#include +#include +#include "ipoib_debug.h" + + +#include "ipoib_driver.h" +#include "ipoib_debug.h" + +#include "ipoib_endpoint.h" +#include "ipoib_port.h" + + +#include "ipoib_adapter.h" + + +#endif __precomp_h \ No newline at end of file diff --git a/branches/WOF2-3/ulp/libibmad/README.txt b/branches/WOF2-3/ulp/libibmad/README.txt new file mode 100644 index 00000000..7c82b7e7 --- /dev/null +++ b/branches/WOF2-3/ulp/libibmad/README.txt @@ -0,0 +1,19 @@ +[1-06-09] + +These 'shared' OFED files (shared between Linux and Windows) are mirrored here for the convience +of Windows developers. + +The 'offical' OFED source files are located in the OFED git repository. + +The policy is 'no source file changes' in non-build files (.h & .c) are accepted here. +Any source file changes here will likely be overwritten when refreshed from the OFED git repository. + +The plan here is to have a single Linux and Windows source. + +If you require source file changes, push the changes to the OFED maintainers. + +For continuing policy discussion, please contact sean.hefty@intel.com + +thank you, + +Stan (stan.smith@intel.com) \ No newline at end of file diff --git a/branches/WOF2-3/ulp/libibmad/dirs b/branches/WOF2-3/ulp/libibmad/dirs new file mode 100644 index 00000000..b1cbe453 --- /dev/null +++ b/branches/WOF2-3/ulp/libibmad/dirs @@ -0,0 +1,2 @@ +DIRS = \ + src \ No newline at end of file diff --git a/branches/WOF2-3/ulp/libibmad/include/infiniband/mad.h b/branches/WOF2-3/ulp/libibmad/include/infiniband/mad.h new file mode 100644 index 00000000..7571a619 --- /dev/null +++ b/branches/WOF2-3/ulp/libibmad/include/infiniband/mad.h @@ -0,0 +1,1086 @@ +/* + * Copyright (c) 2004-2009 Voltaire Inc. All rights reserved. + * Copyright (c) 2009 HNR Consulting. All rights reserved. + * Copyright (c) 2009 Mellanox Technologies LTD. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ +#ifndef _MAD_H_ +#define _MAD_H_ + +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +#define IB_SUBNET_PATH_HOPS_MAX 64 +#define IB_DEFAULT_SUBN_PREFIX 0xfe80000000000000ULL +#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 +#define IB_BM_DATA_OFFS 64 +#define IB_BM_DATA_SZ (IB_MAD_SIZE - IB_BM_DATA_OFFS) +#define IB_BM_BKEY_OFFS 24 +#define IB_BM_BKEY_AND_DATA_SZ (IB_MAD_SIZE - IB_BM_BKEY_OFFS) + +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 MAD_STATUS { + IB_MAD_STS_OK = (0 << 2), + IB_MAD_STS_BUSY = (1 << 0), + IB_MAD_STS_REDIRECT = (1 << 1), + IB_MAD_STS_BAD_BASE_VER_OR_CLASS = (1 << 2), + IB_MAD_STS_METHOD_NOT_SUPPORTED = (2 << 2), + IB_MAD_STS_METHOD_ATTR_NOT_SUPPORTED = (3 << 2), + IB_MAD_STS_INV_ATTR_VALUE = (7 << 2), +}; + +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_LINKSPEEDWIDTHPAIRSTBL = 0x1c, + IB_ATTR_VENDORMADSTBL = 0x1d, + IB_ATTR_SMINFO = 0x20, + + IB_ATTR_LAST +}; + +enum SA_ATTR_ID { + IB_SA_ATTR_NOTICE = 0x02, + IB_SA_ATTR_INFORMINFO = 0x03, + IB_SA_ATTR_NODERECORD = 0x11, + IB_SA_ATTR_PORTINFORECORD = 0x12, + IB_SA_ATTR_SL2VLTABLERECORD = 0x13, + IB_SA_ATTR_SWITCHINFORECORD = 0x14, + IB_SA_ATTR_LFTRECORD = 0x15, + IB_SA_ATTR_RFTRECORD = 0x16, + IB_SA_ATTR_MFTRECORD = 0x17, + IB_SA_ATTR_SMINFORECORD = 0x18, + IB_SA_ATTR_LINKRECORD = 0x20, + IB_SA_ATTR_GUIDINFORECORD = 0x30, + IB_SA_ATTR_SERVICERECORD = 0x31, + IB_SA_ATTR_PKEYTABLERECORD = 0x33, + IB_SA_ATTR_PATHRECORD = 0x35, + IB_SA_ATTR_VLARBTABLERECORD = 0x36, + IB_SA_ATTR_MCRECORD = 0x38, + IB_SA_ATTR_MULTIPATH = 0x3a, + IB_SA_ATTR_INFORMINFORECORD = 0xf3, + + 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_RCV_ERROR_DETAILS = 0x15, + IB_GSI_PORT_XMIT_DISCARD_DETAILS = 0x16, + IB_GSI_PORT_COUNTERS_EXT = 0x1D, + IB_GSI_PORT_XMIT_DATA_SL = 0x36, + IB_GSI_PORT_RCV_DATA_SL = 0x37, + IB_GSI_ATTR_LAST +}; + +enum BM_ATTR_ID { + IB_BM_ATTR_BKEYINFO = 0x10, + IB_BM_ATTR_WRITE_VPD = 0x20, + IB_BM_ATTR_READ_VPD = 0x21, + IB_BM_ATTR_RESET_IBML = 0x22, + IB_BM_ATTR_SET_MODULE_PM_CONTROL = 0x23, + IB_BM_ATTR_GET_MODULE_PM_CONTROL = 0x24, + IB_BM_ATTR_SET_UNIT_PM_CONTROL = 0x25, + IB_BM_ATTR_GET_UNIT_PM_CONTROL = 0x26, + IB_BM_ATTR_SET_IOC_PM_CONTROL = 0x27, + IB_BM_ATTR_GET_IOC_PM_CONTROL = 0x28, + IB_BM_ATTR_SET_MODULE_STATE = 0x29, + IB_BM_ATTR_SET_MODULE_ATTENTION = 0x2A, + IB_BM_ATTR_GET_MODULE_STATUS = 0x2B, + IB_BM_ATTR_IB2IBML = 0x2C, + IB_BM_ATTR_IB2CME = 0x2D, + IB_BM_ATTR_IB2MME = 0x2E, + IB_BM_ATTR_OEM = 0x2F, + + IB_BM_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_DRDLID_F, + IB_DRSMP_DRSLID_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_MCAST_PKEY_SUPR_ENAB_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_OPT_SLTOVL_MAPPING_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_MCAST_FDB_TOP_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_COUNTER_SELECT2_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_XMT_WAIT_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, + IB_SA_PR_SL_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, + + /* + * ClassPortInfo fields + */ + IB_CPI_BASEVER_F, + IB_CPI_CLASSVER_F, + IB_CPI_CAPMASK_F, + IB_CPI_CAPMASK2_F, + IB_CPI_RESP_TIME_VALUE_F, + IB_CPI_REDIRECT_GID_F, + IB_CPI_REDIRECT_TC_F, + IB_CPI_REDIRECT_SL_F, + IB_CPI_REDIRECT_FL_F, + IB_CPI_REDIRECT_LID_F, + IB_CPI_REDIRECT_PKEY_F, + IB_CPI_REDIRECT_QP_F, + IB_CPI_REDIRECT_QKEY_F, + IB_CPI_TRAP_GID_F, + IB_CPI_TRAP_TC_F, + IB_CPI_TRAP_SL_F, + IB_CPI_TRAP_FL_F, + IB_CPI_TRAP_LID_F, + IB_CPI_TRAP_PKEY_F, + IB_CPI_TRAP_HL_F, + IB_CPI_TRAP_QP_F, + IB_CPI_TRAP_QKEY_F, + + /* + * PortXmitDataSL fields + */ + IB_PC_XMT_DATA_SL_FIRST_F, + IB_PC_XMT_DATA_SL0_F = IB_PC_XMT_DATA_SL_FIRST_F, + IB_PC_XMT_DATA_SL1_F, + IB_PC_XMT_DATA_SL2_F, + IB_PC_XMT_DATA_SL3_F, + IB_PC_XMT_DATA_SL4_F, + IB_PC_XMT_DATA_SL5_F, + IB_PC_XMT_DATA_SL6_F, + IB_PC_XMT_DATA_SL7_F, + IB_PC_XMT_DATA_SL8_F, + IB_PC_XMT_DATA_SL9_F, + IB_PC_XMT_DATA_SL10_F, + IB_PC_XMT_DATA_SL11_F, + IB_PC_XMT_DATA_SL12_F, + IB_PC_XMT_DATA_SL13_F, + IB_PC_XMT_DATA_SL14_F, + IB_PC_XMT_DATA_SL15_F, + IB_PC_XMT_DATA_SL_LAST_F, + + /* + * PortRcvDataSL fields + */ + IB_PC_RCV_DATA_SL_FIRST_F, + IB_PC_RCV_DATA_SL0_F = IB_PC_RCV_DATA_SL_FIRST_F, + IB_PC_RCV_DATA_SL1_F, + IB_PC_RCV_DATA_SL2_F, + IB_PC_RCV_DATA_SL3_F, + IB_PC_RCV_DATA_SL4_F, + IB_PC_RCV_DATA_SL5_F, + IB_PC_RCV_DATA_SL6_F, + IB_PC_RCV_DATA_SL7_F, + IB_PC_RCV_DATA_SL8_F, + IB_PC_RCV_DATA_SL9_F, + IB_PC_RCV_DATA_SL10_F, + IB_PC_RCV_DATA_SL11_F, + IB_PC_RCV_DATA_SL12_F, + IB_PC_RCV_DATA_SL13_F, + IB_PC_RCV_DATA_SL14_F, + IB_PC_RCV_DATA_SL15_F, + IB_PC_RCV_DATA_SL_LAST_F, + + /* + * PortXmitDiscardDetails fields + */ + IB_PC_XMT_INACT_DISC_F, + IB_PC_XMT_NEIGH_MTU_DISC_F, + IB_PC_XMT_SW_LIFE_DISC_F, + IB_PC_XMT_SW_HOL_DISC_F, + IB_PC_XMT_DISC_LAST_F, + + /* + * PortRcvErrorDetails fields + */ + IB_PC_RCV_LOCAL_PHY_ERR_F, + IB_PC_RCV_MALFORMED_PKT_ERR_F, + IB_PC_RCV_BUF_OVR_ERR_F, + IB_PC_RCV_DLID_MAP_ERR_F, + IB_PC_RCV_VL_MAP_ERR_F, + IB_PC_RCV_LOOPING_ERR_F, + IB_PC_RCV_ERR_LAST_F, + + /* + * PortSamplesControl fields + */ + IB_PSC_OPCODE_F, + IB_PSC_PORT_SELECT_F, + IB_PSC_TICK_F, + IB_PSC_COUNTER_WIDTH_F, + IB_PSC_COUNTER_MASK0_F, + IB_PSC_COUNTER_MASKS1TO9_F, + IB_PSC_COUNTER_MASKS10TO14_F, + IB_PSC_SAMPLE_MECHS_F, + IB_PSC_SAMPLE_STATUS_F, + IB_PSC_OPTION_MASK_F, + IB_PSC_VENDOR_MASK_F, + IB_PSC_SAMPLE_START_F, + IB_PSC_SAMPLE_INTVL_F, + IB_PSC_TAG_F, + IB_PSC_COUNTER_SEL0_F, + IB_PSC_COUNTER_SEL1_F, + IB_PSC_COUNTER_SEL2_F, + IB_PSC_COUNTER_SEL3_F, + IB_PSC_COUNTER_SEL4_F, + IB_PSC_COUNTER_SEL5_F, + IB_PSC_COUNTER_SEL6_F, + IB_PSC_COUNTER_SEL7_F, + IB_PSC_COUNTER_SEL8_F, + IB_PSC_COUNTER_SEL9_F, + IB_PSC_COUNTER_SEL10_F, + IB_PSC_COUNTER_SEL11_F, + IB_PSC_COUNTER_SEL12_F, + IB_PSC_COUNTER_SEL13_F, + IB_PSC_COUNTER_SEL14_F, + IB_PSC_SAMPLES_ONLY_OPT_MASK_F, + IB_PSC_LAST_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; + +typedef struct ib_bm_call { + unsigned method; + unsigned attrid; + unsigned mod; + unsigned timeout; + uint64_t bkey; +} ib_bm_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 MAD_DEST { + IB_DEST_LID, + IB_DEST_DRPATH, + IB_DEST_GUID, + IB_DEST_DRSLID, + IB_DEST_GID +}; + +enum MAD_NODE_TYPE { + IB_NODE_CA = 1, + IB_NODE_SWITCH, + IB_NODE_ROUTER, + NODE_RNIC, + + IB_NODE_MAX = NODE_RNIC +}; + +/******************************************************************************/ + +/* portid.c */ +MAD_EXPORT char *portid2str(ib_portid_t * portid); +MAD_EXPORT int portid2portnum(ib_portid_t * portid); +MAD_EXPORT int str2drpath(ib_dr_path_t * path, char *routepath, int drslid, + int drdlid); +MAD_EXPORT 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 */ +MAD_EXPORT uint32_t mad_get_field(void *buf, int base_offs, + enum MAD_FIELDS field); +MAD_EXPORT void mad_set_field(void *buf, int base_offs, enum MAD_FIELDS field, + uint32_t val); +/* field must be byte aligned */ +MAD_EXPORT uint64_t mad_get_field64(void *buf, int base_offs, + enum MAD_FIELDS field); +MAD_EXPORT void mad_set_field64(void *buf, int base_offs, enum MAD_FIELDS field, + uint64_t val); +MAD_EXPORT void mad_set_array(void *buf, int base_offs, enum MAD_FIELDS field, + void *val); +MAD_EXPORT void mad_get_array(void *buf, int base_offs, enum MAD_FIELDS field, + void *val); +MAD_EXPORT void mad_decode_field(uint8_t * buf, enum MAD_FIELDS field, + void *val); +MAD_EXPORT void mad_encode_field(uint8_t * buf, enum MAD_FIELDS field, + void *val); +MAD_EXPORT int mad_print_field(enum MAD_FIELDS field, const char *name, + void *val); +MAD_EXPORT char *mad_dump_field(enum MAD_FIELDS field, char *buf, int bufsz, + void *val); +MAD_EXPORT char *mad_dump_val(enum MAD_FIELDS field, char *buf, int bufsz, + void *val); +MAD_EXPORT const char *mad_field_name(enum MAD_FIELDS field); + +/* mad.c */ +MAD_EXPORT void *mad_encode(void *buf, ib_rpc_t * rpc, ib_dr_path_t * drpath, + void *data); +MAD_EXPORT uint64_t mad_trid(void); +MAD_EXPORT int mad_build_pkt(void *umad, ib_rpc_t * rpc, ib_portid_t * dport, + ib_rmpp_hdr_t * rmpp, void *data); + +/* New interface */ +MAD_EXPORT void madrpc_show_errors(int set); +MAD_EXPORT int madrpc_set_retries(int retries); +MAD_EXPORT int madrpc_set_timeout(int timeout); +MAD_EXPORT struct ibmad_port *mad_rpc_open_port(char *dev_name, int dev_port, + int *mgmt_classes, + int num_classes); +MAD_EXPORT void mad_rpc_close_port(struct ibmad_port *srcport); + +/* + * On redirection, the dport argument is updated with the redirection target, + * so subsequent MADs will not go through the redirection process again but + * reach the target directly. + */ +MAD_EXPORT void *mad_rpc(const struct ibmad_port *srcport, ib_rpc_t * rpc, + ib_portid_t * dport, void *payload, void *rcvdata); + +MAD_EXPORT void *mad_rpc_rmpp(const struct ibmad_port *srcport, ib_rpc_t * rpc, + ib_portid_t * dport, ib_rmpp_hdr_t * rmpp, + void *data); +MAD_EXPORT int mad_rpc_portid(struct ibmad_port *srcport); +MAD_EXPORT void mad_rpc_set_retries(struct ibmad_port *port, int retries); +MAD_EXPORT void mad_rpc_set_timeout(struct ibmad_port *port, int timeout); +MAD_EXPORT int mad_rpc_class_agent(struct ibmad_port *srcport, int cls); + +MAD_EXPORT int mad_get_timeout(const struct ibmad_port *srcport, + int override_ms); +MAD_EXPORT int mad_get_retries(const struct ibmad_port *srcport); + +/* register.c */ +MAD_EXPORT int mad_register_port_client(int port_id, int mgmt, + uint8_t rmpp_version); +MAD_EXPORT int mad_register_client(int mgmt, uint8_t rmpp_version) DEPRECATED; +MAD_EXPORT int mad_register_server(int mgmt, uint8_t rmpp_version, + long method_mask[16 / sizeof(long)], + uint32_t class_oui) DEPRECATED; +/* register.c new interface */ +MAD_EXPORT int mad_register_client_via(int mgmt, uint8_t rmpp_version, + struct ibmad_port *srcport); +MAD_EXPORT int mad_register_server_via(int mgmt, uint8_t rmpp_version, + long method_mask[16 / sizeof(long)], + uint32_t class_oui, + struct ibmad_port *srcport); +MAD_EXPORT int mad_class_agent(int mgmt) DEPRECATED; + +/* serv.c */ +MAD_EXPORT int mad_send(ib_rpc_t * rpc, ib_portid_t * dport, + ib_rmpp_hdr_t * rmpp, void *data) DEPRECATED; +MAD_EXPORT void *mad_receive(void *umad, int timeout) DEPRECATED; +MAD_EXPORT int mad_respond(void *umad, ib_portid_t * portid, uint32_t rstatus) + DEPRECATED; + +/* serv.c new interface */ +MAD_EXPORT int mad_send_via(ib_rpc_t * rpc, ib_portid_t * dport, + ib_rmpp_hdr_t * rmpp, void *data, + struct ibmad_port *srcport); +MAD_EXPORT void *mad_receive_via(void *umad, int timeout, + struct ibmad_port *srcport); +MAD_EXPORT int mad_respond_via(void *umad, ib_portid_t * portid, + uint32_t rstatus, struct ibmad_port *srcport); +MAD_EXPORT void *mad_alloc(void); +MAD_EXPORT void mad_free(void *umad); + +/* vendor.c */ +MAD_EXPORT uint8_t *ib_vendor_call(void *data, ib_portid_t * portid, + ib_vendor_call_t * call) DEPRECATED; + +/* vendor.c new interface */ +MAD_EXPORT uint8_t *ib_vendor_call_via(void *data, ib_portid_t * portid, + ib_vendor_call_t * call, + struct ibmad_port *srcport); + +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 */ +MAD_EXPORT int madrpc_portid(void) DEPRECATED; +void *madrpc(ib_rpc_t * rpc, ib_portid_t * dport, void *payload, void *rcvdata) + DEPRECATED; +void *madrpc_rmpp(ib_rpc_t * rpc, ib_portid_t * dport, ib_rmpp_hdr_t * rmpp, + void *data) DEPRECATED; +MAD_EXPORT void madrpc_init(char *dev_name, int dev_port, int *mgmt_classes, + int num_classes) DEPRECATED; +void madrpc_save_mad(void *madbuf, int len) DEPRECATED; + +/* smp.c */ +MAD_EXPORT uint8_t *smp_query(void *buf, ib_portid_t * id, unsigned attrid, + unsigned mod, unsigned timeout) DEPRECATED; +MAD_EXPORT uint8_t *smp_set(void *buf, ib_portid_t * id, unsigned attrid, + unsigned mod, unsigned timeout) DEPRECATED; + +/* smp.c new interface */ +MAD_EXPORT uint8_t *smp_query_via(void *buf, ib_portid_t * id, unsigned attrid, + unsigned mod, unsigned timeout, + const struct ibmad_port *srcport); +MAD_EXPORT uint8_t *smp_set_via(void *buf, ib_portid_t * id, unsigned attrid, + unsigned mod, unsigned timeout, + const struct ibmad_port *srcport); + +/* sa.c */ +uint8_t *sa_call(void *rcvbuf, ib_portid_t * portid, ib_sa_call_t * sa, + unsigned timeout) DEPRECATED; +MAD_EXPORT int ib_path_query(ibmad_gid_t srcgid, ibmad_gid_t destgid, + ib_portid_t * sm_id, void *buf) DEPRECATED; + +/* sa.c new interface */ +MAD_EXPORT uint8_t *sa_rpc_call(const struct ibmad_port *srcport, void *rcvbuf, + ib_portid_t * portid, ib_sa_call_t * sa, + unsigned timeout); +MAD_EXPORT int ib_path_query_via(const struct ibmad_port *srcport, + ibmad_gid_t srcgid, ibmad_gid_t destgid, + ib_portid_t * sm_id, void *buf); + /* returns lid */ + +/* resolve.c */ +MAD_EXPORT int ib_resolve_smlid(ib_portid_t * sm_id, int timeout) DEPRECATED; +MAD_EXPORT int ib_resolve_portid_str(ib_portid_t * portid, char *addr_str, + enum MAD_DEST dest, ib_portid_t * sm_id) + DEPRECATED; +MAD_EXPORT int ib_resolve_self(ib_portid_t * portid, int *portnum, + ibmad_gid_t * gid) DEPRECATED; + +/* resolve.c new interface */ +MAD_EXPORT int ib_resolve_smlid_via(ib_portid_t * sm_id, int timeout, + const struct ibmad_port *srcport); +MAD_EXPORT int ib_resolve_guid_via(ib_portid_t * portid, uint64_t * guid, + ib_portid_t * sm_id, int timeout, + const struct ibmad_port *srcport); +MAD_EXPORT int ib_resolve_gid_via(ib_portid_t * portid, ibmad_gid_t gid, + ib_portid_t * sm_id, int timeout, + const struct ibmad_port *srcport); +MAD_EXPORT int ib_resolve_portid_str_via(ib_portid_t * portid, char *addr_str, + enum MAD_DEST dest, + ib_portid_t * sm_id, + const struct ibmad_port *srcport); +MAD_EXPORT int ib_resolve_self_via(ib_portid_t * portid, int *portnum, + ibmad_gid_t * gid, + const struct ibmad_port *srcport); + +/* gs.c new interface */ +MAD_EXPORT uint8_t *pma_query_via(void *rcvbuf, ib_portid_t * dest, int port, + unsigned timeout, unsigned id, + const struct ibmad_port *srcport); +MAD_EXPORT uint8_t *performance_reset_via(void *rcvbuf, ib_portid_t * dest, + int port, unsigned mask, + unsigned timeout, unsigned id, + const struct ibmad_port *srcport); + +/* bm.c */ +MAD_EXPORT uint8_t *bm_call_via(void *data, ib_portid_t * portid, + ib_bm_call_t * call, + struct ibmad_port *srcport); + +/* dump.c */ +MAD_EXPORT 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, + mad_dump_perfcounters_xmt_sl, mad_dump_perfcounters_rcv_sl, + mad_dump_perfcounters_xmt_disc, mad_dump_perfcounters_rcv_err, + mad_dump_portsamples_control; + +MAD_EXPORT void mad_dump_fields(char *buf, int bufsz, void *val, int valsz, + int start, int end); + +extern MAD_EXPORT int ibdebug; + +#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 */ + +/* Misc. macros: */ +/** align value \a l to \a size (ceil) */ +#define ALIGN(l, size) (((l) + ((size) - 1)) / (size) * (size)) + +/** printf style warning MACRO, includes name of function and pid */ +#define IBWARN(fmt, ...) fprintf(stderr, "ibwarn: [%d] %s: " fmt "\n", getpid(), __func__, ## __VA_ARGS__) + +#define IBDEBUG(fmt, ...) fprintf(stdout, "ibdebug: [%d] %s: " fmt "\n", getpid(), __func__, ## __VA_ARGS__) + +#define IBVERBOSE(fmt, ...) fprintf(stdout, "[%d] %s: " fmt "\n", getpid(), __func__, ## __VA_ARGS__) + +#define IBPANIC(fmt, ...) do { \ + fprintf(stderr, "ibpanic: [%d] %s: " fmt ": %m\n", getpid(), __func__, ## __VA_ARGS__); \ + exit(-1); \ +} while(0) + +MAD_EXPORT void xdump(FILE * file, char *msg, void *p, int size); + +END_C_DECLS +#endif /* _MAD_H_ */ diff --git a/branches/WOF2-3/ulp/libibmad/include/infiniband/mad_osd.h b/branches/WOF2-3/ulp/libibmad/include/infiniband/mad_osd.h new file mode 100644 index 00000000..faabaecd --- /dev/null +++ b/branches/WOF2-3/ulp/libibmad/include/infiniband/mad_osd.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef _MAD_OSD_H_ +#define _MAD_OSD_H_ + +#include +#include +#include +#include +#include +#include + +typedef unsigned __int8 uint8_t; +typedef unsigned __int16 uint16_t; +typedef unsigned __int32 uint32_t; +typedef unsigned __int64 uint64_t; + +#define PRId64 "I64d" +#define PRIx64 "I64x" +#define PRIo64 "I64o" +#define PRIu64 "I64u" + +#ifndef MAD_EXPORT +#define MAD_EXPORT __declspec(dllimport) +#endif +#ifndef IBND_EXPORT +#define IBND_EXPORT __declspec(dllimport) +#endif + +#define DEPRECATED + +#if !defined( __cplusplus ) +#define inline __inline +#endif + +#define bswap_64 _byteswap_uint64 +#if !defined(getpid) + #define getpid() GetCurrentProcessId() +#endif +#define snprintf _snprintf +#if !defined(strtoull) +#define strtoull _strtoui64 +#endif +#define __func__ __FUNCTION__ +#define random rand +#define srandom srand + +#endif /* _MAD_OSD_H_ */ diff --git a/branches/WOF2-3/ulp/libibmad/include/windows/config.h b/branches/WOF2-3/ulp/libibmad/include/windows/config.h new file mode 100644 index 00000000..129ca4fe --- /dev/null +++ b/branches/WOF2-3/ulp/libibmad/include/windows/config.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2010 Intel Corp, 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 _CONFIG_H_ +#define _CONFIG_H_ + +#define MAD_EXPORT __declspec(dllexport) + +#endif /* _CONFIG_H_ */ diff --git a/branches/WOF2-3/ulp/libibmad/src/Sources b/branches/WOF2-3/ulp/libibmad/src/Sources new file mode 100644 index 00000000..e7634bb6 --- /dev/null +++ b/branches/WOF2-3/ulp/libibmad/src/Sources @@ -0,0 +1,55 @@ +!if $(FREEBUILD) +TARGETNAME = libibmad +!else +TARGETNAME = libibmadd +!endif + +TARGETPATH = ..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = DYNLINK + +DLLDEF = $(OBJ_PATH)\$O\ibmad_exports.def + +DLLENTRY = DllMain +USE_MSVCRT = 1 + +SOURCES = \ + ibmad_main.cpp \ + bm.c \ + dump.c \ + fields.c \ + gs.c \ + mad.c \ + portid.c \ + register.c \ + resolve.c \ + rpc.c \ + sa.c \ + serv.c \ + smp.c \ + vendor.c + +INCLUDES = ..\include\infiniband;\ + ..\include;..\include\windows;\ + ..\..\libibverbs\include;\ + ..\..\libibumad\include;\ + ..\..\..\inc;\ + ..\..\..\inc\user;\ + ..\..\..\inc\user\linux; + +USER_C_FLAGS = $(USER_C_FLAGS) -DEXPORT_IBMAD_SYMBOLS +C_DEFINES = $(C_DEFINES) /DHAVE_CONFIG_H + +TARGETLIBS = \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\uuid.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ + $(SDK_LIB_PATH)\advapi32.lib \ + $(SDK_LIB_PATH)\user32.lib \ + $(SDK_LIB_PATH)\ole32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\complib.lib \ + $(TARGETPATH)\*\libibumad.lib +!else + $(TARGETPATH)\*\complibd.lib \ + $(TARGETPATH)\*\libibumadd.lib +!endif diff --git a/branches/WOF2-3/ulp/libibmad/src/bm.c b/branches/WOF2-3/ulp/libibmad/src/bm.c new file mode 100644 index 00000000..31814512 --- /dev/null +++ b/branches/WOF2-3/ulp/libibmad/src/bm.c @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2004-2009 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include + +#include + +#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 *bm_call_via(void *data, ib_portid_t * portid, ib_bm_call_t * call, + struct ibmad_port * srcport) +{ + ib_rpc_t rpc = { 0 }; + int resp_expected; + struct { + uint64_t bkey; + uint8_t reserved[32]; + uint8_t data[IB_BM_DATA_SZ]; + } bm_data; + + DEBUG("route %s data %p", portid2str(portid), data); + if (portid->lid <= 0) { + IBWARN("only lid routes are supported"); + return NULL; + } + + resp_expected = response_expected(call->method); + + rpc.mgtclass = IB_BOARD_MGMT_CLASS; + + rpc.method = call->method; + rpc.attr.id = call->attrid; + rpc.attr.mod = call->mod; + rpc.timeout = resp_expected ? call->timeout : 0; + // send data and bkey + rpc.datasz = IB_BM_BKEY_AND_DATA_SZ; + rpc.dataoffs = IB_BM_BKEY_OFFS; + + // copy data to a buffer which also includes the bkey + bm_data.bkey = htonll(call->bkey); + memset(bm_data.reserved, 0, sizeof(bm_data.reserved)); + memcpy(bm_data.data, data, IB_BM_DATA_SZ); + + DEBUG + ("method 0x%x attr 0x%x mod 0x%x datasz %d off %d res_ex %d bkey 0x%08x%08x", + rpc.method, rpc.attr.id, rpc.attr.mod, rpc.datasz, rpc.dataoffs, + resp_expected, (int)(call->bkey >> 32), (int)call->bkey); + + portid->qp = 1; + if (!portid->qkey) + portid->qkey = IB_DEFAULT_QP1_QKEY; + + if (resp_expected) { + /* FIXME: no RMPP for now */ + if (mad_rpc(srcport, &rpc, portid, &bm_data, &bm_data)) + goto return_ok; + return NULL; + } + + if (mad_send_via(&rpc, portid, 0, &bm_data, srcport) < 0) + return NULL; + +return_ok: + memcpy(data, bm_data.data, IB_BM_DATA_SZ); + return data; +} diff --git a/branches/WOF2-3/ulp/libibmad/src/dump.c b/branches/WOF2-3/ulp/libibmad/src/dump.c new file mode 100644 index 00000000..c29f625b --- /dev/null +++ b/branches/WOF2-3/ulp/libibmad/src/dump.c @@ -0,0 +1,787 @@ +/* + * Copyright (c) 2004-2009 Voltaire Inc. All rights reserved. + * Copyright (c) 2007 Xsigo Systems Inc. All rights reserved. + * Copyright (c) 2009 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 2009 HNR Consulting. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +#include + +void mad_dump_int(char *buf, int bufsz, void *val, int valsz) +{ + switch (valsz) { + case 1: + snprintf(buf, bufsz, "%d", *(uint32_t *) val & 0xff); + break; + case 2: + snprintf(buf, bufsz, "%d", *(uint32_t *) val & 0xffff); + 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", *(uint32_t *) val & 0xff); + break; + case 2: + snprintf(buf, bufsz, "%u", *(uint32_t *) val & 0xffff); + 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", *(uint32_t *) val & 0xff); + break; + case 2: + snprintf(buf, bufsz, "0x%04x", *(uint32_t *) val & 0xffff); + 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) 0xffffffffffULL); + break; + case 6: + snprintf(buf, bufsz, "0x%012" PRIx64, + *(uint64_t *) val & (uint64_t) 0xffffffffffffULL); + break; + case 7: + snprintf(buf, bufsz, "0x%014" PRIx64, + *(uint64_t *) val & (uint64_t) 0xffffffffffffffULL); + 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", *(uint32_t *) val & 0xff); + break; + case 2: + snprintf(buf, bufsz, "%04x", *(uint32_t *) val & 0xffff); + 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) 0xffffffffffULL); + break; + case 6: + snprintf(buf, bufsz, "%012" PRIx64, + *(uint64_t *) val & (uint64_t) 0xffffffffffffULL); + break; + case 7: + snprintf(buf, bufsz, "%014" PRIx64, + *(uint64_t *) val & (uint64_t) 0xffffffffffffffULL); + 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 (mask & (1 << 28)) + s += sprintf(s, "\t\t\t\tIsVendorSpecificMadsTableSupported\n"); + if (mask & (1 << 29)) + s += sprintf(s, "\t\t\t\tIsMcastPkeyTrapSuppressionSupported\n"); + if (mask & (1 << 30)) + s += sprintf(s, "\t\t\t\tIsMulticastFDBTopSupported\n"); + if (mask & (1 << 31)) + s += sprintf(s, "\t\t\t\tIsHierarchyInfoSupported\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]; +} 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; + int 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 (int)(s - buf); +} + +void mad_dump_fields(char *buf, int bufsz, void *val, int valsz, int start, + int end) +{ + _dump_fields(buf, bufsz, val, start, end); +} + +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); +} + +void mad_dump_perfcounters_xmt_sl(char *buf, int bufsz, void *val, int valsz) +{ + int cnt; + + cnt = _dump_fields(buf, bufsz, val, IB_PC_EXT_PORT_SELECT_F, + IB_PC_EXT_XMT_BYTES_F); + _dump_fields(buf + cnt, bufsz - cnt, val, IB_PC_XMT_DATA_SL_FIRST_F, + IB_PC_XMT_DATA_SL_LAST_F); +} + +void mad_dump_perfcounters_rcv_sl(char *buf, int bufsz, void *val, int valsz) +{ + int cnt; + + cnt = _dump_fields(buf, bufsz, val, IB_PC_EXT_PORT_SELECT_F, + IB_PC_EXT_XMT_BYTES_F); + _dump_fields(buf + cnt, bufsz - cnt, val, IB_PC_RCV_DATA_SL_FIRST_F, + IB_PC_RCV_DATA_SL_LAST_F); +} + +void mad_dump_perfcounters_xmt_disc(char *buf, int bufsz, void *val, int valsz) +{ + int cnt; + + cnt = _dump_fields(buf, bufsz, val, IB_PC_EXT_PORT_SELECT_F, + IB_PC_EXT_XMT_BYTES_F); + _dump_fields(buf + cnt, bufsz - cnt, val, IB_PC_XMT_INACT_DISC_F, + IB_PC_XMT_DISC_LAST_F); +} + +void mad_dump_perfcounters_rcv_err(char *buf, int bufsz, void *val, int valsz) +{ + int cnt; + + cnt = _dump_fields(buf, bufsz, val, IB_PC_EXT_PORT_SELECT_F, + IB_PC_EXT_XMT_BYTES_F); + _dump_fields(buf + cnt, bufsz - cnt, val, IB_PC_RCV_LOCAL_PHY_ERR_F, + IB_PC_RCV_ERR_LAST_F); +} + +void mad_dump_portsamples_control(char *buf, int bufsz, void *val, int valsz) +{ + _dump_fields(buf, bufsz, val, IB_PSC_OPCODE_F, IB_PSC_LAST_F); +} + +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/branches/WOF2-3/ulp/libibmad/src/fields.c b/branches/WOF2-3/ulp/libibmad/src/fields.c new file mode 100644 index 00000000..a5a510a4 --- /dev/null +++ b/branches/WOF2-3/ulp/libibmad/src/fields.c @@ -0,0 +1,761 @@ +/* + * Copyright (c) 2004-2009 Voltaire Inc. All rights reserved. + * Copyright (c) 2009 HNR Consulting. All rights reserved. + * Copyright (c) 2009 Mellanox Technologies LTD. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +#include + +/* + * BITSOFFS and BE_OFFS are required due the fact that the bit offsets are inconsistently + * encoded in the IB spec - IB headers are encoded such that the bit offsets + * are in big endian convention (BE_OFFS), while the SMI/GSI queries data fields bit + * offsets are specified using real bit offset (?!) + * The following macros normalize everything to big endian offsets. + */ +#define BITSOFFS(o, w) (((o) & ~31) | ((32 - ((o) & 31) - (w)))), (w) +#define BE_OFFS(o, w) (o), (w) +#define BE_TO_BITSOFFS(o, w) (((o) & ~31) | ((32 - ((o) & 31) - (w)))) + +static const ib_field_t ib_mad_f[] = { + {0, 0}, /* IB_NO_FIELD - reserved as invalid */ + + {0, 64, "GidPrefix", mad_dump_rhex}, + {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) */ + {BE_OFFS(0, 7), "MadMethod", mad_dump_hex}, /* TODO: add dumper */ + {BE_OFFS(7, 1), "MadIsResponse", mad_dump_uint}, /* TODO: add dumper */ + {BE_OFFS(8, 8), "MadClassVersion", mad_dump_uint}, + {BE_OFFS(16, 8), "MadMgmtClass", mad_dump_uint}, /* TODO: add dumper */ + {BE_OFFS(24, 8), "MadBaseVersion", mad_dump_uint}, + + /* second MAD word (4-7 bytes) */ + {BE_OFFS(48, 16), "MadStatus", mad_dump_hex}, /* TODO: add dumper */ + + /* DR SMP only */ + {BE_OFFS(32, 8), "DrSmpHopCnt", mad_dump_uint}, + {BE_OFFS(40, 8), "DrSmpHopPtr", mad_dump_uint}, + {BE_OFFS(48, 15), "DrSmpStatus", mad_dump_hex}, /* TODO: add dumper */ + {BE_OFFS(63, 1), "DrSmpDirection", mad_dump_uint}, /* TODO: add dumper */ + + /* words 3,4,5,6 (8-23 bytes) */ + {64, 64, "MadTRID", mad_dump_hex}, + {BE_OFFS(144, 16), "MadAttr", mad_dump_hex}, /* TODO: add dumper */ + {160, 32, "MadModifier", mad_dump_hex}, /* TODO: add dumper */ + + /* word 7,8 (24-31 bytes) */ + {192, 64, "MadMkey", mad_dump_hex}, + + /* word 9 (32-37 bytes) */ + {BE_OFFS(256, 16), "DrSmpDLID", mad_dump_uint}, + {BE_OFFS(272, 16), "DrSmpSLID", mad_dump_uint}, + + /* word 10,11 (36-43 bytes) */ + {288, 64, "SaSMkey", mad_dump_hex}, + + /* word 12 (44-47 bytes) */ + {BE_OFFS(46 * 8, 16), "SaAttrOffs", mad_dump_uint}, + + /* word 13,14 (48-55 bytes) */ + {48 * 8, 64, "SaCompMask", mad_dump_hex}, + + /* word 13,14 (56-255 bytes) */ + {56 * 8, (256 - 56) * 8, "SaData", mad_dump_hex}, + + /* bytes 64 - 127 */ + {0, 0}, /* IB_SM_DATA_F - reserved as invalid */ + + /* bytes 64 - 256 */ + {64 * 8, (256 - 64) * 8, "GsData", mad_dump_hex}, + + /* bytes 128 - 191 */ + {1024, 512, "DrSmpPath", mad_dump_hex}, + + /* bytes 192 - 255 */ + {1536, 512, "DrSmpRetPath", mad_dump_hex}, + + /* + * PortInfo fields + */ + {0, 64, "Mkey", mad_dump_hex}, + {64, 64, "GidPrefix", mad_dump_hex}, + {BITSOFFS(128, 16), "Lid", mad_dump_uint}, + {BITSOFFS(144, 16), "SMLid", mad_dump_uint}, + {160, 32, "CapMask", mad_dump_portcapmask}, + {BITSOFFS(192, 16), "DiagCode", mad_dump_hex}, + {BITSOFFS(208, 16), "MkeyLeasePeriod", mad_dump_uint}, + {BITSOFFS(224, 8), "LocalPort", mad_dump_uint}, + {BITSOFFS(232, 8), "LinkWidthEnabled", mad_dump_linkwidthen}, + {BITSOFFS(240, 8), "LinkWidthSupported", mad_dump_linkwidthsup}, + {BITSOFFS(248, 8), "LinkWidthActive", mad_dump_linkwidth}, + {BITSOFFS(256, 4), "LinkSpeedSupported", mad_dump_linkspeedsup}, + {BITSOFFS(260, 4), "LinkState", mad_dump_portstate}, + {BITSOFFS(264, 4), "PhysLinkState", mad_dump_physportstate}, + {BITSOFFS(268, 4), "LinkDownDefState", mad_dump_linkdowndefstate}, + {BITSOFFS(272, 2), "ProtectBits", mad_dump_uint}, + {BITSOFFS(277, 3), "LMC", mad_dump_uint}, + {BITSOFFS(280, 4), "LinkSpeedActive", mad_dump_linkspeed}, + {BITSOFFS(284, 4), "LinkSpeedEnabled", mad_dump_linkspeeden}, + {BITSOFFS(288, 4), "NeighborMTU", mad_dump_mtu}, + {BITSOFFS(292, 4), "SMSL", mad_dump_uint}, + {BITSOFFS(296, 4), "VLCap", mad_dump_vlcap}, + {BITSOFFS(300, 4), "InitType", mad_dump_hex}, + {BITSOFFS(304, 8), "VLHighLimit", mad_dump_uint}, + {BITSOFFS(312, 8), "VLArbHighCap", mad_dump_uint}, + {BITSOFFS(320, 8), "VLArbLowCap", mad_dump_uint}, + {BITSOFFS(328, 4), "InitReply", mad_dump_hex}, + {BITSOFFS(332, 4), "MtuCap", mad_dump_mtu}, + {BITSOFFS(336, 3), "VLStallCount", mad_dump_uint}, + {BITSOFFS(339, 5), "HoqLife", mad_dump_uint}, + {BITSOFFS(344, 4), "OperVLs", mad_dump_opervls}, + {BITSOFFS(348, 1), "PartEnforceInb", mad_dump_uint}, + {BITSOFFS(349, 1), "PartEnforceOutb", mad_dump_uint}, + {BITSOFFS(350, 1), "FilterRawInb", mad_dump_uint}, + {BITSOFFS(351, 1), "FilterRawOutb", mad_dump_uint}, + {BITSOFFS(352, 16), "MkeyViolations", mad_dump_uint}, + {BITSOFFS(368, 16), "PkeyViolations", mad_dump_uint}, + {BITSOFFS(384, 16), "QkeyViolations", mad_dump_uint}, + {BITSOFFS(400, 8), "GuidCap", mad_dump_uint}, + {BITSOFFS(408, 1), "ClientReregister", mad_dump_uint}, + {BITSOFFS(409, 1), "McastPkeyTrapSuppressionEnabled", mad_dump_uint}, + {BITSOFFS(411, 5), "SubnetTimeout", mad_dump_uint}, + {BITSOFFS(419, 5), "RespTimeVal", mad_dump_uint}, + {BITSOFFS(424, 4), "LocalPhysErr", mad_dump_uint}, + {BITSOFFS(428, 4), "OverrunErr", mad_dump_uint}, + {BITSOFFS(432, 16), "MaxCreditHint", mad_dump_uint}, + {BITSOFFS(456, 24), "RoundTrip", mad_dump_uint}, + {0, 0}, /* IB_PORT_LAST_F */ + + /* + * NodeInfo fields + */ + {BITSOFFS(0, 8), "BaseVers", mad_dump_uint}, + {BITSOFFS(8, 8), "ClassVers", mad_dump_uint}, + {BITSOFFS(16, 8), "NodeType", mad_dump_node_type}, + {BITSOFFS(24, 8), "NumPorts", mad_dump_uint}, + {32, 64, "SystemGuid", mad_dump_hex}, + {96, 64, "Guid", mad_dump_hex}, + {160, 64, "PortGuid", mad_dump_hex}, + {BITSOFFS(224, 16), "PartCap", mad_dump_uint}, + {BITSOFFS(240, 16), "DevId", mad_dump_hex}, + {256, 32, "Revision", mad_dump_hex}, + {BITSOFFS(288, 8), "LocalPort", mad_dump_uint}, + {BITSOFFS(296, 24), "VendorId", mad_dump_hex}, + {0, 0}, /* IB_NODE_LAST_F */ + + /* + * SwitchInfo fields + */ + {BITSOFFS(0, 16), "LinearFdbCap", mad_dump_uint}, + {BITSOFFS(16, 16), "RandomFdbCap", mad_dump_uint}, + {BITSOFFS(32, 16), "McastFdbCap", mad_dump_uint}, + {BITSOFFS(48, 16), "LinearFdbTop", mad_dump_uint}, + {BITSOFFS(64, 8), "DefPort", mad_dump_uint}, + {BITSOFFS(72, 8), "DefMcastPrimPort", mad_dump_uint}, + {BITSOFFS(80, 8), "DefMcastNotPrimPort", mad_dump_uint}, + {BITSOFFS(88, 5), "LifeTime", mad_dump_uint}, + {BITSOFFS(93, 1), "StateChange", mad_dump_uint}, + {BITSOFFS(94, 2), "OptSLtoVLMapping", mad_dump_uint}, + {BITSOFFS(96, 16), "LidsPerPort", mad_dump_uint}, + {BITSOFFS(112, 16), "PartEnforceCap", mad_dump_uint}, + {BITSOFFS(128, 1), "InboundPartEnf", mad_dump_uint}, + {BITSOFFS(129, 1), "OutboundPartEnf", mad_dump_uint}, + {BITSOFFS(130, 1), "FilterRawInbound", mad_dump_uint}, + {BITSOFFS(131, 1), "FilterRawOutbound", mad_dump_uint}, + {BITSOFFS(132, 1), "EnhancedPort0", mad_dump_uint}, + {BITSOFFS(144, 16), "MulticastFDBTop", mad_dump_hex}, + {0, 0}, /* IB_SW_LAST_F */ + + /* + * SwitchLinearForwardingTable fields + */ + {0, 512, "LinearForwTbl", mad_dump_array}, + + /* + * SwitchMulticastForwardingTable fields + */ + {0, 512, "MulticastForwTbl", mad_dump_array}, + + /* + * NodeDescription fields + */ + {0, 64 * 8, "NodeDesc", mad_dump_string}, + + /* + * Notice/Trap fields + */ + {BITSOFFS(0, 1), "NoticeIsGeneric", mad_dump_uint}, + {BITSOFFS(1, 7), "NoticeType", mad_dump_uint}, + {BITSOFFS(8, 24), "NoticeProducerType", mad_dump_node_type}, + {BITSOFFS(32, 16), "NoticeTrapNumber", mad_dump_uint}, + {BITSOFFS(48, 16), "NoticeIssuerLID", mad_dump_uint}, + {BITSOFFS(64, 1), "NoticeToggle", mad_dump_uint}, + {BITSOFFS(65, 15), "NoticeCount", mad_dump_uint}, + {80, 432, "NoticeDataDetails", mad_dump_array}, + {BITSOFFS(80, 16), "NoticeDataLID", mad_dump_uint}, + {BITSOFFS(96, 16), "NoticeDataTrap144LID", mad_dump_uint}, + {BITSOFFS(128, 32), "NoticeDataTrap144CapMask", mad_dump_uint}, + + /* + * Port counters + */ + {BITSOFFS(8, 8), "PortSelect", mad_dump_uint}, + {BITSOFFS(16, 16), "CounterSelect", mad_dump_hex}, + {BITSOFFS(32, 16), "SymbolErrors", mad_dump_uint}, + {BITSOFFS(48, 8), "LinkRecovers", mad_dump_uint}, + {BITSOFFS(56, 8), "LinkDowned", mad_dump_uint}, + {BITSOFFS(64, 16), "RcvErrors", mad_dump_uint}, + {BITSOFFS(80, 16), "RcvRemotePhysErrors", mad_dump_uint}, + {BITSOFFS(96, 16), "RcvSwRelayErrors", mad_dump_uint}, + {BITSOFFS(112, 16), "XmtDiscards", mad_dump_uint}, + {BITSOFFS(128, 8), "XmtConstraintErrors", mad_dump_uint}, + {BITSOFFS(136, 8), "RcvConstraintErrors", mad_dump_uint}, + {BITSOFFS(144, 8), "CounterSelect2", mad_dump_hex}, + {BITSOFFS(152, 4), "LinkIntegrityErrors", mad_dump_uint}, + {BITSOFFS(156, 4), "ExcBufOverrunErrors", mad_dump_uint}, + {BITSOFFS(176, 16), "VL15Dropped", mad_dump_uint}, + {192, 32, "XmtData", mad_dump_uint}, + {224, 32, "RcvData", mad_dump_uint}, + {256, 32, "XmtPkts", mad_dump_uint}, + {288, 32, "RcvPkts", mad_dump_uint}, + {320, 32, "XmtWait", mad_dump_uint}, + {0, 0}, /* IB_PC_LAST_F */ + + /* + * SMInfo + */ + {0, 64, "SmInfoGuid", mad_dump_hex}, + {64, 64, "SmInfoKey", mad_dump_hex}, + {128, 32, "SmActivity", mad_dump_uint}, + {BITSOFFS(160, 4), "SmPriority", mad_dump_uint}, + {BITSOFFS(164, 4), "SmState", mad_dump_uint}, + + /* + * SA RMPP + */ + {BE_OFFS(24 * 8 + 24, 8), "RmppVers", mad_dump_uint}, + {BE_OFFS(24 * 8 + 16, 8), "RmppType", mad_dump_uint}, + {BE_OFFS(24 * 8 + 11, 5), "RmppResp", mad_dump_uint}, + {BE_OFFS(24 * 8 + 8, 3), "RmppFlags", mad_dump_hex}, + {BE_OFFS(24 * 8 + 0, 8), "RmppStatus", mad_dump_hex}, + + /* data1 */ + {28 * 8, 32, "RmppData1", mad_dump_hex}, + {28 * 8, 32, "RmppSegNum", mad_dump_uint}, + /* data2 */ + {32 * 8, 32, "RmppData2", mad_dump_hex}, + {32 * 8, 32, "RmppPayload", mad_dump_uint}, + {32 * 8, 32, "RmppNewWin", mad_dump_uint}, + + /* + * SA Get Multi Path + */ + {BITSOFFS(41, 7), "MultiPathNumPath", mad_dump_uint}, + {BITSOFFS(120, 8), "MultiPathNumSrc", mad_dump_uint}, + {BITSOFFS(128, 8), "MultiPathNumDest", mad_dump_uint}, + {192, 128, "MultiPathGid", mad_dump_array}, + + /* + * SA Path rec + */ + {64, 128, "PathRecDGid", mad_dump_array}, + {192, 128, "PathRecSGid", mad_dump_array}, + {BITSOFFS(320, 16), "PathRecDLid", mad_dump_uint}, + {BITSOFFS(336, 16), "PathRecSLid", mad_dump_uint}, + {BITSOFFS(393, 7), "PathRecNumPath", mad_dump_uint}, + {BITSOFFS(428, 4), "PathRecSL", mad_dump_uint}, + + /* + * MC Member rec + */ + {0, 128, "McastMemMGid", mad_dump_array}, + {128, 128, "McastMemPortGid", mad_dump_array}, + {256, 32, "McastMemQkey", mad_dump_hex}, + {BITSOFFS(288, 16), "McastMemMLid", mad_dump_hex}, + {BITSOFFS(352, 4), "McastMemSL", mad_dump_uint}, + {BITSOFFS(306, 6), "McastMemMTU", mad_dump_uint}, + {BITSOFFS(338, 6), "McastMemRate", mad_dump_uint}, + {BITSOFFS(312, 8), "McastMemTClass", mad_dump_uint}, + {BITSOFFS(320, 16), "McastMemPkey", mad_dump_uint}, + {BITSOFFS(356, 20), "McastMemFlowLbl", mad_dump_uint}, + {BITSOFFS(388, 4), "McastMemJoinState", mad_dump_uint}, + {BITSOFFS(392, 1), "McastMemProxyJoin", mad_dump_uint}, + + /* + * Service record + */ + {0, 64, "ServRecID", mad_dump_hex}, + {64, 128, "ServRecGid", mad_dump_array}, + {BITSOFFS(192, 16), "ServRecPkey", mad_dump_hex}, + {224, 32, "ServRecLease", mad_dump_hex}, + {256, 128, "ServRecKey", mad_dump_hex}, + {384, 512, "ServRecName", mad_dump_string}, + {896, 512, "ServRecData", mad_dump_array}, /* ATS for example */ + + /* + * ATS SM record - within SA_SR_DATA + */ + {12 * 8, 32, "ATSNodeAddr", mad_dump_hex}, + {BITSOFFS(16 * 8, 16), "ATSMagicKey", mad_dump_hex}, + {BITSOFFS(18 * 8, 16), "ATSNodeType", mad_dump_hex}, + {32 * 8, 32 * 8, "ATSNodeName", mad_dump_string}, + + /* + * SLTOVL MAPPING TABLE + */ + {0, 64, "SLToVLMap", mad_dump_hex}, + + /* + * VL ARBITRATION TABLE + */ + {0, 512, "VLArbTbl", mad_dump_array}, + + /* + * IB vendor classes range 2 + */ + {BE_OFFS(36 * 8, 24), "OUI", mad_dump_array}, + {40 * 8, (256 - 40) * 8, "Vendor2Data", mad_dump_array}, + + /* + * Extended port counters + */ + {BITSOFFS(8, 8), "PortSelect", mad_dump_uint}, + {BITSOFFS(16, 16), "CounterSelect", mad_dump_hex}, + {64, 64, "PortXmitData", mad_dump_uint}, + {128, 64, "PortRcvData", mad_dump_uint}, + {192, 64, "PortXmitPkts", mad_dump_uint}, + {256, 64, "PortRcvPkts", mad_dump_uint}, + {320, 64, "PortUnicastXmitPkts", mad_dump_uint}, + {384, 64, "PortUnicastRcvPkts", mad_dump_uint}, + {448, 64, "PortMulticastXmitPkts", mad_dump_uint}, + {512, 64, "PortMulticastRcvPkts", mad_dump_uint}, + {0, 0}, /* IB_PC_EXT_LAST_F */ + + /* + * GUIDInfo fields + */ + {0, 64, "GUID0", mad_dump_hex}, + + /* + * ClassPortInfo fields + */ + {BITSOFFS(0, 8), "BaseVersion", mad_dump_uint}, + {BITSOFFS(8, 8), "ClassVersion", mad_dump_uint}, + {BITSOFFS(16, 16), "CapabilityMask", mad_dump_hex}, + {BITSOFFS(32, 27), "CapabilityMask2", mad_dump_hex}, + {BITSOFFS(59, 5), "RespTimeVal", mad_dump_uint}, + {64, 128, "RedirectGID", mad_dump_array}, + {BITSOFFS(192, 8), "RedirectTC", mad_dump_hex}, + {BITSOFFS(200, 4), "RedirectSL", mad_dump_uint}, + {BITSOFFS(204, 20), "RedirectFL", mad_dump_hex}, + {BITSOFFS(224, 16), "RedirectLID", mad_dump_uint}, + {BITSOFFS(240, 16), "RedirectPKey", mad_dump_hex}, + {BITSOFFS(264, 24), "RedirectQP", mad_dump_hex}, + {288, 32, "RedirectQKey", mad_dump_hex}, + {320, 128, "TrapGID", mad_dump_array}, + {BITSOFFS(448, 8), "TrapTC", mad_dump_hex}, + {BITSOFFS(456, 4), "TrapSL", mad_dump_uint}, + {BITSOFFS(460, 20), "TrapFL", mad_dump_hex}, + {BITSOFFS(480, 16), "TrapLID", mad_dump_uint}, + {BITSOFFS(496, 16), "TrapPKey", mad_dump_hex}, + {BITSOFFS(512, 8), "TrapHL", mad_dump_uint}, + {BITSOFFS(520, 24), "TrapQP", mad_dump_hex}, + {544, 32, "TrapQKey", mad_dump_hex}, + + /* + * PortXmitDataSL fields + */ + {32, 32, "XmtDataSL0", mad_dump_uint}, + {64, 32, "XmtDataSL1", mad_dump_uint}, + {96, 32, "XmtDataSL2", mad_dump_uint}, + {128, 32, "XmtDataSL3", mad_dump_uint}, + {160, 32, "XmtDataSL4", mad_dump_uint}, + {192, 32, "XmtDataSL5", mad_dump_uint}, + {224, 32, "XmtDataSL6", mad_dump_uint}, + {256, 32, "XmtDataSL7", mad_dump_uint}, + {288, 32, "XmtDataSL8", mad_dump_uint}, + {320, 32, "XmtDataSL9", mad_dump_uint}, + {352, 32, "XmtDataSL10", mad_dump_uint}, + {384, 32, "XmtDataSL11", mad_dump_uint}, + {416, 32, "XmtDataSL12", mad_dump_uint}, + {448, 32, "XmtDataSL13", mad_dump_uint}, + {480, 32, "XmtDataSL14", mad_dump_uint}, + {512, 32, "XmtDataSL15", mad_dump_uint}, + {0, 0}, /* IB_PC_XMT_DATA_SL_LAST_F */ + + /* + * PortRcvDataSL fields + */ + {32, 32, "RcvDataSL0", mad_dump_uint}, + {64, 32, "RcvDataSL1", mad_dump_uint}, + {96, 32, "RcvDataSL2", mad_dump_uint}, + {128, 32, "RcvDataSL3", mad_dump_uint}, + {160, 32, "RcvDataSL4", mad_dump_uint}, + {192, 32, "RcvDataSL5", mad_dump_uint}, + {224, 32, "RcvDataSL6", mad_dump_uint}, + {256, 32, "RcvDataSL7", mad_dump_uint}, + {288, 32, "RcvDataSL8", mad_dump_uint}, + {320, 32, "RcvDataSL9", mad_dump_uint}, + {352, 32, "RcvDataSL10", mad_dump_uint}, + {384, 32, "RcvDataSL11", mad_dump_uint}, + {416, 32, "RcvDataSL12", mad_dump_uint}, + {448, 32, "RcvDataSL13", mad_dump_uint}, + {480, 32, "RcvDataSL14", mad_dump_uint}, + {512, 32, "RcvDataSL15", mad_dump_uint}, + {0, 0}, /* IB_PC_RCV_DATA_SL_LAST_F */ + + /* + * PortXmitDiscardDetails fields + */ + {32, 16, "PortInactiveDiscards", mad_dump_uint}, + {48, 16, "PortNeighborMTUDiscards", mad_dump_uint}, + {64, 16, "PortSwLifetimeLimitDiscards", mad_dump_uint}, + {80, 16, "PortSwHOQLifetimeLimitDiscards", mad_dump_uint}, + {0, 0}, /* IB_PC_XMT_DISC_LAST_F */ + + /* + * PortRcvErrorDetails fields + */ + {32, 16, "PortLocalPhysicalErrors", mad_dump_uint}, + {48, 16, "PortMalformedPktErrors", mad_dump_uint}, + {64, 16, "PortBufferOverrunErrors", mad_dump_uint}, + {80, 16, "PortDLIDMappingErrors", mad_dump_uint}, + {96, 16, "PortVLMappingErrors", mad_dump_uint}, + {112, 16, "PortLoopingErrors", mad_dump_uint}, + {0, 0}, /* IB_PC_RCV_ERR_LAST_F */ + + /* + * PortSamplesControl fields + */ + {BITSOFFS(0, 8), "OpCode", mad_dump_hex}, + {BITSOFFS(8, 8), "PortSelect", mad_dump_uint}, + {BITSOFFS(16, 8), "Tick", mad_dump_hex}, + {BITSOFFS(29, 3), "CounterWidth", mad_dump_uint}, + {BITSOFFS(34, 3), "CounterMask0", mad_dump_hex}, + {BITSOFFS(37, 27), "CounterMasks1to9", mad_dump_hex}, + {BITSOFFS(65, 15), "CounterMasks10to14", mad_dump_hex}, + {BITSOFFS(80, 8), "SampleMechanisms", mad_dump_uint}, + {BITSOFFS(94, 2), "SampleStatus", mad_dump_uint}, + {96, 64, "OptionMask", mad_dump_hex}, + {160, 64, "VendorMask", mad_dump_hex}, + {224, 32, "SampleStart", mad_dump_uint}, + {256, 32, "SampleInterval", mad_dump_uint}, + {288, 16, "Tag", mad_dump_hex}, + {304, 16, "CounterSelect0", mad_dump_hex}, + {320, 16, "CounterSelect1", mad_dump_hex}, + {336, 16, "CounterSelect2", mad_dump_hex}, + {352, 16, "CounterSelect3", mad_dump_hex}, + {368, 16, "CounterSelect4", mad_dump_hex}, + {384, 16, "CounterSelect5", mad_dump_hex}, + {400, 16, "CounterSelect6", mad_dump_hex}, + {416, 16, "CounterSelect7", mad_dump_hex}, + {432, 16, "CounterSelect8", mad_dump_hex}, + {448, 16, "CounterSelect9", mad_dump_hex}, + {464, 16, "CounterSelect10", mad_dump_hex}, + {480, 16, "CounterSelect11", mad_dump_hex}, + {496, 16, "CounterSelect12", mad_dump_hex}, + {512, 16, "CounterSelect13", mad_dump_hex}, + {528, 16, "CounterSelect14", mad_dump_hex}, + {576, 64, "SamplesOnlyOptionMask", mad_dump_hex}, + {0, 0}, /* IB_PSC_LAST_F */ + + {0, 0} /* IB_FIELD_LAST_ */ + +}; + +static void _set_field64(void *buf, int base_offs, const 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)); +} + +static uint64_t _get_field64(void *buf, int base_offs, const ib_field_t * f) +{ + uint64_t val; + memcpy(&val, ((char *)buf + base_offs + f->bitoffs / 8), + sizeof(uint64_t)); + return ntohll(val); +} + +static void _set_field(void *buf, int base_offs, const 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; + } +} + +static uint32_t _get_field(void *buf, int base_offs, const 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 */ +static void _set_array(void *buf, int base_offs, const 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); +} + +static void _get_array(void *buf, int base_offs, const 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); +} + +uint32_t mad_get_field(void *buf, int base_offs, enum MAD_FIELDS field) +{ + return _get_field(buf, base_offs, ib_mad_f + field); +} + +void mad_set_field(void *buf, int base_offs, enum MAD_FIELDS field, + uint32_t val) +{ + _set_field(buf, base_offs, ib_mad_f + field, val); +} + +uint64_t mad_get_field64(void *buf, int base_offs, enum MAD_FIELDS field) +{ + return _get_field64(buf, base_offs, ib_mad_f + field); +} + +void mad_set_field64(void *buf, int base_offs, enum MAD_FIELDS field, + uint64_t val) +{ + _set_field64(buf, base_offs, ib_mad_f + field, val); +} + +void mad_set_array(void *buf, int base_offs, enum MAD_FIELDS field, void *val) +{ + _set_array(buf, base_offs, ib_mad_f + field, val); +} + +void mad_get_array(void *buf, int base_offs, enum MAD_FIELDS field, void *val) +{ + _get_array(buf, base_offs, ib_mad_f + field, val); +} + +void mad_decode_field(uint8_t * buf, enum MAD_FIELDS field, void *val) +{ + const 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, enum MAD_FIELDS field, void *val) +{ + const 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); +} + +/************************/ + +static char *_mad_dump_val(const 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; +} + +static char *_mad_dump_field(const ib_field_t * f, const char *name, char *buf, + int bufsz, void *val) +{ + char dots[128]; + int l, n; + + if (bufsz <= 32) + return NULL; /* 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; +} + +static int _mad_dump(ib_mad_dump_fn * fn, const char *name, void *val, + int valsz) +{ + ib_field_t f; + char buf[512]; + + f.def_dump_fn = fn; + f.bitlen = valsz * 8; + + return printf("%s\n", _mad_dump_field(&f, name, buf, sizeof buf, val)); +} + +static int _mad_print_field(const ib_field_t * f, const 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); +} + +int mad_print_field(enum MAD_FIELDS field, const 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); +} + +char *mad_dump_field(enum MAD_FIELDS field, char *buf, int bufsz, void *val) +{ + if (field <= IB_NO_FIELD || field >= IB_FIELD_LAST_) + return NULL; + return _mad_dump_field(ib_mad_f + field, 0, buf, bufsz, val); +} + +char *mad_dump_val(enum MAD_FIELDS field, char *buf, int bufsz, void *val) +{ + if (field <= IB_NO_FIELD || field >= IB_FIELD_LAST_) + return NULL; + return _mad_dump_val(ib_mad_f + field, buf, bufsz, val); +} + +const char *mad_field_name(enum MAD_FIELDS field) +{ + return (ib_mad_f[field].name); +} diff --git a/branches/WOF2-3/ulp/libibmad/src/gs.c b/branches/WOF2-3/ulp/libibmad/src/gs.c new file mode 100644 index 00000000..3cb2b25a --- /dev/null +++ b/branches/WOF2-3/ulp/libibmad/src/gs.c @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2004-2009 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +#include +#include + +#undef DEBUG +#define DEBUG if (ibdebug) IBWARN + +uint8_t *pma_query_via(void *rcvbuf, ib_portid_t * dest, int port, + unsigned timeout, unsigned id, + const struct ibmad_port * srcport) +{ + ib_rpc_t rpc = { 0 }; + int lid = dest->lid; + + DEBUG("lid %u port %d", lid, port); + + if (lid == -1) { + IBWARN("only lid routed is supported"); + return NULL; + } + + 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; + + if (!dest->qp) + dest->qp = 1; + if (!dest->qkey) + dest->qkey = IB_DEFAULT_QP1_QKEY; + + return mad_rpc(srcport, &rpc, dest, rcvbuf, rcvbuf); +} + +uint8_t *performance_reset_via(void *rcvbuf, ib_portid_t * dest, + int port, unsigned mask, unsigned timeout, + unsigned id, const struct ibmad_port * srcport) +{ + ib_rpc_t rpc = { 0 }; + int lid = dest->lid; + + DEBUG("lid %u port %d mask 0x%x", lid, port, mask); + + if (lid == -1) { + IBWARN("only lid routed is supported"); + return NULL; + } + + 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); + mask = mask >> 16; + mad_set_field(rcvbuf, 0, IB_PC_COUNTER_SELECT2_F, mask); + rpc.attr.mod = 0; + rpc.timeout = timeout; + rpc.datasz = IB_PC_DATA_SZ; + rpc.dataoffs = IB_PC_DATA_OFFS; + if (!dest->qp) + dest->qp = 1; + if (!dest->qkey) + dest->qkey = IB_DEFAULT_QP1_QKEY; + + return mad_rpc(srcport, &rpc, dest, rcvbuf, rcvbuf); +} diff --git a/branches/WOF2-3/ulp/libibmad/src/ibmad.rc b/branches/WOF2-3/ulp/libibmad/src/ibmad.rc new file mode 100644 index 00000000..d4491108 --- /dev/null +++ b/branches/WOF2-3/ulp/libibmad/src/ibmad.rc @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + +#include + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef DBG +#define VER_FILEDESCRIPTION_STR "LibIbMad (Debug)" +#define VER_INTERNALNAME_STR "LibIbMadd.dll" +#define VER_ORIGINALFILENAME_STR "LibIbMadd.dll" +#else +#define VER_FILEDESCRIPTION_STR "LibIbMad" +#define VER_INTERNALNAME_STR "LibIbMad.dll" +#define VER_ORIGINALFILENAME_STR "LibIbMad.dll" +#endif + +#include diff --git a/branches/WOF2-3/ulp/libibmad/src/ibmad_export.def b/branches/WOF2-3/ulp/libibmad/src/ibmad_export.def new file mode 100644 index 00000000..4a7e62ea --- /dev/null +++ b/branches/WOF2-3/ulp/libibmad/src/ibmad_export.def @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2008-2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +LIBRARY LIBIBMAD.DLL + +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE diff --git a/branches/WOF2-3/ulp/libibmad/src/ibmad_exports.src b/branches/WOF2-3/ulp/libibmad/src/ibmad_exports.src new file mode 100644 index 00000000..00e1b449 --- /dev/null +++ b/branches/WOF2-3/ulp/libibmad/src/ibmad_exports.src @@ -0,0 +1,47 @@ +#if DBG +LIBRARY libibmadd.dll +#else +LIBRARY libibmad.dll +#endif + +#ifndef _WIN64 +EXPORTS + mad_set_field; + mad_get_field; + mad_set_array; + mad_get_array; + mad_set_field64; + mad_get_field64; + mad_decode_field; + mad_encode_field; + mad_encode; + mad_trid; + mad_build_pkt; + mad_register_port_client; + mad_register_client; + mad_register_server; + mad_class_agent; + mad_send; + mad_receive; + mad_respond; + mad_alloc; + mad_free; + madrpc_portid; + madrpc_init; + madrpc_set_retries; + madrpc_set_timeout; + madrpc_show_errors; + smp_query; + smp_set; + smp_query_via; + ib_vendor_call; + ib_path_query; + ib_resolve_smlid; + ib_resolve_portid_str; + ib_resolve_self; + portid2str; + portid2portnum; + str2drpath; + drpath2str; + xdump +#endif diff --git a/branches/WOF2-3/ulp/libibmad/src/ibmad_main.cpp b/branches/WOF2-3/ulp/libibmad/src/ibmad_main.cpp new file mode 100644 index 00000000..d95ba153 --- /dev/null +++ b/branches/WOF2-3/ulp/libibmad/src/ibmad_main.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2008-2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include + +#if WINVER < 0x600 +#include "..\..\..\..\etc\user\inet.c" +#endif + +BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) +{ + UNREFERENCED_PARAMETER(hInstance); + UNREFERENCED_PARAMETER(dwReason); + UNREFERENCED_PARAMETER(lpReserved); + + return TRUE; +} diff --git a/branches/WOF2-3/ulp/libibmad/src/libibmad.map b/branches/WOF2-3/ulp/libibmad/src/libibmad.map new file mode 100644 index 00000000..5778e3e9 --- /dev/null +++ b/branches/WOF2-3/ulp/libibmad/src/libibmad.map @@ -0,0 +1,114 @@ +IBMAD_1.3 { + global: + xdump; + 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_fields; + mad_dump_perfcounters; + mad_dump_perfcounters_ext; + mad_dump_perfcounters_xmt_sl; + mad_dump_perfcounters_rcv_sl; + mad_dump_perfcounters_xmt_disc; + mad_dump_perfcounters_rcv_err; + mad_dump_physportstate; + mad_dump_portcapmask; + mad_dump_portinfo; + mad_dump_portsamples_control; + 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; + mad_get_field; + mad_set_field; + mad_get_field64; + mad_set_field64; + mad_get_array; + mad_set_array; + pma_query_via; + performance_reset_via; + mad_build_pkt; + mad_decode_field; + mad_encode; + mad_encode_field; + mad_trid; + portid2portnum; + portid2str; + str2drpath; + drpath2str; + mad_class_agent; + mad_register_client; + mad_register_server; + mad_register_client_via; + mad_register_server_via; + ib_resolve_portid_str; + ib_resolve_self; + ib_resolve_smlid; + ibdebug; + mad_rpc_open_port; + mad_rpc_close_port; + mad_rpc; + mad_rpc_rmpp; + mad_rpc_portid; + mad_rpc_class_agent; + mad_rpc_set_retries; + mad_rpc_set_timeout; + mad_get_timeout; + mad_get_retries; + madrpc; + madrpc_def_timeout; + madrpc_init; + madrpc_portid; + madrpc_rmpp; + madrpc_save_mad; + madrpc_set_retries; + madrpc_set_timeout; + madrpc_show_errors; + ib_path_query; + sa_call; + sa_rpc_call; + mad_alloc; + mad_free; + mad_receive; + mad_respond; + mad_receive_via; + mad_respond_via; + mad_send; + mad_send_via; + smp_query; + smp_set; + ib_vendor_call; + ib_vendor_call_via; + smp_query_via; + smp_set_via; + ib_path_query_via; + ib_resolve_smlid_via; + ib_resolve_guid_via; + ib_resolve_gid_via; + ib_resolve_portid_str_via; + ib_resolve_self_via; + mad_field_name; + bm_call_via; + local: *; +}; diff --git a/branches/WOF2-3/ulp/libibmad/src/mad.c b/branches/WOF2-3/ulp/libibmad/src/mad.c new file mode 100644 index 00000000..acd0e85b --- /dev/null +++ b/branches/WOF2-3/ulp/libibmad/src/mad.c @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2004-2009 Voltaire Inc. All rights reserved. + * Copyright (c) 2009 HNR Consulting. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include + +#include +#include + +#include "mad_internal.h" + +#undef DEBUG +#define DEBUG if (ibdebug) IBWARN + +uint64_t mad_trid(void) +{ + static uint64_t base; + static uint64_t trid; + uint64_t next; + + if (!base) { + srandom((int)time(0) * getpid()); + base = random(); + trid = random(); + } + next = ++trid | (base << 32); + return next; +} + +int mad_get_timeout(const struct ibmad_port *srcport, int override_ms) +{ + return (override_ms ? override_ms : + srcport->timeout ? srcport->timeout : madrpc_timeout); +} + +int mad_get_retries(const struct ibmad_port *srcport) +{ + return (srcport->retries ? srcport->retries : madrpc_retries); +} + +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 NULL; + } + if (drpath->cnt >= IB_SUBNET_PATH_HOPS_MAX) { + IBWARN("dr path with hop count %d", drpath->cnt); + return NULL; + } + 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_field64(buf, 0, IB_MAD_MKEY_F, rpc->mkey); + + 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 (!p) + return -1; + + 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 ((int)(p - mad)); +} diff --git a/branches/WOF2-3/ulp/libibmad/src/mad_internal.h b/branches/WOF2-3/ulp/libibmad/src/mad_internal.h new file mode 100644 index 00000000..3c32d100 --- /dev/null +++ b/branches/WOF2-3/ulp/libibmad/src/mad_internal.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2004-2009 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_INTERNAL_H_ +#define _MAD_INTERNAL_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 timeout, retries; +}; + +extern struct ibmad_port *ibmp; +extern int madrpc_timeout; +extern int madrpc_retries; + +#endif /* _MAD_INTERNAL_H_ */ diff --git a/branches/WOF2-3/ulp/libibmad/src/makefile b/branches/WOF2-3/ulp/libibmad/src/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-3/ulp/libibmad/src/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\inc\openib.def diff --git a/branches/WOF2-3/ulp/libibmad/src/portid.c b/branches/WOF2-3/ulp/libibmad/src/portid.c new file mode 100644 index 00000000..ceb685ec --- /dev/null +++ b/branches/WOF2-3/ulp/libibmad/src/portid.c @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2004-2009 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include + +#include + +#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] = (uint8_t) 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 %u; dlid %u; %d", + path->drslid, path->drdlid, path->p[0]); + if (rc >= (int)dstr_size) + return dstr; + for (i = 1; i <= path->cnt; i++) { + rc += snprintf(dstr + rc, dstr_size - rc, ",%d", path->p[i]); + if (rc >= (int)dstr_size) + break; + } + return (dstr); +} diff --git a/branches/WOF2-3/ulp/libibmad/src/register.c b/branches/WOF2-3/ulp/libibmad/src/register.c new file mode 100644 index 00000000..0ff8006a --- /dev/null +++ b/branches/WOF2-3/ulp/libibmad/src/register.c @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2004-2009 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include + +#include +#include + +#include "mad_internal.h" + +#undef DEBUG +#define DEBUG if (ibdebug) IBWARN + +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; + case IB_BOARD_MGMT_CLASS: + return 1; + } + + return 0; +} + +int mad_class_agent(int mgmt) +{ + if (mgmt < 1 || mgmt > MAX_CLASS) + return -1; + return ibmp->class_agents[mgmt]; +} + +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; + } + + agent = umad_register(port_id, mgmt, vers, rmpp_version, 0); + if (agent < 0) + DEBUG("Can't register agent for class %d", mgmt); + + return agent; +} + +int mad_register_client(int mgmt, uint8_t rmpp_version) +{ + return mad_register_client_via(mgmt, rmpp_version, ibmp); +} + +int mad_register_client_via(int mgmt, uint8_t rmpp_version, + struct ibmad_port *srcport) +{ + int agent; + + if (!srcport) + return -1; + + agent = mad_register_port_client(mad_rpc_portid(srcport), mgmt, + rmpp_version); + if (agent < 0) + return agent; + + srcport->class_agents[mgmt] = agent; + return 0; +} + +int mad_register_server(int mgmt, uint8_t rmpp_version, + long method_mask[], uint32_t class_oui) +{ + return mad_register_server_via(mgmt, rmpp_version, method_mask, + class_oui, ibmp); +} + +int mad_register_server_via(int mgmt, uint8_t rmpp_version, + long method_mask[], uint32_t class_oui, + struct ibmad_port *srcport) +{ + long class_method_mask[16 / sizeof(long)]; + uint8_t oui[3]; + int agent, vers; + + if (method_mask) + memcpy(class_method_mask, method_mask, + sizeof class_method_mask); + else + memset(class_method_mask, 0xff, sizeof(class_method_mask)); + + if (!srcport) + return -1; + + if (srcport->class_agents[mgmt] >= 0) { + DEBUG("Class 0x%x already registered %d", + mgmt, srcport->class_agents[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(srcport->port_id, mgmt, rmpp_version, + oui, class_method_mask)) < 0) { + DEBUG("Can't register agent for class %d", mgmt); + return -1; + } + } else + if ((agent = + umad_register(srcport->port_id, mgmt, vers, rmpp_version, + class_method_mask)) < 0) { + DEBUG("Can't register agent for class %d", mgmt); + return -1; + } + + srcport->class_agents[mgmt] = agent; + + return agent; +} diff --git a/branches/WOF2-3/ulp/libibmad/src/resolve.c b/branches/WOF2-3/ulp/libibmad/src/resolve.c new file mode 100644 index 00000000..f866bf4c --- /dev/null +++ b/branches/WOF2-3/ulp/libibmad/src/resolve.c @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2004-2009 Voltaire Inc. All rights reserved. + * Copyright (c) 2009 HNR Consulting. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include + +#include +#include +#include "mad_internal.h" + +#undef DEBUG +#define DEBUG if (ibdebug) IBWARN + +int ib_resolve_smlid_via(ib_portid_t * sm_id, int timeout, + const struct ibmad_port *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); + mad_decode_field(portinfo, IB_PORT_SMSL_F, &sm_id->sl); + + 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, ibmp); +} + +int ib_resolve_gid_via(ib_portid_t * portid, ibmad_gid_t gid, + ib_portid_t * sm_id, int timeout, + const struct ibmad_port *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 ((portid->lid = + ib_path_query_via(srcport, gid, gid, sm_id, buf)) < 0) + return -1; + + return 0; +} + +int ib_resolve_guid_via(ib_portid_t * portid, uint64_t * guid, + ib_portid_t * sm_id, int timeout, + const struct ibmad_port *srcport) +{ + ib_portid_t sm_portid; + uint8_t buf[IB_SA_DATA_SIZE] = { 0 }; + ib_portid_t self = { 0 }; + uint64_t selfguid, prefix; + ibmad_gid_t selfgid; + uint8_t nodeinfo[64]; + + if (!sm_id) { + sm_id = &sm_portid; + if (ib_resolve_smlid_via(sm_id, timeout, srcport) < 0) + return -1; + } + + if (!smp_query_via(nodeinfo, &self, IB_ATTR_NODE_INFO, 0, 0, srcport)) + return -1; + mad_decode_field(nodeinfo, IB_NODE_PORT_GUID_F, &selfguid); + mad_set_field64(selfgid, 0, IB_GID_PREFIX_F, IB_DEFAULT_SUBN_PREFIX); + mad_set_field64(selfgid, 0, IB_GID_GUID_F, selfguid); + + memcpy(&prefix, portid->gid, sizeof(prefix)); + if (!prefix) + 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, selfgid, portid->gid, sm_id, buf)) < 0) + return -1; + + mad_decode_field(buf, IB_SA_PR_SL_F, &portid->sl); + return 0; +} + +int ib_resolve_portid_str_via(ib_portid_t * portid, char *addr_str, + enum MAD_DEST dest_type, ib_portid_t * sm_id, + const struct ibmad_port *srcport) +{ + ibmad_gid_t gid; + uint64_t guid; + int lid; + char *routepath; + ib_portid_t selfportid = { 0 }; + int selfport = 0; + + memset(portid, 0, sizeof *portid); + + 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; + + case IB_DEST_GID: + if (inet_pton(AF_INET6, addr_str, &gid) <= 0) + return -1; + return ib_resolve_gid_via(portid, gid, sm_id, 0, srcport); + default: + IBWARN("bad dest_type %d", dest_type); + } + + return -1; +} + +int ib_resolve_portid_str(ib_portid_t * portid, char *addr_str, + enum MAD_DEST dest_type, ib_portid_t * sm_id) +{ + return ib_resolve_portid_str_via(portid, addr_str, dest_type, + sm_id, ibmp); +} + +int ib_resolve_self_via(ib_portid_t * portid, int *portnum, ibmad_gid_t * gid, + const struct ibmad_port *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_SMSL_F, &portid->sl); + 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, ibmp); +} diff --git a/branches/WOF2-3/ulp/libibmad/src/rpc.c b/branches/WOF2-3/ulp/libibmad/src/rpc.c new file mode 100644 index 00000000..c5246fed --- /dev/null +++ b/branches/WOF2-3/ulp/libibmad/src/rpc.c @@ -0,0 +1,418 @@ +/* + * Copyright (c) 2004-2009 Voltaire Inc. All rights reserved. + * Copyright (c) 2009 HNR Consulting. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include + +#include +#include + +#include "mad_internal.h" + +int ibdebug; + +static struct ibmad_port mad_port; +struct ibmad_port *ibmp = &mad_port; + +static int iberrs; + +int madrpc_retries = MAD_DEF_RETRIES; +int 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(fmt, ...) do { \ + if (iberrs || ibdebug) \ + IBWARN(fmt, ## __VA_ARGS__); \ +} while (0) + +#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) +{ + madrpc_timeout = timeout; + return 0; +} + +void mad_rpc_set_retries(struct ibmad_port *port, int retries) +{ + port->retries = retries; +} + +void mad_rpc_set_timeout(struct ibmad_port *port, int timeout) +{ + port->timeout = timeout; +} + +int madrpc_def_timeout(void) +{ + return madrpc_timeout; +} + +int madrpc_portid(void) +{ + return ibmp->port_id; +} + +int mad_rpc_portid(struct ibmad_port *srcport) +{ + return srcport->port_id; +} + +int mad_rpc_class_agent(struct ibmad_port *port, int class) +{ + if (class < 1 || class > MAX_CLASS) + return -1; + return port->class_agents[class]; +} + +static int +_do_madrpc(int port_id, void *sndbuf, void *rcvbuf, int agentid, int len, + int timeout, int max_retries) +{ + uint32_t trid; /* only low 32 bits */ + int retries; + int length, status; + + 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 = + (uint32_t) mad_get_field64(umad_get_mad(sndbuf), 0, IB_MAD_TRID_F); + + for (retries = 0; retries < max_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; %m"); + return -1; + } + + /* Use same timeout on receive side just in case */ + /* send packet is lost somewhere. */ + do { + length = len; + if (umad_recv(port_id, rcvbuf, &length, timeout) < 0) { + IBWARN("recv failed: %m"); + 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; +} + +static int redirect_port(ib_portid_t * port, uint8_t * mad) +{ + port->lid = mad_get_field(mad, 64, IB_CPI_REDIRECT_LID_F); + if (!port->lid) { + IBWARN("GID-based redirection is not supported"); + return -1; + } + + port->qp = mad_get_field(mad, 64, IB_CPI_REDIRECT_QP_F); + port->qkey = mad_get_field(mad, 64, IB_CPI_REDIRECT_QKEY_F); + port->sl = (uint8_t) mad_get_field(mad, 64, IB_CPI_REDIRECT_SL_F); + + /* TODO: Reverse map redirection P_Key to P_Key index */ + + if (ibdebug) + IBWARN("redirected to lid %d, qp 0x%x, qkey 0x%x, sl 0x%x", + port->lid, port->qp, port->qkey, port->sl); + + return 0; +} + +void *mad_rpc(const struct ibmad_port *port, ib_rpc_t * rpc, + ib_portid_t * dport, void *payload, void *rcvdata) +{ + int status, len; + uint8_t sndbuf[1024], rcvbuf[1024], *mad; + int redirect = 1; + + while (redirect) { + len = 0; + memset(sndbuf, 0, umad_size() + IB_MAD_SIZE); + + if ((len = mad_build_pkt(sndbuf, rpc, dport, 0, payload)) < 0) + return NULL; + + if ((len = _do_madrpc(port->port_id, sndbuf, rcvbuf, + port->class_agents[rpc->mgtclass], + len, mad_get_timeout(port, rpc->timeout), + mad_get_retries(port))) < 0) { + IBWARN("_do_madrpc failed; dport (%s)", + portid2str(dport)); + return NULL; + } + + mad = umad_get_mad(rcvbuf); + status = mad_get_field(mad, 0, IB_DRSMP_STATUS_F); + + /* check for exact match instead of only the redirect bit; + * that way, weird statuses cause an error, too */ + if (status == IB_MAD_STS_REDIRECT) { + /* update dport for next request and retry */ + /* bail if redirection fails */ + if (redirect_port(dport, mad)) + redirect = 0; + } else + redirect = 0; + } + + if (status != 0) { + ERRS("MAD completed with error status 0x%x; dport (%s)", + status, portid2str(dport)); + return NULL; + } + + 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 struct ibmad_port *port, ib_rpc_t * rpc, + ib_portid_t * dport, ib_rmpp_hdr_t * rmpp, void *data) +{ + 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 NULL; + + if ((len = _do_madrpc(port->port_id, sndbuf, rcvbuf, + port->class_agents[rpc->mgtclass], + len, mad_get_timeout(port, rpc->timeout), + mad_get_retries(port))) < 0) { + IBWARN("_do_madrpc failed; dport (%s)", portid2str(dport)); + return NULL; + } + + 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 NULL; + } + + 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 NULL; + } + 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) +{ + return mad_rpc(ibmp, rpc, dport, payload, rcvdata); +} + +void *madrpc_rmpp(ib_rpc_t * rpc, ib_portid_t * dport, ib_rmpp_hdr_t * rmpp, + void *data) +{ + return mad_rpc_rmpp(ibmp, rpc, dport, rmpp, data); +} + +void +madrpc_init(char *dev_name, int dev_port, int *mgmt_classes, int num_classes) +{ + int fd; + + if (umad_init() < 0) + IBPANIC("can't init UMAD library"); + + if ((fd = 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); + + ibmp->port_id = fd; + memset(ibmp->class_agents, 0xff, sizeof ibmp->class_agents); + while (num_classes--) { + uint8_t rmpp_version = 0; + int mgmt = *mgmt_classes++; + + if (mgmt == IB_SA_CLASS) + rmpp_version = 1; + if (mad_register_client_via(mgmt, rmpp_version, ibmp) < 0) + IBPANIC("client_register for mgmt class %d failed", + mgmt); + } +} + +struct ibmad_port *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; + } + + p->port_id = port_id; + memset(p->class_agents, 0xff, sizeof p->class_agents); + while (num_classes--) { + uint8_t rmpp_version = 0; + int mgmt = *mgmt_classes++; + + if (mgmt == IB_SA_CLASS) + rmpp_version = 1; + if (mgmt < 0 || mgmt >= MAX_CLASS || + mad_register_client_via(mgmt, rmpp_version, p) < 0) { + IBWARN("client_register for mgmt %d failed", mgmt); + if (!errno) + errno = EINVAL; + umad_close_port(port_id); + free(p); + return NULL; + } + } + + return p; +} + +void mad_rpc_close_port(struct ibmad_port *port) +{ + umad_close_port(port->port_id); + free(port); +} diff --git a/branches/WOF2-3/ulp/libibmad/src/sa.c b/branches/WOF2-3/ulp/libibmad/src/sa.c new file mode 100644 index 00000000..a9a93ccc --- /dev/null +++ b/branches/WOF2-3/ulp/libibmad/src/sa.c @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2004-2009 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +#include +#include "mad_internal.h" + +#undef DEBUG +#define DEBUG if (ibdebug) IBWARN + +uint8_t *sa_rpc_call(const struct ibmad_port *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 NULL; + } + + 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; +} + +uint8_t *sa_call(void *rcvbuf, ib_portid_t * portid, ib_sa_call_t * sa, + unsigned timeout) +{ + return sa_rpc_call(ibmp, rcvbuf, portid, sa, timeout); +} + +/* 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) + +int ib_path_query_via(const struct ibmad_port *srcport, ibmad_gid_t srcgid, + ibmad_gid_t destgid, ib_portid_t * sm_id, void *buf) +{ + ib_sa_call_t sa = { 0 }; + uint8_t *p; + int dlid; + + 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_DGID_F, destgid); + mad_encode_field(buf, IB_SA_PR_SGID_F, srcgid); + + p = sa_rpc_call(srcport, 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(ibmp, srcgid, destgid, sm_id, buf); +} diff --git a/branches/WOF2-3/ulp/libibmad/src/serv.c b/branches/WOF2-3/ulp/libibmad/src/serv.c new file mode 100644 index 00000000..df61f259 --- /dev/null +++ b/branches/WOF2-3/ulp/libibmad/src/serv.c @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2004-2009 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +#include +#include + +#include "mad_internal.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) +{ + return mad_send_via(rpc, dport, rmpp, data, ibmp); +} + +int mad_send_via(ib_rpc_t * rpc, ib_portid_t * dport, ib_rmpp_hdr_t * rmpp, + void *data, struct ibmad_port *srcport) +{ + uint8_t pktbuf[1024]; + void *umad = pktbuf; + + memset(pktbuf, 0, umad_size() + IB_MAD_SIZE); + + DEBUG("rmpp %p data %p", rmpp, data); + + if (mad_build_pkt(umad, rpc, dport, rmpp, data) < 0) + return -1; + + 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(srcport->port_id, srcport->class_agents[rpc->mgtclass], + umad, IB_MAD_SIZE, mad_get_timeout(srcport, rpc->timeout), + 0) < 0) { + IBWARN("send failed; %m"); + return -1; + } + + return 0; +} + +int mad_respond(void *umad, ib_portid_t * portid, uint32_t rstatus) +{ + return mad_respond_via(umad, portid, rstatus, ibmp); +} + +int mad_respond_via(void *umad, ib_portid_t * portid, uint32_t rstatus, + struct ibmad_port *srcport) +{ + 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); + rpc.rstatus = rstatus; + + /* 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 + (srcport->port_id, srcport->class_agents[rpc.mgtclass], umad, + IB_MAD_SIZE, mad_get_timeout(srcport, rpc.timeout), 0) < 0) { + DEBUG("send failed; %m"); + return -1; + } + + return 0; +} + +void *mad_receive(void *umad, int timeout) +{ + return mad_receive_via(umad, timeout, ibmp); +} + +void *mad_receive_via(void *umad, int timeout, struct ibmad_port *srcport) +{ + void *mad = umad ? umad : umad_alloc(1, umad_size() + IB_MAD_SIZE); + int agent; + int length = IB_MAD_SIZE; + + if ((agent = umad_recv(srcport->port_id, mad, &length, + mad_get_timeout(srcport, 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/branches/WOF2-3/ulp/libibmad/src/smp.c b/branches/WOF2-3/ulp/libibmad/src/smp.c new file mode 100644 index 00000000..3ff58ce4 --- /dev/null +++ b/branches/WOF2-3/ulp/libibmad/src/smp.c @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2004-2009 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +#include +#include "mad_internal.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 struct ibmad_port *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; + + return mad_rpc(srcport, &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, ibmp); +} + +uint8_t *smp_query_via(void *rcvbuf, ib_portid_t * portid, unsigned attrid, + unsigned mod, unsigned timeout, + const struct ibmad_port * 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; + + return mad_rpc(srcport, &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, ibmp); +} diff --git a/branches/WOF2-3/ulp/libibmad/src/vendor.c b/branches/WOF2-3/ulp/libibmad/src/vendor.c new file mode 100644 index 00000000..11efd76e --- /dev/null +++ b/branches/WOF2-3/ulp/libibmad/src/vendor.c @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2004-2009 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +#include +#include "mad_internal.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) +{ + return ib_vendor_call_via(data, portid, call, ibmp); +} + +uint8_t *ib_vendor_call_via(void *data, ib_portid_t * portid, + ib_vendor_call_t * call, + struct ibmad_port * srcport) +{ + ib_rpc_t rpc = { 0 }; + int range1 = 0, resp_expected; + + DEBUG("route %s data %p", portid2str(portid), data); + if (portid->lid <= 0) + return NULL; /* no direct SMI */ + + if (!(range1 = mad_is_vendor_range1(call->mgmt_class)) && + !(mad_is_vendor_range2(call->mgmt_class))) + return NULL; + + 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 mad_rpc_rmpp(srcport, &rpc, portid, 0, data); /* FIXME: no RMPP for now */ + + return mad_send_via(&rpc, portid, 0, data, srcport) < 0 ? 0 : data; /* FIXME: no RMPP for now */ +} diff --git a/branches/WOF2-3/ulp/libibnetdisc/README.txt b/branches/WOF2-3/ulp/libibnetdisc/README.txt new file mode 100644 index 00000000..7c82b7e7 --- /dev/null +++ b/branches/WOF2-3/ulp/libibnetdisc/README.txt @@ -0,0 +1,19 @@ +[1-06-09] + +These 'shared' OFED files (shared between Linux and Windows) are mirrored here for the convience +of Windows developers. + +The 'offical' OFED source files are located in the OFED git repository. + +The policy is 'no source file changes' in non-build files (.h & .c) are accepted here. +Any source file changes here will likely be overwritten when refreshed from the OFED git repository. + +The plan here is to have a single Linux and Windows source. + +If you require source file changes, push the changes to the OFED maintainers. + +For continuing policy discussion, please contact sean.hefty@intel.com + +thank you, + +Stan (stan.smith@intel.com) \ No newline at end of file diff --git a/branches/WOF2-3/ulp/libibnetdisc/dirs b/branches/WOF2-3/ulp/libibnetdisc/dirs new file mode 100644 index 00000000..b1cbe453 --- /dev/null +++ b/branches/WOF2-3/ulp/libibnetdisc/dirs @@ -0,0 +1,2 @@ +DIRS = \ + src \ No newline at end of file diff --git a/branches/WOF2-3/ulp/libibnetdisc/include/infiniband/ibnetdisc.h b/branches/WOF2-3/ulp/libibnetdisc/include/infiniband/ibnetdisc.h new file mode 100644 index 00000000..49ff7434 --- /dev/null +++ b/branches/WOF2-3/ulp/libibnetdisc/include/infiniband/ibnetdisc.h @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2008 Lawrence Livermore National Lab. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION 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 _IBNETDISC_H_ +#define _IBNETDISC_H_ + +#include +#include +#include + +struct ibnd_chassis; /* forward declare */ +struct ibnd_port; /* forward declare */ + +/** ========================================================================= + * Node + */ +typedef struct ibnd_node { + struct ibnd_node *next; /* all node list in fabric */ + + ib_portid_t path_portid; /* path from "from_node" */ + uint16_t smalid; + uint8_t smalmc; + + /* quick cache of switchinfo below */ + int smaenhsp0; + /* use libibmad decoder functions for switchinfo */ + uint8_t switchinfo[IB_SMP_DATA_SIZE]; + + /* quick cache of info below */ + uint64_t guid; + int type; + int numports; + /* use libibmad decoder functions for info */ + uint8_t info[IB_SMP_DATA_SIZE]; + + char nodedesc[IB_SMP_DATA_SIZE]; + + struct ibnd_port **ports; /* array of ports, indexed by port number + ports[1] == port 1, + ports[2] == port 2, + etc... + Any port in the array MAY BE NULL! + Most notable is non-switches have no + port 0 therefore node.ports[0] == NULL + for those nodes */ + + /* chassis info */ + struct ibnd_node *next_chassis_node; /* next node in ibnd_chassis_t->nodes */ + struct ibnd_chassis *chassis; /* if != NULL the chassis this node belongs to */ + unsigned char ch_type; + unsigned char ch_anafanum; + unsigned char ch_slotnum; + unsigned char ch_slot; + + /* internal use only */ + unsigned char ch_found; + struct ibnd_node *htnext; /* hash table list */ + struct ibnd_node *type_next; /* next based on type */ +} ibnd_node_t; + +/** ========================================================================= + * Port + */ +typedef struct ibnd_port { + uint64_t guid; + int portnum; + int ext_portnum; /* optional if != 0 external port num */ + ibnd_node_t *node; /* node this port belongs to */ + struct ibnd_port *remoteport; /* null if SMA, or does not exist */ + /* quick cache of info below */ + uint16_t base_lid; + uint8_t lmc; + /* use libibmad decoder functions for info */ + uint8_t info[IB_SMP_DATA_SIZE]; + + /* internal use only */ + struct ibnd_port *htnext; +} ibnd_port_t; + +/** ========================================================================= + * Chassis + */ +typedef struct ibnd_chassis { + struct ibnd_chassis *next; + uint64_t chassisguid; + unsigned char chassisnum; + + /* generic grouping by SystemImageGUID */ + unsigned char nodecount; + ibnd_node_t *nodes; + + /* specific to voltaire type nodes */ +#define SPINES_MAX_NUM 18 +#define LINES_MAX_NUM 36 + ibnd_node_t *spinenode[SPINES_MAX_NUM + 1]; + ibnd_node_t *linenode[LINES_MAX_NUM + 1]; +} ibnd_chassis_t; + +#define HTSZ 137 + +typedef struct ibnd_config { + unsigned max_smps; + unsigned show_progress; + unsigned max_hops; + unsigned debug; + unsigned timeout_ms; + unsigned retries; + uint8_t pad[56]; +} ibnd_config_t; + +/** ========================================================================= + * Fabric + * Main fabric object which is returned and represents the data discovered + */ +typedef struct ibnd_fabric { + /* the node the discover was initiated from + * "from" parameter in ibnd_discover_fabric + * or by default the node you ar running on + */ + ibnd_node_t *from_node; + /* NULL term list of all nodes in the fabric */ + ibnd_node_t *nodes; + /* NULL terminated list of all chassis found in the fabric */ + ibnd_chassis_t *chassis; + unsigned maxhops_discovered; + unsigned total_mads_used; + + /* internal use only */ + ibnd_node_t *nodestbl[HTSZ]; + ibnd_port_t *portstbl[HTSZ]; + ibnd_node_t *switches; + ibnd_node_t *ch_adapters; + ibnd_node_t *routers; +} ibnd_fabric_t; + +/** ========================================================================= + * Initialization (fabric operations) + */ + +IBND_EXPORT ibnd_fabric_t *ibnd_discover_fabric(char * ca_name, + int ca_port, + ib_portid_t * from, + struct ibnd_config *config); + /** + * ca_name: (optional) name of the CA to use + * ca_port: (optional) CA port to use + * from: (optional) specify the node to start scanning from. + * If NULL start from the CA/CA port specified + * config: (optional) additional config options for the scan + */ +IBND_EXPORT void ibnd_destroy_fabric(ibnd_fabric_t * fabric); + +IBND_EXPORT ibnd_fabric_t *ibnd_load_fabric(const char *file, + unsigned int flags); + +IBND_EXPORT int ibnd_cache_fabric(ibnd_fabric_t * fabric, const char *file, + unsigned int flags); + +/** ========================================================================= + * Node operations + */ +IBND_EXPORT ibnd_node_t *ibnd_find_node_guid(ibnd_fabric_t * fabric, + uint64_t guid); +IBND_EXPORT ibnd_node_t *ibnd_find_node_dr(ibnd_fabric_t * fabric, char *dr_str); + +typedef void (*ibnd_iter_node_func_t) (ibnd_node_t * node, void *user_data); +IBND_EXPORT void ibnd_iter_nodes(ibnd_fabric_t * fabric, + ibnd_iter_node_func_t func, void *user_data); +IBND_EXPORT void ibnd_iter_nodes_type(ibnd_fabric_t * fabric, + ibnd_iter_node_func_t func, + int node_type, void *user_data); + +/** ========================================================================= + * Chassis queries + */ +IBND_EXPORT uint64_t ibnd_get_chassis_guid(ibnd_fabric_t * fabric, + unsigned char chassisnum); +IBND_EXPORT char *ibnd_get_chassis_type(ibnd_node_t * node); +IBND_EXPORT char *ibnd_get_chassis_slot_str(ibnd_node_t * node, + char *str, size_t size); + +IBND_EXPORT int ibnd_is_xsigo_guid(uint64_t guid); +IBND_EXPORT int ibnd_is_xsigo_tca(uint64_t guid); +IBND_EXPORT int ibnd_is_xsigo_hca(uint64_t guid); + +#endif /* _IBNETDISC_H_ */ diff --git a/branches/WOF2-3/ulp/libibnetdisc/include/windows/config.h b/branches/WOF2-3/ulp/libibnetdisc/include/windows/config.h new file mode 100644 index 00000000..e4739932 --- /dev/null +++ b/branches/WOF2-3/ulp/libibnetdisc/include/windows/config.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2009 Intel Corp, 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 _CONFIG_H_ +#define _CONFIG_H_ + +#include <_errno.h> +#include +#include +#include + +#define ssize_t SSIZE_T +#define read _read +#define write _write +#define stat _stat +#define open _open +#define close _close +#define lseek _lseek +#define unlink _unlink + +#define IBND_EXPORT __declspec(dllexport) + +#endif /* _CONFIG_H_ */ diff --git a/branches/WOF2-3/ulp/libibnetdisc/src/Sources b/branches/WOF2-3/ulp/libibnetdisc/src/Sources new file mode 100644 index 00000000..f67686d6 --- /dev/null +++ b/branches/WOF2-3/ulp/libibnetdisc/src/Sources @@ -0,0 +1,45 @@ +!if $(FREEBUILD) +TARGETNAME = libibnetdisc +!else +TARGETNAME = libibnetdiscd +!endif + +TARGETPATH = ..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = DYNLINK + +DLLDEF = $(OBJ_PATH)\$O\ibnetdisc_exports.def + +DLLENTRY = DllMain +USE_MSVCRT = 1 + +SOURCES = ibnetdisc_main.cpp ibnetdisc.c chassis.c query_smp.c ibnetdisc_cache.c + +INCLUDES = ..\include\infiniband;\ + ..\include;..\include\windows;\ + ..\..\libibmad\include;\ + ..\..\..\tools\infiniband-diags\include;\ + ..\..\libibverbs\include;\ + ..\..\libibumad\include;\ + ..\..\..\inc;\ + ..\..\..\inc\user;\ + ..\..\..\inc\user\linux; + +USER_C_FLAGS = $(USER_C_FLAGS) +C_DEFINES = $(C_DEFINES) /DHAVE_CONFIG_H + +TARGETLIBS = \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\uuid.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ + $(SDK_LIB_PATH)\advapi32.lib \ + $(SDK_LIB_PATH)\user32.lib \ + $(SDK_LIB_PATH)\ole32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\libibumad.lib \ + $(TARGETPATH)\*\libibmad.lib \ + $(TARGETPATH)\*\complib.lib +!else + $(TARGETPATH)\*\libibumadd.lib \ + $(TARGETPATH)\*\libibmadd.lib \ + $(TARGETPATH)\*\complibd.lib +!endif diff --git a/branches/WOF2-3/ulp/libibnetdisc/src/chassis.c b/branches/WOF2-3/ulp/libibnetdisc/src/chassis.c new file mode 100644 index 00000000..25d7473a --- /dev/null +++ b/branches/WOF2-3/ulp/libibnetdisc/src/chassis.c @@ -0,0 +1,1115 @@ +/* + * Copyright (c) 2004-2009 Voltaire Inc. All rights reserved. + * Copyright (c) 2007 Xsigo Systems Inc. All rights reserved. + * Copyright (c) 2008 Lawrence Livermore National Lab. All rights reserved. + * Copyright (c) 2010 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. + * + */ + +/*========================================================*/ +/* FABRIC SCANNER SPECIFIC DATA */ +/*========================================================*/ + +#if HAVE_CONFIG_H +#include +#endif /* HAVE_CONFIG_H */ + +#include +#include + +#include + +#include "internal.h" +#include "chassis.h" + +static char *ChassisTypeStr[6] = +{ "", "ISR9288", "ISR9096", "ISR2012", "ISR2004", "ISR4700" }; +static char *ChassisSlotTypeStr[4] = { "", "Line", "Spine", "SRBD" }; + +typedef struct chassis_scan { + ibnd_chassis_t *first_chassis; + ibnd_chassis_t *current_chassis; + ibnd_chassis_t *last_chassis; +} chassis_scan_t; + +char *ibnd_get_chassis_type(ibnd_node_t * node) +{ + if (!node) { + IBND_DEBUG("node parameter NULL\n"); + return NULL; + } + + /* Currently, only if Voltaire chassis */ + if (mad_get_field(node->info, 0, IB_NODE_VENDORID_F) != VTR_VENDOR_ID) + return NULL; + if (!node->chassis) + return NULL; + if (node->ch_type == UNRESOLVED_CT || node->ch_type > ISR4700_CT) + return NULL; + return ChassisTypeStr[node->ch_type]; +} + +char *ibnd_get_chassis_slot_str(ibnd_node_t * node, char *str, size_t size) +{ + if (!node) { + IBND_DEBUG("node parameter NULL\n"); + return NULL; + } + + /* Currently, only if Voltaire chassis */ + if (mad_get_field(node->info, 0, IB_NODE_VENDORID_F) != VTR_VENDOR_ID) + return NULL; + if (!node->chassis) + return NULL; + if (node->ch_slot == UNRESOLVED_CS || node->ch_slot > SRBD_CS) + return NULL; + if (!str) + return NULL; + snprintf(str, size, "%s %d Chip %d", ChassisSlotTypeStr[node->ch_slot], + node->ch_slotnum, node->ch_anafanum); + return str; +} + +static ibnd_chassis_t *find_chassisnum(ibnd_fabric_t * fabric, + unsigned char chassisnum) +{ + ibnd_chassis_t *current; + + for (current = fabric->chassis; 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 ibnd_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 ibnd_is_xsigo_hca(uint64_t guid) +{ + /* NodeType 2 is HCA */ + if ((guid & 0xffffffff00000000ULL) == 0x0013970200000000ULL) + return 1; + else + return 0; +} + +int ibnd_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 (ibnd_is_xsigo_hca(guid) || ibnd_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(ibnd_node_t * node) +{ + uint64_t sysimgguid = + mad_get_field64(node->info, 0, IB_NODE_SYSTEM_GUID_F); + uint64_t remote_sysimgguid; + + if (!is_xsigo_ca(sysimgguid)) { + /* Byte 3 is NodeType and byte 4 is PortType */ + /* If NodeType is 1 (switch), PortType is masked */ + if (is_xsigo_switch(sysimgguid)) + return sysimgguid & 0xffffffff00ffffffULL; + else + return sysimgguid; + } else { + if (!node->ports || !node->ports[1]) + return 0; + + /* Is there a peer port ? */ + if (!node->ports[1]->remoteport) + return sysimgguid; + + /* If peer port is Leaf 1, use its chassis GUID */ + remote_sysimgguid = + mad_get_field64(node->ports[1]->remoteport->node->info, 0, + IB_NODE_SYSTEM_GUID_F); + if (is_xsigo_leafone(remote_sysimgguid)) + return remote_sysimgguid & 0xffffffff00ffffffULL; + else + return sysimgguid; + } +} + +static uint64_t get_chassisguid(ibnd_node_t * node) +{ + uint32_t vendid = mad_get_field(node->info, 0, IB_NODE_VENDORID_F); + uint64_t sysimgguid = + mad_get_field64(node->info, 0, IB_NODE_SYSTEM_GUID_F); + + if (vendid == TS_VENDOR_ID || vendid == SS_VENDOR_ID) + return topspin_chassisguid(sysimgguid); + else if (vendid == XS_VENDOR_ID || ibnd_is_xsigo_guid(sysimgguid)) + return xsigo_chassisguid(node); + else + return sysimgguid; +} + +static ibnd_chassis_t *find_chassisguid(ibnd_fabric_t * fabric, + ibnd_node_t * node) +{ + ibnd_chassis_t *current; + uint64_t chguid; + + chguid = get_chassisguid(node); + for (current = fabric->chassis; current; current = current->next) + if (current->chassisguid == chguid) + return current; + + return NULL; +} + +uint64_t ibnd_get_chassis_guid(ibnd_fabric_t * fabric, unsigned char chassisnum) +{ + ibnd_chassis_t *chassis; + + if (!fabric) { + IBND_DEBUG("fabric parameter NULL\n"); + return 0; + } + + chassis = find_chassisnum(fabric, chassisnum); + if (chassis) + return chassis->chassisguid; + else + return 0; +} + +static int is_router(ibnd_node_t * n) +{ + uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F); + return (devid == VTR_DEVID_IB_FC_ROUTER || + devid == VTR_DEVID_IB_IP_ROUTER); +} + +static int is_spine_9096(ibnd_node_t * n) +{ + uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F); + return (devid == VTR_DEVID_SFB4 || devid == VTR_DEVID_SFB4_DDR); +} + +static int is_spine_9288(ibnd_node_t * n) +{ + uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F); + return (devid == VTR_DEVID_SFB12 || devid == VTR_DEVID_SFB12_DDR); +} + +static int is_spine_2004(ibnd_node_t * n) +{ + uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F); + return (devid == VTR_DEVID_SFB2004); +} + +static int is_spine_2012(ibnd_node_t * n) +{ + uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F); + return (devid == VTR_DEVID_SFB2012); +} + +static int is_spine_4700(ibnd_node_t * n) +{ + uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F); + return (devid == VTR_DEVID_SFB4700); +} + +static int is_spine_4700x2(ibnd_node_t * n) +{ + uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F); + return (devid == VTR_DEVID_SFB4700X2); +} + +static int is_spine(ibnd_node_t * n) +{ + return (is_spine_9096(n) || is_spine_9288(n) || + is_spine_2004(n) || is_spine_2012(n) || + is_spine_4700(n) || is_spine_4700x2(n)); +} + +static int is_line_24(ibnd_node_t * n) +{ + uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F); + return (devid == VTR_DEVID_SLB24 || + devid == VTR_DEVID_SLB24_DDR || devid == VTR_DEVID_SRB2004); +} + +static int is_line_8(ibnd_node_t * n) +{ + uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F); + return (devid == VTR_DEVID_SLB8); +} + +static int is_line_2024(ibnd_node_t * n) +{ + uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F); + return (devid == VTR_DEVID_SLB2024); +} + +static int is_line_4700(ibnd_node_t * n) +{ + uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F); + return (devid == VTR_DEVID_SLB4018); +} + +static int is_line(ibnd_node_t * n) +{ + return (is_line_24(n) || is_line_8(n) || + is_line_2024(n) || is_line_4700(n)); +} + +int is_chassis_switch(ibnd_node_t * n) +{ + return (is_spine(n) || is_line(n)); +} + +/* these structs help find Line (Anafa) slot number while using spine portnum */ +char line_slot_2_sfb4[37] = { + 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; +char anafa_line_slot_2_sfb4[37] = { + 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +char line_slot_2_sfb12[37] = { + 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; +char anafa_line_slot_2_sfb12[37] = { + 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* LB slot = table[spine port] */ +char line_slot_2_sfb18[37] = { + 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, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18}; +/* LB asic num = table[spine port] */ +char anafa_line_slot_2_sfb18[37] = { + 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 +}; + +/* LB slot = table[spine port] */ +char line_slot_2_sfb18x2[37] = { + 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +/* LB asic num = table[spine port] */ +char anafa_line_slot_2_sfb18x2[37] = { + 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* IPR FCR modules connectivity while using sFB4 port as reference */ +char ipr_slot_2_sfb4_port[37] = { + 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* these structs help find Spine (Anafa) slot number while using spine portnum */ +char spine12_slot_2_slb[37] = { + 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; +char anafa_spine12_slot_2_slb[37] = { + 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +char spine4_slot_2_slb[37] = { + 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; +char anafa_spine4_slot_2_slb[37] = { + 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* FB slot = table[line port] */ +char spine18_slot_2_slb[37] = { + 0, + 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; +/* FB asic = table[line port] */ +char anafa_spine18_slot_2_slb[37] = { + 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; +char anafa_spine18x2_slot_2_slb[37] = { + 0, + 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, + 0, 0, 0, 0, 0, 0, 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 int get_sfb_slot(ibnd_node_t * n, ibnd_port_t * lineport) +{ + n->ch_slot = SPINE_CS; + if (is_spine_9096(n)) { + n->ch_type = ISR9096_CT; + n->ch_slotnum = spine4_slot_2_slb[lineport->portnum]; + n->ch_anafanum = anafa_spine4_slot_2_slb[lineport->portnum]; + } else if (is_spine_9288(n)) { + n->ch_type = ISR9288_CT; + n->ch_slotnum = spine12_slot_2_slb[lineport->portnum]; + n->ch_anafanum = anafa_spine12_slot_2_slb[lineport->portnum]; + } else if (is_spine_2012(n)) { + n->ch_type = ISR2012_CT; + n->ch_slotnum = spine12_slot_2_slb[lineport->portnum]; + n->ch_anafanum = anafa_spine12_slot_2_slb[lineport->portnum]; + } else if (is_spine_2004(n)) { + n->ch_type = ISR2004_CT; + n->ch_slotnum = spine4_slot_2_slb[lineport->portnum]; + n->ch_anafanum = anafa_spine4_slot_2_slb[lineport->portnum]; + } else if (is_spine_4700(n)) { + n->ch_type = ISR4700_CT; + n->ch_slotnum = spine18_slot_2_slb[lineport->portnum]; + n->ch_anafanum = anafa_spine18_slot_2_slb[lineport->portnum]; + } else if (is_spine_4700x2(n)) { + n->ch_type = ISR4700_CT; + n->ch_slotnum = spine18_slot_2_slb[lineport->portnum]; + n->ch_anafanum = anafa_spine18x2_slot_2_slb[lineport->portnum]; + } else { + IBND_ERROR("Unexpected node found: guid 0x%016" PRIx64 "\n", + n->guid); + return -1; + } + return 0; +} + +static int get_router_slot(ibnd_node_t * n, ibnd_port_t * spineport) +{ + uint64_t guessnum = 0; + + n->ch_found = 1; + + n->ch_slot = SRBD_CS; + if (is_spine_9096(spineport->node)) { + n->ch_type = ISR9096_CT; + n->ch_slotnum = line_slot_2_sfb4[spineport->portnum]; + n->ch_anafanum = ipr_slot_2_sfb4_port[spineport->portnum]; + } else if (is_spine_9288(spineport->node)) { + n->ch_type = ISR9288_CT; + n->ch_slotnum = line_slot_2_sfb12[spineport->portnum]; + /* this is a smart guess based on nodeguids order on sFB-12 module */ + guessnum = spineport->node->guid % 4; + /* module 1 <--> remote anafa 3 */ + /* module 2 <--> remote anafa 2 */ + /* module 3 <--> remote anafa 1 */ + n->ch_anafanum = (guessnum == 3 ? 1 : (guessnum == 1 ? 3 : 2)); + } else if (is_spine_2012(spineport->node)) { + n->ch_type = ISR2012_CT; + n->ch_slotnum = line_slot_2_sfb12[spineport->portnum]; + /* this is a smart guess based on nodeguids order on sFB-12 module */ + guessnum = spineport->node->guid % 4; + // module 1 <--> remote anafa 3 + // module 2 <--> remote anafa 2 + // module 3 <--> remote anafa 1 + n->ch_anafanum = (guessnum == 3 ? 1 : (guessnum == 1 ? 3 : 2)); + } else if (is_spine_2004(spineport->node)) { + n->ch_type = ISR2004_CT; + n->ch_slotnum = line_slot_2_sfb4[spineport->portnum]; + n->ch_anafanum = ipr_slot_2_sfb4_port[spineport->portnum]; + } else { + IBND_ERROR("Unexpected node found: guid 0x%016" PRIx64 "\n", + spineport->node->guid); + return -1; + } + return 0; +} + +static int get_slb_slot(ibnd_node_t * n, ibnd_port_t * spineport) +{ + n->ch_slot = LINE_CS; + if (is_spine_9096(spineport->node)) { + n->ch_type = ISR9096_CT; + n->ch_slotnum = line_slot_2_sfb4[spineport->portnum]; + n->ch_anafanum = anafa_line_slot_2_sfb4[spineport->portnum]; + } else if (is_spine_9288(spineport->node)) { + n->ch_type = ISR9288_CT; + n->ch_slotnum = line_slot_2_sfb12[spineport->portnum]; + n->ch_anafanum = anafa_line_slot_2_sfb12[spineport->portnum]; + } else if (is_spine_2012(spineport->node)) { + n->ch_type = ISR2012_CT; + n->ch_slotnum = line_slot_2_sfb12[spineport->portnum]; + n->ch_anafanum = anafa_line_slot_2_sfb12[spineport->portnum]; + } else if (is_spine_2004(spineport->node)) { + n->ch_type = ISR2004_CT; + n->ch_slotnum = line_slot_2_sfb4[spineport->portnum]; + n->ch_anafanum = anafa_line_slot_2_sfb4[spineport->portnum]; + } else if (is_spine_4700(spineport->node)) { + n->ch_type = ISR4700_CT; + n->ch_slotnum = line_slot_2_sfb18[spineport->portnum]; + n->ch_anafanum = anafa_line_slot_2_sfb18[spineport->portnum]; + } else if (is_spine_4700x2(spineport->node)) { + n->ch_type = ISR4700_CT; + n->ch_slotnum = line_slot_2_sfb18x2[spineport->portnum]; + n->ch_anafanum = anafa_line_slot_2_sfb18x2[spineport->portnum]; + } else { + IBND_ERROR("Unexpected node found: guid 0x%016" PRIx64 "\n", + spineport->node->guid); + return -1; + } + return 0; +} + +/* forward declare this */ +static void voltaire_portmap(ibnd_port_t * port); +/* + 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 int fill_voltaire_chassis_record(ibnd_node_t * node) +{ + int p = 0; + ibnd_port_t *port; + ibnd_node_t *remnode = 0; + + if (node->ch_found) /* somehow this node has already been passed */ + return 0; + node->ch_found = 1; + + /* 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)) + /* find the remote node */ + for (p = 1; p <= node->numports; p++) { + port = node->ports[p]; + if (port && is_spine(port->remoteport->node)) + get_router_slot(node, port->remoteport); + } + else if (is_spine(node)) { + int is_4700x2 = is_spine_4700x2(node); + + for (p = 1; p <= node->numports; p++) { + port = node->ports[p]; + if (!port || !port->remoteport) + continue; + + /* + * Skip ISR4700 double density fabric boards ports 19-36 + * as they are chassis external ports + */ + if (is_4700x2 && (port->portnum > 18)) + continue; + + remnode = port->remoteport->node; + if (remnode->type != IB_NODE_SWITCH) { + if (!remnode->ch_found) + get_router_slot(remnode, port); + continue; + } + if (!node->ch_type) + /* we assume here that remoteport belongs to line */ + if (get_sfb_slot(node, port->remoteport)) + return -1; + + /* we could break here, but need to find if more routers connected */ + } + + } else if (is_line(node)) { + int is_4700_line = is_line_4700(node); + + for (p = 1; p <= node->numports; p++) { + port = node->ports[p]; + if (!port || !port->remoteport) + continue; + + if ((is_4700_line && (port->portnum > 18)) || + (!is_4700_line && (port->portnum > 12))) + continue; + + /* we assume here that remoteport belongs to spine */ + if (get_slb_slot(node, port->remoteport)) + return -1; + break; + } + } + + /* for each port of this node, map external ports */ + for (p = 1; p <= node->numports; p++) { + port = node->ports[p]; + if (!port) + continue; + voltaire_portmap(port); + } + + return 0; +} + +static int get_line_index(ibnd_node_t * node) +{ + int retval; + + if (is_line_4700(node)) + retval = node->ch_slotnum; + else + retval = 3 * (node->ch_slotnum - 1) + node->ch_anafanum; + + if (retval > LINES_MAX_NUM || retval < 1) { + printf("%s: retval = %d\n", __FUNCTION__, retval); + IBND_ERROR("Internal error\n"); + return -1; + } + return retval; +} + +static int get_spine_index(ibnd_node_t * node) +{ + int retval; + + if (is_spine_9288(node) || is_spine_2012(node)) + retval = 3 * (node->ch_slotnum - 1) + node->ch_anafanum; + else if (is_spine_4700(node) || is_spine_4700x2(node)) + retval = 2 * (node->ch_slotnum - 1) + node->ch_anafanum; + else + retval = node->ch_slotnum; + + if (retval > SPINES_MAX_NUM || retval < 1) { + IBND_ERROR("Internal error\n"); + return -1; + } + return retval; +} + +static int insert_line_router(ibnd_node_t * node, ibnd_chassis_t * chassis) +{ + int i = get_line_index(node); + + if (i < 0) + return i; + + if (chassis->linenode[i]) + return 0; /* already filled slot */ + + chassis->linenode[i] = node; + node->chassis = chassis; + return 0; +} + +static int insert_spine(ibnd_node_t * node, ibnd_chassis_t * chassis) +{ + int i = get_spine_index(node); + + if (i < 0) + return i; + + if (chassis->spinenode[i]) + return 0; /* already filled slot */ + + chassis->spinenode[i] = node; + node->chassis = chassis; + return 0; +} + +static int pass_on_lines_catch_spines(ibnd_chassis_t * chassis) +{ + ibnd_node_t *node, *remnode; + ibnd_port_t *port; + int i, p; + + for (i = 1; i <= LINES_MAX_NUM; i++) { + int is_4700_line; + + node = chassis->linenode[i]; + + if (!(node && is_line(node))) + continue; /* empty slot or router */ + + is_4700_line = is_line_4700(node); + + for (p = 1; p <= node->numports; p++) { + + port = node->ports[p]; + if (!port || !port->remoteport) + continue; + + if ((is_4700_line && (port->portnum > 18)) || + (!is_4700_line && (port->portnum > 12))) + continue; + + remnode = port->remoteport->node; + + if (!remnode->ch_found) + continue; /* some error - spine not initialized ? FIXME */ + if (insert_spine(remnode, chassis)) + return -1; + } + } + return 0; +} + +static int pass_on_spines_catch_lines(ibnd_chassis_t * chassis) +{ + ibnd_node_t *node, *remnode; + ibnd_port_t *port; + int i, p; + + for (i = 1; i <= SPINES_MAX_NUM; i++) { + int is_4700x2; + + node = chassis->spinenode[i]; + if (!node) + continue; /* empty slot */ + + is_4700x2 = is_spine_4700x2(node); + + for (p = 1; p <= node->numports; p++) { + port = node->ports[p]; + if (!port || !port->remoteport) + continue; + + /* + * ISR4700 double density fabric board ports 19-36 are + * chassis external ports, so skip them + */ + if (is_4700x2 && (port->portnum > 18)) + continue; + + remnode = port->remoteport->node; + + if (!remnode->ch_found) + continue; /* some error - line/router not initialized ? FIXME */ + + if (insert_line_router(remnode, chassis)) + return -1; + } + } + return 0; +} + +/* + Stupid interpolation algorithm... + But nothing to do - have to be compliant with VoltaireSM/NMS +*/ +static void pass_on_spines_interpolate_chguid(ibnd_chassis_t * chassis) +{ + ibnd_node_t *node; + int i; + + for (i = 1; i <= SPINES_MAX_NUM; i++) { + node = chassis->spinenode[i]; + if (!node) + continue; /* skip the empty slots */ + + /* take first guid minus one to be consistent with SM */ + chassis->chassisguid = node->guid - 1; + break; + } +} + +/* + This function fills chassis structure with all nodes + in that chassis + chassis structure = structure of one standalone chassis +*/ +static int build_chassis(ibnd_node_t * node, ibnd_chassis_t * chassis) +{ + int p = 0; + ibnd_node_t *remnode = 0; + ibnd_port_t *port = 0; + + /* we get here with node = chassis_spine */ + if (insert_spine(node, chassis)) + return -1; + + /* loop: pass on all ports of node */ + for (p = 1; p <= node->numports; p++) { + + port = node->ports[p]; + if (!port || !port->remoteport) + continue; + + /* + * ISR4700 double density fabric board ports 19-36 are + * chassis external ports, so skip them + */ + if (is_spine_4700x2(node) && (port->portnum > 18)) + continue; + + remnode = port->remoteport->node; + + if (!remnode->ch_found) + continue; /* some error - line or router not initialized ? FIXME */ + + insert_line_router(remnode, chassis); + } + + if (pass_on_lines_catch_spines(chassis)) + return -1; + /* 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 */ + if (pass_on_spines_catch_lines(chassis)) + return -1; + + /* 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 chassis */ + if (pass_on_lines_catch_spines(chassis)) + return -1; + if (pass_on_spines_catch_lines(chassis)) + return -1; + pass_on_spines_interpolate_chguid(chassis); + + return 0; +} + +/*========================================================*/ +/* 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 +--------------------------------------------------- + +Module : sLB-4018 + +int port | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 +ext port | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 +--------------------------------------------------- + +Module : sFB-4700X2 + + 12X port -> 3 x 4X ports: + +A1 int port | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 + ext port | 7 7 7 8 8 8 9 9 9 10 10 10 11 11 11 12 12 12 +A2 int port | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 + ext port | 1 1 1 2 2 2 3 3 3 4 4 4 5 5 5 6 6 6 + +*/ + +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} +}; + +int int2ext_map_slb4018[37] = { + 0, + 0, 0, 0, 0, 0, 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, 13, 14, 15, 16, 17, 18 +}; + +int int2ext_map_sfb4700x2[2][37] = { + {0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12, 12}, + {0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6} +}; + +/* 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 }; */ + +/* map internal ports to external ports if appropriate */ +static void voltaire_portmap(ibnd_port_t * port) +{ + int portnum = port->portnum; + int chipnum = 0; + ibnd_node_t *node = port->node; + int is_4700_line = is_line_4700(node); + int is_4700x2_spine = is_spine_4700x2(node); + + if (!node->ch_found || (!is_line(node) && !is_4700x2_spine)) { + port->ext_portnum = 0; + return; + } + + if (((is_4700_line || is_4700x2_spine) && + (portnum < 19 || portnum > 36)) || + ((!is_4700_line && !is_4700x2_spine) && + (portnum < 13 || portnum > 24))) { + port->ext_portnum = 0; + return; + } + + if (port->node->ch_anafanum < 1 || port->node->ch_anafanum > 2) { + port->ext_portnum = 0; + return; + } + + chipnum = port->node->ch_anafanum - 1; + + if (is_line_24(node)) + port->ext_portnum = int2ext_map_slb24[chipnum][portnum]; + else if (is_line_2024(node)) + port->ext_portnum = int2ext_map_slb2024[chipnum][portnum]; + /* sLB-4018: Only one asic per LB */ + else if (is_4700_line) + port->ext_portnum = int2ext_map_slb4018[portnum]; + /* sFB-4700X2 4X port */ + else if (is_4700x2_spine) + port->ext_portnum = int2ext_map_sfb4700x2[chipnum][portnum]; + else + port->ext_portnum = int2ext_map_slb8[chipnum][portnum]; +} + +static int add_chassis(chassis_scan_t * chassis_scan) +{ + if (!(chassis_scan->current_chassis = + calloc(1, sizeof(ibnd_chassis_t)))) { + IBND_ERROR("OOM: failed to allocate chassis object\n"); + return -1; + } + + if (chassis_scan->first_chassis == NULL) { + chassis_scan->first_chassis = chassis_scan->current_chassis; + chassis_scan->last_chassis = chassis_scan->current_chassis; + } else { + chassis_scan->last_chassis->next = + chassis_scan->current_chassis; + chassis_scan->last_chassis = chassis_scan->current_chassis; + } + return 0; +} + +static void add_node_to_chassis(ibnd_chassis_t * chassis, ibnd_node_t * node) +{ + node->chassis = chassis; + node->next_chassis_node = chassis->nodes; + chassis->nodes = node; +} + +/* + 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 + Returns: + 0 on success, -1 on failure +*/ +int group_nodes(ibnd_fabric_t * fabric) +{ + ibnd_node_t *node; + int chassisnum = 0; + ibnd_chassis_t *chassis; + ibnd_chassis_t *ch, *ch_next; + chassis_scan_t chassis_scan; + + chassis_scan.first_chassis = NULL; + chassis_scan.current_chassis = NULL; + chassis_scan.last_chassis = 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 (node = fabric->switches; node; node = node->type_next) { + if (mad_get_field(node->info, 0, + IB_NODE_VENDORID_F) == VTR_VENDOR_ID + && fill_voltaire_chassis_record(node)) + goto cleanup; + } + + /* separate every Voltaire chassis from each other and build linked list of them */ + /* algorithm: catch spine and find all surrounding nodes */ + for (node = fabric->switches; node; node = node->type_next) { + if (mad_get_field(node->info, 0, + IB_NODE_VENDORID_F) != VTR_VENDOR_ID) + continue; + if (!node->ch_found + || (node->chassis && node->chassis->chassisnum) + || !is_spine(node)) + continue; + if (add_chassis(&chassis_scan)) + goto cleanup; + chassis_scan.current_chassis->chassisnum = ++chassisnum; + if (build_chassis(node, chassis_scan.current_chassis)) + goto cleanup; + } + + /* now make pass on nodes for chassis which are not Voltaire */ + /* grouped by common SystemImageGUID */ + for (node = fabric->nodes; node; node = node->next) { + if (mad_get_field(node->info, 0, + IB_NODE_VENDORID_F) == VTR_VENDOR_ID) + continue; + if (mad_get_field64(node->info, 0, IB_NODE_SYSTEM_GUID_F)) { + chassis = find_chassisguid(fabric, node); + if (chassis) + chassis->nodecount++; + else { + /* Possible new chassis */ + if (add_chassis(&chassis_scan)) + goto cleanup; + chassis_scan.current_chassis->chassisguid = + get_chassisguid(node); + chassis_scan.current_chassis->nodecount = 1; + if (!fabric->chassis) + fabric->chassis = chassis_scan.first_chassis; + } + } + } + + /* now, make another pass to see which nodes are part of chassis */ + /* (defined as chassis->nodecount > 1) */ + for (node = fabric->nodes; node; node = node->next) { + if (mad_get_field(node->info, 0, + IB_NODE_VENDORID_F) == VTR_VENDOR_ID) + continue; + if (mad_get_field64(node->info, 0, IB_NODE_SYSTEM_GUID_F)) { + chassis = find_chassisguid(fabric, node); + if (chassis && chassis->nodecount > 1) { + if (!chassis->chassisnum) + chassis->chassisnum = ++chassisnum; + if (!node->ch_found) { + node->ch_found = 1; + add_node_to_chassis(chassis, node); + } + } + } + } + + fabric->chassis = chassis_scan.first_chassis; + return 0; + +cleanup: + ch = chassis_scan.first_chassis; + while (ch) { + ch_next = ch->next; + free(ch); + ch = ch_next; + } + fabric->chassis = NULL; + return -1; +} diff --git a/branches/WOF2-3/ulp/libibnetdisc/src/chassis.h b/branches/WOF2-3/ulp/libibnetdisc/src/chassis.h new file mode 100644 index 00000000..f8e0ee2b --- /dev/null +++ b/branches/WOF2-3/ulp/libibnetdisc/src/chassis.h @@ -0,0 +1,91 @@ +/* + * 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 _CHASSIS_H_ +#define _CHASSIS_H_ + +#include + +#include "internal.h" + +/*========================================================*/ +/* 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 +#define VTR_DEVID_SLB4018 0x5a5b +#define VTR_DEVID_SFB4700 0x5a5c +#define VTR_DEVID_SFB4700X2 0x5a5d + +/* 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 */ + +enum ibnd_chassis_type { + UNRESOLVED_CT, ISR9288_CT, ISR9096_CT, ISR2012_CT, ISR2004_CT, + ISR4700_CT +}; +enum ibnd_chassis_slot_type { UNRESOLVED_CS, LINE_CS, SPINE_CS, SRBD_CS }; + +int group_nodes(struct ibnd_fabric *fabric); + +#endif /* _CHASSIS_H_ */ diff --git a/branches/WOF2-3/ulp/libibnetdisc/src/ibnetdisc.c b/branches/WOF2-3/ulp/libibnetdisc/src/ibnetdisc.c new file mode 100644 index 00000000..f525d71b --- /dev/null +++ b/branches/WOF2-3/ulp/libibnetdisc/src/ibnetdisc.c @@ -0,0 +1,626 @@ +/* + * Copyright (c) 2004-2009 Voltaire Inc. All rights reserved. + * Copyright (c) 2007 Xsigo Systems Inc. All rights reserved. + * Copyright (c) 2008 Lawrence Livermore National Laboratory + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +#include +#endif /* HAVE_CONFIG_H */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "internal.h" +#include "chassis.h" + +/* forward declare */ +static int query_node_info(smp_engine_t * engine, ib_portid_t * portid, + ibnd_node_t * node); + +static int recv_switch_info(smp_engine_t * engine, ibnd_smp_t * smp, + uint8_t * mad, void *cb_data) +{ + uint8_t *switch_info = mad + IB_SMP_DATA_OFFS; + ibnd_node_t *node = cb_data; + memcpy(node->switchinfo, switch_info, sizeof(node->switchinfo)); + mad_decode_field(node->switchinfo, IB_SW_ENHANCED_PORT0_F, + &node->smaenhsp0); + return 0; +} + +static int query_switch_info(smp_engine_t * engine, ib_portid_t * portid, + ibnd_node_t * node) +{ + node->smaenhsp0 = 0; /* assume base SP0 */ + return issue_smp(engine, portid, IB_ATTR_SWITCH_INFO, 0, + recv_switch_info, node); +} + +static int add_port_to_dpath(ib_dr_path_t * path, int nextport) +{ + if (path->cnt > sizeof(path->p) - 1) + return -1; + ++path->cnt; + path->p[path->cnt] = (uint8_t) nextport; + return path->cnt; +} + +static int extend_dpath(smp_engine_t * engine, ib_portid_t * portid, + int nextport) +{ + ibnd_scan_t *scan = engine->user_data; + ibnd_fabric_t *fabric = scan->fabric; + + if (scan->cfg->max_hops && + fabric->maxhops_discovered >= scan->cfg->max_hops) + return 0; + + if (portid->lid) { + /* If we were LID routed we need to set up the drslid */ + if (!scan->selfportid.lid) + if (ib_resolve_self_via(&scan->selfportid, NULL, NULL, + scan->ibmad_port) < 0) { + IBND_ERROR("Failed to resolve self\n"); + return -1; + } + portid->drpath.drslid = (uint16_t) scan->selfportid.lid; + portid->drpath.drdlid = 0xFFFF; + } + + if (add_port_to_dpath(&portid->drpath, nextport) < 0) { + IBND_ERROR("add port %d to DR path failed; %s\n", nextport, + portid2str(portid)); + return -1; + } + + if ((unsigned) portid->drpath.cnt > fabric->maxhops_discovered) + fabric->maxhops_discovered = portid->drpath.cnt; + + return 1; +} + +static int recv_node_desc(smp_engine_t * engine, ibnd_smp_t * smp, + uint8_t * mad, void *cb_data) +{ + uint8_t *node_desc = mad + IB_SMP_DATA_OFFS; + ibnd_node_t *node = cb_data; + memcpy(node->nodedesc, node_desc, sizeof(node->nodedesc)); + return 0; +} + +static int query_node_desc(smp_engine_t * engine, ib_portid_t * portid, + ibnd_node_t * node) +{ + return issue_smp(engine, portid, IB_ATTR_NODE_DESC, 0, + recv_node_desc, node); +} + +static void debug_port(ib_portid_t * portid, ibnd_port_t * port) +{ + char width[64], speed[64]; + int iwidth; + int ispeed; + + iwidth = mad_get_field(port->info, 0, IB_PORT_LINK_WIDTH_ACTIVE_F); + ispeed = mad_get_field(port->info, 0, IB_PORT_LINK_SPEED_ACTIVE_F); + IBND_DEBUG + ("portid %s portnum %d: base lid %d state %d physstate %d %s %s\n", + portid2str(portid), port->portnum, port->base_lid, + mad_get_field(port->info, 0, IB_PORT_STATE_F), + mad_get_field(port->info, 0, IB_PORT_PHYS_STATE_F), + mad_dump_val(IB_PORT_LINK_WIDTH_ACTIVE_F, width, 64, &iwidth), + mad_dump_val(IB_PORT_LINK_SPEED_ACTIVE_F, speed, 64, &ispeed)); +} + +static int recv_port_info(smp_engine_t * engine, ibnd_smp_t * smp, + uint8_t * mad, void *cb_data) +{ + ibnd_fabric_t *fabric = ((ibnd_scan_t *) engine->user_data)->fabric; + ibnd_node_t *node = cb_data; + ibnd_port_t *port; + uint8_t *port_info = mad + IB_SMP_DATA_OFFS; + uint8_t port_num, local_port; + + port_num = (uint8_t) mad_get_field(mad, 0, IB_MAD_ATTRMOD_F); + local_port = (uint8_t) mad_get_field(port_info, 0, IB_PORT_LOCAL_PORT_F); + + /* this may have been created before */ + port = node->ports[port_num]; + if (!port) { + port = node->ports[port_num] = calloc(1, sizeof(*port)); + if (!port) { + IBND_ERROR("Failed to allocate port\n"); + return -1; + } + port->guid = + mad_get_field64(node->info, 0, IB_NODE_PORT_GUID_F); + } + + memcpy(port->info, port_info, sizeof(port->info)); + port->node = node; + port->portnum = port_num; + port->ext_portnum = 0; + port->base_lid = (uint16_t) mad_get_field(port->info, 0, IB_PORT_LID_F); + port->lmc = (uint8_t) mad_get_field(port->info, 0, IB_PORT_LMC_F); + + if (port_num == 0) { + node->smalid = port->base_lid; + node->smalmc = port->lmc; + } else if (node->type == IB_NODE_SWITCH) { + port->base_lid = node->smalid; + port->lmc = node->smalmc; + } + + add_to_portguid_hash(port, fabric->portstbl); + + debug_port(&smp->path, port); + + if (port_num && mad_get_field(port->info, 0, IB_PORT_PHYS_STATE_F) + == IB_PORT_PHYS_STATE_LINKUP + && ((node->type == IB_NODE_SWITCH && port_num != local_port) || + (node == fabric->from_node && port_num == local_port))) { + ib_portid_t path = smp->path; + if (extend_dpath(engine, &path, port_num) > 0) + query_node_info(engine, &path, node); + } + + return 0; +} + +static int query_port_info(smp_engine_t * engine, ib_portid_t * portid, + ibnd_node_t * node, int portnum) +{ + IBND_DEBUG("Query Port Info; %s (0x%" PRIx64 "):%d\n", + portid2str(portid), node->guid, portnum); + return issue_smp(engine, portid, IB_ATTR_PORT_INFO, portnum, + recv_port_info, node); +} + +static ibnd_node_t *create_node(smp_engine_t * engine, ib_portid_t * path, + uint8_t * node_info) +{ + ibnd_fabric_t *fabric = ((ibnd_scan_t *) engine->user_data)->fabric; + ibnd_node_t *rc = calloc(1, sizeof(*rc)); + if (!rc) { + IBND_ERROR("OOM: node creation failed\n"); + return NULL; + } + + /* decode just a couple of fields for quicker reference. */ + mad_decode_field(node_info, IB_NODE_GUID_F, &rc->guid); + mad_decode_field(node_info, IB_NODE_TYPE_F, &rc->type); + mad_decode_field(node_info, IB_NODE_NPORTS_F, &rc->numports); + + rc->ports = calloc(rc->numports + 1, sizeof(*rc->ports)); + if (!rc->ports) { + free(rc); + IBND_ERROR("OOM: Failed to allocate the ports array\n"); + return NULL; + } + + rc->path_portid = *path; + memcpy(rc->info, node_info, sizeof(rc->info)); + + add_to_nodeguid_hash(rc, fabric->nodestbl); + + /* add this to the all nodes list */ + rc->next = fabric->nodes; + fabric->nodes = rc; + + add_to_type_list(rc, fabric); + + return rc; +} + +static int get_last_port(ib_portid_t * path) +{ + return path->drpath.p[path->drpath.cnt]; +} + +static void link_ports(ibnd_node_t * node, ibnd_port_t * port, + ibnd_node_t * remotenode, ibnd_port_t * remoteport) +{ + IBND_DEBUG("linking: 0x%" PRIx64 " %p->%p:%u and 0x%" PRIx64 + " %p->%p:%u\n", node->guid, node, port, port->portnum, + remotenode->guid, 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 void dump_endnode(ib_portid_t * path, char *prompt, + ibnd_node_t * node, ibnd_port_t * port) +{ + char type[64]; + mad_dump_node_type(type, sizeof(type), &node->type, sizeof(int)); + printf("%s -> %s %s {%016" PRIx64 "} portnum %d lid %d-%d \"%s\"\n", + portid2str(path), prompt, type, node->guid, + node->type == IB_NODE_SWITCH ? 0 : port->portnum, + port->base_lid, port->base_lid + (1 << port->lmc) - 1, + node->nodedesc); +} + +static int recv_node_info(smp_engine_t * engine, ibnd_smp_t * smp, + uint8_t * mad, void *cb_data) +{ + ibnd_scan_t *scan = engine->user_data; + ibnd_fabric_t *fabric = scan->fabric; + int i = 0; + uint8_t *node_info = mad + IB_SMP_DATA_OFFS; + ibnd_node_t *rem_node = cb_data; + ibnd_node_t *node; + int node_is_new = 0; + uint64_t node_guid = mad_get_field64(node_info, 0, IB_NODE_GUID_F); + uint64_t port_guid = mad_get_field64(node_info, 0, IB_NODE_PORT_GUID_F); + int port_num = mad_get_field(node_info, 0, IB_NODE_LOCAL_PORT_F); + ibnd_port_t *port = NULL; + + node = ibnd_find_node_guid(fabric, node_guid); + if (!node) { + node = create_node(engine, &smp->path, node_info); + if (!node) + return -1; + node_is_new = 1; + } + IBND_DEBUG("Found %s node GUID 0x%" PRIx64 " (%s)\n", + node_is_new ? "new" : "old", node->guid, + portid2str(&smp->path)); + + port = node->ports[port_num]; + if (!port) { + /* If we have not see this port before create a shell for it */ + port = node->ports[port_num] = calloc(1, sizeof(*port)); + port->node = node; + port->portnum = port_num; + } + port->guid = port_guid; + + if (scan->cfg->show_progress) + dump_endnode(&smp->path, node_is_new ? "new" : "known", + node, port); + + if (rem_node == NULL) /* this is the start node */ + fabric->from_node = node; + else { + /* link ports... */ + int rem_port_num = get_last_port(&smp->path); + + if (!rem_node->ports[rem_port_num]) { + IBND_ERROR("Internal Error; " + "Node(%p) 0x%" PRIx64 + " Port %d no port created!?!?!?\n\n", + rem_node, rem_node->guid, rem_port_num); + return -1; + } + + link_ports(node, port, rem_node, rem_node->ports[rem_port_num]); + } + + if (node_is_new) { + query_node_desc(engine, &smp->path, node); + + if (node->type == IB_NODE_SWITCH) { + query_switch_info(engine, &smp->path, node); + for (i = 0; i <= node->numports; i++) + query_port_info(engine, &smp->path, node, i); + } + } + + if (node->type != IB_NODE_SWITCH) + query_port_info(engine, &smp->path, node, port_num); + + return 0; +} + +static int query_node_info(smp_engine_t * engine, ib_portid_t * portid, + ibnd_node_t * node) +{ + IBND_DEBUG("Query Node Info; %s\n", portid2str(portid)); + return issue_smp(engine, portid, IB_ATTR_NODE_INFO, 0, + recv_node_info, node); +} + +ibnd_node_t *ibnd_find_node_guid(ibnd_fabric_t * fabric, uint64_t guid) +{ + int hash = HASHGUID(guid) % HTSZ; + ibnd_node_t *node; + + if (!fabric) { + IBND_DEBUG("fabric parameter NULL\n"); + return NULL; + } + + for (node = fabric->nodestbl[hash]; node; node = node->htnext) + if (node->guid == guid) + return node; + + return NULL; +} + +ibnd_node_t *ibnd_find_node_dr(ibnd_fabric_t * fabric, char *dr_str) +{ + int i = 0; + ibnd_node_t *rc; + ib_dr_path_t path; + + if (!fabric) { + IBND_DEBUG("fabric parameter NULL\n"); + return NULL; + } + + rc = fabric->from_node; + + if (str2drpath(&path, dr_str, 0, 0) == -1) + return NULL; + + for (i = 0; i <= path.cnt; i++) { + ibnd_port_t *remote_port = NULL; + if (path.p[i] == 0) + continue; + if (!rc->ports) + return NULL; + + remote_port = rc->ports[path.p[i]]->remoteport; + if (!remote_port) + return NULL; + + rc = remote_port->node; + } + + return rc; +} + +void add_to_nodeguid_hash(ibnd_node_t * node, ibnd_node_t * hash[]) +{ + int hash_idx = HASHGUID(node->guid) % HTSZ; + + node->htnext = hash[hash_idx]; + hash[hash_idx] = node; +} + +void add_to_portguid_hash(ibnd_port_t * port, ibnd_port_t * hash[]) +{ + int hash_idx = HASHGUID(port->guid) % HTSZ; + + port->htnext = hash[hash_idx]; + hash[hash_idx] = port; +} + +void add_to_type_list(ibnd_node_t * node, ibnd_fabric_t * fabric) +{ + switch (node->type) { + case IB_NODE_CA: + node->type_next = fabric->ch_adapters; + fabric->ch_adapters = node; + break; + case IB_NODE_SWITCH: + node->type_next = fabric->switches; + fabric->switches = node; + break; + case IB_NODE_ROUTER: + node->type_next = fabric->routers; + fabric->routers = node; + break; + } +} + +static int set_config(struct ibnd_config *config, struct ibnd_config *cfg) +{ + if (!config) + return (-EINVAL); + + if (cfg) + memcpy(config, cfg, sizeof(*config)); + + if (!config->max_smps) + config->max_smps = DEFAULT_MAX_SMP_ON_WIRE; + if (!config->timeout_ms) + config->timeout_ms = DEFAULT_TIMEOUT; + if (!config->retries) + config->retries = DEFAULT_RETRIES; + + return (0); +} + +ibnd_fabric_t *ibnd_discover_fabric(char * ca_name, int ca_port, + ib_portid_t * from, + struct ibnd_config *cfg) +{ + struct ibnd_config config = { 0 }; + ibnd_fabric_t *fabric = NULL; + ib_portid_t my_portid = { 0 }; + smp_engine_t engine; + ibnd_scan_t scan; + int nc = 2; + int mc[2] = { IB_SMI_CLASS, IB_SMI_DIRECT_CLASS }; + + if (set_config(&config, cfg)) { + IBND_ERROR("Invalid ibnd_config\n"); + return NULL; + } + + /* If not specified start from "my" port */ + if (!from) + from = &my_portid; + + fabric = calloc(1, sizeof(*fabric)); + if (!fabric) { + IBND_ERROR("OOM: failed to calloc ibnd_fabric_t\n"); + return NULL; + } + + memset(fabric, 0, sizeof(*fabric)); + + memset(&scan.selfportid, 0, sizeof(scan.selfportid)); + scan.fabric = fabric; + scan.cfg = &config; + + if (smp_engine_init(&engine, ca_name, ca_port, &scan, &config)) { + free(fabric); + return (NULL); + } + + scan.ibmad_port = mad_rpc_open_port(ca_name, ca_port, mc, nc); + if (!scan.ibmad_port) { + IBND_ERROR("can't open MAD port (%s:%d)\n", ca_name, ca_port); + smp_engine_destroy(&engine); + return (NULL); + } + mad_rpc_set_timeout(scan.ibmad_port, cfg->timeout_ms); + mad_rpc_set_retries(scan.ibmad_port, cfg->retries); + + IBND_DEBUG("from %s\n", portid2str(from)); + + if (!query_node_info(&engine, from, NULL)) + if (process_mads(&engine) != 0) + goto error; + + fabric->total_mads_used = engine.total_smps; + + if (group_nodes(fabric)) + goto error; + + smp_engine_destroy(&engine); + mad_rpc_close_port(scan.ibmad_port); + return fabric; +error: + smp_engine_destroy(&engine); + mad_rpc_close_port(scan.ibmad_port); + ibnd_destroy_fabric(fabric); + return NULL; +} + +void destroy_node(ibnd_node_t * node) +{ + int p = 0; + + if (node->ports) { + for (p = 0; p <= node->numports; p++) + free(node->ports[p]); + free(node->ports); + } + free(node); +} + +void ibnd_destroy_fabric(ibnd_fabric_t * fabric) +{ + ibnd_node_t *node = NULL; + ibnd_node_t *next = NULL; + ibnd_chassis_t *ch, *ch_next; + + if (!fabric) + return; + + ch = fabric->chassis; + while (ch) { + ch_next = ch->next; + free(ch); + ch = ch_next; + } + node = fabric->nodes; + while (node) { + next = node->next; + destroy_node(node); + node = next; + } + free(fabric); +} + +void ibnd_iter_nodes(ibnd_fabric_t * fabric, ibnd_iter_node_func_t func, + void *user_data) +{ + ibnd_node_t *cur = NULL; + + if (!fabric) { + IBND_DEBUG("fabric parameter NULL\n"); + return; + } + + if (!func) { + IBND_DEBUG("func parameter NULL\n"); + return; + } + + for (cur = fabric->nodes; cur; cur = cur->next) + func(cur, user_data); +} + +void ibnd_iter_nodes_type(ibnd_fabric_t * fabric, ibnd_iter_node_func_t func, + int node_type, void *user_data) +{ + ibnd_node_t *list = NULL; + ibnd_node_t *cur = NULL; + + if (!fabric) { + IBND_DEBUG("fabric parameter NULL\n"); + return; + } + + if (!func) { + IBND_DEBUG("func parameter NULL\n"); + return; + } + + switch (node_type) { + case IB_NODE_SWITCH: + list = fabric->switches; + break; + case IB_NODE_CA: + list = fabric->ch_adapters; + break; + case IB_NODE_ROUTER: + list = fabric->routers; + break; + default: + IBND_DEBUG("Invalid node_type specified %d\n", node_type); + break; + } + + for (cur = list; cur; cur = cur->type_next) + func(cur, user_data); +} diff --git a/branches/WOF2-3/ulp/libibnetdisc/src/ibnetdisc_cache.c b/branches/WOF2-3/ulp/libibnetdisc/src/ibnetdisc_cache.c new file mode 100644 index 00000000..5151f63c --- /dev/null +++ b/branches/WOF2-3/ulp/libibnetdisc/src/ibnetdisc_cache.c @@ -0,0 +1,941 @@ +/* + * Copyright (c) 2004-2007 Voltaire Inc. All rights reserved. + * Copyright (c) 2007 Xsigo Systems Inc. All rights reserved. + * Copyright (c) 2008 Lawrence Livermore National Laboratory + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +#include +#endif /* HAVE_CONFIG_H */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "internal.h" +#include "chassis.h" + +/* For this caching lib, we always cache little endian */ + +/* Cache format + * + * Bytes 1-4 - magic number + * Bytes 5-8 - version number + * Bytes 9-12 - node count + * Bytes 13-16 - port count + * Bytes 17-24 - "from node" guid + * Bytes 25-28 - maxhops discovered + * Bytes X-Y - nodes (variable length) + * Bytes X-Y - ports (variable length) + * + * Nodes are cached as + * + * 2 bytes - smalid + * 1 byte - smalmc + * 1 byte - smaenhsp0 flag + * IB_SMP_DATA_SIZE bytes - switchinfo + * 8 bytes - guid + * 1 byte - type + * 1 byte - numports + * IB_SMP_DATA_SIZE bytes - info + * IB_SMP_DATA_SIZE bytes - nodedesc + * 1 byte - number of ports stored + * 8 bytes - portguid A + * 1 byte - port num A + * 8 bytes - portguid B + * 1 byte - port num B + * ... etc., depending on number of ports stored + * + * Ports are cached as + * + * 8 bytes - guid + * 1 byte - portnum + * 1 byte - external portnum + * 2 bytes - base lid + * 1 byte - lmc + * IB_SMP_DATA_SIZE bytes - info + * 8 bytes - node guid port "owned" by + * 1 byte - flag indicating if remote port exists + * 8 bytes - port guid remotely connected to + * 1 byte - port num remotely connected to + */ + +/* Structs that hold cache info temporarily before + * the real structs can be reconstructed. + */ + +typedef struct ibnd_port_cache_key { + uint64_t guid; + uint8_t portnum; +} ibnd_port_cache_key_t; + +typedef struct ibnd_node_cache { + ibnd_node_t *node; + uint8_t ports_stored_count; + ibnd_port_cache_key_t *port_cache_keys; + struct ibnd_node_cache *next; + struct ibnd_node_cache *htnext; + int node_stored_to_fabric; +} ibnd_node_cache_t; + +typedef struct ibnd_port_cache { + ibnd_port_t *port; + uint64_t node_guid; + uint8_t remoteport_flag; + ibnd_port_cache_key_t remoteport_cache_key; + struct ibnd_port_cache *next; + struct ibnd_port_cache *htnext; + int port_stored_to_fabric; +} ibnd_port_cache_t; + +typedef struct ibnd_fabric_cache { + ibnd_fabric_t *fabric; + uint64_t from_node_guid; + ibnd_node_cache_t *nodes_cache; + ibnd_port_cache_t *ports_cache; + ibnd_node_cache_t *nodescachetbl[HTSZ]; + ibnd_port_cache_t *portscachetbl[HTSZ]; +} ibnd_fabric_cache_t; + +#define IBND_FABRIC_CACHE_BUFLEN 4096 +#define IBND_FABRIC_CACHE_MAGIC 0x8FE7832B +#define IBND_FABRIC_CACHE_VERSION 0x00000001 + +#define IBND_FABRIC_CACHE_COUNT_OFFSET 8 + +#define IBND_FABRIC_CACHE_HEADER_LEN (28) +#define IBND_NODE_CACHE_HEADER_LEN (15 + IB_SMP_DATA_SIZE*3) +#define IBND_PORT_CACHE_KEY_LEN (8 + 1) +#define IBND_PORT_CACHE_LEN (31 + IB_SMP_DATA_SIZE) + +static ssize_t ibnd_read(int fd, void *buf, size_t count) +{ + size_t count_done = 0; + ssize_t ret; + + while ((count - count_done) > 0) { + ret = read(fd, ((char *) buf) + count_done, count - count_done); + if (ret < 0) { + if (errno == EINTR) + continue; + else { + IBND_DEBUG("read: %s\n", strerror(errno)); + return -1; + } + } + if (!ret) + break; + count_done += ret; + } + + if (count_done != count) { + IBND_DEBUG("read: read short\n"); + return -1; + } + + return count_done; +} + +static size_t _unmarshall8(uint8_t * inbuf, uint8_t * num) +{ + (*num) = inbuf[0]; + + return (sizeof(*num)); +} + +static size_t _unmarshall16(uint8_t * inbuf, uint16_t * num) +{ + (*num) = ((uint16_t) inbuf[1] << 8) | inbuf[0]; + + return (sizeof(*num)); +} + +static size_t _unmarshall32(uint8_t * inbuf, uint32_t * num) +{ + (*num) = (uint32_t) inbuf[0]; + (*num) |= ((uint32_t) inbuf[1] << 8); + (*num) |= ((uint32_t) inbuf[2] << 16); + (*num) |= ((uint32_t) inbuf[3] << 24); + + return (sizeof(*num)); +} + +static size_t _unmarshall64(uint8_t * inbuf, uint64_t * num) +{ + (*num) = (uint64_t) inbuf[0]; + (*num) |= ((uint64_t) inbuf[1] << 8); + (*num) |= ((uint64_t) inbuf[2] << 16); + (*num) |= ((uint64_t) inbuf[3] << 24); + (*num) |= ((uint64_t) inbuf[4] << 32); + (*num) |= ((uint64_t) inbuf[5] << 40); + (*num) |= ((uint64_t) inbuf[6] << 48); + (*num) |= ((uint64_t) inbuf[7] << 56); + + return (sizeof(*num)); +} + +static size_t _unmarshall_buf(const void *inbuf, void *outbuf, unsigned int len) +{ + memcpy(outbuf, inbuf, len); + + return len; +} + +static int _load_header_info(int fd, ibnd_fabric_cache_t * fabric_cache, + unsigned int *node_count, unsigned int *port_count) +{ + uint8_t buf[IBND_FABRIC_CACHE_BUFLEN]; + uint32_t magic = 0; + uint32_t version = 0; + size_t offset = 0; + uint32_t tmp32; + + if (ibnd_read(fd, buf, IBND_FABRIC_CACHE_HEADER_LEN) < 0) + return -1; + + offset += _unmarshall32(buf + offset, &magic); + + if (magic != IBND_FABRIC_CACHE_MAGIC) { + IBND_DEBUG("invalid fabric cache file\n"); + return -1; + } + + offset += _unmarshall32(buf + offset, &version); + + if (version != IBND_FABRIC_CACHE_VERSION) { + IBND_DEBUG("invalid fabric cache version\n"); + return -1; + } + + offset += _unmarshall32(buf + offset, node_count); + offset += _unmarshall32(buf + offset, port_count); + + offset += _unmarshall64(buf + offset, &fabric_cache->from_node_guid); + offset += _unmarshall32(buf + offset, &tmp32); + fabric_cache->fabric->maxhops_discovered = tmp32; + + return 0; +} + +static void _destroy_ibnd_node_cache(ibnd_node_cache_t * node_cache) +{ + free(node_cache->port_cache_keys); + if (!node_cache->node_stored_to_fabric && node_cache->node) + destroy_node(node_cache->node); + free(node_cache); +} + +static void _destroy_ibnd_fabric_cache(ibnd_fabric_cache_t * fabric_cache) +{ + ibnd_node_cache_t *node_cache; + ibnd_node_cache_t *node_cache_next; + ibnd_port_cache_t *port_cache; + ibnd_port_cache_t *port_cache_next; + + if (!fabric_cache) + return; + + node_cache = fabric_cache->nodes_cache; + while (node_cache) { + node_cache_next = node_cache->next; + + _destroy_ibnd_node_cache(node_cache); + + node_cache = node_cache_next; + } + + port_cache = fabric_cache->ports_cache; + while (port_cache) { + port_cache_next = port_cache->next; + + if (!port_cache->port_stored_to_fabric && port_cache->port) + free(port_cache->port); + free(port_cache); + + port_cache = port_cache_next; + } + + free(fabric_cache); +} + +static void store_node_cache(ibnd_node_cache_t * node_cache, + ibnd_fabric_cache_t * fabric_cache) +{ + int hash_indx = HASHGUID(node_cache->node->guid) % HTSZ; + + node_cache->next = fabric_cache->nodes_cache; + fabric_cache->nodes_cache = node_cache; + + node_cache->htnext = fabric_cache->nodescachetbl[hash_indx]; + fabric_cache->nodescachetbl[hash_indx] = node_cache; +} + +static int _load_node(int fd, ibnd_fabric_cache_t * fabric_cache) +{ + uint8_t buf[IBND_FABRIC_CACHE_BUFLEN]; + ibnd_node_cache_t *node_cache = NULL; + ibnd_node_t *node = NULL; + size_t offset = 0; + uint8_t tmp8; + + node_cache = (ibnd_node_cache_t *) malloc(sizeof(ibnd_node_cache_t)); + if (!node_cache) { + IBND_DEBUG("OOM: node_cache\n"); + return -1; + } + memset(node_cache, '\0', sizeof(ibnd_node_cache_t)); + + node = (ibnd_node_t *) malloc(sizeof(ibnd_node_t)); + if (!node) { + IBND_DEBUG("OOM: node\n"); + return -1; + } + memset(node, '\0', sizeof(ibnd_node_t)); + + node_cache->node = node; + + if (ibnd_read(fd, buf, IBND_NODE_CACHE_HEADER_LEN) < 0) + goto cleanup; + + offset += _unmarshall16(buf + offset, &node->smalid); + offset += _unmarshall8(buf + offset, &node->smalmc); + offset += _unmarshall8(buf + offset, &tmp8); + node->smaenhsp0 = tmp8; + offset += _unmarshall_buf(buf + offset, node->switchinfo, + IB_SMP_DATA_SIZE); + offset += _unmarshall64(buf + offset, &node->guid); + offset += _unmarshall8(buf + offset, &tmp8); + node->type = tmp8; + offset += _unmarshall8(buf + offset, &tmp8); + node->numports = tmp8; + offset += _unmarshall_buf(buf + offset, node->info, IB_SMP_DATA_SIZE); + offset += _unmarshall_buf(buf + offset, node->nodedesc, + IB_SMP_DATA_SIZE); + + offset += _unmarshall8(buf + offset, &node_cache->ports_stored_count); + + if (node_cache->ports_stored_count) { + unsigned int tomalloc = 0; + unsigned int toread = 0; + unsigned int i; + + tomalloc = + sizeof(ibnd_port_cache_key_t) * + node_cache->ports_stored_count; + + toread = + IBND_PORT_CACHE_KEY_LEN * node_cache->ports_stored_count; + + node_cache->port_cache_keys = + (ibnd_port_cache_key_t *) malloc(tomalloc); + if (!node_cache->port_cache_keys) { + IBND_DEBUG("OOM: node_cache port_cache_keys\n"); + goto cleanup; + } + + if (ibnd_read(fd, buf, toread) < 0) + goto cleanup; + + offset = 0; + + for (i = 0; i < node_cache->ports_stored_count; i++) { + offset += + _unmarshall64(buf + offset, + &node_cache->port_cache_keys[i].guid); + offset += + _unmarshall8(buf + offset, + &node_cache-> + port_cache_keys[i].portnum); + } + } + + store_node_cache(node_cache, fabric_cache); + + return 0; + +cleanup: + _destroy_ibnd_node_cache(node_cache); + return -1; +} + +static void store_port_cache(ibnd_port_cache_t * port_cache, + ibnd_fabric_cache_t * fabric_cache) +{ + int hash_indx = HASHGUID(port_cache->port->guid) % HTSZ; + + port_cache->next = fabric_cache->ports_cache; + fabric_cache->ports_cache = port_cache; + + port_cache->htnext = fabric_cache->portscachetbl[hash_indx]; + fabric_cache->portscachetbl[hash_indx] = port_cache; +} + +static int _load_port(int fd, ibnd_fabric_cache_t * fabric_cache) +{ + uint8_t buf[IBND_FABRIC_CACHE_BUFLEN]; + ibnd_port_cache_t *port_cache = NULL; + ibnd_port_t *port = NULL; + size_t offset = 0; + uint8_t tmp8; + + port_cache = (ibnd_port_cache_t *) malloc(sizeof(ibnd_port_cache_t)); + if (!port_cache) { + IBND_DEBUG("OOM: port_cache\n"); + return -1; + } + memset(port_cache, '\0', sizeof(ibnd_port_cache_t)); + + port = (ibnd_port_t *) malloc(sizeof(ibnd_port_t)); + if (!port) { + IBND_DEBUG("OOM: port\n"); + return -1; + } + memset(port, '\0', sizeof(ibnd_port_t)); + + port_cache->port = port; + + if (ibnd_read(fd, buf, IBND_PORT_CACHE_LEN) < 0) + goto cleanup; + + offset += _unmarshall64(buf + offset, &port->guid); + offset += _unmarshall8(buf + offset, &tmp8); + port->portnum = tmp8; + offset += _unmarshall8(buf + offset, &tmp8); + port->ext_portnum = tmp8; + offset += _unmarshall16(buf + offset, &port->base_lid); + offset += _unmarshall8(buf + offset, &port->lmc); + offset += _unmarshall_buf(buf + offset, port->info, IB_SMP_DATA_SIZE); + offset += _unmarshall64(buf + offset, &port_cache->node_guid); + offset += _unmarshall8(buf + offset, &port_cache->remoteport_flag); + offset += + _unmarshall64(buf + offset, &port_cache->remoteport_cache_key.guid); + offset += + _unmarshall8(buf + offset, + &port_cache->remoteport_cache_key.portnum); + + store_port_cache(port_cache, fabric_cache); + + return 0; + +cleanup: + free(port); + free(port_cache); + return -1; +} + +static ibnd_port_cache_t *_find_port(ibnd_fabric_cache_t * fabric_cache, + ibnd_port_cache_key_t * port_cache_key) +{ + int hash_indx = HASHGUID(port_cache_key->guid) % HTSZ; + ibnd_port_cache_t *port_cache; + + for (port_cache = fabric_cache->portscachetbl[hash_indx]; + port_cache; port_cache = port_cache->htnext) { + if (port_cache->port->guid == port_cache_key->guid + && port_cache->port->portnum == port_cache_key->portnum) + return port_cache; + } + + return NULL; +} + +static ibnd_node_cache_t *_find_node(ibnd_fabric_cache_t * fabric_cache, + uint64_t guid) +{ + int hash_indx = HASHGUID(guid) % HTSZ; + ibnd_node_cache_t *node_cache; + + for (node_cache = fabric_cache->nodescachetbl[hash_indx]; + node_cache; node_cache = node_cache->htnext) { + if (node_cache->node->guid == guid) + return node_cache; + } + + return NULL; +} + +static int _fill_port(ibnd_fabric_cache_t * fabric_cache, ibnd_node_t * node, + ibnd_port_cache_key_t * port_cache_key) +{ + ibnd_port_cache_t *port_cache; + + if (!(port_cache = _find_port(fabric_cache, port_cache_key))) { + IBND_DEBUG("Cache invalid: cannot find port\n"); + return -1; + } + + if (port_cache->port_stored_to_fabric) { + IBND_DEBUG("Cache invalid: duplicate port discovered\n"); + return -1; + } + + node->ports[port_cache->port->portnum] = port_cache->port; + port_cache->port_stored_to_fabric++; + + /* achu: needed if user wishes to re-cache a loaded fabric. + * Otherwise, mostly unnecessary to do this. + */ + add_to_portguid_hash(port_cache->port, fabric_cache->fabric->portstbl); + return 0; +} + +static int _rebuild_nodes(ibnd_fabric_cache_t * fabric_cache) +{ + ibnd_node_cache_t *node_cache; + ibnd_node_cache_t *node_cache_next; + + node_cache = fabric_cache->nodes_cache; + while (node_cache) { + ibnd_node_t *node; + int i; + + node_cache_next = node_cache->next; + + node = node_cache->node; + + /* Insert node into appropriate data structures */ + + node->next = fabric_cache->fabric->nodes; + fabric_cache->fabric->nodes = node; + + add_to_nodeguid_hash(node_cache->node, + fabric_cache->fabric->nodestbl); + + add_to_type_list(node_cache->node, fabric_cache->fabric); + + node_cache->node_stored_to_fabric++; + + /* Rebuild node ports array */ + + if (!(node->ports = + calloc(sizeof(*node->ports), node->numports + 1))) { + IBND_DEBUG("OOM: node->ports\n"); + return -1; + } + + for (i = 0; i < node_cache->ports_stored_count; i++) { + if (_fill_port(fabric_cache, node, + &node_cache->port_cache_keys[i]) < 0) + return -1; + } + + node_cache = node_cache_next; + } + + return 0; +} + +static int _rebuild_ports(ibnd_fabric_cache_t * fabric_cache) +{ + ibnd_port_cache_t *port_cache; + ibnd_port_cache_t *port_cache_next; + + port_cache = fabric_cache->ports_cache; + while (port_cache) { + ibnd_node_cache_t *node_cache; + ibnd_port_cache_t *remoteport_cache; + ibnd_port_t *port; + + port_cache_next = port_cache->next; + + port = port_cache->port; + + if (!(node_cache = + _find_node(fabric_cache, port_cache->node_guid))) { + IBND_DEBUG("Cache invalid: cannot find node\n"); + return -1; + } + + port->node = node_cache->node; + + if (port_cache->remoteport_flag) { + if (!(remoteport_cache = _find_port(fabric_cache, + &port_cache->remoteport_cache_key))) + { + IBND_DEBUG + ("Cache invalid: cannot find remote port\n"); + return -1; + } + + port->remoteport = remoteport_cache->port; + } else + port->remoteport = NULL; + + port_cache = port_cache_next; + } + + return 0; +} + +ibnd_fabric_t *ibnd_load_fabric(const char *file, unsigned int flags) +{ + unsigned int node_count = 0; + unsigned int port_count = 0; + ibnd_fabric_cache_t *fabric_cache = NULL; + ibnd_fabric_t *fabric = NULL; + ibnd_node_cache_t *node_cache = NULL; + int fd = -1; + unsigned int i; + + if (!file) { + IBND_DEBUG("file parameter NULL\n"); + return NULL; + } + + if ((fd = open(file, O_RDONLY)) < 0) { + IBND_DEBUG("open: %s\n", strerror(errno)); + return NULL; + } + + fabric_cache = + (ibnd_fabric_cache_t *) malloc(sizeof(ibnd_fabric_cache_t)); + if (!fabric_cache) { + IBND_DEBUG("OOM: fabric_cache\n"); + goto cleanup; + } + memset(fabric_cache, '\0', sizeof(ibnd_fabric_cache_t)); + + fabric = (ibnd_fabric_t *) malloc(sizeof(ibnd_fabric_t)); + if (!fabric) { + IBND_DEBUG("OOM: fabric\n"); + goto cleanup; + } + memset(fabric, '\0', sizeof(ibnd_fabric_t)); + + fabric_cache->fabric = fabric; + + if (_load_header_info(fd, fabric_cache, &node_count, &port_count) < 0) + goto cleanup; + + for (i = 0; i < node_count; i++) { + if (_load_node(fd, fabric_cache) < 0) + goto cleanup; + } + + for (i = 0; i < port_count; i++) { + if (_load_port(fd, fabric_cache) < 0) + goto cleanup; + } + + /* Special case - find from node */ + if (!(node_cache = + _find_node(fabric_cache, fabric_cache->from_node_guid))) { + IBND_DEBUG("Cache invalid: cannot find from node\n"); + goto cleanup; + } + fabric->from_node = node_cache->node; + + if (_rebuild_nodes(fabric_cache) < 0) + goto cleanup; + + if (_rebuild_ports(fabric_cache) < 0) + goto cleanup; + + if (group_nodes(fabric)) + goto cleanup; + + _destroy_ibnd_fabric_cache(fabric_cache); + close(fd); + return fabric; + +cleanup: + ibnd_destroy_fabric(fabric); + _destroy_ibnd_fabric_cache(fabric_cache); + close(fd); + return NULL; +} + +static ssize_t ibnd_write(int fd, const void *buf, size_t count) +{ + size_t count_done = 0; + ssize_t ret; + + while ((count - count_done) > 0) { + ret = write(fd, ((char *) buf) + count_done, count - count_done); + if (ret < 0) { + if (errno == EINTR) + continue; + else { + IBND_DEBUG("write: %s\n", strerror(errno)); + return -1; + } + } + count_done += ret; + } + return count_done; +} + +static size_t _marshall8(uint8_t * outbuf, uint8_t num) +{ + outbuf[0] = num; + + return (sizeof(num)); +} + +static size_t _marshall16(uint8_t * outbuf, uint16_t num) +{ + outbuf[0] = num & 0x00FF; + outbuf[1] = (num & 0xFF00) >> 8; + + return (sizeof(num)); +} + +static size_t _marshall32(uint8_t * outbuf, uint32_t num) +{ + outbuf[0] = num & 0x000000FF; + outbuf[1] = (num & 0x0000FF00) >> 8; + outbuf[2] = (num & 0x00FF0000) >> 16; + outbuf[3] = (num & 0xFF000000) >> 24; + + return (sizeof(num)); +} + +static size_t _marshall64(uint8_t * outbuf, uint64_t num) +{ + outbuf[0] = (uint8_t) num; + outbuf[1] = (uint8_t) (num >> 8); + outbuf[2] = (uint8_t) (num >> 16); + outbuf[3] = (uint8_t) (num >> 24); + outbuf[4] = (uint8_t) (num >> 32); + outbuf[5] = (uint8_t) (num >> 40); + outbuf[6] = (uint8_t) (num >> 48); + outbuf[7] = (uint8_t) (num >> 56); + + return (sizeof(num)); +} + +static size_t _marshall_buf(void *outbuf, const void *inbuf, unsigned int len) +{ + memcpy(outbuf, inbuf, len); + + return len; +} + +static int _cache_header_info(int fd, ibnd_fabric_t * fabric) +{ + uint8_t buf[IBND_FABRIC_CACHE_BUFLEN]; + size_t offset = 0; + + /* Store magic number, version, and other important info */ + /* For this caching lib, we always assume cached as little endian */ + + offset += _marshall32(buf + offset, IBND_FABRIC_CACHE_MAGIC); + offset += _marshall32(buf + offset, IBND_FABRIC_CACHE_VERSION); + /* save space for node count */ + offset += _marshall32(buf + offset, 0); + /* save space for port count */ + offset += _marshall32(buf + offset, 0); + offset += _marshall64(buf + offset, fabric->from_node->guid); + offset += _marshall32(buf + offset, fabric->maxhops_discovered); + + if (ibnd_write(fd, buf, offset) < 0) + return -1; + + return 0; +} + +static int _cache_header_counts(int fd, unsigned int node_count, + unsigned int port_count) +{ + uint8_t buf[IBND_FABRIC_CACHE_BUFLEN]; + size_t offset = 0; + + offset += _marshall32(buf + offset, node_count); + offset += _marshall32(buf + offset, port_count); + + if (lseek(fd, IBND_FABRIC_CACHE_COUNT_OFFSET, SEEK_SET) < 0) { + IBND_DEBUG("lseek: %s\n", strerror(errno)); + return -1; + } + + if (ibnd_write(fd, buf, offset) < 0) + return -1; + + return 0; +} + +static int _cache_node(int fd, ibnd_node_t * node) +{ + uint8_t buf[IBND_FABRIC_CACHE_BUFLEN]; + size_t offset = 0; + size_t ports_stored_offset = 0; + uint8_t ports_stored_count = 0; + int i; + + offset += _marshall16(buf + offset, node->smalid); + offset += _marshall8(buf + offset, node->smalmc); + offset += _marshall8(buf + offset, (uint8_t) node->smaenhsp0); + offset += _marshall_buf(buf + offset, node->switchinfo, + IB_SMP_DATA_SIZE); + offset += _marshall64(buf + offset, node->guid); + offset += _marshall8(buf + offset, (uint8_t) node->type); + offset += _marshall8(buf + offset, (uint8_t) node->numports); + offset += _marshall_buf(buf + offset, node->info, IB_SMP_DATA_SIZE); + offset += _marshall_buf(buf + offset, node->nodedesc, IB_SMP_DATA_SIZE); + /* need to come back later and store number of stored ports + * because port entries can be NULL or (in the case of switches) + * there is an additional port 0 not accounted for in numports. + */ + ports_stored_offset = offset; + offset += sizeof(uint8_t); + + for (i = 0; i <= node->numports; i++) { + if (node->ports[i]) { + offset += _marshall64(buf + offset, + node->ports[i]->guid); + offset += _marshall8(buf + offset, + (uint8_t) node->ports[i]->portnum); + ports_stored_count++; + } + } + + /* go back and store number of port keys stored */ + _marshall8(buf + ports_stored_offset, ports_stored_count); + + if (ibnd_write(fd, buf, offset) < 0) + return -1; + + return 0; +} + +static int _cache_port(int fd, ibnd_port_t * port) +{ + uint8_t buf[IBND_FABRIC_CACHE_BUFLEN]; + size_t offset = 0; + + offset += _marshall64(buf + offset, port->guid); + offset += _marshall8(buf + offset, (uint8_t) port->portnum); + offset += _marshall8(buf + offset, (uint8_t) port->ext_portnum); + offset += _marshall16(buf + offset, port->base_lid); + offset += _marshall8(buf + offset, port->lmc); + offset += _marshall_buf(buf + offset, port->info, IB_SMP_DATA_SIZE); + offset += _marshall64(buf + offset, port->node->guid); + if (port->remoteport) { + offset += _marshall8(buf + offset, 1); + offset += _marshall64(buf + offset, port->remoteport->guid); + offset += _marshall8(buf + offset, (uint8_t) port->remoteport->portnum); + } else { + offset += _marshall8(buf + offset, 0); + offset += _marshall64(buf + offset, 0); + offset += _marshall8(buf + offset, 0); + } + + if (ibnd_write(fd, buf, offset) < 0) + return -1; + + return 0; +} + +int ibnd_cache_fabric(ibnd_fabric_t * fabric, const char *file, + unsigned int flags) +{ + struct stat statbuf; + ibnd_node_t *node = NULL; + ibnd_node_t *node_next = NULL; + unsigned int node_count = 0; + ibnd_port_t *port = NULL; + ibnd_port_t *port_next = NULL; + unsigned int port_count = 0; + int fd; + int i; + + if (!fabric) { + IBND_DEBUG("fabric parameter NULL\n"); + return -1; + } + + if (!file) { + IBND_DEBUG("file parameter NULL\n"); + return -1; + } + + if (!stat(file, &statbuf)) { + IBND_DEBUG("file '%s' already exists\n", file); + return -1; + } + + if ((fd = open(file, O_CREAT | O_EXCL | O_WRONLY, 0644)) < 0) { + IBND_DEBUG("open: %s\n", strerror(errno)); + return -1; + } + + if (_cache_header_info(fd, fabric) < 0) + goto cleanup; + + node = fabric->nodes; + while (node) { + node_next = node->next; + + if (_cache_node(fd, node) < 0) + goto cleanup; + + node_count++; + node = node_next; + } + + for (i = 0; i < HTSZ; i++) { + port = fabric->portstbl[i]; + while (port) { + port_next = port->htnext; + + if (_cache_port(fd, port) < 0) + goto cleanup; + + port_count++; + port = port_next; + } + } + + if (_cache_header_counts(fd, node_count, port_count) < 0) + goto cleanup; + + if (close(fd) < 0) { + IBND_DEBUG("close: %s\n", strerror(errno)); + goto cleanup; + } + + return 0; + +cleanup: + unlink(file); + close(fd); + return -1; +} diff --git a/branches/WOF2-3/ulp/libibnetdisc/src/ibnetdisc_export.def b/branches/WOF2-3/ulp/libibnetdisc/src/ibnetdisc_export.def new file mode 100644 index 00000000..62e09936 --- /dev/null +++ b/branches/WOF2-3/ulp/libibnetdisc/src/ibnetdisc_export.def @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2008-2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +LIBRARY LIBIBNETDISC.DLL + +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE diff --git a/branches/WOF2-3/ulp/libibnetdisc/src/ibnetdisc_exports.src b/branches/WOF2-3/ulp/libibnetdisc/src/ibnetdisc_exports.src new file mode 100644 index 00000000..0ac15b98 --- /dev/null +++ b/branches/WOF2-3/ulp/libibnetdisc/src/ibnetdisc_exports.src @@ -0,0 +1,21 @@ +#if DBG +LIBRARY libibnetdiscd.dll +#else +LIBRARY libibnetdisc.dll +#endif + +#ifndef _WIN64 +EXPORTS + ibnd_discover_fabric; + ibnd_destroy_fabric; + ibnd_find_node_guid; + ibnd_find_node_dr; + ibnd_is_xsigo_guid; + ibnd_is_xsigo_tca; + ibnd_is_xsigo_hca; + ibnd_get_chassis_guid; + ibnd_get_chassis_type; + ibnd_get_chassis_slot_str; + ibnd_iter_nodes; + ibnd_iter_nodes_type; +#endif diff --git a/branches/WOF2-3/ulp/libibnetdisc/src/ibnetdisc_main.cpp b/branches/WOF2-3/ulp/libibnetdisc/src/ibnetdisc_main.cpp new file mode 100644 index 00000000..7a48a480 --- /dev/null +++ b/branches/WOF2-3/ulp/libibnetdisc/src/ibnetdisc_main.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2008-2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include + +BOOLEAN WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) +{ + UNREFERENCED_PARAMETER(hInstance); + UNREFERENCED_PARAMETER(dwReason); + UNREFERENCED_PARAMETER(lpReserved); + + return TRUE; +} diff --git a/branches/WOF2-3/ulp/libibnetdisc/src/internal.h b/branches/WOF2-3/ulp/libibnetdisc/src/internal.h new file mode 100644 index 00000000..3c599ecf --- /dev/null +++ b/branches/WOF2-3/ulp/libibnetdisc/src/internal.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2008 Lawrence Livermore National Laboratory + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/** ========================================================================= + * Define the internal data structures. + */ + +#ifndef _INTERNAL_H_ +#define _INTERNAL_H_ + +#include +#include + +#define IBND_DEBUG(fmt, ...) \ + if (ibdebug) { \ + printf("%s:%u; " fmt, __FILE__, __LINE__, ## __VA_ARGS__); \ + } +#define IBND_ERROR(fmt, ...) \ + fprintf(stderr, "%s:%u; " fmt, __FILE__, __LINE__, ## __VA_ARGS__) + +/* HASH table defines */ +#define HASHGUID(guid) ((uint32_t)(((uint32_t)(guid) * 101) ^ ((uint32_t)((guid) >> 32) * 103))) + +#define MAXHOPS 63 + +#define DEFAULT_MAX_SMP_ON_WIRE 2 +#define DEFAULT_TIMEOUT 1000 +#define DEFAULT_RETRIES 3 + +typedef struct ibnd_scan { + ib_portid_t selfportid; + ibnd_fabric_t *fabric; + struct ibnd_config *cfg; + struct ibmad_port *ibmad_port; +} ibnd_scan_t; + +typedef struct ibnd_smp ibnd_smp_t; +typedef struct smp_engine smp_engine_t; +typedef int (*smp_comp_cb_t) (smp_engine_t * engine, ibnd_smp_t * smp, + uint8_t * mad_resp, void *cb_data); +struct ibnd_smp { + cl_map_item_t on_wire; + struct ibnd_smp *qnext; + smp_comp_cb_t cb; + void *cb_data; + ib_portid_t path; + ib_rpc_t rpc; +}; + +struct smp_engine { + int umad_fd; + int smi_agent; + int smi_dir_agent; + ibnd_smp_t *smp_queue_head; + ibnd_smp_t *smp_queue_tail; + void *user_data; + cl_qmap_t smps_on_wire; + struct ibnd_config *cfg; + unsigned total_smps; +}; + +int smp_engine_init(smp_engine_t * engine, char * ca_name, int ca_port, + void *user_data, ibnd_config_t *cfg); +int issue_smp(smp_engine_t * engine, ib_portid_t * portid, + unsigned attrid, unsigned mod, smp_comp_cb_t cb, void *cb_data); +int process_mads(smp_engine_t * engine); +void smp_engine_destroy(smp_engine_t * engine); + +void add_to_nodeguid_hash(ibnd_node_t * node, ibnd_node_t * hash[]); + +void add_to_portguid_hash(ibnd_port_t * port, ibnd_port_t * hash[]); + +void add_to_type_list(ibnd_node_t * node, ibnd_fabric_t * fabric); + +void destroy_node(ibnd_node_t * node); + +#endif /* _INTERNAL_H_ */ diff --git a/branches/WOF2-3/ulp/libibnetdisc/src/makefile b/branches/WOF2-3/ulp/libibnetdisc/src/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-3/ulp/libibnetdisc/src/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\inc\openib.def diff --git a/branches/WOF2-3/ulp/libibnetdisc/src/query_smp.c b/branches/WOF2-3/ulp/libibnetdisc/src/query_smp.c new file mode 100644 index 00000000..5fb3e180 --- /dev/null +++ b/branches/WOF2-3/ulp/libibnetdisc/src/query_smp.c @@ -0,0 +1,277 @@ +/* + * Copyright (c) 2010 Lawrence Livermore National Laboratory + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include "internal.h" + +static void queue_smp(smp_engine_t * engine, ibnd_smp_t * smp) +{ + smp->qnext = NULL; + if (!engine->smp_queue_head) { + engine->smp_queue_head = smp; + engine->smp_queue_tail = smp; + } else { + engine->smp_queue_tail->qnext = smp; + engine->smp_queue_tail = smp; + } +} + +static ibnd_smp_t *get_smp(smp_engine_t * engine) +{ + ibnd_smp_t *head = engine->smp_queue_head; + ibnd_smp_t *tail = engine->smp_queue_tail; + ibnd_smp_t *rc = head; + if (head) { + if (tail == head) + engine->smp_queue_tail = NULL; + engine->smp_queue_head = head->qnext; + } + return rc; +} + +static int send_smp(ibnd_smp_t * smp, smp_engine_t * engine) +{ + int rc = 0; + uint8_t umad[1024]; + ib_rpc_t *rpc = &smp->rpc; + int agent = 0; + + memset(umad, 0, umad_size() + IB_MAD_SIZE); + + if (rpc->mgtclass == IB_SMI_CLASS) { + agent = engine->smi_agent; + } else if (rpc->mgtclass == IB_SMI_DIRECT_CLASS) { + agent = engine->smi_dir_agent; + } else { + IBND_ERROR("Invalid class for RPC\n"); + return (-EIO); + } + + if ((rc = mad_build_pkt(umad, &smp->rpc, &smp->path, NULL, NULL)) + < 0) { + IBND_ERROR("mad_build_pkt failed; %d\n", rc); + return rc; + } + + if ((rc = umad_send(engine->umad_fd, agent, umad, IB_MAD_SIZE, + engine->cfg->timeout_ms, engine->cfg->retries)) < 0) { + IBND_ERROR("send failed; %d\n", rc); + return rc; + } + + return 0; +} + +static int process_smp_queue(smp_engine_t * engine) +{ + int rc = 0; + ibnd_smp_t *smp; + while (cl_qmap_count(&engine->smps_on_wire) + < engine->cfg->max_smps) { + smp = get_smp(engine); + if (!smp) + return 0; + + if ((rc = send_smp(smp, engine)) != 0) { + free(smp); + return rc; + } + cl_qmap_insert(&engine->smps_on_wire, (uint32_t) smp->rpc.trid, + (cl_map_item_t *) smp); + engine->total_smps++; + } + return 0; +} + +int issue_smp(smp_engine_t * engine, ib_portid_t * portid, + unsigned attrid, unsigned mod, smp_comp_cb_t cb, void *cb_data) +{ + ibnd_smp_t *smp = calloc(1, sizeof *smp); + if (!smp) { + IBND_ERROR("OOM\n"); + return -ENOMEM; + } + + smp->cb = cb; + smp->cb_data = cb_data; + smp->path = *portid; + smp->rpc.method = IB_MAD_METHOD_GET; + smp->rpc.attr.id = attrid; + smp->rpc.attr.mod = mod; + smp->rpc.timeout = engine->cfg->timeout_ms; + smp->rpc.datasz = IB_SMP_DATA_SIZE; + smp->rpc.dataoffs = IB_SMP_DATA_OFFS; + smp->rpc.trid = mad_trid(); + + if (portid->lid <= 0 || portid->drpath.drslid == 0xffff || + portid->drpath.drdlid == 0xffff) + smp->rpc.mgtclass = IB_SMI_DIRECT_CLASS; /* direct SMI */ + else + smp->rpc.mgtclass = IB_SMI_CLASS; /* Lid routed SMI */ + + portid->sl = 0; + portid->qp = 0; + + queue_smp(engine, smp); + return process_smp_queue(engine); +} + +static int process_one_recv(smp_engine_t * engine) +{ + int rc = 0; + int status = 0; + ibnd_smp_t *smp; + uint8_t *mad; + uint32_t trid; + uint8_t umad[sizeof(struct ib_user_mad) + IB_MAD_SIZE]; + int length = umad_size() + IB_MAD_SIZE; + + memset(umad, 0, sizeof(umad)); + + /* wait for the next message */ + if ((rc = umad_recv(engine->umad_fd, umad, &length, + 0)) < 0) { + if (rc == -EWOULDBLOCK) + return 0; + IBND_ERROR("umad_recv failed: %d\n", rc); + return -1; + } + + mad = umad_get_mad(umad); + trid = (uint32_t) mad_get_field64(mad, 0, IB_MAD_TRID_F); + + smp = (ibnd_smp_t *) cl_qmap_remove(&engine->smps_on_wire, trid); + if ((cl_map_item_t *) smp == cl_qmap_end(&engine->smps_on_wire)) { + IBND_ERROR("Failed to find matching smp for trid (%x)\n", trid); + return -1; + } + + rc = process_smp_queue(engine); + if (rc) + goto error; + + if ((status = umad_status(umad))) { + IBND_ERROR("umad (%s Attr 0x%x:%u) bad status %d; %s\n", + portid2str(&smp->path), smp->rpc.attr.id, + smp->rpc.attr.mod, status, strerror(status)); + } else if ((status = mad_get_field(mad, 0, IB_DRSMP_STATUS_F))) { + IBND_ERROR("mad (%s Attr 0x%x:%u) bad status 0x%x\n", + portid2str(&smp->path), smp->rpc.attr.id, + smp->rpc.attr.mod, status); + } else + rc = smp->cb(engine, smp, mad, smp->cb_data); + +error: + free(smp); + return rc; +} + +int smp_engine_init(smp_engine_t * engine, char * ca_name, int ca_port, + void *user_data, ibnd_config_t *cfg) +{ + memset(engine, 0, sizeof(*engine)); + + if (umad_init() < 0) { + IBND_ERROR("umad_init failed\n"); + return -EIO; + } + + engine->umad_fd = umad_open_port(ca_name, ca_port); + if (engine->umad_fd < 0) { + IBND_ERROR("can't open UMAD port (%s:%d)\n", ca_name, ca_port); + return -EIO; + } + + if ((engine->smi_agent = umad_register(engine->umad_fd, + IB_SMI_CLASS, 1, 0, 0)) < 0) { + IBND_ERROR("Failed to register SMI agent on (%s:%d)\n", + ca_name, ca_port); + goto eio_close; + } + + if ((engine->smi_dir_agent = umad_register(engine->umad_fd, + IB_SMI_DIRECT_CLASS, 1, 0, 0)) < 0) { + IBND_ERROR("Failed to register SMI_DIRECT agent on (%s:%d)\n", + ca_name, ca_port); + goto eio_close; + } + + engine->user_data = user_data; + cl_qmap_init(&engine->smps_on_wire); + engine->cfg = cfg; + return (0); + +eio_close: + umad_close_port(engine->umad_fd); + return (-EIO); +} + +void smp_engine_destroy(smp_engine_t * engine) +{ + cl_map_item_t *item; + ibnd_smp_t *smp; + + /* remove queued smps */ + smp = get_smp(engine); + if (smp) + IBND_ERROR("outstanding SMP's\n"); + for ( /* */ ; smp; smp = get_smp(engine)) + free(smp); + + /* remove smps from the wire queue */ + item = cl_qmap_head(&engine->smps_on_wire); + if (item != cl_qmap_end(&engine->smps_on_wire)) + IBND_ERROR("outstanding SMP's on wire\n"); + for ( /* */ ; item != cl_qmap_end(&engine->smps_on_wire); + item = cl_qmap_head(&engine->smps_on_wire)) { + cl_qmap_remove_item(&engine->smps_on_wire, item); + free(item); + } + + umad_close_port(engine->umad_fd); +} + +int process_mads(smp_engine_t * engine) +{ + int rc; + while (!cl_is_qmap_empty(&engine->smps_on_wire)) + if ((rc = process_one_recv(engine)) != 0) + return rc; + return 0; +} diff --git a/branches/WOF2-3/ulp/libibumad/AUTHORS b/branches/WOF2-3/ulp/libibumad/AUTHORS new file mode 100644 index 00000000..1fd9242b --- /dev/null +++ b/branches/WOF2-3/ulp/libibumad/AUTHORS @@ -0,0 +1,4 @@ +Shahar Frank +Hal Rosenstock +Sasha Khapyorsky +Sean Hefty \ No newline at end of file diff --git a/branches/WOF2-3/ulp/libibumad/COPYING b/branches/WOF2-3/ulp/libibumad/COPYING new file mode 100644 index 00000000..8d741191 --- /dev/null +++ b/branches/WOF2-3/ulp/libibumad/COPYING @@ -0,0 +1,27 @@ +Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. +Copyright (c) 2008 Intel Corporation. All rights reserved. + +This software is available to you under the OpenFabrics.org BSD license +below: + + Redistribution and use in source and binary forms, with or + without modification, are permitted provided that the following + conditions are met: + + - Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + - Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/branches/WOF2-3/ulp/libibumad/dirs b/branches/WOF2-3/ulp/libibumad/dirs new file mode 100644 index 00000000..b1cbe453 --- /dev/null +++ b/branches/WOF2-3/ulp/libibumad/dirs @@ -0,0 +1,2 @@ +DIRS = \ + src \ No newline at end of file diff --git a/branches/WOF2-3/ulp/libibumad/include/infiniband/umad.h b/branches/WOF2-3/ulp/libibumad/include/infiniband/umad.h new file mode 100644 index 00000000..f6b41ace --- /dev/null +++ b/branches/WOF2-3/ulp/libibumad/include/infiniband/umad.h @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2004-2007 Voltaire Inc. All rights reserved. + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenFabrics.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#ifndef UMAD_H +#define UMAD_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Interfaces based on libibumad 1.2.0 + */ + +typedef unsigned __int8 uint8_t; +typedef unsigned __int16 uint16_t; +typedef unsigned __int32 uint32_t; +typedef unsigned __int64 uint64_t; + +#define UMAD_MAX_DEVICES 20 +#define UMAD_ANY_PORT 0 + +// Allow casting to WM_MAD_AV +typedef struct ib_mad_addr +{ + uint32_t qpn; + uint32_t qkey; + uint32_t flow_label; + uint16_t pkey_index; + uint8_t hop_limit; + uint8_t gid_index; + uint8_t gid[16]; + + uint8_t traffic_class; + uint8_t reserved_grh; + uint16_t lid; + uint8_t sl; + uint8_t path_bits; + uint8_t reserved_rate; + uint8_t grh_present; + +} ib_mad_addr_t; + +// Allow casting to WM_MAD +#pragma warning(push) +#pragma warning(disable: 4200) +typedef struct ib_user_mad +{ + uint32_t agent_id; + uint32_t reserved_id; + ib_mad_addr_t addr; + + uint32_t status; + uint32_t timeout_ms; + uint32_t retries; + uint32_t length; + uint8_t data[0]; + +} ib_user_mad_t; +#pragma warning(pop) + +#define UMAD_CA_NAME_LEN 64 +#define UMAD_CA_MAX_PORTS 10 /* 0 - 9 */ +#define UMAD_MAX_PORTS 64 + +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; + uint32_t capmask; + uint64_t gid_prefix; + uint64_t port_guid; + unsigned pkeys_size; + uint16_t *pkeys; + char link_layer[UMAD_CA_NAME_LEN]; + +} 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; + +__declspec(dllexport) +int umad_init(void); +__declspec(dllexport) +int umad_done(void); + +__declspec(dllexport) +int umad_get_cas_names(char cas[][UMAD_CA_NAME_LEN], int max); +__declspec(dllexport) +int umad_get_ca_portguids(char *ca_name, uint64_t *portguids, int max); + +__declspec(dllexport) +int umad_get_ca(char *ca_name, umad_ca_t *ca); +__declspec(dllexport) +int umad_release_ca(umad_ca_t *ca); + +__declspec(dllexport) +int umad_get_port(char *ca_name, int portnum, umad_port_t *port); +__declspec(dllexport) +int umad_release_port(umad_port_t *port); + +__declspec(dllexport) +int umad_get_issm_path(char *ca_name, int portnum, char path[], int max); + +__declspec(dllexport) +int umad_open_port(char *ca_name, int portnum); +__declspec(dllexport) +int umad_close_port(int portid); + +__declspec(dllexport) +void *umad_get_mad(void *umad); + +__declspec(dllexport) +size_t umad_size(void); + +__declspec(dllexport) +int umad_status(void *umad); + +__declspec(dllexport) +ib_mad_addr_t *umad_get_mad_addr(void *umad); +__declspec(dllexport) +int umad_set_grh_net(void *umad, void *mad_addr); +__declspec(dllexport) +int umad_set_grh(void *umad, void *mad_addr); +__declspec(dllexport) +int umad_set_addr_net(void *umad, int dlid, int dqp, int sl, int qkey); +__declspec(dllexport) +int umad_set_addr(void *umad, int dlid, int dqp, int sl, int qkey); +__declspec(dllexport) +int umad_set_pkey(void *umad, int pkey_index); +__declspec(dllexport) +int umad_get_pkey(void *umad); + +__declspec(dllexport) +int umad_send(int portid, int agentid, void *umad, int length, + int timeout_ms, int retries); +__declspec(dllexport) +int umad_recv(int portid, void *umad, int *length, int timeout_ms); +__declspec(dllexport) +int umad_poll(int portid, int timeout_ms); +HANDLE umad_get_fd(int portid); + +__declspec(dllexport) +int umad_register(int portid, int mgmt_class, int mgmt_version, + uint8_t rmpp_version, long method_mask[16/sizeof(long)]); +__declspec(dllexport) +int umad_register_oui(int portid, int mgmt_class, uint8_t rmpp_version, + uint8_t oui[3], long method_mask[16/sizeof(long)]); +__declspec(dllexport) +int umad_unregister(int portid, int agentid); + + +__declspec(dllexport) +int umad_debug(int level); +__declspec(dllexport) +void umad_addr_dump(ib_mad_addr_t *addr); +__declspec(dllexport) +void umad_dump(void *umad); + +__declspec(dllexport) +void *umad_alloc(int num, size_t size); + +__declspec(dllexport) +void umad_free(void *umad); + +#ifdef __cplusplus +} +#endif + +#endif /* UMAD_H */ diff --git a/branches/WOF2-3/ulp/libibumad/src/Sources b/branches/WOF2-3/ulp/libibumad/src/Sources new file mode 100644 index 00000000..971ca4c1 --- /dev/null +++ b/branches/WOF2-3/ulp/libibumad/src/Sources @@ -0,0 +1,39 @@ +!if $(FREEBUILD) +TARGETNAME = libibumad +!else +TARGETNAME = libibumadd +!endif + +TARGETPATH = ..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = DYNLINK + +!if $(_NT_TOOLS_VERSION) == 0x700 +DLLDEF = $O\ibum_exports.def +!else +DLLDEF = $(OBJ_PATH)\$O\ibum_exports.def +!endif + +DLLENTRY = DllMain +USE_MSVCRT=1 + +SOURCES = \ + ibumad.rc \ + ibum_main.cpp \ + umad.cpp + +INCLUDES = ..\include;..\..\libibverbs\include;..\..\..\inc;\ + ..\..\..\inc\user;..\..\..\inc\user\linux; + +USER_C_FLAGS = $(USER_C_FLAGS) -DEXPORT_IBUM_SYMBOLS + +TARGETLIBS = \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\uuid.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\winmad.lib \ + $(TARGETPATH)\*\libibverbs.lib +!else + $(TARGETPATH)\*\winmadd.lib \ + $(TARGETPATH)\*\libibverbsd.lib +!endif diff --git a/branches/WOF2-3/ulp/libibumad/src/ibum_export.def b/branches/WOF2-3/ulp/libibumad/src/ibum_export.def new file mode 100644 index 00000000..1d6e3af6 --- /dev/null +++ b/branches/WOF2-3/ulp/libibumad/src/ibum_export.def @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +LIBRARY LIBIBUMAD.DLL + +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE diff --git a/branches/WOF2-3/ulp/libibumad/src/ibum_exports.src b/branches/WOF2-3/ulp/libibumad/src/ibum_exports.src new file mode 100644 index 00000000..d79244ef --- /dev/null +++ b/branches/WOF2-3/ulp/libibumad/src/ibum_exports.src @@ -0,0 +1,39 @@ +#if DBG +LIBRARY libibumadd.dll +#else +LIBRARY libibumad.dll +#endif + +#ifndef _WIN64 +EXPORTS + 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; +#endif diff --git a/branches/WOF2-3/ulp/libibumad/src/ibum_main.cpp b/branches/WOF2-3/ulp/libibumad/src/ibum_main.cpp new file mode 100644 index 00000000..a308a55b --- /dev/null +++ b/branches/WOF2-3/ulp/libibumad/src/ibum_main.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include + +BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) +{ + UNREFERENCED_PARAMETER(hInstance); + UNREFERENCED_PARAMETER(dwReason); + UNREFERENCED_PARAMETER(lpReserved); + + return TRUE; +} diff --git a/branches/WOF2-3/ulp/libibumad/src/ibumad.h b/branches/WOF2-3/ulp/libibumad/src/ibumad.h new file mode 100644 index 00000000..2ec59657 --- /dev/null +++ b/branches/WOF2-3/ulp/libibumad/src/ibumad.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef IB_UMAD_H +#define IB_UMAD_H + +__inline void* __cdecl operator new(size_t size) +{ + return HeapAlloc(GetProcessHeap(), 0, size); +} + +__inline void __cdecl operator delete(void *pObj) +{ + HeapFree(GetProcessHeap(), 0, pObj); +} + +#endif /* IB_UMAD_H */ diff --git a/branches/WOF2-3/ulp/libibumad/src/ibumad.rc b/branches/WOF2-3/ulp/libibumad/src/ibumad.rc new file mode 100644 index 00000000..4a78b165 --- /dev/null +++ b/branches/WOF2-3/ulp/libibumad/src/ibumad.rc @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + +#include + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef DBG +#define VER_FILEDESCRIPTION_STR "LibIbUmad (Debug)" +#define VER_INTERNALNAME_STR "LibIbUmadd.dll" +#define VER_ORIGINALFILENAME_STR "LibIbUmadd.dll" +#else +#define VER_FILEDESCRIPTION_STR "LibIbUmad" +#define VER_INTERNALNAME_STR "LibIbUmad.dll" +#define VER_ORIGINALFILENAME_STR "LibIbUmad.dll" +#endif + +#include diff --git a/branches/WOF2-3/ulp/libibumad/src/makefile b/branches/WOF2-3/ulp/libibumad/src/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-3/ulp/libibumad/src/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\inc\openib.def diff --git a/branches/WOF2-3/ulp/libibumad/src/umad.cpp b/branches/WOF2-3/ulp/libibumad/src/umad.cpp new file mode 100644 index 00000000..3f4f13cf --- /dev/null +++ b/branches/WOF2-3/ulp/libibumad/src/umad.cpp @@ -0,0 +1,768 @@ +/* + * Copyright (c) 2004-2007 Voltaire Inc. All rights reserved. + * Copyright (c) 2008 Intel Corp., Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#include +#include + +#include +#include +#include +#include <_errno.h> +#include "ibumad.h" + +#define IB_OPENIB_OUI (0x001405) + +#define UMAD_MAX_PKEYS 16 + +typedef struct um_port +{ + IWMProvider *prov; + NET64 dev_guid; + OVERLAPPED overlap; + UINT8 port_num; + +} um_port_t; + +CRITICAL_SECTION crit_sec; +um_port_t ports[UMAD_MAX_PORTS]; + + +__declspec(dllexport) +int umad_init(void) +{ + InitializeCriticalSection(&crit_sec); + return 0; +} + +__declspec(dllexport) +int umad_done(void) +{ + DeleteCriticalSection(&crit_sec); + return 0; +} + +__declspec(dllexport) +int umad_get_cas_names(char cas[][UMAD_CA_NAME_LEN], int max) +{ + struct ibv_device **list; + int cnt, i; + + list = ibv_get_device_list(&cnt); + if (list == NULL) { + return 0; + } + + for (i = 0; i < min(cnt, max); i++) { + strcpy(cas[i], ibv_get_device_name(list[i])); + } + + ibv_free_device_list(list); + return i; +} + +__declspec(dllexport) +int umad_get_ca_portguids(char *ca_name, uint64_t *portguids, int max) +{ + umad_ca_t ca; + int ports = 0, i; + + if (umad_get_ca(ca_name, &ca) < 0) + return -1; + + if (ca.numports + 1 > max) { + umad_release_ca(&ca); + return -ENOMEM; + } + + portguids[ports++] = 0; + for (i = 1; i <= ca.numports; i++) + portguids[ports++] = ca.ports[i]->port_guid; + + umad_release_ca(&ca); + return ports; +} + +static void umad_convert_ca_attr(umad_ca_t *ca, ibv_device_attr *attr) +{ + ca->node_type = 1; // HCA + ca->numports = attr->phys_port_cnt; + strncpy(ca->fw_ver, attr->fw_ver, 20); + memset(ca->ca_type, 0, 40); // TODO: determine what this should be + sprintf(ca->hw_ver, "0x%x", attr->hw_ver); + ca->node_guid = attr->node_guid; + ca->system_guid = attr->sys_image_guid; +} + +static int umad_query_port(struct ibv_context *context, umad_port_t *port) +{ + ibv_port_attr attr; + ibv_gid gid; + int i, ret; + + ret = ibv_query_port(context, (uint8_t) port->portnum, &attr); + if (ret != 0) { + return ret; + } + + port->base_lid = attr.lid; + port->lmc = attr.lmc; + port->sm_lid = attr.sm_lid; + port->sm_sl = attr.sm_sl; + port->state = attr.state; + port->phys_state = attr.phys_state; + port->rate = attr.active_speed; + port->capmask = attr.port_cap_flags; + + // Assume GID 0 contains port GUID and gid prefix + ret = ibv_query_gid(context, (uint8_t) port->portnum, 0, &gid); + if (ret != 0) { + return ret; + } + + port->gid_prefix = gid.global.subnet_prefix; + port->port_guid = gid.global.interface_id; + + port->pkeys_size = min(UMAD_MAX_PKEYS, attr.pkey_tbl_len); + for (i = 0; i < (int) port->pkeys_size; i++) { + ret = ibv_query_pkey(context,(uint8_t) port->portnum, i, &port->pkeys[i]); + if (ret != 0) { + return ret; + } + } + + sprintf(port->link_layer, "IB"); + + return 0; +} + +__declspec(dllexport) +int umad_get_ca(char *ca_name, umad_ca_t *ca) +{ + struct ibv_device **list; + struct ibv_context *context; + ibv_device_attr dev_attr; + int cnt, i, ret = 0; + uint8_t *ports; + size_t port_size; + + list = ibv_get_device_list(&cnt); + if (list == NULL) { + return -ENOMEM; + } + + for (i = 0; i < cnt; i++) { + if (!strcmp(ca_name, ibv_get_device_name(list[i]))) { + break; + } + } + + if (i == cnt) { + ret = -EINVAL; + goto free; + } + + context = ibv_open_device(list[i]); + if (context == NULL) { + ret = -ENOMEM; + goto free; + } + + ret = ibv_query_device(context, &dev_attr); + if (ret != 0) { + goto close; + } + + port_size = sizeof(umad_port_t) + sizeof(uint16_t) * UMAD_MAX_PKEYS; + ports = new uint8_t[port_size * dev_attr.phys_port_cnt]; + if (ports == NULL) { + ret = -ENOMEM; + goto close; + } + + strcpy(ca->ca_name, ca_name); + umad_convert_ca_attr(ca, &dev_attr); + memset(ca->ports, 0, sizeof(ca->ports)); + + for (i = 1; i <= dev_attr.phys_port_cnt; i++, ports += port_size) { + + ca->ports[i] = (umad_port_t *) ports; + strcpy(ca->ports[i]->ca_name, ca_name); + ca->ports[i]->portnum = i; + ca->ports[i]->pkeys = (uint16_t *) (ports + sizeof(umad_port_t)); + + ret = umad_query_port(context, ca->ports[i]); + if (ret != 0) { + delete ports; + goto close; + } + } + +close: + ibv_close_device(context); +free: + ibv_free_device_list(list); + return ret; +} + +__declspec(dllexport) +int umad_release_ca(umad_ca_t *ca) +{ + delete ca->ports[0]; + return 0; +} + +static uint64_t umad_get_ca_guid(char *ca_name) +{ + umad_ca_t ca; + uint64_t guid; + int ret; + + ret = umad_get_ca(ca_name, &ca); + if (ret != 0) { + return 0; + } + + guid = ca.node_guid; + umad_release_ca(&ca); + return guid; +} + +__declspec(dllexport) +int umad_get_port(char *ca_name, int portnum, umad_port_t *port) +{ + umad_ca_t ca; + int ret; + + ret = umad_get_ca(ca_name, &ca); + if (ret != 0) { + return ret; + } + + memcpy(port, ca.ports[portnum], sizeof(umad_port_t)); + + port->pkeys = new uint16_t[ca.ports[portnum]->pkeys_size]; + if (port->pkeys == NULL) { + ret = -ENOMEM; + goto out; + } + + memcpy(port->pkeys, ca.ports[portnum]->pkeys, + sizeof(uint16_t) * ca.ports[portnum]->pkeys_size); +out: + umad_release_ca(&ca); + return ret; +} + +__declspec(dllexport) +int umad_release_port(umad_port_t *port) +{ + delete port->pkeys; + return 0; +} + +__declspec(dllexport) +int umad_get_issm_path(char *ca_name, int portnum, char path[], int max) +{ + return -EINVAL; +} + +static uint8_t umad_find_port(char *ca_name, enum ibv_port_state state) +{ + umad_ca_t ca; + int i, ret; + + ret = umad_get_ca(ca_name, &ca); + if (ret != 0) { + return 0; + } + + for (i = 1; i <= ca.numports; i++) { + if (ca.ports[i]->state == state) { + i = ca.ports[i]->portnum; + umad_release_ca(&ca); + return (uint8_t) i; + } + } + + umad_release_ca(&ca); + return 0; +} + +static int umad_find_ca_port(enum ibv_port_state state, char *ca_name, uint8_t *port) +{ + char names[8][UMAD_CA_NAME_LEN]; + int cnt, i; + + cnt = umad_get_cas_names(names, 8); + + for (i = 0; i < cnt; i++) { + *port = umad_find_port(names[i], state); + if (*port != 0) { + strcpy(ca_name, names[i]); + return 0; + } + } + return -1; +} + +static int umad_resolve_ca_port(char *ca_name, uint8_t *port) +{ + int ret; + + if (ca_name[0] != NULL) { + if (*port != 0) { + return 0; + } + + *port = umad_find_port(ca_name, IBV_PORT_ACTIVE); + if (*port != 0) { + return 0; + } + *port = umad_find_port(ca_name, IBV_PORT_INIT); + if (*port != 0) { + return 0; + } + *port = umad_find_port(ca_name, IBV_PORT_DOWN); + return (*port == 0); + } + + ret = umad_find_ca_port(IBV_PORT_ACTIVE, ca_name, port); + if (ret == 0) { + return 0; + } + ret = umad_find_ca_port(IBV_PORT_INIT, ca_name, port); + if (ret == 0) { + return 0; + } + ret = umad_find_ca_port(IBV_PORT_DOWN, ca_name, port); + return ret; +} + +__declspec(dllexport) +int umad_open_port(char *ca_name, int portnum) +{ + char name[UMAD_CA_NAME_LEN]; + uint8_t port; + HRESULT hr; + int portid; + + if (ca_name != NULL) { + strcpy(name, ca_name); + port = (uint8_t) portnum; + } else { + name[0] = NULL; + port = 0; + } + + hr = umad_resolve_ca_port(name, &port); + if (FAILED(hr)) { + return hr; + } + + EnterCriticalSection(&crit_sec); + for (portid = 0; portid < UMAD_MAX_PORTS; portid++) { + if (ports[portid].prov == NULL) { + break; + } + } + + if (portid == UMAD_MAX_PORTS) { + portid = -ENOMEM; + goto out; + } + + ports[portid].overlap.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if (ports[portid].overlap.hEvent == NULL) { + portid = -ENOMEM; + goto out; + } + + hr = WmGetObject(IID_IWMProvider, (LPVOID*) &ports[portid].prov); + if (FAILED(hr)) { + CloseHandle(ports[portid].overlap.hEvent); + portid = GetLastError() & 0x80000000; + goto out; + } + + ports[portid].dev_guid = umad_get_ca_guid(name); + ports[portid].port_num = port; + +out: + LeaveCriticalSection(&crit_sec); + return portid; +} + +__declspec(dllexport) +int umad_close_port(int portid) +{ + CloseHandle(ports[portid].overlap.hEvent); + ports[portid].prov->Release(); + + EnterCriticalSection(&crit_sec); + ports[portid].prov = NULL; + LeaveCriticalSection(&crit_sec); + + return 0; +} + +__declspec(dllexport) +int umad_set_grh_net(void *umad, void *mad_addr) +{ + struct ib_user_mad *mad = (struct ib_user_mad *) umad; + struct ib_mad_addr *addr = (struct ib_mad_addr *) mad_addr; + + if (mad_addr) { + mad->addr.grh_present = 1; + memcpy(mad->addr.gid, addr->gid, 16); + mad->addr.flow_label = 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; +} + +__declspec(dllexport) +int umad_set_grh(void *umad, void *mad_addr) +{ + struct ib_user_mad *mad = (struct ib_user_mad *) umad; + struct ib_mad_addr *addr = (struct ib_mad_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; +} + +__declspec(dllexport) +int umad_set_pkey(void *umad, int pkey_index) +{ + struct ib_user_mad *mad = (struct ib_user_mad *) umad; + + mad->addr.pkey_index = (uint16_t) pkey_index; + return 0; +} + +__declspec(dllexport) +int umad_get_pkey(void *umad) +{ + struct ib_user_mad *mad = (struct ib_user_mad *) umad; + + return mad->addr.pkey_index; +} + +__declspec(dllexport) +int umad_set_addr(void *umad, int dlid, int dqp, int sl, int qkey) +{ + struct ib_user_mad *mad = (struct ib_user_mad *) umad; + + mad->addr.qpn = htonl(dqp); + mad->addr.lid = htons((uint16_t) dlid); + mad->addr.qkey = htonl(qkey); + mad->addr.sl = (uint8_t) sl; + return 0; +} + +__declspec(dllexport) +int umad_set_addr_net(void *umad, int dlid, int dqp, int sl, int qkey) +{ + struct ib_user_mad *mad = (struct ib_user_mad *) umad; + + mad->addr.qpn = dqp; + mad->addr.lid = (uint16_t) dlid; + mad->addr.qkey = qkey; + mad->addr.sl = (uint8_t) sl; + + return 0; +} + +__declspec(dllexport) +int umad_status(void *umad) +{ + return ((struct ib_user_mad *) umad)->status; +} + +__declspec(dllexport) +ib_mad_addr_t *umad_get_mad_addr(void *umad) +{ + return &((struct ib_user_mad *) umad)->addr; +} + +__declspec(dllexport) +void *umad_get_mad(void *umad) +{ + return ((struct ib_user_mad *)umad)->data; +} + +__declspec(dllexport) +void *umad_alloc(int num, size_t size) +{ + return calloc(num, size); +} + +__declspec(dllexport) +void umad_free(void *umad) +{ + free(umad); +} + +__declspec(dllexport) +size_t umad_size(void) +{ + return sizeof(struct ib_user_mad); +} + +static void umad_convert_addr(struct ib_mad_addr *addr, WM_MAD_AV *av) +{ + av->VersionClassFlow = htonl((6 << 28) | (((uint32_t) addr->traffic_class) << 20) | + (addr->flow_label & 0x000FFFFF)); + av->Reserved = 0; + av->StaticRate = 0; +} + +static void umad_convert_av(WM_MAD_AV *av, struct ib_mad_addr *addr) +{ + uint32_t ver_class_flow; + + ver_class_flow = ntohl(av->VersionClassFlow); + addr->flow_label = ver_class_flow & 0x000FFFFF; + addr->traffic_class = (uint8_t) (ver_class_flow >> 20); +} + +__declspec(dllexport) +int umad_send(int portid, int agentid, void *umad, int length, + int timeout_ms, int retries) +{ + struct ib_user_mad *mad = (struct ib_user_mad *) umad; + HRESULT hr; + + mad->agent_id = agentid; + mad->reserved_id = 0; + + mad->timeout_ms = (uint32_t) timeout_ms; + mad->retries = (uint32_t) retries; + mad->length = (uint32_t) length; + + umad_convert_addr(&mad->addr, &((WM_MAD *) mad)->Address); + hr = ports[portid].prov->Send((WM_MAD *) mad, NULL); + umad_convert_av(&((WM_MAD *) mad)->Address, &mad->addr); + if (FAILED(hr)) { + _set_errno(EIO); + return GetLastError(); + } + + return 0; +} + +static HRESULT umad_cancel_recv(um_port_t *port) +{ + DWORD bytes; + + port->prov->CancelOverlappedRequests(); + return port->prov->GetOverlappedResult(&port->overlap, &bytes, TRUE); +} + +__declspec(dllexport) +int umad_recv(int portid, void *umad, int *length, int timeout_ms) +{ + WM_MAD *mad = (WM_MAD *) umad; + um_port_t *port; + HRESULT hr; + + port = &ports[portid]; + ResetEvent(port->overlap.hEvent); + hr = port->prov->Receive(mad, sizeof(WM_MAD) + (size_t) *length, &port->overlap); + if (hr == WV_IO_PENDING) { + hr = WaitForSingleObject(port->overlap.hEvent, (DWORD) timeout_ms); + if (hr == WAIT_TIMEOUT) { + hr = umad_cancel_recv(port); + if (hr == WV_CANCELLED) { + _set_errno(EWOULDBLOCK); + return -EWOULDBLOCK; + } + } + } + + if (FAILED(hr)) { + _set_errno(EIO); + return -EIO; + } + + if (mad->Length <= (UINT32) *length) { + hr = (HRESULT) mad->Id; + umad_convert_av(&mad->Address, &((struct ib_user_mad *) mad)->addr); + } else { + _set_errno(ENOSPC); + hr = -ENOSPC; + } + + *length = mad->Length; + return hr; +} + +__declspec(dllexport) +int umad_poll(int portid, int timeout_ms) +{ + WM_MAD mad; + um_port_t *port; + HRESULT hr; + + port = &ports[portid]; + ResetEvent(port->overlap.hEvent); + hr = port->prov->Receive(&mad, sizeof mad, &port->overlap); + if (hr == WV_IO_PENDING) { + hr = WaitForSingleObject(port->overlap.hEvent, (DWORD) timeout_ms); + if (hr == WAIT_TIMEOUT) { + hr = umad_cancel_recv(port); + if (hr == WV_CANCELLED) { + _set_errno(ETIMEDOUT); + return -ETIMEDOUT; + } + } + } + + if (FAILED(hr) && hr != ERROR_MORE_DATA) { + _set_errno(EIO); + return -EIO; + } + + return 0; +} + +static int umad_reg_oui(int portid, int mgmt_class, int mgmt_version, + uint8_t rmpp_version, uint8_t oui[3], + long method_mask[16/sizeof(long)]) +{ + WM_REGISTER reg; + UINT64 id = 0; + + UNREFERENCED_PARAMETER(rmpp_version); + + reg.Guid = ports[portid].dev_guid; + reg.Qpn = (mgmt_class == 0x01 || mgmt_class == 0x81) ? 0 : htonl(1); + reg.Port = ports[portid].port_num; + reg.Class = (uint8_t) mgmt_class; + reg.Version = (uint8_t) mgmt_version; + memset(reg.Reserved, 0, sizeof(reg.Reserved)); + memcpy(reg.Oui, oui, sizeof(oui)); + if (method_mask != NULL) { + memcpy(reg.Methods, method_mask, sizeof(reg.Methods)); + } else { + memset(reg.Methods, 0, sizeof(reg.Methods)); + } + ports[portid].prov->Register(®, &id); + + return (int) id; +} + +__declspec(dllexport) +int umad_register_oui(int portid, int mgmt_class, uint8_t rmpp_version, + uint8_t oui[3], long method_mask[16/sizeof(long)]) +{ + return umad_reg_oui(portid, mgmt_class, 1, + rmpp_version, oui, method_mask); +} + +__declspec(dllexport) +int umad_register(int portid, int mgmt_class, int mgmt_version, + uint8_t rmpp_version, long method_mask[16/sizeof(long)]) +{ + uint8_t oui[3]; + + memset(oui, 0, 3); + return umad_reg_oui(portid, mgmt_class, mgmt_version, + rmpp_version, oui, method_mask); +} + +__declspec(dllexport) +int umad_unregister(int portid, int agentid) +{ + return ports[portid].prov->Deregister((UINT64) agentid); +} + +HANDLE umad_get_fd(int portid) +{ + return ports[portid].prov->GetFileHandle(); +} + +__declspec(dllexport) +int umad_debug(int level) +{ + UNREFERENCED_PARAMETER(level); + return 0; +} + +__declspec(dllexport) +void umad_addr_dump(ib_mad_addr_t *addr) +{ + printf("umad_addr:\n"); + printf("\tqpn 0x%x\n", addr->qpn); + printf("\tqkey 0x%x\n", addr->qkey); + printf("\tsl 0x%x\n", addr->sl); + printf("\tlid 0x%x\n", addr->lid); + printf("\tpkey_index 0x%x\n", addr->pkey_index); + printf("\tpath_bits 0x%x\n", addr->path_bits); + printf("\trate 0x%x\n", addr->reserved_rate); + + printf("\tgrh_present 0x%x\n", addr->grh_present); + if (addr->grh_present) { + printf("\tgid_index 0x%x\n", addr->gid_index); + printf("\tgid 0x%x %x\n", + (uint64_t) addr->gid, (uint64_t) (addr->gid + 8)); + printf("\tflow_lable 0x%x\n", addr->flow_label); + printf("\thop_limit 0x%x\n", addr->hop_limit); + printf("\ttraffic_class 0x%x\n", addr->qpn); + } +} + +__declspec(dllexport) +void umad_dump(void *umad) +{ + struct ib_user_mad *mad = (struct ib_user_mad *) umad; + int i; + + umad_addr_dump(&mad->addr); + printf("umad_data\n"); + printf("offset: hex data\n"); + for (i = 0; i < 256; i += 4) { + printf("%03d: ", i); + printf("%02x %02x %02x %02x\n", mad->data[i], mad->data[i + 1], + mad->data[i + 2], mad->data[i + 3]); + } +} diff --git a/branches/WOF2-3/ulp/libibverbs/AUTHORS b/branches/WOF2-3/ulp/libibverbs/AUTHORS new file mode 100644 index 00000000..7c71c124 --- /dev/null +++ b/branches/WOF2-3/ulp/libibverbs/AUTHORS @@ -0,0 +1,4 @@ +Roland Dreier +Dotan Barak +Sean Hefty +Michael S. Tsirkin diff --git a/branches/WOF2-3/ulp/libibverbs/COPYING b/branches/WOF2-3/ulp/libibverbs/COPYING new file mode 100644 index 00000000..9589a0bb --- /dev/null +++ b/branches/WOF2-3/ulp/libibverbs/COPYING @@ -0,0 +1,29 @@ +Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. +Copyright (c) 2004, 2008 Intel Corporation. All rights reserved. +Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc. All rights reserved. +Copyright (c) 2005 PathScale, Inc. All rights reserved. + +This software is available to you under the OpenFabrics.org BSD license +below: + + Redistribution and use in source and binary forms, with or + without modification, are permitted provided that the following + conditions are met: + + - Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + - Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/branches/WOF2-3/ulp/libibverbs/dirs b/branches/WOF2-3/ulp/libibverbs/dirs new file mode 100644 index 00000000..c0df7b8e --- /dev/null +++ b/branches/WOF2-3/ulp/libibverbs/dirs @@ -0,0 +1,3 @@ +DIRS = \ + src \ + examples diff --git a/branches/WOF2-3/ulp/libibverbs/examples/asyncwatch/SOURCES b/branches/WOF2-3/ulp/libibverbs/examples/asyncwatch/SOURCES new file mode 100644 index 00000000..c62d745a --- /dev/null +++ b/branches/WOF2-3/ulp/libibverbs/examples/asyncwatch/SOURCES @@ -0,0 +1,31 @@ +TARGETNAME = ibv_asyncwatch +TARGETPATH = ..\..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = PROGRAM + +UMTYPE = console +UMENTRY = main + +USE_MSVCRT = 1 +USE_STL = 1 +USE_NATIVE_EH = 1 +USE_IOSTREAM = 1 + +SOURCES = \ + asyncwatch.rc \ + asyncwatch.c + +INCLUDES = ..;..\..\include;..\..\..\..\inc;..\..\..\..\inc\user;\ + ..\..\..\..\inc\user\linux + +TARGETLIBS = \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\advapi32.lib \ + $(SDK_LIB_PATH)\user32.lib \ + $(SDK_LIB_PATH)\ole32.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\libibverbs.lib +!else + $(TARGETPATH)\*\libibverbsd.lib +!endif + diff --git a/branches/WOF2-3/ulp/libibverbs/examples/asyncwatch/asyncwatch.c b/branches/WOF2-3/ulp/libibverbs/examples/asyncwatch/asyncwatch.c new file mode 100644 index 00000000..385c8979 --- /dev/null +++ b/branches/WOF2-3/ulp/libibverbs/examples/asyncwatch/asyncwatch.c @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include + +#include + +static const char *event_name_str(enum ibv_event_type event_type) +{ + switch (event_type) { + case IBV_EVENT_DEVICE_FATAL: + return "IBV_EVENT_DEVICE_FATAL"; + case IBV_EVENT_PORT_ACTIVE: + return "IBV_EVENT_PORT_ACTIVE"; + case IBV_EVENT_PORT_ERR: + return "IBV_EVENT_PORT_ERR"; + case IBV_EVENT_LID_CHANGE: + return "IBV_EVENT_LID_CHANGE"; + case IBV_EVENT_PKEY_CHANGE: + return "IBV_EVENT_PKEY_CHANGE"; + case IBV_EVENT_SM_CHANGE: + return "IBV_EVENT_SM_CHANGE"; + case IBV_EVENT_CLIENT_REREGISTER: + return "IBV_EVENT_CLIENT_REREGISTER"; + + case IBV_EVENT_CQ_ERR: + case IBV_EVENT_QP_FATAL: + case IBV_EVENT_QP_REQ_ERR: + case IBV_EVENT_QP_ACCESS_ERR: + case IBV_EVENT_COMM_EST: + case IBV_EVENT_SQ_DRAINED: + case IBV_EVENT_PATH_MIG: + case IBV_EVENT_PATH_MIG_ERR: + case IBV_EVENT_SRQ_ERR: + case IBV_EVENT_SRQ_LIMIT_REACHED: + case IBV_EVENT_QP_LAST_WQE_REACHED: + default: + return "unexpected"; + } +} + +int __cdecl main(int argc, char *argv[]) +{ + struct ibv_device **dev_list; + struct ibv_context *context; + struct ibv_async_event event; + + dev_list = ibv_get_device_list(NULL); + if (!dev_list) { + fprintf(stderr, "No IB devices found\n"); + return 1; + } + + if (!*dev_list) { + fprintf(stderr, "No IB devices found\n"); + return 1; + } + + context = ibv_open_device(*dev_list); + if (!context) { + fprintf(stderr, "Couldn't get context for %s\n", + ibv_get_device_name(*dev_list)); + return 1; + } + + printf("%s: async event\n", ibv_get_device_name(*dev_list)); + + while (1) { + if (ibv_get_async_event(context, &event)) + return 1; + + printf(" event_type %s (%d), port %d\n", + event_name_str(event.event_type), + event.event_type, event.element.port_num); + + ibv_ack_async_event(&event); + } + + return 0; +} diff --git a/branches/WOF2-3/ulp/libibverbs/examples/asyncwatch/asyncwatch.rc b/branches/WOF2-3/ulp/libibverbs/examples/asyncwatch/asyncwatch.rc new file mode 100644 index 00000000..aa7bc92a --- /dev/null +++ b/branches/WOF2-3/ulp/libibverbs/examples/asyncwatch/asyncwatch.rc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef DBG +#define VER_FILEDESCRIPTION_STR "winverbs - Async Event Watch (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "winverbs - Async Event Watch" +#endif + +#define VER_INTERNALNAME_STR "ibv_send_bw.exe" +#define VER_ORIGINALFILENAME_STR "ibv_send_bw.exe" + +#include diff --git a/branches/WOF2-3/ulp/libibverbs/examples/asyncwatch/makefile b/branches/WOF2-3/ulp/libibverbs/examples/asyncwatch/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-3/ulp/libibverbs/examples/asyncwatch/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\..\inc\openib.def diff --git a/branches/WOF2-3/ulp/libibverbs/examples/device_list.c b/branches/WOF2-3/ulp/libibverbs/examples/device_list.c new file mode 100644 index 00000000..7019279e --- /dev/null +++ b/branches/WOF2-3/ulp/libibverbs/examples/device_list.c @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2004 Topspin Communications. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include + +#include +#include + +#include +#include + +int main(int argc, char *argv[]) +{ + struct ibv_device **dev_list; + int num_devices, i; + + dev_list = ibv_get_device_list(&num_devices); + if (!dev_list) { + fprintf(stderr, "No IB devices found\n"); + return 1; + } + + printf(" %-16s\t node GUID\n", "device"); + printf(" %-16s\t----------------\n", "------"); + + for (i = 0; i < num_devices; ++i) { + printf(" %-16s\t%016llx\n", + ibv_get_device_name(dev_list[i]), + (unsigned long long) ntohll(ibv_get_device_guid(dev_list[i]))); + } + + ibv_free_device_list(dev_list); + + return 0; +} diff --git a/branches/WOF2-3/ulp/libibverbs/examples/devinfo/SOURCES b/branches/WOF2-3/ulp/libibverbs/examples/devinfo/SOURCES new file mode 100644 index 00000000..ac30a430 --- /dev/null +++ b/branches/WOF2-3/ulp/libibverbs/examples/devinfo/SOURCES @@ -0,0 +1,31 @@ +TARGETNAME = ibv_devinfo +TARGETPATH = ..\..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = PROGRAM + +UMTYPE = console +UMENTRY = main + +USE_MSVCRT = 1 +USE_STL = 1 +USE_NATIVE_EH = 1 +USE_IOSTREAM = 1 + +SOURCES = \ + devinfo.rc \ + devinfo.c + +INCLUDES = ..;..\..\include;..\..\..\..\inc;..\..\..\..\inc\user;\ + ..\..\..\..\inc\user\linux; + +TARGETLIBS = \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\advapi32.lib \ + $(SDK_LIB_PATH)\user32.lib \ + $(SDK_LIB_PATH)\ole32.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\libibverbs.lib +!else + $(TARGETPATH)\*\libibverbsd.lib +!endif + diff --git a/branches/WOF2-3/ulp/libibverbs/examples/devinfo/devinfo.c b/branches/WOF2-3/ulp/libibverbs/examples/devinfo/devinfo.c new file mode 100644 index 00000000..c50da422 --- /dev/null +++ b/branches/WOF2-3/ulp/libibverbs/examples/devinfo/devinfo.c @@ -0,0 +1,393 @@ +/* + * Copyright (c) 2005 Cisco Systems. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies Ltd. All rights reserved. + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include + +#include "..\..\..\..\etc\user\getopt.c" +#include +#include + +static int verbose = 0; + +static int null_gid(union ibv_gid *gid) +{ + return !(gid->raw[8] | gid->raw[9] | gid->raw[10] | gid->raw[11] | + gid->raw[12] | gid->raw[13] | gid->raw[14] | gid->raw[15]); +} + +static const char *guid_str(uint64_t node_guid, char *str) +{ + node_guid = ntohll(node_guid); + sprintf(str, "%04x:%04x:%04x:%04x", + (unsigned) (node_guid >> 48) & 0xffff, + (unsigned) (node_guid >> 32) & 0xffff, + (unsigned) (node_guid >> 16) & 0xffff, + (unsigned) (node_guid >> 0) & 0xffff); + return str; +} + +static const char *port_phy_state_str(uint8_t phys_state) +{ + switch (phys_state) { + case 1: return "SLEEP"; + case 2: return "POLLING"; + case 3: return "DISABLED"; + case 4: return "PORT_CONFIGURATION TRAINNING"; + case 5: return "LINK_UP"; + case 6: return "LINK_ERROR_RECOVERY"; + case 7: return "PHY TEST"; + default: return "invalid physical state"; + } +} + +static const char *atomic_cap_str(enum ibv_atomic_cap atom_cap) +{ + switch (atom_cap) { + case IBV_ATOMIC_NONE: return "ATOMIC_NONE"; + case IBV_ATOMIC_HCA: return "ATOMIC_HCA"; + case IBV_ATOMIC_GLOB: return "ATOMIC_GLOB"; + default: return "invalid atomic capability"; + } +} + +static const char *mtu_str(enum ibv_mtu max_mtu) +{ + switch (max_mtu) { + case IBV_MTU_256: return "256"; + case IBV_MTU_512: return "512"; + case IBV_MTU_1024: return "1024"; + case IBV_MTU_2048: return "2048"; + case IBV_MTU_4096: return "4096"; + default: return "invalid MTU"; + } +} + +static const char *width_str(uint8_t width) +{ + switch (width) { + case 1: return "1"; + case 2: return "4"; + case 4: return "8"; + case 8: return "12"; + default: return "invalid width"; + } +} + +static const char *speed_str(uint8_t speed) +{ + switch (speed) { + case 1: return "2.5 Gbps"; + case 2: return "5.0 Gbps"; + case 4: return "10.0 Gbps"; + default: return "invalid speed"; + } +} + +static const char *vl_str(uint8_t vl_num) +{ + switch (vl_num) { + case 1: return "1"; + case 2: return "2"; + case 3: return "4"; + case 4: return "8"; + case 5: return "15"; + default: return "invalid value"; + } +} + +static int print_all_port_gids(struct ibv_context *ctx, uint8_t port_num, int tbl_len) +{ + union ibv_gid gid; + int rc = 0; + int i; + + for (i = 0; i < tbl_len; i++) { + rc = ibv_query_gid(ctx, port_num, i, &gid); + if (rc) { + fprintf(stderr, "Failed to query gid to port %d, index %d\n", + port_num, i); + return rc; + } + if (!null_gid(&gid)) + printf("\t\t\tGID[%3d]:\t\t%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", + i, + ntohs(*((uint16_t *) gid.raw + 0)), + ntohs(*((uint16_t *) gid.raw + 1)), + ntohs(*((uint16_t *) gid.raw + 2)), + ntohs(*((uint16_t *) gid.raw + 3)), + ntohs(*((uint16_t *) gid.raw + 4)), + ntohs(*((uint16_t *) gid.raw + 5)), + ntohs(*((uint16_t *) gid.raw + 6)), + ntohs(*((uint16_t *) gid.raw + 7))); + } + return rc; +} + +static int print_hca_cap(struct ibv_device *ib_dev, uint8_t ib_port) +{ + struct ibv_context *ctx; + struct ibv_device_attr device_attr; + struct ibv_port_attr port_attr; + int rc = 0; + uint8_t port; + char buf[256]; + + ctx = ibv_open_device(ib_dev); + if (!ctx) { + fprintf(stderr, "Failed to open device\n"); + rc = 1; + goto cleanup; + } + if (ibv_query_device(ctx, &device_attr)) { + fprintf(stderr, "Failed to query device props"); + rc = 2; + goto cleanup; + } + + printf("hca_id:\t%s\n", ibv_get_device_name(ib_dev)); + if (strlen(device_attr.fw_ver)) + printf("\tfw_ver:\t\t\t\t%s\n", device_attr.fw_ver); + printf("\tnode_guid:\t\t\t%s\n", guid_str(device_attr.node_guid, buf)); + printf("\tsys_image_guid:\t\t\t%s\n", guid_str(device_attr.sys_image_guid, buf)); + printf("\tvendor_id:\t\t\t0x%04x\n", device_attr.vendor_id); + printf("\tvendor_part_id:\t\t\t%d\n", device_attr.vendor_part_id); + printf("\thw_ver:\t\t\t\t0x%X\n", device_attr.hw_ver); + + //if (ibv_read_sysfs_file(ib_dev->ibdev_path, "board_id", buf, sizeof buf) > 0) + // printf("\tboard_id:\t\t\t%s\n", buf); + + printf("\tphys_port_cnt:\t\t\t%d\n", device_attr.phys_port_cnt); + + if (verbose) { + printf("\tmax_mr_size:\t\t\t0x%llx\n", + (unsigned long long) device_attr.max_mr_size); + printf("\tpage_size_cap:\t\t\t0x%llx\n", + (unsigned long long) device_attr.page_size_cap); + printf("\tmax_qp:\t\t\t\t%d\n", device_attr.max_qp); + printf("\tmax_qp_wr:\t\t\t%d\n", device_attr.max_qp_wr); + printf("\tdevice_cap_flags:\t\t0x%08x\n", device_attr.device_cap_flags); + printf("\tmax_sge:\t\t\t%d\n", device_attr.max_sge); + printf("\tmax_sge_rd:\t\t\t%d\n", device_attr.max_sge_rd); + printf("\tmax_cq:\t\t\t\t%d\n", device_attr.max_cq); + printf("\tmax_cqe:\t\t\t%d\n", device_attr.max_cqe); + printf("\tmax_mr:\t\t\t\t%d\n", device_attr.max_mr); + printf("\tmax_pd:\t\t\t\t%d\n", device_attr.max_pd); + printf("\tmax_qp_rd_atom:\t\t\t%d\n", device_attr.max_qp_rd_atom); + printf("\tmax_ee_rd_atom:\t\t\t%d\n", device_attr.max_ee_rd_atom); + printf("\tmax_res_rd_atom:\t\t%d\n", device_attr.max_res_rd_atom); + printf("\tmax_qp_init_rd_atom:\t\t%d\n", device_attr.max_qp_init_rd_atom); + printf("\tmax_ee_init_rd_atom:\t\t%d\n", device_attr.max_ee_init_rd_atom); + printf("\tatomic_cap:\t\t\t%s (%d)\n", + atomic_cap_str(device_attr.atomic_cap), device_attr.atomic_cap); + printf("\tmax_ee:\t\t\t\t%d\n", device_attr.max_ee); + printf("\tmax_rdd:\t\t\t%d\n", device_attr.max_rdd); + printf("\tmax_mw:\t\t\t\t%d\n", device_attr.max_mw); + printf("\tmax_raw_ipv6_qp:\t\t%d\n", device_attr.max_raw_ipv6_qp); + printf("\tmax_raw_ethy_qp:\t\t%d\n", device_attr.max_raw_ethy_qp); + printf("\tmax_mcast_grp:\t\t\t%d\n", device_attr.max_mcast_grp); + printf("\tmax_mcast_qp_attach:\t\t%d\n", device_attr.max_mcast_qp_attach); + printf("\tmax_total_mcast_qp_attach:\t%d\n", + device_attr.max_total_mcast_qp_attach); + printf("\tmax_ah:\t\t\t\t%d\n", device_attr.max_ah); + printf("\tmax_fmr:\t\t\t%d\n", device_attr.max_fmr); + if (device_attr.max_fmr) { + printf("\tmax_map_per_fmr:\t\t%d\n", device_attr.max_map_per_fmr); + } + printf("\tmax_srq:\t\t\t%d\n", device_attr.max_srq); + if (device_attr.max_srq) { + printf("\tmax_srq_wr:\t\t\t%d\n", device_attr.max_srq_wr); + printf("\tmax_srq_sge:\t\t\t%d\n", device_attr.max_srq_sge); + } + printf("\tmax_pkeys:\t\t\t%d\n", device_attr.max_pkeys); + printf("\tlocal_ca_ack_delay:\t\t%d\n", device_attr.local_ca_ack_delay); + } + + for (port = 1; port <= device_attr.phys_port_cnt; ++port) { + /* if in the command line the user didn't ask for info about this port */ + if ((ib_port) && (port != ib_port)) + continue; + + rc = ibv_query_port(ctx, port, &port_attr); + if (rc) { + fprintf(stderr, "Failed to query port %u props\n", port); + goto cleanup; + } + printf("\t\tport:\t%d\n", port); + printf("\t\t\tstate:\t\t\t%s (%d)\n", + ibv_port_state_str(port_attr.state), port_attr.state); + printf("\t\t\tmax_mtu:\t\t%s (%d)\n", + mtu_str(port_attr.max_mtu), port_attr.max_mtu); + printf("\t\t\tactive_mtu:\t\t%s (%d)\n", + mtu_str(port_attr.active_mtu), port_attr.active_mtu); + printf("\t\t\tsm_lid:\t\t\t%d\n", port_attr.sm_lid); + printf("\t\t\tport_lid:\t\t%d\n", port_attr.lid); + printf("\t\t\tport_lmc:\t\t0x%02x\n", port_attr.lmc); + + if (verbose) { + printf("\t\t\tmax_msg_sz:\t\t0x%x\n", port_attr.max_msg_sz); + printf("\t\t\tport_cap_flags:\t\t0x%08x\n", port_attr.port_cap_flags); + printf("\t\t\tmax_vl_num:\t\t%s (%d)\n", + vl_str(port_attr.max_vl_num), port_attr.max_vl_num); + printf("\t\t\tbad_pkey_cntr:\t\t0x%x\n", port_attr.bad_pkey_cntr); + printf("\t\t\tqkey_viol_cntr:\t\t0x%x\n", port_attr.qkey_viol_cntr); + printf("\t\t\tsm_sl:\t\t\t%d\n", port_attr.sm_sl); + printf("\t\t\tpkey_tbl_len:\t\t%d\n", port_attr.pkey_tbl_len); + printf("\t\t\tgid_tbl_len:\t\t%d\n", port_attr.gid_tbl_len); + printf("\t\t\tsubnet_timeout:\t\t%d\n", port_attr.subnet_timeout); + printf("\t\t\tinit_type_reply:\t%d\n", port_attr.init_type_reply); + printf("\t\t\tactive_width:\t\t%sX (%d)\n", + width_str(port_attr.active_width), port_attr.active_width); + printf("\t\t\tactive_speed:\t\t%s (%d)\n", + speed_str(port_attr.active_speed), port_attr.active_speed); + printf("\t\t\tphys_state:\t\t%s (%d)\n", + port_phy_state_str(port_attr.phys_state), port_attr.phys_state); + + if (print_all_port_gids(ctx, port, port_attr.gid_tbl_len)) + goto cleanup; + } + printf("\n"); + } +cleanup: + if (ctx) + if (ibv_close_device(ctx)) { + fprintf(stderr, "Failed to close device"); + rc = 3; + } + return rc; +} + +static void usage(const char *argv0) +{ + printf("Usage: %s print the ca attributes\n", argv0); + printf("\n"); + printf("Options:\n"); + printf(" -d, --ib-dev= use IB device (default first device found)\n"); + printf(" -i, --ib-port= use port of IB device (default all ports)\n"); + printf(" -l, --list print only the IB devices names\n"); + printf(" -v, --verbose print all the attributes of the IB device(s)\n"); +} + +int __cdecl main(int argc, char *argv[]) +{ + char *ib_devname = NULL; + int ret = 0; + struct ibv_device **dev_list, **orig_dev_list; + int num_of_hcas; + uint8_t ib_port = 0; + + /* parse command line options */ + while (1) { + int c; + + c = getopt(argc, argv, "d:i:lv"); + if (c == -1) + break; + + switch (c) { + case 'd': + ib_devname = _strdup(optarg); + break; + + case 'i': + ib_port = (uint8_t) strtol(optarg, NULL, 0); + break; + + case 'v': + verbose = 1; + break; + + case 'l': + dev_list = orig_dev_list = ibv_get_device_list(&num_of_hcas); + if (!dev_list) { + fprintf(stderr, "Failed to get IB devices list"); + return -1; + } + + printf("%d HCA%s found:\n", num_of_hcas, + num_of_hcas != 1 ? "s" : ""); + + while (*dev_list) { + printf("\t%s\n", ibv_get_device_name(*dev_list)); + ++dev_list; + } + + printf("\n"); + + ibv_free_device_list(orig_dev_list); + + return 0; + + default: + usage(argv[0]); + return -1; + } + } + + dev_list = orig_dev_list = ibv_get_device_list(NULL); + if (!dev_list) { + fprintf(stderr, "Failed to get IB device list\n"); + return -1; + } + + if (ib_devname) { + while (*dev_list) { + if (!strcmp(ibv_get_device_name(*dev_list), ib_devname)) + break; + ++dev_list; + } + + if (!*dev_list) { + fprintf(stderr, "IB device '%s' wasn't found\n", ib_devname); + return -1; + } + + ret |= print_hca_cap(*dev_list, ib_port); + } else { + if (!*dev_list) { + fprintf(stderr, "No IB devices found\n"); + return -1; + } + + while (*dev_list) { + ret |= print_hca_cap(*dev_list, ib_port); + ++dev_list; + } + } + + if (ib_devname) + free(ib_devname); + + ibv_free_device_list(orig_dev_list); + + return ret; +} diff --git a/branches/WOF2-3/ulp/libibverbs/examples/devinfo/devinfo.rc b/branches/WOF2-3/ulp/libibverbs/examples/devinfo/devinfo.rc new file mode 100644 index 00000000..6bbe1451 --- /dev/null +++ b/branches/WOF2-3/ulp/libibverbs/examples/devinfo/devinfo.rc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef DBG +#define VER_FILEDESCRIPTION_STR "winverbs - Device information (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "winverbs - Device information " +#endif + +#define VER_INTERNALNAME_STR "ibv_devinfo.exe" +#define VER_ORIGINALFILENAME_STR "ibv_devinfo.exe" + +#include diff --git a/branches/WOF2-3/ulp/libibverbs/examples/devinfo/makefile b/branches/WOF2-3/ulp/libibverbs/examples/devinfo/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-3/ulp/libibverbs/examples/devinfo/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\..\inc\openib.def diff --git a/branches/WOF2-3/ulp/libibverbs/examples/dirs b/branches/WOF2-3/ulp/libibverbs/examples/dirs new file mode 100644 index 00000000..30a94ebe --- /dev/null +++ b/branches/WOF2-3/ulp/libibverbs/examples/dirs @@ -0,0 +1,6 @@ +DIRS = \ + devinfo \ + rc_pingpong \ + uc_pingpong \ + ud_pingpong \ + asyncwatch diff --git a/branches/WOF2-3/ulp/libibverbs/examples/pingpong.c b/branches/WOF2-3/ulp/libibverbs/examples/pingpong.c new file mode 100644 index 00000000..9fb0658e --- /dev/null +++ b/branches/WOF2-3/ulp/libibverbs/examples/pingpong.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2006 Cisco Systems. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "pingpong.h" + +enum ibv_mtu pp_mtu_to_enum(int mtu) +{ + switch (mtu) { + case 256: return IBV_MTU_256; + case 512: return IBV_MTU_512; + case 1024: return IBV_MTU_1024; + case 2048: return IBV_MTU_2048; + case 4096: return IBV_MTU_4096; + default: return -1; + } +} + +uint16_t pp_get_local_lid(struct ibv_context *context, int port) +{ + struct ibv_port_attr attr; + + if (ibv_query_port(context, (uint8_t) port, &attr)) + return 0; + + return attr.lid; +} diff --git a/branches/WOF2-3/ulp/libibverbs/examples/pingpong.h b/branches/WOF2-3/ulp/libibverbs/examples/pingpong.h new file mode 100644 index 00000000..3b59aaeb --- /dev/null +++ b/branches/WOF2-3/ulp/libibverbs/examples/pingpong.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2006 Cisco Systems. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef IBV_PINGPONG_H +#define IBV_PINGPONG_H + +#include + +enum ibv_mtu pp_mtu_to_enum(int mtu); +uint16_t pp_get_local_lid(struct ibv_context *context, int port); + +#endif /* IBV_PINGPONG_H */ diff --git a/branches/WOF2-3/ulp/libibverbs/examples/rc_pingpong/SOURCES b/branches/WOF2-3/ulp/libibverbs/examples/rc_pingpong/SOURCES new file mode 100644 index 00000000..e4d74d6e --- /dev/null +++ b/branches/WOF2-3/ulp/libibverbs/examples/rc_pingpong/SOURCES @@ -0,0 +1,31 @@ +TARGETNAME = ibv_rc_pingpong +TARGETPATH = ..\..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = PROGRAM + +UMTYPE = console +UMENTRY = main + +USE_MSVCRT = 1 +USE_STL = 1 +USE_NATIVE_EH = 1 +USE_IOSTREAM = 1 + +SOURCES = \ + rc_pingpong.rc \ + rc_pingpong.c + +INCLUDES = ..;..\..\include;..\..\..\..\inc;..\..\..\..\inc\user;\ + ..\..\..\..\inc\user\linux + +TARGETLIBS = \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\advapi32.lib \ + $(SDK_LIB_PATH)\user32.lib \ + $(SDK_LIB_PATH)\ole32.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\libibverbs.lib +!else + $(TARGETPATH)\*\libibverbsd.lib +!endif + diff --git a/branches/WOF2-3/ulp/libibverbs/examples/rc_pingpong/makefile b/branches/WOF2-3/ulp/libibverbs/examples/rc_pingpong/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-3/ulp/libibverbs/examples/rc_pingpong/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\..\inc\openib.def diff --git a/branches/WOF2-3/ulp/libibverbs/examples/rc_pingpong/rc_pingpong.c b/branches/WOF2-3/ulp/libibverbs/examples/rc_pingpong/rc_pingpong.c new file mode 100644 index 00000000..5f9511aa --- /dev/null +++ b/branches/WOF2-3/ulp/libibverbs/examples/rc_pingpong/rc_pingpong.c @@ -0,0 +1,752 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include + +#include "..\..\..\..\etc\user\getopt.c" +#include "..\pingpong.c" +#include + +enum { + PINGPONG_RECV_WRID = 1, + PINGPONG_SEND_WRID = 2, +}; + +struct pingpong_context { + struct ibv_context *context; + struct ibv_comp_channel *channel; + struct ibv_pd *pd; + struct ibv_mr *mr; + struct ibv_cq *cq; + struct ibv_qp *qp; + void *buf; + int size; + int rx_depth; + int pending; +}; + +struct pingpong_dest { + int lid; + int qpn; + int psn; +}; + +static int pp_connect_ctx(struct pingpong_context *ctx, int port, int my_psn, + enum ibv_mtu mtu, int sl, + struct pingpong_dest *dest) +{ + struct ibv_qp_attr attr; + + attr.qp_state = IBV_QPS_RTR; + attr.path_mtu = mtu; + attr.dest_qp_num = dest->qpn; + attr.rq_psn = dest->psn; + attr.max_dest_rd_atomic = 1; + attr.min_rnr_timer = 12; + attr.ah_attr.is_global = 0; + attr.ah_attr.dlid = (uint16_t) dest->lid; + attr.ah_attr.sl = (uint8_t) sl; + attr.ah_attr.src_path_bits = 0; + attr.ah_attr.port_num = (uint8_t) port; + + if (ibv_modify_qp(ctx->qp, &attr, + IBV_QP_STATE | + IBV_QP_AV | + IBV_QP_PATH_MTU | + IBV_QP_DEST_QPN | + IBV_QP_RQ_PSN | + IBV_QP_MAX_DEST_RD_ATOMIC | + IBV_QP_MIN_RNR_TIMER)) { + fprintf(stderr, "Failed to modify QP to RTR\n"); + return 1; + } + + attr.qp_state = IBV_QPS_RTS; + attr.timeout = 14; + attr.retry_cnt = 7; + attr.rnr_retry = 7; + attr.sq_psn = my_psn; + attr.max_rd_atomic = 1; + if (ibv_modify_qp(ctx->qp, &attr, + IBV_QP_STATE | + IBV_QP_TIMEOUT | + IBV_QP_RETRY_CNT | + IBV_QP_RNR_RETRY | + IBV_QP_SQ_PSN | + IBV_QP_MAX_QP_RD_ATOMIC)) { + fprintf(stderr, "Failed to modify QP to RTS\n"); + return 1; + } + + return 0; +} + +static struct pingpong_dest *pp_client_exch_dest(const char *servername, int port, + const struct pingpong_dest *my_dest) +{ + struct addrinfo *res, *t; + struct addrinfo hints; + char service[6]; + char msg[sizeof "0000:000000:000000"]; + int n; + SOCKET sockfd = INVALID_SOCKET; + struct pingpong_dest *rem_dest = NULL; + + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + sprintf(service, "%d\0", port); + + n = getaddrinfo(servername, service, &hints, &res); + + if (n != 0) { + fprintf(stderr, "%s for %s:%d\n", gai_strerror(n), servername, port); + return NULL; + } + + for (t = res; t; t = t->ai_next) { + sockfd = socket(t->ai_family, t->ai_socktype, t->ai_protocol); + if (sockfd != INVALID_SOCKET) { + if (!connect(sockfd, t->ai_addr, t->ai_addrlen)) + break; + closesocket(sockfd); + sockfd = INVALID_SOCKET; + } + } + + freeaddrinfo(res); + + if (sockfd == INVALID_SOCKET) { + fprintf(stderr, "Couldn't connect to %s:%d\n", servername, port); + return NULL; + } + + sprintf(msg, "%04x:%06x:%06x", my_dest->lid, my_dest->qpn, my_dest->psn); + if (send(sockfd, msg, sizeof msg, 0) != sizeof msg) { + fprintf(stderr, "Couldn't send local address\n"); + goto out; + } + + if (recv(sockfd, msg, sizeof msg, 0) != sizeof msg) { + perror("client recv"); + fprintf(stderr, "Couldn't recv remote address\n"); + goto out; + } + + send(sockfd, "done", sizeof "done", 0); + + rem_dest = malloc(sizeof *rem_dest); + if (!rem_dest) + goto out; + + sscanf(msg, "%x:%x:%x", &rem_dest->lid, &rem_dest->qpn, &rem_dest->psn); + +out: + closesocket(sockfd); + return rem_dest; +} + +static struct pingpong_dest *pp_server_exch_dest(struct pingpong_context *ctx, + int ib_port, enum ibv_mtu mtu, + int port, int sl, + const struct pingpong_dest *my_dest) +{ + struct addrinfo *res, *t; + struct addrinfo hints; + char service[6]; + char msg[sizeof "0000:000000:000000"]; + int n; + SOCKET sockfd = INVALID_SOCKET, connfd; + struct pingpong_dest *rem_dest = NULL; + + memset(&hints, 0, sizeof hints); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + sprintf(service, "%d\0", port); + + n = getaddrinfo(NULL, service, &hints, &res); + + if (n != 0) { + fprintf(stderr, "%s for port %d\n", gai_strerror(n), port); + return NULL; + } + + for (t = res; t; t = t->ai_next) { + sockfd = socket(t->ai_family, t->ai_socktype, t->ai_protocol); + if (sockfd != INVALID_SOCKET) { + n = 0; + setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &n, sizeof n); + n = 1; + setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *) &n, sizeof n); + + if (!bind(sockfd, t->ai_addr, t->ai_addrlen)) + break; + closesocket(sockfd); + sockfd = INVALID_SOCKET; + } + } + + freeaddrinfo(res); + + if (sockfd == INVALID_SOCKET) { + fprintf(stderr, "Couldn't listen to port %d\n", port); + return NULL; + } + + listen(sockfd, 1); + connfd = accept(sockfd, NULL, 0); + closesocket(sockfd); + if (connfd == INVALID_SOCKET) { + fprintf(stderr, "accept() failed\n"); + return NULL; + } + + n = recv(connfd, msg, sizeof msg, 0); + if (n != sizeof msg) { + perror("server recv"); + fprintf(stderr, "%d/%d: Couldn't recv remote address\n", n, (int) sizeof msg); + goto out; + } + + rem_dest = malloc(sizeof *rem_dest); + if (!rem_dest) + goto out; + + sscanf(msg, "%x:%x:%x", &rem_dest->lid, &rem_dest->qpn, &rem_dest->psn); + + if (pp_connect_ctx(ctx, ib_port, my_dest->psn, mtu, sl, rem_dest)) { + fprintf(stderr, "Couldn't connect to remote QP\n"); + free(rem_dest); + rem_dest = NULL; + goto out; + } + + sprintf(msg, "%04x:%06x:%06x", my_dest->lid, my_dest->qpn, my_dest->psn); + if (send(connfd, msg, sizeof msg, 0) != sizeof msg) { + fprintf(stderr, "Couldn't send local address\n"); + free(rem_dest); + rem_dest = NULL; + goto out; + } + + recv(connfd, msg, sizeof msg, 0); + +out: + closesocket(connfd); + return rem_dest; +} + +static struct pingpong_context *pp_init_ctx(struct ibv_device *ib_dev, int size, + int rx_depth, int port, + int use_event) +{ + struct pingpong_context *ctx; + + ctx = malloc(sizeof *ctx); + if (!ctx) + return NULL; + + ctx->size = size; + ctx->rx_depth = rx_depth; + + ctx->buf = malloc(size); + if (!ctx->buf) { + fprintf(stderr, "Couldn't allocate work buf.\n"); + return NULL; + } + + memset(ctx->buf, 0, size); + + ctx->context = ibv_open_device(ib_dev); + if (!ctx->context) { + fprintf(stderr, "Couldn't get context for %s\n", + ibv_get_device_name(ib_dev)); + return NULL; + } + + if (use_event) { + ctx->channel = ibv_create_comp_channel(ctx->context); + if (!ctx->channel) { + fprintf(stderr, "Couldn't create completion channel\n"); + return NULL; + } + } else + ctx->channel = NULL; + + ctx->pd = ibv_alloc_pd(ctx->context); + if (!ctx->pd) { + fprintf(stderr, "Couldn't allocate PD\n"); + return NULL; + } + + ctx->mr = ibv_reg_mr(ctx->pd, ctx->buf, size, IBV_ACCESS_LOCAL_WRITE); + if (!ctx->mr) { + fprintf(stderr, "Couldn't register MR\n"); + return NULL; + } + + ctx->cq = ibv_create_cq(ctx->context, rx_depth + 1, NULL, + ctx->channel, 0); + if (!ctx->cq) { + fprintf(stderr, "Couldn't create CQ\n"); + return NULL; + } + + { + struct ibv_qp_init_attr attr; + + memset(&attr, 0, sizeof attr); + attr.send_cq = ctx->cq; + attr.recv_cq = ctx->cq; + attr.cap.max_send_wr = 1; + attr.cap.max_recv_wr = rx_depth; + attr.cap.max_send_sge = 1; + attr.cap.max_recv_sge = 1; + attr.qp_type = IBV_QPT_RC; + + ctx->qp = ibv_create_qp(ctx->pd, &attr); + if (!ctx->qp) { + fprintf(stderr, "Couldn't create QP\n"); + return NULL; + } + } + + { + struct ibv_qp_attr attr; + + memset(&attr, 0, sizeof attr); + attr.qp_state = IBV_QPS_INIT; + attr.pkey_index = 0; + attr.port_num = (uint8_t) port; + attr.qp_access_flags = 0; + + if (ibv_modify_qp(ctx->qp, &attr, + IBV_QP_STATE | + IBV_QP_PKEY_INDEX | + IBV_QP_PORT | + IBV_QP_ACCESS_FLAGS)) { + fprintf(stderr, "Failed to modify QP to INIT\n"); + return NULL; + } + } + + return ctx; +} + +int pp_close_ctx(struct pingpong_context *ctx) +{ + if (ibv_destroy_qp(ctx->qp)) { + fprintf(stderr, "Couldn't destroy QP\n"); + return 1; + } + + if (ibv_destroy_cq(ctx->cq)) { + fprintf(stderr, "Couldn't destroy CQ\n"); + return 1; + } + + if (ibv_dereg_mr(ctx->mr)) { + fprintf(stderr, "Couldn't deregister MR\n"); + return 1; + } + + if (ibv_dealloc_pd(ctx->pd)) { + fprintf(stderr, "Couldn't deallocate PD\n"); + return 1; + } + + if (ctx->channel) { + if (ibv_destroy_comp_channel(ctx->channel)) { + fprintf(stderr, "Couldn't destroy completion channel\n"); + return 1; + } + } + + if (ibv_close_device(ctx->context)) { + fprintf(stderr, "Couldn't release context\n"); + return 1; + } + + free(ctx->buf); + free(ctx); + + return 0; +} + +static int pp_post_recv(struct pingpong_context *ctx, int n) +{ + struct ibv_sge list; + struct ibv_recv_wr wr; + struct ibv_recv_wr *bad_wr; + int i; + + list.addr = (uintptr_t) ctx->buf; + list.length = ctx->size; + list.lkey = ctx->mr->lkey; + wr.next = NULL; + wr.wr_id = PINGPONG_RECV_WRID; + wr.sg_list = &list; + wr.num_sge = 1; + + for (i = 0; i < n; ++i) + if (ibv_post_recv(ctx->qp, &wr, &bad_wr)) + break; + + return i; +} + +static int pp_post_send(struct pingpong_context *ctx) +{ + struct ibv_sge list; + struct ibv_send_wr wr; + struct ibv_send_wr *bad_wr; + + list.addr = (uintptr_t) ctx->buf; + list.length = ctx->size; + list.lkey = ctx->mr->lkey; + wr.next = NULL; + wr.wr_id = PINGPONG_SEND_WRID; + wr.sg_list = &list; + wr.num_sge = 1; + wr.opcode = IBV_WR_SEND; + wr.send_flags = IBV_SEND_SIGNALED; + + return ibv_post_send(ctx->qp, &wr, &bad_wr); +} + +static void usage(const char *argv0) +{ + printf("Usage:\n"); + printf(" %s start a server and wait for connection\n", argv0); + printf(" %s -h connect to server at \n", argv0); + printf("\n"); + printf("Options:\n"); + printf(" -p listen on/connect to port (default 18515)\n"); + printf(" -d use IB device (default first device found)\n"); + printf(" -i use port of IB device (default 1)\n"); + printf(" -s size of message to exchange (default 4096)\n"); + printf(" -m path MTU (default 1024)\n"); + printf(" -r number of receives to post at a time (default 500)\n"); + printf(" -n number of exchanges (default 1000)\n"); + printf(" -l service level value\n"); + printf(" -e sleep on CQ events (default poll)\n"); +} + +int __cdecl main(int argc, char *argv[]) +{ + struct ibv_device **dev_list; + struct ibv_device *ib_dev; + struct pingpong_context *ctx; + struct pingpong_dest my_dest; + struct pingpong_dest *rem_dest; + LARGE_INTEGER start, end, freq; + char *ib_devname = NULL; + char *servername = NULL; + int port = 18515; + int ib_port = 1; + int size = 4096; + enum ibv_mtu mtu = IBV_MTU_1024; + int rx_depth = 500; + int iters = 1000; + int use_event = 0; + int routs; + int rcnt, scnt; + int num_cq_events = 0; + int sl = 0; + WORD version; + WSADATA data; + int err; + + srand((unsigned int) time(NULL)); + version = MAKEWORD(2, 2); + err = WSAStartup(version, &data); + if (err) + return -1; + + while (1) { + int c; + + c = getopt(argc, argv, "h:p:d:i:s:m:r:n:l:e"); + if (c == -1) + break; + + switch (c) { + case 'p': + port = strtol(optarg, NULL, 0); + if (port < 0 || port > 65535) { + usage(argv[0]); + return 1; + } + break; + + case 'd': + ib_devname = _strdup(optarg); + break; + + case 'i': + ib_port = strtol(optarg, NULL, 0); + if (ib_port < 0) { + usage(argv[0]); + return 1; + } + break; + + case 's': + size = strtol(optarg, NULL, 0); + break; + + case 'm': + mtu = pp_mtu_to_enum(strtol(optarg, NULL, 0)); + if (mtu < 0) { + usage(argv[0]); + return 1; + } + + case 'r': + rx_depth = strtol(optarg, NULL, 0); + break; + + case 'n': + iters = strtol(optarg, NULL, 0); + break; + + case 'l': + sl = strtol(optarg, NULL, 0); + break; + + case 'e': + ++use_event; + break; + + case 'h': + servername = _strdup(optarg); + break; + + default: + usage(argv[0]); + return 1; + } + } + + dev_list = ibv_get_device_list(NULL); + if (!dev_list) { + fprintf(stderr, "No IB devices found\n"); + return 1; + } + + if (!ib_devname) { + ib_dev = *dev_list; + if (!ib_dev) { + fprintf(stderr, "No IB devices found\n"); + return 1; + } + } else { + int i; + for (i = 0; dev_list[i]; ++i) + if (!strcmp(ibv_get_device_name(dev_list[i]), ib_devname)) + break; + ib_dev = dev_list[i]; + if (!ib_dev) { + fprintf(stderr, "IB device %s not found\n", ib_devname); + return 1; + } + } + + ctx = pp_init_ctx(ib_dev, size, rx_depth, ib_port, use_event); + if (!ctx) + return 1; + + routs = pp_post_recv(ctx, ctx->rx_depth); + if (routs < ctx->rx_depth) { + fprintf(stderr, "Couldn't post receive (%d)\n", routs); + return 1; + } + + if (use_event) + if (ibv_req_notify_cq(ctx->cq, 0)) { + fprintf(stderr, "Couldn't request CQ notification\n"); + return 1; + } + + my_dest.lid = pp_get_local_lid(ctx->context, ib_port); + my_dest.qpn = ctx->qp->qp_num; + my_dest.psn = rand() & 0xffffff; + if (!my_dest.lid) { + fprintf(stderr, "Couldn't get local LID\n"); + return 1; + } + + printf(" local address: LID 0x%04x, QPN 0x%06x, PSN 0x%06x\n", + my_dest.lid, my_dest.qpn, my_dest.psn); + + if (servername) + rem_dest = pp_client_exch_dest(servername, port, &my_dest); + else + rem_dest = pp_server_exch_dest(ctx, ib_port, mtu, port, sl, &my_dest); + + if (!rem_dest) + return 1; + + printf(" remote address: LID 0x%04x, QPN 0x%06x, PSN 0x%06x\n", + rem_dest->lid, rem_dest->qpn, rem_dest->psn); + + if (servername) + if (pp_connect_ctx(ctx, ib_port, my_dest.psn, mtu, sl, rem_dest)) + return 1; + + ctx->pending = PINGPONG_RECV_WRID; + + if (servername) { + if (pp_post_send(ctx)) { + fprintf(stderr, "Couldn't post send\n"); + return 1; + } + ctx->pending |= PINGPONG_SEND_WRID; + } + + if (!QueryPerformanceCounter(&start)) { + perror("QueryPerformanceCounter"); + return 1; + } + + rcnt = scnt = 0; + while (rcnt < iters || scnt < iters) { + if (use_event) { + struct ibv_cq *ev_cq; + void *ev_ctx; + + if (ibv_get_cq_event(ctx->channel, &ev_cq, &ev_ctx)) { + fprintf(stderr, "Failed to get cq_event\n"); + return 1; + } + + ++num_cq_events; + + if (ev_cq != ctx->cq) { + fprintf(stderr, "CQ event for unknown CQ %p\n", ev_cq); + return 1; + } + + if (ibv_req_notify_cq(ctx->cq, 0)) { + fprintf(stderr, "Couldn't request CQ notification\n"); + return 1; + } + } + + { + struct ibv_wc wc[2]; + int ne, i; + + do { + ne = ibv_poll_cq(ctx->cq, 2, wc); + if (ne < 0) { + fprintf(stderr, "poll CQ failed %d\n", ne); + return 1; + } + } while (!use_event && ne < 1); + + for (i = 0; i < ne; ++i) { + if (wc[i].status != IBV_WC_SUCCESS) { + fprintf(stderr, "Failed status %s (%d) for wr_id %d\n", + ibv_wc_status_str(wc[i].status), + wc[i].status, (int) wc[i].wr_id); + return 1; + } + + switch ((int) wc[i].wr_id) { + case PINGPONG_SEND_WRID: + ++scnt; + break; + + case PINGPONG_RECV_WRID: + if (--routs <= 1) { + routs += pp_post_recv(ctx, ctx->rx_depth - routs); + if (routs < ctx->rx_depth) { + fprintf(stderr, + "Couldn't post receive (%d)\n", + routs); + return 1; + } + } + + ++rcnt; + break; + + default: + fprintf(stderr, "Completion for unknown wr_id %d\n", + (int) wc[i].wr_id); + return 1; + } + + ctx->pending &= ~(int) wc[i].wr_id; + if (scnt < iters && !ctx->pending) { + if (pp_post_send(ctx)) { + fprintf(stderr, "Couldn't post send\n"); + return 1; + } + ctx->pending = PINGPONG_RECV_WRID | + PINGPONG_SEND_WRID; + } + } + } + } + + if (!QueryPerformanceCounter(&end) || + !QueryPerformanceFrequency(&freq)) { + perror("QueryPerformanceCounter/Frequency"); + return 1; + } + + { + double sec = (double) (end.QuadPart - start.QuadPart) / (double) freq.QuadPart; + long long bytes = (long long) size * iters * 2; + + printf("%I64d bytes in %.2f seconds = %.2f Mbit/sec\n", + bytes, sec, bytes * 8. / 1000000. / sec); + printf("%d iters in %.2f seconds = %.2f usec/iter\n", + iters, sec, sec * 1000000. / iters); + } + + ibv_ack_cq_events(ctx->cq, num_cq_events); + + if (pp_close_ctx(ctx)) + return 1; + + ibv_free_device_list(dev_list); + free(rem_dest); + + return 0; +} diff --git a/branches/WOF2-3/ulp/libibverbs/examples/rc_pingpong/rc_pingpong.rc b/branches/WOF2-3/ulp/libibverbs/examples/rc_pingpong/rc_pingpong.rc new file mode 100644 index 00000000..7365c013 --- /dev/null +++ b/branches/WOF2-3/ulp/libibverbs/examples/rc_pingpong/rc_pingpong.rc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef DBG +#define VER_FILEDESCRIPTION_STR "winverbs - Reliable Connection pingpong test (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "winverbs - Reliable Connection pingpong test" +#endif + +#define VER_INTERNALNAME_STR "ibv_send_bw.exe" +#define VER_ORIGINALFILENAME_STR "ibv_send_bw.exe" + +#include diff --git a/branches/WOF2-3/ulp/libibverbs/examples/srq_pingpong/SOURCES b/branches/WOF2-3/ulp/libibverbs/examples/srq_pingpong/SOURCES new file mode 100644 index 00000000..9e55c726 --- /dev/null +++ b/branches/WOF2-3/ulp/libibverbs/examples/srq_pingpong/SOURCES @@ -0,0 +1,29 @@ +TARGETNAME = ibv_srq_pingpong +TARGETPATH = ..\..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = PROGRAM + +UMTYPE = console +UMENTRY = main + +USE_MSVCRT = 1 +USE_STL = 1 +USE_NATIVE_EH = 1 +USE_IOSTREAM = 1 + +SOURCES = \ + srq_pingpong.c + +INCLUDES = ..;..\..\include;..\..\..\..\inc;..\..\..\..\inc\user; + +TARGETLIBS = \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\advapi32.lib \ + $(SDK_LIB_PATH)\user32.lib \ + $(SDK_LIB_PATH)\ole32.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\libibverbs.lib +!else + $(TARGETPATH)\*\libibverbsd.lib +!endif + diff --git a/branches/WOF2-3/ulp/libibverbs/examples/srq_pingpong/makefile b/branches/WOF2-3/ulp/libibverbs/examples/srq_pingpong/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-3/ulp/libibverbs/examples/srq_pingpong/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\..\inc\openib.def diff --git a/branches/WOF2-3/ulp/libibverbs/examples/srq_pingpong/srq_pingpong.c b/branches/WOF2-3/ulp/libibverbs/examples/srq_pingpong/srq_pingpong.c new file mode 100644 index 00000000..36446aa8 --- /dev/null +++ b/branches/WOF2-3/ulp/libibverbs/examples/srq_pingpong/srq_pingpong.c @@ -0,0 +1,886 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pingpong.h" + +enum { + PINGPONG_RECV_WRID = 1, + PINGPONG_SEND_WRID = 2, + + MAX_QP = 256, +}; + +static int page_size; + +struct pingpong_context { + struct ibv_context *context; + struct ibv_comp_channel *channel; + struct ibv_pd *pd; + struct ibv_mr *mr; + struct ibv_cq *cq; + struct ibv_srq *srq; + struct ibv_qp *qp[MAX_QP]; + void *buf; + int size; + int num_qp; + int rx_depth; + int pending[MAX_QP]; +}; + +struct pingpong_dest { + int lid; + int qpn; + int psn; +}; + +static int pp_connect_ctx(struct pingpong_context *ctx, int port, enum ibv_mtu mtu, + int sl, const struct pingpong_dest *my_dest, + const struct pingpong_dest *dest) +{ + int i; + + for (i = 0; i < ctx->num_qp; ++i) { + struct ibv_qp_attr attr = { + .qp_state = IBV_QPS_RTR, + .path_mtu = mtu, + .dest_qp_num = dest[i].qpn, + .rq_psn = dest[i].psn, + .max_dest_rd_atomic = 1, + .min_rnr_timer = 12, + .ah_attr = { + .is_global = 0, + .dlid = dest[i].lid, + .sl = sl, + .src_path_bits = 0, + .port_num = port + } + }; + if (ibv_modify_qp(ctx->qp[i], &attr, + IBV_QP_STATE | + IBV_QP_AV | + IBV_QP_PATH_MTU | + IBV_QP_DEST_QPN | + IBV_QP_RQ_PSN | + IBV_QP_MAX_DEST_RD_ATOMIC | + IBV_QP_MIN_RNR_TIMER)) { + fprintf(stderr, "Failed to modify QP[%d] to RTR\n", i); + return 1; + } + + attr.qp_state = IBV_QPS_RTS; + attr.timeout = 14; + attr.retry_cnt = 7; + attr.rnr_retry = 7; + attr.sq_psn = my_dest[i].psn; + attr.max_rd_atomic = 1; + if (ibv_modify_qp(ctx->qp[i], &attr, + IBV_QP_STATE | + IBV_QP_TIMEOUT | + IBV_QP_RETRY_CNT | + IBV_QP_RNR_RETRY | + IBV_QP_SQ_PSN | + IBV_QP_MAX_QP_RD_ATOMIC)) { + fprintf(stderr, "Failed to modify QP[%d] to RTS\n", i); + return 1; + } + } + + return 0; +} + +static struct pingpong_dest *pp_client_exch_dest(const char *servername, int port, + const struct pingpong_dest *my_dest) +{ + struct addrinfo *res, *t; + struct addrinfo hints = { + .ai_family = AF_UNSPEC, + .ai_socktype = SOCK_STREAM + }; + char *service; + char msg[ sizeof "0000:000000:000000"]; + int n; + int r; + int i; + int sockfd = -1; + struct pingpong_dest *rem_dest = NULL; + + if (asprintf(&service, "%d", port) < 0) + return NULL; + + n = getaddrinfo(servername, service, &hints, &res); + + if (n < 0) { + fprintf(stderr, "%s for %s:%d\n", gai_strerror(n), servername, port); + free(service); + return NULL; + } + + for (t = res; t; t = t->ai_next) { + sockfd = socket(t->ai_family, t->ai_socktype, t->ai_protocol); + if (sockfd >= 0) { + if (!connect(sockfd, t->ai_addr, t->ai_addrlen)) + break; + close(sockfd); + sockfd = -1; + } + } + + freeaddrinfo(res); + free(service); + + if (sockfd < 0) { + fprintf(stderr, "Couldn't connect to %s:%d\n", servername, port); + return NULL; + } + + for (i = 0; i < MAX_QP; ++i) { + sprintf(msg, "%04x:%06x:%06x", my_dest[i].lid, my_dest[i].qpn, my_dest[i].psn); + if (write(sockfd, msg, sizeof msg) != sizeof msg) { + fprintf(stderr, "Couldn't send local address\n"); + goto out; + } + } + + rem_dest = malloc(MAX_QP * sizeof *rem_dest); + if (!rem_dest) + goto out; + + for (i = 0; i < MAX_QP; ++i) { + n = 0; + while (n < sizeof msg) { + r = read(sockfd, msg + n, sizeof msg - n); + if (r < 0) { + perror("client read"); + fprintf(stderr, "%d/%d: Couldn't read remote address [%d]\n", + n, (int) sizeof msg, i); + goto out; + } + n += r; + } + + sscanf(msg, "%x:%x:%x", + &rem_dest[i].lid, &rem_dest[i].qpn, &rem_dest[i].psn); + } + + write(sockfd, "done", sizeof "done"); + +out: + close(sockfd); + return rem_dest; +} + +static struct pingpong_dest *pp_server_exch_dest(struct pingpong_context *ctx, + int ib_port, enum ibv_mtu mtu, + int port, int sl, + const struct pingpong_dest *my_dest) +{ + struct addrinfo *res, *t; + struct addrinfo hints = { + .ai_flags = AI_PASSIVE, + .ai_family = AF_UNSPEC, + .ai_socktype = SOCK_STREAM + }; + char *service; + char msg[ sizeof "0000:000000:000000"]; + int n; + int r; + int i; + int sockfd = -1, connfd; + struct pingpong_dest *rem_dest = NULL; + + if (asprintf(&service, "%d", port) < 0) + return NULL; + + n = getaddrinfo(NULL, service, &hints, &res); + + if (n < 0) { + fprintf(stderr, "%s for port %d\n", gai_strerror(n), port); + free(service); + return NULL; + } + + for (t = res; t; t = t->ai_next) { + sockfd = socket(t->ai_family, t->ai_socktype, t->ai_protocol); + if (sockfd >= 0) { + n = 0; + setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &n, sizeof n); + n = 1; + setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *) &n, sizeof n); + + if (!bind(sockfd, t->ai_addr, t->ai_addrlen)) + break; + close(sockfd); + sockfd = -1; + } + } + + freeaddrinfo(res); + free(service); + + if (sockfd < 0) { + fprintf(stderr, "Couldn't listen to port %d\n", port); + return NULL; + } + + listen(sockfd, 1); + connfd = accept(sockfd, NULL, 0); + close(sockfd); + if (connfd < 0) { + fprintf(stderr, "accept() failed\n"); + return NULL; + } + + rem_dest = malloc(MAX_QP *sizeof *rem_dest); + if (!rem_dest) + goto out; + + for (i = 0; i < MAX_QP; ++i) { + n = 0; + while (n < sizeof msg) { + r = read(connfd, msg + n, sizeof msg - n); + if (r < 0) { + perror("server read"); + fprintf(stderr, "%d/%d: Couldn't read remote address [%d]\n", + n, (int) sizeof msg, i); + goto out; + } + n += r; + } + + sscanf(msg, "%x:%x:%x", + &rem_dest[i].lid, &rem_dest[i].qpn, &rem_dest[i].psn); + } + + if (pp_connect_ctx(ctx, ib_port, mtu, sl, my_dest, rem_dest)) { + fprintf(stderr, "Couldn't connect to remote QP\n"); + free(rem_dest); + rem_dest = NULL; + goto out; + } + + for (i = 0; i < MAX_QP; ++i) { + sprintf(msg, "%04x:%06x:%06x", my_dest[i].lid, my_dest[i].qpn, my_dest[i].psn); + if (write(connfd, msg, sizeof msg) != sizeof msg) { + fprintf(stderr, "Couldn't send local address\n"); + free(rem_dest); + rem_dest = NULL; + goto out; + } + } + + read(connfd, msg, sizeof msg); + +out: + close(connfd); + return rem_dest; +} + +static struct pingpong_context *pp_init_ctx(struct ibv_device *ib_dev, int size, + int num_qp, int rx_depth, int port, + int use_event) +{ + struct pingpong_context *ctx; + int i; + + ctx = malloc(sizeof *ctx); + if (!ctx) + return NULL; + + ctx->size = size; + ctx->num_qp = num_qp; + ctx->rx_depth = rx_depth; + + ctx->buf = memalign(page_size, size); + if (!ctx->buf) { + fprintf(stderr, "Couldn't allocate work buf.\n"); + return NULL; + } + + memset(ctx->buf, 0, size); + + ctx->context = ibv_open_device(ib_dev); + if (!ctx->context) { + fprintf(stderr, "Couldn't get context for %s\n", + ibv_get_device_name(ib_dev)); + return NULL; + } + + if (use_event) { + ctx->channel = ibv_create_comp_channel(ctx->context); + if (!ctx->channel) { + fprintf(stderr, "Couldn't create completion channel\n"); + return NULL; + } + } else + ctx->channel = NULL; + + ctx->pd = ibv_alloc_pd(ctx->context); + if (!ctx->pd) { + fprintf(stderr, "Couldn't allocate PD\n"); + return NULL; + } + + ctx->mr = ibv_reg_mr(ctx->pd, ctx->buf, size, IBV_ACCESS_LOCAL_WRITE); + if (!ctx->mr) { + fprintf(stderr, "Couldn't register MR\n"); + return NULL; + } + + ctx->cq = ibv_create_cq(ctx->context, rx_depth + num_qp, NULL, + ctx->channel, 0); + if (!ctx->cq) { + fprintf(stderr, "Couldn't create CQ\n"); + return NULL; + } + + { + struct ibv_srq_init_attr attr = { + .attr = { + .max_wr = rx_depth, + .max_sge = 1 + } + }; + + ctx->srq = ibv_create_srq(ctx->pd, &attr); + if (!ctx->srq) { + fprintf(stderr, "Couldn't create SRQ\n"); + return NULL; + } + } + + for (i = 0; i < num_qp; ++i) { + struct ibv_qp_init_attr attr = { + .send_cq = ctx->cq, + .recv_cq = ctx->cq, + .srq = ctx->srq, + .cap = { + .max_send_wr = 1, + .max_send_sge = 1, + }, + .qp_type = IBV_QPT_RC + }; + + ctx->qp[i] = ibv_create_qp(ctx->pd, &attr); + if (!ctx->qp[i]) { + fprintf(stderr, "Couldn't create QP[%d]\n", i); + return NULL; + } + } + + for (i = 0; i < num_qp; ++i) { + struct ibv_qp_attr attr = { + .qp_state = IBV_QPS_INIT, + .pkey_index = 0, + .port_num = port, + .qp_access_flags = 0 + }; + + if (ibv_modify_qp(ctx->qp[i], &attr, + IBV_QP_STATE | + IBV_QP_PKEY_INDEX | + IBV_QP_PORT | + IBV_QP_ACCESS_FLAGS)) { + fprintf(stderr, "Failed to modify QP[%d] to INIT\n", i); + return NULL; + } + } + + return ctx; +} + +int pp_close_ctx(struct pingpong_context *ctx, int num_qp) +{ + int i; + + for (i = 0; i < num_qp; ++i) { + if (ibv_destroy_qp(ctx->qp[i])) { + fprintf(stderr, "Couldn't destroy QP[%d]\n", i); + return 1; + } + } + + if (ibv_destroy_srq(ctx->srq)) { + fprintf(stderr, "Couldn't destroy SRQ\n"); + return 1; + } + + if (ibv_destroy_cq(ctx->cq)) { + fprintf(stderr, "Couldn't destroy CQ\n"); + return 1; + } + + if (ibv_dereg_mr(ctx->mr)) { + fprintf(stderr, "Couldn't deregister MR\n"); + return 1; + } + + if (ibv_dealloc_pd(ctx->pd)) { + fprintf(stderr, "Couldn't deallocate PD\n"); + return 1; + } + + if (ctx->channel) { + if (ibv_destroy_comp_channel(ctx->channel)) { + fprintf(stderr, "Couldn't destroy completion channel\n"); + return 1; + } + } + + if (ibv_close_device(ctx->context)) { + fprintf(stderr, "Couldn't release context\n"); + return 1; + } + + free(ctx->buf); + free(ctx); + + return 0; +} + +static int pp_post_recv(struct pingpong_context *ctx, int n) +{ + struct ibv_sge list = { + .addr = (uintptr_t) ctx->buf, + .length = ctx->size, + .lkey = ctx->mr->lkey + }; + struct ibv_recv_wr wr = { + .wr_id = PINGPONG_RECV_WRID, + .sg_list = &list, + .num_sge = 1, + }; + struct ibv_recv_wr *bad_wr; + int i; + + for (i = 0; i < n; ++i) + if (ibv_post_srq_recv(ctx->srq, &wr, &bad_wr)) + break; + + return i; +} + +static int pp_post_send(struct pingpong_context *ctx, int qp_index) +{ + struct ibv_sge list = { + .addr = (uintptr_t) ctx->buf, + .length = ctx->size, + .lkey = ctx->mr->lkey + }; + struct ibv_send_wr wr = { + .wr_id = PINGPONG_SEND_WRID, + .sg_list = &list, + .num_sge = 1, + .opcode = IBV_WR_SEND, + .send_flags = IBV_SEND_SIGNALED, + }; + struct ibv_send_wr *bad_wr; + + return ibv_post_send(ctx->qp[qp_index], &wr, &bad_wr); +} + +static int find_qp(int qpn, struct pingpong_context *ctx, int num_qp) +{ + int i; + + for (i = 0; i < num_qp; ++i) + if (ctx->qp[i]->qp_num == qpn) + return i; + + return -1; +} + +static void usage(const char *argv0) +{ + printf("Usage:\n"); + printf(" %s start a server and wait for connection\n", argv0); + printf(" %s connect to server at \n", argv0); + printf("\n"); + printf("Options:\n"); + printf(" -p, --port= listen on/connect to port (default 18515)\n"); + printf(" -d, --ib-dev= use IB device (default first device found)\n"); + printf(" -i, --ib-port= use port of IB device (default 1)\n"); + printf(" -s, --size= size of message to exchange (default 4096)\n"); + printf(" -m, --mtu= path MTU (default 1024)\n"); + printf(" -q, --num-qp= number of QPs to use (default 16)\n"); + printf(" -r, --rx-depth= number of receives to post at a time (default 500)\n"); + printf(" -n, --iters= number of exchanges per QP(default 1000)\n"); + printf(" -l, --sl= service level value\n"); + printf(" -e, --events sleep on CQ events (default poll)\n"); +} + +int main(int argc, char *argv[]) +{ + struct ibv_device **dev_list; + struct ibv_device *ib_dev; + struct ibv_wc *wc; + struct pingpong_context *ctx; + struct pingpong_dest my_dest[MAX_QP]; + struct pingpong_dest *rem_dest; + struct timeval start, end; + char *ib_devname = NULL; + char *servername = NULL; + int port = 18515; + int ib_port = 1; + int size = 4096; + enum ibv_mtu mtu = IBV_MTU_1024; + int num_qp = 16; + int rx_depth = 500; + int iters = 1000; + int use_event = 0; + int routs; + int rcnt, scnt; + int num_wc; + int i; + int num_cq_events = 0; + int sl = 0; + + srand48(getpid() * time(NULL)); + + while (1) { + int c; + + static struct option long_options[] = { + { .name = "port", .has_arg = 1, .val = 'p' }, + { .name = "ib-dev", .has_arg = 1, .val = 'd' }, + { .name = "ib-port", .has_arg = 1, .val = 'i' }, + { .name = "size", .has_arg = 1, .val = 's' }, + { .name = "mtu", .has_arg = 1, .val = 'm' }, + { .name = "num-qp", .has_arg = 1, .val = 'q' }, + { .name = "rx-depth", .has_arg = 1, .val = 'r' }, + { .name = "iters", .has_arg = 1, .val = 'n' }, + { .name = "sl", .has_arg = 1, .val = 'l' }, + { .name = "events", .has_arg = 0, .val = 'e' }, + { 0 } + }; + + c = getopt_long(argc, argv, "p:d:i:s:m:q:r:n:l:e", long_options, NULL); + if (c == -1) + break; + + switch (c) { + case 'p': + port = strtol(optarg, NULL, 0); + if (port < 0 || port > 65535) { + usage(argv[0]); + return 1; + } + break; + + case 'd': + ib_devname = strdupa(optarg); + break; + + case 'i': + ib_port = strtol(optarg, NULL, 0); + if (ib_port < 0) { + usage(argv[0]); + return 1; + } + break; + + case 's': + size = strtol(optarg, NULL, 0); + break; + + case 'm': + mtu = pp_mtu_to_enum(strtol(optarg, NULL, 0)); + if (mtu < 0) { + usage(argv[0]); + return 1; + } + break; + + case 'q': + num_qp = strtol(optarg, NULL, 0); + break; + + case 'r': + rx_depth = strtol(optarg, NULL, 0); + break; + + case 'n': + iters = strtol(optarg, NULL, 0); + break; + + case 'l': + sl = strtol(optarg, NULL, 0); + break; + + case 'e': + ++use_event; + break; + + default: + usage(argv[0]); + return 1; + } + } + + if (optind == argc - 1) + servername = strdupa(argv[optind]); + else if (optind < argc) { + usage(argv[0]); + return 1; + } + + if (num_qp > rx_depth) { + fprintf(stderr, "rx_depth %d is too small for %d QPs -- " + "must have at least one receive per QP.\n", + rx_depth, num_qp); + return 1; + } + + num_wc = num_qp + rx_depth; + wc = alloca(num_wc * sizeof *wc); + + page_size = sysconf(_SC_PAGESIZE); + + dev_list = ibv_get_device_list(NULL); + if (!dev_list) { + fprintf(stderr, "No IB devices found\n"); + return 1; + } + + if (!ib_devname) { + ib_dev = *dev_list; + if (!ib_dev) { + fprintf(stderr, "No IB devices found\n"); + return 1; + } + } else { + int i; + for (i = 0; dev_list[i]; ++i) + if (!strcmp(ibv_get_device_name(dev_list[i]), ib_devname)) + break; + ib_dev = dev_list[i]; + if (!ib_dev) { + fprintf(stderr, "IB device %s not found\n", ib_devname); + return 1; + } + } + + ctx = pp_init_ctx(ib_dev, size, num_qp, rx_depth, ib_port, use_event); + if (!ctx) + return 1; + + routs = pp_post_recv(ctx, ctx->rx_depth); + if (routs < ctx->rx_depth) { + fprintf(stderr, "Couldn't post receive (%d)\n", routs); + return 1; + } + + if (use_event) + if (ibv_req_notify_cq(ctx->cq, 0)) { + fprintf(stderr, "Couldn't request CQ notification\n"); + return 1; + } + + memset(my_dest, 0, sizeof my_dest); + + for (i = 0; i < num_qp; ++i) { + my_dest[i].qpn = ctx->qp[i]->qp_num; + my_dest[i].psn = lrand48() & 0xffffff; + my_dest[i].lid = pp_get_local_lid(ctx->context, ib_port); + if (!my_dest[i].lid) { + fprintf(stderr, "Couldn't get local LID\n"); + return 1; + } + + printf(" local address: LID 0x%04x, QPN 0x%06x, PSN 0x%06x\n", + my_dest[i].lid, my_dest[i].qpn, my_dest[i].psn); + } + + if (servername) + rem_dest = pp_client_exch_dest(servername, port, my_dest); + else + rem_dest = pp_server_exch_dest(ctx, ib_port, mtu, port, sl, my_dest); + + if (!rem_dest) + return 1; + + for (i = 0; i < num_qp; ++i) + printf(" remote address: LID 0x%04x, QPN 0x%06x, PSN 0x%06x\n", + rem_dest[i].lid, rem_dest[i].qpn, rem_dest[i].psn); + + if (servername) + if (pp_connect_ctx(ctx, ib_port, mtu, sl, my_dest, rem_dest)) + return 1; + + if (servername) + for (i = 0; i < num_qp; ++i) { + if (pp_post_send(ctx, i)) { + fprintf(stderr, "Couldn't post send\n"); + return 1; + } + ctx->pending[i] = PINGPONG_SEND_WRID | PINGPONG_RECV_WRID; + } + else + for (i = 0; i < num_qp; ++i) + ctx->pending[i] = PINGPONG_RECV_WRID; + + if (gettimeofday(&start, NULL)) { + perror("gettimeofday"); + return 1; + } + + rcnt = scnt = 0; + while (rcnt < iters || scnt < iters) { + if (use_event) { + struct ibv_cq *ev_cq; + void *ev_ctx; + + if (ibv_get_cq_event(ctx->channel, &ev_cq, &ev_ctx)) { + fprintf(stderr, "Failed to get cq_event\n"); + return 1; + } + + ++num_cq_events; + + if (ev_cq != ctx->cq) { + fprintf(stderr, "CQ event for unknown CQ %p\n", ev_cq); + return 1; + } + + if (ibv_req_notify_cq(ctx->cq, 0)) { + fprintf(stderr, "Couldn't request CQ notification\n"); + return 1; + } + } + + { + int ne, qp_ind; + + do { + ne = ibv_poll_cq(ctx->cq, num_wc, wc); + if (ne < 0) { + fprintf(stderr, "poll CQ failed %d\n", ne); + return 1; + } + } while (!use_event && ne < 1); + + for (i = 0; i < ne; ++i) { + if (wc[i].status != IBV_WC_SUCCESS) { + fprintf(stderr, "Failed status %s (%d) for wr_id %d\n", + ibv_wc_status_str(wc[i].status), + wc[i].status, (int) wc[i].wr_id); + return 1; + } + + qp_ind = find_qp(wc[i].qp_num, ctx, num_qp); + if (qp_ind < 0) { + fprintf(stderr, "Couldn't find QPN %06x\n", + wc[i].qp_num); + return 1; + } + + switch ((int) wc[i].wr_id) { + case PINGPONG_SEND_WRID: + ++scnt; + break; + + case PINGPONG_RECV_WRID: + if (--routs <= num_qp) { + routs += pp_post_recv(ctx, ctx->rx_depth - routs); + if (routs < ctx->rx_depth) { + fprintf(stderr, + "Couldn't post receive (%d)\n", + routs); + return 1; + } + } + + ++rcnt; + break; + + default: + fprintf(stderr, "Completion for unknown wr_id %d\n", + (int) wc[i].wr_id); + return 1; + } + + ctx->pending[qp_ind] &= ~(int) wc[i].wr_id; + if (scnt < iters && !ctx->pending[qp_ind]) { + if (pp_post_send(ctx, qp_ind)) { + fprintf(stderr, "Couldn't post send\n"); + return 1; + } + ctx->pending[qp_ind] = PINGPONG_RECV_WRID | + PINGPONG_SEND_WRID; + } + + } + } + } + + if (gettimeofday(&end, NULL)) { + perror("gettimeofday"); + return 1; + } + + { + float usec = (end.tv_sec - start.tv_sec) * 1000000 + + (end.tv_usec - start.tv_usec); + long long bytes = (long long) size * iters * 2; + + printf("%lld bytes in %.2f seconds = %.2f Mbit/sec\n", + bytes, usec / 1000000., bytes * 8. / usec); + printf("%d iters in %.2f seconds = %.2f usec/iter\n", + iters, usec / 1000000., usec / iters); + } + + ibv_ack_cq_events(ctx->cq, num_cq_events); + + if (pp_close_ctx(ctx, num_qp)) + return 1; + + ibv_free_device_list(dev_list); + free(rem_dest); + + return 0; +} diff --git a/branches/WOF2-3/ulp/libibverbs/examples/srq_pingpong/srq_pingpong.rc b/branches/WOF2-3/ulp/libibverbs/examples/srq_pingpong/srq_pingpong.rc new file mode 100644 index 00000000..43ea8951 --- /dev/null +++ b/branches/WOF2-3/ulp/libibverbs/examples/srq_pingpong/srq_pingpong.rc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef DBG +#define VER_FILEDESCRIPTION_STR "winverbs - Shared Recv Queue pingpong test (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "winverbs - Shared Recv Queue pingpong test" +#endif + +#define VER_INTERNALNAME_STR "ibv_send_bw.exe" +#define VER_ORIGINALFILENAME_STR "ibv_send_bw.exe" + +#include diff --git a/branches/WOF2-3/ulp/libibverbs/examples/uc_pingpong/SOURCES b/branches/WOF2-3/ulp/libibverbs/examples/uc_pingpong/SOURCES new file mode 100644 index 00000000..463261f1 --- /dev/null +++ b/branches/WOF2-3/ulp/libibverbs/examples/uc_pingpong/SOURCES @@ -0,0 +1,31 @@ +TARGETNAME = ibv_uc_pingpong +TARGETPATH = ..\..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = PROGRAM + +UMTYPE = console +UMENTRY = main + +USE_MSVCRT = 1 +USE_STL = 1 +USE_NATIVE_EH = 1 +USE_IOSTREAM = 1 + +SOURCES = \ + uc_pingpong.rc \ + uc_pingpong.c + +INCLUDES = ..;..\..\include;..\..\..\..\inc;..\..\..\..\inc\user;\ + ..\..\..\..\inc\user\linux + +TARGETLIBS = \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\advapi32.lib \ + $(SDK_LIB_PATH)\user32.lib \ + $(SDK_LIB_PATH)\ole32.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\libibverbs.lib +!else + $(TARGETPATH)\*\libibverbsd.lib +!endif + diff --git a/branches/WOF2-3/ulp/libibverbs/examples/uc_pingpong/makefile b/branches/WOF2-3/ulp/libibverbs/examples/uc_pingpong/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-3/ulp/libibverbs/examples/uc_pingpong/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\..\inc\openib.def diff --git a/branches/WOF2-3/ulp/libibverbs/examples/uc_pingpong/uc_pingpong.c b/branches/WOF2-3/ulp/libibverbs/examples/uc_pingpong/uc_pingpong.c new file mode 100644 index 00000000..d17559c1 --- /dev/null +++ b/branches/WOF2-3/ulp/libibverbs/examples/uc_pingpong/uc_pingpong.c @@ -0,0 +1,739 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include + +#include "..\..\..\..\etc\user\getopt.c" +#include "..\pingpong.c" +#include + +enum { + PINGPONG_RECV_WRID = 1, + PINGPONG_SEND_WRID = 2, +}; + +struct pingpong_context { + struct ibv_context *context; + struct ibv_comp_channel *channel; + struct ibv_pd *pd; + struct ibv_mr *mr; + struct ibv_cq *cq; + struct ibv_qp *qp; + void *buf; + int size; + int rx_depth; + int pending; +}; + +struct pingpong_dest { + int lid; + int qpn; + int psn; +}; + +static int pp_connect_ctx(struct pingpong_context *ctx, int port, int my_psn, + enum ibv_mtu mtu, int sl, + struct pingpong_dest *dest) +{ + struct ibv_qp_attr attr; + + memset(&attr, 0, sizeof attr); + attr.qp_state = IBV_QPS_RTR; + attr.path_mtu = mtu; + attr.dest_qp_num = dest->qpn; + attr.rq_psn = dest->psn; + attr.ah_attr.is_global = 0; + attr.ah_attr.dlid = (uint16_t) dest->lid; + attr.ah_attr.sl = (uint8_t) sl; + attr.ah_attr.src_path_bits = 0; + attr.ah_attr.port_num = (uint8_t) port; + + if (ibv_modify_qp(ctx->qp, &attr, + IBV_QP_STATE | + IBV_QP_AV | + IBV_QP_PATH_MTU | + IBV_QP_DEST_QPN | + IBV_QP_RQ_PSN)) { + fprintf(stderr, "Failed to modify QP to RTR\n"); + return 1; + } + + attr.qp_state = IBV_QPS_RTS; + attr.sq_psn = my_psn; + if (ibv_modify_qp(ctx->qp, &attr, + IBV_QP_STATE | IBV_QP_SQ_PSN)) { + fprintf(stderr, "Failed to modify QP to RTS\n"); + return 1; + } + + return 0; +} + +static struct pingpong_dest *pp_client_exch_dest(const char *servername, int port, + const struct pingpong_dest *my_dest) +{ + struct addrinfo *res, *t; + struct addrinfo hints; + char service[6]; + char msg[sizeof "0000:000000:000000"]; + int n; + SOCKET sockfd = INVALID_SOCKET; + struct pingpong_dest *rem_dest = NULL; + + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + sprintf(service, "%d\0", port); + + n = getaddrinfo(servername, service, &hints, &res); + + if (n != 0) { + fprintf(stderr, "%s for %s:%d\n", gai_strerror(n), servername, port); + return NULL; + } + + for (t = res; t; t = t->ai_next) { + sockfd = socket(t->ai_family, t->ai_socktype, t->ai_protocol); + if (sockfd != INVALID_SOCKET) { + if (!connect(sockfd, t->ai_addr, t->ai_addrlen)) + break; + closesocket(sockfd); + sockfd = INVALID_SOCKET; + } + } + + freeaddrinfo(res); + + if (sockfd == INVALID_SOCKET) { + fprintf(stderr, "Couldn't connect to %s:%d\n", servername, port); + return NULL; + } + + sprintf(msg, "%04x:%06x:%06x", my_dest->lid, my_dest->qpn, my_dest->psn); + if (send(sockfd, msg, sizeof msg, 0) != sizeof msg) { + fprintf(stderr, "Couldn't send local address\n"); + goto out; + } + + if (recv(sockfd, msg, sizeof msg, 0) != sizeof msg) { + perror("client read"); + fprintf(stderr, "Couldn't read remote address\n"); + goto out; + } + + send(sockfd, "done", sizeof "done", 0); + + rem_dest = malloc(sizeof *rem_dest); + if (!rem_dest) + goto out; + + sscanf(msg, "%x:%x:%x", &rem_dest->lid, &rem_dest->qpn, &rem_dest->psn); + +out: + closesocket(sockfd); + return rem_dest; +} + +static struct pingpong_dest *pp_server_exch_dest(struct pingpong_context *ctx, + int ib_port, enum ibv_mtu mtu, + int port, int sl, + const struct pingpong_dest *my_dest) +{ + struct addrinfo *res, *t; + struct addrinfo hints; + char service[6]; + char msg[sizeof "0000:000000:000000"]; + int n; + SOCKET sockfd = INVALID_SOCKET, connfd; + struct pingpong_dest *rem_dest = NULL; + + memset(&hints, 0, sizeof hints); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + sprintf(service, "%d\0", port); + + n = getaddrinfo(NULL, service, &hints, &res); + + if (n != 0) { + fprintf(stderr, "%s for port %d\n", gai_strerror(n), port); + return NULL; + } + + for (t = res; t; t = t->ai_next) { + sockfd = socket(t->ai_family, t->ai_socktype, t->ai_protocol); + if (sockfd != INVALID_SOCKET) { + n = 0; + setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &n, sizeof n); + n = 1; + setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *) &n, sizeof n); + + if (!bind(sockfd, t->ai_addr, t->ai_addrlen)) + break; + closesocket(sockfd); + sockfd = INVALID_SOCKET; + } + } + + freeaddrinfo(res); + + if (sockfd == INVALID_SOCKET) { + fprintf(stderr, "Couldn't listen to port %d\n", port); + return NULL; + } + + listen(sockfd, 1); + connfd = accept(sockfd, NULL, 0); + closesocket(sockfd); + if (connfd == INVALID_SOCKET) { + fprintf(stderr, "accept() failed\n"); + return NULL; + } + + n = recv(connfd, msg, sizeof msg, 0); + if (n != sizeof msg) { + perror("server read"); + fprintf(stderr, "%d/%d: Couldn't read remote address\n", n, (int) sizeof msg); + goto out; + } + + rem_dest = malloc(sizeof *rem_dest); + if (!rem_dest) + goto out; + + sscanf(msg, "%x:%x:%x", &rem_dest->lid, &rem_dest->qpn, &rem_dest->psn); + + if (pp_connect_ctx(ctx, ib_port, my_dest->psn, mtu, sl, rem_dest)) { + fprintf(stderr, "Couldn't connect to remote QP\n"); + free(rem_dest); + rem_dest = NULL; + goto out; + } + + sprintf(msg, "%04x:%06x:%06x", my_dest->lid, my_dest->qpn, my_dest->psn); + if (send(connfd, msg, sizeof msg, 0) != sizeof msg) { + fprintf(stderr, "Couldn't send local address\n"); + free(rem_dest); + rem_dest = NULL; + goto out; + } + + recv(connfd, msg, sizeof msg, 0); + +out: + closesocket(connfd); + return rem_dest; +} + +static struct pingpong_context *pp_init_ctx(struct ibv_device *ib_dev, int size, + int rx_depth, int port, + int use_event) +{ + struct pingpong_context *ctx; + + ctx = malloc(sizeof *ctx); + if (!ctx) + return NULL; + + ctx->size = size; + ctx->rx_depth = rx_depth; + + ctx->buf = malloc(size); + if (!ctx->buf) { + fprintf(stderr, "Couldn't allocate work buf.\n"); + return NULL; + } + + memset(ctx->buf, 0, size); + + ctx->context = ibv_open_device(ib_dev); + if (!ctx->context) { + fprintf(stderr, "Couldn't get context for %s\n", + ibv_get_device_name(ib_dev)); + return NULL; + } + + if (use_event) { + ctx->channel = ibv_create_comp_channel(ctx->context); + if (!ctx->channel) { + fprintf(stderr, "Couldn't create completion channel\n"); + return NULL; + } + } else + ctx->channel = NULL; + + ctx->pd = ibv_alloc_pd(ctx->context); + if (!ctx->pd) { + fprintf(stderr, "Couldn't allocate PD\n"); + return NULL; + } + + ctx->mr = ibv_reg_mr(ctx->pd, ctx->buf, size, IBV_ACCESS_LOCAL_WRITE); + if (!ctx->mr) { + fprintf(stderr, "Couldn't register MR\n"); + return NULL; + } + + ctx->cq = ibv_create_cq(ctx->context, rx_depth + 1, NULL, + ctx->channel, 0); + if (!ctx->cq) { + fprintf(stderr, "Couldn't create CQ\n"); + return NULL; + } + + { + struct ibv_qp_init_attr attr; + + memset(&attr, 0, sizeof attr); + attr.send_cq = ctx->cq; + attr.recv_cq = ctx->cq; + attr.cap.max_send_wr = 1; + attr.cap.max_recv_wr = rx_depth; + attr.cap.max_send_sge = 1; + attr.cap.max_recv_sge = 1; + attr.qp_type = IBV_QPT_UC; + + ctx->qp = ibv_create_qp(ctx->pd, &attr); + if (!ctx->qp) { + fprintf(stderr, "Couldn't create QP\n"); + return NULL; + } + } + + { + struct ibv_qp_attr attr; + + memset(&attr, 0, sizeof attr); + attr.qp_state = IBV_QPS_INIT; + attr.pkey_index = 0; + attr.port_num = (uint8_t) port; + attr.qp_access_flags = 0; + + if (ibv_modify_qp(ctx->qp, &attr, + IBV_QP_STATE | + IBV_QP_PKEY_INDEX | + IBV_QP_PORT | + IBV_QP_ACCESS_FLAGS)) { + fprintf(stderr, "Failed to modify QP to INIT\n"); + return NULL; + } + } + + return ctx; +} + +int pp_close_ctx(struct pingpong_context *ctx) +{ + if (ibv_destroy_qp(ctx->qp)) { + fprintf(stderr, "Couldn't destroy QP\n"); + return 1; + } + + if (ibv_destroy_cq(ctx->cq)) { + fprintf(stderr, "Couldn't destroy CQ\n"); + return 1; + } + + if (ibv_dereg_mr(ctx->mr)) { + fprintf(stderr, "Couldn't deregister MR\n"); + return 1; + } + + if (ibv_dealloc_pd(ctx->pd)) { + fprintf(stderr, "Couldn't deallocate PD\n"); + return 1; + } + + if (ctx->channel) { + if (ibv_destroy_comp_channel(ctx->channel)) { + fprintf(stderr, "Couldn't destroy completion channel\n"); + return 1; + } + } + + if (ibv_close_device(ctx->context)) { + fprintf(stderr, "Couldn't release context\n"); + return 1; + } + + free(ctx->buf); + free(ctx); + + return 0; +} + +static int pp_post_recv(struct pingpong_context *ctx, int n) +{ + struct ibv_sge list; + struct ibv_recv_wr wr; + struct ibv_recv_wr *bad_wr; + int i; + + list.addr = (uintptr_t) ctx->buf; + list.length = ctx->size; + list.lkey = ctx->mr->lkey; + wr.next = NULL; + wr.wr_id = PINGPONG_RECV_WRID; + wr.sg_list = &list; + wr.num_sge = 1; + + for (i = 0; i < n; ++i) + if (ibv_post_recv(ctx->qp, &wr, &bad_wr)) + break; + + return i; +} + +static int pp_post_send(struct pingpong_context *ctx) +{ + struct ibv_sge list; + struct ibv_send_wr wr; + struct ibv_send_wr *bad_wr; + + list.addr = (uintptr_t) ctx->buf; + list.length = ctx->size; + list.lkey = ctx->mr->lkey; + wr.next = NULL; + wr.wr_id = PINGPONG_SEND_WRID; + wr.sg_list = &list; + wr.num_sge = 1; + wr.opcode = IBV_WR_SEND; + wr.send_flags = IBV_SEND_SIGNALED; + + return ibv_post_send(ctx->qp, &wr, &bad_wr); +} + +static void usage(const char *argv0) +{ + printf("Usage:\n"); + printf(" %s start a server and wait for connection\n", argv0); + printf(" %s -h connect to server at \n", argv0); + printf("\n"); + printf("Options:\n"); + printf(" -p listen on/connect to port (default 18515)\n"); + printf(" -d use IB device (default first device found)\n"); + printf(" -i use port of IB device (default 1)\n"); + printf(" -s size of message to exchange (default 4096)\n"); + printf(" -m path MTU (default 1024)\n"); + printf(" -r number of receives to post at a time (default 500)\n"); + printf(" -n number of exchanges (default 1000)\n"); + printf(" -l service level value\n"); + printf(" -e sleep on CQ events (default poll)\n"); +} + +int __cdecl main(int argc, char *argv[]) +{ + struct ibv_device **dev_list; + struct ibv_device *ib_dev; + struct pingpong_context *ctx; + struct pingpong_dest my_dest; + struct pingpong_dest *rem_dest; + LARGE_INTEGER start, end, freq; + char *ib_devname = NULL; + char *servername = NULL; + int port = 18515; + int ib_port = 1; + int size = 4096; + enum ibv_mtu mtu = IBV_MTU_1024; + int rx_depth = 500; + int iters = 1000; + int use_event = 0; + int routs; + int rcnt, scnt; + int num_cq_events = 0; + int sl = 0; + WORD version; + WSADATA data; + int err; + + srand((unsigned int) time(NULL)); + version = MAKEWORD(2, 2); + err = WSAStartup(version, &data); + if (err) + return -1; + + while (1) { + int c; + + c = getopt(argc, argv, "h:p:d:i:s:m:r:n:l:e"); + if (c == -1) + break; + + switch (c) { + case 'p': + port = strtol(optarg, NULL, 0); + if (port < 0 || port > 65535) { + usage(argv[0]); + return 1; + } + break; + + case 'd': + ib_devname = _strdup(optarg); + break; + + case 'i': + ib_port = strtol(optarg, NULL, 0); + if (ib_port < 0) { + usage(argv[0]); + return 1; + } + break; + + case 's': + size = strtol(optarg, NULL, 0); + break; + + case 'm': + mtu = pp_mtu_to_enum(strtol(optarg, NULL, 0)); + if (mtu < 0) { + usage(argv[0]); + return 1; + } + + case 'r': + rx_depth = strtol(optarg, NULL, 0); + break; + + case 'n': + iters = strtol(optarg, NULL, 0); + break; + + case 'l': + sl = strtol(optarg, NULL, 0); + break; + + case 'e': + ++use_event; + break; + + case 'h': + servername = _strdup(optarg); + break; + + default: + usage(argv[0]); + return 1; + } + } + + dev_list = ibv_get_device_list(NULL); + if (!dev_list) { + fprintf(stderr, "No IB devices found\n"); + return 1; + } + + if (!ib_devname) { + ib_dev = *dev_list; + if (!ib_dev) { + fprintf(stderr, "No IB devices found\n"); + return 1; + } + } else { + int i; + for (i = 0; dev_list[i]; ++i) + if (!strcmp(ibv_get_device_name(dev_list[i]), ib_devname)) + break; + ib_dev = dev_list[i]; + if (!ib_dev) { + fprintf(stderr, "IB device %s not found\n", ib_devname); + return 1; + } + } + + ctx = pp_init_ctx(ib_dev, size, rx_depth, ib_port, use_event); + if (!ctx) + return 1; + + routs = pp_post_recv(ctx, ctx->rx_depth); + if (routs < ctx->rx_depth) { + fprintf(stderr, "Couldn't post receive (%d)\n", routs); + return 1; + } + + if (use_event) + if (ibv_req_notify_cq(ctx->cq, 0)) { + fprintf(stderr, "Couldn't request CQ notification\n"); + return 1; + } + + my_dest.lid = pp_get_local_lid(ctx->context, ib_port); + my_dest.qpn = ctx->qp->qp_num; + my_dest.psn = rand() & 0xffffff; + if (!my_dest.lid) { + fprintf(stderr, "Couldn't get local LID\n"); + return 1; + } + + printf(" local address: LID 0x%04x, QPN 0x%06x, PSN 0x%06x\n", + my_dest.lid, my_dest.qpn, my_dest.psn); + + if (servername) + rem_dest = pp_client_exch_dest(servername, port, &my_dest); + else + rem_dest = pp_server_exch_dest(ctx, ib_port, mtu, port, sl, &my_dest); + + if (!rem_dest) + return 1; + + printf(" remote address: LID 0x%04x, QPN 0x%06x, PSN 0x%06x\n", + rem_dest->lid, rem_dest->qpn, rem_dest->psn); + + if (servername) + if (pp_connect_ctx(ctx, ib_port, my_dest.psn, mtu, sl, rem_dest)) + return 1; + + ctx->pending = PINGPONG_RECV_WRID; + + if (servername) { + if (pp_post_send(ctx)) { + fprintf(stderr, "Couldn't post send\n"); + return 1; + } + ctx->pending |= PINGPONG_SEND_WRID; + } + + if (!QueryPerformanceCounter(&start)) { + perror("QueryPerformanceCounter"); + return 1; + } + + rcnt = scnt = 0; + while (rcnt < iters || scnt < iters) { + if (use_event) { + struct ibv_cq *ev_cq; + void *ev_ctx; + + if (ibv_get_cq_event(ctx->channel, &ev_cq, &ev_ctx)) { + fprintf(stderr, "Failed to get cq_event\n"); + return 1; + } + + ++num_cq_events; + + if (ev_cq != ctx->cq) { + fprintf(stderr, "CQ event for unknown CQ %p\n", ev_cq); + return 1; + } + + if (ibv_req_notify_cq(ctx->cq, 0)) { + fprintf(stderr, "Couldn't request CQ notification\n"); + return 1; + } + } + + { + struct ibv_wc wc[2]; + int ne, i; + + do { + ne = ibv_poll_cq(ctx->cq, 2, wc); + if (ne < 0) { + fprintf(stderr, "poll CQ failed %d\n", ne); + return 1; + } + } while (!use_event && ne < 1); + + for (i = 0; i < ne; ++i) { + if (wc[i].status != IBV_WC_SUCCESS) { + fprintf(stderr, "Failed status %s (%d) for wr_id %d\n", + ibv_wc_status_str(wc[i].status), + wc[i].status, (int) wc[i].wr_id); + return 1; + } + + switch ((int) wc[i].wr_id) { + case PINGPONG_SEND_WRID: + ++scnt; + break; + + case PINGPONG_RECV_WRID: + if (--routs <= 1) { + routs += pp_post_recv(ctx, ctx->rx_depth - routs); + if (routs < ctx->rx_depth) { + fprintf(stderr, + "Couldn't post receive (%d)\n", + routs); + return 1; + } + } + + ++rcnt; + break; + + default: + fprintf(stderr, "Completion for unknown wr_id %d\n", + (int) wc[i].wr_id); + return 1; + } + + ctx->pending &= ~(int) wc[i].wr_id; + if (scnt < iters && !ctx->pending) { + if (pp_post_send(ctx)) { + fprintf(stderr, "Couldn't post send\n"); + return 1; + } + ctx->pending = PINGPONG_RECV_WRID | + PINGPONG_SEND_WRID; + } + } + } + } + + if (!QueryPerformanceCounter(&end) || + !QueryPerformanceFrequency(&freq)) { + perror("QueryPerformanceCounter/Frequency"); + return 1; + } + + { + double sec = (double) (end.QuadPart - start.QuadPart) / (double) freq.QuadPart; + long long bytes = (long long) size * iters * 2; + + printf("%I64d bytes in %.2f seconds = %.2f Mbit/sec\n", + bytes, sec, bytes * 8. / 1000000. / sec); + printf("%d iters in %.2f seconds = %.2f usec/iter\n", + iters, sec, sec * 1000000. / iters); + } + + ibv_ack_cq_events(ctx->cq, num_cq_events); + + if (pp_close_ctx(ctx)) + return 1; + + ibv_free_device_list(dev_list); + free(rem_dest); + + return 0; +} diff --git a/branches/WOF2-3/ulp/libibverbs/examples/uc_pingpong/uc_pingpong.rc b/branches/WOF2-3/ulp/libibverbs/examples/uc_pingpong/uc_pingpong.rc new file mode 100644 index 00000000..12dbc6de --- /dev/null +++ b/branches/WOF2-3/ulp/libibverbs/examples/uc_pingpong/uc_pingpong.rc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef DBG +#define VER_FILEDESCRIPTION_STR "winverbs - UC pingpong test (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "winverbs - UC pingpong test" +#endif + +#define VER_INTERNALNAME_STR "ibv_send_bw.exe" +#define VER_ORIGINALFILENAME_STR "ibv_send_bw.exe" + +#include diff --git a/branches/WOF2-3/ulp/libibverbs/examples/ud_pingpong/SOURCES b/branches/WOF2-3/ulp/libibverbs/examples/ud_pingpong/SOURCES new file mode 100644 index 00000000..b5277948 --- /dev/null +++ b/branches/WOF2-3/ulp/libibverbs/examples/ud_pingpong/SOURCES @@ -0,0 +1,31 @@ +TARGETNAME = ibv_ud_pingpong +TARGETPATH = ..\..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = PROGRAM + +UMTYPE = console +UMENTRY = main + +USE_MSVCRT = 1 +USE_STL = 1 +USE_NATIVE_EH = 1 +USE_IOSTREAM = 1 + +SOURCES = \ + ud_pingpong.rc \ + ud_pingpong.c + +INCLUDES = ..;..\..\include;..\..\..\..\inc;..\..\..\..\inc\user;\ + ..\..\..\..\inc\user\linux + +TARGETLIBS = \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\advapi32.lib \ + $(SDK_LIB_PATH)\user32.lib \ + $(SDK_LIB_PATH)\ole32.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\libibverbs.lib +!else + $(TARGETPATH)\*\libibverbsd.lib +!endif + diff --git a/branches/WOF2-3/ulp/libibverbs/examples/ud_pingpong/makefile b/branches/WOF2-3/ulp/libibverbs/examples/ud_pingpong/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-3/ulp/libibverbs/examples/ud_pingpong/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\..\inc\openib.def diff --git a/branches/WOF2-3/ulp/libibverbs/examples/ud_pingpong/ud_pingpong.c b/branches/WOF2-3/ulp/libibverbs/examples/ud_pingpong/ud_pingpong.c new file mode 100644 index 00000000..f3e73f7e --- /dev/null +++ b/branches/WOF2-3/ulp/libibverbs/examples/ud_pingpong/ud_pingpong.c @@ -0,0 +1,738 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include + +#include "..\..\..\..\etc\user\getopt.c" +#include "..\pingpong.c" +#include + +enum { + PINGPONG_RECV_WRID = 1, + PINGPONG_SEND_WRID = 2, +}; + +struct pingpong_context { + struct ibv_context *context; + struct ibv_comp_channel *channel; + struct ibv_pd *pd; + struct ibv_mr *mr; + struct ibv_cq *cq; + struct ibv_qp *qp; + struct ibv_ah *ah; + void *buf; + int size; + int rx_depth; + int pending; +}; + +struct pingpong_dest { + int lid; + int qpn; + int psn; +}; + +static int pp_connect_ctx(struct pingpong_context *ctx, int port, int my_psn, + int sl, struct pingpong_dest *dest) +{ + struct ibv_ah_attr ah_attr; + struct ibv_qp_attr attr; + + memset(&ah_attr, 0, sizeof ah_attr); + ah_attr.is_global = 0; + ah_attr.dlid = (uint16_t) dest->lid; + ah_attr.sl = (uint8_t) sl; + ah_attr.src_path_bits = 0; + ah_attr.port_num = (uint8_t) port; + + attr.qp_state = IBV_QPS_RTR; + + if (ibv_modify_qp(ctx->qp, &attr, IBV_QP_STATE)) { + fprintf(stderr, "Failed to modify QP to RTR\n"); + return 1; + } + + attr.qp_state = IBV_QPS_RTS; + attr.sq_psn = my_psn; + + if (ibv_modify_qp(ctx->qp, &attr, + IBV_QP_STATE | IBV_QP_SQ_PSN)) { + fprintf(stderr, "Failed to modify QP to RTS\n"); + return 1; + } + + ctx->ah = ibv_create_ah(ctx->pd, &ah_attr); + if (!ctx->ah) { + fprintf(stderr, "Failed to create AH\n"); + return 1; + } + + return 0; +} + +static struct pingpong_dest *pp_client_exch_dest(const char *servername, int port, + const struct pingpong_dest *my_dest) +{ + struct addrinfo *res, *t; + struct addrinfo hints; + char service[6]; + char msg[sizeof "0000:000000:000000"]; + int n; + SOCKET sockfd = INVALID_SOCKET; + struct pingpong_dest *rem_dest = NULL; + + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + sprintf(service, "%d\0", port); + + n = getaddrinfo(servername, service, &hints, &res); + + if (n != 0) { + fprintf(stderr, "%s for %s:%d\n", gai_strerror(n), servername, port); + return NULL; + } + + for (t = res; t; t = t->ai_next) { + sockfd = socket(t->ai_family, t->ai_socktype, t->ai_protocol); + if (sockfd != INVALID_SOCKET) { + if (!connect(sockfd, t->ai_addr, t->ai_addrlen)) + break; + closesocket(sockfd); + sockfd = INVALID_SOCKET; + } + } + + freeaddrinfo(res); + + if (sockfd == INVALID_SOCKET) { + fprintf(stderr, "Couldn't connect to %s:%d\n", servername, port); + return NULL; + } + + sprintf(msg, "%04x:%06x:%06x", my_dest->lid, my_dest->qpn, my_dest->psn); + if (send(sockfd, msg, sizeof msg, 0) != sizeof msg) { + fprintf(stderr, "Couldn't send local address\n"); + goto out; + } + + if (recv(sockfd, msg, sizeof msg, 0) != sizeof msg) { + perror("client recv"); + fprintf(stderr, "Couldn't recv remote address\n"); + goto out; + } + + send(sockfd, "done", sizeof "done", 0); + + rem_dest = malloc(sizeof *rem_dest); + if (!rem_dest) + goto out; + + sscanf(msg, "%x:%x:%x", &rem_dest->lid, &rem_dest->qpn, &rem_dest->psn); + +out: + closesocket(sockfd); + return rem_dest; +} + +static struct pingpong_dest *pp_server_exch_dest(struct pingpong_context *ctx, + int ib_port, int port, int sl, + const struct pingpong_dest *my_dest) +{ + struct addrinfo *res, *t; + struct addrinfo hints; + char service[6]; + char msg[sizeof "0000:000000:000000"]; + int n; + SOCKET sockfd = INVALID_SOCKET, connfd; + struct pingpong_dest *rem_dest = NULL; + + memset(&hints, 0, sizeof hints); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + sprintf(service, "%d\0", port); + + n = getaddrinfo(NULL, service, &hints, &res); + + if (n != 0) { + fprintf(stderr, "%s for port %d\n", gai_strerror(n), port); + return NULL; + } + + for (t = res; t; t = t->ai_next) { + sockfd = socket(t->ai_family, t->ai_socktype, t->ai_protocol); + if (sockfd != INVALID_SOCKET) { + n = 0; + setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &n, sizeof n); + n = 1; + setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *) &n, sizeof n); + + if (!bind(sockfd, t->ai_addr, t->ai_addrlen)) + break; + closesocket(sockfd); + sockfd = INVALID_SOCKET; + } + } + + freeaddrinfo(res); + + if (sockfd == INVALID_SOCKET) { + fprintf(stderr, "Couldn't listen to port %d\n", port); + return NULL; + } + + listen(sockfd, 1); + connfd = accept(sockfd, NULL, 0); + closesocket(sockfd); + if (connfd == INVALID_SOCKET) { + fprintf(stderr, "accept() failed\n"); + return NULL; + } + + n = recv(connfd, msg, sizeof msg, 0); + if (n != sizeof msg) { + perror("server recv"); + fprintf(stderr, "%d/%d: Couldn't recv remote address\n", n, (int) sizeof msg); + goto out; + } + + rem_dest = malloc(sizeof *rem_dest); + if (!rem_dest) + goto out; + + sscanf(msg, "%x:%x:%x", &rem_dest->lid, &rem_dest->qpn, &rem_dest->psn); + + if (pp_connect_ctx(ctx, ib_port, my_dest->psn, sl, rem_dest)) { + fprintf(stderr, "Couldn't connect to remote QP\n"); + free(rem_dest); + rem_dest = NULL; + goto out; + } + + sprintf(msg, "%04x:%06x:%06x", my_dest->lid, my_dest->qpn, my_dest->psn); + if (send(connfd, msg, sizeof msg, 0) != sizeof msg) { + fprintf(stderr, "Couldn't send local address\n"); + free(rem_dest); + rem_dest = NULL; + goto out; + } + + recv(connfd, msg, sizeof msg, 0); + +out: + closesocket(connfd); + return rem_dest; +} + +static struct pingpong_context *pp_init_ctx(struct ibv_device *ib_dev, int size, + int rx_depth, int port, + int use_event) +{ + struct pingpong_context *ctx; + + ctx = malloc(sizeof *ctx); + if (!ctx) + return NULL; + + ctx->size = size; + ctx->rx_depth = rx_depth; + + ctx->buf = malloc(size + 40); + if (!ctx->buf) { + fprintf(stderr, "Couldn't allocate work buf.\n"); + return NULL; + } + + memset(ctx->buf, 0, size + 40); + + ctx->context = ibv_open_device(ib_dev); + if (!ctx->context) { + fprintf(stderr, "Couldn't get context for %s\n", + ibv_get_device_name(ib_dev)); + return NULL; + } + + if (use_event) { + ctx->channel = ibv_create_comp_channel(ctx->context); + if (!ctx->channel) { + fprintf(stderr, "Couldn't create completion channel\n"); + return NULL; + } + } else + ctx->channel = NULL; + + ctx->pd = ibv_alloc_pd(ctx->context); + if (!ctx->pd) { + fprintf(stderr, "Couldn't allocate PD\n"); + return NULL; + } + + ctx->mr = ibv_reg_mr(ctx->pd, ctx->buf, size + 40, IBV_ACCESS_LOCAL_WRITE); + if (!ctx->mr) { + fprintf(stderr, "Couldn't register MR\n"); + return NULL; + } + + ctx->cq = ibv_create_cq(ctx->context, rx_depth + 1, NULL, + ctx->channel, 0); + if (!ctx->cq) { + fprintf(stderr, "Couldn't create CQ\n"); + return NULL; + } + + { + struct ibv_qp_init_attr attr; + + memset(&attr, 0, sizeof attr); + attr.send_cq = ctx->cq; + attr.recv_cq = ctx->cq; + attr.cap.max_send_wr = 1; + attr.cap.max_recv_wr = rx_depth; + attr.cap.max_send_sge = 1; + attr.cap.max_recv_sge = 1; + attr.qp_type = IBV_QPT_UD, + + ctx->qp = ibv_create_qp(ctx->pd, &attr); + if (!ctx->qp) { + fprintf(stderr, "Couldn't create QP\n"); + return NULL; + } + } + + { + struct ibv_qp_attr attr; + + memset(&attr, 0, sizeof attr); + attr.qp_state = IBV_QPS_INIT; + attr.pkey_index = 0; + attr.port_num = (uint8_t) port; + attr.qkey = 0x11111111; + + if (ibv_modify_qp(ctx->qp, &attr, + IBV_QP_STATE | + IBV_QP_PKEY_INDEX | + IBV_QP_PORT | + IBV_QP_QKEY)) { + fprintf(stderr, "Failed to modify QP to INIT\n"); + return NULL; + } + } + + return ctx; +} + +int pp_close_ctx(struct pingpong_context *ctx) +{ + if (ibv_destroy_qp(ctx->qp)) { + fprintf(stderr, "Couldn't destroy QP\n"); + return 1; + } + + if (ibv_destroy_cq(ctx->cq)) { + fprintf(stderr, "Couldn't destroy CQ\n"); + return 1; + } + + if (ibv_dereg_mr(ctx->mr)) { + fprintf(stderr, "Couldn't deregister MR\n"); + return 1; + } + + if (ibv_destroy_ah(ctx->ah)) { + fprintf(stderr, "Couldn't destroy AH\n"); + return 1; + } + + if (ibv_dealloc_pd(ctx->pd)) { + fprintf(stderr, "Couldn't deallocate PD\n"); + return 1; + } + + if (ctx->channel) { + if (ibv_destroy_comp_channel(ctx->channel)) { + fprintf(stderr, "Couldn't destroy completion channel\n"); + return 1; + } + } + + if (ibv_close_device(ctx->context)) { + fprintf(stderr, "Couldn't release context\n"); + return 1; + } + + free(ctx->buf); + free(ctx); + + return 0; +} + +static int pp_post_recv(struct pingpong_context *ctx, int n) +{ + struct ibv_sge list; + struct ibv_recv_wr wr; + struct ibv_recv_wr *bad_wr; + int i; + + list.addr = (uintptr_t) ctx->buf; + list.length = ctx->size + 40; + list.lkey = ctx->mr->lkey; + wr.next = NULL; + wr.wr_id = PINGPONG_RECV_WRID; + wr.sg_list = &list; + wr.num_sge = 1; + + for (i = 0; i < n; ++i) + if (ibv_post_recv(ctx->qp, &wr, &bad_wr)) + break; + + return i; +} + +static int pp_post_send(struct pingpong_context *ctx, uint32_t qpn) +{ + struct ibv_sge list; + struct ibv_send_wr wr; + struct ibv_send_wr *bad_wr; + + list.addr = (uintptr_t) ctx->buf + 40; + list.length = ctx->size; + list.lkey = ctx->mr->lkey; + wr.next = NULL; + wr.wr_id = PINGPONG_SEND_WRID; + wr.sg_list = &list; + wr.num_sge = 1; + wr.opcode = IBV_WR_SEND; + wr.send_flags = IBV_SEND_SIGNALED; + wr.wr.ud.ah = ctx->ah; + wr.wr.ud.remote_qpn = qpn; + wr.wr.ud.remote_qkey = 0x11111111; + + return ibv_post_send(ctx->qp, &wr, &bad_wr); +} + +static void usage(const char *argv0) +{ + printf("Usage:\n"); + printf(" %s start a server and wait for connection\n", argv0); + printf(" %s -h connect to server at \n", argv0); + printf("\n"); + printf("Options:\n"); + printf(" -p listen on/connect to port (default 18515)\n"); + printf(" -d use IB device (default first device found)\n"); + printf(" -i use port of IB device (default 1)\n"); + printf(" -s size of message to exchange (default 2048)\n"); + printf(" -r number of receives to post at a time (default 500)\n"); + printf(" -n number of exchanges (default 1000)\n"); + printf(" -e sleep on CQ events (default poll)\n"); +} + +int __cdecl main(int argc, char *argv[]) +{ + struct ibv_device **dev_list; + struct ibv_device *ib_dev; + struct pingpong_context *ctx; + struct pingpong_dest my_dest; + struct pingpong_dest *rem_dest; + LARGE_INTEGER start, end, freq; + char *ib_devname = NULL; + char *servername = NULL; + int port = 18515; + int ib_port = 1; + int size = 2048; + int rx_depth = 500; + int iters = 1000; + int use_event = 0; + int routs; + int rcnt, scnt; + int num_cq_events = 0; + int sl = 0; + WORD version; + WSADATA data; + int err; + + srand((unsigned int) time(NULL)); + version = MAKEWORD(2, 2); + err = WSAStartup(version, &data); + if (err) + return -1; + + while (1) { + int c; + + c = getopt(argc, argv, "h:p:d:i:s:r:n:l:e"); + if (c == -1) + break; + + switch (c) { + case 'p': + port = strtol(optarg, NULL, 0); + if (port < 0 || port > 65535) { + usage(argv[0]); + return 1; + } + break; + + case 'd': + ib_devname = _strdup(optarg); + break; + + case 'i': + ib_port = strtol(optarg, NULL, 0); + if (ib_port < 0) { + usage(argv[0]); + return 1; + } + break; + + case 's': + size = strtol(optarg, NULL, 0); + break; + + case 'r': + rx_depth = strtol(optarg, NULL, 0); + break; + + case 'n': + iters = strtol(optarg, NULL, 0); + break; + + case 'l': + sl = strtol(optarg, NULL, 0); + break; + + case 'e': + ++use_event; + break; + + case 'h': + servername = _strdup(optarg); + break; + + default: + usage(argv[0]); + return 1; + } + } + + dev_list = ibv_get_device_list(NULL); + if (!dev_list) { + fprintf(stderr, "No IB devices found\n"); + return 1; + } + + if (!ib_devname) { + ib_dev = *dev_list; + if (!ib_dev) { + fprintf(stderr, "No IB devices found\n"); + return 1; + } + } else { + int i; + for (i = 0; dev_list[i]; ++i) + if (!strcmp(ibv_get_device_name(dev_list[i]), ib_devname)) + break; + ib_dev = dev_list[i]; + if (!ib_dev) { + fprintf(stderr, "IB device %s not found\n", ib_devname); + return 1; + } + } + + ctx = pp_init_ctx(ib_dev, size, rx_depth, ib_port, use_event); + if (!ctx) + return 1; + + routs = pp_post_recv(ctx, ctx->rx_depth); + if (routs < ctx->rx_depth) { + fprintf(stderr, "Couldn't post receive (%d)\n", routs); + return 1; + } + + if (use_event) + if (ibv_req_notify_cq(ctx->cq, 0)) { + fprintf(stderr, "Couldn't request CQ notification\n"); + return 1; + } + + my_dest.lid = pp_get_local_lid(ctx->context, ib_port); + my_dest.qpn = ctx->qp->qp_num; + my_dest.psn = rand() & 0xffffff; + if (!my_dest.lid) { + fprintf(stderr, "Couldn't get local LID\n"); + return 1; + } + + printf(" local address: LID 0x%04x, QPN 0x%06x, PSN 0x%06x\n", + my_dest.lid, my_dest.qpn, my_dest.psn); + + if (servername) + rem_dest = pp_client_exch_dest(servername, port, &my_dest); + else + rem_dest = pp_server_exch_dest(ctx, ib_port, port, sl, &my_dest); + + if (!rem_dest) + return 1; + + printf(" remote address: LID 0x%04x, QPN 0x%06x, PSN 0x%06x\n", + rem_dest->lid, rem_dest->qpn, rem_dest->psn); + + if (servername) + if (pp_connect_ctx(ctx, ib_port, my_dest.psn, sl, rem_dest)) + return 1; + + ctx->pending = PINGPONG_RECV_WRID; + + if (servername) { + if (pp_post_send(ctx, rem_dest->qpn)) { + fprintf(stderr, "Couldn't post send\n"); + return 1; + } + ctx->pending |= PINGPONG_SEND_WRID; + } + + if (!QueryPerformanceCounter(&start)) { + perror("QueryPerformanceCounter"); + return 1; + } + + rcnt = scnt = 0; + while (rcnt < iters || scnt < iters) { + if (use_event) { + struct ibv_cq *ev_cq; + void *ev_ctx; + + if (ibv_get_cq_event(ctx->channel, &ev_cq, &ev_ctx)) { + fprintf(stderr, "Failed to get cq_event\n"); + return 1; + } + + ++num_cq_events; + + if (ev_cq != ctx->cq) { + fprintf(stderr, "CQ event for unknown CQ %p\n", ev_cq); + return 1; + } + + if (ibv_req_notify_cq(ctx->cq, 0)) { + fprintf(stderr, "Couldn't request CQ notification\n"); + return 1; + } + } + + { + struct ibv_wc wc[2]; + int ne, i; + + do { + ne = ibv_poll_cq(ctx->cq, 2, wc); + if (ne < 0) { + fprintf(stderr, "poll CQ failed %d\n", ne); + return 1; + } + } while (!use_event && ne < 1); + + for (i = 0; i < ne; ++i) { + if (wc[i].status != IBV_WC_SUCCESS) { + fprintf(stderr, "Failed status %s (%d) for wr_id %d\n", + ibv_wc_status_str(wc[i].status), + wc[i].status, (int) wc[i].wr_id); + return 1; + } + + switch ((int) wc[i].wr_id) { + case PINGPONG_SEND_WRID: + ++scnt; + break; + + case PINGPONG_RECV_WRID: + if (--routs <= 1) { + routs += pp_post_recv(ctx, ctx->rx_depth - routs); + if (routs < ctx->rx_depth) { + fprintf(stderr, + "Couldn't post receive (%d)\n", + routs); + return 1; + } + } + + ++rcnt; + break; + + default: + fprintf(stderr, "Completion for unknown wr_id %d\n", + (int) wc[i].wr_id); + return 1; + } + + ctx->pending &= ~(int) wc[i].wr_id; + if (scnt < iters && !ctx->pending) { + if (pp_post_send(ctx, rem_dest->qpn)) { + fprintf(stderr, "Couldn't post send\n"); + return 1; + } + ctx->pending = PINGPONG_RECV_WRID | + PINGPONG_SEND_WRID; + } + } + } + } + + if (!QueryPerformanceCounter(&end) || + !QueryPerformanceFrequency(&freq)) { + perror("QueryPerformanceCounter/Frequency"); + return 1; + } + + { + double sec = (double) (end.QuadPart - start.QuadPart) / (double) freq.QuadPart; + long long bytes = (long long) size * iters * 2; + + printf("%I64d bytes in %.2f seconds = %.2f Mbit/sec\n", + bytes, sec, bytes * 8. / 1000000. / sec); + printf("%d iters in %.2f seconds = %.2f usec/iter\n", + iters, sec, sec * 1000000. / iters); + } + + ibv_ack_cq_events(ctx->cq, num_cq_events); + + if (pp_close_ctx(ctx)) + return 1; + + ibv_free_device_list(dev_list); + free(rem_dest); + + return 0; +} diff --git a/branches/WOF2-3/ulp/libibverbs/examples/ud_pingpong/ud_pingpong.rc b/branches/WOF2-3/ulp/libibverbs/examples/ud_pingpong/ud_pingpong.rc new file mode 100644 index 00000000..c5d0ecc7 --- /dev/null +++ b/branches/WOF2-3/ulp/libibverbs/examples/ud_pingpong/ud_pingpong.rc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef DBG +#define VER_FILEDESCRIPTION_STR "winverbs - Unreliable Datagram pingpong test (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "winverbs - Unreliable Datagram pingpong test" +#endif + +#define VER_INTERNALNAME_STR "ibv_send_bw.exe" +#define VER_ORIGINALFILENAME_STR "ibv_send_bw.exe" + +#include diff --git a/branches/WOF2-3/ulp/libibverbs/include/infiniband/sa.h b/branches/WOF2-3/ulp/libibverbs/include/infiniband/sa.h new file mode 100644 index 00000000..0f427f39 --- /dev/null +++ b/branches/WOF2-3/ulp/libibverbs/include/infiniband/sa.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2004 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2010 Intel. All rights reserved. + * + * This software is available to you under the OpenFabrics.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef INFINIBAND_SA_H +#define INFINIBAND_SA_H + +#include + +struct ibv_sa_path_rec { + /* reserved */ + /* reserved */ + union ibv_gid dgid; + union ibv_gid sgid; + uint16_t dlid; + uint16_t slid; + int raw_traffic; + /* reserved */ + uint32_t flow_label; + uint8_t hop_limit; + uint8_t traffic_class; + int reversible; + uint8_t numb_path; + uint16_t pkey; + /* reserved */ + uint8_t sl; + uint8_t mtu_selector; + uint8_t mtu; + uint8_t rate_selector; + uint8_t rate; + uint8_t packet_life_time_selector; + uint8_t packet_life_time; + uint8_t preference; +}; + +#define IBV_PATH_RECORD_REVERSIBLE 0x80 + +struct ibv_path_record { + uint64_t service_id; + union ibv_gid dgid; + union ibv_gid sgid; + uint16_t dlid; + uint16_t slid; + uint32_t flowlabel_hoplimit; /* resv-31:28 flow label-27:8 hop limit-7:0*/ + uint8_t tclass; + uint8_t reversible_numpath; /* reversible-7:7 num path-6:0 */ + uint16_t pkey; + uint16_t qosclass_sl; /* qos class-15:4 sl-3:0 */ + uint8_t mtu; /* mtu selector-7:6 mtu-5:0 */ + uint8_t rate; /* rate selector-7:6 rate-5:0 */ + uint8_t packetlifetime; /* lifetime selector-7:6 lifetime-5:0 */ + uint8_t preference; + uint8_t reserved[6]; +}; + +#define IBV_PATH_FLAG_GMP (1<<0) +#define IBV_PATH_FLAG_PRIMARY (1<<1) +#define IBV_PATH_FLAG_ALTERNATE (1<<2) +#define IBV_PATH_FLAG_OUTBOUND (1<<3) +#define IBV_PATH_FLAG_INBOUND (1<<4) +#define IBV_PATH_FLAG_INBOUND_REVERSE (1<<5) +#define IBV_PATH_FLAG_BIDIRECTIONAL (IBV_PATH_FLAG_OUTBOUND | \ + IBV_PATH_FLAG_INBOUND_REVERSE) + +struct ibv_path_data { + uint32_t flags; + uint32_t reserved; + struct ibv_path_record path; +}; + +#endif /* INFINIBAND_SA_H */ diff --git a/branches/WOF2-3/ulp/libibverbs/include/infiniband/verbs.h b/branches/WOF2-3/ulp/libibverbs/include/infiniband/verbs.h new file mode 100644 index 00000000..f1a6a7dc --- /dev/null +++ b/branches/WOF2-3/ulp/libibverbs/include/infiniband/verbs.h @@ -0,0 +1,1133 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2004, 2008 Intel Corporation. All rights reserved. + * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc. All rights reserved. + * Copyright (c) 2005 PathScale, Inc. All rights reserved. + * + * This software is available to you under the OpenFabrics.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#ifndef INFINIBAND_VERBS_H +#define INFINIBAND_VERBS_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Interfaces based on libibverbs 1.1.4. + */ + +typedef unsigned __int8 uint8_t; +typedef unsigned __int16 uint16_t; +typedef unsigned __int32 uint32_t; +typedef unsigned __int64 uint64_t; + +union ibv_gid +{ + uint8_t raw[16]; + struct + { + uint64_t subnet_prefix; + uint64_t interface_id; + + } global; +}; + +enum ibv_node_type +{ + IBV_NODE_UNKNOWN = -1, + IBV_NODE_CA = 1, + IBV_NODE_SWITCH, + IBV_NODE_ROUTER, + IBV_NODE_RNIC +}; + +enum ibv_transport_type +{ + IBV_TRANSPORT_UNKNOWN = WvDeviceUnknown, + IBV_TRANSPORT_IB = WvDeviceInfiniband, + IBV_TRANSPORT_IWARP = WvDeviceIwarp +}; + +enum ibv_device_cap_flags +{ + IBV_DEVICE_RESIZE_MAX_WR = WV_DEVICE_RESIZE_MAX_WR, + IBV_DEVICE_BAD_PKEY_CNTR = WV_DEVICE_BAD_PKEY_COUNTER, + IBV_DEVICE_BAD_QKEY_CNTR = WV_DEVICE_BAD_QKEY_COUNTER, + IBV_DEVICE_RAW_MULTI = 0, + IBV_DEVICE_AUTO_PATH_MIG = WV_DEVICE_PATH_MIGRATION, + IBV_DEVICE_CHANGE_PHY_PORT = WV_DEVICE_CHANGE_PHYSICAL_PORT, + IBV_DEVICE_UD_AV_PORT_ENFORCE = WV_DEVICE_AH_PORT_CHECKING, + IBV_DEVICE_CURR_QP_STATE_MOD = WV_DEVICE_QP_STATE_MODIFIER, + IBV_DEVICE_SHUTDOWN_PORT = WV_DEVICE_SHUTDOWN_PORT, + IBV_DEVICE_INIT_TYPE = WV_DEVICE_INIT_TYPE, + IBV_DEVICE_PORT_ACTIVE_EVENT = WV_DEVICE_PORT_ACTIVE_EVENT, + IBV_DEVICE_SYS_IMAGE_GUID = WV_DEVICE_SYSTEM_IMAGE_GUID, + IBV_DEVICE_RC_RNR_NAK_GEN = WV_DEVICE_RC_RNR_NAK_GENERATION, + IBV_DEVICE_SRQ_RESIZE = WV_DEVICE_SRQ_RESIZE, + IBV_DEVICE_N_NOTIFY_CQ = WV_DEVICE_BATCH_NOTIFY_CQ +}; + +enum ibv_atomic_cap +{ + IBV_ATOMIC_NONE = WvAtomicNone, + IBV_ATOMIC_HCA = WvAtomicDevice, + IBV_ATOMIC_GLOB = WvAtomicNode +}; + +struct ibv_device_attr +{ + char fw_ver[64]; + uint64_t node_guid; + uint64_t sys_image_guid; + uint64_t max_mr_size; + uint64_t page_size_cap; + uint32_t vendor_id; + uint32_t vendor_part_id; + uint32_t hw_ver; + int max_qp; + int max_qp_wr; + int device_cap_flags; + int max_sge; + int max_sge_rd; + int max_cq; + int max_cqe; + int max_mr; + int max_pd; + int max_qp_rd_atom; + int max_ee_rd_atom; + int max_res_rd_atom; + int max_qp_init_rd_atom; + int max_ee_init_rd_atom; + enum ibv_atomic_cap atomic_cap; + int max_ee; + int max_rdd; + int max_mw; + int max_raw_ipv6_qp; + int max_raw_ethy_qp; + int max_mcast_grp; + int max_mcast_qp_attach; + int max_total_mcast_qp_attach; + int max_ah; + int max_fmr; + int max_map_per_fmr; + int max_srq; + int max_srq_wr; + int max_srq_sge; + uint16_t max_pkeys; + uint8_t local_ca_ack_delay; + uint8_t phys_port_cnt; +}; + +enum ibv_mtu +{ + IBV_MTU_256 = 1, + IBV_MTU_512 = 2, + IBV_MTU_1024 = 3, + IBV_MTU_2048 = 4, + IBV_MTU_4096 = 5 +}; + +enum ibv_port_state +{ + IBV_PORT_NOP = WvPortNop, + IBV_PORT_DOWN = WvPortDown, + IBV_PORT_INIT = WvPortInit, + IBV_PORT_ARMED = WvPortArmed, + IBV_PORT_ACTIVE = WvPortActive, + IBV_PORT_ACTIVE_DEFER = WvPortActiveDefer +}; + +struct ibv_port_attr +{ + enum ibv_port_state state; + enum ibv_mtu max_mtu; + enum ibv_mtu active_mtu; + int gid_tbl_len; + uint32_t port_cap_flags; + uint32_t max_msg_sz; + uint32_t bad_pkey_cntr; + uint32_t qkey_viol_cntr; + uint16_t pkey_tbl_len; + uint16_t lid; + uint16_t sm_lid; + uint8_t lmc; + uint8_t max_vl_num; + uint8_t sm_sl; + uint8_t subnet_timeout; + uint8_t init_type_reply; + uint8_t active_width; + uint8_t active_speed; + uint8_t phys_state; +}; + +// Only device/port level events are currently supported. +enum ibv_event_type +{ + IBV_EVENT_CQ_ERR, + IBV_EVENT_QP_FATAL, + IBV_EVENT_QP_REQ_ERR, + IBV_EVENT_QP_ACCESS_ERR, + IBV_EVENT_COMM_EST, + IBV_EVENT_SQ_DRAINED, + IBV_EVENT_PATH_MIG, + IBV_EVENT_PATH_MIG_ERR, + IBV_EVENT_DEVICE_FATAL, + IBV_EVENT_PORT_ACTIVE, + IBV_EVENT_PORT_ERR, + IBV_EVENT_LID_CHANGE, + IBV_EVENT_PKEY_CHANGE, + IBV_EVENT_SM_CHANGE, + IBV_EVENT_SRQ_ERR, + IBV_EVENT_SRQ_LIMIT_REACHED, + IBV_EVENT_QP_LAST_WQE_REACHED, + IBV_EVENT_CLIENT_REREGISTER +}; + +struct ibv_async_event +{ + union + { + struct ibv_cq *cq; + struct ibv_qp *qp; + struct ibv_srq *srq; + int port_num; + + } element; + enum ibv_event_type event_type; +}; + +enum ibv_wc_status +{ + IBV_WC_SUCCESS = WvWcSuccess, + IBV_WC_LOC_LEN_ERR = WvWcLocalLengthError, + IBV_WC_LOC_QP_OP_ERR = WvWcLocalOpError, + IBV_WC_LOC_PROT_ERR = WvWcLocalProtectionError, + IBV_WC_WR_FLUSH_ERR = WvWcFlushed, + IBV_WC_MW_BIND_ERR = WvWcMwBindError, + IBV_WC_REM_ACCESS_ERR = WvWcRemoteAccessError, + IBV_WC_REM_OP_ERR = WvWcRemoteOpError, + IBV_WC_RNR_RETRY_EXC_ERR = WvWcRnrRetryError, + IBV_WC_RESP_TIMEOUT_ERR = WvWcTimeoutRetryError, + IBV_WC_REM_INV_REQ_ERR = WvWcRemoteInvalidRequest, + IBV_WC_BAD_RESP_ERR = WvWcBadResponse, + IBV_WC_LOC_ACCESS_ERR = WvWcLocalAccessError, + IBV_WC_GENERAL_ERR = WvWcError, + IBV_WC_FATAL_ERR = -1, + IBV_WC_RETRY_EXC_ERR = -2, + IBV_WC_REM_ABORT_ERR = -3, + IBV_WC_LOC_EEC_OP_ERR = -4, + IBV_WC_LOC_RDD_VIOL_ERR = -5, + IBV_WC_REM_INV_RD_REQ_ERR = -6, + IBV_WC_INV_EECN_ERR = -7, + IBV_WC_INV_EEC_STATE_ERR = -8 + +}; + +__declspec(dllexport) +const char *ibv_wc_status_str(enum ibv_wc_status status); + +enum ibv_wc_opcode +{ + IBV_WC_SEND = WvSend, + IBV_WC_RDMA_WRITE = WvRdmaWrite, + IBV_WC_RDMA_READ = WvRdmaRead, + IBV_WC_COMP_SWAP = WvCompareExchange, + IBV_WC_FETCH_ADD = WvFetchAdd, + IBV_WC_BIND_MW = WvBindWindow, +/* + * Set value of IBV_WC_RECV so consumers can test if a completion is a + * receive by testing (opcode & IBV_WC_RECV). + */ + IBV_WC_RECV = WvReceive, + IBV_WC_RECV_RDMA_WITH_IMM = WvReceiveRdmaWrite +}; + +enum ibv_wc_flags +{ + IBV_WC_GRH = WV_WC_GRH_VALID, + IBV_WC_WITH_IMM = WV_WC_IMMEDIATE +}; + +struct ibv_wc +{ + union + { + uint32_t qp_num; + void* reserved; + }; + uint64_t wr_id; + enum ibv_wc_opcode opcode; + uint32_t byte_len; + uint32_t vendor_err2; + uint32_t vendor_err; + enum ibv_wc_status status; + + int wc_flags; + uint32_t imm_data; /* in network byte order */ + uint32_t src_qp; + uint16_t pkey_index; + uint16_t slid; + uint8_t sl; + uint8_t dlid_path_bits; +}; + +enum ibv_access_flags +{ + IBV_ACCESS_LOCAL_WRITE = WV_ACCESS_LOCAL_WRITE, + IBV_ACCESS_REMOTE_WRITE = WV_ACCESS_REMOTE_WRITE, + IBV_ACCESS_REMOTE_READ = WV_ACCESS_REMOTE_READ, + IBV_ACCESS_REMOTE_ATOMIC = WV_ACCESS_REMOTE_ATOMIC, + IBV_ACCESS_MW_BIND = WV_ACCESS_MW_BIND +}; + +struct ibv_pd +{ + struct ibv_context *context; + IWVProtectionDomain *handle; +}; + +/* Reregister MR not supported by WinVerbs */ +enum ibv_rereg_mr_flags +{ + IBV_REREG_MR_CHANGE_TRANSLATION = (1 << 0), + IBV_REREG_MR_CHANGE_PD = (1 << 1), + IBV_REREG_MR_CHANGE_ACCESS = (1 << 2), + IBV_REREG_MR_KEEP_VALID = (1 << 3) +}; + +struct ibv_mr +{ + struct ibv_context *context; + struct ibv_pd *pd; + void *addr; + size_t length; + uint32_t lkey; + uint32_t rkey; +}; + +/* Memory windows not implemented by WinVerbs */ +enum ibv_mw_type +{ + IBV_MW_TYPE_1 = 1, + IBV_MW_TYPE_2 = 2 +}; + +/* Memory windows not implemented by WinVerbs */ +struct ibv_mw +{ + struct ibv_context *context; + struct ibv_pd *pd; + uint32_t rkey; +}; + +struct ibv_global_route +{ + union ibv_gid dgid; + uint32_t flow_label; + uint8_t sgid_index; + uint8_t hop_limit; + uint8_t traffic_class; +}; + +struct ibv_grh +{ + uint32_t version_tclass_flow; + uint16_t paylen; + uint8_t next_hdr; + uint8_t hop_limit; + union ibv_gid sgid; + union ibv_gid dgid; +}; + +enum ibv_rate +{ + IBV_RATE_MAX = 0, + IBV_RATE_2_5_GBPS = 2, + IBV_RATE_5_GBPS = 5, + IBV_RATE_10_GBPS = 3, + IBV_RATE_20_GBPS = 6, + IBV_RATE_30_GBPS = 4, + IBV_RATE_40_GBPS = 7, + IBV_RATE_60_GBPS = 8, + IBV_RATE_80_GBPS = 9, + IBV_RATE_120_GBPS = 10 +}; + +/** + * ibv_rate_to_mult - Convert the IB rate enum to a multiple of the + * base rate of 2.5 Gbit/sec. For example, IBV_RATE_5_GBPS will be + * converted to 2, since 5 Gbit/sec is 2 * 2.5 Gbit/sec. + * @rate: rate to convert. + */ +__declspec(dllexport) +int ibv_rate_to_mult(enum ibv_rate rate); + +/** + * mult_to_ibv_rate - Convert a multiple of 2.5 Gbit/sec to an IB rate enum. + * @mult: multiple to convert. + */ +__declspec(dllexport) +enum ibv_rate mult_to_ibv_rate(int mult); + +struct ibv_ah_attr +{ + struct ibv_global_route grh; + uint16_t dlid; + uint8_t sl; + uint8_t src_path_bits; + uint8_t static_rate; + uint8_t is_global; + uint8_t port_num; +}; + +enum ibv_srq_attr_mask +{ + IBV_SRQ_MAX_WR = 1 << 0, + IBV_SRQ_LIMIT = 1 << 1 +}; + +struct ibv_srq_attr +{ + uint32_t max_wr; + uint32_t max_sge; + uint32_t srq_limit; +}; + +struct ibv_srq_init_attr +{ + void *srq_context; + struct ibv_srq_attr attr; +}; + +enum ibv_qp_type +{ + IBV_QPT_RC = WvQpTypeRc, + IBV_QPT_UC = WvQpTypeUc, + IBV_QPT_UD = WvQpTypeUd +}; + +struct ibv_qp_cap +{ + uint32_t max_send_wr; + uint32_t max_recv_wr; + uint32_t max_send_sge; + uint32_t max_recv_sge; + uint32_t max_inline_data; +}; + +struct ibv_qp_init_attr +{ + void *qp_context; + struct ibv_cq *send_cq; + struct ibv_cq *recv_cq; + struct ibv_srq *srq; + struct ibv_qp_cap cap; + enum ibv_qp_type qp_type; + int sq_sig_all; +}; + +enum ibv_qp_attr_mask +{ + IBV_QP_STATE = WV_QP_ATTR_STATE, + IBV_QP_CUR_STATE = WV_QP_ATTR_CURRENT_STATE, + IBV_QP_EN_SQD_ASYNC_NOTIFY = WV_QP_ATTR_FLAGS, + IBV_QP_ACCESS_FLAGS = WV_QP_ATTR_ACCESS_FLAGS, + IBV_QP_PKEY_INDEX = WV_QP_ATTR_PKEY_INDEX, + IBV_QP_PORT = WV_QP_ATTR_PORT_NUMBER, + IBV_QP_QKEY = WV_QP_ATTR_QKEY, + IBV_QP_AV = WV_QP_ATTR_AV, + IBV_QP_PATH_MTU = WV_QP_ATTR_AV, + IBV_QP_TIMEOUT = WV_QP_ATTR_ACK_TIMEOUT, + IBV_QP_RETRY_CNT = WV_QP_ATTR_ERROR_RETRY_COUNT, + IBV_QP_RNR_RETRY = WV_QP_ATTR_RNR_RETRY_COUNT, + IBV_QP_RQ_PSN = WV_QP_ATTR_RECEIVE_PSN, + IBV_QP_MAX_QP_RD_ATOMIC = WV_QP_ATTR_INITIATOR_DEPTH, + IBV_QP_ALT_PATH = WV_QP_ATTR_ALTERNATE_AV, + IBV_QP_MIN_RNR_TIMER = WV_QP_ATTR_RNR_NAK_TIMEOUT, + IBV_QP_SQ_PSN = WV_QP_ATTR_SEND_PSN, + IBV_QP_MAX_DEST_RD_ATOMIC = WV_QP_ATTR_RESPONDER_RESOURCES, + IBV_QP_PATH_MIG_STATE = WV_QP_ATTR_PATH_MIG_STATE, + IBV_QP_CAP = WV_QP_ATTR_CAPABILITIES, + IBV_QP_DEST_QPN = WV_QP_ATTR_DESTINATION_QPN +}; + +enum ibv_qp_state +{ + IBV_QPS_RESET = WvQpStateReset, + IBV_QPS_INIT = WvQpStateInit, + IBV_QPS_RTR = WvQpStateRtr, + IBV_QPS_RTS = WvQpStateRts, + IBV_QPS_SQD = WvQpStateSqd, + IBV_QPS_SQE = WvQpStateSqError, + IBV_QPS_ERR = WvQpStateError +}; + +enum ibv_mig_state +{ + IBV_MIG_MIGRATED = WvApmMigrated, + IBV_MIG_REARM = WvApmRearm, + IBV_MIG_ARMED = WvApmArmed +}; + +struct ibv_qp_attr +{ + enum ibv_qp_state qp_state; + enum ibv_qp_state cur_qp_state; + enum ibv_mtu path_mtu; + enum ibv_mig_state path_mig_state; + uint32_t qkey; + uint32_t rq_psn; + uint32_t sq_psn; + uint32_t dest_qp_num; + int qp_access_flags; + struct ibv_qp_cap cap; + struct ibv_ah_attr ah_attr; + struct ibv_ah_attr alt_ah_attr; + uint16_t pkey_index; + uint16_t alt_pkey_index; + uint8_t en_sqd_async_notify; + uint8_t sq_draining; + uint8_t max_rd_atomic; + uint8_t max_dest_rd_atomic; + uint8_t min_rnr_timer; + uint8_t port_num; + uint8_t timeout; + uint8_t retry_cnt; + uint8_t rnr_retry; + uint8_t alt_port_num; + uint8_t alt_timeout; +}; + +enum ibv_wr_opcode +{ + IBV_WR_SEND = WvSend, + IBV_WR_RDMA_WRITE = WvRdmaWrite, + IBV_WR_RDMA_READ = WvRdmaRead, + IBV_WR_ATOMIC_CMP_AND_SWP = WvCompareExchange, + IBV_WR_ATOMIC_FETCH_AND_ADD = WvFetchAdd, + IBV_WR_SEND_WITH_IMM = WvSend | 0x80000000, + IBV_WR_RDMA_WRITE_WITH_IMM = WvRdmaWrite | 0x80000000, +}; + +enum ibv_send_flags +{ + IBV_SEND_FENCE = WV_SEND_FENCE, + IBV_SEND_SIGNALED = WV_SEND_SIGNALED, + IBV_SEND_SOLICITED = WV_SEND_SOLICITED, + IBV_SEND_INLINE = WV_SEND_INLINE +}; + +struct ibv_sge +{ + uint64_t addr; + uint32_t length; + uint32_t lkey; +}; + +struct ibv_send_wr +{ + uint64_t wr_id; + struct ibv_send_wr *next; + struct ibv_sge *sg_list; + int num_sge; + enum ibv_wr_opcode opcode; + int send_flags; + uint32_t imm_data; /* in network byte order */ + union + { + struct + { + uint64_t remote_addr; + uint32_t rkey; + + } rdma; + struct + { + uint64_t remote_addr; + uint32_t rkey; + uint64_t compare_add; + uint64_t swap; + + } atomic; + struct + { + struct ibv_ah *ah; + uint32_t remote_qpn; + uint32_t remote_qkey; + + } ud; + } wr; +}; + +struct ibv_recv_wr +{ + uint64_t wr_id; + struct ibv_recv_wr *next; + struct ibv_sge *sg_list; + int num_sge; +}; + +/* Memory windows not implemented by WinVerbs */ +struct ibv_mw_bind +{ + uint64_t wr_id; + struct ibv_mr *mr; + void *addr; + size_t length; + int send_flags; + int mw_access_flags; +}; + +struct ibv_srq +{ + struct ibv_context *context; + void *srq_context; + struct ibv_pd *pd; + IWVSharedReceiveQueue *handle; +}; + +struct ibv_qp +{ + struct ibv_context *context; + void *qp_context; + struct ibv_pd *pd; + struct ibv_cq *send_cq; + struct ibv_cq *recv_cq; + struct ibv_srq *srq; + IWVQueuePair *handle; + union + { + IWVDatagramQueuePair *ud_handle; + IWVConnectQueuePair *conn_handle; + }; + uint32_t qp_num; + enum ibv_qp_state state; + enum ibv_qp_type qp_type; +}; + +struct ibv_comp_channel +{ + struct ibv_context *context; + COMP_CHANNEL comp_channel; +}; + +struct ibv_cq +{ + struct ibv_context *context; + struct ibv_comp_channel *channel; + void *cq_context; + IWVCompletionQueue *handle; + int cqe; + COMP_ENTRY comp_entry; + LONG volatile notify_cnt; + LONG volatile ack_cnt; +}; + +struct ibv_ah +{ + struct ibv_context *context; + struct ibv_pd *pd; + IWVAddressHandle *handle; + ULONG_PTR key; +}; + +struct ibv_device; +struct ibv_context; + +enum +{ + IBV_SYSFS_NAME_MAX = 64 +}; + +struct ibv_device +{ + enum ibv_node_type node_type; + enum ibv_transport_type transport_type; + char name[IBV_SYSFS_NAME_MAX]; +}; + +struct ibv_context +{ + struct ibv_device *device; + IWVDevice *cmd_if; + COMP_CHANNEL channel; +}; + +/** + * ibv_get_device_list - Get list of IB devices currently available + * @num_devices: optional. if non-NULL, set to the number of devices + * returned in the array. + * + * Return a NULL-terminated array of IB devices. The array can be + * released with ibv_free_device_list(). + */ +__declspec(dllexport) +struct ibv_device **ibv_get_device_list(int *num_devices); + +/** + * ibv_free_device_list - Free list from ibv_get_device_list() + * + * Free an array of devices returned from ibv_get_device_list(). Once + * the array is freed, pointers to devices that were not opened with + * ibv_open_device() are no longer valid. Client code must open all + * devices it intends to use before calling ibv_free_device_list(). + */ +__declspec(dllexport) +void ibv_free_device_list(struct ibv_device **list); + +/** + * ibv_get_device_name - Return kernel device name + */ +__declspec(dllexport) +const char *ibv_get_device_name(struct ibv_device *device); + +/** + * ibv_get_device_guid - Return device's node GUID + */ +__declspec(dllexport) +uint64_t ibv_get_device_guid(struct ibv_device *device); + +/** + * ibv_open_device - Initialize device for use + */ +__declspec(dllexport) +struct ibv_context *ibv_open_device(struct ibv_device *device); + +/** + * ibv_close_device - Release device + */ +__declspec(dllexport) +int ibv_close_device(struct ibv_context *context); + +/** + * ibv_get_async_event - Get next async event + * @event: Pointer to use to return async event + * + * All async events returned by ibv_get_async_event() must eventually + * be acknowledged with ibv_ack_async_event(). + */ +__declspec(dllexport) +int ibv_get_async_event(struct ibv_context *context, + struct ibv_async_event *event); + +/** + * ibv_ack_async_event - Acknowledge an async event + * @event: Event to be acknowledged. + * + * All async events which are returned by ibv_get_async_event() must + * be acknowledged. To avoid races, destroying an object (CQ, SRQ or + * QP) will wait for all affiliated events to be acknowledged, so + * there should be a one-to-one correspondence between acks and + * successful gets. + */ +__declspec(dllexport) +void ibv_ack_async_event(struct ibv_async_event *event); + +/** + * ibv_query_device - Get device properties + */ +__declspec(dllexport) +int ibv_query_device(struct ibv_context *context, + struct ibv_device_attr *device_attr); + +/** + * ibv_query_port - Get port properties + */ +__declspec(dllexport) +int ibv_query_port(struct ibv_context *context, uint8_t port_num, + struct ibv_port_attr *port_attr); + +/** + * ibv_query_gid - Get a GID table entry + */ +__declspec(dllexport) +int ibv_query_gid(struct ibv_context *context, uint8_t port_num, + int index, union ibv_gid *gid); + +/** + * ibv_query_pkey - Get a P_Key table entry + */ +__declspec(dllexport) +int ibv_query_pkey(struct ibv_context *context, uint8_t port_num, + int index, uint16_t *pkey); + +/** + * ibv_alloc_pd - Allocate a protection domain + */ +__declspec(dllexport) +struct ibv_pd *ibv_alloc_pd(struct ibv_context *context); + +/** + * ibv_dealloc_pd - Free a protection domain + */ +__declspec(dllexport) +int ibv_dealloc_pd(struct ibv_pd *pd); + +/** + * ibv_reg_mr - Register a memory region + */ +__declspec(dllexport) +struct ibv_mr *ibv_reg_mr(struct ibv_pd *pd, void *addr, + size_t length, int access); + +/** + * ibv_dereg_mr - Deregister a memory region + */ +__declspec(dllexport) +int ibv_dereg_mr(struct ibv_mr *mr); + +/** + * ibv_create_comp_channel - Create a completion event channel + */ +__declspec(dllexport) +struct ibv_comp_channel *ibv_create_comp_channel(struct ibv_context *context); + +/** + * ibv_destroy_comp_channel - Destroy a completion event channel + */ +__declspec(dllexport) +int ibv_destroy_comp_channel(struct ibv_comp_channel *channel); + +/** + * ibv_create_cq - Create a completion queue + * @context - Context CQ will be attached to + * @cqe - Minimum number of entries required for CQ + * @cq_context - Consumer-supplied context returned for completion events + * @channel - Completion channel where completion events will be queued. + * May be NULL if completion events will not be used. + * @comp_vector - Completion vector used to signal completion events. + * Must be >= 0 and < context->num_comp_vectors. + */ +__declspec(dllexport) +struct ibv_cq *ibv_create_cq(struct ibv_context *context, int cqe, + void *cq_context, + struct ibv_comp_channel *channel, + int comp_vector); + +/** + * ibv_resize_cq - Modifies the capacity of the CQ. + * @cq: The CQ to resize. + * @cqe: The minimum size of the CQ. + * + * Users can examine the cq structure to determine the actual CQ size. + */ +__declspec(dllexport) +int ibv_resize_cq(struct ibv_cq *cq, int cqe); + +/** + * ibv_destroy_cq - Destroy a completion queue + */ +__declspec(dllexport) +int ibv_destroy_cq(struct ibv_cq *cq); + +/** + * ibv_get_cq_event - Read next CQ event + * @channel: Channel to get next event from. + * @cq: Used to return pointer to CQ. + * @cq_context: Used to return consumer-supplied CQ context. + * + * All completion events returned by ibv_get_cq_event() must + * eventually be acknowledged with ibv_ack_cq_events(). + */ +__declspec(dllexport) +int ibv_get_cq_event(struct ibv_comp_channel *channel, + struct ibv_cq **cq, void **cq_context); + +/** + * ibv_ack_cq_events - Acknowledge CQ completion events + * @cq: CQ to acknowledge events for + * @nevents: Number of events to acknowledge. + * + * All completion events which are returned by ibv_get_cq_event() must + * be acknowledged. To avoid races, ibv_destroy_cq() will wait for + * all completion events to be acknowledged, so there should be a + * one-to-one correspondence between acks and successful gets. An + * application may accumulate multiple completion events and + * acknowledge them in a single call to ibv_ack_cq_events() by passing + * the number of events to ack in @nevents. + */ +__declspec(dllexport) +void ibv_ack_cq_events(struct ibv_cq *cq, unsigned int nevents); + +/** + * ibv_poll_cq - Poll a CQ for work completions + * @cq:the CQ being polled + * @num_entries:maximum number of completions to return + * @wc:array of at least @num_entries of &struct ibv_wc where completions + * will be returned + * + * Poll a CQ for (possibly multiple) completions. If the return value + * is < 0, an error occurred. If the return value is >= 0, it is the + * number of completions returned. If the return value is + * non-negative and strictly less than num_entries, then the CQ was + * emptied. + */ +__declspec(dllexport) +int ibv_poll_cq(struct ibv_cq *cq, int num_entries, struct ibv_wc *wc); + +/** + * ibv_req_notify_cq - Request completion notification on a CQ. An + * event will be added to the completion channel associated with the + * CQ when an entry is added to the CQ. + * @cq: The completion queue to request notification for. + * @solicited_only: If non-zero, an event will be generated only for + * the next solicited CQ entry. If zero, any CQ entry, solicited or + * not, will generate an event. + */ +__declspec(dllexport) +int ibv_req_notify_cq(struct ibv_cq *cq, int solicited_only); + +/** + * ibv_create_srq - Creates a SRQ associated with the specified protection + * domain. + * @pd: The protection domain associated with the SRQ. + * @srq_init_attr: A list of initial attributes required to create the SRQ. + * + * srq_attr->max_wr and srq_attr->max_sge are read the determine the + * requested size of the SRQ, and set to the actual values allocated + * on return. If ibv_create_srq() succeeds, then max_wr and max_sge + * will always be at least as large as the requested values. + */ +__declspec(dllexport) +struct ibv_srq *ibv_create_srq(struct ibv_pd *pd, + struct ibv_srq_init_attr *srq_init_attr); + +/** + * ibv_modify_srq - Modifies the attributes for the specified SRQ. + * @srq: The SRQ to modify. + * @srq_attr: On input, specifies the SRQ attributes to modify. On output, + * the current values of selected SRQ attributes are returned. + * @srq_attr_mask: A bit-mask used to specify which attributes of the SRQ + * are being modified. + * + * The mask may contain IBV_SRQ_MAX_WR to resize the SRQ and/or + * IBV_SRQ_LIMIT to set the SRQ's limit and request notification when + * the number of receives queued drops below the limit. + */ +__declspec(dllexport) +int ibv_modify_srq(struct ibv_srq *srq, + struct ibv_srq_attr *srq_attr, + int srq_attr_mask); + +/** + * ibv_query_srq - Returns the attribute list and current values for the + * specified SRQ. + * @srq: The SRQ to query. + * @srq_attr: The attributes of the specified SRQ. + */ +__declspec(dllexport) +int ibv_query_srq(struct ibv_srq *srq, struct ibv_srq_attr *srq_attr); + +/** + * ibv_destroy_srq - Destroys the specified SRQ. + * @srq: The SRQ to destroy. + */ +__declspec(dllexport) +int ibv_destroy_srq(struct ibv_srq *srq); + +/** + * ibv_post_srq_recv - Posts a list of work requests to the specified SRQ. + * @srq: The SRQ to post the work request on. + * @recv_wr: A list of work requests to post on the receive queue. + * @bad_recv_wr: On an immediate failure, this parameter will reference + * the work request that failed to be posted on the QP. + */ +__declspec(dllexport) +int ibv_post_srq_recv(struct ibv_srq *srq, + struct ibv_recv_wr *recv_wr, + struct ibv_recv_wr **bad_recv_wr); + +/** + * ibv_create_qp - Create a queue pair. + */ +__declspec(dllexport) +struct ibv_qp *ibv_create_qp(struct ibv_pd *pd, + struct ibv_qp_init_attr *qp_init_attr); + +/** + * ibv_modify_qp - Modify a queue pair. + */ +__declspec(dllexport) +int ibv_modify_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr, + int attr_mask); + +/** + * ibv_query_qp - Returns the attribute list and current values for the + * specified QP. + * @qp: The QP to query. + * @attr: The attributes of the specified QP. + * @attr_mask: A bit-mask used to select specific attributes to query. + * @init_attr: Additional attributes of the selected QP. + * + * The qp_attr_mask may be used to limit the query to gathering only the + * selected attributes. + */ +__declspec(dllexport) +int ibv_query_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr, + int attr_mask, + struct ibv_qp_init_attr *init_attr); + +/** + * ibv_destroy_qp - Destroy a queue pair. + */ +__declspec(dllexport) +int ibv_destroy_qp(struct ibv_qp *qp); + +/** + * ibv_post_send - Post a list of work requests to a send queue. + * + * If IBV_SEND_INLINE flag is set, the data buffers can be reused + * immediately after the call returns. + */ +__declspec(dllexport) +int ibv_post_send(struct ibv_qp *qp, struct ibv_send_wr *wr, + struct ibv_send_wr **bad_wr); + +/** + * ibv_post_recv - Post a list of work requests to a receive queue. + */ +__declspec(dllexport) +int ibv_post_recv(struct ibv_qp *qp, struct ibv_recv_wr *wr, + struct ibv_recv_wr **bad_wr); + +/** + * ibv_create_ah - Create an address handle. + */ +__declspec(dllexport) +struct ibv_ah *ibv_create_ah(struct ibv_pd *pd, struct ibv_ah_attr *attr); + +/** + * ibv_init_ah_from_wc - Initializes address handle attributes from a + * work completion. + * @context: Device context on which the received message arrived. + * @port_num: Port on which the received message arrived. + * @wc: Work completion associated with the received message. + * @grh: References the received global route header. This parameter is + * ignored unless the work completion indicates that the GRH is valid. + * @ah_attr: Returned attributes that can be used when creating an address + * handle for replying to the message. + */ +__declspec(dllexport) +int ibv_init_ah_from_wc(struct ibv_context *context, uint8_t port_num, + struct ibv_wc *wc, struct ibv_grh *grh, + struct ibv_ah_attr *ah_attr); + +/** + * ibv_create_ah_from_wc - Creates an address handle associated with the + * sender of the specified work completion. + * @pd: The protection domain associated with the address handle. + * @wc: Work completion information associated with a received message. + * @grh: References the received global route header. This parameter is + * ignored unless the work completion indicates that the GRH is valid. + * @port_num: The outbound port number to associate with the address. + * + * The address handle is used to reference a local or global destination + * in all UD QP post sends. + */ +__declspec(dllexport) +struct ibv_ah *ibv_create_ah_from_wc(struct ibv_pd *pd, struct ibv_wc *wc, + struct ibv_grh *grh, uint8_t port_num); + +/** + * ibv_destroy_ah - Destroy an address handle. + */ +__declspec(dllexport) +int ibv_destroy_ah(struct ibv_ah *ah); + +/** + * ibv_attach_mcast - Attaches the specified QP to a multicast group. + * @qp: QP to attach to the multicast group. The QP must be a UD QP. + * @gid: Multicast group GID. + * @lid: Multicast group LID in host byte order. + * + * In order to route multicast packets correctly, subnet + * administration must have created the multicast group and configured + * the fabric appropriately. The port associated with the specified + * QP must also be a member of the multicast group. + */ +__declspec(dllexport) +int ibv_attach_mcast(struct ibv_qp *qp, union ibv_gid *gid, uint16_t lid); + +/** + * ibv_detach_mcast - Detaches the specified QP from a multicast group. + * @qp: QP to detach from the multicast group. + * @gid: Multicast group GID. + * @lid: Multicast group LID in host byte order. + */ +__declspec(dllexport) +int ibv_detach_mcast(struct ibv_qp *qp, union ibv_gid *gid, uint16_t lid); + +/** + * ibv_node_type_str - Return string describing node_type enum value + */ +__declspec(dllexport) +const char *ibv_node_type_str(enum ibv_node_type node_type); + +/** + * ibv_port_state_str - Return string describing port_state enum value + */ +__declspec(dllexport) +const char *ibv_port_state_str(enum ibv_port_state port_state); + +/** + * ibv_event_type_str - Return string describing event_type enum value + */ +__declspec(dllexport) +const char *ibv_event_type_str(enum ibv_event_type event); + +/* + * Windows specific structures and interfaces + */ +struct ibvw_windata +{ + IWVProvider *prov; + COMP_MANAGER *comp_mgr; +}; + +#define IBVW_WINDATA_VERSION 1 + +__declspec(dllexport) +int ibvw_get_windata(struct ibvw_windata *windata, int version); + +__declspec(dllexport) +void ibvw_release_windata(struct ibvw_windata *windata, int version); + +__declspec(dllexport) +int ibvw_wv_errno(HRESULT hr); + +#ifdef __cplusplus +} +#endif + +#endif /* INFINIBAND_VERBS_H */ diff --git a/branches/WOF2-3/ulp/libibverbs/src/Sources b/branches/WOF2-3/ulp/libibverbs/src/Sources new file mode 100644 index 00000000..20c50ae1 --- /dev/null +++ b/branches/WOF2-3/ulp/libibverbs/src/Sources @@ -0,0 +1,38 @@ +!if $(FREEBUILD) +TARGETNAME = libibverbs +!else +TARGETNAME = libibverbsd +!endif + +TARGETPATH = ..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = DYNLINK + +!if $(_NT_TOOLS_VERSION) == 0x700 +DLLDEF = $O\ibv_exports.def +!else +DLLDEF = $(OBJ_PATH)\$O\ibv_exports.def +!endif + +DLLENTRY = DllMain +USE_MSVCRT = 1 + +SOURCES = \ + ibverbs.rc \ + ibv_main.cpp \ + verbs.cpp \ + device.cpp \ + enum_strs.cpp + +INCLUDES = ..\include;..\..\..\inc;..\..\..\inc\user;..\..\..\inc\user\linux; + +USER_C_FLAGS = $(USER_C_FLAGS) -DEXPORT_IBV_SYMBOLS + +TARGETLIBS = \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\uuid.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\winverbs.lib +!else + $(TARGETPATH)\*\winverbsd.lib +!endif diff --git a/branches/WOF2-3/ulp/libibverbs/src/device.cpp b/branches/WOF2-3/ulp/libibverbs/src/device.cpp new file mode 100644 index 00000000..e404be79 --- /dev/null +++ b/branches/WOF2-3/ulp/libibverbs/src/device.cpp @@ -0,0 +1,372 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include "..\..\..\etc\user\comp_channel.cpp" + +CRITICAL_SECTION lock; +IWVProvider *prov; +COMP_MANAGER comp_mgr; +static DWORD ref; + +struct verbs_device +{ + struct ibv_device device; + uint64_t guid; + uint8_t phys_port_cnt; +}; + +struct verbs_port +{ + COMP_ENTRY comp_entry; + DWORD event_flag; + uint8_t port_num; +}; + +struct verbs_context +{ + struct ibv_context context; + struct verbs_device device; + uint8_t closing; + struct verbs_port *port; + verbs_port *event_port; +}; + +static int ibv_acquire(void) +{ + HRESULT hr; + + EnterCriticalSection(&lock); + if (ref++ == 0) { + hr = WvGetObject(IID_IWVProvider, (LPVOID*) &prov); + if (FAILED(hr)) { + goto err1; + } + hr = CompManagerOpen(&comp_mgr); + if (FAILED(hr)) { + goto err2; + } + hr = CompManagerMonitor(&comp_mgr, prov->GetFileHandle(), 0); + if (FAILED(hr)) { + goto err3; + } + } + LeaveCriticalSection(&lock); + return 0; + +err3: + CompManagerClose(&comp_mgr); +err2: + prov->Release(); +err1: + ref--; + LeaveCriticalSection(&lock); + return hr; +} + +static void ibv_release(void) +{ + EnterCriticalSection(&lock); + if (--ref == 0) { + CompManagerClose(&comp_mgr); + prov->Release(); + } + LeaveCriticalSection(&lock); +} + +__declspec(dllexport) +int ibvw_get_windata(struct ibvw_windata *windata, int version) +{ + int ret; + + if (version != IBVW_WINDATA_VERSION || ibv_acquire()) { + return -1; + } + + prov->AddRef(); + windata->prov = prov; + windata->comp_mgr = &comp_mgr; + return 0; +} + +__declspec(dllexport) +void ibvw_release_windata(struct ibvw_windata *windata, int version) +{ + prov->Release(); + ibv_release(); +} + +__declspec(dllexport) +struct ibv_device **ibv_get_device_list(int *num) +{ + WV_DEVICE_ATTRIBUTES attr; + struct verbs_device *dev_array; + struct ibv_device **pdev_array; + NET64 *guid; + SIZE_T size, cnt; + HRESULT hr; + + if (ibv_acquire()) { + goto err1; + } + + cnt = 0; + size = sizeof(NET64); + + while ((size / sizeof(NET64)) > cnt) { + if (cnt > 0) { + delete guid; + } + + cnt = size / sizeof(NET64); + guid = new NET64[cnt]; + if (guid == NULL) { + goto err1; + } + + hr = prov->QueryDeviceList(guid, &size); + if (FAILED(hr)) { + goto err2; + } + } + + size /= sizeof(NET64); + dev_array = new struct verbs_device[size]; + pdev_array = new struct ibv_device*[size + 1]; + if (dev_array == NULL || pdev_array == NULL) { + goto err2; + } + + for (cnt = 0; cnt < size; cnt++) { + pdev_array[cnt] = &dev_array[cnt].device; + hr = prov->QueryDevice(guid[cnt], &attr); + if (FAILED(hr)) { + goto err3; + } + + sprintf(dev_array[cnt].device.name, "ibv_device%d", cnt); + dev_array[cnt].device.node_type = IBV_NODE_UNKNOWN; + dev_array[cnt].device.transport_type = (ibv_transport_type) attr.DeviceType; + dev_array[cnt].guid = guid[cnt]; + dev_array[cnt].phys_port_cnt = attr.PhysPortCount; + } + + pdev_array[cnt] = NULL; + if (num != NULL) { + *num = (int) size; + } + return pdev_array; + +err3: + ibv_free_device_list(pdev_array); +err2: + delete guid; +err1: + return NULL; +} + +__declspec(dllexport) +void ibv_free_device_list(struct ibv_device **list) +{ + ibv_release(); + delete CONTAINING_RECORD(list[0], struct verbs_device, device); + delete list; +} + +__declspec(dllexport) +const char *ibv_get_device_name(struct ibv_device *device) +{ + return device->name; +} + +__declspec(dllexport) +uint64_t ibv_get_device_guid(struct ibv_device *device) +{ + return CONTAINING_RECORD(device, struct verbs_device, device)->guid; +} + +__declspec(dllexport) +struct ibv_context *ibv_open_device(struct ibv_device *device) +{ + struct verbs_device *vdev; + struct verbs_context *vcontext; + HRESULT hr; + int i; + + vdev = CONTAINING_RECORD(device, struct verbs_device, device); + vcontext = new struct verbs_context; + if (vcontext == NULL) { + return NULL; + } + + ibv_acquire(); + memcpy(&vcontext->device, vdev, sizeof(struct verbs_device)); + vcontext->context.device = &vcontext->device.device; + vcontext->event_port = NULL; + vcontext->closing = 0; + CompChannelInit(&comp_mgr, &vcontext->context.channel, INFINITE); + + vcontext->port = new struct verbs_port[vdev->phys_port_cnt]; + if (vcontext->port == NULL) { + goto err1; + } + + hr = prov->OpenDevice(vdev->guid, &vcontext->context.cmd_if); + if (FAILED(hr)) { + goto err2; + } + + for (i = 0; i < vdev->phys_port_cnt; i++) { + vcontext->port[i].port_num = (uint8_t) i + 1; + vcontext->port[i].event_flag = 0; + CompEntryInit(&vcontext->context.channel, &vcontext->port[i].comp_entry); + vcontext->port[i].comp_entry.Busy = 1; + vcontext->context.cmd_if->Notify(vcontext->port[i].port_num, + &vcontext->port[i].comp_entry.Overlap, + &vcontext->port[i].event_flag); + } + + return &vcontext->context; + +err2: + delete vcontext->port; +err1: + delete vcontext; + ibv_release(); + return NULL; +} + +__declspec(dllexport) +int ibv_close_device(struct ibv_context *context) +{ + struct verbs_context *vcontext; + int i; + + vcontext = CONTAINING_RECORD(context, struct verbs_context, context); + vcontext->closing = 1; + context->cmd_if->CancelOverlappedRequests(); + + for (i = 0; i < vcontext->device.phys_port_cnt; i++) { + CompEntryCancel(&vcontext->port[i].comp_entry); + } + + context->cmd_if->Release(); + CompChannelCleanup(&vcontext->context.channel); + ibv_release(); + delete vcontext->port; + delete vcontext; + return 0; +} + +static enum ibv_event_type ibv_get_port_event_state(struct verbs_context *vcontext) +{ + WV_PORT_ATTRIBUTES attr; + HRESULT hr; + + hr = vcontext->context.cmd_if->QueryPort(vcontext->event_port->port_num, &attr); + if (FAILED(hr)) { + return IBV_EVENT_PORT_ERR; + } + + return (attr.State == WvPortActive) ? + IBV_EVENT_PORT_ACTIVE : IBV_EVENT_PORT_ERR; +} + +static int ibv_report_port_event(struct verbs_context *vcontext, + struct ibv_async_event *event) +{ + struct verbs_port *port; + int ret = 0; + + port = vcontext->event_port; + event->element.port_num = port->port_num; + + if (port->event_flag & WV_EVENT_ERROR) { + event->event_type = IBV_EVENT_DEVICE_FATAL; + port->event_flag = 0; + } else if (port->event_flag & WV_EVENT_STATE) { + event->event_type = ibv_get_port_event_state(vcontext); + port->event_flag = 0; + } else if (port->event_flag & WV_EVENT_MANAGEMENT) { + event->event_type = IBV_EVENT_SM_CHANGE; + port->event_flag = 0; + } else if (port->event_flag & WV_EVENT_LINK_ADDRESS) { + event->event_type = IBV_EVENT_LID_CHANGE; + port->event_flag &= ~WV_EVENT_LINK_ADDRESS; + } else if (port->event_flag & WV_EVENT_PARTITION) { + event->event_type = IBV_EVENT_PKEY_CHANGE; + port->event_flag &= ~WV_EVENT_PARTITION; + } else { + port->event_flag = 0; + ret = -1; + } + + if (port->event_flag == 0 && !vcontext->closing) { + port->comp_entry.Busy = 1; + vcontext->context.cmd_if->Notify(vcontext->event_port->port_num, + &port->comp_entry.Overlap, + &port->event_flag); + vcontext->event_port = NULL; + } + return ret; +} + +__declspec(dllexport) +int ibv_get_async_event(struct ibv_context *context, + struct ibv_async_event *event) +{ + struct verbs_context *vcontext; + COMP_ENTRY *entry; + int ret; + + vcontext = CONTAINING_RECORD(context, struct verbs_context, context); + if (vcontext->event_port) { + if (ibv_report_port_event(vcontext, event) == 0) { + return 0; + } + } + + ret = CompChannelPoll(&context->channel, &entry); + if (!ret) { + vcontext->event_port = CONTAINING_RECORD(entry, struct verbs_port, comp_entry); + ret = ibv_report_port_event(vcontext, event); + } + + return ret; +} + +__declspec(dllexport) +void ibv_ack_async_event(struct ibv_async_event *event) +{ + // Only device/port level events are currently supported + // nothing to do here at the moment +} diff --git a/branches/WOF2-3/ulp/libibverbs/src/enum_strs.cpp b/branches/WOF2-3/ulp/libibverbs/src/enum_strs.cpp new file mode 100644 index 00000000..945583f9 --- /dev/null +++ b/branches/WOF2-3/ulp/libibverbs/src/enum_strs.cpp @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2008 Lawrence Livermore National Laboratory + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include + +__declspec(dllexport) +const char *ibv_node_type_str(enum ibv_node_type node_type) +{ + static const char *const node_type_str[] = { + "unknown", + "InfiniBand channel adapter", + "InfiniBand switch", + "InfiniBand router", + "iWARP NIC" + }; + + if (node_type < IBV_NODE_CA || node_type > IBV_NODE_RNIC) + return "unknown"; + + return node_type_str[node_type]; +} + +__declspec(dllexport) +const char *ibv_port_state_str(enum ibv_port_state port_state) +{ + static const char *const port_state_str[] = { + "no state change (NOP)", + "PORT_DOWN", + "PORT_INIT", + "PORT_ARMED", + "PORT_ACTIVE", + "PORt_ACTIVE_DEFER" + }; + + if (port_state < IBV_PORT_NOP || port_state > IBV_PORT_ACTIVE_DEFER) + return "unknown"; + + return port_state_str[port_state]; +} + +__declspec(dllexport) +const char *ibv_event_type_str(enum ibv_event_type event) +{ + static const char *const event_type_str[] = { + "CQ error", + "local work queue catastrophic error", + "invalid request local work queue error", + "local access violation work queue error", + "communication established", + "send queue drained", + "path migrated", + "path migration request error", + "local catastrophic error", + "port active", + "port error", + "LID change", + "P_Key change", + "SM change", + "SRQ catastrophic error", + "SRQ limit reached", + "last WQE reached", + "client reregistration", + }; + + if (event < IBV_EVENT_CQ_ERR || event > IBV_EVENT_CLIENT_REREGISTER) + return "unknown"; + + return event_type_str[event]; +} + +__declspec(dllexport) +const char *ibv_wc_status_str(enum ibv_wc_status status) +{ + static const char *const wc_status_str[] = { + "success", + "local length error", + "local QP operation error", + "local protection error", + "Work Request Flushed Error", + "memory management operation error", + "remote access error", + "remote operation error", + "RNR retry counter exceeded", + "response timeout error", + "remote invalid request error", + "bad response error", + "local access error", + "general error", + "fatal error", + "transport retry counter exceeded", + "aborted error", + "local EE context operation error", + "local RDD violation error", + "remote invalid RD request", + "invalid EE context number", + "invalid EE context state" + }; + + if (status < IBV_WC_SUCCESS || status > IBV_WC_GENERAL_ERR) + return "unknown"; + + return wc_status_str[status]; +} diff --git a/branches/WOF2-3/ulp/libibverbs/src/ibv_export.def b/branches/WOF2-3/ulp/libibverbs/src/ibv_export.def new file mode 100644 index 00000000..6c76ba5d --- /dev/null +++ b/branches/WOF2-3/ulp/libibverbs/src/ibv_export.def @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +LIBRARY LIBIBVERBS.DLL + +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE diff --git a/branches/WOF2-3/ulp/libibverbs/src/ibv_exports.src b/branches/WOF2-3/ulp/libibverbs/src/ibv_exports.src new file mode 100644 index 00000000..48fc8bc2 --- /dev/null +++ b/branches/WOF2-3/ulp/libibverbs/src/ibv_exports.src @@ -0,0 +1,57 @@ +#if DBG +LIBRARY libibverbsd.dll +#else +LIBRARY libibverbs.dll +#endif + +#ifndef _WIN64 +EXPORTS +ibv_get_device_list +ibv_free_device_list +ibv_get_device_name +ibv_get_device_guid +ibv_open_device +ibv_close_device +ibv_get_async_event +ibv_ack_async_event +ibv_query_device +ibv_query_port +ibv_query_gid +ibv_query_pkey +ibv_alloc_pd +ibv_dealloc_pd +ibv_reg_mr +ibv_dereg_mr +ibv_create_comp_channel +ibv_destroy_comp_channel +ibv_create_cq +ibv_resize_cq +ibv_destroy_cq +ibv_get_cq_event +ibv_ack_cq_events +ibv_poll_cq +ibv_req_notify_cq +ibv_create_srq +ibv_modify_srq +ibv_query_srq +ibv_destroy_srq +ibv_post_srq_recv +ibv_create_qp +ibv_modify_qp +ibv_query_qp +ibv_destroy_qp +ibv_post_send +ibv_post_recv +ibv_create_ah +ibv_init_ah_from_wc +ibv_create_ah_from_wc +ibv_destroy_ah +ibv_attach_mcast +ibv_detach_mcast +ibv_node_type_str +ibv_port_state_str +ibv_event_type_str +ibvw_get_windata +ibvw_release_windata +ibvw_wv_errno +#endif diff --git a/branches/WOF2-3/ulp/libibverbs/src/ibv_main.cpp b/branches/WOF2-3/ulp/libibverbs/src/ibv_main.cpp new file mode 100644 index 00000000..c6f4b73f --- /dev/null +++ b/branches/WOF2-3/ulp/libibverbs/src/ibv_main.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include <_errno.h> + +extern CRITICAL_SECTION lock; +HANDLE heap; + +BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) +{ + UNREFERENCED_PARAMETER(hInstance); + UNREFERENCED_PARAMETER(lpReserved); + + switch (dwReason) { + case DLL_PROCESS_ATTACH: + heap = HeapCreate(0, 0, 0); + if (heap == NULL) { + return FALSE; + } + InitializeCriticalSection(&lock); + break; + case DLL_PROCESS_DETACH: + DeleteCriticalSection(&lock); + HeapDestroy(heap); + break; + default: + break; + } + + return TRUE; +} diff --git a/branches/WOF2-3/ulp/libibverbs/src/ibverbs.h b/branches/WOF2-3/ulp/libibverbs/src/ibverbs.h new file mode 100644 index 00000000..63eb9685 --- /dev/null +++ b/branches/WOF2-3/ulp/libibverbs/src/ibverbs.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2009 Intel Corp, Inc. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef IB_VERBS_H +#define IB_VERBS_H + +#include <_errno.h> + +extern COMP_MANAGER comp_mgr; +extern HANDLE heap; + +__inline void* __cdecl operator new(size_t size) +{ + return HeapAlloc(heap, 0, size); +} + +__inline void __cdecl operator delete(void *pObj) +{ + HeapFree(heap, 0, pObj); +} + +#endif /* IB_VERBS_H */ diff --git a/branches/WOF2-3/ulp/libibverbs/src/ibverbs.rc b/branches/WOF2-3/ulp/libibverbs/src/ibverbs.rc new file mode 100644 index 00000000..1e2b9c1f --- /dev/null +++ b/branches/WOF2-3/ulp/libibverbs/src/ibverbs.rc @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + +#include + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef DBG +#define VER_FILEDESCRIPTION_STR "LibIbVerbs (Debug)" +#define VER_INTERNALNAME_STR "libibverbsd.dll" +#define VER_ORIGINALFILENAME_STR "libibverbsd.dll" +#else +#define VER_FILEDESCRIPTION_STR "LibIbVerbs" +#define VER_INTERNALNAME_STR "libibverbs.dll" +#define VER_ORIGINALFILENAME_STR "libibverbs.dll" +#endif + +#include diff --git a/branches/WOF2-3/ulp/libibverbs/src/makefile b/branches/WOF2-3/ulp/libibverbs/src/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-3/ulp/libibverbs/src/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\inc\openib.def diff --git a/branches/WOF2-3/ulp/libibverbs/src/verbs.cpp b/branches/WOF2-3/ulp/libibverbs/src/verbs.cpp new file mode 100644 index 00000000..3a22e950 --- /dev/null +++ b/branches/WOF2-3/ulp/libibverbs/src/verbs.cpp @@ -0,0 +1,930 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. + * Copyright (c) 2008-2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include + +#include +#include +#include "ibverbs.h" + + +__declspec(dllexport) +int ibv_rate_to_mult(enum ibv_rate rate) +{ + switch (rate) { + case IBV_RATE_2_5_GBPS: return 1; + case IBV_RATE_5_GBPS: return 2; + case IBV_RATE_10_GBPS: return 4; + case IBV_RATE_20_GBPS: return 8; + case IBV_RATE_30_GBPS: return 12; + case IBV_RATE_40_GBPS: return 16; + case IBV_RATE_60_GBPS: return 24; + case IBV_RATE_80_GBPS: return 32; + case IBV_RATE_120_GBPS: return 48; + default: return -1; + } +} + +__declspec(dllexport) +enum ibv_rate mult_to_ibv_rate(int mult) +{ + switch (mult) { + case 1: return IBV_RATE_2_5_GBPS; + case 2: return IBV_RATE_5_GBPS; + case 4: return IBV_RATE_10_GBPS; + case 8: return IBV_RATE_20_GBPS; + case 12: return IBV_RATE_30_GBPS; + case 16: return IBV_RATE_40_GBPS; + case 24: return IBV_RATE_60_GBPS; + case 32: return IBV_RATE_80_GBPS; + case 48: return IBV_RATE_120_GBPS; + default: return IBV_RATE_MAX; + } +} + +static int ibv_find_gid_index(struct ibv_context *context, uint8_t port_num, + union ibv_gid *gid) +{ + union ibv_gid sgid; + int i = 0, ret; + + do { + ret = ibv_query_gid(context, port_num, i++, &sgid); + } while (!ret && memcmp(&sgid, gid, sizeof *gid)); + + return ret ? -1 : i - 1; +} + +static void ibv_convert_ah_attr(struct ibv_context *context, + WV_ADDRESS_VECTOR *av, struct ibv_ah_attr *attr) +{ + WV_GID gid; + + av->Route.Valid = attr->is_global; + if (av->Route.Valid) { + context->cmd_if->QueryGid(attr->port_num, attr->grh.sgid_index, &gid); + + memcpy(&av->Route.DGid, &attr->grh.dgid, sizeof(av->Route.DGid)); + memcpy(&av->Route.SGid, &gid, sizeof(av->Route.SGid)); + av->Route.TrafficClass = attr->grh.traffic_class; + av->Route.FlowLabel = htonl(attr->grh.flow_label); + av->Route.HopLimit = attr->grh.hop_limit; + } + + av->DLid = htons(attr->dlid); + av->ServiceLevel = attr->sl; + av->SourcePathBits = attr->src_path_bits; + av->StaticRate = attr->static_rate; + av->PortNumber = attr->port_num; +} + +static void ibv_convert_av(struct ibv_context *context, + struct ibv_ah_attr *attr, WV_ADDRESS_VECTOR *av) +{ + WV_GID gid; + + attr->is_global = av->Route.Valid; + if (attr->is_global) { + memcpy(&attr->grh.dgid, &av->Route.DGid, sizeof(attr->grh.dgid)); + attr->grh.flow_label = ntohl(av->Route.FlowLabel); + attr->grh.traffic_class = av->Route.TrafficClass; + attr->grh.hop_limit = av->Route.HopLimit; + attr->grh.sgid_index = (uint8_t) ibv_find_gid_index(context, av->PortNumber, + (ibv_gid *) &av->Route.SGid); + } + + attr->dlid = ntohs(av->DLid); + attr->sl = av->ServiceLevel; + attr->src_path_bits = av->SourcePathBits; + attr->static_rate = av->StaticRate; + attr->port_num = av->PortNumber; +} + +__declspec(dllexport) +int ibv_query_device(struct ibv_context *context, + struct ibv_device_attr *device_attr) +{ + WV_DEVICE_ATTRIBUTES attr; + HRESULT hr; + + hr = context->cmd_if->Query(&attr); + if (FAILED(hr)) { + return ibvw_wv_errno(hr); + } + + sprintf(device_attr->fw_ver, "0x%I64x", attr.FwVersion); + device_attr->node_guid = attr.NodeGuid; + device_attr->sys_image_guid = attr.SystemImageGuid; + device_attr->max_mr_size = attr.MaxMrSize; + device_attr->page_size_cap = attr.PageSizeCapabilityFlags; + device_attr->vendor_id = attr.VendorId; + device_attr->vendor_part_id = attr.VendorPartId; + device_attr->hw_ver = attr.HwVersion; + device_attr->max_qp = (int) attr.MaxQp; + device_attr->max_qp_wr = (int) attr.MaxQpWr; + device_attr->device_cap_flags = (int) attr.CapabilityFlags; + device_attr->max_sge = (int) attr.MaxSge; + device_attr->max_sge_rd = 0; + device_attr->max_cq = (int) attr.MaxCq; + device_attr->max_cqe = (int) attr.MaxCqEntries; + device_attr->max_mr = (int) attr.MaxMr; + device_attr->max_pd = (int) attr.MaxPd; + device_attr->max_qp_rd_atom = (int) attr.MaxQpResponderResources;; + device_attr->max_ee_rd_atom = 0; + device_attr->max_res_rd_atom = (int) attr.MaxResponderResources; + device_attr->max_qp_init_rd_atom = (int) attr.MaxQpInitiatorDepth; + device_attr->max_ee_init_rd_atom = 0; + device_attr->atomic_cap = (enum ibv_atomic_cap) attr.AtomicCapability; + device_attr->max_ee = 0; + device_attr->max_rdd = 0; + device_attr->max_mw = (int) attr.MaxMw; + device_attr->max_raw_ipv6_qp = 0; + device_attr->max_raw_ethy_qp = 0; + device_attr->max_mcast_grp = (int) attr.MaxMulticast; + device_attr->max_mcast_qp_attach = (int) attr.MaxQpAttach; + device_attr->max_total_mcast_qp_attach = (int) attr.MaxMulticastQp; + device_attr->max_ah = (int) attr.MaxAh; + device_attr->max_fmr = (int) attr.MaxFmr; + device_attr->max_map_per_fmr = (int) attr.MaxMapPerFmr; + device_attr->max_srq = (int) attr.MaxSrq; + device_attr->max_srq_wr = (int) attr.MaxSrqWr; + device_attr->max_srq_sge = (int) attr.MaxSrqSge; + device_attr->max_pkeys = (uint16_t) attr.MaxPkeys; + device_attr->local_ca_ack_delay = attr.LocalAckDelay; + device_attr->phys_port_cnt = attr.PhysPortCount; + + return 0; +} + +static enum ibv_mtu ibv_convert_mtu(UINT32 mtu) +{ + switch (mtu) { + case 256: return IBV_MTU_256; + case 512: return IBV_MTU_512; + case 1024: return IBV_MTU_1024; + case 2048: return IBV_MTU_2048; + case 4096: return IBV_MTU_4096; + default: return (ibv_mtu) mtu; + } +} + +__declspec(dllexport) +int ibv_query_port(struct ibv_context *context, uint8_t port_num, + struct ibv_port_attr *port_attr) +{ + WV_PORT_ATTRIBUTES attr; + HRESULT hr; + + hr = context->cmd_if->QueryPort(port_num, &attr); + if (FAILED(hr)) { + return ibvw_wv_errno(hr); + } + + port_attr->state = (enum ibv_port_state) attr.State; + port_attr->max_mtu = ibv_convert_mtu(attr.MaxMtu); + port_attr->active_mtu = ibv_convert_mtu(attr.ActiveMtu); + port_attr->gid_tbl_len = attr.GidTableLength; + port_attr->port_cap_flags = attr.PortCabilityFlags; + port_attr->max_msg_sz = attr.MaxMessageSize; + port_attr->bad_pkey_cntr = attr.BadPkeyCounter; + port_attr->qkey_viol_cntr = attr.QkeyViolationCounter; + port_attr->pkey_tbl_len = attr.PkeyTableLength; + port_attr->lid = ntohs(attr.Lid); + port_attr->sm_lid = ntohs(attr.SmLid); + port_attr->lmc = attr.Lmc; + port_attr->max_vl_num = attr.MaxVls; + port_attr->sm_sl = attr.SmSl; + port_attr->subnet_timeout = attr.SubnetTimeout; + port_attr->init_type_reply = attr.InitTypeReply; + port_attr->active_width = attr.ActiveWidth; + port_attr->active_speed = attr.ActiveSpeed; + port_attr->phys_state = attr.PhysicalState; + + return 0; +} + +__declspec(dllexport) +int ibv_query_gid(struct ibv_context *context, uint8_t port_num, + int index, union ibv_gid *gid) +{ + return ibvw_wv_errno(context->cmd_if->QueryGid(port_num, index, (WV_GID *) gid)); +} + +__declspec(dllexport) +int ibv_query_pkey(struct ibv_context *context, uint8_t port_num, + int index, uint16_t *pkey) +{ + return ibvw_wv_errno(context->cmd_if->QueryPkey(port_num, (UINT16) index, pkey)); +} + +__declspec(dllexport) +struct ibv_pd *ibv_alloc_pd(struct ibv_context *context) +{ + struct ibv_pd *pd; + HRESULT hr; + + pd = new struct ibv_pd; + if (pd == NULL) { + return NULL; + } + + pd->context = context; + hr = context->cmd_if->AllocateProtectionDomain(&pd->handle); + if (FAILED(hr)) { + delete pd; + return NULL; + } + return pd; +} + +__declspec(dllexport) +int ibv_dealloc_pd(struct ibv_pd *pd) +{ + pd->handle->Release(); + delete pd; + return 0; +} + +__declspec(dllexport) +struct ibv_mr *ibv_reg_mr(struct ibv_pd *pd, void *addr, + size_t length, int access) +{ + struct ibv_mr *mr; + HRESULT hr; + + mr = new struct ibv_mr; + if (mr == NULL) { + return NULL; + } + + mr->context = pd->context; + mr->pd = pd; + mr->addr = addr; + mr->length = length; + hr = pd->handle->RegisterMemory(addr, length, access, NULL, + (WV_MEMORY_KEYS *) &mr->lkey); + if (FAILED(hr)) { + delete mr; + return NULL; + } + mr->rkey = ntohl(mr->rkey); + return mr; +} + +__declspec(dllexport) +int ibv_dereg_mr(struct ibv_mr *mr) +{ + HRESULT hr; + + hr = mr->pd->handle->DeregisterMemory(mr->lkey, NULL); + if (SUCCEEDED(hr)) { + delete mr; + } + return ibvw_wv_errno(hr); +} + +__declspec(dllexport) +struct ibv_comp_channel *ibv_create_comp_channel(struct ibv_context *context) +{ + struct ibv_comp_channel *channel; + + channel = new struct ibv_comp_channel; + if (channel == NULL) { + return NULL; + } + + CompChannelInit(&comp_mgr, &channel->comp_channel, INFINITE); + channel->context = context; + return channel; +} + +__declspec(dllexport) +int ibv_destroy_comp_channel(struct ibv_comp_channel *channel) +{ + CompChannelCleanup(&channel->comp_channel); + delete channel; + return 0; +} + +__declspec(dllexport) +struct ibv_cq *ibv_create_cq(struct ibv_context *context, int cqe, void *cq_context, + struct ibv_comp_channel *channel, int comp_vector) +{ + struct ibv_cq *cq; + HRESULT hr; + SIZE_T entries; + + cq = new struct ibv_cq; + if (cq == NULL) { + return NULL; + } + + cq->context = context; + cq->channel = channel; + cq->cq_context = cq_context; + cq->notify_cnt = 0; + cq->ack_cnt = 0; + + entries = cqe; + hr = context->cmd_if->CreateCompletionQueue(&entries, &cq->handle); + if (FAILED(hr)) { + goto err; + } + + if (channel != NULL) { + CompEntryInit(&channel->comp_channel, &cq->comp_entry); + } else { + memset(&cq->comp_entry, 0, sizeof cq->comp_entry); + } + + cq->cqe = (uint32_t) entries; + return cq; + +err: + delete cq; + return NULL; +} + +__declspec(dllexport) +int ibv_resize_cq(struct ibv_cq *cq, int cqe) +{ + HRESULT hr; + SIZE_T entries = cqe; + + hr = cq->handle->Resize(&entries); + if (SUCCEEDED(hr)) { + cq->cqe = (int) entries; + } + return ibvw_wv_errno(hr); +} + +__declspec(dllexport) +int ibv_req_notify_cq(struct ibv_cq *cq, int solicited_only) +{ + HRESULT hr; + + if (InterlockedCompareExchange(&cq->comp_entry.Busy, 1, 0) == 0) { + InterlockedIncrement(&cq->notify_cnt); + hr = cq->handle->Notify(solicited_only ? WvCqSolicited : WvCqNextCompletion, + &cq->comp_entry.Overlap); + if (SUCCEEDED(hr) || hr == WV_IO_PENDING) { + hr = 0; + } else { + InterlockedExchange(&cq->comp_entry.Busy, 0); + InterlockedDecrement(&cq->notify_cnt); + } + } else { + hr = 0; + } + return ibvw_wv_errno(hr); +} + +__declspec(dllexport) +int ibv_poll_cq(struct ibv_cq *cq, int num_entries, struct ibv_wc *wc) +{ + int n; + + num_entries = (int) cq->handle->Poll((WV_COMPLETION *) wc, num_entries); + for (n = 0; n < num_entries; n++) { + wc[n].qp_num = ((ibv_qp *) wc[n].reserved)->qp_num; + wc[n].src_qp = ntohl(wc[n].src_qp); + wc[n].slid = ntohs(wc[n].slid); + } + return num_entries; +} + +__declspec(dllexport) +int ibv_destroy_cq(struct ibv_cq *cq) +{ + cq->handle->CancelOverlappedRequests(); + if (cq->channel != NULL) { + if (CompEntryCancel(&cq->comp_entry)) { + InterlockedIncrement(&cq->ack_cnt); + } + } + + while (cq->ack_cnt < cq->notify_cnt) + Sleep(0); + cq->handle->Release(); + delete cq; + return 0; +} + +__declspec(dllexport) +int ibv_get_cq_event(struct ibv_comp_channel *channel, + struct ibv_cq **cq, void **cq_context) +{ + COMP_ENTRY *entry; + DWORD ret; + + ret = CompChannelPoll(&channel->comp_channel, &entry); + if (!ret) { + *cq = CONTAINING_RECORD(entry, struct ibv_cq, comp_entry); + *cq_context = (*cq)->cq_context; + } + + return ret; +} + +__declspec(dllexport) +void ibv_ack_cq_events(struct ibv_cq *cq, unsigned int nevents) +{ + InterlockedExchangeAdd(&cq->ack_cnt, (LONG) nevents); +} + +__declspec(dllexport) +struct ibv_srq *ibv_create_srq(struct ibv_pd *pd, + struct ibv_srq_init_attr *srq_init_attr) +{ + struct ibv_srq *srq; + HRESULT hr; + + srq = new struct ibv_srq; + if (srq == NULL) { + return NULL; + } + + srq->context = pd->context; + srq->srq_context = srq_init_attr->srq_context; + srq->pd = pd; + + hr = pd->handle->CreateSharedReceiveQueue(srq_init_attr->attr.max_wr, + srq_init_attr->attr.max_sge, + srq_init_attr->attr.srq_limit, + &srq->handle); + if (FAILED(hr)) { + delete srq; + return NULL; + } + + return srq; +} + +__declspec(dllexport) +int ibv_modify_srq(struct ibv_srq *srq, + struct ibv_srq_attr *srq_attr, + int srq_attr_mask) +{ + ibv_srq_attr attr; + + ibv_query_srq(srq, &attr); + if (srq_attr_mask & IBV_SRQ_MAX_WR) { + attr.max_wr = srq_attr->max_wr; + } + if (srq_attr_mask & IBV_SRQ_LIMIT) { + attr.srq_limit = srq_attr->srq_limit; + } + + return ibvw_wv_errno(srq->handle->Modify(attr.max_wr, attr.srq_limit)); +} + +__declspec(dllexport) +int ibv_post_srq_recv(struct ibv_srq *srq, + struct ibv_recv_wr *recv_wr, + struct ibv_recv_wr **bad_recv_wr) +{ + HRESULT hr = 0; + + for (*bad_recv_wr = recv_wr; *bad_recv_wr != NULL && SUCCEEDED(hr); + *bad_recv_wr = (*bad_recv_wr)->next) { + hr = srq->handle->PostReceive((*bad_recv_wr)->wr_id, + (WV_SGE *) (*bad_recv_wr)->sg_list, + (*bad_recv_wr)->num_sge); + } + return ibvw_wv_errno(hr); +} + +__declspec(dllexport) +int ibv_query_srq(struct ibv_srq *srq, struct ibv_srq_attr *srq_attr) +{ + SIZE_T max_wr, max_sge, srq_limit; + HRESULT hr; + + hr = srq->handle->Query(&max_wr, &max_sge, &srq_limit); + if (FAILED(hr)) { + return ibvw_wv_errno(hr); + } + + srq_attr->max_wr = (uint32_t) max_wr; + srq_attr->max_sge = (uint32_t) max_sge; + srq_attr->srq_limit = (uint32_t) srq_limit; + return 0; +} + +__declspec(dllexport) +int ibv_destroy_srq(struct ibv_srq *srq) +{ + srq->handle->Release(); + delete srq; + return 0; +} + +__declspec(dllexport) +struct ibv_qp *ibv_create_qp(struct ibv_pd *pd, + struct ibv_qp_init_attr *qp_init_attr) +{ + WV_QP_CREATE create; + ibv_qp_attr attr; + struct ibv_qp *qp; + HRESULT hr; + + qp = new struct ibv_qp; + if (qp == NULL) { + return NULL; + } + + create.pSendCq = qp_init_attr->send_cq->handle; + create.pReceiveCq = qp_init_attr->recv_cq->handle; + create.pSharedReceiveQueue = (qp_init_attr->srq != NULL) ? + qp_init_attr->srq->handle : NULL; + create.Context = qp; + create.SendDepth = qp_init_attr->cap.max_send_wr; + create.SendSge = qp_init_attr->cap.max_send_sge; + create.ReceiveDepth = qp_init_attr->cap.max_recv_wr; + create.ReceiveSge = qp_init_attr->cap.max_recv_sge; + create.MaxInlineSend = qp_init_attr->cap.max_inline_data; + create.InitiatorDepth = 0; + create.ResponderResources = 0; + create.QpType = (WV_QP_TYPE) qp_init_attr->qp_type; + create.QpFlags = qp_init_attr->sq_sig_all ? WV_QP_SIGNAL_SENDS : 0; + + if (qp_init_attr->qp_type == IBV_QPT_UD) { + hr = pd->handle->CreateDatagramQueuePair(&create, &qp->ud_handle); + } else { + hr = pd->handle->CreateConnectQueuePair(&create, &qp->conn_handle); + } + if (FAILED(hr)) { + goto err; + } + + if (qp_init_attr->qp_type == IBV_QPT_UD) { + qp->ud_handle->QueryInterface(IID_IWVQueuePair, (LPVOID *) &qp->handle); + } else { + qp->conn_handle->QueryInterface(IID_IWVQueuePair, (LPVOID *) &qp->handle); + } + + qp->context = pd->context; + qp->qp_context = qp_init_attr->qp_context; + qp->pd = pd; + qp->send_cq = qp_init_attr->send_cq; + qp->recv_cq = qp_init_attr->recv_cq; + qp->srq = qp_init_attr->srq; + qp->state = IBV_QPS_RESET; + /* qp_num set by ibv_query_qp */ + qp->qp_type = qp_init_attr->qp_type; + + hr = ibv_query_qp(qp, &attr, 0xFFFFFFFF, qp_init_attr); + if (FAILED(hr)) { + goto err; + } + + return qp; + +err: + delete qp; + return NULL; +} + +__declspec(dllexport) +int ibv_query_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr, + int attr_mask, + struct ibv_qp_init_attr *init_attr) +{ + WV_QP_ATTRIBUTES wv_attr; + HRESULT hr; + + hr = qp->handle->Query(&wv_attr); + if (FAILED(hr)) { + return ibvw_wv_errno(hr); + } + + /* ibv_qp exposes qp_num. Save qp_num from query. */ + qp->qp_num = ntohl(wv_attr.Qpn); + + init_attr->qp_context = qp->context; + init_attr->send_cq = qp->send_cq; + init_attr->recv_cq = qp->recv_cq; + init_attr->srq = qp->srq; + init_attr->cap.max_send_wr = (uint32_t) wv_attr.SendDepth; + init_attr->cap.max_recv_wr = (uint32_t) wv_attr.ReceiveDepth; + init_attr->cap.max_send_sge = (uint32_t) wv_attr.SendSge; + init_attr->cap.max_recv_sge = (uint32_t) wv_attr.ReceiveSge; + init_attr->cap.max_inline_data = (uint32_t) wv_attr.MaxInlineSend; + init_attr->qp_type = (enum ibv_qp_type) wv_attr.QpType; + init_attr->sq_sig_all = wv_attr.QpFlags & WV_QP_SIGNAL_SENDS; + + attr->qp_state = (enum ibv_qp_state) wv_attr.QpState; + attr->cur_qp_state = (enum ibv_qp_state) wv_attr.CurrentQpState; + attr->path_mtu = ibv_convert_mtu(wv_attr.PathMtu); + attr->path_mig_state = (enum ibv_mig_state) wv_attr.ApmState; + attr->qkey = ntohl(wv_attr.Qkey); + attr->rq_psn = ntohl(wv_attr.ReceivePsn); + attr->sq_psn = ntohl(wv_attr.SendPsn); + attr->dest_qp_num = ntohl(wv_attr.DestinationQpn); + attr->qp_access_flags = wv_attr.AccessFlags; + attr->cap = init_attr->cap; + ibv_convert_av(qp->context, &attr->ah_attr, &wv_attr.AddressVector); + if (wv_attr.AlternateAddressVector.DLid != 0) { + ibv_convert_av(qp->context, &attr->alt_ah_attr, &wv_attr.AlternateAddressVector); + } + attr->pkey_index = wv_attr.PkeyIndex; + attr->alt_pkey_index = wv_attr.AlternatePkeyIndex; + attr->en_sqd_async_notify = 0; + attr->sq_draining = 0; + attr->max_rd_atomic = (uint8_t) wv_attr.InitiatorDepth; + attr->max_dest_rd_atomic = (uint8_t) wv_attr.ResponderResources; + attr->min_rnr_timer = wv_attr.RnrNakTimeout; + attr->port_num = wv_attr.AddressVector.PortNumber; + attr->timeout = wv_attr.LocalAckTimeout; + attr->retry_cnt = wv_attr.SequenceErrorRetryCount; + attr->rnr_retry = wv_attr.RnrRetryCount; + attr->alt_port_num = wv_attr.AlternateAddressVector.PortNumber; + attr->alt_timeout = wv_attr.AlternateLocalAckTimeout; + + return 0; +} + +__declspec(dllexport) +int ibv_modify_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr, + int attr_mask) +{ + WV_QP_ATTRIBUTES wv_attr; + HRESULT hr; + + wv_attr.SendDepth = attr->cap.max_send_wr; + wv_attr.SendSge = attr->cap.max_send_sge; + wv_attr.ReceiveDepth = attr->cap.max_recv_wr; + wv_attr.ReceiveSge = attr->cap.max_recv_sge; + wv_attr.MaxInlineSend = attr->cap.max_inline_data; + wv_attr.InitiatorDepth = attr->max_rd_atomic; + wv_attr.ResponderResources = attr->max_dest_rd_atomic; + + wv_attr.CurrentQpState = (WV_QP_STATE) attr->cur_qp_state; + wv_attr.QpState = (WV_QP_STATE) attr->qp_state; + wv_attr.ApmState = (WV_APM_STATE) attr->path_mig_state; + wv_attr.DestinationQpn = htonl(attr->dest_qp_num); + wv_attr.Qkey = htonl(attr->qkey); + wv_attr.SendPsn = htonl(attr->sq_psn); + wv_attr.ReceivePsn = htonl(attr->rq_psn); + + wv_attr.AccessFlags = attr->qp_access_flags; + wv_attr.QpFlags = 0; + + ibv_convert_ah_attr(qp->context, &wv_attr.AddressVector, &attr->ah_attr); + wv_attr.AddressVector.PortNumber = attr->port_num; + wv_attr.PathMtu = 0x80 << attr->path_mtu; + wv_attr.PkeyIndex = attr->pkey_index; + wv_attr.LocalAckTimeout = attr->timeout; + + if (attr_mask & IBV_QP_ALT_PATH) { + ibv_convert_ah_attr(qp->context, &wv_attr.AlternateAddressVector, + &attr->alt_ah_attr); + wv_attr.AlternateAddressVector.PortNumber = attr->alt_port_num; + wv_attr.AlternatePathMtu = 0x80 << attr->path_mtu; + wv_attr.AlternatePkeyIndex = attr->alt_pkey_index; + wv_attr.AlternateLocalAckTimeout = attr->alt_timeout; + } + + wv_attr.RnrNakTimeout = attr->min_rnr_timer; + wv_attr.SequenceErrorRetryCount = attr->retry_cnt; + wv_attr.RnrRetryCount = attr->rnr_retry; + + hr = qp->handle->Modify(&wv_attr, attr_mask, NULL); + if (SUCCEEDED(hr) && (attr_mask & IBV_QP_STATE)) { + qp->state = attr->qp_state; + } + + return ibvw_wv_errno(hr); +} + +__declspec(dllexport) +int ibv_post_send(struct ibv_qp *qp, struct ibv_send_wr *wr, + struct ibv_send_wr **bad_wr) +{ + struct ibv_send_wr *cur_wr; + HRESULT hr = 0; + struct ibv_ah *ah; + + if ((qp->qp_type == IBV_QPT_UD) && (wr->next != NULL)) + return ibvw_wv_errno(WV_NOT_SUPPORTED); + + for (cur_wr = wr; cur_wr != NULL; cur_wr = cur_wr->next) { + if (qp->qp_type == IBV_QPT_UD) { + ah = cur_wr->wr.ud.ah; + cur_wr->wr.ud.ah = (struct ibv_ah *) ah->key; + cur_wr->wr.ud.remote_qkey = htonl(cur_wr->wr.ud.remote_qkey); + cur_wr->wr.ud.remote_qpn = htonl(cur_wr->wr.ud.remote_qpn); + } + + if ((cur_wr->opcode & 0x80000000) != 0) { + cur_wr->opcode = (ibv_wr_opcode) (cur_wr->opcode & ~0x80000000); + cur_wr->send_flags = (ibv_send_flags) (cur_wr->send_flags | WV_SEND_IMMEDIATE); + } + + if (cur_wr->opcode != 0) { + cur_wr->wr.rdma.remote_addr = htonll(cur_wr->wr.rdma.remote_addr); + cur_wr->wr.rdma.rkey = htonl(cur_wr->wr.rdma.rkey); + } + } + + hr = qp->handle->PostSend((WV_SEND_REQUEST *) wr, (WV_SEND_REQUEST **) bad_wr); + + for (cur_wr = wr; cur_wr != NULL; cur_wr = cur_wr->next) { + if (cur_wr->opcode != 0) { + cur_wr->wr.rdma.rkey = ntohl(cur_wr->wr.rdma.rkey); + cur_wr->wr.rdma.remote_addr = htonll(cur_wr->wr.rdma.remote_addr); + } + + if ((cur_wr->send_flags & WV_SEND_IMMEDIATE) != 0) { + cur_wr->send_flags = (ibv_send_flags) (cur_wr->send_flags & ~WV_SEND_IMMEDIATE); + cur_wr->opcode = (ibv_wr_opcode) (cur_wr->opcode | 0x80000000); + } + + if (qp->qp_type == IBV_QPT_UD) { + cur_wr->wr.ud.ah = ah; + cur_wr->wr.ud.remote_qkey = ntohl(cur_wr->wr.ud.remote_qkey); + cur_wr->wr.ud.remote_qpn = ntohl(cur_wr->wr.ud.remote_qpn); + } + } + + return ibvw_wv_errno(hr); +} + +__declspec(dllexport) +int ibv_post_recv(struct ibv_qp *qp, struct ibv_recv_wr *wr, + struct ibv_recv_wr **bad_wr) +{ + HRESULT hr = 0; + + for (*bad_wr = wr; *bad_wr != NULL && SUCCEEDED(hr); *bad_wr = (*bad_wr)->next) { + hr = qp->handle->PostReceive((*bad_wr)->wr_id, (WV_SGE *) (*bad_wr)->sg_list, + (*bad_wr)->num_sge); + } + return ibvw_wv_errno(hr); +} + +__declspec(dllexport) +int ibv_destroy_qp(struct ibv_qp *qp) +{ + qp->handle->CancelOverlappedRequests(); + if (qp->qp_type == IBV_QPT_UD) { + qp->ud_handle->Release(); + } else { + qp->conn_handle->Release(); + } + + qp->handle->Release(); + delete qp; + return 0; +} + +__declspec(dllexport) +struct ibv_ah *ibv_create_ah(struct ibv_pd *pd, struct ibv_ah_attr *attr) +{ + WV_ADDRESS_VECTOR av; + struct ibv_ah *ah; + HRESULT hr; + + ah = new struct ibv_ah; + if (ah == NULL) { + return NULL; + } + + ah->context = pd->context; + ah->pd = pd; + ibv_convert_ah_attr(pd->context, &av, attr); + hr = pd->handle->CreateAddressHandle(&av, &ah->handle, &ah->key); + if (FAILED(hr)) { + delete ah; + return NULL; + } + return ah; +} + +__declspec(dllexport) +int ibv_init_ah_from_wc(struct ibv_context *context, uint8_t port_num, + struct ibv_wc *wc, struct ibv_grh *grh, + struct ibv_ah_attr *ah_attr) +{ + uint32_t flow_class; + int ret; + + memset(ah_attr, 0, sizeof *ah_attr); + ah_attr->dlid = wc->slid; + ah_attr->sl = wc->sl; + ah_attr->src_path_bits = wc->dlid_path_bits; + ah_attr->port_num = port_num; + + if (wc->wc_flags & IBV_WC_GRH) { + ah_attr->is_global = 1; + ah_attr->grh.dgid = grh->sgid; + + ret = ibv_find_gid_index(context, port_num, &grh->dgid); + if (ret < 0) { + return ret; + } + + ah_attr->grh.sgid_index = (uint8_t) ret; + flow_class = ntohl(grh->version_tclass_flow); + ah_attr->grh.flow_label = flow_class & 0xFFFFF; + ah_attr->grh.hop_limit = grh->hop_limit; + ah_attr->grh.traffic_class = (flow_class >> 20) & 0xFF; + } + return 0; +} + +__declspec(dllexport) +struct ibv_ah *ibv_create_ah_from_wc(struct ibv_pd *pd, struct ibv_wc *wc, + struct ibv_grh *grh, uint8_t port_num) +{ + struct ibv_ah_attr ah_attr; + int ret; + + ret = ibv_init_ah_from_wc(pd->context, port_num, wc, grh, &ah_attr); + if (ret != 0) { + return NULL; + } + + return ibv_create_ah(pd, &ah_attr); +} + +__declspec(dllexport) +int ibv_destroy_ah(struct ibv_ah *ah) +{ + ah->handle->Release(); + delete ah; + return 0; +} + +__declspec(dllexport) +int ibv_attach_mcast(struct ibv_qp *qp, union ibv_gid *gid, uint16_t lid) +{ + return ibvw_wv_errno(qp->ud_handle->AttachMulticast((WV_GID *) gid, lid, NULL)); +} + +__declspec(dllexport) +int ibv_detach_mcast(struct ibv_qp *qp, union ibv_gid *gid, uint16_t lid) +{ + return ibvw_wv_errno(qp->ud_handle->DetachMulticast((WV_GID *) gid, lid, NULL)); +} + +__declspec(dllexport) +int ibvw_wv_errno(HRESULT hr) +{ + switch (hr) { + case WV_SUCCESS: return 0; + case WV_PENDING: _set_errno(EINPROGRESS); break; + case WV_IO_PENDING: _set_errno(EINPROGRESS); break; + case WV_TIMEOUT: _set_errno(ETIMEDOUT); break; + case WV_BUFFER_OVERFLOW: _set_errno(EOVERFLOW); break; + case WV_DEVICE_BUSY: _set_errno(EBUSY); break; + case WV_ACCESS_VIOLATION: _set_errno(EACCES); break; + case WV_INVALID_HANDLE: _set_errno(EINVAL); break; + case WV_INVALID_PARAMETER: _set_errno(EINVAL); break; + case WV_NO_MEMORY: _set_errno(ENOMEM); break; + case WV_INSUFFICIENT_RESOURCES: _set_errno(ENOSPC); break; + case WV_IO_TIMEOUT: _set_errno(ETIMEDOUT); break; + case WV_NOT_SUPPORTED: _set_errno(ENOSYS); break; + case WV_CANCELLED: _set_errno(ECANCELED); break; + case WV_INVALID_ADDRESS: _set_errno(EADDRNOTAVAIL); break; + case WV_ADDRESS_ALREADY_EXISTS: _set_errno(EADDRINUSE); break; + case WV_CONNECTION_REFUSED: _set_errno(ECONNREFUSED); break; + case WV_CONNECTION_INVALID: _set_errno(ENOTCONN); break; + case WV_CONNECTION_ACTIVE: _set_errno(EISCONN); break; + case WV_HOST_UNREACHABLE: _set_errno(ENETUNREACH); break; + case WV_CONNECTION_ABORTED: _set_errno(ECONNABORTED); break; + case WV_UNKNOWN_ERROR: _set_errno(EIO); break; + } + return -1; +} diff --git a/branches/WOF2-3/ulp/librdmacm/AUTHORS b/branches/WOF2-3/ulp/librdmacm/AUTHORS new file mode 100644 index 00000000..589c93d1 --- /dev/null +++ b/branches/WOF2-3/ulp/librdmacm/AUTHORS @@ -0,0 +1 @@ +Sean Hefty diff --git a/branches/WOF2-3/ulp/librdmacm/COPYING b/branches/WOF2-3/ulp/librdmacm/COPYING new file mode 100644 index 00000000..41367600 --- /dev/null +++ b/branches/WOF2-3/ulp/librdmacm/COPYING @@ -0,0 +1,26 @@ +Copyright (c) 2008 Intel Corporation. All rights reserved. + +This software is available to you under the OpenFabrics.org BSD license +below: + + Redistribution and use in source and binary forms, with or + without modification, are permitted provided that the following + conditions are met: + + - Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + - Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/branches/WOF2-3/ulp/librdmacm/dirs b/branches/WOF2-3/ulp/librdmacm/dirs new file mode 100644 index 00000000..b1051907 --- /dev/null +++ b/branches/WOF2-3/ulp/librdmacm/dirs @@ -0,0 +1,3 @@ +DIRS = \ + src \ + examples diff --git a/branches/WOF2-3/ulp/librdmacm/examples/cmatose/SOURCES b/branches/WOF2-3/ulp/librdmacm/examples/cmatose/SOURCES new file mode 100644 index 00000000..396635f2 --- /dev/null +++ b/branches/WOF2-3/ulp/librdmacm/examples/cmatose/SOURCES @@ -0,0 +1,31 @@ +TARGETNAME = rdma_cmatose +TARGETPATH = ..\..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = PROGRAM + +UMTYPE = console +UMENTRY = main + +USE_MSVCRT = 1 +USE_STL = 1 +USE_NATIVE_EH = 1 +USE_IOSTREAM = 1 + +SOURCES = cmatose.c + +INCLUDES = ..;..\..\include;..\..\..\..\inc;..\..\..\..\inc\user;\ + ..\..\..\libibverbs\include;..\..\..\..\inc\user\linux; + +TARGETLIBS = \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\advapi32.lib \ + $(SDK_LIB_PATH)\user32.lib \ + $(SDK_LIB_PATH)\ole32.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\libibverbs.lib \ + $(TARGETPATH)\*\librdmacm.lib +!else + $(TARGETPATH)\*\libibverbsd.lib \ + $(TARGETPATH)\*\librdmacmd.lib +!endif + diff --git a/branches/WOF2-3/ulp/librdmacm/examples/cmatose/cmatose.c b/branches/WOF2-3/ulp/librdmacm/examples/cmatose/cmatose.c new file mode 100644 index 00000000..e3ce6e6f --- /dev/null +++ b/branches/WOF2-3/ulp/librdmacm/examples/cmatose/cmatose.c @@ -0,0 +1,815 @@ +/* + * Copyright (c) 2005-2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include + +#include "..\..\..\..\etc\user\getopt.c" +#include + +struct cmatest_node { + int id; + struct rdma_cm_id *cma_id; + int connected; + struct ibv_pd *pd; + struct ibv_cq *cq[2]; + struct ibv_mr *mr; + void *mem; + LARGE_INTEGER start_time[4]; + LARGE_INTEGER end_time[4]; +}; + +enum cq_index { + SEND_CQ_INDEX, + RECV_CQ_INDEX +}; + +struct cmatest { + struct rdma_event_channel *channel; + struct cmatest_node *nodes; + int conn_index; + int connects_left; + int disconnects_left; + + struct sockaddr_in dst_in; + struct sockaddr *dst_addr; + struct sockaddr_in src_in; + struct sockaddr *src_addr; +}; + +static struct cmatest test; +static int connections = 1; +static int message_size = 100; +static int message_count = 10; +static uint16_t port = 7471; +static uint8_t set_tos = 0; +static uint8_t tos; +static uint8_t migrate = 0; +static char *dst_addr; +static char *src_addr; +static LARGE_INTEGER start_time[2], end_time[2]; + +static int create_message(struct cmatest_node *node) +{ + if (!message_size) + message_count = 0; + + if (!message_count) + return 0; + + node->mem = malloc(message_size); + if (!node->mem) { + printf("failed message allocation\n"); + return -1; + } + node->mr = ibv_reg_mr(node->pd, node->mem, message_size, + IBV_ACCESS_LOCAL_WRITE); + if (!node->mr) { + printf("failed to reg MR\n"); + goto err; + } + return 0; +err: + free(node->mem); + return -1; +} + +static int init_node(struct cmatest_node *node) +{ + struct ibv_qp_init_attr init_qp_attr; + int cqe, ret; + + node->pd = ibv_alloc_pd(node->cma_id->verbs); + if (!node->pd) { + ret = -1; + printf("cmatose: unable to allocate PD\n"); + goto out; + } + + cqe = message_count ? message_count : 1; + node->cq[SEND_CQ_INDEX] = ibv_create_cq(node->cma_id->verbs, cqe, node, 0, 0); + node->cq[RECV_CQ_INDEX] = ibv_create_cq(node->cma_id->verbs, cqe, node, 0, 0); + if (!node->cq[SEND_CQ_INDEX] || !node->cq[RECV_CQ_INDEX]) { + ret = -1; + printf("cmatose: unable to create CQs\n"); + goto out; + } + + memset(&init_qp_attr, 0, sizeof init_qp_attr); + init_qp_attr.cap.max_send_wr = cqe; + init_qp_attr.cap.max_recv_wr = cqe; + init_qp_attr.cap.max_send_sge = 1; + init_qp_attr.cap.max_recv_sge = 1; + init_qp_attr.qp_context = node; + init_qp_attr.sq_sig_all = 1; + init_qp_attr.qp_type = IBV_QPT_RC; + init_qp_attr.send_cq = node->cq[SEND_CQ_INDEX]; + init_qp_attr.recv_cq = node->cq[RECV_CQ_INDEX]; + ret = rdma_create_qp(node->cma_id, node->pd, &init_qp_attr); + if (ret) { + printf("cmatose: unable to create QP: 0x%x\n", ret); + goto out; + } + + ret = create_message(node); + if (ret) { + printf("cmatose: failed to create messages: 0x%x\n", ret); + goto out; + } +out: + return ret; +} + +static int post_recvs(struct cmatest_node *node) +{ + struct ibv_recv_wr recv_wr, *recv_failure; + struct ibv_sge sge; + int i, ret = 0; + + if (!message_count) + return 0; + + recv_wr.next = NULL; + recv_wr.sg_list = &sge; + recv_wr.num_sge = 1; + recv_wr.wr_id = (uintptr_t) node; + + sge.length = message_size; + sge.lkey = node->mr->lkey; + sge.addr = (uintptr_t) node->mem; + + for (i = 0; i < message_count && !ret; i++ ) { + ret = ibv_post_recv(node->cma_id->qp, &recv_wr, &recv_failure); + if (ret) { + printf("failed to post receives: 0x%x\n", ret); + break; + } + } + return ret; +} + +static int post_sends(struct cmatest_node *node) +{ + struct ibv_send_wr send_wr, *bad_send_wr; + struct ibv_sge sge; + int i, ret = 0; + + if (!node->connected || !message_count) + return 0; + + send_wr.next = NULL; + send_wr.sg_list = &sge; + send_wr.num_sge = 1; + send_wr.opcode = IBV_WR_SEND; + send_wr.send_flags = 0; + send_wr.wr_id = (ULONG_PTR) node; + + sge.length = message_size; + sge.lkey = node->mr->lkey; + sge.addr = (uintptr_t) node->mem; + + for (i = 0; i < message_count && !ret; i++) { + ret = ibv_post_send(node->cma_id->qp, &send_wr, &bad_send_wr); + if (ret) + printf("failed to post sends: 0x%x\n", ret); + } + return ret; +} + +static void connect_error(void) +{ + test.disconnects_left--; + test.connects_left--; +} + +static int addr_handler(struct cmatest_node *node) +{ + int ret; + + QueryPerformanceCounter(&node->end_time[0]); + if (set_tos) { + ret = rdma_set_option(node->cma_id, RDMA_OPTION_ID, + RDMA_OPTION_ID_TOS, &tos, sizeof tos); + if (ret) + printf("cmatose: set TOS option failed: 0x%x\n", ret); + } + + QueryPerformanceCounter(&node->start_time[1]); + ret = rdma_resolve_route(node->cma_id, 2000); + if (ret) { + printf("cmatose: resolve route failed: 0x%x\n", ret); + connect_error(); + } + return ret; +} + +static int route_handler(struct cmatest_node *node) +{ + struct rdma_conn_param conn_param; + int ret; + + QueryPerformanceCounter(&node->end_time[1]); + QueryPerformanceCounter(&node->start_time[2]); + ret = init_node(node); + if (ret) + goto err; + + ret = post_recvs(node); + if (ret) + goto err; + QueryPerformanceCounter(&node->end_time[2]); + + memset(&conn_param, 0, sizeof conn_param); + conn_param.responder_resources = 1; + conn_param.initiator_depth = 1; + conn_param.retry_count = 5; + QueryPerformanceCounter(&node->start_time[3]); + ret = rdma_connect(node->cma_id, &conn_param); + if (ret) { + printf("cmatose: failure connecting: 0x%x\n", ret); + goto err; + } + return 0; +err: + connect_error(); + return ret; +} + +static int connect_handler(struct rdma_cm_id *cma_id) +{ + struct cmatest_node *node; + struct rdma_conn_param conn_param; + int ret; + + if (test.conn_index == connections) { + ret = -1; + goto err1; + } + node = &test.nodes[test.conn_index++]; + + node->cma_id = cma_id; + cma_id->context = node; + + QueryPerformanceCounter(&node->start_time[2]); + ret = init_node(node); + if (ret) + goto err2; + + ret = post_recvs(node); + if (ret) + goto err2; + QueryPerformanceCounter(&node->end_time[2]); + + memset(&conn_param, 0, sizeof conn_param); + conn_param.responder_resources = 1; + conn_param.initiator_depth = 1; + QueryPerformanceCounter(&node->start_time[3]); + ret = rdma_accept(node->cma_id, &conn_param); + if (ret) { + printf("cmatose: failure accepting: 0x%x\n", ret); + goto err2; + } + return 0; + +err2: + node->cma_id = NULL; + connect_error(); +err1: + printf("cmatose: failing connection request\n"); + rdma_reject(cma_id, NULL, 0); + return ret; +} + +static int cma_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *event) +{ + int ret = 0; + + switch (event->event) { + case RDMA_CM_EVENT_ADDR_RESOLVED: + ret = addr_handler(cma_id->context); + break; + case RDMA_CM_EVENT_ROUTE_RESOLVED: + ret = route_handler(cma_id->context); + break; + case RDMA_CM_EVENT_CONNECT_REQUEST: + ret = connect_handler(cma_id); + break; + case RDMA_CM_EVENT_ESTABLISHED: + ((struct cmatest_node *) cma_id->context)->connected = 1; + QueryPerformanceCounter(&((struct cmatest_node *) cma_id->context)->end_time[3]); + test.connects_left--; + break; + case RDMA_CM_EVENT_ADDR_ERROR: + case RDMA_CM_EVENT_ROUTE_ERROR: + case RDMA_CM_EVENT_CONNECT_ERROR: + case RDMA_CM_EVENT_UNREACHABLE: + case RDMA_CM_EVENT_REJECTED: + printf("cmatose: event: %s, error: 0x%x\n", + rdma_event_str(event->event), event->status); + connect_error(); + break; + case RDMA_CM_EVENT_DISCONNECTED: + rdma_disconnect(cma_id); + test.disconnects_left--; + break; + case RDMA_CM_EVENT_DEVICE_REMOVAL: + /* Cleanup will occur after test completes. */ + break; + default: + break; + } + return ret; +} + +static void destroy_node(struct cmatest_node *node) +{ + if (!node->cma_id) + return; + + if (node->cma_id->qp) + rdma_destroy_qp(node->cma_id); + + if (node->cq[SEND_CQ_INDEX]) + ibv_destroy_cq(node->cq[SEND_CQ_INDEX]); + + if (node->cq[RECV_CQ_INDEX]) + ibv_destroy_cq(node->cq[RECV_CQ_INDEX]); + + if (node->mem) { + ibv_dereg_mr(node->mr); + free(node->mem); + } + + if (node->pd) + ibv_dealloc_pd(node->pd); + + /* Destroy the RDMA ID after all device resources */ + rdma_destroy_id(node->cma_id); +} + +static int alloc_nodes(void) +{ + int ret, i; + + test.nodes = malloc(sizeof *test.nodes * connections); + if (!test.nodes) { + printf("cmatose: unable to allocate memory for test nodes\n"); + return -1; + } + memset(test.nodes, 0, sizeof *test.nodes * connections); + + for (i = 0; i < connections; i++) { + test.nodes[i].id = i; + if (dst_addr) { + ret = rdma_create_id(test.channel, + &test.nodes[i].cma_id, + &test.nodes[i], RDMA_PS_TCP); + if (ret) + goto err; + } + } + return 0; +err: + while (--i >= 0) + rdma_destroy_id(test.nodes[i].cma_id); + free(test.nodes); + return ret; +} + +static void destroy_nodes(void) +{ + int i; + + for (i = 0; i < connections; i++) + destroy_node(&test.nodes[i]); + free(test.nodes); +} + +static int poll_cqs(enum CQ_INDEX index) +{ + struct ibv_wc wc[8]; + int done, i, ret; + + for (i = 0; i < connections; i++) { + if (!test.nodes[i].connected) + continue; + + for (done = 0; done < message_count; done += ret) { + ret = ibv_poll_cq(test.nodes[i].cq[index], 8, wc); + if (ret < 0) { + printf("cmatose: failed polling CQ: 0x%x\n", ret); + return ret; + } + Sleep(0); + } + } + return 0; +} + +static int connect_events(void) +{ + struct rdma_cm_event *event; + int err = 0, ret = 0; + + while (test.connects_left && !err) { + err = rdma_get_cm_event(test.channel, &event); + if (!err) { + if (!dst_addr && !start_time[0].QuadPart) + QueryPerformanceCounter(&start_time[0]); + + cma_handler(event->id, event); + rdma_ack_cm_event(event); + } else { + printf("cmatose:rdma_get_cm_event connect events error 0x%x\n", err); + ret = err; + } + } + QueryPerformanceCounter(&end_time[0]); + + return ret; +} + +static int disconnect_events(void) +{ + struct rdma_cm_event *event; + int err = 0, ret = 0; + + while (test.disconnects_left && !err) { + err = rdma_get_cm_event(test.channel, &event); + if (!err) { + if (dst_addr && !start_time[1].QuadPart) + QueryPerformanceCounter(&start_time[1]); + + cma_handler(event->id, event); + rdma_ack_cm_event(event); + } else { + printf("cmatose: rdma_get_cm_event disconnect events error 0x%x\n", err); + ret = err; + } + } + QueryPerformanceCounter(&end_time[1]); + + return ret; +} + +static int migrate_channel(struct rdma_cm_id *listen_id) +{ + struct rdma_event_channel *channel; + int i, ret; + + printf("migrating to new event channel\n"); + + channel = rdma_create_event_channel(); + if (!channel) { + printf("cmatose: failed to create event channel\n"); + return -1; + } + + ret = 0; + if (listen_id) + ret = rdma_migrate_id(listen_id, channel); + + for (i = 0; i < connections && !ret; i++) + ret = rdma_migrate_id(test.nodes[i].cma_id, channel); + + if (!ret) { + rdma_destroy_event_channel(test.channel); + test.channel = channel; + } else + printf("cmatose: failure migrating to channel: 0x%x\n", ret); + + return ret; +} + +static int get_addr(char *dst, struct sockaddr_in *addr) +{ + struct addrinfo *res; + int ret; + + ret = getaddrinfo(dst, NULL, NULL, &res); + if (ret) { + printf("getaddrinfo failed - invalid hostname or IP address\n"); + return ret; + } + + if (res->ai_family != PF_INET) { + ret = -1; + goto out; + } + + *addr = *(struct sockaddr_in *) res->ai_addr; +out: + freeaddrinfo(res); + return ret; +} + +static int run_server(void) +{ + struct rdma_cm_id *listen_id; + int i, ret; + + printf("cmatose: starting server\n"); + ret = rdma_create_id(test.channel, &listen_id, &test, RDMA_PS_TCP); + if (ret) { + printf("cmatose: listen request failed\n"); + return ret; + } + + if (src_addr) { + ret = get_addr(src_addr, &test.src_in); + if (ret) + goto out; + } else + test.src_in.sin_family = PF_INET; + + test.src_in.sin_port = port; + ret = rdma_bind_addr(listen_id, test.src_addr); + if (ret) { + printf("cmatose: bind address failed: 0x%x\n", ret); + goto out; + } + + ret = rdma_listen(listen_id, connections); + if (ret) { + printf("cmatose: failure trying to listen: 0x%x\n", ret); + goto out; + } + + ret = connect_events(); + if (ret) + goto out; + + if (message_count) { + printf("initiating data transfers\n"); + for (i = 0; i < connections; i++) { + ret = post_sends(&test.nodes[i]); + if (ret) + goto out; + } + + printf("completing sends\n"); + ret = poll_cqs(SEND_CQ_INDEX); + if (ret) + goto out; + + printf("receiving data transfers\n"); + ret = poll_cqs(RECV_CQ_INDEX); + if (ret) + goto out; + printf("data transfers complete\n"); + + } + + if (migrate) { + ret = migrate_channel(listen_id); + if (ret) + goto out; + } + + printf("cmatose: disconnecting\n"); + QueryPerformanceCounter(&start_time[1]); + + for (i = 0; i < connections; i++) { + if (!test.nodes[i].connected) + continue; + + test.nodes[i].connected = 0; + rdma_disconnect(test.nodes[i].cma_id); + } + + ret = disconnect_events(); + + printf("disconnected\n"); + +out: + rdma_destroy_id(listen_id); + return ret; +} + +static int run_client(void) +{ + int i, ret, ret2; + + printf("cmatose: starting client\n"); + if (src_addr) { + ret = get_addr(src_addr, &test.src_in); + if (ret) + return ret; + } + + ret = get_addr(dst_addr, &test.dst_in); + if (ret) + return ret; + + test.dst_in.sin_port = port; + + printf("cmatose: connecting\n"); + QueryPerformanceCounter(&start_time[0]); + + for (i = 0; i < connections; i++) { + QueryPerformanceCounter(&test.nodes[i].start_time[0]); + ret = rdma_resolve_addr(test.nodes[i].cma_id, + src_addr ? test.src_addr : NULL, + test.dst_addr, 2000); + if (ret) { + printf("cmatose: failure getting addr: 0x%x\n", ret); + connect_error(); + return ret; + } + } + + ret = connect_events(); + if (ret) + goto disc; + + if (message_count) { + printf("receiving data transfers\n"); + ret = poll_cqs(RECV_CQ_INDEX); + if (ret) + goto disc; + + printf("sending replies\n"); + for (i = 0; i < connections; i++) { + ret = post_sends(&test.nodes[i]); + if (ret) + goto disc; + } + + printf("data transfers complete\n"); + } + + ret = 0; + + if (migrate) { + ret = migrate_channel(NULL); + if (ret) + goto out; + } + +disc: + ret2 = disconnect_events(); + if (ret2) + ret = ret2; +out: + return ret; +} + +static UINT64 sum_counters(int index) +{ + UINT64 total = 0; + int i; + + for (i = 0; i < connections; i++) { + total += (test.nodes[i].end_time[index].QuadPart - + test.nodes[i].start_time[index].QuadPart); + } + return total; +} + +static void show_perf(void) +{ + LARGE_INTEGER freq; + double run_time; + int i; + + QueryPerformanceFrequency(&freq); + run_time = (double) (end_time[0].QuadPart - start_time[0].QuadPart) / + (double) freq.QuadPart; + printf("%d connection%s in %.4f seconds (%.0f connections/second)\n", + connections, connections == 1 ? "" : "s", run_time, + (double) connections / run_time); + + run_time = (double) (end_time[1].QuadPart - start_time[1].QuadPart) / + (double) freq.QuadPart; + printf("%d disconnect%s in %.4f seconds (%.0f disconnects/second)\n", + connections, connections == 1 ? "" : "s", run_time, + (double) connections / run_time); + + if (dst_addr) { + run_time = (double) sum_counters(0) / (double) freq.QuadPart; + printf("sum resolve address times %.4f seconds (%.2f ms average)\n", + run_time, run_time * 1000 / (double) connections); + + run_time = (double) sum_counters(1) / (double) freq.QuadPart; + printf("sum resolve route times %.4f seconds (%.2f ms average)\n", + run_time, run_time * 1000 / (double) connections); + } + + run_time = (double) sum_counters(2) / (double) freq.QuadPart; + printf("sum initialize node times %.4f seconds (%.2f ms average)\n", + run_time, run_time * 1000 / (double) connections); + + run_time = (double) sum_counters(3) / (double) freq.QuadPart; + printf("sum connect/accept times %.4f seconds (%.2f ms average)\n", + run_time, run_time * 1000 / (double) connections); + + if (dst_addr) { + run_time = (double) (sum_counters(3) - sum_counters(2)) / (double) freq.QuadPart; + printf("est. adjusted connect times %.4f seconds (%.2f ms average)\n", + run_time, run_time * 1000 / (double) connections); + } +} + +int __cdecl main(int argc, char **argv) +{ + int op, ret; + + while ((op = getopt(argc, argv, "s:b:c:C:S:t:p:m")) != -1) { + switch (op) { + case 's': + dst_addr = optarg; + break; + case 'b': + src_addr = optarg; + break; + case 'c': + connections = atoi(optarg); + break; + case 'C': + message_count = atoi(optarg); + break; + case 'S': + message_size = atoi(optarg); + break; + case 't': + set_tos = 1; + tos = (uint8_t) atoi(optarg); + break; + case 'p': + port = (uint16_t) atoi(optarg); + break; + case 'm': + migrate = 1; + break; + default: + printf("usage: %s\n", argv[0]); + printf("\t[-s server_address]\n"); + printf("\t[-b bind_address]\n"); + printf("\t[-c connections]\n"); + printf("\t[-C message_count]\n"); + printf("\t[-S message_size]\n"); + printf("\t[-t type_of_service]\n"); + printf("\t[-p port_number]\n"); + printf("\t[-m(igrate)]\n"); + exit(1); + } + } + + test.dst_addr = (struct sockaddr *) &test.dst_in; + test.src_addr = (struct sockaddr *) &test.src_in; + test.connects_left = connections; + test.disconnects_left = connections; + + test.channel = rdma_create_event_channel(); + if (!test.channel) { + printf("failed to create event channel\n"); + exit(1); + } + + if (alloc_nodes()) + exit(1); + + if (dst_addr) + ret = run_client(); + else + ret = run_server(); + + printf("test complete\n"); + show_perf(); + + destroy_nodes(); + rdma_destroy_event_channel(test.channel); + + printf("return status 0x%x\n", ret); + return ret; +} diff --git a/branches/WOF2-3/ulp/librdmacm/examples/cmatose/makefile b/branches/WOF2-3/ulp/librdmacm/examples/cmatose/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-3/ulp/librdmacm/examples/cmatose/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\..\inc\openib.def diff --git a/branches/WOF2-3/ulp/librdmacm/examples/dirs b/branches/WOF2-3/ulp/librdmacm/examples/dirs new file mode 100644 index 00000000..498dd653 --- /dev/null +++ b/branches/WOF2-3/ulp/librdmacm/examples/dirs @@ -0,0 +1,4 @@ +DIRS = \ + cmatose \ + rdma_server \ + rdma_client diff --git a/branches/WOF2-3/ulp/librdmacm/examples/mckey/mckey.c b/branches/WOF2-3/ulp/librdmacm/examples/mckey/mckey.c new file mode 100644 index 00000000..a858ad6b --- /dev/null +++ b/branches/WOF2-3/ulp/librdmacm/examples/mckey/mckey.c @@ -0,0 +1,579 @@ +/* + * Copyright (c) 2005-2007 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +struct cmatest_node { + int id; + struct rdma_cm_id *cma_id; + int connected; + struct ibv_pd *pd; + struct ibv_cq *cq; + struct ibv_mr *mr; + struct ibv_ah *ah; + uint32_t remote_qpn; + uint32_t remote_qkey; + void *mem; +}; + +struct cmatest { + struct rdma_event_channel *channel; + struct cmatest_node *nodes; + int conn_index; + int connects_left; + + struct sockaddr_in6 dst_in; + struct sockaddr *dst_addr; + struct sockaddr_in6 src_in; + struct sockaddr *src_addr; +}; + +static struct cmatest test; +static int connections = 1; +static int message_size = 100; +static int message_count = 10; +static int is_sender; +static int unmapped_addr; +static char *dst_addr; +static char *src_addr; +static enum rdma_port_space port_space = RDMA_PS_UDP; + +static int create_message(struct cmatest_node *node) +{ + if (!message_size) + message_count = 0; + + if (!message_count) + return 0; + + node->mem = malloc(message_size + sizeof(struct ibv_grh)); + if (!node->mem) { + printf("failed message allocation\n"); + return -1; + } + node->mr = ibv_reg_mr(node->pd, node->mem, + message_size + sizeof(struct ibv_grh), + IBV_ACCESS_LOCAL_WRITE); + if (!node->mr) { + printf("failed to reg MR\n"); + goto err; + } + return 0; +err: + free(node->mem); + return -1; +} + +static int verify_test_params(struct cmatest_node *node) +{ + struct ibv_port_attr port_attr; + int ret; + + ret = ibv_query_port(node->cma_id->verbs, node->cma_id->port_num, + &port_attr); + if (ret) + return ret; + + if (message_count && message_size > (1 << (port_attr.active_mtu + 7))) { + printf("mckey: message_size %d is larger than active mtu %d\n", + message_size, 1 << (port_attr.active_mtu + 7)); + return -EINVAL; + } + + return 0; +} + +static int init_node(struct cmatest_node *node) +{ + struct ibv_qp_init_attr init_qp_attr; + int cqe, ret; + + node->pd = ibv_alloc_pd(node->cma_id->verbs); + if (!node->pd) { + ret = -ENOMEM; + printf("mckey: unable to allocate PD\n"); + goto out; + } + + cqe = message_count ? message_count * 2 : 2; + node->cq = ibv_create_cq(node->cma_id->verbs, cqe, node, 0, 0); + if (!node->cq) { + ret = -ENOMEM; + printf("mckey: unable to create CQ\n"); + goto out; + } + + memset(&init_qp_attr, 0, sizeof init_qp_attr); + init_qp_attr.cap.max_send_wr = message_count ? message_count : 1; + init_qp_attr.cap.max_recv_wr = message_count ? message_count : 1; + init_qp_attr.cap.max_send_sge = 1; + init_qp_attr.cap.max_recv_sge = 1; + init_qp_attr.qp_context = node; + init_qp_attr.sq_sig_all = 0; + init_qp_attr.qp_type = IBV_QPT_UD; + init_qp_attr.send_cq = node->cq; + init_qp_attr.recv_cq = node->cq; + ret = rdma_create_qp(node->cma_id, node->pd, &init_qp_attr); + if (ret) { + printf("mckey: unable to create QP: %d\n", ret); + goto out; + } + + ret = create_message(node); + if (ret) { + printf("mckey: failed to create messages: %d\n", ret); + goto out; + } +out: + return ret; +} + +static int post_recvs(struct cmatest_node *node) +{ + struct ibv_recv_wr recv_wr, *recv_failure; + struct ibv_sge sge; + int i, ret = 0; + + if (!message_count) + return 0; + + recv_wr.next = NULL; + recv_wr.sg_list = &sge; + recv_wr.num_sge = 1; + recv_wr.wr_id = (uintptr_t) node; + + sge.length = message_size + sizeof(struct ibv_grh); + sge.lkey = node->mr->lkey; + sge.addr = (uintptr_t) node->mem; + + for (i = 0; i < message_count && !ret; i++ ) { + ret = ibv_post_recv(node->cma_id->qp, &recv_wr, &recv_failure); + if (ret) { + printf("failed to post receives: %d\n", ret); + break; + } + } + return ret; +} + +static int post_sends(struct cmatest_node *node, int signal_flag) +{ + struct ibv_send_wr send_wr, *bad_send_wr; + struct ibv_sge sge; + int i, ret = 0; + + if (!node->connected || !message_count) + return 0; + + send_wr.next = NULL; + send_wr.sg_list = &sge; + send_wr.num_sge = 1; + send_wr.opcode = IBV_WR_SEND_WITH_IMM; + send_wr.send_flags = signal_flag; + send_wr.wr_id = (unsigned long)node; + send_wr.imm_data = htonl(node->cma_id->qp->qp_num); + + send_wr.wr.ud.ah = node->ah; + send_wr.wr.ud.remote_qpn = node->remote_qpn; + send_wr.wr.ud.remote_qkey = node->remote_qkey; + + sge.length = message_size; + sge.lkey = node->mr->lkey; + sge.addr = (uintptr_t) node->mem; + + for (i = 0; i < message_count && !ret; i++) { + ret = ibv_post_send(node->cma_id->qp, &send_wr, &bad_send_wr); + if (ret) + printf("failed to post sends: %d\n", ret); + } + return ret; +} + +static void connect_error(void) +{ + test.connects_left--; +} + +static int addr_handler(struct cmatest_node *node) +{ + int ret; + + ret = verify_test_params(node); + if (ret) + goto err; + + ret = init_node(node); + if (ret) + goto err; + + if (!is_sender) { + ret = post_recvs(node); + if (ret) + goto err; + } + + ret = rdma_join_multicast(node->cma_id, test.dst_addr, node); + if (ret) { + printf("mckey: failure joining: %d\n", ret); + goto err; + } + return 0; +err: + connect_error(); + return ret; +} + +static int join_handler(struct cmatest_node *node, + struct rdma_ud_param *param) +{ + char buf[40]; + + inet_ntop(AF_INET6, param->ah_attr.grh.dgid.raw, buf, 40); + printf("mckey: joined dgid: %s\n", buf); + + node->remote_qpn = param->qp_num; + node->remote_qkey = param->qkey; + node->ah = ibv_create_ah(node->pd, ¶m->ah_attr); + if (!node->ah) { + printf("mckey: failure creating address handle\n"); + goto err; + } + + node->connected = 1; + test.connects_left--; + return 0; +err: + connect_error(); + return -1; +} + +static int cma_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *event) +{ + int ret = 0; + + switch (event->event) { + case RDMA_CM_EVENT_ADDR_RESOLVED: + ret = addr_handler(cma_id->context); + break; + case RDMA_CM_EVENT_MULTICAST_JOIN: + ret = join_handler(cma_id->context, &event->param.ud); + break; + case RDMA_CM_EVENT_ADDR_ERROR: + case RDMA_CM_EVENT_ROUTE_ERROR: + case RDMA_CM_EVENT_MULTICAST_ERROR: + printf("mckey: event: %s, error: %d\n", + rdma_event_str(event->event), event->status); + connect_error(); + ret = event->status; + break; + case RDMA_CM_EVENT_DEVICE_REMOVAL: + /* Cleanup will occur after test completes. */ + break; + default: + break; + } + return ret; +} + +static void destroy_node(struct cmatest_node *node) +{ + if (!node->cma_id) + return; + + if (node->ah) + ibv_destroy_ah(node->ah); + + if (node->cma_id->qp) + rdma_destroy_qp(node->cma_id); + + if (node->cq) + ibv_destroy_cq(node->cq); + + if (node->mem) { + ibv_dereg_mr(node->mr); + free(node->mem); + } + + if (node->pd) + ibv_dealloc_pd(node->pd); + + /* Destroy the RDMA ID after all device resources */ + rdma_destroy_id(node->cma_id); +} + +static int alloc_nodes(void) +{ + int ret, i; + + test.nodes = malloc(sizeof *test.nodes * connections); + if (!test.nodes) { + printf("mckey: unable to allocate memory for test nodes\n"); + return -ENOMEM; + } + memset(test.nodes, 0, sizeof *test.nodes * connections); + + for (i = 0; i < connections; i++) { + test.nodes[i].id = i; + ret = rdma_create_id(test.channel, &test.nodes[i].cma_id, + &test.nodes[i], port_space); + if (ret) + goto err; + } + return 0; +err: + while (--i >= 0) + rdma_destroy_id(test.nodes[i].cma_id); + free(test.nodes); + return ret; +} + +static void destroy_nodes(void) +{ + int i; + + for (i = 0; i < connections; i++) + destroy_node(&test.nodes[i]); + free(test.nodes); +} + +static int poll_cqs(void) +{ + struct ibv_wc wc[8]; + int done, i, ret; + + for (i = 0; i < connections; i++) { + if (!test.nodes[i].connected) + continue; + + for (done = 0; done < message_count; done += ret) { + ret = ibv_poll_cq(test.nodes[i].cq, 8, wc); + if (ret < 0) { + printf("mckey: failed polling CQ: %d\n", ret); + return ret; + } + } + } + return 0; +} + +static int connect_events(void) +{ + struct rdma_cm_event *event; + int ret = 0; + + while (test.connects_left && !ret) { + ret = rdma_get_cm_event(test.channel, &event); + if (!ret) { + ret = cma_handler(event->id, event); + rdma_ack_cm_event(event); + } + } + return ret; +} + +static int get_addr(char *dst, struct sockaddr *addr) +{ + struct addrinfo *res; + int ret; + + ret = getaddrinfo(dst, NULL, NULL, &res); + if (ret) { + printf("getaddrinfo failed - invalid hostname or IP address\n"); + return ret; + } + + memcpy(addr, res->ai_addr, res->ai_addrlen); + freeaddrinfo(res); + return ret; +} + +static int run(void) +{ + int i, ret; + + printf("mckey: starting %s\n", is_sender ? "client" : "server"); + if (src_addr) { + ret = get_addr(src_addr, (struct sockaddr *) &test.src_in); + if (ret) + return ret; + } + + ret = get_addr(dst_addr, (struct sockaddr *) &test.dst_in); + if (ret) + return ret; + + printf("mckey: joining\n"); + for (i = 0; i < connections; i++) { + if (src_addr) { + ret = rdma_bind_addr(test.nodes[i].cma_id, + test.src_addr); + if (ret) { + printf("mckey: addr bind failure: %d\n", ret); + connect_error(); + return ret; + } + } + + if (unmapped_addr) + ret = addr_handler(&test.nodes[i]); + else + ret = rdma_resolve_addr(test.nodes[i].cma_id, + test.src_addr, test.dst_addr, + 2000); + if (ret) { + printf("mckey: resolve addr failure: %d\n", ret); + connect_error(); + return ret; + } + } + + ret = connect_events(); + if (ret) + goto out; + + /* + * Pause to give SM chance to configure switches. We don't want to + * handle reliability issue in this simple test program. + */ + sleep(3); + + if (message_count) { + if (is_sender) { + printf("initiating data transfers\n"); + for (i = 0; i < connections; i++) { + ret = post_sends(&test.nodes[i], 0); + if (ret) + goto out; + } + } else { + printf("receiving data transfers\n"); + ret = poll_cqs(); + if (ret) + goto out; + } + printf("data transfers complete\n"); + } +out: + for (i = 0; i < connections; i++) { + ret = rdma_leave_multicast(test.nodes[i].cma_id, + test.dst_addr); + if (ret) + printf("mckey: failure leaving: %d\n", ret); + } + return ret; +} + +int main(int argc, char **argv) +{ + int op, ret; + + + while ((op = getopt(argc, argv, "m:M:sb:c:C:S:p:")) != -1) { + switch (op) { + case 'm': + dst_addr = optarg; + break; + case 'M': + unmapped_addr = 1; + dst_addr = optarg; + break; + case 's': + is_sender = 1; + break; + case 'b': + src_addr = optarg; + test.src_addr = (struct sockaddr *) &test.src_in; + break; + case 'c': + connections = atoi(optarg); + break; + case 'C': + message_count = atoi(optarg); + break; + case 'S': + message_size = atoi(optarg); + break; + case 'p': + port_space = strtol(optarg, NULL, 0); + break; + default: + printf("usage: %s\n", argv[0]); + printf("\t-m multicast_address\n"); + printf("\t[-M unmapped_multicast_address]\n" + "\t replaces -m and requires -b\n"); + printf("\t[-s(ender)]\n"); + printf("\t[-b bind_address]\n"); + printf("\t[-c connections]\n"); + printf("\t[-C message_count]\n"); + printf("\t[-S message_size]\n"); + printf("\t[-p port_space - %#x for UDP (default), " + "%#x for IPOIB]\n", RDMA_PS_UDP, RDMA_PS_IPOIB); + exit(1); + } + } + + test.dst_addr = (struct sockaddr *) &test.dst_in; + test.connects_left = connections; + + test.channel = rdma_create_event_channel(); + if (!test.channel) { + printf("failed to create event channel\n"); + exit(1); + } + + if (alloc_nodes()) + exit(1); + + ret = run(); + + printf("test complete\n"); + destroy_nodes(); + rdma_destroy_event_channel(test.channel); + + printf("return status %d\n", ret); + return ret; +} diff --git a/branches/WOF2-3/ulp/librdmacm/examples/rdma_client/SOURCES b/branches/WOF2-3/ulp/librdmacm/examples/rdma_client/SOURCES new file mode 100644 index 00000000..3073041a --- /dev/null +++ b/branches/WOF2-3/ulp/librdmacm/examples/rdma_client/SOURCES @@ -0,0 +1,28 @@ +TARGETNAME = rdma_client +TARGETPATH = ..\..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = PROGRAM + +UMTYPE = console +UMENTRY = main + +USE_MSVCRT = 1 + +SOURCES = rdma_client.c + +INCLUDES = ..;..\..\include;..\..\..\..\inc;..\..\..\..\inc\user;\ + ..\..\..\libibverbs\include;..\..\..\..\inc\user\linux; + +TARGETLIBS = \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\advapi32.lib \ + $(SDK_LIB_PATH)\user32.lib \ + $(SDK_LIB_PATH)\ole32.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\libibverbs.lib \ + $(TARGETPATH)\*\librdmacm.lib +!else + $(TARGETPATH)\*\libibverbsd.lib \ + $(TARGETPATH)\*\librdmacmd.lib +!endif + diff --git a/branches/WOF2-3/ulp/librdmacm/examples/rdma_client/makefile b/branches/WOF2-3/ulp/librdmacm/examples/rdma_client/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-3/ulp/librdmacm/examples/rdma_client/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\..\inc\openib.def diff --git a/branches/WOF2-3/ulp/librdmacm/examples/rdma_client/rdma_client.c b/branches/WOF2-3/ulp/librdmacm/examples/rdma_client/rdma_client.c new file mode 100644 index 00000000..e0a394e6 --- /dev/null +++ b/branches/WOF2-3/ulp/librdmacm/examples/rdma_client/rdma_client.c @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2010 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include + +#include "..\..\..\..\etc\user\getopt.c" +#include +#include + +static char *server = "127.0.0.1"; +static char *port = "7471"; + +struct rdma_cm_id *id; +struct ibv_mr *mr; +uint8_t send_msg[16]; +uint8_t recv_msg[16]; + +static int run(void) +{ + struct rdma_addrinfo hints, *res; + struct ibv_qp_init_attr attr; + struct ibv_wc wc; + int ret; + + memset(&hints, 0, sizeof hints); + hints.ai_port_space = RDMA_PS_TCP; + ret = rdma_getaddrinfo(server, port, &hints, &res); + if (ret) { + printf("rdma_getaddrinfo %d\n", errno); + return ret; + } + + memset(&attr, 0, sizeof attr); + attr.cap.max_send_wr = attr.cap.max_recv_wr = 1; + attr.cap.max_send_sge = attr.cap.max_recv_sge = 1; + attr.cap.max_inline_data = 16; + attr.qp_context = id; + attr.sq_sig_all = 1; + ret = rdma_create_ep(&id, res, NULL, &attr); + rdma_freeaddrinfo(res); + if (ret) { + printf("rdma_create_ep %d\n", errno); + return ret; + } + + mr = rdma_reg_msgs(id, recv_msg, 16); + if (!mr) { + printf("rdma_reg_msgs %d\n", errno); + return ret; + } + + ret = rdma_post_recv(id, NULL, recv_msg, 16, mr); + if (ret) { + printf("rdma_post_recv %d\n", errno); + return ret; + } + + ret = rdma_connect(id, NULL); + if (ret) { + printf("rdma_connect %d\n", errno); + return ret; + } + + ret = rdma_post_send(id, NULL, send_msg, 16, NULL, IBV_SEND_INLINE); + if (ret) { + printf("rdma_post_send %d\n", errno); + return ret; + } + + ret = rdma_get_recv_comp(id, &wc); + if (ret <= 0) { + printf("rdma_get_recv_comp %d\n", ret); + return ret; + } + + rdma_disconnect(id); + rdma_dereg_mr(mr); + rdma_destroy_ep(id); + return 0; +} + +int __cdecl main(int argc, char **argv) +{ + int op, ret; + + while ((op = getopt(argc, argv, "s:p:")) != -1) { + switch (op) { + case 's': + server = optarg; + break; + case 'p': + port = optarg; + break; + default: + printf("usage: %s\n", argv[0]); + printf("\t[-s server_address]\n"); + printf("\t[-p port_number]\n"); + exit(1); + } + } + + printf("rdma_client: start\n"); + ret = run(); + printf("rdma_client: end %d\n", ret); + return ret; +} diff --git a/branches/WOF2-3/ulp/librdmacm/examples/rdma_server/SOURCES b/branches/WOF2-3/ulp/librdmacm/examples/rdma_server/SOURCES new file mode 100644 index 00000000..70396d00 --- /dev/null +++ b/branches/WOF2-3/ulp/librdmacm/examples/rdma_server/SOURCES @@ -0,0 +1,28 @@ +TARGETNAME = rdma_server +TARGETPATH = ..\..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = PROGRAM + +UMTYPE = console +UMENTRY = main + +USE_MSVCRT = 1 + +SOURCES = rdma_server.c + +INCLUDES = ..;..\..\include;..\..\..\..\inc;..\..\..\..\inc\user;\ + ..\..\..\libibverbs\include;..\..\..\..\inc\user\linux; + +TARGETLIBS = \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\advapi32.lib \ + $(SDK_LIB_PATH)\user32.lib \ + $(SDK_LIB_PATH)\ole32.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\libibverbs.lib \ + $(TARGETPATH)\*\librdmacm.lib +!else + $(TARGETPATH)\*\libibverbsd.lib \ + $(TARGETPATH)\*\librdmacmd.lib +!endif + diff --git a/branches/WOF2-3/ulp/librdmacm/examples/rdma_server/makefile b/branches/WOF2-3/ulp/librdmacm/examples/rdma_server/makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-3/ulp/librdmacm/examples/rdma_server/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\..\inc\openib.def diff --git a/branches/WOF2-3/ulp/librdmacm/examples/rdma_server/rdma_server.c b/branches/WOF2-3/ulp/librdmacm/examples/rdma_server/rdma_server.c new file mode 100644 index 00000000..8be15775 --- /dev/null +++ b/branches/WOF2-3/ulp/librdmacm/examples/rdma_server/rdma_server.c @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2005-2010 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include + +#include "..\..\..\..\etc\user\getopt.c" +#include +#include + +static char *port = "7471"; + +struct rdma_cm_id *listen_id, *id; +struct ibv_mr *mr; +uint8_t send_msg[16]; +uint8_t recv_msg[16]; + +static int run(void) +{ + struct rdma_addrinfo hints, *res; + struct ibv_qp_init_attr attr; + struct ibv_wc wc; + int ret; + + memset(&hints, 0, sizeof hints); + hints.ai_flags = RAI_PASSIVE; + hints.ai_port_space = RDMA_PS_TCP; + ret = rdma_getaddrinfo(NULL, port, &hints, &res); + if (ret) { + printf("rdma_getaddrinfo %d\n", errno); + return ret; + } + + memset(&attr, 0, sizeof attr); + attr.cap.max_send_wr = attr.cap.max_recv_wr = 1; + attr.cap.max_send_sge = attr.cap.max_recv_sge = 1; + attr.cap.max_inline_data = 16; + attr.sq_sig_all = 1; + ret = rdma_create_ep(&listen_id, res, NULL, &attr); + rdma_freeaddrinfo(res); + if (ret) { + printf("rdma_create_ep %d\n", errno); + return ret; + } + + ret = rdma_listen(listen_id, 0); + if (ret) { + printf("rdma_listen %d\n", errno); + return ret; + } + + ret = rdma_get_request(listen_id, &id); + if (ret) { + printf("rdma_get_request %d\n", errno); + return ret; + } + + mr = rdma_reg_msgs(id, recv_msg, 16); + if (!mr) { + printf("rdma_reg_msgs %d\n", errno); + return ret; + } + + ret = rdma_post_recv(id, NULL, recv_msg, 16, mr); + if (ret) { + printf("rdma_post_recv %d\n", errno); + return ret; + } + + ret = rdma_accept(id, NULL); + if (ret) { + printf("rdma_connect %d\n", errno); + return ret; + } + + ret = rdma_get_recv_comp(id, &wc); + if (ret <= 0) { + printf("rdma_get_recv_comp %d\n", ret); + return ret; + } + + ret = rdma_post_send(id, NULL, send_msg, 16, NULL, IBV_SEND_INLINE); + if (ret) { + printf("rdma_post_send %d\n", errno); + return ret; + } + + ret = rdma_get_send_comp(id, &wc); + if (ret <= 0) { + printf("rdma_get_send_comp %d\n", ret); + return ret; + } + + rdma_disconnect(id); + rdma_dereg_mr(mr); + rdma_destroy_ep(id); + rdma_destroy_ep(listen_id); + return 0; +} + +int __cdecl main(int argc, char **argv) +{ + int op, ret; + + while ((op = getopt(argc, argv, "p:")) != -1) { + switch (op) { + case 'p': + port = optarg; + break; + default: + printf("usage: %s\n", argv[0]); + printf("\t[-p port_number]\n"); + exit(1); + } + } + + printf("rdma_server: start\n"); + ret = run(); + printf("rdma_server: end %d\n", ret); + return ret; +} diff --git a/branches/WOF2-3/ulp/librdmacm/examples/rping/rping.c b/branches/WOF2-3/ulp/librdmacm/examples/rping/rping.c new file mode 100644 index 00000000..1e264feb --- /dev/null +++ b/branches/WOF2-3/ulp/librdmacm/examples/rping/rping.c @@ -0,0 +1,1122 @@ +/* + * Copyright (c) 2005 Ammasso, Inc. All rights reserved. + * Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved. + * Copyright (c) 2009 Intel Corp. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include + +#include "..\..\..\..\etc\user\getopt.c" +#include + +#include + +static int debug = 0; +#define DEBUG_LOG if (debug) printf + +/* + * rping "ping/pong" loop: + * client sends source rkey/addr/len + * server receives source rkey/add/len + * server rdma reads "ping" data from source + * server sends "go ahead" on rdma read completion + * client sends sink rkey/addr/len + * server receives sink rkey/addr/len + * server rdma writes "pong" data to sink + * server sends "go ahead" on rdma write completion + * + */ + +/* + * These states are used to signal events between the completion handler + * and the main client or server thread. + * + * Once CONNECTED, they cycle through RDMA_READ_ADV, RDMA_WRITE_ADV, + * and RDMA_WRITE_COMPLETE for each ping. + */ +enum test_state { + IDLE = 1, + CONNECT_REQUEST, + ADDR_RESOLVED, + ROUTE_RESOLVED, + CONNECTED, + RDMA_READ_ADV, + RDMA_READ_COMPLETE, + RDMA_WRITE_ADV, + RDMA_WRITE_COMPLETE, + RDMA_ERROR +}; + +struct rping_rdma_info { + uint64_t buf; + uint32_t rkey; + uint32_t size; +}; + +#define RPING_SQ_DEPTH 16 + +#define RPING_MSG_FMT "rdma-ping-%d: " +#define RPING_MIN_BUFSIZE 16 + +/* + * Control block struct. + */ +struct rping_cb { + int server; /* 0 iff client */ + pthread_t cqthread; + struct ibv_comp_channel *channel; + struct ibv_cq *cq; + struct ibv_pd *pd; + struct ibv_qp *qp; + + struct ibv_recv_wr rq_wr; /* recv work request record */ + struct ibv_sge recv_sgl; /* recv single SGE */ + struct rping_rdma_info recv_buf;/* malloc'd buffer */ + struct ibv_mr *recv_mr; /* MR associated with this buffer */ + + struct ibv_send_wr sq_wr; /* send work request record */ + struct ibv_sge send_sgl; + struct rping_rdma_info send_buf;/* single send buf */ + struct ibv_mr *send_mr; + + struct ibv_send_wr rdma_sq_wr; /* rdma work request record */ + struct ibv_sge rdma_sgl; /* rdma single SGE */ + char *rdma_buf; /* used as rdma sink */ + struct ibv_mr *rdma_mr; + + uint32_t remote_rkey; /* remote guys RKEY */ + uint64_t remote_addr; /* remote guys TO */ + uint32_t remote_len; /* remote guys LEN */ + + char *start_buf; /* rdma read src */ + struct ibv_mr *start_mr; + + enum test_state state; /* used for cond/signalling */ +// sem_t sem; + + struct sockaddr_in sin; + uint16_t port; /* dst port in NBO */ + int verbose; /* verbose logging */ + int count; /* ping count */ + int size; /* ping data size */ + int validate; /* validate ping data */ + + /* CM stuff */ +// pthread_t cmthread; + struct rdma_event_channel *cm_channel; + struct rdma_cm_id *cm_id; /* connection on client side,*/ + /* listener on service side. */ + struct rdma_cm_id *child_cm_id; /* connection on server side */ +}; + +struct rping_cb *cb; +static void *cm_thread(void *arg); +static void *cq_thread(void *arg); + +static int rping_cma_event_handler(struct rdma_cm_id *cma_id, + struct rdma_cm_event *event) +{ + int ret = 0; + struct rping_cb *cb = cma_id->context; + + DEBUG_LOG("cma_event type %s cma_id %p (%s)\n", + rdma_event_str(event->event), cma_id, + (cma_id == cb->cm_id) ? "parent" : "child"); + + switch (event->event) { + case RDMA_CM_EVENT_ADDR_RESOLVED: + cb->state = ADDR_RESOLVED; + ret = rdma_resolve_route(cma_id, 2000); + if (ret) { + cb->state = RDMA_ERROR; + fprintf(stderr, "rdma_resolve_route error %d\n", ret); +// sem_post(&cb->sem); + } + break; + + case RDMA_CM_EVENT_ROUTE_RESOLVED: + cb->state = ROUTE_RESOLVED; +// sem_post(&cb->sem); + break; + + case RDMA_CM_EVENT_CONNECT_REQUEST: + cb->state = CONNECT_REQUEST; + cb->child_cm_id = cma_id; + DEBUG_LOG("child cma %p\n", cb->child_cm_id); +// sem_post(&cb->sem); + break; + + case RDMA_CM_EVENT_ESTABLISHED: + DEBUG_LOG("ESTABLISHED\n"); + + /* + * Server will wake up when first RECV completes. + */ + if (!cb->server) { + cb->state = CONNECTED; + } +// sem_post(&cb->sem); + break; + + case RDMA_CM_EVENT_ADDR_ERROR: + case RDMA_CM_EVENT_ROUTE_ERROR: + case RDMA_CM_EVENT_CONNECT_ERROR: + case RDMA_CM_EVENT_UNREACHABLE: + case RDMA_CM_EVENT_REJECTED: + fprintf(stderr, "cma event %s, error %d\n", + rdma_event_str(event->event), event->status); +// sem_post(&cb->sem); + ret = -1; + break; + + case RDMA_CM_EVENT_DISCONNECTED: + fprintf(stderr, "%s DISCONNECT EVENT...\n", + cb->server ? "server" : "client"); +// sem_post(&cb->sem); + break; + + case RDMA_CM_EVENT_DEVICE_REMOVAL: + fprintf(stderr, "cma detected device removal!!!!\n"); + ret = -1; + break; + + default: + fprintf(stderr, "unhandled event: %s, ignoring\n", + rdma_event_str(event->event)); + break; + } + + return ret; +} + +static int server_recv(struct rping_cb *cb, struct ibv_wc *wc) +{ + if (wc->byte_len != sizeof(cb->recv_buf)) { + fprintf(stderr, "Received bogus data, size %d\n", wc->byte_len); + return -1; + } + + cb->remote_rkey = ntohl(cb->recv_buf.rkey); + cb->remote_addr = ntohll(cb->recv_buf.buf); + cb->remote_len = ntohl(cb->recv_buf.size); + DEBUG_LOG("Received rkey %x addr %" PRIx64 " len %d from peer\n", + cb->remote_rkey, cb->remote_addr, cb->remote_len); + + if (cb->state <= CONNECTED || cb->state == RDMA_WRITE_COMPLETE) + cb->state = RDMA_READ_ADV; + else + cb->state = RDMA_WRITE_ADV; + + return 0; +} + +static int client_recv(struct rping_cb *cb, struct ibv_wc *wc) +{ + if (wc->byte_len != sizeof(cb->recv_buf)) { + fprintf(stderr, "Received bogus data, size %d\n", wc->byte_len); + return -1; + } + + if (cb->state == RDMA_READ_ADV) + cb->state = RDMA_WRITE_ADV; + else + cb->state = RDMA_WRITE_COMPLETE; + + return 0; +} + +static int rping_cq_event_handler(struct rping_cb *cb) +{ + struct ibv_wc wc; + struct ibv_recv_wr *bad_wr; + int ret; + + while ((ret = ibv_poll_cq(cb->cq, 1, &wc)) == 1) { + ret = 0; + + if (wc.status) { + fprintf(stderr, "cq completion failed status %d\n", + wc.status); + if (wc.status != IBV_WC_WR_FLUSH_ERR) + ret = -1; + goto error; + } + + switch (wc.opcode) { + case IBV_WC_SEND: + DEBUG_LOG("send completion\n"); + break; + + case IBV_WC_RDMA_WRITE: + DEBUG_LOG("rdma write completion\n"); + cb->state = RDMA_WRITE_COMPLETE; +// sem_post(&cb->sem); + break; + + case IBV_WC_RDMA_READ: + DEBUG_LOG("rdma read completion\n"); + cb->state = RDMA_READ_COMPLETE; +// sem_post(&cb->sem); + break; + + case IBV_WC_RECV: + DEBUG_LOG("recv completion\n"); + ret = cb->server ? server_recv(cb, &wc) : + client_recv(cb, &wc); + if (ret) { + fprintf(stderr, "recv wc error: %d\n", ret); + goto error; + } + + ret = ibv_post_recv(cb->qp, &cb->rq_wr, &bad_wr); + if (ret) { + fprintf(stderr, "post recv error: %d\n", ret); + goto error; + } +// sem_post(&cb->sem); + break; + + default: + DEBUG_LOG("unknown!!!!! completion\n"); + ret = -1; + goto error; + } + } + if (ret) { + fprintf(stderr, "poll error %d\n", ret); + goto error; + } + return 0; + +error: + cb->state = RDMA_ERROR; +// sem_post(&cb->sem); + return ret; +} + +static int rping_accept(struct rping_cb *cb) +{ + struct rdma_conn_param conn_param; + int ret; + + DEBUG_LOG("accepting client connection request\n"); + + memset(&conn_param, 0, sizeof conn_param); + conn_param.responder_resources = 1; + conn_param.initiator_depth = 1; + + ret = rdma_accept(cb->child_cm_id, &conn_param); + if (ret) { + fprintf(stderr, "rdma_accept error: %d\n", ret); + return ret; + } + + cm_thread(cb); +// sem_wait(&cb->sem); + if (cb->state == RDMA_ERROR) { + fprintf(stderr, "wait for CONNECTED state %d\n", cb->state); + return -1; + } + return 0; +} + +static void rping_setup_wr(struct rping_cb *cb) +{ + cb->recv_sgl.addr = (uint64_t) (unsigned long) &cb->recv_buf; + cb->recv_sgl.length = sizeof cb->recv_buf; + cb->recv_sgl.lkey = cb->recv_mr->lkey; + cb->rq_wr.sg_list = &cb->recv_sgl; + cb->rq_wr.num_sge = 1; + + cb->send_sgl.addr = (uint64_t) (unsigned long) &cb->send_buf; + cb->send_sgl.length = sizeof cb->send_buf; + cb->send_sgl.lkey = cb->send_mr->lkey; + + cb->sq_wr.opcode = IBV_WR_SEND; + cb->sq_wr.send_flags = IBV_SEND_SIGNALED; + cb->sq_wr.sg_list = &cb->send_sgl; + cb->sq_wr.num_sge = 1; + + cb->rdma_sgl.addr = (uint64_t) (unsigned long) cb->rdma_buf; + cb->rdma_sgl.lkey = cb->rdma_mr->lkey; + cb->rdma_sq_wr.send_flags = IBV_SEND_SIGNALED; + cb->rdma_sq_wr.sg_list = &cb->rdma_sgl; + cb->rdma_sq_wr.num_sge = 1; +} + +static int rping_setup_buffers(struct rping_cb *cb) +{ + int ret; + + DEBUG_LOG("rping_setup_buffers called on cb %p\n", cb); + + cb->recv_mr = ibv_reg_mr(cb->pd, &cb->recv_buf, sizeof cb->recv_buf, + IBV_ACCESS_LOCAL_WRITE); + if (!cb->recv_mr) { + fprintf(stderr, "recv_buf reg_mr failed\n"); + return errno; + } + + cb->send_mr = ibv_reg_mr(cb->pd, &cb->send_buf, sizeof cb->send_buf, 0); + if (!cb->send_mr) { + fprintf(stderr, "send_buf reg_mr failed\n"); + ret = errno; + goto err1; + } + + cb->rdma_buf = malloc(cb->size); + if (!cb->rdma_buf) { + fprintf(stderr, "rdma_buf malloc failed\n"); + ret = -ENOMEM; + goto err2; + } + + cb->rdma_mr = ibv_reg_mr(cb->pd, cb->rdma_buf, cb->size, + IBV_ACCESS_LOCAL_WRITE | + IBV_ACCESS_REMOTE_READ | + IBV_ACCESS_REMOTE_WRITE); + if (!cb->rdma_mr) { + fprintf(stderr, "rdma_buf reg_mr failed\n"); + ret = errno; + goto err3; + } + + if (!cb->server) { + cb->start_buf = malloc(cb->size); + if (!cb->start_buf) { + fprintf(stderr, "start_buf malloc failed\n"); + ret = -ENOMEM; + goto err4; + } + + cb->start_mr = ibv_reg_mr(cb->pd, cb->start_buf, cb->size, + IBV_ACCESS_LOCAL_WRITE | + IBV_ACCESS_REMOTE_READ | + IBV_ACCESS_REMOTE_WRITE); + if (!cb->start_mr) { + fprintf(stderr, "start_buf reg_mr failed\n"); + ret = errno; + goto err5; + } + } + + rping_setup_wr(cb); + DEBUG_LOG("allocated & registered buffers...\n"); + return 0; + +err5: + free(cb->start_buf); +err4: + ibv_dereg_mr(cb->rdma_mr); +err3: + free(cb->rdma_buf); +err2: + ibv_dereg_mr(cb->send_mr); +err1: + ibv_dereg_mr(cb->recv_mr); + return ret; +} + +static void rping_free_buffers(struct rping_cb *cb) +{ + DEBUG_LOG("rping_free_buffers called on cb %p\n", cb); + ibv_dereg_mr(cb->recv_mr); + ibv_dereg_mr(cb->send_mr); + ibv_dereg_mr(cb->rdma_mr); + free(cb->rdma_buf); + if (!cb->server) { + ibv_dereg_mr(cb->start_mr); + free(cb->start_buf); + } +} + +static int rping_create_qp(struct rping_cb *cb) +{ + struct ibv_qp_init_attr init_attr; + int ret; + + memset(&init_attr, 0, sizeof(init_attr)); + init_attr.cap.max_send_wr = RPING_SQ_DEPTH; + init_attr.cap.max_recv_wr = 2; + init_attr.cap.max_recv_sge = 1; + init_attr.cap.max_send_sge = 1; + init_attr.qp_type = IBV_QPT_RC; + init_attr.send_cq = cb->cq; + init_attr.recv_cq = cb->cq; + + if (cb->server) { + ret = rdma_create_qp(cb->child_cm_id, cb->pd, &init_attr); + if (!ret) + cb->qp = cb->child_cm_id->qp; + } else { + ret = rdma_create_qp(cb->cm_id, cb->pd, &init_attr); + if (!ret) + cb->qp = cb->cm_id->qp; + } + + return ret; +} + +static void rping_free_qp(struct rping_cb *cb) +{ + ibv_destroy_qp(cb->qp); + ibv_destroy_cq(cb->cq); + ibv_destroy_comp_channel(cb->channel); + ibv_dealloc_pd(cb->pd); +} + +static int rping_setup_qp(struct rping_cb *cb, struct rdma_cm_id *cm_id) +{ + int ret; + + cb->pd = ibv_alloc_pd(cm_id->verbs); + if (!cb->pd) { + fprintf(stderr, "ibv_alloc_pd failed\n"); + return errno; + } + DEBUG_LOG("created pd %p\n", cb->pd); + + cb->channel = ibv_create_comp_channel(cm_id->verbs); + if (!cb->channel) { + fprintf(stderr, "ibv_create_comp_channel failed\n"); + ret = errno; + goto err1; + } + DEBUG_LOG("created channel %p\n", cb->channel); + + cb->cq = ibv_create_cq(cm_id->verbs, RPING_SQ_DEPTH * 2, cb, + cb->channel, 0); + if (!cb->cq) { + fprintf(stderr, "ibv_create_cq failed\n"); + ret = errno; + goto err2; + } + DEBUG_LOG("created cq %p\n", cb->cq); + + ret = ibv_req_notify_cq(cb->cq, 0); + if (ret) { + fprintf(stderr, "ibv_create_cq failed\n"); + ret = errno; + goto err3; + } + + ret = rping_create_qp(cb); + if (ret) { + fprintf(stderr, "rping_create_qp failed: %d\n", ret); + goto err3; + } + DEBUG_LOG("created qp %p\n", cb->qp); + return 0; + +err3: + ibv_destroy_cq(cb->cq); +err2: + ibv_destroy_comp_channel(cb->channel); +err1: + ibv_dealloc_pd(cb->pd); + return ret; +} + +static void cm_thread(void *arg) +{ + struct rping_cb *cb = arg; + struct rdma_cm_event *event; + int ret; + +// while (1) { + ret = rdma_get_cm_event(cb->cm_channel, &event); + if (ret) { + fprintf(stderr, "rdma_get_cm_event err %d\n", ret); + return; +// exit(ret); + } + ret = rping_cma_event_handler(event->id, event); + rdma_ack_cm_event(event); +// if (ret) +// exit(ret); +// } +} + +static void cq_thread(void *arg) +{ + struct rping_cb *cb = arg; + struct ibv_cq *ev_cq; + void *ev_ctx; + int ret; + +// DEBUG_LOG("cq_thread started.\n"); + +// while (1) { +// pthread_testcancel(); + + ret = ibv_get_cq_event(cb->channel, &ev_cq, &ev_ctx); + if (ret) { + fprintf(stderr, "Failed to get cq event!\n"); + return; +// pthread_exit(NULL); + } + if (ev_cq != cb->cq) { + fprintf(stderr, "Unknown CQ!\n"); + return; +// pthread_exit(NULL); + } + ret = ibv_req_notify_cq(cb->cq, 0); + if (ret) { + fprintf(stderr, "Failed to set notify!\n"); + return; +// pthread_exit(NULL); + } + ret = rping_cq_event_handler(cb); + ibv_ack_cq_events(cb->cq, 1); +// pthread_exit(NULL); +// } +} + +static void rping_format_send(struct rping_cb *cb, char *buf, struct ibv_mr *mr) +{ + struct rping_rdma_info *info = &cb->send_buf; + + info->buf = htonll((uint64_t) (unsigned long) buf); + info->rkey = htonl(mr->rkey); + info->size = htonl(cb->size); + + DEBUG_LOG("RDMA addr %" PRIx64" rkey %x len %d\n", + ntohll(info->buf), ntohl(info->rkey), ntohl(info->size)); +} + +static int rping_test_server(struct rping_cb *cb) +{ + struct ibv_send_wr *bad_wr; + int ret; + + while (1) { + /* Wait for client's Start STAG/TO/Len */ + cq_thread(cb); +// sem_wait(&cb->sem); + if (cb->state != RDMA_READ_ADV) { + fprintf(stderr, "wait for RDMA_READ_ADV state %d\n", + cb->state); + ret = -1; + break; + } + + DEBUG_LOG("server received sink adv\n"); + + /* Issue RDMA Read. */ + cb->rdma_sq_wr.opcode = IBV_WR_RDMA_READ; + cb->rdma_sq_wr.wr.rdma.rkey = cb->remote_rkey; + cb->rdma_sq_wr.wr.rdma.remote_addr = cb->remote_addr; + cb->rdma_sq_wr.sg_list->length = cb->remote_len; + + ret = ibv_post_send(cb->qp, &cb->rdma_sq_wr, &bad_wr); + if (ret) { + fprintf(stderr, "post send error %d\n", ret); + break; + } + DEBUG_LOG("server posted rdma read req \n"); + + /* Wait for read completion */ + cq_thread(cb); +// sem_wait(&cb->sem); + if (cb->state != RDMA_READ_COMPLETE) { + fprintf(stderr, "wait for RDMA_READ_COMPLETE state %d\n", + cb->state); + ret = -1; + break; + } + DEBUG_LOG("server received read complete\n"); + + /* Display data in recv buf */ + if (cb->verbose) + printf("server ping data: %s\n", cb->rdma_buf); + + /* Tell client to continue */ + ret = ibv_post_send(cb->qp, &cb->sq_wr, &bad_wr); + if (ret) { + fprintf(stderr, "post send error %d\n", ret); + break; + } + DEBUG_LOG("server posted go ahead\n"); + + /* Wait for client's RDMA STAG/TO/Len */ + cq_thread(cb); +// sem_wait(&cb->sem); + if (cb->state != RDMA_WRITE_ADV) { + fprintf(stderr, "wait for RDMA_WRITE_ADV state %d\n", + cb->state); + ret = -1; + break; + } + DEBUG_LOG("server received sink adv\n"); + + /* RDMA Write echo data */ + cb->rdma_sq_wr.opcode = IBV_WR_RDMA_WRITE; + cb->rdma_sq_wr.wr.rdma.rkey = cb->remote_rkey; + cb->rdma_sq_wr.wr.rdma.remote_addr = cb->remote_addr; + cb->rdma_sq_wr.sg_list->length = strlen(cb->rdma_buf) + 1; + DEBUG_LOG("rdma write from lkey %x laddr %" PRIx64 " len %d\n", + cb->rdma_sq_wr.sg_list->lkey, + cb->rdma_sq_wr.sg_list->addr, + cb->rdma_sq_wr.sg_list->length); + + ret = ibv_post_send(cb->qp, &cb->rdma_sq_wr, &bad_wr); + if (ret) { + fprintf(stderr, "post send error %d\n", ret); + break; + } + + /* Wait for completion */ + cq_thread(cb); +// ret = sem_wait(&cb->sem); + if (cb->state != RDMA_WRITE_COMPLETE) { + fprintf(stderr, "wait for RDMA_WRITE_COMPLETE state %d\n", + cb->state); + ret = -1; + break; + } + DEBUG_LOG("server rdma write complete \n"); + + /* Tell client to begin again */ + ret = ibv_post_send(cb->qp, &cb->sq_wr, &bad_wr); + if (ret) { + fprintf(stderr, "post send error %d\n", ret); + break; + } + DEBUG_LOG("server posted go ahead\n"); + } + + return ret; +} + +static int rping_bind_server(struct rping_cb *cb) +{ + int ret; + + cb->sin.sin_port = cb->port; + ret = rdma_bind_addr(cb->cm_id, (struct sockaddr *) &cb->sin); + if (ret) { + fprintf(stderr, "rdma_bind_addr error %d\n", ret); + return ret; + } + DEBUG_LOG("rdma_bind_addr successful\n"); + + DEBUG_LOG("rdma_listen\n"); + ret = rdma_listen(cb->cm_id, 3); + if (ret) { + fprintf(stderr, "rdma_listen failed: %d\n", ret); + return ret; + } + + return 0; +} + +static struct rping_cb *clone_cb(struct rping_cb *listening_cb) +{ + struct rping_cb *cb = malloc(sizeof *cb); + if (!cb) + return NULL; + *cb = *listening_cb; + cb->child_cm_id->context = cb; + return cb; +} + +static void free_cb(struct rping_cb *cb) +{ + free(cb); +} + +static int rping_run_server(struct rping_cb *cb) +{ + struct ibv_recv_wr *bad_wr; + int ret; + + ret = rping_bind_server(cb); + if (ret) + return ret; + + cm_thread(cb); +// sem_wait(&cb->sem); + if (cb->state != CONNECT_REQUEST) { + fprintf(stderr, "wait for CONNECT_REQUEST state %d\n", + cb->state); + return -1; + } + + ret = rping_setup_qp(cb, cb->child_cm_id); + if (ret) { + fprintf(stderr, "setup_qp failed: %d\n", ret); + return ret; + } + + ret = rping_setup_buffers(cb); + if (ret) { + fprintf(stderr, "rping_setup_buffers failed: %d\n", ret); + goto err1; + } + + ret = ibv_post_recv(cb->qp, &cb->rq_wr, &bad_wr); + if (ret) { + fprintf(stderr, "ibv_post_recv failed: %d\n", ret); + goto err2; + } + +// pthread_create(&cb->cqthread, NULL, cq_thread, cb); + + ret = rping_accept(cb); + if (ret) { + fprintf(stderr, "connect error %d\n", ret); + goto err2; + } + + rping_test_server(cb); + rdma_disconnect(cb->child_cm_id); + rdma_destroy_id(cb->child_cm_id); +err2: + rping_free_buffers(cb); +err1: + rping_free_qp(cb); + + return ret; +} + +static int rping_test_client(struct rping_cb *cb) +{ + int ping, start, cc, i, ret = 0; + struct ibv_send_wr *bad_wr; + unsigned char c; + + start = 65; + for (ping = 0; !cb->count || ping < cb->count; ping++) { + cb->state = RDMA_READ_ADV; + + /* Put some ascii text in the buffer. */ + cc = sprintf(cb->start_buf, RPING_MSG_FMT, ping); + for (i = cc, c = start; i < cb->size; i++) { + cb->start_buf[i] = c; + c++; + if (c > 122) + c = 65; + } + start++; + if (start > 122) + start = 65; + cb->start_buf[cb->size - 1] = 0; + + rping_format_send(cb, cb->start_buf, cb->start_mr); + ret = ibv_post_send(cb->qp, &cb->sq_wr, &bad_wr); + if (ret) { + fprintf(stderr, "post send error %d\n", ret); + break; + } + + /* Wait for server to ACK */ + cq_thread(cb); +// sem_wait(&cb->sem); + if (cb->state != RDMA_WRITE_ADV) { + fprintf(stderr, "wait for RDMA_WRITE_ADV state %d\n", + cb->state); + ret = -1; + break; + } + + rping_format_send(cb, cb->rdma_buf, cb->rdma_mr); + ret = ibv_post_send(cb->qp, &cb->sq_wr, &bad_wr); + if (ret) { + fprintf(stderr, "post send error %d\n", ret); + break; + } + + /* Wait for the server to say the RDMA Write is complete. */ + cq_thread(cb); +// sem_wait(&cb->sem); + if (cb->state != RDMA_WRITE_COMPLETE) { + fprintf(stderr, "wait for RDMA_WRITE_COMPLETE state %d\n", + cb->state); + ret = -1; + break; + } + + if (cb->validate) + if (memcmp(cb->start_buf, cb->rdma_buf, cb->size)) { + fprintf(stderr, "data mismatch!\n"); + ret = -1; + break; + } + + if (cb->verbose) + printf("ping data: %s\n", cb->rdma_buf); + } + + return ret; +} + +static int rping_connect_client(struct rping_cb *cb) +{ + struct rdma_conn_param conn_param; + int ret; + + memset(&conn_param, 0, sizeof conn_param); + conn_param.responder_resources = 1; + conn_param.initiator_depth = 1; + conn_param.retry_count = 10; + + ret = rdma_connect(cb->cm_id, &conn_param); + if (ret) { + fprintf(stderr, "rdma_connect error %d\n", ret); + return ret; + } + + cm_thread(cb); +// sem_wait(&cb->sem); + if (cb->state != CONNECTED) { + fprintf(stderr, "wait for CONNECTED state %d\n", cb->state); + return -1; + } + + DEBUG_LOG("rmda_connect successful\n"); + return 0; +} + +static int rping_bind_client(struct rping_cb *cb) +{ + int ret; + + cb->sin.sin_port = cb->port; + ret = rdma_resolve_addr(cb->cm_id, NULL, (struct sockaddr *) &cb->sin, 2000); + if (ret) { + fprintf(stderr, "rdma_resolve_addr error %d\n", ret); + return ret; + } + + cm_thread(cb); +// sem_wait(&cb->sem); + if (cb->state != ROUTE_RESOLVED) { + fprintf(stderr, "waiting for addr/route resolution state %d\n", + cb->state); + return -1; + } + + DEBUG_LOG("rdma_resolve_addr - rdma_resolve_route successful\n"); + return 0; +} + +static int rping_run_client(struct rping_cb *cb) +{ + struct ibv_recv_wr *bad_wr; + int ret; + + ret = rping_bind_client(cb); + if (ret) + return ret; + + ret = rping_setup_qp(cb, cb->cm_id); + if (ret) { + fprintf(stderr, "setup_qp failed: %d\n", ret); + return ret; + } + + ret = rping_setup_buffers(cb); + if (ret) { + fprintf(stderr, "rping_setup_buffers failed: %d\n", ret); + goto err1; + } + + ret = ibv_post_recv(cb->qp, &cb->rq_wr, &bad_wr); + if (ret) { + fprintf(stderr, "ibv_post_recv failed: %d\n", ret); + goto err2; + } + +// pthread_create(&cb->cqthread, NULL, cq_thread, cb); + + ret = rping_connect_client(cb); + if (ret) { + fprintf(stderr, "connect error %d\n", ret); + goto err2; + } + + rping_test_client(cb); + rdma_disconnect(cb->cm_id); +err2: + rping_free_buffers(cb); +err1: + rping_free_qp(cb); + + return ret; +} + +static int get_addr(char *dst, struct sockaddr_in *addr) +{ + struct addrinfo *res; + int ret; + + ret = getaddrinfo(dst, NULL, NULL, &res); + if (ret) { + printf("getaddrinfo failed - invalid hostname or IP address\n"); + return ret; + } + + if (res->ai_family != PF_INET) { + ret = -1; + goto out; + } + + *addr = *(struct sockaddr_in *) res->ai_addr; +out: + freeaddrinfo(res); + return ret; +} + +static void usage() +{ + printf("rdma_rping -s [-vVd] [-S size] [-C count] [-a addr] [-p port]\n"); + printf("rdma_rping -c [-vVd] [-S size] [-C count] -a addr [-p port]\n"); + printf("\t-c\t\tclient side\n"); + printf("\t-s\t\tserver side\n"); + printf("\t-v\t\tdisplay ping data to stdout\n"); + printf("\t-V\t\tvalidate ping data\n"); + printf("\t-d\t\tdebug printfs\n"); + printf("\t-S size \tping data size\n"); + printf("\t-C count\tping count times\n"); + printf("\t-a addr\t\taddress\n"); + printf("\t-p port\t\tport\n"); +} + +int main(int argc, char *argv[]) +{ +// struct rping_cb *cb; + int op; + int ret = 0; + + cb = malloc(sizeof(*cb)); + if (!cb) + return -ENOMEM; + + memset(cb, 0, sizeof(*cb)); + cb->server = -1; + cb->state = IDLE; + cb->size = 64; + cb->sin.sin_family = PF_INET; + cb->port = htons(7174); +// sem_init(&cb->sem, 0, 0); + + opterr = 0; + while ((op=getopt(argc, argv, "a:Pp:C:S:t:scvVd")) != -1) { + switch (op) { + case 'a': + ret = get_addr(optarg, &cb->sin); + break; + case 'p': + cb->port = htons(atoi(optarg)); + DEBUG_LOG("port %d\n", (int) atoi(optarg)); + break; + case 's': + cb->server = 1; + DEBUG_LOG("server\n"); + break; + case 'c': + cb->server = 0; + DEBUG_LOG("client\n"); + break; + case 'S': + cb->size = atoi(optarg); + if (cb->size < RPING_MIN_BUFSIZE) { + fprintf(stderr, "Invalid size (minimum is %d) " RPING_MIN_BUFSIZE); + ret = EINVAL; + } else + DEBUG_LOG("size %d\n", (int) atoi(optarg)); + break; + case 'C': + cb->count = atoi(optarg); + if (cb->count < 0) { + fprintf(stderr, "Invalid count %d\n", cb->count); + ret = EINVAL; + } else + DEBUG_LOG("count %d\n", (int) cb->count); + break; + case 'v': + cb->verbose++; + DEBUG_LOG("verbose\n"); + break; + case 'V': + cb->validate++; + DEBUG_LOG("validate data\n"); + break; + case 'd': + debug++; + break; + default: + usage(); + ret = EINVAL; + goto out; + } + } + if (ret) + goto out; + + if (cb->server == -1) { + usage(); + ret = EINVAL; + goto out; + } + + cb->cm_channel = rdma_create_event_channel(); + if (!cb->cm_channel) { + ret = errno; + fprintf(stderr, "rdma_create_event_channel error %d\n", ret); + goto out; + } + + ret = rdma_create_id(cb->cm_channel, &cb->cm_id, cb, RDMA_PS_TCP); + if (ret) { + ret = errno; + fprintf(stderr, "rdma_create_id error %d\n", ret); + goto out2; + } + DEBUG_LOG("created cm_id %p\n", cb->cm_id); + +// pthread_create(&cb->cmthread, NULL, cm_thread, cb); + + if (cb->server) + ret = rping_run_server(cb); + else + ret = rping_run_client(cb); + + DEBUG_LOG("destroy cm_id %p\n", cb->cm_id); + rdma_destroy_id(cb->cm_id); +out2: + rdma_destroy_event_channel(cb->cm_channel); +out: + free(cb); + return ret; +} diff --git a/branches/WOF2-3/ulp/librdmacm/examples/udaddy/udaddy.c b/branches/WOF2-3/ulp/librdmacm/examples/udaddy/udaddy.c new file mode 100644 index 00000000..9e74a228 --- /dev/null +++ b/branches/WOF2-3/ulp/librdmacm/examples/udaddy/udaddy.c @@ -0,0 +1,701 @@ +/* + * Copyright (c) 2005-2006 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +struct cmatest_node { + int id; + struct rdma_cm_id *cma_id; + int connected; + struct ibv_pd *pd; + struct ibv_cq *cq; + struct ibv_mr *mr; + struct ibv_ah *ah; + uint32_t remote_qpn; + uint32_t remote_qkey; + void *mem; +}; + +struct cmatest { + struct rdma_event_channel *channel; + struct cmatest_node *nodes; + int conn_index; + int connects_left; + + struct sockaddr_in dst_in; + struct sockaddr *dst_addr; + struct sockaddr_in src_in; + struct sockaddr *src_addr; +}; + +static struct cmatest test; +static int connections = 1; +static int message_size = 100; +static int message_count = 10; +static uint16_t port = 7174; +static uint8_t set_tos = 0; +static uint8_t tos; +static char *dst_addr; +static char *src_addr; +static enum rdma_port_space port_space = RDMA_PS_UDP; + +static int create_message(struct cmatest_node *node) +{ + if (!message_size) + message_count = 0; + + if (!message_count) + return 0; + + node->mem = malloc(message_size + sizeof(struct ibv_grh)); + if (!node->mem) { + printf("failed message allocation\n"); + return -1; + } + node->mr = ibv_reg_mr(node->pd, node->mem, + message_size + sizeof(struct ibv_grh), + IBV_ACCESS_LOCAL_WRITE); + if (!node->mr) { + printf("failed to reg MR\n"); + goto err; + } + return 0; +err: + free(node->mem); + return -1; +} + +static int verify_test_params(struct cmatest_node *node) +{ + struct ibv_port_attr port_attr; + int ret; + + ret = ibv_query_port(node->cma_id->verbs, node->cma_id->port_num, + &port_attr); + if (ret) + return ret; + + if (message_count && message_size > (1 << (port_attr.active_mtu + 7))) { + printf("udaddy: message_size %d is larger than active mtu %d\n", + message_size, 1 << (port_attr.active_mtu + 7)); + return -EINVAL; + } + + return 0; +} + +static int init_node(struct cmatest_node *node) +{ + struct ibv_qp_init_attr init_qp_attr; + int cqe, ret; + + node->pd = ibv_alloc_pd(node->cma_id->verbs); + if (!node->pd) { + ret = -ENOMEM; + printf("udaddy: unable to allocate PD\n"); + goto out; + } + + cqe = message_count ? message_count * 2 : 2; + node->cq = ibv_create_cq(node->cma_id->verbs, cqe, node, 0, 0); + if (!node->cq) { + ret = -ENOMEM; + printf("udaddy: unable to create CQ\n"); + goto out; + } + + memset(&init_qp_attr, 0, sizeof init_qp_attr); + init_qp_attr.cap.max_send_wr = message_count ? message_count : 1; + init_qp_attr.cap.max_recv_wr = message_count ? message_count : 1; + init_qp_attr.cap.max_send_sge = 1; + init_qp_attr.cap.max_recv_sge = 1; + init_qp_attr.qp_context = node; + init_qp_attr.sq_sig_all = 0; + init_qp_attr.qp_type = IBV_QPT_UD; + init_qp_attr.send_cq = node->cq; + init_qp_attr.recv_cq = node->cq; + ret = rdma_create_qp(node->cma_id, node->pd, &init_qp_attr); + if (ret) { + printf("udaddy: unable to create QP: %d\n", ret); + goto out; + } + + ret = create_message(node); + if (ret) { + printf("udaddy: failed to create messages: %d\n", ret); + goto out; + } +out: + return ret; +} + +static int post_recvs(struct cmatest_node *node) +{ + struct ibv_recv_wr recv_wr, *recv_failure; + struct ibv_sge sge; + int i, ret = 0; + + if (!message_count) + return 0; + + recv_wr.next = NULL; + recv_wr.sg_list = &sge; + recv_wr.num_sge = 1; + recv_wr.wr_id = (uintptr_t) node; + + sge.length = message_size + sizeof(struct ibv_grh); + sge.lkey = node->mr->lkey; + sge.addr = (uintptr_t) node->mem; + + for (i = 0; i < message_count && !ret; i++ ) { + ret = ibv_post_recv(node->cma_id->qp, &recv_wr, &recv_failure); + if (ret) { + printf("failed to post receives: %d\n", ret); + break; + } + } + return ret; +} + +static int post_sends(struct cmatest_node *node, int signal_flag) +{ + struct ibv_send_wr send_wr, *bad_send_wr; + struct ibv_sge sge; + int i, ret = 0; + + if (!node->connected || !message_count) + return 0; + + send_wr.next = NULL; + send_wr.sg_list = &sge; + send_wr.num_sge = 1; + send_wr.opcode = IBV_WR_SEND_WITH_IMM; + send_wr.send_flags = signal_flag; + send_wr.wr_id = (unsigned long)node; + send_wr.imm_data = htonl(node->cma_id->qp->qp_num); + + send_wr.wr.ud.ah = node->ah; + send_wr.wr.ud.remote_qpn = node->remote_qpn; + send_wr.wr.ud.remote_qkey = node->remote_qkey; + + sge.length = message_size; + sge.lkey = node->mr->lkey; + sge.addr = (uintptr_t) node->mem; + + for (i = 0; i < message_count && !ret; i++) { + ret = ibv_post_send(node->cma_id->qp, &send_wr, &bad_send_wr); + if (ret) + printf("failed to post sends: %d\n", ret); + } + return ret; +} + +static void connect_error(void) +{ + test.connects_left--; +} + +static int addr_handler(struct cmatest_node *node) +{ + int ret; + + if (set_tos) { + ret = rdma_set_option(node->cma_id, RDMA_OPTION_ID, + RDMA_OPTION_ID_TOS, &tos, sizeof tos); + if (ret) + printf("udaddy: set TOS option failed: %d\n", ret); + } + + ret = rdma_resolve_route(node->cma_id, 2000); + if (ret) { + printf("udaddy: resolve route failed: %d\n", ret); + connect_error(); + } + return ret; +} + +static int route_handler(struct cmatest_node *node) +{ + struct rdma_conn_param conn_param; + int ret; + + ret = verify_test_params(node); + if (ret) + goto err; + + ret = init_node(node); + if (ret) + goto err; + + ret = post_recvs(node); + if (ret) + goto err; + + memset(&conn_param, 0, sizeof conn_param); + ret = rdma_connect(node->cma_id, &conn_param); + if (ret) { + printf("udaddy: failure connecting: %d\n", ret); + goto err; + } + return 0; +err: + connect_error(); + return ret; +} + +static int connect_handler(struct rdma_cm_id *cma_id) +{ + struct cmatest_node *node; + struct rdma_conn_param conn_param; + int ret; + + if (test.conn_index == connections) { + ret = -ENOMEM; + goto err1; + } + node = &test.nodes[test.conn_index++]; + + node->cma_id = cma_id; + cma_id->context = node; + + ret = verify_test_params(node); + if (ret) + goto err2; + + ret = init_node(node); + if (ret) + goto err2; + + ret = post_recvs(node); + if (ret) + goto err2; + + memset(&conn_param, 0, sizeof conn_param); + conn_param.qp_num = node->cma_id->qp->qp_num; + ret = rdma_accept(node->cma_id, &conn_param); + if (ret) { + printf("udaddy: failure accepting: %d\n", ret); + goto err2; + } + node->connected = 1; + test.connects_left--; + return 0; + +err2: + node->cma_id = NULL; + connect_error(); +err1: + printf("udaddy: failing connection request\n"); + rdma_reject(cma_id, NULL, 0); + return ret; +} + +static int resolved_handler(struct cmatest_node *node, + struct rdma_cm_event *event) +{ + node->remote_qpn = event->param.ud.qp_num; + node->remote_qkey = event->param.ud.qkey; + node->ah = ibv_create_ah(node->pd, &event->param.ud.ah_attr); + if (!node->ah) { + printf("udaddy: failure creating address handle\n"); + goto err; + } + + node->connected = 1; + test.connects_left--; + return 0; +err: + connect_error(); + return -1; +} + +static int cma_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *event) +{ + int ret = 0; + + switch (event->event) { + case RDMA_CM_EVENT_ADDR_RESOLVED: + ret = addr_handler(cma_id->context); + break; + case RDMA_CM_EVENT_ROUTE_RESOLVED: + ret = route_handler(cma_id->context); + break; + case RDMA_CM_EVENT_CONNECT_REQUEST: + ret = connect_handler(cma_id); + break; + case RDMA_CM_EVENT_ESTABLISHED: + ret = resolved_handler(cma_id->context, event); + break; + case RDMA_CM_EVENT_ADDR_ERROR: + case RDMA_CM_EVENT_ROUTE_ERROR: + case RDMA_CM_EVENT_CONNECT_ERROR: + case RDMA_CM_EVENT_UNREACHABLE: + case RDMA_CM_EVENT_REJECTED: + printf("udaddy: event: %s, error: %d\n", + rdma_event_str(event->event), event->status); + connect_error(); + ret = event->status; + break; + case RDMA_CM_EVENT_DEVICE_REMOVAL: + /* Cleanup will occur after test completes. */ + break; + default: + break; + } + return ret; +} + +static void destroy_node(struct cmatest_node *node) +{ + if (!node->cma_id) + return; + + if (node->ah) + ibv_destroy_ah(node->ah); + + if (node->cma_id->qp) + rdma_destroy_qp(node->cma_id); + + if (node->cq) + ibv_destroy_cq(node->cq); + + if (node->mem) { + ibv_dereg_mr(node->mr); + free(node->mem); + } + + if (node->pd) + ibv_dealloc_pd(node->pd); + + /* Destroy the RDMA ID after all device resources */ + rdma_destroy_id(node->cma_id); +} + +static int alloc_nodes(void) +{ + int ret, i; + + test.nodes = malloc(sizeof *test.nodes * connections); + if (!test.nodes) { + printf("udaddy: unable to allocate memory for test nodes\n"); + return -ENOMEM; + } + memset(test.nodes, 0, sizeof *test.nodes * connections); + + for (i = 0; i < connections; i++) { + test.nodes[i].id = i; + if (dst_addr) { + ret = rdma_create_id(test.channel, + &test.nodes[i].cma_id, + &test.nodes[i], port_space); + if (ret) + goto err; + } + } + return 0; +err: + while (--i >= 0) + rdma_destroy_id(test.nodes[i].cma_id); + free(test.nodes); + return ret; +} + +static void destroy_nodes(void) +{ + int i; + + for (i = 0; i < connections; i++) + destroy_node(&test.nodes[i]); + free(test.nodes); +} + +static void create_reply_ah(struct cmatest_node *node, struct ibv_wc *wc) +{ + struct ibv_qp_attr attr; + struct ibv_qp_init_attr init_attr; + + node->ah = ibv_create_ah_from_wc(node->pd, wc, node->mem, + node->cma_id->port_num); + node->remote_qpn = ntohl(wc->imm_data); + + ibv_query_qp(node->cma_id->qp, &attr, IBV_QP_QKEY, &init_attr); + node->remote_qkey = attr.qkey; +} + +static int poll_cqs(void) +{ + struct ibv_wc wc[8]; + int done, i, ret; + + for (i = 0; i < connections; i++) { + if (!test.nodes[i].connected) + continue; + + for (done = 0; done < message_count; done += ret) { + ret = ibv_poll_cq(test.nodes[i].cq, 8, wc); + if (ret < 0) { + printf("udaddy: failed polling CQ: %d\n", ret); + return ret; + } + + if (ret && !test.nodes[i].ah) + create_reply_ah(&test.nodes[i], wc); + } + } + return 0; +} + +static int connect_events(void) +{ + struct rdma_cm_event *event; + int ret = 0; + + while (test.connects_left && !ret) { + ret = rdma_get_cm_event(test.channel, &event); + if (!ret) { + ret = cma_handler(event->id, event); + rdma_ack_cm_event(event); + } + } + return ret; +} + +static int get_addr(char *dst, struct sockaddr_in *addr) +{ + struct addrinfo *res; + int ret; + + ret = getaddrinfo(dst, NULL, NULL, &res); + if (ret) { + printf("getaddrinfo failed - invalid hostname or IP address\n"); + return ret; + } + + if (res->ai_family != PF_INET) { + ret = -1; + goto out; + } + + *addr = *(struct sockaddr_in *) res->ai_addr; +out: + freeaddrinfo(res); + return ret; +} + +static int run_server(void) +{ + struct rdma_cm_id *listen_id; + int i, ret; + + printf("udaddy: starting server\n"); + ret = rdma_create_id(test.channel, &listen_id, &test, port_space); + if (ret) { + printf("udaddy: listen request failed\n"); + return ret; + } + + if (src_addr) { + ret = get_addr(src_addr, &test.src_in); + if (ret) + goto out; + } else + test.src_in.sin_family = PF_INET; + + test.src_in.sin_port = port; + ret = rdma_bind_addr(listen_id, test.src_addr); + if (ret) { + printf("udaddy: bind address failed: %d\n", ret); + return ret; + } + + ret = rdma_listen(listen_id, 0); + if (ret) { + printf("udaddy: failure trying to listen: %d\n", ret); + goto out; + } + + connect_events(); + + if (message_count) { + printf("receiving data transfers\n"); + ret = poll_cqs(); + if (ret) + goto out; + + printf("sending replies\n"); + for (i = 0; i < connections; i++) { + ret = post_sends(&test.nodes[i], IBV_SEND_SIGNALED); + if (ret) + goto out; + } + + ret = poll_cqs(); + if (ret) + goto out; + printf("data transfers complete\n"); + } +out: + rdma_destroy_id(listen_id); + return ret; +} + +static int run_client(void) +{ + int i, ret; + + printf("udaddy: starting client\n"); + if (src_addr) { + ret = get_addr(src_addr, &test.src_in); + if (ret) + return ret; + } + + ret = get_addr(dst_addr, &test.dst_in); + if (ret) + return ret; + + test.dst_in.sin_port = port; + + printf("udaddy: connecting\n"); + for (i = 0; i < connections; i++) { + ret = rdma_resolve_addr(test.nodes[i].cma_id, + src_addr ? test.src_addr : NULL, + test.dst_addr, 2000); + if (ret) { + printf("udaddy: failure getting addr: %d\n", ret); + connect_error(); + return ret; + } + } + + ret = connect_events(); + if (ret) + goto out; + + if (message_count) { + printf("initiating data transfers\n"); + for (i = 0; i < connections; i++) { + ret = post_sends(&test.nodes[i], 0); + if (ret) + goto out; + } + printf("receiving data transfers\n"); + ret = poll_cqs(); + if (ret) + goto out; + + printf("data transfers complete\n"); + } +out: + return ret; +} + +int main(int argc, char **argv) +{ + int op, ret; + + while ((op = getopt(argc, argv, "s:b:c:C:S:t:p:")) != -1) { + switch (op) { + case 's': + dst_addr = optarg; + break; + case 'b': + src_addr = optarg; + break; + case 'c': + connections = atoi(optarg); + break; + case 'C': + message_count = atoi(optarg); + break; + case 'S': + message_size = atoi(optarg); + break; + case 't': + set_tos = 1; + tos = (uint8_t) atoi(optarg); + break; + case 'p': + port_space = strtol(optarg, NULL, 0); + break; + default: + printf("usage: %s\n", argv[0]); + printf("\t[-s server_address]\n"); + printf("\t[-b bind_address]\n"); + printf("\t[-c connections]\n"); + printf("\t[-C message_count]\n"); + printf("\t[-S message_size]\n"); + printf("\t[-t type_of_service]\n"); + printf("\t[-p port_space - %#x for UDP (default), " + "%#x for IPOIB]\n", RDMA_PS_UDP, RDMA_PS_IPOIB); + exit(1); + } + } + + test.dst_addr = (struct sockaddr *) &test.dst_in; + test.src_addr = (struct sockaddr *) &test.src_in; + test.connects_left = connections; + + test.channel = rdma_create_event_channel(); + if (!test.channel) { + printf("failed to create event channel\n"); + exit(1); + } + + if (alloc_nodes()) + exit(1); + + if (dst_addr) + ret = run_client(); + else + ret = run_server(); + + printf("test complete\n"); + destroy_nodes(); + rdma_destroy_event_channel(test.channel); + + printf("return status %d\n", ret); + return ret; +} diff --git a/branches/WOF2-3/ulp/librdmacm/include/rdma/rdma_cma.h b/branches/WOF2-3/ulp/librdmacm/include/rdma/rdma_cma.h new file mode 100644 index 00000000..bec57f07 --- /dev/null +++ b/branches/WOF2-3/ulp/librdmacm/include/rdma/rdma_cma.h @@ -0,0 +1,722 @@ +/* + * Copyright (c) 2005-2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenFabrics.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#if !defined(RDMA_CMA_H) +#define RDMA_CMA_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Interfaces based on librdmacm 1.0.8. + */ + +#define RDMA_MAX_PRIVATE_DATA 56 + +/* + * Upon receiving a device removal event, users must destroy the associated + * RDMA identifier and release all resources allocated with the device. + */ +enum rdma_cm_event_type +{ + RDMA_CM_EVENT_ADDR_RESOLVED, + RDMA_CM_EVENT_ADDR_ERROR, + RDMA_CM_EVENT_ROUTE_RESOLVED, + RDMA_CM_EVENT_ROUTE_ERROR, + RDMA_CM_EVENT_CONNECT_REQUEST, + RDMA_CM_EVENT_CONNECT_RESPONSE, + RDMA_CM_EVENT_CONNECT_ERROR, + RDMA_CM_EVENT_UNREACHABLE, + RDMA_CM_EVENT_REJECTED, + RDMA_CM_EVENT_ESTABLISHED, + RDMA_CM_EVENT_DISCONNECTED, + RDMA_CM_EVENT_DEVICE_REMOVAL, + RDMA_CM_EVENT_MULTICAST_JOIN, + RDMA_CM_EVENT_MULTICAST_ERROR, + RDMA_CM_EVENT_ADDR_CHANGE, + RDMA_CM_EVENT_TIMEWAIT_EXIT +}; + +enum rdma_port_space +{ + RDMA_PS_IPOIB = 0x0002, + RDMA_PS_IB = 0x0003, + RDMA_PS_TCP = 0x0106, + RDMA_PS_UDP = 0x0111, +}; + +#define RDMA_IB_IP_PS_MASK 0xFFFFFFFFFFFF0000ULL +#define RDMA_IB_IP_PORT_MASK 0x000000000000FFFFULL +#define RDMA_IB_IP_PS_TCP 0x0000000001060000ULL +#define RDMA_IB_IP_PS_UDP 0x0000000001110000ULL + +/* + * Global qkey value for UDP QPs and multicast groups created via the + * RDMA CM. + */ +#define RDMA_UDP_QKEY 0x01234567 + +struct rdma_ib_addr +{ + union ibv_gid sgid; + union ibv_gid dgid; + uint16_t pkey; +}; + +struct rdma_addr +{ + struct sockaddr src_addr; + uint8_t src_pad[sizeof(SOCKADDR_IN6) - + sizeof(struct sockaddr)]; + struct sockaddr dst_addr; + uint8_t dst_pad[sizeof(SOCKADDR_IN6) - + sizeof(struct sockaddr)]; + union + { + struct rdma_ib_addr ibaddr; + } addr; +}; + +struct rdma_route +{ + struct rdma_addr addr; + struct ibv_sa_path_rec *path_rec; + int num_paths; +}; + +struct rdma_event_channel +{ + COMP_CHANNEL channel; +}; + +struct rdma_cm_id +{ + struct ibv_context *verbs; + struct rdma_event_channel *channel; + void *context; + struct ibv_qp *qp; + struct rdma_route route; + enum rdma_port_space ps; + uint8_t port_num; + COMP_ENTRY comp_entry; + + union { + IWVConnectEndpoint *connect; + IWVDatagramEndpoint *datagram; + } ep; + + struct rdma_cm_event *event; + struct ibv_comp_channel *send_cq_channel; + struct ibv_cq *send_cq; + struct ibv_comp_channel *recv_cq_channel; + struct ibv_cq *recv_cq; +}; + +enum { + RDMA_MAX_RESP_RES = 0xFF, + RDMA_MAX_INIT_DEPTH = 0xFF +}; + +struct rdma_conn_param +{ + const void *private_data; + uint8_t private_data_len; + uint8_t responder_resources; + uint8_t initiator_depth; + uint8_t flow_control; + uint8_t retry_count; /* ignored when accepting */ + uint8_t rnr_retry_count; + /* Fields below ignored if a QP is created on the rdma_cm_id. */ + uint8_t srq; + uint32_t qp_num; +}; + +struct rdma_ud_param +{ + const void *private_data; + uint8_t private_data_len; + struct ibv_ah_attr ah_attr; + uint32_t qp_num; + uint32_t qkey; +}; + +struct rdma_cm_event +{ + struct rdma_cm_id *id; + struct rdma_cm_id *listen_id; + enum rdma_cm_event_type event; + int status; + union + { + struct rdma_conn_param conn; + struct rdma_ud_param ud; + + } param; +}; + +#define RAI_PASSIVE 0x00000001 + +struct rdma_addrinfo { + int ai_flags; + int ai_family; + int ai_qp_type; + int ai_port_space; + socklen_t ai_src_len; + socklen_t ai_dst_len; + struct sockaddr *ai_src_addr; + struct sockaddr *ai_dst_addr; + char *ai_src_canonname; + char *ai_dst_canonname; + size_t ai_route_len; + void *ai_route; + size_t ai_connect_len; + void *ai_connect; + struct rdma_addrinfo *ai_next; +}; + +/** + * rdma_create_event_channel - Open a channel used to report communication events. + * Description: + * Asynchronous events are reported to users through event channels. Each + * event channel maps to a file descriptor. + * Notes: + * All created event channels must be destroyed by calling + * rdma_destroy_event_channel. Users should call rdma_get_cm_event to + * retrieve events on an event channel. + * See also: + * rdma_get_cm_event, rdma_destroy_event_channel + */ +__declspec(dllexport) +struct rdma_event_channel *rdma_create_event_channel(void); + +/** + * rdma_destroy_event_channel - Close an event communication channel. + * @channel: The communication channel to destroy. + * Description: + * Release all resources associated with an event channel and closes the + * associated file descriptor. + * Notes: + * All rdma_cm_id's associated with the event channel must be destroyed, + * and all returned events must be acked before calling this function. + * See also: + * rdma_create_event_channel, rdma_get_cm_event, rdma_ack_cm_event + */ +__declspec(dllexport) +void rdma_destroy_event_channel(struct rdma_event_channel *channel); + +/** + * rdma_create_id - Allocate a communication identifier. + * @channel: The communication channel that events associated with the + * allocated rdma_cm_id will be reported on. + * @id: A reference where the allocated communication identifier will be + * returned. + * @context: User specified context associated with the rdma_cm_id. + * @ps: RDMA port space. + * Description: + * Creates an identifier that is used to track communication information. + * Notes: + * Rdma_cm_id's are conceptually equivalent to a socket for RDMA + * communication. The difference is that RDMA communication requires + * explicitly binding to a specified RDMA device before communication + * can occur, and most operations are asynchronous in nature. Communication + * events on an rdma_cm_id are reported through the associated event + * channel. Users must release the rdma_cm_id by calling rdma_destroy_id. + * See also: + * rdma_create_event_channel, rdma_destroy_id, rdma_get_devices, + * rdma_bind_addr, rdma_resolve_addr, rdma_connect, rdma_listen, + */ +__declspec(dllexport) +int rdma_create_id(struct rdma_event_channel *channel, + struct rdma_cm_id **id, void *context, + enum rdma_port_space ps); + +/** + * rdma_create_ep - Allocate a communication identifier and qp. + * @id: A reference where the allocated communication identifier will be + * returned. + * @res: Result from rdma_getaddrinfo, which specifies the source and + * destination addresses, plus optional routing and connection information. + * @pd: Optional protection domain. This parameter is ignored if qp_init_attr + * is NULL. + * @qp_init_attr: Optional attributes for a QP created on the rdma_cm_id. + * Description: + * Create an identifier and option QP used for communication. + * Notes: + * If qp_init_attr is provided, then a queue pair will be allocated and + * associated with the rdma_cm_id. If a pd is provided, the QP will be + * created on that PD. Otherwise, the QP will be allocated on a default + * PD. + * The rdma_cm_id will be set to use synchronous operations (connect, + * listen, and get_request). To convert to asynchronous operation, the + * rdma_cm_id should be migrated to a user allocated event channel. + * See also: + * rdma_create_id, rdma_create_qp, rdma_migrate_id, rdma_connect, + * rdma_listen + */ +__declspec(dllexport) +int rdma_create_ep(struct rdma_cm_id **id, struct rdma_addrinfo *res, + struct ibv_pd *pd, struct ibv_qp_init_attr *qp_init_attr); + +/** + * rdma_destroy_ep - Deallocates a communication identifier and qp. + * @id: The communication identifer to destroy. + * Description: + * Destroys the specified rdma_cm_id and any associated QP created + * on that id. + * See also: + * rdma_create_ep + */ +__declspec(dllexport) +void rdma_destroy_ep(struct rdma_cm_id *id); + +/** + * rdma_destroy_id - Release a communication identifier. + * @id: The communication identifier to destroy. + * Description: + * Destroys the specified rdma_cm_id and cancels any outstanding + * asynchronous operation. + * Notes: + * Users must free any associated QP with the rdma_cm_id before + * calling this routine and ack an related events. + * See also: + * rdma_create_id, rdma_destroy_qp, rdma_ack_cm_event + */ +__declspec(dllexport) +int rdma_destroy_id(struct rdma_cm_id *id); + +/** + * rdma_bind_addr - Bind an RDMA identifier to a source address. + * @id: RDMA identifier. + * @addr: Local address information. Wildcard values are permitted. + * Description: + * Associates a source address with an rdma_cm_id. The address may be + * wildcarded. If binding to a specific local address, the rdma_cm_id + * will also be bound to a local RDMA device. + * Notes: + * Typically, this routine is called before calling rdma_listen to bind + * to a specific port number, but it may also be called on the active side + * of a connection before calling rdma_resolve_addr to bind to a specific + * address. + * See also: + * rdma_create_id, rdma_listen, rdma_resolve_addr, rdma_create_qp + */ +__declspec(dllexport) +int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr); + +/** + * rdma_resolve_addr - Resolve destination and optional source addresses. + * @id: RDMA identifier. + * @src_addr: Source address information. This parameter may be NULL. + * @dst_addr: Destination address information. + * @timeout_ms: Time to wait for resolution to complete. + * Description: + * Resolve destination and optional source addresses from IP addresses + * to an RDMA address. If successful, the specified rdma_cm_id will + * be bound to a local device. + * Notes: + * This call is used to map a given destination IP address to a usable RDMA + * address. If a source address is given, the rdma_cm_id is bound to that + * address, the same as if rdma_bind_addr were called. If no source + * address is given, and the rdma_cm_id has not yet been bound to a device, + * then the rdma_cm_id will be bound to a source address based on the + * local routing tables. After this call, the rdma_cm_id will be bound to + * an RDMA device. This call is typically made from the active side of a + * connection before calling rdma_resolve_route and rdma_connect. + * See also: + * rdma_create_id, rdma_resolve_route, rdma_connect, rdma_create_qp, + * rdma_get_cm_event, rdma_bind_addr + */ +__declspec(dllexport) +int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, + struct sockaddr *dst_addr, int timeout_ms); + +/** + * rdma_resolve_route - Resolve the route information needed to establish a connection. + * @id: RDMA identifier. + * @timeout_ms: Time to wait for resolution to complete. + * Description: + * Resolves an RDMA route to the destination address in order to establish + * a connection. The destination address must have already been resolved + * by calling rdma_resolve_addr. + * Notes: + * This is called on the client side of a connection after calling + * rdma_resolve_addr, but before calling rdma_connect. + * See also: + * rdma_resolve_addr, rdma_connect, rdma_get_cm_event + */ +__declspec(dllexport) +int rdma_resolve_route(struct rdma_cm_id *id, int timeout_ms); + +/** + * rdma_create_qp - Allocate a QP. + * @id: RDMA identifier. + * @pd: protection domain for the QP. + * @qp_init_attr: initial QP attributes. + * Description: + * Allocate a QP associated with the specified rdma_cm_id and transition it + * for sending and receiving. + * Notes: + * The rdma_cm_id must be bound to a local RDMA device before calling this + * function, and the protection domain must be for that same device. + * QPs allocated to an rdma_cm_id are automatically transitioned by the + * librdmacm through their states. After being allocated, the QP will be + * ready to handle posting of receives. If the QP is unconnected, it will + * be ready to post sends. + * See also: + * rdma_bind_addr, rdma_resolve_addr, rdma_destroy_qp, ibv_create_qp, + * ibv_modify_qp + */ +__declspec(dllexport) +int rdma_create_qp(struct rdma_cm_id *id, struct ibv_pd *pd, + struct ibv_qp_init_attr *qp_init_attr); + +/** + * rdma_destroy_qp - Deallocate a QP. + * @id: RDMA identifier. + * Description: + * Destroy a QP allocated on the rdma_cm_id. + * Notes: + * Users must destroy any QP associated with an rdma_cm_id before + * destroying the ID. + * See also: + * rdma_create_qp, rdma_destroy_id, ibv_destroy_qp + */ +__declspec(dllexport) +void rdma_destroy_qp(struct rdma_cm_id *id); + +/** + * rdma_connect - Initiate an active connection request. + * @id: RDMA identifier. + * @conn_param: connection parameters. + * Description: + * For a connected rdma_cm_id, this call initiates a connection request + * to a remote destination. For an unconnected rdma_cm_id, it initiates + * a lookup of the remote QP providing the datagram service. + * Notes: + * Users must have resolved a route to the destination address + * by having called rdma_resolve_route before calling this routine. + * See also: + * rdma_resolve_route, rdma_disconnect, rdma_listen, rdma_get_cm_event + */ +__declspec(dllexport) +int rdma_connect(struct rdma_cm_id *id, struct rdma_conn_param *conn_param); + +/** + * rdma_listen - Listen for incoming connection requests. + * @id: RDMA identifier. + * @backlog: backlog of incoming connection requests. + * Description: + * Initiates a listen for incoming connection requests or datagram service + * lookup. The listen will be restricted to the locally bound source + * address. + * Notes: + * Users must have bound the rdma_cm_id to a local address by calling + * rdma_bind_addr before calling this routine. If the rdma_cm_id is + * bound to a specific IP address, the listen will be restricted to that + * address and the associated RDMA device. If the rdma_cm_id is bound + * to an RDMA port number only, the listen will occur across all RDMA + * devices. + * See also: + * rdma_bind_addr, rdma_connect, rdma_accept, rdma_reject, rdma_get_cm_event + */ +__declspec(dllexport) +int rdma_listen(struct rdma_cm_id *id, int backlog); + +__declspec(dllexport) +int rdma_get_request(struct rdma_cm_id *listen, struct rdma_cm_id **id); + +/** + * rdma_accept - Called to accept a connection request. + * @id: Connection identifier associated with the request. + * @conn_param: Information needed to establish the connection. + * Description: + * Called from the listening side to accept a connection or datagram + * service lookup request. + * Notes: + * Unlike the socket accept routine, rdma_accept is not called on a + * listening rdma_cm_id. Instead, after calling rdma_listen, the user + * waits for a connection request event to occur. Connection request + * events give the user a newly created rdma_cm_id, similar to a new + * socket, but the rdma_cm_id is bound to a specific RDMA device. + * rdma_accept is called on the new rdma_cm_id. + * See also: + * rdma_listen, rdma_reject, rdma_get_cm_event + */ +__declspec(dllexport) +int rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param); + +/** + * rdma_reject - Called to reject a connection request. + * @id: Connection identifier associated with the request. + * @private_data: Optional private data to send with the reject message. + * @private_data_len: Size of the private_data to send, in bytes. + * Description: + * Called from the listening side to reject a connection or datagram + * service lookup request. + * Notes: + * After receiving a connection request event, a user may call rdma_reject + * to reject the request. If the underlying RDMA transport supports + * private data in the reject message, the specified data will be passed to + * the remote side. + * See also: + * rdma_listen, rdma_accept, rdma_get_cm_event + */ +__declspec(dllexport) +int rdma_reject(struct rdma_cm_id *id, const void *private_data, + uint8_t private_data_len); + +/** + * rdma_notify - Notifies the librdmacm of an asynchronous event. + * @id: RDMA identifier. + * @event: Asynchronous event. + * Description: + * Used to notify the librdmacm of asynchronous events that have occurred + * on a QP associated with the rdma_cm_id. + * Notes: + * Asynchronous events that occur on a QP are reported through the user's + * device event handler. This routine is used to notify the librdmacm of + * communication events. In most cases, use of this routine is not + * necessary, however if connection establishment is done out of band + * (such as done through Infiniband), it's possible to receive data on a + * QP that is not yet considered connected. This routine forces the + * connection into an established state in this case in order to handle + * the rare situation where the connection never forms on its own. + * Events that should be reported to the CM are: IB_EVENT_COMM_EST. + * See also: + * rdma_connect, rdma_accept, rdma_listen + */ +__declspec(dllexport) +int rdma_notify(struct rdma_cm_id *id, enum ibv_event_type event); + +/** + * rdma_disconnect - This function disconnects a connection. + * @id: RDMA identifier. + * Description: + * Disconnects a connection and transitions any associated QP to the + * error state. + * See also: + * rdma_connect, rdma_listen, rdma_accept + */ +__declspec(dllexport) +int rdma_disconnect(struct rdma_cm_id *id); + +/** + * rdma_join_multicast - Joins a multicast group. + * @id: Communication identifier associated with the request. + * @addr: Multicast address identifying the group to join. + * @context: User-defined context associated with the join request. + * Description: + * Joins a multicast group and attaches an associated QP to the group. + * Notes: + * Before joining a multicast group, the rdma_cm_id must be bound to + * an RDMA device by calling rdma_bind_addr or rdma_resolve_addr. Use of + * rdma_resolve_addr requires the local routing tables to resolve the + * multicast address to an RDMA device. The user must call + * rdma_leave_multicast to leave the multicast group and release any + * multicast resources. The context is returned to the user through + * the private_data field in the rdma_cm_event. + * See also: + * rdma_leave_multicast, rdma_bind_addr, rdma_resolve_addr, rdma_create_qp + */ +__declspec(dllexport) +int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr, + void *context); + +/** + * rdma_leave_multicast - Leaves a multicast group. + * @id: Communication identifier associated with the request. + * @addr: Multicast address identifying the group to leave. + * Description: + * Leaves a multicast group and detaches an associated QP from the group. + * Notes: + * Calling this function before a group has been fully joined results in + * canceling the join operation. Users should be aware that messages + * received from the multicast group may stilled be queued for + * completion processing immediately after leaving a multicast group. + * Destroying an rdma_cm_id will automatically leave all multicast groups. + * See also: + * rdma_join_multicast, rdma_destroy_qp + */ +__declspec(dllexport) +int rdma_leave_multicast(struct rdma_cm_id *id, struct sockaddr *addr); + +/** + * rdma_get_cm_event - Retrieves the next pending communication event. + * @channel: Event channel to check for events. + * @event: Allocated information about the next communication event. + * Description: + * Retrieves a communication event. If no events are pending, by default, + * the call will block until an event is received. + * Notes: + * The default synchronous behavior of this routine can be changed by + * modifying the file descriptor associated with the given channel. All + * events that are reported must be acknowledged by calling rdma_ack_cm_event. + * Destruction of an rdma_cm_id will block until related events have been + * acknowledged. + * See also: + * rdma_ack_cm_event, rdma_create_event_channel, rdma_event_str + */ +__declspec(dllexport) +int rdma_get_cm_event(struct rdma_event_channel *channel, + struct rdma_cm_event **event); + +/** + * rdma_ack_cm_event - Free a communication event. + * @event: Event to be released. + * Description: + * All events which are allocated by rdma_get_cm_event must be released, + * there should be a one-to-one correspondence between successful gets + * and acks. + * See also: + * rdma_get_cm_event, rdma_destroy_id + */ +__declspec(dllexport) +int rdma_ack_cm_event(struct rdma_cm_event *event); + +static uint16_t rdma_get_src_port(struct rdma_cm_id *id) +{ + return id->route.addr.src_addr.sa_family == PF_INET6 ? + ((struct sockaddr_in6 *) &id->route.addr.src_addr)->sin6_port : + ((struct sockaddr_in *) &id->route.addr.src_addr)->sin_port; +} + +static uint16_t rdma_get_dst_port(struct rdma_cm_id *id) +{ + return id->route.addr.dst_addr.sa_family == PF_INET6 ? + ((struct sockaddr_in6 *) &id->route.addr.dst_addr)->sin6_port : + ((struct sockaddr_in *) &id->route.addr.dst_addr)->sin_port; +} + +static struct sockaddr *rdma_get_local_addr(struct rdma_cm_id *id) +{ + return &id->route.addr.src_addr; +} + +static struct sockaddr *rdma_get_peer_addr(struct rdma_cm_id *id) +{ + return &id->route.addr.dst_addr; +} + +/** + * rdma_get_devices - Get list of RDMA devices currently available. + * @num_devices: If non-NULL, set to the number of devices returned. + * Description: + * Return a NULL-terminated array of opened RDMA devices. Callers can use + * this routine to allocate resources on specific RDMA devices that will be + * shared across multiple rdma_cm_id's. + * Notes: + * The returned array must be released by calling rdma_free_devices. Devices + * remain opened while the librdmacm is loaded. + * See also: + * rdma_free_devices + */ +__declspec(dllexport) +struct ibv_context **rdma_get_devices(int *num_devices); + +/** + * rdma_free_devices - Frees the list of devices returned by rdma_get_devices. + * @list: List of devices returned from rdma_get_devices. + * Description: + * Frees the device array returned by rdma_get_devices. + * See also: + * rdma_get_devices + */ +__declspec(dllexport) +void rdma_free_devices(struct ibv_context **list); + +/** + * rdma_event_str - Returns a string representation of an rdma cm event. + * @event: Asynchronous event. + * Description: + * Returns a string representation of an asynchronous event. + * See also: + * rdma_get_cm_event + */ +__declspec(dllexport) +const char *rdma_event_str(enum rdma_cm_event_type event); + +/* Option levels */ +enum +{ + RDMA_OPTION_ID = 0 +}; + +/* Option details */ +enum +{ + RDMA_OPTION_ID_TOS = 0 /* uint8_t: RFC 2474 */ +}; + +/** + * rdma_set_option - Set options for an rdma_cm_id. + * @id: Communication identifier to set option for. + * @level: Protocol level of the option to set. + * @optname: Name of the option to set. + * @optval: Reference to the option data. + * @optlen: The size of the %optval buffer. + */ +__declspec(dllexport) +int rdma_set_option(struct rdma_cm_id *id, int level, int optname, + void *optval, size_t optlen); + +/** + * rdma_migrate_id - Move an rdma_cm_id to a new event channel. + * @id: Communication identifier to migrate. + * @channel: New event channel for rdma_cm_id events. + */ +__declspec(dllexport) +int rdma_migrate_id(struct rdma_cm_id *id, struct rdma_event_channel *channel); + +/** + * rdma_getaddrinfo - RDMA address and route resolution service. + */ +__declspec(dllexport) +int rdma_getaddrinfo(char *node, char *service, + struct rdma_addrinfo *hints, + struct rdma_addrinfo **res); + +__declspec(dllexport) +void rdma_freeaddrinfo(struct rdma_addrinfo *res); + +__declspec(dllexport) +int rdmaw_wsa_errno(int wsa_err); + +#ifdef __cplusplus +} +#endif + +#endif /* RDMA_CMA_H */ diff --git a/branches/WOF2-3/ulp/librdmacm/include/rdma/rdma_verbs.h b/branches/WOF2-3/ulp/librdmacm/include/rdma/rdma_verbs.h new file mode 100644 index 00000000..feb01be7 --- /dev/null +++ b/branches/WOF2-3/ulp/librdmacm/include/rdma/rdma_verbs.h @@ -0,0 +1,297 @@ +/* + * Copyright (c) 2010 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#if !defined(RDMA_VERBS_H) +#define RDMA_VERBS_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +static __inline int rdma_seterrno(int ret) +{ + if (ret) { + errno = ret; + ret = -1; + } + return ret; +} + +/* + * Memory registration helpers. + */ +static __inline struct ibv_mr * +rdma_reg_msgs(struct rdma_cm_id *id, void *addr, size_t length) +{ + return ibv_reg_mr(id->qp->pd, addr, length, IBV_ACCESS_LOCAL_WRITE); +} + +static __inline struct ibv_mr * +rdma_reg_read(struct rdma_cm_id *id, void *addr, size_t length) +{ + return ibv_reg_mr(id->qp->pd, addr, length, IBV_ACCESS_LOCAL_WRITE | + IBV_ACCESS_REMOTE_READ); +} + +static __inline struct ibv_mr * +rdma_reg_write(struct rdma_cm_id *id, void *addr, size_t length) +{ + return ibv_reg_mr(id->qp->pd, addr, length, IBV_ACCESS_LOCAL_WRITE | + IBV_ACCESS_REMOTE_WRITE); +} + +static __inline int +rdma_dereg_mr(struct ibv_mr *mr) +{ + return rdma_seterrno(ibv_dereg_mr(mr)); +} + + +/* + * Vectored send, receive, and RDMA operations. + * Support multiple scatter-gather entries. + */ +static __inline int +rdma_post_recvv(struct rdma_cm_id *id, void *context, struct ibv_sge *sgl, + int nsge) +{ + struct ibv_recv_wr wr, *bad; + + wr.wr_id = (uintptr_t) context; + wr.next = NULL; + wr.sg_list = sgl; + wr.num_sge = nsge; + + return rdma_seterrno(ibv_post_recv(id->qp, &wr, &bad)); +} + +static __inline int +rdma_post_sendv(struct rdma_cm_id *id, void *context, struct ibv_sge *sgl, + int nsge, int flags) +{ + struct ibv_send_wr wr, *bad; + + wr.wr_id = (uintptr_t) context; + wr.next = NULL; + wr.sg_list = sgl; + wr.num_sge = nsge; + wr.opcode = IBV_WR_SEND; + wr.send_flags = flags; + + return rdma_seterrno(ibv_post_send(id->qp, &wr, &bad)); +} + +static __inline int +rdma_post_readv(struct rdma_cm_id *id, void *context, struct ibv_sge *sgl, + int nsge, int flags, uint64_t remote_addr, uint32_t rkey) +{ + struct ibv_send_wr wr, *bad; + + wr.wr_id = (uintptr_t) context; + wr.next = NULL; + wr.sg_list = sgl; + wr.num_sge = nsge; + wr.opcode = IBV_WR_RDMA_READ; + wr.send_flags = flags; + wr.wr.rdma.remote_addr = remote_addr; + wr.wr.rdma.rkey = rkey; + + return rdma_seterrno(ibv_post_send(id->qp, &wr, &bad)); +} + +static __inline int +rdma_post_writev(struct rdma_cm_id *id, void *context, struct ibv_sge *sgl, + int nsge, int flags, uint64_t remote_addr, uint32_t rkey) +{ + struct ibv_send_wr wr, *bad; + + wr.wr_id = (uintptr_t) context; + wr.next = NULL; + wr.sg_list = sgl; + wr.num_sge = nsge; + wr.opcode = IBV_WR_RDMA_WRITE; + wr.send_flags = flags; + wr.wr.rdma.remote_addr = remote_addr; + wr.wr.rdma.rkey = rkey; + + return rdma_seterrno(ibv_post_send(id->qp, &wr, &bad)); +} + +/* + * Simple send, receive, and RDMA calls. + */ +static __inline int +rdma_post_recv(struct rdma_cm_id *id, void *context, void *addr, + size_t length, struct ibv_mr *mr) +{ + struct ibv_sge sge; + + assert((addr >= mr->addr) && + (((uint8_t) addr + length) <= ((uint8_t) mr->addr + mr->length))); + sge.addr = (uint64_t) (uintptr_t) addr; + sge.length = (uint32_t) length; + sge.lkey = mr->lkey; + + return rdma_post_recvv(id, context, &sge, 1); +} + +static __inline int +rdma_post_send(struct rdma_cm_id *id, void *context, void *addr, + size_t length, struct ibv_mr *mr, int flags) +{ + struct ibv_sge sge; + + sge.addr = (uint64_t) (uintptr_t) addr; + sge.length = (uint32_t) length; + sge.lkey = mr ? mr->lkey : 0; + + return rdma_post_sendv(id, context, &sge, 1, flags); +} + +static __inline int +rdma_post_read(struct rdma_cm_id *id, void *context, void *addr, + size_t length, struct ibv_mr *mr, int flags, + uint64_t remote_addr, uint32_t rkey) +{ + struct ibv_sge sge; + + sge.addr = (uint64_t) (uintptr_t) addr; + sge.length = (uint32_t) length; + sge.lkey = mr->lkey; + + return rdma_post_readv(id, context, &sge, 1, flags, remote_addr, rkey); +} + +static __inline int +rdma_post_write(struct rdma_cm_id *id, void *context, void *addr, + size_t length, struct ibv_mr *mr, int flags, + uint64_t remote_addr, uint32_t rkey) +{ + struct ibv_sge sge; + + sge.addr = (uint64_t) (uintptr_t) addr; + sge.length = (uint32_t) length; + sge.lkey = mr ? mr->lkey : 0; + + return rdma_post_writev(id, context, &sge, 1, flags, remote_addr, rkey); +} + +static __inline int +rdma_post_ud_send(struct rdma_cm_id *id, void *context, void *addr, + size_t length, struct ibv_mr *mr, int flags, + struct ibv_ah *ah, uint32_t remote_qpn) +{ + struct ibv_send_wr wr, *bad; + struct ibv_sge sge; + + sge.addr = (uint64_t) (uintptr_t) addr; + sge.length = (uint32_t) length; + sge.lkey = mr ? mr->lkey : 0; + + wr.wr_id = (uintptr_t) context; + wr.next = NULL; + wr.sg_list = &sge; + wr.num_sge = 1; + wr.opcode = IBV_WR_SEND; + wr.send_flags = flags; + wr.wr.ud.ah = ah; + wr.wr.ud.remote_qpn = remote_qpn; + wr.wr.ud.remote_qkey = RDMA_UDP_QKEY; + + return rdma_seterrno(ibv_post_send(id->qp, &wr, &bad)); +} + +// Comment out until patch to automatically create CQs +static __inline int +rdma_get_send_comp(struct rdma_cm_id *id, struct ibv_wc *wc) +{ + struct ibv_cq *cq; + void *context; + int ret; + + ret = ibv_poll_cq(id->send_cq, 1, wc); + if (ret) + goto out; + + ret = ibv_req_notify_cq(id->send_cq, 0); + if (ret) + return rdma_seterrno(ret); + + while (!(ret = ibv_poll_cq(id->send_cq, 1, wc))) { + ret = ibv_get_cq_event(id->send_cq_channel, &cq, &context); + if (ret) + return rdma_seterrno(ret); + + assert(cq == id->send_cq && context == id); + ibv_ack_cq_events(id->send_cq, 1); + } +out: + return (ret < 0) ? rdma_seterrno(ret) : ret; +} + +static __inline int +rdma_get_recv_comp(struct rdma_cm_id *id, struct ibv_wc *wc) +{ + struct ibv_cq *cq; + void *context; + int ret; + + ret = ibv_poll_cq(id->recv_cq, 1, wc); + if (ret) + goto out; + + ret = ibv_req_notify_cq(id->recv_cq, 0); + if (ret) + return rdma_seterrno(ret); + + while (!(ret = ibv_poll_cq(id->recv_cq, 1, wc))) { + ret = ibv_get_cq_event(id->recv_cq_channel, &cq, &context); + if (ret) + return rdma_seterrno(ret); + + assert(cq == id->recv_cq && context == id); + ibv_ack_cq_events(id->recv_cq, 1); + } +out: + return (ret < 0) ? rdma_seterrno(ret) : ret; +} + +#ifdef __cplusplus +} +#endif + +#endif /* RDMA_CMA_H */ diff --git a/branches/WOF2-3/ulp/librdmacm/src/Sources b/branches/WOF2-3/ulp/librdmacm/src/Sources new file mode 100644 index 00000000..4934f049 --- /dev/null +++ b/branches/WOF2-3/ulp/librdmacm/src/Sources @@ -0,0 +1,42 @@ +!if $(FREEBUILD) +TARGETNAME = librdmacm +!else +TARGETNAME = librdmacmd +!endif + +TARGETPATH = ..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = DYNLINK + +!if $(_NT_TOOLS_VERSION) == 0x700 +DLLDEF = $O\cma_exports.def +!else +DLLDEF = $(OBJ_PATH)\$O\cma_exports.def +!endif + +DLLENTRY = DllMain +USE_MSVCRT = 1 + +SOURCES = \ + cma.rc \ + cma_main.cpp \ + cma.cpp \ + addrinfo.cpp + +INCLUDES = ..\include;..\..\..\inc;..\..\..\inc\user;..\..\libibverbs\include;\ + ..\..\..\inc\user\linux; + +USER_C_FLAGS = $(USER_C_FLAGS) -DEXPORT_CMA_SYMBOLS + +TARGETLIBS = \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\uuid.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ + $(SDK_LIB_PATH)\iphlpapi.lib \ + $(TARGETPATH)\*\ibat.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\libibverbs.lib \ + $(TARGETPATH)\*\winverbs.lib +!else + $(TARGETPATH)\*\libibverbsd.lib \ + $(TARGETPATH)\*\winverbsd.lib +!endif diff --git a/branches/WOF2-3/ulp/librdmacm/src/addrinfo.cpp b/branches/WOF2-3/ulp/librdmacm/src/addrinfo.cpp new file mode 100644 index 00000000..5d53ca64 --- /dev/null +++ b/branches/WOF2-3/ulp/librdmacm/src/addrinfo.cpp @@ -0,0 +1,243 @@ +/* + * Copyright (c) 2010 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include + +#include "cma.h" +#include +#include + +static DWORD addr_ref; + +static void ucma_startup(void) +{ + WSADATA wsadata; + + EnterCriticalSection(&lock); + if (addr_ref++) { + goto out; + } + + if (WSAStartup(MAKEWORD(2, 2), &wsadata)) { + addr_ref--; + } + +out: + LeaveCriticalSection(&lock); +} + +static void ucma_shutdown(void) +{ + EnterCriticalSection(&lock); + if (--addr_ref == 0) { + WSACleanup(); + } + LeaveCriticalSection(&lock); +} + +static void ucma_convert_to_ai(struct addrinfo *ai, struct rdma_addrinfo *rai) +{ + memset(ai, 0, sizeof *ai); + ai->ai_flags = rai->ai_flags; + ai->ai_family = rai->ai_family; + + switch (rai->ai_qp_type) { + case IBV_QPT_RC: + ai->ai_socktype = SOCK_STREAM; + break; + case IBV_QPT_UD: + ai->ai_socktype = SOCK_DGRAM; + break; + } + + switch (rai->ai_port_space) { + case RDMA_PS_TCP: + ai->ai_protocol = IPPROTO_TCP; + break; + case RDMA_PS_IPOIB: + case RDMA_PS_UDP: + ai->ai_protocol = IPPROTO_UDP; + break; + } + + if (rai->ai_flags & RAI_PASSIVE) { + ai->ai_addrlen = rai->ai_src_len; + ai->ai_addr = rai->ai_src_addr; + } else { + ai->ai_addrlen = rai->ai_dst_len; + ai->ai_addr = rai->ai_dst_addr; + } + ai->ai_canonname = rai->ai_dst_canonname; + ai->ai_next = NULL; +} + +static int ucma_convert_to_rai(struct rdma_addrinfo *rai, struct addrinfo *ai) +{ + struct sockaddr *addr; + char *canonname; + + memset(rai, 0, sizeof *rai); + rai->ai_flags = ai->ai_flags; + rai->ai_family = ai->ai_family; + + switch (ai->ai_socktype) { + case SOCK_STREAM: + rai->ai_qp_type = IBV_QPT_RC; + break; + case SOCK_DGRAM: + rai->ai_qp_type = IBV_QPT_UD; + break; + } + + switch (ai->ai_protocol) { + case IPPROTO_TCP: + rai->ai_port_space = RDMA_PS_TCP; + break; + case IPPROTO_UDP: + rai->ai_port_space = RDMA_PS_UDP; + break; + } + + addr = (struct sockaddr *) malloc(ai->ai_addrlen); + if (!addr) + return rdma_seterrno(ENOMEM); + + canonname = (char *) (ai->ai_canonname ? malloc(strlen(ai->ai_canonname) + 1) : NULL); + if (canonname) + strcpy(canonname, ai->ai_canonname); + + memcpy(addr, ai->ai_addr, ai->ai_addrlen); + if (ai->ai_flags & RAI_PASSIVE) { + rai->ai_src_addr = addr; + rai->ai_src_len = ai->ai_addrlen; + rai->ai_src_canonname = canonname; + } else { + rai->ai_dst_addr = addr; + rai->ai_dst_len = ai->ai_addrlen; + rai->ai_dst_canonname = canonname; + } + + return 0; +} + +__declspec(dllexport) +int rdma_getaddrinfo(char *node, char *service, + struct rdma_addrinfo *hints, + struct rdma_addrinfo **res) +{ + struct rdma_addrinfo *rai; + struct addrinfo ai_hints; + struct addrinfo *ai; + int ret; + + ucma_startup(); + if (hints) + ucma_convert_to_ai(&ai_hints, hints); + + ret = getaddrinfo(node, service, &ai_hints, &ai); + if (ret) + return rdmaw_wsa_errno(ret); + + rai = (struct rdma_addrinfo *) malloc(sizeof(*rai)); + if (!rai) { + ret = rdma_seterrno(ENOMEM); + goto err1; + } + + // Windows does not set AI_PASSIVE on output + ai->ai_flags |= hints ? hints->ai_flags : 0; + ret = ucma_convert_to_rai(rai, ai); + if (ret) + goto err2; + + if (!rai->ai_src_len && hints && hints->ai_src_len) { + rai->ai_src_addr = (struct sockaddr *) calloc(1, hints->ai_src_len); + if (!rai->ai_src_addr) { + ret = rdma_seterrno(ENOMEM); + goto err2; + } + memcpy(rai->ai_src_addr, hints->ai_src_addr, + hints->ai_src_len); + rai->ai_src_len = hints->ai_src_len; + } + + // requires ib acm support -- + //if (!(rai->ai_flags & RAI_PASSIVE)) + // ucma_ib_resolve(rai); + + freeaddrinfo(ai); + *res = rai; + return 0; + +err2: + rdma_freeaddrinfo(rai); +err1: + freeaddrinfo(ai); + return ret; +} + +__declspec(dllexport) +void rdma_freeaddrinfo(struct rdma_addrinfo *res) +{ + struct rdma_addrinfo *rai; + + while (res) { + rai = res; + res = res->ai_next; + + if (rai->ai_connect) + free(rai->ai_connect); + + if (rai->ai_route) + free(rai->ai_route); + + if (rai->ai_src_canonname) + free(rai->ai_src_canonname); + + if (rai->ai_dst_canonname) + free(rai->ai_dst_canonname); + + if (rai->ai_src_addr) + free(rai->ai_src_addr); + + if (rai->ai_dst_addr) + free(rai->ai_dst_addr); + + free(rai); + } + ucma_shutdown(); +} diff --git a/branches/WOF2-3/ulp/librdmacm/src/cma.cpp b/branches/WOF2-3/ulp/librdmacm/src/cma.cpp new file mode 100644 index 00000000..835d0204 --- /dev/null +++ b/branches/WOF2-3/ulp/librdmacm/src/cma.cpp @@ -0,0 +1,1469 @@ +/* + * Copyright (c) 2005-2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include <_errno.h> +#include +#include +#include "cma.h" +#include "..\..\..\etc\user\comp_channel.cpp" + +static struct ibvw_windata windata; + +enum cma_state +{ + cma_idle, + cma_listening, + cma_get_request, + cma_addr_bind, + cma_addr_resolve, + cma_route_resolve, + cma_passive_connect, + cma_active_connect, + cma_active_accept, + cma_accepting, + cma_connected, + cma_active_disconnect, + cma_passive_disconnect, + cma_disconnected, + cma_destroying +}; + +#define CMA_DEFAULT_BACKLOG 16 + +struct cma_id_private +{ + struct rdma_cm_id id; + enum cma_state state; + struct cma_device *cma_dev; + int sync; + int backlog; + int index; + volatile LONG refcnt; + struct rdma_cm_id **req_list; + struct ibv_pd *pd; + struct ibv_qp_init_attr *qp_init_attr; + uint8_t initiator_depth; + uint8_t responder_resources; +}; + +struct cma_device +{ + struct ibv_context *verbs; + struct ibv_pd *pd; + uint64_t guid; + int port_cnt; + uint8_t max_initiator_depth; + uint8_t max_responder_resources; +}; + +struct cma_event { + struct rdma_cm_event event; + uint8_t private_data[RDMA_MAX_PRIVATE_DATA]; + struct cma_id_private *id_priv; +}; + +static struct cma_device *cma_dev_array; +static int cma_dev_cnt; +static DWORD ref; + +static int ucma_acquire(void) +{ + struct ibv_device **dev_list = NULL; + struct cma_device *cma_dev; + struct ibv_device_attr attr; + int i, ret, dev_cnt; + + EnterCriticalSection(&lock); + if (ref++) { + goto out; + } + + ret = ibvw_get_windata(&windata, IBVW_WINDATA_VERSION); + if (ret) { + goto err1; + } + + dev_list = ibv_get_device_list(&dev_cnt); + if (dev_list == NULL) { + ret = -1; + goto err2; + } + + cma_dev_array = new struct cma_device[dev_cnt]; + if (cma_dev_array == NULL) { + ret = -1; + goto err3; + } + + for (i = 0; dev_list[i];) { + cma_dev = &cma_dev_array[i]; + + cma_dev->guid = ibv_get_device_guid(dev_list[i]); + cma_dev->verbs = ibv_open_device(dev_list[i]); + if (cma_dev->verbs == NULL) { + ret = -1; + goto err4; + } + + cma_dev->pd = ibv_alloc_pd(cma_dev->verbs); + if (cma_dev->pd == NULL) { + ibv_close_device(cma_dev->verbs); + ret = -1; + goto err4; + } + + ++i; + ret = ibv_query_device(cma_dev->verbs, &attr); + if (ret) { + goto err4; + } + + cma_dev->port_cnt = attr.phys_port_cnt; + cma_dev->max_initiator_depth = (uint8_t) attr.max_qp_init_rd_atom; + cma_dev->max_responder_resources = (uint8_t) attr.max_qp_rd_atom; + } + ibv_free_device_list(dev_list); + cma_dev_cnt = dev_cnt; +out: + LeaveCriticalSection(&lock); + return 0; + +err4: + while (i--) { + ibv_dealloc_pd(cma_dev_array[i].pd); + ibv_close_device(cma_dev_array[i].verbs); + } + delete cma_dev_array; +err3: + ibv_free_device_list(dev_list); +err2: + ibvw_release_windata(&windata, IBVW_WINDATA_VERSION); +err1: + ref--; + LeaveCriticalSection(&lock); + return ret; +} + +void ucma_release(void) +{ + int i; + + EnterCriticalSection(&lock); + if (--ref == 0) { + for (i = 0; i < cma_dev_cnt; i++) { + ibv_dealloc_pd(cma_dev_array[i].pd); + ibv_close_device(cma_dev_array[i].verbs); + } + delete cma_dev_array; + cma_dev_cnt = 0; + ibvw_release_windata(&windata, IBVW_WINDATA_VERSION); + } + LeaveCriticalSection(&lock); +} + +__declspec(dllexport) +struct ibv_context **rdma_get_devices(int *num_devices) +{ + struct ibv_context **devs = NULL; + int i; + + if (ucma_acquire()) { + goto out; + } + + devs = new struct ibv_context *[cma_dev_cnt + 1]; + if (devs == NULL) { + goto out; + } + + for (i = 0; i < cma_dev_cnt; i++) { + devs[i] = cma_dev_array[i].verbs; + } + devs[i] = NULL; +out: + if (num_devices != NULL) { + *num_devices = devs ? cma_dev_cnt : 0; + } + return devs; +} + +__declspec(dllexport) +void rdma_free_devices(struct ibv_context **list) +{ + delete list; + ucma_release(); +} + +__declspec(dllexport) +struct rdma_event_channel *rdma_create_event_channel(void) +{ + struct rdma_event_channel *channel; + + if (ucma_acquire()) { + return NULL; + } + + channel = new struct rdma_event_channel; + if (channel == NULL) { + return NULL; + } + + CompChannelInit(windata.comp_mgr, &channel->channel, INFINITE); + return channel; +} + +__declspec(dllexport) +void rdma_destroy_event_channel(struct rdma_event_channel *channel) +{ + CompChannelCleanup(&channel->channel); + delete channel; + ucma_release(); +} + +__declspec(dllexport) +int rdma_create_id(struct rdma_event_channel *channel, + struct rdma_cm_id **id, void *context, + enum rdma_port_space ps) +{ + struct cma_id_private *id_priv; + HRESULT hr; + int ret; + + ret = ucma_acquire(); + if (ret) { + return ret; + } + + id_priv = new struct cma_id_private; + if (id_priv == NULL) { + ret = ENOMEM; + goto err1; + } + + RtlZeroMemory(id_priv, sizeof(struct cma_id_private)); + id_priv->refcnt = 1; + id_priv->id.context = context; + + if (!channel) { + id_priv->id.channel = rdma_create_event_channel(); + if (!id_priv->id.channel) { + goto err2; + } + id_priv->sync = 1; + } else { + id_priv->id.channel = channel; + } + id_priv->id.ps = ps; + CompEntryInit(&id_priv->id.channel->channel, &id_priv->id.comp_entry); + + if (ps == RDMA_PS_TCP) { + hr = windata.prov->CreateConnectEndpoint(&id_priv->id.ep.connect); + } else { + hr = windata.prov->CreateDatagramEndpoint(&id_priv->id.ep.datagram); + } + if (FAILED(hr)) { + ret = ibvw_wv_errno(hr); + goto err2; + } + + *id = &id_priv->id; + return 0; + +err2: + delete id_priv; +err1: + ucma_release(); + return hr; +} + +static void ucma_destroy_listen(struct cma_id_private *id_priv) +{ + while (--id_priv->backlog >= 0) { + if (id_priv->req_list[id_priv->backlog] != NULL) { + InterlockedDecrement(&id_priv->refcnt); + rdma_destroy_id(id_priv->req_list[id_priv->backlog]); + } + } + + delete id_priv->req_list; +} + +__declspec(dllexport) +int rdma_destroy_id(struct rdma_cm_id *id) +{ + struct cma_id_private *id_priv; + + id_priv = CONTAINING_RECORD(id, struct cma_id_private, id); + + EnterCriticalSection(&lock); + id_priv->state = cma_destroying; + LeaveCriticalSection(&lock); + + if (id->ps == RDMA_PS_TCP) { + id->ep.connect->CancelOverlappedRequests(); + } else { + id->ep.datagram->CancelOverlappedRequests(); + } + + if (CompEntryCancel(&id->comp_entry) != NULL) { + InterlockedDecrement(&id_priv->refcnt); + } + + if (id_priv->backlog > 0) { + ucma_destroy_listen(id_priv); + } + + if (id_priv->id.ps == RDMA_PS_TCP) { + id_priv->id.ep.connect->Release(); + } else { + id_priv->id.ep.datagram->Release(); + } + + if (id->event) { + rdma_ack_cm_event(id->event); + } + InterlockedDecrement(&id_priv->refcnt); + while (id_priv->refcnt) { + Sleep(0); + } + if (id_priv->sync) { + rdma_destroy_event_channel(id->channel); + } + delete id_priv; + ucma_release(); + return 0; +} + +static int ucma_addrlen(struct sockaddr *addr) +{ + if (addr->sa_family == PF_INET) { + return sizeof(struct sockaddr_in); + } else { + return sizeof(struct sockaddr_in6); + } +} + +static int ucma_get_device(struct cma_id_private *id_priv, uint64_t guid) +{ + struct cma_device *cma_dev; + int i; + + for (i = 0; i < cma_dev_cnt; i++) { + cma_dev = &cma_dev_array[i]; + if (cma_dev->guid == guid) { + id_priv->cma_dev = cma_dev; + id_priv->id.verbs = cma_dev->verbs; + return 0; + } + } + return -1; +} + +static int ucma_query_connect(struct rdma_cm_id *id, struct rdma_conn_param *param) +{ + struct cma_id_private *id_priv; + WV_CONNECT_ATTRIBUTES attr; + HRESULT hr; + int ret; + + id_priv = CONTAINING_RECORD(id, struct cma_id_private, id); + hr = id->ep.connect->Query(&attr); + if (FAILED(hr)) { + return ibvw_wv_errno(hr); + } + + RtlCopyMemory(&id->route.addr.src_addr, &attr.LocalAddress, + sizeof attr.LocalAddress); + RtlCopyMemory(&id->route.addr.dst_addr, &attr.PeerAddress, + sizeof attr.PeerAddress); + + if (param != NULL) { + RtlCopyMemory((void *) param->private_data, attr.Param.Data, + attr.Param.DataLength); + param->private_data_len = (uint8_t) attr.Param.DataLength; + param->responder_resources = (uint8_t) attr.Param.ResponderResources; + param->initiator_depth = (uint8_t) attr.Param.InitiatorDepth; + param->flow_control = 1; + param->retry_count = attr.Param.RetryCount; + param->rnr_retry_count = attr.Param.RnrRetryCount; + } + + if (id_priv->cma_dev == NULL && attr.Device.DeviceGuid != 0) { + ret = ucma_get_device(id_priv, attr.Device.DeviceGuid); + if (ret) { + return ret; + } + + id->route.addr.addr.ibaddr.pkey = attr.Device.Pkey; + id_priv->id.port_num = attr.Device.PortNumber; + } + + return 0; +} + +static int ucma_query_datagram(struct rdma_cm_id *id, struct rdma_ud_param *param) +{ + struct cma_id_private *id_priv; + WV_DATAGRAM_ATTRIBUTES attr; + HRESULT hr; + int ret; + + id_priv = CONTAINING_RECORD(id, struct cma_id_private, id); + hr = id->ep.datagram->Query(&attr); + if (FAILED(hr)) { + return hr; + } + + RtlCopyMemory(&id->route.addr.src_addr, &attr.LocalAddress, + sizeof attr.LocalAddress); + RtlCopyMemory(&id->route.addr.dst_addr, &attr.PeerAddress, + sizeof attr.PeerAddress); + + if (param != NULL) { + RtlCopyMemory((void *) param->private_data, attr.Param.Data, + attr.Param.DataLength); + param->private_data_len = (uint8_t) attr.Param.DataLength; + // ucma_convert_av(&attr.Param.AddressVector, param->ah_attr) + param->qp_num = attr.Param.Qpn; + param->qkey = attr.Param.Qkey; + } + + if (id_priv->cma_dev == NULL && attr.Device.DeviceGuid != 0) { + ret = ucma_get_device(id_priv, attr.Device.DeviceGuid); + if (ret) + return ret; + id->route.addr.addr.ibaddr.pkey = attr.Device.Pkey; + id_priv->id.port_num = attr.Device.PortNumber; + } + return 0; +} + +__declspec(dllexport) +int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr) +{ + struct cma_id_private *id_priv; + HRESULT hr; + int ret; + + if (id->ps == RDMA_PS_TCP) { + hr = id->ep.connect->BindAddress(addr); + if (SUCCEEDED(hr)) { + ret = ucma_query_connect(id, NULL); + } else { + ret = ibvw_wv_errno(hr); + } + } else { + hr = id->ep.datagram->BindAddress(addr); + if (SUCCEEDED(hr)) { + ret = ucma_query_datagram(id, NULL); + } else { + ret = ibvw_wv_errno(hr); + } + } + + if (!ret) { + id_priv = CONTAINING_RECORD(id, struct cma_id_private, id); + id_priv->state = cma_addr_bind; + } + return ret; +} + +static int ucma_complete(struct cma_id_private *id_priv) +{ + int ret; + + if (!id_priv->sync) { + return 0; + } + + if (id_priv->id.event) { + rdma_ack_cm_event(id_priv->id.event); + id_priv->id.event = NULL; + } + + ret = rdma_get_cm_event(id_priv->id.channel, &id_priv->id.event); + if (ret) { + return ret; + } + + return id_priv->id.event->status; +} + +__declspec(dllexport) +int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, + struct sockaddr *dst_addr, int timeout_ms) +{ + struct cma_id_private *id_priv; + WV_SOCKADDR addr; + SOCKET s; + DWORD size; + HRESULT hr; + int ret; + + id_priv = CONTAINING_RECORD(id, struct cma_id_private, id); + if (id_priv->state == cma_idle) { + if (src_addr == NULL) { + if (id->ps == RDMA_PS_TCP) { + s = socket(dst_addr->sa_family, SOCK_STREAM, IPPROTO_TCP); + } else { + s = socket(dst_addr->sa_family, SOCK_DGRAM, IPPROTO_UDP); + } + if (s == INVALID_SOCKET) { + return rdmaw_wsa_errno(WSAGetLastError()); + } + + hr = WSAIoctl(s, SIO_ROUTING_INTERFACE_QUERY, dst_addr, ucma_addrlen(dst_addr), + &addr, sizeof addr, &size, NULL, NULL); + closesocket(s); + if (FAILED(hr)) { + return rdmaw_wsa_errno(WSAGetLastError()); + } + src_addr = &addr.Sa; + } + + ret = rdma_bind_addr(id, src_addr); + if (ret) { + return ret; + } + } + + RtlCopyMemory(&id->route.addr.dst_addr, dst_addr, ucma_addrlen(dst_addr)); + id_priv->state = cma_addr_resolve; + + id_priv->refcnt++; + CompEntryPost(&id->comp_entry); + return ucma_complete(id_priv); +} + +__declspec(dllexport) +int rdma_resolve_route(struct rdma_cm_id *id, int timeout_ms) +{ + struct cma_id_private *id_priv; + IBAT_PATH_BLOB path; + HRESULT hr; + + hr = IBAT::ResolvePath(&id->route.addr.src_addr, &id->route.addr.dst_addr, + &path, timeout_ms); + if (FAILED(hr)) { + return ibvw_wv_errno(hr); + } + + hr = (id->ps == RDMA_PS_TCP) ? + id->ep.connect->Modify(WV_EP_OPTION_ROUTE, &path, sizeof path) : + id->ep.datagram->Modify(WV_EP_OPTION_ROUTE, &path, sizeof path); + if (FAILED(hr)) { + return ibvw_wv_errno(hr); + } + + id_priv = CONTAINING_RECORD(id, struct cma_id_private, id); + id_priv->state = cma_route_resolve; + + id_priv->refcnt++; + CompEntryPost(&id->comp_entry); + return ucma_complete(id_priv); +} + +static int ucma_modify_qp_init(struct cma_id_private *id_priv, struct ibv_qp *qp) +{ + struct ibv_qp_attr qp_attr; + UINT16 index; + HRESULT hr; + + RtlZeroMemory(&qp_attr, sizeof qp_attr); + qp_attr.qp_state = IBV_QPS_INIT; + qp_attr.port_num = id_priv->id.port_num; + hr = qp->context->cmd_if->FindPkey(id_priv->id.port_num, + id_priv->id.route.addr.addr.ibaddr.pkey, + &index); + if (FAILED(hr)) { + return ibvw_wv_errno(hr); + } + + qp_attr.pkey_index = index; + return ibv_modify_qp(qp, &qp_attr, (enum ibv_qp_attr_mask) + (IBV_QP_STATE | IBV_QP_PKEY_INDEX | IBV_QP_PORT)); +} + +static int ucma_init_ud_qp(struct cma_id_private *id_priv, struct ibv_qp *qp) +{ + struct ibv_qp_attr qp_attr; + int qp_attr_mask, ret; + + ret = ucma_modify_qp_init(id_priv, qp); + if (ret) { + return ret; + } + + qp_attr.qp_state = IBV_QPS_RTR; + ret = ibv_modify_qp(qp, &qp_attr, IBV_QP_STATE); + if (ret) { + return ret; + } + + qp_attr.qp_state = IBV_QPS_RTS; + qp_attr.sq_psn = 0; + return ibv_modify_qp(qp, &qp_attr, (enum ibv_qp_attr_mask) + (IBV_QP_STATE | IBV_QP_SQ_PSN)); +} + +static void ucma_destroy_cqs(struct rdma_cm_id *id) +{ + if (id->recv_cq) + ibv_destroy_cq(id->recv_cq); + + if (id->recv_cq_channel) + ibv_destroy_comp_channel(id->recv_cq_channel); + + if (id->send_cq) + ibv_destroy_cq(id->send_cq); + + if (id->send_cq_channel) + ibv_destroy_comp_channel(id->send_cq_channel); +} + +static int ucma_create_cqs(struct rdma_cm_id *id, struct ibv_qp_init_attr *attr) +{ + if (!attr->recv_cq) { + id->recv_cq_channel = ibv_create_comp_channel(id->verbs); + if (!id->recv_cq_channel) + goto err; + + id->recv_cq = ibv_create_cq(id->verbs, attr->cap.max_recv_wr, + id, id->recv_cq_channel, 0); + if (!id->recv_cq) + goto err; + + attr->recv_cq = id->recv_cq; + } + + if (!attr->send_cq) { + id->send_cq_channel = ibv_create_comp_channel(id->verbs); + if (!id->send_cq_channel) + goto err; + + id->send_cq = ibv_create_cq(id->verbs, attr->cap.max_send_wr, + id, id->send_cq_channel, 0); + if (!id->send_cq) + goto err; + + attr->send_cq = id->send_cq; + } + + return 0; +err: + ucma_destroy_cqs(id); + return rdma_seterrno(ENOMEM); +} + +__declspec(dllexport) +int rdma_create_qp(struct rdma_cm_id *id, struct ibv_pd *pd, + struct ibv_qp_init_attr *qp_init_attr) +{ + struct cma_id_private *id_priv; + struct ibv_qp *qp; + int ret; + + id_priv = CONTAINING_RECORD(id, struct cma_id_private, id); + if (!pd) { + pd = id_priv->cma_dev->pd; + } else if (id->verbs != pd->context) { + return rdma_seterrno(EINVAL); + } + + ret = ucma_create_cqs(id, qp_init_attr); + if (ret) { + return ret; + } + + qp = ibv_create_qp(pd, qp_init_attr); + if (!qp) { + ret = rdma_seterrno(ENOMEM); + goto err1; + } + + if (id->ps == RDMA_PS_TCP) { + ret = ucma_modify_qp_init(id_priv, qp); + } else { + ret = ucma_init_ud_qp(id_priv, qp); + } + if (ret) { + goto err2; + } + + id->qp = qp; + return 0; +err2: + ibv_destroy_qp(qp); +err1: + ucma_destroy_cqs(id); + return ret; +} + +__declspec(dllexport) +void rdma_destroy_qp(struct rdma_cm_id *id) +{ + ibv_destroy_qp(id->qp); + ucma_destroy_cqs(id); +} + +static int ucma_valid_param(struct cma_id_private *id_priv, + struct rdma_conn_param *param) +{ + if (id_priv->id.ps != RDMA_PS_TCP) { + return 0; + } + + if (!id_priv->id.qp && !param) { + return rdma_seterrno(EINVAL); + } + + if (!param) { + return 0; + } + + if ((param->responder_resources != RDMA_MAX_RESP_RES) && + (param->responder_resources > id_priv->cma_dev->max_responder_resources)) { + return rdma_seterrno(EINVAL); + } + + if ((param->initiator_depth != RDMA_MAX_INIT_DEPTH) && + (param->initiator_depth > id_priv->cma_dev->max_initiator_depth)) { + return rdma_seterrno(EINVAL); + } + + return 0; +} + +static void ucma_set_connect_attr(struct cma_id_private *id_priv, + struct rdma_conn_param *param, + WV_CONNECT_PARAM *attr) +{ + RtlZeroMemory(attr, sizeof *attr); + + attr->ResponderResources = id_priv->responder_resources; + attr->InitiatorDepth = id_priv->initiator_depth; + + if (param) { + attr->RetryCount = param->retry_count; + attr->RnrRetryCount = param->rnr_retry_count; + if ((attr->DataLength = param->private_data_len)) { + RtlCopyMemory(attr->Data, param->private_data, attr->DataLength); + } + } else { + attr->RetryCount = 7; + attr->RnrRetryCount = 7; + } +} + +__declspec(dllexport) +int rdma_connect(struct rdma_cm_id *id, struct rdma_conn_param *conn_param) +{ + struct cma_id_private *id_priv; + WV_CONNECT_PARAM attr; + HRESULT hr; + int ret; + + id_priv = CONTAINING_RECORD(id, struct cma_id_private, id); + ret = ucma_valid_param(id_priv, conn_param); + if (ret) { + return ret; + } + + if (conn_param && conn_param->responder_resources != RDMA_MAX_RESP_RES) { + id_priv->responder_resources = conn_param->responder_resources; + } else { + id_priv->responder_resources = id_priv->cma_dev->max_responder_resources; + } + if (conn_param && conn_param->initiator_depth != RDMA_MAX_INIT_DEPTH) { + id_priv->initiator_depth = conn_param->initiator_depth; + } else { + id_priv->initiator_depth = id_priv->cma_dev->max_initiator_depth; + } + + ucma_set_connect_attr(id_priv, conn_param, &attr); + + id_priv->state = cma_active_connect; + id_priv->refcnt++; + id->comp_entry.Busy = 1; + hr = id->ep.connect->Connect(id->qp->conn_handle, &id->route.addr.dst_addr, + &attr, &id->comp_entry.Overlap); + if (FAILED(hr) && hr != WV_IO_PENDING) { + id_priv->refcnt--; + id->comp_entry.Busy = 0; + id_priv->state = cma_route_resolve; + return ibvw_wv_errno(hr); + } + + return ucma_complete(id_priv); +} + +static int ucma_get_request(struct cma_id_private *listen, int index) +{ + struct cma_id_private *id_priv = NULL; + HRESULT hr; + int ret; + + EnterCriticalSection(&lock); + if (listen->state != cma_listening) { + ret = ibvw_wv_errno(WV_INVALID_PARAMETER); + goto err1; + } + + InterlockedIncrement(&listen->refcnt); + ret = rdma_create_id(listen->id.channel, &listen->req_list[index], + listen, listen->id.ps); + if (ret) { + goto err2; + } + + id_priv = CONTAINING_RECORD(listen->req_list[index], struct cma_id_private, id); + id_priv->index = index; + id_priv->state = cma_get_request; + + id_priv->refcnt++; + id_priv->id.comp_entry.Busy = 1; + if (listen->id.ps == RDMA_PS_TCP) { + hr = listen->id.ep.connect->GetRequest(id_priv->id.ep.connect, + &id_priv->id.comp_entry.Overlap); + } else { + hr = listen->id.ep.datagram->GetRequest(id_priv->id.ep.datagram, + &id_priv->id.comp_entry.Overlap); + } + if (FAILED(hr) && hr != WV_IO_PENDING) { + ret = ibvw_wv_errno(hr); + id_priv->id.comp_entry.Busy = 0; + id_priv->refcnt--; + goto err2; + } + LeaveCriticalSection(&lock); + + return 0; + +err2: + InterlockedDecrement(&listen->refcnt); +err1: + LeaveCriticalSection(&lock); + if (id_priv != NULL) { + rdma_destroy_id(&id_priv->id); + } + return ret; +} + +__declspec(dllexport) +int rdma_listen(struct rdma_cm_id *id, int backlog) +{ + struct cma_id_private *id_priv, *req_id; + HRESULT hr; + int i, ret; + + if (backlog <= 0) { + backlog = CMA_DEFAULT_BACKLOG; + } + + id_priv = CONTAINING_RECORD(id, struct cma_id_private, id); + id_priv->req_list = new struct rdma_cm_id*[backlog]; + if (id_priv->req_list == NULL) { + return -1; + } + + RtlZeroMemory(id_priv->req_list, sizeof(struct rdma_cm_id *) * backlog); + id_priv->backlog = backlog; + + id_priv->state = cma_listening; + hr = (id->ps == RDMA_PS_TCP) ? + id->ep.connect->Listen(backlog) : id->ep.datagram->Listen(backlog); + if (FAILED(hr)) { + return ibvw_wv_errno(hr); + } + + for (i = 0; i < backlog; i++) { + ret = ucma_get_request(id_priv, i); + if (ret) { + return ret; + } + } + + return 0; +} + +__declspec(dllexport) +int rdma_get_request(struct rdma_cm_id *listen, struct rdma_cm_id **id) +{ + struct cma_id_private *id_priv; + struct rdma_cm_event *event; + int ret; + + id_priv = CONTAINING_RECORD(listen, struct cma_id_private, id); + if (!id_priv->sync) { + return rdma_seterrno(EINVAL); + } + + if (listen->event) { + rdma_ack_cm_event(listen->event); + listen->event = NULL; + } + + ret = rdma_get_cm_event(listen->channel, &event); + if (ret) + return ret; + + if (event->status) { + ret = rdma_seterrno(event->status); + goto err; + } + + if (event->event != RDMA_CM_EVENT_CONNECT_REQUEST) { + ret = rdma_seterrno(EINVAL); + goto err; + } + + if (id_priv->qp_init_attr) { + ret = rdma_create_qp(event->id, id_priv->pd, id_priv->qp_init_attr); + if (ret) + goto err; + } + + *id = event->id; + (*id)->event = event; + return 0; + +err: + listen->event = event; + return ret; +} + +__declspec(dllexport) +int rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param) +{ + struct cma_id_private *id_priv; + WV_CONNECT_PARAM attr; + HRESULT hr; + int ret; + + id_priv = CONTAINING_RECORD(id, struct cma_id_private, id); + ret = ucma_valid_param(id_priv, conn_param); + if (ret) { + return ret; + } + + if (!conn_param || conn_param->initiator_depth == RDMA_MAX_INIT_DEPTH) { + id_priv->initiator_depth = min(id_priv->initiator_depth, + id_priv->cma_dev->max_initiator_depth); + } else { + id_priv->initiator_depth = conn_param->initiator_depth; + } + if (!conn_param || conn_param->responder_resources == RDMA_MAX_RESP_RES) { + id_priv->responder_resources = min(id_priv->responder_resources, + id_priv->cma_dev->max_responder_resources); + } else { + id_priv->responder_resources = conn_param->responder_resources; + } + + ucma_set_connect_attr(id_priv, conn_param, &attr); + + id_priv->state = cma_accepting; + id_priv->refcnt++; + id->comp_entry.Busy = 1; + hr = id->ep.connect->Accept(id->qp->conn_handle, &attr, + &id->comp_entry.Overlap); + if (FAILED(hr) && hr != WV_IO_PENDING) { + id_priv->refcnt--; + id->comp_entry.Busy = 0; + id_priv->state = cma_disconnected; + return ibvw_wv_errno(hr); + } + + return ucma_complete(id_priv); +} + +__declspec(dllexport) +int rdma_reject(struct rdma_cm_id *id, const void *private_data, + uint8_t private_data_len) +{ + struct cma_id_private *id_priv; + HRESULT hr; + + id_priv = CONTAINING_RECORD(id, struct cma_id_private, id); + id_priv->state = cma_disconnected; + hr = id->ep.connect->Reject(private_data, private_data_len); + if (FAILED(hr)) { + return ibvw_wv_errno(hr); + } + return 0; +} + +__declspec(dllexport) +int rdma_notify(struct rdma_cm_id *id, enum ibv_event_type event) +{ + return 0; +} + +__declspec(dllexport) +int rdma_disconnect(struct rdma_cm_id *id) +{ + struct cma_id_private *id_priv; + HRESULT hr; + + id_priv = CONTAINING_RECORD(id, struct cma_id_private, id); + if (id_priv->state == cma_connected) { + id_priv->state = cma_active_disconnect; + } else { + id_priv->state = cma_disconnected; + } + hr = id->ep.connect->Disconnect(NULL); + if (FAILED(hr)) { + return ibvw_wv_errno(hr); + } + + return ucma_complete(id_priv); +} + +__declspec(dllexport) +int rdma_ack_cm_event(struct rdma_cm_event *event) +{ + struct cma_event *evt; + struct cma_id_private *listen; + + evt = CONTAINING_RECORD(event, struct cma_event, event); + InterlockedDecrement(&evt->id_priv->refcnt); + if (evt->event.listen_id) { + listen = CONTAINING_RECORD(evt->event.listen_id, struct cma_id_private, id); + InterlockedDecrement(&listen->refcnt); + } + delete evt; + return 0; +} + +static int ucma_process_conn_req(struct cma_event *event) +{ + struct cma_id_private *listen, *id_priv; + struct cma_event_channel *chan; + + listen = (struct cma_id_private *) event->id_priv->id.context; + id_priv = event->id_priv; + + ucma_get_request(listen, id_priv->index); + + if (event->event.status) { + goto err; + } + + if (listen->sync) { + event->event.status = rdma_migrate_id(&id_priv->id, NULL); + if (event->event.status) { + goto err; + } + } + + event->event.status = ucma_query_connect(&id_priv->id, + &event->event.param.conn); + if (event->event.status) { + goto err; + } + + event->event.event = RDMA_CM_EVENT_CONNECT_REQUEST; + id_priv->state = cma_passive_connect; + event->event.listen_id = &listen->id; + id_priv->initiator_depth = event->event.param.conn.initiator_depth; + id_priv->responder_resources = event->event.param.conn.responder_resources; + + return 0; + +err: + InterlockedDecrement(&listen->refcnt); + InterlockedDecrement(&id_priv->refcnt); + rdma_destroy_id(&id_priv->id); + return event->event.status; +} + +static int ucma_process_conn_resp(struct cma_event *event) +{ + struct rdma_cm_id *id; + WV_CONNECT_PARAM attr; + HRESULT hr; + + if (event->event.status) { + goto err; + } + + RtlZeroMemory(&attr, sizeof(attr)); + event->id_priv->state = cma_accepting; + + id = &event->id_priv->id; + id->comp_entry.Busy = 1; + hr = id->ep.connect->Accept(id->qp->conn_handle, &attr, + &id->comp_entry.Overlap); + if (FAILED(hr) && hr != WV_IO_PENDING) { + id->comp_entry.Busy = 0; + event->event.status = hr; + goto err; + } + + return EINPROGRESS; + +err: + event->event.event = (event->event.status == WV_REJECTED) ? + RDMA_CM_EVENT_REJECTED : + RDMA_CM_EVENT_CONNECT_ERROR; + event->id_priv->state = cma_disconnected; + return 0; +} + +static void ucma_process_establish(struct cma_event *event) +{ + struct cma_id_private *id_priv = event->id_priv; + + if (!event->event.status) { + event->event.status = ucma_query_connect(&id_priv->id, + &event->event.param.conn); + } + + if (!event->event.status) { + event->event.event = RDMA_CM_EVENT_ESTABLISHED; + + id_priv->state = cma_connected; + InterlockedIncrement(&id_priv->refcnt); + id_priv->id.comp_entry.Busy = 1; + id_priv->id.ep.connect->NotifyDisconnect(&id_priv->id.comp_entry.Overlap); + } else { + event->event.event = RDMA_CM_EVENT_CONNECT_ERROR; + event->id_priv->state = cma_disconnected; + } +} + +static int ucma_process_event(struct cma_event *event) +{ + struct cma_id_private *listen, *id_priv; + WV_CONNECT_ATTRIBUTES attr; + int ret = 0; + + id_priv = event->id_priv; + + EnterCriticalSection(&lock); + switch (id_priv->state) { + case cma_get_request: + listen = (struct cma_id_private *) id_priv->id.context; + if (listen->state != cma_listening) { + InterlockedDecrement(&id_priv->refcnt); + ret = ECANCELED; + break; + } + + listen->req_list[id_priv->index] = NULL; + LeaveCriticalSection(&lock); + return ucma_process_conn_req(event); + case cma_addr_resolve: + event->event.event = RDMA_CM_EVENT_ADDR_RESOLVED; + break; + case cma_route_resolve: + event->event.event = RDMA_CM_EVENT_ROUTE_RESOLVED; + break; + case cma_active_connect: + ret = ucma_process_conn_resp(event); + break; + case cma_accepting: + ucma_process_establish(event); + break; + case cma_connected: + event->event.event = RDMA_CM_EVENT_DISCONNECTED; + id_priv->state = cma_passive_disconnect; + break; + case cma_active_disconnect: + event->event.event = RDMA_CM_EVENT_DISCONNECTED; + id_priv->state = cma_disconnected; + break; + default: + InterlockedDecrement(&id_priv->refcnt); + ret = ECANCELED; + } + LeaveCriticalSection(&lock); + + return ret; +} + +__declspec(dllexport) +int rdma_get_cm_event(struct rdma_event_channel *channel, + struct rdma_cm_event **event) +{ + struct cma_event *evt; + struct rdma_cm_id *id; + COMP_ENTRY *entry; + DWORD bytes, ret; + + evt = new struct cma_event; + if (evt == NULL) { + return -1; + } + + do { + RtlZeroMemory(evt, sizeof(struct cma_event)); + + ret = CompChannelPoll(&channel->channel, &entry); + if (ret) { + delete evt; + return ret; + } + + id = CONTAINING_RECORD(entry, struct rdma_cm_id, comp_entry); + evt->id_priv = CONTAINING_RECORD(id, struct cma_id_private, id); + evt->event.id = id; + evt->event.param.conn.private_data = evt->private_data; + evt->event.param.conn.private_data_len = RDMA_MAX_PRIVATE_DATA; + + evt->event.status = id->ep.connect-> + GetOverlappedResult(&entry->Overlap, &bytes, FALSE); + + ret = ucma_process_event(evt); + } while (ret); + + *event = &evt->event; + return 0; +} + + +__declspec(dllexport) +int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr, + void *context) +{ + return rdma_seterrno(ENOSYS); +} + +__declspec(dllexport) +int rdma_leave_multicast(struct rdma_cm_id *id, struct sockaddr *addr) +{ + return rdma_seterrno(ENOSYS); +} + +__declspec(dllexport) +const char *rdma_event_str(enum rdma_cm_event_type event) +{ + switch (event) { + case RDMA_CM_EVENT_ADDR_RESOLVED: + return "RDMA_CM_EVENT_ADDR_RESOLVED"; + case RDMA_CM_EVENT_ADDR_ERROR: + return "RDMA_CM_EVENT_ADDR_ERROR"; + case RDMA_CM_EVENT_ROUTE_RESOLVED: + return "RDMA_CM_EVENT_ROUTE_RESOLVED"; + case RDMA_CM_EVENT_ROUTE_ERROR: + return "RDMA_CM_EVENT_ROUTE_ERROR"; + case RDMA_CM_EVENT_CONNECT_REQUEST: + return "RDMA_CM_EVENT_CONNECT_REQUEST"; + case RDMA_CM_EVENT_CONNECT_RESPONSE: + return "RDMA_CM_EVENT_CONNECT_RESPONSE"; + case RDMA_CM_EVENT_CONNECT_ERROR: + return "RDMA_CM_EVENT_CONNECT_ERROR"; + case RDMA_CM_EVENT_UNREACHABLE: + return "RDMA_CM_EVENT_UNREACHABLE"; + case RDMA_CM_EVENT_REJECTED: + return "RDMA_CM_EVENT_REJECTED"; + case RDMA_CM_EVENT_ESTABLISHED: + return "RDMA_CM_EVENT_ESTABLISHED"; + case RDMA_CM_EVENT_DISCONNECTED: + return "RDMA_CM_EVENT_DISCONNECTED"; + case RDMA_CM_EVENT_DEVICE_REMOVAL: + return "RDMA_CM_EVENT_DEVICE_REMOVAL"; + case RDMA_CM_EVENT_MULTICAST_JOIN: + return "RDMA_CM_EVENT_MULTICAST_JOIN"; + case RDMA_CM_EVENT_MULTICAST_ERROR: + return "RDMA_CM_EVENT_MULTICAST_ERROR"; + case RDMA_CM_EVENT_ADDR_CHANGE: + return "RDMA_CM_EVENT_ADDR_CHANGE"; + case RDMA_CM_EVENT_TIMEWAIT_EXIT: + return "RDMA_CM_EVENT_TIMEWAIT_EXIT"; + default: + return "UNKNOWN EVENT"; + } +} + +__declspec(dllexport) +int rdma_set_option(struct rdma_cm_id *id, int level, int optname, + void *optval, size_t optlen) +{ + return rdma_seterrno(ENOSYS); +} + +__declspec(dllexport) +int rdma_migrate_id(struct rdma_cm_id *id, struct rdma_event_channel *channel) +{ + struct cma_id_private *id_priv; + int sync; + + id_priv = CONTAINING_RECORD(id, struct cma_id_private, id); + if (id_priv->sync && !channel) { + return rdma_seterrno(EINVAL); + } + + if (id->comp_entry.Busy) { + return rdma_seterrno(EBUSY); + } + + if ((sync = (channel == NULL))) { + channel = rdma_create_event_channel(); + if (!channel) { + return rdma_seterrno(ENOMEM); + } + } + + if (id_priv->sync) { + if (id->event) { + rdma_ack_cm_event(id->event); + id->event = NULL; + } + rdma_destroy_event_channel(id->channel); + } + + id_priv->sync = sync; + id->channel = channel; + id->comp_entry.Channel = &channel->channel; + return 0; +} + +static int ucma_passive_ep(struct rdma_cm_id *id, struct rdma_addrinfo *res, + struct ibv_pd *pd, struct ibv_qp_init_attr *qp_init_attr) +{ + struct cma_id_private *id_priv; + int ret; + + ret = rdma_bind_addr(id, res->ai_src_addr); + if (ret) + return ret; + + id_priv = CONTAINING_RECORD(id, struct cma_id_private, id); + id_priv->pd = pd; + + if (qp_init_attr) { + id_priv->qp_init_attr = new struct ibv_qp_init_attr; + if (!id_priv->qp_init_attr) + return rdma_seterrno(ENOMEM); + + *id_priv->qp_init_attr = *qp_init_attr; + id_priv->qp_init_attr->qp_type = (enum ibv_qp_type) res->ai_qp_type; + } + + return 0; +} + +__declspec(dllexport) +int rdma_create_ep(struct rdma_cm_id **id, struct rdma_addrinfo *res, + struct ibv_pd *pd, struct ibv_qp_init_attr *qp_init_attr) +{ + struct rdma_cm_id *cm_id; + int ret; + + ret = rdma_create_id(NULL, &cm_id, NULL, (enum rdma_port_space) res->ai_port_space); + if (ret) + return ret; + + if (res->ai_flags & RAI_PASSIVE) { + ret = ucma_passive_ep(cm_id, res, pd, qp_init_attr); + if (ret) + goto err; + goto out; + } + + ret = rdma_resolve_addr(cm_id, res->ai_src_addr, res->ai_dst_addr, 2000); + if (ret) + goto err; + + ret = rdma_resolve_route(cm_id, 2000); + if (ret) + goto err; + + qp_init_attr->qp_type = (enum ibv_qp_type) res->ai_qp_type; + ret = rdma_create_qp(cm_id, pd, qp_init_attr); + if (ret) + goto err; + +out: + *id = cm_id; + return 0; + +err: + rdma_destroy_ep(cm_id); + return ret; +} + +__declspec(dllexport) +void rdma_destroy_ep(struct rdma_cm_id *id) +{ + struct cma_id_private *id_priv; + + if (id->qp) + rdma_destroy_qp(id); + + id_priv = CONTAINING_RECORD(id, struct cma_id_private, id); + if (id_priv->qp_init_attr) { + delete id_priv->qp_init_attr; + } + rdma_destroy_id(id); +} + +__declspec(dllexport) +int rdmaw_wsa_errno(int wsa_err) +{ + switch (wsa_err) { + case 0: return 0; + case WSAEWOULDBLOCK: _set_errno(EWOULDBLOCK); break; + case WSAEINPROGRESS: _set_errno(EINPROGRESS); break; + case WSAEALREADY: _set_errno(EALREADY); break; + case WSAENOTSOCK: _set_errno(ENOTSOCK); break; + case WSAEDESTADDRREQ: _set_errno(EDESTADDRREQ); break; + case WSAEMSGSIZE: _set_errno(EMSGSIZE); break; + case WSAEPROTOTYPE: _set_errno(EPROTOTYPE); break; + case WSAENOPROTOOPT: _set_errno(ENOPROTOOPT); break; + case WSAEPROTONOSUPPORT:_set_errno(EPROTONOSUPPORT); break; + case WSAEOPNOTSUPP: _set_errno(EOPNOTSUPP); break; + case WSAEAFNOSUPPORT: _set_errno(EAFNOSUPPORT); break; + case WSAEADDRINUSE: _set_errno(EADDRINUSE); break; + case WSAEADDRNOTAVAIL: _set_errno(EADDRNOTAVAIL); break; + case WSAENETDOWN: _set_errno(ENETDOWN); break; + case WSAENETUNREACH: _set_errno(ENETUNREACH); break; + case WSAENETRESET: _set_errno(ENETRESET); break; + case WSAECONNABORTED: _set_errno(ECONNABORTED); break; + case WSAECONNRESET: _set_errno(ECONNRESET); break; + case WSAENOBUFS: _set_errno(ENOBUFS); break; + case WSAEISCONN: _set_errno(EISCONN); break; + case WSAENOTCONN: _set_errno(ENOTCONN); break; + case WSAETIMEDOUT: _set_errno(ETIMEDOUT); break; + case WSAECONNREFUSED: _set_errno(ECONNREFUSED); break; + case WSAELOOP: _set_errno(ELOOP); break; + case WSAENAMETOOLONG: _set_errno(ENAMETOOLONG); break; + case WSAEHOSTUNREACH: _set_errno(EHOSTUNREACH); break; + case WSAENOTEMPTY: _set_errno(ENOTEMPTY); break; + } + return -1; +} diff --git a/branches/WOF2-3/ulp/librdmacm/src/cma.h b/branches/WOF2-3/ulp/librdmacm/src/cma.h new file mode 100644 index 00000000..918a7936 --- /dev/null +++ b/branches/WOF2-3/ulp/librdmacm/src/cma.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2008-2009 Intel Corp. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef CMA_H +#define CMA_H + +extern CRITICAL_SECTION lock; +extern HANDLE heap; + +void ucma_cleanup(); + +__inline void* __cdecl operator new(size_t size) +{ + return HeapAlloc(heap, 0, size); +} + +__inline void __cdecl operator delete(void *pObj) +{ + HeapFree(heap, 0, pObj); +} + +#endif /* CMA_H */ diff --git a/branches/WOF2-3/ulp/librdmacm/src/cma.rc b/branches/WOF2-3/ulp/librdmacm/src/cma.rc new file mode 100644 index 00000000..fd205458 --- /dev/null +++ b/branches/WOF2-3/ulp/librdmacm/src/cma.rc @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + +#include + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef _DEBUG_ +#define VER_FILEDESCRIPTION_STR "LibRdmaCm (Debug)" +#define VER_INTERNALNAME_STR "librdmacmd.dll" +#define VER_ORIGINALFILENAME_STR "librdmacmd.dll" +#else +#define VER_FILEDESCRIPTION_STR "LibRdmaCm" +#define VER_INTERNALNAME_STR "librdmacm.dll" +#define VER_ORIGINALFILENAME_STR "librdmacm.dll" +#endif + +#include diff --git a/branches/WOF2-3/ulp/librdmacm/src/cma_export.def b/branches/WOF2-3/ulp/librdmacm/src/cma_export.def new file mode 100644 index 00000000..7a2b1ec4 --- /dev/null +++ b/branches/WOF2-3/ulp/librdmacm/src/cma_export.def @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +LIBRARY LIBRDMACM.DLL + +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE diff --git a/branches/WOF2-3/ulp/librdmacm/src/cma_exports.src b/branches/WOF2-3/ulp/librdmacm/src/cma_exports.src new file mode 100644 index 00000000..2d6b3364 --- /dev/null +++ b/branches/WOF2-3/ulp/librdmacm/src/cma_exports.src @@ -0,0 +1,37 @@ +#if DBG +LIBRARY librdmacmd.dll +#else +LIBRARY librdmacm.dll +#endif + +#ifndef _WIN64 +EXPORTS +rdma_create_event_channel +rdma_destroy_event_channel +rdma_create_id +rdma_destroy_id +rdma_bind_addr +rdma_resolve_addr +rdma_resolve_route +rdma_create_qp +rdma_destroy_qp +rdma_connect +rdma_listen +rdma_accept +rdma_reject +rdma_notify +rdma_disconnect +rdma_join_multicast +rdma_leave_multicast +rdma_get_cm_event +rdma_ack_cm_event +rdma_get_devices +rdma_free_devices +rdma_event_str +rdma_set_option +rdma_migrate_id +rdma_getaddrinfo +rdma_freeaddrinfo +rdma_get_request +rdmaw_wsa_errno +#endif diff --git a/branches/WOF2-3/ulp/librdmacm/src/cma_main.cpp b/branches/WOF2-3/ulp/librdmacm/src/cma_main.cpp new file mode 100644 index 00000000..0084633d --- /dev/null +++ b/branches/WOF2-3/ulp/librdmacm/src/cma_main.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2008-2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include "cma.h" + +CRITICAL_SECTION lock; +HANDLE heap; + +BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) +{ + UNREFERENCED_PARAMETER(hInstance); + UNREFERENCED_PARAMETER(lpReserved); + + switch (dwReason) { + case DLL_PROCESS_ATTACH: + heap = HeapCreate(0, 0, 0); + if (heap == NULL) { + return FALSE; + } + InitializeCriticalSection(&lock); + break; + case DLL_PROCESS_DETACH: + DeleteCriticalSection(&lock); + HeapDestroy(heap); + break; + default: + break; + } + + return TRUE; +} diff --git a/branches/WOF2-3/ulp/librdmacm/src/makefile b/branches/WOF2-3/ulp/librdmacm/src/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-3/ulp/librdmacm/src/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\inc\openib.def diff --git a/branches/WOF2-3/ulp/nd/dirs b/branches/WOF2-3/ulp/nd/dirs new file mode 100644 index 00000000..db5a8974 --- /dev/null +++ b/branches/WOF2-3/ulp/nd/dirs @@ -0,0 +1,2 @@ +DIRS=\ + user diff --git a/branches/WOF2-3/ulp/nd/user/NdAdapter.cpp b/branches/WOF2-3/ulp/nd/user/NdAdapter.cpp new file mode 100644 index 00000000..6a7a065d --- /dev/null +++ b/branches/WOF2-3/ulp/nd/user/NdAdapter.cpp @@ -0,0 +1,953 @@ +/* + * Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id:$ + */ + +#include "NdCq.h" +#include "NdAdapter.h" +#include "NdMw.h" +#include "NdEndpoint.h" +#include "NdProv.h" +#include "NdMr.h" +#include "NdListen.h" +#include "NdConnector.h" + +#include "al_dev.h" +#pragma warning( push, 3 ) +#include "winternl.h" +#pragma warning( pop ) + +#include +#include +#include + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "NdAdapter.tmh" +#endif + + +namespace NetworkDirect +{ + +/////////////////////////////////////////////////////////////////////////////// +// +// HPC Pack 2008 Beta 2 SPI +// +/////////////////////////////////////////////////////////////////////////////// + + +CAdapter::CAdapter(void) : + m_nRef( 1 ), + m_hSync( INVALID_HANDLE_VALUE ), + m_hAsync( INVALID_HANDLE_VALUE ), + m_hCa( 0 ), + m_hPd( 0 ), + m_uCa( NULL ), + m_uPd( NULL ), + m_pParent( NULL ) +{ + m_Ifc.h_uvp_lib = NULL; +} + +CAdapter::~CAdapter(void) +{ + if( m_hPd ) + DeallocPd(); + + if( m_hCa ) + CloseCa(); + + if( m_hSync != INVALID_HANDLE_VALUE ) + CloseHandle( m_hSync ); + + if( m_hAsync != INVALID_HANDLE_VALUE ) + CloseHandle( m_hAsync ); + + if( m_pParent ) + m_pParent->Release(); +} + +HRESULT CAdapter::Initialize( + CProvider* pParent, + const struct sockaddr* pAddr, + const IBAT_PORT_RECORD* pPortRecord ) +{ + m_pParent = pParent; + m_pParent->AddRef(); + + HRESULT hr = OpenFiles(); + if( FAILED( hr ) ) + return hr; + + hr = OpenCa( pPortRecord->CaGuid ); + if( FAILED( hr ) ) + return hr; + + hr = AllocPd(); + if( FAILED( hr ) ) + return hr; + + m_PortNum = pPortRecord->PortNum; + m_PortGuid = pPortRecord->PortGuid; + + switch( pAddr->sa_family ) + { + case AF_INET: + RtlCopyMemory( &m_Addr.v4, pAddr, sizeof(m_Addr.v4) ); + ND_PRINT( TRACE_LEVEL_INFORMATION, ND_DBG_NDI, + ("Local address: IP %#x, port %#hx\n", + cl_hton32(m_Addr.v4.sin_addr.S_un.S_addr), cl_hton16(m_Addr.v4.sin_port) ) ); + break; + case AF_INET6: + RtlCopyMemory( &m_Addr.v6, pAddr, sizeof(m_Addr.v6) ); + break; + default: + return ND_INVALID_ADDRESS; + } + return S_OK; +} + +HRESULT CAdapter::Create( + CProvider* pParent, + const struct sockaddr* pAddr, + const IBAT_PORT_RECORD* pPortRecord, + __out INDAdapter** ppAdapter + ) +{ + CAdapter* pAdapter = new CAdapter(); + if( pAdapter == NULL ) + return ND_NO_MEMORY; + + HRESULT hr = pAdapter->Initialize( pParent, pAddr, pPortRecord ); + if( FAILED( hr ) ) + { + delete pAdapter; + return hr; + } + + *ppAdapter = pAdapter; + return ND_SUCCESS; +} + +// IUnknown overrides. +HRESULT CAdapter::QueryInterface( + const IID &riid, + LPVOID FAR *ppvObj ) +{ + if( IsEqualIID( riid, IID_IUnknown ) ) + { + *ppvObj = this; + return S_OK; + } + + if( IsEqualIID( riid, IID_INDAdapter ) ) + { + *ppvObj = this; + return S_OK; + } + + return E_NOINTERFACE; +} + +ULONG CAdapter::AddRef(void) +{ + return InterlockedIncrement( &m_nRef ); +} + +ULONG CAdapter::Release(void) +{ + ULONG ref = InterlockedDecrement( &m_nRef ); + if( ref == 0 ) + delete this; + + return ref; +} + +// *** INDOverlapped methods *** +HRESULT CAdapter::CancelOverlappedRequests(void) +{ + // Memory registration IOCTLs can't be cancelled. + return S_OK; +} + +HRESULT CAdapter::GetOverlappedResult( + __inout OVERLAPPED *pOverlapped, + __out SIZE_T *pNumberOfBytesTransferred, + __in BOOL bWait + ) +{ + ND_ENTER( ND_DBG_NDI ); + + *pNumberOfBytesTransferred = 0; + ::GetOverlappedResult( + m_hAsync, + pOverlapped, + (DWORD*)pNumberOfBytesTransferred, + bWait ); + return (HRESULT)pOverlapped->Internal; +} + +// INDAdapter overrides. +HANDLE CAdapter::GetFileHandle(void) +{ + return m_hAsync; +} + +HRESULT CAdapter::Query( + __in DWORD VersionRequested, + __out_bcount_part_opt(*pBufferSize, *pBufferSize) ND_ADAPTER_INFO* pInfo, + __inout_opt SIZE_T* pBufferSize + ) +{ + ND_ENTER( ND_DBG_NDI ); + + if( VersionRequested != 1 ) + return ND_NOT_SUPPORTED; + + if( *pBufferSize < sizeof(ND_ADAPTER_INFO1) ) + { + *pBufferSize = sizeof(ND_ADAPTER_INFO1); + return ND_BUFFER_OVERFLOW; + } + + ib_ca_attr_t* pAttr = NULL; + DWORD size = 0; + HRESULT hr = QueryCa( pAttr, &size ); + if( hr != ND_BUFFER_OVERFLOW ) + return hr; + + pAttr = (ib_ca_attr_t*)HeapAlloc( GetProcessHeap(), 0, size ); + if( !pAttr ) + return ND_UNSUCCESSFUL; + + hr = QueryCa( pAttr, &size ); + if( FAILED( hr ) ) + { + HeapFree( GetProcessHeap(), 0, pAttr ); + return hr; + } + + pInfo->VendorId = pAttr->vend_id; + pInfo->DeviceId = pAttr->dev_id; + pInfo->MaxInboundSge = pAttr->max_sges; + pInfo->MaxInboundRequests = pAttr->max_wrs; + pInfo->MaxInboundLength = (SIZE_T)pAttr->p_port_attr[m_PortNum - 1].max_msg_size; + pInfo->MaxOutboundSge = pAttr->max_sges; + pInfo->MaxOutboundRequests = pAttr->max_wrs; + pInfo->MaxOutboundLength = (SIZE_T)pAttr->p_port_attr[m_PortNum - 1].max_msg_size; + pInfo->MaxInboundReadLimit = pAttr->max_qp_resp_res; + pInfo->MaxOutboundReadLimit = pAttr->max_qp_init_depth; + pInfo->MaxCqEntries = pAttr->max_cqes; +#ifndef SIZE_MAX +#ifdef _WIN64 +#define SIZE_MAX _UI64_MAX +#else +#define SIZE_MAX UINT_MAX +#endif +#endif + if( pAttr->init_region_size > SIZE_MAX ) + pInfo->MaxRegistrationSize = SIZE_MAX; + else + pInfo->MaxRegistrationSize = (SIZE_T)pAttr->init_region_size; + pInfo->MaxWindowSize = pInfo->MaxRegistrationSize; + pInfo->LargeRequestThreshold = 16 * 1024; + pInfo->MaxCallerData = 56; + pInfo->MaxCalleeData = 148; + *pBufferSize = sizeof(ND_ADAPTER_INFO1); + HeapFree( GetProcessHeap(), 0, pAttr ); + return S_OK; +} + +HRESULT CAdapter::Control( + __in DWORD IoControlCode, + __in_bcount_opt(InBufferSize) const void* pInBuffer, + __in SIZE_T InBufferSize, + __out_bcount_opt(OutBufferSize) void* pOutBuffer, + __in SIZE_T OutBufferSize, + __out SIZE_T* pBytesReturned, + __inout OVERLAPPED* pOverlapped + ) +{ + UNREFERENCED_PARAMETER( IoControlCode ); + UNREFERENCED_PARAMETER( pInBuffer ); + UNREFERENCED_PARAMETER( InBufferSize ); + UNREFERENCED_PARAMETER( pOutBuffer ); + UNREFERENCED_PARAMETER( OutBufferSize ); + UNREFERENCED_PARAMETER( pBytesReturned ); + UNREFERENCED_PARAMETER( pOverlapped ); + + return ND_NOT_SUPPORTED; +} + +HRESULT CAdapter::CreateCompletionQueue( + __in SIZE_T nEntries, + __deref_out INDCompletionQueue** ppCq + ) +{ + ND_ENTER( ND_DBG_NDI ); + + CCq* pCq = new CCq(); + if( pCq == NULL ) + return ND_NO_MEMORY; + + HRESULT hr = pCq->Initialize( this, nEntries ); + if( FAILED(hr) ) + { + delete pCq; + return hr; + } + + *ppCq = pCq; + return S_OK; +} + + +HRESULT CAdapter::RegisterMemory( + __in_bcount(BufferSize) const void* pBuffer, + __in SIZE_T BufferSize, + __inout OVERLAPPED* pOverlapped, + __deref_out ND_MR_HANDLE* phMr + ) +{ + ND_ENTER( ND_DBG_NDI ); + + /* Get a MR tracking structure. */ + CMr* pMr = new CMr(); + if( pMr == NULL ) + return ND_NO_MEMORY; + + pMr->pBase = (const char*)pBuffer; + + if( BufferSize > ULONG_MAX ) + return ND_INVALID_PARAMETER_2; + pMr->Length = (uint32_t)BufferSize; + + /* Clear the mr_ioctl */ + pMr->mr_ioctl.in.h_pd = m_hPd; + pMr->mr_ioctl.in.mem_create.vaddr_padding = (ULONG_PTR)pBuffer; + pMr->mr_ioctl.in.mem_create.length = BufferSize; + // No support for MWs yet, so simulate it. + pMr->mr_ioctl.in.mem_create.access_ctrl = + IB_AC_RDMA_READ | IB_AC_RDMA_WRITE | IB_AC_LOCAL_WRITE; + + *phMr = (ND_MR_HANDLE)pMr; + // + // We must issue the IOCTL on the synchronous file handle. + // If the user bound the async file handle to an I/O completion port + // DeviceIoControl could succeed, but not return data, so the MR + // wouldn't be updated. + // + // We use a second IOCTL to complet the user's overlapped. + // + DWORD bytes_ret = 0; + BOOL ret = DeviceIoControl( m_hSync, UAL_REG_MR, + &pMr->mr_ioctl.in, sizeof(pMr->mr_ioctl.in), + &pMr->mr_ioctl.out, sizeof(pMr->mr_ioctl.out), + &bytes_ret, NULL ); + if( !ret ) + { + CL_ASSERT( GetLastError() != ERROR_IO_PENDING ); + + delete pMr; + return ND_UNSUCCESSFUL; + } + if( bytes_ret != sizeof(pMr->mr_ioctl.out) || + pMr->mr_ioctl.out.status != IB_SUCCESS ) + { + delete pMr; + return ND_UNSUCCESSFUL; + } + + // + // The registration succeeded. Now issue the user's IOCTL. + // + pOverlapped->Internal = ND_PENDING; + HRESULT hr = NtDeviceIoControlFile( + m_hAsync, + pOverlapped->hEvent, + NULL, + (ULONG_PTR)pOverlapped->hEvent & 1 ? NULL : pOverlapped, + (IO_STATUS_BLOCK*)&pOverlapped->Internal, + UAL_NDI_NOOP, + NULL, + 0, + NULL, + 0 ); + + if( hr != ND_PENDING && hr != ND_SUCCESS ) + { + delete pMr; + return hr; + } + + AddRef(); + return ND_SUCCESS; +} + +HRESULT CAdapter::DeregisterMemory( + __in ND_MR_HANDLE hMr, + __inout OVERLAPPED* pOverlapped + ) +{ + ND_ENTER( ND_DBG_NDI ); + + CMr* pMr = (CMr*)hMr; + + // + // We must issue the IOCTL on the synchronous file handle. + // If the user bound the async file handle to an I/O completion port + // DeviceIoControl could succeed, but not return data, so the MR + // wouldn't be updated. + // + // We use a second IOCTL to complet the user's overlapped. + // + DWORD bytes_ret = 0; + BOOL ret = DeviceIoControl( m_hSync, UAL_DEREG_MR, + &pMr->mr_ioctl.out.h_mr, sizeof(pMr->mr_ioctl.out.h_mr), + &pMr->mr_ioctl.out.status, sizeof(pMr->mr_ioctl.out.status), + &bytes_ret, NULL ); + if( !ret ) + { + CL_ASSERT( GetLastError() != ERROR_IO_PENDING ); + pMr->mr_ioctl.out.status = IB_ERROR; + } + if( bytes_ret != sizeof(pMr->mr_ioctl.out.status) ) + return ND_UNSUCCESSFUL; + + switch( pMr->mr_ioctl.out.status ) + { + case IB_SUCCESS: + { + delete pMr; + Release(); + + // + // The deregistration succeeded. Now issue the user's IOCTL. + // + pOverlapped->Internal = ND_PENDING; + HRESULT hr = NtDeviceIoControlFile( + m_hAsync, + pOverlapped->hEvent, + NULL, + (ULONG_PTR)pOverlapped->hEvent & 1 ? NULL : pOverlapped, + (IO_STATUS_BLOCK*)&pOverlapped->Internal, + UAL_NDI_NOOP, + NULL, + 0, + NULL, + 0 ); + CL_ASSERT( SUCCEEDED( hr ) ); + return hr; + } + case IB_RESOURCE_BUSY: + return ND_DEVICE_BUSY; + + default: + return ND_UNSUCCESSFUL; + } +} + +HRESULT CAdapter::CreateMemoryWindow( + __out ND_RESULT* pInvalidateResult, + __deref_out INDMemoryWindow** ppMw + ) +{ + ND_ENTER( ND_DBG_NDI ); + + CMw* pMw = new CMw(); + if( pMw == NULL ) + return ND_NO_MEMORY; + + HRESULT hr = pMw->Initialize( this, pInvalidateResult ); + if( FAILED(hr) ) + { + delete pMw; + return hr; + } + + *ppMw = pMw; + return S_OK; +} + +HRESULT CAdapter::CreateConnector( + __deref_out INDConnector** ppConnector + ) +{ + ND_ENTER( ND_DBG_NDI ); + + return CConnector::Create( this, ppConnector ); +} + +HRESULT CAdapter::Listen( + __in SIZE_T Backlog, + __in INT Protocol, + __in USHORT Port, + __out_opt USHORT* pAssignedPort, + __deref_out INDListen** ppListen + ) +{ + ND_ENTER( ND_DBG_NDI ); + + return CListen::Create( + this, + Backlog, + Protocol, + Port, + pAssignedPort, + ppListen + ); +} + +HRESULT CAdapter::GetLocalAddress( + __out_bcount_part(*pAddressLength, *pAddressLength) struct sockaddr *pAddr, + __inout SIZE_T *pAddressLength ) +{ + ND_ENTER( ND_DBG_NDI ); + + switch( m_Addr.v4.sin_family ) + { + case AF_INET: + if( *pAddressLength < sizeof(struct sockaddr_in) ) + { + *pAddressLength = sizeof(struct sockaddr_in); + return ND_BUFFER_OVERFLOW; + } + *(struct sockaddr_in*)pAddr = m_Addr.v4; + ND_PRINT( TRACE_LEVEL_INFORMATION, ND_DBG_NDI, + ("Local address: IP %#x, port %#hx\n", + cl_hton32(m_Addr.v4.sin_addr.S_un.S_addr), cl_hton16(m_Addr.v4.sin_port) ) ); + return S_OK; + + case AF_INET6: + if( *pAddressLength < sizeof(struct sockaddr_in6) ) + { + *pAddressLength = sizeof(struct sockaddr_in6); + return ND_BUFFER_OVERFLOW; + } + *(struct sockaddr_in6*)pAddr = m_Addr.v6; + return S_OK; + + default: + return ND_INVALID_ADDRESS; + } +} + +HRESULT CAdapter::OpenFiles(void) +{ + ND_ENTER( ND_DBG_NDI ); + + /* First open the kernel device. */ + CL_ASSERT( m_hSync == INVALID_HANDLE_VALUE ); + m_hSync = CreateFile( + "\\\\.\\ibal", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + 0, + NULL + ); + if( m_hSync == INVALID_HANDLE_VALUE ) + return ND_UNSUCCESSFUL; + + // Now issue the BIND IOCTL which associates us as a client. + ULONG ver = AL_IOCTL_VERSION; + DWORD BytesRet; + BOOL fSuccess = DeviceIoControl( + m_hSync, + UAL_BIND, + &ver, + sizeof(ver), + NULL, + 0, + &BytesRet, + NULL + ); + if( fSuccess != TRUE ) + return ND_UNSUCCESSFUL; + + // Now create the async file. + m_hAsync = CreateFile( + "\\\\.\\ibal", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_OVERLAPPED, + NULL + ); + if( m_hAsync == INVALID_HANDLE_VALUE ) + return ND_UNSUCCESSFUL; + + /* + * Send an IOCTL down on the main file handle to bind this file + * handle with our proxy context. + */ + UINT64 hFile = (ULONG_PTR)m_hAsync; + fSuccess = DeviceIoControl( + m_hSync, + UAL_BIND_ND, + &hFile, + sizeof(hFile), + NULL, + 0, + &BytesRet, + NULL + ); + if( fSuccess != TRUE ) + return ND_UNSUCCESSFUL; + + return S_OK; +} + +HRESULT CAdapter::OpenCa( + __in UINT64 CaGuid ) +{ + ND_ENTER( ND_DBG_NDI ); + + ual_get_uvp_name_ioctl_t al_ioctl; + + /* Initialize assuming no user-mode support */ + cl_memclr( &al_ioctl, sizeof(al_ioctl) ); + cl_memclr( &m_Ifc, sizeof(m_Ifc) ); + + /* init with the guid */ + m_Ifc.guid = CaGuid; + + DWORD BytesRet; + BOOL fSuccess = DeviceIoControl( + m_hSync, + UAL_GET_VENDOR_LIBCFG, + &CaGuid, sizeof(CaGuid), + &al_ioctl.out, sizeof(al_ioctl.out), + &BytesRet, + NULL + ); + + if( fSuccess != TRUE || BytesRet != sizeof(al_ioctl.out) ) + return ND_INSUFFICIENT_RESOURCES; + + if( !strlen( al_ioctl.out.uvp_lib_name ) ) + { + /* Vendor does not implement user-mode library */ + return ND_NOT_SUPPORTED; + } + + /* + * The vendor supports a user-mode library + * open the library and get the interfaces supported + */ +#if DBG + HRESULT hr = StringCbCatA( al_ioctl.out.uvp_lib_name, 32, "d.dll" ); +#else + HRESULT hr = StringCbCatA( al_ioctl.out.uvp_lib_name, 32, ".dll" ); +#endif + if( FAILED( hr ) ) + return ND_NOT_SUPPORTED; + + m_Ifc.h_uvp_lib = LoadLibrary( al_ioctl.out.uvp_lib_name ); + if( m_Ifc.h_uvp_lib == NULL ) + return ND_NOT_SUPPORTED; + + uvp_get_interface_t pfn_uvp_ifc = (uvp_get_interface_t)GetProcAddress( + m_Ifc.h_uvp_lib, + "uvp_get_interface" + ); + + if( pfn_uvp_ifc == NULL ) + return ND_NOT_SUPPORTED; + + /* Query the vendor-supported user-mode functions */ + pfn_uvp_ifc( IID_UVP, &m_Ifc.user_verbs ); + + ual_open_ca_ioctl_t ca_ioctl; + cl_memclr( &ca_ioctl, sizeof(ca_ioctl) ); + + /* Pre call to the UVP library */ + ib_api_status_t status = IB_ERROR; + if( m_Ifc.user_verbs.pre_open_ca ) + { + status = m_Ifc.user_verbs.pre_open_ca( + CaGuid, + &ca_ioctl.in.umv_buf, + (ib_ca_handle_t*)(ULONG_PTR)&m_uCa + ); + if( status != IB_SUCCESS ) + { + CL_ASSERT( status != IB_VERBS_PROCESSING_DONE ); + return ND_INSUFFICIENT_RESOURCES; + } + } + + ca_ioctl.in.guid = CaGuid; + ca_ioctl.in.context = (ULONG_PTR)this; + + fSuccess = DeviceIoControl( + m_hSync, + UAL_OPEN_CA, + &ca_ioctl.in, + sizeof(ca_ioctl.in), + &ca_ioctl.out, + sizeof(ca_ioctl.out), + &BytesRet, + NULL + ); + + if( fSuccess != TRUE || BytesRet != sizeof(ca_ioctl.out) ) + { + status = IB_ERROR; + } + else + { + status = ca_ioctl.out.status; + m_hCa = ca_ioctl.out.h_ca; + } + + /* Post uvp call */ + if( m_Ifc.user_verbs.post_open_ca ) + { + status = m_Ifc.user_verbs.post_open_ca( + CaGuid, + status, + (ib_ca_handle_t*)(ULONG_PTR)&m_uCa, + &ca_ioctl.out.umv_buf ); + } + + // TODO: Does the UVP need a query call to succeed? + // IBAL always does this internally. + + return (status == IB_SUCCESS? S_OK : ND_INSUFFICIENT_RESOURCES ); +} + +HRESULT CAdapter::QueryCa( + __out_bcount(*pSize) ib_ca_attr_t* pAttr, + __inout DWORD* pSize ) +{ + ND_ENTER( ND_DBG_NDI ); + + ual_query_ca_ioctl_t ca_ioctl; + + cl_memclr( &ca_ioctl, sizeof(ca_ioctl) ); + + ca_ioctl.in.h_ca = m_hCa; + ca_ioctl.in.p_ca_attr = (ULONG_PTR)pAttr; + ca_ioctl.in.byte_cnt = *pSize; + + /* Call the uvp pre call if the vendor library provided a valid ca handle */ + ib_api_status_t status; + if( m_uCa && m_Ifc.user_verbs.pre_query_ca ) + { + /* Pre call to the UVP library */ + status = m_Ifc.user_verbs.pre_query_ca( + m_uCa, pAttr, *pSize, &ca_ioctl.in.umv_buf ); + if( status != IB_SUCCESS ) + return ND_UNSUCCESSFUL; + } + + DWORD BytesRet; + BOOL fSuccess = DeviceIoControl( + m_hSync, + UAL_QUERY_CA, + &ca_ioctl.in, + sizeof(ca_ioctl.in), + &ca_ioctl.out, + sizeof(ca_ioctl.out), + &BytesRet, + NULL + ); + if( fSuccess != TRUE || BytesRet != sizeof(ca_ioctl.out) ) + { + status = IB_ERROR; + } + else + { + *pSize = ca_ioctl.out.byte_cnt; + status = ca_ioctl.out.status; + } + + /* The attributes, if any, will be directly copied by proxy */ + /* Post uvp call */ + if( m_uCa && m_Ifc.user_verbs.post_query_ca ) + { + m_Ifc.user_verbs.post_query_ca( m_uCa, + status, pAttr, ca_ioctl.out.byte_cnt, &ca_ioctl.out.umv_buf ); + } + + switch( status ) + { + case IB_SUCCESS: + return S_OK; + case IB_INSUFFICIENT_MEMORY: + return ND_BUFFER_OVERFLOW; + default: + return ND_INSUFFICIENT_RESOURCES; + } +} + +void CAdapter::CloseCa(void) +{ + ND_ENTER( ND_DBG_NDI ); + + ib_api_status_t status; + + /* Call the uvp pre call if the vendor library provided a valid ca handle */ + if( m_uCa && m_Ifc.user_verbs.pre_close_ca ) + { + /* Pre call to the UVP library */ + status = m_Ifc.user_verbs.pre_close_ca( m_uCa ); + if( status != IB_SUCCESS ) + return; + } + + DWORD BytesRet; + BOOL fSuccess = DeviceIoControl( + m_hSync, + UAL_CLOSE_CA, + &m_hCa, + sizeof(m_hCa), + &status, + sizeof(status), + &BytesRet, + NULL + ); + + if( fSuccess != TRUE || BytesRet != sizeof(status) ) + status = IB_ERROR; + + if( m_uCa && m_Ifc.user_verbs.post_close_ca ) + m_Ifc.user_verbs.post_close_ca( m_uCa, status ); + + if( m_Ifc.h_uvp_lib ) + FreeLibrary( m_Ifc.h_uvp_lib ); + + m_hCa = 0; +} + +HRESULT CAdapter::AllocPd(void) +{ + ND_ENTER( ND_DBG_NDI ); + + /* Clear the pd_ioctl */ + ual_alloc_pd_ioctl_t pd_ioctl; + cl_memclr( &pd_ioctl, sizeof(pd_ioctl) ); + + /* Pre call to the UVP library */ + ib_api_status_t status; + if( m_uCa && m_Ifc.user_verbs.pre_allocate_pd ) + { + status = m_Ifc.user_verbs.pre_allocate_pd( + m_uCa, + &pd_ioctl.in.umv_buf, + (ib_pd_handle_t*)(ULONG_PTR)&m_uPd + ); + if( status != IB_SUCCESS ) + return ND_INSUFFICIENT_RESOURCES; + } + + pd_ioctl.in.h_ca = m_hCa; + pd_ioctl.in.type = IB_PDT_NORMAL; + pd_ioctl.in.context = (ULONG_PTR)this; + + DWORD BytesRet; + BOOL fSuccess = DeviceIoControl( + m_hSync, + UAL_ALLOC_PD, + &pd_ioctl.in, + sizeof(pd_ioctl.in), + &pd_ioctl.out, + sizeof(pd_ioctl.out), + &BytesRet, + NULL + ); + + if( fSuccess != TRUE || BytesRet != sizeof(pd_ioctl.out) ) + { + status = IB_ERROR; + } + else + { + status = pd_ioctl.out.status; + if( pd_ioctl.out.status == IB_SUCCESS ) + m_hPd = pd_ioctl.out.h_pd; + } + + /* Post uvp call */ + if( m_uCa && m_Ifc.user_verbs.post_allocate_pd ) + { + m_Ifc.user_verbs.post_allocate_pd( + m_uCa, + status, + (ib_pd_handle_t*)(ULONG_PTR)&m_uPd, + &pd_ioctl.out.umv_buf ); + } + + return (status == IB_SUCCESS? S_OK : ND_INSUFFICIENT_RESOURCES); +} + +void CAdapter::DeallocPd(void) +{ + ND_ENTER( ND_DBG_NDI ); + + ib_api_status_t status; + + /* Call the uvp pre call if the vendor library provided a valid ca handle */ + if( m_uPd && m_Ifc.user_verbs.pre_deallocate_pd ) + { + /* Pre call to the UVP library */ + status = m_Ifc.user_verbs.pre_deallocate_pd( m_uPd ); + if( status != IB_SUCCESS ) + return; + } + + DWORD BytesRet; + BOOL fSuccess = DeviceIoControl( + m_hSync, + UAL_DEALLOC_PD, + &m_hPd, + sizeof(m_hPd), + &status, + sizeof(status), + &BytesRet, + NULL + ); + + if( fSuccess == FALSE || BytesRet != sizeof(status) ) + status = IB_ERROR; + + /* Call vendor's post_close ca */ + if( m_uPd && m_Ifc.user_verbs.post_deallocate_pd ) + m_Ifc.user_verbs.post_deallocate_pd( m_uPd, status ); + + m_hPd = 0; +} + +} // namespace diff --git a/branches/WOF2-3/ulp/nd/user/NdAdapter.h b/branches/WOF2-3/ulp/nd/user/NdAdapter.h new file mode 100644 index 00000000..79b79e04 --- /dev/null +++ b/branches/WOF2-3/ulp/nd/user/NdAdapter.h @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id:$ + */ + +#pragma once + +#include "ndspi.h" +#include "nddebug.h" +#include +#include +#include +#include "ual_ci_ca.h" + +#include "NdProv.h" + + +namespace NetworkDirect +{ + +class CCq; +class CAddr; +class CProvider; + +class CAdapter : + public INDAdapter +{ + friend class CCq; + friend class CEndpoint; + friend class CConnector; + friend class CMw; + friend class CMr; + friend class CListen; + +private: + CAdapter(void); + ~CAdapter(void); + + HRESULT Initialize( + CProvider* pParent, + const struct sockaddr* pAddr, + const IBAT_PORT_RECORD* pPortRecord + ); + +public: + static HRESULT Create( + CProvider* pParent, + const struct sockaddr* pAddr, + const IBAT_PORT_RECORD* pPortRecord, + __out INDAdapter** ppAdapter + ); + + // *** IUnknown methods *** + HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + LPVOID FAR* ppvObj + ); + + ULONG STDMETHODCALLTYPE AddRef(void); + + ULONG STDMETHODCALLTYPE Release(void); + + // *** INDOverlapped methods *** + HRESULT STDMETHODCALLTYPE CancelOverlappedRequests(void); + + HRESULT STDMETHODCALLTYPE GetOverlappedResult( + __inout OVERLAPPED *pOverlapped, + __out SIZE_T *pNumberOfBytesTransferred, + __in BOOL bWait + ); + + // *** INDAdapter methods *** + HANDLE STDMETHODCALLTYPE GetFileHandle(void); + + HRESULT STDMETHODCALLTYPE Query( + __in DWORD VersionRequested, + __out_bcount_part_opt(*pBufferSize, *pBufferSize) ND_ADAPTER_INFO* pInfo, + __inout_opt SIZE_T* pBufferSize + ); + + HRESULT STDMETHODCALLTYPE Control( + __in DWORD IoControlCode, + __in_bcount_opt(InBufferSize) const void* pInBuffer, + __in SIZE_T InBufferSize, + __out_bcount_opt(OutBufferSize) void* pOutBuffer, + __in SIZE_T OutBufferSize, + __out SIZE_T* pBytesReturned, + __inout OVERLAPPED* pOverlapped + ); + + HRESULT STDMETHODCALLTYPE CreateCompletionQueue( + __in SIZE_T nEntries, + __deref_out INDCompletionQueue** ppCq + ); + + HRESULT STDMETHODCALLTYPE RegisterMemory( + __in_bcount(BufferSize) const void* pBuffer, + __in SIZE_T BufferSize, + __inout OVERLAPPED* pOverlapped, + __deref_out ND_MR_HANDLE* phMr + ); + + HRESULT STDMETHODCALLTYPE CompleteRegisterMemory( + __in ND_MR_HANDLE hMr, + __in OVERLAPPED* pOverlapped + ); + + HRESULT STDMETHODCALLTYPE DeregisterMemory( + __in ND_MR_HANDLE hMr, + __inout OVERLAPPED* pOverlapped + ); + + HRESULT STDMETHODCALLTYPE CompleteDeregisterMemory( + __in ND_MR_HANDLE hMr, + __in OVERLAPPED* pOverlapped + ); + + HRESULT STDMETHODCALLTYPE CreateMemoryWindow( + __out ND_RESULT* pInvalidateResult, + __deref_out INDMemoryWindow** ppMw + ); + + HRESULT STDMETHODCALLTYPE CreateConnector( + __deref_out INDConnector** ppConnector + ); + + HRESULT STDMETHODCALLTYPE Listen( + __in SIZE_T Backlog, + __in INT Protocol, + __in USHORT Port, + __out_opt USHORT* pAssignedPort, + __deref_out INDListen** ppListen + ); + + HRESULT GetLocalAddress( + __out_bcount_part(*pAddressLength, *pAddressLength) struct sockaddr* pAddr, + __inout SIZE_T *pAddressLength ); + +private: + HRESULT OpenFiles(void); + + HRESULT OpenCa( + __in UINT64 CaGuid + ); + + HRESULT QueryCa( + __out_bcount(*pSize) ib_ca_attr_t* pAttr, + __inout DWORD* pSize + ); + + void CloseCa(void); + + HRESULT AllocPd(void); + + void DeallocPd(void); + +protected: + volatile LONG m_nRef; + + CProvider* m_pParent; + UINT64 m_PortGuid; + UINT8 m_PortNum; + + HANDLE m_hSync; + HANDLE m_hAsync; + + ual_ci_interface_t m_Ifc; + // Kernel IBAL handles. + uint64_t m_hCa; + uint64_t m_hPd; + // UVP handles. + ib_ca_handle_t m_uCa; + ib_pd_handle_t m_uPd; + + union _addr + { + struct sockaddr unspec; + struct sockaddr_in v4; + struct sockaddr_in6 v6; + + } m_Addr; +}; + +} // namespace \ No newline at end of file diff --git a/branches/WOF2-3/ulp/nd/user/NdConnector.cpp b/branches/WOF2-3/ulp/nd/user/NdConnector.cpp new file mode 100644 index 00000000..3cb4aa2d --- /dev/null +++ b/branches/WOF2-3/ulp/nd/user/NdConnector.cpp @@ -0,0 +1,935 @@ +/* + * Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id:$ + */ + +#include "NdCq.h" +#include "NdAdapter.h" +#include "NdMw.h" +#include "NdEndpoint.h" +#include "NdProv.h" +#include "NdMr.h" +#include "NdListen.h" +#include "NdConnector.h" + +#include "al_dev.h" +#pragma warning( push, 3 ) +#include "winternl.h" +#pragma warning( pop ) +#include "iba/ibat.h" + +#include +#include +#include + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "NdConnector.tmh" +#endif + + +namespace NetworkDirect +{ + +CConnector::CConnector(void) : + m_nRef( 1 ), + m_pParent( NULL ), + m_pEndpoint( NULL ), + m_Protocol( 0 ), + m_LocalPort( 0 ), + m_cid( 0 ), + m_fActive( false ) +{ +} + +CConnector::~CConnector(void) +{ + FreeCid(); + + if( m_pEndpoint ) + m_pEndpoint->Release(); + + if( m_pParent ) + m_pParent->Release(); +} + +void CConnector::FreeCid(void) +{ + if( m_cid != 0 ) + { + DWORD bytes_ret; + DeviceIoControl( + m_pParent->m_hSync, + UAL_DESTROY_CEP, + &m_cid, + sizeof(m_cid), + NULL, + 0, + &bytes_ret, + NULL ); + + m_cid = 0; + } +} + +HRESULT CConnector::Create( + __in CAdapter* pParent, + __deref_out INDConnector** ppConnector + ) +{ + CConnector* pConnector = new CConnector(); + if( pConnector == NULL ) + return ND_NO_MEMORY; + + pConnector->m_pParent = pParent; + pParent->AddRef(); + + *ppConnector = pConnector; + return S_OK; +} + +HRESULT CConnector::QueryInterface( + REFIID riid, + LPVOID FAR* ppvObj + ) +{ + if( IsEqualIID( riid, IID_IUnknown ) ) + { + *ppvObj = this; + return S_OK; + } + + if( IsEqualIID( riid, IID_INDConnector ) ) + { + *ppvObj = this; + return S_OK; + } + + return E_NOINTERFACE; +} + +ULONG CConnector::AddRef(void) +{ + return InterlockedIncrement( &m_nRef ); +} + +ULONG CConnector::Release(void) +{ + ULONG ref = InterlockedDecrement( &m_nRef ); + if( ref == 0 ) + delete this; + + return ref; +} + +// *** INDOverlapped methods *** +HRESULT CConnector::CancelOverlappedRequests(void) +{ + ND_ENTER( ND_DBG_NDI ); + + DWORD bytes_ret; + BOOL ret = DeviceIoControl( + m_pParent->m_hSync, + UAL_NDI_CANCEL_CM_IRPS, + &m_cid, + sizeof(m_cid), + NULL, + 0, + &bytes_ret, + NULL ); + + if( ret ) + return S_OK; + else + return ND_UNSUCCESSFUL; +} + +HRESULT CConnector::GetOverlappedResult( + __inout OVERLAPPED *pOverlapped, + __out SIZE_T *pNumberOfBytesTransferred, + __in BOOL bWait + ) +{ + ND_ENTER( ND_DBG_NDI ); + + *pNumberOfBytesTransferred = 0; + ::GetOverlappedResult( + m_pParent->GetFileHandle(), + pOverlapped, + (DWORD*)pNumberOfBytesTransferred, + bWait ); + return (HRESULT)pOverlapped->Internal; +} + +HRESULT CConnector::CreateEndpoint( + __in INDCompletionQueue* pInboundCq, + __in INDCompletionQueue* pOutboundCq, + __in SIZE_T nInboundEntries, + __in SIZE_T nOutboundEntries, + __in SIZE_T nInboundSge, + __in SIZE_T nOutboundSge, + __in SIZE_T InboundReadLimit, + __in SIZE_T OutboundReadLimit, + __out_opt SIZE_T* pMaxInlineData, + __deref_out INDEndpoint** ppEndpoint + ) +{ + ND_ENTER( ND_DBG_NDI ); + + // + // Check that the verb provider supports user-mode operations. + // If not, a different class should be created. + // + if( m_pParent->m_Ifc.user_verbs.pre_create_qp == NULL || + m_pParent->m_Ifc.user_verbs.post_create_qp == NULL || + m_pParent->m_Ifc.user_verbs.nd_modify_qp == NULL || + m_pParent->m_Ifc.user_verbs.nd_get_qp_state == NULL || + m_pParent->m_Ifc.user_verbs.pre_destroy_qp == NULL || + m_pParent->m_Ifc.user_verbs.post_destroy_qp == NULL || + m_pParent->m_Ifc.user_verbs.post_send == NULL || + m_pParent->m_Ifc.user_verbs.post_recv == NULL /*|| + m_pParent->m_Ifc.user_verbs.bind_mw == NULL*/ ) + { + return ND_NOT_SUPPORTED; + } + + if( m_pEndpoint != NULL ) + return ND_NOT_SUPPORTED; + + HRESULT hr = CEndpoint::Create( + m_pParent, + static_cast(pInboundCq), + static_cast(pOutboundCq), + nInboundEntries, + nOutboundEntries, + nInboundSge, + nOutboundSge, + InboundReadLimit, + OutboundReadLimit, + pMaxInlineData, + (INDEndpoint**)&m_pEndpoint + ); + + if( SUCCEEDED( hr ) ) + { + m_pEndpoint->AddRef(); + *ppEndpoint = m_pEndpoint; + } + + return hr; +} + +// +// Connects an endpoint to the specified destinaton address. +// +// Only basic checks on input data are performed in user-mode, +// and request is handed to the kernel, where: +// 1. the destination address is resolved to a destination GID +// 2. the destination GID is used to get a path record +// 3. the path record is used to issue a CM REQ +// 4. a CM REP is received (or REJ or timeout). +// 5. the request is completed. +// +HRESULT CConnector::Connect( + __inout INDEndpoint* pEndpoint, + __in_bcount(AddressLength) const struct sockaddr* pAddress, + __in SIZE_T AddressLength, + __in INT Protocol, + __in_opt USHORT LocalPort, + __in_bcount_opt(PrivateDataLength) const void* pPrivateData, + __in SIZE_T PrivateDataLength, + __inout OVERLAPPED* pOverlapped + ) +{ + ND_ENTER( ND_DBG_NDI ); + + if( AddressLength < sizeof(struct sockaddr) ) + return ND_INVALID_ADDRESS; + + if( Protocol > UCHAR_MAX || Protocol < 0 ) + return ND_INVALID_PARAMETER_4; + + m_Protocol = (UINT8)Protocol; + + // + // CM REQ supports 92 bytes of private data. We expect to use IP + // addressing annex, which eats up 36 bytes, leaving us with 56. + // + if( PrivateDataLength > 56 ) + return ND_BUFFER_OVERFLOW; + + // + // Only support connecting the endpoint we created. + // + if( pEndpoint != m_pEndpoint ) + return ND_INVALID_PARAMETER_1; + + // + // Format the private data to match the RDMA CM annex spec as we + // check the address validity. + // + ual_ndi_req_cm_ioctl_in_t ioctl; + ioctl.pdata.maj_min_ver = 0; + if( LocalPort == 0 ) + { + m_LocalPort = (USHORT)_byteswap_ulong( m_pEndpoint->m_Qpn ); + } + else + { + m_LocalPort = LocalPort; + } + ioctl.pdata.src_port = _byteswap_ushort( m_LocalPort ); + + // Resolve the GIDs. + HRESULT hr = IBAT::Resolve( + &m_pParent->m_Addr.unspec, + pAddress, + (IBAT_PATH_BLOB*)&ioctl.path + ); + if( FAILED( hr ) ) + { + if( hr == E_PENDING ) + { + // + // Complete the request with a timeout status. + // + pOverlapped->Internal = ND_PENDING; + hr = NtDeviceIoControlFile( + m_pParent->GetFileHandle(), + pOverlapped->hEvent, + NULL, + (ULONG_PTR)pOverlapped->hEvent & 1 ? NULL : pOverlapped, + (IO_STATUS_BLOCK*)&pOverlapped->Internal, + UAL_NDI_NOOP, + &hr, + sizeof(hr), + NULL, + 0 ); + } + return hr; + } + + switch( ((struct sockaddr_in*)pAddress)->sin_family ) + { + case AF_INET: + if( AddressLength != sizeof(struct sockaddr_in) ) + return ND_INVALID_ADDRESS; + + if( m_pParent->m_Addr.v4.sin_family != AF_INET ) + return ND_INVALID_ADDRESS; + + // + // Copy the destination address so we can satisfy a + // GetPeerAddress request. + // + m_PeerAddr.v4 = *(struct sockaddr_in*)pAddress; + + ioctl.dst_port = m_PeerAddr.v4.sin_port; + ioctl.pdata.ipv = 0x40; + + // Local address. + RtlZeroMemory( &ioctl.pdata.src_ip_addr, ATS_IPV4_OFFSET ); + CopyMemory( + &ioctl.pdata.src_ip_addr[ATS_IPV4_OFFSET>>2], + (uint8_t*)&m_pParent->m_Addr.v4.sin_addr, + sizeof( m_pParent->m_Addr.v4.sin_addr ) + ); + + // Destination address. + RtlZeroMemory( &ioctl.pdata.dst_ip_addr, ATS_IPV4_OFFSET ); + CopyMemory( + &ioctl.pdata.dst_ip_addr[ATS_IPV4_OFFSET>>2], + (uint8_t*)&m_PeerAddr.v4.sin_addr, + sizeof( m_PeerAddr.v4.sin_addr ) + ); + ND_PRINT( TRACE_LEVEL_INFORMATION, ND_DBG_NDI, + ("local address: IP %#x, port %#hx, dest address: IP %#x, port %#hx\n", + cl_hton32(m_pParent->m_Addr.v4.sin_addr.S_un.S_addr), cl_hton16(m_pParent->m_Addr.v4.sin_port), + cl_hton32(m_PeerAddr.v4.sin_addr.S_un.S_addr), cl_hton16(m_PeerAddr.v4.sin_port) ) ); + break; + + case AF_INET6: + if( AddressLength != sizeof(struct sockaddr_in6) ) + return ND_INVALID_ADDRESS; + + // + // Copy the destination address so we can satisfy a + // GetPeerAddress request. + // + m_PeerAddr.v6 = *(struct sockaddr_in6*)pAddress; + + ioctl.dst_port = m_PeerAddr.v6.sin6_port; + ioctl.pdata.ipv = 0x60; + + // Local address. + CopyMemory( + ioctl.pdata.src_ip_addr, + m_pParent->m_Addr.v6.sin6_addr.u.Byte, + sizeof(ioctl.pdata.src_ip_addr) + ); + + // Destination address. + CopyMemory( ioctl.pdata.dst_ip_addr, + m_PeerAddr.v6.sin6_addr.u.Byte, + sizeof(ioctl.pdata.dst_ip_addr) + ); + break; + + default: + return ND_INVALID_ADDRESS; + } + + // Copy the user's private data. + CopyMemory( ioctl.pdata.pdata, pPrivateData, PrivateDataLength ); + + // + // It's only valid to call Connect with a new or reused endpoint: + // the QP must be in the INIT state. + // + switch( m_pParent->m_Ifc.user_verbs.nd_get_qp_state( m_pEndpoint->m_uQp ) ) + { + case IB_QPS_INIT: + break; + + case IB_QPS_RTS: + return ND_CONNECTION_ACTIVE; + + default: + return ND_UNSUCCESSFUL; + } + + // + // Create the CEP. We do this so that we have a valid CID in user-mode + // in case the user calls CancelOverlappedRequests or releases the object. + // + UINT64 context = 0; + ual_create_cep_ioctl_t create; + DWORD bytes_ret; + BOOL fSuccess = DeviceIoControl( + m_pParent->m_hSync, + UAL_CREATE_CEP, + &context, + sizeof(context), + &create, + sizeof(create), + &bytes_ret, + NULL + ); + if( !fSuccess || + bytes_ret != sizeof(create) || + create.status != IB_SUCCESS ) + { + return ND_INSUFFICIENT_RESOURCES; + } + + m_cid = create.cid; + + // + // Fill in the rest of the input buffer and send the request down + // to the kernel and let everything else be done there. + // + ioctl.h_qp = m_pEndpoint->m_hQp; + ioctl.guid = m_pParent->m_PortGuid; + ioctl.cid = m_cid; + ioctl.prot = m_Protocol; + ioctl.pdata_size = sizeof(ioctl.pdata); + ioctl.init_depth = m_pEndpoint->m_Ord; + ioctl.resp_res = m_pEndpoint->m_Ird; + + ND_PRINT( TRACE_LEVEL_INFORMATION, ND_DBG_NDI, + ("Connect QP %#I64x, QPn %#x, Guid %#I64x \n", + m_pEndpoint->m_hQp, + m_pEndpoint->m_Qpn, + m_pParent->m_PortGuid ) ); + + m_fActive = true; + + pOverlapped->Internal = ND_PENDING; + hr = NtDeviceIoControlFile( + m_pParent->GetFileHandle(), + pOverlapped->hEvent, + NULL, + (ULONG_PTR)pOverlapped->hEvent & 1 ? NULL : pOverlapped, + (IO_STATUS_BLOCK*)&pOverlapped->Internal, + UAL_NDI_REQ_CM, + &ioctl, + sizeof(ioctl), + NULL, + 0 ); + + if( FAILED( hr ) ) + { + FreeCid(); + m_pEndpoint->Release(); + m_pEndpoint = NULL; + } + + return hr; +} + +HRESULT CConnector::CompleteConnect( + __inout OVERLAPPED* pOverlapped + ) +{ + ND_ENTER( ND_DBG_NDI ); + + if( !m_fActive ) + return ND_CONNECTION_INVALID; + + if( m_pEndpoint == NULL ) + return ND_CONNECTION_INVALID; + + // + // Get the UVP's buffer for modify operations. + // + void* pOutbuf; + DWORD szOutbuf; + + m_pParent->m_Ifc.user_verbs.nd_modify_qp( + (const ib_qp_handle_t)m_pEndpoint->m_uQp, + &pOutbuf, + &szOutbuf + ); + + ND_PRINT( TRACE_LEVEL_INFORMATION, ND_DBG_NDI, + ("CompleteConnect QP %#I64x, QPn %#x\n", m_pEndpoint->m_hQp, m_pEndpoint->m_Qpn ) ); + + pOverlapped->Internal = ND_PENDING; + return NtDeviceIoControlFile( + m_pParent->GetFileHandle(), + pOverlapped->hEvent, + NULL, + (ULONG_PTR)pOverlapped->hEvent & 1 ? NULL : pOverlapped, + (IO_STATUS_BLOCK*)&pOverlapped->Internal, + UAL_NDI_RTU_CM, + &m_cid, + sizeof(m_cid), + pOutbuf, + szOutbuf ); +} + +HRESULT CConnector::Accept( + __in INDEndpoint* pEndpoint, + __in_bcount_opt(PrivateDataLength) const void* pPrivateData, + __in SIZE_T PrivateDataLength, + __inout OVERLAPPED* pOverlapped + ) +{ + ND_ENTER( ND_DBG_NDI ); + + if( PrivateDataLength > IB_REJ_PDATA_SIZE ) + return ND_BUFFER_OVERFLOW; + + // + // Only support connecting the endpoint we created. + // + if( pEndpoint != m_pEndpoint ) + return ND_INVALID_PARAMETER_1; + + // + // Get the UVP's buffer for modify operations. + // + void* pOutbuf; + DWORD szOutbuf; + + m_pParent->m_Ifc.user_verbs.nd_modify_qp( + static_cast(pEndpoint)->m_uQp, + &pOutbuf, + &szOutbuf + ); + + ual_ndi_rep_cm_ioctl_in_t ioctl; + ioctl.h_qp = m_pEndpoint->m_hQp; + ioctl.cid = m_cid; + ioctl.init_depth = m_pEndpoint->m_Ord; + ioctl.resp_res = m_pEndpoint->m_Ird; + ioctl.pdata_size = (uint8_t)PrivateDataLength; + CopyMemory( &ioctl.pdata, pPrivateData, PrivateDataLength ); + + ND_PRINT( TRACE_LEVEL_INFORMATION, ND_DBG_NDI, + ("Accept QP %#I64x, cid %d \n", ioctl.h_qp, ioctl.cid ) ); + + pOverlapped->Internal = ND_PENDING; + HRESULT hr = NtDeviceIoControlFile( + m_pParent->GetFileHandle(), + pOverlapped->hEvent, + NULL, + (ULONG_PTR)pOverlapped->hEvent & 1 ? NULL : pOverlapped, + (IO_STATUS_BLOCK*)&pOverlapped->Internal, + UAL_NDI_REP_CM, + &ioctl, + sizeof(ioctl), + pOutbuf, + szOutbuf ); + + if( FAILED( hr ) ) + { + m_pEndpoint->Release(); + m_pEndpoint = NULL; + } + return hr; +} + +HRESULT CConnector::Reject( + __in_bcount_opt(PrivateDataLength) const void* pPrivateData, + __in SIZE_T PrivateDataLength + ) +{ + ND_ENTER( ND_DBG_NDI ); + + if( PrivateDataLength > IB_REJ_PDATA_SIZE ) + return ND_BUFFER_OVERFLOW; + + ual_ndi_rej_cm_ioctl_in_t ioctl; + ioctl.cid = m_cid; + ioctl.pdata_size = (uint8_t)PrivateDataLength; + if( pPrivateData != NULL ) + { + CopyMemory( &ioctl.pdata, pPrivateData, PrivateDataLength ); + } + + ND_PRINT( TRACE_LEVEL_INFORMATION, ND_DBG_NDI, + ("Connection rejected with pdata_size %d, cid %d\n", + (int)PrivateDataLength, ioctl.cid )); + + IO_STATUS_BLOCK IoStatus; + return NtDeviceIoControlFile( + m_pParent->m_hSync, + NULL, + NULL, + NULL, + &IoStatus, + UAL_NDI_REJ_CM, + &ioctl, + sizeof(ioctl), + NULL, + 0 ); +} + +HRESULT CConnector::GetConnectionData( + __out_opt SIZE_T* pInboundReadLimit, + __out_opt SIZE_T* pOutboundReadLimit, + __out_bcount_part_opt(*pPrivateDataLength, *pPrivateDataLength) void* pPrivateData, + __inout SIZE_T* pPrivateDataLength + ) +{ + ND_ENTER( ND_DBG_NDI ); + + IO_STATUS_BLOCK IoStatus; + ual_cep_get_pdata_ioctl_t IoctlBuf; + + IoctlBuf.in.cid = m_cid; + HRESULT hr = NtDeviceIoControlFile( + m_pParent->m_hSync, + NULL, + NULL, + NULL, + &IoStatus, + UAL_CEP_GET_PDATA, + &IoctlBuf, + sizeof(IoctlBuf.in), + &IoctlBuf, + sizeof(IoctlBuf.out) ); + + // UAL_CEP_GET_PDATA never returns pending. + if( FAILED( hr ) ) + return hr; + + // On the passive side, check that we got the REQ private data. + if( !m_fActive ) + { + hr = GetPdataForPassive( + IoctlBuf.out.pdata, + IoctlBuf.out.pdata_len, + pPrivateData, + pPrivateDataLength + ); + } + else + { + hr = GetPdataForActive( + IoctlBuf.out.pdata, + IoctlBuf.out.pdata_len, + pPrivateData, + pPrivateDataLength + ); + } + + if( FAILED( hr ) && hr != ND_BUFFER_OVERFLOW ) + return hr; + + if( pInboundReadLimit ) + { + *pInboundReadLimit = IoctlBuf.out.resp_res; + } + + if( pOutboundReadLimit ) + { + *pOutboundReadLimit = IoctlBuf.out.init_depth; + } + + return hr; +} + +HRESULT CConnector::GetLocalAddress( + __out_bcount_part_opt(*pAddressLength, *pAddressLength) struct sockaddr* pAddress, + __inout SIZE_T* pAddressLength + ) +{ + ND_ENTER( ND_DBG_NDI ); + + if( m_pEndpoint == NULL ) + return ND_CONNECTION_INVALID; + + ib_qp_state_t state = + m_pParent->m_Ifc.user_verbs.nd_get_qp_state( m_pEndpoint->m_uQp ); + if( state != IB_QPS_RTS ) + return ND_CONNECTION_INVALID; + + HRESULT hr = m_pParent->GetLocalAddress( pAddress, pAddressLength ); + if( FAILED(hr) ) + return hr; + + // V4 and V6 addresses have the port number in the same place. + ((struct sockaddr_in*)pAddress)->sin_port = m_LocalPort; +#if DBG || defined(EVENT_TRACING) + struct sockaddr_in*pAddrV4 = (struct sockaddr_in*)pAddress; +#endif + ND_PRINT( TRACE_LEVEL_INFORMATION, ND_DBG_NDI, + ("Local address: IP %#x, port %#hx\n", + cl_hton32(pAddrV4->sin_addr.S_un.S_addr), cl_hton16(pAddrV4->sin_port) ) ); + + return S_OK; +} + +HRESULT CConnector::GetAddressFromPdata( + __out_bcount_part(*pAddressLength, *pAddressLength) struct sockaddr* pAddress, + __inout SIZE_T* pAddressLength + ) +{ + ND_ENTER( ND_DBG_NDI ); + + IO_STATUS_BLOCK IoStatus; + ual_cep_get_pdata_ioctl_t IoctlBuf; + + IoctlBuf.in.cid = m_cid; + + HRESULT hr = NtDeviceIoControlFile( + m_pParent->m_hSync, + NULL, + NULL, + NULL, + &IoStatus, + UAL_CEP_GET_PDATA, + &IoctlBuf, + sizeof(IoctlBuf.in), + &IoctlBuf, + sizeof(IoctlBuf.out) ); + + // UAL_CEP_GET_PDATA never returns pending. + if( FAILED( hr ) ) + { + CL_ASSERT( hr != ND_PENDING ); + return hr; + } + + if( IoctlBuf.out.pdata_len != IB_REQ_PDATA_SIZE ) + return ND_CONNECTION_ABORTED; + + ib_cm_rdma_req_t* pIpData = (ib_cm_rdma_req_t*)&IoctlBuf.out.pdata; + CL_ASSERT( pIpData->maj_min_ver == 0 ); + + SIZE_T len; + switch( pIpData->ipv ) + { + case 0x40: + len = 4; + break; + case 0x60: + len = 16; + break; + default: + CL_ASSERT( pIpData->ipv == 0x40 || pIpData->ipv == 0x60 ); + len = 0; + break; + } + + if( len > *pAddressLength ) + { + *pAddressLength = len; + return ND_BUFFER_OVERFLOW; + } + + ((struct sockaddr_in*)pAddress)->sin_port = + _byteswap_ushort( pIpData->src_port ); + + switch( pIpData->ipv ) + { + case 0x40: + ((struct sockaddr_in*)pAddress)->sin_family = AF_INET; + ((struct sockaddr_in*)pAddress)->sin_addr.s_addr = pIpData->src_ip_addr[3]; + ZeroMemory( ((struct sockaddr_in*)pAddress)->sin_zero, + sizeof( ((struct sockaddr_in*)pAddress)->sin_zero ) ); + break; + + case 0x60: + ((struct sockaddr_in6*)pAddress)->sin6_family = AF_INET6; + ((struct sockaddr_in6*)pAddress)->sin6_flowinfo = 0; + RtlCopyMemory( (char*)((struct sockaddr_in6*)pAddress)->sin6_addr.s6_bytes, + (char *const)pIpData->src_ip_addr, sizeof(pIpData->src_ip_addr) ); + ((struct sockaddr_in6*)pAddress)->sin6_scope_id = 0; + break; + } + + *pAddressLength = len; + return hr; +} + +HRESULT CConnector::GetPeerAddress( + __out_bcount_part_opt(*pAddressLength, *pAddressLength) struct sockaddr* pAddress, + __inout SIZE_T* pAddressLength + ) +{ + ND_ENTER( ND_DBG_NDI ); + + if( !m_fActive ) + return GetAddressFromPdata( pAddress, pAddressLength ); + + if( m_pEndpoint == NULL ) + return ND_CONNECTION_INVALID; + + ib_qp_state_t state = + m_pParent->m_Ifc.user_verbs.nd_get_qp_state( m_pEndpoint->m_uQp ); + if( state != IB_QPS_RTS ) + return ND_CONNECTION_INVALID; + + switch( m_PeerAddr.v4.sin_family ) + { + case AF_INET: + if( *pAddressLength < sizeof(struct sockaddr_in) ) + { + *pAddressLength = sizeof(struct sockaddr_in); + return ND_BUFFER_OVERFLOW; + } + *(struct sockaddr_in*)pAddress = m_PeerAddr.v4; + ND_PRINT( TRACE_LEVEL_INFORMATION, ND_DBG_NDI, + ("Peer address: IP %#x, port %#hx\n", + cl_hton32(m_PeerAddr.v4.sin_addr.S_un.S_addr), cl_hton16(m_PeerAddr.v4.sin_port) ) ); + break; + + case AF_INET6: + if( *pAddressLength < sizeof(struct sockaddr_in6) ) + { + *pAddressLength = sizeof(struct sockaddr_in6); + return ND_BUFFER_OVERFLOW; + } + *(struct sockaddr_in6*)pAddress = m_PeerAddr.v6; + break; + + default: + return ND_CONNECTION_INVALID; + } + + return S_OK; +} + +HRESULT CConnector::NotifyDisconnect( + __inout OVERLAPPED* pOverlapped + ) +{ + ND_ENTER( ND_DBG_NDI ); + + pOverlapped->Internal = ND_PENDING; + return NtDeviceIoControlFile( + m_pParent->GetFileHandle(), + pOverlapped->hEvent, + NULL, + (ULONG_PTR)pOverlapped->hEvent & 1 ? NULL : pOverlapped, + (IO_STATUS_BLOCK*)&pOverlapped->Internal, + UAL_NDI_NOTIFY_DREQ, + &m_cid, + sizeof(m_cid), + NULL, + 0 ); +} + +HRESULT CConnector::Disconnect( + __inout OVERLAPPED* pOverlapped + ) +{ + ND_ENTER( ND_DBG_NDI ); + + if( m_pEndpoint == NULL ) + return ND_CONNECTION_INVALID; + + ib_qp_state_t state = + m_pParent->m_Ifc.user_verbs.nd_get_qp_state( m_pEndpoint->m_uQp ); + if( state != IB_QPS_RTS ) + return ND_CONNECTION_INVALID; + + // + // Get the UVP's buffer for modify operations. + // + void* pOutbuf; + DWORD szOutbuf; + + m_pParent->m_Ifc.user_verbs.nd_modify_qp( + m_pEndpoint->m_uQp, + &pOutbuf, + &szOutbuf + ); + + ND_PRINT( TRACE_LEVEL_INFORMATION, ND_DBG_NDI, + ("Disconnect QP %#I64x, QPn %#x\n", m_pEndpoint->m_hQp, m_pEndpoint->m_Qpn ) ); + + pOverlapped->Internal = ND_PENDING; + HRESULT hr = NtDeviceIoControlFile( + m_pParent->GetFileHandle(), + pOverlapped->hEvent, + NULL, + (ULONG_PTR)pOverlapped->hEvent & 1 ? NULL : pOverlapped, + (IO_STATUS_BLOCK*)&pOverlapped->Internal, + UAL_NDI_DREQ_CM, + &m_cid, + sizeof(m_cid), + pOutbuf, + szOutbuf ); + + if( SUCCEEDED( hr ) ) + { + m_pEndpoint->Release(); + m_pEndpoint = NULL; + } + + return hr; +} + +} // namespace diff --git a/branches/WOF2-3/ulp/nd/user/NdConnector.h b/branches/WOF2-3/ulp/nd/user/NdConnector.h new file mode 100644 index 00000000..6f701a9e --- /dev/null +++ b/branches/WOF2-3/ulp/nd/user/NdConnector.h @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id:$ + */ + +#pragma once + +#include "ndspi.h" +#include "nddebug.h" +#include +#include +#include +#include "ual_ci_ca.h" + + +namespace NetworkDirect +{ + +class CConnector : + public INDConnector +{ + friend class CListen; + +private: + CConnector(void); + ~CConnector(void); + void FreeCid(void); + +public: + static HRESULT Create( + __in CAdapter* pParent, + __deref_out INDConnector** ppConnector + ); + + // *** IUnknown methods *** + HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + LPVOID FAR* ppvObj + ); + + ULONG STDMETHODCALLTYPE AddRef(void); + + ULONG STDMETHODCALLTYPE Release(void); + + // *** INDOverlapped methods *** + HRESULT STDMETHODCALLTYPE CancelOverlappedRequests(void); + + HRESULT STDMETHODCALLTYPE GetOverlappedResult( + __inout OVERLAPPED *pOverlapped, + __out SIZE_T *pNumberOfBytesTransferred, + __in BOOL bWait + ); + + // *** INDConnector methods *** + HRESULT STDMETHODCALLTYPE CreateEndpoint( + __in INDCompletionQueue* pInboundCq, + __in INDCompletionQueue* pOutboundCq, + __in SIZE_T nInboundEntries, + __in SIZE_T nOutboundEntries, + __in SIZE_T nInboundSge, + __in SIZE_T nOutboundSge, + __in SIZE_T InboundReadLimit, + __in SIZE_T OutboundReadLimit, + __out_opt SIZE_T* pMaxInlineData, + __deref_out INDEndpoint** ppEndpoint + ); + + HRESULT STDMETHODCALLTYPE Connect( + __in INDEndpoint* pEndpoint, + __in_bcount(AddressLength) const struct sockaddr* pAddress, + __in SIZE_T AddressLength, + __in INT Protocol, + __in_opt USHORT LocalPort, + __in_bcount_opt(PrivateDataLength) const void* pPrivateData, + __in SIZE_T PrivateDataLength, + __inout OVERLAPPED* pOverlapped + ); + + HRESULT STDMETHODCALLTYPE CompleteConnect( + __inout OVERLAPPED* pOverlapped + ); + + HRESULT STDMETHODCALLTYPE Accept( + __in INDEndpoint* pEndpoint, + __in_bcount_opt(PrivateDataLength) const void* pPrivateData, + __in SIZE_T PrivateDataLength, + __inout OVERLAPPED* pOverlapped + ); + + HRESULT STDMETHODCALLTYPE Reject( + __in_bcount_opt(PrivateDataLength) const void* pPrivateData, + __in SIZE_T PrivateDataLength + ); + + HRESULT STDMETHODCALLTYPE GetConnectionData( + __out_opt SIZE_T* pInboundReadLimit, + __out_opt SIZE_T* pOutboundReadLimit, + __out_bcount_part_opt(*pPrivateDataLength, *pPrivateDataLength) void* pPrivateData, + __inout SIZE_T* pPrivateDataLength + ); + + HRESULT STDMETHODCALLTYPE GetLocalAddress( + __out_bcount_part_opt(*pAddressLength, *pAddressLength) struct sockaddr* pAddress, + __inout SIZE_T* pAddressLength + ); + + HRESULT STDMETHODCALLTYPE GetPeerAddress( + __out_bcount_part_opt(*pAddressLength, *pAddressLength) struct sockaddr* pAddress, + __inout SIZE_T* pAddressLength + ); + + HRESULT STDMETHODCALLTYPE NotifyDisconnect( + __inout_opt OVERLAPPED* pOverlapped + ); + + HRESULT STDMETHODCALLTYPE Disconnect( + __inout OVERLAPPED* pOverlapped + ); + +private: + HRESULT GetAddressFromPdata( + __out_bcount_part(*pAddressLength, *pAddressLength) struct sockaddr* pAddress, + __inout SIZE_T* pAddressLength + ); + +protected: + volatile LONG m_nRef; + + CAdapter* m_pParent; + + CEndpoint* m_pEndpoint; + + UINT8 m_Protocol; + USHORT m_LocalPort; + net32_t m_cid; + bool m_fActive; + + union _addr + { + struct sockaddr_in v4; + struct sockaddr_in6 v6; + + } m_PeerAddr; +}; + +} diff --git a/branches/WOF2-3/ulp/nd/user/NdCq.cpp b/branches/WOF2-3/ulp/nd/user/NdCq.cpp new file mode 100644 index 00000000..94c71c3b --- /dev/null +++ b/branches/WOF2-3/ulp/nd/user/NdCq.cpp @@ -0,0 +1,487 @@ +/* + * Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id:$ + */ + +#include "NdCq.h" +#include "NdAdapter.h" +#include "al_cq.h" +#include "al_dev.h" +#include "al.h" +#include "al_verbs.h" +#pragma warning( push, 3 ) +#include "winternl.h" +#pragma warning( pop ) +#include "limits.h" +#include "nddebug.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "NdCq.tmh" +#endif + + +namespace NetworkDirect +{ + + CCq::CCq(void) : + m_nRef( 1 ), + m_pParent( NULL ), + m_hCq( 0 ), + m_uCq( NULL ) + { + } + + CCq::~CCq(void) + { + if( m_hCq ) + CloseCq(); + + if( m_pParent ) + m_pParent->Release(); + } + + HRESULT CCq::Initialize( + CAdapter* pParent, + SIZE_T nEntries ) + { + if( nEntries > UINT_MAX ) + return ND_INVALID_PARAMETER; + + m_pParent = pParent; + pParent->AddRef(); + + return CreateCq( (UINT32)nEntries ); + } + + HRESULT CCq::QueryInterface( + REFIID riid, + LPVOID FAR* ppvObj + ) + { + if( IsEqualIID( riid, IID_IUnknown ) ) + { + *ppvObj = this; + return S_OK; + } + + if( IsEqualIID( riid, IID_INDCompletionQueue ) ) + { + *ppvObj = this; + return S_OK; + } + + return E_NOINTERFACE; + } + + ULONG CCq::AddRef(void) + { + return InterlockedIncrement( &m_nRef ); + } + + ULONG CCq::Release(void) + { + ULONG ref = InterlockedDecrement( &m_nRef ); + if( ref == 0 ) + delete this; + + return ref; + } + + // *** INDOverlapped methods *** + HRESULT CCq::CancelOverlappedRequests(void) + { + ND_ENTER( ND_DBG_NDI ); + + DWORD BytesRet; + DeviceIoControl( + m_pParent->m_hSync, + UAL_NDI_CANCEL_CQ, + &m_hCq, + sizeof(m_hCq), + NULL, + 0, + &BytesRet, + NULL + ); + + return S_OK; + } + + HRESULT CCq::GetOverlappedResult( + __inout OVERLAPPED *pOverlapped, + __out SIZE_T *pNumberOfBytesTransferred, + __in BOOL bWait + ) + { + ND_ENTER( ND_DBG_NDI ); + + *pNumberOfBytesTransferred = 0; + ::GetOverlappedResult( + m_pParent->GetFileHandle(), + pOverlapped, + (DWORD*)pNumberOfBytesTransferred, + bWait ); + ND_PRINT( TRACE_LEVEL_VERBOSE, ND_DBG_NDI, + ("==> %s, result %#x, bytes %d\n", __FUNCTION__, (int)pOverlapped->Internal, (int)*pNumberOfBytesTransferred )); + return (HRESULT)pOverlapped->Internal; + } + + // *** INDCompletionQueue methods *** + HRESULT CCq::Resize( + __in SIZE_T nEntries + ) + { + ND_ENTER( ND_DBG_NDI ); + + if( nEntries > UINT_MAX ) + return ND_INVALID_PARAMETER; + + ib_api_status_t status; + + /* Clear the IOCTL buffer */ + ual_modify_cq_ioctl_t cq_ioctl; + cl_memclr( &cq_ioctl, sizeof(cq_ioctl) ); + + /* Call the uvp pre call if the vendor library provided a valid ca handle */ + if( m_uCq && m_pParent->m_Ifc.user_verbs.pre_resize_cq ) + { + /* Pre call to the UVP library */ + status = m_pParent->m_Ifc.user_verbs.pre_resize_cq( + m_uCq, (uint32_t*)&nEntries, &cq_ioctl.in.umv_buf ); + if( status != IB_SUCCESS ) + goto exit; + } + + cq_ioctl.in.h_cq = m_hCq; + cq_ioctl.in.size = (DWORD)nEntries; + + DWORD BytesRet; + BOOL fSuccess = DeviceIoControl( + m_pParent->m_hSync, + UAL_MODIFY_CQ, + &cq_ioctl.in, + sizeof(cq_ioctl.in), + &cq_ioctl.out, + sizeof(cq_ioctl.out), + &BytesRet, + NULL + ); + + if( fSuccess != TRUE || BytesRet != sizeof(cq_ioctl.out) ) + status = IB_ERROR; + else + status = cq_ioctl.out.status; + + /* Post uvp call */ + if( m_uCq && m_pParent->m_Ifc.user_verbs.post_resize_cq ) + { + m_pParent->m_Ifc.user_verbs.post_resize_cq( + m_uCq, status, cq_ioctl.out.size, &cq_ioctl.out.umv_buf ); + } + +exit: + switch( status ) + { + case IB_INVALID_CQ_SIZE: + return ND_INVALID_PARAMETER; + + case IB_SUCCESS: + return S_OK; + + case IB_INSUFFICIENT_RESOURCES: + return ND_INSUFFICIENT_RESOURCES; + + default: + return ND_UNSUCCESSFUL; + } + } + + HRESULT CCq::Notify( + __in DWORD Type, + __inout OVERLAPPED* pOverlapped + ) + { +// ND_ENTER( ND_DBG_NDI ); + + ual_ndi_notify_cq_ioctl_in_t ioctl; + ioctl.h_cq = m_hCq; + ioctl.notify_comps = (boolean_t)Type; + pOverlapped->Internal = ND_PENDING; + HRESULT hr = NtDeviceIoControlFile( + m_pParent->GetFileHandle(), + pOverlapped->hEvent, + NULL, + (ULONG_PTR)pOverlapped->hEvent & 1 ? NULL : pOverlapped, + (IO_STATUS_BLOCK*)&pOverlapped->Internal, + UAL_NDI_NOTIFY_CQ, + &ioctl, + sizeof(ioctl), + NULL, + 0 ); + + if( hr == ND_PENDING && Type != ND_CQ_NOTIFY_ERRORS ) + { + m_pParent->m_Ifc.user_verbs.rearm_cq( + m_uCq, + (Type == ND_CQ_NOTIFY_SOLICITED) ? TRUE : FALSE + ); + ND_PRINT( TRACE_LEVEL_VERBOSE, ND_DBG_NDI, + ("==> %s, rearming with Type %d\n", __FUNCTION__, Type)); + } + else + { + ND_PRINT( TRACE_LEVEL_ERROR, ND_DBG_NDI, + ("==> %s failed: hr %#x, notify_type %d \n", __FUNCTION__, hr, Type )); + } + return hr; + } + + SIZE_T CCq::GetResults( + __out_ecount(nResults) ND_RESULT* pResults[], + __in SIZE_T nResults + ) + { +#if DBG + if (!(++g.c_cnt % 100000000)) // || !(rcv_pkts % 1000) || !(snd_pkts % 1000) + ND_PRINT( TRACE_LEVEL_VERBOSE, ND_DBG_NDI, + ("==> %s, cnt %I64d, rcv: %I64d:%I64d:%I64d, snd %I64d:%I64d:%I64d\n", + __FUNCTION__, g.c_cnt, + g.c_rcv_pkts, g.c_rcv_bytes, g.c_rcv_pkts_err, + g.c_snd_pkts, g.c_snd_bytes, g.c_snd_pkts_err)); +#endif + SIZE_T i = 0; + + while( nResults-- ) + { + ib_wc_t wc; + ib_wc_t* pWc = &wc; + ib_wc_t* pDoneWc; + wc.p_next = NULL; + ib_api_status_t status = + m_pParent->m_Ifc.user_verbs.poll_cq( m_uCq, &pWc, &pDoneWc ); + + if( status != IB_SUCCESS ) + break; + + pResults[i] = (ND_RESULT*)wc.wr_id; + if( wc.wc_type == IB_WC_RECV ) + pResults[i]->BytesTransferred = wc.length; + + if( wc.recv.conn.recv_opt & IB_RECV_OPT_IMMEDIATE ) + { + // Emulated receive with invalidate - the immediate + // data holds the RKey that is supposed to be invalidated. + + //TODO: We need the QP handle (or context) so we can force an + // error if we don't find a matching MW for the given RKEY. + // We also need to change the receive status in this case to + // ND_INVALIDATION_ERROR; + } + + switch( wc.status ) + { + case IB_WCS_SUCCESS: + pResults[i]->Status = ND_SUCCESS; + break; + case IB_WCS_LOCAL_LEN_ERR: + pResults[i]->Status = ND_LOCAL_LENGTH; + break; + case IB_WCS_LOCAL_OP_ERR: + case IB_WCS_LOCAL_ACCESS_ERR: + case IB_WCS_GENERAL_ERR: + default: + pResults[i]->Status = ND_INTERNAL_ERROR; + break; + case IB_WCS_LOCAL_PROTECTION_ERR: + case IB_WCS_MEM_WINDOW_BIND_ERR: + pResults[i]->Status = ND_ACCESS_VIOLATION; + break; + case IB_WCS_WR_FLUSHED_ERR: + pResults[i]->Status = ND_CANCELED; + break; + case IB_WCS_REM_INVALID_REQ_ERR: + pResults[i]->Status = ND_BUFFER_OVERFLOW; + break; + case IB_WCS_REM_ACCESS_ERR: + case IB_WCS_REM_OP_ERR: + case IB_WCS_BAD_RESP_ERR: + pResults[i]->Status = ND_REMOTE_ERROR; + break; + case IB_WCS_RNR_RETRY_ERR: + case IB_WCS_TIMEOUT_RETRY_ERR: + pResults[i]->Status = ND_TIMEOUT; + break; + } + i++; + // leo +#if DBG + { + if (wc.wc_type == IB_WC_RECV) + { + if (!wc.status) + { + ++g.c_rcv_pkts; + g.c_rcv_bytes += wc.length; + } + else + ++g.c_rcv_pkts_err; + } + else + { + if (!wc.status) + { + ++g.c_snd_pkts; + g.c_snd_bytes += wc.length; + } + else + ++g.c_snd_pkts_err; + } + } +#endif + continue; + } + return i; + } + + HRESULT CCq::CreateCq( + __in UINT32 nEntries ) + { + ND_ENTER( ND_DBG_NDI ); + + /* Clear the IOCTL buffer */ + ual_create_cq_ioctl_t cq_ioctl; + cl_memclr( &cq_ioctl, sizeof(cq_ioctl) ); + + /* Pre call to the UVP library */ + ib_api_status_t status; + if( m_pParent->m_uCa && m_pParent->m_Ifc.user_verbs.pre_create_cq ) + { + status = m_pParent->m_Ifc.user_verbs.pre_create_cq( + m_pParent->m_uCa, + &nEntries, + &cq_ioctl.in.umv_buf, + (ib_cq_handle_t*)(ULONG_PTR)&m_uCq + ); + if( status != IB_SUCCESS ) + goto done; + } + + cq_ioctl.in.h_ca = m_pParent->m_hCa; + cq_ioctl.in.size = nEntries; + cq_ioctl.in.h_wait_obj = NULL; + cq_ioctl.in.context = (ULONG_PTR)this; + cq_ioctl.in.ev_notify = FALSE; + + DWORD BytesRet; + BOOL fSuccess = DeviceIoControl( + m_pParent->m_hSync, + UAL_NDI_CREATE_CQ, + &cq_ioctl.in, + sizeof(cq_ioctl.in), + &cq_ioctl.out, + sizeof(cq_ioctl.out), + &BytesRet, + NULL + ); + + if( fSuccess != TRUE || BytesRet != sizeof(cq_ioctl.out) ) + status = IB_ERROR; + else + status = cq_ioctl.out.status; + + m_hCq = cq_ioctl.out.h_cq; + + /* Post uvp call */ + if( m_pParent->m_uCa && m_pParent->m_Ifc.user_verbs.post_create_cq ) + { + m_pParent->m_Ifc.user_verbs.post_create_cq( + m_pParent->m_uCa, + status, + cq_ioctl.out.size, + (ib_cq_handle_t*)(ULONG_PTR)&m_uCq, + &cq_ioctl.out.umv_buf ); + } + +done: + switch( status ) + { + case IB_INVALID_CQ_SIZE: + return ND_INVALID_PARAMETER; + + case IB_INSUFFICIENT_RESOURCES: + return ND_INSUFFICIENT_RESOURCES; + + case IB_INSUFFICIENT_MEMORY: + return ND_NO_MEMORY; + + case IB_SUCCESS: + return S_OK; + + default: + return ND_UNSUCCESSFUL; + } + } + + void CCq::CloseCq(void) + { + ND_ENTER( ND_DBG_NDI ); + + ib_api_status_t status; + + if( m_uCq && m_pParent->m_Ifc.user_verbs.pre_destroy_cq ) + { + /* Pre call to the UVP library */ + status = m_pParent->m_Ifc.user_verbs.pre_destroy_cq( m_uCq ); + if( status != IB_SUCCESS ) + return; + } + + DWORD BytesRet; + BOOL fSuccess = DeviceIoControl( + m_pParent->m_hSync, + UAL_DESTROY_CQ, + &m_hCq, + sizeof(m_hCq), + &status, + sizeof(status), + &BytesRet, + NULL + ); + + if( fSuccess != TRUE || BytesRet != sizeof(status) ) + status = IB_ERROR; + + if( m_uCq && m_pParent->m_Ifc.user_verbs.post_destroy_cq ) + m_pParent->m_Ifc.user_verbs.post_destroy_cq( m_uCq, status ); + } + +} // namespace diff --git a/branches/WOF2-3/ulp/nd/user/NdCq.h b/branches/WOF2-3/ulp/nd/user/NdCq.h new file mode 100644 index 00000000..f4bdb79a --- /dev/null +++ b/branches/WOF2-3/ulp/nd/user/NdCq.h @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id:$ + */ + +#pragma once +#include "ndspi.h" +#include +#include "al_cq.h" + + +namespace NetworkDirect +{ + class CAdapter; + + class CCq : + public INDCompletionQueue + { + friend class CEndpoint; + public: + CCq(void); + ~CCq(void); + + HRESULT Initialize( + CAdapter* pParent, + SIZE_T nEntries ); + + // *** IUnknown methods *** + HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + LPVOID FAR* ppvObj + ); + + ULONG STDMETHODCALLTYPE AddRef(void); + + ULONG STDMETHODCALLTYPE Release(void); + + // *** INDOverlapped methods *** + HRESULT STDMETHODCALLTYPE CancelOverlappedRequests(void); + + HRESULT STDMETHODCALLTYPE GetOverlappedResult( + __inout_opt OVERLAPPED *pOverlapped, + __out SIZE_T *pNumberOfBytesTransferred, + __in BOOL bWait + ); + + // *** INDCompletionQueue methods *** + HANDLE STDMETHODCALLTYPE GetAdapterFileHandle(void); + + HRESULT STDMETHODCALLTYPE Close(void); + + HRESULT STDMETHODCALLTYPE Resize( + __in SIZE_T nEntries + ); + + HRESULT STDMETHODCALLTYPE Notify( + __in DWORD Type, + __inout_opt OVERLAPPED* pOverlapped + ); + + SIZE_T STDMETHODCALLTYPE GetResults( + __out_ecount(nResults) ND_RESULT* pResults[], + __in SIZE_T nResults + ); + + private: + HRESULT CreateCq( + __in UINT32 nEntries ); + + HRESULT Complete( + __in HRESULT Status ); + + HRESULT ModifyCq( + __in SIZE_T nEntries ); + + void CloseCq(void); + + private: + volatile LONG m_nRef; + + CAdapter* m_pParent; + + UINT64 m_hCq; + ib_cq_handle_t m_uCq; + }; + +} // namespace diff --git a/branches/WOF2-3/ulp/nd/user/NdEndpoint.cpp b/branches/WOF2-3/ulp/nd/user/NdEndpoint.cpp new file mode 100644 index 00000000..9d322d38 --- /dev/null +++ b/branches/WOF2-3/ulp/nd/user/NdEndpoint.cpp @@ -0,0 +1,1035 @@ +/* + * Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id:$ + */ + +#include "NdEndpoint.h" +#include "NdCq.h" +#include "NdAdapter.h" +#include "NdMr.h" +#include "NdListen.h" +#include "limits.h" +#include "al_dev.h" +#pragma warning( push, 3 ) +#include "winternl.h" +#pragma warning( pop ) +#include "nddebug.h" + +extern uint32_t g_nd_max_inline_size; + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "NdEndpoint.tmh" +#endif + +#if DBG +dbg_data g = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; +#endif + +#ifndef SIZE_MAX +#ifdef _WIN64 +#define SIZE_MAX _UI64_MAX +#else +#define SIZE_MAX UINT_MAX +#endif +#endif + +namespace NetworkDirect +{ + +/////////////////////////////////////////////////////////////////////////////// +// +// HPC Pack 2008 Beta 2 SPI +// +/////////////////////////////////////////////////////////////////////////////// + + +CEndpoint::CEndpoint(void) : + m_nRef( 1 ), + m_pParent( NULL ), + m_hQp( 0 ) +{ +} + +CEndpoint::~CEndpoint(void) +{ + if( m_hQp ) + DestroyQp(); + + if( m_pParent ) + m_pParent->Release(); +} + +HRESULT CEndpoint::Initialize( + __in CAdapter* pParent, + __in CCq* pInboundCq, + __in CCq* pOutboundCq, + __in SIZE_T nInboundEntries, + __in SIZE_T nOutboundEntries, + __in SIZE_T nInboundSge, + __in SIZE_T nOutboundSge, + __in SIZE_T InboundReadLimit, + __in SIZE_T OutboundReadLimit, + __out_opt SIZE_T* pMaxInlineData + ) +{ + ND_ENTER( ND_DBG_NDI ); + + if( InboundReadLimit > UCHAR_MAX ) + return ND_INVALID_PARAMETER_8; + + if( OutboundReadLimit > UCHAR_MAX ) + return ND_INVALID_PARAMETER_9; + + m_pParent = pParent; + m_pParent->AddRef(); + + CL_ASSERT( + m_pParent->m_Ifc.user_verbs.pre_create_qp != NULL || + m_pParent->m_Ifc.user_verbs.post_create_qp != NULL || + m_pParent->m_Ifc.user_verbs.nd_modify_qp != NULL || + m_pParent->m_Ifc.user_verbs.nd_get_qp_state != NULL || + m_pParent->m_Ifc.user_verbs.pre_destroy_qp != NULL || + m_pParent->m_Ifc.user_verbs.post_destroy_qp != NULL || + m_pParent->m_Ifc.user_verbs.post_query_qp != NULL || + m_pParent->m_Ifc.user_verbs.post_send != NULL || + m_pParent->m_Ifc.user_verbs.post_recv != NULL /*|| + m_pParent->m_Ifc.user_verbs.bind_mw != NULL*/ ); + + m_MaxInlineSize = g_nd_max_inline_size; + + HRESULT hr = CreateQp( + pInboundCq, + pOutboundCq, + nInboundEntries, + nOutboundEntries, + nInboundSge, + nOutboundSge, + InboundReadLimit, + OutboundReadLimit, + m_MaxInlineSize ); + + if( FAILED( hr ) ) + return hr; + + ib_qp_attr_t qp_attr; + hr = QueryQp(&qp_attr); + if( FAILED( hr ) ) { + DestroyQp(); + return hr; + } + else + m_MaxInlineSize = (UINT32)qp_attr.sq_max_inline; + + + m_Ird = (UINT8)InboundReadLimit; + m_Ord = (UINT8)OutboundReadLimit; + + // Move the QP to the INIT state so users can post receives. + hr = ModifyQp( IB_QPS_INIT ); + if( FAILED( hr ) ) + DestroyQp(); + + if( SUCCEEDED( hr ) && pMaxInlineData != NULL ) + *pMaxInlineData = m_MaxInlineSize; + + return hr; +} + +HRESULT CEndpoint::Create( + __in CAdapter* pParent, + __in CCq* pInboundCq, + __in CCq* pOutboundCq, + __in SIZE_T nInboundEntries, + __in SIZE_T nOutboundEntries, + __in SIZE_T nInboundSge, + __in SIZE_T nOutboundSge, + __in SIZE_T InboundReadLimit, + __in SIZE_T OutboundReadLimit, + __out_opt SIZE_T* pMaxInlineData, + __out INDEndpoint** ppEndpoint + ) +{ + CEndpoint* pEp = new CEndpoint(); + if( pEp == NULL ) + return ND_NO_MEMORY; + + HRESULT hr = pEp->Initialize( + pParent, + pInboundCq, + pOutboundCq, + nInboundEntries, + nOutboundEntries, + nInboundSge, + nOutboundSge, + InboundReadLimit, + OutboundReadLimit, + pMaxInlineData + ); + + if( FAILED( hr ) ) + { + pEp->Release(); + return hr; + } + + *ppEndpoint = pEp; + return ND_SUCCESS; +} + +HRESULT CEndpoint::QueryInterface( + REFIID riid, + LPVOID FAR* ppvObj + ) +{ + if( IsEqualIID( riid, IID_IUnknown ) ) + { + *ppvObj = this; + return S_OK; + } + + if( IsEqualIID( riid, IID_INDEndpoint ) ) + { + *ppvObj = this; + return S_OK; + } + + return E_NOINTERFACE; +} + +ULONG CEndpoint::AddRef(void) +{ + return InterlockedIncrement( &m_nRef ); +} + +ULONG CEndpoint::Release(void) +{ + ULONG ref = InterlockedDecrement( &m_nRef ); + if( ref == 0 ) + delete this; + + return ref; +} + +// *** INDEndpoint methods *** +HRESULT CEndpoint::Flush(void) +{ + return ModifyQp( IB_QPS_ERROR ); +} + +void CEndpoint::StartRequestBatch(void) +{ + return; +} + +void CEndpoint::SubmitRequestBatch(void) +{ + return; +} + +HRESULT CEndpoint::Send( + __out ND_RESULT* pResult, + __in_ecount(nSge) const ND_SGE* pSgl, + __in SIZE_T nSge, + __in DWORD Flags + ) +{ + ib_send_wr_t wr; + ib_local_ds_t* pDs; + ib_local_ds_t ds[4]; + + if( nSge > UINT_MAX ) + return ND_DATA_OVERRUN; + else if( nSge <= 4 ) + pDs = ds; + else + { + pDs = new ib_local_ds_t[nSge]; + if( !pDs ) + return ND_NO_MEMORY; + } + + pResult->BytesTransferred = 0; + for( SIZE_T i = 0; i < nSge; i++ ) + { + pDs[i].vaddr = (ULONG_PTR)pSgl[i].pAddr; + if( pSgl[i].Length > UINT_MAX ) + { + if( nSge > 4 ) + delete[] pDs; + return ND_BUFFER_OVERFLOW; + } + pDs[i].length = (uint32_t)pSgl[i].Length; + pDs[i].lkey = ((CMr*)pSgl[i].hMr)->mr_ioctl.out.lkey; + + // Send completions don't include the length. It's going to + // be all or nothing, so store it now and we can reset if the + // request fails. + pResult->BytesTransferred += pSgl[i].Length; + } + + wr.p_next = NULL; + wr.wr_id = (ULONG_PTR)pResult; + wr.wr_type = WR_SEND; + if ( pResult->BytesTransferred <= m_MaxInlineSize ) + wr.send_opt = IB_SEND_OPT_INLINE; + else + wr.send_opt = 0; + + if( !(Flags & ND_OP_FLAG_SILENT_SUCCESS) ) + wr.send_opt |= IB_SEND_OPT_SIGNALED; + if( Flags & ND_OP_FLAG_READ_FENCE ) + wr.send_opt |= IB_SEND_OPT_FENCE; + if( Flags & ND_OP_FLAG_SEND_AND_SOLICIT_EVENT ) + wr.send_opt |= IB_SEND_OPT_SOLICITED; + wr.num_ds = (uint32_t)nSge; + wr.ds_array = pDs; + + ib_api_status_t status = + m_pParent->m_Ifc.user_verbs.post_send( m_uQp, &wr, NULL ); + if( nSge > 4 ) + delete[] pDs; + + // leo + CL_ASSERT( nSge || pSgl == NULL ); +#if DBG + if (!status ) + { + if (pSgl) + { + ++g.snd_pkts; + g.snd_bytes += pSgl[0].Length; + } + else + ++g.snd_pkts_zero; + } + else + ++g.snd_pkts_err; +#endif + + switch( status ) + { + case IB_SUCCESS: + return S_OK; + case IB_INSUFFICIENT_RESOURCES: + return ND_NO_MORE_ENTRIES; + case IB_INVALID_MAX_SGE: + return ND_DATA_OVERRUN; + case IB_INVALID_QP_STATE: + return ND_CONNECTION_INVALID; + default: + return ND_UNSUCCESSFUL; + } +} + +HRESULT CEndpoint::SendAndInvalidate( + __out ND_RESULT* pResult, + __in_ecount(nSge) const ND_SGE* pSgl, + __in SIZE_T nSge, + __in const ND_MW_DESCRIPTOR* pRemoteMwDescriptor, + __in DWORD Flags + ) +{ + ND_ENTER( ND_DBG_NDI ); + + ib_send_wr_t wr; + ib_local_ds_t* pDs; + + if( nSge > UINT_MAX ) + return ND_DATA_OVERRUN; + + pDs = new ib_local_ds_t[nSge]; + if( !pDs ) + return ND_NO_MEMORY; + + pResult->BytesTransferred = 0; + for( SIZE_T i = 0; i < nSge; i++ ) + { + pDs[i].vaddr = (ULONG_PTR)pSgl[i].pAddr; + if( pSgl[i].Length > UINT_MAX ) + { + delete[] pDs; + return ND_BUFFER_OVERFLOW; + } + pDs[i].length = (uint32_t)pSgl[i].Length; + pDs[i].lkey = ((CMr*)pSgl[i].hMr)->mr_ioctl.out.lkey; + + // Send completions don't include the length. It's going to + // be all or nothing, so store it now and we can reset if the + // request fails. + pResult->BytesTransferred += pSgl[i].Length; + } + + wr.p_next = NULL; + wr.wr_id = (ULONG_PTR)pResult; + wr.wr_type = WR_SEND; + if ( pResult->BytesTransferred <= m_MaxInlineSize ) + wr.send_opt = IB_SEND_OPT_INLINE; + else + wr.send_opt = 0; + // We simulate invalidate operations (since we simulate MW use). We + // put the RKey in the immediate data, the recipient will do the + // lookup of the MW based on that (as they would with a regular + // invalidate request). + wr.send_opt |= IB_SEND_OPT_IMMEDIATE; + if( !(Flags & ND_OP_FLAG_SILENT_SUCCESS) ) + wr.send_opt |= IB_SEND_OPT_SIGNALED; + if( Flags & ND_OP_FLAG_READ_FENCE ) + wr.send_opt |= IB_SEND_OPT_FENCE; + if( Flags & ND_OP_FLAG_SEND_AND_SOLICIT_EVENT ) + wr.send_opt |= IB_SEND_OPT_SOLICITED; + wr.num_ds = (uint32_t)nSge; + wr.ds_array = pDs; + // Put the RKey in the immeditate data. + wr.immediate_data = pRemoteMwDescriptor->Token; + + ib_api_status_t status = + m_pParent->m_Ifc.user_verbs.post_send( m_uQp, &wr, NULL ); + delete[] pDs; + + switch( status ) + { + case IB_SUCCESS: + return S_OK; + case IB_INSUFFICIENT_RESOURCES: + return ND_NO_MORE_ENTRIES; + case IB_INVALID_MAX_SGE: + return ND_DATA_OVERRUN; + case IB_INVALID_QP_STATE: + return ND_CONNECTION_INVALID; + default: + return ND_UNSUCCESSFUL; + } +} + +HRESULT CEndpoint::Receive( + __out ND_RESULT* pResult, + __in_ecount(nSge) const ND_SGE* pSgl, + __in SIZE_T nSge + ) +{ +#if DBG + if (!(++g.rcv_cnt % 1000)) + ND_PRINT( TRACE_LEVEL_VERBOSE, ND_DBG_NDI, + ("==> %s, cnt %I64d, rcv %I64d:%I64d:%I64d:%I64d\n", + __FUNCTION__, g.rcv_cnt, g.rcv_pkts, g.rcv_bytes, g.rcv_pkts_err, g.rcv_pkts_zero )); +#endif + ib_recv_wr_t wr; + ib_local_ds_t* pDs; + ib_local_ds_t ds[4]; + + if( nSge > UINT_MAX ) + return ND_DATA_OVERRUN; + else if( nSge <= 4 ) + pDs = ds; + else + { + pDs = new ib_local_ds_t[nSge]; + if( !pDs ) + return ND_NO_MEMORY; + } + + for( SIZE_T i = 0; i < nSge; i++ ) + { + pDs[i].vaddr = (ULONG_PTR)pSgl[i].pAddr; + if( pSgl[i].Length > UINT_MAX ) + { + if( nSge > 4 ) + delete[] pDs; + return ND_BUFFER_OVERFLOW; + } + pDs[i].length = (uint32_t)pSgl[i].Length; + pDs[i].lkey = ((CMr*)pSgl[i].hMr)->mr_ioctl.out.lkey; + } + + wr.p_next = NULL; + wr.wr_id = (ULONG_PTR)pResult; + wr.num_ds = (uint32_t)nSge; + wr.ds_array = pDs; + + ib_api_status_t status = + m_pParent->m_Ifc.user_verbs.post_recv( m_uQp, &wr, NULL ); + + if( nSge > 4 ) + delete[] pDs; + + // leo + CL_ASSERT( nSge || pSgl == NULL ); +#if DBG + if (!status) + { + if (pSgl) + { + ++g.rcv_pkts; + g.rcv_bytes += pSgl[0].Length; + } + else + ++g.rcv_pkts_zero; + } + else + ++g.rcv_pkts_err; +#endif + + switch( status ) + { + case IB_SUCCESS: + return S_OK; + case IB_INSUFFICIENT_RESOURCES: + return ND_NO_MORE_ENTRIES; + case IB_INVALID_MAX_SGE: + return ND_DATA_OVERRUN; + case IB_INVALID_QP_STATE: + return ND_CONNECTION_INVALID; + default: + return ND_UNSUCCESSFUL; + } +} + +HRESULT CEndpoint::Bind( + __out ND_RESULT* pResult, + __in ND_MR_HANDLE hMr, + __in INDMemoryWindow* pMw, + __in_bcount(BufferSize) const void* pBuffer, + __in SIZE_T BufferSize, + __in DWORD Flags, + __out ND_MW_DESCRIPTOR* pMwDescriptor + ) +{ + ND_ENTER( ND_DBG_NDI ); + + UNREFERENCED_PARAMETER( pMw ); + UNREFERENCED_PARAMETER( Flags ); + + CMr* pMr = ((CMr*)hMr); + + if( pBuffer < pMr->pBase || + pBuffer > pMr->pBase + pMr->Length ) + { + return ND_INVALID_PARAMETER_4; + } + + if( ((const char*)pBuffer + BufferSize) > (pMr->pBase + pMr->Length) ) + { + return ND_INVALID_PARAMETER_5; + } + + // Ok, this here is a workaround since the Mellanox HCA driver doesn't + // support MWs. This should be pushed into the HCA driver. + pMwDescriptor->Base = _byteswap_uint64( (UINT64)(ULONG_PTR)pBuffer ); + pMwDescriptor->Length = _byteswap_uint64( BufferSize ); + pMwDescriptor->Token = pMr->mr_ioctl.out.rkey; + + // Zero-byte RDMA write. Could also be a no-op on the send queue + // which would be better, but requires changing the HCA driver. + ib_send_wr_t wr; + wr.p_next = NULL; + wr.wr_id = (ULONG_PTR)pResult; + wr.wr_type = WR_RDMA_WRITE; + wr.send_opt = IB_SEND_OPT_SIGNALED; + wr.num_ds = 0; + wr.ds_array = NULL; + + wr.remote_ops.vaddr = 0; + wr.remote_ops.rkey = 0; + + pResult->BytesTransferred = 0; + + // TODO: Track the MW by rkey, so we can unbind it. + + ib_api_status_t status = + m_pParent->m_Ifc.user_verbs.post_send( m_uQp, &wr, NULL ); + + switch( status ) + { + case IB_SUCCESS: + return S_OK; + case IB_INSUFFICIENT_RESOURCES: + return ND_NO_MORE_ENTRIES; + case IB_INVALID_QP_STATE: + return ND_CONNECTION_INVALID; + default: + return ND_UNSUCCESSFUL; + } +} + +HRESULT CEndpoint::Invalidate( + __out ND_RESULT* pResult, + __in INDMemoryWindow* pMw, + __in DWORD Flags + ) +{ + ND_ENTER( ND_DBG_NDI ); + + UNREFERENCED_PARAMETER( pMw ); + UNREFERENCED_PARAMETER( Flags ); + + // Zero-byte RDMA write. Could also be a no-op on the send queue + // which would be better, but requires changing the HCA driver. + ib_send_wr_t wr; + wr.p_next = NULL; + wr.wr_id = (ULONG_PTR)pResult; + wr.wr_type = WR_RDMA_WRITE; + wr.send_opt = IB_SEND_OPT_SIGNALED; + wr.num_ds = 0; + wr.ds_array = NULL; + + wr.remote_ops.vaddr = 0; + wr.remote_ops.rkey = 0; + + pResult->BytesTransferred = 0; + + ib_api_status_t status = + m_pParent->m_Ifc.user_verbs.post_send( m_uQp, &wr, NULL ); + + switch( status ) + { + case IB_SUCCESS: + // TODO: Stop trackign MW + return S_OK; + case IB_INSUFFICIENT_RESOURCES: + return ND_NO_MORE_ENTRIES; + case IB_INVALID_QP_STATE: + return ND_CONNECTION_INVALID; + default: + return ND_UNSUCCESSFUL; + } +} + +HRESULT CEndpoint::Rdma( + __out ND_RESULT* pResult, + __in ib_wr_type_t Type, + __in_ecount(nSge) const ND_SGE* pSgl, + __in SIZE_T nSge, + __in const ND_MW_DESCRIPTOR* pRemoteMwDescriptor, + __in ULONGLONG Offset, + __in DWORD Flags + ) +{ +// ND_ENTER( ND_DBG_NDI ); + + ib_send_wr_t wr; + ib_local_ds_t* pDs; + ib_local_ds_t ds[4]; + + if( nSge > UINT_MAX ) + return ND_DATA_OVERRUN; + else if( nSge <= 4 ) + pDs = ds; + else + { + pDs = new ib_local_ds_t[nSge]; + if( !pDs ) + return ND_NO_MEMORY; + } + + pResult->BytesTransferred = 0; + for( SIZE_T i = 0; i < nSge; i++ ) + { + pDs[i].vaddr = (ULONG_PTR)pSgl[i].pAddr; + if( pSgl[i].Length > UINT_MAX ) + { + if( nSge > 4 ) + delete[] pDs; + return ND_BUFFER_OVERFLOW; + } + pDs[i].length = (uint32_t)pSgl[i].Length; + pDs[i].lkey = ((CMr*)pSgl[i].hMr)->mr_ioctl.out.lkey; + + //TODO: temporary - a workaround of test bug + //leo + if( (int)pSgl[i].Length < 0 ) + { + pDs[i].length = 0 - (int)pSgl[i].Length; +#if DBG + ND_PRINT( TRACE_LEVEL_VERBOSE, ND_DBG_NDI, + ("nSge %d, i %d, Length %#x\n", nSge, i, pSgl[i].Length )); + if( nSge > 4 ) + delete[] pDs; + return ND_BUFFER_OVERFLOW; +#endif + } + + // Send completions don't include the length. It's going to + // be all or nothing, so store it now and we can reset if the + // request fails. + pResult->BytesTransferred += pSgl[i].Length; + } + + wr.p_next = NULL; + wr.wr_id = (ULONG_PTR)pResult; + wr.wr_type = Type; + if ( (pResult->BytesTransferred <= m_MaxInlineSize) && Type != WR_RDMA_READ) + wr.send_opt = IB_SEND_OPT_INLINE; + else + wr.send_opt = 0; + if( !(Flags & ND_OP_FLAG_SILENT_SUCCESS) ) + wr.send_opt |= IB_SEND_OPT_SIGNALED; + if( Flags & ND_OP_FLAG_READ_FENCE ) + wr.send_opt |= IB_SEND_OPT_FENCE; + wr.num_ds = (uint32_t)nSge; + wr.ds_array = pDs; + + UINT64 vaddr = _byteswap_uint64( pRemoteMwDescriptor->Base ); + vaddr += Offset; + wr.remote_ops.vaddr = vaddr; + wr.remote_ops.rkey = pRemoteMwDescriptor->Token; + + ib_api_status_t status = + m_pParent->m_Ifc.user_verbs.post_send( m_uQp, &wr, NULL ); + + if( nSge > 4 ) + delete[] pDs; + + switch( status ) + { + case IB_SUCCESS: + return S_OK; + case IB_INSUFFICIENT_RESOURCES: + return ND_NO_MORE_ENTRIES; + case IB_INVALID_MAX_SGE: + return ND_DATA_OVERRUN; + case IB_INVALID_QP_STATE: + return ND_CONNECTION_INVALID; + default: + return ND_UNSUCCESSFUL; + } +} + +HRESULT CEndpoint::Read( + __out ND_RESULT* pResult, + __in_ecount(nSge) const ND_SGE* pSgl, + __in SIZE_T nSge, + __in const ND_MW_DESCRIPTOR* pRemoteMwDescriptor, + __in ULONGLONG Offset, + __in DWORD Flags + ) +{ +// ND_ENTER( ND_DBG_NDI ); + + return Rdma( pResult, WR_RDMA_READ, pSgl, nSge, + pRemoteMwDescriptor, Offset, Flags ); +} + +HRESULT CEndpoint::Write( + __out ND_RESULT* pResult, + __in_ecount(nSge) const ND_SGE* pSgl, + __in SIZE_T nSge, + __in const ND_MW_DESCRIPTOR* pRemoteMwDescriptor, + __in ULONGLONG Offset, + __in DWORD Flags + ) +{ +// ND_ENTER( ND_DBG_NDI ); + + return Rdma( pResult, WR_RDMA_WRITE, pSgl, nSge, + pRemoteMwDescriptor, Offset, Flags ); +} + +HRESULT CEndpoint::CreateQp( + __in CCq* pInboundCq, + __in CCq* pOutboundCq, + __in SIZE_T nInboundEntries, + __in SIZE_T nOutboundEntries, + __in SIZE_T nInboundSge, + __in SIZE_T nOutboundSge, + __in SIZE_T InboundReadLimit, + __in SIZE_T OutboundReadLimit, + __in SIZE_T MaxInlineData + ) +{ + ND_ENTER( ND_DBG_NDI ); + + if( MaxInlineData > UINT_MAX ) + return ND_INVALID_PARAMETER_3; + if( nInboundEntries > UINT_MAX ) + return ND_INVALID_PARAMETER_4; + if( nOutboundEntries > UINT_MAX ) + return ND_INVALID_PARAMETER_5; + if( nInboundSge > UINT_MAX ) + return ND_INVALID_PARAMETER_6; + if( nOutboundSge > UINT_MAX ) + return ND_INVALID_PARAMETER_7; + if( InboundReadLimit > UCHAR_MAX ) + return ND_INVALID_PARAMETER_9; + if( OutboundReadLimit > UCHAR_MAX ) + return ND_INVALID_PARAMETER_10; + + /* Setup the qp_ioctl */ + ual_create_qp_ioctl_t qp_ioctl; + cl_memclr( &qp_ioctl, sizeof(qp_ioctl) ); + + qp_ioctl.in.qp_create.qp_type = IB_QPT_RELIABLE_CONN; + qp_ioctl.in.qp_create.sq_depth = (uint32_t)nOutboundEntries; + qp_ioctl.in.qp_create.rq_depth = (uint32_t)nInboundEntries; + qp_ioctl.in.qp_create.sq_sge = (uint32_t)nOutboundSge; + qp_ioctl.in.qp_create.rq_sge = (uint32_t)nInboundSge; + qp_ioctl.in.qp_create.sq_max_inline = (uint32_t)MaxInlineData; + qp_ioctl.in.qp_create.h_srq = NULL; + qp_ioctl.in.qp_create.sq_signaled = FALSE; + + /* Pre call to the UVP library */ + CL_ASSERT( m_pParent->m_Ifc.user_verbs.pre_create_qp ); + qp_ioctl.in.qp_create.h_sq_cq = pOutboundCq->m_uCq; + qp_ioctl.in.qp_create.h_rq_cq = pInboundCq->m_uCq; + ib_api_status_t status = m_pParent->m_Ifc.user_verbs.pre_create_qp( + m_pParent->m_uPd, + &qp_ioctl.in.qp_create, + &qp_ioctl.in.umv_buf, + (ib_qp_handle_t*)(ULONG_PTR)&m_uQp + ); + if( status != IB_SUCCESS ) + return ND_INSUFFICIENT_RESOURCES; + + /* + * Convert the handles to KAL handles once again starting + * from the input qp attribute + */ + qp_ioctl.in.h_pd = m_pParent->m_hPd; + qp_ioctl.in.qp_create.h_sq_cq = (ib_cq_handle_t)pOutboundCq->m_hCq; + qp_ioctl.in.qp_create.h_rq_cq = (ib_cq_handle_t)pInboundCq->m_hCq; + qp_ioctl.in.context = (ULONG_PTR)this; + qp_ioctl.in.ev_notify = FALSE; + + DWORD bytes_ret; + BOOL fSuccess = DeviceIoControl( + m_pParent->m_hSync, + UAL_CREATE_QP, + &qp_ioctl.in, + sizeof(qp_ioctl.in), + &qp_ioctl.out, + sizeof(qp_ioctl.out), + &bytes_ret, + NULL ); + + if( fSuccess != TRUE || bytes_ret != sizeof(qp_ioctl.out) ) + qp_ioctl.out.status = IB_ERROR; + + /* Post uvp call */ + CL_ASSERT( m_pParent->m_Ifc.user_verbs.post_create_qp ); + m_pParent->m_Ifc.user_verbs.post_create_qp( + m_pParent->m_uPd, + qp_ioctl.out.status, + (ib_qp_handle_t*)(ULONG_PTR)&m_uQp, + &qp_ioctl.out.umv_buf + ); + + + switch( qp_ioctl.out.status ) + { + case IB_SUCCESS: + m_hQp = qp_ioctl.out.h_qp; + m_Qpn = qp_ioctl.out.attr.num; + ND_PRINT( TRACE_LEVEL_INFORMATION, ND_DBG_NDI, + ("Created QP %#I64x, QPn %#x, pd %#I64x, context %p \n", + m_hQp, m_Qpn, m_pParent->m_hPd, this ) ); + return S_OK; + + case IB_INVALID_MAX_WRS: + if( nInboundEntries > nOutboundEntries ) + return ND_INVALID_PARAMETER_4; + else + return ND_INVALID_PARAMETER_5; + + case IB_INVALID_MAX_SGE: + if( nInboundSge > nOutboundSge ) + return ND_INVALID_PARAMETER_6; + else + return ND_INVALID_PARAMETER_7; + + case IB_INSUFFICIENT_MEMORY: + return ND_NO_MEMORY; + + default: + return ND_INSUFFICIENT_RESOURCES; + } +} + +void CEndpoint::DestroyQp() +{ + ND_ENTER( ND_DBG_NDI ); + + /* Call the uvp pre call if the vendor library provided a valid QP handle */ + CL_ASSERT( m_pParent->m_Ifc.user_verbs.pre_destroy_qp ); + m_pParent->m_Ifc.user_verbs.pre_destroy_qp( m_uQp ); + + ual_destroy_qp_ioctl_t qp_ioctl; + cl_memclr( &qp_ioctl, sizeof(qp_ioctl) ); + qp_ioctl.in.h_qp = m_hQp; + + ND_PRINT( TRACE_LEVEL_INFORMATION, ND_DBG_NDI, + ("Destroy QP %I64x\n", m_hQp) ); + + DWORD bytes_ret; + BOOL fSuccess = DeviceIoControl( + m_pParent->m_hSync, + UAL_DESTROY_QP, + &qp_ioctl.in, + sizeof(qp_ioctl.in), + &qp_ioctl.out, + sizeof(qp_ioctl.out), + &bytes_ret, + NULL + ); + + if( fSuccess != TRUE || bytes_ret != sizeof(qp_ioctl.out) ) + qp_ioctl.out.status = IB_ERROR; + + ND_PRINT( TRACE_LEVEL_INFORMATION, ND_DBG_NDI, + ("Destroyed QP %#I64x, QPn %#x, pd %#I64x, context %p \n", + m_hQp, m_Qpn, m_pParent->m_hPd, this ) ); + + /* Call vendor's post_destroy_qp */ + CL_ASSERT( m_pParent->m_Ifc.user_verbs.post_destroy_qp ); + m_pParent->m_Ifc.user_verbs.post_destroy_qp( + m_uQp, + qp_ioctl.out.status + ); + m_hQp = NULL; +} + +HRESULT CEndpoint::ModifyQp( + __in ib_qp_state_t NewState ) +{ + ND_ENTER( ND_DBG_NDI ); + + /* Setup the qp_ioctl */ + ual_ndi_modify_qp_ioctl_in_t qp_ioctl; + cl_memclr( &qp_ioctl, sizeof(qp_ioctl) ); + + switch( NewState ) + { + case IB_QPS_INIT: + qp_ioctl.qp_mod.state.init.primary_port = m_pParent->m_PortNum; + qp_ioctl.qp_mod.state.init.qkey = 0; + qp_ioctl.qp_mod.state.init.pkey_index = 0; + qp_ioctl.qp_mod.state.init.access_ctrl = + IB_AC_LOCAL_WRITE | IB_AC_RDMA_READ | IB_AC_RDMA_WRITE; + + // Fall through. + case IB_QPS_RESET: + case IB_QPS_ERROR: + qp_ioctl.qp_mod.req_state = NewState; + } + + /* Call the uvp ND modify verb */ + CL_ASSERT( m_pParent->m_Ifc.user_verbs.nd_modify_qp ); + void* pOutbuf; + DWORD szOutbuf; + + m_pParent->m_Ifc.user_verbs.nd_modify_qp( + m_uQp, + &pOutbuf, + &szOutbuf + ); + + qp_ioctl.h_qp = m_hQp; + + DWORD bytes_ret; + BOOL fSuccess = DeviceIoControl( + m_pParent->m_hSync, + UAL_NDI_MODIFY_QP, + &qp_ioctl, + sizeof(qp_ioctl), + pOutbuf, + szOutbuf, + &bytes_ret, + NULL ); + + if( fSuccess != TRUE ) + return ND_UNSUCCESSFUL; + + return S_OK; +} + +HRESULT CEndpoint::QueryQp( + __out ib_qp_attr_t *qp_attr + ) +{ + ib_api_status_t status; + + ND_ENTER( ND_DBG_NDI ); + + ual_query_qp_ioctl_t qp_ioctl; + cl_memclr( &qp_ioctl, sizeof(qp_ioctl) ); + qp_ioctl.in.h_qp = m_hQp; + + /* Call the uvp pre call if the vendor library provided a valid ca handle */ + if( m_pParent->m_Ifc.user_verbs.pre_query_qp ) + { + /* Pre call to the UVP library */ + status = m_pParent->m_Ifc.user_verbs.pre_query_qp( m_uQp, &qp_ioctl.in.umv_buf ); + if( status != IB_SUCCESS ) + goto done; + } + + DWORD bytes_ret; + BOOL fSuccess = DeviceIoControl( + m_pParent->m_hSync, + UAL_QUERY_QP, + &qp_ioctl.in, + sizeof(qp_ioctl.in), + &qp_ioctl.out, + sizeof(qp_ioctl.out), + &bytes_ret, + NULL + ); + + if( fSuccess != TRUE || bytes_ret != sizeof(qp_ioctl.out) ) + status = IB_ERROR; + else + status = qp_ioctl.out.status; + + /* Call vendor's post_query_qp */ + CL_ASSERT( m_pParent->m_Ifc.user_verbs.post_query_qp ); + if( m_pParent->m_Ifc.user_verbs.post_query_qp ) + { + m_pParent->m_Ifc.user_verbs.post_query_qp( m_uQp, status, + &qp_ioctl.out.attr, &qp_ioctl.out.umv_buf ); + } + +done: + ND_PRINT( TRACE_LEVEL_INFORMATION, ND_DBG_NDI, + ("Queried QP %#I64x, QPn %#x, pd %#I64x, context %p, status %#x \n", + m_hQp, m_Qpn, m_pParent->m_hPd, this, status ) ); + + switch( status ) + { + case IB_SUCCESS: + *qp_attr = qp_ioctl.out.attr; + return S_OK; + + default: + return ND_UNSUCCESSFUL; + } + +} + +} // namespace diff --git a/branches/WOF2-3/ulp/nd/user/NdEndpoint.h b/branches/WOF2-3/ulp/nd/user/NdEndpoint.h new file mode 100644 index 00000000..fd1eabd4 --- /dev/null +++ b/branches/WOF2-3/ulp/nd/user/NdEndpoint.h @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id:$ + */ + +#pragma once +#include "ndspi.h" +#include +#include + + +namespace NetworkDirect +{ + + +/////////////////////////////////////////////////////////////////////////////// +// +// HPC Pack 2008 Beta 2 SPI +// +/////////////////////////////////////////////////////////////////////////////// + +class CAdapter; +class CCq; + +class CEndpoint : + public INDEndpoint +{ + friend class CConnector; + +private: + CEndpoint(void); + ~CEndpoint(void); + + HRESULT Initialize( + __in CAdapter* pParent, + __in CCq* pInboundCq, + __in CCq* pOutboundCq, + __in SIZE_T nInboundEntries, + __in SIZE_T nOutboundEntries, + __in SIZE_T nInboundSge, + __in SIZE_T nOutboundSge, + __in SIZE_T InboundReadLimit, + __in SIZE_T OutboundReadLimit, + __out_opt SIZE_T* pMaxInlineData + ); + +public: + static HRESULT Create( + __in CAdapter* pParent, + __in CCq* pInboundCq, + __in CCq* pOutboundCq, + __in SIZE_T nInboundEntries, + __in SIZE_T nOutboundEntries, + __in SIZE_T nInboundSge, + __in SIZE_T nOutboundSge, + __in SIZE_T InboundReadLimit, + __in SIZE_T OutboundReadLimit, + __out_opt SIZE_T* pMaxInlineData, + __out INDEndpoint** ppEndpoint + ); + + // *** IUnknown methods *** + HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + LPVOID FAR* ppvObj + ); + + ULONG STDMETHODCALLTYPE AddRef(void); + + ULONG STDMETHODCALLTYPE Release(void); + + // *** INDEndpoint methods *** + HRESULT STDMETHODCALLTYPE Flush(void); + + void STDMETHODCALLTYPE StartRequestBatch(void); + + void STDMETHODCALLTYPE SubmitRequestBatch(void); + + HRESULT STDMETHODCALLTYPE Send( + __out ND_RESULT* pResult, + __in_ecount(nSge) const ND_SGE* pSgl, + __in SIZE_T nSge, + __in DWORD Flags + ); + + HRESULT STDMETHODCALLTYPE SendAndInvalidate( + __out ND_RESULT* pResult, + __in_ecount(nSge) const ND_SGE* pSgl, + __in SIZE_T nSge, + __in const ND_MW_DESCRIPTOR* pRemoteMwDescriptor, + __in DWORD Flags + ); + + HRESULT STDMETHODCALLTYPE Receive( + __out ND_RESULT* pResult, + __in_ecount(nSge) const ND_SGE* pSgl, + __in SIZE_T nSge + ); + + HRESULT STDMETHODCALLTYPE Bind( + __out ND_RESULT* pResult, + __in ND_MR_HANDLE hMr, + __in INDMemoryWindow* pMw, + __in_bcount(BufferSize) const void* pBuffer, + __in SIZE_T BufferSize, + __in DWORD Flags, + __out ND_MW_DESCRIPTOR* pMwDescriptor + ); + + HRESULT STDMETHODCALLTYPE Invalidate( + __out ND_RESULT* pResult, + __in INDMemoryWindow* pMw, + __in DWORD Flags + ); + + HRESULT STDMETHODCALLTYPE Read( + __out ND_RESULT* pResult, + __in_ecount(nSge) const ND_SGE* pSgl, + __in SIZE_T nSge, + __in const ND_MW_DESCRIPTOR* pRemoteMwDescriptor, + __in ULONGLONG Offset, + __in DWORD Flags + ); + + HRESULT STDMETHODCALLTYPE Write( + __out ND_RESULT* pResult, + __in_ecount(nSge) const ND_SGE* pSgl, + __in SIZE_T nSge, + __in const ND_MW_DESCRIPTOR* pRemoteMwDescriptor, + __in ULONGLONG Offset, + __in DWORD Flags + ); + +private: + HRESULT Rdma( + __out ND_RESULT* pResult, + __in ib_wr_type_t Type, + __in_ecount(nSge) const ND_SGE* pSgl, + __in SIZE_T nSge, + __in const ND_MW_DESCRIPTOR* pRemoteMwDescriptor, + __in ULONGLONG Offset, + __in DWORD Flags + ); + + HRESULT CreateQp( + __in CCq* pInboundCq, + __in CCq* pOutboundCq, + __in SIZE_T nInboundEntries, + __in SIZE_T nOutboundEntries, + __in SIZE_T nInboundSge, + __in SIZE_T nOutboundSge, + __in SIZE_T InboundReadLimit, + __in SIZE_T OutboundReadLimit, + __in SIZE_T MaxInlineData + ); + + void DestroyQp(); + + HRESULT QueryQp( + __out ib_qp_attr_t *qp_attr + ); + + HRESULT ModifyQp( + __in ib_qp_state_t NewState + ); + +protected: + volatile LONG m_nRef; + + CAdapter* m_pParent; + + uint64_t m_hQp; + ib_qp_handle_t m_uQp; + + net32_t m_Qpn; + + UINT8 m_Ird; + UINT8 m_Ord; + UINT32 m_MaxInlineSize; +}; + +} // namespace diff --git a/branches/WOF2-3/ulp/nd/user/NdListen.cpp b/branches/WOF2-3/ulp/nd/user/NdListen.cpp new file mode 100644 index 00000000..82f01110 --- /dev/null +++ b/branches/WOF2-3/ulp/nd/user/NdListen.cpp @@ -0,0 +1,385 @@ +/* + * Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id:$ + */ + +#include "NdListen.h" +#include "NdAdapter.h" +#include "NdEndpoint.h" +#include "NdConnector.h" +#include "al_dev.h" +#pragma warning( push, 3 ) +#include "winternl.h" +#pragma warning( pop ) +#include +#include +#include "nddebug.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "NdListen.tmh" +#endif + +namespace NetworkDirect +{ + +HRESULT GetPdataForPassive( + __in UINT8* pSrc, + __in SIZE_T SrcLength, + __out_bcount_part_opt(*pPrivateDataLength, *pPrivateDataLength) void* pPrivateData, + __inout SIZE_T* pPrivateDataLength + ) +{ + if( SrcLength != IB_REQ_PDATA_SIZE ) + { + ND_PRINT( TRACE_LEVEL_ERROR, ND_DBG_NDI, + ("Connection aborted: incorrect pdata_len %d \n", (int)SrcLength )); + return ND_CONNECTION_ABORTED; + } + + if( pPrivateDataLength == NULL ) + return S_OK; + + ib_cm_rdma_req_t* pIpData = (ib_cm_rdma_req_t*)pSrc; + CL_ASSERT( pIpData->maj_min_ver == 0 ); + CL_ASSERT( pIpData->ipv == 0x40 || pIpData->ipv == 0x60 ); + + if( *pPrivateDataLength == 0 ) + { + *pPrivateDataLength = sizeof(pIpData->pdata); + return ND_BUFFER_OVERFLOW; + } + + CopyMemory( + pPrivateData, + pIpData->pdata, + min( *pPrivateDataLength, sizeof(pIpData->pdata) ) + ); + + HRESULT hr; + if( *pPrivateDataLength < sizeof(pIpData->pdata) ) + { + hr = ND_BUFFER_OVERFLOW; + } + else + { + hr = S_OK; + } + + *pPrivateDataLength = sizeof(pIpData->pdata); + return hr; +} + +HRESULT GetPdataForActive( + __in UINT8* pSrc, + __in SIZE_T SrcLength, + __out_bcount_part_opt(*pPrivateDataLength, *pPrivateDataLength) void* pPrivateData, + __inout SIZE_T* pPrivateDataLength + ) +{ + if( pPrivateDataLength == NULL ) + return S_OK; + + if( *pPrivateDataLength == 0 ) + { + *pPrivateDataLength = SrcLength; + return ND_BUFFER_OVERFLOW; + } + + CopyMemory( + pPrivateData, + pSrc, + min( *pPrivateDataLength, SrcLength ) ); + + HRESULT hr; + if( *pPrivateDataLength < IB_REJ_PDATA_SIZE ) + { + hr = ND_BUFFER_OVERFLOW; + } + else + { + hr = S_OK; + } + + *pPrivateDataLength = SrcLength; + return hr; +} + + CListen::CListen(void) : + m_nRef( 1 ), + m_pParent( NULL ), + m_cid( 0 ) + { + } + + CListen::~CListen(void) + { + if( m_cid != 0 ) + { + DWORD bytes_ret; + DeviceIoControl( + m_pParent->m_hSync, + UAL_DESTROY_CEP, + &m_cid, + sizeof(m_cid), + NULL, + 0, + &bytes_ret, + NULL ); + } + + if( m_pParent ) + m_pParent->Release(); + } + + HRESULT CListen::Initialize( + __in CAdapter* pParent, + __in SIZE_T Backlog, + __in INT Protocol, + __in USHORT Port, + __out_opt USHORT* pAssignedPort + ) + { + ND_ENTER( ND_DBG_NDI ); + + m_pParent = pParent; + m_pParent->AddRef(); + + UNREFERENCED_PARAMETER( Backlog ); + + if( Port == 0 && pAssignedPort == NULL ) + return ND_INVALID_PARAMETER_MIX; + + // + // IP Addressing Annex only supports a single byte for protocol. + // + if( Protocol > UCHAR_MAX || Protocol < 0 ) + return ND_INVALID_PARAMETER_3; + + ual_cep_listen_ioctl_t listen; + listen.cid = 0; + + listen.cep_listen.svc_id = + 0x0000000001000000 | Protocol << 16 | Port; + + listen.cep_listen.port_guid = m_pParent->m_PortGuid; + + switch( m_pParent->m_Addr.v4.sin_family ) + { + case AF_INET: + ZeroMemory( listen.compare, ATS_IPV4_OFFSET ); + CopyMemory( &listen.compare[ATS_IPV4_OFFSET], + (uint8_t*)&m_pParent->m_Addr.v4.sin_addr, + sizeof(m_pParent->m_Addr.v4.sin_addr) ); + ND_PRINT( TRACE_LEVEL_INFORMATION, ND_DBG_NDI, + ("Listen for: IP %#x, port %#hx\n", + cl_hton32(m_pParent->m_Addr.v4.sin_addr.S_un.S_addr), cl_hton16(m_pParent->m_Addr.v4.sin_port) ) ); + break; + case AF_INET6: + CopyMemory( listen.compare, + (uint8_t*)&m_pParent->m_Addr.v6.sin6_addr, + sizeof(m_pParent->m_Addr.v6.sin6_addr) ); + break; + } + listen.cep_listen.p_cmp_buf = listen.compare; + listen.cep_listen.cmp_len = 16; + listen.cep_listen.cmp_offset = FIELD_OFFSET( ib_cm_rdma_req_t, dst_ip_addr ); + + IO_STATUS_BLOCK IoStatus; + IoStatus.Status = NtDeviceIoControlFile( + m_pParent->m_hSync, + NULL, + NULL, + NULL, + &IoStatus, + UAL_NDI_LISTEN_CM, + &listen, + sizeof(listen), + &m_cid, + sizeof(m_cid) ); + + switch( IoStatus.Status ) + { + case ND_SUCCESS: + ND_PRINT( TRACE_LEVEL_INFORMATION, ND_DBG_NDI, + ("Listen for: Guid %#I64x, sid %#I64x\n", + m_pParent->m_PortGuid, listen.cep_listen.svc_id ) ); + break; + + case IB_INVALID_SETTING: + return ND_ADDRESS_ALREADY_EXISTS; + + default: + return IoStatus.Status; + } + + ND_PRINT( TRACE_LEVEL_INFORMATION, ND_DBG_NDI, + ("Created listen CEP with cid %d \n", m_cid ) ); + + // TODO: Come up with something better for port number. + if( Port == 0 ) + Port = (USHORT)m_cid | (USHORT)(m_cid >> 16); + + if( pAssignedPort ) + *pAssignedPort = Port; + + m_Protocol = (UINT8)Protocol; + return S_OK; + } + + HRESULT CListen::Create( + __in CAdapter* pParent, + __in SIZE_T Backlog, + __in INT Protocol, + __in USHORT Port, + __out_opt USHORT* pAssignedPort, + __deref_out INDListen** ppListen + ) + { + CListen* pListen = new CListen(); + if( pListen == NULL ) + return ND_NO_MEMORY; + + HRESULT hr = pListen->Initialize( + pParent, + Backlog, + Protocol, + Port, + pAssignedPort ); + if( FAILED( hr ) ) + { + delete pListen; + return hr; + } + + *ppListen = pListen; + return S_OK; + } + + // *** IUnknown methods *** + HRESULT CListen::QueryInterface( + REFIID riid, + LPVOID FAR* ppvObj + ) + { + if( IsEqualIID( riid, IID_IUnknown ) ) + { + *ppvObj = this; + return S_OK; + } + + if( IsEqualIID( riid, IID_INDListen ) ) + { + *ppvObj = this; + return S_OK; + } + + return E_NOINTERFACE; + } + + ULONG CListen::AddRef(void) + { + return InterlockedIncrement( &m_nRef ); + } + + ULONG CListen::Release(void) + { + ULONG ref = InterlockedDecrement( &m_nRef ); + if( ref == 0 ) + delete this; + + return ref; + } + + // *** INDOverlapped methods *** + HRESULT CListen::CancelOverlappedRequests(void) + { + ND_ENTER( ND_DBG_NDI ); + + DWORD bytes_ret; + BOOL ret = DeviceIoControl( + m_pParent->m_hSync, + UAL_NDI_CANCEL_CM_IRPS, + &m_cid, + sizeof(m_cid), + NULL, + 0, + &bytes_ret, + NULL ); + + if( ret ) + return S_OK; + else + return ND_UNSUCCESSFUL; + } + + HRESULT CListen::GetOverlappedResult( + __inout OVERLAPPED *pOverlapped, + __out SIZE_T *pNumberOfBytesTransferred, + __in BOOL bWait + ) + { + ND_ENTER( ND_DBG_NDI ); + + *pNumberOfBytesTransferred = 0; + ::GetOverlappedResult( + m_pParent->GetFileHandle(), + pOverlapped, + (DWORD*)pNumberOfBytesTransferred, + bWait ); + return (HRESULT)pOverlapped->Internal; + } + + // *** INDListen methods *** + HRESULT CListen::GetConnectionRequest( + __inout INDConnector* pConnector, + __inout OVERLAPPED* pOverlapped + ) + { + ND_ENTER( ND_DBG_NDI ); + + static_cast(pConnector)->m_Protocol = m_Protocol; + + pOverlapped->Internal = ND_PENDING; + return NtDeviceIoControlFile( + m_pParent->GetFileHandle(), + pOverlapped->hEvent, + NULL, + (ULONG_PTR)pOverlapped->hEvent & 1 ? NULL : pOverlapped, + (IO_STATUS_BLOCK*)&pOverlapped->Internal, + UAL_NDI_GET_REQ_CM, + &m_cid, + sizeof(m_cid), + &static_cast(pConnector)->m_cid, + sizeof(static_cast(pConnector)->m_cid) ); + } + +} // namespace diff --git a/branches/WOF2-3/ulp/nd/user/NdListen.h b/branches/WOF2-3/ulp/nd/user/NdListen.h new file mode 100644 index 00000000..3372fbf8 --- /dev/null +++ b/branches/WOF2-3/ulp/nd/user/NdListen.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id:$ + */ + +#pragma once +#include "ndspi.h" +#include + + +namespace NetworkDirect +{ + +HRESULT GetPdataForPassive( + __in UINT8* pSrc, + __in SIZE_T SrcLength, + __out_bcount_part_opt(*pPrivateDataLength, *pPrivateDataLength) void* pPrivateData, + __inout SIZE_T* pPrivateDataLength + ); + +HRESULT GetPdataForActive( + __in UINT8* pSrc, + __in SIZE_T SrcLength, + __out_bcount_part_opt(*pPrivateDataLength, *pPrivateDataLength) void* pPrivateData, + __inout SIZE_T* pPrivateDataLength + ); + +class CAdapter; + +class CListen : + public INDListen +{ +private: + CListen(void); + ~CListen(void); + + HRESULT Initialize( + __in CAdapter* pParent, + __in SIZE_T Backlog, + __in INT Protocol, + __in USHORT Port, + __out_opt USHORT* pAssignedPort + ); + +public: + static HRESULT Create( + __in CAdapter* pParent, + __in SIZE_T Backlog, + __in INT Protocol, + __in USHORT Port, + __out_opt USHORT* pAssignedPort, + __deref_out INDListen** ppListen + ); + + // *** IUnknown methods *** + HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + LPVOID FAR* ppvObj + ); + + ULONG STDMETHODCALLTYPE AddRef(void); + + ULONG STDMETHODCALLTYPE Release(void); + + // *** INDOverlapped methods *** + HRESULT STDMETHODCALLTYPE CancelOverlappedRequests(void); + + HRESULT STDMETHODCALLTYPE GetOverlappedResult( + __inout OVERLAPPED *pOverlapped, + __out SIZE_T *pNumberOfBytesTransferred, + __in BOOL bWait + ); + + // *** INDListen methods *** + HRESULT STDMETHODCALLTYPE GetConnectionRequest( + __inout INDConnector* pConnector, + __inout OVERLAPPED* pOverlapped + ); + +private: + volatile LONG m_nRef; + + CAdapter* m_pParent; + + UINT8 m_Protocol; + net32_t m_cid; +}; + +} // namespace diff --git a/branches/WOF2-3/ulp/nd/user/NdMr.cpp b/branches/WOF2-3/ulp/nd/user/NdMr.cpp new file mode 100644 index 00000000..2216e63f --- /dev/null +++ b/branches/WOF2-3/ulp/nd/user/NdMr.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id:$ + */ + +#include +#include "ndspi.h" +#include "NdMr.h" + + +namespace NetworkDirect +{ + + CMr::CMr(void) + { + } + + CMr::~CMr(void) + { + } + +} // namespace diff --git a/branches/WOF2-3/ulp/nd/user/NdMr.h b/branches/WOF2-3/ulp/nd/user/NdMr.h new file mode 100644 index 00000000..1b320e63 --- /dev/null +++ b/branches/WOF2-3/ulp/nd/user/NdMr.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id:$ + */ + +#pragma once + +#include "iba/ib_al_ioctl.h" + + +namespace NetworkDirect +{ + + class CMr + { + friend class CAdapter; + friend class CEndpoint; + + public: + CMr(void); + ~CMr(void); + + protected: + const char* pBase; + uint32_t Length; + ual_reg_mem_ioctl_t mr_ioctl; + }; + +} // namespace diff --git a/branches/WOF2-3/ulp/nd/user/NdMw.cpp b/branches/WOF2-3/ulp/nd/user/NdMw.cpp new file mode 100644 index 00000000..cc10eb04 --- /dev/null +++ b/branches/WOF2-3/ulp/nd/user/NdMw.cpp @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id:$ + */ + +#include "NdMw.h" +#include "NdAdapter.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "NdMw.tmh" +#endif + + +namespace NetworkDirect +{ + + CMw::CMw(void) : + m_nRef( 1 ), + m_pParent( NULL ) + { + } + + CMw::~CMw(void) + { + if( m_pParent ) + m_pParent->Release(); + } + + HRESULT CMw::Initialize( + CAdapter* pParent, + ND_RESULT* pInvalidateResult + ) + { + m_pParent = pParent; + m_pParent->AddRef(); + + m_pInvalidateResult = pInvalidateResult; + return S_OK; + } + + HRESULT CMw::QueryInterface( + REFIID riid, + LPVOID FAR* ppvObj + ) + { + if( IsEqualIID( riid, IID_IUnknown ) ) + { + *ppvObj = this; + return S_OK; + } + + if( IsEqualIID( riid, IID_INDMemoryWindow ) ) + { + *ppvObj = this; + return S_OK; + } + + return E_NOINTERFACE; + } + + ULONG CMw::AddRef(void) + { + return InterlockedIncrement( &m_nRef ); + } + + ULONG CMw::Release(void) + { + ULONG ref = InterlockedDecrement( &m_nRef ); + if( ref == 0 ) + delete this; + + return ref; + } + + HRESULT CMw::Close(void) + { + Release(); + return S_OK; + } + +} // namespace diff --git a/branches/WOF2-3/ulp/nd/user/NdMw.h b/branches/WOF2-3/ulp/nd/user/NdMw.h new file mode 100644 index 00000000..be1f0d44 --- /dev/null +++ b/branches/WOF2-3/ulp/nd/user/NdMw.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id:$ + */ + +#pragma once +#include "ndspi.h" + + +namespace NetworkDirect +{ + + class CAdapter; + + class CMw : + public INDMemoryWindow + { + public: + CMw(void); + ~CMw(void); + + HRESULT Initialize( + CAdapter* pParent, + ND_RESULT* pInvalidateResult ); + + // *** IUnknown methods *** + HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + LPVOID FAR* ppvObj + ); + + ULONG STDMETHODCALLTYPE AddRef(void); + + ULONG STDMETHODCALLTYPE Release(void); + + // *** INDMemoryWindow methods *** + HRESULT STDMETHODCALLTYPE Close(void); + + //operator ND_RESULT*(){ return m_pInvalidateResult; }; + + private: + volatile LONG m_nRef; + + CAdapter* m_pParent; + + ND_RESULT* m_pInvalidateResult; + }; + +} // namespace \ No newline at end of file diff --git a/branches/WOF2-3/ulp/nd/user/NdProv.cpp b/branches/WOF2-3/ulp/nd/user/NdProv.cpp new file mode 100644 index 00000000..fe584baa --- /dev/null +++ b/branches/WOF2-3/ulp/nd/user/NdProv.cpp @@ -0,0 +1,576 @@ +/* + * Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id:$ + */ + +#include +#include +#include +#include +#include +#pragma warning( push, 3 ) +#include +#include +#include +#include +#include +#include +#pragma warning( pop ) +#include "ndprov.h" +#include "ndadapter.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "NdProv.tmh" +#endif + +#include "nddebug.h" + +uint32_t g_nd_dbg_level = TRACE_LEVEL_ERROR; +/* WPP doesn't want here literals! */ +uint32_t g_nd_dbg_flags = 0x80000001; /* ND_DBG_ERROR | ND_DBG_NDI; */ +uint32_t g_nd_max_inline_size = 160; + +HANDLE ghHeap; + + +namespace NetworkDirect +{ + + static LONG gnRef = 0; + + CProvider::CProvider() : + m_nRef( 1 ) + { + InterlockedIncrement( &gnRef ); + } + + CProvider::~CProvider() + { + InterlockedDecrement( &gnRef ); + } + + HRESULT CProvider::QueryInterface( + const IID &riid, + void **ppObject ) + { + if( IsEqualIID( riid, IID_IUnknown ) ) + { + *ppObject = this; + return S_OK; + } + + if( IsEqualIID( riid, IID_INDProvider ) ) + { + *ppObject = this; + return S_OK; + } + + return E_NOINTERFACE; + } + + ULONG CProvider::AddRef() + { + return InterlockedIncrement( &m_nRef ); + } + + ULONG CProvider::Release() + { + ULONG ref = InterlockedDecrement( &m_nRef ); + if( ref == 0 ) + delete this; + + return ref; + } + + HRESULT CProvider::QueryAddressList( + __out_bcount_part_opt(*pBufferSize, *pBufferSize) SOCKET_ADDRESS_LIST* pAddressList, + __inout SIZE_T* pBufferSize ) + { + ND_ENTER( ND_DBG_NDI ); + + HANDLE hIbatDev = CreateFileW( IBAT_WIN32_NAME, + MAXIMUM_ALLOWED, 0, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); + if( hIbatDev == INVALID_HANDLE_VALUE ) + return ND_NO_MEMORY; + + IOCTL_IBAT_IP_ADDRESSES_IN addrIn; + + addrIn.Version = IBAT_IOCTL_VERSION; + addrIn.PortGuid = 0; + + DWORD size = sizeof(IOCTL_IBAT_IP_ADDRESSES_OUT); + IOCTL_IBAT_IP_ADDRESSES_OUT *pAddrOut; + do + { + pAddrOut = (IOCTL_IBAT_IP_ADDRESSES_OUT*)HeapAlloc( + GetProcessHeap(), + 0, + size ); + if( !pAddrOut ) + { + //AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + // ("Failed to allocate output buffer.\n") ); + return ND_NO_MEMORY; + } + + if( !DeviceIoControl( hIbatDev, IOCTL_IBAT_IP_ADDRESSES, + &addrIn, sizeof(addrIn), pAddrOut, size, &size, NULL ) ) + { + HeapFree( GetProcessHeap(), 0, pAddrOut ); + //AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, + // ("IOCTL_IBAT_IP_ADDRESSES failed (%x).\n", GetLastError()) ); + return ND_UNSUCCESSFUL; + } + + if( pAddrOut->Size > size ) + { + size = pAddrOut->Size; + HeapFree( GetProcessHeap(), 0, pAddrOut ); + pAddrOut = NULL; + } + + } while( !pAddrOut ); + + CloseHandle( hIbatDev ); + + // + // Note: the required size computed is a few bytes larger than necessary, + // but that keeps the code clean. + // + SIZE_T size_req = sizeof(SOCKET_ADDRESS_LIST); + + switch( pAddrOut->AddressCount ) + { + case 0: + break; + + default: + size_req += (pAddrOut->AddressCount - 1) * + (sizeof(SOCKET_ADDRESS) + sizeof(SOCKADDR)); + /* Fall through. */ + __fallthrough; + + case 1: + /* Add the space for the first address. */ + size_req += sizeof(SOCKADDR); + break; + } + + if( size_req > *pBufferSize ) + { + HeapFree( GetProcessHeap(), 0, pAddrOut ); + *pBufferSize = size_req; + return ND_BUFFER_OVERFLOW; + } + + ZeroMemory( pAddressList, *pBufferSize ); + + /* We store the array of addresses after the last address pointer: + * iAddressCount + * Address[0]; <-- points to sockaddr[0] + * Address[1]; <-- points to sockaddr[1] + * ... + * Address[n-1]; <-- points to sockaddr[n-1] + * sockaddr[0]; + * sockaddr[1]; + * ... + * sockaddr[n-1] + */ + BYTE* pBuf = (BYTE*)(&(pAddressList->Address[pAddrOut->AddressCount])); + *pBufferSize = size_req; + + pAddressList->iAddressCount = 0; + for( LONG i = 0; i < pAddrOut->AddressCount; i++ ) + { + pAddressList->Address[pAddressList->iAddressCount].lpSockaddr = + (LPSOCKADDR)pBuf; + + switch( pAddrOut->Address[i].IpVersion ) + { + case 4: + { + struct sockaddr_in* pAddr4 = ((struct sockaddr_in*)pBuf); + pAddr4->sin_family = AF_INET; + pAddr4->sin_addr.s_addr = + *((u_long*)&pAddrOut->Address[i].Address[12]); + pAddressList->Address[pAddressList->iAddressCount].iSockaddrLength = + sizeof(struct sockaddr_in); + } + break; + + case 6: + { + struct sockaddr_in6* pAddr6 = ((struct sockaddr_in6*)pBuf); + pAddr6->sin6_family = AF_INET6; + CopyMemory( + &pAddr6->sin6_addr, + pAddrOut->Address[i].Address, + sizeof(pAddr6->sin6_addr) ); + pAddressList->Address[pAddressList->iAddressCount].iSockaddrLength = + sizeof(struct sockaddr_in6); + } + break; + + default: + continue; + } + + pBuf += pAddressList->Address[pAddressList->iAddressCount++].iSockaddrLength; + } + + HeapFree( GetProcessHeap(), 0, pAddrOut ); + + return S_OK; + } + + HRESULT CProvider::OpenAdapter( + __in_bcount(AddressLength) const struct sockaddr* pAddress, + __in SIZE_T AddressLength, + __deref_out INDAdapter** ppAdapter ) + { + ND_ENTER( ND_DBG_NDI ); + + if( AddressLength < sizeof(struct sockaddr) ) + return ND_INVALID_ADDRESS; + + IOCTL_IBAT_IP_TO_PORT_IN in; + in.Version = IBAT_IOCTL_VERSION; + + switch( pAddress->sa_family ) + { + case AF_INET: + if( AddressLength < sizeof(struct sockaddr_in) ) + return ND_INVALID_ADDRESS; + in.Address.IpVersion = 4; + RtlCopyMemory( + &in.Address.Address[12], + &((struct sockaddr_in*)pAddress)->sin_addr, + sizeof( ((struct sockaddr_in*)pAddress)->sin_addr ) ); + break; + + case AF_INET6: + if( AddressLength < sizeof(struct sockaddr_in6) ) + return ND_INVALID_ADDRESS; + in.Address.IpVersion = 6; + RtlCopyMemory( + in.Address.Address, + &((struct sockaddr_in6*)pAddress)->sin6_addr, + sizeof(in.Address.Address) ); + break; + + default: + return ND_INVALID_ADDRESS; + } + + HANDLE hIbatDev = CreateFileW( IBAT_WIN32_NAME, + MAXIMUM_ALLOWED, 0, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); + if( hIbatDev == INVALID_HANDLE_VALUE ) + return ND_NO_MEMORY; + + IBAT_PORT_RECORD out; + DWORD size; + BOOL fSuccess = DeviceIoControl( hIbatDev, IOCTL_IBAT_IP_TO_PORT, + &in, sizeof(in), &out, sizeof(out), &size, NULL ); + + CloseHandle( hIbatDev ); + if( !fSuccess || size == 0 ) + return ND_INVALID_ADDRESS; + + return CAdapter::Create( this, pAddress, &out, ppAdapter ); + } + + CClassFactory::CClassFactory(void) : + m_nRef( 1 ) + { + InterlockedIncrement( &gnRef ); + } + + CClassFactory::~CClassFactory(void) + { + InterlockedDecrement( &gnRef ); + } + + HRESULT CClassFactory::QueryInterface( + REFIID riid, + void** ppObject ) + { + if( IsEqualIID( riid, IID_IUnknown ) ) + { + *ppObject = this; + return S_OK; + } + if( IsEqualIID( riid, IID_IClassFactory ) ) + { + *ppObject = this; + return S_OK; + } + + return E_NOINTERFACE; + } + + ULONG CClassFactory::AddRef() + { + return InterlockedIncrement( &m_nRef ); + } + + ULONG CClassFactory::Release() + { + ULONG ref = InterlockedDecrement( &m_nRef ); + if( ref == 0 ) + delete this; + + return ref; + } + + HRESULT CClassFactory::CreateInstance( + IUnknown* pUnkOuter, + REFIID riid, + void** ppObject ) + { + if( pUnkOuter != NULL ) + return CLASS_E_NOAGGREGATION; + + if( IsEqualIID( riid, IID_INDProvider ) ) + { + *ppObject = new CProvider(); + if( !*ppObject ) + return E_OUTOFMEMORY; + + return S_OK; + } + + return E_NOINTERFACE; + } + + HRESULT CClassFactory::LockServer( BOOL fLock ) + { + UNREFERENCED_PARAMETER( fLock ); + return S_OK; + } + +} // namespace + +void* __cdecl operator new( + size_t count + ) +{ + return HeapAlloc( ghHeap, 0, count ); +} + + +void __cdecl operator delete( + void* object + ) +{ + HeapFree( ghHeap, 0, object ); +} + +extern "C" { +STDAPI DllGetClassObject( + REFCLSID rclsid, + REFIID riid, + LPVOID * ppv + ) +{ + ND_ENTER( ND_DBG_NDI ); + + UNREFERENCED_PARAMETER( rclsid ); + + if( IsEqualIID( riid, IID_IClassFactory ) ) + { + NetworkDirect::CClassFactory* pFactory = new NetworkDirect::CClassFactory(); + if( pFactory == NULL ) + return E_OUTOFMEMORY; + + *ppv = pFactory; + return S_OK; + } + + return E_NOINTERFACE; +} + +STDAPI DllCanUnloadNow(void) +{ + ND_ENTER( ND_DBG_NDI ); + + if( InterlockedCompareExchange( &NetworkDirect::gnRef, 0, 0 ) != 0 ) + return S_FALSE; + + return S_OK; +} + +int +WSPAPI +WSPStartup( + IN WORD wVersionRequested, + OUT LPWSPDATA lpWSPData, + IN LPWSAPROTOCOL_INFOW lpProtocolInfo, + IN WSPUPCALLTABLE UpcallTable, + OUT LPWSPPROC_TABLE lpProcTable + ) +{ + UNREFERENCED_PARAMETER( wVersionRequested ); + UNREFERENCED_PARAMETER( lpWSPData ); + UNREFERENCED_PARAMETER( lpProtocolInfo ); + UNREFERENCED_PARAMETER( UpcallTable ); + UNREFERENCED_PARAMETER( lpProcTable ); + return WSASYSNOTREADY; +} + +static BOOL +_DllMain( + IN HINSTANCE hinstDll, + IN DWORD dwReason, + IN LPVOID lpvReserved ) +{ + + ND_ENTER( ND_DBG_NDI ); + + UNUSED_PARAM( hinstDll ); + UNUSED_PARAM( lpvReserved ); + + switch( dwReason ) + { + case DLL_PROCESS_ATTACH: + TCHAR env_var[16]; + DWORD i; + + +#if defined(EVENT_TRACING) +#if DBG + WPP_INIT_TRACING(L"ibndprov.dll"); +#else + WPP_INIT_TRACING(L"ibndprov.dll"); +#endif +#elif DBG + i = GetEnvironmentVariable( "IBNDPROV_DBG_LEVEL", env_var, sizeof(env_var) ); + if( i && i <= 16 ) + { + g_nd_dbg_level = _tcstoul( env_var, NULL, 16 ); + } + + i = GetEnvironmentVariable( "IBNDPROV_DBG_FLAGS", env_var, sizeof(env_var) ); + if( i && i <= 16 ) + { + g_nd_dbg_flags = _tcstoul( env_var, NULL, 16 ); + } + + if( g_nd_dbg_flags & ND_DBG_ERR ) + g_nd_dbg_flags |= CL_DBG_ERROR; + + ND_PRINT( TRACE_LEVEL_ERROR, ND_DBG_ERR , + ("(pcs %#x) IbNdProv: Debug print: level:%d, flags 0x%x\n", + GetCurrentProcessId(), g_nd_dbg_level ,g_nd_dbg_flags) ); +#endif + + i = GetEnvironmentVariable( "IBNDPROV_MAX_INLINE_SIZE", env_var, sizeof(env_var) ); + if( i && i <= 16 ) + { + g_nd_max_inline_size = _tcstoul( env_var, NULL, 16 ); + } + + ghHeap = HeapCreate( 0, 0, 0 ); + if( ghHeap == NULL ) + { + ND_PRINT_EXIT( + TRACE_LEVEL_ERROR, ND_DBG_NDI, ("Failed to allocate private heap.\n") ); +#if defined(EVENT_TRACING) + WPP_CLEANUP(); +#endif + return FALSE; + } + + ND_PRINT(TRACE_LEVEL_INFORMATION, ND_DBG_NDI, ("DllMain: DLL_PROCESS_ATTACH\n") ); + break; + + case DLL_PROCESS_DETACH: + HeapDestroy( ghHeap ); + ND_PRINT(TRACE_LEVEL_INFORMATION, ND_DBG_NDI, + ("DllMain: DLL_PROCESS_DETACH, ref count %d\n", NetworkDirect::gnRef) ); + +#if defined(EVENT_TRACING) + WPP_CLEANUP(); +#endif + break; + } + + ND_EXIT( ND_DBG_NDI ); + + return TRUE; +} + + +extern BOOL APIENTRY +_DllMainCRTStartupForGS( + IN HINSTANCE h_module, + IN DWORD ul_reason_for_call, + IN LPVOID lp_reserved ); + + +BOOL APIENTRY +DllMain( + IN HINSTANCE h_module, + IN DWORD ul_reason_for_call, + IN LPVOID lp_reserved ) +{ + switch( ul_reason_for_call ) + { + case DLL_PROCESS_ATTACH: + if( !_DllMainCRTStartupForGS( + h_module, ul_reason_for_call, lp_reserved ) ) + { + return FALSE; + } + + return _DllMain( h_module, ul_reason_for_call, lp_reserved ); + + case DLL_THREAD_ATTACH: + ND_PRINT(TRACE_LEVEL_INFORMATION, ND_DBG_NDI, ("DllMain: DLL_THREAD_ATTACH\n") ); + break; + + case DLL_THREAD_DETACH: + ND_PRINT(TRACE_LEVEL_INFORMATION, ND_DBG_NDI, ("DllMain: DLL_THREAD_DETACH\n") ); + break; + + case DLL_PROCESS_DETACH: + _DllMain( h_module, ul_reason_for_call, lp_reserved ); + + return _DllMainCRTStartupForGS( + h_module, ul_reason_for_call, lp_reserved ); + } + return TRUE; +} + +} // extern "C" + diff --git a/branches/WOF2-3/ulp/nd/user/NdProv.def b/branches/WOF2-3/ulp/nd/user/NdProv.def new file mode 100644 index 00000000..f2fb99c5 --- /dev/null +++ b/branches/WOF2-3/ulp/nd/user/NdProv.def @@ -0,0 +1,6 @@ +LIBRARY IbNdProv.dll + +EXPORTS + DllGetClassObject private + WSPStartup + DllCanUnloadNow private \ No newline at end of file diff --git a/branches/WOF2-3/ulp/nd/user/NdProv.h b/branches/WOF2-3/ulp/nd/user/NdProv.h new file mode 100644 index 00000000..21de4a70 --- /dev/null +++ b/branches/WOF2-3/ulp/nd/user/NdProv.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id:$ + */ + +#pragma once +#include + +#ifdef __cplusplus +namespace NetworkDirect +{ + + +/////////////////////////////////////////////////////////////////////////////// +// +// HPC Pack 2008 Beta 2 SPI +// +/////////////////////////////////////////////////////////////////////////////// + +class CProvider : + public INDProvider +{ + friend class CClassFactory; + +public: + CProvider(void); + ~CProvider(void); + + // IUnknown Methods + HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + void** ppObject + ); + + ULONG STDMETHODCALLTYPE AddRef(void); + ULONG STDMETHODCALLTYPE Release(void); + + // INDProvider Methods + HRESULT STDMETHODCALLTYPE QueryAddressList( + __out_bcount_part_opt(*pBufferSize, *pBufferSize) SOCKET_ADDRESS_LIST* pAddressList, + __inout SIZE_T* pBufferSize + ); + + HRESULT STDMETHODCALLTYPE OpenAdapter( + __in_bcount(AddressLength) const struct sockaddr* pAddress, + __in SIZE_T AddressLength, + __deref_out INDAdapter** ppAdapter + ); + +private: + volatile LONG m_nRef; +}; + + +class CClassFactory : public IClassFactory +{ +public: + CClassFactory(void); + ~CClassFactory(void); + + // IUnknown Methods. + HRESULT STDMETHODCALLTYPE QueryInterface( REFIID riid, void** ppObject ); + ULONG STDMETHODCALLTYPE AddRef(void); + ULONG STDMETHODCALLTYPE Release(void); + + // IClassFactory Methods. + HRESULT STDMETHODCALLTYPE CreateInstance( IUnknown* pUnkOuter, REFIID riid, void** ppObject ); + HRESULT STDMETHODCALLTYPE LockServer( BOOL fLock ); + +private: + volatile LONG m_nRef; +}; + +} // namespace + +void* __cdecl operator new( + size_t count + ); + +void __cdecl operator delete( + void* object + ); + +#endif // __cplusplus diff --git a/branches/WOF2-3/ulp/nd/user/NdProv.rc b/branches/WOF2-3/ulp/nd/user/NdProv.rc new file mode 100644 index 00000000..d40c4240 --- /dev/null +++ b/branches/WOF2-3/ulp/nd/user/NdProv.rc @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef _DEBUG_ +#define VER_FILEDESCRIPTION_STR "OpenFabrics NetworkDirect Infiniband Provider (Debug)" +#define VER_INTERNALNAME_STR "ibndprov.dll" +#define VER_ORIGINALFILENAME_STR "ibndprov.dll" +#else +#define VER_FILEDESCRIPTION_STR "OpenFabrics NetworkDirect Infiniband Provider" +#define VER_INTERNALNAME_STR "ibndprov.dll" +#define VER_ORIGINALFILENAME_STR "ibndprov.dll" +#endif + +#include + diff --git a/branches/WOF2-3/ulp/nd/user/README.txt b/branches/WOF2-3/ulp/nd/user/README.txt new file mode 100644 index 00000000..35420c10 --- /dev/null +++ b/branches/WOF2-3/ulp/nd/user/README.txt @@ -0,0 +1,18 @@ + +[04-23-09] stan + Network Direct InfiniBand provider sources building here, no more fake builds. + ND builds require + MS WIndows SDK v6.1 + Server 2008 HPC SDK (defines ND_INC env var in WDK build env) + If HPC SDK not present then all arch builds for ND are skipped, comment in .log file. + If HPC SKD present then build for ND provider for x86 & x64, no IA64 until ND over winverbs. + +[10-22-08] + Latest MS ND source (delivered to Qlogic 10-22-08 from Microsoft). + ND binaries (ndinstall.exe + ndibprov.dll) generated from WinOF svn.1684 tree by Alex Estrin. + MS ND provider source version in sync with MS ND SDK (2.0.1551.0). + + +[9-10-08] + Current ND binaries @ 2.0.0.3140 built from Mellanox internal tree. + diff --git a/branches/WOF2-3/ulp/nd/user/SOURCES b/branches/WOF2-3/ulp/nd/user/SOURCES new file mode 100644 index 00000000..7e2593b8 --- /dev/null +++ b/branches/WOF2-3/ulp/nd/user/SOURCES @@ -0,0 +1,64 @@ +TARGETNAME=ibndprov + +TARGETPATH=..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE=DYNLINK +DLLDEF = $(OBJ_PATH)\$O\NdProv.def +DLLENTRY=DllMain + +!if $(FREEBUILD) +ENABLE_EVENT_TRACING=1 +#!else +#ENABLE_EVENT_TRACING=1 +!endif + +USE_NTDLL=1 + +SOURCES= \ + NdProv.rc \ + NdAdapter.cpp \ + NdCq.cpp \ + NdEndpoint.cpp \ + NdListen.cpp \ + NdMr.cpp \ + NdMw.cpp \ + NdProv.cpp \ + NdConnector.cpp + + +INCLUDES=$(SDK_INC_PATH);..\..\..\inc;..\..\..\inc\user;..\..\..\core\al;\ + ..\..\..\core\al\user;$(ND_SDK_PATH)\include;\ + $(PLATFORM_SDK_PATH)\include + +USER_C_FLAGS=$(USER_C_FLAGS) -DEXPORT_AL_SYMBOLS -DCL_NO_TRACK_MEM -DWPP_OLDCC + +#/GL +#LINKER_FLAGS=$(LINKER_FLAGS) /LTCG + +TARGETLIBS= \ + $(SDK_LIB_PATH)\Kernel32.lib\ + $(SDK_LIB_PATH)\Advapi32.lib\ + $(SDK_LIB_PATH)\ws2_32.lib \ + $(SDK_LIB_PATH)\iphlpapi.lib \ + $(TARGETPATH)\*\ibat.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\complib.lib \ +!else + $(TARGETPATH)\*\complibd.lib\ +!endif + $(SDK_LIB_PATH)\uuid.lib + + +!IFDEF ENABLE_EVENT_TRACING + +C_DEFINES = $(C_DEFINES) -DEVENT_TRACING + +RUN_WPP = $(SOURCES) -ext: .c .h .C .H \ + -scan:nddebug.h \ + -func:ND_PRINT(LEVEL,FLAGS,(MSG,...)) \ + -func:ND_PRINT_EXIT(LEVEL,FLAGS,(MSG,...)) \ + -dll +!ENDIF + +BUILD_PRODUCES=NetworkDirect + +MSC_WARNING_LEVEL= /W4 diff --git a/branches/WOF2-3/ulp/nd/user/fre_svr-03_ia64/ia64/ibndprov.dll b/branches/WOF2-3/ulp/nd/user/fre_svr-03_ia64/ia64/ibndprov.dll new file mode 100644 index 0000000000000000000000000000000000000000..ad07788f64a8b900004aff3eb073c669b253f1aa GIT binary patch literal 37376 zcmeIb4R}=5wKu+#Ou_&IGhiYSf({xKCFmqG`TiPACJaKtBq0e1VF+YG5v3^Z}n}DK4r7ae#Kxyw_Qj3a^wv>5)Yo9sEOfsPU z-}`^w=f2MktU3Ga&$ZWDd+oK?-sha++jp@j#+VA=_cPXqEB%@I@8y4dNS=Ppucou- zC%-+fFJk%I^H$b3wCP)&Et{M*oAn!Onwwh${RW5L>1x(DH0ujjl5` zpz05J zaQ_E>Eo<0VPjxCiuvr*e9-(5N-siU}amQKYyr~gt#_pqz$g$7Zan%8K)4f>^M=}}+#xL>%t}`oin#3Ce_^8UJr~I+|LL@pbfxc>zSc2LM5TX2xy}y8WNv{{;#>x{a~p zfOf!}fad@^0rdCttzaGC9l(cxPXLh+;^~0dfF!^ph%3Q$E#NM|Lx4`i{R-E^fKLE1 zsBbplX25NLt1%|>5dQ>#{$g-Xe|fmx90)g|j+KDh0A@h&pE8C?L{|Z7X91=%wzyzr zp{2-DMtKolT4}+xtk_bB`=upIS5kc8imDR2mbB>0g&M)3FQ~6+-sI3PC|O~<5%J}& z4b2WgUtH5%v&pg9(M)5fti>fboJiZ+AZ)B>jEXcnn)HinYg#FxqGVYKRa-d2%uIkJ zKq5c~7}1&88GsLP9B>qH2tavn-TLJG$s4*`e!u&!KmO#RCbjO9&wf0sSXKP8PRw`Q zxA^co&u@&ayX%Q1Pam87>0KZE`H`i!+HEB^`;w)F_5$nTk|pRK3&brC6IWhwYl&s0 zedW?(%ZiGXV?~rQWtJuOf)&NK<(8EeR?&P%bIaCdC9S-8Vt(6-vX%Bxddj%SaRFKf zaN%(Zot3y{mer#*Dsfbw!k6H52-w5;YcA5H`-Xc%^kTAyB?x@o3Cw zorqgp$mJrqABYKRlV=#cFOUla-Sf66)7rH+uWi^+(*$;~(+kb)<|H$F!enMkaV-b@ z6mS&xui-j5&CGTIu3Thh@28vD?3>MOCBW6*YTx7#>R29GtmKALm<_L7R_%L%sl9jc@A*^V3IGbu( zTOGA!jy6}55H?>)i_lPqvAZTm?%&(Dn%QoIF9IISHM2+aaLt$H`kRb_w;qiA)&A)* zKiyNdRebijpa0=o1#;27X~i<$Knq1`2D&uV7R-DYMV1HLJJJm;^S zYpE|Q+_Ggu(jER=sv|4qHkaUfH{c^cc9oeK|IIQp<)*A9Zq4!PYj!>s`Q-`iq!*^t z6!aYX-m;&lj=cQz^ux!tz4+6@*BriEa!)Lp{qE;)&Jj)y-S$k?+tmf_$6xB1zw4F! zUo9^D(TVI$51;yT{qFy`Zg<<7R|`CPF4wiL#>`G2{EM|_wif?x1~jk@ ztcD3Ba_n@qobNlxHvqVKotdXMvs%{5oUDblqf9Mp!aw@^rg+W1_0{_Z5{;&-96$d! zcIN!MR&A8qb8dnBAbfqTnYjTrhnfAh-pu+M5Wd6Aikg7OW;5H=VrDh1X4VWa@5a~! zd{Z1EIOejMgJ4nMmU-nsQCWFmx$a+$?vp?NV(DwD-QFao>S>;<^8ePoU(@Y%sZzW{^^K}}n)t>d z_e2bpBa&vqpvcIfyvFEyni_*5qlRv5jH#!&GAL3t6x*n-r^!=^)IRK0McdbfqApp~ zb@T7_hem=xiJeKE=Z?-9PYkJ8ZS;0#`n3;vLyMpu?Th9J_i^on_+D#7O0lN%gw|k< zsNSm%A}tC@#Txf|6%(xp=?2-wPKL0idaoupTd`V-kV;kKYDVm0wN#4C!R$hvm6A(S z<+)S+B>p6qu1+eB_1qaxcXgt50dC`Qy{Wf2p~sqxJ3a1F>a;HwC-#2UTb$H+BHzBQ z_cwK-&D2}5zb*I^y#d7~v#HnDd&qr4+uJ_@eb6z@eLO#Ge7`RyTzvW^@~2-Sf5s*9 zXN1cynUk~!`hDv8e!rG!4@_vk*L=(PIGt3X)*j#m`j4yK9kI-FTap+dOqzya*eOOx z5!wS{M6X5Db1TZ~LaBrP$M*ZibDPUoY*_g!)<_lcJ=TccVqK3lvbQ+4#~KAb*wj)* z0$4z7h!Jg?I;nzKJyR-99AFXPuTHeaR`1n^w61~hsH+-dR!bvaJlT0?R3rpMXQx`$ zxl{w@sEAH$ROdMHw5WT{v#+&iZn9_sLnc_rdx4%s?L85tw$7d){^;xMeqYph`jLdF zCXP$g(`$~p)X=0v)g=-^>fT~K^{uA}Dy~i}QuP$Y;4)LPB#1?^k|j|rikB=4#G-^c z$ztd!nS_2LU5`7HSc1_Ri@R&Z5|FVtzWzh-(NmOY8;FS*D2nJBD2fC@OLYFY9Z)!p zX1^<`YXC!;Rr*>g8H1jK+A)L>TJ0XMThNl4MuqmJ{{G_=N%GVrAqJ!}4@KdZ^3_Qb z$Bx^ZF@cu7=EMnck~wicJUHX@9uNRS^kId}s_#5;W=gT9$Epv<#rcB3GEbpN*h1G$Y_1ptUQF>;A=4_%v07bA5pj)G$g>KQ-M$!C+MX#x8G9xTndE3) zAX>dgJv47m%+TCD(L+~_Pf`uV?1>tR+!Gnf<`geY-9iF>r@F3#e%H890p z8ha}+fp&JDyoSWZIH6i4$2H!Qlfvf!%0~C`YeFd`chT7In=~Q5*LoA5w68H(Z<^2? zD!VCMWhlfE1sc(WM);EbzUT?fp~h?7$HSpW2F)S=|PTt(U! zRcZmG($ZW4LnC;QqH(kauJuHOCLop!%kFbhzxIGINjlvBNkY$+QiZPjy>&u#zc02Y zQnJK$dj)mZ38wY?MIaPn*%a%H-d;x_70vV?kJTQSia9LQ*41<$#JChD^&ZCT&@%(m zFmUWXC`^$Kcb&wP#YDu#B7(OGBtsgpXwdOd+v`N^)PCISV1yw6(=E6uTB}TuXNsI4 z%rMfs4`NY3NO?a|aioBNDp5;B3a%5F_p13gIy1_ZVCwR83}*}sVpwnzTIRT;_5Kqo zqDycp6|@?Zb%bF;q6EtnBH}&{go2j??hXwD=g8m$#}7mdMY)e(B;zw|4e$EGjUVlc z6&gvcJ?K7pFQgJIhTt!YPrrkz z$JU)FMpj^0O9!Tsh7u?bOw$Q?pddG;+$SQ&8%Y6z)M4$^d#3k@_NBctU83h-1acHr zCzej^nNlN+vv++H`d24e)mS|J27(fGu+DulqHgNDy`S{H1LVS1HT!GyYND|$nG?br zZIU&?Sget$i-2fNm_QMfCDzQDfI7+&e>rpf{z?5O=WynPtwJA`yQD8Lz#vqM!&+U? zF)p%BLYFTTKdvPVr+(?({!euCu?xzk?v>u{I*9=5KcSoYE<^ye zk&N$!ir{KeM+$>97Qa&~>LZerN3ilDmCaRTuO+<3qLE|KKEoAeb~*;LRG*$g7bs3gq0cGADCDEinVATEM4=BUbOfPA zk$TiTq1s0%(|*eIEQR(^=t&AaN}>Nnp&kl7NFjkj_apRjB(^Gn@nRt(H!c6Z+pM^iHlb9n2^N?cnYtCF+hn;adM*Y$G%82>m&!;xEayyRoVP;E3q;j z6G744i^za4~aoa%3l^|$JLFe?0#Md#MDO7s@Z z+kj4`zg6##Gox}T22BU|m=6u8q`+|Ldj(F{5O+tV^qKErY`34YsNtKb^tB~3wptn( z=OUzBB@4%L6^G4Ldig$R1ASO_(eE#ps%1Be(O=~$zEBE|6sT>DYEMDDt$sJlX8!gB zvEzb2E&;uQgLKkhfg0^IcgF=41Q8?7J5((dsIv!!tBeQTBQvxQ^)Kx@amMe@@9Lic zX_fkiavLM0w|qH7v6xCfTtOC{WYtwk?{=Pys5G_c(?MuVk>aFn_{31$RHVErfj4yU^cSdge)zU0h6$?3f0 z${T}AmRD9uA6&lp6@lWvzTo$Jez_hU*1iz~m8N(5;y};E5uj%aEQ-d2)tPE%EV-yB zt^VT4q16UXXl0%AN@S=ktc|Md_N?<<8@U>ni@ zJNJlRD!w2tPH+VTrn%Bne6|!>Ri5IJ(s~WV%rj%VzR_T-&ydI4C=H}ypKBUMn%*@@)Jh$v zhN2o5+NGV;FxEC#NbRQXbArZGaj2{ml~>vPzm*2vJ|@hBKuzlV0gcVcvaCcBmk)+a z!KI}bNS7x6;D|7Tl?RlL@RD~@o zu02M3lIz=sG*r<$2)V0@oa=`c(HZ*DT30Ebg?SEy;35+_@3~;^>-DN?a)wtwi%$ z!lY|}kg6;vlI-K6O#ECELWQrv!r1{L*hh$kRHe+qRUs@~Ie~?QWmWz1U=|XOLOHmT z*XI?cN$qRFG2$R(Ff7Bc<|2=GJtl#BD?KnEzIWd5hcRKr?gY%#g>RNah*T+SgoV;) z3u(*f)hj70wu}~@>Glh{-q@HO?+KH8bmpZix(~XByARr3G1gb^f)z6WdhS~jJk>+6 zB~It5oXCSQHYg$?+Bb*^PiE*;K3ri0zvKHW6qr<$03`(_wg3VrMA`hmlZy0+k%R5( z?sIk_MxMOZ1!)qRiM|Cil{xzj%m(4+Y>Z7$5!oF{q(Mfy{jO;s*JMnK@A!U6)8gRx zt-#BVOHF{Oz32RXtRZ19aC>4X0ZtEhMj_O3TO1$vF!cu`=&%S^@j6<4dn_8`F;+wf&#pJ>%dm5HJ)R;tvCwsp$yEIfi_o&5L(sxOvVC#o(AH^FFmWov>u_RV3Nf<2B)9fl@ zCWDHOuWHm+)$gLg-IjovUe;Hz?qHP<>^3nYV7WE2Qh%G?r_I6AZBS4{YpA4=p{J#&a=(ps^{4adZ$|Zf)R-MA zZEx(?HotTM3V!<@WM0X*A9?M}{Vu-!Dh3h&hSARl6Lc&zZcXW4>M_pna7@cIK-=8#$GKis%r9aQyG3g!h1 zz{^=4iDu7IPw`W*IcSAPW`OHX^vmrygh|mWcg(V%dc})Z+UiXKQL8>M+9y{+rt2`K z#Nq>z#VbnOswzGtN@PaSthh>AmV~J))>H9RS=T;llPoCS;Jc&KA(p!|E5f?8uQR^A z#@7NB5o+ZCuX5=Fu>fvAo4-_rb;xY+z1ypO;2BU0Q&n$g|$?`MpxFd{cdZ5 z-)+_VjRyxA&258b6G6LoyINkJWb~!guo8 zv9a_BO-tjnViL5XjDX`@A_Idf##lu$2CsiX>3Ga}Go*oF$;Ae8WArMx z@!xSpzkG@$mtjp%p)aG~gfbgMEX0}cUOI-segl+lLXgJzMs zdmJu39~`0HP6;TD{!fX=Hd=t&$dLd&fSJ>*F0J2>m9f7yK^`_n??J_Zz>h;gE%ABp zbrP)XfpPu{-h$$%2%w)MP1#rC+K*dGs=f(qXYB6~&5{GXdpuR#{g;r7o~x;MVt$ z22$uq%gd>JT@@{L49lykl6X{3V_fPauOOP8N-gRZ*I8i}SWu_sWb*<)S}mLbhIBp4SMs7|gxnxDou~Rtx%B(aKSrE8R_`5igP_ZE zj-7x1x}#DAEMu(iY_T@qD<-I>qh0@?`POBl-2>q^U<|)Yhb9t^7x+x#{kwEX4dTHX z&ddtV%oP~B^|7%EFBNm-MVP=t#-K7|0ubq(gEHkog%t16d=y#-!#mVD;~vhbG@i?J z>9jk33Nq3eJAbjx?by#qxIJWl?l1LkjTa$;OVs{d8X$}LIZUk1K&8011Kn zV8PEJE8(*sDu#MZxb!Q2r^BDXO2_~$l*tux$2GLkpZ#m$I;qnOVvtYGQyC9w-w#kj z2o6g}vp?2$OGGIu!F7G{hmx%Bi;u%huM&&Taz~!QQ@p>lF{8BpRY;ZCaZ2p)iLPO> zoCKHXpD9*BqMbC}kr3qKZa zSSHL}hT$GAp3lEe+sMDEei^YDbyR$dyrItxN4VolXo zI_YyRIc0{(Mb~gAcmbNkx-Zf!f%Sy<^mUM}a^o@gMOBsd{=G=|baZBa0q25vyGpE% zZO^0Cl2_$fp^;WyaMz45arIeuhF^RC>&Pp`i>oh4t5nh&jd+z5A91_NkM(jt3TQH2 zvCg-R$Ie;eBgExgKP z*#UJAcEE}bup?oV9r2P`R|$5AmJem#aK2QJ@uf;S>We4T_bnV)Eu>q8MZ}PK#E>|d zA@i$z=h2<7qA~4C1dkl|@cMDG`WdhsmDOFi@pSCY{(_`54N?jbg`i5d3u5V6akWes zzVy&RD82PKYSU=lhr(A!^5ECo|+u?%Q#(dKgY`(&`UlN|YrpmPExs z-N2gt>r3A8D@P@-Y=Y#SK;l91jxeq?qgjRoeTWA}Og< zMeWT#puL}qOhtkxXGZo2bio%SZVylfOCk<`SXIV@bWt1q+Bb2!So>=+Ln_f3&yoMh zq7hqFvP@uYO5;@?s|Q5a{z1zTP>cmeIE`P|A<=bQbe$4iK6xN791!MOF|$ERMrSrY z-gNSKn+%smbl>Mdh#c&}2bjOI?~3`g4@ZfBChVsFLrm9=M|FZ~2<1-KFs*K3wRFU~ zfx>5^>w=}Uj!4V$Iy8Z1-1FCkJT55%=y}*>={W0;y zASO$#Dydx~Zc#~w?sFZg^B*C~5aA3`x*f63eUj?}d|O8EIZI-MXxT4Tyb2$JSbSKt z93jp8TdP)i~orgkD`nH(8cAxUnB7=M#P%& zQsH+c!bRskuVB;^=P0vM1;a;j-brh6Eb%V$AW2NPAgIua1z1{ z5xdVI_vNPm#j%!l9P6?J{!EJwqCjGO`ie-#GA*&nuv78dc-)?))GyIyrX>Nla6frZ z{~5P^bh0YbqDS0$ihGY|NyP04-R{F})f;O1^>m*FVu}r194mSfNY1dU@1dDbDo!wZ zMNc9R#*5vt2#DP|{I`%IdB1QBMf5Ddt*0cuRP0Wogo1dFhpNWCiSCQk9uJi+_3t4M zh=12^pa^eI_X{MfWaV;KiAO`3WrvAJM_~_9PFf0tc)iOIpbCx0$~~T8YM?66P-A^* zeJkut@rC6`7az0n-<9|cF}Bs2uTe2!%3wFO#W%tTIgTuK!2bfpD`-AJ=*cC4>S4zcarHT>hwOUk6?%~Q<@t%Yr zaY*J%#D#p@czz{}TK|hHiApaLQL3D^!Irn>Q58*P_$Q8)pXGAAA1*#M)``?cddh9+SO#R*{MlY$0Gf`m9(n!coSm zD1ldVCC67+R$AVu?5b;k8Z80f8SJuO+cD zQhKMSNZ+$=p3g{%fOftnWAzpboQH4%DG6)E=sWxx*cXjDcM6^=I(rkGxjB z#G3QSJSu^MVIj(^3t)9tNl%&=oMLwllPo_**)vj?4#(ja+c-QGkxr{+uIIA}8SaJGc94gGG+1r)AA zoD>ODA#IzWvXAxDAx&4_Lm0wgDx?z{o+6z)gAK;0;xJgQhH|4rTHH_02VY^x;0tj_ zgeoAKNyZcqIVR(ASV??=6a%MTKv9o#B6H#?PUP7~!C!bXl-(3OyoTAvH9h+b`Ur=B z_w*td2VEUH8i(5Z=itUBc9S0RbhqM{TnXKD1b_!fPuXyEtlmrxs>kSdbgIPEyyG_* z6z5Mn z+DOOn5_0xBdJauSINdT6Ef%Dq^KJ^)wol{l|4v_kLgO-cF5G zbdq|s?BKrU9_<@D*CPieiSz? z|A)|A#L>hVt(|=T2S>f-eA)wL0o11jP=D*U@|^alXn8;(qbfi~xV6zD?*^x&6_gyX zJfs`2Jd8;yuxmiHybt+gTB=;z+^=yu;=rC)4yy17v333~sDbDyG&CB6hLeF0rTt=-mqdybXS`dvw zrzJjQ6fgOI9zj`ny%+1Sg{~9kR+f2O>dG=~aM^I`zdmI6t}}Ya^gn6N%QvA|>^pc9 zI`=%RhG}0Xa3Hl*Qdb7;?Myh4dilx~WA6s4oSyff<2yv?9@t~WI%ylcW;*vkEY9%R z1|w)gLb8oWgNYI6j@Ivj6qe5Mo z$-jdU!$3n?s>Vi8j1++_7j+OaAOZw(%zA)Zp$I}f(S`dpq%rCLL>fnkBO#M4C*&Yr z))kJ3z?+_f*NN%@b9}^r`6@gdY@N*?%NVuEAZn$hP<+Ps%0)O#)Hq(xxh-83W>|&j z#;R3ATaCwz-X4o~=z1b`oDRE%($TVVu>yxj7;bR%3#sM)xL8W5xS)NhWcIoK2%KxZ zM+dtf-Wc&JZ06vx0+;jbr!epsk2S0kGbg{QsE82BpRcz0StHdQ( z{gELZ;!&dQ0=}JI^+v{SGaI^5n&fs|V4e~+pBCvrX=8+~vVQ4mGjk8Z2|MDC(-2N+ znCsuC)%a+)M=RnJ$a&$Wp{rpSOC=iV@YHt&T`6pB6-v76Af|PAbct&CNaRPu?SW%p z^*O*{Fe2khP=KHA3X+(wrpP+Cac-6$ppC3w&XFsmo{adh|ERcYY3VCg!_!6XLmbM40>=9(;EtI~2f-@+ z@1y_xAlOLuMR*srJ9?1;CpvJ(&vn6LIaSrDv(>Bh*Mj$f6OT~(t0_sH6kN_ZGg{s97gymkN_Tt^PaC#k&VI?g5CPPGZ?- z+OwcJ2n&A1j1F9J%Z!VJhRJK&&j&5E-|4NA@eSl0I)=?{TUoj9;aQ9~h3Ea=6O&!_#7Q+iGq|f-t4WraCGFbS9 znus$Lhr~!GZ6S}MWTa>vq9tP#LPetSR(Jo5>?+mvpSm3|Cpi_3=T2{c)*7=B-NS`r zRv3mFcT~sHDSXj#e2mZItT4`H#R_}q9ojk9>Ds37f z2n-T!_k#!`V}kZRdNgIg;*0ULsXZO1xqUK4D!^M(d>9~K;^==sWN;K8IfF$;I)mL8 z^LIK%Ir8Q%=EjCQ)Vo*KJ-2K z2dtT*InMTVSSQkfo!4V&)(?1$1A}S(|M$UEIO|f=JRb50-fDvZj^m4QBbt%>=4;(jg0rmA7@1kbY|)NQMr-6J8m=*5ROjxnhB~-l;4?R@nn}U^Vy@0}l(WD$7oq?gp^_9pW^$y$H>&n+pUF3I=Qc+8eh8x$Z{K0QhY_F*&{k^S8e|wVM99=4WAhetO))ml z!e|(`R!5e>7!podPK)@FEBRR>oE``gAF9iM@=9G#O|0v3#vLE*$}yXtz~~vBNEGq5 zuX8PIRQpm;FD?Bi;}mN(dPjSI^oUO1bexJFnyx$?72OwUW}QLZ#I9*IkR{_ zxeY=L5t)#eEAwI4GW;aVq&{7Qs&l9az18teWMyVVZp^s{GMW3JO$<^TvWozxzTqM`Oj_fsTm(gU;1A|4okUQF zdfkHk1*0N&*~jgcU*2}1aZm+LDdS)_#@Dzpb-8iiMR!I`n;*fq#n(}>|CQ?~-h?u* z=I|!|>()`ca%CKUJizhCnh%@l{>;AJm}iCUnSJDz5roV>^1TX8nSDugtoY1UBgGwbdb$bpsSSH7F0=hs{?y0 z1$yx{8j$kVi}->8;jo&U9-`z#QKrc^{{xoH-La#V%%37*O%=rF%I>50aOb`|F{5V* zZAFo@?eu=iutbwtpusabc<|SI`Z>hZNy`%Ix(^Om9$~Jj{NeICammafylZO3%sOew zOnSgQ;KQafXD^t5U^KaIY;|Js4}8_r@jSu7?0$J?sbgvG6f~vnUPWyc=}PI5$cJ-K zq)ftFAR+>X-YW-V_@eh-H9z+L+pn1b_Kjip4LQ9$1`NNoqiPDAezA?M!Ix` zy3YMF^(9i<{SqQj8@F3upsKYmRbE{uR_sFU=23T4SHK-b5zml+>K?t=(HC+=Ih!9* zPUT0GZ|Oa${dMnvtxoEaJylh3Rq;BwtBUh;df=$?E(~yg8&0yn>VF{#L7VTN*mICL zF0`yFQo{oGZ^2#(i8&l+I6NH#PU1#BJ<^vA_Y;3Un~qsy^B#{i6n9EE(Nw%cTA>q* zd!!WzKhRsE>nVN+Uaqyh)_Fa}-|e;Pdy2m!yY>QZwnf|2lllOS(6 z$x^5dIM}uWYw0zTT5!5Dwyd7U-at`&1X}bwOj{qLk2@TKXQOIx66bu8%=zDy;eiLP zPH{kUHoA*5_I!)71JAYLfGz1+zIx=5fujO+VBPrkI^P?UL7qQVOMhGws?I+nt{{^br|H4ZA$URXE+L!U@f&T?U4-)9-`^lb%dA6s3`=~G;{t99Az+Wo6 z!9oRbkfe`q-I^zj_qlcrQxju+;Rl$(5xFDbo{HzPqU?zN?G4~ut?T+nF#X+};IXtV z+6|r(`Fb8BAF(i_+|%tqpvvYu0#p=w$<55?tiFbe=T-g}s93p7CuMKcj%TrOYTi~) zI?==VQd)l$RPk`G;V3e92^F}i&@4gB&dKNl$vC$7yk$#>!ut+joQKatJcF)5d3 zPnTZeVomN%yk_Mr-d)7$6uAGA-enXJj2nQV`E;c%Zt47jPXBS;ipH{op)m{ zg6l_z=c=%sz8Pi-e|3sfKq3*Cq)0=MRA4)4R4V>d>1j*g_EMGdLIf^84H$o;FGSGD zFGMJ(xX>3O+zM$T<0lB)MO=h#;36~+cH-4sjF#!g#Ar_73`#AK4;3SBAcxFarKQRf zH_E9NlEm?Dkbsfl8~#<$KnV2u-vhl49t(e>*@!Vc18(^Yrz+4|?7QIMT=F z>GH<80p#!h46^XG=I9T@&(SqxuHp#5_HjlFmiO?#2hZH36fb>9U4^F~Lwy4L90RRP zgU>PG&7F9msdXmKs`rGPRj+K!@U0n^7y9&YE=J#kEuSmMZ90021N$&|4tLx(3?KG* z{)ToTb4&hge#Lbg9M>ao^{s^~4o41+E^G^|LfCl5AGbYlwehRRat8U9Q$EXCqvee8 zj5L7vE0O@LRu?MJg$UlEK zZaGyDel#fjNKjaHd2po=wE5>kc(M_;^#r zwli3mnBD#H*-_48LwNay<_>SXM~K%vS@)#z93IIE!JzxxJ(@0@oyXyacNm;+^f=MD zaTD@9F(#urcSa;Ublk?U91x2kseKXf(+y>z@0a$+^DUhHILQ+ypy%0x_e{Z?of*TD zlUgOG`Z{03KmC3(aHJAdximKc`S4KCALxKAT=&IK@ZUqF+;xxFt{lP)h0TG(D*yY? z&S5K-&iGyXW!Jtmux99cv~(QC((!4@@{H7RfS$gy?4c*zmZ-9eRLUkq5}m-S^4$pa z4;$oakL7@kV(`4}pydFp7v|rp@-4>|%|3{2E555>_Pe~;TWZAHhhq8G(tbiq+kH0# zEYRlx?YC)~JY9z$E?EBgyA=6>j6HyG(pFR(_-jY_5xCCwv@0=;)o;VMiV*iuP}~UO z@bWGeA5?bcU5xEOoIWVdins?57w+%B(>G}A{08> z8#X$YwiL893(l6NqJ}01vr>*Whrn2~fKPky&wC_AE~PJi;9E&|IBJ(RZ*&GeI`dFO zxG!_`vT^mYa#rAU;5#2PjtXa*qzRpHZA6YFQqQ5DTVALOh>M;xs}LrXInAf(xCQRNQd zlF7>~WhIv7#uUzUwk>j{6W@3#1`%sEf$nptEgofQCKQXBYBsg8gmJOU9qo=LHg`03 zdCR6v4rhS9;9Z$xQv*8g?ssVohxaLD20;&Ly;ywr0IN-1d@bqN< ze~SAmT%WpzvA@j5R0bS>h<2+Hb^%@k{086wJPDYG^n6_32Axg-c=W+c#@XkcJ=KxyVXCmJ&giiuukoSkU{|@3C zaD5*z3-S55pO5l~aQz(ROA%Lta5Jv6kY_3As{`Bu_&(DA4Rop|0NyS@A>wL~MhD)$ z2OxgbqP``7Z2;oUN0c8tySo!+Ip8tCQ-D_izX5y-P<4UMfSUlf0&WM~33w3jGr&H; zalm^xL08M~iz*7J(;27WxK z05kx)0RIYj9&i9~65t2ud!cs#4S;V0UIcsq_zW;h0RUNKmfP_-v_)7I01;>g+2pv0i@9)Srk*@>G>EoiK*FSHib=P8W@w)nHHwd z3^tQp!D3k)yAo$&;@MSfHk*TQJkDiTvul{1&12WH>sTV2&#q@TumwmDO%Qf>@J~Ok$_=sWwD`XZ{#Fj8CTgq-@%h+;O z%u3h_W@DwS3|7KQR)N{MimhU++3jo%zS309)-gL<&uZ|srj4wYIanRr#Om>Nrbc!L zzQ(kfHRJ0{t!xXv($t2pIl1tqrmgsf^|mZJ6Jb97kNMH zVIu3rT>Aj?uy28&yV!&5JM6pcA@(r)7q)amNi8PWc0NlKHZ>L0G*>h?!GtJj*~)N_ z*`=VVrmbzohDLm%jN!E!_(-2qaJ4df!v_0CO0qY!*`1qPTg@gOSG$>iHm$9xMX)!u z*y|h2$!SUgOf7qGLJCjVgxDHEaN1ky>X0K)&uDC0!(EP`xXm@S_6@GOpqOTS!PG8n zYjxOR`31$dHn-X_K{un#(D)W7MZvVN*Ew4@Uph6k*cLL5?7T62uFae=io2Z9S|ilk z!zQ4)hUU7Ku!*qR@PW4pm9@2R49?zA%W1j^7KGBjKvWz5I-8NYCGbjx_*^G)C zHo{a0iY5lsI_heu&Ex>}o%OtOd~+_q&$_0TtqRjNA(aY^PnFA3x12J+YaQ+OQS5@^ zTb(VnoH+q3f|9nhHcyNML0ats%tL#7P1D3=!CBL4Z+2~-m;y%EPQXC!FUL&gSD<-{ zAH!@y5@9wWG8D53$)lJ}NKr5gB(!X#rt4q@%LB!=p>10m2pod`xJ;K$rJg_tf~%O= zj?6*10VUOiFB?KAYa41dK_r5i*Ahr-;nuVrLnJ_L8hQ=Q4T8PdvDIvpMPM|J$kWo? z=1}B{CqOeO(Xw`cNxK1pMuWR;V@sI=5ORFNH!DVSsE6B=) zsOya_4b6cX<=zL1aN2P!!be}SOfV7wGK{sxHA_HzHg8hKX>eyLazfiQS`{5)-z>P4 zZj6sdNo8E{5k6W5qry%%VGFk20d3q+H%gq4T9w30R_zQTYe-2-xMZm|1y8OsxwH}A zv6QW8vbT~F9vjG^SxDSloMWRIU#-U4olDI|T9O937!(~M!9nqx9L)}A!^VjP#zwy^ zm_cO(tm2v!N(IM<>Ym^fOg8m)+Kfcg{S!<7k==F$A)1bH-`*hM|yy>r%#&WmFiMmv0mV;h&y4K+}L zvQV{B9H!zrR}){&L-i>sB>sFz(CQvvGqwj~HJV7Y-q_SYHjL8&ufc@Ul%c+53m@Aw zYlh9x)X;o~y%rx6rnx_$)B*^Gw8ZnZwK^QN_L_}CL;GcFlXE$^Z$z<4_>dkO=G3U1 zt<9wvhvTwrRtDy{cv(Z#Z?ij`PP#)eRH(j#N zNJ486z+lxmMsTi>f<-Ja)JL0^hd_{sh0735#4edHRCvB38wpR?ED)Y>@gx@E;zL*; zE<=Fz;gY~nJDiO6@gfi~p+ku|UIxNeNYo8B6hf@`APdASMNYz% zA14fQ7FxY=)irA32I}Prq`%<(geFziDLk558p|(N)K+6BvyYTgYt1%VM%r6PmtJj6 zXj~vKC1nWkC@7NZ4-m8so?qCeydGymi?c!47QiSdC3pz6ZI(L_rqw_S<#s6po3f7@ zvZes;6xU`~bPdlk!F+AwADj;;?j}c#Q)Xf)H-a-!7i6A=Ff2F=8g-Bldn42?iGd-| zRZy$Oxxwye;u{d0810H;7?(!8KpJ%f3x^ssiPbl5|L5<&Aq94u;lJX3`OXq-&i~@7 zHwyn7_Tqm~{x6|G1Z~~IM+vuH$RC|`fd4d1JWeja=Llcv9_-^pg%sj9<|q@cmGD5? z@oV9}$ffX0mf(IVev1&Mzt>cMy~w2y()dse#l$dM(Uw{H2&n-o{3AIH{`(;!B2cpc z4`lOz@VXAMmM8M%e=7*$f|N4f1aTHZ{0& z@Ft3JrEk(xN(;Q6^w$b6ZNz9Bg~-tc&ndOt3LF}cubJmtfqMtSMclVa=^K$#kNO?R zw-x!E@UZIPvu!}gfm8u^HiTQ?V{PERSZubz$2&c!y-MUHPwZGbDew>*I2drHP%?bP z8R#Q}kC;Ofn6j7-a^r4=R zhZq~!Vd8#@KBRCwG7uV1KRrCq)YE#j+JZV;P*Ve9h%U=fV=d~umE*i3&<=5wT32{V zcQSV_hr1P?_J{y2YvHpd+6MFWQoN}GHbjpW@CO^)z(qTup79(=3(!A}_d1!=KZA!! z!mt+uh=A1BphrqC#v~K_8IWlPx;T-e8Lg7E1m;XEP$OFOqCaUYWcq zd2RCgeP}vvI%V>ihD~Qo zs#JBVCRLXjn;M_`KJzC?r9P9oC-wQ%zSLJ!y{Y?C52PMSJ)C+Z z^=RscsmD`KrTS8bQ_rNHO&v+SfQ=MYnmSFBrb~-Wi%&~P)2Ah-Wu)b#nbQi>tZD1h zYSZe|n$lX+cBMU(_DI^JX}i;&NP8;nnY2A=&!_dJy_$A7?MT|uv=7scr=3dkr46T@ zNjsZ1l6C>xGpclTx+Yzh9-AJYo{+9jPfTBso|JA#H>GE!=cJp{qcav{~_)U5oh+N|cRJG1V~dLZkyto>PUWxbd6LDq$= zsO%}(GqU5e&u7Qx2Ckviz$2=KQw&FKCmCbpq!K;9G5| zF*pnjhRud82A5%*p~KK+c*O9SVUOXUVR7<1$?qrsIoXu5E#(g>lZ=lVUpC&7YD!&_ z`qT8Er}w8nnenrX*D~U>Q?k>uZ_9o=`{y}}bBl7Dav#rqD)-skKjxmzHRUbK`(<8# z-ay_5d4J3MPX6BfPxAko4|T#$q5Vk1DMM%S^pq=7ZcO=Wiq>c{E;p7M>x>^5rVPn@Kc%%k*PYbLtOM zA5VQT)s|kFzB4^GV|GSP#&PuU?-^N{Ycls|p3eLGo86KvWZ$3t+w5c6 zUuKu(+?8{0&UbRQk;qQL~Ba4{W literal 0 HcmV?d00001 diff --git a/branches/WOF2-3/ulp/nd/user/fre_svr-03_ia64/ia64/ndinstall.exe b/branches/WOF2-3/ulp/nd/user/fre_svr-03_ia64/ia64/ndinstall.exe new file mode 100644 index 0000000000000000000000000000000000000000..e79150e5a33d1505e06df343ca3252882dbc9836 GIT binary patch literal 11264 zcmeHN3v^Re);?)d2oT!HG-DCepe=$tOnYgYHmOZ%14Ua%n?9kXgyyzMNt2M=l;XhH znwBARsi1?8nekPtfc}iH(ScEfN}*7vDBuG|e1L)zEIRdn zTC+S^`|N%8*=L`9_IciOlD}{Ri6n$b0fIotc3>LxV*Jxl0NK$uz8Xzl9(7>Sc1hlW zNkvwhN9A%mYu)C0RkhjSaB`}ptjg_msB8{Z&H|IF-f3ZHjvYHXKBRihX7Bmk-4nKi z;S{OavIpr?#Ji9YTMa1luE)my;aJ7gFZPiw)Gu#5B zfsj0jlsvdb$PM$3lL*NeiHwlzz!?|hZk-6M0I0>ZM5H4K8G$5)D1rnHO8{`%z9Itu z>6^ub3OrhXmJd=v0&zl1b7V40&oDz0J(sffa?H5Q!s`BhXHQ_UIx&BG1#;L^j&}&fCp*HAB0{R(s6*v zfE+*>;7RaL0^SF_3D^yI8L$;_KVU7O3D5wr1HwUb9ljEN?@37Bmf}l^%|*ugLbg-K>Ml zb~-q>({5t93KQ#YuvN33ic*`y%_(4i9Ix+f|&ERe6HC=!)H7v#{>bqLdqPAzSZkU`3&jrXQ2lIZ*rU zmlyH4*lJsijkWwp4R(m<**x4;*`Cp~?Ou<$mQ7bBcvOpK*lwHQ269zajwT7}M72dV zLzQ3}O-fDK28Xxa=yr0>YNy?!a;LuxnR{ip6@(PBwHOg4 zX1kX)G=?fwt*~*{P{pt;hYeNoW41v@4r|Bo5!GC+B-AvMF!Vt*|0P3p|O-*Z>nwzj!MXqUDb5B!j zRFuJBXl-qc!dj$mGB!048JTj6##q`!Mv_#u+Gt#hVyY=kYmtSGY{?R<)hd&XY;?I+ zxLh(BmKXd+0*fIxg#Rx{p(c_ilte<;jY3n7DdUqFmc-K$cdS2FGW0~ib0QM_>hy{g zPWLiIHAyqn6&#K}%PN-I92H(npbF>Gx*9iIwZg%2RgIdI3LAsSVF~roOqXTpm3CRL z$9gyE3N9}c^Jhu~uZ&OLqaYIN#&KBa-nRy>p~$yKzPNI?l=RXdO8U;oOWF)W#x}zs z^R2O@#P1ypT!<#bHz;^-XkI-u7wadd6ud)L*)O0$Np+T&pQe5_l?vWLJ|iBSI+<|9 zC@57R`J>v8z0uaQwA!F_Uqz?_qp2kDWJvcos&e}!q4K_I+U|y1+C1@o!`ZeuMx&5o z-Fh(_b~kr(@U4)4)_a2a)>IEI>o*LUN|t-bf;d$z-xV3~yK=*CZ%q(9zoIEw58paki1vMVhQfsjpt4MFgcZm>nHX&jj0J6?xkjsk zdXO3w_)sp6mc@&_)0#tE;`46FJgtGt}gA7Ty!if{xR-hBlH zbgYQ|R7Zw)lLEd(H_gVt#>f$r@?d(5nE2sNA+eWr3N1x@1S8!Tw0vgJa<2m8*!tlx z+j=gWBF$$uV)?l=q)PeK^0rp{1-Qc+LC2)BQ8b2&3k?fv1!@ir{?jj@_nKa((h)JO z_lt@8V4@WX-)dRJYPpaaFboO8Y0BXjNclHP+FX*~D)cRfz2~NN`vxNxbEAJN(aqqb zy4$>mV|HfI!L}Wh`UY*~T%vE#&L#K;-P|ZB8agiseK%9R-jU)+?u!&w$O4a{&OUiS zhHCnv0*8PEr4<^O&OT+3vZ^jw?b|Pi{ZkeAGa5L&gGzX>3}s@_7YaVQwTFuk4*9yJ zTCd!FW^rY3BDNPX7#ul>gk&S)4oX^Q(MUrhH6lUzGPQqCY=<7HU^z^|DG3-++eZ+> z9P?KWS=!^MM_f{W<;h*^Qi#M4S*; z$$2m@tZjnzU0SG@7CMhjr@VY$6x9VEk+jN_UKy4|hBLg3ALY+KZY&5iV#<`4 zckyh1HyjtGnPVaOk&u5ute#r!9U&+mMk>^(cB(kg4qJlWu4&GI*^>N)oD?0J->yTV zt%)# zz#IG$Wn(KK=a&h}7BN*OrrMimf^@V{ z@7)0%zKkhqoB_OY>${UsTKNd_%L8%9VLF4Y2^>J;^sDfpxEE;0(jCAX@lDt1+tK|Z z?_z{e#23XY_?-AyJ}*A5xX@ToV8v!Cu?Wd%L1?P)@#n;V%{1jxa5LMA-G}#w}XRm zQYp%y8UBdv^l;Ht3^g)-s<3>buslv!J|&UvG7JIy`ut4DAV*@W^u24&M z%Pu=m#PJ51iLZ<;;XN`&UCNK}4PNLr2xOn(ENxxeuN2%Ee!evFZAPvUisk%#IbR~9 zsdSn$D8AK8Yhqf*LAEVF;J+j z&VvfSp`Ryy!yp&S9|_3O^wv&PDp{qwJDWEQ!UX=P_pPSY0^wAmML%i7S+tcuRoMlT zX+?bpU{lhKqPZ zY+9L|yM`~86_)bv@cRSXf?Pg-5ToUPx27LMfj@G3K1#g`5YkNYn3hrye7>xpl>b|x z7TnX5!MJn|LLcxXWb!m$qaxCq!0Tf(R8hYh&nYt|Q52nV6GbC4i2nEDVzB|Uis`&~ zKD2Jb_pzWfirnBV6B4!}6`n}q0TMRUG^Yhu5sauTUE~{~_2ZvRPfc@U+!#sBMl1=T zy&+td;$V3gnyZW4AG0kh)>IO+ZTSf1aO=0FZ8@^IhU>A@^0{*DIrk{czR168&%5Qm z-8gYg(Z28g9A_0eB1MgLGHWi~I##2%eC!Z;6jJ;Vo{j}2C{v2 zFrDCrS`nBHb(bBU>QH|k>W9nYje#}D26bJ`Hho1+Mg;Lj)kTz5cGYA=f`mQ{AcHK_ zg3#xQLUfvs9TfYubl3dP^{;97af)Z?oisOU;9y5ATHj~FSIi)`8V%~=y+e$5P*CbX zGyQ^6AHq2zhMOUmOXUn_8ACtQuO0A4?OXu8{$%ROf%pB%ROjNV;Rm1QGgGk4b}X5N z?P_cVjg@6IzP^aY$wnGy&lOQrj))TUBATHCdSrc+3y3$64vUDT z9ai8rgRFz2>DJ@u(tT0%^H+k7Y^RwWcBJ-2(a+*hQqs9E$|B~5HZ6Prph!El9$x_< zsr%^!wzkC5xjdbcw49(+gM=Su0fm~`TY>=_JEqe+1v?4d9p%j7fv@?abfW?8=eq_h z;P2ICOMOkN51rH+(;&Vj+P^Fz|WgA$PPEaw}x+ z7%gNQM$Mmwj0r{YvCJ`0GEnk?4+f6sh>85#G8@1+S^q=;tvZ0w&7+ zcgpy#_Xrk-cc|`I&cCyO#>%F&4P)M!3Lg) zd}qVyOiei0{3uaMvxM%#zcMIoB5$#k+F3}Kq~<9_i`0Og1Cj}FWKT16yLSSp6+ zzdJ1d#+!)bWcGXc( zI0L@J&GHsdNb~Q-LULmq{?im^Ln_d8jGy~hgZnBs;a7;_4I{~UPg%Nnqca1P(zj3 z<*MRVx{zP*X{dH{LI0$ZOj;}KdN=LMe5b{0XLH5NSd68PhypL`UTI|A zxL>ZP7wfpUrM8eysC1F7dYQ-|WDZS-Ztsh%^uBkV1-HDzxS@dq_M4O&yznow)w5Y1 zSin+>ERHM+J2oVaC$p<{5J%*XHsc3ZgJH~P4-_7px^vF@?o-#hyj>c)^}aZMS58<0 z%as_!MGQ=OxD4ls7+h*cEe;jz2ptOgBCF@Grx(YRAs;L0Y=2XTrU+DBb>L?^_dgzcXL2>VNDN z*R(Bv+WV+Yf3WiVgj3huyI_2uPrv-ZBM)RpN3~6T{xSWzT~FkE**tE2^F4pn@6x@u z>1|=&jg7nC(L1}3uRGn;GxycsZOPivx~%w?w6+1)@l~^Te01-}=N>)Z_v>d1vfDpz z_^kK8r{31mJUM5I;@W2ipHqCcch7e@eVgC?W}xrH9d|wOwt?;4cVG0T=bjkJ|{Ci^Xb!RPv7#z-CJ(WT)nmZY~wZQb;TgwvGmrI}O z{CM~3^MURg9{b1Ig{AlDb{Ty)#m&EyUHZLm{qrL>uD<5vjE^6G>+pW*N1Kk~MdLp` z1pn@UIoou3OX<;6{9C|Pd>k}MF7lS>fidr|47riBz$(FuY87GwUQ|t3;}>A{uL7P= z=76T*b?HAZ&@UN++xv|pC}#vQ&RKqKCMddoNbw7=K{S_!O}MR+Kp%%UQybn|YoX1C z_g5C09i#@Yt%Teo%BaaK++(K!X5l?n4So_Cg|gX@smDvL8S*P(jTtFyZV36n^eva> zI7y?(Ya~-pCR|4jBs_S*rFFYtgAH;HQSPT-d#PP+tcO7xsogf%MC-ADOVjj~*(}x` zd=1u-=wbDipk6m*F4dQWmuIyIYG6twk`$srTk&=;mZf#kmuojL)qJU?wARb(oC&!` z06}~!>dgaPE0&_(a=}lu#kKhG#F0ew;N`q$(269{4h^U){iwogI(_%H!V)JeaYB;~ z91mpkpwR-IIik%ALiJGVsLf%&(^RmRe#-V-`Z7R*FY6ZKMUC9BR$qFbp95`6#hR)` z8%jlQSYX!*r0E}2Vy@D2We=o;{GTGWI#Kk$Mx^OTqwS&Nv;;M|FSdgANN|MWe-;?q zcqK+I9R(h=)eLJd_3tR@3sm6W6BIbpO7LBy{!o2f-7;(Ktm(<>Qi%5=cksWR;I2? zJ(oIBGf8v1CP!1CDb+M<)@dHmJfnG0vrV&0)2%tIIi~qi^Nl7tZE6~mmX?;8_E_5P zwBu=Cr2RAPUukLSx2NZ%&r6@5Zb~mpUz}c(?n%El{h{=i(s!i4o&NXqkJCR(kJ66T z{z4n4P0*%jb=qugskTyEt+i9Gk34)+Otc eE0UKauS#wbZ>XseKZl<^@UsVg_Q1c-1OEewW+agS literal 0 HcmV?d00001 diff --git a/branches/WOF2-3/ulp/nd/user/fre_svr-08_ia64/ia64/ibndprov.dll b/branches/WOF2-3/ulp/nd/user/fre_svr-08_ia64/ia64/ibndprov.dll new file mode 100644 index 0000000000000000000000000000000000000000..e48bdd26d7cf69e2593dfb7b5f425f49791901d4 GIT binary patch literal 37376 zcmeIb4R}=5)i1u2Op*ZxW`slnL>V+F3ff6#^8GcKOc;cONkS5ok0Fo=NeoFy&IGVT z6NhL{j?-eRt*=-6(pp<>ZOhw=#wt1iN5X{=*znXKXs)T7Us?8=wO4A%y)NTptBI4R{4`0`MVVGU~e)kOn9NoJQWa00#lT z1UwGd30RN3*9F>{9Jsb2eifh$Pz;Flr;KqD;TnK26EKCb#YHQNEhUx;DueLSY74Fv zrIupcFD+ZTlH!Y3)RfV+tW{qr)CvxLQA2IZCWn4O*$UfDh_7^RXmJSo(%P2VO^(fu z78+X>txmzwj#s5fUVkY1*9WJ?J+r4`tN4pw{`{Tq z70LDYl$+TJ8)$@k0v{m5VrGw(pxq^C&uV7-Z#T1#0AH0p?$58g#?nwxyk*OVMR)nX zwsuCf+~z7=9|U{^SYBgh#vfUxr`?>h#HBgCcJBR8M1OWh8^3pQZBgH;?=JhX>copb zop$Wh_UE4|-skXsE&t3dvyXrB+8p6M-|f%Vys@^Z^YjaS^LM>e`0K^R|9&QS(<5j9 z+OYdK*YECF{c@38Z~RI8xpM8*zgw&Mv;D72etGQXmOr_(-}$Qj_^SE8ze?`sUvd4a zWheb&Px8mFHvjH1$39ED?Vf-A>`u9^)>V_|L(?(a(k{V zkROCI>&)z7K&`{f{;R>vjx-{CmzmWxo7vr)&1_q%nYFi>*}VYsZZq2j_^LQ?#PQ>i z10_*`2<5(_vbgeHL;0U9*Ay-3Pn_|OCmzmQ7lS+-bJoy!#7}+NErvA$%;vk+Y-ns* zuW8-TRNwBfZ*6X{Z_CP9(`clh4J~yrw>xibtJ@H0MDkZj!~GU@UW{;cUYsyJ zPbW;vn=VXVWXPM_sWN(eF-DJh?S2(IN`E|ecb7V*U3JK!X4>a1YDv|*29r@(7F8!@ zi4A0F3(Hb1r9X>_tVZfmH)$GZo~!Zy-gQvZ>v5{mJidk|RRc|YsN+dxxeP-KknrlzfoQcGcO4UYBceY>quqU(#>d`)Lj&hyWhQ;?=qtZ$>-Dk80Yt-8P>LAjhkW{L1 ztyeM8ijZ!IUFv2CYu4`91ZOK%OHop}YC_G3U96VMkvW)MsIyvfYHHlu)KB40a_Z`( z(ggRmB)Y2?tqX9QgzL@yrOAEPRNU!tmsYQRzBHx(-zt*UbLC|s}^|P zi<|sff0d!nn$cfsLRugqtIwL*Uz(>x^jWj|OU-@OY~vBpx~R`;5Y?hpg^F`TYu?)Z zdBME_#U-<;-`juGbw=Ai7=}LRnBh8I7%_g(8y6`)^D_A}FOxs(GWoM2<(JHhw1)@1 z>iK@ZmT3=%wcl_4+Qc}WRHfD)<^={%t6g0Q%zgVJF-nM^igDO2MoCfH!(vpwMbmd1 z%IZR?gZ?KBdM9$5%U41~`6|^&RY`r;sQyx2pEbI_G@;KL13uW)QdKfoKx~K;ZJK(i zida2eDor`WqQGCBXiZqVUmw!C2EwDRX^Oi;8u|38?rkyA5D=Z6YFX!09Wuv6bz5V) zCy1v--EWS$+<>9P+1FV#H(NA;@f17)`hmMe?Ku;pw$2V48z98&L2t}N;*$8N!Urwt z={Kt`g9b?5U#h3R^_4)y)r%#nzLGdxrc0J&u_QsVq=+R+l4XHdl3XuY41Hzs=r_{! zxHE}m7@Y~YyG|?v8B3EI-Uc7tB`LN;aZ!g#qIwRMM1!DZI)CD$P&iFyzjIN~Aq-_! z?QN}Q40;Y~#}GnjwQHhoK}%{H71|dD2TzCh`ssKf4%9IFV(?4(>ZS0poKbbZr=9#- zpLJnajos_@=MS0ZO_*l__(iBv({I!FmqL(~DkCB}FLKFwAtmR9Ap@Gsi%gSw3QZyw zx<0(QQV@7C#ao4Jt1!oEbuLB3T&qxE6(+g7an6iAlYLox;(aDLS{H~`?@{~a?TPbU zvnSR!Yhseh7q=(I7riGsl+9@#n!1H#{7!LR5B;ujohe+pRES^dOjJetuG%xjH+3x5 z8NCN07d$j&V&4?0;~+>%c;6tswv-UQLhizAOo>!uzcoc6Wq6@}tFgZd6KHq$dvi%# zjA7L(Ip%uai;tWGC>vd;=Y~>9?xJzf8y^mto^{nqO^?(ziRXN}lg zdL*s`_w+C{Fc(4R!szjwR!ts++0?f{8c}ON&82?eiW%6EoPa=B(BEwEa~&`Bv+BPX%dHhm!Y76=|PWsRfWqOLGYfjo?8_ z7JL|&fe}yuEBm5Cb0e0l&EAXBp!Tp3FC82FAi3{qsY=)T);b|}(3{W~Em;zJJ%YOD z4Ac7kBCrfGcS?0eProCOie?5+Cuk2(!NeA70Bd@WV6Y1D{l_q6^j(Fy894SH5hhE= zdfvl4#ze#=AcD6EBtsgpXh4lIgX~PgltJ9VB9o!$|Kvf<*zf@A*K* z+ecff6fMysxHypPSMzanevB)@)aB_I&KMZPu;3)L%+W;agJ)Dkg5XptXf-J72t!z+ z1j`g6;yMk4f|moXE)4^d$lwIW4@dc8T&FLQ@fop(NAVpX%hM6bf_Vac2v*=Uoj$;MKROmzfAYjPMx zP?l&uCk%CzCH``z`Tg;O@6F*%i&%v|0^7g|$QQ;Eglcg_s|z|NE=(>#H0V(zO_=kb z0(QbBpwjyE{fE2HL|r1OKJMLl1dV8)FIKB)gsVu3vCy6H|01)0JV|q?}v)u8c|0IgOn4$ zQ!DBtnv_Sdo+6dawPC*{vT_2^Br~uH9^i6Zy<}ZP0;qlAwZStn+Fz7v+{IB?3ItPV z?YY+{4zL%au}H}s)IKnP@v7bVG=5)<(o@vdHG=JyC~Of5g;pWWY86skUX_q|3sWOw z??=cuV4h)S=i)F+4HzgiN^yD$eL^7}g}fAE6nd9J!_yHufzU0{dej_N?W2_G1ZDaK zg*+5`ibBs)=)Y0uQ3^dop`8?Z0HGJ7v6Tso7YkYW(JYDyH{%k`gk)S)Oqhm?nmG#x z+EBoE$G{r8R18?@vTVRam*N3EUGkAr&xBN5%uKi*mu@B`=A(&jA$}l_)HPAdMd? zQlow5>Kau+5HaFBzO_=3I(JBzWjx{vm-6=cy#R$YyBy!*YVnu~v`scASJmCI~HEC$uhdF%7Hu0K{$Q||B7dtb9KW?#4Z zNC+2+2IV)8)8KYPBuZVG1Xl$}VEq^T4(IMGVnL#I<&x6_C8zO{RW}8ftgNn){&?l$ zGXlkbJL>nlf3+SR*1ix2m8N%j6G6|#QJ`llrirHHJF?a73FM-VzvI)Ve0NZs4sjim zMD;){25#@w~KhhM86R|KJ+&OQoaY;$&w) zU|Oo(r5DPPRpl-nDR0m~%xpuJktrx73z};r%6X!iDlv~&7gUp8c)nV+47)8CY^X); zwhY@E7Lc%RNfw>w3DRt?VH5EE_{!az8R*`P|MdHt3~tL&XbtkG zN%vb(rPQU7zOf1cmt%zW9uX~PrTdrTR4|#>UB=VNYgvxMXl6z))&*X&@SCi4PzNI zL+Uj3UKBL$s-qRuF&dkbWLb$OE*}Y*g3HS>kgiOGqyQ1F z`v-~aSSwVEP`HxfIIPK2uA}l$-U5;VS>dG-rHxaKn_ZBGJv&#JyofpQt zJP+Jk;G83^J==TAIa9I>i}%~mmSj0E-oFw7;^^uzN?a|KtVHu#!ldUAAyr*TBssuE znfSRngbH7Rg|h=hu#XT6sY;oJt3p_~GK__UWlh8KU=|XOLOFOpug@b)l{(jeW5hwo zU_^#tEk+*i2229?R=Z(9eD`y|AI5|gyAv=|7rs^rAyTES78Xh$FQhG_m#?O**fLsp zzSl44`V-=Iz9me;#JzMy?-A#4?-9E*&ic~buwo8@o(EP3PxTONiPL!sC-P9-dMF|x z);oj=PiE*8K3ri0zv=x53QQ_VhLVC36CiLxjLrWCsYH($IoPT0y=WKW&&nX^5Z4I<6i7@O`AvOBD#K}LH0&Z!{RButBMdVfXJ;?Tscz$=eSO@OKW7yW*$ zAz?3Yd%~9t|As5880xqqk&k2zJM3et&h7-uw3( zNrT=YOpy+I_i7+N=Y7$}i@g`oU!2JD_-?8pg1kxg>n)TFmUT_#?6QI6(vUBnx@sV$ z8fsyFf#o$VfXDF*gvSE!mLNRZ<^|y~nd5Qp47y5ICQYCkaa!l(f%8D`+-r!2;ij&^ z){*pW8mjJl)Z$F(+oV#k^~1N1l8i^n#Tu1ZmLQfT50&U?b`>#`K}9FkH0f&^cG2MO zNXASr>nm7y(_cje9^O$mNQI8BhXPA-E;qiFJ=0kN@q*!2fj@4$UHp@5xV=hto0t`_ z+?rUqzeDfU=3(hJB&eY^RMLp=r&3I%-$uLo(|Gl_qWS@9%np^dKjBN8U%CJVzxgRq zQ0M*H4da}=pbw&8I43hGd7P7b;aR9UvM5g4ye^DYsMz=D#-C`$IK_nRqUlw5 zv*A(XLu?+86<%>KTTt#A)=8tUJdR}!nU(%yO$*jRRX?p@UbFzboavTm_AGaoJ`J0L zR(NCvIJco+F2_+!iXORRmV?wQUcB1YUR6d zsU@||U#`MBWH$KT>(M^=EU1MkN$2lGtUtpWhslBBzm0fgdxXzV+6Q;yw!dV0Ur~}& zq85vEQi%quJ+UZ(+wC>NtRTbv&ZcvkI*; zC|?nK?+Em9YqXD4gV@KlLLZS(?4uc5>?0Wnp2r%x5#jyIb>m~{QJR(}XvIa)iaOGY zd}03tO{U|+$wvkTSBwdYVhmpYg3?Kt^RAK(1xqeAkegyx!DIiXGxo&`B)JT0f+~Fl z{U%q~AYviTgtsy=3=SHgbd!TL##gF4LajS^tqV}=SNAw9O1z@S;qvprS?cZNfYKQJ zka%pP1-OkI3D5(WInCTI26w1CR7@|V;#7**v77~1n3q?k;y3@sZ5Kc0G#o_noby0_t80QaC(K2uBndj_S_x+!#AC=n zwyV491Wa`end;n>s*_4|SZqlp38LkEK>1uy)>Tlc3v3v;4Sl466gtxKatdEp#Y$bn z@~WyV36;|rm%7O-h-RlyOMd5hxFU|ZK4QW(D}))YkFHi$Z#s@Q7Fc|p6=8t|by`U_ zFYu$)!g*jw*9&|lFIq;(4Pw)|*PgGG{?z@KsEel>JmYQ$K7Cfp9x8hTo-26Ai};d?rc$T{@%&@nAJ)W))}V3XI)`lmvyB ziaGK;OkkfesLZ$kM7PgDnaZF-iuY(f3ax|T9qOEM4d+!GFJ?P++MUmUjC97%U#fFC z4l)vMH`$*D%l%uEM2O%LwSSie$YTDux2NkwH}ZovQt45*YLBRP#z|EtMX2o3v#!5S z*?PM_#qBVgnZ#Urcu6HT#G+W1$CpDP7_lCofkJw6pxh9M>xM;)xO|G6PN8VD=2KJX zeUvD1b?M+hUW1Wgho_A?5|0+90d5B*0j>*NGjJs^2Vha)K3MSc$V&J)h>D?J6E6LV z-|5%~uoALB3uSVJ+;I(U^ymIoxL)e^fEeUcb5|!p+7ANM5Q1aU$=p9{dnKY2mEgL* z^leF2_ob&{rq_t27q}zO;4VE_-jr3|@G_)I>^duUc}3^2*mYj)8VMT-24}3a_HB7J zYB?*G=p>7mjv^^&0jXJ1_dyvctWOVCxDF-3^EpiG(}jN)Zd@i@vkb$-M@}pd+2flj z4-cJePzR3^NKEji!Ic-WoN9{C?Xh#vIeehbF@xlM##KAvd z9m}hn!KD(DD9()WgT-Va&5*P-jI=Vufb^qCXS_^>tD$j4 z(30CA7*AOD4Z(ki87FvCgp|eQ7mB~9&W9`%2Wk2zY=WkLD^_3$qBSXKcE_BGQ5WWB zzu!P}DO}RQlOCUcEsMAzn!-IgdL9ldZRMr0tFs_VnKCmC@?ym0KPvKk;?^KCv6FLiMwd7H`S7@YFqpsQ! zCf;$umF3qy@Cx!uN#Y%&(khj-S|iSqlA`WZ`LSLeL;+2e;r6;2iQt=Qx*=otEu5?#a4<@F0V!?b9pBTx5?wA!g!=fcc*md^Y^s720#Dfl*8rT z)hHp2oE!Hi9u%D?M2pN0sC%#jR&;n06(C zM~-WF{RCP47+8+U>Mq>4yLRV(N>Z8uDTRnaP$k=_SbjmgLnaJgdgvgOV)>|KQ%MyX z@hS)>M3m(7cbFU@YNurkS;W;RI4*v!Vqn@%2Yli<>b9ry$Y zk%K+>0P`32T`|87;M5S%gx&N%i0QhCsD`PAQ10{$)9MyhOILymD10nBM-@eDAxZM9 zDzy*LsCGZGgJ!!bwQGY4j_?H5>+f6|P_@g{QX5q5C{u>_pNTI9F;!|)Nu3&Ti%K%| zUhGnR{w|^nQSCuWw=1FjfaDy7Z_DVpXi13@EeFM_m*GPYOOJ_`6Qp`i$f`GmkM$Ec zz?DP;1Irhk_O+O*WbKg|rFvM^rKjDcFO&I84tlK9yN+@-{`lijv%Jsv7qux-U_?-Bh~VzlS^^{$0C)BD_7ldr4Ty z%H^&Sw}vvy4imSI!fv9Rv=j*OdY2(U6&g=fy4}OnKuw^briSu{HrScs-sMOapRn=Y zmG})Yw$<7DsF*N$sF&K}8)1YTN0vI^-%Ifdnm;7;%4DYNAfYY;tN_x?Iw|k^&ZAbDAGboe&i4NgCsR{NzEyx_|UpeK|RZwCk5-Si!=aQ zp#T@;p2RIFBA*@eKlV%%UvQVck`(NlaBGgMV$!WYlO5+@>$jvdMN4n?mFWA{&GV*_ zCZMgaNm#zk0Mb4jL0W{xV(eXh4GfM0u)8O&hd%aB2A!1s!QJq5h3^kyI%pun&3hbm zj-3#a`09>GG;wtow6vo=q+3v_vX?c4#wL1g3(&nqLYLdHTc_yRO|_eWl=US`qxyLnUsC&NOt zO_yekU<#6vd0acpfp&;)PeczJREa^Z)+V4hu$UH1Q^;PYJwKxde8c8wT(765Da(%K z3~h>v1$N(mv7ui@hvxc5d7&+e=6Ni8#|)q>7Kt6qJoj5c?(AqhqUhJ z8$dYgE$7o7t_Yw$HGukSzn3Sq$3@G73K>-aGQzKo7I`-~C9R<3A-O@6(e=ku( zMo%WQvXsdhB{GvpK`+MR@kBhSsKycEz9N|TII0RlcyLseyUb$;utFZ+yL&E~=80fk z0O9w3h6)w+S*wnuJ|W0o!s*nE(L={ZFLN>!m0UrswV*%YYAuLHq0m_xkizmgp3je6KWLMpn_xon?TgVlbP#3yz{H?yy_&h!>)?(j< z^!6I@VZx?l8m6}-n%-y~6`0Q^fj2z}uM^dW z%t=v)%(L)xuyr2&W9p^}nO#_*l2cD&iB! z=fcgtYhf8nWg6+&l;eV~9LBZ|C0+Fp(|SC+L^ZrC^0VRgz&WsnJm4@CWxW~{;K#dy zB<9O$rU$Pq3$Eeh%Ifi<+7!E5xQ1)wnOUo5;Z%ASS{~a+-hK>Avy0UY-O%rx}hyL@EU?aJg;9k`3 z>_-M1>A)dB=cwCqwx&sEYf$U21MdSz9-;Kxr1)IRXy=R?9MB!*RnP%3(K#Yr%Dp6f zpJ%00cG41+blCXT!q=KK>jdpmVUoMef7it%*CCDT5JXTXvE1{WInW%01wUg(C$6|< z#zjKIe1F+aLtl)6TSia%8oaeRqLjAqgnaw$qi ziq;`oGR7cOA{uXV4PKR7quTL|%K>weQ_*f2<6Ks(uy4OfTjx4m$7Ft9{M>&42ki?nR%><5kmW3lQamsMgGAf=5Q4~hvQHrB(a zn_~g9!gY=bE0#Kinpcychibf&v2tzLiNZs%q#U2U3PX?UE3XGByj1QXyRd=RT)=I* ztjZ?EkjO#JzUy%SWZX}qYKNaju?1!$-TRyIih}aRQa;6>^9dgA!pvyKV+CWn7E=ry zlH_^qunN_9hRf<)7DUTJj!`zp$S5nd1mE1C4C5x2O3`|X*T==1Gy85OPb!?FYVVHe zd>8kcrYP_CVASIEJIwnC0+a#TO6^^Z4C96fnObCQehpnyjLi!$8YZmOk!2{3gj1H& z5`N}NewYZy2ZF?h>N23bQrFYrbzRB0 z?Ly7HlRmVG6GJ<+lFV=wuB8UN^Xb59OvEq2Y@+qpn18QQ zdb_;bb#}ycP*o+}r4pM{RMK$I@JTcsWV00Ms-=zvHPYABfz6d7y||ACq`dbc?lmAB zQFGH%l$6yq!@=&Bg!W$o=0;k@qhvN96 z_g*zW_x}5ea+?%i!`Hb9sPEitD$QGxAMjhwEwV&ZgAOO-95+HzFOkhPl-v}5$ntON zacWpvO>(!TxVxSuyY1ZL;0DnQE-})jE7bL_7pX7N+TIrsf!es; zx|gcfzEFK_y;!viwVTJ>Q9S{76h%Bs{;7NPV%I>(8RcAlMme3IQT|&0d)nXjAF|a; zJ+h~&2Cgbz2X|F*eohOVRo;aG?(e`+_Lu#87a?f#j$+e6;<(VVszeP7+`k2zB_!r> zoZ<9z95{&^`S{2{F5FN20c|>Gjoo`Z*HGFm;Yd^IPHBZsEbWt4ApBr|nXa$&VR*UL z^jqikm43V5s_!fPmh9RKxY=&uZnhh_n{A$dYl43(%$#I-$4Qn#ZNR~{16WJ@NNU09 z>V%308heLIlA_R}`w`mv7<=B~C_EcAL-CyRB{Jv#P=O~NxH`oN%~|L!4%zcP$}T+E zh7-1=XZh-pM+VLc(1~^98|%EUP6Bz}Un~7(b*NG=51j0c?33j*SB$pa{lMO-?!G69 zVPQu{6V81T_@iy;`H!%T<*pjV@xc)~_27Sq)QoHf4hc7Nn=6IeTsUJ3#v})Pdb|O} z>RX8C=V(=E!Ct|Lv`yEfmY>v>s~d`&(ti{l8`(53w)v6pt7IJz(KCHes&h2wlJw~3QvHY!%PlWg|N%CJ|Kj8QTI|^{=HPSfA32C z$URXE+86QcfqyTd2MP4^4Q2NuJloU2eM}gSeSt7O2!E;U1`8F$A(B46cWaKH=yUBE zrY6Su!cQ=RBXUO~Jr>VpMcEP^c@;RX)%E-{nEozK@C4cy?FCPXe0@)lk65^>(%tJo zpvLC?9Z*r|B{wslvwAKU&sqMxRIE~_ld?H#$HQ1SHg9Vno#^I#DQ`Fls<=7VaF(97 zNHFTXJ*a)G*SEu^7U=R+ogPa}(!$Z^N60`G~)9q4X;Fxf^vmWQcJ^7b$KQ(j(9 zUHUn9jP6)Y1HZDy&qd13iEDGld(WJuwYJysKH1D&@%c1+I`tA4YjSVmJu4URo+3`C z!2M_R-lBkD+=%?4&iKFrRT+ol%dxRZU3p~s!anqnj=e(xVJ*TBOKpJifwJ&FM0(#f zqIP<52Vav8l2zk<)k9eB$b-*tI_B(XWzgKjCE$840oU;7*jK3dL+o7Ul&6z_g7zjn zAVcero?+THAD3k1I82T7_b}!Ys5eWlz!>92H{T_(*Y5V_T?dmpJ3vv8FhSTEpUn=ige=ZnUvT8Rr^uDVmp zZ6WCqQXk@E-;04#^%7S=@@s=CqlJ_}B~F8DV-gcPRPL{<-F&+b215N%%uM!_FHz$A za$=DR5z*KoK^|BHT;_dGjC-xFEb_`j#{YPUA0JhBe;soXTt7NIScUEM%`i*&yHlhh z5{bYhMH+&n0^3PrQt^JZyCXU9U{&Ca2wZ#`G5*Hhh@g?*h)_v!p>IUE4bnu$PY|}Z za1pwZi_kpSiPv&5TBaWtqd9>?C>w!%s2IsF=?I>+%FC5UZj@s!B#9H-%-k zKnV2uXMtV^kA?SXHsVi5jFj_f81_-{JbeT2gP!*Rj`Z<)y0Yn-0P+uf3|aV6bM)Jh z=jiohuHp#5jtNE!miO?#2h)I*;^j}NtMK?^s84{OW1y93@Hqy&x)X0SwNA%j^}dk9 z>eWqI-qpkMLZ6<_#pny$@|i(y)3H+=*oVP`xD&Qv_^`(VIJ66yU-nn?OU~QjxE_J4 zZw*{=ICE%pVq0Jp!p8Id#Fc@ojbGiC^T@ZH@>wnzE$5Brr9*gO4%PA`o#0vb`LQQ; zxCWNXxl<|98U5*jb2o#z<6{O+jVR|dc$@r*>rt7P>;nEqYvnOMSxf0L_G_Lre;=N@ zsd@C9m_@(WnCLg%K)?Bm@LT_2;wpZbx}0CGS->x`Df}{D&o8$m+xR2~Uoav<(A^GxgP`fhV1Fx){=mV#16RzW(^ZkjtfNSo7 zdnV(J%8X&97vH^_^f+1bAOFkmC&QxNRS-R7ISS1WH7J#+vX{Wqehi-WceD>5@EP2Y z-Sdcub9Wto>M5JVXZELD9<}W$?>}ix#}Vv5dFl0wr)HnJbO2{QG zwl@XywVRvac=%t$4chpjo3C2~X0LaX9Q()mdHftgQ?!7jMOq$~ zPbSJc8yrJXAYdPLfx+WSF`4Q3~Dv zDk^Xe!uuNNp1(^4;>Woh9_G824tmn5OIMdCO1qO*M+m9z!BaqCm}K+`K{_hjTRuDI;ZpG9oZ)Qi8(CL18@)8@2)A zz~9{n?}nGqvsH;e_kZH| zc>Hl4LVL@`&28+XxXq5u8{4+yJ3&!pLb0Q>aie2tYf)>9(B9fy(%9@^A5)GFhrn2i zfX|umPn!HDdMSP71mBOk%Tc$qWn+8bLpzDlk-kRqI-5{0+s=yG9r$(+HL#eKMwPTX z9LpOwwAZ$8XT_|jxwXS#t!=48>x0296+6aS`cbsiQQJo482bSaFK(vKS=~Sw*xFk+ zIyyQi2fk0F#4N6>Yey^|nTcNBT3Z)rZ!sh;2%8%AYH*81t()6w+Z~o|8~I0uaPB6i z-05iFZo?;DTH80*wrq41wK|CwaIB-{m5m$k;t`DfJPP+k&h~bEf@oy}x?8ujj{#4EgrN{S%8DC1YB%7HR}nzEsJ6MegJr5#I@&ikwt$d< zsu=r8c>T<(s%ioHAZHyq;%E~ZTU*coAr$KJj&8SD3&zWZt7sw6JnP;IvvfdW-NAj>!wYP_5gdCE4sq5sSzD-=M^n+ zHr914X8(+?YH1IP$G4!0s~6jrD){VV8=LJUzRm4yBN)}(xPc@3U)0v}+77|e-rkBn zo?!SaPHS_gV`&>cpksk(Z%@MpK0~gMm`MzBk5B0cT)62IK1*Bb9NSj5E(cbufb!qw z=onA6Kx-_uS(n>@)2+qw7kXq3VGDf2?&m!WCI(~Q4ZvaOk(7HNaovpdu7i=Z9)Rod znNUM`X-*?x=QWHq0QwR3BmN|=mL$kA;4s1pd@m6GE*^yI0cZes0+LhkjW|FlwpL>o z;1hAU?guFMjR;?h_~6{j&?UA+zWUE@IK%Pz+ONq z(pTX64(Rv^U>VB&Nski)^HA5d@OrMgwXQw*}XGaJ>VC#%15yDi0Gk0j0lNV&08Rit0Ze)T zvI{T*mH{>ab^^W+*bg`b7y)Se@a;N)4X_DtFW^zYuK=$D-Us{>kRUR)5KshI1K0}q zCg2&stALXLA0Vb5eE?(vZU@u?wgVmkJOda6ya%`dz+?67IzS;{J)j5h4B)qbi-1`V zqMv{oKr283JPQ~C_yAfr_yn*5>HzlwegHTCI1A8x1N{e716lz01AYwH5BLZ$19n{+ zU^$=-@F3t9fWv@414aOeyBNC}U4aWHyCqun3sOv@oZxV$<0SmcSC()i^?w#AdPCY!1Gec@4Xk&1HHv zk6p*EXDMtxyMf)v7O;wxdVM~~mEoHZ}Wo$VsWo2vyv$1kk!7ABGRs|hj!&b37*qv-OzG}6W ztz&k!p4H;(RvTFzbFg~0i8bJBR!!_Ke7$NjYr)s7+SnF+)v5zuzjETsR$K8+(CzGQ z_I0*{b+LQcy{wz{u=|(`;@`{eXAiJGCbE9Kj^RP(X5V1nWV_fy>|5;H>|yo@`wm;W zp{x#*b0?peikq8@YFnyWnqhvFwQgm&$DC5sT-(vHVnY)?>BjIH5`5IKU2wKBd*cTC zMoO|bcG%lDx3!r~Jg#mt|IA!RbE{x)ZnZZwno~2B1ej^|;Dj`uunDoXg3xYnt*=Lp zKs{rz9gTN8g5oyU*4Z~W>w{ui@C8`Au)WP;ht(Jq-`3J*$K>9EHbdiE+bIfWiM_tP zb@Sy@LyK)8!^+MZ!{_brwlkstVJRoH)d~&vhzV$}v8BE>Vj?U)d=M|JvX0J;!Py(@ zcte{o&nx{4M0N15N!r`m9rcadg3`c~&8WC>Bg~ATXktK}qrR5fObt-Ky@6K_!y>@X z`sUWH3ez?rl?qKvmCI7M+GT#%IXdlQ*agM6wYS!B<^-?^O4`!a5*`VHwAlrimiErt z=I~^py|&HX;@ljb0!G(`VIcRHVhFMsOf>|J;bt5%h z4+~lzD9#NX+dDwu5cDTxx_m121VRv8MR+?h2jvEoR42X!38AcOtlb2W2xeYuAgPsG z;&u#?0JUl8HMTSg_7=xhvr!g-u{a`6YfFbikt?16&7eff+5zV91_&Arn~sgGZOXu& z7%dOav8sX!HQPx%?G3GMiiif6r9rJAD;J`!H?=ml1ZtFfA1K0U$FYbUec3X>NCe0* z-Wt~|0rAf$Na4OxH7>|<5xZopvtPDnloo*r)Y`Y8ExUqhW zI3cwviI=UqJ&3F!B`M*ur8*Qmxz6O$MtsLIxVG8eMoM^mActllac^xOAI<)0wP zWAVf;>H+Uvd+pe~IG$mw!*@Bha|zv03neIvNE^jrDz0}nb58(NpOQl2&xZtg2JrP~ zdoWgGiA3v-&5dNkv^(H&2rEq)8d|sTu}!mP#0<@iEqB@L@bP7u`vXcXfM7^VJYPqf z!%=6i-6%A6UZFNQmxKFN6q|$(>G5Gsjmp_NoQiQcAukPkpOJ*tAb`QDbDZE@Aq9(AV5pBZEf0Yp5sQ=| zl89Y4U#ReWK{gVeh*=;!k>W`#BE^TWK2nAN>mwzBqjoqb?Gr^HU_yrybD|7HtdOW1 zY$$|QAan&_u;s)yF38cT^IfW)w)+s!i zS{lzUSJY8!C$o=~Qd{kIT1ML2#+F_k&1hU8M=WIs@F*yf>JJdK172g;ro5i^#@6;m zVS50hpp@Vt)UjFaK!jEUDU{o(3~b6iX2_ZXxKmt*UC}i>OPKlEv9(dy*bq?M&5qi3 znTes?2+l-Zka-ruu;46c)It95jZnKJ28KXaL9N>M4R%K}-@M?&=u{NLgf!v>(x@X? zIMkv^tiEykzvOSX8U7dUSMH|0`2U#oYVrRPJpNy!{~J&sincG|V}n~N98-x7rBZ=dR;OY-hUG0)hV&v$6=a1TM z0}hSI*TVCyz`X#F1y=vqnPvUqxY4C6wI2drHP%3t?2yxG#4{02aEQBV~PY(|&^|XQ0vl%sR zLTyArJz5gbIs<12=M{l=h@;fH!c)4FxpO7lt?(2_1!!3ZpDWQen6H=PO%1RidbEN+ z*wh6s+OT>iav&o>{|w&iR8Ida9wrIH-UuKHQeTT6DZLn%Ozho3rm+))RFbj|^tBe) zj`MetY7b@j|MyRaJ&!2tSEQ~_txIi4ZBA`V6;ijQ?nv!U-I>~#y53l4Y%n$(+l+#7 zn{kJ++ql!%XME7O%lNSIIpcuwWuwP<(0JH*)OgHz!g$j7w(+#lY$`TcP0LL-(@N7S z(;CxyQ=O^7)NE=q38rnP9j0#6PE()hLDO#24^2;-o;B?;J!cv)y=?NB4w?>|j+%~{ zPMA)b-Zq^!oi%w)!>0453#Jj%C|vjn=}GCy>H74P^abgUr|(YxVfxeQ&!+E5e=dC> z{pEB|`oZ+W=||I#rJqPYnf`YA>GZSd-t^)0^XV7TN76^J0ieoIXJ|5X83`Fl8Oa&? zjFgN88H+Lu8Kw+t#_|kX#>$LU8EqLt#M|2DlQNSt^_eM|3o;jF8Zu3pS($m6 z=FH+uYv%GyTV`TbR#s`&s;tdf_ho%I>)EWqth9WvSC8`~xLlKSV@_&LZjL2qMUIej zPflOXw{jlOc_ZgU&Z(UDa?a&wa%beu&YhRLAU8fQC2x6NV_r*MPu??mx8$egTk`MC zHx#57SPPm8S_|$gc&6az1%m~%3+EOtDQqv?TG(H>yYN?q-a?2cdk$?aGL##t4ULBT z48w-%)YYjislQIWkeZM-D{WDlCGBTvvy9goQ;l85Jd*=l`Ox&KDK33OdUN`t>2pD~ z%#0s{F0W>+%{-U+VP;fT2m13s)?-<}%G#fGA?wC$bM}ht>g9odJo_vIYO@#Q4t zp2^M6+n)EGychCb&iieiKW}D!a(-&QJ-;r$EC0UypXC1{e}Dep@|P6cT4*d>T3A-N zp>R{-J%uis0L=2l6Ju}yuA=+tn0GBk^SGYpU$3|Gb6{4lb2JSvnHoAr$6VrIZxy~ne$T4 z$((=XMCZ=T&B-oBu)n z`FwT3{DP{2H3c07cNg>(xC?d{JYVo~!I^@;7W}PX8sy>TLPMdcFsHD%&|P?<@Q;PV zg`XAvqYxWe>~VB)s^I~{gNA=Iyk+=<;RAyz)s|Y7x*_%6)L*53l6t+d2z`Cn_$T9^ zjh`5AH07IaGgV{IUUsI4-P*G3=IVSFZ zhxp&durEe3n`)>u^c%iu_>SRI!?#oSrQVvhB&{-Sb=thmb~f#U zwDV~f(?-)`jFXL58Iz22jW-x?G3FT;8b%7 literal 0 HcmV?d00001 diff --git a/branches/WOF2-3/ulp/nd/user/fre_svr-08_ia64/ia64/ndinstall.exe b/branches/WOF2-3/ulp/nd/user/fre_svr-08_ia64/ia64/ndinstall.exe new file mode 100644 index 0000000000000000000000000000000000000000..72fd10ed396a8ee631110e52cc4944d3b7d2dc74 GIT binary patch literal 9216 zcmeHMeQ;A(cE7UaV2CjyMH@(fh{WEI@UhRxlJ#Y5gGEeZ2Vpt3mDmVjJ^M+>lJfMP zF`baLS9k|SxS=iENjph4uCv?hE|ap`O~a=7Fd++JhGbd7rp_jldZ#22HEC$Wf@!>Y z{hg;LY`)UzADMPKxteqDJ?EZ#&bjBF`|i_u4G-*L`HV3=Kv5VwfR;+NT7P*phT-Dd zUMyxmpZVsJ1G@S*moy2Xgefk@y2L=YsUr}L#w61g-XzLVQz&Yx-QYEK$AbLI*|TSr zXrkMno_p(pgWs;p!Ri@v>*fPrJtI$R^>qey{E@o5Rr*bJMQWR`jn7cq#!!bqGOo1P z<7TX0r)S^)u5xK?jOFQW)D<%J4R9A_XSf!kH2^pj*QxzH#%=(b19fCGYB+1|HyQj^ z-LE1h8o^|mpY3HksFyEcEJ#>2W6zSKuPh$McIg;9i@9XN^~#=kSL_M+k6n)$^pz6d zE1`Ydh>Gl@wbCX}D<;M^uM7sH0BF0(HV%L_vs(buN;P96E5(G^0h+o75L8)L7z}dt zN|BGmz*t0bJQ|+~?X*(O*qUkR*WLd`4}@=LtQYVo;0eHUfHnY?V`xVKrvT>xLMdZS z00*E1Pz?A22l*7>IN)c1y@1_-9>BvGr;=c-53$(S2$~D96hP$`Y5`~NVC-qY2w*>8 zH{cO~2nYk(08M~D1~>p5U@2fRU>@KtK(4&8fZ;S{OY~Nz``d+6c#fWX7UY4@3K+%N z8pY#)N-6U)AE1f3Sp#ci8}MrawGFG-4v-knx|x}+0wu(@uqaMyUXsNqRPv%26HT1}kq<;nJh*rMe5nwm>db3=)UaYB~!p81fszRPrIq@GtB9N%f#)uRWR1bcOfF00}+{b_i9Q_ z+d`6{DTZaWyr$%Own0WMA3^x2Vy+gVEzRq3nC_1Tw!kDQX6g(@gRl|%M1&rM9(gy` zdCAt=`g*MCnsXzuKrqLrd8n0Rx@Q68t4o(OA^*c-fDF#abR?+JTkHM7b2smPw0F4v z?{1%XePL?2ARqJ&N87fTxD{3Bsuf(DgjbWTZCgUoHW>ll7TXf;6nX!)h~V$FS=&Np zRMDX3!jlWAlWyO$OBVMzVT(w!##Hn zCQ4H7bA#(V9>pr`yEF{D`wvTaMk)>GQuh%O)4sQtH>r;${kTEbK`@#kR?;N^tzE>C}Up-G# z6r(;nT%5!4{-PUStQeP~^$Z4$j-V`?PvQ42`v?GXgPuB8A z+_Mym2E?)O{xsW;UUo$K&+Nr1o(id!^p2vzfyftdhmc1xX$-2yNb|L@5Za(w3;xsl zv3q?l6L;R6fj?J~?kq9@B)Ow7Z%2_*k#SEd%4wpcH|Wy`n+M~%M-A0GPskUS9ZpW< zZIWg^s&lQ7^saBoC+56TL&5fQC{0d;d{S9*A|jP0Cq!u`1WkUfDC2jKTzQ5X$>aIT zw!+L)&^ca|DTJEwg3PbcC`JJi%p>E*Y)>#vS)F`CQTNB6`FkvI`UW+pNy053zcH2Lp@AgVL4SCRZCGR#{C95Ec1qKz_Rmj z1dp2#QKNV`n%_&cPX>qPlSktERQst{cbb{b+uWiUJ(%b`BrR|rhAHRQrQ}oN1|fqv zim?epax*~?QF8Wc`}R~SW=xdYDd`36R$n~%6B;V0z) z{(Q32$5Ev$wH(vsq}?ilP4X^R>n!I^`wCF||Z{z{mwYj{A? zV?!H;TtEi^hvj(#Z37($pbsVQrvUQeAK>c0^RZAWUo}* z^Ah11;B&rrFnutr8>R(h7Qjic>2+9&8IhqSve&H8N}iS99ZS+duVFPEmP=T({t{$hb-tXx7(apmpQ%&275f2BHcC$yPI zF5R1gAMf#sv0kNSwJW9108_P0tJDiN-B8%sZ_j$U{ZP8bm48t4@2BRYo&CM@Z`94% z3zunUXWI1a1x*Imx$@tb^Fqx$Z}XfN9=gGNV&HtsU~S?2o<(>PrR$2E7sZ+B*24UE zou7+E$=7frEp@&leuQWFrUx~#;X>go9jzVMp(H=aUPP;F%sfDmkI1ZqmSwMb8Z)Wf zQCOC)E;*RF?ZWZoST2CZO%#VL&CEwD3-Av~HJjp43o!FYrUPPg9(m%DN0idXFZBhy zwCIA01&l0RTVhB>N(_U5Wn(zo>NB>?J!$@>C&g#z?ZQ2&2~W8v2Hj_a!!++uy5Vdv zHJiFVKh~K3uzh1ztLkw@o~J(3i*Q#6_hPREiiJ!y#nJ2YHHQe4GC`%oQ{!P+hZCi` zJ{M2nBEhf(v+Cgx^9VK(kGh)VMMZKgaZjonDlbcKbPb$%xTOC-VTd8Ia8N%h#WRUazQw+wf#_M zWj?x)hX8UHYAeuQ-wdkLlKh0auPv|M_fhpfI*&+(A5jiXnt9>)@I0)3+>5uo2^__8 z=t|3zW_dy}+R!(jRg5mJtyWvO8GN9O&6iR2w~1FRG{7Qb%=VE$YtQ#<<$d4yw(fYPBhFsZFU(ZB~?{ zdE&7G0ZrP?hTGIuKfD?3pu2E5LioTKF0vy9^un&gRu0kNa1hv$0(z03sb?cc3fk0B z?FPpy5~d81{diA8mo|WovanOV{@SQZ^AzK9bm0jOO>Ut|X&fqtnKR7BSuPfa&8Wr;Yy#$LDRpo+ZSQEw9{;*1*`lX|x;e zKn@SIA{x`m7-)!fc5WJ97&(t1XxA$LpYkzx=i%Sw+DI(H-^*`j4TPpQjX zdpdt8wgs;o1yU>$+s2FR&zRqj|LWa=P&6QRCD=Tjzk}}$AKV(JIugbXKzckUbKl!=*0%H#n^{TuB19g=@=i%4# z)<HeROTCJ01{`;Lw=ZZF+>w{n4zsG#SPt{h)dI z0_|)=EGS3#IyHrY$nxcHlzDNxhZm6*>ZWuUvMr>ag()(cLLFOG0HBfZ9tR-0;=S zv+kjrtI$Krfa&qOG8TWBM>D+0p^M0;M_Cu7g^+*eAvwxAk!@$}J1P&y%8@s*1Im$) z=RjYD6pD_m1y46J^#Sm2hcy9Ucxa+Dpru?sjl@{5O6z4yF(;>^790sY14(xrHiW z%WSWsOqBLzCCFs;OUu-%r@qgugS0KGrViDH7S$U;*tHEfeW;vsm7FVgz^eJ*s;;_B z^}kK+Q>4*)C{CN9NxZZQ+L3I8(kCz+BKSoF2kkyZ-Sl{xsozfwUrjNnU*qUuy zY+G$RY)RWwwqMu|*^b(NWm{=)w8!m#V*j>%z<$*Jmi?stUHb?2f3aum|7JgL&vz_# z-04{3sCW1sAxG4aaD314*N$PwvySH-haJZpZ#zDAeB$`banW&uv&d<5mOEWexAR`7 z*XegYm$)~$ cQ(T7Amlc+klr1g$YPR-ksb72Gzw^L<0d>azy8r+H literal 0 HcmV?d00001 diff --git a/branches/WOF2-3/ulp/nd/user/makefile b/branches/WOF2-3/ulp/nd/user/makefile new file mode 100644 index 00000000..af891baf --- /dev/null +++ b/branches/WOF2-3/ulp/nd/user/makefile @@ -0,0 +1,17 @@ +# +# Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +# If ND SDK installed then Defeat IA64 builds +# Otherwise, default all builds. + +DDK_BLOCK_ON_IA64=1 +!IFNDEF ND_SDK_PATH +!MESSAGE Skipping ibndprov.dll build: ND_SD_PATH not set. +DDK_BLOCK_ON_X86=1 +DDK_BLOCK_ON_AMD64=1 +!ENDIF + +!INCLUDE ..\..\..\inc\openib.def diff --git a/branches/WOF2-3/ulp/nd/user/makefile.inc b/branches/WOF2-3/ulp/nd/user/makefile.inc new file mode 100644 index 00000000..cf8ed40f --- /dev/null +++ b/branches/WOF2-3/ulp/nd/user/makefile.inc @@ -0,0 +1,27 @@ +# Fake like something useful is being built. +# Recreate standard build obj{fre|chk}_xxx_xxx\ folders from cached binaries. +# files then copied to the $(ND_TARGET*) +# +# When ND sources hit svn, this hack will be removed. +# recreate dir structure and nd binaries are obj*\ folders tend to get +# removed; don't want to lose the ONLY copies of the ND binaries we have. +# +# ND on ia64 is not supported [8-07-08]. Building the ia64\ folders is a +# blantant hack to keep the build happy; WIX installer does not use the +# ia64 .exe or .dll. If someone knows how to force the build to skip ia64, +# please enlighten. + +.\$(O)\ibndprov.dll : + xcopy fre_w7_ia64 objfre_win7_ia64 /E/I/K/Y + xcopy fre_w7_ia64 objchk_win7_ia64 /E/I/K/Y + xcopy fre_svr-08_ia64 objfre_wlh_ia64 /E/I/K/Y + xcopy fre_svr-08_ia64 objchk_wlh_ia64 /E/I/K/Y + xcopy fre_svr-03_ia64 objfre_wnet_ia64 /E/I/K/Y + xcopy fre_svr-03_ia64 objchk_wnet_ia64 /E/I/K/Y + +$(ND_TARGET1) : .\$(O)\ibndprov.dll + copy /B/Y .\$(O)\$(@B).dll $@ + +$(ND_TARGET2) : .\$(O)\ndinstall.exe + copy /B/Y .\$(O)\$(@B).exe $@ + diff --git a/branches/WOF2-3/ulp/nd/user/nddebug.h b/branches/WOF2-3/ulp/nd/user/nddebug.h new file mode 100644 index 00000000..ab5607b4 --- /dev/null +++ b/branches/WOF2-3/ulp/nd/user/nddebug.h @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id:$ + */ + +#pragma once + +#ifdef __MODULE__ +#undef __MODULE__ +#endif +#define __MODULE__ "[ND]" + + +#include + +extern uint32_t g_nd_dbg_level; +extern uint32_t g_nd_dbg_flags; + +#if defined(EVENT_TRACING) +// +// Software Tracing Definitions +// + + +#define WPP_CONTROL_GUIDS \ + WPP_DEFINE_CONTROL_GUID(NDCtlGuid1,(1463B4CE,7A66,47a4,ABDB,09EE7AD9E698), \ + WPP_DEFINE_BIT( ND_DBG_ERROR)\ + WPP_DEFINE_BIT( ND_DBG_NDI)) + + + +#define WPP_LEVEL_FLAGS_ENABLED(lvl, flags) (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= lvl) +#define WPP_LEVEL_FLAGS_LOGGER(lvl,flags) WPP_LEVEL_LOGGER(flags) +#define WPP_FLAG_ENABLED(flags)(WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= TRACE_LEVEL_VERBOSE) +#define WPP_FLAG_LOGGER(flags) WPP_LEVEL_LOGGER(flags) + + +// begin_wpp config +// ND_ENTER( FLAG ); +// ND_EXIT( FLAG ); +// USEPREFIX(ND_PRINT, "%!STDPREFIX! [ND] :%!FUNC!() :"); +// USESUFFIX(ND_ENTER, " [ND] :%!FUNC!():["); +// USESUFFIX(ND_EXIT, " [ND] :%!FUNC!():]"); +// end_wpp + + + +#else + +#include +#include + +/* + * Debug macros + */ + + +/* Debug message source */ +#define ND_DBG_ERR (1 << 0) +#define ND_DBG_NDI (1 << 1) + +#define ND_DBG_ERROR (CL_DBG_ERROR | ND_DBG_ERR) + +#if DBG + +// assignment of _level_ is need to to overcome warning C4127 +#define ND_PRINT( _level_,_flag_,_msg_) \ + { \ + if( g_nd_dbg_level >= (_level_) ) \ + CL_TRACE( _flag_, g_nd_dbg_flags, _msg_ ); \ + } + + +#define ND_PRINT_EXIT( _level_,_flag_,_msg_) \ + { \ + if( g_nd_dbg_level >= (_level_) ) \ + CL_TRACE( _flag_, g_nd_dbg_flags, _msg_ );\ + ND_EXIT( _flag_ );\ + } + +#define ND_ENTER( _flag_) \ + { \ + if( g_nd_dbg_level >= TRACE_LEVEL_VERBOSE ) \ + CL_ENTER( _flag_, g_nd_dbg_flags ); \ + } + +#define ND_EXIT( _flag_)\ + { \ + if( g_nd_dbg_level >= TRACE_LEVEL_VERBOSE ) \ + CL_EXIT( _flag_, g_nd_dbg_flags ); \ + } + + +#else + +#define ND_PRINT( lvl, flags, msg) + +#define ND_PRINT_EXIT( _level_,_flag_,_msg_) + +#define ND_ENTER( _flag_) + +#define ND_EXIT( _flag_) + + +#endif + +#endif //EVENT_TRACING + + +#if DBG +struct dbg_data +{ + int64_t rcv_cnt; + int64_t rcv_pkts; + int64_t rcv_bytes; + int64_t rcv_pkts_err; + int64_t rcv_pkts_zero; + int64_t snd_cnt; + int64_t snd_pkts; + int64_t snd_bytes; + int64_t snd_pkts_err; + int64_t snd_pkts_zero; + int64_t c_cnt; + int64_t c_rcv_pkts; + int64_t c_rcv_bytes; + int64_t c_rcv_pkts_err; + int64_t c_snd_pkts; + int64_t c_snd_bytes; + int64_t c_snd_pkts_err; +}; + +extern dbg_data g; + +#endif diff --git a/branches/WOF2-3/ulp/netdirect/dirs b/branches/WOF2-3/ulp/netdirect/dirs new file mode 100644 index 00000000..0e61a797 --- /dev/null +++ b/branches/WOF2-3/ulp/netdirect/dirs @@ -0,0 +1 @@ +DIRS = user diff --git a/branches/WOF2-3/ulp/netdirect/user/SOURCES b/branches/WOF2-3/ulp/netdirect/user/SOURCES new file mode 100644 index 00000000..ef6f2a19 --- /dev/null +++ b/branches/WOF2-3/ulp/netdirect/user/SOURCES @@ -0,0 +1,43 @@ +!if $(FREEBUILD) +TARGETNAME = wvndprov +!else +TARGETNAME = wvndprovd +!endif + +TARGETPATH = ..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = DYNLINK + +!if $(_NT_TOOLS_VERSION) == 0x700 +DLLDEF = $O\nd_export.def +!else +DLLDEF = $(OBJ_PATH)\$O\nd_export.def +!endif + +DLLENTRY = DllMain +USE_MSVCRT = 1 + +SOURCES = \ + nd_main.cpp \ + nd_base.cpp \ + nd_provider.cpp \ + nd_adapter.cpp \ + nd_listen.cpp \ + nd_connect.cpp \ + nd_ep.cpp \ + nd_mw.cpp \ + nd_cq.cpp + +INCLUDES = ..\..\..\inc;..\..\..\inc\user;\ + ..\..\..\inc\user\linux;$(ND_SDK_PATH)\include; + +TARGETLIBS = \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\uuid.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ + $(SDK_LIB_PATH)\iphlpapi.lib \ + $(TARGETPATH)\*\ibat.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\winverbs.lib +!else + $(TARGETPATH)\*\winverbsd.lib +!endif diff --git a/branches/WOF2-3/ulp/netdirect/user/makefile b/branches/WOF2-3/ulp/netdirect/user/makefile new file mode 100644 index 00000000..c43884f1 --- /dev/null +++ b/branches/WOF2-3/ulp/netdirect/user/makefile @@ -0,0 +1,14 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!IFNDEF ND_SDK_PATH +!MESSAGE Skipping wvndprov.dll build: ND_SD_PATH not set. +DDK_BLOCK_ON_X86 = 1 +DDK_BLOCK_ON_AMD64 = 1 +DDK_BLOCK_ON_IA64 = 1 +!ENDIF + +!INCLUDE ..\..\..\inc\openib.def diff --git a/branches/WOF2-3/ulp/netdirect/user/nd_adapter.cpp b/branches/WOF2-3/ulp/netdirect/user/nd_adapter.cpp new file mode 100644 index 00000000..805f77b4 --- /dev/null +++ b/branches/WOF2-3/ulp/netdirect/user/nd_adapter.cpp @@ -0,0 +1,302 @@ +/* + * Copyright (c) 2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION 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 "nd_adapter.h" +#include "nd_cq.h" +#include "nd_listen.h" +#include "nd_connect.h" +#include "nd_mw.h" +#include "nd_ep.h" + + +CNDAdapter::CNDAdapter(CNDProvider *pProvider) +{ + pProvider->AddRef(); + m_pProvider = pProvider; + m_pWvProvider = NULL; + m_pWvDevice = NULL; + m_pWvPd = NULL; + DListInit(&m_MrList); + InitializeCriticalSection(&m_Lock); +} + +STDMETHODIMP CNDAdapter:: +Init(const struct sockaddr *pAddress, SIZE_T AddressLength) +{ + HRESULT hr; + + hr = WvGetObject(IID_IWVProvider, (LPVOID *) &m_pWvProvider); + if (FAILED(hr)) { + return NDConvertWVStatus(hr); + } + + hr = m_pWvProvider->TranslateAddress(pAddress, &m_DevAddress); + if (FAILED(hr)) { + return NDConvertWVStatus(hr); + } + + hr = m_pWvProvider->OpenDevice(m_DevAddress.DeviceGuid, &m_pWvDevice); + if (FAILED(hr)) { + return NDConvertWVStatus(hr); + } + + hr = m_pWvDevice->AllocateProtectionDomain(&m_pWvPd); + if (FAILED(hr)) { + return NDConvertWVStatus(hr); + } + + RtlCopyMemory(&m_Address, pAddress, AddressLength); + return ND_SUCCESS; +} + +CNDAdapter::~CNDAdapter(void) +{ + ND_MR *mr; + + while (!DListEmpty(&m_MrList)) { + mr = CONTAINING_RECORD(m_MrList.Next, ND_MR, Entry); + DListRemove(&mr->Entry); + m_pWvPd->DeregisterMemory(mr->Keys.Lkey, NULL); + delete mr; + } + + if (m_pWvPd != NULL) { + m_pWvPd->Release(); + } + if (m_pWvDevice != NULL) { + m_pWvDevice->Release(); + } + if (m_pWvProvider != NULL) { + m_pWvProvider->Release(); + } + m_pProvider->Release(); + DeleteCriticalSection(&m_Lock); +} + +STDMETHODIMP CNDAdapter:: +QueryInterface(REFIID riid, LPVOID FAR* ppvObj) +{ + if (riid != IID_IUnknown && riid != IID_INDAdapter) { + *ppvObj = NULL; + return E_NOINTERFACE; + } + + *ppvObj = this; + AddRef(); + return ND_SUCCESS; +} + +STDMETHODIMP_(ULONG) CNDAdapter:: +AddRef(void) +{ + return CNDBase::AddRef(); +} + +STDMETHODIMP_(ULONG) CNDAdapter:: +Release(void) +{ + return CNDBase::Release(); +} + +STDMETHODIMP CNDAdapter:: +CancelOverlappedRequests(void) +{ + m_pWvPd->CancelOverlappedRequests(); + return ND_SUCCESS; +} + +STDMETHODIMP CNDAdapter:: +GetOverlappedResult(OVERLAPPED *pOverlapped, + SIZE_T *pNumberOfBytesTransferred, BOOL bWait) +{ + DLIST_ENTRY *entry; + ND_MR *mr; + HRESULT hr; + + ::GetOverlappedResult(GetFileHandle(), pOverlapped, + (LPDWORD) pNumberOfBytesTransferred, bWait); + hr = (HRESULT) pOverlapped->Internal; + + if (FAILED(hr)) { + EnterCriticalSection(&m_Lock); + for (entry = m_MrList.Next; entry != &m_MrList; entry = entry->Next) { + mr = CONTAINING_RECORD(entry, ND_MR, Entry); + if (mr->Context == pOverlapped) { + DListRemove(entry); + delete mr; + break; + } + } + LeaveCriticalSection(&m_Lock); + } + + return NDConvertWVStatus(hr); +} + +STDMETHODIMP_(HANDLE) CNDAdapter:: +GetFileHandle(void) +{ + return m_pWvProvider->GetFileHandle(); +} + +STDMETHODIMP CNDAdapter:: +Query(DWORD VersionRequested, ND_ADAPTER_INFO* pInfo, SIZE_T* pBufferSize) +{ + WV_DEVICE_ATTRIBUTES attr; + HRESULT hr; + + if (VersionRequested != 1) { + return ND_NOT_SUPPORTED; + } + + if (*pBufferSize < sizeof(ND_ADAPTER_INFO)) { + hr = ND_BUFFER_OVERFLOW; + goto out; + } + + hr = m_pWvDevice->Query(&attr); + if (FAILED(hr)) { + goto out; + } + + pInfo->VendorId = attr.VendorId; + pInfo->DeviceId = attr.VendorPartId; + pInfo->MaxInboundSge = min(attr.MaxSge, ND_MAX_SGE); + pInfo->MaxInboundRequests = attr.MaxQpWr; + pInfo->MaxInboundLength = 1 << 31; + pInfo->MaxOutboundSge = min(attr.MaxSge, ND_MAX_SGE); + pInfo->MaxOutboundRequests = attr.MaxQpWr; + pInfo->MaxOutboundLength = 1 << 31; + pInfo->MaxInlineData = attr.MaxInlineSend; + pInfo->MaxInboundReadLimit = attr.MaxQpResponderResources; + pInfo->MaxOutboundReadLimit = attr.MaxQpInitiatorDepth; + pInfo->MaxCqEntries = attr.MaxCqEntries; + pInfo->MaxRegistrationSize = attr.MaxMrSize; + pInfo->MaxWindowSize = attr.MaxMrSize; + pInfo->LargeRequestThreshold = 0; + pInfo->MaxCallerData = ND_PRIVATE_DATA_SIZE; + pInfo->MaxCalleeData = ND_PRIVATE_DATA_SIZE; + +out: + *pBufferSize = sizeof(ND_ADAPTER_INFO); + return NDConvertWVStatus(hr); +} + +STDMETHODIMP CNDAdapter:: +Control(DWORD IoControlCode, const void* pInBuffer, SIZE_T InBufferSize, + void* pOutBuffer, SIZE_T OutBufferSize, SIZE_T* pBytesReturned, + OVERLAPPED* pOverlapped) +{ + return DeviceIoControl(GetFileHandle(), IoControlCode, + (LPVOID) pInBuffer, (DWORD) InBufferSize, + pOutBuffer, (DWORD) OutBufferSize, + (LPDWORD) pBytesReturned, pOverlapped) ? + ND_SUCCESS : HRESULT_FROM_WIN32(GetLastError()); +} + +STDMETHODIMP CNDAdapter:: +CreateCompletionQueue(SIZE_T nEntries, INDCompletionQueue** ppCq) +{ + return CNDCompletionQueue::CreateInstance(this, nEntries, ppCq); +} + +STDMETHODIMP CNDAdapter:: +RegisterMemory(const void* pBuffer, SIZE_T BufferSize, + OVERLAPPED* pOverlapped, ND_MR_HANDLE* phMr) +{ + ND_MR *mr; + HRESULT hr; + DWORD flags; + + mr = new ND_MR; + if (mr == NULL) { + return ND_NO_MEMORY; + } + + mr->Context = pOverlapped; + EnterCriticalSection(&m_Lock); + DListInsertHead(&mr->Entry, &m_MrList); + LeaveCriticalSection(&m_Lock); + + // TODO: restrict access when MWs are implemented + flags = WV_ACCESS_REMOTE_READ | WV_ACCESS_REMOTE_WRITE | + WV_ACCESS_REMOTE_ATOMIC | WV_ACCESS_LOCAL_WRITE | WV_ACCESS_MW_BIND; + hr = m_pWvPd->RegisterMemory(pBuffer, BufferSize, flags, pOverlapped, &mr->Keys); + if (SUCCEEDED(hr) || hr == WV_IO_PENDING) { + *phMr = (ND_MR_HANDLE) mr; + } else { + CleanupMr(mr); + } + + return NDConvertWVStatus(hr); +} + +STDMETHODIMP CNDAdapter:: +DeregisterMemory(ND_MR_HANDLE hMr, OVERLAPPED* pOverlapped) +{ + ND_MR *mr; + HRESULT hr; + + mr = (ND_MR *) hMr; + hr = m_pWvPd->DeregisterMemory(mr->Keys.Lkey, pOverlapped); + if (SUCCEEDED(hr) || hr == WV_IO_PENDING) { + CleanupMr(mr); + } + return NDConvertWVStatus(hr); +} + +void CNDAdapter:: +CleanupMr(ND_MR *pMr) +{ + EnterCriticalSection(&m_Lock); + DListRemove(&pMr->Entry); + LeaveCriticalSection(&m_Lock); + delete pMr; +} + +STDMETHODIMP CNDAdapter:: +CreateMemoryWindow(ND_RESULT* pInvalidateResult, INDMemoryWindow** ppMw) +{ + // TODO: do something with pInvalidateResult + return CNDMemoryWindow::CreateInstance(this, ppMw); +} + +STDMETHODIMP CNDAdapter:: +CreateConnector(INDConnector** ppConnector) +{ + return CNDConnector::CreateInstance(this, ppConnector); +} + +STDMETHODIMP CNDAdapter:: +Listen(SIZE_T Backlog, INT Protocol, USHORT Port, + USHORT* pAssignedPort, INDListen** ppListen) +{ + return CNDListen::CreateInstance(this, Backlog, Protocol, Port, + pAssignedPort, ppListen); +} diff --git a/branches/WOF2-3/ulp/netdirect/user/nd_adapter.h b/branches/WOF2-3/ulp/netdirect/user/nd_adapter.h new file mode 100644 index 00000000..01919584 --- /dev/null +++ b/branches/WOF2-3/ulp/netdirect/user/nd_adapter.h @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#ifndef _ND_ADAPTER_H_ +#define _ND_ADAPTER_H_ + +#include +#include "nd_base.h" +#include "nd_provider.h" +#include + + +typedef struct _ND_MR +{ + DLIST_ENTRY Entry; + WV_MEMORY_KEYS Keys; + void *Context; + +} ND_MR; + + +class CNDAdapter : public INDAdapter, public CNDBase +{ +public: + // IUnknown methods + STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + // INDOverlapped methods + STDMETHODIMP CancelOverlappedRequests(); + STDMETHODIMP GetOverlappedResult(OVERLAPPED *pOverlapped, + SIZE_T *pNumberOfBytesTransferred, BOOL bWait); + + // INDDevice methods + STDMETHODIMP_(HANDLE) GetFileHandle(); + STDMETHODIMP Query(DWORD VersionRequested, ND_ADAPTER_INFO* pInfo, + SIZE_T* pBufferSize); + STDMETHODIMP Control(DWORD IoControlCode, + const void* pInBuffer, SIZE_T InBufferSize, + void* pOutBuffer, SIZE_T OutBufferSize, + SIZE_T* pBytesReturned, OVERLAPPED* pOverlapped); + STDMETHODIMP CreateCompletionQueue(SIZE_T nEntries, INDCompletionQueue** ppCq); + STDMETHODIMP RegisterMemory(const void* pBuffer, SIZE_T BufferSize, + OVERLAPPED* pOverlapped, ND_MR_HANDLE* phMr); + STDMETHODIMP DeregisterMemory(ND_MR_HANDLE hMr, OVERLAPPED* pOverlapped); + STDMETHODIMP CreateMemoryWindow(ND_RESULT* pInvalidateResult, + INDMemoryWindow** ppMw); + STDMETHODIMP CreateConnector(INDConnector** ppConnector); + STDMETHODIMP Listen(SIZE_T Backlog, INT Protocol, USHORT Port, + USHORT* pAssignedPort, INDListen** ppListen); + + CNDAdapter(CNDProvider *pProvider); + ~CNDAdapter(); + void Delete() {delete this;} + static STDMETHODIMP + CreateInstance(CNDProvider *pProvider, const struct sockaddr *pAddress, + SIZE_T AddressLength, INDAdapter** ppAdapter) + { + HRESULT hr; + CNDAdapter *adapter; + + adapter = new CNDAdapter(pProvider); + if (adapter == NULL) { + hr = ND_NO_MEMORY; + goto err1; + } + + hr = adapter->Init(pAddress, AddressLength); + if (FAILED(hr)) { + goto err2; + } + + *ppAdapter = adapter; + return ND_SUCCESS; + + err2: + adapter->Release(); + err1: + *ppAdapter = NULL; + return hr; + } + + IWVProvider *m_pWvProvider; + IWVDevice *m_pWvDevice; + IWVProtectionDomain *m_pWvPd; + SOCKADDR_STORAGE m_Address; + WV_DEVICE_ADDRESS m_DevAddress; + +protected: + CNDProvider *m_pProvider; + DLIST_ENTRY m_MrList; + CRITICAL_SECTION m_Lock; + + STDMETHODIMP Init(const struct sockaddr *pAddress, SIZE_T AddressLength); + void CleanupMr(ND_MR *pMr); +}; + +#endif // _ND_ADAPTER_H_ diff --git a/branches/WOF2-3/ulp/netdirect/user/nd_base.cpp b/branches/WOF2-3/ulp/netdirect/user/nd_base.cpp new file mode 100644 index 00000000..5dfaf114 --- /dev/null +++ b/branches/WOF2-3/ulp/netdirect/user/nd_base.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "nd_base.h" +#include + +CNDBase::CNDBase() +{ + m_nRef = 1; +} + +STDMETHODIMP_(ULONG) CNDBase:: +AddRef(void) +{ + return InterlockedIncrement(&m_nRef); +} + +STDMETHODIMP_(ULONG) CNDBase:: +Release(void) +{ + ULONG ref; + + ref = (ULONG) InterlockedDecrement(&m_nRef); + if (ref == 0) { + Delete(); + } + return ref; +} + +HRESULT NDConvertWVStatus(HRESULT hr) +{ + switch (hr) { + case WV_IO_PENDING: + return ND_PENDING; + default: + return hr; + } +} diff --git a/branches/WOF2-3/ulp/netdirect/user/nd_base.h b/branches/WOF2-3/ulp/netdirect/user/nd_base.h new file mode 100644 index 00000000..d11b1a0e --- /dev/null +++ b/branches/WOF2-3/ulp/netdirect/user/nd_base.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#ifndef _ND_BASE_H_ +#define _ND_BASE_H_ + +#include +#include +#include + +class CNDBase +{ +public: + CNDBase(); + ~CNDBase() {}; + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + virtual void Delete() {}; + + volatile LONG m_nRef; + +protected: +}; + +__inline void* __cdecl operator new(size_t size) +{ + return HeapAlloc(GetProcessHeap(), 0, size); +} + +__inline void __cdecl operator delete(void *pObj) +{ + HeapFree(GetProcessHeap(), 0, pObj); +} + +HRESULT NDConvertWVStatus(HRESULT hr); + +#endif // _ND_BASE_H_ diff --git a/branches/WOF2-3/ulp/netdirect/user/nd_connect.cpp b/branches/WOF2-3/ulp/netdirect/user/nd_connect.cpp new file mode 100644 index 00000000..3042530d --- /dev/null +++ b/branches/WOF2-3/ulp/netdirect/user/nd_connect.cpp @@ -0,0 +1,324 @@ +/* + * Copyright (c) 2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION 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 "nd_connect.h" +#include "nd_ep.h" +#include + + +CNDConnector::CNDConnector(CNDAdapter *pAdapter) +{ + pAdapter->AddRef(); + m_pAdapter = pAdapter; + m_pWvConnEp = NULL; + m_Connects = 0; +} + +STDMETHODIMP CNDConnector:: +Init(void) +{ + IWVConnectEndpoint *ep; + HRESULT hr; + + hr = m_pAdapter->m_pWvProvider->CreateConnectEndpoint(&ep); + if (FAILED(hr)) { + return NDConvertWVStatus(hr); + } + + if (m_pWvConnEp != NULL) { + m_pWvConnEp->Release(); + } + + m_pWvConnEp = ep; + return ND_SUCCESS; +} + +CNDConnector::~CNDConnector() +{ + if (m_pWvConnEp != NULL) { + m_pWvConnEp->Release(); + } + m_pAdapter->Release(); +} + +STDMETHODIMP CNDConnector:: +QueryInterface(REFIID riid, LPVOID FAR* ppvObj) +{ + if (riid != IID_IUnknown && riid != IID_INDConnector) { + *ppvObj = NULL; + return E_NOINTERFACE; + } + + *ppvObj = this; + AddRef(); + return ND_SUCCESS; +} + +STDMETHODIMP_(ULONG) CNDConnector:: +AddRef(void) +{ + return CNDBase::AddRef(); +} + +STDMETHODIMP_(ULONG) CNDConnector:: +Release(void) +{ + return CNDBase::Release(); +} + +STDMETHODIMP CNDConnector:: +CancelOverlappedRequests(void) +{ + HRESULT hr; + + hr = m_pWvConnEp->CancelOverlappedRequests(); + return NDConvertWVStatus(hr); +} + +STDMETHODIMP CNDConnector:: +GetOverlappedResult(OVERLAPPED *pOverlapped, + SIZE_T *pNumberOfBytesTransferred, BOOL bWait) +{ + HRESULT hr; + + hr = m_pWvConnEp->GetOverlappedResult(pOverlapped, + (DWORD *) pNumberOfBytesTransferred, + bWait); + return NDConvertWVStatus(hr); +} + +STDMETHODIMP CNDConnector:: +CreateEndpoint(INDCompletionQueue* pInboundCq, INDCompletionQueue* pOutboundCq, + SIZE_T nInboundEntries, SIZE_T nOutboundEntries, + SIZE_T nInboundSge, SIZE_T nOutboundSge, + SIZE_T InboundReadLimit, SIZE_T OutboundReadLimit, + SIZE_T* pMaxInlineData, INDEndpoint** ppEndpoint) +{ + CNDCompletionQueue *incq = (CNDCompletionQueue *) pInboundCq; + CNDCompletionQueue *outcq = (CNDCompletionQueue *) pOutboundCq; + + return CNDEndpoint::CreateInstance(this, incq, outcq, + nInboundEntries, nOutboundEntries, + nInboundSge, nOutboundSge, + InboundReadLimit, OutboundReadLimit, + pMaxInlineData, ppEndpoint); +} + +STDMETHODIMP CNDConnector:: +Connect(INDEndpoint* pEndpoint, + const struct sockaddr* pAddress, SIZE_T AddressLength, + INT Protocol, USHORT LocalPort, + const void* pPrivateData, SIZE_T PrivateDataLength, + OVERLAPPED* pOverlapped) +{ + CNDEndpoint *ep = (CNDEndpoint *) pEndpoint; + WV_SOCKADDR addr; + WV_CONNECT_PARAM attr; + IBAT_PATH_BLOB path; + HRESULT hr; + + if (m_Connects++ > 0) { + hr = Init(); + if (FAILED(hr)) { + goto out; + } + } + + RtlCopyMemory(&addr, &m_pAdapter->m_Address, AddressLength); + if (addr.Sa.sa_family == AF_INET) { + addr.Sin.sin_port = LocalPort; + } else { + addr.Sin6.sin6_port = LocalPort; + } + + hr = IBAT::ResolvePath(&addr.Sa, pAddress, &path, INFINITE); + if (FAILED(hr)) { + goto out; + } + + hr = m_pWvConnEp->BindAddress(&addr.Sa); + if (FAILED(hr)) { + goto out; + } + + hr = m_pWvConnEp->Modify(WV_EP_OPTION_ROUTE, &path, sizeof path); + if (FAILED(hr)) { + goto out; + } + + RtlZeroMemory(&attr, sizeof attr); + if ((attr.DataLength = PrivateDataLength)) { + RtlCopyMemory(attr.Data, pPrivateData, PrivateDataLength); + } + attr.ResponderResources = ep->m_ResponderResources; + attr.InitiatorDepth = ep->m_InitiatorDepth; + attr.RetryCount = 7; + + hr = m_pWvConnEp->Connect(ep->m_pWvQp, pAddress, &attr, pOverlapped); +out: + return NDConvertWVStatus(hr); +} + +STDMETHODIMP CNDConnector:: +CompleteConnect(OVERLAPPED* pOverlapped) +{ + WV_CONNECT_PARAM attr; + HRESULT hr; + + RtlZeroMemory(&attr, sizeof attr); + hr = m_pWvConnEp->Accept(NULL, &attr, pOverlapped); + return NDConvertWVStatus(hr); +} + +STDMETHODIMP CNDConnector:: +Accept(INDEndpoint* pEndpoint, + const void* pPrivateData, SIZE_T PrivateDataLength, + OVERLAPPED* pOverlapped) +{ + CNDEndpoint *ep = (CNDEndpoint *) pEndpoint; + WV_CONNECT_PARAM attr; + HRESULT hr; + + RtlZeroMemory(&attr, sizeof attr); + if ((attr.DataLength = PrivateDataLength)) { + RtlCopyMemory(attr.Data, pPrivateData, PrivateDataLength); + } + attr.ResponderResources = ep->m_ResponderResources; + attr.InitiatorDepth = ep->m_InitiatorDepth; + + hr = m_pWvConnEp->Accept(ep->m_pWvQp, &attr, pOverlapped); + return NDConvertWVStatus(hr); +} + +STDMETHODIMP CNDConnector:: +Reject(const void* pPrivateData, SIZE_T PrivateDataLength) +{ + HRESULT hr; + + hr = m_pWvConnEp->Reject(pPrivateData, PrivateDataLength); + return NDConvertWVStatus(hr); +} + +STDMETHODIMP CNDConnector:: +GetConnectionData(SIZE_T* pInboundReadLimit, SIZE_T* pOutboundReadLimit, + void* pPrivateData, SIZE_T* pPrivateDataLength) +{ + WV_CONNECT_ATTRIBUTES attr; + HRESULT hr; + + hr = m_pWvConnEp->Query(&attr); + if (FAILED(hr)) { + return NDConvertWVStatus(hr); + } + + if (pInboundReadLimit) { + *pInboundReadLimit = attr.Param.ResponderResources; + } + if (pOutboundReadLimit) { + *pOutboundReadLimit = attr.Param.InitiatorDepth; + } + if (pPrivateDataLength) { + if (*pPrivateDataLength < ND_PRIVATE_DATA_SIZE) { + hr = ND_BUFFER_OVERFLOW; + } + + RtlCopyMemory(pPrivateData, attr.Param.Data, + min(*pPrivateDataLength, ND_PRIVATE_DATA_SIZE)); + *pPrivateDataLength = ND_PRIVATE_DATA_SIZE; + } + + return hr; +} + +static SIZE_T GetAddressSize(WV_SOCKADDR *addr) +{ + return (addr->Sa.sa_family == AF_INET) ? sizeof(addr->Sin) : sizeof(addr->Sin6); +} + +STDMETHODIMP CNDConnector:: +GetLocalAddress(struct sockaddr* pAddress, SIZE_T* pAddressLength) +{ + WV_CONNECT_ATTRIBUTES attr; + HRESULT hr; + + hr = m_pWvConnEp->Query(&attr); + if (FAILED(hr)) { + return NDConvertWVStatus(hr); + } + + if (*pAddressLength < GetAddressSize(&attr.LocalAddress)) { + hr = ND_BUFFER_OVERFLOW; + goto out; + } + + RtlCopyMemory(pAddress, &attr.LocalAddress, GetAddressSize(&attr.LocalAddress)); +out: + *pAddressLength = GetAddressSize(&attr.LocalAddress); + return NDConvertWVStatus(hr); +} + +STDMETHODIMP CNDConnector:: +GetPeerAddress(struct sockaddr* pAddress, SIZE_T* pAddressLength) +{ + WV_CONNECT_ATTRIBUTES attr; + HRESULT hr; + + hr = m_pWvConnEp->Query(&attr); + if (FAILED(hr)) { + return NDConvertWVStatus(hr); + } + + if (*pAddressLength < GetAddressSize(&attr.PeerAddress)) { + hr = ND_BUFFER_OVERFLOW; + goto out; + } + + RtlCopyMemory(pAddress, &attr.PeerAddress, GetAddressSize(&attr.PeerAddress)); +out: + *pAddressLength = GetAddressSize(&attr.PeerAddress); + return NDConvertWVStatus(hr); +} + +STDMETHODIMP CNDConnector:: +NotifyDisconnect(OVERLAPPED* pOverlapped) +{ + HRESULT hr; + + hr = m_pWvConnEp->NotifyDisconnect(pOverlapped); + return NDConvertWVStatus(hr); +} + +STDMETHODIMP CNDConnector:: +Disconnect(OVERLAPPED* pOverlapped) +{ + HRESULT hr; + + hr = m_pWvConnEp->Disconnect(pOverlapped); + return NDConvertWVStatus(hr); +} diff --git a/branches/WOF2-3/ulp/netdirect/user/nd_connect.h b/branches/WOF2-3/ulp/netdirect/user/nd_connect.h new file mode 100644 index 00000000..688fedc7 --- /dev/null +++ b/branches/WOF2-3/ulp/netdirect/user/nd_connect.h @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#ifndef _ND_CONNECTOR_H_ +#define _ND_CONNECTOR_H_ + +#include +#include +#include "nd_base.h" +#include "nd_adapter.h" + + +#define ND_PRIVATE_DATA_SIZE 56 + + +class CNDConnector : public INDConnector, public CNDBase +{ +public: + // IUnknown methods + STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + // INDOverlapped methods + STDMETHODIMP CancelOverlappedRequests(); + STDMETHODIMP GetOverlappedResult(OVERLAPPED *pOverlapped, + SIZE_T *pNumberOfBytesTransferred, BOOL bWait); + + // INDConnector methods + STDMETHODIMP CreateEndpoint(INDCompletionQueue* pInboundCq, + INDCompletionQueue* pOutboundCq, + SIZE_T nInboundEntries, SIZE_T nOutboundEntries, + SIZE_T nInboundSge, SIZE_T nOutboundSge, + SIZE_T InboundReadLimit, SIZE_T OutboundReadLimit, + SIZE_T* pMaxInlineData, INDEndpoint** ppEndpoint); + STDMETHODIMP Connect(INDEndpoint* pEndpoint, + const struct sockaddr* pAddress, SIZE_T AddressLength, + INT Protocol, USHORT LocalPort, + const void* pPrivateData, SIZE_T PrivateDataLength, + OVERLAPPED* pOverlapped); + STDMETHODIMP CompleteConnect(OVERLAPPED* pOverlapped); + STDMETHODIMP Accept(INDEndpoint* pEndpoint, + const void* pPrivateData, SIZE_T PrivateDataLength, + OVERLAPPED* pOverlapped); + STDMETHODIMP Reject(const void* pPrivateData, SIZE_T PrivateDataLength); + STDMETHODIMP GetConnectionData(SIZE_T* pInboundReadLimit, + SIZE_T* pOutboundReadLimit, + void* pPrivateData, SIZE_T* pPrivateDataLength); + STDMETHODIMP GetLocalAddress(struct sockaddr* pAddress, SIZE_T* pAddressLength); + STDMETHODIMP GetPeerAddress(struct sockaddr* pAddress, SIZE_T* pAddressLength); + STDMETHODIMP NotifyDisconnect(OVERLAPPED* pOverlapped); + STDMETHODIMP Disconnect(OVERLAPPED* pOverlapped); + + CNDConnector(CNDAdapter *pAdapter); + ~CNDConnector(); + void Delete() {delete this;} + static STDMETHODIMP + CreateInstance(CNDAdapter *pAdapter, INDConnector** ppConnector) + { + HRESULT hr; + CNDConnector *conn; + + conn = new CNDConnector(pAdapter); + if (conn == NULL) { + hr = ND_NO_MEMORY; + goto err1; + } + + hr = conn->Init(); + if (FAILED(hr)) { + goto err2; + } + + *ppConnector = conn; + return ND_SUCCESS; + + err2: + conn->Release(); + err1: + *ppConnector = NULL; + return hr; + } + + IWVConnectEndpoint *m_pWvConnEp; + CNDAdapter *m_pAdapter; + +protected: + STDMETHODIMP Init(); + int m_Connects; +}; + +#endif // _ND_CONNECTOR_H_ diff --git a/branches/WOF2-3/ulp/netdirect/user/nd_cq.cpp b/branches/WOF2-3/ulp/netdirect/user/nd_cq.cpp new file mode 100644 index 00000000..07dabc23 --- /dev/null +++ b/branches/WOF2-3/ulp/netdirect/user/nd_cq.cpp @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION 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 "nd_cq.h" + +CNDCompletionQueue::CNDCompletionQueue(CNDAdapter *pAdapter) +{ + pAdapter->AddRef(); + m_pAdapter = pAdapter; + m_pWvCq = NULL; +} + +STDMETHODIMP CNDCompletionQueue:: +Init(SIZE_T nEntries) +{ + HRESULT hr; + + hr = m_pAdapter->m_pWvDevice->CreateCompletionQueue(&nEntries, &m_pWvCq); + return NDConvertWVStatus(hr); +} + +CNDCompletionQueue::~CNDCompletionQueue() +{ + if (m_pWvCq != NULL) { + m_pWvCq->Release(); + } + m_pAdapter->Release(); +} + +STDMETHODIMP CNDCompletionQueue:: +QueryInterface(REFIID riid, LPVOID FAR* ppvObj) +{ + if (riid != IID_IUnknown && riid != IID_INDCompletionQueue) { + *ppvObj = NULL; + return E_NOINTERFACE; + } + + *ppvObj = this; + AddRef(); + return ND_SUCCESS; +} + +STDMETHODIMP_(ULONG) CNDCompletionQueue:: +AddRef(void) +{ + return CNDBase::AddRef(); +} + +STDMETHODIMP_(ULONG) CNDCompletionQueue:: +Release(void) +{ + return CNDBase::Release(); +} + +STDMETHODIMP CNDCompletionQueue:: +CancelOverlappedRequests(void) +{ + HRESULT hr; + + hr = m_pWvCq->CancelOverlappedRequests(); + return NDConvertWVStatus(hr); +} + +STDMETHODIMP CNDCompletionQueue:: +GetOverlappedResult(OVERLAPPED *pOverlapped, + SIZE_T *pNumberOfBytesTransferred, BOOL bWait) +{ + HRESULT hr; + + hr = m_pWvCq->GetOverlappedResult(pOverlapped, + (DWORD *) pNumberOfBytesTransferred, bWait); + return NDConvertWVStatus(hr); +} + +STDMETHODIMP CNDCompletionQueue:: +Resize(SIZE_T nEntries) +{ + HRESULT hr; + + hr = m_pWvCq->Resize(&nEntries); + return NDConvertWVStatus(hr); +} + +STDMETHODIMP CNDCompletionQueue:: +Notify(DWORD Type, OVERLAPPED* pOverlapped) +{ + HRESULT hr; + + hr = m_pWvCq->Notify((WV_CQ_NOTIFY_TYPE) Type, pOverlapped); + return NDConvertWVStatus(hr); +} + +STDMETHODIMP_(HRESULT) CNDCompletionQueue:: +ConvertStatus(WV_WC_STATUS Status) +{ + switch (Status) { + case WvWcSuccess: + return ND_SUCCESS; + case WvWcFlushed: + return ND_CANCELED; + case WvWcLocalLengthError: + return ND_LOCAL_LENGTH; + case WvWcRnrRetryError: + case WvWcTimeoutRetryError: + return ND_TIMEOUT; + case WvWcLocalAccessError: + case WvWcLocalOpError: + case WvWcLocalProtectionError: + case WvWcMwBindError: + return ND_ACCESS_VIOLATION; + case WvWcRemoteAccessError: + case WvWcRemoteOpError: + case WvWcRemoteInvalidRequest: + case WvWcBadResponse: + return ND_REMOTE_ERROR; + default: + return ND_INTERNAL_ERROR; + } +} + +STDMETHODIMP_(SIZE_T) CNDCompletionQueue:: +GetResults(ND_RESULT* pResults[], SIZE_T nResults) +{ + WV_COMPLETION comp[8]; + SIZE_T cnt, total, i; + + for (total = 0; nResults; nResults -= cnt) { + cnt = min(8, nResults); + cnt = m_pWvCq->Poll(comp, cnt); + if (cnt == 0) { + break; + } + + for (i = 0; i < cnt; i++) { + pResults[total] = (ND_RESULT *) comp[i].WrId; + if (comp[i].Opcode & WvReceive) { + pResults[total]->BytesTransferred = comp[i].Length; + } + pResults[total++]->Status = ConvertStatus(comp[i].Status); + } + } + return total; +} diff --git a/branches/WOF2-3/ulp/netdirect/user/nd_cq.h b/branches/WOF2-3/ulp/netdirect/user/nd_cq.h new file mode 100644 index 00000000..06c4d6c4 --- /dev/null +++ b/branches/WOF2-3/ulp/netdirect/user/nd_cq.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#ifndef _ND_CQ_H_ +#define _ND_CQ_H_ + +#include +#include +#include "nd_base.h" +#include "nd_adapter.h" + +class CNDCompletionQueue : public INDCompletionQueue, public CNDBase +{ +public: + // IUnknown methods + STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + // INDOverlapped methods + STDMETHODIMP CancelOverlappedRequests(); + STDMETHODIMP GetOverlappedResult(OVERLAPPED *pOverlapped, + SIZE_T *pNumberOfBytesTransferred, BOOL bWait); + + // INDCompletionQueue methods + STDMETHODIMP Resize(SIZE_T nEntries); + STDMETHODIMP Notify(DWORD Type, OVERLAPPED* pOverlapped); + STDMETHODIMP_(SIZE_T) GetResults(ND_RESULT* pResults[], SIZE_T nResults); + + CNDCompletionQueue(CNDAdapter *pAdapter); + ~CNDCompletionQueue(); + void Delete() {delete this;} + static STDMETHODIMP + CreateInstance(CNDAdapter *pAdapter, SIZE_T nEntries, INDCompletionQueue** ppCq) + { + HRESULT hr; + CNDCompletionQueue *cq; + + cq = new CNDCompletionQueue(pAdapter); + if (cq == NULL) { + hr = ND_NO_MEMORY; + goto err1; + } + + hr = cq->Init(nEntries); + if (FAILED(hr)) { + goto err2; + } + + *ppCq = cq; + return ND_SUCCESS; + + err2: + cq->Release(); + err1: + *ppCq = NULL; + return hr; + } + + IWVCompletionQueue *m_pWvCq; + +protected: + CNDAdapter *m_pAdapter; + STDMETHODIMP Init(SIZE_T nEntries); + STDMETHODIMP_(HRESULT) ConvertStatus(WV_WC_STATUS Status); +}; + +#endif // _ND_CQ_H_ diff --git a/branches/WOF2-3/ulp/netdirect/user/nd_ep.cpp b/branches/WOF2-3/ulp/netdirect/user/nd_ep.cpp new file mode 100644 index 00000000..7060b208 --- /dev/null +++ b/branches/WOF2-3/ulp/netdirect/user/nd_ep.cpp @@ -0,0 +1,318 @@ +/* + * Copyright (c) 2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION 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 "nd_ep.h" +#include "nd_adapter.h" +#include "nd_connect.h" +#include "nd_cq.h" +#include "nd_mw.h" +#include + + +CNDEndpoint::CNDEndpoint(CNDConnector *pConnector) +{ + pConnector->AddRef(); + m_pConnector = pConnector; + m_pWvQp = NULL; + m_pInboundCq = NULL; + m_pOutboundCq = NULL; +} + +STDMETHODIMP_(void) CNDEndpoint:: +InitMaxInline(void) +{ + TCHAR val[16]; + DWORD ret; + + ret = GetEnvironmentVariable("IBNDPROV_MAX_INLINE_SIZE", val, 16); + m_MaxInlineSend = (ret > 0 && ret <= 16) ? (SIZE_T) strtoul(val, NULL, 16) : 160; +} + +STDMETHODIMP CNDEndpoint:: +Init(CNDCompletionQueue* pInboundCq, CNDCompletionQueue* pOutboundCq, + SIZE_T nInboundEntries, SIZE_T nOutboundEntries, + SIZE_T nInboundSge, SIZE_T nOutboundSge, + SIZE_T InboundReadLimit, SIZE_T OutboundReadLimit, + SIZE_T* pMaxInlineData) +{ + WV_QP_CREATE create; + WV_QP_ATTRIBUTES attr; + WV_DEVICE_ADDRESS *addr; + DWORD opts; + HRESULT hr; + + m_pInboundCq = pInboundCq; + m_pOutboundCq = pOutboundCq; + m_pInboundCq->AddRef(); + m_pOutboundCq->AddRef(); + m_InitiatorDepth = OutboundReadLimit; + m_ResponderResources = InboundReadLimit; + InitMaxInline(); + + RtlZeroMemory(&create, sizeof create); + create.pSendCq = pOutboundCq->m_pWvCq; + create.pReceiveCq = pInboundCq->m_pWvCq; + create.Context = this; + create.SendDepth = nOutboundEntries; + create.SendSge = nOutboundSge; + create.ReceiveDepth = nInboundEntries; + create.ReceiveSge = nInboundSge; + create.InitiatorDepth = OutboundReadLimit; + create.ResponderResources = InboundReadLimit; + create.MaxInlineSend = m_MaxInlineSend; + create.QpType = WvQpTypeRc; + + hr = m_pConnector->m_pAdapter->m_pWvPd->CreateConnectQueuePair(&create, &m_pWvQp); + if (FAILED(hr)) { + return NDConvertWVStatus(hr); + } + + opts = WV_QP_ATTR_STATE | WV_QP_ATTR_PORT_NUMBER | WV_QP_ATTR_PKEY_INDEX; + attr.QpState = WvQpStateInit; + addr = &m_pConnector->m_pAdapter->m_DevAddress; + attr.AddressVector.PortNumber = addr->PortNumber; + hr = m_pConnector->m_pAdapter->m_pWvDevice->FindPkey(addr->PortNumber, addr->Pkey, + &attr.PkeyIndex); + if (FAILED(hr)) { + return NDConvertWVStatus(hr); + } + + hr = m_pWvQp->Modify(&attr, opts, NULL); + if (FAILED(hr)) { + return NDConvertWVStatus(hr); + } + + if (pMaxInlineData) { + *pMaxInlineData = m_MaxInlineSend; + } + return ND_SUCCESS; +} + +CNDEndpoint::~CNDEndpoint() +{ + if (m_pWvQp != NULL) { + m_pWvQp->Release(); + } + if (m_pInboundCq != NULL) { + m_pInboundCq->Release(); + } + if (m_pOutboundCq != NULL) { + m_pOutboundCq->Release(); + } + m_pConnector->Release(); +} + +STDMETHODIMP CNDEndpoint:: +QueryInterface(REFIID riid, LPVOID FAR* ppvObj) +{ + if (riid != IID_IUnknown && riid != IID_INDEndpoint) { + *ppvObj = NULL; + return E_NOINTERFACE; + } + + *ppvObj = this; + AddRef(); + return ND_SUCCESS; +} + +STDMETHODIMP_(ULONG) CNDEndpoint:: +AddRef(void) +{ + return CNDBase::AddRef(); +} + +STDMETHODIMP_(ULONG) CNDEndpoint:: +Release(void) +{ + return CNDBase::Release(); +} + +STDMETHODIMP CNDEndpoint:: +Flush(void) +{ + return ND_SUCCESS; +} + +STDMETHODIMP_(void) CNDEndpoint:: +StartRequestBatch(void) +{ + // no-op +} + +STDMETHODIMP_(void) CNDEndpoint:: +SubmitRequestBatch(void) +{ + // no-op +} + +STDMETHODIMP_(SIZE_T) CNDEndpoint:: +ConvertSgl(const ND_SGE* pSgl, SIZE_T nSge, WV_SGE* pWvSgl) +{ + SIZE_T i, len = 0; + + for (i = 0; i < nSge; i++) { + pWvSgl[i].pAddress = pSgl[i].pAddr; + pWvSgl[i].Length = (UINT32) pSgl[i].Length; + len += pWvSgl[i].Length; + pWvSgl[i].Lkey = pSgl[i].hMr ? ((ND_MR *) pSgl[i].hMr)->Keys.Lkey : 0; + } + return len; +} + +STDMETHODIMP_(DWORD) CNDEndpoint:: +ConvertSendFlags(DWORD Flags) +{ + DWORD opts = 0; + + if (!(Flags & ND_OP_FLAG_SILENT_SUCCESS)) { + opts |= WV_SEND_SIGNALED; + } + if (Flags & ND_OP_FLAG_READ_FENCE) { + opts |= WV_SEND_FENCE; + } + if (Flags & ND_OP_FLAG_SEND_AND_SOLICIT_EVENT) { + opts |= WV_SEND_SOLICITED; + } + return opts; +} + +STDMETHODIMP_(DWORD) CNDEndpoint:: +ConvertAccessFlags(DWORD Flags) +{ + DWORD opts = 0; + + if (!(Flags & ND_OP_FLAG_ALLOW_READ)) { + opts |= WV_ACCESS_REMOTE_READ; + } + if (Flags & ND_OP_FLAG_ALLOW_WRITE) { + opts |= WV_ACCESS_REMOTE_WRITE; + } + return opts; +} + +STDMETHODIMP CNDEndpoint:: +Send(ND_RESULT* pResult, const ND_SGE* pSgl, SIZE_T nSge, DWORD Flags) +{ + WV_SGE sgl[ND_MAX_SGE]; + DWORD opts; + HRESULT hr; + + pResult->BytesTransferred = ConvertSgl(pSgl, nSge, sgl); + opts = ConvertSendFlags(Flags) | + (pResult->BytesTransferred <= m_MaxInlineSend ? WV_SEND_INLINE : 0); + hr = m_pWvQp->Send((UINT64) pResult, sgl, nSge, opts, 0); + return NDConvertWVStatus(hr); +} + +STDMETHODIMP CNDEndpoint:: +SendAndInvalidate(ND_RESULT* pResult, const ND_SGE* pSgl, SIZE_T nSge, + const ND_MW_DESCRIPTOR* pRemoteMwDescriptor, DWORD Flags) +{ + HRESULT hr; + + hr = Send(pResult, pSgl, nSge, Flags); + return NDConvertWVStatus(hr); +} + +STDMETHODIMP CNDEndpoint:: +Receive(ND_RESULT* pResult, const ND_SGE* pSgl, SIZE_T nSge) +{ + WV_SGE sgl[ND_MAX_SGE]; + HRESULT hr; + + ConvertSgl(pSgl, nSge, sgl); + hr = m_pWvQp->PostReceive((UINT64) pResult, sgl, nSge); + return NDConvertWVStatus(hr); +} + +STDMETHODIMP CNDEndpoint:: +Bind(ND_RESULT* pResult, ND_MR_HANDLE hMr, INDMemoryWindow* pMw, + const void* pBuffer, SIZE_T BufferSize, DWORD Flags, + ND_MW_DESCRIPTOR* pMwDescriptor) +{ + CNDMemoryWindow *mw = (CNDMemoryWindow *) pMw; + ND_MR *mr = (ND_MR *) hMr; + HRESULT hr; + + pResult->BytesTransferred = 0; + pMwDescriptor->Base = htonll((UINT64) (ULONG_PTR) pBuffer); + pMwDescriptor->Length = htonll(BufferSize); + pMwDescriptor->Token = mr->Keys.Rkey; + + hr = m_pWvQp->Write((UINT64) pResult, NULL, 0, ConvertSendFlags(Flags), + 0, 0, 0); + return NDConvertWVStatus(hr); +} + +STDMETHODIMP CNDEndpoint:: +Invalidate(ND_RESULT* pResult, INDMemoryWindow* pMw, DWORD Flags) +{ + HRESULT hr; + + pResult->BytesTransferred = 0; + hr = m_pWvQp->Write((UINT64) pResult, NULL, 0, ConvertSendFlags(Flags), + 0, 0, 0); + return NDConvertWVStatus(hr); +} + +STDMETHODIMP CNDEndpoint:: +Read(ND_RESULT* pResult, const ND_SGE* pSgl, SIZE_T nSge, + const ND_MW_DESCRIPTOR* pRemoteMwDescriptor, ULONGLONG Offset, DWORD Flags) +{ + WV_SGE sgl[ND_MAX_SGE]; + UINT64 addr; + DWORD opts; + HRESULT hr; + + pResult->BytesTransferred = ConvertSgl(pSgl, nSge, sgl); + opts = ConvertSendFlags(Flags) | + (pResult->BytesTransferred ? 0 : WV_SEND_INLINE); + addr = ntohll(pRemoteMwDescriptor->Base) + Offset; + hr = m_pWvQp->Read((UINT64) pResult, sgl, nSge, opts, + htonll(addr), pRemoteMwDescriptor->Token); + return NDConvertWVStatus(hr); +} + +STDMETHODIMP CNDEndpoint:: +Write(ND_RESULT* pResult, const ND_SGE* pSgl, SIZE_T nSge, + const ND_MW_DESCRIPTOR* pRemoteMwDescriptor, ULONGLONG Offset, DWORD Flags) +{ + WV_SGE sgl[ND_MAX_SGE]; + UINT64 addr; + DWORD opts; + HRESULT hr; + + pResult->BytesTransferred = ConvertSgl(pSgl, nSge, sgl); + opts = ConvertSendFlags(Flags) | + (pResult->BytesTransferred <= m_MaxInlineSend ? WV_SEND_INLINE : 0); + addr = ntohll(pRemoteMwDescriptor->Base) + Offset; + hr = m_pWvQp->Write((UINT64) pResult, sgl, nSge, opts, 0, + htonll(addr), pRemoteMwDescriptor->Token); + return NDConvertWVStatus(hr); +} diff --git a/branches/WOF2-3/ulp/netdirect/user/nd_ep.h b/branches/WOF2-3/ulp/netdirect/user/nd_ep.h new file mode 100644 index 00000000..78fac3fa --- /dev/null +++ b/branches/WOF2-3/ulp/netdirect/user/nd_ep.h @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#ifndef _ND_ENDPOINT_H_ +#define _ND_ENDPOINT_H_ + +#include +#include +#include "nd_base.h" +#include "nd_connect.h" +#include "nd_cq.h" +#include "nd_adapter.h" + + +#define ND_MAX_SGE 8 + + +class CNDEndpoint : public INDEndpoint, public CNDBase +{ +public: + // IUnknown methods + STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + // INDEndpoint methods + STDMETHODIMP Flush(); + STDMETHODIMP_(void) StartRequestBatch(); + STDMETHODIMP_(void) SubmitRequestBatch(); + STDMETHODIMP Send(ND_RESULT* pResult, const ND_SGE* pSgl, SIZE_T nSge, DWORD Flags); + STDMETHODIMP SendAndInvalidate(ND_RESULT* pResult, const ND_SGE* pSgl, SIZE_T nSge, + const ND_MW_DESCRIPTOR* pRemoteMwDescriptor, + DWORD Flags); + STDMETHODIMP Receive(ND_RESULT* pResult, const ND_SGE* pSgl, SIZE_T nSge); + STDMETHODIMP Bind(ND_RESULT* pResult, ND_MR_HANDLE hMr, INDMemoryWindow* pMw, + const void* pBuffer, SIZE_T BufferSize, DWORD Flags, + ND_MW_DESCRIPTOR* pMwDescriptor); + STDMETHODIMP Invalidate(ND_RESULT* pResult, INDMemoryWindow* pMw, DWORD Flags); + STDMETHODIMP Read(ND_RESULT* pResult, const ND_SGE* pSgl, SIZE_T nSge, + const ND_MW_DESCRIPTOR* pRemoteMwDescriptor, + ULONGLONG Offset, DWORD Flags); + STDMETHODIMP Write(ND_RESULT* pResult, const ND_SGE* pSgl, SIZE_T nSge, + const ND_MW_DESCRIPTOR* pRemoteMwDescriptor, + ULONGLONG Offset, DWORD Flags); + + CNDEndpoint(CNDConnector *pConnector); + ~CNDEndpoint(); + void Delete() {delete this;} + static STDMETHODIMP + CreateInstance(CNDConnector *pConnector, + CNDCompletionQueue* pInboundCq, CNDCompletionQueue* pOutboundCq, + SIZE_T nInboundEntries, SIZE_T nOutboundEntries, + SIZE_T nInboundSge, SIZE_T nOutboundSge, + SIZE_T InboundReadLimit, SIZE_T OutboundReadLimit, + SIZE_T* pMaxInlineData, INDEndpoint** ppEndpoint) + { + HRESULT hr; + CNDEndpoint *ep; + + ep = new CNDEndpoint(pConnector); + if (ep == NULL) { + hr = ND_NO_MEMORY; + goto err1; + } + + hr = ep->Init(pInboundCq, pOutboundCq, nInboundEntries, nOutboundEntries, + nInboundSge, nOutboundSge, InboundReadLimit, OutboundReadLimit, + pMaxInlineData); + if (FAILED(hr)) { + goto err2; + } + + *ppEndpoint = ep; + return ND_SUCCESS; + + err2: + ep->Release(); + err1: + *ppEndpoint = NULL; + return hr; + } + + IWVConnectQueuePair *m_pWvQp; + SIZE_T m_InitiatorDepth; + SIZE_T m_ResponderResources; + SIZE_T m_MaxInlineSend; + +protected: + CNDConnector *m_pConnector; + CNDCompletionQueue *m_pInboundCq; + CNDCompletionQueue *m_pOutboundCq; + + STDMETHODIMP Init(CNDCompletionQueue* pInboundCq, CNDCompletionQueue* pOutboundCq, + SIZE_T nInboundEntries, SIZE_T nOutboundEntries, + SIZE_T nInboundSge, SIZE_T nOutboundSge, + SIZE_T InboundReadLimit, SIZE_T OutboundReadLimit, + SIZE_T* pMaxInlineData); + STDMETHODIMP_(void) InitMaxInline(); + STDMETHODIMP_(SIZE_T) ConvertSgl(const ND_SGE* pSgl, SIZE_T nSge, WV_SGE *pWvSgl); + STDMETHODIMP_(DWORD) ConvertSendFlags(DWORD Flags); + STDMETHODIMP_(DWORD) ConvertAccessFlags(DWORD Flags); +}; + +#endif // _ND_ENDPOINT_H_ diff --git a/branches/WOF2-3/ulp/netdirect/user/nd_export.def b/branches/WOF2-3/ulp/netdirect/user/nd_export.def new file mode 100644 index 00000000..f02ae6f7 --- /dev/null +++ b/branches/WOF2-3/ulp/netdirect/user/nd_export.def @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#if _DEBUG_ +LIBRARY WVNDPROVD.DLL +#else +LIBRARY WVNDPROV.DLL +#endif + +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + WSPStartup diff --git a/branches/WOF2-3/ulp/netdirect/user/nd_exports.src b/branches/WOF2-3/ulp/netdirect/user/nd_exports.src new file mode 100644 index 00000000..042f3cdb --- /dev/null +++ b/branches/WOF2-3/ulp/netdirect/user/nd_exports.src @@ -0,0 +1,12 @@ +#if DBG +LIBRARY wvndprov.dll +#else +LIBRARY wvndprov.dll +#endif + +#ifndef _WIN64 +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + WSPStartup +#endif diff --git a/branches/WOF2-3/ulp/netdirect/user/nd_listen.cpp b/branches/WOF2-3/ulp/netdirect/user/nd_listen.cpp new file mode 100644 index 00000000..df43d0b2 --- /dev/null +++ b/branches/WOF2-3/ulp/netdirect/user/nd_listen.cpp @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION 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 "nd_listen.h" +#include "nd_adapter.h" +#include "nd_connect.h" + + +CNDListen::CNDListen(CNDAdapter *pAdapter) +{ + pAdapter->AddRef(); + m_pAdapter = pAdapter; + m_pWvConnEp = NULL; +} + +STDMETHODIMP CNDListen:: +Init(SIZE_T Backlog, INT Protocol, USHORT *pPort) +{ + WV_CONNECT_ATTRIBUTES attr; + WV_SOCKADDR addr; + HRESULT hr; + + /* All connection-oriented protocols map to IPPROTO_TCP */ + if (Protocol == IPPROTO_UDP) { + return ND_NOT_SUPPORTED; + } + + hr = m_pAdapter->m_pWvProvider->CreateConnectEndpoint(&m_pWvConnEp); + if (FAILED(hr)) { + return NDConvertWVStatus(hr); + } + + if (m_pAdapter->m_Address.ss_family == AF_INET) { + RtlCopyMemory(&addr.Sin, &m_pAdapter->m_Address, sizeof(addr.Sin)); + addr.Sin.sin_port = *pPort; + } else { + RtlCopyMemory(&addr.Sin6, &m_pAdapter->m_Address, sizeof(addr.Sin6)); + addr.Sin6.sin6_port = *pPort; + } + + hr = m_pWvConnEp->BindAddress(&addr.Sa); + if (FAILED(hr)) { + goto err; + } + + hr = m_pWvConnEp->Listen(Backlog); + if (FAILED(hr)) { + goto err; + } + + if (*pPort == 0) { + hr = m_pWvConnEp->Query(&attr); + if (FAILED(hr)) { + goto err; + } + *pPort = (addr.Sa.sa_family == AF_INET) ? + attr.LocalAddress.Sin.sin_port : attr.LocalAddress.Sin6.sin6_port; + } + + return ND_SUCCESS; +err: + m_pWvConnEp->Release(); + return NDConvertWVStatus(hr); +} + +CNDListen::~CNDListen() +{ + if (m_pWvConnEp != NULL) { + m_pWvConnEp->Release(); + } + m_pAdapter->Release(); +} + +STDMETHODIMP CNDListen:: +QueryInterface(REFIID riid, LPVOID FAR* ppvObj) +{ + if (riid != IID_IUnknown && riid != IID_INDListen) { + *ppvObj = NULL; + return E_NOINTERFACE; + } + + *ppvObj = this; + AddRef(); + return ND_SUCCESS; +} + +STDMETHODIMP_(ULONG) CNDListen:: +AddRef(void) +{ + return CNDBase::AddRef(); +} + +STDMETHODIMP_(ULONG) CNDListen:: +Release(void) +{ + return CNDBase::Release(); +} + +STDMETHODIMP CNDListen:: +CancelOverlappedRequests(void) +{ + HRESULT hr; + + hr = m_pWvConnEp->CancelOverlappedRequests(); + return NDConvertWVStatus(hr); +} + +STDMETHODIMP CNDListen:: +GetOverlappedResult(OVERLAPPED *pOverlapped, + SIZE_T *pNumberOfBytesTransferred, BOOL bWait) +{ + HRESULT hr; + + hr = m_pWvConnEp->GetOverlappedResult(pOverlapped, + (DWORD *) pNumberOfBytesTransferred, + bWait); + return NDConvertWVStatus(hr); +} + +STDMETHODIMP CNDListen:: +GetConnectionRequest(INDConnector* pConnector, OVERLAPPED* pOverlapped) +{ + CNDConnector *conn = (CNDConnector *) pConnector; + HRESULT hr; + + hr = m_pWvConnEp->GetRequest(conn->m_pWvConnEp, pOverlapped); + return NDConvertWVStatus(hr); +} diff --git a/branches/WOF2-3/ulp/netdirect/user/nd_listen.h b/branches/WOF2-3/ulp/netdirect/user/nd_listen.h new file mode 100644 index 00000000..15526fbe --- /dev/null +++ b/branches/WOF2-3/ulp/netdirect/user/nd_listen.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#ifndef _ND_LISTEN_H_ +#define _ND_LISTEN_H_ + +#include +#include +#include "nd_base.h" +#include "nd_adapter.h" + +class CNDListen : public INDListen, public CNDBase +{ +public: + // IUnknown methods + STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + // INDOverlapped methods + STDMETHODIMP CancelOverlappedRequests(); + STDMETHODIMP GetOverlappedResult(OVERLAPPED *pOverlapped, + SIZE_T *pNumberOfBytesTransferred, BOOL bWait); + + // INDListen methods + STDMETHODIMP GetConnectionRequest(INDConnector* pConnector, + OVERLAPPED* pOverlapped); + + CNDListen(CNDAdapter *pAdapter); + ~CNDListen(); + void Delete() {delete this;} + static STDMETHODIMP + CreateInstance(CNDAdapter *pAdapter, SIZE_T Backlog, INT Protocol, USHORT Port, + USHORT* pAssignedPort, INDListen** ppListen) + { + HRESULT hr; + CNDListen *listener; + + listener = new CNDListen(pAdapter); + if (listener == NULL) { + hr = ND_NO_MEMORY; + goto err1; + } + + hr = listener->Init(Backlog, Protocol, &Port); + if (FAILED(hr)) { + goto err2; + } + + if (pAssignedPort) { + *pAssignedPort = Port; + } + *ppListen = listener; + return ND_SUCCESS; + + err2: + listener->Release(); + err1: + *ppListen = NULL; + return hr; + } + +protected: + CNDAdapter *m_pAdapter; + IWVConnectEndpoint *m_pWvConnEp; + + STDMETHODIMP Init(SIZE_T Backlog, INT Protocol, USHORT *pPort); +}; + +#endif // _ND_LISTEN_H_ diff --git a/branches/WOF2-3/ulp/netdirect/user/nd_main.cpp b/branches/WOF2-3/ulp/netdirect/user/nd_main.cpp new file mode 100644 index 00000000..a27764de --- /dev/null +++ b/branches/WOF2-3/ulp/netdirect/user/nd_main.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include "nd_provider.h" + + +extern "C" { + +extern BOOL APIENTRY +_DllMainCRTStartupForGS(HINSTANCE h_module, DWORD ul_reason_for_call, + LPVOID lp_reserved); + + +BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) +{ + switch (dwReason) { + case DLL_PROCESS_ATTACH: + case DLL_PROCESS_DETACH: + return _DllMainCRTStartupForGS(hInstance, dwReason, lpReserved); + default: + return TRUE; + } +} + +STDAPI DllCanUnloadNow(void) +{ + return S_OK; +} + +STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void** ppv) +{ + UNREFERENCED_PARAMETER(rclsid); + + if (riid != IID_IClassFactory) { + *ppv = NULL; + return E_NOINTERFACE; + } + + *ppv = new CNDClassFactory(); + if (*ppv == NULL) { + return E_OUTOFMEMORY; + } + + return S_OK; +} + +int WSPStartup(WORD wVersionRequested, LPWSPDATA lpWSPData, + LPWSAPROTOCOL_INFOW lpProtocolInfo, + WSPUPCALLTABLE UpcallTable, LPWSPPROC_TABLE lpProcTable) +{ + UNREFERENCED_PARAMETER(wVersionRequested); + UNREFERENCED_PARAMETER(lpWSPData); + UNREFERENCED_PARAMETER(lpProtocolInfo); + UNREFERENCED_PARAMETER(UpcallTable); + UNREFERENCED_PARAMETER(lpProcTable); + return WSASYSNOTREADY; +} + +} // extern "C" \ No newline at end of file diff --git a/branches/WOF2-3/ulp/netdirect/user/nd_main.h b/branches/WOF2-3/ulp/netdirect/user/nd_main.h new file mode 100644 index 00000000..9a892722 --- /dev/null +++ b/branches/WOF2-3/ulp/netdirect/user/nd_main.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#ifndef _ND_MAIN_H_ +#define _ND_MAIN_H_ + +#include + +#endif // _ND_MAIN_H_ diff --git a/branches/WOF2-3/ulp/netdirect/user/nd_mw.cpp b/branches/WOF2-3/ulp/netdirect/user/nd_mw.cpp new file mode 100644 index 00000000..61f5a7af --- /dev/null +++ b/branches/WOF2-3/ulp/netdirect/user/nd_mw.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION 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 "nd_mw.h" + +CNDMemoryWindow::CNDMemoryWindow(CNDAdapter *pAdapter) +{ + pAdapter->AddRef(); + m_pAdapter = pAdapter; + m_pWvMw = NULL; +} + +STDMETHODIMP CNDMemoryWindow:: +Init(void) +{ + HRESULT hr; + + // Current WinOF drivers do not support MWs. + //hr = m_pAdapter->m_pWvPd->AllocateMemoryWindow(&m_pWvMw); + hr = ND_SUCCESS; + return NDConvertWVStatus(hr); +} + +CNDMemoryWindow::~CNDMemoryWindow() +{ + if (m_pWvMw != NULL) { + m_pWvMw->Release(); + } + m_pAdapter->Release(); +} + +STDMETHODIMP CNDMemoryWindow:: +QueryInterface(REFIID riid, LPVOID FAR* ppvObj) +{ + if (riid != IID_IUnknown && riid != IID_INDMemoryWindow) { + *ppvObj = NULL; + return E_NOINTERFACE; + } + + *ppvObj = this; + AddRef(); + return ND_SUCCESS; +} + +STDMETHODIMP_(ULONG) CNDMemoryWindow:: +AddRef(void) +{ + return CNDBase::AddRef(); +} + +STDMETHODIMP_(ULONG) CNDMemoryWindow:: +Release(void) +{ + return CNDBase::Release(); +} diff --git a/branches/WOF2-3/ulp/netdirect/user/nd_mw.h b/branches/WOF2-3/ulp/netdirect/user/nd_mw.h new file mode 100644 index 00000000..b7e42bc1 --- /dev/null +++ b/branches/WOF2-3/ulp/netdirect/user/nd_mw.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#ifndef _ND_MW_H_ +#define _ND_MW_H_ + +#include +#include +#include "nd_base.h" +#include "nd_adapter.h" + +class CNDMemoryWindow : public INDMemoryWindow , public CNDBase +{ +public: + // IUnknown methods + STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + CNDMemoryWindow(CNDAdapter *m_pAdapter); + ~CNDMemoryWindow(); + void Delete() {delete this;} + static STDMETHODIMP + CreateInstance(CNDAdapter *pAdapter, INDMemoryWindow** ppMw) + { + HRESULT hr; + CNDMemoryWindow *mw; + + mw = new CNDMemoryWindow(pAdapter); + if (mw == NULL) { + hr = ND_NO_MEMORY; + goto err1; + } + + hr = mw->Init(); + if (FAILED(hr)) { + goto err2; + } + + *ppMw = mw; + return ND_SUCCESS; + + err2: + mw->Release(); + err1: + *ppMw = NULL; + return hr; + } + + IWVMemoryWindow *m_pWvMw; +protected: + CNDAdapter *m_pAdapter; + + STDMETHODIMP Init(); +}; + +#endif // _ND_MW_H_ diff --git a/branches/WOF2-3/ulp/netdirect/user/nd_provider.cpp b/branches/WOF2-3/ulp/netdirect/user/nd_provider.cpp new file mode 100644 index 00000000..d0f0a402 --- /dev/null +++ b/branches/WOF2-3/ulp/netdirect/user/nd_provider.cpp @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION 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 "nd_provider.h" +#include "nd_adapter.h" +#include + +STDMETHODIMP CNDProvider:: +QueryInterface(REFIID riid, LPVOID FAR* ppvObj) +{ + if (riid != IID_IUnknown && riid != IID_INDProvider) { + *ppvObj = NULL; + return E_NOINTERFACE; + } + + *ppvObj = this; + AddRef(); + return ND_SUCCESS; +} + +STDMETHODIMP_(ULONG) CNDProvider:: +AddRef(void) +{ + return CNDBase::AddRef(); +} + +STDMETHODIMP_(ULONG) CNDProvider:: +Release(void) +{ + return CNDBase::Release(); +} + +STDMETHODIMP CNDProvider:: +QueryAddressList(SOCKET_ADDRESS_LIST* pAddressList, SIZE_T* pBufferSize) +{ + WV_DEVICE_ADDRESS devaddr; + IWVProvider *prov; + struct addrinfo *res, *ai; + HRESULT hr; + int cnt = 0; + size_t addrlen = 0, size; + UINT8 *offset; + + hr = WvGetObject(IID_IWVProvider, (LPVOID *) &prov); + if (FAILED(hr)) { + return NDConvertWVStatus(hr); + } + + hr = getaddrinfo("..localmachine", NULL, NULL, &res); + if (hr) { + goto release; + } + + for (ai = res; ai; ai = ai->ai_next) { + ai->ai_flags = prov->TranslateAddress(ai->ai_addr, &devaddr); + if (SUCCEEDED(ai->ai_flags)) { + cnt++; + addrlen += ai->ai_addrlen; + } + } + + if (cnt == 0) { + *pBufferSize = 0; + goto free; + } + + size = sizeof(SOCKET_ADDRESS_LIST) + sizeof(SOCKET_ADDRESS) * (cnt - 1); + if (size + addrlen > *pBufferSize) { + *pBufferSize = size + addrlen; + hr = ND_BUFFER_OVERFLOW; + goto free; + } + + pAddressList->iAddressCount = cnt; + offset = (UINT8 *) pAddressList + size; + for (cnt = 0, ai = res; ai; ai = ai->ai_next) { + if (SUCCEEDED(ai->ai_flags)) { + pAddressList->Address[cnt].iSockaddrLength = ai->ai_addrlen; + pAddressList->Address[cnt].lpSockaddr = (LPSOCKADDR) offset; + RtlCopyMemory(offset, ai->ai_addr, ai->ai_addrlen); + offset += ai->ai_addrlen; + } + } + +free: + freeaddrinfo(res); +release: + prov->Release(); + return NDConvertWVStatus(hr); +} + +STDMETHODIMP CNDProvider:: +OpenAdapter(const struct sockaddr* pAddress, SIZE_T AddressLength, + INDAdapter** ppAdapter) +{ + return CNDAdapter::CreateInstance(this, pAddress, AddressLength, ppAdapter); +} + + +//------------------------- +// CNDClassFactory routines +//------------------------- + +STDMETHODIMP CNDClassFactory:: +QueryInterface(REFIID riid, LPVOID FAR* ppvObj) +{ + if (riid != IID_IUnknown && riid != IID_IClassFactory) { + *ppvObj = NULL; + return E_NOINTERFACE; + } + + *ppvObj = this; + AddRef(); + return ND_SUCCESS; +} + +STDMETHODIMP_(ULONG) CNDClassFactory:: +AddRef(void) +{ + return CNDBase::AddRef(); +} + +STDMETHODIMP_(ULONG) CNDClassFactory:: +Release(void) +{ + return CNDBase::Release(); +} + +STDMETHODIMP CNDClassFactory:: +CreateInstance(IUnknown* pUnkOuter, REFIID riid, void** ppObject) +{ + if (pUnkOuter != NULL) { + return CLASS_E_NOAGGREGATION; + } + + if (riid != IID_INDProvider) { + *ppObject = NULL; + return E_NOINTERFACE; + } + + *ppObject = new CNDProvider(); + if (*ppObject == NULL) { + return E_OUTOFMEMORY; + } + + return S_OK; +} + +STDMETHODIMP CNDClassFactory:: +LockServer(BOOL fLock) +{ + UNREFERENCED_PARAMETER(fLock); + return S_OK; +} diff --git a/branches/WOF2-3/ulp/netdirect/user/nd_provider.h b/branches/WOF2-3/ulp/netdirect/user/nd_provider.h new file mode 100644 index 00000000..63278c85 --- /dev/null +++ b/branches/WOF2-3/ulp/netdirect/user/nd_provider.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#ifndef _ND_PROVIDER_H_ +#define _ND_PROVIDER_H_ + +#include +#include +#include "nd_base.h" + +class CNDProvider : public INDProvider, public CNDBase +{ +public: + // IUnknown methods + STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + // INDProvider methods + STDMETHODIMP QueryAddressList(SOCKET_ADDRESS_LIST* pAddressList, + SIZE_T* pBufferSize); + STDMETHODIMP OpenAdapter(const struct sockaddr* pAddress, + SIZE_T AddressLength, INDAdapter** ppAdapter); + + CNDProvider() {}; + ~CNDProvider() {}; + void Delete() {delete this;} +}; + + +class CNDClassFactory : public IClassFactory, public CNDBase +{ +public: + // IUnknown methods + STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + // IClassFactory methods + STDMETHODIMP CreateInstance(IUnknown* pUnkOuter, REFIID riid, void** ppObject); + STDMETHODIMP LockServer(BOOL fLock); + + CNDClassFactory() {}; + ~CNDClassFactory() {}; + void Delete() {delete this;} +}; + +#endif // _ND_PROVIDER_H_ \ No newline at end of file diff --git a/branches/WOF2-3/ulp/netdirect/user/netdirect.rc b/branches/WOF2-3/ulp/netdirect/user/netdirect.rc new file mode 100644 index 00000000..7ed0d78b --- /dev/null +++ b/branches/WOF2-3/ulp/netdirect/user/netdirect.rc @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + +#include + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef _DEBUG_ +#define VER_FILEDESCRIPTION_STR "OpenFabrics Winverbs Network Direct Provider (Debug)" +#define VER_INTERNALNAME_STR "wvndprovd.dll" +#define VER_ORIGINALFILENAME_STR "wvndprovd.dll" +#else +#define VER_FILEDESCRIPTION_STR "OpenFabrics Winverbs Network Direct Provider" +#define VER_INTERNALNAME_STR "wvndprov.dll" +#define VER_ORIGINALFILENAME_STR "wvndprov.dll" +#endif + +#include diff --git a/branches/WOF2-3/ulp/netdirect2/dirs b/branches/WOF2-3/ulp/netdirect2/dirs new file mode 100644 index 00000000..0e61a797 --- /dev/null +++ b/branches/WOF2-3/ulp/netdirect2/dirs @@ -0,0 +1 @@ +DIRS = user diff --git a/branches/WOF2-3/ulp/netdirect2/user/SOURCES b/branches/WOF2-3/ulp/netdirect2/user/SOURCES new file mode 100644 index 00000000..891bb46a --- /dev/null +++ b/branches/WOF2-3/ulp/netdirect2/user/SOURCES @@ -0,0 +1,45 @@ +!if $(FREEBUILD) +TARGETNAME = wvnd2prov +!else +TARGETNAME = wvnd2provd +!endif + +TARGETPATH = ..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = DYNLINK + +!if $(_NT_TOOLS_VERSION) == 0x700 +DLLDEF = $O\nd_export.def +!else +DLLDEF = $(OBJ_PATH)\$O\nd_export.def +!endif + +DLLENTRY = DllMain +USE_NTDLL = 1 + +SOURCES = \ + nd_main.cpp \ + nd_base.cpp \ + nd_provider.cpp \ + nd_adapter.cpp \ + nd_listen.cpp \ + nd_connect.cpp \ + nd_qp.cpp \ + nd_ep.cpp \ + nd_mw.cpp \ + nd_cq.cpp \ + nd_srq.cpp + +INCLUDES = ..\..\..\inc;..\..\..\inc\user;\ + ..\..\..\inc\user\linux;$(ND2_SDK_PATH)\include; + +TARGETLIBS = \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\uuid.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ + $(SDK_LIB_PATH)\iphlpapi.lib \ + $(TARGETPATH)\*\ibat.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\winverbs.lib +!else + $(TARGETPATH)\*\winverbsd.lib +!endif diff --git a/branches/WOF2-3/ulp/netdirect2/user/makefile b/branches/WOF2-3/ulp/netdirect2/user/makefile new file mode 100644 index 00000000..c43884f1 --- /dev/null +++ b/branches/WOF2-3/ulp/netdirect2/user/makefile @@ -0,0 +1,14 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!IFNDEF ND_SDK_PATH +!MESSAGE Skipping wvndprov.dll build: ND_SD_PATH not set. +DDK_BLOCK_ON_X86 = 1 +DDK_BLOCK_ON_AMD64 = 1 +DDK_BLOCK_ON_IA64 = 1 +!ENDIF + +!INCLUDE ..\..\..\inc\openib.def diff --git a/branches/WOF2-3/ulp/netdirect2/user/nd_adapter.cpp b/branches/WOF2-3/ulp/netdirect2/user/nd_adapter.cpp new file mode 100644 index 00000000..d168ba3f --- /dev/null +++ b/branches/WOF2-3/ulp/netdirect2/user/nd_adapter.cpp @@ -0,0 +1,281 @@ +/* + * Copyright (c) 2009-2010 Intel Corporation. All rights reserved. + * Copyright (c) 2010 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "nd_adapter.h" +#include "nd_cq.h" +#include "nd_listen.h" +#include "nd_connect.h" +#include "nd_mw.h" +#include "nd_qp.h" +#include "nd_srq.h" +#include "nd_ep.h" + +CNDAdapter::CNDAdapter(CNDProvider *pProvider) +{ + pProvider->AddRef(); + m_pProvider = pProvider; + m_pWvDevice = NULL; + m_pWvPd = NULL; + m_MaxInlineSend = 0; +} + +STDMETHODIMP CNDAdapter:: +Init(UINT64 adapterId) +{ + HRESULT hr; + TCHAR val[16]; + DWORD ret; + + m_DeviceGuid = adapterId; + hr = m_pProvider->m_pWvProvider->OpenDevice(m_DeviceGuid, &m_pWvDevice); + if (FAILED(hr)) { + return NDConvertWVStatus(hr); + } + + hr = m_pWvDevice->AllocateProtectionDomain(&m_pWvPd); + if (FAILED(hr)) { + return NDConvertWVStatus(hr); + } + + ret = GetEnvironmentVariable("IBNDPROV_MAX_INLINE_SIZE", val, 16); + m_MaxInlineSend = (ret > 0 && ret <= 16) ? (SIZE_T) strtoul(val, NULL, 16) : 160; + return ND_SUCCESS; +} + +CNDAdapter::~CNDAdapter(void) +{ + if (m_pWvPd != NULL) { + m_pWvPd->Release(); + } + if (m_pWvDevice != NULL) { + m_pWvDevice->Release(); + } + m_pProvider->Release(); +} + +STDMETHODIMP CNDAdapter:: +QueryInterface(REFIID riid, LPVOID FAR* ppvObj) +{ + if (riid != IID_IUnknown && riid != IID_INDAdapter) { + *ppvObj = NULL; + return E_NOINTERFACE; + } + + *ppvObj = this; + AddRef(); + return ND_SUCCESS; +} + +STDMETHODIMP_(ULONG) CNDAdapter:: +AddRef(void) +{ + return CNDBase::AddRef(); +} + +STDMETHODIMP_(ULONG) CNDAdapter:: +Release(void) +{ + return CNDBase::Release(); +} + +STDMETHODIMP_(HANDLE) CNDAdapter:: +GetFileHandle(void) +{ + return m_pProvider->m_pWvProvider->GetFileHandle(); +} + +STDMETHODIMP CNDAdapter:: +Query(ND_ADAPTER_INFO* pInfo, SIZE_T* pcbInfo) +{ + WV_DEVICE_ATTRIBUTES attr; + HRESULT hr; + + if (*pcbInfo < sizeof(ND_ADAPTER_INFO)) { + hr = ND_BUFFER_OVERFLOW; + goto out; + } + + if (pInfo != NULL && pInfo->InfoVersion != 1) { + hr = ND_NOT_SUPPORTED; + goto out; + } + + hr = NDConvertWVStatus(m_pWvDevice->Query(&attr)); + if (FAILED(hr)) { + goto out; + } + + pInfo->VendorId = (UINT16) attr.VendorId; + pInfo->DeviceId = (UINT16) attr.VendorPartId; + pInfo->AdapterId = m_DeviceGuid; + pInfo->MaxRegistrationSize = attr.MaxMrSize; + pInfo->MaxWindowSize = attr.MaxMrSize; + pInfo->MaxReceiveSge = (DWORD) attr.MaxSge; + pInfo->MaxInitiatorSge = (DWORD) attr.MaxSge; + pInfo->MaxReadSge = (DWORD) attr.MaxSge; + pInfo->MaxTransferLength = 1 << 31; + pInfo->MaxInboundReadLimit = (DWORD) attr.MaxQpResponderResources; + pInfo->MaxOutboundReadLimit = (DWORD) attr.MaxQpInitiatorDepth; + pInfo->MaxReceiveQueueDepth = (DWORD) attr.MaxQpWr; + pInfo->MaxInitiatorQueueDepth = (DWORD) attr.MaxQpWr; + pInfo->MaxSharedReceiveQueueDepth = (DWORD) attr.MaxSrqWr; + pInfo->MaxCompletionQueueDepth = (DWORD) attr.MaxCqEntries; + pInfo->InlineRequestThreshold = m_MaxInlineSend; + pInfo->LargeRequestThreshold = 0; + pInfo->MaxCallerData = ND_PRIVATE_DATA_SIZE; + pInfo->MaxCalleeData = ND_PRIVATE_DATA_SIZE; + pInfo->InlineDataFactor = 0; + pInfo->InlineDataAdjustment = -((LONG) attr.MaxInlineSend); + pInfo->InOrderDMA = TRUE; + pInfo->SupportsCQResize = TRUE; + pInfo->SupportsLoopbackConnections = TRUE; + +out: + *pcbInfo = sizeof(ND_ADAPTER_INFO); + return hr; +} + +STDMETHODIMP CNDAdapter:: +QueryAddressList(SOCKET_ADDRESS_LIST* pAddressList, SIZE_T* pcbAddressList) +{ + return m_pProvider->QueryAdapterAddressList(pAddressList, pcbAddressList, m_DeviceGuid); +} + +STDMETHODIMP CNDAdapter:: +CreateCompletionQueue(REFIID iid, DWORD queueDepth, USHORT group, KAFFINITY affinity, + VOID** ppCompletionQueue) +{ + return CNDCompletionQueue::CreateInstance(this, queueDepth, group, + affinity, ppCompletionQueue); +} + +STDMETHODIMP CNDAdapter:: +CreateMemoryRegion(REFIID iid, VOID** ppMemoryRegion) +{ + if (iid != IID_INDMemoryRegion) { + return E_NOINTERFACE; + } + + return CNDMemoryRegion::CreateInstance(this, ppMemoryRegion); +} + +STDMETHODIMP CNDAdapter:: +CreateMemoryWindow(REFIID iid, VOID** ppMemoryWindow) +{ + if (iid != IID_INDMemoryWindow) { + return E_NOINTERFACE; + } + + return CNDMemoryWindow::CreateInstance(this, ppMemoryWindow); +} + +STDMETHODIMP CNDAdapter:: +CreateSharedReceiveQueue(REFIID iid, DWORD queueDepth, DWORD maxSge, + DWORD notifyThreshold, USHORT group, + KAFFINITY affinity, VOID** ppSharedReceiveQueue) +{ + if (iid != IID_INDSharedReceiveQueue) { + return E_NOINTERFACE; + } + + return CNDSharedReceiveQueue::CreateInstance(this, queueDepth, maxSge, + notifyThreshold, group, affinity, + ppSharedReceiveQueue); +} + +STDMETHODIMP CNDAdapter:: +CreateQueuePair(REFIID iid, IUnknown* pReceiveCompletionQueue, + IUnknown* pInitiatorCompletionQueue, VOID* context, + DWORD receiveQueueDepth, DWORD initiatorQueueDepth, + DWORD maxReceiveRequestSge, DWORD maxInitiatorRequestSge, + VOID** ppQueuePair) +{ + CNDCompletionQueue *rcq = (CNDCompletionQueue *) pReceiveCompletionQueue; + CNDCompletionQueue *icq = (CNDCompletionQueue *) pInitiatorCompletionQueue; + + if (iid != IID_INDQueuePair) { + return E_NOINTERFACE; + } + + return CNDQueuePair::CreateInstance(this, rcq, icq, NULL, + context, receiveQueueDepth, initiatorQueueDepth, + maxReceiveRequestSge, maxInitiatorRequestSge, + ppQueuePair); +} + +STDMETHODIMP CNDAdapter:: +CreateQueuePairWithSrq(REFIID iid, IUnknown* pReceiveCompletionQueue, + IUnknown* pInitiatorCompletionQueue, + IUnknown* pSharedReceiveQueue, VOID* context, + DWORD initiatorQueueDepth, DWORD maxInitiatorRequestSge, + VOID** ppQueuePair) +{ + CNDCompletionQueue *rcq = (CNDCompletionQueue *) pReceiveCompletionQueue; + CNDCompletionQueue *icq = (CNDCompletionQueue *) pInitiatorCompletionQueue; + CNDSharedReceiveQueue *srq = (CNDSharedReceiveQueue *) pSharedReceiveQueue; + + if (iid != IID_INDQueuePair) { + return E_NOINTERFACE; + } + + return CNDQueuePair::CreateInstance(this, rcq, icq, srq, + context, 0, initiatorQueueDepth, 0, + maxInitiatorRequestSge, ppQueuePair); +} + +STDMETHODIMP CNDAdapter:: +CreateSharedEndpoint(REFIID iid, VOID** ppSharedEndpoint) +{ + if (iid != IID_INDSharedEndpoint) { + return E_NOINTERFACE; + } + + return CNDSharedEndpoint::CreateInstance(this, ppSharedEndpoint); +} + +STDMETHODIMP CNDAdapter:: +CreateConnector(REFIID iid, VOID** ppConnector) +{ + if (iid != IID_INDConnector) { + return E_NOINTERFACE; + } + + return CNDConnector::CreateInstance(this, ppConnector); +} + +STDMETHODIMP CNDAdapter:: +CreateListen(REFIID iid, VOID** ppListen) +{ + if (iid != IID_INDListen) { + return E_NOINTERFACE; + } + + return CNDListen::CreateInstance(this, ppListen); +} diff --git a/branches/WOF2-3/ulp/netdirect2/user/nd_adapter.h b/branches/WOF2-3/ulp/netdirect2/user/nd_adapter.h new file mode 100644 index 00000000..941f80a1 --- /dev/null +++ b/branches/WOF2-3/ulp/netdirect2/user/nd_adapter.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2009-2010 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#ifndef _ND_ADAPTER_H_ +#define _ND_ADAPTER_H_ + +#include +#include "nd_base.h" +#include "nd_provider.h" + + +class CNDAdapter : public INDAdapter, public CNDBase +{ +public: + // IUnknown methods + STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + // INDAdapter methods + STDMETHODIMP_(HANDLE) GetFileHandle(); + STDMETHODIMP Query(ND_ADAPTER_INFO* pInfo, SIZE_T* pcbInfo); + STDMETHODIMP QueryAddressList(SOCKET_ADDRESS_LIST* pAddressList, SIZE_T* pcbAddressList); + STDMETHODIMP CreateCompletionQueue(REFIID iid, DWORD queueDepth, USHORT group, + KAFFINITY affinity, VOID** ppCompletionQueue); + STDMETHODIMP CreateMemoryRegion(REFIID iid, VOID** ppMemoryRegion); + STDMETHODIMP CreateMemoryWindow(REFIID iid, VOID** ppMemoryWindow); + STDMETHODIMP CreateSharedReceiveQueue(REFIID iid, DWORD queueDepth, DWORD maxSge, + DWORD notifyThreshold, USHORT group, + KAFFINITY affinity, VOID** ppSharedReceiveQueue); + STDMETHODIMP CreateQueuePair(REFIID iid, IUnknown* pReceiveCompletionQueue, + IUnknown* pInitiatorCompletionQueue, VOID* context, + DWORD receiveQueueDepth, DWORD initiatorQueueDepth, + DWORD maxReceiveRequestSge, DWORD maxInitiatorRequestSge, + VOID** ppQueuePair); + STDMETHODIMP CreateQueuePairWithSrq(REFIID, IUnknown* pReceiveCompletionQueue, + IUnknown* pInitiatorCompletionQueue, + IUnknown* pSharedReceiveQueue, VOID* context, + DWORD initiatorQueueDepth, DWORD maxInitiatorRequestSge, + VOID** ppQueuePair); + STDMETHODIMP CreateSharedEndpoint(REFIID iid, VOID** ppSharedEndpoint); + STDMETHODIMP CreateConnector(REFIID iid, VOID** ppConnector); + STDMETHODIMP CreateListen(REFIID iid, VOID** ppListen); + + CNDAdapter(CNDProvider *pProvider); + ~CNDAdapter(); + void Delete() {delete this;} + static STDMETHODIMP + CreateInstance(CNDProvider *pProvider, UINT64 adapterId, VOID** ppAdapter) + { + HRESULT hr; + CNDAdapter *adapter; + + adapter = new CNDAdapter(pProvider); + if (adapter == NULL) { + hr = ND_NO_MEMORY; + goto err1; + } + + hr = adapter->Init(adapterId); + if (FAILED(hr)) { + goto err2; + } + + *ppAdapter = adapter; + return ND_SUCCESS; + + err2: + adapter->Release(); + err1: + *ppAdapter = NULL; + return hr; + } + + CNDProvider *m_pProvider; + IWVDevice *m_pWvDevice; + IWVProtectionDomain *m_pWvPd; + DWORD m_MaxInlineSend; + +protected: + UINT64 m_DeviceGuid; + + STDMETHODIMP Init(UINT64 adapterId); +}; + +#endif // _ND_ADAPTER_H_ diff --git a/branches/WOF2-3/ulp/netdirect2/user/nd_base.cpp b/branches/WOF2-3/ulp/netdirect2/user/nd_base.cpp new file mode 100644 index 00000000..933b2296 --- /dev/null +++ b/branches/WOF2-3/ulp/netdirect2/user/nd_base.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2009-2010 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "nd_base.h" +#include + +CNDBase::CNDBase() +{ + m_nRef = 1; +} + +STDMETHODIMP_(ULONG) CNDBase:: +AddRef(void) +{ + return InterlockedIncrement(&m_nRef); +} + +STDMETHODIMP_(ULONG) CNDBase:: +Release(void) +{ + ULONG ref; + + ref = (ULONG) InterlockedDecrement(&m_nRef); + if (ref == 0) { + Delete(); + } + return ref; +} + +HRESULT NDConvertWVStatus(HRESULT hr) +{ + switch (hr) { + case WV_IO_PENDING: + return ND_PENDING; + default: + return hr; + } +} diff --git a/branches/WOF2-3/ulp/netdirect2/user/nd_base.h b/branches/WOF2-3/ulp/netdirect2/user/nd_base.h new file mode 100644 index 00000000..855fc673 --- /dev/null +++ b/branches/WOF2-3/ulp/netdirect2/user/nd_base.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2009-2010 Intel Corporation. All rights reserved. + * Copyright (c) 2010 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#ifndef _ND_BASE_H_ +#define _ND_BASE_H_ + +#include +#include +#include + +class CNDBase +{ +public: + CNDBase(); + ~CNDBase() {}; + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + virtual void Delete() {}; + + volatile LONG m_nRef; + +protected: +}; + +extern HANDLE g_hHeap; + +__inline void* __cdecl operator new(size_t size) +{ + return HeapAlloc(g_hHeap, 0, size); +} + +__inline void __cdecl operator delete(void *pObj) +{ + HeapFree(g_hHeap, 0, pObj); +} + +HRESULT NDConvertWVStatus(HRESULT hr); + +#endif // _ND_BASE_H_ diff --git a/branches/WOF2-3/ulp/netdirect2/user/nd_connect.cpp b/branches/WOF2-3/ulp/netdirect2/user/nd_connect.cpp new file mode 100644 index 00000000..7d9f71df --- /dev/null +++ b/branches/WOF2-3/ulp/netdirect2/user/nd_connect.cpp @@ -0,0 +1,332 @@ +/* + * Copyright (c) 2009-2010 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "nd_connect.h" +#include "nd_ep.h" +#include "nd_qp.h" +#include + + +CNDConnector::CNDConnector(CNDAdapter *pAdapter) +{ + pAdapter->AddRef(); + m_pAdapter = pAdapter; + m_pWvConnEp = NULL; + m_Connects = 0; +} + +STDMETHODIMP CNDConnector:: +Init(void) +{ + IWVConnectEndpoint *ep; + HRESULT hr; + + hr = m_pAdapter->m_pProvider->m_pWvProvider->CreateConnectEndpoint(&ep); + if (FAILED(hr)) { + return NDConvertWVStatus(hr); + } + + if (m_pWvConnEp != NULL) { + m_pWvConnEp->Release(); + } + + m_pWvConnEp = ep; + return ND_SUCCESS; +} + +CNDConnector::~CNDConnector() +{ + if (m_pWvConnEp != NULL) { + m_pWvConnEp->Release(); + } + m_pAdapter->Release(); +} + +STDMETHODIMP CNDConnector:: +QueryInterface(REFIID riid, LPVOID FAR* ppvObj) +{ + if (riid != IID_IUnknown && riid != IID_INDConnector) { + *ppvObj = NULL; + return E_NOINTERFACE; + } + + *ppvObj = this; + AddRef(); + return ND_SUCCESS; +} + +STDMETHODIMP_(ULONG) CNDConnector:: +AddRef(void) +{ + return CNDBase::AddRef(); +} + +STDMETHODIMP_(ULONG) CNDConnector:: +Release(void) +{ + return CNDBase::Release(); +} + +STDMETHODIMP CNDConnector:: +CancelOverlappedRequests(void) +{ + HRESULT hr; + + hr = m_pWvConnEp->CancelOverlappedRequests(); + return NDConvertWVStatus(hr); +} + +STDMETHODIMP CNDConnector:: +GetOverlappedResult(OVERLAPPED *pOverlapped, BOOL bWait) +{ + DWORD bytes; + HRESULT hr; + + hr = m_pWvConnEp->GetOverlappedResult(pOverlapped, &bytes, bWait); + return NDConvertWVStatus(hr); +} + +STDMETHODIMP CNDConnector:: +ConnectQp(IUnknown* pQueuePair, BOOL SharedAddress, + const struct sockaddr* pSrcAddress, SIZE_T cbSrcAddress, + const struct sockaddr* pDestAddress, SIZE_T cbDestAddress, + DWORD inboundReadLimit, DWORD outboundReadLimit, + const VOID* pPrivateData, DWORD cbPrivateData, OVERLAPPED* pOverlapped) +{ + CNDQueuePair *qp = (CNDQueuePair *) pQueuePair; + WV_CONNECT_PARAM attr; + IBAT_PATH_BLOB path; + HRESULT hr; + + if (m_Connects++ > 0) { + hr = Init(); + if (FAILED(hr)) { + goto out; + } + } + + hr = IBAT::ResolvePath(pSrcAddress, pDestAddress, &path, INFINITE); + if (FAILED(hr)) { + goto out; + } + + if (SharedAddress) { + //hr = m_pWvConnEp->BindAddress((SOCKADDR *) pSrcAddress); + if (FAILED(hr)) { + goto out; + } + } else { + hr = m_pWvConnEp->BindAddress((SOCKADDR *) pSrcAddress); + if (FAILED(hr)) { + goto out; + } + } + + hr = m_pWvConnEp->Modify(WV_EP_OPTION_ROUTE, &path, sizeof path); + if (FAILED(hr)) { + goto out; + } + + RtlZeroMemory(&attr, sizeof attr); + if ((attr.DataLength = cbPrivateData)) { + RtlCopyMemory(attr.Data, pPrivateData, cbPrivateData); + } + attr.ResponderResources = inboundReadLimit; + attr.InitiatorDepth = outboundReadLimit; + attr.RetryCount = 7; + + hr = m_pWvConnEp->Connect(qp->m_pWvQp, pDestAddress, &attr, pOverlapped); +out: + return NDConvertWVStatus(hr); +} + +STDMETHODIMP CNDConnector:: +Connect(IUnknown* pQueuePair, + const struct sockaddr* pSrcAddress, SIZE_T cbSrcAddress, + const struct sockaddr* pDestAddress, SIZE_T cbDestAddress, + DWORD inboundReadLimit, DWORD outboundReadLimit, + const VOID* pPrivateData, DWORD cbPrivateData, OVERLAPPED* pOverlapped) +{ + return ConnectQp(pQueuePair, FALSE, pSrcAddress, cbSrcAddress, + pDestAddress, cbDestAddress, inboundReadLimit, + outboundReadLimit, pPrivateData, cbPrivateData, pOverlapped); +} + +STDMETHODIMP CNDConnector:: +ConnectSharedEndpoint(IUnknown* pQueuePair, IUnknown* pSharedEndpoint, + const struct sockaddr* pDestAddress, SIZE_T cbDestAddress, + DWORD inboundReadLimit, DWORD outboundReadLimit, + const VOID* pPrivateData, DWORD cbPrivateData, + OVERLAPPED* pOverlapped) +{ + CNDSharedEndpoint *sep = (CNDSharedEndpoint *) pSharedEndpoint; + + return ConnectQp(pQueuePair, TRUE, (SOCKADDR *) &sep->m_Address, sep->m_AddressSize, + pDestAddress, cbDestAddress, inboundReadLimit, + outboundReadLimit, pPrivateData, cbPrivateData, pOverlapped); +} + +STDMETHODIMP CNDConnector:: +CompleteConnect(OVERLAPPED* pOverlapped) +{ + WV_CONNECT_PARAM attr; + HRESULT hr; + + RtlZeroMemory(&attr, sizeof attr); + hr = m_pWvConnEp->Accept(NULL, &attr, pOverlapped); + return NDConvertWVStatus(hr); +} + +STDMETHODIMP CNDConnector:: +Accept(IUnknown* pQueuePair, DWORD inboundReadLimit, DWORD outboundReadLimit, + const VOID* pPrivateData, DWORD cbPrivateData, OVERLAPPED* pOverlapped) +{ + CNDQueuePair *qp = (CNDQueuePair *) pQueuePair; + WV_CONNECT_PARAM attr; + HRESULT hr; + + RtlZeroMemory(&attr, sizeof attr); + if ((attr.DataLength = cbPrivateData)) { + RtlCopyMemory(attr.Data, pPrivateData, cbPrivateData); + } + attr.ResponderResources = inboundReadLimit; + attr.InitiatorDepth = outboundReadLimit; + + hr = m_pWvConnEp->Accept(qp->m_pWvQp, &attr, pOverlapped); + return NDConvertWVStatus(hr); +} + +STDMETHODIMP CNDConnector:: +Reject(const void* pPrivateData, DWORD cbPrivateData) +{ + HRESULT hr; + + hr = m_pWvConnEp->Reject(pPrivateData, cbPrivateData); + return NDConvertWVStatus(hr); +} + +STDMETHODIMP CNDConnector:: +GetConnectionData(DWORD* pInboundReadLimit, DWORD* pOutboundReadLimit, + void* pPrivateData, DWORD* pcbPrivateData) +{ + WV_CONNECT_ATTRIBUTES attr; + HRESULT hr; + + hr = m_pWvConnEp->Query(&attr); + if (FAILED(hr)) { + return NDConvertWVStatus(hr); + } + + if (pInboundReadLimit) { + *pInboundReadLimit = (DWORD) attr.Param.ResponderResources; + } + if (pOutboundReadLimit) { + *pOutboundReadLimit = (DWORD) attr.Param.InitiatorDepth; + } + if (pcbPrivateData) { + if (*pcbPrivateData < ND_PRIVATE_DATA_SIZE) { + hr = ND_BUFFER_OVERFLOW; + } + + RtlCopyMemory(pPrivateData, attr.Param.Data, + min(*pcbPrivateData, ND_PRIVATE_DATA_SIZE)); + *pcbPrivateData = ND_PRIVATE_DATA_SIZE; + } + + return hr; +} + +SIZE_T GetAddressSize(WV_SOCKADDR *addr) +{ + return (addr->Sa.sa_family == AF_INET) ? sizeof(addr->Sin) : sizeof(addr->Sin6); +} + +STDMETHODIMP CNDConnector:: +GetLocalAddress(struct sockaddr* pAddress, SIZE_T* pcbAddress) +{ + WV_CONNECT_ATTRIBUTES attr; + HRESULT hr; + SIZE_T size; + + hr = m_pWvConnEp->Query(&attr); + if (FAILED(hr)) { + return NDConvertWVStatus(hr); + } + + size = GetAddressSize(&attr.LocalAddress); + if (*pcbAddress >= size) { + RtlCopyMemory(pAddress, &attr.LocalAddress, size); + } else { + hr = ND_BUFFER_OVERFLOW; + } + + *pcbAddress = size; + return NDConvertWVStatus(hr); +} + +STDMETHODIMP CNDConnector:: +GetPeerAddress(struct sockaddr* pAddress, SIZE_T* pcbAddress) +{ + WV_CONNECT_ATTRIBUTES attr; + HRESULT hr; + SIZE_T size; + + hr = m_pWvConnEp->Query(&attr); + if (FAILED(hr)) { + return NDConvertWVStatus(hr); + } + + size = GetAddressSize(&attr.PeerAddress); + if (*pcbAddress >= size) { + RtlCopyMemory(pAddress, &attr.PeerAddress, size); + } else { + hr = ND_BUFFER_OVERFLOW; + } + + *pcbAddress = size; + return hr; +} + +STDMETHODIMP CNDConnector:: +NotifyDisconnect(OVERLAPPED* pOverlapped) +{ + HRESULT hr; + + hr = m_pWvConnEp->NotifyDisconnect(pOverlapped); + return NDConvertWVStatus(hr); +} + +STDMETHODIMP CNDConnector:: +Disconnect(OVERLAPPED* pOverlapped) +{ + HRESULT hr; + + hr = m_pWvConnEp->Disconnect(pOverlapped); + return NDConvertWVStatus(hr); +} diff --git a/branches/WOF2-3/ulp/netdirect2/user/nd_connect.h b/branches/WOF2-3/ulp/netdirect2/user/nd_connect.h new file mode 100644 index 00000000..0140430b --- /dev/null +++ b/branches/WOF2-3/ulp/netdirect2/user/nd_connect.h @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2009-2010 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#ifndef _ND_CONNECTOR_H_ +#define _ND_CONNECTOR_H_ + +#include +#include +#include "nd_base.h" +#include "nd_adapter.h" + + +#define ND_PRIVATE_DATA_SIZE 56 + + +class CNDConnector : public INDConnector, public CNDBase +{ +public: + // IUnknown methods + STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + // INDOverlapped methods + STDMETHODIMP CancelOverlappedRequests(); + STDMETHODIMP GetOverlappedResult(OVERLAPPED *pOverlapped, BOOL bWait); + + // INDConnector methods + STDMETHODIMP Connect(IUnknown* pQueuePair, + const struct sockaddr* pSrcAddress, SIZE_T cbSrcAddress, + const struct sockaddr* pDestAddress, SIZE_T cbDestAddress, + DWORD inboundReadLimit, DWORD outboundReadLimit, + const VOID* pPrivateData, DWORD cbPrivateData, OVERLAPPED* pOverlapped); + STDMETHODIMP ConnectSharedEndpoint(IUnknown* pQueuePair, IUnknown* pSharedEndpoint, + const struct sockaddr* pDestAddress, SIZE_T cbDestAddress, + DWORD inboundReadLimit, DWORD outboundReadLimit, + const VOID* pPrivateData, DWORD cbPrivateData, + OVERLAPPED* pOverlapped); + STDMETHODIMP CompleteConnect(OVERLAPPED* pOverlapped); + STDMETHODIMP Accept(IUnknown* pQueuePair, DWORD inboundReadLimit, DWORD outboundReadLimit, + const VOID* pPrivateData, DWORD cbPrivateData, OVERLAPPED* pOverlapped); + STDMETHODIMP Reject(const VOID* pPrivateData, DWORD cbPrivateData); + STDMETHODIMP GetConnectionData(DWORD* pInboundReadLimit, DWORD* pOutboundReadLimit, + VOID* pPrivateData, DWORD* pcbPrivateData); + STDMETHODIMP GetLocalAddress(struct sockaddr* pAddress, SIZE_T* pcbAddress); + STDMETHODIMP GetPeerAddress(struct sockaddr* pAddress, SIZE_T* pcbAddress); + STDMETHODIMP NotifyDisconnect(OVERLAPPED* pOverlapped); + STDMETHODIMP Disconnect(OVERLAPPED* pOverlapped); + + CNDConnector(CNDAdapter *pAdapter); + ~CNDConnector(); + void Delete() {delete this;} + static STDMETHODIMP + CreateInstance(CNDAdapter *pAdapter, VOID** ppConnector) + { + HRESULT hr; + CNDConnector *conn; + + conn = new CNDConnector(pAdapter); + if (conn == NULL) { + hr = ND_NO_MEMORY; + goto err1; + } + + hr = conn->Init(); + if (FAILED(hr)) { + goto err2; + } + + *ppConnector = conn; + return ND_SUCCESS; + + err2: + conn->Release(); + err1: + *ppConnector = NULL; + return hr; + } + + IWVConnectEndpoint *m_pWvConnEp; + CNDAdapter *m_pAdapter; + +protected: + STDMETHODIMP Init(); + STDMETHODIMP ConnectQp(IUnknown* pQueuePair, BOOL SharedAddress, + const struct sockaddr* pSrcAddress, SIZE_T cbSrcAddress, + const struct sockaddr* pDestAddress, SIZE_T cbDestAddress, + DWORD inboundReadLimit, DWORD outboundReadLimit, + const VOID* pPrivateData, DWORD cbPrivateData, + OVERLAPPED* pOverlapped); + int m_Connects; +}; + +SIZE_T GetAddressSize(WV_SOCKADDR *addr); + +#endif // _ND_CONNECTOR_H_ diff --git a/branches/WOF2-3/ulp/netdirect2/user/nd_cq.cpp b/branches/WOF2-3/ulp/netdirect2/user/nd_cq.cpp new file mode 100644 index 00000000..2d9d0d63 --- /dev/null +++ b/branches/WOF2-3/ulp/netdirect2/user/nd_cq.cpp @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2009-2010 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "nd_cq.h" + +CNDCompletionQueue::CNDCompletionQueue(CNDAdapter *pAdapter) +{ + pAdapter->AddRef(); + m_pAdapter = pAdapter; + m_pWvCq = NULL; +} + +STDMETHODIMP CNDCompletionQueue:: +Init(DWORD queueDepth, USHORT group, KAFFINITY affinity) +{ + HRESULT hr; + + hr = m_pAdapter->m_pWvDevice->CreateCompletionQueue((SIZE_T *) &queueDepth, &m_pWvCq); + return NDConvertWVStatus(hr); +} + +CNDCompletionQueue::~CNDCompletionQueue() +{ + if (m_pWvCq != NULL) { + m_pWvCq->Release(); + } + m_pAdapter->Release(); +} + +STDMETHODIMP CNDCompletionQueue:: +QueryInterface(REFIID riid, LPVOID FAR* ppvObj) +{ + if (riid != IID_IUnknown && riid != IID_INDCompletionQueue) { + *ppvObj = NULL; + return E_NOINTERFACE; + } + + *ppvObj = this; + AddRef(); + return ND_SUCCESS; +} + +STDMETHODIMP_(ULONG) CNDCompletionQueue:: +AddRef(void) +{ + return CNDBase::AddRef(); +} + +STDMETHODIMP_(ULONG) CNDCompletionQueue:: +Release(void) +{ + return CNDBase::Release(); +} + +STDMETHODIMP CNDCompletionQueue:: +CancelOverlappedRequests(void) +{ + HRESULT hr; + + hr = m_pWvCq->CancelOverlappedRequests(); + return NDConvertWVStatus(hr); +} + +STDMETHODIMP CNDCompletionQueue:: +GetOverlappedResult(OVERLAPPED *pOverlapped, BOOL bWait) +{ + DWORD bytes; + HRESULT hr; + + hr = m_pWvCq->GetOverlappedResult(pOverlapped, &bytes, bWait); + return NDConvertWVStatus(hr); +} + +STDMETHODIMP CNDCompletionQueue:: +GetNotifyAffinity(USHORT* pGroup, KAFFINITY* pAffinity) +{ + return ND_NOT_SUPPORTED; +} + +STDMETHODIMP CNDCompletionQueue:: +Resize(DWORD queueDepth) +{ + HRESULT hr; + + hr = m_pWvCq->Resize((SIZE_T *) &queueDepth); + return NDConvertWVStatus(hr); +} + +STDMETHODIMP CNDCompletionQueue:: +Notify(DWORD type, OVERLAPPED* pOverlapped) +{ + HRESULT hr; + + hr = m_pWvCq->Notify((WV_CQ_NOTIFY_TYPE) type, pOverlapped); + return NDConvertWVStatus(hr); +} + +STDMETHODIMP_(HRESULT) CNDCompletionQueue:: +ConvertStatus(WV_WC_STATUS Status) +{ + switch (Status) { + case WvWcSuccess: + return ND_SUCCESS; + case WvWcFlushed: + return ND_CANCELED; + case WvWcLocalLengthError: + return ND_LOCAL_LENGTH; + case WvWcRnrRetryError: + case WvWcTimeoutRetryError: + return ND_TIMEOUT; + case WvWcLocalAccessError: + case WvWcLocalOpError: + case WvWcLocalProtectionError: + case WvWcMwBindError: + return ND_ACCESS_VIOLATION; + case WvWcRemoteAccessError: + case WvWcRemoteOpError: + case WvWcRemoteInvalidRequest: + case WvWcBadResponse: + return ND_REMOTE_ERROR; + default: + return ND_INTERNAL_ERROR; + } +} + +STDMETHODIMP_(DWORD) CNDCompletionQueue:: +GetResults(ND_RESULT results[], DWORD nResults) +{ + WV_COMPLETION wc[8]; + DWORD cnt, total, i; + + for (total = 0; nResults; nResults -= cnt) { + cnt = min(8, nResults); + cnt = (DWORD) m_pWvCq->Poll(wc, cnt); + if (cnt == 0) { + break; + } + + for (i = 0; i < cnt; i++) { + results[total].Status = ConvertStatus(wc[i].Status); + if (wc[i].Opcode & WvReceive) { + results[total].BytesTransferred = wc[i].Length; + } + results[total].QueuePairContext = wc[i].QpContext; + results[total].RequestContext = (VOID *) (ULONG_PTR) wc[i].WrId; + } + } + return total; +} diff --git a/branches/WOF2-3/ulp/netdirect2/user/nd_cq.h b/branches/WOF2-3/ulp/netdirect2/user/nd_cq.h new file mode 100644 index 00000000..83568542 --- /dev/null +++ b/branches/WOF2-3/ulp/netdirect2/user/nd_cq.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2009-2010 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#ifndef _ND_CQ_H_ +#define _ND_CQ_H_ + +#include +#include +#include "nd_base.h" +#include "nd_adapter.h" + +class CNDCompletionQueue : public INDCompletionQueue, public CNDBase +{ +public: + // IUnknown methods + STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + // INDOverlapped methods + STDMETHODIMP CancelOverlappedRequests(); + STDMETHODIMP GetOverlappedResult(OVERLAPPED *pOverlapped, BOOL bWait); + + // INDCompletionQueue methods + STDMETHODIMP GetNotifyAffinity(USHORT* pGroup, KAFFINITY* pAffinity); + STDMETHODIMP Resize(DWORD queueDepth); + STDMETHODIMP Notify(DWORD type, OVERLAPPED* pOverlapped); + STDMETHODIMP_(DWORD) GetResults(ND_RESULT results[], DWORD nResults); + + CNDCompletionQueue(CNDAdapter *pAdapter); + ~CNDCompletionQueue(); + void Delete() {delete this;} + static STDMETHODIMP + CreateInstance(CNDAdapter *pAdapter, DWORD queueDepth, USHORT group, + KAFFINITY affinity, VOID** ppCq) + { + HRESULT hr; + CNDCompletionQueue *cq; + + cq = new CNDCompletionQueue(pAdapter); + if (cq == NULL) { + hr = ND_NO_MEMORY; + goto err1; + } + + hr = cq->Init(queueDepth, group, affinity); + if (FAILED(hr)) { + goto err2; + } + + *ppCq = cq; + return ND_SUCCESS; + + err2: + cq->Release(); + err1: + *ppCq = NULL; + return hr; + } + + IWVCompletionQueue *m_pWvCq; + +protected: + CNDAdapter *m_pAdapter; + STDMETHODIMP Init(DWORD queueDepth, USHORT group, KAFFINITY affinity); + STDMETHODIMP_(HRESULT) ConvertStatus(WV_WC_STATUS Status); +}; + +#endif // _ND_CQ_H_ diff --git a/branches/WOF2-3/ulp/netdirect2/user/nd_ep.cpp b/branches/WOF2-3/ulp/netdirect2/user/nd_ep.cpp new file mode 100644 index 00000000..3f73e162 --- /dev/null +++ b/branches/WOF2-3/ulp/netdirect2/user/nd_ep.cpp @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2009-2010 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "nd_ep.h" +#include "nd_adapter.h" +#include + + +CNDSharedEndpoint::CNDSharedEndpoint(CNDAdapter *pAdapter) +{ + pAdapter->AddRef(); + m_pAdapter = pAdapter; +} + +CNDSharedEndpoint::~CNDSharedEndpoint() +{ + m_pAdapter->Release(); +} + +STDMETHODIMP CNDSharedEndpoint:: +QueryInterface(REFIID riid, LPVOID FAR* ppvObj) +{ + if (riid != IID_IUnknown && riid != IID_INDSharedEndpoint) { + *ppvObj = NULL; + return E_NOINTERFACE; + } + + *ppvObj = this; + AddRef(); + return ND_SUCCESS; +} + +STDMETHODIMP_(ULONG) CNDSharedEndpoint:: +AddRef(void) +{ + return CNDBase::AddRef(); +} + +STDMETHODIMP_(ULONG) CNDSharedEndpoint:: +Release(void) +{ + return CNDBase::Release(); +} + +STDMETHODIMP CNDSharedEndpoint:: +Bind(const struct sockaddr* pAddress, SIZE_T cbAddress) +{ + //??? + return ND_NOT_SUPPORTED; +} + +STDMETHODIMP CNDSharedEndpoint:: +GetLocalAddress(struct sockaddr* pAddress, SIZE_T* pcbAddress) +{ + HRESULT hr; + + if (*pcbAddress >= m_AddressSize) { + RtlCopyMemory(pAddress, &m_Address, m_AddressSize); + hr = ND_SUCCESS; + } else { + hr = ND_BUFFER_OVERFLOW; + } + + *pcbAddress = m_AddressSize; + return NDConvertWVStatus(hr); +} diff --git a/branches/WOF2-3/ulp/netdirect2/user/nd_ep.h b/branches/WOF2-3/ulp/netdirect2/user/nd_ep.h new file mode 100644 index 00000000..81ec1896 --- /dev/null +++ b/branches/WOF2-3/ulp/netdirect2/user/nd_ep.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2009-2010 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#ifndef _ND_ENDPOINT_H_ +#define _ND_ENDPOINT_H_ + +#include +#include +#include "nd_base.h" +#include "nd_adapter.h" + + +class CNDSharedEndpoint : public INDSharedEndpoint, public CNDBase +{ +public: + // IUnknown methods + STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + // INDEndpoint methods + STDMETHODIMP Bind(const struct sockaddr* pAddress, SIZE_T cbAddress); + STDMETHODIMP GetLocalAddress(struct sockaddr* pAddress, SIZE_T* pcbAddress); + + CNDSharedEndpoint(CNDAdapter *pAdapter); + ~CNDSharedEndpoint(); + void Delete() {delete this;} + static STDMETHODIMP + CreateInstance(CNDAdapter *pAdapter, VOID** ppSharedEndpoint) + { + HRESULT hr; + CNDSharedEndpoint *ep; + + ep = new CNDSharedEndpoint(pAdapter); + if (ep == NULL) { + hr = ND_NO_MEMORY; + goto err; + } + + *ppSharedEndpoint = ep; + return ND_SUCCESS; + + err: + *ppSharedEndpoint = NULL; + return hr; + } + + SOCKADDR_STORAGE m_Address; + SIZE_T m_AddressSize; + CNDAdapter *m_pAdapter; +}; + +#endif // _ND_ENDPOINT_H_ diff --git a/branches/WOF2-3/ulp/netdirect2/user/nd_export.def b/branches/WOF2-3/ulp/netdirect2/user/nd_export.def new file mode 100644 index 00000000..f02ae6f7 --- /dev/null +++ b/branches/WOF2-3/ulp/netdirect2/user/nd_export.def @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#if _DEBUG_ +LIBRARY WVNDPROVD.DLL +#else +LIBRARY WVNDPROV.DLL +#endif + +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + WSPStartup diff --git a/branches/WOF2-3/ulp/netdirect2/user/nd_exports.src b/branches/WOF2-3/ulp/netdirect2/user/nd_exports.src new file mode 100644 index 00000000..042f3cdb --- /dev/null +++ b/branches/WOF2-3/ulp/netdirect2/user/nd_exports.src @@ -0,0 +1,12 @@ +#if DBG +LIBRARY wvndprov.dll +#else +LIBRARY wvndprov.dll +#endif + +#ifndef _WIN64 +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + WSPStartup +#endif diff --git a/branches/WOF2-3/ulp/netdirect2/user/nd_listen.cpp b/branches/WOF2-3/ulp/netdirect2/user/nd_listen.cpp new file mode 100644 index 00000000..ee225403 --- /dev/null +++ b/branches/WOF2-3/ulp/netdirect2/user/nd_listen.cpp @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2009-2010 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "nd_listen.h" +#include "nd_adapter.h" +#include "nd_connect.h" + + +CNDListen::CNDListen(CNDAdapter *pAdapter) +{ + pAdapter->AddRef(); + m_pAdapter = pAdapter; + m_pWvConnEp = NULL; +} + +CNDListen::~CNDListen() +{ + if (m_pWvConnEp != NULL) { + m_pWvConnEp->Release(); + } + m_pAdapter->Release(); +} + +STDMETHODIMP CNDListen:: +QueryInterface(REFIID riid, LPVOID FAR* ppvObj) +{ + if (riid != IID_IUnknown && riid != IID_INDListen) { + *ppvObj = NULL; + return E_NOINTERFACE; + } + + *ppvObj = this; + AddRef(); + return ND_SUCCESS; +} + +STDMETHODIMP_(ULONG) CNDListen:: +AddRef(void) +{ + return CNDBase::AddRef(); +} + +STDMETHODIMP_(ULONG) CNDListen:: +Release(void) +{ + return CNDBase::Release(); +} + +STDMETHODIMP CNDListen:: +CancelOverlappedRequests(void) +{ + HRESULT hr; + + hr = m_pWvConnEp->CancelOverlappedRequests(); + return NDConvertWVStatus(hr); +} + +STDMETHODIMP CNDListen:: +GetOverlappedResult(OVERLAPPED *pOverlapped, BOOL bWait) +{ + DWORD bytes; + HRESULT hr; + + hr = m_pWvConnEp->GetOverlappedResult(pOverlapped, &bytes, bWait); + return NDConvertWVStatus(hr); +} + +STDMETHODIMP CNDListen:: +Listen(const struct sockaddr* pAddress, SIZE_T cbAddress, SIZE_T backlog) +{ + WV_SOCKADDR addr; + HRESULT hr; + + hr = m_pAdapter->m_pProvider->m_pWvProvider->CreateConnectEndpoint(&m_pWvConnEp); + if (FAILED(hr)) { + return NDConvertWVStatus(hr); + } + + hr = m_pWvConnEp->BindAddress((SOCKADDR *) pAddress); + if (FAILED(hr)) { + goto err; + } + + hr = m_pWvConnEp->Listen(backlog); + if (FAILED(hr)) { + goto err; + } + + return ND_SUCCESS; + +err: + m_pWvConnEp->Release(); + m_pWvConnEp = NULL; + return NDConvertWVStatus(hr); +} + +STDMETHODIMP CNDListen:: +GetLocalAddress(struct sockaddr* pAddress, SIZE_T* pcbAddress) +{ + WV_CONNECT_ATTRIBUTES attr; + HRESULT hr; + SIZE_T size; + + hr = m_pWvConnEp->Query(&attr); + if (FAILED(hr)) { + return NDConvertWVStatus(hr); + } + + size = GetAddressSize(&attr.LocalAddress); + if (*pcbAddress >= size) { + RtlCopyMemory(pAddress, &attr.LocalAddress.Sa, size); + } else { + hr = ND_BUFFER_OVERFLOW; + } + + *pcbAddress = size; + return hr; +} + +STDMETHODIMP CNDListen:: +GetConnectionRequest(IUnknown* pConnector, OVERLAPPED* pOverlapped) +{ + CNDConnector *conn = (CNDConnector *) pConnector; + HRESULT hr; + + hr = m_pWvConnEp->GetRequest(conn->m_pWvConnEp, pOverlapped); + return NDConvertWVStatus(hr); +} diff --git a/branches/WOF2-3/ulp/netdirect2/user/nd_listen.h b/branches/WOF2-3/ulp/netdirect2/user/nd_listen.h new file mode 100644 index 00000000..08f2d011 --- /dev/null +++ b/branches/WOF2-3/ulp/netdirect2/user/nd_listen.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2009-2010 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#ifndef _ND_LISTEN_H_ +#define _ND_LISTEN_H_ + +#include +#include +#include "nd_base.h" +#include "nd_adapter.h" + +class CNDListen : public INDListen, public CNDBase +{ +public: + // IUnknown methods + STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + // INDOverlapped methods + STDMETHODIMP CancelOverlappedRequests(); + STDMETHODIMP GetOverlappedResult(OVERLAPPED *pOverlapped, BOOL bWait); + + // INDListen methods + STDMETHODIMP Listen(const struct sockaddr* pAddress, SIZE_T cbAddress, SIZE_T backlog); + STDMETHODIMP GetLocalAddress(struct sockaddr* pAddress, SIZE_T* pcbAddress); + STDMETHODIMP GetConnectionRequest(IUnknown* pConnector, OVERLAPPED* pOverlapped); + + CNDListen(CNDAdapter *pAdapter); + ~CNDListen(); + void Delete() {delete this;} + static STDMETHODIMP + CreateInstance(CNDAdapter *pAdapter, VOID** ppListen) + { + HRESULT hr; + CNDListen *listener; + + listener = new CNDListen(pAdapter); + if (listener == NULL) { + hr = ND_NO_MEMORY; + goto err1; + } + + *ppListen = listener; + return ND_SUCCESS; + + err1: + *ppListen = NULL; + return hr; + } + +protected: + CNDAdapter *m_pAdapter; + IWVConnectEndpoint *m_pWvConnEp; + + STDMETHODIMP Init(); +}; + +#endif // _ND_LISTEN_H_ diff --git a/branches/WOF2-3/ulp/netdirect2/user/nd_main.cpp b/branches/WOF2-3/ulp/netdirect2/user/nd_main.cpp new file mode 100644 index 00000000..e995d608 --- /dev/null +++ b/branches/WOF2-3/ulp/netdirect2/user/nd_main.cpp @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2009-2010 Intel Corporation. All rights reserved. + * Copyright (c) 2010 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include "nd_provider.h" + +HANDLE g_hHeap; +volatile LONG g_nRef; + +extern "C" { + +extern BOOL APIENTRY +_DllMainCRTStartupForGS(HINSTANCE h_module, DWORD ul_reason_for_call, + LPVOID lp_reserved); + + +BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) +{ + switch (dwReason) { + case DLL_PROCESS_ATTACH: + if (_DllMainCRTStartupForGS(hInstance, dwReason, lpReserved)) { + return FALSE; + } + + g_hHeap = HeapCreate(0, 0, 0); + return (g_hHeap != NULL); + case DLL_PROCESS_DETACH: + if (g_hHeap != NULL) { + HeapDestroy(g_hHeap); + } + return _DllMainCRTStartupForGS(hInstance, dwReason, lpReserved); + default: + return FALSE; + } +} + +STDAPI DllCanUnloadNow(void) +{ + return (g_nRef == 0) ? S_OK : S_FALSE; +} + +STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void** ppv) +{ + UNREFERENCED_PARAMETER(rclsid); + + if (riid != IID_INDProvider) { + *ppv = NULL; + return E_NOINTERFACE; + } + + return CNDProvider::CreateInstance(ppv); +} + +int WSPStartup(WORD wVersionRequested, LPWSPDATA lpWSPData, + LPWSAPROTOCOL_INFOW lpProtocolInfo, + WSPUPCALLTABLE UpcallTable, LPWSPPROC_TABLE lpProcTable) +{ + UNREFERENCED_PARAMETER(wVersionRequested); + UNREFERENCED_PARAMETER(lpWSPData); + UNREFERENCED_PARAMETER(lpProtocolInfo); + UNREFERENCED_PARAMETER(UpcallTable); + UNREFERENCED_PARAMETER(lpProcTable); + return WSASYSNOTREADY; +} + +} // extern "C" \ No newline at end of file diff --git a/branches/WOF2-3/ulp/netdirect2/user/nd_main.h b/branches/WOF2-3/ulp/netdirect2/user/nd_main.h new file mode 100644 index 00000000..9a892722 --- /dev/null +++ b/branches/WOF2-3/ulp/netdirect2/user/nd_main.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2009 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#ifndef _ND_MAIN_H_ +#define _ND_MAIN_H_ + +#include + +#endif // _ND_MAIN_H_ diff --git a/branches/WOF2-3/ulp/netdirect2/user/nd_mw.cpp b/branches/WOF2-3/ulp/netdirect2/user/nd_mw.cpp new file mode 100644 index 00000000..82338bcf --- /dev/null +++ b/branches/WOF2-3/ulp/netdirect2/user/nd_mw.cpp @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2009-2010 Intel Corporation. All rights reserved. + * Copyright (c) 2010 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "nd_mw.h" + + +CNDMemoryRegion::CNDMemoryRegion(CNDAdapter *pAdapter) +{ + pAdapter->AddRef(); + m_pAdapter = pAdapter; + RtlZeroMemory(&m_Keys, sizeof(m_Keys)); + m_pOverlapped = NULL; +} + +CNDMemoryRegion::~CNDMemoryRegion() +{ + m_pAdapter->Release(); +} + +STDMETHODIMP CNDMemoryRegion:: +QueryInterface(REFIID riid, LPVOID FAR* ppvObj) +{ + if (riid != IID_IUnknown && riid != IID_INDMemoryRegion) { + *ppvObj = NULL; + return E_NOINTERFACE; + } + + *ppvObj = this; + AddRef(); + return ND_SUCCESS; +} + +STDMETHODIMP_(ULONG) CNDMemoryRegion:: +AddRef(void) +{ + return CNDBase::AddRef(); +} + +STDMETHODIMP_(ULONG) CNDMemoryRegion:: +Release(void) +{ + return CNDBase::Release(); +} + +STDMETHODIMP CNDMemoryRegion:: +CancelOverlappedRequests(void) +{ + if (m_pOverlapped != NULL) { + CancelIoEx(m_pAdapter->GetFileHandle(), m_pOverlapped); + } + + return ND_SUCCESS; +} + +STDMETHODIMP CNDMemoryRegion:: +GetOverlappedResult(OVERLAPPED *pOverlapped, BOOL bWait) +{ + DWORD bytes; + HRESULT hr; + + hr = NDConvertWVStatus(m_pAdapter->m_pWvPd-> + GetOverlappedResult(pOverlapped, &bytes, bWait)); + if (hr != ND_PENDING) { + m_pOverlapped = NULL; + } + + return hr; +} + +DWORD CNDMemoryRegion:: +ConvertAccessFlags(DWORD Flags) +{ + DWORD opts = 0; + + if (Flags & ND_MR_FLAG_ALLOW_LOCAL_WRITE) { + opts |= WV_ACCESS_LOCAL_WRITE; + } + if (Flags & ND_MR_FLAG_ALLOW_REMOTE_READ) { + opts |= WV_ACCESS_REMOTE_READ | WV_ACCESS_MW_BIND; + } + if (Flags & ND_MR_FLAG_ALLOW_REMOTE_WRITE) { + opts |= WV_ACCESS_REMOTE_WRITE | WV_ACCESS_MW_BIND; + } + if (!(Flags & ND_MR_FLAG_DO_NOT_SECURE_VM)) { + opts |= WV_ACCESS_CACHABLE; + } + + return opts; +} + +STDMETHODIMP CNDMemoryRegion:: +Register(const VOID* pBuffer, SIZE_T cbBuffer, DWORD flags, OVERLAPPED* pOverlapped) +{ + HRESULT hr; + + m_pOverlapped = pOverlapped; + hr = m_pAdapter->m_pWvPd->RegisterMemory(pBuffer, cbBuffer, ConvertAccessFlags(flags), + pOverlapped, &m_Keys); + return NDConvertWVStatus(hr); +} + +STDMETHODIMP CNDMemoryRegion:: +Deregister(OVERLAPPED* pOverlapped) +{ + HRESULT hr; + + m_pOverlapped = pOverlapped; + hr = m_pAdapter->m_pWvPd->DeregisterMemory(m_Keys.Lkey, pOverlapped); + return NDConvertWVStatus(hr); +} + +STDMETHODIMP_(UINT32) CNDMemoryRegion:: +GetLocalToken() +{ + return m_Keys.Lkey; +} + +STDMETHODIMP_(UINT32) CNDMemoryRegion:: +GetRemoteToken() +{ + return m_Keys.Rkey; +} + + +CNDMemoryWindow::CNDMemoryWindow(CNDAdapter *pAdapter) +{ + pAdapter->AddRef(); + m_pAdapter = pAdapter; + m_pMr = NULL; +} + +CNDMemoryWindow::~CNDMemoryWindow() +{ + m_pAdapter->Release(); +} + +STDMETHODIMP CNDMemoryWindow:: +QueryInterface(REFIID riid, LPVOID FAR* ppvObj) +{ + if (riid != IID_IUnknown && riid != IID_INDMemoryWindow) { + *ppvObj = NULL; + return E_NOINTERFACE; + } + + *ppvObj = this; + AddRef(); + return ND_SUCCESS; +} + +STDMETHODIMP_(ULONG) CNDMemoryWindow:: +AddRef(void) +{ + return CNDBase::AddRef(); +} + +STDMETHODIMP_(ULONG) CNDMemoryWindow:: +Release(void) +{ + return CNDBase::Release(); +} + +STDMETHODIMP_(UINT32) CNDMemoryWindow:: +GetRemoteToken() +{ + return m_pMr->GetRemoteToken(); +} diff --git a/branches/WOF2-3/ulp/netdirect2/user/nd_mw.h b/branches/WOF2-3/ulp/netdirect2/user/nd_mw.h new file mode 100644 index 00000000..245addc1 --- /dev/null +++ b/branches/WOF2-3/ulp/netdirect2/user/nd_mw.h @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2009-2010 Intel Corporation. All rights reserved. + * Copyright (c) 2010 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#ifndef _ND_MW_H_ +#define _ND_MW_H_ + +#include +#include +#include "nd_base.h" +#include "nd_adapter.h" + +class CNDMemoryRegion : public INDMemoryRegion, public CNDBase +{ +public: + // IUnknown methods + STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + // INDOverlapped methods + STDMETHODIMP CancelOverlappedRequests(); + STDMETHODIMP GetOverlappedResult(OVERLAPPED *pOverlapped, BOOL bWait); + + // INDMemoryRegion methods + STDMETHODIMP Register(const VOID* pBuffer, SIZE_T cbBuffer, DWORD flags, + OVERLAPPED* pOverlapped); + STDMETHODIMP Deregister(OVERLAPPED* pOverlapped); + STDMETHODIMP_(UINT32) GetLocalToken(); + STDMETHODIMP_(UINT32) GetRemoteToken(); + + CNDMemoryRegion(CNDAdapter *m_pAdapter); + ~CNDMemoryRegion(); + void Delete() {delete this;} + static STDMETHODIMP + CreateInstance(CNDAdapter *pAdapter, VOID** ppMemoryRegion) + { + HRESULT hr; + CNDMemoryRegion *mr; + + mr = new CNDMemoryRegion(pAdapter); + if (mr == NULL) { + hr = ND_NO_MEMORY; + goto err; + } + + *ppMemoryRegion = mr; + return ND_SUCCESS; + + err: + *ppMemoryRegion = NULL; + return hr; + } + + WV_MEMORY_KEYS m_Keys; + +protected: + CNDAdapter *m_pAdapter; + OVERLAPPED *m_pOverlapped; + + DWORD ConvertAccessFlags(DWORD Flags); +}; + + +class CNDMemoryWindow : public INDMemoryWindow, public CNDBase +{ +public: + // IUnknown methods + STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + // INDMemoryWindow methods + STDMETHODIMP_(UINT32) GetRemoteToken(); + + CNDMemoryWindow(CNDAdapter *m_pAdapter); + ~CNDMemoryWindow(); + void Delete() {delete this;} + static STDMETHODIMP + CreateInstance(CNDAdapter *pAdapter, VOID** ppMemoryWindow) + { + HRESULT hr; + CNDMemoryWindow *mw; + + mw = new CNDMemoryWindow(pAdapter); + if (mw == NULL) { + hr = ND_NO_MEMORY; + goto err; + } + + *ppMemoryWindow = mw; + return ND_SUCCESS; + + err: + *ppMemoryWindow = NULL; + return hr; + } + + CNDMemoryRegion *m_pMr; + +protected: + CNDAdapter *m_pAdapter; +}; + +#endif // _ND_MW_H_ diff --git a/branches/WOF2-3/ulp/netdirect2/user/nd_provider.cpp b/branches/WOF2-3/ulp/netdirect2/user/nd_provider.cpp new file mode 100644 index 00000000..37362f70 --- /dev/null +++ b/branches/WOF2-3/ulp/netdirect2/user/nd_provider.cpp @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2009-2010 Intel Corporation. All rights reserved. + * Copyright (c) 2010 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "nd_provider.h" +#include "nd_adapter.h" +#include + +extern volatile LONG g_nRef; + + +CNDProvider::CNDProvider() +{ + m_pWvProvider = NULL; + InterlockedIncrement(&g_nRef); +} + +STDMETHODIMP CNDProvider:: +Init() +{ + HRESULT hr; + + hr = WvGetObject(IID_IWVProvider, (LPVOID *) &m_pWvProvider); + if (FAILED(hr)) { + return hr; + } + + if (!SetFileCompletionNotificationModes(m_pWvProvider->GetFileHandle(), + FILE_SKIP_COMPLETION_PORT_ON_SUCCESS | + FILE_SKIP_SET_EVENT_ON_HANDLE)) { + return HRESULT_FROM_WIN32(GetLastError()); + } + + return ND_SUCCESS; +} + +CNDProvider::~CNDProvider() +{ + if (m_pWvProvider) { + m_pWvProvider->Release(); + } + InterlockedDecrement(&g_nRef); +} + +STDMETHODIMP CNDProvider:: +QueryInterface(REFIID riid, LPVOID FAR* ppvObj) +{ + if (riid != IID_IUnknown && riid != IID_INDProvider) { + *ppvObj = NULL; + return E_NOINTERFACE; + } + + *ppvObj = this; + AddRef(); + return ND_SUCCESS; +} + +STDMETHODIMP_(ULONG) CNDProvider:: +AddRef(void) +{ + return CNDBase::AddRef(); +} + +STDMETHODIMP_(ULONG) CNDProvider:: +Release(void) +{ + return CNDBase::Release(); +} + +STDMETHODIMP CNDProvider:: +QueryAdapterAddressList(SOCKET_ADDRESS_LIST* pAddressList, + SIZE_T* pcbAddressList, UINT64 adapterId) +{ + WV_DEVICE_ADDRESS devaddr; + struct addrinfo *res, *ai; + HRESULT hr; + int cnt = 0; + size_t addrlen = 0, size; + UINT8 *offset; + + hr = getaddrinfo("..localmachine", NULL, NULL, &res); + if (hr) { + goto out; + } + + for (ai = res; ai; ai = ai->ai_next) { + ai->ai_flags = m_pWvProvider->TranslateAddress(ai->ai_addr, &devaddr); + if (SUCCEEDED(ai->ai_flags) && + ((adapterId == 0) || (adapterId == devaddr.DeviceGuid))) { + cnt++; + addrlen += ai->ai_addrlen; + } + } + + if (cnt == 0) { + *pcbAddressList = 0; + goto free; + } + + size = sizeof(SOCKET_ADDRESS_LIST) + sizeof(SOCKET_ADDRESS) * (cnt - 1); + if (size + addrlen > *pcbAddressList) { + *pcbAddressList = size + addrlen; + hr = ND_BUFFER_OVERFLOW; + goto free; + } + + pAddressList->iAddressCount = cnt; + offset = (UINT8 *) pAddressList + size; + for (cnt = 0, ai = res; ai; ai = ai->ai_next) { + if (SUCCEEDED(ai->ai_flags)) { + pAddressList->Address[cnt].iSockaddrLength = ai->ai_addrlen; + pAddressList->Address[cnt].lpSockaddr = (LPSOCKADDR) offset; + RtlCopyMemory(offset, ai->ai_addr, ai->ai_addrlen); + offset += ai->ai_addrlen; + } + } + +free: + freeaddrinfo(res); +out: + return NDConvertWVStatus(hr); +} + +STDMETHODIMP CNDProvider:: +QueryAddressList(SOCKET_ADDRESS_LIST* pAddressList, SIZE_T* pcbAddressList) +{ + return QueryAdapterAddressList(pAddressList, pcbAddressList, 0); +} + +STDMETHODIMP CNDProvider:: +ResolveAddress(const struct sockaddr* pAddress, SIZE_T cbAddress, UINT64* pAdapterId) +{ + WV_DEVICE_ADDRESS devaddr; + HRESULT hr; + + hr = m_pWvProvider->TranslateAddress(pAddress, &devaddr); + if (FAILED(hr)) { + return NDConvertWVStatus(hr); + } + + *pAdapterId = devaddr.DeviceGuid; + return ND_SUCCESS; +} + +STDMETHODIMP CNDProvider:: +OpenAdapter(REFIID iid, UINT64 adapterId, VOID** ppAdapter) +{ + if (iid != IID_INDAdapter) { + return E_NOINTERFACE; + } + + return CNDAdapter::CreateInstance(this, adapterId, ppAdapter); +} diff --git a/branches/WOF2-3/ulp/netdirect2/user/nd_provider.h b/branches/WOF2-3/ulp/netdirect2/user/nd_provider.h new file mode 100644 index 00000000..10d39008 --- /dev/null +++ b/branches/WOF2-3/ulp/netdirect2/user/nd_provider.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2009-2010 Intel Corporation. All rights reserved. + * Copyright (c) 2010 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#ifndef _ND_PROVIDER_H_ +#define _ND_PROVIDER_H_ + +#include +#include +#include "nd_base.h" + +class CNDProvider : public INDProvider, public CNDBase +{ +public: + // IUnknown methods + STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + // INDProvider methods + STDMETHODIMP QueryAddressList(SOCKET_ADDRESS_LIST* pAddressList, + SIZE_T* pcbAddressList); + STDMETHODIMP ResolveAddress(const struct sockaddr* pAddress, + SIZE_T cbAddress, UINT64* pAdapterId); + STDMETHODIMP OpenAdapter(REFIID iid, UINT64 adapterId, VOID** ppAdapter); + + CNDProvider(); + ~CNDProvider(); + + void Delete() {delete this;} + static STDMETHODIMP + CreateInstance(VOID** ppProvider) + { + HRESULT hr; + CNDProvider *provider; + + provider = new CNDProvider(); + if (provider == NULL) { + hr = ND_NO_MEMORY; + goto err1; + } + + hr = provider->Init(); + if (FAILED(hr)) { + goto err2; + } + + *ppProvider = provider; + return ND_SUCCESS; + + err2: + provider->Release(); + err1: + *ppProvider = NULL; + return hr; + } + + STDMETHODIMP QueryAdapterAddressList(SOCKET_ADDRESS_LIST* pAddressList, + SIZE_T* pcbAddressList, UINT64 adapterId); + IWVProvider *m_pWvProvider; + +private: + STDMETHODIMP Init(); +}; + +#endif // _ND_PROVIDER_H_ \ No newline at end of file diff --git a/branches/WOF2-3/ulp/netdirect2/user/nd_qp.cpp b/branches/WOF2-3/ulp/netdirect2/user/nd_qp.cpp new file mode 100644 index 00000000..da66de81 --- /dev/null +++ b/branches/WOF2-3/ulp/netdirect2/user/nd_qp.cpp @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2009-2010 Intel Corporation. All rights reserved. + * Copyright (c) 2010 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "nd_qp.h" +#include "nd_adapter.h" +#include "nd_connect.h" +#include "nd_cq.h" +#include "nd_mw.h" +#include + + +CNDQueuePair::CNDQueuePair(CNDAdapter *pAdapter) +{ + pAdapter->AddRef(); + m_pAdapter = pAdapter; + m_pWvQp = NULL; + m_pReceiveCq = NULL; + m_pSendCq = NULL; +} + +STDMETHODIMP CNDQueuePair:: +Init(CNDCompletionQueue* pReceiveCompletionQueue, + CNDCompletionQueue* pInitiatorCompletionQueue, + CNDSharedReceiveQueue *pSharedReceiveQueue, + VOID* context, DWORD receiveQueueDepth, DWORD initiatorQueueDepth, + DWORD maxReceiveRequestSGE, DWORD maxInitiatorRequestSGE) +{ + WV_QP_CREATE create; + WV_QP_ATTRIBUTES attr; + DWORD opts; + HRESULT hr; + + RtlZeroMemory(&create, sizeof create); + m_pReceiveCq = pReceiveCompletionQueue; + m_pSendCq = pInitiatorCompletionQueue; + m_pReceiveCq->AddRef(); + m_pSendCq->AddRef(); + if ((m_pSrq = pSharedReceiveQueue)) { + m_pSrq->AddRef(); + create.pSharedReceiveQueue = m_pSrq->m_pWvSrq; + } + + create.pSendCq = m_pSendCq->m_pWvCq; + create.pReceiveCq = m_pReceiveCq->m_pWvCq; + create.Context = context; + create.SendDepth = initiatorQueueDepth; + create.SendSge = maxInitiatorRequestSGE; + create.ReceiveDepth = receiveQueueDepth; + create.ReceiveSge = maxReceiveRequestSGE; + create.MaxInlineSend = m_pAdapter->m_MaxInlineSend; + create.QpType = WvQpTypeRc; + + hr = m_pAdapter->m_pWvPd->CreateConnectQueuePair(&create, &m_pWvQp); + if (FAILED(hr)) { + return NDConvertWVStatus(hr); + } + + opts = WV_QP_ATTR_STATE | WV_QP_ATTR_PORT_NUMBER | WV_QP_ATTR_PKEY_INDEX; + attr.QpState = WvQpStateInit; + attr.PkeyIndex = 0; + attr.AddressVector.PortNumber = 1; + + hr = m_pWvQp->Modify(&attr, opts, NULL); + if (FAILED(hr)) { + return NDConvertWVStatus(hr); + } + + return ND_SUCCESS; +} + +CNDQueuePair::~CNDQueuePair() +{ + if (m_pWvQp != NULL) { + m_pWvQp->Release(); + } + if (m_pReceiveCq != NULL) { + m_pReceiveCq->Release(); + } + if (m_pSendCq != NULL) { + m_pSendCq->Release(); + } + if (m_pSrq != NULL) { + m_pSrq->Release(); + } + m_pAdapter->Release(); +} + +STDMETHODIMP CNDQueuePair:: +QueryInterface(REFIID riid, LPVOID FAR* ppvObj) +{ + if (riid != IID_IUnknown && riid != IID_INDQueuePair) { + *ppvObj = NULL; + return E_NOINTERFACE; + } + + *ppvObj = this; + AddRef(); + return ND_SUCCESS; +} + +STDMETHODIMP_(ULONG) CNDQueuePair:: +AddRef(void) +{ + return CNDBase::AddRef(); +} + +STDMETHODIMP_(ULONG) CNDQueuePair:: +Release(void) +{ + return CNDBase::Release(); +} + +STDMETHODIMP CNDQueuePair:: +Flush(void) +{ + WV_QP_ATTRIBUTES attr; + HRESULT hr; + + attr.QpState = WvQpStateError; + hr = m_pWvQp->Modify(&attr, WV_QP_ATTR_STATE, NULL); + return NDConvertWVStatus(hr); +} + +STDMETHODIMP_(DWORD) CNDQueuePair:: +ConvertSendFlags(DWORD Flags) +{ + DWORD opts = 0; + + if (!(Flags & ND_OP_FLAG_SILENT_SUCCESS)) { + opts |= WV_SEND_SIGNALED; + } + if (Flags & ND_OP_FLAG_READ_FENCE) { + opts |= WV_SEND_FENCE; + } + if (Flags & ND_OP_FLAG_SEND_AND_SOLICIT_EVENT) { + opts |= WV_SEND_SOLICITED; + } + if (Flags & ND_OP_FLAG_INLINE) { + opts |= WV_SEND_INLINE; + } + return opts; +} + +STDMETHODIMP CNDQueuePair:: +Send(VOID* requestContext, const ND_SGE* pSge, DWORD nSge, DWORD flags) +{ + HRESULT hr; + + hr = m_pWvQp->Send((UINT64) (ULONG_PTR) requestContext, (WV_SGE *) pSge, nSge, + ConvertSendFlags(flags), 0); + return NDConvertWVStatus(hr); +} + +STDMETHODIMP CNDQueuePair:: +Receive(VOID* requestContext, const ND_SGE* pSge, DWORD nSge) +{ + HRESULT hr; + + hr = m_pWvQp->PostReceive((UINT64) (ULONG_PTR) requestContext, (WV_SGE *) pSge, nSge); + return NDConvertWVStatus(hr); +} + +STDMETHODIMP CNDQueuePair:: +Bind(VOID* requestContext, IUnknown* pMemoryRegion, + IUnknown* pMemoryWindow, const VOID* pBuffer, SIZE_T cbBuffer, + DWORD flags) +{ + CNDMemoryRegion *mr = (CNDMemoryRegion *) pMemoryRegion; + CNDMemoryWindow *mw = (CNDMemoryWindow *) pMemoryWindow; + HRESULT hr; + + if (mw->m_pMr != NULL) { + mw->m_pMr->Release(); + } + mw->m_pMr = mr; + mr->AddRef(); + hr = m_pWvQp->Write((UINT64) (ULONG_PTR) requestContext, NULL, 0, + ConvertSendFlags(flags), 0, 0, 0); + return NDConvertWVStatus(hr); +} + +STDMETHODIMP CNDQueuePair:: +Invalidate(VOID* requestContext, IUnknown* pMemoryWindow, DWORD flags) +{ + CNDMemoryWindow *mw = (CNDMemoryWindow *) pMemoryWindow; + HRESULT hr; + + mw->m_pMr->Release(); + mw->m_pMr = NULL; + hr = m_pWvQp->Write((UINT64) (ULONG_PTR) requestContext, NULL, 0, + ConvertSendFlags(flags), 0, 0, 0); + return NDConvertWVStatus(hr); +} + +STDMETHODIMP CNDQueuePair:: +Read(VOID* requestContext, const ND_SGE* pSge, DWORD nSge, + UINT64 remoteAddress, UINT32 remoteToken, DWORD flags) +{ + DWORD opts; + HRESULT hr; + + hr = m_pWvQp->Read((UINT64) (ULONG_PTR) requestContext, (WV_SGE *) pSge, nSge, + ConvertSendFlags(flags), htonll(remoteAddress), remoteToken); + return NDConvertWVStatus(hr); +} + +STDMETHODIMP CNDQueuePair:: +Write(VOID* requestContext, const ND_SGE* pSge, DWORD nSge, + UINT64 remoteAddress, UINT32 remoteToken, DWORD flags) +{ + DWORD opts; + HRESULT hr; + + hr = m_pWvQp->Write((UINT64) (ULONG_PTR) requestContext, (WV_SGE *) pSge, nSge, + ConvertSendFlags(flags), 0, htonll(remoteAddress), remoteToken); + return NDConvertWVStatus(hr); +} diff --git a/branches/WOF2-3/ulp/netdirect2/user/nd_qp.h b/branches/WOF2-3/ulp/netdirect2/user/nd_qp.h new file mode 100644 index 00000000..c986e847 --- /dev/null +++ b/branches/WOF2-3/ulp/netdirect2/user/nd_qp.h @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2009-2010 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#ifndef _ND_QUEUEPAIR_H_ +#define _ND_QUEUEPAIR_H_ + +#include +#include +#include "nd_base.h" +#include "nd_cq.h" +#include "nd_srq.h" +#include "nd_adapter.h" + + +class CNDQueuePair : public INDQueuePair, public CNDBase +{ +public: + // IUnknown methods + STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + // INDQueuePair methods + STDMETHODIMP Flush(); + STDMETHODIMP Send(VOID* requestContext, const ND_SGE* pSge, DWORD nSge, DWORD flags); + STDMETHODIMP Receive(VOID* requestContext, const ND_SGE* pSge, DWORD nSge); + STDMETHODIMP Bind(VOID* requestContext, IUnknown* pMemoryRegion, + IUnknown* pMemoryWindow, const VOID* pBuffer, SIZE_T cbBuffer, + DWORD flags); + STDMETHODIMP Invalidate(VOID* requestContext, IUnknown* pMemoryWindow, DWORD flags); + STDMETHODIMP Read(VOID* requestContext, const ND_SGE* pSge, DWORD nSge, + UINT64 remoteAddress, UINT32 remoteToken, DWORD flags); + STDMETHODIMP Write(VOID* requestContext, const ND_SGE* pSge, DWORD nSge, + UINT64 remoteAddress, UINT32 remoteToken, DWORD flags); + + CNDQueuePair(CNDAdapter *pAdapter); + ~CNDQueuePair(); + void Delete() {delete this;} + static STDMETHODIMP + CreateInstance(CNDAdapter *pAdapter, + CNDCompletionQueue* pReceiveCompletionQueue, + CNDCompletionQueue* pInitiatorCompletionQueue, + CNDSharedReceiveQueue *pSharedReceiveQueue, + VOID* context, DWORD receiveQueueDepth, DWORD initiatorQueueDepth, + DWORD maxReceiveRequestSge, DWORD maxInitiatorRequestSge, + VOID** ppQueuePair) + { + HRESULT hr; + CNDQueuePair *qp; + + qp = new CNDQueuePair(pAdapter); + if (qp == NULL) { + hr = ND_NO_MEMORY; + goto err1; + } + + hr = qp->Init(pReceiveCompletionQueue, pInitiatorCompletionQueue, + pSharedReceiveQueue, context, receiveQueueDepth, + initiatorQueueDepth, maxReceiveRequestSge, maxInitiatorRequestSge); + if (FAILED(hr)) { + goto err2; + } + + *ppQueuePair = qp; + return ND_SUCCESS; + + err2: + qp->Release(); + err1: + *ppQueuePair = NULL; + return hr; + } + + IWVConnectQueuePair *m_pWvQp; + +protected: + CNDAdapter *m_pAdapter; + CNDCompletionQueue *m_pReceiveCq; + CNDCompletionQueue *m_pSendCq; + CNDSharedReceiveQueue *m_pSrq; + + STDMETHODIMP Init(CNDCompletionQueue* pReceiveCompletionQueue, + CNDCompletionQueue* pInitiatorCompletionQueue, + CNDSharedReceiveQueue *pSharedReceiveQueue, + VOID* context, DWORD receiveQueueDepth, DWORD initiatorQueueDepth, + DWORD maxReceiveRequestSge, DWORD maxInitiatorRequestSge); + STDMETHODIMP_(DWORD) ConvertSendFlags(DWORD Flags); +}; + +#endif // _ND_QUEUEPAIR_H_ diff --git a/branches/WOF2-3/ulp/netdirect2/user/nd_srq.cpp b/branches/WOF2-3/ulp/netdirect2/user/nd_srq.cpp new file mode 100644 index 00000000..a3073040 --- /dev/null +++ b/branches/WOF2-3/ulp/netdirect2/user/nd_srq.cpp @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2009-2010 Intel Corporation. All rights reserved. + * Copyright (c) 2010 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "nd_srq.h" + + +CNDSharedReceiveQueue::CNDSharedReceiveQueue(CNDAdapter *pAdapter) +{ + pAdapter->AddRef(); + m_pAdapter = pAdapter; + m_pWvSrq = NULL; +} + +STDMETHODIMP CNDSharedReceiveQueue:: +Init(DWORD queueDepth, DWORD maxSGE, DWORD notifyThreshold, + USHORT group, KAFFINITY affinity) +{ + HRESULT hr; + + hr = m_pAdapter->m_pWvPd->CreateSharedReceiveQueue(queueDepth, maxSGE, + notifyThreshold, &m_pWvSrq); + return NDConvertWVStatus(hr); +} + +CNDSharedReceiveQueue::~CNDSharedReceiveQueue() +{ + if (m_pWvSrq != NULL) { + m_pWvSrq->Release(); + } + m_pAdapter->Release(); +} + +STDMETHODIMP CNDSharedReceiveQueue:: +QueryInterface(REFIID riid, LPVOID FAR* ppvObj) +{ + if (riid != IID_IUnknown && riid != IID_INDSharedReceiveQueue) { + *ppvObj = NULL; + return E_NOINTERFACE; + } + + *ppvObj = this; + AddRef(); + return ND_SUCCESS; +} + +STDMETHODIMP_(ULONG) CNDSharedReceiveQueue:: +AddRef(void) +{ + return CNDBase::AddRef(); +} + +STDMETHODIMP_(ULONG) CNDSharedReceiveQueue:: +Release(void) +{ + return CNDBase::Release(); +} + +STDMETHODIMP CNDSharedReceiveQueue:: +CancelOverlappedRequests(void) +{ + HRESULT hr; + + hr = m_pWvSrq->CancelOverlappedRequests(); + return NDConvertWVStatus(hr); +} + +STDMETHODIMP CNDSharedReceiveQueue:: +GetOverlappedResult(OVERLAPPED *pOverlapped, BOOL bWait) +{ + DWORD bytes; + HRESULT hr; + + hr = m_pWvSrq->GetOverlappedResult(pOverlapped, &bytes, bWait); + return NDConvertWVStatus(hr); +} + +STDMETHODIMP CNDSharedReceiveQueue:: +GetNotifyAffinity(USHORT *pGroup, KAFFINITY* pAffinity) +{ + return ND_NOT_SUPPORTED; +} + +STDMETHODIMP CNDSharedReceiveQueue:: +Modify(DWORD queueDepth, DWORD notifyThreshold) +{ + HRESULT hr; + + hr = m_pWvSrq->Modify(queueDepth, notifyThreshold); + return NDConvertWVStatus(hr); +} + +STDMETHODIMP CNDSharedReceiveQueue:: +Notify(OVERLAPPED* pOverlapped) +{ + HRESULT hr; + + hr = m_pWvSrq->Notify(pOverlapped); + return NDConvertWVStatus(hr); +} + +#ifdef _WIN64 + +C_ASSERT(sizeof(WV_SGE) == sizeof(ND_SGE)); +C_ASSERT(FIELD_OFFSET(WV_SGE, pAddress) == FIELD_OFFSET(ND_SGE, Buffer)); +C_ASSERT(RTL_FIELD_SIZE(WV_SGE, pAddress) == RTL_FIELD_SIZE(ND_SGE, Buffer)); +C_ASSERT(FIELD_OFFSET(WV_SGE, Length) == FIELD_OFFSET(ND_SGE, BufferLength)); +C_ASSERT(RTL_FIELD_SIZE(WV_SGE, Length) == RTL_FIELD_SIZE(ND_SGE, BufferLength)); +C_ASSERT(FIELD_OFFSET(WV_SGE, Lkey) == FIELD_OFFSET(ND_SGE, MemoryRegionToken)); +C_ASSERT(RTL_FIELD_SIZE(WV_SGE, Lkey) == RTL_FIELD_SIZE(ND_SGE, MemoryRegionToken)); + +STDMETHODIMP CNDSharedReceiveQueue:: +Receive(VOID* requestContext, const ND_SGE* pSge, DWORD nSge) +{ + HRESULT hr; + + hr = m_pWvSrq->PostReceive((UINT64) (ULONG_PTR) requestContext, (WV_SGE *) pSge, nSge); + return NDConvertWVStatus(hr); +} + +#else + +STDMETHODIMP CNDSharedReceiveQueue:: +Receive(VOID* requestContext, const ND_SGE* pSge, DWORD nSge) +{ + WV_SGE sgl[4]; + WV_SGE *sge; + DWORD i; + HRESULT hr; + + if (nSge > _countof(sgl)) { + sge = new WV_SGE[nSge]; + if (sge == NULL) { + return ND_NO_MEMORY; + } + } else { + sge = sgl; + } + + for (i = 0; i < nSge; i++) { + sge->pAddress = pSge[i].Buffer; + sge->Length = pSge[i].BufferLength; + sge->Lkey = pSge[i].MemoryRegionToken; + } + + hr = m_pWvSrq->PostReceive((UINT64) (ULONG_PTR) requestContext, sge, nSge); + if (nSge > _countof(sgl)) { + delete[] sge; + } + return NDConvertWVStatus(hr); +} + +#endif \ No newline at end of file diff --git a/branches/WOF2-3/ulp/netdirect2/user/nd_srq.h b/branches/WOF2-3/ulp/netdirect2/user/nd_srq.h new file mode 100644 index 00000000..cf1ec70e --- /dev/null +++ b/branches/WOF2-3/ulp/netdirect2/user/nd_srq.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2009-2010 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#ifndef _ND_SRQ_H_ +#define _ND_SRQ_H_ + +#include +#include +#include "nd_base.h" +#include "nd_adapter.h" + + +class CNDSharedReceiveQueue : public INDSharedReceiveQueue, public CNDBase +{ +public: + // IUnknown methods + STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + // INDOverlapped methods + STDMETHODIMP CancelOverlappedRequests(); + STDMETHODIMP GetOverlappedResult(OVERLAPPED *pOverlapped, BOOL bWait); + + // INDSharedReceiveQueue methods + STDMETHODIMP GetNotifyAffinity(USHORT *pGroup, KAFFINITY* pAffinity); + STDMETHODIMP Modify(DWORD queueDepth, DWORD notifyThreshold); + STDMETHODIMP Notify(OVERLAPPED* pOverlapped); + STDMETHODIMP Receive(VOID* requestContext, const ND_SGE* pSge, DWORD nSge); + + CNDSharedReceiveQueue(CNDAdapter *pAdapter); + ~CNDSharedReceiveQueue(); + void Delete() {delete this;} + static STDMETHODIMP + CreateInstance(CNDAdapter *pAdapter, DWORD queueDepth, DWORD maxSge, + DWORD notifyThreshold, USHORT group, KAFFINITY affinity, + VOID** ppSharedReceiveQueue) + { + HRESULT hr; + CNDSharedReceiveQueue *srq; + + srq = new CNDSharedReceiveQueue(pAdapter); + if (srq == NULL) { + hr = ND_NO_MEMORY; + goto err1; + } + + hr = srq->Init(queueDepth, maxSge, notifyThreshold, group, affinity); + if (FAILED(hr)) { + goto err2; + } + + *ppSharedReceiveQueue = srq; + return ND_SUCCESS; + + err2: + srq->Release(); + err1: + *ppSharedReceiveQueue = NULL; + return hr; + } + + IWVSharedReceiveQueue *m_pWvSrq; + +protected: + CNDAdapter *m_pAdapter; + + STDMETHODIMP Init(DWORD queueDepth, DWORD maxSge, DWORD notifyThreshold, + USHORT group, KAFFINITY affinity); +}; + +#endif // _ND_SRQ_H_ diff --git a/branches/WOF2-3/ulp/netdirect2/user/netdirect.rc b/branches/WOF2-3/ulp/netdirect2/user/netdirect.rc new file mode 100644 index 00000000..7ed0d78b --- /dev/null +++ b/branches/WOF2-3/ulp/netdirect2/user/netdirect.rc @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2008 Intel Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + +#include + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef _DEBUG_ +#define VER_FILEDESCRIPTION_STR "OpenFabrics Winverbs Network Direct Provider (Debug)" +#define VER_INTERNALNAME_STR "wvndprovd.dll" +#define VER_ORIGINALFILENAME_STR "wvndprovd.dll" +#else +#define VER_FILEDESCRIPTION_STR "OpenFabrics Winverbs Network Direct Provider" +#define VER_INTERNALNAME_STR "wvndprov.dll" +#define VER_ORIGINALFILENAME_STR "wvndprov.dll" +#endif + +#include diff --git a/branches/WOF2-3/ulp/opensm/dirs b/branches/WOF2-3/ulp/opensm/dirs new file mode 100644 index 00000000..389156fd --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/dirs @@ -0,0 +1,2 @@ +DIRS=\ + user diff --git a/branches/WOF2-3/ulp/opensm/user/AUTHORS b/branches/WOF2-3/ulp/opensm/user/AUTHORS new file mode 100644 index 00000000..7f5d6cb7 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/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/branches/WOF2-3/ulp/opensm/user/README b/branches/WOF2-3/ulp/opensm/user/README new file mode 100644 index 00000000..55a837fe --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/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/branches/WOF2-3/ulp/opensm/user/README.windows b/branches/WOF2-3/ulp/opensm/user/README.windows new file mode 100644 index 00000000..c9221693 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/README.windows @@ -0,0 +1,111 @@ +OpenSM for Windows: last updated [6-21-10] +-------------------------------------------------- + +OpenSM provides a user-mode implementation for an InfiniBand Subnet Manager and +Administrator. Such a software entity is required to run in order to +initialize the InfiniBand hardware (at least one SM per each InfiniBand subnet). + +The full list of OpenSM features is described in the user manual +provided in the doc/ directory. + +The installation of OpenSM includes: + +%ProgramFiles%\OFED\ + opensm.exe - the SM/SA executable + osmtest.exe - a test program for the SM/SA + +The standard OFED installation creates an OpenSM Windows Service which is +inactive by default. If one chooses the install feature 'Startup OpenSM' then +the OpenSM Windows Service is reset to start automatically at System boot. +Multiple OpenSM instances within a fabric are supported; the last OpenSM +invocation will be the MASTER opensm, while others will be in STANDBY mode +awaiting the demise of the MASTER opensm instance. + + +Building opensm.exe, osmtest.exe from the SVN tree with MSFT WDK 7600.16385.1 +----------------------------------------------------------------------------- + cd trunk\ulp\opensm + build /wg + +Note the file trunk\ulp\opensm\mad-vendor.inc controls which vendor +(IBAL or UMAD) is built with. Currently both vendors have been tested and +pass all osm tests (osmtest, saquery PR) along with configuring a 52 node +Windows HPC Edition cluster. +The preferred vendor is UMAD as this is the vendor which is utilized by the +OFED for Linux opensm build; therefore the UMAD vendor has seen the largest +number of nodes and operational hours. + + +OpenSM 3.3.6 status +------------- + +openSM 3.3.6 [vendor-IBAL] configured a 53 node HPC fabric runing Intel MPI regression tests. +All osmtests pass successfully; see 'opensm\user\scripts\osm-regress.bat'. + +The openSM as a service is functioning correctly; the OpenSM log file resides in +%TEMP\osm.log which translates to %windir%\temp\osm.log when run as a service. +Additionally %TEMP\osm.syslog or '%windir%\temp\osm.syslog', when run as a service, exists +as a high level record of OpenSM events; where osm.log contains more detailed information +which controlled by opensm.exe -V and/or -D command line switches. + +The log path is now static in definition as the usage output changed which no +longer allowed calls to GetTempPath(). In order to work around this fopen() +is actually a macro which redirects to Fopen(). The difference being Fopen() +will strdup_expand() the filename argument and then call the Windows version +of fopen(). This approach allows filenames like '%TEMP%\osm.log' to be properly +expanded and opened without excessive code changes to filenames. + +The osm vendor is 'IBAL' until UMAD QP1/SA interfaces are debugged. +The include file user\mad-vendor.inc define which osm vendor is being built/used. +Make sure all SOURCES files are using the same vendor! + + + +OpenSM Code Base +---------------- + +OpenSM src is based on the OFED management\opensm sources for the 3.3.6 release. + +Based-on implies the following build processes: + + If you use the [ANNOUNCE]'d management (OpenSM and infiniband diagnostics) + tarballs, the lex/yacc and config files are already constructed: + see http://www.openfabrics.org/downloads/management/ + (listed in http://www.openfabrics.org/downloads/management/latest.txt) + + otherwise + + From the OFED management maintainers git repository on a Linux system + 1) git clone git://git.openfabrics.org/~sashak/management + 2) cd management/libibumad; ./autogen.sh && ./configure && make + 3) cd management/libibmad; ./autogen.sh && ./configure && make + 4) cd management/opensm; ./autogen.sh && ./configure && make + 5) remove *.o *.po *.lo .deps/ .libs/ + 6) tar zcf ofed-mgmt.tgz management + 7) Move the ofed-mgmt.tgz tarball to a Windows system where current + Windows opensm src resides. + 8) unzip tar ball + 9) diff trunk\ulp\opensm management\opensm + + 10) Carefully apply/reject changes. + There are a few (<30) differing files which the OFED community + declined to accept due to Windows orientation; an ongoing story...sigh. + The bigger change blocks are found in the following files: + opensm\main.c OpenSM as a Windows service support. + opensm\console.c Windows console support without poll(). + libvendor\osm_vendor_al.c + Makefile(s) are Windows specific; leave'em be. + + 10) Due to the usage of Linux only tools AutoTools, lex & yacc, the + following files are static in the windows src. Static in the sense the + files are configured in the Linux environment with the resultant .c .h + files moved into the Windows opensm src tree. + Watch out for differing versions of yacc/bison/lex. The .y & .l files + are modified in the Windows src to emphasize changes required in the + .c & .h files; basically minor changes. + + a) management/opensm/opensm/osm_qow_parser_y.y + b) management/opensm/opensm/osm_qos_parser_l.l + c) management/opensm/opensm/configure.h + d) management/opensm/include/opensm/osm_version.h + diff --git a/branches/WOF2-3/ulp/opensm/user/complib/README.txt b/branches/WOF2-3/ulp/opensm/user/complib/README.txt new file mode 100644 index 00000000..abc98b42 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/complib/README.txt @@ -0,0 +1,6 @@ + + +******* DO NOT Confuse this complib\ with trunk\core\complib; trunk\core\complib\ and + trunk\inc\complib are the prefered versions and searched 1st. + +This complib\ exists only for OFED openSM code compatibility. \ No newline at end of file diff --git a/branches/WOF2-3/ulp/opensm/user/complib/cl_dispatcher.c b/branches/WOF2-3/ulp/opensm/user/complib/cl_dispatcher.c new file mode 100644 index 00000000..d09c9b3c --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/complib/cl_dispatcher.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. + * + */ + +/* + * Abstract: + * Implementation of Dispatcher abstraction. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include + +/* give some guidance when we build our cl_pool of messages */ +#define CL_DISP_INITIAL_MSG_COUNT 256 +#define CL_DISP_MSG_GROW_SIZE 64 + +/* give some guidance when we build our cl_pool of registration elements */ +#define CL_DISP_INITIAL_REG_COUNT 16 +#define CL_DISP_REG_GROW_SIZE 16 + +/******************************************************************** + __cl_disp_worker + + Description: + This function takes messages off the FIFO and calls Processmsg() + This function executes as passive level. + + Inputs: + p_disp - Pointer to Dispatcher object + + Outputs: + None + + Returns: + None +********************************************************************/ +void __cl_disp_worker(IN void *context) +{ + cl_disp_msg_t *p_msg; + cl_dispatcher_t *p_disp = (cl_dispatcher_t *) context; + + cl_spinlock_acquire(&p_disp->lock); + + /* Process the FIFO until we drain it dry. */ + while (cl_qlist_count(&p_disp->msg_fifo)) { + /* Pop the message at the head from the FIFO. */ + p_msg = + (cl_disp_msg_t *) cl_qlist_remove_head(&p_disp->msg_fifo); + + /* we track the tim ethe last message spent in the queue */ + p_disp->last_msg_queue_time_us = + cl_get_time_stamp() - p_msg->in_time; + + /* + * Release the spinlock while the message is processed. + * The user's callback may reenter the dispatcher + * and cause the lock to be reaquired. + */ + cl_spinlock_release(&p_disp->lock); + p_msg->p_dest_reg->pfn_rcv_callback((void *)p_msg->p_dest_reg-> + context, + (void *)p_msg->p_data); + + cl_atomic_dec(&p_msg->p_dest_reg->ref_cnt); + + /* The client has seen the data. Notify the sender as appropriate. */ + if (p_msg->pfn_xmt_callback) { + p_msg->pfn_xmt_callback((void *)p_msg->context, + (void *)p_msg->p_data); + cl_atomic_dec(&p_msg->p_src_reg->ref_cnt); + } + + /* Grab the lock for the next iteration through the list. */ + cl_spinlock_acquire(&p_disp->lock); + + /* Return this message to the pool. */ + cl_qpool_put(&p_disp->msg_pool, (cl_pool_item_t *) p_msg); + } + + cl_spinlock_release(&p_disp->lock); +} + +void cl_disp_construct(IN cl_dispatcher_t * const p_disp) +{ + CL_ASSERT(p_disp); + + cl_qlist_init(&p_disp->reg_list); + cl_ptr_vector_construct(&p_disp->reg_vec); + cl_qlist_init(&p_disp->msg_fifo); + cl_spinlock_construct(&p_disp->lock); + cl_qpool_construct(&p_disp->msg_pool); +} + +void cl_disp_shutdown(IN cl_dispatcher_t * const p_disp) +{ + CL_ASSERT(p_disp); + + /* Stop the thread pool. */ + cl_thread_pool_destroy(&p_disp->worker_threads); + + /* Process all outstanding callbacks. */ + __cl_disp_worker(p_disp); + + /* Free all registration info. */ + while (!cl_is_qlist_empty(&p_disp->reg_list)) + free(cl_qlist_remove_head(&p_disp->reg_list)); +} + +void cl_disp_destroy(IN cl_dispatcher_t * const p_disp) +{ + CL_ASSERT(p_disp); + + cl_spinlock_destroy(&p_disp->lock); + /* Destroy the message pool */ + cl_qpool_destroy(&p_disp->msg_pool); + /* Destroy the pointer vector of registrants. */ + cl_ptr_vector_destroy(&p_disp->reg_vec); +} + +cl_status_t cl_disp_init(IN cl_dispatcher_t * const p_disp, + IN const uint32_t thread_count, + IN const char *const name) +{ + cl_status_t status; + + CL_ASSERT(p_disp); + + cl_disp_construct(p_disp); + + status = cl_spinlock_init(&p_disp->lock); + if (status != CL_SUCCESS) { + cl_disp_destroy(p_disp); + return (status); + } + + /* Specify no upper limit to the number of messages in the pool */ + status = cl_qpool_init(&p_disp->msg_pool, CL_DISP_INITIAL_MSG_COUNT, + 0, CL_DISP_MSG_GROW_SIZE, sizeof(cl_disp_msg_t), + NULL, NULL, NULL); + if (status != CL_SUCCESS) { + cl_disp_destroy(p_disp); + return (status); + } + + status = cl_ptr_vector_init(&p_disp->reg_vec, CL_DISP_INITIAL_REG_COUNT, + CL_DISP_REG_GROW_SIZE); + if (status != CL_SUCCESS) { + cl_disp_destroy(p_disp); + return (status); + } + + status = cl_thread_pool_init(&p_disp->worker_threads, thread_count, + __cl_disp_worker, p_disp, name); + if (status != CL_SUCCESS) + cl_disp_destroy(p_disp); + + return (status); +} + +cl_disp_reg_handle_t cl_disp_register(IN cl_dispatcher_t * const p_disp, + IN const cl_disp_msgid_t msg_id, + IN cl_pfn_msgrcv_cb_t pfn_callback + OPTIONAL, + IN const void *const context OPTIONAL) +{ + cl_disp_reg_info_t *p_reg; + cl_status_t status; + + CL_ASSERT(p_disp); + + /* Check that the requested registrant ID is available. */ + cl_spinlock_acquire(&p_disp->lock); + if ((msg_id != CL_DISP_MSGID_NONE) && + (msg_id < cl_ptr_vector_get_size(&p_disp->reg_vec)) && + (cl_ptr_vector_get(&p_disp->reg_vec, msg_id))) { + cl_spinlock_release(&p_disp->lock); + return (NULL); + } + + /* Get a registration info from the pool. */ + p_reg = (cl_disp_reg_info_t *) malloc(sizeof(cl_disp_reg_info_t)); + if (!p_reg) { + cl_spinlock_release(&p_disp->lock); + return (NULL); + } else { + memset(p_reg, 0, sizeof(cl_disp_reg_info_t)); + } + + p_reg->p_disp = p_disp; + p_reg->ref_cnt = 0; + p_reg->pfn_rcv_callback = pfn_callback; + p_reg->context = context; + p_reg->msg_id = msg_id; + + /* Insert the registration in the list. */ + cl_qlist_insert_tail(&p_disp->reg_list, (cl_list_item_t *) p_reg); + + /* Set the array entry to the registrant. */ + /* The ptr_vector grow automatically as necessary. */ + if (msg_id != CL_DISP_MSGID_NONE) { + status = cl_ptr_vector_set(&p_disp->reg_vec, msg_id, p_reg); + if (status != CL_SUCCESS) { + free(p_reg); + cl_spinlock_release(&p_disp->lock); + return (NULL); + } + } + + cl_spinlock_release(&p_disp->lock); + + return (p_reg); +} + +void cl_disp_unregister(IN const cl_disp_reg_handle_t handle) +{ + cl_disp_reg_info_t *p_reg; + cl_dispatcher_t *p_disp; + + if (handle == CL_DISP_INVALID_HANDLE) + return; + + p_reg = (cl_disp_reg_info_t *) handle; + p_disp = p_reg->p_disp; + CL_ASSERT(p_disp); + + cl_spinlock_acquire(&p_disp->lock); + /* + * Clear the registrant vector entry. This will cause any further + * post calls to fail. + */ + if (p_reg->msg_id != CL_DISP_MSGID_NONE) { + CL_ASSERT(p_reg->msg_id < + cl_ptr_vector_get_size(&p_disp->reg_vec)); + cl_ptr_vector_set(&p_disp->reg_vec, p_reg->msg_id, NULL); + } + cl_spinlock_release(&p_disp->lock); + + while (p_reg->ref_cnt > 0) + cl_thread_suspend(1); + + cl_spinlock_acquire(&p_disp->lock); + /* Remove the registrant from the list. */ + cl_qlist_remove_item(&p_disp->reg_list, (cl_list_item_t *) p_reg); + /* Return the registration info to the pool */ + free(p_reg); + + cl_spinlock_release(&p_disp->lock); +} + +cl_status_t cl_disp_post(IN const cl_disp_reg_handle_t handle, + IN const cl_disp_msgid_t msg_id, + IN const void *const p_data, + IN cl_pfn_msgdone_cb_t pfn_callback OPTIONAL, + IN const void *const context OPTIONAL) +{ + cl_disp_reg_info_t *p_src_reg = (cl_disp_reg_info_t *) handle; + cl_disp_reg_info_t *p_dest_reg; + cl_dispatcher_t *p_disp; + cl_disp_msg_t *p_msg; + + p_disp = handle->p_disp; + CL_ASSERT(p_disp); + CL_ASSERT(msg_id != CL_DISP_MSGID_NONE); + + cl_spinlock_acquire(&p_disp->lock); + /* Check that the recipient exists. */ + p_dest_reg = cl_ptr_vector_get(&p_disp->reg_vec, msg_id); + if (!p_dest_reg) { + cl_spinlock_release(&p_disp->lock); + return (CL_NOT_FOUND); + } + + /* Get a free message from the pool. */ + p_msg = (cl_disp_msg_t *) cl_qpool_get(&p_disp->msg_pool); + if (!p_msg) { + cl_spinlock_release(&p_disp->lock); + return (CL_INSUFFICIENT_MEMORY); + } + + /* Initialize the message */ + p_msg->p_src_reg = p_src_reg; + p_msg->p_dest_reg = p_dest_reg; + p_msg->p_data = p_data; + p_msg->pfn_xmt_callback = pfn_callback; + p_msg->context = context; + p_msg->in_time = cl_get_time_stamp(); + + /* + * Increment the sender's reference count if they request a completion + * notification. + */ + if (pfn_callback) + cl_atomic_inc(&p_src_reg->ref_cnt); + + /* Increment the recipient's reference count. */ + cl_atomic_inc(&p_dest_reg->ref_cnt); + + /* Queue the message in the FIFO. */ + cl_qlist_insert_tail(&p_disp->msg_fifo, (cl_list_item_t *) p_msg); + cl_spinlock_release(&p_disp->lock); + + /* Signal the thread pool that there is work to be done. */ + cl_thread_pool_signal(&p_disp->worker_threads); + return (CL_SUCCESS); +} + +void cl_disp_get_queue_status(IN const cl_disp_reg_handle_t handle, + OUT uint32_t * p_num_queued_msgs, + OUT uint64_t * p_last_msg_queue_time_ms) +{ + cl_dispatcher_t *p_disp = ((cl_disp_reg_info_t *) handle)->p_disp; + + cl_spinlock_acquire(&p_disp->lock); + + if (p_last_msg_queue_time_ms) + *p_last_msg_queue_time_ms = + p_disp->last_msg_queue_time_us / 1000; + + if (p_num_queued_msgs) + *p_num_queued_msgs = cl_qlist_count(&p_disp->msg_fifo); + + cl_spinlock_release(&p_disp->lock); +} diff --git a/branches/WOF2-3/ulp/opensm/user/complib/cl_event_wheel.c b/branches/WOF2-3/ulp/opensm/user/complib/cl_event_wheel.c new file mode 100644 index 00000000..03e27b36 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/complib/cl_event_wheel.c @@ -0,0 +1,566 @@ +/* + * Copyright (c) 2004-2007 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include + +#define CL_DBG(fmt, ...) + +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/branches/WOF2-3/ulp/opensm/user/config.h b/branches/WOF2-3/ulp/opensm/user/config.h new file mode 100644 index 00000000..946cad1b --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/config.h @@ -0,0 +1,51 @@ +/* + * 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 the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +/* + * Abstract: + * Windows-specific definitions + * + * Environment: + * Windows + * + * $Revision: $ + */ + +#ifndef _CONFIG_h_ +#define _CONFIG_h_ + +#include +#include + +#endif /*_CONFIG_h_ */ + diff --git a/branches/WOF2-3/ulp/opensm/user/dirs b/branches/WOF2-3/ulp/opensm/user/dirs new file mode 100644 index 00000000..e08ed5ed --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/dirs @@ -0,0 +1,6 @@ +DIRS=\ + libvendor \ + opensm \ + osmtest \ + ibtrapgen + diff --git a/branches/WOF2-3/ulp/opensm/user/doc/OpenSM_PKey_Mgr.txt b/branches/WOF2-3/ulp/opensm/user/doc/OpenSM_PKey_Mgr.txt new file mode 100644 index 00000000..e0706e06 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/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/branches/WOF2-3/ulp/opensm/user/doc/OpenSM_RN.pdf b/branches/WOF2-3/ulp/opensm/user/doc/OpenSM_RN.pdf new file mode 100644 index 0000000000000000000000000000000000000000..700924f24c83aee85a43e28b0a5f887967eede78 GIT binary patch literal 117072 zcmb@u1zc2H)HjUMjes;Vbl1!PLkmcEN-EvmA>AoRhjb_5&90CmR@(c6sH~2qqc?#0}s8*cn<12(U}( zaB}cM03aS7J$5+@TN49E3r`bc04KXR00iXaC-=X71oax%A8P5VOl-}Z%>h6jPId_kYiAQjb_r_( zXOl-JMs~&~?4nRTf$U-c5VUBBLnlF?g#^e8h87SYH;`Qw01XQvAtz@?69XG)v6wd0 z*Vi}I*Kh7=Lo-I<+y?>Rgq5Na{e%6D#NlFl+V^RshKvjXuBks7bqpe>MIJxr-~gl6 zGB`q=as+OTewQ$P`I&EkN>XTR@(aGlCmm9whmTOgw&1CBAL`DG;c_DrX?6nn{NT*1 z5tZ1fhcc96wUjcD-pkBC%wo*+Um+2b#li`oy&F>8F%cJ-#S?G?@4Z|Lx(IENe@*5(k% z9Y7nLPmJUtCK|M={HJR)e30{}D7GXlef80TAzhIpBvMlnfkgoS=awW@qhU zW9tL}!6MDr!pPaq5x@x)5@LU>!wG=?(PLNhus694J!q5}o4D(MpfLyL<%NdFZ(cG~ zG1G^-imWRT5j04S8901K)RlL@NkWmAf{%ft50`u&#r40mzm4A?fTLt!W&+g%1g$dA zh*orQwuYjP69B>uEtOEhtr}tm&IZo?#8$+}*}~3N2O7q= zOqyES09zMp>%V{Ku`3wZz{G-otfOWQjWlEEJqViF&}Cqftf8s^e~?t29bJr^ z)f`PsZgUQ{f7ncU6K4Zss6J4Yp-Bu-`5W_o$b#+)st2?V095pTq2Z7FAN!Sn>hNQ0 z(ojFBSvXspFo-Y;K|g=bhUxfY_9GJ~XD0yob|rRk8$%OgV-sU&dfl4rcC)|p!3aP2 z#O!RHO>Cj85Uw9;-`WwjOXyY|p-=v@xQd-KG)n;-(2W^e7>L@r>%es9<^%$Gc!7HC zVvct9e-k;OL}+ZNm^j(FI2yt12}3lfRYakCz8&eY|FGMSRh$5vzv~B^@k2iq9jJdn zoLm4dFfV|M69n}S)Gn}?hWY~5Q{0Z!prcz$vTHy`|2FsS^xwomCBmff0C{hvas7~? z1Py1H)PKsl)%ADPV8Z`rSwB6d1o+|ee+h$v+&|&~hDiULupi!p3i~h3Zr$~}W-!A4 zqS@`@P@4f^mH6M=yrumv?C)}Y>w$ln3XMhAWL!kvgf)koUKjK~j2p#?~ngj@10Dqc@T~pD}(!>ZhS=t6V z8`j&vb_=cCc1Efu&N}SScAj0$#N8SC9Gc)_dhFuv&XTIIw1)CXs=`+I8KS?d@;89o z)&`h9?Bcdiu(q%@V}ER6D`M+p@z=emfs@JY3^faA8D$lpzi~)3jzWGcz7VNW&v8QpydL3-9F>t0Nl=p-ow6O&wug!KYjlt2P%W>*LAxV z5Wo$61Ne3EK!f)8F-(tJ{h)Ji>6}ojLiL5syPXTY|HZ=vwKn%}_po`tcwlsx4!`zv zs{>T#Uwea&!O+46+Xw9XFFI5vjOW*0Vc#&FU~B!pXPAz#>vkUW8B7LjZRi|WWB03j zxHbNd1o_MPe>>;aSE8`0&kB820e&500HTHG~e}z1|stCZ;z}m@#T~X=hKvf>V!Nvh(x3mB2i9Ga; zR$WX52wl$9z{T2`T~zX~@$akrU3`BwS5T1ukM8R4rbsH>TD{kHmII^tg4w+WJxXHK z7VtGknv|xk#@sMF6u|J=xe9+!F5UU!Qb?u_q<}1BzJ&K(N^n@a07sOjOgp9>Z)C-$ zRzS$C!Mm7>8BgaMU-2V0%PxNigVk3Dy*W8kBX#?!m^(26xUk|a+vQ}opzSx$r~Ph8sQ5aCDT5l_7e63pi_27uZa( z|F-kIMWhDYk(JiJTjM#S?zun?u`$wp3U(+ zihPr1piKlgCNi0ntf@+Bwj#MSvQN#qjG*?DBn`c`7$qe?Ye30kt2oWmGGHHFeteht z9Y~*&{oR_7OgIC?RP8is7PI$HaS`r%)Pd-yrtjzRd{>bmHBNc^@~|2ddvJLDM93|@ zBQ$kIwhunXMi?iecdvVP9_#goEiVVPqGv}wi}#~v3UpLFaMJ}+pJkc#;B+!NAF@Wq zT;o`24|f$5z7eMz#1ib&S^b*hNXJCr;eo=b{2Vi#c2`g!0aHUn;h~nfTa|KVoSVi5 zaffO6?wKFcP|Nu`gE07KgAA?QZy~beM@F?`1M))dbF~aLIDTo7^YfE>B2G88MUO+4zyxGn$_CVa{)Fm1o%Dfs#_e6QCnOq}2wy zArU!2wl|q17NJ(2tyfbVdzyt<^_R1AH`^1=_7%G1nPhQ3SLYvx4VFyNc`O*tIEcW+ z-%Z{jP*^;R*Y0^ehdp=Qc^YEWJP)oEvYX7k2u(AO`tIry_HMnkWkBo@KTTG(U4Ka7 zOAEOz0^i_0r)-=aDhyh4f}G1I4=b;u!OClCn!Ub7SSE{lNH+*XaGCw_AhiE_X}HD4 ze-*9&Pl)wDVimMV{qI=yqv`k^t6*648&*MI)qemMtnmH?GEf?+>$FGIiHrOiU(bGTvVP6GZD^o8w{iTl0sAYyf69c(`4xg-=<(vO zu)PgeXbAuQ{nwtM^uKifIlgVOpyQt*`Inr(nyjDCehb@M*B4e$DE0q87fA1GPE+B$Zt7UmllypOKD8%;0st`ui;s)Suzu0r(Y zy|Yd|=GT`HGfzkExhvpkD(HLMc~T*8iNex=uSufU$x1MHdgb4`Y1~D{n;G~R<6PXu z$?$4le^F*%Pi(mKX7kx~=hWt!$_XRbgb$T|quQTAW*`VW%|sxw{H zC+w0-yDdZ~wUWgiZO@-9 zwvbEw@N%|RCK8!6$vO@^udmzjcXA@_q@st}-O=x=Ot(Wz1o`9Bat&>7SUA>4*f$x* z<%b|?_7VOBcSf&^@s{Y(_(Se7=Q2ITW)1uPsCG}uO54`gyPDWZ$&Xw?89`nJBZ@5e z149!IMAQuOV4R$vJLd6Nbe8On^z57P2<0Xq$ZTf47T?BYMS)&Ad&5+E(6<_MTa21! zh>p3EPn3X2gD5?F+9{ulTCvDBwF1J3z0sY)jl4uB6;a^-qLiYwT@@l2at6KHG3Z=9t>0SO)0=C%Usu=ARKBU$)frv;D^U8ZAc}(z~XmIV` zp*o*w8<3)VHx0LgygMx4XJDo9+pWvZfHdJ z{KQ{Gn3LO}vaRV(SatzMPZJ7C0NWT3FW(<|qwAgeI*yk%-* z_<0&DR#88uo`JH?r3yVdYJk|7?bMUQ&x++iE$X<**)n{e(=rzp3cD~|H$`QNwE3-F zN#ry_(cR*~AB3)MX!2*{6V}na?>Zt?=vuRF9!*_{(*|nLt79^uDVVmdHABRQs5VMK zP8}TuS(5TVrLU9bHigX=+%%YolgRZoxBumrA>Vj`Bix@T(rFmJq)j z$y-Fq6yvjR~Q#vo_1IN?VQe?5hdv7iR$PhdTg!+0`rSYQIT^`Mc`^UgvFlN7Z zUKzK~abBEsn{JVGT?FKZN4B*aPX?-w1RQFVwo(-Fcplo2O{80Eq?3kTEf*~1 zry*de_oEpWirs{nwaWzG)ESR(kI8pQNtr+SkS^ZV?k#D6jWuh-y_BJ(mv?g_=OuA1 zrZwg_0`ljbo%aYFV;t-pk;{02e587b>-W+vuF@O+q;$4r;IifFW(WhTk&e#3!1FR7 z1$m-}sgU)<&9R|H-It~M(cPy5AD9xiq)0&g9J=65MXQZ!p)j`(Z_m`UF>voXty%Yw zw%5}pKF59uH5PqpYw1}hg8H}Nq?+05LIThlKu5cx85vB=6H=b9MI7``<^NB>iY+W zoy}L@vc(ZObu3?Cy)|xoVEvK^gojD8vSh?s#O^Hh22)0sVp>olvVWISI*8KoDGN{S z(n>P{K8^S&ZA%_}|KJug3vpOX@;V{5E;~gPKR`Z8Pi{+I;FT6dk-LlQVEM~U<|)A& zf!7}sj#^JVU1dZFr32L8`ZFGXwto?%_OLDd(^p#DXu)22r_OIo_<7-8q~%Y2Yh1;; zN;xbBG)#ah%3s7OvDfgi3-gbkRY+4l-efOucE%M!nXik*QJY^keD;7QNQoVt*j%a*59a7OncVkS0$s(>dLc{YsBp$3lyc z0oPqjN}GGRNeVAwsg{CNlpEucTwS%y29ln6H|@yCOsqZM`(P`Gltotcg(M$!GSC8% z&!*92)Nhaf6=M?S6{V=_*U@H~E-4?M=W|B>=3nXb@WtBR9SDF5ni=TNa1jMwbA@zJ z>1hlqw5VFz zWbx2qR~RfX=}7@f3I7WDK2{p~bk_<^Pen=H3i^x4v2kA0PR<%k>3}5$hww|c;S{yU zCj&7I)Y-Xs8bIp2qQYUE`>fb{3}x!1<5vf3?O*63R@I~1+UNCp(>}P1w_RSkQOV>N zT&=4#m?47le+QXo0~JhWw(HFm%zl6gpCs^Drx1K_wY^xQkJ ztF;@5!|#3YRAxu_-Lm%3i{)q?wF~TvZ`pGa<&mXlR=Eu|m&42>pjN&~wE{BvkDKpx z>54jcX`~|xJSOMhsD$sgoo4|=-BOrVr5rXER|hgD#AxWR$23$p1@?Fl>k*s5vP_me zgHLx9F1-%D9MnhFS0!y<6qvqER*QMKWysxIvWWp&Tf5#V@qED@IfIk&puGcIQBcg~ z?#Xa&kZ7JDLNi^l<5+`?OT2@_yQ8^NW?QBsMy;Kt64?MkS>a0rN)#`pk&yPnnd@N7 zsXpMbp6WKi_a^b+su}83-sW1?PTS8+ree6nB$+Q8P$HQ6NTV}vl%5_xm7jAv!=5Y_ z9&$w#d5L29`m8%cdn(7wds*X`!$DE>{cK?t}g zboX!&JW$`qetB{FWexG0C@uiiqxlr~q?vH%GRH}fKeHk8@MG_4293b_g+SK&p+G(o zmwmpV2l@BC@b`kMgg11u3VHp2B45gJ!NqstD#=fXyc?C8s8Z`%^CKT6JMgo94;8oK zsdbK6s?L(d#bxZoi?JVFIYg!&CJHdDgnZLAIXTYPKOz{3cuXpt{S9n2p8vVOkG4z~ zFS=wlvtL%uEPz-*hZ9NHS#!BNDR=B+1Vvd6cV(1uA)O8L%H$sMxnDu-7tpmu7CU~J z1P;Ck3cL4`?xh`amzzw+!X5NSGM2;!aC6c)gc^Ot$yc0z z$jVHyh0|ViGuyiBVhSQHtTk`+#Eg4oCxjD41;?s6w=lyQ)x&jOPgf=5zR=>}wN=oM z+tT*oOWJ3i>YKBomf+a2)$m1|Tn$yv2Qpq&1iLCuqLUO`iHz$= z-e@rS#tyaNrROSFV1{=fQppRP%o5R5-0ixm#+8vO^iMUc-B5h#n^GUxxjJL{0T26r z1S_vi_(tg^)vP$Fxu3|ME)Hiy_ALC4$M;-?oZ9e$XX{skZdhT+61q<{6elxwA5LN) zA-zY^z4^|zySE(_D~_bPFk&X`V(WfUexlq3&Qtel);`o`dO6I=OIpF-tQ;#I&MorJ z+|a3AdH9ti)7co>YJ6E2(5jJ&T{&eG_ zZ-W%y#idGI>^c5^vnGk(m^{?(3kpVi7!S@-un|Dmx0A?+z3P?jQh}0-&1vBao{Cp; zJ8fanojl3Uz!lWV{KfH#UgVj)i@7l}FV5o+^DfZdvzO&QU?3Ly8bq@xfzX+-8< zu-x08P@53pGQR2y>Xt|%5fL~P68;)ujv;=~U3*4mON~Xsta37CF2fYq>)$J1oO7@- zwo${(gMVzSKH;ZOsBXN3QH37qrSMovaIiPVv!kD;&k=s@c5rf>T5%1{8SpoPXFFRsYe>xS!l>v1oxn=aWt zW#onD*b-`1xz;9TZcXshm4aMPt!v!cu1&}X7v}@p#9t#v23gLW%?YW?Hy0O69QHl8 z=n%1CRUceUKW(M&8?b$exh%1XE}je6Ffh3iW%-cn{^9_RFnHkn-tpuo zpJAU@?~>gnWY%9l=o_`-9=dTuWLGU;Na`^>oc9wZiJ@W;3W1mR zx~VkL_bY)MMCA2n(bphn8c|%=v0IUbGW+d~isZyz?GJm|QQ$ke+r!JhP9GQeY*{`3 zh0d(vgz(fy+yAsZhx3y)oN@{K)S^*-bgp0_6$?`-1%Qe1d3 z=T~uX0TP6qet105UG!DHO9_HqCB} zkZdS{KJFj%hB9tAH;<9VAU!h>HYZ?+JF0-3)J9~Y-lt{gMA_wNLJoM&PT72QlE}_; zeU(%dlK(;uf~g_7NjJWpoUf0F(%^y=YN=Z?_hKY7VOT}!8AT0h+agChz?i#F4tHG7 z`cpoufT zcoi%ejCM%Y?XT&*k5br(Z<*wVZiiMaK#N|oP!jtxPx1E^f4DQ{l1i6~w>mT-@7++ud&z zN&e{HUyahGO32g=s?ubdB*$v>MEdyA`KrrTuC&*jIK(=MIB?cD?cn1I2om-Qpdb4o zHyazxh5Ido%?~txQ+_&tTa${RkeX6>1E}=-1)Ae_KXG)}T z$`H2a^VM^x)FD_r&-}P!0&L#lMA*#r3OeVf&mr-ET>N8amg<@h@CFZ5Zwy-o0`p2g zL9TsW3SA-|ibn;#h=QNCOaXqDc^$!*9gu4zQd6*VWY2H{*RP3Qrs~3%hmlOVHc6A- zT-8gLj)yBMCH46sivM<8^TLJCLi4=aLbLRF(_TQW+J^5?>Px|emsdN7-kF~cuS5$` z()qm&gvbgVcmgzRzFuksyKKcQd50E~I7i6zio%KY=stL~Pomx2-^c0_0;hkNRlSr# z#$D%;T*~pbCU~H%{n~&f>p87|LA_jM%5X|f;+F4O`HaU%GP*ODb!vw$U}_TgE5BHh zu<^y$4{~&!4i0_hhXLr`wikPmovy^!Q@7i2Th}DDb zQ;?sgO-Nt+)}ZC2qBjT*-an+X`Z~Z+?X{;l=7~%zfrmz#^I=*-GvKU`s}4IxPSWJP zq@f6IqH%O?;CijVyLCSaWhp%NW?r0p!6!6C29*}rI#&DR;PYKptBtSNjt>cxe7={}adlYv zwIiXC?kRK|43R?vM#9dP_;c!M?Hpf3vdwXN3ZFUcDm{`}rcc-HXDTz5%pYGokk}8C zijY2<@REF>w@238ratkGgDy>`b5r4UaE)p9`k|X>OYlu;phmp!RH|M zChoI=$mU_Sgy>39+`X^pkc4EpLKeZ^-tz z=_CsA_&iwVkoR}(7p07SiBEE9M6eD)+vjSokXR$mx>ogh!V26@i zRF`JCrP2Cl^>ISC%&QfV=v+M2wD>y>0Rc`7ecfMWpLniX&g48VPtk!lqvPOH067>s zCTVL~c<%+Kw%nPWUi-9~hsyhMoJC%Nzx$H>jzw>DazLcUctRTCM7+0Kc5JXh1J zfl)USWe^5q6_FUXP7}G{Wak#&$(4z~YaA5WJhD(HYu!ZNgVy^3X{wk$Xz>G~1{tR?@_g@Aek`kVmf0mATJi=zQiX~UUe*Z_MYsMFH)u#V7|6WJ2uP)1Xf}sFFM4$nf{7^D2qS# z8R3fv?K-`5SVT5;_q_l)oB8opj|=_B6sC0-UlC$ro#jNZn}oGmrjfR;jbF}?FM@b& z+{~Q5&$^&{H;Rw?9!Q*hM!S10;)FG9TvtBG@8Iw2=yb!(k34FffQ!gIsOK;evQ{4- zeO<6xc+#SzmSdkp`6zR-{*iXQbbI3wF#@8uF_D3mjG=u9yrhApq()g~>&-#IBQ$X- zETk#@Z`#{&S=W~Nr5#Z(l)2C)*b{q8>J62v!B1^X%MYClD24gDeRk%%v7f)&#B6ag z3d%rp1zs_?t9Lozk@#dFCoe^I_{PJw=PM|( z#TH9%Zc@rG%jbrpxrx_t(mFiSVw7X^HQv~GdEI=OGAQl^7MU7Vs_9mPgRPafuF~%} z>7}tHEWWSCT7uG8&_oE zML=Lfz@m7Ths9#~g$p7vyCyjtA*1v#jh$PFHTe?jn+y+Eou_Jr(jio|?W6!=_hi_@9&1a+CcYc{@L_hjul92t&rJy0ev7&$-{^1FBc zdCm28Tf*@2o-m=oGWZCaaX*{AOV-NQ*&Atr7lMgTo{o#hq=cV-@_kY0ePu)+mOM_s zhE~kjK&|GbYBHk+9cP-VT7_jfGSfg&$Sb};H^-3PRoo%_)Mo^uv2@EeWMbZl1IZ7y zJtf!8{OxVr^!6H+Iz*oh}+KKb8rm>1Gm`O>Emf<<_l?!d6itno<8q?BH z^2|tQpx3j|1O)}fK72=mk88bd*yFl=mT}1cIO~GfwIkCAzMyoc$RtkqQMk+Hx%d3~ ziB{*v*W3awowr%C1&>O_fkz2DQXB99(<_oza|z3_>f<-oLR)3%NgkKE9b&?rsM>Go z+_rc08kW`OT06xvbvU^n(8qIj(8U&V#TmX=->PDou3x{h5??iHp3oFZy?cQa(&M*? z&`+n?UX`NfyQ}qmq`SM$yq+f(Z~*CF`d%zkZyB;Kuv9K||6nxA)mgGE0l?s90lD%m z$iWi=wVB{JQ^}jFF)?9g@Dlc4`Je7l9O)2XK98g$QYhf_%1v|;p{blLnAb4^VC~?< z8WAZ21m2L4h;5M*;+o54QJ ztSn>djH1Gk-H5o|$nYJ0udFAk{2~Zc)tudT;#4<^r{mT@c%7$sIXS9Sz93}p>Tk;9KRIE&R_3Y_ zoFu0nG9bZCPWH{q;YHi=Tq-b~6P2>3iq2Em7#(#^^4=JjjIqKS&dAcKcky~##HZ$A ziJ*NaDHs(TU2o5I{b6OdDd3?`+};{P@B@4UhN!*(=8(>Iikl`>rt?1jDWMc)i@lh&fm1SmUfl)o{18c%%@d{j zG-=L#-OW>jDtnj$PAJPg^*f_B{CPRAx5P^O1*e_4Pv&$LMLgQTuThgkeT*Qs8I-HL z55>JX+@y~~Jtkbpea&$6{m7qKtBA6C!im&`d!a1z!lkK_wfe_?H*GE3B0^VXOm0MOYf5UxeZhIWwd@MHd@ysX+!BML zzwut7yEfG#Ft%e7S$OklMNMIqLDM?{jyuQH_!3>H1`1;d=2UOAC%_k8Ps6hho8QyC zk#d!Bzi1xJ5}b%KUoXbmM+>BGr&W^9CB3X8Ur&Bx`_4I<*YVOcYRyFO_1D7G07K2i zOjVrL+<|NMrwS)Q$EE^ZVA(lpLeGtf`AywZLy#yrv%MdCUqx=WZoP;{Q+puATuNib zT??AmZR5T9ZTGa`s@=u8SyrqdVI|!Pet^5rjZthrad6*^eoOQAZM059HDk>{!O=HH zq_-R63gKySUE46TM8KS2lWs7b<~INOCFr$WMQSEil(f@Y!|8)}D!M|`(*zP3VYnnH zDgw$Fo}J7e*;~hypWs=VqvEzR@;ihSh@(0c*9}zkZ60F1 zRDd^rIUoFjFZEgEC&NsoI~=%PJ<^=2|+^^b)w!e`esP&`UD~a-w_c^K33dc z;NZ8D9=rBEdh8DUeM3Y-8DaaceV1Kh>y583akK1##%!d)_;|Do(Ks(H z%s~C^GgDsO?8TYqHTxP1>Q%0t8$54onEAGx1w*<`iN4Z&YG4Ybl!;6l+nx87cEb|7 z!|$iH4>T_bCy|@Y51;p;bg20Xbp|A5KU#uXlbv1KUFWlsi%!dZoMzLv81v(Nc{{z6NtHbwJ!B2tDRCL#{yA9r;41lSj|Bx-pG9R3BUc64ynh>aUA2EO- zKLE)HbewR$yv0h&^OmPhLV+u$iYZ6j|K5vzEOj&Lc;k(}G(E5L!DA)*{%5h?8i|wz zuG2L|rK8RgbEdfOOR=d&YwNnw(x@dPpYfs#CZFR~_2#sTc+jEJzgjjAb5f5Y<6rvZ z@p*2PGe(0{VbO}O?rs1LrXaQRIXqcY=;9;-L@J1e;FWn{c>!40UAn$?fOMd@?DET* ze5dm?6?L!HY5Vl^HOz6a;+FxZy=&Pl8`*65s`5l&p~LLkkLyo`qH&ccaC@1FXmBak zbK-~4upXODZI9c$WX`fF6}m5aU`*2|ox>800e{y}O_OP9bZn~{#q}9xK&~xAh=7aE z)#Az)y050*3_jbznf;hEZkY;|G%CCfLGsg0FKdymjXL)w>62A z%9p$dpmIlk^7K(O*}H^n%8F&L=4$tH4R8>!!_1;YA{X)FGx#aW>>{jZrm79)^@2<+ zP;YW6J>QARF{i`b3m-mH!OF#k9%&(0;>-cnW-4rIa~Khrbz2XPWbNwu=$5H)@Ab<9 zYZO4=Lz0y0&72qftrniu)a3#^CkJ{jx& zLU+Y?arY=rkLsDa8$9VXQzMkXn@p~3mcT(kBKNM?J~~-Y#Qbx>Vn~dFJYzDl`G;>y zzL<$>F-Hq>`%LYEa3UHS>S8o#)vjVIYi@jOx+XD%Sd4t_$h;ftheu&IJys*NU7w&@z|6?#jo9qB}jF0`^QIbeB7QF=4cKd$j!S>`)5N-2X-C- z!VTTfzYU^{=VID|n3;OMr6SnLij|3w;A=3%7Iyr0g)<3eB z?JJN$fbLdNcM1^jlpXamMV^=eFJs=a`Cc?~(JRU)CE=md$})?+?{e>GbHU4aqf+XL z9O-&GufZV+tkBg{d`&m2({KFc?R;~Up^Lnj?ALczM3A&}5gL>`yyCIollroAdN7vV@C z$i3T^ZhIj3czNtNo_~H@tEG=0_kGX{WB667*2fk6Q*P^Cu%EZd4(3=v5h|W*zinLWY}DO$9N}|^P{Q% z(+}wVpDPgxKu@LK6K8)^_+;2EgU5y1rrRiytbRr^BYJo^*R`vx#+c&A$ayb@C6EI= zqPCSrr}z@9e8HK-CP@W#I@p{54Y*uGCKd>6@+zfxfn?h8F&KjR0p*+(( zwg0qlYp(yXx{4H&7F=(eue;Wl`y8S6CIHuWi)-|ml@~1vj=SzIh&A7=x-sD=5Y%uYstiSoo;(%ag0Cf}WPArxp}W z`}@)QQFvS;5+g)NPxu~-s9it!X6soy5KA27$X%(5Kg_^LzOk9(bI?CX&%;IIr+HT% zF2ocEL0>>zcB#r(y7U{nwnpX6SHEII=_pBDmT&i@?<@@!oM#YQw-PmrwO4+{VS=Cj z#2B`k>cCYwVYUq+&LYicG?Fp7Opm6%*4tRPz{n6}!Ax0Lf?Qm)7e>o{B|!hN`yFjBN*g z8+<@M_r>FLRsP#bgpZIV!NylRC|Np+7!VNKXO~o_H)!uldJYM^Hq+s&?sdW8et&3t z7dx`T#$&SQv0C)a_rNXmWKU1z73pBKZcYVMO>>oDa8bztvRj73@K^s13q&Vg$YT-d ztQe$`4)*)z2q_Ma5tB+wr|TPgIF{{|Y0%dY$-+(u)VtR6PRZXb*s6q=D3pi>r0<3)9 z-4I1|zk)9jM6wi^dj#{aSr6VZ_sB9!T&g;&toq+^f0G-i9UfN5cuCSuaI!(+M;? zz^tSWC{#Aq=$^%N+`=;rK1PD+xgO#0xnkJ8fG?kziwkKLUq0~NyK1>0Nbos(F7kY0 zVRHAm{nCLsL`wW2<35^3H)l;-0`v`b_pRG$mi_mJi#+Sk;ZiYR(g#v&AG!?;ge3x0 zC#;(q12_mA`DfacM=V^dU+6UDT25q^WNx-~Wya=LO+xHNwUX83k?Ac8If(N#1eUya zqWjkysKx0+xS}!cQZg7zPB)Y-HcMIXU#HTIB)4;oCXL(MsP3;U$2C3s^nLzSDNO)A zCWpO>m?%w-U$&fEL2HA9;}kXh>1FNH5k?NVpn_$A&_ILwPNX|a_I0{gYjxon0s6yJ zWRFZ7c~ewzOoFJhL71{64dTh~p6y+(P6tNzog=M4kcgf;NgyHOA3RQeN7HJU=yt5? zB45KgU$sQ=)uI{90Ve8atv2Wv z=yq$Xjp_V(JrSYhSW3lgtKG2z;W!_fspZEVl=!VoKpHfK_zx)Rhe)5+7p~RvG^j-f zdl<_3Woy3Y@RL@TE{YyXP}A7pKkF?+jGWt<`^v|GVcVme?L9iFLjHZb9J|Z*-d}V|B%*ChI;dFAw>zsgv zrE!!ZO+R48fQ3t$29OE&#g9$rt&2cq`JfK}(rc0e)dLQ^u6eW%(hmBOR?nC1dkT%Dum^@iY>!wSHbPqfTK`c39*C zNBr3%>;B|#y29QY)_(8IQ9kvIISTAqOIaA^qoBy1j3Zx*d!!2UIAj@IVw)FAO3^29 zijw%=ETbNCQufP)}Ycolw~m0Zd34|Y@h6YOPlq9An5>; zXrV5Ob*8~i>r|#Bv8H59M!VO$1-Nr0Nz`9uW-Z;gaO$18epu6IqcgvAdAz$zMDhM2 zFm7MGjw<{LtF=ZhTmxGS(64?Q>j_Du1&$abB^)ZE8Jd&mhlTYU)`e^%> zA79irh^KHVm-t(Uu_z8`JE8A%Hu7^oZt$i=v&v4p%*s2ISbCg&fotKu;J6SQy`;oX zvS}vV7I_Yf{?wV-c`PdE7=94^?EIs6bdIZ6vH)b&C)kfw3W>>1-^>j?TY3SE16*35 zAGStXF7%3O913?wZM<^8;Fz(deH=#cp zlV??MoY|eXD}B-AoBe5foOsqafRfA=qw2m2aohm;Myg-^KDK&`W%$972Q605c5Vk* ze1Qfo#RhFljm&9n5i{v@DbC_YnU4h}hl<`MGMxGc99X2{!<2Lb)w0AQ!|S@0B;N8m z8adoEjM&j8oghYNBjzp&U`wOrMUc@5{ATvVa@J+v_K9mio~pk-__f>A0}{-X?9dSG z3bKS`g@@oto+v3fG^JU^dF5^Bf4b9Zl*}0AXC_?F%*F;+g__if3CYOB8RQ*$yTc=> z+SfL=RSYM)GRN^WpR(>T4Va2eFwXbdmxL|+1=7fsvf^%dWwhP=T}R|xpV4{A912W$ z{YeDu5-n$O+Oo9>zRqfPsRBpp6HI(G^e&C~t$P(?_9^(4!8IwET-nA=c9TwJa$eh@ z-1awbia*`ybzgTL0wgw1K-y8QxrPH$v?Tz3Bgg4!>Brr6!jI`~K<`%&6gr+E>@V(1 zOq3^Y-|X8)&T3F9CnuFm?@m5lpt+c8bWHbh;9NumNkSf6yKc^YVYd5_rd`H`>B+Ox z&MoTKFL>7nmmXaj$-g9cLB)SkN9RGk`2$@w!}kbc%FDSUNP?Hd3J(mZl|BM}^kwlZ za;uM2z7n1 zn3RK&jF9hDacqLhcTMjlTyhs-jdPLkpOckL$n5thRHd_UOIF@ z$EgLI%+ri3rTmxz4a4}KOQl7hl~UN+3Oj#!0^Y^^Y>;Lk&goOR zzZ4Sv@vRqOzpdrA&*@@N*^^@CH=Lz<>^7Dop_Zv7etEH%c@|owYe|xpf6XtFE5gDQ{UBD3 z?z40N#TVW{FS(-Bav^@I#(dGo%)_5H^e_~Q&0PZ^b!tF=4ZMCIhO2{v9Ezr?kU0jn zRGlN0dw0zG>8g%mbO^JI1KtZJKNK-9GL(PmV?OZq^z?Loe*E4dLoA#E(%p70>NzT9 zjSoqL?h2C0dCi?IE?$oZ{jVAJs*#&xnTFV`9NLUT*W5p0c&z739T8!R<6+aiT9%p1 zQi!pg8@~FuH@f>h`*E{*#xVOJDPt|;D^8HMm{gvb8hTEuhc>UQJi}`(`TapZy=iL! zXXmrA37r~l?K0GlTg1_f0s>1}>LaG~W=<0DasuyB9tabzy+HTu-i@Le8S<9Vm0>b_ zb-%=lT`#@l)n~cEbKNK7#wHl<5K##oqBkzzdEZhP5`GQyd-65MP zV+~Z401;PEI7iIfjf%iXxA)Y184fL#8q)HFXlgx*iVv=hxARu0&Da#BoETGlQ>yHoS{w4ACPKr4C_Vo0 z%)OCcVmN>Y5R`kDc`+(%S7h|dco?%OTBO>iG8^**Eg5Dm0%Ri>dp>GV2^OPSfKgxD z&?`Ir44Y7Be$5Gc%*bU`w)?nZaVPZkAnL)!nDN-+5!) z`$rneOvQ|~V#SUbnUVXWi>h5+V&b@pZ8dj1R8(X-8;-FAgStY~F zCT#b)*6F<;I0cb_Y?ihdL0dw5a;Kn zu`e<+itC`$9T?Jz!EEoa3ucE&zMPy6k4vK;fAZX1m+rQgmdIu2^0|53J6?nI5%=2P z?=-gu)M7+Tuq;wL7vDWwmSf)uQZ=%;Ev<5&M{EpVTj-lKcgPy}Uhf~s%g1W1eIP6Q z9&}d{_H{rDlQT6G5n{)g1KUK|fk8Cl17!4AiW- zZ_GdX$Bz4sNL=hDSDBCc!GKMxThEt1XqI+252~#i`;!;a>Gm-B*4yKEKFs)5(qT^d zYUY<)u#J0JBPQ{6r(c5^#;LMB6iQ2fEn(ZOz$|K>DjCPA{(25A7QR0)8SWN7)|BQ~ zNCa;La(V@+_ojGy-31M#r<$E2A2R#7VSy~3aQbx#m1I}${+@G{yGnpNsWV=ZeemU6 z50UJsxD4oE9Ki5MqKJqX{UB6uqQOu`4xRFYIPlrXE(aRd6S9m);St~Ah8aRbj zw>4K_k)lF2E}<%a;hK~3y|DAUr}aEZm4>B8 zED&|LSzl+A6;A@G1c4wjuxL9XHnL!QtzgJ@n!!b(*K=Br7hQ<-Cp6BrS~Ei`U+aa+ z^3B`VlF~!3-iObZ`I)if&h>a#P`g&Ehaf<|j{?99^@kXCN>j`GB#ivJ`-^p#3VV1Cg!EQajvwo`&Kb&?FYRIk&p;mgd@BF-I zS1>O3@KQ;QfNzKEvo`1<`kfZ$0zZF*nd95LvyLUEQDUJ2QRyP2U`bWLXE%@IbURi3 zA*us9YTc#=!{tpXHS4nHQ}JfpmIdFgN(UH&7EQ$M#l18LFkktCjQ?&;R^DXySf5Nb8lsZeyi^tJV2Dn31HN;w#E# zv!bQH(6^7NDOn2Hb-J`fd?mq9@r9g#KjukHJTw=s|I-b^LzR|(J+o4cO1lyhJSg$! z*jHLi=M#Q^BmUv;T&@%5G3FO~IWV3wky2-cOWwT7lSjLRXeZ1Kw!DjegQHOVE9*gG zTMioGSV%_8x~c@e&-J*DI))kLB{6S=>kandXO0;TcO_C=wo_kDdPBcgAy$U+H+XpM zis!QVeAvM1XmpsceJb_(DE2`GpJT;mM`p3zeX1Bu_(T>p?Y+S3XdS1jBRHw@SPr#% z7>ikS6%50zE-0~3hvqm>0#X(V4hZwCC=EVaQZWB5(WrgKkj8|9jRU20 zkzlPdb%y=s`Ey5}O04dbV3LxI-2^y&-%?%=K~%32+?XAIqwJU1W^v#0D4wb%Cjn&q z^$u2{o{Pkl!S~}=HbJ}_aZOR$Ozls+pKGipF1`#=hpd>!Acy2F4@7~U^WftGxAXdN zxwmGd@zx^6$jSkesXHPKL4^1TestF55BIqsBhOXlJV5+B^U6ld04$Cd6OWsY5j>99 z@HidpzHp?h{$9ty0OGTne}qP_%NTTSnbq2~7mVF5sBGKQE#XRyYoo~JCf-`Ju7d6> z`mj-P!(ZFod-GA1nq9@`%HXa-mi4q{KKR@shHJ@n$4YfTRacGCu{Ff{=u?uISTqvO zS^=?))_mUZ9ga-tNR-%sVg9Uusy`m?U_KmZa_V=Q$hxXz;2w@LwyVgi4^(x1dA&bb zq#7|Y7?=IU#|8YJ&jhY2!oN>{&F#!! zx3gQqU&xBL%IPg4;Tr~f+q)f(@rb;X(N?&99$59&bmON|i;s`R{;CJ1lb9GwfQ!KA z5E8s-16QeR#Y?#ew?W7dB>as9jQou`5E$jH-GC?#qnI7Im0wdMij^{pk-Rgdmg4mM z63=tzh$-A5wb_b|CykSv{wNq%kbdL&?lw#P0J9einyw(f=!37qNVSIQwTHFzJo0|# zWfINLyw^9EWL&p-@h=o~Bo>aw61vpY^-?Y&fH%XTR*cB;ilPT)(Mkpt;Y~rK%c}D* z!J3Q+pvrjWKUCP5Q2H{yq3n__x#RmmgV043jY`{J2TfSGK@~y4>=5Mn$Jj3oI{3t3 zZE5WU9BvbNTVlE|!R2Kcegf{p;~{edT6%r$L>U&K<_SqRj3%ijm&EfwRj9;hJhE>L zZ%Q*y3~m+xVN$x6gVo=hMq3|A_!d1fQ%Qu_6cWN-jaaSQTz?U|H%BzSMB_&%Hy{hUO88@cVtr(tE&{p_x#ySxy&UW?4mJPNvUZkhrQag{mtv5XxUmGWc?pdJmx z<5C%}^E@(U*=N=PAXx}*=-I@eoS~vtFpK(C~N~}z93p2;7<;wq5kajHCr7M4LDY?cM8sj(P?^MXT}IU zLe5~b{(JH%H8*R{o(kxtJ^Uj?sCN(fZtO^3JTH5((oB-ZtrOK#mcy)t8rw?wy~qfK zX)v1YhSraprmC&2+dRs2!QM`E7GCb7g{)N51G((v_wlZQ^2Q%#uiLJM5p1LjXwAJY zBW8Eix-#1AHiZl&kfgk7I(^6)bX+|jwcoJVr%J``t`$^-`NYE+*kWh#yygaij35#VDt=U9aXp77fr%c)F7e}6ZF6()X zV$bVGjDB=&vb(ZXHjxIG5Og<~nw@iQ9Da^z^&3Yk%AznWGE_@&Ac!y#q$(Z`P)KS> z2y;Qtjf6F0N=QoqocZ$b#!g0;P8U+7Ks!=0B-9-(z2Q8Q3fIAR6CrHLe`G*vE7xGa zzaHsxkilHkE~p3;;X8v1Y71E%1U4JGjD{S*mZ#YL5~i1pn8S1UI^M#}zrp@?^0AtK z>0xFnHp}}F*3S0x+1*rZ4%XwE)o1P42R?h}VZY%z&!JC`bI<;OQ+r(Ny~m@Mh|}^q zQ6JwUD+{243v|>*;p=IR%4o|?2Q6pbo@n3eh8qng6z9ebgck|u%+GMytFT$Cu$gb8 zvA<_@LefyPYp2*XrFn|wdOx3C8NATzXLG)^K%)I92}l!mqcFb|@RmQDO zvK8xSD%gX9RIh+DH73Ta`JLJl2PbXZtUT8PnZd*fB@}2j&ykdoUOKpeB3ZOuhf+Ps zQ1Z(PwR(hT@FWOinyMO8N|jQxMwLXDJ;dQL_X5-O#6kthZm6?Tg<9Q4fxQFT1xOMw zbtO>_iE5m}m^bjAtY7bz7oBvSsggUmFBh^5srMKO=2fsc+>h|qkf!O-fQvfJ_K8Fi z?v^fF-=}11$Pt@Z->3O!$XL7Q*YFp7-umsv+G>w0jmx)Cb?XLaLftCHz}OHI;V|r2 z9@m>mV{_xRMNs1VBz=Gv^X9id4IU%RwLK>iZlTL;n}lnIH6IC} z%;nG*!C?LT5Fd~qsEXMRt4fnv{ywi~>DaEcAYI;vfYux$Pa&o{OjNuzqt&gaOf8jt zhOZnk022J8%aXma!k4X%aEF|g#w0>(*oErOu{ngAg2MQvp@5;P(oq$7=!1T}Qp#Qg z3Ffwxhyi6Rh!Zg55FvynhB?l4j84S%#D&H;^zZ>0-fg63Bvg?8TM&|mTkalAU-#qu z5&4bA{i8m!nA%lO?}gG>+D&847TdLXJFG5Fq+xJ#pLa8nnNXg z5Af(;l#nz;LjcAe6@8T=OM97>_ScEy>!ML^G_0X0grz^4T zA#3J$?gR*VxL{yq+lqi&{$~5*3qiD#8n|D@07V{SLEu^|Rlrc>(Lk6>BBr)Ejgsp`DYFB{^i>t58ry=*r8m=ObR) z$+Elga9=$7gSHIrm+}Rj2j`u%=*kd-m=^?{a+PmbD4LXtkJcv!C4#ZlSv^R4%iPvS zq>oE8Q_i!CC3>~k?^+wo4e#u!>*4L#spk>vyt~c;eszGuTXlhyK&&MGaFM9e1cR0F z&&}66amPGb^Ng}q>?zKAoza@Ua4zBx1@!a-p4VLt8l3W+s@FTl4UWYMDZmuss9Hlz z2}n{wy7BG|C$Z2MZ?!rX7wnlA&1qYKRwEpNQO*of8da==sO)^+&OU_ciB5Su(H|Q5 zqtn9h>aKUBFR|f6qfW&nnfXOwtOHJuskpv_BV<72ZtyzrvV5L0_&g(c)=2wkBlz(P zbeAwfe;P0c50&yTo3Rdrrh}Y?y@71*4`0}-gLR2Peb0z6x?ZN2x^(1R86HFp>+xkTc<8{XMb3M#w#gpsld%0fL7XLFA@ zqqb$`n=d~%;lJ=>$p}B<6z5$K8e#6t5}YHiLlp}{4EF24x>`>Aejc~%Ja9Cyata0+ zUHIw@(ltm7+!@0LIQ6G}LZGD$%_-v+t(NP4Y`Lc96H)@gUWvc=+4j+QV%+r}>(#3||^i_17H^W*^t8R@oZ2(tf;Te~qI@k2MQw zlCYGVFsu(m9}Mml zccEsWa#==LEe{hJTk-8fe@u%rkZ!=)4!?)xH3LEZ6-G#&V!G`4C9 z2dd&$W$Ih41sG)}Q!&?NRH&eF>Qf2h2ByPBjo~1ybZsnyvp@STY^Sw!mf*oQ;xBg1 zgia!k$zppkN~f`bg8J zfEI7DJsk($Jd7y=MdpfX>fs#N38I|X3j1Ky^q4U51x1_g6qkF`nwBqbq+oNWO-}Zc z&EnF6)~k2pbw9hw^1>Z*d#rgdl!0C4!49On0TUct}0u{hC@Y2Em>UjAA$NUu5shzE#j0J z>J^gWsZpK)r@=zx!FQlP1_I^!p_|#`w=2>}MlP)zrh_iGMii;ks8~25i=NS>>#${G zCUO$e?g?^PdstAyCV-ffQyIzjsS%)AUCNQ3;ny!$K^NTI7Y_;LjhZT1dA}-+k!K~A z35&^!rv!ELzQZM{MG{X#mw%PVDbRTzN#27O|EXW44y~fHi0#8nL)R8ifE*@PEiEkq zcOuzjxmJiDZZ)e`S)Q^~K-PRxPgkl~=@-y2T89xTtEPx7rl9h{7;{+!K8)xT4gesT zyx+)tc;56fi{U>SO;ThC0Bf9idg~;IOK*nU+m?1$q7csD#T*PMOx{ zLT+c1+a6rJjbA<8;}#9d5tw$~lk$4W0yJ8P^$BUV%!{TN+B2oLbXo7{>F^h!67?x? z+1U&S$-@0f1-D;5$c_IP5#KzBBOmqe@>NJqc8ROC<9xVK$eA4%pcqeVX9(Snvk#?{ zDJ>P$2IBXx1x8s|r&8Tiun_nWXg}{~yC;J-88-yVOl8IW-o$;VHI6u|Ioq@`YO(w6 zwB>Sqdcw{iN()E^PxjOtqT9%Y#q1NKxA6gsvdWcMtThAc`FGrio6W{cU@Gez)}J5* z&v%6_ddDsdb`Lo(IeH$OXTD8~Kl-O@FW1LxzL54AitW}@v4KN*2jgehOn9xyX@+Ce zb`58oBr&U}H~`tmz=Rf2{2YFMR96Cd_s#Y&3~|0mVFVqBMZ^H+qrNQ3G~v2MMFU4E zXPFX+#`0Sf*c%jhE6i7yF6;xoJyg@Kv6E+8uY4 zluCMo#PJWBqZ?rJ%cR4{?kLJ-l#oEPo@#5APfr)05tW7e8%w8?6+yn{Z7a%KqFtem zuA4@sp+LOf3Gn%A7E0Fq7?Mc%s@Xo}CzRQ`9^6@E$_4}GpQ9J6F)4D1)rBaw!CsS4 zgYnbi?kpe}slU$a$woxZ@gOJQP{ug0F#L|63MnILcULGqS@scdPKpMZlOt@2@WcC@ ziMb`0Oaf;1Hl~U!G@X}Ms*$+E0UTj2=mNo(sfv!Sy+pN?tQPJx+~d&Lq+fWD4I4e@ zRqRL-K~w`8DM@#Lx`hS&7SdK5;AS(n0BQ*$aOg2^h2V_zBXq^rs;bIeL zz87#6xp$j^qH+hb?g+vN)9UcU-j?M6JjA-&KdT`3$;Jg@U-YWCJW=om)a-UOBJRDF^1 zR%rTF6IV;|KThDwoDZt(jt`~hU}07yO*6uf5S77bWsynX4V1LHPhZhW!|QWiesrL7 zDH%r7o~-Nh+h?J0oB23K>Zq%cedHoCyk4nFER`aYkI}z+y89M^koMG2W7h2TB|cGf z6OT57gVJ@Z;kIBLATA`T;}@!iNc`UjJ4B4T<9*fR3`B*;9UGO9M)$!7HIjfy+Ld}@{{ z(jodCB^@(!SBMq|_k#A+K~5s(l7eDQhk!SO#d!m9P5cw;5!Uzo6;(ixMWi66X-89+ zqr;I9;9Xp0Tk697R`K|CA%4i`&><^ehA!)8zgVoqDaNCrC&jG*S|ESs$))oXG?0DL6{4W;#Er-)7D>THTkBD15vFMfJ=3i5vt^UD;_Z783jM zJr}z%kz%`;m^?yZX6V@M!bbv{KDHtDr+q@(j;5JK`l%LH z3R?JH**CU{pAg_N?WA;eMl|Asq^rCD-r&3NyqZMt>7uKtoOuTY<@9;5N;9qwA|;2F z|GaUSod@xNdq&PO*{Xk_`INNxedpfJ^h>XW(%?a6>j4}#9TmlSnP*K?Gx(b;s%P0* zXf;Njam!|~r_7WP&*PL2r3~NY3!3fi`L>X`V(aB7xHIpmI&dq;uCkn_4xe)q)^~gk z9iWgWFqOfTU2^F@+Ktql^1I0h*7Q7!%e@u>8w|7w+A7hB#SJnBbdNho=EcS@K491U z$U(s)z4XCTM#{KcUbo8Gs3Tkv=v3V@C3t)n6?b7}kg;0ao%w_Xuu}Vj)`k87{BDNn~^pVY42M7m&7g%!fz|&QP4(xQ*Zs zhGPa;Zgs}aCdbd>!*`z21H>FF3YSy!sNSoSd?85@Z>7$!_oo}p2m zf=NSZz=bcv$L48VJ6>I1CI`bw`I|Yvp!c3g`ACh|J;K*ydNe$#z)bCNlG3zkIbI|% z5s$3IHrbNyhcZ=j%9SQ~i?7ZCih{E}ph};d9$)F#7qHRylS9lxVv_pNhXTeM48vJF zAaIcj%aEc-4VP7CEYUzEj2Xoq(pWKsj+lkhBLYB~sKN*k2qf^pLYM|ArU>#RF7Zn0 zXV``B&n}j)PIq%IJDo0Hx-OOdR^G&;^RBL-qQ$^~1@EH$q+r4^P#1yF0tz>fK1(O= zP>9PJ<4hR}CEF9hKeOPJhQwtbA2V-a#8J@5OnsRev(ZKEby<%ReZs>~?ZBJ*R$Mo< zL-%^>$q{KiT9t60lH!&q@zwSvxGW?kNLq^PHfm{lR`AZ*W)R5S;50_X`ICoBu0Q8# zSSQk9dDSU%E^4FM$M5J5_$)iG?`@P~iD8v~j<>0h+W~vGM>uQj93oWer8e){B4%PS#EkUP>inWs;~~PfSF>?zTs^4Vz&NoKv^vieWh&;|VWn|9=0q^c zaj6V8-_x!Tb~v=>#!xJyhj)wY)*rh8S2ko`=W*vp$WoOdf`Ay|4PV+c!J5n!N?d*p z%GDolf6$caR?$>aUr^z8F`#ipo2@CVVLgCFt-`GS_zqPtFZaSc+L2{)nz(2u$yl(l zFc&-Nvz(GV7owc~V{+~hQb=6nsvzWS{Uv8tUvoVVIk|Cx5}t^t{DP6q$S42}#-+W; zt_9q#^^{oy*;9oU0GWfcE)UQx)pBa#E)kf(`YOT>5h6uinv~03jDuw_g1#O`-XFDS zjPm9hSJdq_Fu8+&RPQE&z};%Gii%2g=_35TRpz~363Q02yU`krj_%qQrFi&*-P*Uq zz8NT?$;l1}0=qD}fVLTPFOo|IXSEQo9~)7)4FUbjauN=xG#e9HtA4hz!CBxP3F*VpIPN@80&OOy_kCN+PucNy}PU5QESKt87GBYWNc*vQTu(~I9 ztPf0Y229q~0iSCT8a+-^rBu!iYzVOMrz!(`VGvRUZvwEGnr7(^RTvu2WIuAzL=g@@ z^IuA^Aj|10%!dPm1uWXBn9s;Os>{kf>SAQ8ojD^H;Lu&9n{`KY_0qSy7Ir-i+Dmcu zqa5=7*dAvQ16=P`EIy4s4cu{d6qNLA4rO(^nBn;37j$g8W2~OXA$=fCxmPOh(xnqn z!;^u`oedDGEM--)VoU8bu|ko-gJ+h=e@CIpj-zhnEK!2vDBjm?lV*UY4E(7aSJY^> zW_Z8On#*_cQHf%IoHnLBXbGW|-3!J$=c-4KE}UG7-i*V}7IC4Oc!H97*KG z&oL7#ut=LHyl&LK-h6{Rji~A*Z2HyF*?uFD3<;E$Jj7noo5Gdd0w{AB{9a*x@dm4U zA8LgN+xC5Vg3%7`SXqz(C@|q8rlz>e&N$02V%1Qx(1`)%bqEB0^YzM{AqPB_q=;43 zmt!Z;u@zIY74KqKjn(hrd5)Lr*v5Ej^;m&?g$(>6Q{rsbZ?SqLZ-oinqLBL&4%B;OnAW%Ysuz_{vwBHbbqIO;E)@}*G|P^*t0 zD}cf9a%h0~Y@BE07tT--@HE~W&RVYFxmld1w_|U@3%6bSaSaPViJ#8*7YuZK`3|KpmO@!;)Q`OqOmAZf2dr-ZkZLM>Jw}mC*|Ki2i|_ zxeF5gOx=;2XxWtfP}SF0;R^qlOT=3H(^WyGq%(x?E*94K&h}gcS)V4j;jqK{CR&lu z!{mo1sb<{w;z#4hENIJ^lBCt?arDBb19TC4w`endM)R;nL%pGDK{|SCkAwXu`)~L1&?;2}>%z&2mKHg&sNn_nGR)~prolDe2gYOj7b{ZS$92eOURqd5j+;0!~cfmt`q zwWH+VCM-;y8^>_^kssP*qvic5FUE^v?XY_B&FOc$se)7^Iy06@pjIi_^`% zm5EqM7OCrN$wT2$O`_S4*+J;oOg`r*LY%az164`SW)Hzi@JC_be6n0ll0k^ReoJGa zCyqP3sB4H&<2@))=IIF5*iU`4uiRPRC`dx)`0@{n0}j3`I(T4;0zOQ4jTmtG@vRsAv^#r z8``iXB1tK`bz)M9|DuPgT;1k+e=R#D{CHnm+AwCEF|oK@$^+w|G68;70Q#9&fC1RG zKHtP$sb=FaWLMN(-?Q1y7eXr=Sv4^5NssR5&k-gf$ao^}*N9{s3?h<{E6^2e74eaU z_`7uejhZ1x3lqeJ1aY%~lYQt|Tm$6KuSnNu*}O({wgehv88+vovG(HL)RR{1#SJmJ z)BU0Hx!vq+5x2L*&i2OECs$)SKxSr`hn_^MXNZh~`JWVBKGiv=c%a2@`neq;+rh~e zfDq>e!i05}Zc-=suw2;MOv#fRsS{S8v^GaNy%H6de)LyyIS)yb3GZ^R*C;knUlT08 zGqQAfZyT_%>j+kzj2v*anHMz>SX=O$fFhpz#A%Wc? zhFPiGiXfu}!O*=T*Sx_8^ycGYg7>RhiCYz`NNZ(CP`4mNJ2T0y?3pkK&+QeDW%E41 zv6o9@))dw5?eDKU&0J+)dSk|DnN1^XcC%-5TML>a@tOJ^jRrn3M5HQz6`T*Ly$;vY zu2k`H>Hk!{AzOvkdLQ#4!LEBDJ$I%zeF{IxFfyWS<%lc=HuIRvJ6N;5E^Twg3Z*yM zDtoMTIeN;o`MYd&3PJ(K(kS{)aj{`BT>I=3(d2~^pCxhrGU|e^jMy%7x}CO5i^4^p zJ)|w60|=Klqb8WAzoXIVw#RpWD~OH*=?(~(*D_!w_{U+)%DJx-)W}S#s#yUm$p ztz&&NToG`wouPx_@#r98rGX-I5GCY3+V=4dR3q~bmPeRlYg{8Lr>x(9{IcrL^1Syb zuX#Fx%4GpjVE?mnlT<$<6n_eVH^-{Eqn?S~Hb$?5>t?+Wd>$%gkdh{hC{V1VYr8Bu zA&ye-X5?wsa|5{|0dvV1>TP>cgM@m5@MUPnQ4oY$xH53&7U_W~Oe;s@^GEac!dpkd zw+TYaHdSY%C4*chuwo*tF@B?Au%dbs>Z{ZC9?-K)GHJAA5~?8VDCNLF@Im$q71rvV z{S*#=VIyl4g#GM;de19+6z74&QtFwU+FWja@6&scb|0dxy^<@}s$pb?z6l9{HSqWHp%nY}JN#;SMsLv;OR^)T^KsbqLKXc9Uy`@0gQ3+-Yu5Fm7O2o%f+6#@K&R+wOjJjg+e zCku-nS~A4cyyVv+KF$P;{*74cR>|C(5_o?T+E!DKs33~Lk9z?R<504!#8(8hUvhd_ z=*Vp~w8ki3?K90YH@hU`Yzw zxd4D008H>NvLJwW_?wRS2U_qSfBZ9C=WmSR?||%%5BAP) z3HIM09ytJ|5fH?m49j17j0EzoCXTKaCT{HC1wIu zTPGKLdpk#G0F7Q!h~N)2i?xM;t&s=8FVdwAfYS1>(tiV^{;M=2DKq4KSl@ z)B*V4e=dYyFaIB{111h9<6mj|vyOkK>E9w?{wE~`0Q%e14#1lJ7pcD|`Cmiwf8+-c z$DjH69mk(izbDi05n-fbB2cz7b#?=ULLg!Sn6Snswni5JlC?kP+wZ6ZZEfwG0ff;% zY8JpV2H-3IC>4U=Gxrxu?Eif%^6#Pj1B(1h=HH>n0MPb7t}cIc>vunYb>&xQ0eod6 zXKi*yIzZ|f7yx`M4h}j1qKN^(WM*aN{PidkGXVffPsa)P!3KbG3fVatn>hX=H!}dl z{)E}dSlC+83j!Fhs!Ea+=FWgE7CpV2n;V^tiM6$Xt(`lak(~_zCB5<=&;K)k`tM=- z1NQlU2dVu(V6^{N6xzQp-hX167+Dzp6Q${&X-Y-vtG2l8NS`-rw}_X;SZbx2pg@Kk z6Uf5m2GkVMN>5EN8QD z*V4>c-;`UJSf&r?yTq9~tm3Z%X+xz# zxap7VCB+PSVjD20MY~E-1#mi%v5Bos)zOp;)lDq@f1U2hfZ=foPFz7wd`qQWB7H$;BnURt*0yVPGL(GGn8{o%1&AEUy) z+Swl4F#IwYkkA85x|=v(=fY4;flM+Ugn%cyjLh|7ScHrTgagi(`_U-E>Cup~DKSTX zkux)_sF==_{Pt4DeEB9AOB19eV_IaU08Seo`6* zJ7OCV8f@lMCSrzfIWo|sY3AkLb=KwvE-h`Q#{Pj_EuiF2=S5w&WW=-GpgJDQocv3m zYwV|PUz}PfuFb0lr{b&xCOqINM0!6TII1Zt9;mfY9aJB()_huXZ6i%~K_8j^xVxWv zS@~mmnbhmv+RXRWG`9S3#_iz?s46+O?tvA)a|ObRZA3HeDGE<;aU$i=oAyy(Iu>@q zwYy|R3s0_22*+k#kqJn8AVk)AU^wl8lL1^t-v?`O-q_%nt$RZc_>5MzIiA`qv{UAM z36$XlCi#PjWshq`-kM-Bl-F>eH`$MixF@`kU4_pH!hx8&BxiYuJem4xp=Y1m1){C* zs_AlFq17C^*FF|PbWY4&^1gP2zT3{Pwh8j8_t-Qd%?j(Dqws@LaGk^E#3$&@_Y>xT z5w3(Ol4{J|czArMb#fDMG9WU0(Tkb|17)~fa)Ks?FP&2gz5}I9qlHKx$Rp?n8z)74 z*3nvM(zzEApdgURtMC@J0?ENt_LtzjW6sd~=CaMRKK+(7OT35%~XX8D8<7x3|vz2Qi6n(hS+5f3+9DrG}&ebW5N>N^ZQ#m zJHk*9hy+7$YGg;@l^CN+-_c&>j>|E*rd>Ymb(+XBWDOcO8f{(&TA5xuhXh_JM{J7v z89Oov#K`{egZIE*s8URf=I4x1A~f)CMh=>g)-uzq(DPf0PWsTOkwzK3gro$8*O3`2 zHx&ZA>)+F5zq2Ig}NDJvosAOZ69GBm2RljM08@ zMUyOn6>JoHtUd6p7$}dXw?^qp0xRkqo^5>RrnhkVGyI)Ds&zOwdhjs(5I168$zN^0w$P8$jTbB=8m?NbKCHxut}0A$i^v0*xM9j{NIJDf3BcKJkx=G` zB8DxIurnhmZ%M3Yk0(MTH@%-a^=Bmg@}U^6=D2hxLpEC17B8N;BTAXp8_C|aWTXij z>)?<0zYR&RP1&ec8-O<3DsNBWtoPrbvuT5|O=S%4zX&+2h)3)WlyJQ3bFFUNq$bc# z`%Eqt98#8Mx+5V)j?jlO;kDb&VwV}t%8KVB$Y`o}FTZ6t@~wZL_f4IHXI~l4P=Y~% zEEa&lPQLVFPm9lJlXo$Nm(AX!`_2yvbo>2g_CLAyzkTtaYwRzRNbt+V5&ZH~1iw5S zz|8-#_!0mxhQEIO`%=vK|LI!H_}60m8}0t@i!t-xi}By4``;I14kkMGKNjOZfR+q& zjEsPlnH7MKXQN|f1w0C%nX)te`RKnd#(!JCKlTRyyfpu<`?nYWAG$0obWDIg0L(WN zDDMr?GqS&x!nIO{I@;-AHqz3xeq3Q5dl~ZK#RYP z$bWPne+&O|_WxP_`BjsMMLGO;tzu`_Z4Hj@O5EUa{lYyfG19K&DA zfa0O!{G;6eSAj8c{#WV$zr7^A7(oBm#e z?=k+=LGJmXK8c)&LNE!JLzi0F zlYgR&=d00M`hBUSneDgCqec+n52I!NwXU{c0Sp1=3P<9Rn)aW!;# z!SMbzSy_yht&xU`8GSI8?}miQ!a^k{gCg9h6yu>WEvECFCgu~lY9zXkW@g#2!#$sS z<6^#pBECv=3*+nN5f4>BJA$BE-iBqO7+sk&*5HL)sUn8T1SC8STUnB;WD*2_D^cO0 z6PeF!FO3i2HYQZriuvI-Ny{ASk(lniW3-ki1ymOO6CKifmwZ zn4Z{4?)Qb@yk3aCU%@_pRQ=$uC~jiNs($GkzTj!9Qf*pJUC2Y*&nb#Ve&UmoN#Q!^ z$u5n$RTRy^gaIXoD+K(3EmtbfMN7;9_>dhd(SqXJkf=pC4?+qb+L1R4o4w~Xa)CKV z1fdR=Suu>X0{S|*oY3M>%dK9-Tvj(&JR@T}0Q=eklRn9%&uEGLxa#DqLoki8HX zW=B+iwouPbZ)ZvJkL>p)CjF^?RL7WnX<}`R_M7+Zr;srM$-ZHXgkds6>m+g$>xHLY zW1>d~`!8KW)P00(j^K|`XD;DIQq~j}pbFR$1g;hr^GP7Q5NNq*N&vi%11h0&$JXHd z7tY8YlZUqW@MZ4Uq)oB61d`7`RLf^G+$8DI@ zQe{21&g!#xY<5IQE8gFJm;&|d^&UTa+y1wtKX||jmWRl?atR<#zdtd{Cve_ zs=!mK6COR~U6CoI^x2<58O#lb4$cw?FVL^fR()m9k2%!KhQUej8g3Ma=(IVQ1_sTT zbznqmP=8xeWGF&Cy9FE##kdQcvK3wWvj7cj(&%<)uNTG_@K zCT^Su%8OHCqZ!ZRAFGo&>P+A-`$>Xgc(2dW^t!l^7pc|u>{r7)y9-1j^Z7-- zCzW3!C@At_J02rAAtn3UOrhjcLUuJw@8axL-;7w@S%0o2Y*hfC*Vb-|9e}yzrRR<( zn!wOa6cQ_9a}W4p(l7DJ%^aV_zs3@GU-KTz){!N?KIpU(iWZb!|Ka4!viVX=?KwXD zw3(sSqxvLd<}<@yMPZ9zB^&qGqxy4^?8`@QG;SXC%;&iwPOB~S;#jGBzU$(QsGCaXI{&JOKnen`=xuOYXc^ud6gN*5X!{4DKjKf{1i*h7X5AJjQ|C zCV^43^0O1r5R^0oQxc76O>wMhmJpgtN*jNK zTIU@E{EP$j2?yOH(bfkfSzRdM)Y7qa6|-t6o?wJ>Q4Ybg=&_!dzMzjD{9LLa^>yRQ z5069qQm4q!U|NN-0~$e)Wa^AGFT_(v*}_4jUAa0Vg@EOz95NHtPYG+>XxpL}{^mpO z<(PUEYU~Qthk$K7ZLp7|kZJBbWEY_R_-|Q=457fg!Ib3KaNW_QC1E*v^ zpIhpob5Pngl8!A3qBTnm^TXe0<<6}@vh;h`f)Yp&aRGC7rk?fjaz}x!$m6s!%e9#9-_L|rph+r2aVyO$d&Q(+$o>h2nws5=w)4|-(8Vsab?$dd*4Y-4=t_m_d3b zN0p2m;#?B%J-0bfm|-A&7MWe2I0uW-hB_XO^o*)Vg_hGB^19;qb>%Y>Lo&fbN;vht z`J14AUB7MvAu!@FId0EahIe>24r@RCHpHLJ7O~MCK3mAof?{o;t@Ouwj%7K5K{T;- zYbK<1zJXkOz$?g)0_l(7ViONq&na(e#*eVQ4QzTuk7EVm_iOT^eJSeS`c*x@>W`87 z`oCo3Jym|_Ge4uVUfZi-avwn@D0=kSbWMuHE_EEYgR`HzOKxFd<+t;I+~zRR{?P0r z6*sHYNmLJ?Tdgr`hU^@8yp7cisidjeW%zYLM2eouXJ1#Mqx;G>U0_tz^{f9eDI^G= z@K=%}0l7xUoz{RiwXJ#loxFGC>eOZEjP%%t1p`(1)W; zL96he#CDF=rBfCbtH}_MuV7#+hE(#+$ZYUk`pr|7%_SR}sLN6k4wQ<774j$c>x$N$ zAiHZ)tgs5tw(`8~XDtYVdyL0aUs)fiK+)w?QCEQ}qnj|i2XNfm3~hwxeQIK)$dv17 zOnVhn=R9ib7x10Msywvx zGFuBjD|f;iGp8%bDu7xyf6XzXOwYHIOLY6BA+3QH^?KuDzsoosAwzh|nMuOx#{F~@ zjv~_M1)QAEop!A?r{f$v#fwXVxKni(PPKe{+V++Bu%{ZgAk%bdPxH9T@KNqH5SwMX zWG7|O?tuRIP3u!|G#YOrH)ajv+fbeOm~&5?6)s(oB#Gx8g`2Z=l)?{O7JPobO)qKN z_AQYZ4yp0PNO6|ko4c#)+CW5@VMFCeAVlRvnyrNDkChJKUKt~jCC&x@B1@$c^Dn4S z3Xk`whgGG3FG0{chwL9jgL4aK8j2HykQ;AdVhjOWv7@~a8(eM4x;e6{W8XCdsdLB)nLDR@$Y0u8F4yR-!oK%u1Qz(~iev3e^aQz@pZ zXX0lEP9z37@BTl$y=FFk8c-BoPLbNsMxUOHd-H{X+pwF+roghh~`9l*u-K z1o$i*)0LNKDEYE}kJD3#aso@hU+SEl_u48 z?~bg$SYbay`n(EKa_!GNu|z)j$WS!25QS%T+MCIM?WHgE+#cspS7Lx^=vS3Vdru(k z>0UZR#o2Isbrme>`s>WBHeL;^TgfG*DpLy&>aK5SuvCMEtOglM!mVPS3uiCwXJAp_ z)5jorTG5j|ZtCj6n~}aPeQ{%0cG*pqL`R&YC3{3*yMwarmqU~?8j)@nY?EIs>7eQ`JI|!Bs6c>}YwZ9FOm#(cw3XZ;Lf3`1WRZni;X}lsaguVG zB&rTRrYzuLhxnShRhsEiwZSf9-LB(&X0$lI-jgpe|F-0jE>}V3OZ%1orxqe1nDR|haxtk*t8+orpMCO#Yuv-yk;3n;uPNqp#3E+TYliLPusx? zUB(lk#sh&?)1;VAw4H$XR>dK&xkJf_C(n*U7OEH@KISCBz$gLA!VO?jy4Px6Ff+wK{=uS&S%51$jS(wXVEkid3RarBy$5rl?JgwI zkt!=qldAZFy{_2@#vUIv+K1TJW+S0E8#J>&_ECB~zwOP2uNx_wUQAI4=Ns@WtLsiH+uM@e4lGHCSZyiqK^}eU_FBi;HR4Spr8P8Fc1P5RFmSiTjwmy8lH%b z1ogewI-In~)`8U~GD?ergHcRVe`Qv<>C`}Yi={TR1=j5v?3sGICJmrMfIv?twbvIn z6{X&RI~-}CuPaCwR>>bVV8YW^fH6b)<+D5LgmFdafnuz;M&O1~=^1pPZ-naZxWe3*-A%N=#<)D`fqKe*cFHOPtU1=mwB@^2bH3zH}AoSoNq&# zZJ#oEtc>nD1CN}(!I%aQXs^QT{fc5xwu4?i4`->0OL^jvFz$PMmKc08e;q(GBL-Hm zJEn13X@^3rKhR&k3s%9wJ`4;}S%T>Q`qVMJ6=7&Wl024b$06UamkCU=x2%MNV14>f zNdprNm@b{`;$A^lJO9-de%K5+DLU=*uOJSGYG>K{qbQKv^@cP8g?wY_*h4q z6EbvQp7`R@U_JRtk;10NDe;=c0gR4$NQ)3ljd$6$Dk6XV=j?UjfNb4ItQG17yuvi| z<5lzhq91PstB~H>o0A;zoUdSNyeYr1Fi_LNq0XkHg zv5842iID5xu9F1Iy@7+>EdkR_rv%8kp0Z+r5<+r@ka%K#!cRYRg(&}71!He}`SZvp z6{Mk9!7Rx~n~MMXfujz@gOJA5X#sE3_uCFiNG6812BW~3@h=t(z@JE@(mk52M{Jtk zdhpBuQId$A>;YIy3Ze$%CdcwF6Dai?@en|#j=(d z)!>nHdv`V|CJVQSZ|3(I97`Fa5MG0^fs+L4+^gO1F}pc(uPKnt_-wPW46?H~5X_Z$ z`T7>T+&rSs95B{q^)|#W+1<&i3qdf#E`V3)t&Zz)q#-!nMv#o!vBM4nB(#;@nl36) zN{j5GkTMefjsE9$pO4Xqr3CpUW^U;56o;ZUA03V>A5g0 z#0h0wCkyNl=$8pFtfGn^3Re`L68lJ4!o)fVq2#IyRPc7+Fu$Vqk^W2P$d45He`#C) zB9=dzn4yEYos;d4*z6aLb|#&FzLeFsHvVDd*2a!B z5>EP7=7#^$hfE#uIoRoxoQ$ni@!44aX^8);A*637ZftI9=7i76!bGS3zuL^q40HmH zhCfsppOu5-Uj~hT+BA&xEOh_Tr+|&Al`%dI0}Cz7zeQh$f2+;^8%qBuy8k#U-0h5i zJSL|9`f&JHzf4U3;U7`7{jnVwYX8EVP|Ez>F{~tH^Z%O)pngRba=Ko8rV_^Jm)w)bo z8QUKS+;vm48^;}b%+|&q8)(dB|0~a|lOOJf0Vf-A#TF@lNq&3p#A;U=O`ynw!*gU3 zoJ?)(*+ui}n7KU6V!KYwr5UF?Kah^H(g**}7N*%~UYZn5i?6TjuvK2Jw#6h#iVksJ znF3cjK)TRPm-l@HY9(7y$Y!4((UUxI9`2I=^yS*@G7j9}_LwHwa?P<7aL24-Cy4T)N7 zVPHRU9Y+is;^e_@c&?FQ`20Bfh~+9D&$LFt|=hn)G;9t!D!=~A-@^e zgCO|4I*|O}-|uq93*m|%{JZk#O4SJMMIo9TT6G+u($qt7pM@_wQT=C<;Z-PC*oHnd zuvAIX(5cQENoywEU5VF$!Hxi-gUbWhriYqzCU6vTRTxYZmwy(cExZE zr)cxGii~L=aA!k2!;i$#L}wa&vXM;50D@GL5|3u1sg_gg!@vkYOm`zosJ@v>(v}gZ z3)bn#_~c_6_m;QvX2`LF+O2WiozrTkJ;Y4zZ$ zr=ThMgcm2qZM1^5!B(tv0YuMlO6I}6Kb*!ES&F67puJW&Fn@>7P@6s^*@0U!>x1b> zlPUR7^^=30>pn@lL*LepnUQ9i8RT7KZoR`9~Kiu5q*E8J)^w%HB z4NAvZyCV4PkE)Q8S1sh&lZo~Mp8a{W#o!#+!Ws2%Tmbyqq3Gtxe5dh*7> zH5KiH6H1LeKDpKVY+PJ{aduJq}9~ zZ6}u{?qr=7m7o7-d?N0{QtBG5sk23aw(q(alj?5Wn!L$E@ABCuO9S#eUk62(cqc)M z*VqGf7H-Kg)05kPF}MU4?ILD`0iIfWD7uY%_t}T!%)Y1vtZImqvWw2I*n9eskEcCw z_e(st;n#g!tM^jqkHyycf0FUD^KSC$pZ}nPv?uvll$OqsLH+8eCb}0pV67?lpeQ|~ zj<~d?RxI)wk5F4O5};A?$)-kG# zAI#k zMe(yLqogi(_=f$pxEMF|U(r;Ce>1WFy&f?B$F%OqPvpkrUmzFpMj<-dQjXB{a3Ab4U6}@mf8uwlWjTR9J)d zuyGa|J5-JEQz_sz-IYmU@=Wi#RC#L>%XBT=4w6RA)5>|@cOzkXhA`dBe)GN=E3Y;> zh(^hnEcBZQ$mkOJB2h~+iYj=G<$Em}!YyK2@5s`ImJ zgM)U~>Wlk#dncKY^xDpn38}qq7IpWt!SWVR&Ayge?LQsD-RA4lMf>ZkDqCp#mzvSi zBc_u!s5B}b18G5U8!|F3u=~L+Uub4vYcHPHIqud+^YL9Uv?6h{bOBR^7nQ*X%b zUbv~>cA#*{&942KE@`F=4DUHufKuX*^$Vi`j+hczV?II@fmadZoKR)Lj6&JB4;2O{NmVb_=9qhKs_?j3QlqW$qa8TOQo5K6To`12k|xI2PN17LaGApwHr)CkpT-|AW`$6@tj0qMS89F=BN zulh@Gx;^bb&!;StyuUw}F4VM%sKwBXKtf19_%~Himj6r^8NUU;>qYQx--h0qENQ_2 zsOk9$s7SPfWgVn=Gz2p0?Yixp0{Xa|lL(odXI1ak&c9wpTL9*?@h-0KyAK(4xS%nm z4*{J)msVjfqmGs`!>Op0TQjA{__X?fNd9(i7}3>tEUZNyqNLF<<`gc18eJB$GZ}6# zt)M7E?+!+9P@luar+_XLn8<CVs(e01H=T-xT>sx9uae{Mj8w z&aocU>k_2>H^jp8p);Er9;;w039Whtj*4H2bo2U9C&+3gT4-<R;!Dj;SXbDgxv&EvM72 zqkaP6K9TCg=_HiwES5PE)Jn`M1bJwq&S)NB4-jU!kroSR!Gd%=d_|f1y^Z3owqf*2 ze(#9#P7*UH1lb;kzacx4fG-&^zOL}0{8&q@$=U)rOix6^5fM92xI{(L*C1VOy|D6aWhLPR zxuV)eAUj(6rJcc)r!vmEt_!Zel_X}n<^UR2{qwORp`?2lNLI5W^qCGUpDI{EqNG8w z%xQKxzMVeIJYB>7THB3SX!+)C4`FoaV3ca*EO1R!bh8BxyE5D5b`Ljn-%2C|mBjOo zIwb;4Jam|J-+(~KNj=IF%GWZ&2X_O;i;=A3g$Pp#?R%QhpsdmXL4B9$gs_|_Y}vlD z1953(M>~kKHudc%*>~^FBv#|m#kO&yF~bI|^Chu7T#uU3t!!>CquG^D+e2peKP-}8 z$Ht`@9fGB=v8e~Zz}%AnuSDUZH2k1SUauE&S5SgbcWRzp&WYTq_^imoz3C*&5gj?V;}S8%#RO9(N3Q#j%2 zd%zg;F>Z=d2%pO`N3}z|6`c-43gh=6`2Wniu?tY#M)gdz=Lf7oc@cs)gsH+scKm6R z2~?@|o^joM#R}nbW0IkQgsQ|h0HEXi2)}Nk>a4whKus%M)~#NV8BpBtyH#Ik@Pdv_ zh-QM8kj~Lo`?)jFg$zHw!}Kp5)9ekN3&LQ>N$&o#Enav=f}PT%2czfsyC@4$S@bG) zopg{KEZvu(w_ldtECc}wV74y(-41K{7z18%nu@XXnfwku$$VoQW={pSI449)&o0h>ou1J}71*ImKh zeg-9_le5u0Q}SLYaU^@xAle>CUjC&`nQLGlbJa6mZXLDJ9i6&%L9{D(>Q{ee$+l>L z3LZuU+&E6J-eb`>&Ooss-~zC(nxI(kAOGhZr|BG;pXwex`JtIvUj_&qEVl0SwzzCC z^G;!)(`C`>N-La^S{5 zhNT>s^f8p6K5`{6Q1}L$y!!>AkIBG#`G=dKt_o(^8Tfx^fgz%;UxJPIcwAjVVUb}` zs}rKF=VTGav4AgIp8ei27e@pghdwpOy6?p0G_AB-w-gaJ?j`5OuEN8q&ERUz8LBOj4!BL>&1ZV%+ z!-&cNjn#h=E7CtF=0Ks$ooMOclI-Fv_XISJ_U(hbWd)Ig(ZEBf>#+MdhE zVyf5cDwqnXZerAl_;)lZBLrC=9)*xsjm6W$()*{6T^(G-UWo)BZbmPl#Y1-*aujN; zbwipK?|j&)lhmjOI{yL#$i9Y#kj1S>(2wANjnbGZvp-oJesJ?frmkHA#pK0TR~K6~ zNR6Ka)*H_Wexthl;&rFUiG!A09b#1WK5 zbzbWfra6qe&3HH6KetVI`|$V4b5X))z;dX`I*r?^?VG0PR}bbB=$_hQo{M%dYBaZtX6i^9ta+P$P zXWFk6X6o|hH|m7K@B;EFSIcfIi|pHUDawYX8Rg^7+s|47Mvsk?;ww{bD{$Om*b9Lv zh_-POUq@Z*4r?rd$FARXa>3xMkgh4(@$QZp_zy}bkuSPs0Ehngy>;v{R-SKo=*CsF_Al*8u zr^Kp>ANhFVzZnp<#gC5zT9X{A(hm%okwvnV2>AM9@J?U5KcmC(ICA@mx~$sJ?3Bd` zm`xid!!_2`yKs4yDC7B#X>ikll|*p)hQG@O;G%U(2S#GDQp(^*I6o8wLUKhXtZhbg z&F1GD;bvR>@N#W)O=P3k21PCBVx$_U;+3u%cR5^~ao||bR^|}y4nfMW?amcd?QLP^ zf^n(1wOM7G3eS&^`~z$aB#FWWIjQf{u|7gkYlb!Z>CdR`eF02q=aynUtwh&U)AHF= zYac%3pJ}KgQaW_EaJi=y+UU*+91#X?cE(gpGh2P`!5?fYgB$?SEAq|F>S^PLo{l$hF^Pk&qs4Iz-3(p6WlUfbQ zA}{%C*{$&M>l*9b4)^b^>N`Y>>jaEp&j~{~)}%HBPcjZ3EBYJEM@LO8pEU-CV#XG@ zKnT~ht>q;hKPwuRyvwGI@Qb3eb9tXtUpo;xLfT3B)o41E&79C_4WsTAN<^&7FKC6{ zx2rBc6Wmc@?(I(kp=}WoWgXPtf2s}spC0F^2KlNVYbEF>r!95~N+s37&XW$BrLpI2GH+Xhzx1T~AlYk-hDAf7g?x`%<;9-$cG_QV1Kt#_?`{9{L~OC>~M&>_55! zIGhv58Qn&gRt51TzbnIQ1ih6r@oWiENbm0Yd`YbI+CFXp11PcKJyO=sUNkH(_>rkw z2n#X7vSR+I77(7MwD5}1CC)5XNcw%K9NGBtoJz`lx-HjRiNM~JTU%up}hk!%on@GIsFB~}-v1Wk(wLbRNG zh`0|Bv2q_+h_=r7y#yygAq(7cHYL*^?9r@vFdl8pQAIe9XRYKFY))Igl1Ku+Pniwf zr3hDYXt+0-3tm%4*Lb=FRBaSM&ntZ?2I}CPO#jjnvo9QZxDC(Ca!(7X#%j=1z>Ad~ zu#kmMYoIALoa1QK)V}#B|3#!_8_30H6w)Iab4LG(gV*%fR^>6s>7~98r6iBCZ>13M z@(eFcjz!fJMuI((MeaRG*_0X2JsY^5>Ix*mJa%S*Ed1bXOobHUV$$Cw?5iM)f8D|V zx|dx0(c2XiO3rcZ5S(-!$ zX-&IPn_@K&z$_MPJ&JJ-Mu({F_!3-vbh~QQm9lH%H6R2*sS13IRHw^qn1TJLWP}ou z?w8NAA-AOtlgC(aVs0*qpeGmD+BL(q6)vPpcy@g5eH_=7e7%%k{Tdl>m%*m)f^)WG zbKF(KN@goeRTiPx8p{;Kz+d$&aRr^Fr&pJFG2L3c&-=a-rNuxdfrd=jdyC?{jpf5h zilNQHY;g7m&Pq2K7PZ?!$-qC9W&&-hrx0Lr73~($0upJ(p!Vz=_N)gbdl_!b@p4+9 zb-Vha*$s>NSr^n=(YeJ+*+^yeASn=T1VQpRJ@yKH5bjl`Txp&kg}o~(X-G&;i&U*E zM*)Uj1a8uy7ttr}5Js%Iy5;0~YdK(HGrp<_F%Hvh`s)E#j0&%zFDslNlY?;n#}HiE zC)LO)m4!#T;hTye$i4D7zoDFw%9g;XFZZSEmUO6Ro`AMld3}KE`+r_$xv4UnX1hk; zA)9{>+S`IT{w|XdB%5Np2YAp`L-%>c?l+2c{1An-&`y7fPmt~$%OUgv0*hbdecRh` z$UT2EL6bZFmV+ZJcR(+z?2a&a$8V)1_~zHG5j!{%Rc$fj$@06+YR0X$q7^Tc>bB3R z)uf{_0TNAhz9b)X2jlTIE)rvkeSVQ-`68vzmfh|gEf2YWEHJYgEFi=KfxYr8>r%8m z68_98u3|GK)L=S|v)$~~6WMJ8`to0f`fSY2HZ7&N-)rQ0LZMHSVXFjgvtJ%@-o(>k znEi?%`q>W#T5~)Tx)d+v&N)88hn+{mR4LDbp2vGaeMyq2TCDOp^vK;5++f3huNrA} zoNr9MCLx|WrTucUy~EJ&!e8o4z@bYQI2BdkFX%8@$iYNu>r-nfuwViNk(}d zX48dFn>aSdkmKiXY-62=HV^45q&zw3zWU2h0SF+Wy%_XFdiqs|PN|AU73HNoYVfc= zHL+uVdiv5GQRulirZb=)ebHx-=a z=1u=x`u~%@`2PwWva+%<{WtpJq?(rP#xSDKO3kX+wZPydZCmFr5&v~_M@2Pp_zF35 zgwb|&X>&!f{Daqzcczvi@wMnr`CVkd!LG?^FD9-Q@6YG?@{55(D_-|csr<@xTT%^e zlkwgd(6*?F`bNsJgM9k1^c`vFtLqvvQdU-1i|$Nm{Zp^JW7h<^IkBs8v#P3yiPMVu zIu~Brd}%WCOwqb*RC`>F&yx=|?qn3>>dLyh3GcFFTR*N_rcsFK$sTE+?1c<)Kc>6AKjP?wM`nQmNcSzsPnH>~DApq-uzH47IAoCn6WB-o1q{QzjALVs z(oc{2v|AD;fpiqJtvO!u?AO&Kk?MX|k9IvKJTm+tjTpjJrG0LiD5a9$&p3wj2Rbv$ zW>BrRXk;LI1Q{e0?!b|iVv3E3v8$`E+zN)_gNQ?H!N~Zd8%BdcE+?I5I2!nu{%vL) zGM}f=tDmi3KDMOYUf*N(|Wnn8(7wiMCEF;#f zo$;C_xs-i@TraSJ&8tdwn-x6O?mF90!)@|tC>>O4+;b0whsa>p1&@WC!I(HYa)Ai| z0eh@>A7ncKqca6K{c6>ubZsCGqJ|@D3+!oPL$!pY1U==D^u7F;eJ(;Fj+wKnjZ-apms{?<>rb7 zW6jL$cf>vxp1wF-Ci;iA3$z4LFx!i00<=uBi~PDV7FF)E5V6MvI3m`IU#7YuRYP+O z!pTv&k>1ngYSLC9E5KHzS+TMKsXD(3Q`GmYg`+IyP)1+u+Keqox9$q7MFoTNuv=H! z0_C`y=e+>>7;D-+wl*lwtX25O3AN^O;q(Hs{%tQ6T9m6U9K%7H9%EFIp z7Fm>U4+H~=b=paqNCTUlebMb*+PS?y0<0g{4OZE=^)3f-MiG&|7^+I~5e<42p_5-52kH+f{tAvlzqbFb*~pXi*M?hU?lN>^~M z4IzYmpF^~n!;p+x9x%ZFLHw>_MYs1G^OK{tO(Hkr!$7yHuzou3Z(5gkV( z@*9Nqq||m;j#=zEQHCsnCxk#b#M_P zF*SUtF&^;#M}$4&N36R3c4=>oT_kj{dAL#`e8f}$kWB_uE>%|S&2d3J^%a2WBwEkr zb7fhy((>Fe%tvqzUVxq3t3MHTvKTWEGemI^45>@uu7uySSO;M zh&hFqZOgx$I9I9-E-iBjKY(SWy-`B+*jsmr^gYCw1N7zMVnuxS7DW$JSC#TUc;qxg zD9|&OsN$N;a{UM^vQFpdhmNG1xNyTkQT%Z%tK1m)x1Rb#%~oxSXt`sp;{Vu)dpy>x z9wia~@^&0j@=9hWuTOv6%B8Y1=*NvUt#8qspf#cc_xb8Ep`E4fw~83K6-BgYb?qe6 z)+E%RJ1eLj)-$`yjrh|wU4URSg+#DT*0(r7bt-_E82;uv7PQQp0ST7dlLE;k8~i2} z)PCZyr(Voq(ys`3>m6v_bs@B`s5PR4tz8k^dh+L&!rCcKYHhAt5Gc_*5#RvoBHnx+ z21^{P2N^e8{nq^>oHw-4D54u2wGoLR@?#pmhMyCs9rCmj;W2VxupR`NsrWuT0Nz%k z18R`mUuF?9HYa(I*__~8!PT7zo!hK%I3*8~(%u$hPp8JRuL-fk!)$b@A)>Tc9#%ND zIQ9`W0v}1+xWsqROjLC5P^{m{#=pT=H4_O3J$<{p^lX%?lg5?08>Sn3_?)^ z6?>qJCxaDAccJ3U{eFo3m`KW-t-YMj?n%HDdiFOg~`12p2PQ_&`LRsQs&jq9lWN#+ku=RAkJ zWl@h-X?~o{AIDyfBURp><^EtHy(;u*Kmbd2>&`2CZzjrxUFEFDecl)FKpO-rM0ug# zJA9IIP`cMfWOLtf_*RN{d$&U51K=6mR~p||#m(03RsuXELK+Z^2G-w2B=8T$W^SSb zcwGdll6wX6IvjmtI3TlHgUcl3U=VB$;KsZ!f_s}6!=p$;ISqaFw+dmXJyC|4!FOJT zJPM$&&{Il){2V|_w)V%bGd;UO^>X<-dYxp*M2li(CB4WH&d?NvJ_6LbOJ{6~x#l;3 zjJ~2~b3+$Y0|)ffS@oX|BK6Fw%LbYCHolj1t8|lmq$-wooqbR@Cyz6kVD?_Uzjm>! zkKvV>yZ=eCRD!)K-{dGovTJs%G2}_N4P+$OQRJmzJ-TC~4Asep@?c8pV(&qKk@PTn zl>)f;O!)hW6v9BP&iboiHYxaDW6{tWhm55%KF8ga4uQFBDA4#%qD|8tdI}rFBwIjm zlGNy{(Neeb*akr&sXGabh6h7wsDHvSbQN_yg*{#`fpcK&+T3pDt;6Tq7EwN`kwW?d zmbj?&)o%0|bHCm0rNBiMuF@rQ?k%SloT7STXJfH|VK$N+V(luXzR-;(^~Im6K7wjB zvyb+sXzH5BBHprO+3hy_tg&|D0at0*3`7RM=EkM$&$vJz5tr7L;{rW%DMZOy1z>GZ zcdErJT3n#4PAWt+4V0jDRsYh2$P3>Q)P+ONY3$Y=8;;n9Ut>BVoBDYf`_?!j^R52K z4EVyDi1CEz-A}t`8Wh{s1@3{HS%h2vDO~#IEa?-)DiQ-c^M&`Y)O^V5AmkeyV=(S8 zc)X?JK017NJ%~F}*R_VG)<&$rq*xV#eZkm}Py=W8iE>qvW;J5agxfVj`tc3huSksP?TbEW40W;rMItf z+t<`9HqilDu-C21jHkFp!b=D{Dye=p`J1t0+(q6om`GA8)w9YXosaI-%~XyI zyHL=0a@fxsS2LxXirEu15|7`a)?1fWHfJ24L2V=$2YODlElwXmO;J2eG|X+}Q8a18 zqS(tFSa|_kAa4U7$*|KR-M~`F?t3jF6Si~lN#GRKQC+P?8z&ym*3fKE-X@2TGj>Y1 z8}U{;SxEfhS^(Lo-UHzZ5N4&^E)yt5v{_XniH1idD96L%c^^llJaK~P_$E1pu?3VnALr%dFkoF1u zN#nN><5ipiGw|0=B3KxfQG}?JMwaIhkOgr~l~V+?++;A|6Q|MJ`L|=6c%Q4PSSP{i z6sV{RHTR1em+ls2W4>|#f@8i&4nsPAadn2UFBtTci2cAIP}Szs{TsDz(pYDzr5GR0 zfNU8@ zfOk1F+dQj43|e=N@A-($yizyXo`NHzlZ&^hO$$mEDfs6H%$z8k{m0rxmTYd!3>wbq ztS$FSM-a2=} zRdE-`c}^9iss*X~Y89|aKk1>zWvMHxPFir=+C9^6TMeY&McRcb;jK0lEvQYdZiy0- zfpwYEH((8kh5R^m%Wcos$)1vE%Er#h3Z&E!Ax}-%1#k2tB6f7+jmmU2G9>oGdilD%IZ8w^fr+ZzVls*@mWcB zDCANS*p0%IE)E?NJa{Q%XIPwKyvDuCBN#7EQ?n4EnPL?IQOwG?vN*Z%o3Zh6r)J^C zg23^d8>^&k@_hLh#{_RXa(;<)EbaLlmeT}ftRpYx(Q{#pI}NrB>u#ONSK6Lf9R4z8 z)3SX8ed~DCU0uavI6n0NXEG5e7@uf6CXjvj#sEKP(BWTsXA7)#1MWAAR60rhCd!%b z6vkAAfVs0FRO&eZ|u8!Kg z4x?gYYWHzp5+iPG!X4fQ=j?x;Dek(;06$ND)9LCinq@#jHld@4iS{K1;sl+>Q)yHr!9%%p}>kB3UR(W*7;} zAPm=%JwpcOfSNY`Ig%#|J0bj2JRs<93yJsgfmf zJ#16;IL8X|YnU!hp^J{pSM|@%pFzv5L!t?ebnis~hCI6upPpcj3J+9H)03$|yJ?Q> zt-dPc`6VOlN-KRT!lX(N=K@dG`#rLJA>LCe<14Bvm3@z{{Rlll00pi_%HxKl&20gb z3e92oS+~#!E#UTmcm+l&A1h$kIU_v(m`!Xo3`S*8Hf;<-@JNE{G5CyTzpM69h4e%k zB!^|5Aqod82%9~`-Uyr7IT=G@=>thn!WTi{FB*E^hX^k=Mo%14rhX`ReG!PS zkokCsQV&7fak!=sNd>ROuEn4|EIlk|tW6v2%_;jy%i7nP&7X3l66o2WDhyG}y z;BlF+TdEiU9JxYf7==DJ=`Xz8j`fRvwKC|!&hg^04-3}fS7f%p4 z#LM+Ix;Ysy(3vH#=ZF5ynjx4=bGT2p!OYD-C8r=1x03$78%VzFth%v`CCW!ZVYQ?h z+AC7{-azSjl{8@B+QTuN2#q;tJpC)S%4rLl+6iO-$fyTWhj^-_bgc}RtBt0#9ZR=J zy@yMs0VY@_ya)k~buftM`ryN|^}Cye2xC8)=Jl@)FT?A>&t2L}!F@$1WHxK>nd7D) z0`x>Q$q9oJ4LSf4rHV-d;Lt)_sxc~#p%DsB@{-lI2Luq9f^(M&E-jXpFDZV148lkP zm!HZD(09PSIRunh-ETpegr%}4GOi&^rbwlkFN!uHkVt=r(-u(`iW#^Dx^L-Nx!F-k zQJUfEOT=*RjBDC$Sjj-<7@vwy45YGQ=I`U)D98A4Z~sZvj(F+Lkc)g_u$EyQJmlWy zk_Egmk9a8^>hL2(iv$ehaJM5U&|I$eQn1UFfNwh#GLC%7B*nN(+``+wHDJ`3dSSnW zBvmcOJqOEXfpi5vO z!eq5o@u+B5w&4I>ID^-EO3fDG!~JOuSTJn4K7`R*OBsSoa|$MbV>*VBM zmQ`@nyU_&GIUG^X-L}<7_4YN;!$x!1GFTQ&^<*GUYjfF&Ss>{KY_Uw@Q4+2w-EIj( z4a*=n&wWFUOVSR;n^0z{h|kUxnV`=HO`3ZslKY`4S(R~OXvEE1wft0(NlNLV5~z(M z5-D(=TAoyp#KR%&V8ss6-IViSW-~F(Djvb__|uVCT5^@8h^o-Yv-Wv{<3sznOc%%o zWmuuel0qt;5L%V`SaIK2$d=ui_)xiUa*i8uR$-j=k{kDU&bz`e!G2vvi4w1#Bco^T zK_$^=oQL8yc(PmD^#)umMk&*xA@RdE0uYu~^dfpSdNk-Sg!f{hj9_*2q5|qu;uJlH z>K&C|9%5avm@wtb@nHtMN;;oRlX3F7xY|+o5TLeo^P$)8@kt3lY)}N*hiktB$X}V` z{5h3vhfW7d3hMS z3C1hY-81=8bqUrJorxQMfqBian+IKc6EBEPbDyj-L6~Z23EUj`%HweC` znc_oTcJ;7aniJES+vp60`#w*GyRI*rO_PEQ&O>$zLZxEjE_#du;#RgYT_r!_h}S#y z8Z2o`Zfg;reR_-S_=}T=*z=hsE>5y$GDV=u2~t%w|Xv0fg* zJg7&tGP+L(3`rAMg{p?sGoe)*r5;nuJb*DSAxcGOdrd_u zTbAO=*e$=(JEl9G(6JpIl>^XLat>wV2MTi>{No1;El3Ku#Z@TEDm%?)Ae$Stx5N7> zbynYwXow_>`N!lIehL#J=G(<_&+T!{I$0nemr)q0@RcIGN;jm5BR;9omTqc!@(_pZ zxia^~CW*R(;RGy0tOOTC2iqo61NpQRFvfH~I!P1Ae+zLPPfB6`HR(2+Iv({%U#ZPb zR!QK6^y0C#1eCYW*&x7&B+PY@jc0cc4LIEo_kJfODCgI92~j^1GCT9(@(2wLQLg@^ z%D=Ny(7>^d51-D$hHa!2_iNXozhL|o0Bu%Y2LjIMcjFfaf{+1 z#d-3Iaf{M?1;r$NM08*b{`+QJK;>9~#9l)`NJhVSH)weQPZtY)jF6Mt?WB(bivHc%-?cZ6m|8e{NzmsGCtN0Ql(|?QCI@PRy;#`Pd)xY~< zCI+t3YbHqKkJGii?p-r>h z_tu8gBQmB=hm4$_$02D*R|=ZLs^o7AQg$(~3Q+qlhAE7P4s8m}-u6riF>~D*()KbK zWTkmyw$*H}jjODY%6&+p0#4LJiYsW1Vd^RGWG!}9%Tt;F&lTT`tKQE<`%#si1T|M) z&-pBq>trs%+=+a1J{T=zkg8CdREy1{APpR%-<|2rB%+F6Y18gymvIZ96bG`;k;Yw; zW}}#K2b(??iJwm(@GiGNIzIsE@PaLN<#U2n_Z2(8b;91nBZAT0u`+gv*h?%Ekz5OM zv5Y5P91d|Vi32Pe0YY&6IrRQO{6Re37!h@@_rVso{ALA0*^Qja_sVC@qz9=shB z2j)XH)qZw^vWFhNaxq`AL|9Id*}-nf_+4{`=E#gLUy-?3z|JArtv6v z+;(B7h|78a^XygPdPloz(;@L}T-G;Z#A?*77sz|~%elhlg$#YGNA(M`g?9C)6lizb z89A1AATs;k1CrM3A&;-en=cP4pVz(1`=blTJl~JIp|^=ZPK0zb@XSZVUkRA!!chFM z$KMx0(K=&4ti#{~32;ztf926DG1`F#&FL!;VN`I?h5h8> zdXXv^Zg^tDv@8nx0OZb;Vh608lXy$4zwDh`-tu=aCdgzhr zYp>w&n@LvCBc}D-TmFQEF6|zY3urUM1)<&4uK)+DLNGI>%7>E?)3R~d(0_x}=5wgu za$78}$|pxyhM~|HOq0xKq7NbQFxvkWFbK4$I0hzfBa){~1GCPfNxHw0X8*S8ze>B8 zL8Q&rQ~9f14igywJ<(_N&^nu7P6NoS`hxf?AA*I!S;!4@kUoCMWePZMyidK^E>w(E zH%VvE8-Of~9dYkAP)Wv`FqTd~hSoEA17v|unVq^V&>718k4C}^?db)Lc~^>~km7fFpdM{n=msN>5Y+&tfmAQ0KQIp1$^1>_t$Yc^o2{ic~PARB@JmfRFk( zb^q%kh$Rn}5wJx89K>g8dgLGsbW?a(@lH*G6FEOnsV5NLYg&FpWZ7+=INIEWx?>sB zPvMYXe~Z;d+Y8??r8<}3@$LJ|nmk}}DZR+t%s#1kpRL}CU%^XKU9E^IeqpGWc-be- zYex?6rt?>c7_#_(qqL6c50({9mYofrM_a+F8-zxu?F4YOu)BC-Uq_YTCP{+hB6H3N zMw;gpfv7R>e#`zOoRfMIA~Q&u0)O-M!< z3?r5RjcFvPH!xLeh?yX#Sn0^Aiw?E!gDbovQ!k-u({Ddsw>>jUN z$3hJc1ja&vv|QLo`U1aKjPNX9F{T3zDaEcuzz5e*G4h6!v~=;`|3MJ z+&YWSL5s7%?$;mPgjpHl0@n?l2W5)G60QF^-)~uAMp-}qc%po}(JWqr18`QvTO2V7 zLtIhC8&rAo+QmFrF7f!}H@P@ZU{2+SlGsgu%21MKUyg9S+icLU>HjQx8_zbFtIO7w zr?(5Q!?@(UZs|&1*H!Z#qy@oiu=eJSJG96m9!E5KMJeuu8`~Mlan{={CjnEx6yb!T zt{EYcxLvV^T@Jxey)V|(Uv)tJVS=T@KI~^?3))210~SB`wzvYwR5m0di?e(Gvfh6? z_)QPZALb}Ah1B>zdJ=t)kZajc}6 zYPim#BNm;X0w5j*KMcSY(X{cse*Z^ZT2WTmEyJ1?jAfIigS6+CFwMIB(K$WKQGFOh zh*CzBon8NFtFU$#L9s0NwV~k?&xK>R|;fU|sC#mh@4O_Qx? zrrv=i!$2P!<~zUE@`S=}I1E%3kX1{TvOP?1$#)9ZXvydEAeO|Cgm%=Xx0 zNTe;Td6^5vP@A2ae}<2=!V?Y4?>w}Hb1Y*y6c<)a4c&l4zjz-DXxU95M2HO5#Xev= z*cF5W%-kvzEWF6D=pQG&$Z+T%*Pm&0%BF|;HTeLMB;7+OyCLDG0jPaaE;Pk3M4h?Z`fIWJ1< z;L;@K*HmcWXpkQJ{S&x@@V~pPdgf|8$cHt(Fjs(}O;gOTsS-ga-Ic$nc$amuQqFo4 zp}^hAk-FzoKRB{4 z2%JD)W$I2c=(LN}sk7YxO;?T|*8tV4fF8qm9KoghieEJ9#b9;Pr4{%Fd?jL16D{vL zIJ)YwZumi(OROg-vD8Ik3?s}W2@)n>nL|X*DR|I=A@K<6Ct9gXJ&@WX+pf(rZKq{> zli@5At4&&?^_VfdSK8jhqn21!FCvHp;xcMkEni^WW7DE|_$w*3;iryW?+ z#k}6FS%dVuIK^7c=u+++A=hr(T4QtCzI+g8nChdOQ`Vcq$Z2c3p!=_J`}+;PH#bH- zSrX5O^V8?;84{$6jch&L9}X%d+7$VZTS}PA5Z=pEKMgdjX(2*>2}elzD#CL`@n%>? z0uG~tN&0wodI*XHfU1{B;N9Q#radP>EFlU6DIpQ==SCKH{z^ynuC@@Jg;lyY=r{`z zT`ZAMfJhYdG`~N728wmr!HeifuR?nRC|w6;VJZlro9bmJ?`rT=mf)2vsEyGy!D|J} z$oqQR;eg+Z2gS@XRDAy3gvce@#6NjGXNv{X6Xe~AAGWsk-H(DkM>IyP!CUn@l5VkR zXwA4;hW8yH>+;DrLmY@=>h?`%^GT=`H5fjJtDhNN&fXqi2^5oEZQJiV2aT}U0Yn}9 zWq_1asz0-pr$;+D5?J`7sxQ!!|DGU^1-@?)YNLpL2skWGk!1L@ zuA}yf@=HosxGk2kkkUM|$r*x`PSq&1wyf*+HH9BtDKE@$bNiElzYivaz5h+$4-Omyve zOP$GNfLU>am?acY_MfllWhbR^unL<%s^S9~rVPSuMpoZxXZGvEXa?V{v2CsgnNL#K z#2MEvXd4JTq!v2!`r>LeczpzHiQ!m7gF6iu3?8J?qRo}&G=h1Uua@!HO5Zb`H=@~O zY`oFx@)+A8SqZc92M0}l<>0InNEX^1Z2_`n8_62c8E{6GNL$5mLcbLnE!MZmh7{Xv z0ixK1I;XoV;mie2q_Md>*O)438h!hLck@i?n_~ZS$T)DNjYF?fTS4!+^)B}1Qt~`$ zF7ah%7A}TSBmxACWLkKE{E(y@GgL54q6$l72o2860x68&h15!W9xt0*sZjR~A5f3Z zu$F>QhQpWKq4=A&SOfBKTC(X9`$^+)4>wh4>#04fY&iK6uA#;nvBpZ`jDknfoNcm& zE32+-{4`M&DYfU?pq#IEtIfYdU5n0Y9l;ECI;0Gb)JA?2twMcS=|2l zAZ|bJeB*~S^_Yc3o<9ISvC*jiP6+*pT=Ng+`_CxxO#d_fJJbKF6*AMmtdRd~nEX$f z#PKhg^k-)OnCl+_`L}2+te=6{{|W$4&p^xa89kexwgMM&P31ge~keDXOjOI z`F~v+{-5^G%#0lWNg94`(5$c{zMp??&}`?bN=VL*8r1No+ql*>X~RWL(XI6hTxr#- z5N8vT-F0@l=UX+Ovw{Of?Akqk!k>NLI?=POSmyn;PHS4VK{is_Z<^e1QV9JzC6+ZX zpQ5_AK2X9CrpY}9P4lqwJuHuWa7WEUZ-P`j|R%9UjZY?Yy7U5|}TC8<~gbZkgZk?y@5`%)UpA_LVlX(EiF8 zp4-OBvULm*-v{qUgWk)}@|$q7o|B~UOG2MW|HxOI7DHXP#U6PW0VlNW4f=jD1k)U01Fb0LG%{#|$ zq&HCLcc*nbJd46BW2m>C1rpqiBF>A6mE>`S<~CJ}c3_t?EXhI#NI4BkOu#abYe-5LI@gxV>#`%+HnDG^)Pc&YYx| zow$y?zTT|3s$~#ii=nMTLQ6gRH_=Fq!I6eVY*X{W!|o6ZOri~>tFfu9S+;o`C(zP- z5d-UUF3B?+~8-Rha+G*5;!BvQ?r9NyETSA|K=LDfrk@_RGG!BI#s-<;%1{tv2zrT_}3*GwJOLkJ$@T60$)K0a2 zS1C1LnFv{9bwz>u5LN5*xEfs_)9DS(UV=hyavOK^2Wl*n1s$W zo2^t{5m^7xz3X6t-6>IjG%NeV^E$8yIgZggi%uF@|0l*`=cw>yCrBMhp4RRPWY&*rUO6cPlmYc1hX!7k7c>)-I;=UwB@!d$OsB zU2nb2YQfz$OCd|#*fwszq7oyF)Mc%OOm&MoQ2cmdlSyLl;~HFGc9xsWS>_Xh6vsMWVh-AV=o;l1U`us}?YWm!$7V-JOEf z&sM=qG7YfiD8}UC&WwF7a#%ls>6r~&WdQT&bD`2GM?HU~c|-h0-pHRp({XfCovccR zsdC8ng;$%C%rd4BXLY9D0_CR>71Z@+&w-~uElxVL%3=Hi_xf3j&*_JoNapeYxEk|= zX#Pne`RVc`hRp+yFT}2U=;OqO6SAZxtZm7Cvem&Zsn~>_jPgPm=8qWi^}!c`gdKVwyzv0T(6Exz%_t1OBSVk{_s?!~Sew zS`61~^--gWxD!mi^O$R=MXRTnxRAh>(=nkeTbp|N^P+m+YYl4Qs5HziKolKKXP3Hr zV!-7zlou`_f}e?&8_Q}kInM&5RfkRx(`-6i?O>?y>>owbQ_RO<*V9sQ4`5-`eF(zn zSEtS2LW1>TUQ6LFlK{84bS;h!P%FSzyTX_dM;5hO9*d8oiN88E^y50j#suD@pP4%>${zH93tnI+J|5Xq*QWb ztVj%of#;F89@AG6+(RlXK>^&H{o*w((rtnwb1smyB?_v>HnXKDTfQ4bc`#xbGC^p` zc~xtq;F21Uesp{TE|(f`otzhU(D~*vkU_2|$mm>3KZHc=4jgf^B+A~Q$u@3#V)>1N zIW{ATxYOqXd9vaAUNO*8Vaznt3RtBMDMwcFmimwOT_-pNn*>GkFVW?3!m6g)UnQM* zmm%Rqj&q>oV)$dnx*iYE)Gc_NK%UGCN4-vUO-*^zIDY;jsm5Z~t&f(}pkOeOv_RxL zs?AYdv@h$L)3?D9@$YZdbo9{>dhqj6QN!FR?Y*|n55XynMntb(J)DLMCV#DOGm;pA zlO$V&U$e}foQX$;5rau9iIi=vEvJ?O86MGoaI;GLEqf^Q#c#n<6icFjd# z)E)w@Bug&HU4nD97)NwG;YWB{@t_3`=K;ra93KxPQ?`;`BaeWhFGR=&+$*AF+XXzO zd?P0^SBdfzh)e}XQ89RRM@y|C<4?|4cj>dnoNOFag;$}-t94p z3fcCPzhqCkMs1U}%m7Fa+DdN|>Z{LgKx08@O>cGB7*|Jb{e>T1TT@dS#l^~bx&f~a{9)&vT9tLz()HR_yFSZYMK z!wAWL;yX~8S!InE`hb*E+EzWSZhdke>c)*y%BqkyNjS|av>a_PPDj$X7O%ygsM6a6 zG>_LL+dc0toP^2o2g7vJXU^vassA3m(8MVPtR7%<&nY0#7RifZ z&}(b|#Ir+LhYNBF?cU!T;!prLYxYve1ECFIX3itUY(z?Bshg%Z@)9Eci+EG)`5~uRF#@4B^>EoyT`C-P2F{ z5Lu1LpgoK!q33^@AzdB*g^VlQSt9~ExjqMEyxghsOx5wzz8#w?sZQFhieKUTJ7($- zS~UVv;kQCuC>d3pq&voe0WHXEdP%u;G4t-95tnVr>cPZToc`EZfSL8!OH1LWfJ}tB zepots4!ze*Mr<2ZN&}d5BT>r}e5cqH`AAsH=q{t_-8#caKznzaxlcXXkRA2o*~ zoCb0A65dT8vSUZ=K1-sFrD!4aq^gdyPQ(^q1XLO1rw^|=(7o91<+lLVayX(RO<|1G zOUK`t@^J6t@1l%N_G%_^)rLN6(G-9H;G$yhcBz8cR}abbWw@g`sf2e z4<>6Q3kTeXtG3qO-AFzU8>4R8=H1A`x2!3GYiJ+feIg)nPd@A=ZFulAa*Ik}t(&*d z{3|gt2EayyINLVl4cHfP3tPAFARi4KDwFW2b+RxB?W1|w))}?B+Z?_~gFBF*dh06^%1rwiti`WSqgT%O2;9DDag7$)r1BEN5{b*N_&Q`syzm# z(mjN{co_N)8_?lys9d#W^+dk0-S=U(x%}4Sfb-e}NYK7E;LE7nY?cWl)ErKU<_muqYg4z+&&#u2RS=og-@gKLsKnmf zN;9Bkx@9dkjNJFoNRT9NbRkcQvNO4^5slrw8G2WYpgRL^Z-FZ{*VN(OeYKn=_F>j< zo4pX*Cc3oT<;WbkIjes~$7*y4rhao#R-KPdU%2tH3RWA*3tNi_)W@qQ7US55RK(9VujTza5e%8`>4fzvnf%#oL0V2N1r z&GIwacv#;BnW&ZAg_kjf)<|B0+Z*|jxx}cnSH3fiXKO52s{CqM%$ zRA?0@kOZA9Q-b{?hy%0h8&w~Gd&s5&&7^*mj<7CQC(;WGT0EPI#7Yt(&q6wpi1QAi zCrD(6!7zRt2%-ZK&1t+*P+Bcn2S{qO`*;%-m(e8-HPdzc!yX;S|AgR|C>;~#O+BhmS_wGHEO1m8jxTAm@Bx$!gO3nXQrb{37XMhIjd zyQTHjXXKCSroolM0w|$U2=xQ`4I>XVna+HbJ2ZP&aFW3+b^PUOs%1ci@vzciq^TLS z%O^MZtK&_{&bboJN1@3w!_mm?yxLhxm9iaxO95HVdIp2n<)NVl;W$^wj;w-)L2c%B z(t**DD)-pV99!#IX@m7}y8xoXCQ}yp?Md6GALEhy07|Q}n>iFKX(7h&MR*9m{PeoI zRY2t_``RQI1I1CL_3YbHA{CJawOIdxi{&B2D~#yA{&Pl`%~?Ch?|ved*zvXT%j<9h z_7GjhRZSd*{vzELtpsTLeMSGd^Ko6_DaTf z#+fq4*$>{l)Llg=_KljhFPkK4pye$~k~J>5Y+jS7FF+MJKobrz+UenIp%BiHVTgNwetl;d_S5TciQf5$%O2b zx<4?x`xE68%yBaO3$K4XIExx;B$q;C(%tw>{$#IN7g~^sI~e5mHbGJ^M}t%sJR?U_ zI~|c@?GLoQ*8I&dI!k*hv>cyy=!!-yh^su^*2EJcinTdlT}^_89;XyjCR$;b$zlF; zwP3t%)w$}sShG0G;b;3C)M1^-P;xiv7J1{Ei3qvo`X>~SOLWNs}GhlT)8{CjUggG4m;And)-7`J@wy`uz2=fXWles0OzFZU&k z3I&zlRL~k@7uWK89fL15V%P&|?W6EYS0lZU9iW(d!@2R%b`$u_=ZIGI5xw*FAL>2H zTh6K#iZ3lJ-CFWj%ajSWX9ARc$;46SoEO+Je`)iH(>l@Uqz}_Y@&RQC%YosR$g4G% z+o0PfGRATA)O1lx(r9k!Y{)P;TS;>>CZ%TO++PjM`zCS(sc zU{>{T0n8vlmqEReR!=!zQIIe)>9})m9}(W?NnsR+}NB?>~1QOP_ z%Lb27nv4{Am0nw~pzu{u$$|T0T^K3b2;mu=3kqR{qX_<`u4~+Tc=gF^^INv_V`3i5Ep4LMogu?v)i3_2S_GH9*L3(W#A(I|NQ)9cb@@@_)j zK6q$g3}j9;ZddN@ih0)GO>>OKh0FiG@Fdy2%iM(ljGBGnY!C@rrzFe!rI@0IF=;sJ zoj$NKQTIWyI1IHMaYe6~G#}3d9Ah`XK)sE;uFlnxXdEH2!bfE-OjikqBR;E@QmB0lUTI0IOn=$h%M5b3BRjWD0pa`Ee|1jQBv1^3IfAR=`}G0N0Ze zFB;3J?KkOlAdrq$QX4uJS#O&qx9eFLgRhxJ)p7!3AVAr8%Z2mAS^jGTL@gpcb&K5m zB49KdgDg$^md^~8Qp^u8P)@9UqezW~)u)KZJLD3YYqGmBDRJm@xeOf2|_loRgDw2eE6c{QJ&6gN?@);@_ym%*+OIx|fE<7#qcE2eum5JVD z-~ln_a$T`2>mBY8Y)mL%%_KExb$<7vs>4-+^Q}>kbw6P!V#jrmpe*|a>s)}^9>Xz> zI4m}uF50p}^Bu4WsimMz=q0y_XHs5nPsLOy9a_zuz-Uo|t{%=%E~*y=!mcE2rZ4i^ zX?k`!OIWbx0aqQrchgS!g5O_G0ou()t1?*XhRE+2{rfl96Bs+lq=yCmj1v=Cg6CZ6 z21o?G4I_RQ6P?q|yB_WWvZ5epX-6NxsT6DcB(iZ`jpC)DErPj>gQ9P`kmPw5SYw1` z-4abto*eZEc3R!GKVx7}0HJs-^ONwj>b3{R6M=(B&b% zozhz1r)a^75RBcPn>Cs;GAOyh6WVTCR(eoN@)_$}gM)32e&;me6z%52uh5E?3pO;* zk%pv!X+SOft!}$63&>Quw3?rq7U6d*cXLZ3C>ScH5Dy0wyywwUUC=m9QM94}c~~#_ zdea!d6I8nWboVM_Lf1<7V5?B}i=!@AOILr6k>HDXCPw9g;wq}(!A|dBL557A1mQ`8 zt`%tHL<6Wj9Ar*Yy|r@NJoNHj^@+_DQzD2%7~#HN(C=7O5;xpfRB>8}_+iWpzh*R& zu%!B$2eo(;#PN^biV%6z<1TqK;_L|2c@Xi_2Z30>16y_rA)(By(WkcXopSxZ8Ur)ov$OuO5&8cOzxrpT z|7LE%%=(|=>sTd>$`Ucai#)uCYc5C7YWsL{1qcX^fVBxxi%NqF$Pgk}Y~B>T9{T^v z5x>f}X|};>rK`LEcOkpV4~@u11s_QOPX#uA|0zK{#(}gLN?`%Dr}F8&y#f)Hmgj#> z{<&F^ozoWK>0TzCtR(_g_X->|;wH^VeljVctkgp;!IOx^fN%{6D~^n+X^9 zL&Y6I%>=o%eSa86PM4pEtj!V9YV%#7*H)nVOE)i%NocfpPuXR(vx~;WM-Qu!9k$-E z*_M0u%B!^AJg>p#qYjzy1_C25QO$gf6MQLqeHavm4p*5mt0m!mzg;2u!4n!?b2K+L z3dilWQF(6hm~qQ#%{vcO4?dh_Ey{81#9;2m-JPy|&19Wy6y42^DAl5VQ%tz**X^nP z45T*e{)9ucRZ!X=lCCHR0~KNkNb3i0t4N-yx({nv?Rf89^M95(J)77z zB!O-;3ZySe8JX&M!f+Gm6(k`_f&Yv_orjc?xdK$_{>HsDM?jODgxA8xj84tMM!?3=;=is14IEAWwD@;m77GVQCn0kK z2Ye<*I%$J{mKm5o0a~05oqj{6{3gxt2iE0Z5HR?E5MmTR$1rv>chvesX#PY~VZ#3e zSH@?d|3_l~yk=wj#MSA$FcuJjYY`ya#n zo+`(0QlB0EEa!K}e|G+?)A?^4?O(QJ|MWRvU}IzZnvvkCrP^u0o;8<26Quis+ zl^=)s?Pf0+NT0znEAcU)Bl9fq{$a_NF>V~_72yWN)VkhPq*TWqr^~v20w;*EZ$O}+ z!qFhNmQp~>EO1*z?%*@5eL}jJxPsN?VDvkwq$5atBnVIakGGJ?O^?=m`KM{k4cy)LJ3So+IQfveb3+xe0OsHcm{dhEp675 zv-vPDgsbb{**n?3`GnbPerwU@kvSmNk-OL*$0(;uJ^{nQin}!(6`3=e9KPNPnS6Vv z*P>IS>(o~`s#1v|Fc!tP+rdD^=rN-9w%oT;d1Y7_HG6(-bMvbj2Od_da$TsqYqQAQ zsgh&v$m7k^SMy*d&Sn|!UAujM0TV*%R?nnqb$hXRdNpG4e07zM*EQbsc%|EYXDjRK-VTR zul-B@h@fGHL#*2xIb2vu1SBPwE;6N{p=lDnMsjT)O&W2Ar+N{w0oI6m3H(P1?l`Wl z%^|*(CwV9xTc@t?Bwl0`$qNxD9>c2hHzH1oFFIGDzs3aAIP++%CX-?gv2mP|h&UC7 zpLa)3EgEps&UZ>Zv*liP5^mC!ExiX{UeDvSYOLZfs3uXDDj>V>9 z=CUL;rM_yu9g5x|9la=?y&x8xorW-$W^3@xjXe`{Q@A|aD|g0rAboh>W#4)EJD!bZGi+9)EdMxhENtCK=3YY{4y9{i<)|Odt)ocla)ReP4)%Q-}KrT5m_w(MBqTb2AQ1v@ZFIjIZAf%yu$9QMm_gQ<%33r4eSrp zXA9G-JhSeN`Le5>)T{qpU*y6uK1IRGamkbYRQ-A9zzb%B-1Olw$6V5rxgIT6=bMHL za-f{G!b^8S6q^V{W0e|{&+Njy1eF>&&F>$E%pXY+jpyg+LR8GzQ3%akkLS1)YE(da z4dnJD%M6JbRlK_liD(b4MD}QwHy+g{$RxQnHqa(Pqmd36SEG^7CiOXE6AG_l@o9Pz zKrmSifiA}M3Y`qr-{IEVR!p!l%He?1XVb=Qy~BwD{l|lP$K1ePdb{T9O=qy`RAZny zS(RX!dpEuCnFUQ(K0RKrgm03^`;+< zzO0R&tc|X$jgGF3wytqO#3Zcs5C7UUCgF7Nci+1CJYs(tZE)5ObjJ8ED{>GCtEEyYPRPu-!J;Y|w8gZ{6XE;tKrmITCPyia7#1=?cgc+hBm& zMIpD7ofrARb*)QxBTQccr;o>x@a~Amo05|qO8XU2g0eV0SjZ?3RV9tr5Bg5u;+xz% z3kBCxlz-q;zAs-dU`)j$Upx>8ckKR%?2w<{_m+)n(^FKsSTJ6CiI;Ax8g6;eI{rnJ z++qkT;DK{Pc|9ur=?y=&-)Tpf7cMH$%Tb>6T0Di;^} zm<~>PiLry7kPx=jrId@E>kfc42Fw_>a0z`ff9RASX?H?Fmv;aPWj{7_x{3>Zsy7bE zK7}AGSY2^ocR4;1SX~c$K!&7HT93YsjmYO30E4=%=DPJ+9qCiK4nb!Ub#Z|AqYF@7 zh3=cZ3>Ya%L6ZtjJ9Ba_VKCL<9L_of&pEHob}ADBPzsxCs{^yHE7+}}I^Q+PI8zEFF1wR~B1@pB(uYVf;wv*WkLh7Ij} z$-i8`{xo5wDm@M;rO6XHy>f~cN8m6FQ@5=%T6wupVJ#tA1Ge$(YWTA1>c?>bID<=n z@ktN}&29}~J=~M85`C~4W~2b-6}N>$T&Q@lVO0#Gze8G zdjN{xc>WsF6Rp~wzCQoGRnC`}ch&pt{n3tLr7DEM$?fIrYNIoo_x zy|qQH(yo_qT(@WKg=(IV`!g&?5zvqd;PVxGwMX;)J1Hwh{Yqf(50}vizC%nfrZpg( z#?oO@bG{0lc2phJlZQFyGKmS{$eqTUn|Z$UGmMjzpRhX7(MekK3q~Y#{A4E^FI=bU z<0eEgY>Om{!qMu4^Pz|eL=B;+43Ff0^I?Dd$LG;4O)r#pWwgbLAGuhVTL-XRr~J5` zb_EO1kS0%NibEbb&g^jSTB2oDIh0dK%D7rPIn+Bm8hSfQCWWm*>kt#8?RCscwAbwlzLG7eTn|A4hp5+)^!^09J3up~?prwYaf z8)2?uA?1#z=(eY*acOPv2qxu;vI#^IiE?tu2qL9aF||?>HYJDhwea5Ku5R=zJNU!~ zZqSR>qzzm&TuSQG5*l3dD{;7!9!N|~#pEO5;s;ChzS|uJfrx3~-TmexXQYZ7#};c> z8%#N{G@btknm&M^OnS-RvDn|>ZvVz&IsSH^4=kvtJl;arW7#p-5I_Z%CRi76y~r7h&ragn>3Hl9o1W;oI3)0?et9r|snq!+@g zZYzr$uOk7Ch~51w2=mx|C=8F7hxlT~faWGgjLfFNh3N4uxkh$VwtQ=9r=5!vj7KUTeQSpCZN5=XwXEoBG^Q=dshK>lR&maR~I)S_o~Rt zO^G3QBUL0|2Ifez>G~)Og$ATN>8!Xe?mBy{nS)bo;qOz3Vt`}dTxtCQ-CSUUwTwU} zNs;^-Q=ZxKsy{Z7Mh1|e$jx571(zs@TX4LbpUm8$OeHA9MXrAOWIq(f3tRU%Ui-@7QEJP;^&~*5tpsCrj`Fyak1Y1svBY+ z9Yco~e06d>GkUPG-uVGL4UzGHuQ6b6rMIK!^Y(nULih3dw1KDh@%*sYyOAnLXlqP! zeH>RXG(~t2=Q|o#3EBs7>lw?wW7!^5GPF!IK`2$lIU^Q*qv$sbvFmAPwpg6hLwRmx zpD%f$L3lBJ0WsZS+9~(Rs@tcnJ&Kyvx0C(H(+YSpL{8${S0H9RtE0a?L@M1opL5hU z@v!ak+$8INiZ4$88{Aum=nbwA-=XfW105c_n6+XN8GO069M3=f*!_LrJie2ar`Sbt z)QeSegxr>DeIfxA_>qvsUI@^AP#=?MH*Tc02c2YvuMzXT6)XVVLuiv#Bc4AO4XqQU zM5VBlc|J?ga@cVBdjOm`ofi6z45WMR)?S^rY#&vPhKTx1VRyO1X=X;R-O4SwJ=ma7 zVO^N3KHQ?|K!qY5KIH5l4bg4N!nTC3wyH3PuR4C4nbEuPU>o|p1@bpe?02vEs=MnI zd75)9zF!}=s@&h^bG(5Tc#0Jv9$xdce^)8*?%Trfy|U0{WBqagy2G92#(Cn)mW5Sh z-CwUDG%>PSr@X#gX!EfL&-|Q;mDfn&Qm=9n1Jv4EMh_Iv76Dhea){oJ>B!j;%hyfrU*zH`V^J74|oc1m@Lvy4bZunROmT5h+hn zcz66($*!<5I)%a!I!7F(sKi)g4YAF;c0w#)BXL(lp2Y0Ng~ZrKqq3hhOVRX|HigQS zne0ypQHi-rpMK1pH%N#I11pK)Y!-{VgRFWYRT^iYhP~PDDa?Y;xLfQRS7s9PZ_UIb z+fXP-IT=Z{MPN(F%|D|h92uqhFsS5ZPZg0Z97A|T*5h&@NwabTG&qSVQX?KAQzM=s zQ@;jFf;#>v(U0clO4Sl2;7a8=neSd5Q|l^+9>*Drqed(kLe0+o1s|MPT-FI{O7tag zDFcHd&K)8O(X5I9mpy-Te6rjsTA)$9%L)Z4)N+1OY$0%)A^$7ww zR8x8=VskJ@0SV^7W<-zpZte8I?p1OlpnY>au)5CNN9eEi^rkxU&oP@+h+o3>w;7xC z4Lg87QGIG#7nnq_00dC+lfs+wo)x#CQ0Upr73#HDKOjBBUIax}Z#M--MHHk_=*ylU zQ@L0d%hZbWF6U-oT-3W=Jbj<-o*(aDFE95`ihO-}KAz5;ZZPg1hE5jH=)b5Jc2y4A zvkkwwy6@Z{u#k%htiwSzgEjd`+QHgo0o94Pu%_sYmkrd)bVUbv^9}KUoMh<3*rfwE z0xS%lE|)5>Ld<#~Q@;pQR_6YC3X$@2hs9>CbgaBYa-SMX2f@4myLgQpRLr2hLqkqC{18-ucfyBIvo?xg7@RnF};rbTlPwZ2*vB_J}m8rfj0BL z43K7YK<#H`-7k&Ao(WDf1xUV=)$TpMO|+J zT2waBFE+4Z`M7Lb1fIF>yA44d~*-9I~-Mc zyoW|$^CP7uvL?DFN?~v@rLq&>d58K(ik8sy=p2yX^>sWiPV0r*ZLEB75Yz>(W-vZR zzz@8<8~!QuC-8A1cidq|F2Nc8DS2U!pkMi@%*Y65`8)SM7Hi~>H#1!qk6%8&!2uLU zuP0BetkXRd$DwxE^DB{bpclO`k$f9O{dJi2C%$B}ayXMxO-aPcb(3Zfmkf7oRMlXtMBrP~B$(00Y2LiO&8Vm;3Fp^>2z111szQ zXD&zo$>ly_*#GaZo*C*>;o84nJwLjaYl%nUA+4X`#dC9)8VM2;t%USjkA$u#JFATG zCS(uJGclfHe;!CC7vvKy$(GUV&6biJ^WG9CV;(3w+|~T(xk^_&x@sjQypBVXxKcp; zUS%qi)Hj%H8L^Sv)OV4!=$yXWH@@(KIozR39#&}6B)-m+KH2Nlu4ezJz)G!S*;>S}Ew{b4f6>uqW{h~IuP z3p{gUIbd$H$r*$FD2+BtBQ^r7Tk5ksRDCQ{>S9oPP$yXh(en}SEs428lk z+>#41j)udm3hZhZIW>xoRfhaL0!!W+b(=VihicbskY5~RrLc*6+ei~R?)$~hijLKx zUqe?Jxek-p7+-$v=OoOgHknv_4yb9kojiwuh(YYUSl+a^FE!pj+mn+o>R*G>i0xYr z(oalk)7+}G|CA%!9kf}l)XPnL3>&W?%c8cByNx85#xXxPbDD6BbWn!y($~#OCQSl4 zrC+5KmeH}>MqjHOI0@*1BA3=YRXW${7F_BcJRWH5Ql|RV&>nvrSU)OOM-J#ot?GO| z+HmBkvDH=90=MqL^?~o>vKQH-`wTLo&-LKr_5I}}WN$Upgbk0mW~>E8IEXSA9P&0h4Yx?yCEeG#jA0Kc^?V$7eSot51~;u zI6OXY_vf}S>q(tk)H#8BjCGbdcI-meX;V*bId zrIQLB?AcF^bq~Xrp6=oK%5(am+1nN}ms9Cwwk-5BC^5624$dJ{$}}6B!&e~kD;{|- zJ)AmmDGjko(uGuBA{X#z+1-U%*-JmLSnr6~P19}WMmwsb^Yaff2ON$Wqfl+%z~-9# zX+n)p%F9t_W5n-0&M~5t@@__X#A$!xYaT#P)wE9PLWM&uL`ag+4DBB=R0anph1P^JfaRl6rfbM0e4<+%hV)6hIRN%k}){)*K_9{B{zd-RD)_Q}NYxGTkl z<7p{(4IEjq7t-~y)l^u`rvtap6Q9bA&5MYeoE%lV8(A#Uqq0heFnyu>wP)^DJ-OSiCGhho!ueRLjY~0yb`reB~qnFMJ@7*sW3e zk+1NmvnPL$w4le;y9F1*=^5v1jt;X^eiHs7mT6WO6Z8!R>fq{Zg0#CB-C$B5zP;TA z{q*t&U9aQY%)_9Vn(jbKO~GtdlHX$9sNn!%cWJH)Z5iXVCDn{L7!#AtjCWMiViyl~ z{0aA~9eSC4Xw{8}4&A(rp^n!)&Y(g9sH^uq;KHo4nBKyb^Nnsy>Yc8JT*94`R#p8S zKGsJKlh|TewHiTH6RGMV$q>W~!s&Fp(S`<>9i};3&W4{0@Nxxp9yoYF@qBR|n3r)R z%Fe2ce^Y=wWB^4|PSXG-y_$Xn{*Qo9U5hHULcirW-iR-!3i8EGjbdFRoLxC*uzIw5 zG?wX<@lb{~{D+T*S<zLiXM_Kl zUB(-^{@2Ctzr|``2^=Kwvb@uWjsk=OA_J3y@k9HeUsMW#22y6vs(_xNSm<{R|+(|99@V|JVi)u{Ja@Ha0Q-RQXN*wVx^;Hug^k-HuK{Jy>%-t2|eYkUakFKI;~l z?WoK%T#q+=DdqAqB6pMKl8c3n*zH&$4TpGEDC}@TR1WN4+&5!T8*NYhwb62>I}s5I zcDjWs1BJslE9&mG%k(vknksNNoD^&)KTJ(ph_qG;(^S**C`zxrIMb1-*cWHDe!45M zND!eoh9O}ms^&*N+@VnzQrskZtky@EN^s$ zINS5WX0k*3I>%rmW9q%1u#q@>GIQ1P)_h~B>&{%NAY za_|6^EK^$hU9}7dp8Y*>mV}*vxb($&8acvHg}F866iZ9vS6mDi%ZgPc+J}J!F!)$P zE6kd?zd+Z3%2U+bct4L`rW%^bKu6$K6ORmQ`crLXgX<{V%#CYBDz7$^-A(UO&=&zQ zaay$q_c$MusC9ND_gWnmHfWoY?u3Y11C#uDtvIkTULAjM76+BNiUO?A=kgMPkF{tq zrl*0vbL;Q43D?mkf)XrxHWz3nisj%%AX!~sU`ys{RJ-R-SjZA}`O>3o7h6iPs_Q@( zZTcg?8jQ({?-_T7G&?z8r2w3V&&xc_I2!mM^J3|I%crZ%`U@#ksZ`|>IGf2ZX%jB$ z&J26gES9?n>~R{8J09tjOm*bwXo{kw+YR&~g6^^uLRzpAN_oqsBN(gd!7u&hu$%8> z(bv}e+Ww#Rz6CmpVp}^t@hAw0iYP)5G(=A(Gt)EE-I4H+@FqM$l&9z9OeO>n z4!=)OL|z_6Ma1Lriijd2h=_^`BFalqK%zVZdCNmYKvDj$s;8OVRn>UC_pZCvU29zH ztV8d7z5DCEckS9$T~)I`^GM6SKV;wTpZ`kDmERrM_t2Y#W9!}j_QSJuZDZj4jNFz( zr!J{mc*)9sHCHD;(s}ZNQE#U8YIM^*XO6BK_1>1FKUN>j&MAEP@RrEZo(GGs*|lZP zlIom)lz%jrJtds%z3cikH+{WBLneD$)E z`qI>8YY$IrRx)SHo0DeDx^rZ!dfkfWu6z8(KgP^|{LJS57ku+}*{w-SXAdl0a@pou z&$g`L8FRD$l83H)aMZrcTMj)rao}%bo;~trt?D%N2CXH-Wo$b9znzGgdb?DD}g69%rkw((C%{iZiqchjaHh73A1@b+U%7Pors z{pU9YCwHr?+C25TWBaE@+MWNw>&F^ydEM(Hyl}y&s(*g_@qLjEbI*(%jUnK$ zCw`hUI``|UdBFjzM%CJ|>}biUg%@r;{pH%%pMA@-yx}W(E#5KbZ|%A^rC#+f71fU~ z`|8uTfAl_l=E(K_lMg?->eyq4A8P&fB`rVd`o}LXEo~b4{f^Mj)nkrU4_)_0pXXop z&%SH)o}8BJt7Z*+V&`Kgc2w71Q!(J-ZEcRfGv%ulZ)Fa??5TPuUV5$TrZUeh#obkjV~#GKJQ@XzIT1L zIP}H7s)H||SiI$~k6Zq%J@LzmW{+>Z?3219n?*)A${~_v{rjJ2iZ8ZR?e5B4yRzW_++@;lK|cEDLs-e)6@6 zqx$6Dar4YsSO0s?KX2c+Xw0-0SN8b%srAp#>R5m2wfz?!sylK;{Y{m}Ykk?TMQ-b- zj`yy9|M9t}-h4GJyYtWw=MGuZ*=Q1d{@;}gJ6?NPqox~cb=f{;=tUhCog8qVdHjn5 z8;{i9@am%GBZhAunY6z7Jqzxxn{wpV8iQvTtJ=Rf{k(ofjoxVX*!g82j=gvI!HeI2 z_sGF1-__scy{27w`lQ7(p081~HzTRC&I2uG{4M<5y6uNQTK8g$O9!01JUOTC&`7a< z~R~8I-Dt*lMCB05wx3FsPbD1sMFAq(w z{nN+qKX|IwrIN`EQd?-}myWxl`+|`f*=ntH}qt)}Pknri-u6d7+j6c!x(k7tgLyZ~m(v8}*;* zG-P@5(6JMKZ#Q=S3rm&{EWWz-&npIZZN0Tc@tHXfcli0_^pmf6`h9=sjXQS^YPxRu zZC5q9zs-q1N~c`c^R#4H@l3h z`&jrkZ?lO5w%<3gevNByDjDCuI=ABdz87yBIjeGZn`K}4ql4>Z%vigA_^fw!w*I1e z`xo!8UVYKhX_vQ*dUuAjcNXabKIu1Zjye0TErV;mUeM>-pYJSB+kYf~-PV}{dbO>& zaQ@1z@3&cZr0zZ0H*Q;BxVppr$JQ;saNM%end?Wr_;9!0^D2)I&;RY;GpDy~m2&%Y zqyN5WdhbCgz4za@vvc(WPu}v@x-YJM_4{TOcl~hf?)=WbG~F=p=5dR^7!_H5edF#I z1aDt)ymfYP|G>MSUHIs+o0^=QRaUz4sn*+WJkqs#!TGfdf4zC_xWdaDwEU^V74LP} z{~sqhEZ*H|+xnU7@2Gv@{6<^u9nyW1Wgx7SyA z-rVX5Ywv9Eh_<#8X8FD~y-xZo6S!ql5a*`f+RdR!wIe1$4 zytgJdocOExdf_#5Pjr8!UiW2p{czEO6T8#HUAAg3PHxcQ>r1}cabo4cFB&#k@_hd@ zwU4&`;nP#aLss{CYf=8XAJ=x@d)@mF4SVv2h1<8!y>fGUt6O|p?|&US?OzuDxygy~ zkFVT))9_^-1}&?xziddJKT!Xb86C6x=aywvf4_G1v}dOO{?)f_Pu2-{|EOh0^QJwG z-s*B{%OmUZNAJ1kUeBhZHOJIzKj|J#KQOAwlk?N`lm*p8zwXlKw{E#d_ivw7c-vhY zJ8fw-dqDG}%V&OHr`1oFH|}`m_HWl5|3}$-6_;GTxm7{&@}<*0|KRbNzOP43D%;z= zeovKo75*4wLf-&0~e?Dc;u7{6IIgqTqKEB?@w>&4-r>{8qIn7p4!ik+W*`$ zP3knAJL$W=bB1bL+T7c{;PBV8TYm7%p{$0t9;>(Dk$L0me%N!zfja&3iaKn`zii{l zlY6{@yv|2ab=}!)H*of?ho$$?DTurY`Zkji`;P3~>iyP=a*En$H{7LgBESUL8}v4q-cF5=Y<*+F zyW@q!Pc;7Uli8PDR=qc~h3BJ9Yv*oQakS^!J=Z=p=;+KDZ4agP&mFU@@BT>@ zEAsbUu(Ipw+{c#B*!Ww|cjx6@`RwSc2TfV`+%>Om={DqsGbMYQ9(#0r<5jhPmNp@#N|T+fUy;Xk}#3%ROfFn>w}cfT>SUo7OLPa-S!r z_g@{!zu<|lPh3*FbK2T&TO> zBcGG4A6CWsNz9n#kQI>}Y)zqc3ztMH`ZsT%>JRay;mtd+6_z-`2m-D$Ch+?q;L2?Q zL-3QOV**WsfUo4R1;JFm&L3?HbO_jI%^X_*9XdbnDJBT`AmAr5*#aol`2kS2fGMR+ z157Dp8emE((;!nynFd1;5T^bBo?;ND{y+c%!qm^6Vi2bOAiISy^#?)BAWZ#1b_-$Z z4}zFMnEFE?W)PQHJ@raDtfnd(d_ zWoj^`l&Qg#Ql5lv!Si|m{P)2^D(8Ash=sO zOwq)EB0Bs`DP`)1QmhbGVPQflK6Q%Y?df>K8`grL+B4IwCXL_-Kl9nqjesUsS6rj*)P zXG$qkohhX@)|pbu)L=>}Qv*sJ(O^KSBN_}SbwmT&px+Ss^chLlCA0>yfOE z-9{j32MJSy^?O0W)L?y9kTPX`R**7feO8b%WqlTQVZ`5s^;tp6l=WFbVpD_lSwYH_ z^(NM)u^3aYAjN19#9sjMz;20~8u7poaZ^JOgdlEe z2-q!gQ^VWrDREOn5P~3XY6x%(2@3cDFGqp`HZ&lJn;In?yM-_fnRr_g6sYMyj06R0 zI;NB`)zLP6Bq&hRv0LIy(Px7x2?_|ng9HUSVdx-10f8TaI8zAVIT94;=E2ko3LXIv zz^0^()A;42e84Ce>3T291g>6cNI!baMDPvKCu*b%|4*_0|l(7(i2PtDAz}u2C76K3> zWh?|BM#@+SK#Y{J5P%0MV^Ifz2PtDAU_7WzQH1zN84Cn>kTMnm@E~O@1mHo+SO^e7 zq>P0C#7G$n0W3z!SO~zBl(8t#z?77+5P&HuVWY{j^~#~ zs_k}miR#04Ixa(Ki?++zC31%CaDHi~+U{nT$Og8v`K6X>yP931^06JwE>XnTZpNj~ zvVc8UVb>UDAyrt757(^c^x4HJzh-}rB~5;f(6dWZevQbpD^qrjPSR%=ru>@SA8Xv~ z8a*P?O8j{!?R<7s%Kwh$VHc(R8m+^wN!c~*hNKg}A0?U3u1N8BxD3~^-iKc^eB7fZ zOIUU}%Kpysm0gYUYc#%CG1|%J;WGpndSI4-KhhR4E5!=Zvmz*pm854y;2tYVVbWVyrN=MXY0rm8O;m{T(k^LeI8G*vchOpxIE&?iaKq#nqI~``JD9MdfL_K#z$_tC~!_lI$QcwHh zvMStdMK!xy4{GG;K~HwLsFdANB;I005^f1Hv zMPx8~<^cXDvSzWW1hWyE2xgs{5*$$2BVIXW^^bFA)?>phK{XFYTeZ~_o#PdGnEvO{ z)RBL#oBGkP#(|s)W6Wtw+^H|E^#3O}PSF?jA=q?@h^8JUXwF3erw%4?rW_@VsGNG2pt*7docfl)nR1lDf^t48aWjhoPE&9^ z^r2fvCn)NsE_Hx0`66PeH{GEQ?^Z6Jb1d{)`BwPIPDvU>q%isSl|=m~ITzM7XOLQ7%eg>P4y> zV{rB@L)1so*s+e<@P2hRn8h(#-*`cu{LaZNuZ#Ia+e2 zHQrXDLukT+Rjkpt5*@@efrO_1bTA2G4o5;$cRJAsS_w`4=|C$2%bEpH@(!R%7j^SF z0yP?GSwd5HI+Qhp}xsjpi_D=^a z*3^!IJ0Cn@8bGuppZBrxr08&CL%mAiT)jLNv1W{H_3_MzWE7H%bJB!qZPc#uat>{C=HdDXhlAKrBtpM%~?}iHku@Krj@If_0y(GLd?yp`~$B2 zgt#FYTuGmLm8fUSiUNvM%|GIJ+e7e&^0KpP*YgDB7xsQ~VX=Ox-d2H=&TB8K@# zL|Z*+A}(DXA6nXQfqg)(9IP*p3Ooy9MIXt(Pug%Nn-D%kilIZ6pkZ!=Wx*Ui-eTHS zWM~#9a5gcn#8cN2JmyH%c$$X^-tA>+A}0C3#q?xCG^@W8t}-P$t#~Aep2Ez$XiGlL zX`7ymzqu`?8qfM*Yr`F3si9lnVR!5tal)E^U2Z0Lj z;#3|4Dm?Y7gFNfLMK+Epq&S)v1`6elIixt87X~Ug?Oo$=xRkAOleo~%l|&4KE9xsg zlWNaC!V=eQ~$h5ICD(VCS7m>Zw}^9>xjE zGnCfndKdLdJZ-H+J);wpM|;-CeuaKU2V+{1J^$>hfOGXKJT06E9i|>hS5i-1E5H@5 z;vbdW*r?RIxR$e5>8DMW(BXJRzTqFO-T2@mrTDt%nm)n@K^cDz=LYZrS<+9Nt-wEk z&)^cCHe3;}Xu15uy370G1DUMf-Ms-UWRmE(G+btWCH@@l4d6qnr2ic54d9!xgm-DW zoDaT%i+IP>l3-3vF;qwMk0&+}k97%>{&Tojljn@AH773a((t)T((lrE+52jW=>Wcj z!A-xS>f&o0-0+Hc;EN#K@CyI(RT6G^g@5@n3I!g?iY*8i%ww&kQNWpblz8f1GUjCJ z<#NPYL2RohaMqx4H72eTm1v)Cc z!?$rfqaznc*3x@7ItsjFHi~>`< zqa#mpSX%~MtfRy`TCG4wrQgN5j1I~ZF_aw>QlfQKc$bFDt)sxhXl|h##5{vY$1x#A zswuE%qbdnb+pPdcXCT3;YvZP5%CYQILQ}_*AuiyG=_qT5h3!}YE>A~U`!5u5R-q`S zqpa;2Dm(_zN<3|}0v&nyZ|&_+sb_Q)c*lGcQO_nmm3Z1{2_D7_%7Yqf--rtxC7ybg zsAqJPcz53h87rAFkuU_MKmlHf7Ljem7YpCZM1PXv?$UgTAG_~ z724rb)?Ch606La3k@;!HTvgDaZ;z89cu>dkTG=j+_8Moy)vNH1_8P}C_42YzYxlS9 zQo@F-SK+BsNdtj;T~XLOW~4~%?FOe_b;1>&60B|KHhBRqPrtFr=(yztxT0-4W}^t4 z*RCo&bu7VK#iHz4zEMQYUNIAEZHHIDd9kP%VB-U;@@;uJq{36r68dme5WC>S_Uf37 zB5+Peg?Di+r=!BtHcRv~I*Q7hZ-#NRjtWnES)!iPQQ=*j3pxRLYRoz!z=e(yPg|`( zM~QcFE~6u_cC(HjaHAvRtE3xSWm(@8VoWN3LG1 zlRez%sPHb%<#bf|xO2NzmQ?g-4T^8#AuHuAiAADUdKUTZMn0)v{h@7HWoZ<@#hA_y zJcNw!KmOeXLvtB1jFbXr%8b`DyP^?zJ=r*&#-kMN*K1$}1R|NK$x zrzUZ)gKymBu@jX3IFr;dsVHes(%_`zq@GEYN#UeoTt|~eCV7&EB$XxQ;eW$$U4;KH zO{z%6Ni1CJ*%MU$vWDh=`3}b`#8XWB<{gU$4Nm5p!J;EQL(1~XhOs?(6{+d%+P7$t z-kz<9hXwGXzt-=w;&|DLVUc`lvv`oketQDv&;%`bb|e}u2uH(be~GnEcGvjnv@KeV z7#7YS8i^+7MFtg>W~Ll|_k)z=qJqqn-ob2d_OP~*!9^WMl}CDw>Xw^7YG}S$kkYE< zr7c>8@k?Zpv=QN9X@&d;E-I2E75SMrw9V<-{)Sd9YhBu6M8=4cVI_EW@`#e+(u#}` znJN694E&pk(^HZ;Bsw%RrB8N`A&z$_J%m2f3N<^{4y&X+We^j4X|YN2HZj zG{plslcGLnZ!5+2JoX}<{IZhtqCV+9k2n47lkDHAg)5TTlf!vsmC?+U%F3dG3@zf* zBYAmRTG&?@NDE*acADwU)6)vQMxhoAhmAm?-+taO!qf3U`~gqYUEZhdkco=J+Mv0=6kLrDcnB#)t5;jYCBLEz0n#+D7<; zWu#>ME2Axbl`dLVo(tDyrnG17$_@{;=;Gx8$i{C77mm!rZq&>aOzj2IeEu|FAlL8D z@R=C_t)GSBY9a*XHPU=$t}m3~H!_00e*Zf!oSl8{S1u`GAsZf+ot=?YmS4%X*LKQ^ zg+tgV^o9yTg=u=55o>&YlCk(LJoGtAERuKbW7g0+7w5ve-sz7wvtgC zE*+GaG9s-YQW&l*j;6G$pU`~oQST3x&D#`{t`G5UH`Yth4F+v3c=|rnJHBmV<>)(LnGT$ zP+78qv3XVot1GefDuBZmO_Y?W>Aajo(N6yEHL!jwgacuH_&Yxora3KTV)vAlH+L4X zsp)o6-dtUi53q~!0ja6+;n;}sNMWr@y~&0a!vCH94~uDn_+-HT#QxJTWs121_FrfOuabunfz;&Ad_u{185|Dp^#UyAHFQIGZ!8DLZJ}*7U`7f{BUQd42L<1cGkVD zwK(t9@fxC?p-ze+JrKgQu5hoevpFBfb9G&pVo1k%ULqI6i{lQ3dkrKV35T;t#pfEB z0Tt~6nbfv$E~yl2kV$O;GPX+C@g4?F^p&51gdpK?ijyp3C)o-5LQ?xhHj`r4(BKj2 zUY(skB+WSJC`IJk=)ye8ahV$Fyk!zs7Ya|2$iLKSg*qq!bbu24O_(Na{S>qFIk@< z`SP?&s4md$-ag=aX~NJr6$Ux9D$CSePs}E{B%)4#!rhDWpW$@`S(Tv zr%5>sM-8$Q5CvQSpBE*W>^Jo8GUuS&wt^uxDK0z%2PjH1ovlI^aB|;cpi7qd844Si z>`+BPpWG)KK~wfG7PU#wz)o!GJ<#Pz&j|5@Q=QKZ@nfz<8Cygn$oLWLqKuthCdg0% z$}%~}hHz@Hgkx(DM13JtWs*#e7c@7S3(jkk?$xCl1P8UTdRBN3gPjX1$k0*CGPWkj zi9;DC*zoOJ=m&yp5o{Dgl|Ce>0n#tthf87yA!LdKR-iZZ!> z)7jQL5r+dyC0R(0Qyr%)OE_JsEl`EYwueZHd);80_yo?T++XUZ+@^8Bpv1-SO7$d; zB$eB=A=gNV7IyHdlM9YOm+XSqkYWf$gJe^5!1BF{ehb}#e6OOmKys2|(!fAW;w;yR zhQUs$5#LR&pE2r@#zK&>MT&x5Ot~L4Ot}VON9>CCnu^-OWXB>1&p;h3y|2m7G_&43*DW>Bhu4IB$B`P>Z2eHjkhz7NSh*7fi2QM?fak zNRUZmdz@@9`4TdzPDH3lzJ!b|~MeKUX7h+Eyx0F z4~8g{#=mIh(l`$?sV2m*n{B`m^o6836cd};#e4vnR2QRlNI4NQXchxKk|CqYGO4yTF&`o63wULlV$xEw0e(71$`P2}mAK%HA<6au{v&7X zMb6G4qZE*H4w{SI34^ygv%^XgV#2sTg8X;q1Q}m{ zCd#B**~HorDGt~qvh>`boSU$fONuMZJ;*k|B(0=Rmvd84o_j#)DCZ{ZIFoIvXh%U5 zqvCTh?3Qebxn{`*_*nrdt}y>B#X*SwjEU3ENF}m9zV|`EVe(btr^zBuI4hrQz$Kb$OcR9Z)C1l(Jux7$82^%055^<2Q0ZR#qI7rwa z5eLiyi8x5ufQLaMCnnkg4}?VDn8=BVoS4XomIV@RA<-5RZ6VPXYzrjvK_VX{@`2qN z618$7A0+ZYA|E93fo*|AK1k$)L_V-vL!v%N|noN-yNW@$7!?=huCYUQtYfjguXWM?X9FxgQT31OagafB;)VO8`GVhpdH- ziGhQKhlw$OlS3B31%&c|xHuF5AP5(bLmU9+0>OAVMIKbemIJiMqaX^4qaX@&k;(%V|4GiPHii3yi3Jz`{=M@~>a2@`g4{lD_6+XB@ zkSjR2xxiO(fI(MraC2V8!Oe3O2LyUW=iJb%ym7;>+6y<&RlRZZ@LaJq2;2$&&M$-$ za>cG7An+BMAzUEPm1p5bbam~j?LxRAS9pU!ui62W^D15_=T(}aAnq%&hjL%lFAQ|m z-(WDVD>U-}p?`-5_XP0Y<;MjDLH;g3E-2R(ox@`Z`074x@ZaUf1%+JkK`tni=kK=0 z1$Xl+w7`H@Y@7?m`49WJK!4|#3kG-ezv+z&#tpr?27zA13%jB>E*Q@h|KQ>Q!UO5= z@sEp#6LJLy&p*hN2mbVxXSuJ~Jr@t;iXUcwYXy&wxQt z?klnf!LIlbJnCMFVPJT|zrq_AC+zP&2>geAz>6Z_Puq2JFtD&PalpfdR~0Jof&u`7 z#{mvS2NRcz!U4j`p`mPIs^VmgC^Ent%C@#n@G1iYmjpnWL(0a~768{9oHxWbF>QV> z5fLDl1VmgE1QHYG7KML>aB^|M(}_4I!qJ5V`NhFvB4Y40xHn6{BPSN#UP6>hCN^eH<^Xus z;1C7Cc%bkS2?pWjkg%|FGI8LLurhEm5i>EeH8$ap0`PG1z$+>kj1yi?!N5EmDgb!k z78G=JaxgKlhSx}=hWh&Yrux&z9~#>l8_QFLy^)boy$!8!S#c?~jmg}|d{AU@iM@50 z^bKH*jX)#v-KUy7=;#~h=ugkqlInlR#AW*r1*4S?VAn3aoyT1$odeJO_{`^HjS>iL zXWjtSx93McA<&TD`fS3}^Yznlh+3SmaT6`XFNZx$T$duy0~ddn45_14hau1dOhLBg zt2W5fWdi>2kZsDP%}&#)r!-pO9xX3*_z44t_IH=EPqcu;;_h4%<$GwUF}rm4s${(2 zJM*TiKJhahl8Qmlvto0P=GlSJq3LCoAU8U(ksS>zz+A0OheL`Tq3GK^kOG-39SN(l z9lttijs}_G=!ynSP(n5UN`~UBJMRl(_fA4qZN%tr#`$7cHuI7BwQrYH(c;7q>Z$;1 zx#gs_-yG!bpnClTxSfzG1J!`39+kWh6F0jT-w7%7?hQawV^bp&atQ1OfrM}gE_yNM zH8I=|hRR>OgG-Q2$kBv}x^u283d+*Q8Iz#AH9>hv_)OnkLbwkzjvTj}6iBalLq7+o z5jBFktSsCFw#)a8Z__VDrjrPBLIu0vT~pc80azn_SezE4ZD}N+yGBL{V=v~~0!ebk zan1wB^~W2N8eP2KA!E3rIU%I_8w=w`L&hJuUaewXa#Ke2QfI4)UIG%z!fL-?GUqltpE zlNG$BapaIUur_f-1enW^^2a)S1&VNIWezzLCj(;xCj&&-frnoB3IdKJ;w!uofPYo6 zGqDjias{a&R_sQgtvfxd?I> zQbep@h(r{Q(#qEC0-3CVp^4Q6MtHslDF4+E^xdRRzZXPyH@XZL3KriK{Z0iIMjQ}8A z>c$oZm(YRmFv`siFPGt|N|!^~#L?E-!RSI~h%)I9c_EbYD>D~3FA0@LFb~gE@U4o7 z%b%#U;aQjq42KS{lDWBHa0S6{UJ8*z9kK5!^9Ue+!9-Ny7cegctBe2$uRIX&pxofA z@UAHD0>fYMekw>2052{sApa}G3j%)Q`Y#8*;QG=+5fCr)=f6U{kmzp^|4M2X5dY*E z(VxP(|5u0?h<}5KSowwPOC`c-M06ql1>(iF-yr^U0=Q*g(0Iu!0^%jL|4QS9=lli{ zvGNOzmy{tO{$f1;m#!}q_#4E(oa=(dpP>Z6iRgR(1J`gvg>U;6;>F4@G+x>aoJR0} z;~LQ%{tY5x)S=3gOR@fq;%K68l@A;+I} z@xMa6;xiX!_Y2p5`V6AK{V#I7;xmW_|5rKw=`)B)+kb(0#b*$0;ja+?^ch6I^B*8y zI_s~xzF7H%>py*l^S^P;eZ^-kR{nzcGd{pI122jG6OC7VhWmG)xkQQ3HSj-jeZk6a zTq9O~q45u&L5xQJix{uC%tc)N1>mLd6ahS!kpImZ5$*5q9&@qs3&6_=rU-!jN0zTR z4EOI2bBPfyM8q`hzp#9P_cs|LR(_%I4}U?73;qkhEAGPmySw~Meu@CZjOf1ryy7j~ zzkACCd_=|bvyS~Yr679#-<5K)@(asgN!kqpCz$>0|Q6v5W@DES#}uFu`@6-L9}3w5coaFPkZK&fS25e20#^r zSiLl2RaG$J@t^8~w`#UVDke_a9Pk4n4pkF3Cpdg~aV@ILA@1gMUj%`s*$?{7eY({@<@l_W!yMz3{Qi?=Zxf4*-go#=~ETo!oF`Ll6_) ze|TNu`2!>PBC}t9UaY~N1i@h=-tevn{)xbZfcM7}KmdHYd+|oxMcn!8Y50{chlqir z2|`Hl77gB)%A2?<+gcmgD5|iD*jgD&!COKLBRN%gOYZPfUR)p!aU1v`$->4AE;k!t z8%K*jzyB%m-wfzy9Mk5I5*0;YGe+qC!YqGj9WV5HsY3-tIe4q4pa?KEuyQovu(kVn zaRL2Li{MZZ{<*Fq2LQ4I;Z6Qujpc=se_Di-iM2XBIYQWB5a@+9A{y|2;TA3rc&}{Y zWMs}EZ|h)fV0H1}0}~4~b0_%eA`mf9Gjjy+z~JKtMhM%FmKmMU9s9ls@*#Oazk6&AO4Ex0L3dsa#*+ zAW^0VyD2%S``u2CSX_Sl2@_ope{1<9DBLn!>pSYhfsy<|O*C%pkdS*j!M@m0m`T^^ zvI9I)rG`zFKOR+dbSnLboS5&*v3~x_zvt`34DxETc1&Uh7-jd9wW~RS_=;x51h)W5 z>YD2aec;myJAayb^&3n6{mS%poIdoT%?XUzUs5J&fqS*8Fl4`??S5rE^Zk5z8s{$} z#BPj92079X)LP$dE6+|Bwg%nW5s6nJ>%WCs`NdZ>Z8lWL%I$+!X)FFKtoOrP#wxeN z1nYd*hsB+jRqsUvlj%ddP>91nJDP#54o1FNz9@znQysEgLDiBW z-uwYH&pr6w@;Yf5uo4x`Xp2$O46B8@e`?W`68;`wdprIIM4sN^;MjjxMPxxH^kL8T zmR9)K&7e*6*`7Wx>@kez#k_i}6GfFiWo07{Pb-kzpFS;#BRH}8A{aQjJA;#qqiv|P zt0Tnjh<#n}c6M?1rWbg^63cD^>MH(*s%UGfS<7Ij{$3#&>(`0XYN~ff4m@VOZ%>MH zL$^L+dd@e+(%y}DCpxz^RYDCLzJqa#@te_ZqN`#D%^2ZqDts8&@|d0h`yWSV7a8Hd z26E_S>GxM4hw%Iw$hqLN4)_7iFM$vU;DjFqA=VM^ivS5vmWZ&9_>TC05h8yE_df#Y z|N4*Ed$Au5193chaYPCa!id0*27?8u7ls4-d(I+(V>;Kkogp@7JX8 z$2}f+=>OyTlH$uxFg(^FXhgt8gm%RBumAt#6~6u_%|EX%k_G(wS04YM?^jtM@cyv} z0UHdLBM5;9{vR=X`lrP8_q7YSKWRk3;QBw4?XOQmA;ABgrvCqO(}fNFnkQhO|Cu5X znEuba06(VunHS(cO8H-T0iNeB@&a6ZaC-y-;RDS7&%6MJ{A*qS{+1Q~>dk&;1^8+F zKb{o9e_g{Nj5t5CfmdK~j$AB^OqB17{F*M3V%$|#TuIx#Y&%jSqKjLM@U*>)(IdF6 z3|>;9Dq%`tA`^*74xBmJV$ty+LA_g@tqt8-Q{h z3FKbD&c;WBG5xAdrdVqn>&NqyhZqqSb+odbjliw*V79L-cu4oiVHiwN6%I*!_Jw)S zW!VGrB=_uSh5#kvwQW@UN^pr~O5M_vMV`?Q*kS5EWz1&DBALK#i=+o%$)jO+-oRW3 z-$d`j^jb%(^yr}#5o*fq@HYnyy_Vh<~zfTeVfn#eewDdp#+uMz_=+p7L$}en4p+%^TJB!+h zT_;Gu?Ru*EqaM$r9Cv0YnUg_%{r>*Gpk?-WyJ|1=I2FI)-e&FRcBk>g9ew*wP<%q9I9=*|_SDv!=p zh`mgP6~IDYtE!BOkc);firIINcHZG2Eqp;zF2|elncQQGeuV+r;+~qB{4xF+>-bP* zMzB9qy&&Ovr165jLuS3r)6aXFC@5(t4AaPW^$C)E_y|$F2vM4a!9f@u0IGR!lwy*P z!aTi50p5(fQGe z0GPDGxIs9Y!uSz)=h4248Zr@u1S+SqzD8p4QH>x4iLmuzzs6V%3`nQywOKywRa!=M z!mmd4M3WOHNZU+{1)}sD+_u7~X{s+K3-?i(rgX!~_kA?YP(}O@gP5Pit-!l;(>j-%LaR3542u?t{#Snh%;p!N%e{wBiw8q(HBH2E<22 zM(-boI>m$KJmhm;Qhhv|M|Ggll-U3fygG~!qSs@Xy3>$R%v2Z!l;#x|w#eF3YGZ0= zy2;!h^*|M(b}uY#QSt8U^#PjIr>o?v)~m!6VT)oo*(P5G$`{IMMmNn<`*X}WmMNQ-68U-;g0>03@>sHJ6}iY1C*R{se11O4uF`eY9xAz^xKj5g!&u1*x$* zh?6p?1{uZ4#LIOHFVZZEFWw=2w$S#f*f?K(2y=~T4gFEfCzI#HD^_?lv2}r-;hw3Y zvsL!9JlOJ#OV@gsdvw{GofoC695%2w$PRH`6YkGrxhX$HD+)Z+o)p#Sr!mU%_ZB!~9;2oskg=!wkDFYE zdM4TXQM z?v|U5*{tle9$&9-R0iAtV;x}I)NqYwjz1c|KT+gCDDdHS^lfc{`aOREKmIO(`}`ap zO%IzMS{4;NjIG6*OrO-+RNA~HQVo>QU>v`jv@>&(b?kH$dcuF;yv?>ZG5vVxutG0F zFM29&itYOSDArX%Dq_#2%@vMA>g@)KModXea~v4amUY^LG?1P4bgEyKu!ZnjUwQP? zJ1{y8>RO>A;UF1FsgI9opda|{1F9bUaA%?cL(19q=6Y`$G#LaG`x$r<+zfaSu!+^s zaIg5@dwr{>3Cvtf%@5&09g?i2bUUXXJK#2`Ibc2j?d$0aSx)XdG~_pAF+6DH58r=2 z*#4B{M3#s_lY!@U;0O9P=XSXdjWeQ@|*-o?KG+FNo zs){gmaEz$z__69jSQ6nTSpR_cPV7f$7d1=9jcXwootP#KI}bI*G`&VV)%-0pSB2eG zzw3X$Qz0ghe^yER#_(}#S?69S!CkNX&LZA4nn%*$`xTVd*#}M)p3b8C^vSV>GEhxo z^|Cjn5~&$enmB{(Zv+gdXM|L4hHkV)x4o(USpBkkY2ST6kYX5bGyo?oCF~K!CO19! zG>6w)~HA6r}qVA)*kM&JG$!w2b~8(&PUFBu1^|hy;@7; zYkC%vT^}$Mj*poPWp7rOusj(&7+kj8Uk&C)epH$7K2flImeF2hR=gDW(0%jfBk@Op zLuXZmRuf`+c2kx6ANEK0ze2^VhX+4z*seCza9YpJAX}w9o<5OlP3*x#$G4f1ov<3` z=ZQL2K*~baK8vf0r;Cq>|B+yxFqkNkSd>JW6r6OJY@GZh6IA_88MmYnJ$@&S?XEs*|6+4ITSh1b53(@a;IM_zy9zB`sPg@W!{UoC~uwLuH@_F z_ZEm1R28xnrWcVGJugNob}n8m(JvV)l__m5gOwGQ)0Zbz5Lbj$B3HUsZoM;qH(jM! z)%RZdeRDNmbwv$(O>QksZDQSxx)=4>_5Ste4IT~qjdqRSn#`K!n)RB;S~OY)J}7(ZHMjiozPwK-P}F!Uh}@<{^Wu6!O3CB5&6;U@38Of#}AH| zPF#Or{D?bcKCM2JIU7H>K0k;58sgA@_vC-{bciA0?>*hcbnlN}EWv-W2mb}uKm1Nf z#KOr@(ZoU2*4ob21~FoR{W51n4Dv1}jF&AR;+T}<=cI%a_{VQN6fVY58M@_ z4#|6*c>ASBv!v;6-y5Vg3d^A4;*>9F3nA>sdf5^z*EZQ7JfViXzB}^6V*VePtkonM6uK>Jq!WjyJ`JnJt+YHTeh+Yu#ho1uPq*}^ zrMGlN`|{6MpPU8G_C8n?02?(+PDEsub&bB}jOqx~-b{20Uw~n!AU`N^eY%Fr7*5i@ zi`qJv*M2wp7=2yL^@X$KCTL9Zl>u3bX}VU*987|;`Q{SlRx*!I-z@<(meco98&p!R zQ(-X;lo9(YX8X8Ziu|n(-~{KFFP^@QG($^EYD@q=`M$cdLgP;TL+bm&*M!h-g3ghB zvuTnZz_2uR5@kbP|9Z?nQ94P zB4)7LLsWc_@CSoosWR(Q<3+(CO0^&^v$3TL5^Lus#kE z6=sLXa;o{W3!3k}o_-zP+RdAb%pWd=6_d`R6nU`FDo5^ym1skc!Gf?{r zeKmSm$Ex8sf6r#i4@vlOP?V~VA%J=$FegXJqaXfyI~_lrWIf4v$}Y??IhmxPq5shn0^msJtzTrEB;7YbSR zKpfXd@JGSZbGoeY$fzY8PZS6AVjU~?)xD7uae6;>Mm0PZYuP92gNZ`X&`puh&p4Y3}0n4=IlIu*Q%ulzSti z0oy8!6{R8fYQBQ^TX>mY}q+RO5UQIo0sz>*)YmK_VyFPUZJxf z`NpT`;0~gr%u8~e-aF~rnG*jApqZR>&pG~(&{|_ zYoGib+IBcx$j1=Pxn6YQONr`ED%jb+AVnOu=SuCLbmuWy&@bktd<6%Fwe&1d7!g{4KeVytIR*zk4%CCu5>WQ}kPiM1dvJz17 z)w-|^b41UB%$lU1omU$7Lk8tqB_+)teoPc^Z1TKsK!87P4Vg(&)Xh9UkbNw1CaO8; z-OuI2Gd}6=H^|)6(l49z3S&>@2a$KO>&p_)YX|w`_1!<}PtSXC@oN|u?6N(6_{L#; zZD+}0`*^-@Xi+&o^L}7MulplQ^qM3E7avduysGeMrA#o$_2auERV`d16vsuY_FGNw z>7!o|B*TTp7~hb8)PkzE(-%`dewIVZwFuDGDz3u-(?bIavs?vz?HxyxZ>Jg-Q=&@2 zM^&vBLEfSszAo7JBdrYV8}bcdE0Vj1OMGKB1*T>9H3=RUKYHM>dptbWfZH)qtL8kP zRrzCaYxH%9+Dnr-ZCh6!N*hLG+eHmnWFKMAl0mIVm}LNJ`YnfUZH=SvDH5;0f3#m; zeZ7+=j>f5N`3nD?apP^PWHK&dJc_v)Beq-)C&?l_X&LHK0g2~b8#Ge>G!A;K(2AM4 zI#Lok@d5h!%xhgeYj;`6gTiB%ZW8ElP?z!nNd5jf|6 z^C@bt;lRU1TKJ}vui85w=KU{rul!Z-H3olPrY8y$=#X=4*c8BhDPx`f&KR$$1ldES#bYy+N>Bx*+Mo)!@zdTagKYmd;Xf=`J`<)<;p2uEY zMu`xw;C6FMF9|Ez!@cL9!DhkKiS6p$M$OdOAGgHUS*rUi&YK3w`K_Gc)NMT(!@D*td(4{aGjC;lZ^{V$K&8Qatk@sWlrwhr z%yOg?w6Cl3jr4o1__NZnJMlbq6>KdwUsy~J< z=Lz+?pa~~q8ooJdOVS!iH!~l@yOC3%Eu2?4(L+AOtj;zO?pFOtE?Fy`mJrjYHo_m3 z2$SJDA*wsphlu%Chx3bQJ0e5?Ecd!YqJz4d>p#*R1^7~`Q+7XfEF{tKFP-qGF75JX zp>x}13Aj^z-wggBpmOt^K}J5a3y|wYGbAuwC9WL%kj%42v6eQzvLWlaSgbuC+xI~6 zN6-qVkeRYn86qO)7UFQbfw^6bJAGunh9$5a9g~CoEd4#w{*VW^q|$c4kA||obam1f z=n#j!9Z%_!ku~!r=hx;$*KyLAZHvhm{1if6kPaycHO^tMzB@O(iE-?m9Wl>!W|7K4 z5+p%LB8lO50(r zI@U{}CY=3e5prW%!b3#+3VN@R#=`J27#hb%a(jBL6=aR5ST~s8M)*QF>FfiImI<>I zChxJ`rCuX!$~_-%*l;%Gx|LI5UgLrH^0loXVJIyUo5sY{7-wiZ_wjp%QfarTdi%#~ z*)k8YZ6r?2P%6d?ZbqY(<3AWDqbo*fJuM@Wmdx>qH>_AuNcM_*@7J<0X8Dnr z;6?}=k9F`${tw!5@muEJ!kapToYiUL*Vf&?XUL~l1ZO{4I_+`A55kbp(Nk9#PTIIP zOt6Rk0bS?(JNw4wH~$E6bd{-oGa+Xix0AvHrB-mJ+T%K{T`iX6K2Dxn#e8*25#qrR z;VN@O$0nt|*9KXo9-&hPBc;y|?KKI4^X9kmYj${dC)c+EDbISJ04YPon`}7*nRPxd zq>(-bI*WD%3*iDa7=+)gOo-~DHEft}>tm}h53+z<9V0<;X>!xJ%6Khv4~v9M?eBg* zch87}$J3^hlh4$Bp9A13Kcw#s zRuSNH{O*@on5Xs3rgQE&dULuyuD-6=w&d=4=jfNYUSBo=3-xIpBH^_+)o0h2UcNf3 z{lWe@DKj|T=B7reOGR|b+E+e?d@h$mt8&-IGZU(w=}Esv@i!RH{Vm6iCIr>w>hkg= zb~|5KGz(j^sr4)*9yTy`cH1Q5%}T7|h-Uy+3=H%Y6vAi@tdhC_v8g5WQAfmR=E74- zmP>k4mh265*5+SA1xlfus&D(r^-EdS7>qs4b-3Qs2PQ`K@Ye4pADumbkcZ^4EY+R)rxr8 zf!yJ>(Yq2(_fQAk`e3*~#_r|ZdMKBTEmqvRVxIMSjRGvSW)Wr`$y@UUGI!vSDFAp* zgiFL8@_9N-j$KJqjhk4<$Jv_UWJfNTa_C_LbEf@FG>1yzR7|_!?xeR6MK~>!U;qr~ zg{`UP%z254zV}<$c1UJdDq}fDiV^i$CC8&%fp@((2ZYljPPh6V+ftJ_xY=Ekdy_cC z|HZOwa-PAg_~7Q@Q!SsvrgYBFR!BLz^$^0 z1W0ldhaaE5MDmrm$>~iD4QpjA^_qziXr+=E$E`ln(0_hgp(E&KA?4Tkf1?vVqQw!z>uolDj1qV&t z=|MCH^z1aIG$8AhEDTTm{wl-JQf!t!8fLXKdZ4Aw+lg2GDN%jOichG^u^Oj=O#ov^ zr!3KsuJaD>aTtr5Zdr~(o?qy3*vPjpTz3FjFB8>#A~38rfJDvxH*HR)(3f041LUcZ z@$9hZ!kn?JlTo^&S(w}fJatwvpXDZKsV2#HZPe*D@I3vzIM{_J5%_gwTkKxqQ69bm z=mcB*?yJ|&?mxrcz4I|+WfdAh0oK!bkd@VkzQB-n@D^%9S?@f^d%UtkgPRzS!|tt! zJ$pQtbZCp?84$}p^Px4?B!DRA`h6gsYpVXC_7fWnoe88?L-u0p2SsK`he+~*89=gR zt@z1uwp;=GYh}fld&0~w#qDpZHAw_Z=KxpA9IINX@hW$^%OQhF3a$mxF-emsysDy+ zE*h&rKBm`EW3IQ>f#v6m+GEaU-#=dc(l|ytBRO2or8@PxUTD6%b1{XPS|ma<%soUb z#mbOE1w{6ag7I4!MSRnALLwS&$nD{~j|LfI&FpSeY+ZZlVyTR^)&|&J_Xz3)GZfgq zS7S`XF(sXP1(+Ng1f|>r3-OHs=e{!|8>b6`kMefu%g&>d+1m>bODn7VqK9 zdv6%t+D^q&s_+_dj%`PJjy!hLsb9cHOYrCRU}S|RyxV9ZXFWoydL1QO9z233_NWq9 zG{Qu}IltU>E%C`#^r%F3lZiLgy|=X)MyGyv3X3GAr+gU+v7dQwW*T_AaMst_*P~5u zenZ;Wsu7O;>apQ#TPjg(b zpw9sPh>sa*1lZ1y{j83(iiB12$RwApjqx5)>JZ&shHP=Kf*qxr#+diDpbyamu)mlro4~pgfDe7*4GH(Pt|APvp6C#8%1WF-hjKalM2yW;)@>8_Y^$6b z)_415=6{Brc{%4ehujkn^?wz5ZPYRj^hNqj2ydEihLLc2_WGV3(*aVK22O#BGjAqt zEY0FDU1D8n2SXw;{7hBy%RNk=Z!hbnPM%KHO}b9iNgda2`c|l}c=g673rr=SuJ3xL zeBM13$-zwI^E42o%&~|1s#`DrP=DsU7Cz${m_y+dBHbZ^B-*ZXTWpI$tFEh)%{c%` ze>b&kCXNzP=^mR8d{_RgyP)aJfHn06y-)Ug*^;=vxb)~XucN{-_x@NMCvL0wW*xxD zFwrufXpE5Y$?`{8h8BDKPV-$~98a5*>BaR^S<3zE{x@6bc-S%HeXbwBmhW5IBOkBC zG3`Zri#h{b(*J0Vzy7_&c%cOX^;Ib;c4TrY9l~Ka-w?;kz5nrv@Q{c0r)yZx^;7q- zYT#AB?SLG0?r)T+FyYCOQnVsBcpwX;q zba_jz_RKC0Loea0)R|W~c6vNcwLs5}U4}=?-ArYVH#G)5Fz6+Sv2Ue+9F@@UJ?iAH zBnX$iZ}Q>3p)gUjaae}mQU!n2lDCACBr!)F4`G(TLpm~p5(@(DM_WVS;|;b)E6W59 z_EzCRlxI$DGh$z#HaPa<2uQ2TGKC}r7{446XPs;gT3ynKYuJcS_eTqni&fKbY2dcB z#M7oiW^Q`JQgXf-8U3Q1r+O=)T2tr-76?YKOyiqB+FOzJrE=d{PFRw7?q;ihQlNS* zY-wMN){xTO`EWYmljo_YTW0IE_4W@Dla4PH?Q3IYR`5(5w-CBeii zLZn2G%mssqP=96eD9M`cN(0OVOddp%e449}OL1YWTzni}=SA_n3$vNVZ*KV|1;LYr z4O_C%bsrI$oM$aM==qZskI)1d#zj6nyOnCW#f8cYsIEEFb=e^xVLQa+>6KV-fz`bHetVCypD6V$!pWi8@^@1*Z42 zhNibAwt^%>r1ri(zJFVHld`T+?Q0c~AwjxjRsPMha?`Y>U00F%XXp8T>LITPP{|Dx zppcWE7hD{*kfZMBb$zN)VI?9&o69(`q>tgLF9b{8B*sX}0%&plKu)aD^E7gyF(kD! z#*<{2oPt8(=oSINL=)G7vIX|Krc%7V*<;*jRU&P7&lsJy*%WzK%YT$yVI3Sr_f}d< z&IISZA^U^cgJ|s4VOC$Y0B%&D*$~D`^EcZQqAKW_Uiz5PBuY^u%mfurvdLMUL^Exz z66jDt&5E+2tr~@vMoVARhHkp1oX!b{We}?*L?T!F`Z_Xowk^v%^jNSQOMg)qr+v+g z0mv)QWpC&Zqorx#x#<^Qk32rQ_<11{izj)ARZgC-?FSXIMMqd{Qj4#A)}u7qT1slO z^#i*|?%LPg1FjTGT)51oWTFu5S}K9zmNnjkQxpC-gqSj!l!1;`I?+7a4LA6yay;+J zD8>gz#@0O%EhAvpP&U0?@6CnfZyd)A{obMUKt}s0rByEQZ4t?HWm@KIGLC4NI`4}z zB3)G1=a0WUWcqg80n{+LPw@0x*7N9DJ5_pdsyFeT(=>_McyAsh>>H*5{7P_Rr|rXw zMwe01WJm_Tpw0`^FEL65g{0kSyY4G%Jvr3iexm2@(RVky(_#kAf_HP!5qqoR2llNo4A8`=e2yKi85U%jBD z;e0z=3|m|hAALlBN9)_m)HBPh{N~VCO58XS9MK(b-y15Gf%R-m3wIq2XoPs%o~}=} z5xl5c#jAHT^3TEq#AGNI)$tq+?B=eoU(eJPWum;nD;MSdiZ~DA;#mj~6Cd{DDWR~iqvvm!yqMBhVN^*D6)>F-q3ZSKL zx&;st^l04>yD2nWdOl4TnjWP(Aj_NE_eR4qFY#`sfX-dd@|Evr?Wr5~dxnGDx0Of@ z`nRzJy|3SRQGRyT7}YnsDRk3d7Q9Emyp_h$D)Y$8$rF8w2Zl#Nl}JR)qDYc>@O@hF zLrF*{z8qnfx@P!bcZJ3el~`tV2F?T()ndy+43_TPfY-c!t_}em3q-wk@lQxaA{b_^ zDMdY_yJPQZdE8$z^SJ?X-mfo_I_PtzvR$YCY)Y?1;w@w4%c-?geX`A%vf+7p(~Ou| zdCgK-KVuZ_>kUeSaL*j(qfK(-+NaoPPx=696jTjj(8M2`XV%sE&5Kx^hDp!1NnV9c zkOQ?u8XnuOrkqgJ`Iz%2%6bQkP)4lC+`2V6&^#^DG#UK#G!bvVZMx6$uv<++71cW{ zzxW`fH)Da#nayVv{d4|{8M>HhG~Ukk0S&1p`YCp1w>Me(sy+Tph75$buiWC6(nhM{ zs%$bH4{du~_h@x4n6V=;-LrA>uVF8f)oyP)+lpQNM8pnsH z4&U@@AFSD`9Fm`1V<{^ynv(owd`$ycXq9Y-)S~6^R`F51F%l9DlgvX^h#pqgg{(7#- zOChmf=O4$OlS>DhEi20z+1%RiQf0Em^2I@WQR|W`*8rxc6brjA6q}NY`qstKcstC){%L+0^FA&Q@zO zY7am$VrApQCo^K)E?;;gf4WE@u+iDO!rmL$^g7~^v@sVZ!zS&rT`@S)7N)lU<$6r!e2G3A-<1&%6Itisi5EVn)ayg0I-l(ny9?d(LuT7)lH7p zuG&n#g9ElRCGJvzVX8a51{6fGv0j zl2WzbJ3oGx%d6^ciK>Mh^9&0d_TG;B?Bm=n>Eq=E`d=e$iak;g0Ood z_zhN!$WtSjO%lz*#yxRQpsUn=p!-*6DlaoaeQ&CVR>~r59!SFF!H+R#d5{uRC>y*Z zQkeD@Y9vgB7A;poJ}O!SJd30?+Itx0T7D=yC|HK?uP2O{s^A(3dsGLRpPGN&!l z`U*aItQVZNTlaykNYX{x?WC?JRp4u=`BEPK7PjA=CVEAwj9Wh{sg`1kY^t2XcpQG1 zhAx^2yjjkP_chd*PEjFj$ml-f(33y#-#6uN1aLwPM`v+H zo6dV-_u3{u>WR3TViXIyH;qFbS&i2e}A*^$cU_o!&{8XHqY(4udH*-E#qlZlp;C^E)rYsM zlywA0M@c1;f`}+EmHCx$JzDO5;%FFDdPr<(jz!eO%x52vEso`wSJ_?Mxw?<<>v}xx ziTRM49IN$uwTAku?Zp*~H^tpA#I$DcqN`6^UZTF_A>*aL#}$uEefl9I7YqRPNFeYlZ zzdV>aGHFk64hxke!~%Gd6!Ko1^15^M{6R8nf^hGqT|{~bv2Y(!piKwWM2X?&+b< z-`betQ+H5jOxu5>>&Efnc~c_#^k5q;+Us@<2N)#OG7B7c zoVP^L5ap+N1I?Ey%NN~8^c}QPLY_OklqFr<=lZKHd^NK>k;W^X3A&Gu zd-fF>yPiaNsz=jgyNs6S<_|bYOqddV$S0s3sHkjBNVs$V`4b)-f!Jf>(vI{dVRr^B z#@DmvL5^ynlzcOv-M>r>aE7bjlAnIWTZ!UJhbM5y>G&FDZQ%4UDooO!j`X#8PGL4! z$4%;eL-(!jj)EWaM{+GrqqKKAG!L6bUo7GcffeSv9XHQpQmtjuu9X%>gL3T0-+fxr z6AU9#`byMsmyC{xdMQ1!7aRY9*~qsc>*Tws*7<@rM7E9TI;GNCpW$9ZF;vxHnHd;d zE5meog6ErI!xX^ptbIB?w}#`Tp*u#xzI|jj=tNYYOe=+TO`9}UZ}qX2aO+B?+lU~lzJ~d4=x>z ze=ez8;*%GV$Sv)Y@@6$i-Synut^d6HmqNIFVPrGj6 z*+If+@T)Hd>Qb;BrQv|ckIa^R_#Y^Zm>X;t3x%2l`i`}e;iI+J2fQ1zNH)#p zq3b^%As72XQ)ME-K2s6hX@2bUigfIz)oE+K@oVVds>f(1MrB zf%IOvlaBuMfNqLFS4%H#kT zRHXD=uSL+Ph=aVy<@wbe-d2qZ34K<3xYX}NYGUvTn=v1b#xWpFpO(=8PC6)tSdEimJ^j(u6jfUOGp%^ z!$js0j{qOMFDTf89}*GY56AU>8<`hGO;Ks#YaZ0+X>grNhbD!;fU2Z-yi;@a!1-b5 z`SJe7WVke;qtueV42;n?Xquh59mxNmAD}sX)8)bX0>#C-kHqO_1S2hlOEBO(l{wve0A%4x8b?8mq6#JkQNr{;o zoDkt0ZHDWiho+!TuQvdD5n_BJ)3VukM`2)NA920m*JW=Z8YXkH#yr;7*pbcOa3&rY z9*GF|naiykug7zKGWF5>h|~3@1T~vWPx1qK+9&zXhHcWs+*pk|H4?FEM-*csySo#u z8%nCoao)_F*TY%;fZ%@BwFCx*Wc=A_u5*>YNMvrme$V@Z5|W!T4N zB;B6WBH9dAB-BxbDdzEAhn;H^T@TchC0R6)IvTy)H0N&s1MN%zE>+Wuj4352_3Fy5 zriNc9@8axC?0-u43@k*;l!VTvUgwo}qP$dK6C1~q6yG59{sGCZ5oIvL(?=DqC*g&w$H6(_Seo<#qP%kIXu1kH zVlDFzPfxSk>-7#Ts2#Vq!t_IlxrHVA$z)J6~Zn{i!ng)1>-VA(v$M>Rzr%u(lr0J5y0n-Cb4p!PgP9)7h{rrYF(~3Mk#6O5|EOXZlyz> zK|n=+|NH&&>KC0kXJ0F?wf3Gfv%pYKc`YH3-jrE5Pjsp%hFqO`Z^Fg7xIiz7`9Atc zCk?A=EI-VcSF{i9m~1_~=GkiU(3Xu=g-@NNcf`&ni(pQ|M=FNY4hjeVRRq9f5k<{QK2c=_sDbDSTn zFeouCDcS3l$ueT^pgv|L@Xwvkp{+{xGIMuwe8{J{#&`kAmnKco$(4mfwf~-?Q-VVH zLcvac*%REUG}Bu>Fd&!g!WuYOA<~GeweQvHISf|xgzO8k3NgVV7lkNRv$ZS)LoHd2 zr@=!Jf0wuP*vu?ESMp}!GVQ)T3?6}yy$l3l5V<4YCXdK`=4ISwYxWa_xrO}MUOvEG zH6{(Pz%(?Tv~q@vino>fI$!LSmcoacgrVBXNQG?;LttSJ=Tb<*%rjl*rpJ|(=^XeV zQvj(O@O6-)Fqc>+1yi!oD%9s1PsN-XrCYbXCpKpdIYa zJICWRtJAvkEb~u+qM?k~c%my^A9ZwiguN8T%^T{yXfbR!rkmwPOzh1gH5xKa$5V?^ zH<~+A!?PQqDFhw@pHyFDs;*?dQPhOv zM*_)6Tnp1^>}M+rg}tT4h=x~#r?dIRL|$kJv{v#0{6rZZ>5`5)O?B2blZ4NYFREXR zkkLx|Hl0;9~!=rvctAacH&{^Mgt4iW+oD4WBr@Vkz&SRG!xQ<*psES zl-DbhpU+m(k4Hg=uWEc~iXo)N00X6yCJVT8IN-{1eG*4jXORC}MA<^><&WWGs>Fb)dubXwKrqstUtMnQPuuyUra zze-*Phmu8pD2S=!oo@mA%HFNp`gmg6^$dfOvVQbg;!Ce39ZDuSB0wtGR}X59clMm+ zZwE9u77DO(6!vK!cg#NO5)0B__I$ROqtDU%#X&B-@7e4n&O@cP&m%)K&0yZ5%VDAL z)Mth{@7yZN^q-^z4;d1-OyCT*lme;%GmIysq0&!&CJ@QqZHli_i| z72#ku&|UN~L4Tq>SYc&`mTM{X58)0eo+L>*ogjy@WPVh9e_2z8EJy7iWftj%iw)ng zP19UbcKi+iXL-l59&xw|akMD@nx-eq*5uVJ|1XE4d0o9Jhi(;yZ#>CaTUw@$A zJ`j1*TVZ4_RzG+AI(7AXRgZYCD+%TW5d-26czmTo|Sk@AK>@&X;F(e;p%6!6j{h%mbJP*pEN=ac~( zC*gFjFE&YCr!&pnwmsy5CW2xl0a8hHPx>w2aiH^CLWIp}Ys?U$iuoc~N{N>Fj zuT0+!;YRuG7V)L`FyYUU_c(v>^!P^jS!l(^3`!&#Fq>pq&wCQ4re{&g!@+y7qNQga zM8VNs=1Tye6||95#-ymEZKii-fyI#x?&*VDpPzow_rk|< zfUiK8e;Uz;yPn`tyN9Io!8CCHz?m4ab1SnICn`r7_1QY{hbr;o>O2bUsbb{$e)0aC zqVF=Vi^S<(?$aV-3k~Cw^i@hcNyFXo8O zC+lsJT&?NmA2Nur;{9;g`0|wk*p;YW!i3<$vfaYW@6pQz;fDGgP7KPk$ahZOb3#J{ zuhtk(Q&G1aQb2Aoa|DX(;;A&A4xwy6z1vHP$0nJT2l9-&-@A9493>ux_%t>%M7F1(_Ibl%4wO{QPJFU#1U;Whi;sXm@P>@_v?79um zxqSmKBn*$}<4@>uw#bxIj%miUEWlUOZ&UM9OZq40EDqPVv?&BV{gRN?Jd6|d%SAoN zy>$aP!bB58PKuvdTJqR^)n?p5_@tAlBShy`zPI2P(*MpCv)9se%k6mHr$oDuqLi*! zi^jrq#9tMO1Sb5Y?w8#DZx5a!Ff(hQIa++6r5^K7<~IqklJkToh$Tr%ZvK|XfMY$J zHtV)h|0(5sH}%B7Lems0G5ZGxUnU;p65eui5Y%V$t56IN zu4}=|6dF5tvDPTkdn!NfbtApp-_Ll~FzGi#N}Zr_AddoW)Jsxv5UPQhrtj6x701hG zoTn?5;%40U?)dn4cJ?#MJZU(XG!#S&6X6VjoN`wzrjxWtTvlV-2YXkQ0nZ<#yOq$5 z;p9WqX4cJm{3}j_@Xo8*q6bfqgdQW2ClAvMV3Spo z<uIgeDoqS8m*+F{7;etXPVld^$p;iSowuD zo|M|3vb}qzi@6ryp}m%&%QNfZ+EM4XeGX+aC_N@BseojX?$>Xmlwi+XI@0T*Pk=mA z0i}a=0*>VKv7x2QEJ1cv|+%E@&DeI0!z;%0)FL5JZ*A zVp5oo6gy>P@P6oTWi1gJQIo#uWf~VBeK9MG8Dsi3&P<|^ae2&-yr8_UMRm^9kBj^) zMd0z@7iIa}rIhT!ACj<(DI#=yr;fI})FRhZ#q#An>>C!aBV z8_eXU3cpwKRh;6Ol=7oK^(4!kgao6E6dyLC4lbRZpl98os4IV20o}$)pU^f%9FQ9o z7M8V$YAu^zR4mEBEC766YJ1fJ9*YDZ83LGtBe}u)4g)G6BvI5%;3f5n*sdx}`_KFy z3V5u}lu?rNv%RkB{wO&pH}hbi4nsoDm-z~A%xE>*osG@XviHv16GgiTgQi`BJWr5HiIjN=q`IfrMa1y2w8$SWBgC#E^JgJwJSO&$b_kX!6C{2>~okKFx;w+$rk621hr_#`qV(dnpP+XhpdLa+$RXr^*jz2^dUzt zJ3v1qZiNyN<8kuHCx-7W-RsS3ME1bGX@<2HNN~fFciR&vN~mKW6-Qo^jF#?_ch>la9t6I}(e3PJlxi)K2cE zk-gm9_>z-(+PVp+VreYPC{B)|pG#hF%3}`tQXiTlmhY5Q-`j#2V@7nTQBv!u;?s;wC=l_0*lu6ioP|D9J=(#`=wx91bY-V$im4ZsB}eV_3`Op=fm-K{mHQpEk~3AZM(DYc=Gi&o_*`z z)=g4hqYu!6dWUE4nAGvrZYHNF(WlpxuthJrQ`{L@x!E`_WJza~ z{3DRhWwkSe1}~0X?d1!PTtZP6o1?AaNADZw2e@l_q`ic>1L zvUwz)UktJ6LJjp{Q=C20Y3!R;1&ZP4Q^=VF*8YMwGtUQ#^rRhIc+QUT4V(_zs9Y0S zEX-7~)$7mN5~DR@-G!Jfrqo}IH7{eTiRD2zY)(uN?upVCetZt#2|X1S@lS(qdHD_T zxLEx~IfMLL#aelKga?GL!!D>W?KXHk^>{iO)7Uo{x*5)Cq#-%;1@r7=ce&DwHco(% zA-0&a%;`HVI&1!Td**F~maLQlVbFA@WyO))ugkG*G<6dTaziiiXDX}$w`>xv4|B!m zE&D%iH2HrnMk?~>sc?2(5=mor!(>@L-r**-5CbCgtOy^k_W{ z^YC&(%nH%nmg7tBKO1feBYRAlDydQK6;|uGv>NJ}i12j3hn%OXTHa-x!9qL zo_Z`Q6*`-R2w0HvDc1WJ5DX^^| zy&k+^CZq)y!3~YTPQdW(!L2wM@O2tnQ&71oW2J>~o6cB6qtT-C*)~mnSM}BRX)T|E z<%dR52MTNpId(^pcW-AD(cOiPXA8galr}bfd!|IeqUg4#b66b}yb>dkZqievhu7n53&1;%_A-Zv7y>!A4HD%8+;KZA z=+{rcl02Hlz?zX-WJKXSg&#sJSi_kyge!;i=U1r4KvjwPj+1w}+B?l^QBq-xi83cQ zq;uP4GUz_D8n2)d$2&^6NUKj|0RkuR#*!n8yxkrR)-)Q zBZme29gmu7FcVoa-Shg`Qqs-sU0j#NHTpp7xN0+I&UiKsnl)c+KAPFH!-Hg%70f0` zSnAA-Y#evl&JtCneP?rtQIzGR-Dt`m=@*ywG1!iyA|FYqiA-$tMYSkO%Ej&dK!@Ql zQ+m&FvqRdX&~n@45DXuLvlLRRSkVDdRfaSAOA$lU2JQJ07(obWtgA*h40yCkgk zeR@qCVX|Q!EdtU#L#-y-tldJN%&RYYtu7F}GR1V7fKN}>eF@%-%SmDbHgR!LkJ`aY z!ReQv8$wj_TnyK9Q?>}Ba?PqTuqxg-%D0*qf?obe8t%p10NPAvhdFh#>+aH!j}PzJssJbXG|Gm_!1Ix>TX77(;W)hy(#R3yCui^8b^$|%lM>| zEZjT8#yCJq(w;v52??dKX%P`19m9NC$&BM9i&P5G)f|( zXtRvJq6Mv7m4MGUm}*>fu|rS{d?mcH5{m~7>V@uj4A zZ9ANzf{6wm#@Eyj??z`k(7HINhaM!YGgtmOW|M-0DfO%3gIz0x6Da>zAD%CTbv8$E zvE;}PMynp!lAk7951A-4PZb;qc9I(UqFK(WfB#lhJU@SsPL{yeRFBTc#j!S)9A~&9 zof31^)6iN_`Q7MZ!9h2OnRpDXy2-xN=&(dfQiH`Ji#8XUm`ho+86~mo3_5B~f_7*T zZ0G?vX(zsUdKevKr#SKxS!gtbLg=?*^wN0GqcNRO8XILz!JNQUcCYeFKRsa?pf`7A z=_HYGw6z$?&NhJyP&OrY+k2qI`;eTCJl%9k@GFvHJ`cr73vmP*5n7=aGAaS7t4m4| zevVX>IkO-mRkm?dzadNcc<0%N-EuCyu?Rm8rzfW`_#qiwd?)z_i# zJbKWwlSvJ;b(JHn0YL_QgkWx8UFM4VicxG8HH=dR7OdJpPhb6x{fdg8;-a70LOMP1ZT;D@bF6YBkAJqIJbSPEn`?3HkOxK*uX7)5jLeSF09_HdsNe zu5*mh5A==|5-s`L$rmb@&1PCzqwPRMgHsd{q!KBG%XYs4|0?CtH1A3+QD!Lb^w6Ch zMUwbcHxcHZuQB}hz;}LC1O8q+Wtg?SQA8Xy4VLbwF%;097GdtEqi4`zz_W|Mb3Cr{ zh04+r=RMWkOMeyf3OjtQVmj|IKLde)r(v89-}>~8^}no#v?9Pc%{!2eF>-ZRsh^Sa z>ErNh&0c+rseWK6aGVZ1UTf4hVMMZZ)@c>o+HFZ&J|0}(wD+k#Dh^_Y)XrNFHKJL} z4SYO(bm3*&I^xLtvnc#|bjbySK(&DCHD1(_RGREZPk!J;cx8AiVb;PaQN|TqjcS|P z)XI-Z6f`5ERr|@13M+LG`g2#}F+C5JblZ93L>8l#XSbp%izUnQ^COcE-!SoEH zc)pKs+xWJgjg(F@=xQ?6=?#9x#^h?L8hMO=<>lNmE-I#rh6w(&OXxzJB>sFz!c#Mx zyMa=nQui%s7Az?|dh=ofFF2-lvyi{vVXZfu%xJ^>I!lrBY7SM&K#cPY{e!J|9`xJ* z%z!>4cp!ePxN~4o5nWLJqlYA?Qns$kZ^hvxIFV6wQCeI#8eCUXzjGbqX}_Ku{y-%H z(^9>p-s)&1}cH-2N%Nx!2x0{vJ+68mGpnC7wFVth!E zpHApGqGo~OrzfatWO66w8#=jsVI|2QkhLc{%-4udCI; z);^8f4w~Uwvh(sN13kP|=1m61MC1wo=CK5zttjHGdVeu|ol||3PRfiW)=s-VM9m%E zUgS8FhNjhJzrk9SO@>Wre^I}}CPy|FoK)nodOLk2vbc{{gcI#X80^kvspifOOVUnt z{JghWC#!d`9j&-(F;m-P7VcMeZukjNw&|Q9IF&ph@d3DH`->90PZ9isH-*I*c!VCA zdu^_hvwwbwmd%)(l}rcp()+H32iiB;(~i|GZICB7al_BYdxF+pq&zIZg*+ zotUWmWxbkMDBuUmxjMPV!z3b2s^vYpV}`lfvekM_$L-7McgH^t6S!6#IeBU?YXdFn z2e_-vbk8dvznHOJ89Mn=Jk4A=AOHP4WjLG$JppMrzNz; z4ou5yYmvv<^pinN26XX-G{v6Ep$mN-9X26$IIOrt_C z)5Cg%E%*e;Iq=?OPvpLVmHmF#SD!uR){*K+nTf%kQNEW&i!fOj2!B}Jfhh??;_%qe z+0MHjLLurM+_72JNo4OwR1NA)Y>qi|D(>{o%(=z)(o!!i#wW(qFJ4vdx3C!OcKN40 zXag2jbS}i1G9Em&tWa)3Iy<05sEHYss210bEhBHQBy%TN2^CCknSTX<>8M{gTzK3G zw*Y_%=%Yci=|AdaUK3ElMu=R-`uvIB_zAjvgd{a0i5#c(#vSI)& zrD|~y^-vwnWzEw1_MG@MfOweRb!HikBi9vtwDKFm z0oa0J8LUjrtIn9O2qHgT6sy20Dvm#OW1ysd@0E!XAY39LAqc-AR%QAn3op=YNV%vW zb|RCcdZU~=Pp-(rtD>t6!(U2S4nSyoMTAY_SsvviG8&&npc4tKTOQ%OUfq>qOW@o%S7#?1s ztno4&0vJh1d1U=pVai!+LfcS^kKQ*{XTd=Uf;f0X0~27y zO$4_H6P_zs_l%}31AW@zU##*FPH8B~v?@I_y~Xn}{v^F^lKD2j<5u5-Gdox1u!~dp zxK05g{o+-0dJ~D4Y7OBFe9C#_?0(wXB=LDIrb8NPym6SQ7o^xM%(`tPfu6*C3+Fh} zJ>NS;=2pU=cX>9r%f`gmhnE7`j(22JhkAHPd!lM-{TITm{HZ1L^7u5scsxtNQO9P; zmF8qkc)xpFje1yql|<_cZ-2l*ZpLv{#j&d1gEXWzR5jaWvh-=QX18ac7pN1g4kn2! zwP_61sAtb;^pftC{tBal;+}ArIW5!nXY8PFbCtW`-Mz3boLAem@k+zF`c5Qz#vgjupTeUWe^76S&J|cK4)gcvd z8Tk@{-G`(FlJdw8l21!Z6*f1=&yW-ZS}OAfV&ou((--7qOwslpcg+|E$D=}B9rAK} zs%442{oXDbIjmOO@4=t+ZpODh+mQJYq-Uyjm};Nk?vn;2;aQfqk#8}6m>h0-`69QJ zxt>}GO53cYdaX+8duIh6@{l7ZMlUV#C&WmdfS!}0L}6nMn83%m8Zj_7WtWV^Oj*EG zl!B#pb&b;#v0j14PkS&1m^W0^)UpyS5tmZO9)Le-@9y&m^s!*3VcQGqj0OZ(pb--_ zda0P0Aj~7rzXyFyMC_Ap!!o*gp0QTjY#$<%;keDmBiWbzXM;>Pg> z!vIk^vnPpsNPG}vOkE6(P`Ql)M!ZA5O3)5!?-FBs`4k_wd03hV(UgoweSGBbvVII6 zvNxGu^I0;v(m})EC$cwX$qg8`4f9k8gZ1oHP_Yb&)ug5=@RAz-(gnh_sFEb z9FuP#N0f8NwLSBx8B7_j4Sw|p{V*ty2{!mf+%Az&9 zz}l#>SCO44t-@BrM;ZTx^Veo>GLOvG^hRyxc!jk$aYfw8q_bs0-x`4(73eHkrHwwJ zgd`s^-|NuX<#j`-HfCP% zSS6!!7`fTJ(Ns|;dB#qlyFXPNl_yRj6Z&HB^zc&1Zk}je|$a`bv2fpPG#J$#wV_DCGxRAuhfdi(-vSxODc!RE>-w3^|E5Tf;>Z(e0cU_w&O+7a; zRTm~CYYtisD#3FkVQp!P{uUJaA(J^V-9wbbuPP85K_k&VVTSGCbG{;6-q;47k>!XpUp?g%Ay5Rxp$4eB;wD1^kr5H> z9i(c?0zIa2d92oA`plAx-aJ==UQ!$0 zBnx7uqu6FJ9r8owT3iYJ_FDM@LyF$?vZ!d*$>D>?9_c?&d=My#>dl4y!k%5FJ*|u) zUC1GP9wa;1zV5i=CJIXvRuT5YD)RlJnvqHE7q^CqR+1hA%Wpp2`)JF@t4*9fxIu50 z+l2jLOZa(y5RI9LQxfk@H?kl(tc_J{egQtP=(m$9e~NC&LP9As1@-+BLJq;jmB)9B zoGfB`QWzeWByk5q1e*7VpRZ*G2^S*zyJIrWDlK6us&;vGh?D%-SXOq5mhMM(pRvzH z&E0c&kzURNw(?tB1f6ckS_)$iE8NGD&X%}mlUMcG`a1no_xk*)dcf9 zg;Z>tT6!+gOf?&qT5#AG#FUV3vir4$*8&5rm#SE(cYKzF7Tx&}nqj>1qZ{Nt4~ma( zXA_NYzn%g%yX%2M%HvMW{W5IbflyjcYvD;uc2>E5h#_LW_!HXs~5IkjC>&Ya3S2yY>!8b^{@y)RluPqSM z%XGdzY)}DgE9<#9X~vbw?jsMeV=2@g0#=4ii@ZpOgeZD*{r6S8)Kt-Y3)8QW6%I8s zHgZ<`8duiP#)q;kO~+YTJNj&-J`a5im#sQohl|k?Z_JT8iHv!QOz8V4Kum_VQihaX zRle1pJJHSJv_~UC<%MJ_hONRUV;;U&Uj+*~-?|szNXsw&RuK8~X4-{-y271;Tk6Kz%ei8|-P|1is$bZ%KXW3srd(W&C$OE< z3Nn{}q^=I7Q)aowQOW~yE0(0e0_#(q=AopW(hqFG3)%1fazzi1kKc2b=I)AG>)Y7_{gO6?3cB72pXpKhU_)W|Iy2RSZd*VX z>#hRi=!aU_fYtV|j9Ggf`~{#uMqO8dYNL_{Rs=U zAF#JXSglkgITlvsmS+|^?zF1zQKhH}sG7Gvp-^N{Ik|$#9F;z2=&DOL*o+zniqU1x zj*W!%xlP8#jQA;}eD51Mf#w$x+{^UanmJEhdZ9LxjuKNjMutE@P_RSCtf%LN_Q<|A z8(8xY_->Oy6~#r7ij|EP-n_s|D^K0Fh9j4^_sOsz3zVPu^StOZjvTBfR)Xj=0nb~4 z$MsP!9m2C4U0eGW@z%;61ra&knM^-^OulO`a5bO*Y9`m8`OVVoyAX7Ahvs0p)$c6k z?sZnxV3Ad}KrE=ISs|HJ)tF!3uq$FsXW_OyMG|7b*HWZE1Sw z3feQa>;Cj;R|XE7ok!(46p&q5{xYknN8|?||YY@9?>qo$>Y!M)h>jl`iMpa;(b z%1&9H;Lu;{(3_Wdy)H$pbl!{;SKL~$06f9#FY<1Bgc!&7&Fcw$)e!ZnB5mcC)H8O< zVEm3Vo?TH!6lpEl(LiuWuW_KF@u1|1ij?$;7DkHlmK{na7WGboQDaa;6HTo{R>NtV zl{k9~>MGawg&sy>5Z_IiyzDw{J!GrP%>6Leo?LHlgyoizSvTi|F})p*j6)oIBwx^= zMa`>>D+!%8`J3Ax<@liY1|vnqhv7bE(-xEyHI05|B2ajH!P zt|qmRPVVa-9xWJ{s@F|LzI`#rn?V3c+?1~{7hpS2Lz6r9jSHF{g#hDJsu$g*}>2GCWf5hexE3Ii#yMqd@4R3C2oQMd#~3O35CpbQbCyJx%`QDy3-sxIk^dTio9XgoM;4en4xrG zHBljIjJ+A?muV}`_~O&HrA>Gh2(}p*pCkK3kj5P8Y9}{AdOdQ`e1Lp_1h9EAw#gk& z0iaOnS(k-;#Ko!#;WoRSn2|L|4&bc(wmM|`1=rDJGd^AY<5a2Z1Pf!1Y#~k!7ZcMe zIA7V?S%{bKo5ki#VsyZ1ercHg<9$hVCMjT5V4A$wzM?ezrF;$Fs9y2PD7j<$!-0 z(A@hD89hLzy^nm*>1#w+M7If5K7F)=3JsQaz<`$)Qqw$D;*Stcrl9oK@qXjCjl@=;AU3k;$rM?f)Efs3YSt&P7|UtCX35{_cad)k~{SM>4RAiWC-U%c{zOH;q(Lb2T7-*l#L<^KL3&q<7esqFrXk^;}vyl zuq|cksIuIYi=L%a;;PWaGc1SlFHzW6*gI z(t7I{H9p$6F`a@YY$Kgs4s;vup|l7*u;u_O&Tm)<%RmfS99_`3Laq|YcMpJsmUh}h zbbWhn`)%3GKsYy<*x@4gIBV@~l+pL0HrTKvZo6Q7toZ&FB{7$3XTG9`Cj#IZBx!6! zZBWfEruzJ+tcSS4`%wP+Utu0F3>Z!X<9uYT*!yrV z^TBIEURrR6@(cqf`M0yHeoI15FI=jD?ojF}C`#Vmr`ps%est0kKt~X~x(JHF!XO~> z+j}teR8gdJEaEVMXZCHojfnx$Sfq%N*Tynz7`6_|>kH(4v=lBqYD<7BNutGeUYM20 zD~didmYj;vw1F0XnY2b0=AeTELOUyc^Nqc3O)w)P%vBeH=`AEWzKoZ0_AkrqVx7^# z<~$tNP=N4KnGl5O-j4$6^X4cb-57T)E&64M)>QCIHr`dgvArP3$$RFhXus_jFB#b2 zRIZw%qw<9>=TOho{_1_J39!yrsqamzgT<(jz7N6((@TNQ5{!>m_6zPf4G!yiAy=h+N6*gL?`3H3TPcwdP}+z*KHHA`gVq{U*~l@XsprO*qd? zsWdMupfSGd(j9td_4G@3Q>Z*=W=7Kco*5~99usJ6i0ZrUMh`T0LbY}H2AsUoZ4y^c z3d*Dnn&(G`JVXjGQ?V38LGyV;eSz}!62Yq}0~_;Ui;|g$S&pKFdZH*r4PuBLz0}lK z16qNRuQ}Z*oX7Ai1rnHVvrE4&FVENx?xpO$!VFb68bF+DWJ%#L=QBp;HuPBQ@;;>v zic=Wo8}%#Q57gEuQgpL#d08?mRgCuTC=@3W*f^GuHrSNVj~A``CMbVujU*N>X`TI* zuUc(c{M?ioYEz6^O82|Tkbaly&r&6^h?y7@UFeHBIl4LUwL_-_eLM2pri2-jkH@qm zg_jr-fExBSvOCRI(3bet5bUq$)F53vZS*!5oIiV-LDj8D)ImME$Oo54IO)JF8X4}T zK$$mvK9cUTv{mNH6ZSlpp&*QSqI_nDm?vgrdcMi*9a9(58eG|zASKi43&I(XD1L^| z1=ZgS>!6kbrL#1qML_W$s1NRwX~eLKh^X-l_4LaRy1MN8!un*&5GezlPYd%z?@x4>%+MnnKFDcYYI;t79TI!#SFnERo0BgjqlvUZ|DBrUiu;9y z6A|_SxP|-)AF8qYkZuU{v3Au+LT`Xo&Wm-g7wFV{L{8QLYB@`RNHJ=m0~W~^;`Oo2 z*6j@tsRrU2V@HfujT*h(UiK#L(F z_jwwu;O+gejb%rXsbq0Emeo^0&m0wTIc25XWzP!Lt~Dx;VlcHdjf3aa=8<5n8^Qe7 z+&zcl4iudNgJ6#@)|Sxc17g8GS70WupyQr8*EYeSq7e8DiNYaZCOT&JF|;8Ezuv$# zdp<%_kQuGp>tz0NlWx`8O~}$3f{lRcHTw|vWh^X^oG*nAo|((IUkp>j6vLU6$^IkM z2C~b-i;xDxlW0>5QQt81tTs_JwuX38&H5jYR_MFDDdI$Ai|Nas_$BN5@J3qjdhvf- z1@onY2?9Sw%Zk)RX=5eCm4ZX}&uyo#p75v<>7fTl|3s*MAaDGN419SG)>2KIATyZO zgJTRAV^u6a*In>&i`YO1|C-~p|69G-N_+<&IBX<4asZONCj%w-kUAEIWx8z%Z)-Qk z)N!dn3%qcU94B+CGg}>8VfRr2!hSO&z1ect7v2o}_;v5im=0MT zo9h`KptWuW5rgLA*^!FSQM0kJGSjnwrk>uc&GKvQn~~3oCU)iqq%u|pmY^xGO11_z z;kE!N9ZP#1bFzE5*C02zzkzOqmIloe2EnrZ95#GCmJb9=Pff?jNYB7X1{woC^|b5%p$KT~c;3`l=xzuPI{ zxAL&w%*woxhY_G8D<}<6vNX}V_M<$|-VQX(7rmIJ9g`^mmF=-D%E3 ze>?H|#uK;3yc350Z()>dL6fHMi*k*7PZVa>+a-U+@V(Hwb@p$;7}!{tS?>g6_~ntG z)3Wa(g!Lv3ZscMBh4!@zfS@?HwV(t5Z7pn#0XmlY*Z;Buh3tI+e-CiHO)?g`o1pj= zGPnM|i~SpM?+HlvD`cn`ZzW`*`!i}8K#seS=RWxFaXx>e{a&9Dlnb<`nipUKUswyAZBR` z8gOl{V|SgMp!C1x8Ce}Yvwx!ETA07`;MRwC0^K0}DG)OQC=71&22sv^IFNB{46N-z z%m8xmeG~sCvpW)H`zru%k^jJAWMrkgQ=aNq%(2~%xj!92PyI{(>(H|^Hn>w?0cdFF z2nzN4Lj5MeJE1^>YwsuM&GL8V_><><@)SKI+b{q8mhhJBZv1o0(l;if1IRcS*f^LN zINq1!8uo8b-1zk_-v0@W>#^^5o}dGHLc+lLn(Orptn6%m=9!{_jm3R0fWCkEzhM3} zJ3TAI??Au7y_Fsm=z<2Igw{8()HC_Z#Xt4@ONYP0`$nT1C{Ql`U0`m4?FNcZ7ewJ8 z51RaEZDjk+XTMU3^}fAsd~i=KCgxvi-TL`XE&5+o^8X`ceg^GdO5Ud9oumGa5k?kP z)<06_pQHh$sU2t@JSbHa>_GIWW1|m{G5{s8CC~{V#(({yo*6(8RAy~VbU{@OX!(~< z|BJl-PFqkSvC;lgp6ySb2IUOMtI|MADiCknz$^2~iUDq>+TUXnO;Tx~9ROr-yK8BG z3HhgNnq>Fl`X|!=ZLXVa{_Q7_xmf-X^@b#F{B$iU{e4ld*$rf*|9^!2O^0`Mz;_#x9kjTtn|ODH``s6WV?yXyT0X5l^8$@{j7}l&Grvlve4bK-d(xAEkHMt zu+aYPa3(r>*58u+u7-bl9)x{e4}aEWpw)jw*0tDwIqw$s4|g%r)BnL1_p2>EHQRM! z8JZZ`+gua!b?BJ<1OjN1DogT7+x{Id|G|UzG-bZEQSd%Ir~=&hmWB4FBmWK00+6ydx4Ykz z$^y+z^qc`ypxS9?U}OWT)YqNrubsd@*9%!1nOOcM=(_Q-{?#-8r+7Md;@x%D|0UFakn&$b{kdVeuAhu_3@pEzDi+$mGJ~24ASosY z(6O~OF|xF{-fG>*_Ghl#+;ro!yUvmJ|IU>g)&H~%>vaU(Y&L%N87#CnxpHT)Kl_Yp zgE0aGb?kHiQb2u!d;2z)pXm34=uWfSY^A%=^G^wAuYL17Y(TaF@agFpfHc4DV}66( z_SIsb8f<4`XkuV4xO~^7JjU{ts5X@!210Gca72!COx= z-R%)*Z<6|!pKm$;w^;N5e$ZzK`q!S&xvn%OdH~SI{aQQ_i;03tH4vZzv@zGe&t)vM z|I+6jPv6DCKat4F%=W9NyAHCOW&uQ*Hzc70>ga7Pt~uF2@8152<);dNd;RaCzz7PC z-{zH0fxW z|6uqV68s&;j3D&ioFa3R-uE@WzU4k9^KCZVMeIKz1!{RfA@v*OdMBb_aN|n_pvCnD z?4Qnph3;DP{|5T)KTr$9_FEmgzxkIA6g7O;OmUMM*L%I6M?iN4>et!KeHH(Uv~HBT zQ}G|Ova-?rku`sl7Tt9m-72gI5<(Ja1OQF`y^>)r2d`MGWX z{|2v97F1OH7YvoyNryPp^S_u6+x{F`~0 z=-IAMt!|BYtLbmW7yv?+4kk9ho904U$HwIP(DZ&i{dv>>iF&KRZ~Z_9ygrA$bKOmi z`i*+Cg}F27zc&1NNccD6jg#(N_IF`rqGe+P9XQ`$fD-*@`*4#R*V{{D8=$?B@$Fg2 zeVbmd^xs&&^H9Bf zB4;|3eQtzhKp(QLxvwyS`o0#L|q0kCT%|NnVW9*bel( z0S%3#qa(G&?M|Lr4`=}(qfxkipPQS8A84a*U;{D%=&u&dPXT@!;I{<7{UQJ~2ihoD z>F61NmKU&P1|7xUj0p#=BMj0V^s1sF{q?K26sgE~eOiALFp7%I06LbRdV(&OwE^mZ zxJrXYR#2Em5%eK~7LAaTod~E5+FdU$qCj`O%+Gk`2K_+*9rS>FhVZ*ANE%og*%<@q z=or~({vB`r=T!1!WeeamGxCp}7cF65mFb8&#xqI7S!ZH(wEYEJXtUeW*$S7WVjoeM zL^hSXm%G<;$VV=>(ghKFoZ5`e*dnEItbaYH5L2GnDvnP<^CgKydu9|1EdhDa8QAZ9 zfg=7jd!i3gtsfGTpH!Z5sn1NFb70NjFhTS!B*l+J11}AlK(sO)++3hN1n(8~HTt;`g^M~ZI=y9>qa-ZtTt1Nyg3;mQu+A&713FHedX#Z{ zl=)Nt-h(nf=ojg>6}E+Qnc@+t~9ekcb*x+0>7&ZssF8wuA$1ai)CKNu$q=Xm%4t>Ftx(J0hm-AFG6C$oBN z)p-P%orSRMs#gt!p&9dNB^!3F1pzuPV3rSMMh)CsTP|f@3z|g*f1KzZsoHkTTU{S1 zW1A#2k$GCaik-)|@?^megVzBpW%&OQ_m*K*Ze80j-JK#GQqpVDDczkSA>Ae2jiiD| zcL^x1bccYHbcb|zhrCPJ?(MzzdY;?;zQ^%>|KM0K$DHRH^PFRxW6bM%6cM&|%rwM6 ze&vaN6z^Lu@)B)rf~3dZ3F5pKemBL-Z=x9gwwv_mboj`*p|+03b}ofs6@N{%-pj*T zV7}xt%Q_%pblqX##jP?oeLBu1vmXQlU}o49?zLG&5Fyt2C&i#axG;HadBtJlH|k2m zWGzCE6<;*r&yMWSGme+Syf_Pc29$|nQrKEjgUoLam0)uEd$epAFjqR!%~rglX{ zt6sa;FRJ47)Xhj(KCv`3RP(k=G=+*f&`%sdH{!{lnu~?HCwP*X{2sO@xQjt0?0Z{= z0M!o0t4t#$4s>HLm{$)Eh=iVJp3dgzND5|k=?L4;F_Chpy-@J>p19Vs)&t0eDn~(j zZWiN9P^{^_L$u6TzN-{e+5mx+VwUO$mb|$W*>pB*O zGUD??0+I=*B1`WM1@0;N)zn8lOb%pHRaX0sg`BCiZA(j(0Lan<*wg2)h*6K%X&rnc zwTEdMtvDqT#wm~B&pE!ji#KM%u~whhj3*IQQhSQIUOrT}n`a$q^sEm&ZQMh4_{xhr zt=mDGZ*tCoDS$@$0FlYss26Iq2G5)zfT(rr8fH&u1NElZ6Dk4%vv%hBOYVB=Qxb*N zxrXmIXa=hozjBoY@>f!6?YDf(J`$@*ywY2i*DC%bHW z9P(*Jh*N6TTye6I&dHcL-&><&!Z!4Lq3IE+Tbn|M;j_I=x9Qi^7LKn`b9r2)LVOIrVVGdFlq+iaj*4S6mCRYl9yMt^I9bAkUpji%f2ITf09GK6-j|~Dpq4z z;*1${RHAx0_a^%*q_%z(&)X+GW2*1SA50*dr#(hR2IQU!Lc&2%o_R@vs{sEMZ~m{R z&mDo1-9>n0cPvPD7f_Jh=N2H^1M#&o8SC9aM0TGwlif#VWOpGg=(GDF?&3YrZ})@T z*PzJm;{>w%D1_|(7$v)}?EN?je+$( zxMO%S!2KwI`%wV*qX6zl0o;!QxE}?0KML@E6yW`efcK*S??(aNj{>|O1$aLS@O~8F z{V44Bqp;tP!hSyr``swu&v1^rp+U#yf1Kffzs_*>JEP41<`8GU8}t4U{m)bU$IS0z zj=xTEP5?;j`gw|T0=bxge>=qg^Ju;gf&f2C`mA>m){n#fZ%6eHWd31>1(d%3X@-@Z ziQ{+dfa12FHGD93en9_sI~?3BptSBjCgEiHv9#Y>&Yz_haG}SK@Ae;dI60X>KKe)S z!^O?S!SNf0ekqZGGxUp;@Yff_!2$X&j-Qq|IezO4`e6w0M?nk>a=)ktzZhZ%Wj22< z2^8W1{vOYPbA>xgK(-&HB(O{Ru?PME9)JrJEdE>)I}6i~DD*!f$N$CBk6Ij9OFy>R zKP<7`g}HxxO#sf{bGy4W-B+5yTKciU{$U9e4gZB68}MJC$9-Qy2KPPv*!_RE#LmtA z3wo@e{P6eDyDK1rT@yHNVCUla%k|i~e~%k}fcLY+2X0B=*nyoBls)`(J$5ek-v{rH z>KNE1f#U~u4wk>bW9I}(ZNCfNA0oi5;%qca)21(CwL&g{WswKsMmru1dbqp>>z^p>3Kj7u73gEeLWVeC2$M@1pd$$ z{x~v#?Cie}9`FxE7M$mSV+bGs#1Mai2Lv(1Z+af^UZ4cKBya=)Waaz?JT~s%2M>6! zz=E@M7Y+Y?GXYsZ1o0<$te_C$cS-LL%^9pEa0CJ11`))c;DKVk-v;l#5(U-}xDW!s z3F3#Jo(C#o{TuM^Yf51J;Vx_VJ9q#N5JCI|4*&}Lej7aCef0zEn!phRfE`2-Kfwcl z!oJ@I@4m7F)(|*;0Ac+Lc%ZQFwig$ z`Fx6%_OR z3&*>!_<>s!IDTMd{UyNw;qh<4`=9pGoznNql2}o4{;Uc`GJy&|Mr-C1_zaRa12 zB=0zWjuoQCKyfYuO*qLCr$udmOOI{Nsv}Rq8sald@coSMV)SYmo&%`+Em_e`!TWV^ z8I4gs#jW75kNliG&3=)bSWG?(ptapRA%_Af7fX)SEkTpfo+8xxLCpnK?+k@!Qu}@Z zT6V&C7E8HSTyEXgN0{4g+HL%n5@OqrsJW2&46&HJOXfb8xU(AD-WkIzZ+LK@#08ao zl9nBy@g-;(TW5>FYV+2^Lq48yN7f5ib5rxdRuKd|M|uXs#qROJ;!K{OIXn&llJKM7 z?B%?^i||u6ymdG<;+5wH5+6L`&75)a_9bA>pMHcBrqpQMbcX{hQv z-d7+sv}Hz&8&%K;#zdp!N@g(v9jT_tw8UdtB@&TX`}VH6V#zEvaQUPXFlNg_nm;0~ zduQk?AebPK11Yfdb7Xf`5sXM#T^A4>95hOJ2l?ZQs(ar%H8#t|Xi`HMRB=90nWYZ< zl;wU^oEG*OJ>pCiZ(tvJyP2A2NV%0IQ;wtC$_V=^`9z$~6ep%j`@N#UjPU7VqL2ML zo;S?YbrjK83-&fQebbJCW-;B_I_7s`6;}2-nL5&1#N6-md<>a-)i-Ba;kjNW%ub!+9;h#BAM9xw;*Hd~Idm{!pdb=I5i%sy0Ng+PGl7PnY7kUlE>tc+YLTkmt zLadWl5n{i+gd}0K9UgtJYmpLORw|4lzT~=%Op)j??00>%nkE=nSe>ElY9IEvV!qvN z(pk=}O1wW>+tL6<+nHk>^AyS{LvvS&@4VNTqy0F+4Jj0#)H3Y@6d5TxCnWmw?z*)L zqH`&}(o>5LYz*mRz4ExN_!yxdWZGnMpu5(km}E@E~%WUcF5?G=9|`-izxP6 z^X~HJ_Hw7zWR2&|%2;hx@XItIT|0&wz9g?7u7{C{5WcF0WOs!$a^6P@akZ*GzF1De zMV4uYy0GnX)9m6i@`c0TIHoSs_k~hTw(BR{C*rWf^6iYwhO4Kll=SZJWRPy=BDkS- zlH`W*bt(i1+c`T6Rxt)^p$?8R-R{;M%Lv=V?@&^kK~f^@MrAQpxC$vZrpUz3!OWzc zM+`iPbMsOz&|raO^JmdE*zL0Vz)`nH^J-SK+Q;>^JBxAX(IWXfxkVPZWSs|S>2*e> zx)2wrBkxwQqSkstHMwtQ7e%%|rHC2FbhmtLwysMqc=JTpBk1|GFj^J8(Br{i?U2lj z2iY^k(&-tmUJ!0ZxoY#jmD6F&?7>Vw%InQM%KX4kqw)F@qC(;!+9D?BO8pl)P8C!c z?A|1J9)d)x<5G=h5w9j0a;P&0uBmu@%;d>hTI?kOS(GGJa_G~Al5iisxsRGE8b5mW zT()T`onAp3ngp{;k*q^*(5dT-Tmu7{gz|*Uz&G)Su2A1P;dvTKNe|FIOayE^JF2aw$_XYM0yWo*&%s9`0QtlOI&c>R8iOxl=i`Pn1 zgTO7Vz>~djY?^Sl+1OdiJfwm}grn;TINnD4dfhWj0_X!r9c7y8eb#SFpG21vzVswo zaxit&!8RxfilBPv?YCv&-4-Wz+~B8Qx_|6mr`=`b5pb4J&5ulDDlC7T7*;R*DExBQ zl65OMZ;kABW5LstD*sjLCRxF7ImJUR_u7XCnO!BD!Ohsst@+nmBYRnf8CI&}Pvn+W z%+kXRI;tQy^^JKJori--Wp*sKC;blDLQ>j0Qcv6Mcj%gaEnZz?*Z03NHBU}%?4qL?*m=!Tb7dK($_=$(< zDa%#*n$GT2#pPTO)U27YfxaFtu~~g^3I=gJHcFu|dMXrEu-0JZqn)%MUla7Iv9ul% zqsNJK*Bj$fSk(0LRRYtIayCIs3t?k#(TxWc;of@UJ4X3kidaW{_Yt$zJhtfM_if4| zTg&Rxpo5=H$JO@Y3!4qZ+uIRQXu~#TmxO&96uy~By+T9hoV2NUd-6rjUYjPv>EPSq zv*m@slw{1^<1I1ntNtCyU}Mb!Xu9Q>9J5wc8?03uigcx)n988j!!5Vt5n0zu-s-U0 z9(wbKG`=_czE*u6Xj`IF5!Ht(-&nNDqODw_`+TS8LoVTPH6?eJrI0R`Yi*!+Ny>`# zcy_T)_E!;}m}a9|abZs_F2D7!1XkRzxaDW-4w3!?t-vvpqn$D1=E14yp?J;xDk{O; z7&_6)@(=E?aZ;(*L6xvK^4}11P8IvdQM0bggTI$uF>Qu44w$8VA!y0_oI`toFFl<( zTah|@Ag$)mcGhuq{cYJ$MuVDGyG*=~m|nZYtRIDcP^~WIP)*WUDPl-vvj5Sx;!4$x z&B(}%y5XuspWJ8rd>31-D|4qeE~gYjXhrQi>?_Jbv%=&>Maj6Q5t`2@2^rB#kEFj> ziU6dAR$()~`Ddq?ZVr5Y%J5O>J8rXY;W6ekP*tObO#qQg}6B#$d$xBGM>Mh2ME=yf?-d2KWl89Ft zHR?+$e#z#01y(Y`QVn0mCwv+^r!Amr=oNLRM^T$3COJMOeSv5i(D+m}+)WCF0`agD z${lQR|F1*~e0Bei_VoYgCgb>{O8sZ|82gXhM)}`Wo_{1>pa$O`G5CL0p4tCO$^Kis z`hVY+bvNVxh*1Gt|1CuIRF+d{V?k+H(>PBc+2o$z!1a6m+SzXgBgA}@Ls9Dyb&I!v z{BRT+?$d&@>$Ih_?c&{ZoNa|g>QFUlJe-`={Rvkx?~rCfB7vN4A$NQjk0+9%4~Lvz zW(6HTS~k2wL}FLlkQ)gUpjT{1Bu#MZaY__mvCf-$6m5Hg;r|(8OacWH;cf6M^=;~} z(=t5z*vP99!lp90%w)*+auq@^YcX(izJzNxEUUlJ?y)8&B)BmtVG1vKw=cuj<23E0 zwxiV3S0*S@m?c6pUC1%fwexMl#Y;^>)!}w3tuX$WhL-MoIu0zo~Spj%fQAlV(% zyb1V`;DXvb*+9j?|6W&+12Tc?hM;FHvoJ{-KmXAu5BhJWKX1%}&8zS5_|-fY3lnH( zfJXVztqDrnm_S#?I6!6Nf3$0YDZ1ZH001gwa{e^|Hl|-MK{DBzFx_9NX8L)h8vL~W zmV^U-)Tlt>CKnJir@NkwABDKzkV@{R#0u&^0sJ*30Mp&w`kxa~cwwz##ss>&$prf8 z?iM=uDgCA9{Wnqqb(H?uHwyZh3)DmUBLfF-TB{tFc;{yBHMq- zu46T{ZKt{Lya!4aC}BklX+vXy35>6)XD3mptyvGYW$IW|6DvQBcD$Ein)P9A{yxti z5)xxfrJsf-0gF?SZ09qSLfjUEAe`tN97zLK8UD~}-=T(E_t$9RT zNLq;*y6ju?BY@`M59q5m}F|Vl29JOdw`8qV_X_c3Ar5+8k_q4AJd<2(B=iFTH6m z->eG-PZpW0NV8uhaXLGBrwK-cSFnp)`W>SiEg8}akL)Khe_YCIeCLYR1ljIm>Cf1_ zw%@#J7%;QO;6B&68v82Q6ovW2x8@a6i0MgMfn@lhkc@WoFGkCc40}JTBAgarDAHdS z?uff~vXs23*%i5vW<$+w4jjVZdxa!B4q6$$w z6}rGbA4Q0UAZpe-od@yCDyBi}yNK!gthtxyeIc2bh1#b_1GY9yB_#>Br#p4;WwfCf z{KO21LP(`=F=A*b(!2QrCeC3H?G8Q>xR2R}_bDOgiE8#W%BSdErA*m@&VK*HE}}i4JO<0l3K&4#T)e{^ihh+9?;XI#62oGSkJpM zu!I)hlfmV}?=Puf!~{poqUk|uhbo?}6ChY9oz|MSXx9ZG2Z7$0dp;$avA$8%^<~k6 zqY1JC;y+m_P^?3E+)y$xf21G!X7gXSz#5k%ttaiyXZaXa5b;wBG zikPi_LV|r+Dt|hxfp4U+@aHOX1fK>mzptyq;LZvmHx7Di!3bPiZ8Nd3ud+Abpv9ck z>6Wz?D^9FyVK*Cxnzh&0Ft2CMWpMBWa6K-bPLG-){GxnD=Hkf8w~@t_Gx6Z`_Q`jM zrAJLLq8A*~lL*4=u+yLVbjr%3CEB6q%08I%rRrGjSt*|I2e6QqE-&>rl3{+EZNw63 z+9$qtnSr2}ZC+yTM{X3O@j437>a2`Tz6#;_DhLtBN42EI;+Eglgmc}-LN|A^N%7v?!|8H}3Bp?eZJn}sO3AVj_* zWe0IvPo%yOSx|a4btmm`=D1}ibk^?l7YMx>c$?5T3A1efMpON zVs;LSh0cBjy`Az~dPe7?>o8q`X6I%tb(^Hh2Z9CtT7xcDoFD7pn%k4O9mia*W$io> zU!~-UXImK}+qVN6`uL)g$$Q^^@9i_%Y-^RRysq7Kiaggtc`rO(Q@OK~pYgfG(i#hC zDaG2rAQ_=^$l~<|fHtdZ7nQ>I1g;E{ODL@Sr4IM3wdS-DBsntbPP3#y$j=$`rG(ItpmHchYj?_^P9Cz5FPi5Wo72xeiTS zH$N0=@&!d~R{D?^b@}u5I|b?H^QkY|`0)N^5<^!ibUT|QJ)&F<*t}MxpLU5(lvw*% zT6Og-K(B*({U|?&*uumF;%Q+d@e-MkC4yJ8cE-X^A3nV2bGf=Kf|d*n2&8k|Z5(IF zcTnz^pcm9YaWRqU&*^2`z~BRNO-3S5N7zT9;gs^(DSN&4iOZUm#wJQkf`xuy_DMb56lTe&Ww^1S1&ur` z3wkpZgypRKT1RbHq{ILklz{^yzuGDVk<;o0mz*X=+FS1GfJ008q^GRhPJ^q{S>tYk z5KA`QX@iu4XjVOxX4@m8tK~jC6faSEWyfjBIb>4^zmgfipz=W*E1=j3r#K?-R&?4w z3{X+^6&!*rBP!K}=~Av5aWN8%&SvaHekt9@kr)~56 z9#|+{K+$z{L-NU@X>BOrXOMB3HDcZ(1gYCSKvcAEw(YY%fa6}JQAF)~0B`I*`qjI~ zyN6_B(B{+j;_xTB#Plf>Lj~i!E}8rjO=US5sV7VyabN|BXE{D^rE$CM22O-{!($aZ zXm{r#6()q=`u-cCHOG;!{#atzXw4w_Ehv5=i zy!Lct?*l_^%uihT9}GEJcHZp{OhQp-Jfj?2qv+a28r;$VY3_{_|!|xE3jUnvQRI1aktz~ zPN1Xu5^gXT%qYwbtRoJ&4!xL&RuiuMembT!!N)&f_--@9U8g;Oi#y^x=W7*Z^No5H z&>eD@i=^Y(8tSr`*2u^QUPE{Y9O|Q54!O^*@}H?4sAu4?^U1$bS?tB)9~3zFR<+jb zOi&bwL&wo=?UAxEYzt1dpDU@xXkd{y%ZRech;Xw*&VyccGFtAJsHfk(t{H_dl5;Z^ zn_~d@DA^Cg6&ZDvM72}guA<~F`&6pIx1cC|ToF}fyWpYZ!o`+Uo$ z5PYdMgUil@Pc~PC>CO0j=alYypm&^qZYi_dfp4MEVfjZw0-M14;T~ef^-42!{pN{e zqXz=SF^sQ1&N0f7=FHRwL{Ar$hpc!FS}ZBH*IAf8Z-XR?nT&eRiV(iiBU$5RY0K{v zj|sz_;rG^l694VztRSfDL*+i@<&oilg@ zajg-Q0o2a+0@EHE)>8UM}%Ih303}CLlSe)lwIkY@;1Mku**D zI-~ZaRQmhq>zWZeGaS=hDV9?BveK_|Q#&t3hF-oSFJoAgOWrb`w2IprdMWK%Mf}P! z&tuUTdOW)KftY)n=2Lgg+|J{Kih)n6EMXH8Lf2o3KDc54Y1(@;h zn!R}0A1jyk_I9oAX$(f-^L4dni%^}U6z{spNT0(IQZsTf)Yq9~!{FCi0{U{8-I%Qt zZg_BXV~&_h`(SVpQG}l^4aVw;e7R_QPPi>yW@SM1cxX7lZ{VR<`8mA7WMaEv;z}#y z_w2Q^n8!^og-ZKPl=E%sUYS7w_-wB0hDBzoJfj2CCU;}0C#4_CpeH7xrL@>XUEvg# zZ)?5Kz41;LU-%?hvnwjX9|O&L9OyJHWgD?(XQ_MT3K?zknUm{7E^%4*XMQ*-QVI>A zeyM8zM53mM-oq~B@hCn&FM>T0ZQ*J^oaIm6X>%a;Osvh1lsGq^TRi!#8kc`_Wh)FELRE(ox)W(1xFgAT#Q!*k9#O1ri{GD`LY?> z?0@ZmKN8%3vjgt$Rf5$-{?c^r`j$Z#CO~;Vs2>b;Uk7v@^GBmJ5D1bw{<|b10cu5H zW50jQ7`V##9Rk0|ANQ6(oim`@KWv~p8wl!JX8-Mr4gd2cfIEo)VF#qHfbJZz{kWw8 zTG8(o`+qFykLL-3UDDsAle;C|^*n-Zxq_4#&@=RapiYC|2Jik^l3*?UzbhjD_oQ{_ zaQ`8K0Jwpy|5XH;wwdX|^cvSVHUxbAYQ<6V*#NRf*XXV2fdPAeI5EsfsYF|Xh`eN! z(G?)3?{-yHBLl1 z3ZhBWjq?7IAI|XosylB_g1__WN|M)~2r_#=)zi=ZEWbh%`ZA_h0f2cAE*jtDTZy1b>)|=aC7Yle1!Uul&T)@{7K51n{%U0{JsS2_iBW;xYc%^atrFv zbYnm203&I<=I^g}#>+}5UlRCetYOnvX0_7pxA_{wct3>3cN58idfCrb=AQ<+t<_YQ z5lzvXQ{X1?FgRM%#@Fp*Hq%TLFdUC<+oCPpKBZT_XRNRPtcQ7N*-C!@*#mgwNnr2W zJVJplpAOXB7HAv-=D&_RtlfCsyhDafJ`rAf5u`p~eq0~9Bf~K#nC-fPBSGa2KQZTa zFi9H){UBzw=B0=rO6maZYbj+(DD|a%OpI#_lE6dtL{h2hi6r!H0vTQMK!2A0pw>`^ zMA>k80}8wshMQB`kGyHa^KK}{bc=H)x0A;DD$j6HfpiKkWZ}9uOQtHZYA;IK(FN;k z-8^pOVFbUsp6nL&3*A@9b|2h3PFU2C z!rXLm&lsO0Rg8;7E6}@4_=K)TX>1)o0_0a-tWc|JiL4nY#XxcG6)9fij5?mqA|D0O zzzrXd255h1Lb62i((lZq2GGv0%d(FgpQvq5NhmYLEY>E%Xr#piLVu`kyj%{It9v&K z50UYxM@x%WJ@ar0I1DA+M#hsX!_#3NTaGCPK=984qK|$)&RUOn@RZldw7tSFK-{Rze74;OIvzwA-(dXA;JX|&w&ehd zj-O&St&-S^Qied%^=o^oyQN=yw78HbO3q;fALU4b)wH@upmGsvni-p-YNy+L zg9+mao%ET9SGWs}??TNAsqoR@gQrj9N>X{MB<4KF6I$eEHTihkyLS3$23#t(h_8AO znZt{hl}?Ht%aK&!>y*Wq z7r=F*qHcN)3tLLaFnXvYiZmDtdfYBR==xb_|AA}=+PknD+0>{CSEYB{6g#s_G;^e% zx#}A-Rhb_$i885L;X0h>;mwQIVu(fi$HazIb@I}*$$pFRr7jx6#It_B!S}jQ^Ky>< zBkaIfoXEI<>I%iSv=Y04t0Sv)d8O0Af&edJ`HkiBLgl4{vyFD0&a1%Gm|`}=&Q&fP z7rx@6MUI%)b|36e&!SRWl-ipwITh?AfJLqeZM_|_Q4nYxyid0OWZ6e+1p3+x5o*-{5xTBa@1;~Y|5(O8f zf#UEMcXWNHe%8SF81yvMwwNZ#Tv0s!$8ZlxI`S`i*mjT0tvkbfuJB#`YbkkTg=?tM zI#vO~i&w$Lz&T7+&VdS=XAkOu_(e|N{Oy!!78;ksA3IW(d7?n%@Fh=TbPVH?eluq- zH_kg_qmMDYhLj)hr`dh*M*C?9vn_O|F4?IMK~5Ipyph!#L^Zyvip)7pAnw0!UFBa1<7;5RdZ}PKU~cIz~`H)s|13Mfva{XiHN)Z*sqW2Y!TC z@Hk)Paq9Ekc@i_GbK+4fjp49W&5>B*Dm}Wm6WW38j^vmcCD%C2mgVxVHNEP?GkA)R ztXE`b;CbX(_vzUgRO@v4c3mYbrysqtR*F<&RHPf+wiFQlUh8~F6i)=J$4&nwjyX32 z@(9`ZnuF+*EK4eP1;aHhp@>x}KjL;2YAdRj@4JWZc@w_$Nz(bgmdlQk_LzQ4%X)N# zOW3?t*y4rfbP`ER>vOT_JhkfE4^2oiUr@E+=08Qq&Y>tS!*3nXCi+}22C29wW;>;< z?<$+NZ|tP?vz_5oO`LF;p5Ea6cNS-Ys<&=$uk5UZvd>n!V^C$a)`iDc)4ZCWJ=KKs zzR(<6(tYB@nB>fX{`m|25KMuYn}@yLzQ>m{AU~tK3)G%`QbUeb=`Cf`CyWEMK?bD* zw~LQ3>fGhRBjuv9cx?ogBw~splfG2YdTXuFz5y)myH2>v{i`kZc9c<){5_Y^dg%(x znFp9+q7GuR4wkhxi_6&6N?AuVuY9cz-wl(B9|e)~+D)^qL>XUc9zX=yRXj$6_R+G* zq{S?&TY0mrD?^Q36&lc7BN!*@IUBb0Hq&!Q$;Mth;YOH)c0^8_C)c$Qu1F*4-M&fg zmX&BV4zhKjkxCdp?#rb?npcROT?4{Xwg*pdzis7%-aMOSK1`n zgdf1U`Q?c-j~>&8#4=H78d{?Pbjb_JjpG8mgEin*=AgXEuK1GeGht?>0cv0 zD9N85i%Ps9mfzduA`pk_-M)P2+O!0@??_DcP5}Dj=`%vct8Swg%b&6uQ%;p6I_9iR zzpv!D9oG_VA@S(p2~KkaxLWbHRx)NKkGRn7lY|vpylNn}T@^wN?(pAS_mr3a-s$#< zp&$~bMQ;$3!i1#=KE_!AJ8B}i4SvshEejJ0Clh`wKuf^r)}?}^2v5Ilf@a;OU{puz z?OX0d0>NmVx~F^udLoVn<+Lx1_|Z_9$=%rsybpM&bFHE}p6SIbPw!W2EQxd3-jI4+cTU8AgAPcwl%J;R;lpz^ zemps|P@43um;AMi+(4Z|#W!jGC>%2R<#qjc(~go_FgQ6-h9EjJkL(n0`pQmiA(q6i2*uO3$b9ljzGB+lv0KVqrQ@v zT@KKcZ3rf`U3a_ajSvPQ6P5NQut6sVgOY>45S4Cc$hXSe&xOco$QX|2ROG>R9g8SH z>)QT7N=KMKVsI0iqWJfX7wrCTTS8`O%CX3~L;b0XGg%QlF!BUjg4KuD^PbA`AzIuV zBEuZTa2e=deLTvGSV)6)w<62O#B?Y(ecD%1Rp^@1)H2(AQTC>q6fMPGm5_ck<^{zo zF&*E{3B~#hqK>@AR_1!9+x=o;3Et)tfzvF#WZ_XqJ)!mNEegg_VYEjSsvOc!8DBhe zN{U`>tyR;-%FbeJ*9J~O1TNIPMLX5HV~ut*I&%BZ$Nvc|S~96iGO z-C}^%9bsYsg$&wc=-35eP2JSXFA$C=j4%~z4#U^aCxb^2WfZmhno*#XG`G~vg~`L@ zI#MnSwMyMas)d43GbEzz$wr3uCGxjN?cb?h1gRymQk#czlwp^1o?va1ZmHFW_Bw^6 zzQai$I>8fHSN`l*Y-luIytCPBLKO4-o#iadhtuB9{kfAmYL2ESMkeJ7;?vz##zqM) zBp{OV1LjbFN+V(`Tud`Ssy3EfeE6?Y&@l~!Y zju%r5k0y%3N3}f4V)h#a_Q<;Y{3qd<5#P|V`%HolBB7Mjy!6$`e5>BlTdO}5rB8IB zlgeQLkuic+p16YM!5gO@B6JLj0ZLJbH<^v1(;8-dgAB{MRQ; zULMbp;`+P^95EISXb(zqUT{tfQv`127glsRS?IAfXkQ{kF-lK-blM(JAgO!PsiNi| z`Yca57CMY=!!`#OhlmD`Uu~?jFh5$m!Sw9aqETa${ng`KY+v#VRVr+jY2zAC%#$6j z_*{GQ3G!5#Azt88H@C91G@rJqoEuTP8Y)d!>&Ys$?>8KwPhM|_B#;Q$G2xIPwk2T; zD5Ytt1sD@z-&;PmO#Fa43EOtf+zheQF<%BwmAZSs$9<{}UX=o;v9jMuRDV~TIDS!_ z{=Me<$Me*|be!FNazDl2&|JYbclG&7kWLV43sJ`%^i_IP=B}k7iA8Q~VT;`s@5-`=_fl=!7K~)~6C$ny8a7yw zW%C7jU+na=&4;H#HDQ(MCMm*KSMZcxOk_-QhxgByx$Q=U1A;Zi?DUU$qjs!t1`LQK zDKmz7*n_H=QR@$2M11YnTpF+;-r91?xB(K~1X77yF>g@frOXbjTys!r#5_%-%FHGy0~EvI=Aw!-qQ6>%Bus50LUIa%HIyK9wBkz!LWj@4X6d${@m$RjRC~KjzX|kCE)d|B8x~u9>o=fb?ooG1?W!w&`uZId1OnaGLQ(@S za>LhZsu!Y69DD#u$)rh@aS`Wu z$*3@962CdH(^9oqR!+$1*0{RSZN6M%!_~RE2lTyvT!Q0pXWP_QgT(FGH9Uj>D!q? z9^x0{y{Y=XK>-63PEZJam{y+GRhKr09l~&>7)^-vZp`hmcSm)L$Ym}1Fi2L1|3N`?%S6wo53Q51|)H1F|(|{;IOWEFO7r}^nCauKgm=5huv{*Wyh4d zhm%?i9ZTh{-Xbt{#uYkm7j?ts>oA!#4Xr61qikP~rMZ&F9=-*=8ZNfQi#Cxf_yehk zR9bydU2cWWNwZ~`V(U(fq14{uI2@*>41R({aUKzkY8sAxj3%0%a|yB-Pq6TJO=L3(=lDqkXUy&m zor5Ba@)xVt-fVI!cIGu}vv_|P5oF_Ld!Ncs$OUx-BsDVzGj)QiMp#+-NKEGN|4X!%+8B&am@6*Mo^ z$1i%RoYe-0eA|2lOyD70)X1^(a_PZg7HDC-5GEyWpi38DYQ+zywG6V#3K|f$>IYuf zi*zQtF6b*Yf2l9z4TuQ|E`uG8jfi?N%hypqX)(%&Re8**VzVZ zeRLXx6ZN?#RcZ!--jjJx!O@Se1R09y47GT&2>lU^stX&QA|7nW6r^Y-Rvo^K0>zvt z2^9;xcP|Dm3V~+`4*@o61_~;B+?*0;?l96}pIWzwC4JJdFN5t7i9Q-&p$(gpUjs(v zYaFW2#}%ZC@^D7-Yyl&w>xPt@ZC?$!vfRVT6E0%jfP542)Y#V)mW3Qh8SP^aRfkXb zUYDr5=^eaKabZ5RySBn0XAnR2^1^r|bCm}WheIpVun4*l$Z(L>o<}ybBT}5Y!Tn^v zORb8Ebf~%h0m3Nrwt{4)i{6U_LS5{jkAWC*8+btZ|5Z^~YsCVQK&BsoTOpd-)^JXnTo)-N)= zdNMNN96?=R_mMPn>Ou57OIJzm>b~d1qPw}?Y|$$Y%duVb^mfs_GG(3aayw$e`j1e? z+LOq;&62h={FgPEm6_GLGgIc{k>=tKqv)R)Dn!`FZL?y)W`W@PdT@%zQv%yt(ONy)KeA@8g#^E$RM zdt+w(eBr?xuktF!i`kcc!RZ=mN|6-A_TAe1!lsb~8;=V8b;Pn?$F!@J!0@Em%xYL9bJU z#_unO9`J8wOKeOVZc~xx+(l%ZCD?Ht4lfkpv4*=rNb-j>4=<$TF1N8tfkGU_lYNE( zm)(S|T_&~^Lx3KuA)ApQ`fzX&jaegBs*K?FMb8rBv*1REq2P5y+*y=(^|;|@6#$X9 zHBZf5Dhe=5r8*0uBMP3|D}KmV@DzfZ$|7UW^&u(sT_pTFb_768f9J@=C3ty z8Wx$CACAc#968RIwPZ1PM|8JLrFc0pxWnQHP3wee38`kV@3(8NT^>rg zcsTWi2Ck5e2FJHk~_+P?n&r@xS57QJ2%)V3>RCVfj z<0ZDjP;T6T=KPW3+aXM3`;j=^tl*AdWKghULX%ve&PmVfT;3+TkMQz02?i6DrN1^whUE_B}Gyqr?LfPqcKNB%++5I!Wie= z%QvKNL~9uEgF`!I?3{2y#UepE$XMdDR!n2g^Ls9_hCFy9#mzrXk-9?|6TtYUq0{?sCcBa{GrRx&v*F+ zxa#xW%iI3{$_0LTx!xbW7(l>(eOhqDk6hqqSrdbMdv#WmVS&&JR>?{1{6sTD>MH3xF*n4LjNG#pgV4nj1>LNyKT@y1m-oxkQ17PEpk*3TKgTpu%l@_i_CT zpld`oRyg9ce1Bt_R`FwWd-U4$O?wZT2KEry{&m9qMH;EGR$N*mXUV?A#oRGgFmWJu9@ts%PHxDV8rY;$*6%ofIBz*VF zQq!B&2=y>e>YgM8s;41~=McTw*iJSIpn#vMt={_F7^fqAy8KgJ&(Y!Ysb|}WbHmX- zRLOCPNbAVAueXNm0rTN2cuiBt%SA^6C+Pz?R%lU<0%~1e^4V+FR!yc$eSk0xb$g>l zPNL~)P~Ub(G`dI(19tT3$4b_0QEI6qnCf8%bo}e0di*c;D$KD6WvrwzDskHsL7v3M z!l3(+19?I4tmNS}3|mw7h6+9P=A`XY-LVW+RdSXt)5&3YkaP<35Mk=K?s}_YqcgOi znE!pxIKFM*?a@HVTz%z(NG*72lIu3~B^6V}&^`lHS%!DG`h^{0!{}~0Ya*i@Sq*rk zyI)o}l|6f_^p27bAq-;R?8v4up@dZvdNn;fE*?H?v(%Q%Cl(uAkG-@hX zU=`I=-eMui6Xdbo({B$QIeqIyv636pN+MO(Q&pv=vX~%&*ZkpZr?I|sgDk*sfH?ce zX*x7-hS%PoC3QN$%PrpJLdd0qBA()XIxn5;qIRwcdxf#QeR&$PP$At+y-hNfd;%oL z3JukUm`yKtiFH5csxqey{L*Mb7Smxdj*E_m9sxQW5hEjV8QoS~l|Ioy2xl4G(hyrn zT3JE*b2MBRQ4NvFaKq6k zTFP_QFE5oHalQ!`(0p}QbLgk(audNx2?>S8vFz5zBI1NgTY96N2rHYjfGGG9f0A1z zv|QDHrpYjm4}Vn1&f<&pgu9MXh*8H= z%rUa|nGIhw0a3Tnk#jtjBh)U~ zOtPb^PH$S5G)CU}QjW{wPvk>}N=L^q^oH4SmX(O}PkC93m3RZ9M8@ct+LCDMzTrF% ztYmOU+A2b=S~fV*(}qb9aqi{X2r(YvOr=3ihcTkpLI0;_D495A% z@H%G@ay(8o@`3f*Z>eEXxlBZrB-hb~F;oe9M&=?ae_ zwZC{!hEG^0peq(5)Qb7)xlJ2z@Npp<0YtV^a)))4Kq&*^b0WegGFzH`pC4-piJV(^ z#;R|h(lEBu(I~&Cn^UbU%Aw~uKr15;9tX*Mh#milDV^{Yi(-!gIFMMJp{TbfGiGuRZ2M zH5MfyUUQgd!5MkBRk$0kKH)ykU#%@Oii;P*mu7k6Ykh>@hrigsJtdsn9m&Dj)iOh- zFw)jZf-V+#W?r6{!)(50W1(bI#6_8$zuC_cLs#EFVu=08iyxt^eVjWl0=su7D*6ky zVxa$Sc1m*DqCr8lxmMpn4f#rFn@`%gY%_F^=cx^qQdRy*WvmGBp_U6P zVD#eC%Cl=#+}@sQ)7-alJWt@tUNNAdz~}%-67@c+$oj}St$#Sjq?0J2@g@#2pU;OE z@4NE;_`yPuf}{vGyQa4D`jH8RSkO|N6={_?VO_jN)^2<6@5lXqC9Tc3rMJkp^`T82xmkjP1cd%c zCmt{vH<{g;OT=C{1b;WWV6mI6 zKca`jhNahb0{Dj|7mxz6NIk*82r+3$UTj{s$W~hJ0Ov}7D zwhN+#0+VnGF?U?mA+&{ka1ov+ko-|#w+}jM9LSIU^Oji`x-lo5W z$phkeycnt)n#0BT=||L?L5!Yd4L%>zHzkB zNGIpfpqDBw=>x)Dt`8Bzq9!pzo*uS@T)MmxQ&3>D@M!7x)Uin#KcRF*i#~IuddJ#6 z7RBHXdM!$JOLX4L%!*`wXn0szwDu+*XcyEFn8=7uK=@v7$&mP@OR?4H*wZ_00`2tU zflESFI%Jg?{&DN(g6868&31M=MHoiV5z162@vAFwRw-+ZP^{}ymWkBNoTAC_I`KQA z7mK=zUDq;7!%qPKbP_*fFwPqZE45@q5Ip8uD1qB)!R)W)4tp8&Q$ESHt_l~4W=)(qJd|owE_Eu%bgP#ba4hklc%}C5N~JR?;4k~qk%v^2gvMQi z(knm6lt|Dq?+I!DAzo&yR7rB39B2O{$gkNxok#xNPGQVU=lF0ZHBV2!iNByPn|$?)TC3-AAETko9MadL2XiKoD+3|4kV`2R z-?8j(-FWROq;Io#;7E(CcTmhmWLg zqvX5uDA8|P_}y@fv4QDsb9!L{op0GOy2ddA0%IN^u61^H61YXKQ_6Tygx}5b9fa4X zjuVO80782xFix`{6#YVZ7|);;U;)SX19_#}$A7-;N`lEWWKdVemC0K2)DNvt5Npk)HjSeez(l;7)5^qnwO( zvCBd5m$tlnJ5awW(DsfHfPzOudQ3rw)KHHdeK!{L?)|xHhpnEf%Top?TcUBQN$%^k zZ;o5+!=GBpYZ3=nM+k=tQb#`;5=cGJZeLQ@j5ye3cJX;*FFi5}!Ed2XwJXHE?aZV% zEDQgxpZxX8rws7Elf4KK<`>9N{;Q!|=9G1SaX)K-d`w@nQLDB#~eHNf@H0VSr=G8LyS zJH*Ey{!0{sz3^Sp3b&9?_nfaO8^>=zFVXq8dwNYlsUOJ=gnKZaP6_EQj<}%b=s2Jg zgrVuRnDKAw9yAr#`<>TDKRVwI!xxd;6f@`4Z+wT){Vzs=DDMop<|mq+kGmg~wS_5} zG762IXp|IhE1EQ)3gI|2bC;4xw*1yp%e>dBJ$XF2)^mHC!aKQhN+IGCmcx}NplpLd zhC#$~(Z004&un7}2e%_or9ipS{IFd4PQD?_9L_fFGAx=`IIZI*vb9J>Cjou7V)}N! zm?+u46mOR^P>;lmPahCL);YZ0GNf=E=M0e}Yog#FJTtx@o>;q-u7@z6O@e8~b3#2ojRcV>1Pbn2dE>@86G#=#@O~rmmZV!E= z+&5C`2Pb6*n0d}~jO~D+-)bb}4B;m+70IPJrpZ^_<9*2Js&Z|)V^wtoS;WY>7DpMz zT}Y~vB|)5*COr*xl05Ma%*9~&c^hCMe24RLCl}SU{rsVG5uCN`Hw^& zSbh^K{;tLJ`^o>c7Sms_{r}gHivC~mef$;w%aF~H5N7v?qJ*kkwNOF$c=_1>u&leB!v3+Uwd=u*2=J#ZpWLJ1v{HddO zlj&zBKN`ND>3?fayzv@IfOseK%+f$XpmZU^MdC<=Jqa)PE}$WDI0`Z&&k;h4J#@2p zF7$j?E=6LZ7KsN)I`QV11CnH~j#>WWSv2!tsRY;&=0l)&Ky&vfK7(K@xp1Ci1aGeq zS19-!QO?iDAm@Zgh&h zF)7O#B7}xst^hvMAg?L_;=fV&lp&253q3{x*8^qe1C`0b*tE3I_7D~hB)P9 zObpBzs-mM)|9%Qn18hHU95MF9Z+0jOpL{njEf-ekqe$B{)GOWj|vyH=1nzv(0 z%+pm6%vV~)BS1Z8$Y`PXoZUjw)mq6#7=s#;7SPx4UkH~fcncR7Cah)e4FP9yhf|yR zR#@KX%k5@+pAIwEYJu` zPOfr-J>Ef=SvHw@ZZa5#LIG3+i`|#DbU(!*a7gR77m@7K42zFF=5R`votA6LV+BFX z)Fol+tXFNsUC*?9v24ag?|aN)>)a1zx)y$zr+VmOcV<|tK4YROg`!w#z6Wn-{{m?i zEalr%p5k)45jAdWyK2r1lTZKEW>Nr)fi>5E{Ejz-orq;Sq7sVebeN)~f009?reyVm zEla9~cI=C-vZH5%dm+?lsI<1>0!{7ZA&hc_bmHLm*Bs0igM~nX`KWF#ug!QgAG^j| zXy(d7HhS#kbBN&}N8u$|h7fktagz#JH|n+>iE5WN&G3WgGe7j$&F|B6Gc%q7;B_I zLz{dy(yEQ!^GezY5HqY!__u}qFB#K+RoMSvb;?oy;d{vVhrHFN($D{wxyJh63j6O5 z{AY#z&p-b+I3kw6=%oMu_WBqJZyR3~Pc?ABAX8BdnLHjj`pmb8T|c|xlC&JEdg8Fo%V2Xy<%PZ3qT&{A zuh3q@#wP9cRm!BQ;9gsgI50snzE^sfB1pLy1CyWAG{_@sk|a!z9i@j8BN4>@9j|Bm zJ=b99NRC3hsi7=meiSG_U`3}+&09eP7{1Nb45lR$o+2e^Yb*Y z`T_C!NDklNxLuWZ4(>O#_Kxg=;Pm~YKqq~<{%w2U(_BnR6DNHacf1~V zizmI1Sfl_EeVktr-*Hn2MByu~qo}RB zxNmEMUj?yxvG~kKgLcyislBshhysGG@uZ1owsVt{`#6sCuTV^I+N#gmLw{)tWR}-k z7%8_%O2UN37qCYQIek2bQ7JpLg!D>tuW`1!Ia7CMd9{0ej1!p*v%xxF!f>bmto9Z& zpWiMVl|_*bnE=ikuTGG{{VG7^7f(k#9;&*GF|*~Yh{$i^V*5Rgr(xl&vL>fMlYm29 z0+lL2dlC27x13iE79h71`%K5^%|i<^@!n$zvX=p!wUfZLN{8(=C3qMm(Vd1PO`VQb zTfcNXoD|X#N5+(G=qXKz>rKi2LYA+wX3D>WxdH`qv4q?v?7Mq`zIp7|!9-nnH@;Zj zv1L=H=8o;lZP^wji}9uE`wU|~;X>dWSt`&xCat)_`jrcL!2zE*EKKtQLW;FnQudc2 zw@jB~zLEsDR>P5VDtL?$XWsI-ow0J{sxzzE%|^I9aw!faV)6GA41a93Jg6xr$B#IBy(YZ3kY5Q&JK2K^c;@=QV^?EvNZ zv%NDA6}-q)t}}(YKtA(Tj`ZtR(Hs~GZ5PBv$E0l}Pwu@N`@0;lLeav!-`Y}=-avsH zHWJ4JEFewjXJrp9HV=@s$KAn^x4}h*JLKk4qGt4wBvpD0nVQEA?@uAt3ZAlgYOMQ; z`ElQVJ360)_Drx|&z`JJd+MM#GxI$63M;CozSOP;c*$Cp#{H{ zIS;!F`U*h^TR^>hSN`i;$>dp~8>*4}Fy|gd@&y;1$l^DHH zPa?T%H+w9t8qlBf=DLWPS{a$k2M=1mO~ANfl!ZIeZ{`PTqvb{d$dyo9orA4`^_Gp4 z35BEH&}e0+vHH0)q@b(X9m!=?1{&`mubIVyY?m{affYF3HqVG?o*;Jf85HsW6@mkS zG?khrBSxoYLp0i1)3LH_p+|&-RB>$EM*A83B(Zh1#u}5wouqf&t|Z13tD2|QHH)e* z!7AphNZepAG{dBU2xB4SZ&t@|n6yhprZtcess!DXD@bV27yIX0KpaW4KUjL8J%pg zKv*_XPxX6G{i)^(0qSgmME*%LJdORvU9Pnz@U`}shNI81<@vAtl4v*fK$p5-YQj>5 z&5oK@(46I`YC=}=x~LJqZWcUzp_m|53C5%DKzYw{tf>Gz`f_8?^ncmu?8d64ZW&!VNK`5mKP z4b0Xf99pv4ZhdsR)P!moT>3(S`OD$GXlZyEz~IePWnXmEi1@ zdzy82j~Rc6+g%jCw4Zlci(@3nK_#ub7(0hXLy)|QbId#XBz^E^jw#09rWu7$Y>n%f`GA!QH+Cj4JUmXQR-v9~v}xHi0AD-p9k-mzsXCN%ju zRpUn`$E4K@1CE%7_%|#MQ3{|6#4xVqa$>@pom1ha9C{=p@F9B?7{uWxP~~r(Hyb!h zLgHLvN4uGzC}g+5G${jtBdYQ}j$OU=K!|_!I&h<{Tw_OB6pKvs*AIyW7JgsJd;Fr& zJaqfpk6{2`IdBu4OD!!5xWBx}C7sZpFPm%@oB7>6@^bXju-PkJy>}2e;P`foicw56 zNo`b7hWUBK$7%`H@~%xNR`@Lr%+rJrZ5`)}zDMD%&?0rzMS9uhM%9 z0vVV^r6*HRr;|EfAmWQi4uu$+H0&;MEX;UOv1PSGT6PveOxgKyvHU^$HOEcFNf$R@ zIPaMJm%b_Ru7T2$bL*+j34y1HF+gj_v3LUDUt+*Z=d>mY$etVb=Eal_9MZOQG)T@O z0eOTF=KvZK)Nt9kt%L6Q^h=|53 z(;^sqCYRTu<$?DUVLvJGdI7_#D!3^vd_4;n%tmba181QU*$>j_qC$Dd884y6b>W!S z1>vR%gz*^%;i0~kGcnZ@$jhz@Cn1u_nMyc6M-q`C2q%BB3Lv!p_R&s2kYyx-&a$E# z3))H&6U6(dDs2Ns!NE{8?Nl<5LUx$EKt`n$Q4tD#M6h4R5{OmTX|^@KNt^PvXwSX? z(q9Jgm%=6cVCE2;P10mlVpC9V)A@1p%j@y z>D_+qxO1QL6@14G)_cN!n@b#W{Zj0~7YO$Q+dF{R~ka9yvS;<&zEoymX77`I2_T zec%QQ&M4A*O7C;QnEA?VA>Z&`R+PHyu?Qc*oSQI&tjIKB^$>C6?_Kzxl-Amx;%XOp zvk8b?qwl~R`R%1JP`hU~1%l+lv783-5mhm+uN97@JV49^{gMejPiScvKrKf6qPTOb zGh?16c|$!KwL%$(@$I79Q*{ttmj|I;tkK=>`Hh(t|7|TyU~RfE6A(Q(eUi>Vs^yvu zGOv|SGkGj{c#@5CV0vDlDqqC4>{>$2obW{<1|KLi@{TZM0M4VEfwQ8wfx(zp(ifI8G z--br-i>VW`w?1zByy@IRUGz!K$&cRgGoLt?JYIA44z&%sBlO}h-wO3`-Er7GgZFZt zb7F|IOFmve+%9*IQ-Hm7Z3gon_W;+1%j!7Gw{mEAm36UY%>MP(;*P@=?RMmX@n|Y< zxQ$(*YWj*k2KRUzKvg2{m8M!s1bgXnE_K_=b4pl-S0tAEFQ z$J2|*ALc=+50S5(sRJz2!Hn38;_#+EG#OZ_l51En40y1j7RgqG-&}RQqy2^30xB0t zcwaknwfFfJFZ7UV1;@7u?m|Z!@Y23dY7VA9nP9~9x%JNoy2S|XjkzN$4Oq&-&QTLB zZE}dtLs}C*JY{-;94?iWf&zZ8L|u}7pJA#@h+c4v+TeS~)(F9?d&x+`I*Ih)Ci2GQ zHa^R|vqI3~62m-iVs<;plbFc6fUn5B<&%Ku*yRX^-cS0E-K5n-N zwgbf*dadE#sjJ67lDuG5--?Fi-uBc-cv^a8AsLBaFNED8%hkk%r zP`JJf`y|MUV%XtE8pT?D$b3|(GvDlc>+J(QIr90|a-Oa@TsE8TlZUmeLSD>Tdh(hq zv&8Lbpgksjvv=EtiKbdHxtF64u5A_Ei@EW&m$}hb0fG(+Au`SbMHbLe#*DPldd^&{ z7~=4yr-I!CNVl{Km5Qxr_^;cU=CkHNU~U~r{?n--nbzw z=V8;ui>~M*Nk8V;UJ+nW0?~z;Au0&>nAaci>mgbd{N%pR_fY>wV^$re!%#EV+zBnE z?)gz$%e0`JB6q6k+3h+24Y_PDTXOYu#%_U5*;-Zo)vu?neAgXfpFs*z?ub%$w>ypz zu?oA;8&tZB`sy+wNuhaCG#7i~k)-bLMw8Iyq^EYBl_ zvh;$UqLEM61$NFDN13lvyO2}s)xi0AMu_RX2#auc$R8#PU)O%{V%7QjteBI@Vuhoo zaP@d(0cEHZd47dXC|n;+WdEw3ZzvuW&AT38YZbbSInto>%4mMm%sQ0k%mcQIr=mpf zGCBHkYsf~&Bb<{f07?t}lSx@jIHeoo(&UMBs1h9zyj0GaTtZ*phsij3RQ=~j^({&s zTgdGb+|d#oyx%-P0)&K;0FASa{x$rsTa-(hpp zis4gp>r+wv-?sQ;{O1x_znA^zAn$i9`ak@XKXtbLu%^Rd_%tH^bbbFb^5^m$bnX98 z`;#!SG^73-_4Gfr%Kmw*-z)yVH8lLaLw^SUuii2X?Y|lt{((zh8Akf#sE*=8_%j4K zVSxam5mU4_L{WR5&=%|xl3d+smwTz9W| zUq`O@yC^jsFkKO?Vq0EBSIIGjsgF~!Qd!$RCYsM)E5W3wVA`39bcFC&So+X-yW8J6 zCc0lkRI_HjRYfhZjHR2{<1*`oVt`&H@egfJ3%D*r$?Ax}Uy#Rk!7>U-J6e$K)XZv! z4xG@DjWI`#_(D?p%>EyfIiIg@7Ylv$SDcNLBe zB&OS45o-(2alWooJSmuYo2S09z78)k^4!fB%s1#a*mkc`>UN}?h$v$$=c?AH-WmI0 zXPtASfqOt0p;ceyIo7}SH55h7Chrw=pq?$18u{Bal&DT9pJG_+jbs%MoLC@tF9N@z zi<(NY|5M7z)X-|gp>DY7q22&R(d;>#HZk8*e0`MI5P5O(Xt7sSLWWH-3w!UItCiNG zHBb}(`Wd83w%N)3KnBUk!`=Q<&7$M!*~-dGi!^rf!};0^j8nm4w9I;3k*!Z`=w(`f zB^^P*fnZni<+yS+w2^yjM~gi)_Bd<8_|Bx@`Douw7lLO#N7XV4Wl5B#ta2%m=16m! zj=rHjXUKk)W!QO&10(t6ar6fn^qWt@wrD&BaV2E5N_LtW`c9Ox{awXjYM^E5h*t4n z53Oa)w4=KGqI-!d!ZX}#l^pl7Nm+wI1y-$0cqrdGfGX>3>8+LkXYDE|8#szRG~eQR z)|1n*4)8G$)f^WQl>FCBq97${-*eHaFVgIwcdipsb9BXF1@@()dphwIFoW#y{2tyR zVEd|)Yc#LqR<(}iLl1}WO`i9QJ<0^@wAWkcS<$>%@Ok|3o;7HsxV4dtWzC>mU#TA@ zj5sFO{9Pz44B(Z8*$@dWEezrpSIU|x#jbLPVYb(Rka89jdGvyJLLjqwlSJ6(Y=&JQ z^uq9MI6M`#wcOp^31^I`HgmrMd1@u1S5cDDmPwEdh?Eh2PuG|-I1e-aCR}Lm^6?F6 z5V)vr?4>#`G#au6O^q}ndXm4N$RwX`KIIohR6^&+NY)gDfm6c-yOQ}F zRHR=Jh+X?}lK(iyVu?n+-mhO1o&D&t>k9&ldCcsHEo~uBxv0L{HFU~ION;5Ydf>zfB$S9YswTRhI8H^mt2a4|Y+0Q&L@tEj0dgBC%isZ+{DAx}tm@?Q&ys>9C|DbbRjUmbsXA zJ22x+m9jsX-_jcfq(5sm(qvLFK#Mx!F)r3sSc9NODXYEsCF;=5JFb4F%w06`+N@U} zS;fo$j)uYb2Z9%WS#Ui$jUATT-6jb&V;?GnuvvGQGp^pY@^Z&P#^XnxcPc38t*cp- zFg(_&i*4z2QXeL2ml z(sCKaBz_Osq{T%&ZNs}l8WR#w7(`gUAI5!LUeA+qcb~Aw-d6J2AID}xn*E3~ropE8 zHYLS#NO}lWj!B#tea(x@{zDVJZt@C4QkGK&`-4squX9nRgkl!pDT>rD#jz7c8x3u( z_>-NBKtQ=nMbnCEEYqOt@$4c-kqPkrfk5DhiF)9u-Pu0yD~wO``vfNB8z@Y|-z!k& z27eh^aiopHA7CVMe;MlY)YFcP$6P*bJ?Y(AtOJXUrAXN{Wni!yqa#I$j4&3w$y;Ij zDdpP*k5A0O)vpb#&9V?72)$a;}Z6&7_zo#BKtR3WHcs$fK>59C+=-1&mqSG;;vaPTyS*Q*sT1_)!EO|wE%r}rl zJ@uy1*|?iVygU9FL^Q<`^Sa((nNko3thp=qgYU@6PzsY{0^iwovlc4{jN){~HYs|> zohh0r5EWHJWg!tt&8gf76ead@1W@Lh6>fApc-6HRg7_n4>nX^RCFm{YLh^@4zA_HQ z;i9ywqE{u5#H{pU%Tk`@oVExIGNg~qSWOQ=1-$963i)XfZc^l2zO*hw@h{O>0s03P z0^|vEjS4qq2BLt_$64>ooS2hAvNddmtCd9_^JUAGC?Qd;977onzU4TPs9ChhiK>ZSVu zwmiAceA<-w@{GdAnO$6a8zGk6m01BxxKI+O9+3`RoA5OM{Tf+`#Eb z4!nc9ieZgND9v{(J;>-_@e>jpXLw+MB%P^~8TDj;;!!fxY>sJ}^Y~NBQjlM9w;%84 zYq5INP^Ql+wWV>qhW^hY{B1iw50ZiyU#TW0tlK4S-BeGUm|_A1i#5I%?^Cg4o#o@} zkslQDC5uXr2`O+{PzS|NkWF34=A<|bWL{UJgr)W;Ko}fXi=TNg-hx;wOv=wq7lC`_ z8<=`LbMGiNoYdR+U%Vl@i6STBy~p{W|EyD=^*#eRqP2y~1tgTiLl0FD8SWl3BY;`8 zGISIbV=HyGgLV=<8y_Ec=MEmO`bkp0^=a4Dk_48apS z8Wabqdf)S*N*XYbtXWT4aI1k61k= zul2IgQ}UGdlG@6>M0~*U7Cf$tF{7jbihGukBnhNSferjB2I-r>uVMi>fQ610&upkz zoikm6HfKqHsaP4-;E3KjO0}R6H-J>s$?M~Mq^MJexttb&fn3)?^D3=nZ(_9KdX}`d z`5e;NlE|ziqJ*FZ38$8Ut)NL_!mWI@Foy8LL4m;`op4RQ^(s1vQ~#(u(svvJHP`M}WvRijtevH@;<-m;IUY+fwbS|7C+WB>WFPZaN(}zF5tTZaD z!VH(L)(k1QhednqxOpzl)14>j8%J(Q2BxFq(%EMCgI{tmD%v?K71Tee#kO!}78Pwf z#0$tTVk)NRZt)lL|FraVSz|n;WbMN+NRu}w0-*ib0j9BEyzqR@(zl0pY)oeuo9hf8 zR#;y8qQT(VV%7-9zSt9MqOt8LTzO7q0Mk=dsPV?SjO=sVw}mvimOERlV0FErMDlfl z45ki1Ds80K#~uj-S~@XYSCzPe!MZD#0bQiZ0`hadHWPDwRBre{k@4&0` z%ISdtzMz8qBc!R~CpzzPU39}x1|NGJ6GX*6c@(SCqe!jdcqf#P#4c!2Pga6LA&>hL zq#PSla6J4h^s7LHjYyJugmATQhkdA%7?E+OLq8jTa$mU#r0B~n>+bA-J*_URr6K%!0yd`+AS324Su5P(IC$ozeWoBx%ZXH=#Y^hZU|>0oZG zWCfcP$}@%^F-NWzm#+bg7Nv~7V&yRbJ}tnbU26SAj3T!O`k;@ zA`c8^HY%-`In%UOVaOX%V`O;hLm6b{%YIgbL@j$oD7oSe^g^H z|Dxeod$QMcH`=!;^^`TY+wSj0?vDZ?usspC^x@}Dce{HFS=1`1EKN9H*Y7zwQM(c% zgJMX)l6}T?>afCuki7axY5t-!*>H5OjDGnouhJSE>fPWe2Vp#>i1mlHJm-{iw>3+4 zjq1qK;W98XqYpA8fyEZTVwRIfGi6D&myr8czcf8ngmf=Ww6rP)4NbI*YmZR0M%xDio%@G7?+@S|5G1x(prLi}vzVEbQ8W zTHkkluEHA*b!06TVWAue4J*5{$kwhawUU~*+YR9n?#_>uJ8d5H`K(yDgmVy*=WFs2 zJ=gQzGs#;HPfXDBUhN1o)AaY(9`@%dGY?-c?{M?98WKq#GoXse>GJ+ym$qX8mJJn9 z$#H|VJJwT`8sef-U|`-G9DZ&(S-9^P*$zLQ$Dd6#jSwU@KgL}ZIXU(Qt9OB9w=i3XbwC!B#R8?m2epoE%o*c(V-Vz>DU-e!k$T!{MxKG^Y(Dovj=W}&Yk zN#e79?YHCNkvyiocy`rp>f;i8*KDLdht;}mEu&3)Kx?%5Xg5EJ!AYdPnHL%9^*cnX zc+W)M+xj8f!z$FnhhZIYQ4q^YR5Th$KP8-FE06<8Oz$O3O%b*=ODJa6 z*YheGF8?slR(f*!I(h6<-?;3!IJI@(*iC90g~=0IA3pyhwy~kvl5y^a=M`0;>xC@K*92naW|Nwy>@?M0xbgsQbgjI$qdqFdO@d8DNNNA z1FH!Wg}z@T*(7$j!INZ&)Om{X#Jqv#F-$BVpaA}0*@aZxzbLPLBv0H$4aQA4B61sk zxkz(?3C%U(gKWZ58z{?&p*ctpMvV7bK^x>3Js6d6A!u|#dSCB}(zXl2%5xCp8m-?3 zWX`1Vern5^3-ApZqj^%d>dTe$H}dir2@p^Gl<&Ha(}}{aXY__KTDt!9DRk6P@tnEE z+{w!~TTcwrQ1?H^$pSR_B8JnVr?lEF%AAZLk@G5!#T8G|Bf z;p-*$6sc>`8f)iybL+1zFa4q{qKzRXe;yPU&rEFUEi<@+q7hzpZj5|2h9||Ms;l;v zPAT4I5jjvhJ`0YBvCApmRtH9$yvl>AH8jP9>jSMpylw3^#B@>wpT;sSVK%z zX5P?^7-D}KFn-7@(nP;0#5&zlzrLJH83x!26wy1bN!$8%4QI>>AbwoH%f=c2JbTFl zos1qp4nim%NAxHFN`O+<$wp6aG;hAH?xGICXW-I~jZdQ>vLh$dznh1!{$;E2_w$gy zoqYVZ{rq2(58D4W`S{Zq^gmIqVf~Yd^f&19-%tLpO$h!%=l>V2h=G;Rl!m5Lhk9l3jeF&sINFa&PdA5NV^imyJfqYwTAlPJAP z=W1cslGY~xO-by>w=fB^*!TcGviW6*MFl*mu5ftO+c)!4LTCaa0g;{Kmz-@F(N#6S za%2jl!~O9>x@g@a^Z6<>^35T6_;G3*GjzmrW*W-lcwcye-zUR zJUUv}&i81cnu-f^t@t~&nuQ9Zo3w`p3iq4+=lg!*BHV9<4v(EEgoRRpM%E zSEnj0h{@tXh=4R#0OEZhW>r-bH0}XZAp*lCJUM#MgbpW+HFsRe{Q!;j@)rD@y^>{_ zXE*Z|PK`^|MQ+CpewrM+z%Cx>-t~=T7Y8hlJVHD-@HuTm59@L>TAG&|iV0^Hw9h;d zTr5VJIk}RCdpgYBjAs?hQn=IrJhb%rZ=Sqk+5zaL2}2%vn=`P?}gWN;QnYm+C2UhR>d>jI{QZfa`7~H$-r4M#09q;&&abWhk zhJfv>LQ4m&oR$#)DXXhoWF!F#&Xgx``L0V;zJ_;K(S26NFNVqUU`J)Ayo&sDF|+~W zmmbCt${hzUhgJW*JpvjQ77>~_8(UIdRxs6P9BjY(6C5Dertb=AOLW?nr=>@}sE=Hb zY@z;TpH0yd_4iSPFE^mZn_*hgI>KlQ{&zwSxKx&^L`W5qL{d|xH*I<{uP z=ThLZ0e9AFI95+>qbPrXzT)c z@9U3mHoug~NbaO(F_nWwU1GrhmP(fEW6jG*6(k#lMvNmouKB!H)BXCY3OI2ZX4F@h zHkn}jP#nC->CaHn+5ACyIqHY|dt8!tInzU~^*QUKOtMYxPb`54u0-G8o}GUH0RB9e{{HOz2bO^KHx&zq z^*0w6=hJxnlevY%`Wsn*Lre3gSs5+OpAPP{pZ4T`Jf@}jeH?!N{Kr}Qx99Nh&-|}* znC`E0n3m>0r-9MZ{E2b+yOa1YD%NjY039tW6+I69r_VM`G>UXyOOz!VcfBJnf(fol!_`^*8Gf(u)|GwYXCt8A) z=AT6RAHa$~BQY>g{b82&8Hovpo{{n2w@YK7WuasICz1Zx^Z&Ibx=#Z*1{_+J&m?|k zkN(pDj_%(~-yflv{yx;7@74c`Mf+(1_qkK_G*qmgvFPakZND@IT6$)Ne-`R5X8K=S zMaTLH8Tli1bW}7fpF76>-(s3&$75twm{It*eokAvhDu&PZgPHN)P9Y-=-9O*0ziyfTZCMPTZ^j>neXLY;pGY4@ z*8d=d40Lq#|15=nm976%GAFfy0xiv_XW{SS@_()n|7UgjGsFM5T+=hr(fy0db^2e_ z&Ln`bQo$ORf+`xFsEoy~(dEj$-7aV#=%rXx`MktDj!bu<`IkS0A@h2hjAM1YWj7W* zjvb4SkFvPQs?I00s3tP0lCouVo7lqED3Gz?}y`)^A)w#4zvuaQG>| zJPvknG18IVrj^;(o(2?P%dhQkb4*lpsj(L(l?7AwzN!{LpE?ho09}I=Xolnsed#%*ht62jDKD=I%x!1FA)YI-xd< z6`_;VevBLr|M&omkR-d<#uHz-cL~?9achDyB&IvDT#c8Tx-&9Vz|v>wb2xQftX~{; z;FThEMg0fBG4|KR*QsZCR*mCG)9;2gv&YZ>Ft(B#YwZSiGxi@i!k4$Qt#Y&N?cLf1 zF_gD!OiSkjgZ7JK@|xWN;htznE%HjwZNuxT+zj&()kk`FV}PSrq}AUM3A!!A#g9*5 zLt#j_>WM5$q=;ZA8|++-!iG!YKc{bS2BomF;`tiE&Q4WncpjSJ0%AG!sSO_ zwKeW7=I0dmV~tnor3cY_^EP~^PP$N)_ge2~>&ci(!4=`&AOVO_ItQ@Lebe@RaWhpQ z^hy|0`;;HzFbZ@9CFenK=&eFQe?YHkaMgW&eyF#Gnh@{p?9Uvam2D40SV;HP4Wg?Q zUn-i45Dt9ZK=kTyqu7Mv#^jWZg6j2w4|y!V0#$CdTXCsnL^b&WD7eEZqD+Vn zN0~n#3=_0 z|1lp2D4nQEY{+d&;-q6WSY1`IKO7$Zk{dT>=n~>x z!`02=FrbW!NFc-llZxzU_uYP74mcLUyn3_++q`@gfOHPjWQ#Nf0U1`V-*5#v@>C2I zfpn-2^8`D8kk`?PF~}l|LGUO@W>L?QT>>mUnRkXT^bV-TN};6D7H`As{y6J@Af9;m z((0J3>#VXjj}kun9+R7&!?%fs2ay;_(@XqI^b`Sh5CN}jBey&36?pYlGSZ@>qDe($ z7|$a!tAtL)%G@0KIMAR%lzOHNH{uX9B6?ZaX1kz$lp-^WkLULpnSz>{Jcr^i`bbl} z-!&;z43NHoFRF%^mLM!bs8>d!J4`{XuK+I|0oC>`paXch@O?cFynPX1|D@%d?L$T? z!!oc)MW4O$o3YuCc|*GQTnjqB3=r{3rGaWKqpNyXgMD7|U}Qarn8(@bxR_*DD!`bO zBIs&`JPqe#5r54TDF5x(tUE!7;c*awce{6BCn?hW$W zuXxpAf_A~bf1_1cNH&c#QV&tpYF|}&U<`#gYUh26_u9GNp&sE`ql8&#Z!_raf-yN5 zmt+G>?fHrBKZ+Z>GWE1>ua3jm2mkQUbsVOnFgjFJQgZjMHwsoJH1@~Qq7nRK6wg)Qb1CJctY&o!>#+_Bmp;;Z86~(y2gE6FQ zRK!Zo9}c*_Xdbl|k4;7gT4B`P@DC^x?>S=cX(U*hv!4$|rrr#OaXO^kKD_CEa@{n3 z052non;G0#QidRQFl6r?wJ}T|hjoH5fN=*-3hZWL8INW$AZM`qA=F#yJDO$CXd=&K;tTH8RRET+#Wq zzaKHUR~U#oL5F+dMt}4s-|6$a;MINBqMN|S!Ci_b5s@<^#yQm;~-)2}pD!=$e>g-PA1{0hizxm>H zDknz=w{@)kjOfRQVNrmg6Q`>FXMtjj?u!cBTe$g1*dU(3VXiQW8`80VFt=f zIQb1*H&pBr9&Z}v?CfMm2G?QxA@^edM?6-9a5qbi*;x&aV`}z~K!pvp^X^k>a~;fT zPP^OQ32ahzO@V_^%O;_0AP;e=1xpmbU>XFkwa1x3qN+g7H7~) z1@&Hm2BoOJjtPtPVrr?nS@_@_L6Uf4*;&H4qz`EH8Tv99R1ho8084B%5L@v2hyan} zc;NOwWPm{0<25dW659?m$TE;{94^#Q$WyE8d?zJ9@qA~aw9&gq3Pu2Vh3{byzLqDO zUE8rLY5)Lu-2I^+x@(qUonb)EyUb5xl8--P4eq;?(mts(HLh)<)QdzanRR{4UVy#mQiQ0 ztVLSxEKqKDLb7XQ%L%g|s`00TVl`g*b@ILHP#1m4Yf`qF^$FZ=)J{)vDkBPWM)GK8 z^JNzLCFDS%NaB%y#blrA_wLO3*qOE!N^8bv=OB$i+q<-Kad~R>C#jdFlMuO#)$&dd z5IFot1!s1hs<|j}h3p4<>!F13`WRn?<|0|=$U2h8 zI;7#brS>(36d&|`1}^DSS!HWhz6rE7UPvdChFAJ%9&GCWe0BJ4A|YXY9ogkmC6VY@ z4}9?wwqRu}OYFtJA}kDI8Wm$w31&p`=TkQ(pYk%wEh69C5LnPpf?}h;gT=&IMkZO4 zpEn2%h@{&~etH-hR}gY2srjRC6{hvWC*zObfLKF`d0L6V=PaI zkhJd$o0mOi00NcL4t(*lv5w;Ulj#$+z4o@*UkXLN0(+IC-el0g~CLe-%`GOg=Ta?W|fX9!P3H7)xm^P7mQfI6zLUdJykTg9iqRZ)LOCz^5Wf4+|s|YhTu?X&D zdD7Bhd{=MH&eF9Wn#YJVtYiEh*jKD2O=JvzPDWXRq+ygYOuaE%aOBJq?Ww}=z9~4K z$_{kg`qK7XJ0+PH^RCS((GGCJ96!BQq<%KC@iMC}(VRm|i+C2VHt?)JAHW;EaPx8R znr4IiiS1lOJH~LSu(}vwXs6Er7p~euEj6!KUHD#98UpJV7ILf4B-nnhHxkmzn;;Gm zx<|+lGy9JH9^QmoJj0}9R187_EGKWoD^CJ0&1G~aCJ-QT6SM36h5#m%DMLPB28Re5 zYJ0JaQgV1v>pue%7l~j7xuviH0QRErtG>tu00vlOl|%SDw~m4SKZ^eRt;P129rrI5 z8`D2qZ2wrf@So{*G5oPa{#x>ZBphk^IwEe~9VzU7Y0KilWgdilD<3v+9kWxUcs5Vi1afSw_K zuV8;Zcnx4aEdOqMv-buDC&@zbNvI_s`(!rsrxRQ*!;Zszw+Ay2;)HW(#RR`uN&2Dugh z3HZ>kjyr?V+p?C3&*a)bg^#1}%k{TssQ$b`S|6c^Px=~5;GSOuG2OR(4FZ6UTfj>B zrHZ|>_L2=QClMQ*V|F_l(7>3Q@Q`lU#k>#hig}Ua`^|Z>c}F_9!cuWV`P$-v>K>5m z&C)H`??smZ>jq2T7n~fDYqMcJ8JByQb(!Cli*=Vpg>1Ol-NGFu|%s zK+6@;+FsAW(3PzP1^{ye3CUKUQ*<~JTYi3u?Q1DD~LCtOpdu^eEPev0wt|+9mDv?`q&{hINP= zki}j>WVY`npLZY0YJG=zTvi#Vkcy5TfCz?W(XE8QwoRX-SlFc6D$Snv>jBV%h9rmB(sVFVRZL=IIi& ze34OQ)oEE9KC~8Z3>?48ze@=KTexJXa;Ln|O@%FpErr!;f~9?gxDH_}Xkqh~Ze7Qn z@9r*~bQWUVB$UvjoI1lIoCTM=FB{7RPm$0>|B)nQ%!+Mx^!u~4k5TuDob+H+Gp2X7 zb&;R2@0WYm47LZj5Qbjty1_OIi)QYf#RW+Ja5z|4IxqDEGb7WN+|EFwAI&|{XK~&! zo(~hmKrF2>t4Y>w`!#OAamdt0_Vl-nvegjQQj^e6eH+Ggli~TRicj=9D?ij)P?*O&gpx@^(_0f%T-u(R zkpNliaFm7CtJUXu7Z;GL&L8#mEP&`orajbWmc>; zIst6JJH{2!iLgJ;@`q1=?Q~fNlVkJP_nI=mc6m_JD}0LnG*Ge5NTR>mA`)0*vhsVJ z&Y-N_smy_Rof?cp}2(z?)jL(Sxr!nYr#Uy|Fy~kz2f? zGx~JWQfuZ?g)D}>gN<`U!ZNA9sp<{sO4f&;HxCDp-@N>bs=ltuU*eljg07z75+w1b z!-si$;#k|Y{FSn6JC{rvNwF*L=`b{c`84Kfyx+%L&g+S)P?)Y6g#8>Wt@00SLu}4_0<&u;_eU#BJ2s-FzPO(lK!z8lzM_MwL`Wj+9%NNUR~X-~S3NL3 z?MDmp(n}V^QWq!H#AtuWiXt7X8Fpzot){x2@E_R8SaC)v*ksj(+x)J0two&@&Or&hH(>6T(`nbpFI+4#P#6Q(-z5#m9Ex->TUyuCy zMW?`agAaJKm$((}n*BCk56_33 z>9`LD{PkzuoshjpN?&$@Lg5`F{Uz#8&_71mi#a_|eZ&s{C^G^W0_RD;$7jZd?FIFk zbR)}UJ2enN8Zk$G%-b#GE~A@R-a#ir~y2VWp%<}QQ=;F=Y%lXEJzIX}bE zH`+5KxG}R0W$-TTAD2QFvv0{z(?1jM^}I96a{L#UT~^?8Q1q#S&D7q5!JPJl%qy`Z4rjzhnh^bwGO-7&FkLq_w{slCmSgos_|T1@ zP)=O@reNxN@cxP9$cBu~d+do@zPgHqxFbx8a6E59jTCqBv9U<>!bqFJE=QJmQCm)G zwD17{?^s6wyPr{peKCr;ZaRQ7D^7t*7%1Z*y0NV`(~n>gl=i8{P(TLiz9ZuC0#`o# zMKlB((Flns7^Z@KOuw{u#psOy${~6N@M=w75#Nw<0pCypqeJv}n`*k4ZpWjjo3lnq z*5RTl{D@g0sVA_&A-xXR(RViEOV(G)F!sVfsJszKF|P!OA>Ac^6u%+6s9B{F_H?td z5D#qHGdz3swfPaMG9nZRdQHpym1#4AT5`Wq z{2c!XF!E_d#34yK;yZ0C%!Dn*gfKlE?f+5FIWMTvW4G7{=?(Qctqo; zh2HAgQFT5^stc!1dmPCF7)^(~sU@ zUkB~l{QZ246O&im|UW0^tJCu(6dsmh}m%Fq$=>`3%wxrg@NK`Z-k$^dN*l| zrB^$kqtdv1p#aRh$9Mo)H+ApU$wm>4-RuCn zy<@mSynUuR7)eY&>{vrHPjSG)_RtF%X+kZ(m zS66f`bb%J74o)n%3(b^Rt2KR2l$X`uCs_eJiV@L%qq`v^6TD}!kx4SSI8IO^;OnC6 zU+Rx$DoQ3Owkz2(+ppA|6$dBg_d2MLh;{I4Z)*4O$QLl%H#C$WJoE0GT#|9U{Z_W{ z>f|XL`rP!8hJJ!f*7?cDM1Y!KzKwUb*9mOUq0GZ$4R1Dsg&_o(qQDnnIEnc!@df48 zY7g1BqdF_F&{|etAAqeus+|hYbN}LSH(|2-N%R2%0109i1Hzz>2~Ou=RQZkMQgL5yTvs=V~N6 zLbxCuF(VNJbQzkhv5ec-j6ty)#Fpm=+sR>rpVy=*t(X|7a_1vE)0PW*fk|qQ_C-E4~$!PtaKFen@v^jD|k;ct_7{DcA z!h4`tErQ1@j9Ntr-?4-Y;~EgA@o1ojL5oxZV69w4z+f7bHr};;OW@Z1qXx-hP=ok` z2tV|p0QB17Zu{51z&Jz6bymh^oU|>2X!P=!?*)7Lx9{RM@8XV_;Gx7?%KTL;cHvPf z!C?#gll=scp7ZXx@RGU@1j@MZ4te0maN*72fFwd;j>Rdh-j#q0lX~Hea)MsSosqVQ zT46lJ@3r8oA4$P}%-HgH(f20%fybZUVh(aouaN6=eaZO&0>ot}WB;vh@~6}P|5Gb} zk2(FVZ}Jz;^e?^%^FR3}41ZZG|EcLH3=DsL?ce$)e;xgw`6mCju!g^$?0>)-7}*$D z{zDUGBj#ZEuZh(oCbft4nNwP|n7v#bG01NEy%ogpF8uO}Qu(O{RK!K;0&z99eC#UP zG7QSrIGiglZSeV`S#51~<2>j5VYBkFi_K#iEV_PGFV*q7kAh z;P@+kmiH&|_9Z%V6S0z*Jpx6m?d#JFnXuJO5+#h$X*Kjb22L;Eo(f@Sf^k%5eBB!O z1*|`vgZ4sE=HowBALaL2eMp+`)rG-$WeU`MW&k-Jymfr)qco5od8+8msxC(Y0(NZ=BjHGnx!;w!6L_Z&Tr^J9~V8 z@AcgY3ML?)D#*RpM-(ey5s&#v*Do0~@{MDHGS()9@z>6@-|P`SuUWBt=&yK|@(05Z zwwjBE^ZIxIlx=4oJ&?zzNgl%F!iUU=4U`}$tBJV_`$ToGi8d^}A`6h_L(tlps3zE% z`&GyvP6y(`C5@PpAQ)ia%Z0nmV)n?J9+PZdzC$VZ&(tqT2bM#EMAQVN-AI?DRis0|2*ls$s=*Cg!8DW)W3HzPA%NXP5GrcxhPW{q6 zhf86;@X%YW*RIz^x7_+|^7gzEZ0_ZmPM63}tTFB-T)-Ki9hIgO@TjRm-g9{2UEyn} zg=OZXJNyydXFr{)$K1#D92^quE}TW$sn3H;?*a@g!XX*j^KM?UA;|{aRj33rC1?}} zPKo?Bw}~RIS}mUNGmoY_UVvL@_r7^^U*7Ho7%8C7?E)|p3eSy~7}>2)iV++AnOJL~ zW@DqE*3HGxmYCwA{NgH9qwb#nW1^h)u4J(D<>d6LEe%BEB#6Z z!)qVO#^T+n``D7c54~osUJW*|+AOeI2#Fr2yd)>1Bx044C?xzcxhPgDf=+J0GBiIh zaZ$y{*Kr}dGJtG|ACDvvD4Mu{LL~rL-M9UGTb^#H1C|Egw#T;6pVF`Ba`s=7UT(M0 z-$SCd#6<&&npME0$#x)Brf~Y2x??rI`0>1#N}8;v=1Qr;~#b zF+$#IN7#h~SOfCRBW*5VQ2ZYm{_O4p<5ca1%k)vxuOx`EkjLCrdc?*mU}g|+Xk-U6 zpl<$XuR$|jK~JJd>!}>AWXRQ`U%_I9UEw&NF`~>m8(u-}l5IhhB@#^EFV;TIXT2~` z*{ERLwhp1mM(=auD{%*5@`x8bl>&!fxFzYmhLLVJkAWX z*}C>tirNVoZMfRClOhAV%0@Zq=3ClcWO4h(04cnn-{Ms9q&vKFoV#ps+=9#WYnhc0 zYLA?E%eWqNPb`A2-Q8%6Gai?T6hMP;jjOx!eU>*$IUi( z)!8H^2CF4`DDGww+?9D~7oP~cI=SAhYZWm}%~EZM+57ESRIXH0alTK@iQ2>HIs{oO%Q~ig&b$Dx0euBj zw2FvynH@@OWHvnRVr!i7<&T256;Et9E(y?Nhu{mB7EFj4nDD~pBq6FzOObbIevgU_ z%FCOq1zx@``XbX&q_z{$ztBR;Bm3BI^e5`=Pb#zp`IvOy+n3tV6-7qrw}em@AjsPp zFnO6g3UiR?LxkfAc;@#e(@-c03EiZ!2%wJ!_@oA; zc>M6Ug(YQq5KVc0U1@+~c2~h}TT7k{q9-C62+^~T?_|U+R-7_Ww)Ja=ziL=TY}w^w z-R}Z!9zgmj{VCD`$OJOT6QqPA5n^9(OtktK&T|wQ|Af|IVw}YSx_P=N*(a$PWPwBd zJq*2e={6W{6l{>DhD)Y=Oeg}b*N#+uK(0`m)Gs}T1I=t~IQbf3=OkQjhB912Osmlx ziq+P0^|AJB9c8`srEU%Neeii*LAgc6SApF%V!-KHMRG3uIMFlf_F#`)$zHllAG~JMCn;9MZY2+ zef@x~_Jb+?8i13{>yYD?T(FF5hP#IqpI1HrPaRXSR*^edeetk0om616DcNs}sp=~z z1%jc&wX_w=7@~{IF-y62gGQY z(MQ!(Q>rddJqN>gml>zU&e3>{y;S1Jc?*^cWcK5Y`q(Pke+tD=S;tIpWCAb!7I!+j zIKpP7rjB>mB9nwR=3lDKPF0);L$=mf>1}B_>>e*u?Du_2Zhdz-MN0RfEW>T|k$$aq zse`plLw&|w$Kcc~T$&dltkTk=idj3g}AM;@Kn&RUoX z;F4}b#PSzNoxjcmE28I;d6HVNmJo+*QUV$AeKvE7{5VwMOclhDagp@CH%60eHFRXC z<;crHo7XbJK!AaWMTe4kRBC{{4P30Y)#AkPKWi zxUUnZKmp)vSl~f7p0tnzI-)JXE6*j2eiZ=%86|S}6*_W`7)5*7O-fFP$q=f53O3<& z9)bhdHr?FJLfqXceYdG^6lbXbEsWJ4vJ*nluh}OK3q39bwA2{ff(jrLHoS;~B+rdu zQHUZN@K0*+f-B(m?=``{B@g~l;r_iQ_;1k%28RDteBrO?!@p<*mVed=e-Xz2NsaLD z#uxr^H~+Zpzc6ctKLq^0LHCS*u=qb01_s(cNHf!)!HWOe2>$H!@s@9 z|51^!|8IcSmaz+ysDIkJ2D~v;`%h6P21F4c)V9CQ6+r}Uz)MxP2PLF&JyE%+KVzQ3 zU$Qt3w2$S}m`=XAPu^{FLABV_YEINv9@-27rqt9(rC}p?bFtIdnI|=ohe;K! zy1OD)vA$=}Ur+8Ln9wGBbi1;3`}#0sBW5v*rIFTyM1I9trRw%&GcH2@B>Dq5-khuN z2C#5OeYV3c>?uVe4eA@2(LoVq7n?h@-ZbyVhV|PZqhyvB7#6I+1=h~~|H9z%%%MGrqD$f{GI zX5s;S-3q6_A+stZa&6j(WNK#4t#m$D96WrQwyj{QgJ=$UX?43>11QM~zV5AYE z=$fHVxFZcmpKRYFO50WX4h+{z35p1e%zn3X6l9wr2>DT_^rxRY_*h=Hhb6MId2Eb1 zDNXLKy2Q7}Ee<+^o>~4}@zmZc5Y>Nx9VfctYI}agT9E?ldAI-mJoSN%*5&o~ejF{Q zh!~H6W{9)o2s}Q|4r`4co2_HmbnK5nDc#G#1pOV1W9};QO=NmSYRXsdklWxPlIZ1n zBgf*uFY*zYY*%a4TKv{Mmdh1R#EOg{v#zm6Rg-z8{WS}AD>;tctbXDohV7?KY}!z- zvr|RTzjfZe@_u!dsgx0^^PqGN)k=i9nA~0?sr#m@3r1ezy$|UA>@O~d7xuWTCoto6 zaHDpK=xyeXC%h}sJgFvT%HPK+KP^Cf_hxM@@S5cPp%Zk~d z9}`<9i-wuR7KfbP38Ef?b^w5R_eY_~Gl#8~TQsR-9DFm&Z?Uf8K75gMxgk$&I^U=K zvpO^0v3c6Dc|5A95GbzZjH`V4VQrKQ6r>6;Od3;}ZB8u#BM_!&G#D6Ne{$*?0xJ}9 z009tzVb_`5+u}BQ1(xWd?oHtz`Y@azy$93o_ z%=9vj#O*9?#R4K&-TWuwHOX6*X1Y1IjFxQUBRviA9TF-mmo1yK*#VZXfOSH=-(9N` zbkC6b&Ob`}Gj!B-5&0IUOHvMrO+S)l{L&Jek_1G88L4`Ke&ULSVLh6$KINp0lXT3i z)fa0VQ9H;X|DG@3K7zS^szKGznl07r*y#9iBjLyVO92Y?QeG6U5PXsu6kCr+b#2cM zlL{EA zISBy$Ni$!DGuF6mP^x{<(ce|^`n>mk z=0JLAY>e^haC5R2w|4;I`ZKRwpc?az^$EK@U%5+{Ce!BeeA%IVA)_E~T_ zBv3@%ag-#`f%N#(d~|J1Bpx`DL8Mx+C_x|xbdMFz#N>6tM9u;?kFtGA0WbNkh7TYo5T$O8Dk=*hwZ$w!zw7qTEPoZV28ZT+20L6{ zjHyg$`>88la|%ptGm5g3Bg@%A^!ixi92P*-IBh%vy-I@Hbu6N5zUo)7671w%GDNd7ica#H zrQ4iZv2LEuJXy7#Gtn~A-ayr(JJziJ&IlZq3ZZmayE0}b zlJYa)H+g;Luafv!dZ@3yY5yG~H-xhuXnNV5C((2Xb|C}_;8=u2#>J;5ERPIW7fx`S zrsaHHE0>H%&ryF#O#d_~TuJ%hGEKd0H2L!&sB9>ZujWthV!{~%UHlq8!G z0RF;kv0>iRTIoHaf-8dDIy`K+M}|uWvQT)ET^d0~s4!CW8CE|YNl_70U4HNmZlx7P zLA4BKrT8^_$I-W~1`2{hi>Lu=G!c^&{7FAAhFQ1ok5fpb#s#FZqg3&PD|q^|UUyW^ z7>5w0JkV&QWGXBbVnoW%@s(ThgIh8@20?1Fd|?RCOavzz&aecFgNY+vfb3m8RkZX= z074yR?pIbRp*X7daps)8p0u?K#YR$m_M@)>R<^4iF`0HydI7P`&f`y80iOJ;jpUuT zk$|2);xf$gI_Rs@@LAT>kY)fZW^=>PQ8ZvU4g@DVW#x%|<#0yH=mNC}^W-2HwS#xt z_bk){(y3&BPe*9^H(socVGqQ911B?B6^l-!+9T>b6>%a@E6d_EF4aQX$JC1 zdVEo)*;v%lKl0C#-zR`n1sn?!{qn|1ZhhF9UCfaAL$l%cdVk$m`3eR*mB1C26m?BU z3fcKR;MFADN+v)&i~cw+IfMk;|-Ue~3Oxv?P0dI_8C| zrRMkPG+S5M# z-R0WdN1|(qV7J@d`J+(;q@z{Ki+sInFo(zS+{L?&aZ5zwM8mzV4BHhA!GwGiuLSf7 z_ylNaX;WJAT%I~ zH?1t6&!+*kzD)OsnAI=v13% z*rY~U5}_Tp@78SAp0Pf`rU)MS#j%VM?#&`So!MesqO(Uw?yCKKNHw37LtWJ!2H2sets{aPP=kmPK4tHz$n>x-888}6HBDy3s+1S zoRe@`hz_+_jQmHV^CdVyDd5-vZo&v~LZb3RPpyr5aMvi;-;ZeD{Trk6YTLya)F^&o1Otgq%%Wztf39v8fEW;4RQ0 zmZ+Ae;p8#k3t4CzA50$KED^OW@faZBOEyB!0#`U?Vtk`T=1PP1_64s9_`8Ec)G<#fJYAebuje zny}@-E*6C94ie6!@MA`)WYLOnj<|S`KmWlVQ-S-@{NNpqwt4ZG6}!ohvbDo711(5gVN|*L`D#0D4HzlpY(SN;AlSkN_Eqp5LR16 zUq1_JGSWvpXmx8`UL2)vhp12bD2rdkp2nv-rXouiA+21a-?j zw*i-#%m@ zgMRy0M!-K*;>&EXv!H;Y#z2)73qk=MKY0uY+KUqbm{vvpL<3j}zpSD%2&qcK3xVO@#OWjWKRttY?Vx1Aq>V87 zN81KzU+wcc#dZ=y4*W*kda4eWtRi96`1Wkh*K3#qc_M;&^r4R?V6SD#=UY$nwT9kp zPa7ofZ>cJFCH~;mdK*j9ykVrw&VWk01No?C;?g!rC5Z*tBj2KUNrMogTGC(lFGuxV zSrm8Le>|wc04jU%ug$YXGxgkCVEPm*v@mR^QR^<=*Y(HY78a!4X4L-zrD}HB&W`zz zYhxkpMSv!n~_)$f)*1q5-aYIm-Z! z@&={us(h&IT=j#w5>cSJn7L&fJgDSrj+JxOBug=RX$ht^USLzg4GXexUc@qP-ugAl zL-i43tZy@P(4w``JuABy($iO;K)ah0!o1M==x&hDb>yjAYe3P>Eh;i5?N&sZE}ns( zbFhO?Sjzj^YWmrcWc%CX13e&8VmAdtR*AtSHaU8DT(qzfD=Auit+#H)uihcQfUg|( zV5LVkV8>J(9Ytb+B*b&QaAf7t{Fk-nr<$mq{hx&%M`8EnXk{|62zmeoS*`tlTkc;}|3=CG*OUEE9S8RRn1Qm6-C#xf zzSixVI06P;j1WH`qFe_WGfCVKYN4pV-U^k`GqYY-C6eNm&>@4k-?0r5>RQ8YW5+=Y zCy~UO=4N`B96-0d0ohPaRC^eUeA_e)m|97kjTSoY%WZ>5#;zxa(nj^*&AcJS+vx3i zL;B4n%WgRRIWzX;1w=>brqrrG`e}D8%5>Z&Sg$D8TkI5wnHFzznac;8)Ei6=^K+(J z%x2RY>lgU=lc2|On-0Rr-Q{DOJIHUy8EZU2y#YI*BW$*T+3YFqU_g6BLkIvrVgTh` zO8iUao`nTaL=3I@m!D_xh%?bZ03kd16!2CvCRR`}9tg9aPariQ0mIIsw!(_BBkL_avW^ zYIju+_TMvqR#z2@RUODj>;N{`Yk1X10mB1@@27#zC(j?l zP+`(YFwWWxx|w`6I#xAJXM)up zOYD4|JeH+y)vuT+4cc1Fi^>KfCA7?GS9rcH} zz!qXcU;IVsQqYXX0}SPH>*|tN;+(MKkSLSyP z(O#NQOKHrB*R4~i*Ld}Lu|Z|`QNDVW;HA=39l88e^7-_G0P4Oal>7BVtSCD1qOsB< zg`3nog*&Y{d`klXl76Ap1Zl_JWrk$~okZAR|GhWSIGb0nwTKB8z&b?7*G@W1$r7gE z$u$4WzkABhN)@aa13+*ia?0Ok0ky-|)wRQ|;)0Fh30yum;^SL{MrPX);<$(il)##3 zz9*2Qk>pJ)(O;X{wudhX}7X04LC&-sgJ_lEX8^ zlEL>_-0buJW9}VeEnC-Z;c2U;ZQHhO+qP|6HEpA&ZKI}b+cv*CYu}T7&UaR_?@n%V z@4ue(kuma)AHBDy;c0dk=b&N>WkmeLL59jSWzEzWM(;wG;r?nDtH^T$HKi9af)P?o zs%Y`w-b0BWQd&SVphlQEI`-3eE_BFMUh~yXSc(inF{jfOJi6O`C%C>fcpVn6HXFw5 zmWm=m%02~FK!{M`d4tqj(yQZZ)ueE>qozw@%Lx zTW8Bs8QCE_N5a(oo=5TE)3kpLX0-plcu%ONL)*4q0L;(v|IJn20jOUdm1QOQchqs?ai$Vs3H^T?V%N@ZkrwG24pvJ0IDizIabH^##*B-lwG5VyK=SeW*56!2tP zlzOzQ%MMS(2SB7=lp%aR5^}LGh&r4HEUbzR{G_xl%E(6|QQ_w0$eE&I>^k%O#rgJ% zQ!wzmY28#J?2Kf6HO===goIGU+p) zSBc<-pU2>{@$A7TobS=}U-?NW$$4kd}% z(NGzf8$i2Xuev_55^wZRK5nDU?j5)fF1(4!%*ffVbS)ekfJ0{EZm}1nkQ^0-E;Wx58dQB!lrh%BM$mx@WFzPX1|K6@3*4dl1U}=&93tg) z29=*tRU5F73gOYAS-U0wRqYdOj5iNs>XvTHIy#b;s+~!b%wXC73CQTt8?&<|Ko6@9 zCEF~(%mpfyoqLSW0M);JIVoovD8bOjphp^u0a&gvF$s;2C@+(l)@%wI%X;Lo2jSlK zW{irVp~F=sIa>OHywVE0T957D_z}#(Ff21mRLQ?7fYa}AZ9Fzn2YzG$JF&uQSjuX2 z#$(Bi0y%yoGu|RoVA}Y)5mCE_c%$V&KY`o|m>|1qlZcl`l8<9iJPmES3wJ;Ba@3~K z%Zjw78X|5jIHk>xt4v&LUQTu%is_P~0d`Ipo!MGzRbWW;V~qugU6g zBmEGfn1c3BStYxH%s{+mhpl42m2^kPxi;CT^o)#PZGWW;@BStB)A|7-e>fEqr3|<^ z5h4GAp~3(dQPu^hVCiA>nN4w%9XkV!K6#()qGdx8VjH2bzmG}AvV9JY!eRcG_(5Z* z8_2Zt=3JG|76xi?EU>|F{xFj!m~8}1i*)g6({}AS(T*6PFeuKpb?CI@XKqln`d?NjV8BIlLb|(cManx3(&mh$e-mm=AEcFQVnwCA|QHbF9X;u8Nhb&z&%rGv) za-#-mCb!wtN0kbUSvoPqEsT`Zp@= zd=ju}T4krGOje)@?T}$l^3^Z1$}G+myor~kxb^}^s}r3cIxS`uweg^Jn_*rSlI#>e)m{`N zBH&`w44?rZ&A}=dL%X>6kWi}zceojvu6K32hAYf~<4uUYyxBV^g{mE2dNvLMy{ufe zeZ)-dz*u;(^o4*3hghN{D;#J*qB}urG{SUTCqu4f$hVz(2V~eX>+>g<;KeL^qveW+ zU{*^fGd?u1W3g37FuIx%{xq$>cl~{vwx0zTNFFCPsus_g4>w$9`~dKTUZ{;5AnSKOKJVsgl;#Su4LnIRw=pw1 z%{d82#34$@d=rhPNSrOabJC(}LZRai2ek;r=AY;*20haJ2Ed^#UP{R$Ma-U~C&TEY zlSG^9F)W>Yyy3#!*8C2C3QjPD`{4?THezgC4c@Y@T;WbD8Ji#i%lr$)QxIEUOC$Rz z9uD8N5RWc^TjZ8t~S&~q6GIZx$1bS-@_K?G!_PK^v}9#*c;q9VDqkmi5N)QK~CyupY?~-^Iu&TQRMp9 zT)C&m%S!#0)(@KjIm{zA;2Tm`brHD9UhJ65n@oSu2#_c?!1ZuCV0u2bNMqLhB=`;= z3K+MHX$v1RnmDJIruD8xZ-&D=f2Ex@z;tk^SEJ#b&#jqzBZej{fTtvB8JFmyFtK~X zyn0i83b!yaoq^o7_X!r@Y9kfiMd98e!ZA1AkpP4=4^?KQzjbfDEW*gP!m_ram}P9B z$d_saag%8s+Tia&Nch>zE?U7`?LM6abJdGa(|WhEL(oU0qCbYEely`1H6r98L>KJi z0nMf58~3hEcU`X8jr|S(SP%FBt!oTkG!<9L#^MtNkC-3;TbaUjE^< z`uC=nzYJl2o8b84#QIN@(*JG2g7Kf$t^Zt1$;QF{FA^NdYOA*E;;4VNz9Y}w^8=v{ zP@=Z<(#PABFrgFiYkeNT!DLWNOo$ipE9&~cMjZql(~3kUqpZRLtJbA-EOtF-dA`?J zQKVe1hP|$?ziLBM97Q#ZN)hc2;K4d0xF;YwV0#E0STSs8y&8J3-t%lf12ardzs(M; z#@w4}wKK6FD@!SKG=PX|p*?}cmaoNdMP)nvL$4^&xrIwm8S-r&&>8l1xoUasndY6I zCOjn34|!-rUm z(T+k|iN&2Ya8)1Qsn;iEur1~vy`uLoy`nI1w;$iY8~d>1{uRI~zxK zG~Sr<(rc_`uai9(+P+#o8D29{_{N6V@GHVrs6ce&mxtJ|-nUaQdt|p?OdUkB55izo zs-5VevnP#8>#MiE$91{blaM(|`Fsg61Imhf8|+T|Q;OSBS=hcP#=j%4v;wF529Jb- zOh>3WuZ(=gMh<@rNLjHLeb51|uW4~>(#PAzgZL=eH_fD;MS;Tf8NUo{K#%_7B|$_j zQJfZ=oP)kCbt4@fXz&d$b_IRrg3k9|st%O=P5CQrp&V~$Lxw~(t8$l1?-8071aLq= zZyd3+w(0TdNl1q~A}Xpy4X?)=@$2v~Ob)M)%9!i4=k?&dP7o4FJI>h7vSWs z`rPrKi*LbRm`Tg3yC_2aj-X`WnxGwLKWun`wbP+X)u^6(=Mtqz&iiTTuH6cdr%Jpsx() zIOztar#=kC1BdE8xRUfTUIgk83`Xr&dNoE8yzW~Vra)q^3I z)_%5o?4c+R|E|gg;#+bZm^-(+yk8V6YuVnV6wsw#$iiOMHYO@6+uI2{pG*~!luNL*$`wXcJ>>#rMCKz~b&i;yB1^zALoB^=7Rxd@=GEGYO2;uNRP<06HJ>~=tPX%N6V>$oPpHup2AsMby{vEaGYZ7dmZ zspiy&$e+8bJeGXZ#HEOm7hoRi9(+Sp zTP0iei=0M!`6=G{Bp7WG&IJ5O2&E5gBl>SLPeI^2VPLPwVSVmB=#&gQw`?ko`z`OT z?)I=)%`4<9>Bh_^{kn+lT_L^k==7ODA7)j?!p-RTy)0-&DC9`WF&SW+gF?reYaiv1C;0=R@^*I`Ca z^*68XP-Fq>{DHjd2UNgr)_HEGG^v-U@jGg;RB=4IGZtJL-6#wvSKRQ=W}xI9R{=;0 z8*>-fd6!q5)_kxx9_)E;8SL-hiI0Bh$wLUl4I_}jucI4ekqy0LQ&HJNaFq@7ld#nD zdI1ep=+N9LzqgVOYA|rI{0l_lU3u47|<(V^%=U2ei3O1Oy4qf^lv~Ym;-q za_xtb^R9B_Pq5@4!WbZgzU9FgJ2396WdmBVTwjbaS(>?Sz-3aD0~h#!5zEbA^;t>= z06-v5I;0YOiEMY4;D8*8cflESUB-yinZ_|jqodQjsD50GZx`Eb|I3p>K_7r4DS-6VxFzm)eKtf~*T#4)CD+}xe8ZS6X zv}0`^r^K_J zqBDG4<>{wJgNgZ>ZxCtyZ%~BzdP?`P9WEjl+#$aB*&P_L(c|4HhFLOLrQHC7_bAAB z?eyXBiNfLOVs+bmV?=4}6MZ@iq#R~Z+=D9IlS$Y+EXhEvF;HgE@FAKt2Pu)L5(9sz zd!Ur@lP3LY#czO#XB}>wptgE_TzLH)1Z5wQ_}vh=YkCgI2}WNW#!7WLtZ{yUpY`}R z-JX~RH6glz6`j?2^<4AM(&YsVSX)tNw?#XF2p_hPHxyxxjDT4PwQ%eNtX^Tdj0wPl zAFMxo=M{BTrVD={6XJ%f9R=(JuGv65VhzdaPZM|KHhSABfw?rtWL## z+<^ysD$pum-lPr#=oU00YtN}4e+cl0a%md=!ZvwXyQ5?nwZk zr893Mso4oaf`w~m9`0 zq6mTVL_qW<$Q!0KRyQ4MV{|p1;dZH+DcP#q`y-qkePSE>9hz;)m0Or{f=uj~l5?ai zL@MNU+~*W5+4~T7lvt#nO-8WW|C>pdhRb%J|0bsf;fNTRN~lO&63X-#k(eJ266j(B zbYOo)lRd@2D`8^WjwLgZe6`4@?h$_>?yS1HS>^;b`e6CpP1`>P2ZWon-y=2dPzU{B zGg`!+=I*ljwpoAzpU-aYf5tU zA>3~}Mcaj^6qRs-%H)Se!o0NIy>C}%t=cuD zhB+)=pmy(q?gszi6%kYh*B_L*rYd!+PLvoSQO(X=eBU(> z5SEdw@sut8c^Z!&Eqi{iE$v2HP(k?}>Dhq)ZkhD$+4I?%`Rpq~^RO^;$fjE@mTwSA<*Afxu}8rfobazK;6k z|2{G~;gC;^o~YAO@WilO$u9$CwBK`BU)DAJ68tB=HkVGOxaQgXmG`G=xNZcy0vJvr z=4A1wP>$lX=T~h;+K+ERj${~C8~LxLJ?vr;hT}oV7=fp}LJ?eh#fCS=(6Um6zu!*bfgkIh)@AKG4MwJ5)#+ zkl4WKYK5VofK_!e%w;oK@jzPVO*kwo7V2<8iCAQ59b63M{^f#ECcZ?Zea)g4_qQIM zQ_Zp>O|r;cgVN_S%*MTvJUC&^%X4^}r;cz^Y5g00qu&+a@HV`Yb%mR!&K4(hQ1Tey zqfCjf8b-n4PLTOTdi~_Thmus1DPsyyH03-St6`*At%(XD% zUkQ`~V{Hp(79CFbal2{J3T>5a7rs`ya$H4c`XHhG@59Y$t* za^q&flnG<6H!?7u;8@bE(PhDzbqEiP_S!{O4}rX@fA&v<`#$BmG)5okhNzd-1hhGI zyYGXbOY(2G40{$RE_Z^t@V9LAk@{HVl#656VXq9h8&&2_9G;PvB=2Fq=Wbt`bgc_} zYK62`&;_oBVWa?lGul{>P16rPpX+o&34$C}=-XCj%+)ro3}9l+?;r)}VHpe>hj)A0 zAG7NCIZ0zyHEuojssat>7s z>LkDqc(ESzu({J2fh)KD;zlFa`4fO`DwlY&6f>A;WTf7K=E|w?s`(4%LmSo6ciZ^g` zfLMIt!dBJi@vY+JcKRE^dYzh=4h=6=Y7#_?_fN-h40>3P>yL7JLkH{-%DoI4c<8C- z8@u#fKRr}jqp!Q=A-Qo-ZDo6cXDDb6zF&gp(KBFjFPu=r9u$f!30Q; z7QC?27t3e}v~nk(1R=dNR4r}`0dIZR(ttkiP(GJ``JXg+ZdbPtS=F?kQJ zZ`;@95P-}@j3X)jKCketmO9tfRv&QpRlqRik5Hpb+Q{pYx?O$otdfaQ`7v74wBO_s z1^#(@zJO>SUG9ec@QLzX2!>X?;A7S~VC#_$w*wr`w()W7{JoSq%k==p$5-hDnnt<5yD(Evyv z)tk##eEOaqN$DI_Rc$8U?41uOrO}HKvu8mC#{+UybvLnl;}@*Fe~{{s#+jR-OW2+) z>QBgZBow%h_kX!NYU0TNby0$7FiRj2adn%|q_osV3}`nid@L3?E^ z5<>{_SEfiKQ%V;p6dEY!xuUo&@zm~>vv<`phQ0iRH*qk0g!Iu6@^4_}j@xqaVfSa5 zL=fPJ$=f+dZk4NYAN@rx6FO0E%V<;$y$&8*%4wAMaCB>LTvO|ARHI||5^BqG;wxu> zm`$~il*R~VF>A{8kk@eV4;`b6>3c;)ZXb z6zDgsIb>FAzR7ydilv^ahugzM^-OUBixMCKz3*~>Z*~AW2La|)H1&r?Bx+=ARmM}W zvHe<}rhbu)0Ymmoro40@ii$5=5Q(dyf|2I)n2kMbaFqdGwK#+RYeH41_Iam%{>Eeo zmBU%8QA*((o7+&4ti~RpO9B!3gQ9j3Eh(*Hm&`_*BfQ@f?$Of`HQEMbYFs)e2ALT* zevwp3M3S4LmB*(&9_T?QC!=jYT1s_Yr#ET~H{ky-`;!XdDi&Lg!b zz>?KOZQdrqk0Sb8^wGXb#?leC^*9ZOutCnC>E8~+Cr;kK)ttsPNYs&svLwl9FnlDW zO!JDJubwA5(19QAXZG~ zp8$OuH0Nb$8@{k{9bM<4?jE3KpWPc~S1M6t?HT$ezzygRbo74^7|EBBGJTSx<8 z&O?Q^vmo5I7vQwcZYV4VlCrSfu~P_VM!moiW4bk*#pUYLhvdYyehuc{W)eslBpxzG zI>A)jFy{{J5F=F45mJC(JEMg|+iK!|CxKYzw<}^w?QG*k{diW{G-I1=)oH7~4oFQ5UNB){za+^?266InbO1#~h;!ab|KrmH5uaL0Et==f%UBXWjXAx%n* zqgdHNd{5$-@&gGLOWEciWBNMK^aq&4j!I)!OsFkCvnuX)P90)`7tWYqtY~OtZ7CKN zL8&EOovMb(1d0a>UGAS4gUr{R)j$1xDnSt$z?e9foxAcf*~+lYuOUGsYZ?uZeq1}m zB@{r@KP^3YYr^Z!-S}Wh-6b;2?iAOI4%inLMS`sMZXF@6tzIL?YX2_kE@0To=FN2J zoxw1E{o~XHQ30mfKz;u#smNWOLj$_+$_ug7t2hqvJfih=LlaGoI@x36j-i z)%aAF-^|rr()d)L6@oS&$}%*YS7tXONv%5gl@Z&KdemxrU2b#Xb1>+l^rh;5=PcUh z7`qHbRt++F@uE2f$+iO7{r%Rd{sB$q1d)v+QsT+ajSdqKm@c3^34 z!C~^PEu}QIgpcF_x8n%+^tKys-%5sic;FL(G|i0t&3388F|L(yupzeH;X`RgBgM0H zhj)3uZJs+nd?WV$q57T$hw*Lkt~`ZH02-f{v#|V~=VNI`6rha$(4iRDgD{6<#uu2`uA|^pW%pq15W)Vz5M^-6eInAfm2NX@QM9f zaEj@#NdDi#slRUhzu_(W>tz2OPBAlc{0lhsS0}G1qEBv(`9TB-b;f2VcqpDVnFgJq zHNv>ulVLA`7Gf9j@Aw7tBd$dFEu}xpwGxMojQoGBUPvvLbCy=iJ$rA%54N|a=ftw*X3Gg3R@Y8h zG#9w2QRHxPhkocnEm)OSbxOznp{ z4Ur6X_(P=K@RSSJ*y%g$h!99C>!N1V_=rja9sQqY|h>Kf}KZM0l6!sT>EyNas;G z`J>LPdq@NWu;ZCi;guGZ@0b@EeohGs%|*mkdx#e3f4+jSOER5pOo`9kSi|2p?Zzn} z)2VV*;pj}c;g<9brR^}FyqbB<86mn*ae?}x)Ek@a(d;_eo8A`-RF+bE zu8ll#;I+u1>uL-n+-(E6)+%@>(u=bZ_X$IpMtLY9Y3M_c4CKD);x~AAXpCi+Pu!mx zpNc#%aU{*`Ek1}Vzx%&b6V8;nqNF9V4W><4;0>-#5;IJ}-s)bIz|->Mvrnuy2co5D z(b;_$-`86<2e?0;9fq}BZ$o}Rp0izVY3hWpGD`Y>?2fdif&9MMPqN$r$pNbGG3xL} zudr!Yo+SS=Kd*2n&ULt>!`s?>V6%B;&!tW!)ADbC+_45@S3vj~q0cG`6Cce8b|RO( zytne?Lc#iqV^Exht1cp|0)v08$L$P2Tdwq|*;;o$Uwt?`D*}+EqK4PZeS`E{{bHtQ zcji`o`Dq^-GvFj7?Wzs1d2S0@A%@$qM9%9@!o|W~E$xg9K8nY zzx#+>6KZC2>GV<7AV;FhoP~%6te!_%73O<_O|ukM>c-4I{;;b4y^zxFFPUPg9Krh@ zcDFdgvZoIl6KP!;)*5n~fpio~W2cU{+eQI{7+Xx8=qCu|kX!M`0BVxL3n>;V%g;hyelad||zY;+!c9WASc>~(VuPu~zcB+eD zmBxvld&!)g_2!$?lkS77D_?MEr6DJQ#jSj2VBEl@1eG~j8O)hl%&j^!Sd?uBMrMc& z6q;D|@;v9Df7Tzq16Rpp8x-mNKJ614hL3fw32W{?RxgPq;|Ct#^{pWX zUt+YC3YPUzy%hAa_wjZ97DW{c0x^&9ja4P3<7uckMfM;y`SuuWIdmIhImG0gB4ouj z1w$xmefLhWF4e~XNpJ#P^ya;X3LvPewT4W$GN@EaKtu;+*anf2v7R_B%aul)lAHqZ zV5@2Uhz42lVJ=W%%)0*Mv(yeCZ1I{O)_)M3zPic?+upuEZ9{=iFZQn5SKd5ZFp4$X z$2FyH2wy*k9+DR8YF3DyO-s4uu7tApiG}5m?rEOBR~bINC_tfwBk7}uQWgM$1{7(u z)M2TfWm};l5@J~RuAAx|7_2J*jK&_?U_J7~4%T3@u8!!dyUd5alj-mpPwoT!3in>@ zZtNn{ol%I)t^cJxFGBWtbb$xL0ve707^hr);=YfVLg-i87THy$#L(;vxCE+>fpeds z5kvhLhy!|pc}Q8M0Wt2^6J*6LlL$fyjPliJXmv4E$Qp_-TYYdVpb9l+9H|abHrenHgs+SO1m!Ney}(D+BX*oz3E~Y z(jm~!DmfaUR+33?jyTS!=T`bzo=9(#Q*w z!u-}vi}mp$3JTz&7$4V2D3`TDUU+L#7T03xvqVSeQ*Sb(5+A$e4dqpleqe0hR zH4myX_0cYZy6MW(l=aqJJ*Gt~&~inYKYA^7Ye{VhjqkV(Z=LWZZBWbsPs^}iYrq(& z7`82=xof$4!0lF}$G5NE=sa<^6Oj=tIt6WrnE%PP^VMWoR@Clr)|t1lUlQTpe3PMC zWOq%~*lNmHz6OUwD-{A)P7s>84GbF_G6!Sqmj z@PQ_iapG!(4^u7Tdz|)d0sdu|qIUDj;lvi4M^SyKvidUJa{v9V$vvcQd5;T>q(MMV zV|Uz%>OinHj%!n^z;F8ep-rftnTyZ38(B6hM9V(B9{M>1MS%$or{_w0+XK6-1Cd$E z9*Xc_Qr(8K%w#%5(`d{6L;~X4{g7x=RwKD5yK3&c&KcIIQQmTQVDZwRYkou7K1k2< zjLS@8r;n%wC7v`K+qNC&HdM${=Jk1(_h`%e~*O!X{Y+%AQsvG^yL2I_x}%-=Kk4K^`HOJ|MDg=vatVaZ_=MI zH7BC)bWNJgJwJ~+iil!r9*zAPF0ux(xc%9EG7@@q75f@z;&Ocwn84S6wDi2D$ZMe4 zkR%eCb+>ur@p*p}7%XA?VBq?o!?B2?Z()-dN1}{* zZ~S9@123xc8sdc74`++$U%;o|%W96azorfX#Kg=O8n6?4AckaCnD7w69Km!&%kyhA zU!CPvyB0a8zNm>&BS#oKMAH{pbiwk4T(tG`F1E9 zw6W*;cuo+`U5uT42ZPnEKQY0x%8hG4gQ3gbO^d7nSZ^ioP8%i_6r1A)M+$SeFceLf z<{E13%k%N(hxnqr5&#RLUH}rZ-W-KRGp(J7@ zEXF2#z5rG$9~)>K7aJ6@g^{$W>kb?5q3zD;ZM8Uq^!`xc_HBj?Kp|pUi;XWaXvLde z2Avo;eOz69&OO%CW0Z9r?lM-$az(AfSt5QnMlX1#r@D@U8twz=LE;bF2c!qXqz{z# z&mgk{+8BgLLyN;(;n!_|D1uXBD6t?JGohzPZv`{`(CFKzQr|?iuU*>xiu9^m=CR;> zt{yauNJFgmJ_E@aMf>2|1H3!H$nk_z-U23SLNbtT3r_&?&-B!oG0==A`;)83jrD7L z9^p6Yj-k$wli%u{U+nxu>r1M{h? zdUK^S9Wd;r->#yGb?5c8EPA#%m&T@gJ`{I9dsxp-RqDqq!%_JWX1XQxs0&mM$F{n( zf7Wd6Zz;ZTuA+f*BR_RqtB$H&D9ViPNb!s031=N7=i6z52gZs}PHED@nIy7YOW7!9 zz*_ekd%CV;qo+Hc;ATDB)96wuV2mR8j4$%J3y1Jp?)g6ZoBFTer|n)50b0IX3kVj6I5 ztGU2J4(?F*;^)Q??>5K=tI!qx`)nwgCFU0{w#W3(j>cZ+mPuE2Dq8xBljk0}p4}w; z(XuQYW4$TQjZ|Gm@dD>%xQ1Ij*HC=C1^I2XG<-}WAft({iX2;ryQYS&?6rduyr5<; z(q=E!k8rU8mCcP9(;-V^*tV<7-MRHanP#=1-vJ*0?_TgK3ifZZfJt7O(vpo}nQm=+ z1)VtCMk<0qEI};B=S9uE27cXI(`tu?x>*kx=a-G7KR9&AVy%!$MWbwK<%`m1WHY2e_qVM|Q&XcE?FMdnObk_O z$N}-j77tQpgTjDF_al=LTg&H7YbZWx&nEzx|mH37fY#DMG-mSvb9^|sbJcW zLT_s15T30VPcP3!$7oO>F5@uM=Ntcw#z||grgB0W1*d}R5mgsEPqnQ+)?<*aCRla{ zDg|4BgxuYDsZLUvMadKfZ{-wEj=@vU)o@rwi8kDAQi?FM(PW$+3IW0(yXbhlzWvJ1 z8695}XQjhqYE>)z(gRm>RKls*0|(wdD=j!TH(PtFGM`okuoV5C_M&QeDAClc)rj zRK37u5vF%yb@(l1JjVF(%s7w6z|2t5~0v3g2+V)xzJg zHt{jg44w=70jcNCS>1`U*-h0D)}*)LlVr|@#@Xr%+>s&<(ZF4&mxs(WGPyiaERWO| z>esZsJH_}vjzMA&iE_FdjZpJtGq?mp@rIzRX1e-K%wB%eme{Mdcg#S7hkl%O{2bQB zU6{>DmS*!=ZyvB4%hqmx?kDmM~374lf!~Aj%3S);l*& zD|YA<2?fvg3387N&z-99lt3GDVR4E19By_9&eF3AUD?E47uWw`PyME^rrWG+@uk_Z z4Z0E6cvqh-`KQ)ntFt(@Bzd*4JP7OLJBfU3oLusG!?F3N;`l5M*K^i|2}H53^epgM zRon0D`m0d8LaU{Q6dSFKODmzV^_8FAEOxHJMmh|BQ+T^2+JpuUW_6sPoA#C+BZziE zs9bu{h z!u;)E__t?2`s!b<+qF?)b#>l;HrzGuuq)YxpQfO{%0LMxk`N!A%IdR(ADS;##09%^ zo(zuM=8O{d33y(#>sgZ9am6Wl#DmvJov9kIQ%G_KakejFjGe+LVt7g!5tlK9!%Vf( z6~;$q$F5zC*w)LrnA>T^PU?DexjG$giw?4aroK_)Pnkc8xvB76P5-#GIjocY?6P03 z9m?QJl0gcwD4>wqsvGWvXnb+tZP(U}x}*PnpTfRAQ_OL#!QPh;!3WgwgOR)f<^6)W z4uuv$J!IgA0J3aaGSP-sN$0aZ9S2PAOsIlg$dBs|v%%I6ZZW6#Q&leuDpjv+{Po^a zxAFs;Dl-`k!Wl{|pQ;veN%+ zO4@c~^oP%~8go1vVr9NZk2MT%LZdA5%4!IY?;RMB$Wy$w!-{4ik%qumfhv?tjmQv zI0d-J{R`=iqSuT~znX84yZJX_*e+~M5MAs@_Q@`4v~ILu!(_4<_Pa!M%23@O=PGs$4C=|qA_;t}dCNC+H#{9s%Q&3W65Qk&CAv9DYNI*_ z#CLH>!&h%?jxM9sv50h$1k+#Dv1Eb5<1j|s&^|;{mk4M|>3fye!WeDN{^gfkKM ziyBgHDlfWc$}g}9Bvr9)0GWlr*>NbEJf*YutQD!&);S8DOp!!~--C5Y5qk~(0__Bl z)a2+iZ&Z!?0ffmgxd++&rmv#vQ~mw@_oqj_QYRyrNwd2@aS#`H3A-ynZcaB5#3{f9 zrFYBh3@=du38rFhb(&oJLXbvr-YQS^L;997EB!|QJjqEB?Y6sL-F-a>KHRRSXs2N5 zihf~`@O|AB%1jhk*EzVDgsJO{(=z3Eoq#uZ49U~18N z`>}kupkg9d=Yp$kC`;hC{qwEE3HX@L5z!XPaL}!Cx%i|hcvtj6)L0|RienoIWh6Ek z*!FyA&2mF}ue;%X1%GI1i^)8Fy&la}V>5DWjo~E9jG?ltkW;vFCCaDOTO=Ll zIP6uba7H<@4SN$H6Hs7GiX#d>6)lH7DVzf`WRt!DIY#kABT5v`@q&^E-fwUxMl?qB zdvrA?(iU}n>Q^HZy!kuJHNZMQ4XXC|wuhsd<&cn}Het5Np}PVH3#C-u>{!thdGlef z5R~FY_&8G?Ma?870tUMdOZJ=!jT~jyweA+d<{xu?7U8)BANi(?A={<%0%QZcv-Jue zE40h_wo{9tm{v#}Pd1(OkHcTjDP184Yh^zK77~TbfN3a}Jj+*q;9nvV#4C5ORXS0{ zOHJjud#E>Y&%nX%q|N@44`-La7aq-L1y9Bp{XL(!WUI+fi;>Ee#bIz^qM*$UhOZ4H zu@bwku<6ot!2R=(-a?^aj;~8_t}@{qe3TgSj_09-H3gb9pw4nRHQb_{NqDMO&>I7w z+k&+XyI42A^fe%=3O{Ms*!}E+xi-PsutF2ld<1z)HK)Ez%uu3>8McAQ&;a!f*VQ92 zx#**j>9<4Wu!o@DoO71={6vp`j6`YZqa-PXJhC!lDVQ4B z3IHi%)~Py3o=|j<5dgOYmSK36>?cWk_zXDmPe5g84M zDm#ugOmT$qCPgVs%!|((UzT0psHc;xk_eiCJF~GOxBKhY+&Kom% z=3Pab-10gK1Sff;q+)bUk*{J?o70VyhFv1Yugo&MP{;9$Sp594&6c@dj2O{ye!P7C zs7dK~5~qM&&4V9W<+d>qU6#1+#H>V0eDVM_>SHFTWCSW&a4{fmTA^s7!+FmSU|KDr#=%#5ONFp+0Zn*j{wdTub;uqWq~oRg}?BC39e&PP!*WKFUB z*0*?9yQD(SPB}N&k$+u^wAe*b5o-**dIEOH<_HC>KC%%eaPh_oonhhlis zDuol0gB{)pRO+`QH%~e%KWCvsLOLeZ!C5)tFml)H!0l#K;b?)T&Q27}I?-OGC45_* zNSk4+TabA|(k^lL;cxq4n9sA1vbj<^C2D~V*h%}y68WBy#)$qfuwSKXI01f>T;lYF zzeB{_Pn#$%(@S9x5U2Df*R@kGfYfT<&Xq%$#}&j2*&q+)vXlnR>GPbuk;JEgW7ehG z#E0v7s%wf(JuRlUImoK>FpguSmLB zkjU~5M++9XrOwNFU(5;Poi35tzJP8bOxUSf>iSM9BkyPTv2|cOUWk{0bjpTY&iJSH zv9Gxk-}XN)9CO=w)&-7Af+qU9l0;j79|uFDAq*Z;9yo&f^Pp(n0|t3%<~Qf&w8z=# zPALn%+s0-Hv_ofO#kKkoUC`V}Gjk)2Y*;>K=nY6cb-CZd-#TVpW768MEXF#|hwsYX zRIDxSU1~pKvX-Y7Dclw%vB_{Z&6lW*Xw(9a4osCvE^)aFEmvmMpKd~*Ci&^T4Yv8k z^BS}od-}%n{uGSpO6h7ZrMm|qq70rQ;ba4Y!;KK=Ud~q-*QT*y&LR$33r7`{M^jKG zPrdQ8aGT|&Z#j_i`URPMM%C2qZv9K%*#hb8ZBINb*Pdk&qk^7qE|d@6<2IXM#OWxW z@Y(1Q4OtTbid!M#z52R}L#lJ9GI1TAd13E!2*U+Co!0F^6Cf99Kx3hmKXzoP`AeZ&`AL}-cgxjS9o4DBd`0)s;uMPs z(qhzfN(-_EDc9^pdj{c#8$U$}-%W{BNl%p0?f7)==m!iP`6giax|m%aOzgbX6BykZ zmPptWX`H%_bZMhulQHB^SeYJ2o0q*NgBwSY&$AQj*Vp@z%4x^1Uv|m!@6eXvh{w?t zT^*5SH{Z8N0Crv#(h zTpdyo%^9@&QpQ90VdJZ-7^Q}7RbO&CMiaMedR55&fIi;@{E`3>7g<(Z9hA(lmqjgx zC9=C(5-?Gd^E;rwYV4lQk!<~_L7UliqrrwkTLym~}=EiXV zqZ^`d+7(=fi(JTeVtlS8UJ3Vv(S)AvbM-LSu(+;;P()n^sSE~;pvEx~KxFgS;#C=2 z9|rgPiuYFUjJ%R0X!t?7H4n`u7)WGDhvLP!^OM0Ym`Fx`d%etWA-Qw8raYRI9$frE z^$TkHLf7&?)tA*($g_1OvP=L}rF#z;&l;|A=e!xRZWxQa86YZL+a}6m&eMmXI&i0W zWQKg#ajh^=ND0UnhDzvNI<^OU%P0-UDM^crc-oP|K_U@hTD_T^doPz==5aaGkfQSxfb*)#X3AU#?NYaDaOV!lhrEt7HZJgZ?e^ZR zR1WL!on2ID4cGuiFFZs<@0tW<_ktfx5#yXH2<*q0HhIXx;b(LfSvt}jXwvw&f}*BH zu#-)>X4qRO#DqMYQrHChf&5POAxPs$#wf+2EONlKxOtr74p0Ah z%r{|g3609Z!XoOQ#e+23F(=sgM$hQnxPLKdC#w3!QgB*^euQ3-inZ6S$OMbYHd#VY z?5ghy8Wk%JF>0ySDVG1Z-Rzf`R8{*rtobuEa#594{=IthPm}Y%F*N?Q0PBAYjZFV# zXk`9}C+XiC8vn6M_iu;Bf7-47H`E)}KkCi@Qi7EKk1IKUo$SB)n3x%u*#7m<7`y&w zX#C@2dLh7XKnXN`VM(q>zs1E`ZyGSs5dv8%)-#wdrJM-*{O;$aBuN)jlI^4&DPn?lb&LGuIdr8n_`~Qf0$LQGJ zeBU>=ZQHhO+qUf$+qP|I#mMIyVWlxDBqLN1?8F#$65s@T;1oY6^>Cg6Hn)Eb|8}zZM&b zVFM*-+57m`6w%$pGew~>yVk~yaLCEaa;B$quiSfNlE|HuT+{dVZ9>FV}5% zd0Qv3AmT!t{|UpFoMkAnUaelLo~({S_8LWYZL0far3_Q_+Pxn4Q}m;%s%lEGX7SC9 zWxWSuEQ;&V1?*XV_U7Xc1s&SL$p!rxf6(css{e!Q=dn=O3g$*is35xCYs;ouO~%Fh z;}NZm??OsgQO@h49QLqJq!C||;*Pf=TM6z!-i%H27G{f#S$S%ymdx&EfPWV@mOHAa z7785A$Z-@fJ>L!&B1@xL{Pjn1c*WNda*vgu;t&y9c;GvwPBs?eL;$#6)L&C!(<>yl8Al!x<5baBH z_z3YDVKy3V$3Blp;lzqe;LA4=rH$lnNCDip;)T*j`An`H1yPovq?%@j6^!G0^-zSK%^7cgnzwi z*x$6q@GjP_Y@hQ(qdf)>3uq5?kmCaEU*b{f+*WK@g2QJEgC=f59OAuR&0W#NV7WKK zf7bx1_YH*AVZWkx^I5JZr%*66V+?j8bn03Z)4p;{FSA&N#1+*l2 zjE{Ef0JufwFe1^|Nc#dkF-prg8SmjF<4Vu!!9C|;Z|p6v`eR5%sUMiA zy2@iD4DSyM*asC{YlI|B=>2W+0I_3*4-UEHc|96~pDC5-vAg4kG9)d74F)Z7pD9!Ls--CmDU;3Aiex zoUakSJtZx!W0a7b$jeDVoSezU%_jn4*SPvo2lyY0jko?oF*H#Zk#5!k=7|R!hNjJ3 zWwi$)QGcYs$V95bD|QwvO}h8mFQ=^vud1z*Q}gTHZY`zWG?~B;IocCYtMVG#;OH#J z5HdELz!C^hg+h^5H_Jrk*-vAWtQCaZ6IS>Ybzov&xhulISuT<+SODj5y+lUBPS9T-H%} z(~COaOxTDIU7t~J3)6Ca`n#}cJlY&dd$6LPa9(PUGDqNAhCny+1p(cdJR?DNgyT7! z4cdi_n#%5!3+)!QSZeBP$AoEJFf2^**t|s8o@;ik|Z$g(Lnj#;nJgbb66aJB;a{V>5Ac<*@ zr3r2!5T9xsaDkTHr(+etVn!4rSUhBMvRx^@5D9_gelM@#Z!`q3I_@)!MbiqK#6?_Z z>&8!yd$-=x&J2*o=SAu@P3;)TuH+yzu#4D}iq#BmcWcb#eObzf&>t6HNJ0Z2JqSJz z(S20ffiCBF@~WuNmteNA6Y}YgHl0oR-fI0lYp2-W=T&X4#~&+&-+0NBpmJgRfG0mn zoCxU<4Gx>VbKT5Ye`^!Ytc&!}F5ynD(|)n4Kh+F=PwsAN#@w*gsvbwVN3AZiqYxi$ zk;%-t%<}`cDX~a1%_ic}X5!BC1(1+D5D3fR>rJVq_(zeG45C4ciYn6FmiisUVnJCE zLGPkJBX<0vp09{_zE`AfC=1yD{xffjl)H<5IFmT3UIKF4P1c4N=@NserkS8Q$|W0+j6iJKE`Lf$ zritHHNW7lrbgmdM6#{46%%{bl+r@;#_(yCNLCzv__ghV85}alb<#@%Vc)@ddnCv_x zw=frT9?gu(`k8W0!y?vg6z>;kcx74l_BauEWlPw9!V_TuySoy5?< z1w_xm<4+~#h8&8~z~cU}zY%NyTvWYeCAfuP6-=pOcu(6t^(65o2p z&==>IcuB~kliaf&AS)H}5&XmOnktcpHDT-BX{liFOZNMJpjXQUn;l5MKBfUZ3Ig?> zG>S9Cj%%_>&`PH!HDDkPgcgppmO`;Wgc6&6-q{rrwzXJIJe+ zIqQgS0+NHSd0j6)(AB$bUx-5P>n4Ks$4(fn6CloZhddA*>A3Q=21dL@@-PK~DleR%QRM*fUl@Mk{mv}KEQo|7+5jpD-y)(fFkGe$Kc+<1E$ z*9i!kBD=7gK5&~(R|};K-)<6lSsi!`C~{*8_*J12TD)9Dj&fr~!{7=hny~UHybu(h zhpMcSiI5LYo(>rcC~qwYxW&oc$mFpys5qHZ6kWJ+aRcE9k+pJNS82-BIf_*TWx5&9 z#u+T7>;-j11Yl^z1sJXbQBO%#C<)O*YMzt};92#wrQUhbo?xchehnsk>BRH8OLy%D zKi?Mlv%8Q)TO6{`3Dry2JFVu&i)F@!Zz{XApCfmKgl%=|StzHiPq$tVQrvmrJI%es?FgawJ&|VueFgl@5qzpz@{)EiBrEtb4k&sV73jrM zA#%ZdmO9}%P%A?90LkhtyKB+qgHQ&vQ}-m&&6+|t3FJ03@uHl`1r}VHI(UX926b2# zp|x*9hEHonLEL{(Nz_-EoNU;uQ@4?Rqyr=f!7`V=-k8+|*>}>KsL4%*;pe7|3e)FK z?`ewTBZbviA{44<7l8=JFHORFn;BUlZDMF(>Z8ztv16^H7D5Ft?4Y$)igu7oJike# zh1VP6u;Olr@;B-@2zp#p;eH)joZR5+rUltGUiP_5HUOwupg24g(ov38 zIYpx~Pf4&G11OlB1%LJF%o*Y7M1}_w6-vDX#>+xGcM3Ek=vKsZRT}si^{HLKZBrCd zY8tA|&snCtx>g?o{vpk5qNvZ5Vd0fi-S#y9>K1v z)5@c$Bxnu3qHtjcD_BG50mfp_c=g?8hI?JP>Y8DxG0@Yyfb05fnL;p!fWC8Y;yYEL zAr^7RagWq&+V^ip+}Sihu7qJ=b~}=A@tvM=>Sj3~lRnmA6V$Hw4@ffa)d`o_Gf4e* zg*#7k%%U$1z|QP()(Q=!;nLU8#LANM?{v>$fxlX9(K zf4zvuZh~t@!K$9=gU^YrlXzVCD(1?8qcT`!J#X5_hG^+(RZDX+7dW(~;pbg?Os!7i zCNB44ezQAp?~n2kB@GB=-)0$vM;&zQ-}263i-H2xj);&%&lLKZm?31qNOtn41Czhc zsORv`W1t@kKhin$P7vQYeQP3v7s<2?cp036D!yhDwZzj`JpCI7@D_TD?_Vl3EPrc+{atVPHx!z`YGnUK zp<(&Y3eDdYl7CB~Vfj1x{9h?Fe;xWiw)Ow-t1|zL_x{7m|CWIMyLMT!x~=^>8^Sla zT+rlG0I-Qjs#q_yRN#HSb~xLmrNhtxy1&8lR~4;k>b!}?{kFTfRO>qum2^NR66Ia{ z@l`H&ZZ9rlbZ^yP+0KrM!r6!I%S*S_7BXsN1r z3chq)se8S|=`j$xJazizmgB_Djj#j2HB^JcK?)P`Bqp)fa|bqvT%mJ{8UTIrjP76X z(};*yL7^QH5&5R5io!p;ZdI#Zd1|cg=k0*lx!43gLRq4b=QQj_v1^^^z zx9DArpfTI2Nx}X|tTl+7S$jv`RK_3Qz4Cif5yJaAVmu%9M2JjAaXKU76rQAwC=B!T z-VIN84H*pq;HiRq6sd;d(QnWBiQm=|1KC|(u6!5W=g7y8=XSm7XF$#@%>Y4omny)f z<~yQp^{_Issv$|%+3s03QnliPCL~dFgN^B1<320i#;ypu+dyCz?Br|LH<6%t*$Nr7 zZtINQo6nC{oW$7gJjHi;#ebgV5<6{_Ni5RE(Vr()kze#y*)X2uR)4iV>< z!{9B1n8hz-jY(yFW6UQ5qDwyP2HSIQb$&4?NkS5~(@1#rl2O^@@`q=^-4XJgfit?H z=sL`A`Wi9<(i|VyY`gn9tPs!^yJ4N=T(`59*#hH=|6C0vFbyPn(y5%a zhjFPJyLYg^^Gx!2K1gutI|Ow+AE4!B37S0;#C*3OMruI&^4{JLux;Vr3(X7K`d+n9 zYL4MH=&N#Fx2>B(urZ!3MiGDrh0+KW2?;quXxw@&(upwpS{o6ka)7so>wBgLyI1^t zez>G<0MGmzW2OL+s*ZG;?a!az`!~tdvuClHK!qtAo={eSbq{StsPxDxl#u&)NozV zWSe7i&Sikos(uQLAav)yR=$ldj|rVs5RKtCtDO0K&eNpEA`);@0DewC+u`Ov1ukZz z6#q;KM|$iy^(oSNixsSCBQJW`Q8dX$&mwgx%aZJv6{3^G#taCJN%S9ec`AX7vmPKO za@?uU!Fv_=G0}IwZ5b87Yp^c0ZimH(+bs$f-4lttIzW-}r=V@-F@43&Tmjk8@Do{4 z@U!Yu6#g~gl8gBAb5b=2z_X1jUam89<=U@QqYTuR_%UCMo?>!jfHd%9K(*7q9ypka zn5B-29-kd2sKjf}9cLj+eSq*pg$2+X`o ztCaagVhySlE?A}?ERJ~Yrh1n*Q0@E308R%&E&QUgFRl6GVQ32jc~M{{6jkThcx zwha4ky8adD;&!`7CS-JJlB zSlU-3>1e1K-|P6i(vN7T$>D$>)@_SS40+)?hmAJvuJ5N$4bj8U6n22!^;|F$*BP;+ z*5Q0&s!36aH2D)xrxaqCTdwiFu=&qm-Y57$O-DGcF=vz3%PUk&6X)>1&S&NxRR;&6 zX6X+$iKZ5PQRrAq!k}c4JfzFlZYxHLVcW84%@fle~%oo!MIB<;@a5a^pbc5efQ=~xUa2Q3dqDY`Z|yHF{- zGJi5sWuoJX_yl7stDME?_eZxN+C;!I2;V;|fzw8_S^K|#WGlBlSUJlFOnZy5b-|)}W z;{Wf?&Oeih|JXx(J3B1@jkA-jzWyK1PM;qEa+DeS_4I&0J+wKnH~Tr_d!sQ7MT5CW z7*PuesV3wd>J#{}ih5Fq2aPRSXjn~;ih52Zm+HsER13=U=F-IJ(!wbVijvHAtr2}x zNZb!I1aLi?e{|GcJP)J1-}9zVXP(9p2Xg#6ULCzcVgTKw=wn4O%JdSUwv(iqU!j;% z&`S`Cx@g|rSfNN{NgNMe-1u%AKjwm2Ab9wXShw$sXeQ*2i={x2#JZMLwd@5(Du9~K@76pNyfu2SWuBE&Ia>O z&#AE_fu`nAuO*V9hHt@E#JMXsuD+Y*5}}$ko{W)uK?`!m=J3zld0}Hgoc+#JcX1{Q z3`u~SH(AU}S0wk{D;fJ$U45EA@yot`Cf0Lu%)h791mT`YCPGJ| z81aRH?)3QKt_9UYIU{*a&rKgRW%i`lT>7(-X|`ulSRkd`D*-It?vKvtsKy@nA$Wcs z-{-Tk<$)ic?}z8=Y?8*m1B`ILZgxRnkve{-4`X5I!x0}??oiUB)@8odcImgp)BEWj ztFB&)IFr}9c2XX%ncc-*>j}oB$u?lC#)na@u#AEEH}T3-Y(viz5?7n2lV{qk(#G-@ zcWJyh+(8&H0F)y^=WDdYa7T0vt^P!~Oa}d$&#|z=Q{$ei_0&j~hQSG@*BGsM>)MR4 z>(;upT6k)v+E{6~)_R?+u`v*$j)s<>yQ@3Mn$^t8f~4Lj78OAO2e+b@!ww>eMNB6l zaRsO#*K-lb{BexxTLQf38Q99s)8(9?59b}|J~alDPBos{W`pJJ2Ym0?xWM~$RkKFJ zfG#!@5!uBNBPfhSh;zlvfK4PU3D!RAVhW*roC)&qPV7!>K7y`72Ut1Q=hv@X^Sh9u zz%@LDTYb)}>Rhkhc3!g~k$w76`!S%!`@B$$!-#V<&tMsO&86$JFegPV>^H=;ca^?! zlxdIA%gAEpuaH0FU2n?1%NsxChvI92bM{R{9*@H5KOI!YJ^G~K1S7H#)3O@jyZYQ(}e-VY%?`2C;H-=yHJW^}hJM3~=-k3al5ykH{I z`9yheKG5$|?!guneh&p;nK`R0Y=+M;C)W43;AShpMO@} zl0EqVo?;{vxF0BxiVxtuTc&IMaIH`x7a$E+9(QrSo84>WZ3`aX> zIsRppZ!G~T$8Uh-HZ2VC z8=ZnE^SzM-_S!%5ryc&p2sS<*)|Smjc_GpXrtK^)U|20)x)9X+5saP@;7-l?;FQno z76lSf?WX{wKv{nb@s$wM5Odn}9g(X09GlbH$EsM7U5Gzx5->;4N3gNNz$;s^s-A#b zxZw8owRn$8p)juUBt4OhJ?&K-BP2Rhm7TS$4)XJrtd?ndj6Eh!`m&7UN|?0WI0|Jm zw>fZTeJ4b)iuPp6(GbWLKA4H->_RHI5ZbTNnXn1L+=Ow2pLFZYAES&;b*(3m5r~6W z%ouI1W^1}VV81ZVgh{8LG2g|WlMjW^BD3cMiAzA_o0B`zC(U03Ibi9a=1%Yx z`Xy)fY$p5+gA=q1W;@RE!fOp*7@Pxl;FQZ9Gh4RN^1C|hwZgTb_C%NvTAI4n8>l=0 zgXavpo1S3Y2h(eo@a=${xr~lJRMOA|AA&Lqhz(PfX$Yl z+(*$Yq`DlPJ^{isd2LMxLc){=v2dJ@Hgbi1!B@N3Tg6l^axM); zG}6SqnPGQb)3SPC^-5kuhWy~vucaznDq$tgPqTDGpqs;>OQ93S!l0cX=7a5SS%dp)#BFf?k;-Pv_VPt3<7iZ0VVKdrTBLuD#B zSFEsXgx5LRxP9)H4kIaggvTU6MjV=qoNP!q3))FoyS`$`KEG&P)-|gQ=Hj9?PqnSN zi^OVBxB}tc`xUl`e8nR6_Xgd=<<&l@>OxcH>n-ETtpucZvvxO8G0GVNDe5ztV{Vz7m99KY!2*5`Hvw6rVAn z<;3tHD>KhAFfgZO8?M<4k93-CM!pc$UDFQ`A8O_#2ANdUA( z#M~8PfM3Mf->9Fb<$S2p(i<8mv(t9rGiv`bG#5U?SdYK!G~qy){fd;fs7b5RR}N-2 zA3RiU)=b2tZdZzj%puoNQ9H)JRvphC(7rhK+MthVPY@lFh9Hqz10d4~cK@=@;k&I6s3eY&P5{5(8XSFIN^SKWd1cqV-a`boGiifFMs;JYy+VeY5ASsvM^!`i|N zE2w=3MHt|(2{(Rm-?!4Tzbau=G=Yi_pS>M?j$*j2r%^P|?BZQ%1DUh$UUz9O^NP>t zN4G!u2BYJpQ0P(0F0?LAb$p$VLs|Tknq*B2sin3J_?b6rnnuH=U8~}f*f7TT6zFTD zKvMJh%cJF@)fRNlw`UJ%RY8CxJVWY-dqAT%McPc!QDR|9D8_cq^&9fPL6Ha^;Qqsa!+ZwM}`!j**+ z#JKP_FeAtGD9x&ktd*G8H!aAF0Lnea@Z!s6mYb0`NBy47p=OryF1o&reU&CWE-BL% z3guLuW{B`o`a{`h@3A{Byptyhs_u}UQfIp=*Ol;A`PN>#B;C*?SO=#*((xv-PYVB%+!p~vJK$6z)>F6mZWNM<)wiP;%>|H`<@x4-(&NS1o+aYz+W(y{L z&CxuA+R@U4X>JI=WEH|0XKXln0UlDy&JtWBGQ1f74W|)s)emt=965cD6=U zYn*_%p~#Wc1sATX;dcNm+xc^2V-=BAdxq|JgKC_K(!M-20GA@{=S`S0?whv#BFAcJ zFGv|f(2MX}7fim#M+p|;Ne5L#;d+>DgQ?;x;N2mCryWQZig3@P-1Q%XPRzoFpq+If zgE&6k6Gcsri(MdmRV7+aFRghJs2vLMaWS68B?5%s(@Y-Tb)%lgyqw zk!S%zn5@ zsGOGRuFJ)Y9xYO1E$BKVuOx#(HPb#gX`}75;-u2nRH$*mSCN{^(ZrjuVy|9u&z|P% zqM1}Og7rk}izx63HA8K%Enh?$6QoWw&qMhuZ zVWW0~!I(!hzVjkjy-{ebuO^Q*q#6yT4yGvN$k@~fYYdeZp5g~f2_>pTxMLd_9=)$< z7nX0|w4rh#Dqg^E>&>K(qB{>>PFteT99_9~AWOC$H{3d=_eO6u_25z%0 zJ?Ew>8Yg)A5Q`ay10tFr)H%RV9Zq#1!ws7iE%N@v%Q3uSG&i%*_$@*>*_y-P#^skJ%!S@{Rm~9&rQ^$uM)PZ( zJLgSu8=c3g{*6*V_iawF({6M(=i9tZ?qMb@`aqX%G@k3Fst)iQRBbIHZ$XsQoB})o zIY*CH{$+XhZ@xuv!wjC-Y~xh=ofL7%|#&|e7SkF*GVB>ULhX!8GpsdH4643 z&vh=IJfLze!PefQQ`t6LS7S<$dsq#P4$7OgU8p)Tfy}O{MtL=67!?)j2F5*N?^IU06yfYRJjAG+j;?SNC6ZZzkX*&k^pYO^@+py zoB`R(2ei@MAOiQsKdT5KD44Y4I2N}vtY4uoi!2%ydD&22_qcur-S>kU2HqkFVO}NV zO9*<73k>x`(h^Wz^@fQIzvrAlbH7~+rkY+oQ``_zh29^&IrMDci$ZQAl{F()WSQ(R zxCA_0zb@5y)Ry0CqZD0gNa74V!|!*021p<(YqW5C6~Q8Rowd zvj0V%Vf)Xv&fi0{|DLV$cZT!7lxO~#5B{IZGkkpX3QqRM%BC*b^a>(k^eUzvF1qxh z9xmd_E`~0qJUsN`%8Ud|Y;1qs1>g7U|LKad{4@6ZAFd878}omo$V97uQ&ZSb{GRIw z>d_&~F>XsIQb8@U49`QW1&erFf(W%;s?}0?BrUUk^g2sOH5&b*gwa5P_q5x7fg6k3 zzQ$<3Mze1m7EP5LkZ9EuVTqA|;J+sd$wwr2#8E^HNi^vcmAFC|lo(_{A}?^Z89-H|l5U$(u3Nn9RgS=*<%?D6{AzL*)d zUnSaO0i?%B$sVOBa1;_6=dgSP;z3i9bVyiG!Lr1_l_nMy?xcXhjIcZ#l42NlY{5tq z6rqw`IIsvz=*NdXB?wuZLM}xC6)y@WgERwO_@*|$d+^*g&7@n|Dbu2$B0a#)?3@B9 zi;<@h9u_Ez8-oIPu$NPTP)iEYU_p-6!eYVDdUZ518^LYOkPGB<6pe32b0je1ifL&V zD9!a-)j1Z0-FIIP?(}0c80&;EZ~n<-Qs%(#mU$Dznjh63OcGA9f!%^JLSxR$<3h>4 zJ8_AgYR9;i=g{N&RdA3eX>+W=BZ)!5P7xS@l1h6N1#bcyzM?W9*(foIJ`lk9777{eXkaDgY6{sX6;kA+Y+Yj z%MOYg%t3f47x7^or<@MZXHOXLr>g5V8|vz@tv;9K>S90DwF_X;IlY%o(6qClXf}`+ zv4C=J@x(%Dwby3qBQNQy8nT7_mRwz%r>+}!qkUGLsbLgc2e^WzQVN_0qZw-e^p54~ zOC(j?$@NP|9UdW^Y==*o@K^siZHP%91Yr*33AfvV(> z$4?=&ozIh%La>n;@Uw6M=4{wuv(ekTs(uvQ1O1MPKn#0`lAEJXQE@;bwb{!%XUvxO zo_a$aVQ~+m6kO=X2dhAvgZCgIFE{gJNHMU=SXJ>C%0j?pefiJvsROZbCC;!!3ZC@{GDQ>8Ty z;&Rh+2TKLG8Tf=VN4kfV>%3uZf)_0lCOyPp#CTc7hpj-?d>+kvqPw6pIJdKzepJSy zG|TL?^k6tUf!Th~98k@pkjqJEb@R=s*Z1PdLctTTKEd16u(x&^LpqmngxGnKi^**< z=1F_qzRyho&NSE?`vp~dc1x`-gs!>?H~`5$(KwbtWv^UyNp{LKfkie)RrNpTZmp7r<~o+;B?>9%NXOdyJU_5h~Y z14uSDzaI=#(A9j`=$%Io#wZb-vBDUQtZ#t6_4RRo-nCw}#bw~$A_9HZ%P6m*;`V3L zSf41*9U(gMpy+!CQCbz0KIerwjN9d7+D@4>i0RDZ8{lr)Du>VtlZqTn46JaGaOk*k zD4fC9UVU%{HMd@d+wc5iwUDZynz_ocOZ_K-LVWmOPCT{{PQn$Cp>o461t=;+O*zah zmYq=0vNw=cvNq)%HOzgGpV2Z-5!|H-`)q>;B|s{Hhk9*VRCE znoNKa=Eyta-hP2b9x1rw`9)T2fH;zHEE@7~-z?D8>g)d?C_E5Drn7WrEr%HPwc^wTF0E=)Og&6G2q!>|&4G^U zSKs%36BG^{#O_7~fCjM|vo>A1Rb9^>%cv>YK33m`SI>uu(3EI?n_FrW6Akdc#h)>t zYNm#A#TYgGTl3~m- z1}f^$sa+u{t%)U)m>n;4)W=*j%dBDYogRvqq$0}8ZO`TaK4!>184NcI`CNl4v+N*G z91G?_#W!UO7=>Gaydc(b<_|Uw{piqE$sUCYqCQfHCeSaBG#Az2&U+mY1(ra;sC#Cw z!~>R@#dpzC6&g5xf8PgD-46Oj9=@N0S8QDwB&Qe6%NQA)RvdZ`w-et*5~)tMu)o&ODm0F}FN;)%Vk%x3qELU4)%j@)*%xi0)e z6P*MRY9dOAgi3X2BqmXsg`$fP9rx_eZ+|2w!9O~o! ztE-pn$eK=8_j`q>sa#Cf*Cf(}t^nKag z(-HaRBJh9hB(j*|7L!FMdA<)>Liv}%EmeyfBBRPTn8di8fICv~((*mCSIhH9H}dQG z`M*D3o;fDc9yjKgN6j@2_Xv#AEWV^eA!J7fstyF!aQI9B6$r!8ly24FlNj!~_7J&m z+-kQlbyHZb`$7sx1snO*Z>zpD{Xr6s(P+c1`C%5e_1YI_o>?WW$VSbS+S?PDzp@^> zH?X+`eQ%J;{jAoQf4&x8iLSbjV)bRIw)dK#Z|23jr3OoHSIxsnWLix^dFTnK-j3sJ z5VJyV`-6G*)&pu_YfR-ziI>|lX#x6|)0<57B1)AxQ8Jp>x9lG5l`>;ooXux*@q2d} z9>r)Gy2~p_o1_f6uO{kh47ItVVVh=R{jS3)Yf0fYXcrm*=~In^aYXl85Aa7@Z|%Cb z7fsh^8FBj6*&0mvghkJ1>`OaLi^RenKz?I-bsTi-Cx5tQqh+wIhv$lSr?N`*L9ybyWw6!N(fVmLHDU7PXM}ZUnt8 z`$HXsdhpUWCJOgj)`af)+3B_!G3pmri%lo$G!vY$z2>zV8zWQQDg#av!?Mz~z2d5g zSK=+Jscw{^btT+UhS$}Fo#=j^XnfE3lL)6cap_F>)_~+F96(gH_7f9 z=nr@*l^IiN(_5E+q#y41unk|A;-qSetdz>LYD{U}v}X5bRrL!%@2hDoa_sY7fGP|K7j zgo~E~u3eSwekkSisIflAGiYcf)^EGuc+YBAJgVp3vjncnRSjEmxrm0Y-iF&XVN2DE3CQN7!{%st# zCmC1W&fD`Kv5U-yGOBNbh@mv`a-k%z!T=#GK_$MARqyt-PrS8@&W*SDY2EFYxpklE zayWn7&%hx>Ty$pLM&U{Tb|vk*r6`|Wg3WA9B8?`e343Fp7QXl<#uz|5*rgv=M7g%E z4+7OR_dk!j8+pc|U|C=_D8kB{s3OVnYD=;3+p+WsA*!I-mg8Ev62B-*C^aMs%{K*# z2+VrF5}0`NhKoVo6$U_SrZ8_`Quojzm2Z;CcPZhk>Nnh%S6r9fWucGVjD$$jAf+&g zYEoTI5wlFx-F@3v-3e7mtjvHVnZeJ4M_Z5JNM{;p2#HA{nL=$?FZ(262{$ zE7l#O0pn8h5Zu_=0oeOD*^dfpKH7y>HTmz{2YiKnas7>d41C$S7E5Ax(zd>vY4(D( z>)K7+0ylAKHp)3&rc0eAO;4h6Rd%mv-A%%_i51ktWa?v^&ED`hqinJ5rRq~sBePRe z=BCh;p`Ghq(xFgqHLF1II<2Z+F%Zr$)};Pee&Xr@YI&!?of}fk9Q{&PjVw)8F_vm= z16~#_!xZD@=et6O7TPVu638nG`;n<&mi>@T5ipKq8KF6Edz38 znXST!-=AOyvDm8;BiKUl^_b*z@+)E`yFn*Ku$JPEK@Rk;nAzOA>;qhR`TI9Jq`|E2 zGk3jTm$LI5K^io@Gn`RaP9u;e%kGv2Y<6r0;b2_N{m+d8J7grP?3!h?;Or&%;u~Ju zf>zjYlNKXWSKK+P#BG1_na|3#{mjwGM0m~2tZFsETYMn@pwD78&03jKW1g0Anp8g+ zi$vG0DG1AtM&9Qtd5(_0_!RHs!aL}_w1*|M;yLdd=<7?uo?NS+%~y|tOB6~R&x9|)wUt(Ow^3K&=kt@~t`E|EYQb5Xa-QmHtfrhGI@!u(Xn0d9t#=d!X%m|`?@wUXnqe-gtEE#c1xoQ9F{KG%>V0$ZjvU{vvDfFE)L z>_kn>pea^bZBT2l6o}kBBR)!achDw#-BiKj)Uy}PFqK5)$2255Q(Vc&^qfH2{q=Vt zj?EF&MLZxvOea0A-p;(j>&iCv3cuqIdtU{aTmW>CTycnKH06>Ep-6wdTy)5 zB5x97AT)bwxd`G1-i;I%$7mM+NG@o~Bvx=t&c{azfYJb&*oTj?9mXt4^lE@4^U>lZ zjRpMS!~wRm0>mP2U_!!(o6N-H?gSLuMc&jPev)fJPl?nAIGd#GM^su!@KFectZ2=P z_)OiJYSdczW7Yr!5YIGrsM!!37C1b4ndyri0&N8*b0k#)R4)TY%$YE%uWDx?;tHJsYNB3EUINu zs|X;dsp+niZq^nq_8m4D)iDj9PFhm|Xn*sgQkVm|uT9lfg#9w@vhu{r{-BN2pea?TN1|3UA;HXOZ6-njdQ4{ z;>Rc!S8C?^#C#wa2g_T(yHN}JSLeW1<0twoBiSKcadW3mIHJ8m|#?Iv&g8?QSY?yk!DTYI|>FZQ? zjWd?ni=n#lt@bGxq3bm+UTZ$iPE$@Dt3kWLEgNxceDKqEu_Y^^PUzlwr)Bc!JQ?D5 zA`#CSzE|J#O_ZX#X4uVt{aP4(U{LMft9FO2$6VO1E#F$&44naMP4X#+grP$62`<|- zr<}2WzX*1dC37`35wD^5AI=DsfH$SuWU29ygBJBvj!ro?IBD^2`DA#cWePnRoj5>m zfd@LFasaa26X1$0JjCMa!hS4U!x=U-wK&h^^!jZ)S3D|qN&Tnsn#VT6mBTb(P%UX21yjXVq4qik$uBQW1=m1|GRNeU1!E0ep+ zx2W3p9-m#6W(0)Y^Ww~KTY+iOv*i{$hVrszo`y*V)}Z}16fot)SJj)ju9B8os1z;L z_o`>iEbS(hBJRgqEu8YWphZNfNDf2y*_S%;6_<3X#-)#Z2V;Mz%k#7c+bqd^ETw`c z1?lrOyaLB9y%mi%u(A&<2rGYhDX3I8h|l-piBWUrp~8Z}djj`829xnHh8*-D`cU{ON zHIEL^W-rDhZc_*1MJ{vt*l;@r<;!Rsz<(7aveZvAj9IZNZj(> zEF|>1{q%f)xgSoul}f^2CrGpb!lF}4941u$)*dIb&(lfMD zOJ~`>oF_sP!Mv&x!{sUkc}ZRU9bv0=cv^zj_A##kQvd^Md8HQO7bj$sKPO_ z8nPfIM=ut@Inz?_o`R?quS2TBZX*oZ*hvi&Fd8TTeSRa8i3#g8u zINv9Mq>ZTLNTQ(06;a3xnQhvvLf;jAb}bxFc(LnE_4Tri9b;NWklXAfzLXv)@yzN% zN=*Wp-0%a41hZ2tD_W0-IGX8!W(5?v&Dw;5^m9bh0075hw8Mpdj>tNLq|g3`_g+78gLIWLm(bw;WMS5d{Q{m zeCO(_rTA91anh+q;22?Iez|YO%u+yV6}l5zjf5j}Th|xm(Mqg4G`4KmhAgox+Y`2F zKH5FiBK-En%>2oK_K6KJ_UOr?E|g%bLnONFFo3iI;2Rfq;TT9F_*R}RjcV0)=#2zI zdd=OU=_F$Y(458rim|;D>8*qBnsa!JN^tqfh8^e0UFSOJ5FK! zh+J?u&}c=V`@}NoJz4^$Uwai=mCBv8>8p$CO>1OkIpE=;iF4Yz=Mx`bgc>(%iy@fSutR*JxvC z?o7bRMlWLOY;0=hLO{#J_$@(vUsFiP-b0&~m5qUbmYMxq6k%j#Ctze?X4It@{QH@l z46J{hC}wDDY2!)p*Vj|h3mZB}{NwVB9P}Fhc+bkn`ggGW->&?(uX3_^?#DUW&Vq{`Cqgpj{juwu>Kvc`EOY~tpEE2?q7%gFKSEwAN-!b zp6vf6Co!`Aw=<%$)urRUTRc5)>If$xKvZ;+3CSon&Jt|2S}s{cs$Q0n0fHTZ(ZYC*oWHA&|>Z`%`GvZcwtz z%g2~){1|E{pqvnoKjP)i=9bngVP=&S;F>^ zQVH^;3?!dINyRi@f|+%9R}T9}c?+hm?D~zHjC?N~z4&$b4|3MLn-Nnwot<}4XzXE5 z^U&HIN|W55Y#9c9pvXGHj#}fl#MpJ}K6gNl;CJTG%RuxxGMHd&kp6fSKJ5)T zxG^9B1`NIxai9d&V3DJYv24d=n)H!h`7)9CzXp+%FY(^7ttIlP65}aNgD{g8o~S7c zbqq#Cp`NP3b_sxp^Eo%{I)Q10>^6P;)_=2-7>e83+h1*e`iTEIU$(#63hf~H8J21^ zTa;@D_)@&fuTH}&N_Nb}DenDFUI_-Ywb|QECXyX2!wFr40Ww8;uGoUO1u_gwRdiZQ zeA%q5;LU8H5<})m0te zT0MoW=FRAk19U6EcFAt6l*p61Sd#vcXxsWcL;$%aCdi?;2!k9kWP2cOwXH{H}Ctuy2tCDsyel6 zpLMF%-gW6N#}lCsDNYw-w>wj#$Zso>M zK0&hTn;YU*94^#jB;$J7ud4HqYGY`{xmmd^JwD{98uMS!GvQ&H%6B;0GrEcZ;4z>1)$->opP{=6^K#43P z7{Oab<#-8E`;2RbBH$d z?KBh^VcTgW$eaU-z%DS?HqGL?B{7;TI^={qolE2mzjB2s-!y_t-za9g7oZ!VZdvSSPWK`>|LVN0=uX#h0k_=_s1)6Sx z9pN^Y3MD4tI1%Z^Yd$&=0yHVs)^0zw!nY5LOI-?wIEJm$+}L{W5k&RK)RAei2kxtsj-mzZqO%kv?bRz2H+>9Y6H2>{*{4H*7}ld^?!w0T zdX6&;usf97@WPWp$1$Irf!OYeBkc{L-emTA;ke6F0h&RB(_X&h?1YMI5?)5t2C^}& zZP4o;`Q0$r_SLCXy@(1hUPf4+|F#=1?3gBb}rUb-o>|FnDQq0`! ztp6mb=V$zgRblMy&X1z=-mWMlikNbL_(>L(BfWS%G~0iPZR z$4@||q{Ie1;QXx)l>TxQ?Y{sw&jRr`;0D0?FXs~nl360>8!){xb=$;>f-s|FsLd+X zND{58MX2x%(+bjaqKxKL#1as+S(6{atsZTL{p08(0ZlNh`7YeN(?=d2_w_GnF7F5D zF9yF~@L(yFICJv!)WWP1BRXQ3M(6VcIpTy~oKRx8Uw>sh8D0;k`tbGPYH;{F{tQl= z46Z4IembNXlJ=?i7<|vTaTeZwEvAo08 z{Z1Ob{HzEIWH@zfRKfZRir-24zri4$k_7{26UTT-BI!#F#eL}P#7&AG^Kp$?jual& zj}5fjrJkA=Vpg3}CCd~Bs&sjIMLcJmSMe-DsYs2U)7!HlmvKLWEfky8w05l6)9ka4uZu14 zwCgK9d%Ny2JL!tK^46RQ=I5z(-mFtV2#xV#2gAixv9wEzO29#uEF7b19nX4Tj_Dc+ z?h6L>dPJpFZeVW66~<_Zb4Bm=*0^AyS0`yIPCrOO_tB+XrmEdGo=dx$YP_63q$3b6 z zbG;4+B}We1w;sMI>3M>2jryRaWba1Hsm3di53NO-&Ws@VmXph{+jGB4Hmf)u^xzBV z5$*fGtab*XQxvuG$F?8Q?Dt$mocVzH*<^EttCSe|8aV~YZIR^a&#cF)tRHR?ml&1^ zp}8mGF8OMB`Le}aXKv8mMLXDaOIn63S&GaDt-kH3H2<{jf)RKLkzZF$p%@1}Iul&l zMq?|CmM0fLjWPfV`bD~!iU^wzg6}NAukek5vUlVs>;tpHh{^W@91VwQy_}<=E%NrO zsmyk}WqHQi)Z1wj4!r?xhD7-Uk#eg@4w3w%;P5>HHB5r4C;M%IYgZ9x!I%#;do9i9 z+3^aq&Fhkx-8-oD_er(3ws z8UqQ|U_<_r`wgVRP;`i1Iy+LlHO9r4A--ao$6eX#MxX@Qb~e*a;(dkY%$D2B)GC%7 z$KqyUgCVvO=m83rxN`{gqJA5re$?Su<+=GEaFWpki;?(MgnI+7?OwS|ipL6i0Mu>K z6hF3m3l@+q!8bJJ29R07+j_io-bO|&fI3WL5)hGUkzhK+Rq8q?O}>%tN|&7FI{I!I zOEEv4?qJ{hFAC~e>uS1gH;u_o^HpV3W6DZ{fR{`mMn0}5QvNX@n86cLBvpKJt6puz zHCMfnU#@uXVCKC0;i3C>zJJ;c{3hEP$le9%MKT}q;JWDyzC!hpJIF+>bFxX3Rk%nX zaBty4F)*qq{Jw~q7|u5$E*o;KRW}aH!$dnSt98cmjTj%$XW^G_>vE5v1{&xJ-`JFo zKI(M%)Ww5FSz9s$voZ_HJ9xW#p*cPk=IW>Q-AKZR$5^)Sc1V?O39A@JW4$k?wq zSu;e8^&W|w;VslMYlMz3PKe|L&JBH_Hf_u$)W7jkA_`O{ghGcBv^!kt*#a-6fu zYX#WXmpfUV zdf4cbgmD*Z(KVRb=aZc8$=-6@lz1A_5dj9BM9L}u`l0-Q-?_^B zL0?Hp5NB>o@a8*C2iG`M$%mnCH}-+vD9pEL98mb$?B^qx29X5Q@M};jmo`-3Z=hA| z%U8YB@w$;pSWVLc3bGU>h6y^*X1`%ZM!vZ5wqMC{N2czkn-}M~VP6heFA9*55=NSQ z0P#1!Awp=pN+eh#PIdbh>+vmiA{!4;2@P6;a!n1=Y$u~=hsCW!;#RWh5+Rn!E=H{j zU0TORY#SvWUHBt{Jhxz+mVlBz>0Vg412Gxyh>^w8B%eK}%CX@~R!y10C@VA#y%D;H z>s3l!k46#K1~%plgb8e>`T=(U(qV9bhefT?C1hz8K~};wyh4@Pq9o9#KL@Yk+h750 zoF+fC*g(WsF4a|TWiGJ6KxdndHfx?yx@SMgF=8^5Q_aJJdShP zTY$<1Nd?i)YKTDenIHS5IKSNflAkK$BsZ^%`b)^y7u@)h=!|NcEtfgj6cyotsflKi z<3f7CnN=~f$IARc8+!Wdu2TakfAs7`MGg9&X)clU`GYq7m!3tsw_)TB|) zg%n{%>^Q_)8CYNx)s`5zozu4QNAztBs*U}kz?1EKgKBSnoop|$`Pd(|w-DG!4rg=9 z*K8w8X%v-U>`d!kRidn{702ElELQtmzWJK7_7jN#1| zhH=EN7(aKiM<6j{n|){u&J9e7y)$^JmJ&X?h9bfEjW{U5&*8_obbhB{%4x&5zMR!w z*k1jk;z;^s5TgY=_!AWY17}OCjtCF;wt7y3HbN5rnnvg-wl$iP5R9^Hj2#)AVKv$IcoQlD!(#80n=2BNyUM8yI+qtu zYmHUIYL%17sf}ebR5MdRma&%eL1JX;Y9MgynMLd6t8Gj-!9mz7CAOl&s1@~xJYB8( zN2RRPjb`ILMADVa+e@@`rLem8Vws&eSr-o`^Pz^O zUK3!l-ltGmpr}e$Ip$n}J{vTcmVtl8u07ubs0J*9ucm2Ou@NQG(5LcRcO{AnQ}YXQ z3Yok!Z5}+?XBs^iNE8^Tzd#I+EpbyoVHV+jd-P2#?FACot^%o2XaoTsC>PV{0{Xkb zJRR4h&L2T*9oOQA=AQ=Y%T(&CCPDq)uuK=1+jnI(kT4Jn5GE!FR&v7G?Ve%Jq&BYS zh{uCF()iI8Ury710drfrG? zRGS7#24|>=M3KX$Y;9AJV!Yre+!cg|j)M01Ae;cD2>}j5y;o&$Ayj_gQp!5VT*QWe z4x3%?1uLpUN11Cg2N+Ec(?sKHUVrT+bCc0m;;eg2W5|tUC`|7|8~+iLj&rfbyIFDc z==1UN*gKr;>q%6Nf##}vRAE*IjK?>FDSnif?_!4JJTaoCRUXu;~_s^aWo0AOr+08&0sJ z1GLXJX0nm>Wo9#my2JZIr2Y|i4j9O*gzbd#@kWig_`twuKaG{X;PuI|-VR=&*Fr)_ zhfHHXS~%_@)8${85k!9Dh|46qejn9+Zgm1fs>Yr76`L$;q*cDJrJ$;TqTw`zwq0Do ziZwW-gj{uCasT;cI(Gq!q)tg zPAx;aH3y3s2Mw}q;MSuXn$movzJGS9eI(V7?YMYsdQb>bT8CjvN4%zwaTL{F;p53X zPYG$k^K8;sn+tVM)H7k8GD$abwMa5mmi1CZ$xkq&nhBAaTzBKYqw$qo(LZB`r1@}0 zJvNW3FxK9V(+M3-cMCk-#Hs5h2|DWlY@j(%jY%NrG`@n|r}5O;O1j7^*J?;qzs z8fK5~IDc=JHpJ*M_(q7MpHM6u)mKd4$eKqbZ)_Qny6!jn{ktgW=D~rLan$-2B5S7D zXb;-ZenqYC^^uWs+@Rf?=pn!6{ra4{k)v3cSge&A{BsnVJ|-BSr2+9-bVYlxtc{L{ zWBa!{Qg~s(4^T0se0pMI+|&Xc5KfkYvfjhU&~IyaHD&2BPO~*)Is9geNE7+tgLnIs z%=i(POw_9%4CDEnKTJ7w3rYLnbU2sPG!5uv_h4Xm!@{2;D z&qnFtLnz3r-f_OC4j<urv$+Kr|}GqpJNmM(Rc>O)7Xl_&;EgOi|t=cFc$aZQG^4<^GfwN8jMWz z%gz)OXv|`k*{Eem$L$0bd}oeTZJl9~J;#r*t^Z%*7?T()el?+PMg zN*DGoJT5)>IHjw8*e3+D8o=Jkx0$|xYd_^h=aE84wK0L!97Kzz7;$F_725T>eEIeM z;3i-#k~sqq`tBvm|UsYrj-pKbm=_YizSs zjew;>p9q{;qU!Yqq|^r`OB)jqg-{H68hJePH&xxG>a=M5Fr-^K2!llluUAc9A^B|I!(d?tE^b5;V%mE+M~_EXl#d;SCwE(6fnYE0v89%BTd>4x~_UKvoha#hwDea!F1cOEi7=5v-plb z&h`>_uu0B+F7rJut?XV>xuO|sGJfdCiH2`S9@e=H(knCA$HgDEEO=~S-KWq8kU=}Q zQPP(UoXsMO0j;SZ1WFHt`r2Hb)huB4;HV>9o_Hj|WP}2+-dVs=jbVhi_z%5s{K>Q; zzI0O2Yr_@E9tceI`X0@GXa3YQKPVMY=rBbzdYhOmiQ>^3YNCCPI^9fzydm=ZT2v7C z$vURan(FI5k>X*xpRE08D$XodKRw<2{=N7uWU?3~dkE3hu2jt^L0k%CcK5hd-xxSM zSqM8st^Qls78h_eN#e^}sGPLL8@KKHsw(gr&ZDx3<8v6WskC(d<*rjOJY?hG|Uh}Z2TotVN?8FG#&1gf)sw<5@rc&BUUFIeI`SZ zBD5IY528S2r^Rco>DP&@XJ5wdjMXHJygp*FX9%WIk|3+pay?)%p$@(e9bqZE?+)jG z86a?nvLF0*#lur%vRY*N5>ty22d9*L>aIIwtKM?isl|atMm{LrbU>3$5zvM6#QeXg=Zj&LuqO+FJ8VjBW(T8>387P=unm zI{Gh~dqU{NRH*l)Q98xoPebjpiLm!@&6n%gmETEeAX~Dr@5R)J>P00aE*h`bjx2Ke z?Irn@{?K@PwNJ`_n!lgsB%@8sFsP^{8O{ia`oOQVGIXZ^}9zu3B|bZ#!(_Dr#X z^#ri#H@=-aTHs1rwJ)3_)F*)a_P&4ZxVd<~X+;x@k@oGx zF><}l3}iTl?Ab5|8dIqZNW>>)!P+xwaKTX#m`f1G4%%~g-sQCEHl{o5jTfxKos^EY z_kg<^EB@Uo6KxCidV)cU?JJkpG0yzboEJeir$rM&Q|VO58?4M;0;1^$M?Jp1$35Y= zn7fCGUwjz~Jm9Xyem2>y3M?{J?9+boWvI1gpsaB@rk2EX{`8@b~t_btq2mr|-Bye@|g-ggA!sfd> zN*knk*>^S;t_!=J#Y;VoDO=%uv_kq!q`Cx))EC%9GJIh4I1Vl*EpOPOK{a*8@~x&Qd0W5q6GU9khA zu>y315tbAyv{)T~E7#Qi@)6LO>hX-frpIAp1vuafOWHOCN*fo4Sau zrTO7^#Jj%yLKw`h;|9X2_|uiz+gfKd0+m$#H`&YWSX*CTSLSDhkoFTg-;iIr9l0Oe zA&tNtrdCXJ*?ik}&Jnlo)c0^tSs%ZQMrsqIt|aqsgPe8`S$rjb3~iIp0Jw#$@)DCB zbL$;qp$6}JY97c?(hdY}$jB4V0lD3%m9 zADs071S)>Zwr~F$s64&5eu-pHN8YFJ?l0zVzP# zmH!5t{4t>P3!88Nxc&{(oq16d;N++K>xbae?o{d!pq6x2XaX`Q09hGSW;BNCcyXaT zv|9jP*5mvv{0oJI4ql7^5ql;F;~}kgmur!l5eb7Ew5eK#$*&2FuF!=P{c!FYvB`@B z?JNt~q_Ztw>6vot#jzyhSn>sbo+gfc88#Bwo%1<8x<@X2bUT0Mj-mpcQ_nC#RTHg~ zt?Ng~U2=2gmtIN`5>OvSgD6(maP$spY*R&P0c=4huw&o+z0Hz@1*8s9MXWA^l*9Ti z6$gpr6Nju%GUIIAY0iqr?YIY&K2fBI8ngxZENl`<=fd9i0~!$@DQ0znn1v=TMG_LN z$;6SXwKkR(Bi9$wj%`YSAwyjrK`sWu^&NWL8^X;6vNiop)sENHY+4`*bC|`vB|+%y zQLDyu{6)392VG7$2j$(ei*IcZez0WE3e>9=AsjiV>Le}$N&RdX>(2W8??_l z%YHq|5*{(HmRW7*Dty99jnwAhJ45MmVoGKTB@;Z3VI~qgWTMR&R759gc zHz+8kMRvOVX!LOE?@lhPqM7>4du{eo4{kIo1ZeF<(Jl=Dp)p?Iu z5!uX9I(bJZ1xX>mJ~kR>A=rUz6&pnWP6^+S{2Vp|t|yp+Hz4H43*1VQ+fu?eq_E9U zU=Nt#m}p>1C;n~tj@l(EKEvrEpKPK}usZ9q)N&W3&~AOL$?XFJSg&z2tZcBPzOPm97V9%R+>u2`6`xdREJ?=uuh2p zufS5%^zp#d!0@D~W!>!P$I^?Bm?=+sMn(( zUZ6tzlI}1`mT|l8svA4bo|)aZzl|u@nYlA{nm3<_Ohlg z<4gMYZ-UzdP=>DyaV?vt_%L?P#NOh`+Mv{gmSNF2NhLJGmz_P!1f=J$Aby!|Qd zRtI3CQBzc3${-G}D>HY3_id8q$Tlx~kifq7CB(Wd*&bx*weDDwnF5ZDOiUL!o9nm#}YL83CU*niFL z$DSBcUA>Q<8Rr~p9l5hPlHfx6@crdyYw-g=VK+>B3wkyV6bdkG!3pfU1|LB25{F#v z8I-?ByygeE$BT{nf&1yYTJ{xqTyh2?(l?z#W0!cvStlPEs=qKFNLPAYiY^RU}hU$cLkyEfX)lz+VGNQg)s{x#D{8yL)^b=TBMAm^EJ3- zlY{p-!lC~?X2md5Mf2G#BrPnO8;-vBYCLn@5{0mm9Pnt`Bu zFjB>a(M#-(tqI>Dg!CEAZ+j&XA##=w;MU07*cIRmgv3qrUGITT(6N+-K>qrT{s$%D zKX{`*^;ZB%8bZLaejtOx0r)}xb8P=V>S^G7rh)urPs8)2fBOagyU+9g;-&pufS)P; z_RfPy)?p7e{6&C@b$h(rQG$tH^!q zI_W-hkBD}*Jh{$saW>Qun&73bNYNxF6^_Vado-VYc?OlXNop!yCpx+;+6=xQih_w8 z6;J_yb1dTcY6P>RAbCQW-L+GI(zT;)9Gb?U%Bx5x4k4(^o(7(?|EeP>U|TkTx4i$T z<3lCu`#8x(RXpe}v{M(3X{1fs{5lwltU$jNQ(=AetfhV}#*Pw^tEnW$3--*<6AuRQK*b${;^DW)hw8Oq*iDmuRUffe^iRO!K z!NZPI8Ex|;m}bn9GOZkz-63p?o#}*A_2m(>-lDz*0q1NW|4WhPeBuZFtjb?xXpUzx@-q`! z$;`^gLB_~g!Ny9@T2Aqq6a62sp@D8||HOv=dEejI&_J3K!xNQ>m6;jX#l_4DWDNbr zhUVh_Nt^zS4gH)25?~%ko-^@hUNi?g$M3vo26i@%pRMD6AVxF)iC*+PHREpu|Bb4o zWbb73jFA8K7QhDklSC!0=in%0s%KBa0%QZLni)EpI%u*!o9;gon}84UDF9hR&&$*P z)77Wrr!DKVnL9hMxc_Q-`p2K|$jQn|!U2ToPupMn94t>tg!74)#Py_=p7x&NaI>-f zjQ4a5jPrE<=|Aj1BGaGm!SeLn|1msg4H%UTc$=rcJZ+z{^XvRmA)b$c*Piydo~{A+ ze_j9mKfp}=iuZKwISaoP{U1~PpU?by8~}D8ckH#EgV9s*!IS^RUHj((@w2b^PXfX9p9{nvg780=|EU^(t8QRL zGXJ*!Q?Q=?`Si@6>fu-Q{*3#y{#7e~{O9jedX53Cm*@KaZTnQOzs^7HKP^w!pSFLl z$EP^JTs+k@aQXGGrE<2I2Z=>W_{4H}%KD!uqWK0RKPK-{0DWJP#}Uy9)4U_rYJv z`)?8g02**SYl0_f1j@sc46tysJZpicI(?E6b|9(pNlu=QpSI63^Q1lgjpZpWP}YHW z__aJeI2QKjgno(spS9yJ&G($hv#9=RC{M9|>C0cSp6>9}WPaV@Nsj`X4e;zw&HXF8 zKbzan^>em?cm9?AKNp7;n8wrc)JUGTzbnc=74=!vpRNOo_Um4M-@pKXCpPF)WB*T@ z((?lc0EO!J2J~!H^z`cf-?x{iNAYK*zy<840k(ucOs4)NGWeru0G0Efkinnrq&R@% za0~!e_Fu?=`4439e{CoAH*nyOeyD$`{n?)pJ<}hpfraCD?f)#L|4PUG|GEAoQh%G$ zQ@i~0yWlAXP*nb2O#aUF?SC&Ze|#=Iiya9!Hz(6?9}KKO;P)53d`vRHM$P;a$jR!P zD>_>7@i_qP?)0n>;auj@)aR}7IZ^K8A#W63O|0F6VSo}82!a>KiFm?FWXhbs*u}d5=kchNs@{TT=z?KgXK`J~OU1s#~_?RSt zIwFWc_K=`F26CJl0;uF6Wp+x&EBGX*$O+%LMPRrHHkrTz;SG_w2wXG0+h0!jlYLMc z#j%A5;RF?f!4U(CC>(*~+RYKsp~l3fc@N8lW&t85lNXI&4%P)FaXzOX@D^WSloT2x zhOaZx^8tVga(EvT@3WeakHSyGXIe&fZuH}iT z4Zn8l#x!y$&A=`Z-Usadf`VTCn=xd~57Wh$SG_`-N=ymE%PQ5~{8QKK2lh9Jj|^Kj z9HGeYcZe;#?MFu|adP#sx32xBbs6=B>t;8*$p~6CXWV!{W*(OAy}oLd3F5wghvzS# z%TUfCdv)*$58#(HN3%=1tx4A0Dj4&=DS22E>E=%F)vXlSn%%h2Egm_1tlnh^x+bFc znC$qhTcaE4S`|u6%bY<~F!+(l+2!;bRF79?NvLW5koR92kCM#qsu~|xGkA~m3mO?6 z@xIj{6$?5@+a&h$yRKo;!nIj8u7FOcd%ODy$}pCBJfbsTtz-9hI&z4dz;Z{pQm@*( zxdu-asw8?-6l&`&97U&0ze(HiErwniCgP-f&3UlC|FQ6n1N6Ax@PaD1=HT4xR3Hgx zk43F+t1z=7hP$U-sXq4=vmJsum(k8-pe{G1(GT`+sId3ak4 zc%M&dHXGUU^%cAccbg#p4QtmoTp2|n=o^x);V?gtu^^46HZ>yoSk*`o_MCS%%=uyy z*N9yMK^m=XNrdtME*uAPb9h&2t^9`y_@nlwIj4s4EPMK8T@NM)^|e`&Q)M-^?;P>| z?K)ZBBg*gkDwDF%^}0ok@#`=kFXJH_hD5n6!N&qP!Z5<4Ls+yJ4ax0)9M)#f2GDgH zq+z|~!Oxi1D@PRKh-2W0n*?*i51uwHM-1g~95PzpB!KAXLv|hsFu>PPa>9^H=Q5M! z%ab1YP;0Lee=%z0IrCxG2|Qjp0lX~XLZq&SEV7~`n}=1|q`W88z1$H)^Kwsw*3?_+o4t2d!$w89AMbEAr_%DN?Fys}i!gGnvwO1DhNgDd{&@?U61<)>Zb~HR3D`L>$ zZ36!A9^cloH9clmu5-;<2yykehM(&V`YHy$OCp53FZEH(TbW=+mDGiU8|;IJ-Iq6R ziZT;7g|n6I?j-N#fnK$au5)GLH=5B-PjFnBKCHW6M6@u(yKGE^Ulduq8y=akNuDV^ z8osaL;UYZqFb@aP= zQvpVid%EYm7|TyENS%op4-oZ;+V-yAONwqV>gfC4ZOpA{U(c+sB4H{?TwTsBRAs!A zCT#i%=Il`OqYAxP8w<@>hDlGw`2>Ul$t96vB`N({!`8xS4`S=ghFV_91l`%(zBX&4 zH$!Lz9~CxAcO5gkt4QLxn=BZQRj=1VlVbfkd)wAF-rCVVQh~MfNya%^J1-B_YfJ33 zl$OjdQhg^uPZG0|QK7!?v1_{K$FaBMDV2S}MRrmSbTaV1s7DbI&dA#EH;@9{143j( z7Op4Y^%E@r27Nf$enB4=HlRJfsF|gsk^Pg`07oNXBVad$(LX|;C-1~hw+41VJs~ND zKSQB7wf+bKPJ}y5!q`wTG?8d91aMaZ{SMo(4O1MSaBUpXchdrB#HUx;g=Oi7yUBzH zM){wcl;WtXZlWbaNCT7<;69!|5-8p9`wM%u4M`q)3(0up2WZuR!>U_A<5A!4VDEQ=%~iD0UY;@^ugKj@so2r|A;Pkzj%`aYZ4ri)`Q4Z1h=|zz(^Wd_}+}T zbww93Kx%m^@jeT@s!nR7FG$AFwo)hJd&v<34+1{XU8+fQZ-09NjJf?qG1g89&j9vT zcBJ5xpf)Q*HAI#%D_nB~MvnQ&KJ7~KZLsjm=!veIQH4zRdo$rIQhjMJ!=0ZRlkcX zvu-7$@}j;RKsv=Z!HiNC@SPsOC%BMrpOBRKQT$U=cS4nCkCJwZvN8z9+g)0#lNo5S zUMFHp!*!QT?a#QS$hBi5xrndkfGgQN#Qd?hw7^x?Le>J75pY6EP(u(fY7hiDPzV9g zthAqDN5g*3tJrD!!RqUvTOBl~aLS7Wb+Tc!?;WpiLd6~lF0bPp{g?O!Rs*scNDI*f zl9gYt>l(Z%=a@9hmj*bc%o-huRS#{oFGBrucQBto@%AV{Md{_Otu0M4YIo~-W6|fR4blgGu8U)fCl-3)By0r?Y zjXWlc9Du58qSXfyiQe|D*^fD2MUD49dzpP7$&^G2-Pmntx(`B~ z{WDdsUHvoR@3dC7!T7PS8(W7Vy%>)je14vaS-S`xyG&4#XTrQtkY|c#cG3WwU`5Re z2YG~N2FYg1KmAMP|I{`AH_D%j<#*)|H0}Mbm4AtvU}PL8!aW^#9X4g10aY{#n!gZg zjR*th2ilP`6my?X%E))ObG=t8@VP^HwTX+Iv56*B!zUiP;zbD>;=z45Cz3b_dNdA$YbwU$AR1dcpdO;} zL46OEWhDD%s0=iTq==W z@lo{xgEV!b21a!W)4TzLB%H)Ms0yk5SGaD`T}c)J-AR=YRu3i`hRdRQ>J}E`(IP4u z@b!4SFU0V2_mFBnt~CwOX-{sM9u%AFtp^ovnHHaaYi7*o-m&uBX1NJE@+jifN1t@g z6pO^!Vxja8aSbbCY5(XVGvA;1xvm2}kw<@XD)d?u8ZUz0zE1rE&AFD63#J5>nAArH zRQ35?j*zgREfw+gnZ-kv6p^q)mYh2RR|M@w$H;7e{&kLLFr30`p&C@>;<7Bn zb;*PAq~=x{UuPemga0Tp{l4R}RywP2g7Z1e&IhZ@UBWdi%6Wr@K4kJsT&mL?uFBEdc^v*E1qV%lxlA)$1)8_-!V^*+3vGK+0u? z@0G&*Wxu9*-9Ox1Og16gY@XkhW@dGI9)oDxYE8z-KAsI6A%)`I;((>NN@SS*`@iVgXd&I7@)V#F2{lO!PyWVvhorQ7tB|5i68(IGJjON?p)JS4=%(?Mvg|GsD zKuKbi`-aZ9r3KZZ;Lo=YdQh~!@~B}UZjUR*2D zM7{#_ze!BO{tR*No|sjAX4}-CBc)|r%E)4On7_nhjZI~ocg4ga^CPaLZn)xd52T)(h;@;N_a8}YotkFtW~044kltA+?h3vM{puMp~q0yL4^O9NM@+HJqMsBi< zOl@{Zy(qDCQ0kL=1P)#EONE#HrI!6;=1U<-~1>ZLpkxf;1+l;cS6`=g#c2{ozLsqpSI$!TOfWB~Hwrn?ZUW3j0_}A2c-{48#u56B0U*Rv{-h%1zs|UpjB?EgAcCx zwRfL7(4ghePeP!C49G@#A5CDObkH!nV?-yzwx%lRW>qqrVLKXU&_k9c7f8Yi+f8xc zxwwVgnYmW&;0e!KD89~1hIf;yL6(8C3rWrSK~Mw=18Z~%huEl=l}+XDA7K6omu-K- zVuULgA5ZYzzW<92Ds0EZJDe~y>WFrz@R5m%8khV4K?9Rf5H`P5YpO|%A8N}5Bk zoi|{P^vDZ9gkxx^)80xV=Ji__fl5Rq<3+dA7FA}W7Bu1G-8y2&_5xQzln(h_Si){o z7^BI2mLTdTZY;FoKT06;AI~8<;5MasN>GMct_MofXzBy=k(zf66I-&u@&a72CB zlFuKlOK^PX8anrT#yL2>pKyOPyarT@~kV?G~X8 zA3VrMuJE({^EhJW#m&fTgZEEe@o}v-4xR6Dp)LqDJVRBMb0;~?%!tiBO_z%&IV~<0 zb6Pad!|o@XLvO6*ml^h&L_F&YkFcK4FF1$ZTAu){-+R_K9ARB8uC-`BpR!v9&JXp% zvp(-Afp^_((pl=pT4I^u1ltQva+x}vsl+pW@V21mG2Qq}co=0>?-k?n>xtypM1CIc z&PZrxFGsx=z!#ZPhP%lyD)|S(y{q?pydF2F@?OHCbp0OT3RL#x=#A6C3*UtgoyeSX zy(IeQW*KchrZQD&l^%U_HE_H~AL~yp?C$UFpJdvFAJDz*VBC1(e2GHv>HMXZ`NP`m zH!Z^j_(RJ)c@6w;wTvq8LtX@^Wq7`ID#k~;i6^`uf{tR)1Fett55rQ&a`9a0SVm8t z40gr^+NHbWipYwI8XGA&IoFMv7kvz$3aQca4%uOC6|n%2i1;I#jut_=?QU$yyE&iI zQ-W6X$&o8E7&w8KN@Ia5ZBRo8SSB-!R7Y9Wd8 zvWLFSdr_VwxMhxtAdeMVF~Iu@EKz@>4JKCa1&e(lQ>x&owFpa|TkR)^L~Z&&k`mca zlsP(3)(|lm>j6R^0tc}b6PaR3lCLx5Q3i;`aPWC^CA6gii=W0+V5B&O1+a|M^R^gN zX@oaW;n;X{u-CRw!Np(cW5t*&XTPA3r|7Nu6csd)!o_31Q}O97$b~UCkG-SnZqI1* zO$324Es8zDRXKULWBux@H_jF$-D#J^lDV7Cq_R?_2|ffC>I|kYRga+X+9s!2+*Y@~ zd-HNGqcSI(71NUpv(SxH!9@kte~tCdf9&?}bcPMnx2qrFQCTih{y% ze1RdgdDsWf?co>ZPtd;jjdEl6LJwBK6P_OQlt9YPzK5Jgj`Ni`>;M~^&jdNv$Z4rU zXvJm{m+rT^OscxlAVRo#ak44D;6W0N^gsghS4j;RwHHGn1nIB9xNnYOHYyyh?|$rV zHXayg_eb8U5qpD+gCLH8hk*cEc|ayXvZenn3}pXfpwIrtP?8M{Wp`WWc#*MtcjK}J zx-AbbSJS%}O=IuKb-pnB!Qoo)d#7Ivb|VunEiK=>_HM8#j!C}(xTkQB4I~?vu~kn} zurnk%7j80`yGCj(5ZCaVTX3n{-9V+%Ko{7pYQ9t33TxuJP&G4Kr@^Sp~cQsUd zW>?VL2diIRrPT+XUD_@Y4b79Y%MKD#W*6}F%ooa*w|6VG@QTsw>Bt|{7j@?rnfrd$ z)SwZxa;4oYN-L1e_+<78aQk_;Rn=XFIRQG1d}Xry{q_CP*ZZ|?lbbMz%*F5hG-^B+CSDL95!}~2 zK1hsRuX&z%UoP6%94#$>jeX3Ll#zF+$#~;Y2Wxf+)zWL4X|*>)-sbdheU*5~Ff~h= zBzC(3wH$D8FIEeuySZXKB*f)X9FO>m3LK2;>R~ngIAY2ze_4N*_a<0a7MQ z;IL;#8PCm*U7ar5_rCTfov=7u%7Ww=AOM^lABZ*{0(v7)?%oy%NpUVRvXX?~dS!ky z(Wr=Y&(I3uZB5Vdm+IAsAK7mtqdCJ~q; z(x5O6ui+%8R+xeD<+;q>&9+(2oaj+^w?YQL)^{-ByU!Dsq_f(6QIICd^g_ArG0v^> z@mgRK;cnD8fPyx{oXoE71)jdB?7&c1hgEA<8f`MtgAzMo4#gQPl{`L@>kD)WiMdIH zH*eC-iU7%@ioJuRJqh~5IK-iI04PmSPI#uEH+~GqdN&C5`?O&sjp}&;N|}kBnyC&b zDE3Hv9pHsg)0SGDVx=67aKeEPV*FcI(-A(^_Ad?HtAW6+IM zqrv)>KSUWyxrzl81%*eY1XV=}!1nZ06oR@Ad86Eh<+YzG^olDrtB9j3Ghu<{@X*t~ zD9#KQz!gs!BzQsQ^c9YnmJjk;ZkSQH$n_m2Uy7>QYCBJsV_e|p>D;#No_uI|ybQFw zBvHwdi|9V+keY0=+&_;1W*rm^z1OI-wXOO~qr~Hr?yPZA# z@Ls)pmU_EuIwl^rsb-lB8q=`Pfm^qQ=lJ#I@{}z;4FgJbTsoPq`8?%of_u7xX@P?< z;OA2-yS&mTD#pG3KDgT7+WfQGo9befUdidh%iq38>sjrQKJv#LyN{hzf;*I-$vzcv zTxo;B*E4H<+7@%YdTZ_&VtVR`czgr*ie=Jm5%gY@T{{ylM~Z)x$uzSn zzI6;TubT34dvI(AC%x4RMamw-)JIv0hML?|`_wv2+xp^`eVXz6{9+gXeDEkBlQ(u^ z+cf)$ZM>57+Lv{+3e!EM`y$UP`HgO;s|U}lOW`$evM)KU+p9UMaAh}ZLF`G{9O8a~WL9{`XBc9etbCW`0}B%k~K}7Yky1k2ts4BaYqPPou}-vtec$^ojkt`UMa4uojs+oaYr(|iyw6^|8kC?zVYLu=d}lGE_`bA z)p~FHW5wQKMbDQxL5iC;I{FV8t?M4o5G^3U6z)I52a^F-s%eYYJ~N>d)~ zE!dR5*!6k$P3A)nJmU_y`KZp+cSBH_W=)E?d}P3zr1ujaxChP3xZrZN{D5ww>wH7Ou>*{7wnUp_)yP>jZ;yt1g(#3-lBMG;La8OSYw>}pP6_>@xkk~M|)l@ zaw?uUvwu#>(;kKX{({5nuHDTT(~#_OVkMt@@<(D*i-|sy(wbx(uJV zb$sZqyP4BH0~{^8pKsqPj`Qwe$JnWX3nDG9manwDRNhACUinJhUDaJH-P1egKRD8( zy=U0bHnBbieE%rr4zZh+2OHhkIC0ZfOV#i?!Ra;Hp^vsrw3$>puujk4YmQ>AR{tQ4 z1B$2C_zcxId6BYwK!p1l2b+aoj3aapcNRqK{k1-SbLPY1%8f_Ab4BAFm-f~iqt>Cl zM+SUa#McxZpQL{E(8dqFyNtg!S4DI362YpyXV&e@{4uD#O_fJ~o2steZWfrXbm~&& z)HS-@yDqjX2b|QgJp9gjWR}ImLl(B)?GK1FtlL}Pop@I<)+;D#U*<-uw%bZv9~`dS z=v|k;DZ6rr?Yapkb1JW1i5UO-=#3DSSc^dsd$WTp%eq9i>tZCb)0?4c)=f1mGq}@c zb(ZCjlPA409t^8BQM+AJ5g(WClb7QCJU!SrJ|o^Q{P)AU;NihP;)f1*-1P9hvENhm z<6U%Dg?9=&`?s!*p;G?SlY2*XRdDG3^Uja+Z~rd)`>56+bhOi=*b9EVi+H4F8eqdEfn)=69Fi;Af6AhGnIA4=x`N$#U#z9ubUZAby~?jw9SFzN?RQgC#UV7P^=ha*qvS8V@}+R ztseb?*PnCUWU_JcipSkA6}20CZG2^eZf14z(#A9J*ND>%1;^(c&8f`hEm##iE-o%O zx*>dq!KEEWqDUVjk%IC|M~&#uY`(yKnst@atMa^p30*%K{(Nh?CCih$x_!#}?@1kg zZ*p<(JXj^X{xgF!ReeyM)D46jEH&&gK~0eRcKySD)%X^PI*E|1{93)u)-pQJ21jEz*iU8QV>J zMU~T=a@MjtgIzwTB`!@~k~hKc;@z8<)Ou}yal>QX_iNK0h~q3@iY8u3J$A)CMN=GO zacZ$3$^7+~xt)6Ld3>Sl!O&IEIy?wTF(E>zt%W4lG?5s&M~Iw`!{eUZ)2 zE~$#>+0jGQ#LIs^@8PTZ-$UYOJHLB)y8ObBn_miRqhFR@U>%x~xWmov{r9C>owU0Q zXN5eleIvSUxHrh_{oVeFzP}g55BT<^NNBs*UHM@A@5c(!rMUirFm{PFmPGU{QYxNdSYYV!-raxyAg-WxvuZ=2RJQ;L0^A*1&AQ?O>U z&888mDPwxIKAv_fWQtnUdi9a5Dz53w{90FB^g1SS;Xa=aWv{wk(@iWkIHj0#_x6wx zZ(T1Ovp@N4R;#NqPIK&enIj@gYNrNS+dPSxYxDNlkz3wx?3`a`{g9q-lPv0RDMlei#1m z&pyvJ-8$>zi2d58j`01}_Z`}++&!{(>JieQi#j z_&y?QOaCy(;N$|_+>h-#@kOG?rT)Qhmp`6v=~FWzUNh&c%Ds27x;a-XZg7?M^gJTa z9PIse`?)1SOES(5f3kDmsM$5o#`SdwKmY6VrweyV2Zyh}_pLrC-#b4mN!em=6=#C|<{Y3CtZJv#Fo-8SqQ@onHcmA#uTF0Bqg6$6n}&(zeY=}K zTRGcxa(rEwea)*oZ^X&Z98Lv?4}YBebb08{AIU{3v+K0&ZYpL~8VWl+UEX-$O^xsL z;p-11_jaC~;8Hy~FS_@wFA+bMCj|7JH%DXZ75i0pHWsQM+OcU#Z=($*rra-AOLTd0 z^bb3Cad>WXuav~>>doWLom*0ZfC**>^|^^zr*wi3bYI=N|bC`d7XK{}q589RU=bU&k$2U2la4N5Z`OdZh8po%#?&LG?=&qV? zFIqX+x)ml2h!AX04zR7-S~9QDG)UnPFJJk~UEaQ=*2X1Y&POcsi(UKiWshIWE%K7t z!jgb4BW|>Q)2GU4*D3d>!jdoXZQv*60Gq0fB`$^M2Eh-RF0;0Tj;#tReVjgwGiHG2 z`m1wC-(X+sJ!pQ_;%%M#RgZcp2*?#_=O-j6#rF_fd)~Np#>L@U!e;S;ofEhR-5m_7 z7Ph}RPVZigLHFk-rahnc-ZAiOp29uPDThxRIX%jMvD_ka^{?Ry54v9uD&}lmu9?36 zW6XS&YX|O~{;29VXJOaWGai?AB+WWqe&bA+J36K>HHI&|_$?Wq?{oO`(_y)L#Ito~wa zse8Wa!4jjrgU`Mlnr&L)GClIvw(w<%y^gu&3%9hk&R@Kxb>&*$hg*`+SGFqHPG~JR zS2mx9m*h&=*Oi=Y7W3tOIr#rus*K!`bz_FHQq=6xejn|0^f!;#*#BzzK(E|j{W4C# zQ}b8-yYRq|pm#`d`Rj!LI zU6Ym7W14pGHG`#HHpe`Gx9*Rg@8IX0TCh@G+hxqsrP?pW^Lse+p+(EPMl750s{I9Gzy~6G`R&`KqWoGN<_cc}1AR)^3XseA1 zBO=ZD9d$ILt&}e+b0cqApS&!J^NEOXYNPw6aL?*WQ$z2LHpkNzmPL==u_ z1|E2$>$e}IW*1C2>HS7GTtnk)+Vc@`5PYvnoJQ<{KT5k(t_vo=DKwfaQYkty=S;Y}=ce9u=?6#NZj;s?|L$0iDvCSU{;V$k5gxv5S;J86cBOU~E-sEL9puyB z@b}C@w%+ok)BOw^W}aMcc;e{0CvBHTB@QYXV*fDqM&X@hIpm}&jBa`m5k++(?>L%9K=UZUqK17>ue?C-l^*b@K3?^ljLeI2mr%+-UdyR$@V z>s;WQu!FQdt?E-grPw|=bhi7D&u5-TDmwTMYTF~>u7g78i>h;3?}Hz(xIKP7_P1z1 z*mz3>{C4mv(}lVj+ed%kq7wU2iFv5RZHLugE-7D_ZeGK>8Snhcu4qhweyRKY_6M`K zJU3lv>1S9o)7<#X)!|x$+gHyURLByI8`k^l+IZuk?QMfYpS{wVJjMQUR&SZ)@6GEyx!_Q(d*)!@r{~mmKK97FdgSUU^qcAEH}h)UKXx$w zTD3pFVrEjW&>p|a{f{d;%pX)ZM06}ssj+f36grJ6KV?&$^57$tU*~ew;-4z7{+;{j z(e0XHBO8aFx!$0&s^RykfSi;b_hO>j+{rzZS<#(WyDZx$1DyXFy!4|&x_;W z#{Zv<1$A;0MDq(JOoG5x;*9@)p{IVZ68FcTzJtM9wK1(nt`M5FyP7)kWxSIb%e7r= z=Y!GT%fe?bkC_{6c4GJWOEEtOm~XoK(®!g(7FjJW@7ciN-bHUo3pPKa=|vK#0O zSL*V<_VtG`{_N7OfU6avAbLG`sus3*!l{JV`uD}d^BtNlMkyj+8#+h$|)N+Por(_ zF~Npg`To0OZ{Pne+%WP%1z$mYWbWF*&yH|J4ZE+*2~4;$=jOHp2iH_@;;#PQIRZs)8UhGQMN7VA~(#ZBM7^jX2XR?l2^ zv>qBEUJ({;lKE3(+ROW)K1Q$3xSFkV&A8H!pW&s{?NNV?Rc5=}d)8UzW{0#Nt+H`0 zf0W9ab?ddu3Vhu=1Xd5;Q~Q>4N#ma1-4i)Sj|DBb_u|)`wkaWve6gcxxNWz?)#KK8 zxc8-EjL|1S`SPK$cht+4jdcs@>s8Y3X@`x1)z37uoeCO8gbw&<-pa_7@4ac1*OP@B zg$?=IJvScY%~z^xTehRs(H|i{K77?Lcza^?y>AK2hlPp%eEJfX@i);t{6x~p{Xgoo zUaQ-!y0vrT!YxvlM_*z^fCyHtIDm2-ou*Y?p9eLbbQ zBsZm%kt5gIB_(9tXXBi1E4A`WgYR5YzSTdcbgflagBwmxmlSz-_txYz8h>5FIXCM< zha#sZ(E)Ad)DEBU=klLV@2{NcGst&M(#o7K=B5|UEnBv{zW&d*M<>%Dof;Ja9@s%T+k1ZPYO~Ei} z%SX+s;hyDlh6NlcytLty)e^JHZiOj3ELonPHYKjT6Z+zc`oP34r!VQftzEJHkKv3} z3p}I#EYGdAO73CT;c1sP9D^mpUoA?yG(Pxr_S!xJPFJ?>)kR%%p?$lEP>S1u}dcU@-R+}ca9lc^hzD{BGitAr1x0xLjN2P{t+NGd> zOi&STt2|+%PtCoM-BW7jh~C>~z1>sZ&eZkpo)s0HbB3@ri>B+HihkGjTJ0efwdzAE z$4#b9(@1^0xxQaUeATV{ovq)kGBY2Wn^iq}a_Bhw4c;j?`jjgd9a4Fle#AVoG^z34 zr7s@eIA$tFKJkTty=^nfN6#@DKe~F}f+N)hPiIw38u>M8l4|KGi@=+OSN3gr+og79 z@?5{K9jEAjYyHABTYq7KqUy{k?caPi?DsA`wGDT|oHmP<4Z56&AK!Xh&7riowAE>I zGUs)C*ve$w*iN^roG%4gN4#4;dh6%IYsVh`GB;;ekgaDgT*n?XqF=4gGJNl?TnOKHiNERy|Vxv5V`ZzI$5h?>8TG|KNdD zhsq1|^bgl*Owhj<^6lMMhd)VAkIcS&?{m%D!nZ&AUI=Ua@wIWia!%H)3yXJ#-(BsP z8Fs35Uc+0%)luqYiEs8yHEG>(>adv6i#;FyteJYnLdh)Q<48lJIe}_+b)KG!wCwyk zb0!Agu8G*vJF8^i`@I>~fBcSG4_w~))ULNrwxs+}eBk@!lHX0&S!)NjTk7%j@o>{~ z=l_2FRr7L(r)%GcD?3sb%&Yshr#L@+%_QG*!C56g`n~2}o$U~u+!%6t`1xPoKi-@j z*SE3p>(nJnD$DNAe|t4I<5`bJd(k7q3l$rleC{ru|334UZ@%H3^JXJvEM2iheT;W4v5JTCs;SFGvF|R9Skd-k4<8NBNjZ|%*TspT)SRQ)`Y$9GpQ5o`!3waPV5wuBNrzgV0*uYRTWW#u|lI!|R$= zu7yQAJI~hgd)Mi`F1*^1-A*{hHC^D{rpA85*}M6Mtvp)4abD3!W5#8UL9ElKM;gb2 z+C^=y%(-&kJIZZ9R(g*`-u~VnBNRMp#4~Po*j4S;nPaD_lKeQ*Xe6^S^8&9s-4jAtMO*t$@#8Y z19rDj9%|{9(y+d4x=7Sv$)6*dGs0*6MqgX09^;@bFNca{-zX6@pth zUw4Q_rY?E7;b4B@DuUcz+j9=lo%PfC#jHY4EP80R#zjSLgZ=Y0G8J+KojbjV_Q=#poZLC*-BD%DU5;(7c|S%7_Z6D$w%Z%gwkQq$cxm_5 z=FhFn=jd)%i0z%FCo*&``0Czu{R=1Ep5qQ!8LsOPb<$x}*Yy`SSj_CT(sEW*pXj`G z(UJLDzTAYpxif;|mXFieo;$YMU#Ca4{~>|d$2adQyPVR7Kbz|EIToKJ78XSO`{j_l~)ZphrB*ou;0F~Q_?guQI2ps8`2@R>oOXMsy)<{J~W(MK;2^WS-S*wMA`*3G}XC(WjFPnQD!sY=D2_wQ^~d?5GUoKT+L zZq>xTdFN9Oo_EyKT_P~ee1GncOGM%5Wj{W=c4JjdU%uqm`_UOLjlVw^NB^jEJ8h>_ zrt!13Xz1(t)7{o8dh>Ms13!O1Sd9Z0nmdtMV=%zH;HrVVB?Uo^Gt2 z-T#@Z+n9b89%bB+-p6B3D$TT-eP!yE-+eE(-{+aXXS?h74UwlJ`ep?WntrNmdR$px zWR-5VX6mD^@bjOJX0c^o+CBLYaLVkf>4;~p1{X3?ax5Oc9KXBb#`YXNcO%8#<4ix# zSn|x_sk*Oz_SIQS9`w7o^v&YPa@|0dMr!G{-1e8Um#xUV+{<)*N?b$9>Fr}Ht{j~I z@=ngDw-0{?E?9Qf`{n*I?wpkh<9Of}%gI!r&~eFt8$e^@oZL8O1*~)E#qK zZlXEzTdCUkq`Y9gm%k%xo~Fk90=d0QuJg2C->RwNlyB$L|9`c1{;Ynp_UCr-Ec||K z!hrNSYqgiYSs0mQ?KRBeSs(YhQ8r7U0)O-jIDHLnrH@WHvSv$Ct1sr?rynn7d;E

PUH z`UHK@n)9ul=8snuzkeOxd+g2{vm~cqhhK*E3SBCSzw_Po`qS*vjNhF^@ueXd4}M?o zd!}K--=!Y{yIurehhKicI;e9jsB_}M4-5E-DRrL1 zPaua`x}WX4ahrDB-EY&CU$l4jxK{kQkM`e=>{c_css+l;TQV<0h}lfug6~;_Z@&G% z9-!Op=Qs0|@|6qMe<^g;U%Pe1o)HzUdS$7dx1Zy!>^JtD&I&h`#I`=qme>E-QkN6| zO5^_eeqY5~_0}%a9&bA3M5M0f?$NP&f5OckH~jsix?!eG^we4l^X$LHuF((6zUi(` zb&lO>+v{D|`Mvm>V;c0f>4x^*zvS!i-KuduVOtLr?u##5HdXuj;t=)g%R`Q{wiec? zzH`csTlZY=sddil$#3`W(Y{xocE4P6-=j4PZuM9Bwrovgs^3`KLv~O1Wu;Ah$g)fx zUOvcU!Fa{78u2!ZY&3N@3lDt{ur0N+we%Kl4xWGL!Bv--1;Tpn?z=wjeNXWF2xGZ| zK6C#}>+;93;YGlS=Z9|IhIO^scD}-Ofql+A&^r@XT59#lSJ${tP^_2GTYG%`#O#dh zg{fznDr+(ng@X1^Ma+=AWdC6zAT(ckE+;5~C_54`Xp;vBICqJG` zx>sdecjSkEwwcP9SkphZd(N94t)_A!OV=;`yRYdfw_q*bFIDfg#bdpnvQje+8=Z>G zDi(%~d1-GK5Tb2hv}o%POK+CSOC{U)PV9YwcSXss_f};UyIKd;8t6S8P;+F+>$E%5 z4~^B(-93N4{*&nt=g*Hl^qE*w?j3hTb+xO?QMT)Ot%==>RgZO;^?vc;;Dsa7E^ln7 zW#E_YyC=AkUu>k^kaw)~{w32SVRiJ~F!$6McGnKv+&y*m{bNB_`B^h&IMkNc@7aC- z*tF<1QNE?S;d=@`Tprr}(es~0>vtGwd#k@V(kmmpzOmtx$@Fl}yp#(e4KKfymd^fQ z{`-et#ou$`pFaPnTHUBnE6R?KTAzLAMD~{x*&g0IinG7@)7h_nWhJWSraH`{<{O%H#T7Di#{@rn=?XKT1js6AXzAGWEAH zd98XN^iQkAY?VE|G-|%xRLS^LlTmAs;bG-(GUNBniaPUU=l=Y8>)^SuG$?#R=#{$1 zwWqdPUp|qTcq6VddYZyF&kH3cUUdhP>Z;W)irh!K#}hi` zox5|tY}ubrd58WUvL1NdeCvg$Po6w``b4F4a?aR$27;NJe7D3s%eLNQx~^lV{<`Wb zb(K{5o=W!ftslTs7U=H~9GEi1&OdUc;||Bxv!b318FR2(pkRUB39D&wyYjeU9`$Dr z)NQ-gt=-6R+n*>_&Kq^xbPr1{@@%`#9apAwR5}&8aYv=;r$3ieGhg3dDdylJnTsfzrkXT~QtKp8g&s=@4$BeP6 z?M8c+PMGYKURD~pSjVw@YJA5k>s?+46B3)idadI!rESrc`nsQsQcoG24IMqJ zjX@-f8@MTT{iJO__NcwiS7>{^_3QkSFZVTq2DD1ZU)<(Vr~8A|bqmxxO&*hJyV5^D zcBR(LRyA!36P-F|DZ2KUs-HQ2&i;Jcf)tC^itY8@r+kdM$W<)X%XFNRnr{(Nsia+b zFn?UZ&XrmFZR}g?v>$a=C(OXrgd61k?yBY}^-C!$W^MTxId#mX2|7vLK5Y%WxytDB zc2~P;83}s^b)CC5-!5{R&e?9Cw$F7G81Cqyq`WGnTl&zlS%*?`SAOU*bL_^kmsAz5 zj#J^c?!}2o@oD3neavFuy!hxBb`LHse6gs1ReMoKf7Ok*BXc5^v^?JESz6B-m!Gu4 zOuyLUOInY^PC6E!E?g9^+o5(rKWXCQ^mZ%X*?QJ?vQ=GoQDca~a{e6iIc<+SzOk%0 zFtJiGLZ{vBjc0?}x$IK)?v`r1Y4o?TBRW{97PTwsmolreH778}Lw%4>O{P*|JN2H9 zM!mbMu3Ry_by1tjs3p$b23=Kdv#7nH-D4BOwjDbsb$8USoY*R-RX|t!N>S@wZMf}= zI$c%UsQ+l;R#%IKJ^h_myeeF2)4eR>QCpwB@QMCsDxAn;Kc8W(%8q#1rk(bn{lP*f z)x-G@#@QS;Q@E4YzMs{DDS^Wy+|$a})jV*I$>jB!xYVP6Mih%Te&n|7*-k4RM{ese zbv}1phDGWWy|1=6JlB=jxHwOCDLMQqJB2mzQq;QB_a6jK+#O|m!f{B?>(?yA)AR=0 zJ#2HQ$msp^2KM)lVMCVA6?eMEeT=n( z$)ekvw!|g`PPDO(3Y@q&$lhc~|3oW=E_%-m-xZplIPr5^n8~m+Sv#X%ri!}Hh^*Hc zV_*@sXe6hYPWWZl5FH?(`T{Yr1F5dS$cEAf8o!D2;Y#KMbdbYE7&N0uU6P8;m ze!lv|aFD5;PHe-Tw~>cBdk#*}N_`i3*l(k6Kff41?fYu|4+hp;Kk7bUu&!8qbqwD@ zXCZg>d~u=@+Nx*w#bZrYkrrpVsgfRC?#%6Y6e^-Jr1T)@ZJVrNT}1ZL6IQsgJp3 zv(9QffAgMAY8&=>?X%ErtI@m6W|>tU?{ng&s+jk4-Hmk*^&V4dD|WM(d#pO5jo!S! zYYW^I;(B-W8+9&9YtmA+@BR6Yww`la_-JJ-uS`Yd$*BcrCoBJ)m#$bkDU0{9Po;6b z-->6gF0@|W_P4^%4G)V0U#`xvQf#$EWbtf_*O*R5`l-4G{OM6vHO_<0rl(pPeD#Xb zt{vabAuueoiRL-z<*f#Y5U z@4KqEKZMogEgoglv3G&$$weclvJREajU`sfky^Xm z$&Wdk-)Gnye7eWU@N0BbV`f?3?N2OcoqN=f{&;FP@h~Uh;OkYRs`hz2-nwhko3Sni zbyJqA@uJNVjIKVtJ8fWB!SKWW12^x}ap~QELOOS>O~*MaykbV__S!K>y$!E>q_gwx z72LJ!8f?2~IwZY(q2ufvxxV;kUf;&>XWk3Ke}?|FubJK0v!=ni-4X4Y+36J>f`5Jc zP;oPPd2Zw0@PedARWpA4G|USR`groM|MRt*XYEnzYaoc8^=x){$ex|7NhLdmJlwx- zd4W~>^+x-~s?A|HpWVJ2;_IAbKWur3$(ZMRLMv4Cyc?@7eR^A6UuD}w!VXx}Lu6_&uFni{O3x7j`bHiOv zj`+N&F=WxZKOc+!6#X!+@Cy$qv$eC^Gw092+#kuqXFhwXvfnSgab<1PnRWH*IhLQ^ z2QPH_t9JGKQ0`6PkKwRJJ@k9%9l1P3`gKAMuj!?2t}$E-DVL@Q@Tit>|;;Oy|*Q+eX>Ab?W2wH1CFXwwllRhkj4|t~?7WvuWL? z%%;=C&+Fz0GTI$i>Y(VTvHDY%)#`;)6e`-Jy6Q#PZ`9i8*1NslYxMzoy;_Z&(5lS> zqg8D_WfWYjhjF?oy!VAw76)E7jH4`SRN}^?41SgDUEmpDsyC zFq^Kq;jU{aA66XvzyaS5ACHskfaW)??B=<{H=&EsyA0#u5=rW^Rrr_s9xV8mx{MP3 zMLVqM_tfPm=)OSeGnb7R=Xm&xJc|CMuIqz;X?OJhREOWw`nYU~KKSk} zsyy5Z3IEQ-u8O5Bqu;WypSNHhd~Lg)6-Qssn#S20T0`xQWKs{>?ODqRaqK>`x7bkRJ|n-SAZVj&wnQGi)577CDh`VK`&L7_m5Ak2EP&=^%4?i7WlXQaf)2T&85^!tfwI!sy6k#@1RQpA-jYU>m?8>NPS~^lN6sSC~13IN{H%6e-#{~ zOGp)zSWinCBfIGDcxR-Hse%&gB~nyD%z8eTM-{}Z7YNzNRQgJICh9nB1Yy>L&yYLl zyQ`a|kS^-#Ye|Jb3N^H`r0tOr08#2O>jgqCrCt&_v=o<8k68~=lzPm1fGG8Z^<1Q$ zx*@5_2p&=|BCO{j^&&~+&`+dVLWH%wK*&St;Zj&COe9j2dct}>rJk^!PpK!Y=OgPy zg!Oz%Jz+f`si#)so2(Zg^>EiMW`qE#7ZcVCka{s;y#T4F^Bm(Ls&~*SkAZ}gdct}k zrJk^!ihDXIHWj4Q6V^j=;_&E9Nn|wCTx3R*WHVznBsM+^vK1e~t2whZ|C+-g1Iid| z5ifF{PfcUQDScT!OMDM}%8%%%;>!0*c3in@zbK6h0j49#*iG!JyM~ zn2?fSC|c0{$y7`+7%IyIl>|ePz+s|_#$Yf(n50uM7$i^0P|7@)i=taHtTtgNmL)@M zGe+4$)C1BIl9RZBeg>cF{&a9LWd&50poe4z6QXvJ49`s%m80pQx(TDY2R&>zVbn-O z58(`E%tiwPJ)AdVP&diY-h@$|k{;%pFchtlA-@Tu1{!+!XD|^P<$Zc8(1cN`lOyTm zbQ_4cD5rBIy_~_oZ{T^{mm;dZaD6rAUlEneIFhK6l%-M^M-o;NOoRpr4&e_G3S};b z@Q0YP1uhtuJOgGEVm6v5a3x_yb!!-tkUF@dni8WhxPKW{mn*3TgFzT@xsqxy7*$qM z4GD&ND3>d#27^)hB-LOr)GS;{H7JY^A%!qWH6$1{IPfIZkYIe|avoj}K8JEI53dIw zCVxl{uLmDIfiS!te3(`s46g^3?f|3eLF7t=Naae}Di~}f$&%0J!GPQ}4QxuFsI$`Z z%ci6%0t*4eTA$BDwS)iR7~SERV56VM7g2IV?F1YMKn@dZl$?Oar!c&BVm_5enP8*j zVCF~Z!@VRHa3EqJV_~+41w0DFy#yFaPE4@T`UE`iCPXDs7R{Ex#RO)I+JJ~QF?G&Qh-ed2iGxE#8(=7*643?|ebn}Jv`JzEFjO}QeV}7VEJBkYj)X=uVW=Jw zIzeG@(>h8p90{#pFdk}qhF%~afgI&ahF>rkRThgYkV6w+c!RvT{SZd!!~6jl)%JX> z_alsw!~B6T6hjQlkUSUh0Qhnh;u%8pT!v>zC%YLlG&5~JqJP#j}9IO zYR4v{jfe6(o1wIfH4q7GGTL}(_-2#Q#zWbTO-36JjY(`W+IWZ$vB_xTq3I8VKVcu@ zpZ9FvfWRuYb->HKz zEE_{Rqm0TXqm73mnoULq>ksrsN2JK;J}iL>7Zd2f~PY@DX=r)8D+##3Y}JHHM$i&)}mB&1MJ+ zgQ2#fuk39qi)b*L;k=9-sxQM)Bp6zkU^65|f>HiuSPFxox-m3Gf>CWRBI|+ZBwIve zV?N5VY=)^w$|4%UX1FhdQMM3q#YZfY%}^Ca4#fdORTvD_m!T>QhHPf2iUdP6kj+pP z35JLoo1wrGjPfPD0@&21h;gy$)j$RlQ0>gHV7e?dTVXR)MS@W?EQYEu7_KH)X2b46$vIrqYpz>XpCBIfgs19Aw>BF0*1g)-T;RnjL4n{ zk()h*u&N@lki!?sW>55cF&S(^m=3@kgLp3F9GGGd5OjSp8EHc3`C>BAjG?k(GR};} zVt|Nhp^1-}j4}~qVc;eB6A?EOlQAX+$|xp7OblIFOh%X(#yT+>U}E${GQMCL6dGPK0hkVJ--m>Pb_&=OO_4;flwD)o|~ z1zv;DCqoO`6=6hZLBk@9tOa6SM!Uqx5{c&Of7&T1c!~`&E zs9{(z^$h3;=ovUM0XZsVF)WyoLumphCP)s|jbXuz9AzKw4(M3aGw^xZ z#$Yi9b0uJ?Za6W4fq_czI5B~N0nuePPD}uURWiWvm;wyhf)f*v6QNYe#r*;6e^gnb z9@NAOX7IRu^fUw~CNLmTZHf~Uz|dkF8z&}!QNt)sOb|xN;X@%{$UdByAUTwxabm&; z3PH&c_2BbSyWqqGqD>&IcU_DA@r<)q_Zt zsP*KfO3>1rDn($S)I^i|J@iDp@%i9%F;0S^Zs2nBPN534?!))NiRGRa*UV^Ej}!^ilrh;45s3Y7Zrr|l8P&s z?un(s3T6mmsi;B&5E)ePb!-6PLmp5|u!{^S0UBBestZzJ7r{LM0=o$60T8q*!8`y0 zQwib$5HgkM+yY=#VuE&n6j)EN4q$~~7eP8WLKI8{=Ku)lBKoxud7EGy!1R!Me6#?f z2aQAU4d8SLB61U2_z)9p1EfGbK{jAZ0P09^4S>Kdf@%N+Mi5K`HV)v41kr$v19&3A zGXO&B3G0nvS_|8Tc<(Sq9flwoz}ArwMBAe!TQNZ~V3z=#MlcM3Ko>zUVB-KxW%fSk z3?M>vB(sUp~X5)<443L+zjwim&;Dkhi(2PH6AP(r$}>_=~g z%gufwpm&mqBCHo z30;u=MPx*YAkjl%QVP_Q5ha2Y4EhKu$hRUgqD0U|L}WyXAi0Xjh=Q*j28i?tWEl|| zQD{~uA|ndT<3wacp=li0hT8>$2SCJx0|pO(2_lOBMJr&fQbG8gNMF|psHX5SWl1#fWUf!Jism#SWl1#fWUf!JOBjN z6XXFPu$~|f0D<)cc>oBkC&&XpU_C(|00Qd?@&FK6Pml-L2m`wa@&Nl_P$7amz)2A> zl^_oQ!4nDc01#4-w>|7dK}!(i0U)Fck9&Zijs$rC2>Lw19RPwpPf!Qg)`C7yFb9Aj zr4YmcAV?_$ZvY6X$0G+Iq@J`MW{bdxu<(VmF-SdWJA4^Edt)M^ zcs#Jzn20EVi~+)XGe9DM@ZQXWMQMQWS^>lX2+yPdaRI_>1rQG)+$R9>0m6L(4-^1| z`vg{_P(j=$uqO)vOGFev5a~oj@!{+RK)Ce)K}RAYiqAudhlnVEAcl#E0th`3x1P^K zU6+U`XnUldupY4)5fM>*9t`RtBBJ;_;BF!!qWFlmh=_;+2-Fi1#YgLWA|j#yLb~v_ z2MFmRtcRum2yc5n3LO!_2LOU<6MO(5C`j-D_(p8V3Ipso z5K>QC53>Q7ykMP@&qqm&-~*rvT9x1fd_MF*Sa%@`LU)5H4hew~1Rns_2kHqv01zsO z$2~w$A%YJ81Px8_0bq*=!mWp?GMGy60Rb1t63nwOy98AD5_~{_b^&1Og-fA@auLA? zU}+GlP4EGLkQ8n`Ku{rq4+vm@1PE_?0gMy?5!OR?2MCWG0a}oPX&h!3oaRDC;B5~O z)REu=uzm+d5PX12U@%=nx`^zD5P8`T3N&Xw0R({*^QC@oOhl9r;z!?@h$w&{`wlk!``4V5m5kvdLp6#0`){h0R-xah!XN)smGXzD1eZ9+$R7b^|(&} zLh5m!0EE<&)F_o3q!g$pB1(uzx-k(^03r3H^(ey= z5d~66J!w5KIb$-S5Z5*)BMNm&V=|&p4>XpFC^WDU3{%L57&a#OfDln;AZ2(R5kEF2 z_y9;D^+ekv<_pw~EQr(-Z7+aC4Q!5(f<$dh@Btw@=wM9n0f0a~!3O{W^#mV)0|TI* z-~#|5^+ekXV6JRT@BxrQ>PhQi77V-ogsCv)H757~97h241Rnqh)DwIFAW%>60f0a~ z!3Tr_*tsw!_y9miJ!w7awFDmkDWsmX9`#y+55USkQct!$>a_$P04Y#U@Bx58J;4V6 z0`&wR5Tb*`#snV#2&pHnN4=Kd10aRelh&hNOY;FD`=Qh=H~R^oPfM6DOj!gn*$@3* zC>2rA=Y>)c1;dX}Dx#pz3#B3o#x3+!_K=z-kA!p2NIlsfpwA1XA`1FE93dwQBK4$C zpwA1XA`1GvP%5IJ&kLm@3i`ZIDx#pz!!i=_MCkKEGNOdg=iyK`E+vFMFC-%ho%e?I zCsGQjC#)9&i-vPHgcS67IA%japq`8$ z1Rnqh8G&1Gj6zyS@Bvt=LlADgF`P}*hl8n@^)MnsM#}hoI{cd;lOMg||KAXrzm<9p4*)X*8bt5`U}lg~2tEK1REXdM zz|5f91Rnr`g>>O@57bEr5FR-If%OC*0G@;j;?@HxLQllw9x@D6h~NVNfvE%^00`J0 z!3O{WQwcr*5Im9K0{}ro(|mx)eyBe3vL6%>Hf29>xpelUelH**3Ls;B0TEFEi2%YQ z3LuDdBBFr(L8KEA1rS6!5m5j^cOxPSAn5Z%L;=JH2=@s<5Y|LQ0R&xyh$w)dix3e7 z6cqX?5m7)v!7d`AfNz3&BBB5ST|`6y1qJJghyn<#Cn5?Uu%3u0fRK8;KL7;QlMw}H zrvM@%3XbamM6^A;q^1v@3G2;3dciI-qF_%DAbd^=Qs6W)qTsL~KzM%uwv5yhZO=hD zlHda%1=S|_06<_W!3O|>Y7=|_Xf~)P_y9nlp5OxjfqH@u00im@J^&D?C-?wB(5eI< z00>%w-~&MHAtneu01z||!3TirL*o#903fiQ-~#}G^#mUP2&^ag06<_p!3O{W>j^#p z5ZFcV0a#rCBM3eKs|&~oA{U|UP2dT5Oz@HQ1RsFm2_S+Gz*q#j2tEMo+DM9s92j~4 z!p8xSf;tj>03fI%!3O|>RweiVh_D`5BtS&mqXZ_T`2dmqP^ikyerQ{X zo`}Kb9*ovf%okSJ+4?X|#~TfJ5I{tKKr;)Nxf4GLVLfbC>I(=y0MjA_;nu_c0H`PU06?Ig-~+Hg1r;Lr z0QKUifZzkLWdL;~_yBAfpn|yd03j*ddVnAR2tEKC3lIPVAAmJ|C`j-D*!4nESldHS zh7nPK^8o~bhj2cCAgDIZ2M`2C;CuieAn5{}4v2ASATSl@0|Xc9)vAc*XT5INZo6=2r=;Gh94N|V`-{yi*$ zHODYOFnxt1E+oVS2#Y8r#RrJ=3CuHLsf;XW3=r0vQ9%(vSZ_v<7$9t31Q5(4VL^@1 z1?h>8M--Amc9GV@1OWy;vLM)nM-(auMo2{zEGocC98nOM312Frpt}LnA*H|wsfdE$ z2l7KoA-l+kg5(M(XhpEA8^iwupZVq zU}=$rpl{)P02PGZjPn5mL3hLX0D_={<9q-?U_H(U5Cqoad;mdUJ<|GAbENr3YKl$yW@oDU!f zjKKK-g1`ux4-nZ8Jy34;Lnm+~b3Y(Q((8Vp5Pr`mBMP>O03vGzvnM_oQRvVPpNuFp zq2iMfh1QGU$SKiikdI+Il7LXYB_j$g4#5s3DFywMj3{(C2R1E9Dd?1BM8PQ>fJmR9 z6ih}GIw=F0HWA}IycmWn8pT%{rkrV)Iph(eiE zDxy%@l!_>rlk%k^3MQa%0R&+L%8^nLg>od$Fd-&j0t(yKL_w4zaXx^gz%HB*APC%n z^8tV$@xW3Up$ifZ><;4)I{O3ra|DFK1m^>gt5BHWd;mdUD$WNG1g7GA03b+Wuw#s= zhZP2-9*-P!K?Oi~+yewni1Pu+d&p@xA3zX#B5plEP;HzKASqCf^8tWR+v9uyL7)rg z0{}tN=i__;L0}io2M`1m!ubH?V@ScUp@>%-rC>hJ2aptcB4IsB!F-$#ASq}_iez1jYtOoJk0ti1Ps`2w52pIFnM)gg75SQV=;bA0VQ1kNKO3f^<&0Yugcayq(gm>5oDF`1P8Bu6!4c=Lw)2iTU9(FqPVaV z0}yUKOrD^QL`1>t223R)3Lt1NoMFPK3~7Kz@Bx58J;4V6f;tj>0Qw{wAi{ch=?Eaa zKY$b}h_^jJU@E}}pyz_A1Rnqh>>~I8bY}EKN!!y=j_%mtF?@i5Kt00;BoGP{h7T|h z6lC~-1VZh_@Btb^*K5Gb6LjP-5Y&<30}KSFGJHS+LGFfgNkl=)2*P?;qXa2Qy3fK+3>PE%)24=H|M`*2`&>;3?$a)5-|mlhakLO)U{Gg*BDU+Va(v@H(g`IKsq3mjNl$7m^`7Pv|l6`tWX&PMkl0Z43(ul(}cn5 z4|A7MGlulhb!f%}`pj)c%@{mG5?jp}JVO#(O&APo%!NkH7(7D~Udp)dQt>31w)OL(h<^2O4-Jq@hU;X6NvB8fhQ&aCk{x3WH}z zctdkpc!q>HG+}7OkT8d444xsO4$T;PhEzRZr2%F<hJ-;hWAF?Kg^;8hm}5e=f>{!644s1jge480ghn(;qW4?jkSr;QUR32t zs6*HG{Bh&fIo{fzY>^m}^SMFyrMiLDvjIW?-VO2}Egt3A<(xJxJoOCJ;tvSSco& z0%lNr0O=lN51J$aXU~NnY4_NJC6e&6N3ygl?BM~DU>eJ3iP0D$7O`wRT-@jRdh%Eh zXsq#mL4ojr<>==#&n=Y28si)2;kn3#!dzIB0z4K4G|7zi^_=JH0V?S}MXQ9}9X_KH z5+Rp0I>f^*DA2{#$0LB{zsPU#Ja-RwmTM?0(9450&fmj#!dRBSi`#q`Po#OCdx)i+IZOoM7viP9EFPIhR#|jGYV9g8E z=SqTKA`CBwGr}Ae59){NF0pD{z=8>0EEivQ7W_2PBLEeq+ng#4Lmo%S6h`)OSr$R_ zd{9%eTv!$^0rT8gP&X?dc)pE?kB=W~ir*q1cThr)o|F=pvKu#<%VBY$y#oSWe0-q6 z{d`$|a~WG4nHG|CKdLY+aT_Kwy)TxrxRk@P^9W^G`uVzf_y-114K&eX(SiV|869R+DOf=i5bhJBB6H_?1}&oE%VkmE zJXFa5)@1vU4yZ7l<>j&f*f zfRR3)ev9S>dM$uLSa`uUj-aVl=n*2qKBpiTpLv0y$ORKT7A>CV2GJ==K9q%ULWIX= z8U;;y#w|u-9>My|-KVq|9GM|{7@sxDCD4U6*3aF;2Sl-Wg2PCnCXEoe9J(4!=Cd4w z7Ww-HfE^MlOFaNq5BWqC@~AGm$i*#i-eM0b`k(-v6dYNQD8LW}8O85ZQNcbdt0Ba;n5_^8e^*YF5FtEZya(CjdW1$D(9fmT)vZxuE2sBghLpYDU4Rmt1Sc=tt-NrS(&j z2u7af$h5e8M^n=UM*M&1m(&b_k;i&|3von^^o%&%jsZd5)a~Wg7I!foru=?r6-lPD zgnP+eBd-@w<2qvwO|qG`mn%+mVtUN@XJZn+CC!mnTZ&pR=HRuJ?<;CNXT&8pKr-gb z%W>35-XxEk&+mt}LZw@i8pxaE|2yYW6=dXL5TtknWf0O#sh52Q?qGUB@xMyoKE?w2 zAJ4#hFum0CU(diDO)uR1R|(wJSR}P<6*ZY*T1#?+)qgyMn({Oip%*&-s|b;}v2pev zhT*9j_PLt+=s$|!xm$9N>3`d>wG&%>VB|5AC} z^{^xKKNO+nkxg~MW)CelF*Vz4F4CMi|51eSJw5yXkLpu{Xwy@$jP;MF5Wc5p^8fV| z!uRy7{=bUgy&e^(hmC)jMfjd(0sr+3!uMEy{Kr!W-~Ufj5NZnF)WkFi_z%OViGFjD z|0O6XKEM?DpXOf_YiKI*KRpBY{Qop#qoza5Gq3@!b%gEfxThiHyU^3$=G9uK)xLdbL1CzL|=Rnn73uRX}e) z$P^%YI$md}g4`z%IbON|EUU{r0rz!tx<(a%8K#Uh-ocxDE4m?9-W-+Ml405h6NjaD z^x}?;cHG05IP74ccbR0w@otTYgLd@Bmy9^xr7>}s>7rNVq{XS7MLD)3ap;6H;<#(2 zw9A>jQ*#eF+L7(BoFbzgcdL|kFi1umcdC@Q91c!RYvdRM^c%fUB%@t^%0^d8qf@#v z;w^X;iNnNDM!aROqC?;^;w^g>or{+er#HjoR~5ZIAS2#_SCQ?&2W7<#=y>-jP{njijK<4h$92!Ye%PtWyD+XD#SWEr6VKWf>)6^4E!?UEqE1)%aUh$ z|4)wXNE~({q_txkHKS&b?T!u<%80k%RnU$$?q$SV@G26A3@0PrLSIGV@JB|x1+OA; z*~CHbP|9x^bb3fedkbELh(vpEGU6?G6^Y9x4tmS81!G`aS4MjaeHE&TcE_c~iKQ>h zt4LfnanO6Ha*P4n(ORpF_7=Q~#N{LoikGyYT~6YlcFkH42mUN$Ov`;0Z3W7Rx8POq zDEeYI8Sxgp3WE*$G94N57Wyh^M_)uFBi@2nk+_`1L9BCOUWImt?<$eePAqdtiOWeG z#4;Bq4pRu&rj*r=_f>4(3iAOu%TV+NHRDxm(hA~omH_Fk>n3s3sx-NgzlKI{YBS>4 z0!T~ZxK}0Lzd%iIp{ShMExi-YsQ>Q;MtYOHNgiWOE!aaWa$zeaFp-k8=0+c`Y*LRg zEHw3$6K3Qhmy|pNk91g)i(I5Udgn|=9?!#g^FUGb`k{91dg4isQZ|8xvik zB%>X7Eh&!fg^>}*JqzCt(3EE>*UGjfwW7h)RmxZJRa>(9ao>`aMaQ~j%)woYtxAJ6 z=tW=|aon?*I9vlDUmowbm^?a%E>AzPEQQGVsag|L=ti+h%k=gO@u-eYlbbeVzN>f*k|3$#>Sywl?H=oL>n zqX~7sxP|(nyOpGylURJh^`rKIkyS>XbT6uYb2Pvzpo~1}-e!5UmWnRskSRd=7b}1k zBIOkzk}|#!iB@anunuAo3a>J?S}U(WOHQWNgXP3Db%w$MG&ab{ z6Fpf<9_Fqx@E+*|;BCTDwueml82PDy!~70MVy`nXvh86@`s zq?4rz$a@0moV-e|NQeHN@(=SZRt1(prIS(L~t|VWsN$)?RD#J>Zv_-_? zl}rKI^;h~;>=sRuolw&+YPVEC&gKpM8h48Y;0-RBI*@)QdIGwtLq?u-Gy2pV*s|P^ zem%U|AVOXaIi%kmZ$TctbuVoXv5F-{4$&)DGV)|kChS3nhh^l+j!eqSZW+_>t2fyX zp^UeWEFq&`W^YMeP6$zFw_A`$cLB-RkNcOTlj!SJWW-Sg8TFVr>N9fX@lK4%BX%oS z9`D4MJTw$Kr!Q>|m1$ctN1i->y4QsQ!^XVhUAMqFx% z4Bd<)Q(Iyj#?FXA>&RI`q%R3*Nk5$4m(hg(w0H5qx_yVCNqXDjIY4w~vqF2bS7zl?q~1~th`^>uhyFMxK~tNy*D@G0>NNwO|jrh(Sg_;a@5JaO_V; zp75`fyzHVfeTP^}_Q$u%v~e)Nitj6BhQrR3%G zFY1N!7VL*FPm|UE5C5Va6B&Dm{!7|}zL;G`{vZC8$1;fHR8s9Jk7ZB;R!jAj6aUl| zY)$gmxl*Vr`g#Q!`w9O_$;)op(3iKhq+bqqhUp@f52f_WVYbwwYzz9)h2PTlQ+GhL zBoB=zBTx93va}E#?3obyzP*;@ zWye$cGQO7NWlvkuH}$n7FT1)1cWV8kec5Iu3{ZbrTP7bB+4`9Tl4iliepJdD-TuhpS?xd8FCp=8b%Q9Sz`jg*32^=fm`kJPU) zUvTT3!xby`ab48iY+qQJ%;08_5exrOfRXZVSyKkWNzp7r}4$~6?vS=dXUhu>Xo-b(e6_|A=?W-Dl*#uX=XFmuCAFnWBC zp-V;R-}H9GiN3p1jAoYfy=2qwvA9Pwy*hFFzV1fiy;SROFWba_yq#n8y>K&qVM#P5 zOZh2I%BGhtX84aMNHRZ)UZw9BE2E-UiJo8W`!aJAeW7nnf#>)yHb;tH>G$I?1mj06 z^OR8T81YzKZJnN6JMoj~D|v~0l|DX}_?aGSoB4hr-{~c{IeNF`(=%^#^ll!eH{j;z z-L_2+#LdyWK1{F2&C$Dco1T`NqxY3=dUtM)-cS3cN9kthi_^{N#kx6qj}D%mvzw#$ z7|H3ayE%Ff_n02So1u@(H(B4>-eZP7f=!HG=CA5=yjWoL;yEjQVQ;6$_h$GhJd^2V zzB&3rpIf5JIr>7M+5B{#iSi$r{d0etZ!!1%LO&I~((gwyT>HMPze*p;f{k9*-$Y;N zr(7BAlbW!eMou~V{ss9)c08k(^*8b3ktfsJg)`&1c6&QLY&b(t`a-=y${Btl*SYa8^H=*D`5=wHmv6hz(QUlUy_%lCJhIc>CdHb>Q%m;sUb^k>%IWKo zE!@a^;VOCL!p!7?S}A#P19^IG^TfNHGZmiy^c3fjT=!jpzZf$jScL!!NOF3^^Z5A` z=EU2k{(TXwexCh~j?w9)sX&ENMcVAG?b=l%*L5bq7;@29XU zr7sMFLRM2s_@m<=nIG)?GI2Zlh}kGBh=98akwLYrAg)zcA(mc`+nb)SKaEgF9~_kx zM8sW%;Ha!1GVUq_M}#!*#aPRww`W5%Z0s8+YcbPdE9l@(+vcNK!8vcjC0 zgQLP0353!|4Fic&6IuW%eq4#KIcA zOx^_j`_+huSnD(&gs$V~;L!Ymh{sv_h|Wm-#A#pQ{sTt?#i-~&)x#CR?lb3{DsU0tTm_rljQCx}KamIrLU3KJ>2V=|gLGrqH z^vzwUzTZo?qYwYZm&7m>=fUjA8#@(!FWip4u~X6a!tLmT9lyVPV7kq-Q_=TRxBGl! zr=pj++xdg=b12N3##?ptF+ODlvC3VA;Ha!1%WhWzj*5$?2gR*A`rxRlpukmEAvh{4 z^djz^?BK{_Fb;}bbqzF*stUc3`vw|ERfS&4eTCqNl`mUdy)~FQsw#+y?kY5nstR*r z4vzfZX81#Az3zL^#;B^$PvgEqr~XdG1)=EMv~ zah#u}rmWDbtX3Ugu(jy$|H-b$F4T3KOE%#EX}g*hstU7cR&Z2Sm=kkwROp??VI@5(E6jPRxy?qJ>#FD>y3jt{tn)a#U5Ao6L=)s=}O@;ix!eJZPq@ zq(^0iIWY%EWraC02S>%qEO1ty{bhx@$=o=qS`aZS@DZ2H^13FNRyyE_=U|Oq=CT4e z)&5UVtpp@h`!j*H68+9ImmCDw%JcW?|nZyFzq@^r}RbS*Py_b(#Iu!<45MO(ibuN1FqXV zKYq`B;ACN*-tUPIKoGO^Mb4F>S&@_eDE~W;>>C8w;t6hAn}E5N^1ot8CUB}yany9C z;wS40U3u>a;*yxrMUAB`G_qG$_iIIjSnmiMb6@RYBHc5YD6A z(CLF8%npikDgE97>Opa?jz09Fs-QquS0Q>(R?wL&J=psV!$Fa*u7So;RY9lnxq-$} zRY9eEuE3b`)UeqK!MawNqpE^R`P@L`sHzYo=ecvP5FGi9uR-uG5*rpqN*p zuf|6toal@7sl{F&HKMuw-8qV#OAP{eX}aZ=@3jVjyApY^7O+n^3pX+2hggGPUHbJR zuxOAVtwdgU63xmUM<$W`f#V=Bmy&PkO4egsk#koQx!-){h4FcEzo|9|!j-=67X=3_ z#hDpBbJ_X5%b{u2ab%QyTktO6mPVItiy7FSaXx;%Ly=M5A{YFC8l8FXAHdu&2oboR zM_!Swv}5qVi$QM{cJwRsFK)J21HEW_j@I}IWrbe2eTC>kSwVJ59ZQT+@m|3|U|T&# ztqUG_F(|UtHPE_HRp@7~b)l*tK33O4bit1W2Z}Frp{gK@Z`VNULRCRL>8?VPLRCTJ zte2*W%=SZj-utN7t3>ZH14Em)GxWt)Y*1iJzh7LR8x+?{^o4cSD6K?aEbR(wC3?Ru zK7cuNB2M(hMAjHBrQZ~0OF^wfUo2jd^F7IHQ@DE?p_RVx@iK!#T8X~UH@utK@hS2Z z4+?0d?>hiCD4><-ixn@W$cpK6@*UP5Gc#y(mVSR-*inVE5N^Q>T2;-_#RBseR7-y@s`P5hp|&(e|mt58;=cQ|p7_^iaw%A>^wg|hVf1!z1d zl$EaUdML)AP?pkfP+se=$T!g!^Gl(ujy}T3H&q2)hb5>h-g7dBbQwO=w+5;TGJ`vg zSlxUtp)*{=!;}=qk>t9-a&;? z!K_5@uMUlENY0*IxV~q8JXzex;@tH&ecuzwj0$BXdf#G=&AFZ9$M=V$25qJ9gAnIQ zsX&&}7s=vAiQ4L4Pe-GRWO1W}ZDo4DEnKO@fU?D!YS;zk9r()U?7^Y|!; zmFN+U(aUBj(K`q~Du|`@MeeatL99fN+hhF5{7v)@c8m&QC3<9R-xnL5=pA7g1;k4F z5N{LO_bCC?%S((1DR{~{a`odnZ`Iy!J z;=$8Vz^wfJ!d?lQmFWw6C2&@zFYJ}zS((1DR|04y`XcewD2P_3cMx|JNGs77iEu{6 zv{e5Og*{P7OX>H;{8dOR(K~28YND(}U(8<()k^fm{N+SvR^N(bxufD)`u*au_)+1k zL|@oXB4}p$SrzLGKG8gVvA!^5^Yn#$iNc(xXEJ5`0N&Qq$8RTpqqvPQYLJ%h^oqx& z#*0XnhaZiXkgVcRe!PTa6^HVpB3YdS8vcVLDWf7;9n=SX+*iossYsU67eV@?B3X$Z zV`kqM`6hY~FC7)h>gWT{Eh1h=g|fN|0fv?pWCiXjG*rD}Nv3dDfgvqW_))>Ej=pul z(Y{g9tgb@qLRCQ~v0kAnuJDWsXC?Zg#|md9`eKn+I7{h^>~f>RS&81^uTkNwL|+&c zg|ia9M?#GXXDNLVMKLOzmFNp2p>S5B$Aig}2EV8?aysebT9DC;kyiS+U1;=Tq!Ycv z#p5M7tB5}sH8LxG-_faY7S4(pRv0;r%u3()n^dDlW+i%ui${&jO7spFuWn}1EILr! zv82KU2^Ys=RJb7GB0`)B7i7G12$%|LsRer}R!S4P+S|MpizNsLR)~JOdKOhxU(t-#TH^Zr*l9mdQ zT;2Pil9mcZpdT%$q@}{fa~e@WC9M_we2EGwX|3QEfC?&Ut>9Cd3My%>Q0Y=rh7*$1 zt;$HcNFlnqQD`ewaMy?m7bIOINv1+@J;PFw2%ZWTBwaimMTJX}cFRqLOOkd|Ooa=Q zUVAhi6)s46t6(S&EvTfm z0{q&XR-CI1!KsBJZh{t6($Ye4|Aq=GX{}H#ikutv+A0;cmEaWX(mrhc6cv`@n=`|@ z^$7FTO+ve32u`C^8skfFSCRLb7GzHAemru?ncyw~UPV+MEy$csEx2<|gDDO zQ>U&VQa)D*jw17t4XWT@T^FK-Qtt!+%M~ic69g<*aKw^M&&W9xuhJudz;Xj+g&8ro zK3A$OAXsjpGI@f6brnL9s)a;Qu#P@Bsw;?`&zjmQRFg*{y1EvEqe@c+2kYot17!s< z+KHoT@<>cqZlPMKB&e%1sdS-uN}DTjBIfg4h%W4jz_Ga?I9S&}OrEj@3G3=AL<@C= znfXi?%GoJESZbiI5CeboNV*C%u<*^Ffu_oGN(e5-f?; zP8Iy=3MyQXbCIESbt7hu~c$oe37SgznXa%o{k&M~ZOziLJWna|qkBI_^}W&|C& zS_)1uv91rH8GOw9d`Zw{g-e2FetQeOpfwu3xSm3ndpRq8aT3P`&VXNzb0N_e4i8)O zd3ui|;rqRi)A#*k9Qt0yiQZ3Iq3=bU-Vmt<2>+$)K(4^ovIJOa=PT@4R=q+m<8;M$ z#YWjH^fJyY6+2a=+_BUap_7NS_4ue2qclrjAwyJ{r!OYvO3*O9kWpNSQXd5OQu=tB!TITJw9=RQET~taXU_Zg`}wPjOa(Aa5AGcGN58-2 zG{e8&&tIi4(xPJCM809{PWrH^=A!^!>HEmi_z}FTqi+suS)rf6U4`a2l@)pm-BoBU z6u9F`@vd{1TMK1{-bSlywl6&7>9X)iW+CutOoOAkLO+SS27;q~;k3uhKF|8D0vcBY ziL9o}yah+Cfl7@O?K*cMyivy3#H?u7nZ603z%}BcdD(*|gu;DYNuZZ@x!TvP6z)=v z)}Eb%F`AKb*rBW!`r9G}Ih^;2uuJI+^Ahq^ zfvT(o+){E6^o93+9ai$n@e^cA$%}L3c1kh6YYR@2WR!1H%r$@iBW$X7y9X-moE{@n&0%mpe&F*_|1`=XuJf1wSyBij%`2K8nMYv~vB1c*^#RbRG{>B?RSsT`ZV=4Wv zq?cKH<|me*lD-#j`hIcLzZM)z>Erb==U*nS@Ds1~IsKe`!})Y{b}cBD^0O&m{@4xGT<2?^Wsd z*Tt4Of@bFWyD7H7@ix*dy$2h^|I7qtJl7l+IR7*AH|WdpnV0XOIG>Eva&!FeD}DsR z((&9C5ZPKFETu1UQ-EOg@>R%g0|I8_qY##?M%C)FRtQVz3wyg(1nW#bv%0J$f=k)2 z+3CgG)0gIdEdW+WK4<>df?#zOX3YOu5UdVyoTcy0bNBrn=Lwa13WC*rA9XIg@mP@0 z+Sz>`@=XC~t_8qS`rcv0K7Uk%Dx!mdGt3-xqt+HLX_6zHfRPAmD@O+MBA9C}aFu*Lo^i8TI}cXviwhm=d9bPq@LRVP^rZ9s z$i#E4&W!lZLhfnNR`CSp%*gDE!@>1DSXFN9koL^ii*%lxJoe^T#(h`B+{F7>b6+n& zjmW?=M~riI3WZU}`K(m86_g=Jm43b2xhhh{pq|!`;;A@}!sCmj zR5x_Xd7quD#d`sKeO9U)Ouv79R;rr{6jG3??`o0tgH!z3xmvsw2l;uf{?n&7AOG!! z`05r;_1*t^_Uz01w=WsBFFzMe1Ni;*xAK?s+WEV8pWZ$Y^LG8mKfk}f{=@B`?mu4t z_g61J{u}jU7Je7sZnBLZnwJni#OS5g&U5w;w;%5LC}h#jch^%Js~cJ>g_j={`3F- z$D^xPFTZ*8FT3YA&)@&<{>NAU?JpnhzyHfW{qgQEKi!QlAN~EaFP{GLTbdK3+v{+k$l-!=61wSDXmH!&!zudk*jgT~c?~v@nyAOYS_wMzx-+#D$ zbN~GICz#%Uee?7>|NT5tPvcL|-@SbG!=JyseYk%Hc)xpmb9lVk{BgB^a*d{( zAKran`c_SvUTuUVR+Hz2;c4M zUR3jG^stCn)$5a4HE~Uv_Ba0jxx;_s5BHy28tF&lSASlH>sN=UCs>B7AB|uAc^R%> z9ipCK8Loabe)Z>NxPEnrdV)*C)osiG6~1}&Guy5&zu?Eu8@DskaE2zEXN?0J4)|}r zeG(r04aY_7M@d-yuU}pN_S3_U?>_t{Jif248!^A>4&kfoa#?$;TfZ>701?zuASDVvP~RPrm|ulk=50BA+x9Ra&X-x z8KCnr1`ICk0!Bq(V=9Xz__=Ho@oR}LUVF-AyNGK_bo&TC(XtH}uC1&cCMUX$>Ew=- zPu7oZ%M_<|VK3|Wj@_u&r7-itRIqV5Y)x*vL!{13eLEaX*LK4yGJGn3L&R0(vUsjK zmqjYQTo$PZa#?%3H40DmdB+DS52+Os&lGo)6~! z9&Qd1)Ft0La8Eyf@4yx6%<}K%sVA!t%Sl7Btqb#>!9|uyIZWqx~sV;<8cCa;oC#_7! zSwU?s@HCa#`vJAjv1=~6+Wa~&F)z`2caw=*3Yd6_wnANg8MugJ-2 z_7Br(x=XIqh+yjZqZdP@`qHxS^Q^2rIIDD|aZLPi@BSwHFO;=7X|2m+v&qI{Oyhto z@iN4lVp@il=DE*hy7H=?z(-x(3sdEFv1EOJe1KZtdUb4KYK9#Zz3IKhr2#EFhKxY8Viu01Cp-{W8~ z`?f4b?HLoLL&CWY4pJiqNa@h~Eb|S1ahC6fIcRhwq|f8W%9Gb$PSW<-9#GaEy%JuC zKDX~NE3?10+Oke({U?I1zqHIOYP$FTR#wz^@CT4OqSy&!t0c0 zUcWI}j$50*%+&0o6FOjfSjr-$MQ$U)6m!`j`^wZknD0Yg^z7e5*Iorq{b;Z0(u+s#ey5(9`$U1zkMn5M-x49p8%=qH@_b_X9ff>!K{8 z$J6)r5ucRH3c84E&2(5wD;u&8OuIw&87LdG+@dV6ziX0}XZsRmd99_4|1vLRF0%gO zZaAIUUB0);YiN{ZJ*8}${hTPvdnU?udF_d^f^J{X?F+gHOHT3tW=QscHq2*@vb=s! z#xBgh*PiB4-3TdVI($OY({;-|mg+JHR=1cREXmdn?o^p9+0QsHERNO&&ZC!Q+zj9g zC&}n`+15daS7UVMZ$M}GZj`xB`WgydF=y5+7S`_QbDvZl)(-+1ZLY?qB!3UJH(BDJ znmjh^?4Pn(UFY?KGTWO*S@uOKi+im}pGiXK{lL*NI>V{?UZe-f-{VZf$|A{Tri&W_ zR+jgnv@zs;ZIoqSfHD?V`<`LpY;{{!_GtKs;YC^Y9Vu%mz7pLk?ii%9cF#1Ixh>fi zwvKDbCJ#1n)(`d{CJ&Y)(<{hK9^1H!oq687o)QG^eLMKv-yX8x$ynKbCdwidKaIuh^O%67g^ z11UJqfWFr5-scCdp2-r^>EAo}{9w=N{T< zcRUsdD(-68*CAsKRa`vT|jATH&Rn(UJ$006@K>N;JU%FpO4GnHuf<1ykuMJW6)m6QW*{H zDTrL=^A~)`^k4uy%zYcyu4_ZPiImzfoEms{6Su7r9SfJ2xnDQz@);lBw8@ecT66`6VevNN5@pg2UU~Gs9ei&v4!))U==hknXQx$0 zxY?O!wyS2>C^NeT6lv>zz?1&HmK#OdC2O?VAu>ao%qcTF#IDTj5M?IIIFQQYOquO9 zC^K2IJvUiWX0qg3k;yVr?q^xX0aunKWhP5bYcod1F0{QIspH4MSQ|8KZNy1f(yPdB zoOKd1vj>!!J&4S+-p0md4yNF3_}ar^o68(j-`nuD2WZ4)j_YGG2fp{QvRDH^6%HJ2 ztT-IAvi6*Ik_U)qri-1Fm$}S&N5`a#^Gx8eQ)C%rCn&d^M+Hf$1&7sq|LYG`{p;6K|hP-c5N-uW?~m9iYq zh2|0%WV~=-VPyoDd716~NR({*56W!a$GrF&0E}sE0Lhr#wk^ep%97)08`EvPAdzIw zF}t_HX|K^mj;dUj$S*H*-QXP2+lVya`Fruwww1YVaG>n{;IPQ*j&2XY53CKK5$gws z%+|)PrS%U6Pgqbu$kq?=18<`xLP>SqhvPWUWxjJC4$bg2fU{%ohx>3WM=ob@dVElm}WFM3J z#paJwW@jfHmgnl8|(e>vpY^iT;@ZhtO=Gon?2ZF1$ZX%)#wPe zw=w`2FLRl5jn!=o(o~f z{doifUn< zOC&l?{sH)bj};ezjLy%1NFeL>ufPwmLWU=@de}aNGTWzc+T&~4-p>~>_pal-s$@Du zXn>6iM>aMFqyx1vAcV?vmo1LB;pYoPwYW}lrPbT;^96R|Zchnk@P7FD!g}xL3yhv& zOO&||ah1Z_;GT_*6&Dh1?LM^pqdMQX6KA%G5DXhrj>gP(9xyOjCkYL3{!o0QLy5f1 z*IK{7$|=dgFfH5z!$Bx>J9!{*-P#>p*9M|`GaXwi8!ODIjTKjoY+MF*7WO^6n}Pe% zl18eG2pMx;?4Cb$S!k?{t?MMmE;jaD{PZ^Vu9I;o)7n6Zyv+AeK%mYaw=%76vF{;l z#Pp9Xtm#@2f3W6~r^$%;1M3IPT0cfsz04nG*ZP6`V*ME7t(IilM}ii;%;KOp^764K z9NotNK-Rv8ak8>v-@{Vj{1rZRTs*Pwd0bV5`DXsO-DvwG%1q{DQ?NCKGV`059kxHB z%=SlQIkkCCnfXH;8QT7cGTXzFZq?>5W#;E_s$sYaWu`-vSxhur4f9_pGhBt;g5fHZ znGUh@Grxo~o4-VA*q%62BINahZI7)Ll)20~+|D|=;ZQiw4GP6UB zsOwOmn`!=T*jX4aY>I6RiaQN)EN=6hi_A6#xb5DqV{RKlyiDdencjxw8zDLZN5}ex z(_m$T#W%%KzPG``V0A~=A&ir?fkCi-Fp;bcl+xNjnAQ&l#@mQ@PjyY%5PsloZ1P>z zxNUE16lJ#W0eY~#J!LL)!o9s89IP3C1i5;d%bbu2@5f;K6mHqL%r~RUocIG9E5gmJ zjjiLN8!n(*Ke$+K{UH9p+rVn){xUsmtZ)Uq4aaj3o6DRKId5aw>RU!n)Y&OrWna$>IxVPbP*8%@!Kan!?S-E** zK5JZOvNrZC-nk#-209U#*5tvrtZ$|2FGvC3&95V zJ@eco?8x2%I_*r=5wpKtH5$;_|S&%agzt(%GM9A3Yt7H8zv8qj=dl8#$)n9ND^i8 zz`Zhg43-Niyh+26I3n;p#NcsmTyJz=fcz20GgyJ~2UcMGaaX}~oa+!arlX(j;FcJU z#Ic6^4BS<4UMwdJhvJq4k+NbRO42ElFIS~azN5$I;5PYwm7_7|&oNLCD4$y-r}FVD z))}@qnLpCz*`9X8pty`4YTp+~N<^pB5 zPsSBBJS^PPtZUqIHB6NnNuCQJ9=5(wX6qYaxrX0IsBX5WxX-p{qRg<@ zNUdZtFX9R!RbtjZ%4|KtGqZg+Wwy=`N^Ck#nPIAwnV-!zzfd#ZZMX49c&zC&xPZwBb+-QQinWJ(2{xvL2H09w+)F?lzE^!E841+$;3Egu3Jf@B4aUXk*-c1jH+ilKpFTv!&y#yQ6;$8yii_c4- zNN=O?54e}$Z4~|i;R4@5sv}u{)o&mK9ATQc^jU4f(UT;S!u%C812l4 z8-VVMaxcO9LHLmMgL?_q2KN$7Pq~+1{Q&Z{IaAzAAadGmF<60r&+jE{$!p+k_`L+8 z6bv_`%zZsVb$wh8hN%LJ8U{d_&tKd>n@3;;Rt8pJV-HqfeIs?2*)@(eysqUOU?gDqHr=@nRkt$A!+OdceR^zrkYVnEWqp5tbF ze?7+=xBc9A96hFulM~-p0O8rVj06PdvB$((KZq-^F<_b-&uk4$=D zf@+foAu-O2A6Sv9qG+Zg~ zhub==uI*hYvvq4ntU;dplo^&m1fTOltbvUmZe7-0M#a{J2q86@vyZpFaaNS(U|XPX z(z`O#s;zI$EM?PBEn~$vEc&vHK}?5550)`l^dLrH(Sv0Sni?!NahVHE5tg-av5AXK zTx{Yr0?S-j=E5=;mbq{ofyEvy_F%CG$Jwy>%8NZ%?7?CW7JG0UfyEvy_F%CG$Jwy> z2a7#e?7?CW7JG0UfyEvy_F%CG$Jwy>2a7#e?7?CW7JG0UfyEvy_F%CG$Jwy>2a7#e z?7?CW7JG0UfyEvy_F%CG$Jwy>2a7#e?7?CW7JG0UfyEvy_F%CG$Jwy>2a7#e?7?CW z7JG0UfyEvy_F%CG$Jwy>2a7#e?7?CW7JG0UfyEvy_F%CG$Jwy>2a7#e?7?CW7JG0U zfyEvy_F%CG$Jwy>2a7#e?7?CW7JG0UfyEvy_F%CG$Jwy>2a7#e?7?CW7JG0UfyEyD z|7{N*KHR=~egEOhFP=WV{{Gcp?yq>oaQE!lmtTB*xc%_(%ZK|PzWjpMcfb7N@BZ$; L{`2p@{Nn!sB*1eJ literal 0 HcmV?d00001 diff --git a/branches/WOF2-3/ulp/opensm/user/doc/QoS_management_in_OpenSM.txt b/branches/WOF2-3/ulp/opensm/user/doc/QoS_management_in_OpenSM.txt new file mode 100644 index 00000000..fef8a622 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/doc/QoS_management_in_OpenSM.txt @@ -0,0 +1,492 @@ + + QoS Management in OpenSM + +============================================================================== + Table of contents +============================================================================== + +1. Overview +2. Full QoS Policy File +3. Simplified QoS Policy Definition +4. Policy File Syntax Guidelines +5. Examples of Full Policy File +6. Simplified QoS Policy - Details and Examples +7. SL2VL Mapping and VL Arbitration + + +============================================================================== + 1. Overview +============================================================================== + +When QoS in OpenSM is enabled (-Q or --qos), OpenSM looks for QoS Policy file. +The default name of OpenSM QoS policy file is +/usr/local/etc/opensm/qos-policy.conf. The default may be changed by using -Y +or --qos_policy_file option with OpenSM. + +During fabric initialization and at every heavy sweep OpenSM parses the QoS +policy file, applies its settings to the discovered fabric elements, and +enforces the provided policy on client requests. The overall flow for such +requests is: + - The request is matched against the defined matching rules such that the + QoS Level definition is found. + - Given the QoS Level, path(s) search is performed with the given + restrictions imposed by that level. + +There are two ways to define QoS policy: + - Full policy, where the policy file syntax provides an administrator + various ways to match PathRecord/MultiPathRecord (PR/MPR) request and + enforce various QoS constraints on the requested PR/MPR + - Simplified QoS policy definition, where an administrator would be able to + match PR/MPR requests by various ULPs and applications running on top of + these ULPs. + +While the full policy syntax is very flexible, in many cases the simplified +policy definition would be sufficient. + + +============================================================================== + 2. Full QoS Policy File +============================================================================== + +QoS policy file has the following sections: + +I) Port Groups (denoted by port-groups). +This section defines zero or more port groups that can be referred later by +matching rules (see below). Port group lists ports by: + - Port GUID + - Port name, which is a combination of NodeDescription and IB port number + - PKey, which means that all the ports in the subnet that belong to + partition with a given PKey belong to this port group + - Partition name, which means that all the ports in the subnet that belong + to partition with a given name belong to this port group + - Node type, where possible node types are: CA, SWITCH, ROUTER, ALL, and + SELF (SM's port). + +II) QoS Setup (denoted by qos-setup). +This section describes how to set up SL2VL and VL Arbitration tables on +various nodes in the fabric. +However, this is not supported in OpenSM currently. +SL2VL and VLArb tables should be configured in the OpenSM options file +(default location - /usr/local/etc/opensm/opensm.conf). + +III) QoS Levels (denoted by qos-levels). +Each QoS Level defines Service Level (SL) and a few optional fields: + - MTU limit + - Rate limit + - PKey + - Packet lifetime +When path(s) search is performed, it is done with regards to restriction that +these QoS Level parameters impose. +One QoS level that is mandatory to define is a DEFAULT QoS level. It is +applied to a PR/MPR query that does not match any existing match rule. +Similar to any other QoS Level, it can also be explicitly referred by any +match rule. + +IV) QoS Matching Rules (denoted by qos-match-rules). +Each PathRecord/MultiPathRecord query that OpenSM receives is matched against +the set of matching rules. Rules are scanned in order of appearance in the QoS +policy file such as the first match takes precedence. +Each rule has a name of QoS level that will be applied to the matching query. +A default QoS level is applied to a query that did not match any rule. +Queries can be matched by: + - Source port group (whether a source port is a member of a specified group) + - Destination port group (same as above, only for destination port) + - PKey + - QoS class + - Service ID +To match a certain matching rule, PR/MPR query has to match ALL the rule's +criteria. However, not all the fields of the PR/MPR query have to appear in +the matching rule. +For instance, if the rule has a single criterion - Service ID, it will match +any query that has this Service ID, disregarding rest of the query fields. +However, if a certain query has only Service ID (which means that this is the +only bit in the PR/MPR component mask that is on), it will not match any rule +that has other matching criteria besides Service ID. + + +============================================================================== + 3. Simplified QoS Policy Definition +============================================================================== + +Simplified QoS policy definition comprises of a single section denoted by +qos-ulps. Similar to the full QoS policy, it has a list of match rules and +their QoS Level, but in this case a match rule has only one criterion - its +goal is to match a certain ULP (or a certain application on top of this ULP) +PR/MPR request, and QoS Level has only one constraint - Service Level (SL). +The simplified policy section may appear in the policy file in combine with +the full policy, or as a stand-alone policy definition. +See more details and list of match rule criteria below. + + +============================================================================== + 4. Policy File Syntax Guidelines +============================================================================== + +- Empty lines are ignored. +- Leading and trailing blanks, as well as empty lines, are ignored, so + the indentation in the example is just for better readability. +- Comments are started with the pound sign (#) and terminated by EOL. +- Any keyword should be the first non-blank in the line, unless it's a + comment. +- Keywords that denote section/subsection start have matching closing + keywords. +- Having a QoS Level named "DEFAULT" is a must - it is applied to PR/MPR + requests that didn't match any of the matching rules. +- Any section/subsection of the policy file is optional. + + +============================================================================== + 5. Examples of Full Policy File +============================================================================== + +As mentioned earlier, any section of the policy file is optional, and +the only mandatory part of the policy file is a default QoS Level. +Here's an example of the shortest policy file: + + qos-levels + qos-level + name: DEFAULT + sl: 0 + end-qos-level + end-qos-levels + +Port groups section is missing because there are no match rules, which means +that port groups are not referred anywhere, and there is no need defining +them. And since this policy file doesn't have any matching rules, PR/MPR query +won't match any rule, and OpenSM will enforce default QoS level. +Essentially, the above example is equivalent to not having QoS policy file +at all. + +The following example shows all the possible options and keywords in the +policy file and their syntax: + + # + # See the comments in the following example. + # They explain different keywords and their meaning. + # + port-groups + + port-group # using port GUIDs + name: Storage + # "use" is just a description that is used for logging + # Other than that, it is just a comment + use: SRP Targets + port-guid: 0x10000000000001, 0x10000000000005-0x1000000000FFFA + port-guid: 0x1000000000FFFF + end-port-group + + port-group + name: Virtual Servers + # The syntax of the port name is as follows: + # "node_description/Pnum". + # node_description is compared to the NodeDescription of the node, + # and "Pnum" is a port number on that node. + port-name: vs1 HCA-1/P1, vs2 HCA-1/P1 + end-port-group + + # using partitions defined in the partition policy + port-group + name: Partitions + partition: Part1 + pkey: 0x1234 + end-port-group + + # using node types: CA, ROUTER, SWITCH, SELF (for node that runs SM) + # or ALL (for all the nodes in the subnet) + port-group + name: CAs and SM + node-type: CA, SELF + end-port-group + + end-port-groups + + qos-setup + # This section of the policy file describes how to set up SL2VL and VL + # Arbitration tables on various nodes in the fabric. + # However, this is not supported in OpenSM currently - the section is + # parsed and ignored. SL2VL and VLArb tables should be configured in the + # OpenSM options file (by default - /usr/local/etc/opensm/opensm.conf). + end-qos-setup + + qos-levels + + # Having a QoS Level named "DEFAULT" is a must - it is applied to + # PR/MPR requests that didn't match any of the matching rules. + qos-level + name: DEFAULT + use: default QoS Level + sl: 0 + end-qos-level + + # the whole set: SL, MTU-Limit, Rate-Limit, PKey, Packet Lifetime + qos-level + name: WholeSet + sl: 1 + mtu-limit: 4 + rate-limit: 5 + pkey: 0x1234 + packet-life: 8 + end-qos-level + + end-qos-levels + + # Match rules are scanned in order of their apperance in the policy file. + # First matched rule takes precedence. + qos-match-rules + + # matching by single criteria: QoS class + qos-match-rule + use: by QoS class + qos-class: 7-9,11 + # Name of qos-level to apply to the matching PR/MPR + qos-level-name: WholeSet + end-qos-match-rule + + # show matching by destination group and service id + qos-match-rule + use: Storage targets + destination: Storage + service-id: 0x10000000000001, 0x10000000000008-0x10000000000FFF + qos-level-name: WholeSet + end-qos-match-rule + + qos-match-rule + source: Storage + use: match by source group only + qos-level-name: DEFAULT + end-qos-match-rule + + qos-match-rule + use: match by all parameters + qos-class: 7-9,11 + source: Virtual Servers + destination: Storage + service-id: 0x0000000000010000-0x000000000001FFFF + pkey: 0x0F00-0x0FFF + qos-level-name: WholeSet + end-qos-match-rule + + end-qos-match-rules + + +============================================================================== + 6. Simplified QoS Policy - Details and Examples +============================================================================== + +Simplified QoS policy match rules are tailored for matching ULPs (or some +application on top of a ULP) PR/MPR requests. This section has a list of +per-ULP (or per-application) match rules and the SL that should be enforced +on the matched PR/MPR query. + +Match rules include: + - Default match rule that is applied to PR/MPR query that didn't match any + of the other match rules + - SDP + - SDP application with a specific target TCP/IP port range + - SRP with a specific target IB port GUID + - RDS + - iSER + - iSER application with a specific target TCP/IP port range + - IPoIB with a default PKey + - IPoIB with a specific PKey + - any ULP/application with a specific Service ID in the PR/MPR query + - any ULP/application with a specific PKey in the PR/MPR query + - any ULP/application with a specific target IB port GUID in the PR/MPR query + +Since any section of the policy file is optional, as long as basic rules of +the file are kept (such as no referring to nonexisting port group, having +default QoS Level, etc), the simplified policy section (qos-ulps) can serve +as a complete QoS policy file. +The shortest policy file in this case would be as follows: + + qos-ulps + default : 0 #default SL + end-qos-ulps + +It is equivalent to the previous example of the shortest policy file, and it +is also equivalent to not having policy file at all. + +Below is an example of simplified QoS policy with all the possible keywords: + + qos-ulps + default : 0 # default SL + sdp, port-num 30000 : 0 # SL for application running on top + # of SDP when a destination + # TCP/IPport is 30000 + sdp, port-num 10000-20000 : 0 + sdp : 1 # default SL for any other + # application running on top of SDP + rds : 2 # SL for RDS traffic + iser, port-num 900 : 0 # SL for iSER with a specific target + # port + iser : 3 # default SL for iSER + ipoib, pkey 0x0001 : 0 # SL for IPoIB on partition with + # pkey 0x0001 + ipoib : 4 # default IPoIB partition, + # pkey=0x7FFF + any, service-id 0x6234 : 6 # match any PR/MPR query with a + # specific Service ID + any, pkey 0x0ABC : 6 # match any PR/MPR query with a + # specific PKey + srp, target-port-guid 0x1234 : 5 # SRP when SRP Target is located on + # a specified IB port GUID + any, target-port-guid 0x0ABC-0xFFFFF : 6 # match any PR/MPR query with + # a specific target port GUID + end-qos-ulps + + +Similar to the full policy definition, matching of PR/MPR queries is done in +order of appearance in the QoS policy file such as the first match takes +precedence, except for the "default" rule, which is applied only if the query +didn't match any other rule. + +All other sections of the QoS policy file take precedence over the qos-ulps +section. That is, if a policy file has both qos-match-rules and qos-ulps +sections, then any query is matched first against the rules in the +qos-match-rules section, and only if there was no match, the query is matched +against the rules in qos-ulps section. + +Note that some of these match rules may overlap, so in order to use the +simplified QoS definition effectively, it is important to understand how each +of the ULPs is matched: + +6.1 IPoIB +IPoIB query is matched by PKey. Default PKey for IPoIB partition is 0x7fff, so +the following three match rules are equivalent: + + ipoib : + ipoib, pkey 0x7fff : + any, pkey 0x7fff : + +6.2 SDP +SDP PR query is matched by Service ID. The Service-ID for SDP is +0x000000000001PPPP, where PPPP are 4 hex digits holding the remote TCP/IP Port +Number to connect to. The following two match rules are equivalent: + + sdp : + any, service-id 0x0000000000010000-0x000000000001ffff : + +6.3 RDS +Similar to SDP, RDS PR query is matched by Service ID. The Service ID for RDS +is 0x000000000106PPPP, where PPPP are 4 hex digits holding the remote TCP/IP +Port Number to connect to. Default port number for RDS is 0x48CA, which makes +a default Service-ID 0x00000000010648CA. The following two match rules are +equivalent: + + rds : + any, service-id 0x00000000010648CA : + +6.4 iSER +Similar to RDS, iSER query is matched by Service ID, where the the Service ID +is also 0x000000000106PPPP. Default port number for iSER is 0x0CBC, which makes +a default Service-ID 0x0000000001060CBC. The following two match rules are +equivalent: + + iser : + any, service-id 0x0000000001060CBC : + +6.5 SRP +Service ID for SRP varies from storage vendor to vendor, thus SRP query is +matched by the target IB port GUID. The following two match rules are +equivalent: + + srp, target-port-guid 0x1234 : + any, target-port-guid 0x1234 : + +Note that any of the above ULPs might contain target port GUID in the PR +query, so in order for these queries not to be recognized by the QoS manager +as SRP, the SRP match rule (or any match rule that refers to the target port +guid only) should be placed at the end of the qos-ulps match rules. + +6.6 MPI +SL for MPI is manually configured by MPI admin. OpenSM is not forcing any SL +on the MPI traffic, and that's why it is the only ULP that did not appear in +the qos-ulps section. + + +============================================================================== + 7. SL2VL Mapping and VL Arbitration +============================================================================== + +OpenSM cached options file has a set of QoS related configuration parameters, +that are used to configure SL2VL mapping and VL arbitration on IB ports. +These parameters are: + - Max VLs: the maximum number of VLs that will be on the subnet. + - High limit: the limit of High Priority component of VL Arbitration + table (IBA 7.6.9). + - VLArb low table: Low priority VL Arbitration table (IBA 7.6.9) template. + - VLArb high table: High priority VL Arbitration table (IBA 7.6.9) template. + - SL2VL: SL2VL Mapping table (IBA 7.6.6) template. It is a list of VLs + corresponding to SLs 0-15 (Note that VL15 used here means drop this SL). + +There are separate QoS configuration parameters sets for various target types: +CAs, routers, switch external ports, and switch's enhanced port 0. The names +of such parameters are prefixed by "qos__" string. Here is a full list +of the currently supported sets: + + qos_ca_ - QoS configuration parameters set for CAs. + qos_rtr_ - parameters set for routers. + qos_sw0_ - parameters set for switches' port 0. + qos_swe_ - parameters set for switches' external ports. + +Here's the example of typical default values for CAs and switches' external +ports (hard-coded in OpenSM initialization): + + qos_ca_max_vls 15 + qos_ca_high_limit 0 + qos_ca_vlarb_high 0:4,1:0,2:0,3:0,4:0,5:0,6:0,7:0,8:0,9:0,10:0,11:0,12:0,13:0,14:0 + qos_ca_vlarb_low 0:0,1:4,2:4,3:4,4:4,5:4,6:4,7:4,8:4,9:4,10:4,11:4,12:4,13:4,14:4 + qos_ca_sl2vl 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,7 + + qos_swe_max_vls 15 + qos_swe_high_limit 0 + qos_swe_vlarb_high 0:4,1:0,2:0,3:0,4:0,5:0,6:0,7:0,8:0,9:0,10:0,11:0,12:0,13:0,14:0 + qos_swe_vlarb_low 0:0,1:4,2:4,3:4,4:4,5:4,6:4,7:4,8:4,9:4,10:4,11:4,12:4,13:4,14:4 + qos_swe_sl2vl 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,7 + +VL arbitration tables (both high and low) are lists of VL/Weight pairs. +Each list entry contains a VL number (values from 0-14), and a weighting value +(values 0-255), indicating the number of 64 byte units (credits) which may be +transmitted from that VL when its turn in the arbitration occurs. A weight +of 0 indicates that this entry should be skipped. If a list entry is +programmed for VL15 or for a VL that is not supported or is not currently +configured by the port, the port may either skip that entry or send from any +supported VL for that entry. + +Note, that the same VLs may be listed multiple times in the High or Low +priority arbitration tables, and, further, it can be listed in both tables. + +The limit of high-priority VLArb table (qos__high_limit) indicates the +number of high-priority packets that can be transmitted without an opportunity +to send a low-priority packet. Specifically, the number of bytes that can be +sent is high_limit times 4K bytes. + +A high_limit value of 255 indicates that the byte limit is unbounded. +Note: if the 255 value is used, the low priority VLs may be starved. +A value of 0 indicates that only a single packet from the high-priority table +may be sent before an opportunity is given to the low-priority table. + +Keep in mind that ports usually transmit packets of size equal to MTU. +For instance, for 4KB MTU a single packet will require 64 credits, so in order +to achieve effective VL arbitration for packets of 4KB MTU, the weighting +values for each VL should be multiples of 64. + +Below is an example of SL2VL and VL Arbitration configuration on subnet: + + qos_ca_max_vls 15 + qos_ca_high_limit 6 + qos_ca_vlarb_high 0:4 + qos_ca_vlarb_low 0:0,1:64,2:128,3:192,4:0,5:64,6:64,7:64 + qos_ca_sl2vl 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,7 + + qos_swe_max_vls 15 + qos_swe_high_limit 6 + qos_swe_vlarb_high 0:4 + qos_swe_vlarb_low 0:0,1:64,2:128,3:192,4:0,5:64,6:64,7:64 + qos_swe_sl2vl 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,7 + +In this example, there are 8 VLs configured on subnet: VL0 to VL7. VL0 is +defined as a high priority VL, and it is limited to 6 x 4KB = 24KB in a single +transmission burst. Such configuration would suilt VL that needs low latency +and uses small MTU when transmitting packets. Rest of VLs are defined as low +priority VLs with different weights, while VL4 is effectively turned off. diff --git a/branches/WOF2-3/ulp/opensm/user/doc/current-routing.txt b/branches/WOF2-3/ulp/opensm/user/doc/current-routing.txt new file mode 100644 index 00000000..b7675188 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/doc/current-routing.txt @@ -0,0 +1,390 @@ +Current OpenSM Routing +7/9/07 + +OpenSM offers five routing engines: + +1. Min Hop Algorithm - based on the minimum hops to each node where the +path length is optimized. + +2. UPDN Unicast routing algorithm - also based on the minimum hops to each +node, but it is constrained to ranking rules. This algorithm should be chosen +if the subnet is not a pure Fat Tree, and deadlock may occur due to a +loop in the subnet. + +3. Fat-tree Unicast routing algorithm - this algorithm optimizes routing +of fat-trees for congestion-free "shift" communication pattern. +It should be chosen if a subnet is a symmetrical fat-tree. +Similar to UPDN routing, Fat-tree routing is credit-loop-free. + +4. LASH unicast routing algorithm - uses Infiniband virtual layers +(SL) to provide deadlock-free shortest-path routing while also +distributing the paths between layers. LASH is an alternative +deadlock-free topology-agnostic routing algorithm to the non-minimal +UPDN algorithm avoiding the use of a potentially congested root node. + +5. DOR Unicast routing algorithm - based on the Min Hop algorithm, but +avoids port equalization except for redundant links between the same +two switches. This provides deadlock free routes for hypercubes when +the fabric is cabled as a hypercube and for meshes when cabled as a +mesh (see details below). + +OpenSM provides an optional unicast routing cache (enabled by -A or +--ucast_cache options). When enabled, unicast routing cache prevents +routing recalculation (which is a heavy task in a large cluster) when +there was no topology change detected during the heavy sweep, or when +the topology change does not require new routing calculation, e.g. when +one or more CAs/RTRs/leaf switches going down, or one or more of these +nodes coming back after being down. +A very common case that is handled by the unicast routing cache is host +reboot, which otherwise would cause two full routing recalculations: one +when the host goes down, and the other when the host comes back online. + +OpenSM also supports a file method which can load routes from a table. See +modular-routing.txt for more information on this. + +The basic routing algorithm is comprised of two stages: +1. MinHop matrix calculation + How many hops are required to get from each port to each LID ? + The algorithm to fill these tables is different if you run standard +(min hop) or Up/Down. + For standard routing, a "relaxation" algorithm is used to propagate +min hop from every destination LID through neighbor switches + For Up/Down routing, a BFS from every target is used. The BFS tracks link +direction (up or down) and avoid steps that will perform up after a down +step was used. + +2. Once MinHop matrices exist, each switch is visited and for each target LID, +a decision is made as to what port should be used to get to that LID. + This step is common to standard and Up/Down routing. Each port has a +counter counting the number of target LIDs going through it. + When there are multiple alternative ports with same MinHop to a LID, +the one with less previously assigned ports is selected. + If LMC > 0, more checks are added: Within each group of LIDs assigned to +same target port, + a. use only ports which have same MinHop + b. first prefer the ones that go to different systemImageGuid (then +the previous LID of the same LMC group) + c. if none - prefer those which go through another NodeGuid + d. fall back to the number of paths method (if all go to same node). + + +Effect of Topology Changes + +OpenSM will preserve existing routing in any case where there is no change in +the fabric switches unless the -r (--reassign_lids) option is specified. + +-r +--reassign_lids + This option causes OpenSM to reassign LIDs to all + end nodes. Specifying -r on a running subnet + may disrupt subnet traffic. + Without -r, OpenSM attempts to preserve existing + LID assignments resolving multiple use of same LID. + +If a link is added or removed, OpenSM does not recalculate +the routes that do not have to change. A route has to change +if the port is no longer UP or no longer the MinHop. When routing changes +are performed, the same algorithm for balancing the routes is invoked. + +In the case of using the file based routing, any topology changes are +currently ignored The 'file' routing engine just loads the LFTs from the file +specified, with no reaction to real topology. Obviously, this will not be able +to recheck LIDs (by GUID) for disconnected nodes, and LFTs for non-existent +switches will be skipped. Multicast is not affected by 'file' routing engine +(this uses min hop tables). + + +Min Hop Algorithm +----------------- + +The Min Hop algorithm is invoked by default if no routing algorithm is +specified. It can also be invoked by specifying '-R minhop'. + +The Min Hop algorithm is divided into two stages: computation of +min-hop tables on every switch and LFT output port assignment. Link +subscription is also equalized with the ability to override based on +port GUID. The latter is supplied by: + +-i +-ignore-guids + This option provides the means to define a set of ports + (by guids) that will be ignored by the link load + equalization algorithm. + +LMC awareness routes based on (remote) system or switch basis. + + +UPDN Routing Algorithm +---------------------- + +Purpose of UPDN Algorithm + +The UPDN algorithm is designed to prevent deadlocks from occurring in loops +of the subnet. A loop-deadlock is a situation in which it is no longer +possible to send data between any two hosts connected through the loop. As +such, the UPDN routing algorithm should be used if the subnet is not a pure +Fat Tree, and one of its loops may experience a deadlock (due, for example, +to high pressure). + +The UPDN algorithm is based on the following main stages: + +1. Auto-detect root nodes - based on the CA hop length from any switch in +the subnet, a statistical histogram is built for each switch (hop num vs +number of occurrences). If the histogram reflects a specific column (higher +than others) for a certain node, then it is marked as a root node. Since +the algorithm is statistical, it may not find any root nodes. The list of +the root nodes found by this auto-detect stage is used by the ranking +process stage. + + Note 1: The user can override the node list manually. + Note 2: If this stage cannot find any root nodes, and the user did not + specify a guid list file, OpenSM defaults back to the Min Hop + routing algorithm. + +2. Ranking process - All root switch nodes (found in stage 1) are assigned +a rank of 0. Using the BFS algorithm, the rest of the switch nodes in the +subnet are ranked incrementally. This ranking aids in the process of enforcing +rules that ensure loop-free paths. + +3. Min Hop Table setting - after ranking is done, a BFS algorithm is run from +each (CA or switch) node in the subnet. During the BFS process, the FDB table +of each switch node traversed by BFS is updated, in reference to the starting +node, based on the ranking rules and guid values. + +At the end of the process, the updated FDB tables ensure loop-free paths +through the subnet. + +Note: Up/Down routing does not allow LID routing communication between +switches that are located inside spine "switch systems". +The reason is that there is no way to allow a LID route between them +that does not break the Up/Down rule. +One ramification of this is that you cannot run SM on switches other +than the leaf switches of the fabric. + + +UPDN Algorithm Usage + +Activation through OpenSM + +Use '-R updn' option (instead of old '-u') to activate the UPDN algorithm. +Use `-a ' for adding an UPDN guid file that contains the +root nodes for ranking. +If the `-a' option is not used, OpenSM uses its auto-detect root nodes +algorithm. + +Notes on the guid list file: +1. A valid guid file specifies one guid in each line. Lines with an invalid +format will be discarded. +2. The user should specify the root switch guids. However, it is also +possible to specify CA guids; OpenSM will use the guid of the switch (if +it exists) that connects the CA to the subnet as a root node. + + +To learn more about deadlock-free routing, see the article +"Deadlock Free Message Routing in Multiprocessor Interconnection Networks" +by William J Dally and Charles L Seitz (1985). + + +Fat-tree Routing Algorithm +-------------------------- + +Purpose: + +The fat-tree algorithm optimizes routing for "shift" communication pattern. +It should be chosen if a subnet is a symmetrical or almost symmetrical +fat-tree of various types. +It supports not just K-ary-N-Trees, by handling for non-constant K, +cases where not all leafs (CAs) are present, any Constant +Bisectional Ratio (CBB) ratio. As in UPDN, fat-tree also prevents +credit-loop-deadlocks. + +If the root guid file is not provided ('-a' or '--root_guid_file' options), +the topology has to be pure fat-tree that complies with the following rules: + - Tree rank should be between two and eight (inclusively) + - Switches of the same rank should have the same number + of UP-going port groups*, unless they are root switches, + in which case the shouldn't have UP-going ports at all. + - Switches of the same rank should have the same number + of DOWN-going port groups, unless they are leaf switches. + - Switches of the same rank should have the same number + of ports in each UP-going port group. + - Switches of the same rank should have the same number + of ports in each DOWN-going port group. + - All the CAs have to be at the same tree level (rank). + +If the root guid file is provided, the topology doesn't have to be pure +fat-tree, and it should only comply with the following rules: + - Tree rank should be between two and eight (inclusively) + - All the Compute Nodes** have to be at the same tree level (rank). + Note that non-compute node CAs are allowed here to be at different + tree ranks. + +* ports that are connected to the same remote switch are referenced as +'port group'. +** list of compute nodes (CNs) can be specified by '-u' or '--cn_guid_file' +OpenSM options. + +Note that although fat-tree algorithm supports trees with non-integer CBB +ratio, the routing will not be as balanced as in case of integer CBB ratio. +In addition to this, although the algorithm allows leaf switches to have any +number of CAs, the closer the tree is to be fully populated, the more effective +the "shift" communication pattern will be. +In general, even if the root list is provided, the closer the topology to a +pure and symmetrical fat-tree, the more optimal the routing will be. + +The algorithm also dumps compute node ordering file (opensm-ftree-ca-order.dump) +in the same directory where the OpenSM log resides. This ordering file provides +the CN order that may be used to create efficient communication pattern, that +will match the routing tables. + +Routing between non-CN nodes + + +The use of the cn_guid_file option allows non-CN nodes to be located on different levels in the fat tree. +In such case, it is not guaranteed that the Fat Tree algorithm will route between two non-CN nodes. +In the scheme below, N1, N2 and N3 are non-CN nodes. Although all the CN have routes to and from them, +there will not necessarily be a route between N1,N2 and N3. +Such routes would require to use at least one of the Switch the wrong way around +(In fact, go out of one of the top Switch through a downgoing port while we are supposed to go up). + + Spine1 Spine2 Spine 3 + / \ / | \ / \ + / \ / | \ / \ + N1 Switch N2 Switch N3 + /|\ /|\ + / | \ / | \ + Going down to compute nodes + +To solve this problem, a list of non-CN nodes can be specified by \'-G\' or \'--io_guid_file\' option. +Theses nodes will be allowed to use switches the wrong way around a specific number of times (specified by \'-H\' or \'--max_reverse_hops\'. +With the proper max_reverse_hops and io_guid_file values, you can ensure full connectivity in the Fat Tree. + +In the scheme above, with a max_reverse_hop of 1, routes will be instanciated between N1<->N2 and N2<->N3. +With a max_reverse_hops value of 2, N1,N2 and N3 will all have routes between them. + +Please note that using max_reverse_hops creates routes that use the switch in a counter-stream way. +This option should never be used to connect nodes with high bandwidth traffic between them ! It should only be used +to allow connectivity for HA purposes or similar. +Also having routes the other way around can in theory cause credit loops. + +Use these options with extreme care ! + + +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. + +For open regular cartesian meshes the DOR algorithm is the ideal +routing algorithm. For toroidal meshes on the other hand there +are routing loops that can cause deadlocks. LASH can be used to +route these cases. The performance of LASH can be improved by +preconditioning the mesh in cases where there are multiple links +connecting switches and also in cases where the switches are not +cabled consistently. An option exists for LASH to do this. To +invoke this use '-R lash -Q --do_mesh_analysis'. This will +add an additional phase that analyses the mesh to try to determine +the dimension and size of a mesh. If it determines that the mesh +looks like an open or closed cartesian mesh it reorders the ports +in dimension order before the rest of the LASH algorithm runs. + +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/branches/WOF2-3/ulp/opensm/user/doc/opensm_release_notes-3.3.txt b/branches/WOF2-3/ulp/opensm/user/doc/opensm_release_notes-3.3.txt new file mode 100644 index 00000000..fb27b274 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/doc/opensm_release_notes-3.3.txt @@ -0,0 +1,735 @@ + OpenSM Release Notes 3.3 + ============================= + +Version: OpenSM 3.3.x +Repo: git://git.openfabrics.org/~sashak/management.git +Date: Dec 2009 + +1 Overview +---------- +This document describes the contents of the OpenSM 3.3 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.3.6. + +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 + +* Mesh Analysis for LASH routing algorithm. + The performance of LASH can be improved by preconditioning the mesh in + cases where there are multiple links connecting switches and also in + cases where the switches are not cabled consistently. + Activated with --do_mesh_analysis command line and config file option. + +* Reloadable OpenSM configuration (preliminary implemented) + This is possible now to reload OpenSM configuration parameters on the + fly without restarting. + +* Routing paths sorted balancing (for UpDown and MinHops) + This sorts the port order in which routing paths balancing is performed + by OpenSM. Helps to improve performance dramatically (40-50%) for most + popular application communication patterns. + To overwrite this behavior use --guid_routing_order_file command line + option. + +* Weighted Lid Matrices calculation (for UpDown, MinHop and DOR). + This low level routing fine-tuning feature provides the means to + define a weighting factor per port for customizing the least weight + hops for the routing. Custom weights are provided using file specified + with '--hop_weights_file' command line option. + +* I/O nodes connectivity (for FatTree). + This provides possibility to define the set of I/O nodes for the + Fat-Tree routing algorithm. I/O nodes are non-CN nodes allowed to use + up to N (specified using --max_reverse_hops) switches the wrong way + around to improve connectivity. I/O nodes list is provided using file + and --io_guid_file command line option. + +* MGID to MLID compression - infrastructure for many MGIDs to single MLID + compression. This becomes helpful when number of multicast groups + exceeds subnet's MLID routing capability (normally 1024 groups). In such + cases many multicast groups (MGID) can be routed using same MLID value. + +* Many code improvements, optimizations and cleanups. + +* Windows support (early stage). + +1.2 Minor New Features: + +cde0c0d opensm: Convert remaining helper routines for GID printing format +bc5743c opensm: Add support for MaxCreditHint and LinkRoundTripLatency to + osm_dump_port_info +6cd34ab opensm: Add Dell to known vendor list +003d6bd opensm: Add more info for traps 144 and 256-259 in osm_dump_notice +5b0c5de opensm/osm_ucat_ftree.c Enhance min hops counters usage +0715b92 ib_types.h: Add ib_switch_info_get_state_opt_sl2vlmapping routine +2ddba79 opensm: Remove some __ and __osm_ prefixes +ea0691f opensm/iba/ib_types.h: Add PortXmit/RcvDataSL PerfMgt attributes +9c79be5 ib_types.h: Adding BKEY violation trap (259) +c608ea6 opensm: Add and utilize ib_gid_is_notzero routine +b639e64 opensm: Handle trap repress on trap 144 generation +b034205 Add pkey table support to osm_get_all_port_attr +876605b opensm/ib_types.h: Add attribute ID for PortCountersExtended +aae3bbc opensm: PortInfo requests for discovered switches +0147b09 opensm/osm_lid_mgr: use single array for used_lids +a9225b0 opensm/Makefile.am: remove osm_build_id.h junk file generation +8e3a57d opensm/osm_console.c: Add list of SMs to status command +3d664b9 opensm/osm_console.c : Added dump_portguid function to console to + generate a list of port guids matching one or more regexps +85b35bc opensm/osm_helper.c: print port number as decimal +8674cb7 opensm: sort port order for routing by switch loads +80c0d48 opensm: rescan config file even in standby +8b7aa5e opensm/osm_subnet.c enable log_max_size opt update +8558ee5 opensm/include/iba/ib_types.h: Add xmit_wait for PortCounters +ecde2f7 opensm/osm_subnet.c support subnet configuration rescan and update +58c45e4 opensm/osm_log.c save log_max_size in subnet opt in MB +cf88e93 opensm: Add new partition keyword for all hca, switches and routers +4bfd4e0 opensm: remove libibcommon build dependencies +3718fc4 opensm/event_plugin: link opensm with -rdynamic flag +587ce14 opensm/osm_inform.c report IB traps to plugin +ced5a6e opensm/opensm/osm_console.c: move reporting of plugins to "status" + command. +696aca2 opensm: Add configurable retries for transactions +0d932ff opensm/osm_sa_mcmember_record.c: optimization in zero mgid comparison +254c2ef opensm/osm_sm_mad_ctrl.c: In sm_mad_ctrl_send_err_cb, set init + failure on PKeyTable and QoS initialization failure +83bd10a opensm: Reduce heap consumption by multicast routing tables (MFTs) +cd33bc5 opensm: Add some additional HP vendor IDs/OUIs +f78ec3a opensm/osm_mcast_tbl.(h c): Make max_mlid_ho be maximum MLID configured +2d13530 opensm: Add infrastructure support for PortInfo + IsMulticastPkeyTrapSuppressionSupported +3ace760 opensm: Reduce heap consumption by unicast routing tables (LFTs) +eec568e osmtest: Add SA get PathRecord stress test +aabc476 opensm: Add infrastructure support for more newly allocated PortInfo + CapabilityMask bits +c83c331 opensm: improve multicast re-routing requests processing +46db92f opensm: Parallelize (Stripe) MFT sets across switches +00c6a6e opensm: Parallelize (Stripe) LFT sets across switches +e21c651 opensm/osm_base.h: Add new SA ClassPortInfo:CapabilityMask2 bit + allocations +09056b1 opensm/ib_types.h: Add CounterSelect2 field to PortCounters attribute +6a63003 opensm: Add ability to configure SMSL +25f071f opensm/lash: Set minimum VL for LASH to use +622d853 opensm/osm_ucast_ftree.cd: Added support for same level links +8146ba7 opensm: Add new Sun vendor ID +1d7dd18 opensm/osm_ucast_ftree.c: Enhanced Fat-Tree algorithm +e07a2f1 Add LMC support to DOR routing +1acfe8a opensm: Add SuperMicro to list of recognized vendors +f02f40e opensm: implement 'connect_roots' option in fat-tree routing +748d41e opensm SA DB dump/restore: added option to dump SA DB on every sweep +b03a95e complib/cl_fleximap: add cl_fmap_match() function +b7a8a87 opensm/include/iba/ib_types.h: adding Congestion Control definitions +fa356f8 opensm: Add support for optimized SLtoVLMappingTable programming +8aaae91 Dimension port order file support +7662eec opensm: Add option to specify prefix to syslog messages +2382cf3 opensm: Add update_desc command to opensm console + +1.3 Library API Changes + + None + +1.4 Software Dependencies + +OpenSM depends on the installation of libibumad package (distributed as +part of OFA IB management together with OpenSM) and IB stack presence, +in particular libibumad uses user_mad kernel interface ('ib_umad' kernel +module). 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:M_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 + +18990fa opensm: set IS_SM bit during opensm init +3551389 fix local port smlid in osm_send_trap144() +a6de48d opensm/osm_link_mgr.c initialize SMSL +82df467 opensm/osm_req.c: Shouldn't reveal port's MKey on Trap method +45ebff9 opensm/osm_console_io.h: Modify osm_console_exit so only the + connection is killed, not the socket +d10660a opensm/osm_req.c: In osm_send_trap144, set producer type according + to node type +8a2d2dd opensm/osm_node_info_rcv.c: create physp for the newly discovered + port of the known node +39b241f opensm/lid_mgr: fix duplicated lid assignment +b44c398 opensm: invalidate routing cache when entering master state +595f2e3 opensm: update LFTs when entering master +8406c65 opensm: fix port chooser +fa90512 opensm/osm_vendor_*_sa: fix incompatibility with QLogic SM +7ec9f7c opensm: discard multicast SA PR with wildcard DGID +5cdb53f opensm/osm_sa_node_record.c use comp mask to match by LID or GUID +55f9772 opensm: Return single PathRecord for SubnAdmGet with DGID/SGID wild + carded +5ec0b5f opensm: compress IPV6 SNM groups to use a single MLID +26e7e83 opensm/osm_lid_mgr: fix couple of duplicate LIDs bugs +fedc419 opensm: Multicast root switch calculation + +4.2 Other Bug Fixes + +4911e0b performance-manager-HOWTO.txt: Indicate master state +86ccaa4 opensm/osm_pkey_mgr.c: Fix pkey endian in log message +b79b079 opensm.8.in: Add mention of backing documentation for QoS policy + file and performance manager +b4d92af opensm/osm_perfmgr.c: Eliminate duplicated error number +a10b57a opensm/osm_ucast_ftree.c: lids are always handled in host order +44273a2 opensm/osm_ucast_ftree.c: fixing bug in indexing +5cd98f7 Fix further bugs around console closure and clean up code. +6b34339 opensm/osm_opensm.c: add newline to log message +68c241c send trap144 when local priority is higher than master priority +6462999 opensm/osm_inform.c: In __osm_send_report, make sure p_report_madw + valid before using +9b8561a opensm/console: Fixed osm_console poll to handle POLLHUP +91d0700 osm_vendor_ibumad.c: In clear_madw, fix tid endian in message +5a5136b osm_switch.h : Fixed wrong comment about return value of + osm_switch_set_hops +c1ec8c0 osm_ucast_ftree.c: Removed useless initialization on switch indexes +418d01f opensm/osm_helper.c: use single buffer in osm_dump_dr_smp() +2c9153c opensm/osm_helper.c: consolidate dr path printing code +048c447 opensm/osm_helper.c: return then log is inactive +dd3ef0c opensm: Return error status when cl_disp_register fails +0143bf7 opensm/osm_perfmgr.c: Improve assert in osm_pc_rcv_process +6622504 osm_perfmgr.c: In osm_perfmgr_shutdown, add missing cl_disp_unregister +7b66dee opensm: remove unneeded anymore physp initializations +f11274a opensm/partition-config.txt: Update for defmember feature +d240e7d opensm/osm_sm_state_mgr.c: Remove unneeded return statement +898fb8c opensm: Improve some snprintf uses +6820e63 opensm/osm_sa_link_record.c: improve get_base_lid() +64c8d31 opensm: initialize all switch ports +555fae8 opensm/sweep: add log message before lid assignment +8e22307 opensm/console: Enhance perfmgr print_counters for better nodenames +b9721a1 opensm/osm_console.c: Improve perfmgr print_counters error message +4d8dc72 opensm/osm_inform.c: Fix sense of zero GID compare in __match_inf_rec +a98dd82 opensm/main.c: remove enable_stack_dump() call +db6d51e opensm/osm_subnet: fix crash in qos string config parameters reloading +e5111c8 opensm: proper config file rescan +e5295b2 opensm: pre-scan command line for config file option +e2f549e opensm/osm_console.c: Eliminate some extraneous parentheses +0a265dc opensm/console: dump_portguid - don't duplicate matched guids +540fefb opensm/console: dump_portguid command fixes +d96202c opensm/osm_console.c: Add missing command in help_perfmgr +ae1bd3c opensm/osm_helper.c: Add port counters to __osm_disp_msg_str +1d38b31 opensm/osm_ucast_mgr.c: Add error numbers for some OSM_LOG prin +156c749 opensm: fix structure definition for trap 257-258 +5c09f4a opensm/osm_state_mgr.c: small bug in scanning lid table +72a2fa2 opensm/osm_sa.c: fixing SA MAD dump +539a4d3 opensm/osm_ucast_ftree.c Fixed bad init value for down port index +6690833 opensm/ftree: simplify root guids setup. +90e3291 opensm/ftree: cleanup ftree_sw_tbl_element_t use +c07d245 opensm/qos_config: no invalid option message on default values +b382ad8 opensm: avoid memory leaks on config parameters reloading +45f57ce opensm/osm_ucast_ftree.c: Fixed bug on index port incrementation +3d618aa opensm/osm_subnet.c: break matching when config parameter already found +44d98e3 opensm/osm_subnet.c: clean_val() remove trailing quotation +173010a opensm/doc/perf-manager-arch.txt: Fix some commentary typos +83bf6c5 opensm/osm_subnet.c fix parse functions for big endian machines +6b9a1e9 opensm/PerfMgr: Primarily fix enhanced switch port 0 perf manager + operation +4f79a17 opensm/osm_perfmgr.c: In osm_perfmgr_init, eliminate memory leak + on error +22da81f opensm/osm_ucast_ftree.c: fix full topology dump +aa25fcb opensm/osm_port_info_rcv.c: don't clear sw->need_update if port 0 + is active +003bd4b opensm/osm_subnet.c Fix memory leak for QOS string parameters. +9cbbab2 opensm/opensm.spec: fix event plugin config options +996e8f6 OpenSM: update osmeventplugin example for the new TRAP event. +67f4c07 opensm/lash: simplify some memory allocations +3e6bcdb opensm/lash: fix memory leaks +3ff97b9 opensm/vendor: save some stack memory +ccc7621 opensm/osm_ucast_ftree.c: fixing errors in comments +1a802b3 Corrected incoherency in __osm_ftree_fabric_route_to_non_cns comments +85a7e54 opensm/osm_sm.c: fix MC group creation in race condition +aad1af2 opensm/osm_trap_rcv.c: Improvements in log_trap_info() +f619d67 opensm/osm_trap_rcv.c: Minor reorganization of trap_rcv_process_request +084335b opensm/link_mgr: verify port's lid +d525931 opensm/osm_vendor_ibumad: Use OSM_UMAD_MAX_AGENTS rather than + UMAD_CA_MAX_AGENTS +f342c62 opensm/osm_sa.c: don't ignore failure in osm_mgrp_add_port() +587fda4 osmtest/osmt_multicast.c: fix strict aliasing breakage warning +6931f3e opensm: make subnet's max mlid update implementation independent +30f1acd osm_ucast_ftree.c missing reset of ca_ports +ac04779 opensm: fix LFT allocation size +a7838d0 opensm/osm_ucast_cache: reduce OSM_LOG_INFO debug printouts +c027335 opensm/osm_ucast_updn.c: Further reduction in cas_per_sw allocation +e8ee292 opensm/opensm/osm_subnet.c: adjust buffer to ensure a '\n' is printed +84d9830 opensm/osm_ucast_updn.c: Reduce temporary allocation of cas_per_sw +347ad64 opensm/ib_types.h: Mask off client rereg bit in set_client_rereg +c2ab189 opensm/osm_state_mgr.c: in cleanup_switch() check only relevant + LFT part +40c93d3 use transportable constant attributes +c8fa71a osmtest -code cleanup - use strncasecmp() +770704a opensm/osm_mcast_mgr.c: In mcast_mgr_set_mft_block, fix node GUID + in log message +3d20f82 opensm/osm_sa_path_record.c: separate router guid resolution code +27ea3c8 opensm: fix gcc-4.4.1 warnings +c88bfd3 opensm/osm_lid_mgr.c: Fix typo in OSM_LOG message +a9ea08c opensm/osm_mesh.c: Add dump_mesh routine at OSM_LOG_DEBUG level +bc2a61e C++ style coding does not compile +6647600 opensm: remove meanless 'const' keywords in APIs +323a74f opensm/osm_qos_parser_y.y: fix endless loop +0121a81 opensm: fix endless looping in mcast_mgr +696c022 opensm: fix some obvious -Wsign-compare warnings +b91e3c3 opensm/osm_get_port_by_lid(): don't bother with lmc +ca582df opensm/osm_get_port_by_lid(): speedup a port lookup +fd846ee opensm/osm_mesh.c: simplify compare_switches() function +fe20080 osm_sa.c - void * arithmetic causes problems +220130f osm_helper.c use explicit value for struct init +0168ece use standard varargs syntax in macro OSM_LOG() +180b335 update functions to match .h prototypes +9240ef4 opensm/osm_ucast_lash: fix use after free bug +6f1a21a opensm: osm_get_port_by_lid() helper +c9e2818 opensm/osm_sa_path_record.c: validate multicast membership +225dcf5 opensm/osm_mesh.c: Remove edges in lash matrix +4dd928b opensm/osm_sa_mcmember_record.c: clean uninitialized variable use +c48f0bc opensm/osm_perfmgr_db.c: Fix memory leak of db nodes +82d3585 opensm/osm_notice.c: move logging code to separate function +9557f60 opensm/osm_inform.c: For traps 64-67, use GID from DataDetails in + log message +e2e78d9 opensm/opensm.8.in: Indicate default rule for Default partition +08c5beb opensm/osm_sa_node_record.c: dump NodeInfo with debug verbosity +1fe88f0 opensm/multicast: merge mcm_port and mcm_info +ba75747 opensm/multicast: consolidate port addition/removing code +5e61ab8 opensm: port object reference in mcm ports list +5c5dacf opensm: fix uninitialized return value in osm_sm_mcgrp_leave() +7cfe18d osm_ucast_ftree.c: Removed reverse_hop parameters from + fabric_route_upgoing_by_going_down +aa7fb47 opensm/multicast: kill mc group to_be_deleted flag +a4910fe opensm/osm_mcast_mgr.c: multicast routing by mlid - renaming +1d14060 opensm/multicast: remove change id tracking +5a84951 opensm: use mgrp pointer as osm_sm_mcgrp_join/leave() parameter +d8e3ff5 opensm: use mgrp pointer in port mcm_info +0631cd3 opensm doc: Indicated limited (rather than partial) partition + membership +1010535 opensm/osm_ucast_lash.c: In lash_core, return status -1 for all errors +942e20f opensm/osm_helper.c: Add SM priority changed into trap 144 description +2372999 opensm/osm_ucast_mgr: better lft setup +e268b32 opensm/osm_helper.c: Only change method when > rather than >= +9309e8c complib/cl_event.c: change nanosec var type long +d93b126 opensm/complib: account for nsec overflow in timeout values +ef4c8ac opensm/osm_qos_policy.c: matching PR query to QoS level with pkey +c93b58b opensm: fixing some data types in osm_req_get/set +2b89177 opensm/libvendor/osm_vendor_ibumad.c: Handle umad_alloc failure in + osm_vendor_get +2cba163 opensm/osm_helper.c: In osm_dump_dr_smp, fix endian of status +47397e3 opensm/osm_sm_mad_ctrl.c: Fix endian of status in error message +e83b7ca opensm/osm_mesh.c: Reorder switches for lash +9256239 opensm/osm_trap_rcv.c: Validate trap is 144 before checking for + NodeDescription changed +011d9ca opensm/osm_ucast_lash.c: Handle calloc failure in generate_cdg_for_sp +59964d7 opensm: fixing handling of opt.max_wire_smps +f4e3cd0 opensm/osm_ucast_lash.c: Directly call calloc/free rather than + create/delete_cdg +5a208bd opensm/osm_ucast_lash.c: Added error numbers to some error log messages +3b80d10 opensm/osm_helper.c: fix printing trap 258 details +f682fe0 opensm: do not configure MFTs when mcast support is disabled +cc42095 opensm/osm_sm_mad_ctrl.c: In sm_mad_ctrl_send_err_cb, indicate + failed attribute +aebf215 opensm/osm_ucast_lash.c: Remove osm_mesh_node_delete call from + switch_delete +1ef4694 opensm/osm_path.h: In osm_dr_path_init, only copy needed part of path +c594a2d opensm: osm_dr_path_extend can fail due to invalid hop count +46e5668 opensm/osm_lash: Fix use after free problem in osm_mesh_node_delete +81841dc opensm/osm_ucast_lash.c: Handle malloc failures better +2801203 opensm: remove extra "0x" from debug message. +88821d2 opensm/main.c: Display SMSL when specified +f814dcd opensm/osm_subnet.c: Format lash_start_vl consistent with other + uint8 items +66669c9 opensm/main.c: Display LASH start VL when specified +31bb0a7 opensm/osm_mcst_mgr.c: check number of switches only once +75e672c opensm: find MC group by MGID using fleximap +2b7260d Clarify the syntax of the hop_weights_file +e6f0070 opensm/osm_mesh.c: Improve VL utilization +27497a0 opensm/osm_ucast_ftree.c Fix assert comparing number of CAs to CN ports +3b98131 opensm/osm_qos_policy.c: Use proper size in malloc in + osm_qos_policy_vlarb_scope_create +e6f367d opensm/osm_ucast_ftree.c: Made error numbers unique in some log + messages +83261a8 osm_ucast_ftree.c Count number of hops instead of calculating it +7bdf4ff opensm/osm_sa_(path multipath)_record.c: Fix typo in a couple of + log messages +0f8ed87 opensm/osm_ucast_mgr.c: Add error numbers to some error log messages +0b5ccb4 complib/Makefile.am: prevent file duplications +e0b8ec9 opensm/osm_sminfo_rcv.c: clean type of smi_rcv_process_get_sm() +4d01005 opensm: sweep component processors return status value +6ad8d78 opensm/libvendor/osm_vendor_(ibumad mlx)_sa.c: Handle malloc + failure in __osmv_send_sa_req +cf97ebf opensm/osm_ucast_lash.(h c): Replace memory allocation by array +957461c opensm/osm_sa.c add attribute and component mask to error message +5d339a1 osm_dump.c dump port if lft is set up +518083d osm_port.c: check if op_vls = 0 before max_op_vls comparison +b6964cb opensm/osm_port.c: Change log level of Invalid OP_VLS 0 message + to VERBOSE +b27568c opensm/PerfMgr: Reduce host name length +bc495c0 opensm/osm_lid_mgr.c bug in opensm LID assignment +5a466fd opensm/osm_perfmgr_db.c: Remove unneeded initialization in + perfmgr_db_print_by_name +57cf328 opensm/osm_ucast_ftree.c Increase the size of the hop table +8323cf1 opensm/PerfMgr: Remove some underbars from internal names +65b1c15 opensm: Changes to spec and make files for updated release notes +cd226c7 OpenSM: include/vendor/osm_vendor.h - Replaced #elif with no + condition by #else +9f8bd4a management: Fixed custom_release in SPEC files +c0b8207 opensm/PerfMgr: Change redir_tbl_size to num_ports for better clarity +596bb08 opensm/osm_sa.c: check for SA DB file only if requested +2f2bd4e opensm SA DB dump/restore: load SA DB only once +4abcbf2 opensm: Added print_desc to various log messages +5e3d235 opensm/osm_vendor_ibumad.c: Move error info into single message +8e5ca10 opensm/libvendor//osm_vendor_ibumad_sa.c: uninitialized fields +d13c2b6 opensm/osm_sm_mad_ctrl.c Changes to some error messages +f79d315 opensm/osm_sm_mad_ctrl.c: Add missing call to return mad to mad pool +150a9b1 opensm/osm_sa_mcmember_record.c: print mcast join/create failures in + VERBOSE instead of DEBUG level +9b7882a opensm/osm_vendor_ibumad.c: Change LID format to decimal in log message +5256c43 opensm/osm_vendor_mlx: fix compilation error +93db10d opensm/osm_vendor_mlx_txn.c: eliminate bunch of compilation warnings +156fdc1 opensm/osm_helper.c Log format changes +7a55434 opensm/osm_ucast_ftree.c Changed log level +a1694de opensm/osm_state_mgr.c Added more info to some error messages +fdec20a opensm/osm_trap_rcv.c: Eliminate heavy sweep on receipt of trap 145 +13a32a7 opensm - standardize on a single Windows #define - take #2 +b236a10 opensm/osm_db_files.c: kill useless malloc() castings +4ba0c26 opensm/osm_db_files.c: add '/' path delimited +e3b98a5 opensm/osm_sm_mad_ctrl.c: Fix qp0_mads_accounting +dbbe5b3 opensm/osm_subnet.c: fixing bug in dumping options file +f22856a opensm/osm_ucast_mgr.c: fix memory leak +0d5f0b6 opensm: osm_get_mgrp_by_mgid() helper +e3c044a osm_sa_mcmember_record.c: pass MCM Record data to mlid allocator +3dda2dc opensm/osm_sa_member_record.c: mlid independent MGID generator +1f95a3c opensm/osm_sa_mcmember_record.c: move mgid allocation code +b78add1 complib: replace intn_t types by C99 intptr_t +a864fd3 osmtest/osmt_mtl_regular_qp.c: cleaning uintn_t use +9e01318 opensm/osm_console.c: make const functions +f8c4c3e opensm/osm_mgrp_new(): add subnet db insertion +80da047 complib/fleximap: make compar callback to return int +bf7fe2d opensm: cleanup intn_t uses +0862bba opensm/main.c: opensm cannot be killed while asking for port guid +2b70193 opensm/complib: bug in cl_list_insert_array_head/tail functions +4764199 opensm - use C99 transportable data type for pointer storage +a9c326c opensm/osm_state_mgr.c: do not probe remote side of port 0 +4945706 opensm/osm_mcast_mgr.c: fix return value on alloc_mfts() failures +8312a24 OpenSM: Fix unused variable compiler warning. +ab8f0a3 opensm/partition: keep multicast group pointer +a817430 opensm: Only clear SMP beyond end of PortInfo attribute +52fb6f2 opensm/osm_switch.h: Remove dead osm_switch_get_physp_ptr routine +aa6d932 opensm/osm_mcast_tbl.c: In osm_mcast_tbl_clear_mlid, use memset to + clear port mask entry +2ad846b opensm/osm_trap_rcv.c: use source_lid and port_num for logging +b9d7756 opensm/osm_mcast_tbl: Fix size of port mask table array +11c0a9b opensm/main.c: Use strtoul rather than strtol for parsing transaction + timeout +0608af9 opensm/osm_sm_mad_ctrl.c: In sm_mad_ctrl_send_err_cb, revert setting + of init failure on QoS initialization failures +c6b4d4a opensm/osm_vendor_ibumad.c: Add transaction ID to osm_vendor_send + log message +520af84 opensm/osm_sa_path_record.c: don't set dgid pointer for local subnet +4a878fb opensm/osm_mcast_mgr.c: fix osm_mcast_mgr_compute_max_hops for + managed switch + +* 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 +-----------------------------------------|-------------------------- +The main stream Linux kernel | 2.6.x +OFED | 1.5,1.5.x +OFED | 1.4 +OFED | 1.3 +OFED | 1.2 +OFED | 1.1 +OFED | 1.0 + +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/branches/WOF2-3/ulp/opensm/user/doc/partition-config.txt b/branches/WOF2-3/ulp/opensm/user/doc/partition-config.txt new file mode 100644 index 00000000..50e40def --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/doc/partition-config.txt @@ -0,0 +1,131 @@ +OpenSM Partition configuration +=============================== + +The default name of OpenSM partitions configuration file is +'/etc/opensm/partitions.conf'. The default may be changed by +using the --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 always +have full membership in default partition. All other end ports will have +full membership if the partition configuration file is not found or cannot +be accessed, or limited membership if the file exists and can be accessed +but there is no rule for the Default partition. + +Effectively, this amounts to the same as if one of the following rules +below appear in the partition configuration file: +In the case of no rule for the Default partition: +Default=0x7fff : ALL=limited, SELF=full ; +In the case of no partition configuration file or file cannot be accessed: +Default=0x7fff : ALL=full ; + + +File Format +=========== + +Comments: +-------- + +Line content followed after '#' character is comment and ignored by +parser. + + +General file format: +------------------- + +: ; + + +Partition Definition: +-------------------- + +[PartitionName][=PKey][,flag[=value]][,defmember=full|limited] + +PartitionName - string, 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. +defmember=full|limited - specifies default membership for port guid + list. Default is limited. + +Currently recognized flags are: + +ipoib - indicates that this partition may be used for IPoIB, as + result IPoIB capable MC group will be created. +rate= - specifies rate for this IPoIB MC group (default is 3 (10GBps)) +mtu= - specifies MTU for this IPoIB MC group (default is 4 (2048)) +sl= - specifies SL for this IPoIB MC group (default is 0) +scope= - specifies scope for this IPoIB MC group (default is 2 (link +local)) + +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. +- 'ALL_CAS' means all Channel Adapter end ports in this subnet. +- 'ALL_SWITCHES' means all Switch end ports in this subnet. +- 'ALL_ROUTERS' means all Router 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 ; +Default=0x7fff : ALL, ALL_SWITCHES=full, 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; + diff --git a/branches/WOF2-3/ulp/opensm/user/doc/perf-manager-arch.txt b/branches/WOF2-3/ulp/opensm/user/doc/perf-manager-arch.txt new file mode 100644 index 00000000..2fc1fd25 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/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, possibly monitor 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 as 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/branches/WOF2-3/ulp/opensm/user/doc/performance-manager-HOWTO.txt b/branches/WOF2-3/ulp/opensm/user/doc/performance-manager-HOWTO.txt new file mode 100644 index 00000000..078e8b48 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/doc/performance-manager-HOWTO.txt @@ -0,0 +1,154 @@ +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 + 64 bit 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 in + addition to master state. + +Known issues are: + + 1) Data counters will be lost on high data rate links. Sweeping the + fabric fast enough for even a DDR link is not practical. + 2) Default partition support only. + + +Setup and Usage +=============== + +Using the Performance Manager consists of 3 steps: + + 1) compiling in support for the perfmgr (Optionally: the console + socket as well) + 2) enabling the perfmgr and console in opensm.conf + 3) retrieving data which has been collected. + 3a) using console to "dump data" + 3b) using a plugin module to store the data to your own + "database" + +Step 1: Compile in support for the Performance Manager +------------------------------------------------------ + +Because of the performance manager's experimental status, it is not enabled at +compile time by default. (This will hopefully soon change as more people use +it and confirm that it does not break things... ;-) The configure option is +"--enable-perf-mgr". + +At this time it is really best to enable the console socket option as well. +OpenSM can be run in an "interactive" mode. But with the console socket option +turned on one can also make a connection to a running OpenSM. The console +option is "--enable-console-socket". This option requires the use of +tcp_wrappers to ensure security. Please be aware of your configuration for +tcp_wrappers as the commands presented in the console can affect the operation +of your subnet. + +The following configure line includes turning on the performance manager as +well as the console: + + ./configure --enable-perf-mgr --enable-console-socket + + +Step 2: Enable the perfmgr and console in opensm.conf +----------------------------------------------------- + +Turning the Perfmorance Manager on is pretty easy, set the following options in +the opensm.conf config file. (Default location is +/usr/local/etc/opensm/opensm.conf) + + # Turn it all on. + perfmgr TRUE + + # sweep time in seconds + perfmgr_sweep_time_s 180 + + # Dump file to dump the events to + event_db_dump_file /var/log/opensm_port_counters.log + +Also enable the console socket and configure the port for it to listen to if +desired. + + # console [off|local|socket] + console socket + + # Telnet port for console (default 10000) + console_port 10000 + +As noted above you also need to set up tcp_wrappers to prevent unauthorized +users from connecting to the console.[*] + + [*] As an alternate you can use the loopback mode but I noticed when + writing this (OpenSM v3.1.10; OFED 1.3) that there are some bugs in + specifying the loopback mode in the opensm.conf file. Look for this to + be fixed in newer versions. + + [**] Also you could use "local" but this is only useful if you run + OpenSM in the foreground of a terminal. As OpenSM is usually started + as a daemon I left this out as an option. + +Step 3: retrieve data which has been collected +---------------------------------------------- + +Step 3a: Using console dump function +------------------------------------ + +The console command "perfmgr dump_counters" will dump counters to the file +specified in the opensm.conf file. In the example above +"/var/log/opensm_port_counters.log" + +Example output is below: + + +"SW1 wopr ISR9024D (MLX4 FW)" 0x8f10400411f56 port 1 (Since Mon May 12 13:27:14 2008) + symbol_err_cnt : 0 + link_err_recover : 0 + link_downed : 0 + rcv_err : 0 + rcv_rem_phys_err : 0 + rcv_switch_relay_err : 2 + xmit_discards : 0 + xmit_constraint_err : 0 + rcv_constraint_err : 0 + link_integrity_err : 0 + buf_overrun_err : 0 + vl15_dropped : 0 + xmit_data : 470435 + rcv_data : 405956 + xmit_pkts : 8954 + rcv_pkts : 6900 + unicast_xmit_pkts : 0 + unicast_rcv_pkts : 0 + multicast_xmit_pkts : 0 + multicast_rcv_pkts : 0 + + + +Step 3b: Using a plugin module +------------------------------ + +If you want a more automated method of retrieving the data OpenSM provides a +plugin interface to extend OpenSM. The header file is osm_event_plugin.h. +The functions you register with this interface will be called when data is +collected. You can then use that data as appropriate. + +An example plugin can be configured at compile time using the +"--enable-default-event-plugin" option on the configure line. This plugin is +very simple. It logs "events" received from the performance manager to a log +file. I don't recommend using this directly but rather use it as a template to +create your own plugin. + diff --git a/branches/WOF2-3/ulp/opensm/user/doc/qos-config.txt b/branches/WOF2-3/ulp/opensm/user/doc/qos-config.txt new file mode 100644 index 00000000..b71bf1d8 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/doc/qos-config.txt @@ -0,0 +1,44 @@ +Trivial low level QoS configuration proposition +=============================================== + +Basically there is a set of QoS related low-level configuration parameters. +All these parameter names are prefixed by "qos_" string. Here is a full +list of these parameters: + + qos_max_vls - The maximum number of VLs that will be on the subnet + qos_high_limit - The limit of High Priority component of VL Arbitration + table (IBA 7.6.9) + qos_vlarb_low - Low priority VL Arbitration table (IBA 7.6.9) template + qos_vlarb_high - High priority VL Arbitration table (IBA 7.6.9) template + Both VL arbitration templates are pairs of VL and weight + qos_sl2vl - SL2VL Mapping table (IBA 7.6.6) template. It is a list + of VLs corresponding to SLs 0-15 (Note the VL15 used + here means drop this SL) + +Typical default values (hard-coded in OpenSM initialization) are: + + qos_max_vls 15 + qos_high_limit 0 + qos_vlarb_low 0:0,1:4,2:4,3:4,4:4,5:4,6:4,7:4,8:4,9:4,10:4,11:4,12:4,13:4,14:4 + qos_vlarb_high 0:4,1:0,2:0,3:0,4:0,5:0,6:0,7:0,8:0,9:0,10:0,11:0,12:0,13:0,14:0 + qos_sl2vl 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,7 + +The syntax is compatible with rest of OpenSM configuration options and +values may be stored in OpenSM config file (cached options file). + +In addition to the above, we may define separate QoS configuration +parameters sets for various target types. As targets, we currently support +CAs, routers, switch external ports, and switch's enhanced port 0. The +names of such specialized parameters are prefixed by "qos__" +string. Here is a full list of the currently supported sets: + + qos_ca_ - QoS configuration parameters set for CAs. + qos_rtr_ - parameters set for routers. + qos_sw0_ - parameters set for switches' port 0. + qos_swe_ - parameters set for switches' external ports. + +Examples: + + qos_sw0_max_vls 2 + qos_ca_sl2vl 0,1,2,3,5,5,5,12,12,0, + qos_swe_high_limit 0 diff --git a/branches/WOF2-3/ulp/opensm/user/ibtrapgen/Makefile b/branches/WOF2-3/ulp/opensm/user/ibtrapgen/Makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/ibtrapgen/Makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\..\inc\openib.def diff --git a/branches/WOF2-3/ulp/opensm/user/ibtrapgen/SOURCES b/branches/WOF2-3/ulp/opensm/user/ibtrapgen/SOURCES new file mode 100644 index 00000000..b479a708 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/ibtrapgen/SOURCES @@ -0,0 +1,70 @@ +!if $(FREEBUILD) +TARGETNAME=ibtrapgen +!else +TARGETNAME=ibtrapgend +!endif + +!if !defined(WINIBHOME) +WINIBHOME=..\..\..\.. +!endif + +LIBPATH=$(WINIBHOME)\bin\user\obj$(BUILD_ALT_DIR) + +!if defined(OSM_TARGET) +TARGETPATH=$(OSM_TARGET)\bin\user\obj$(BUILD_ALT_DIR) +!else +TARGETPATH=$(WINIBHOME)\bin\user\obj$(BUILD_ALT_DIR) +!endif + +!INCLUDE ..\mad-vendor.inc + +TARGETTYPE=PROGRAM +UMTYPE=console +USE_MSVCRT=1 +OVR_DIR=..\addon + + +SOURCES=\ + main.c \ + ibtrapgen.c \ + osm_files.c + + +OSM_HOME=.. + +TARGETLIBS=\ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ +!if $(FREEBUILD) + $(VENDOR_LIBS) \ + $(LIBPATH)\*\ibal.lib \ + $(LIBPATH)\*\complib.lib +!else + $(VENDOR_LIBSD) \ + $(LIBPATH)\*\ibald.lib \ + $(LIBPATH)\*\complibd.lib +!endif + +INCLUDES= \ + $(WINIBHOME)\inc; \ + $(WINIBHOME)\inc\user; \ + $(WINIBHOME)\inc\user\linux; \ + $(VENDOR_INC); \ + $(OSM_HOME); \ + $(OSM_HOME)\include; + +# Could be any special flag needed for this project +USER_C_FLAGS=$(USER_C_FLAGS) /MD + +#Add preproccessor definitions +C_DEFINES=$(C_DEFINES) -D__WIN__ -D$(VENDOR_IF) -DHAVE_CONFIG_H + +!if !$(FREEBUILD) +#C_DEFINES=$(C_DEFINES) -D_DEBUG -DDEBUG -DDBG +C_DEFINES=$(C_DEFINES) +!endif + +LINKER_FLAGS= $(LINKER_FLAGS) + +MSC_WARNING_LEVEL= /W3 /wd4090 + diff --git a/branches/WOF2-3/ulp/opensm/user/ibtrapgen/ibtrapgen.c b/branches/WOF2-3/ulp/opensm/user/ibtrapgen/ibtrapgen.c new file mode 100644 index 00000000..452e4b6e --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/ibtrapgen/ibtrapgen.c @@ -0,0 +1,440 @@ +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + This software program is available to you under a choice of one of two + licenses. You may choose to be licensed under either the GNU General Public + License (GPL) Version 2, June 1991, available at + http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, + the text of which follows: + + "Recipient" has requested a license and Intel Corporation ("Intel") + is willing to grant a license for the software entitled + InfiniBand(tm) System Software (the "Software") being provided by + Intel Corporation. + + The following definitions apply to this License: + + "Licensed Patents" means patent claims licensable by Intel Corporation which + are necessarily infringed by the use or sale of the Software alone or when + combined with the operating system referred to below. + + "Recipient" means the party to whom Intel delivers this Software. + "Licensee" means Recipient and those third parties that receive a license to + any operating system available under the GNU Public License version 2.0 or + later. + + Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + + The license is provided to Recipient and Recipient's Licensees under the + following terms. + + Redistribution and use in source and binary forms of the Software, with or + without modification, are permitted provided that the following + conditions are met: + Redistributions of source code of the Software may retain the above copyright + notice, this list of conditions and the following disclaimer. + + Redistributions in binary form of the Software may reproduce the above + copyright notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + Neither the name of Intel Corporation nor the names of its contributors shall + be used to endorse or promote products derived from this Software without + specific prior written permission. + + Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, + royalty-free patent license under Licensed Patents to make, use, sell, offer + to sell, import and otherwise transfer the Software, if any, in source code + and object code form. This license shall include changes to the Software that + are error corrections or other minor changes to the Software that do not add + functionality or features when the Software is incorporated in any version of + a operating system that has been distributed under the GNU General Public + License 2.0 or later. This patent license shall apply to the combination of + the Software and any operating system licensed under the GNU Public License + version 2.0 or later if, at the time Intel provides the Software to + Recipient, such addition of the Software to the then publicly + available versions of such operating system available under the GNU + Public License version 2.0 or later (whether in gold, beta or alpha + form) causes such combination to be covered by the Licensed + Patents. The patent license shall not apply to any other + combinations which include the Software. No hardware per se is + licensed hereunder. + + 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 INTEL OR ITS 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. + --------------------------------------------------------------------------*/ + +/* + * Abstract: + * Implementation of ibtrapgen_t. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.2 $ + */ + +#include +#include +#include +#include +#include +#include +#include +#include "ibtrapgen.h" + +#define GUID_ARRAY_SIZE 64 + +/********************************************************************** + **********************************************************************/ +/* + This function initializes the main object, the log and the Osm Vendor +*/ +ib_api_status_t +ibtrapgen_init( IN ibtrapgen_t * const p_ibtrapgen, + IN ibtrapgen_opt_t * const p_opt, + IN const osm_log_level_t log_flags + ) +{ + ib_api_status_t status; + + /* just making sure - cleanup the static global obj */ + cl_memclr( p_ibtrapgen, sizeof( *p_ibtrapgen ) ); + + /* construct and init the log */ + p_ibtrapgen->p_log = (osm_log_t *)cl_malloc(sizeof(osm_log_t)); + osm_log_construct( p_ibtrapgen->p_log ); + status = osm_log_init( p_ibtrapgen->p_log, p_opt->force_log_flush, + 0x0001, p_opt->log_file,FALSE ); + if( status != IB_SUCCESS ) + return ( status ); + + osm_log_set_level( p_ibtrapgen->p_log, log_flags ); + + /* finaly can declare we are here ... */ + osm_log( p_ibtrapgen->p_log, OSM_LOG_FUNCS, + "ibtrapgen_init: [\n" ); + + /* assign all the opts */ + p_ibtrapgen->p_opt = p_opt; + + /* initialize the osm vendor service object */ + p_ibtrapgen->p_vendor = osm_vendor_new( p_ibtrapgen->p_log, + p_opt->transaction_timeout ); + + if( p_ibtrapgen->p_vendor == NULL ) + { + status = IB_INSUFFICIENT_RESOURCES; + osm_log( p_ibtrapgen->p_log, OSM_LOG_ERROR, + "ibtrapgen_init: ERR 0001: " + "Unable to allocate vendor object" ); + goto Exit; + } + + /* all mads (actually wrappers) are taken and returned to a pool */ + osm_mad_pool_construct( &p_ibtrapgen->mad_pool ); + status = osm_mad_pool_init( &p_ibtrapgen->mad_pool ); + if( status != IB_SUCCESS ) + goto Exit; + + Exit: + osm_log( p_ibtrapgen->p_log, OSM_LOG_FUNCS, + "ibtrapgen_init: ]\n" ); + return ( status ); +} + +/****f* opensm: SM/__ibtrapgen_rcv_callback + * NAME + * __osm_sm_mad_ctrl_rcv_callback + * + * DESCRIPTION + * This is the callback from the transport layer for received MADs. + * + * SYNOPSIS + */ +void +__ibtrapgen_rcv_callback( + IN osm_madw_t *p_madw, + IN void *bind_context, + IN osm_madw_t *p_req_madw ) +{ + ibtrapgen_t* p_ibtrapgen = (ibtrapgen_t*)bind_context; + + OSM_LOG_ENTER( p_ibtrapgen->p_log ); + + CL_ASSERT( p_madw ); + + OSM_LOG( p_ibtrapgen->p_log, OSM_LOG_VERBOSE, + "Got callback trans_id %64I\n", + cl_ntoh64(p_madw->p_mad->trans_id) ); + + OSM_LOG_EXIT( p_ibtrapgen->p_log ); +} + +/****f* opensm: SM/__ibtrapgen_send_err_cb + * NAME + * __ibtrapgen_send_err_cb + * + * DESCRIPTION + * This is the callback from the transport layer for received MADs. + * + * SYNOPSIS + */ +void +__ibtrapgen_send_err_cb( + IN void *bind_context, + IN osm_madw_t *p_madw ) +{ + ibtrapgen_t* p_ibtrapgen = (ibtrapgen_t*)bind_context; + + OSM_LOG_ENTER( p_ibtrapgen->p_log ); + + osm_log( p_ibtrapgen->p_log, OSM_LOG_ERROR, + "__ibtrapgen_send_err_cb: ERR 0011: " + "MAD completed in error (%s).\n", + ib_get_err_str( p_madw->status ) ); + + CL_ASSERT( p_madw ); + + osm_log( p_ibtrapgen->p_log, OSM_LOG_ERROR, + "__ibtrapgen_send_err_cb: ERR 0012: " + "We shouldn't be here!! TID:0x%016" PRIx64 ".\n", + cl_ntoh64(p_madw->p_mad->trans_id) ); + OSM_LOG_EXIT( p_ibtrapgen->p_log ); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +ibtrapgen_bind( IN ibtrapgen_t * p_ibtrapgen ) +{ + ib_api_status_t status; + uint32_t num_ports = GUID_ARRAY_SIZE; + ib_port_attr_t attr_array[GUID_ARRAY_SIZE]; + osm_bind_info_t bind_info; + uint8_t i; + + OSM_LOG_ENTER( p_ibtrapgen->p_log ); + + /* + * Call the transport layer for a list of local port + * GUID values. + */ + status = osm_vendor_get_all_port_attr( p_ibtrapgen->p_vendor, + attr_array, &num_ports ); + if ( status != IB_SUCCESS ) + { + osm_log( p_ibtrapgen->p_log, OSM_LOG_ERROR, + "ibtrapgen_bind: ERR 0002: " + "Failure getting local port attributes (%s)\n", + ib_get_err_str( status ) ); + goto Exit; + } + + /* make sure the requested port exists */ + if ( p_ibtrapgen->p_opt->port_num > num_ports ) + { + osm_log( p_ibtrapgen->p_log, OSM_LOG_ERROR, + "ibtrapgen_bind: ERR 0003: " + "Given port number out of range %u > %u\n", + p_ibtrapgen->p_opt->port_num , num_ports ); + status = IB_NOT_FOUND; + goto Exit; + } + + for ( i = 0 ; i < num_ports ; i++ ) + { + osm_log(p_ibtrapgen->p_log, OSM_LOG_INFO, + "ibtrapgen_bind: Found port number:%u " + " with GUID:0x%016" PRIx64 "\n", + i, cl_ntoh64(attr_array[i].port_guid) ); + } + /* check if the port is active */ +/* if (attr_array[p_ibtrapgen->p_opt->port_num - 1].link_state < 4) */ +/* { */ +/* osm_log( p_ibtrapgen->p_log, OSM_LOG_ERROR, */ +/* "ibtrapgen_bind: ERR 0004: " */ +/* "Given port number link state is not active: %s.\n", */ +/* ib_get_port_state_str( */ +/* attr_array[p_ibtrapgen->p_opt->port_num - 1].link_state ) */ +/* ); */ +/* status = IB_NOT_FOUND; */ +/* goto Exit; */ +/* } */ + + p_ibtrapgen->port_guid = attr_array[p_ibtrapgen->p_opt->port_num - 1].port_guid; + /* save sm_lid as we need it when sending the Trap (dest lid)*/ + p_ibtrapgen->p_opt->sm_lid = attr_array[p_ibtrapgen->p_opt->port_num - 1].sm_lid; + + osm_log(p_ibtrapgen->p_log, OSM_LOG_DEBUG, + "ibtrapgen_bind: Port Num:%u " + "GUID:0x%016"PRIx64"\n", + p_ibtrapgen->p_opt->port_num, + p_ibtrapgen->port_guid ); + + /* ok finaly bind the sa interface to this port */ + /* TODO - BIND LIKE THE osm_sm_mad_ctrl does */ + bind_info.class_version = 1; + bind_info.is_report_processor = TRUE; + bind_info.is_responder = TRUE; + bind_info.is_trap_processor = TRUE; + bind_info.mad_class = IB_MCLASS_SUBN_LID; + bind_info.port_guid = p_ibtrapgen->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_ibtrapgen->p_log, OSM_LOG_DEBUG, + "ibtrapgen_bind: Trying to bind to GUID:0x%016"PRIx64"\n", + bind_info.port_guid ); + + p_ibtrapgen->h_bind = osm_vendor_bind( p_ibtrapgen->p_vendor, + &bind_info, + &p_ibtrapgen->mad_pool, + __ibtrapgen_rcv_callback, + __ibtrapgen_send_err_cb, + p_ibtrapgen ); + + if( p_ibtrapgen->h_bind == OSM_BIND_INVALID_HANDLE ) + { + osm_log( p_ibtrapgen->p_log, OSM_LOG_ERROR, + "ibtrapgen_bind: ERR 0005: " + "Unable to bind to SA\n" ); + status = IB_ERROR; + goto Exit; + } + + Exit: + OSM_LOG_EXIT( p_ibtrapgen->p_log ); + return ( status ); +} + +/********************************************************************** + **********************************************************************/ +void +ibtrapgen_destroy( IN ibtrapgen_t * p_ibtrapgen ) +{ + if( p_ibtrapgen->p_vendor ) + { + osm_vendor_delete( &p_ibtrapgen->p_vendor ); + } + + osm_log_destroy( p_ibtrapgen->p_log ); + cl_free( p_ibtrapgen->p_log ); +} + +/********************************************************************** + **********************************************************************/ + +ib_api_status_t +ibtrapgen_run( IN ibtrapgen_t * const p_ibtrapgen ) +{ + osm_madw_t* p_report_madw; + ib_mad_notice_attr_t* p_report_ntc; + ib_mad_t* p_mad; + ib_smp_t* p_smp_mad; + osm_mad_addr_t mad_addr; + static atomic32_t trap_fwd_trans_id = 0x02DAB000; + ib_api_status_t status; + osm_log_t *p_log = p_ibtrapgen->p_log; + uint16_t i; + + OSM_LOG_ENTER( p_log ); + + osm_log( p_log, OSM_LOG_INFO, + "ibtrapgen_run: " + "Sending trap:%u from LID:0x%X %u times\n", + p_ibtrapgen->p_opt->trap_num, + p_ibtrapgen->p_opt->lid, + p_ibtrapgen->p_opt->number ); + + printf("-V- SM lid is : 0x%04X\n",cl_ntoh16(p_ibtrapgen->p_opt->sm_lid)); + mad_addr.dest_lid = (p_ibtrapgen->p_opt->sm_lid); + /* ??? - what is path_bits? What should be the value here?? */ + mad_addr.path_bits = 0; + /* ??? - what is static_rate? What should be the value here?? */ + mad_addr.static_rate = 0; + + mad_addr.addr_type.smi.source_lid = cl_hton16(p_ibtrapgen->p_opt->lid); + mad_addr.addr_type.smi.port_num = p_ibtrapgen->p_opt->src_port; + + for (i = 1 ; i <= p_ibtrapgen->p_opt->number ; i++ ) + { + p_report_madw = osm_mad_pool_get( &p_ibtrapgen->mad_pool, + p_ibtrapgen->h_bind, + MAD_BLOCK_SIZE, + &mad_addr ); + + if( !p_report_madw ) + { + osm_log(p_log, OSM_LOG_ERROR, + "ibtrapgen_run: ERR 00020: " + "osm_mad_pool_get failed.\n" ); + status = IB_ERROR; + goto Exit; + } + + p_report_madw->resp_expected = FALSE; + + /* 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_LID, + 1, + IB_MAD_METHOD_TRAP, + cl_hton64( (uint64_t)cl_atomic_inc( &trap_fwd_trans_id ) ), + IB_MAD_ATTR_NOTICE, + 0); + + p_smp_mad = osm_madw_get_smp_ptr( p_report_madw ); + + /* The payload is analyzed as mad notice attribute */ + p_report_ntc = (ib_mad_notice_attr_t*)(ib_smp_get_payload_ptr(p_smp_mad)); + + cl_memclr( p_report_ntc, sizeof(*p_report_ntc) ); + p_report_ntc->generic_type = 0x83; /* is generic subn mgt type */ + ib_notice_set_prod_type(p_report_ntc, 2); /* A switch generator */ + p_report_ntc->g_or_v.generic.trap_num = cl_hton16(p_ibtrapgen->p_opt->trap_num); + p_report_ntc->issuer_lid = cl_hton16(p_ibtrapgen->p_opt->lid); + if (p_ibtrapgen->p_opt->trap_num == 128) + { + p_report_ntc->data_details.ntc_128.sw_lid = cl_hton16(p_ibtrapgen->p_opt->lid); + } + else + { + p_report_ntc->data_details.ntc_129_131.lid = + cl_hton16(p_ibtrapgen->p_opt->lid); + p_report_ntc->data_details.ntc_129_131.port_num = + p_ibtrapgen->p_opt->src_port; + } + + status = osm_vendor_send(p_report_madw->h_bind, p_report_madw, FALSE ); + if (status != IB_SUCCESS) + { + osm_log(p_log, OSM_LOG_ERROR, + "ibtrapgen_run: ERR 0021: " + "osm_vendor_send. status = %s\n", + ib_get_err_str(status)); + goto Exit; + } + osm_log(p_log, OSM_LOG_INFO, + "ibtrapgen_run: " + "Sent trap number:%u out of:%u\n", + i, + p_ibtrapgen->p_opt->number ); + /* sleep according to rate time. The usleep is in usec - need to revert + the milisecs to usecs. */ + usleep(p_ibtrapgen->p_opt->rate*1000); + } + + Exit: + OSM_LOG_EXIT( p_log ); + return(status); +} diff --git a/branches/WOF2-3/ulp/opensm/user/ibtrapgen/ibtrapgen.h b/branches/WOF2-3/ulp/opensm/user/ibtrapgen/ibtrapgen.h new file mode 100644 index 00000000..6fe54862 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/ibtrapgen/ibtrapgen.h @@ -0,0 +1,313 @@ +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + This software program is available to you under a choice of one of two + licenses. You may choose to be licensed under either the GNU General Public + License (GPL) Version 2, June 1991, available at + http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, + the text of which follows: + + "Recipient" has requested a license and Intel Corporation ("Intel") + is willing to grant a license for the software entitled + InfiniBand(tm) System Software (the "Software") being provided by + Intel Corporation. + + The following definitions apply to this License: + + "Licensed Patents" means patent claims licensable by Intel Corporation which + are necessarily infringed by the use or sale of the Software alone or when + combined with the operating system referred to below. + + "Recipient" means the party to whom Intel delivers this Software. + "Licensee" means Recipient and those third parties that receive a license to + any operating system available under the GNU Public License version 2.0 or + later. + + Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + + The license is provided to Recipient and Recipient's Licensees under the + following terms. + + Redistribution and use in source and binary forms of the Software, with or + without modification, are permitted provided that the following + conditions are met: + Redistributions of source code of the Software may retain the above copyright + notice, this list of conditions and the following disclaimer. + + Redistributions in binary form of the Software may reproduce the above + copyright notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + Neither the name of Intel Corporation nor the names of its contributors shall + be used to endorse or promote products derived from this Software without + specific prior written permission. + + Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, + royalty-free patent license under Licensed Patents to make, use, sell, offer + to sell, import and otherwise transfer the Software, if any, in source code + and object code form. This license shall include changes to the Software that + are error corrections or other minor changes to the Software that do not add + functionality or features when the Software is incorporated in any version of + a operating system that has been distributed under the GNU General Public + License 2.0 or later. This patent license shall apply to the combination of + the Software and any operating system licensed under the GNU Public License + version 2.0 or later if, at the time Intel provides the Software to + Recipient, such addition of the Software to the then publicly + available versions of such operating system available under the GNU + Public License version 2.0 or later (whether in gold, beta or alpha + form) causes such combination to be covered by the Licensed + Patents. The patent license shall not apply to any other + combinations which include the Software. No hardware per se is + licensed hereunder. + + 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 INTEL OR ITS 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. + --------------------------------------------------------------------------*/ + + +/* + * Abstract: + * Declaration of ibtrapgen_t. + * This object represents the ibtrapgen object. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.1 $ + */ + +#ifndef _IBTRAPGEN_H_ +#define _IBTRAPGEN_H_ + +#include +#include +#include +#include +#include +#include + +/****h* Trap_Generator_App/Ibtrapgen + * NAME + * Ibtrapgen + * + * DESCRIPTION + * The Ibtrapgen object create/join and leave multicast group. + * + * AUTHOR + * Yael Kalka, Mellanox. + * + *********/ + +/****s* Trap_Generator_App/ibtrapgen_opt_t + * NAME + * ibtrapgen_opt_t + * + * DESCRIPTION + * Ibtrapgen options structure. This structure contains the various + * specific configuration parameters for ibtrapgen. + * + * SYNOPSYS + */ +typedef struct _ibtrapgen_opt +{ + uint8_t trap_num; + uint16_t number; + uint16_t rate; + uint16_t lid; + uint16_t sm_lid; + uint8_t src_port; + uint8_t port_num; + uint32_t transaction_timeout; + boolean_t force_log_flush; + char *log_file; +} ibtrapgen_opt_t; +/* + * FIELDS + * + * trap_num + * Trap number to generate. + * + * number + * Number of times trap should be generated. + * + * rate + * Rate of trap generation (in miliseconds) + * + * lid + * Lid from which the trap should be generated. + * + * src_port + * Source port from which the trap should be generated. + * + * port_num + * Port num used for communicating with the SA. + * + * SEE ALSO + *********/ + +/****s* Trap Generator App/ibtrapgen_t + * NAME + * ibtrapgen_t + * + * DESCRIPTION + * Ibtrapgen structure. + * + * This object should be treated as opaque and should + * be manipulated only through the provided functions. + * + * SYNOPSYS + */ +typedef struct _ibtrapgen +{ + osm_log_t *p_log; + struct _osm_vendor *p_vendor; + osm_bind_handle_t h_bind; + osm_mad_pool_t mad_pool; + + ibtrapgen_opt_t *p_opt; + ib_net64_t port_guid; +} ibtrapgen_t; +/* + * FIELDS + * p_log + * Log facility used by all Ibtrapgen 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 + * + * p_opt + * ibtrapgen options structure + * + * guid + * guid for the port over which ibtrapgen is running. + * + * SEE ALSO + *********/ + +/****f* Trap_Generator_App/ibtrapgen_destroy + * NAME + * ibtrapgen_destroy + * + * DESCRIPTION + * The ibtrapgen_destroy function destroys an ibtrapgen object, releasing + * all resources. + * + * SYNOPSIS + */ +void ibtrapgen_destroy( IN ibtrapgen_t * p_ibtrapgen ); + +/* + * PARAMETERS + * p_ibtrapgen + * [in] Pointer to a Trap_Generator_App object to destroy. + * + * RETURN VALUE + * This function does not return a value. + * + * NOTES + * Performs any necessary cleanup of the specified Trap_Generator_App object. + * Further operations should not be attempted on the destroyed object. + * This function should only be called after a call to ibtrapgen_init. + * + * SEE ALSO + * ibtrapgen_init + *********/ + +/****f* Trap_Generator_App/ibtrapgen_init + * NAME + * ibtrapgen_init + * + * DESCRIPTION + * The ibtrapgen_init function initializes a Trap_Generator_App object for use. + * + * SYNOPSIS + */ +ib_api_status_t ibtrapgen_init( IN ibtrapgen_t * const p_ibtrapgen, + IN ibtrapgen_opt_t * const p_opt, + IN const osm_log_level_t log_flags + ); + +/* + * PARAMETERS + * p_ibtrapgen + * [in] Pointer to an ibtrapgen_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 Trap_Generator_App object was initialized successfully. + * + * NOTES + * Allows calling other Trap_Generator_App methods. + * + * SEE ALSO + * ibtrapgen object, ibtrapgen_construct, ibtrapgen_destroy + *********/ + + +/****f* Trap_Generator_App/ibtrapgen_bind + * NAME + * ibtrapgen_bind + * + * DESCRIPTION + * Binds ibtrapgen to a local port. + * + * SYNOPSIS + */ +ib_api_status_t ibtrapgen_bind( IN ibtrapgen_t * p_ibtrapgen ); +/* + * PARAMETERS + * p_ibtrapgen + * [in] Pointer to an ibtrapgen_t object. + * + * RETURN VALUES + * IB_SUCCESS if OK + * + * NOTES + * + * SEE ALSO + *********/ + +/****f* Trap_Generator_App/ibtrapgen_run + * NAME + * ibtrapgen_run + * + * DESCRIPTION + * Runs the ibtrapgen flow: Creation of traps. + * + * SYNOPSIS + */ +ib_api_status_t ibtrapgen_run( IN ibtrapgen_t * const p_ibtrapgen ); + +/* + * PARAMETERS + * p_ibtrapgen + * [in] Pointer to an ibtrapgen_t object. + * + * RETURN VALUES + * IB_SUCCESS on success + * + * NOTES + * + * SEE ALSO + *********/ + +#endif /* */ diff --git a/branches/WOF2-3/ulp/opensm/user/ibtrapgen/main.c b/branches/WOF2-3/ulp/opensm/user/ibtrapgen/main.c new file mode 100644 index 00000000..f7f1de7d --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/ibtrapgen/main.c @@ -0,0 +1,465 @@ +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + This software program is available to you under a choice of one of two + licenses. You may choose to be licensed under either the GNU General Public + License (GPL) Version 2, June 1991, available at + http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, + the text of which follows: + + "Recipient" has requested a license and Intel Corporation ("Intel") + is willing to grant a license for the software entitled + InfiniBand(tm) System Software (the "Software") being provided by + Intel Corporation. + + The following definitions apply to this License: + + "Licensed Patents" means patent claims licensable by Intel Corporation which + are necessarily infringed by the use or sale of the Software alone or when + combined with the operating system referred to below. + + "Recipient" means the party to whom Intel delivers this Software. + "Licensee" means Recipient and those third parties that receive a license to + any operating system available under the GNU Public License version 2.0 or + later. + + Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + + The license is provided to Recipient and Recipient's Licensees under the + following terms. + + Redistribution and use in source and binary forms of the Software, with or + without modification, are permitted provided that the following + conditions are met: + Redistributions of source code of the Software may retain the above copyright + notice, this list of conditions and the following disclaimer. + + Redistributions in binary form of the Software may reproduce the above + copyright notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + Neither the name of Intel Corporation nor the names of its contributors shall + be used to endorse or promote products derived from this Software without + specific prior written permission. + + Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, + royalty-free patent license under Licensed Patents to make, use, sell, offer + to sell, import and otherwise transfer the Software, if any, in source code + and object code form. This license shall include changes to the Software that + are error corrections or other minor changes to the Software that do not add + functionality or features when the Software is incorporated in any version of + a operating system that has been distributed under the GNU General Public + License 2.0 or later. This patent license shall apply to the combination of + the Software and any operating system licensed under the GNU Public License + version 2.0 or later if, at the time Intel provides the Software to + Recipient, such addition of the Software to the then publicly + available versions of such operating system available under the GNU + Public License version 2.0 or later (whether in gold, beta or alpha + form) causes such combination to be covered by the Licensed + Patents. The patent license shall not apply to any other + combinations which include the Software. No hardware per se is + licensed hereunder. + + 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 INTEL OR ITS 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. + --------------------------------------------------------------------------*/ + + +/* + * Abstract: + * Command line interface for ibtrapgen. + * Parse and fill in the options and call the actual code. + * Implemented in ibtrapgen: + * Initialize the ibmgrp object (and log) + * Bind ibmgrp to the requested IB port. + * Run the actual command + * + * Environment: + * Linux User Mode + * + * $Revision: 1.1 $ + */ + +#include +#include +#ifndef __WIN__ +#include +#endif +#include +#include +#include "ibtrapgen.h" + +#define DEFAULT_RETRY_COUNT 3 +#define DEFAULT_TRANS_TIMEOUT_MILLISEC 1000 + +/********************************************************************** + **********************************************************************/ +boolean_t +ibtrapgen_is_debug() +{ +#if defined( _DEBUG_ ) + return TRUE; +#else + return FALSE; +#endif /* defined( _DEBUG_ ) */ +} + +/********************************************************************** + **********************************************************************/ +void show_usage(void); + +void +show_usage( ) +{ + printf( "\n------- ibtrapgen - Usage and options ----------------------\n" ); + printf( "Usage: one of the following optional flows:\n" ); + printf(" ibtrapgen -t|--trap_num -n|--number \n" + " -r|--rate -l|--lid \n" + " -s|--src_port -p|--port_num \n" ); + printf( "\nOptions:\n" ); + printf( "-t \n" + "--trap_num \n" + " This option specifies the number of the trap to generate.\n" + " Valid values are 128-131.\n" ); + printf( "-n \n" + "--number \n" + " This option specifies the number of times to generate this trap.\n" + " If not specified - default to 1.\n" ); + printf( "-r \n" + "--rate \n" + " This option specifies the rate of the trap generation.\n" + " What is the time period between one generation and another?\n" + " The value is given in miliseconds. \n" + " If the number of trap creations is 1 - this value is ignored.\n" ); + printf( "-l \n" + "--lid \n" + " This option specifies the lid address from where the trap should\n" + " be generated.\n" ); + printf( "-s \n" + "--src_port \n" + " This option specifies the port number from which the trap should\n" + " be generated. If trap number is 128 - this value is ignored (since\n" + " trap 128 is not sent with a specific port number)\n" ); + printf( "-p \n" + "--port_num \n" + " This is the port number used for communicating with\n" + " the SA.\n" ); + printf( "-h\n" + "--help\n" " Display this usage info then exit.\n\n" ); + printf( "-o\n" + "--out_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( "-x \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 -x, ibtrapgen defaults to ERROR + INFO (0x3).\n" + " Specifying -x 0 disables all messages.\n" + " Specifying -x 0xFF enables all messages (see -V).\n\n" ); +} + +/********************************************************************** + **********************************************************************/ +/* + Converts a GID string of the format 0xPPPPPPPPPPPPPPPP:GGGGGGGGGGGGGGGG + to a gid type +*/ +int +str2gid( + IN char *str, + OUT ib_gid_t *p_gid + ); + +int +str2gid( + IN char *str, + OUT ib_gid_t *p_gid + ) +{ + ib_gid_t temp; + char buf[38]; + char *p_prefix, *p_guid; + + CL_ASSERT(p_gid); + + strcpy(buf, str); + p_prefix = buf; + /*p_guid = index(buf, ':');*/ + p_guid = strchr( buf, ':' ); + + if (! p_guid) + { + printf("Wrong format for gid %s\n", buf); + return 1; + } + + *p_guid = '\0'; + p_guid++; + + errno = 0; + temp.unicast.prefix = cl_hton64(strtoull(p_prefix, NULL, 0)); + if (errno) { + printf("Wrong format for gid prefix:%s (got %u)\n", + p_prefix, errno); + return 1; + } + + temp.unicast.interface_id = cl_hton64(strtoull(p_guid, NULL, 16)); + if (errno) { + printf("Wrong format for gid guid:%s\n", p_guid); + return 1; + } + + *p_gid = temp; + return 0; +} +void OsmReportState(IN const char *p_str) +{ +} +/********************************************************************** + **********************************************************************/ +int OSM_CDECL +main( int argc, + char *argv[] ) +{ + static ibtrapgen_t ibtrapgen; + ibtrapgen_opt_t opt = { 0 }; + ib_api_status_t status; + uint32_t log_flags = OSM_LOG_ERROR | OSM_LOG_INFO; + uint32_t next_option; + const char *const short_option = "t:n:r:s:l:p:o:vVh"; + + /* + * 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[] = { + {"trap_num", 1, NULL, 't'}, + {"number", 1, NULL, 'n'}, + {"rate", 1, NULL, 'r'}, + {"lid", 1, NULL, 'l'}, + {"src_port", 1, NULL, 's'}, + {"port_num", 1, NULL, 'p'}, + {"help", 0, NULL, 'h'}, + {"verbose", 0, NULL, 'v'}, + {"out_log_file", 1, NULL, 'o'}, + {"vf", 1, NULL, 'x'}, + {"V", 0, NULL, 'V'}, + + {NULL, 0, NULL, 0} /* Required at end of array */ + }; + + + opt.trap_num = 0; + opt.number = 1; /* This is the default value */ + opt.rate = 0; + opt.lid = 0; + opt.src_port = 0; + opt.port_num = 0; + opt.log_file = NULL; + opt.force_log_flush = FALSE; + opt.transaction_timeout = DEFAULT_TRANS_TIMEOUT_MILLISEC; + + do + { + next_option = getopt_long_only( argc, argv, short_option, + long_option, NULL ); + + switch ( next_option ) + { + case 't': + /* + * Define the trap number + */ + opt.trap_num = (uint8_t)atoi( optarg ); + if ((opt.trap_num < 128) || (opt.trap_num > 131)) + { + printf( "-E- Given trap number is illegal! \n" + " Supportes generation of traps 128-131.\n" ); + exit(1); + } + printf( "-I- Trap Number = %u\n", opt.trap_num ); + break; + + case 'n': + /* + * Define the number of occurences + */ + opt.number = (uint16_t)atoi( optarg ); + + printf( "-I- Number Trap Occurences = %u\n", opt.number ); + break; + + case 'r': + /* + * Define the rate of the trap + */ + opt.rate = (uint16_t)atoi( optarg ); + + printf( "-I- Trap Rate = %u miliseconds\n", opt.rate ); + break; + + + case 'l': + /* + * Define the source lid of the trap + */ + opt.lid = (uint16_t)strtoul( optarg , NULL , 16); + + printf( "-I- Trap Lid = 0x%04X\n", opt.lid ); + break; + + case 's': + /* + * Define the source port number of the trap + */ + opt.src_port = (uint8_t)atoi( optarg ); + + printf( "-I- Trap Port Number = %u\n", opt.src_port ); + break; + + case 'p': + /* + * Specifies port guid with which to bind. + */ + opt.port_num = (uint8_t)atoi( optarg ); + printf( "-I- Port Num:%u\n", opt.port_num ); + break; + + case 'o': + opt.log_file = optarg; + printf("-I- Log File:%s\n", opt.log_file ); + break; + + case 'v': + /* + * Increases log verbosity. + */ + log_flags = ( log_flags << 1 ) | 1; + printf( "-I- Verbose 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( "-I- Enabling maximum log verbosity\n" ); + break; + + case 'h': + show_usage( ); + return 0; + + case 'x': + log_flags = strtol( optarg, NULL, 0 ); + printf( "-I- Verbose 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 ); + + /* Check for mandatory options */ + if (opt.trap_num == 0) + { + printf( "-E- Missing trap number.\n" ); + exit(1); + } + if (opt.lid == 0) + { + printf( "-E- Missing lid.\n" ); + exit(1); + } + if (opt.src_port == 0 && opt.trap_num >= 129 && opt.trap_num <= 131) + { + /* for trap 129-131 should be given source port number */ + printf( "-E- source port number.\n" ); + exit(1); + } + if (opt.port_num == 0) + { + printf( "-E- Missing port number.\n" ); + exit(1); + } + if (opt.rate == 0 && opt.number > 1) + { + /* for number of traps greater than 1 need to give the rate for the + trap generation. */ + printf( "-E- Missing rate.\n" ); + exit(1); + } + + + /* init the main object and sub objects (log and osm vendor) */ + status = ibtrapgen_init( &ibtrapgen, &opt, ( osm_log_level_t ) log_flags ); + if( status != IB_SUCCESS ) + { + printf("-E- fail to init ibtrapgen.\n"); + goto Exit; + } + + /* bind to a specific port */ + status = ibtrapgen_bind( &ibtrapgen ); + if (status != IB_SUCCESS) exit(status); + + /* actual work */ + status = ibtrapgen_run( &ibtrapgen ); + if (status != IB_SUCCESS) + { + printf("IBTRAPGEN: FAIL\n"); + } + else + { + printf("IBTRAPGEN: PASS\n"); + } + + //ibtrapgen_destroy( &ibtrapgen ); + + Exit: + exit ( status ); +} diff --git a/branches/WOF2-3/ulp/opensm/user/ibtrapgen/osm_files.c b/branches/WOF2-3/ulp/opensm/user/ibtrapgen/osm_files.c new file mode 100644 index 00000000..95065542 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/ibtrapgen/osm_files.c @@ -0,0 +1,9 @@ + +/* Supply required OpenSM src files - easier to maintain/diff these files + * against OFE/openSM source. + */ + +#include <..\opensm\osm_mad_pool.c> +#include <..\opensm\osm_log.c> +#include <..\opensm\osm_helper.c> + diff --git a/branches/WOF2-3/ulp/opensm/user/ibtrapgen/vendor-ibal.inc b/branches/WOF2-3/ulp/opensm/user/ibtrapgen/vendor-ibal.inc new file mode 100644 index 00000000..303cdd49 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/ibtrapgen/vendor-ibal.inc @@ -0,0 +1,2 @@ + +!INCLUDE ..\opensm\vendor-ibal.inc diff --git a/branches/WOF2-3/ulp/opensm/user/ibtrapgen/vendor-umad.inc b/branches/WOF2-3/ulp/opensm/user/ibtrapgen/vendor-umad.inc new file mode 100644 index 00000000..d106d80f --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/ibtrapgen/vendor-umad.inc @@ -0,0 +1,2 @@ + +!INCLUDE ..\opensm\vendor-umad.inc diff --git a/branches/WOF2-3/ulp/opensm/user/include/README.txt b/branches/WOF2-3/ulp/opensm/user/include/README.txt new file mode 100644 index 00000000..fa4f3220 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/README.txt @@ -0,0 +1,15 @@ + + +****** WARNING ****** + +Do not confuse the folders iba\ and complib\ with the folders trunk\inc\complib trunk\inc\iba ! + +The folders in trunk\inc\ are prefered and searched first when building OpenSM! + +The iba\ folder is present to track OFED ib_types.h changes in order to stay in sync; not used in opensm build. + + 'In spirit' the files user\include\iba\ib_types.h == inc\iba\ib_types.h are equivalent. + +One day into the future, ib_types.h will be split apart where some of those parts end up +in opensm\user\inc\ relevant folders. Point being in ib_types.h contains far too many +disjoint definitions, collect the OpenSM and MAD handling items in respective .h files. \ No newline at end of file diff --git a/branches/WOF2-3/ulp/opensm/user/include/complib/cl_dispatcher.h b/branches/WOF2-3/ulp/opensm/user/include/complib/cl_dispatcher.h new file mode 100644 index 00000000..0840f62a --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/complib/cl_dispatcher.h @@ -0,0 +1,631 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of dispatcher abstraction. + */ + +#ifndef _CL_DISPATCHER_H_ +#define _CL_DISPATCHER_H_ + +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* Component Library/Dispatcher +* NAME +* Dispatcher +* +* DESCRIPTION +* The Dispatcher provides a facility for message routing to +* asynchronous worker threads. +* +* The Dispatcher functions operate on a cl_dispatcher_t structure +* which should be treated as opaque and should be manipulated +* only through the provided functions. +* +* SEE ALSO +* Structures: +* cl_dispatcher_t +* +* Initialization/Destruction: +* cl_disp_construct, cl_disp_init, cl_disp_shutdown, cl_disp_destroy +* +* Manipulation: +* cl_disp_post, cl_disp_reset, cl_disp_wait_on +*********/ +/****s* Component Library: Dispatcher/cl_disp_msgid_t +* NAME +* cl_disp_msgid_t +* +* DESCRIPTION +* Defines the type of dispatcher messages. +* +* SYNOPSIS +*/ +typedef uint32_t cl_disp_msgid_t; +/**********/ + +/****s* Component Library: Dispatcher/CL_DISP_MSGID_NONE +* NAME +* CL_DISP_MSGID_NONE +* +* DESCRIPTION +* Defines a message value that means "no message". +* This value is used during registration by Dispatcher clients +* that do not wish to receive messages. +* +* No Dispatcher message is allowed to have this value. +* +* SYNOPSIS +*/ +#define CL_DISP_MSGID_NONE 0xFFFFFFFF +/**********/ + +/****s* Component Library: Dispatcher/CL_DISP_INVALID_HANDLE +* NAME +* CL_DISP_INVALID_HANDLE +* +* DESCRIPTION +* Defines the value of an invalid Dispatcher registration handle. +* +* SYNOPSIS +*/ +#define CL_DISP_INVALID_HANDLE ((cl_disp_reg_handle_t)0) +/*********/ + +/****f* Component Library: Dispatcher/cl_pfn_msgrcv_cb_t +* NAME +* cl_pfn_msgrcv_cb_t +* +* DESCRIPTION +* This typedef defines the prototype for client functions invoked +* by the Dispatcher. The Dispatcher calls the corresponding +* client function when delivering a message to the client. +* +* The client function must be reentrant if the user creates a +* Dispatcher with more than one worker thread. +* +* SYNOPSIS +*/ +typedef void + (*cl_pfn_msgrcv_cb_t) (IN void *context, IN void *p_data); +/* +* PARAMETERS +* context +* [in] Client specific context specified in a call to +* cl_disp_register +* +* p_data +* [in] Pointer to the client specific data payload +* of this message. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* This typedef provides a function prototype reference for +* the function provided by Dispatcher clients as a parameter +* to the cl_disp_register function. +* +* SEE ALSO +* Dispatcher, cl_disp_register +*********/ + +/****f* Component Library: Dispatcher/cl_pfn_msgdone_cb_t +* NAME +* cl_pfn_msgdone_cb_t +* +* DESCRIPTION +* This typedef defines the prototype for client functions invoked +* by the Dispatcher. The Dispatcher calls the corresponding +* client function after completing delivery of a message. +* +* The client function must be reentrant if the user creates a +* Dispatcher with more than one worker thread. +* +* SYNOPSIS +*/ +typedef void + (*cl_pfn_msgdone_cb_t) (IN void *context, IN void *p_data); +/* +* PARAMETERS +* context +* [in] Client specific context specified in a call to +* cl_disp_post +* +* p_data +* [in] Pointer to the client specific data payload +* of this message. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* This typedef provides a function prototype reference for +* the function provided by Dispatcher clients as a parameter +* to the cl_disp_post function. +* +* SEE ALSO +* Dispatcher, cl_disp_post +*********/ + +/****s* Component Library: Dispatcher/cl_dispatcher_t +* NAME +* cl_dispatcher_t +* +* DESCRIPTION +* Dispatcher structure. +* +* The Dispatcher is thread safe. +* +* The cl_dispatcher_t structure should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _cl_dispatcher { + cl_spinlock_t lock; + cl_ptr_vector_t reg_vec; + cl_qlist_t reg_list; + cl_thread_pool_t worker_threads; + cl_qlist_t msg_fifo; + cl_qpool_t msg_pool; + uint64_t last_msg_queue_time_us; +} cl_dispatcher_t; +/* +* FIELDS +* reg_vec +* Vector of registration info objects. Indexed by message msg_id. +* +* lock +* Spinlock to guard internal structures. +* +* msg_fifo +* FIFO of messages being processed by the Dispatcher. New +* messages are posted to the tail of the FIFO. Worker threads +* pull messages from the front. +* +* worker_threads +* Thread pool of worker threads to dispose of posted messages. +* +* msg_pool +* Pool of message objects to be processed through the FIFO. +* +* reg_count +* Count of the number of registrants. +* +* state +* Indicates the state of the object. +* +* last_msg_queue_time_us +* The time that the last message spent in the Q in usec +* +* SEE ALSO +* Dispatcher +*********/ + +/****s* Component Library: Dispatcher/cl_disp_reg_info_t +* NAME +* cl_disp_reg_info_t +* +* DESCRIPTION +* Defines the dispatcher registration object structure. +* +* The cl_disp_reg_info_t structure is for internal use by the +* Dispatcher only. +* +* SYNOPSIS +*/ +typedef struct _cl_disp_reg_info { + cl_list_item_t list_item; + cl_pfn_msgrcv_cb_t pfn_rcv_callback; + const void *context; + atomic32_t ref_cnt; + cl_disp_msgid_t msg_id; + cl_dispatcher_t *p_disp; +} cl_disp_reg_info_t; +/* +* FIELDS +* pfn_rcv_callback +* Client's message receive callback. +* +* context +* Client's context for message receive callback. +* +* rcv_thread_count +* Number of threads currently in the receive callback. +* +* msg_done_thread_count +* Number of threads currently in the message done callback. +* +* state +* State of this registration object. +* DISP_REGSTATE_INIT: initialized and inactive +* DISP_REGSTATE_ACTIVE: in active use +* DISP_REGSTATE_UNREGPEND: unregistration is pending +* +* msg_id +* Dispatcher message msg_id value for this registration object. +* +* p_disp +* Pointer to parent Dispatcher. +* +* SEE ALSO +*********/ + +/****s* Component Library: Dispatcher/cl_disp_msg_t +* NAME +* cl_disp_msg_t +* +* DESCRIPTION +* Defines the dispatcher message structure. +* +* The cl_disp_msg_t structure is for internal use by the +* Dispatcher only. +* +* SYNOPSIS +*/ +typedef struct _cl_disp_msg { + cl_pool_item_t item; + const void *p_data; + cl_disp_reg_info_t *p_src_reg; + cl_disp_reg_info_t *p_dest_reg; + cl_pfn_msgdone_cb_t pfn_xmt_callback; + uint64_t in_time; + const void *context; +} cl_disp_msg_t; +/* +* FIELDS +* item +* List & Pool linkage. Must be first element in the structure!! +* +* msg_id +* The message's numberic ID value. +* +* p_data +* Pointer to the data payload for this message. The payload +* is opaque to the Dispatcher. +* +* p_reg_info +* Pointer to the registration info of the sender. +* +* pfn_xmt_callback +* Client's message done callback. +* +* in_time +* The absolute time the message was inserted into the queue +* +* context +* Client's message done callback context. +* +* SEE ALSO +*********/ + +/****s* Component Library: Dispatcher/cl_disp_reg_info_t +* NAME +* cl_disp_reg_info_t +* +* DESCRIPTION +* Defines the Dispatcher registration handle. This handle +* should be treated as opaque by the client. +* +* SYNOPSIS +*/ +typedef const struct _cl_disp_reg_info *cl_disp_reg_handle_t; +/**********/ + +/****f* Component Library: Dispatcher/cl_disp_construct +* NAME +* cl_disp_construct +* +* DESCRIPTION +* This function constructs a Dispatcher object. +* +* SYNOPSIS +*/ +void cl_disp_construct(IN cl_dispatcher_t * const p_disp); +/* +* PARAMETERS +* p_disp +* [in] Pointer to a Dispatcher. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling cl_disp_init and cl_disp_destroy. +* +* SEE ALSO +* Dispatcher, cl_disp_init, cl_disp_destroy +*********/ + +/****f* Component Library: Dispatcher/cl_disp_init +* NAME +* cl_disp_init +* +* DESCRIPTION +* This function initializes a Dispatcher object. +* +* SYNOPSIS +*/ +cl_status_t +cl_disp_init(IN cl_dispatcher_t * const p_disp, + IN const uint32_t thread_count, IN const char *const name); +/* +* PARAMETERS +* p_disp +* [in] Pointer to a Dispatcher. +* +* thread_count +* [in] The number of worker threads to create in this Dispatcher. +* A value of 0 causes the Dispatcher to create one worker thread +* per CPU in the system. When the Dispatcher is created with +* only one thread, the Dispatcher guarantees to deliver posted +* messages in order. When the Dispatcher is created with more +* than one thread, messages may be delivered out of order. +* +* name +* [in] Name to associate with the threads. The name may be up to 16 +* characters, including a terminating null character. All threads +* created in the Dispatcher have the same name. +* +* RETURN VALUE +* CL_SUCCESS if the operation is successful. +* +* SEE ALSO +* Dispatcher, cl_disp_destoy, cl_disp_register, cl_disp_unregister, +* cl_disp_post +*********/ + +/****f* Component Library: Dispatcher/cl_disp_shutdown +* NAME +* cl_disp_shutdown +* +* DESCRIPTION +* This function shutdown a Dispatcher object. So it unreg all messages and +* clears the fifo and waits for the threads to exit +* +* SYNOPSIS +*/ +void cl_disp_shutdown(IN cl_dispatcher_t * const p_disp); +/* +* PARAMETERS +* p_disp +* [in] Pointer to a Dispatcher. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* This function does not returns until all worker threads +* have exited client callback functions and been successfully +* shutdowned. +* +* SEE ALSO +* Dispatcher, cl_disp_construct, cl_disp_init +*********/ + +/****f* Component Library: Dispatcher/cl_disp_destroy +* NAME +* cl_disp_destroy +* +* DESCRIPTION +* This function destroys a Dispatcher object. +* +* SYNOPSIS +*/ +void cl_disp_destroy(IN cl_dispatcher_t * const p_disp); +/* +* PARAMETERS +* p_disp +* [in] Pointer to a Dispatcher. +* +* RETURN VALUE +* This function does not return a value. +* +* SEE ALSO +* Dispatcher, cl_disp_construct, cl_disp_init +*********/ + +/****f* Component Library: Dispatcher/cl_disp_register +* NAME +* cl_disp_register +* +* DESCRIPTION +* This function registers a client with a Dispatcher object. +* +* SYNOPSIS +*/ +cl_disp_reg_handle_t +cl_disp_register(IN cl_dispatcher_t * const p_disp, + IN const cl_disp_msgid_t msg_id, + IN cl_pfn_msgrcv_cb_t pfn_callback OPTIONAL, + IN const void *const context); +/* +* PARAMETERS +* p_disp +* [in] Pointer to a Dispatcher. +* +* msg_id +* [in] Numberic message ID for which the client is registering. +* If the client does not wish to receive any messages, +* (a send-only client) then the caller should set this value +* to CL_DISP_MSGID_NONE. For efficiency, numeric message msg_id +* values should start with 0 and should be contiguous, or nearly so. +* +* pfn_callback +* [in] Message receive callback. The Dispatcher calls this +* function after receiving a posted message with the +* appropriate message msg_id value. Send-only clients may specify +* NULL for this value. +* +* context +* [in] Client context value passed to the cl_pfn_msgrcv_cb_t +* function. +* +* RETURN VALUE +* On success a Dispatcher registration handle. +* CL_CL_DISP_INVALID_HANDLE otherwise. +* +* SEE ALSO +* Dispatcher, cl_disp_unregister, cl_disp_post +*********/ + +/****f* Component Library: Dispatcher/cl_disp_unregister +* NAME +* cl_disp_unregister +* +* DESCRIPTION +* This function unregisters a client from a Dispatcher. +* +* SYNOPSIS +*/ +void cl_disp_unregister(IN const cl_disp_reg_handle_t handle); +/* +* PARAMETERS +* handle +* [in] cl_disp_reg_handle_t value return by cl_disp_register. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* This function will not return until worker threads have exited +* the callback functions for this client. Do not invoke this +* function from a callback. +* +* SEE ALSO +* Dispatcher, cl_disp_register +*********/ + +/****f* Component Library: Dispatcher/cl_disp_post +* NAME +* cl_disp_post +* +* DESCRIPTION +* This function posts a message to a Dispatcher object. +* +* SYNOPSIS +*/ +cl_status_t +cl_disp_post(IN const cl_disp_reg_handle_t handle, + IN const cl_disp_msgid_t msg_id, + IN const void *const p_data, + IN cl_pfn_msgdone_cb_t pfn_callback OPTIONAL, + IN const void *const context); +/* +* PARAMETERS +* handle +* [in] cl_disp_reg_handle_t value return by cl_disp_register. +* +* msg_id +* [in] Numeric message msg_id value associated with this message. +* +* p_data +* [in] Data payload for this message. +* +* pfn_callback +* [in] Pointer to a cl_pfn_msgdone_cb_t function. +* The Dispatcher calls this function after the message has been +* processed by the recipient. +* The caller may pass NULL for this value, which indicates no +* message done callback is necessary. +* +* context +* [in] Client context value passed to the cl_pfn_msgdone_cb_t +* function. +* +* RETURN VALUE +* CL_SUCCESS if the message was successfully queued in the Dispatcher. +* +* NOTES +* The caller must not modify the memory pointed to by p_data until +* the Dispatcher call the pfn_callback function. +* +* SEE ALSO +* Dispatcher +*********/ + +/****f* Component Library: Dispatcher/cl_disp_get_queue_status +* NAME +* cl_disp_get_queue_status +* +* DESCRIPTION +* This function posts a message to a Dispatcher object. +* +* SYNOPSIS +*/ +void +cl_disp_get_queue_status(IN const cl_disp_reg_handle_t handle, + OUT uint32_t * p_num_queued_msgs, + OUT uint64_t * p_last_msg_queue_time_ms); +/* +* PARAMETERS +* handle +* [in] cl_disp_reg_handle_t value return by cl_disp_register. +* +* p_last_msg_queue_time_ms +* [out] pointer to a variable to hold the time the last popped up message +* spent in the queue +* +* p_num_queued_msgs +* [out] number of messages in the queue +* +* RETURN VALUE +* Thr time the last popped up message stayed in the queue, in msec +* +* NOTES +* Extarnel Locking is not required. +* +* SEE ALSO +* Dispatcher +*********/ + +END_C_DECLS +#endif /* !defined(_CL_DISPATCHER_H_) */ diff --git a/branches/WOF2-3/ulp/opensm/user/include/complib/cl_event_wheel.h b/branches/WOF2-3/ulp/opensm/user/include/complib/cl_event_wheel.h new file mode 100644 index 00000000..abc5ed00 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/complib/cl_event_wheel.h @@ -0,0 +1,457 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of event wheel abstraction. + */ + +#ifndef _CL_EVENT_WHEEL_H_ +#define _CL_EVENT_WHEEL_H_ + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* Component Library/Event_Wheel +* NAME +* Event_Wheel +* +* DESCRIPTION +* The Event_Wheel provides a facility for registering delayed events +* and getting called once they timeout. +* +* The Event_Wheel functions operate on a cl_event_wheel_t structure +* which should be treated as opaque and should be manipulated +* only through the provided functions. +* +* SEE ALSO +* Structures: +* cl_event_wheel_t +* +* Initialization/Destruction: +* cl_event_wheel_construct, cl_event_wheel_init, cl_event_wheel_destroy +* +* Manipulation: +* cl_event_wheel_reg, cl_event_wheel_unreg +* +*********/ +/****f* Component Library: Event_Wheel/cl_pfn_event_aged_cb_t +* NAME +* cl_pfn_event_aged_cb_t +* +* DESCRIPTION +* This typedef defines the prototype for client functions invoked +* by the Event_Wheel. The Event_Wheel calls the corresponding +* client function when the specific item has aged. +* +* SYNOPSIS +*/ +typedef uint64_t + (*cl_pfn_event_aged_cb_t) (IN uint64_t key, + IN uint32_t num_regs, IN void *context); +/* +* PARAMETERS +* key +* [in] The key used for registering the item in the call to +* cl_event_wheel_reg +* +* num_regs +* [in] The number of times this event was registered (pushed in time). +* +* context +* [in] Client specific context specified in a call to +* cl_event_wheel_reg +* +* RETURN VALUE +* This function returns the abosolute time the event should fire in [usec]. +* If lower then current time means the event should be unregistered +* immediatly. +* +* NOTES +* This typedef provides a function prototype reference for +* the function provided by Event_Wheel clients as a parameter +* to the cl_event_wheel_reg function. +* +* SEE ALSO +* Event_Wheel, cl_event_wheel_reg +*********/ + +/****s* Component Library: Event_Wheel/cl_event_wheel_t +* NAME +* cl_event_wheel_t +* +* DESCRIPTION +* Event_Wheel structure. +* +* The Event_Wheel is thread safe. +* +* The cl_event_wheel_t structure should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _cl_event_wheel { + cl_spinlock_t lock; + cl_spinlock_t *p_external_lock; + + cl_qmap_t events_map; + boolean_t closing; + cl_qlist_t events_wheel; + cl_timer_t timer; +} cl_event_wheel_t; +/* +* FIELDS +* lock +* Spinlock to guard internal structures. +* +* p_external_lock +* Reference to external spinlock to guard internal structures +* if the event wheel is part of a larger object protected by its own lock +* +* events_map +* A Map holding all registered event items by their key. +* +* closing +* A flag indicating the event wheel is closing. This means that +* callbacks that are called when closing == TRUE should just be ignored. +* +* events_wheel +* A list of the events sorted by expiration time. +* +* timer +* The timer scheduling event time propagation. +* +* SEE ALSO +* Event_Wheel +*********/ + +/****s* Component Library: Event_Wheel/cl_event_wheel_reg_info_t +* NAME +* cl_event_wheel_reg_info_t +* +* DESCRIPTION +* Defines the event_wheel registration object structure. +* +* The cl_event_wheel_reg_info_t structure is for internal use by the +* Event_Wheel only. +* +* SYNOPSIS +*/ +typedef struct _cl_event_wheel_reg_info { + cl_map_item_t map_item; + cl_list_item_t list_item; + uint64_t key; + cl_pfn_event_aged_cb_t pfn_aged_callback; + uint64_t aging_time; + uint32_t num_regs; + void *context; + cl_event_wheel_t *p_event_wheel; +} cl_event_wheel_reg_info_t; +/* +* FIELDS +* map_item +* The map item of this event +* +* list_item +* The sorted by aging time list item +* +* key +* The key by which one can find the event +* +* pfn_aged_callback +* The clients Event-Aged callback +* +* aging_time +* The delta time [msec] for which the event should age. +* +* num_regs +* The number of times the same event (key) was registered +* +* context +* Client's context for event-aged callback. +* +* p_event_wheel +* Pointer to this event wheel object +* +* SEE ALSO +*********/ + +/****f* Component Library: Event_Wheel/cl_event_wheel_construct +* NAME +* cl_event_wheel_construct +* +* DESCRIPTION +* This function constructs a Event_Wheel object. +* +* SYNOPSIS +*/ +void cl_event_wheel_construct(IN cl_event_wheel_t * const p_event_wheel); +/* +* PARAMETERS +* p_event_wheel +* [in] Pointer to a Event_Wheel. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling cl_event_wheel_init and cl_event_wheel_destroy. +* +* SEE ALSO +* Event_Wheel, cl_event_wheel_init, cl_event_wheel_destroy +*********/ + +/****f* Component Library: Event_Wheel/cl_event_wheel_init +* NAME +* cl_event_wheel_init +* +* DESCRIPTION +* This function initializes a Event_Wheel object. +* +* SYNOPSIS +*/ +cl_status_t +cl_event_wheel_init(IN cl_event_wheel_t * const p_event_wheel); + +/* +* PARAMETERS +* p_event_wheel +* [in] Pointer to a Event_Wheel. +* +* RETURN VALUE +* CL_SUCCESS if the operation is successful. +* +* SEE ALSO +* Event_Wheel, cl_event_wheel_destoy, cl_event_wheel_reg, cl_event_wheel_unreg +* +*********/ + +/****f* Component Library: Event_Wheel/cl_event_wheel_init +* NAME +* cl_event_wheel_init +* +* DESCRIPTION +* This function initializes a Event_Wheel object. +* +* SYNOPSIS +*/ +cl_status_t +cl_event_wheel_init_ex(IN cl_event_wheel_t * const p_event_wheel, + IN cl_spinlock_t * p_external_lock); + +/* +* PARAMETERS +* p_event_wheel +* [in] Pointer to a Event_Wheel. +* +* p_external_lock +* [in] Reference to external spinlock to guard internal structures +* if the event wheel is part of a larger object protected by its own lock +* +* RETURN VALUE +* CL_SUCCESS if the operation is successful. +* +* SEE ALSO +* Event_Wheel, cl_event_wheel_destoy, cl_event_wheel_reg, cl_event_wheel_unreg +* +*********/ + +/****f* Component Library: Event_Wheel/cl_event_wheel_destroy +* NAME +* cl_event_wheel_destroy +* +* DESCRIPTION +* This function destroys a Event_Wheel object. +* +* SYNOPSIS +*/ +void cl_event_wheel_destroy(IN cl_event_wheel_t * const p_event_wheel); +/* +* PARAMETERS +* p_event_wheel +* [in] Pointer to a Event_Wheel. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* This function does not returns until all client callback functions +* been successfully finished. +* +* SEE ALSO +* Event_Wheel, cl_event_wheel_construct, cl_event_wheel_init +*********/ + +/****f* Component Library: Event_Wheel/cl_event_wheel_dump +* NAME +* cl_event_wheel_dump +* +* DESCRIPTION +* This function dumps the details of an Event_Whell object. +* +* SYNOPSIS +*/ +void cl_event_wheel_dump(IN cl_event_wheel_t * const p_event_wheel); +/* +* PARAMETERS +* p_event_wheel +* [in] Pointer to a Event_Wheel. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Note that this function should be called inside a lock of the event wheel! +* It doesn't aquire the lock by itself. +* +* SEE ALSO +* Event_Wheel, cl_event_wheel_construct, cl_event_wheel_init +*********/ + +/****f* Component Library: Event_Wheel/cl_event_wheel_reg +* NAME +* cl_event_wheel_reg +* +* DESCRIPTION +* This function registers a client with a Event_Wheel object. +* +* SYNOPSIS +*/ +cl_status_t +cl_event_wheel_reg(IN cl_event_wheel_t * const p_event_wheel, + IN const uint64_t key, + IN const uint64_t aging_time_usec, + IN cl_pfn_event_aged_cb_t pfn_callback, + IN void *const context); +/* +* PARAMETERS +* p_event_wheel +* [in] Pointer to a Event_Wheel. +* +* key +* [in] The specifc Key by which events are registered. +* +* aging_time_usec +* [in] The absolute time this event should age in usec +* +* pfn_callback +* [in] Event Aging callback. The Event_Wheel calls this +* function after the time the event has registed for has come. +* +* context +* [in] Client context value passed to the cl_pfn_event_aged_cb_t +* function. +* +* RETURN VALUE +* On success a Event_Wheel CL_SUCCESS or CL_ERROR otherwise. +* +* SEE ALSO +* Event_Wheel, cl_event_wheel_unreg +*********/ + +/****f* Component Library: Event_Wheel/cl_event_wheel_unreg +* NAME +* cl_event_wheel_unreg +* +* DESCRIPTION +* This function unregisters a client event from a Event_Wheel. +* +* SYNOPSIS +*/ +void +cl_event_wheel_unreg(IN cl_event_wheel_t * const p_event_wheel, + IN uint64_t key); +/* +* PARAMETERS +* p_event_wheel +* [in] Pointer to a Event_Wheel. +* +* key +* [in] The key used for registering the event +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* After the event has aged it is automatically removed from +* the event wheel. So it should only be invoked when the need arises +* to remove existing events before they age. +* +* SEE ALSO +* Event_Wheel, cl_event_wheel_reg +*********/ + +/****f* Component Library: Event_Wheel/cl_event_wheel_num_regs +* NAME +* cl_event_wheel_num_regs +* +* DESCRIPTION +* This function returns the number of times an event was registered. +* +* SYNOPSIS +*/ +uint32_t +cl_event_wheel_num_regs(IN cl_event_wheel_t * const p_event_wheel, + IN uint64_t key); +/* +* PARAMETERS +* p_event_wheel +* [in] Pointer to a Event_Wheel. +* +* key +* [in] The key used for registering the event +* +* RETURN VALUE +* The number of times the event was registered. +* 0 if never registered or eventually aged. +* +* SEE ALSO +* Event_Wheel, cl_event_wheel_reg, cl_event_wheel_unreg +*********/ + +END_C_DECLS +#endif /* !defined(_CL_EVENT_WHEEL_H_) */ diff --git a/branches/WOF2-3/ulp/opensm/user/include/iba/ib_cm_types.h b/branches/WOF2-3/ulp/opensm/user/include/iba/ib_cm_types.h new file mode 100644 index 00000000..29fa2bcc --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/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 __WIN__ + +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/* + * Defines known Communication management class versions + */ +#define IB_MCLASS_CM_VER_2 2 +#define IB_MCLASS_CM_VER_1 1 +/* + * Defines the size of user available data in communication management MADs + */ +#define IB_REQ_PDATA_SIZE_VER2 92 +#define IB_MRA_PDATA_SIZE_VER2 222 +#define IB_REJ_PDATA_SIZE_VER2 148 +#define IB_REP_PDATA_SIZE_VER2 196 +#define IB_RTU_PDATA_SIZE_VER2 224 +#define IB_LAP_PDATA_SIZE_VER2 168 +#define IB_APR_PDATA_SIZE_VER2 148 +#define IB_DREQ_PDATA_SIZE_VER2 220 +#define IB_DREP_PDATA_SIZE_VER2 224 +#define IB_SIDR_REQ_PDATA_SIZE_VER2 216 +#define IB_SIDR_REP_PDATA_SIZE_VER2 136 +#define IB_REQ_PDATA_SIZE_VER1 92 +#define IB_MRA_PDATA_SIZE_VER1 222 +#define IB_REJ_PDATA_SIZE_VER1 148 +#define IB_REP_PDATA_SIZE_VER1 204 +#define IB_RTU_PDATA_SIZE_VER1 224 +#define IB_LAP_PDATA_SIZE_VER1 168 +#define IB_APR_PDATA_SIZE_VER1 151 +#define IB_DREQ_PDATA_SIZE_VER1 220 +#define IB_DREP_PDATA_SIZE_VER1 224 +#define IB_SIDR_REQ_PDATA_SIZE_VER1 216 +#define IB_SIDR_REP_PDATA_SIZE_VER1 140 +#define IB_ARI_SIZE 72 // redefine +#define IB_APR_INFO_SIZE 72 +/****d* Access Layer/ib_rej_status_t +* NAME +* ib_rej_status_t +* +* DESCRIPTION +* Rejection reasons. +* +* SYNOPSIS +*/ +typedef ib_net16_t ib_rej_status_t; +/* +* SEE ALSO +* ib_cm_rej, ib_cm_rej_rec_t +* +* SOURCE +*/ +#define IB_REJ_INSUF_QP CL_HTON16(1) +#define IB_REJ_INSUF_EEC CL_HTON16(2) +#define IB_REJ_INSUF_RESOURCES CL_HTON16(3) +#define IB_REJ_TIMEOUT CL_HTON16(4) +#define IB_REJ_UNSUPPORTED CL_HTON16(5) +#define IB_REJ_INVALID_COMM_ID CL_HTON16(6) +#define IB_REJ_INVALID_COMM_INSTANCE CL_HTON16(7) +#define IB_REJ_INVALID_SID CL_HTON16(8) +#define IB_REJ_INVALID_XPORT CL_HTON16(9) +#define IB_REJ_STALE_CONN CL_HTON16(10) +#define IB_REJ_RDC_NOT_EXIST CL_HTON16(11) +#define IB_REJ_INVALID_GID CL_HTON16(12) +#define IB_REJ_INVALID_LID CL_HTON16(13) +#define IB_REJ_INVALID_SL CL_HTON16(14) +#define IB_REJ_INVALID_TRAFFIC_CLASS CL_HTON16(15) +#define IB_REJ_INVALID_HOP_LIMIT CL_HTON16(16) +#define IB_REJ_INVALID_PKT_RATE CL_HTON16(17) +#define IB_REJ_INVALID_ALT_GID CL_HTON16(18) +#define IB_REJ_INVALID_ALT_LID CL_HTON16(19) +#define IB_REJ_INVALID_ALT_SL CL_HTON16(20) +#define IB_REJ_INVALID_ALT_TRAFFIC_CLASS CL_HTON16(21) +#define IB_REJ_INVALID_ALT_HOP_LIMIT CL_HTON16(22) +#define IB_REJ_INVALID_ALT_PKT_RATE CL_HTON16(23) +#define IB_REJ_PORT_REDIRECT CL_HTON16(24) +#define IB_REJ_INVALID_MTU CL_HTON16(26) +#define IB_REJ_INSUFFICIENT_RESP_RES CL_HTON16(27) +#define IB_REJ_USER_DEFINED CL_HTON16(28) +#define IB_REJ_INVALID_RNR_RETRY CL_HTON16(29) +#define IB_REJ_DUPLICATE_LOCAL_COMM_ID CL_HTON16(30) +#define IB_REJ_INVALID_CLASS_VER CL_HTON16(31) +#define IB_REJ_INVALID_FLOW_LBL CL_HTON16(32) +#define IB_REJ_INVALID_ALT_FLOW_LBL CL_HTON16(33) + +#define IB_REJ_SERVICE_HANDOFF CL_HTON16(65535) +/******/ + +/****d* Access Layer/ib_apr_status_t +* NAME +* ib_apr_status_t +* +* DESCRIPTION +* Automatic path migration status information. +* +* SYNOPSIS +*/ +typedef uint8_t ib_apr_status_t; +/* +* SEE ALSO +* ib_cm_apr, ib_cm_apr_rec_t +* +* SOURCE + */ +#define IB_AP_SUCCESS 0 +#define IB_AP_INVALID_COMM_ID 1 +#define IB_AP_UNSUPPORTED 2 +#define IB_AP_REJECT 3 +#define IB_AP_REDIRECT 4 +#define IB_AP_IS_CURRENT 5 +#define IB_AP_INVALID_QPN_EECN 6 +#define IB_AP_INVALID_LID 7 +#define IB_AP_INVALID_GID 8 +#define IB_AP_INVALID_FLOW_LBL 9 +#define IB_AP_INVALID_TCLASS 10 +#define IB_AP_INVALID_HOP_LIMIT 11 +#define IB_AP_INVALID_PKT_RATE 12 +#define IB_AP_INVALID_SL 13 +/******/ + +/****d* Access Layer/ib_cm_cap_mask_t +* NAME +* ib_cm_cap_mask_t +* +* DESCRIPTION +* Capability mask values in ClassPortInfo. +* +* SYNOPSIS +*/ +#define IB_CM_RELIABLE_CONN_CAPABLE CL_HTON16(9) +#define IB_CM_RELIABLE_DGRM_CAPABLE CL_HTON16(10) +#define IB_CM_RDGRM_CAPABLE CL_HTON16(11) +#define IB_CM_UNRELIABLE_CONN_CAPABLE CL_HTON16(12) +#define IB_CM_SIDR_CAPABLE CL_HTON16(13) +/* +* SEE ALSO +* ib_cm_rep, ib_class_port_info_t +* +* SOURCE +* +*******/ + +/* + * Service ID resolution status + */ +typedef uint16_t ib_sidr_status_t; +#define IB_SIDR_SUCCESS 0 +#define IB_SIDR_UNSUPPORTED 1 +#define IB_SIDR_REJECT 2 +#define IB_SIDR_NO_QP 3 +#define IB_SIDR_REDIRECT 4 +#define IB_SIDR_UNSUPPORTED_VER 5 + +END_C_DECLS +#endif /* ndef __WIN__ */ +#endif /* __IB_CM_TYPES_H__ */ diff --git a/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_attrib_req.h b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_attrib_req.h new file mode 100644 index 00000000..0389eee8 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_attrib_req.h @@ -0,0 +1,108 @@ +/* + * 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_ATTRIB_REQ_H_ +#define _OSM_ATTRIB_REQ_H_ + +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/* + * Abstract: + * Declaration of the attribute request object. This object + * encapsulates information needed by the generic request controller + * to request an attribute from a node. + * These objects are part of the OpenSM family of objects. + */ +/****h* OpenSM/Attribute Request +* NAME +* Attribute Request +* +* DESCRIPTION +* The Attribute Request structure encapsulates +* encapsulates information needed by the generic request controller +* to request an attribute from a node. +* +* This structure allows direct access to member variables. +* +* AUTHOR +* Steve King, Intel +* +*********/ +/****s* OpenSM: Attribute Request/osm_attrib_req_t +* NAME +* osm_attrib_req_t +* +* DESCRIPTION +* Attribute request structure. +* +* This structure allows direct access to member variables. +* +* SYNOPSIS +*/ +typedef struct osm_attrib_req { + uint16_t attrib_id; + uint32_t attrib_mod; + osm_madw_context_t context; + osm_dr_path_t path; + cl_disp_msgid_t err_msg; +} osm_attrib_req_t; +/* +* FIELDS +* attrib_id +* Attribute ID for this request. +* +* attrib_mod +* Attribute modifier for this request. +* +* context +* Context to insert in outbound mad wrapper context. +* +* path +* The directed route path to the node. +* +* SEE ALSO +*********/ + +END_C_DECLS +#endif /* _OSM_ATTRIB_REQ_H_ */ diff --git a/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_base.h b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_base.h new file mode 100644 index 00000000..89df2cf2 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_base.h @@ -0,0 +1,910 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2009 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Copyright (c) 2009 Sun Microsystems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Basic OpenSM definitions and structures. + * This object represents an OpenSM "base class". + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_BASE_H_ +#define _OSM_BASE_H_ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#ifdef __WIN__ +#include +#endif + +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* OpenSM/Constants +* NAME +* Constants +* +* DESCRIPTION +* The following constants are used throughout the OpenSM. +* +* AUTHOR +* Steve King, Intel +* +*********/ +/****h* OpenSM/Base +* NAME +* Base +* +* DESCRIPTION +* The Base object encapsulates basic information needed by the +* OpenSM to manage objects. Each OpenSM object includes the +* Base object as the first member. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Steve King, Intel +* +*********/ +/****s* OpenSM: Base/OSM_DEFAULT_M_KEY +* NAME +* OSM_DEFAULT_M_KEY +* +* DESCRIPTION +* Managment key value used by the OpenSM. +* +* SYNOPSIS +*/ +#define OSM_DEFAULT_M_KEY 0 +/********/ +/****s* OpenSM: Base/OSM_DEFAULT_SM_KEY +* NAME +* OSM_DEFAULT_SM_KEY +* +* DESCRIPTION +* Subnet Manager key value used by the OpenSM. +* +* SYNOPSIS +*/ +#define OSM_DEFAULT_SM_KEY CL_HTON64(1) +/********/ +/****s* OpenSM: Base/OSM_DEFAULT_SA_KEY +* NAME +* OSM_DEFAULT_SA_KEY +* +* DESCRIPTION +* Subnet Adminstration key value. +* +* SYNOPSIS +*/ +#define OSM_DEFAULT_SA_KEY OSM_DEFAULT_SM_KEY +/********/ +/****s* OpenSM: Base/OSM_DEFAULT_LMC +* NAME +* OSM_DEFAULT_LMC +* +* DESCRIPTION +* Default LMC value used by the OpenSM. +* +* SYNOPSIS +*/ +#define OSM_DEFAULT_LMC 0 +/********/ +/****s* OpenSM: Base/OSM_DEFAULT_MAX_OP_VLS +* NAME +* OSM_DEFAULT_MAX_OP_VLS +* +* DESCRIPTION +* Default Maximal Operational VLs to be initialized on +* the link ports PortInfo by the OpenSM. +* Default value provides backward compatibility. +* +* SYNOPSIS +*/ +#define OSM_DEFAULT_MAX_OP_VLS 5 +/********/ +/****s* OpenSM: Base/OSM_DEFAULT_SL +* NAME +* OSM_DEFAULT_SL +* +* DESCRIPTION +* Default SL value used by the OpenSM. +* +* SYNOPSIS +*/ +#define OSM_DEFAULT_SL 0 +/********/ +/****s* OpenSM: Base/OSM_DEFAULT_SM_PRIORITY +* NAME +* OSM_DEFAULT_SM_PRIORITY +* +* DESCRIPTION +* Default SM priority value used by the OpenSM, +* as defined in the SMInfo attribute. 0 is the lowest priority. +* +* SYNOPSIS +*/ +#define OSM_DEFAULT_SM_PRIORITY 0 +/********/ +/****d* OpenSM: Base/OSM_DEFAULT_TMP_DIR +* NAME +* OSM_DEFAULT_TMP_DIR +* +* DESCRIPTION +* Specifies the default temporary directory for the log file, +* osm-subnet.lst, and other log files. +* +* SYNOPSIS +*/ +#ifdef __WIN__ +#define OSM_DEFAULT_TMP_DIR "%TEMP%\\" +#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. +* +* SYNOPSIS +*/ +#ifdef __WIN__ +#define OSM_DEFAULT_CACHE_DIR OPENSM_CONFIG_DIR +#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 OSM_DEFAULT_TMP_DIR "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 +*/ +#if 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 +/***********/ + +/****d* OpenSM: Base/OSM_DEFAULT_PARTITION_CONFIG_FILE +* NAME +* OSM_DEFAULT_PARTITION_CONFIG_FILE +* +* DESCRIPTION +* Specifies the default partition config file name +* +* SYNOPSIS +*/ +#if 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 +/***********/ + +/****d* OpenSM: Base/OSM_DEFAULT_QOS_POLICY_FILE +* NAME +* OSM_DEFAULT_QOS_POLICY_FILE +* +* DESCRIPTION +* Specifies the default QoS policy file name +* +* SYNOPSIS +*/ +#if 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 +/***********/ + +/****d* OpenSM: Base/OSM_DEFAULT_PREFIX_ROUTES_FILE +* NAME +* OSM_DEFAULT_PREFIX_ROUTES_FILE +* +* DESCRIPTION +* Specifies the default prefix routes file name +* +* SYNOPSIS +*/ +#if 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 +*/ +#ifdef __WIN__ +#define OSM_DEFAULT_TRANS_TIMEOUT_MILLISEC 3000 +#else +#define OSM_DEFAULT_TRANS_TIMEOUT_MILLISEC 200 +#endif +/***********/ +/****d* OpenSM: Base/OSM_DEFAULT_SUBNET_TIMEOUT +* NAME +* OSM_DEFAULT_SUBNET_TIMEOUT +* +* DESCRIPTION +* Specifies the default subnet timeout. +* timeout time = 4us * 2^timeout. +* We use here ~1sec. +* +* SYNOPSIS +*/ +#define OSM_DEFAULT_SUBNET_TIMEOUT 0x12 +/***********/ +/****d* OpenSM: Base/OSM_DEFAULT_SWITCH_PACKET_LIFE +* NAME +* OSM_DEFAULT_SWITCH_PACKET_LIFE +* +* DESCRIPTION +* Specifies the default max life time for a pcket on the switch. +* timeout time = 4us * 2^timeout. +* We use here the value of ~1sec +* A Value > 19dec disables this mechanism. +* +* SYNOPSIS +*/ +#define OSM_DEFAULT_SWITCH_PACKET_LIFE 0x12 +/***********/ +/****d* OpenSM: Base/OSM_DEFAULT_HEAD_OF_QUEUE_LIFE +* NAME +* OSM_DEFAULT_HEAD_OF_QUEUE_LIFE +* +* DESCRIPTION +* Sets the time a packet can live in the head of the VL Queue +* We use here the value of ~1sec +* A Value > 19dec disables this mechanism. +* +* SYNOPSIS +*/ +#define OSM_DEFAULT_HEAD_OF_QUEUE_LIFE 0x12 +/***********/ +/****d* OpenSM: Base/OSM_DEFAULT_LEAF_HEAD_OF_QUEUE_LIFE +* NAME +* OSM_DEFAULT_LEAF_HEAD_OF_QUEUE_LIFE +* +* DESCRIPTION +* Sets the time a packet can live in the head of the VL Queue +* of a port that drives a CA port. +* We use here the value of ~256msec +* +* SYNOPSIS +*/ +#define OSM_DEFAULT_LEAF_HEAD_OF_QUEUE_LIFE 0x10 +/***********/ +/****d* OpenSM: Base/OSM_DEFAULT_VL_STALL_COUNT +* NAME +* OSM_DEFAULT_LEAF_VL_COUNT +* +* DESCRIPTION +* Sets the number of consecutive head of queue life time drops that +* puts the VL into stalled state. In stalled state, the port is supposed +* to drop everything for 8*(head of queue lifetime) +* +* SYNOPSIS +*/ +#define OSM_DEFAULT_VL_STALL_COUNT 0x7 +/***********/ +/****d* OpenSM: Base/OSM_DEFAULT_LEAF_VL_STALL_COUNT +* NAME +* OSM_DEFAULT_LEAF_VL_STALL_COUNT +* +* DESCRIPTION +* Sets the number of consecutive head of queue life time drops that +* puts the VL into stalled state. In stalled state, the port is supposed +* to drop everything for 8*(head of queue lifetime). This value is for +* switch ports driving a CA port. +* +* SYNOPSIS +*/ +#define OSM_DEFAULT_LEAF_VL_STALL_COUNT 0x7 +/***********/ +/****d* OpenSM: Base/OSM_DEFAULT_TRAP_SUPRESSION_TIMEOUT +* NAME +* OSM_DEFAULT_TRAP_SUPRESSION_TIMEOUT +* +* DESCRIPTION +* Specifies the default timeout for ignoring same trap. +* timeout time = 5000000us +* We use here ~5sec. +* +* SYNOPSIS +*/ +#define OSM_DEFAULT_TRAP_SUPRESSION_TIMEOUT 5000000 +/***********/ +/****d* OpenSM: Base/OSM_DEFAULT_UNHEALTHY_TIMEOUT +* NAME +* OSM_DEFAULT_UNHEALTHY_TIMEOUT +* +* DESCRIPTION +* Specifies the default timeout for setting port as unhealthy. +* timeout time = 60000000us +* We use here ~60sec. +* +* SYNOPSIS +*/ +#define OSM_DEFAULT_UNHEALTHY_TIMEOUT 60000000 +/***********/ +/****d* OpenSM: Base/OSM_DEFAULT_ERROR_THRESHOLD +* NAME +* OSM_DEFAULT_ERROR_THRESHOLD +* +* DESCRIPTION +* Specifies default link error threshold to be set by SubnSet(PortInfo). +* +* SYNOPSIS +*/ +#define OSM_DEFAULT_ERROR_THRESHOLD 0x08 +/***********/ +/****d* OpenSM: Base/OSM_DEFAULT_SMP_MAX_ON_WIRE +* NAME +* OSM_DEFAULT_SMP_MAX_ON_WIRE +* +* DESCRIPTION +* Specifies the default number of VL15 SMP MADs allowed on +* the wire at any one time. +* +* SYNOPSIS +*/ +#define OSM_DEFAULT_SMP_MAX_ON_WIRE 4 +/***********/ +/****d* OpenSM: Base/OSM_SM_DEFAULT_QP0_RCV_SIZE +* NAME +* OSM_SM_DEFAULT_QP0_RCV_SIZE +* +* DESCRIPTION +* Specifies the default size (in MADs) of the QP0 receive queue +* +* SYNOPSIS +*/ +#define OSM_SM_DEFAULT_QP0_RCV_SIZE 256 +/***********/ +/****d* OpenSM: Base/OSM_SM_DEFAULT_QP0_SEND_SIZE +* NAME +* OSM_SM_DEFAULT_QP0_SEND_SIZE +* +* DESCRIPTION +* Specifies the default size (in MADs) of the QP0 send queue +* +* SYNOPSIS +*/ +#define OSM_SM_DEFAULT_QP0_SEND_SIZE 256 +/***********/ +/****d* OpenSM: Base/OSM_SM_DEFAULT_QP1_RCV_SIZE +* NAME +* OSM_SM_DEFAULT_QP1_RCV_SIZE +* +* DESCRIPTION +* Specifies the default size (in MADs) of the QP1 receive queue +* +* SYNOPSIS +*/ +#define OSM_SM_DEFAULT_QP1_RCV_SIZE 256 +/***********/ +/****d* OpenSM: Base/OSM_SM_DEFAULT_QP1_SEND_SIZE +* NAME +* OSM_SM_DEFAULT_QP1_SEND_SIZE +* +* DESCRIPTION +* Specifies the default size (in MADs) of the QP1 send queue +* +* SYNOPSIS +*/ +#define OSM_SM_DEFAULT_QP1_SEND_SIZE 256 +/****d* OpenSM: Base/OSM_PM_DEFAULT_QP1_RCV_SIZE +* NAME +* OSM_PM_DEFAULT_QP1_RCV_SIZE +* +* DESCRIPTION +* Specifies the default size (in MADs) of the QP1 receive queue +* +* SYNOPSIS +*/ +#define OSM_PM_DEFAULT_QP1_RCV_SIZE 256 +/***********/ +/****d* OpenSM: Base/OSM_PM_DEFAULT_QP1_SEND_SIZE +* NAME +* OSM_PM_DEFAULT_QP1_SEND_SIZE +* +* DESCRIPTION +* Specifies the default size (in MADs) of the QP1 send queue +* +* SYNOPSIS +*/ +#define OSM_PM_DEFAULT_QP1_SEND_SIZE 256 +/****d* OpenSM: Base/OSM_SM_DEFAULT_POLLING_TIMEOUT_MILLISECS +* NAME +* OSM_SM_DEFAULT_POLLING_TIMEOUT_MILLISECS +* +* DESCRIPTION +* Specifies the polling timeout (in miliseconds) - the timeout +* between one poll to another. +* +* SYNOPSIS +*/ +#define OSM_SM_DEFAULT_POLLING_TIMEOUT_MILLISECS 10000 +/**********/ +/****d* OpenSM: Base/OSM_SM_DEFAULT_POLLING_RETRY_NUMBER +* NAME +* OSM_SM_DEFAULT_POLLING_RETRY_NUMBER +* +* DESCRIPTION +* Specifies the number of polling retries before the SM goes back +* to DISCOVERY stage. So the default total time for handoff is 40 sec. +* +* SYNOPSIS +*/ +#define OSM_SM_DEFAULT_POLLING_RETRY_NUMBER 4 +/**********/ +/****d* OpenSM: MC Member Record Receiver/OSM_DEFAULT_MGRP_MTU +* Name +* OSM_DEFAULT_MGRP_MTU +* +* DESCRIPTION +* Default MTU used for new MGRP creation (2048 bytes) +* Note it includes the MTUSelector which is set to "Greater Than" +* +* SYNOPSIS +*/ +#define OSM_DEFAULT_MGRP_MTU 0x04 +/***********/ +/****d* OpenSM: MC Member Record Receiver/OSM_DEFAULT_MGRP_RATE +* Name +* OSM_DEFAULT_MGRP_RATE +* +* DESCRIPTION +* Default RATE used for new MGRP creation (10Gb/sec) +* Note it includes the RateSelector which is set to "Greater Than" +* +* SYNOPSIS +*/ +#define OSM_DEFAULT_MGRP_RATE 0x03 +/***********/ +/****d* OpenSM: MC Member Record Receiver/OSM_DEFAULT_MGRP_SCOPE +* Name +* OSM_DEFAULT_MGRP_SCOPE +* +* DESCRIPTION +* Default SCOPE used for new MGRP creation (link local) +* +* SYNOPSIS +*/ +#define OSM_DEFAULT_MGRP_SCOPE IB_MC_SCOPE_LINK_LOCAL +/***********/ +/****d* OpenSM: Base/OSM_DEFAULT_QOS_MAX_VLS + * Name + * OSM_DEFAULT_QOS_MAX_VLS + * + * DESCRIPTION + * Default Maximum VLs used by the OpenSM. + * + * SYNOPSIS + */ +#define OSM_DEFAULT_QOS_MAX_VLS 15 +/***********/ +/****d* OpenSM: Base/OSM_DEFAULT_QOS_HIGH_LIMIT + * Name + * OSM_DEFAULT_QOS_HIGH_LIMIT + * + * DESCRIPTION + * Default Limit of High Priority in VL Arbitration used by OpenSM. + * + * SYNOPSIS + */ +#define OSM_DEFAULT_QOS_HIGH_LIMIT 0 +/***********/ +/****d* OpenSM: Base/OSM_DEFAULT_QOS_VLARB_HIGH + * Name + * OSM_DEFAULT_QOS_VLARB_HIGH + * + * DESCRIPTION + * Default High Priority VL Arbitration table used by the OpenSM. + * + * SYNOPSIS + */ +#define OSM_DEFAULT_QOS_VLARB_HIGH "0:4,1:0,2:0,3:0,4:0,5:0,6:0,7:0,8:0,9:0,10:0,11:0,12:0,13:0,14:0" +/***********/ +/****d* OpenSM: Base/OSM_DEFAULT_QOS_VLARB_LOW + * Name + * OSM_DEFAULT_QOS_VLARB_LOW + * + * DESCRIPTION + * Default Low Priority VL Arbitration table used by the OpenSM. + * + * SYNOPSIS + */ +#define OSM_DEFAULT_QOS_VLARB_LOW "0:0,1:4,2:4,3:4,4:4,5:4,6:4,7:4,8:4,9:4,10:4,11:4,12:4,13:4,14:4" +/***********/ +/****d* OpenSM: Base/OSM_DEFAULT_QOS_SL2VL + * Name + * OSM_DEFAULT_QOS_SL2VL + * + * DESCRIPTION + * Default QoS SL2VL Mapping Table used by the OpenSM. + * + * SYNOPSIS + */ +#define OSM_DEFAULT_QOS_SL2VL "0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,7" +/***********/ +/****d* OpenSM: Base/OSM_NO_PATH +* NAME +* OSM_NO_PATH +* +* DESCRIPTION +* Value indicating there is no path to the given LID. +* +* SYNOPSIS +*/ +#define OSM_NO_PATH 0xFF +/**********/ +/****d* OpenSM: Base/OSM_NODE_DESC_UNKNOWN +* NAME +* OSM_NODE_DESC_UNKNOWN +* +* DESCRIPTION +* Value indicating the Node Description is not set and is "unknown" +* +* SYNOPSIS +*/ +#define OSM_NODE_DESC_UNKNOWN "" +/**********/ +/****d* OpenSM: Base/osm_thread_state_t +* NAME +* osm_thread_state_t +* +* DESCRIPTION +* Enumerates the possible states of worker threads, such +* as the subnet sweeper. +* +* SYNOPSIS +*/ +typedef enum _osm_thread_state { + OSM_THREAD_STATE_NONE = 0, + OSM_THREAD_STATE_INIT, + OSM_THREAD_STATE_RUN, + OSM_THREAD_STATE_EXIT +} osm_thread_state_t; +/***********/ + +/* + * OSM_CAP are from IBA 1.2.1 Table 117 and Table 188 + */ + +/****d* OpenSM: Base/OSM_CAP_IS_TRAP_SUP +* Name +* OSM_CAP_IS_SUBN_TRAP_SUP +* +* DESCRIPTION +* Management class generates Trap() MADs +* +* SYNOPSIS +*/ +#define OSM_CAP_IS_SUBN_TRAP_SUP (1 << 0) +/***********/ + +/****d* OpenSM: Base/OSM_CAP_IS_GET_SET_NOTICE_SUP +* Name +* OSM_CAP_IS_GET_SET_NOTICE_SUP +* +* DESCRIPTION +* Management class supports Get/Set(Notice) +* +* SYNOPSIS +*/ +#define OSM_CAP_IS_SUBN_GET_SET_NOTICE_SUP (1 << 1) +/***********/ + +/****d* OpenSM: Base/OSM_CAP_IS_SUBN_OPT_RECS_SUP +* Name +* OSM_CAP_IS_SUBN_OPT_RECS_SUP +* +* DESCRIPTION +* Support all optional attributes except: +* MCMemberRecord, TraceRecord, MultiPathRecord +* +* SYNOPSIS +*/ +#define OSM_CAP_IS_SUBN_OPT_RECS_SUP (1 << 8) +/***********/ + +/****d* OpenSM: Base/OSM_CAP_IS_UD_MCAST_SUP +* Name +* OSM_CAP_IS_UD_MCAST_SUP +* +* DESCRIPTION +* Multicast is supported +* +* SYNOPSIS +*/ +#define OSM_CAP_IS_UD_MCAST_SUP (1 << 9) +/***********/ + +/****d* OpenSM: Base/OSM_CAP_IS_MULTIPATH_SUP +* Name +* OSM_CAP_IS_MULTIPATH_SUP +* +* DESCRIPTION +* MultiPathRecord and TraceRecord are supported +* +* SYNOPSIS +*/ +#define OSM_CAP_IS_MULTIPATH_SUP (1 << 10) +/***********/ + +/****d* OpenSM: Base/OSM_CAP_IS_REINIT_SUP +* Name +* OSM_CAP_IS_REINIT_SUP +* +* DESCRIPTION +* SM/SA supports re-initialization supported +* +* SYNOPSIS +*/ +#define OSM_CAP_IS_REINIT_SUP (1 << 11) +/***********/ + +/****d* OpenSM: Base/OSM_CAP_IS_PORT_INFO_CAPMASK_MATCH_SUPPORTED +* Name +* OSM_CAP_IS_PORT_INFO_CAPMASK_MATCH_SUPPORTED +* +* DESCRIPTION +* SM/SA supports enhanced SA PortInfoRecord searches per 1.2 Errata: +* ClassPortInfo:CapabilityMask.IsPortInfoCapMaskMatchSupported is 1, +* then the AttributeModifier of the SubnAdmGet() and SubnAdmGetTable() +* methods affects the matching behavior on the PortInfo:CapabilityMask +* component. If the high-order bit (bit 31) of the AttributeModifier +* is set to 1, matching on the CapabilityMask component will not be an +* exact bitwise match as described in . Instead, +* matching will only be performed on those bits which are set to 1 in +* the PortInfo:CapabilityMask embedded in the query. +* +* SYNOPSIS +*/ +#define OSM_CAP_IS_PORT_INFO_CAPMASK_MATCH_SUPPORTED (1 << 13) +/***********/ + +/****d* OpenSM: Base/OSM_CAP2_IS_QOS_SUPPORTED +* Name +* OSM_CAP2_IS_QOS_SUPPORTED +* +* DESCRIPTION +* QoS is supported +* +* SYNOPSIS +*/ +#define OSM_CAP2_IS_QOS_SUPPORTED (1 << 1) +/***********/ + +/****d* OpenSM: Base/OSM_CAP2_IS_REVERSE_PATH_PKEY_SUPPPORTED +* Name +* OSM_CAP2_IS_REVERSE_PATH_PKEY_SUPPPORTED +* +* DESCRIPTION +* Reverse path PKeys indicate in PathRecord responses +* +* SYNOPSIS +*/ +#define OSM_CAP2_IS_REVERSE_PATH_PKEY_SUPPPORTED (1 << 2) +/***********/ + +/****d* OpenSM: Base/OSM_CAP2_IS_MCAST_TOP_SUPPORTED +* Name +* OSM_CAP2_IS_MCAST_TOP_SUPPORTED +* +* DESCRIPTION +* SwitchInfo.MulticastFDBTop is supported +* +* SYNOPSIS +*/ +#define OSM_CAP2_IS_MCAST_TOP_SUPPORTED (1 << 3) +/***********/ + +/****d* OpenSM: Base/OSM_CAP2_IS_HIERARCHY_SUPPORTED +* Name +* +* DESCRIPTION +* Hierarchy info suppported +* +* SYNOPSIS +*/ +#define OSM_CAP2_IS_HIERARCHY_SUPPORTED (1 << 4) +/***********/ + +/****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 + +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; +/***********/ + +/****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_SUN2 0x002128 +#define OSM_VENDOR_ID_3LEAFNTWKS 0x0016A1 +#define OSM_VENDOR_ID_XSIGO 0x001397 +#define OSM_VENDOR_ID_HP2 0x0018FE +#define OSM_VENDOR_ID_DELL 0x00188B +#define OSM_VENDOR_ID_SUPERMICRO 0x003048 +#define OSM_VENDOR_ID_HP3 0x0019BB +#define OSM_VENDOR_ID_HP4 0x00237D + +/**********/ + +END_C_DECLS +#endif /* _OSM_BASE_H_ */ diff --git a/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_config.h b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_config.h new file mode 100644 index 00000000..2b940989 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_config.h @@ -0,0 +1,69 @@ +/* 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 OpenSM config directory */ +#define OPENSM_CONFIG_DIR "%ProgramFiles%\\OFED\\OpenSM" + +/* Define a default node name map file */ +#define HAVE_DEFAULT_NODENAME_MAP OPENSM_CONFIG_DIR "\\ib-node-name-map" + +/* Define a default OpenSM config file */ +#define HAVE_DEFAULT_OPENSM_CONFIG_FILE OPENSM_CONFIG_DIR "\\opensm.conf" + +/* Define a Partition config file */ +#define HAVE_DEFAULT_PARTITION_CONFIG_FILE OPENSM_CONFIG_DIR "\\partitions.conf" + +/* Define a Prefix Routes config file */ +#define HAVE_DEFAULT_PREFIX_ROUTES_FILE OPENSM_CONFIG_DIR "\\prefix-routes.conf" + +/* Define a QOS policy config file */ +#define HAVE_DEFAULT_QOS_POLICY_FILE OPENSM_CONFIG_DIR "\\qos-policy.conf" + +/* Define as 1 for vapi vendor */ +/* #undef OSM_VENDOR_INTF_MTL */ + +/* Define as 1 for OpenIB vendor */ +#ifdef OSM_VENDOR_INTF_AL +#undef OSM_VENDOR_INTF_OPENIB +#else +#define OSM_VENDOR_INTF_OPENIB 1 +#endif + +/* 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/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_config.h.in b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_config.h.in new file mode 100644 index 00000000..3164568e --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/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/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_console.h b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_console.h new file mode 100644 index 00000000..671c57d5 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_console.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2005-2007 Voltaire, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _OSM_CONSOLE_H_ +#define _OSM_CONSOLE_H_ + +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +int osm_console(osm_opensm_t * p_osm); +END_C_DECLS +#endif /* _OSM_CONSOLE_H_ */ diff --git a/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_console_io.h b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_console_io.h new file mode 100644 index 00000000..39a64df2 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_console_io.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2005-2007 Voltaire, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ +/* + * Abstract: + * Declaration of osm_console_t. + * This object represents the OpenSM Console object. + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_CONSOLE_IO_H_ +#define _OSM_CONSOLE_IO_H_ + +#include +#include + +#define OSM_DISABLE_CONSOLE "off" +#define OSM_LOCAL_CONSOLE "local" +#define OSM_REMOTE_CONSOLE "socket" +#define OSM_LOOPBACK_CONSOLE "loopback" +#define OSM_CONSOLE_NAME "OSM Console" + +#define OSM_DEFAULT_CONSOLE OSM_DISABLE_CONSOLE +#define OSM_DEFAULT_CONSOLE_PORT 10000 +#define OSM_DAEMON_NAME "opensm" + +#define OSM_COMMAND_PROMPT "$ " + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +typedef struct osm_console { + int socket; + int in_fd; + int out_fd; + int authorized; + FILE *in; + FILE *out; + char client_type[32]; + char client_ip[64]; + char client_hn[128]; +} osm_console_t; + +void osm_console_prompt(FILE * out); +int osm_console_init(osm_subn_opt_t * opt, osm_console_t * p_oct, osm_log_t * p_log); +void osm_console_exit(osm_console_t * p_oct, osm_log_t * p_log); +int is_console_enabled(osm_subn_opt_t *p_opt); + +#ifdef ENABLE_OSM_CONSOLE_SOCKET +int cio_open(osm_console_t * p_oct, int new_fd, osm_log_t * p_log); +int cio_close(osm_console_t * p_oct, osm_log_t * p_log); +int is_authorized(osm_console_t * p_oct); +#else +#define cio_close(c, log) +#endif + +END_C_DECLS +#endif /* _OSM_CONSOLE_IO_H_ */ diff --git a/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_db.h b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_db.h new file mode 100644 index 00000000..fd2d3c85 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_db.h @@ -0,0 +1,424 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _OSM_DB_H_ +#define _OSM_DB_H_ + +/* + * Abstract: + * Declaration of the DB interface. + */ + +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* OpenSM/Database +* NAME +* Database +* +* DESCRIPTION +* The OpenSM database interface provide the means to restore persistent +* data, query, modify, delete and eventually commit it back to the +* persistent media. +* +* The interface is defined such that it can is not "data dependent": +* All keys and data items are texts. +* +* The DB implementation should be thread safe, thus callers do not need to +* provide serialization. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Eitan Zahavi, Mellanox Technologies LTD +* +*********/ +/****s* OpenSM: Database/osm_db_domain_t +* NAME +* osm_db_domain_t +* +* DESCRIPTION +* A domain of the database. Can be viewed as a database table. +* +* The osm_db_domain_t object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct osm_db_domain { + struct osm_db *p_db; + void *p_domain_imp; +} osm_db_domain_t; +/* +* FIELDS +* p_db +* Pointer to the parent database object. +* +* p_domain_imp +* Pointer to the db implementation object +* +* SEE ALSO +* osm_db_t +*********/ + +/****s* OpenSM: Database/osm_db_t +* NAME +* osm_db_t +* +* DESCRIPTION +* The main database object. +* +* The osm_db_t object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct osm_db { + void *p_db_imp; + osm_log_t *p_log; + cl_list_t domains; +} osm_db_t; +/* +* FIELDS +* p_db_imp +* Pointer to the database implementation object +* +* p_log +* Pointer to the OSM logging facility +* +* domains +* List of initialize domains +* +* SEE ALSO +*********/ + +/****f* OpenSM: Database/osm_db_construct +* NAME +* osm_db_construct +* +* DESCRIPTION +* Construct a database. +* +* SYNOPSIS +*/ +void osm_db_construct(IN osm_db_t * 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 * 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 * 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 * 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 *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 *p_key, IN char *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 *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/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_db_pack.h b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_db_pack.h new file mode 100644 index 00000000..039cbd8d --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_db_pack.h @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/****h* OpenSM/DB-Pack +* NAME +* Database Types +* +* DESCRIPTION +* This module provides packing and unpacking of the database +* storage into specific types. +* +* The following domains/conversions are supported: +* guid2lid - key is a guid and data is a lid. +* +* AUTHOR +* Eitan Zahavi, Mellanox Technologies LTD +* +*********/ + +#ifndef _OSM_DB_PACK_H_ +#define _OSM_DB_PACK_H_ + +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****f* OpenSM: DB-Pack/osm_db_guid2lid_init +* NAME +* osm_db_guid2lid_init +* +* DESCRIPTION +* Initialize a domain for the guid2lid table +* +* SYNOPSIS +*/ +static inline osm_db_domain_t *osm_db_guid2lid_init(IN osm_db_t * 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 * 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 * 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 * 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 * 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/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_errors.h b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_errors.h new file mode 100644 index 00000000..667e0b48 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/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/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_event_plugin.h b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_event_plugin.h new file mode 100644 index 00000000..1ba26593 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_event_plugin.h @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2007 The Regents of the University of California. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _OSM_EVENT_PLUGIN_H_ +#define _OSM_EVENT_PLUGIN_H_ + +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* OpenSM Event plugin interface +* DESCRIPTION +* Database interface to record subnet events +* +* Implementations of this object _MUST_ be thread safe. +* +* AUTHOR +* Ira Weiny, LLNL +* +*********/ + +#define OSM_EPI_NODE_NAME_LEN (65) + +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; + +/** ========================================================================= + * 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/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_helper.h b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_helper.h new file mode 100644 index 00000000..1c2fae63 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_helper.h @@ -0,0 +1,549 @@ +/* + * Copyright (c) 2004-2009 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) 2009 HNR Consulting. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _OSM_HELPER_H_ +#define _OSM_HELPER_H_ + +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/* + * Abstract: + * Declaration of helpful functions. + */ +/****f* OpenSM: Helper/ib_get_sa_method_str + * NAME + * ib_get_sa_method_str + * + * DESCRIPTION + * Returns a string for the specified SA Method value. + * + * SYNOPSIS + */ +const char *ib_get_sa_method_str(IN uint8_t method); +/* + * PARAMETERS + * method + * [in] Network order METHOD ID value. + * + * RETURN VALUES + * Pointer to the method string. + * + * NOTES + * + * SEE ALSO + *********/ + +/****f* OpenSM: Helper/ib_get_sm_method_str +* NAME +* ib_get_sm_method_str +* +* DESCRIPTION +* Returns a string for the specified SM Method value. +* +* SYNOPSIS +*/ +const char *ib_get_sm_method_str(IN uint8_t method); +/* +* PARAMETERS +* method +* [in] Network order METHOD ID value. +* +* RETURN VALUES +* Pointer to the method string. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Helper/ib_get_sm_attr_str +* NAME +* ib_get_sm_attr_str +* +* DESCRIPTION +* Returns a string for the specified SM attribute value. +* +* SYNOPSIS +*/ +const char *ib_get_sm_attr_str(IN ib_net16_t attr); +/* +* PARAMETERS +* attr +* [in] Network order attribute ID value. +* +* RETURN VALUES +* Pointer to the attribute string. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Helper/ib_get_sa_attr_str +* NAME +* ib_get_sa_attr_str +* +* DESCRIPTION +* Returns a string for the specified SA attribute value. +* +* SYNOPSIS +*/ +const char *ib_get_sa_attr_str(IN ib_net16_t attr); +/* +* PARAMETERS +* attr +* [in] Network order attribute ID value. +* +* RETURN VALUES +* Pointer to the attribute string. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Helper/ib_get_trap_str +* NAME +* ib_get_trap_str +* +* DESCRIPTION +* Returns a name for the specified trap. +* +* SYNOPSIS +*/ +const char *ib_get_trap_str(uint16_t trap_num); +/* +* PARAMETERS +* trap_num +* [in] Network order trap number. +* +* RETURN VALUES +* Name of the trap. +* +*********/ + +extern const ib_gid_t ib_zero_gid; + +/****f* IBA Base: Types/ib_gid_is_notzero +* NAME +* ib_gid_is_notzero +* +* DESCRIPTION +* Returns a boolean indicating whether or not the GID is zero. +* +* SYNOPSIS +*/ +static inline boolean_t ib_gid_is_notzero(IN const ib_gid_t * p_gid) +{ + return memcmp(p_gid, &ib_zero_gid, sizeof(*p_gid)); +} + +/* +* PARAMETERS +* p_gid +* [in] Pointer to the GID object. +* +* RETURN VALUES +* Returns TRUE if GID is not zero. +* FALSE otherwise. +* +* NOTES +* +* SEE ALSO +* ib_gid_t +*********/ + +/****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 * p_log, IN ib_net64_t node_guid, + IN ib_net64_t port_guid, IN uint8_t port_num, + IN const ib_port_info_t * p_pi, + IN 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 * p_log, IN const ib_path_rec_t * p_pr, + IN osm_log_level_t log_level); + +void osm_dump_multipath_record(IN osm_log_t * p_log, + IN const ib_multipath_rec_t * p_mpr, + IN osm_log_level_t log_level); + +void osm_dump_node_record(IN osm_log_t * p_log, + IN const ib_node_record_t * p_nr, + IN osm_log_level_t log_level); + +void osm_dump_mc_record(IN osm_log_t * p_log, IN const ib_member_rec_t * p_mcmr, + IN osm_log_level_t log_level); + +void osm_dump_link_record(IN osm_log_t * p_log, + IN const ib_link_record_t * p_lr, + IN osm_log_level_t log_level); + +void osm_dump_service_record(IN osm_log_t * p_log, + IN const ib_service_record_t * p_sr, + IN osm_log_level_t log_level); + +void osm_dump_portinfo_record(IN osm_log_t * p_log, + IN const ib_portinfo_record_t * p_pir, + IN osm_log_level_t log_level); + +void osm_dump_guidinfo_record(IN osm_log_t * p_log, + IN const ib_guidinfo_record_t * p_gir, + IN osm_log_level_t log_level); + +void osm_dump_inform_info(IN osm_log_t * p_log, + IN const ib_inform_info_t * p_ii, + IN osm_log_level_t log_level); + +void osm_dump_inform_info_record(IN osm_log_t * p_log, + IN const ib_inform_info_record_t * p_iir, + IN osm_log_level_t log_level); + +void osm_dump_switch_info_record(IN osm_log_t * p_log, + IN const ib_switch_info_record_t * p_sir, + IN osm_log_level_t log_level); + +void osm_dump_sm_info_record(IN osm_log_t * p_log, + IN const ib_sminfo_record_t * p_smir, + IN osm_log_level_t log_level); + +void osm_dump_pkey_block(IN osm_log_t * p_log, IN uint64_t port_guid, + IN uint16_t block_num, IN uint8_t port_num, + IN const ib_pkey_table_t * p_pkey_tbl, + IN osm_log_level_t log_level); + +void osm_dump_slvl_map_table(IN osm_log_t * 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 * p_slvl_tbl, + IN osm_log_level_t log_level); + +void osm_dump_vl_arb_table(IN osm_log_t * p_log, IN uint64_t port_guid, + IN uint8_t block_num, IN uint8_t port_num, + IN const ib_vl_arb_table_t * p_vla_tbl, + IN 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 * p_log, + IN const ib_node_info_t * p_ni, + IN 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 * p_log, IN const ib_sm_info_t * p_smi, + IN 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 * p_log, + IN const ib_switch_info_t * p_si, + IN 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 * p_log, + IN const ib_mad_notice_attr_t * p_ntci, + IN 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 description string. +* +* NOTES +* +* SEE ALSO +*********/ + +void osm_dump_dr_path(IN osm_log_t * p_log, IN const osm_dr_path_t * p_path, + IN osm_log_level_t level); + +void osm_dump_smp_dr_path(IN osm_log_t * p_log, IN const ib_smp_t * p_smp, + IN osm_log_level_t level); + +void osm_dump_dr_smp(IN osm_log_t * p_log, IN const ib_smp_t * p_smp, + IN osm_log_level_t level); + +void osm_dump_sa_mad(IN osm_log_t * p_log, IN const ib_sa_mad_t * p_smp, + IN 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 description 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 guid_ho); + +const char *osm_get_mtu_str(IN uint8_t mtu); + +const char *osm_get_lwa_str(IN uint8_t lwa); + +const char *osm_get_mtu_str(IN uint8_t mtu); + +const char *osm_get_lwa_str(IN uint8_t lwa); + +const char *osm_get_lsa_str(IN uint8_t 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 description 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 description string. +* +* NOTES +* +* SEE ALSO +*********/ + +END_C_DECLS +#endif /* _OSM_HELPER_H_ */ diff --git a/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_inform.h b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_inform.h new file mode 100644 index 00000000..293ee5ca --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_inform.h @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osm_inform_rec_t. + * This object represents an IBA Inform Record. + * This object is part of the OpenSM family of objects. + * + * Author: + * Eitan Zahavi, Mellanox + */ + +#ifndef _OSM_INFR_H_ +#define _OSM_INFR_H_ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* OpenSM/Inform Record +* NAME +* Inform Record +* +* DESCRIPTION +* The Inform record encapsulates the information needed by the +* SA to manage InformInfo registrations and sending Reports(Notice) +* when SM receives Traps for registered LIDs. +* +* The inform records is not thread safe, thus callers must provide +* serialization. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Eitan Zahavi, Mellanox +* +*********/ +/****s* OpenSM: Inform Record/osm_infr_t +* NAME +* osm_infr_t +* +* DESCRIPTION +* Inform Record structure. +* +* The osm_infr_t object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct osm_infr { + cl_list_item_t list_item; + osm_bind_handle_t h_bind; + osm_sa_t *sa; + osm_mad_addr_t report_addr; + ib_inform_info_record_t inform_record; +} osm_infr_t; +/* +* FIELDS +* list_item +* List Item for qlist linkage. Must be first element!! +* +* h_bind +* A handle of lower level mad srvc +* +* sa +* A pointer to osm_sa object +* +* report_addr +* Report address +* +* inform_record +* The Inform Info Record +* +* SEE ALSO +*********/ + +/****f* OpenSM: Inform Record/osm_infr_new +* NAME +* osm_infr_new +* +* DESCRIPTION +* Allocates and initializes a Inform Record for use. +* +* SYNOPSIS +*/ +osm_infr_t *osm_infr_new(IN const osm_infr_t * p_infr_rec); +/* +* PARAMETERS +* p_inf_rec +* [in] Pointer to IB Inform Record +* +* RETURN VALUES +* pointer to osm_infr_t structure. +* +* NOTES +* Allows calling other inform record methods. +* +* SEE ALSO +* Inform Record, osm_infr_delete +*********/ + +/****f* OpenSM: Inform Record/osm_infr_delete +* NAME +* osm_infr_delete +* +* DESCRIPTION +* Destroys and deallocates the osm_infr_t structure. +* +* SYNOPSIS +*/ +void osm_infr_delete(IN osm_infr_t * 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 * 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 * 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/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_lid_mgr.h b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_lid_mgr.h new file mode 100644 index 00000000..5d1a608b --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_lid_mgr.h @@ -0,0 +1,279 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osm_lid_mgr_t. + * This object represents the LID Manager object. + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_LID_MGR_H_ +#define _OSM_LID_MGR_H_ + +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +#define OSM_LID_MGR_LIST_SIZE_MIN 256 +/****h* OpenSM/LID Manager +* NAME +* LID Manager +* +* DESCRIPTION +* The LID Manager object encapsulates the information +* needed to control LID assignments on the subnet. +* +* The LID Manager object is thread safe. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Steve King, Intel +* +*********/ +struct osm_sm; +/****s* OpenSM: LID Manager/osm_lid_mgr_t +* NAME +* osm_lid_mgr_t +* +* DESCRIPTION +* LID Manager structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct osm_lid_mgr { + struct osm_sm *sm; + osm_subn_t *p_subn; + osm_db_t *p_db; + osm_log_t *p_log; + cl_plock_t *p_lock; + osm_db_domain_t *p_g2l; + cl_qlist_t free_ranges; + uint8_t used_lids[IB_LID_UCAST_END_HO + 1]; +} 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. +* +* p_g2l +* Pointer to the database domain storing guid to lid mapping. +* +* used_lids +* An array of used lids. 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 * 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 * 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 * 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 +*/ +int osm_lid_mgr_process_sm(IN osm_lid_mgr_t * p_mgr); +/* +* PARAMETERS +* p_mgr +* [in] Pointer to an osm_lid_mgr_t object. +* +* RETURN VALUES +* Returns 0 on success and non-zero value otherwise. +* +* 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 +*/ +int osm_lid_mgr_process_subnet(IN osm_lid_mgr_t * p_mgr); +/* +* PARAMETERS +* p_mgr +* [in] Pointer to an osm_lid_mgr_t object. +* +* RETURN VALUES +* Returns 0 on success and non-zero value otherwise. +* +* NOTES +* +* SEE ALSO +* LID Manager +*********/ + +END_C_DECLS +#endif /* _OSM_LID_MGR_H_ */ diff --git a/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_log.h b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_log.h new file mode 100644 index 00000000..d1a3443e --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_log.h @@ -0,0 +1,478 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2006 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osm_log_t. + * This object represents the log file. + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_LOG_H_ +#define _OSM_LOG_H_ + +#ifndef __WIN__ +#include +#endif +#include +#include +#include +#include + +#ifdef __GNUC__ +#define STRICT_OSM_LOG_FORMAT __attribute__((format(printf, 3, 4))) +#else +#define STRICT_OSM_LOG_FORMAT +#endif + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +#ifdef __WIN__ +#define LOG_ENTRY_SIZE_MAX 2048 +#else +#define LOG_ENTRY_SIZE_MAX 4096 +#endif +#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; + char *log_prefix; +} 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 * 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 * 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 * p_log, IN boolean_t flush, + IN uint8_t log_flags, IN const char *log_file, + IN unsigned long max_size, + IN 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 * p_log, IN boolean_t flush, + IN uint8_t log_flags, IN const char *log_file, + IN boolean_t accum_log_file); +/* + * Same as osm_log_init_v2() but without max_size parameter + */ + +void osm_log(IN osm_log_t * p_log, IN 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 * 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 * p_log, + IN 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 * p_log, + IN 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 * p_log, IN osm_log_level_t verbosity, + IN const char *p_buf); + +#define OSM_LOG(log, level, fmt, ...) do { \ + if (osm_log_is_active(log, (level))) \ + osm_log(log, level, "%s: " fmt, __func__, ## __VA_ARGS__); \ + } 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/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_mad_pool.h b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_mad_pool.h new file mode 100644 index 00000000..c7665a6d --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_mad_pool.h @@ -0,0 +1,370 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osm_mad_pool_t. + * This object represents a pool of management datagram (MAD) objects. + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_MAD_POOL_H_ +#define _OSM_MAD_POOL_H_ + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* OpenSM/MAD Pool +* NAME +* MAD Pool +* +* DESCRIPTION +* The MAD Pool encapsulates the information needed by the +* OpenSM to manage a pool of MAD objects. The OpenSM allocates +* one MAD Pool per IBA subnet. +* +* The MAD Pool is thread safe. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Steve King, Intel +* +*********/ +/****s* OpenSM: MAD Pool/osm_mad_pool_t +* NAME +* osm_mad_pool_t +* +* DESCRIPTION +* MAD Pool structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct osm_mad_pool { + atomic32_t mads_out; +} osm_mad_pool_t; +/* +* FIELDS +* mads_out +* Running total of the number of MADs outstanding. +* +* SEE ALSO +* MAD Pool +*********/ + +/****f* OpenSM: MAD Pool/osm_mad_pool_construct +* NAME +* osm_mad_pool_construct +* +* DESCRIPTION +* This function constructs a MAD Pool. +* +* SYNOPSIS +*/ +void osm_mad_pool_construct(IN osm_mad_pool_t * 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 * 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 * 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 * p_pool, + IN osm_bind_handle_t h_bind, + IN uint32_t total_size, + IN const osm_mad_addr_t * 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 * p_pool, IN osm_madw_t * 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 * p_pool, + IN osm_bind_handle_t h_bind, + IN uint32_t total_size, + IN const ib_mad_t * p_mad, + IN const osm_mad_addr_t * 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 * 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 * 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/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_madw.h b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_madw.h new file mode 100644 index 00000000..81d30e17 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_madw.h @@ -0,0 +1,1120 @@ +/* + * Copyright (c) 2004-2009 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) 2009 HNR Consulting. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osm_mad_wrapper_t. + * This object represents the context wrapper for OpenSM MAD processing. + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_MADW_H_ +#define _OSM_MADW_H_ + +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****s* OpenSM: MAD Wrapper/osm_bind_info_t +* NAME +* osm_bind_info_t +* +* DESCRIPTION +* +* SYNOPSIS +*/ +typedef struct osm_bind_info { + ib_net64_t port_guid; + uint8_t mad_class; + uint8_t class_version; + boolean_t is_responder; + boolean_t is_trap_processor; + boolean_t is_report_processor; + uint32_t send_q_size; + uint32_t recv_q_size; + uint32_t timeout; + uint32_t retries; +} 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 +* +* timeout +* Transaction timeout +* +* retries +* Number of retries for transaction +* +* 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 * p_madw, + IN osm_bind_handle_t h_bind, + IN uint32_t mad_size, + IN const osm_mad_addr_t * 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 * 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 * 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 + * 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 + * 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 + * 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 + * 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 * + 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 * + 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 + * 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 * + 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 * + 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 * + 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 * + 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 * + 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 * 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 * + 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 * 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 * 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 * p_madw, + IN const ib_mad_t * 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 * p_dest, + IN const osm_madw_t * 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/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_mcast_tbl.h b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_mcast_tbl.h new file mode 100644 index 00000000..9f65f139 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_mcast_tbl.h @@ -0,0 +1,486 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2009 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Copyright (c) 2009 HNR Consulting. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osm_mcast_tbl_t. + * This object represents a multicast forwarding table. + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_MCAST_TBL_H_ +#define _OSM_MCAST_TBL_H_ + +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****s* OpenSM: Forwarding Table/osm_mcast_tbl_t +* NAME +* osm_mcast_tbl_t +* +* DESCRIPTION +* Multicast Forwarding Table structure. +* +* Callers may directly access this object. +* +* SYNOPSIS +*/ +typedef struct osm_mcast_fwdbl { + uint8_t num_ports; + uint8_t max_position; + uint16_t max_block; + int16_t max_block_in_use; + uint16_t num_entries; + uint16_t max_mlid_ho; + uint16_t mft_depth; + uint16_t(*p_mask_tbl)[][IB_MCAST_POSITION_MAX + 1]; +} 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 (host order) for the currently allocated multicast +* port mask table. +* +* mft_depth +* Number of MLIDs in the currently allocated multicast port mask +* table. +* +* p_mask_tbl +* Pointer to a two dimensional array of port_masks for this switch. +* The first dimension is MLID offset, 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 +*/ +void osm_mcast_tbl_init(IN osm_mcast_tbl_t * p_tbl, IN uint8_t num_ports, + IN uint16_t 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 +* None. +* +* 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 ** 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_realloc +* NAME +* osm_mcast_tbl_realloc +* +* DESCRIPTION +* This function reallocates the multicast port mask table if necessary. +* +* SYNOPSIS +*/ +int osm_mcast_tbl_realloc(IN osm_mcast_tbl_t * p_tbl, IN unsigned mlid_offset); +/* +* PARAMETERS +* +* p_tbl +* [in] Pointer to the Multicast Forwarding Table object. +* +* mlid_offset +* [in] Offset of MLID being accessed. +* +* RETURN VALUE +* Returns 0 on success and non-zero value 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 * 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 * p_tbl, IN uint16_t mlid_ho, + IN 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 * p_tbl, IN 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 * p_tbl, + IN uint16_t mlid_ho, IN 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 * p_tbl, + IN 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 * p_tbl, + IN const ib_net16_t * p_block, + IN int16_t block_num, + IN 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 * p_tbl, + IN int16_t block_num, IN uint8_t position, + OUT ib_net16_t * 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 * 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 * 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 * 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/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_mcm_port.h b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_mcm_port.h new file mode 100644 index 00000000..ee0ff99d --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_mcm_port.h @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osm_mcm_port_t. + * This object represents the membership of a port in a multicast group. + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_MCM_PORT_H_ +#define _OSM_MCM_PORT_H_ + +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS + +struct osm_mgrp; + +/****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; + cl_list_item_t list_item; + osm_port_t *port; + struct osm_mgrp *mgrp; + 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 +* Reference to the parent port. +* +* mgrp +* The pointer to multicast group where this port is member of +* +* 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 osm_port_t * port, IN struct osm_mgrp *mgrp, + IN ib_member_rec_t *mcmr, IN boolean_t proxy); +/* +* PARAMETERS +* port +* [in] Pointer to the port object. +* +* mgrp +* [in] Pointer to multicast group where this port is joined. +* +* mcmr +* [in] Pointer to MCMember record of the join request +* +* proxy +* [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 * 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/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_mesh.h b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_mesh.h new file mode 100644 index 00000000..4be391fd --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_mesh.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2008,2009 System Fabric Works, 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: + * Declarations for mesh analysis + */ + +#ifndef OSM_MESH_H +#define OSM_MESH_H + +struct _lash; +struct _switch; + +/* + * per switch to switch link info + */ +typedef struct _link { + int switch_id; + int link_id; + int next_port; + int num_ports; + int ports[0]; +} link_t; + +/* + * per switch node mesh info + */ +typedef struct _mesh_node { + int *axes; /* used to hold and reorder assigned axes */ + int *coord; /* mesh coordinates of switch */ + int **matrix; /* distances between adjacant switches */ + int *poly; /* characteristic polynomial of matrix */ + /* used as an invariant classification */ + int dimension; /* apparent dimension of mesh around node */ + int temp; /* temporary holder for distance info */ + int type; /* index of node type in mesh_info array */ + unsigned int num_links; /* number of 'links' to adjacent switches */ + link_t *links[0]; /* per link information */ +} mesh_node_t; + +void osm_mesh_node_delete(struct _lash *p_lash, struct _switch *sw); +int osm_mesh_node_create(struct _lash *p_lash, struct _switch *sw); +int osm_do_mesh_analysis(struct _lash *p_lash); + +#endif diff --git a/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_msgdef.h b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_msgdef.h new file mode 100644 index 00000000..6d4c34f6 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/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/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_mtree.h b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_mtree.h new file mode 100644 index 00000000..43db7f83 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_mtree.h @@ -0,0 +1,274 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osm_mtree_t. + * This object represents multicast spanning tree. + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_MTREE_H_ +#define _OSM_MTREE_H_ + +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +#define OSM_MTREE_LEAF ((void*)-1) +/****h* OpenSM/Multicast Tree +* NAME +* Multicast Tree +* +* DESCRIPTION +* The Multicast Tree object encapsulates the information needed by the +* OpenSM to manage multicast fabric routes. It is a tree structure +* in which each node in the tree represents a switch, and may have a +* varying number of children. +* +* Multicast trees do not contain loops. +* +* The Multicast Tree is not thread safe, thus callers must provide +* serialization. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Steve King, Intel +* +*********/ +/****s* OpenSM: Multicast Tree/osm_mtree_node_t +* NAME +* osm_mtree_node_t +* +* DESCRIPTION +* The MTree Node object encapsulates the information needed by the +* OpenSM for a particular switch in the multicast tree. +* +* The MTree Node object is not thread safe, thus callers must provide +* serialization. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct osm_mtree_node { + cl_map_item_t map_item; + const 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 * 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 * 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 * + p_mtn, + IN 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 const osm_switch_t *osm_mtree_node_get_switch_ptr(IN const + osm_mtree_node_t * + 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/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_multicast.h b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_multicast.h new file mode 100644 index 00000000..c869342b --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_multicast.h @@ -0,0 +1,389 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osm_mgrp_t. + * This object represents an IBA Multicast Group. + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_MULTICAST_H_ +#define _OSM_MULTICAST_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* OpenSM/Multicast Group +* NAME +* Multicast Group +* +* DESCRIPTION +* The Multicast Group encapsulates the information needed by the +* OpenSM to manage Multicast Groups. The OpenSM allocates one +* Multicast Group object per Multicast Group in the IBA subnet. +* +* The Multicast Group is not thread safe, thus callers must provide +* serialization. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Steve King, Intel +* +*********/ + +/****s* OpenSM: Multicast Group/osm_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_fmap_item_t map_item; + cl_list_item_t list_item; + ib_net16_t mlid; + cl_qmap_t mcm_port_tbl; + ib_member_rec_t mcmember_rec; + boolean_t well_known; + unsigned full_members; +} osm_mgrp_t; +/* +* FIELDS +* map_item +* Map Item for fmap linkage. Must be first element!! +* +* list_item +* List item for linkage in osm_mgrp_box's mgrp_list qlist. +* +* mlid +* The network ordered LID of this Multicast Group (must be +* >= 0xC000). +* +* 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 +* +* SEE ALSO +*********/ + +/****s* OpenSM: Multicast Group/osm_mgrp_box_t +* NAME +* osm_mgrp_box_t +* +* DESCRIPTION +* Multicast structure which holds all multicast groups with same MLID. +* +* SYNOPSIS +*/ +typedef struct osm_mgrp_box { + uint16_t mlid; + cl_qlist_t mgrp_list; + osm_mtree_node_t *root; +} osm_mgrp_box_t; +/* +* FIELDS +* mlid +* The host 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. +* +* mgrp_list +* List of multicast groups (mpgr object) having same MLID value. +* +* 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 osm_subn_t * subn, IN ib_net16_t mlid, + IN ib_member_rec_t * mcmr); +/* +* PARAMETERS +* subn +* [in] Pointer to osm_subn_t object. +* mlid +* [in] Multicast LID for this multicast group. +* +* mcmr +* [in] MCMember Record 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_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 * p_mgrp, + IN 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 * 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 * 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 * mgrp, IN osm_port_t *port, + IN ib_member_rec_t *mcmr, IN boolean_t proxy); +/* +* PARAMETERS +* mgrp +* [in] Pointer to an osm_mgrp_t object to initialize. +* +* port +* [in] Pointer to an osm_port_t object +* +* mcmr +* [in] Pointer to MCMember record received for the join +* +* proxy +* [in] The proxy join state for this port in the group. +* +* RETURN VALUES +* IB_SUCCESS +* IB_INSUFFICIENT_MEMORY +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Multicast Group/osm_mgrp_get_mcm_port +* NAME +* osm_mgrp_get_mcm_port +* +* DESCRIPTION +* finds a port in the multicast group. +* +* SYNOPSIS +*/ +osm_mcm_port_t *osm_mgrp_get_mcm_port(IN const osm_mgrp_t * p_mgrp, + IN ib_net64_t port_guid); +/* +* PARAMETERS +* p_mgrp +* [in] Pointer to an osm_mgrp_t object. +* +* port_guid +* [in] Port guid of the departing port. +* +* RETURN VALUES +* Pointer to the mcm port object when present or NULL otherwise. +* +* 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 * subn, IN osm_log_t * log, + IN osm_mgrp_t * mgrp, IN ib_net64_t port_guid); +/* +* PARAMETERS +* +* subn +* [in] Pointer to the subnet object +* +* log +* [in] The log object pointer +* +* mgrp +* [in] Pointer to an osm_mgrp_t object. +* +* port_guid +* [in] Port guid of the departing port. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +void osm_mgrp_remove_port(osm_subn_t * subn, osm_log_t * log, osm_mgrp_t * mgrp, + osm_mcm_port_t * mcm_port, ib_member_rec_t * mcmr); +void osm_mgrp_cleanup(osm_subn_t * subn, osm_mgrp_t * mpgr); +void osm_mgrp_box_delete(osm_mgrp_box_t *mbox); + +END_C_DECLS +#endif /* _OSM_MULTICAST_H_ */ diff --git a/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_node.h b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_node.h new file mode 100644 index 00000000..797fe37e --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_node.h @@ -0,0 +1,668 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osm_node_t. + * This object represents an IBA node. + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_NODE_H_ +#define _OSM_NODE_H_ + +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS + +struct osm_switch; + +/****h* OpenSM/Node +* NAME +* Node +* +* DESCRIPTION +* The Node object encapsulates the information needed by the +* OpenSM to manage nodes. The OpenSM allocates one Node object +* per node in the IBA subnet. +* +* The Node object is not thread safe, thus callers must provide +* serialization. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Steve King, Intel +* +*********/ + +/****s* OpenSM: Node/osm_node_t +* NAME +* osm_node_t +* +* DESCRIPTION +* Node structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct osm_node { + cl_map_item_t map_item; + struct osm_switch *sw; + ib_node_info_t node_info; + ib_node_desc_t node_desc; + uint32_t discovery_count; + uint32_t physp_tbl_size; + char *print_desc; + osm_physp_t physp_table[1]; +} osm_node_t; +/* +* FIELDS +* map_item +* Linkage structure for cl_qmap. MUST BE FIRST MEMBER! +* +* sw +* For switch node contains pointer to appropriate osm_switch +* structure. NULL for non-switch nodes. Can be used for fast +* access to switch object and for simple node type detection +* +* node_info +* The IBA defined NodeInfo data for this node. +* +* node_desc +* The IBA defined NodeDescription data for this node. +* +* discovery_count +* The number of times this node has been discovered +* during the current fabric sweep. This number is reset +* to zero at the start of a sweep. +* +* phsyp_tbl_size +* The size of the physp_table array. This value is one greater +* than the number of ports in the node, since port numbers +* start with 1 for some bizzare reason. +* +* print_desc +* A printable version of the node description. +* +* phsyp_table +* Array of physical port objects belonging to this node. +* Index is contiguous by local port number. +* For switches, port 0 is the always the management port (14.2.5.6). +* MUST BE LAST MEMBER! - Since it grows !!!! +* +* SEE ALSO +* Node object +*********/ + +/****f* OpenSM: Node/osm_node_delete +* NAME +* osm_node_delete +* +* DESCRIPTION +* The osm_node_delete function destroys a node, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_node_delete(IN OUT osm_node_t ** 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 * 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 * p_node, + IN 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 * 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 number of osm_physp ports allocated for this node. +* For switches, it is the number of external physical ports plus +* port 0. For CAs and routers, it is the number of external physical +* ports plus 1. +* +* SYNOPSIS +*/ +static inline uint8_t osm_node_get_num_physp(IN const osm_node_t * 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 * p_node, + IN 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 * p_node, + IN 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 * p_node, + IN 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 * p_node, + IN 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 * p_node, uint8_t port_num, + IN const osm_madw_t * 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 * 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 * p_node, IN uint8_t port_num, + IN osm_node_t * p_remote_node, IN 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 * p_node, IN uint8_t port_num, + IN osm_node_t * p_remote_node, IN 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 * p_node, IN uint8_t port_num, + IN osm_node_t * p_remote_node, + IN 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 * p_node, IN 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 * p_node, + IN uint8_t port_num, + IN osm_node_t * p_remote_node, + IN 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/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_opensm.h b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_opensm.h new file mode 100644 index 00000000..7049088d --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_opensm.h @@ -0,0 +1,523 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2006 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osm_opensm_t. + * This object represents the OpenSM super object. + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_OPENSM_H_ +#define _OSM_OPENSM_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* OpenSM/OpenSM +* NAME +* OpenSM +* +* DESCRIPTION +* The OpenSM object encapsulates the information needed by the +* OpenSM to govern itself. The OpenSM is one OpenSM object. +* +* The OpenSM object is thread safe. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* AUTHOR +* Steve King, Intel +* +*********/ +/****d* OpenSM: OpenSM/osm_routing_engine_type_t +* NAME +* osm_routing_engine_type_t +* +* DESCRIPTION +* Enumerates the possible routing engines that +* could be used to route a subnet. +* +* SYNOPSIS +*/ +typedef enum _osm_routing_engine_type { + OSM_ROUTING_ENGINE_TYPE_NONE = 0, + OSM_ROUTING_ENGINE_TYPE_MINHOP, + OSM_ROUTING_ENGINE_TYPE_UPDN, + OSM_ROUTING_ENGINE_TYPE_FILE, + OSM_ROUTING_ENGINE_TYPE_FTREE, + OSM_ROUTING_ENGINE_TYPE_LASH, + OSM_ROUTING_ENGINE_TYPE_DOR, + OSM_ROUTING_ENGINE_TYPE_UNKNOWN +} osm_routing_engine_type_t; +/***********/ + +/****s* OpenSM: OpenSM/osm_routing_engine +* NAME +* struct osm_routing_engine +* +* DESCRIPTION +* OpenSM routing engine module definition. +* NOTES +* routing engine structure - multicast callbacks may be +* added later. +*/ +struct osm_routing_engine { + const char *name; + void *context; + int (*build_lid_matrices) (void *context); + int (*ucast_build_fwd_tables) (void *context); + void (*ucast_dump_tables) (void *context); + void (*delete) (void *context); + struct osm_routing_engine *next; +}; +/* +* FIELDS +* name +* The routing engine name (will be used in logs). +* +* context +* The routing engine context. Will be passed as parameter +* to the callback functions. +* +* build_lid_matrices +* The callback for lid matrices generation. +* +* ucast_build_fwd_tables +* The callback for unicast forwarding table generation. +* +* ucast_dump_tables +* The callback for dumping unicast routing tables. +* +* delete +* The delete method, may be used for routing engine +* internals cleanup. +* +* next +* Pointer to next routing engine in the list. +*/ + +/****s* OpenSM: OpenSM/osm_opensm_t +* NAME +* osm_opensm_t +* +* DESCRIPTION +* OpenSM structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct osm_opensm { + const char *osm_version; + osm_subn_t subn; + osm_sm_t sm; + osm_sa_t sa; +#ifdef ENABLE_OSM_PERF_MGR + osm_perfmgr_t perfmgr; +#endif /* ENABLE_OSM_PERF_MGR */ + cl_qlist_t plugin_list; + osm_db_t db; + osm_mad_pool_t mad_pool; + osm_vendor_t *p_vendor; + osm_vl15_t vl15; + osm_log_t log; + cl_dispatcher_t disp; + cl_plock_t lock; + struct osm_routing_engine *routing_engine_list; + osm_routing_engine_type_t routing_engine_used; + osm_stats_t stats; + osm_console_t console; + nn_map_t *node_name_map; +} osm_opensm_t; +/* +* FIELDS +* osm_version +* OpenSM version (as generated in osm_version.h) +* +* subn +* Subnet object for this subnet. +* +* sm +* The Subnet Manager (SM) object for this subnet. +* +* sa +* The Subnet Administration (SA) object for this subnet. +* +* db +* Persistant storage of some data required between sessions. +* +* mad_pool +* Pool of Management Datagram (MAD) objects. +* +* p_vendor +* Pointer to the Vendor specific adapter for various +* transport interfaces, such as UMADT, AL, etc. The +* particular interface is set at compile time. +* +* vl15 +* The VL15 interface. +* +* log +* Log facility used by all OpenSM components. +* +* disp +* Central dispatcher containing the OpenSM worker threads. +* +* lock +* Shared lock guarding most OpenSM structures. +* +* routing_engine_list +* List of routing engines that should be tried for use. +* +* routing_engine_used +* Indicates which routing engine was used to route a subnet. +* +* stats +* Open SM statistics block +* +* SEE ALSO +*********/ + +/****f* OpenSM: OpenSM/osm_opensm_construct +* NAME +* osm_opensm_construct +* +* DESCRIPTION +* This function constructs an OpenSM object. +* +* SYNOPSIS +*/ +void osm_opensm_construct(IN osm_opensm_t * 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 * 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 * p_osm, + IN const osm_subn_opt_t * 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 * 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 * p_osm, + IN 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 * p_osm, IN 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 * p_osm, IN uint32_t wait_us, + IN boolean_t 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/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_partition.h b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_partition.h new file mode 100644 index 00000000..201802b9 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_partition.h @@ -0,0 +1,274 @@ +/* + * Copyright (c) 2004-2009 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_prtn_t. + * This object represents an IBA Partition. + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_PARTITION_H_ +#define _OSM_PARTITION_H_ + +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* OpenSM/Partition +* NAME +* Partition +* +* DESCRIPTION +* The Partition object encapsulates the information needed by the +* OpenSM to manage Partitions. The OpenSM allocates one Partition +* object per Partition in the IBA subnet. +* +* The Partition is not thread safe, thus callers must provide +* serialization. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Steve King, Intel +* +*********/ +/****s* OpenSM: Partition/osm_prtn_t +* NAME +* osm_prtn_t +* +* DESCRIPTION +* Partition structure. +* +* The osm_prtn_t object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct osm_prtn { + cl_map_item_t map_item; + ib_net16_t pkey; + uint8_t sl; + osm_mgrp_t *mgrp; + 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. +* +* sl +* The Service Level (SL) associated with this Partiton. +* +* mgrp +* The pointer to the well known Multicast Group +* that was created for this partition (when configured). +* +* 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 ** 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 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 * p_prtn, + IN 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 * p_log, + IN osm_subn_t * 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/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_path.h b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_path.h new file mode 100644 index 00000000..85847e70 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_path.h @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2004-2009 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) 2009 HNR Consulting. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _OSM_PATH_H_ +#define _OSM_PATH_H_ + +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/* + * Abstract: + * Declaration of path related objects. + * These objects are part of the OpenSM family of objects. + */ +/****h* OpenSM/DR Path +* NAME +* DR Path +* +* DESCRIPTION +* The DR Path structure encapsulates a directed route through the subnet. +* +* This structure allows direct access to member variables. +* +* AUTHOR +* Steve King, Intel +* +*********/ +/****s* OpenSM: DR Path/osm_dr_path_t +* NAME +* osm_dr_path_t +* +* DESCRIPTION +* Directed Route structure. +* +* This structure allows direct access to member variables. +* +* SYNOPSIS +*/ +typedef struct osm_dr_path { + osm_bind_handle_t h_bind; + uint8_t hop_count; + uint8_t path[IB_SUBNET_PATH_HOPS_MAX]; +} osm_dr_path_t; +/* +* FIELDS +* h_bind +* Bind handle for port to which this path applies. +* +* hop_count +* The number of hops in this path. +* +* path +* The array of port numbers that comprise this path. +* +* SEE ALSO +* DR Path structure +*********/ +/****f* OpenSM: DR Path/osm_dr_path_construct +* NAME +* osm_dr_path_construct +* +* DESCRIPTION +* This function constructs a directed route path object. +* +* SYNOPSIS +*/ +static inline void osm_dr_path_construct(IN osm_dr_path_t * 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 * p_path, IN osm_bind_handle_t h_bind, + IN 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, hop_count + 1); +} + +/* +* 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 int osm_dr_path_extend(IN osm_dr_path_t * p_path, + IN uint8_t port_num) +{ + p_path->hop_count++; + + if (p_path->hop_count >= IB_SUBNET_PATH_HOPS_MAX) + return -1; + /* + Location 0 in the path array is reserved per IB spec. + */ + p_path->path[p_path->hop_count] = port_num; + return 0; +} + +/* +* 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 VALUES +* 0 indicates path was extended. +* Other than 0 indicates path was not extended. +* +* 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 * 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/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_perfmgr.h b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_perfmgr.h new file mode 100644 index 00000000..a99c4b30 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_perfmgr.h @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2007 The Regents of the University of California. + * Copyright (c) 2007-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2009 HNR Consulting. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _OSM_PERFMGR_H_ +#define _OSM_PERFMGR_H_ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#ifdef ENABLE_OSM_PERF_MGR + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/****h* OpenSM/PerfMgr +* NAME +* PerfMgr +* +* DESCRIPTION +* Performance manager thread which takes care of polling the fabric for +* Port counters values. +* +* The PerfMgr object is thread safe. +* +* AUTHOR +* Ira Weiny, LLNL +* +*********/ + +#define OSM_PERFMGR_DEFAULT_SWEEP_TIME_S 180 +#define OSM_PERFMGR_DEFAULT_DUMP_FILE "opensm_port_counters.log" +#define OSM_PERFMGR_DEFAULT_MAX_OUTSTANDING_QUERIES 500 + +/****s* OpenSM: PerfMgr/osm_perfmgr_state_t */ +typedef enum { + PERFMGR_STATE_DISABLE, + PERFMGR_STATE_ENABLED, + PERFMGR_STATE_NO_DB +} osm_perfmgr_state_t; + +/****s* OpenSM: PerfMgr/osm_perfmgr_sweep_state_t */ +typedef enum { + PERFMGR_SWEEP_SLEEP, + PERFMGR_SWEEP_ACTIVE, + PERFMGR_SWEEP_SUSPENDED +} osm_perfmgr_sweep_state_t; + +/* Redirection information */ +typedef struct redir { + ib_net16_t redir_lid; + ib_net32_t redir_qp; +} redir_t; + +/* Node to store information about nodes being monitored */ +typedef struct monitored_node { + cl_map_item_t map_item; + struct monitored_node *next; + uint64_t guid; + boolean_t esp0; + char *name; + uint32_t num_ports; + 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 queries */ + uint32_t max_outstanding_queries; + cl_qmap_t monitored_map; /* map the nodes being tracked */ + 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 * p_perfmgr); +void osm_perfmgr_destroy(osm_perfmgr_t * 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 * perfmgr) +{ + return 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 * p_perfmgr, + 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 * perfmgr, + struct osm_opensm *osm, + const osm_subn_opt_t * p_opt); +/* +* PARAMETERS +* perfmgr +* [in] Pointer to an osm_perfmgr_t object to initialize. +* +* osm +* [in] Pointer to the OpenSM object. +* +* p_opt +* [in] Pointer to the subnet options structure. +* +* 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/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_perfmgr_db.h b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_perfmgr_db.h new file mode 100644 index 00000000..58267f72 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_perfmgr_db.h @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2007 The Regents of the University of California. + * Copyright (c) 2009 HNR Consulting. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _PERFMGR_EVENT_DB_H_ +#define _PERFMGR_EVENT_DB_H_ + +#ifdef ENABLE_OSM_PERF_MGR + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS + +struct osm_perfmgr; +/****h* OpenSM/PerfMgr Event Database +* DESCRIPTION +* Database interface to record subnet events +* +* Implementations of this object _MUST_ be thread safe. +* +* AUTHOR +* Ira Weiny, LLNL +* +*********/ +typedef enum { + PERFMGR_EVENT_DB_SUCCESS = 0, + PERFMGR_EVENT_DB_FAIL, + PERFMGR_EVENT_DB_NOMEM, + PERFMGR_EVENT_DB_GUIDNOTFOUND, + PERFMGR_EVENT_DB_PORTNOTFOUND, + PERFMGR_EVENT_DB_NOT_IMPL +} perfmgr_db_err_t; + +/** ========================================================================= + * Port error reading + */ +typedef struct { + uint64_t symbol_err_cnt; + uint64_t link_err_recover; + uint64_t link_downed; + uint64_t rcv_err; + uint64_t rcv_rem_phys_err; + uint64_t rcv_switch_relay_err; + uint64_t xmit_discards; + uint64_t xmit_constraint_err; + uint64_t rcv_constraint_err; + uint64_t link_integrity; + uint64_t buffer_overrun; + uint64_t vl15_dropped; + time_t time; +} perfmgr_db_err_reading_t; + +/** ========================================================================= + * Port data count reading + */ +typedef struct { + uint64_t xmit_data; /* can be used for std or extended */ + uint64_t rcv_data; /* can be used for std or extended */ + uint64_t xmit_pkts; /* can be used for std or extended */ + uint64_t rcv_pkts; /* can be used for std or extended */ + uint64_t unicast_xmit_pkts; + uint64_t unicast_rcv_pkts; + uint64_t multicast_xmit_pkts; + uint64_t multicast_rcv_pkts; + time_t time; +} perfmgr_db_data_cnt_reading_t; + +/** ========================================================================= + * 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; + boolean_t esp0; + db_port_t *ports; + uint8_t num_ports; + char node_name[NODE_NAME_SIZE]; +} db_node_t; + +/** ========================================================================= + * all nodes in the subnet. + */ +typedef struct perfmgr_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, + boolean_t esp0, 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/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_pkey.h b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_pkey.h new file mode 100644 index 00000000..28d4fa8d --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_pkey.h @@ -0,0 +1,634 @@ +/* + * Copyright (c) 2010 Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _OSM_PKEY_H_ +#define _OSM_PKEY_H_ + +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/* + Forward references. +*/ +struct osm_physp; +struct osm_port; +struct osm_subn; +struct osm_node; +struct osm_physp; + +/* + * Abstract: + * Declaration of pkey manipulation functions. + */ + +/****s* OpenSM: osm_pkey_tbl_t +* NAME +* osm_pkey_tbl_t +* +* DESCRIPTION +* This object represents a pkey table. The need for a special object +* is required to optimize search performance of a PKey in the IB standard +* non sorted table. +* +* The osm_pkey_tbl_t object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct osm_pkeybl { + cl_ptr_vector_t blocks; + cl_ptr_vector_t new_blocks; + cl_map_t keys; + cl_qlist_t pending; + uint16_t used_blocks; + uint16_t max_blocks; +} osm_pkey_tbl_t; +/* +* FIELDS +* blocks +* The IBA defined blocks of pkey values, updated from the subnet +* +* new_blocks +* The blocks of pkey values, will be used for updates by SM +* +* keys +* A set holding all keys +* +* pending +* A list of osm_pending_pkey structs that is temporarily set by +* the pkey mgr and used during pkey mgr algorithm only +* +* used_blocks +* Tracks the number of blocks having non-zero pkeys +* +* max_blocks +* The maximal number of blocks this partition table might hold +* this value is based on node_info (for port 0 or CA) or +* switch_info updated on receiving the node_info or switch_info +* GetResp +* +* NOTES +* 'blocks' vector should be used to store pkey values obtained from +* the port and SM pkey manager should not change it directly, for this +* purpose 'new_blocks' should be used. +* +* The only pkey values stored in 'blocks' vector will be mapped with +* 'keys' map +* +*********/ + +/****s* OpenSM: osm_pending_pkey_t +* NAME +* osm_pending_pkey_t +* +* DESCRIPTION +* This objects stores temporary information on pkeys, their target block, +* and index during the pkey manager operation +* +* SYNOPSIS +*/ +typedef struct osm_pending_pkey { + cl_list_item_t list_item; + uint16_t pkey; + uint16_t block; + uint8_t index; + boolean_t is_new; +} osm_pending_pkey_t; +/* +* FIELDS +* pkey +* The actual P_Key +* +* block +* The block index based on the previous table extracted from the +* device +* +* index +* The index of the pkey within the block +* +* is_new +* TRUE for new P_Keys such that the block and index are invalid +* in that case +* +*********/ + +/****f* OpenSM: osm_pkey_tbl_construct +* NAME +* osm_pkey_tbl_construct +* +* DESCRIPTION +* Constructs the PKey table object +* +* SYNOPSIS +*/ +void osm_pkey_tbl_construct(IN osm_pkey_tbl_t * p_pkey_tbl); +/* +* p_pkey_tbl +* [in] Pointer to osm_pkey_tbl_t object. +* +* NOTES +* +*********/ + +/****f* OpenSM: osm_pkey_tbl_init +* NAME +* osm_pkey_tbl_init +* +* DESCRIPTION +* Inits the PKey table object +* +* SYNOPSIS +*/ +ib_api_status_t osm_pkey_tbl_init(IN osm_pkey_tbl_t * p_pkey_tbl); +/* +* p_pkey_tbl +* [in] Pointer to osm_pkey_tbl_t object. +* +* NOTES +* +*********/ + +/****f* OpenSM: osm_pkey_tbl_destroy +* NAME +* osm_pkey_tbl_destroy +* +* DESCRIPTION +* Destroys the PKey table object +* +* SYNOPSIS +*/ +void osm_pkey_tbl_destroy(IN osm_pkey_tbl_t * p_pkey_tbl); +/* +* p_pkey_tbl +* [in] Pointer to osm_pkey_tbl_t object. +* +* NOTES +* +*********/ + +/****f* OpenSM: osm_pkey_tbl_get_num_blocks +* NAME +* osm_pkey_tbl_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 block 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 * p_physp1, + IN const struct osm_physp * p_physp2, + IN 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 *p_physp1, + IN const struct osm_physp *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 * p_physp_1, + IN const struct osm_physp * 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 * p_port_1, + IN const struct osm_port * 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 ib_net16_t pkey, + IN const struct osm_physp *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/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_port.h b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_port.h new file mode 100644 index 00000000..b5999586 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_port.h @@ -0,0 +1,1460 @@ +/* + * Copyright (c) 2004-2009 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: + * Declaration of port related objects. + * These objects comprise an IBA port. + * These objects are part of the OpenSM family of objects. + */ + +#ifndef _OSM_PORT_H_ +#define _OSM_PORT_H_ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/* + Forward references. +*/ +struct osm_port; +struct osm_node; +struct osm_mgrp; + +/****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; + uint8_t hop_wf; +} 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. +* +* hop_wf +* Hop weighting factor to be used in the routing. +* +* 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 * 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 * p_physp, IN ib_net64_t port_guid, + IN uint8_t port_num, IN const struct osm_node *p_node, + IN osm_bind_handle_t h_bind, IN uint8_t hop_count, + IN const uint8_t * 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 * 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 * 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 * 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 * 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 * 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 * p_physp, + IN const ib_port_info_t * 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 * 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 + * 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 * 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 * + 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 * 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 * 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 * 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 * 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 * 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 * p_physp, + IN const osm_physp_t * 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 * p_physp, + IN osm_physp_t * 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 * p_physp, + IN osm_physp_t * 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 * 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 * 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 * + p_physp) +{ + CL_ASSERT(p_physp); + CL_ASSERT(osm_physp_is_valid(p_physp)); + return 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 * 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 * 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 * 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 * + 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 CA. +* +* 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 ** 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 *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 * 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 * 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 * 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 * p_port, + OUT uint16_t * p_min_lid, + OUT uint16_t * 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: 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/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_port_profile.h b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_port_profile.h new file mode 100644 index 00000000..ba08b105 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_port_profile.h @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005,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 Switch/osm_port_profile_t. + * This object represents a port profile for an IBA switch. + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_PORT_PROFILE_H_ +#define _OSM_PORT_PROFILE_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* OpenSM/Port Profile +* NAME +* Port Profile +* +* DESCRIPTION +* The Port Profile object contains profiling information for +* each Physical Port on a switch. The profile information +* may be used to optimize path selection. +* +* AUTHOR +* Steve King, Intel +* +*********/ +/****s* OpenSM: Switch/osm_port_profile_t +* NAME +* osm_port_profile_t +* +* DESCRIPTION +* The Port Profile object contains profiling information for +* each Physical Port on the switch. The profile information +* may be used to optimize path selection. +* +* This object should be treated as opaque and should be +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct osm_port_profile { + uint32_t num_paths; +} osm_port_profile_t; +/* +* FIELDS +* num_paths +* The number of paths using this port. +* +* SEE ALSO +*********/ + +/****s* OpenSM: Switch/osm_port_mask_t +* NAME +* osm_port_mask_t +* +* DESCRIPTION +* The Port Mask object contains a port numbered bit mask +* for whether the port should be ignored by the link load +* equalization algorithm. +* +* SYNOPSIS +*/ +typedef long osm_port_mask_t[32 / sizeof(long)]; +/* +* FIELDS +* osm_port_mask_t +* Bit mask by port number +* +* SEE ALSO +*********/ + +/****f* OpenSM: Port Profile/osm_port_prof_construct +* NAME +* osm_port_prof_construct +* +* DESCRIPTION +* +* +* SYNOPSIS +*/ +static inline void osm_port_prof_construct(IN osm_port_profile_t * 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 * 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 * 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/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_prefix_route.h b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_prefix_route.h new file mode 100644 index 00000000..b2f354b3 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_prefix_route.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _OSM_PREFIX_ROUTE_H_ +#define _OSM_PREFIX_ROUTE_H_ + +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS + +typedef struct { + cl_list_item_t list_item; /* must be first */ + ib_net64_t prefix; /* zero means "any" */ + ib_net64_t guid; /* zero means "any" */ +} osm_prefix_route_t; + +#ifdef ROUTER_EXP +#error ROUTER_EXP is deprecated, specify prefix routes at runtime instead (see opensm man page for details) +#endif + +END_C_DECLS +#endif /* _OSM_PREFIX_ROUTE_H_ */ diff --git a/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_qos_policy.h b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_qos_policy.h new file mode 100644 index 00000000..864ed91c --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_qos_policy.h @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2004-2009 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 QoS Policy data types and functions. + * + * Author: + * Yevgeny Kliteynik, Mellanox + */ + +#ifndef OSM_QOS_POLICY_H +#define OSM_QOS_POLICY_H + +#include +#include +#include +#include +#include + +#define YYSTYPE char * +#define OSM_QOS_POLICY_MAX_PORTS_ON_SWITCH 128 +#define OSM_QOS_POLICY_DEFAULT_LEVEL_NAME "default" + +#define OSM_QOS_POLICY_ULP_SDP_SERVICE_ID 0x0000000000010000ULL +#define OSM_QOS_POLICY_ULP_RDS_SERVICE_ID 0x0000000001060000ULL +#define OSM_QOS_POLICY_ULP_RDS_PORT 0x48CA +#define OSM_QOS_POLICY_ULP_ISER_SERVICE_ID 0x0000000001060000ULL +#define OSM_QOS_POLICY_ULP_ISER_PORT 0x0CBC + +#define OSM_QOS_POLICY_NODE_TYPE_CA (((uint8_t)1)< +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* OpenSM/Remote SM +* NAME +* Remote SM +* +* DESCRIPTION +* The Remote SM object encapsulates the information tracked for +* other SM ports on the subnet. +* +* The Remote SM object is thread safe. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* AUTHOR +* Steve King, Intel +* +*********/ +/****s* OpenSM: Remote SM/osm_remote_sm_t +* NAME +* osm_remote_sm_t +* +* DESCRIPTION +* Remote Subnet Manager structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct osm_remote_sm { + cl_map_item_t map_item; + const osm_port_t *p_port; + ib_sm_info_t smi; +} osm_remote_sm_t; +/* +* FIELDS +* map_item +* Linkage for the cl_qmap container. MUST BE FIRST ELEMENT!! +* p_port +* Pointer to the port object for this SM. +* +* smi +* The SMInfo attribute for this SM. +* +* SEE ALSO +*********/ + +/****f* OpenSM: SM/osm_remote_sm_construct +* NAME +* osm_remote_sm_construct +* +* DESCRIPTION +* This function constructs an Remote SM object. +* +* SYNOPSIS +*/ +void osm_remote_sm_construct(IN osm_remote_sm_t * 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 * 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 * p_sm, IN const osm_port_t * p_port, + IN const ib_sm_info_t * 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/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_router.h b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_router.h new file mode 100644 index 00000000..722e6015 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_router.h @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005,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_router_t. + * This object represents an IBA router. + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_ROUTER_H_ +#define _OSM_ROUTER_H_ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* OpenSM/Router +* NAME +* Router +* +* DESCRIPTION +* The Router object encapsulates the information needed by the +* OpenSM to manage routers. The OpenSM allocates one router object +* per router in the IBA subnet. +* +* The Router object is not thread safe, thus callers must provide +* serialization. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Hal Rosenstock, Voltaire +* +*********/ +/****s* OpenSM: Router/osm_router_t +* NAME +* osm_router_t +* +* DESCRIPTION +* Router structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct osm_router { + cl_map_item_t map_item; + osm_port_t *p_port; +} osm_router_t; +/* +* FIELDS +* map_item +* Linkage structure for cl_qmap. MUST BE FIRST MEMBER! +* +* p_port +* Pointer to the Port object for this router. +* +* SEE ALSO +* Router object +*********/ + +/****f* OpenSM: Router/osm_router_delete +* NAME +* osm_router_delete +* +* DESCRIPTION +* Destroys and deallocates the object. +* +* SYNOPSIS +*/ +void osm_router_delete(IN OUT osm_router_t ** 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 * 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 * 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 * 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/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_sa.h b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_sa.h new file mode 100644 index 00000000..ccaddd24 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_sa.h @@ -0,0 +1,495 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osm_sa_t. + * This object represents an IBA subnet. + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_SA_H_ +#define _OSM_SA_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* OpenSM/SA +* NAME +* SA +* +* DESCRIPTION +* The SA object encapsulates the information needed by the +* OpenSM to instantiate a subnet administrator. The OpenSM allocates +* one SA object per subnet manager. +* +* The SA object is thread safe. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* AUTHOR +* Ranjit Pandit, Intel +* Anil Keshavamurthy, Intel +* +*********/ +/****d* OpenSM: SA/osm_sa_state_t +* NAME +* osm_sa_state_t +* +* DESCRIPTION +* Enumerates the possible states of SA object. +* +* SYNOPSIS +*/ +typedef enum _osm_sa_state { + OSM_SA_STATE_INIT = 0, + OSM_SA_STATE_READY +} osm_sa_state_t; +/***********/ + +/****s* OpenSM: SM/osm_sa_t +* NAME +* osm_sa_t +* +* DESCRIPTION +* Subnet Administration structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct osm_sa { + osm_sa_state_t state; + osm_sm_t *sm; + osm_subn_t *p_subn; + osm_vendor_t *p_vendor; + osm_log_t *p_log; + osm_mad_pool_t *p_mad_pool; + cl_dispatcher_t *p_disp; + cl_plock_t *p_lock; + atomic32_t sa_trans_id; + osm_sa_mad_ctrl_t mad_ctrl; + cl_timer_t sr_timer; + boolean_t dirty; + 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 +* +* dirty +* A flag that denotes that SA DB is dirty and needs +* to be written to the dump file (if dumping is enabled) +* +* 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 * 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 * 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 * 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 * p_sm, IN osm_sa_t * p_sa, + IN osm_subn_t * p_subn, IN osm_vendor_t * p_vendor, + IN osm_mad_pool_t * p_mad_pool, + IN osm_log_t * p_log, IN osm_stats_t * p_stats, + IN cl_dispatcher_t * p_disp, + IN cl_plock_t * 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 * p_sa, IN 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 * p_madw, + IN boolean_t 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 * p_madw, + IN 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 +* 0 if the SA DB was actually dumped +* >0 if there was no need to dump the SA DB +* <0 if some error occurred. +* +*********/ + +/****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 ib_net64_t comp_mask, + IN ib_member_rec_t * 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 +* +*********/ + +END_C_DECLS +#endif /* _OSM_SA_H_ */ diff --git a/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_sa_mad_ctrl.h b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_sa_mad_ctrl.h new file mode 100644 index 00000000..0d57db27 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_sa_mad_ctrl.h @@ -0,0 +1,337 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osm_sa_mad_ctrl_t. + * This object represents a controller that receives the IBA SA + * attributes from a node. + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_SA_MAD_CTRL_H_ +#define _OSM_SA_MAD_CTRL_H_ + +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* OpenSM/SA MAD Controller +* NAME +* SA MAD Controller +* +* DESCRIPTION +* The SA MAD Controller object encapsulates +* the information needed to receive MADs from the transport layer. +* +* The SA MAD Controller object is thread safe. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Ranjit Pandit, Intel +* +*********/ + +struct osm_sa; +/****s* OpenSM: SA MAD Controller/osm_sa_mad_ctrl_t +* NAME +* osm_sa_mad_ctrl_t +* +* DESCRIPTION +* SA MAD Controller structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct osm_sa_mad_ctrl { + struct osm_sa *sa; + osm_log_t *p_log; + osm_mad_pool_t *p_mad_pool; + osm_vendor_t *p_vendor; + osm_bind_handle_t h_bind; + cl_dispatcher_t *p_disp; + cl_disp_reg_handle_t h_disp; + osm_stats_t *p_stats; + osm_subn_t *p_subn; +} osm_sa_mad_ctrl_t; +/* +* FIELDS +* sa +* Pointer to the SA object. +* +* p_log +* Pointer to the log object. +* +* p_mad_pool +* Pointer to the MAD pool. +* +* p_vendor +* Pointer to the vendor specific interfaces object. +* +* h_bind +* Bind handle returned by the transport layer. +* +* p_disp +* Pointer to the Dispatcher. +* +* h_disp +* Handle returned from dispatcher registration. +* +* p_stats +* Pointer to the OpenSM statistics block. +* +* SEE ALSO +* SA MAD Controller object +* SA MADr object +*********/ + +/****f* OpenSM: SA MAD Controller/osm_sa_mad_ctrl_construct +* NAME +* osm_sa_mad_ctrl_construct +* +* DESCRIPTION +* This function constructs a SA MAD Controller object. +* +* SYNOPSIS +*/ +void osm_sa_mad_ctrl_construct(IN osm_sa_mad_ctrl_t * 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 * 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 * p_ctrl, + IN struct osm_sa * sa, + IN osm_mad_pool_t * p_mad_pool, + IN osm_vendor_t * p_vendor, + IN osm_subn_t * p_subn, + IN osm_log_t * p_log, + IN osm_stats_t * p_stats, + IN cl_dispatcher_t * 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 * p_ctrl, + IN 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 * 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 * 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/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_service.h b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_service.h new file mode 100644 index 00000000..fa8c31dd --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_service.h @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _OSM_SVCR_H_ +#define _OSM_SVCR_H_ + +/* + * Abstract: + * Declaration of osm_service_rec_t. + * This object represents an IBA Service Record. + * This object is part of the OpenSM family of objects. + */ + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* OpenSM/Service Record +* NAME +* Service Record +* +* DESCRIPTION +* The service record encapsulates the information needed by the +* SA to manage service registrations. +* +* The service records is not thread safe, thus callers must provide +* serialization. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Anil S Keshavamurthy, Intel +* +*********/ +/****s* OpenSM: Service Record/osm_svcr_t +* NAME +* osm_svcr_t +* +* DESCRIPTION +* Service Record structure. +* +* The osm_svcr_t object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct osm_svcr { + cl_list_item_t list_item; + ib_service_record_t service_record; + uint32_t modified_time; + uint32_t lease_period; +} osm_svcr_t; +/* +* FIELDS +* map_item +* Map Item for qmap linkage. Must be first element!! +* +* svc_rec +* IB Service record structure +* +* modified_time +* Last modified time of this record in milliseconds +* +* lease_period +* Remaining lease period for this record +* +* +* SEE ALSO +*********/ + +/****f* OpenSM: Service Record/osm_svcr_new +* NAME +* osm_svcr_new +* +* DESCRIPTION +* Allocates and initializes a Service Record for use. +* +* SYNOPSIS +*/ +osm_svcr_t *osm_svcr_new(IN const ib_service_record_t * p_svc_rec); +/* +* PARAMETERS +* p_svc_rec +* [in] Pointer to IB Service Record +* +* RETURN VALUES +* pointer to osm_svcr_t structure. +* +* NOTES +* Allows calling other service record methods. +* +* SEE ALSO +* Service Record, osm_svcr_delete +*********/ + +/****f* OpenSM: Service Record/osm_svcr_init +* NAME +* osm_svcr_init +* +* DESCRIPTION +* Initializes the osm_svcr_t structure. +* +* SYNOPSIS +*/ +void osm_svcr_init(IN osm_svcr_t * 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 * 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 * 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/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_sm.h b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_sm.h new file mode 100644 index 00000000..eeff0d51 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_sm.h @@ -0,0 +1,739 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005,2009 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osm_sm_t. + * This object represents an IBA subnet. + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_SM_H_ +#define _OSM_SM_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* OpenSM/SM +* NAME +* SM +* +* DESCRIPTION +* The SM object encapsulates the information needed by the +* OpenSM to instantiate a subnet manager. The OpenSM allocates +* one SM object per subnet manager. +* +* The SM object is thread safe. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* AUTHOR +* Steve King, Intel +* +*********/ +/****s* OpenSM: SM/osm_sm_t +* NAME +* osm_sm_t +* +* DESCRIPTION +* Subnet Manager structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct osm_sm { + osm_thread_state_t thread_state; + unsigned signal_mask; + cl_spinlock_t signal_lock; + cl_spinlock_t state_lock; + cl_event_t signal_event; + cl_event_t subnet_up_event; + cl_timer_t sweep_timer; + cl_timer_t polling_timer; + cl_event_wheel_t trap_aging_tracker; + cl_thread_t sweeper; + unsigned master_sm_found; + uint32_t retry_number; + ib_net64_t master_sm_guid; + osm_remote_sm_t *p_polling_sm; + osm_subn_t *p_subn; + osm_db_t *p_db; + osm_vendor_t *p_vendor; + osm_log_t *p_log; + osm_mad_pool_t *p_mad_pool; + osm_vl15_t *p_vl15; + cl_dispatcher_t *p_disp; + cl_plock_t *p_lock; + atomic32_t sm_trans_id; + unsigned mlids_req_max; + uint8_t *mlids_req; + 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 * 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 * 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 * 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 * p_sm, IN osm_subn_t * p_subn, + IN osm_db_t * p_db, IN osm_vendor_t * p_vendor, + IN osm_mad_pool_t * p_mad_pool, + IN osm_vl15_t * p_vl15, IN osm_log_t * p_log, + IN osm_stats_t * p_stats, + IN cl_dispatcher_t * p_disp, IN cl_plock_t * 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 * 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 * 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 * p_sm, IN 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 * p_path, + IN ib_net16_t attr_id, IN ib_net32_t attr_mod, + IN cl_disp_msgid_t err_msg, + IN const osm_madw_context_t * 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 * p_path, + IN const uint8_t * p_payload, + IN size_t payload_size, IN ib_net16_t attr_id, + IN ib_net32_t attr_mod, IN cl_disp_msgid_t err_msg, + IN const osm_madw_context_t * 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 * p_req_madw, + IN ib_net16_t status, + IN const uint8_t * 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_reroute_mlid +* NAME +* osm_sm_reroute_mlid +* +* DESCRIPTION +* Requests (schedules) MLID rerouting +* +* SYNOPSIS +*/ +void osm_sm_reroute_mlid(osm_sm_t * sm, ib_net16_t mlid); + +/* +* PARAMETERS +* sm +* [in] Pointer to an osm_sm_t object. +* +* mlid +* [in] MLID value +* +* 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 * p_sm, + IN uint32_t wait_us, + IN boolean_t 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 uint8_t l_priority, + IN ib_net64_t l_guid, + IN uint8_t r_priority, + IN 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/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_sm_mad_ctrl.h b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_sm_mad_ctrl.h new file mode 100644 index 00000000..b15b822c --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_sm_mad_ctrl.h @@ -0,0 +1,321 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osm_sm_mad_ctrl_t. + * This object represents a controller that receives the IBA NodeInfo + * attribute from a node. + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_SM_MAD_CTRL_H_ +#define _OSM_SM_MAD_CTRL_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* OpenSM/SM MAD Controller +* NAME +* SM MAD Controller +* +* DESCRIPTION +* The SM MAD Controller object encapsulates +* the information needed to receive MADs from the transport layer. +* +* The SM MAD Controller object is thread safe. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Steve King, Intel +* +*********/ +/****s* OpenSM: SM MAD Controller/osm_sm_mad_ctrl_t +* NAME +* osm_sm_mad_ctrl_t +* +* DESCRIPTION +* SM MAD Controller structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct osm_sm_mad_ctrl { + osm_log_t *p_log; + osm_subn_t *p_subn; + osm_mad_pool_t *p_mad_pool; + osm_vl15_t *p_vl15; + osm_vendor_t *p_vendor; + osm_bind_handle_t h_bind; + cl_plock_t *p_lock; + cl_dispatcher_t *p_disp; + cl_disp_reg_handle_t h_disp; + osm_stats_t *p_stats; +} osm_sm_mad_ctrl_t; +/* +* FIELDS +* p_log +* Pointer to the log object. +* +* p_subn +* Pointer to the subnet object. +* +* p_mad_pool +* Pointer to the MAD pool. +* +* p_vendor +* Pointer to the vendor specific interfaces object. +* +* h_bind +* Bind handle returned by the transport layer. +* +* p_lock +* Pointer to the serializing lock. +* +* p_disp +* Pointer to the Dispatcher. +* +* h_disp +* Handle returned from dispatcher registration. +* +* p_stats +* Pointer to the OpenSM statistics block. +* +* SEE ALSO +* SM MAD Controller object +* SM MADr object +*********/ + +/****f* OpenSM: SM MAD Controller/osm_sm_mad_ctrl_construct +* NAME +* osm_sm_mad_ctrl_construct +* +* DESCRIPTION +* This function constructs a SM MAD Controller object. +* +* SYNOPSIS +*/ +void osm_sm_mad_ctrl_construct(IN osm_sm_mad_ctrl_t * 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 * 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 * p_ctrl, + IN osm_subn_t * p_subn, + IN osm_mad_pool_t * p_mad_pool, + IN osm_vl15_t * p_vl15, + IN osm_vendor_t * p_vendor, + IN osm_log_t * p_log, + IN osm_stats_t * p_stats, + IN cl_plock_t * p_lock, + IN cl_dispatcher_t * 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 * p_ctrl, + IN 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 * 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/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_stats.h b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_stats.h new file mode 100644 index 00000000..37f6811f --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_stats.h @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osm_stats_t. + * This object represents the OpenSM statistics object. + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_STATS_H_ +#define _OSM_STATS_H_ + +#ifdef HAVE_LIBPTHREAD +#include +#else +#include +#endif +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* OpenSM/Statistics +* NAME +* OpenSM +* +* DESCRIPTION +* The OpenSM object encapsulates the information needed by the +* OpenSM to track interesting traffic and internal statistics. +* +* AUTHOR +* Steve King, Intel +* +*********/ +/****s* OpenSM: Statistics/osm_stats_t +* NAME +* osm_stats_t +* +* DESCRIPTION +* OpenSM statistics block. +* +* SYNOPSIS +*/ +typedef struct osm_stats { + atomic32_t qp0_mads_outstanding; + atomic32_t qp0_mads_outstanding_on_wire; + atomic32_t qp0_mads_rcvd; + atomic32_t qp0_mads_sent; + atomic32_t qp0_unicasts_sent; + atomic32_t qp0_mads_rcvd_unknown; + atomic32_t sa_mads_outstanding; + atomic32_t sa_mads_rcvd; + atomic32_t sa_mads_sent; + atomic32_t sa_mads_rcvd_unknown; + atomic32_t sa_mads_ignored; +#ifdef HAVE_LIBPTHREAD + pthread_mutex_t mutex; + pthread_cond_t cond; +#else + cl_event_t event; +#endif +} osm_stats_t; +/* +* FIELDS +* qp0_mads_outstanding +* Contains the number of MADs outstanding on QP0. +* When this value reaches zero, OpenSM has discovered all +* nodes on the subnet, and finished retrieving attributes. +* At that time, subnet configuration may begin. +* This variable must be manipulated using atomic instructions. +* +* qp0_mads_outstanding_on_wire +* The number of MADs outstanding on the wire at any moment. +* +* qp0_mads_rcvd +* Total number of QP0 MADs received. +* +* qp0_mads_sent +* Total number of QP0 MADs sent. +* +* qp0_unicasts_sent +* Total number of response-less MADs sent on the wire. This count +* includes getresp(), send() and trap() methods. +* +* qp0_mads_rcvd_unknown +* Total number of unknown QP0 MADs received. This includes +* unrecognized attribute IDs and methods. +* +* sa_mads_outstanding +* Contains the number of SA MADs outstanding on QP1. +* +* sa_mads_rcvd +* Total number of SA MADs received. +* +* sa_mads_sent +* Total number of SA MADs sent. +* +* sa_mads_rcvd_unknown +* Total number of unknown SA MADs received. This includes +* unrecognized attribute IDs and methods. +* +* sa_mads_ignored +* Total number of SA MADs received because SM is not +* master or SM is in first time sweep. +* +* SEE ALSO +***************/ + +static inline uint32_t osm_stats_inc_qp0_outstanding(osm_stats_t *stats) +{ + uint32_t outstanding; + +#ifdef HAVE_LIBPTHREAD + pthread_mutex_lock(&stats->mutex); + outstanding = ++stats->qp0_mads_outstanding; + pthread_mutex_unlock(&stats->mutex); +#else + outstanding = cl_atomic_inc(&stats->qp0_mads_outstanding); +#endif + + return outstanding; +} + +static inline uint32_t osm_stats_dec_qp0_outstanding(osm_stats_t *stats) +{ + uint32_t outstanding; + +#ifdef HAVE_LIBPTHREAD + pthread_mutex_lock(&stats->mutex); + outstanding = --stats->qp0_mads_outstanding; + if (!outstanding) + pthread_cond_signal(&stats->cond); + pthread_mutex_unlock(&stats->mutex); +#else + outstanding = cl_atomic_dec(&stats->qp0_mads_outstanding); + if (!outstanding) + cl_event_signal(&stats->event); +#endif + + return outstanding; +} + +END_C_DECLS +#endif /* _OSM_STATS_H_ */ diff --git a/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_subnet.h b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_subnet.h new file mode 100644 index 00000000..94079f1c --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_subnet.h @@ -0,0 +1,1185 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2009 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Copyright (c) 2008 Xsigo Systems Inc. All rights reserved. + * Copyright (c) 2009 System Fabric Works, Inc. All rights reserved. + * Copyright (c) 2009 HNR Consulting. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osm_subn_t. + * This object represents an IBA subnet. + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_SUBNET_H_ +#define _OSM_SUBNET_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +#define OSM_SUBNET_VECTOR_MIN_SIZE 0 +#define OSM_SUBNET_VECTOR_GROW_SIZE 1 +#define OSM_SUBNET_VECTOR_CAPACITY 256 +struct osm_opensm; +struct osm_qos_policy; + +/****h* OpenSM/Subnet +* NAME +* Subnet +* +* DESCRIPTION +* The Subnet object encapsulates the information needed by the +* OpenSM to manage a subnet. The OpenSM allocates one Subnet object +* per IBA subnet. +* +* The Subnet object is not thread safe, thus callers must provide +* serialization. +* +* This object is essentially a container for the various components +* of a subnet. Callers may directly access the member variables. +* +* AUTHOR +* Steve King, Intel +* +*********/ + +/****s* OpenSM: Subnet/osm_qos_options_t +* NAME +* osm_qos_options_t +* +* DESCRIPTION +* Subnet QoS options structure. This structure contains the various +* QoS specific configuration parameters for the subnet. +* +* SYNOPSIS +*/ +typedef struct osm_qos_options { + unsigned max_vls; + int high_limit; + char *vlarb_high; + char *vlarb_low; + char *sl2vl; +} osm_qos_options_t; +/* +* FIELDS +* +* max_vls +* The number of maximum VLs on the Subnet (0 == use default) +* +* high_limit +* The limit of High Priority component of VL Arbitration +* table (IBA 7.6.9) (-1 == use default) +* +* vlarb_high +* High priority VL Arbitration table template. (NULL == use default) +* +* vlarb_low +* Low priority VL Arbitration table template. (NULL == use default) +* +* sl2vl +* SL2VL Mapping table (IBA 7.6.6) template. (NULL == use default) +* +*********/ + +/****s* OpenSM: Subnet/osm_subn_opt_t +* NAME +* osm_subn_opt_t +* +* DESCRIPTION +* Subnet options structure. This structure contains the various +* site specific configuration parameters for the subnet. +* +* SYNOPSIS +*/ +typedef struct osm_subn_opt { + char *config_file; + ib_net64_t guid; + ib_net64_t m_key; + ib_net64_t sm_key; + ib_net64_t sa_key; + ib_net64_t subnet_prefix; + ib_net16_t m_key_lease_period; + uint32_t sweep_interval; + uint32_t max_wire_smps; + uint32_t transaction_timeout; + uint32_t transaction_retries; + 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; + char *hop_weights_file; + char *dimn_ports_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 *io_guid_file; + uint16_t max_reverse_hops; + char *ids_guid_file; + char *guid_routing_order_file; + char *sa_db_file; + boolean_t sa_db_dump; + boolean_t do_mesh_analysis; + boolean_t exit_on_fatal; + boolean_t honor_guid2lid_file; + boolean_t daemon; + boolean_t sm_inactive; + boolean_t babbling_port_policy; + boolean_t use_optimized_slvl; + 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 *event_plugin_options; + char *node_name_map_name; + char *prefix_routes_file; + char *log_prefix; + boolean_t consolidate_ipv6_snm_req; + struct osm_subn_opt *file_opts; /* used for update */ + uint8_t lash_start_vl; /* starting vl to use in lash */ + uint8_t sm_sl; /* which SL to use for SM/SA communication */ +} 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. +* +* transaction_retries +* The number of retries for a transaction. Default is 3. +* +* 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 and fat-tree routing engines (even if this violates +* "pure" deadlock free up/down or fat-tree 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) +* +* io_guid_file +* Name of the file that contains list of I/O 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. +* +* sa_db_dump +* When TRUE causes OpenSM to dump SA DB at the end of every +* light sweep regardless the current verbosity level. +* +* 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. +* +* use_optimized_slvl +* Use optimized SLtoVLMappingTable programming if +* device indicates it supports this. +* +* 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_plugin_name +* Specify the name(s) of the event plugin(s) +* +* event_plugin_options +* Options string that would be passed to the plugin(s) +* +* 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; + cl_fmap_t mgrp_mgid_tbl; + void *mboxes[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) +* +* mgrp_mgid_tbl +* Container of pointers to all Multicast group objects in +* the subnet. Indexed by MGID. +* +* mboxes +* Array of pointers to all Multicast MLID box 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 * 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 * 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 * p_subn, + IN struct osm_opensm *p_osm, + IN const osm_subn_opt_t * 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 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: Port/osm_get_port_by_lid_ho +* NAME +* osm_get_port_by_lid_ho +* +* DESCRIPTION +* Returns a pointer of the port object for given lid value. +* +* SYNOPSIS +*/ +struct osm_port *osm_get_port_by_lid_ho(const osm_subn_t * subn, uint16_t lid); +/* +* PARAMETERS +* subn +* [in] Pointer to the subnet data structure. +* +* lid +* [in] LID requested in hot byte order. +* +* RETURN VALUES +* The port structure pointer if found. NULL otherwise. +* +* SEE ALSO +* Subnet object, osm_port_t +*********/ + +/****f* OpenSM: Port/osm_get_port_by_lid +* NAME +* osm_get_port_by_lid +* +* DESCRIPTION +* Returns a pointer of the port object for given lid value. +* +* SYNOPSIS +*/ +static inline struct osm_port *osm_get_port_by_lid(IN osm_subn_t const * subn, + IN ib_net16_t lid) +{ + return osm_get_port_by_lid_ho(subn, cl_ntoh16(lid)); +} +/* +* PARAMETERS +* subn +* [in] Pointer to the subnet data structure. +* +* lid +* [in] LID requested in network byte order. +* +* RETURN VALUES +* The port structure pointer if found. NULL otherwise. +* +* SEE ALSO +* Subnet object, osm_port_t +*********/ + +/****f* OpenSM: Subnet/osm_get_mgrp_by_mgid +* NAME +* osm_get_mgrp_by_mgid +* +* DESCRIPTION +* The looks for the given multicast group in the subnet table by mgid. +* NOTE: this code is not thread safe. Need to grab the lock before +* calling it. +* +* SYNOPSIS +*/ +struct osm_mgrp *osm_get_mgrp_by_mgid(IN osm_subn_t * subn, IN ib_gid_t * mgid); +/* +* PARAMETERS +* subn +* [in] Pointer to an osm_subn_t object +* +* mgid +* [in] The multicast group MGID value +* +* RETURN VALUES +* The multicast group structure pointer if found. NULL otherwise. +*********/ + +/****f* OpenSM: Subnet/osm_get_mbox_by_mlid +* NAME +* osm_get_mbox_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_box *osm_get_mbox_by_mlid(osm_subn_t const *p_subn, ib_net16_t mlid) +{ + return p_subn->mboxes[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: 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 * 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 * 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 * 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 * 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 * 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 * p_opt); + +END_C_DECLS +#endif /* _OSM_SUBNET_H_ */ diff --git a/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_switch.h b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_switch.h new file mode 100644 index 00000000..7fe11426 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_switch.h @@ -0,0 +1,1143 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2009 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osm_switch_t. + * This object represents an IBA switch. + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_SWITCH_H_ +#define _OSM_SWITCH_H_ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* OpenSM/Switch +* NAME +* Switch +* +* DESCRIPTION +* The Switch object encapsulates the information needed by the +* OpenSM to manage switches. The OpenSM allocates one switch object +* per switch in the IBA subnet. +* +* The Switch object is not thread safe, thus callers must provide +* serialization. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Steve King, Intel +* +*********/ +/****s* OpenSM: Switch/osm_switch_t +* NAME +* osm_switch_t +* +* DESCRIPTION +* Switch structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct osm_switch { + cl_map_item_t map_item; + osm_node_t *p_node; + ib_switch_info_t switch_info; + uint16_t max_lid_ho; + uint8_t num_ports; + uint16_t num_hops; + uint8_t **hops; + osm_port_profile_t *p_prof; + uint8_t *dimn_ports; + uint8_t *lft; + uint8_t *new_lft; + uint16_t lft_size; + osm_mcast_tbl_t mcast_tbl; + int32_t mft_block_num; + uint32_t mft_position; + unsigned endport_links; + unsigned need_update; + void *priv; + cl_map_item_t mgrp_item; + uint32_t num_of_mcm; + uint8_t is_mc_member; +} 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. +* +* need_update +* When set indicates that switch was probably reset, so +* fwd tables and rest cached data should be flushed +* +* mgrp_item +* map item for switch in building mcast tree +* +* num_of_mcm +* number of mcast members(ports) connected to switch +* +* is_mc_member +* whether switch is a mcast member itself +* +* 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; + uint8_t port; + } 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. +* +* port +* Port number on the 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 ** 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 * p_node, + IN const osm_madw_t * 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 * p_sw, + IN uint16_t lid_ho, + IN 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 * p_sw, IN uint16_t lid_ho, + IN uint8_t port_num, IN 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 0 if successfull. -1 if it failed +* +* 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 * p_sw, + IN 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 * 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 * p_sw, + IN uint16_t lid_ho) +{ + if (lid_ho == 0 || lid_ho > p_sw->max_lid_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_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 * + p_sw, IN 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 * 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 * 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 * p_sw, + IN uint16_t block_id, OUT uint8_t * 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 * 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 * p_sw, + IN const ib_switch_info_t * 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 * p_sw, + IN 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 * p_sw, IN const uint8_t * p_block, + IN 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 > p_sw->lft_size) + 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 * p_sw, IN const ib_net16_t * p_block, + IN uint16_t block_num, IN 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 * p_sw, + IN uint16_t block_num, + IN uint8_t position, + OUT ib_net16_t * 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 * 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 * 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 * 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_get_dimn_port +* NAME +* osm_switch_get_dimn_port +* +* DESCRIPTION +* Get the routing ordered port +* +* SYNOPSIS +*/ +static inline uint8_t osm_switch_get_dimn_port(IN const osm_switch_t * p_sw, + IN uint8_t port_num) +{ + CL_ASSERT(p_sw); + if (p_sw->dimn_ports == NULL) + return port_num; + return p_sw->dimn_ports[port_num]; +} +/* +* PARAMETERS +* p_sw +* [in] Pointer to the switch object. +* +* port_num +* [in] Port number in the switch +* +* RETURN VALUES +* Returns the port number ordered for routing purposes. +*/ + +/****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 * p_sw, + IN osm_port_t * p_port, IN uint16_t lid_ho, + IN unsigned start_from, + IN boolean_t ignore_existing, + IN 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 * p_sw, + IN osm_port_t * p_port, + IN uint16_t mlid_ho, + IN 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 * 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 * p_sw, + IN 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 * 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 * p_sw, IN 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/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_ucast_cache.h b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_ucast_cache.h new file mode 100644 index 00000000..af17bb20 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_ucast_cache.h @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2008 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: + * Header file that describes Unicast Cache functions. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#ifndef _OSM_UCAST_CACHE_H_ +#define _OSM_UCAST_CACHE_H_ + +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS + +struct osm_ucast_mgr; + +/****h* OpenSM/Unicast Manager/Unicast Cache +* NAME +* Unicast Cache +* +* DESCRIPTION +* The Unicast Cache object encapsulates the information +* needed to cache and write unicast routing of the subnet. +* +* The Unicast Cache object is NOT thread safe. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Yevgeny Kliteynik, Mellanox +* +*********/ + +/****f* OpenSM: Unicast Cache/osm_ucast_cache_invalidate +* NAME +* osm_ucast_cache_invalidate +* +* DESCRIPTION +* The osm_ucast_cache_invalidate function purges the +* unicast cache and marks the cache as invalid. +* +* SYNOPSIS +*/ +void osm_ucast_cache_invalidate(struct osm_ucast_mgr *p_mgr); +/* +* PARAMETERS +* p_mgr +* [in] Pointer to the ucast mgr object. +* +* RETURN VALUE +* This function does not return any value. +* +* NOTES +* +* SEE ALSO +* Unicast Manager object +*********/ + +/****f* OpenSM: Unicast Cache/osm_ucast_cache_check_new_link +* NAME +* osm_ucast_cache_check_new_link +* +* DESCRIPTION +* The osm_ucast_cache_check_new_link checks whether +* the newly discovered link still allows us to use +* cached unicast routing. +* +* SYNOPSIS +*/ +void osm_ucast_cache_check_new_link(struct osm_ucast_mgr *p_mgr, + osm_node_t * p_node_1, uint8_t port_num_1, + osm_node_t * p_node_2, uint8_t port_num_2); +/* +* PARAMETERS +* p_mgr +* [in] Pointer to the unicast manager object. +* +* physp1 +* [in] Pointer to the first physical port of the link. +* +* physp2 +* [in] Pointer to the second physical port of the link. +* +* RETURN VALUE +* This function does not return any value. +* +* NOTES +* The function checks whether the link was previously +* cached/dropped or is this a completely new link. +* If it decides that the new link makes cached routing +* invalid, the cache is purged and marked as invalid. +* +* SEE ALSO +* Unicast Cache object +*********/ + +/****f* OpenSM: Unicast Cache/osm_ucast_cache_add_link +* NAME +* osm_ucast_cache_add_link +* +* DESCRIPTION +* The osm_ucast_cache_add_link adds link to the cache. +* +* SYNOPSIS +*/ +void osm_ucast_cache_add_link(struct osm_ucast_mgr *p_mgr, + osm_physp_t * physp1, osm_physp_t * physp2); +/* +* PARAMETERS +* p_mgr +* [in] Pointer to the unicast manager object. +* +* physp1 +* [in] Pointer to the first physical port of the link. +* +* physp2 +* [in] Pointer to the second physical port of the link. +* +* RETURN VALUE +* This function does not return any value. +* +* NOTES +* Since the cache operates with ports and not links, +* the function adds two port entries (both sides of the +* link) to the cache. +* If it decides that the dropped link makes cached routing +* invalid, the cache is purged and marked as invalid. +* +* SEE ALSO +* Unicast Manager object +*********/ + +/****f* OpenSM: Unicast Cache/osm_ucast_cache_add_node +* NAME +* osm_ucast_cache_add_node +* +* DESCRIPTION +* The osm_ucast_cache_add_node adds node and all +* its links to the cache. +* +* SYNOPSIS +*/ +void osm_ucast_cache_add_node(struct osm_ucast_mgr *p_mgr, osm_node_t * p_node); +/* +* PARAMETERS +* p_mgr +* [in] Pointer to the unicast manager object. +* +* p_node +* [in] Pointer to the node object that should be cached. +* +* RETURN VALUE +* This function does not return any value. +* +* NOTES +* If the function decides that the dropped node makes cached +* routing invalid, the cache is purged and marked as invalid. +* +* SEE ALSO +* Unicast Manager object +*********/ + +/****f* OpenSM: Unicast Cache/osm_ucast_cache_process +* NAME +* osm_ucast_cache_process +* +* DESCRIPTION +* The osm_ucast_cache_process function writes the +* cached unicast routing on the subnet switches. +* +* SYNOPSIS +*/ +int osm_ucast_cache_process(struct osm_ucast_mgr *p_mgr); +/* +* PARAMETERS +* p_mgr +* [in] Pointer to the unicast manager object. +* +* RETURN VALUE +* This function returns zero on sucess and non-zero +* value otherwise. +* +* NOTES +* Iterates through all the subnet switches and writes +* the LFTs that were calculated during the last routing +* engine execution to the switches. +* +* SEE ALSO +* Unicast Manager object +*********/ + +END_C_DECLS +#endif /* _OSM_UCAST_CACHE_H_ */ diff --git a/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_ucast_lash.h b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_ucast_lash.h new file mode 100644 index 00000000..3224a75a --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_ucast_lash.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2008,2009 System Fabric Works, Inc. All rights reserved. + * 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) 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: + * Declarations for LASH algorithm + */ + +#ifndef OSM_UCAST_LASH_H +#define OSM_UCAST_LASH_H + +#include + +enum { + UNQUEUED, + Q_MEMBER, + MST_MEMBER, + MAX_INT = 9999, + NONE = MAX_INT +}; + +typedef struct _cdg_vertex { + 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_deps; + struct vertex_deps { + struct _cdg_vertex *v; + int num_used; + } deps[0]; +} cdg_vertex_t; + +typedef struct _switch { + osm_switch_t *p_sw; + int id; + int used_channels; + int *dij_channels; + int q_state; + mesh_node_t *node; + struct routing_table { + unsigned out_link; + unsigned lane; + } routing_table[0]; +} 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[IB_MAX_NUM_VLS]; + int ***virtual_location; +} lash_t; + +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); + +#endif diff --git a/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_ucast_mgr.h b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_ucast_mgr.h new file mode 100644 index 00000000..b4490d68 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_ucast_mgr.h @@ -0,0 +1,300 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2009 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osm_ucast_mgr_t. + * This object represents the Unicast Manager object. + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_UCAST_MGR_H_ +#define _OSM_UCAST_MGR_H_ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* OpenSM/Unicast Manager +* NAME +* Unicast Manager +* +* DESCRIPTION +* The Unicast Manager object encapsulates the information +* needed to control unicast LID forwarding on the subnet. +* +* The Unicast Manager object is thread safe. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Steve King, Intel +* +*********/ +struct osm_sm; +/****s* OpenSM: Unicast Manager/osm_ucast_mgr_t +* NAME +* osm_ucast_mgr_t +* +* DESCRIPTION +* Unicast Manager structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct osm_ucast_mgr { + struct osm_sm *sm; + osm_subn_t *p_subn; + osm_log_t *p_log; + cl_plock_t *p_lock; + uint16_t max_lid; + 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. +* +* 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 * 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 * 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 * 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_tables +* NAME +* osm_ucast_mgr_set_fwd_tables +* +* DESCRIPTION +* Setup forwarding table for the switch (from prepared new_lft). +* +* SYNOPSIS +*/ +void osm_ucast_mgr_set_fwd_tables(IN osm_ucast_mgr_t * p_mgr); +/* +* PARAMETERS +* p_mgr +* [in] Pointer to an osm_ucast_mgr_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 * 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 * 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/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_version.h b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_version.h new file mode 100644 index 00000000..5f354110 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_version.h @@ -0,0 +1,55 @@ +/* + * 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 +*/ +#ifdef OSM_VENDOR_INTF_AL +#define OSM_VERSION "OpenSM 3.3.6" " IBAL" +#else +#define OSM_VERSION "OpenSM 3.3.6" " UMAD" +#endif +/********/ + +#endif /* _OSM_VERSION_H_ */ diff --git a/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_version.h.in b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_version.h.in new file mode 100644 index 00000000..9f1f7aaa --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/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/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_vl15intf.h b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_vl15intf.h new file mode 100644 index 00000000..a2dfa8f8 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/opensm/osm_vl15intf.h @@ -0,0 +1,361 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF 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 a VL15 interface object. + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_VL15INTF_H_ +#define _OSM_VL15INTF_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* OpenSM/VL15 +* NAME +* VL15 +* +* DESCRIPTION +* The VL15 object encapsulates the information needed by the +* OpenSM to instantiate the VL15 interface. The OpenSM allocates +* one VL15 object per subnet. +* +* The VL15 object transmits MADs to the wire at a throttled rate, +* so as to not overload the VL15 buffering of subnet components. +* OpenSM modules may post VL15 MADs to the VL15 interface as fast +* as possible. +* +* The VL15 object is thread safe. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* AUTHOR +* Steve King, Intel +* +*********/ +/****d* OpenSM: SM/osm_vl15_state_t +* NAME +* osm_vl15_state_t +* +* DESCRIPTION +* Enumerates the possible states of SM object. +* +* SYNOPSIS +*/ +typedef enum _osm_vl15_state { + OSM_VL15_STATE_INIT = 0, + OSM_VL15_STATE_READY +} osm_vl15_state_t; +/***********/ + +/****s* OpenSM: VL15/osm_vl15_t +* NAME +* osm_vl15_t +* +* DESCRIPTION +* VL15 structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct osm_vl15 { + osm_thread_state_t thread_state; + osm_vl15_state_t state; + uint32_t max_wire_smps; + cl_event_t signal; + cl_thread_t poller; + cl_qlist_t rfifo; + cl_qlist_t ufifo; + cl_spinlock_t lock; + osm_vendor_t *p_vend; + osm_log_t *p_log; + osm_stats_t *p_stats; +} osm_vl15_t; +/* +* FIELDS +* thread_state +* Tracks the thread state of the poller thread. +* +* state +* Tracks the state of the VL15 interface itself. +* +* max_wire_smps +* Maximum number of VL15 MADs allowed on the wire at one time. +* +* signal +* Event on which the poller sleeps. +* +* rfifo +* First-in First-out queue for outbound VL15 MADs for which +* a response is expected, aka the "response fifo" +* +* ufifo +* First-in First-out queue for outbound VL15 MADs for which +* no response is expected, aka the "unicast fifo". +* +* poller +* Worker thread pool that services the fifo to transmit VL15 MADs +* +* lock +* Spinlock guarding the FIFO. +* +* p_vend +* Pointer to the vendor transport object. +* +* p_log +* Pointer to the log object. +* +* p_stats +* Pointer to the OpenSM statistics block. +* +* SEE ALSO +* VL15 object +*********/ + +/****f* OpenSM: VL15/osm_vl15_construct +* NAME +* osm_vl15_construct +* +* DESCRIPTION +* This function constructs an VL15 object. +* +* SYNOPSIS +*/ +void osm_vl15_construct(IN osm_vl15_t * 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 * 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 * p_vl15, IN osm_vendor_t * p_vend, + IN osm_log_t * p_log, IN osm_stats_t * p_stats, + IN 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 * p_vl15, IN osm_madw_t * 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 * 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 * p_vl, IN osm_mad_pool_t * 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/branches/WOF2-3/ulp/opensm/user/include/opensm/st.h b/branches/WOF2-3/ulp/opensm/user/include/opensm/st.h new file mode 100644 index 00000000..b6e405d4 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/opensm/st.h @@ -0,0 +1,103 @@ +/* + * 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 +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +#define st_ptr_t uintptr_t +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/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_mtl_bind.h b/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_mtl_bind.h new file mode 100644 index 00000000..fa0b6f75 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_mtl_bind.h @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _OSM_BIND_H_ +#define _OSM_BIND_H_ + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****s* OpenSM: Vendor/osm_vendor_mgt_bind +* NAME +* osm_vendor_mgt_bind_t +* +* DESCRIPTION +* Tracks the handles returned by IB_MGT to the SMI and GSI +* Nulled on init of the vendor obj. Populated on first bind. +* +* SYNOPSIS +*/ +typedef struct _osm_vendor_mgt_bind { + boolean_t smi_init, gsi_init; + IB_MGT_mad_hndl_t smi_mads_hdl; + IB_MGT_mad_hndl_t gsi_mads_hdl; + struct _osm_mtl_bind_info *smi_p_bind; +} osm_vendor_mgt_bind_t; + +/* +* FIELDS +* smi_mads_hdl +* Handle returned by IB_MGT_get_handle to the IB_MGT_SMI +* +* gsi_mads_hdl +* Handle returned by IB_MGT_get_handle to the IB_MGT_GSI +* +* SEE ALSO +*********/ + +/****s* OpenSM: Vendor osm_mtl_bind_info_t +* NAME +* osm_mtl_bind_info_t +* +* DESCRIPTION +* Handle to the result of binding a class callbacks to IB_MGT. +* +* SYNOPSIS +*/ +typedef struct _osm_mtl_bind_info { + IB_MGT_mad_hndl_t mad_hndl; + osm_vendor_t *p_vend; + void *client_context; + VAPI_hca_hndl_t hca_hndl; + VAPI_hca_id_t hca_id; + uint8_t port_num; + osm_vend_mad_recv_callback_t rcv_callback; + osm_vend_mad_send_err_callback_t send_err_callback; + osm_mad_pool_t *p_osm_pool; +} osm_mtl_bind_info_t; + +/* +* FIELDS +* mad_hndl +* the handle returned from the registration in IB_MGT +* +* p_vend +* Pointer to the vendor object. +* +* client_context +* User's context passed during osm_bind +* +* hca_id +* HCA Id we bind to. +* +* port_num +* Port number (within the HCA) of the bound port. +* +* rcv_callback +* OSM Callback function to be called on receive of MAD. +* +* send_err_callback +* OSM Callback to be called on send error. +* +* p_osm_pool +* Points to the MAD pool used by OSM +* +* +* SEE ALSO +*********/ +ib_api_status_t +osm_mtl_send_mad(IN osm_mtl_bind_info_t * p_bind, IN osm_madw_t * const p_madw); + +END_C_DECLS +#endif // _OSM_BIND_H_ diff --git a/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_pkt_randomizer.h b/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_pkt_randomizer.h new file mode 100644 index 00000000..db32bbc3 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_pkt_randomizer.h @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osm_subn_t. + * This object represents an IBA subnet. + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_PKT_RANDOMIZER_H_ +#define _OSM_PKT_RANDOMIZER_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* OpenSM/Packet Randomizer +* NAME +* Packet Randomizer +* +* DESCRIPTION +* The Packet Randomizer object encapsulates the information needed for +* randomly dropping packets for debug. +* +* The Packet Randomizer object is not thread safe, thus callers must +* provide serialization. +* +* AUTHOR +* Yael Kalka, Mellanox +* +*********/ +/****d* OpenSM: Pkt_Randomizer/osm_pkt_randomizer_t +* NAME +* osm_pkt_randomizer_t +* +* DESCRIPTION +* Packet randomizer structure. This structure contains the various +* parameters needed by the packet randomizer. +* +* SYNOPSIS +*/ +typedef struct _osm_pkt_randomizer { + uint8_t osm_pkt_drop_rate; + uint8_t osm_pkt_num_unstable_links; + uint8_t osm_pkt_unstable_link_rate; + osm_dr_path_t *fault_dr_paths; + uint8_t num_paths_initialized; +} osm_pkt_randomizer_t; + +/* +* FIELDS +* +* osm_pkt_drop_rate +* Used by the randomizer whether to drop a packet or not. +* Taken from the global variable OSM_PKT_DROP_RATE. If not given or +* if set to zero, the randomizer will not run. +* +* osm_pkt_num_unstable_links +* The number of unstable links to be drawn. +* Taken from the global variable OSM_PKT_NUM_UNSTABLE_LINKS. default = 1. +* +* osm_pkt_unstable_link_rate +* Used by the randomizer whether to add a packet to the unstable links +* list or not. Taken from the global variable OSM_PKT_UNSTABLE_LINK_RATE. +* default = 20. +* +* fault_dr_path +* Array of osm_dr_path_t objects, that includes all the dr_paths +* that are marked as errored. +* +* num_paths_initialized +* Describes the number of paths from the fault_dr_paths array that +* have already been initialized. +* +* SEE ALSO +* Packet Randomizer object +*********/ + +/****f* OpenSM: Pkt_Randomizer/osm_pkt_randomizer_init +* NAME +* osm_pkt_randomizer_init +* +* DESCRIPTION +* The osm_pkt_randomizer_init function initializes the Packet Randomizer object. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_pkt_randomizer_init(IN OUT osm_pkt_randomizer_t ** pp_pkt_randomizer, + IN osm_log_t * p_log); +/* +* PARAMETERS +* p_pkt_randomizer +* [in] Pointer to the Packet Randomizer object to be initialized. +* +* p_log +* [in] Pointer to the log object. +* +* RETURN VALUE +* None +* +* NOTES +* +* SEE ALSO +* +*********/ + +/****f* OpenSM: Pkt_Randomizer/osm_pkt_randomizer_destroy +* NAME +* osm_pkt_randomizer_destroy +* +* DESCRIPTION +* The osm_pkt_randomizer_destroy function destroys the Packet Randomizer object. +* +* SYNOPSIS +*/ +void +osm_pkt_randomizer_destroy(IN osm_pkt_randomizer_t ** pp_pkt_randomizer, + IN osm_log_t * p_log); +/* +* PARAMETERS +* p_pkt_randomizer +* [in] Pointer to the Packet Randomizer object to be destroyed. +* +* p_log +* [in] Pointer to the log object. +* +* RETURN VALUE +* None +* +* NOTES +* +* SEE ALSO +* +*********/ + +/****f* OpenSM: Pkt_Randomizer/osm_pkt_randomizer_madw_drop +* NAME +* osm_pkt_randomizer_madw_drop +* +* DESCRIPTION +* The osm_pkt_randomizer_madw_drop is base function of the packet +* randomizer. +* It decides according to different random criteria whether or not +* the packet received should be dropped (according to its dr_path). +* This function is relevant both for mads sent by the SM and mads +* received by the SM. +* It returns TRUE if the mad should be dropped, and FALSE otherwise. +* +* SYNOPSIS +*/ +boolean_t +osm_pkt_randomizer_mad_drop(IN osm_log_t * p_log, + IN osm_pkt_randomizer_t * p_pkt_randomizer, + IN const ib_mad_t * p_mad); +/* +* PARAMETERS +* p_subn +* [in] Pointer to the Subnet object for this subnet. +* +* p_log +* [in] Pointer to the log object. +* +* p_mad +* [in] Pointer to the ib_mad_t mad to be checked. +* +* RETURN VALUE +* TRUE if the mad should be dropped. FALSE otherwise. +* +* NOTES +* +* SEE ALSO +* +*********/ + +END_C_DECLS +#endif /* _OSM_PKT_RANDOMIZER_H */ diff --git a/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_ts_useraccess.h b/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_ts_useraccess.h new file mode 100644 index 00000000..d30b8953 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/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/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_umadt.h b/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_umadt.h new file mode 100644 index 00000000..d4e240f8 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_umadt.h @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osm_mad_wrapper_t. + * This object represents the context wrapper for OpenSM MAD processing. + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_UMADT_h_ +#define _OSM_UMADT_h_ + +#include "iba/ib_types.h" +#include +#include +#include "umadt.h" +#include "ibt.h" + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS + +typedef struct _umadt_obj_t { + void *umadt_handle; + UMADT_INTERFACE uMadtInterface; + IBT_INTERFACE IbtInterface; + boolean init_done; + cl_spinlock_t register_lock; + cl_qlist_t register_list; + osm_log_t *p_log; + uint32_t timeout; + +} umadt_obj_t; +/*********/ + +/****s* OpenSM: Umadt MAD Wrapper/osm_bind_info +* NAME +* osm_bind_info +* +* DESCRIPTION +* Context needed for processing individual MADs +* +* SYNOPSIS +*/ + +typedef struct _mad_bind_info_t { + cl_list_item_t list_item; + umadt_obj_t *p_umadt_obj; + osm_mad_pool_t *p_mad_pool; + osm_vend_mad_recv_callback_t mad_recv_callback; + void *client_context; + cl_thread_t recv_processor_thread; + cl_spinlock_t trans_ctxt_lock; + cl_qlist_t trans_ctxt_list; + cl_timer_t timeout_timer; + cl_spinlock_t timeout_list_lock; + cl_qlist_t timeout_list; + RegisterClassStruct umadt_reg_class; + MADT_HANDLE umadt_handle; /* Umadt type */ + +} mad_bind_info_t; + +typedef struct _trans_context_t { + cl_list_item_t list_item; + uint64_t trans_id; + uint64_t sent_time; /* micro secs */ + void *context; +} trans_context_t; + +/* +* FIELDS +* list_item +* List linkage for pools and lists. MUST BE FIRST MEMBER! +* +* p_mad_pool +* Pointer to the MAD pool to be used by mads with this bind handle. +* +* mad_recv_callback +* Callback function called by the mad receive processor. +* +* client_context +* context to be passed to the receive callback. +* +* recv_processor_thread +* Thread structure for the receive processor thread. +* +* umadt_reg_class +* Umadt register class struct used to register with Umadt. +* +* umadt_handle +* Umadt returns this handle from a registration call. The transport layer +* uses this handle to talk to Umadt. +* +* SEE ALSO +*********/ + +END_C_DECLS +#endif /*_OSM_UMADT_h_ */ diff --git a/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor.h b/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor.h new file mode 100644 index 00000000..b7636c46 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor.h @@ -0,0 +1,71 @@ +/* + * 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: + * Include file used by OpenSM to pull in the correct vendor file. + */ + +/* + this is the generic include file which includes + the proper vendor specific file +*/ +#include + +#if defined( OSM_VENDOR_INTF_TEST ) +#include +#elif defined( OSM_VENDOR_INTF_UMADT ) +#include +#elif defined( OSM_VENDOR_INTF_MTL ) +/* HACK - I do not know how to prevent complib from loading kernel H files */ +#undef __init +#include +#elif defined( OSM_VENDOR_INTF_TS ) +#undef __init +#include +#elif defined( OSM_VENDOR_INTF_ANAFA ) +#undef __init +#include +#elif defined( OSM_VENDOR_INTF_SIM ) +#undef __init +#include +#elif defined( OSM_VENDOR_INTF_OPENIB ) +#include +#elif defined( OSM_VENDOR_INTF_AL ) +#include +#else +#error No MAD Interface selected! +#error Choose an interface in osm_config.h +#endif diff --git a/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_al.h b/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_al.h new file mode 100644 index 00000000..e40664a1 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_al.h @@ -0,0 +1,350 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osm_mad_wrapper_t. + * This object represents the context wrapper for OpenSM MAD processing. + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_VENDOR_AL_H_ +#define _OSM_VENDOR_AL_H_ + +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* OpenSM/Vendor AL +* NAME +* Vendor AL +* +* DESCRIPTION +* +* The Vendor AL object is thread safe. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* Enable various hacks to compensate for bugs in external code... +* +* +* AUTHOR +* +* +*********/ +/****h* OpenSM/Vendor Access Layer (AL) +* NAME +* Vendor AL +* +* DESCRIPTION +* This file is the vendor specific file for the AL Infiniband API. +* +* AUTHOR +* Steve King, Intel +* +*********/ +#define OSM_AL_SQ_SGE 256 +#define OSM_AL_RQ_SGE 256 +#define OSM_DEFAULT_RETRY_COUNT 3 +/* AL supports RMPP */ +#define VENDOR_RMPP_SUPPORT 1 +/****s* OpenSM: Vendor AL/osm_ca_info_t +* NAME +* osm_ca_info_t +* +* DESCRIPTION +* Structure containing information about local Channle Adapters. +* +* SYNOPSIS +*/ +typedef struct _osm_ca_info { + ib_net64_t guid; + size_t attr_size; + ib_ca_attr_t *p_attr; + +} osm_ca_info_t; +/* +* FIELDS +* guid +* Node GUID of the local CA. +* +* attr_size +* Size of the CA attributes for this CA. +* +* p_attr +* Pointer to dynamicly allocated CA Attribute structure. +* +* SEE ALSO +*********/ + +/****f* OpenSM: CA Info/osm_ca_info_get_num_ports +* NAME +* osm_ca_info_get_num_ports +* +* DESCRIPTION +* Returns the number of ports owned by this CA. +* +* SYNOPSIS +*/ +static inline uint8_t +osm_ca_info_get_num_ports(IN const osm_ca_info_t * const p_ca_info) +{ + return (p_ca_info->p_attr->num_ports); +} + +/* +* PARAMETERS +* p_ca_info +* [in] Pointer to a CA Info object. +* +* RETURN VALUE +* Returns the number of ports owned by this CA. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: CA Info/osm_ca_info_get_port_guid +* NAME +* osm_ca_info_get_port_guid +* +* DESCRIPTION +* Returns the port GUID of the specified port owned by this CA. +* +* SYNOPSIS +*/ +static inline ib_net64_t +osm_ca_info_get_port_guid(IN const osm_ca_info_t * const p_ca_info, + IN const uint8_t index) +{ + return (p_ca_info->p_attr->p_port_attr[index].port_guid); +} + +/* +* PARAMETERS +* p_ca_info +* [in] Pointer to a CA Info object. +* +* index +* [in] Port "index" for which to retrieve the port GUID. +* The index is the offset into the ca's internal array +* of port attributes. +* +* RETURN VALUE +* Returns the port GUID of the specified port owned by this CA. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: CA Info/osm_ca_info_get_port_num +* NAME +* osm_ca_info_get_port_num +* +* DESCRIPTION +* Returns the port number of the specified port owned by this CA. +* Port numbers start with 1 for HCA's. +* +* SYNOPSIS +*/ +static inline uint8_t +osm_ca_info_get_port_num(IN const osm_ca_info_t * const p_ca_info, + IN const uint8_t index) +{ + return (p_ca_info->p_attr->p_port_attr[index].port_num); +} + +/* +* PARAMETERS +* p_ca_info +* [in] Pointer to a CA Info object. +* +* index +* [in] Port "index" for which to retrieve the port GUID. +* The index is the offset into the ca's internal array +* of port attributes. +* +* RETURN VALUE +* Returns the port GUID of the specified port owned by this CA. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: CA Info/osm_ca_info_get_ca_guid +* NAME +* osm_ca_info_get_ca_guid +* +* DESCRIPTION +* Returns the GUID of the specified CA. +* +* SYNOPSIS +*/ +static inline ib_net64_t +osm_ca_info_get_ca_guid(IN const osm_ca_info_t * const p_ca_info) +{ + return (p_ca_info->p_attr->ca_guid); +} + +/* +* PARAMETERS +* p_ca_info +* [in] Pointer to a CA Info object. +* +* RETURN VALUE +* Returns the GUID of the specified CA. +* +* NOTES +* +* SEE ALSO +*********/ + +/****s* OpenSM: Vendor AL/osm_bind_handle_t +* NAME +* osm_bind_handle_t +* +* DESCRIPTION +* handle returned by the vendor transport bind call. +* +* SYNOPSIS +*/ +typedef struct _osm_vendor +{ + ib_al_handle_t h_al; + osm_log_t *p_log; + uint32_t ca_count; + osm_ca_info_t *p_ca_info; + uint32_t timeout; + ib_ca_handle_t h_ca; + ib_pd_handle_t h_pd; + +} osm_vendor_t; +/* +* FIELDS +* h_al +* Handle returned by AL open call (ib_open_al). +* +* p_log +* Pointer to the log object. +* +* ca_count +* Number of CA's in the array pointed to by p_ca_info. +* +* p_ca_info +* Pointer to dynamically allocated array of CA info objects. +* +* h_pool +* MAD Pool handle returned by ib_create_mad_pool at init time. +* +* timeout +* Transaction timeout time in milliseconds. +* +* SEE ALSO +*********/ + +#define OSM_BIND_INVALID_HANDLE 0 + +/****s* OpenSM: Vendor AL/osm_bind_handle_t +* NAME +* osm_bind_handle_t +* +* DESCRIPTION +* handle returned by the vendor transport bind call. +* +* SYNOPSIS +*/ +typedef void *osm_bind_handle_t; +/***********/ + +/****s* OpenSM/osm_vend_wrap_t +* NAME +* AL Vendor MAD Wrapper +* +* DESCRIPTION +* AL specific MAD wrapper. AL transport layer uses this for +* housekeeping. +* +* SYNOPSIS +*********/ +typedef struct _osm_vend_wrap_t +{ + uint32_t size; + osm_bind_handle_t h_bind; + ib_mad_element_t *p_elem; + ib_av_handle_t h_av; + void *p_resp_madw; + +} osm_vend_wrap_t; +/* +* FIELDS +* size +* Size of the allocated MAD +* +* h_bind +* Bind handle used on this transaction +* +* p_elem +* Pointer to the mad element structure associated with +* this mad. +* +* h_av +* Address vector handle used for this transaction. +* +* p_resp_madw +* Pointer to the mad wrapper structure used to hold the pending +* reponse to the mad, if any. If a response is expected, the +* wrapper for the reponse is allocated during the send call. +* +* SEE ALSO +*********/ + +END_C_DECLS +#endif /* _OSM_VENDOR_AL_H_ */ diff --git a/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_api.h b/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_api.h new file mode 100644 index 00000000..9c6a4106 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_api.h @@ -0,0 +1,487 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Specification of the OpenSM transport API. This API is OpenSM's view + * of the Infiniband transport. + */ + +#ifndef _OSM_VENDOR_API_H_ +#define _OSM_VENDOR_API_H_ + +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****s* OpenSM Vendor API/osm_vend_mad_recv_callback_t +* NAME +* osm_vend_mad_recv_callback_t +* +* DESCRIPTION +* Function prototype for the vendor MAD receive callback. +* The vendor layer calls this function for MAD receives. +* +* SYNOPSIS +*/ +typedef void (*osm_vend_mad_recv_callback_t) (IN osm_madw_t * p_madw, + IN void *bind_context, + IN osm_madw_t * p_req_madw); +/* +* PARAMETERS +* p_madw +* [in] The received MAD wrapper. +* +* bind_context +* [in] User context supplied during the bind call. +* +* p_req_madw +* [in] Pointer to the request mad wrapper that generated this response. +* If the inbound MAD is not a response, this field is NULL. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****s* OpenSM Vendor API/osm_vend_mad_send_err_callback_t +* NAME +* osm_vend_mad_send_err_callback_t +* +* DESCRIPTION +* Function prototype for the vendor send failure callback. +* The vendor layer calls this function when MADs expecting +* a response are completed in error, most likely due to a +* timeout. +* +* SYNOPSIS +*/ +typedef void (*osm_vend_mad_send_err_callback_t) (IN void *bind_context, + IN osm_madw_t * p_madw); +/* +* PARAMETERS +* bind_context +* [in] User context supplied during the bind call. +* +* p_madw +* [in] Pointer to the request mad that failed. +* +* RETURN VALUES +* None. +* +* NOTES +* The vendor layer does not call this function (or any other) +* for MADs that were not expecting a response. +* +* SEE ALSO +*********/ + +/****f* OpenSM Vendor API/osm_vendor_new +* NAME +* osm_vendor_new +* +* DESCRIPTION +* Allocates and initializes a new osm_vendor_t object. +* OpenSM calls this function before any other in the vendor API. +* This object is passed as a parameter to all other vendor functions. +* +* SYNOPSIS +*/ +osm_vendor_t *osm_vendor_new(IN osm_log_t * const p_log, + IN const uint32_t timeout); +/* +* PARAMETERS +* p_log +* [in] Pointer to the log object to use. +* +* timeout +* [in] transaction timeout +* +* RETURN VALUES +* Returns a pointer to the vendor object. +* +* NOTES +* +* SEE ALSO +*********/ + +/****s* OpenSM Vendor API/osm_vendor_delete +* NAME +* osm_vendor_delete +* +* DESCRIPTION +* Dealocate the vendor object. +* +* SYNOPSIS +*/ +void osm_vendor_delete(IN osm_vendor_t ** const pp_vend); +/* +* PARAMETERS +* pp_vend +* [in/out] pointer to pointer to vendor objcet to be deleted +* +* RETURN VALUES +* None +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM Vendor API/osm_vendor_get_all_port_attr +* NAME +* osm_vendor_get_all_port_attr +* +* 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 immediately +* 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/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_ibumad.h b/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_ibumad.h new file mode 100644 index 00000000..dcf0eeb3 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_ibumad.h @@ -0,0 +1,182 @@ +/* + * 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_VENDOR_UMAD_H_ +#define _OSM_VENDOR_UMAD_H_ + +#include +#include +#include +#include + +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* OpenSM/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 +#define OSM_UMAD_MAX_AGENTS 32 + +/****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[OSM_UMAD_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/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mlx.h b/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mlx.h new file mode 100644 index 00000000..2b105acd --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mlx.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2007,2009 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _OSMV_H_ +#define _OSMV_H_ + +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/* + Forward reference +*/ +struct _osm_pkt_randomizer; + +/* The structure behind the OSM Vendor handle */ + +typedef struct _osm_vendor { + + /* for holding common transport info - useful at ibmgt transport */ + void *p_transport_info; + + osm_log_t *p_log; + + /* Uniform timeout for every ACK/single MAD */ + uint32_t resp_timeout; + + /* Uniform timeout for every rmpp transaction */ + uint32_t ttime_timeout; + + /* All the bind handles associated with the vendor */ + cl_qlist_t bind_handles; + + /* run randomizer flag */ + boolean_t run_randomizer; + + /* Packet Randomizer object */ + struct _osm_pkt_randomizer *p_pkt_randomizer; + +} osm_vendor_t; + +/* Repeating the definitions in osm_vendor_api.h */ + +typedef void *osm_bind_handle_t; + +typedef struct _osm_vend_wrap { + ib_mad_t *p_mad; +} osm_vend_wrap_t; + +#ifndef OSM_BIND_INVALID_HANDLE +#define OSM_BIND_INVALID_HANDLE NULL +#endif + +/* The maximum number of retransmissions of the same MAD */ +#define OSM_DEFAULT_RETRY_COUNT 3 + +END_C_DECLS +#endif diff --git a/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mlx_defs.h b/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mlx_defs.h new file mode 100644 index 00000000..7bb93432 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mlx_defs.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005,2009 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _OSMV_DEFS_H_ +#define _OSMV_DEFS_H_ + +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/* The maximum number of outstanding MADs an RMPP sender can transmit */ +#define OSMV_RMPP_RECV_WIN 16 +/* 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/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mlx_dispatcher.h b/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mlx_dispatcher.h new file mode 100644 index 00000000..23a24207 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/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/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mlx_hca.h b/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mlx_hca.h new file mode 100644 index 00000000..f3477e6f --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mlx_hca.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _OSMV_HCA_H_ +#define _OSMV_HCA_H_ + +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +#if defined( OSM_VENDOR_INTF_TS_NO_VAPI ) || defined( OSM_VENDOR_INTF_SIM ) +#define VAPI_hca_hndl_t uint32_t +#define VAPI_hca_id_t char* +#endif +ib_api_status_t +osm_vendor_get_guid_ca_and_port(IN osm_vendor_t const *p_vend, + IN ib_net64_t const guid, + OUT uint32_t * p_hca_hndl, + OUT char *p_hca_id, + OUT uint8_t * p_hca_idx, + OUT uint32_t * p_port_num); + +END_C_DECLS +#endif /* _OSMV_HCA_H_ */ diff --git a/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mlx_inout.h b/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mlx_inout.h new file mode 100644 index 00000000..af06e2f0 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mlx_inout.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _OSMV_INOUT_H_ +#define _OSMV_INOUT_H_ + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +#ifdef IN +#undef IN +#endif +#ifdef OUT +#undef OUT +#endif +#ifndef OSM_VENDOR_INTF_ANAFA +#ifndef OSM_VENDOR_INTF_TS_NO_VAPI +#ifndef OSM_VENDOR_INTF_SIM +#include +#endif +#endif +#endif +#ifndef IN +#define IN +#endif +#ifndef OUT +#define OUT +#endif +#ifndef OSM_VENDOR_INTF_TS_NO_VAPI +#ifndef OSM_VENDOR_INTF_ANAFA +#ifndef OSM_VENDOR_INTF_SIM +#include +#include +#endif +#endif +#endif +END_C_DECLS +#endif /* _OSMV_INOUT_H_ */ diff --git a/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mlx_rmpp_ctx.h b/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mlx_rmpp_ctx.h new file mode 100644 index 00000000..dac37492 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mlx_rmpp_ctx.h @@ -0,0 +1,289 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _OSMV_RMPP_CTX_H +#define _OSMV_RMPP_CTX_H + +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS + +typedef struct _osmv_rmpp_send_ctx { + + uint8_t status; + + uint32_t window_first; + uint32_t window_last; + + uint32_t mad_sz; + boolean_t is_sa_mad; + + cl_event_t event; + + /* Segmentation engine */ + osmv_rmpp_sar_t sar; + osm_log_t *p_log; + +} osmv_rmpp_send_ctx_t; + +typedef struct _osmv_rmpp_recv_ctx { + + boolean_t is_sa_mad; + + uint32_t expected_seg; + + /* Reassembly buffer */ + cl_qlist_t *p_rbuf; + + /* Reassembly engine */ + osmv_rmpp_sar_t sar; + osm_log_t *p_log; + +} osmv_rmpp_recv_ctx_t; + +/* + * NAME + * osmv_rmpp_send_ctx_init + * + * DESCRIPTION + * c'tor for rmpp_send_ctx obj + * + * SEE ALSO + * + */ +ib_api_status_t +osmv_rmpp_send_ctx_init(osmv_rmpp_send_ctx_t * p_ctx, void *arbt_mad, + uint32_t mad_sz, osm_log_t * p_log); + +/* + * NAME + * osmv_rmpp_send_ctx_done + * + * DESCRIPTION + * d'tor for rmpp_send_ctx obj + * + * SEE ALSO + * + */ +void osmv_rmpp_send_ctx_done(IN osmv_rmpp_send_ctx_t * ctx); + +/* + * NAME + * osmv_rmpp_send_ctx_get_wf + * + * DESCRIPTION + * returns number of first segment in current window + * SEE ALSO + * + */ +static inline uint32_t +osmv_rmpp_send_ctx_get_wf(IN const osmv_rmpp_send_ctx_t * p_ctx) +{ + CL_ASSERT(p_ctx); + return p_ctx->window_first; +} + +/* + * NAME + * osmv_rmpp_send_ctx_set_wf + * + * DESCRIPTION + * sets number of first segment in current window + * SEE ALSO + * + */ +static inline void +osmv_rmpp_send_ctx_set_wf(IN osmv_rmpp_send_ctx_t * p_ctx, IN uint32_t val) +{ + CL_ASSERT(p_ctx); + p_ctx->window_first = val; +} + +/* + * NAME + * osmv_rmpp_send_ctx_get_wl + * + * DESCRIPTION + * returns number of last segment in current window + * SEE ALSO + * + */ +static inline uint32_t +osmv_rmpp_send_ctx_get_wl(IN const osmv_rmpp_send_ctx_t * p_send_ctx) +{ + CL_ASSERT(p_send_ctx); + return p_send_ctx->window_last; +} + +/* + * NAME + * osmv_rmpp_send_ctx_set_wl + * + * DESCRIPTION + * sets number of last segment in current window + * SEE ALSO + * + */ +static inline void +osmv_rmpp_send_ctx_set_wl(IN osmv_rmpp_send_ctx_t * p_ctx, IN uint32_t val) +{ + CL_ASSERT(p_ctx); + p_ctx->window_last = val; +} + +/* + * NAME + * osmv_rmpp_send_ctx_get_num_segs + * + * DESCRIPTION + * returns the total number of mad segments to send + * SEE ALSO + * + */ +uint32_t osmv_rmpp_send_ctx_get_num_segs(IN osmv_rmpp_send_ctx_t * p_send_ctx); + +/* + * NAME + * osmv_rmpp_send_ctx_get_seg + * + * DESCRIPTION + * Retrieves the mad segment by seg number (including setting the mad relevant bits & hdrs) + * SEE ALSO + * + */ +ib_api_status_t +osmv_rmpp_send_ctx_get_seg(IN osmv_rmpp_send_ctx_t * p_send_ctx, + IN uint32_t seg_idx, IN uint32_t resp_timeout, + OUT void *p_mad); + +/* + * NAME + * osmv_rmpp_recv_ctx_init + * + * DESCRIPTION + * c'tor for rmpp_recv_ctx obj + * SEE ALSO + * + */ +ib_api_status_t +osmv_rmpp_recv_ctx_init(osmv_rmpp_recv_ctx_t * p_ctx, osm_log_t * p_log); + +/* + * NAME + * osmv_rmpp_recv_ctx_done + * + * DESCRIPTION + * d'tor for rmpp_recv_ctx obj + * SEE ALSO + * + */ +void osmv_rmpp_recv_ctx_done(IN osmv_rmpp_recv_ctx_t * p_ctx); + +/* + * NAME + * osmv_rmpp_recv_ctx_get_es + * + * DESCRIPTION + * retrunes index of expected segement in the curr window + * + */ +static inline uint32_t +osmv_rmpp_recv_ctx_get_es(IN const osmv_rmpp_recv_ctx_t * p_recv_ctx) +{ + CL_ASSERT(p_recv_ctx); + return p_recv_ctx->expected_seg; +} + +/* + * NAME + * osmv_rmpp_recv_ctx_set_es + * + * DESCRIPTION + * sets index of expected segement in the curr window + * + */ +static inline void +osmv_rmpp_recv_ctx_set_es(IN osmv_rmpp_recv_ctx_t * p_recv_ctx, IN uint32_t val) +{ + CL_ASSERT(p_recv_ctx); + p_recv_ctx->expected_seg = val; +} + +/* + * NAME + * osmv_rmpp_recv_ctx_store_madw_seg + * + * DESCRIPTION + * stores rmpp mad in the list + * + */ +ib_api_status_t +osmv_rmpp_recv_ctx_store_mad_seg(IN osmv_rmpp_recv_ctx_t * p_recv_ctx, + IN void *p_mad); + +uint32_t +osmv_rmpp_recv_ctx_get_cur_byte_num(IN osmv_rmpp_recv_ctx_t * p_recv_ctx); + +uint32_t +osmv_rmpp_recv_ctx_get_byte_num_from_first(IN osmv_rmpp_recv_ctx_t * + p_recv_ctx); + +uint32_t +osmv_rmpp_recv_ctx_get_byte_num_from_last(IN osmv_rmpp_recv_ctx_t * p_recv_ctx); + +/* + * NAME + * osmv_rmpp_recv_ctx_reassemble_arbt_mad + * + * DESCRIPTION + * reassembles all rmpp buffs to one big arbitrary mad + */ +ib_api_status_t +osmv_rmpp_recv_ctx_reassemble_arbt_mad(IN osmv_rmpp_recv_ctx_t * p_recv_ctx, + IN uint32_t size, IN void *p_arbt_mad); + +END_C_DECLS +#endif diff --git a/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mlx_sar.h b/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mlx_sar.h new file mode 100644 index 00000000..7d82cb4f --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mlx_sar.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _OSMV_SAR_H_ +#define _OSMV_SAR_H_ + +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS + +typedef struct _osmv_rmpp_sar { + void *p_arbt_mad; + uint32_t data_len; /* total data len in all the mads */ + /* these data members contain only constants */ + uint32_t hdr_sz; + uint32_t data_sz; /*typical data sz for this kind of mad (sa or regular */ + +} osmv_rmpp_sar_t; + +/* + * NAME + * osmv_rmpp_sar_alloc + * + * DESCRIPTION + * c'tor for rmpp_sar object + * + * SEE ALSO + * + */ +ib_api_status_t +osmv_rmpp_sar_init(osmv_rmpp_sar_t * p_sar, void *p_arbt_mad, + uint32_t mad_size, boolean_t is_sa_mad); + +/* + * NAME + * osmv_rmpp_sar_dealloc + * + * DESCRIPTION + * d'tor for rmpp_sar object + * + * SEE ALSO + * + */ +void osmv_rmpp_sar_done(osmv_rmpp_sar_t * p_sar); + +/* + * NAME + * osmv_rmpp_sar_get_mad_seg + * + * DESCRIPTION + * segments the original mad buffer . returnes a mad with the data of the i-th segment + * + * SEE ALSO + * + */ +ib_api_status_t +osmv_rmpp_sar_get_mad_seg(osmv_rmpp_sar_t * p_sar, uint32_t seg_idx, + void *p_buf); + +/* + * NAME + * osmv_rmpp_sar_reassemble_arbt_mad + * + * DESCRIPTION + * gets a qlist of mads and reassmbles to one big mad buffer + * ALSO - deallocates the mad list + * + * SEE ALSO + * + */ +ib_api_status_t +osmv_rmpp_sar_reassemble_arbt_mad(osmv_rmpp_sar_t * p_sar, cl_qlist_t * p_bufs); + +END_C_DECLS +#endif /* _OSMV_SAR_H_ */ diff --git a/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mlx_sender.h b/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mlx_sender.h new file mode 100644 index 00000000..e8a97d6c --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mlx_sender.h @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _OSMV_RMPP_SENDER_H_ +#define _OSMV_RMPP_SENDER_H_ + +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****d* OSM Vendor/osmv_simple_send_madw + * NAME + * osmv_simple_send_madw + * + * DESCRIPTION + * Send a single MAD (256 bytes). + * + * If this MAD requires a response, set the timeout event. + * The function call returns when the MAD's send completion is received. + * + */ +ib_api_status_t +osmv_simple_send_madw(IN osm_bind_handle_t h_bind, + IN osm_madw_t * const p_madw, + IN osmv_txn_ctx_t * p_txn, IN boolean_t is_retry); + +/****d* OSM Vendor/osmv_rmpp_send_madw + * NAME + * osmv_rmpp_send_madw + * + * DESCRIPTION + * Send a single MAD wrapper (of arbitrary length). + * Follow the RMPP semantics + * (segmentation, send window, timeouts etc). + * + * The function call returns either when the whole MAD + * has been acknowledged, or upon error. + */ +ib_api_status_t +osmv_rmpp_send_madw(IN osm_bind_handle_t h_bind, + IN osm_madw_t * const p_madw, + IN osmv_txn_ctx_t * p_txn, IN boolean_t is_rmpp_ds); + +/* + * NAME osmv_rmpp_send_ack + * + * DESCRIPTION + */ + +ib_api_status_t +osmv_rmpp_send_ack(IN osm_bind_handle_t h_bind, + IN const ib_mad_t * p_req_mad, + IN uint32_t seg_num, + IN uint32_t nwl, IN const osm_mad_addr_t * p_mad_addr); + +/* + * NAME osmv_rmpp_send_nak + * + * DESCRIPTION Send the RMPP ABORT or STOP packet + */ + +ib_api_status_t +osmv_rmpp_send_nak(IN osm_bind_handle_t h_bind, + IN const ib_mad_t * p_req_mad, + IN const osm_mad_addr_t * p_mad_addr, + IN uint8_t nak_type, IN uint8_t status); + +/* + * NAME osmv_rmpp_snd_error + * + * DESCRIPTION Mark an error status and signal the sender thread to handle it + */ + +static inline void +osmv_rmpp_snd_error(IN osmv_rmpp_send_ctx_t * p_send_ctx, + IN ib_api_status_t status) +{ + p_send_ctx->status = status; + + /* Release the thread waiting on send() + * It will release the transaction's context + */ + cl_event_signal(&p_send_ctx->event); +} + +END_C_DECLS +#endif /* _OSMV_RMPP_SENDER_H_ */ diff --git a/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mlx_svc.h b/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mlx_svc.h new file mode 100644 index 00000000..ac19294b --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mlx_svc.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. + * + */ + +#ifndef _OSMV_SVC_H_ +#define _OSMV_SVC_H_ + +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +inline static 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/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mlx_transport.h b/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mlx_transport.h new file mode 100644 index 00000000..94d2a49e --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mlx_transport.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/** + * FILE osmv_transport.h + * AUTHOR Edward Bortnikov + * + * DESCRIPTION + * The lower-level MAD transport interface implementation + * that allows sending a single MAD/receiving a callback + * when a single MAD is received. +*/ + +#ifndef _OSMV_TRANSPORT_H_ +#define _OSMV_TRANSPORT_H_ + +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/* + * NAME + * osmv_transport_init + * + * DESCRIPTION + * Setup the MAD transport infrastructure (filters, callbacks etc). + */ +#define VENDOR_HCA_MAXNAMES 32 +ib_api_status_t +osmv_transport_init(IN osm_bind_info_t * p_info, + IN char hca_id[VENDOR_HCA_MAXNAMES], + IN uint8_t hca_idx, IN osmv_bind_obj_t * p_bo); + +/* + * NAME + * osmv_transport_send_mad + * + * DESCRIPTION + * Send a single MAD (256 byte) + */ +ib_api_status_t +osmv_transport_mad_send(IN const osm_bind_handle_t h_bind, + IN void *p_mad, IN const osm_mad_addr_t * p_mad_addr); + +/* + * NAME + * osmv_transport_done + * + * DESCRIPTION + * deallocator of transportation infrastructure + */ +void osmv_transport_done(IN const osm_bind_handle_t h_bind); + +END_C_DECLS +#endif /* _OSMV_TRANSPORT_H_ */ diff --git a/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mlx_transport_anafa.h b/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mlx_transport_anafa.h new file mode 100644 index 00000000..891aae41 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/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/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mlx_txn.h b/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mlx_txn.h new file mode 100644 index 00000000..1115dc4f --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mlx_txn.h @@ -0,0 +1,380 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _OSMV_TXN_H_ +#define _OSMV_TXN_H_ + +#include +#include + +#include +#include +#include + +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS + +typedef enum _osmv_txn_rmpp_state { + + OSMV_TXN_RMPP_NONE = 0, /* Not part of RMPP transaction */ + + OSMV_TXN_RMPP_SENDER, + OSMV_TXN_RMPP_RECEIVER +} osmv_txn_rmpp_state_t; + +typedef struct _osmv_rmpp_txfr { + + osmv_txn_rmpp_state_t rmpp_state; + boolean_t is_rmpp_init_by_peer; + osmv_rmpp_send_ctx_t *p_rmpp_send_ctx; + osmv_rmpp_recv_ctx_t *p_rmpp_recv_ctx; + +} osmv_rmpp_txfr_t; + +typedef struct _osmv_txn_ctx { + + /* The original Transaction ID */ + uint64_t tid; + /* The key by which the Transaction is stored */ + uint64_t key; + + /* RMPP Send/Receive contexts, if applicable */ + osmv_rmpp_txfr_t rmpp_txfr; + + /* A MAD that was sent during the transaction (request or response) */ + osm_madw_t *p_madw; + + /* Reference to a log to enable tracing */ + osm_log_t *p_log; + +} osmv_txn_ctx_t; + +typedef struct _osmv_txn_mgr { + + /* Container of all the transactions */ + cl_qmap_t *p_txn_map; + + /* The timeouts DB */ + cl_event_wheel_t *p_event_wheel; + + /* Reference to a log to enable tracing */ + osm_log_t *p_log; + +} osmv_txn_mgr_t; + +/* * * * * * * osmv_txn_ctx_t functions * * * * * * * * */ + +/* + * NAME + * osmv_txn_init + * + * DESCRIPTION + * allocs & inits the osmv_txn_ctx obj and insert it into the db + * SEE ALSO + * + */ +ib_api_status_t +osmv_txn_init(IN osm_bind_handle_t h_bind, + IN uint64_t tid, IN uint64_t key, OUT osmv_txn_ctx_t ** pp_txn); + +/* + * NAME + * osmv_rmpp_txfr_init_sender + * + * DESCRIPTION + * init the rmpp send ctx in the transaction + * + * SEE ALSO + * + */ +ib_api_status_t +osmv_txn_init_rmpp_sender(IN osm_bind_handle_t h_bind, + IN osmv_txn_ctx_t * p_txn, IN osm_madw_t * p_madw); + +/* + * NAME + * osmv_rmpp_txfr_init_receiver + * + * DESCRIPTION + * init the rmpp recv ctx in the transaction + * + * SEE ALSO + * + */ +ib_api_status_t +osmv_txn_init_rmpp_receiver(IN osm_bind_handle_t h_bind, + IN osmv_txn_ctx_t * p_txn, + IN boolean_t is_init_by_peer); + +/* + * NAME + * osmv_txn_done + * + * DESCRIPTION + * destroys txn object and removes it from the db + * + * SEE ALSO + * + */ +void +osmv_txn_done(IN osm_bind_handle_t h_bind, + IN uint64_t key, IN boolean_t is_in_cb); +/* + * NAME + * osmv_txn_get_tid + * + * DESCRIPTION + * returns tid of the transaction + * SEE ALSO + * + */ +static inline uint64_t osmv_txn_get_tid(IN osmv_txn_ctx_t * p_txn) +{ + CL_ASSERT(NULL != p_txn); + return p_txn->tid; +} + +/* + * NAME + * osmv_txn_get_key + * + * DESCRIPTION + * returns key of the transaction + * SEE ALSO + * + */ + +static inline uint64_t osmv_txn_get_key(IN osmv_txn_ctx_t * p_txn) +{ + CL_ASSERT(NULL != p_txn); + return p_txn->key; +} + +/* + * NAME + * osmv_txn_is_rmpp_init_by_peer + * + * DESCRIPTION + * returns whether the rmpp txfr was init by the peer + * + * SEE ALSO + * + */ +static inline boolean_t osmv_txn_is_rmpp_init_by_peer(IN osmv_txn_ctx_t * p_txn) +{ + CL_ASSERT(NULL != p_txn); + return p_txn->rmpp_txfr.is_rmpp_init_by_peer; +} + +/* + * NAME + * osmv_txn_get_rmpp_send_ctx + * + * DESCRIPTION + * returns osmv_rmpp_send_ctx obj + * SEE ALSO + * + */ +static inline osmv_rmpp_send_ctx_t *osmv_txn_get_rmpp_send_ctx(IN osmv_txn_ctx_t + * p_txn) +{ + CL_ASSERT(NULL != p_txn); + return p_txn->rmpp_txfr.p_rmpp_send_ctx; +} + +/* + * NAME + * osmv_txn_get_rmpp_recv_ctx + * + * DESCRIPTION + * returns osmv_rmpp_recv_ctx obj + * SEE ALSO + * + */ +static inline osmv_rmpp_recv_ctx_t *osmv_txn_get_rmpp_recv_ctx(IN osmv_txn_ctx_t + * p_txn) +{ + CL_ASSERT(NULL != p_txn); + return p_txn->rmpp_txfr.p_rmpp_recv_ctx; +} + +/* + * NAME + * osmv_txn_get_rmpp_state + * + * DESCRIPTION + * returns the rmpp role of the transactino ( send/ recv) + * SEE ALSO + * + */ +static inline osmv_txn_rmpp_state_t +osmv_txn_get_rmpp_state(IN osmv_txn_ctx_t * p_txn) +{ + CL_ASSERT(NULL != p_txn); + return p_txn->rmpp_txfr.rmpp_state; +} + +/* + * NAME + * osmv_txn_set_rmpp_state + * + * DESCRIPTION + * sets the rmpp role of the transaction (send/ recv) + * SEE ALSO + * + */ +static inline void +osmv_txn_set_rmpp_state(IN osmv_txn_ctx_t * p_txn, + IN osmv_txn_rmpp_state_t state) +{ + CL_ASSERT(NULL != p_txn); + p_txn->rmpp_txfr.rmpp_state = state; +} + +/* + * NAME + * osmv_txn_get_madw + * + * DESCRIPTION + * returns the requester madw + * SEE ALSO + * + */ +static inline osm_madw_t *osmv_txn_get_madw(IN osmv_txn_ctx_t * p_txn) +{ + CL_ASSERT(NULL != p_txn); + return p_txn->p_madw; +} + +/* + * NAME + * osmv_txn_set_madw + * + * DESCRIPTION + * sets the requester madw + * SEE ALSO + * + */ +static inline void +osmv_txn_set_madw(IN osmv_txn_ctx_t * p_txn, IN osm_madw_t * p_madw) +{ + CL_ASSERT(NULL != p_txn); + p_txn->p_madw = p_madw; +} + +/* + * NAME + * osmv_txn_set_timeout_ev + * + * DESCRIPTION + * + * SEE ALSO + * + */ +ib_api_status_t +osmv_txn_set_timeout_ev(IN osm_bind_handle_t h_bind, + IN uint64_t key, IN uint64_t msec); +/* + * NAME + * osmv_txn_remove_timeout_ev + * + * DESCRIPTION + + * SEE ALSO + * + */ +void osmv_txn_remove_timeout_ev(IN osm_bind_handle_t h_bind, IN uint64_t key); +/* + * NAME + * osmv_txn_lookup + * + * DESCRIPTION + * get a transaction by its key + * + * SEE ALSO + * + */ +ib_api_status_t +osmv_txn_lookup(IN osm_bind_handle_t h_bind, + IN uint64_t key, OUT osmv_txn_ctx_t ** pp_txn); + +void osmv_txn_abort_rmpp_txns(IN osm_bind_handle_t h_bind); + +/* * * * * * * * * * * * */ +/* + * NAME + * osmv_txnmgr_init + * + * DESCRIPTION + * c'tor for txn mgr obj + * SEE ALSO + * + */ +ib_api_status_t +osmv_txnmgr_init(IN osmv_txn_mgr_t * p_tx_mgr, + IN osm_log_t * p_log, IN cl_spinlock_t * p_lock); + +/* + * NAME + * osmv_txnmgr_done + * + * DESCRIPTION + * c'tor for txn mgr obj + * SEE ALSO + * + */ +void osmv_txnmgr_done(IN osm_bind_handle_t h_bind); + +void osmv_txn_lock(IN osm_bind_handle_t h_bind); +void osmv_txn_unlock(IN osm_bind_handle_t h_bind); + +inline static uint64_t osmv_txn_uniq_key(IN uint64_t tid) +{ + uint64_t pid = getpid(); + + return ((pid << 32) | (tid & 0xFFFFFFFF)); +} + +END_C_DECLS +#endif /* _OSMV_TXN_H_ */ diff --git a/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mtl.h b/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mtl.h new file mode 100644 index 00000000..55f5e9e4 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mtl.h @@ -0,0 +1,348 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Definition of interface for the MTL Vendor + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_VENDOR_MTL_H_ +#define _OSM_VENDOR_MTL_H_ + +#undef IN +#undef OUT +#include +#include +#include +#define IN +#define OUT +#include "iba/ib_types.h" +#include "iba/ib_al.h" +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* OpenSM/Vendor MTL +* NAME +* Vendor MTL +* +* DESCRIPTION +* +* The Vendor MTL object is thread safe. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* +* AUTHOR +* +* +*********/ +/****s* OpenSM: Vendor MTL/osm_ca_info_t +* NAME +* osm_ca_info_t +* +* DESCRIPTION +* Structure containing information about local Channle Adapters. +* +* SYNOPSIS +*/ +typedef struct _osm_ca_info { + ib_net64_t guid; + size_t attr_size; + ib_ca_attr_t *p_attr; + +} osm_ca_info_t; + +/* +* FIELDS +* guid +* Node GUID of the local CA. +* +* attr_size +* Size of the CA attributes for this CA. +* +* p_attr +* Pointer to dynamicly allocated CA Attribute structure. +* +* SEE ALSO +*********/ + +#define OSM_DEFAULT_RETRY_COUNT 3 + +/***** OpenSM: Vendor MTL/osm_vendor_t +* NAME +* osm_vendor_t +* +* DESCRIPTION +* The structure defining a vendor +* +* SYNOPSIS +*/ +typedef struct _osm_vendor { + ib_al_handle_t h_al; + osm_log_t *p_log; + uint32_t ca_count; + osm_ca_info_t *p_ca_info; + uint32_t timeout; + struct osm_transaction_mgr_t *p_transaction_mgr; +} osm_vendor_t; + +/* +* FIELDS +* h_al +* Handle returned by MTL open call (ib_open_al). +* +* p_log +* Pointer to the log object. +* +* ca_count +* Number of CA's in the array pointed to by p_ca_info. +* +* p_ca_info +* Pointer to dynamically allocated array of CA info objects. +* +* timeout +* Transaction timeout time in milliseconds. +* +* p_transaction_mgr +* Pointer to Transaction Manager. +* +* SEE ALSO +*********/ + +/****f* OpenSM: Vendor MTL/CA Info/osm_ca_info_get_port_guid +* NAME +* osm_ca_info_get_port_guid +* +* DESCRIPTION +* Returns the port GUID of the specified port owned by this CA. +* +* SYNOPSIS +*/ +static inline ib_net64_t +osm_ca_info_get_port_guid(IN const osm_ca_info_t * const p_ca_info, + IN const uint8_t index) +{ + return (p_ca_info->p_attr->p_port_attr[index].port_guid); +} + +/* +* PARAMETERS +* p_ca_info +* [in] Pointer to a CA Info object. +* +* index +* [in] Port "index" for which to retrieve the port GUID. +* The index is the offset into the ca's internal array +* of port attributes. +* +* RETURN VALUE +* Returns the port GUID of the specified port owned by this CA. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Vendor MTL/CA Info/osm_ca_info_get_num_ports +* NAME +* osm_ca_info_get_num_ports +* +* DESCRIPTION +* Returns the number of ports of the given ca_info +* +* SYNOPSIS +*/ +static inline uint8_t +osm_ca_info_get_num_ports(IN const osm_ca_info_t * const p_ca_info) +{ + return (p_ca_info->p_attr->num_ports); +} + +/* +* PARAMETERS +* p_ca_info +* [in] Pointer to a CA Info object. +* +* RETURN VALUE +* Returns the number of CA ports +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: SM Vendor/osm_vendor_get_guid_ca_and_port + * NAME + * osm_vendor_get_guid_ca_and_port + * + * DESCRIPTION + * Given the vendor obj and a guid + * return the ca id and port number that have that guid + * + * SYNOPSIS + */ +ib_api_status_t +osm_vendor_get_guid_ca_and_port(IN osm_vendor_t * const p_vend, + IN ib_net64_t const guid, + OUT VAPI_hca_hndl_t * p_hca_hndl, + OUT VAPI_hca_id_t * p_hca_id, + OUT uint32_t * p_port_num); + +/* +* PARAMETERS +* p_vend +* [in] Pointer to an osm_vendor_t object. +* +* guid +* [in] The guid to search for. +* +* p_hca_id +* [out] The HCA Id (VAPI_hca_id_t *) that the port is found on. +* +* p_port_num +* [out] Pointer to a port number arg to be filled with the port number with the given guid. +* +* RETURN VALUES +* IB_SUCCESS on SUCCESS +* IB_INVALID_GUID if the guid is notfound on any Local HCA Port +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Vendor MTL/osm_vendor_get_all_port_attr + * NAME + * osm_vendor_get_all_port_attr + * + * DESCRIPTION + * Fill in the array of port_attr with all available ports on ALL the + * avilable CAs on this machine. + * ALSO - + * UPDATE THE VENDOR OBJECT LIST OF CA_INFO STRUCTS + * + * SYNOPSIS + */ +ib_api_status_t osm_vendor_get_all_port_attr(IN osm_vendor_t * const p_vend, + IN ib_port_attr_t * + const p_attr_array, + IN uint32_t * const p_num_ports); + +/* +* PARAMETERS +* p_vend +* [in] Pointer to an osm_vendor_t object. +* +* p_attr_array +* [out] Pre-allocated array of port attributes to be filled in +* +* p_num_ports +* [out] The size of the given array. Filled in by the actual numberof ports found. +* +* RETURN VALUES +* IB_SUCCESS if OK +* IB_INSUFFICIENT_MEMORY if not enough place for all ports was provided. +* +* NOTES +* +* SEE ALSO +*********/ + +#define OSM_BIND_INVALID_HANDLE 0 + +/****s* OpenSM: Vendor MTL/osm_bind_handle_t +* NAME +* osm_bind_handle_t +* +* DESCRIPTION +* handle returned by the vendor transport bind call. +* +* SYNOPSIS +*/ +typedef void *osm_bind_handle_t; + +/***********/ + +/****s* OpenSM: Vendor MTL/osm_vend_wrap_t +* NAME +* MTL Vendor MAD Wrapper +* +* DESCRIPTION +* MTL specific MAD wrapper. MTL transport layer uses this for +* housekeeping. +* +* SYNOPSIS +*********/ +typedef struct _osm_vend_wrap_t { + uint32_t size; + osm_bind_handle_t h_bind; + // ib_av_handle_t h_av; + ib_mad_t *mad_buf_p; + void *p_resp_madw; +} osm_vend_wrap_t; + +/* +* FIELDS +* size +* Size of the allocated MAD +* +* h_bind +* Bind handle used on this transaction +* +* h_av +* Address vector handle used for this transaction. +* +* p_resp_madw +* Pointer to the mad wrapper structure used to hold the pending +* reponse to the mad, if any. If a response is expected, the +* wrapper for the reponse is allocated during the send call. +* +* SEE ALSO +*********/ + +END_C_DECLS +#endif /* _OSM_VENDOR_MTL_H_ */ diff --git a/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mtl_hca_guid.h b/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mtl_hca_guid.h new file mode 100644 index 00000000..de7c5545 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/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/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mtl_transaction_mgr.h b/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mtl_transaction_mgr.h new file mode 100644 index 00000000..a69be8da --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_mtl_transaction_mgr.h @@ -0,0 +1,299 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Definition of interface for the MTL Vendor + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_TRANSACTION_MGR_H_ +#define _OSM_TRANSACTION_MGR_H_ + + /* + #include + #include + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef OSM_VENDOR_INTF_MTL +#include +#include +#endif + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****s* OpenSM: Transaction Manager/osm_madw_req_t +* NAME +* osm_madw_req_t +* +* DESCRIPTION +* The structure defining each object in the transaction_mgr. +* For every request mad sent, we will save such an object for it. +* +* SYNOPSIS +*/ +typedef struct _osm_madw_req { + cl_list_item_t list_item; + cl_map_item_t map_item; + osm_madw_t *p_madw; + uint64_t waking_time; + uint8_t retry_cnt; + osm_bind_handle_t *p_bind; +} osm_madw_req_t; + +/* +* FIELDS +* list_item +* List item for qlist linkage. Must be first element!! +* +* map_item +* Map item for qmap linkage. +* +* p_madw +* pointer to mad wrapper that is expecting to get a response. +* +* waking_time +* Time stamp (in microseconds) when the p_madw needs to wake up. +* This value is +* cl_get_time_stamp() + timeout during the sending of the mad. +* where timeout should be given in microseconds. +* +* retry_cnt +* The number of outstanding retries to be called. +*********/ + +/****s* OpenSM: Transaction Manager/osm_transaction_mgr_t +* NAME +* osm_transaction_mgr_t +* +* DESCRIPTION +* This structure defines the transaction manager. +* It holds a qlist and a qmap, a lock on the transaction manager, and +* a timer used for the list. +* The manager is responsible for keeping track of every request mad that was +* sent. It is used for finding mads according to their transaction id, and for +* acting as an event wheel - reporting as error each packet was supposed to get +* a response and didn't get one by the timeout time expected. +* +* Both the list and the map hold the osm_madw_req_t objects - one for every madw. +* +* Managing of the list: +* The timer wakes on the timeout of the first madw. If the waking_time is greater than +* the current time - then the mad received a response. If not - the mad didn't get +* its response. +* +* SYNOPSIS +*/ +typedef struct _osm_transaction_mgr { + cl_qmap_t *madw_by_tid_map_p; + cl_qlist_t *madw_reqs_list_p; + cl_spinlock_t transaction_mgr_lock; + cl_timer_t madw_list_timer; +} osm_transaction_mgr_t; + +/* +* FIELDS +* madw_by_tid_map_p +* A qmap with key = transaction id. and value of osm_madw_req_t. +* +* madw_reqs_list_p +* A qlist of all the madw with their waking time. +* +* transaction_mgr_lock +* Lock used on the transaction manager - make sure changes on it are serial. +* +* madw_list_timer +* Timer on the list. +*********/ + +/****f* OpenSM: Transaction Manager/osm_transaction_mgr_init +* NAME +* osm_transaction_mgr_init +* +* DESCRIPTION +* Initialize the transaction manager. +* Will update the p_transaction_mgr in the vendor object with +* the new Transaction Manager created.* +* +* SYNOPSIS +*/ +void osm_transaction_mgr_init(IN osm_vendor_t * const p_vend); + +/* +* PARAMETERS +* p_vend +* [in] Pointer to a Osm Vendor object. +* +*********/ + +/****f* OpenSM: Transaction Manager/osm_transaction_mgr_destroy +* NAME +* osm_transaction_mgr_destroy +* +* DESCRIPTION +* Destroy the transaction manager. +* Will de-allocate all memory allocated by the Transaction +* Manager up to now. +* +* SYNOPSIS +*/ +void osm_transaction_mgr_destroy(IN osm_vendor_t * const p_vend); + +/* +* PARAMETERS +* p_vend +* [in] Pointer to a Osm Vendor object. +* +*********/ + +/****f* OpenSM: Transaction Manager/osm_transaction_mgr_insert_madw +* NAME +* osm_transaction_mgr_insert_madw +* +* DESCRIPTION +* Insert a new madw to the manager. The madw is added with a waking_time, +* Which is equal to the current_time + timeout. This is the maximum time +* that the madw can leave without being handled (e.g - get a response). +* If there are no madw saved in the manager - start the timer for vendor +* timeout period. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_transaction_mgr_insert_madw(IN osm_bind_handle_t * p_bind, + IN osm_madw_t * p_madw); +/* +* PARAMETERS +* p_vend +* [in] Pointer to a mtl bind object. +* +* p_madw +* [in] Pointer to the Mad Wrapper to be added. +* +*********/ + +/****f* OpenSM: Transaction Manager/osm_transaction_mgr_erase_madw +* NAME +* osm_transaction_mgr_erase_madw +* +* DESCRIPTION +* Erase a madw object from the manager. +* The removal is done using the transaction id of the mad - using +* it the madw_p is allocated (in the qmap) and removed from the +* qmap and qlist. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_transaction_mgr_erase_madw(IN osm_vendor_t * const p_vend, + IN ib_mad_t * p_mad); +/* +* PARAMETERS +* p_vend +* [in] Pointer to a Osm Vendor object. +* +* p_mad +* [in] Pointer to the Mad to be removed. +* +*********/ + +/****f* OpenSM: Transaction Manager/osm_transaction_mgr_get_madw_for_tid +* NAME +* osm_transaction_mgr_get_madw_for_tid +* +* DESCRIPTION +* Return the mad wrapper, given the p_mad (and in it the transaction id) +* +* SYNOPSIS +*/ +ib_api_status_t +osm_transaction_mgr_get_madw_for_tid(IN osm_vendor_t * const p_vend, + IN ib_mad_t * const p_mad, + OUT osm_madw_t ** req_madw_p); +/* +* PARAMETERS +* p_vend +* [in] Pointer to a Osm Vendor object. +* +* p_mad +* [in] Pointer to the Mad to be located. +* +* req_madw_p +* [out] Pointer to the mad Wrapper to be found. +* +*********/ + +/****f* OpenSM: Transaction Manager/osm_transaction_mgr_callback +* NAME +* osm_transaction_mgr_callback +* +* DESCRIPTION +* This callback is called on timeout of the timer. +* It checks the time of the head madw in the qlist, and compares it to +* the current time. +* Will send an error callback if the time of the madw is less than the +* current time - this means that the madw wasn't removed in the timeout +* it was supposed to be handled. +* +* SYNOPSIS +*/ +void osm_transaction_mgr_callback(IN void *context); +/* +* PARAMETERS +* context +* [in] void* context +* +*********/ + +END_C_DECLS +#endif /* _OSM_TRANSACTION_MGR_H_ */ diff --git a/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_sa_api.h b/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_sa_api.h new file mode 100644 index 00000000..0451caa7 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_sa_api.h @@ -0,0 +1,866 @@ +/* + * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Specification of the OpenSM SA Client API. This API uses the basic osm + * vendor API to provide SA Client interface. + */ + +#ifndef _OSM_VENDOR_SA_API_H_ +#define _OSM_VENDOR_SA_API_H_ + +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****d* OpenSM Vendor SA Client/osmv_flags_t +* NAME +* osmv_flags_t +* +* DESCRIPTION +* Access layer flags used to direct the operation of various calls. +* +* SYNOPSIS +*/ +typedef uint32_t osmv_flags_t; +#define OSM_SA_FLAGS_SYNC 0x00000001 +/* +* VALUES +* OSM_SA_FLAGS_SYNC +* Indicates that the given operation should be performed synchronously. +* The call will block until it completes. Callbacks will still be +* invoked. +* +* SEE ALSO +* osmv_query_sa +*****/ + +/****d* OpenSM Vendor SA Client/osmv_query_type_t +* NAME +* osmv_query_type_t +* +* DESCRIPTION +* Abstracted queries supported by the access layer. +* +* SYNOPSIS +*/ +typedef enum _osmv_query_type { + OSMV_QUERY_USER_DEFINED, + + OSMV_QUERY_ALL_SVC_RECS, + OSMV_QUERY_SVC_REC_BY_NAME, + OSMV_QUERY_SVC_REC_BY_ID, + + OSMV_QUERY_CLASS_PORT_INFO, + + OSMV_QUERY_NODE_REC_BY_NODE_GUID, + OSMV_QUERY_PORT_REC_BY_LID, + OSMV_QUERY_PORT_REC_BY_LID_AND_NUM, + + OSMV_QUERY_VLARB_BY_LID_PORT_BLOCK, + OSMV_QUERY_SLVL_BY_LID_AND_PORTS, + + OSMV_QUERY_PATH_REC_BY_PORT_GUIDS, + OSMV_QUERY_PATH_REC_BY_GIDS, + OSMV_QUERY_PATH_REC_BY_LIDS, + + OSMV_QUERY_UD_MULTICAST_SET, + OSMV_QUERY_UD_MULTICAST_DELETE, + + OSMV_QUERY_MULTIPATH_REC, + +} osmv_query_type_t; +/* +* VALUES +* OSMV_QUERY_USER_DEFINED +* Query the SA based on user-defined input. Queries of this type +* should reference an osmv_user_query_t structure as input to the +* query. +* +* OSMV_QUERY_SVC_REC_BY_NAME +* Query for service records based on the service name. Queries of +* this type should reference an ib_svc_name_t structure as input +* to the query. +* +* OSMV_QUERY_SVC_REC_BY_ID +* Query for service records based on the service ID. Queries of +* this type should reference an ib_net64_t value that indicates +* the ID of the service being requested. +* +* OSMV_QUERY_NODE_REC_BY_NODE_GUID +* Query for node information based on the node's GUID. Queries of +* this type should reference an ib_net64_t value that indicates +* the GUID of the node being requested. +* +* OSMV_QUERY_PORT_REC_BY_LID +* Query for port information based on the port's base LID. Queries +* of this type should reference an ib_net16_t value that indicates +* the base LID of the port being requested. +* +* OSMV_QUERY_PORT_REC_BY_LID_AND_NUM +* Query for port information based on the port's LID and port num. +* Queries of this type should reference an osmv_user_query_t +* structure as input to the query. The port num and lid should +* be provided by it. +* +* OSMV_QUERY_PATH_REC_BY_PORT_GUIDS +* Query for path records between the specified pair of port GUIDs. +* Queries of this type should reference an osmv_guid_pair_t +* structure that indicates the GUIDs of the path being requested. +* +* OSMV_QUERY_PATH_REC_BY_GIDS +* Query for path records between the specified pair of port GIDs. +* Queries of this type should reference an osmv_gid_pair_t +* structure that indicates the GIDs of the path being requested. +* +* OSMV_QUERY_PATH_REC_BY_LIDS +* Query for path records between the specified pair of port LIDs. +* Queries of this type should reference an osmv_lid_pair_t +* structure that indicates the LIDs of the path being requested. +* +* NOTES +* This enum is used to define abstracted queries provided by the access +* layer. Users may issue queries not listed here by sending MADs directly +* to subnet administration or a class manager. These queries are +* intended to represent those most often used by clients. +* +* SEE ALSO +* osmv_query, osmv_query_req_t, osmv_user_query_t, osmv_gid_pair_t, +* osmv_lid_pair_t osmv_guid_pair_t +*****/ + +/****s* OpenSM Vendor SA Client/osmv_user_query_t +* NAME +* osmv_user_query_t +* +* DESCRIPTION +* User-defined query information. +* +* SYNOPSIS +*/ +typedef struct _osmv_user_query { + uint8_t method; + ib_net16_t attr_id; + ib_net16_t attr_offset; + ib_net32_t attr_mod; + ib_net64_t comp_mask; + void *p_attr; +} osmv_user_query_t; +/* +* FIELDS +* +* method +* Method to be used +* +* attr_id +* Attribute identifier of query data. +* +* attr_offset +* Size of the query attribute, in 8-byte words. Users can set +* this value by passing in the sizeof( attribute ) into the +* ib_get_attr_offset() routine. +* +* attr_mod +* Attribute modifier for query request. +* +* comp_mask +* Indicates the attribute components that are specified for the +* query. +* +* p_attr +* References the attribute structure used as input into the query. +* This field is ignored if comp_mask is set to 0. +* +* NOTES +* This structure is used to describe a user-defined query. The attribute +* ID, attribute offset, component mask, and attribute structure must match +* those defined by the IBA specification. Users should refer to chapter +* 15 of the IBA specification for additional details. +* +* SEE ALSO +* osmv_query_type_t, ib_get_attr_offset, ib_get_attr_size, osmv_query_sa +*****/ + +/****s* OpenSM Vendor SA Client/osmv_gid_pair_t +* NAME +* osmv_gid_pair_t +* +* DESCRIPTION +* Source and destination GIDs. +* +* SYNOPSIS +*/ +typedef struct _osmv_gid_pair { + ib_gid_t src_gid; + ib_gid_t dest_gid; +} osmv_gid_pair_t; +/* +* FIELDS +* src_gid +* Source GID of a path. +* +* dest_gid +* Destination GID of a path. +* +* NOTES +* This structure is used to describe the endpoints of a path. +* +* SEE ALSO +* ib_gid_t +*****/ + +/****s* OpenSM Vendor SA Client/osmv_lid_pair_t +* NAME +* osmv_lid_pair_t +* +* DESCRIPTION +* Source and destination LIDs. +* +* SYNOPSIS +*/ +typedef struct _osmv_lid_pair { + ib_net16_t src_lid; + ib_net16_t dest_lid; +} osmv_lid_pair_t; +/* +* FIELDS +* src_lid +* Source LID of a path. +* +* dest_lid +* Destination LID of a path. +* +* NOTES +* This structure is used to describe the endpoints of a path. +*****/ + +/****s* OpenSM Vendor SA Client/osmv_guid_pair_t +* NAME +* osmv_guid_pair_t +* +* DESCRIPTION +* Source and destination GUIDs. These may be port or channel adapter +* GUIDs, depending on the context in which this structure is used. +* +* SYNOPSIS +*/ +typedef struct _osmv_guid_pair { + ib_net64_t src_guid; + ib_net64_t dest_guid; +} osmv_guid_pair_t; +/* +* FIELDS +* src_guid +* Source GUID of a path. +* +* dest_guid +* Destination GUID of a path. +* +* NOTES +* This structure is used to describe the endpoints of a path. The given +* GUID pair may belong to either ports or channel adapters. +* +* SEE ALSO +* ib_guid_t +*****/ + +/****s* OpenSM Vendor SA Client/osmv_multipath_req_t +* NAME +* osmv_multipath_req_t +* +* DESCRIPTION +* Fields from which to generate a MultiPathRecord request. +* +* SYNOPSIS +*/ +typedef struct _osmv_multipath_req_t { + ib_net64_t comp_mask; + uint16_t pkey; + boolean_t reversible; + uint8_t num_path; + uint8_t sl; + uint8_t independence; + uint8_t sgid_count; + uint8_t dgid_count; + ib_gid_t gids[IB_MULTIPATH_MAX_GIDS]; +} osmv_multipath_req_t; +/* +* FIELDS +* +* NOTES +* This structure is used to describe a multipath request. +* +* SEE ALSO +*****/ + +/****s* OpenSM Vendor SA Client/osmv_query_res_t +* NAME +* osmv_query_res_t +* +* DESCRIPTION +* Contains the results of a subnet administration query. +* +* SYNOPSIS +*/ +typedef struct _osmv_query_res { + const void *query_context; + ib_api_status_t status; + osmv_query_type_t query_type; + uint32_t result_cnt; + osm_madw_t *p_result_madw; +} osmv_query_res_t; +/* +* FIELDS +* query_context +* User-defined context information associated with the query +* through the osm_vendor_query_sa call. +* +* status +* Indicates the success of the query operation. +* +* query_type +* Indicates the type of query for which the results are being +* returned. This matches the query_type specified through the +* osm_vendor_query_sa call. +* +* result_cnt +* The number of result structures that were returned by the query. +* +* p_result_madw +* For queries returning IB_SUCCESS or IB_REMOTE_ERROR, this +* references the MAD wrapper returned by subnet administration +* containing the list of results or the returned error code. +* +* NOTES +* A query result structure is returned to a client through their +* osmv_pfn_query_cb_t routine to notify them of the results of a subnet +* administration query. If the query was successful or received an error +* from subnet administration, p_result_madw will reference a MAD wrapper +* containing the results. The MAD referenced by p_result_madw is owned by +* the user and remains available even after their callback returns. Users +* must call osm_mad_pool_put() to return the MAD wrapper back to the +* mad pool when they are done accessing the results. +* +* To retrieve individual result structures from the p_result_madw, users +* may call osmv_get_query_result(). +* +* SEE ALSO +* osmv_query_sa, osmv_pfn_query_cb_t, ib_api_status_t, +* osmv_query_status_t, osmv_query_type_t, +* osmv_get_query_result +*****/ + +/****f* OpenSM Vendor SA Client/osmv_get_query_result +* NAME +* osmv_get_query_result +* +* DESCRIPTION +* Retrieves a result structure from a MADW returned by a call to +* osmv_query_sa(). +* +* SYNOPSIS +*/ +static inline void *osmv_get_query_result(IN osm_madw_t * p_result_madw, + IN uint32_t result_index) +{ + ib_sa_mad_t *p_sa_mad; + + CL_ASSERT(p_result_madw); + p_sa_mad = (ib_sa_mad_t *) osm_madw_get_mad_ptr(p_result_madw); + CL_ASSERT(p_sa_mad); + CL_ASSERT(ib_get_attr_size(p_sa_mad->attr_offset) * (result_index + 1) + + IB_SA_MAD_HDR_SIZE <= p_result_madw->mad_size); + + return (p_sa_mad->data + + (ib_get_attr_size(p_sa_mad->attr_offset) * result_index)); +} + +/* +* PARAMETERS +* p_result_madw +* [in] This is a reference to the MAD returned as a result of the +* query. +* +* result_index +* [in] A zero-based index indicating which result to return. +* +* NOTES +* This call returns a pointer to the start of a result structure from a +* call to osmv_query_sa(). The type of result structure must be known to +* the user either through the user's context or the query_type returned as +* part of the osmv_query_res_t structure. +* +* SEE ALSO +* osmv_query_res_t, osm_madw_t +*****/ + +/****f* OpenSM Vendor SA Client/osmv_get_query_path_rec +* NAME +* osmv_get_query_path_rec +* +* DESCRIPTION +* Retrieves a path record result from a MAD returned by a call to +* osmv_query_sa(). +* +* SYNOPSIS +*/ +static inline ib_path_rec_t *osmv_get_query_path_rec(IN osm_madw_t * + p_result_madw, + IN uint32_t result_index) +{ + ib_sa_mad_t *p_sa_mad; + + CL_ASSERT(p_result_madw); + p_sa_mad = (ib_sa_mad_t *) osm_madw_get_mad_ptr(p_result_madw); + CL_ASSERT(p_sa_mad && p_sa_mad->attr_id == IB_MAD_ATTR_PATH_RECORD); + + return ((ib_path_rec_t *) + osmv_get_query_result(p_result_madw, result_index)); +} + +/* +* PARAMETERS +* p_result_madw +* [in] This is a reference to the MAD returned as a result of the +* query. +* +* result_index +* [in] A zero-based index indicating which result to return. +* +* NOTES +* This call returns a pointer to the start of a path record result from +* a call to osmv_query_sa(). +* +* SEE ALSO +* osmv_query_res_t, osm_madw_t, osmv_get_query_result, ib_path_rec_t +*****/ + +/****f* OpenSM Vendor SA Client/osmv_get_query_portinfo_rec +* NAME +* osmv_get_query_portinfo_rec +* +* DESCRIPTION +* Retrieves a port info record result from a MAD returned by a call to +* osmv_query_sa(). +* +* SYNOPSIS +*/ +static inline ib_portinfo_record_t *osmv_get_query_portinfo_rec(IN osm_madw_t * + p_result_madw, + IN uint32_t + result_index) +{ + ib_sa_mad_t *p_sa_mad; + + CL_ASSERT(p_result_madw); + p_sa_mad = (ib_sa_mad_t *) osm_madw_get_mad_ptr(p_result_madw); + CL_ASSERT(p_sa_mad && p_sa_mad->attr_id == IB_MAD_ATTR_PORTINFO_RECORD); + + return ((ib_portinfo_record_t *) osmv_get_query_result(p_result_madw, + result_index)); +} + +/* +* PARAMETERS +* p_result_madw +* [in] This is a reference to the MAD returned as a result of the +* query. +* +* result_index +* [in] A zero-based index indicating which result to return. +* +* NOTES +* This call returns a pointer to the start of a port info record result +* from a call to osmv_query_sa(). +* +* SEE ALSO +* osmv_query_res_t, osm_madw_t, osmv_get_query_result, ib_portinfo_record_t +*****/ + +/****f* OpenSM Vendor SA Client/osmv_get_query_node_rec +* NAME +* osmv_get_query_node_rec +* +* DESCRIPTION +* Retrieves a node record result from a MAD returned by a call to +* osmv_query_sa(). +* +* SYNOPSIS +*/ +static inline ib_node_record_t *osmv_get_query_node_rec(IN osm_madw_t * + p_result_madw, + IN uint32_t + result_index) +{ + ib_sa_mad_t *p_sa_mad; + + CL_ASSERT(p_result_madw); + p_sa_mad = (ib_sa_mad_t *) osm_madw_get_mad_ptr(p_result_madw); + CL_ASSERT(p_sa_mad && p_sa_mad->attr_id == IB_MAD_ATTR_NODE_RECORD); + + return ((ib_node_record_t *) osmv_get_query_result(p_result_madw, + result_index)); +} + +/* +* PARAMETERS +* p_result_madw +* [in] This is a reference to the MAD returned as a result of the +* query. +* +* result_index +* [in] A zero-based index indicating which result to return. +* +* NOTES +* This call returns a pointer to the start of a node record result from +* a call to osmv_query_sa(). +* +* SEE ALSO +* osmv_query_res_t, osm_madw_t, osmv_get_query_result, ib_node_record_t +*****/ + +/****f* OpenSM Vendor SA Client/osmv_get_query_svc_rec +* NAME +* osmv_get_query_svc_rec +* +* DESCRIPTION +* Retrieves a service record result from a MAD returned by a call to +* osmv_query_sa(). +* +* SYNOPSIS +*/ +static inline ib_service_record_t *osmv_get_query_svc_rec(IN osm_madw_t * + p_result_madw, + IN uint32_t + result_index) +{ + ib_sa_mad_t *p_sa_mad; + + CL_ASSERT(p_result_madw); + p_sa_mad = (ib_sa_mad_t *) osm_madw_get_mad_ptr(p_result_madw); + CL_ASSERT(p_sa_mad && p_sa_mad->attr_id == IB_MAD_ATTR_SERVICE_RECORD); + + return ((ib_service_record_t *) osmv_get_query_result(p_result_madw, + result_index)); +} + +/* +* PARAMETERS +* p_result_madw +* [in] This is a reference to the MAD returned as a result of the +* query. +* +* result_index +* [in] A zero-based index indicating which result to return. +* +* NOTES +* This call returns a pointer to the start of a service record result from +* a call to osmv_query_sa(). +* +* SEE ALSO +* osmv_query_res_t, osm_madw_t, osmv_get_query_result, ib_service_record_t +*****/ + +/****f* OpenSM Vendor SA Client/osmv_get_query_mc_rec +* NAME +* osmv_get_query_mc_rec +* +* DESCRIPTION +* Retrieves a multicast record result from a MAD returned by a call to +* osmv_query_sa(). +* +* SYNOPSIS +*/ +static inline ib_member_rec_t *osmv_get_query_mc_rec(IN osm_madw_t * + p_result_madw, + IN uint32_t result_index) +{ + ib_sa_mad_t *p_sa_mad; + + CL_ASSERT(p_result_madw); + p_sa_mad = (ib_sa_mad_t *) osm_madw_get_mad_ptr(p_result_madw); + CL_ASSERT(p_sa_mad && p_sa_mad->attr_id == IB_MAD_ATTR_MCMEMBER_RECORD); + + return ((ib_member_rec_t *) osmv_get_query_result(p_result_madw, + result_index)); +} + +/* +* PARAMETERS +* p_result_madw +* [in] This is a reference to the MAD returned as a result of the +* query. +* +* result_index +* [in] A zero-based index indicating which result to return. +* +* NOTES +* This call returns a pointer to the start of a service record result from +* a call to osmv_query_sa(). +* +* SEE ALSO +* osmv_query_res_t, osm_madw_t, osmv_get_query_result, ib_member_rec_t +*****/ + +/****f* OpenSM Vendor SA Client/osmv_get_query_inform_info_rec +* NAME +* osmv_get_query_inform_info_rec +* +* DESCRIPTION +* Retrieves an InformInfo record result from a MAD returned by +* a call to osmv_query_sa(). +* +* SYNOPSIS +*/ +static inline ib_inform_info_record_t *osmv_get_query_inform_info_rec(IN + osm_madw_t + * + p_result_madw, + IN + uint32_t + result_index) +{ + ib_sa_mad_t *p_sa_mad; + + CL_ASSERT(p_result_madw); + p_sa_mad = (ib_sa_mad_t *) osm_madw_get_mad_ptr(p_result_madw); + CL_ASSERT(p_sa_mad + && p_sa_mad->attr_id == IB_MAD_ATTR_INFORM_INFO_RECORD); + + return ((ib_inform_info_record_t *) osmv_get_query_result(p_result_madw, + result_index)); +} + +/* +* PARAMETERS +* p_result_madw +* [in] This is a reference to the MAD returned as a result of the +* query. +* +* result_index +* [in] A zero-based index indicating which result to return. +* +* NOTES +* This call returns a pointer to the start of a service record result from +* a call to osmv_query_sa(). +* +* SEE ALSO +* osmv_query_res_t, osm_madw_t, osmv_get_query_result, ib_inform_info_record_t +*****/ + +/****f* OpenSM Vendor SA Client/osmv_pfn_query_cb_t +* NAME +* osmv_pfn_query_cb_t +* +* DESCRIPTION +* User-defined callback invoked on completion of subnet administration +* query. +* +* SYNOPSIS +*/ +typedef void + (*osmv_pfn_query_cb_t) (IN osmv_query_res_t * p_query_res); +/* +* PARAMETERS +* p_query_res +* [in] This is a reference to a structure containing the result of +* the query. +* +* NOTES +* This routine is invoked to notify a client of the result of a subnet +* administration query. The p_query_rec parameter references the result +* of the query and, in the case of a successful query, any information +* returned by subnet administration. +* +* In the kernel, this callback is usually invoked using a tasklet, +* dependent on the implementation of the underlying verbs provider driver. +* +* SEE ALSO +* osmv_query_res_t +*****/ + +/****s* OpenSM Vendor SA Client/osmv_query_req_t +* NAME +* osmv_query_req_t +* +* DESCRIPTION +* Information used to request an access layer provided query of subnet +* administration. +* +* SYNOPSIS +*/ +typedef struct _osmv_query_req { + osmv_query_type_t query_type; + const void *p_query_input; + ib_net64_t sm_key; + + uint32_t timeout_ms; + uint32_t retry_cnt; + osmv_flags_t flags; + + const void *query_context; + osmv_pfn_query_cb_t pfn_query_cb; +} osmv_query_req_t; +/* +* FIELDS +* query_type +* Indicates the type of query that the access layer should +* perform. +* +* p_query_input +* A pointer to the input for the query. The data referenced by +* this structure is dependent on the type of query being requested +* and is determined by the specified query_type. +* +* sm_key +* The SM_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/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_test.h b/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_test.h new file mode 100644 index 00000000..8b360b96 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_test.h @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _OSM_VENDOR_TEST_H_ +#define _OSM_VENDOR_TEST_H_ + +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/* This value must be zero for the TEST transport. */ +#define OSM_BIND_INVALID_HANDLE 0 +/* + * Abstract: + * Declaration of vendor specific transport interface. + * This is the "Test" vendor which allows compilation and some + * testing without a real vendor interface. + * These objects are part of the OpenSM family of objects. + */ +/****h* OpenSM/Vendor Test +* NAME +* Vendor Test +* +* DESCRIPTION +* The Vendor Test structure encapsulates an artificial transport layer +* interface for testing. +* +* AUTHOR +* Steve King, Intel +* +*********/ +/****s* OpenSM: Vendor Test/osm_vend_wrap_t +* NAME +* osm_vend_wrap_t +* +* DESCRIPTION +* Vendor specific MAD wrapper context. +* +* This structure allows direct access to member variables. +* +* SYNOPSIS +*/ +typedef struct _osm_vend_wrap { + uint32_t dummy; + +} osm_vend_wrap_t; +/*********/ + +/****s* OpenSM: Vendor Test/osm_vendor_t +* NAME +* osm_vendor_t +* +* DESCRIPTION +* Vendor specific MAD interface. +* +* This interface defines access to the vendor specific MAD +* transport layer. +* +* SYNOPSIS +*/ +typedef struct _osm_vendor { + osm_log_t *p_log; + uint32_t timeout; + +} osm_vendor_t; +/*********/ + +typedef struct _osm_bind_handle { + osm_vendor_t *p_vend; + ib_net64_t port_guid; + uint8_t mad_class; + uint8_t class_version; + boolean_t is_responder; + boolean_t is_trap_processor; + boolean_t is_report_processor; + uint32_t send_q_size; + uint32_t recv_q_size; + +} *osm_bind_handle_t; + +END_C_DECLS +#endif /* _OSM_VENDOR_TEST_H_ */ diff --git a/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_ts.h b/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_ts.h new file mode 100644 index 00000000..7fbbf1a0 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_ts.h @@ -0,0 +1,410 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Definition of interface for the TS Vendor + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_VENDOR_TS_H_ +#define _OSM_VENDOR_TS_H_ + +#undef IN +#undef OUT +#include +#include +#include +#define IN +#define OUT +#include "iba/ib_types.h" +#include "iba/ib_al.h" +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****s* OpenSM: Vendor TS/osm_bind_handle_t + * NAME + * osm_bind_handle_t + * + * DESCRIPTION + * handle returned by the vendor transport bind call. + * + * SYNOPSIS + */ +typedef void *osm_bind_handle_t; +/* +**********/ +#define OSM_DEFAULT_RETRY_COUNT 3 + +/****s* OpenSM: Vendor osm_ts_bind_info_t + * NAME + * osm_ts_bind_info_t + * + * DESCRIPTION + * Handle to the result of binding a class callbacks . + * + * SYNOPSIS + */ +typedef struct _osm_ts_bind_info { + int ul_dev_fd; + VAPI_hca_hndl_t hca_hndl; + struct _osm_vendor *p_vend; + void *client_context; + uint8_t port_num; + void *rcv_callback; + void *send_err_callback; + struct _osm_mad_pool *p_osm_pool; + cl_thread_t poller; +} osm_ts_bind_info_t; +/* + * FIELDS + * ul_dev_file_hdl + * the file handle to be used for sending the MADs + * + * hca_hndl + * Handle to the HCA provided by the underlying VAPI + * + * p_vend + * Pointer to the vendor object. + * + * client_context + * User's context passed during osm_bind + * + * hca_id + * HCA Id we bind to. + * + * port_num + * Port number (within the HCA) of the bound port. + * + * rcv_callback + * OSM Callback function to be called on receive of MAD. + * + * send_err_callback + * OSM Callback to be called on send error. + * + * p_osm_pool + * Points to the MAD pool used by OSM + * + * poller + * A thread reading from the device file handle + * + * SEE ALSO + *********/ + +/****h* OpenSM/Vendor TS + * NAME + * Vendor TS + * + * DESCRIPTION + * + * The Vendor TS object is thread safe. + * + * This object should be treated as opaque and should be + * manipulated only through the provided functions. + * + * + * AUTHOR + * + * + *********/ + +/****s* OpenSM: Vendor TS/osm_ca_info_t + * NAME + * osm_ca_info_t + * + * DESCRIPTION + * Structure containing information about local Channle Adapters. + * + * SYNOPSIS + */ +typedef struct _osm_ca_info { + ib_net64_t guid; + size_t attr_size; + ib_ca_attr_t *p_attr; + +} osm_ca_info_t; + +/* + * FIELDS + * guid + * Node GUID of the local CA. + * + * attr_size + * Size of the CA attributes for this CA. + * + * p_attr + * Pointer to dynamicly allocated CA Attribute structure. + * + * SEE ALSO + *********/ + +/***** OpenSM: Vendor TS/osm_vendor_t + * NAME + * osm_vendor_t + * + * DESCRIPTION + * The structure defining a TS vendor + * + * SYNOPSIS + */ +typedef struct _osm_vendor { + osm_log_t *p_log; + uint32_t ca_count; + osm_ca_info_t *p_ca_info; + uint32_t timeout; + struct _osm_transaction_mgr *p_transaction_mgr; + osm_ts_bind_info_t smi_bind; + osm_ts_bind_info_t gsi_bind; +} osm_vendor_t; + +/* + * FIELDS + * h_al + * Handle returned by TS open call . + * + * p_log + * Pointer to the log object. + * + * ca_count + * Number of CA's in the array pointed to by p_ca_info. + * + * p_ca_info + * Pointer to dynamically allocated array of CA info objects. + * + * timeout + * Transaction timeout time in milliseconds. + * + * p_transaction_mgr + * Pointer to Transaction Manager. + * + * smi_bind + * Bind information for handling SMI MADs + * + * gsi_bind + * Bind information for GSI MADs + * + * SEE ALSO + *********/ + +/****f* OpenSM: Vendor TS/CA Info/osm_ca_info_get_port_guid + * NAME + * osm_ca_info_get_port_guid + * + * DESCRIPTION + * Returns the port GUID of the specified port owned by this CA. + * + * SYNOPSIS + */ +static inline ib_net64_t +osm_ca_info_get_port_guid(IN const osm_ca_info_t * const p_ca_info, + IN const uint8_t index) +{ + return (p_ca_info->p_attr->p_port_attr[index].port_guid); +} + +/* + * PARAMETERS + * p_ca_info + * [in] Pointer to a CA Info object. + * + * index + * [in] Port "index" for which to retrieve the port GUID. + * The index is the offset into the ca's internal array + * of port attributes. + * + * RETURN VALUE + * Returns the port GUID of the specified port owned by this CA. + * + * NOTES + * + * SEE ALSO + *********/ + +/****f* OpenSM: Vendor TS/CA Info/osm_ca_info_get_num_ports + * NAME + * osm_ca_info_get_num_ports + * + * DESCRIPTION + * Returns the number of ports of the given ca_info + * + * SYNOPSIS + */ +static inline uint8_t +osm_ca_info_get_num_ports(IN const osm_ca_info_t * const p_ca_info) +{ + return (p_ca_info->p_attr->num_ports); +} + +/* + * PARAMETERS + * p_ca_info + * [in] Pointer to a CA Info object. + * + * RETURN VALUE + * Returns the number of CA ports + * + * NOTES + * + * SEE ALSO + *********/ + +/****f* OpenSM: SM Vendor/osm_vendor_get_guid_ca_and_port + * NAME + * osm_vendor_get_guid_ca_and_port + * + * DESCRIPTION + * Given the vendor obj and a guid + * return the ca id and port number that have that guid + * + * SYNOPSIS + */ +ib_api_status_t +osm_vendor_get_guid_ca_and_port(IN osm_vendor_t * const p_vend, + IN ib_net64_t const guid, + OUT VAPI_hca_hndl_t * p_hca_hndl, + OUT VAPI_hca_id_t * p_hca_id, + OUT uint32_t * p_port_num); + +/* + * PARAMETERS + * p_vend + * [in] Pointer to an osm_vendor_t object. + * + * guid + * [in] The guid to search for. + * + * p_hca_id + * [out] The HCA Id (VAPI_hca_id_t *) that the port is found on. + * + * p_port_num + * [out] Pointer to a port number arg to be filled with the port number with the given guid. + * + * RETURN VALUES + * IB_SUCCESS on SUCCESS + * IB_INVALID_GUID if the guid is notfound on any Local HCA Port + * + * NOTES + * + * SEE ALSO + *********/ + +/****f* OpenSM: Vendor TS/osm_vendor_get_all_port_attr + * NAME + * osm_vendor_get_all_port_attr + * + * DESCRIPTION + * Fill in the array of port_attr with all available ports on ALL the + * avilable CAs on this machine. + * ALSO - + * UPDATE THE VENDOR OBJECT LIST OF CA_INFO STRUCTS + * + * SYNOPSIS + */ +ib_api_status_t osm_vendor_get_all_port_attr(IN osm_vendor_t * const p_vend, + IN ib_port_attr_t * + const p_attr_array, + IN uint32_t * const p_num_ports); + +/* + * PARAMETERS + * p_vend + * [in] Pointer to an osm_vendor_t object. + * + * p_attr_array + * [out] Pre-allocated array of port attributes to be filled in + * + * p_num_ports + * [out] The size of the given array. Filled in by the actual numberof ports found. + * + * RETURN VALUES + * IB_SUCCESS if OK + * IB_INSUFFICIENT_MEMORY if not enough place for all ports was provided. + * + * NOTES + * + * SEE ALSO + *********/ + +#define OSM_BIND_INVALID_HANDLE 0 + +/****s* OpenSM: Vendor TS/osm_vend_wrap_t + * NAME + * TS Vendor MAD Wrapper + * + * DESCRIPTION + * TS specific MAD wrapper. TS transport layer uses this for + * housekeeping. + * + * SYNOPSIS + *********/ +typedef struct _osm_vend_wrap_t { + uint32_t size; + osm_bind_handle_t h_bind; + ib_mad_t *p_mad_buf; + void *p_resp_madw; +} osm_vend_wrap_t; + +/* + * FIELDS + * size + * Size of the allocated MAD + * + * h_bind + * Bind handle used on this transaction + * + * h_av + * Address vector handle used for this transaction. + * + * p_resp_madw + * Pointer to the mad wrapper structure used to hold the pending + * reponse to the mad, if any. If a response is expected, the + * wrapper for the reponse is allocated during the send call. + * + * SEE ALSO + *********/ + +END_C_DECLS +#endif /* _OSM_VENDOR_TS_H_ */ diff --git a/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_umadt.h b/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_umadt.h new file mode 100644 index 00000000..88581c66 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/vendor/osm_vendor_umadt.h @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osm_mad_wrapper_t. + * This object represents the context wrapper for OpenSM MAD processing. + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_VENDOR_UMADT_h_ +#define _OSM_VENDOR_UMADT_h_ + +#include "iba/ib_types.h" +#include "complib/cl_qlist.h" +#include "complib/cl_thread.h" +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* OpenSM/ Vendor Umadt +* NAME +* MAD Wrapper +* +* DESCRIPTION +* +* +* AUTHOR +* Ranjit Pandit, Intel +* +*********/ +typedef void *osm_vendor_t; +#define OSM_BIND_INVALID_HANDLE 0 + +/****s* OpenSM: Vendor Umadt /osm_bind_handle_t +* NAME +* osm_bind_handle_t +* +* DESCRIPTION +* handle returned by the vendor transport bind call. +* +* SYNOPSIS +*/ + +typedef void *osm_bind_handle_t; + +/****s* OpenSM: Vendor Umadt /mad_direction_t +* NAME +* mad_direction_t +* +* DESCRIPTION +* Tags for mad wrapper to indicate the direction of mads. +* Umadt vendor transport layer uses this tag to call the appropriate +* Umadt APIs. +* +* SYNOPSIS +*/ +typedef enum _mad_direction_t { + SEND = 0, + RECEIVE, +} mad_direction_t; + +/****s* OpenSM/ osm_vend_wrap_t +* NAME +* Umadt Vendor MAD Wrapper +* +* DESCRIPTION +* Umadt specific MAD wrapper. Umadt transport layer sets this for +* housekeeping. +* +* SYNOPSIS +*********/ +typedef struct _osm_vend_wrap_t { + MadtStruct *p_madt_struct; + mad_direction_t direction; // send or receive + uint32_t size; +} osm_vend_wrap_t; +/* +* FIELDS +* p_madt_struct +* Umadt mad structure to identify a mad. +* +* direction +* Used to identify a mad with it's direction. +* +* SEE ALSO +*********/ + +END_C_DECLS +#endif /* _OSM_VENDOR_UMADT_h_ */ diff --git a/branches/WOF2-3/ulp/opensm/user/include/vendor/winosm_common.h b/branches/WOF2-3/ulp/opensm/user/include/vendor/winosm_common.h new file mode 100644 index 00000000..91fdc137 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/include/vendor/winosm_common.h @@ -0,0 +1,211 @@ +#ifndef _OSM_COMMON_H_ +#define _OSM_COMMON_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#define cl_is_debug osm_is_debug + +#include +#include +#include + +#pragma warning(disable : 4996) +#pragma warning(disable : 4100) + +#include +#include +#include + +typedef int ssize_t; + +#define OSM_API __stdcall +#define OSM_CDECL __cdecl + +#define complib_init() +#define complib_exit() + +#define chmod(a,b) _chmod(a,b) +#define S_IRUSR _S_IREAD +#define S_IWUSR _S_IWRITE + +#define snprintf _snprintf +#define vsnprintf _vsnprintf +#ifndef strtoull +#define strtoull _strtoui64 +#endif + +#ifndef PATH_MAX +#define PATH_MAX MAX_PATH +#endif +#define O_NONBLOCK 0 + +#define open _open +#define close _close +#define fileno _fileno +#define stat _stat +#define fstat _fstat +#define unlink(str) _unlink(str) +#define dup2(a,b) +#define isatty _isatty + +#ifndef getpid +#define getpid() GetCurrentProcessId() +#endif + +#define usleep(usec) SleepEx(usec/1000,TRUE) + +#ifdef HAVE_LIBPTHREAD +#error HAVE_LIBPTHREAD defined? +#endif + +/* for those cases where uses of pthreads constructs do not have + * #ifdef HAVE_LIBPTHREAD protection. + */ +#define pthread_t cl_thread_t +#define pthread_mutex_t cl_mutex_t + +#define pthread_mutex_lock cl_mutex_acquire +#define pthread_mutex_unlock cl_mutex_release +#define pthread_mutex_init(a,b) cl_mutex_init((a)) +#define pthread_mutex_destroy cl_mutex_destroy + +#define pthread_cond_init(a,b) +#define pthread_cond_signal cl_event_signal +#define pthread_cond_destroy(a) + + +/************************************************************************/ +static char* +get_char_option(const char* optstring, + char*const* argv,int argc, + int iArg, int* opt_ind,char* opt_p); +int +getopt_long_only(int argc, char *const*argv, + const char *optstring, + const struct option *longopts, int *longindex); + +/**************************************************************************/ + +/* Verify the correct ETIMEDOUT value is defined in all compiled files */ +#ifndef ETIMEDOUT +#define ETIMEDOUT (10060) +#endif + +extern char *strdup_expand(const char *); +extern FILE *Fopen(const char *,const char *); +#define fopen Fopen + +/* The following defines replace syslog.h */ + +void openlog(char *ident, int option, int facility); +void closelog(void); +#define LOG_CONS (1<<0) +#define LOG_PID (1<<2) +#define LOG_USER (1<<3) + +void syslog(int priority, char *fmt, ... ); + +#define LOG_DEBUG 7 +#define LOG_INFO 6 +#define LOG_NOTICE 5 +#define LOG_WARNING 4 +#define LOG_ERR 3 +#define LOG_CRIT 2 +#define LOG_ALTERT 1 +#define LOG_EMERG 0 + +/*****************************************/ + +/****f* OpenSM: osm_common/GetOsmTempPath +* NAME +* GetOsmTempPath +* +* DESCRIPTION +* The function retrieves the temp path defined in Windows using its API +* +* SYNOPSIS +*/ +char* +GetOsmTempPath(void); +/* +* PARAMETERS +* NONE +* +* RETURN VALUE +* This function returns string containing the default temp path in windows +* +* NOTES +*/ + +/****f* OpenSM: osm_common/GetOsmCachePath +* NAME +* GetOsmCachePath +* +* DESCRIPTION +* The function retrieves the path the cache directory. This directory is +* the etc dir under the installation directory of the mellanox stack. +* The installation directory should be pointed out by the WinIB_HOME variable. +* If WinIB_HOME variable is missing, or there is not /etc/ dir under it - then +* the function will return the getOsmTempPath() value. +* +* SYNOPSIS +*/ +char* +GetOsmCachePath(void); +/* +* PARAMETERS +* NONE +* +* RETURN VALUE +* function returns string containing the default cache path for osm use. +* +* NOTES +*/ + +/* **** Move this to inc\complib\cl_qlist.h once it works correctly */ + +/****d* Component Library: Quick List/cl_item_obj +* NAME +* cl_item_obj +* +* DESCRIPTION +* used to extract a 'typed' pointer from Quick List item. +* +* SYNOPSIS +*/ + +#define cl_item_obj(item_ptr, obj_ptr, item_field) \ + (void*)((uint8_t*)item_ptr - \ + ((uint8_t*)(&(obj_ptr)->item_field) - (uint8_t*)(obj_ptr))) +/* +* PARAMETERS +* item_ptr +* [in] Pointer to a cl_qlist structure. +* +* obj_ptr +* [in] object pointer +* +* item_field +* [in] object pointer field +* +* TypeOF_Obj +* +* RETURN VALUE +* returns a 'TypeOF_Obj ptr +* +* SEE ALSO +* Quick List +*********/ + +#endif /* _OSM_COMMON_H_ */ diff --git a/branches/WOF2-3/ulp/opensm/user/libvendor/ChangeLog b/branches/WOF2-3/ulp/opensm/user/libvendor/ChangeLog new file mode 100644 index 00000000..4ff3e099 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/libvendor/ChangeLog @@ -0,0 +1,64 @@ +2007-07-11 Hal Rosenstock + + * configure.in: Bump version to 2.2.1 + +2007-07-10 Sean Hefty + + * osm_vendor_ibumad.c: Use pkey index, rather than pkey + on umad_set_pkey call. Using index 0 for now. + +2007-05-07 Hal Rosenstock + + * osm_vendor_ibumad.(h c): Remove support for issmdisabled + +2007-03-29 Hal Rosenstock + + * configure.in: Bump version to 2.2.0 + +2007-03-27 Hal Rosenstock + + * osm_vendor_ibumad.(h c): Add support for issmdisabled + +2007-03-13 Hal Rosenstock + + * osm_vendor_ibumad.c: In osm_vendor_set_sm, set issmfd to + -1 on open error + +2007-03-12 Hal Rosenstock + + * osm_vendor_ibumad.c: In umad_receiver, display DR path of + sent MAD when it times out. In osm_vendor_send, simplify redundant + code. Cosmetic change to osm_log message in osm_vendor_bind. + +2007-02-20 Hal Rosenstock + + * configure.in: Bump version to 2.1.1 + +2007-02-20 Sasha Khapyorsky + + * osm_vendor_ibumad.(h c): Fix termination crash associated + with umad_receiver thread termination. + + * osm_vendor_mlx_sa.c, osm_vendor_mlx_sim.c: Changes for + compilation failures detected during ibutils/ibmgtsim building + +2007=01-10 Sasha Khapyorsky + + * osm_vendor_ibumad.c: Close umad port in + osm_vendor_delete so same process can reinitialize + and resuse vendor layer. + +2006-10-12 Hal Rosenstock + + * osm_vendor_ibumad.c (umad_receiver): Fix endian of LID + displayed in send timeout error message. + +2006-10-10 Hal Rosenstock + + * osm_vendor_ibumad.c: Print errors to stderr rather than + stdout. + +2006-09-28 Eitan Zahavi + + * osm_vendor_mlx_sa.c: Missing status on timeout SA query. + diff --git a/branches/WOF2-3/ulp/opensm/user/libvendor/Makefile b/branches/WOF2-3/ulp/opensm/user/libvendor/Makefile new file mode 100644 index 00000000..3ad42085 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/libvendor/Makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the Windows NT DDK +# +!INCLUDE ..\..\..\..\inc\openib.def + diff --git a/branches/WOF2-3/ulp/opensm/user/libvendor/SOURCES b/branches/WOF2-3/ulp/opensm/user/libvendor/SOURCES new file mode 100644 index 00000000..6fb3182b --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/libvendor/SOURCES @@ -0,0 +1,66 @@ +# Build the 'vendor' library for linking opensm.exe + +!if !defined(WINIBHOME) +WINIBHOME=..\..\..\.. +!endif + +LIBPATH=$(WINIBHOME)\bin\user\obj$(BUILD_ALT_DIR) + +!if defined(OSM_TARGET) +TARGETPATH=$(OSM_TARGET)\bin\user\obj$(BUILD_ALT_DIR) +!else +TARGETPATH=$(LIBPATH) +!endif + +!INCLUDE ..\mad-vendor.inc + +TARGETNAME=$(VENDOR_LIB) +TARGETTYPE=LIBRARY + +USE_NTDLL=1 +USE_NATIVE_EH=1 +OVR_DIR=..\addon + + +SOURCES= complib_files.c \ + winosm_common.c \ + $(VENDOR_SRC) + + +OSM_HOME=.. + +TARGETLIBS=\ +!if $(FREEBUILD) + $(LIBPATH)\*\complib.lib +!else + $(LIBPATH)\*\complibd.lib +!endif + +INCLUDES= \ + $(WINIBHOME)\inc; \ + $(WINIBHOME)\inc\user; \ + $(WINIBHOME)\inc\user\complib; \ + $(WINIBHOME)\inc\user\linux; \ + $(VENDOR_INC) \ + $(OSM_HOME); \ + $(OSM_HOME)\include; + +# Could be any special flag needed for this project +USER_C_FLAGS=$(USER_C_FLAGS) + +#Add preproccessor definitions +C_DEFINES=$(C_DEFINES) -D__WIN__ -DHAVE_CONFIG_H -D$(VENDOR_IF) + +!if !$(FREEBUILD) +C_DEFINES=$(C_DEFINES) -D_DEBUG -DDEBUG -DDBG +# in cl_types_osd.h '_DEBUG_' is defined by virture of '_DEBUG" being defined. +!else +# favor fast over default small; default is /Oxs. +MSC_OPTIMIZATION= /Oxt +!endif + +LINKER_FLAGS= $(LINKER_FLAGS) /DEF:$(VENDOR_LIB).exports + +MSC_WARNING_LEVEL= /W2 /wd4242 + + diff --git a/branches/WOF2-3/ulp/opensm/user/libvendor/complib_files.c b/branches/WOF2-3/ulp/opensm/user/libvendor/complib_files.c new file mode 100644 index 00000000..062d1a17 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/libvendor/complib_files.c @@ -0,0 +1,3 @@ + +#include <..\complib\cl_dispatcher.c> +#include <..\complib\cl_event_wheel.c> diff --git a/branches/WOF2-3/ulp/opensm/user/libvendor/libosmvendor.ver b/branches/WOF2-3/ulp/opensm/user/libvendor/libosmvendor.ver new file mode 100644 index 00000000..132452ae --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/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=3:3:0 diff --git a/branches/WOF2-3/ulp/opensm/user/libvendor/osm_pkt_randomizer.c b/branches/WOF2-3/ulp/opensm/user/libvendor/osm_pkt_randomizer.c new file mode 100644 index 00000000..6a690e9b --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/libvendor/osm_pkt_randomizer.c @@ -0,0 +1,323 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_pkt_randomizer_t. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +#ifndef __WIN__ +#include +#include +#endif + +/********************************************************************** + * Return TRUE if the path is in a fault path, and FALSE otherwise. + * By in a fault path the meaning is that there is a path in the fault + * paths that the given path includes it. + * E.g: if there is a fault path: 0,1,4 + * For the given path: 0,1,4,7 the return value will be TRUE, also for + * the given path: 0,1,4 the return value will be TRUE, but for + * the given paths: 0,1 or 0,3,1,4 - the return value will be FALSE. + **********************************************************************/ +boolean_t +__osm_pkt_randomizer_is_path_in_fault_paths(IN osm_log_t * p_log, + IN osm_dr_path_t * p_dr_path, + IN osm_pkt_randomizer_t * + p_pkt_rand) +{ + boolean_t res = FALSE, found_path; + osm_dr_path_t *p_found_dr_path; + uint8_t ind1, ind2; + + OSM_LOG_ENTER(p_log); + + for (ind1 = 0; ind1 < p_pkt_rand->num_paths_initialized; ind1++) { + found_path = TRUE; + p_found_dr_path = &(p_pkt_rand->fault_dr_paths[ind1]); + /* if the hop count of the found path is greater than the + hop count of the input path - then it is not part of it. + Check the next path. */ + if (p_found_dr_path->hop_count > p_dr_path->hop_count) + continue; + + /* go over all the ports in the found path and see if they match + the ports in the input path */ + for (ind2 = 0; ind2 <= p_found_dr_path->hop_count; ind2++) + if (p_found_dr_path->path[ind2] != + p_dr_path->path[ind2]) + found_path = FALSE; + + /* If found_path is TRUE then there is a full match of the path */ + if (found_path == TRUE) { + OSM_LOG(p_log, OSM_LOG_VERBOSE, + "Given path is in a fault path\n"); + res = TRUE; + break; + } + } + + OSM_LOG_EXIT(p_log); + return res; +} + +/********************************************************************** + * For a given dr_path - return TRUE if the path should be dropped, + * return FALSE otherwise. + * The check uses random criteria in order to determine whether or not + * the path should be dropped. + * First - if not all paths are initialized, it randomally chooses if + * to use this path as a fault path or not. + * Second - if the path is in the fault paths (meaning - it is equal + * to or includes one of the fault paths) - then it randomally chooses + * if to drop it or not. + **********************************************************************/ +boolean_t +__osm_pkt_randomizer_process_path(IN osm_log_t * p_log, + IN osm_pkt_randomizer_t * p_pkt_rand, + IN osm_dr_path_t * p_dr_path) +{ + boolean_t res = FALSE; + static boolean_t rand_value_init = FALSE; + static int rand_value; + boolean_t in_fault_paths; + uint8_t i; + char buf[BUF_SIZE]; + char line[BUF_SIZE]; + + OSM_LOG_ENTER(p_log); + + if (rand_value_init == FALSE) { + int seed; +#ifdef __WIN__ + SYSTEMTIME st; +#else + struct timeval tv; + struct timezone tz; +#endif /* __WIN__ */ + + /* initiate the rand_value according to timeofday */ + rand_value_init = TRUE; + +#ifdef __WIN__ + GetLocalTime(&st); + seed = st.wMilliseconds; +#else + gettimeofday(&tv, &tz); + seed = tv.tv_usec; +#endif /* __WIN__ */ + + 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/branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_al.c b/branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_al.c new file mode 100644 index 00000000..3980482a --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_al.c @@ -0,0 +1,1527 @@ +/* + * 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. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +/* + * Abstract: + * Implementation of osm_req_t. + * This object represents the generic attribute requester. + * This object is part of the opensm family of objects. + * + * Environment: + * Windows User Mode + * + * $Revision: 1.8 $ + */ + +#ifdef OSM_VENDOR_INTF_AL +/* + Next available error code: 0x300 +*/ + +#ifdef HAVE_CONFIG +#include +#endif + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +/****s* OpenSM: Vendor AL/osm_al_bind_info_t + * NAME + * osm_al_bind_info_t + * + * DESCRIPTION + * Structure containing bind information. + * + * SYNOPSIS + */ +typedef struct _osm_al_bind_info +{ + osm_vendor_t *p_vend; + void *client_context; + ib_qp_handle_t h_qp; + ib_mad_svc_handle_t h_svc; + uint8_t port_num; + ib_pool_key_t pool_key; + osm_vend_mad_recv_callback_t rcv_callback; + osm_vend_mad_send_err_callback_t send_err_callback; + osm_mad_pool_t *p_osm_pool; + ib_av_handle_t h_dr_av; + +} osm_al_bind_info_t; +/* + * FIELDS + * p_vend + * Pointer to the vendor object. + * + * client_context + * User's context passed during osm_bind + * + * h_qp + * Handle the QP for this bind. + * + * h_qp_svc + * Handle the QP mad service for this bind. + * + * port_num + * Port number (within the HCA) of the bound port. + * + * pool_key + * Pool key returned by all for this QP. + * + * h_dr_av + * Address vector handle used for all directed route SMPs. + * + * SEE ALSO + *********/ + + +inline static ib_api_status_t +__osm_al_convert_wcs( + IN ib_wc_status_t const wc_status ) +{ + switch( wc_status ) + { + case IB_WCS_SUCCESS: + return( IB_SUCCESS ); + + case IB_WCS_TIMEOUT_RETRY_ERR: + return( IB_TIMEOUT ); + + default: + return( IB_ERROR ); + } +} + + +void AL_API +__osm_set_vend_wrap( IN osm_al_bind_info_t* const p_bind, + IN ib_mad_element_t* const p_elem, + OUT osm_vend_wrap_t* p_vw) +{ + p_vw->h_bind = p_bind; + p_vw->size = p_elem->size; + p_vw->p_elem = p_elem; + p_vw->h_av = 0; + p_vw->p_resp_madw = NULL; + +} + + +static void AL_API +__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 AL_API +__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 AL_API +__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 ); +} + + +/* +Send_cb will handle the following cases: +Element Status | Send Response (no reponse expected) | Send Request (response expeceted) +================|======================================|======================== + ERROR | Free : AV , madw(send_err_cb) | Free:AV,madw,resp_madw + SUCCESS | Free : AV , madw | Free:AV,madw + +Element Status | Receive Response (no reponse expected) +================|=========================================== + ERROR | Free : AV , madw(send_err_cb) + SUCCESS | Free : AV , madw, resp_madw (both through rcv_callback) +*/ + +static void AL_API +__osm_al_send_callback( + IN const ib_mad_svc_handle_t h_mad_svc, + 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* p_vw = osm_madw_get_vend_ptr( p_madw ); + ib_mad_t *p_mad = ib_get_mad_buf( p_elem ); + ib_av_attr_t av_attr; + ib_pd_handle_t h_pd; + ib_api_status_t status_elem,status; + osm_madw_t *p_new_madw; + + OSM_LOG_ENTER( p_vend->p_log ); + UNUSED_PARAM(h_mad_svc); + + CL_ASSERT( p_vw ); + CL_ASSERT( p_vw->h_av ); + + /* since we use context1 safely, and its the only place that removes the + clean p_elem, p_madw, h_av no checks are required */ + + status_elem = __osm_al_convert_wcs(p_elem->status); + + osm_log( p_vend->p_log, OSM_LOG_DEBUG, + "%s[line %d]: Destroying av handle %p.\n", + __FUNCTION__, __LINE__, p_elem->h_av ); + + /* Check first if its a direct route handle , in this case skip */ + if (p_elem->h_av != p_bind->h_dr_av) + { + ib_destroy_av( p_elem->h_av ); + } + + /* Since the free order is first resp_madw then madw (PARENT) we should check + this case first */ + if (p_elem->resp_expected) + { + p_madw->status = status_elem; + if ( status_elem != IB_SUCCESS ) + { + /* + Return any wrappers to the pool that may have been + pre-emptively allocated to handle a receive. + */ + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "%s[line %d]: ERR 3333 " + "Mad Completed with WQE Error: %s.\n", + __FUNCTION__,__LINE__,ib_get_wc_status_str(p_elem->status)); + 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 + { + /* We are in response flow of receive, need to apply the rcv_callback. + The rcv_callback will free the resp_madw, req_madw, p_elem of + receive and request */ + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "%s[line %d]: " + "Mad is a response, processed in p_bind->rcv_callback\n", + __FUNCTION__, __LINE__ ); + p_new_madw = p_vw->p_resp_madw; + p_bind->rcv_callback( p_new_madw, p_bind->client_context, p_madw ); + } + } + else + { + uint64_t saved_trans_id = cl_ntoh64( p_mad->trans_id ); + + osm_log( p_vend->p_log, OSM_LOG_DEBUG, + "%s[line %d]: Returning MAD to pool, TID 0x%" PRIx64 ".\n", + __FUNCTION__, __LINE__, saved_trans_id ); + + osm_mad_pool_put( p_bind->p_osm_pool, p_madw ); + + if ( status_elem != IB_SUCCESS ) { + osm_log( p_vend->p_log, OSM_LOG_ERROR, + "%s[line %d]: ERR 3B0B request Mad (TID 0x%" PRIx64 ") failed '%s' " + "pool mads_out %u\n", + __FUNCTION__, __LINE__, saved_trans_id, ib_get_err_str(status_elem), + p_bind->p_osm_pool->mads_out); + } + } + OSM_LOG_EXIT( p_vend->p_log ); +} + + +/* + Receive_cb will be applied in the following cases : + Element Status | Receive Response (no reponse expected) | Receive Request (response expected) + ================|========================================= + ERROR | NOT APPLIED | NOT_APPLIED + SUCCESS | Free : Resp_madw , copy_req_madw | Allocate new_madw (for response then in send_cb free) + */ + +static void AL_API +__osm_al_rcv_callback( + IN const ib_mad_svc_handle_t h_mad_svc, + 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,*p_copy_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 ); + UNUSED_PARAM(h_mad_svc); + CL_ASSERT( p_elem->context1 == NULL ); + CL_ASSERT( p_elem->context2 == NULL ); + +#if 0 + osm_log( p_vend->p_log, OSM_LOG_VERBOSE, + "%s[line %d]: Handling Transaction: 0x%" PRIx64 " .\n", + __FUNCTION__, __LINE__, cl_ntoh64(p_elem->p_mad_buf->trans_id)); +#endif + + p_new_mad = ib_get_mad_buf( p_elem ); + + osm_log( p_vend->p_log, OSM_LOG_DEBUG, + "%s[line %d]: Acquired implicitly MAD %p.\n", + __FUNCTION__, __LINE__, p_new_mad); + /* + 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 = 0; /* FIXME: handle GRH */ + memset(&mad_addr.addr_type.gsi.grh_info, 0, + sizeof(mad_addr.addr_type.gsi.grh_info)); + } + + /* + If this MAD is a response to a previous request, + then grab our pre-allocated MAD wrapper. + Otherwise, allocate a new MAD wrapper. + context1 - contains the request madw + */ + if( ib_mad_is_response( p_new_mad ) ) + { + /* + The acquiring was done in the ib_get_mad_buf function. + If this is a request - then we impllicitly allocate the MAD. + In this case - it was allocated in the lower layer. The message + is for tracking down messages - locate how/where this mad was + allocated. + */ + osm_log( p_vend->p_log, OSM_LOG_DEBUG, + "%s[line %d]: " + "The Mad is a response, processed in __osm_al_send_callback\n", + __FUNCTION__,__LINE__); + 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 ); + p_new_vw = osm_madw_get_vend_ptr( p_new_madw ); + __osm_set_vend_wrap(p_bind,p_elem,p_new_vw); + } + else + { + osm_log( p_vend->p_log, OSM_LOG_DEBUG, + "%s[line %d]: " + "The Mad is a request, processed in p_bind->rcv_callback\n", + __FUNCTION__,__LINE__); + 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 ); + + __osm_set_vend_wrap(p_bind,p_elem,p_new_vw); + + 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, + ((osm_madw_t*)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 ) ); + } + else + p_vend->timeout = timeout; + + 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 = cl_zalloc( 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; + } + + status = osm_vendor_init( p_vend, p_log, timeout ); + if( status != IB_SUCCESS ) + { + cl_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 ); + cl_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 ) ); + } + /* attr size by verbs definition is required to be (uint32_t *) under opensm + it is only being set as 1 */ + status = ib_query_ca_by_guid( p_vend->h_al, ca_guid, NULL, + (uint32_t*)&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 = cl_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, + (uint32_t*)&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 ) ); + } + + 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 ) + cl_free( p_ca_info->p_attr ); + + cl_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 = cl_zalloc( sizeof(*p_ca_info) ); + if( p_ca_info == NULL ) + goto Exit; + + 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; + } + + 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 size_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 = cl_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. + * Also allocate p_vend->p_ca_info if not allocated and init it . + * + * 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; + size_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 ); + + /* + 1) Determine the number of CA's + 2) If not allready allocated - allocate an array big enough to hold the + ca info object, the ca info will be overwrite to contain the new ca info + 3) Call again to retrieve the guids. + */ + status = __osm_vendor_get_ca_guids( p_vend, &p_ca_guid, &ca_count ); + + if (p_vend->p_ca_info == NULL) + { + p_vend->p_ca_info = cl_zalloc( 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; + } + } + + 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 ); + /* convert lid to host order */ + p_attr_array[port_count].lid = cl_ntoh16(p_attr_array[port_count].lid); + port_count++; + } + } + } + else + { + status = IB_INSUFFICIENT_MEMORY; + } + + *p_num_ports = total_ports; + + Exit: + if( p_ca_guid ) + cl_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 ) +{ + cl_memclr( p_av, 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", + cl_ntoh64( 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 = cl_zalloc( 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; + } + + 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. + */ + cl_memclr( &qp_create, 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 ) + { + 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 ) ); + cl_free( p_bind ); + p_bind = 0; + goto Exit; + } + + CL_ASSERT( p_bind->h_qp ); + CL_ASSERT( p_bind->pool_key ); + + cl_memclr( &mad_svc, 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; + +#define _NEW 1 + +#if _NEW + if (p_user_bind->is_responder) { + mad_svc.method_array[IB_MAD_METHOD_GET] = TRUE; + mad_svc.method_array[IB_MAD_METHOD_SET] = TRUE; + if (p_user_bind->mad_class == IB_MCLASS_SUBN_ADM) { + mad_svc.method_array[IB_MAD_METHOD_GETTABLE] = TRUE; + mad_svc.method_array[IB_MAD_METHOD_DELETE] = TRUE; +#ifdef DUAL_SIDED_RMPP + mad_svc.method_array[IB_MAD_METHOD_GETMULTI] = TRUE; +#endif + /* Add in IB_MAD_METHOD_GETTRACETABLE when supported by OpenSM */ + } + } +#else + 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; + +#ifdef DUAL_SIDED_RMPP + mad_svc.method_array[IB_MAD_METHOD_GETMULTI] = TRUE; +#endif +#endif + + /* Add in IB_MAD_METHOD_GETTRACETABLE when supported by OpenSM */ +#if _NEW + if (p_user_bind->is_report_processor) + mad_svc.method_array[IB_MAD_METHOD_REPORT] = TRUE; + + if (p_user_bind->is_trap_processor) { + mad_svc.method_array[IB_MAD_METHOD_TRAP] = TRUE; + mad_svc.method_array[IB_MAD_METHOD_TRAP_REPRESS] = TRUE; + } +#endif + status = ib_reg_mad_svc( p_bind->h_qp, &mad_svc, &p_bind->h_svc ); + + if( status != IB_SUCCESS ) + { + 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 ) ); + cl_free( p_bind ); + p_bind = 0; + 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 ) ); + + cl_free( p_bind ); + p_bind = 0; + 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 ); +} + + +/* osm_vendor_unbind is added due to OSM-1.8.0 gen2 merging + The functionality will be added when the Gen2 osm_vendor_unbind + will be implemented. +*/ +void +osm_vendor_unbind( + 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; + + OSM_LOG_ENTER( p_vend->p_log ); + + 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 ) +{ + 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", 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. + In order to seperate the receive callback and the send callback + dependency , we copy the request madw and send it as context2 + Which in time in the receive callback will replace the req_madw + to allow avoid races with send callback + */ + 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 ) + { + cl_memclr( &av, 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 ); + /* Since we in immediate error the vendor layer is expected to handle the + rollback , i.e free of madw */ + if (p_madw) + osm_mad_pool_put( p_bind->p_osm_pool, p_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, cleaning up (%s)\n", + ib_get_err_str( status ) ); + + /* When we destroy the av - we should take the pointer from local allocation + since we do not "trust" IBAL to keep track in p_elem */ + + if (p_vw->h_av && (p_vw->h_av != p_bind->h_dr_av) ) + { + osm_log( p_vend->p_log, OSM_LOG_DEBUG, + "%s[line %d] Destroying av handle %p.\n", + __FUNCTION__,__LINE__,p_vw->h_av ); + ib_destroy_av( p_vw->h_av ); + } + + if( p_vw->p_resp_madw ) + osm_mad_pool_put( p_bind->p_osm_pool, p_vw->p_resp_madw ); + + /* Immediate error: the vendor layer is expected to handle the + rollback, i.e free of madw */ + if (p_madw) + osm_mad_pool_put( p_bind->p_osm_pool, p_madw ); + } + + 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; + + OSM_LOG_ENTER( p_vend->p_log ); + + 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_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 ); + + cl_memclr( &attr_mod, 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/branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_ibumad.c b/branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_ibumad.c new file mode 100644 index 00000000..6dd67f98 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_ibumad.c @@ -0,0 +1,1198 @@ +/* + * Copyright (c) 2004-2009 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) 2009 HNR Consulting. All rights reserved. + * Copyright (c) 2009 Sun Microsystems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_vendor_t (for umad). + * This object represents the OpenIB vendor layer. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#ifdef OSM_VENDOR_INTF_OPENIB + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/****s* OpenSM: Vendor UMAD/osm_umad_bind_info_t + * NAME + * osm_umad_bind_info_t + * + * DESCRIPTION + * Structure containing bind information. + * + * SYNOPSIS + */ +typedef struct _osm_umad_bind_info { + osm_vendor_t *p_vend; + void *client_context; + osm_mad_pool_t *p_mad_pool; + osm_vend_mad_recv_callback_t mad_recv_callback; + osm_vend_mad_send_err_callback_t send_err_callback; + ib_net64_t port_guid; + int port_id; + int agent_id; + int agent_id1; /* SMI requires two agents */ + int timeout; + int max_retries; +} 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, cl_ntoh64(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(0x00000000ffffffffULL)); + 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 * OSM_API 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; + uint32_t status; + + 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"); + _set_errno(0); + 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); + _set_errno(0); + 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 >= OSM_UMAD_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 (%d bytes) failed -- dropping packet\n", + MAX(length, MAD_BLOCK_SIZE)); + 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 ((status=umad_status(p_madw->vend_wrap.umad))) { + + if (mad->mgmt_class != IB_MCLASS_SUBN_DIR) { + /* LID routed */ + OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5410: " + "Send completed with error(%u) -- dropping\n" + "\t\t\tClass 0x%x, Method 0x%X, Attr 0x%X, " + "TID 0x%" PRIx64 ", LID %u\n", + status, mad->mgmt_class, mad->method, + cl_ntoh16(mad->attr_id), + cl_ntoh64(mad->trans_id), + 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 Send completed with error(%u) -- dropping\n" + "\t\t\tMethod 0x%X, Attr 0x%X, TID 0x%" PRIx64 + ", Hop Ptr: 0x%X\n", + status, mad->method, cl_ntoh16(mad->attr_id), + cl_ntoh64(mad->trans_id), 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 */ +#ifdef __WIN__ + 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); +#else + 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); +#endif + } + + 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 */ +#ifdef __WIN__ + pthread_mutex_lock(&p_vend->cb_mutex); + (*p_bind->mad_recv_callback) (p_madw, p_bind->client_context, + p_req_madw); + pthread_mutex_unlock(&p_vend->cb_mutex); +#else /* !__WIN__ */ + 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); +#endif + } + + 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; + +#ifdef HAVE_LIBPTHREADS + if (pthread_create(&p_ur->tid, NULL, umad_receiver, p_ur) < 0) + return -1; + + return 0; +#else + { + ib_api_status_t status; + + status = cl_thread_init( &p_ur->tid, + (void*)umad_receiver, + (void*)p_ur, + "umad_recvr" ); + + if (status != IB_SUCCESS) { + OSM_LOG(p_ur->p_log, OSM_LOG_ERROR, + "ERR: thread 'umad_recvr' start failure: %s\n", + ib_get_err_str(status)); + } + return (status != IB_SUCCESS ? -1 : 0); + } +#endif +} + +static void umad_receiver_stop(umad_receiver_t * p_ur) +{ +#ifdef HAVE_LIBPTHREADS + pthread_cancel(p_ur->tid); + pthread_join(p_ur->tid, NULL); + p_ur->tid = 0; +#else + /* XXX hangs current thread - suspect umad_recv() ignoring wakeup. + cl_thread_destroy(&p_ur->tid); + */ +#endif + 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\n", + 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 = 0, i, j, k; + + 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 attributes */ + 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; + if (attr->num_pkeys && attr->p_pkey_table) { + if (attr->num_pkeys > ca.ports[j]->pkeys_size) + attr->num_pkeys = ca.ports[j]->pkeys_size; + for (k = 0; k < attr->num_pkeys; k++) + attr->p_pkey_table[k] = + cl_hton16(ca.ports[j]->pkeys[k]); + } + attr->num_pkeys = ca.ports[j]->pkeys_size; + attr++; + if (attr - p_attr_array > *p_num_ports) { + done = 1; + break; + } + } + umad_release_ca(&ca); + } + } + + *p_num_ports = attr - p_attr_array; + +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_PORTS_PER_CA + 1)) < 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 < OSM_UMAD_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; + } +#ifndef __WIN__ + 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; + } +#endif + 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; + p_bind->timeout = p_user_bind->timeout ? p_user_bind->timeout : + p_vend->timeout; + p_bind->max_retries = p_user_bind->retries ? p_user_bind->retries : + p_vend->max_retries; + + 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 >= OSM_UMAD_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 >= OSM_UMAD_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 (p_vw->umad ? umad_get_mad(p_vw->umad) : NULL); +} + +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; + } + /* GS 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 GS 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_bind->timeout : 0, + p_bind->max_retries)) < 0) { + OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5430: " + "Send p_madw = %p of size %d TID 0x%" PRIx64 " failed %d (%m)\n", + p_madw, sent_mad_size, cl_ntoh64(p_mad->trans_id), 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); +} + +#ifndef __WIN__ + +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); +} + +#else /* ! __WIN__ */ + +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); + + OSM_LOG_EXIT(p_vend->p_log); +} +#endif /* ! __WIN__ */ + +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/branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_ibumad_sa.c b/branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_ibumad_sa.c new file mode 100644 index 00000000..bfd6307d --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_ibumad_sa.c @@ -0,0 +1,733 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2007,2009 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Copyright (c) 2009 HNR Consulting. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include + +/* this struct is the internal rep of the bind handle */ +typedef struct _osmv_sa_bind_info { + osm_bind_handle_t h_bind; + osm_log_t *p_log; + osm_vendor_t *p_vendor; + osm_mad_pool_t *p_mad_pool; + cl_event_t sync_event; + time_t last_lids_update_sec; +} osmv_sa_bind_info_t; + +/* + Call back on new mad received: + + We basically only need to set the context of the query. + Or report an error. + + A pointer to the actual context of the request (a copy of the oriignal + request structure) is attached as the p_madw->context.ni_context.node_guid +*/ +static void +__osmv_sa_mad_rcv_cb(IN osm_madw_t * p_madw, + IN void *bind_context, IN osm_madw_t * p_req_madw) +{ + osmv_sa_bind_info_t *p_bind = (osmv_sa_bind_info_t *) bind_context; + osmv_query_req_t *p_query_req_copy = NULL; + osmv_query_res_t query_res; + ib_sa_mad_t *p_sa_mad; + ib_net16_t mad_status; + + OSM_LOG_ENTER(p_bind->p_log); + + if (!p_req_madw) { + OSM_LOG(p_bind->p_log, OSM_LOG_DEBUG, + "Ignoring a non-response mad\n"); + osm_mad_pool_put(p_bind->p_mad_pool, p_madw); + goto Exit; + } + + /* obtain the sent context since we store it during send in the ni_ctx */ + p_query_req_copy = + (osmv_query_req_t *) (uintptr_t)(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 = %u / %u (%u)\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 *) (uintptr_t)(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); + + 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; + bind_info.timeout = OSM_DEFAULT_TRANS_TIMEOUT_MILLISEC; + bind_info.retries = OSM_DEFAULT_RETRY_COUNT; + + /* 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)); + if (!p_query_req_copy) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 5511: " + "Unable to acquire memory for query copy\n"); + osm_mad_pool_put(p_bind->p_mad_pool, p_madw); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + *p_query_req_copy = *p_query_req; + p_madw->context.ni_context.node_guid = + (ib_net64_t) (uintptr_t)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) +{ + union { + 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; +#endif + ib_class_port_info_t class_port_info; + } u; + osmv_sa_mad_data_t sa_mad_data; + osmv_sa_bind_info_t *p_bind = (osmv_sa_bind_info_t *) h_bind; + osmv_user_query_t *p_user_query; +#ifdef DUAL_SIDED_RMPP + osmv_multipath_req_t *p_mpr_req; + int i, j; +#endif + 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 = &u.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 = &u.svc_rec; + memcpy(u.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 = &u.svc_rec; + u.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 = &u.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 = &u.node_rec; + u.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 = &u.port_info; + u.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(&u.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 | IB_PR_COMPMASK_NUMBPATH); + u.path_rec.num_path = 0x7f; + sa_mad_data.p_attr = &u.path_rec; + ib_gid_set_default(&u.path_rec.dgid, + ((osmv_guid_pair_t *) (p_query_req-> + p_query_input))-> + dest_guid); + ib_gid_set_default(&u.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(&u.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 | IB_PR_COMPMASK_NUMBPATH); + u.path_rec.num_path = 0x7f; + sa_mad_data.p_attr = &u.path_rec; + memcpy(&u.path_rec.dgid, + &((osmv_gid_pair_t *) (p_query_req->p_query_input))-> + dest_gid, sizeof(ib_gid_t)); + memcpy(&u.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(&u.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 = &u.path_rec; + u.path_rec.dlid = + ((osmv_lid_pair_t *) (p_query_req->p_query_input))-> + dest_lid; + u.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(&u.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 = &u.multipath_rec; + sa_mad_data.comp_mask = p_mpr_req->comp_mask; + u.multipath_rec.num_path = p_mpr_req->num_path; + if (p_mpr_req->reversible) + u.multipath_rec.num_path |= 0x80; + else + u.multipath_rec.num_path &= ~0x80; + u.multipath_rec.pkey = p_mpr_req->pkey; + ib_multipath_rec_set_sl(&u.multipath_rec, p_mpr_req->sl); + ib_multipath_rec_set_qos_class(&u.multipath_rec, 0); + u.multipath_rec.independence = p_mpr_req->independence; + u.multipath_rec.sgid_count = p_mpr_req->sgid_count; + u.multipath_rec.dgid_count = p_mpr_req->dgid_count; + j = 0; + for (i = 0; i < p_mpr_req->sgid_count; i++, j++) + u.multipath_rec.gids[j] = p_mpr_req->gids[j]; + for (i = 0; i < p_mpr_req->dgid_count; i++, j++) + u.multipath_rec.gids[j] = p_mpr_req->gids[j]; + break; +#endif + + default: + OSM_LOG(p_log, OSM_LOG_ERROR, "DBG:001 UNKNOWN 0x%x (%d)\n", + p_query_req->query_type, p_query_req->query_type); + 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/branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_mlx.c b/branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_mlx.c new file mode 100644 index 00000000..4486f00b --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_mlx.c @@ -0,0 +1,768 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * 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/branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_mlx_dispatcher.c b/branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_mlx_dispatcher.c new file mode 100644 index 00000000..ad6ed835 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_mlx_dispatcher.c @@ -0,0 +1,710 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include + +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 = ib_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/branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_mlx_hca.c b/branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_mlx_hca.c new file mode 100644 index 00000000..fa168ced --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_mlx_hca.c @@ -0,0 +1,522 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#if defined(OSM_VENDOR_INTF_MTL) | defined(OSM_VENDOR_INTF_TS) +#undef IN +#undef OUT +#include +#include +#include +#include +#include +#include + +/******************************************************************************** + * + * Provide the functionality for selecting an HCA Port and Obtaining it's guid. + * + ********************************************************************************/ + +typedef struct _osm_ca_info { + ib_net64_t guid; + size_t attr_size; + ib_ca_attr_t *p_attr; +} osm_ca_info_t; + +/********************************************************************** + * Convert the given GID to GUID by copy of it's upper 8 bytes + **********************************************************************/ +ib_api_status_t +__osm_vendor_gid_to_guid(IN u_int8_t * gid, OUT VAPI_gid_t * guid) +{ + memcpy(guid, gid + 8, 8); + return (IB_SUCCESS); +} + +/********************************************************************** + * Returns a pointer to the port attribute of the specified port + * owned by this CA. + ************************************************************************/ +static ib_port_attr_t *__osm_ca_info_get_port_attr_ptr(IN const osm_ca_info_t * + const p_ca_info, + IN const uint8_t index) +{ + return (&p_ca_info->p_attr->p_port_attr[index]); +} + +/******************************************************************************** + * get the CA names available on the system + * NOTE: user of this function needs to deallocate p_hca_ids after usage. + ********************************************************************************/ +static ib_api_status_t +__osm_vendor_get_ca_ids(IN osm_vendor_t * const p_vend, + IN VAPI_hca_id_t ** const p_hca_ids, + IN uint32_t * const p_num_guids) +{ + ib_api_status_t status; + VAPI_ret_t vapi_res; + + OSM_LOG_ENTER(p_vend->p_log); + + CL_ASSERT(p_hca_ids); + CL_ASSERT(p_num_guids); + + /* first call is just to get the number */ + vapi_res = EVAPI_list_hcas(0, p_num_guids, NULL); + + /* fail ? */ + if (vapi_res == VAPI_EINVAL_PARAM) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__osm_vendor_get_ca_ids: ERR 3D08: : " + "Bad parameter in calling: EVAPI_list_hcas. (%d)\n", + vapi_res); + status = IB_ERROR; + goto Exit; + } + + /* NO HCA ? */ + if (*p_num_guids == 0) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__osm_vendor_get_ca_ids: ERR 3D09: " + "No available channel adapters.\n"); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + /* allocate and really call - user of this function needs to deallocate it */ + *p_hca_ids = + (VAPI_hca_id_t *) malloc(*p_num_guids * sizeof(VAPI_hca_id_t)); + + /* now call it really */ + vapi_res = EVAPI_list_hcas(*p_num_guids, p_num_guids, *p_hca_ids); + + /* too many ? */ + if (vapi_res == VAPI_EAGAIN) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__osm_vendor_get_ca_ids: ERR 3D10: " + "More CA GUIDs than allocated array (%d).\n", + *p_num_guids); + status = IB_ERROR; + goto Exit; + } + + /* fail ? */ + if (vapi_res != VAPI_OK) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__osm_vendor_get_ca_ids: ERR 3D11: : " + "Bad parameter in calling: EVAPI_list_hcas.\n"); + status = IB_ERROR; + goto Exit; + } + + if (osm_log_is_active(p_vend->p_log, OSM_LOG_DEBUG)) { + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "__osm_vendor_get_ca_ids: " + "Detected %u local channel adapters.\n", *p_num_guids); + } + + status = IB_SUCCESS; + +Exit: + OSM_LOG_EXIT(p_vend->p_log); + return (status); +} + +/********************************************************************** + * Initialize an Info Struct for the Given HCA by its Id + **********************************************************************/ +static ib_api_status_t +__osm_ca_info_init(IN osm_vendor_t * const p_vend, + IN VAPI_hca_id_t ca_id, OUT osm_ca_info_t * const p_ca_info) +{ + ib_api_status_t status = IB_ERROR; + VAPI_ret_t vapi_res; + VAPI_hca_hndl_t hca_hndl; + VAPI_hca_vendor_t hca_vendor; + VAPI_hca_cap_t hca_cap; + VAPI_hca_port_t hca_port; + uint8_t port_num; + IB_gid_t *p_port_gid; + uint16_t maxNumGids; + + OSM_LOG_ENTER(p_vend->p_log); + + /* get the HCA handle */ + vapi_res = EVAPI_get_hca_hndl(ca_id, &hca_hndl); + if (vapi_res != VAPI_OK) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__osm_ca_info_init: ERR 3D05: " + "Fail to get HCA handle (%u).\n", vapi_res); + goto Exit; + } + + if (osm_log_is_active(p_vend->p_log, OSM_LOG_DEBUG)) { + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "__osm_ca_info_init: " "Querying CA %s.\n", ca_id); + } + + /* query and get the HCA capability */ + vapi_res = VAPI_query_hca_cap(hca_hndl, &hca_vendor, &hca_cap); + if (vapi_res != VAPI_OK) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__osm_ca_info_init: ERR 3D06: " + "Fail to get HCA Capabilities (%u).\n", vapi_res); + goto Exit; + } + + /* get the guid of the HCA */ + memcpy(&(p_ca_info->guid), hca_cap.node_guid, 8 * sizeof(u_int8_t)); + p_ca_info->attr_size = 1; + p_ca_info->p_attr = (ib_ca_attr_t *) malloc(sizeof(ib_ca_attr_t)); + memcpy(&(p_ca_info->p_attr->ca_guid), hca_cap.node_guid, + 8 * sizeof(u_int8_t)); + + /* now obtain the attributes of the ports */ + p_ca_info->p_attr->num_ports = hca_cap.phys_port_num; + p_ca_info->p_attr->p_port_attr = + (ib_port_attr_t *) malloc(hca_cap.phys_port_num * + sizeof(ib_port_attr_t)); + + for (port_num = 0; port_num < p_ca_info->p_attr->num_ports; port_num++) { + + /* query the port attributes */ + vapi_res = + VAPI_query_hca_port_prop(hca_hndl, port_num + 1, &hca_port); + if (vapi_res != VAPI_OK) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__osm_ca_info_init: ERR 3D07: " + "Fail to get HCA Port Attributes (%d).\n", + vapi_res); + goto Exit; + } + + /* first call to know the size of the gid table */ + vapi_res = + VAPI_query_hca_gid_tbl(hca_hndl, port_num + 1, 0, + &maxNumGids, NULL); + p_port_gid = (IB_gid_t *) malloc(maxNumGids * sizeof(IB_gid_t)); + + vapi_res = + VAPI_query_hca_gid_tbl(hca_hndl, port_num + 1, maxNumGids, + &maxNumGids, p_port_gid); + if (vapi_res != VAPI_OK) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__osm_ca_info_init: ERR 3D12: " + "Fail to get HCA Port GID (%d).\n", vapi_res); + goto Exit; + } + + __osm_vendor_gid_to_guid(p_port_gid[0], + (IB_gid_t *) & p_ca_info->p_attr-> + p_port_attr[port_num].port_guid); + p_ca_info->p_attr->p_port_attr[port_num].lid = hca_port.lid; + p_ca_info->p_attr->p_port_attr[port_num].link_state = + hca_port.state; + p_ca_info->p_attr->p_port_attr[port_num].sm_lid = + hca_port.sm_lid; + + free(p_port_gid); + } + + status = IB_SUCCESS; +Exit: + OSM_LOG_EXIT(p_vend->p_log); + return (status); +} + +void +osm_ca_info_destroy(IN osm_vendor_t * const p_vend, + IN osm_ca_info_t * const p_ca_info, IN uint8_t num_ca) +{ + osm_ca_info_t *p_ca; + uint8_t i; + + OSM_LOG_ENTER(p_vend->p_log); + + for (i = 0; i < num_ca; i++) { + p_ca = &p_ca_info[i]; + + if (NULL != p_ca->p_attr) { + if (0 != p_ca->p_attr->num_ports) { + free(p_ca->p_attr->p_port_attr); + } + + free(p_ca->p_attr); + } + } + + free(p_ca_info); + + OSM_LOG_EXIT(p_vend->p_log); +} + +/********************************************************************** + * Fill in the array of port_attr with all available ports on ALL the + * avilable CAs on this machine. + * ALSO - + * Update the vendor object list of ca_info structs + **********************************************************************/ +ib_api_status_t +osm_vendor_get_all_port_attr(IN osm_vendor_t * const p_vend, + IN ib_port_attr_t * const p_attr_array, + IN uint32_t * const p_num_ports) +{ + ib_api_status_t status; + + uint32_t ca; + uint32_t ca_count = 0; + uint32_t port_count = 0; + uint8_t port_num; + uint32_t total_ports = 0; + VAPI_hca_id_t *p_ca_ids = NULL; + osm_ca_info_t *p_ca_infos = NULL; + uint32_t attr_array_sz = *p_num_ports; + + OSM_LOG_ENTER(p_vend->p_log); + + CL_ASSERT(p_vend); + + /* determine the number of CA's */ + status = __osm_vendor_get_ca_ids(p_vend, &p_ca_ids, &ca_count); + if (status != IB_SUCCESS) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_get_all_port_attr: ERR 3D13: " + "Fail to get CA Ids.\n"); + goto Exit; + } + + /* Allocate an array big enough to hold the ca info objects */ + p_ca_infos = malloc(ca_count * sizeof(osm_ca_info_t)); + if (p_ca_infos == NULL) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_get_all_port_attr: ERR 3D14: " + "Unable to allocate CA information array.\n"); + goto Exit; + } + + memset(p_ca_infos, 0, ca_count * sizeof(osm_ca_info_t)); + + /* + * For each CA, retrieve the CA info attributes + */ + for (ca = 0; ca < ca_count; ca++) { + status = + __osm_ca_info_init(p_vend, p_ca_ids[ca], &p_ca_infos[ca]); + if (status != IB_SUCCESS) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_get_all_port_attr: ERR 3D15: " + "Unable to initialize CA Info object (%s).\n", + ib_get_err_str(status)); + goto Exit; + } + total_ports += p_ca_infos[ca].p_attr->num_ports; + } + + *p_num_ports = total_ports; + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "osm_vendor_get_all_port_attr: total ports:%u \n", total_ports); + + /* + * If the user supplied enough storage, return the port guids, + * otherwise, return the appropriate error. + */ + if (attr_array_sz >= total_ports) { + for (ca = 0; ca < ca_count; ca++) { + uint32_t num_ports; + + num_ports = p_ca_infos[ca].p_attr->num_ports; + + for (port_num = 0; port_num < num_ports; port_num++) { + p_attr_array[port_count] = + *__osm_ca_info_get_port_attr_ptr(&p_ca_infos + [ca], + port_num); + port_count++; + } + } + } else { + status = IB_INSUFFICIENT_MEMORY; + goto Exit; + } + + status = IB_SUCCESS; + +Exit: + if (p_ca_ids) + free(p_ca_ids); + + if (p_ca_infos) { + osm_ca_info_destroy(p_vend, p_ca_infos, ca_count); + } + + OSM_LOG_EXIT(p_vend->p_log); + return (status); +} + +/********************************************************************** + * Given the vendor obj and a guid + * return the ca id and port number that have that guid + **********************************************************************/ + +ib_api_status_t +osm_vendor_get_guid_ca_and_port(IN osm_vendor_t * const p_vend, + IN ib_net64_t const guid, + OUT VAPI_hca_hndl_t * p_hca_hndl, + OUT VAPI_hca_id_t * p_hca_id, + OUT uint8_t * p_hca_idx, + OUT uint32_t * p_port_num) +{ + + ib_api_status_t status; + VAPI_hca_id_t *p_ca_ids = NULL; + VAPI_ret_t vapi_res; + VAPI_hca_hndl_t hca_hndl; + VAPI_hca_vendor_t hca_vendor; + VAPI_hca_cap_t hca_cap; + IB_gid_t *p_port_gid = NULL; + uint16_t maxNumGids; + ib_net64_t port_guid; + uint32_t ca, portIdx, ca_count; + + OSM_LOG_ENTER(p_vend->p_log); + + CL_ASSERT(p_vend); + + /* + * 1) Determine the number of CA's + * 2) Allocate an array big enough to hold the ca info objects. + * 3) Call again to retrieve the guids. + */ + status = __osm_vendor_get_ca_ids(p_vend, &p_ca_ids, &ca_count); + if (status != IB_SUCCESS) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_get_guid_ca_and_port: ERR 3D16: " + "Fail to get CA Ids.\n"); + goto Exit; + } + + /* + * For each CA, retrieve the CA info attributes + */ + for (ca = 0; ca < ca_count; ca++) { + /* get the HCA handle */ + vapi_res = EVAPI_get_hca_hndl(p_ca_ids[ca], &hca_hndl); + if (vapi_res != VAPI_OK) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_get_guid_ca_and_port: ERR 3D17: " + "Fail to get HCA handle (%u).\n", vapi_res); + goto Exit; + } + + /* get the CA attributes - to know how many ports it has: */ + if (osm_log_is_active(p_vend->p_log, OSM_LOG_DEBUG)) { + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "osm_vendor_get_guid_ca_and_port: " + "Querying CA %s.\n", p_ca_ids[ca]); + } + + /* query and get the HCA capability */ + vapi_res = VAPI_query_hca_cap(hca_hndl, &hca_vendor, &hca_cap); + if (vapi_res != VAPI_OK) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_get_guid_ca_and_port: ERR 3D18: " + "Fail to get HCA Capabilities (%u).\n", + vapi_res); + goto Exit; + } + + /* go over all ports - to obtail their guids */ + for (portIdx = 0; portIdx < hca_cap.phys_port_num; portIdx++) { + vapi_res = + VAPI_query_hca_gid_tbl(hca_hndl, portIdx + 1, 0, + &maxNumGids, NULL); + p_port_gid = + (IB_gid_t *) malloc(maxNumGids * sizeof(IB_gid_t)); + + /* get the port guid */ + vapi_res = + VAPI_query_hca_gid_tbl(hca_hndl, portIdx + 1, + maxNumGids, &maxNumGids, + p_port_gid); + if (vapi_res != VAPI_OK) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_get_guid_ca_and_port: ERR 3D19: " + "Fail to get HCA Port GID (%d).\n", + vapi_res); + goto Exit; + } + + /* convert to SF style */ + __osm_vendor_gid_to_guid(p_port_gid[0], + (VAPI_gid_t *) & port_guid); + + /* finally did we find it ? */ + if (port_guid == guid) { + *p_hca_hndl = hca_hndl; + memcpy(p_hca_id, p_ca_ids[ca], + sizeof(VAPI_hca_id_t)); + *p_hca_idx = ca; + *p_port_num = portIdx + 1; + status = IB_SUCCESS; + goto Exit; + } + + free(p_port_gid); + p_port_gid = NULL; + } /* ALL PORTS */ + } /* all HCAs */ + + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_get_guid_ca_and_port: ERR 3D20: " + "Fail to find HCA and Port for Port Guid 0x%" PRIx64 "\n", + cl_ntoh64(guid)); + status = IB_INVALID_GUID; + +Exit: + if (p_ca_ids != NULL) + free(p_ca_ids); + if (p_port_gid != NULL) + free(p_port_gid); + OSM_LOG_EXIT(p_vend->p_log); + return (status); +} + +#endif diff --git a/branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_mlx_hca_sim.c b/branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_mlx_hca_sim.c new file mode 100644 index 00000000..91efafae --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_mlx_hca_sim.c @@ -0,0 +1,862 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#if defined(OSM_VENDOR_INTF_SIM) +#undef IN +#undef OUT + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/****************************************************************************** +* +* Provides the functionality for selecting an HCA Port and Obtaining it's guid. +* This version is based on $IBMGTSIM_DIR/$IBMGTSIM_NODE file system. +* This is a mimic of the OpenIB gen1 file system +* +******************************************************************************/ + +char *__get_simulator_dir(void) +{ + static char *ibmgtSimDir = NULL; + static char *defaultIbmgtSimDir = "/tmp/ibmgtsim"; + static char *ibmgtSimNode = NULL; + static char dirName[1024]; + + /* we use the first pointer to know if we were here */ + if (ibmgtSimDir == NULL) { + /* obtain the simulator directory */ + ibmgtSimDir = getenv("IBMGTSIM_DIR"); + if (ibmgtSimDir == NULL) { + printf + ("-W- Environment variable: IBMGTSIM_DIR does not exist.\n"); + printf + (" Please create one used by the simulator.\n"); + printf(" Using /tmp/ibmgtsim as default.\n"); + ibmgtSimDir = defaultIbmgtSimDir; + } + + /* obtain the node name we simulate */ + ibmgtSimNode = getenv("IBMGTSIM_NODE"); + if (ibmgtSimNode == NULL) { + printf + ("-W- Environment variable: IBMGTSIM_NODE does not exist.\n"); + printf + (" This variable should be the name of the node you wish to simulate.\n"); + printf(" Using H-1 as default.\n"); + ibmgtSimNode = "H-1"; + } + sprintf(dirName, "%s/%s", ibmgtSimDir, ibmgtSimNode); + } + + return dirName; +} + +typedef struct _osm_ca_info { + ib_net64_t guid; + size_t attr_size; + ib_ca_attr_t *p_attr; + +} osm_ca_info_t; + +/********************************************************************** + * Returns a pointer to the port attribute of the specified port + * owned by this CA. + ************************************************************************/ +static ib_port_attr_t *__osm_ca_info_get_port_attr_ptr(IN const osm_ca_info_t * + const p_ca_info, + IN const uint8_t index) +{ + return (&p_ca_info->p_attr->p_port_attr[index]); +} + +/********************************************************************** + * Obtain the number of local CAs by scanning /proc/infiniband/core + **********************************************************************/ +int __hca_sim_get_num_cas(void) +{ + int num_cas = 0; + DIR *dp; + struct dirent *ep; + + dp = opendir(__get_simulator_dir()); + + if (dp != NULL) { + while ((ep = readdir(dp))) { + /* CAs are directories with the format ca[1-9][0-9]* */ + /* if ((ep->d_type == DT_DIR) && !strncmp(ep->d_name, "ca", 2)) */ + if (!strncmp(ep->d_name, "ca", 2)) { + num_cas++; + } + } + closedir(dp); + } else { + printf("__hca_sim_get_num_cas: ERROR : ail to open dir %s\n", + __get_simulator_dir()); + exit(1); + } + + if (!num_cas) + exit(1); + return num_cas; +} + +/* + name: InfiniHost0 + provider: tavor + node GUID: 0002:c900:0120:3470 + ports: 2 + vendor ID: 0x2c9 + device ID: 0x5a44 + HW revision: 0xa1 + FW revision: 0x300020080 +*/ +typedef struct _sim_ca_info { + char name[32]; + char provider[32]; + uint64_t guid; + uint8_t num_ports; + uint32_t vend_id; + uint16_t dev_id; + uint16_t rev_id; + uint64_t fw_rev; +} sim_ca_info_t; + +/********************************************************************** + * Parse the CA Info file available in ibmgtSimDir/caN/info + **********************************************************************/ +static ib_api_status_t +__parse_ca_info_file(IN osm_vendor_t * const p_vend, + IN uint32_t idx, OUT sim_ca_info_t * sim_ca_info) +{ + ib_api_status_t status = IB_ERROR; + int info_file; + char file_name[256]; + char file_buffer[3200]; + char *p_ch; + int g1, g2, g3, g4; + int num_ports; + uint32_t len; + + OSM_LOG_ENTER(p_vend->p_log); + + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "__parse_ca_info_file: " "Querying CA %d.\n", idx); + + /* we use the proc file system so we must be able to open the info file .. */ + sprintf(file_name, "%s/ca%d/info", __get_simulator_dir(), idx); + info_file = open(file_name, O_RDONLY); + if (!info_file) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__parse_ca_info_file: ERR 5105: " + "Fail to open HCA:%d info file:(%s).\n", idx, + file_name); + goto Exit; + } + + /* read in the file */ + len = read(info_file, file_buffer, 3200); + close(info_file); + file_buffer[len] = '\0'; + + /* + parse the file ... + name: InfiniHost0 + provider: tavor + node GUID: 0002:c900:0120:3470 + ports: 2 + vendor ID: 0x2c9 + device ID: 0x5a44 + HW revision: 0xa1 + FW revision: 0x300020080 + */ + if (!(p_ch = strstr(file_buffer, "name:"))) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__parse_ca_info_file: ERR 5106: " + "Fail to obtain HCA name. In info file:(%s).\n", + file_buffer); + goto Exit; + } + if (sscanf(p_ch, "name: %s", sim_ca_info->name) != 1) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__parse_ca_info_file: ERR 5107: " + "Fail to parse name in info file:(%s).\n", p_ch); + goto Exit; + } + + /* get the guid of the HCA */ + if (!(p_ch = strstr(file_buffer, "node GUID:"))) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__parse_ca_info_file: ERR 5108: " + "Fail to obtain GUID in info file:(%s).\n", + file_buffer); + goto Exit; + } + if (sscanf(p_ch, "node GUID: %x:%x:%x:%x", &g1, &g2, &g3, &g4) != 4) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__parse_ca_info_file: ERR 5109: " + "Fail to parse GUID in info file:(%s).\n", p_ch); + goto Exit; + } + sim_ca_info->guid = (uint64_t) g1 << 48 | (uint64_t) g1 << 32 + | (uint64_t) g1 << 16 | (uint64_t) g3; + + /* obtain number of ports */ + if (!(p_ch = strstr(file_buffer, "ports:"))) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__parse_ca_info_file: ERR 5110: " + "Fail to obtain number of ports in info file:(%s).\n", + file_buffer); + goto Exit; + } + if (sscanf(p_ch, "ports: %d", &num_ports) != 1) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__parse_ca_info_file: ERR 5111: " + "Fail to parse num ports in info file:(%s).\n", p_ch); + goto Exit; + } + sim_ca_info->num_ports = num_ports; + + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "__parse_ca_info_file: " + "CA1 = name:%s guid:0x%016llx ports:%d\n", + sim_ca_info->name, sim_ca_info->guid, sim_ca_info->num_ports); + + status = IB_SUCCESS; +Exit: + OSM_LOG_EXIT(p_vend->p_log); + return status; +} + +/* + state: ACTIVE + LID: 0x0001 + LMC: 0x0000 + SM LID: 0x0001 + SM SL: 0x0000 + Capabilities: IsSM + IsTrapSupported + IsAutomaticMigrationSupported + IsSLMappingSupported + IsLEDInfoSupported + IsSystemImageGUIDSupported + IsVendorClassSupported + IsCapabilityMaskNoticeSupported +*/ +typedef struct _sim_port_info { + uint8_t state; + uint16_t lid; + uint8_t lmc; + uint16_t sm_lid; + uint8_t sm_sl; +} sim_port_info_t; + +/********************************************************************** + * Parse the Port Info file available in ibmgtSimDir/caN/portM/info + * Port num is 1..N + **********************************************************************/ +static ib_api_status_t +__parse_port_info_file(IN osm_vendor_t * const p_vend, + IN uint32_t hca_idx, + IN uint8_t port_num, OUT sim_port_info_t * sim_port_info) +{ + ib_api_status_t status = IB_ERROR; + int info_file; + char file_name[256]; + char file_buffer[3200]; + char state[12]; + char *p_ch; + int lid, sm_lid, lmc, sm_sl; + uint32_t len; + + OSM_LOG_ENTER(p_vend->p_log); + + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "__parse_port_info_file: " + "Parsing Proc File System Port Info CA %d Port %d.\n", hca_idx, + port_num); + + /* we use the proc file system so we must be able to open the info file .. */ + sprintf(file_name, "%s/ca%d/port%d/info", __get_simulator_dir(), + hca_idx, port_num); + info_file = open(file_name, O_RDONLY); + if (!info_file) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__parse_port_info_file: ERR 5112: " + "Fail to open HCA:%d Port:%d info file:(%s).\n", + hca_idx, port_num, file_name); + goto Exit; + } + + /* read in the file */ + len = read(info_file, file_buffer, 3200); + close(info_file); + file_buffer[len] = '\0'; + + /* + parse the file ... + state: ACTIVE + LID: 0x0001 + LMC: 0x0000 + SM LID: 0x0001 + SM SL: 0x0000 + ... + */ + if (!(p_ch = strstr(file_buffer, "state:"))) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__parse_port_info_file: ERR 5113: " + "Fail to obtain port state. In info file:(%s).\n", + file_buffer); + goto Exit; + } + if (sscanf(p_ch, "state: %s", state) != 1) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__parse_port_info_file: ERR 5114: " + "Fail to parse state from info file:(%s).\n", p_ch); + goto Exit; + } + + if (!strcmp(state, "ACTIVE")) + sim_port_info->state = IB_LINK_ACTIVE; + else if (!strcmp(state, "DOWN")) + sim_port_info->state = IB_LINK_DOWN; + else if (!strcmp(state, "INIT")) + sim_port_info->state = IB_LINK_INIT; + else if (!strcmp(state, "ARMED")) + sim_port_info->state = IB_LINK_ARMED; + else + sim_port_info->state = 0; + + /* get lid */ + if (!(p_ch = strstr(file_buffer, "LID:"))) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__parse_port_info_file: ERR 5115: " + "Fail to obtain port lid. In info file:(%s).\n", + file_buffer); + goto Exit; + } + if (sscanf(p_ch, "LID: %x", &lid) != 1) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__parse_port_info_file: ERR 5116: " + "Fail to parse lid from info file:(%s).\n", p_ch); + goto Exit; + } + sim_port_info->lid = lid; + /* get LMC */ + if (!(p_ch = strstr(file_buffer, "LMC:"))) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__parse_port_info_file: ERR 5117: " + "Fail to obtain port LMC. In info file:(%s).\n", + file_buffer); + goto Exit; + } + if (sscanf(p_ch, "LMC: %x", &lmc) != 1) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__parse_port_info_file: ERR 5118: " + "Fail to parse LMC from info file:(%s).\n", p_ch); + goto Exit; + } + sim_port_info->lmc = lmc; + + /* get SM LID */ + if (!(p_ch = strstr(file_buffer, "SM LID:"))) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__parse_port_info_file: ERR 5119: " + "Fail to obtain port SM LID. In info file:(%s).\n", + file_buffer); + goto Exit; + } + if (sscanf(p_ch, "SM LID: %x", &sm_lid) != 1) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__parse_port_info_file: ERR 5120: " + "Fail to parse SM LID from info file:(%s).\n", p_ch); + goto Exit; + } + sim_port_info->sm_lid = sm_lid; + + /* get SM LID */ + if (!(p_ch = strstr(file_buffer, "SM SL:"))) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__parse_port_info_file: ERR 5121: " + "Fail to obtain port SM SL. In info file:(%s).\n", + file_buffer); + goto Exit; + } + if (sscanf(p_ch, "SM SL: %x", &sm_sl) != 1) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__parse_port_info_file: ERR 5122: " + "Fail to parse SM SL from info file:(%s).\n", p_ch); + goto Exit; + } + sim_port_info->sm_sl = sm_sl; + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "__parse_port_info_file: " + "Obtained Port:%d = state:%d, lid:0x%04X, lmc:%d, sm_lid:0x%04X, sm_sl:%d\n", + port_num, sim_port_info->state, sim_port_info->lid, + sim_port_info->lmc, sim_port_info->sm_lid, + sim_port_info->sm_sl); + + status = IB_SUCCESS; +Exit: + OSM_LOG_EXIT(p_vend->p_log); + return status; +} + +/********************************************************************** + * Parse the port guid_tbl file to obtain the port guid. + * File format is: + * [ 0] fe80:0000:0000:0000:0002:c900:0120:3472 + **********************************************************************/ +static ib_api_status_t +__get_port_guid_from_port_gid_tbl(IN osm_vendor_t * const p_vend, + IN uint32_t hca_idx, + IN uint8_t port_num, OUT uint64_t * port_guid) +{ + ib_api_status_t status = IB_ERROR; + int info_file; + char file_name[256]; + char file_buffer[3200]; + char *p_ch; + int g[8]; + uint32_t len; + + OSM_LOG_ENTER(p_vend->p_log); + + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "__get_port_guid_from_port_gid_tbl: " + "Parsing Proc File System Port Guid Table CA %d Port %d.\n", + hca_idx, port_num); + + /* we use the proc file system so we must be able to open the info file .. */ + sprintf(file_name, "%s/ca%d/port%d/gid_table", + __get_simulator_dir(), hca_idx, port_num); + info_file = open(file_name, O_RDONLY); + if (!info_file) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__get_port_guid_from_port_gid_tbl: ERR 5123: " + "Fail to open HCA:%d Port:%d gid_table file:(%s).\n", + hca_idx, port_num, file_name); + goto Exit; + } + + /* read in the file */ + len = read(info_file, file_buffer, 3200); + close(info_file); + file_buffer[len] = '\0'; + + /* + parse the file ... + [ 0] fe80:0000:0000:0000:0002:c900:0120:3472 + ... + */ + if (!(p_ch = strstr(file_buffer, "[ 0]"))) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__get_port_guid_from_port_gid_tbl: ERR 5124: " + "Fail to obtain first gid index. In gid_table file:(%s).\n", + file_buffer); + goto Exit; + } + if (sscanf(p_ch + 6, "%x:%x:%x:%x:%x:%x:%x:%x", + &g[7], &g[6], &g[5], &g[4], &g[3], &g[2], &g[1], &g[0]) != 8) + { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__get_port_guid_from_port_gid_tbl: ERR 5125: " + "Fail to parse gid from gid_table file:(%s).\n", p_ch); + goto Exit; + } + + *port_guid = + (uint64_t) g[3] << 48 | (uint64_t) g[2] << 32 | (uint64_t) g[1] << + 16 | g[0]; + status = IB_SUCCESS; +Exit: + OSM_LOG_EXIT(p_vend->p_log); + return status; +} + +/********************************************************************** + * Initialize an Info Struct for the Given HCA by its index 1..N + **********************************************************************/ +static ib_api_status_t +__osm_ca_info_init(IN osm_vendor_t * const p_vend, + IN uint32_t const idx, OUT osm_ca_info_t * const p_ca_info) +{ + ib_api_status_t status = IB_ERROR; + uint8_t port_num; + uint64_t port_guid; + + sim_ca_info_t sim_ca_info; + + OSM_LOG_ENTER(p_vend->p_log); + + /* parse the CA info file */ + if (__parse_ca_info_file(p_vend, idx, &sim_ca_info) != IB_SUCCESS) + goto Exit; + + p_ca_info->guid = cl_hton64(sim_ca_info.guid); + + /* set size of attributes and allocate them */ + p_ca_info->attr_size = 1; + p_ca_info->p_attr = (ib_ca_attr_t *) malloc(sizeof(ib_ca_attr_t)); + + p_ca_info->p_attr->ca_guid = p_ca_info->guid; + p_ca_info->p_attr->num_ports = sim_ca_info.num_ports; + + /* now obtain the attributes of the ports */ + p_ca_info->p_attr->p_port_attr = + (ib_port_attr_t *) malloc(sim_ca_info.num_ports * + sizeof(ib_port_attr_t)); + + /* get all the ports info */ + for (port_num = 1; port_num <= sim_ca_info.num_ports; port_num++) { + sim_port_info_t sim_port_info; + /* query the port attributes */ + if (__parse_port_info_file + (p_vend, idx, port_num, &sim_port_info)) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__osm_ca_info_init: ERR 5126: " + "Fail to get HCA:%d Port:%d Attributes.\n", idx, + port_num); + goto Exit; + } + + /* HACK: the lids should have been converted to network but the rest of the code + is wrong and provdes them as is (host order) - so we stick with it. */ + p_ca_info->p_attr->p_port_attr[port_num - 1].lid = + sim_port_info.lid; + p_ca_info->p_attr->p_port_attr[port_num - 1].link_state = + sim_port_info.state; + p_ca_info->p_attr->p_port_attr[port_num - 1].sm_lid = + sim_port_info.sm_lid; + + /* get the port guid */ + if (__get_port_guid_from_port_gid_tbl + (p_vend, idx, port_num, &port_guid)) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__osm_ca_info_init: ERR 5127: " + "Fail to get HCA:%d Port:%d Guid.\n", idx, + port_num); + goto Exit; + } + p_ca_info->p_attr->p_port_attr[port_num - 1].port_guid = + cl_hton64(port_guid); + } + + status = IB_SUCCESS; +Exit: + OSM_LOG_EXIT(p_vend->p_log); + return (status); +} + +void +osm_ca_info_destroy(IN osm_vendor_t * const p_vend, + IN osm_ca_info_t * const p_ca_info, IN uint8_t num_ca) +{ + osm_ca_info_t *p_ca; + uint8_t i; + + OSM_LOG_ENTER(p_vend->p_log); + + for (i = 0; i < num_ca; i++) { + p_ca = &p_ca_info[i]; + + if (NULL != p_ca->p_attr) { + if (0 != p_ca->p_attr->num_ports) { + free(p_ca->p_attr->p_port_attr); + } + + free(p_ca->p_attr); + } + } + + free(p_ca_info); + + OSM_LOG_EXIT(p_vend->p_log); +} + +/********************************************************************** + * Fill in the array of port_attr with all available ports on ALL the + * avilable CAs on this machine. + **********************************************************************/ +ib_api_status_t +osm_vendor_get_all_port_attr(IN osm_vendor_t * const p_vend, + IN ib_port_attr_t * const p_attr_array, + IN uint32_t * const p_num_ports) +{ + ib_api_status_t status = IB_SUCCESS; + + uint32_t caIdx; + uint32_t ca_count = 0; + uint32_t port_count = 0; + uint8_t port_num; + uint32_t total_ports = 0; + osm_ca_info_t *p_ca_infos = NULL; + uint32_t attr_array_sz = *p_num_ports; + + OSM_LOG_ENTER(p_vend->p_log); + + CL_ASSERT(p_vend); + + /* determine the number of CA's */ + ca_count = __hca_sim_get_num_cas(); + if (!ca_count) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_get_all_port_attr: ERR 5128: " + "Fail to get Any CA Ids.\n"); + goto Exit; + } + + /* Allocate an array big enough to hold the ca info objects */ + p_ca_infos = malloc(ca_count * sizeof(osm_ca_info_t)); + if (p_ca_infos == NULL) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_get_all_port_attr: ERR 5129: " + "Unable to allocate CA information array.\n"); + goto Exit; + } + + memset(p_ca_infos, 0, ca_count * sizeof(osm_ca_info_t)); + + /* + * For each CA, retrieve the CA info attributes + */ + for (caIdx = 1; caIdx <= ca_count; caIdx++) { + status = + __osm_ca_info_init(p_vend, caIdx, &p_ca_infos[caIdx - 1]); + if (status != IB_SUCCESS) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_get_all_port_attr: ERR 5130: " + "Unable to initialize CA Info object (%s).\n", + ib_get_err_str(status)); + goto Exit; + } + total_ports += p_ca_infos[caIdx - 1].p_attr->num_ports; + } + + *p_num_ports = total_ports; + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "osm_vendor_get_all_port_attr: total ports:%u \n", total_ports); + + /* + * If the user supplied enough storage, return the port guids, + * otherwise, return the appropriate error. + */ + if (attr_array_sz >= total_ports) { + for (caIdx = 1; caIdx <= ca_count; caIdx++) { + uint32_t num_ports; + + num_ports = p_ca_infos[caIdx - 1].p_attr->num_ports; + + for (port_num = 0; port_num < num_ports; port_num++) { + p_attr_array[port_count] = + *__osm_ca_info_get_port_attr_ptr(&p_ca_infos + [caIdx - + 1], + port_num); + port_count++; + } + } + } else { + status = IB_INSUFFICIENT_MEMORY; + goto Exit; + } + + status = IB_SUCCESS; + +Exit: + if (p_ca_infos) { + osm_ca_info_destroy(p_vend, p_ca_infos, ca_count); + } + + OSM_LOG_EXIT(p_vend->p_log); + return (status); +} + +/********************************************************************** + * Given the vendor obj and a port guid + * return the ca id and port number that have that guid + **********************************************************************/ + +ib_api_status_t +osm_vendor_get_guid_ca_and_port(IN osm_vendor_t * const p_vend, + IN ib_net64_t const guid, + OUT uint32_t * p_hca_hndl, + OUT char *p_hca_id, + OUT uint8_t * p_hca_idx, + OUT uint32_t * p_port_num) +{ + uint32_t caIdx; + uint32_t ca_count = 0; + uint8_t port_num; + ib_api_status_t status = IB_ERROR; + + OSM_LOG_ENTER(p_vend->p_log); + + CL_ASSERT(p_vend); + + /* determine the number of CA's */ + ca_count = __hca_sim_get_num_cas(); + if (!ca_count) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_get_guid_ca_and_port: ERR 5131: " + "Fail to get Any CA Ids.\n"); + goto Exit; + } + + /* + * For each CA, retrieve the CA info attributes + */ + for (caIdx = 1; caIdx <= ca_count; caIdx++) { + sim_ca_info_t sim_ca_info; + if (__parse_ca_info_file(p_vend, caIdx, &sim_ca_info) == + IB_SUCCESS) { + /* get all the ports info */ + for (port_num = 1; port_num <= sim_ca_info.num_ports; + port_num++) { + uint64_t port_guid; + if (!__get_port_guid_from_port_gid_tbl + (p_vend, caIdx, port_num, &port_guid)) { + if (cl_hton64(port_guid) == guid) { + osm_log(p_vend->p_log, + OSM_LOG_DEBUG, + "osm_vendor_get_guid_ca_and_port: " + "Found Matching guid on HCA:%d Port:%d.\n", + caIdx, port_num); + strcpy(p_hca_id, + sim_ca_info.name); + *p_port_num = port_num; + *p_hca_idx = caIdx - 1; + *p_hca_hndl = 0; + status = IB_SUCCESS; + goto Exit; + } + } + } + } + } + + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_get_guid_ca_and_port: ERR 5132: " + "Fail to find HCA and Port for Port Guid 0x%" PRIx64 "\n", + cl_ntoh64(guid)); + status = IB_INVALID_GUID; + +Exit: + + OSM_LOG_EXIT(p_vend->p_log); + return (status); +} + +/********************************************************************** + * Given the vendor obj HCA ID and Port Num + * update the given port guid if found. Return 0 on success. + **********************************************************************/ + +ib_api_status_t +osm_vendor_get_guid_by_ca_and_port(IN osm_vendor_t * const p_vend, + IN char *hca_id, + IN uint32_t port_num, + OUT uint64_t * p_port_guid) +{ + uint32_t caIdx; + uint32_t ca_count = 0; + ib_api_status_t status = IB_ERROR; + + OSM_LOG_ENTER(p_vend->p_log); + + CL_ASSERT(p_vend); + + /* determine the number of CA's */ + ca_count = __hca_sim_get_num_cas(); + if (!ca_count) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_get_guid_by_ca_and_port: ERR 5133: " + "Fail to get Any CA Ids.\n"); + goto Exit; + } + + /* + * For each CA, retrieve the CA info attributes + */ + for (caIdx = 1; caIdx <= ca_count; caIdx++) { + sim_ca_info_t sim_ca_info; + if (__parse_ca_info_file(p_vend, caIdx, &sim_ca_info) == + IB_SUCCESS) { + /* if not identical by id - go to next one */ + if (strcmp(sim_ca_info.name, hca_id)) + continue; + + if ((port_num < 1) + || (port_num > sim_ca_info.num_ports)) { + return 1; + } + + if (!__get_port_guid_from_port_gid_tbl + (p_vend, caIdx, port_num, p_port_guid)) { + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "osm_vendor_get_guid_by_ca_and_port: " + "Found Matching guid on HCA:%d Port:%d.\n", + caIdx, port_num); + status = IB_SUCCESS; + goto Exit; + } + } + } + + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_get_guid_by_ca_and_port: ERR 5134: " + "Fail to find HCA:%s\n", hca_id); + status = IB_INVALID_GUID; + +Exit: + + OSM_LOG_EXIT(p_vend->p_log); + return (status); +} + +#endif diff --git a/branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_mlx_ibmgt.c b/branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_mlx_ibmgt.c new file mode 100644 index 00000000..d54296f9 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_mlx_ibmgt.c @@ -0,0 +1,783 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* AUTHOR Edward Bortnikov + * + * DESCRIPTION + * The lower-level MAD transport interface implementation + * that allows sending a single MAD/receiving a callback + * when a single MAD is received. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include + +typedef struct _osmv_IBMGT_transport_mgr_ { + IB_MGT_mad_type_t mad_type; + uint8_t mgmt_class; /* for gsi */ + /* for communication between send call back and send mad */ + boolean_t is_send_ok; + cl_event_t send_done; +} osmv_IBMGT_transport_mgr_t; + +typedef struct _osmv_IBMGT_transport_info_ { + IB_MGT_mad_hndl_t smi_h; + cl_qlist_t *p_smi_list; + + IB_MGT_mad_hndl_t gsi_h; + /* holds bind object list for every binded mgmt class */ + cl_qlist_t *gsi_mgmt_lists[15]; +} osmv_IBMGT_transport_info_t; + +static void +__osmv_IBMGT_rcv_desc_to_osm_addr(IN IB_MGT_mad_rcv_desc_t * p_rcv_desc, + IN uint8_t is_smi, + OUT osm_mad_addr_t * p_mad_addr); + +static void +__osmv_IBMGT_osm_addr_to_ibmgt_addr(IN const osm_mad_addr_t * p_mad_addr, + IN uint8_t is_smi, OUT IB_ud_av_t * p_av); + +void +__osmv_IBMGT_send_cb(IN IB_MGT_mad_hndl_t mad_hndl, + IN u_int64_t wrid, + IN IB_comp_status_t status, IN void *private_ctx_p); + +void +__osmv_IBMGT_rcv_cb(IN IB_MGT_mad_hndl_t mad_hndl, + IN void *private_ctx_p, + IN void *payload_p, + IN IB_MGT_mad_rcv_desc_t * rcv_remote_info_p); + +/* + * NAME + * osmv_transport_init + * + * DESCRIPTION + * Setup the MAD transport infrastructure (filters, callbacks etc). + */ + +ib_api_status_t +osmv_transport_init(IN osm_bind_info_t * p_info, + IN char hca_id[VENDOR_HCA_MAXNAMES], + IN uint8_t hca_idx, IN osmv_bind_obj_t * p_bo) +{ + ib_api_status_t st = IB_SUCCESS; + IB_MGT_ret_t ret; + IB_MGT_mad_type_t mad_type; + osmv_IBMGT_transport_mgr_t *p_mgr; + osmv_IBMGT_transport_info_t *p_tpot_info; + cl_list_obj_t *p_obj = NULL; + osm_log_t *p_log = p_bo->p_vendor->p_log; + int i; + + UNUSED_PARAM(hca_idx); + + /* if first bind, allocate tranport_info at vendor */ + if (NULL == p_bo->p_vendor->p_transport_info) { + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "osmv_transport_init: first bind() for the vendor\n"); + p_bo->p_vendor->p_transport_info + = (osmv_IBMGT_transport_info_t *) + malloc(sizeof(osmv_IBMGT_transport_info_t)); + if (NULL == p_bo->p_vendor->p_transport_info) { + return IB_INSUFFICIENT_MEMORY; + } + memset(p_bo->p_vendor->p_transport_info, 0, + sizeof(osmv_IBMGT_transport_info_t)); + p_tpot_info = + (osmv_IBMGT_transport_info_t *) (p_bo->p_vendor-> + p_transport_info); + + p_tpot_info->smi_h = 0xffffffff; + p_tpot_info->p_smi_list = NULL; + + p_tpot_info->gsi_h = 0xffffffff; + for (i = 0; i < 15; i++) { + + p_tpot_info->gsi_mgmt_lists[i] = NULL; + } + + } else { + + p_tpot_info = + (osmv_IBMGT_transport_info_t *) (p_bo->p_vendor-> + p_transport_info); + } + + /* Initialize the magic_ptr to the pointer of the p_bo info. + This will be used to signal when the object is being destroyed, so no + real action will be done then. */ + p_bo->magic_ptr = p_bo; + + /* allocate transport mgr */ + p_mgr = malloc(sizeof(osmv_IBMGT_transport_mgr_t)); + if (NULL == p_mgr) { + free(p_tpot_info); + osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, + "osmv_transport_init: ERR 7201: " "alloc failed \n"); + return IB_INSUFFICIENT_MEMORY; + } + + memset(p_mgr, 0, sizeof(osmv_IBMGT_transport_mgr_t)); + + p_bo->p_transp_mgr = p_mgr; + + switch (p_info->mad_class) { + case IB_MCLASS_SUBN_LID: + case IB_MCLASS_SUBN_DIR: + mad_type = IB_MGT_SMI; + break; + + case IB_MCLASS_SUBN_ADM: + default: + mad_type = IB_MGT_GSI; + break; + } + + /* we only support one class registration per SMI/GSI !!! */ + switch (mad_type) { + case IB_MGT_SMI: + /* we do not need to bind the handle if already available */ + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "osmv_transport_init: SMI bind\n"); + + if (p_tpot_info->smi_h == 0xffffffff) { + ret = IB_MGT_get_handle(hca_id, + p_bo->port_num, + IB_MGT_SMI, + &(p_tpot_info->smi_h)); + if (IB_MGT_OK != ret) { + osm_log(p_log, OSM_LOG_ERROR, + "osmv_transport_init: ERR 7202: " + "IB_MGT_get_handle for smi failed \n"); + st = IB_ERROR; + free(p_mgr); + goto Exit; + } + + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "osmv_transport_init: got smi handle:%d \n", + p_tpot_info->smi_h); + + ret = IB_MGT_bind_sm(p_tpot_info->smi_h); + if (IB_MGT_OK != ret) { + osm_log(p_log, OSM_LOG_ERROR, + "osmv_transport_init: ERR 7203: " + "IB_MGT_bind_sm failed \n"); + st = IB_ERROR; + free(p_mgr); + goto Exit; + } + + /* init smi list */ + p_tpot_info->p_smi_list = malloc(sizeof(cl_qlist_t)); + if (NULL == p_tpot_info->p_smi_list) { + osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, + "osmv_transport_init: ERR 7204: " + "alloc failed \n"); + IB_MGT_unbind_sm(p_tpot_info->smi_h); + IB_MGT_release_handle(p_tpot_info->smi_h); + free(p_mgr); + return IB_INSUFFICIENT_MEMORY; + } + memset(p_tpot_info->p_smi_list, 0, sizeof(cl_qlist_t)); + cl_qlist_init(p_tpot_info->p_smi_list); + + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "osmv_transport_init: before reg_cb\n"); + ret = IB_MGT_reg_cb(p_tpot_info->smi_h, + &__osmv_IBMGT_rcv_cb, + p_bo, + &__osmv_IBMGT_send_cb, + p_tpot_info->p_smi_list, + IB_MGT_RCV_CB_MASK | + IB_MGT_SEND_CB_MASK); + if (ret != IB_SUCCESS) { + osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, + "osmv_transport_init: ERR 7205: " + "reg_cb failed with return code:%x \n", + ret); + IB_MGT_unbind_sm(p_tpot_info->smi_h); + IB_MGT_release_handle(p_tpot_info->smi_h); + free(p_tpot_info->p_smi_list); + free(p_mgr); + st = IB_ERROR; + goto Exit; + } + + } + /* insert to list of smi's - for raising callbacks later on */ + p_obj = malloc(sizeof(cl_list_obj_t)); + if (p_obj) + memset(p_obj, 0, sizeof(cl_list_obj_t)); + cl_qlist_set_obj(p_obj, p_bo); + cl_qlist_insert_tail(p_tpot_info->p_smi_list, + &p_obj->list_item); + + break; + + case IB_MGT_GSI: + /* we do not need to bind the handle if already available */ + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "osmv_transport_init: ERR 7206: GSI bind\n"); + if (p_tpot_info->gsi_h == 0xffffffff) { + ret = IB_MGT_get_handle(hca_id, + p_bo->port_num, + IB_MGT_GSI, + &(p_tpot_info->gsi_h)); + if (IB_MGT_OK != ret) { + osm_log(p_log, OSM_LOG_ERROR, + "osmv_transport_init: ERR 7207: " + "IB_MGT_get_handle for gsi failed \n"); + st = IB_ERROR; + free(p_mgr); + goto Exit; + } + } + + /* this mgmt class was not binded yet */ + if (p_tpot_info->gsi_mgmt_lists[p_info->mad_class] == NULL) { + ret = + IB_MGT_bind_gsi_class(p_tpot_info->gsi_h, + p_info->mad_class); + if (IB_MGT_OK != ret) { + osm_log(p_log, OSM_LOG_ERROR, + "osmv_transport_init: ERR 7208: " + "IB_MGT_bind_gsi_class failed \n"); + st = IB_ERROR; + free(p_mgr); + goto Exit; + } + + p_tpot_info->gsi_mgmt_lists[p_info->mad_class] = + malloc(sizeof(cl_qlist_t)); + if (NULL == + p_tpot_info->gsi_mgmt_lists[p_info->mad_class]) { + IB_MGT_unbind_gsi_class(p_tpot_info->gsi_h, + p_info->mad_class); + free(p_mgr); + return IB_INSUFFICIENT_MEMORY; + } + memset(p_tpot_info->gsi_mgmt_lists[p_info->mad_class], + 0, sizeof(cl_qlist_t)); + cl_qlist_init(p_tpot_info-> + gsi_mgmt_lists[p_info->mad_class]); + } + /* insert to list of smi's - for raising callbacks later on */ + p_obj = malloc(sizeof(cl_list_obj_t)); + if (p_obj) + memset(p_obj, 0, sizeof(cl_list_obj_t)); + cl_qlist_set_obj(p_obj, p_bo); + cl_qlist_insert_tail(p_tpot_info-> + gsi_mgmt_lists[p_info->mad_class], + &p_obj->list_item); + + p_mgr->mgmt_class = p_info->mad_class; + ret = IB_MGT_reg_cb(p_tpot_info->gsi_h, + &__osmv_IBMGT_rcv_cb, + p_bo, + &__osmv_IBMGT_send_cb, + p_bo, + IB_MGT_RCV_CB_MASK | IB_MGT_SEND_CB_MASK); + + if (ret != IB_SUCCESS) { + IB_MGT_unbind_gsi_class(p_tpot_info->gsi_h, + p_mgr->mgmt_class); + free(p_tpot_info->gsi_mgmt_lists[p_mgr->mgmt_class]); + free(p_mgr); + st = IB_ERROR; + goto Exit; + } + + break; + + default: + osm_log(p_log, OSM_LOG_ERROR, + "osmv_transport_init: ERR 7209: unrecognized mgmt class \n"); + st = IB_ERROR; + free(p_mgr); + goto Exit; + } + + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "osmv_transport_init: GSI bind\n"); + cl_event_construct(&p_mgr->send_done); + cl_event_init(&p_mgr->send_done, TRUE); + p_mgr->is_send_ok = FALSE; + p_mgr->mad_type = mad_type; + +Exit: + /* OSM_LOG_EXIT(p_log ); */ + return (ib_api_status_t) st; +} + +/* + * NAME + * osmv_transport_send_mad + * + * DESCRIPTION + * Send a single MAD (256 byte) + */ + +ib_api_status_t +osmv_transport_mad_send(IN const osm_bind_handle_t h_bind, + IN void *p_ib_mad, IN const osm_mad_addr_t * p_mad_addr) +{ + + osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; + osmv_IBMGT_transport_info_t *p_tpot_info = + (osmv_IBMGT_transport_info_t *) (p_bo->p_vendor->p_transport_info); + osm_vendor_t const *p_vend = p_bo->p_vendor; + ib_api_status_t status; + IB_ud_av_t av; + IB_MGT_ret_t ret; + ib_mad_t *p_mad = p_ib_mad; + + OSM_LOG_ENTER(p_vend->p_log); + + CL_ASSERT(p_bo->p_vendor->p_transport_info); + + /* + * For all sends other than directed route SM MADs, + * acquire an address vector for the destination. + */ + if (p_mad->mgmt_class != IB_MCLASS_SUBN_DIR) { + __osmv_IBMGT_osm_addr_to_ibmgt_addr(p_mad_addr, + p_mad->mgmt_class == + IB_MCLASS_SUBN_LID, &av); + } else { + /* is a directed route - we need to construct a permissive address */ + memset(&av, 0, sizeof(av)); + /* we do not need port number since it is part of the mad_hndl */ + av.dlid = IB_LID_PERMISSIVE; + } + + /* send it */ + if ((p_mad->mgmt_class == IB_MCLASS_SUBN_DIR) || + (p_mad->mgmt_class == IB_MCLASS_SUBN_LID)) { + + /* SMI CASE */ + if (osm_log_is_active(p_vend->p_log, OSM_LOG_DEBUG)) { + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "osmv_transport_mad_send: " + "av.dlid:0x%X, " + "av.static_rate:%d, " + "av.path_bits:%d.\n", + cl_ntoh16(av.dlid), av.static_rate, + av.src_path_bits); + } + + ret = IB_MGT_send_mad(p_tpot_info->smi_h, p_mad, /* actual payload */ + &av, /* address vector */ + (u_int64_t) CAST_P2LONG(p_bo), + IB_MGT_DEFAULT_SEND_TIME); + } else { + /* GSI CASE - Support Remote QP */ + if (osm_log_is_active(p_vend->p_log, OSM_LOG_DEBUG)) { + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "osmv_transport_mad_send: " + "av.dlid:0x%X, av.static_rate:%d, av.path_bits:%d, remote qp:%d \n", + cl_ntoh16(av.dlid), av.static_rate, + av.src_path_bits, + cl_ntoh32(p_mad_addr->addr_type.gsi.remote_qp) + ); + } + + ret = IB_MGT_send_mad_to_qp(p_tpot_info->gsi_h, p_mad, /* actual payload */ + &av, /* address vector */ + (u_int64_t) CAST_P2LONG(p_bo), + IB_MGT_DEFAULT_SEND_TIME, + cl_ntoh32(p_mad_addr->addr_type.gsi. + remote_qp)); + + } + + status = IB_SUCCESS; + if (ret != IB_MGT_OK) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osmv_transport_mad_send: ERR 7210: " + "Error sending mad (%d).\n", ret); + status = IB_ERROR; + } else { + osmv_IBMGT_transport_mgr_t *p_mgr = + (osmv_IBMGT_transport_mgr_t *) (p_bo->p_transp_mgr); + + /* Let the others work when I am sleeping ... */ + osmv_txn_unlock(p_bo); + + cl_event_wait_on(&(p_mgr->send_done), 0xffffffff, TRUE); + + /* Re-acquire the lock */ + osmv_txn_lock(p_bo); + + if (TRUE == p_bo->is_closing) { + + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osmv_transport_mad_send: ERR 7211: " + "The handle %p is being unbound, cannot send.\n", + h_bind); + status = IB_ERROR; + } + + if (p_mgr->is_send_ok == FALSE) { + status = IB_ERROR; + } + } + + OSM_LOG_EXIT(p_vend->p_log); + return (status); +} + +void osmv_transport_done(IN const osm_bind_handle_t h_bind) +{ + osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; + osm_log_t *p_log = p_bo->p_vendor->p_log; + osmv_IBMGT_transport_mgr_t *p_mgr; + osmv_IBMGT_transport_info_t *p_tpot_info; + IB_MGT_ret_t ret; + cl_list_obj_t *p_obj = NULL; + cl_list_item_t *p_item, *p_item_tmp; + int i; + cl_qlist_t *p_list = NULL; + + OSM_LOG_ENTER(p_log); + + CL_ASSERT(p_bo); + + /* First of all - zero out the magic_ptr, so if a callback is called - + it'll know that we are currently closing down, and will not handle the + mad. */ + p_bo->magic_ptr = 0; + + p_mgr = (osmv_IBMGT_transport_mgr_t *) (p_bo->p_transp_mgr); + p_tpot_info = + (osmv_IBMGT_transport_info_t *) (p_bo->p_vendor->p_transport_info); + + switch (p_mgr->mad_type) { + case IB_MGT_SMI: + p_list = p_tpot_info->p_smi_list; + + /* remove from the bindings list */ + p_item = cl_qlist_head(p_list); + while (p_item != cl_qlist_end(p_list)) { + p_obj = PARENT_STRUCT(p_item, cl_list_obj_t, list_item); + if (cl_qlist_obj(p_obj) == h_bind) { + break; + } + p_item_tmp = cl_qlist_next(p_item); + p_item = p_item_tmp; + } + + CL_ASSERT(p_item != cl_qlist_end(p_list)); + cl_qlist_remove_item(p_list, p_item); + if (p_obj) + free(p_obj); + + /* no one is binded to smi anymore - we can free the list, unbind & realease the hndl */ + if (cl_is_qlist_empty(p_list) == TRUE) { + free(p_list); + p_list = NULL; + + ret = IB_MGT_unbind_sm(p_tpot_info->smi_h); + if (ret != IB_MGT_OK) { + osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, + "osmv_transport_done: ERR 7212: " + "Failed to unbind sm\n"); + } + + ret = IB_MGT_release_handle(p_tpot_info->smi_h); + if (ret != IB_MGT_OK) { + osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, + "osmv_transport_done: ERR 7213: " + "Failed to release smi handle\n"); + } + p_tpot_info->smi_h = 0xffffffff; + } + break; + + case IB_MGT_GSI: + p_list = p_tpot_info->gsi_mgmt_lists[p_mgr->mgmt_class]; + /* remove from the bindings list */ + p_item = cl_qlist_head(p_list); + while (p_item != cl_qlist_end(p_list)) { + p_obj = PARENT_STRUCT(p_item, cl_list_obj_t, list_item); + if (cl_qlist_obj(p_obj) == h_bind) { + break; + } + p_item_tmp = cl_qlist_next(p_item); + p_item = p_item_tmp; + } + + CL_ASSERT(p_item != cl_qlist_end(p_list)); + cl_qlist_remove_item(p_list, p_item); + if (p_obj) + free(p_obj); + + /* no one is binded to this class anymore - we can free the list and unbind this class */ + if (cl_is_qlist_empty(p_list) == TRUE) { + free(p_list); + p_list = NULL; + + ret = + IB_MGT_unbind_gsi_class(p_tpot_info->gsi_h, + p_mgr->mgmt_class); + if (ret != IB_MGT_OK) { + osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, + "osmv_transport_done: ERR 7214: " + "Failed to unbind gsi class\n"); + } + } + + /* all the mgmt classes are unbinded - release gsi handle */ + for (i = 0; i < 15; i++) { + if (p_tpot_info->gsi_mgmt_lists[i] != NULL) { + break; + } + } + + if (i == 15) { + ret = IB_MGT_release_handle(p_tpot_info->gsi_h); + if (ret != IB_MGT_OK) { + osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, + "osmv_transport_done: ERR 7215: " + "Failed to release gsi handle\n"); + } + p_tpot_info->gsi_h = 0xffffffff; + } + } /* end switch */ + + free(p_mgr); +} + +/********************************************************************** + * IB_MGT Receive callback : invoked after each receive + **********************************************************************/ +void +__osmv_IBMGT_rcv_cb(IN IB_MGT_mad_hndl_t mad_hndl, + IN void *private_ctx_p, + IN void *payload_p, + IN IB_MGT_mad_rcv_desc_t * rcv_remote_info_p) +{ + osmv_bind_obj_t *p_bo; + osm_mad_addr_t mad_addr; + cl_list_item_t *p_item; + cl_list_obj_t *p_obj; + cl_qlist_t *p_list; + ib_mad_t *p_mad = (ib_mad_t *) payload_p; + osm_vendor_t *p_vendor; + osmv_IBMGT_transport_info_t *p_tinfo; + + __osmv_IBMGT_rcv_desc_to_osm_addr(rcv_remote_info_p, + ((p_mad->mgmt_class == + IB_MCLASS_SUBN_LID) + || (p_mad->mgmt_class == + IB_MCLASS_SUBN_DIR)), &mad_addr); + + /* different handling of SMI and GSI */ + if ((p_mad->mgmt_class == IB_MCLASS_SUBN_DIR) || + (p_mad->mgmt_class == IB_MCLASS_SUBN_LID)) { + /* SMI CASE */ + p_bo = (osmv_bind_obj_t *) private_ctx_p; + /* Make sure the p_bo object is still relevant */ + if ((p_bo->magic_ptr != p_bo) || p_bo->is_closing) + return; + + p_vendor = p_bo->p_vendor; + p_tinfo = + (osmv_IBMGT_transport_info_t *) p_vendor->p_transport_info; + p_list = p_tinfo->p_smi_list; + } else { + /* GSI CASE */ + p_bo = (osmv_bind_obj_t *) private_ctx_p; + /* Make sure the p_bo object is still relevant */ + if ((p_bo->magic_ptr != p_bo) || p_bo->is_closing) + return; + + p_vendor = p_bo->p_vendor; + p_tinfo = + (osmv_IBMGT_transport_info_t *) p_vendor->p_transport_info; + p_list = p_tinfo->gsi_mgmt_lists[p_mad->mgmt_class]; + } + + /* go over the bindings list and send the mad, one of them will accept it, + the others will drope + */ + p_item = cl_qlist_head(p_list); + while (p_item != cl_qlist_end(p_list)) { + p_obj = PARENT_STRUCT(p_item, cl_list_obj_t, list_item); + p_bo = cl_qlist_obj(p_obj); + /* give upper layer the mad */ + osmv_dispatch_mad((osm_bind_handle_t) p_bo, payload_p, + &mad_addr); + /* Make sure the p_bo object is still relevant */ + if ((p_bo->magic_ptr != p_bo) || p_bo->is_closing) + return; + + p_item = cl_qlist_next(p_item); + } +} + +/********************************************************************** + * IB_MGT Send callback : invoked after each send + **********************************************************************/ +void +__osmv_IBMGT_send_cb(IN IB_MGT_mad_hndl_t mad_hndl, + IN u_int64_t wrid, + IN IB_comp_status_t status, IN void *private_ctx_p) +{ + osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) CAST_P2LONG(wrid); + + osmv_IBMGT_transport_mgr_t *p_mgr = + (osmv_IBMGT_transport_mgr_t *) p_bo->p_transp_mgr; + + /* Make sure the p_bo object is still relevant */ + if (p_bo->magic_ptr != p_bo) + return; + + /* we assume that each send on a bind object is synchronized, and no paralel sends + from diffrent threads with same object can be made */ + if (status == IB_COMP_SUCCESS) { + p_mgr->is_send_ok = TRUE; + } else + p_mgr->is_send_ok = FALSE; + cl_event_signal(&p_mgr->send_done); + +} + +/********************************************************************** + * IB_MGT to OSM ADDRESS VECTOR + **********************************************************************/ +static void +__osmv_IBMGT_rcv_desc_to_osm_addr(IN IB_MGT_mad_rcv_desc_t * p_rcv_desc, + IN uint8_t is_smi, + OUT osm_mad_addr_t * p_mad_addr) +{ + /* p_mad_addr->dest_lid = p_osm->subn.sm_base_lid; - for resp we use the dest lid ... */ + p_mad_addr->dest_lid = cl_hton16(p_rcv_desc->remote_lid); + p_mad_addr->static_rate = 0; /* HACK - we do not know the rate ! */ + p_mad_addr->path_bits = p_rcv_desc->local_path_bits; + /* Clear the grh any way to avoid unset fields */ + memset(&p_mad_addr->addr_type.gsi.grh_info, 0, + sizeof(p_mad_addr->addr_type.gsi.grh_info)); + + if (is_smi) { + /* SMI */ + p_mad_addr->addr_type.smi.source_lid = + cl_hton16(p_rcv_desc->remote_lid); + p_mad_addr->addr_type.smi.port_num = 99; /* HACK - if used - should fail */ + } else { + /* GSI */ + /* seems to me there is a IBMGT bug reversing the QPN ... */ + /* Does IBMGT supposed to provide the QPN is network or HOST ? */ + p_mad_addr->addr_type.gsi.remote_qp = cl_hton32(p_rcv_desc->qp); + + p_mad_addr->addr_type.gsi.remote_qkey = IB_QP1_WELL_KNOWN_Q_KEY; + /* we do have the p_mad_addr->pkey_ix but how to get the PKey by index ? */ + /* the only way seems to be to use VAPI_query_hca_pkey_tbl and obtain */ + /* the full PKey table - than go by the index. */ + /* since this does not seem reasonable to me I simply use the default */ + /* There is a TAVOR limitation that only one P_KEY is supported per */ + /* QP - so QP1 must use IB_DEFAULT_PKEY */ + p_mad_addr->addr_type.gsi.pkey_ix = 0; + p_mad_addr->addr_type.gsi.service_level = p_rcv_desc->sl; + + p_mad_addr->addr_type.gsi.global_route = p_rcv_desc->grh_flag; + /* copy the GRH data if relevant */ + if (p_mad_addr->addr_type.gsi.global_route) { + p_mad_addr->addr_type.gsi.grh_info.ver_class_flow = + ib_grh_set_ver_class_flow(p_rcv_desc->grh. + IP_version, + p_rcv_desc->grh. + traffic_class, + p_rcv_desc->grh. + flow_label); + p_mad_addr->addr_type.gsi.grh_info.hop_limit = + p_rcv_desc->grh.hop_limit; + memcpy(&p_mad_addr->addr_type.gsi.grh_info.src_gid.raw, + &p_rcv_desc->grh.sgid, sizeof(ib_net64_t)); + memcpy(&p_mad_addr->addr_type.gsi.grh_info.dest_gid.raw, + p_rcv_desc->grh.dgid, sizeof(ib_net64_t)); + } + } +} + +/********************************************************************** + * OSM ADDR VECTOR TO IB_MGT + **********************************************************************/ +void +__osmv_IBMGT_osm_addr_to_ibmgt_addr(IN const osm_mad_addr_t * p_mad_addr, + IN uint8_t is_smi, OUT IB_ud_av_t * p_av) +{ + + /* For global destination or Multicast address: */ + u_int8_t ver; + + memset(p_av, 0, sizeof(IB_ud_av_t)); + + p_av->src_path_bits = p_mad_addr->path_bits; + p_av->static_rate = p_mad_addr->static_rate; + p_av->dlid = cl_ntoh16(p_mad_addr->dest_lid); + + if (is_smi) { + p_av->sl = 0; /* Just to note we use 0 here. */ + } else { + p_av->sl = p_mad_addr->addr_type.gsi.service_level; + p_av->grh_flag = p_mad_addr->addr_type.gsi.global_route; + + if (p_mad_addr->addr_type.gsi.global_route) { + ib_grh_get_ver_class_flow(p_mad_addr->addr_type.gsi. + grh_info.ver_class_flow, &ver, + &p_av->traffic_class, + &p_av->flow_label); + p_av->hop_limit = + p_mad_addr->addr_type.gsi.grh_info.hop_limit; + p_av->sgid_index = 0; /* we always use source GID 0 */ + memcpy(&p_av->dgid, + &p_mad_addr->addr_type.gsi.grh_info.dest_gid.raw, + sizeof(ib_net64_t)); + + } + } +} diff --git a/branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_mlx_rmpp_ctx.c b/branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_mlx_rmpp_ctx.c new file mode 100644 index 00000000..6d2ddd31 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_mlx_rmpp_ctx.c @@ -0,0 +1,361 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include + +#include +#include + +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/branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_mlx_sa.c b/branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_mlx_sa.c new file mode 100644 index 00000000..461ad27e --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_mlx_sa.c @@ -0,0 +1,874 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005,2008 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Copyright (c) 2009 HNR Consulting. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include + +/* this struct is the internal rep of the bind handle */ +typedef struct _osmv_sa_bind_info { + osm_bind_handle_t h_bind; + osm_log_t *p_log; + osm_vendor_t *p_vendor; + osm_mad_pool_t *p_mad_pool; + uint64_t port_guid; + cl_event_t sync_event; + uint64_t last_lids_update_sec; + uint16_t lid; + uint16_t sm_lid; +} osmv_sa_bind_info_t; + +/* + Call back on new mad received: + + We basically only need to set the context of the query. + Or report an error. + + A pointer to the actual context of the request (a copy of the oriignal + request structure) is attached as the p_madw->context.ni_context.node_guid +*/ +void +__osmv_sa_mad_rcv_cb(IN osm_madw_t * p_madw, + IN void *bind_context, IN osm_madw_t * p_req_madw) +{ + osmv_sa_bind_info_t *p_bind = (osmv_sa_bind_info_t *) bind_context; + osmv_query_req_t *p_query_req_copy = NULL; + osmv_query_res_t query_res; + ib_sa_mad_t *p_sa_mad; + ib_net16_t mad_status; + + OSM_LOG_ENTER(p_bind->p_log); + + if (!p_req_madw) { + osm_log(p_bind->p_log, OSM_LOG_DEBUG, + "__osmv_sa_mad_rcv_cb: " + "Ignoring a non-response mad\n"); + osm_mad_pool_put(p_bind->p_mad_pool, p_madw); + goto Exit; + } + + /* obtain the sent context */ + p_query_req_copy = + (osmv_query_req_t *) (p_req_madw->context.arb_context.context1); + + /* provide the context of the original request in the result */ + query_res.query_context = p_query_req_copy->query_context; + + /* provide the resulting madw */ + query_res.p_result_madw = p_madw; + + /* update the req fields */ + p_sa_mad = (ib_sa_mad_t *) p_madw->p_mad; + + /* if we got a remote error track it in the status */ + mad_status = (ib_net16_t) (p_sa_mad->status & IB_SMP_STATUS_MASK); + if (mad_status != IB_SUCCESS) { + osm_log(p_bind->p_log, OSM_LOG_ERROR, + "__osmv_sa_mad_rcv_cb: ERR 0501: " + "Remote error:0x%04X .\n", mad_status); + query_res.status = IB_REMOTE_ERROR; + } else { + query_res.status = IB_SUCCESS; + } + + /* what if we have got back an empty mad ? */ + if (!p_madw->mad_size) { + osm_log(p_bind->p_log, OSM_LOG_ERROR, + "__osmv_sa_mad_rcv_cb: ERR 0502: " + "Got an empty mad.\n"); + query_res.status = IB_ERROR; + } + + if (IB_SUCCESS == mad_status) { + + /* if we are in not in a method response of an rmpp nature we must get only 1 */ + /* HACK: in the future we might need to be smarter for other methods... */ + if (p_sa_mad->method != IB_MAD_METHOD_GETTABLE_RESP) { + query_res.result_cnt = 1; + } else { +#ifndef VENDOR_RMPP_SUPPORT + if (mad_status != IB_SUCCESS) + query_res.result_cnt = 0; + else + query_res.result_cnt = 1; +#else + /* we used the offset value to calculate the number of + records in here */ + if (ib_get_attr_size(p_sa_mad->attr_offset) == 0) { + query_res.result_cnt = 0; + osm_log(p_bind->p_log, OSM_LOG_DEBUG, + "__osmv_sa_mad_rcv_cb: Count = 0\n"); + } + else { + query_res.result_cnt = + (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 = %u / %u (%u)\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 = OSM_SM_DEFAULT_QP1_RCV_SIZE; + bind_info.recv_q_size = OSM_SM_DEFAULT_QP1_SEND_SIZE; + bind_info.timeout = OSM_DEFAULT_TRANS_TIMEOUT_MILLISEC; + bind_info.retries = OSM_DEFAULT_RETRY_COUNT; + + /* 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)); + if (!p_query_req_copy) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0511: " + "Unable to acquire memory for query copy\n"); + osm_mad_pool_put(p_bind->p_mad_pool, p_madw); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + *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) +{ + union { + 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; +#endif + ib_class_port_info_t class_port_info; + } u; + osmv_sa_mad_data_t sa_mad_data; + osmv_sa_bind_info_t *p_bind = (osmv_sa_bind_info_t *) h_bind; + osmv_user_query_t *p_user_query; +#ifdef DUAL_SIDED_RMPP + osmv_multipath_req_t *p_mpr_req; + int i, j; +#endif + 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; + + memset((void*)&u, 0, sizeof(u)); + + /* 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.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 = &u.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 = &u.svc_rec; + memcpy(u.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 = &u.svc_rec; + u.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 = &u.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.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 = &u.node_rec; + u.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 = &u.port_info; + u.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(&u.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 | IB_PR_COMPMASK_NUMBPATH); + u.path_rec.num_path = 0x7f; + sa_mad_data.p_attr = &u.path_rec; + ib_gid_set_default(&u.path_rec.dgid, + ((osmv_guid_pair_t *) (p_query_req-> + p_query_input))->dest_guid); + ib_gid_set_default(&u.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(&u.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 | IB_PR_COMPMASK_NUMBPATH); + u.path_rec.num_path = 0x7f; + sa_mad_data.p_attr = &u.path_rec; + memcpy(&u.path_rec.dgid, + &((osmv_gid_pair_t *) (p_query_req->p_query_input))-> + dest_gid, sizeof(ib_gid_t)); + memcpy(&u.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(&u.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 = &u.path_rec; + u.path_rec.dlid = + ((osmv_lid_pair_t *) (p_query_req->p_query_input))-> + dest_lid; + u.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; + +#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(&u.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 = &u.multipath_rec; + sa_mad_data.comp_mask = p_mpr_req->comp_mask; + u.multipath_rec.num_path = p_mpr_req->num_path; + if (p_mpr_req->reversible) + u.multipath_rec.num_path |= 0x80; + else + u.multipath_rec.num_path &= ~0x80; + u.multipath_rec.pkey = p_mpr_req->pkey; + ib_multipath_rec_set_sl(&u.multipath_rec, p_mpr_req->sl); + ib_multipath_rec_set_qos_class(&u.multipath_rec, 0); + u.multipath_rec.independence = p_mpr_req->independence; + u.multipath_rec.sgid_count = p_mpr_req->sgid_count; + u.multipath_rec.dgid_count = p_mpr_req->dgid_count; + j = 0; + for (i = 0; i < p_mpr_req->sgid_count; i++, j++) + u.multipath_rec.gids[j] = p_mpr_req->gids[j]; + for (i = 0; i < p_mpr_req->dgid_count; i++, j++) + u.multipath_rec.gids[j] = p_mpr_req->gids[j]; + break; +#endif + + default: + osm_log(p_log, OSM_LOG_ERROR, + "osmv_query_sa DBG:001 UNKNOWN 0x%x (%d)\n", + p_query_req->query_type,p_query_req->query_type); + 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/branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_mlx_sar.c b/branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_mlx_sar.c new file mode 100644 index 00000000..e9444768 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_mlx_sar.c @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include + +ib_api_status_t +osmv_rmpp_sar_init(osmv_rmpp_sar_t * p_sar, void *p_arbt_mad, + uint32_t mad_size, boolean_t is_sa_mad) +{ + CL_ASSERT(p_sar); + p_sar->p_arbt_mad = p_arbt_mad; + if (is_sa_mad) { + p_sar->data_len = mad_size - IB_SA_MAD_HDR_SIZE; + p_sar->hdr_sz = IB_SA_MAD_HDR_SIZE; + p_sar->data_sz = IB_SA_DATA_SIZE; + } else { + p_sar->data_len = mad_size - MAD_RMPP_HDR_SIZE; + p_sar->hdr_sz = MAD_RMPP_HDR_SIZE; + p_sar->data_sz = MAD_RMPP_DATA_SIZE; + } + return IB_SUCCESS; +} + +void osmv_rmpp_sar_done(osmv_rmpp_sar_t * p_sar) +{ + p_sar->p_arbt_mad = NULL; +} + +/* the big mad should be with mad header, rmpp header ( &sa hdr) space */ +ib_api_status_t +osmv_rmpp_sar_get_mad_seg(IN osmv_rmpp_sar_t * p_sar, + IN uint32_t seg_idx, OUT void *p_buf) +{ + void *p_seg; + uint32_t sz_left; + uint32_t num_segs; + + CL_ASSERT(p_sar); + + num_segs = p_sar->data_len / p_sar->data_sz; + if ((p_sar->data_len % p_sar->data_sz) > 0) { + num_segs++; + } + + if ((seg_idx > num_segs) && (seg_idx != 1)) { + return IB_NOT_FOUND; + } + + /* cleanup */ + memset(p_buf, 0, MAD_BLOCK_SIZE); + + /* attach header */ + memcpy(p_buf, p_sar->p_arbt_mad, p_sar->hdr_sz); + + /* fill data */ + p_seg = + (char *)p_sar->p_arbt_mad + p_sar->hdr_sz + + ((seg_idx - 1) * p_sar->data_sz); + sz_left = p_sar->data_len - ((seg_idx - 1) * p_sar->data_sz); + if (sz_left > p_sar->data_sz) + memcpy((char *)p_buf + p_sar->hdr_sz, (char *)p_seg, + p_sar->data_sz); + else + memcpy((char *)p_buf + p_sar->hdr_sz, (char *)p_seg, sz_left); + + return IB_SUCCESS; +} + +/* turns a list of mads to one big mad - including header */ +/* ALSO - deallocates the list */ +ib_api_status_t +osmv_rmpp_sar_reassemble_arbt_mad(osmv_rmpp_sar_t * p_sar, cl_qlist_t * p_bufs) +{ + void *buf_tmp, *p_mad; + cl_list_item_t *p_item; + cl_list_obj_t *p_obj; + uint32_t space_left = p_sar->data_len + p_sar->hdr_sz; + + CL_ASSERT(p_sar); + CL_ASSERT(FALSE == cl_is_qlist_empty(p_bufs)); + + /* attach header */ + p_mad = p_sar->p_arbt_mad; + p_item = cl_qlist_head(p_bufs); + p_obj = PARENT_STRUCT(p_item, cl_list_obj_t, list_item); + buf_tmp = cl_qlist_obj(p_obj); + memcpy(p_mad, buf_tmp, p_sar->hdr_sz); + p_mad = (char *)p_mad + p_sar->hdr_sz; + space_left -= p_sar->hdr_sz; + + /* reassemble data */ + while (FALSE == cl_is_qlist_empty(p_bufs)) { + + p_item = cl_qlist_remove_head(p_bufs); + p_obj = PARENT_STRUCT(p_item, cl_list_obj_t, list_item); + buf_tmp = cl_qlist_obj(p_obj); + + if (FALSE == cl_is_qlist_empty(p_bufs)) { + memcpy((char *)p_mad, (char *)buf_tmp + p_sar->hdr_sz, + p_sar->data_sz); + p_mad = (char *)p_mad + p_sar->data_sz; + space_left -= p_sar->data_sz; + } else { + /* the last mad on the list */ + memcpy((char *)p_mad, (char *)buf_tmp + p_sar->hdr_sz, + space_left); + p_mad = (char *)p_mad + space_left; + } + + free(buf_tmp); + free(p_obj); + } + + return IB_SUCCESS; +} diff --git a/branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_mlx_sender.c b/branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_mlx_sender.c new file mode 100644 index 00000000..69d25b37 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_mlx_sender.c @@ -0,0 +1,390 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include + +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/branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_mlx_sim.c b/branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_mlx_sim.c new file mode 100644 index 00000000..9266198e --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_mlx_sim.c @@ -0,0 +1,439 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* AUTHOR Eitan Zahavi + * + * DESCRIPTION + * The lower-level MAD transport interface implementation + * that allows sending a single MAD/receiving a callback + * when a single MAD is received. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* the simulator messages definition */ +#include + +typedef struct _osmv_ibms_transport_mgr { + ibms_conn_handle_t conHdl; /* the connection handle we talk to */ + ibms_bind_msg_t filter; /* the bind message defining the filtering */ + cl_thread_t receiver; /* the thread waiting for incomming messages */ +} osmv_ibms_transport_mgr_t; + +static void +__osmv_ibms_mad_addr_to_osm_addr(IN osm_vendor_t const *p_vend, + IN struct _ibms_mad_addr *p_ibms_addr, + IN uint8_t is_smi, + OUT osm_mad_addr_t * p_osm_addr); + +static void +__osmv_ibms_osm_addr_to_mad_addr(IN const osm_mad_addr_t * p_osm_addr, + IN uint8_t is_smi, + OUT struct _ibms_mad_addr *p_ibms_addr); + +/* this is the callback function the "server" will call on incoming + messages */ +void __osmv_ibms_receiver_callback(void *p_ctx, ibms_mad_msg_t * p_mad) +{ + osm_mad_addr_t mad_addr; + osmv_bind_obj_t *const p_bo = (osmv_bind_obj_t *) p_ctx; + ib_api_status_t status = IB_SUCCESS; + + /* Make sure the p_bo object is still relevant */ + if ((p_bo->magic_ptr != p_bo) || p_bo->is_closing) + return; + + { + OSM_LOG_ENTER(p_bo->p_vendor->p_log); + + /* some logging */ + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "__osmv_ibms_receiver_callback: " + "MAD QPN:%d SLID:0x%04x class:0x%02x " + "method:0x%02x attr:0x%04x status:0x%04x " + "tid:0x%016" PRIx64 "\n", + p_mad->addr.dqpn, + cl_ntoh16(p_mad->addr.slid), + p_mad->header.mgmt_class, + p_mad->header.method, + cl_ntoh16(p_mad->header.attr_id), + cl_ntoh16(p_mad->header.status), + cl_ntoh64(p_mad->header.trans_id)); + + /* first arrange an address */ + __osmv_ibms_mad_addr_to_osm_addr(p_bo->p_vendor, + &p_mad->addr, + (((ib_mad_t *) & p_mad-> + header)->mgmt_class == + IB_MCLASS_SUBN_LID) + || + (((ib_mad_t *) & p_mad-> + header)->mgmt_class == + IB_MCLASS_SUBN_DIR), + &mad_addr); + + /* call the receiver callback */ + + status = + osmv_dispatch_mad((osm_bind_handle_t) p_bo, + (void *)&p_mad->header, &mad_addr); + + OSM_LOG_EXIT(p_bo->p_vendor->p_log); + } +} + +ib_api_status_t +osm_vendor_get_guid_by_ca_and_port(IN osm_vendor_t * const p_vend, + IN char *hca_id, + IN uint32_t port_num, + OUT uint64_t * p_port_guid); + +/* + * NAME + * osmv_transport_init + * + * DESCRIPTION + * Setup the MAD transport infrastructure (filters, callbacks etc). + */ + +ib_api_status_t +osmv_transport_init(IN osm_bind_info_t * p_info, + IN char hca_id[VENDOR_HCA_MAXNAMES], + IN uint8_t hca_idx, IN osmv_bind_obj_t * p_bo) +{ + ibms_conn_handle_t conHdl; /* the connection we talk to the simulator through */ + osmv_ibms_transport_mgr_t *p_mgr = + malloc(sizeof(osmv_ibms_transport_mgr_t)); + int qpn; + int ibms_status; + uint64_t port_guid; + + if (!p_mgr) { + return IB_INSUFFICIENT_MEMORY; + } + + memset(p_mgr, 0, sizeof(osmv_ibms_transport_mgr_t)); + + /* create the client socket connected to the simulator */ + /* also perform the "connect" message - such that we + validate the target guid */ + if (osm_vendor_get_guid_by_ca_and_port + (p_bo->p_vendor, hca_id, p_bo->port_num, &port_guid)) { + return IB_INVALID_GUID; + } + + conHdl = + ibms_connect(port_guid, __osmv_ibms_receiver_callback, + (void *)p_bo); + if (!conHdl) { + printf("fail to connect to the server.\n"); + exit(1); + } + + /* + * Create the MAD filter on this file handle. + */ + + p_mgr->filter.port = p_bo->port_num; + p_mgr->filter.only_input = 1; + p_mgr->filter.mask = + IBMS_BIND_MASK_PORT | + IBMS_BIND_MASK_INPUT | IBMS_BIND_MASK_QP | IBMS_BIND_MASK_CLASS; + + switch (p_info->mad_class) { + case IB_MCLASS_SUBN_LID: + case IB_MCLASS_SUBN_DIR: + qpn = 0; + p_mgr->filter.qpn = qpn; + p_mgr->filter.mgt_class = IB_MCLASS_SUBN_LID; + ibms_status = ibms_bind(conHdl, &p_mgr->filter); + if (ibms_status) { + return IB_ERROR; + } + + p_mgr->filter.mgt_class = IB_MCLASS_SUBN_DIR; + ibms_status = ibms_bind(conHdl, &p_mgr->filter); + if (ibms_status) { + return IB_ERROR; + } + + break; + + case IB_MCLASS_SUBN_ADM: + default: + qpn = 1; + p_mgr->filter.qpn = qpn; + p_mgr->filter.mgt_class = p_info->mad_class; + ibms_status = ibms_bind(conHdl, &p_mgr->filter); + if (ibms_status) { + return IB_ERROR; + } + break; + } + + p_mgr->conHdl = conHdl; + + p_bo->p_transp_mgr = p_mgr; + + /* Initialize the magic_ptr to the pointer of the p_bo info. + This will be used to signal when the object is being destroyed, so no + real action will be done then. */ + p_bo->magic_ptr = p_bo; + + return IB_SUCCESS; +} + +/* + * NAME + * osmv_transport_send_mad + * + * DESCRIPTION + * Send a single MAD (256 byte) + */ + +ib_api_status_t +osmv_transport_mad_send(IN const osm_bind_handle_t h_bind, + IN void *p_mad, IN const osm_mad_addr_t * p_mad_addr) +{ + + osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; + osm_vendor_t const *p_vend = p_bo->p_vendor; + int ret; + ibms_mad_msg_t mad_msg; + ib_api_status_t status; + + const ib_mad_t *p_mad_hdr = p_mad; + + OSM_LOG_ENTER(p_vend->p_log); + + memset(&mad_msg, 0, sizeof(mad_msg)); + + /* Make sure the p_bo object is still relevant */ + if ((p_bo->magic_ptr != p_bo) || p_bo->is_closing) + return IB_INVALID_CALLBACK; + + /* + * Copy the MAD over to the sent mad + */ + memcpy(&mad_msg.header, p_mad_hdr, MAD_BLOCK_SIZE); + + /* + * For all sends other than directed route SM MADs, + * acquire an address vector for the destination. + */ + if (p_mad_hdr->mgmt_class != IB_MCLASS_SUBN_DIR) { + + __osmv_ibms_osm_addr_to_mad_addr(p_mad_addr, + p_mad_hdr->mgmt_class == + IB_MCLASS_SUBN_LID, + &mad_msg.addr); + } else { + /* is a directed route - we need to construct a permissive address */ + /* we do not need port number since it is part of the mad_hndl */ + mad_msg.addr.dlid = IB_LID_PERMISSIVE; + mad_msg.addr.slid = IB_LID_PERMISSIVE; + mad_msg.addr.sqpn = 0; + mad_msg.addr.dqpn = 0; + } + + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "osmv_transport_mad_send: " + "Sending QPN:%d DLID:0x%04x class:0x%02x " + "method:0x%02x attr:0x%04x status:0x%04x " + "tid:0x%016" PRIx64 "\n", + mad_msg.addr.dqpn, + cl_ntoh16(mad_msg.addr.dlid), + mad_msg.header.mgmt_class, + mad_msg.header.method, + cl_ntoh16(mad_msg.header.attr_id), + cl_ntoh16(mad_msg.header.status), + cl_ntoh64(mad_msg.header.trans_id) + ); + + /* send it */ + ret = + ibms_send(((osmv_ibms_transport_mgr_t *) (p_bo->p_transp_mgr))-> + conHdl, &mad_msg); + if (ret) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osmv_transport_mad_send: ERR 5304: " + "Error sending mad (%d).\n", ret); + status = IB_ERROR; + goto Exit; + } + + status = IB_SUCCESS; + +Exit: + OSM_LOG_EXIT(p_vend->p_log); + return (status); +} + +void osmv_transport_done(IN const osm_bind_handle_t h_bind) +{ + osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; + osmv_ibms_transport_mgr_t *p_tpot_mgr = + (osmv_ibms_transport_mgr_t *) (p_bo->p_transp_mgr); + + CL_ASSERT(p_bo); + + /* First of all - zero out the magic_ptr, so if a callback is called - + it'll know that we are currently closing down, and will not handle the + mad. */ + p_bo->magic_ptr = 0; + /* usleep(3000000); */ + + ibms_disconnect(p_tpot_mgr->conHdl); + + /* seems the only way to abort a blocking read is to make it read something */ + free(p_tpot_mgr); +} + +static void +__osmv_ibms_osm_addr_to_mad_addr(IN const osm_mad_addr_t * p_osm_addr, + IN uint8_t is_smi, + OUT struct _ibms_mad_addr *p_ibms_addr) +{ + + /* For global destination or Multicast address: */ + p_ibms_addr->dlid = cl_ntoh16(p_osm_addr->dest_lid); + p_ibms_addr->sl = p_osm_addr->addr_type.gsi.service_level; + if (is_smi) { + p_ibms_addr->sqpn = 0; + p_ibms_addr->dqpn = 0; + } else { + p_ibms_addr->sqpn = 1; + p_ibms_addr->dqpn = + cl_ntoh32(p_osm_addr->addr_type.gsi.remote_qp); + } + /* + HACK we limit to the first PKey Index assuming it will + always be the default PKey + */ + p_ibms_addr->pkey_index = 0; +} + +static void +__osmv_ibms_mad_addr_to_osm_addr(IN osm_vendor_t const *p_vend, + IN struct _ibms_mad_addr *p_ibms_addr, + IN uint8_t is_smi, + OUT osm_mad_addr_t * p_osm_addr) +{ + memset(p_osm_addr, 0, sizeof(osm_mad_addr_t)); + p_osm_addr->dest_lid = cl_hton16(p_ibms_addr->slid); + p_osm_addr->static_rate = 0; + p_osm_addr->path_bits = 0; + if (is_smi) { + /* SMI */ + p_osm_addr->addr_type.smi.source_lid = + cl_hton16(p_ibms_addr->slid); + p_osm_addr->addr_type.smi.port_num = 1; /* TODO add if required p_ibms_addr->port; */ + } else { + /* GSI */ + p_osm_addr->addr_type.gsi.remote_qp = + cl_ntoh32(p_ibms_addr->sqpn); + p_osm_addr->addr_type.gsi.remote_qkey = IB_QP1_WELL_KNOWN_Q_KEY; + p_osm_addr->addr_type.gsi.pkey_ix = p_ibms_addr->pkey_index; + p_osm_addr->addr_type.gsi.service_level = p_ibms_addr->sl; + + p_osm_addr->addr_type.gsi.global_route = FALSE; + /* copy the GRH data if relevant - TopSpin imp doesnt relate to GRH!!! */ + /* + if (p_osm_addr->addr_type.gsi.global_route) + { + p_osm_addr->addr_type.gsi.grh_info.ver_class_flow = + ib_grh_set_ver_class_flow(p_rcv_desc->grh.IP_version, + p_rcv_desc->grh.traffic_class, + p_rcv_desc->grh.flow_label); + p_osm_addr->addr_type.gsi.grh_info.hop_limit = p_rcv_desc->grh.hop_limit; + memcpy(&p_osm_addr->addr_type.gsi.grh_info.src_gid.raw, + &p_rcv_desc->grh.sgid, sizeof(ib_net64_t)); + memcpy(&p_osm_addr->addr_type.gsi.grh_info.dest_gid.raw, + p_rcv_desc->grh.dgid, sizeof(ib_net64_t)); + } + */ + } +} + +/* + * NAME osm_vendor_set_sm + * + * DESCRIPTION Modifies the port info for the bound port to set the "IS_SM" bit + * according to the value given (TRUE or FALSE). + */ + +void osm_vendor_set_sm(IN osm_bind_handle_t h_bind, IN boolean_t is_sm_val) +{ + osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; + osm_vendor_t const *p_vend = p_bo->p_vendor; + int ret; + ibms_cap_msg_t cap_msg; + + OSM_LOG_ENTER(p_vend->p_log); + + cap_msg.mask = IB_PORT_CAP_IS_SM; + if (is_sm_val) + cap_msg.capabilities = IB_PORT_CAP_IS_SM; + else + cap_msg.capabilities = 0; + + ret = ibms_set_cap(((osmv_ibms_transport_mgr_t *) (p_bo-> + p_transp_mgr))-> + conHdl, &cap_msg); + + if (ret) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_set_sm: ERR 5312: " + "Unable set 'IS_SM' bit to:%u in port attributes.\n", + is_sm_val); + } + OSM_LOG_EXIT(p_vend->p_log); +} diff --git a/branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_mlx_ts.c b/branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_mlx_ts.c new file mode 100644 index 00000000..3966aacf --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_mlx_ts.c @@ -0,0 +1,505 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* AUTHOR Edward Bortnikov + * + * DESCRIPTION + * The lower-level MAD transport interface implementation + * that allows sending a single MAD/receiving a callback + * when a single MAD is received. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +typedef struct _osmv_TOPSPIN_transport_mgr_ { + int device_fd; + osm_ts_user_mad_filter filter; + cl_thread_t receiver; +} osmv_TOPSPIN_transport_mgr_t; + +static void +__osmv_TOPSPIN_mad_addr_to_osm_addr(IN osm_vendor_t const *p_vend, + IN struct ib_mad *p_mad, + IN uint8_t is_smi, + OUT osm_mad_addr_t * p_mad_addr); + +static void +__osmv_TOPSPIN_osm_addr_to_mad_addr(IN const osm_mad_addr_t * p_mad_addr, + IN uint8_t is_smi, + OUT struct ib_mad *p_mad); + +void __osmv_TOPSPIN_receiver_thr(void *p_ctx) +{ + int ts_ret_code; + struct ib_mad mad; + osm_mad_addr_t mad_addr; + osmv_bind_obj_t *const p_bo = (osmv_bind_obj_t *) p_ctx; + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER(p_bo->p_vendor->p_log); + + /* Make sure the p_bo object is still relevant */ + if ((p_bo->magic_ptr != p_bo) || p_bo->is_closing) + return; + + /* we set the type of cancelation for this thread */ + /* pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); */ + + while (1) { + /* Make sure the p_bo object is still relevant */ + if ((p_bo->magic_ptr != p_bo) || p_bo->is_closing) + return; + + /* we read one mad at a time and pass it to the read callback function */ + ts_ret_code = + read(((osmv_TOPSPIN_transport_mgr_t *) (p_bo-> + p_transp_mgr))-> + device_fd, &mad, sizeof(mad)); + /* Make sure the p_bo object is still relevant */ + if ((p_bo->magic_ptr != p_bo) || p_bo->is_closing) + return; + + if (ts_ret_code != sizeof(mad)) { + osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, + "__osmv_TOPSPIN_receiver_thr: ERR 6803: " + "error with read, bytes = %d, errno = %d\n", + ts_ret_code, errno); + break; + } else { + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "__osmv_TOPSPIN_receiver_thr: " + "MAD QPN:%d SLID:0x%04x class:0x%02x " + "method:0x%02x attr:0x%04x status:0x%04x " + "tid:0x%016" PRIx64 "\n", + mad.dqpn, + cl_ntoh16(mad.slid), + mad.mgmt_class, + mad.r_method, + cl_ntoh16(mad.attribute_id), + cl_ntoh16(mad.status), + cl_ntoh64(mad.transaction_id)); + + /* first arrange an address */ + __osmv_TOPSPIN_mad_addr_to_osm_addr(p_bo->p_vendor, + &mad, + (((ib_mad_t *) & + mad)-> + mgmt_class == + IB_MCLASS_SUBN_LID) + || + (((ib_mad_t *) & + mad)-> + mgmt_class == + IB_MCLASS_SUBN_DIR), + &mad_addr); + + /* call the receiver callback */ + + status = + osmv_dispatch_mad((osm_bind_handle_t) p_bo, + (void *)&mad, &mad_addr); + + /* Make sure the p_bo object is still relevant */ + if ((p_bo->magic_ptr != p_bo) || p_bo->is_closing) + return; + + if (IB_INTERRUPTED == status) { + + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "__osmv_TOPSPIN_receiver_thr: " + "The bind handle %p is being closed. " + "Breaking the loop.\n", p_bo); + break; + } + } + } + + OSM_LOG_EXIT(p_bo->p_vendor->p_log); +} + +/* + * NAME + * osmv_transport_init + * + * DESCRIPTION + * Setup the MAD transport infrastructure (filters, callbacks etc). + */ + +ib_api_status_t +osmv_transport_init(IN osm_bind_info_t * p_info, + IN char hca_id[VENDOR_HCA_MAXNAMES], + IN uint8_t hca_idx, IN osmv_bind_obj_t * p_bo) +{ + cl_status_t cl_st; + char device_file[16]; + int device_fd; + int ts_ioctl_ret; + osmv_TOPSPIN_transport_mgr_t *p_mgr = + malloc(sizeof(osmv_TOPSPIN_transport_mgr_t)); + int qpn; + + if (!p_mgr) { + return IB_INSUFFICIENT_MEMORY; + } + + memset(p_mgr, 0, sizeof(osmv_TOPSPIN_transport_mgr_t)); + + /* open TopSpin file device */ + /* HACK: assume last char in hostid is the HCA index */ + sprintf(device_file, "/dev/ts_ua%u", hca_idx); + device_fd = open(device_file, O_RDWR); + if (device_fd < 0) { + fprintf(stderr, "Fatal: Fail to open the file:%s err:%d\n", + device_file, errno); + return IB_ERROR; + } + + /* + * Create the MAD filter on this file handle. + */ + + p_mgr->filter.port = p_bo->port_num; + p_mgr->filter.direction = TS_IB_MAD_DIRECTION_IN; + p_mgr->filter.mask = + TS_IB_MAD_FILTER_DIRECTION | + TS_IB_MAD_FILTER_PORT | + TS_IB_MAD_FILTER_QPN | TS_IB_MAD_FILTER_MGMT_CLASS; + + switch (p_info->mad_class) { + case IB_MCLASS_SUBN_LID: + case IB_MCLASS_SUBN_DIR: + qpn = 0; + p_mgr->filter.qpn = qpn; + p_mgr->filter.mgmt_class = IB_MCLASS_SUBN_LID; + ts_ioctl_ret = + ioctl(device_fd, TS_IB_IOCSMADFILTADD, &p_mgr->filter); + if (ts_ioctl_ret < 0) { + return IB_ERROR; + } + + p_mgr->filter.mgmt_class = IB_MCLASS_SUBN_DIR; + ts_ioctl_ret = + ioctl(device_fd, TS_IB_IOCSMADFILTADD, &p_mgr->filter); + if (ts_ioctl_ret < 0) { + return IB_ERROR; + } + + break; + + case IB_MCLASS_SUBN_ADM: + default: + qpn = 1; + p_mgr->filter.qpn = qpn; + p_mgr->filter.mgmt_class = p_info->mad_class; + ts_ioctl_ret = + ioctl(device_fd, TS_IB_IOCSMADFILTADD, &p_mgr->filter); + if (ts_ioctl_ret < 0) { + return IB_ERROR; + } + break; + } + + p_mgr->device_fd = device_fd; + + p_bo->p_transp_mgr = p_mgr; + + /* Initialize the magic_ptr to the pointer of the p_bo info. + This will be used to signal when the object is being destroyed, so no + real action will be done then. */ + p_bo->magic_ptr = p_bo; + + /* init receiver thread */ + cl_st = + cl_thread_init(&p_mgr->receiver, __osmv_TOPSPIN_receiver_thr, + (void *)p_bo, "osmv TOPSPIN rcv thr"); + + return (ib_api_status_t) cl_st; +} + +/* + * NAME + * osmv_transport_send_mad + * + * DESCRIPTION + * Send a single MAD (256 byte) + */ + +ib_api_status_t +osmv_transport_mad_send(IN const osm_bind_handle_t h_bind, + IN void *p_mad, IN const osm_mad_addr_t * p_mad_addr) +{ + + osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; + osm_vendor_t const *p_vend = p_bo->p_vendor; + struct ib_mad ts_mad; + int ret; + ib_api_status_t status; + + const ib_mad_t *p_mad_hdr = p_mad; + + OSM_LOG_ENTER(p_vend->p_log); + + memset(&ts_mad, 0, sizeof(ts_mad)); + + /* Make sure the p_bo object is still relevant */ + if ((p_bo->magic_ptr != p_bo) || p_bo->is_closing) + return IB_INVALID_CALLBACK; + + /* + * Copy the MAD over to the sent mad + */ + memcpy(&ts_mad, p_mad_hdr, MAD_BLOCK_SIZE); + + /* + * For all sends other than directed route SM MADs, + * acquire an address vector for the destination. + */ + if (p_mad_hdr->mgmt_class != IB_MCLASS_SUBN_DIR) { + + __osmv_TOPSPIN_osm_addr_to_mad_addr(p_mad_addr, + p_mad_hdr->mgmt_class == + IB_MCLASS_SUBN_LID, + &ts_mad); + } else { + /* is a directed route - we need to construct a permissive address */ + /* we do not need port number since it is part of the mad_hndl */ + ts_mad.dlid = IB_LID_PERMISSIVE; + ts_mad.slid = IB_LID_PERMISSIVE; + ts_mad.sqpn = 0; + ts_mad.dqpn = 0; + } + + ts_mad.port = p_bo->port_num; + + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "osmv_transport_mad_send: " + "Sending QPN:%d DLID:0x%04x class:0x%02x " + "method:0x%02x attr:0x%04x status:0x%04x " + "tid:0x%016" PRIx64 "\n", + ts_mad.dqpn, + cl_ntoh16(ts_mad.dlid), + ts_mad.mgmt_class, + ts_mad.r_method, + cl_ntoh16(ts_mad.attribute_id), + cl_ntoh16(ts_mad.status), cl_ntoh64(ts_mad.transaction_id) + ); + + /* send it */ + ret = + write(((osmv_TOPSPIN_transport_mgr_t *) (p_bo->p_transp_mgr))-> + device_fd, &ts_mad, sizeof(ts_mad)); + + if (ret != sizeof(ts_mad)) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osmv_transport_mad_send: ERR 6804: " + "Error sending mad (%d).\n", ret); + status = IB_ERROR; + goto Exit; + } + + status = IB_SUCCESS; + +Exit: + OSM_LOG_EXIT(p_vend->p_log); + return (status); +} + +/* + register a new mad type to the opened device file + and send a mad through - the main idea is to make + the filter catch it such that the read unblocks +*/ +void __osm_transport_gen_dummy_mad(osmv_bind_obj_t * p_bo) +{ + struct ib_mad ts_mad; + osmv_TOPSPIN_transport_mgr_t *p_mgr = + (osmv_TOPSPIN_transport_mgr_t *) (p_bo->p_transp_mgr); + struct ib_get_port_info_ioctl port_data; + int ts_ioctl_ret; + + /* prepare the mad fields following the stored filter on the bind */ + memset(&ts_mad, 0, sizeof(ts_mad)); + ts_mad.format_version = 1; + ts_mad.mgmt_class = p_mgr->filter.mgmt_class; + ts_mad.attribute_id = 0x2; + ts_mad.class_version = 1; + ts_mad.r_method = cl_ntoh16(0x2); + ts_mad.port = p_bo->port_num; + ts_mad.sqpn = p_mgr->filter.qpn; + ts_mad.dqpn = p_mgr->filter.qpn; + ts_mad.slid = 0xffff; + /* we must send to our local lid ... */ + port_data.port = p_bo->port_num; + ts_ioctl_ret = ioctl(p_mgr->device_fd, TS_IB_IOCGPORTINFO, &port_data); + ts_mad.dlid = port_data.port_info.lid; + ts_mad.transaction_id = 0x9999; + write(p_mgr->device_fd, &ts_mad, sizeof(ts_mad)); +} + +void osmv_transport_done(IN const osm_bind_handle_t h_bind) +{ + osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; + osmv_TOPSPIN_transport_mgr_t *p_tpot_mgr = + (osmv_TOPSPIN_transport_mgr_t *) (p_bo->p_transp_mgr); + + CL_ASSERT(p_bo); + + /* First of all - zero out the magic_ptr, so if a callback is called - + it'll know that we are currently closing down, and will not handle the + mad. */ + p_bo->magic_ptr = 0; + /* usleep(3000000); */ + + /* seems the only way to abort a blocking read is to make it read something */ + __osm_transport_gen_dummy_mad(p_bo); + cl_thread_destroy(&(p_tpot_mgr->receiver)); + free(p_tpot_mgr); +} + +static void +__osmv_TOPSPIN_osm_addr_to_mad_addr(IN const osm_mad_addr_t * p_mad_addr, + IN uint8_t is_smi, OUT struct ib_mad *p_mad) +{ + + /* For global destination or Multicast address: */ + p_mad->dlid = cl_ntoh16(p_mad_addr->dest_lid); + p_mad->sl = p_mad_addr->addr_type.gsi.service_level; + if (is_smi) { + p_mad->sqpn = 0; + p_mad->dqpn = 0; + } else { + p_mad->sqpn = 1; + p_mad->dqpn = cl_ntoh32(p_mad_addr->addr_type.gsi.remote_qp); + } + /* + HACK we limit to the first PKey Index assuming it will + always be the default PKey + */ + p_mad->pkey_index = 0; +} + +static void +__osmv_TOPSPIN_mad_addr_to_osm_addr(IN osm_vendor_t const *p_vend, + IN struct ib_mad *p_mad, + IN uint8_t is_smi, + OUT osm_mad_addr_t * p_mad_addr) +{ + p_mad_addr->dest_lid = cl_hton16(p_mad->slid); + p_mad_addr->static_rate = 0; + p_mad_addr->path_bits = 0; + if (is_smi) { + /* SMI */ + p_mad_addr->addr_type.smi.source_lid = cl_hton16(p_mad->slid); + p_mad_addr->addr_type.smi.port_num = p_mad->port; + } else { + /* GSI */ + p_mad_addr->addr_type.gsi.remote_qp = cl_ntoh32(p_mad->sqpn); + p_mad_addr->addr_type.gsi.remote_qkey = IB_QP1_WELL_KNOWN_Q_KEY; + /* There is a TAVOR limitation that only one P_KEY is supported per */ + /* QP - so QP1 must use IB_DEFAULT_PKEY */ + p_mad_addr->addr_type.gsi.pkey_ix = p_mad->pkey_index; + p_mad_addr->addr_type.gsi.service_level = p_mad->sl; + + p_mad_addr->addr_type.gsi.global_route = FALSE; + /* copy the GRH data if relevant - TopSpin imp doesnt relate to GRH!!! */ + /* + if (p_mad_addr->addr_type.gsi.global_route) + { + p_mad_addr->addr_type.gsi.grh_info.ver_class_flow = + ib_grh_set_ver_class_flow(p_rcv_desc->grh.IP_version, + p_rcv_desc->grh.traffic_class, + p_rcv_desc->grh.flow_label); + p_mad_addr->addr_type.gsi.grh_info.hop_limit = p_rcv_desc->grh.hop_limit; + memcpy(&p_mad_addr->addr_type.gsi.grh_info.src_gid.raw, + &p_rcv_desc->grh.sgid, sizeof(ib_net64_t)); + memcpy(&p_mad_addr->addr_type.gsi.grh_info.dest_gid.raw, + p_rcv_desc->grh.dgid, sizeof(ib_net64_t)); + } + */ + } +} + +/* + * NAME osm_vendor_set_sm + * + * DESCRIPTION Modifies the port info for the bound port to set the "IS_SM" bit + * according to the value given (TRUE or FALSE). + */ +#if (defined(OSM_VENDOR_INTF_TS_NO_VAPI) || defined(OSM_VENDOR_INTF_TS)) + +void osm_vendor_set_sm(IN osm_bind_handle_t h_bind, IN boolean_t is_sm_val) +{ + osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; + osm_vendor_t const *p_vend = p_bo->p_vendor; + int ts_ioctl_ret; + int device_fd = + ((osmv_TOPSPIN_transport_mgr_t *) (p_bo->p_transp_mgr))->device_fd; + struct ib_set_port_info_ioctl set_port_data; + + OSM_LOG_ENTER(p_vend->p_log); + + memset(&set_port_data, 0, sizeof(set_port_data)); + + set_port_data.port = p_bo->port_num; + set_port_data.port_info.valid_fields = IB_PORT_IS_SM; + set_port_data.port_info.is_sm = is_sm_val; + ts_ioctl_ret = ioctl(device_fd, TS_IB_IOCSPORTINFO, &set_port_data); + if (ts_ioctl_ret < 0) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_set_sm: ERR 6805: " + "Unable set 'IS_SM' bit to:%u in port attributes (%d).\n", + is_sm_val, ts_ioctl_ret); + } + + OSM_LOG_EXIT(p_vend->p_log); +} + +#endif diff --git a/branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_mlx_txn.c b/branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_mlx_txn.c new file mode 100644 index 00000000..55c312a3 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/libvendor/osm_vendor_mlx_txn.c @@ -0,0 +1,680 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005,2009 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include + +#include +#include +#include +#include +#include + +static ib_api_status_t +__osmv_txnmgr_lookup(IN osmv_txn_mgr_t * p_tx_mgr, + IN uint64_t key, OUT osmv_txn_ctx_t ** pp_txn); + +static ib_api_status_t +__osmv_txnmgr_insert_txn(IN osmv_txn_mgr_t * p_tx_mgr, + IN osmv_txn_ctx_t * p_txn, IN uint64_t key); + +static ib_api_status_t +__osmv_txnmgr_remove_txn(IN osmv_txn_mgr_t * p_tx_mgr, + IN uint64_t key, OUT osmv_txn_ctx_t ** pp_txn); + +static void __osmv_txn_all_done(osm_bind_handle_t h_bind); + +static uint64_t +__osmv_txn_timeout_cb(IN uint64_t key, + IN uint32_t num_regs, IN void *cb_context); + +ib_api_status_t +osmv_txn_init(IN osm_bind_handle_t h_bind, + IN uint64_t tid, IN uint64_t key, OUT osmv_txn_ctx_t ** pp_txn) +{ + ib_api_status_t st; + osmv_txn_ctx_t *p_txn; + osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; + + OSM_LOG_ENTER(p_bo->p_vendor->p_log); + + CL_ASSERT(NULL != h_bind && NULL != pp_txn); + + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "Starting transaction 0x%016" PRIx64 + " (key=0x%016" PRIx64 ")\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%016" PRIx64 + " (key=0x%016" PRIx64 ") 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%016" PRIx64 " 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%016" PRIx64 "\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%016" PRIx64 " 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%016" PRIx64 "\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%016" PRIx64 " - " + "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 <= OSM_DEFAULT_RETRY_COUNT) { + /* 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%016" PRIx64 ")" + " 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%016" PRIx64 ").\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 (0x%016" PRIx64 ") " + "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%016" PRIx64 ") 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 <= OSM_DEFAULT_RETRY_COUNT) { + /* 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%016" PRIx64 "). 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/branches/WOF2-3/ulp/opensm/user/libvendor/osmv_ibal.exports b/branches/WOF2-3/ulp/opensm/user/libvendor/osmv_ibal.exports new file mode 100644 index 00000000..f77a1e92 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/libvendor/osmv_ibal.exports @@ -0,0 +1,34 @@ +#if DBG +LIBRARY osmv_ibald.lib +#else +LIBRARY osmv_ibal.lib +#endif + + +EXPORTS +osm_vendor_set_debug +cl_disp_init +cl_disp_destroy +cl_disp_shutdown +cl_event_wheel_init +cl_event_wheel_destroy +cl_event_wheel_construct +cl_event_wheel_reg +cl_event_wheel_num_regs +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 +getopt_long_only diff --git a/branches/WOF2-3/ulp/opensm/user/libvendor/osmv_openib.exports b/branches/WOF2-3/ulp/opensm/user/libvendor/osmv_openib.exports new file mode 100644 index 00000000..1bb39faf --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/libvendor/osmv_openib.exports @@ -0,0 +1,33 @@ +#if DBG +LIBRARY osmv_openibd.lib +#else +LIBRARY osmv_openib.lib +#endif + + +EXPORTS +osm_vendor_set_debug +cl_disp_init +cl_disp_destroy +cl_disp_shutdown +cl_event_wheel_init +cl_event_wheel_destroy +cl_event_wheel_construct +cl_event_wheel_reg +cl_event_wheel_num_regs +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 diff --git a/branches/WOF2-3/ulp/opensm/user/libvendor/vendor-ibal.inc b/branches/WOF2-3/ulp/opensm/user/libvendor/vendor-ibal.inc new file mode 100644 index 00000000..473e9f8f --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/libvendor/vendor-ibal.inc @@ -0,0 +1,6 @@ +# vendor IBAL +VENDOR_LIB=osmv_ibal +VENDOR_IF=OSM_VENDOR_INTF_AL +VENDOR_SRC=osm_vendor_al.c osm_vendor_mlx_sa.c +VENDOR_INC= + diff --git a/branches/WOF2-3/ulp/opensm/user/libvendor/vendor-umad.inc b/branches/WOF2-3/ulp/opensm/user/libvendor/vendor-umad.inc new file mode 100644 index 00000000..b927e797 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/libvendor/vendor-umad.inc @@ -0,0 +1,5 @@ +# Vendor UMAD +VENDOR_LIB=osmv_openib +VENDOR_IF=OSM_VENDOR_INTF_OPENIB +VENDOR_SRC=osm_vendor_ibumad.c osm_vendor_ibumad_sa.c +VENDOR_INC=$(WINIBHOME)\ulp\libibmad\include; $(WINIBHOME)\ulp\libibumad\include; diff --git a/branches/WOF2-3/ulp/opensm/user/libvendor/winosm_common.c b/branches/WOF2-3/ulp/opensm/user/libvendor/winosm_common.c new file mode 100644 index 00000000..5fd6ea8a --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/libvendor/winosm_common.c @@ -0,0 +1,215 @@ + +#include +#include +#include +#include +#include +#include + +#include <..\..\..\..\etc\user\inet.c> + +/* + * Just like fopen() except the filename string is env var expanded prior + * to opening the file. Allows %TEMP%\osm.log to work. + */ +#undef fopen + +FILE *Fopen( + const char *filename, + const char *mode ) +{ + FILE *pFile; + char *fname; + + fname = strdup_expand(filename); + pFile = fopen(fname,mode); + free(fname); + return pFile; +} + +#define OSM_MAX_LOG_NAME_SIZE 512 + +static char *syslog_fname; +static FILE *syslog_file; +static char *syslog_id; + +void openlog(char *ident, int option, int facility) +{ + if (!syslog_fname) + syslog_fname = strdup(OSM_DEFAULT_TMP_DIR "osm.syslog"); + + if (!syslog_file) { + syslog_file = Fopen(syslog_fname,"w"); + if (syslog_file) + syslog_id = strdup(ident); + } +} + +void closelog(void) +{ + if (syslog_file) { + fprintf(syslog_file, "\n[%s] Closing syslog\n",syslog_id); + fflush(syslog_file); + fclose(syslog_file); + syslog_file = NULL; + if (syslog_id) { + free((void*)syslog_id); + syslog_id = NULL; + } + if (syslog_fname) { + free((void*)syslog_fname); + syslog_fname = NULL; + } + } +} + +/* output to user-mode DebugView monitor if running */ + +void syslog(int prio, char *fmt, ... ) +{ + char Buffer[1400]; + SYSTEMTIME st; + uint32_t pid = GetCurrentThreadId(); + int rc; + va_list args; + + va_start(args,fmt); + rc = _vsnprintf(Buffer, sizeof(Buffer), (LPSTR)fmt, args); + va_end(args); + + if (!syslog_file) { + OutputDebugStringA(Buffer); + return; + } + + if ( rc < 0 ) + fprintf(syslog_file,"syslog() overflow @ %d\n", sizeof(Buffer)); + + GetLocalTime(&st); + + fprintf(syslog_file, "[%s][%02d-%02d-%4d %02d:%02d:%02d:%03d][%04X] %s", + syslog_id, st.wMonth, st.wDay, st.wYear, + st.wHour, st.wMinute, st.wSecond, st.wMilliseconds, pid, + Buffer); + fflush(syslog_file); +} + + +#if 0 +/* Mellanox specific WinIB_HOME env var override of %TEMP% from previous + * openSM port; Not currently utilized pending feedback. + */ + +char* +GetOsmTempPath(void) +{ + char* temp_path; + int length; + + temp_path = (char*)cl_malloc(OSM_MAX_LOG_NAME_SIZE); + if (!temp_path) + return temp_path; + + length = GetTempPath(OSM_MAX_LOG_NAME_SIZE,temp_path); + if (length > OSM_MAX_LOG_NAME_SIZE) + { + cl_free(temp_path); + temp_path = (char*)cl_malloc(length+1); + GetTempPath(length+1,temp_path); + } + return temp_path; +} + +char* +GetOsmCachePath(void) +{ + char* cache_path; + char* tmp_file_name; + char* winib_home, tmp; + HANDLE hFile; + + winib_home = getenv("WinIB_HOME"); + if (winib_home == NULL) + { + /* The WinIB_HOME variable isn't defined. Use the + default temp path */ + return GetOsmTempPath(); + } + cache_path = (char*)cl_malloc(OSM_MAX_LOG_NAME_SIZE); + strcpy(cache_path, winib_home); + + strcat(cache_path, "\\etc\\"); + tmp_file_name = (char*)cl_malloc(OSM_MAX_LOG_NAME_SIZE); + strcpy(tmp_file_name, cache_path); + strcat(tmp_file_name, "opensm.opts"); + hFile = CreateFile(tmp_file_name, + GENERIC_READ, + 0, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + if (hFile == INVALID_HANDLE_VALUE) + { + cl_free(cache_path); + return GetOsmTempPath(); + } + /* Such file exists. This means the directory is usable */ + CloseHandle(hFile); + + return cache_path; +} +#endif + + +/* + * Like _strdup() with Environment varible expansion. + * Example: str '%windir%\temp\osm.log' --> 'C:\windows\temp\osm.log' + * Multiple Env vars are supported. + */ + +char *strdup_expand(const char *base) +{ + char *str,*p,*s,*es,*xs,*rc,*n; + char p_env[80]; + + str = _strdup(base); + + while( (s = strchr(str,'%')) ) + { + p = strchr((++s),'%'); + if (!p) + return str; + + memcpy(p_env,s,p-s); + p_env[p-s] = '\0'; + + es = getenv(p_env); + if (!es) + return str; + + xs = (char*)malloc(strlen(str)+strlen(es)); + for(rc=str,n=xs; rc < (s-1);rc++) *n++ = *rc; + *n='\0'; + strcat(n,es); + strcat(n,(p+1)); + free(str); + str = xs; + } + return str; +} + + +/****************************************************************************/ + +#include <..\..\..\etc\user\getopt.c> + +int getopt_long_only(int argc, char *const*argv, const char *optstring, + const struct option *longopts, int *longindex) +{ + return getopt_long( argc, argv, optstring, longopts, longindex ); +} + +/* getimeofday() */ +#include <..\..\..\etc\user\gtod.c> + diff --git a/branches/WOF2-3/ulp/opensm/user/mad-vendor.inc b/branches/WOF2-3/ulp/opensm/user/mad-vendor.inc new file mode 100644 index 00000000..bb66968d --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/mad-vendor.inc @@ -0,0 +1,6 @@ + +# include only 'one' mad vendor. + +#!INCLUDE vendor-ibal.inc + +!INCLUDE vendor-umad.inc diff --git a/branches/WOF2-3/ulp/opensm/user/man/opensm.8 b/branches/WOF2-3/ulp/opensm/user/man/opensm.8 new file mode 100644 index 00000000..a45d6786 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/man/opensm.8 @@ -0,0 +1,1105 @@ +.TH OPENSM 8 "October 22, 2009" "OpenIB" "OpenIB Management" + +.SH NAME +opensm \- InfiniBand subnet manager and administration (SM/SA) + +.SH SYNOPSIS +.B opensm +[\-\-version]] +[\-F | \-\-config ] +[\-c(reate-config) ] +[\-g(uid) ] +[\-l(mc) ] +[\-p(riority) ] +[\-smkey ] +[\-\-sm_sl ] +[\-r(eassign_lids)] +[\-R | \-\-routing_engine ] +[\-\-do_mesh_analysis] +[\-\-lash_start_vl ] +[\-A | \-\-ucast_cache] +[\-z | \-\-connect_roots] +[\-M | \-\-lid_matrix_file ] +[\-U | \-\-lfts_file ] +[\-S | \-\-sadb_file ] +[\-a | \-\-root_guid_file ] +[\-u | \-\-cn_guid_file ] +[\-G | \-\-io_guid_file ] +[\-H | \-\-max_reverse_hops ] +[\-X | \-\-guid_routing_order_file ] +[\-m | \-\-ids_guid_file ] +[\-o(nce)] +[\-s(weep) ] +[\-t(imeout) ] +[\-\-retries ] +[\-maxsmps ] +[\-console [off | local | socket | loopback]] +[\-console-port ] +[\-i(gnore-guids) ] +[\-w | \-\-hop_weights_file ] +[\-f | \-\-log_file ] +[\-L | \-\-log_limit ] [\-e(rase_log_file)] +[\-P(config) ] +[\-N | \-\-no_part_enforce] +[\-Q | \-\-qos [\-Y | \-\-qos_policy_file ]] +[\-y | \-\-stay_on_fatal] +[\-B | \-\-daemon] +[\-I | \-\-inactive] +[\-\-perfmgr] +[\-\-perfmgr_sweep_time_s ] +[\-\-prefix_routes_file ] +[\-\-consolidate_ipv6_snm_req] +[\-v(erbose)] [\-V] [\-D ] [\-d(ebug) ] +[\-h(elp)] [\-?] + +.SH DESCRIPTION +.PP +opensm is an InfiniBand compliant Subnet Manager and Administration, +and runs on top of OpenIB. + +opensm provides an implementation of an InfiniBand Subnet Manager and +Administration. Such a software entity is required to run for in order +to initialize the InfiniBand hardware (at least one per each +InfiniBand subnet). + +opensm also now contains an experimental version of a performance +manager as well. + +opensm defaults were designed to meet the common case usage on clusters with up to a few hundred nodes. Thus, in this default mode, opensm will scan the IB +fabric, initialize it, and sweep occasionally for changes. + +opensm attaches to a specific IB port on the local machine and configures only +the fabric connected to it. (If the local machine has other IB ports, +opensm will ignore the fabrics connected to those other ports). If no port is +specified, it will select the first "best" available port. + +opensm can present the available ports and prompt for a port number to +attach to. + +By default, the run is logged to two files: /var/log/messages and /var/log/opensm.log. +The first file will register only general major events, whereas the second +will include details of reported errors. All errors reported in this second +file should be treated as indicators of IB fabric health issues. +(Note that when a fatal and non-recoverable error occurs, opensm will exit.) +Both log files should include the message "SUBNET UP" if opensm was able to +setup the subnet correctly. + +.SH OPTIONS + +.PP +.TP +\fB\-\-version\fR +Prints OpenSM version and exits. +.TP +\fB\-F\fR, \fB\-\-config\fR +The name of the OpenSM config file. When not specified +\fB\% /usr/local/etc/opensm/opensm.conf\fP will be used (if exists). +.TP +\fB\-c\fR, \fB\-\-create-config\fR +OpenSM will dump its configuration to the specified file and exit. +This is a way to generate OpenSM configuration file template. +.TP +\fB\-g\fR, \fB\-\-guid\fR +This option specifies the local port GUID value +with which OpenSM should bind. OpenSM may be +bound to 1 port at a time. +If GUID given is 0, OpenSM displays a list +of possible port GUIDs and waits for user input. +Without -g, OpenSM tries to use the default port. +.TP +\fB\-l\fR, \fB\-\-lmc\fR +This option specifies the subnet's LMC value. +The number of LIDs assigned to each port is 2^LMC. +The LMC value must be in the range 0-7. +LMC values > 0 allow multiple paths between ports. +LMC values > 0 should only be used if the subnet +topology actually provides multiple paths between +ports, i.e. multiple interconnects between switches. +Without -l, OpenSM defaults to LMC = 0, which allows +one path between any two ports. +.TP +\fB\-p\fR, \fB\-\-priority\fR +This option specifies the SM\'s PRIORITY. +This will effect the handover cases, where master +is chosen by priority and GUID. Range goes from 0 +(default and lowest priority) to 15 (highest). +.TP +\fB\-smkey\fR +This option specifies the SM\'s SM_Key (64 bits). +This will effect SM authentication. +Note that OpenSM version 3.2.1 and below used the default value '1' +in a host byte order, it is fixed now but you may need this option to +interoperate with old OpenSM running on a little endian machine. +.TP +\fB\-\-sm_sl\fR +This option sets the SL to use for communication with the SM/SA. +Defaults to 0. +.TP +\fB\-r\fR, \fB\-\-reassign_lids\fR +This option causes OpenSM to reassign LIDs to all +end nodes. Specifying -r on a running subnet +may disrupt subnet traffic. +Without -r, OpenSM attempts to preserve existing +LID assignments resolving multiple use of same LID. +.TP +\fB\-R\fR, \fB\-\-routing_engine\fR +This option chooses routing engine(s) to use instead of Min Hop +algorithm (default). Multiple routing engines can be specified +separated by commas so that specific ordering of routing algorithms +will be tried if earlier routing engines fail. +Supported engines: minhop, updn, file, ftree, lash, dor +.TP +\fB\-\-do_mesh_analysis\fR +This option enables additional analysis for the lash routing engine to +precondition switch port assignments in regular cartesian meshes which +may reduce the number of SLs required to give a deadlock free routing. +.TP +\fB\-\-lash_start_vl\fR +This option sets the starting VL to use for the lash routing algorithm. +Defaults to 0. +.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 routing engines (up/down and +fat-tree) to make connectivity between root switches and in +this way to be fully IBA complaint. In many cases this can +violate "pure" deadlock free algorithm, so use it carefully. +.TP +\fB\-M\fR, \fB\-\-lid_matrix_file\fR +This option specifies the name of the lid matrix dump file +from where switch lid matrices (min hops tables will be +loaded. +.TP +\fB\-U\fR, \fB\-\-lfts_file\fR +This option specifies the name of the LFTs file +from where switch forwarding tables will be loaded. +.TP +\fB\-S\fR, \fB\-\-sadb_file\fR +This option specifies the name of the SA DB dump file +from where SA database will be loaded. +.TP +\fB\-a\fR, \fB\-\-root_guid_file\fR +Set the root nodes for the Up/Down or Fat-Tree routing +algorithm to the guids provided in the given file (one to a line). +.TP +\fB\-u\fR, \fB\-\-cn_guid_file\fR +Set the compute nodes for the Fat-Tree routing algorithm +to the guids provided in the given file (one to a line). +.TP +\fB\-G\fR, \fB\-\-io_guid_file\fR +Set the I/O nodes for the Fat-Tree routing algorithm +to the guids provided in the given file (one to a line). +I/O nodes are non-CN nodes allowed to use up to max_reverse_hops switches +the wrong way around to improve connectivity. +.TP +\fB\-H\fR, \fB\-\-max_reverse_hops\fR +Set the maximum number of reverse hops an I/O node is allowed +to make. A reverse hop is the use of a switch the wrong way around. +.TP +\fB\-m\fR, \fB\-\-ids_guid_file\fR +Name of the map file with set of the IDs which will be used +by Up/Down routing algorithm instead of node GUIDs +(format: per line). +.TP +\fB\-X\fR, \fB\-\-guid_routing_order_file\fR +Set the order port guids will be routed for the MinHop +and Up/Down routing algorithms to the guids provided in the +given file (one to a line). +.TP +\fB\-o\fR, \fB\-\-once\fR +This option causes OpenSM to configure the subnet +once, then exit. Ports remain in the ACTIVE state. +.TP +\fB\-s\fR, \fB\-\-sweep\fR +This option specifies the number of seconds between +subnet sweeps. Specifying -s 0 disables sweeping. +Without -s, OpenSM defaults to a sweep interval of +10 seconds. +.TP +\fB\-t\fR, \fB\-\-timeout\fR +This option specifies the time in milliseconds +used for transaction timeouts. +Specifying -t 0 disables timeouts. +Without -t, OpenSM defaults to a timeout value of +200 milliseconds. +.TP +\fB\-\-retries\fR +This option specifies the number of retries used +for transactions. +Without --retries, OpenSM defaults to 3 retries +for transactions. +.TP +\fB\-maxsmps\fR +This option specifies the number of VL15 SMP MADs +allowed on the wire at any one time. +Specifying -maxsmps 0 allows unlimited outstanding +SMPs. +Without -maxsmps, OpenSM defaults to a maximum of +4 outstanding SMPs. +.TP +\fB\-console [off | local | socket | loopback]\fR +This option brings up the OpenSM console (default off). +Note that the socket and loopback options will only be available +if OpenSM was built with --enable-console-socket. +.TP +\fB\-console-port\fR +Specify an alternate telnet port for the socket console (default 10000). +Note that this option only appears if OpenSM was built with +--enable-console-socket. +.TP +\fB\-i\fR, \fB\-ignore-guids\fR +This option provides the means to define a set of ports +(by node guid and port number) that will be ignored by the link load +equalization algorithm. +.TP +\fB\-w\fR, \fB\-\-hop_weights_file\fR +This option provides weighting factors per port representing a hop cost in +computing the lid matrix. The file consists of lines containing a switch port +GUID (specified as a 64 bit hex number, with leading 0x), output port number, +and weighting factor. Any port not listed in the file defaults to a weighting +factor of 1. Lines starting with # are comments. Weights affect only the +output route from the port, so many useful configurations will require weights +to be specified in pairs. +.TP +\fB\-x\fR, \fB\-\-honor_guid2lid\fR +This option forces OpenSM to honor the guid2lid file, +when it comes out of Standby state, if such file exists +under OSM_CACHE_DIR, and is valid. +By default, this is FALSE. +.TP +\fB\-f\fR, \fB\-\-log_file\fR +This option defines the log to be the given file. +By default, the log goes to /var/log/opensm.log. +For the log to go to standard output use -f stdout. +.TP +\fB\-L\fR, \fB\-\-log_limit\fR +This option defines maximal log file size in MB. When +specified the log file will be truncated upon reaching +this limit. +.TP +\fB\-e\fR, \fB\-\-erase_log_file\fR +This option will cause deletion of the log file +(if it previously exists). By default, the log file +is accumulative. +.TP +\fB\-P\fR, \fB\-\-Pconfig\fR +This option defines the optional partition configuration file. +The default name is \fB\%/usr/local/etc/opensm/partitions.conf\fP. +.TP +\fB\-\-prefix_routes_file\fR +Prefix routes control how the SA responds to path record queries for +off-subnet DGIDs. By default, the SA fails such queries. The +.B PREFIX ROUTES +section below describes the format of the configuration file. +The default path is \fB\%/usr/local/etc/opensm/prefix\-routes.conf\fP. +.TP +\fB\-Q\fR, \fB\-\-qos\fR +This option enables QoS setup. It is disabled by default. +.TP +\fB\-Y\fR, \fB\-\-qos_policy_file\fR +This option defines the optional QoS policy file. The default +name is \fB\%/usr/local/etc/opensm/qos-policy.conf\fP. See +QoS_management_in_OpenSM.txt in opensm doc for more information on +configuring QoS policy via this file. +.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. See performance-manager-HOWTO.txt in opensm doc for +more information on running perfmgr. +.TP +\fB\-perfmgr_sweep_time_s\fR +Specify the sweep time for the performance manager in seconds +(default is 180 seconds). Only takes +effect if --enable-perfmgr was specified at configure time. +.TP +.BI --consolidate_ipv6_snm_req +Use shared MLID for IPv6 Solicited Node Multicast groups per MGID scope +and P_Key. +.TP +\fB\-v\fR, \fB\-\-verbose\fR +This option increases the log verbosity level. +The -v option may be specified multiple times +to further increase the verbosity level. +See the -D option for more information about +log verbosity. +.TP +\fB\-V\fR +This option sets the maximum verbosity level and +forces log flushing. +The -V option is equivalent to \'-D 0xFF -d 2\'. +See the -D option for more information about +log verbosity. +.TP +\fB\-D\fR +This option sets the log verbosity level. +A flags field must follow the -D option. +A bit set/clear in the flags enables/disables a +specific log level as follows: + + BIT LOG LEVEL ENABLED + ---- ----------------- + 0x01 - ERROR (error messages) + 0x02 - INFO (basic messages, low volume) + 0x04 - VERBOSE (interesting stuff, moderate volume) + 0x08 - DEBUG (diagnostic, high volume) + 0x10 - FUNCS (function entry/exit, very high volume) + 0x20 - FRAMES (dumps all SMP and GMP frames) + 0x40 - ROUTING (dump FDB routing information) + 0x80 - currently unused. + +Without -D, OpenSM defaults to ERROR + INFO (0x3). +Specifying -D 0 disables all messages. +Specifying -D 0xFF enables all messages (see -V). +High verbosity levels may require increasing +the transaction timeout with the -t option. +.TP +\fB\-d\fR, \fB\-\-debug\fR +This option specifies a debug option. +These options are not normally needed. +The number following -d selects the debug +option to enable as follows: + + OPT Description + --- ----------------- + -d0 - Ignore other SM nodes + -d1 - Force single threaded dispatching + -d2 - Force log flushing after each log message + -d3 - Disable multicast support +.TP +\fB\-h\fR, \fB\-\-help\fR +Display this usage info then exit. +.TP +\fB\-?\fR +Display this usage info then exit. + +.SH ENVIRONMENT VARIABLES +.PP +The following environment variables control opensm behavior: + +OSM_TMP_DIR - controls the directory in which the temporary files generated by +opensm are created. These files are: opensm-subnet.lst, opensm.fdbs, and +opensm.mcfdbs. By default, this directory is /var/log. + +OSM_CACHE_DIR - opensm stores certain data to the disk such that subsequent +runs are consistent. The default directory used is /var/cache/opensm. +The following file is included in it: + + guid2lid - stores the LID range assigned to each GUID + +.SH NOTES +.PP +When opensm receives a HUP signal, it starts a new heavy sweep as if a trap was received or a topology change was found. +.PP +Also, SIGUSR1 can be used to trigger a reopen of /var/log/opensm.log for +logrotate purposes. + +.SH PARTITION CONFIGURATION +.PP +The default name of OpenSM partitions configuration file is +\fB\%/usr/local/etc/opensm/partitions.conf\fP. The default may be changed +by using the --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 always +have full membership in default partition. All other end ports will have +full membership if the partition configuration file is not found or cannot +be accessed, or limited membership if the file exists and can be accessed +but there is no rule for the Default partition. + +Effectively, this amounts to the same as if one of the following rules +below appear in the partition configuration file. + +In the case of no rule for the Default partition: + +Default=0x7fff : ALL=limited, SELF=full ; + +In the case of no partition configuration file or file cannot be accessed: + +Default=0x7fff : ALL=full ; + + +File Format + +Comments: + +Line content followed after \'#\' character is comment and ignored by +parser. + +General file format: + +: ; + +Partition Definition: + +[PartitionName][=PKey][,flag[=value]][,defmember=full|limited] + + PartitionName - string, will be used with logging. When omitted + empty string will be used. + PKey - P_Key value for this partition. Only low 15 bits will + be used. When omitted will be autogenerated. + flag - used to indicate IPoIB capability of this partition. + defmember=full|limited - specifies default membership for port guid + list. Default is limited. + +Currently recognized flags are: + + ipoib - indicates that this partition may be used for IPoIB, as + result IPoIB capable MC group will be created. + rate= - specifies rate for this IPoIB MC group + (default is 3 (10GBps)) + mtu= - specifies MTU for this IPoIB MC group + (default is 4 (2048)) + sl= - specifies SL for this IPoIB MC group + (default is 0) + scope= - specifies scope for this IPoIB MC group + (default is 2 (link local)). Multiple scope settings + are permitted for a partition. + +Note that values for rate, mtu, and scope should be specified as +defined in the IBTA specification (for example, mtu=4 for 2048). + +PortGUIDs list: + + PortGUID - GUID of partition member EndPort. Hexadecimal + numbers should start from 0x, decimal numbers + are accepted too. + full or limited - indicates full or limited membership for this + port. When omitted (or unrecognized) limited + membership is assumed. + +There are two useful keywords for PortGUID definition: + + - 'ALL' means all end ports in this subnet. + - 'ALL_CAS' means all Channel Adapter end ports in this subnet. + - 'ALL_SWITCHES' means all Switch end ports in this subnet. + - 'ALL_ROUTERS' means all Router 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 ; + Default=0x7fff : ALL, ALL_SWITCHES=full, SELF=full ; + + NewPartition , ipoib : 0x123456=full, 0x3456789034=limi, 0x2134af2306 ; + + YetAnotherOne = 0x300 : SELF=full ; + YetAnotherOne = 0x300 : ALL=limited ; + + ShareIO = 0x80 , defmember=full : 0x123451, 0x123452; + # 0x123453, 0x123454 will be limited + ShareIO = 0x80 : 0x123453, 0x123454, 0x123455=full; + # 0x123456, 0x123457 will be limited + ShareIO = 0x80 : defmember=limited : 0x123456, 0x123457, 0x123458=full; + ShareIO = 0x80 , defmember=full : 0x123459, 0x12345a; + ShareIO = 0x80 , defmember=full : 0x12345b, 0x12345c=limited, 0x12345d; + + +Note: + +The following rule is equivalent to how OpenSM used to run prior to the +partition manager: + + Default=0x7fff,ipoib:ALL=full; + +.SH QOS CONFIGURATION +.PP +There are a set of QoS related low-level configuration parameters. +All these parameter names are prefixed by "qos_" string. Here is a full +list of these parameters: + + qos_max_vls - The maximum number of VLs that will be on the subnet + qos_high_limit - The limit of High Priority component of VL + Arbitration table (IBA 7.6.9) + qos_vlarb_low - Low priority VL Arbitration table (IBA 7.6.9) + template + qos_vlarb_high - High priority VL Arbitration table (IBA 7.6.9) + template + Both VL arbitration templates are pairs of + VL and weight + qos_sl2vl - SL2VL Mapping table (IBA 7.6.6) template. It is + a list of VLs corresponding to SLs 0-15 (Note + that VL15 used here means drop this SL) + +Typical default values (hard-coded in OpenSM initialization) are: + + qos_max_vls 15 + qos_high_limit 0 + qos_vlarb_low 0:0,1:4,2:4,3:4,4:4,5:4,6:4,7:4,8:4,9:4,10:4,11:4,12:4,13:4,14:4 + qos_vlarb_high 0:4,1:0,2:0,3:0,4:0,5:0,6:0,7:0,8:0,9:0,10:0,11:0,12:0,13:0,14:0 + qos_sl2vl 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,7 + +The syntax is compatible with rest of OpenSM configuration options and +values may be stored in OpenSM config file (cached options file). + +In addition to the above, we may define separate QoS configuration +parameters sets for various target types. As targets, we currently support +CAs, routers, switch external ports, and switch's enhanced port 0. The +names of such specialized parameters are prefixed by "qos__" +string. Here is a full list of the currently supported sets: + + qos_ca_ - QoS configuration parameters set for CAs. + qos_rtr_ - parameters set for routers. + qos_sw0_ - parameters set for switches' port 0. + qos_swe_ - parameters set for switches' external ports. + +Examples: + qos_sw0_max_vls=2 + qos_ca_sl2vl=0,1,2,3,5,5,5,12,12,0, + qos_swe_high_limit=0 + +.SH PREFIX ROUTES +.PP +Prefix routes control how the SA responds to path record queries for +off-subnet DGIDs. By default, the SA fails such queries. +Note that IBA does not specify how the SA should obtain off-subnet path +record information. +The prefix routes configuration is meant as a stop-gap until the +specification is completed. +.PP +Each line in the configuration file is a 64-bit prefix followed by a +64-bit GUID, separated by white space. +The GUID specifies the router port on the local subnet that will +handle the prefix. +Blank lines are ignored, as is anything between a \fB#\fP character +and the end of the line. +The prefix and GUID are both in hex, the leading 0x is optional. +Either, or both, can be wild-carded by specifying an +asterisk instead of an explicit prefix or GUID. +.PP +When responding to a path record query for an off-subnet DGID, +opensm searches for the first prefix match in the configuration file. +Therefore, the order of the lines in the configuration file is important: +a wild-carded prefix at the beginning of the configuration file renders +all subsequent lines useless. +If there is no match, then opensm fails the query. +It is legal to repeat prefixes in the configuration file, +opensm will return the path to the first available matching router. +A configuration file with a single line where both prefix and GUID +are wild-carded means that a path record query specifying any +off-subnet DGID should return a path to the first available router. +This configuration yields the same behavior formerly achieved by +compiling opensm with -DROUTER_EXP which has been obsoleted. + +.SH ROUTING +.PP +OpenSM now offers five routing engines: + +1. Min Hop Algorithm - based on the minimum hops to each node where the +path length is optimized. + +2. UPDN Unicast routing algorithm - also based on the minimum hops to each +node, but it is constrained to ranking rules. This algorithm should be chosen +if the subnet is not a pure Fat Tree, and deadlock may occur due to a +loop in the subnet. + +3. Fat Tree Unicast routing algorithm - this algorithm optimizes routing +for congestion-free "shift" communication pattern. +It should be chosen if a subnet is a symmetrical or almost symmetrical +fat-tree of various types, not just K-ary-N-Trees: non-constant K, not +fully staffed, any Constant Bisectional Bandwidth (CBB) ratio. +Similar to UPDN, Fat Tree routing is constrained to ranking rules. + +4. LASH unicast routing algorithm - uses Infiniband virtual layers +(SL) to provide deadlock-free shortest-path routing while also +distributing the paths between layers. LASH is an alternative +deadlock-free topology-agnostic routing algorithm to the non-minimal +UPDN algorithm avoiding the use of a potentially congested root node. + +5. DOR Unicast routing algorithm - based on the Min Hop algorithm, but +avoids port equalization except for redundant links between the same +two switches. This provides deadlock free routes for hypercubes when +the fabric is cabled as a hypercube and for meshes when cabled as a +mesh (see details below). + +OpenSM also supports a file method which +can load routes from a table. See \'Modular Routing Engine\' for more +information on this. + +The basic routing algorithm is comprised of two stages: + +1. MinHop matrix calculation + How many hops are required to get from each port to each LID ? + The algorithm to fill these tables is different if you run standard +(min hop) or Up/Down. + For standard routing, a "relaxation" algorithm is used to propagate +min hop from every destination LID through neighbor switches + For Up/Down routing, a BFS from every target is used. The BFS tracks link +direction (up or down) and avoid steps that will perform up after a down +step was used. + +2. Once MinHop matrices exist, each switch is visited and for each target LID a +decision is made as to what port should be used to get to that LID. + This step is common to standard and Up/Down routing. Each port has a +counter counting the number of target LIDs going through it. + When there are multiple alternative ports with same MinHop to a LID, +the one with less previously assigned ports is selected. + If LMC > 0, more checks are added: Within each group of LIDs assigned to +same target port, + a. use only ports which have same MinHop + b. first prefer the ones that go to different systemImageGuid (then +the previous LID of the same LMC group) + c. if none - prefer those which go through another NodeGuid + d. fall back to the number of paths method (if all go to same node). + +Effect of Topology Changes + +OpenSM will preserve existing routing in any case where there is no change in +the fabric switches unless the -r (--reassign_lids) option is specified. + +-r +.br +--reassign_lids + This option causes OpenSM to reassign LIDs to all + end nodes. Specifying -r on a running subnet + may disrupt subnet traffic. + Without -r, OpenSM attempts to preserve existing + LID assignments resolving multiple use of same LID. + +If a link is added or removed, OpenSM does not recalculate +the routes that do not have to change. A route has to change +if the port is no longer UP or no longer the MinHop. When routing changes +are performed, the same algorithm for balancing the routes is invoked. + +In the case of using the file based routing, any topology changes are +currently ignored The 'file' routing engine just loads the LFTs from the file +specified, with no reaction to real topology. Obviously, this will not be able +to recheck LIDs (by GUID) for disconnected nodes, and LFTs for non-existent +switches will be skipped. Multicast is not affected by 'file' routing engine +(this uses min hop tables). + + +Min Hop Algorithm + +The Min Hop algorithm is invoked by default if no routing algorithm is +specified. It can also be invoked by specifying '-R minhop'. + +The Min Hop algorithm is divided into two stages: computation of +min-hop tables on every switch and LFT output port assignment. Link +subscription is also equalized with the ability to override based on +port GUID. The latter is supplied by: + +-i +.br +-ignore-guids + This option provides the means to define a set of ports + (by guid) that will be ignored by the link load + equalization algorithm. Note that only endports (CA, + switch port 0, and router ports) and not switch external + ports are supported. + +LMC awareness routes based on (remote) system or switch basis. + + +Purpose of UPDN Algorithm + +The UPDN algorithm is designed to prevent deadlocks from occurring in loops +of the subnet. A loop-deadlock is a situation in which it is no longer +possible to send data between any two hosts connected through the loop. As +such, the UPDN routing algorithm should be used if the subnet is not a pure +Fat Tree, and one of its loops may experience a deadlock (due, for example, +to high pressure). + +The UPDN algorithm is based on the following main stages: + +1. Auto-detect root nodes - based on the CA hop length from any switch in +the subnet, a statistical histogram is built for each switch (hop num vs +number of occurrences). If the histogram reflects a specific column (higher +than others) for a certain node, then it is marked as a root node. Since +the algorithm is statistical, it may not find any root nodes. The list of +the root nodes found by this auto-detect stage is used by the ranking +process stage. + + Note 1: The user can override the node list manually. + Note 2: If this stage cannot find any root nodes, and the user did + not specify a guid list file, OpenSM defaults back to the + Min Hop routing algorithm. + +2. Ranking process - All root switch nodes (found in stage 1) are assigned +a rank of 0. Using the BFS algorithm, the rest of the switch nodes in the +subnet are ranked incrementally. This ranking aids in the process of enforcing +rules that ensure loop-free paths. + +3. Min Hop Table setting - after ranking is done, a BFS algorithm is run from +each (CA or switch) node in the subnet. During the BFS process, the FDB table +of each switch node traversed by BFS is updated, in reference to the starting +node, based on the ranking rules and guid values. + +At the end of the process, the updated FDB tables ensure loop-free paths +through the subnet. + +Note: Up/Down routing does not allow LID routing communication between +switches that are located inside spine "switch systems". +The reason is that there is no way to allow a LID route between them +that does not break the Up/Down rule. +One ramification of this is that you cannot run SM on switches other +than the leaf switches of the fabric. + + +UPDN Algorithm Usage + +Activation through OpenSM + +Use '-R updn' option (instead of old '-u') to activate the UPDN algorithm. +Use '-a ' for adding an UPDN guid file that contains the +root nodes for ranking. +If the `-a' option is not used, OpenSM uses its auto-detect root nodes +algorithm. + +Notes on the guid list file: + +1. A valid guid file specifies one guid in each line. Lines with an invalid +format will be discarded. +.br +2. The user should specify the root switch guids. However, it is also +possible to specify CA guids; OpenSM will use the guid of the switch (if +it exists) that connects the CA to the subnet as a root node. + + +Fat-tree Routing Algorithm + +The fat-tree algorithm optimizes routing for "shift" communication pattern. +It should be chosen if a subnet is a symmetrical or almost symmetrical +fat-tree of various types. +It supports not just K-ary-N-Trees, by handling for non-constant K, +cases where not all leafs (CAs) are present, any CBB ratio. +As in UPDN, fat-tree also prevents credit-loop-deadlocks. + +If the root guid file is not provided ('-a' or '--root_guid_file' options), +the topology has to be pure fat-tree that complies with the following rules: + - Tree rank should be between two and eight (inclusively) + - Switches of the same rank should have the same number + of UP-going port groups*, unless they are root switches, + in which case the shouldn't have UP-going ports at all. + - Switches of the same rank should have the same number + of DOWN-going port groups, unless they are leaf switches. + - Switches of the same rank should have the same number + of ports in each UP-going port group. + - Switches of the same rank should have the same number + of ports in each DOWN-going port group. + - All the CAs have to be at the same tree level (rank). + +If the root guid file is provided, the topology doesn't have to be pure +fat-tree, and it should only comply with the following rules: + - Tree rank should be between two and eight (inclusively) + - All the Compute Nodes** have to be at the same tree level (rank). + Note that non-compute node CAs are allowed here to be at different + tree ranks. + +* ports that are connected to the same remote switch are referenced as +\'port group\'. + +** list of compute nodes (CNs) can be specified by \'-u\' or \'--cn_guid_file\' +OpenSM options. + +Topologies that do not comply cause a fallback to min hop routing. +Note that this can also occur on link failures which cause the topology +to no longer be "pure" fat-tree. + +Note that although fat-tree algorithm supports trees with non-integer CBB +ratio, the routing will not be as balanced as in case of integer CBB ratio. +In addition to this, although the algorithm allows leaf switches to have any +number of CAs, the closer the tree is to be fully populated, the more +effective the "shift" communication pattern will be. +In general, even if the root list is provided, the closer the topology to a +pure and symmetrical fat-tree, the more optimal the routing will be. + +The algorithm also dumps compute node ordering file (opensm-ftree-ca-order.dump) +in the same directory where the OpenSM log resides. This ordering file provides +the CN order that may be used to create efficient communication pattern, that +will match the routing tables. + +Routing between non-CN nodes + +The use of the cn_guid_file option allows non-CN nodes to be located on different levels in the fat tree. +In such case, it is not guaranteed that the Fat Tree algorithm will route between two non-CN nodes. +To solve this problem, a list of non-CN nodes can be specified by \'-G\' or \'--io_guid_file\' option. +Theses nodes will be allowed to use switches the wrong way round a specific number of times (specified by \'-H\' or \'--max_reverse_hops\'. +With the proper max_reverse_hops and io_guid_file values, you can ensure full connectivity in the Fat Tree. + +Please note that using max_reverse_hops creates routes that use the switch in a counter-stream way. +This option should never be used to connect nodes with high bandwidth traffic between them ! It should only be used +to allow connectivity for HA purposes or similar. +Also having routes the other way around can in theory cause credit loops. + +Use these options with extreme care ! + +Activation through OpenSM + +Use '-R ftree' option to activate the fat-tree algorithm. +Use '-a ' to provide root nodes for ranking. If the `-a' option +is not used, routing algorithm will detect roots automatically. +Use '-u ' to provide the list of compute nodes. If the `-u' option +is not used, all the CAs are considered as compute nodes. + +Note: LMC > 0 is not supported by fat-tree routing. If this is +specified, the default routing algorithm is invoked instead. + + +LASH Routing Algorithm + +LASH is an acronym for LAyered SHortest Path Routing. It is a +deterministic shortest path routing algorithm that enables topology +agnostic deadlock-free routing within communication networks. + +When computing the routing function, LASH analyzes the network +topology for the shortest-path routes between all pairs of sources / +destinations and groups these paths into virtual layers in such a way +as to avoid deadlock. + +Note LASH analyzes routes and ensures deadlock freedom between switch +pairs. The link from HCA between and switch does not need virtual +layers as deadlock will not arise between switch and HCA. + +In more detail, the algorithm works as follows: + +1) LASH determines the shortest-path between all pairs of source / +destination switches. Note, LASH ensures the same SL is used for all +SRC/DST - DST/SRC pairs and there is no guarantee that the return +path for a given DST/SRC will be the reverse of the route SRC/DST. + +2) LASH then begins an SL assignment process where a route is assigned +to a layer (SL) if the addition of that route does not cause deadlock +within that layer. This is achieved by maintaining and analysing a +channel dependency graph for each layer. Once the potential addition +of a path could lead to deadlock, LASH opens a new layer and continues +the process. + +3) Once this stage has been completed, it is highly likely that the +first layers processed will contain more paths than the latter ones. +To better balance the use of layers, LASH moves paths from one layer +to another so that the number of paths in each layer averages out. + +Note, the implementation of LASH in opensm attempts to use as few layers +as possible. This number can be less than the number of actual layers +available. + +In general LASH is a very flexible algorithm. It can, for example, +reduce to Dimension Order Routing in certain topologies, it is topology +agnostic and fares well in the face of faults. + +It has been shown that for both regular and irregular topologies, LASH +outperforms Up/Down. The reason for this is that LASH distributes the +traffic more evenly through a network, avoiding the bottleneck issues +related to a root node and always routes shortest-path. + +The algorithm was developed by Simula Research Laboratory. + + +Use '-R lash -Q ' option to activate the LASH algorithm. + +Note: QoS support has to be turned on in order that SL/VL mappings are +used. + +Note: LMC > 0 is not supported by the LASH routing. If this is +specified, the default routing algorithm is invoked instead. + +For open regular cartesian meshes the DOR algorithm is the ideal +routing algorithm. For toroidal meshes on the other hand there +are routing loops that can cause deadlocks. LASH can be used to +route these cases. The performance of LASH can be improved by +preconditioning the mesh in cases where there are multiple links +connecting switches and also in cases where the switches are not +cabled consistently. An option exists for LASH to do this. To +invoke this use '-R lash -Q --do_mesh_analysis'. This will +add an additional phase that analyses the mesh to try to determine +the dimension and size of a mesh. If it determines that the mesh +looks like an open or closed cartesian mesh it reorders the ports +in dimension order before the rest of the LASH algorithm runs. + +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 /usr/local/etc/opensm/opensm.conf +default OpenSM config file. + +.TP +.B /usr/local/etc/opensm/ib-node-name-map +default node name map file. See ibnetdiscover for more information on format. + +.TP +.B /usr/local/etc/opensm/partitions.conf +default partition config file + +.TP +.B /usr/local/etc/opensm/qos-policy.conf +default QOS policy config file + +.TP +.B /usr/local/etc/opensm/prefix-routes.conf +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/branches/WOF2-3/ulp/opensm/user/man/osmtest.8 b/branches/WOF2-3/ulp/opensm/user/man/osmtest.8 new file mode 100644 index 00000000..a9d29eb8 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/man/osmtest.8 @@ -0,0 +1,191 @@ +.TH OSMTEST 8 "August 31, 2009" "OpenIB" "OpenIB Management" + +.SH NAME +osmtest \- InfiniBand subnet manager and administration (SM/SA) test program + +.SH SYNOPSIS +.B osmtest +[\-f(low) ] [\-w(ait) ] [\-d(ebug) ] +[\-m(ax_lid) ] [\-g(uid)[=]] [-p(ort)] +[\-i(nventory) ] [\-s(tress)] [\-M(ulticast_Mode)] +[\-t(imeout) ] [\-l | \-\-log_file] [\-v] [\-vf ] +[\-h(elp)] + +.SH DESCRIPTION +.PP +osmtest is a test program to validate InfiniBand subnet manager and +administration (SM/SA). + +Default is to run all flows with the exception of the QoS flow. + +osmtest provides a test suite for opensm. + +osmtest has the following capabilities and testing flows: + +It creates an inventory file of all available Nodes, Ports, and PathRecords, +including all their fields. +It verifies the existing inventory, with all the object fields, and matches it +to a pre-saved one. +A Multicast Compliancy test. +An Event Forwarding test. +A Service Record registration test. +An RMPP stress test. +A Small SA Queries stress test. + +It is recommended that after installing opensm, the user should run +"osmtest -f c" to generate the inventory file, and +immediately afterwards run "osmtest -f a" to test OpenSM. + +Another recommendation for osmtest usage is to create the inventory when the +IB fabric is stable, and occasionally +run "osmtest -v" to verify that nothing has changed. + +.SH OPTIONS + +.PP +.TP +\fB\-f\fR, \fB\-\-flow\fR +This option directs osmtest to run a specific flow: + FLOW DESCRIPTION + c = create an inventory file with all nodes, ports and paths + a = run all validation tests (expecting an input inventory) + v = only validate the given inventory file + s = run service registration, deregistration, and lease test + e = run event forwarding test + f = flood the SA with queries according to the stress mode + m = multicast flow + q = QoS info: dump VLArb and SLtoVL tables + t = run trap 64/65 flow (this flow requires running of external tool) + (default is all flows except QoS) +.TP +\fB\-w\fR, \fB\-\-wait\fR +This option specifies the wait time for trap 64/65 in seconds +It is used only when running -f t - the trap 64/65 flow +(default to 10 sec) +.TP +\fB\-d\fR, \fB\-\-debug\fR +This option specifies a debug option. +These options are not normally needed. +The number following -d selects the debug +option to enable as follows: + + OPT Description + --- ----------------- + -d0 - Ignore other SM nodes + -d1 - Force single threaded dispatching + -d2 - Force log flushing after each log message + -d3 - Disable multicast support +.TP +\fB\-m\fR, \fB\-\-max_lid\fR +This option specifies the maximal LID number to be searched +for during inventory file build (default to 100) +.TP +\fB\-g\fR, \fB\-\-guid\fR +This option specifies the local port GUID value +with which OpenSM should bind. OpenSM may be +bound to 1 port at a time. +If GUID given is 0, OpenSM displays a list +of possible port GUIDs and waits for user input. +Without -g, OpenSM trys to use the default port. +.TP +\fB\-p\fR, \fB\-\-port\fR +This option displays a menu of possible local port GUID values +with which osmtest could bind +.TP +\fB\-i\fR, \fB\-\-inventory\fR +This option specifies the name of the inventory file +Normally, osmtest expects to find an inventory file, +which osmtest uses to validate real-time information +received from the SA during testing +If -i is not specified, osmtest defaults to the file +\'osmtest.dat\' +See -c option for related information +.TP +\fB\-s\fR, \fB\-\-stress\fR +This option runs the specified stress test instead +of the normal test suite +Stress test options are as follows: + + OPT Description + --- ----------------- + -s1 - Single-MAD (RMPP) response SA queries + -s2 - Multi-MAD (RMPP) response SA queries + -s3 - Multi-MAD (RMPP) Path Record SA queries + -s4 - Single-MAD (non RMPP) get 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.rosenstock@gmail.com > +.TP +Eitan Zahavi +.RI < eitan@mellanox.co.il > diff --git a/branches/WOF2-3/ulp/opensm/user/opensm/ChangeLog b/branches/WOF2-3/ulp/opensm/user/opensm/ChangeLog new file mode 100644 index 00000000..e15071e0 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/ChangeLog @@ -0,0 +1,115 @@ +2007-07-11 Hal Rosenstock + + * configure.in: Bump to version 2.2.1 + +2007-06-20 Hal Rosenstock + + * osm_helper.c: Add 3LeafNetworks and Xsigo to osm_get_manufacturer_str + +2007-06-15 Sasha Khapyorsky + + * osm_helper.c: Fix PortInfo:CapMask printing when CapMask is 0 + +2007-06-11 Sasha Khapyorsky + + * osm_helper.c: Remove OSM_SM_SIGNAL_MASTER_OR_HIGHER_SM_DETECTED + from __osm_sm_mgr_signal_str + +2007-06-06 Sasha Khapyorsky + + * osm_helper.c: More optimally deal with manufacturer strings + +2007-06-06 Hal Rosenstock + + * osm_helper.c: Add Sun to osm_get_manufacturer_str + +2007-06-04 Hal Rosenstock + + * osm_helper.c: Add 8x to __osm_lwa_str_fixed_width + +2007-05-07 Sasha Khapyorsky + + * osm_helper.c: Remove repeated strlen() calls + +2007-04-27 Ira K. Weiny + + * osm_helper.c: In osm_dump_notice, use ib_get_producer_type_str + for printing producer type + +2007-04-26 Hal Rosenstock + + * osm_helper.c: Clarify the proper usage of + osm_get_node_type_str_fixed_width to take uint8_t rather + than uint32_t for node_type argument + +2007-04-25 Yevgeny Kliteynik + + * osm_helper.c: Fix problematic usage of sprintf() when + source and destination strings overlap. + +2007-04-24 Albert L. Chu + + * osm_helper.c: In osm_get_node_type_str_fixed_width, fix + both range limit and endian of node type check + +2007-03-29 Hal Rosenstock + + * configure.in: Bump version to 2.2.0 + +2007-03-21 Sasha Khapyorsky + + * osm_log.c: Changed to support daemon mode + +2007-03-01 Hal Rosenstock + + * configure.in: Bump version to 2.1.2 + + * osm_helper.c: Eliminate extraneous comma in __osm_disp_msg_ string + for OSM_MSG_MAD_PORT_INFO + +2007-02-26 Sasha Khapyorsky + + * osm_log.c: Minor optimization to previous change to osm_log + for also flushing on OSM_LOG_SYS + +2007-02-26 Yevgeny Kliteynik + + * osm_log.c: In osm_log, flush log on OSM_LOG_SYS (as well + as OSM_LOG_ERROR) + +2007-02-20 Hal Rosenstock + + * configure.in: Bump version to 2.1.1 + + * osm_helper.c: In osm_dbg_get_capabilities_str, only display + Capability Mask if there are capabilities present + +2007-01-22 Hal Rosenstock + + * osm_helper.c: Change DR path format from [%X] to %d, + +2007-01-08 Sasha Khapyorsky + + * osm_log.c: Add osm_log_reopen_file API + +2006-12-22 Hal Rosenstock + + * osm_helper.c: Add osm_dump_switch_info_record API + +2006-11-03 Sasha Khapyorsky + + * osm_log.c: Add osm_log_printf API + +2006-10-30 Sasha Khapyorsky + + * osm_helper.c: Fix seg fault with strings which + might not be null terminated + +2006-10-18 Yevgeny Kliteynik + + * osm_log.c: Windows porting changes + +2006-09-19 Yevgeny Kliteynik + + * osm_log.c: Windows porting changes + diff --git a/branches/WOF2-3/ulp/opensm/user/opensm/Makefile b/branches/WOF2-3/ulp/opensm/user/opensm/Makefile new file mode 100644 index 00000000..a0c06273 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/Makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\..\inc\openib.def diff --git a/branches/WOF2-3/ulp/opensm/user/opensm/SOURCES b/branches/WOF2-3/ulp/opensm/user/opensm/SOURCES new file mode 100644 index 00000000..32302d44 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/SOURCES @@ -0,0 +1,75 @@ + +TARGETNAME=opensm + +!if !defined(WINIBHOME) +WINIBHOME=..\..\..\.. +!endif + +LIBPATH=$(WINIBHOME)\bin\user\obj$(BUILD_ALT_DIR) + +!if defined(OSM_TARGET) +TARGETPATH=$(OSM_TARGET)\bin\user\obj$(BUILD_ALT_DIR) +!else +TARGETPATH=$(LIBPATH) +!endif + +!include ..\mad-vendor.inc + +TARGETTYPE=PROGRAM +UMTYPE=console +UMENTRY=main +USE_MSVCRT=1 + +SOURCES=\ + osm.mc \ + opensm.rc \ + osm_qos_parser_y.c \ + osm_qos_parser_l.c \ + osm_sa_mcmember_record.c \ + osm_sa_path_record.c \ + osm_files.c + +OSM_HOME=.. + +TARGETLIBS= \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ +!if $(FREEBUILD) + $(VENDOR_LIBS) \ + $(LIBPATH)\*\complib.lib \ + $(LIBPATH)\*\ibal.lib +!else + $(VENDOR_LIBSD) \ + $(LIBPATH)\*\complibd.lib \ + $(LIBPATH)\*\ibald.lib +!endif + +INCLUDES= \ + $(WINIBHOME)\inc; \ + $(WINIBHOME)\inc\user; \ + $(WINIBHOME)\inc\user\linux; \ + $(VENDOR_INC) \ + $(OSM_HOME); \ + $(OSM_HOME)\include; + +# Could be any special flag needed for this project +#USER_C_FLAGS=$(USER_C_FLAGS) /MD + +#Add preproccessor definitions +C_DEFINES=$(C_DEFINES) -D__WIN__ -DHAVE_CONFIG_H -D$(VENDOR_IF) + +C_DEFINES=$(C_DEFINES) -DWINVER=$(_NT_TARGET_VERSION) + +!if !$(FREEBUILD) +C_DEFINES=$(C_DEFINES) -D_DEBUG -DDEBUG -DDBG +# If not specified, default is no optimization: /Od /Oi per WDK docs. +!else +# If not specified, default is /Oxs, favor fast code here. +MSC_OPTIMIZATION= /Oxt +!endif + +LINKER_FLAGS= $(LINKER_FLAGS) + +MSC_WARNING_LEVEL= /W2 /wd4090 /wd4242 /wd4334 /wd4007 + + diff --git a/branches/WOF2-3/ulp/opensm/user/opensm/dlfcn.h b/branches/WOF2-3/ulp/opensm/user/opensm/dlfcn.h new file mode 100644 index 00000000..025b10fa --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/dlfcn.h @@ -0,0 +1,14 @@ + + +#define RTLD_LAZY 1 + +void *dlopen(char *lib, int flags) { return (void*)0; } + +void *dlsym(void *hdl, char *sym) +{ + return (void*)0; // always fail. +} + +char * dlerror(void) { return NULL; } + +void dlclose(void *hdl) { } diff --git a/branches/WOF2-3/ulp/opensm/user/opensm/libopensm.map b/branches/WOF2-3/ulp/opensm/user/opensm/libopensm.map new file mode 100644 index 00000000..00992558 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/libopensm.map @@ -0,0 +1,60 @@ +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; + ib_zero_gid; + 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/branches/WOF2-3/ulp/opensm/user/opensm/libopensm.ver b/branches/WOF2-3/ulp/opensm/user/opensm/libopensm.ver new file mode 100644 index 00000000..a04beb5c --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/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=4:0:0 diff --git a/branches/WOF2-3/ulp/opensm/user/opensm/main.c b/branches/WOF2-3/ulp/opensm/user/opensm/main.c new file mode 100644 index 00000000..c073cc8c --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/main.c @@ -0,0 +1,1534 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2009 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2010 Intel Corporation. All rights reserved. + * Copyright (c) 2009 HNR Consulting. All rights reserved. + * Copyright (c) 2009 System Fabric Works, 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: + * Command line interface for opensm. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +volatile unsigned int osm_exit_flag = 0; + +static volatile unsigned int osm_hup_flag = 0; +static volatile unsigned int osm_usr1_flag = 0; + +#define MAX_LOCAL_IBPORTS 64 +#define INVALID_GUID (0xFFFFFFFFFFFFFFFFULL) + +#ifndef __WIN__ + +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); +} + +#else /* __WIN__ */ + +#ifdef complib_exit +#undef complib_exit +#endif +#define complib_exit() g_service_state = SERVICE_STATE_START_FAILED + +#define block_signals() +#define setup_signals() +#define cl_is_debug osm_is_debug + +HANDLE osm_exit_event = NULL; + +typedef struct _osm_main_args_t +{ + int argc; + char** argv; + boolean_t is_service; +} osm_main_args_t; + +static osm_main_args_t osm_main_args; + +enum service_state { + SERVICE_STATE_STARTING, + SERVICE_STATE_STARTED_OK, + SERVICE_STATE_START_FAILED +}; + +enum service_state g_service_state = SERVICE_STATE_STARTING; + +SERVICE_STATUS OsmServiceStatus; +SERVICE_STATUS_HANDLE OsmServiceStatusHandle; + +void SvcDebugOut(LPSTR String, ... ); +static char *WinErrorStr(DWORD err); +void WINAPI OsmServiceCtrlHandler (DWORD opcode); + +BOOL WINAPI OsmServiceStart (DWORD argc, LPTSTR *argv); + +DWORD OsmServiceInitialization (DWORD argc, LPTSTR *argv, DWORD *specificError); +#endif /* __WIN__ */ + + +/********************************************************************** + **********************************************************************/ + +static void show_usage(void) +{ + printf("\n------- OpenSM - Usage and options ----------------------\n"); + printf("Usage: opensm [options]\n"); + printf("Options:\n"); + printf("--version\n Prints OpenSM version and exits.\n\n"); + printf("--config, -F \n" + " The name of the OpenSM config file. When not specified\n" + " " OSM_DEFAULT_CONFIG_FILE + " will be used (if exists).\n\n"); + printf("--create-config, -c \n" + " OpenSM will dump its configuration to the specified file and exit.\n" + " This is a way to generate OpenSM configuration file template.\n\n"); + printf("--guid, -g \n" + " This option specifies the local port GUID value\n" + " with which OpenSM should bind. OpenSM may be\n" + " bound to 1 port at a time.\n" + " If GUID given is 0, OpenSM displays a list\n" + " of possible port GUIDs and waits for user input.\n" + " Without -g, OpenSM tries to use the default port.\n\n"); + printf("--lmc, -l \n" + " This option specifies the subnet's LMC value.\n" + " The number of LIDs assigned to each port is 2^LMC.\n" + " The LMC value must be in the range 0-7.\n" + " LMC values > 0 allow multiple paths between ports.\n" + " LMC values > 0 should only be used if the subnet\n" + " topology actually provides multiple paths between\n" + " ports, i.e. multiple interconnects between switches.\n" + " Without -l, OpenSM defaults to LMC = 0, which allows\n" + " one path between any two ports.\n\n"); + printf("--priority, -p \n" + " This option specifies the SM's PRIORITY.\n" + " This will effect the handover cases, where master\n" + " is chosen by priority and GUID. Range goes\n" + " from 0 (lowest priority) to 15 (highest).\n\n"); + printf("--smkey, -k \n" + " This option specifies the SM's SM_Key (64 bits).\n" + " This will effect SM authentication.\n" + " Note that OpenSM version 3.2.1 and below used the\n" + " default value '1' in a host byte order, it is fixed\n" + " now but you may need this option to interoperate\n" + " with old OpenSM running on a little endian machine.\n\n"); + printf("--reassign_lids, -r\n" + " This option causes OpenSM to reassign LIDs to all\n" + " end nodes. Specifying -r on a running subnet\n" + " may disrupt subnet traffic.\n" + " Without -r, OpenSM attempts to preserve existing\n" + " LID assignments resolving multiple use of same LID.\n\n"); + printf("--routing_engine, -R \n" + " This option chooses routing engine(s) to use instead of default\n" + " Min Hop algorithm. Multiple routing engines can be specified\n" + " separated by commas so that specific ordering of routing\n" + " algorithms will be tried if earlier routing engines fail.\n" + " Supported engines: updn, file, ftree, lash, dor\n\n"); + printf("--do_mesh_analysis\n" + " This option enables additional analysis for the lash\n" + " routing engine to precondition switch port assignments\n" + " in regular cartesian meshes which may reduce the number\n" + " of SLs required to give a deadlock free routing\n\n"); + printf("--lash_start_vl \n" + " Sets the starting VL to use for the lash routing algorithm.\n" + " Defaults to 0.\n"); + printf("--sm_sl \n" + " Sets the SL to use to communicate with the SM/SA. Defaults to 0.\n\n"); + printf("--connect_roots, -z\n" + " This option enforces routing engines (up/down and \n" + " fat-tree) to make connectivity between root switches\n" + " and in this way be IBA compliant. In many cases,\n" + " this can violate \"pure\" deadlock free algorithm, so\n" + " use it carefully.\n\n"); + printf("--ucast_cache, -A\n" + " This option enables unicast routing cache to prevent\n" + " routing recalculation (which is a heavy task in a\n" + " large cluster) when there was no topology change\n" + " detected during the heavy sweep, or when the topology\n" + " change does not require new routing calculation,\n" + " e.g. in case of host reboot.\n" + " This option becomes very handy when the cluster size\n" + " is thousands of nodes.\n\n"); + printf("--lid_matrix_file, -M \n" + " This option specifies the name of the lid matrix dump file\n" + " from where switch lid matrices (min hops tables will be\n" + " loaded.\n\n"); + printf("--lfts_file, -U \n" + " This option specifies the name of the LFTs file\n" + " from where switch forwarding tables will be loaded.\n\n"); + printf("--sadb_file, -S \n" + " This option specifies the name of the SA DB dump file\n" + " from where SA database will be loaded.\n\n"); + printf("--root_guid_file, -a \n" + " Set the root nodes for the Up/Down or Fat-Tree routing\n" + " algorithm to the guids provided in the given file (one\n" + " to a line)\n" "\n"); + printf("--cn_guid_file, -u \n" + " Set the compute nodes for the Fat-Tree routing algorithm\n" + " to the guids provided in the given file (one to a line)\n\n"); + printf("--io_guid_file, -G \n" + " Set the I/O nodes for the Fat-Tree routing algorithm\n" + " to the guids provided in the given file (one to a line)\n\n"); + printf("--max_reverse_hops, -H \n" + " Set the max number of hops the wrong way around\n" + " an I/O node is allowed to do (connectivity for I/O nodes on top swithces)\n\n"); + printf("--ids_guid_file, -m \n" + " Name of the map file with set of the IDs which will be used\n" + " by Up/Down routing algorithm instead of node GUIDs\n" + " (format: per line)\n\n"); + printf("--guid_routing_order_file, -X \n" + " Set the order port guids will be routed for the MinHop\n" + " and Up/Down routing algorithms to the guids provided in the\n" + " given file (one to a line)\n\n"); + printf("--once, -o\n" + " This option causes OpenSM to configure the subnet\n" + " once, then exit. Ports remain in the ACTIVE state.\n\n"); + printf("--sweep, -s \n" + " This option specifies the number of seconds between\n" + " subnet sweeps. Specifying -s 0 disables sweeping.\n" + " Without -s, OpenSM defaults to a sweep interval of\n" + " 10 seconds.\n\n"); + printf("--timeout, -t \n" + " This option specifies the time in milliseconds\n" + " used for transaction timeouts.\n" + " Specifying -t 0 disables timeouts.\n" + " Without -t, OpenSM defaults to a timeout value of\n" + " 200 milliseconds.\n\n"); + printf("--retries \n" + " This option specifies the number of retries used\n" + " for transactions.\n" + " Without --retries, OpenSM defaults to %u retries\n" + " for transactions.\n\n", OSM_DEFAULT_RETRY_COUNT); + printf("--maxsmps, -n \n" + " This option specifies the number of VL15 SMP MADs\n" + " allowed on the wire at any one time.\n" + " Specifying --maxsmps 0 allows unlimited outstanding\n" + " SMPs.\n" + " Without --maxsmps, OpenSM defaults to a maximum of\n" + " 4 outstanding SMPs.\n\n"); + printf("--console, -q [off|local" +#ifdef ENABLE_OSM_CONSOLE_SOCKET + "|socket|loopback" +#endif + "]\n This option activates the OpenSM console (default off).\n\n"); +#ifdef ENABLE_OSM_CONSOLE_SOCKET + printf("--console-port, -C \n" + " Specify an alternate telnet port for the console (default %d).\n\n", + OSM_DEFAULT_CONSOLE_PORT); +#endif + printf("--ignore-guids, -i \n" + " This option provides the means to define a set of ports\n" + " (by guid) that will be ignored by the link load\n" + " equalization algorithm.\n\n"); + printf("--hop_weights_file, -w \n" + " This option provides the means to define a weighting\n" + " factor per port for customizing the least weight\n" + " hops for the routing.\n\n"); + printf("--dimn_ports_file, -O \n" + " This option provides the means to define a mapping\n" + " between ports and dimension (Order) for controlling\n" + " Dimension Order Routing (DOR).\n\n"); + printf("--honor_guid2lid, -x\n" + " This option forces OpenSM to honor the guid2lid file,\n" + " when it comes out of Standby state, if such file exists\n" + " under OSM_CACHE_DIR, and is valid. By default, this is FALSE.\n\n"); + printf("--log_file, -f \n" + " This option defines the log to be the given file.\n" + " By default, the log goes to /var/log/opensm.log.\n" + " For the log to go to standard output use -f stdout.\n\n"); + printf("--log_limit, -L \n" + " This option defines maximal log file size in MB. When\n" + " specified the log file will be truncated upon reaching\n" + " this limit.\n\n"); + printf("--erase_log_file, -e\n" + " This option will cause deletion of the log file\n" + " (if it previously exists). By default, the log file\n" + " is accumulative.\n\n"); + printf("--Pconfig, -P \n" + " This option defines the optional partition configuration file.\n" + " The default name is \'" + OSM_DEFAULT_PARTITION_CONFIG_FILE "\'.\n\n"); + printf("--no_part_enforce, -N\n" + " This option disables partition enforcement on switch external ports.\n\n"); + printf("--qos, -Q\n" " This option enables QoS setup.\n\n"); + printf("--qos_policy_file, -Y \n" + " This option defines the optional QoS policy file.\n" + " The default name is \'" OSM_DEFAULT_QOS_POLICY_FILE + "\'.\n\n"); + printf("--stay_on_fatal, -y\n" + " This option will cause SM not to exit on fatal initialization\n" + " issues: if SM discovers duplicated guids or 12x link with\n" + " lane reversal badly configured.\n" + " By default, the SM will exit on these errors.\n\n"); + printf("--daemon, -B\n" + " Run in daemon mode - OpenSM will run in the background.\n\n"); + printf("--inactive, -I\n" + " Start SM in inactive rather than normal init SM state.\n\n"); +#ifdef ENABLE_OSM_PERF_MGR + printf("--perfmgr\n" " Start with PerfMgr enabled.\n\n"); + printf("--perfmgr_sweep_time_s \n" + " PerfMgr sweep interval in seconds.\n\n"); +#endif + printf("--prefix_routes_file \n" + " This option specifies the prefix routes file.\n" + " Prefix routes control how the SA responds to path record\n" + " queries for off-subnet DGIDs. Default file is:\n" + " " OSM_DEFAULT_PREFIX_ROUTES_FILE "\n\n"); + printf("--consolidate_ipv6_snm_req\n" + " Use shared MLID for IPv6 Solicited Node Multicast groups\n" + " per MGID scope and P_Key.\n\n"); + printf("--log_prefix \n" + " Prefix to syslog messages from OpenSM.\n\n"); + printf("--verbose, -v\n" + " This option increases the log verbosity level.\n" + " The -v option may be specified multiple times\n" + " to further increase the verbosity level.\n" + " See the -D option for more information about\n" + " log verbosity.\n\n"); + printf("--V, -V\n" + " This option sets the maximum verbosity level and\n" + " forces log flushing.\n" + " The -V is equivalent to '-D 0xFF -d 2'.\n" + " See the -D option for more information about\n" + " log verbosity.\n\n"); + printf("--D, -D \n" + " This option sets the log verbosity level.\n" + " A flags field must follow the -D option.\n" + " A bit set/clear in the flags enables/disables a\n" + " specific log level as follows:\n" + " BIT LOG LEVEL ENABLED\n" + " ---- -----------------\n" + " 0x01 - ERROR (error messages)\n" + " 0x02 - INFO (basic messages, low volume)\n" + " 0x04 - VERBOSE (interesting stuff, moderate volume)\n" + " 0x08 - DEBUG (diagnostic, high volume)\n" + " 0x10 - FUNCS (function entry/exit, very high volume)\n" + " 0x20 - FRAMES (dumps all SMP and GMP frames)\n" + " 0x40 - ROUTING (dump FDB routing information)\n" + " 0x80 - currently unused.\n" + " Without -D, OpenSM defaults to ERROR + INFO (0x3).\n" + " Specifying -D 0 disables all messages.\n" + " Specifying -D 0xFF enables all messages (see -V).\n" + " High verbosity levels may require increasing\n" + " the transaction timeout with the -t option.\n\n"); + printf("--debug, -d \n" + " This option specifies a debug option.\n" + " These options are not normally needed.\n" + " The number following -d selects the debug\n" + " option to enable as follows:\n" + " OPT Description\n" + " --- -----------------\n" + " -d0 - Ignore other SM nodes\n" + " -d1 - Force single threaded dispatching\n" + " -d2 - Force log flushing after each log message\n" + " -d3 - Disable multicast support\n" + " -d10 - Put OpenSM in testability mode\n" + " Without -d, no debug options are enabled\n\n"); + printf("--help, -h, -?\n" + " Display this usage info then exit.\n\n"); +#ifdef __WIN__ + printf("\nExtended OpenSM Service Control:\n"); + printf(" 'sc control OpenSM 128' Clear OSM Log file.\n"); + printf(" 'sc control OpenSM 129' Start a Heavy Sweep.\n"); +#endif + 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[MAX_LOCAL_IBPORTS]; + uint32_t num_ports = MAX_LOCAL_IBPORTS; + uint32_t i, choice = 0; + ib_api_status_t status; + + for (i = 0; i < num_ports; i++) { + attr_array[i].num_pkeys = 0; + attr_array[i].p_pkey_table = NULL; + } + + /* 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 (1) { + 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("\n\t0: Exit\n"); + printf("\nEnter choice (0-%u): ", i); + fflush(stdout); + if (scanf("%u", &choice) <= 0) { + char junk[128]; + if (scanf("%s", junk) <= 0) + printf("\nError: Cannot scan!\n"); + } else if (choice == 0) + return 0; + else if (choice <= num_ports) + break; + printf("\nError: Lame choice! Please try again.\n"); + } + choice--; + printf("Choice guid=0x%" PRIx64 "\n", + cl_ntoh64(attr_array[choice].port_guid)); + return attr_array[choice].port_guid; +} + +#ifndef __WIN__ + +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; +} + +#else /* __WIN__ */ + +static int daemonize(osm_opensm_t * osm) +{ + return 0; +} + +#endif /* ndef __WIN__ */ + +/********************************************************************** + **********************************************************************/ +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) { + if (osm_console(p_osm)) + console_init_flag = 0; + } 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; +} + +#define SET_STR_OPT(opt, val) do { \ + opt = val ? strdup(val) : NULL ; \ +} while (0) + + +int +opensm_main(void *OsmMainArgs) +{ + int argc = ((osm_main_args_t*)OsmMainArgs)->argc; + char** argv = ((osm_main_args_t*)OsmMainArgs)->argv; + osm_opensm_t osm = {0}; + osm_subn_opt_t opt; + ib_net64_t sm_key = 0; + ib_api_status_t status; + int32_t temp; + uint32_t dbg_lvl; + boolean_t run_once_flag = FALSE; + int32_t vendor_debug = 0; + int next_option; + char *conf_template = NULL, *config_file = NULL; + uint32_t val; + const char *const short_option = +#ifdef __WIN__ + "?" +#endif + "F:c:i:w:O:f:ed:D:g:l:L:s:t:a:u:m:X:R:zM:U:S:P:Y:ANBIQvVhoryxp:n:q:k:C:G:H:"; + + /* + 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'}, + {"hop_weights_file", 1, NULL, 'w'}, + {"dimn_ports_file", 1, NULL, 'O'}, + {"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'}, + {"io_guid_file", 1, NULL, 'G'}, + {"max_reverse_hops", 1, NULL, 'H'}, + {"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 + {"service", 0, NULL, 'B'}, + {"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}, + {"do_mesh_analysis", 0, NULL, 5}, + {"lash_start_vl", 1, NULL, 6}, + {"sm_sl", 1, NULL, 7}, + {"retries", 1, NULL, 8}, + {"log_prefix", 1, NULL, 9}, + {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); + } + +#ifdef __WIN__ + if (osm_main_args.is_service) { + // incorporate Windows system event log write() + // printf("%s\n", OSM_VERSION); + } + else { + printf("-------------------------------------------------\n"); + printf("%s\n", OSM_VERSION); + } +#else + printf("-------------------------------------------------\n"); + printf("%s\n", OSM_VERSION); +#endif + + osm_subn_set_default_opt(&opt); + + if (osm_subn_parse_conf_file(OSM_DEFAULT_CONFIG_FILE, &opt) < 0) + printf("\nFail to parse config file \'%s\'\n", + OSM_DEFAULT_CONFIG_FILE); + + do { + next_option = getopt_long_only(argc, argv, short_option, + long_option, NULL); + switch (next_option) { + case 'F': + config_file = optarg; + printf("Config file is `%s`:\n", config_file); + break; + default: + break; + } + } while (next_option != -1 && next_option != '?'); + + optind = 0; /* reset command line */ + + if (config_file && osm_subn_parse_conf_file(config_file, &opt) < 0) + printf("\nFail to parse config file \'%s\'\n", config_file); + + 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': + 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. + */ + SET_STR_OPT(opt.port_prof_ignore_file, optarg); + printf(" Ignore Guids File = %s\n", + opt.port_prof_ignore_file); + break; + + case 'w': + opt.hop_weights_file = optarg; + printf(" Hop Weights File = %s\n", + opt.hop_weights_file); + break; + + case 'O': + opt.dimn_ports_file = optarg; + printf(" Dimension Ports File = %s\n", + opt.dimn_ports_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 = strtoul(optarg, NULL, 0); + printf(" Transaction timeout = %u\n", + opt.transaction_timeout); + break; + + case 'n': + opt.max_wire_smps = strtoul(optarg, NULL, 0); + if (opt.max_wire_smps == 0 || + opt.max_wire_smps > 0x7FFFFFFF) + 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 + ) + SET_STR_OPT(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': + SET_STR_OPT(opt.log_file, optarg); + break; + + case 'L': + opt.log_max_size = strtoul(optarg, NULL, 0); + printf(" Log file max size is %lu MBytes\n", + opt.log_max_size); + break; + + case 'e': + opt.accum_log_file = FALSE; + printf(" Creating new log file\n"); + break; + + case 'P': + SET_STR_OPT(opt.partition_config_file, optarg); + break; + + case 'N': + opt.no_partition_enforcement = TRUE; + break; + + case 'Q': + opt.qos = TRUE; + break; + + case 'Y': + SET_STR_OPT(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': + SET_STR_OPT(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': + SET_STR_OPT(opt.lid_matrix_dump_file, optarg); + printf(" Lid matrix dump file is \'%s\'\n", optarg); + break; + + case 'U': + SET_STR_OPT(opt.lfts_file, optarg); + printf(" LFTs file is \'%s\'\n", optarg); + break; + + case 'S': + SET_STR_OPT(opt.sa_db_file, optarg); + printf(" SA DB file is \'%s\'\n", optarg); + break; + + case 'a': + SET_STR_OPT(opt.root_guid_file, optarg); + printf(" Root Guid File: %s\n", opt.root_guid_file); + break; + + case 'u': + SET_STR_OPT(opt.cn_guid_file, optarg); + printf(" Compute Node Guid File: %s\n", + opt.cn_guid_file); + break; + + case 'G': + opt.io_guid_file = optarg; + printf(" I/O Node Guid File: %s\n", opt.io_guid_file); + break; + case 'H': + opt.max_reverse_hops = atoi(optarg); + printf(" Max Reverse Hops: %d\n", opt.max_reverse_hops); + break; + case 'm': + SET_STR_OPT(opt.ids_guid_file, optarg); + printf(" IDs Guid File: %s\n", opt.ids_guid_file); + break; + + case 'X': + SET_STR_OPT(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: + SET_STR_OPT(opt.prefix_routes_file, optarg); + break; + case 4: + opt.consolidate_ipv6_snm_req = TRUE; + break; + case 5: + opt.do_mesh_analysis = TRUE; + break; + case 6: + temp = strtol(optarg, NULL, 0); + if (temp < 0 || temp >= IB_MAX_NUM_VLS) { + fprintf(stderr, + "ERROR: starting lash vl must be between 0 and 15\n"); + return -1; + } + opt.lash_start_vl = (uint8_t) temp; + printf(" LASH starting VL = %d\n", opt.lash_start_vl); + break; + case 7: + temp = strtol(optarg, NULL, 0); + if (temp < 0 || temp > 15) { + fprintf(stderr, + "ERROR: SM's SL must be between 0 and 15\n"); + return -1; + } + opt.sm_sl = (uint8_t) temp; + printf(" SMSL = %d\n", opt.sm_sl); + break; + case 8: + opt.transaction_retries = strtoul(optarg, NULL, 0); + printf(" Transaction retries = %u\n", + opt.transaction_retries); + break; + case 9: + SET_STR_OPT(opt.log_prefix, optarg); + printf("Log prefix = %s\n", opt.log_prefix); + break; + case 'h': + case '?': + case ':': + show_usage(); + break; + + case -1: + break; /* done with option */ + default: /* something wrong */ + show_usage(); + exit(1); + } + } while (next_option != -1); + +#ifdef __WIN__ + if (osm_main_args.is_service) { + if (is_console_enabled(&opt)) { + free(opt.console); + opt.console = strdup(OSM_DISABLE_CONSOLE); + } + } +#endif + 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); + + if (opt.guid == 0) + goto Exit; + + 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, "Still outstanding MADs (mad_pool %u) QP0(%u), " + "Forcing OpenSM exit...\n", + osm_exit_flag, osm.mad_pool.mads_out, + osm.stats.qp0_mads_outstanding); +#ifdef HAVE_LIBPTHREAD + pthread_cond_signal(&osm.stats.cond); +#else + cl_event_signal(&osm.stats.event); +#endif + } + +Exit: + osm_opensm_destroy(&osm); + complib_exit(); + + return 0; +} + +#ifdef __WIN__ + +int +main(int argc, char **argv) +{ + int i; + boolean_t run_as_service = FALSE; + SERVICE_TABLE_ENTRY DispatchTable[] = + { + { "OpenSM", (LPSERVICE_MAIN_FUNCTION) OsmServiceStart }, + { NULL, NULL } + }; + + osm_main_args.argc = argc; + osm_main_args.argv = argv; + + /* Is OpenSM being run as a Windows service or from a cmd line? */ + for (i = 0 ; i< argc ; i++) { + if (!strcmp(argv[i], "--service")) { + run_as_service = TRUE; + osm_main_args.is_service = TRUE; + break; + } + if (!strcmp(argv[i], "/?")) + show_usage(); + } + + osm_exit_event = CreateEvent(NULL, FALSE, FALSE, NULL); + if(osm_exit_event == NULL) { + printf( "\nCreateEvent failed err %d\n", GetLastError()); + return( 1 ); + } + + if (!run_as_service) { + /* Running as console executable */ + osm_main_args.is_service = FALSE; + return opensm_main( (void*)&osm_main_args ); + } + + /* Running as a Windows service */ + + i = 0; + if (!StartServiceCtrlDispatcher( DispatchTable )) { + i = GetLastError(); + SvcDebugOut(" [OSM_SERVICE] StartServiceCtrlDispatcher (%s)\n", + WinErrorStr(i)); + } + return i; +} + +/* + * Carried over from previous 3.0.0 openSM port. + * Problem is that Windows service startup needs feedback as to whether openSM + * actually started up successfully or not. Windows service manager calls the + * OsmServiceStart routine which spawns a thread to run opensm. The OpenSM + * thread communicates with the OsmServiceStart thread via g_service_state. + * Once the OpenSM thread resets g_service_state from SERVICE_STATE_STARTING, + * the OsmServiceStart() will return to the Windows service manager. + * The coding problem is how to catch 'all' Error & Success startup conditions + * and reset g_service_state without hacking the entire body of OFED OpenSM + * code (Linux folks are touchy about Windows code in shared code). + * Somebody once decided that scanning osm_log (aka syslog()) message strings + * seemed was the way to solve this this problem. + * For each call to osm_log() with verbosity OSM_LOG_SYS (aka syslog() called) + * OsmReportState() is called; [see osm_log.c]. + */ + +void OsmReportState(IN const char *p_str) +{ + if ( !strcmp(p_str, "SUBNET UP\n") + || !strcmp(p_str, "SM port is down\n") + || !strcmp(p_str, "Errors during initialization\n") + || !strcmp(p_str, "Entering STANDBY state\n") ) + { + /* change Service startup state to OK */ + InterlockedCompareExchange( (LONG *)&g_service_state , + SERVICE_STATE_STARTED_OK, + SERVICE_STATE_STARTING ); + if (osm_main_args.is_service) + SvcDebugOut(" [OSM_SERVICE] %s", p_str); + + // consider Windows system event log write() + return; + } + + /* Check opt.exit_on_fatal messages */ + if ( !strcmp(p_str, "Found remote SM with non-matching sm_key. Exiting\n") + || !strncmp(p_str, "Errors on subnet. Duplicate GUID found ",39) + || !strcmp(p_str, "Found remote SM with non-matching sm_key. Exiting\n") + || !strcmp(p_str, "FATAL: duplicated guids or 12x lane reversal\n") ) + { + /* change Service startup state to Failed */ + InterlockedCompareExchange( (LONG *)&g_service_state, + SERVICE_STATE_START_FAILED, + SERVICE_STATE_STARTING ); + if (osm_main_args.is_service) + SvcDebugOut(" [OSM_SERVICE] %s", p_str); + + // consider Windows system event log write() here. + return; + } + + if ( !strcmp(p_str, OSM_VERSION"\n") || + !strcmp(p_str, "Entering MASTER state\n") || + !strcmp(p_str, "Entering DISCOVERING state\n") ) + { + // consider Windows system event log write() here. + if (osm_main_args.is_service) + SvcDebugOut(" [OSM_SERVICE] %s", p_str); + } +} + + +static char *WinErrorStr(DWORD err) +{ + char *s; + + if (err == NO_ERROR) + return "Success"; + + if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + err, + 0, + (LPTSTR)&s, + 0, + NULL) == 0) + { /* failed */ + // Unknown error code %08x (%d) + s = "WinErrorStr: FormatMessage() error?"; + } + else + { /* success */ + char * p = strchr(s, '\r'); + if(p != NULL) /* lose CRLF */ + *p = '\0'; + } + return s; +} + + +void SvcDebugOut(LPSTR fmt, ... ) +{ + CHAR Buffer[1024]; + va_list args; + + va_start(args,fmt); + _vsnprintf(Buffer, 1024, fmt, args); + va_end(args); + OutputDebugStringA(Buffer); +} + +/* Local OpenSM service control codes: 128 - 255. + * + * invoke with 'sc control OpenSM local-control-code' + * 'sc control OpenSM 128' clear & reopen %windir%\temp\osm.log + */ +#define SERVICE_CONTROL_OSM_REOPEN_LOG_FILE 128 +#define SERVICE_CONTROL_OSM_START_HEAVY_SWEEP 129 + +void WINAPI OsmServiceCtrlHandler( IN DWORD Opcode ) +{ + DWORD status=0; + char *ctl; + + switch(Opcode) + { + case SERVICE_CONTROL_SHUTDOWN: + case SERVICE_CONTROL_STOP: + if (Opcode == SERVICE_CONTROL_STOP) + ctl = "STOP"; + else + ctl = "SHUTDOWN"; + syslog(LOG_INFO,"[OSM_SERVICE] SERVICE_CONTROL_%s\n",ctl); + + // Do whatever it takes to stop here. + osm_exit_flag = TRUE; + SetEvent(osm_exit_event); + + OsmServiceStatus.dwWin32ExitCode = 0; + OsmServiceStatus.dwCurrentState = SERVICE_STOPPED; + OsmServiceStatus.dwCheckPoint = 0; + OsmServiceStatus.dwWaitHint = 0; + + if (!SetServiceStatus (OsmServiceStatusHandle, &OsmServiceStatus)) + { + status = GetLastError(); + } + SvcDebugOut(" [OSM_SERVICE] Exit SERVICE_CONTROL_%s (%ld) '%s'\n", + ctl, status, WinErrorStr(status)); + return; + + case SERVICE_CONTROL_INTERROGATE: + SvcDebugOut(" [OSM_SERVICE] SERVICE_CONTROL_INTERROGATE\n"); + break; // bail out to send current status. + + case SERVICE_CONTROL_PAUSE: + SvcDebugOut(" [OSM_SERVICE] SERVICE_CONTROL_PAUSE\n"); + break; + + case SERVICE_CONTROL_CONTINUE: + SvcDebugOut(" [OSM_SERVICE] SERVICE_CONTROL_CONTINUE\n"); + break; + + case SERVICE_CONTROL_OSM_REOPEN_LOG_FILE: + osm_usr1_flag = 1; + SvcDebugOut(" [OSM_SERVICE] SERVICE_CONTROL_OSM_REOPEN_LOG_FILE\n"); + syslog(LOG_INFO,"[SERVICE_CONTROL] REOPEN_LOG_FILE\n"); + break; + + case SERVICE_CONTROL_OSM_START_HEAVY_SWEEP: + osm_hup_flag = 1; + SvcDebugOut("[OSM_SERVICE] SERVICE_CONTROL_OSM_START_HEAVY_SWEEP\n"); + syslog(LOG_INFO,"[SERVICE_CONTROL] START_HEAVY_SWEEP\n"); + break; + + default: + SvcDebugOut(" [OSM_SERVICE] Unrecognized opcode %ld\n", Opcode); + } + + // Send current status. + if (!SetServiceStatus (OsmServiceStatusHandle, &OsmServiceStatus)) + { + status = GetLastError(); + SvcDebugOut(" [OSM_SERVICE] SetServiceStatus error(%ld) %s\n", + status,WinErrorStr(status)); + } + else + SvcDebugOut(" [OSM_SERVICE] %s() Exit status %ld\n",__func__, status); +} + + +BOOL WINAPI OsmServiceStart (DWORD argc, LPTSTR *argv) +{ + DWORD status; + DWORD specificError; + + OsmServiceStatus.dwServiceType = SERVICE_WIN32; + OsmServiceStatus.dwCurrentState = SERVICE_START_PENDING; + OsmServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | + SERVICE_ACCEPT_SHUTDOWN; + /* Add when Pause/Standby supported SERVICE_ACCEPT_PAUSE_CONTINUE */ + OsmServiceStatus.dwWin32ExitCode = 0; + OsmServiceStatus.dwServiceSpecificExitCode = 0; + OsmServiceStatus.dwCheckPoint = 0; + OsmServiceStatus.dwWaitHint = 2000; + + OsmServiceStatusHandle = RegisterServiceCtrlHandler( "OpenSM", + OsmServiceCtrlHandler); + + if (OsmServiceStatusHandle == (SERVICE_STATUS_HANDLE)0) + { + status = GetLastError(); + SvcDebugOut(" [OSM_SERVICE] RegisterServiceCtrlHandler failed(%d) %s\n", + status,WinErrorStr(status)); + return 0; + } + + // Initialization code goes here. + status = OsmServiceInitialization(argc, argv, &specificError); + + while (status == NO_ERROR && g_service_state == SERVICE_STATE_STARTING) + { + Sleep(1000); + OsmServiceStatus.dwCheckPoint++; + if (!SetServiceStatus (OsmServiceStatusHandle, &OsmServiceStatus)) + { + status = GetLastError(); + SvcDebugOut(" [OSM_SERVICE] SetServiceStatus error(%ld) %s\n", + status,WinErrorStr(status)); + } + + } + CL_ASSERT(g_service_state == SERVICE_STATE_STARTED_OK || + g_service_state == SERVICE_STATE_START_FAILED || + status != NO_ERROR); + + // Handle error condition + if (status != NO_ERROR || g_service_state == SERVICE_STATE_START_FAILED) + { + OsmServiceStatus.dwCurrentState = SERVICE_STOPPED; + OsmServiceStatus.dwCheckPoint = 0; + OsmServiceStatus.dwWaitHint = 0; + OsmServiceStatus.dwWin32ExitCode = status; + OsmServiceStatus.dwServiceSpecificExitCode = specificError; + + SetServiceStatus (OsmServiceStatusHandle, &OsmServiceStatus); + SvcDebugOut(" [OSM_SERVICE] Service Startup error reported; exit\n"); + return 0; + } + + // Initialization complete - report running status. + OsmServiceStatus.dwCurrentState = SERVICE_RUNNING; + OsmServiceStatus.dwCheckPoint = 0; + OsmServiceStatus.dwWaitHint = 0; + + if (!SetServiceStatus (OsmServiceStatusHandle, &OsmServiceStatus)) + { + status = GetLastError(); + SvcDebugOut(" [OSM_SERVICE] SetServiceStatus error %ld\n",status); + } + + SvcDebugOut(" [OSM_SERVICE] StartUP SUCCESS\n"); + + return 1; // SUCCESS +} + + +// Stub initialization function. +DWORD OsmServiceInitialization( DWORD argc, + LPTSTR *argv, + DWORD *specificError ) +{ + DWORD rc = 0; + + if (CreateThread(NULL, 0, opensm_main, &osm_main_args, 0, NULL) == NULL) + { + SvcDebugOut(" [OSM_SERVICE] failed to create thread (%d)\n", + GetLastError()); + rc = 1; + } + return rc; +} + +#endif /* __WIN__ */ + diff --git a/branches/WOF2-3/ulp/opensm/user/opensm/opensm.rc b/branches/WOF2-3/ulp/opensm/user/opensm/opensm.rc new file mode 100644 index 00000000..ad2684e7 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/opensm.rc @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN +#ifdef _DEBUG_ +#define VER_FILEDESCRIPTION_STR "OpenSM InfiniBand Subnet Manager 3.3.6 (Debug)" +#define VER_INTERNALNAME_STR "opensm.exe" +#define VER_ORIGINALFILENAME_STR "opensm.exe" +#else +#define VER_FILEDESCRIPTION_STR "OpenSM InfiniBand Subnet Manager 3.3.6" +#define VER_INTERNALNAME_STR "opensm.exe" +#define VER_ORIGINALFILENAME_STR "opensm.exe" +#endif +#include diff --git a/branches/WOF2-3/ulp/opensm/user/opensm/osm.mc b/branches/WOF2-3/ulp/opensm/user/opensm/osm.mc new file mode 100644 index 00000000..3030f718 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm.mc @@ -0,0 +1,29 @@ +;/*++ +;============================================================================= +;Copyright (c) 2005 Mellanox Technologies +; +;Module Name: +; +; osm.mc +; +;Abstract: +; +; OpenSM event log messages +; +;Authors: +; +; Leonid Keller +; +;Environment: +; +; Kernel Mode . +; +;============================================================================= +;--*/ +; + +MessageId=0x0000 SymbolicName=EVENT_OSM_ANY_INFO +Language=English +%1 +. + diff --git a/branches/WOF2-3/ulp/opensm/user/opensm/osm_console.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_console.c new file mode 100644 index 00000000..a60cb335 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_console.c @@ -0,0 +1,1607 @@ +/* + * Copyright (c) 2005-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2009 HNR Consulting. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#define _GNU_SOURCE /* for getline */ +#include +#include +#ifndef __WIN__ +#include +#include +#include +#include +#include +#ifdef ENABLE_OSM_CONSOLE_SOCKET +#include +#endif +#endif /* ndef __WIN__ */ +#include +#include +#include +#include +#include +#include +#include +#include + +extern void osm_update_node_desc(IN osm_opensm_t *osm); + +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 = { +#ifdef __WIN__ + 0,2,0,NULL +#else +on: 0, delay_s: 2, loop_function:NULL +#endif +}; + +#ifdef __WIN__ +extern const struct command console_cmds[]; +#else +static const struct command console_cmds[]; +#endif + +static char *next_token(char **p_last) +{ + return strtok_r(NULL, " \t\n\r", p_last); +} + +#ifdef ENABLE_OSM_PERF_MGR +static char *name_token(char **p_last) +{ + return strtok_r(NULL, "\t\n\r", p_last); +} +#endif + +static void help_command(FILE * out, int detail) +{ + int i; + + fprintf(out, "Supported commands and syntax:\n"); + fprintf(out, "help []\n"); + /* skip help command */ + for (i = 1; console_cmds[i].name; i++) + console_cmds[i].help_function(out, 0); +} + +#ifndef __WIN__ +static void help_quit(FILE * out, int detail) +{ + fprintf(out, "quit (not valid in local mode; use ctl-c)\n"); +} +#endif + +static void help_loglevel(FILE * out, int detail) +{ + fprintf(out, "loglevel []\n"); + if (detail) { + fprintf(out, " log-level is OR'ed from the following\n"); + fprintf(out, " OSM_LOG_NONE 0x%02X\n", + OSM_LOG_NONE); + fprintf(out, " OSM_LOG_ERROR 0x%02X\n", + OSM_LOG_ERROR); + fprintf(out, " OSM_LOG_INFO 0x%02X\n", + OSM_LOG_INFO); + fprintf(out, " OSM_LOG_VERBOSE 0x%02X\n", + OSM_LOG_VERBOSE); + fprintf(out, " OSM_LOG_DEBUG 0x%02X\n", + OSM_LOG_DEBUG); + fprintf(out, " OSM_LOG_FUNCS 0x%02X\n", + OSM_LOG_FUNCS); + fprintf(out, " OSM_LOG_FRAMES 0x%02X\n", + OSM_LOG_FRAMES); + fprintf(out, " OSM_LOG_ROUTING 0x%02X\n", + OSM_LOG_ROUTING); + fprintf(out, " OSM_LOG_SYS 0x%02X\n", + OSM_LOG_SYS); + fprintf(out, "\n"); + fprintf(out, " OSM_LOG_DEFAULT_LEVEL 0x%02X\n", + OSM_LOG_DEFAULT_LEVEL); + } +} + +static void help_priority(FILE * out, int detail) +{ + fprintf(out, "priority []\n"); +} + +static void help_resweep(FILE * out, int detail) +{ + fprintf(out, "resweep [heavy|light]\n"); +} + +static void help_reroute(FILE * out, int detail) +{ + fprintf(out, "reroute\n"); + if (detail) { + fprintf(out, "reroute the fabric\n"); + } +} + +static void help_status(FILE * out, int detail) +{ + fprintf(out, "status [loop]\n"); + if (detail) { + fprintf(out, " loop -- type \"q\" to quit\n"); + } +} + +static void help_logflush(FILE * out, int detail) +{ + fprintf(out, "logflush -- flush the opensm.log file\n"); +} + +static void help_querylid(FILE * out, int detail) +{ + fprintf(out, + "querylid lid -- print internal information about the lid specified\n"); +} + +static void help_portstatus(FILE * out, int detail) +{ + fprintf(out, "portstatus [ca|switch|router]\n"); + if (detail) { + fprintf(out, "summarize port status\n"); + fprintf(out, + " [ca|switch|router] -- limit the results to the node type specified\n"); + } + +} + +static void help_switchbalance(FILE * out, int detail) +{ + fprintf(out, "switchbalance [verbose] [guid]\n"); + if (detail) { + fprintf(out, "output switch balancing information\n"); + fprintf(out, + " [verbose] -- verbose output\n" + " [guid] -- limit results to specified guid\n"); + } +} + +static void help_lidbalance(FILE * out, int detail) +{ + fprintf(out, "lidbalance [switchguid]\n"); + if (detail) { + fprintf(out, "output lid balanced forwarding information\n"); + fprintf(out, + " [switchguid] -- limit results to specified switch guid\n"); + } +} + +static void help_dump_conf(FILE *out, int detail) +{ + fprintf(out, "dump_conf\n"); + if (detail) { + fprintf(out, "dump current opensm configuration\n"); + } +} + +static void help_update_desc(FILE *out, int detail) +{ + fprintf(out, "update_desc\n"); + if (detail) { + fprintf(out, "update node description for all nodes\n"); + } +} + +#ifdef ENABLE_OSM_PERF_MGR +static void help_perfmgr(FILE * out, int detail) +{ + fprintf(out, + "perfmgr [enable|disable|clear_counters|dump_counters|print_counters|sweep_time[seconds]]\n"); + if (detail) { + fprintf(out, + "perfmgr -- print the performance manager state\n"); + fprintf(out, + " [enable|disable] -- change the perfmgr state\n"); + fprintf(out, + " [sweep_time] -- change the perfmgr sweep time (requires [seconds] option)\n"); + fprintf(out, + " [clear_counters] -- clear the counters stored\n"); + fprintf(out, + " [dump_counters [mach]] -- dump the counters (optionally in [mach]ine readable format)\n"); + fprintf(out, + " [print_counters ] -- print the counters for the specified node\n"); + } +} +#endif /* ENABLE_OSM_PERF_MGR */ + +/* more help routines go here */ + +static void help_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) +{ + char *p_cmd; + int i, found = 0; + + p_cmd = next_token(p_last); + if (!p_cmd) + help_command(out, 0); + else { + for (i = 1; console_cmds[i].name; i++) { + if (!strcmp(p_cmd, console_cmds[i].name)) { + found = 1; + console_cmds[i].help_function(out, 1); + break; + } + } + if (!found) { + fprintf(out, "%s : Command not found\n\n", p_cmd); + help_command(out, 0); + } + } +} + +static void loglevel_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) +{ + char *p_cmd; + int level; + + p_cmd = next_token(p_last); + if (!p_cmd) + fprintf(out, "Current log level is 0x%x\n", + osm_log_get_level(&p_osm->log)); + else { + /* Handle x, 0x, and decimal specification of log level */ + if (!strncmp(p_cmd, "x", 1)) { + p_cmd++; + level = strtoul(p_cmd, NULL, 16); + } else { + if (!strncmp(p_cmd, "0x", 2)) { + p_cmd += 2; + level = strtoul(p_cmd, NULL, 16); + } else + level = strtol(p_cmd, NULL, 10); + } + if ((level >= 0) && (level < 256)) { + fprintf(out, "Setting log level to 0x%x\n", level); + osm_log_set_level(&p_osm->log, level); + } else + fprintf(out, "Invalid log level 0x%x\n", level); + } +} + +static void priority_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) +{ + char *p_cmd; + int priority; + + p_cmd = next_token(p_last); + if (!p_cmd) + fprintf(out, "Current sm-priority is %d\n", + p_osm->subn.opt.sm_priority); + else { + priority = strtol(p_cmd, NULL, 0); + if (0 > priority || 15 < priority) + fprintf(out, + "Invalid sm-priority %d; must be between 0 and 15\n", + priority); + else { + fprintf(out, "Setting sm-priority to %d\n", priority); + osm_set_sm_priority(&p_osm->sm, (uint8_t)priority); + } + } +} + +static const 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 const 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 dump_sms(osm_opensm_t * p_osm, FILE * out) +{ + osm_subn_t *p_subn = &p_osm->subn; + osm_remote_sm_t *p_rsm; + + fprintf(out, "\n Known SMs\n" + " ---------\n"); + fprintf(out, " Port GUID SM State Priority\n"); + fprintf(out, " --------- -------- --------\n"); + fprintf(out, " 0x%" PRIx64 " %s %d SELF\n", + cl_ntoh64(p_subn->sm_port_guid), + sm_state_str(p_subn->sm_state), + p_subn->opt.sm_priority); + + CL_PLOCK_ACQUIRE(p_osm->sm.p_lock); + p_rsm = (osm_remote_sm_t *) cl_qmap_head(&p_subn->sm_guid_tbl); + while (p_rsm != (osm_remote_sm_t *) cl_qmap_end(&p_subn->sm_guid_tbl)) { + fprintf(out, " 0x%" PRIx64 " %s %d\n", + cl_ntoh64(p_rsm->smi.guid), + sm_state_str(ib_sminfo_get_state(&p_rsm->smi)), + ib_sminfo_get_priority(&p_rsm->smi)); + p_rsm = (osm_remote_sm_t *) cl_qmap_next(&p_rsm->map_item); + } + CL_PLOCK_RELEASE(p_osm->sm.p_lock); +} + +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, " SM Priority : %d\n", + p_osm->subn.opt.sm_priority); + fprintf(out, " SA State : %s\n", + sa_state_str(p_osm->sa.state)); + fprintf(out, " Routing Engine : %s\n", + osm_routing_engine_type_str(p_osm-> + routing_engine_used)); + + fprintf(out, " Loaded event plugins :"); + if (cl_qlist_head(&p_osm->plugin_list) == + cl_qlist_end(&p_osm->plugin_list)) { + fprintf(out, " "); + } + for (item = cl_qlist_head(&p_osm->plugin_list); + item != cl_qlist_end(&p_osm->plugin_list); + item = cl_qlist_next(item)) + fprintf(out, " %s", + ((osm_epi_plugin_t *)item)->plugin_name); + fprintf(out, "\n"); + +#ifdef ENABLE_OSM_PERF_MGR + fprintf(out, "\n PerfMgr state/sweep state : %s/%s\n", + osm_perfmgr_get_state_str(&p_osm->perfmgr), + osm_perfmgr_get_sweep_state_str(&p_osm->perfmgr)); +#endif + fprintf(out, "\n MAD stats\n" + " ---------\n" + " QP0 MADs outstanding : %d\n" + " QP0 MADs outstanding (on wire) : %d\n" + " QP0 MADs rcvd : %d\n" + " QP0 MADs sent : %d\n" + " QP0 unicasts sent : %d\n" + " QP0 unknown MADs rcvd : %d\n" + " SA MADs outstanding : %d\n" + " SA MADs rcvd : %d\n" + " SA MADs sent : %d\n" + " SA unknown MADs rcvd : %d\n" + " SA MADs ignored : %d\n" + " SA MAD pool outstanding : %d\n" + " SM MAD pool outstanding : %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, + p_osm->sa.p_mad_pool->mads_out, + p_osm->sm.p_mad_pool->mads_out +); + 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); + dump_sms(p_osm, out); + 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) +{ + unsigned 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); + p_port = osm_get_port_by_lid_ho(&p_osm->subn, 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 %u 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; + port_report_t *next; + + while (item != NULL) { + fprintf(out, " 0x%016" PRIx64 " %d (%s)\n", + item->node_guid, item->port_num, item->print_desc); + 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); +} + +static void update_desc_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) +{ + osm_update_node_desc(p_osm); +} + +#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 = name_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 or node GUID 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 */ + +#ifndef __WIN__ +static void quit_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) +{ + cio_close(&p_osm->console, &p_osm->log); +} +#endif + +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 */ +#ifdef __WIN__ + +static void exit_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) +{ + syslog(LOG_INFO, "graceful OpenSM shutdown.\n"); + osm_exit_flag = 1; +} + +static void help_exit(FILE * out, int detail) +{ + fprintf(out, "exit - graceful OpenSM shutdown.\n"); +} + +static void logit(char **p_last, osm_opensm_t * p_osm, FILE * out) +{ + OSM_LOG(&p_osm->log, OSM_LOG_ERROR, "%s",p_last[0]); + fflush(p_osm->log.out_port); +} + +static void help_logit(FILE * out, int detail) +{ + fprintf(out, "logit - write cmd-line to osm.log file.\n"); +} + +static void reset_log(char **p_last, osm_opensm_t * p_osm, FILE * out) +{ + extern void truncate_log_file(osm_log_t * p_log); + + OSM_LOG(&p_osm->log, OSM_LOG_ERROR, "LogFile Reset - last entry.\n"); + truncate_log_file(&p_osm->log); + OSM_LOG(&p_osm->log, OSM_LOG_ERROR, "LogFile Reset\n"); + fflush(p_osm->log.out_port); +} + +static void help_reset_log(FILE * out, int detail) +{ + fprintf(out, "logreset - clear the osm.log file.\n"); +} + +#else /* def __WIN__ */ + +typedef struct _regexp_list { + regex_t exp; + struct _regexp_list *next; +} regexp_list_t; + +static void dump_portguid_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) +{ + cl_qmap_t *p_port_guid_tbl; + osm_port_t *p_port, *p_next_port; + regexp_list_t *p_regexp, *p_head_regexp = NULL; + FILE *output = out; + + while (1) { + char *p_cmd = next_token(p_last); + if (!p_cmd) + break; + + if (strcmp(p_cmd, "file") == 0) { + p_cmd = next_token(p_last); + if (p_cmd) { + output = fopen(p_cmd, "w+"); + if (output == NULL) { + fprintf(out, + "Could not open file %s: %s\n", + p_cmd, strerror(errno)); + output = out; + } + } else + fprintf(out, "No file name passed\n"); + } else if (!(p_regexp = malloc(sizeof(*p_regexp)))) { + fprintf(out, "No memory\n"); + break; + } else if (regcomp(&p_regexp->exp, p_cmd, + REG_NOSUB | REG_EXTENDED) != 0) { + fprintf(out, "Cannot parse regular expression \'%s\'." + " Skipping\n", p_cmd); + free(p_regexp); + continue; + } else { + p_regexp->next = p_head_regexp; + p_head_regexp = p_regexp; + } + } + + /* Check we have at least one expression to match */ + if (p_head_regexp == NULL) { + fprintf(out, "No valid expression provided. Aborting\n"); + return; + } + + if (p_osm->sm.p_subn->need_update != 0) { + fprintf(out, "Subnet is not ready yet. Try again later\n"); + return; + } + + /* Subnet doesn't need to be updated so we can carry on */ + + CL_PLOCK_ACQUIRE(p_osm->sm.p_lock); + p_port_guid_tbl = &(p_osm->sm.p_subn->port_guid_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); + + for (p_regexp = p_head_regexp; p_regexp != NULL; + p_regexp = p_regexp->next) + if (regexec(&p_regexp->exp, p_port->p_node->print_desc, + 0, NULL, 0) == 0) { + fprintf(output, "0x%" PRIxLEAST64 "\n", + cl_ntoh64(p_port->p_physp->port_guid)); + break; + } + } + + CL_PLOCK_RELEASE(p_osm->sm.p_lock); + if (output != out) + fclose(output); + + for (; p_head_regexp; p_head_regexp = p_regexp) { + p_regexp = p_head_regexp->next; + regfree(&p_head_regexp->exp); + free(p_head_regexp); + } +} + +static void help_dump_portguid(FILE * out, int detail) +{ + fprintf(out, + "dump_portguid [file filename] regexp1 [regexp2 [regexp3 ...]] -- Dump port GUID matching a regexp \n"); + if (detail) { + fprintf(out, + "getguidgetguid -- Dump all the port GUID whom node_desc matches one of the provided regexp\n"); + fprintf(out, + " [file filename] -- Send the port GUID list to the specified file instead of regular output\n"); + } + +} +#endif /* def __WIN__ */ + +#ifndef __WIN__ +static +#endif +const struct command console_cmds[] = { + {"help", &help_command, &help_parse}, +#ifdef __WIN__ + {"exit", &help_exit, &exit_parse}, + {"logit", &help_logit, &logit}, + {"logreset", &help_reset_log, &reset_log}, +#else + {"quit", &help_quit, &quit_parse}, +#endif + {"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}, + {"update_desc", &help_update_desc, &update_desc_parse}, + {"version", &help_version, &version_parse}, +#ifdef ENABLE_OSM_PERF_MGR + {"perfmgr", &help_perfmgr, &perfmgr_parse}, +#endif /* ENABLE_OSM_PERF_MGR */ +#ifndef __WIN__ + {"dump_portguid", &help_dump_portguid, &dump_portguid_parse}, +#endif + {NULL, NULL, NULL} /* end of array */ +}; + +static void parse_cmd_line(char *line, osm_opensm_t * p_osm) +{ + char *p_cmd, *p_last; + int i, found = 0; + FILE *out = p_osm->console.out; + + while (isspace(*line)) + line++; + if (!*line) + return; + + /* find first token which is the command */ + p_cmd = strtok_r(line, " \t\n\r", &p_last); + if (p_cmd) { + for (i = 0; console_cmds[i].name; i++) { + if (loop_command.on) { + if (!strcmp(p_cmd, "q")) { + loop_command.on = 0; + } + found = 1; + break; + } + if (!strcmp(p_cmd, console_cmds[i].name)) { + found = 1; + console_cmds[i].parse_function(&p_last, p_osm, + out); + break; + } + } + if (!found) { + fprintf(out, "%s : Command not found\n\n", p_cmd); + help_command(out, 0); + } + } else { + fprintf(out, "Error parsing command line: `%s'\n", line); + } + if (loop_command.on) { + fprintf(out, "use \"q\" to quit loop\n"); + fflush(out); + } +} + +#ifdef __WIN__ + +int osm_console(osm_opensm_t * p_osm) +{ + osm_console_t *p_oct = &p_osm->console; + char p_line[120]; + char *n; + + 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; + } + } + + /* Get input line */ + n = fgets(p_line, 120, p_oct->in); + if (n != NULL) { + /* Parse and act on input */ + parse_cmd_line(p_line, p_osm); + if (!loop_command.on) { + osm_console_prompt(p_oct->out); + } + } + + return 0; +} + +#else /* !__WIN__ */ + +int 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; + + 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 0; + +#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_osm->log, OSM_LOG_ERROR, + "ERR 4B04: Failed to accept console socket: %s\n", + strerror(errno)); + p_oct->in_fd = -1; + return 0; + } + if (inet_ntop + (AF_INET, &sin.sin_addr, p_oct->client_ip, + sizeof(p_oct->client_ip)) == NULL) { + snprintf(p_oct->client_ip, sizeof(p_oct->client_ip), + "STRING_UNKNOWN"); + } + if ((hent = gethostbyaddr((const char *)&sin.sin_addr, + sizeof(struct in_addr), + AF_INET)) == NULL) { + snprintf(p_oct->client_hn, sizeof(p_oct->client_hn), + "STRING_UNKNOWN"); + } else { + snprintf(p_oct->client_hn, sizeof(p_oct->client_hn), + "%s", hent->h_name); + } + if (is_authorized(p_oct)) { + cio_open(p_oct, new_fd, &p_osm->log); + } else { + OSM_LOG(&p_osm->log, OSM_LOG_ERROR, + "ERR 4B05: Console connection denied: %s (%s)\n", + p_oct->client_hn, p_oct->client_ip); + close(new_fd); + } + return 0; + } +#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 + cio_close(p_oct, &p_osm->log); + if (p_line) + free(p_line); + return 0; + } + /* input fd is closed (hanged up) */ + if (pollfd[1].revents & POLLHUP) { +#ifdef ENABLE_OSM_CONSOLE_SOCKET + /* If we are using a socket, we close the current connection */ + if (p_oct->socket >= 0) { + cio_close(p_oct, &p_osm->log); + return 0; + } +#endif + /* If we use a local console, stdin is closed (most probable is pipe ended) + * so we close the local console */ + return -1; + } + + return 0; +} +#endif /* __WIN__ */ diff --git a/branches/WOF2-3/ulp/opensm/user/opensm/osm_console_io.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_console_io.c new file mode 100644 index 00000000..afb26363 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_console_io.c @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2005-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2008 HNR Consulting. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Provide a framework for the Console which decouples the connection + * or I/O from the functionality, or commands. + * + * Extensible - allows a variety of connection methods independent of + * the console commands. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#define _GNU_SOURCE /* for getline */ +#ifdef ENABLE_OSM_CONSOLE_SOCKET +#include +#include +#include +#include +#endif +#include +#include +#include +#include + +static int is_local(char *str) +{ + /* convenience - checks if just stdin/stdout */ + if (str) + return (strcmp(str, OSM_LOCAL_CONSOLE) == 0); + return 0; +} + +static int is_loopback(char *str) +{ + /* convenience - checks if socket based connection */ + if (str) + return (strcmp(str, OSM_LOOPBACK_CONSOLE) == 0); + return 0; +} + +static int is_remote(char *str) +{ + /* convenience - checks if socket based connection */ + if (str) + return strcmp(str, OSM_REMOTE_CONSOLE) == 0 || is_loopback(str); + return 0; +} + +int is_console_enabled(osm_subn_opt_t * p_opt) +{ + /* checks for a variety of types of consoles - default is off or 0 */ + if (p_opt) + return is_local(p_opt->console) || is_loopback(p_opt->console) + || is_remote(p_opt->console); + return 0; +} + + +#ifdef ENABLE_OSM_CONSOLE_SOCKET +int cio_close(osm_console_t * p_oct, osm_log_t * p_log) +{ + int rtnval = -1; + if (p_oct && p_oct->in_fd > 0) { + OSM_LOG(p_log, OSM_LOG_INFO, + "Console connection closed: %s (%s)\n", + p_oct->client_hn, p_oct->client_ip); + 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; +} + +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')) + cio_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; +} + +/********************************************************************** + * Do authentication & authorization check + **********************************************************************/ +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) +{ +#ifdef ENABLE_OSM_CONSOLE_SOCKET + cio_close(p_oct, p_log); + if (p_oct->socket > 0) { + OSM_LOG(p_log, OSM_LOG_INFO, "Closing console socket\n"); + close(p_oct->socket); + p_oct->socket = -1; + } +#endif +} diff --git a/branches/WOF2-3/ulp/opensm/user/opensm/osm_db_files.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_db_files.c new file mode 100644 index 00000000..5b4dedd0 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_db_files.c @@ -0,0 +1,691 @@ +/* + * Copyright (c) 2004-2009 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 the osm_db interface using simple text files + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include + +/****d* Database/OSM_DB_MAX_LINE_LEN + * NAME + * OSM_DB_MAX_LINE_LEN + * + * DESCRIPTION + * The Maximal line length allowed for the file + * + * SYNOPSIS + */ +#define OSM_DB_MAX_LINE_LEN 1024 +/**********/ + +/****d* Database/OSM_DB_MAX_GUID_LEN + * NAME + * OSM_DB_MAX_GUID_LEN + * + * DESCRIPTION + * The Maximal word length allowed for the file (guid or lid) + * + * SYNOPSIS + */ +#define OSM_DB_MAX_GUID_LEN 32 +/**********/ + +/****s* OpenSM: Database/osm_db_domain_imp + * NAME + * osm_db_domain_imp + * + * DESCRIPTION + * An implementation for domain of the database based on text files and + * hash tables. + * + * SYNOPSIS + */ +typedef struct osm_db_domain_imp { + char *file_name; + st_table *p_hash; + cl_spinlock_t lock; +} osm_db_domain_imp_t; +/* + * FIELDS + * + * SEE ALSO + * osm_db_domain_t + *********/ + +/****s* OpenSM: Database/osm_db_imp_t + * NAME + * osm_db_imp_t + * + * DESCRIPTION + * An implementation for file based database + * + * SYNOPSIS + */ +typedef struct osm_db_imp { + char *db_dir_name; +} osm_db_imp_t; +/* + * FIELDS + * + * db_dir_name + * The directory holding the database + * + * SEE ALSO + * osm_db_t + *********/ + +void osm_db_construct(IN osm_db_t * 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 * 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 * 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 * 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 = strdup_expand(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 * p_db, IN char *domain_name) +{ + osm_db_domain_t *p_domain; + osm_db_domain_imp_t *p_domain_imp; + size_t path_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 = malloc(sizeof(osm_db_domain_t)); + CL_ASSERT(p_domain != NULL); + + p_domain_imp = malloc(sizeof(osm_db_domain_imp_t)); + CL_ASSERT(p_domain_imp != NULL); + + path_len = strlen(((osm_db_imp_t *) p_db->p_db_imp)->db_dir_name) + + strlen(domain_name) + 2; + + /* set the domain file name */ + p_domain_imp->file_name = malloc(path_len); + CL_ASSERT(p_domain_imp->file_name != NULL); + snprintf(p_domain_imp->file_name, path_len, +#ifdef __WIN__ + "%s\\%s", +#else + "%s/%s", +#endif + ((osm_db_imp_t *) p_db->p_db_imp)->db_dir_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 = 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 = malloc(sizeof(char) * + (strlen(p_rest_of_line) + 1)); + strcpy(p_accum_val, p_rest_of_line); + } else { + p_accum_val = 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 = 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 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 = 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, 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 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, clear_tbl_entry, (st_data_t) NULL); + cl_spinlock_release(&p_domain_imp->lock); + + return 0; +} + +static int 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, 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 *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 *p_key, IN char *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 *p_key) +{ + osm_log_t *p_log = p_domain->p_db->p_log; + osm_db_domain_imp_t *p_domain_imp = + (osm_db_domain_imp_t *) p_domain->p_domain_imp; + char *p_prev_val = NULL; + int res; + + OSM_LOG_ENTER(p_log); + + cl_spinlock_acquire(&p_domain_imp->lock); + if (st_delete(p_domain_imp->p_hash, + (void *)&p_key, (void *)&p_prev_val)) { + if (st_lookup(p_domain_imp->p_hash, + (st_data_t) p_key, (void *)&p_prev_val)) { + OSM_LOG(p_log, OSM_LOG_ERROR, + "key:%s still exists in:%s with value:%s\n", + p_key, p_domain_imp->file_name, p_prev_val); + res = 1; + } else { + free(p_key); + free(p_prev_val); + res = 0; + } + } else { + OSM_LOG(p_log, OSM_LOG_DEBUG, + "fail to find key:%s. delete failed\n", p_key); + res = 1; + } + cl_spinlock_release(&p_domain_imp->lock); + + OSM_LOG_EXIT(p_log); + return res; +} + +#ifdef TEST_OSMDB +#include +#include + +int main(int argc, char **argv) +{ + osm_db_t db; + osm_log_t log; + osm_db_domain_t *p_dbd; + cl_list_t keys; + cl_list_iterator_t kI; + char *p_key; + char *p_val; + int i; + + cl_list_construct(&keys); + cl_list_init(&keys, 10); + + osm_log_init_v2(&log, TRUE, 0xff, "/var/log/osm_db_test.log", 0, FALSE); + + osm_db_construct(&db); + if (osm_db_init(&db, &log)) { + printf("db init failed\n"); + exit(1); + } + + p_dbd = osm_db_domain_init(&db, "lid_by_guid"); + + if (osm_db_restore(p_dbd)) { + printf("failed to restore\n"); + } + + if (osm_db_keys(p_dbd, &keys)) { + printf("failed to get keys\n"); + } else { + kI = cl_list_head(&keys); + while (kI != cl_list_end(&keys)) { + p_key = cl_list_obj(kI); + kI = cl_list_next(kI); + + p_val = osm_db_lookup(p_dbd, p_key); + printf("key = %s val = %s\n", p_key, p_val); + } + } + + cl_list_remove_all(&keys); + + /* randomly add and remove numbers */ + for (i = 0; i < 10; i++) { + int k; + float v; + int is_add; + char val_buf[16]; + char key_buf[16]; + + k = floor(1.0 * rand() / RAND_MAX * 100); + v = rand(); + sprintf(key_buf, "%u", k); + sprintf(val_buf, "%u", v); + + is_add = (rand() < RAND_MAX / 2); + + if (is_add) { + osm_db_update(p_dbd, key_buf, val_buf); + } else { + osm_db_delete(p_dbd, key_buf); + } + } + if (osm_db_keys(p_dbd, &keys)) { + printf("failed to get keys\n"); + } else { + kI = cl_list_head(&keys); + while (kI != cl_list_end(&keys)) { + p_key = cl_list_obj(kI); + kI = cl_list_next(kI); + + p_val = osm_db_lookup(p_dbd, p_key); + printf("key = %s val = %s\n", p_key, p_val); + } + } + if (osm_db_store(p_dbd)) + printf("failed to store\n"); + + osm_db_destroy(&db); + cl_list_destroy(&keys); +} +#endif diff --git a/branches/WOF2-3/ulp/opensm/user/opensm/osm_db_pack.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_db_pack.c new file mode 100644 index 00000000..a1b61a79 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_db_pack.c @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2006 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +static inline void pack_guid(uint64_t guid, char *p_guid_str) +{ + sprintf(p_guid_str, "0x%016" PRIx64, guid); +} + +static inline uint64_t unpack_guid(char *p_guid_str) +{ + return strtoull(p_guid_str, NULL, 0); +} + +static inline void pack_lids(uint16_t min_lid, uint16_t max_lid, char *lid_str) +{ + sprintf(lid_str, "0x%04x 0x%04x", min_lid, max_lid); +} + +static inline int 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 * 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 = 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 * 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; + + pack_guid(guid, guid_str); + p_lid_str = osm_db_lookup(p_g2l, guid_str); + if (!p_lid_str) + return 1; + if (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 * p_g2l, IN uint64_t guid, + IN uint16_t min_lid, IN uint16_t max_lid) +{ + char guid_str[20]; + char lid_str[16]; + + pack_guid(guid, guid_str); + 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 * p_g2l, IN uint64_t guid) +{ + char guid_str[20]; + pack_guid(guid, guid_str); + return osm_db_delete(p_g2l, guid_str); +} diff --git a/branches/WOF2-3/ulp/opensm/user/opensm/osm_drop_mgr.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_drop_mgr.c new file mode 100644 index 00000000..d8d3e563 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_drop_mgr.c @@ -0,0 +1,491 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2008 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Copyright (c) 2008 Xsigo Systems Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_drop_mgr_t. + * This object represents the Drop Manager object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void 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 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_port_t *mcm_port=NULL; + 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; + } + + /* issue a notice - trap 65 */ + /* details of the notice */ + notice.generic_type = 0x83; /* is generic subn mgt type */ + ib_notice_set_prod_type_ho(¬ice, 4); /* A class manager generator */ + /* endport ceases to be reachable */ + notice.g_or_v.generic.trap_num = CL_HTON16(65); + /* The sm_base_lid is saved in network order already. */ + notice.issuer_lid = sm->p_subn->sm_base_lid; + /* following C14-72.1.2 and table 119 p725 */ + /* we need to provide the GID */ + port_gid.unicast.prefix = sm->p_subn->opt.subnet_prefix; + port_gid.unicast.interface_id = port_guid; + memcpy(&(notice.data_details.ntc_64_67.gid), + &(port_gid), sizeof(ib_gid_t)); + + /* According to page 653 - the issuer gid in this case of trap + is the SM gid, since the SM is the initiator of this trap. */ + notice.issuer_gid.unicast.prefix = sm->p_subn->opt.subnet_prefix; + notice.issuer_gid.unicast.interface_id = sm->p_subn->sm_port_guid; + + status = osm_report_notice(sm->p_log, sm->p_subn, ¬ice); + if (status != IB_SUCCESS) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0103: " + "Error sending trap reports (%s)\n", + ib_get_err_str(status)); + } + + 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); + } + + 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); + + while (!cl_is_qlist_empty(&p_port->mcm_list)) { + mcm_port = cl_item_obj(cl_qlist_head(&p_port->mcm_list), + mcm_port, list_item); + osm_mgrp_delete_port(sm->p_subn, sm->p_log, mcm_port->mgrp, + p_port->guid); + } + + /* initialize the p_node - may need to get node_desc later */ + p_node = p_port->p_node; + + osm_port_delete(&p_port); + + 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 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 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) + drop_mgr_remove_port(sm, p_port); + else + drop_mgr_clean_physp(sm, p_physp); + } + } + + return_val = TRUE; + + if (p_node->sw) + 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 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)); + + 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)); + + 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)); + + 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)); + + 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, *p_port_guid_tbl; + osm_port_t *p_port, *p_next_port; + osm_node_t *p_node, *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) + 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 */ + 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) + drop_mgr_remove_port(sm, p_port); + } + + CL_PLOCK_RELEASE(sm->p_lock); + OSM_LOG_EXIT(sm->p_log); +} diff --git a/branches/WOF2-3/ulp/opensm/user/opensm/osm_dump.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_dump.c new file mode 100644 index 00000000..a5c7127d --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_dump.c @@ -0,0 +1,639 @@ +/* + * Copyright (c) 2009 Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2006 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Various OpenSM dumpers + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void dump_ucast_path_distribution(cl_map_item_t * 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 *) 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 * 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 *) item; + osm_opensm_t *p_osm = cxt; + + p_node = p_sw->p_node; + + max_lid_ho = p_sw->max_lid_ho; + + fprintf(file, "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 = osm_get_port_by_lid_ho(&p_osm->subn, 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, "%03u : HOPS UNKNOWN\n", port_num); + 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 * item, FILE * file, void *cxt) +{ + osm_switch_t *p_sw = (osm_switch_t *) 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 * item, FILE * file, void *cxt) +{ + osm_switch_t *p_sw = (osm_switch_t *) 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 = osm_get_port_by_lid_ho(&p_osm->subn, 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 * item, FILE * file, void *cxt) +{ + osm_switch_t *p_sw = (osm_switch_t *) 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 = osm_get_port_by_lid_ho(&p_osm->subn, 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 * item, FILE * file, void *cxt) +{ + osm_node_t *p_node = (osm_node_t *) 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 * item, FILE * file, void *cxt) +{ + osm_node_t *p_node = (osm_node_t *) 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/branches/WOF2-3/ulp/opensm/user/opensm/osm_event_plugin.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_event_plugin.c new file mode 100644 index 00000000..dbf5a641 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_event_plugin.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2008-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2007 The Regents of the University of California. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/****h* OpenSM Event plugin interface +* DESCRIPTION +* Database interface to record subnet events +* +* Implementations of this object _MUST_ be thread safe. +* +* AUTHOR +* Ira Weiny, LLNL +* +*********/ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include + +#if defined(PATH_MAX) +#define OSM_PATH_MAX (PATH_MAX + 1) +#elif defined (_POSIX_PATH_MAX) +#define OSM_PATH_MAX (_POSIX_PATH_MAX + 1) +#else +#define OSM_PATH_MAX 256 +#endif + +/** + * functions + */ +osm_epi_plugin_t *osm_epi_construct(osm_opensm_t *osm, char *plugin_name) +{ + char lib_name[OSM_PATH_MAX]; + struct old_if { unsigned ver; } *old_impl; + osm_epi_plugin_t *rc = NULL; + + if (!plugin_name || !*plugin_name) + return NULL; + + /* find the plugin */ + snprintf(lib_name, sizeof(lib_name), "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/branches/WOF2-3/ulp/opensm/user/opensm/osm_files.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_files.c new file mode 100644 index 00000000..0540861c --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_files.c @@ -0,0 +1,86 @@ +/* + * [4-15-2010] + * + * files moved from SOURCES to here to decrease opensm.exe build time. + * Reduced OpenSM.exe build time by 29 seconds. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + diff --git a/branches/WOF2-3/ulp/opensm/user/opensm/osm_helper.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_helper.c new file mode 100644 index 00000000..0803f0f3 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_helper.c @@ -0,0 +1,2247 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2009 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Copyright (c) 2009 HNR Consulting. All rights reserved. + * Copyright (c) 2009 Sun Microsystems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of opensm helper functions. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define LINE_LENGTH 256 + +#define ARR_SIZE(a) (sizeof(a)/sizeof((a)[0])) + +/* we use two tables - one for queries and one for responses */ +static const char *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 *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 *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 *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 *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 + +static int sprint_uint8_arr(char *buf, size_t size, + const uint8_t * arr, size_t len) +{ + unsigned int n, i; + for (i = 0, n = 0; i < len; i++) { + n += snprintf(buf + n, size - n, "%s%u", i == 0 ? "" : ",", + arr[i]); + if (n >= size) + break; + } + return n; +} + +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 = 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 = 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, SM priority 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"; +} + +const ib_gid_t ib_zero_gid = { {0} }; + +static ib_api_status_t dbg_do_line(IN char **pp_local, IN uint32_t buf_size, + IN const char *p_prefix_str, + IN const char *p_new_str, + IN uint32_t * 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 uint32_t buf_size, + IN const char *p_prefix_str, + IN const ib_port_info_t * 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_HAS_VEND_MADS) { + if (dbg_do_line(&p_local, buf_size, p_prefix_str, + "IB_PORT_CAP_HAS_VEND_MADS\n", + &total_len) != IB_SUCCESS) + return; + } + if (p_pi->capability_mask & IB_PORT_CAP_HAS_MCAST_PKEY_TRAP_SUPPRESS) { + if (dbg_do_line(&p_local, buf_size, p_prefix_str, + "IB_PORT_CAP_HAS_MCAST_PKEY_TRAP_SUPPRESS\n", + &total_len) != IB_SUCCESS) + return; + } + if (p_pi->capability_mask & IB_PORT_CAP_HAS_MCAST_FDB_TOP) { + if (dbg_do_line(&p_local, buf_size, p_prefix_str, + "IB_PORT_CAP_HAS_MCAST_FDB_TOP\n", + &total_len) != IB_SUCCESS) + return; + } + if (p_pi->capability_mask & IB_PORT_CAP_HAS_HIER_INFO) { + if (dbg_do_line(&p_local, buf_size, p_prefix_str, + "IB_PORT_CAP_HAS_HIER_INFO\n", + &total_len) != IB_SUCCESS) + return; + } +} + +void osm_dump_port_info(IN osm_log_t * p_log, IN ib_net64_t node_guid, + IN ib_net64_t port_guid, IN uint8_t port_num, + IN const ib_port_info_t * p_pi, + IN 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\tmcast_pkey_trap_suppr...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" + "\t\t\t\tmax_credit_hint.........0x%X\n" + "\t\t\t\tlink_round_trip_latency.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_mcast_pkey_trap_suppress(p_pi), + ib_port_info_get_timeout(p_pi), p_pi->resp_time_value, + p_pi->error_threshold, cl_ntoh16(p_pi->max_credit_hint), + cl_ntoh32(p_pi->link_rt_latency)); + + /* 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 * p_log, + IN const ib_portinfo_record_t * p_pir, + IN osm_log_level_t log_level) +{ + if (osm_log_is_active(p_log, log_level)) { + char buf[BUF_SIZE]; + const ib_port_info_t *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.................%u\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 * p_log, + IN const ib_guidinfo_record_t * p_gir, + IN osm_log_level_t log_level) +{ + if (osm_log_is_active(p_log, log_level)) { + const ib_guid_info_t *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 * p_log, IN const ib_node_info_t * p_ni, + IN 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 * p_log, + IN const ib_node_record_t * p_nr, + IN 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 *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 * p_log, IN const ib_path_rec_t * p_pr, + IN 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, + "PathRecord dump:\n" + "\t\t\t\tservice_id..............0x%016" PRIx64 "\n" + "\t\t\t\tdgid....................%s\n" + "\t\t\t\tsgid....................%s\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%02X%02X%02X%02X%02X%02X\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, + p_pr->resv2[0], p_pr->resv2[1], p_pr->resv2[2], + p_pr->resv2[3], p_pr->resv2[4], p_pr->resv2[5]); + } +} + +void osm_dump_multipath_record(IN osm_log_t * p_log, + IN const ib_multipath_rec_t * p_mpr, + IN osm_log_level_t log_level) +{ + if (osm_log_is_active(p_log, log_level)) { + char gid_str[INET6_ADDRSTRLEN]; + 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.................." + "%s\n", i + 1, + inet_ntop(AF_INET6, p_gid->raw, + gid_str, + sizeof gid_str)); + 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.................." + "%s\n", i + 1, + inet_ntop(AF_INET6, p_gid->raw, + gid_str, + sizeof gid_str)); + 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 * p_log, IN const ib_member_rec_t * p_mcmr, + IN 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 * p_log, + IN const ib_service_record_t * p_sr, + IN 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 * p_log, + IN const ib_inform_info_t * p_ii, + IN osm_log_level_t log_level) +{ + if (osm_log_is_active(p_log, log_level)) { + uint32_t qpn; + uint8_t resp_time_val; + char gid_str[INET6_ADDRSTRLEN]; + 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.....................%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_ii->gid.raw, gid_str, + sizeof gid_str), + 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.....................%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_ii->gid.raw, gid_str, + sizeof gid_str), + 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 * p_log, + IN const ib_inform_info_record_t * p_iir, + IN 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 * p_log, + IN const ib_link_record_t * p_lr, + IN 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 * p_log, + IN const ib_switch_info_t * p_si, + IN 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" + "\t\t\t\tmcast_top...............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, + cl_ntoh16(p_si->mcast_top)); + } +} + +void osm_dump_switch_info_record(IN osm_log_t * p_log, + IN const ib_switch_info_record_t * p_sir, + IN 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 * p_log, IN uint64_t port_guid, + IN uint16_t block_num, IN uint8_t port_num, + IN const ib_pkey_table_t * p_pkey_tbl, + IN 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 * 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 * p_slvl_tbl, + IN 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 * p_log, IN uint64_t port_guid, + IN uint8_t block_num, IN uint8_t port_num, + IN const ib_vl_arb_table_t * p_vla_tbl, + IN 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 * p_log, IN const ib_sm_info_t * p_smi, + IN 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 * p_log, + IN const ib_sminfo_record_t * p_smir, + IN 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 * p_log, + IN const ib_mad_notice_attr_t * p_ntci, + IN osm_log_level_t log_level) +{ + if (!osm_log_is_active(p_log, log_level)) + return; + + if (ib_notice_is_generic(p_ntci)) { + char gid_str[INET6_ADDRSTRLEN]; + char gid_str2[INET6_ADDRSTRLEN]; + char buff[1024]; + int n; + 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..................%s\n", + inet_ntop(AF_INET6, p_ntci->data_details. + ntc_64_67.gid.raw, gid_str, + sizeof gid_str)); + 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\tlocal_changes............%u\n" + "\t\t\t\tnew_cap_mask.............0x%08x\n" + "\t\t\t\tchange_flags.............0x%x\n", + cl_ntoh16(p_ntci->data_details.ntc_144.lid), + p_ntci->data_details.ntc_144.local_changes, + cl_ntoh32(p_ntci->data_details.ntc_144. + new_cap_mask), + cl_ntoh16(p_ntci->data_details.ntc_144. + change_flgs)); + 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; + case 256: + n = sprintf(buff, + "\t\t\t\tlid......................%u\n" + "\t\t\t\tdrslid...................%u\n" + "\t\t\t\tmethod...................0x%x\n" + "\t\t\t\tattr_id..................0x%x\n" + "\t\t\t\tattr_mod.................0x%x\n" + "\t\t\t\tm_key....................0x%016" + PRIx64 "\n" + "\t\t\t\tdr_notice................%d\n" + "\t\t\t\tdr_path_truncated........%d\n" + "\t\t\t\tdr_hop_count.............%u\n", + cl_ntoh16(p_ntci->data_details.ntc_256.lid), + cl_ntoh16(p_ntci->data_details.ntc_256. + dr_slid), + p_ntci->data_details.ntc_256.method, + cl_ntoh16(p_ntci->data_details.ntc_256. + attr_id), + cl_ntoh32(p_ntci->data_details.ntc_256. + attr_mod), + cl_ntoh64(p_ntci->data_details.ntc_256. + mkey), + p_ntci->data_details.ntc_256. + dr_trunc_hop >> 7, + p_ntci->data_details.ntc_256. + dr_trunc_hop >> 6, + p_ntci->data_details.ntc_256. + dr_trunc_hop & 0x3f); + n += snprintf(buff + n, sizeof(buff) - n, + "Directed Path Dump of %u hop path:" + "\n\t\t\t\tPath = ", + p_ntci->data_details.ntc_256. + dr_trunc_hop & 0x3f); + n += sprint_uint8_arr(buff + n, sizeof(buff) - n, + p_ntci->data_details.ntc_256. + dr_rtn_path, + (p_ntci->data_details.ntc_256. + dr_trunc_hop & 0x3f) + 1); + if (n >= sizeof(buff)) { + n = sizeof(buff) - 2; + break; + } + snprintf(buff + n, sizeof(buff) - n, "\n"); + break; + case 257: + case 258: + sprintf(buff, + "\t\t\t\tlid1.....................%u\n" + "\t\t\t\tlid2.....................%u\n" + "\t\t\t\tkey......................0x%x\n" + "\t\t\t\tsl.......................%d\n" + "\t\t\t\tqp1......................0x%x\n" + "\t\t\t\tqp2......................0x%x\n" + "\t\t\t\tgid1.....................%s\n" + "\t\t\t\tgid2.....................%s\n", + cl_ntoh16(p_ntci->data_details.ntc_257_258. + lid1), + cl_ntoh16(p_ntci->data_details.ntc_257_258. + lid2), + cl_ntoh32(p_ntci->data_details.ntc_257_258.key), + cl_ntoh32(p_ntci->data_details.ntc_257_258. + qp1) >> 28, + cl_ntoh32(p_ntci->data_details.ntc_257_258. + qp1) & 0xffffff, + cl_ntoh32(p_ntci->data_details.ntc_257_258. + qp2) & 0xffffff, + inet_ntop(AF_INET6, p_ntci->data_details. + ntc_257_258.gid1.raw, gid_str, + sizeof gid_str), + inet_ntop(AF_INET6, p_ntci->data_details. + ntc_257_258.gid2.raw, gid_str2, + sizeof gid_str2)); + break; + case 259: + sprintf(buff, + "\t\t\t\tdata_valid...............0x%x\n" + "\t\t\t\tlid1.....................%u\n" + "\t\t\t\tlid2.....................%u\n" + "\t\t\t\tpkey.....................0x%x\n" + "\t\t\t\tsl.......................%d\n" + "\t\t\t\tqp1......................0x%x\n" + "\t\t\t\tqp2......................0x%x\n" + "\t\t\t\tgid1.....................%s\n" + "\t\t\t\tgid2.....................%s\n" + "\t\t\t\tsw_lid...................%u\n" + "\t\t\t\tport_no..................%u\n", + cl_ntoh16(p_ntci->data_details.ntc_259. + data_valid), + cl_ntoh16(p_ntci->data_details.ntc_259.lid1), + cl_ntoh16(p_ntci->data_details.ntc_259.lid2), + cl_ntoh16(p_ntci->data_details.ntc_259.pkey), + cl_ntoh32(p_ntci->data_details.ntc_259. + sl_qp1) >> 24, + cl_ntoh32(p_ntci->data_details.ntc_259. + sl_qp1) & 0xffffff, + cl_ntoh32(p_ntci->data_details.ntc_259.qp2), + inet_ntop(AF_INET6, p_ntci->data_details. + ntc_259.gid1.raw, gid_str, + sizeof gid_str), + inet_ntop(AF_INET6, p_ntci->data_details. + ntc_259.gid2.raw, gid_str2, + sizeof gid_str2), + cl_ntoh16(p_ntci->data_details.ntc_259.sw_lid), + p_ntci->data_details.ntc_259.port_no); + 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 * p_log, IN const ib_smp_t * p_smp, + IN osm_log_level_t log_level) +{ + if (osm_log_is_active(p_log, log_level)) { + char buf[BUF_SIZE]; + unsigned n; + + n = 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) { + n += snprintf(buf + n, sizeof(buf) - n, + "\t\t\t\tD bit...................0x%X\n" + "\t\t\t\tstatus..................0x%X\n", + ib_smp_is_d(p_smp), + cl_ntoh16(ib_smp_get_status(p_smp))); + } else { + n += snprintf(buf + n, sizeof(buf) - n, + "\t\t\t\tstatus..................0x%X\n", + cl_ntoh16(p_smp->status)); + } + + n += snprintf(buf + n, sizeof(buf) - n, + "\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)); + + if (p_smp->mgmt_class == IB_MCLASS_SUBN_DIR) { + uint32_t i; + n += snprintf(buf + n, sizeof(buf) - n, + "\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)); + + n += snprintf(buf + n, sizeof(buf) - n, + "\n\t\t\t\tInitial path: "); + n += sprint_uint8_arr(buf + n, sizeof(buf) - n, + p_smp->initial_path, + p_smp->hop_count + 1); + + n += snprintf(buf + n, sizeof(buf) - n, + "\n\t\t\t\tReturn path: "); + n += sprint_uint8_arr(buf + n, sizeof(buf) - n, + p_smp->return_path, + p_smp->hop_count + 1); + + n += snprintf(buf + n, sizeof(buf) - n, + "\n\t\t\t\tReserved: "); + for (i = 0; i < 7; i++) { + n += snprintf(buf + n, sizeof(buf) - n, + "[%0X]", p_smp->resv1[i]); + } + n += snprintf(buf + n, sizeof(buf) - n, "\n"); + + for (i = 0; i < 64; i += 16) { + n += snprintf(buf + n, sizeof(buf) - n, + "\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]); + } + } else { + /* not a Direct Route so provide source and destination lids */ + n += snprintf(buf + n, sizeof(buf) - n, + "\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 * p_log, IN const ib_sa_mad_t * p_mad, + IN 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 * p_log, IN const osm_dr_path_t * p_path, + IN osm_log_level_t log_level) +{ + if (osm_log_is_active(p_log, log_level)) { + char buf[BUF_SIZE]; + unsigned n = 0; + + n = sprintf(buf, "Directed Path Dump of %u hop path: " + "Path = ", p_path->hop_count); + + sprint_uint8_arr(buf + n, sizeof(buf) - n, p_path->path, + p_path->hop_count + 1); + osm_log(p_log, log_level, "%s\n", buf); + } +} + +void osm_dump_smp_dr_path(IN osm_log_t * p_log, IN const ib_smp_t * p_smp, + IN osm_log_level_t log_level) +{ + if (osm_log_is_active(p_log, log_level)) { + char buf[BUF_SIZE]; + unsigned n; + + n = sprintf(buf, "Received SMP on a %u hop path: " + "Initial path = ", p_smp->hop_count); + n += sprint_uint8_arr(buf + n, sizeof(buf) - n, + p_smp->initial_path, + p_smp->hop_count + 1); + + n += sprintf(buf + n, ", Return path = "); + n += sprint_uint8_arr(buf + n, sizeof(buf) - n, + p_smp->return_path, p_smp->hop_count + 1); + + osm_log(p_log, log_level, "%s\n", buf); + } +} + +static const char *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 sm_signal_str[signal]; +} + +static const char *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 + "OSM_MSG_MAD_PORT_COUNTERS", + "UNKNOWN!!" +}; + +const char *osm_get_disp_msg_str(IN cl_disp_msgid_t msg) +{ + if (msg > OSM_MSG_MAX) + msg = OSM_MSG_MAX; + return disp_msg_str[msg]; +} + +static const char *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 port_state_str_fixed_width[port_state]; +} + +static const char *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 node_type_str_fixed_width[node_type]; +} + +const char *osm_get_manufacturer_str(IN uint64_t 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 *dell_str = "Dell"; + static const char *supermicro_str = "SuperMicro"; + 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: + case OSM_VENDOR_ID_HP3: + case OSM_VENDOR_ID_HP4: + return hp_str; + case OSM_VENDOR_ID_RIOWORKS: + return rioworks_str; + case OSM_VENDOR_ID_SUN: + case OSM_VENDOR_ID_SUN2: + return sun_str; + case OSM_VENDOR_ID_3LEAFNTWKS: + return leafntwks_str; + case OSM_VENDOR_ID_XSIGO: + return xsigo_str; + case OSM_VENDOR_ID_DELL: + return dell_str; + case OSM_VENDOR_ID_SUPERMICRO: + return supermicro_str; + default: + return unknown_str; + } +} + +static const char *mtu_str_fixed_width[] = { + "??? ", + "256 ", + "512 ", + "1024", + "2048", + "4096" +}; + +const char *osm_get_mtu_str(IN uint8_t mtu) +{ + if (mtu > IB_MTU_LEN_4096) + return mtu_str_fixed_width[0]; + else + return mtu_str_fixed_width[mtu]; +} + +static const char *lwa_str_fixed_width[] = { + "???", + "1x ", + "4x ", + "???", + "8x ", + "???", + "???", + "???", + "12x" +}; + +const char *osm_get_lwa_str(IN uint8_t lwa) +{ + if (lwa > 8) + return lwa_str_fixed_width[0]; + else + return lwa_str_fixed_width[lwa]; +} + +static const char *lsa_str_fixed_width[] = { + "???", + "2.5", + "5 ", + "???", + "10 " +}; + +const char *osm_get_lsa_str(IN uint8_t lsa) +{ + if (lsa > 4) + return lsa_str_fixed_width[0]; + else + return lsa_str_fixed_width[lsa]; +} + +static const char *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 sm_mgr_signal_str[signal]; +} + +static const char *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(sm_mgr_state_str) ? + sm_mgr_state_str[state] : + sm_mgr_state_str[ARR_SIZE(sm_mgr_state_str) - 1]; +} diff --git a/branches/WOF2-3/ulp/opensm/user/opensm/osm_inform.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_inform.c new file mode 100644 index 00000000..2cdf456c --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_inform.c @@ -0,0 +1,617 @@ +/* + * Copyright (c) 2004-2009 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) 2009 HNR Consulting. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of inform record functions. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct osm_infr_match_ctxt { + cl_list_t *p_remove_infr_list; + ib_mad_notice_attr_t *p_ntc; +} osm_infr_match_ctxt_t; + +void osm_infr_delete(IN osm_infr_t * 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 const osm_subn_t * 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 * 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; + + 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; + } + + /* if inform_info.gid is not zero, ignore lid range */ + if (ib_gid_is_notzero(&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 * 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); + p_subn->p_osm->sa.dirty = TRUE; + + 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); + p_subn->p_osm->sa.dirty = TRUE; + + 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 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)); + + if (!p_report_madw) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0203" + "osm_mad_pool_get failed\n"); + status = IB_ERROR; + goto Exit; + } + + p_report_madw->resp_expected = TRUE; + + /* 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 * 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 = osm_get_port_by_lid(p_subn, + 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"); + 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 + **********************************************************************/ +static void log_notice(osm_log_t * log, osm_log_level_t level, + ib_mad_notice_attr_t * ntc) +{ + char gid_str[INET6_ADDRSTRLEN]; + ib_gid_t *gid; + + /* an official Event information log */ + if (ib_notice_is_generic(ntc)) { + if ((ntc->g_or_v.generic.trap_num == CL_HTON16(64)) || + (ntc->g_or_v.generic.trap_num == CL_HTON16(65)) || + (ntc->g_or_v.generic.trap_num == CL_HTON16(66)) || + (ntc->g_or_v.generic.trap_num == CL_HTON16(67))) + gid = &ntc->data_details.ntc_64_67.gid; + else + gid = &ntc->issuer_gid; + OSM_LOG(log, level, + "Reporting Generic Notice type:%u num:%u (%s)" + " from LID:%u GID:%s\n", + ib_notice_get_type(ntc), + cl_ntoh16(ntc->g_or_v.generic.trap_num), + ib_get_trap_str(ntc->g_or_v.generic.trap_num), + cl_ntoh16(ntc->issuer_lid), + inet_ntop(AF_INET6, gid->raw, gid_str, sizeof gid_str)); + } else + OSM_LOG(log, level, + "Reporting Vendor Notice type:%u vend:%u dev:%u" + " from LID:%u GID:%s\n", + ib_notice_get_type(ntc), + cl_ntoh32(ib_notice_get_vend_id(ntc)), + cl_ntoh16(ntc->g_or_v.vend.dev_id), + cl_ntoh16(ntc->issuer_lid), + inet_ntop(AF_INET6, ntc->issuer_gid.raw, gid_str, + sizeof gid_str)); +} + +ib_api_status_t osm_report_notice(IN osm_log_t * p_log, IN osm_subn_t * p_subn, + IN ib_mad_notice_attr_t * p_ntc) +{ + 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; + } + + if (osm_log_is_active(p_log, OSM_LOG_INFO)) + log_notice(p_log, OSM_LOG_INFO, p_ntc); + + /* 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); + + /* report IB traps to plugin */ + osm_opensm_report_event(p_subn->p_osm, OSM_EVENT_ID_TRAP, p_ntc); + + OSM_LOG_EXIT(p_log); + + return IB_SUCCESS; +} diff --git a/branches/WOF2-3/ulp/opensm/user/opensm/osm_lid_mgr.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_lid_mgr.c new file mode 100644 index 00000000..50860040 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_lid_mgr.c @@ -0,0 +1,1206 @@ +/* + * Copyright (c) 2004-2009 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_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: + * 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 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 lid_mgr_get_port_min_lid + * 3.1.2 if a change required send the port info + * 3.2 if any change send the signal PENDING... + * + * 4. Store the guid2lid + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/********************************************************************** + lid range item of qlist + **********************************************************************/ +typedef struct osm_lid_mgr_range { + cl_list_item_t item; + uint16_t min_lid; + uint16_t max_lid; +} osm_lid_mgr_range_t; + +void osm_lid_mgr_construct(IN osm_lid_mgr_t * p_mgr) +{ + memset(p_mgr, 0, sizeof(*p_mgr)); +} + +void osm_lid_mgr_destroy(IN osm_lid_mgr_t * p_mgr) +{ + cl_list_item_t *p_item; + + OSM_LOG_ENTER(p_mgr->p_log); + + while ((p_item = cl_qlist_remove_head(&p_mgr->free_ranges)) != + cl_qlist_end(&p_mgr->free_ranges)) + free((osm_lid_mgr_range_t *) p_item); + 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 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); + + lmc_mask = ~((1 << p_mgr->p_subn->opt.lmc) - 1); + + 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; + } + + while ((p_item = (osm_db_guid_elem_t *) cl_qlist_remove_head(&guids)) + != (osm_db_guid_elem_t *) 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 (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) + /* mark that it was visited */ + for (lid = min_lid; lid <= max_lid; lid++) + p_mgr->used_lids[lid] = 1; + else 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); + } /* got a lid */ + free(p_item); + } /* all guids */ +Exit: + OSM_LOG_EXIT(p_mgr->p_log); +} + +ib_api_status_t osm_lid_mgr_init(IN osm_lid_mgr_t * 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_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 */ + lid_mgr_validate_db(p_mgr); + } + +Exit: + OSM_LOG_EXIT(p_mgr->p_log); + return status; +} + +static uint16_t 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 lid_mgr_init_sweep(IN osm_lid_mgr_t * p_mgr) +{ + cl_ptr_vector_t *p_discovered_vec = &p_mgr->p_subn->port_lid_tbl; + uint16_t max_defined_lid, max_persistent_lid, max_discovered_lid; + uint16_t disc_min_lid, disc_max_lid, db_min_lid, 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, req_lid, num_lids, lid; + + OSM_LOG_ENTER(p_mgr->p_log); + + lmc_mask = ~((1 << p_mgr->p_subn->opt.lmc) - 1); + + /* 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) { + osm_db_clear(p_mgr->p_g2l); + memset(p_mgr->used_lids, 0, sizeof(p_mgr->used_lids)); + 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"); + else { + OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, + "Honor current guid2lid file when coming out " + "of standby\n"); + 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"); + lid_mgr_validate_db(p_mgr); + } + } + + /* we need to cleanup the empty ranges list */ + while ((p_item = cl_qlist_remove_head(&p_mgr->free_ranges)) != + cl_qlist_end(&p_mgr->free_ranges)) + free((osm_lid_mgr_range_t *) p_item); + + /* 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 = 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 = trim_lid(disc_min_lid); + disc_max_lid = 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)) + continue; + + 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++) + p_mgr->used_lids[lid] = 0; + } + } + + /* + 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 = sizeof(p_mgr->used_lids) - 1; + + /* but the vectors have one extra entry for lid=0 */ + if (max_discovered_lid) + max_discovered_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 && p_mgr->used_lids[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; + /* check this is a discovered port */ + } else if (lid <= max_discovered_lid && + (p_port = 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 && + p_mgr->used_lids[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 = malloc(sizeof(osm_lid_mgr_range_t)); + if (p_range) { + p_range->min_lid = lid; + p_range->max_lid = lid; + } + } + /* this lid is used so we need to finalize the previous free range */ + } else 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 = 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 lid_mgr_is_range_not_persistent(IN osm_lid_mgr_t * p_mgr, + IN uint16_t lid, + IN uint16_t num_lids) +{ + uint16_t i; + uint8_t start_lid = (uint8_t) (1 << p_mgr->p_subn->opt.lmc); + + if (lid < start_lid) + return FALSE; + + for (i = lid; i < lid + num_lids; i++) + if (p_mgr->used_lids[i]) + return FALSE; + + return TRUE; +} + +/********************************************************************** +find a free lid range +**********************************************************************/ +static void lid_mgr_find_free_lid_range(IN osm_lid_mgr_t * p_mgr, + IN uint8_t num_lids, + OUT uint16_t * p_min_lid, + OUT uint16_t * 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); + lmc_mask = ~((1 << p_mgr->p_subn->opt.lmc) - 1); + + /* + 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); + free(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 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 = trim_lid(min_lid); + max_lid = trim_lid(max_lid); + for (lid = min_lid; lid <= max_lid; lid++) + if (lid < max_tbl_lid && + p_port == 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 lid_mgr_get_port_lid(IN osm_lid_mgr_t * p_mgr, + IN osm_port_t * p_port, + OUT uint16_t * p_min_lid, + OUT uint16_t * 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); + + /* 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 (p_mgr->p_subn->first_time_master_sweep == TRUE && + p_mgr->p_subn->opt.reassign_lids == TRUE) + goto AssignLid; + + lmc_mask = ~(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); + 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); + 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 NewLidSet; + } 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) { + /* make sure lid is valid */ + if ((min_lid & lmc_mask) == min_lid) { + /* is it free */ + if (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); + } + +AssignLid: + /* first cleanup the existing discovered lid range */ + lid_mgr_cleanup_discovered_port_lid_range(p_mgr, p_port); + + /* find an empty space */ + 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++) + p_mgr->used_lids[lid] = 1; + + /* 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 lid_mgr_set_remote_pi_state_to_init(IN osm_lid_mgr_t * p_mgr, + IN osm_physp_t * 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 int lid_mgr_set_physp_pi(IN osm_lid_mgr_t * p_mgr, + IN osm_port_t * p_port, + IN osm_physp_t * p_physp, IN ib_net16_t 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; + int ret = 0; + + 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. + */ + + memcpy(payload, p_old_pi, sizeof(ib_port_info_t)); + memset(payload + sizeof(ib_port_info_t), 0, + IB_SMP_DATA_SIZE - 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"... + */ + 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, + "Setting 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) + goto Exit; + + 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); + if (status != IB_SUCCESS) + ret = -1; + +Exit: + OSM_LOG_EXIT(p_mgr->p_log); + return ret; +} + +/********************************************************************** + Processes our own node + Lock must already be held. +**********************************************************************/ +static int lid_mgr_process_our_sm_node(IN osm_lid_mgr_t * p_mgr) +{ + osm_port_t *p_port; + uint16_t min_lid_ho; + uint16_t max_lid_ho; + int ret; + + 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)); + ret = -1; + 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. + */ + 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. + */ + ret = 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 ret; +} + +int osm_lid_mgr_process_sm(IN osm_lid_mgr_t * p_mgr) +{ + int ret; + + 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 */ + lid_mgr_init_sweep(p_mgr); + + ret = lid_mgr_process_our_sm_node(p_mgr); + + CL_PLOCK_RELEASE(p_mgr->p_lock); + + OSM_LOG_EXIT(p_mgr->p_log); + return ret; +} + +/********************************************************************** + 1 go through all ports in the subnet. + 1.1 call 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... +**********************************************************************/ +int osm_lid_mgr_process_subnet(IN osm_lid_mgr_t * p_mgr) +{ + cl_qmap_t *p_port_guid_tbl; + osm_port_t *p_port; + ib_net64_t port_guid; + int lid_changed, ret = 0; + uint16_t min_lid_ho, max_lid_ho; + + 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); + + 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 + lid_mgr_get_port_lid) + */ + lid_changed = 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 (lid_mgr_set_physp_pi(p_mgr, p_port, p_port->p_physp, + cl_hton16(min_lid_ho))) + ret = -1; + } /* all ports */ + + /* store the guid to lid table in persistent db */ + osm_db_store(p_mgr->p_g2l); + + CL_PLOCK_RELEASE(p_mgr->p_lock); + + OSM_LOG_EXIT(p_mgr->p_log); + return ret; +} diff --git a/branches/WOF2-3/ulp/opensm/user/opensm/osm_lin_fwd_rcv.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_lin_fwd_rcv.c new file mode 100644 index 00000000..f2567d6e --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_lin_fwd_rcv.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005,2008 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Copyright (c) 2009 Sun Microsystems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_lft_rcv_t. + * This object represents the Linear Forwarding Table Receiver object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include + +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 = 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)" + ", Switch 0x%" PRIx64 " %s\n", + ib_get_err_str(status), cl_ntoh64(node_guid), + p_sw->p_node->print_desc); + } + } + + CL_PLOCK_RELEASE(sm->p_lock); + OSM_LOG_EXIT(sm->p_log); +} diff --git a/branches/WOF2-3/ulp/opensm/user/opensm/osm_link_mgr.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_link_mgr.c new file mode 100644 index 00000000..75b44a3e --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_link_mgr.c @@ -0,0 +1,474 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2007 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Copyright (c) 2009 Sun Microsystems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_link_mgr_t. + * This file implements the Link Manager object. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static uint8_t link_mgr_get_smsl(IN osm_sm_t * sm, IN osm_physp_t * p_physp) +{ + osm_opensm_t *p_osm = sm->p_subn->p_osm; + const osm_port_t *p_sm_port, *p_src_port; + ib_net16_t slid; + uint8_t sl; + + OSM_LOG_ENTER(sm->p_log); + + if (p_osm->routing_engine_used != OSM_ROUTING_ENGINE_TYPE_LASH + || !(slid = osm_physp_get_base_lid(p_physp))) { + /* Use default SL if lash routing is not used */ + OSM_LOG_EXIT(sm->p_log); + return sm->p_subn->opt.sm_sl; + } + + /* Find osm_port of the SM itself = dest_port */ + p_sm_port = osm_get_port_by_lid(sm->p_subn, sm->p_subn->sm_base_lid); + + /* Find osm_port of the source = p_physp */ + p_src_port = osm_get_port_by_lid(sm->p_subn, slid); + + /* Call lash to find proper SL */ + sl = osm_get_lash_sl(p_osm, p_src_port, p_sm_port); + + OSM_LOG_EXIT(sm->p_log); + return sl; +} + +static int link_mgr_set_physp_pi(osm_sm_t * sm, IN osm_physp_t * p_physp, + IN uint8_t port_state) +{ + 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 port_num, mtu, op_vls, smsl = OSM_DEFAULT_SL; + boolean_t esp0 = FALSE, send_set = FALSE; + osm_physp_t *p_remote_physp; + int ret = 0; + + OSM_LOG_ENTER(sm->p_log); + + p_node = osm_physp_get_node_ptr(p_physp); + + p_old_pi = &p_physp->port_info; + + 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 + (IBA 1.2.1 p.830 table 146). + */ + 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) { + + /* Even for base port 0 we might have to set smsl + (if we are using lash routing) */ + smsl = link_mgr_get_smsl(sm, p_physp); + if (smsl != ib_port_info_get_master_smsl(p_old_pi)) { + send_set = TRUE; + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Setting SMSL to %d on port 0 GUID 0x%016" + PRIx64 "\n", smsl, + cl_ntoh64(osm_physp_get_port_guid + (p_physp))); + } else { + /* This means the switch doesn't support + enhanced port 0 and we don't need to + change SMSL. 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; + } + } else + esp0 = TRUE; + } + + memcpy(payload, p_old_pi, sizeof(ib_port_info_t)); + memset(payload + sizeof(ib_port_info_t), 0, + IB_SMP_DATA_SIZE - 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); + + /* Check whether this is base port0 smsl handling only */ + if (port_num == 0 && esp0 == FALSE) { + ib_port_info_set_master_smsl(p_pi, smsl); + goto Send; + } + + /* + PAST THIS POINT WE ARE HANDLING EITHER A NON PORT 0 OR ENHANCED PORT 0 + */ + + 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; + + smsl = link_mgr_get_smsl(sm, p_physp); + if (smsl != ib_port_info_get_master_smsl(p_old_pi)) { + + ib_port_info_set_master_smsl(p_pi, smsl); + + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Setting SMSL to %d on GUID 0x%016" + PRIx64 ", port %d\n", smsl, + cl_ntoh64(osm_physp_get_port_guid + (p_physp)), port_num); + + 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; + } + } + +Send: + 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) + goto Exit; + + 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); + if (status) + ret = -1; + +Exit: + OSM_LOG_EXIT(sm->p_log); + return ret; +} + +static int link_mgr_process_node(osm_sm_t * sm, IN osm_node_t * p_node, + IN const uint8_t link_state) +{ + osm_physp_t *p_physp; + uint32_t i, num_physp; + int ret = 0; + uint8_t current_state; + + 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 (link_mgr_set_physp_pi(sm, p_physp, link_state)) + ret = -1; + } + + OSM_LOG_EXIT(sm->p_log); + return ret; +} + +int 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; + int ret = 0; + + 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 (link_mgr_process_node(sm, p_node, link_state)) + ret = -1; + + CL_PLOCK_RELEASE(sm->p_lock); + + OSM_LOG_EXIT(sm->p_log); + return ret; +} diff --git a/branches/WOF2-3/ulp/opensm/user/opensm/osm_log.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_log.c new file mode 100644 index 00000000..a745d47b --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_log.c @@ -0,0 +1,359 @@ +/* + * Copyright (c) 2004-2009 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 osm_log_t. + * This object represents the log file. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static int log_exit_count = 0; + +#include +#include +#include + +static char *month_str[] = { + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec" +}; + +#ifndef __WIN__ + +static void truncate_log_file(osm_log_t * 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 */ + +void truncate_log_file(osm_log_t * p_log) +{ + int fd = _fileno(p_log->out_port); + HANDLE hFile = (HANDLE) _get_osfhandle(fd); + + if (_lseek(fd, 0, SEEK_SET) < 0) + fprintf(stderr, "truncate_log_file: cannot rewind: %s\n", + strerror(errno)); + SetEndOfFile(hFile); + p_log->count = 0; +} + +extern void OsmReportState(IN const char *p_str); + +#endif /* ndef __WIN__ */ + +void osm_log(IN osm_log_t * p_log, IN osm_log_level_t verbosity, + IN const char *p_str, ...) +{ + char buffer[LOG_ENTRY_SIZE_MAX]; + va_list args; + int ret; +#ifdef __WIN__ + SYSTEMTIME st; + uint32_t pid = GetCurrentThreadId(); + int rc; +#else + pid_t pid = 0; + time_t tim; + struct tm result; + uint64_t time_usecs; + uint32_t usecs; +#endif /* __WIN__ */ + + /* If this is a call to syslog - always print it */ + if (!(verbosity & p_log->level)) + return; + + va_start(args, p_str); +#ifndef __WIN__ + if (p_log->log_prefix == NULL) + vsprintf(buffer, p_str, args); + else { + int n = snprintf(buffer, sizeof(buffer), "%s: ", p_log->log_prefix); + vsprintf(buffer + n, p_str, args); + } +#else + if (p_log->log_prefix == NULL) + rc = _vsnprintf(buffer, sizeof(buffer), (LPSTR)p_str, args); + else { + int n = snprintf(buffer, sizeof(buffer), "%s: ", p_log->log_prefix); + rc = _vsnprintf(buffer + n, (sizeof(buffer) - n), (LPSTR)p_str, args); + } +#endif + va_end(args); + + if ( rc < 0 ) { + syslog(LOG_INFO,"%s() osm.log buffer-overflow @ bufsize %d\n", + __FUNCTION__,sizeof(buffer)); + } + + /* 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 __WIN__ + OsmReportState(buffer); +#endif /* __WIN__ */ + } + + /* 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 __WIN__ + GetLocalTime(&st); +_retry: + ret = + fprintf(p_log->out_port, + "[%s-%02d-%04d %02d:%02d:%02d:%03d][%04X] 0x%02x -> %s", + month_str[st.wMonth-1], st.wDay, st.wYear, + 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 * p_log, IN 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 * p_log, IN boolean_t flush, + IN uint8_t log_flags, IN const char *log_file, + IN unsigned long max_size, + IN boolean_t accum_log_file) +{ + p_log->level = log_flags | OSM_LOG_SYS; + p_log->flush = flush; + p_log->count = 0; + p_log->max_size = max_size << 20; /* convert size in MB to bytes */ + 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 * p_log, IN boolean_t flush, + IN uint8_t log_flags, IN const char *log_file, + IN boolean_t accum_log_file) +{ + return osm_log_init_v2(p_log, flush, log_flags, log_file, 0, + accum_log_file); +} diff --git a/branches/WOF2-3/ulp/opensm/user/opensm/osm_mad_pool.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_mad_pool.c new file mode 100644 index 00000000..62dff416 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_mad_pool.c @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_mad_pool_t. + * This object represents a pool of management datagram (MAD) objects. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include + +void osm_mad_pool_construct(IN osm_mad_pool_t * p_pool) +{ + CL_ASSERT(p_pool); + + memset(p_pool, 0, sizeof(*p_pool)); +} + +void osm_mad_pool_destroy(IN osm_mad_pool_t * p_pool) +{ + CL_ASSERT(p_pool); +} + +ib_api_status_t osm_mad_pool_init(IN osm_mad_pool_t * p_pool) +{ + p_pool->mads_out = 0; + + return IB_SUCCESS; +} + +osm_madw_t *osm_mad_pool_get(IN osm_mad_pool_t * p_pool, + IN osm_bind_handle_t h_bind, + IN uint32_t total_size, + IN const osm_mad_addr_t * 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 * p_pool, + IN osm_bind_handle_t h_bind, + IN uint32_t total_size, + IN const ib_mad_t * p_mad, + IN const osm_mad_addr_t * 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 * 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 * p_pool, IN osm_madw_t * 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/branches/WOF2-3/ulp/opensm/user/opensm/osm_mcast_fwd_rcv.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_mcast_fwd_rcv.c new file mode 100644 index 00000000..4e053323 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_mcast_fwd_rcv.c @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2004-2009 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) 2009 Sun Microsystems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_mft_rcv_t. + * This object represents the Multicast Forwarding Table Receiver object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void osm_mft_rcv_process(IN void *context, IN void *data) +{ + osm_sm_t *sm = context; + osm_madw_t *p_madw = data; + ib_smp_t *p_smp; + uint32_t block_num; + uint8_t position; + osm_switch_t *p_sw; + osm_mft_context_t *p_mft_context; + uint16_t *p_block; + ib_net64_t node_guid; + ib_api_status_t status; + + CL_ASSERT(sm); + + OSM_LOG_ENTER(sm->p_log); + + CL_ASSERT(p_madw); + + p_smp = osm_madw_get_smp_ptr(p_madw); + p_block = 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)" + ", Switch 0x%016" PRIx64 + " (%s), block %u, position %u\n", + ib_get_err_str(status), cl_ntoh64(node_guid), + p_sw->p_node->print_desc, block_num, position); + } + } + + CL_PLOCK_RELEASE(sm->p_lock); + OSM_LOG_EXIT(sm->p_log); +} diff --git a/branches/WOF2-3/ulp/opensm/user/opensm/osm_mcast_mgr.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_mcast_mgr.c new file mode 100644 index 00000000..32da52f5 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_mcast_mgr.c @@ -0,0 +1,1171 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2009 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Copyright (c) 2008 Xsigo Systems Inc. All rights reserved. + * Copyright (c) 2009 Sun Microsystems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_mcast_mgr_t. + * This file implements the Multicast Manager object. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct osm_mcast_work_obj { + cl_list_item_t list_item; + osm_port_t *p_port; + cl_map_item_t map_item; +} osm_mcast_work_obj_t; + +static osm_mcast_work_obj_t *mcast_work_obj_new(IN osm_port_t * p_port) +{ + 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 = p_port; + } + + return p_obj; +} + +static void mcast_work_obj_delete(IN osm_mcast_work_obj_t * p_wobj) +{ + free(p_wobj); +} + +static int make_port_list(cl_qlist_t * list, osm_mgrp_box_t * mbox) +{ + cl_qmap_t map; + cl_map_item_t *map_item; + cl_list_item_t *list_item; + osm_mgrp_t *mgrp=NULL; + osm_mcm_port_t *mcm_port=NULL; + osm_mcast_work_obj_t *wobj; + + cl_qmap_init(&map); + cl_qlist_init(list); + + for (list_item = cl_qlist_head(&mbox->mgrp_list); + list_item != cl_qlist_end(&mbox->mgrp_list); + list_item = cl_qlist_next(list_item)) { + mgrp = cl_item_obj(list_item, mgrp, list_item); + for (map_item = cl_qmap_head(&mgrp->mcm_port_tbl); + map_item != cl_qmap_end(&mgrp->mcm_port_tbl); + map_item = cl_qmap_next(map_item)) { + /* Acquire the port object for this port guid, then + create the new worker object to build the list. */ + mcm_port = cl_item_obj(map_item, mcm_port, map_item); + if (cl_qmap_get(&map, mcm_port->port->guid) != + cl_qmap_end(&map)) + continue; + wobj = mcast_work_obj_new(mcm_port->port); + if (!wobj) + return -1; + cl_qlist_insert_tail(list, &wobj->list_item); + cl_qmap_insert(&map, mcm_port->port->guid, + &wobj->map_item); + } + } + return 0; +} + +static void drop_port_list(cl_qlist_t * list) +{ + while (cl_qlist_count(list)) + mcast_work_obj_delete((osm_mcast_work_obj_t *) + cl_qlist_remove_head(list)); +} + +/********************************************************************** + Recursively remove nodes from the tree + *********************************************************************/ +static void 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)) + mcast_mgr_purge_tree_node(p_mtn->child_array[i]); + p_mtn->child_array[i] = NULL; + } + + free(p_mtn); +} + +static void mcast_mgr_purge_tree(osm_sm_t * sm, IN osm_mgrp_box_t * mbox) +{ + OSM_LOG_ENTER(sm->p_log); + + if (mbox->root) + mcast_mgr_purge_tree_node(mbox->root); + mbox->root = NULL; + + OSM_LOG_EXIT(sm->p_log); +} + +static void create_mgrp_switch_map(cl_qmap_t * m, cl_qlist_t * port_list) +{ + osm_mcast_work_obj_t *wobj=NULL; + osm_port_t *port; + osm_switch_t *sw; + ib_net64_t guid; + cl_list_item_t *i; + + cl_qmap_init(m); + for (i = cl_qlist_head(port_list); i != cl_qlist_end(port_list); + i = cl_qlist_next(i)) { + wobj = cl_item_obj(i, wobj, list_item); + port = wobj->p_port; + if (port->p_node->sw) { + sw = port->p_node->sw; + sw->is_mc_member = 1; + } else { + sw = port->p_physp->p_remote_physp->p_node->sw; + sw->num_of_mcm++; + } + guid = osm_node_get_node_guid(sw->p_node); + if (cl_qmap_get(m, guid) == cl_qmap_end(m)) + cl_qmap_insert(m, guid, &sw->mgrp_item); + } +} + +static void destroy_mgrp_switch_map(cl_qmap_t * m) +{ + osm_switch_t *sw=NULL; + cl_map_item_t *i; + + for (i = cl_qmap_head(m); i != cl_qmap_end(m); i = cl_qmap_next(i)) { + sw = cl_item_obj(i, sw, mgrp_item); + sw->num_of_mcm = 0; + sw->is_mc_member = 0; + } + cl_qmap_remove_all(m); +} + +/********************************************************************** + Calculate the maximal "min hops" from the given switch to any + of the group HCAs + **********************************************************************/ +#ifdef OSM_VENDOR_INTF_ANAFA +static float mcast_mgr_compute_avg_hops(osm_sm_t * sm, cl_qmap_t * m, + const osm_switch_t * this_sw) +{ + float avg_hops = 0; + uint32_t hops = 0; + uint32_t num_ports = 0; + uint16_t lid; + uint32_t least_hops; + cl_map_item_t *i; + osm_switch_t *sw; + + OSM_LOG_ENTER(sm->p_log); + + for (i = cl_qmap_head(m); i != cl_qmap_end(m); i = cl_qmap_next(i)) { + sw = cl_item_obj(i, sw, mcast_item); + lid = cl_ntoh16(osm_node_get_base_lid(sw->p_node, 0)); + least_hops = osm_switch_get_least_hops(this_sw, lid); + /* for all host that are MC members and attached to the switch, + we should add the (least_hops + 1) * number_of_such_hosts. + If switch itself is in the MC, we should add the least_hops only */ + hops += (least_hops + 1) * sw->num_of_mcm + + least_hops * sw->is_mc_member; + num_ports += sw->num_of_mcm + sw->is_mc_member; + } + + /* We shouldn't be here if there aren't any ports in the group. */ + CL_ASSERT(num_ports); + + avg_hops = (float)(hops / num_ports); + + OSM_LOG_EXIT(sm->p_log); + return avg_hops; +} +#else +static float mcast_mgr_compute_max_hops(osm_sm_t * sm, cl_qmap_t * m, + const osm_switch_t * this_sw) +{ + uint32_t max_hops = 0, hops; + uint16_t lid; + cl_map_item_t *i; + osm_switch_t *sw=NULL; + + OSM_LOG_ENTER(sm->p_log); + + /* + For each member of the multicast group, compute the + number of hops to its base LID. + */ + for (i = cl_qmap_head(m); i != cl_qmap_end(m); i = cl_qmap_next(i)) { + sw = cl_item_obj(i, sw, mgrp_item); + lid = cl_ntoh16(osm_node_get_base_lid(sw->p_node, 0)); + hops = osm_switch_get_least_hops(this_sw, lid); + if (!sw->is_mc_member) + hops += 1; + if (hops > max_hops) + max_hops = hops; + } + + /* Note that at this point we might get (max_hops == 0), + which means that there's only one member in the mcast + group, and it's the current switch */ + + OSM_LOG_EXIT(sm->p_log); + return (float)max_hops; +} +#endif + +/********************************************************************** + 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 *mcast_mgr_find_optimal_switch(osm_sm_t * sm, + cl_qlist_t * list) +{ + cl_qmap_t mgrp_sw_map; + cl_qmap_t *p_sw_tbl; + osm_switch_t *p_sw, *p_best_sw = NULL; + float hops = 0; + float best_hops = 10000; /* any big # will do */ + + OSM_LOG_ENTER(sm->p_log); + + p_sw_tbl = &sm->p_subn->sw_guid_tbl; + + create_mgrp_switch_map(&mgrp_sw_map, list); + 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; + +#ifdef OSM_VENDOR_INTF_ANAFA + hops = mcast_mgr_compute_avg_hops(sm, &mgrp_sw_map, p_sw); +#else + hops = mcast_mgr_compute_max_hops(sm, &mgrp_sw_map, p_sw); +#endif + + 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 " (%s), hops = %f\n", + cl_ntoh64(osm_node_get_node_guid(p_best_sw->p_node)), + p_best_sw->p_node->print_desc, best_hops); + else + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "No multicast capable switches detected\n"); + + destroy_mgrp_switch_map(&mgrp_sw_map); + OSM_LOG_EXIT(sm->p_log); + return p_best_sw; +} + +/********************************************************************** + This function returns the existing or optimal root switch for the tree. +**********************************************************************/ +static osm_switch_t *mcast_mgr_find_root_switch(osm_sm_t * sm, cl_qlist_t *list) +{ + 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 = mcast_mgr_find_optimal_switch(sm, list); + + OSM_LOG_EXIT(sm->p_log); + return p_sw; +} + +static int mcast_mgr_set_mft_block(osm_sm_t * sm, IN osm_switch_t * p_sw, + uint32_t block_num, uint32_t position) +{ + osm_node_t *p_node; + osm_dr_path_t *p_path; + osm_madw_context_t context; + ib_api_status_t status; + uint32_t block_id_ho; + osm_mcast_tbl_t *p_tbl; + ib_net16_t block[IB_MCAST_BLOCK_SIZE]; + int ret = 0; + + 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. + */ + + context.mft_context.node_guid = osm_node_get_node_guid(p_node); + context.mft_context.set_method = TRUE; + + p_tbl = osm_switch_get_mcast_tbl_ptr(p_sw); + + if (osm_mcast_tbl_get_block(p_tbl, (uint16_t) block_num, + (uint8_t) position, block)) { + block_id_ho = block_num + (position << 28); + + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Writing MFT block %u position %u to switch 0x%" PRIx64 + "\n", block_num, position, + cl_ntoh64(context.mft_context.node_guid)); + + 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, + &context); + if (status != IB_SUCCESS) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0A02: " + "Sending multicast fwd. tbl. block to %s failed (%s)\n", + p_node->print_desc, ib_get_err_str(status)); + ret = -1; + } + } + + OSM_LOG_EXIT(sm->p_log); + return ret; +} + +/********************************************************************** + This is part of 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. +**********************************************************************/ +static void mcast_mgr_subdivide(osm_sm_t * sm, uint16_t mlid_ho, + osm_switch_t * p_sw, cl_qlist_t * p_list, + cl_qlist_t * list_array, uint8_t array_size) +{ + uint8_t port_num; + boolean_t ignore_existing; + osm_mcast_work_obj_t *p_wobj; + + OSM_LOG_ENTER(sm->p_log); + + /* + For Multicast Groups, we don't want 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. + */ + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0A03: " + "Error routing MLID 0x%X through switch 0x%" + PRIx64 " %s\n" + "\t\t\t\tNo multicast paths from this switch " + "for port with LID %u\n", mlid_ho, + cl_ntoh64(osm_node_get_node_guid(p_sw->p_node)), + p_sw->p_node->print_desc, + cl_ntoh16(osm_port_get_base_lid + (p_wobj->p_port))); + mcast_work_obj_delete(p_wobj); + continue; + } + + if (port_num > array_size) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0A04: " + "Error routing MLID 0x%X through switch 0x%" + PRIx64 " %s\n" + "\t\t\t\tNo multicast paths from this switch " + "to port with LID %u\n", mlid_ho, + cl_ntoh64(osm_node_get_node_guid(p_sw->p_node)), + p_sw->p_node->print_desc, + cl_ntoh16(osm_port_get_base_lid + (p_wobj->p_port))); + 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 mcast_mgr_purge_list(osm_sm_t * sm, cl_qlist_t * list) +{ + if (osm_log_is_active(sm->p_log, OSM_LOG_ERROR)) { + osm_mcast_work_obj_t *wobj=NULL; + cl_list_item_t *i; + for (i = cl_qlist_head(list); i != cl_qlist_end(list); + i = cl_qlist_next(i)) { + wobj = cl_item_obj(i, wobj, list_item); + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0A06: " + "Unable to route for port 0x%" PRIx64 "\n", + osm_port_get_guid(wobj->p_port)); + } + } + drop_port_list(list); +} + +/********************************************************************** + 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 *mcast_mgr_branch(osm_sm_t * sm, uint16_t mlid_ho, + osm_switch_t * p_sw, + cl_qlist_t * p_list, uint8_t depth, + uint8_t upstream_port, + uint8_t * 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; + osm_mcast_work_obj_t *p_wobj; + cl_qlist_t *p_port_list; + size_t count; + 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); + + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "Routing MLID 0x%X through switch 0x%" PRIx64 + " %s, %u nodes at depth %u\n", + mlid_ho, cl_ntoh64(node_guid), p_sw->p_node->print_desc, + 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); + 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 " %s does not support multicast\n", + cl_ntoh64(node_guid), p_sw->p_node->print_desc); + + /* + Deallocate all the work objects on this branch of the tree. + */ + 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. + */ + 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"); + mcast_mgr_purge_list(sm, p_list); + osm_mtree_destroy(p_mtn); + p_mtn = NULL; + 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]); + + mcast_mgr_subdivide(sm, mlid_ho, 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 %u 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); + 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] = + mcast_mgr_branch(sm, mlid_ho, 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); + mcast_work_obj_delete(p_wobj); + } + } + + free(list_array); +Exit: + OSM_LOG_EXIT(sm->p_log); + return p_mtn; +} + +static ib_api_status_t mcast_mgr_build_spanning_tree(osm_sm_t * sm, + osm_mgrp_box_t * mbox) +{ + cl_qlist_t port_list; + uint32_t num_ports; + osm_switch_t *p_sw; + ib_api_status_t status = IB_SUCCESS; + uint8_t max_depth = 0; + + OSM_LOG_ENTER(sm->p_log); + + /* + 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. + */ + mcast_mgr_purge_tree(sm, mbox); + + /* build the first "subset" containing all member ports */ + if (make_port_list(&port_list, mbox)) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0A10: " + "Insufficient memory to make port list\n"); + status = IB_ERROR; + goto Exit; + } + + num_ports = cl_qlist_count(&port_list); + if (num_ports == 0) { + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "MLID 0x%X has no members - nothing to do\n", + mbox->mlid); + 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 = mcast_mgr_find_root_switch(sm, &port_list); + 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", + mbox->mlid); + drop_port_list(&port_list); + status = IB_ERROR; + goto Exit; + } + + mbox->root = mcast_mgr_branch(sm, mbox->mlid, 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", + mbox->mlid, num_ports, 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 * p_mgrp, + IN const osm_mtree_node_t * 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 mcast_mgr_clear(osm_sm_t * sm, uint16_t mlid) +{ + 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, 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 + +/********************************************************************** + Process the entire group. + NOTE : The lock should be held externally! + **********************************************************************/ +static ib_api_status_t mcast_mgr_process_mlid(osm_sm_t * sm, uint16_t mlid) +{ + ib_api_status_t status = IB_SUCCESS; + osm_mgrp_box_t *mbox; + + OSM_LOG_ENTER(sm->p_log); + + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Processing multicast group with lid 0x%X\n", mlid); + + /* Clear the multicast tables to start clean, then build + the spanning tree which sets the mcast table bits for each + port in the group. */ + mcast_mgr_clear(sm, mlid); + + mbox = osm_get_mbox_by_mlid(sm->p_subn, cl_hton16(mlid)); + if (mbox) { + status = mcast_mgr_build_spanning_tree(sm, mbox); + if (status != IB_SUCCESS) + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0A17: " + "Unable to create spanning tree (%s) for mlid " + "0x%x\n", ib_get_err_str(status), mlid); + } + + OSM_LOG_EXIT(sm->p_log); + return status; +} + +static int mcast_mgr_set_mftables(osm_sm_t * sm) +{ + cl_qmap_t *p_sw_tbl = &sm->p_subn->sw_guid_tbl; + osm_switch_t *p_sw; + osm_mcast_tbl_t *p_tbl; + int block_notdone, ret = 0; + int16_t block_num, max_block = -1; + + p_sw = (osm_switch_t *) cl_qmap_head(p_sw_tbl); + while (p_sw != (osm_switch_t *) cl_qmap_end(p_sw_tbl)) { + p_sw->mft_block_num = 0; + p_sw->mft_position = 0; + p_tbl = osm_switch_get_mcast_tbl_ptr(p_sw); + if (osm_mcast_tbl_get_max_block_in_use(p_tbl) > max_block) + max_block = osm_mcast_tbl_get_max_block_in_use(p_tbl); + p_sw = (osm_switch_t *) cl_qmap_next(&p_sw->map_item); + } + + /* Stripe the MFT blocks across the switches */ + for (block_num = 0; block_num <= max_block; block_num++) { + block_notdone = 1; + while (block_notdone) { + block_notdone = 0; + p_sw = (osm_switch_t *) cl_qmap_head(p_sw_tbl); + while (p_sw != (osm_switch_t *) cl_qmap_end(p_sw_tbl)) { + if (p_sw->mft_block_num == block_num) { + block_notdone = 1; + if (mcast_mgr_set_mft_block(sm, p_sw, + p_sw->mft_block_num, + p_sw->mft_position)) + ret = -1; + p_tbl = osm_switch_get_mcast_tbl_ptr(p_sw); + if (++p_sw->mft_position > p_tbl->max_position) { + p_sw->mft_position = 0; + p_sw->mft_block_num++; + } + } + p_sw = (osm_switch_t *) cl_qmap_next(&p_sw->map_item); + } + } + } + + return ret; +} + +static int alloc_mfts(osm_sm_t * sm) +{ + int i; + cl_map_item_t *item; + osm_switch_t *p_sw; + + for (i = sm->p_subn->max_mcast_lid_ho - IB_LID_MCAST_START_HO; i >= 0; + i--) + if (sm->p_subn->mboxes[i]) + break; + if (i < 0) + return 0; + + /* Now, walk switches and (re)allocate multicast tables */ + for (item = cl_qmap_head(&sm->p_subn->sw_guid_tbl); + item != cl_qmap_end(&sm->p_subn->sw_guid_tbl); + item = cl_qmap_next(item)) { + p_sw = (osm_switch_t *) item; + if (osm_mcast_tbl_realloc(&p_sw->mcast_tbl, i)) + return -1; + } + return 0; +} + +int osm_mcast_mgr_process(osm_sm_t * sm) +{ + int i, ret = 0; + + OSM_LOG_ENTER(sm->p_log); + + /* 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); + + /* If there are no switches in the subnet 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; + } + + if (alloc_mfts(sm)) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, + "ERR 0A07: alloc_mfts failed\n"); + ret = -1; + goto exit; + } + + for (i = 0; i <= sm->p_subn->max_mcast_lid_ho - IB_LID_MCAST_START_HO; + i++) + if (sm->p_subn->mboxes[i] || sm->mlids_req[i]) + mcast_mgr_process_mlid(sm, i + IB_LID_MCAST_START_HO); + + memset(sm->mlids_req, 0, sm->mlids_req_max); + sm->mlids_req_max = 0; + + ret = mcast_mgr_set_mftables(sm); + +exit: + CL_PLOCK_RELEASE(sm->p_lock); + + OSM_LOG_EXIT(sm->p_log); + + return ret; +} + +/********************************************************************** + This is the function that is invoked during idle time to handle the + process request for mcast groups where join/leave/delete was required. + **********************************************************************/ +int osm_mcast_mgr_process_mgroups(osm_sm_t * sm) +{ + int ret = 0; + unsigned i; + + OSM_LOG_ENTER(sm->p_log); + + CL_PLOCK_EXCL_ACQUIRE(sm->p_lock); + + /* If there are no switches in the subnet 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; + } + + if (alloc_mfts(sm)) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, + "ERR 0A09: alloc_mfts failed\n"); + ret = -1; + goto exit; + } + + for (i = 0; i <= sm->mlids_req_max; i++) { + if (!sm->mlids_req[i]) + continue; + sm->mlids_req[i] = 0; + mcast_mgr_process_mlid(sm, i + IB_LID_MCAST_START_HO); + } + + memset(sm->mlids_req, 0, sm->mlids_req_max); + sm->mlids_req_max = 0; + + ret = mcast_mgr_set_mftables(sm); + + osm_dump_mcast_routes(sm->p_subn->p_osm); + +exit: + CL_PLOCK_RELEASE(sm->p_lock); + OSM_LOG_EXIT(sm->p_log); + return ret; +} diff --git a/branches/WOF2-3/ulp/opensm/user/opensm/osm_mcast_tbl.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_mcast_tbl.c new file mode 100644 index 00000000..0121c58b --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_mcast_tbl.c @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2009 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Copyright (c) 2009 HNR Consulting. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_mcast_tbl_t. + * This object represents a multicast forwarding table. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include + +void osm_mcast_tbl_init(IN osm_mcast_tbl_t * p_tbl, IN uint8_t num_ports, + IN uint16_t 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; + } + + 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); +} + +void osm_mcast_tbl_destroy(IN osm_mcast_tbl_t * p_tbl) +{ + free(p_tbl->p_mask_tbl); +} + +void osm_mcast_tbl_set(IN osm_mcast_tbl_t * p_tbl, IN uint16_t mlid_ho, + IN uint8_t port) +{ + unsigned mlid_offset, mask_offset, bit_mask; + int16_t block_num; + + CL_ASSERT(p_tbl && 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; + 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; +} + +int osm_mcast_tbl_realloc(IN osm_mcast_tbl_t * p_tbl, IN unsigned mlid_offset) +{ + size_t mft_depth, size; + uint16_t (*p_mask_tbl)[][IB_MCAST_POSITION_MAX + 1]; + + if (mlid_offset < p_tbl->mft_depth) + goto done; + + /* + 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. + */ + mft_depth = (mlid_offset / IB_MCAST_BLOCK_SIZE + 1) * IB_MCAST_BLOCK_SIZE; + size = mft_depth * (IB_MCAST_POSITION_MAX + 1) * IB_MCAST_MASK_SIZE / 8; + p_mask_tbl = realloc(p_tbl->p_mask_tbl, size); + if (!p_mask_tbl) + return -1; + memset((uint8_t *)p_mask_tbl + p_tbl->mft_depth * (IB_MCAST_POSITION_MAX + 1) * IB_MCAST_MASK_SIZE / 8, + 0, + size - p_tbl->mft_depth * (IB_MCAST_POSITION_MAX + 1) * IB_MCAST_MASK_SIZE / 8); + p_tbl->p_mask_tbl = p_mask_tbl; + p_tbl->mft_depth = mft_depth; +done: + p_tbl->max_mlid_ho = mlid_offset + IB_LID_MCAST_START_HO; + return 0; +} + +boolean_t osm_mcast_tbl_is_port(IN const osm_mcast_tbl_t * p_tbl, + IN uint16_t mlid_ho, IN uint8_t port_num) +{ + unsigned mlid_offset, mask_offset, 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 * p_tbl, + IN uint16_t mlid_ho) +{ + unsigned 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 * p_tbl, + IN const ib_net16_t * p_block, + IN int16_t block_num, + IN 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->mft_depth) + 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 * p_tbl, IN uint16_t mlid_ho) +{ + unsigned mlid_offset; + + CL_ASSERT(p_tbl); + CL_ASSERT(mlid_ho >= IB_LID_MCAST_START_HO); + + mlid_offset = mlid_ho - IB_LID_MCAST_START_HO; + if (p_tbl->p_mask_tbl && mlid_offset < p_tbl->mft_depth) + memset((uint8_t *)p_tbl->p_mask_tbl + mlid_offset * (IB_MCAST_POSITION_MAX + 1) * IB_MCAST_MASK_SIZE / 8, + 0, + (IB_MCAST_POSITION_MAX + 1) * IB_MCAST_MASK_SIZE / 8); +} + +boolean_t osm_mcast_tbl_get_block(IN osm_mcast_tbl_t * p_tbl, + IN int16_t block_num, IN uint8_t position, + OUT ib_net16_t * p_block) +{ + uint32_t i; + uint16_t mlid_start_ho; + + CL_ASSERT(p_tbl); + CL_ASSERT(p_block); + CL_ASSERT(block_num * IB_MCAST_BLOCK_SIZE <= p_tbl->mft_depth); + + 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); + + 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/branches/WOF2-3/ulp/opensm/user/opensm/osm_mcm_port.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_mcm_port.c new file mode 100644 index 00000000..17a6117d --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_mcm_port.c @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_mcm_port_t. + * This object represents the membership of a port in a multicast group. + * This object is part of the OpenSM family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include + +osm_mcm_port_t *osm_mcm_port_new(IN osm_port_t *port, IN osm_mgrp_t *mgrp, + IN ib_member_rec_t *mcmr, IN boolean_t proxy) +{ + 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 = port; + p_mcm->mgrp = mgrp; + p_mcm->port_gid = mcmr->port_gid; + p_mcm->scope_state = mcmr->scope_state; + p_mcm->proxy_join = proxy; + } + + return p_mcm; +} + +void osm_mcm_port_delete(IN osm_mcm_port_t * p_mcm) +{ + CL_ASSERT(p_mcm); + free(p_mcm); +} diff --git a/branches/WOF2-3/ulp/opensm/user/opensm/osm_mesh.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_mesh.c new file mode 100644 index 00000000..662c6090 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_mesh.c @@ -0,0 +1,1735 @@ +/* + * Copyright (c) 2008-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2008,2009 System Fabric Works, 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: + * routines to analyze certain meshes + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include + +#define MAX_DEGREE (8) +#define MAX_DIMENSION (8) +#define LARGE (0x7fffffff) + +/* + * characteristic polynomials for selected 1d through 8d tori + */ +static const struct mesh_info { + int dimension; /* dimension of the torus */ + int size[MAX_DIMENSION]; /* size of the torus */ + unsigned int degree; /* degree of polynomial */ + int poly[MAX_DEGREE+1]; /* polynomial */ +} mesh_info[] = { + {0, {0}, 0, {0}, }, + + {1, {2}, 1, {0, -1}, }, + {1, {3}, 2, {-1, 0, 1}, }, + {1, {5}, 2, {-9, 0, 1}, }, + {1, {6}, 2, {-36, 0, 1}, }, + + {2, {2, 2}, 2, {-4, 0, 1}, }, + {2, {3, 2}, 3, {8, 9, 0, -1}, }, + {2, {5, 2}, 3, {24, 17, 0, -1}, }, + {2, {6, 2}, 3, {32, 24, 0, -1}, }, + {2, {3, 3}, 4, {-15, -32, -18, 0, 1}, }, + {2, {5, 3}, 4, {-39, -64, -26, 0, 1}, }, + {2, {6, 3}, 4, {-48, -80, -33, 0, 1}, }, + {2, {5, 5}, 4, {-63, -96, -34, 0, 1}, }, + {2, {6, 5}, 4, {-48, -112, -41, 0, 1}, }, + {2, {6, 6}, 4, {0, -128, -48, 0, 1}, }, + + {3, {2, 2, 2}, 3, {16, 12, 0, -1}, }, + {3, {3, 2, 2}, 4, {-28, -48, -21, 0, 1}, }, + {3, {5, 2, 2}, 4, {-60, -80, -29, 0, 1}, }, + {3, {6, 2, 2}, 4, {-64, -96, -36, 0, 1}, }, + {3, {3, 3, 2}, 5, {48, 127, 112, 34, 0, -1}, }, + {3, {5, 3, 2}, 5, {96, 215, 160, 42, 0, -1}, }, + {3, {6, 3, 2}, 5, {96, 232, 184, 49, 0, -1}, }, + {3, {5, 5, 2}, 5, {144, 303, 208, 50, 0, -1}, }, + {3, {6, 5, 2}, 5, {96, 296, 232, 57, 0, -1}, }, + {3, {6, 6, 2}, 5, {0, 256, 256, 64, 0, -1}, }, + {3, {3, 3, 3}, 6, {-81, -288, -381, -224, -51, 0, 1}, }, + {3, {5, 3, 3}, 6, {-153, -480, -557, -288, -59, 0, 1}, }, + {3, {6, 3, 3}, 6, {-144, -480, -591, -320, -66, 0, 1}, }, + {3, {5, 5, 3}, 6, {-225, -672, -733, -352, -67, 0, 1}, }, + {3, {6, 5, 3}, 6, {-144, -576, -743, -384, -74, 0, 1}, }, + {3, {6, 6, 3}, 6, {0, -384, -720, -416, -81, 0, 1}, }, + {3, {5, 5, 5}, 6, {-297, -864, -909, -416, -75, 0, 1}, }, + {3, {6, 5, 5}, 6, {-144, -672, -895, -448, -82, 0, 1}, }, + {3, {6, 6, 5}, 6, {0, -384, -848, -480, -89, 0, 1}, }, + {3, {6, 6, 6}, 6, {0, 0, -768, -512, -96, 0, 1}, }, + + {4, {2, 2, 2, 2}, 4, {-48, -64, -24, 0, 1}, }, + {4, {3, 2, 2, 2}, 5, {80, 180, 136, 37, 0, -1}, }, + {4, {5, 2, 2, 2}, 5, {144, 276, 184, 45, 0, -1}, }, + {4, {6, 2, 2, 2}, 5, {128, 288, 208, 52, 0, -1}, }, + {4, {3, 3, 2, 2}, 6, {-132, -416, -487, -256, -54, 0, 1}, }, + {4, {5, 3, 2, 2}, 6, {-228, -640, -671, -320, -62, 0, 1}, }, + {4, {6, 3, 2, 2}, 6, {-192, -608, -700, -352, -69, 0, 1}, }, + {4, {5, 5, 2, 2}, 6, {-324, -864, -855, -384, -70, 0, 1}, }, + {4, {6, 5, 2, 2}, 6, {-192, -736, -860, -416, -77, 0, 1}, }, + {4, {6, 6, 2, 2}, 6, {0, -512, -832, -448, -84, 0, 1}, }, + {4, {3, 3, 3, 2}, 7, {216, 873, 1392, 1101, 440, 75, 0, -1}, }, + {4, {5, 3, 3, 2}, 7, {360, 1329, 1936, 1405, 520, 83, 0, -1}, }, + {4, {6, 3, 3, 2}, 7, {288, 1176, 1872, 1455, 560, 90, 0, -1}, }, + {4, {5, 5, 3, 2}, 7, {504, 1785, 2480, 1709, 600, 91, 0, -1}, }, + {4, {6, 5, 3, 2}, 7, {288, 1368, 2272, 1735, 640, 98, 0, -1}, }, + {4, {6, 6, 3, 2}, 7, {0, 768, 1920, 1728, 680, 105, 0, -1}, }, + {4, {5, 5, 5, 2}, 7, {648, 2241, 3024, 2013, 680, 99, 0, -1}, }, + {4, {6, 5, 5, 2}, 7, {288, 1560, 2672, 2015, 720, 106, 0, -1}, }, + {4, {6, 6, 5, 2}, 7, {0, 768, 2176, 1984, 760, 113, 0, -1}, }, + {4, {6, 6, 6, 2}, 7, {0, 0, 1536, 1920, 800, 120, 0, -1}, }, + {4, {3, 3, 3, 3}, 8, {-351, -1728, -3492, -3712, -2202, -704, -100, 0, 1}, }, + {4, {5, 3, 3, 3}, 8, {-567, -2592, -4860, -4800, -2658, -800, -108, 0, 1}, }, + {4, {6, 3, 3, 3}, 8, {-432, -2160, -4401, -4672, -2733, -848, -115, 0, 1}, }, + {4, {5, 5, 3, 3}, 8, {-783, -3456, -6228, -5888, -3114, -896, -116, 0, 1}, }, + {4, {6, 5, 3, 3}, 8, {-432, -2448, -5241, -5568, -3165, -944, -123, 0, 1}, }, + {4, {6, 6, 3, 3}, 8, {0, -1152, -3888, -5056, -3183, -992, -130, 0, 1}, }, + {4, {5, 5, 5, 3}, 8, {-999, -4320, -7596, -6976, -3570, -992, -124, 0, 1}, }, + {4, {6, 5, 5, 3}, 8, {-432, -2736, -6081, -6464, -3597, -1040, -131, 0, 1}, }, + {4, {6, 6, 5, 3}, 8, {0, -1152, -4272, -5760, -3591, -1088, -138, 0, 1}, }, + {4, {6, 6, 6, 3}, 8, {0, 0, -2304, -4864, -3552, -1136, -145, 0, 1}, }, + + {5, {2, 2, 2, 2, 2}, 5, {128, 240, 160, 40, 0, -1}, }, + {5, {3, 2, 2, 2, 2}, 6, {-208, -576, -600, -288, -57, 0, 1}, }, + {5, {5, 2, 2, 2, 2}, 6, {-336, -832, -792, -352, -65, 0, 1}, }, + {5, {6, 2, 2, 2, 2}, 6, {-256, -768, -816, -384, -72, 0, 1}, }, + {5, {3, 3, 2, 2, 2}, 7, {336, 1228, 1776, 1287, 480, 78, 0, -1}, }, + {5, {5, 3, 2, 2, 2}, 7, {528, 1772, 2368, 1599, 560, 86, 0, -1}, }, + {5, {6, 3, 2, 2, 2}, 7, {384, 1504, 2256, 1644, 600, 93, 0, -1}, }, + {5, {5, 5, 2, 2, 2}, 7, {720, 2316, 2960, 1911, 640, 94, 0, -1}, }, + {5, {6, 5, 2, 2, 2}, 7, {384, 1760, 2704, 1932, 680, 101, 0, -1}, }, + {5, {6, 6, 2, 2, 2}, 7, {0, 1024, 2304, 1920, 720, 108, 0, -1}, }, + {5, {3, 3, 3, 2, 2}, 8, {-540, -2448, -4557, -4480, -2481, -752, -103, 0, 1}, }, + {5, {5, 3, 3, 2, 2}, 8, {-828, -3504, -6101, -5632, -2945, -848, -111, 0, 1}, }, + {5, {6, 3, 3, 2, 2}, 8, {-576, -2784, -5412, -5440, -3015, -896, -118, 0, 1}, }, + {5, {5, 5, 3, 2, 2}, 8, {-1116, -4560, -7645, -6784, -3409, -944, -119, 0, 1}, }, + {5, {6, 5, 3, 2, 2}, 8, {-576, -3168, -6404, -6400, -3455, -992, -126, 0, 1}, }, + {5, {6, 6, 3, 2, 2}, 8, {0, -1536, -4800, -5824, -3468, -1040, -133, 0, 1}, }, + {5, {5, 5, 5, 2, 2}, 8, {-1404, -5616, -9189, -7936, -3873, -1040, -127, 0, 1}, }, + {5, {6, 5, 5, 2, 2}, 8, {-576, -3552, -7396, -7360, -3895, -1088, -134, 0, 1}, }, + {5, {6, 6, 5, 2, 2}, 8, {0, -1536, -5312, -6592, -3884, -1136, -141, 0, 1}, }, + {5, {6, 6, 6, 2, 2}, 8, {0, 0, -3072, -5632, -3840, -1184, -148, 0, 1}, }, + + {6, {2, 2, 2, 2, 2, 2}, 6, {-320, -768, -720, -320, -60, 0, 1}, }, + {6, {3, 2, 2, 2, 2, 2}, 7, {512, 1680, 2208, 1480, 520, 81, 0, -1}, }, + {6, {5, 2, 2, 2, 2, 2}, 7, {768, 2320, 2848, 1800, 600, 89, 0, -1}, }, + {6, {6, 2, 2, 2, 2, 2}, 7, {512, 1920, 2688, 1840, 640, 96, 0, -1}, }, + {6, {3, 3, 2, 2, 2, 2}, 8, {-816, -3392, -5816, -5312, -2767, -800, -106, 0, 1}, }, + {6, {5, 3, 2, 2, 2, 2}, 8, {-1200, -4672, -7544, -6528, -3239, -896, -114, 0, 1}, }, + {6, {6, 3, 2, 2, 2, 2}, 8, {-768, -3584, -6608, -6272, -3304, -944, -121, 0, 1}, }, + {6, {5, 5, 2, 2, 2, 2}, 8, {-1584, -5952, -9272, -7744, -3711, -992, -122, 0, 1}, }, + {6, {6, 5, 2, 2, 2, 2}, 8, {-768, -4096, -7760, -7296, -3752, -1040, -129, 0, 1}, }, + {6, {6, 6, 2, 2, 2, 2}, 8, {0, -2048, -5888, -6656, -3760, -1088, -136, 0, 1}, }, + + {7, {2, 2, 2, 2, 2, 2, 2}, 7, {768, 2240, 2688, 1680, 560, 84, 0, -1}, }, + {7, {3, 2, 2, 2, 2, 2, 2}, 8, {-1216, -4608, -7280, -6208, -3060, -848, -109, 0, 1}, }, + {7, {5, 2, 2, 2, 2, 2, 2}, 8, {-1728, -6144, -9200, -7488, -3540, -944, -117, 0, 1}, }, + {7, {6, 2, 2, 2, 2, 2, 2}, 8, {-1024, -4608, -8000, -7168, -3600, -992, -124, 0, 1}, }, + + {8, {2, 2, 2, 2, 2, 2, 2, 2}, 8, {-1792, -6144, -8960, -7168, -3360, -896, -112, 0, 1}, }, + + /* + * mesh errors + */ + {2, {6, 6}, 4, {-192, -256, -80, 0, 1}, }, + + {-1, {0,}, 0, {0, }, }, +}; + +/* + * per fabric mesh info + */ +typedef struct _mesh { + int num_class; /* number of switch classes */ + int *class_type; /* index of first switch found for each class */ + int *class_count; /* population of each class */ + int dimension; /* mesh dimension */ + int *size; /* an array to hold size of mesh */ + int dim_order[MAX_DIMENSION]; +} mesh_t; + +typedef struct sort_ctx { + lash_t *p_lash; + mesh_t *mesh; +} sort_ctx_t; + +typedef struct comp { + int index; + sort_ctx_t ctx; +} comp_t; + +/* + * poly_alloc + * + * allocate a polynomial of degree n + */ +static int *poly_alloc(lash_t *p_lash, int n) +{ + osm_log_t *p_log = &p_lash->p_osm->log; + int *p; + + if (!(p = calloc(n+1, sizeof(int)))) + OSM_LOG(p_log, OSM_LOG_ERROR, + "Failed allocating poly - out of memory\n"); + + return p; +} + +/* + * print a polynomial + */ +static char *poly_print(int n, int *coeff) +{ + static char str[(MAX_DEGREE+1)*20]; + char *p = str; + int i; + int first = 1; + int t; + int sign; + + str[0] = 0; + + for (i = 0; i <= n; i++) { + if (!coeff[i]) + continue; + + if (coeff[i] < 0) { + sign = 1; + t = -coeff[i]; + } else { + sign = 0; + t = coeff[i]; + } + + p += sprintf(p, "%s", sign? "-" : (first? "" : "+")); + first = 0; + + if (t != 1 || i == 0) + p += sprintf(p, "%d", t); + + if (i) + p += sprintf(p, "x"); + if (i > 1) + p += sprintf(p, "^%d", i); + } + + return str; +} + +/* + * poly_diff + * + * return a nonzero value if polynomials differ else 0 + */ +static int poly_diff(unsigned int n, const int *p, switch_t *s) +{ + if (s->node->num_links != n) + return 1; + + return memcmp(p, s->node->poly, n*sizeof(int)); +} + +/* + * m_free + * + * free a square matrix of rank l + */ +static void m_free(int **m, int l) +{ + int i; + + if (m) { + for (i = 0; i < l; i++) { + if (m[i]) + free(m[i]); + } + free(m); + } +} + +/* + * m_alloc + * + * allocate a square matrix of rank l + */ +static int **m_alloc(lash_t *p_lash, int l) +{ + osm_log_t *p_log = &p_lash->p_osm->log; + int i; + int **m = NULL; + + do { + if (!(m = calloc(l, sizeof(int *)))) + break; + + for (i = 0; i < l; i++) { + if (!(m[i] = calloc(l, sizeof(int)))) + break; + } + if (i != l) + break; + + return m; + } while (0); + + OSM_LOG(p_log, OSM_LOG_ERROR, + "Failed allocating matrix - out of memory\n"); + + m_free(m, l); + return NULL; +} + +/* + * pm_free + * + * free a square matrix of rank l of polynomials + */ +static void pm_free(int ***m, int l) +{ + int i, j; + + if (m) { + for (i = 0; i < l; i++) { + if (m[i]) { + for (j = 0; j < l; j++) { + if (m[i][j]) + free(m[i][j]); + } + free(m[i]); + } + } + free(m); + } +} + +/* + * pm_alloc + * + * allocate a square matrix of rank l of polynomials of degree n + */ +static int ***pm_alloc(lash_t *p_lash, int l, int n) +{ + osm_log_t *p_log = &p_lash->p_osm->log; + int i, j; + int ***m = NULL; + + do { + if (!(m = calloc(l, sizeof(int **)))) + break; + + for (i = 0; i < l; i++) { + if (!(m[i] = calloc(l, sizeof(int *)))) + break; + + for (j = 0; j < l; j++) { + if (!(m[i][j] = calloc(n+1, sizeof(int)))) + break; + } + if (j != l) + break; + } + if (i != l) + break; + + return m; + } while (0); + + OSM_LOG(p_log, OSM_LOG_ERROR, + "Failed allocating matrix - out of memory\n"); + + pm_free(m, l); + return NULL; +} + +static int determinant(lash_t *p_lash, int n, int rank, int ***m, int *p); + +/* + * sub_determinant + * + * compute the determinant of a submatrix of matrix of rank l of polynomials of degree n + * with row and col removed in poly. caller must free poly + */ +static int sub_determinant(lash_t *p_lash, int n, int l, int row, int col, + int ***matrix, int **poly) +{ + int ret = -1; + int ***m = NULL; + int *p = NULL; + int i, j, k, x, y; + int rank = l - 1; + + do { + if (!(p = poly_alloc(p_lash, n))) { + break; + } + + if (rank <= 0) { + p[0] = 1; + ret = 0; + break; + } + + if (!(m = pm_alloc(p_lash, rank, n))) { + free(p); + p = NULL; + break; + } + + x = 0; + for (i = 0; i < l; i++) { + if (i == row) + continue; + + y = 0; + for (j = 0; j < l; j++) { + if (j == col) + continue; + + for (k = 0; k <= n; k++) + m[x][y][k] = matrix[i][j][k]; + + y++; + } + x++; + } + + if (determinant(p_lash, n, rank, m, p)) { + free(p); + p = NULL; + break; + } + + ret = 0; + } while (0); + + pm_free(m, rank); + *poly = p; + return ret; +} + +/* + * determinant + * + * compute the determinant of matrix m of rank of polynomials of degree deg + * and add the result to polynomial p allocated by caller + */ +static int determinant(lash_t *p_lash, int deg, int rank, int ***m, int *p) +{ + int i, j, k; + int *q; + int sign = 1; + + /* + * handle simple case of 1x1 matrix + */ + if (rank == 1) { + for (i = 0; i <= deg; i++) + p[i] += m[0][0][i]; + } + + /* + * handle simple case of 2x2 matrix + */ + else if (rank == 2) { + for (i = 0; i <= deg; i++) { + if (m[0][0][i] == 0) + continue; + + for (j = 0; j <= deg; j++) { + if (m[1][1][j] == 0) + continue; + + p[i+j] += m[0][0][i]*m[1][1][j]; + } + } + + for (i = 0; i <= deg; i++) { + if (m[0][1][i] == 0) + continue; + + for (j = 0; j <= deg; j++) { + if (m[1][0][j] == 0) + continue; + + p[i+j] -= m[0][1][i]*m[1][0][j]; + } + } + } + + /* + * handle the general case + */ + else { + for (i = 0; i < rank; i++) { + if (sub_determinant(p_lash, deg, rank, 0, i, m, &q)) + return -1; + + for (j = 0; j <= deg; j++) { + if (m[0][i][j] == 0) + continue; + + for (k = 0; k <= deg; k++) { + if (q[k] == 0) + continue; + + p[j+k] += sign*m[0][i][j]*q[k]; + } + } + + free(q); + sign = -sign; + } + } + + return 0; +} + +/* + * char_poly + * + * compute the characteristic polynomial of matrix of rank + * by computing the determinant of m-x*I and return in poly + * as an array. caller must free poly + */ +static int char_poly(lash_t *p_lash, int rank, int **matrix, int **poly) +{ + osm_log_t *p_log = &p_lash->p_osm->log; + int ret = -1; + int i, j; + int ***m = NULL; + int *p = NULL; + int deg = rank; + + OSM_LOG_ENTER(p_log); + + do { + if (!matrix) + break; + + if (!(p = poly_alloc(p_lash, deg))) + break; + + if (!(m = pm_alloc(p_lash, rank, deg))) { + free(p); + p = NULL; + break; + } + + for (i = 0; i < rank; i++) { + for (j = 0; j < rank; j++) { + m[i][j][0] = matrix[i][j]; + } + m[i][i][1] = -1; + } + + if (determinant(p_lash, deg, rank, m, p)) { + free(p); + p = NULL; + break; + } + + ret = 0; + } while (0); + + pm_free(m, rank); + *poly = p; + + OSM_LOG_EXIT(p_log); + return ret; +} + +/* + * get_switch_metric + * + * compute the matrix of minimum distances between each of + * the adjacent switch nodes to sw along paths + * that do not go through sw. do calculation by + * relaxation method + * allocate space for the matrix and save in node_t structure + */ +static int get_switch_metric(lash_t *p_lash, int sw) +{ + osm_log_t *p_log = &p_lash->p_osm->log; + int ret = -1; + unsigned int i, j, change; + int sw1, sw2, sw3; + switch_t *s = p_lash->switches[sw]; + switch_t *s1, *s2, *s3; + int **m; + mesh_node_t *node = s->node; + unsigned int num_links = node->num_links; + + OSM_LOG_ENTER(p_log); + + do { + if (!(m = m_alloc(p_lash, num_links))) + break; + + for (i = 0; i < num_links; i++) { + sw1 = node->links[i]->switch_id; + s1 = p_lash->switches[sw1]; + + /* make all distances big except s1 to itself */ + for (sw2 = 0; sw2 < p_lash->num_switches; sw2++) + p_lash->switches[sw2]->node->temp = LARGE; + + s1->node->temp = 0; + + do { + change = 0; + + for (sw2 = 0; sw2 < p_lash->num_switches; sw2++) { + s2 = p_lash->switches[sw2]; + if (s2->node->temp == LARGE) + continue; + for (j = 0; j < s2->node->num_links; j++) { + sw3 = s2->node->links[j]->switch_id; + s3 = p_lash->switches[sw3]; + + if (sw3 == sw) + continue; + + if ((s2->node->temp + 1) < s3->node->temp) { + s3->node->temp = s2->node->temp + 1; + change++; + } + } + } + } while (change); + + for (j = 0; j < num_links; j++) { + sw2 = node->links[j]->switch_id; + s2 = p_lash->switches[sw2]; + m[i][j] = s2->node->temp; + } + } + + if (char_poly(p_lash, num_links, m, &node->poly)) { + m_free(m, num_links); + m = NULL; + break; + } + + ret = 0; + } while (0); + + node->matrix = m; + + OSM_LOG_EXIT(p_log); + return ret; +} + +/* + * classify_switch + * + * add switch to histogram of switch types + * we keep a reference to the first switch + * found of each type as an exemplar + */ +static void classify_switch(lash_t *p_lash, mesh_t *mesh, int sw) +{ + osm_log_t *p_log = &p_lash->p_osm->log; + int i; + switch_t *s = p_lash->switches[sw]; + switch_t *s1; + + OSM_LOG_ENTER(p_log); + + if (!s->node->poly) + goto done; + + for (i = 0; i < mesh->num_class; i++) { + s1 = p_lash->switches[mesh->class_type[i]]; + + if (poly_diff(s->node->num_links, s->node->poly, s1)) + continue; + + mesh->class_count[i]++; + goto done; + } + + mesh->class_type[mesh->num_class] = sw; + mesh->class_count[mesh->num_class] = 1; + mesh->num_class++; + +done: + OSM_LOG_EXIT(p_log); +} + +/* + * classify_mesh_type + * + * try to look up node polynomial in table + */ +static void classify_mesh_type(lash_t *p_lash, int sw) +{ + osm_log_t *p_log = &p_lash->p_osm->log; + int i; + switch_t *s = p_lash->switches[sw]; + const struct mesh_info *t; + + OSM_LOG_ENTER(p_log); + + if (!s->node->poly) + goto done; + + for (i = 1; (t = &mesh_info[i])->dimension != -1; i++) { + if (poly_diff(t->degree, t->poly, s)) + continue; + + s->node->type = i; + s->node->dimension = t->dimension; + OSM_LOG_EXIT(p_log); + return; + } + +done: + s->node->type = 0; + OSM_LOG_EXIT(p_log); + return; +} + +/* + * remove_edges + * + * remove type from nodes that have fewer links + * than adjacent nodes + */ +static void remove_edges(lash_t *p_lash) +{ + osm_log_t *p_log = &p_lash->p_osm->log; + int sw; + mesh_node_t *n, *nn; + unsigned i; + + OSM_LOG_ENTER(p_log); + + for (sw = 0; sw < p_lash->num_switches; sw++) { + n = p_lash->switches[sw]->node; + if (!n->type) + continue; + + for (i = 0; i < n->num_links; i++) { + nn = p_lash->switches[n->links[i]->switch_id]->node; + + if (nn->num_links > n->num_links) { + OSM_LOG(p_log, OSM_LOG_DEBUG, + "removed edge switch %s\n", + p_lash->switches[sw]->p_sw->p_node->print_desc); + n->type = -1; + break; + } + } + } + + OSM_LOG_EXIT(p_log); +} + +/* + * get_local_geometry + * + * analyze the local geometry around each switch + */ +static int get_local_geometry(lash_t *p_lash, mesh_t *mesh) +{ + osm_log_t *p_log = &p_lash->p_osm->log; + int sw; + int status = 0; + + OSM_LOG_ENTER(p_log); + + for (sw = 0; sw < p_lash->num_switches; sw++) { + /* + * skip switches with more links than MAX_DEGREE + * since they will never match a known case + */ + if (p_lash->switches[sw]->node->num_links > MAX_DEGREE) + continue; + + if (get_switch_metric(p_lash, sw)) { + status = -1; + goto Exit; + } + classify_mesh_type(p_lash, sw); + } + + remove_edges(p_lash); + + for (sw = 0; sw < p_lash->num_switches; sw++) { + if (p_lash->switches[sw]->node->type < 0) + continue; + classify_switch(p_lash, mesh, sw); + } + +Exit: + OSM_LOG_EXIT(p_log); + return status; +} + +static void print_axis(lash_t *p_lash, char *p, int sw, int port) +{ + mesh_node_t *node = p_lash->switches[sw]->node; + char *name = p_lash->switches[sw]->p_sw->p_node->print_desc; + int c = node->axes[port]; + + p += sprintf(p, "%s[%d] = ", name, port); + if (c) + p += sprintf(p, "%s%c -> ", ((c - 1) & 1) ? "-" : "+", 'X' + (c - 1)/2); + else + p += sprintf(p, "N/A -> "); + p += sprintf(p, "%s\n", + p_lash->switches[node->links[port]->switch_id]->p_sw->p_node->print_desc); +} + +/* + * seed_axes + * + * assign axes to the links of the seed switch + * assumes switch is of type cartesian mesh + * axes are numbered 1 to n i.e. +x => 1 -x => 2 etc. + * this assumes that if all distances are 2 that + * an axis has only 2 nodes so +A and -A collapse to +A + */ +static void seed_axes(lash_t *p_lash, int sw) +{ + osm_log_t *p_log = &p_lash->p_osm->log; + mesh_node_t *node = p_lash->switches[sw]->node; + int n = node->num_links; + int i, j, c; + + OSM_LOG_ENTER(p_log); + + if (!node->matrix || !node->dimension) + goto done; + + for (c = 1; c <= 2*node->dimension; c++) { + /* + * find the next unassigned axis + */ + for (i = 0; i < n; i++) { + if (!node->axes[i]) + break; + } + + node->axes[i] = c++; + + /* + * find the matching opposite direction + */ + for (j = 0; j < n; j++) { + if (node->axes[j] || j == i) + continue; + + if (node->matrix[i][j] != 2) + break; + } + + if (j != n) { + node->axes[j] = c; + } + } + + if (osm_log_is_active(p_log, OSM_LOG_DEBUG)) { + char buf[256], *p; + + for (i = 0; i < n; i++) { + p = buf; + print_axis(p_lash, p, sw, i); + OSM_LOG(p_log, OSM_LOG_DEBUG, "%s", buf); + } + } + +done: + OSM_LOG_EXIT(p_log); +} + +/* + * opposite + * + * compute the opposite of axis for switch + */ +static inline int opposite(switch_t *s, int axis) +{ + unsigned i, j; + int negaxis = 1 + (1 ^ (axis - 1)); + + if (!s->node->matrix) + return 0; + + for (i = 0; i < s->node->num_links; i++) { + if (s->node->axes[i] == axis) { + for (j = 0; j < s->node->num_links; j++) { + if (j == i) + continue; + if (s->node->matrix[i][j] != 2) + return negaxis; + } + + return axis; + } + } + + return 0; +} + +/* + * make_geometry + * + * induce a geometry on the switches + */ +static void make_geometry(lash_t *p_lash, int sw) +{ + osm_log_t *p_log = &p_lash->p_osm->log; + int num_switches = p_lash->num_switches; + int sw1, sw2; + switch_t *s, *s1, *s2, *seed; + unsigned int i, j, k, l, n, m; + unsigned int change; + + OSM_LOG_ENTER(p_log); + + s = p_lash->switches[sw]; + + if (!s->node->matrix) + goto done; + + /* + * assign axes to seed switch + */ + seed_axes(p_lash, sw); + seed = p_lash->switches[sw]; + + /* + * induce axes in other switches until + * there is no more change + */ + do { + change = 0; + + /* phase 1 opposites */ + for (sw1 = 0; sw1 < num_switches; sw1++) { + s1 = p_lash->switches[sw1]; + n = s1->node->num_links; + + /* + * ignore chain fragments + */ + if (n < seed->node->num_links && n <= 2) + continue; + + /* + * only process 'mesh' switches + */ + if (!s1->node->matrix) + continue; + + for (i = 0; i < n; i++) { + if (!s1->node->axes[i]) + continue; + + /* + * can't tell across if more than one + * likely looking link + */ + m = 0; + for (j = 0; j < n; j++) { + if (j == i) + continue; + + if (s1->node->matrix[i][j] != 2) + m++; + } + + if (m != 1) { + continue; + } + + for (j = 0; j < n; j++) { + if (j == i) + continue; + + /* Rule out opposite nodes when distance greater than 4 */ + if (s1->node->matrix[i][j] != 2 && + s1->node->matrix[i][j] <= 4) { + if (s1->node->axes[j]) { + if (s1->node->axes[j] != opposite(seed, s1->node->axes[i])) { + OSM_LOG(p_log, OSM_LOG_DEBUG, + "phase 1 mismatch\n"); + } + } else { + s1->node->axes[j] = opposite(seed, s1->node->axes[i]); + change++; + } + } + } + } + } + + /* phase 2 switch to switch */ + for (sw1 = 0; sw1 < num_switches; sw1++) { + s1 = p_lash->switches[sw1]; + n = s1->node->num_links; + + if (!s1->node->matrix) + continue; + + for (i = 0; i < n; i++) { + int l2 = s1->node->links[i]->link_id; + + if (!s1->node->axes[i]) + continue; + + if (l2 == -1) { + OSM_LOG(p_log, OSM_LOG_DEBUG, + "no reverse link\n"); + continue; + } + + sw2 = s1->node->links[i]->switch_id; + s2 = p_lash->switches[sw2]; + + if (!s2->node->matrix) + continue; + + if (!s2->node->axes[l2]) { + /* + * set axis to opposite of s1->axes[i] + */ + s2->node->axes[l2] = opposite(seed, s1->node->axes[i]); + change++; + } else { + if (s2->node->axes[l2] != opposite(seed, s1->node->axes[i])) { + OSM_LOG(p_log, OSM_LOG_DEBUG, + "phase 2 mismatch\n"); + } + } + } + } + + /* Phase 3 corners */ + for (sw1 = 0; sw1 < num_switches; sw1++) { + s = p_lash->switches[sw1]; + n = s->node->num_links; + + if (!s->node->matrix) + continue; + + for (i = 0; i < n; i++) { + if (!s->node->axes[i]) + continue; + + for (j = 0; j < n; j++) { + if (i == j || !s->node->axes[j] || s->node->matrix[i][j] != 2) + continue; + + s1 = p_lash->switches[s->node->links[i]->switch_id]; + s2 = p_lash->switches[s->node->links[j]->switch_id]; + + /* + * find switch (other than s1) that neighbors i and j + * have in common + */ + for (k = 0; k < s1->node->num_links; k++) { + if (s1->node->links[k]->switch_id == sw1) + continue; + + for (l = 0; l < s2->node->num_links; l++) { + if (s2->node->links[l]->switch_id == sw1) + continue; + + if (s1->node->links[k]->switch_id == s2->node->links[l]->switch_id) { + if (s1->node->axes[k]) { + if (s1->node->axes[k] != s->node->axes[j]) { + OSM_LOG(p_log, OSM_LOG_DEBUG, "phase 3 mismatch\n"); + } + } else { + s1->node->axes[k] = s->node->axes[j]; + change++; + } + + if (s2->node->axes[l]) { + if (s2->node->axes[l] != s->node->axes[i]) { + OSM_LOG(p_log, OSM_LOG_DEBUG, "phase 3 mismatch\n"); + } + } else { + s2->node->axes[l] = s->node->axes[i]; + change++; + } + goto next_j; + } + } + } +next_j: + ; + } + } + } + } while (change); + +done: + OSM_LOG_EXIT(p_log); +} + +/* + * return |a| < |b| + */ +static inline int ltmag(int a, int b) +{ + int a1 = (a >= 0)? a : -a; + int b1 = (b >= 0)? b : -b; + + return (a1 < b1) || (a1 == b1 && a > b); +} + +/* + * reorder_node_links + * + * reorder the links out of a switch in sign/dimension order + */ +static int reorder_node_links(lash_t *p_lash, mesh_t *mesh, int sw) +{ + osm_log_t *p_log = &p_lash->p_osm->log; + switch_t *s = p_lash->switches[sw]; + mesh_node_t *node = s->node; + int n = node->num_links; + link_t **links; + int *axes; + int i, j, k, l; + int c; + int next = 0; + int dimension = mesh->dimension; + + if (!(links = calloc(n, sizeof(link_t *)))) { + OSM_LOG(p_log, OSM_LOG_ERROR, + "Failed allocating links array - out of memory\n"); + return -1; + } + + if (!(axes = calloc(n, sizeof(int)))) { + free(links); + OSM_LOG(p_log, OSM_LOG_ERROR, + "Failed allocating axes array - out of memory\n"); + return -1; + } + + /* + * find the links with axes + */ + for (i = 0; i < dimension; i++) { + j = mesh->dim_order[i]; + for (k = 1; k <= 2; k++) { + c = 2*j + k; + + if (node->coord[j] > 0) + c = opposite(s, c); + + for (l = 0; l < n; l++) { + if (!node->links[l]) + continue; + if (node->axes[l] == c) { + links[next] = node->links[l]; + axes[next] = node->axes[l]; + node->links[l] = NULL; + next++; + } + } + } + } + + /* + * get the rest + */ + for (i = 0; i < n; i++) { + if (!node->links[i]) + continue; + + links[next] = node->links[i]; + axes[next] = node->axes[i]; + node->links[i] = NULL; + next++; + } + + for (i = 0; i < n; i++) { + node->links[i] = links[i]; + node->axes[i] = axes[i]; + } + + free(links); + free(axes); + + return 0; +} + +/* + * make_coord + */ +static int make_coord(lash_t *p_lash, mesh_t *mesh, int seed) +{ + osm_log_t *p_log = &p_lash->p_osm->log; + unsigned int i, j, k; + int sw; + switch_t *s, *s1; + unsigned int change; + unsigned int dimension = mesh->dimension; + int num_switches = p_lash->num_switches; + int assigned_axes = 0, unassigned_axes = 0; + + OSM_LOG_ENTER(p_log); + + for (sw = 0; sw < num_switches; sw++) { + s = p_lash->switches[sw]; + + s->node->coord = calloc(dimension, sizeof(int)); + if (!s->node->coord) { + OSM_LOG(p_log, OSM_LOG_ERROR, + "Failed allocating coord - out of memory\n"); + OSM_LOG_EXIT(p_log); + return -1; + } + + for (i = 0; i < dimension; i++) + s->node->coord[i] = (sw == seed) ? 0 : LARGE; + + for (i = 0; i < s->node->num_links; i++) + if (s->node->axes[i] == 0) + unassigned_axes++; + else + assigned_axes++; + } + + OSM_LOG(p_log, OSM_LOG_DEBUG, "%d/%d unassigned/assigned axes\n", + unassigned_axes, assigned_axes); + + do { + change = 0; + + for (sw = 0; sw < num_switches; sw++) { + s = p_lash->switches[sw]; + + if (s->node->coord[0] == LARGE) + continue; + + for (j = 0; j < s->node->num_links; j++) { + if (!s->node->axes[j]) + continue; + + s1 = p_lash->switches[s->node->links[j]->switch_id]; + + for (k = 0; k < dimension; k++) { + int coord = s->node->coord[k]; + unsigned axis = s->node->axes[j] - 1; + + if (k == axis/2) + coord += (axis & 1)? -1 : +1; + + if (ltmag(coord, s1->node->coord[k])) { + s1->node->coord[k] = coord; + change++; + } + } + } + } + } while (change); + + OSM_LOG_EXIT(p_log); + return 0; +} + +/* + * measure geometry + */ +static int measure_geometry(lash_t *p_lash, mesh_t *mesh) +{ + osm_log_t *p_log = &p_lash->p_osm->log; + int i, j; + int sw; + switch_t *s; + int dimension = mesh->dimension; + int num_switches = p_lash->num_switches; + int max[MAX_DIMENSION]; + int min[MAX_DIMENSION]; + int size[MAX_DIMENSION]; + int max_size; + int max_index; + + OSM_LOG_ENTER(p_log); + + mesh->size = calloc(dimension, sizeof(int)); + if (!mesh->size) { + OSM_LOG(p_log, OSM_LOG_ERROR, + "Failed allocating size - out of memory\n"); + OSM_LOG_EXIT(p_log); + return -1; + } + + for (i = 0; i < dimension; i++) { + max[i] = -LARGE; + min[i] = LARGE; + } + + for (sw = 0; sw < num_switches; sw++) { + s = p_lash->switches[sw]; + + for (i = 0; i < dimension; i++) { + if (s->node->coord[i] == LARGE) + continue; + if (s->node->coord[i] > max[i]) + max[i] = s->node->coord[i]; + if (s->node->coord[i] < min[i]) + min[i] = s->node->coord[i]; + } + } + + for (i = 0; i < dimension; i++) + mesh->size[i] = size[i] = max[i] - min[i] + 1; + + /* + * find an order of dimensions that places largest + * sizes first since this seems to work best with LASH + */ + for (j = 0; j < dimension; j++) { + max_size = -1; + max_index = -1; + + for (i = 0; i < dimension; i++) { + if (size[i] > max_size) { + max_size = size[i]; + max_index = i; + } + } + + mesh->dim_order[j] = max_index; + size[max_index] = -1; + } + + OSM_LOG_EXIT(p_log); + return 0; +} + +/* + * reorder links + */ +static int reorder_links(lash_t *p_lash, mesh_t *mesh) +{ + osm_log_t *p_log = &p_lash->p_osm->log; + int sw; + int num_switches = p_lash->num_switches; + + OSM_LOG_ENTER(p_log); + + for (sw = 0; sw < num_switches; sw++) { + if (reorder_node_links(p_lash, mesh, sw)) { + OSM_LOG_EXIT(p_log); + return -1; + } + } + + OSM_LOG_EXIT(p_log); + return 0; +} + +/* + * compare two switches in a sort + */ +static int OSM_CDECL compare_switches(const void *p1, const void *p2) +{ + const comp_t *cp1 = p1, *cp2 = p2; + const sort_ctx_t *ctx = &cp1->ctx; + switch_t *s1 = ctx->p_lash->switches[cp1->index]; + switch_t *s2 = ctx->p_lash->switches[cp2->index]; + int i, j; + int ret; + + for (i = 0; i < ctx->mesh->dimension; i++) { + j = ctx->mesh->dim_order[i]; + if ((ret = s1->node->coord[j] - s2->node->coord[j])); + return ret; + } + + return 0; +} + +/* + * sort_switches - reorder switch array + */ +static void sort_switches(lash_t *p_lash, mesh_t *mesh) +{ + unsigned int i, j; + unsigned int num_switches = p_lash->num_switches; + comp_t *comp; + int *reverse; + switch_t *s; + switch_t **switches; + + comp = malloc(num_switches * sizeof(comp_t)); + reverse = malloc(num_switches * sizeof(int)); + switches = malloc(num_switches * sizeof(switch_t *)); + if (!comp || !reverse || !switches) { + OSM_LOG(&p_lash->p_osm->log, OSM_LOG_ERROR, + "Failed memory allocation - switches not sorted!\n"); + goto Exit; + } + + for (i = 0; i < num_switches; i++) { + comp[i].index = i; + comp[i].ctx.mesh = mesh; + comp[i].ctx.p_lash = p_lash; + } + + qsort(comp, num_switches, sizeof(comp_t), compare_switches); + + for (i = 0; i < num_switches; i++) + reverse[comp[i].index] = i; + + for (i = 0; i < num_switches; i++) { + s = p_lash->switches[comp[i].index]; + switches[i] = s; + s->id = i; + for (j = 0; j < s->node->num_links; j++) + s->node->links[j]->switch_id = + reverse[s->node->links[j]->switch_id]; + } + + for (i = 0; i < num_switches; i++) + p_lash->switches[i] = switches[i]; + +Exit: + if (switches) + free(switches); + if (comp) + free(comp); + if (reverse) + free(reverse); +} + +/* + * osm_mesh_delete - free per mesh resources + */ +static void mesh_delete(mesh_t *mesh) +{ + if (mesh) { + if (mesh->class_type) + free(mesh->class_type); + + if (mesh->class_count) + free(mesh->class_count); + + if (mesh->size) + free(mesh->size); + + free(mesh); + } +} + +/* + * osm_mesh_create - allocate per mesh resources + */ +static mesh_t *mesh_create(lash_t *p_lash) +{ + osm_log_t *p_log = &p_lash->p_osm->log; + mesh_t *mesh; + + if(!(mesh = calloc(1, sizeof(mesh_t)))) + goto err; + + if (!(mesh->class_type = calloc(p_lash->num_switches, sizeof(int)))) + goto err; + + if (!(mesh->class_count = calloc(p_lash->num_switches, sizeof(int)))) + goto err; + + return mesh; + +err: + mesh_delete(mesh); + OSM_LOG(p_log, OSM_LOG_ERROR, + "Failed allocating mesh - out of memory\n"); + return NULL; +} + +/* + * osm_mesh_node_delete - cleanup per switch resources + */ +void osm_mesh_node_delete(lash_t *p_lash, switch_t *sw) +{ + osm_log_t *p_log = &p_lash->p_osm->log; + unsigned i; + mesh_node_t *node = sw->node; + unsigned num_ports = sw->p_sw->num_ports; + + OSM_LOG_ENTER(p_log); + + if (node) { + for (i = 0; i < num_ports; i++) + if (node->links[i]) + free(node->links[i]); + + if (node->poly) + free(node->poly); + + if (node->matrix) { + for (i = 0; i < node->num_links; i++) { + if (node->matrix[i]) + free(node->matrix[i]); + } + free(node->matrix); + } + + if (node->axes) + free(node->axes); + + if (node->coord) + free(node->coord); + + free(node); + + sw->node = NULL; + } + + OSM_LOG_EXIT(p_log); +} + +/* + * osm_mesh_node_create - allocate per switch resources + */ +int osm_mesh_node_create(lash_t *p_lash, switch_t *sw) +{ + osm_log_t *p_log = &p_lash->p_osm->log; + unsigned i; + mesh_node_t *node; + unsigned num_ports = sw->p_sw->num_ports; + + OSM_LOG_ENTER(p_log); + + if (!(node = sw->node = calloc(1, sizeof(mesh_node_t) + num_ports * sizeof(link_t *)))) + goto err; + + for (i = 0; i < num_ports; i++) + if (!(node->links[i] = calloc(1, sizeof(link_t) + num_ports * sizeof(int)))) + goto err; + + if (!(node->axes = calloc(num_ports, sizeof(int)))) + goto err; + + for (i = 0; i < num_ports; i++) { + node->links[i]->switch_id = NONE; + } + + OSM_LOG_EXIT(p_log); + return 0; + +err: + osm_mesh_node_delete(p_lash, sw); + OSM_LOG(p_log, OSM_LOG_ERROR, + "Failed allocating mesh node - out of memory\n"); + OSM_LOG_EXIT(p_log); + return -1; +} + +static void dump_mesh(lash_t *p_lash) +{ + osm_log_t *p_log = &p_lash->p_osm->log; + int sw; + int num_switches = p_lash->num_switches; + int dimension; + int i, j, k, n; + switch_t *s, *s2; + char buf[256]; + + OSM_LOG_ENTER(p_log); + + for (sw = 0; sw < num_switches; sw++) { + s = p_lash->switches[sw]; + dimension = s->node->dimension; + n = sprintf(buf, "["); + for (i = 0; i < dimension; i++) { + n += snprintf(buf + n, sizeof(buf) - n, + "%2d", s->node->coord[i]); + if (n > sizeof(buf)) + n = sizeof(buf); + if (i != dimension - 1) { + n += snprintf(buf + n, sizeof(buf) - n, "%s", ","); + if (n > sizeof(buf)) + n = sizeof(buf); + } + } + n += snprintf(buf + n, sizeof(buf) - n, "]"); + if (n > sizeof(buf)) + n = sizeof(buf); + for (j = 0; j < s->node->num_links; j++) { + s2 = p_lash->switches[s->node->links[j]->switch_id]; + n += snprintf(buf + n, sizeof(buf) - n, " [%d]->[", j); + if (n > sizeof(buf)) + n = sizeof(buf); + for (k = 0; k < dimension; k++) { + n += snprintf(buf + n, sizeof(buf) - n, "%2d", + s2->node->coord[k]); + if (n > sizeof(buf)) + n = sizeof(buf); + if (k != dimension - 1) { + n += snprintf(buf + n, sizeof(buf) - n, + ","); + if (n > sizeof(buf)) + n = sizeof(buf); + } + } + n += snprintf(buf + n, sizeof(buf) - n, "]"); + if (n > sizeof(buf)) + n = sizeof(buf); + } + OSM_LOG(p_log, OSM_LOG_DEBUG, "%s\n", buf); + } + + OSM_LOG_EXIT(p_log); +} + +/* + * osm_do_mesh_analysis + */ +int osm_do_mesh_analysis(lash_t *p_lash) +{ + osm_log_t *p_log = &p_lash->p_osm->log; + mesh_t *mesh; + int max_class = -1; + int max_class_num = 0; + int max_class_type = -1; + int i; + switch_t *s; + char buf[256], *p; + + OSM_LOG_ENTER(p_log); + + mesh = mesh_create(p_lash); + if (!mesh) + goto err; + + if (get_local_geometry(p_lash, mesh)) + goto err; + + if (mesh->num_class == 0) { + OSM_LOG(p_log, OSM_LOG_INFO, + "found no likely mesh nodes - done\n"); + goto done; + } + + /* + * find dominant switch class + */ + OSM_LOG(p_log, OSM_LOG_INFO, "found %d node class%s\n", + mesh->num_class, (mesh->num_class == 1)? "" : "es"); + for (i = 0; i < mesh->num_class; i++) { + OSM_LOG(p_log, OSM_LOG_INFO, + "class[%d] has %d members with type = %d\n", + i, mesh->class_count[i], + p_lash->switches[mesh->class_type[i]]->node->type); + if (mesh->class_count[i] > max_class_num) { + max_class = i; + max_class_num = mesh->class_count[i]; + max_class_type = mesh->class_type[i]; + } + } + + s = p_lash->switches[max_class_type]; + + p = buf; + p += sprintf(p, "%snode shape is ", + (mesh->num_class == 1) ? "" : "most common "); + + if (s->node->type) { + const struct mesh_info *t = &mesh_info[s->node->type]; + + for (i = 0; i < t->dimension; i++) { + p += sprintf(p, "%s%d%s", i? " x " : "", t->size[i], + (t->size[i] == 6)? "+" : ""); + } + p += sprintf(p, " mesh\n"); + + mesh->dimension = t->dimension; + } else { + p += sprintf(p, "unknown geometry\n"); + } + + OSM_LOG(p_log, OSM_LOG_INFO, "%s", buf); + + OSM_LOG(p_log, OSM_LOG_INFO, "poly = %s\n", + poly_print(s->node->num_links, s->node->poly)); + + if (s->node->type) { + make_geometry(p_lash, max_class_type); + + if (make_coord(p_lash, mesh, max_class_type)) + goto err; + + if (measure_geometry(p_lash, mesh)) + goto err; + + if (reorder_links(p_lash, mesh)) + goto err; + + sort_switches(p_lash, mesh); + + p = buf; + p += sprintf(p, "found "); + for (i = 0; i < mesh->dimension; i++) + p += sprintf(p, "%s%d", i? " x " : "", mesh->size[i]); + p += sprintf(p, " mesh\n"); + + OSM_LOG(p_log, OSM_LOG_INFO, "%s", buf); + } + + if (osm_log_is_active(p_log, OSM_LOG_DEBUG)) + dump_mesh(p_lash); + +done: + mesh_delete(mesh); + OSM_LOG_EXIT(p_log); + return 0; + +err: + mesh_delete(mesh); + OSM_LOG_EXIT(p_log); + return -1; +} diff --git a/branches/WOF2-3/ulp/opensm/user/opensm/osm_mtree.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_mtree.c new file mode 100644 index 00000000..f36993c9 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_mtree.c @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2004-2009 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_mtree_node_t. + * This file implements the Multicast Tree object. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +osm_mtree_node_t *osm_mtree_node_new(IN const osm_switch_t * p_sw) +{ + osm_mtree_node_t *p_mtn; + uint32_t i; + + p_mtn = malloc(sizeof(osm_mtree_node_t) + + sizeof(void *) * (p_sw->num_ports - 1)); + if (!p_mtn) + return NULL; + + memset(p_mtn, 0, sizeof(*p_mtn)); + p_mtn->p_sw = 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; + + 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 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)) + mtree_dump(p_mtn->child_array[i]); + } + } +} +#endif diff --git a/branches/WOF2-3/ulp/opensm/user/opensm/osm_multicast.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_multicast.c new file mode 100644 index 00000000..1dab4302 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_multicast.c @@ -0,0 +1,325 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2006,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 multicast functions. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static osm_mgrp_box_t *mgrp_box_new(uint16_t mlid) +{ + osm_mgrp_box_t *mbox = malloc(sizeof(*mbox)); + if (!mbox) + return NULL; + + memset(mbox, 0, sizeof(*mbox)); + mbox->mlid = mlid; + cl_qlist_init(&mbox->mgrp_list); + + return mbox; +} + +void mgrp_box_delete(osm_mgrp_box_t *mbox) +{ + osm_mtree_destroy(mbox->root); + free(mbox); +} + +void mgrp_delete(IN osm_mgrp_t * 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); + } + + free(p_mgrp); +} + +void osm_mgrp_box_delete(osm_mgrp_box_t *mbox) +{ + osm_mgrp_t *mgrp=NULL; + while(cl_qlist_count(&mbox->mgrp_list)) { + mgrp = cl_item_obj(cl_qlist_remove_head(&mbox->mgrp_list), + mgrp, list_item); + mgrp_delete(mgrp); + } + mgrp_box_delete(mbox); +} + +osm_mgrp_t *osm_mgrp_new(IN osm_subn_t * subn, IN ib_net16_t mlid, + IN ib_member_rec_t * mcmr) +{ + osm_mgrp_t *p_mgrp; + osm_mgrp_box_t *mbox; + + 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->mcmember_rec = *mcmr; + + mbox = osm_get_mbox_by_mlid(subn, p_mgrp->mlid); + if (!mbox && !(mbox = mgrp_box_new(cl_ntoh16(p_mgrp->mlid)))) { + free(p_mgrp); + return NULL; + } + + cl_qlist_insert_tail(&mbox->mgrp_list, &p_mgrp->list_item); + subn->mboxes[mbox->mlid - IB_LID_MCAST_START_HO] = mbox; + + cl_fmap_insert(&subn->mgrp_mgid_tbl, &p_mgrp->mcmember_rec.mgid, + &p_mgrp->map_item); + + return p_mgrp; +} + +void osm_mgrp_cleanup(osm_subn_t * subn, osm_mgrp_t * mgrp) +{ + osm_mgrp_box_t *mbox; + osm_mcm_port_t *mcm_port; + + if (mgrp->full_members) + return; + + while (cl_qmap_count(&mgrp->mcm_port_tbl)) { + mcm_port = (osm_mcm_port_t *)cl_qmap_head(&mgrp->mcm_port_tbl); + cl_qmap_remove_item(&mgrp->mcm_port_tbl, &mcm_port->map_item); + cl_qlist_remove_item(&mcm_port->port->mcm_list, + &mcm_port->list_item); + osm_mcm_port_delete(mcm_port); + } + + if (mgrp->well_known) + return; + + cl_fmap_remove_item(&subn->mgrp_mgid_tbl, &mgrp->map_item); + + mbox = osm_get_mbox_by_mlid(subn, mgrp->mlid); + cl_qlist_remove_item(&mbox->mgrp_list, &mgrp->list_item); + if (cl_is_qlist_empty(&mbox->mgrp_list)) { + subn->mboxes[cl_ntoh16(mgrp->mlid) - IB_LID_MCAST_START_HO] = NULL; + mgrp_box_delete(mbox); + } + free(mgrp); +} + +static void mgrp_send_notice(osm_subn_t * subn, osm_log_t * log, + osm_mgrp_t * mgrp, unsigned num) +{ + ib_mad_notice_attr_t notice; + ib_api_status_t status; + + notice.generic_type = 0x83; /* generic SubnMgt type */ + ib_notice_set_prod_type_ho(¬ice, 4); /* A Class Manager generator */ + notice.g_or_v.generic.trap_num = CL_HTON16(num); + /* The sm_base_lid is saved in network order already. */ + notice.issuer_lid = subn->sm_base_lid; + /* following o14-12.1.11 and table 120 p726 */ + /* we need to provide the MGID */ + memcpy(¬ice.data_details.ntc_64_67.gid, + &mgrp->mcmember_rec.mgid, sizeof(ib_gid_t)); + + /* According to page 653 - the issuer gid in this case of trap + is the SM gid, since the SM is the initiator of this trap. */ + notice.issuer_gid.unicast.prefix = subn->opt.subnet_prefix; + notice.issuer_gid.unicast.interface_id = subn->sm_port_guid; + + if ((status = osm_report_notice(log, subn, ¬ice))) + OSM_LOG(log, OSM_LOG_ERROR, "ERR 7601: " + "Error sending trap reports (%s)\n", + ib_get_err_str(status)); +} + +osm_mcm_port_t *osm_mgrp_add_port(IN osm_subn_t * subn, osm_log_t * log, + IN osm_mgrp_t * mgrp, osm_port_t *port, + IN ib_member_rec_t *mcmr, IN boolean_t proxy) +{ + osm_mcm_port_t *mcm_port; + cl_map_item_t *prev_item; + uint8_t prev_join_state = 0, join_state = mcmr->scope_state; + uint8_t prev_scope; + + if (osm_log_is_active(log, OSM_LOG_VERBOSE)) { + char gid_str[INET6_ADDRSTRLEN]; + OSM_LOG(log, OSM_LOG_VERBOSE, "Port 0x%016" PRIx64 " joining " + "MC group %s (mlid 0x%x)\n", cl_ntoh64(port->guid), + inet_ntop(AF_INET6, mgrp->mcmember_rec.mgid.raw, + gid_str, sizeof(gid_str)), + cl_ntoh16(mgrp->mlid)); + } + + mcm_port = osm_mcm_port_new(port, mgrp, mcmr, proxy); + if (!mcm_port) + return NULL; + + /* + 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(&mgrp->mcm_port_tbl, port->guid, + &mcm_port->map_item); + + /* if already exists - revert the insertion and only update join state */ + if (prev_item != &mcm_port->map_item) { + osm_mcm_port_delete(mcm_port); + mcm_port = (osm_mcm_port_t *) prev_item; + + ib_member_get_scope_state(mcm_port->scope_state, &prev_scope, + &prev_join_state); + mcm_port->scope_state = + ib_member_set_scope_state(prev_scope, + prev_join_state | join_state); + } else { + cl_qlist_insert_tail(&port->mcm_list, &mcm_port->list_item); + osm_sm_reroute_mlid(&subn->p_osm->sm, mgrp->mlid); + } + + /* o15.0.1.11: copy the join state */ + mcmr->scope_state = mcm_port->scope_state; + + if ((join_state & IB_JOIN_STATE_FULL) && + !(prev_join_state & IB_JOIN_STATE_FULL) && + ++mgrp->full_members == 1) + mgrp_send_notice(subn, log, mgrp, 66); + + subn->p_osm->sa.dirty = TRUE; + return mcm_port; +} + +void osm_mgrp_remove_port(osm_subn_t * subn, osm_log_t * log, osm_mgrp_t * mgrp, + osm_mcm_port_t * mcm_port, ib_member_rec_t *mcmr) +{ + uint8_t join_state = mcmr->scope_state & 0xf; + uint8_t port_join_state, 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_port->scope_state & 0x0F; + new_join_state = port_join_state & ~join_state; + + if (osm_log_is_active(log, OSM_LOG_VERBOSE)) { + char gid_str[INET6_ADDRSTRLEN]; + OSM_LOG(log, OSM_LOG_VERBOSE, + "Port 0x%" PRIx64 " leaving MC group %s (mlid 0x%x)\n", + cl_ntoh64(mcm_port->port->guid), + inet_ntop(AF_INET6, mgrp->mcmember_rec.mgid.raw, + gid_str, sizeof(gid_str)), + cl_ntoh16(mgrp->mlid)); + } + + if (new_join_state) { + mcm_port->scope_state = + new_join_state | (mcm_port->scope_state & 0xf0); + OSM_LOG(log, OSM_LOG_DEBUG, + "updating port 0x%" PRIx64 " JoinState 0x%x -> 0x%x\n", + cl_ntoh64(mcm_port->port->guid), + port_join_state, new_join_state); + mcmr->scope_state = mcm_port->scope_state; + } else { + mcmr->scope_state = mcm_port->scope_state; + OSM_LOG(log, OSM_LOG_DEBUG, "removing port 0x%" PRIx64 "\n", + cl_ntoh64(mcm_port->port->guid)); + cl_qmap_remove_item(&mgrp->mcm_port_tbl, &mcm_port->map_item); + cl_qlist_remove_item(&mcm_port->port->mcm_list, + &mcm_port->list_item); + osm_mcm_port_delete(mcm_port); + osm_sm_reroute_mlid(&subn->p_osm->sm, mgrp->mlid); + } + + /* 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); + osm_mgrp_cleanup(subn, mgrp); + } + + subn->p_osm->sa.dirty = TRUE; +} + +void osm_mgrp_delete_port(osm_subn_t * subn, osm_log_t * log, osm_mgrp_t * mgrp, + ib_net64_t port_guid) +{ + ib_member_rec_t mcmrec; + cl_map_item_t *item = cl_qmap_get(&mgrp->mcm_port_tbl, port_guid); + + if (item != cl_qmap_end(&mgrp->mcm_port_tbl)) { + mcmrec.scope_state = 0xf; + osm_mgrp_remove_port(subn, log, mgrp, (osm_mcm_port_t *) item, + &mcmrec); + } +} + +osm_mcm_port_t *osm_mgrp_get_mcm_port(IN const osm_mgrp_t * p_mgrp, + IN ib_net64_t port_guid) +{ + cl_map_item_t *item = cl_qmap_get(&p_mgrp->mcm_port_tbl, port_guid); + if (item != cl_qmap_end(&p_mgrp->mcm_port_tbl)) + return (osm_mcm_port_t *)item; + return NULL; +} diff --git a/branches/WOF2-3/ulp/opensm/user/opensm/osm_node.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_node.c new file mode 100644 index 00000000..e6d7ccd3 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_node.c @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_node_t. + * This object represents an Infiniband Node. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include + +void osm_node_init_physp(IN osm_node_t * p_node, uint8_t port_num, + IN const osm_madw_t * p_madw) +{ + ib_net64_t port_guid; + ib_smp_t *p_smp; + ib_node_info_t *p_ni; + + p_smp = osm_madw_get_smp_ptr(p_madw); + + p_ni = ib_smp_get_payload_ptr(p_smp); + port_guid = p_ni->port_guid; + + 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); +} + +osm_node_t *osm_node_new(IN const osm_madw_t * 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_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]); + + if (p_ni->node_type == IB_NODE_TYPE_SWITCH) + for (i = 0; i <= p_ni->num_ports; i++) + osm_node_init_physp(p_node, i, p_madw); + else + osm_node_init_physp(p_node, + ib_node_info_get_local_port_num(p_ni), + p_madw); + p_node->print_desc = strdup(OSM_NODE_DESC_UNKNOWN); + + return p_node; +} + +static void 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 ** p_node) +{ + CL_ASSERT(p_node && *p_node); + node_destroy(*p_node); + free(*p_node); + *p_node = NULL; +} + +void osm_node_link(IN osm_node_t * p_node, IN uint8_t port_num, + IN osm_node_t * p_remote_node, IN 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 * p_node, IN uint8_t port_num, + IN osm_node_t * p_remote_node, IN 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 * p_node, IN uint8_t port_num, + IN osm_node_t * p_remote_node, + IN 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 * p_node, + IN uint8_t port_num, + IN osm_node_t * p_remote_node, + IN 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 * p_node, IN 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 * p_node, + IN 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 * p_node, + IN 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/branches/WOF2-3/ulp/opensm/user/opensm/osm_node_desc_rcv.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_node_desc_rcv.c new file mode 100644 index 00000000..53161fa1 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_node_desc_rcv.c @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2004-2009 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 osm_nd_rcv_t. + * This object represents the NodeDescription Receiver object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void nd_rcv_process_nd(IN osm_sm_t * sm, IN osm_node_t * p_node, + IN const ib_node_desc_t * 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_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 + nd_rcv_process_nd(sm, p_node, p_nd); + + CL_PLOCK_RELEASE(sm->p_lock); + OSM_LOG_EXIT(sm->p_log); +} diff --git a/branches/WOF2-3/ulp/opensm/user/opensm/osm_node_info_rcv.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_node_info_rcv.c new file mode 100755 index 00000000..3e18d0f2 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_node_info_rcv.c @@ -0,0 +1,804 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2009 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Copyright (c) 2009 HNR Consulting. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_ni_rcv_t. + * This object represents the NodeInfo Receiver object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void report_duplicated_guid(IN osm_sm_t * sm, osm_physp_t * p_physp, + osm_node_t * p_neighbor_node, + const uint8_t port_num) +{ + osm_physp_t *p_old, *p_new; + osm_dr_path_t path; + + p_old = p_physp->p_remote_physp; + p_new = osm_node_get_physp_ptr(p_neighbor_node, port_num); + + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D01: " + "Found duplicated node.\n" + "Node 0x%" PRIx64 " port %u is reachable from remote node " + "0x%" PRIx64 " port %u and remote node 0x%" PRIx64 " port %u.\n" + "Paths are:\n", + cl_ntoh64(p_physp->p_node->node_info.node_guid), + p_physp->port_num, + cl_ntoh64(p_old->p_node->node_info.node_guid), p_old->port_num, + cl_ntoh64(p_new->p_node->node_info.node_guid), p_new->port_num); + + osm_dump_dr_path(sm->p_log, osm_physp_get_dr_path_ptr(p_physp), + OSM_LOG_ERROR); + + path = *osm_physp_get_dr_path_ptr(p_new); + if (osm_dr_path_extend(&path, port_num)) + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D05: " + "DR path with hop count %d couldn't be extended\n", + path.hop_count); + 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); + if (osm_dr_path_extend(&path, p_physp->p_remote_physp->port_num)) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D08: " + "DR path with hop count %d couldn't be extended\n", + path.hop_count); + return; + } + + 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 ni_rcv_set_links(IN osm_sm_t * sm, osm_node_t * p_node, + const uint8_t port_num, + const osm_ni_context_t * 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; + } + + /* When setting the link, ports on both + sides of the link should be initialized */ + CL_ASSERT(osm_node_link_has_valid_ports(p_node, port_num, + p_neighbor_node, + p_ni_context->port_num)); + + 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); +} + +static void ni_rcv_get_port_info(IN osm_sm_t * sm, IN osm_node_t * node, + IN const osm_madw_t * madw) +{ + osm_madw_context_t context; + osm_physp_t *physp; + ib_node_info_t *ni; + unsigned port, num_ports; + ib_api_status_t status; + + ni = ib_smp_get_payload_ptr(osm_madw_get_smp_ptr(madw)); + + if (ni->node_type == IB_NODE_TYPE_SWITCH) { + port = 0; + num_ports = osm_node_get_num_physp(node); + } else { + port = ib_node_info_get_local_port_num(ni); + num_ports = port + 1; + } + + physp = osm_node_get_physp_ptr(node, port); + + context.pi_context.node_guid = osm_node_get_node_guid(node); + context.pi_context.port_guid = osm_physp_get_port_guid(physp); + context.pi_context.set_method = FALSE; + context.pi_context.light_sweep = FALSE; + context.pi_context.active_transition = FALSE; + + for (; port < num_ports; port++) { + status = osm_req_get(sm, osm_physp_get_dr_path_ptr(physp), + IB_MAD_ATTR_PORT_INFO, cl_hton32(port), + CL_DISP_MSGID_NONE, &context); + if (status != IB_SUCCESS) + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR OD02: " + "Failure initiating PortInfo request (%s)\n", + ib_get_err_str(status)); + } +} + +/********************************************************************** + 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 ni_rcv_get_node_desc(IN osm_sm_t * sm, IN osm_node_t * p_node, + IN const osm_madw_t * 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_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 ni_rcv_process_new_ca_or_router(IN osm_sm_t * sm, + IN osm_node_t * p_node, + IN const osm_madw_t * p_madw) +{ + OSM_LOG_ENTER(sm->p_log); + + ni_rcv_get_port_info(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 ni_rcv_process_existing_ca_or_router(IN osm_sm_t * sm, + IN osm_node_t * p_node, + IN const osm_madw_t * p_madw) +{ + ib_node_info_t *p_ni; + ib_smp_t *p_smp; + osm_port_t *p_port; + osm_port_t *p_port_check; + uint8_t port_num; + osm_physp_t *p_physp; + 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_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, port_num, 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 for 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); + } + + ni_rcv_get_port_info(sm, p_node, p_madw); + +Exit: + OSM_LOG_EXIT(sm->p_log); +} + +static void ni_rcv_process_switch(IN osm_sm_t * sm, IN osm_node_t * p_node, + IN const osm_madw_t * 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)); + + if (p_node->discovery_count == 1) + ni_rcv_get_port_info(sm, p_node, p_madw); + + OSM_LOG_EXIT(sm->p_log); +} + +/********************************************************************** + The plock must be held before calling this function. +**********************************************************************/ +static void ni_rcv_process_existing_switch(IN osm_sm_t * sm, + IN osm_node_t * p_node, + IN const osm_madw_t * 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) + ni_rcv_process_switch(sm, p_node, p_madw); + else if (!p_node->sw) { + /* 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))); + 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 ni_rcv_process_new_switch(IN osm_sm_t * sm, IN osm_node_t * p_node, + IN const osm_madw_t * p_madw) +{ + OSM_LOG_ENTER(sm->p_log); + + 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 ni_rcv_process_new(IN osm_sm_t * sm, IN const osm_madw_t * 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_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; + ni_rcv_set_links(sm, p_node, port_num, p_ni_context); + goto Exit; + } else + ni_rcv_set_links(sm, p_node, port_num, p_ni_context); + + p_node->discovery_count++; + 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: + ni_rcv_process_new_ca_or_router(sm, p_node, p_madw); + break; + case IB_NODE_TYPE_SWITCH: + 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 ni_rcv_process_existing(IN osm_sm_t * sm, IN osm_node_t * p_node, + IN const osm_madw_t * 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_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: + ni_rcv_process_existing_ca_or_router(sm, p_node, p_madw); + break; + + case IB_NODE_TYPE_SWITCH: + 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; + } + + 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_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) + ni_rcv_process_new(sm, p_madw); + else + 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/branches/WOF2-3/ulp/opensm/user/opensm/osm_opensm.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_opensm.c new file mode 100644 index 00000000..7c988d14 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_opensm.c @@ -0,0 +1,483 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2006 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_opensm_t. + * This object represents the opensm super object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct routing_engine_module { + const char *name; + int (*setup) (struct osm_routing_engine *, osm_opensm_t *); +}; + +extern int osm_ucast_minhop_setup(struct osm_routing_engine *, osm_opensm_t *); +extern int osm_ucast_updn_setup(struct osm_routing_engine *, osm_opensm_t *); +extern int osm_ucast_file_setup(struct osm_routing_engine *, osm_opensm_t *); +extern int osm_ucast_ftree_setup(struct osm_routing_engine *, osm_opensm_t *); +extern int osm_ucast_lash_setup(struct osm_routing_engine *, osm_opensm_t *); +extern int osm_ucast_dor_setup(struct osm_routing_engine *, osm_opensm_t *); + +const static struct routing_engine_module routing_modules[] = { + {"minhop", osm_ucast_minhop_setup}, + {"updn", osm_ucast_updn_setup}, + {"file", osm_ucast_file_setup}, + {"ftree", osm_ucast_ftree_setup}, + {"lash", osm_ucast_lash_setup}, + {"dor", osm_ucast_dor_setup}, + {NULL, NULL} +}; + +const char *osm_routing_engine_type_str(IN osm_routing_engine_type_t type) +{ + switch (type) { + case OSM_ROUTING_ENGINE_TYPE_NONE: + return "none"; + case OSM_ROUTING_ENGINE_TYPE_MINHOP: + return "minhop"; + case OSM_ROUTING_ENGINE_TYPE_UPDN: + return "updn"; + case OSM_ROUTING_ENGINE_TYPE_FILE: + return "file"; + case OSM_ROUTING_ENGINE_TYPE_FTREE: + return "ftree"; + case OSM_ROUTING_ENGINE_TYPE_LASH: + return "lash"; + case OSM_ROUTING_ENGINE_TYPE_DOR: + return "dor"; + default: + break; + } + return "unknown"; +} + +osm_routing_engine_type_t osm_routing_engine_type(IN const char *str) +{ + /* For legacy reasons, consider a NULL pointer and the string + * "null" as the minhop routing engine. + */ + if (!str || !strcasecmp(str, "null") + || !strcasecmp(str, "minhop")) + return OSM_ROUTING_ENGINE_TYPE_MINHOP; + else if (!strcasecmp(str, "none")) + return OSM_ROUTING_ENGINE_TYPE_NONE; + else if (!strcasecmp(str, "updn")) + return OSM_ROUTING_ENGINE_TYPE_UPDN; + else if (!strcasecmp(str, "file")) + return OSM_ROUTING_ENGINE_TYPE_FILE; + else if (!strcasecmp(str, "ftree")) + return OSM_ROUTING_ENGINE_TYPE_FTREE; + else if (!strcasecmp(str, "lash")) + return OSM_ROUTING_ENGINE_TYPE_LASH; + else if (!strcasecmp(str, "dor")) + return OSM_ROUTING_ENGINE_TYPE_DOR; + else + return OSM_ROUTING_ENGINE_TYPE_UNKNOWN; +} + +static void append_routing_engine(osm_opensm_t *osm, + struct osm_routing_engine *routing_engine) +{ + struct osm_routing_engine *r; + + routing_engine->next = NULL; + + if (!osm->routing_engine_list) { + osm->routing_engine_list = routing_engine; + return; + } + + r = osm->routing_engine_list; + while (r->next) + r = r->next; + + r->next = routing_engine; +} + +static void setup_routing_engine(osm_opensm_t *osm, const char *name) +{ + struct osm_routing_engine *re; + const struct routing_engine_module *m; + + for (m = routing_modules; m->name && *m->name; m++) { + if (!strcmp(m->name, name)) { + re = malloc(sizeof(struct osm_routing_engine)); + if (!re) { + OSM_LOG(&osm->log, OSM_LOG_VERBOSE, + "memory allocation failed\n"); + return; + } + memset(re, 0, sizeof(struct osm_routing_engine)); + + re->name = m->name; + if (m->setup(re, osm)) { + OSM_LOG(&osm->log, OSM_LOG_VERBOSE, + "setup of routing" + " engine \'%s\' failed\n", name); + return; + } + OSM_LOG(&osm->log, OSM_LOG_DEBUG, + "\'%s\' routing engine set up\n", re->name); + append_routing_engine(osm, re); + return; + } + } + + OSM_LOG(&osm->log, OSM_LOG_ERROR, + "cannot find or setup routing engine \'%s\'\n", 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 * 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 * 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 * p_osm, + IN const osm_subn_opt_t * 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; + p_osm->log.log_prefix = p_opt->log_prefix; + + /* 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 * p_osm, IN 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 */ + + /* setting IS_SM in capability mask */ + OSM_LOG(&p_osm->log, OSM_LOG_INFO, "Setting IS_SM on port 0x%016" PRIx64 "\n", + cl_ntoh64(guid)); + osm_vendor_set_sm(p_osm->sm.mad_ctrl.h_bind, TRUE); + +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/branches/WOF2-3/ulp/opensm/user/opensm/osm_perfmgr.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_perfmgr.c new file mode 100644 index 00000000..ce271aa5 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_perfmgr.c @@ -0,0 +1,1284 @@ +/* + * Copyright (c) 2007 The Regents of the University of California. + * Copyright (c) 2007-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2009 HNR Consulting. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_perfmgr_t. + * This object implements an IBA performance manager. + * + * Author: + * Ira Weiny, LLNL + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#ifdef ENABLE_OSM_PERF_MGR +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define 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 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 + +/********************************************************************** + * Internal helper functions. + **********************************************************************/ +static 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 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 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 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, + 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 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); + + /* + * get the monitored node struct to have the printable name + * for log 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->num_ports) { + 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->num_ports); + 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 * pm, 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; + bind_info.timeout = pm->subn->opt.transaction_timeout; + bind_info.retries = pm->subn->opt.transaction_retries; + + 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, + perfmgr_mad_recv_callback, + 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)); + } + +Exit: + OSM_LOG_EXIT(pm->log); + return status; +} + +/********************************************************************** + * Unbind the PerfMgr from the vendor layer for MAD sends/receives + **********************************************************************/ +static void perfmgr_mad_unbind(osm_perfmgr_t * 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 = IB_QP1; + + if (mon_node && mon_node->num_ports && port < mon_node->num_ports && + 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->num_ports && port < mon_node->num_ports && + 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 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 * 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 thread if there are 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 * 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 num_ports; + + OSM_LOG_ENTER(pm->log); + + if (cl_qmap_get(&pm->monitored_map, node_guid) + == cl_qmap_end(&pm->monitored_map)) { + /* if not already in map add it */ + num_ports = osm_node_get_num_physp(node); + mon_node = malloc(sizeof(*mon_node) + + sizeof(redir_t) * num_ports); + 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) * num_ports); + mon_node->guid = node_guid; + mon_node->name = strdup(node->print_desc); + mon_node->num_ports = num_ports; + /* check for enhanced switch port 0 */ + mon_node->esp0 = (node->sw && + ib_switch_info_is_enhanced_port0(&node->sw-> + switch_info)); + 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 perfmgr_query_counters(cl_map_item_t * p_map_item, void *context) +{ + ib_api_status_t status = IB_SUCCESS; + osm_perfmgr_t *pm = context; + osm_node_t *node = NULL; + monitored_node_t *mon_node = (monitored_node_t *) p_map_item; + osm_madw_context_t mad_context; + uint64_t node_guid = 0; + ib_net32_t remote_qp; + uint8_t port, num_ports = 0; + + 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 there is a database object ready to store this info */ + if (perfmgr_db_create_entry(pm->db, node_guid, mon_node->esp0, + 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; + } + + /* issue the query for each port */ + for (port = mon_node->esp0 ? 0 : 1; 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 = 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. + * This code should not be here, but merged with main OpenSM + **********************************************************************/ +extern int wait_for_pending_transactions(osm_stats_t * stats); +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 4C84: " + "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 * 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 * 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 * 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 * 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 * p_map_item, void *cxt) +{ + osm_switch_t *p_sw = (osm_switch_t *) p_map_item; + 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, pm); + cl_plock_release(pm->lock); + + /* then for each node query their counters */ + cl_qmap_apply_func(&pm->monitored_map, perfmgr_query_counters, 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); + clear_mad_stats(); +#endif + + pm->sweep_state = PERFMGR_SWEEP_SLEEP; +} + +/********************************************************************** + * PerfMgr timer - loop continuously and signal SM to run PerfMgr + * processor if enabled. + **********************************************************************/ +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 * pm) +{ + OSM_LOG_ENTER(pm->log); + cl_timer_stop(&pm->sweep_timer); + cl_disp_unregister(pm->pc_disp_h); + perfmgr_mad_unbind(pm); + OSM_LOG_EXIT(pm->log); +} + +void osm_perfmgr_destroy(osm_perfmgr_t * 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 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 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 = 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 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 + * there is a thread available to process the mad received on the wire. + **********************************************************************/ +static void pc_recv_process(void *context, void *data) +{ + osm_perfmgr_t *pm = context; + osm_madw_t *p_madw = 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); + + /* + * get the monitored node struct to have the printable name + * for log 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); + + CL_ASSERT(p_mad->attr_id == IB_MAD_ATTR_PORT_CNTRS || + p_mad->attr_id == IB_MAD_ATTR_CLASS_PORT_INFO); + + /* 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->num_ports) { + 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->num_ports); + 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 = 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; + } + + 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) + perfmgr_check_oob_clear(pm, p_mon_node, port, &err_reading, + &data_reading); + + /* log any critical events from this reading */ + 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); + } + + 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 * pm, osm_opensm_t * osm, + const osm_subn_opt_t * p_opt) +{ + ib_api_status_t status; + + 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 = 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; + + status = IB_INSUFFICIENT_RESOURCES; + 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, + pc_recv_process, pm); + if (pm->pc_disp_h == CL_DISP_INVALID_HANDLE) { + perfmgr_db_destroy(pm->db); + goto Exit; + } + + init_monitored_nodes(pm); + + cl_timer_start(&pm->sweep_timer, pm->sweep_time_s * 1000); + + status = IB_SUCCESS; +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"); +} + +/******************************************************************* + * Dump the DB 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)); +} + +/******************************************************************* + * Print the DB 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) + 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/branches/WOF2-3/ulp/opensm/user/opensm/osm_perfmgr_db.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_perfmgr_db.c new file mode 100644 index 00000000..ee0a92a1 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_perfmgr_db.c @@ -0,0 +1,818 @@ +/* + * Copyright (c) 2008-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2007 The Regents of the University of California. + * Copyright (c) 2009 HNR Consulting. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#ifdef ENABLE_OSM_PERF_MGR + +#include +#include +#include +#include +#include + +#include +#include +#include + +static void free_node(db_node_t * node); + +/** ========================================================================= + */ +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 db; +} + +/** ========================================================================= + */ +void perfmgr_db_destroy(perfmgr_db_t * db) +{ + cl_map_item_t *item, *next_item; + + if (db) { + item = cl_qmap_head(&db->pc_data); + while (item != cl_qmap_end(&db->pc_data)) { + next_item = cl_qmap_next(item); + free_node((db_node_t *)item); + item = next_item; + } + 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 >= node->num_ports || (!node->esp0 && port == 0)) + return PERFMGR_EVENT_DB_PORTNOTFOUND; + return PERFMGR_EVENT_DB_SUCCESS; +} + +/** ========================================================================= + */ +static db_node_t *malloc_node(uint64_t guid, boolean_t esp0, + 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; + rc->esp0 = esp0; + + 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, sizeof(rc->node_name), "%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, boolean_t esp0, + 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, esp0, 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; + + 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 = (node->esp0) ? 0 : 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 = (node->esp0) ? 0 : 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; + db_node_t *node; + + 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; + + 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 0x%" 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/branches/WOF2-3/ulp/opensm/user/opensm/osm_pkey.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_pkey.c new file mode 100644 index 00000000..de4fbb5a --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_pkey.c @@ -0,0 +1,427 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2006,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 opensm pkey manipulation functions. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void osm_pkey_tbl_construct(IN osm_pkey_tbl_t * p_pkey_tbl) +{ + cl_ptr_vector_construct(&p_pkey_tbl->blocks); + cl_ptr_vector_construct(&p_pkey_tbl->new_blocks); + cl_map_construct(&p_pkey_tbl->keys); +} + +void osm_pkey_tbl_destroy(IN osm_pkey_tbl_t * p_pkey_tbl) +{ + ib_pkey_table_t *p_block; + uint16_t num_blocks, i; + + num_blocks = (uint16_t) (cl_ptr_vector_get_size(&p_pkey_tbl->blocks)); + for (i = 0; i < num_blocks; i++) + if ((p_block = cl_ptr_vector_get(&p_pkey_tbl->blocks, i))) + free(p_block); + cl_ptr_vector_destroy(&p_pkey_tbl->blocks); + + num_blocks = + (uint16_t) (cl_ptr_vector_get_size(&p_pkey_tbl->new_blocks)); + for (i = 0; i < num_blocks; i++) + if ((p_block = cl_ptr_vector_get(&p_pkey_tbl->new_blocks, i))) + free(p_block); + cl_ptr_vector_destroy(&p_pkey_tbl->new_blocks); + + cl_map_remove_all(&p_pkey_tbl->keys); + cl_map_destroy(&p_pkey_tbl->keys); +} + +ib_api_status_t osm_pkey_tbl_init(IN osm_pkey_tbl_t * p_pkey_tbl) +{ + cl_ptr_vector_init(&p_pkey_tbl->blocks, 0, 1); + cl_ptr_vector_init(&p_pkey_tbl->new_blocks, 0, 1); + cl_map_init(&p_pkey_tbl->keys, 1); + cl_qlist_init(&p_pkey_tbl->pending); + p_pkey_tbl->used_blocks = 0; + p_pkey_tbl->max_blocks = 0; + return IB_SUCCESS; +} + +void osm_pkey_tbl_init_new_blocks(IN const osm_pkey_tbl_t * p_pkey_tbl) +{ + ib_pkey_table_t *p_block; + size_t b, num_blocks = cl_ptr_vector_get_size(&p_pkey_tbl->new_blocks); + + for (b = 0; b < num_blocks; b++) + if ((p_block = cl_ptr_vector_get(&p_pkey_tbl->new_blocks, b))) + memset(p_block, 0, sizeof(*p_block)); +} + +void osm_pkey_tbl_cleanup_pending(IN osm_pkey_tbl_t * p_pkey_tbl) +{ + cl_list_item_t *p_item; + + p_item = cl_qlist_remove_head(&p_pkey_tbl->pending); + while (p_item != cl_qlist_end(&p_pkey_tbl->pending)) { + free((osm_pending_pkey_t *) p_item); + } +} + +ib_api_status_t osm_pkey_tbl_set(IN osm_pkey_tbl_t * p_pkey_tbl, + IN uint16_t block, IN ib_pkey_table_t * p_tbl) +{ + uint16_t b, i; + ib_pkey_table_t *p_pkey_block; + uint16_t *p_prev_pkey; + ib_net16_t pkey; + + /* make sure the block is allocated */ + if (cl_ptr_vector_get_size(&p_pkey_tbl->blocks) > block) + p_pkey_block = + (ib_pkey_table_t *) cl_ptr_vector_get(&p_pkey_tbl->blocks, + block); + else + p_pkey_block = NULL; + + if (!p_pkey_block) { + p_pkey_block = + (ib_pkey_table_t *) malloc(sizeof(ib_pkey_table_t)); + if (!p_pkey_block) + return IB_ERROR; + memset(p_pkey_block, 0, sizeof(ib_pkey_table_t)); + cl_ptr_vector_set(&p_pkey_tbl->blocks, block, p_pkey_block); + } + + /* sets the block values */ + memcpy(p_pkey_block, p_tbl, sizeof(ib_pkey_table_t)); + + /* + NOTE: as the spec does not require uniqueness of PKeys in + tables there is no other way but to refresh the entire keys map. + + Moreover, if the same key exists but with full membership it should + have precedence on the key with limited membership ! + */ + cl_map_remove_all(&p_pkey_tbl->keys); + + for (b = 0; b < cl_ptr_vector_get_size(&p_pkey_tbl->blocks); b++) { + + p_pkey_block = cl_ptr_vector_get(&p_pkey_tbl->blocks, b); + if (!p_pkey_block) + continue; + + for (i = 0; i < IB_NUM_PKEY_ELEMENTS_IN_BLOCK; i++) { + pkey = p_pkey_block->pkey_entry[i]; + if (ib_pkey_is_invalid(pkey)) + continue; + + /* + ignore the PKey Full Member bit in the key but store + the pointer to the table element as the map value + */ + p_prev_pkey = + cl_map_get(&p_pkey_tbl->keys, + ib_pkey_get_base(pkey)); + + /* we only insert if no previous or it is not full member */ + if ((p_prev_pkey == NULL) || + (cl_ntoh16(*p_prev_pkey) < cl_ntoh16(pkey))) + cl_map_insert(&p_pkey_tbl->keys, + ib_pkey_get_base(pkey), + &(p_pkey_block->pkey_entry[i]) + ); + } + } + return IB_SUCCESS; +} + +/* + Store the given pkey in the "new" blocks array. + Also, make sure the regular block exists. +*/ +ib_api_status_t osm_pkey_tbl_set_new_entry(IN osm_pkey_tbl_t * p_pkey_tbl, + IN uint16_t block_idx, + IN uint8_t pkey_idx, + IN uint16_t pkey) +{ + ib_pkey_table_t *p_block; + + if (!(p_block = osm_pkey_tbl_new_block_get(p_pkey_tbl, block_idx))) { + p_block = (ib_pkey_table_t *) malloc(sizeof(ib_pkey_table_t)); + if (!p_block) + return IB_ERROR; + memset(p_block, 0, sizeof(ib_pkey_table_t)); + cl_ptr_vector_set(&p_pkey_tbl->new_blocks, block_idx, p_block); + } + + p_block->pkey_entry[pkey_idx] = pkey; + if (p_pkey_tbl->used_blocks <= block_idx) + p_pkey_tbl->used_blocks = block_idx + 1; + + return IB_SUCCESS; +} + +boolean_t osm_pkey_find_next_free_entry(IN osm_pkey_tbl_t * p_pkey_tbl, + OUT uint16_t * p_block_idx, + OUT uint8_t * p_pkey_idx) +{ + ib_pkey_table_t *p_new_block; + + CL_ASSERT(p_block_idx); + CL_ASSERT(p_pkey_idx); + + while (*p_block_idx < p_pkey_tbl->max_blocks) { + if (*p_pkey_idx > IB_NUM_PKEY_ELEMENTS_IN_BLOCK - 1) { + *p_pkey_idx = 0; + (*p_block_idx)++; + if (*p_block_idx >= p_pkey_tbl->max_blocks) + return FALSE; + } + + p_new_block = + osm_pkey_tbl_new_block_get(p_pkey_tbl, *p_block_idx); + + if (!p_new_block || + ib_pkey_is_invalid(p_new_block->pkey_entry[*p_pkey_idx])) + return TRUE; + else + (*p_pkey_idx)++; + } + return FALSE; +} + +ib_api_status_t osm_pkey_tbl_get_block_and_idx(IN osm_pkey_tbl_t * p_pkey_tbl, + IN uint16_t * p_pkey, + OUT uint16_t * p_block_idx, + OUT uint8_t * p_pkey_idx) +{ + uint16_t num_of_blocks; + uint16_t block_index; + ib_pkey_table_t *block; + + CL_ASSERT(p_block_idx != NULL); + CL_ASSERT(p_pkey_idx != NULL); + + num_of_blocks = (uint16_t) cl_ptr_vector_get_size(&p_pkey_tbl->blocks); + for (block_index = 0; block_index < num_of_blocks; block_index++) { + block = osm_pkey_tbl_block_get(p_pkey_tbl, block_index); + if ((block->pkey_entry <= p_pkey) && + (p_pkey < + block->pkey_entry + IB_NUM_PKEY_ELEMENTS_IN_BLOCK)) { + *p_block_idx = block_index; + *p_pkey_idx = (uint8_t) (p_pkey - block->pkey_entry); + return IB_SUCCESS; + } + } + return IB_NOT_FOUND; +} + +static boolean_t 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 * p_physp1, + IN const osm_physp_t * p_physp2, + IN 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 && match_pkey(pkey1, pkey2)); +} + +ib_net16_t osm_physp_find_common_pkey(IN const osm_physp_t * p_physp1, + IN const osm_physp_t * 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 (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 * p_physp_1, + IN const osm_physp_t * 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 * p_port_1, + IN const osm_port_t * 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 ib_net16_t pkey, + IN const osm_physp_t * 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/branches/WOF2-3/ulp/opensm/user/opensm/osm_pkey_mgr.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_pkey_mgr.c new file mode 100644 index 00000000..379079c6 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_pkey_mgr.c @@ -0,0 +1,520 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2007 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Copyright (c) 2009 Sun Microsystems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of the P_Key Manager (Partititon Manager). + * This is part of the OpenSM. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + The max number of pkey blocks for a physical port is located in + a different place for switch external ports (SwitchInfo) and the + rest of the ports (NodeInfo). +*/ +static uint16_t +pkey_mgr_get_physp_max_blocks(IN const osm_subn_t * p_subn, + IN const osm_physp_t * p_physp) +{ + osm_node_t *p_node = osm_physp_get_node_ptr(p_physp); + uint16_t num_pkeys = 0; + + if (!p_node->sw || (osm_physp_get_port_num(p_physp) == 0)) + num_pkeys = cl_ntoh16(p_node->node_info.partition_cap); + else + num_pkeys = cl_ntoh16(p_node->sw->switch_info.enforce_cap); + return ((num_pkeys + 31) / 32); +} + +/* + * Insert new pending pkey entry to the specific port pkey table + * pending pkeys. New entries are inserted at the back. + */ +static void +pkey_mgr_process_physical_port(IN osm_log_t * p_log, + IN osm_sm_t * sm, + IN const ib_net16_t pkey, + IN osm_physp_t * p_physp) +{ + osm_node_t *p_node = osm_physp_get_node_ptr(p_physp); + osm_pkey_tbl_t *p_pkey_tbl; + ib_net16_t *p_orig_pkey; + char *stat = NULL; + osm_pending_pkey_t *p_pending; + + p_pkey_tbl = &p_physp->pkeys; + p_pending = (osm_pending_pkey_t *) malloc(sizeof(osm_pending_pkey_t)); + if (!p_pending) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0502: " + "Failed to allocate new pending pkey entry for node " + "0x%016" PRIx64 " port %u\n", + cl_ntoh64(osm_node_get_node_guid(p_node)), + osm_physp_get_port_num(p_physp)); + return; + } + p_pending->pkey = pkey; + p_orig_pkey = cl_map_get(&p_pkey_tbl->keys, ib_pkey_get_base(pkey)); + if (!p_orig_pkey) { + p_pending->is_new = TRUE; + cl_qlist_insert_tail(&p_pkey_tbl->pending, + (cl_list_item_t *) p_pending); + stat = "inserted"; + } else { + CL_ASSERT(ib_pkey_get_base(*p_orig_pkey) == + ib_pkey_get_base(pkey)); + p_pending->is_new = FALSE; + if (osm_pkey_tbl_get_block_and_idx(p_pkey_tbl, p_orig_pkey, + &p_pending->block, + &p_pending->index) != + IB_SUCCESS) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0503: " + "Failed to obtain P_Key 0x%04x block and index " + "for node 0x%016" PRIx64 " port %u\n", + cl_ntoh16(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 ib_api_status_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 (%s)\n", + cl_ntoh64(osm_node_get_node_guid + (osm_physp_get_node_ptr(p_physp))), + osm_physp_get_port_num(p_physp), + p_physp->p_node->print_desc); + return IB_SUCCESS; + } + + memcpy(payload, p_pi, sizeof(ib_port_info_t)); + memset(payload + sizeof(ib_port_info_t), 0, + IB_SMP_DATA_SIZE - 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 (%s)\n", + cl_ntoh64(osm_node_get_node_guid + (osm_physp_get_node_ptr(p_physp))), + osm_physp_get_port_num(p_physp), + p_physp->p_node->print_desc); + else + OSM_LOG(p_log, OSM_LOG_DEBUG, + "Set PortInfo for node 0x%016" PRIx64 " port %u (%s)\n", + cl_ntoh64(osm_node_get_node_guid + (osm_physp_get_node_ptr(p_physp))), + osm_physp_get_port_num(p_physp), + p_physp->p_node->print_desc); + return status; +} + +static int 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; + osm_pending_pkey_t *p_pending; + boolean_t found; + ib_pkey_table_t empty_block; + int ret = 0; + + 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 (%s)\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_physp->p_node->print_desc); + } + 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 (%s)\n", + cl_ntoh16(p_pending->pkey), + cl_ntoh64(osm_node_get_node_guid + (p_node)), + osm_physp_get_port_num(p_physp), + p_physp->p_node->print_desc); + } 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 (%s)\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), + p_physp->p_node->print_desc); + } + } + + 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 (%s)\n", block_index, + cl_ntoh64(osm_node_get_node_guid(p_node)), + osm_physp_get_port_num(p_physp), + p_physp->p_node->print_desc); + 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 (%s)\n", block_index, + cl_ntoh64(osm_node_get_node_guid(p_node)), + osm_physp_get_port_num(p_physp), + p_physp->p_node->print_desc); + ret = -1; + } + } + + return ret; +} + +static int 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; + ib_pkey_table_t empty_block; + int ret = 0; + + memset(&empty_block, 0, sizeof(ib_pkey_table_t)); + + p_physp = p_port->p_physp; + if (!p_physp) + return -1; + peer = osm_physp_get_remote(p_physp); + if (!peer) + return -1; + p_node = osm_physp_get_node_ptr(peer); + if (!p_node->sw || !p_node->sw->switch_info.enforce_cap) + return 0; + + 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 (%s). 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), + p_node->print_desc); + enforce = FALSE; + ret = -1; + } + + if (pkey_mgr_enforce_partition(p_log, sm, peer, enforce)) + ret = -1; + + if (enforce == FALSE) + return ret; + + 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) { + 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 (%s)\n", block_index, + cl_ntoh64(osm_node_get_node_guid + (p_node)), + osm_physp_get_port_num(peer), + p_node->print_desc); + ret = -1; + } + } + } + + if (!ret) + OSM_LOG(p_log, OSM_LOG_DEBUG, + "Pkey table was updated for node 0x%016" PRIx64 + " port %u (%s)\n", + cl_ntoh64(osm_node_get_node_guid(p_node)), + osm_physp_get_port_num(peer), p_node->print_desc); + + return ret; +} + +int 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; + int ret = 0; + + 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"); + ret = -1; + 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)) + ret = -1; + 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)) + ret = -1; + } + +_err: + CL_PLOCK_RELEASE(&p_osm->lock); + OSM_LOG_EXIT(&p_osm->log); + return ret; +} diff --git a/branches/WOF2-3/ulp/opensm/user/opensm/osm_pkey_rcv.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_pkey_rcv.c new file mode 100644 index 00000000..709ef0b4 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_pkey_rcv.c @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * WE 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_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 care 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/branches/WOF2-3/ulp/opensm/user/opensm/osm_port.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_port.c new file mode 100644 index 00000000..11cd01dd --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_port.c @@ -0,0 +1,634 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_physp_t. + * This object represents an Infiniband Port. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include + +void osm_physp_construct(IN osm_physp_t * 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 * 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 * p_physp, IN ib_net64_t port_guid, + IN uint8_t port_num, IN const struct osm_node *p_node, + IN osm_bind_handle_t h_bind, IN uint8_t hop_count, + IN const uint8_t * 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 ** pp_port) +{ + free(*pp_port); + *pp_port = NULL; +} + +osm_port_t *osm_port_new(IN const ib_node_info_t * p_ni, + IN osm_node_t * p_parent_node) +{ + osm_port_t *p_port; + ib_net64_t port_guid; + osm_physp_t *p_physp; + uint8_t port_num; + + p_port = malloc(sizeof(*p_port)); + if (!p_port) + return NULL; + + 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; + + return p_port; +} + +void osm_port_get_lid_range_ho(IN const osm_port_t * p_port, + IN uint16_t * p_min_lid, IN uint16_t * 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); +} + +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); + + if (op_vls == 0) { + /* for non compliant implementations */ + OSM_LOG(p_log, OSM_LOG_VERBOSE, + "Invalid OP_VLS = 0. Forcing correction to 1 (VL0)\n"); + op_vls = 1; + } + + /* support user limitation of max_op_vls */ + if (op_vls > p_subn->opt.max_op_vls) + op_vls = p_subn->opt.max_op_vls; + + OSM_LOG_EXIT(p_log); + return op_vls; +} + +static inline uint64_t ptr_to_key(void const *p) +{ + uint64_t k = 0; + + memcpy(&k, p, sizeof(void *)); + return k; +} + +static inline void *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 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, 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 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, + 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, + 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, + 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); + 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, + ptr_to_key(p_remote_physp)) + == NULL + && cl_map_get(&visited_map, + ptr_to_key + (p_remote_physp)) == NULL) { + /* Insert the port into the visited_map, and save its source port */ + cl_map_insert(&visited_map, + 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 */ + 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 * 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 * 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/branches/WOF2-3/ulp/opensm/user/opensm/osm_port_info_rcv.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_port_info_rcv.c new file mode 100644 index 00000000..ad3e81f6 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_port_info_rcv.c @@ -0,0 +1,618 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2009 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Copyright (c) 2009 HNR Consulting. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_pi_rcv_t. + * This object represents the PortInfo Receiver object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void pi_rcv_check_and_fix_lid(osm_log_t * log, ib_port_info_t * 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 pi_rcv_process_endport(IN osm_sm_t * sm, IN osm_physp_t * p_physp, + IN const ib_port_info_t * 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) { + 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 pi_rcv_process_switch_port(IN osm_sm_t * sm, IN osm_node_t * p_node, + IN osm_physp_t * p_physp, + IN ib_port_info_t * 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); + + if (osm_dr_path_extend(&path, + osm_physp_get_port_num + (p_physp))) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, + "ERR 0F08: " + "DR path with hop count %d couldn't be extended\n", + path.hop_count); + break; + } + + 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 && port_num != 0) + 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; + pi_rcv_process_endport(sm, p_physp, p_pi); + } + + OSM_LOG_EXIT(sm->p_log); +} + +static void pi_rcv_process_ca_or_router_port(IN osm_sm_t * sm, + IN osm_node_t * p_node, + IN osm_physp_t * p_physp, + IN ib_port_info_t * 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); + + 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 * p_node, IN osm_physp_t * 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 pi_rcv_get_pkey_slvl_vla_tables(IN osm_sm_t * sm, + IN osm_node_t * p_node, + IN osm_physp_t * 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 pi_rcv_process_set(IN osm_sm_t * sm, IN osm_node_t * p_node, + IN uint8_t port_num, IN osm_madw_t * 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_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, 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_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) + 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); + + CL_ASSERT(p_physp); + + /* 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: + pi_rcv_process_ca_or_router_port(sm, p_node, p_physp, + p_pi); + break; + case IB_NODE_TYPE_SWITCH: + 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) + 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/branches/WOF2-3/ulp/opensm/user/opensm/osm_prtn.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_prtn.c new file mode 100644 index 00000000..f2493ba5 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_prtn.c @@ -0,0 +1,388 @@ +/* + * Copyright (c) 2006-2009 Voltaire, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_prtn_t. + * This object represents an IBA partition. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern int osm_prtn_config_parse_file(osm_log_t * p_log, osm_subn_t * p_subn, + const char *file_name); + +static uint16_t global_pkey_counter; + +osm_prtn_t *osm_prtn_new(IN const char *name, IN 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 ** 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, unsigned type, 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); + if (!type || osm_node_get_type(p_port->p_node) == type) { + 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->mgrp = p_mgrp; + } + + /* 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->mgrp) + p->mgrp = p_mgrp; + } + + 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 prtn_make_default(osm_log_t * p_log, osm_subn_t * 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, 0, 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 * p_log, osm_subn_t * 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 = 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/branches/WOF2-3/ulp/opensm/user/opensm/osm_prtn_config.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_prtn_config.c new file mode 100644 index 00000000..7f0e6469 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_prtn_config.c @@ -0,0 +1,469 @@ +/* + * 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 partition management configuration + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +struct part_conf { + osm_log_t *p_log; + osm_subn_t *p_subn; + osm_prtn_t *p_prtn; + unsigned is_ipoib, mtu, rate, sl, scope_mask; + boolean_t full; +}; + +extern osm_prtn_t *osm_prtn_make_new(osm_log_t * p_log, osm_subn_t * p_subn, + const char *name, uint16_t pkey); +extern ib_api_status_t osm_prtn_add_all(osm_log_t * p_log, osm_subn_t * p_subn, + osm_prtn_t * p, unsigned type, + boolean_t full); +extern ib_api_status_t osm_prtn_add_port(osm_log_t * p_log, + osm_subn_t * p_subn, osm_prtn_t * p, + ib_net64_t guid, boolean_t full); +extern ib_api_status_t osm_prtn_add_mcgroup(osm_log_t * p_log, + osm_subn_t * p_subn, osm_prtn_t * p, + uint8_t rate, + uint8_t mtu, uint8_t scope); + +static int partition_create(unsigned lineno, struct part_conf *conf, + char *name, char *id, char *flag, char *flag_val) +{ + uint16_t pkey; + unsigned int scope; + + if (!id && name && isdigit(*name)) { + id = name; + name = NULL; + } + + if (id) { + char *end; + + pkey = (uint16_t) strtoul(id, &end, 0); + if (end == id || *end) + return -1; + } else + pkey = 0; + + conf->p_prtn = osm_prtn_make_new(conf->p_log, conf->p_subn, + name, cl_hton16(pkey)); + if (!conf->p_prtn) + return -1; + + if (!conf->p_subn->opt.qos && conf->sl != OSM_DEFAULT_SL) { + OSM_LOG(conf->p_log, OSM_LOG_DEBUG, "Overriding SL %d" + " to default SL %d on partition %s" + " as QoS is not enabled.\n", + conf->sl, OSM_DEFAULT_SL, name); + conf->sl = OSM_DEFAULT_SL; + } + conf->p_prtn->sl = (uint8_t) conf->sl; + + if (!conf->is_ipoib) + return 0; + + if (!conf->scope_mask) { + osm_prtn_add_mcgroup(conf->p_log, conf->p_subn, conf->p_prtn, + (uint8_t) conf->rate, + (uint8_t) conf->mtu, + 0); + return 0; + } + + for (scope = 0; scope < 16; scope++) { + if (((1<scope_mask) == 0) + continue; + + osm_prtn_add_mcgroup(conf->p_log, conf->p_subn, conf->p_prtn, + (uint8_t) conf->rate, + (uint8_t) conf->mtu, + (uint8_t) scope); + } + return 0; +} + +static int partition_add_flag(unsigned lineno, struct part_conf *conf, + char *flag, char *val) +{ + int len = strlen(flag); + if (!strncmp(flag, "ipoib", len)) { + conf->is_ipoib = 1; + } else if (!strncmp(flag, "mtu", len)) { + if (!val || (conf->mtu = strtoul(val, NULL, 0)) == 0) + OSM_LOG(conf->p_log, OSM_LOG_VERBOSE, + "PARSE WARN: line %d: " + "flag \'mtu\' requires valid value" + " - skipped\n", lineno); + } else if (!strncmp(flag, "rate", len)) { + if (!val || (conf->rate = strtoul(val, NULL, 0)) == 0) + OSM_LOG(conf->p_log, OSM_LOG_VERBOSE, + "PARSE WARN: line %d: " + "flag \'rate\' requires valid value" + " - skipped\n", lineno); + } else if (!strncmp(flag, "scope", len)) { + unsigned int scope; + if (!val || (scope = strtoul(val, NULL, 0)) == 0 || scope > 0xF) + OSM_LOG(conf->p_log, OSM_LOG_VERBOSE, + "PARSE WARN: line %d: " + "flag \'scope\' requires valid value" + " - skipped\n", lineno); + else + conf->scope_mask |= (1< 15 || + (*end && !isspace(*end))) + OSM_LOG(conf->p_log, OSM_LOG_VERBOSE, + "PARSE WARN: line %d: " + "flag \'sl\' requires valid value" + " - skipped\n", lineno); + else + conf->sl = sl; + } else if (!strncmp(flag, "defmember", len)) { + if (!val || (strncmp(val, "limited", strlen(val)) + && strncmp(val, "full", strlen(val)))) + OSM_LOG(conf->p_log, OSM_LOG_VERBOSE, + "PARSE WARN: line %d: " + "flag \'defmember\' requires valid value (limited or full)" + " - skipped\n", lineno); + else + conf->full = strncmp(val, "full", strlen(val)) == 0; + } else { + OSM_LOG(conf->p_log, OSM_LOG_VERBOSE, + "PARSE WARN: line %d: " + "unrecognized partition flag \'%s\'" + " - ignored\n", lineno, flag); + } + return 0; +} + +static int partition_add_port(unsigned lineno, struct part_conf *conf, + char *name, char *flag) +{ + osm_prtn_t *p = conf->p_prtn; + ib_net64_t guid; + boolean_t full = conf->full; + + if (!name || !*name || !strncmp(name, "NONE", strlen(name))) + return 0; + + if (flag) { + /* reset default membership to limited */ + full = FALSE; + if (!strncmp(flag, "full", strlen(flag))) + full = TRUE; + else if (strncmp(flag, "limited", strlen(flag))) { + OSM_LOG(conf->p_log, OSM_LOG_VERBOSE, + "PARSE WARN: line %d: " + "unrecognized port flag \'%s\'." + " Assume \'limited\'\n", lineno, flag); + } + } + + if (!strncmp(name, "ALL", strlen(name))) { + return osm_prtn_add_all(conf->p_log, conf->p_subn, p, + 0, full) == IB_SUCCESS ? 0 : -1; + } else if (!strncmp(name, "ALL_CAS", strlen(name))) { + return osm_prtn_add_all(conf->p_log, conf->p_subn, p, + IB_NODE_TYPE_CA, full) == IB_SUCCESS ? 0 : -1; + } else if (!strncmp(name, "ALL_SWITCHES", strlen(name))) { + return osm_prtn_add_all(conf->p_log, conf->p_subn, p, + IB_NODE_TYPE_SWITCH, full) == IB_SUCCESS ? 0 : -1; + } else if (!strncmp(name, "ALL_ROUTERS", strlen(name))) { + return osm_prtn_add_all(conf->p_log, conf->p_subn, p, + IB_NODE_TYPE_ROUTER, full) == IB_SUCCESS ? 0 : -1; + } else if (!strncmp(name, "SELF", strlen(name))) { + guid = cl_ntoh64(conf->p_subn->sm_port_guid); + } else { + char *end; + guid = strtoull(name, &end, 0); + if (!guid || *end) + return -1; + } + + if (osm_prtn_add_port(conf->p_log, conf->p_subn, p, + cl_hton64(guid), full) != IB_SUCCESS) + return -1; + + return 0; +} + +/* conf file parser */ + +#define STRIP_HEAD_SPACES(p) while (*(p) == ' ' || *(p) == '\t' || \ + *(p) == '\n') { (p)++; } +#define STRIP_TAIL_SPACES(p) { char *q = (p) + strlen(p); \ + while ( q != (p) && ( *q == '\0' || \ + *q == ' ' || *q == '\t' || \ + *q == '\n')) { *q-- = '\0'; }; } + +static int parse_name_token(char *str, char **name, char **val) +{ + int len = 0; + char *p, *q; + + *name = *val = NULL; + + p = str; + + while (*p == ' ' || *p == '\t' || *p == '\n') + p++; + + q = strchr(p, '='); + if (q) + *q++ = '\0'; + + len = strlen(str) + 1; + str = q; + + q = p + strlen(p); + while (q != p && (*q == '\0' || *q == ' ' || *q == '\t' || *q == '\n')) + *q-- = '\0'; + + *name = p; + + p = str; + if (!p) + return len; + + while (*p == ' ' || *p == '\t' || *p == '\n') + p++; + + q = p + strlen(p); + len += (int)(q - str) + 1; + while (q != p && (*q == '\0' || *q == ' ' || *q == '\t' || *q == '\n')) + *q-- = '\0'; + *val = p; + + return len; +} + +static struct part_conf *new_part_conf(osm_log_t * p_log, osm_subn_t * p_subn) +{ + static struct part_conf part; + struct part_conf *conf = ∂ + + memset(conf, 0, sizeof(*conf)); + conf->p_log = p_log; + conf->p_subn = p_subn; + conf->p_prtn = NULL; + conf->is_ipoib = 0; + conf->sl = OSM_DEFAULT_SL; + conf->full = FALSE; + return conf; +} + +static int flush_part_conf(struct part_conf *conf) +{ + memset(conf, 0, sizeof(*conf)); + return 0; +} + +static int parse_part_conf(struct part_conf *conf, char *str, int lineno) +{ + int ret, len = 0; + char *name, *id, *flag, *flval; + char *q, *p; + + p = str; + if (*p == '\t' || *p == '\0' || *p == '\n') + p++; + + len += (int)(p - str); + str = p; + + if (conf->p_prtn) + goto skip_header; + + q = strchr(p, ':'); + if (!q) { + OSM_LOG(conf->p_log, OSM_LOG_ERROR, "PARSE ERROR: line %d: " + "no partition definition found\n", lineno); + fprintf(stderr, "\nPARSE ERROR: line %d: " + "no partition definition found\n", lineno); + return -1; + } + + *q++ = '\0'; + str = q; + + name = id = flag = flval = NULL; + + q = strchr(p, ','); + if (q) + *q = '\0'; + + ret = parse_name_token(p, &name, &id); + p += ret; + len += ret; + + while (q) { + flag = flval = NULL; + q = strchr(p, ','); + if (q) + *q++ = '\0'; + ret = parse_name_token(p, &flag, &flval); + if (!flag) { + OSM_LOG(conf->p_log, OSM_LOG_ERROR, + "PARSE ERROR: line %d: " + "bad partition flags\n", lineno); + fprintf(stderr, "\nPARSE ERROR: line %d: " + "bad partition flags\n", lineno); + return -1; + } + p += ret; + len += ret; + partition_add_flag(lineno, conf, flag, flval); + } + + if (p != str || (partition_create(lineno, conf, + name, id, flag, flval) < 0)) { + OSM_LOG(conf->p_log, OSM_LOG_ERROR, "PARSE ERROR: line %d: " + "bad partition definition\n", lineno); + fprintf(stderr, "\nPARSE ERROR: line %d: " + "bad partition definition\n", lineno); + return -1; + } + +skip_header: + do { + name = flag = NULL; + q = strchr(p, ','); + if (q) + *q++ = '\0'; + ret = parse_name_token(p, &name, &flag); + if (partition_add_port(lineno, conf, name, flag) < 0) { + OSM_LOG(conf->p_log, OSM_LOG_ERROR, + "PARSE ERROR: line %d: " + "bad PortGUID\n", lineno); + fprintf(stderr, "PARSE ERROR: line %d: " + "bad PortGUID\n", lineno); + return -1; + } + p += ret; + len += ret; + } while (q); + + return len; +} + +int osm_prtn_config_parse_file(osm_log_t * p_log, osm_subn_t * p_subn, + const char *file_name) +{ + char line[1024]; + struct part_conf *conf = NULL; + FILE *file; + int lineno; + + file = fopen(file_name, "r"); + if (!file) { + OSM_LOG(p_log, OSM_LOG_VERBOSE, + "Cannot open config file \'%s\': %s\n", + file_name, strerror(errno)); + return -1; + } + + lineno = 0; + + while (fgets(line, sizeof(line) - 1, file) != NULL) { + char *q, *p = line; + + lineno++; + + p = line; + + q = strchr(p, '#'); + if (q) + *q = '\0'; + + do { + int len; + while (*p == ' ' || *p == '\t' || *p == '\n') + p++; + if (*p == '\0') + break; + + if (!conf && !(conf = new_part_conf(p_log, p_subn))) { + OSM_LOG(conf->p_log, OSM_LOG_ERROR, + "PARSE ERROR: line %d: " + "internal: cannot create config\n", + lineno); + fprintf(stderr, + "PARSE ERROR: line %d: " + "internal: cannot create config\n", + lineno); + break; + } + + q = strchr(p, ';'); + if (q) + *q = '\0'; + + len = parse_part_conf(conf, p, lineno); + if (len < 0) { + break; + } + + p += len; + + if (q) { + flush_part_conf(conf); + conf = NULL; + } + } while (q); + } + + fclose(file); + + return 0; +} diff --git a/branches/WOF2-3/ulp/opensm/user/opensm/osm_qos.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_qos.c new file mode 100644 index 00000000..45991b42 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_qos.c @@ -0,0 +1,393 @@ +/* + * Copyright (c) 2006-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2009 HNR Consulting. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of OpenSM QoS infrastructure primitives + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +struct qos_config { + uint8_t max_vls; + uint8_t vl_high_limit; + ib_vl_arb_table_t vlarb_high[2]; + ib_vl_arb_table_t vlarb_low[2]; + ib_slvl_table_t sl2vl; +}; + +static void qos_build_config(struct qos_config *cfg, osm_qos_options_t * opt, + osm_qos_options_t * dflt); + +/* + * QoS primitives + */ +static ib_api_status_t vlarb_update_table_block(osm_sm_t * sm, + osm_physp_t * p, + uint8_t port_num, + unsigned force_update, + const ib_vl_arb_table_t * + table_block, + unsigned block_length, + unsigned block_num) +{ + ib_vl_arb_table_t block; + osm_madw_context_t context; + uint32_t attr_mod; + unsigned vl_mask, i; + ib_api_status_t status; + + 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; + + status = 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); + if (status != IB_SUCCESS) + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 6202 : " + "failed to update VLArbitration tables " + "for port %" PRIx64 " block %u\n", + cl_ntoh64(p->port_guid), block_num); + + return status; +} + +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, uint32_t attr_mod, + 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); + ib_api_status_t status; + 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; + status = 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); + if (status != IB_SUCCESS) + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 6203 : " + "failed to update SL2VLMapping tables " + "for port %" PRIx64 ", attr_mod 0x%x\n", + cl_ntoh64(p->port_guid), attr_mod); + return status; +} + +static int qos_extports_setup(osm_sm_t * sm, osm_node_t *node, + const struct qos_config *qcfg) +{ + osm_physp_t *p0, *p; + unsigned force_update; + unsigned num_ports = osm_node_get_num_physp(node); + int ret = 0; + unsigned i, j; + + for (i = 1; i < num_ports; i++) { + p = osm_node_get_physp_ptr(node, i); + force_update = p->need_update || sm->p_subn->need_update; + p->vl_high_limit = qcfg->vl_high_limit; + if (vlarb_update(sm, p, p->port_num, force_update, qcfg)) + ret = -1; + } + + p0 = osm_node_get_physp_ptr(node, 0); + if (!(p0->port_info.capability_mask & IB_PORT_CAP_HAS_SL_MAP)) + return ret; + + if (ib_switch_info_get_opt_sl2vlmapping(&node->sw->switch_info) && + sm->p_subn->opt.use_optimized_slvl) { + p = osm_node_get_physp_ptr(node, 1); + force_update = p->need_update || sm->p_subn->need_update; + return sl2vl_update_table(sm, p, 1, 0x30000, force_update, + &qcfg->sl2vl); + } + + for (i = 1; i < num_ports; i++) { + p = osm_node_get_physp_ptr(node, i); + force_update = p->need_update || sm->p_subn->need_update; + for (j = 0; j < num_ports; j++) + if (sl2vl_update_table(sm, p, i, i << 8 | j, + force_update, &qcfg->sl2vl)) + ret = -1; + } + + return ret; +} + +static int qos_endport_setup(osm_sm_t * sm, osm_physp_t * p, + const struct qos_config *qcfg) +{ + unsigned force_update = p->need_update || sm->p_subn->need_update; + + p->vl_high_limit = qcfg->vl_high_limit; + if (vlarb_update(sm, p, 0, force_update, qcfg)) + return -1; + + if (!(p->port_info.capability_mask & IB_PORT_CAP_HAS_SL_MAP)) + return 0; + + if (sl2vl_update_table(sm, p, 0, 0, force_update, &qcfg->sl2vl)) + return -1; + + return 0; +} + +int 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; + osm_node_t *p_node; + int ret = 0; + + if (!p_osm->subn.opt.qos) + return 0; + + 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) { + if (qos_extports_setup(&p_osm->sm, p_node, &swe_config)) + ret = -1; + + /* 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; + + if (qos_endport_setup(&p_osm->sm, p_port->p_physp, cfg)) + ret = -1; + } + + cl_plock_release(&p_osm->lock); + OSM_LOG_EXIT(&p_osm->log); + + return ret; +} + +/* + * 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/branches/WOF2-3/ulp/opensm/user/opensm/osm_qos_parser_l.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_qos_parser_l.c new file mode 100644 index 00000000..e7526615 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_qos_parser_l.c @@ -0,0 +1,2679 @@ + +#line 3 "osm_qos_parser_l.c" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 +#define YY_FLEX_SUBMINOR_VERSION 35 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#ifdef __WIN__ +#include +#include +#define isatty _isatty +#endif +#include +#include +#include +#include + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have . Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; +#endif /* ! C99 */ + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#endif /* ! FLEXINT_H */ + +#ifdef __cplusplus + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +/* C99 requires __STDC__ to be defined as 1. */ +#if defined (__STDC__) + +#define YY_USE_CONST + +#endif /* defined (__STDC__) */ +#endif /* ! __cplusplus */ + +#ifdef YY_USE_CONST +#define yyconst const +#else +#define yyconst +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an unsigned + * integer for use as an array index. If the signed char is negative, + * we want to instead treat it as an 8-bit unsigned char, hence the + * double cast. + */ +#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN (yy_start) = 1 + 2 * + +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START (((yy_start) - 1) / 2) +#define YYSTATE YY_START + +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) + +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE yyrestart(yyin ) + +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#define YY_BUF_SIZE 16384 +#endif + +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +extern int yyleng; + +extern FILE *yyin, *yyout; + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + + #define YY_LESS_LINENO(n) + +/* Return all but the first "n" matched characters back to the input stream. */ +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + *yy_cp = (yy_hold_char); \ + YY_RESTORE_YY_MORE_OFFSET \ + (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) + +#define unput(c) yyunput( c, (yytext_ptr) ) + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + yy_size_t yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +/* Stack of input buffers. */ +static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ +static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ +static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */ + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + * + * Returns the top of the stack, or NULL. + */ +#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ + ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ + : NULL) + +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] + +/* yy_hold_char holds the character lost when yytext is formed. */ +static char yy_hold_char; +static int yy_n_chars; /* number of characters read into yy_ch_buf */ +int yyleng; + +/* Points to current character in buffer. */ +static char *yy_c_buf_p = (char *) 0; +static int yy_init = 0; /* whether we need to initialize */ +static int yy_start = 0; /* start state number */ + +/* Flag which is used to allow yywrap()'s to do buffer switches + * instead of setting up a fresh yyin. A bit of a hack ... + */ +static int yy_did_buffer_switch_on_eof; + +void yyrestart (FILE *input_file ); +void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ); +YY_BUFFER_STATE yy_create_buffer (FILE *file,int size ); +void yy_delete_buffer (YY_BUFFER_STATE b ); +void yy_flush_buffer (YY_BUFFER_STATE b ); +void yypush_buffer_state (YY_BUFFER_STATE new_buffer ); +void yypop_buffer_state (void ); + +static void yyensure_buffer_stack (void ); +static void yy_load_buffer_state (void ); +static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file ); + +#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER ) + +YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size ); +YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ); +YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len ); + +void *yyalloc (yy_size_t ); +void *yyrealloc (void *,yy_size_t ); +void yyfree (void * ); + +#define yy_new_buffer yy_create_buffer + +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! YY_CURRENT_BUFFER ){ \ + yyensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer(yyin,YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ + } + +#define yy_set_bol(at_bol) \ + { \ + if ( ! YY_CURRENT_BUFFER ){\ + yyensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer(yyin,YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ + } + +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + +/* Begin user sect3 */ + +typedef unsigned char YY_CHAR; + +FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; + +typedef int yy_state_type; + +extern int yylineno; + +int yylineno = 1; + +extern char *yytext; +#define yytext_ptr yytext + +static yy_state_type yy_get_previous_state (void ); +static yy_state_type yy_try_NUL_trans (yy_state_type current_state ); +static int yy_get_next_buffer (void ); +static void yy_fatal_error (yyconst char msg[] ); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + (yytext_ptr) = yy_bp; \ + yyleng = (size_t) (yy_cp - yy_bp); \ + (yy_hold_char) = *yy_cp; \ + *yy_cp = '\0'; \ + (yy_c_buf_p) = yy_cp; + +#define YY_NUM_RULES 82 +#define YY_END_OF_BUFFER 83 +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct yy_trans_info + { + flex_int32_t yy_verify; + flex_int32_t yy_nxt; + }; +static yyconst flex_int16_t yy_accept[551] = + { 0, + 0, 0, 83, 81, 3, 4, 81, 81, 79, 78, + 76, 75, 75, 77, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 3, 2, 0, 80, 0, 1, + 75, 0, 0, 0, 57, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 74, 60, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 45, 0, 0, 39, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 67, 0, 0, + 0, 65, 59, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 45, 0, 39, 0, 34, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 69, 0, + 0, 67, 0, 0, 0, 65, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, + 33, 0, 0, 0, 0, 0, 54, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 34, 0, 0, + + 0, 0, 0, 0, 0, 0, 72, 0, 0, 69, + 0, 56, 0, 0, 58, 0, 0, 0, 0, 0, + 0, 40, 0, 35, 0, 33, 0, 0, 0, 0, + 54, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 72, 0, 0, 0, 0, 0, 0, 43, 0, 0, + 0, 0, 0, 35, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 51, 0, 0, 0, 0, 0, 63, 0, + 0, 0, 61, 0, 0, 0, 0, 0, 0, 0, + + 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, + 0, 0, 0, 51, 0, 0, 0, 0, 0, 0, + 0, 61, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 23, 0, 11, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 73, 0, 0, 0, 0, 0, 0, 41, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 46, 0, 32, + 0, 0, 31, 0, 49, 9, 0, 29, 0, 30, + + 0, 50, 0, 21, 0, 0, 0, 0, 0, 0, + 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 46, 32, 0, 31, 49, 7, 29, + 30, 50, 0, 0, 0, 47, 0, 53, 19, 0, + 0, 0, 36, 37, 15, 0, 0, 0, 0, 68, + 66, 0, 0, 42, 0, 52, 0, 0, 0, 0, + 6, 0, 0, 0, 0, 0, 48, 0, 0, 47, + 53, 0, 44, 17, 0, 36, 13, 0, 0, 70, + 0, 42, 52, 0, 24, 0, 12, 0, 0, 0, + + 0, 48, 0, 0, 44, 0, 62, 0, 0, 10, + 22, 0, 0, 0, 0, 0, 0, 27, 0, 38, + 0, 0, 8, 0, 20, 0, 16, 0, 0, 55, + 25, 38, 0, 0, 0, 18, 14, 55, 0, 0, + 0, 0, 0, 28, 0, 0, 26, 64, 71, 0 + } ; + +static yyconst flex_int32_t yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 1, 4, 5, 1, 1, 1, 1, 1, + 1, 6, 1, 7, 8, 1, 1, 9, 10, 11, + 10, 10, 10, 10, 10, 10, 10, 12, 1, 1, + 1, 1, 1, 1, 13, 14, 15, 16, 17, 18, + 1, 19, 20, 1, 1, 21, 1, 22, 23, 24, + 1, 25, 26, 27, 28, 1, 29, 30, 31, 1, + 1, 1, 1, 1, 1, 1, 32, 33, 34, 35, + + 36, 37, 38, 39, 40, 1, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 30, + 54, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static yyconst flex_int32_t yy_meta[55] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, + 2, 1, 2, 2, 2, 2, 2, 2, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1 + } ; + +static yyconst flex_int16_t yy_base[554] = + { 0, + 0, 0, 759, 760, 53, 760, 754, 754, 760, 760, + 760, 48, 51, 760, 42, 53, 51, 43, 56, 77, + 54, 54, 712, 707, 706, 703, 38, 63, 707, 84, + 115, 706, 701, 707, 71, 760, 744, 760, 744, 760, + 71, 0, 76, 68, 760, 87, 88, 92, 77, 86, + 93, 94, 96, 101, 698, 109, 710, 699, 698, 691, + 698, 705, 104, 703, 690, 688, 686, 113, 154, 684, + 133, 698, 115, 0, 760, 141, 140, 129, 134, 168, + 135, 169, 146, 171, 140, 688, 682, 723, 687, 678, + 720, 691, 690, 684, 674, 684, 668, 671, 712, 683, + + 666, 172, 665, 714, 667, 175, 712, 177, 674, 664, + 184, 186, 164, 179, 192, 193, 194, 709, 180, 196, + 199, 708, 760, 200, 204, 194, 660, 668, 171, 209, + 661, 664, 212, 697, 668, 663, 694, 217, 693, 188, + 692, 659, 656, 695, 662, 693, 231, 692, 653, 659, + 211, 650, 654, 657, 204, 240, 246, 224, 686, 225, + 642, 684, 216, 232, 640, 682, 236, 651, 230, 633, + 637, 635, 634, 636, 635, 253, 674, 254, 635, 260, + 672, 623, 622, 621, 637, 261, 667, 206, 626, 631, + 634, 629, 622, 621, 628, 653, 624, 657, 620, 649, + + 620, 607, 606, 224, 273, 257, 651, 265, 607, 649, + 602, 760, 601, 600, 760, 275, 615, 598, 596, 633, + 611, 640, 277, 639, 597, 637, 584, 629, 596, 595, + 632, 233, 601, 600, 579, 580, 579, 582, 587, 590, + 241, 280, 586, 255, 570, 571, 584, 286, 266, 580, + 618, 571, 568, 567, 578, 294, 258, 613, 564, 563, + 604, 559, 562, 607, 568, 561, 564, 560, 554, 558, + 562, 558, 551, 563, 564, 546, 547, 552, 586, 559, + 560, 297, 589, 582, 549, 543, 553, 554, 760, 545, + 548, 298, 581, 546, 531, 572, 571, 542, 529, 531, + + 573, 534, 565, 271, 530, 538, 520, 533, 528, 523, + 517, 514, 529, 527, 513, 519, 521, 513, 760, 518, + 517, 511, 522, 552, 511, 514, 498, 505, 516, 514, + 497, 544, 491, 536, 499, 498, 491, 495, 305, 494, + 500, 501, 504, 499, 492, 525, 524, 313, 314, 494, + 316, 317, 484, 319, 321, 322, 293, 521, 760, 478, + 492, 480, 483, 484, 484, 325, 476, 479, 484, 511, + 760, 474, 466, 465, 507, 471, 328, 511, 468, 463, + 458, 459, 458, 461, 286, 289, 339, 504, 341, 503, + 468, 342, 501, 343, 500, 452, 344, 498, 345, 497, + + 346, 496, 453, 760, 448, 347, 348, 459, 458, 450, + 350, 359, 490, 455, 454, 481, 442, 436, 443, 442, + 438, 361, 481, 362, 437, 445, 446, 428, 429, 443, + 444, 441, 442, 471, 470, 363, 469, 468, 760, 467, + 466, 465, 434, 414, 364, 462, 365, 461, 760, 366, + 422, 367, 459, 458, 760, 410, 418, 412, 413, 760, + 760, 410, 368, 452, 370, 451, 401, 409, 411, 403, + 760, 403, 414, 401, 412, 379, 442, 400, 400, 439, + 438, 381, 437, 760, 388, 435, 760, 401, 387, 760, + 386, 431, 430, 385, 381, 421, 760, 382, 385, 380, + + 383, 422, 387, 386, 419, 382, 760, 370, 364, 364, + 760, 364, 375, 374, 373, 372, 383, 358, 384, 404, + 397, 396, 760, 352, 760, 353, 760, 352, 385, 398, + 760, 397, 360, 354, 348, 760, 760, 387, 337, 281, + 266, 253, 236, 161, 75, 42, 760, 760, 760, 760, + 415, 417, 63 + } ; + +static yyconst flex_int16_t yy_def[554] = + { 0, + 550, 1, 550, 550, 550, 550, 551, 552, 550, 550, + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + 550, 550, 550, 550, 550, 550, 551, 550, 552, 550, + 550, 553, 550, 550, 550, 550, 550, 550, 550, 550, + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + 550, 550, 550, 553, 550, 550, 550, 550, 550, 550, + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + 550, 550, 550, 550, 550, 550, 550, 550, 550, 0, + 550, 550, 550 + } ; + +static yyconst flex_int16_t yy_nxt[815] = + { 0, + 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 13, 14, 15, 4, 16, 17, 4, 4, 4, 18, + 4, 4, 4, 4, 19, 20, 4, 4, 4, 4, + 4, 21, 4, 16, 22, 23, 24, 25, 4, 18, + 4, 4, 26, 27, 4, 28, 29, 30, 31, 32, + 33, 34, 4, 4, 35, 36, 41, 41, 41, 41, + 41, 41, 43, 44, 74, 45, 47, 46, 48, 61, + 46, 49, 35, 36, 43, 44, 549, 42, 50, 41, + 41, 41, 62, 43, 45, 44, 46, 55, 47, 56, + 49, 48, 51, 52, 63, 43, 75, 44, 76, 49, + + 50, 53, 80, 64, 77, 54, 50, 65, 79, 548, + 78, 51, 52, 81, 83, 67, 82, 75, 49, 84, + 85, 76, 109, 77, 53, 80, 77, 79, 50, 54, + 51, 52, 78, 83, 106, 83, 81, 94, 82, 53, + 85, 84, 111, 54, 107, 77, 110, 112, 114, 51, + 68, 95, 113, 96, 83, 102, 69, 87, 115, 70, + 101, 119, 53, 123, 103, 104, 126, 54, 114, 116, + 120, 113, 124, 102, 117, 121, 106, 125, 147, 118, + 122, 115, 123, 104, 119, 111, 107, 151, 148, 126, + 112, 155, 156, 157, 116, 160, 163, 120, 158, 117, + + 164, 124, 121, 159, 118, 167, 125, 122, 169, 547, + 176, 156, 151, 180, 155, 163, 172, 173, 186, 174, + 177, 189, 175, 181, 204, 208, 160, 169, 187, 190, + 191, 152, 147, 164, 153, 154, 192, 167, 193, 161, + 212, 205, 148, 232, 165, 204, 206, 157, 215, 233, + 248, 207, 158, 168, 176, 223, 152, 159, 249, 153, + 154, 180, 186, 212, 177, 224, 208, 249, 215, 209, + 161, 181, 187, 248, 205, 546, 256, 165, 223, 206, + 270, 282, 257, 271, 207, 168, 258, 292, 224, 280, + 281, 283, 545, 285, 299, 256, 286, 293, 282, 292, + + 403, 544, 250, 287, 288, 258, 377, 300, 283, 293, + 209, 250, 342, 343, 387, 389, 378, 392, 394, 344, + 397, 345, 399, 401, 388, 390, 412, 393, 395, 377, + 398, 543, 400, 402, 430, 431, 413, 432, 433, 378, + 387, 404, 389, 392, 394, 397, 399, 401, 445, 447, + 388, 452, 390, 393, 395, 398, 400, 402, 446, 448, + 412, 453, 463, 465, 476, 445, 447, 482, 452, 463, + 413, 465, 464, 466, 477, 446, 448, 483, 453, 464, + 476, 466, 482, 519, 529, 519, 529, 542, 538, 541, + 477, 540, 483, 520, 530, 520, 530, 539, 532, 538, + + 537, 536, 535, 534, 533, 532, 531, 528, 527, 526, + 525, 524, 523, 522, 484, 37, 37, 39, 39, 521, + 505, 518, 517, 502, 516, 515, 514, 513, 512, 511, + 510, 493, 492, 509, 508, 507, 486, 506, 505, 481, + 480, 504, 503, 502, 501, 500, 499, 498, 497, 496, + 495, 494, 493, 492, 491, 490, 489, 488, 487, 454, + 486, 485, 481, 480, 479, 478, 442, 441, 440, 438, + 437, 435, 434, 475, 474, 473, 472, 471, 470, 469, + 468, 467, 423, 462, 461, 460, 459, 458, 457, 456, + 455, 454, 451, 450, 449, 444, 443, 442, 441, 440, + + 439, 438, 437, 436, 435, 434, 429, 428, 427, 426, + 425, 424, 423, 422, 421, 420, 419, 418, 417, 416, + 415, 414, 411, 410, 409, 408, 407, 406, 405, 396, + 391, 386, 385, 384, 383, 382, 381, 380, 379, 376, + 375, 374, 373, 372, 371, 332, 370, 369, 368, 367, + 366, 365, 364, 324, 363, 362, 361, 360, 359, 358, + 357, 356, 355, 354, 353, 352, 351, 350, 349, 348, + 347, 346, 341, 340, 301, 339, 338, 337, 336, 335, + 334, 333, 332, 331, 330, 329, 328, 327, 326, 325, + 324, 323, 322, 321, 320, 319, 318, 317, 316, 315, + + 314, 313, 312, 311, 310, 309, 308, 307, 264, 306, + 305, 304, 303, 302, 301, 298, 297, 296, 295, 251, + 294, 291, 290, 289, 284, 279, 278, 277, 276, 275, + 274, 273, 272, 231, 269, 268, 267, 266, 226, 265, + 264, 222, 263, 262, 261, 260, 259, 255, 254, 253, + 210, 252, 251, 247, 246, 245, 244, 243, 198, 242, + 241, 240, 239, 238, 237, 236, 235, 234, 231, 230, + 229, 228, 227, 226, 225, 222, 221, 220, 219, 218, + 217, 216, 214, 166, 213, 162, 211, 210, 203, 202, + 201, 200, 199, 198, 146, 197, 144, 196, 195, 194, + + 188, 185, 184, 183, 182, 179, 178, 171, 170, 166, + 162, 150, 149, 146, 145, 144, 143, 142, 141, 140, + 139, 138, 137, 136, 135, 134, 133, 132, 131, 130, + 129, 128, 127, 108, 105, 100, 99, 98, 97, 93, + 92, 91, 90, 89, 88, 86, 40, 38, 73, 72, + 71, 66, 60, 59, 58, 57, 40, 38, 550, 3, + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + 550, 550, 550, 550 + } ; + +static yyconst flex_int16_t yy_chk[815] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 5, 5, 12, 12, 12, 13, + 13, 13, 15, 15, 553, 16, 18, 17, 18, 27, + 22, 19, 35, 35, 21, 21, 546, 12, 19, 41, + 41, 41, 27, 15, 16, 15, 17, 21, 18, 22, + 19, 18, 20, 20, 28, 21, 43, 21, 44, 30, + + 19, 20, 49, 28, 46, 20, 30, 28, 48, 545, + 47, 20, 20, 50, 52, 30, 51, 43, 30, 53, + 54, 44, 73, 46, 20, 49, 56, 48, 30, 20, + 31, 31, 47, 68, 71, 52, 50, 63, 51, 31, + 54, 53, 76, 31, 71, 56, 73, 76, 78, 31, + 31, 63, 77, 63, 68, 69, 31, 56, 79, 31, + 68, 81, 31, 83, 69, 69, 85, 31, 78, 80, + 82, 77, 84, 102, 80, 82, 106, 84, 108, 80, + 82, 79, 83, 102, 81, 111, 106, 112, 108, 85, + 111, 113, 114, 115, 116, 117, 119, 120, 115, 116, + + 121, 124, 120, 115, 116, 125, 124, 120, 126, 544, + 130, 114, 151, 133, 113, 119, 129, 129, 138, 129, + 130, 140, 129, 133, 155, 158, 160, 126, 138, 140, + 140, 112, 147, 164, 112, 112, 140, 167, 140, 117, + 163, 156, 147, 188, 121, 155, 156, 157, 169, 188, + 204, 156, 157, 125, 176, 178, 151, 157, 206, 151, + 151, 180, 186, 163, 176, 178, 208, 249, 169, 158, + 160, 180, 186, 204, 205, 543, 216, 164, 223, 205, + 232, 242, 216, 232, 205, 167, 216, 248, 223, 241, + 241, 242, 542, 244, 257, 256, 244, 248, 282, 292, + + 357, 541, 206, 244, 244, 256, 339, 257, 282, 292, + 208, 249, 304, 304, 348, 349, 339, 351, 352, 304, + 354, 304, 355, 356, 348, 349, 366, 351, 352, 377, + 354, 540, 355, 356, 385, 385, 366, 386, 386, 377, + 387, 357, 389, 392, 394, 397, 399, 401, 406, 407, + 387, 411, 389, 392, 394, 397, 399, 401, 406, 407, + 412, 411, 422, 424, 436, 445, 447, 450, 452, 463, + 412, 465, 422, 424, 436, 445, 447, 450, 452, 463, + 476, 465, 482, 506, 517, 519, 529, 539, 538, 535, + 476, 534, 482, 506, 517, 519, 529, 533, 532, 530, + + 528, 526, 524, 522, 521, 520, 518, 516, 515, 514, + 513, 512, 510, 509, 450, 551, 551, 552, 552, 508, + 505, 504, 503, 502, 501, 500, 499, 498, 496, 495, + 494, 493, 492, 491, 489, 488, 486, 485, 483, 481, + 480, 479, 478, 477, 475, 474, 473, 472, 470, 469, + 468, 467, 466, 464, 462, 459, 458, 457, 456, 454, + 453, 451, 448, 446, 444, 443, 442, 441, 440, 438, + 437, 435, 434, 433, 432, 431, 430, 429, 428, 427, + 426, 425, 423, 421, 420, 419, 418, 417, 416, 415, + 414, 413, 410, 409, 408, 405, 403, 402, 400, 398, + + 396, 395, 393, 391, 390, 388, 384, 383, 382, 381, + 380, 379, 378, 376, 375, 374, 373, 372, 370, 369, + 368, 367, 365, 364, 363, 362, 361, 360, 358, 353, + 350, 347, 346, 345, 344, 343, 342, 341, 340, 338, + 337, 336, 335, 334, 333, 332, 331, 330, 329, 328, + 327, 326, 325, 324, 323, 322, 321, 320, 318, 317, + 316, 315, 314, 313, 312, 311, 310, 309, 308, 307, + 306, 305, 303, 302, 301, 300, 299, 298, 297, 296, + 295, 294, 293, 291, 290, 288, 287, 286, 285, 284, + 283, 281, 280, 279, 278, 277, 276, 275, 274, 273, + + 272, 271, 270, 269, 268, 267, 266, 265, 264, 263, + 262, 261, 260, 259, 258, 255, 254, 253, 252, 251, + 250, 247, 246, 245, 243, 240, 239, 238, 237, 236, + 235, 234, 233, 231, 230, 229, 228, 227, 226, 225, + 224, 222, 221, 220, 219, 218, 217, 214, 213, 211, + 210, 209, 207, 203, 202, 201, 200, 199, 198, 197, + 196, 195, 194, 193, 192, 191, 190, 189, 187, 185, + 184, 183, 182, 181, 179, 177, 175, 174, 173, 172, + 171, 170, 168, 166, 165, 162, 161, 159, 154, 153, + 152, 150, 149, 148, 146, 145, 144, 143, 142, 141, + + 139, 137, 136, 135, 134, 132, 131, 128, 127, 122, + 118, 110, 109, 107, 105, 104, 103, 101, 100, 99, + 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, + 88, 87, 86, 72, 70, 67, 66, 65, 64, 62, + 61, 60, 59, 58, 57, 55, 39, 37, 34, 33, + 32, 29, 26, 25, 24, 23, 8, 7, 3, 550, + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + + 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, + 550, 550, 550, 550 + } ; + +static yy_state_type yy_last_accepting_state; +static char *yy_last_accepting_cpos; + +extern int yy_flex_debug; +int yy_flex_debug = 0; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +char *yytext; +#line 1 "osm_qos_parser_l.l" +#line 2 "osm_qos_parser_l.l" +/* + * Copyright (c) 2004-2006 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: + * Lexer of OSM QoS parser. + * + * Environment: + * Linux User Mode + * + * Author: + * Yevgeny Kliteynik, Mellanox + */ + +#include +#include "osm_qos_parser_y.h" + +#define HANDLE_IF_IN_DESCRIPTION if (in_description) { yylval = strdup(yytext); return TK_TEXT; } + +#define SAVE_POS save_pos() +static void save_pos(); + +extern int column_num; +extern int line_num; +extern FILE * yyin; +extern YYSTYPE yylval; + +boolean_t in_description = FALSE; +boolean_t in_list_of_hex_num_ranges = FALSE; +boolean_t in_node_type = FALSE; +boolean_t in_list_of_numbers = FALSE; +boolean_t in_list_of_strings = FALSE; +boolean_t in_list_of_num_pairs = FALSE; +boolean_t in_asterisk_or_list_of_numbers = FALSE; +boolean_t in_list_of_num_ranges = FALSE; +boolean_t in_single_string = FALSE; +boolean_t in_single_number = FALSE; + +static void reset_new_line_flags(); +#define RESET_NEW_LINE_FLAGS reset_new_line_flags() + +#define START_USE {in_description = TRUE;} /* list of strings including whitespace (description) */ +#define START_PORT_GUID {in_list_of_hex_num_ranges = TRUE;} /* comma-separated list of hex num ranges */ +#define START_PORT_NAME {in_list_of_strings = TRUE;} /* comma-separated list of following strings: ../../.. */ +#define START_PARTITION {in_single_string = TRUE;} /* single string w/o whitespaces (partition name) */ +#define START_NAME {in_single_string = TRUE;} /* single string w/o whitespaces (port group name) */ +#define START_QOS_LEVEL_NAME {in_single_string = TRUE;} /* single string w/o whitespaces (qos level name in match rule) */ + +#define START_NODE_TYPE {in_node_type = TRUE;} /* comma-separated list of node types (ROUTER,CA,...) */ +#define START_SL2VL_TABLE {in_list_of_numbers = TRUE;} /* comma-separated list of hex or dec numbers */ + +#define START_GROUP {in_list_of_strings = TRUE;} /* list of strings w/o whitespaces (group names) */ +#define START_ACROSS {in_list_of_strings = TRUE;} /* list of strings w/o whitespaces (group names) */ +#define START_ACROSS_TO {in_list_of_strings = TRUE;} /* list of strings w/o whitespaces (group names) */ +#define START_ACROSS_FROM {in_list_of_strings = TRUE;} /* list of strings w/o whitespaces (group names) */ +#define START_SOURCE {in_list_of_strings = TRUE;} /* list of strings w/o whitespaces (group names) */ +#define START_DESTINATION {in_list_of_strings = TRUE;} /* list of strings w/o whitespaces (group names) */ + +#define START_VLARB_HIGH {in_list_of_num_pairs = TRUE;} /* comma-separated list of hex or dec num pairs: "num1:num2" */ +#define START_VLARB_LOW {in_list_of_num_pairs = TRUE;} /* comma-separated list of hex or dec num pairs: "num1:num2" */ + +#define START_TO {in_asterisk_or_list_of_numbers = TRUE;} /* (asterisk) or (comma-separated list of hex or dec numbers) */ +#define START_FROM {in_asterisk_or_list_of_numbers = TRUE;} /* (asterisk) or (comma-separated list of hex or dec numbers) */ + +#define START_PATH_BITS {in_list_of_num_ranges = TRUE;} /* comma-separated list of hex or dec num ranges */ +#define START_QOS_CLASS {in_list_of_num_ranges = TRUE;} /* comma-separated list of hex or dec num ranges */ +#define START_SERVICE_ID {in_list_of_num_ranges = TRUE;} /* comma-separated list of hex or dec num ranges */ +#define START_PKEY {in_list_of_num_ranges = TRUE;} /* comma-separated list of hex or dec num ranges */ + +#define START_SL {in_single_number = TRUE;} /* single number */ +#define START_VLARB_HIGH_LIMIT {in_single_number = TRUE;} /* single number */ +#define START_MTU_LIMIT {in_single_number = TRUE;} /* single number */ +#define START_RATE_LIMIT {in_single_number = TRUE;} /* single number */ +#define START_PACKET_LIFE {in_single_number = TRUE;} /* single number */ + +#define START_ULP_DEFAULT {in_single_number = TRUE;} /* single number */ +#define START_ULP_ANY {in_list_of_num_ranges = TRUE;} /* comma-separated list of hex or dec num ranges */ +#define START_ULP_SDP_DEFAULT {in_single_number = TRUE;} /* single number */ +#define START_ULP_SDP_PORT {in_list_of_num_ranges = TRUE;} /* comma-separated list of hex or dec num ranges */ +#define START_ULP_RDS_DEFAULT {in_single_number = TRUE;} /* single number */ +#define START_ULP_RDS_PORT {in_list_of_num_ranges = TRUE;} /* comma-separated list of hex or dec num ranges */ +#define START_ULP_ISER_DEFAULT {in_single_number = TRUE;} /* single number */ +#define START_ULP_ISER_PORT {in_list_of_num_ranges = TRUE;} /* comma-separated list of hex or dec num ranges */ +#define START_ULP_SRP_GUID {in_list_of_num_ranges = TRUE;} /* comma-separated list of hex or dec num ranges */ +#define START_ULP_IPOIB_DEFAULT {in_single_number = TRUE;} /* single number */ +#define START_ULP_IPOIB_PKEY {in_list_of_num_ranges = TRUE;} /* comma-separated list of hex or dec num ranges */ + + +#define YY_NO_INPUT 1 +#line 933 "osm_qos_parser_l.c" + +#define INITIAL 0 + +#ifndef YY_NO_UNISTD_H +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +#include +#endif + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +static int yy_init_globals (void ); + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int yylex_destroy (void ); + +int yyget_debug (void ); + +void yyset_debug (int debug_flag ); + +YY_EXTRA_TYPE yyget_extra (void ); + +void yyset_extra (YY_EXTRA_TYPE user_defined ); + +FILE *yyget_in (void ); + +void yyset_in (FILE * in_str ); + +FILE *yyget_out (void ); + +void yyset_out (FILE * out_str ); + +int yyget_leng (void ); + +char *yyget_text (void ); + +int yyget_lineno (void ); + +void yyset_lineno (int line_number ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap (void ); +#else +extern int yywrap (void ); +#endif +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy (char *,yyconst char *,int ); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * ); +#endif + +#ifndef YY_NO_INPUT + +#ifdef __cplusplus +static int yyinput (void ); +#else +static int input (void ); +#endif + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#define YY_READ_BUF_SIZE 8192 +#endif + +/* Copy whatever the last rule matched to the standard output. */ +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO fwrite( yytext, yyleng, 1, yyout ) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ + { \ + int c = '*'; \ + int n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else \ + { \ + errno=0; \ + while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \ + { \ + if( errno != EINTR) \ + { \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + break; \ + } \ + errno=0; \ + clearerr(yyin); \ + } \ + }\ +\ + +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) +#endif + +/* end tables serialization structures and prototypes */ + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int yylex (void); + +#define YY_DECL int yylex (void) +#endif /* !YY_DECL */ + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK break; +#endif + +#define YY_RULE_SETUP \ + YY_USER_ACTION + +/** The main scanner function which does all the work. + */ +YY_DECL +{ + register yy_state_type yy_current_state; + register char *yy_cp, *yy_bp; + register int yy_act; + +#line 201 "osm_qos_parser_l.l" + + + +#line 1117 "osm_qos_parser_l.c" + + if ( !(yy_init) ) + { + (yy_init) = 1; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! (yy_start) ) + (yy_start) = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! YY_CURRENT_BUFFER ) { + yyensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer(yyin,YY_BUF_SIZE ); + } + + yy_load_buffer_state( ); + } + + while ( 1 ) /* loops until end-of-file is reached */ + { + yy_cp = (yy_c_buf_p); + + /* Support of yytext. */ + *yy_cp = (yy_hold_char); + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = (yy_start); +yy_match: + do + { + register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 551 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + ++yy_cp; + } + while ( yy_base[yy_current_state] != 760 ); + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + if ( yy_act == 0 ) + { /* have to back up */ + yy_cp = (yy_last_accepting_cpos); + yy_current_state = (yy_last_accepting_state); + yy_act = yy_accept[yy_current_state]; + } + + YY_DO_BEFORE_ACTION; + +do_action: /* This label is used only to access EOF actions. */ + + switch ( yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = (yy_hold_char); + yy_cp = (yy_last_accepting_cpos); + yy_current_state = (yy_last_accepting_state); + goto yy_find_action; + +case 1: +/* rule 1 can match eol */ +YY_RULE_SETUP +#line 204 "osm_qos_parser_l.l" +{ SAVE_POS; RESET_NEW_LINE_FLAGS; } /* swallow comment */ + YY_BREAK +case 2: +/* rule 2 can match eol */ +YY_RULE_SETUP +#line 205 "osm_qos_parser_l.l" +{ SAVE_POS; RESET_NEW_LINE_FLAGS; } /* trailing blanks with new line */ + YY_BREAK +case 3: +YY_RULE_SETUP +#line 206 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; } + YY_BREAK +case 4: +/* rule 4 can match eol */ +YY_RULE_SETUP +#line 207 "osm_qos_parser_l.l" +{ SAVE_POS; RESET_NEW_LINE_FLAGS; } + YY_BREAK +case 5: +YY_RULE_SETUP +#line 209 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_QOS_ULPS_START; } + YY_BREAK +case 6: +YY_RULE_SETUP +#line 210 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_QOS_ULPS_END; } + YY_BREAK +case 7: +YY_RULE_SETUP +#line 212 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_PORT_GROUPS_START; } + YY_BREAK +case 8: +YY_RULE_SETUP +#line 213 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_PORT_GROUPS_END; } + YY_BREAK +case 9: +YY_RULE_SETUP +#line 214 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_PORT_GROUP_START; } + YY_BREAK +case 10: +YY_RULE_SETUP +#line 215 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_PORT_GROUP_END; } + YY_BREAK +case 11: +YY_RULE_SETUP +#line 217 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_QOS_SETUP_START; } + YY_BREAK +case 12: +YY_RULE_SETUP +#line 218 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_QOS_SETUP_END; } + YY_BREAK +case 13: +YY_RULE_SETUP +#line 219 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_VLARB_TABLES_START; } + YY_BREAK +case 14: +YY_RULE_SETUP +#line 220 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_VLARB_TABLES_END; } + YY_BREAK +case 15: +YY_RULE_SETUP +#line 221 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_VLARB_SCOPE_START; } + YY_BREAK +case 16: +YY_RULE_SETUP +#line 222 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_VLARB_SCOPE_END; } + YY_BREAK +case 17: +YY_RULE_SETUP +#line 224 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_SL2VL_TABLES_START; } + YY_BREAK +case 18: +YY_RULE_SETUP +#line 225 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_SL2VL_TABLES_END; } + YY_BREAK +case 19: +YY_RULE_SETUP +#line 226 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_SL2VL_SCOPE_START; } + YY_BREAK +case 20: +YY_RULE_SETUP +#line 227 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_SL2VL_SCOPE_END; } + YY_BREAK +case 21: +YY_RULE_SETUP +#line 229 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_QOS_LEVELS_START; } + YY_BREAK +case 22: +YY_RULE_SETUP +#line 230 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_QOS_LEVELS_END; } + YY_BREAK +case 23: +YY_RULE_SETUP +#line 231 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_QOS_LEVEL_START; } + YY_BREAK +case 24: +YY_RULE_SETUP +#line 232 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_QOS_LEVEL_END; } + YY_BREAK +case 25: +YY_RULE_SETUP +#line 234 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_QOS_MATCH_RULES_START; } + YY_BREAK +case 26: +YY_RULE_SETUP +#line 235 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_QOS_MATCH_RULES_END; } + YY_BREAK +case 27: +YY_RULE_SETUP +#line 236 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_QOS_MATCH_RULE_START; } + YY_BREAK +case 28: +YY_RULE_SETUP +#line 237 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_QOS_MATCH_RULE_END; } + YY_BREAK +case 29: +YY_RULE_SETUP +#line 239 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_PORT_GUID; return TK_PORT_GUID; } + YY_BREAK +case 30: +YY_RULE_SETUP +#line 240 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_PORT_NAME; return TK_PORT_NAME; } + YY_BREAK +case 31: +YY_RULE_SETUP +#line 241 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_PARTITION; return TK_PARTITION; } + YY_BREAK +case 32: +YY_RULE_SETUP +#line 242 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_NODE_TYPE; return TK_NODE_TYPE; } + YY_BREAK +case 33: +YY_RULE_SETUP +#line 243 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_NAME; return TK_NAME; } + YY_BREAK +case 34: +YY_RULE_SETUP +#line 244 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_USE; return TK_USE; } + YY_BREAK +case 35: +YY_RULE_SETUP +#line 245 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_GROUP; return TK_GROUP; } + YY_BREAK +case 36: +YY_RULE_SETUP +#line 246 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_VLARB_HIGH; return TK_VLARB_HIGH; } + YY_BREAK +case 37: +YY_RULE_SETUP +#line 247 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_VLARB_LOW; return TK_VLARB_LOW; } + YY_BREAK +case 38: +YY_RULE_SETUP +#line 248 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_VLARB_HIGH_LIMIT; return TK_VLARB_HIGH_LIMIT;} + YY_BREAK +case 39: +YY_RULE_SETUP +#line 249 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_TO; return TK_TO; } + YY_BREAK +case 40: +YY_RULE_SETUP +#line 250 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_FROM; return TK_FROM; } + YY_BREAK +case 41: +YY_RULE_SETUP +#line 251 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_ACROSS_TO; return TK_ACROSS_TO; } + YY_BREAK +case 42: +YY_RULE_SETUP +#line 252 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_ACROSS_FROM; return TK_ACROSS_FROM;} + YY_BREAK +case 43: +YY_RULE_SETUP +#line 253 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_ACROSS; return TK_ACROSS; } + YY_BREAK +case 44: +YY_RULE_SETUP +#line 254 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_SL2VL_TABLE; return TK_SL2VL_TABLE;} + YY_BREAK +case 45: +YY_RULE_SETUP +#line 255 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_SL; return TK_SL; } + YY_BREAK +case 46: +YY_RULE_SETUP +#line 256 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_MTU_LIMIT; return TK_MTU_LIMIT; } + YY_BREAK +case 47: +YY_RULE_SETUP +#line 257 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_RATE_LIMIT; return TK_RATE_LIMIT; } + YY_BREAK +case 48: +YY_RULE_SETUP +#line 258 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_PACKET_LIFE; return TK_PACKET_LIFE;} + YY_BREAK +case 49: +YY_RULE_SETUP +#line 259 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_PATH_BITS; return TK_PATH_BITS; } + YY_BREAK +case 50: +YY_RULE_SETUP +#line 260 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_QOS_CLASS; return TK_QOS_CLASS; } + YY_BREAK +case 51: +YY_RULE_SETUP +#line 261 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_SOURCE; return TK_SOURCE; } + YY_BREAK +case 52: +YY_RULE_SETUP +#line 262 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_DESTINATION; return TK_DESTINATION;} + YY_BREAK +case 53: +YY_RULE_SETUP +#line 263 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_SERVICE_ID; return TK_SERVICE_ID; } + YY_BREAK +case 54: +YY_RULE_SETUP +#line 264 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_PKEY; return TK_PKEY; } + YY_BREAK +case 55: +YY_RULE_SETUP +#line 265 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_QOS_LEVEL_NAME; return TK_QOS_LEVEL_NAME;} + YY_BREAK +case 56: +YY_RULE_SETUP +#line 267 "osm_qos_parser_l.l" +{ SAVE_POS; if (in_node_type) return TK_NODE_TYPE_ROUTER; yylval = strdup(yytext); return TK_TEXT; } + YY_BREAK +case 57: +YY_RULE_SETUP +#line 268 "osm_qos_parser_l.l" +{ SAVE_POS; if (in_node_type) return TK_NODE_TYPE_CA; yylval = strdup(yytext); return TK_TEXT; } + YY_BREAK +case 58: +YY_RULE_SETUP +#line 269 "osm_qos_parser_l.l" +{ SAVE_POS; if (in_node_type) return TK_NODE_TYPE_SWITCH; yylval = strdup(yytext); return TK_TEXT; } + YY_BREAK +case 59: +YY_RULE_SETUP +#line 270 "osm_qos_parser_l.l" +{ SAVE_POS; if (in_node_type) return TK_NODE_TYPE_SELF; yylval = strdup(yytext); return TK_TEXT; } + YY_BREAK +case 60: +YY_RULE_SETUP +#line 271 "osm_qos_parser_l.l" +{ SAVE_POS; if (in_node_type) return TK_NODE_TYPE_ALL; yylval = strdup(yytext); return TK_TEXT; } + YY_BREAK +case 61: +YY_RULE_SETUP +#line 273 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_ULP_DEFAULT; return TK_ULP_DEFAULT; } + YY_BREAK +case 62: +YY_RULE_SETUP +#line 274 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_ULP_ANY; return TK_ULP_ANY_SERVICE_ID; } + YY_BREAK +case 63: +YY_RULE_SETUP +#line 275 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_ULP_ANY; return TK_ULP_ANY_PKEY; } + YY_BREAK +case 64: +YY_RULE_SETUP +#line 276 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_ULP_ANY; return TK_ULP_ANY_TARGET_PORT_GUID; } + YY_BREAK +case 65: +YY_RULE_SETUP +#line 278 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_ULP_SDP_DEFAULT; return TK_ULP_SDP_DEFAULT; } + YY_BREAK +case 66: +YY_RULE_SETUP +#line 279 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_ULP_SDP_PORT; return TK_ULP_SDP_PORT; } + YY_BREAK +case 67: +YY_RULE_SETUP +#line 281 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_ULP_RDS_DEFAULT; return TK_ULP_RDS_DEFAULT; } + YY_BREAK +case 68: +YY_RULE_SETUP +#line 282 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_ULP_RDS_PORT; return TK_ULP_RDS_PORT; } + YY_BREAK +case 69: +YY_RULE_SETUP +#line 284 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_ULP_SDP_DEFAULT; return TK_ULP_ISER_DEFAULT; } + YY_BREAK +case 70: +YY_RULE_SETUP +#line 285 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_ULP_SDP_PORT; return TK_ULP_ISER_PORT; } + YY_BREAK +case 71: +YY_RULE_SETUP +#line 287 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_ULP_SRP_GUID; return TK_ULP_SRP_GUID; } + YY_BREAK +case 72: +YY_RULE_SETUP +#line 289 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_ULP_IPOIB_DEFAULT; return TK_ULP_IPOIB_DEFAULT; } + YY_BREAK +case 73: +YY_RULE_SETUP +#line 290 "osm_qos_parser_l.l" +{ SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_ULP_IPOIB_PKEY; return TK_ULP_IPOIB_PKEY; } + YY_BREAK +case 74: +YY_RULE_SETUP +#line 292 "osm_qos_parser_l.l" +{ + SAVE_POS; + yylval = strdup(yytext); + if (in_description || in_list_of_strings || in_single_string) + return TK_TEXT; + return TK_NUMBER; + } + YY_BREAK +case 75: +YY_RULE_SETUP +#line 300 "osm_qos_parser_l.l" +{ + SAVE_POS; + yylval = strdup(yytext); + if (in_description || in_list_of_strings || in_single_string) + return TK_TEXT; + return TK_NUMBER; + } + YY_BREAK +case 76: +YY_RULE_SETUP +#line 309 "osm_qos_parser_l.l" +{ + SAVE_POS; + if (in_description || in_list_of_strings || in_single_string) + { + yylval = strdup(yytext); + return TK_TEXT; + } + return TK_DASH; + } + YY_BREAK +case 77: +YY_RULE_SETUP +#line 319 "osm_qos_parser_l.l" +{ + SAVE_POS; + if (in_description || in_list_of_strings || in_single_string) + { + yylval = strdup(yytext); + return TK_TEXT; + } + return TK_DOTDOT; + } + YY_BREAK +case 78: +YY_RULE_SETUP +#line 329 "osm_qos_parser_l.l" +{ + SAVE_POS; + if (in_description) + { + yylval = strdup(yytext); + return TK_TEXT; + } + return TK_COMMA; + } + YY_BREAK +case 79: +YY_RULE_SETUP +#line 339 "osm_qos_parser_l.l" +{ + SAVE_POS; + if (in_description || in_list_of_strings || in_single_string) + { + yylval = strdup(yytext); + return TK_TEXT; + } + return TK_ASTERISK; + } + YY_BREAK +case 80: +/* rule 80 can match eol */ +YY_RULE_SETUP +#line 349 "osm_qos_parser_l.l" +{ + SAVE_POS; + yylval = strdup(&yytext[1]); + yylval[strlen(yylval)-1] = '\0'; + return TK_TEXT; + } + YY_BREAK +case 81: +YY_RULE_SETUP +#line 356 "osm_qos_parser_l.l" +{ SAVE_POS; yylval = strdup(yytext); return TK_TEXT;} + YY_BREAK +case 82: +YY_RULE_SETUP +#line 358 "osm_qos_parser_l.l" +ECHO; + YY_BREAK +#line 1663 "osm_qos_parser_l.c" +case YY_STATE_EOF(INITIAL): + yyterminate(); + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = (yy_hold_char); + YY_RESTORE_YY_MORE_OFFSET + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * yylex(). If so, then we have to assure + * consistency between YY_CURRENT_BUFFER and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( ); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state ); + + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++(yy_c_buf_p); + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = (yy_c_buf_p); + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer( ) ) + { + case EOB_ACT_END_OF_FILE: + { + (yy_did_buffer_switch_on_eof) = 0; + + if ( yywrap( ) ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! (yy_did_buffer_switch_on_eof) ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + (yy_c_buf_p) = + (yytext_ptr) + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( ); + + yy_cp = (yy_c_buf_p); + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + (yy_c_buf_p) = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; + + yy_current_state = yy_get_previous_state( ); + + yy_cp = (yy_c_buf_p); + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ +} /* end of yylex */ + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ +static int yy_get_next_buffer (void) +{ + register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + register char *source = (yytext_ptr); + register int number_to_move, i; + int ret_val; + + if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1; + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; + + else + { + int num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = YY_CURRENT_BUFFER; + + int yy_c_buf_p_offset = + (int) ((yy_c_buf_p) - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = 0; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - + number_to_move - 1; + + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), + (yy_n_chars), (size_t) num_to_read ); + + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + if ( (yy_n_chars) == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + yyrestart(yyin ); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + /* Extend the array by 50%, plus the number we really need. */ + yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ); + if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); + } + + (yy_n_chars) += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; + + (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + + return ret_val; +} + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + + static yy_state_type yy_get_previous_state (void) +{ + register yy_state_type yy_current_state; + register char *yy_cp; + + yy_current_state = (yy_start); + + for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) + { + register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 551 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + } + + return yy_current_state; +} + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) +{ + register int yy_is_jam; + register char *yy_cp = (yy_c_buf_p); + + register YY_CHAR yy_c = 1; + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 551 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + yy_is_jam = (yy_current_state == 550); + + return yy_is_jam ? 0 : yy_current_state; +} + +#ifndef YY_NO_INPUT +#ifdef __cplusplus + static int yyinput (void) +#else + static int input (void) +#endif + +{ + int c; + + *(yy_c_buf_p) = (yy_hold_char); + + if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) + /* This was really a NUL. */ + *(yy_c_buf_p) = '\0'; + + else + { /* need more input */ + int offset = (yy_c_buf_p) - (yytext_ptr); + ++(yy_c_buf_p); + + switch ( yy_get_next_buffer( ) ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + yyrestart(yyin ); + + /*FALLTHROUGH*/ + + case EOB_ACT_END_OF_FILE: + { + if ( yywrap( ) ) + return EOF; + + if ( ! (yy_did_buffer_switch_on_eof) ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(); +#else + return input(); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + (yy_c_buf_p) = (yytext_ptr) + offset; + break; + } + } + } + + c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */ + *(yy_c_buf_p) = '\0'; /* preserve yytext */ + (yy_hold_char) = *++(yy_c_buf_p); + + return c; +} +#endif /* ifndef YY_NO_INPUT */ + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * + * @note This function does not reset the start condition to @c INITIAL . + */ + void yyrestart (FILE * input_file ) +{ + + if ( ! YY_CURRENT_BUFFER ){ + yyensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer(yyin,YY_BUF_SIZE ); + } + + yy_init_buffer(YY_CURRENT_BUFFER,input_file ); + yy_load_buffer_state( ); +} + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * + */ + void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ) +{ + + /* TODO. We should be able to replace this entire function body + * with + * yypop_buffer_state(); + * yypush_buffer_state(new_buffer); + */ + yyensure_buffer_stack (); + if ( YY_CURRENT_BUFFER == new_buffer ) + return; + + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + YY_CURRENT_BUFFER_LVALUE = new_buffer; + yy_load_buffer_state( ); + + /* We don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag + * is looked at is after yywrap() is called, so it's safe + * to go ahead and always set it. + */ + (yy_did_buffer_switch_on_eof) = 1; +} + +static void yy_load_buffer_state (void) +{ + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; + yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; + (yy_hold_char) = *(yy_c_buf_p); +} + +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * + * @return the allocated buffer state. + */ + YY_BUFFER_STATE yy_create_buffer (FILE * file, int size ) +{ + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + yy_init_buffer(b,file ); + + return b; +} + +/** Destroy the buffer. + * @param b a buffer created with yy_create_buffer() + * + */ + void yy_delete_buffer (YY_BUFFER_STATE b ) +{ + + if ( ! b ) + return; + + if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + yyfree((void *) b->yy_ch_buf ); + + yyfree((void *) b ); +} + +#ifndef _UNISTD_H /* assume unistd.h has isatty() for us */ +#ifdef __cplusplus +extern "C" { +#endif +#ifndef __WIN__ +#ifdef __THROW /* this is a gnuism */ +extern int isatty (int ) __THROW; +#else +extern int isatty (int ); +#endif +#endif +#ifdef __cplusplus +} +#endif +#endif + +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a yyrestart() or at EOF. + */ + static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file ) + +{ + int oerrno = errno; + + yy_flush_buffer(b ); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + + /* If b is the current buffer, then yy_init_buffer was _probably_ + * called from yyrestart() or through yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER){ + b->yy_bs_lineno = 1; + b->yy_bs_column = 0; + } + + b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; + + errno = oerrno; +} + +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * + */ + void yy_flush_buffer (YY_BUFFER_STATE b ) +{ + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == YY_CURRENT_BUFFER ) + yy_load_buffer_state( ); +} + +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * + */ +void yypush_buffer_state (YY_BUFFER_STATE new_buffer ) +{ + if (new_buffer == NULL) + return; + + yyensure_buffer_stack(); + + /* This block is copied from yy_switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + (yy_buffer_stack_top)++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from yy_switch_to_buffer. */ + yy_load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; +} + +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * + */ +void yypop_buffer_state (void) +{ + if (!YY_CURRENT_BUFFER) + return; + + yy_delete_buffer(YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + if ((yy_buffer_stack_top) > 0) + --(yy_buffer_stack_top); + + if (YY_CURRENT_BUFFER) { + yy_load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; + } +} + +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +static void yyensure_buffer_stack (void) +{ + int num_to_alloc; + + if (!(yy_buffer_stack)) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ + num_to_alloc = 1; + (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + ); + if ( ! (yy_buffer_stack) ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + + (yy_buffer_stack_max) = num_to_alloc; + (yy_buffer_stack_top) = 0; + return; + } + + if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ + + /* Increase the buffer to prepare for a possible push. */ + int grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = (yy_buffer_stack_max) + grow_size; + (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc + ((yy_buffer_stack), + num_to_alloc * sizeof(struct yy_buffer_state*) + ); + if ( ! (yy_buffer_stack) ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + /* zero only the new slots.*/ + memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); + (yy_buffer_stack_max) = num_to_alloc; + } +} + +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + * + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size ) +{ + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return 0; + + b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); + + b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = 0; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + yy_switch_to_buffer(b ); + + return b; +} + +/** Setup the input buffer state to scan a string. The next call to yylex() will + * scan from a @e copy of @a str. + * @param yystr a NUL-terminated string to scan + * + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + * yy_scan_bytes() instead. + */ +YY_BUFFER_STATE yy_scan_string (yyconst char * yystr ) +{ + + return yy_scan_bytes(yystr,strlen(yystr) ); +} + +/** Setup the input buffer state to scan the given bytes. The next call to yylex() will + * scan from a @e copy of @a bytes. + * @param bytes the byte buffer to scan + * @param len the number of bytes in the buffer pointed to by @a bytes. + * + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, int _yybytes_len ) +{ + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = _yybytes_len + 2; + buf = (char *) yyalloc(n ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); + + for ( i = 0; i < _yybytes_len; ++i ) + buf[i] = yybytes[i]; + + buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; + + b = yy_scan_buffer(buf,n ); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; +} + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +static void yy_fatal_error (yyconst char* msg ) +{ + (void) fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); +} + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + yytext[yyleng] = (yy_hold_char); \ + (yy_c_buf_p) = yytext + yyless_macro_arg; \ + (yy_hold_char) = *(yy_c_buf_p); \ + *(yy_c_buf_p) = '\0'; \ + yyleng = yyless_macro_arg; \ + } \ + while ( 0 ) + +/* Accessor methods (get/set functions) to struct members. */ + +/** Get the current line number. + * + */ +int yyget_lineno (void) +{ + + return yylineno; +} + +/** Get the input stream. + * + */ +FILE *yyget_in (void) +{ + return yyin; +} + +/** Get the output stream. + * + */ +FILE *yyget_out (void) +{ + return yyout; +} + +/** Get the length of the current token. + * + */ +int yyget_leng (void) +{ + return yyleng; +} + +/** Get the current token. + * + */ + +char *yyget_text (void) +{ + return yytext; +} + +/** Set the current line number. + * @param line_number + * + */ +void yyset_lineno (int line_number ) +{ + + yylineno = line_number; +} + +/** Set the input stream. This does not discard the current + * input buffer. + * @param in_str A readable stream. + * + * @see yy_switch_to_buffer + */ +void yyset_in (FILE * in_str ) +{ + yyin = in_str ; +} + +void yyset_out (FILE * out_str ) +{ + yyout = out_str ; +} + +int yyget_debug (void) +{ + return yy_flex_debug; +} + +void yyset_debug (int bdebug ) +{ + yy_flex_debug = bdebug ; +} + +static int yy_init_globals (void) +{ + /* Initialization is the same as for the non-reentrant scanner. + * This function is called from yylex_destroy(), so don't allocate here. + */ + + (yy_buffer_stack) = 0; + (yy_buffer_stack_top) = 0; + (yy_buffer_stack_max) = 0; + (yy_c_buf_p) = (char *) 0; + (yy_init) = 0; + (yy_start) = 0; + +/* Defined in main.c */ +#ifdef YY_STDINIT + yyin = stdin; + yyout = stdout; +#else + yyin = (FILE *) 0; + yyout = (FILE *) 0; +#endif + + /* For future reference: Set errno on error, since we are called by + * yylex_init() + */ + return 0; +} + +/* yylex_destroy is for both reentrant and non-reentrant scanners. */ +int yylex_destroy (void) +{ + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ + yy_delete_buffer(YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + yypop_buffer_state(); + } + + /* Destroy the stack itself. */ + yyfree((yy_buffer_stack) ); + (yy_buffer_stack) = NULL; + + /* Reset the globals. This is important in a non-reentrant scanner so the next time + * yylex() is called, initialization will occur. */ + yy_init_globals( ); + + return 0; +} + +/* + * Internal utility routines. + */ + +#ifndef yytext_ptr +static void yy_flex_strncpy (char* s1, yyconst char * s2, int n ) +{ + register int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; +} +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * s ) +{ + register int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; +} +#endif + +void *yyalloc (yy_size_t size ) +{ + return (void *) malloc( size ); +} + +void *yyrealloc (void * ptr, yy_size_t size ) +{ + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return (void *) realloc( (char *) ptr, size ); +} + +void yyfree (void * ptr ) +{ + free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ +} + +#define YYTABLES_NAME "yytables" + +#line 358 "osm_qos_parser_l.l" + + + + +/********************************************* + *********************************************/ + +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/branches/WOF2-3/ulp/opensm/user/opensm/osm_qos_parser_l.l b/branches/WOF2-3/ulp/opensm/user/opensm/osm_qos_parser_l.l new file mode 100644 index 00000000..a31c79ee --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_qos_parser_l.l @@ -0,0 +1,394 @@ +%{ +/* + * Copyright (c) 2004-2006 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: + * Lexer of OSM QoS parser. + * + * Environment: + * Linux User Mode + * + * Author: + * Yevgeny Kliteynik, Mellanox + */ + +#include +#include "osm_qos_parser_y.h" + +#define HANDLE_IF_IN_DESCRIPTION if (in_description) { yylval = strdup(yytext); return TK_TEXT; } + +#define SAVE_POS save_pos() +static void save_pos(); + +extern int column_num; +extern int line_num; +extern FILE * yyin; +extern YYSTYPE yylval; + +boolean_t in_description = FALSE; +boolean_t in_list_of_hex_num_ranges = FALSE; +boolean_t in_node_type = FALSE; +boolean_t in_list_of_numbers = FALSE; +boolean_t in_list_of_strings = FALSE; +boolean_t in_list_of_num_pairs = FALSE; +boolean_t in_asterisk_or_list_of_numbers = FALSE; +boolean_t in_list_of_num_ranges = FALSE; +boolean_t in_single_string = FALSE; +boolean_t in_single_number = FALSE; + +static void reset_new_line_flags(); +#define RESET_NEW_LINE_FLAGS reset_new_line_flags() + +#define START_USE {in_description = TRUE;} /* list of strings including whitespace (description) */ +#define START_PORT_GUID {in_list_of_hex_num_ranges = TRUE;} /* comma-separated list of hex num ranges */ +#define START_PORT_NAME {in_list_of_strings = TRUE;} /* comma-separated list of following strings: ../../.. */ +#define START_PARTITION {in_single_string = TRUE;} /* single string w/o whitespaces (partition name) */ +#define START_NAME {in_single_string = TRUE;} /* single string w/o whitespaces (port group name) */ +#define START_QOS_LEVEL_NAME {in_single_string = TRUE;} /* single string w/o whitespaces (qos level name in match rule) */ + +#define START_NODE_TYPE {in_node_type = TRUE;} /* comma-separated list of node types (ROUTER,CA,...) */ +#define START_SL2VL_TABLE {in_list_of_numbers = TRUE;} /* comma-separated list of hex or dec numbers */ + +#define START_GROUP {in_list_of_strings = TRUE;} /* list of strings w/o whitespaces (group names) */ +#define START_ACROSS {in_list_of_strings = TRUE;} /* list of strings w/o whitespaces (group names) */ +#define START_ACROSS_TO {in_list_of_strings = TRUE;} /* list of strings w/o whitespaces (group names) */ +#define START_ACROSS_FROM {in_list_of_strings = TRUE;} /* list of strings w/o whitespaces (group names) */ +#define START_SOURCE {in_list_of_strings = TRUE;} /* list of strings w/o whitespaces (group names) */ +#define START_DESTINATION {in_list_of_strings = TRUE;} /* list of strings w/o whitespaces (group names) */ + +#define START_VLARB_HIGH {in_list_of_num_pairs = TRUE;} /* comma-separated list of hex or dec num pairs: "num1:num2" */ +#define START_VLARB_LOW {in_list_of_num_pairs = TRUE;} /* comma-separated list of hex or dec num pairs: "num1:num2" */ + +#define START_TO {in_asterisk_or_list_of_numbers = TRUE;} /* (asterisk) or (comma-separated list of hex or dec numbers) */ +#define START_FROM {in_asterisk_or_list_of_numbers = TRUE;} /* (asterisk) or (comma-separated list of hex or dec numbers) */ + +#define START_PATH_BITS {in_list_of_num_ranges = TRUE;} /* comma-separated list of hex or dec num ranges */ +#define START_QOS_CLASS {in_list_of_num_ranges = TRUE;} /* comma-separated list of hex or dec num ranges */ +#define START_SERVICE_ID {in_list_of_num_ranges = TRUE;} /* comma-separated list of hex or dec num ranges */ +#define START_PKEY {in_list_of_num_ranges = TRUE;} /* comma-separated list of hex or dec num ranges */ + +#define START_SL {in_single_number = TRUE;} /* single number */ +#define START_VLARB_HIGH_LIMIT {in_single_number = TRUE;} /* single number */ +#define START_MTU_LIMIT {in_single_number = TRUE;} /* single number */ +#define START_RATE_LIMIT {in_single_number = TRUE;} /* single number */ +#define START_PACKET_LIFE {in_single_number = TRUE;} /* single number */ + +#define START_ULP_DEFAULT {in_single_number = TRUE;} /* single number */ +#define START_ULP_ANY {in_list_of_num_ranges = TRUE;} /* comma-separated list of hex or dec num ranges */ +#define START_ULP_SDP_DEFAULT {in_single_number = TRUE;} /* single number */ +#define START_ULP_SDP_PORT {in_list_of_num_ranges = TRUE;} /* comma-separated list of hex or dec num ranges */ +#define START_ULP_RDS_DEFAULT {in_single_number = TRUE;} /* single number */ +#define START_ULP_RDS_PORT {in_list_of_num_ranges = TRUE;} /* comma-separated list of hex or dec num ranges */ +#define START_ULP_ISER_DEFAULT {in_single_number = TRUE;} /* single number */ +#define START_ULP_ISER_PORT {in_list_of_num_ranges = TRUE;} /* comma-separated list of hex or dec num ranges */ +#define START_ULP_SRP_GUID {in_list_of_num_ranges = TRUE;} /* comma-separated list of hex or dec num ranges */ +#define START_ULP_IPOIB_DEFAULT {in_single_number = TRUE;} /* single number */ +#define START_ULP_IPOIB_PKEY {in_list_of_num_ranges = TRUE;} /* comma-separated list of hex or dec num ranges */ + + +%} + +%option nounput noinput + +QOS_ULPS_START qos\-ulps +QOS_ULPS_END end\-qos\-ulps +PORT_GROUPS_START port\-groups +PORT_GROUPS_END end\-port\-groups +PORT_GROUP_START port\-group +PORT_GROUP_END end\-port\-group +PORT_NUM port\-num +NAME name +USE use +PORT_GUID port\-guid +TARGET_PORT_GUID target\-port\-guid +PORT_NAME port\-name +PARTITION partition +NODE_TYPE node\-type +QOS_SETUP_START qos\-setup +QOS_SETUP_END end\-qos\-setup +VLARB_TABLES_START vlarb\-tables +VLARB_TABLES_END end\-vlarb\-tables +VLARB_SCOPE_START vlarb\-scope +VLARB_SCOPE_END end\-vlarb\-scope +GROUP group +ACROSS across +VLARB_HIGH vlarb\-high +VLARB_LOW vlarb\-low +VLARB_HIGH_LIMIT vl\-high\-limit +SL2VL_TABLES_START sl2vl\-tables +SL2VL_TABLES_END end\-sl2vl\-tables +SL2VL_SCOPE_START sl2vl\-scope +SL2VL_SCOPE_END end\-sl2vl\-scope +TO to +FROM from +ACROSS_TO across\-to +ACROSS_FROM across\-from +SL2VL_TABLE sl2vl\-table +QOS_LEVELS_START qos\-levels +QOS_LEVELS_END end\-qos\-levels +QOS_LEVEL_START qos\-level +QOS_LEVEL_END end\-qos\-level +SL sl +MTU_LIMIT mtu\-limit +RATE_LIMIT rate\-limit +PACKET_LIFE packet\-life +PATH_BITS path\-bits +QOS_MATCH_RULES_START qos\-match\-rules +QOS_MATCH_RULES_END end\-qos\-match\-rules +QOS_MATCH_RULE_START qos\-match\-rule +QOS_MATCH_RULE_END end\-qos\-match\-rule +QOS_CLASS qos\-class +SOURCE source +DESTINATION destination +SERVICE_ID service\-id +PKEY pkey +QOS_LEVEL_NAME qos\-level\-name + +ROUTER [Rr][Oo][Uu][Tt][Ee][Rr] +CA [Cc][Aa] +SWITCH [Ss][Ww][Ii][Tt][Cc][Hh] +SELF [Ss][Ee][Ll][Ff] +ALL [Aa][Ll][Ll] + +ULP_SDP [Ss][Dd][Pp] +ULP_SRP [Ss][Rr][Pp] +ULP_RDS [Rr][Dd][Ss] +ULP_IPOIB [Ii][Pp][Oo][Ii][Bb] +ULP_ISER [Ii][Ss][Ee][Rr] +ULP_ANY [Aa][Nn][Yy] +ULP_DEFAULT [Dd][Ee][Ff][Aa][Uu][Ll][Tt] + +WHITE [ \t]+ +NEW_LINE \n +COMMENT \#.*\n +WHITE_DOTDOT_WHITE [ \t]*:[ \t]* +WHITE_COMMA_WHITE [ \t]*,[ \t]* +QUOTED_TEXT \"[^\"]*\" + +%% + + +{COMMENT} { SAVE_POS; RESET_NEW_LINE_FLAGS; } /* swallow comment */ +{WHITE}{NEW_LINE} { SAVE_POS; RESET_NEW_LINE_FLAGS; } /* trailing blanks with new line */ +{WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; } +{NEW_LINE} { SAVE_POS; RESET_NEW_LINE_FLAGS; } + +{QOS_ULPS_START} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_QOS_ULPS_START; } +{QOS_ULPS_END} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_QOS_ULPS_END; } + +{PORT_GROUPS_START} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_PORT_GROUPS_START; } +{PORT_GROUPS_END} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_PORT_GROUPS_END; } +{PORT_GROUP_START} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_PORT_GROUP_START; } +{PORT_GROUP_END} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_PORT_GROUP_END; } + +{QOS_SETUP_START} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_QOS_SETUP_START; } +{QOS_SETUP_END} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_QOS_SETUP_END; } +{VLARB_TABLES_START} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_VLARB_TABLES_START; } +{VLARB_TABLES_END} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_VLARB_TABLES_END; } +{VLARB_SCOPE_START} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_VLARB_SCOPE_START; } +{VLARB_SCOPE_END} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_VLARB_SCOPE_END; } + +{SL2VL_TABLES_START} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_SL2VL_TABLES_START; } +{SL2VL_TABLES_END} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_SL2VL_TABLES_END; } +{SL2VL_SCOPE_START} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_SL2VL_SCOPE_START; } +{SL2VL_SCOPE_END} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_SL2VL_SCOPE_END; } + +{QOS_LEVELS_START} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_QOS_LEVELS_START; } +{QOS_LEVELS_END} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_QOS_LEVELS_END; } +{QOS_LEVEL_START} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_QOS_LEVEL_START; } +{QOS_LEVEL_END} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_QOS_LEVEL_END; } + +{QOS_MATCH_RULES_START} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_QOS_MATCH_RULES_START; } +{QOS_MATCH_RULES_END} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_QOS_MATCH_RULES_END; } +{QOS_MATCH_RULE_START} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_QOS_MATCH_RULE_START; } +{QOS_MATCH_RULE_END} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_QOS_MATCH_RULE_END; } + +{PORT_GUID}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_PORT_GUID; return TK_PORT_GUID; } +{PORT_NAME}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_PORT_NAME; return TK_PORT_NAME; } +{PARTITION}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_PARTITION; return TK_PARTITION; } +{NODE_TYPE}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_NODE_TYPE; return TK_NODE_TYPE; } +{NAME}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_NAME; return TK_NAME; } +{USE}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_USE; return TK_USE; } +{GROUP}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_GROUP; return TK_GROUP; } +{VLARB_HIGH}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_VLARB_HIGH; return TK_VLARB_HIGH; } +{VLARB_LOW}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_VLARB_LOW; return TK_VLARB_LOW; } +{VLARB_HIGH_LIMIT}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_VLARB_HIGH_LIMIT; return TK_VLARB_HIGH_LIMIT;} +{TO}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_TO; return TK_TO; } +{FROM}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_FROM; return TK_FROM; } +{ACROSS_TO}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_ACROSS_TO; return TK_ACROSS_TO; } +{ACROSS_FROM}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_ACROSS_FROM; return TK_ACROSS_FROM;} +{ACROSS}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_ACROSS; return TK_ACROSS; } +{SL2VL_TABLE}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_SL2VL_TABLE; return TK_SL2VL_TABLE;} +{SL}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_SL; return TK_SL; } +{MTU_LIMIT}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_MTU_LIMIT; return TK_MTU_LIMIT; } +{RATE_LIMIT}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_RATE_LIMIT; return TK_RATE_LIMIT; } +{PACKET_LIFE}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_PACKET_LIFE; return TK_PACKET_LIFE;} +{PATH_BITS}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_PATH_BITS; return TK_PATH_BITS; } +{QOS_CLASS}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_QOS_CLASS; return TK_QOS_CLASS; } +{SOURCE}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_SOURCE; return TK_SOURCE; } +{DESTINATION}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_DESTINATION; return TK_DESTINATION;} +{SERVICE_ID}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_SERVICE_ID; return TK_SERVICE_ID; } +{PKEY}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_PKEY; return TK_PKEY; } +{QOS_LEVEL_NAME}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_QOS_LEVEL_NAME; return TK_QOS_LEVEL_NAME;} + +{ROUTER} { SAVE_POS; if (in_node_type) return TK_NODE_TYPE_ROUTER; yylval = strdup(yytext); return TK_TEXT; } +{CA} { SAVE_POS; if (in_node_type) return TK_NODE_TYPE_CA; yylval = strdup(yytext); return TK_TEXT; } +{SWITCH} { SAVE_POS; if (in_node_type) return TK_NODE_TYPE_SWITCH; yylval = strdup(yytext); return TK_TEXT; } +{SELF} { SAVE_POS; if (in_node_type) return TK_NODE_TYPE_SELF; yylval = strdup(yytext); return TK_TEXT; } +{ALL} { SAVE_POS; if (in_node_type) return TK_NODE_TYPE_ALL; yylval = strdup(yytext); return TK_TEXT; } + +{ULP_DEFAULT}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_ULP_DEFAULT; return TK_ULP_DEFAULT; } +{ULP_ANY}{WHITE_COMMA_WHITE}{SERVICE_ID} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_ULP_ANY; return TK_ULP_ANY_SERVICE_ID; } +{ULP_ANY}{WHITE_COMMA_WHITE}{PKEY} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_ULP_ANY; return TK_ULP_ANY_PKEY; } +{ULP_ANY}{WHITE_COMMA_WHITE}{TARGET_PORT_GUID} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_ULP_ANY; return TK_ULP_ANY_TARGET_PORT_GUID; } + +{ULP_SDP}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_ULP_SDP_DEFAULT; return TK_ULP_SDP_DEFAULT; } +{ULP_SDP}{WHITE_COMMA_WHITE}{PORT_NUM} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_ULP_SDP_PORT; return TK_ULP_SDP_PORT; } + +{ULP_RDS}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_ULP_RDS_DEFAULT; return TK_ULP_RDS_DEFAULT; } +{ULP_RDS}{WHITE_COMMA_WHITE}{PORT_NUM} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_ULP_RDS_PORT; return TK_ULP_RDS_PORT; } + +{ULP_ISER}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_ULP_SDP_DEFAULT; return TK_ULP_ISER_DEFAULT; } +{ULP_ISER}{WHITE_COMMA_WHITE}{PORT_NUM} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_ULP_SDP_PORT; return TK_ULP_ISER_PORT; } + +{ULP_SRP}{WHITE_COMMA_WHITE}{TARGET_PORT_GUID} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_ULP_SRP_GUID; return TK_ULP_SRP_GUID; } + +{ULP_IPOIB}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_ULP_IPOIB_DEFAULT; return TK_ULP_IPOIB_DEFAULT; } +{ULP_IPOIB}{WHITE_COMMA_WHITE}{PKEY} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_ULP_IPOIB_PKEY; return TK_ULP_IPOIB_PKEY; } + +0[xX][0-9a-fA-F]+ { + SAVE_POS; + yylval = strdup(yytext); + if (in_description || in_list_of_strings || in_single_string) + return TK_TEXT; + return TK_NUMBER; + } + +[0-9]+ { + SAVE_POS; + yylval = strdup(yytext); + if (in_description || in_list_of_strings || in_single_string) + return TK_TEXT; + return TK_NUMBER; + } + + +- { + SAVE_POS; + if (in_description || in_list_of_strings || in_single_string) + { + yylval = strdup(yytext); + return TK_TEXT; + } + return TK_DASH; + } + +: { + SAVE_POS; + if (in_description || in_list_of_strings || in_single_string) + { + yylval = strdup(yytext); + return TK_TEXT; + } + return TK_DOTDOT; + } + +, { + SAVE_POS; + if (in_description) + { + yylval = strdup(yytext); + return TK_TEXT; + } + return TK_COMMA; + } + +\* { + SAVE_POS; + if (in_description || in_list_of_strings || in_single_string) + { + yylval = strdup(yytext); + return TK_TEXT; + } + return TK_ASTERISK; + } + +{QUOTED_TEXT} { + SAVE_POS; + yylval = strdup(&yytext[1]); + yylval[strlen(yylval)-1] = '\0'; + return TK_TEXT; + } + +. { SAVE_POS; yylval = strdup(yytext); return TK_TEXT;} + +%% + + +/********************************************* + *********************************************/ + +static void save_pos() +{ + int i; + for (i = 0; i < yyleng; i++) + { + if (yytext[i] == '\n') + { + line_num ++; + column_num = 1; + } + else + column_num ++; + } +} + +/********************************************* + *********************************************/ + +static void reset_new_line_flags() +{ + in_description = FALSE; + in_list_of_hex_num_ranges = FALSE; + in_node_type = FALSE; + in_list_of_numbers = FALSE; + in_list_of_strings = FALSE; + in_list_of_num_pairs = FALSE; + in_asterisk_or_list_of_numbers = FALSE; + in_list_of_num_ranges = FALSE; + in_single_string = FALSE; + in_single_number = FALSE; +} diff --git a/branches/WOF2-3/ulp/opensm/user/opensm/osm_qos_parser_y.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_qos_parser_y.c new file mode 100644 index 00000000..68c32556 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_qos_parser_y.c @@ -0,0 +1,5181 @@ + +/* A Bison parser, made by GNU Bison 2.4.1. */ + +/* Skeleton implementation for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 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, see . */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Bison version. */ +#define YYBISON_VERSION "2.4.1" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 0 + +/* Push parsers. */ +#define YYPUSH 0 + +/* Pull parsers. */ +#define YYPULL 1 + +/* Using locations. */ +#define YYLSP_NEEDED 0 + + + +/* Copy the first part of user declarations. */ + +/* Line 189 of yacc.c */ +#line 1 "osm_qos_parser_y.y" + +/* + * Copyright (c) 2004-2009 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 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 + */ + +#ifdef __WIN__ +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __WIN__ +#define malloc +#define free +#define fopen Fopen +#endif + +#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; +#ifndef __WIN__ +extern int errno; +#endif +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; + +/***************************************************/ + + + +/* Line 189 of yacc.c */ +#line 260 "osm_qos_parser_y.c" + +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + +/* Enabling the token table. */ +#ifndef YYTOKEN_TABLE +# define YYTOKEN_TABLE 0 +#endif + + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + TK_NUMBER = 258, + TK_DASH = 259, + TK_DOTDOT = 260, + TK_COMMA = 261, + TK_ASTERISK = 262, + TK_TEXT = 263, + TK_QOS_ULPS_START = 264, + TK_QOS_ULPS_END = 265, + TK_PORT_GROUPS_START = 266, + TK_PORT_GROUPS_END = 267, + TK_PORT_GROUP_START = 268, + TK_PORT_GROUP_END = 269, + TK_QOS_SETUP_START = 270, + TK_QOS_SETUP_END = 271, + TK_VLARB_TABLES_START = 272, + TK_VLARB_TABLES_END = 273, + TK_VLARB_SCOPE_START = 274, + TK_VLARB_SCOPE_END = 275, + TK_SL2VL_TABLES_START = 276, + TK_SL2VL_TABLES_END = 277, + TK_SL2VL_SCOPE_START = 278, + TK_SL2VL_SCOPE_END = 279, + TK_QOS_LEVELS_START = 280, + TK_QOS_LEVELS_END = 281, + TK_QOS_LEVEL_START = 282, + TK_QOS_LEVEL_END = 283, + TK_QOS_MATCH_RULES_START = 284, + TK_QOS_MATCH_RULES_END = 285, + TK_QOS_MATCH_RULE_START = 286, + TK_QOS_MATCH_RULE_END = 287, + TK_NAME = 288, + TK_USE = 289, + TK_PORT_GUID = 290, + TK_PORT_NAME = 291, + TK_PARTITION = 292, + TK_NODE_TYPE = 293, + TK_GROUP = 294, + TK_ACROSS = 295, + TK_VLARB_HIGH = 296, + TK_VLARB_LOW = 297, + TK_VLARB_HIGH_LIMIT = 298, + TK_TO = 299, + TK_FROM = 300, + TK_ACROSS_TO = 301, + TK_ACROSS_FROM = 302, + TK_SL2VL_TABLE = 303, + TK_SL = 304, + TK_MTU_LIMIT = 305, + TK_RATE_LIMIT = 306, + TK_PACKET_LIFE = 307, + TK_PATH_BITS = 308, + TK_QOS_CLASS = 309, + TK_SOURCE = 310, + TK_DESTINATION = 311, + TK_SERVICE_ID = 312, + TK_QOS_LEVEL_NAME = 313, + TK_PKEY = 314, + TK_NODE_TYPE_ROUTER = 315, + TK_NODE_TYPE_CA = 316, + TK_NODE_TYPE_SWITCH = 317, + TK_NODE_TYPE_SELF = 318, + TK_NODE_TYPE_ALL = 319, + TK_ULP_DEFAULT = 320, + TK_ULP_ANY_SERVICE_ID = 321, + TK_ULP_ANY_PKEY = 322, + TK_ULP_ANY_TARGET_PORT_GUID = 323, + TK_ULP_SDP_DEFAULT = 324, + TK_ULP_SDP_PORT = 325, + TK_ULP_RDS_DEFAULT = 326, + TK_ULP_RDS_PORT = 327, + TK_ULP_ISER_DEFAULT = 328, + TK_ULP_ISER_PORT = 329, + TK_ULP_SRP_GUID = 330, + TK_ULP_IPOIB_DEFAULT = 331, + TK_ULP_IPOIB_PKEY = 332 + }; +#endif +/* Tokens. */ +#define TK_NUMBER 258 +#define TK_DASH 259 +#define TK_DOTDOT 260 +#define TK_COMMA 261 +#define TK_ASTERISK 262 +#define TK_TEXT 263 +#define TK_QOS_ULPS_START 264 +#define TK_QOS_ULPS_END 265 +#define TK_PORT_GROUPS_START 266 +#define TK_PORT_GROUPS_END 267 +#define TK_PORT_GROUP_START 268 +#define TK_PORT_GROUP_END 269 +#define TK_QOS_SETUP_START 270 +#define TK_QOS_SETUP_END 271 +#define TK_VLARB_TABLES_START 272 +#define TK_VLARB_TABLES_END 273 +#define TK_VLARB_SCOPE_START 274 +#define TK_VLARB_SCOPE_END 275 +#define TK_SL2VL_TABLES_START 276 +#define TK_SL2VL_TABLES_END 277 +#define TK_SL2VL_SCOPE_START 278 +#define TK_SL2VL_SCOPE_END 279 +#define TK_QOS_LEVELS_START 280 +#define TK_QOS_LEVELS_END 281 +#define TK_QOS_LEVEL_START 282 +#define TK_QOS_LEVEL_END 283 +#define TK_QOS_MATCH_RULES_START 284 +#define TK_QOS_MATCH_RULES_END 285 +#define TK_QOS_MATCH_RULE_START 286 +#define TK_QOS_MATCH_RULE_END 287 +#define TK_NAME 288 +#define TK_USE 289 +#define TK_PORT_GUID 290 +#define TK_PORT_NAME 291 +#define TK_PARTITION 292 +#define TK_NODE_TYPE 293 +#define TK_GROUP 294 +#define TK_ACROSS 295 +#define TK_VLARB_HIGH 296 +#define TK_VLARB_LOW 297 +#define TK_VLARB_HIGH_LIMIT 298 +#define TK_TO 299 +#define TK_FROM 300 +#define TK_ACROSS_TO 301 +#define TK_ACROSS_FROM 302 +#define TK_SL2VL_TABLE 303 +#define TK_SL 304 +#define TK_MTU_LIMIT 305 +#define TK_RATE_LIMIT 306 +#define TK_PACKET_LIFE 307 +#define TK_PATH_BITS 308 +#define TK_QOS_CLASS 309 +#define TK_SOURCE 310 +#define TK_DESTINATION 311 +#define TK_SERVICE_ID 312 +#define TK_QOS_LEVEL_NAME 313 +#define TK_PKEY 314 +#define TK_NODE_TYPE_ROUTER 315 +#define TK_NODE_TYPE_CA 316 +#define TK_NODE_TYPE_SWITCH 317 +#define TK_NODE_TYPE_SELF 318 +#define TK_NODE_TYPE_ALL 319 +#define TK_ULP_DEFAULT 320 +#define TK_ULP_ANY_SERVICE_ID 321 +#define TK_ULP_ANY_PKEY 322 +#define TK_ULP_ANY_TARGET_PORT_GUID 323 +#define TK_ULP_SDP_DEFAULT 324 +#define TK_ULP_SDP_PORT 325 +#define TK_ULP_RDS_DEFAULT 326 +#define TK_ULP_RDS_PORT 327 +#define TK_ULP_ISER_DEFAULT 328 +#define TK_ULP_ISER_PORT 329 +#define TK_ULP_SRP_GUID 330 +#define TK_ULP_IPOIB_DEFAULT 331 +#define TK_ULP_IPOIB_PKEY 332 + + + + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef int YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +#endif + + +/* Copy the second part of user declarations. */ + + +/* Line 264 of yacc.c */ +#line 456 "osm_qos_parser_y.c" + +#ifdef short +# undef short +#endif + +#ifdef YYTYPE_UINT8 +typedef YYTYPE_UINT8 yytype_uint8; +#else +typedef unsigned char yytype_uint8; +#endif + +#ifdef YYTYPE_INT8 +typedef YYTYPE_INT8 yytype_int8; +#elif (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +typedef signed char yytype_int8; +#else +typedef short int yytype_int8; +#endif + +#ifdef YYTYPE_UINT16 +typedef YYTYPE_UINT16 yytype_uint16; +#else +typedef unsigned short int yytype_uint16; +#endif + +#ifdef YYTYPE_INT16 +typedef YYTYPE_INT16 yytype_int16; +#else +typedef short int yytype_int16; +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned int +# endif +#endif + +#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) + +#ifndef YY_ +# if YYENABLE_NLS +# if ENABLE_NLS +# include /* INFRINGES ON USER NAME SPACE */ +# define YY_(msgid) dgettext ("bison-runtime", msgid) +# endif +# endif +# ifndef YY_ +# define YY_(msgid) msgid +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(e) ((void) (e)) +#else +# define YYUSE(e) /* empty */ +#endif + +/* Identity function, used to suppress warnings about constant conditions. */ +#ifndef lint +# define YYID(n) (n) +#else +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static int +YYID (int yyi) +#else +static int +YYID (yyi) + int yyi; +#endif +{ + return yyi; +} +#endif + +#if ! defined yyoverflow || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include /* INFRINGES ON USER NAME SPACE */ +# ifndef _STDLIB_H +# define _STDLIB_H 1 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's `empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined _STDLIB_H \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include /* INFRINGES ON USER NAME SPACE */ +# ifndef _STDLIB_H +# define _STDLIB_H 1 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ + + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yytype_int16 yyss_alloc; + YYSTYPE yyvs_alloc; +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAXIMUM) + +/* Copy COUNT objects from FROM to TO. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(To, From, Count) \ + __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# else +# define YYCOPY(To, From, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (To)[yyi] = (From)[yyi]; \ + } \ + while (YYID (0)) +# endif +# endif + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ + Stack = &yyptr->Stack_alloc; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (YYID (0)) + +#endif + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 3 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 262 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 78 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 165 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 238 +/* YYNRULES -- Number of states. */ +#define YYNSTATES 328 + +/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 332 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ +static const yytype_uint8 yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77 +}; + +#if YYDEBUG +/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in + YYRHS. */ +static const yytype_uint16 yyprhs[] = +{ + 0, 0, 3, 5, 6, 9, 11, 13, 15, 17, + 19, 23, 25, 28, 32, 34, 37, 41, 43, 45, + 46, 49, 51, 53, 55, 57, 59, 61, 63, 67, + 68, 71, 74, 78, 79, 82, 86, 88, 90, 91, + 94, 96, 98, 100, 102, 104, 108, 109, 112, 116, + 118, 120, 121, 124, 126, 128, 130, 132, 134, 136, + 138, 142, 143, 146, 150, 152, 154, 155, 158, 160, + 162, 164, 166, 168, 170, 172, 174, 178, 179, 182, + 186, 188, 190, 191, 194, 196, 198, 200, 202, 204, + 206, 208, 211, 212, 218, 219, 225, 226, 232, 233, + 237, 238, 244, 245, 249, 250, 256, 257, 261, 262, + 268, 269, 275, 276, 280, 281, 287, 289, 291, 293, + 295, 297, 299, 301, 303, 305, 307, 309, 311, 313, + 316, 318, 321, 323, 326, 328, 331, 333, 336, 338, + 341, 343, 346, 348, 350, 354, 356, 358, 360, 362, + 364, 366, 368, 370, 372, 374, 377, 379, 382, 384, + 387, 389, 392, 394, 397, 399, 402, 404, 407, 409, + 412, 414, 417, 419, 422, 424, 427, 429, 431, 433, + 435, 437, 439, 441, 443, 445, 448, 450, 453, 455, + 458, 460, 463, 465, 468, 470, 473, 475, 478, 480, + 483, 485, 488, 490, 493, 495, 498, 500, 503, 505, + 508, 510, 513, 515, 518, 520, 523, 525, 527, 529, + 532, 534, 536, 540, 542, 544, 548, 550, 554, 560, + 562, 564, 566, 568, 572, 578, 582, 584, 586 +}; + +/* YYRHS -- A `-1'-separated list of the rules' RHS. */ +static const yytype_int16 yyrhs[] = +{ + 79, 0, -1, 80, -1, -1, 80, 81, -1, 82, + -1, 84, -1, 91, -1, 107, -1, 114, -1, 9, + 83, 10, -1, 121, -1, 83, 121, -1, 11, 85, + 12, -1, 86, -1, 85, 86, -1, 87, 89, 88, + -1, 13, -1, 14, -1, -1, 89, 90, -1, 147, + -1, 149, -1, 153, -1, 151, -1, 155, -1, 157, + -1, 159, -1, 15, 92, 16, -1, -1, 92, 93, + -1, 92, 100, -1, 17, 94, 18, -1, -1, 94, + 95, -1, 96, 98, 97, -1, 19, -1, 20, -1, + -1, 98, 99, -1, 168, -1, 170, -1, 174, -1, + 176, -1, 172, -1, 21, 101, 22, -1, -1, 101, + 102, -1, 103, 105, 104, -1, 23, -1, 24, -1, + -1, 105, 106, -1, 178, -1, 180, -1, 182, -1, + 184, -1, 186, -1, 188, -1, 196, -1, 25, 108, + 26, -1, -1, 108, 109, -1, 110, 112, 111, -1, + 27, -1, 28, -1, -1, 112, 113, -1, 198, -1, + 200, -1, 202, -1, 204, -1, 206, -1, 208, -1, + 210, -1, 212, -1, 29, 115, 30, -1, -1, 115, + 116, -1, 117, 119, 118, -1, 31, -1, 32, -1, + -1, 119, 120, -1, 214, -1, 216, -1, 222, -1, + 218, -1, 220, -1, 224, -1, 226, -1, 65, 232, + -1, -1, 134, 238, 5, 122, 146, -1, -1, 135, + 238, 5, 123, 146, -1, -1, 136, 238, 5, 124, + 146, -1, -1, 137, 125, 146, -1, -1, 138, 238, + 5, 126, 146, -1, -1, 139, 127, 146, -1, -1, + 140, 238, 5, 128, 146, -1, -1, 141, 129, 146, + -1, -1, 142, 238, 5, 130, 146, -1, -1, 143, + 238, 5, 131, 146, -1, -1, 144, 132, 146, -1, + -1, 145, 238, 5, 133, 146, -1, 66, -1, 67, + -1, 68, -1, 69, -1, 70, -1, 71, -1, 72, + -1, 73, -1, 74, -1, 75, -1, 76, -1, 77, + -1, 232, -1, 148, 228, -1, 33, -1, 150, 228, + -1, 34, -1, 152, 231, -1, 36, -1, 154, 238, + -1, 35, -1, 156, 238, -1, 59, -1, 158, 231, + -1, 37, -1, 160, 161, -1, 38, -1, 162, -1, + 161, 6, 162, -1, 163, -1, 164, -1, 165, -1, + 166, -1, 167, -1, 61, -1, 62, -1, 60, -1, + 64, -1, 63, -1, 169, 231, -1, 39, -1, 171, + 231, -1, 40, -1, 173, 232, -1, 43, -1, 175, + 235, -1, 41, -1, 177, 235, -1, 42, -1, 179, + 231, -1, 39, -1, 181, 231, -1, 40, -1, 183, + 231, -1, 47, -1, 185, 231, -1, 46, -1, 187, + 190, -1, 45, -1, 189, 192, -1, 44, -1, 191, + -1, 194, -1, 7, -1, 193, -1, 195, -1, 7, + -1, 238, -1, 238, -1, 197, 233, -1, 48, -1, + 199, 228, -1, 33, -1, 201, 228, -1, 34, -1, + 203, 232, -1, 49, -1, 205, 232, -1, 50, -1, + 207, 232, -1, 51, -1, 209, 232, -1, 52, -1, + 211, 238, -1, 53, -1, 213, 238, -1, 59, -1, + 215, 228, -1, 34, -1, 217, 238, -1, 54, -1, + 219, 231, -1, 55, -1, 221, 231, -1, 56, -1, + 223, 228, -1, 58, -1, 225, 238, -1, 57, -1, + 227, 238, -1, 59, -1, 229, -1, 230, -1, 229, + 230, -1, 8, -1, 228, -1, 231, 6, 228, -1, + 234, -1, 234, -1, 233, 6, 234, -1, 3, -1, + 236, 5, 237, -1, 235, 6, 236, 5, 237, -1, + 3, -1, 3, -1, 239, -1, 240, -1, 241, 4, + 242, -1, 239, 6, 241, 4, 242, -1, 239, 6, + 240, -1, 3, -1, 3, -1, 3, -1 +}; + +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const yytype_uint16 yyrline[] = +{ + 0, 276, 276, 279, 280, 283, 284, 285, 286, 287, + 311, 314, 315, 344, 347, 348, 351, 354, 359, 365, + 366, 369, 370, 371, 372, 373, 374, 375, 402, 405, + 406, 407, 412, 415, 416, 419, 422, 427, 433, 434, + 449, 450, 451, 452, 453, 458, 461, 462, 465, 468, + 473, 479, 480, 499, 500, 501, 502, 503, 504, 505, + 529, 532, 533, 536, 539, 544, 550, 551, 554, 555, + 556, 557, 558, 559, 560, 561, 583, 586, 587, 590, + 593, 598, 604, 605, 608, 609, 610, 611, 612, 613, + 614, 636, 654, 654, 675, 675, 696, 696, 731, 731, + 744, 744, 777, 777, 790, 790, 823, 823, 836, 836, + 869, 869, 905, 905, 925, 925, 956, 959, 962, 965, + 968, 971, 974, 977, 980, 983, 986, 989, 993, 1032, + 1055, 1060, 1083, 1088, 1154, 1159, 1179, 1184, 1204, 1209, + 1217, 1222, 1227, 1232, 1233, 1236, 1237, 1238, 1239, 1240, + 1243, 1249, 1255, 1261, 1269, 1291, 1308, 1313, 1330, 1335, + 1353, 1358, 1375, 1380, 1397, 1413, 1430, 1435, 1454, 1459, + 1476, 1481, 1499, 1504, 1509, 1514, 1519, 1524, 1525, 1528, + 1535, 1536, 1539, 1546, 1578, 1611, 1654, 1671, 1694, 1699, + 1722, 1727, 1747, 1752, 1772, 1778, 1798, 1804, 1824, 1830, + 1865, 1870, 1903, 1920, 1943, 1948, 1982, 1987, 2004, 2009, + 2026, 2031, 2054, 2059, 2092, 2097, 2130, 2141, 2148, 2149, + 2152, 2159, 2160, 2165, 2168, 2169, 2172, 2180, 2186, 2194, + 2200, 2206, 2209, 2215, 2227, 2239, 2247, 2254, 2260 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "TK_NUMBER", "TK_DASH", "TK_DOTDOT", + "TK_COMMA", "TK_ASTERISK", "TK_TEXT", "TK_QOS_ULPS_START", + "TK_QOS_ULPS_END", "TK_PORT_GROUPS_START", "TK_PORT_GROUPS_END", + "TK_PORT_GROUP_START", "TK_PORT_GROUP_END", "TK_QOS_SETUP_START", + "TK_QOS_SETUP_END", "TK_VLARB_TABLES_START", "TK_VLARB_TABLES_END", + "TK_VLARB_SCOPE_START", "TK_VLARB_SCOPE_END", "TK_SL2VL_TABLES_START", + "TK_SL2VL_TABLES_END", "TK_SL2VL_SCOPE_START", "TK_SL2VL_SCOPE_END", + "TK_QOS_LEVELS_START", "TK_QOS_LEVELS_END", "TK_QOS_LEVEL_START", + "TK_QOS_LEVEL_END", "TK_QOS_MATCH_RULES_START", "TK_QOS_MATCH_RULES_END", + "TK_QOS_MATCH_RULE_START", "TK_QOS_MATCH_RULE_END", "TK_NAME", "TK_USE", + "TK_PORT_GUID", "TK_PORT_NAME", "TK_PARTITION", "TK_NODE_TYPE", + "TK_GROUP", "TK_ACROSS", "TK_VLARB_HIGH", "TK_VLARB_LOW", + "TK_VLARB_HIGH_LIMIT", "TK_TO", "TK_FROM", "TK_ACROSS_TO", + "TK_ACROSS_FROM", "TK_SL2VL_TABLE", "TK_SL", "TK_MTU_LIMIT", + "TK_RATE_LIMIT", "TK_PACKET_LIFE", "TK_PATH_BITS", "TK_QOS_CLASS", + "TK_SOURCE", "TK_DESTINATION", "TK_SERVICE_ID", "TK_QOS_LEVEL_NAME", + "TK_PKEY", "TK_NODE_TYPE_ROUTER", "TK_NODE_TYPE_CA", + "TK_NODE_TYPE_SWITCH", "TK_NODE_TYPE_SELF", "TK_NODE_TYPE_ALL", + "TK_ULP_DEFAULT", "TK_ULP_ANY_SERVICE_ID", "TK_ULP_ANY_PKEY", + "TK_ULP_ANY_TARGET_PORT_GUID", "TK_ULP_SDP_DEFAULT", "TK_ULP_SDP_PORT", + "TK_ULP_RDS_DEFAULT", "TK_ULP_RDS_PORT", "TK_ULP_ISER_DEFAULT", + "TK_ULP_ISER_PORT", "TK_ULP_SRP_GUID", "TK_ULP_IPOIB_DEFAULT", + "TK_ULP_IPOIB_PKEY", "$accept", "head", "qos_policy_entries", + "qos_policy_entry", "qos_ulps_section", "qos_ulps", + "port_groups_section", "port_groups", "port_group", "port_group_start", + "port_group_end", "port_group_entries", "port_group_entry", + "qos_setup_section", "qos_setup_items", "vlarb_tables", + "vlarb_scope_items", "vlarb_scope", "vlarb_scope_start", + "vlarb_scope_end", "vlarb_scope_entries", "vlarb_scope_entry", + "sl2vl_tables", "sl2vl_scope_items", "sl2vl_scope", "sl2vl_scope_start", + "sl2vl_scope_end", "sl2vl_scope_entries", "sl2vl_scope_entry", + "qos_levels_section", "qos_levels", "qos_level", "qos_level_start", + "qos_level_end", "qos_level_entries", "qos_level_entry", + "qos_match_rules_section", "qos_match_rules", "qos_match_rule", + "qos_match_rule_start", "qos_match_rule_end", "qos_match_rule_entries", + "qos_match_rule_entry", "qos_ulp", "$@1", "$@2", "$@3", "$@4", "$@5", + "$@6", "$@7", "$@8", "$@9", "$@10", "$@11", "$@12", + "qos_ulp_type_any_service", "qos_ulp_type_any_pkey", + "qos_ulp_type_any_target_port_guid", "qos_ulp_type_sdp_default", + "qos_ulp_type_sdp_port", "qos_ulp_type_rds_default", + "qos_ulp_type_rds_port", "qos_ulp_type_iser_default", + "qos_ulp_type_iser_port", "qos_ulp_type_srp_guid", + "qos_ulp_type_ipoib_default", "qos_ulp_type_ipoib_pkey", "qos_ulp_sl", + "port_group_name", "port_group_name_start", "port_group_use", + "port_group_use_start", "port_group_port_name", + "port_group_port_name_start", "port_group_port_guid", + "port_group_port_guid_start", "port_group_pkey", "port_group_pkey_start", + "port_group_partition", "port_group_partition_start", + "port_group_node_type", "port_group_node_type_start", + "port_group_node_type_list", "node_type_item", "node_type_ca", + "node_type_switch", "node_type_router", "node_type_all", + "node_type_self", "vlarb_scope_group", "vlarb_scope_group_start", + "vlarb_scope_across", "vlarb_scope_across_start", + "vlarb_scope_vlarb_high_limit", "vlarb_scope_vlarb_high_limit_start", + "vlarb_scope_vlarb_high", "vlarb_scope_vlarb_high_start", + "vlarb_scope_vlarb_low", "vlarb_scope_vlarb_low_start", + "sl2vl_scope_group", "sl2vl_scope_group_start", "sl2vl_scope_across", + "sl2vl_scope_across_start", "sl2vl_scope_across_from", + "sl2vl_scope_across_from_start", "sl2vl_scope_across_to", + "sl2vl_scope_across_to_start", "sl2vl_scope_from", + "sl2vl_scope_from_start", "sl2vl_scope_to", "sl2vl_scope_to_start", + "sl2vl_scope_from_list_or_asterisk", "sl2vl_scope_from_asterisk", + "sl2vl_scope_to_list_or_asterisk", "sl2vl_scope_to_asterisk", + "sl2vl_scope_from_list_of_ranges", "sl2vl_scope_to_list_of_ranges", + "sl2vl_scope_sl2vl_table", "sl2vl_scope_sl2vl_table_start", + "qos_level_name", "qos_level_name_start", "qos_level_use", + "qos_level_use_start", "qos_level_sl", "qos_level_sl_start", + "qos_level_mtu_limit", "qos_level_mtu_limit_start", + "qos_level_rate_limit", "qos_level_rate_limit_start", + "qos_level_packet_life", "qos_level_packet_life_start", + "qos_level_path_bits", "qos_level_path_bits_start", "qos_level_pkey", + "qos_level_pkey_start", "qos_match_rule_use", "qos_match_rule_use_start", + "qos_match_rule_qos_class", "qos_match_rule_qos_class_start", + "qos_match_rule_source", "qos_match_rule_source_start", + "qos_match_rule_destination", "qos_match_rule_destination_start", + "qos_match_rule_qos_level_name", "qos_match_rule_qos_level_name_start", + "qos_match_rule_service_id", "qos_match_rule_service_id_start", + "qos_match_rule_pkey", "qos_match_rule_pkey_start", "single_string", + "single_string_elems", "single_string_element", "string_list", + "single_number", "num_list", "number", "num_list_with_dotdot", + "number_from_pair_1", "number_from_pair_2", "list_of_ranges", + "num_list_with_dash", "single_number_from_range", "number_from_range_1", + "number_from_range_2", 0 +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to + token YYLEX-NUM. */ +static const yytype_uint16 yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, + 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, + 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, + 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, + 325, 326, 327, 328, 329, 330, 331, 332 +}; +# endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_uint8 yyr1[] = +{ + 0, 78, 79, 80, 80, 81, 81, 81, 81, 81, + 82, 83, 83, 84, 85, 85, 86, 87, 88, 89, + 89, 90, 90, 90, 90, 90, 90, 90, 91, 92, + 92, 92, 93, 94, 94, 95, 96, 97, 98, 98, + 99, 99, 99, 99, 99, 100, 101, 101, 102, 103, + 104, 105, 105, 106, 106, 106, 106, 106, 106, 106, + 107, 108, 108, 109, 110, 111, 112, 112, 113, 113, + 113, 113, 113, 113, 113, 113, 114, 115, 115, 116, + 117, 118, 119, 119, 120, 120, 120, 120, 120, 120, + 120, 121, 122, 121, 123, 121, 124, 121, 125, 121, + 126, 121, 127, 121, 128, 121, 129, 121, 130, 121, + 131, 121, 132, 121, 133, 121, 134, 135, 136, 137, + 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, + 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, + 158, 159, 160, 161, 161, 162, 162, 162, 162, 162, + 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, + 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, + 183, 184, 185, 186, 187, 188, 189, 190, 190, 191, + 192, 192, 193, 194, 195, 196, 197, 198, 199, 200, + 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, + 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, + 221, 222, 223, 224, 225, 226, 227, 228, 229, 229, + 230, 231, 231, 232, 233, 233, 234, 235, 235, 236, + 237, 238, 239, 239, 239, 239, 240, 241, 242 +}; + +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ +static const yytype_uint8 yyr2[] = +{ + 0, 2, 1, 0, 2, 1, 1, 1, 1, 1, + 3, 1, 2, 3, 1, 2, 3, 1, 1, 0, + 2, 1, 1, 1, 1, 1, 1, 1, 3, 0, + 2, 2, 3, 0, 2, 3, 1, 1, 0, 2, + 1, 1, 1, 1, 1, 3, 0, 2, 3, 1, + 1, 0, 2, 1, 1, 1, 1, 1, 1, 1, + 3, 0, 2, 3, 1, 1, 0, 2, 1, 1, + 1, 1, 1, 1, 1, 1, 3, 0, 2, 3, + 1, 1, 0, 2, 1, 1, 1, 1, 1, 1, + 1, 2, 0, 5, 0, 5, 0, 5, 0, 3, + 0, 5, 0, 3, 0, 5, 0, 3, 0, 5, + 0, 5, 0, 3, 0, 5, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, + 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, + 1, 2, 1, 1, 3, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, + 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, + 1, 2, 1, 2, 1, 2, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, + 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, + 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, + 1, 2, 1, 2, 1, 2, 1, 1, 1, 2, + 1, 1, 3, 1, 1, 3, 1, 3, 5, 1, + 1, 1, 1, 3, 5, 3, 1, 1, 1 +}; + +/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state + STATE-NUM when YYTABLE doesn't specify something else to do. Zero + means the default is an error. */ +static const yytype_uint8 yydefact[] = +{ + 3, 0, 2, 1, 0, 0, 29, 61, 77, 4, + 5, 6, 7, 8, 9, 0, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127, 0, 11, + 0, 0, 0, 98, 0, 102, 0, 106, 0, 0, + 112, 0, 17, 0, 14, 19, 0, 0, 0, 226, + 91, 223, 10, 12, 236, 0, 231, 232, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 13, 15, 0, 28, 33, 46, 30, 31, 60, 64, + 62, 66, 76, 80, 78, 82, 92, 0, 0, 94, + 96, 99, 128, 100, 103, 104, 107, 108, 110, 113, + 114, 18, 130, 132, 136, 134, 140, 142, 138, 16, + 20, 21, 0, 22, 0, 24, 0, 23, 0, 25, + 0, 26, 0, 27, 0, 0, 0, 0, 0, 0, + 235, 0, 238, 233, 0, 0, 0, 0, 0, 0, + 0, 220, 129, 217, 218, 131, 221, 133, 135, 137, + 139, 152, 150, 151, 154, 153, 141, 143, 145, 146, + 147, 148, 149, 32, 36, 34, 38, 45, 49, 47, + 51, 65, 188, 190, 192, 194, 196, 198, 200, 202, + 63, 67, 68, 0, 69, 0, 70, 0, 71, 0, + 72, 0, 73, 0, 74, 0, 75, 0, 81, 204, + 206, 208, 210, 214, 212, 216, 79, 83, 84, 0, + 85, 0, 87, 0, 88, 0, 86, 0, 89, 0, + 90, 0, 93, 0, 95, 97, 101, 105, 109, 111, + 115, 219, 0, 0, 0, 0, 187, 189, 191, 193, + 195, 197, 199, 201, 203, 205, 207, 209, 211, 213, + 215, 234, 222, 144, 37, 156, 158, 162, 164, 160, + 35, 39, 40, 0, 41, 0, 44, 0, 42, 0, + 43, 0, 50, 166, 168, 176, 174, 172, 170, 186, + 48, 52, 53, 0, 54, 0, 55, 0, 56, 0, + 57, 0, 58, 0, 59, 0, 155, 157, 159, 229, + 161, 0, 163, 165, 167, 169, 171, 179, 173, 177, + 178, 183, 182, 175, 180, 181, 184, 185, 224, 0, + 0, 0, 0, 230, 227, 225, 0, 228 +}; + +/* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int16 yydefgoto[] = +{ + -1, 1, 2, 9, 10, 28, 11, 43, 44, 45, + 109, 72, 110, 12, 46, 76, 125, 165, 166, 260, + 234, 261, 77, 126, 169, 170, 280, 235, 281, 13, + 47, 80, 81, 180, 127, 181, 14, 48, 84, 85, + 206, 128, 207, 29, 129, 134, 135, 61, 136, 63, + 137, 65, 138, 139, 68, 140, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 91, 111, + 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, + 122, 123, 124, 156, 157, 158, 159, 160, 161, 162, + 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, + 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, + 292, 293, 308, 309, 313, 314, 310, 315, 294, 295, + 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, + 192, 193, 194, 195, 196, 197, 208, 209, 210, 211, + 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, + 146, 143, 144, 147, 92, 317, 51, 300, 301, 324, + 55, 56, 57, 58, 133 +}; + +/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +#define YYPACT_NINF -279 +static const yytype_int16 yypact[] = +{ + -279, 19, 5, -279, 63, 9, -279, -279, -279, -279, + -279, -279, -279, -279, -279, 21, -279, -279, -279, -279, + -279, -279, -279, -279, -279, -279, -279, -279, 45, -279, + 29, 29, 29, -279, 29, -279, 29, -279, 29, 29, + -279, 29, -279, 0, -279, -279, 36, 33, -4, -279, + -279, -279, -279, -279, 31, 61, 62, -279, 70, 71, + 79, 21, 80, 21, 81, 21, 83, 85, 21, 86, + -279, -279, 4, -279, -279, -279, -279, -279, -279, -279, + -279, -279, -279, -279, -279, -279, -279, 29, 64, -279, + -279, -279, -279, -279, -279, -279, -279, -279, -279, -279, + -279, -279, -279, -279, -279, -279, -279, -279, -279, -279, + -279, -279, 84, -279, 84, -279, 84, -279, 29, -279, + 29, -279, 84, -279, 91, 32, 39, -5, 24, 21, + -279, 90, -279, -279, 21, 21, 21, 21, 21, 21, + 21, -279, -279, 84, -279, -279, -279, 92, -279, -279, + 92, -279, -279, -279, -279, -279, 93, -279, -279, -279, + -279, -279, -279, -279, -279, -279, -279, -279, -279, -279, + -279, -279, -279, -279, -279, -279, -279, -279, -279, -279, + -279, -279, -279, 84, -279, 84, -279, 21, -279, 21, + -279, 21, -279, 21, -279, 29, -279, 29, -279, -279, + -279, -279, -279, -279, -279, -279, -279, -279, -279, 84, + -279, 29, -279, 84, -279, 84, -279, 84, -279, 29, + -279, 29, -279, 64, -279, -279, -279, -279, -279, -279, + -279, -279, 84, 91, 107, 25, -279, -279, -279, -279, + -279, -279, -279, -279, -279, -279, 92, 92, -279, -279, + -279, -279, -279, -279, -279, -279, -279, -279, -279, -279, + -279, -279, -279, 84, -279, 84, -279, 21, -279, 97, + -279, 97, -279, -279, -279, -279, -279, -279, -279, -279, + -279, -279, -279, 84, -279, 84, -279, 84, -279, 84, + -279, 8, -279, 18, -279, 21, 92, 92, -279, -279, + 117, 120, 117, 92, 92, 92, 92, -279, -279, -279, + -279, -279, -279, -279, -279, -279, -279, 135, -279, 97, + 123, 21, 137, -279, -279, -279, 123, -279 +}; + +/* YYPGOTO[NTERM-NUM]. */ +static const yytype_int16 yypgoto[] = +{ + -279, -279, -279, -279, -279, -279, -279, -279, 53, -279, + -279, -279, -279, -279, -279, -279, -279, -279, -279, -279, + -279, -279, -279, -279, -279, -279, -279, -279, -279, -279, + -279, -279, -279, -279, -279, -279, -279, -279, -279, -279, + -279, -279, -279, 116, -279, -279, -279, -279, -279, -279, + -279, -279, -279, -279, -279, -279, -279, -279, -279, -279, + -279, -279, -279, -279, -279, -279, -279, -279, -32, -279, + -279, -279, -279, -279, -279, -279, -279, -279, -279, -279, + -279, -279, -279, -279, -77, -279, -279, -279, -279, -279, + -279, -279, -279, -279, -279, -279, -279, -279, -279, -279, + -279, -279, -279, -279, -279, -279, -279, -279, -279, -279, + -279, -279, -279, -279, -279, -279, -279, -279, -279, -279, + -279, -279, -279, -279, -279, -279, -279, -279, -279, -279, + -279, -279, -279, -279, -279, -279, -279, -279, -279, -279, + -279, -279, -279, -279, -279, -279, -279, -279, -279, -279, + -108, -279, 14, -120, -6, -279, -278, -113, -160, -166, + -31, -279, 74, 75, -55 +}; + +/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule which + number is the opposite. If zero, do what YYDEFACT says. + If YYTABLE_NINF, syntax error. */ +#define YYTABLE_NINF -238 +static const yytype_int16 yytable[] = +{ + 59, 60, 150, 62, 142, 64, 145, 66, 67, 50, + 69, 54, 70, 42, 4, 307, 5, 318, 101, 3, + 6, 54, 42, 171, 49, 312, 82, 83, 172, 173, + 7, 94, 54, 96, 8, -237, 99, 102, 103, 104, + 105, 106, 107, 325, 174, 175, 176, 177, 178, 272, + 163, 164, 73, 74, 179, 52, 198, 75, 199, 78, + 79, 167, 168, 108, 273, 274, 86, 132, 87, 275, + 276, 277, 278, 279, 88, 236, 89, 237, 200, 201, + 202, 203, 204, 205, 90, 93, 95, 148, 97, 149, + 98, 100, 141, 246, 223, 247, 71, 222, 232, 233, + 299, 244, 224, 225, 226, 227, 228, 229, 230, 248, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 319, 252, 320, 323, 254, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 321, 326, 296, 53, 297, 255, 256, 257, 258, + 259, 151, 152, 153, 154, 155, 253, 231, 302, 322, + 327, 130, 131, 303, 242, 304, 243, 305, 251, 306, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 245, 238, 0, 239, 0, 240, 0, 241, 249, 0, + 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 311, 298, 316 +}; + +static const yytype_int16 yycheck[] = +{ + 31, 32, 122, 34, 112, 36, 114, 38, 39, 15, + 41, 3, 12, 13, 9, 7, 11, 295, 14, 0, + 15, 3, 13, 28, 3, 7, 30, 31, 33, 34, + 25, 63, 3, 65, 29, 4, 68, 33, 34, 35, + 36, 37, 38, 321, 49, 50, 51, 52, 53, 24, + 18, 19, 16, 17, 59, 10, 32, 21, 34, 26, + 27, 22, 23, 59, 39, 40, 5, 3, 6, 44, + 45, 46, 47, 48, 4, 183, 5, 185, 54, 55, + 56, 57, 58, 59, 5, 5, 5, 118, 5, 120, + 5, 5, 8, 213, 4, 215, 43, 129, 6, 6, + 3, 209, 134, 135, 136, 137, 138, 139, 140, 217, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 6, 232, 5, 3, 20, 65, 66, + 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, + 77, 6, 5, 263, 28, 265, 39, 40, 41, 42, + 43, 60, 61, 62, 63, 64, 233, 143, 271, 319, + 326, 87, 87, 283, 195, 285, 197, 287, 223, 289, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 211, 187, -1, 189, -1, 191, -1, 193, 219, -1, + 221, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 291, 267, 293 +}; + +/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const yytype_uint8 yystos[] = +{ + 0, 79, 80, 0, 9, 11, 15, 25, 29, 81, + 82, 84, 91, 107, 114, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 83, 121, + 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, + 144, 145, 13, 85, 86, 87, 92, 108, 115, 3, + 232, 234, 10, 121, 3, 238, 239, 240, 241, 238, + 238, 125, 238, 127, 238, 129, 238, 238, 132, 238, + 12, 86, 89, 16, 17, 21, 93, 100, 26, 27, + 109, 110, 30, 31, 116, 117, 5, 6, 4, 5, + 5, 146, 232, 5, 146, 5, 146, 5, 5, 146, + 5, 14, 33, 34, 35, 36, 37, 38, 59, 88, + 90, 147, 148, 149, 150, 151, 152, 153, 154, 155, + 156, 157, 158, 159, 160, 94, 101, 112, 119, 122, + 240, 241, 3, 242, 123, 124, 126, 128, 130, 131, + 133, 8, 228, 229, 230, 228, 228, 231, 238, 238, + 231, 60, 61, 62, 63, 64, 161, 162, 163, 164, + 165, 166, 167, 18, 19, 95, 96, 22, 23, 102, + 103, 28, 33, 34, 49, 50, 51, 52, 53, 59, + 111, 113, 198, 199, 200, 201, 202, 203, 204, 205, + 206, 207, 208, 209, 210, 211, 212, 213, 32, 34, + 54, 55, 56, 57, 58, 59, 118, 120, 214, 215, + 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, + 226, 227, 146, 4, 146, 146, 146, 146, 146, 146, + 146, 230, 6, 6, 98, 105, 228, 228, 232, 232, + 232, 232, 238, 238, 228, 238, 231, 231, 228, 238, + 238, 242, 228, 162, 20, 39, 40, 41, 42, 43, + 97, 99, 168, 169, 170, 171, 172, 173, 174, 175, + 176, 177, 24, 39, 40, 44, 45, 46, 47, 48, + 104, 106, 178, 179, 180, 181, 182, 183, 184, 185, + 186, 187, 188, 189, 196, 197, 231, 231, 232, 3, + 235, 236, 235, 231, 231, 231, 231, 7, 190, 191, + 194, 238, 7, 192, 193, 195, 238, 233, 234, 6, + 5, 6, 236, 3, 237, 234, 5, 237 +}; + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +/* Like YYERROR except do call yyerror. This remains here temporarily + to ease the transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. */ + +#define YYFAIL goto yyerrlab + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + yytoken = YYTRANSLATE (yychar); \ + YYPOPSTACK (1); \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ +while (YYID (0)) + + +#define YYTERROR 1 +#define YYERRCODE 256 + + +/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. + If N is 0, then set CURRENT to the empty location which ends + the previous symbol: RHS[0] (always defined). */ + +#define YYRHSLOC(Rhs, K) ((Rhs)[K]) +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + if (YYID (N)) \ + { \ + (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ + (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ + } \ + else \ + { \ + (Current).first_line = (Current).last_line = \ + YYRHSLOC (Rhs, 0).last_line; \ + (Current).first_column = (Current).last_column = \ + YYRHSLOC (Rhs, 0).last_column; \ + } \ + while (YYID (0)) +#endif + + +/* YY_LOCATION_PRINT -- Print the location on the stream. + This macro was not mandated originally: define only if we know + we won't break user code: when these are the locations we know. */ + +#ifndef YY_LOCATION_PRINT +# if YYLTYPE_IS_TRIVIAL +# define YY_LOCATION_PRINT(File, Loc) \ + fprintf (File, "%d.%d-%d.%d", \ + (Loc).first_line, (Loc).first_column, \ + (Loc).last_line, (Loc).last_column) +# else +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +# endif +#endif + + +/* YYLEX -- calling `yylex' with the right arguments. */ + +#ifdef YYLEX_PARAM +# define YYLEX yylex (YYLEX_PARAM) +#else +# define YYLEX yylex () +#endif + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (YYID (0)) + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Type, Value); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (YYID (0)) + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +#else +static void +yy_symbol_value_print (yyoutput, yytype, yyvaluep) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; +#endif +{ + if (!yyvaluep) + return; +# ifdef YYPRINT + if (yytype < YYNTOKENS) + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# else + YYUSE (yyoutput); +# endif + switch (yytype) + { + default: + break; + } +} + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +#else +static void +yy_symbol_print (yyoutput, yytype, yyvaluep) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; +#endif +{ + if (yytype < YYNTOKENS) + YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); + else + YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); + + yy_symbol_value_print (yyoutput, yytype, yyvaluep); + YYFPRINTF (yyoutput, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) +#else +static void +yy_stack_print (yybottom, yytop) + yytype_int16 *yybottom; + yytype_int16 *yytop; +#endif +{ + YYFPRINTF (stderr, "Stack now"); + for (; yybottom <= yytop; yybottom++) + { + int yybot = *yybottom; + YYFPRINTF (stderr, " %d", yybot); + } + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (YYID (0)) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_reduce_print (YYSTYPE *yyvsp, int yyrule) +#else +static void +yy_reduce_print (yyvsp, yyrule) + YYSTYPE *yyvsp; + int yyrule; +#endif +{ + int yynrhs = yyr2[yyrule]; + int yyi; + unsigned long int yylno = yyrline[yyrule]; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + YYFPRINTF (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], + &(yyvsp[(yyi + 1) - (yynrhs)]) + ); + YYFPRINTF (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyvsp, Rule); \ +} while (YYID (0)) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static YYSIZE_T +yystrlen (const char *yystr) +#else +static YYSIZE_T +yystrlen (yystr) + const char *yystr; +#endif +{ + YYSIZE_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +# endif + +# ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static char * +yystpcpy (char *yydest, const char *yysrc) +#else +static char * +yystpcpy (yydest, yysrc) + char *yydest; + const char *yysrc; +#endif +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYSIZE_T yyn = 0; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (! yyres) + return yystrlen (yystr); + + return yystpcpy (yyres, yystr) - yyres; +} +# endif + +/* Copy into YYRESULT an error message about the unexpected token + YYCHAR while in state YYSTATE. Return the number of bytes copied, + including the terminating null byte. If YYRESULT is null, do not + copy anything; just return the number of bytes that would be + copied. As a special case, return 0 if an ordinary "syntax error" + message will do. Return YYSIZE_MAXIMUM if overflow occurs during + size calculation. */ +static YYSIZE_T +yysyntax_error (char *yyresult, int yystate, int yychar) +{ + int yyn = yypact[yystate]; + + if (! (YYPACT_NINF < yyn && yyn <= YYLAST)) + return 0; + else + { + int yytype = YYTRANSLATE (yychar); + YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]); + YYSIZE_T yysize = yysize0; + YYSIZE_T yysize1; + int yysize_overflow = 0; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + int yyx; + +# if 0 + /* This is so xgettext sees the translatable formats that are + constructed on the fly. */ + YY_("syntax error, unexpected %s"); + YY_("syntax error, unexpected %s, expecting %s"); + YY_("syntax error, unexpected %s, expecting %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"); +# endif + char *yyfmt; + char const *yyf; + static char const yyunexpected[] = "syntax error, unexpected %s"; + static char const yyexpecting[] = ", expecting %s"; + static char const yyor[] = " or %s"; + char yyformat[sizeof yyunexpected + + sizeof yyexpecting - 1 + + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2) + * (sizeof yyor - 1))]; + char const *yyprefix = yyexpecting; + + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yycount = 1; + + yyarg[0] = yytname[yytype]; + yyfmt = yystpcpy (yyformat, yyunexpected); + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + yyformat[sizeof yyunexpected - 1] = '\0'; + break; + } + yyarg[yycount++] = yytname[yyx]; + yysize1 = yysize + yytnamerr (0, yytname[yyx]); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + yyfmt = yystpcpy (yyfmt, yyprefix); + yyprefix = yyor; + } + + yyf = YY_(yyformat); + yysize1 = yysize + yystrlen (yyf); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + + if (yysize_overflow) + return YYSIZE_MAXIMUM; + + if (yyresult) + { + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + char *yyp = yyresult; + int yyi = 0; + while ((*yyp = *yyf) != '\0') + { + if (*yyp == '%' && yyf[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyf += 2; + } + else + { + yyp++; + yyf++; + } + } + } + return yysize; + } +} +#endif /* YYERROR_VERBOSE */ + + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) +#else +static void +yydestruct (yymsg, yytype, yyvaluep) + const char *yymsg; + int yytype; + YYSTYPE *yyvaluep; +#endif +{ + YYUSE (yyvaluep); + + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + + switch (yytype) + { + + default: + break; + } +} + +/* Prevent warnings from -Wmissing-prototypes. */ +#ifdef YYPARSE_PARAM +#if defined __STDC__ || defined __cplusplus +int yyparse (void *YYPARSE_PARAM); +#else +int yyparse (); +#endif +#else /* ! YYPARSE_PARAM */ +#if defined __STDC__ || defined __cplusplus +int yyparse (void); +#else +int yyparse (); +#endif +#endif /* ! YYPARSE_PARAM */ + + +/* The lookahead symbol. */ +int yychar; + +/* The semantic value of the lookahead symbol. */ +YYSTYPE yylval; + +/* Number of syntax errors so far. */ +int yynerrs; + + + +/*-------------------------. +| yyparse or yypush_parse. | +`-------------------------*/ + +#ifdef YYPARSE_PARAM +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void *YYPARSE_PARAM) +#else +int +yyparse (YYPARSE_PARAM) + void *YYPARSE_PARAM; +#endif +#else /* ! YYPARSE_PARAM */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void) +#else +int +yyparse () + +#endif +#endif +{ + + + int yystate; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + + /* The stacks and their tools: + `yyss': related to states. + `yyvs': related to semantic values. + + Refer to the stacks thru separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs; + YYSTYPE *yyvsp; + + YYSIZE_T yystacksize; + + int yyn; + int yyresult; + /* Lookahead token as an internal (translated) token number. */ + int yytoken; + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + +#if YYERROR_VERBOSE + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + yytoken = 0; + yyss = yyssa; + yyvs = yyvsa; + yystacksize = YYINITDEPTH; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + yyssp = yyss; + yyvsp = yyvs; + + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + yytype_int16 *yyss1 = yyss; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yystacksize); + + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyexhaustedlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyexhaustedlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yytype_int16 *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss_alloc, yyss); + YYSTACK_RELOCATE (yyvs_alloc, yyvs); +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + if (yystate == YYFINAL) + YYACCEPT; + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + + /* Do appropriate processing given the current state. Read a + lookahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to lookahead token. */ + yyn = yypact[yystate]; + if (yyn == YYPACT_NINF) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = YYLEX; + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yyn == 0 || yyn == YYTABLE_NINF) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the lookahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + + /* Discard the shifted token. */ + yychar = YYEMPTY; + + yystate = yyn; + *++yyvsp = yylval; + + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + `$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 17: + +/* Line 1455 of yacc.c */ +#line 354 "osm_qos_parser_y.y" + { + __parser_port_group_start(); + } + break; + + case 18: + +/* Line 1455 of yacc.c */ +#line 359 "osm_qos_parser_y.y" + { + if ( __parser_port_group_end() ) + return 1; + } + break; + + case 36: + +/* Line 1455 of yacc.c */ +#line 422 "osm_qos_parser_y.y" + { + __parser_vlarb_scope_start(); + } + break; + + case 37: + +/* Line 1455 of yacc.c */ +#line 427 "osm_qos_parser_y.y" + { + if ( __parser_vlarb_scope_end() ) + return 1; + } + break; + + case 49: + +/* Line 1455 of yacc.c */ +#line 468 "osm_qos_parser_y.y" + { + __parser_sl2vl_scope_start(); + } + break; + + case 50: + +/* Line 1455 of yacc.c */ +#line 473 "osm_qos_parser_y.y" + { + if ( __parser_sl2vl_scope_end() ) + return 1; + } + break; + + case 64: + +/* Line 1455 of yacc.c */ +#line 539 "osm_qos_parser_y.y" + { + __parser_qos_level_start(); + } + break; + + case 65: + +/* Line 1455 of yacc.c */ +#line 544 "osm_qos_parser_y.y" + { + if ( __parser_qos_level_end() ) + return 1; + } + break; + + case 80: + +/* Line 1455 of yacc.c */ +#line 593 "osm_qos_parser_y.y" + { + __parser_match_rule_start(); + } + break; + + case 81: + +/* Line 1455 of yacc.c */ +#line 598 "osm_qos_parser_y.y" + { + if ( __parser_match_rule_end() ) + return 1; + } + break; + + case 91: + +/* Line 1455 of yacc.c */ +#line 636 "osm_qos_parser_y.y" + { + /* 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); + } + break; + + case 92: + +/* Line 1455 of yacc.c */ +#line 654 "osm_qos_parser_y.y" + { + /* "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; + + } + break; + + case 94: + +/* Line 1455 of yacc.c */ +#line 675 "osm_qos_parser_y.y" + { + /* "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; + + } + break; + + case 96: + +/* Line 1455 of yacc.c */ +#line 696 "osm_qos_parser_y.y" + { + /* 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(); + + } + break; + + case 98: + +/* Line 1455 of yacc.c */ +#line 731 "osm_qos_parser_y.y" + { + /* "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; + + } + break; + + case 100: + +/* Line 1455 of yacc.c */ +#line 744 "osm_qos_parser_y.y" + { + /* 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; + + } + break; + + case 102: + +/* Line 1455 of yacc.c */ +#line 777 "osm_qos_parser_y.y" + { + /* "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; + + } + break; + + case 104: + +/* Line 1455 of yacc.c */ +#line 790 "osm_qos_parser_y.y" + { + /* 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; + + } + break; + + case 106: + +/* Line 1455 of yacc.c */ +#line 823 "osm_qos_parser_y.y" + { + /* "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; + + } + break; + + case 108: + +/* Line 1455 of yacc.c */ +#line 836 "osm_qos_parser_y.y" + { + /* 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; + + } + break; + + case 110: + +/* Line 1455 of yacc.c */ +#line 869 "osm_qos_parser_y.y" + { + /* 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(); + + } + break; + + case 112: + +/* Line 1455 of yacc.c */ +#line 905 "osm_qos_parser_y.y" + { + /* 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; + + } + break; + + case 114: + +/* Line 1455 of yacc.c */ +#line 925 "osm_qos_parser_y.y" + { + /* 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; + + } + break; + + case 116: + +/* Line 1455 of yacc.c */ +#line 957 "osm_qos_parser_y.y" + { __parser_ulp_match_rule_start(); } + break; + + case 117: + +/* Line 1455 of yacc.c */ +#line 960 "osm_qos_parser_y.y" + { __parser_ulp_match_rule_start(); } + break; + + case 118: + +/* Line 1455 of yacc.c */ +#line 963 "osm_qos_parser_y.y" + { __parser_ulp_match_rule_start(); } + break; + + case 119: + +/* Line 1455 of yacc.c */ +#line 966 "osm_qos_parser_y.y" + { __parser_ulp_match_rule_start(); } + break; + + case 120: + +/* Line 1455 of yacc.c */ +#line 969 "osm_qos_parser_y.y" + { __parser_ulp_match_rule_start(); } + break; + + case 121: + +/* Line 1455 of yacc.c */ +#line 972 "osm_qos_parser_y.y" + { __parser_ulp_match_rule_start(); } + break; + + case 122: + +/* Line 1455 of yacc.c */ +#line 975 "osm_qos_parser_y.y" + { __parser_ulp_match_rule_start(); } + break; + + case 123: + +/* Line 1455 of yacc.c */ +#line 978 "osm_qos_parser_y.y" + { __parser_ulp_match_rule_start(); } + break; + + case 124: + +/* Line 1455 of yacc.c */ +#line 981 "osm_qos_parser_y.y" + { __parser_ulp_match_rule_start(); } + break; + + case 125: + +/* Line 1455 of yacc.c */ +#line 984 "osm_qos_parser_y.y" + { __parser_ulp_match_rule_start(); } + break; + + case 126: + +/* Line 1455 of yacc.c */ +#line 987 "osm_qos_parser_y.y" + { __parser_ulp_match_rule_start(); } + break; + + case 127: + +/* Line 1455 of yacc.c */ +#line 990 "osm_qos_parser_y.y" + { __parser_ulp_match_rule_start(); } + break; + + case 128: + +/* Line 1455 of yacc.c */ +#line 993 "osm_qos_parser_y.y" + { + /* 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; + } + break; + + case 129: + +/* Line 1455 of yacc.c */ +#line 1032 "osm_qos_parser_y.y" + { + /* '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); + } + break; + + case 130: + +/* Line 1455 of yacc.c */ +#line 1055 "osm_qos_parser_y.y" + { + RESET_BUFFER; + } + break; + + case 131: + +/* Line 1455 of yacc.c */ +#line 1060 "osm_qos_parser_y.y" + { + /* '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); + } + break; + + case 132: + +/* Line 1455 of yacc.c */ +#line 1083 "osm_qos_parser_y.y" + { + RESET_BUFFER; + } + break; + + case 133: + +/* Line 1455 of yacc.c */ +#line 1088 "osm_qos_parser_y.y" + { + /* '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); + } + break; + + case 134: + +/* Line 1455 of yacc.c */ +#line 1154 "osm_qos_parser_y.y" + { + RESET_BUFFER; + } + break; + + case 135: + +/* Line 1455 of yacc.c */ +#line 1159 "osm_qos_parser_y.y" + { + /* '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); + } + } + break; + + case 136: + +/* Line 1455 of yacc.c */ +#line 1179 "osm_qos_parser_y.y" + { + RESET_BUFFER; + } + break; + + case 137: + +/* Line 1455 of yacc.c */ +#line 1184 "osm_qos_parser_y.y" + { + /* '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); + } + } + break; + + case 138: + +/* Line 1455 of yacc.c */ +#line 1204 "osm_qos_parser_y.y" + { + RESET_BUFFER; + } + break; + + case 139: + +/* Line 1455 of yacc.c */ +#line 1209 "osm_qos_parser_y.y" + { + /* '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); + } + break; + + case 140: + +/* Line 1455 of yacc.c */ +#line 1217 "osm_qos_parser_y.y" + { + RESET_BUFFER; + } + break; + + case 141: + +/* Line 1455 of yacc.c */ +#line 1222 "osm_qos_parser_y.y" + { + /* 'node-type' in 'port-group' - any num of instances */ + } + break; + + case 142: + +/* Line 1455 of yacc.c */ +#line 1227 "osm_qos_parser_y.y" + { + RESET_BUFFER; + } + break; + + case 150: + +/* Line 1455 of yacc.c */ +#line 1243 "osm_qos_parser_y.y" + { + p_current_port_group->node_types |= + OSM_QOS_POLICY_NODE_TYPE_CA; + } + break; + + case 151: + +/* Line 1455 of yacc.c */ +#line 1249 "osm_qos_parser_y.y" + { + p_current_port_group->node_types |= + OSM_QOS_POLICY_NODE_TYPE_SWITCH; + } + break; + + case 152: + +/* Line 1455 of yacc.c */ +#line 1255 "osm_qos_parser_y.y" + { + p_current_port_group->node_types |= + OSM_QOS_POLICY_NODE_TYPE_ROUTER; + } + break; + + case 153: + +/* Line 1455 of yacc.c */ +#line 1261 "osm_qos_parser_y.y" + { + p_current_port_group->node_types |= + (OSM_QOS_POLICY_NODE_TYPE_CA | + OSM_QOS_POLICY_NODE_TYPE_SWITCH | + OSM_QOS_POLICY_NODE_TYPE_ROUTER); + } + break; + + case 154: + +/* Line 1455 of yacc.c */ +#line 1269 "osm_qos_parser_y.y" + { + 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); + } + break; + + case 155: + +/* Line 1455 of yacc.c */ +#line 1291 "osm_qos_parser_y.y" + { + /* '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); + } + break; + + case 156: + +/* Line 1455 of yacc.c */ +#line 1308 "osm_qos_parser_y.y" + { + RESET_BUFFER; + } + break; + + case 157: + +/* Line 1455 of yacc.c */ +#line 1313 "osm_qos_parser_y.y" + { + /* '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); + } + break; + + case 158: + +/* Line 1455 of yacc.c */ +#line 1330 "osm_qos_parser_y.y" + { + RESET_BUFFER; + } + break; + + case 159: + +/* Line 1455 of yacc.c */ +#line 1335 "osm_qos_parser_y.y" + { + /* '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); + } + break; + + case 160: + +/* Line 1455 of yacc.c */ +#line 1353 "osm_qos_parser_y.y" + { + RESET_BUFFER; + } + break; + + case 161: + +/* Line 1455 of yacc.c */ +#line 1358 "osm_qos_parser_y.y" + { + /* '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); + } + break; + + case 162: + +/* Line 1455 of yacc.c */ +#line 1375 "osm_qos_parser_y.y" + { + RESET_BUFFER; + } + break; + + case 163: + +/* Line 1455 of yacc.c */ +#line 1380 "osm_qos_parser_y.y" + { + /* '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); + } + break; + + case 164: + +/* Line 1455 of yacc.c */ +#line 1397 "osm_qos_parser_y.y" + { + RESET_BUFFER; + } + break; + + case 165: + +/* Line 1455 of yacc.c */ +#line 1413 "osm_qos_parser_y.y" + { + /* '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); + } + break; + + case 166: + +/* Line 1455 of yacc.c */ +#line 1430 "osm_qos_parser_y.y" + { + RESET_BUFFER; + } + break; + + case 167: + +/* Line 1455 of yacc.c */ +#line 1435 "osm_qos_parser_y.y" + { + /* '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); + } + break; + + case 168: + +/* Line 1455 of yacc.c */ +#line 1454 "osm_qos_parser_y.y" + { + RESET_BUFFER; + } + break; + + case 169: + +/* Line 1455 of yacc.c */ +#line 1459 "osm_qos_parser_y.y" + { + /* '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); + } + break; + + case 170: + +/* Line 1455 of yacc.c */ +#line 1476 "osm_qos_parser_y.y" + { + RESET_BUFFER; + } + break; + + case 171: + +/* Line 1455 of yacc.c */ +#line 1481 "osm_qos_parser_y.y" + { + /* '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); + } + break; + + case 172: + +/* Line 1455 of yacc.c */ +#line 1499 "osm_qos_parser_y.y" + { + RESET_BUFFER; + } + break; + + case 173: + +/* Line 1455 of yacc.c */ +#line 1504 "osm_qos_parser_y.y" + { + /* 'from' in 'sl2vl-scope' - any num of instances */ + } + break; + + case 174: + +/* Line 1455 of yacc.c */ +#line 1509 "osm_qos_parser_y.y" + { + RESET_BUFFER; + } + break; + + case 175: + +/* Line 1455 of yacc.c */ +#line 1514 "osm_qos_parser_y.y" + { + /* 'to' in 'sl2vl-scope' - any num of instances */ + } + break; + + case 176: + +/* Line 1455 of yacc.c */ +#line 1519 "osm_qos_parser_y.y" + { + RESET_BUFFER; + } + break; + + case 179: + +/* Line 1455 of yacc.c */ +#line 1528 "osm_qos_parser_y.y" + { + int i; + for (i = 0; i < OSM_QOS_POLICY_MAX_PORTS_ON_SWITCH; i++) + p_current_sl2vl_scope->from[i] = TRUE; + } + break; + + case 182: + +/* Line 1455 of yacc.c */ +#line 1539 "osm_qos_parser_y.y" + { + int i; + for (i = 0; i < OSM_QOS_POLICY_MAX_PORTS_ON_SWITCH; i++) + p_current_sl2vl_scope->to[i] = TRUE; + } + break; + + case 183: + +/* Line 1455 of yacc.c */ +#line 1546 "osm_qos_parser_y.y" + { + 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 ( (int64_t)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); + } + break; + + case 184: + +/* Line 1455 of yacc.c */ +#line 1578 "osm_qos_parser_y.y" + { + 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 ( (int64_t)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); + } + break; + + case 185: + +/* Line 1455 of yacc.c */ +#line 1611 "osm_qos_parser_y.y" + { + /* '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); + } + break; + + case 186: + +/* Line 1455 of yacc.c */ +#line 1654 "osm_qos_parser_y.y" + { + RESET_BUFFER; + } + break; + + case 187: + +/* Line 1455 of yacc.c */ +#line 1671 "osm_qos_parser_y.y" + { + /* '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); + } + break; + + case 188: + +/* Line 1455 of yacc.c */ +#line 1694 "osm_qos_parser_y.y" + { + RESET_BUFFER; + } + break; + + case 189: + +/* Line 1455 of yacc.c */ +#line 1699 "osm_qos_parser_y.y" + { + /* '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); + } + break; + + case 190: + +/* Line 1455 of yacc.c */ +#line 1722 "osm_qos_parser_y.y" + { + RESET_BUFFER; + } + break; + + case 191: + +/* Line 1455 of yacc.c */ +#line 1727 "osm_qos_parser_y.y" + { + /* '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); + } + break; + + case 192: + +/* Line 1455 of yacc.c */ +#line 1747 "osm_qos_parser_y.y" + { + RESET_BUFFER; + } + break; + + case 193: + +/* Line 1455 of yacc.c */ +#line 1752 "osm_qos_parser_y.y" + { + /* '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); + } + break; + + case 194: + +/* Line 1455 of yacc.c */ +#line 1772 "osm_qos_parser_y.y" + { + /* 'mtu-limit' in 'qos-level' - one instance */ + RESET_BUFFER; + } + break; + + case 195: + +/* Line 1455 of yacc.c */ +#line 1778 "osm_qos_parser_y.y" + { + /* '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); + } + break; + + case 196: + +/* Line 1455 of yacc.c */ +#line 1798 "osm_qos_parser_y.y" + { + /* 'rate-limit' in 'qos-level' - one instance */ + RESET_BUFFER; + } + break; + + case 197: + +/* Line 1455 of yacc.c */ +#line 1804 "osm_qos_parser_y.y" + { + /* '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); + } + break; + + case 198: + +/* Line 1455 of yacc.c */ +#line 1824 "osm_qos_parser_y.y" + { + /* 'packet-life' in 'qos-level' - one instance */ + RESET_BUFFER; + } + break; + + case 199: + +/* Line 1455 of yacc.c */ +#line 1830 "osm_qos_parser_y.y" + { + /* '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; + } + } + } + break; + + case 200: + +/* Line 1455 of yacc.c */ +#line 1865 "osm_qos_parser_y.y" + { + RESET_BUFFER; + } + break; + + case 201: + +/* Line 1455 of yacc.c */ +#line 1870 "osm_qos_parser_y.y" + { + /* '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; + } + } + } + break; + + case 202: + +/* Line 1455 of yacc.c */ +#line 1903 "osm_qos_parser_y.y" + { + RESET_BUFFER; + } + break; + + case 203: + +/* Line 1455 of yacc.c */ +#line 1920 "osm_qos_parser_y.y" + { + /* '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); + } + break; + + case 204: + +/* Line 1455 of yacc.c */ +#line 1943 "osm_qos_parser_y.y" + { + RESET_BUFFER; + } + break; + + case 205: + +/* Line 1455 of yacc.c */ +#line 1948 "osm_qos_parser_y.y" + { + /* '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; + } + } + } + break; + + case 206: + +/* Line 1455 of yacc.c */ +#line 1982 "osm_qos_parser_y.y" + { + RESET_BUFFER; + } + break; + + case 207: + +/* Line 1455 of yacc.c */ +#line 1987 "osm_qos_parser_y.y" + { + /* '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); + } + break; + + case 208: + +/* Line 1455 of yacc.c */ +#line 2004 "osm_qos_parser_y.y" + { + RESET_BUFFER; + } + break; + + case 209: + +/* Line 1455 of yacc.c */ +#line 2009 "osm_qos_parser_y.y" + { + /* '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); + } + break; + + case 210: + +/* Line 1455 of yacc.c */ +#line 2026 "osm_qos_parser_y.y" + { + RESET_BUFFER; + } + break; + + case 211: + +/* Line 1455 of yacc.c */ +#line 2031 "osm_qos_parser_y.y" + { + /* '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); + } + break; + + case 212: + +/* Line 1455 of yacc.c */ +#line 2054 "osm_qos_parser_y.y" + { + RESET_BUFFER; + } + break; + + case 213: + +/* Line 1455 of yacc.c */ +#line 2059 "osm_qos_parser_y.y" + { + /* '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; + } + } + } + break; + + case 214: + +/* Line 1455 of yacc.c */ +#line 2092 "osm_qos_parser_y.y" + { + RESET_BUFFER; + } + break; + + case 215: + +/* Line 1455 of yacc.c */ +#line 2097 "osm_qos_parser_y.y" + { + /* '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; + } + } + } + break; + + case 216: + +/* Line 1455 of yacc.c */ +#line 2130 "osm_qos_parser_y.y" + { + RESET_BUFFER; + } + break; + + case 217: + +/* Line 1455 of yacc.c */ +#line 2141 "osm_qos_parser_y.y" + { + cl_list_insert_tail(&tmp_parser_struct.str_list, + strdup(__parser_strip_white(tmp_parser_struct.str))); + tmp_parser_struct.str[0] = '\0'; + } + break; + + case 220: + +/* Line 1455 of yacc.c */ +#line 2152 "osm_qos_parser_y.y" + { + strcat(tmp_parser_struct.str,(yyvsp[(1) - (1)])); + free((yyvsp[(1) - (1)])); + } + break; + + case 226: + +/* Line 1455 of yacc.c */ +#line 2172 "osm_qos_parser_y.y" + { + uint64_t * p_num = (uint64_t*)malloc(sizeof(uint64_t)); + __parser_str2uint64(p_num,(yyvsp[(1) - (1)])); + free((yyvsp[(1) - (1)])); + cl_list_insert_tail(&tmp_parser_struct.num_list, p_num); + } + break; + + case 227: + +/* Line 1455 of yacc.c */ +#line 2180 "osm_qos_parser_y.y" + { + 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); + } + break; + + case 228: + +/* Line 1455 of yacc.c */ +#line 2186 "osm_qos_parser_y.y" + { + 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); + } + break; + + case 229: + +/* Line 1455 of yacc.c */ +#line 2194 "osm_qos_parser_y.y" + { + __parser_str2uint64(&tmp_parser_struct.num_pair[0],(yyvsp[(1) - (1)])); + free((yyvsp[(1) - (1)])); + } + break; + + case 230: + +/* Line 1455 of yacc.c */ +#line 2200 "osm_qos_parser_y.y" + { + __parser_str2uint64(&tmp_parser_struct.num_pair[1],(yyvsp[(1) - (1)])); + free((yyvsp[(1) - (1)])); + } + break; + + case 232: + +/* Line 1455 of yacc.c */ +#line 2209 "osm_qos_parser_y.y" + { + 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); + } + break; + + case 233: + +/* Line 1455 of yacc.c */ +#line 2215 "osm_qos_parser_y.y" + { + 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); + } + break; + + case 234: + +/* Line 1455 of yacc.c */ +#line 2227 "osm_qos_parser_y.y" + { + 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); + } + break; + + case 235: + +/* Line 1455 of yacc.c */ +#line 2239 "osm_qos_parser_y.y" + { + 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); + } + break; + + case 236: + +/* Line 1455 of yacc.c */ +#line 2247 "osm_qos_parser_y.y" + { + __parser_str2uint64(&tmp_parser_struct.num_pair[0],(yyvsp[(1) - (1)])); + __parser_str2uint64(&tmp_parser_struct.num_pair[1],(yyvsp[(1) - (1)])); + free((yyvsp[(1) - (1)])); + } + break; + + case 237: + +/* Line 1455 of yacc.c */ +#line 2254 "osm_qos_parser_y.y" + { + __parser_str2uint64(&tmp_parser_struct.num_pair[0],(yyvsp[(1) - (1)])); + free((yyvsp[(1) - (1)])); + } + break; + + case 238: + +/* Line 1455 of yacc.c */ +#line 2260 "osm_qos_parser_y.y" + { + __parser_str2uint64(&tmp_parser_struct.num_pair[1],(yyvsp[(1) - (1)])); + free((yyvsp[(1) - (1)])); + } + break; + + + +/* Line 1455 of yacc.c */ +#line 4167 "osm_qos_parser_y.c" + default: break; + } + YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + + /* Now `shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*------------------------------------. +| yyerrlab -- here on detecting error | +`------------------------------------*/ +yyerrlab: + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if ! YYERROR_VERBOSE + yyerror (YY_("syntax error")); +#else + { + YYSIZE_T yysize = yysyntax_error (0, yystate, yychar); + if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM) + { + YYSIZE_T yyalloc = 2 * yysize; + if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM)) + yyalloc = YYSTACK_ALLOC_MAXIMUM; + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yyalloc); + if (yymsg) + yymsg_alloc = yyalloc; + else + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + } + } + + if (0 < yysize && yysize <= yymsg_alloc) + { + (void) yysyntax_error (yymsg, yystate, yychar); + yyerror (yymsg); + } + else + { + yyerror (YY_("syntax error")); + if (yysize != 0) + goto yyexhaustedlab; + } + } +#endif + } + + + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + + /* Pacify compilers like GCC when the user code never invokes + YYERROR and the label yyerrorlab therefore never appears in user + code. */ + if (/*CONSTCOND*/ 0) + goto yyerrorlab; + + /* Do not reclaim the symbols of the rule which action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (yyn != YYPACT_NINF) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + + yydestruct ("Error: popping", + yystos[yystate], yyvsp); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + *++yyvsp = yylval; + + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#if !defined(yyoverflow) || YYERROR_VERBOSE +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here. | +`-------------------------------------------------*/ +yyexhaustedlab: + yyerror (YY_("memory exhausted")); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: + if (yychar != YYEMPTY) + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval); + /* Do not reclaim the symbols of the rule which action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + yystos[*yyssp], yyvsp); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif +#if YYERROR_VERBOSE + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); +#endif + /* Make sure YYID is used. */ + return YYID (yyresult); +} + + + +/* Line 1675 of yacc.c */ +#line 2266 "osm_qos_parser_y.y" + + +/*************************************************** + ***************************************************/ + +int osm_qos_parse_policy_file(IN osm_subn_t * 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) +{ + char *p; + + while (isspace(*str)) + str++; + if (!*str) + return str; + p = str + strlen(str) - 1; + while (isspace(*p)) + *p-- = '\0'; + + return str; +} + +/*************************************************** + ***************************************************/ + +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 __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/branches/WOF2-3/ulp/opensm/user/opensm/osm_qos_parser_y.h b/branches/WOF2-3/ulp/opensm/user/opensm/osm_qos_parser_y.h new file mode 100644 index 00000000..ed19e9a0 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_qos_parser_y.h @@ -0,0 +1,208 @@ + +/* A Bison parser, made by GNU Bison 2.4.1. */ + +/* Skeleton interface for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 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, see . */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + TK_NUMBER = 258, + TK_DASH = 259, + TK_DOTDOT = 260, + TK_COMMA = 261, + TK_ASTERISK = 262, + TK_TEXT = 263, + TK_QOS_ULPS_START = 264, + TK_QOS_ULPS_END = 265, + TK_PORT_GROUPS_START = 266, + TK_PORT_GROUPS_END = 267, + TK_PORT_GROUP_START = 268, + TK_PORT_GROUP_END = 269, + TK_QOS_SETUP_START = 270, + TK_QOS_SETUP_END = 271, + TK_VLARB_TABLES_START = 272, + TK_VLARB_TABLES_END = 273, + TK_VLARB_SCOPE_START = 274, + TK_VLARB_SCOPE_END = 275, + TK_SL2VL_TABLES_START = 276, + TK_SL2VL_TABLES_END = 277, + TK_SL2VL_SCOPE_START = 278, + TK_SL2VL_SCOPE_END = 279, + TK_QOS_LEVELS_START = 280, + TK_QOS_LEVELS_END = 281, + TK_QOS_LEVEL_START = 282, + TK_QOS_LEVEL_END = 283, + TK_QOS_MATCH_RULES_START = 284, + TK_QOS_MATCH_RULES_END = 285, + TK_QOS_MATCH_RULE_START = 286, + TK_QOS_MATCH_RULE_END = 287, + TK_NAME = 288, + TK_USE = 289, + TK_PORT_GUID = 290, + TK_PORT_NAME = 291, + TK_PARTITION = 292, + TK_NODE_TYPE = 293, + TK_GROUP = 294, + TK_ACROSS = 295, + TK_VLARB_HIGH = 296, + TK_VLARB_LOW = 297, + TK_VLARB_HIGH_LIMIT = 298, + TK_TO = 299, + TK_FROM = 300, + TK_ACROSS_TO = 301, + TK_ACROSS_FROM = 302, + TK_SL2VL_TABLE = 303, + TK_SL = 304, + TK_MTU_LIMIT = 305, + TK_RATE_LIMIT = 306, + TK_PACKET_LIFE = 307, + TK_PATH_BITS = 308, + TK_QOS_CLASS = 309, + TK_SOURCE = 310, + TK_DESTINATION = 311, + TK_SERVICE_ID = 312, + TK_QOS_LEVEL_NAME = 313, + TK_PKEY = 314, + TK_NODE_TYPE_ROUTER = 315, + TK_NODE_TYPE_CA = 316, + TK_NODE_TYPE_SWITCH = 317, + TK_NODE_TYPE_SELF = 318, + TK_NODE_TYPE_ALL = 319, + TK_ULP_DEFAULT = 320, + TK_ULP_ANY_SERVICE_ID = 321, + TK_ULP_ANY_PKEY = 322, + TK_ULP_ANY_TARGET_PORT_GUID = 323, + TK_ULP_SDP_DEFAULT = 324, + TK_ULP_SDP_PORT = 325, + TK_ULP_RDS_DEFAULT = 326, + TK_ULP_RDS_PORT = 327, + TK_ULP_ISER_DEFAULT = 328, + TK_ULP_ISER_PORT = 329, + TK_ULP_SRP_GUID = 330, + TK_ULP_IPOIB_DEFAULT = 331, + TK_ULP_IPOIB_PKEY = 332 + }; +#endif +/* Tokens. */ +#define TK_NUMBER 258 +#define TK_DASH 259 +#define TK_DOTDOT 260 +#define TK_COMMA 261 +#define TK_ASTERISK 262 +#define TK_TEXT 263 +#define TK_QOS_ULPS_START 264 +#define TK_QOS_ULPS_END 265 +#define TK_PORT_GROUPS_START 266 +#define TK_PORT_GROUPS_END 267 +#define TK_PORT_GROUP_START 268 +#define TK_PORT_GROUP_END 269 +#define TK_QOS_SETUP_START 270 +#define TK_QOS_SETUP_END 271 +#define TK_VLARB_TABLES_START 272 +#define TK_VLARB_TABLES_END 273 +#define TK_VLARB_SCOPE_START 274 +#define TK_VLARB_SCOPE_END 275 +#define TK_SL2VL_TABLES_START 276 +#define TK_SL2VL_TABLES_END 277 +#define TK_SL2VL_SCOPE_START 278 +#define TK_SL2VL_SCOPE_END 279 +#define TK_QOS_LEVELS_START 280 +#define TK_QOS_LEVELS_END 281 +#define TK_QOS_LEVEL_START 282 +#define TK_QOS_LEVEL_END 283 +#define TK_QOS_MATCH_RULES_START 284 +#define TK_QOS_MATCH_RULES_END 285 +#define TK_QOS_MATCH_RULE_START 286 +#define TK_QOS_MATCH_RULE_END 287 +#define TK_NAME 288 +#define TK_USE 289 +#define TK_PORT_GUID 290 +#define TK_PORT_NAME 291 +#define TK_PARTITION 292 +#define TK_NODE_TYPE 293 +#define TK_GROUP 294 +#define TK_ACROSS 295 +#define TK_VLARB_HIGH 296 +#define TK_VLARB_LOW 297 +#define TK_VLARB_HIGH_LIMIT 298 +#define TK_TO 299 +#define TK_FROM 300 +#define TK_ACROSS_TO 301 +#define TK_ACROSS_FROM 302 +#define TK_SL2VL_TABLE 303 +#define TK_SL 304 +#define TK_MTU_LIMIT 305 +#define TK_RATE_LIMIT 306 +#define TK_PACKET_LIFE 307 +#define TK_PATH_BITS 308 +#define TK_QOS_CLASS 309 +#define TK_SOURCE 310 +#define TK_DESTINATION 311 +#define TK_SERVICE_ID 312 +#define TK_QOS_LEVEL_NAME 313 +#define TK_PKEY 314 +#define TK_NODE_TYPE_ROUTER 315 +#define TK_NODE_TYPE_CA 316 +#define TK_NODE_TYPE_SWITCH 317 +#define TK_NODE_TYPE_SELF 318 +#define TK_NODE_TYPE_ALL 319 +#define TK_ULP_DEFAULT 320 +#define TK_ULP_ANY_SERVICE_ID 321 +#define TK_ULP_ANY_PKEY 322 +#define TK_ULP_ANY_TARGET_PORT_GUID 323 +#define TK_ULP_SDP_DEFAULT 324 +#define TK_ULP_SDP_PORT 325 +#define TK_ULP_RDS_DEFAULT 326 +#define TK_ULP_RDS_PORT 327 +#define TK_ULP_ISER_DEFAULT 328 +#define TK_ULP_ISER_PORT 329 +#define TK_ULP_SRP_GUID 330 +#define TK_ULP_IPOIB_DEFAULT 331 +#define TK_ULP_IPOIB_PKEY 332 + + + + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef int YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +#endif + +extern YYSTYPE yylval; + + diff --git a/branches/WOF2-3/ulp/opensm/user/opensm/osm_qos_parser_y.y b/branches/WOF2-3/ulp/opensm/user/opensm/osm_qos_parser_y.y new file mode 100644 index 00000000..f5c9ba0d --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_qos_parser_y.y @@ -0,0 +1,3066 @@ +%{ +/* + * Copyright (c) 2004-2009 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 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 + */ +#ifdef __WIN__ +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __WIN__ +/* prevent redefinition in windows header files */ +#define malloc +#define free +#endif + +#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; +#ifndef __WIN__ +extern int errno; +#endif +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 ( (int64_t)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 ( (uint64_t)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 * 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) +{ + char *p; + + while (isspace(*str)) + str++; + if (!*str) + return str; + p = str + strlen(str) - 1; + while (isspace(*p)) + *p-- = '\0'; + + return str; +} + +/*************************************************** + ***************************************************/ + +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 __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/branches/WOF2-3/ulp/opensm/user/opensm/osm_qos_policy.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_qos_policy.c new file mode 100644 index 00000000..8156c9df --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_qos_policy.c @@ -0,0 +1,1057 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2009 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Copyright (c) 2008 Xsigo Systems Inc. All rights reserved. + * Copyright (c) 2009 HNR Consulting. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * OSM QoS Policy functions. + * + * Author: + * Yevgeny Kliteynik, Mellanox + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern osm_qos_level_t __default_simple_qos_level; + +/*************************************************** + ***************************************************/ + +static void +__build_nodebyname_hash(osm_qos_policy_t * p_qos_policy) +{ + osm_node_t * p_node; + cl_qmap_t * p_node_guid_tbl = &p_qos_policy->p_subn->node_guid_tbl; + + p_qos_policy->p_node_hash = st_init_strtable(); + CL_ASSERT(p_qos_policy->p_node_hash); + + if (!p_node_guid_tbl || !cl_qmap_count(p_node_guid_tbl)) + return; + + for (p_node = (osm_node_t *) cl_qmap_head(p_node_guid_tbl); + p_node != (osm_node_t *) cl_qmap_end(p_node_guid_tbl); + p_node = (osm_node_t *) cl_qmap_next(&p_node->map_item)) { + if (!st_lookup(p_qos_policy->p_node_hash, + (st_data_t)p_node->print_desc, NULL)) + st_insert(p_qos_policy->p_node_hash, + (st_data_t)p_node->print_desc, + (st_data_t)p_node); + } +} + +/*************************************************** + ***************************************************/ + +static boolean_t +__is_num_in_range_arr(uint64_t ** range_arr, + unsigned range_arr_len, uint64_t num) +{ + unsigned ind_1 = 0; + unsigned ind_2 = range_arr_len - 1; + unsigned ind_mid; + + if (!range_arr || !range_arr_len) + return FALSE; + + while (ind_1 <= ind_2) { + if (num < range_arr[ind_1][0] || num > range_arr[ind_2][1]) + return FALSE; + else if (num <= range_arr[ind_1][1] || num >= range_arr[ind_2][0]) + return TRUE; + + ind_mid = ind_1 + (ind_2 - ind_1 + 1)/2; + + if (num < range_arr[ind_mid][0]) + ind_2 = ind_mid; + else if (num > range_arr[ind_mid][1]) + ind_1 = ind_mid; + else + return TRUE; + + ind_1++; + ind_2--; + } + + return FALSE; +} + +/*************************************************** + ***************************************************/ + +static void __free_single_element(void *p_element, void *context) +{ + if (p_element) + free(p_element); +} + +/*************************************************** + ***************************************************/ + +osm_qos_port_t *osm_qos_policy_port_create(osm_physp_t *p_physp) +{ + osm_qos_port_t *p = + (osm_qos_port_t *) calloc(1, sizeof(osm_qos_port_t)); + if (p) + 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 *) calloc(1, sizeof(osm_qos_port_group_t)); + if (p) + 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 *) calloc(1, sizeof(osm_qos_vlarb_scope_t)); + if (p) { + 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 *) calloc(1, sizeof(osm_qos_sl2vl_scope_t)); + if (p) { + 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 *) calloc(1, 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(ib_pkey_get_base(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 *) calloc(1, sizeof(osm_qos_match_rule_t)); + if (p) { + 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 *)calloc(1, sizeof(osm_qos_policy_t)); + if (!p_qos_policy) + return NULL; + + cl_list_construct(&p_qos_policy->port_groups); + cl_list_init(&p_qos_policy->port_groups, 10); + + cl_list_construct(&p_qos_policy->vlarb_tables); + cl_list_init(&p_qos_policy->vlarb_tables, 10); + + cl_list_construct(&p_qos_policy->sl2vl_tables); + cl_list_init(&p_qos_policy->sl2vl_tables, 10); + + cl_list_construct(&p_qos_policy->qos_levels); + cl_list_init(&p_qos_policy->qos_levels, 10); + + cl_list_construct(&p_qos_policy->qos_match_rules); + cl_list_init(&p_qos_policy->qos_match_rules, 10); + + p_qos_policy->p_subn = p_subn; + __build_nodebyname_hash(p_qos_policy); + + return p_qos_policy; +} + +/*************************************************** + ***************************************************/ + +void osm_qos_policy_destroy(osm_qos_policy_t * p_qos_policy) +{ + cl_list_iterator_t list_iterator; + osm_qos_port_group_t *p_port_group = NULL; + osm_qos_vlarb_scope_t *p_vlarb_scope = NULL; + osm_qos_sl2vl_scope_t *p_sl2vl_scope = NULL; + osm_qos_level_t *p_qos_level = NULL; + osm_qos_match_rule_t *p_qos_match_rule = NULL; + + if (!p_qos_policy) + return; + + list_iterator = cl_list_head(&p_qos_policy->port_groups); + while (list_iterator != cl_list_end(&p_qos_policy->port_groups)) { + p_port_group = + (osm_qos_port_group_t *) cl_list_obj(list_iterator); + if (p_port_group) + osm_qos_policy_port_group_destroy(p_port_group); + list_iterator = cl_list_next(list_iterator); + } + cl_list_remove_all(&p_qos_policy->port_groups); + cl_list_destroy(&p_qos_policy->port_groups); + + list_iterator = cl_list_head(&p_qos_policy->vlarb_tables); + while (list_iterator != cl_list_end(&p_qos_policy->vlarb_tables)) { + p_vlarb_scope = + (osm_qos_vlarb_scope_t *) cl_list_obj(list_iterator); + if (p_vlarb_scope) + osm_qos_policy_vlarb_scope_destroy(p_vlarb_scope); + list_iterator = cl_list_next(list_iterator); + } + cl_list_remove_all(&p_qos_policy->vlarb_tables); + cl_list_destroy(&p_qos_policy->vlarb_tables); + + list_iterator = cl_list_head(&p_qos_policy->sl2vl_tables); + while (list_iterator != cl_list_end(&p_qos_policy->sl2vl_tables)) { + p_sl2vl_scope = + (osm_qos_sl2vl_scope_t *) cl_list_obj(list_iterator); + if (p_sl2vl_scope) + osm_qos_policy_sl2vl_scope_destroy(p_sl2vl_scope); + list_iterator = cl_list_next(list_iterator); + } + cl_list_remove_all(&p_qos_policy->sl2vl_tables); + cl_list_destroy(&p_qos_policy->sl2vl_tables); + + list_iterator = cl_list_head(&p_qos_policy->qos_levels); + while (list_iterator != cl_list_end(&p_qos_policy->qos_levels)) { + p_qos_level = (osm_qos_level_t *) cl_list_obj(list_iterator); + if (p_qos_level) + osm_qos_policy_qos_level_destroy(p_qos_level); + list_iterator = cl_list_next(list_iterator); + } + cl_list_remove_all(&p_qos_policy->qos_levels); + cl_list_destroy(&p_qos_policy->qos_levels); + + list_iterator = cl_list_head(&p_qos_policy->qos_match_rules); + while (list_iterator != cl_list_end(&p_qos_policy->qos_match_rules)) { + p_qos_match_rule = + (osm_qos_match_rule_t *) cl_list_obj(list_iterator); + if (p_qos_match_rule) + osm_qos_policy_match_rule_destroy(p_qos_match_rule); + list_iterator = cl_list_next(list_iterator); + } + cl_list_remove_all(&p_qos_policy->qos_match_rules); + cl_list_destroy(&p_qos_policy->qos_match_rules); + + if (p_qos_policy->p_node_hash) + st_free_table(p_qos_policy->p_node_hash); + + free(p_qos_policy); + + p_qos_policy = NULL; +} + +/*************************************************** + ***************************************************/ + +static boolean_t +__qos_policy_is_port_in_group(osm_subn_t * p_subn, + const osm_physp_t * p_physp, + osm_qos_port_group_t * p_port_group) +{ + osm_node_t *p_node = osm_physp_get_node_ptr(p_physp); + ib_net64_t port_guid = osm_physp_get_port_guid(p_physp); + uint64_t port_guid_ho = cl_ntoh64(port_guid); + + /* check whether this port's type matches any of group's types */ + + if ( p_port_group->node_types & + (((uint8_t)1)<port_map, port_guid_ho) != + cl_qmap_end(&p_port_group->port_map)) + return TRUE; + + return FALSE; +} /* __qos_policy_is_port_in_group() */ + +/*************************************************** + ***************************************************/ + +static boolean_t +__qos_policy_is_port_in_group_list(const osm_qos_policy_t * p_qos_policy, + const osm_physp_t * p_physp, + cl_list_t * p_port_group_list) +{ + osm_qos_port_group_t *p_port_group; + cl_list_iterator_t list_iterator; + + list_iterator = cl_list_head(p_port_group_list); + while (list_iterator != cl_list_end(p_port_group_list)) { + p_port_group = + (osm_qos_port_group_t *) cl_list_obj(list_iterator); + if (p_port_group) { + if (__qos_policy_is_port_in_group + (p_qos_policy->p_subn, p_physp, p_port_group)) + return TRUE; + } + list_iterator = cl_list_next(list_iterator); + } + return FALSE; +} + +/*************************************************** + ***************************************************/ + +static osm_qos_match_rule_t *__qos_policy_get_match_rule_by_params( + const osm_qos_policy_t * p_qos_policy, + uint64_t service_id, + uint16_t qos_class, + uint16_t pkey, + const osm_physp_t * p_src_physp, + const osm_physp_t * p_dest_physp, + ib_net64_t comp_mask) +{ + osm_qos_match_rule_t *p_qos_match_rule = NULL; + cl_list_iterator_t list_iterator; + osm_log_t * p_log = &p_qos_policy->p_subn->p_osm->log; + + boolean_t matched_by_sguid = FALSE, + matched_by_dguid = FALSE, + matched_by_class = FALSE, + matched_by_sid = FALSE, + matched_by_pkey = FALSE; + + if (!cl_list_count(&p_qos_policy->qos_match_rules)) + return NULL; + + OSM_LOG_ENTER(p_log); + + /* Go over all QoS match rules and find the one that matches the request */ + + list_iterator = cl_list_head(&p_qos_policy->qos_match_rules); + while (list_iterator != cl_list_end(&p_qos_policy->qos_match_rules)) { + p_qos_match_rule = + (osm_qos_match_rule_t *) cl_list_obj(list_iterator); + if (!p_qos_match_rule) { + list_iterator = cl_list_next(list_iterator); + continue; + } + + /* If a match rule has Source groups, PR request source has to be in this list */ + + if (cl_list_count(&p_qos_match_rule->source_group_list)) { + if (!__qos_policy_is_port_in_group_list(p_qos_policy, + p_src_physp, + &p_qos_match_rule-> + source_group_list)) + { + list_iterator = cl_list_next(list_iterator); + continue; + } + matched_by_sguid = TRUE; + } + + /* If a match rule has Destination groups, PR request dest. has to be in this list */ + + if (cl_list_count(&p_qos_match_rule->destination_group_list)) { + if (!__qos_policy_is_port_in_group_list(p_qos_policy, + p_dest_physp, + &p_qos_match_rule-> + destination_group_list)) + { + list_iterator = cl_list_next(list_iterator); + continue; + } + matched_by_dguid = TRUE; + } + + /* If a match rule has QoS classes, PR request HAS + to have a matching QoS class to match the rule */ + + if (p_qos_match_rule->qos_class_range_len) { + if (!(comp_mask & IB_PR_COMPMASK_QOS_CLASS)) { + list_iterator = cl_list_next(list_iterator); + continue; + } + + if (!__is_num_in_range_arr + (p_qos_match_rule->qos_class_range_arr, + p_qos_match_rule->qos_class_range_len, + qos_class)) { + list_iterator = cl_list_next(list_iterator); + continue; + } + matched_by_class = TRUE; + } + + /* If a match rule has Service IDs, PR request HAS + to have a matching Service ID to match the rule */ + + if (p_qos_match_rule->service_id_range_len) { + if (!(comp_mask & IB_PR_COMPMASK_SERVICEID_MSB) || + !(comp_mask & IB_PR_COMPMASK_SERVICEID_LSB)) { + list_iterator = cl_list_next(list_iterator); + continue; + } + + if (!__is_num_in_range_arr + (p_qos_match_rule->service_id_range_arr, + p_qos_match_rule->service_id_range_len, + service_id)) { + list_iterator = cl_list_next(list_iterator); + continue; + } + matched_by_sid = TRUE; + } + + /* If a match rule has PKeys, PR request HAS + to have a matching PKey to match the rule */ + + if (p_qos_match_rule->pkey_range_len) { + if (!(comp_mask & IB_PR_COMPMASK_PKEY)) { + list_iterator = cl_list_next(list_iterator); + continue; + } + + if (!__is_num_in_range_arr + (p_qos_match_rule->pkey_range_arr, + p_qos_match_rule->pkey_range_len, + pkey & 0x7FFF)) { + list_iterator = cl_list_next(list_iterator); + continue; + } + matched_by_pkey = TRUE; + } + + /* if we got here, then this match-rule matched this PR request */ + break; + } + + if (list_iterator == cl_list_end(&p_qos_policy->qos_match_rules)) + p_qos_match_rule = NULL; + + if (p_qos_match_rule) + OSM_LOG(p_log, OSM_LOG_DEBUG, + "request matched rule (%s) by:%s%s%s%s%s\n", + (p_qos_match_rule->use) ? + p_qos_match_rule->use : "no description", + (matched_by_sguid) ? " SGUID" : "", + (matched_by_dguid) ? " DGUID" : "", + (matched_by_class) ? " QoS_Class" : "", + (matched_by_sid) ? " ServiceID" : "", + (matched_by_pkey) ? " PKey" : ""); + else + OSM_LOG(p_log, OSM_LOG_DEBUG, + "request not matched any rule\n"); + + OSM_LOG_EXIT(p_log); + return p_qos_match_rule; +} /* __qos_policy_get_match_rule_by_params() */ + +/*************************************************** + ***************************************************/ + +static osm_qos_level_t *__qos_policy_get_qos_level_by_name( + const osm_qos_policy_t * p_qos_policy, + char *name) +{ + osm_qos_level_t *p_qos_level = NULL; + cl_list_iterator_t list_iterator; + + list_iterator = cl_list_head(&p_qos_policy->qos_levels); + while (list_iterator != cl_list_end(&p_qos_policy->qos_levels)) { + p_qos_level = (osm_qos_level_t *) cl_list_obj(list_iterator); + if (!p_qos_level) + continue; + + /* names are case INsensitive */ + if (strcasecmp(name, p_qos_level->name) == 0) + return p_qos_level; + + list_iterator = cl_list_next(list_iterator); + } + + return NULL; +} + +/*************************************************** + ***************************************************/ + +static osm_qos_port_group_t *__qos_policy_get_port_group_by_name( + const osm_qos_policy_t * p_qos_policy, + const char *const name) +{ + osm_qos_port_group_t *p_port_group = NULL; + cl_list_iterator_t list_iterator; + + list_iterator = cl_list_head(&p_qos_policy->port_groups); + while (list_iterator != cl_list_end(&p_qos_policy->port_groups)) { + p_port_group = + (osm_qos_port_group_t *) cl_list_obj(list_iterator); + if (!p_port_group) + continue; + + /* names are case INsensitive */ + if (strcasecmp(name, p_port_group->name) == 0) + return p_port_group; + + list_iterator = cl_list_next(list_iterator); + } + + return NULL; +} + +/*************************************************** + ***************************************************/ + +static void __qos_policy_validate_pkey( + osm_qos_policy_t * p_qos_policy, + osm_qos_match_rule_t * p_qos_match_rule, + osm_prtn_t * p_prtn) +{ + uint8_t sl; + uint32_t flow; + uint8_t hop; + + 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->mgrp) + return; + + CL_ASSERT((cl_ntoh16(p_prtn->mgrp->mcmember_rec.pkey) & 0x7fff) == + (cl_ntoh16(p_prtn->pkey) & 0x7fff)); + + ib_member_get_sl_flow_hop(p_prtn->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_prtn->mgrp->mcmember_rec.mlid), + p_prtn->sl); + p_prtn->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/branches/WOF2-3/ulp/opensm/user/opensm/osm_remote_sm.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_remote_sm.c new file mode 100644 index 00000000..6b8bd1c9 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_remote_sm.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_sm_t. + * This object represents the remote SM object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include + +void osm_remote_sm_construct(IN osm_remote_sm_t * p_sm) +{ + memset(p_sm, 0, sizeof(*p_sm)); +} + +void osm_remote_sm_destroy(IN osm_remote_sm_t * p_sm) +{ + memset(p_sm, 0, sizeof(*p_sm)); +} + +void osm_remote_sm_init(IN osm_remote_sm_t * p_sm, IN const osm_port_t * p_port, + IN const ib_sm_info_t * 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/branches/WOF2-3/ulp/opensm/user/opensm/osm_req.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_req.c new file mode 100644 index 00000000..fe7d134c --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_req.c @@ -0,0 +1,274 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005,2009 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Copyright (c) 2009 HNR Consulting. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_req_t. + * This object represents the generic attribute requester. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/********************************************************************** + The plock MAY or MAY NOT be held before calling this function. +**********************************************************************/ +ib_api_status_t osm_req_get(IN osm_sm_t * sm, IN const osm_dr_path_t * p_path, + IN ib_net16_t attr_id, IN ib_net32_t attr_mod, + IN cl_disp_msgid_t err_msg, + IN const osm_madw_context_t * 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 * p_path, + IN const uint8_t * p_payload, + IN size_t payload_size, + IN ib_net16_t attr_id, IN ib_net32_t attr_mod, + IN cl_disp_msgid_t err_msg, + IN const osm_madw_context_t * 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, *smport; + 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; + + smport = osm_get_port_by_guid(sm->p_subn, sm->master_sm_guid); + if (!smport) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, + "ERR 1106: cannot find master SM port by guid 0x%" PRIx64 "\n", + cl_ntoh64(sm->master_sm_guid)); + return -1; + } + + 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 = smport->p_physp->port_info.base_lid; + madw->mad_addr.addr_type.smi.source_lid = pi->base_lid; + madw->resp_expected = TRUE; + 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 = 0; + + ntc = (ib_mad_notice_attr_t *) smp->data; + + ntc->generic_type = 0x80 | IB_NOTICE_TYPE_INFO; + ib_notice_set_prod_type_ho(ntc, osm_node_get_type(port->p_node)); + 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(madw->mad_addr.dest_lid)); + + osm_vl15_post(sm->p_vl15, madw); + + return 0; +} diff --git a/branches/WOF2-3/ulp/opensm/user/opensm/osm_resp.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_resp.c new file mode 100644 index 00000000..22d5a808 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_resp.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_resp_t. + * This object represents the generic attribute responder. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void resp_make_resp_smp(IN osm_sm_t * sm, IN const ib_smp_t * p_src_smp, + IN ib_net16_t status, + IN const uint8_t * p_payload, + OUT ib_smp_t * 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 * p_req_madw, + IN ib_net16_t mad_status, + IN const uint8_t * 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); + 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/branches/WOF2-3/ulp/opensm/user/opensm/osm_router.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_router.c new file mode 100644 index 00000000..c10b7bee --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_router.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_router_t. + * This object represents an Infiniband router. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include + +void osm_router_delete(IN OUT osm_router_t ** pp_rtr) +{ + free(*pp_rtr); + *pp_rtr = NULL; +} + +osm_router_t *osm_router_new(IN osm_port_t * p_port) +{ + osm_router_t *p_rtr; + + CL_ASSERT(p_port); + + p_rtr = 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/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa.c new file mode 100644 index 00000000..279fd953 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa.c @@ -0,0 +1,1133 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2009 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Copyright (c) 2008 Xsigo Systems Inc. All rights reserved. + * Copyright (c) 2010 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: + * Implementation of osm_sa_t. + * This object represents the Subnet Administration object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define OSM_SA_INITIAL_TID_VALUE 0xabc + +extern void osm_cpi_rcv_process(IN void *context, IN void *data); +extern void osm_gir_rcv_process(IN void *context, IN void *data); +extern void osm_infr_rcv_process(IN void *context, IN void *data); +extern void osm_infir_rcv_process(IN void *context, IN void *data); +extern void osm_lftr_rcv_process(IN void *context, IN void *data); +extern void osm_lr_rcv_process(IN void *context, IN void *data); +extern void osm_mcmr_rcv_process(IN void *context, IN void *data); +extern void osm_mftr_rcv_process(IN void *context, IN void *data); +extern void osm_mpr_rcv_process(IN void *context, IN void *data); +extern void osm_nr_rcv_process(IN void *context, IN void *data); +extern void osm_pr_rcv_process(IN void *context, IN void *data); +extern void osm_pkey_rec_rcv_process(IN void *context, IN void *data); +extern void osm_pir_rcv_process(IN void *context, IN void *data); +extern void osm_sr_rcv_process(IN void *context, IN void *data); +extern void osm_slvl_rec_rcv_process(IN void *context, IN void *data); +extern void osm_smir_rcv_process(IN void *context, IN void *data); +extern void osm_sir_rcv_process(IN void *context, IN void *data); +extern void osm_vlarb_rec_rcv_process(IN void *context, IN void *data); +extern void osm_sr_rcv_lease_cb(IN void *context); + +void osm_sa_construct(IN osm_sa_t * 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 * 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 * 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 * p_sm, IN osm_sa_t * p_sa, + IN osm_subn_t * p_subn, IN osm_vendor_t * p_vendor, + IN osm_mad_pool_t * p_mad_pool, + IN osm_log_t * p_log, IN osm_stats_t * p_stats, + IN cl_dispatcher_t * p_disp, IN cl_plock_t * p_lock) +{ + ib_api_status_t status; + + 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; + + status = IB_INSUFFICIENT_RESOURCES; + 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; + + status = IB_SUCCESS; +Exit: + OSM_LOG_EXIT(p_log); + return status; +} + +ib_api_status_t osm_sa_bind(IN osm_sa_t * p_sa, IN 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 * p_madw, + IN boolean_t 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 * p_madw, + IN 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 + unsigned char *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 %u records for SubnAdmGet(%s) comp_mask 0x%016" PRIx64 "\n", + num_rec, ib_get_sa_attr_str(sa_mad->attr_id), + cl_ntoh64(sa_mad->comp_mask)); + 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; + +#ifdef DUAL_SIDED_RMPP + if (resp_sa_mad->method == IB_MAD_METHOD_GETTABLE_RESP || + resp_sa_mad->method == IB_MAD_METHOD_GETMULTI_RESP) { +#else + if (resp_sa_mad->method == IB_MAD_METHOD_GETTABLE_RESP) { +#endif + /* 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_dump_sa_mad(sa->p_log, resp_sa_mad, OSM_LOG_FRAMES); + osm_sa_send(sa, resp_madw, FALSE); + +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; + + 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 (p_mgrp = (osm_mgrp_t *) cl_fmap_head(&p_osm->subn.mgrp_mgid_tbl); + p_mgrp != (osm_mgrp_t *) cl_fmap_end(&p_osm->subn.mgrp_mgid_tbl); + p_mgrp = (osm_mgrp_t *) cl_fmap_next(&p_mgrp->map_item)) + 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) +{ + int res = 1; + if (p_osm->sa.dirty) { + res = opensm_dump_to_file( + p_osm, "opensm-sa.dump", sa_dump_all_sa); + p_osm->sa.dirty = FALSE; + } + return res; +} + +/* + * 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_mgid(&p_osm->subn, &p_mcm_rec->mgid); + if (p_mgrp) { + if (p_mgrp->mlid == mlid) { + 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; + + if (!p_osm->subn.first_time_master_sweep) { + OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, + "Not first sweep - skip SA DB restore\n"); + return 0; + } + + 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; + } + + OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, + "Restoring SA DB from file \'%s\'\n", + file_name); + + 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_member_rec_t mcmr; + ib_net64_t guid; + osm_port_t *port; + boolean_t proxy; + + PARSE_AHEAD(p, net64, " port_gid=0x", + &mcmr.port_gid.unicast.prefix); + PARSE_AHEAD(p, net64, ":0x", + &mcmr.port_gid.unicast.interface_id); + PARSE_AHEAD(p, net8, " scope_state=0x", &mcmr.scope_state); + PARSE_AHEAD(p, net8, " proxy_join=0x", &val); + proxy = val; + + guid = mcmr.port_gid.unicast.interface_id; + port = osm_get_port_by_guid(&p_osm->subn, guid); + if (port && + cl_qmap_get(&p_mgrp->mcm_port_tbl, guid) == + cl_qmap_end(&p_mgrp->mcm_port_tbl) && + !osm_mgrp_add_port(&p_osm->subn, &p_osm->log, + p_mgrp, port, &mcmr, proxy)) + rereg_clients = 1; + } 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 loading succeeded, do whatever 'no_clients_rereg' says. + * If loading failed at some point, turn off the 'no_clients_rereg' + * option (turn on re-registartion requests). + */ + if (rereg_clients) + p_osm->subn.opt.no_clients_rereg = FALSE; + + /* We've just finished loading SA DB file - clear the "dirty" flag */ + p_osm->sa.dirty = FALSE; + +_error: + fclose(file); + return ret; +} diff --git a/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_class_port_info.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_class_port_info.c new file mode 100644 index 00000000..b3dd7979 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_class_port_info.c @@ -0,0 +1,207 @@ +/* + * 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 osm_cpi_rcv_t. + * This object represents the ClassPortInfo Receiver object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_MSECS_TO_RTV 24 +/* Precalculated table in msec (index is related to encoded value) */ +/* 4.096 usec * 2 ** n (where n = 8 - 31) */ +const static uint32_t msecs_to_rtv_table[MAX_MSECS_TO_RTV] = { + 1, 2, 4, 8, + 16, 33, 67, 134, + 268, 536, 1073, 2147, + 4294, 8589, 17179, 34359, + 68719, 137438, 274877, 549755, + 1099511, 2199023, 4398046, 8796093 +}; + +static void cpi_rcv_respond(IN osm_sa_t * sa, IN const osm_madw_t * 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 at the SMDB - no lock required. */ + + cpi_rcv_respond(sa, p_madw); + +Exit: + OSM_LOG_EXIT(sa->p_log); +} diff --git a/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_guidinfo_record.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_guidinfo_record.c new file mode 100644 index 00000000..b99cc2cf --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_guidinfo_record.c @@ -0,0 +1,346 @@ +/* + * Copyright (c) 2006-2009 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_gir_rcv_t. + * This object represents the GUIDInfoRecord Receiver object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct osm_gir_item { + cl_list_item_t list_item; + ib_guidinfo_record_t rec; +} osm_gir_item_t; + +typedef struct osm_gir_search_ctxt { + const ib_guidinfo_record_t *p_rcvd_rec; + ib_net64_t comp_mask; + cl_qlist_t *p_list; + osm_sa_t *sa; + const osm_physp_t *p_req_physp; +} osm_gir_search_ctxt_t; + +static ib_api_status_t gir_rcv_new_gir(IN osm_sa_t * sa, + IN const osm_node_t * p_node, + IN cl_qlist_t * p_list, + IN ib_net64_t const match_port_guid, + IN ib_net16_t const match_lid, + IN const osm_physp_t * 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 sa_gir_create_gir(IN osm_sa_t * sa, IN osm_node_t * p_node, + IN cl_qlist_t * p_list, + IN ib_net64_t const match_port_guid, + IN ib_net16_t const match_lid, + IN const osm_physp_t * 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++) + 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 sa_gir_by_comp_mask_cb(IN cl_map_item_t * p_map_item, IN void *cxt) +{ + const osm_gir_search_ctxt_t *p_ctxt = cxt; + 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; + } + + 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, 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/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_informinfo.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_informinfo.c new file mode 100644 index 00000000..12451098 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_informinfo.c @@ -0,0 +1,595 @@ +/* + * Copyright (c) 2004-2009 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) 2009 HNR Consulting. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_infr_rcv_t. + * This object represents the InformInfo Receiver object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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; + ib_net64_t portguid; + uint16_t lid_range_begin, lid_range_end, lid; + + 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); + + if (ib_gid_is_notzero(&p_infr_rec->inform_record.inform_info.gid)) { + /* 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; + } + + /* 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_port->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 { + size_t lids_size; + + /* 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); + + lids_size = cl_ptr_vector_get_size(&sa->p_subn->port_lid_tbl); + + /* 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; + else if (lid_range_end >= lids_size) + lid_range_end = lids_size - 1; + + if (lid_range_begin >= lids_size) { + /* requested lids are out of range */ + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4302: " + "Given LIDs (%u-%u) are out of range (%u)\n", + lid_range_begin, lid_range_end, lids_size); + valid = FALSE; + goto Exit; + } + + /* 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_port = osm_get_port_by_lid_ho(sa->p_subn, lid); + if (p_port == NULL) + continue; + + /* 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_port->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 infr_rcv_respond(IN osm_sa_t * sa, IN osm_madw_t * 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 sa_inform_info_rec_by_comp_mask(IN osm_sa_t * sa, + IN const osm_infr_t * p_infr, + osm_iir_search_ctxt_t * 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(&p_rec_item->rec, &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 sa_inform_info_rec_by_comp_mask_cb(IN cl_list_item_t * p_list_item, + IN void *context) +{ + const osm_infr_t *p_infr = (osm_infr_t *) p_list_item; + osm_iir_search_ctxt_t *p_ctxt = context; + + sa_inform_info_rec_by_comp_mask(p_ctxt->sa, p_infr, p_ctxt); +} + +/********************************************************************** +Received a Get(InformInfoRecord) or GetTable(InformInfoRecord) MAD +**********************************************************************/ +static void infr_rcv_process_get_method(osm_sa_t * sa, IN osm_madw_t * 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, + 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 infr_rcv_process_set_method(osm_sa_t * sa, IN osm_madw_t * 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 */ + 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; + } + + 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; + } + + infr_rcv_process_get_method(sa, p_madw); + +Exit: + OSM_LOG_EXIT(sa->p_log); +} diff --git a/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_lft_record.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_lft_record.c new file mode 100644 index 00000000..96b86e28 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_lft_record.c @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005,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_lftr_rcv_t. + * This object represents the LinearForwardingTable Receiver object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct osm_lftr_item { + cl_list_item_t list_item; + ib_lft_record_t rec; +} osm_lftr_item_t; + +typedef struct osm_lftr_search_ctxt { + const ib_lft_record_t *p_rcvd_rec; + ib_net64_t comp_mask; + cl_qlist_t *p_list; + osm_sa_t *sa; + const osm_physp_t *p_req_physp; +} osm_lftr_search_ctxt_t; + +static ib_api_status_t lftr_rcv_new_lftr(IN osm_sa_t * sa, + IN const osm_switch_t * p_sw, + IN cl_qlist_t * p_list, + IN ib_net16_t lid, IN uint16_t 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 lftr_rcv_by_comp_mask(IN cl_map_item_t * p_map_item, IN void *cxt) +{ + const osm_lftr_search_ctxt_t *p_ctxt = cxt; + const osm_switch_t *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++) + 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, 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/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_link_record.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_link_record.c new file mode 100644 index 00000000..966a3af7 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_link_record.c @@ -0,0 +1,477 @@ +/* + * Copyright (c) 2004-2009 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 osm_lr_rcv_t. + * This object represents the LinkRecord Receiver object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct osm_lr_item { + cl_list_item_t list_item; + ib_link_record_t link_rec; +} osm_lr_item_t; + +static void lr_rcv_build_physp_link(IN osm_sa_t * sa, IN ib_net16_t from_lid, + IN ib_net16_t to_lid, IN uint8_t from_port, + IN 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 ib_net16_t get_base_lid(IN const osm_physp_t * p_physp) +{ + if (p_physp->p_node->node_info.node_type == IB_NODE_TYPE_SWITCH) + p_physp = osm_node_get_physp_ptr(p_physp->p_node, 0); + return osm_physp_get_base_lid(p_physp); +} + +static void lr_rcv_get_physp_link(IN osm_sa_t * sa, + IN const ib_link_record_t * 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 * 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; + + from_base_lid = get_base_lid(p_src_physp); + to_base_lid = get_base_lid(p_dest_physp); + + 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); + + 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 lr_rcv_get_port_links(IN osm_sa_t * sa, + IN const ib_link_record_t * 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 * 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) + 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) + 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) + 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) + 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) + 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) + 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 lr_rcv_get_end_points(IN osm_sa_t * sa, + IN const osm_madw_t * p_madw, + OUT const osm_port_t ** pp_src_port, + OUT const osm_port_t ** pp_dest_port) +{ + const ib_link_record_t *p_lr; + const ib_sa_mad_t *p_sa_mad; + ib_net64_t comp_mask; + 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) { + *pp_src_port = osm_get_port_by_lid(sa->p_subn, p_lr->from_lid); + if (!*pp_src_port) { + /* + 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) { + *pp_dest_port = osm_get_port_by_lid(sa->p_subn, p_lr->to_lid); + if (!*pp_dest_port) { + /* + 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 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_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); + + status = lr_rcv_get_end_points(sa, p_madw, &p_src_port, &p_dest_port); + + if (status == IB_SA_MAD_STATUS_SUCCESS) + 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/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_mad_ctrl.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_mad_ctrl.c new file mode 100644 index 00000000..81aa30d4 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_mad_ctrl.c @@ -0,0 +1,565 @@ +/* + * Copyright (c) 2004-2009 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) 2009 HNR Consulting. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_sa_mad_ctrl_t. + * This object is part of the SA object. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/****f* opensm: SA/sa_mad_ctrl_disp_done_callback + * NAME + * 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 sa_mad_ctrl_disp_done_callback(IN void *context, IN void *p_data) +{ + osm_sa_mad_ctrl_t *p_ctrl = context; + osm_madw_t *p_madw = 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/sa_mad_ctrl_process + * NAME + * sa_mad_ctrl_process + * + * DESCRIPTION + * This function handles known methods for received MADs. + * + * SYNOPSIS + */ +static void sa_mad_ctrl_process(IN osm_sa_mad_ctrl_t * 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, + 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 (%s)\n", + CL_STATUS_MSG(status), + cl_ntoh16(p_sa_mad->attr_id), + ib_get_sa_attr_str(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/sa_mad_ctrl_rcv_callback + * NAME + * sa_mad_ctrl_rcv_callback + * + * DESCRIPTION + * This is the callback from the transport layer for received MADs. + * + * SYNOPSIS + */ +static void sa_mad_ctrl_rcv_callback(IN osm_madw_t * p_madw, IN void *context, + IN osm_madw_t * p_req_madw) +{ + osm_sa_mad_ctrl_t *p_ctrl = 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: + 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/sa_mad_ctrl_send_err_callback + * NAME + * 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 sa_mad_ctrl_send_err_callback(IN void *context, + IN osm_madw_t * p_madw) +{ + osm_sa_mad_ctrl_t *p_ctrl = 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); + + /* 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, + 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 * 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 * 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 * p_ctrl, + IN osm_sa_t * sa, + IN osm_mad_pool_t * p_mad_pool, + IN osm_vendor_t * p_vendor, + IN osm_subn_t * p_subn, + IN osm_log_t * p_log, + IN osm_stats_t * p_stats, + IN cl_dispatcher_t * 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 * p_ctrl, + IN 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; + bind_info.timeout = p_ctrl->sa->p_subn->opt.transaction_timeout; + bind_info.retries = p_ctrl->sa->p_subn->opt.transaction_retries; + + 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, + sa_mad_ctrl_rcv_callback, + 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 * 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/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_mcmember_record.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_mcmember_record.c new file mode 100644 index 00000000..6698d6fb --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_mcmember_record.c @@ -0,0 +1,1513 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2009 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Copyright (c) 2008 Xsigo Systems Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_mcmr_recv_t. + * This object represents the MCMemberRecord Receiver object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 void copy_from_create_mc_rec(IN ib_member_rec_t * dest, + IN const ib_member_rec_t * 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. +**********************************************************************/ +/* 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 */ +#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) + +static int compare_ipv6_snm_mgids(const void *m1, const void *m2) +{ + return memcmp(m1, m2, sizeof(ib_gid_t) - 6); +} + +static ib_net16_t find_ipv6_snm_mlid(osm_subn_t *subn, ib_gid_t *mgid) +{ + osm_mgrp_t *m = (osm_mgrp_t *)cl_fmap_match(&subn->mgrp_mgid_tbl, mgid, + compare_ipv6_snm_mgids); + if (m != (osm_mgrp_t *)cl_fmap_end(&subn->mgrp_mgid_tbl)) + return m->mlid; + return 0; +} + +static unsigned match_ipv6_snm_mgid(ib_gid_t * mgid) +{ + return ((mgid->unicast.prefix & PREFIX_MASK) == PREFIX_SIGNATURE && + (mgid->unicast.interface_id & INT_ID_MASK) == INT_ID_SIGNATURE); +} + +static ib_net16_t get_new_mlid(osm_sa_t * sa, ib_member_rec_t * mcmr) +{ + osm_subn_t *p_subn = sa->p_subn; + ib_net16_t requested_mlid = mcmr->mlid; + 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_mbox_by_mlid(p_subn, requested_mlid)) + return requested_mlid; + + if (sa->p_subn->opt.consolidate_ipv6_snm_req + && match_ipv6_snm_mgid(&mcmr->mgid) + && (requested_mlid = find_ipv6_snm_mlid(sa->p_subn, &mcmr->mgid))) { + char 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, mcmr->mgid.raw, str, sizeof(str))); + return requested_mlid; + } + + max = p_subn->max_mcast_lid_ho - IB_LID_MCAST_START_HO + 1; + for (i = 0; i < max; i++) + if (!sa->p_subn->mboxes[i]) + return cl_hton16(i + IB_LID_MCAST_START_HO); + + return 0; +} + +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 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 mcmr_rcv_respond(IN osm_sa_t * sa, IN osm_madw_t * 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_VERBOSE, + "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_VERBOSE, + "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_VERBOSE, + "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_VERBOSE, + "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_VERBOSE, + "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_VERBOSE, + "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 * 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_VERBOSE, + "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_VERBOSE, + "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 = osm_mgrp_get_mcm_port(p_mgrp, portguid); + + /* o15-0.2.1: If this is a new port being added - nothing to check */ + if (!*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->guid), + 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 = osm_mgrp_get_mcm_port(p_mgrp, portguid); + + /* 1 */ + if (!*pp_mcm_port) { + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Failed to find the port in the MC group\n"); + return FALSE; + } + + /* 2 */ + if (!(p_recvd_mcmember_rec->scope_state & 0x0F & + (*pp_mcm_port)->scope_state)) { + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Could not find any matching bits in the stored " + "and requested JoinStates\n"); + return FALSE; + } + + /* 3 */ + if (((p_recvd_mcmember_rec->scope_state & 0x0F) | + (0x0F & (*pp_mcm_port)->scope_state)) != + (0x0F & (*pp_mcm_port)->scope_state)) { + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Some bits in the request JoinState (0x%X) are not " + "set in the stored port (0x%X)\n", + (p_recvd_mcmember_rec->scope_state & 0x0F), + (0x0F & (*pp_mcm_port)->scope_state)); + return FALSE; + } + + /* 4 */ + /* Validate according the the proxy_join (o15-0.1.2) */ + if (validate_modify(sa, p_mgrp, p_mad_addr, p_recvd_mcmember_rec, + pp_mcm_port) == FALSE) { + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "proxy_join validation failure\n"); + return FALSE; + } + return TRUE; +} + +/* + * Check legality of the requested MGID (note this does not hold for SA + * created MGIDs) + * + * Implementing o15-0.1.5: + * A multicast GID is considered to be invalid if: + * 1. It does not comply with the rules as specified in 4.1.1 "GID Usage and + * Properties" on page 145: + * + * 14) The multicast GID format is (bytes are comma sep): + * 0xff,,,,

,

,

,

,

,

,

,

,,,, + * Fl 4bit = Flags (b) + * Sc 4bit = Scope (c) + * Si 16bit = Signature (2) + * P 64bit = GID Prefix (should be a subnet unique ID - normally Subnet Prefix) + * Id 32bit = Unique ID in the Subnet (might be MLID or Pkey ?) + * + * a) 8-bits of 11111111 at the start of the GID identifies this as being a + * multicast GID. + * b) Flags is a set of four 1-bit flags: 000T with three flags reserved + * and defined as zero (0). The T flag is defined as follows: + * i) T = 0 indicates this is a permanently assigned (i.e. wellknown) + * multicast GID. See RFC 2373 and RFC 2375 as reference + * for these permanently assigned GIDs. + * ii) T = 1 indicates this is a non-permanently assigned (i.e. transient) + * multicast GID. + * c) Scope is a 4-bit multicast scope value used to limit the scope of + * the multicast group. The following table defines scope value and + * interpretation. + * + * Multicast Address Scope Values: + * 0x2 Link-local + * 0x5 Site-local + * 0x8 Organization-local + * 0xE Global + * + * 2. It contains the SA-specific signature of 0xA01B and has the link-local + * scope bits set. (EZ: the idea here is that SA created MGIDs are the + * only source for this signature with link-local scope) + */ +static ib_api_status_t validate_requested_mgid(IN osm_sa_t * sa, + IN const ib_member_rec_t * + p_mcm_rec) +{ + uint16_t signature; + boolean_t valid = TRUE; + + OSM_LOG_ENTER(sa->p_log); + + /* 14-a: mcast GID must start with 0xFF */ + if (p_mcm_rec->mgid.multicast.header[0] != 0xFF) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B01: " + "Wrong MGID Prefix 0x%02X must be 0xFF\n", + cl_ntoh16(p_mcm_rec->mgid.multicast.header[0])); + valid = FALSE; + goto Exit; + } + + /* the MGID signature can mark IPoIB or SA assigned MGIDs */ + memcpy(&signature, &(p_mcm_rec->mgid.multicast.raw_group_id), + sizeof(signature)); + signature = cl_ntoh16(signature); + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "MGID Signed as 0x%04X\n", signature); + + /* + * We skip any checks for MGIDs that follow IPoIB + * GID structure as defined by the IETF ipoib-link-multicast. + * + * For IPv4 over IB, the signature will be "0x401B". + * + * | 8 | 4 | 4 | 16 bits | 16 bits | 48 bits | 32 bits | + * +--------+----+----+-----------------+---------+----------+---------+ + * |11111111|0001|scop||< P_Key >|00.......0|| + * +--------+----+----+-----------------+---------+----------+---------+ + * + * For IPv6 over IB, the signature will be "0x601B". + * + * | 8 | 4 | 4 | 16 bits | 16 bits | 80 bits | + * +--------+----+----+-----------------+---------+--------------------+ + * |11111111|0001|scop||< P_Key >|000.............0001| + * +--------+----+----+-----------------+---------+--------------------+ + * + */ + if (signature == 0x401B || signature == 0x601B) { + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Skipping MGID Validation for IPoIB Signed (0x%04X) MGIDs\n", + signature); + goto Exit; + } + + /* 14-b: the 3 upper bits in the "flags" should be zero: */ + if (p_mcm_rec->mgid.multicast.header[1] & 0xE0) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B28: " + "MGID uses Reserved Flags: flags=0x%X\n", + (p_mcm_rec->mgid.multicast.header[1] & 0xE0) >> 4); + valid = FALSE; + goto Exit; + } + + /* 2 - now what if the link local format 0xA01B is used - + the scope should not be link local */ + if (signature == 0xA01B && + (p_mcm_rec->mgid.multicast.header[1] & 0x0F) == + IB_MC_SCOPE_LINK_LOCAL) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B24: " + "MGID uses 0xA01B signature but with link-local scope\n"); + valid = FALSE; + goto Exit; + } + + /* + * For SA assigned MGIDs (signature 0xA01B): + * There is no real way to make sure the Unique MGID Prefix is really unique. + * If we could enforce using the Subnet Prefix for that purpose it would + * have been nice. But the spec does not require it. + */ + +Exit: + OSM_LOG_EXIT(sa->p_log); + return valid; +} + +/********************************************************************** + Check if the requested new MC group parameters are realizable. + Also set the default MTU and Rate if not provided by the user. +**********************************************************************/ +static boolean_t mgrp_request_is_realizable(IN osm_sa_t * sa, + IN ib_net64_t comp_mask, + IN ib_member_rec_t * p_mcm_rec, + IN const osm_physp_t * 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_VERBOSE, + "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_VERBOSE, + "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_VERBOSE, + "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_VERBOSE, + "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; +} + +static unsigned build_new_mgid(osm_sa_t * sa, ib_net64_t comp_mask, + ib_member_rec_t * mcmr) +{ + static uint32_t uniq_count; + ib_gid_t *mgid = &mcmr->mgid; + uint8_t scope; + unsigned i; + + /* use the given scope state only if requested! */ + if (comp_mask & IB_MCR_COMPMASK_SCOPE) + ib_member_get_scope_state(mcmr->scope_state, &scope, NULL); + else + /* to guarantee no collision with other subnets use local scope! */ + scope = IB_MC_SCOPE_LINK_LOCAL; + + mgid->raw[0] = 0xff; + mgid->raw[1] = 0x10 | scope; + mgid->raw[2] = 0xa0; + mgid->raw[3] = 0x1b; + + /* HACK: use the SA port gid to make it globally unique */ + memcpy(&mgid->raw[4], &sa->p_subn->opt.subnet_prefix, sizeof(uint64_t)); + + for (i = 0; i < 1000; i++) { + memcpy(&mgid->raw[10], &uniq_count, 4); + uniq_count++; + if (!osm_get_mgrp_by_mgid(sa->p_subn, mgid)) + return 1; + } + + return 0; +} + +/********************************************************************** + Call this function to create a new mgrp. +**********************************************************************/ +static ib_api_status_t mcmr_rcv_create_new_mgrp(IN osm_sa_t * sa, + IN ib_net64_t comp_mask, + IN const ib_member_rec_t * + p_recvd_mcmember_rec, + IN const osm_physp_t * p_physp, + OUT osm_mgrp_t ** pp_mgrp) +{ + ib_net16_t mlid; + 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); + + /* we need to create the new MGID if it was not defined */ + if (!ib_gid_is_notzero(&p_recvd_mcmember_rec->mgid)) { + /* create a new MGID */ + char gid_str[INET6_ADDRSTRLEN]; + + if (!build_new_mgid(sa, comp_mask, &mcm_rec)) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B23: " + "cannot allocate unique MGID value\n"); + status = IB_SA_MAD_STATUS_NO_RESOURCES; + goto Exit; + } + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Allocated new MGID:%s\n", + inet_ntop(AF_INET6, mcm_rec.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"); + 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"); + status = IB_SA_MAD_STATUS_REQ_INVALID; + goto Exit; + } + + mlid = get_new_mlid(sa, &mcm_rec); + 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)); + + mcm_rec.mlid = mlid; + /* create a new MC Group */ + *pp_mgrp = osm_mgrp_new(sa->p_subn, mlid, &mcm_rec); + 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; + } + + /* 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 */ + +Exit: + OSM_LOG_EXIT(sa->p_log); + return status; +} + +/********************************************************************** + 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 * + p_recvd_mcmember_rec, + OUT osm_mgrp_t ** pp_mgrp) +{ + osm_mgrp_t *mgrp; + + if ((mgrp = osm_get_mgrp_by_mgid(sa->p_subn, + &p_recvd_mcmember_rec->mgid))) { + *pp_mgrp = mgrp; + return IB_SUCCESS; + } + return mcmr_rcv_create_new_mgrp(sa, comp_mask, p_recvd_mcmember_rec, + NULL, pp_mgrp); +} + +/********************************************************************* +Process a request for leaving the group +**********************************************************************/ +static void mcmr_rcv_leave_mgrp(IN osm_sa_t * sa, IN osm_madw_t * 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_net64_t portguid; + osm_mcm_port_t *p_mcm_port; + + 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_subn, &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; + } + + 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; + } + + /* remove port and/or update join state */ + osm_mgrp_remove_port(sa->p_subn, sa->p_log, p_mgrp, p_mcm_port, + &mcmember_rec); + CL_PLOCK_RELEASE(sa->p_lock); + + mcmr_rcv_respond(sa, p_madw, &mcmember_rec); + +Exit: + OSM_LOG_EXIT(sa->p_log); +} + +/********************************************************************** + Handle a join (or create) request +**********************************************************************/ +static void mcmr_rcv_join_mgrp(IN osm_sa_t * sa, IN osm_madw_t * 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; + 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 */ + uint8_t join_state; + boolean_t proxy; + + 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; + } + + proxy = (p_physp != p_request_physp); + + if (proxy && !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_VERBOSE, + "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_subn, &p_recvd_mcmember_rec->mgid); + if (!p_mgrp) { + /* 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 = 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; + } else + /* no need for a new group */ + is_new_group = 0; + + CL_ASSERT(p_mgrp); + + /* + * 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 */ + osm_mgrp_cleanup(sa->p_subn, 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; + } + + /* 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); + + /* create or update existing port (join-state will be updated) */ + p_mcmr_port = osm_mgrp_add_port(sa->p_subn, sa->p_log, p_mgrp, p_port, + &mcmember_rec, proxy); + if (!p_mcmr_port) { + /* we fail to add the port so we might need to delete the group */ + osm_mgrp_cleanup(sa->p_subn, p_mgrp); + CL_PLOCK_RELEASE(sa->p_lock); + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B06: " + "osm_mgrp_add_port failed\n"); + osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_NO_RESOURCES); + goto Exit; + } + + /* Release the lock as we don't need it. */ + CL_PLOCK_RELEASE(sa->p_lock); + + if (osm_log_is_active(sa->p_log, OSM_LOG_DEBUG)) + osm_dump_mc_record(sa->p_log, &mcmember_rec, OSM_LOG_DEBUG); + + 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 mcmr_rcv_new_mcmr(IN osm_sa_t * sa, + IN const ib_member_rec_t * p_rcvd_rec, + IN cl_qlist_t * 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)); + + /* 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 */ + p_mcm_port = osm_mgrp_get_mcm_port(p_mgrp, portguid); + if (!p_mcm_port) /* port not in group */ + goto Exit; + 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 /* 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); + + mcmr_rcv_new_mcmr(sa, &match_rec, list); + } + p_item = cl_qmap_next(p_item); + } + } else { /* One MC record returned */ + 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; + + mcmr_rcv_new_mcmr(sa, &match_rec, list); + } + +Exit: + OSM_LOG_EXIT(sa->p_log); +} + +/********************************************************************** + Handle a query request +**********************************************************************/ +static void mcmr_query_mgrp(IN osm_sa_t * sa, IN osm_madw_t * 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; + + 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 (p_mgrp = (osm_mgrp_t *) cl_fmap_head(&sa->p_subn->mgrp_mgid_tbl); + p_mgrp != (osm_mgrp_t *) cl_fmap_end(&sa->p_subn->mgrp_mgid_tbl); + p_mgrp = (osm_mgrp_t *) cl_fmap_next(&p_mgrp->map_item)) + 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 + */ + 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 + */ + mcmr_rcv_leave_mgrp(sa, p_madw); + break; + case IB_MAD_METHOD_GET: + case IB_MAD_METHOD_GETTABLE: + /* + * Querying a Multicast Group + */ + 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/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_mft_record.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_mft_record.c new file mode 100644 index 00000000..a38ee51c --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_mft_record.c @@ -0,0 +1,269 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_mftr_rcv_t. + * This object represents the MulticastForwardingTable Receiver object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct osm_mftr_item { + cl_list_item_t list_item; + ib_mft_record_t rec; +} osm_mftr_item_t; + +typedef struct osm_mftr_search_ctxt { + const ib_mft_record_t *p_rcvd_rec; + ib_net64_t comp_mask; + cl_qlist_t *p_list; + osm_sa_t *sa; + const osm_physp_t *p_req_physp; +} osm_mftr_search_ctxt_t; + +static ib_api_status_t mftr_rcv_new_mftr(IN osm_sa_t * sa, + IN osm_switch_t * p_sw, + IN cl_qlist_t * p_list, + IN ib_net16_t lid, IN uint16_t block, + IN uint8_t 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 mftr_rcv_by_comp_mask(IN cl_map_item_t * p_map_item, IN void *cxt) +{ + const osm_mftr_search_ctxt_t *p_ctxt = cxt; + osm_switch_t *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++) + 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, 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/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_multipath_record.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_multipath_record.c new file mode 100644 index 00000000..9712bd5c --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_multipath_record.c @@ -0,0 +1,1482 @@ +/* + * Copyright (c) 2006-2009 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 osm_mpr_rcv_t. + * This object represents the MultiPath Record Receiver object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#if defined (VENDOR_RMPP_SUPPORT) && defined (DUAL_SIDED_RMPP) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define OSM_SA_MPR_MAX_NUM_PATH 127 + +typedef struct osm_mpr_item { + cl_list_item_t list_item; + ib_path_rec_t path_rec; + const osm_port_t *p_src_port; + const osm_port_t *p_dest_port; + int hops; +} osm_mpr_item_t; + +typedef struct osm_path_parms { + ib_net16_t pkey; + uint8_t mtu; + uint8_t rate; + uint8_t sl; + uint8_t pkt_life; + boolean_t reversible; + int hops; +} osm_path_parms_t; + +static boolean_t sa_multipath_rec_is_tavor_port(IN const osm_port_t * 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 +sa_multipath_rec_apply_tavor_mtu_limit(IN const ib_multipath_rec_t * p_mpr, + IN const osm_port_t * p_src_port, + IN const osm_port_t * 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 (!sa_multipath_rec_is_tavor_port(p_src_port) && + !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 mpr_rcv_get_path_parms(IN osm_sa_t * sa, + IN const ib_multipath_rec_t * + p_mpr, + IN const osm_port_t * p_src_port, + IN const osm_port_t * p_dest_port, + IN const uint16_t dest_lid_ho, + IN const ib_net64_t comp_mask, + OUT osm_path_parms_t * 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 && + 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 constraints: 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 mpr_rcv_build_pr(IN osm_sa_t * sa, IN const osm_port_t * p_src_port, + IN const osm_port_t * p_dest_port, + IN uint16_t src_lid_ho, IN uint16_t dest_lid_ho, + IN uint8_t preference, + IN const osm_path_parms_t * p_parms, + OUT ib_path_rec_t * 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 *mpr_rcv_get_lid_pair_path(IN osm_sa_t * sa, + IN const ib_multipath_rec_t * + p_mpr, + IN const osm_port_t * + p_src_port, + IN const osm_port_t * + 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 = 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 = 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; + + 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 mpr_rcv_get_port_pair_paths(IN osm_sa_t * sa, + IN const ib_multipath_rec_t * p_mpr, + IN const osm_port_t * p_req_port, + IN const osm_port_t * p_src_port, + IN const osm_port_t * p_dest_port, + IN const uint32_t rem_paths, + IN const ib_net64_t comp_mask, + IN cl_qlist_t * 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; + unsigned src_offset, 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 = 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 = 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 *mpr_rcv_get_apm_port_pair_paths(IN osm_sa_t * sa, + IN const + ib_multipath_rec_t * + p_mpr, + IN const osm_port_t * + p_src_port, + IN const osm_port_t * + p_dest_port, + IN int base_offs, + IN const ib_net64_t + comp_mask, + IN cl_qlist_t * 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; + unsigned 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 = 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 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 mpr_rcv_get_end_points(IN osm_sa_t * sa, + IN const osm_madw_t * 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 = 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 = + 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 mpr_rcv_get_apm_paths(IN osm_sa_t * sa, + IN const ib_multipath_rec_t * p_mpr, + IN const osm_port_t * p_req_port, + IN osm_port_t ** _pp_ports, + IN const ib_net64_t comp_mask, + IN cl_qlist_t * 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 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 independent, 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] = + 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] = + 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] = + 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] = + 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 mpr_rcv_process_pairs(IN osm_sa_t * sa, + IN const ib_multipath_rec_t * p_mpr, + IN osm_port_t * p_req_port, + IN osm_port_t ** pp_ports, IN const int nsrc, + IN int ndest, IN ib_net64_t comp_mask, + IN cl_qlist_t * 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 = + 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 = 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: " + "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) + mpr_rcv_get_apm_paths(sa, p_mpr, requester_port, pp_ports, + p_sa_mad->comp_mask, &pr_list); + else + 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/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_node_record.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_node_record.c new file mode 100644 index 00000000..8a2f83a4 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_node_record.c @@ -0,0 +1,337 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_nr_rcv_t. + * This object represents the NodeInfo Receiver object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct osm_nr_item { + cl_list_item_t list_item; + ib_node_record_t rec; +} osm_nr_item_t; + +typedef struct osm_nr_search_ctxt { + const ib_node_record_t *p_rcvd_rec; + ib_net64_t comp_mask; + cl_qlist_t *p_list; + osm_sa_t *sa; + const osm_physp_t *p_req_physp; +} osm_nr_search_ctxt_t; + +static ib_api_status_t nr_rcv_new_nr(osm_sa_t * sa, + IN const osm_node_t * p_node, + IN cl_qlist_t * p_list, + IN ib_net64_t port_guid, IN ib_net16_t 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 nr_rcv_create_nr(IN osm_sa_t * sa, IN osm_node_t * p_node, + IN cl_qlist_t * p_list, + IN ib_net64_t const match_port_guid, + IN ib_net16_t const match_lid, + IN const osm_physp_t * p_req_physp, + IN const ib_net64_t comp_mask) +{ + 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 ((comp_mask & IB_NR_COMPMASK_PORTGUID) + && (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 (comp_mask & IB_NR_COMPMASK_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) + continue; + } + + nr_rcv_new_nr(sa, p_node, p_list, port_guid, base_lid); + } + + OSM_LOG_EXIT(sa->p_log); +} + +static void nr_rcv_by_comp_mask(IN cl_map_item_t * p_map_item, IN void *context) +{ + const osm_nr_search_ctxt_t *p_ctxt = context; + osm_node_t *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 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_DEBUG); + + 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) && + p_node->node_info.sys_guid != p_rcvd_rec->node_info.sys_guid) + goto Exit; + + if ((comp_mask & IB_NR_COMPMASK_BASEVERSION) && + p_node->node_info.base_version != + p_rcvd_rec->node_info.base_version) + goto Exit; + + if ((comp_mask & IB_NR_COMPMASK_CLASSVERSION) && + p_node->node_info.class_version != + p_rcvd_rec->node_info.class_version) + goto Exit; + + if ((comp_mask & IB_NR_COMPMASK_NODETYPE) && + p_node->node_info.node_type != p_rcvd_rec->node_info.node_type) + goto Exit; + + if ((comp_mask & IB_NR_COMPMASK_NUMPORTS) && + p_node->node_info.num_ports != p_rcvd_rec->node_info.num_ports) + goto Exit; + + if ((comp_mask & IB_NR_COMPMASK_PARTCAP) && + p_node->node_info.partition_cap != + p_rcvd_rec->node_info.partition_cap) + goto Exit; + + if ((comp_mask & IB_NR_COMPMASK_DEVID) && + p_node->node_info.device_id != p_rcvd_rec->node_info.device_id) + goto Exit; + + if ((comp_mask & IB_NR_COMPMASK_REV) && + p_node->node_info.revision != + p_rcvd_rec->node_info.revision) + goto Exit; + + if ((comp_mask & IB_NR_COMPMASK_PORTNUM) && + 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) && + 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) && + strncmp((char *)&p_node->node_desc, (char *)&p_rcvd_rec->node_desc, + sizeof(ib_node_desc_t))) + goto Exit; + + nr_rcv_create_nr(sa, p_node, p_ctxt->p_list, match_port_guid, + match_lid, p_req_physp, comp_mask); + +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, 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/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_path_record.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_path_record.c new file mode 100644 index 00000000..a2dda590 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_path_record.c @@ -0,0 +1,1610 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2007 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Copyright (c) 2008 Xsigo Systems Inc. All rights reserved. + * Copyright (c) 2009 HNR Consulting. All rights reserved. + * Copyright (c) 2010 Sun Microsystems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_pr_rcv_t. + * This object represents the PathRecord Receiver object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_HOPS 64 + +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 inline boolean_t sa_path_rec_is_tavor_port(IN const osm_port_t * 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 +sa_path_rec_apply_tavor_mtu_limit(IN const ib_path_rec_t * p_pr, + IN const osm_port_t * p_src_port, + IN const osm_port_t * 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 (!sa_path_rec_is_tavor_port(p_src_port) && + !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; + + 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 pr_rcv_get_path_parms(IN osm_sa_t * sa, + IN const ib_path_rec_t * p_pr, + IN const osm_port_t * p_src_port, + IN const osm_port_t * p_dest_port, + IN const uint16_t dest_lid_ho, + IN const ib_net64_t comp_mask, + OUT osm_path_parms_t * 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; + int hops = 0; + + 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 && + 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; + } + } + + /* update number of hops traversed */ + hops++; + if (hops > MAX_HOPS) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, + "Path from GUID 0x%016" PRIx64 " (%s) to" + " lid %u GUID 0x%016" PRIx64 " (%s) needs" + " more than %d hops, max %d hops allowed\n", + cl_ntoh64(osm_physp_get_port_guid(p_src_physp)), + p_src_physp->p_node->print_desc, dest_lid_ho, + cl_ntoh64(osm_physp_get_port_guid + (p_dest_physp)), + p_dest_physp->p_node->print_desc, hops, + MAX_HOPS); + 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 constraints: 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 pr_rcv_build_pr(IN osm_sa_t * sa, IN const osm_port_t * p_src_port, + IN const osm_port_t * p_dest_port, + IN const ib_gid_t * 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 * p_parms, + OUT ib_path_rec_t * 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; + + if (p_dgid) + 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 (p_dgid) + 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 *pr_rcv_get_lid_pair_path(IN osm_sa_t * sa, + IN const ib_path_rec_t * p_pr, + IN const osm_port_t * p_src_port, + IN const osm_port_t * + p_dest_port, + IN const ib_gid_t * 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 = 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 = 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) && + !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; + } + + 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 pr_rcv_get_port_pair_paths(IN osm_sa_t * sa, + IN const ib_sa_mad_t *sa_mad, + IN const osm_port_t * p_req_port, + IN const osm_port_t * p_src_port, + IN const osm_port_t * p_dest_port, + IN const ib_gid_t * p_dgid, + IN cl_qlist_t * p_list) +{ + const ib_path_rec_t *p_pr = ib_sa_mad_get_payload_ptr(sa_mad); + ib_net64_t comp_mask = sa_mad->comp_mask; + 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; + unsigned iterations, src_offset, 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 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_max_ho = dest_lid_min_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_max_ho = src_lid_min_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 (sa_mad->method == IB_MAD_METHOD_GET) + iterations = 1; + else if (comp_mask & IB_PR_COMPMASK_NUMBPATH) + iterations = ib_path_rec_num_path(p_pr); + else + iterations = (unsigned) (-1); + + while (path_num < iterations) { + /* + These paths are "fully redundant" + */ + + p_pr_item = 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 = 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); +} + +/* Find the router port that is configured to handle this prefix, if any */ +static ib_net64_t find_router(const osm_sa_t *sa, ib_net64_t prefix) +{ + osm_prefix_route_t *route = NULL; + osm_router_t *rtr; + cl_qlist_t *l = &sa->p_subn->prefix_routes_list; + cl_list_item_t *i; + + OSM_LOG(sa->p_log, OSM_LOG_VERBOSE, "Non local DGID subnet prefix " + "0x%016" PRIx64 "\n", cl_ntoh64(prefix)); + + for (i = cl_qlist_head(l); i != cl_qlist_end(l); i = cl_qlist_next(i)) { + osm_prefix_route_t *r = (osm_prefix_route_t *)i; + if (!r->prefix || r->prefix == prefix) { + route = r; + break; + } + } + if (!route) + return 0; + + if (route->guid == 0) /* first router */ + rtr = (osm_router_t *) cl_qmap_head(&sa->p_subn->rtr_guid_tbl); + else + rtr = (osm_router_t *) cl_qmap_get(&sa->p_subn->rtr_guid_tbl, + route->guid); + + if (rtr == (osm_router_t *) cl_qmap_end(&sa->p_subn->rtr_guid_tbl)) + return 0; + + return osm_port_get_guid(osm_router_get_port_ptr(rtr)); +} + +static ib_net16_t pr_rcv_get_end_points(IN osm_sa_t * sa, + IN const ib_sa_mad_t *sa_mad, + OUT const osm_port_t ** pp_src_port, + OUT const osm_port_t ** pp_dest_port, + OUT const ib_gid_t ** pp_dgid) +{ + const ib_path_rec_t *p_pr = ib_sa_mad_get_payload_ptr(sa_mad); + ib_net64_t comp_mask = sa_mad->comp_mask; + ib_net64_t dest_guid; + 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. + */ + + /* + 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 if (comp_mask & IB_PR_COMPMASK_SLID) { + *pp_src_port = osm_get_port_by_lid(sa->p_subn, p_pr->slid); + if (!*pp_src_port) { + /* + 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; + } + } else + *pp_src_port = NULL; + + if (comp_mask & IB_PR_COMPMASK_DGID) { + if (!ib_gid_is_link_local(&p_pr->dgid) && + !ib_gid_is_multicast(&p_pr->dgid) && + ib_gid_get_subnet_prefix(&p_pr->dgid) != + sa->p_subn->opt.subnet_prefix) { + dest_guid = find_router(sa, p_pr->dgid.unicast.prefix); + if (!dest_guid) { + char gid_str[INET6_ADDRSTRLEN]; + OSM_LOG(sa->p_log, OSM_LOG_VERBOSE, + "Off subnet DGID %s, but router not " + "found\n", + inet_ntop(AF_INET6, p_pr->dgid.raw, + gid_str, sizeof(gid_str))); + sa_status = IB_SA_MAD_STATUS_INVALID_GID; + goto Exit; + } + if (pp_dgid) + *pp_dgid = &p_pr->dgid; + } else + dest_guid = p_pr->dgid.unicast.interface_id; + + *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 if (comp_mask & IB_PR_COMPMASK_DLID) { + *pp_dest_port = osm_get_port_by_lid(sa->p_subn, p_pr->dlid); + if (!*pp_dest_port) { + /* + 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; + } + } else + *pp_dest_port = NULL; + +Exit: + OSM_LOG_EXIT(sa->p_log); + return sa_status; +} + +static void pr_rcv_process_world(IN osm_sa_t * sa, IN const ib_sa_mad_t * sa_mad, + IN const osm_port_t * requester_port, + IN const ib_gid_t * p_dgid, + IN cl_qlist_t * 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)) { + pr_rcv_get_port_pair_paths(sa, sa_mad, requester_port, + p_src_port, p_dest_port, + p_dgid, p_list); + if (sa_mad->method == IB_MAD_METHOD_GET && + cl_qlist_count(p_list) > 0) + goto Exit; + + 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); + } + +Exit: + OSM_LOG_EXIT(sa->p_log); +} + +static void pr_rcv_process_half(IN osm_sa_t * sa, IN const ib_sa_mad_t * sa_mad, + IN const osm_port_t * requester_port, + IN const osm_port_t * p_src_port, + IN const osm_port_t * p_dest_port, + IN const ib_gid_t * p_dgid, + IN cl_qlist_t * 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)) { + pr_rcv_get_port_pair_paths(sa, sa_mad, requester_port, + p_src_port, p_port, p_dgid, + p_list); + if (sa_mad->method == IB_MAD_METHOD_GET && + cl_qlist_count(p_list) > 0) + break; + 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)) { + pr_rcv_get_port_pair_paths(sa, sa_mad, requester_port, + p_port, p_dest_port, p_dgid, + p_list); + if (sa_mad->method == IB_MAD_METHOD_GET && + cl_qlist_count(p_list) > 0) + break; + p_port = (osm_port_t *) cl_qmap_next(&p_port->map_item); + } + } + + OSM_LOG_EXIT(sa->p_log); +} + +static void pr_rcv_process_pair(IN osm_sa_t * sa, IN const ib_sa_mad_t * sa_mad, + IN const osm_port_t * requester_port, + IN const osm_port_t * p_src_port, + IN const osm_port_t * p_dest_port, + IN const ib_gid_t * p_dgid, + IN cl_qlist_t * p_list) +{ + OSM_LOG_ENTER(sa->p_log); + + pr_rcv_get_port_pair_paths(sa, sa_mad, requester_port, p_src_port, + p_dest_port, p_dgid, p_list); + + OSM_LOG_EXIT(sa->p_log); +} + +static ib_api_status_t pr_match_mgrp_attributes(IN osm_sa_t * sa, + IN const ib_sa_mad_t * sa_mad, + IN const osm_mgrp_t * p_mgrp) +{ + const ib_path_rec_t *p_pr = ib_sa_mad_get_payload_ptr(sa_mad); + ib_net64_t comp_mask = sa_mad->comp_mask; + const osm_port_t *port; + ib_api_status_t status = IB_ERROR; + uint32_t flow_label; + uint8_t sl, hop_limit; + + OSM_LOG_ENTER(sa->p_log); + + /* check that MLID of the MC group matches the PathRecord DLID */ + if ((comp_mask & IB_PR_COMPMASK_DLID) && p_mgrp->mlid != p_pr->dlid) + goto Exit; + + /* If SGID and/or SLID specified, should validate as member of MC group */ + if (comp_mask & IB_PR_COMPMASK_SGID) { + port = osm_get_port_by_guid(sa->p_subn, + p_pr->sgid.unicast.interface_id); + if (!port || !osm_mgrp_get_mcm_port(p_mgrp, port->guid)) + goto Exit; + } + + if (comp_mask & IB_PR_COMPMASK_SLID) { + port = osm_get_port_by_lid(sa->p_subn, p_pr->slid); + if (!port || !osm_mgrp_get_mcm_port(p_mgrp, port->guid)) + goto Exit; + } + + /* Also, MTU, rate, packet lifetime, and raw traffic requested are not currently checked */ + if ((comp_mask & IB_PR_COMPMASK_PKEY) && + 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) && 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) && + sa_mad->method != IB_MAD_METHOD_GET && + ib_path_rec_num_path(p_pr) == 0) + goto Exit; + + if ((comp_mask & IB_PR_COMPMASK_FLOWLABEL) && + ib_path_rec_flow_lbl(p_pr) != flow_label) + goto Exit; + + if ((comp_mask & IB_PR_COMPMASK_HOPLIMIT) && + ib_path_rec_hop_limit(p_pr) != hop_limit) + goto Exit; + + if ((comp_mask & IB_PR_COMPMASK_TCLASS) && + p_pr->tclass != p_mgrp->mcmember_rec.tclass) + goto Exit; + + status = IB_SUCCESS; + +Exit: + OSM_LOG_EXIT(sa->p_log); + return status; +} + +static void pr_process_multicast(osm_sa_t * sa, const ib_sa_mad_t *sa_mad, + cl_qlist_t *list) +{ + ib_path_rec_t *pr = ib_sa_mad_get_payload_ptr(sa_mad); + osm_mgrp_t *mgrp; + ib_api_status_t status; + osm_pr_item_t *pr_item; + uint32_t flow_label; + uint8_t sl, hop_limit; + + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Multicast destination requested\n"); + + mgrp = osm_get_mgrp_by_mgid(sa->p_subn, &pr->dgid); + if (!mgrp) { + 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, pr->dgid.raw, gid_str, + sizeof gid_str)); + return; + } + + /* Make sure the rest of the PathRecord matches the MC group attributes */ + status = pr_match_mgrp_attributes(sa, sa_mad, mgrp); + if (status != IB_SUCCESS) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F19: " + "MC group attributes don't match PathRecord request\n"); + return; + } + + pr_item = malloc(sizeof(*pr_item)); + if (pr_item == NULL) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F18: " + "Unable to allocate path record for MC group\n"); + return; + } + memset(pr_item, 0, sizeof(*pr_item)); + + /* Copy PathRecord request into response */ + pr_item->path_rec = *pr; + + /* Now, use the MC info to cruft up the PathRecord response */ + pr_item->path_rec.dgid = mgrp->mcmember_rec.mgid; + pr_item->path_rec.dlid = mgrp->mcmember_rec.mlid; + pr_item->path_rec.tclass = mgrp->mcmember_rec.tclass; + pr_item->path_rec.num_path = 1; + pr_item->path_rec.pkey = mgrp->mcmember_rec.pkey; + + /* MTU, rate, and packet lifetime should be exactly */ + pr_item->path_rec.mtu = (2 << 6) | mgrp->mcmember_rec.mtu; + pr_item->path_rec.rate = (2 << 6) | mgrp->mcmember_rec.rate; + pr_item->path_rec.pkt_life = (2 << 6) | mgrp->mcmember_rec.pkt_life; + + /* SL, Hop Limit, and Flow Label */ + ib_member_get_sl_flow_hop(mgrp->mcmember_rec.sl_flow_hop, + &sl, &flow_label, &hop_limit); + ib_path_rec_set_sl(&pr_item->path_rec, sl); + ib_path_rec_set_qos_class(&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(&mgrp->mcmember_rec.mgid) != + IB_MC_SCOPE_LINK_LOCAL) + hop_limit = IB_HOPLIMIT_MAX; + + pr_item->path_rec.hop_flow_raw = + cl_hton32(hop_limit) | (flow_label << 8); + + cl_qlist_insert_tail(list, &pr_item->list_item); +} + +void osm_pr_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_madw_get_sa_mad_ptr(p_madw); + ib_path_rec_t *p_pr = ib_sa_mad_get_payload_ptr(p_sa_mad); + cl_qlist_t pr_list; + const ib_gid_t *p_dgid = NULL; + const osm_port_t *p_src_port, *p_dest_port; + osm_port_t *requester_port; + + OSM_LOG_ENTER(sa->p_log); + + CL_ASSERT(p_madw); + + 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 ((p_sa_mad->comp_mask & IB_PR_COMPMASK_DGID) && + ib_gid_is_multicast(&p_pr->dgid)) { + pr_process_multicast(sa, p_sa_mad, &pr_list); + goto Unlock; + } + + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Unicast destination requested\n"); + + if (pr_rcv_get_end_points(sa, p_sa_mad, &p_src_port, &p_dest_port, + &p_dgid) != IB_SA_MAD_STATUS_SUCCESS) + goto Unlock; + /* + What happens next depends on the type of endpoint information + that was specified.... + */ + if (p_src_port) { + if (p_dest_port) + pr_rcv_process_pair(sa, p_sa_mad, requester_port, + p_src_port, p_dest_port, p_dgid, + &pr_list); + else + pr_rcv_process_half(sa, p_sa_mad, requester_port, + p_src_port, NULL, p_dgid, &pr_list); + } else { + if (p_dest_port) + pr_rcv_process_half(sa, p_sa_mad, requester_port, + NULL, p_dest_port, p_dgid, &pr_list); + else + /* + Katie, bar the door! + */ + pr_rcv_process_world(sa, p_sa_mad, requester_port, + p_dgid, &pr_list); + } + +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/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_pkey_record.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_pkey_record.c new file mode 100644 index 00000000..0bbc7f53 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_pkey_record.c @@ -0,0 +1,309 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct osm_pkey_item { + cl_list_item_t list_item; + ib_pkey_table_record_t rec; +} osm_pkey_item_t; + +typedef struct osm_pkey_search_ctxt { + const ib_pkey_table_record_t *p_rcvd_rec; + ib_net64_t comp_mask; + uint16_t block_num; + cl_qlist_t *p_list; + osm_sa_t *sa; + const osm_physp_t *p_req_physp; +} osm_pkey_search_ctxt_t; + +static void sa_pkey_create(IN osm_sa_t * sa, IN osm_physp_t * p_physp, + IN osm_pkey_search_ctxt_t * 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 sa_pkey_check_physp(IN osm_sa_t * sa, IN osm_physp_t * p_physp, + osm_pkey_search_ctxt_t * 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) { + 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++) + sa_pkey_create(sa, p_physp, p_ctxt, block); + } + + OSM_LOG_EXIT(sa->p_log); +} + +static void sa_pkey_by_comp_mask(IN osm_sa_t * sa, IN const osm_port_t * p_port, + osm_pkey_search_ctxt_t * 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)) + 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; + + sa_pkey_check_physp(sa, p_physp, p_ctxt); + } + } +Exit: + OSM_LOG_EXIT(sa->p_log); +} + +static void sa_pkey_by_comp_mask_cb(IN cl_map_item_t * p_map_item, IN void *cxt) +{ + const osm_port_t *p_port = (osm_port_t *) p_map_item; + osm_pkey_search_ctxt_t *p_ctxt = cxt; + + 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_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_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) { + p_port = osm_get_port_by_lid(sa->p_subn, p_rcvd_rec->lid); + if (!p_port) + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 460B: " + "No port found with LID %u\n", + cl_ntoh16(p_rcvd_rec->lid)); + else + sa_pkey_by_comp_mask(sa, p_port, &context); + } else + cl_qmap_apply_func(&sa->p_subn->port_guid_tbl, + 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/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_portinfo_record.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_portinfo_record.c new file mode 100644 index 00000000..8702d6bd --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_portinfo_record.c @@ -0,0 +1,539 @@ +/* + * Copyright (c) 2004-2009 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 osm_pir_rcv_t. + * This object represents the PortInfoRecord Receiver object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct osm_pir_item { + cl_list_item_t list_item; + ib_portinfo_record_t rec; +} osm_pir_item_t; + +typedef struct osm_pir_search_ctxt { + const ib_portinfo_record_t *p_rcvd_rec; + ib_net64_t comp_mask; + cl_qlist_t *p_list; + osm_sa_t *sa; + const osm_physp_t *p_req_physp; + boolean_t is_enhanced_comp_mask; +} osm_pir_search_ctxt_t; + +static ib_api_status_t pir_rcv_new_pir(IN osm_sa_t * sa, + IN const osm_physp_t * p_physp, + IN cl_qlist_t * 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 sa_pir_create(IN osm_sa_t * sa, IN const osm_physp_t * p_physp, + IN osm_pir_search_ctxt_t * 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; + } + + 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 sa_pir_check_physp(IN osm_sa_t * sa, IN const osm_physp_t * p_physp, + osm_pir_search_ctxt_t * 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; + } + + sa_pir_create(sa, p_physp, p_ctxt); + +Exit: + OSM_LOG_EXIT(sa->p_log); +} + +static void sa_pir_by_comp_mask(IN osm_sa_t * sa, IN osm_node_t * p_node, + osm_pir_search_ctxt_t * 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)) + 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; + + sa_pir_check_physp(sa, p_physp, p_ctxt); + } + } + + OSM_LOG_EXIT(sa->p_log); +} + +static void sa_pir_by_comp_mask_cb(IN cl_map_item_t * p_map_item, IN void *cxt) +{ + osm_node_t *p_node = (osm_node_t *) p_map_item; + osm_pir_search_ctxt_t *p_ctxt = cxt; + + 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 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_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_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); + + /* + 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 | IB_PIR_COMPMASK_BASELID)) { + p_port = osm_get_port_by_lid(sa->p_subn, p_rcvd_rec->lid); + if (p_port) + sa_pir_by_comp_mask(sa, p_port->p_node, &context); + else + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 2109: " + "No port found with LID %u\n", + cl_ntoh16(p_rcvd_rec->lid)); + } else + cl_qmap_apply_func(&sa->p_subn->node_guid_tbl, + 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/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_service_record.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_service_record.c new file mode 100644 index 00000000..e007e020 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_service_record.c @@ -0,0 +1,800 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2006 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_sr_rcv_t. + * This object represents the ServiceRecord Receiver object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct osm_sr_item { + cl_list_item_t list_item; + ib_service_record_t service_rec; +} osm_sr_item_t; + +typedef struct osm_sr_match_item { + cl_qlist_t sr_list; + ib_service_record_t *p_service_rec; + ib_net64_t comp_mask; + osm_sa_t *sa; +} osm_sr_match_item_t; + +typedef struct osm_sr_search_ctxt { + osm_sr_match_item_t *p_sr_item; + const osm_physp_t *p_req_physp; +} osm_sr_search_ctxt_t; + +static boolean_t +match_service_pkey_with_ports_pkey(IN osm_sa_t * sa, + IN const osm_madw_t * p_madw, + ib_service_record_t * 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 * 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 sr_rcv_respond(IN osm_sa_t * sa, IN osm_madw_t * p_madw, + IN cl_qlist_t * 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 * p_list_item, IN void *context) +{ + osm_sr_search_ctxt_t *p_ctxt = 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 sr_rcv_process_get_method(osm_sa_t * sa, IN osm_madw_t * 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; + } + + sr_rcv_respond(sa, p_madw, &sr_match_item.sr_list); + +Exit: + OSM_LOG_EXIT(sa->p_log); + return; +} + +static void sr_rcv_process_set_method(osm_sa_t * sa, IN osm_madw_t * 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); + + sr_rcv_respond(sa, p_madw, &sr_list); + +Exit: + OSM_LOG_EXIT(sa->p_log); +} + +static void sr_rcv_process_delete_method(osm_sa_t * sa, IN osm_madw_t * 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); + + 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; + } + 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; + } + sr_rcv_process_delete_method(sa, p_madw); + break; + case IB_MAD_METHOD_GET: + case IB_MAD_METHOD_GETTABLE: + 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/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_slvl_record.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_slvl_record.c new file mode 100644 index 00000000..5dbbb6a9 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_slvl_record.c @@ -0,0 +1,294 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_slvl_rec_rcv_t. + * This object represents the SLtoVL Mapping Query Receiver object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct osm_slvl_item { + cl_list_item_t list_item; + ib_slvl_table_record_t rec; +} osm_slvl_item_t; + +typedef struct osm_slvl_search_ctxt { + const ib_slvl_table_record_t *p_rcvd_rec; + ib_net64_t comp_mask; + uint8_t in_port_num; + cl_qlist_t *p_list; + osm_sa_t *sa; + const osm_physp_t *p_req_physp; +} osm_slvl_search_ctxt_t; + +static void sa_slvl_create(IN osm_sa_t * sa, IN const osm_physp_t * p_physp, + IN osm_slvl_search_ctxt_t * 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 sa_slvl_by_comp_mask(IN osm_sa_t * sa, IN const osm_port_t * p_port, + osm_slvl_search_ctxt_t * 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)) + 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; + + sa_slvl_create(sa, p_out_physp, p_ctxt, + in_port_num); + } + } + } + OSM_LOG_EXIT(sa->p_log); +} + +static void sa_slvl_by_comp_mask_cb(IN cl_map_item_t * p_map_item, IN void *cxt) +{ + const osm_port_t *p_port = (osm_port_t *) p_map_item; + osm_slvl_search_ctxt_t *p_ctxt = cxt; + + 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) { + p_port = osm_get_port_by_lid(sa->p_subn, p_rcvd_rec->lid); + if (!p_port) { + 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 */ + sa_slvl_by_comp_mask(sa, p_port, &context); + else + cl_qmap_apply_func(&sa->p_subn->port_guid_tbl, + 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/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_sminfo_record.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_sminfo_record.c new file mode 100644 index 00000000..3b772630 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_sminfo_record.c @@ -0,0 +1,314 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_smir_rcv_t. + * This object represents the SMInfo Receiver object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct osm_smir_item { + cl_list_item_t list_item; + ib_sminfo_record_t rec; +} osm_smir_item_t; + +typedef struct osm_smir_search_ctxt { + const ib_sminfo_record_t *p_rcvd_rec; + ib_net64_t comp_mask; + cl_qlist_t *p_list; + osm_sa_t *sa; + const osm_physp_t *p_req_physp; +} osm_smir_search_ctxt_t; + +static ib_api_status_t smir_rcv_new_smir(IN osm_sa_t * sa, + IN const osm_port_t * p_port, + IN cl_qlist_t * 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 * 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 sa_smir_by_comp_mask(IN osm_sa_t * sa, + IN const osm_remote_sm_t * p_rem_sm, + osm_smir_search_ctxt_t * 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 */ + + 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 sa_smir_by_comp_mask_cb(IN cl_map_item_t * p_map_item, IN void *cxt) +{ + const osm_remote_sm_t *p_rem_sm = (osm_remote_sm_t *) p_map_item; + osm_smir_search_ctxt_t *p_ctxt = cxt; + + 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) { + p_port = osm_get_port_by_lid(sa->p_subn, p_rcvd_rec->lid); + if (!p_port) { + 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; + 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)) + 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, + 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/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_sw_info_record.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_sw_info_record.c new file mode 100644 index 00000000..a58c6f59 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_sw_info_record.c @@ -0,0 +1,258 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_sir_rcv_t. + * This object represents the SwitchInfo Receiver object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct osm_sir_item { + cl_list_item_t list_item; + ib_switch_info_record_t rec; +} osm_sir_item_t; + +typedef struct osm_sir_search_ctxt { + const ib_switch_info_record_t *p_rcvd_rec; + ib_net64_t comp_mask; + cl_qlist_t *p_list; + osm_sa_t *sa; + const osm_physp_t *p_req_physp; +} osm_sir_search_ctxt_t; + +static ib_api_status_t sir_rcv_new_sir(IN osm_sa_t * sa, + IN const osm_switch_t * p_sw, + IN cl_qlist_t * p_list, + IN ib_net16_t 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 sir_rcv_create_sir(IN osm_sa_t * sa, IN const osm_switch_t * p_sw, + IN cl_qlist_t * p_list, IN ib_net16_t match_lid, + IN const osm_physp_t * 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; + + } + + 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 sir_rcv_by_comp_mask(IN cl_map_item_t * p_map_item, IN void *cxt) +{ + const osm_sir_search_ctxt_t *p_ctxt = cxt; + const osm_switch_t *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; + } + + 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, 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/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_vlarb_record.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_vlarb_record.c new file mode 100644 index 00000000..92a34d4a --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_sa_vlarb_record.c @@ -0,0 +1,306 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_vlarb_rec_rcv_t. + * This object represents the VLArbitrationRecord Receiver object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct osm_vl_arb_item { + cl_list_item_t list_item; + ib_vl_arb_table_record_t rec; +} osm_vl_arb_item_t; + +typedef struct osm_vl_arb_search_ctxt { + const ib_vl_arb_table_record_t *p_rcvd_rec; + ib_net64_t comp_mask; + uint8_t block_num; + cl_qlist_t *p_list; + osm_sa_t *sa; + const osm_physp_t *p_req_physp; +} osm_vl_arb_search_ctxt_t; + +static void sa_vl_arb_create(IN osm_sa_t * sa, IN osm_physp_t * p_physp, + IN osm_vl_arb_search_ctxt_t * 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 sa_vl_arb_check_physp(IN osm_sa_t * sa, IN osm_physp_t * p_physp, + osm_vl_arb_search_ctxt_t * 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) + sa_vl_arb_create(sa, p_physp, p_ctxt, block); + } + + OSM_LOG_EXIT(sa->p_log); +} + +static void sa_vl_arb_by_comp_mask(osm_sa_t * sa, IN const osm_port_t * p_port, + osm_vl_arb_search_ctxt_t * 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)) + 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; + + sa_vl_arb_check_physp(sa, p_physp, p_ctxt); + } + } +Exit: + OSM_LOG_EXIT(sa->p_log); +} + +static void sa_vl_arb_by_comp_mask_cb(IN cl_map_item_t * p_map_item, void *cxt) +{ + const osm_port_t *p_port = (osm_port_t *) p_map_item; + osm_vl_arb_search_ctxt_t *p_ctxt = cxt; + + 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) { + p_port = osm_get_port_by_lid(sa->p_subn, p_rcvd_rec->lid); + if (!p_port) { + 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 */ + sa_vl_arb_by_comp_mask(sa, p_port, &context); + else + cl_qmap_apply_func(&sa->p_subn->port_guid_tbl, + 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/branches/WOF2-3/ulp/opensm/user/opensm/osm_service.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_service.c new file mode 100644 index 00000000..bf7c7522 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_service.c @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2004-2009 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 record functions. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include + +void osm_svcr_delete(IN osm_svcr_t * p_svcr) +{ + free(p_svcr); +} + +void osm_svcr_init(IN osm_svcr_t * 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 * 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; + + if (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))) + return CL_NOT_FOUND; + else + return CL_SUCCESS; +} + +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 * 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); + p_subn->p_osm->sa.dirty = TRUE; + + 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); + p_subn->p_osm->sa.dirty = TRUE; + + OSM_LOG_EXIT(p_log); +} diff --git a/branches/WOF2-3/ulp/opensm/user/opensm/osm_slvl_map_rcv.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_slvl_map_rcv.c new file mode 100644 index 00000000..351bf5bd --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_slvl_map_rcv.c @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2004-2009 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) 2009 HNR Consulting. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_slvl_rcv_t. + * This object represents the SLtoVL Receiver object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * WE ONLY RECEIVE 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; + uint32_t attr_mod; + uint8_t startinport, endinport, startoutport, endoutport; + uint8_t in_port, out_port; + + 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_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) { + 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) { + unsigned num_ports = osm_node_get_num_physp(p_node) - 1; + attr_mod = cl_ntoh32(p_smp->attr_mod); + + if (attr_mod & 0x10000) { + startoutport = ib_switch_info_is_enhanced_port0(&p_node->sw->switch_info) ? 0 : 1; + endoutport = osm_node_get_num_physp(p_node) - 1; + } else + startoutport = endoutport = attr_mod & 0xff; + + if (attr_mod & 0x20000) { + startinport = ib_switch_info_is_enhanced_port0(&p_node->sw->switch_info) ? 0 : 1; + endinport = osm_node_get_num_physp(p_node) - 1; + } else + startinport = endinport = (attr_mod >> 8) & 0xff; + + if (startinport > num_ports || startoutport > num_ports) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2C07" + "Invalid attribute modifier 0x%x received in" + " response from switch 0x%" PRIx64 "\n", + cl_ntoh32(attr_mod), cl_ntoh64(node_guid)); + goto Exit; + } + + } else { + startoutport = endoutport = p_port->p_physp->port_num; + startinport = endinport = 0; + } + + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, "Received SLtoVL GetResp" + " in_port_num %u out_port_num %u with GUID 0x%" PRIx64 + " for parent node GUID 0x%" PRIx64 ", TID 0x%" PRIx64 "\n", + startinport == endinport ? startinport : 0xff, + startoutport == endoutport ? startoutport : 0xff, + cl_ntoh64(port_guid), cl_ntoh64(node_guid), + cl_ntoh64(p_smp->trans_id)); + + osm_dump_slvl_map_table(sm->p_log, port_guid, + startinport == endinport ? startinport : 0xff, + startoutport == endoutport ? startoutport : 0xff, + p_slvl_tbl, OSM_LOG_DEBUG); + + for (out_port = startoutport; out_port <= endoutport; out_port++) { + p_physp = osm_node_get_physp_ptr(p_node, out_port); + for (in_port = startinport; in_port <= endinport; in_port++) + osm_physp_set_slvl_tbl(p_physp, p_slvl_tbl, in_port); + } + +Exit: + cl_plock_release(sm->p_lock); + + OSM_LOG_EXIT(sm->p_log); +} diff --git a/branches/WOF2-3/ulp/opensm/user/opensm/osm_sm.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_sm.c new file mode 100644 index 00000000..9687f0e6 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_sm.c @@ -0,0 +1,447 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Copyright (c) 2008 Xsigo Systems Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_sm_t. + * This object represents the SM Receiver object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 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 sm_sweeper(IN void *p_ptr) +{ + ib_api_status_t status; + osm_sm_t * p_sm = 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) + 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 * 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); + 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 * 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 * 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->state_lock); + free(p_sm->mlids_req); + + 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 * p_sm, IN osm_subn_t * p_subn, + IN osm_db_t * p_db, IN osm_vendor_t * p_vendor, + IN osm_mad_pool_t * p_mad_pool, + IN osm_vl15_t * p_vl15, IN osm_log_t * p_log, + IN osm_stats_t * p_stats, + IN cl_dispatcher_t * p_disp, IN cl_plock_t * p_lock) +{ + ib_api_status_t status; + + 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; + + p_sm->mlids_req_max = 0; + p_sm->mlids_req = malloc((IB_LID_MCAST_END_HO - IB_LID_MCAST_START_HO + + 1) * sizeof(p_sm->mlids_req[0])); + if (!p_sm->mlids_req) + goto Exit; + memset(p_sm->mlids_req, 0, + (IB_LID_MCAST_END_HO - IB_LID_MCAST_START_HO + + 1) * sizeof(p_sm->mlids_req[0])); + + 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; + + status = IB_INSUFFICIENT_RESOURCES; + 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, 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 * 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 * p_sm, IN 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; +} + +void osm_sm_reroute_mlid(osm_sm_t * sm, ib_net16_t mlid) +{ + mlid = cl_ntoh16(mlid) - IB_LID_MCAST_START_HO; + sm->mlids_req[mlid] = 1; + if (sm->mlids_req_max < mlid) + sm->mlids_req_max = mlid; + osm_sm_signal(sm, OSM_SIGNAL_IDLE_TIME_PROCESS_REQUEST); + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, "rerouting requested for MLID 0x%x\n", + mlid + IB_LID_MCAST_START_HO); +} + +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/branches/WOF2-3/ulp/opensm/user/opensm/osm_sm_mad_ctrl.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_sm_mad_ctrl.c new file mode 100644 index 00000000..a74f11ed --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_sm_mad_ctrl.c @@ -0,0 +1,905 @@ +/* + * Copyright (c) 2004-2009 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) 2009 HNR Consulting. All rights reserved. + * Copyright (c) 2009 Sun Microsystems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_sm_mad_ctrl_t. + * This object represents the SM MAD request controller object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/****f* opensm: SM/sm_mad_ctrl_retire_trans_mad + * NAME + * 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 sm_mad_ctrl_retire_trans_mad(IN osm_sm_mad_ctrl_t * p_ctrl, + IN osm_madw_t * 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/sm_mad_ctrl_disp_done_callback + * NAME + * 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 sm_mad_ctrl_disp_done_callback(IN void *context, IN void *p_data) +{ + osm_sm_mad_ctrl_t *p_ctrl = context; + osm_madw_t *p_madw = 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); + sm_mad_ctrl_retire_trans_mad(p_ctrl, p_madw); + } else if (p_madw->resp_expected == TRUE) + 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/sm_mad_ctrl_update_wire_stats + * NAME + * sm_mad_ctrl_update_wire_stats + * + * DESCRIPTION + * Updates wire stats for outstanding MADs and calls the VL15 poller. + * + * SYNOPSIS + */ +static void sm_mad_ctrl_update_wire_stats(IN osm_sm_mad_ctrl_t * 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/sm_mad_ctrl_process_get_resp + * NAME + * 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 sm_mad_ctrl_process_get_resp(IN osm_sm_mad_ctrl_t * 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 = transaction_context; + + 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); + 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, + 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 (%s)\n", + CL_STATUS_MSG(status), cl_ntoh16(p_smp->attr_id), + ib_get_sm_attr_str(p_smp->attr_id)); + goto Exit; + } + +Exit: + OSM_LOG_EXIT(p_ctrl->p_log); +} + +/****f* opensm: SM/sm_mad_ctrl_process_get + * NAME + * sm_mad_ctrl_process_get + * + * DESCRIPTION + * This function handles method Get() for received MADs. + * + * SYNOPSIS + */ +static void sm_mad_ctrl_process_get(IN osm_sm_mad_ctrl_t * 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)); + 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, + 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/sm_mad_ctrl_process_set + * NAME + * sm_mad_ctrl_process_set + * + * DESCRIPTION + * This function handles method Set() for received MADs. + * + * SYNOPSIS + */ +static void sm_mad_ctrl_process_set(IN osm_sm_mad_ctrl_t * 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); + 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, + 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/sm_mad_ctrl_process_trap + * NAME + * sm_mad_ctrl_process_trap + * + * DESCRIPTION + * This function handles method Trap() for received MADs. + * + * SYNOPSIS + */ +static void sm_mad_ctrl_process_trap(IN osm_sm_mad_ctrl_t * 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); + 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, + 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/sm_mad_ctrl_process_trap_repress + * NAME + * sm_mad_ctrl_process_trap_repress + * + * DESCRIPTION + * This function handles method TrapRepress() for received MADs. + * + * SYNOPSIS + */ +static void sm_mad_ctrl_process_trap_repress(IN osm_sm_mad_ctrl_t * p_ctrl, + IN osm_madw_t * p_madw) +{ + ib_smp_t *p_smp; + + 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_NOTICE: + sm_mad_ctrl_retire_trans_mad(p_ctrl, p_madw); + break; + default: + cl_atomic_inc(&p_ctrl->p_stats->qp0_mads_rcvd_unknown); + OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3105: " + "Unsupported attribute 0x%X\n", + cl_ntoh16(p_smp->attr_id)); + osm_dump_dr_smp(p_ctrl->p_log, p_smp, OSM_LOG_ERROR); + osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw); + break; + } + + OSM_LOG_EXIT(p_ctrl->p_log); +} + +static void log_rcv_cb_error(osm_log_t *p_log, ib_smp_t *p_smp, ib_net16_t status) +{ + char buf[BUF_SIZE]; + uint32_t i; + + if (p_smp->mgmt_class == IB_MCLASS_SUBN_DIR) { + char ipath[BUF_SIZE], rpath[BUF_SIZE]; + int ni = sprintf(ipath, "%d", p_smp->initial_path[0]); + int nr = sprintf(rpath, "%d", p_smp->return_path[0]); + for (i = 1; i <= p_smp->hop_count; i++) { + ni += sprintf(ipath + ni, ",%d", p_smp->initial_path[i]); + nr += sprintf(rpath + nr, ",%d", p_smp->return_path[i]); + } + snprintf(buf, sizeof(buf), + "\n\t\t\tInitial path: %s Return path: %s", + ipath, rpath); + } + + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 3111: " + "Received MAD with error status = 0x%X\n" + "\t\t\t%s(%s), attr_mod 0x%x, TID 0x%" PRIx64 "%s\n", + cl_ntoh16(status), ib_get_sm_method_str(p_smp->method), + ib_get_sm_attr_str(p_smp->attr_id), cl_ntoh32(p_smp->attr_mod), + cl_ntoh64(p_smp->trans_id), + p_smp->mgmt_class == IB_MCLASS_SUBN_DIR ? buf : ""); + + osm_dump_dr_smp(p_log, p_smp, OSM_LOG_VERBOSE); +} + +/* + * PARAMETERS + * + * RETURN VALUES + * + * NOTES + * + * SEE ALSO + *********/ + +/****f* opensm: SM/sm_mad_ctrl_rcv_callback + * NAME + * sm_mad_ctrl_rcv_callback + * + * DESCRIPTION + * This is the callback from the transport layer for received MADs. + * + * SYNOPSIS + */ +static void 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 = 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)) { + CL_ASSERT(p_madw->resp_expected == FALSE); + sm_mad_ctrl_retire_trans_mad(p_ctrl, p_madw); + } else if (p_madw->resp_expected == TRUE) + 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) + log_rcv_cb_error(p_ctrl->p_log, p_smp, status); + + switch (p_smp->method) { + case IB_MAD_METHOD_GET_RESP: + CL_ASSERT(p_req_madw != NULL); + 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); + sm_mad_ctrl_process_get(p_ctrl, p_madw); + break; + case IB_MAD_METHOD_TRAP: + CL_ASSERT(p_req_madw == NULL); + sm_mad_ctrl_process_trap(p_ctrl, p_madw); + break; + case IB_MAD_METHOD_SET: + CL_ASSERT(p_req_madw == NULL); + sm_mad_ctrl_process_set(p_ctrl, p_madw); + break; + case IB_MAD_METHOD_TRAP_REPRESS: + CL_ASSERT(p_req_madw != NULL); + sm_mad_ctrl_process_trap_repress(p_ctrl, p_madw); + break; + case IB_MAD_METHOD_SEND: + case IB_MAD_METHOD_REPORT: + case IB_MAD_METHOD_REPORT_RESP: + 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/sm_mad_ctrl_send_err_cb + * NAME + * 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 sm_mad_ctrl_send_err_cb(IN void *context, IN osm_madw_t * p_madw) +{ + osm_sm_mad_ctrl_t *p_ctrl = context; + ib_api_status_t status; + ib_smp_t *p_smp; + + OSM_LOG_ENTER(p_ctrl->p_log); + + CL_ASSERT(p_madw); + + p_smp = osm_madw_get_smp_ptr(p_madw); + OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3113: " + "MAD completed in error (%s): " + "%s(%s), attr_mod 0x%x, TID 0x%" PRIx64 "\n", + ib_get_err_str(p_madw->status), + ib_get_sm_method_str(p_smp->method), + ib_get_sm_attr_str(p_smp->attr_id), cl_ntoh32(p_smp->attr_mod), + cl_ntoh64(p_smp->trans_id)); + + /* + 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. + */ + 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 || + p_smp->attr_id == IB_MAD_ATTR_P_KEY_TABLE)) { + OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3119: " + "Set method failed for attribute 0x%X (%s)\n", + cl_ntoh16(p_smp->attr_id), + ib_get_sm_attr_str(p_smp->attr_id)); + p_ctrl->p_subn->subnet_initialization_error = TRUE; + } + + osm_dump_dr_smp(p_ctrl->p_log, p_smp, OSM_LOG_VERBOSE); + + /* + 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. + */ + 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, + 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. + */ + 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 * 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 * 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 * p_ctrl, + IN osm_subn_t * p_subn, + IN osm_mad_pool_t * p_mad_pool, + IN osm_vl15_t * p_vl15, + IN osm_vendor_t * p_vendor, + IN osm_log_t * p_log, + IN osm_stats_t * p_stats, + IN cl_plock_t * p_lock, + IN cl_dispatcher_t * 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 * p_ctrl, + IN 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; + bind_info.timeout = p_ctrl->p_subn->opt.transaction_timeout; + bind_info.retries = p_ctrl->p_subn->opt.transaction_retries; + + 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, + sm_mad_ctrl_rcv_callback, + 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/branches/WOF2-3/ulp/opensm/user/opensm/osm_sm_state_mgr.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_sm_state_mgr.c new file mode 100644 index 00000000..a8acd3d2 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_sm_state_mgr.c @@ -0,0 +1,540 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_sm_state_mgr_t. + * This file implements the SM State Manager object. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void osm_report_sm_state(osm_sm_t * sm) +{ + char buf[64]; + const char *state_str = osm_get_sm_mgr_state_str(sm->p_subn->sm_state); + + osm_log(sm->p_log, OSM_LOG_SYS, "Entering %s state\n", state_str); + snprintf(buf, sizeof(buf), "ENTERING SM %s STATE", state_str); + OSM_LOG_MSG_BOX(sm->p_log, OSM_LOG_VERBOSE, buf); +} + +static void 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 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 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 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. + */ + 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) */ + 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); +} + +static void sm_state_mgr_signal_error(osm_sm_t * sm, IN 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; + + 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: + 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: + 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); + sm_state_mgr_start_polling(sm); + break; + default: + 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); + 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 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. + */ + 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: + 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: + 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: + 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: + 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: + 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/branches/WOF2-3/ulp/opensm/user/opensm/osm_sminfo_rcv.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_sminfo_rcv.c new file mode 100755 index 00000000..48d801f3 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_sminfo_rcv.c @@ -0,0 +1,590 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_sminfo_rcv_t. + * This object represents the SMInfo Receiver object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/********************************************************************** + Return TRUE if the remote sm given (by ib_sm_info_t) is higher, + return FALSE otherwise. + By higher - we mean: SM with higher priority or with same priority + and lower GUID. +**********************************************************************/ +static boolean_t smi_rcv_remote_sm_is_higher(IN osm_sm_t * sm, + IN const ib_sm_info_t * p_rem_smi) +{ + return osm_sm_is_greater_than(ib_sminfo_get_priority(p_rem_smi), + p_rem_smi->guid, + sm->p_subn->opt.sm_priority, + sm->p_subn->sm_port_guid); + +} + +static void smi_rcv_process_get_request(IN osm_sm_t * sm, + IN const osm_madw_t * 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 smi_rcv_check_set_req_legality(IN const ib_smp_t * 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 smi_rcv_process_set_request(IN osm_sm_t * sm, + IN const osm_madw_t * 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 = smi_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 int smi_rcv_process_get_sm(IN osm_sm_t * sm, + IN const osm_remote_sm_t * 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 (smi_rcv_remote_sm_is_higher(sm, p_smi)) { + /* 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); + + if (!smi_rcv_remote_sm_is_higher(sm, p_smi)) + osm_send_trap144(sm, + TRAP_144_MASK_SM_PRIORITY_CHANGE); + 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 (smi_rcv_remote_sm_is_higher(sm, p_smi)) + 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 && + smi_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 smi_rcv_process_get_response(IN osm_sm_t * sm, + IN const osm_madw_t * 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; + + smi_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 smi_rcv_process_set_response(IN osm_sm_t * sm, + IN const osm_madw_t * 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 */ + smi_rcv_process_get_response(sm, p_madw); + else + /* this is a response to a Set method */ + smi_rcv_process_set_response(sm, p_madw); + } else if (p_smp->method == IB_MAD_METHOD_GET) + /* This is a SubnGet request */ + smi_rcv_process_get_request(sm, p_madw); + else + /* This should be a SubnSet request */ + smi_rcv_process_set_request(sm, p_madw); + +Exit: + OSM_LOG_EXIT(sm->p_log); +} diff --git a/branches/WOF2-3/ulp/opensm/user/opensm/osm_state_mgr.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_state_mgr.c new file mode 100644 index 00000000..afa2c6a6 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_state_mgr.c @@ -0,0 +1,1438 @@ +/* + * Copyright (c) 2009 Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2009 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Copyright (c) 2009 HNR Consulting. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_state_mgr_t. + * This file implements the State Manager object. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern void osm_drop_mgr_process(IN osm_sm_t * sm); +extern int osm_qos_setup(IN osm_opensm_t * p_osm); +extern int osm_pkey_mgr_process(IN osm_opensm_t * p_osm); +extern int osm_mcast_mgr_process(IN osm_sm_t * sm); +extern int osm_mcast_mgr_process_mgroups(IN osm_sm_t * sm); +extern int osm_link_mgr_process(IN osm_sm_t * sm, IN uint8_t state); + +static void 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 state_mgr_reset_node_count(IN cl_map_item_t * p_map_item, + IN void *context) +{ + osm_node_t *p_node = (osm_node_t *) p_map_item; + + p_node->discovery_count = 0; +} + +static void state_mgr_reset_port_count(IN cl_map_item_t * p_map_item, + IN void *context) +{ + osm_port_t *p_port = (osm_port_t *) p_map_item; + + p_port->discovery_count = 0; +} + +static void state_mgr_reset_switch_count(IN cl_map_item_t * p_map_item, + IN void *context) +{ + osm_switch_t *p_sw = (osm_switch_t *) p_map_item; + + p_sw->need_update = 1; +} + +static void state_mgr_get_sw_info(IN cl_map_item_t * 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 (%s)\n", + ib_get_err_str(status)); + + OSM_LOG_EXIT(sm->p_log); +} + +/********************************************************************** + Initiate a remote port info request for the given physical port + **********************************************************************/ +static void state_mgr_get_remote_port_info(IN osm_sm_t * sm, + IN osm_physp_t * 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)); + if (osm_dr_path_extend(&rem_node_dr_path, osm_physp_get_port_num(p_physp))) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 332D: " + "DR path with hop count %d couldn't be extended " + "so skipping PortInfo query\n", + p_dr_path->hop_count); + goto Exit; + } + + 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 (%s)\n", + ib_get_err_str(status)); + +Exit: + 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 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, + state_mgr_reset_node_count, sm); + + cl_qmap_apply_func(&sm->p_subn->port_guid_tbl, + state_mgr_reset_port_count, sm); + + cl_qmap_apply_func(&sm->p_subn->sw_guid_tbl, + 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 (%s)\n", + ib_get_err_str(status)); + } 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 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 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 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 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 (%s)\n", + ib_get_err_str(status)); + 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 = 1; 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 (%s)\n", + ib_get_err_str(status)); + } + } + 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; +#ifndef __WIN__ + osm_remote_sm_t *r_sm = cl_item_obj(item, r_sm, map_item); +#else + osm_remote_sm_t *r_sm=NULL; +#endif + osm_sm_t *sm = cxt; + ib_api_status_t ret; + +#ifdef __WIN__ + r_sm = cl_item_obj(item, r_sm, map_item); +#endif + 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)); +} + +static void state_mgr_update_node_desc(IN cl_map_item_t * obj, IN void *context) +{ + osm_madw_context_t mad_context; + osm_node_t *p_node = (osm_node_t *) obj; + 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); + + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Updating NodeDesc for 0x%016" PRIx64 "\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); +} + +void osm_update_node_desc(IN osm_opensm_t *osm) +{ + CL_PLOCK_ACQUIRE(&osm->lock); + cl_qmap_apply_func(&osm->subn.node_guid_tbl, state_mgr_update_node_desc, + &osm->sm); + CL_PLOCK_RELEASE(&osm->lock); +} + +/********************************************************************** + During a light sweep, check each node to see if the node description + is valid and if not issue a ND query. +**********************************************************************/ +static void state_mgr_get_node_desc(IN cl_map_item_t * obj, IN void *context) +{ + osm_node_t *p_node = (osm_node_t *) obj; + osm_sm_t *sm = context; + + 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))); + + state_mgr_update_node_desc(obj, context); + +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 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, 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, 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); + + 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 *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 *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 state_mgr_send_handover(IN osm_sm_t * sm, IN osm_remote_sm_t * 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 state_mgr_report_new_ports(IN osm_sm_t * sm) +{ + ib_gid_t port_gid; + ib_mad_notice_attr_t notice; + ib_api_status_t status; + ib_net64_t port_guid; + cl_map_item_t *p_next; + osm_port_t *p_port; + uint16_t min_lid_ho; + uint16_t max_lid_ho; + + OSM_LOG_ENTER(sm->p_log); + + CL_PLOCK_ACQUIRE(sm->p_lock); + p_next = cl_qmap_head(&sm->p_subn->port_guid_tbl); + while (p_next != cl_qmap_end(&sm->p_subn->port_guid_tbl)) { + p_port = (osm_port_t *) p_next; + p_next = cl_qmap_next(p_next); + + if (!p_port->is_new) + continue; + + port_guid = osm_port_get_guid(p_port); + /* issue a notice - trap 64 */ + + /* details of the notice */ + notice.generic_type = 0x83; /* is generic subn mgt type */ + ib_notice_set_prod_type_ho(¬ice, 4); /* A Class Manager generator */ + /* endport becomes reachable */ + notice.g_or_v.generic.trap_num = CL_HTON16(64); + /* The sm_base_lid is saved in network order already. */ + notice.issuer_lid = sm->p_subn->sm_base_lid; + /* following C14-72.1.1 and table 119 p739 */ + /* we need to provide the GID */ + port_gid.unicast.prefix = sm->p_subn->opt.subnet_prefix; + port_gid.unicast.interface_id = port_guid; + memcpy(&(notice.data_details.ntc_64_67.gid), &(port_gid), + sizeof(ib_gid_t)); + + /* According to page 653 - the issuer gid in this case of trap + * is the SM gid, since the SM is the initiator of this trap. */ + notice.issuer_gid.unicast.prefix = + sm->p_subn->opt.subnet_prefix; + notice.issuer_gid.unicast.interface_id = + sm->p_subn->sm_port_guid; + + status = osm_report_notice(sm->p_log, sm->p_subn, ¬ice); + if (status != IB_SUCCESS) + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3318: " + "Error sending trap reports on GUID:0x%016" + PRIx64 " (%s)\n", port_gid.unicast.interface_id, + ib_get_err_str(status)); + osm_port_get_lid_range_ho(p_port, &min_lid_ho, &max_lid_ho); + OSM_LOG(sm->p_log, OSM_LOG_INFO, + "Discovered new port with GUID:0x%016" PRIx64 + " LID range [%u,%u] of node: %s\n", + cl_ntoh64(port_gid.unicast.interface_id), + min_lid_ho, max_lid_ho, + p_port->p_node ? p_port->p_node-> + print_desc : "UNKNOWN"); + + p_port->is_new = 0; + } + CL_PLOCK_RELEASE(sm->p_lock); + + OSM_LOG_EXIT(sm->p_log); +} + +/********************************************************************** + * Make sure that the lid_port_tbl of the subnet has only the ports + * that are recognized, and in the correct lid place. There could be + * errors if we wanted to assign a certain port with lid X, but that + * request didn't reach the port. In this case port_lid_tbl will have + * the port under lid X, though the port isn't updated with this lid. + * We will run a new heavy sweep (since there were errors in the + * initialization), but here we'll clean the database from incorrect + * information. + **********************************************************************/ +static void 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 %u 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 %u," + " 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 %u 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, sw->max_lid_ho + 1)) + osm_log(log, OSM_LOG_ERROR, "ERR 331D: " + "LFT of switch 0x%016" PRIx64 " (%s) is not up to date\n", + cl_ntoh64(sw->p_node->node_info.node_guid), + sw->p_node->print_desc); + 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; + unsigned config_parsed = 0; + + if (sm->p_subn->force_heavy_sweep) { + 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"); + else + config_parsed = 1; + } + + 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 + */ + 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 + && (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) { + if (sm->p_subn->opt.sa_db_dump) + osm_sa_db_file_dump(sm->p_subn->p_osm); + 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 || sm->p_subn->coming_out_of_standby)) + 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 (!config_parsed && 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 = state_mgr_sweep_hop_0(sm); + if (status != IB_SUCCESS || + wait_for_pending_transactions(&sm->p_subn->p_osm->stats)) + return; + + if (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 = 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 presence */ + 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 = state_mgr_get_highest_sm(sm); + if (p_remote_sm != NULL) { + /* report new ports (trap 64) before leaving MASTER */ + state_mgr_report_new_ports(sm); + + /* need to handover the mastership + * to the remote sm, and move to standby */ + 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 = 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_LOG_MSG_BOX(sm->p_log, OSM_LOG_VERBOSE, + "PKEY and QOS setup completed - STARTING SM LID CONFIG"); + + 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"); + 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. */ + 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 + */ + 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); + state_mgr_up_msg(sm); + sm->p_subn->first_time_master_sweep = FALSE; + + if (osm_log_is_active(sm->p_log, OSM_LOG_VERBOSE) || + sm->p_subn->opt.sa_db_dump) + 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; + if (!sm->p_subn->opt.disable_multicast) { + 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/branches/WOF2-3/ulp/opensm/user/opensm/osm_subnet.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_subnet.c new file mode 100644 index 00000000..6461a1b4 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_subnet.c @@ -0,0 +1,1663 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2009 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Copyright (c) 2008 Xsigo Systems Inc. All rights reserved. + * Copyright (c) 2009 System Fabric Works, Inc. All rights reserved. + * Copyright (c) 2009 HNR Consulting. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_subn_t. + * This object represents an IBA subnet. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const char null_str[] = "(null)"; + +#define OPT_OFFSET(opt) offsetof(osm_subn_opt_t, opt) + +typedef struct opt_rec { + const char *name; + unsigned long opt_offset; + void (*parse_fn)(osm_subn_t *p_subn, char *p_key, char *p_val_str, + void *p_val1, void *p_val2, + void (*)(osm_subn_t *, void *)); + void (*setup_fn)(osm_subn_t *p_subn, void *p_val); + int can_update; +} opt_rec_t; + +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("%s", 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) - 2) + n = sizeof(buf) - 2; + snprintf(buf + n, sizeof(buf) - n, "\n"); + va_end(args); + printf("%s", buf); + cl_log_event("OpenSM", CL_LOG_INFO, buf, NULL, 0); +} + +static void opts_setup_log_flags(osm_subn_t *p_subn, void *p_val) +{ + p_subn->p_osm->log.level = *((uint8_t *) p_val); +} + +static void opts_setup_force_log_flush(osm_subn_t *p_subn, void *p_val) +{ + p_subn->p_osm->log.flush = *((boolean_t *) p_val); +} + +static void opts_setup_accum_log_file(osm_subn_t *p_subn, void *p_val) +{ + p_subn->p_osm->log.accum_log_file = *((boolean_t *) p_val); +} + +static void opts_setup_log_max_size(osm_subn_t *p_subn, void *p_val) +{ + uint32_t log_max_size = *((uint32_t *) p_val); + + p_subn->p_osm->log.max_size = log_max_size << 20; /* convert from MB to bytes */ +} + +static void opts_setup_sminfo_polling_timeout(osm_subn_t *p_subn, void *p_val) +{ + osm_sm_t *p_sm = &p_subn->p_osm->sm; + uint32_t sminfo_polling_timeout = *((uint32_t *) p_val); + + cl_timer_stop(&p_sm->polling_timer); + cl_timer_start(&p_sm->polling_timer, sminfo_polling_timeout); +} + +static void opts_setup_sm_priority(osm_subn_t *p_subn, void *p_val) +{ + osm_sm_t *p_sm = &p_subn->p_osm->sm; + uint8_t sm_priority = *((uint8_t *) p_val); + + osm_set_sm_priority(p_sm, sm_priority); +} + +static void opts_parse_net64(IN osm_subn_t *p_subn, IN char *p_key, + IN char *p_val_str, void *p_v1, void *p_v2, + void (*pfn)(osm_subn_t *, void *)) +{ + uint64_t *p_val1 = p_v1, *p_val2 = p_v2; + uint64_t val = strtoull(p_val_str, NULL, 0); + + if (cl_hton64(val) != *p_val1) { + log_config_value(p_key, "0x%016" PRIx64, val); + if (pfn) + pfn(p_subn, &val); + *p_val1 = *p_val2 = cl_ntoh64(val); + } +} + +static void opts_parse_uint32(IN osm_subn_t *p_subn, IN char *p_key, + IN char *p_val_str, void *p_v1, void *p_v2, + void (*pfn)(osm_subn_t *, void *)) +{ + uint32_t *p_val1 = p_v1, *p_val2 = p_v2; + uint32_t val = strtoul(p_val_str, NULL, 0); + + if (val != *p_val1) { + log_config_value(p_key, "%u", val); + if (pfn) + pfn(p_subn, &val); + *p_val1 = *p_val2 = val; + } +} + +static void opts_parse_int32(IN osm_subn_t *p_subn, IN char *p_key, + IN char *p_val_str, void *p_v1, void *p_v2, + void (*pfn)(osm_subn_t *, void *)) +{ + int32_t *p_val1 = p_v1, *p_val2 = p_v2; + int32_t val = strtol(p_val_str, NULL, 0); + + if (val != *p_val1) { + log_config_value(p_key, "%d", val); + if (pfn) + pfn(p_subn, &val); + *p_val1 = *p_val2 = val; + } +} + +static void opts_parse_uint16(IN osm_subn_t *p_subn, IN char *p_key, + IN char *p_val_str, void *p_v1, void *p_v2, + void (*pfn)(osm_subn_t *, void *)) +{ + uint16_t *p_val1 = p_v1, *p_val2 = p_v2; + uint16_t val = (uint16_t) strtoul(p_val_str, NULL, 0); + + if (val != *p_val1) { + log_config_value(p_key, "%u", val); + if (pfn) + pfn(p_subn, &val); + *p_val1 = *p_val2 = val; + } +} + +static void opts_parse_net16(IN osm_subn_t *p_subn, IN char *p_key, + IN char *p_val_str, void *p_v1, void *p_v2, + void (*pfn)(osm_subn_t *, void *)) +{ + uint16_t *p_val1 = p_v1, *p_val2 = p_v2; + uint16_t val = strtoul(p_val_str, NULL, 0); + + if (cl_hton16(val) != *p_val1) { + log_config_value(p_key, "0x%04x", val); + if (pfn) + pfn(p_subn, &val); + *p_val1 = *p_val2 = cl_hton16(val); + } +} + +static void opts_parse_uint8(IN osm_subn_t *p_subn, IN char *p_key, + IN char *p_val_str, void *p_v1, void *p_v2, + void (*pfn)(osm_subn_t *, void *)) +{ + uint8_t *p_val1 = p_v1, *p_val2 = p_v2; + uint8_t val = strtoul(p_val_str, NULL, 0); + + if (val != *p_val1) { + log_config_value(p_key, "%u", val); + if (pfn) + pfn(p_subn, &val); + *p_val1 = *p_val2 = val; + } +} + +static void opts_parse_boolean(IN osm_subn_t *p_subn, IN char *p_key, + IN char *p_val_str, void *p_v1, void *p_v2, + void (*pfn)(osm_subn_t *, void *)) +{ + boolean_t *p_val1 = p_v1, *p_val2 = p_v2; + boolean_t val; + + if (!p_val_str) + return; + + if (strcmp("TRUE", p_val_str)) + val = FALSE; + else + val = TRUE; + + if (val != *p_val1) { + log_config_value(p_key, "%s", p_val_str); + if (pfn) + pfn(p_subn, &val); + *p_val1 = *p_val2 = val; + } +} + +static void opts_parse_charp(IN osm_subn_t *p_subn, IN char *p_key, + IN char *p_val_str, void *p_v1, void *p_v2, + void (*pfn)(osm_subn_t *, void *)) +{ + char **p_val1 = p_v1, **p_val2 = p_v2; + const char *current_str = *p_val1 ? *p_val1 : null_str ; + + if (p_val_str && strcmp(p_val_str, current_str)) { + char *new; + log_config_value(p_key, "%s", p_val_str); + /* special case the "(null)" string */ + new = strcmp(null_str, p_val_str) ? strdup(p_val_str) : NULL; + if (pfn) + pfn(p_subn, new); + if (*p_val1 && *p_val1 != *p_val2) + free(*p_val1); + if (*p_val2) + free(*p_val2); + *p_val1 = *p_val2 = new; + } +} + +static const opt_rec_t opt_tbl[] = { + { "guid", OPT_OFFSET(guid), opts_parse_net64, NULL, 0 }, + { "m_key", OPT_OFFSET(m_key), opts_parse_net64, NULL, 1 }, + { "sm_key", OPT_OFFSET(sm_key), opts_parse_net64, NULL, 1 }, + { "sa_key", OPT_OFFSET(sa_key), opts_parse_net64, NULL, 1 }, + { "subnet_prefix", OPT_OFFSET(subnet_prefix), opts_parse_net64, NULL, 1 }, + { "m_key_lease_period", OPT_OFFSET(m_key_lease_period), opts_parse_net16, NULL, 1 }, + { "sweep_interval", OPT_OFFSET(sweep_interval), opts_parse_uint32, NULL, 1 }, + { "max_wire_smps", OPT_OFFSET(max_wire_smps), opts_parse_uint32, NULL, 1 }, + { "console", OPT_OFFSET(console), opts_parse_charp, NULL, 0 }, + { "console_port", OPT_OFFSET(console_port), opts_parse_uint16, NULL, 0 }, + { "transaction_timeout", OPT_OFFSET(transaction_timeout), opts_parse_uint32, NULL, 0 }, + { "transaction_retries", OPT_OFFSET(transaction_retries), opts_parse_uint32, NULL, 0 }, + { "max_msg_fifo_timeout", OPT_OFFSET(max_msg_fifo_timeout), opts_parse_uint32, NULL, 1 }, + { "sm_priority", OPT_OFFSET(sm_priority), opts_parse_uint8, opts_setup_sm_priority, 1 }, + { "lmc", OPT_OFFSET(lmc), opts_parse_uint8, NULL, 1 }, + { "lmc_esp0", OPT_OFFSET(lmc_esp0), opts_parse_boolean, NULL, 1 }, + { "max_op_vls", OPT_OFFSET(max_op_vls), opts_parse_uint8, NULL, 1 }, + { "force_link_speed", OPT_OFFSET(force_link_speed), opts_parse_uint8, NULL, 1 }, + { "reassign_lids", OPT_OFFSET(reassign_lids), opts_parse_boolean, NULL, 1 }, + { "ignore_other_sm", OPT_OFFSET(ignore_other_sm), opts_parse_boolean, NULL, 1 }, + { "single_thread", OPT_OFFSET(single_thread), opts_parse_boolean, NULL, 0 }, + { "disable_multicast", OPT_OFFSET(disable_multicast), opts_parse_boolean, NULL, 1 }, + { "subnet_timeout", OPT_OFFSET(subnet_timeout), opts_parse_uint8, NULL, 1 }, + { "packet_life_time", OPT_OFFSET(packet_life_time), opts_parse_uint8, NULL, 1 }, + { "vl_stall_count", OPT_OFFSET(vl_stall_count), opts_parse_uint8, NULL, 1 }, + { "leaf_vl_stall_count", OPT_OFFSET(leaf_vl_stall_count), opts_parse_uint8, NULL, 1 }, + { "head_of_queue_lifetime", OPT_OFFSET(head_of_queue_lifetime), opts_parse_uint8, NULL, 1 }, + { "leaf_head_of_queue_lifetime", OPT_OFFSET(leaf_head_of_queue_lifetime), opts_parse_uint8, NULL, 1 }, + { "local_phy_errors_threshold", OPT_OFFSET(local_phy_errors_threshold), opts_parse_uint8, NULL, 1 }, + { "overrun_errors_threshold", OPT_OFFSET(overrun_errors_threshold), opts_parse_uint8, NULL, 1 }, + { "sminfo_polling_timeout", OPT_OFFSET(sminfo_polling_timeout), opts_parse_uint32, opts_setup_sminfo_polling_timeout, 1 }, + { "polling_retry_number", OPT_OFFSET(polling_retry_number), opts_parse_uint32, NULL, 1 }, + { "force_heavy_sweep", OPT_OFFSET(force_heavy_sweep), opts_parse_boolean, NULL, 1 }, + { "port_prof_ignore_file", OPT_OFFSET(port_prof_ignore_file), opts_parse_charp, NULL, 0 }, + { "hop_weights_file", OPT_OFFSET(hop_weights_file), opts_parse_charp, NULL, 0 }, + { "dimn_ports_file", OPT_OFFSET(dimn_ports_file), opts_parse_charp, NULL, 0 }, + { "port_profile_switch_nodes", OPT_OFFSET(port_profile_switch_nodes), opts_parse_boolean, NULL, 1 }, + { "sweep_on_trap", OPT_OFFSET(sweep_on_trap), opts_parse_boolean, NULL, 1 }, + { "routing_engine", OPT_OFFSET(routing_engine_names), opts_parse_charp, NULL, 0 }, + { "connect_roots", OPT_OFFSET(connect_roots), opts_parse_boolean, NULL, 1 }, + { "use_ucast_cache", OPT_OFFSET(use_ucast_cache), opts_parse_boolean, NULL, 0 }, + { "log_file", OPT_OFFSET(log_file), opts_parse_charp, NULL, 0 }, + { "log_max_size", OPT_OFFSET(log_max_size), opts_parse_uint32, opts_setup_log_max_size, 1 }, + { "log_flags", OPT_OFFSET(log_flags), opts_parse_uint8, opts_setup_log_flags, 1 }, + { "force_log_flush", OPT_OFFSET(force_log_flush), opts_parse_boolean, opts_setup_force_log_flush, 1 }, + { "accum_log_file", OPT_OFFSET(accum_log_file), opts_parse_boolean, opts_setup_accum_log_file, 1 }, + { "partition_config_file", OPT_OFFSET(partition_config_file), opts_parse_charp, NULL, 0 }, + { "no_partition_enforcement", OPT_OFFSET(no_partition_enforcement), opts_parse_boolean, NULL, 1 }, + { "qos", OPT_OFFSET(qos), opts_parse_boolean, NULL, 1 }, + { "qos_policy_file", OPT_OFFSET(qos_policy_file), opts_parse_charp, NULL, 0 }, + { "dump_files_dir", OPT_OFFSET(dump_files_dir), opts_parse_charp, NULL, 0 }, + { "lid_matrix_dump_file", OPT_OFFSET(lid_matrix_dump_file), opts_parse_charp, NULL, 0 }, + { "lfts_file", OPT_OFFSET(lfts_file), opts_parse_charp, NULL, 0 }, + { "root_guid_file", OPT_OFFSET(root_guid_file), opts_parse_charp, NULL, 0 }, + { "cn_guid_file", OPT_OFFSET(cn_guid_file), opts_parse_charp, NULL, 0 }, + { "io_guid_file", OPT_OFFSET(io_guid_file), opts_parse_charp, NULL, 0 }, + { "max_reverse_hops", OPT_OFFSET(max_reverse_hops), opts_parse_uint16, NULL, 0 }, + { "ids_guid_file", OPT_OFFSET(ids_guid_file), opts_parse_charp, NULL, 0 }, + { "guid_routing_order_file", OPT_OFFSET(guid_routing_order_file), opts_parse_charp, NULL, 0 }, + { "sa_db_file", OPT_OFFSET(sa_db_file), opts_parse_charp, NULL, 0 }, + { "sa_db_dump", OPT_OFFSET(sa_db_dump), opts_parse_boolean, NULL, 1 }, + { "do_mesh_analysis", OPT_OFFSET(do_mesh_analysis), opts_parse_boolean, NULL, 1 }, + { "exit_on_fatal", OPT_OFFSET(exit_on_fatal), opts_parse_boolean, NULL, 1 }, + { "honor_guid2lid_file", OPT_OFFSET(honor_guid2lid_file), opts_parse_boolean, NULL, 1 }, + { "daemon", OPT_OFFSET(daemon), opts_parse_boolean, NULL, 0 }, + { "sm_inactive", OPT_OFFSET(sm_inactive), opts_parse_boolean, NULL, 1 }, + { "babbling_port_policy", OPT_OFFSET(babbling_port_policy), opts_parse_boolean, NULL, 1 }, + { "use_optimized_slvl", OPT_OFFSET(use_optimized_slvl), opts_parse_boolean, NULL, 1 }, +#ifdef ENABLE_OSM_PERF_MGR + { "perfmgr", OPT_OFFSET(perfmgr), opts_parse_boolean, NULL, 0 }, + { "perfmgr_redir", OPT_OFFSET(perfmgr_redir), opts_parse_boolean, NULL, 0 }, + { "perfmgr_sweep_time_s", OPT_OFFSET(perfmgr_sweep_time_s), opts_parse_uint16, NULL, 0 }, + { "perfmgr_max_outstanding_queries", OPT_OFFSET(perfmgr_max_outstanding_queries), opts_parse_uint32, NULL, 0 }, + { "event_db_dump_file", OPT_OFFSET(event_db_dump_file), opts_parse_charp, NULL, 0 }, +#endif /* ENABLE_OSM_PERF_MGR */ + { "event_plugin_name", OPT_OFFSET(event_plugin_name), opts_parse_charp, NULL, 0 }, + { "event_plugin_options", OPT_OFFSET(event_plugin_options), opts_parse_charp, NULL, 0 }, + { "node_name_map_name", OPT_OFFSET(node_name_map_name), opts_parse_charp, NULL, 0 }, + { "qos_max_vls", OPT_OFFSET(qos_options.max_vls), opts_parse_uint32, NULL, 1 }, + { "qos_high_limit", OPT_OFFSET(qos_options.high_limit), opts_parse_int32, NULL, 1 }, + { "qos_vlarb_high", OPT_OFFSET(qos_options.vlarb_high), opts_parse_charp, NULL, 1 }, + { "qos_vlarb_low", OPT_OFFSET(qos_options.vlarb_low), opts_parse_charp, NULL, 1 }, + { "qos_sl2vl", OPT_OFFSET(qos_options.sl2vl), opts_parse_charp, NULL, 1 }, + { "qos_ca_max_vls", OPT_OFFSET(qos_ca_options.max_vls), opts_parse_uint32, NULL, 1 }, + { "qos_ca_high_limit", OPT_OFFSET(qos_ca_options.high_limit), opts_parse_int32, NULL, 1 }, + { "qos_ca_vlarb_high", OPT_OFFSET(qos_ca_options.vlarb_high), opts_parse_charp, NULL, 1 }, + { "qos_ca_vlarb_low", OPT_OFFSET(qos_ca_options.vlarb_low), opts_parse_charp, NULL, 1 }, + { "qos_ca_sl2vl", OPT_OFFSET(qos_ca_options.sl2vl), opts_parse_charp, NULL, 1 }, + { "qos_sw0_max_vls", OPT_OFFSET(qos_sw0_options.max_vls), opts_parse_uint32, NULL, 1 }, + { "qos_sw0_high_limit", OPT_OFFSET(qos_sw0_options.high_limit), opts_parse_int32, NULL, 1 }, + { "qos_sw0_vlarb_high", OPT_OFFSET(qos_sw0_options.vlarb_high), opts_parse_charp, NULL, 1 }, + { "qos_sw0_vlarb_low", OPT_OFFSET(qos_sw0_options.vlarb_low), opts_parse_charp, NULL, 1 }, + { "qos_sw0_sl2vl", OPT_OFFSET(qos_sw0_options.sl2vl), opts_parse_charp, NULL, 1 }, + { "qos_swe_max_vls", OPT_OFFSET(qos_swe_options.max_vls), opts_parse_uint32, NULL, 1 }, + { "qos_swe_high_limit", OPT_OFFSET(qos_swe_options.high_limit), opts_parse_int32, NULL, 1 }, + { "qos_swe_vlarb_high", OPT_OFFSET(qos_swe_options.vlarb_high), opts_parse_charp, NULL, 1 }, + { "qos_swe_vlarb_low", OPT_OFFSET(qos_swe_options.vlarb_low), opts_parse_charp, NULL, 1 }, + { "qos_swe_sl2vl", OPT_OFFSET(qos_swe_options.sl2vl), opts_parse_charp, NULL, 1 }, + { "qos_rtr_max_vls", OPT_OFFSET(qos_rtr_options.max_vls), opts_parse_uint32, NULL, 1 }, + { "qos_rtr_high_limit", OPT_OFFSET(qos_rtr_options.high_limit), opts_parse_int32, NULL, 1 }, + { "qos_rtr_vlarb_high", OPT_OFFSET(qos_rtr_options.vlarb_high), opts_parse_charp, NULL, 1 }, + { "qos_rtr_vlarb_low", OPT_OFFSET(qos_rtr_options.vlarb_low), opts_parse_charp, NULL, 1 }, + { "qos_rtr_sl2vl", OPT_OFFSET(qos_rtr_options.sl2vl), opts_parse_charp, NULL, 1 }, + { "enable_quirks", OPT_OFFSET(enable_quirks), opts_parse_boolean, NULL, 1 }, + { "no_clients_rereg", OPT_OFFSET(no_clients_rereg), opts_parse_boolean, NULL, 1 }, + { "prefix_routes_file", OPT_OFFSET(prefix_routes_file), opts_parse_charp, NULL, 0 }, + { "consolidate_ipv6_snm_req", OPT_OFFSET(consolidate_ipv6_snm_req), opts_parse_boolean, NULL, 1 }, + { "lash_start_vl", OPT_OFFSET(lash_start_vl), opts_parse_uint8, NULL, 1 }, + { "sm_sl", OPT_OFFSET(sm_sl), opts_parse_uint8, NULL, 1 }, + { "log_prefix", OPT_OFFSET(log_prefix), opts_parse_charp, NULL, 1 }, + {0} +}; + +static int compar_mgids(const void *m1, const void *m2) +{ + return memcmp(m1, m2, sizeof(ib_gid_t)); +} + +void osm_subn_construct(IN osm_subn_t * 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); + cl_fmap_init(&p_subn->mgrp_mgid_tbl, compar_mgids); +} + +void osm_subn_destroy(IN osm_subn_t * 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_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); + } + + cl_fmap_remove_all(&p_subn->mgrp_mgid_tbl); + + for (i = 0; i <= p_subn->max_mcast_lid_ho - IB_LID_MCAST_START_HO; + i++) + if (p_subn->mboxes[i]) + osm_mgrp_box_delete(p_subn->mboxes[i]); + + 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 * p_subn, IN osm_opensm_t * p_osm, + IN const osm_subn_opt_t * 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; +} + +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) +{ + osm_port_t *port = osm_get_port_by_lid(p_subn, p_mad_addr->dest_lid); + if (!port) + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 7504: " + "Lid is out of range: %u\n", + cl_ntoh16(p_mad_addr->dest_lid)); + + return port; +} + +ib_api_status_t osm_get_gid_by_mad_addr(IN osm_log_t * p_log, + IN const osm_subn_t * p_subn, + IN osm_mad_addr_t * p_mad_addr, + OUT ib_gid_t * p_gid) +{ + const osm_port_t *p_port; + + if (p_gid == NULL) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 7505: " + "Provided output GID is NULL\n"); + return IB_INVALID_PARAMETER; + } + + p_port = osm_get_port_by_mad_addr(p_log, p_subn, p_mad_addr); + if (!p_port) + return IB_INVALID_PARAMETER; + + p_gid->unicast.interface_id = p_port->p_physp->port_guid; + p_gid->unicast.prefix = p_subn->opt.subnet_prefix; + + 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) +{ + osm_port_t *p_port; + + p_port = osm_get_port_by_mad_addr(p_log, p_subn, p_mad_addr); + if (!p_port) + return NULL; + + return p_port->p_physp; +} + +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; +} + +osm_port_t *osm_get_port_by_lid_ho(IN osm_subn_t const * subn, IN uint16_t lid) +{ + if (lid < cl_ptr_vector_get_size(&subn->port_lid_tbl)) + return cl_ptr_vector_get(&subn->port_lid_tbl, lid); + return NULL; +} + +osm_mgrp_t *osm_get_mgrp_by_mgid(IN osm_subn_t * subn, IN ib_gid_t * mgid) +{ + osm_mgrp_t *mgrp; + + mgrp= (osm_mgrp_t *)cl_fmap_get(&subn->mgrp_mgid_tbl, mgid); + if (mgrp != (osm_mgrp_t *)cl_fmap_end(&subn->mgrp_mgid_tbl)) + return mgrp; + return NULL; +} + +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(osm_qos_options_t *opt, osm_qos_options_t *f) +{ + opt->max_vls = 0; + opt->high_limit = -1; + if (opt->vlarb_high) + free(opt->vlarb_high); + opt->vlarb_high = NULL; + if (opt->vlarb_low) + free(opt->vlarb_low); + opt->vlarb_low = NULL; + if (opt->sl2vl) + free(opt->sl2vl); + opt->sl2vl = NULL; + if (f) + memcpy(f, opt, sizeof(*f)); +} + +void osm_subn_set_default_opt(IN osm_subn_opt_t * 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 = strdup(OSM_DEFAULT_CONSOLE); + p_opt->console_port = OSM_DEFAULT_CONSOLE_PORT; + p_opt->transaction_timeout = OSM_DEFAULT_TRANS_TIMEOUT_MILLISEC; + p_opt->transaction_retries = OSM_DEFAULT_RETRY_COUNT; + /* 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; + p_opt->use_optimized_slvl = 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->event_plugin_options = 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->dump_files_dir = strdup(p_opt->dump_files_dir); + p_opt->log_file = strdup(OSM_DEFAULT_LOG_FILE); + p_opt->log_max_size = 0; + p_opt->partition_config_file = strdup(OSM_DEFAULT_PARTITION_CONFIG_FILE); + p_opt->no_partition_enforcement = FALSE; + p_opt->qos = FALSE; + p_opt->qos_policy_file = strdup(OSM_DEFAULT_QOS_POLICY_FILE); + p_opt->accum_log_file = TRUE; + p_opt->port_prof_ignore_file = NULL; + p_opt->hop_weights_file = NULL; + p_opt->dimn_ports_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->io_guid_file = NULL; + p_opt->max_reverse_hops = 0; + p_opt->ids_guid_file = NULL; + p_opt->guid_routing_order_file = NULL; + p_opt->sa_db_file = NULL; + p_opt->sa_db_dump = FALSE; + p_opt->do_mesh_analysis = FALSE; + p_opt->exit_on_fatal = TRUE; + p_opt->enable_quirks = FALSE; + p_opt->no_clients_rereg = FALSE; + p_opt->prefix_routes_file = strdup(OSM_DEFAULT_PREFIX_ROUTES_FILE); + p_opt->consolidate_ipv6_snm_req = FALSE; + p_opt->lash_start_vl = 0; + p_opt->sm_sl = OSM_DEFAULT_SL; + p_opt->log_prefix = NULL; + subn_init_qos_options(&p_opt->qos_options, NULL); + subn_init_qos_options(&p_opt->qos_ca_options, NULL); + subn_init_qos_options(&p_opt->qos_sw0_options, NULL); + subn_init_qos_options(&p_opt->qos_swe_options, NULL); + subn_init_qos_options(&p_opt->qos_rtr_options, NULL); +} + +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-- = '\0'; + } + return val; +} + +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 * 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 parse_prefix_routes_file(IN osm_subn_t * 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) { + if (*max_vls) + 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) { + if (*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) { + *vlarb = strdup(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) { + *sl2vl = strdup(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 * 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 (p_opts->max_wire_smps == 0) + p_opts->max_wire_smps = 0x7FFFFFFF; + else if (p_opts->max_wire_smps > 0x7FFFFFFF) { + log_report(" Invalid Cached Option Value: max_wire_smps = %u," + " Using Default: %u\n", + p_opts->max_wire_smps, OSM_DEFAULT_SMP_MAX_ON_WIRE); + p_opts->max_wire_smps = OSM_DEFAULT_SMP_MAX_ON_WIRE; + } + + 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 * p_opts) +{ + char line[1024]; + FILE *opts_file; + char *p_key, *p_val; + const opt_rec_t *r; + void *p_field1, *p_field2; + + 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; + if (!p_opts->file_opts && !(p_opts->file_opts = malloc(sizeof(*p_opts)))) + return -1; + memcpy(p_opts->file_opts, p_opts, sizeof(*p_opts)); + + 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); + + for (r = opt_tbl; r->name; r++) { + if (strcmp(r->name, p_key)) + continue; + + p_field1 = (uint8_t *)p_opts->file_opts + r->opt_offset; + p_field2 = (uint8_t *)p_opts + r->opt_offset; + /* don't call setup function first time */ + r->parse_fn(NULL, p_key, p_val, p_field1, p_field2, + NULL); + break; + } + } + fclose(opts_file); + + osm_subn_verify_config(p_opts); + + return 0; +} + +int osm_subn_rescan_conf_files(IN osm_subn_t * p_subn) +{ + char line[1024]; + osm_subn_opt_t *p_opts = &p_subn->opt; + const opt_rec_t *r; + FILE *opts_file; + char *p_key, *p_val; + void *p_field1, *p_field2; + + if (!p_opts->config_file) + return 0; + + opts_file = fopen(p_opts->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_opts->config_file, strerror(errno)); + return -1; + } + + subn_init_qos_options(&p_opts->qos_options, + &p_opts->file_opts->qos_options); + subn_init_qos_options(&p_opts->qos_ca_options, + &p_opts->file_opts->qos_ca_options); + subn_init_qos_options(&p_opts->qos_sw0_options, + &p_opts->file_opts->qos_sw0_options); + subn_init_qos_options(&p_opts->qos_swe_options, + &p_opts->file_opts->qos_swe_options); + subn_init_qos_options(&p_opts->qos_rtr_options, + &p_opts->file_opts->qos_rtr_options); + + 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); + + for (r = opt_tbl; r->name; r++) { + if (!r->can_update || strcmp(r->name, p_key)) + continue; + + p_field1 = (uint8_t *)p_opts->file_opts + r->opt_offset; + p_field2 = (uint8_t *)p_opts + r->opt_offset; + r->parse_fn(p_subn, p_key, p_val, p_field1, p_field2, + r->setup_fn); + break; + } + } + fclose(opts_file); + + osm_subn_verify_config(p_opts); + + parse_prefix_routes_file(p_subn); + + return 0; +} + +int osm_subn_output_conf(FILE *out, IN osm_subn_opt_t * 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" + "# sm_sl determines SMSL used for SM/SA communication\n" + "sm_sl %u\n\n" + "# The code of maximal time a packet can live in a switch\n" + "# The actual time is 4.096usec * 2^\n" + "# The value 0x14 disables this mechanism\n" + "packet_life_time 0x%02x\n\n" + "# The number of sequential packets dropped that cause the port\n" + "# to enter the VLStalled state. The result of setting this value to\n" + "# zero is undefined.\n" + "vl_stall_count 0x%02x\n\n" + "# The number of sequential packets dropped that cause the port\n" + "# to enter the VLStalled state. This value is for switch ports\n" + "# driving a CA or router port. The result of setting this value\n" + "# to zero is undefined.\n" + "leaf_vl_stall_count 0x%02x\n\n" + "# The code of maximal time a packet can wait at the head of\n" + "# transmission queue.\n" + "# The actual time is 4.096usec * 2^\n" + "# The value 0x14 disables this mechanism\n" + "head_of_queue_lifetime 0x%02x\n\n" + "# The maximal time a packet can wait at the head of queue on\n" + "# switch port connected to a CA or router port\n" + "leaf_head_of_queue_lifetime 0x%02x\n\n" + "# Limit the maximal operational VLs\n" + "max_op_vls %u\n\n" + "# Force PortInfo:LinkSpeedEnabled on switch ports\n" + "# If 0, don't modify PortInfo:LinkSpeedEnabled on switch port\n" + "# Otherwise, use value for PortInfo:LinkSpeedEnabled on switch port\n" + "# Values are (IB Spec 1.2.1, 14.2.5.6 Table 146 \"PortInfo\")\n" + "# 1: 2.5 Gbps\n" + "# 3: 2.5 or 5.0 Gbps\n" + "# 5: 2.5 or 10.0 Gbps\n" + "# 7: 2.5 or 5.0 or 10.0 Gbps\n" + "# 2,4,6,8-14 Reserved\n" + "# Default 15: set to PortInfo:LinkSpeedSupported\n" + "force_link_speed %u\n\n" + "# The subnet_timeout code that will be set for all the ports\n" + "# The actual timeout is 4.096usec * 2^\n" + "subnet_timeout %u\n\n" + "# Threshold of local phy errors for sending Trap 129\n" + "local_phy_errors_threshold 0x%02x\n\n" + "# Threshold of credit overrun errors for sending Trap 130\n" + "overrun_errors_threshold 0x%02x\n\n", + cl_ntoh64(p_opts->guid), + cl_ntoh64(p_opts->m_key), + cl_ntoh16(p_opts->m_key_lease_period), + cl_ntoh64(p_opts->sm_key), + cl_ntoh64(p_opts->sa_key), + cl_ntoh64(p_opts->subnet_prefix), + p_opts->lmc, + p_opts->lmc_esp0 ? "TRUE" : "FALSE", + p_opts->sm_sl, + 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, + "# The file holding routing weighting factors per output port\n" + "hop_weights_file %s\n\n", + p_opts->hop_weights_file ? p_opts->hop_weights_file : null_str); + + fprintf(out, + "# The file holding non-default port order per switch for DOR routing \n" + "dimn_ports_file %s\n\n", + p_opts->dimn_ports_file ? p_opts->dimn_ports_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 fat-tree I/O node guids\n" + "# One guid in each line\nio_guid_file %s\n\n", + p_opts->io_guid_file ? p_opts->io_guid_file : null_str); + + fprintf(out, + "# Number of reverse hops allowed for I/O nodes \n" + "# Used for connectivity between I/O nodes connected to Top Switches\nmax_reverse_hops %d\n\n", + p_opts->max_reverse_hops); + + 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, + "# Do mesh topology analysis (for LASH algorithm)\n" + "do_mesh_analysis %s\n\n", + p_opts->do_mesh_analysis ? "TRUE" : "FALSE"); + + fprintf(out, + "# Starting VL for LASH algorithm\n" + "lash_start_vl %u\n\n", + p_opts->lash_start_vl); + + 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, + "# If TRUE causes OpenSM to dump SA database at the end of\n" + "# every light sweep, regardless of the verbosity level\n" + "sa_db_dump %s\n\n", + p_opts->sa_db_dump ? "TRUE" : "FALSE"); + + 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" + "# The maximum number of retries allowed for a transaction to complete\n" + "transaction_retries %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->transaction_retries, + 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" + "# Use Optimized SLtoVLMapping programming if supported by device\n" + "use_optimized_slvl %s\n\n", + p_opts->daemon ? "TRUE" : "FALSE", + p_opts->sm_inactive ? "TRUE" : "FALSE", + p_opts->babbling_port_policy ? "TRUE" : "FALSE", + p_opts->use_optimized_slvl ? "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" + "event_plugin_name %s\n\n" + "# Options string that would be passed to the plugin(s)\n" + "event_plugin_options %s\n\n", + p_opts->event_plugin_name ? + p_opts->event_plugin_name : null_str, + p_opts->event_plugin_options ? + p_opts->event_plugin_options : 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, + 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"); + + fprintf(out, "# Log prefix\nlog_prefix %s\n\n", p_opts->log_prefix); + + /* optional string attributes ... */ + + return 0; +} + +int osm_subn_write_conf_file(char *file_name, IN osm_subn_opt_t * 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/branches/WOF2-3/ulp/opensm/user/opensm/osm_sw_info_rcv.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_sw_info_rcv.c new file mode 100644 index 00000000..f79aca73 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_sw_info_rcv.c @@ -0,0 +1,382 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005,2008 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Copyright (c) 2009 HNR Consulting. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_si_rcv_t. + * This object represents the SwitchInfo Receiver object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if 0 +/********************************************************************** + The plock must be held before calling this function. +**********************************************************************/ +static void si_rcv_get_fwd_tbl(IN osm_sm_t * sm, IN osm_switch_t * 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 si_rcv_get_mcast_fwd_tbl(IN osm_sm_t * sm, IN osm_switch_t * 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 si_rcv_process_new(IN osm_sm_t * sm, IN osm_node_t * p_node, + IN const osm_madw_t * 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_smp_get_payload_ptr(p_smp); + + osm_dump_switch_info(sm->p_log, p_si, OSM_LOG_DEBUG); + + 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 (cl_ntoh16(p_si->mcast_cap) + IB_LID_MCAST_START_HO - 1 < + sm->p_subn->max_mcast_lid_ho) { + sm->p_subn->max_mcast_lid_ho = cl_ntoh16(p_si->mcast_cap) + + IB_LID_MCAST_START_HO - 1; + 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); + +#if 0 + /* 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. */ + + si_rcv_get_fwd_tbl(sm, p_sw); + if (!sm->p_subn->opt.disable_multicast) + 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 si_rcv_process_existing(IN osm_sm_t * sm, + IN osm_node_t * p_node, + IN const osm_madw_t * 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_smp_get_payload_ptr(p_smp); + p_si_context = osm_madw_get_si_context_ptr(p_madw); + + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, "Received logical %cetResp()\n", + p_si_context->set_method ? 'S' : 'G'); + + osm_switch_set_switch_info(p_sw, p_si); + + if (p_si_context->light_sweep == TRUE && !p_si_context->set_method) { + /* If state changed bit is on 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 (ib_switch_info_get_state_change(p_si)) { + osm_dump_switch_info(sm->p_log, p_si, OSM_LOG_DEBUG); + is_change_detected = TRUE; + } + } + + 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_smp_get_payload_ptr(p_smp); + 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) { + CL_PLOCK_RELEASE(sm->p_lock); + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3606: " + "SwitchInfo received for nonexistent node " + "with GUID 0x%" PRIx64 "\n", cl_ntoh64(node_guid)); + goto Exit; + } + + /* 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) { + 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 if (si_rcv_process_existing(sm, p_node, p_madw)) + /* we might get back a request for signaling change was detected */ + sm->p_subn->force_heavy_sweep = TRUE; + + CL_PLOCK_RELEASE(sm->p_lock); +Exit: + OSM_LOG_EXIT(sm->p_log); +} diff --git a/branches/WOF2-3/ulp/opensm/user/opensm/osm_switch.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_switch.c new file mode 100644 index 00000000..9581c4c9 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_switch.c @@ -0,0 +1,638 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2009 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Copyright (c) 2009 HNR Consulting. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_switch_t. + * This object represents an Infiniband switch. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include + +cl_status_t osm_switch_set_hops(IN osm_switch_t * p_sw, IN uint16_t lid_ho, + IN uint8_t port_num, IN 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; +} + +void osm_switch_delete(IN OUT osm_switch_t ** pp_sw) +{ + osm_switch_t *p_sw = *pp_sw; + unsigned i; + + osm_mcast_tbl_destroy(&p_sw->mcast_tbl); + if (p_sw->p_prof) + free(p_sw->p_prof); + if (p_sw->dimn_ports) + free(p_sw->dimn_ports); + 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 * p_node, + IN const osm_madw_t * p_madw) +{ + osm_switch_t *p_sw; + ib_switch_info_t *p_si; + ib_smp_t *p_smp; + uint8_t num_ports; + uint32_t port_num; + + CL_ASSERT(p_madw); + CL_ASSERT(p_node); + + p_smp = osm_madw_get_smp_ptr(p_madw); + p_si = 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); + + if (!p_si->lin_cap) /* The switch doesn't support LFT */ + return NULL; + + p_sw = malloc(sizeof(*p_sw)); + if (!p_sw) + return NULL; + + memset(p_sw, 0, sizeof(*p_sw)); + + p_sw->p_node = p_node; + p_sw->switch_info = *p_si; + p_sw->num_ports = num_ports; + p_sw->need_update = 2; + + p_sw->p_prof = malloc(sizeof(*p_sw->p_prof) * num_ports); + if (!p_sw->p_prof) + goto err; + + memset(p_sw->p_prof, 0, sizeof(*p_sw->p_prof) * num_ports); + + osm_mcast_tbl_init(&p_sw->mcast_tbl, osm_node_get_num_physp(p_node), + cl_ntoh16(p_si->mcast_cap)); + + for (port_num = 0; port_num < num_ports; port_num++) + osm_port_prof_construct(&p_sw->p_prof[port_num]); + + return p_sw; + +err: + osm_switch_delete(&p_sw); + return NULL; +} + +boolean_t osm_switch_get_lft_block(IN const osm_switch_t * p_sw, + IN uint16_t block_id, OUT uint8_t * 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 * +switch_find_guid_common(IN const osm_switch_t * 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; + unsigned 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 * +switch_find_sys_guid_count(IN const osm_switch_t * p_sw, + IN struct osm_remote_guids_count *r, + IN uint8_t port_num) +{ + return switch_find_guid_common(p_sw, r, port_num, 1, 0); +} + +static struct osm_remote_node * +switch_find_node_guid_count(IN const osm_switch_t * p_sw, + IN struct osm_remote_guids_count *r, + IN uint8_t port_num) +{ + return switch_find_guid_common(p_sw, r, port_num, 0, 1); +} + +uint8_t osm_switch_recommend_path(IN const osm_switch_t * p_sw, + IN osm_port_t * p_port, IN uint16_t lid_ho, + IN unsigned start_from, + IN boolean_t ignore_existing, + IN 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; + struct osm_remote_node null_remote_node = {NULL, 0, 0}; + + 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 = osm_switch_get_dimn_port(p_sw, 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]); + + 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 (!p_rem_node_first) + p_rem_node_first = p_rem_node; + else if (p_rem_node != p_rem_node_first) + continue; + if (routing_for_lmc) { + struct osm_remote_guids_count *r = p_port->priv; + uint8_t rem_port = osm_physp_get_port_num(p_rem_physp); + unsigned int j; + + for (j = 0; j < r->count; j++) { + p_remote_guid = &r->guids[j]; + if ((p_remote_guid->node == p_rem_node) + && (p_remote_guid->port == rem_port)) + break; + } + if (j == r->count) + p_remote_guid = &null_remote_node; + } + /* + Advanced LMC routing requires tracking of the + best port by the node connected to the other side of + it. + */ + } else if (routing_for_lmc) { + /* Is the sys guid already used ? */ + p_remote_guid = 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 = 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) { + 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); +} + +static int alloc_lft(IN osm_switch_t * p_sw, uint16_t lids) +{ + uint16_t lft_size; + + /* Ensure LFT is in units of LFT block size */ + lft_size = (lids / IB_SMP_DATA_SIZE + 1) * IB_SMP_DATA_SIZE; + if (lft_size > p_sw->lft_size) { + uint8_t *new_lft = realloc(p_sw->lft, lft_size); + if (!new_lft) + return -1; + memset(new_lft + p_sw->lft_size, OSM_NO_PATH, + lft_size - p_sw->lft_size); + p_sw->lft = new_lft; + p_sw->lft_size = lft_size; + } + + return 0; +} + +int osm_switch_prepare_path_rebuild(IN osm_switch_t * p_sw, IN uint16_t max_lids) +{ + uint8_t **hops; + unsigned i; + + if (alloc_lft(p_sw, max_lids)) + return -1; + + 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 = realloc(p_sw->new_lft, p_sw->lft_size))) + return -1; + + memset(p_sw->new_lft, OSM_NO_PATH, p_sw->lft_size); + + 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) { + hops = realloc(p_sw->hops, (max_lids + 1) * sizeof(hops[0])); + if (!hops) + return -1; + memset(hops + p_sw->num_hops, 0, + (max_lids + 1 - p_sw->num_hops) * sizeof(hops[0])); + p_sw->hops = hops; + p_sw->num_hops = max_lids + 1; + } + p_sw->max_lid_ho = max_lids; + + return 0; +} + +uint8_t osm_switch_get_port_least_hops(IN const osm_switch_t * 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 * p_sw, + IN osm_port_t * p_port, + IN uint16_t mlid_ho, + IN boolean_t 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/branches/WOF2-3/ulp/opensm/user/opensm/osm_trap_rcv.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_trap_rcv.c new file mode 100644 index 00000000..3a78e37a --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_trap_rcv.c @@ -0,0 +1,622 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2007 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Copyright (c) 2009 HNR Consulting. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_trap_rcv_t. + * This object represents the Trap Receiver object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern void osm_req_get_node_desc(IN osm_sm_t * sm, osm_physp_t *p_physp); + +/********************************************************************** + * + * TRAP HANDLING: + * + * Assuming traps can be caused by bad hardware we should provide + * a mechanism for filtering their propagation into the actual logic + * of OpenSM such that it is not overloaded by them. + * + * We will provide a trap filtering mechanism with "Aging" capability. + * This mechanism will track incoming traps, clasify them by their + * source and content and provide back their age. + * + * A timer running in the background will toggle a timer counter + * that should be referenced by the aging algorithm. + * To provide an efficient handling of aging, we also track all traps + * in a sorted list by their aging. + * + * The generic Aging Tracker mechanism is implemented in the + * cl_aging_tracker object. + * + **********************************************************************/ + +static osm_physp_t *get_physp_by_lid_and_num(IN osm_sm_t * sm, + IN ib_net16_t lid, IN uint8_t num) +{ + osm_port_t *p_port = osm_get_port_by_lid(sm->p_subn, 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); +} + +static uint64_t aging_tracker_callback(IN uint64_t key, IN uint32_t num_regs, + IN void *context) +{ + osm_sm_t *sm = context; + ib_net16_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 = (ib_net16_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, cl_ntoh16(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, cl_ntoh16(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 trap_calc_crc32(void *buffer, uint32_t count) +{ + uint32_t temp1, temp2; + uint32_t crc = -1L; + unsigned char *p = (unsigned char *)buffer; + /* precalculated 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 uint64_t trap_get_key(IN uint16_t lid, IN uint8_t port_num, + IN ib_mad_notice_attr_t * p_ntci) +{ + uint32_t crc = trap_calc_crc32(p_ntci, sizeof(ib_mad_notice_attr_t)); + return ((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; + + /* 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 */ + + 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; + + return 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); +} + +static void log_trap_info(osm_log_t *p_log, ib_mad_notice_attr_t *p_ntci, + ib_net16_t source_lid, ib_net64_t trans_id) +{ + if (!osm_log_is_active(p_log, OSM_LOG_ERROR)) + return; + + if (ib_notice_is_generic(p_ntci)) { + char str[32]; + + 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))) + snprintf(str, sizeof(str), " Port %u", + p_ntci->data_details.ntc_129_131.port_num); + else + str[0] = '\0'; + + OSM_LOG(p_log, OSM_LOG_ERROR, + "Received Generic Notice type:%u " + "num:%u (%s) Producer:%u (%s) " + "from LID:%u%s 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), str, cl_ntoh64(trans_id)); + } else + OSM_LOG(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(trans_id)); +} + +static int shutup_noisy_port(osm_sm_t *sm, ib_net16_t lid, uint8_t port, + unsigned num) +{ + osm_physp_t *p = get_physp_by_lid_and_num(sm, lid, port); + if (!p) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3805: " + "Failed to find physical port by lid:%u num:%u\n", + cl_ntoh16(lid), port); + return -1; + } + + /* 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 >= 250) { + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "Disabling noisy physical port 0x%016" PRIx64 + ": lid %u, num %u\n", + cl_ntoh64(osm_physp_get_port_guid(p)), + cl_ntoh16(lid), port); + if (disable_port(sm, p)) + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3811: " + "Failed to disable.\n"); + else + return 1; + } + + /* 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 (osm_physp_is_healthy(p)) { + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "Marking unhealthy physical port by lid:%u num:%u\n", + cl_ntoh16(lid), port); + osm_physp_set_health(p, FALSE); + return 2; + } + return 0; +} + +static void trap_rcv_process_request(IN osm_sm_t * sm, + IN const osm_madw_t * 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; + 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 receive 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 */ + log_trap_info(sm->p_log, p_ntci, source_lid, 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; + port_num = p_ntci->data_details.ntc_129_131.port_num; + } + + /* try to find it in the aging tracker */ + trap_key = trap_get_key(source_lid, port_num, p_ntci); + 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_VERBOSE, + "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) { + int ret = shutup_noisy_port(sm, source_lid, + port_num, + num_received); + if (ret == 1) /* port disabled */ + goto Exit; + else if (ret == 2) /* unhealthy - run sweep */ + run_heavy_sweep = TRUE; + /* in any case increase timeout interval */ + 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, + aging_tracker_callback, sm); + else + cl_event_wheel_reg(&sm->trap_aging_tracker, trap_key, + cl_get_time_stamp() + event_wheel_timeout, + NULL, NULL); + + /* 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, + "Ignoring noisy traps.\n"); + goto Exit; + } + } + + /* Check for node description update. IB Spec v1.2.1 pg 823 */ + if (!ib_notice_is_generic(p_ntci)) + goto check_sweep; + if (cl_ntoh16(p_ntci->g_or_v.generic.trap_num) == 144 && + 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"); + goto check_sweep; + } else if (cl_ntoh16(p_ntci->g_or_v.generic.trap_num) == 145) + /* this assumes that trap 145 content is not broken? */ + p_physp->p_node->node_info.sys_guid = + p_ntci->data_details.ntc_145.new_sys_guid; + +check_sweep: + /* 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_heavy_sweep flag of the subnet. + Sweep also on traps 144 - these traps signal a change of + certain port capabilities. + TODO: In the future this can be changed 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 || + 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_port = osm_get_port_by_lid(sm->p_subn, source_lid); + if (!p_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); +} + +static void trap_rcv_process_response(IN osm_sm_t * sm, + IN const osm_madw_t * 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)) + trap_rcv_process_response(sm, p_madw); + else + trap_rcv_process_request(sm, p_madw); + + OSM_LOG_EXIT(sm->p_log); +} diff --git a/branches/WOF2-3/ulp/opensm/user/opensm/osm_ucast_cache.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_ucast_cache.c new file mode 100644 index 00000000..c84e0660 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_ucast_cache.c @@ -0,0 +1,1028 @@ +/* + * Copyright (c) 2008-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2008-2009 Mellanox Technologies LTD. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of OpenSM Cached Unicast Routing + * + * Environment: + * Linux User Mode + * + */ + +#if HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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_DEBUG, + "Link location change discovered\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_DEBUG, + "Found uncached switch/link (lid %u, port %u)\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_DEBUG, + "Found uncached switch link (lid %u, port %u)\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_DEBUG, + "Remote lid change on switch lid %u, port %u " + "(was %u, now %u)\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_DEBUG, + "Remote node type change on switch lid %u, port %u\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); + + 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); + + OSM_LOG(p_mgr->p_log, OSM_LOG_VERBOSE, "Unicast Cache invalidated\n"); +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_DEBUG, + "New switch found (lid %u)\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_DEBUG, + "New switch/link found (lid %u)\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_DEBUG, + "New CA/RTR found (lid %u)\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_DEBUG, + "Remote node type change on switch lid %u, port %u\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_DEBUG, + "Remote lid change on switch lid %u, port %u" + "(was %u, now %u)\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_DEBUG, + "Missing non-leaf switch (lid %u)\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_DEBUG, + "Switch lid %u, port %u: missing link to existing switch\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_DEBUG, + "Switch lid %u, port %u: missing link to non-leaf switch\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_DEBUG, + "Switch lid %u, port %u: missing leaf-2-leaf link\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_DEBUG, "Found CA-2-CA link\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_DEBUG, "Dropping CA-2-CA link\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_DEBUG, + "Dropped non-leaf switch (lid %u)\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_DEBUG, + "No LID matrices for switch lid %u\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(p_sw->lft_size); + if (!p_sw->lft) + return IB_INSUFFICIENT_MEMORY; + memset(p_sw->lft, OSM_NO_PATH, p_sw->lft_size); + } + + } + + osm_ucast_mgr_set_fwd_tables(p_mgr); + + return 0; +} diff --git a/branches/WOF2-3/ulp/opensm/user/opensm/osm_ucast_file.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_ucast_file.c new file mode 100644 index 00000000..f1cd5973 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_ucast_file.c @@ -0,0 +1,389 @@ +/* + * Copyright (c) 2006-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2006,2008-2009 Mellanox Technologies LTD. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of OpenSM unicast routing module which loads + * routes from the dump file + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +static uint16_t remap_lid(osm_opensm_t * p_osm, uint16_t lid, ib_net64_t guid) +{ + osm_port_t *p_port; + uint16_t min_lid, max_lid; + uint8_t lmc; + + p_port = osm_get_port_by_guid(&p_osm->subn, guid); + if (!p_port) { + OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, + "cannot find port guid 0x%016" PRIx64 + " , will use the same lid\n", cl_ntoh64(guid)); + return lid; + } + + osm_port_get_lid_range_ho(p_port, &min_lid, &max_lid); + if (min_lid <= lid && lid <= max_lid) + return lid; + + lmc = osm_port_get_lmc(p_port); + return min_lid + (lid & ((1 << lmc) - 1)); +} + +static void add_path(osm_opensm_t * p_osm, + osm_switch_t * p_sw, uint16_t lid, uint8_t port_num, + ib_net64_t port_guid) +{ + uint16_t new_lid; + uint8_t old_port; + + new_lid = port_guid ? remap_lid(p_osm, lid, port_guid) : lid; + old_port = osm_switch_get_port_by_lid(p_sw, new_lid); + if (old_port != OSM_NO_PATH && old_port != port_num) { + OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, + "LID collision is detected on switch " + "0x016%" PRIx64 ", will overwrite LID %u entry\n", + cl_ntoh64(osm_node_get_node_guid(p_sw->p_node)), + new_lid); + } + + p_sw->new_lft[new_lid] = port_num; + if (!(p_osm->subn.opt.port_profile_switch_nodes && port_guid && + osm_get_switch_by_guid(&p_osm->subn, port_guid))) + osm_switch_count_path(p_sw, port_num); + + OSM_LOG(&p_osm->log, OSM_LOG_DEBUG, + "route 0x%04x(was 0x%04x) %u 0x%016" PRIx64 + " is added to switch 0x%016" PRIx64 "\n", + new_lid, lid, port_num, cl_ntoh64(port_guid), + cl_ntoh64(osm_node_get_node_guid(p_sw->p_node))); +} + +static void add_lid_hops(osm_opensm_t * p_osm, osm_switch_t * p_sw, + uint16_t lid, ib_net64_t guid, + uint8_t hops[], unsigned len) +{ + uint16_t new_lid; + uint8_t i; + + new_lid = guid ? remap_lid(p_osm, lid, guid) : lid; + if (len > p_sw->num_ports) + len = p_sw->num_ports; + + for (i = 0; i < len; i++) + osm_switch_set_hops(p_sw, lid, i, hops[i]); +} + +static int do_ucast_file_load(void *context) +{ + char line[1024]; + char *file_name; + FILE *file; + ib_net64_t sw_guid, port_guid; + osm_opensm_t *p_osm = context; + osm_switch_t *p_sw; + uint16_t lid; + uint8_t port_num; + unsigned lineno; + + file_name = p_osm->subn.opt.lfts_file; + if (!file_name) { + OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, + "LFTs file name is not given; " + "using default routing algorithm\n"); + return 1; + } + + file = fopen(file_name, "r"); + if (!file) { + OSM_LOG(&p_osm->log, OSM_LOG_ERROR | OSM_LOG_SYS, "ERR 6302: " + "cannot open ucast dump file \'%s\': %m\n", file_name); + return -1; + } + + lineno = 0; + p_sw = NULL; + + while (fgets(line, sizeof(line) - 1, file) != NULL) { + char *p, *q; + lineno++; + + p = line; + while (isspace(*p)) + p++; + + if (*p == '#') + continue; + + if (!strncmp(p, "Multicast mlids", 15)) { + OSM_LOG(&p_osm->log, OSM_LOG_ERROR | OSM_LOG_SYS, + "ERR 6303: " + "Multicast dump file detected; " + "skipping parsing. Using default " + "routing algorithm\n"); + } else if (!strncmp(p, "Unicast lids", 12)) { + 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, p_sw->lft_size); + } 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 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); + 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); + } + } + + 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/branches/WOF2-3/ulp/opensm/user/opensm/osm_ucast_ftree.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_ucast_ftree.c new file mode 100644 index 00000000..a66be414 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_ucast_ftree.c @@ -0,0 +1,4112 @@ +/* + * Copyright (c) 2009 Simula Research Laboratory. All rights reserved. + * Copyright (c) 2009 Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2009 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of OpenSM FatTree routing + */ + +#if HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * FatTree rank is bounded between 2 and 8: + * - Tree of rank 1 has only trivial routing paths, + * so no need to use FatTree routing. + * - Why maximum rank is 8: + * Each node (switch) is assigned a unique tuple. + * Switches are stored in two cl_qmaps - one is + * ordered by guid, and the other by a key that is + * generated from tuple. Since cl_qmap supports only + * a 64-bit key, the maximal tuple lenght is 8 bytes. + * which means that maximal tree rank is 8. + * Note that the above also implies that each switch + * can have at max 255 up/down ports. + */ + +#define FAT_TREE_MIN_RANK 2 +#define FAT_TREE_MAX_RANK 8 + +typedef enum { + FTREE_DIRECTION_DOWN = -1, + FTREE_DIRECTION_SAME, + FTREE_DIRECTION_UP +} ftree_direction_t; + +/*************************************************** + ** + ** Forward references + ** + ***************************************************/ +struct ftree_sw_t_; +struct ftree_hca_t_; +struct ftree_port_t_; +struct ftree_port_group_t_; +struct ftree_fabric_t_; + +/*************************************************** + ** + ** ftree_tuple_t definition + ** + ***************************************************/ + +#define FTREE_TUPLE_BUFF_LEN 1024 +#define FTREE_TUPLE_LEN 8 + +typedef uint8_t ftree_tuple_t[FTREE_TUPLE_LEN]; +typedef uint64_t ftree_tuple_key_t; + +/*************************************************** + ** + ** 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 routes upwards */ + uint32_t counter_down; /* number of allocated routes 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; + uint16_t base_lid; /* base lid of the current node */ + uint16_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 */ + boolean_t is_io; /* whether this port is an I/O node */ + uint32_t counter_down; /* number of allocated routes downwards */ + uint32_t counter_up; /* number of allocated routes upwards */ +} 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; + uint16_t base_lid; + ftree_port_group_t **down_port_groups; + uint8_t down_port_groups_num; + ftree_port_group_t **sibling_port_groups; + uint8_t sibling_port_groups_num; + ftree_port_group_t **up_port_groups; + uint8_t up_port_groups_num; + boolean_t is_leaf; + unsigned down_port_groups_idx; + uint8_t *hops; + uint32_t min_counter_down; + boolean_t counter_up_changed; +} 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_qmap_t cn_guid_tbl; + cl_qmap_t io_guid_tbl; + unsigned cn_num; + unsigned ca_ports; + 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; + boolean_t fabric_built; +} ftree_fabric_t; + +/*************************************************** + ** + ** comparators + ** + ***************************************************/ + +static int OSM_CDECL 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 +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 + 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 tuple_init(IN ftree_tuple_t tuple) +{ + memset(tuple, 0xFF, FTREE_TUPLE_LEN); +} + +/***************************************************/ + +static inline boolean_t tuple_assigned(IN ftree_tuple_t tuple) +{ + return (tuple[0] != 0xFF); +} + +/***************************************************/ + +#define FTREE_TUPLE_BUFFERS_NUM 6 + +static char *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 (!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; +} /* tuple_to_str() */ + +/***************************************************/ + +static inline ftree_tuple_key_t tuple_to_key(IN ftree_tuple_t tuple) +{ + ftree_tuple_key_t key; + memcpy(&key, tuple, FTREE_TUPLE_LEN); + return key; +} + +/***************************************************/ + +static inline void 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 *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 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 *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 port_destroy(IN ftree_port_t * p_port) +{ + if (p_port) + free(p_port); +} + +/*************************************************** + ** + ** ftree_port_group_t functions + ** + ***************************************************/ + +static ftree_port_group_t *port_group_create(IN uint16_t base_lid, + IN uint16_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, + IN boolean_t is_io) +{ + 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; + p_group->is_io = is_io; + return p_group; +} /* port_group_create() */ + +/***************************************************/ + +static void 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); + port_destroy(p_port); + } + cl_ptr_vector_destroy(&p_group->ports); + free(p_group); +} /* port_group_destroy() */ + +/***************************************************/ + +static void 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" : (direction == + FTREE_DIRECTION_SAME) + ? "SIBLING" : "UP", cl_ntoh64(p_group->port_guid), + p_group->base_lid, cl_ntoh64(p_group->remote_port_guid), + p_group->remote_base_lid); + +} /* port_group_dump() */ + +/***************************************************/ + +static void 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 = 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 *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; + tuple_init(p_sw->tuple); + + p_sw->base_lid = + cl_ntoh16(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 *)); + p_sw->sibling_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 + || !p_sw->sibling_port_groups) + return NULL; + + /* initialize lft buffer */ + memset(p_osm_sw->new_lft, OSM_NO_PATH, p_osm_sw->lft_size); + p_sw->hops = malloc((p_osm_sw->max_lid_ho + 1) * sizeof(*(p_sw->hops))); + if (p_sw->hops == NULL) + return NULL; + memset(p_sw->hops, OSM_NO_PATH, p_osm_sw->max_lid_ho + 1); + + return p_sw; +} /* sw_create() */ + +/***************************************************/ + +static void sw_destroy(IN ftree_fabric_t * p_ftree, IN ftree_sw_t * p_sw) +{ + uint8_t i; + + if (!p_sw) + return; + free(p_sw->hops); + + for (i = 0; i < p_sw->down_port_groups_num; i++) + port_group_destroy(p_sw->down_port_groups[i]); + for (i = 0; i < p_sw->sibling_port_groups_num; i++) + port_group_destroy(p_sw->sibling_port_groups[i]); + for (i = 0; i < p_sw->up_port_groups_num; i++) + port_group_destroy(p_sw->up_port_groups[i]); + if (p_sw->down_port_groups) + free(p_sw->down_port_groups); + if (p_sw->sibling_port_groups) + free(p_sw->sibling_port_groups); + if (p_sw->up_port_groups) + free(p_sw->up_port_groups); + + free(p_sw); +} /* sw_destroy() */ + +/***************************************************/ + +static uint64_t 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 sw_get_guid_ho(IN ftree_sw_t * p_sw) +{ + return cl_ntoh64(sw_get_guid_no(p_sw)); +} + +/***************************************************/ + +static void 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 SIBLINGS, %u UP\n", + tuple_to_str(p_sw->tuple), sw_get_guid_ho(p_sw), + p_sw->down_port_groups_num, p_sw->sibling_port_groups_num, + p_sw->up_port_groups_num); + + for (i = 0; i < p_sw->down_port_groups_num; i++) + port_group_dump(p_ftree, p_sw->down_port_groups[i], + FTREE_DIRECTION_DOWN); + for (i = 0; i < p_sw->sibling_port_groups_num; i++) + port_group_dump(p_ftree, p_sw->sibling_port_groups[i], + FTREE_DIRECTION_SAME); + for (i = 0; i < p_sw->up_port_groups_num; i++) + port_group_dump(p_ftree, p_sw->up_port_groups[i], + FTREE_DIRECTION_UP); + +} /* sw_dump() */ + +/***************************************************/ + +static boolean_t sw_ranked(IN ftree_sw_t * p_sw) +{ + return (p_sw->rank != 0xFFFFFFFF); +} + +/***************************************************/ + +static ftree_port_group_t *sw_get_port_group_by_remote_lid(IN ftree_sw_t * p_sw, + IN uint16_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 if (direction == FTREE_DIRECTION_SAME) { + port_groups = p_sw->sibling_port_groups; + size = p_sw->sibling_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; +} /* sw_get_port_group_by_remote_lid() */ + +/***************************************************/ + +static void sw_add_port(IN ftree_sw_t * p_sw, IN uint8_t port_num, + IN uint8_t remote_port_num, IN uint16_t base_lid, + IN uint16_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 = + sw_get_port_group_by_remote_lid(p_sw, remote_base_lid, direction); + + if (!p_group) { + p_group = port_group_create(base_lid, remote_base_lid, + port_guid, 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, FALSE); + CL_ASSERT(p_group); + + if (direction == FTREE_DIRECTION_UP) { + p_sw->up_port_groups[p_sw->up_port_groups_num++] = + p_group; + } else if (direction == FTREE_DIRECTION_SAME) { + p_sw-> + sibling_port_groups[p_sw->sibling_port_groups_num++] + = p_group; + } else + p_sw->down_port_groups[p_sw->down_port_groups_num++] = + p_group; + } + port_group_add_port(p_group, port_num, remote_port_num); + +} /* sw_add_port() */ + +/***************************************************/ + +static inline cl_status_t sw_set_hops(IN ftree_sw_t * p_sw, IN uint16_t lid, + IN uint8_t port_num, IN uint8_t hops, + IN boolean_t is_target_sw) +{ + /* set local min hop table(LID) */ + p_sw->hops[lid] = hops; + if (is_target_sw) + return osm_switch_set_hops(p_sw->p_osm_sw, lid, port_num, hops); + return 0; +} + +/***************************************************/ + +static int set_hops_on_remote_sw(IN ftree_port_group_t * p_group, + IN uint16_t target_lid, IN uint8_t hops, + IN boolean_t is_target_sw) +{ + ftree_port_t *p_port; + uint8_t i, ports_num; + ftree_sw_t *p_remote_sw = p_group->remote_hca_or_sw.p_sw; + + /* if lid is a switch, we set the min hop table in the osm_switch struct */ + CL_ASSERT(p_group->remote_node_type == IB_NODE_TYPE_SWITCH); + p_remote_sw->hops[target_lid] = hops; + + /* If taget lid is a switch we set the min hop table values + * for each port on the associated osm_sw struct */ + if (!is_target_sw) + return 0; + + ports_num = (uint8_t) cl_ptr_vector_get_size(&p_group->ports); + for (i = 0; i < ports_num; i++) { + cl_ptr_vector_at(&p_group->ports, i, (void *)&p_port); + if (sw_set_hops(p_remote_sw, target_lid, + p_port->remote_port_num, hops, is_target_sw)) + return -1; + } + return 0; +} + +/***************************************************/ + +static inline uint8_t +sw_get_least_hops(IN ftree_sw_t * p_sw, IN uint16_t target_lid) +{ + CL_ASSERT(p_sw->hops != NULL); + return p_sw->hops[target_lid]; +} + +/*************************************************** + ** + ** ftree_hca_t functions + ** + ***************************************************/ + +static ftree_hca_t *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 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++) + 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 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 hca_get_guid_ho(IN ftree_hca_t * p_hca) +{ + return cl_ntoh64(hca_get_guid_no(p_hca)); +} + +/***************************************************/ + +static void 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", + hca_get_guid_ho(p_hca), p_hca->up_port_groups_num); + + for (i = 0; i < p_hca->up_port_groups_num; i++) + port_group_dump(p_ftree, p_hca->up_port_groups[i], + FTREE_DIRECTION_UP); +} + +/***************************************************/ + +static ftree_port_group_t *hca_get_port_group_by_remote_lid(IN ftree_hca_t * + p_hca, + IN uint16_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 hca_add_port(IN ftree_hca_t * p_hca, IN uint8_t port_num, + IN uint8_t remote_port_num, IN uint16_t base_lid, + IN uint16_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, + IN boolean_t is_io) +{ + 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 = hca_get_port_group_by_remote_lid(p_hca, remote_base_lid); + + if (!p_group) { + p_group = port_group_create(base_lid, remote_base_lid, + port_guid, 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, is_io); + p_hca->up_port_groups[p_hca->up_port_groups_num++] = p_group; + } + port_group_add_port(p_group, port_num, remote_port_num); + +} /* hca_add_port() */ + +/*************************************************** + ** + ** ftree_fabric_t functions + ** + ***************************************************/ + +static ftree_fabric_t *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_qmap_init(&p_ftree->io_guid_tbl); + + return p_ftree; +} + +/***************************************************/ + +static void 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); + 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); + 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); + 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 io_guid_tbl */ + p_next_guid_element = + (name_map_item_t *) cl_qmap_head(&p_ftree->io_guid_tbl); + while (p_next_guid_element != + (name_map_item_t *) cl_qmap_end(&p_ftree->io_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->io_guid_tbl); + + /* 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->ca_ports = 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 = 0; + p_ftree->leaf_switches = NULL; + p_ftree->fabric_built = FALSE; + +} /* fabric_destroy() */ + +/***************************************************/ + +static void fabric_destroy(ftree_fabric_t * p_ftree) +{ + if (!p_ftree) + return; + fabric_clear(p_ftree); + free(p_ftree); +} + +/***************************************************/ + +static uint8_t fabric_get_rank(ftree_fabric_t * p_ftree) +{ + return p_ftree->leaf_switch_rank + 1; +} + +/***************************************************/ + +static void fabric_add_hca(ftree_fabric_t * p_ftree, osm_node_t * p_osm_node) +{ + ftree_hca_t *p_hca = 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 fabric_add_sw(ftree_fabric_t * p_ftree, osm_switch_t * p_osm_sw) +{ + ftree_sw_t *p_sw = 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 (p_sw->base_lid > p_ftree->lft_max_lid) + p_ftree->lft_max_lid = p_sw->base_lid; +} + +/***************************************************/ + +static void fabric_add_sw_by_tuple(IN ftree_fabric_t * p_ftree, + IN ftree_sw_t * p_sw) +{ + CL_ASSERT(tuple_assigned(p_sw->tuple)); + + cl_qmap_insert(&p_ftree->sw_by_tuple_tbl, tuple_to_key(p_sw->tuple), + &sw_tbl_element_create(p_sw)->map_item); +} + +/***************************************************/ + +static ftree_sw_t *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(tuple_assigned(tuple)); + + tuple_to_key(tuple); + + p_element = + (ftree_sw_tbl_element_t *) cl_qmap_get(&p_ftree->sw_by_tuple_tbl, + 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 *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 *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 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)) { + 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) + 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"); +} /* fabric_dump() */ + +/***************************************************/ + +static void 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 CA ports (%u of them CNs), %u switches\n", + cl_qmap_count(&p_ftree->hca_tbl), p_ftree->ca_ports, + p_ftree->cn_num, cl_qmap_count(&p_ftree->sw_tbl)); + + CL_ASSERT(p_ftree->ca_ports >= 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", + sw_get_guid_ho(p_sw), + p_sw->base_lid, + 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", + sw_get_guid_ho(p_ftree->leaf_switches[i]), + p_ftree->leaf_switches[i]->base_lid, + tuple_to_str(p_ftree->leaf_switches[i]->tuple)); + } + } +} /* fabric_dump_general_info() */ + +/***************************************************/ + +static void 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 = + 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", + 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); +} /* fabric_dump_hca_ordering() */ + +/***************************************************/ + +static void 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); + fabric_add_sw_by_tuple(p_ftree, p_sw); +} + +/***************************************************/ + +static void fabric_assign_first_tuple(IN ftree_fabric_t * p_ftree, + IN ftree_sw_t * p_sw) +{ + uint8_t i; + ftree_tuple_t new_tuple; + + tuple_init(new_tuple); + new_tuple[0] = (uint8_t) p_sw->rank; + for (i = 1; i <= p_sw->rank; i++) + new_tuple[i] = 0; + + fabric_assign_tuple(p_ftree, p_sw, new_tuple); +} + +/***************************************************/ + +static void 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; + + 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 = 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); + +} /* fabric_get_new_tuple() */ + +/***************************************************/ + +static inline boolean_t fabric_roots_provided(IN ftree_fabric_t * p_ftree) +{ + return (p_ftree->p_osm->subn.opt.root_guid_file != NULL); +} + +/***************************************************/ + +static inline boolean_t fabric_cns_provided(IN ftree_fabric_t * p_ftree) +{ + return (p_ftree->p_osm->subn.opt.cn_guid_file != NULL); +} + +/***************************************************/ + +static inline boolean_t fabric_ios_provided(IN ftree_fabric_t * p_ftree) +{ + return (p_ftree->p_osm->subn.opt.io_guid_file != NULL); +} + +/***************************************************/ + +static int 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), + 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; +} /* fabric_mark_leaf_switches() */ + +/***************************************************/ + +static void 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; + + 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. */ + 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, tuple_to_str(p_sw->tuple), + p_sw->base_lid, 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, p_sw); + + while (!cl_is_list_empty(&bfs_list)) { + p_sw = (ftree_sw_t *) cl_list_remove_head(&bfs_list); + + /* 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 (tuple_assigned(p_remote_sw->tuple)) { + /* this switch has been already indexed */ + continue; + } + /* allocate new tuple */ + 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. */ + 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, p_remote_sw); + } + /* 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 */ + 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 (tuple_assigned(p_remote_sw->tuple)) + continue; + /* allocate new tuple */ + 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. */ + 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, p_remote_sw); + } + /* 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 */ + 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); +} /* fabric_make_indexing() */ + +/***************************************************/ + +static int 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", + 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 */ + 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; +} /* fabric_create_leaf_switch_array() */ + +/***************************************************/ + +static void 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; + } +} /* fabric_set_max_cn_per_leaf() */ + +/***************************************************/ + +static boolean_t 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 = 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", + sw_get_guid_ho + (reference_sw_arr[p_sw->rank]), + reference_sw_arr[p_sw->rank]->base_lid, + tuple_to_str + (reference_sw_arr[p_sw->rank]->tuple), + reference_sw_arr[p_sw-> + rank]-> + up_port_groups_num, + sw_get_guid_ho(p_sw), p_sw->base_lid, + 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", + sw_get_guid_ho + (reference_sw_arr[p_sw->rank]), + reference_sw_arr[p_sw->rank]->base_lid, + tuple_to_str + (reference_sw_arr[p_sw->rank]->tuple), + reference_sw_arr[p_sw-> + rank]-> + down_port_groups_num, + sw_get_guid_ho(p_sw), p_sw->base_lid, + 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", + sw_get_guid_ho + (reference_sw_arr + [p_sw->rank]), + reference_sw_arr[p_sw-> + rank]-> + base_lid, + tuple_to_str + (reference_sw_arr + [p_sw->rank]->tuple), + cl_ptr_vector_get_size + (&p_ref_group->ports), + sw_get_guid_ho(p_sw), + p_sw->base_lid, + 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", + sw_get_guid_ho + (reference_sw_arr + [p_sw->rank]), + reference_sw_arr[p_sw-> + rank]-> + base_lid, + tuple_to_str + (reference_sw_arr + [p_sw->rank]->tuple), + cl_ptr_vector_get_size + (&p_ref_group->ports), + sw_get_guid_ho(p_sw), + p_sw->base_lid, + 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; +} /* fabric_validate_topology() */ + +/*************************************************** + ***************************************************/ + +static void 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; +} + +/*************************************************** + ***************************************************/ + +/* + * Function: Finds the least loaded port group and stores its counter + * Given : A switch + */ +static inline void recalculate_min_counter_down(ftree_sw_t * p_sw) +{ + uint32_t min = (1 << 30); + uint32_t i; + for (i = 0; i < p_sw->down_port_groups_num; i++) { + if (p_sw->down_port_groups[i]->counter_down < min) { + min = p_sw->down_port_groups[i]->counter_down; + } + } + p_sw->min_counter_down = min; + return; +} + +/* + * Function: Return the counter value of the least loaded down port group + * Given : A switch + */ +static inline uint32_t find_lowest_loaded_group_on_sw(ftree_sw_t * p_sw) +{ + return p_sw->min_counter_down; +} + +/* + * Function: Compare the load of two port groups and return which is the least loaded + * Given : Two port groups with remote switch + * When both port groups are equally loaded, it picks the one whom + * remote switch down ports are least loaded. + * This way, it prefers the switch from where it will be easier to go down (creating upward routes). + * If both are equal, it picks the bigger GUID to be deterministic. + */ +static inline int port_group_compare_load_down(const ftree_port_group_t * p1, + const ftree_port_group_t * p2) +{ + int temp = p1->counter_down - p2->counter_down; + if (temp > 0) + return 1; + if (temp < 0) + return -1; + + /* Find the less loaded remote sw and choose this one */ + do { + uint32_t load1 = + find_lowest_loaded_group_on_sw(p1->remote_hca_or_sw.p_sw); + uint32_t load2 = + find_lowest_loaded_group_on_sw(p2->remote_hca_or_sw.p_sw); + temp = load1 - load2; + if (temp > 0) + return 1; + } while (0); + /* If they are both equal, choose the biggest GUID */ + if (p1->remote_port_guid > p2->remote_port_guid) + return 1; + + return -1; + +} + +/* + * Function: Sorts an array of port group by up load order + * Given : A port group array and its length + * As the list is mostly sorted, we used a bubble sort instead of qsort + * as it is much faster. + * + * Important note: + * This function and bubble_sort_down must NOT be factorized. + * Although most of the code is the same and a function pointer could be used + * for the compareason function, it would prevent the compareason function to be inlined + * and cost a great deal to performances. + */ +static inline void +bubble_sort_up(ftree_port_group_t ** p_group_array, uint32_t nmemb) +{ + uint32_t i = 0; + uint32_t j = 0; + ftree_port_group_t *tmp = p_group_array[0]; + + /* As this function is a great number of times, we only go into the loop + * if one of the port counters has changed, thus saving some tests */ + if (tmp->hca_or_sw.p_sw->counter_up_changed == FALSE) { + return; + } + /* While we did modifications on the array order */ + /* i may grew above array length but next loop will fail and tmp will be null for the next time + * this way we save a test i < nmemb for each pass through the loop */ + for (i = 0; tmp; i++) { + /* Assume the array is orderd */ + tmp = NULL; + /* Comparing elements j and j-1 */ + for (j = 1; j < (nmemb - i); j++) { + /* If they are the wrong way around */ + if (p_group_array[j]->counter_up < + p_group_array[j - 1]->counter_up) { + /* We invert them */ + tmp = p_group_array[j - 1]; + p_group_array[j - 1] = p_group_array[j]; + p_group_array[j] = tmp; + /* This sets tmp != NULL so the main loop will make another pass */ + } + } + } + + /* We have reordered the array so as long noone changes the counter + * it's not necessary to do it again */ + p_group_array[0]->hca_or_sw.p_sw->counter_up_changed = FALSE; +} + +static inline void +bubble_sort_siblings(ftree_port_group_t ** p_group_array, uint32_t nmemb) +{ + uint32_t i = 0; + uint32_t j = 0; + ftree_port_group_t *tmp = p_group_array[0]; + + /* While we did modifications on the array order */ + /* i may grew above array length but next loop will fail and tmp will be null for the next time + * this way we save a test i < nmemb for each pass through the loop */ + for (i = 0; tmp != NULL; i++) { + /* Assume the array is orderd */ + tmp = NULL; + /* Comparing elements j and j-1 */ + for (j = 1; j < (nmemb - i); j++) { + /* If they are the wrong way around */ + if (p_group_array[j]->counter_up < + p_group_array[j - 1]->counter_up) { + /* We invert them */ + tmp = p_group_array[j - 1]; + p_group_array[j - 1] = p_group_array[j]; + p_group_array[j] = tmp; + + } + } + } +} + +/* + * Function: Sorts an array of port group. Order is decide through + * port_group_compare_load_down ( up counters, least load remote switch, biggest GUID) + * Given : A port group array and its length. Each port group points to a remote switch (not a HCA) + * As the list is mostly sorted, we used a bubble sort instead of qsort + * as it is much faster. + * + * Important note: + * This function and bubble_sort_up must NOT be factorized. + * Although most of the code is the same and a function pointer could be used + * for the compareason function, it would prevent the compareason function to be inlined + * and cost a great deal to performances. + */ +static inline void +bubble_sort_down(ftree_port_group_t ** p_group_array, uint32_t nmemb) +{ + uint32_t i = 0; + uint32_t j = 0; + ftree_port_group_t *tmp = p_group_array[0]; + + /* While we did modifications on the array order */ + /* i may grew above array length but next loop will fail and tmp will be null for the next time + * this way we save a test i < nmemb for each pass through the loop */ + for (i = 0; tmp; i++) { + /* Assume the array is orderd */ + tmp = NULL; + /* Comparing elements j and j-1 */ + for (j = 1; j < (nmemb - i); j++) { + /* If they are the wrong way around */ + if (port_group_compare_load_down + (p_group_array[j], p_group_array[j - 1]) < 0) { + /* We invert them */ + tmp = p_group_array[j - 1]; + p_group_array[j - 1] = p_group_array[j]; + p_group_array[j] = tmp; + + } + } + } +} + +/*************************************************** + ***************************************************/ + +/* + * 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 boolean_t +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 uint16_t target_lid, + IN boolean_t is_real_lid, + IN boolean_t is_main_path, + IN boolean_t is_target_a_sw, + IN uint8_t current_hops) +{ + 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 j; + uint16_t k; + boolean_t created_route = FALSE; + boolean_t routed = 0; + uint8_t least_hops; + + /* 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 FALSE; + + /* foreach down-going port group (in load order) */ + bubble_sort_up(p_sw->down_port_groups, p_sw->down_port_groups_num); + + if (p_sw->sibling_port_groups_num > 0) + bubble_sort_siblings(p_sw->sibling_port_groups, + p_sw->sibling_port_groups_num); + + for (k = 0; + k < + (p_sw->down_port_groups_num + + (is_real_lid ? p_sw->sibling_port_groups_num : 0)); k++) { + + if (k < p_sw->down_port_groups_num) { + p_group = p_sw->down_port_groups[k]; + } else { + p_group = + p_sw->sibling_port_groups[k - + p_sw-> + down_port_groups_num]; + } + + /* If this port group doesn't point to a switch, mark + that the route was created and skip to the next group */ + if (p_group->remote_node_type != IB_NODE_TYPE_SWITCH) { + created_route = TRUE; + 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); + + for (j = 0; j < ports_num; j++) { + cl_ptr_vector_at(&p_group->ports, j, (void *)&p_port); + /* first port that we're checking - set as port with the lowest load */ + /* or this port is less loaded - use it as min */ + if (!p_min_port || + p_port->counter_up < p_min_port->counter_up) + 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; + least_hops = sw_get_least_hops(p_remote_sw, target_lid); + + if (least_hops != 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", + current_hops, + tuple_to_str(p_remote_sw->tuple), + p_group->base_lid, + tuple_to_str(p_sw->tuple), + p_group->remote_base_lid); + /* We skip only if we have come through a longer path */ + if (current_hops + 1 >= least_hops) + 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 (or with a longer path) + * + 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 + */ + + /* setting fwd tbl port only if this is real LID */ + if (is_real_lid) { + p_remote_sw->p_osm_sw->new_lft[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", + tuple_to_str(p_remote_sw->tuple), + 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. */ + + set_hops_on_remote_sw(p_group, target_lid, + current_hops + 1, is_target_a_sw); + } + + /* Recursion step: + Assign upgoing ports by stepping down, starting on REMOTE switch */ + routed = 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 */ + 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 */ + is_target_a_sw, /* Wheter target lid is a switch or not */ + current_hops + 1); /* Number of hops done to this point */ + created_route |= routed; + /* Counters are promoted only if a route toward a node is created */ + if (routed) { + p_min_port->counter_up++; + p_group->counter_up++; + p_group->hca_or_sw.p_sw->counter_up_changed = TRUE; + } + } + /* done scanning all the down-going port groups */ + + /* if the route was created, promote the index that + indicates which group should we start with when + going through all the downgoing groups */ + if (created_route) + p_sw->down_port_groups_idx = (p_sw->down_port_groups_idx + 1) + % p_sw->down_port_groups_num; + + return created_route; +} /* 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 boolean_t +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 uint16_t target_lid, + IN boolean_t is_real_lid, + IN boolean_t is_main_path, + IN boolean_t is_target_a_sw, + IN uint16_t reverse_hop_credit, + IN uint16_t reverse_hops, + IN uint8_t current_hops) +{ + 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; + boolean_t created_route = FALSE; + boolean_t routed = FALSE; + + /* 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 */ + created_route = 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 */ + is_real_lid, /* whether this target LID is real or dummy */ + is_main_path, /* whether this path to HCA should by tracked by counters */ + is_target_a_sw, /* Wheter target lid is a switch or not */ + current_hops); /* Number of hops done up to this point */ + + /* recursion stop condition - if it's a root switch, */ + if (p_sw->rank == 0) { + if (reverse_hop_credit > 0) { + /* We go up by going down as we have some reverse_hop_credit left */ + /* We use the index to scatter a bit the reverse up routes */ + p_sw->down_port_groups_idx = + (p_sw->down_port_groups_idx + + 1) % p_sw->down_port_groups_num; + i = p_sw->down_port_groups_idx; + for (j = 0; j < p_sw->down_port_groups_num; j++) { + + 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; + p_remote_sw = p_group->remote_hca_or_sw.p_sw; + + created_route |= 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 */ + 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 */ + is_target_a_sw, /* Wheter target lid is a switch or not */ + reverse_hop_credit - 1, /* Remaining reverse_hops allowed */ + reverse_hops + 1, /* Number of reverse_hops done up to this point */ + current_hops + + + 1); + } + + } + return created_route; + } + + /* We should generate a list of port sorted by load so we can find easily the least + * going port and explore the other pots on secondary routes more easily (and quickly) */ + bubble_sort_down(p_sw->up_port_groups, p_sw->up_port_groups_num); + + p_min_group = p_sw->up_port_groups[0]; + /* 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", + target_lid, + tuple_to_str(p_sw->tuple), + 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 (p_min_group->counter_down == + (p_min_group->remote_hca_or_sw.p_sw->min_counter_down + + 1)) { + recalculate_min_counter_down + (p_min_group->remote_hca_or_sw.p_sw); + } + + if (is_real_lid) { + /* This LID may already be in the LFT in the reverse_hop feature is used */ + /* We update the LFT only if this LID isn't already present. */ + + /* skip if target lid has been already set on remote switch fwd tbl (with a bigger hop count) */ + if ((p_remote_sw->p_osm_sw->new_lft[target_lid] == + OSM_NO_PATH) + || + ((p_remote_sw->p_osm_sw->new_lft[target_lid] != + OSM_NO_PATH) + && + (current_hops + 1 < + sw_get_least_hops(p_remote_sw, target_lid)))) { + + p_remote_sw->p_osm_sw->new_lft[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", + tuple_to_str(p_remote_sw->tuple), + 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. */ + + set_hops_on_remote_sw(p_min_group, target_lid, + current_hops + 1, + is_target_a_sw); + + /* Recursion step: + Assign downgoing ports by stepping up, starting on REMOTE switch. */ + created_route |= 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 */ + 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 */ + is_target_a_sw, /* Wheter target lid is a switch or not */ + reverse_hop_credit, /* Remaining reverse_hops allowed */ + reverse_hops, /* Number of reverse_hops done up to this point */ + current_hops + + + 1); + } + } + } + /* we're done for the third case */ + if (!is_real_lid) + return created_route; + + /* 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 = is_main_path ? 1 : 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 (with a bigger hop count) */ + if (p_remote_sw->p_osm_sw->new_lft[target_lid] != OSM_NO_PATH) + if (current_hops + 1 >= + sw_get_least_hops(p_remote_sw, target_lid)) + 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", + target_lid, + tuple_to_str(p_sw->tuple), + 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. */ + p_min_port = NULL; + 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); + 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; + } + } + + p_port = p_min_port; + p_remote_sw->p_osm_sw->new_lft[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. */ + + set_hops_on_remote_sw(p_group, target_lid, + current_hops + 1, is_target_a_sw); + + /* Recursion step: + Assign downgoing ports by stepping up, starting on REMOTE switch. */ + routed = 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 */ + TRUE, /* whether the target LID is real or dummy */ + FALSE, /* whether this is path to HCA that should by tracked by counters */ + is_target_a_sw, /* Wheter target lid is a switch or not */ + reverse_hop_credit, /* Remaining reverse_hops allowed */ + reverse_hops, /* Number of reverse_hops done up to this point */ + current_hops + 1); + created_route |= routed; + } + + /* Now doing the same thing with horizontal links */ + if (p_sw->sibling_port_groups_num > 0) + bubble_sort_down(p_sw->sibling_port_groups, + p_sw->sibling_port_groups_num); + + for (i = 0; i < p_sw->sibling_port_groups_num; i++) { + p_group = p_sw->sibling_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 (with a bigger hop count) */ + if (p_remote_sw->p_osm_sw->new_lft[target_lid] != OSM_NO_PATH) + if (current_hops + 1 >= + sw_get_least_hops(p_remote_sw, target_lid)) + 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", + target_lid, + tuple_to_str(p_sw->tuple), + 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. */ + + p_min_port = NULL; + 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); + 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; + } + } + + p_port = p_min_port; + p_remote_sw->p_osm_sw->new_lft[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. */ + + set_hops_on_remote_sw(p_group, target_lid, + current_hops + 1, is_target_a_sw); + + /* Recursion step: + Assign downgoing ports by stepping up, starting on REMOTE switch. */ + routed = 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 */ + TRUE, /* whether the target LID is real or dummy */ + FALSE, /* whether this is path to HCA that should by tracked by counters */ + is_target_a_sw, /* Wheter target lid is a switch or not */ + reverse_hop_credit, /* Remaining reverse_hops allowed */ + reverse_hops, /* Number of reverse_hops done up to this point */ + current_hops + 1); + created_route |= routed; + if (routed) { + p_min_group->counter_down++; + p_min_port->counter_down++; + } + } + + /* If we don't have any reverse hop credits, we are done */ + if (reverse_hop_credit == 0) + return created_route; + + if (p_sw->is_leaf) + return created_route; + + /* We explore all the down group ports */ + /* We try to reverse jump for each of them */ + /* They already have a route to us from the upgoing_by_going_down started earlier */ + /* This is only so it'll continue exploring up, after this step backwards */ + for (i = 0; i < p_sw->down_port_groups_num; i++) { + p_group = p_sw->down_port_groups[i]; + p_remote_sw = p_group->remote_hca_or_sw.p_sw; + + /* Skip this port group unless it points to a switch */ + if (p_group->remote_node_type != IB_NODE_TYPE_SWITCH) + continue; + + /* Recursion step: + Assign downgoing ports by stepping up, fter doing one step down starting on REMOTE switch. */ + created_route |= 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 */ + TRUE, /* whether the target LID is real or dummy */ + TRUE, /* whether this is path to HCA that should by tracked by counters */ + is_target_a_sw, /* Wheter target lid is a switch or not */ + reverse_hop_credit - 1, /* Remaining reverse_hops allowed */ + reverse_hops + 1, /* Number of reverse_hops done up to this point */ + current_hops + + 1); + } + return created_route; + +} /* 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 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; + unsigned int i, j; + uint16_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 = + 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[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", + tuple_to_str(p_sw->tuple), + hca_lid, p_port->port_num); + + /* set local min hop table(LID) to route to the CA */ + sw_set_hops(p_sw, hca_lid, p_port->port_num, 1, FALSE); + + /* 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. */ + 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 */ + TRUE, /* whether this HCA LID is real or dummy */ + TRUE, /* whether this path to HCA should by tracked by counters */ + FALSE, /* wheter target lid is a switch or not */ + 0, /* Number of reverse hops allowed */ + 0, /* Number of reverse hops done yet */ + 1); /* Number of hops done yet */ + + /* 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; j < + p_ftree->max_cn_per_leaf - routed_targets_on_leaf; + j++) { + /* assign downgoing ports by stepping up */ + 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 */ + FALSE, /* whether this HCA LID is real or dummy */ + TRUE, /* whether this path to HCA should by tracked by counters */ + FALSE, /* Wheter the target LID is a switch or not */ + 0, /* Number of reverse hops allowed */ + 0, /* Number of reverse hops done yet */ + 1); /* Number of hops done yet */ + } + } + } + /* done going through all the leaf switches */ + OSM_LOG_EXIT(&p_ftree->p_osm->log); +} /* 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 connected to the HCA port + * call assign-down-going-port-by-ascending-up(TRUE,TRUE) on the switch + * + * Routing to these HCAs is routing a REAL hca lid on MAIN path. + * We 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 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; + uint16_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[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", + tuple_to_str(p_sw->tuple), + hca_lid, port_num_on_switch); + + /* set local min hop table(LID) to route to the CA */ + sw_set_hops(p_sw, hca_lid, port_num_on_switch, /* port num */ + 1, FALSE); /* 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. */ + 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 */ + TRUE, /* whether this HCA LID is real or dummy */ + TRUE, /* whether this path to HCA should by tracked by counters */ + FALSE, /* Wheter the target LID is a switch or not */ + p_hca_port_group->is_io ? p_ftree->p_osm->subn.opt.max_reverse_hops : 0, /* Number or reverse hops allowed */ + 0, /* Number or reverse hops done yet */ + 1); /* Number of hops done yet */ + } + /* done with all the port groups of this HCA - go to next HCA */ + } + + OSM_LOG_EXIT(&p_ftree->p_osm->log); +} /* 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 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[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", + tuple_to_str(p_sw->tuple), p_sw->base_lid); + + /* set min hop table of the switch to itself */ + sw_set_hops(p_sw, p_sw->base_lid, 0, /* port_num */ + 0, TRUE); /* hops */ + + 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 */ + TRUE, /* whether the target LID is a real or dummy */ + FALSE, /* whether this path to HCA should by tracked by counters */ + TRUE, /* Wheter the target LID is a switch or not */ + 0, /* Number of reverse hops allowed */ + 0, /* Number of reverse hops done yet */ + 0); /* Number of hops done yet */ + } + + OSM_LOG_EXIT(&p_ftree->p_osm->log); +} /* fabric_route_to_switches() */ + +/*************************************************** + ***************************************************/ + +static void fabric_route_roots(IN ftree_fabric_t * p_ftree) +{ + uint16_t lid; + uint8_t port_num; + osm_port_t *p_port; + ftree_sw_t *p_sw; + ftree_sw_t *p_leaf_sw; + + OSM_LOG_ENTER(&p_ftree->p_osm->log); + + /* + * We need a switch that will accomodate all the down/up turns in + * the fabric. Having these turn in a single place in the fabric + * will not create credit loops. + * So we need to select this switch. + * The idea here is to chose leaf with the highest index. I don't + * have any theory to back me up on this. It's just a general thought + * that this way the switch that might be a bottleneck for many mcast + * groups will be far away from the OpenSM, so it will draw the + * multicast traffic away from the SM. + */ + + p_leaf_sw = p_ftree->leaf_switches[p_ftree->leaf_switches_num-1]; + + /* + * Now go over all the switches in the fabric that + * have lower rank, and route the missing LIDs to + * the selected leaf switch. + * In short, this leaf switch now poses a target + * for all those missing LIDs. + */ + + 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 >= p_ftree->leaf_switch_rank) + continue; + + for (lid = 1; lid <= p_leaf_sw->p_osm_sw->max_lid_ho; lid ++) { + + if (p_sw->p_osm_sw->new_lft[lid] != OSM_NO_PATH || + p_leaf_sw->hops[lid] == OSM_NO_PATH) + continue; + + p_port = osm_get_port_by_lid_ho(&p_ftree->p_osm->subn, + lid); + + /* we're interested only in switches */ + if (!p_port || !p_port->p_node->sw) + continue; + + /* + * the missing LID will be routed through the same + * port that routes to the selected leaf switch + */ + port_num = p_sw->p_osm_sw->new_lft[p_leaf_sw->base_lid]; + + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_DEBUG, + "Switch %s: setting path to LID %u " + "through port %u\n", + tuple_to_str(p_sw->tuple), lid, port_num); + + /* set local lft */ + p_sw->p_osm_sw->new_lft[lid] = port_num; + + /* + * Set local min hop table. + * The distance to the target LID is a distance + * to the selected leaf switch plus the distance + * from the leaf to the target LID. + */ + sw_set_hops(p_sw, lid, port_num, + p_sw->hops[p_leaf_sw->base_lid] + + p_leaf_sw->hops[lid], TRUE); + } + } + + OSM_LOG_EXIT(&p_ftree->p_osm->log); +} /* fabric_route_roots() */ + +/***************************************************/ + +static int 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: + fabric_add_hca(p_ftree, p_osm_node); + break; + case IB_NODE_TYPE_ROUTER: + break; + case IB_NODE_TYPE_SWITCH: + 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; +} /* fabric_populate_nodes() */ + +/*************************************************** + ***************************************************/ + +static boolean_t sw_update_rank(IN ftree_sw_t * p_sw, IN uint32_t new_rank) +{ + if (sw_ranked(p_sw) && p_sw->rank <= new_rank) + return FALSE; + p_sw->rank = new_rank; + return TRUE; + +} + +/***************************************************/ + +static void 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 = 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 (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; + +} /* rank_switches_from_leafs() */ + +/***************************************************/ + +static int 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", + 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 = 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 (!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", + hca_get_guid_ho(p_hca), + sw_get_guid_ho(p_sw), 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; +} /* rank_leaf_switches() */ + +/***************************************************/ + +static void 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 +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; + boolean_t is_io = 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 = 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 (!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 { + if (fabric_ios_provided(p_ftree)) { + name_map_item_t *p_elem = (name_map_item_t *) + cl_qmap_get(&p_ftree->io_guid_tbl, + cl_ntoh64 + (osm_physp_get_port_guid + (p_osm_port))); + if (p_elem != (name_map_item_t *) + cl_qmap_end(&p_ftree->io_guid_tbl)) + is_io = TRUE; + + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_DEBUG, + "Marking I/O 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))); + } + } + p_ftree->ca_ports++; + + hca_add_port(p_hca, /* local ftree_hca object */ + i, /* local port number */ + remote_port_num, /* remote port number */ + cl_ntoh16(osm_node_get_base_lid(p_node, i)), /* local lid */ + cl_ntoh16(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, is_io); /* whether this port is compute node */ + } + +Exit: + return res; +} /* fabric_construct_hca_ports() */ + +/*************************************************** + ***************************************************/ + +static int 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; + uint16_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", + sw_get_guid_ho(p_sw), + 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 = + 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 = + cl_ntoh16(osm_physp_get_base_lid + (p_remote_osm_port)); + break; + + case IB_NODE_TYPE_SWITCH: + /* switch connected to another switch */ + + p_remote_sw = + 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 (p_sw->rank > p_remote_sw->rank) { + direction = FTREE_DIRECTION_UP; + } else if (p_sw->rank == p_remote_sw->rank) { + direction = FTREE_DIRECTION_SAME; + } else + direction = FTREE_DIRECTION_DOWN; + + /* switch LID is only in port 0 port_info structure */ + remote_base_lid = + cl_ntoh16(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; + } + 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 (remote_base_lid > p_ftree->lft_max_lid) + p_ftree->lft_max_lid = remote_base_lid; + } + +Exit: + return res; +} /* fabric_construct_sw_ports() */ + +/*************************************************** + ***************************************************/ +struct rank_root_cxt { + ftree_fabric_t *fabric; + cl_list_t *list; +}; + +static int rank_root_sw_by_guid(void *cxt, uint64_t guid, char *p) +{ + struct rank_root_cxt *c = cxt; + ftree_sw_t *sw; + + sw = fabric_get_sw_by_guid(c->fabric, cl_hton64(guid)); + if (!sw) { + /* the specified root guid wasn't found in the fabric */ + OSM_LOG(&c->fabric->p_osm->log, OSM_LOG_ERROR, "ERR AB24: " + "Root switch GUID 0x%" PRIx64 " not found\n", guid); + return 0; + } + + OSM_LOG(&c->fabric->p_osm->log, OSM_LOG_DEBUG, + "Ranking root switch with GUID 0x%" PRIx64 "\n", guid); + sw->rank = 0; + cl_list_insert_tail(c->list, sw); + + return 0; +} + +static int fabric_rank_from_roots(IN ftree_fabric_t * p_ftree) +{ + struct rank_root_cxt context; + 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; + 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 */ + 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); + + context.fabric = p_ftree; + context.list = &ranking_bfs_list; + if (parse_node_map(p_ftree->p_osm->subn.opt.root_guid_file, + rank_root_sw_by_guid, &context)) { + res = -1; + goto Exit; + } + + 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 = 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 (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", + 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; +} /* fabric_rank_from_roots() */ + +/*************************************************** + ***************************************************/ + +static int 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 (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 */ + 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, sw_reverse_rank, (void *)p_ftree); + +Exit: + cl_list_destroy(&ranking_bfs_list); + OSM_LOG_EXIT(&p_ftree->p_osm->log); + return res; +} /* fabric_rank_from_hcas() */ + +/*************************************************** + ***************************************************/ + +static int fabric_rank(IN ftree_fabric_t * p_ftree) +{ + int res = 0; + + OSM_LOG_ENTER(&p_ftree->p_osm->log); + + if (fabric_roots_provided(p_ftree)) + res = fabric_rank_from_roots(p_ftree); + else + res = fabric_rank_from_hcas(p_ftree); + + if (res) + goto Exit; + + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_VERBOSE, + "FatTree max switch rank is %u\n", p_ftree->max_switch_rank); + +Exit: + OSM_LOG_EXIT(&p_ftree->p_osm->log); + return res; +} /* fabric_rank() */ + +/*************************************************** + ***************************************************/ + +static void 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 (!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", + 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", + 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_VERBOSE, + "FatTree leaf switch rank is %u\n", p_ftree->leaf_switch_rank); + OSM_LOG_EXIT(&p_ftree->p_osm->log); +} /* fabric_set_leaf_rank() */ + +/*************************************************** + ***************************************************/ + +static int 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 (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 (fabric_construct_sw_ports(p_ftree, p_sw) != 0) { + res = -1; + goto Exit; + } + } +Exit: + OSM_LOG_EXIT(&p_ftree->p_osm->log); + return res; +} /* fabric_populate_ports() */ + +/*************************************************** + ***************************************************/ +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 fabric_read_guid_files(IN ftree_fabric_t * p_ftree) +{ + int status = 0; + + OSM_LOG_ENTER(&p_ftree->p_osm->log); + + if (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)) { + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_ERROR, + "ERR AB23: " "Problem parsing CN guid file\n"); + status = -1; + goto Exit; + } + + if (!cl_qmap_count(&p_ftree->cn_guid_tbl)) { + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_ERROR, + "ERR AB27: " + "Compute node guids file has no valid guids\n"); + status = -1; + goto Exit; + } + } + + if (fabric_ios_provided(p_ftree)) { + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_DEBUG, + "Fetching I/O nodes from file %s\n", + p_ftree->p_osm->subn.opt.io_guid_file); + + if (parse_node_map(p_ftree->p_osm->subn.opt.io_guid_file, + add_guid_item_to_map, + &p_ftree->io_guid_tbl)) { + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_ERROR, + "ERR AB28: Problem parsing I/O guid file\n"); + status = -1; + goto Exit; + } + + if (!cl_qmap_count(&p_ftree->io_guid_tbl)) { + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_ERROR, + "ERR AB29: " + "I/O node guids file has no valid guids\n"); + status = -1; + goto Exit; + } + } +Exit: + OSM_LOG_EXIT(&p_ftree->p_osm->log); + return status; +} /*fabric_read_guid_files() */ + +/*************************************************** + ***************************************************/ + +static int construct_fabric(IN void *context) +{ + ftree_fabric_t *p_ftree = context; + int status = 0; + + OSM_LOG_ENTER(&p_ftree->p_osm->log); + + fabric_clear(p_ftree); + + if (p_ftree->p_osm->subn.opt.lmc > 0) { + osm_log(&p_ftree->p_osm->log, OSM_LOG_INFO, + "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_INFO, + "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_INFO, + "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 (fabric_populate_nodes(p_ftree) != 0) { + osm_log(&p_ftree->p_osm->log, OSM_LOG_INFO, + "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 (fabric_read_guid_files(p_ftree) != 0) { + osm_log(&p_ftree->p_osm->log, OSM_LOG_INFO, + "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_INFO, + "Fabric has %u CAs - 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 (fabric_rank(p_ftree) != 0) { + osm_log(&p_ftree->p_osm->log, OSM_LOG_INFO, + "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 (fabric_populate_ports(p_ftree) != 0) { + osm_log(&p_ftree->p_osm->log, OSM_LOG_INFO, + "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_INFO, + "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. */ + fabric_set_leaf_rank(p_ftree); + + if (fabric_get_rank(p_ftree) > FAT_TREE_MAX_RANK || + fabric_get_rank(p_ftree) < FAT_TREE_MIN_RANK) { + osm_log(&p_ftree->p_osm->log, OSM_LOG_INFO, + "Fabric rank is %u (should be between %u and %u)\n", + 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 (fabric_mark_leaf_switches(p_ftree)) { + osm_log(&p_ftree->p_osm->log, OSM_LOG_INFO, + "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) */ + 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 (fabric_create_leaf_switch_array(p_ftree)) { + osm_log(&p_ftree->p_osm->log, OSM_LOG_INFO, + "Fabric topology is not a fat-tree\n"); + status = -1; + goto Exit; + } + + /* calculate and set ftree.max_cn_per_leaf field */ + fabric_set_max_cn_per_leaf(p_ftree); + + /* print general info about fabric topology */ + fabric_dump_general_info(p_ftree); + + /* dump full tree topology */ + if (osm_log_is_active(&p_ftree->p_osm->log, OSM_LOG_DEBUG)) + 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 (!fabric_roots_provided(p_ftree) && + !fabric_validate_topology(p_ftree)) { + osm_log(&p_ftree->p_osm->log, OSM_LOG_INFO, + "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); + +Exit: + if (status != 0) { + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_VERBOSE, + "Clearing FatTree Fabric data structures\n"); + 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; +} /* construct_fabric() */ + +/*************************************************** + ***************************************************/ + +static int 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"); + 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"); + 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"); + fabric_route_to_switches(p_ftree); + + if (p_ftree->p_osm->subn.opt.connect_roots) { + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_VERBOSE, + "Connecting switches that are unreachable within " + "Up/Down rules\n"); + fabric_route_roots(p_ftree); + } + + /* for each switch, set its fwd table */ + cl_qmap_apply_func(&p_ftree->sw_tbl, set_sw_fwd_table, (void *)p_ftree); + + /* write out hca ordering file */ + 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 delete(IN void *context) +{ + if (!context) + return; + 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 = fabric_create(); + if (!p_ftree) + return -1; + + p_ftree->p_osm = p_osm; + + r->context = (void *)p_ftree; + r->build_lid_matrices = construct_fabric; + r->ucast_build_fwd_tables = do_routing; + r->delete = delete; + + return 0; +} diff --git a/branches/WOF2-3/ulp/opensm/user/opensm/osm_ucast_lash.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_ucast_lash.c new file mode 100644 index 00000000..f635cfc7 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_ucast_lash.c @@ -0,0 +1,1317 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2009 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. + * Copyright (c) 2008,2009 System Fabric Works, Inc. All rights reserved. + * Copyright (c) 2009 HNR Consulting. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of LASH algorithm Calculation functions + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct _reachable_dest { + int switch_id; + struct _reachable_dest *next; +} reachable_dest_t; + +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]->node->num_links; + switch_t *s1 = p_lash->switches[sw1]; + mesh_node_t *node = s1->node; + switch_t *s2; + link_t *l; + unsigned int i; + + /* + * if doing mesh analysis: + * - do not consider connections to self + * - collapse multiple connections between + * pair of switches to a single locical link + */ + if (p_lash->p_osm->subn.opt.do_mesh_analysis) { + if (sw1 == sw2) + return; + + /* see if we are already linked to sw2 */ + for (i = 0; i < num; i++) { + l = node->links[i]; + + if (node->links[i]->switch_id == sw2) { + l->ports[l->num_ports++] = phy_port_1; + return; + } + } + } + + l = node->links[num]; + l->switch_id = sw2; + l->link_id = -1; + l->ports[l->num_ports++] = phy_port_1; + + s2 = p_lash->switches[sw2]; + for (i = 0; i < s2->node->num_links; i++) { + if (s2->node->links[i]->switch_id == sw1) { + s2->node->links[i]->link_id = num; + l->link_id = i; + break; + } + } + + node->num_links++; + + 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(const 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; +} + +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_deps; i++) { + cycle_found = + cycle_exists(start, current->deps[i].v, current, + new_visit_num); + if (cycle_found == 1) + i = current->num_deps; + } + + current->seen = 1; + if (prev != NULL) + prev->next = NULL; + } + + return cycle_found; +} + +static inline int get_next_switch(lash_t *p_lash, int sw, int link) +{ + return p_lash->switches[sw]->node->links[link]->switch_id; +} + +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 = get_next_switch(p_lash, sw, 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 = get_next_switch(p_lash, i_next_switch, next_link); + found = 0; + + for (i = 0; i < v->num_deps; i++) + if (v->deps[i].v == + cdg_vertex_matrix[lane][i_next_switch] + [i_next_next_switch]) { + found = 1; + depend = i; + } + + CL_ASSERT(found); + + if (v->deps[depend].num_used == 1) { + for (i = depend; + i < v->num_deps - 1; i++) { + v->deps[i].v = v->deps[i + 1].v; + v->deps[i].num_used = + v->deps[i + 1].num_used; + } + + v->num_deps--; + } else + v->deps[depend].num_used--; + } + } + + sw = i_next_switch; + output_link = switches[sw]->routing_table[dest_switch].out_link; + + if (sw != dest_switch) + i_next_switch = get_next_switch(p_lash, sw, 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; + + for (i = 0; i < sw->node->num_links; i++) + if (sw->node->links[i]->switch_id == 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->node->num_links; i++) { + swi = switches[sw->node->links[i]->switch_id]; + if (swi->q_state == UNQUEUED) { + enqueue(&bfsq, swi); + sw->dij_channels[sw->used_channels++] = swi->id; + } + } + } + + cl_list_destroy(&bfsq); +} + +static int 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]; + if (generate_routing_func_for_mst(p_lash, next_switch, &dest)) + return -1; + + 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)); + if (!i_dest) + return -1; + i_dest->switch_id = sw->id; + i_dest->next = concat_dest; + *destinations = i_dest; + return 0; +} + +static int 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 = get_next_switch(p_lash, sw, output_link); + + while (sw != dest_switch) { + + if (cdg_vertex_matrix[lane][sw][next_switch] == NULL) { + v = calloc(1, sizeof(*v) + (num_switches - 1) * sizeof(v->deps[0])); + if (!v) + return -1; + v->from = sw; + v->to = next_switch; + v->temp = 1; + 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_deps; j++) + if (prev->deps[j].v == v) { + exists = 1; + prev->deps[j].num_used++; + } + + if (exists == 0) { + prev->deps[prev->num_deps].v = v; + prev->deps[prev->num_deps].num_used++; + prev->num_deps++; + + CL_ASSERT(prev->num_deps < (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 = get_next_switch(p_lash, sw, output_link); + } + + prev = v; + } + return 0; +} + +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 = get_next_switch(p_lash, sw, 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 = get_next_switch(p_lash, sw, 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 = get_next_switch(p_lash, sw, 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_deps); + v->num_deps = v->num_deps - v->num_temp_depend; + v->num_temp_depend = 0; + v->num_using_vertex--; + + for (i = v->num_deps; i < p_lash->num_switches - 1; i++) + v->deps[i].num_used = 0; + } + + sw = next_switch; + output_link = switches[sw]->routing_table[dest_switch].out_link; + + if (sw != dest_switch) + next_switch = get_next_switch(p_lash, sw, output_link); + + } +} + +static int 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, 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; + unsigned start_vl = p_lash->p_osm->subn.opt.lash_start_vl; + + max_filled_lane = 0; + min_filled_lane = lanes_needed - 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++; + } + } + + if (generate_cdg_for_sp(p_lash, src, dest, min_filled_lane) || + generate_cdg_for_sp(p_lash, dest, src, min_filled_lane)) + return -1; + + output_link = p_lash->switches[src]->routing_table[dest].out_link; + next_switch = get_next_switch(p_lash, src, output_link); + + output_link2 = p_lash->switches[dest]->routing_table[src].out_link; + next_switch2 = get_next_switch(p_lash, dest, 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 + start_vl; + p_lash->switches[dest]->routing_table[src].lane = min_filled_lane + start_vl; + } + + 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; + } + } + return 0; +} + +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) + num_switches * sizeof(sw->routing_table[0])); + if (!sw) + return NULL; + + memset(sw, 0, sizeof(*sw)); + for (i = 0; i < num_switches; i++) { + sw->routing_table[i].out_link = NONE; + sw->routing_table[i].lane = NONE; + } + + sw->id = id; + sw->dij_channels = malloc(num_ports * sizeof(int)); + if (!sw->dij_channels) { + free(sw); + return NULL; + } + + sw->p_sw = p_sw; + p_sw->priv = sw; + + if (osm_mesh_node_create(p_lash, sw)) { + free(sw->dij_channels); + free(sw); + return NULL; + } + + return sw; +} + +static void switch_delete(lash_t *p_lash, switch_t * sw) +{ + if (sw->dij_channels) + free(sw->dij_channels); + free(sw); +} + +static void delete_mesh_switches(lash_t *p_lash) +{ + if (p_lash->switches) { + unsigned id; + for (id = 0; ((int)id) < p_lash->num_switches; id++) + if (p_lash->switches[id]) + osm_mesh_node_delete(p_lash, + p_lash->switches[id]); + } +} + +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); + + delete_mesh_switches(p_lash); + + /* 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]) + 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); + + 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 ****)); + if (p_lash->cdg_vertex_matrix == NULL) + goto Exit_Mem_Error; + 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 */ + memset(p_lash->num_mst_in_lane, 0, + IB_MAX_NUM_VLS * 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 = -1; + int *switch_bitmap = NULL; /* Bitmap to check if we have processed this pair */ + unsigned start_vl = p_lash->p_osm->subn.opt.lash_start_vl; + + OSM_LOG_ENTER(p_log); + + if (p_lash->p_osm->subn.opt.do_mesh_analysis && osm_do_mesh_analysis(p_lash)) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 4D05: Mesh analysis failed\n"); + goto Exit; + } + + for (i = 0; i < num_switches; i++) { + + shortest_path(p_lash, i); + if (generate_routing_func_for_mst(p_lash, i, &dests)) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 4D06: " + "generate_routing_func_for_mst failed\n"); + goto Exit; + } + + 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 = calloc(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; + } + + 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) { + if (generate_cdg_for_sp(p_lash, i, dest_switch, v_lane) || + generate_cdg_for_sp(p_lash, dest_switch, i, v_lane)) { + OSM_LOG(p_log, OSM_LOG_ERROR, + "ERR 4D07: generate_cdg_for_sp failed\n"); + goto Exit; + } + + output_link = + switches[i]->routing_table[dest_switch].out_link; + output_link2 = + switches[dest_switch]->routing_table[i].out_link; + + i_next_switch = get_next_switch(p_lash, i, output_link); + i_next_switch2 = get_next_switch(p_lash, dest_switch, 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 + start_vl; + switches[dest_switch]->routing_table[i].lane = v_lane + start_vl; + + if (cycle_found == 1 || cycle_found2 == 1) { + if (++lanes_needed > p_lash->vl_min) + goto Error_Not_Enough_Lanes; + + if (generate_cdg_for_sp(p_lash, i, dest_switch, v_lane) || + generate_cdg_for_sp(p_lash, dest_switch, i, v_lane)) { + OSM_LOG(p_log, OSM_LOG_ERROR, + "ERR 4D08: generate_cdg_for_sp failed\n"); + goto Exit; + } + + 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; + } + } + + 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]); + + OSM_LOG(p_log, OSM_LOG_INFO, + "Lanes needed: %d, Balancing\n", lanes_needed); + + if (balance_virtual_lanes(p_lash, lanes_needed)) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 4D09: Balancing failed\n"); + goto Exit; + } + + 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]); + + status = 0; + goto Exit; + +Error_Not_Enough_Lanes: + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 4D02: " + "Lane requirements (%d) exceed available lanes (%d)" + " with starting lane (%d)\n", + lanes_needed, p_lash->vl_min, start_vl); +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 int get_next_port(switch_t *sw, int link) +{ + link_t *l = sw->node->links[link]; + int port = l->next_port++; + + /* + * note if not doing mesh analysis + * then num_ports is always 1 + */ + if (l->next_port >= l->num_ports) + l->next_port = 0; + + return l->ports[port]; +} + +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_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 switch 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, p_sw->lft_size); + + for (lid = 1; lid <= max_lid_ho; lid++) { + port = osm_get_port_by_lid_ho(p_subn, 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 = + get_next_port(sw, 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_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, 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, 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 = calloc(p_lash->num_switches, sizeof(switch_t *)); + if (!p_lash->switches) + return -1; + + 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; + + if (p_lash->p_osm->subn.opt.lash_start_vl >= vl_min) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 4D03: " + "Start VL(%d) too high for min operational vl(%d)\n", + p_lash->p_osm->subn.opt.lash_start_vl, vl_min); + return -1; + } + + p_lash->vl_min = vl_min - p_lash->p_osm->subn.opt.lash_start_vl; + + OSM_LOG(p_log, OSM_LOG_INFO, + "min operational vl(%d) start vl(%d) max_switches(%d)\n", + p_lash->vl_min, p_lash->p_osm->subn.opt.lash_start_vl, + 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 switch 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 status = 0; + + OSM_LOG_ENTER(p_log); + + p_lash->balance_limit = 6; + + /* everything starts here */ + lash_cleanup(p_lash); + + status = discover_network_properties(p_lash); + if (status) + goto Exit; + + status = init_lash_structures(p_lash); + if (status) + goto Exit; + + process_switches(p_lash); + + status = lash_core(p_lash); + if (status) + goto Exit; + + populate_fwd_tbls(p_lash); + +Exit: + if (p_lash->vl_min) + free_lash_structures(p_lash); + OSM_LOG_EXIT(p_log); + + return status; +} + +static lash_t *lash_create(osm_opensm_t * p_osm) +{ + lash_t *p_lash; + + p_lash = calloc(1, sizeof(lash_t)); + if (!p_lash) + return NULL; + + 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, p_lash->switches[id]); + free(p_lash->switches); + } + + free(p_lash); +} + +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) +{ + 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 p_osm->subn.opt.lash_start_vl; + + 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/branches/WOF2-3/ulp/opensm/user/opensm/osm_ucast_mgr.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_ucast_mgr.c new file mode 100644 index 00000000..9ccd5832 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_ucast_mgr.c @@ -0,0 +1,1156 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2009 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_ucast_mgr_t. + * This file implements the Unicast Manager object. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void osm_ucast_mgr_construct(IN osm_ucast_mgr_t * p_mgr) +{ + memset(p_mgr, 0, sizeof(*p_mgr)); +} + +void osm_ucast_mgr_destroy(IN osm_ucast_mgr_t * 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 * 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 ucast_mgr_process_hop_0_1(IN cl_map_item_t * p_map_item, + IN void *context) +{ + osm_switch_t * p_sw = (osm_switch_t *) p_map_item; + osm_node_t *p_remote_node; + uint16_t lid, remote_lid; + uint8_t i; + + lid = cl_ntoh16(osm_node_get_base_lid(p_sw->p_node, 0)); + osm_switch_set_hops(p_sw, lid, 0, 0); + + for (i = 1; i < p_sw->num_ports; i++) { + osm_physp_t *p = osm_node_get_physp_ptr(p_sw->p_node, i); + p_remote_node = (p && p->p_remote_physp) ? + p->p_remote_physp->p_node : NULL; + + 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, p->hop_wf); + } + } +} + +static void ucast_mgr_process_neighbor(IN osm_ucast_mgr_t * p_mgr, + IN osm_switch_t * p_this_sw, + IN osm_switch_t * p_remote_sw, + IN uint8_t port_num, + IN uint8_t remote_port_num) +{ + osm_switch_t *p_sw; + cl_map_item_t *item; + uint16_t lid_ho; + uint8_t hops; + osm_physp_t *p; + + 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 = osm_node_get_physp_ptr(p_this_sw->p_node, port_num); + + for (item = cl_qmap_head(&p_mgr->p_subn->sw_guid_tbl); + item != cl_qmap_end(&p_mgr->p_subn->sw_guid_tbl); + item = cl_qmap_next(item)) { + p_sw = (osm_switch_t *) item; + lid_ho = cl_ntoh16(osm_node_get_base_lid(p_sw->p_node, 0)); + hops = osm_switch_get_least_hops(p_remote_sw, lid_ho); + if (hops == OSM_NO_PATH) + continue; + hops += p->hop_wf; + 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, "ERR 3A03: " + "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, + boolean_t dor, 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; + uint8_t rem_port = osm_physp_get_port_num(p->p_remote_physp); + + for (i = 0; i < r->count; i++) + if (r->guids[i].node == node) + if (!dor || (r->guids[i].port == rem_port)) + return &r->guids[i]; + + r->guids[i].node = node; + r->guids[i].forwarded_to = 0; + r->guids[i].port = rem_port; + r->count++; + return &r->guids[i]; +} + +static void ucast_mgr_process_port(IN osm_ucast_mgr_t * p_mgr, + IN osm_switch_t * p_sw, + IN osm_port_t * 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 && !p_mgr->is_dor) + /* 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_mgr->is_dor, + p_port->priv))) + rem_node_used->forwarded_to++; + } + +Exit: + OSM_LOG_EXIT(p_mgr->p_log); +} + +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 ucast_mgr_process_tbl(IN cl_map_item_t * p_map_item, + IN void *context) +{ + osm_ucast_mgr_t *p_mgr = context; + osm_switch_t * 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, p_sw->max_lid_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)) { +#ifndef __WIN__ + osm_port_t *port=cl_item_obj(item, port, list_item); +#else + osm_port_t *port=NULL; // skip uninitialized var err + port = cl_item_obj(item, port, list_item); +#endif + ucast_mgr_process_port(p_mgr, p_sw, port, i); + } + } + + if (p_mgr->p_subn->opt.lmc) + free_ports_priv(p_mgr); + + OSM_LOG_EXIT(p_mgr->p_log); +} + +static void ucast_mgr_process_neighbors(IN cl_map_item_t * p_map_item, + IN void *context) +{ + osm_switch_t * p_sw = (osm_switch_t *) p_map_item; + osm_ucast_mgr_t * p_mgr = 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; + + 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); +} + +static int set_hop_wf(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, hop_wf; + char *e; + + 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, &e, 0)) || (p == e) || + 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; + } + + p = e + 1; + + if (!*p || !(hop_wf = strtoul(p, &e, 0)) || p == e || hop_wf >= 0x100) { + OSM_LOG(m->p_log, OSM_LOG_DEBUG, + "bad hop weight factor specified for guid 0x%016" PRIx64 + "port %u\n", guid, port); + return 0; + } + + physp = osm_node_get_physp_ptr(node, port); + if (!physp) + return 0; + + physp->hop_wf = hop_wf; + + return 0; +} + +static void set_default_hop_wf(cl_map_item_t * 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->hop_wf = 1; + } +} + +static int set_dimn_ports(void *ctx, uint64_t guid, char *p) +{ + osm_subn_t *p_subn = ctx; + osm_node_t *node = osm_get_node_by_guid(p_subn, cl_hton64(guid)); + osm_switch_t *sw; + uint8_t *dimn_ports = NULL; + uint8_t port; + unsigned int *ports = NULL; + const int bpw = sizeof(*ports)*8; + int words; + int i = 1; /* port 0 maps to port 0 */ + + if (!node || !(sw = node->sw)) { + OSM_LOG(&p_subn->p_osm->log, OSM_LOG_VERBOSE, + "switch with guid 0x%016" PRIx64 " is not found\n", + guid); + return 0; + } + + if (sw->dimn_ports) { + OSM_LOG(&p_subn->p_osm->log, OSM_LOG_VERBOSE, + "switch with guid 0x%016" PRIx64 " already listed\n", + guid); + return 0; + } + + dimn_ports = malloc(sizeof(*dimn_ports)*sw->num_ports); + if (!dimn_ports) { + OSM_LOG(&p_subn->p_osm->log, OSM_LOG_ERROR, + "ERR 3A07: cannot allocate memory for dimn_ports\n"); + return -1; + } + memset(dimn_ports, 0, sizeof(*dimn_ports)*sw->num_ports); + + /* the ports array is for record keeping of which ports have + * been seen */ + words = (sw->num_ports + bpw - 1)/bpw; + ports = malloc(words*sizeof(*ports)); + if (!ports) { + OSM_LOG(&p_subn->p_osm->log, OSM_LOG_ERROR, + "ERR 3A08: cannot allocate memory for ports\n"); + return -1; + } + memset(ports, 0, words*sizeof(*ports)); + + while ((*p != '\0') && (*p != '#')) { + char *e; + + port = strtoul(p, &e, 0); + if ((p == e) || (port == 0) || (port >= sw->num_ports) || + !osm_node_get_physp_ptr(node, port)) { + OSM_LOG(&p_subn->p_osm->log, OSM_LOG_VERBOSE, + "bad port %d specified for guid 0x%016" PRIx64 "\n", + port, guid); + free(dimn_ports); + free(ports); + return 0; + } + + if (ports[port/bpw] & (1u << (port%bpw))) { + OSM_LOG(&p_subn->p_osm->log, OSM_LOG_VERBOSE, + "port %d already specified for guid 0x%016" PRIx64 "\n", + port, guid); + free(dimn_ports); + free(ports); + return 0; + } + + ports[port/bpw] |= (1u << (port%bpw)); + dimn_ports[i++] = port; + + p = e; + while (isspace(*p)) { + p++; + } + } + + if (i > 1) { + for (port = 1; port < sw->num_ports; port++) { + /* fill out the rest of the dimn_ports array + * in sequence using the remaining unspecified + * ports. + */ + if (!(ports[port/bpw] & (1u << (port%bpw)))) { + dimn_ports[i++] = port; + } + } + sw->dimn_ports = dimn_ports; + } else { + free(dimn_ports); + } + + free(ports); + return 0; +} + +int osm_ucast_mgr_build_lid_matrices(IN osm_ucast_mgr_t * 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 up the weighting factors for the routing. + */ + cl_qmap_apply_func(p_sw_guid_tbl, set_default_hop_wf, NULL); + if (p_mgr->p_subn->opt.hop_weights_file) { + OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, + "Fetching hop weight factor file \'%s\'\n", + p_mgr->p_subn->opt.hop_weights_file); + if (parse_node_map(p_mgr->p_subn->opt.hop_weights_file, + set_hop_wf, p_mgr)) { + OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, "ERR 3A05: " + "cannot parse hop_weights_file \'%s\'\n", + p_mgr->p_subn->opt.hop_weights_file); + } + } + + /* + 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, 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, + 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; + } + if (p_sw->dimn_ports) { + free(p_sw->dimn_ports); + p_sw->dimn_ports = NULL; + } + } + + if (p_subn->opt.dimn_ports_file) { + OSM_LOG(&p_subn->p_osm->log, OSM_LOG_DEBUG, + "Fetching dimension ports file \'%s\'\n", + p_subn->opt.dimn_ports_file); + if (parse_node_map(p_subn->opt.dimn_ports_file, + set_dimn_ports, p_subn)) { + OSM_LOG(&p_subn->p_osm->log, OSM_LOG_ERROR, "ERR 3A05: " + "cannot parse dimn_ports_file \'%s\'\n", + p_subn->opt.dimn_ports_file); + } + } + + 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 * 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 * 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 void add_sw_endports_to_order_list(osm_switch_t * sw, + osm_ucast_mgr_t * m) +{ + osm_port_t *port; + osm_physp_t *p; + int i; + + for (i = 1; i < sw->num_ports; i++) { + p = osm_node_get_physp_ptr(sw->p_node, i); + if (p && p->p_remote_physp && !p->p_remote_physp->p_node->sw) { + port = osm_get_port_by_guid(m->p_subn, + p->p_remote_physp-> + port_guid); + cl_qlist_insert_tail(&m->port_order_list, + &port->list_item); + port->flag = 1; + } + } +} + +static void sw_count_endport_links(osm_switch_t * sw) +{ + osm_physp_t *p; + int i; + + sw->endport_links = 0; + for (i = 1; i < sw->num_ports; i++) { + p = osm_node_get_physp_ptr(sw->p_node, i); + if (p && p->p_remote_physp && !p->p_remote_physp->p_node->sw) + sw->endport_links++; + } +} + +static int OSM_CDECL compar_sw_load(const void *s1, const void *s2) +{ +#define get_sw_endport_links(s) (*(osm_switch_t **)s)->endport_links + return get_sw_endport_links(s2) - get_sw_endport_links(s1); +} + +static void sort_ports_by_switch_load(osm_ucast_mgr_t * m) +{ + int i, num = cl_qmap_count(&m->p_subn->sw_guid_tbl); + void **s = malloc(num * sizeof(*s)); + if (!s) { + OSM_LOG(m->p_log, OSM_LOG_ERROR, "ERR 3A0C: " + "No memory, skip by switch load sorting.\n"); + return; + } + s[0] = cl_qmap_head(&m->p_subn->sw_guid_tbl); + for (i = 1; i < num; i++) + s[i] = cl_qmap_next(s[i - 1]); + + for (i = 0; i < num; i++) + sw_count_endport_links(s[i]); + + qsort(s, num, sizeof(*s), compar_sw_load); + + for (i = 0; i < num; i++) + add_sw_endports_to_order_list(s[i], m); + free(s); +} + +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 3A0D: " + "cannot parse guid routing order file \'%s\'\n", + p_mgr->p_subn->opt.guid_routing_order_file); + } else + sort_ports_by_switch_load(p_mgr); + + 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 3A0E: " + "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, ucast_mgr_process_tbl, + p_mgr); + + cl_qlist_remove_all(&p_mgr->port_order_list); + + return 0; +} + +static void ucast_mgr_set_fwd_top(IN cl_map_item_t * p_map_item, + IN void *cxt) +{ + osm_ucast_mgr_t *p_mgr = cxt; + osm_switch_t * p_sw = (osm_switch_t *) p_map_item; + 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; + 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); + + if (p_mgr->max_lid < p_sw->max_lid_ho) + p_mgr->max_lid = p_sw->max_lid_ho; + + 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)); + } + + OSM_LOG_EXIT(p_mgr->p_log); +} + +static int set_lft_block(IN osm_switch_t *p_sw, IN osm_ucast_mgr_t *p_mgr, + IN uint16_t block_id_ho) +{ + uint8_t block[IB_SMP_DATA_SIZE]; + osm_madw_context_t context; + osm_dr_path_t *p_path; + ib_api_status_t status; + + /* + Send linear forwarding table blocks to the switch + as long as the switch indicates it has blocks needing + configuration. + */ + 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); + return -1; + } + + p_path = osm_physp_get_dr_path_ptr(osm_node_get_physp_ptr(p_sw->p_node, 0)); + + context.lft_context.node_guid = osm_node_get_node_guid(p_sw->p_node); + context.lft_context.set_method = TRUE; + + if (!osm_switch_get_lft_block(p_sw, block_id_ho, block) || + (!p_sw->need_update && !p_mgr->p_subn->need_update && + !memcmp(block, p_sw->new_lft + block_id_ho * IB_SMP_DATA_SIZE, + IB_SMP_DATA_SIZE))) + return 0; + + OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, + "Writing FT block %u to switch 0x%" PRIx64 "\n", block_id_ho, + cl_ntoh64(context.lft_context.node_guid)); + + status = osm_req_set(p_mgr->sm, p_path, + p_sw->new_lft + block_id_ho * IB_SMP_DATA_SIZE, + IB_SMP_DATA_SIZE, 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)); + return -1; + } + + return 0; +} + +static void ucast_mgr_pipeline_fwd_tbl(osm_ucast_mgr_t * p_mgr) +{ + cl_qmap_t *tbl; + cl_map_item_t *item; + unsigned i, max_block = p_mgr->max_lid / 64 + 1; + + tbl = &p_mgr->p_subn->sw_guid_tbl; + for (i = 0; i < max_block; i++) + for (item = cl_qmap_head(tbl); item != cl_qmap_end(tbl); + item = cl_qmap_next(item)) + set_lft_block((osm_switch_t *)item, p_mgr, i); +} + +void osm_ucast_mgr_set_fwd_tables(osm_ucast_mgr_t * p_mgr) +{ + p_mgr->max_lid = 0; + + cl_qmap_apply_func(&p_mgr->p_subn->sw_guid_tbl, ucast_mgr_set_fwd_top, + p_mgr); + + ucast_mgr_pipeline_fwd_tbl(p_mgr); +} + +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); + + osm_ucast_mgr_set_fwd_tables(&osm->sm.ucast_mgr); + + return 0; +} + +int osm_ucast_mgr_process(IN osm_ucast_mgr_t * 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); + osm_ucast_mgr_set_fwd_tables(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/branches/WOF2-3/ulp/opensm/user/opensm/osm_ucast_updn.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_ucast_updn.c new file mode 100644 index 00000000..e6674889 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_ucast_updn.c @@ -0,0 +1,668 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2007,2009 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Copyright (c) 2009 HNR Consulting. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of Up Down Algorithm using ranking & Min Hop + * Calculation functions + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include + +/* //////////////////////////// */ +/* Local types */ +/* //////////////////////////// */ + +/* direction */ +typedef enum updn_switch_dir { + UP = 0, + DOWN +} updn_switch_dir_t; + +/* updn structure */ +typedef struct updn { + unsigned num_roots; + osm_opensm_t *p_osm; +} updn_t; + +struct updn_node { + cl_list_item_t list; + osm_switch_t *sw; + uint64_t id; + updn_switch_dir_t dir; + unsigned rank; + unsigned visited; +}; + +/* This function returns direction based on rank and guid info of current & + remote ports */ +static updn_switch_dir_t updn_get_dir(unsigned cur_rank, unsigned rem_rank, + uint64_t cur_id, uint64_t rem_id) +{ + /* HACK: comes to solve root nodes connection, in a classic subnet root nodes do not connect + directly, but in case they are we assign to root node an UP direction to allow UPDN to discover + the subnet correctly (and not from the point of view of the last root node). + */ + if (!cur_rank && !rem_rank) + return UP; + + if (cur_rank < rem_rank) + return DOWN; + else if (cur_rank > rem_rank) + return UP; + else { + /* Equal rank, decide by id number, bigger == UP direction */ + if (cur_id > rem_id) + return UP; + else + return DOWN; + } +} + +/********************************************************************** + * This function does the bfs of min hop table calculation by guid index + * as a starting point. + **********************************************************************/ +static int updn_bfs_by_node(IN osm_log_t * p_log, IN osm_subn_t * p_subn, + IN osm_switch_t * p_sw) +{ + uint8_t pn, pn_rem; + cl_qlist_t list; + uint16_t lid; + struct updn_node *u; + updn_switch_dir_t next_dir, current_dir; + + OSM_LOG_ENTER(p_log); + + lid = osm_node_get_base_lid(p_sw->p_node, 0); + lid = cl_ntoh16(lid); + osm_switch_set_hops(p_sw, lid, 0, 0); + + OSM_LOG(p_log, OSM_LOG_DEBUG, + "Starting from switch - port GUID 0x%" PRIx64 " lid %u\n", + cl_ntoh64(p_sw->p_node->node_info.port_guid), lid); + + u = p_sw->priv; + u->dir = UP; + + /* Update list with the new element */ + cl_qlist_init(&list); + cl_qlist_insert_tail(&list, &u->list); + + /* BFS the list till no next element */ + while (!cl_is_qlist_empty(&list)) { + u = (struct updn_node *)cl_qlist_remove_head(&list); + u->visited = 0; /* cleanup */ + current_dir = u->dir; + /* Go over all ports of the switch and find unvisited remote nodes */ + for (pn = 1; pn < u->sw->num_ports; pn++) { + osm_node_t *p_remote_node; + struct updn_node *rem_u; + uint8_t current_min_hop, remote_min_hop, + set_hop_return_value; + osm_switch_t *p_remote_sw; + + p_remote_node = + osm_node_get_remote_node(u->sw->p_node, pn, + &pn_rem); + /* If no remote node OR remote node is not a SWITCH + continue to next pn */ + if (!p_remote_node || !p_remote_node->sw) + continue; + /* Fetch remote guid only after validation of remote node */ + p_remote_sw = p_remote_node->sw; + rem_u = p_remote_sw->priv; + /* Decide which direction to mark it (UP/DOWN) */ + next_dir = updn_get_dir(u->rank, rem_u->rank, + u->id, rem_u->id); + + /* Check if this is a legal step : the only illegal step is going + from DOWN to UP */ + if ((current_dir == DOWN) && (next_dir == UP)) { + OSM_LOG(p_log, OSM_LOG_DEBUG, + "Avoiding move from 0x%016" PRIx64 + " to 0x%016" PRIx64 "\n", + cl_ntoh64(osm_node_get_node_guid(u->sw->p_node)), + cl_ntoh64(osm_node_get_node_guid(p_remote_node))); + /* Illegal step */ + continue; + } + /* Set MinHop value for the current lid */ + current_min_hop = osm_switch_get_least_hops(u->sw, lid); + /* Check hop count if better insert into list && update + the remote node Min Hop Table */ + remote_min_hop = + osm_switch_get_hop_count(p_remote_sw, lid, pn_rem); + if (current_min_hop + 1 < remote_min_hop) { + set_hop_return_value = + osm_switch_set_hops(p_remote_sw, lid, + pn_rem, + current_min_hop + 1); + if (set_hop_return_value) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR AA01: " + "Invalid value returned from set min hop is: %d\n", + set_hop_return_value); + } + /* Check if remote port has already been visited */ + if (!rem_u->visited) { + /* Insert updn_switch item into the list */ + rem_u->dir = next_dir; + rem_u->visited = 1; + cl_qlist_insert_tail(&list, + &rem_u->list); + } + } + } + } + + OSM_LOG_EXIT(p_log); + return 0; +} + +/* NOTE : PLS check if we need to decide that the first */ +/* rank is a SWITCH for BFS purpose */ +static int updn_subn_rank(IN updn_t * p_updn) +{ + osm_switch_t *p_sw; + osm_physp_t *p_physp, *p_remote_physp; + cl_qlist_t list; + cl_map_item_t *item; + struct updn_node *u, *remote_u; + uint8_t num_ports, port_num; + osm_log_t *p_log = &p_updn->p_osm->log; + unsigned max_rank = 0; + + OSM_LOG_ENTER(p_log); + cl_qlist_init(&list); + + /* add all roots to the list */ + for (item = cl_qmap_head(&p_updn->p_osm->subn.sw_guid_tbl); + item != cl_qmap_end(&p_updn->p_osm->subn.sw_guid_tbl); + item = cl_qmap_next(item)) { + p_sw = (osm_switch_t *)item; + u = p_sw->priv; + if (!u->rank) + cl_qlist_insert_tail(&list, &u->list); + } + + /* BFS the list till it's empty */ + while (!cl_is_qlist_empty(&list)) { + u = (struct updn_node *)cl_qlist_remove_head(&list); + /* Go over all remote nodes and rank them (if not already visited) */ + p_sw = u->sw; + num_ports = p_sw->num_ports; + OSM_LOG(p_log, OSM_LOG_DEBUG, + "Handling switch GUID 0x%" PRIx64 "\n", + cl_ntoh64(osm_node_get_node_guid(p_sw->p_node))); + for (port_num = 1; port_num < num_ports; port_num++) { + ib_net64_t port_guid; + + /* Current port fetched in order to get remote side */ + p_physp = + osm_node_get_physp_ptr(p_sw->p_node, port_num); + + if (!p_physp) + continue; + + p_remote_physp = p_physp->p_remote_physp; + + /* + make sure that all the following occur on p_remote_physp: + 1. The port isn't NULL + 2. It is a switch + */ + if (p_remote_physp && p_remote_physp->p_node->sw) { + remote_u = p_remote_physp->p_node->sw->priv; + port_guid = p_remote_physp->port_guid; + + if (remote_u->rank > u->rank + 1) { + remote_u->rank = u->rank + 1; + max_rank = remote_u->rank; + cl_qlist_insert_tail(&list, + &remote_u->list); + OSM_LOG(p_log, OSM_LOG_DEBUG, + "Rank of port GUID 0x%" PRIx64 + " = %u\n", cl_ntoh64(port_guid), + remote_u->rank); + } + } + } + } + + /* Print Summary of ranking */ + OSM_LOG(p_log, OSM_LOG_VERBOSE, + "Subnet ranking completed. Max Node Rank = %d\n", max_rank); + OSM_LOG_EXIT(p_log); + return 0; +} + +/* hack: preserve min hops entries to any other root switches */ +static void updn_clear_non_root_hops(updn_t * updn, osm_switch_t * sw) +{ + osm_port_t *port; + unsigned i; + + for (i = 0; i < sw->num_hops; i++) + if (sw->hops[i]) { + port = osm_get_port_by_lid_ho(&updn->p_osm->subn, i); + if (!port || !port->p_node->sw + || ((struct updn_node *)port->p_node->sw->priv)-> + rank != 0) + memset(sw->hops[i], 0xff, 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_non_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)); + + lid_ho = (uint16_t) cl_ptr_vector_get_size(&p_updn->p_osm->subn.port_lid_tbl) + 1; + cas_per_sw = malloc(lid_ho * 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, lid_ho * 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/branches/WOF2-3/ulp/opensm/user/opensm/osm_vl15intf.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_vl15intf.c new file mode 100644 index 00000000..863120f0 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_vl15intf.c @@ -0,0 +1,366 @@ +/* + * Copyright (c) 2009 Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2006,2009 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_vl15_t. + * This object represents the VL15 Interface object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static void vl15_send_mad(osm_vl15_t * p_vl, osm_madw_t * p_madw) +{ + ib_api_status_t status; + + /* + Non-response-expected mads are not throttled on the wire + since we can have no confirmation that they arrived + at their destination. + */ + if (p_madw->resp_expected == TRUE) + /* + Note that other threads may not see the response MAD + arrive before send() even returns. + In that case, the wire count would temporarily go negative. + To avoid this confusion, preincrement the counts on the + assumption that send() will succeed. + */ + cl_atomic_inc(&p_vl->p_stats->qp0_mads_outstanding_on_wire); + else + cl_atomic_inc(&p_vl->p_stats->qp0_unicasts_sent); + + cl_atomic_inc(&p_vl->p_stats->qp0_mads_sent); + + status = osm_vendor_send(osm_madw_get_bind_handle(p_madw), + p_madw, p_madw->resp_expected); + + if (status == IB_SUCCESS) { + OSM_LOG(p_vl->p_log, OSM_LOG_DEBUG, + "%u QP0 MADs on wire, %u outstanding, " + "%u unicasts sent, %u total sent\n", + p_vl->p_stats->qp0_mads_outstanding_on_wire, + p_vl->p_stats->qp0_mads_outstanding, + p_vl->p_stats->qp0_unicasts_sent, + p_vl->p_stats->qp0_mads_sent); + return; + } + + OSM_LOG(p_vl->p_log, OSM_LOG_ERROR, "ERR 3E03: " + "MAD send failed (%s)\n", ib_get_err_str(status)); + + /* + The MAD was never successfully sent, so + fix up the pre-incremented count values. + */ + + /* Decrement qp0_mads_sent that were incremented in the code above. + qp0_mads_outstanding will be decremented by send error callback + (called by osm_vendor_send() */ + cl_atomic_dec(&p_vl->p_stats->qp0_mads_sent); + if (!p_madw->resp_expected) + cl_atomic_dec(&p_vl->p_stats->qp0_unicasts_sent); +} + +static void vl15_poller(IN void *p_ptr) +{ + ib_api_status_t status; + osm_madw_t *p_madw; + osm_vl15_t *p_vl = 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 * 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 * 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 * p_vl, IN osm_vendor_t * p_vend, + IN osm_log_t * p_log, IN osm_stats_t * p_stats, + IN 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, vl15_poller, p_vl, + "opensm poller"); +Exit: + OSM_LOG_EXIT(p_log); + return status; +} + +void osm_vl15_poll(IN osm_vl15_t * 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 * p_vl, IN osm_madw_t * 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 = %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 * p_vl, IN osm_mad_pool_t * 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/branches/WOF2-3/ulp/opensm/user/opensm/osm_vl_arb_rcv.c b/branches/WOF2-3/ulp/opensm/user/opensm/osm_vl_arb_rcv.c new file mode 100644 index 00000000..37e30bd1 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/osm_vl_arb_rcv.c @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2004-2009 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) 2010 HNR Consulting. All rights reserved. + * Copyright (c) 2010 Sun Microsystems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_vla_rcv_t. + * This object represents the Vl Arbitration Receiver object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * WE 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_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) { + 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 care 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; + } + + 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_dump_vl_arb_table(sm->p_log, port_guid, block_num, port_num, + p_vla_tbl, OSM_LOG_DEBUG); + 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/branches/WOF2-3/ulp/opensm/user/opensm/st.c b/branches/WOF2-3/ulp/opensm/user/opensm/st.c new file mode 100644 index 00000000..676b1c23 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/st.c @@ -0,0 +1,584 @@ +/* + * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2006 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* static char sccsid[] = "@(#) st.c 5.1 89/12/14 Crucible"; */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +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(void) +{ + FILE *f = fopen(OSM_DEFAULT_TMP_DIR "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/branches/WOF2-3/ulp/opensm/user/opensm/vendor-ibal.inc b/branches/WOF2-3/ulp/opensm/user/opensm/vendor-ibal.inc new file mode 100644 index 00000000..85a2dcec --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/vendor-ibal.inc @@ -0,0 +1,5 @@ +# Vendor IBAL +VENDOR_LIBS=$(LIBPATH)\*\osmv_ibal.lib +VENDOR_LIBSD=$(VENDOR_LIBS) +VENDOR_IF=OSM_VENDOR_INTF_AL + diff --git a/branches/WOF2-3/ulp/opensm/user/opensm/vendor-umad.inc b/branches/WOF2-3/ulp/opensm/user/opensm/vendor-umad.inc new file mode 100644 index 00000000..f6460da8 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/opensm/vendor-umad.inc @@ -0,0 +1,15 @@ +# Vendor umad + +VENDOR_INC= $(WINIBHOME)\ulp\libibmad\include; \ + $(WINIBHOME)\ulp\libibumad\include; + +VENDOR_LIBS=$(TARGETPATH)\*\osmv_openib.lib \ + $(LIBPATH)\*\libibmad.lib \ + $(LIBPATH)\*\libibumad.lib + +VENDOR_LIBSD=$(TARGETPATH)\*\osmv_openib.lib \ + $(LIBPATH)\*\libibmadd.lib \ + $(LIBPATH)\*\libibumadd.lib + +VENDOR_IF=OSM_VENDOR_INTF_OPENIB + diff --git a/branches/WOF2-3/ulp/opensm/user/osmeventplugin/libosmeventplugin.map b/branches/WOF2-3/ulp/opensm/user/osmeventplugin/libosmeventplugin.map new file mode 100644 index 00000000..15bf29a9 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/osmeventplugin/libosmeventplugin.map @@ -0,0 +1,5 @@ +OSMPMDB_1.0 { + global: + osm_event_plugin; + local: *; +}; diff --git a/branches/WOF2-3/ulp/opensm/user/osmeventplugin/libosmeventplugin.ver b/branches/WOF2-3/ulp/opensm/user/osmeventplugin/libosmeventplugin.ver new file mode 100644 index 00000000..c463efc2 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/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/branches/WOF2-3/ulp/opensm/user/osmeventplugin/src/osmeventplugin.c b/branches/WOF2-3/ulp/opensm/user/osmeventplugin/src/osmeventplugin.c new file mode 100644 index 00000000..24618785 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/osmeventplugin/src/osmeventplugin.c @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2007 The Regents of the University of California. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** ========================================================================= + * This is a simple example plugin which logs some of the events the OSM + * generates to this interface. + */ +#define SAMPLE_PLUGIN_OUTPUT_FILE "/tmp/osm_sample_event_plugin_output" +typedef struct _log_events { + FILE *log_file; + osm_log_t *osmlog; +} _log_events_t; + +/** ========================================================================= + */ +static void *construct(osm_opensm_t *osm) +{ + _log_events_t *log = malloc(sizeof(*log)); + if (!log) + return (NULL); + + log->log_file = fopen(SAMPLE_PLUGIN_OUTPUT_FILE, "a+"); + + if (!(log->log_file)) { + osm_log(&osm->log, OSM_LOG_ERROR, + "Sample Event Plugin: Failed to open output file \"%s\"\n", + SAMPLE_PLUGIN_OUTPUT_FILE); + free(log); + return (NULL); + } + + log->osmlog = &osm->log; + return ((void *)log); +} + +/** ========================================================================= + */ +static void destroy(void *_log) +{ + _log_events_t *log = (_log_events_t *) _log; + fclose(log->log_file); + free(log); +} + +/** ========================================================================= + */ +static void handle_port_counter(_log_events_t * log, osm_epi_pe_event_t * pc) +{ + if (pc->symbol_err_cnt > 0 + || pc->link_err_recover > 0 + || pc->link_downed > 0 + || pc->rcv_err > 0 + || pc->rcv_rem_phys_err > 0 + || pc->rcv_switch_relay_err > 0 + || pc->xmit_discards > 0 + || pc->xmit_constraint_err > 0 + || pc->rcv_constraint_err > 0 + || pc->link_integrity > 0 + || pc->buffer_overrun > 0 || pc->vl15_dropped > 0) { + fprintf(log->log_file, + "Port counter errors for node 0x%" PRIx64 + " (%s) port %d\n", pc->port_id.node_guid, + pc->port_id.node_name, pc->port_id.port_num); + } +} + +/** ========================================================================= + */ +static void +handle_port_counter_ext(_log_events_t * log, osm_epi_dc_event_t * epc) +{ + fprintf(log->log_file, + "Recieved Data counters for node 0x%" PRIx64 " (%s) port %d\n", + epc->port_id.node_guid, + epc->port_id.node_name, epc->port_id.port_num); +} + +/** ========================================================================= + */ +static void handle_port_select(_log_events_t * log, osm_epi_ps_event_t * ps) +{ + if (ps->xmit_wait > 0) { + fprintf(log->log_file, + "Port select Xmit Wait counts for node 0x%" PRIx64 + " (%s) port %d\n", ps->port_id.node_guid, + ps->port_id.node_name, ps->port_id.port_num); + } +} + +/** ========================================================================= + */ +static void handle_trap_event(_log_events_t *log, ib_mad_notice_attr_t *p_ntc) +{ + if (ib_notice_is_generic(p_ntc)) { + fprintf(log->log_file, + "Generic trap type %d; event %d; from LID 0x%x\n", + ib_notice_get_type(p_ntc), + cl_ntoh16(p_ntc->g_or_v.generic.trap_num), + cl_ntoh16(p_ntc->issuer_lid)); + } else { + fprintf(log->log_file, + "Vendor trap type %d; from LID 0x%x\n", + ib_notice_get_type(p_ntc), + cl_ntoh16(p_ntc->issuer_lid)); + } + +} + +/** ========================================================================= + */ +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, (ib_mad_notice_attr_t *) event_data); + break; + case OSM_EVENT_ID_SUBNET_UP: + fprintf(log->log_file, "Subnet up reported\n"); + break; + case OSM_EVENT_ID_MAX: + default: + osm_log(log->osmlog, OSM_LOG_ERROR, + "Unknown event (%d) reported to plugin\n", event_id); + } + fflush(log->log_file); +} + +/** ========================================================================= + * 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/branches/WOF2-3/ulp/opensm/user/osmtest/Makefile b/branches/WOF2-3/ulp/opensm/user/osmtest/Makefile new file mode 100644 index 00000000..b8c9cc35 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/osmtest/Makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the Windows NT DDK +# + +!INCLUDE ..\..\..\..\inc\openib.def diff --git a/branches/WOF2-3/ulp/opensm/user/osmtest/SOURCES b/branches/WOF2-3/ulp/opensm/user/osmtest/SOURCES new file mode 100644 index 00000000..1027e8d7 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/osmtest/SOURCES @@ -0,0 +1,71 @@ +TARGETNAME=osmtest + +!if !defined(WINIBHOME) +WINIBHOME=..\..\..\.. +!endif + +LIBPATH=$(WINIBHOME)\bin\user\obj$(BUILD_ALT_DIR) + +!if defined(OSM_TARGET) +TARGETPATH=$(OSM_TARGET)\bin\user\obj$(BUILD_ALT_DIR) +!else +TARGETPATH=$(WINIBHOME)\bin\user\obj$(BUILD_ALT_DIR) +!endif + +!include ..\mad-vendor.inc + +TARGETTYPE=PROGRAM +UMTYPE=console +USE_MSVCRT=1 +OVR_DIR=..\addon + + +SOURCES=osmtest.rc \ + osmt_files.c \ + osmt_slvl_vl_arb.c \ + osmt_service.c \ + osmt_multicast.c \ + osmt_inform.c \ + osmtest.c \ + main.c + +OSM_HOME=.. + +TARGETLIBS=\ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ +!if $(FREEBUILD) + $(VENDOR_LIBS) \ + $(LIBPATH)\*\ibal.lib \ + $(LIBPATH)\*\complib.lib +!else + $(VENDOR_LIBSD) \ + $(LIBPATH)\*\ibald.lib \ + $(LIBPATH)\*\complibd.lib +!endif + + +INCLUDES= \ + $(WINIBHOME)\inc; \ + $(WINIBHOME)\inc\user; \ + $(WINIBHOME)\inc\user\linux; \ + $(VENDOR_INC) \ + $(OSM_HOME); \ + $(OSM_HOME)\osmtest\include; \ + $(OSM_HOME)\include; + +# Could be any special flag needed for this project +USER_C_FLAGS=$(USER_C_FLAGS) /MD + +#Add preproccessor definitions + +C_DEFINES=$(C_DEFINES) -D__WIN__ -D$(VENDOR_IF) -DHAVE_CONFIG_H + +!if !$(FREEBUILD) +#C_DEFINES=$(C_DEFINES) -D_DEBUG -DDEBUG -DDBG +C_DEFINES=$(C_DEFINES) +!endif + +LINKER_FLAGS= $(LINKER_FLAGS) +MSC_WARNING_LEVEL= /W3 /wd4007 /wd4090 + diff --git a/branches/WOF2-3/ulp/opensm/user/osmtest/include/osmt_inform.h b/branches/WOF2-3/ulp/opensm/user/osmtest/include/osmt_inform.h new file mode 100644 index 00000000..4bae63a9 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/osmtest/include/osmt_inform.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef __OSMT_INFORM__ +#define __OSMT_INFORM__ + +#ifdef OSM_VENDOR_INTF_MTL +#include +#include +#include "osmt_mtl_regular_qp.h" +#endif + +typedef struct _osmt_qp_ctx { +#ifdef OSM_VENDOR_INTF_MTL + osmt_mtl_mad_res_t qp_bind_hndl; +#endif + uint8_t *p_send_buf; + uint8_t *p_recv_buf; +#ifdef OSM_VENDOR_INTF_MTL + IB_MGT_mad_hndl_t ib_mgt_qp0_handle; +#endif +} osmt_qp_ctx_t; + +ib_api_status_t +osmt_bind_inform_qp(IN osmtest_t * const p_osmt, OUT osmt_qp_ctx_t * p_qp_ctx); + +void +osmt_unbind_inform_qp(IN osmtest_t * const p_osmt, IN osmt_qp_ctx_t * p_qp_ctx); + +ib_api_status_t +osmt_reg_unreg_inform_info(IN osmtest_t * p_osmt, + IN osmt_qp_ctx_t * p_qp_ctx, + IN ib_inform_info_t * p_inform_info, + IN uint8_t reg_flag); + +ib_api_status_t +osmt_trap_wait(IN osmtest_t * const p_osmt, IN osmt_qp_ctx_t * p_qp_ctx); + +ib_api_status_t +osmt_init_inform_info(IN osmtest_t * const p_osmt, OUT ib_inform_info_t * p_ii); + +ib_api_status_t +osmt_init_inform_info_by_trap(IN osmtest_t * const p_osmt, + IN ib_net16_t trap_num, + OUT ib_inform_info_t * p_ii); + +#endif /* __OSMT_INFORM__ */ diff --git a/branches/WOF2-3/ulp/opensm/user/osmtest/include/osmt_mtl_regular_qp.h b/branches/WOF2-3/ulp/opensm/user/osmtest/include/osmt_mtl_regular_qp.h new file mode 100644 index 00000000..b9136e69 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/osmtest/include/osmt_mtl_regular_qp.h @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2001-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * mad.h - + * Header file for common special QP resources creation code. + * + * Creation date: + * + * Version: osmt_mtl_regular_qp.h,v 1.2 2003/03/20 16:05:10 eitan + * + * Authors: + * Elazar Raab + * + * Changes: + */ + +#ifndef H_MAD_H +#define H_MAD_H + +#include +#include +#include +#include + +#if defined(MAD_IN) || defined(MAD_OUT) +#error MACROS MAD_IN and MAD_OUT are in use, do not override +#endif +#define MAD_IN +#define MAD_OUT + +/* HCA Constants */ +#define HCA_ID "mt21108_pci0" +#define GRH_LEN 40 +#define KNOWN_QP1_QKEY 0x80010000 + +#define MAX_OUTS_SQ 2 /* Max. buffers posted for requests in SQ */ +#define MAX_OUTS_RQ 5 /* Max. buffers posted for responses in RQ */ + +#define MAX_POLL_CNT 300 +#define POLL_SLEEP 1 /* for usleep */ + +#define MAD_SIZE 256 /* MADs are always 256B */ +#define MAD_ATTR_OFFSET 16 +#define MAD_TID_OFFSET 8 + +/* Verbs SQP resources handles */ +typedef struct { + VAPI_hca_id_t hca_id; /*id of HCA */ + u_int8_t port_num; /* the port num to use */ + VAPI_hca_hndl_t hca_hndl; /*handle of HCA */ + VAPI_qp_hndl_t qp_hndl; /*handle of QP I use */ + VAPI_mr_hndl_t mr_hndl; /*handle of memory region */ + VAPI_cq_hndl_t rq_cq_hndl, sq_cq_hndl; /*handle of send & receive completion Queues */ + VAPI_pd_hndl_t pd_hndl; /*handle of Partition Domain */ + /* VAPI_ud_av_hndl_t av_hndl; */ + IB_lid_t slid; + /*LID*/ void *buf_ptr; /*mem buffer for outstanding pkts */ + MT_size_t buf_size; /*size of mem buffer for outstanding pkts */ + + u_int32_t max_outs_sq; /*max # of outstanding pkts in send queue */ + u_int32_t max_outs_rq; /*max # of outstanding pkts in receive queue */ + + IB_rkey_t l_key; /*my l_key for memory regions */ + VAPI_qkey_t qkey; /*my qkey */ + + EVAPI_compl_handler_hndl_t rq_cq_eventh, sq_cq_eventh; /* event handlers for polling */ + + bool is_sqp; /* relate to union below - my QP */ + union { + VAPI_special_qp_t sqp_type; + VAPI_qp_num_t qp_num; + } qp_id; + void *wait_q; +} osmt_mtl_mad_res_t; + +/* init an osmt_mtl_mad_res_t with all resources initialized (use functions below) */ +VAPI_ret_t osmt_mtl_init(osmt_mtl_mad_res_t * res /*pointer to res (resources) struct */ + ); +VAPI_ret_t osmt_mtl_init_opened_hca(osmt_mtl_mad_res_t * res /*pointer to res (resources) struct */ + ); + +/* Cleanup all resources of (which are valid) in res */ +VAPI_ret_t osmt_mtl_mad_cleanup(osmt_mtl_mad_res_t * res /*pointer to res (resources) struct */ + ); + +/* create CQs and QP as given in res->is_sqp (if TRUE, get special QP) */ +VAPI_ret_t osmt_mtl_get_qp_resources(osmt_mtl_mad_res_t * res /*pointer to res (resources) struct */ + ); + +/* move QP to RTS state */ +VAPI_ret_t osmt_mtl_mad_qp_init(osmt_mtl_mad_res_t * res /*max number of outstanding packets allowed in send queue */ + ); + +/* create and register res->buf_ptr */ +VAPI_ret_t osmt_mtl_mad_create_mr(osmt_mtl_mad_res_t * res /*pointer to res (resources) struct */ + ); + +VAPI_ret_t osmt_mtl_create_av(osmt_mtl_mad_res_t * res, /* pointer to res (resources) struct */ + int16_t dlid, /*destination lid */ + VAPI_ud_av_hndl_t * avh_p /* address vectr handle to update */ + ); + +/* Send MAD to given dest QP*/ +VAPI_ret_t osmt_mtl_mad_send(osmt_mtl_mad_res_t * res, /*pointer to res (resources) struct */ + VAPI_wr_id_t id, /*wqe ID */ + void *mad, /*mad buffer to send */ + VAPI_qp_num_t dest_qp, /*destination QP */ + IB_sl_t sl, /*Service Level */ + u_int32_t dest_qkey, /*Destination QP KEY */ + VAPI_ud_av_hndl_t avh /* address vectr handle to use */ + ); + +/* post buffers to RQ. returns num of buffers actually posted */ +int osmt_mtl_mad_post_recv_bufs(osmt_mtl_mad_res_t * res, /*pointer to res (resources) struct */ + void *buf_array, /*array of receive buffers */ + u_int32_t num_o_bufs, /*number of receive buffers */ + u_int32_t size, /* size of expected receive packet - MAD */ + VAPI_wr_id_t start_id /* start id for receive buffers */ + ); + +/* Poll given CQ for completion max_poll times (POLL_SLEEP [usec] delays). result in wc_desc_p. */ +VAPI_ret_t osmt_mtl_mad_poll4cqe(VAPI_hca_hndl_t hca, /*handle for HCA */ + VAPI_cq_hndl_t cq, /*handle for Completion Queue - Rcv/Send */ + VAPI_wc_desc_t * wc_desc_p, /*handle of cqe */ + u_int32_t max_poll, /*number of polling iterations */ + u_int32_t poll_sleep, /*timeout for each polling */ + VAPI_ud_av_hndl_t * avh_p /* address vectopr handle to cleanup */ + ); + +#endif diff --git a/branches/WOF2-3/ulp/opensm/user/osmtest/include/osmtest.h b/branches/WOF2-3/ulp/opensm/user/osmtest/include/osmtest.h new file mode 100644 index 00000000..e0d63b0a --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/osmtest/include/osmtest.h @@ -0,0 +1,510 @@ +/* + * Copyright (c) 2006 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osmtest_t. + * This object represents the OSMTest Test object. + * + */ + +#ifndef _OSMTEST_H_ +#define _OSMTEST_H_ + +#include +#include +#include +#include +#include +#include +#include "osmtest_base.h" +#include "osmtest_subnet.h" + +enum OSMT_FLOWS { + OSMT_FLOW_ALL = 0, + OSMT_FLOW_CREATE_INVENTORY, + OSMT_FLOW_VALIDATE_INVENTORY, + OSMT_FLOW_SERVICE_REGISTRATION, + OSMT_FLOW_EVENT_FORWARDING, + OSMT_FLOW_STRESS_SA, + OSMT_FLOW_MULTICAST, + OSMT_FLOW_QOS, + OSMT_FLOW_TRAP, +}; + +/****s* OpenSM: Subnet/osmtest_opt_t + * NAME + * osmtest_opt_t + * + * DESCRIPTION + * Subnet options structure. This structure contains the various + * site specific configuration parameters for osmtest. + * + * SYNOPSIS + */ +typedef struct _osmtest_opt { + uint32_t transaction_timeout; + boolean_t force_log_flush; + boolean_t create; + uint32_t retry_count; + uint32_t stress; + uint32_t mmode; + char file_name[OSMTEST_FILE_PATH_MAX]; + uint8_t flow; + uint8_t wait_time; + char *log_file; + boolean_t ignore_path_records; +} osmtest_opt_t; + +/* + * FIELDS + * + * SEE ALSO + *********/ + +/****h* OSMTest/OSMTest + * NAME + * OSMTest + * + * DESCRIPTION + * The OSMTest object tests an SM/SA for conformance to a known + * set of data about an Infiniband subnet. + * + * AUTHOR + * Steve King, Intel + * + *********/ + +/****s* OSMTest/osmtest_t + * NAME + * osmtest_t + * + * DESCRIPTION + * OSMTest structure. + * + * This object should be treated as opaque and should + * be manipulated only through the provided functions. + * + * SYNOPSIS + */ +typedef struct _osmtest { + osm_log_t log; + struct _osm_vendor *p_vendor; + osm_bind_handle_t h_bind; + osm_mad_pool_t mad_pool; + + osmtest_opt_t opt; + ib_port_attr_t local_port; + subnet_t exp_subn; + cl_qpool_t node_pool; + cl_qpool_t port_pool; + cl_qpool_t link_pool; + + uint16_t max_lid; +} osmtest_t; + +/* + * FIELDS + * log + * Log facility used by all OSMTest components. + * + * p_vendor + * Pointer to the vendor transport layer. + * + * h_bind + * The bind handle obtained by osm_vendor_sa_api/osmv_bind_sa + * + * mad_pool + * The mad pool provided for teh vendor layer to allocate mad wrappers in + * + * opt + * osmtest options structure + * + * local_port + * Port attributes for the port over which osmtest is running. + * + * exp_subn + * Subnet object representing the expected subnet + * + * node_pool + * Pool of objects for use in populating the subnet databases. + * + * port_pool + * Pool of objects for use in populating the subnet databases. + * + * link_pool + * Pool of objects for use in populating the subnet databases. + * + * SEE ALSO + *********/ + +/****s* OpenSM: Subnet/osmtest_req_context_t + * NAME + * osmtest_req_context_t + * + * DESCRIPTION + * Query context for ib_query callback function. + * + * SYNOPSIS + */ +typedef struct _osmtest_req_context { + osmtest_t *p_osmt; + osmv_query_res_t result; +} osmtest_req_context_t; + +typedef struct _osmtest_mgrp_t { + cl_map_item_t map_item; + ib_member_rec_t mcmember_rec; +} osmtest_mgrp_t; + +/* + * FIELDS + * + * SEE ALSO + *********/ + +/****f* OSMTest/osmtest_construct + * NAME + * osmtest_construct + * + * DESCRIPTION + * This function constructs an OSMTest object. + * + * SYNOPSIS + */ +void osmtest_construct(IN osmtest_t * const p_osmt); + +/* + * PARAMETERS + * p_osmt + * [in] Pointer to a OSMTest object to construct. + * + * RETURN VALUE + * This function does not return a value. + * + * NOTES + * Allows calling osmtest_init, osmtest_destroy. + * + * Calling osmtest_construct is a prerequisite to calling any other + * method except osmtest_init. + * + * SEE ALSO + * SM object, osmtest_init, osmtest_destroy + *********/ + +/****f* OSMTest/osmtest_destroy + * NAME + * osmtest_destroy + * + * DESCRIPTION + * The osmtest_destroy function destroys an osmtest object, releasing + * all resources. + * + * SYNOPSIS + */ +void osmtest_destroy(IN osmtest_t * const p_osmt); + +/* + * PARAMETERS + * p_osmt + * [in] Pointer to a OSMTest object to destroy. + * + * RETURN VALUE + * This function does not return a value. + * + * NOTES + * Performs any necessary cleanup of the specified OSMTest object. + * Further operations should not be attempted on the destroyed object. + * This function should only be called after a call to osmtest_construct or + * osmtest_init. + * + * SEE ALSO + * SM object, osmtest_construct, osmtest_init + *********/ + +/****f* OSMTest/osmtest_init + * NAME + * osmtest_init + * + * DESCRIPTION + * The osmtest_init function initializes a OSMTest object for use. + * + * SYNOPSIS + */ +ib_api_status_t osmtest_init(IN osmtest_t * const p_osmt, + IN const osmtest_opt_t * const p_opt, + IN const osm_log_level_t log_flags); + +/* + * PARAMETERS + * p_osmt + * [in] Pointer to an osmtest_t object to initialize. + * + * p_opt + * [in] Pointer to the options structure. + * + * log_flags + * [in] Log level flags to set. + * + * RETURN VALUES + * IB_SUCCESS if the OSMTest object was initialized successfully. + * + * NOTES + * Allows calling other OSMTest methods. + * + * SEE ALSO + * SM object, osmtest_construct, osmtest_destroy + *********/ + +/****f* OSMTest/osmtest_run + * NAME + * osmtest_run + * + * DESCRIPTION + * Runs the osmtest suite. + * + * SYNOPSIS + */ +ib_api_status_t osmtest_run(IN osmtest_t * const p_osmt); + +/* + * PARAMETERS + * p_osmt + * [in] Pointer to an osmtest_t object. + * + * guid + * [in] Port GUID over which to run the test suite. + * + * RETURN VALUES + * IB_SUCCESS + * + * NOTES + * + * SEE ALSO + *********/ + +/****f* OSMTest/osmtest_bind + * NAME + * osmtest_bind + * + * DESCRIPTION + * Binds osmtest to a local port. + * + * SYNOPSIS + */ +ib_api_status_t osmtest_bind(IN osmtest_t * p_osmt, + IN uint16_t max_lid, IN ib_net64_t guid OPTIONAL); + +/* + * PARAMETERS + * p_osmt + * [in] Pointer to an osmtest_t object. + * + * max_lid + * [in] The maximal lid to query about (if RMPP is not supported) + * + * guid + * [in] Port GUID over which to run the test suite. + * If zero, the bind function will display a menu of local + * port guids and wait for user input. + * + * RETURN VALUES + * IB_SUCCESS + * + * NOTES + * + * SEE ALSO + *********/ + +/****f* OSMTest/osmtest_query_res_cb + * NAME + * osmtest_query_res_cb + * + * DESCRIPTION + * A Callback for the query to invoke on completion + * + * SYNOPSIS + */ +void osmtest_query_res_cb(IN osmv_query_res_t * p_rec); +/* + * PARAMETERS + * p_rec + * [in] Pointer to an ib_query_rec_t object used for the query. + * + * RETURN VALUES + * NONE + * + * NOTES + * + * SEE ALSO + *********/ + +/****f* OSMTest/ib_get_mad_status_str + * NAME + * ib_get_mad_status_str + * + * DESCRIPTION + * return the string representing the given mad status + * + * SYNOPSIS + */ +const char *ib_get_mad_status_str(IN const ib_mad_t * const p_mad); +/* + * PARAMETERS + * p_mad + * [in] Pointer to the mad payload + * + * RETURN VALUES + * NONE + * + * NOTES + * + * SEE ALSO + *********/ + +/****f* OSMTest/osmt_run_service_records_flow + * NAME + * osmt_run_service_records_flow + * + * DESCRIPTION + * Run the service record testing flow. + * + * SYNOPSIS + */ +ib_api_status_t osmt_run_service_records_flow(IN osmtest_t * const p_osmt); +/* + * PARAMETERS + * p_osmt + * [in] Pointer to the osmtest obj + * + * RETURN VALUES + * IB_SUCCESS if PASS + * + * NOTES + * + * SEE ALSO + *********/ + +ib_api_status_t osmt_run_inform_info_flow(IN osmtest_t * const p_osmt); + +/****f* OSMTest/osmt_run_slvl_and_vlarb_records_flow + * NAME + * osmt_run_slvl_and_vlarb_records_flow + * + * DESCRIPTION + * Run the sl2vl and vlarb tables testing flow. + * + * SYNOPSIS + */ +ib_api_status_t +osmt_run_slvl_and_vlarb_records_flow(IN osmtest_t * const p_osmt); +/* + * PARAMETERS + * p_osmt + * [in] Pointer to the osmtest obj + * + * RETURN VALUES + * IB_SUCCESS if PASS + * + * NOTES + * + * SEE ALSO + *********/ + +/****f* OSMTest/osmt_run_mcast_flow + * NAME + * osmt_run_mcast_flow + * + * DESCRIPTION + * Run the multicast test flow + * + * SYNOPSIS + */ +ib_api_status_t osmt_run_mcast_flow(IN osmtest_t * const p_osmt); +/* + * PARAMETERS + * p_osmt + * [in] Pointer to the osmtest obj + * + * RETURN VALUES + * IB_SUCCESS if PASS + * + * NOTES + * + * SEE ALSO + *********/ + +/****f* OSMTest/osmt_run_trap64_65_flow + * NAME + * osmt_run_trap64_65_flow + * + * DESCRIPTION + * Run the trap 64/65 test flow. This test is ran with + * an outside tool. + * + * SYNOPSIS + */ +ib_api_status_t osmt_run_trap64_65_flow(IN osmtest_t * const p_osmt); +/* + * PARAMETERS + * p_osmt + * [in] Pointer to the osmtest obj + * + * RETURN VALUES + * IB_SUCCESS if PASS + * + * NOTES + * + * SEE ALSO + *********/ + +ib_api_status_t +osmtest_get_all_recs(IN osmtest_t * const p_osmt, + IN ib_net16_t const attr_id, + IN size_t const attr_size, + IN OUT osmtest_req_context_t * const p_context); + +ib_api_status_t +osmtest_get_local_port_lmc(IN osmtest_t * const p_osmt, + IN ib_net16_t lid, OUT uint8_t * const p_lmc); + +/* + * A few auxiliary macros for logging + */ + +#define EXPECTING_ERRORS_START "[[ ===== Expecting Errors - START ===== " +#define EXPECTING_ERRORS_END " ===== Expecting Errors - END ===== ]]" + +#endif /* _OSMTEST_H_ */ diff --git a/branches/WOF2-3/ulp/opensm/user/osmtest/include/osmtest_base.h b/branches/WOF2-3/ulp/opensm/user/osmtest/include/osmtest_base.h new file mode 100644 index 00000000..00749705 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/osmtest/include/osmtest_base.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osmtest_t. + * This object represents the OSMTest Test object. + * + */ +#ifndef _OSMTEST_BASE_H_ +#define _OSMTEST_BASE_H_ + +#ifndef __WIN__ +#include +#else +#include +#endif + +#define OSMTEST_MAX_LINE_LEN 120 +#define OSMTEST_FILE_PATH_MAX PATH_MAX + +#define STRESS_SMALL_RMPP_THR 100000 +/* + Take long times when querying 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 +#define STRESS_GET_PR 100000 + +extern const char *const p_file; + +#endif /* _OSMTEST_BASE_H_ */ diff --git a/branches/WOF2-3/ulp/opensm/user/osmtest/include/osmtest_subnet.h b/branches/WOF2-3/ulp/opensm/user/osmtest/include/osmtest_subnet.h new file mode 100644 index 00000000..dfd92016 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/osmtest/include/osmtest_subnet.h @@ -0,0 +1,326 @@ +/* + * Copyright (c) 2006 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osmtest_t. + * This object represents the OSMTest Test object. + * + */ + +#ifndef _OSMTEST_SUBNET_H_ +#define _OSMTEST_SUBNET_H_ + +#include +#include +#include +#include +#include +#include + +/****s* Subnet Database/generic_t +* NAME +* generic_t +* +* DESCRIPTION +* Subnet database object for fields common to all record types. +* All other database types must be castable to this type. +* +* SYNOPSIS +*/ +typedef struct _generic { + cl_map_item_t map_item; /* must be first element! */ + uint32_t count; /* must be second element! */ +} generic_t; + +/* +* FIELDS +* +* SEE ALSO +*********/ + +/****s* Subnet Database/node_t +* NAME +* node_t +* +* DESCRIPTION +* Subnet database object for nodes. +* Must be castable to generic_t. +* +* SYNOPSIS +*/ +typedef struct _node { + cl_map_item_t map_item; /* must be first element! */ + uint32_t count; /* must be second element! */ + ib_node_record_t rec; + ib_node_record_t comp; +} node_t; + +/* +* FIELDS +* map_item +* Provides linkage for the qmap container. +* +* rec +* NodeRecord for this node as read from the database file. +* +* comp +* NodeRecord indicating which fields should be compared against rec. +* Bits set in the comp NodeRecord indicate that bit in the rec structure +* should be compared against real-time data from the SA. +* +* count +* Utility counter used by the validation logic. Typically used to +* to indicate the number of times a matching node was received from +* the SA. +* +* SEE ALSO +*********/ + +static inline node_t *node_new(void) +{ + node_t *p_obj; + + p_obj = malloc(sizeof(*p_obj)); + if (p_obj) + memset(p_obj, 0, sizeof(*p_obj)); + return (p_obj); +} + +static inline void node_delete(IN node_t * p_obj) +{ + free(p_obj); +} + +/****s* Subnet Database/port_t +* NAME +* port_t +* +* DESCRIPTION +* Subnet database object for ports. +* Must be castable to generic_t. +* +* SYNOPSIS +*/ +typedef struct _port { + cl_map_item_t map_item; /* must be first element! */ + uint32_t count; /* must be second element! */ + /* Since there is no unique identifier for all ports we + must be able to have such a key by the lid and port num */ + uint64_t port_id; + ib_portinfo_record_t rec; + ib_portinfo_record_t comp; +} port_t; + +/* +* FIELDS +* +* map_item +* Provides linkage for the qmap container. +* +* rec +* PortInfoRecord for this port as read from the database file. +* +* comp +* PortInfoRecord indicating which fields should be compared against rec. +* Bits set in the comp NodeRecord indicate that bit in the rec structure +* should be compared against real-time data from the SA. +* +* count +* Utility counter used by the validation logic. Typically used to +* to indicate the number of times a matching node was received from +* the SA. +* +* SEE ALSO +*********/ + +static inline port_t *port_new(void) +{ + port_t *p_obj; + + p_obj = malloc(sizeof(*p_obj)); + if (p_obj) + memset(p_obj, 0, sizeof(*p_obj)); + return (p_obj); +} + +static inline void port_delete(IN port_t * p_obj) +{ + free(p_obj); +} + +static inline uint64_t +port_gen_id(IN ib_net16_t const lid, IN uint8_t const port_num) +{ + return (lid << 8 | port_num); +} + +static inline void +port_ext_id(IN uint64_t id, IN ib_net16_t * p_lid, IN uint8_t * p_port_num) +{ + CL_ASSERT((id & 0xFF) < 0x100); + *p_port_num = (uint8_t) (id & 0xFF); + CL_ASSERT(((id >> 8) & 0xFFFF) < 0x10000); + *p_lid = (uint16_t) ((id >> 8) & 0xFFFF); +} + +static inline void +port_set_id(IN port_t * p_obj, + IN ib_net16_t const lid, IN uint8_t const port_num) +{ + p_obj->port_id = port_gen_id(lid, port_num); +} + +static inline void +port_get_id(IN port_t * p_obj, IN ib_net16_t * p_lid, IN uint8_t * p_port_num) +{ + port_ext_id(p_obj->port_id, p_lid, p_port_num); +} + +/****s* Subnet Database/path_t +* NAME +* node_t +* +* DESCRIPTION +* Subnet database object for paths. +* Must be castable to generic_t. +* +* SYNOPSIS +*/ +typedef struct _path { + cl_map_item_t map_item; /* must be first element! */ + uint32_t count; /* must be second element! */ + ib_path_rec_t rec; + ib_path_rec_t comp; +} path_t; + +/* +* FIELDS +* map_item +* Provides linkage for the qmap container. +* +* rec +* PathRecord for this path as read from the database file. +* +* comp +* PathRecord indicating which fields should be compared against rec. +* Bits set in the comp PathRecord indicate that bit in the rec structure +* should be compared against real-time data from the SA. +* +* count +* Utility counter used by the validation logic. Typically used to +* to indicate the number of times a matching node was received from +* the SA. +* +* SEE ALSO +*********/ + +static inline path_t *path_new(void) +{ + path_t *p_obj; + + p_obj = malloc(sizeof(*p_obj)); + if (p_obj) + memset(p_obj, 0, sizeof(*p_obj)); + return (p_obj); +} + +static inline void path_delete(IN path_t * p_obj) +{ + free(p_obj); +} + +/****s* Subnet Database/subnet_t +* NAME +* subnet_t +* +* DESCRIPTION +* Subnet database object. +* +* SYNOPSIS +*/ +typedef struct _subnet { + cl_qmap_t node_lid_tbl; + cl_qmap_t node_guid_tbl; + cl_qmap_t mgrp_mlid_tbl; + /* cl_qmap_t port_lid_tbl; */ + /* cl_qmap_t port_guid_tbl; */ + cl_qmap_t port_key_tbl; + cl_qmap_t link_tbl; + cl_qmap_t path_tbl; +} subnet_t; + +/* +* FIELDS +* +* SEE ALSO +*********/ + +/****f* Subnet Database/subnet_construct +* NAME +* subnet_construct +* +* DESCRIPTION +* This function constructs an subnet database object. +* This function cannot fail. +* +* SYNOPSIS +*/ +void subnet_construct(IN subnet_t * const p_subn); + +/* +* FIELDS +* +* SEE ALSO +*********/ + +/****f* Subnet Database/subnet_init +* NAME +* subnet_init +* +* DESCRIPTION +* This function initializes an subnet database object. +* +* SYNOPSIS +*/ +cl_status_t subnet_init(IN subnet_t * const p_subn); + +/* +* FIELDS +* +* SEE ALSO +*********/ + +#endif diff --git a/branches/WOF2-3/ulp/opensm/user/osmtest/main.c b/branches/WOF2-3/ulp/opensm/user/osmtest/main.c new file mode 100644 index 00000000..a8f41fe3 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/osmtest/main.c @@ -0,0 +1,622 @@ +/* + * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 2009 HNR Consulting. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Command line interface for osmtest. + * + */ + +#include +#include +#include +#include +#include "osmtest.h" + +/******************************************************************** + D E F I N E G L O B A L V A R I A B L E S +*********************************************************************/ + +/* + This is the global osmtest object. + One osmtest object is required per subnet. + Future versions could support multiple subents by + instantiating more than one osmtest object. +*/ +#define MAX_LOCAL_IBPORTS 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() +{ + printf + ("\n------- osmtest - Usage and options ----------------------\n"); + printf("Usage: osmtest [options]\n"); + printf("Options:\n"); + printf("-f \n" + "--flow \n" + " This option directs osmtest to run a specific flow:\n" + " FLOW DESCRIPTION\n" + " c = create an inventory file with all nodes, ports and paths\n" + " a = run all validation tests (expecting an input inventory)\n" + " v = only validate the given inventory file\n" + " s = run service registration, deregistration, and lease test\n" + " e = run event forwarding test\n" + " f = flood the SA with queries according to the stress mode\n" + " m = multicast flow\n" + " q = QoS info: dump VLArb and SLtoVL tables\n" + " t = run trap 64/65 flow (this flow requires running of external tool)\n" + " (default is all flows except QoS)\n\n"); + + printf("-w \n" + "--wait \n" + " This option specifies the wait time for trap 64/65 in seconds\n" + " It is used only when running -f t - the trap 64/65 flow\n" + " (default to 10 sec)\n\n"); + printf("-d \n" + "--debug \n" + " This option specifies a debug option\n" + " These options are not normally needed\n" + " The number following -d selects the debug\n" + " option to enable as follows:\n" + " OPT Description\n" + " --- -----------------\n" + " -d0 - Unused.\n" + " -d1 - Do not scan/compare path records.\n" + " -d2 - Force log flushing after each log message.\n" + " Without -d, no debug options are enabled\n\n"); + printf("-m \n" + "--max_lid \n" + " This option specifies the maximal LID number to be searched\n" + " for during inventory file build (default to 100)\n\n"); + printf("-g \n" + "--guid \n" + " This option specifies the local port GUID value\n" + " with which osmtest should bind. osmtest may be\n" + " bound to 1 port at a time\n\n"); + printf("-p \n" + "--port\n" + " This option displays a menu of possible local port GUID values\n" + " with which osmtest could bind\n\n"); + printf("-h\n" + "--help\n" " Display this usage info then exit\n\n"); + printf("-i \n" + "--inventory \n" + " This option specifies the name of the inventory file\n" + " Normally, osmtest expects to find an inventory file,\n" + " which osmtest uses to validate real-time information\n" + " received from the SA during testing\n" + " If -i is not specified, osmtest defaults to the file\n" + " 'osmtest.dat'\n" + " See -c option for related information\n\n"); + printf("-s\n" + "--stress\n" + " This option runs the specified stress test instead\n" + " of the normal test suite\n" + " Stress test options are as follows:\n" + " OPT Description\n" + " --- -----------------\n" + " -s1 - Single-MAD (RMPP) response SA queries\n" + " -s2 - Multi-MAD (RMPP) response SA queries\n" + " -s3 - Multi-MAD (RMPP) Path Record SA queries\n" + " -s4 - Single-MAD (non RMPP) get Path Record SA queries\n" + " Without -s, stress testing is not performed\n\n"); + printf("-M\n" + "--Multicast_Mode\n" + " This option specify length of Multicast test:\n" + " OPT Description\n" + " --- -----------------\n" + " -M1 - Short Multicast Flow (default) - single mode\n" + " -M2 - Short Multicast Flow - multiple mode\n" + " -M3 - Long Multicast Flow - single mode\n" + " -M4 - Long Multicast Flow - multiple mode\n" + " Single mode - Osmtest is tested alone, with no other\n" + " apps that interact with OpenSM MC\n" + " Multiple mode - Could be run with other apps using MC with\n" + " OpenSM." + " Without -M, default flow testing is performed\n\n"); + + printf("-t \n" + " This option specifies the time in milliseconds\n" + " used for transaction timeouts\n" + " Specifying -t 0 disables timeouts\n" + " Without -t, osmtest defaults to a timeout value of\n" + " 1 second\n\n"); + printf("-l\n" + "--log_file\n" + " This option defines the log to be the given file\n" + " By default the log goes to stdout\n\n"); + printf("-v\n" + " This option increases the log verbosity level\n" + " The -v option may be specified multiple times\n" + " to further increase the verbosity level\n" + " See the -vf option for more information about.\n" + " log verbosity\n\n"); + printf("-V\n" + " This option sets the maximum verbosity level and\n" + " forces log flushing\n" + " The -V is equivalent to '-vf 0xFF -d 2'\n" + " See the -vf option for more information about.\n" + " log verbosity\n\n"); + printf("-vf \n" + " This option sets the log verbosity level\n" + " A flags field must follow the -vf option\n" + " A bit set/clear in the flags enables/disables a\n" + " specific log level as follows:\n" + " BIT LOG LEVEL ENABLED\n" + " ---- -----------------\n" + " 0x01 - ERROR (error messages)\n" + " 0x02 - INFO (basic messages, low volume)\n" + " 0x04 - VERBOSE (interesting stuff, moderate volume)\n" + " 0x08 - DEBUG (diagnostic, high volume)\n" + " 0x10 - FUNCS (function entry/exit, very high volume)\n" + " 0x20 - FRAMES (dumps all SMP and GMP frames)\n" + " 0x40 - currently unused\n" + " 0x80 - currently unused\n" + " Without -vf, osmtest defaults to ERROR + INFO (0x3)\n" + " Specifying -vf 0 disables all messages\n" + " Specifying -vf 0xFF enables all messages (see -V)\n" + " High verbosity levels may require increasing\n" + " the transaction timeout with the -t option\n\n"); +} + +static void print_all_guids(IN osmtest_t * p_osmt) +{ + ib_api_status_t status; + uint32_t num_ports = MAX_LOCAL_IBPORTS; + ib_port_attr_t attr_array[MAX_LOCAL_IBPORTS] = { {0} }; + uint32_t 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 = MAX_LOCAL_IBPORTS; + ib_port_attr_t attr_array[MAX_LOCAL_IBPORTS] = { {0} }; + uint32_t 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 = +#ifdef __WIN__ + "?" +#endif + "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 = (uint16_t) 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; + case 4: + printf("SA Get Path Record 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; + +#ifdef __WIN__ + case '?': +#endif + 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/branches/WOF2-3/ulp/opensm/user/osmtest/osmt_files.c b/branches/WOF2-3/ulp/opensm/user/osmtest/osmt_files.c new file mode 100644 index 00000000..65b6bcb0 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/osmtest/osmt_files.c @@ -0,0 +1,11 @@ + +/* + * Supply missing files/routines for Windows osmtest build. + * Point being to minimize mods to other OFED/opensm files... + */ + +void OsmReportState(const char *p_str) { } + +#include <..\opensm\osm_log.c> +#include <..\opensm\osm_mad_pool.c> +#include <..\opensm\osm_helper.c> diff --git a/branches/WOF2-3/ulp/opensm/user/osmtest/osmt_inform.c b/branches/WOF2-3/ulp/opensm/user/osmtest/osmt_inform.c new file mode 100644 index 00000000..a28c0051 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/osmtest/osmt_inform.c @@ -0,0 +1,767 @@ +/* + * Copyright (c) 2006-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifdef OSM_VENDOR_INTF_MTL +/* + * Abstract: + * Implementation of InformInfo testing flow.. + * Top level is osmt_run_inform_info_flow: + * osmt_bind_inform_qp + * osmt_reg_unreg_inform_info + * osmt_send_trap_wait_for_forward + * + */ + +#include +#include +#include +#include +#include +#include +#include "osmtest.h" +#include "osmt_inform.h" + +/* + * Prepare an asynchronous QP (rcv) for sending inform info and + * handling the incoming reports. + * + */ +ib_api_status_t +osmt_bind_inform_qp(IN osmtest_t * const p_osmt, OUT osmt_qp_ctx_t * p_qp_ctx) +{ + ib_net64_t port_guid; + VAPI_hca_hndl_t hca_hndl; + VAPI_hca_id_t hca_id; + uint32_t port_num; + VAPI_ret_t vapi_ret; + IB_MGT_ret_t mgt_ret; + uint8_t hca_index; + osm_log_t *p_log = &p_osmt->log; + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER(p_log); + + port_guid = p_osmt->local_port.port_guid; + + OSM_LOG(p_log, OSM_LOG_DEBUG, "Binding to port 0x%" PRIx64 "\n", + cl_ntoh64(port_guid)); + + /* obtain the hca name and port num from the guid */ + OSM_LOG(p_log, OSM_LOG_DEBUG, + "Finding CA and Port that owns port guid 0x%" PRIx64 "\n", + port_guid); + + mgt_ret = + osm_vendor_get_guid_ca_and_port(p_osmt->p_vendor, + port_guid, + &hca_hndl, + &hca_id[0], &hca_index, &port_num); + if (mgt_ret != IB_MGT_OK) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0109: " + "Unable to obtain CA and port (%d).\n"); + status = IB_ERROR; + goto Exit; + } +#define OSMT_MTL_REVERSE_QP1_WELL_KNOWN_Q_KEY 0x80010000 + + strncpy(p_qp_ctx->qp_bind_hndl.hca_id, hca_id, sizeof(hca_id)); + p_qp_ctx->qp_bind_hndl.hca_hndl = hca_hndl; + p_qp_ctx->qp_bind_hndl.port_num = port_num; + p_qp_ctx->qp_bind_hndl.max_outs_sq = 10; + p_qp_ctx->qp_bind_hndl.max_outs_rq = 10; + p_qp_ctx->qp_bind_hndl.qkey = OSMT_MTL_REVERSE_QP1_WELL_KNOWN_Q_KEY; + + vapi_ret = osmt_mtl_init_opened_hca(&p_qp_ctx->qp_bind_hndl); + if (vapi_ret != VAPI_OK) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0114: " + "Error initializing QP.\n"); + status = IB_ERROR; + goto Exit; + } + + /* we use the pre-allocated buffers for send and receive : + send from buf[0] + receive from buf[2] + */ + p_qp_ctx->p_send_buf = + (uint8_t *) p_qp_ctx->qp_bind_hndl.buf_ptr + GRH_LEN; + p_qp_ctx->p_recv_buf = + (uint8_t *) p_qp_ctx->qp_bind_hndl.buf_ptr + 2 * (GRH_LEN + + MAD_BLOCK_SIZE); + + /* Need to clear assigned memory of p_send_buf - before using it to send any data */ + memset(p_qp_ctx->p_send_buf, 0, MAD_BLOCK_SIZE); + + status = IB_SUCCESS; + OSM_LOG(p_log, OSM_LOG_DEBUG, "Initialized QP:0x%X in VAPI Mode\n", + p_qp_ctx->qp_bind_hndl.qp_id); + + OSM_LOG(p_log, OSM_LOG_DEBUG, "Binding to IB_MGT SMI\n"); + + /* we also need a QP0 handle for sending packets */ + mgt_ret = IB_MGT_get_handle(hca_id, port_num, IB_MGT_SMI, + &(p_qp_ctx->ib_mgt_qp0_handle)); + if (IB_MGT_OK != mgt_ret) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0115: " + "Error obtaining IB_MGT handle to SMI\n"); + status = IB_ERROR; + goto Exit; + } + +Exit: + OSM_LOG_EXIT(p_log); + return status; +} + +/* + * Close the QP + */ +void +osmt_unbind_inform_qp(IN osmtest_t * const p_osmt, IN osmt_qp_ctx_t * p_qp_ctx) +{ + osm_log_t *p_log = &p_osmt->log; + + OSM_LOG_ENTER(p_log); + + osmt_mtl_mad_cleanup(&p_qp_ctx->qp_bind_hndl); + + IB_MGT_release_handle(p_qp_ctx->ib_mgt_qp0_handle); + + OSM_LOG(p_log, OSM_LOG_DEBUG, "Unbind QP handles\n"); + OSM_LOG_EXIT(&p_osmt->log); +} + +/* + * Register/Unregister to receive the given InformInfo + * + * Uses the qp context to send the inform info mad. + * Wait for GetResp(InformInfoResp) + * + */ +ib_api_status_t +osmt_reg_unreg_inform_info(IN osmtest_t * p_osmt, + IN osmt_qp_ctx_t * p_qp_ctx, + IN ib_inform_info_t * p_inform_info, + IN uint8_t reg_flag) +{ + ib_sa_mad_t *p_sa_mad = (ib_sa_mad_t *) (p_qp_ctx->p_send_buf); + ib_inform_info_t *p_ii = ib_sa_mad_get_payload_ptr(p_sa_mad); /* SA Payload */ + VAPI_ret_t vapi_ret; + VAPI_wc_desc_t wc_desc; + VAPI_ud_av_hndl_t avh; + static VAPI_wr_id_t wrid = 16198; + osm_log_t *p_log = &p_osmt->log; + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER(&p_osmt->log); + + /* init the MAD */ + ib_mad_init_new((ib_mad_t *) p_sa_mad, + IB_MCLASS_SUBN_ADM, + (uint8_t) 2, + IB_MAD_METHOD_SET, cl_hton64(wrid), (ib_net16_t) 0, 0); + wrid++; + p_sa_mad->attr_id = IB_MAD_ATTR_INFORM_INFO; + + /* copy the reference inform info */ + memcpy(p_ii, p_inform_info, sizeof(ib_inform_info_t)); + + if (reg_flag) { + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Subscribing InformInfo: Traps from lid:0x%X to 0x%X, trap num :0x%X\n", + p_ii->lid_range_begin, p_ii->lid_range_end, + p_ii->g_or_v.generic.trap_num); + } else { + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "UnSubscribing InformInfo: Traps from lid:0x%X to 0x%X\n", + p_ii->lid_range_begin, p_ii->lid_range_end); + } + + /* set the subscribe bit */ + if (reg_flag) { + p_ii->subscribe = 1; + } else { + p_ii->subscribe = 0; + /* + * we need to set the QPN on the mad if we unsubscribe: + * o13-2.1.1 - QPN Field need to be set when unsubscribing. + */ + ib_inform_info_set_qpn(p_ii, + cl_hton32(p_qp_ctx->qp_bind_hndl.qp_id. + qp_num)); + } + + osm_dump_inform_info(&p_osmt->log, p_ii, OSM_LOG_DEBUG); + + /* --------------------- PREP ------------------------- */ + if (osmt_mtl_mad_post_recv_bufs(&p_qp_ctx->qp_bind_hndl, p_qp_ctx->p_recv_buf, 1, /* but we need only one mad at a time */ + GRH_LEN + MAD_BLOCK_SIZE, wrid) != 1) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0120: " + "Error posting recv bufs\n"); + status = IB_ERROR; + goto Exit; + } + OSM_LOG(p_log, OSM_LOG_DEBUG, "Posted recv bufs\n"); + + vapi_ret = + osmt_mtl_create_av(&p_qp_ctx->qp_bind_hndl, + p_osmt->local_port.sm_lid, &avh); + if (vapi_ret != VAPI_OK) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0121: " + "Error Preparing AVH (%s)\n", + VAPI_strerror_sym(vapi_ret)); + status = IB_ERROR; + goto Exit; + } + OSM_LOG(p_log, OSM_LOG_DEBUG, "Prepared AVH\n"); + + if (osm_log_is_active(p_log, OSM_LOG_DEBUG)) { + osm_dump_sa_mad(p_log, (ib_sa_mad_t *) (p_qp_ctx->p_send_buf), + OSM_LOG_DEBUG); +#if 0 + for (i = 56; i < 253; i++) { + if (i % 8 == 0) { + printf("\n %d : ", i); + } + printf("0x%02X ", p_qp_ctx->p_send_buf[i]); + } +#endif + printf("\n"); + } + + /* --------------------- SEND ------------------------- */ + vapi_ret = osmt_mtl_mad_send(&p_qp_ctx->qp_bind_hndl, wrid, p_qp_ctx->p_send_buf, 1, /* SA is QP1 */ + 0, /* SL is 0 */ + OSMT_MTL_REVERSE_QP1_WELL_KNOWN_Q_KEY, + avh); + if (vapi_ret != VAPI_OK) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0122: " + "Error sending mad (%s)\n", + VAPI_strerror_sym(vapi_ret)); + status = IB_ERROR; + goto Exit; + } + + vapi_ret = osmt_mtl_mad_poll4cqe(p_qp_ctx->qp_bind_hndl.hca_hndl, + p_qp_ctx->qp_bind_hndl.sq_cq_hndl, + &wc_desc, 20, 10000, NULL); + if (vapi_ret != VAPI_OK) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0123: " + "Error getting send completion (%s)\n", + VAPI_strerror_sym(vapi_ret)); + status = IB_ERROR; + goto Exit; + } + + if (wc_desc.status != VAPI_SUCCESS) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0124: " + "Error on send completion (%s) (%d)\n", + VAPI_strerror_sym(wc_desc.status), wc_desc.status); + status = IB_ERROR; + goto Exit; + } + OSM_LOG(p_log, OSM_LOG_DEBUG, "Sent MAD\n"); + + /* --------------------- RECV ------------------------- */ + vapi_ret = osmt_mtl_mad_poll4cqe(p_qp_ctx->qp_bind_hndl.hca_hndl, + p_qp_ctx->qp_bind_hndl.rq_cq_hndl, + &wc_desc, 20, 10000, &avh); + if (vapi_ret != VAPI_SUCCESS) { + if (vapi_ret == VAPI_CQ_EMPTY) { + status = IB_TIMEOUT; + } else { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0125: " + "Error receiving mad (%s)\n", + VAPI_strerror_sym(vapi_ret)); + status = IB_ERROR; + } + goto Exit; + } + + /* check to see if successful - by examination of the subscribe bit */ + p_sa_mad = (ib_sa_mad_t *) (p_qp_ctx->p_recv_buf + GRH_LEN); + + if (p_sa_mad->status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "Remote error = %s\n", + ib_get_mad_status_str((ib_mad_t *) p_sa_mad)); + status = IB_REMOTE_ERROR; + goto Exit; + } + + if (p_sa_mad->method != IB_MAD_METHOD_GET_RESP) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "Expected IB_MAD_METHOD_GET_RESP but got:(%X)\n", + p_sa_mad->method); + status = IB_REMOTE_ERROR; + goto Exit; + } + + if (p_sa_mad->attr_id != IB_MAD_ATTR_INFORM_INFO) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "Expected IB_MAD_ATTR_INFORM_INFO but got:(%X)\n", + cl_ntoh16(p_sa_mad->attr_id)); + status = IB_REMOTE_ERROR; + goto Exit; + } + + p_ii = ib_sa_mad_get_payload_ptr(p_sa_mad); + if (!p_ii->subscribe) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0126: " + "Subscribe/Unsubscribe Failed\n"); + status = IB_REMOTE_ERROR; + } + +Exit: + OSM_LOG_EXIT(&p_osmt->log); + return status; +} + +/* + * Send a trap (Subn LID Route) Trap(Notice) through the regular + * connection QP connection (targeted at QP0) + * + * Wait for the trap repress + */ +ib_api_status_t +osmt_send_trap_wait_for_forward(IN osmtest_t * const p_osmt, + IN osmt_qp_ctx_t * p_qp_ctx) +{ + ib_smp_t *p_smp = (ib_smp_t *) (p_qp_ctx->p_send_buf); + ib_mad_notice_attr_t *p_ntc = ib_smp_get_payload_ptr(p_smp); + ib_sa_mad_t *p_sa_mad; + IB_MGT_ret_t mgt_res; + VAPI_ret_t vapi_ret; + VAPI_wc_desc_t wc_desc; + VAPI_ud_av_hndl_t avh; + IB_ud_av_t av; + static VAPI_wr_id_t wrid = 2222; + osm_log_t *p_log = &p_osmt->log; + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER(p_log); + + OSM_LOG(p_log, OSM_LOG_INFO, + "Sending Traps to QP0 of SA LID:0x%X\n", + p_osmt->local_port.sm_lid); + + /* init the MAD */ + memset(p_smp, 0, sizeof(ib_smp_t)); + ib_mad_init_new((ib_mad_t *) p_smp, + IB_MCLASS_SUBN_LID, + (uint8_t) 2, + IB_MAD_METHOD_TRAP, cl_hton64(wrid), (ib_net16_t) 0, 0); + + wrid++; + p_smp->attr_id = IB_MAD_ATTR_NOTICE; + + /* prepare the notice */ + p_ntc->generic_type = 0x82; /* generic, type = 2 */ + ib_notice_set_prod_type_ho(p_ntc, 1); + p_ntc->g_or_v.generic.trap_num = cl_hton16(0x26); + p_ntc->issuer_lid = cl_hton16(2); + + /* --------------------- PREP ------------------------- */ + if (osmt_mtl_mad_post_recv_bufs(&p_qp_ctx->qp_bind_hndl, p_qp_ctx->p_recv_buf, 1, /* we need to receive both trap repress and report */ + GRH_LEN + MAD_BLOCK_SIZE, wrid) != 1) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0127: " + "Error posting recv bufs\n"); + status = IB_ERROR; + goto Exit; + } + OSM_LOG(p_log, OSM_LOG_DEBUG, "Posted recv bufs\n"); + + av.dlid = p_osmt->local_port.sm_lid; + av.grh_flag = FALSE; + + /* EZ: returned in HACK: use constants */ + av.static_rate = 0; /* p_mad_addr->static_rate; */ + av.src_path_bits = 1; /* p_mad_addr->path_bits; */ + av.sl = 0; /* p_mad_addr->addr_type.gsi.service_level; */ + + OSM_LOG(p_log, OSM_LOG_DEBUG, + "av.dlid 0x%X, av.static_rate %d, av.path_bits %d\n", + cl_ntoh16(av.dlid), av.static_rate, av.src_path_bits); + + /* send it */ + mgt_res = IB_MGT_send_mad(p_qp_ctx->ib_mgt_qp0_handle, p_smp, /* actual payload */ + &av, /* address vector */ + wrid, /* casting the mad wrapper pointer for err cb */ + p_osmt->opt.transaction_timeout); + if (mgt_res != IB_MGT_OK) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0128: " + "Error sending mad (%d)\n", mgt_res); + status = IB_ERROR; + goto Exit; + } + + vapi_ret = + osmt_mtl_create_av(&p_qp_ctx->qp_bind_hndl, + p_osmt->local_port.sm_lid, &avh); + if (vapi_ret != VAPI_OK) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0129: " + "Error Preparing AVH (%s)\n", + VAPI_strerror_sym(vapi_ret)); + status = IB_ERROR; + goto Exit; + } + OSM_LOG(p_log, OSM_LOG_DEBUG, "Prepared AVH\n"); + + OSM_LOG(p_log, OSM_LOG_DEBUG, "Trap MAD Sent\n"); + + /* --------------------- RECV ------------------------- */ + vapi_ret = osmt_mtl_mad_poll4cqe(p_qp_ctx->qp_bind_hndl.hca_hndl, + p_qp_ctx->qp_bind_hndl.rq_cq_hndl, + &wc_desc, 200, 10000, &avh); + if (vapi_ret != VAPI_SUCCESS) { + if (vapi_ret == VAPI_CQ_EMPTY) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0130: " + "Timeout receiving mad (%s)\n", + VAPI_strerror_sym(vapi_ret)); + status = IB_TIMEOUT; + } else { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0131: " + "Error receiving mad (%s)\n", + VAPI_strerror_sym(vapi_ret)); + status = IB_ERROR; + } + goto Exit; + } + + /* check to see if successful - by examination of the subscribe bit */ + p_sa_mad = (ib_sa_mad_t *) (p_qp_ctx->p_recv_buf + GRH_LEN); + + if (p_sa_mad->method == IB_MAD_METHOD_REPORT) { + if (p_sa_mad->attr_id == IB_MAD_ATTR_NOTICE) { + OSM_LOG(p_log, OSM_LOG_INFO, "Received the Report!\n"); + status = IB_SUCCESS; + } else { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 1020" + "Did not receive a Report(Notice) but attr:%d\n", + cl_ntoh16(p_sa_mad->attr_id)); + status = IB_ERROR; + } + } else { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 1020" + "Received an Unexpected Method:%d\n", p_smp->method); + status = IB_ERROR; + } + +Exit: + OSM_LOG_EXIT(p_log); + return status; +} + +/* + * Wait for a trap on QPn + * + */ +ib_api_status_t +osmt_trap_wait(IN osmtest_t * const p_osmt, IN osmt_qp_ctx_t * p_qp_ctx) +{ + ib_smp_t *p_smp = (ib_smp_t *) (p_qp_ctx->p_send_buf); + ib_sa_mad_t *p_sa_mad; + VAPI_ret_t vapi_ret; + VAPI_wc_desc_t wc_desc; + osm_log_t *p_log = &p_osmt->log; + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER(p_log); + + OSM_LOG(p_log, OSM_LOG_INFO, + "Waiting for Traps under QP:0x%X of SA LID:0x%X\n", + cl_ntoh16(p_osmt->local_port.sm_lid)); + + /* --------------------- RECV ------------------------- */ + vapi_ret = osmt_mtl_mad_poll4cqe(p_qp_ctx->qp_bind_hndl.hca_hndl, + p_qp_ctx->qp_bind_hndl.rq_cq_hndl, + &wc_desc, + // 200, + p_osmt->opt.wait_time * 100, + 10000, NULL); + if (vapi_ret != VAPI_SUCCESS) { + if (vapi_ret == VAPI_CQ_EMPTY) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0130: " + "Timeout receiving mad (%s)\n", + VAPI_strerror_sym(vapi_ret)); + status = IB_TIMEOUT; + } else { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0131: " + "Error receiving mad (%s)\n", + VAPI_strerror_sym(vapi_ret)); + status = IB_ERROR; + } + goto Exit; + } + + /* check to see if successful - by examination of the subscribe bit */ + p_sa_mad = (ib_sa_mad_t *) (p_qp_ctx->p_recv_buf + GRH_LEN); + + if (p_sa_mad->method == IB_MAD_METHOD_REPORT) { + if (p_sa_mad->attr_id == IB_MAD_ATTR_NOTICE) { + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Received the Report!\n"); + status = IB_SUCCESS; + } else { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 1020" + "Did not receive a Report(Notice) but attr:%d\n", + cl_ntoh16(p_sa_mad->attr_id)); + status = IB_ERROR; + } + } else { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 1020" + "Received an Unexpected Method:%d\n", p_smp->method); + status = IB_ERROR; + } + +Exit: + OSM_LOG_EXIT(p_log); + return status; +} + +/* + * Initialize an inform info attribute: + * Catch all traps in the lid range of the p_osmt + * + */ +ib_api_status_t +osmt_init_inform_info(IN osmtest_t * const p_osmt, OUT ib_inform_info_t * p_ii) +{ + + memset(p_ii, 0, sizeof(ib_inform_info_t)); + /* p_ii->lid_range_begin = cl_hton16(1); */ + p_ii->lid_range_begin = 0xFFFF; + p_ii->lid_range_end = cl_hton16(p_osmt->max_lid); + p_ii->is_generic = 1; /* have to choose */ + p_ii->trap_type = 0xFFFF; /* ALL */ + p_ii->g_or_v.generic.trap_num = 0xFFFF; /* ALL */ + p_ii->g_or_v.generic.node_type_lsb = 0xFFFF; /* ALL */ + p_ii->g_or_v.generic.node_type_msb = 0xFF; /* ALL */ + return IB_SUCCESS; +} + +ib_api_status_t +osmt_init_inform_info_by_trap(IN osmtest_t * const p_osmt, + IN ib_net16_t trap_num, + OUT ib_inform_info_t * p_ii) +{ + + memset(p_ii, 0, sizeof(ib_inform_info_t)); + /* p_ii->lid_range_begin = cl_hton16(1); */ + p_ii->lid_range_begin = 0xFFFF; + p_ii->lid_range_end = cl_hton16(p_osmt->max_lid); + p_ii->is_generic = 1; /* have to choose */ + p_ii->trap_type = 0xFFFF; /* ALL */ + p_ii->g_or_v.generic.trap_num = trap_num; /* ALL */ + p_ii->g_or_v.generic.node_type_lsb = 0xFFFF; /* ALL */ + p_ii->g_or_v.generic.node_type_msb = 0xFF; /* ALL */ + return IB_SUCCESS; +} + +/* + * Run a complete inform info test flow: + * - try to unregister inform info (should fail) + * - register an inform info + * - try to unregister inform info (should succeed) + * - register an inform info + * - send a trap - sleep + * - check that a Report(Notice) arrived that match the sent one + * + */ +ib_api_status_t osmt_run_inform_info_flow(IN osmtest_t * const p_osmt) +{ + ib_inform_info_t inform_info; + ib_api_status_t status; + osmt_qp_ctx_t qp_ctx; + + OSM_LOG_ENTER(&p_osmt->log); + + /* bind the QP */ + status = osmt_bind_inform_qp(p_osmt, &qp_ctx); + if (status != IB_SUCCESS) { + goto Exit; + } + + /* init the inform info */ + osmt_init_inform_info(p_osmt, &inform_info); + + /* first try to unsubscribe */ + status = osmt_reg_unreg_inform_info(p_osmt, &qp_ctx, &inform_info, 0); + /* WAS IB_REMOTE_ERROR */ + if (status != IB_REMOTE_ERROR) { + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Error during UnSubscribe: (%s)\n", + ib_get_err_str(status)); + goto Exit; + } else { + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Expected Failure to UnSubscribe non existing InformInfo\n"); + status = IB_ERROR; + goto Exit; + } + } + + /* send the inform info registration */ + status = osmt_reg_unreg_inform_info(p_osmt, &qp_ctx, &inform_info, 1); + if (status != IB_SUCCESS) { + goto Exit; + } + + /* send a trap through QP0 and wait on QPN */ + status = osmt_send_trap_wait_for_forward(p_osmt, &qp_ctx); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Error during Send Trap and Wait For Report: (%s)\n", + ib_get_err_str(status)); + goto Exit; + } + + /* try to unsubscribe for cleanup */ + status = osmt_reg_unreg_inform_info(p_osmt, &qp_ctx, &inform_info, 0); + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Error during UnSubscribe: (%s)\n", + ib_get_err_str(status)); + goto Exit; + } else { + if (status == IB_REMOTE_ERROR) { + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Remote Error during UnSubscribe\n"); + status = IB_ERROR; + goto Exit; + } + } + +Exit: + osmt_unbind_inform_qp(p_osmt, &qp_ctx); + OSM_LOG_EXIT(&p_osmt->log); + return status; +} + +/* + * Run a complete inform info test flow: + * - try to unregister inform info (should fail) + * - register an inform info + * - try to unregister inform info (should succeed) + * - register an inform info + * - send a trap - sleep + * - check that a Report(Notice) arrived that match the sent one + * + */ +ib_api_status_t osmt_run_trap64_65_flow(IN osmtest_t * const p_osmt) +{ + ib_inform_info_t inform_info; + ib_api_status_t status; + osmt_qp_ctx_t qp_ctx; + + OSM_LOG_ENTER(&p_osmt->log); + + /* bind the QP */ + status = osmt_bind_inform_qp(p_osmt, &qp_ctx); + if (status != IB_SUCCESS) { + goto Exit; + } + + /* init the inform info */ + osmt_init_inform_info_by_trap(p_osmt, cl_hton16(64), &inform_info); + + /* send the inform info registration */ + status = osmt_reg_unreg_inform_info(p_osmt, &qp_ctx, &inform_info, 1); + if (status != IB_SUCCESS) { + goto Exit; + } + + /*--------------------- PREP -------------------------*/ + if (osmt_mtl_mad_post_recv_bufs(&qp_ctx.qp_bind_hndl, qp_ctx.p_recv_buf, 1, /* we need to receive the report */ + GRH_LEN + MAD_BLOCK_SIZE, 1) != 1) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0127: " + "Error posting recv bufs for trap 64\n"); + status = IB_ERROR; + goto Exit; + } + + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, "Posted recv bufs for trap 64\n"); + + /* init the inform info */ + osmt_init_inform_info_by_trap(p_osmt, cl_hton16(65), &inform_info); + + /* send the inform info registration */ + status = osmt_reg_unreg_inform_info(p_osmt, &qp_ctx, &inform_info, 1); + if (status != IB_SUCCESS) { + goto Exit; + } + + /*--------------------- PREP -------------------------*/ + if (osmt_mtl_mad_post_recv_bufs(&qp_ctx.qp_bind_hndl, qp_ctx.p_recv_buf, 1, /* we need to 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 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/branches/WOF2-3/ulp/opensm/user/osmtest/osmt_mtl_regular_qp.c b/branches/WOF2-3/ulp/opensm/user/osmtest/osmt_mtl_regular_qp.c new file mode 100644 index 00000000..f603ade2 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/osmtest/osmt_mtl_regular_qp.c @@ -0,0 +1,470 @@ +/* + * Copyright (c) 2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifdef OSM_VENDOR_INTF_MTL + +/* - Mellanox Confidential and Proprietary - + * + * Copyright (C) Jul. 2001, Mellanox Technologies Ltd. ALL RIGHTS RESERVED. + * + * Except as specifically permitted herein, no portion of the information, + * including but not limited to object code and source code, may be reproduced, + * modified, distributed, republished or otherwise exploited in any form or by + * any means for any purpose without the prior written permission of Mellanox + * Technologies Ltd. Use of software subject to the terms and conditions + * detailed in the file "LICENSE.txt". + * + * End of legal section ...................................................... + * + * osmt_mtl_regular_qp.c - + * Provide Simple Interface for Sending and Receiving MADS through a regular QP + * + * Creation date: + * + * Version: $Id$ + * + * Authors: + * Eitan Zahavi + * + * Changes: + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +/* + * Initialize the QP etc. + * Given in res: port_num, max_outs_sq, max_outs_rq + */ +VAPI_ret_t osmt_mtl_get_qp_resources(IN OUT osmt_mtl_mad_res_t * res) +{ + VAPI_ret_t ret; + VAPI_hca_port_t hca_port_info; + VAPI_qp_init_attr_t qp_init_attr; + VAPI_qp_prop_t qp_prop; + VAPI_cqe_num_t act_num; + + /* Get HCA LID */ + ret = + VAPI_query_hca_port_prop(res->hca_hndl, res->port_num, + &hca_port_info); + VAPI_CHECK_RET; + res->slid = hca_port_info.lid; + + /* Get a PD */ + ret = VAPI_alloc_pd(res->hca_hndl, &(res->pd_hndl)); + VAPI_CHECK_RET; + + /* Create CQ for RQ and SQ *//* TBD - Check we have enough act nums */ + ret = + VAPI_create_cq(res->hca_hndl, res->max_outs_sq + 1, + &(res->sq_cq_hndl), &act_num); + VAPI_CHECK_RET; + ret = + VAPI_create_cq(res->hca_hndl, res->max_outs_rq + 1, + &(res->rq_cq_hndl), &act_num); + VAPI_CHECK_RET; + + /* register event handlers for polling(block mode) internal use */ + /* ret= EVAPI_set_comp_eventh(res->hca_hndl,res->rq_cq_hndl, */ + /* EVAPI_POLL_CQ_UNBLOCK_HANDLER,NULL,&(res->rq_cq_eventh)); */ + /* VAPI_CHECK_RET; */ + /* ret= EVAPI_set_comp_eventh(res->hca_hndl,res->sq_cq_hndl, */ + /* EVAPI_POLL_CQ_UNBLOCK_HANDLER,NULL,&(res->sq_cq_eventh)); */ + /* VAPI_CHECK_RET; */ + + /* Create QP */ + qp_init_attr.cap.max_oust_wr_sq = res->max_outs_sq + 1; + qp_init_attr.cap.max_oust_wr_rq = res->max_outs_rq + 1; + qp_init_attr.cap.max_sg_size_sq = 4; + qp_init_attr.cap.max_sg_size_rq = 4; + + qp_init_attr.pd_hndl = res->pd_hndl; + qp_init_attr.rdd_hndl = 0; + qp_init_attr.rq_cq_hndl = res->rq_cq_hndl; + qp_init_attr.rq_sig_type = VAPI_SIGNAL_ALL_WR; /* That's default for IB */ + qp_init_attr.sq_cq_hndl = res->sq_cq_hndl; + qp_init_attr.sq_sig_type = VAPI_SIGNAL_REQ_WR; + qp_init_attr.ts_type = VAPI_TS_UD; + + ret = + VAPI_create_qp(res->hca_hndl, &qp_init_attr, &(res->qp_hndl), + &qp_prop); + VAPI_CHECK_RET; + res->qp_id.qp_num = qp_prop.qp_num; + + return (VAPI_OK); +} + +VAPI_ret_t osmt_mtl_qp_init(osmt_mtl_mad_res_t * res) +{ + VAPI_ret_t ret; + + VAPI_qp_attr_t qp_attr; + VAPI_qp_attr_mask_t qp_attr_mask; + VAPI_qp_cap_t qp_cap; + + /* + * Change QP to INIT + * + */ + QP_ATTR_MASK_CLR_ALL(qp_attr_mask); + qp_attr.qp_state = VAPI_INIT; + QP_ATTR_MASK_SET(qp_attr_mask, QP_ATTR_QP_STATE); + qp_attr.pkey_ix = 0; + QP_ATTR_MASK_SET(qp_attr_mask, QP_ATTR_PKEY_IX); + qp_attr.port = res->port_num; + QP_ATTR_MASK_SET(qp_attr_mask, QP_ATTR_PORT); + qp_attr.qkey = res->qkey; + QP_ATTR_MASK_SET(qp_attr_mask, QP_ATTR_QKEY); + + /* If I do not set this mask, I get an error from HH. QPM should catch it */ + ret = + VAPI_modify_qp(res->hca_hndl, res->qp_hndl, &qp_attr, &qp_attr_mask, + &qp_cap); + VAPI_CHECK_RET; + + return (ret); + +} + +VAPI_ret_t osmt_mtl_qp_2_rtr_rts(osmt_mtl_mad_res_t * res) +{ + VAPI_ret_t ret; + + VAPI_qp_attr_t qp_attr; + VAPI_qp_attr_mask_t qp_attr_mask; + VAPI_qp_cap_t qp_cap; + + /* + * Change QP to RTR + * + */ + QP_ATTR_MASK_CLR_ALL(qp_attr_mask); + qp_attr.qp_state = VAPI_RTR; + QP_ATTR_MASK_SET(qp_attr_mask, QP_ATTR_QP_STATE); + /* qp_attr.rq_psn = 0; */ + /* QP_ATTR_MASK_SET(qp_attr_mask,QP_ATTR_RQ_PSN); */ + + ret = + VAPI_modify_qp(res->hca_hndl, res->qp_hndl, &qp_attr, &qp_attr_mask, + &qp_cap); + VAPI_CHECK_RET; + + /* + * Change QP to RTS + * + */ + QP_ATTR_MASK_CLR_ALL(qp_attr_mask); + qp_attr.qp_state = VAPI_RTS; + QP_ATTR_MASK_SET(qp_attr_mask, QP_ATTR_QP_STATE); + qp_attr.sq_psn = 0; + QP_ATTR_MASK_SET(qp_attr_mask, QP_ATTR_SQ_PSN); + + ret = + VAPI_modify_qp(res->hca_hndl, res->qp_hndl, &qp_attr, &qp_attr_mask, + &qp_cap); + VAPI_CHECK_RET; + + return (ret); +} + +VAPI_ret_t osmt_mtl_mad_create_mr(osmt_mtl_mad_res_t * res) +{ + + VAPI_ret_t ret; + + VAPI_mrw_t mr_in, mr_out; + + res->buf_size = + (MAD_SIZE + GRH_LEN) * (res->max_outs_sq + res->max_outs_rq + 1); + + /* Register single memory address region for all buffers */ + res->buf_ptr = VMALLOC(res->buf_size); + + if (res->buf_ptr == ((VAPI_virt_addr_t) NULL)) { + ret = VAPI_EAGAIN; + VAPI_CHECK_RET; + } + + /* Enable local and remote access to memory region */ + mr_in.acl = VAPI_EN_LOCAL_WRITE | VAPI_EN_REMOTE_WRITE; + mr_in.l_key = 0; + mr_in.pd_hndl = res->pd_hndl; + mr_in.r_key = 0; + mr_in.size = res->buf_size; + ASSERT_VOIDP2UINTN(res->buf_ptr); + mr_in.start = (VAPI_virt_addr_t) (uintn_t) (res->buf_ptr); + mr_in.type = VAPI_MR; + + ret = VAPI_register_mr(res->hca_hndl, &mr_in, &(res->mr_hndl), &mr_out); + VAPI_CHECK_RET; + + res->l_key = mr_out.l_key; + + return (ret); +} + +VAPI_ret_t osmt_mtl_init_opened_hca(osmt_mtl_mad_res_t * res) +{ + VAPI_ret_t ret; + + res->pd_hndl = VAPI_INVAL_HNDL; + res->rq_cq_hndl = VAPI_INVAL_HNDL; + res->sq_cq_hndl = VAPI_INVAL_HNDL; + res->sq_cq_eventh = VAPI_INVAL_HNDL; + res->rq_cq_eventh = VAPI_INVAL_HNDL; + res->qp_hndl = VAPI_INVAL_HNDL; + res->mr_hndl = VAPI_INVAL_HNDL; + + /* + * Create QP + * + */ + ret = osmt_mtl_get_qp_resources(res); + if (ret != VAPI_OK) { + return ret; + } + + /* + * Move to init + * + */ + ret = osmt_mtl_qp_init(res); + if (ret != VAPI_OK) { + return ret; + } + + /* + * Initialize memory regions + * + */ + ret = osmt_mtl_mad_create_mr(res); + if (ret != VAPI_OK) { + return ret; + } + + /* only now move to RTR and RTS */ + ret = osmt_mtl_qp_2_rtr_rts(res); + if (ret != VAPI_OK) { + return ret; + } + + return VAPI_OK; +} + +VAPI_ret_t osmt_mtl_mad_cleanup(osmt_mtl_mad_res_t * res) +{ + if (res->qp_hndl != VAPI_INVAL_HNDL) { + VAPI_destroy_qp(res->hca_hndl, res->qp_hndl); + } + if (res->sq_cq_eventh != VAPI_INVAL_HNDL) { + EVAPI_clear_comp_eventh(res->hca_hndl, res->sq_cq_eventh); + } + if (res->rq_cq_eventh != VAPI_INVAL_HNDL) { + EVAPI_clear_comp_eventh(res->hca_hndl, res->rq_cq_eventh); + } + if (res->rq_cq_hndl != VAPI_INVAL_HNDL) { + VAPI_destroy_cq(res->hca_hndl, res->rq_cq_hndl); + } + if (res->sq_cq_hndl != VAPI_INVAL_HNDL) { + VAPI_destroy_cq(res->hca_hndl, res->sq_cq_hndl); + } + if (res->mr_hndl != VAPI_INVAL_HNDL) { + VAPI_deregister_mr(res->hca_hndl, res->mr_hndl); + } + if (res->pd_hndl != VAPI_INVAL_HNDL) { + VAPI_dealloc_pd(res->hca_hndl, res->pd_hndl); + } +#if 0 + /* open/close of HCA should be done system wide - not per application */ + if (res->hca_hndl != VAPI_INVAL_HNDL) { + VAPI_close_hca(res->hca_hndl); /* TBD: HCA_open/close should be done on a system wide basis */ + } +#endif + return VAPI_OK; +} + +VAPI_ret_t osmt_mtl_create_av(osmt_mtl_mad_res_t * res, int16_t dlid, + VAPI_ud_av_hndl_t * avh_p) +{ + VAPI_ud_av_t av; + VAPI_ret_t ret; + + av.dlid = dlid; + av.port = res->port_num; + av.sl = 0; /* dest->sl; */ + av.src_path_bits = 0; /* dest->ee_dlid.dst_path_bits; */ + av.static_rate = 0; + /* GRH ? */ + av.grh_flag = 0; + + ret = VAPI_create_addr_hndl(res->hca_hndl, res->pd_hndl, &av, avh_p); + if (ret != VAPI_OK) { + MTL_ERROR1("%s: failed VAPI_create_addr_hndl (%s)\n", __func__, + VAPI_strerror_sym(ret)); + return ret; + } + return VAPI_OK; +} + +VAPI_ret_t osmt_mtl_mad_send(osmt_mtl_mad_res_t * res, VAPI_wr_id_t id, + void *mad, VAPI_qp_num_t dest_qp, IB_sl_t sl, + u_int32_t dest_qkey, VAPI_ud_av_hndl_t avh) +{ + VAPI_sr_desc_t sr; + VAPI_sg_lst_entry_t sg_entry; + VAPI_ret_t ret; + + /* building SEND request */ + sr.opcode = VAPI_SEND; + sr.remote_ah = avh; + sr.remote_qp = dest_qp; + sr.remote_qkey = dest_qkey; + + sr.id = id; + sr.set_se = FALSE; + sr.fence = FALSE; + sr.comp_type = VAPI_SIGNALED; + sr.sg_lst_len = 1; + sr.sg_lst_p = &sg_entry; + ASSERT_VOIDP2UINTN(mad); + sg_entry.addr = (VAPI_virt_addr_t) (uintn_t) (mad); + sg_entry.len = MAD_SIZE; + sg_entry.lkey = res->l_key; + + ret = VAPI_post_sr(res->hca_hndl, res->qp_hndl, &sr); + if (ret != VAPI_OK) { + MTL_ERROR1(__FUNCTION__ ": failed VAPI_post_sr (%s)\n", + VAPI_strerror_sym(ret)); + return ret; + } + + return VAPI_OK; +} + +int osmt_mtl_mad_post_recv_bufs(osmt_mtl_mad_res_t * res, void *buf_array, + u_int32_t num_o_bufs, u_int32_t size, + VAPI_wr_id_t start_id) +{ + uint32_t i; + void *cur_buf; + VAPI_rr_desc_t rr; + VAPI_sg_lst_entry_t sg_entry; + VAPI_ret_t ret; + + rr.opcode = VAPI_RECEIVE; + rr.comp_type = VAPI_SIGNALED; /* All with CQE (IB compliant) */ + rr.sg_lst_len = 1; /* single buffers */ + rr.sg_lst_p = &sg_entry; + sg_entry.lkey = res->l_key; + cur_buf = buf_array; + for (i = 0; i < num_o_bufs; i++) { + rr.id = start_id + i; /* WQE id used is the index to buffers ptr array */ + ASSERT_VOIDP2UINTN(cur_buf); + sg_entry.addr = (VAPI_virt_addr_t) (uintn_t) cur_buf; + sg_entry.len = size; + memset(cur_buf, 0x00, size); /* fill with 0 */ + ret = VAPI_post_rr(res->hca_hndl, res->qp_hndl, &rr); + if (ret != VAPI_OK) { + MTL_ERROR1(__FUNCTION__ + ": failed posting RQ WQE (%s)\n", + VAPI_strerror_sym(ret)); + return i; + } + MTL_DEBUG4(__FUNCTION__ ": posted buf at %p\n", cur_buf); + cur_buf += size; + } + + return i; /* num of buffers posted */ +} + +VAPI_ret_t osmt_mtl_mad_poll4cqe(VAPI_hca_hndl_t hca, VAPI_cq_hndl_t cq, + VAPI_wc_desc_t * wc_desc_p, + u_int32_t max_poll, u_int32_t poll_sleep, + VAPI_ud_av_hndl_t * avh_p) +{ + VAPI_ret_t ret = VAPI_CQ_EMPTY; + u_int32_t poll_cnt = 0; + + /* wait for something to arrive */ + while ((ret == VAPI_CQ_EMPTY) && (poll_cnt < max_poll)) { + ret = VAPI_poll_cq(hca, cq, wc_desc_p); + /* don't sleep if we already succeeded) */ + if (ret != VAPI_CQ_EMPTY) { + break; + } + usleep(poll_sleep); + poll_cnt++; + } + + /* if passed an AVH to destory - do it */ + if (avh_p != NULL) { + VAPI_destroy_addr_hndl(hca, *avh_p); + } + + if ((poll_cnt == max_poll) && (ret == VAPI_CQ_EMPTY)) { + MTL_DEBUG1(__FUNCTION__ + ": Failed to get completion on wq after %d polls.\n", + max_poll); + return VAPI_CQ_EMPTY; + } + + if (ret != VAPI_OK) { + MTL_DEBUG1(__FUNCTION__ + ": VAPI_poll_cq failed with ret=%s on sq_cq\n", + mtl_strerror_sym(ret)); + return ret; + } + + if (wc_desc_p->status != VAPI_SUCCESS) { + MTL_DEBUG1(__FUNCTION__ ": completion error (%d) detected\n", + wc_desc_p->status); + } + + return VAPI_OK; +} + +#endif /* OSM_VENDOR_INTF_MTL */ diff --git a/branches/WOF2-3/ulp/opensm/user/osmtest/osmt_multicast.c b/branches/WOF2-3/ulp/opensm/user/osmtest/osmt_multicast.c new file mode 100644 index 00000000..ed8577c2 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/osmtest/osmt_multicast.c @@ -0,0 +1,2575 @@ +/* + * Copyright (c) 2006-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005,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 Multicast Member testing flow.. + * + */ + +#ifndef __WIN__ +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include "osmtest.h" + +static void __osmt_print_all_multicast_records(IN osmtest_t * const p_osmt) +{ + uint32_t i; + ib_api_status_t status; + osmv_query_req_t req; + osmv_user_query_t user; + osmtest_req_context_t context; + ib_member_rec_t *mcast_record; + + memset(&context, 0, sizeof(context)); + memset(&req, 0, sizeof(req)); + memset(&user, 0, sizeof(user)); + + user.attr_id = IB_MAD_ATTR_MCMEMBER_RECORD; + user.attr_offset = ib_get_attr_offset(sizeof(*mcast_record)); + + req.query_type = OSMV_QUERY_USER_DEFINED; + req.timeout_ms = p_osmt->opt.transaction_timeout; + req.retry_cnt = 1; + req.flags = OSM_SA_FLAGS_SYNC; + context.p_osmt = p_osmt; + req.query_context = &context; + req.pfn_query_cb = osmtest_query_res_cb; + req.p_query_input = &user; + + /* UnTrusted (SMKey of 0) - get the multicast groups */ + status = osmv_query_sa(p_osmt->h_bind, &req); + + if (status != IB_SUCCESS || context.result.status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 02B5: " + "Failed getting the multicast groups records - %s/%s\n", + ib_get_err_str(status), + ib_get_err_str(context.result.status)); + return; + } + + osm_log(&p_osmt->log, OSM_LOG_INFO, + "\n |------------------------------------------|" + "\n | Remaining Multicast Groups |" + "\n |------------------------------------------|\n"); + + for (i = 0; i < context.result.result_cnt; i++) { + mcast_record = + osmv_get_query_mc_rec(context.result.p_result_madw, i); + osm_dump_mc_record(&p_osmt->log, mcast_record, OSM_LOG_INFO); + } + + /* Trusted - now get the multicast group members */ + req.sm_key = OSM_DEFAULT_SM_KEY; + status = osmv_query_sa(p_osmt->h_bind, &req); + + if (status != IB_SUCCESS || context.result.status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 02B6: " + "Failed getting the multicast group members records - %s/%s\n", + ib_get_err_str(status), + ib_get_err_str(context.result.status)); + return; + } + + osm_log(&p_osmt->log, OSM_LOG_INFO, + "\n |--------------------------------------------------|" + "\n | Remaining Multicast Group Members |" + "\n |--------------------------------------------------|\n"); + + for (i = 0; i < context.result.result_cnt; i++) { + mcast_record = + osmv_get_query_mc_rec(context.result.p_result_madw, i); + osm_dump_mc_record(&p_osmt->log, mcast_record, OSM_LOG_INFO); + } + +} + +static cl_status_t +__match_mgids(IN const void *const p_object, IN void *context) +{ + ib_gid_t *p_mgid_context = (ib_gid_t *) context; + ib_gid_t *p_mgid_list_item = (ib_gid_t *) p_object; + int32_t count; + + count = memcmp(p_mgid_context, p_mgid_list_item, sizeof(ib_gid_t)); + if (count == 0) + return CL_SUCCESS; + else + return CL_NOT_FOUND; +} + +ib_api_status_t osmt_query_mcast(IN osmtest_t * const p_osmt) +{ + ib_api_status_t status = IB_SUCCESS; + osmv_user_query_t user; + osmv_query_req_t req; + osmtest_req_context_t context; + ib_member_rec_t *p_rec; + uint32_t i, num_recs = 0; + cl_list_t mgids_list; + cl_list_t *p_mgids_list; + cl_list_iterator_t p_mgids_res; + cl_status_t cl_status; + cl_map_item_t *p_item, *p_next_item; + osmtest_mgrp_t *p_mgrp; + + OSM_LOG_ENTER(&p_osmt->log); + + /* + * Do a blocking query for all Multicast Records in the subnet. + * The result is returned in the result field of the caller's + * context structure. + * + * The query structures are locals. + */ + + memset(&req, 0, sizeof(req)); + memset(&user, 0, sizeof(user)); + + context.p_osmt = p_osmt; + user.attr_id = IB_MAD_ATTR_MCMEMBER_RECORD; + user.attr_offset = ib_get_attr_offset(sizeof(ib_member_rec_t)); + + req.query_type = OSMV_QUERY_USER_DEFINED; + req.timeout_ms = p_osmt->opt.transaction_timeout; + req.retry_cnt = p_osmt->opt.retry_count; + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = &context; + req.pfn_query_cb = osmtest_query_res_cb; + req.p_query_input = &user; + + status = osmv_query_sa(p_osmt->h_bind, &req); + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0203: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + goto Exit; + } + + status = context.result.status; + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0264: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + if (status == IB_REMOTE_ERROR) + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "Remote error = %s.\n", + ib_get_mad_status_str(osm_madw_get_mad_ptr + (context.result. + p_result_madw))); + goto Exit; + } + + /* ok we have got something */ + /* First Delete the old MGID Table */ + p_next_item = cl_qmap_head(&p_osmt->exp_subn.mgrp_mlid_tbl); + while (p_next_item != cl_qmap_end(&p_osmt->exp_subn.mgrp_mlid_tbl)) { + p_item = p_next_item; + p_next_item = cl_qmap_next(p_item); + cl_qmap_remove_item(&p_osmt->exp_subn.mgrp_mlid_tbl, p_item); + free(p_item); + } + + cl_list_construct(&mgids_list); + cl_list_init(&mgids_list, num_recs); + p_mgids_list = &mgids_list; + num_recs = context.result.result_cnt; + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "Received %u records\n", + num_recs); + + for (i = 0; i < num_recs; i++) { + p_rec = osmv_get_query_result(context.result.p_result_madw, i); + p_mgids_res = + cl_list_find_from_head(p_mgids_list, __match_mgids, + &(p_rec->mgid)); + /* If returns iterator other than end of list, same mgid exists already */ + if (p_mgids_res != cl_list_end(p_mgids_list)) { + char gid_str[INET6_ADDRSTRLEN]; + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0265: " + "MCG MGIDs are the same - invalid MGID : %s\n", + inet_ntop(AF_INET6, p_rec->mgid.raw, gid_str, + sizeof gid_str)); + status = IB_ERROR; + goto Exit; + + } + osm_dump_mc_record(&p_osmt->log, p_rec, OSM_LOG_VERBOSE); + cl_status = cl_list_insert_head(p_mgids_list, &(p_rec->mgid)); + if (cl_status) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0205: " + "Could not add MGID to cl_list\n"); + status = IB_ERROR; + goto Exit; + } + p_mgrp = (osmtest_mgrp_t *) malloc(sizeof(*p_mgrp)); + if (!p_mgrp) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0204: " + "Could not allocate new MCG\n"); + status = IB_ERROR; + goto Exit; + } + memcpy(&p_mgrp->mcmember_rec, p_rec, + sizeof(p_mgrp->mcmember_rec)); + cl_qmap_insert(&p_osmt->exp_subn.mgrp_mlid_tbl, + cl_ntoh16(p_rec->mlid), &p_mgrp->map_item); + } + +Exit: + if (context.result.p_result_madw != NULL) { + osm_mad_pool_put(&p_osmt->mad_pool, + context.result.p_result_madw); + context.result.p_result_madw = NULL; + } + + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/* given a multicast request send and wait for response. */ +ib_api_status_t +osmt_send_mcast_request(IN osmtest_t * const p_osmt, + IN uint8_t is_set, + IN ib_member_rec_t * p_mc_req, + IN uint64_t comp_mask, OUT ib_sa_mad_t * p_res) +{ + osmtest_req_context_t context; + ib_api_status_t status = IB_SUCCESS; + osmv_user_query_t user; + osmv_query_req_t req; + + OSM_LOG_ENTER(&p_osmt->log); + + /* + * Do a blocking query for this record in the subnet. + * + * The query structures are locals. + */ + memset(&req, 0, sizeof(req)); + memset(&user, 0, sizeof(user)); + memset(&context, 0, sizeof(context)); + memset(p_res, 0, sizeof(ib_sa_mad_t)); + + context.p_osmt = p_osmt; + + user.p_attr = p_mc_req; + user.comp_mask = comp_mask; + + if (is_set == 1) + req.query_type = OSMV_QUERY_UD_MULTICAST_SET; + else if (is_set == 0) + req.query_type = OSMV_QUERY_UD_MULTICAST_DELETE; + else if (is_set == 0xee) { + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Set USER DEFINED QUERY\n"); + req.query_type = OSMV_QUERY_USER_DEFINED; + user.method = IB_MAD_METHOD_GET; + user.attr_id = IB_MAD_ATTR_MCMEMBER_RECORD; + user.attr_offset = ib_get_attr_offset(sizeof(ib_member_rec_t)); + } else if (is_set == 0xff) { + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Set USER DEFINED QUERY\n"); + req.query_type = OSMV_QUERY_USER_DEFINED; + user.method = IB_MAD_METHOD_SET; + user.attr_id = IB_MAD_ATTR_MCMEMBER_RECORD; + user.attr_offset = ib_get_attr_offset(sizeof(ib_member_rec_t)); + } + + /* TODO : Check the validity of all user fields in order to use + OSMV_QUERY_USER_DEFINED + p_user_query = ( osmv_user_query_t * ) p_query_req->p_query_input; + if (p_user_query->method) sa_mad_data.method = p_user_query->method; + sa_mad_data.attr_offset = p_user_query->attr_offset; + sa_mad_data.attr_id = p_user_query->attr_id; + sa_mad_data.comp_mask = p_user_query->comp_mask; + sa_mad_data.p_attr = p_user_query->p_attr; + */ + + req.timeout_ms = p_osmt->opt.transaction_timeout; + req.retry_cnt = p_osmt->opt.retry_count; + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = &context; + req.pfn_query_cb = osmtest_query_res_cb; + req.p_query_input = &user; + + status = osmv_query_sa(p_osmt->h_bind, &req); + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0206: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + goto Exit; + } + + /* ok it worked */ + memcpy(p_res, osm_madw_get_mad_ptr(context.result.p_result_madw), + sizeof(ib_sa_mad_t)); + + status = context.result.status; + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0224: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + if (status == IB_REMOTE_ERROR) + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "Remote error = %s\n", + ib_get_mad_status_str(osm_madw_get_mad_ptr + (context.result. + p_result_madw))); + } + +Exit: + /* + * Return the IB query MAD to the pool as necessary. + */ + if (context.result.p_result_madw != NULL) { + osm_mad_pool_put(&p_osmt->mad_pool, + context.result.p_result_madw); + context.result.p_result_madw = NULL; + } + + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +void osmt_init_mc_query_rec(IN osmtest_t * const p_osmt, + IN OUT ib_member_rec_t * p_mc_req) +{ + /* use default values so we can change only what we want later */ + memset(p_mc_req, 0, sizeof(ib_member_rec_t)); + + /* we leave the MGID to the user */ + memcpy(&p_mc_req->port_gid.unicast.interface_id, + &p_osmt->local_port.port_guid, + sizeof(p_osmt->local_port.port_guid)); + + /* use our own subnet prefix: */ + p_mc_req->port_gid.unicast.prefix = CL_HTON64(0xFE80000000000000ULL); + + /* ib_net32_t qkey; */ + /* ib_net16_t mlid; - we keep it zero for upper level to decide. */ + /* uint8_t mtu; - keep it zero means - anything you have please. */ + /* uint8_t tclass; can leave as zero for now (between subnets) */ + /* ib_net16_t pkey; leave as zero */ + p_mc_req->rate = IB_LINK_WIDTH_ACTIVE_4X; + /* uint8_t pkt_life; zero means greater than zero ... */ + /* ib_net32_t sl_flow_hop; keep it all zeros */ + /* we want to use a link local scope: 0x02 */ + p_mc_req->scope_state = ib_member_set_scope_state(0x02, 0); +} + +/*********************************************************************** + * UD Multicast testing flow: + * o15.0.1.3: + * - Request new MCG with not enough components in comp_mask : + * ERR_INSUFFICIENT_COMPONENTS + * o15.0.1.8: + * - Request a join with irrelevant RATE and get a ERR_INVALID_REQ + * o15.0.1.4: + * - Create an MGID by asking for a join with MGID = 0 + * providing P_Key, Q_Key, SL, FlowLabel, Tclass. + * o15.0.1.5: + * - Check the returned MGID is valid. (p 804) + * o15.0.1.6: + * - Create a new MCG with valid requested MGID. + * - Try to create a new MCG with invalid MGID : get back ERR_REQ_INVALID + * - Try again with MGID prefix = 0xA01B (maybe 0x1BA0 little or big ?) + * - Try to create again the already created group: ERR_REQ_INVALID + * o15.0.1.7 - implicitlly checked during the prev steps. + * o15.0.1.9 + * - Create MCG with Invalid JoinState.FullMember != 1 : get ERR_REQ_INVALID + * o15.0.1.10 - can't check on a single client . + * o15.0.1.11: + * - Try to join into a MGID that exists with JoinState=SendOnlyMember - + * see that it updates JoinState. What is the routing change? + * - We can not check simple join since we have only one tester (for now) + * o15.0.1.12: + * - The last join should have a special treatment in the SA (sender only) + * but what is it ? + * o15.0.1.13: + * - Try joining with wrong rate - ERR_REQ_INVALID + * o15.0.1.14: + * - Try partial delete - actually updating the join state. check it. + * - Register by InformInfo flow to receive trap 67 on MCG delete. + * - Try full delete (JoinState and should be 0) + * - Wait for trap 67. + * - Try joining (not full mem) again to see the group was deleted. + * (should fail - o15.0.1.13) + * o15.0.1.15: + * - Try deletion of the IPoIB MCG and get: ERR_REQ_INVALID + * o15.0.1.16: + * - Try GetTable with PortGUID wildcarded and get back some groups. + ***********************************************************************/ + +/* The following macro can be used only within the osmt_run_mcast_flow() function */ +#define IS_IPOIB_MGID(p_mgid) \ + ( !memcmp(&osm_ipoib_good_mgid, (p_mgid), sizeof(osm_ipoib_good_mgid)) || \ + !memcmp(&osm_ts_ipoib_good_mgid, (p_mgid), sizeof(osm_ts_ipoib_good_mgid)) ) + +ib_api_status_t osmt_run_mcast_flow(IN osmtest_t * const p_osmt) +{ + char gid_str[INET6_ADDRSTRLEN]; + char gid_str2[INET6_ADDRSTRLEN]; + ib_api_status_t status; + ib_member_rec_t mc_req_rec; + union { + ib_sa_mad_t sa_mad; + ib_member_rec_t mcmr; + } res; + ib_sa_mad_t *sa_mad; + ib_member_rec_t *p_mc_res; + 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; + 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 */ + 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); + + sa_mad = &res.sa_mad; + p_mc_res = ib_sa_mad_get_payload_ptr(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, + 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 */ + + /* 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, + 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, 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, 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, + sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if (status != IB_REMOTE_ERROR || + ((ib_net16_t) (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 *) 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, + sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if (status != IB_REMOTE_ERROR || + ((ib_net16_t) (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 *) 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; + + 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, + sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if (status != IB_REMOTE_ERROR || + ((ib_net16_t) (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 *) sa_mad)); + status = IB_ERROR; + goto Exit; + } + + osmt_init_mc_query_rec(p_osmt, &mc_req_rec); + + 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, + sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if (status != IB_REMOTE_ERROR || + ((ib_net16_t) (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 *) sa_mad)); + status = IB_ERROR; + goto Exit; + } + + osmt_init_mc_query_rec(p_osmt, &mc_req_rec); + + 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, + sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if (status != IB_REMOTE_ERROR || + ((ib_net16_t) (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 *) 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, + sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if (status != IB_REMOTE_ERROR || + 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 *) 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, + sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if (status != IB_REMOTE_ERROR || + 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 *) 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, + sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if (status != IB_REMOTE_ERROR || + 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 *) 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, + sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if (status != IB_REMOTE_ERROR || + 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 *) 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, + sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if (status != IB_REMOTE_ERROR || + 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 *) 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, + sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if (status != IB_REMOTE_ERROR || + 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 *) 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, + sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if (status != IB_REMOTE_ERROR || + 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 *) 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); + + /* 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, + sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if (status != IB_REMOTE_ERROR || + ((ib_net16_t) (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 *) 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 *) 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); + + /* 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, + sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if (status != IB_REMOTE_ERROR || + ((ib_net16_t) (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 *) 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); + + /* 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, + sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if (status != IB_REMOTE_ERROR || + ((ib_net16_t) (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 *) 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, + 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 *) sa_mad)); + goto Exit; + } + + /* Save the mlid created in test_created_mlids map */ + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "created MGID:%s MLID:0x%04X\n", + inet_ntop(AF_INET6, p_mc_res->mgid.raw, gid_str, + sizeof gid_str), cl_ntoh16(p_mc_res->mlid)); + cl_map_insert(&test_created_mlids, cl_ntoh16(p_mc_res->mlid), p_mc_res); + + /* 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, + 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 *) sa_mad)); + goto Exit; + } + + /* Save the mlid created in test_created_mlids map */ + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "Created MGID:%s MLID:0x%04X\n", + inet_ntop(AF_INET6, p_mc_res->mgid.raw, gid_str, + sizeof gid_str), cl_ntoh16(p_mc_res->mlid)); + cl_map_insert(&test_created_mlids, cl_ntoh16(p_mc_res->mlid), p_mc_res); + + /* 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, + 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 *) sa_mad)); + goto Exit; + } + + /* Save the mlid created in test_created_mlids map */ + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "Created MGID:%s MLID:0x%04X\n", + inet_ntop(AF_INET6, p_mc_res->mgid.raw, gid_str, + sizeof gid_str), cl_ntoh16(p_mc_res->mlid)); + cl_map_insert(&test_created_mlids, cl_ntoh16(p_mc_res->mlid), p_mc_res); + + /* 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, + 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 *) sa_mad)); + goto Exit; + } + + /* Save the mlid created in test_created_mlids map */ + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "Created MGID:%s MLID:0x%04X\n", + inet_ntop(AF_INET6, p_mc_res->mgid.raw, gid_str, + sizeof gid_str), cl_ntoh16(p_mc_res->mlid)); + cl_map_insert(&test_created_mlids, cl_ntoh16(p_mc_res->mlid), p_mc_res); + + /* 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, + 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 *) sa_mad)); + goto Exit; + } + + /* Save the mlid created in test_created_mlids map */ + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "Created MGID:%s MLID:0x%04X\n", + inet_ntop(AF_INET6, p_mc_res->mgid.raw, gid_str, + sizeof gid_str), cl_ntoh16(p_mc_res->mlid)); + cl_map_insert(&test_created_mlids, cl_ntoh16(p_mc_res->mlid), p_mc_res); + + /* 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, + 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 *) sa_mad)); + goto Exit; + } + + /* Save the mlid created in test_created_mlids map */ + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "Created MGID:%s MLID:0x%04X\n", + inet_ntop(AF_INET6, p_mc_res->mgid.raw, gid_str, + sizeof gid_str), cl_ntoh16(p_mc_res->mlid)); + cl_map_insert(&test_created_mlids, cl_ntoh16(p_mc_res->mlid), p_mc_res); + + /* 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, + 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 *) sa_mad)); + goto Exit; + } + + /* Save the mlid created in test_created_mlids map */ + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "Created MGID:%s MLID:0x%04X\n", + inet_ntop(AF_INET6, p_mc_res->mgid.raw, gid_str, + sizeof gid_str), cl_ntoh16(p_mc_res->mlid)); + cl_map_insert(&test_created_mlids, cl_ntoh16(p_mc_res->mlid), p_mc_res); + + /* 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); + + /* 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, + 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 *) sa_mad)); + goto Exit; + } + + /* Save the mlid created in test_created_mlids map */ + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "Created MGID:%s MLID:0x%04X\n", + inet_ntop(AF_INET6, p_mc_res->mgid.raw, gid_str, + sizeof gid_str), cl_ntoh16(p_mc_res->mlid)); + cl_map_insert(&test_created_mlids, cl_ntoh16(p_mc_res->mlid), p_mc_res); + + /* 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, sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if ((status != IB_REMOTE_ERROR) || + (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 *) 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, + 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 *) sa_mad)); + goto Exit; + } + + /* Save the mlid created in test_created_mlids map */ + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "Created MGID:%s MLID:0x%04X\n", + inet_ntop(AF_INET6, p_mc_res->mgid.raw, gid_str, + sizeof gid_str), cl_ntoh16(p_mc_res->mlid)); + cl_map_insert(&test_created_mlids, cl_ntoh16(p_mc_res->mlid), p_mc_res); + + 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, + sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if ((status != IB_REMOTE_ERROR) || + (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 *) 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, + sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if ((status != IB_REMOTE_ERROR) || + (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 *) 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, + sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if ((status != IB_REMOTE_ERROR) || + (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 *) 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, + 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 *) sa_mad)); + goto Exit; + } + + /* Save the mlid created in test_created_mlids map */ + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "Created MGID:%s MLID:0x%04X\n", + inet_ntop(AF_INET6, p_mc_res->mgid.raw, gid_str, + sizeof gid_str), cl_ntoh16(p_mc_res->mlid)); + cl_map_insert(&test_created_mlids, cl_ntoh16(p_mc_res->mlid), p_mc_res); + + /* 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, + sa_mad); + + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if ((status != IB_REMOTE_ERROR) || + (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 *) 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, + 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 *) sa_mad)); + goto Exit; + } + + /* Save the mlid created in test_created_mlids map */ + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "Created MGID:%s MLID:0x%04X\n", + inet_ntop(AF_INET6, p_mc_res->mgid.raw, gid_str, + sizeof gid_str), cl_ntoh16(p_mc_res->mlid)); + cl_map_insert(&test_created_mlids, cl_ntoh16(p_mc_res->mlid), p_mc_res); + + /* 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, + sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if ((status != IB_REMOTE_ERROR) || + (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 *) 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, + 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 *) sa_mad)); + goto Exit; + } + + /* Save the mlid created in test_created_mlids map */ + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "Created MGID:%s MLID:0x%04X\n", + inet_ntop(AF_INET6, p_mc_res->mgid.raw, gid_str, + sizeof gid_str), cl_ntoh16(p_mc_res->mlid)); + cl_map_insert(&test_created_mlids, cl_ntoh16(p_mc_res->mlid), p_mc_res); + + /* 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, + sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if ((status != IB_REMOTE_ERROR) || + (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 *) 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, + 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 *) sa_mad)); + goto Exit; + } + + /* Save the mlid created in test_created_mlids map */ + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "Created MGID:%s MLID:0x%04X\n", + inet_ntop(AF_INET6, p_mc_res->mgid.raw, gid_str, + sizeof gid_str), cl_ntoh16(p_mc_res->mlid)); + cl_map_insert(&test_created_mlids, cl_ntoh16(p_mc_res->mlid), p_mc_res); + + /* 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 */ + 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, 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 *) sa_mad)); + goto Exit; + } + + 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, + 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 *) 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, + 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 *) 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, + 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, + 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 *) sa_mad)); + status = IB_ERROR; + goto Exit; + } + + 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, + 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 *) 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, + 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 *) 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, + 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 *) 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, + sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if ((status != IB_REMOTE_ERROR) || + (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 existing MGID: %s/%s\n", + ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) 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 than 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, + sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if ((status != IB_REMOTE_ERROR) || + (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 than max) joining an existing MGID: %s/%s\n", + ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) 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, + sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if ((status != IB_REMOTE_ERROR) || + (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 than min) joining an existing MGID: %s/%s\n", + ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) 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, + 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 *) 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, + 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 *) 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, 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 *) 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, sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if ((status != IB_REMOTE_ERROR) || + (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 *) 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, + 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 *) 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, + 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, sa_mad); + + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if ((status != IB_REMOTE_ERROR) || + (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 *) 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, + 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, + 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 *) 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, 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 *) sa_mad)); + status = IB_ERROR; + goto Exit; + } + + 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, 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 *) 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, 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 *) 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) { + 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, sa_mad); + if (status == IB_SUCCESS) { + cur_mlid = cl_ntoh16(p_mc_res->mlid); + /* Save the mlid created in test_created_mlids map */ + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Created MGID:%s MLID:0x%04X\n", + inet_ntop(AF_INET6, p_mc_res->mgid.raw, + gid_str, sizeof gid_str), + cl_ntoh16(p_mc_res->mlid)); + cl_map_insert(&test_created_mlids, + cl_ntoh16(p_mc_res->mlid), + p_mc_res); + } else 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 ((sa_mad->status & IB_SMP_STATUS_MASK) == + IB_SA_MAD_STATUS_NO_RESOURCES) + /* You can quietly exit the loop since no available mlid in SA DB + i.e. reached the maximum valid avalable mlid */ + break; + 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, + 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 *) + 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/branches/WOF2-3/ulp/opensm/user/osmtest/osmt_service.c b/branches/WOF2-3/ulp/opensm/user/osmtest/osmt_service.c new file mode 100644 index 00000000..9921c26f --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/osmtest/osmt_service.c @@ -0,0 +1,1587 @@ +/* + * Copyright (c) 2006-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2006 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of service records testing flow.. + * Top level is osmt_run_service_records_flow: + * osmt_register_service + * osmt_get_service_by_name + * osmt_get_all_services + * osmt_delete_service_by_name + * + */ + +#ifndef __WIN__ +#include +#else +#include +#endif +#include +#include +#include +#include +#include "osmtest.h" + + +ib_api_status_t +osmt_register_service(IN osmtest_t * const p_osmt, + IN ib_net64_t service_id, + IN ib_net16_t service_pkey, + IN ib_net32_t service_lease, + IN uint8_t service_key_lsb, IN char *service_name) +{ + osmv_query_req_t req; + osmv_user_query_t user; + osmtest_req_context_t context; + ib_service_record_t svc_rec; + osm_log_t *p_log = &p_osmt->log; + ib_api_status_t status; + + OSM_LOG_ENTER(p_log); + + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Registering service: name: %s id: 0x%" PRIx64 "\n", + service_name, cl_ntoh64(service_id)); + + memset(&req, 0, sizeof(req)); + memset(&context, 0, sizeof(context)); + memset(&user, 0, sizeof(user)); + memset(&svc_rec, 0, sizeof(svc_rec)); + + /* set the new service record fields */ + svc_rec.service_id = service_id; + svc_rec.service_pkey = service_pkey; + svc_rec.service_gid.unicast.prefix = 0; + svc_rec.service_gid.unicast.interface_id = p_osmt->local_port.port_guid; + svc_rec.service_lease = service_lease; + memset(&svc_rec.service_key, 0, 16 * sizeof(uint8_t)); + svc_rec.service_key[0] = service_key_lsb; + memset(svc_rec.service_name, 0, sizeof(svc_rec.service_name)); + memcpy(svc_rec.service_name, service_name, + (strlen(service_name) + 1) * sizeof(char)); + + /* prepare the data used for this query */ + /* sa_mad_data.method = IB_MAD_METHOD_SET; */ + /* sa_mad_data.sm_key = 0; */ + + context.p_osmt = p_osmt; + req.query_context = &context; + req.query_type = OSMV_QUERY_USER_DEFINED; + req.pfn_query_cb = osmtest_query_res_cb; + req.p_query_input = &user; + req.flags = OSM_SA_FLAGS_SYNC; + req.sm_key = 0; + req.timeout_ms = p_osmt->opt.transaction_timeout; + + user.method = IB_MAD_METHOD_SET; + user.attr_id = IB_MAD_ATTR_SERVICE_RECORD; + if (ib_pkey_is_invalid(service_pkey)) { + /* if given an invalid service_pkey - don't turn the PKEY compmask on */ + user.comp_mask = IB_SR_COMPMASK_SID | + IB_SR_COMPMASK_SGID | + IB_SR_COMPMASK_SLEASE | + IB_SR_COMPMASK_SKEY | IB_SR_COMPMASK_SNAME; + } else { + user.comp_mask = IB_SR_COMPMASK_SID | + IB_SR_COMPMASK_SGID | + IB_SR_COMPMASK_SPKEY | + IB_SR_COMPMASK_SLEASE | + IB_SR_COMPMASK_SKEY | IB_SR_COMPMASK_SNAME; + } + user.attr_offset = ib_get_attr_offset(sizeof(ib_service_record_t)); + user.p_attr = &svc_rec; + + status = osmv_query_sa(p_osmt->h_bind, &req); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A01: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + goto Exit; + } + + status = context.result.status; + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A02: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + + if (status == IB_REMOTE_ERROR) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "Remote error = %s\n", + ib_get_mad_status_str(osm_madw_get_mad_ptr + (context.result. + p_result_madw))); + } + goto Exit; + } + +Exit: + if (context.result.p_result_madw != NULL) { + osm_mad_pool_put(&p_osmt->mad_pool, + context.result.p_result_madw); + context.result.p_result_madw = NULL; + } + + OSM_LOG_EXIT(&p_osmt->log); + return status; +} + +ib_api_status_t +osmt_register_service_with_full_key(IN osmtest_t * const p_osmt, + IN ib_net64_t service_id, + IN ib_net16_t service_pkey, + IN ib_net32_t service_lease, + IN uint8_t * service_key, + IN char *service_name) +{ + osmv_query_req_t req; + osmv_user_query_t user; + osmtest_req_context_t context; + ib_service_record_t svc_rec, *p_rec; + osm_log_t *p_log = &p_osmt->log; + ib_api_status_t status; + uint8_t i, skey[16]; + + OSM_LOG_ENTER(p_log); + + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Registering service: name: %s id: 0x%" PRIx64 "\n", + service_name, cl_ntoh64(service_id)); + + memset(&req, 0, sizeof(req)); + memset(&context, 0, sizeof(context)); + memset(&user, 0, sizeof(user)); + memset(&svc_rec, 0, sizeof(svc_rec)); + + /* set the new service record fields */ + svc_rec.service_id = service_id; + svc_rec.service_pkey = service_pkey; + svc_rec.service_gid.unicast.prefix = 0; + svc_rec.service_gid.unicast.interface_id = p_osmt->local_port.port_guid; + svc_rec.service_lease = service_lease; + memset(&svc_rec.service_key, 0, 16 * sizeof(uint8_t)); + memcpy(svc_rec.service_key, service_key, 16 * sizeof(uint8_t)); + memset(svc_rec.service_name, 0, sizeof(svc_rec.service_name)); + memset(skey, 0, 16 * sizeof(uint8_t)); + memcpy(svc_rec.service_name, service_name, + (strlen(service_name) + 1) * sizeof(char)); + + /* prepare the data used for this query */ + /* sa_mad_data.method = IB_MAD_METHOD_SET; */ + /* sa_mad_data.sm_key = 0; */ + + context.p_osmt = p_osmt; + req.query_context = &context; + req.query_type = OSMV_QUERY_USER_DEFINED; + req.pfn_query_cb = osmtest_query_res_cb; + req.p_query_input = &user; + req.flags = OSM_SA_FLAGS_SYNC; + req.sm_key = 0; + req.timeout_ms = p_osmt->opt.transaction_timeout; + + user.method = IB_MAD_METHOD_SET; + user.attr_id = IB_MAD_ATTR_SERVICE_RECORD; + if (ib_pkey_is_invalid(service_pkey)) { + /* if given an invalid service_pkey - don't turn the PKEY compmask on */ + user.comp_mask = IB_SR_COMPMASK_SID | + IB_SR_COMPMASK_SGID | + IB_SR_COMPMASK_SLEASE | + IB_SR_COMPMASK_SKEY | IB_SR_COMPMASK_SNAME; + } else { + user.comp_mask = IB_SR_COMPMASK_SID | + IB_SR_COMPMASK_SGID | + IB_SR_COMPMASK_SPKEY | + IB_SR_COMPMASK_SLEASE | + IB_SR_COMPMASK_SKEY | IB_SR_COMPMASK_SNAME; + } + user.attr_offset = ib_get_attr_offset(sizeof(ib_service_record_t)); + user.p_attr = &svc_rec; + + status = osmv_query_sa(p_osmt->h_bind, &req); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A03: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + goto Exit; + } + + status = context.result.status; + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A04: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + + if (status == IB_REMOTE_ERROR) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "Remote error = %s\n", + ib_get_mad_status_str(osm_madw_get_mad_ptr + (context.result. + p_result_madw))); + } + goto Exit; + } + + /* Check service key on context to see if match */ + p_rec = osmv_get_query_svc_rec(context.result.p_result_madw, 0); + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Comparing service key...\n" "return key is:\n"); + for (i = 0; i <= 15; i++) { + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "service_key sent[%u] = %u, service_key returned[%u] = %u\n", + i, service_key[i], i, p_rec->service_key[i]); + } + /* since c15-0.1.14 not supported all key association queries should bring in return zero in service key */ + if (memcmp(skey, p_rec->service_key, 16 * sizeof(uint8_t)) != 0) { + status = IB_REMOTE_ERROR; + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A33: " + "Data mismatch in service_key\n"); + goto Exit; + } + +Exit: + if (context.result.p_result_madw != NULL) { + osm_mad_pool_put(&p_osmt->mad_pool, + context.result.p_result_madw); + context.result.p_result_madw = NULL; + } + + OSM_LOG_EXIT(&p_osmt->log); + return status; +} + +ib_api_status_t +osmt_register_service_with_data(IN osmtest_t * const p_osmt, + IN ib_net64_t service_id, + IN ib_net16_t service_pkey, + IN ib_net32_t service_lease, + IN uint8_t service_key_lsb, + IN uint8_t * service_data8, + IN ib_net16_t * service_data16, + IN ib_net32_t * service_data32, + IN ib_net64_t * service_data64, + IN char *service_name) +{ + osmv_query_req_t req; + osmv_user_query_t user; + osmtest_req_context_t context; + ib_service_record_t svc_rec, *p_rec; + osm_log_t *p_log = &p_osmt->log; + ib_api_status_t status; + /* ib_service_record_t* p_rec; */ + + OSM_LOG_ENTER(p_log); + + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Registering service: name: %s id: 0x%" PRIx64 "\n", + service_name, cl_ntoh64(service_id)); + + memset(&req, 0, sizeof(req)); + memset(&context, 0, sizeof(context)); + memset(&user, 0, sizeof(user)); + memset(&svc_rec, 0, sizeof(svc_rec)); + + /* set the new service record fields */ + svc_rec.service_id = service_id; + svc_rec.service_pkey = service_pkey; + svc_rec.service_gid.unicast.prefix = 0; + svc_rec.service_gid.unicast.interface_id = p_osmt->local_port.port_guid; + svc_rec.service_lease = service_lease; + memset(&svc_rec.service_key, 0, 16 * sizeof(uint8_t)); + svc_rec.service_key[0] = service_key_lsb; + + /* Copy data to service_data arrays */ + memcpy(svc_rec.service_data8, service_data8, 16 * sizeof(uint8_t)); + memcpy(svc_rec.service_data16, service_data16, 8 * sizeof(ib_net16_t)); + memcpy(svc_rec.service_data32, service_data32, 4 * sizeof(ib_net32_t)); + memcpy(svc_rec.service_data64, service_data64, 2 * sizeof(ib_net64_t)); + + memset(svc_rec.service_name, 0, sizeof(svc_rec.service_name)); + memcpy(svc_rec.service_name, service_name, + (strlen(service_name) + 1) * sizeof(char)); + + /* prepare the data used for this query */ + /* sa_mad_data.method = IB_MAD_METHOD_SET; */ + /* sa_mad_data.sm_key = 0; */ + + context.p_osmt = p_osmt; + req.query_context = &context; + req.query_type = OSMV_QUERY_USER_DEFINED; + req.pfn_query_cb = osmtest_query_res_cb; + req.p_query_input = &user; + req.flags = OSM_SA_FLAGS_SYNC; + req.sm_key = 0; + req.timeout_ms = p_osmt->opt.transaction_timeout; + + user.method = IB_MAD_METHOD_SET; + user.attr_id = IB_MAD_ATTR_SERVICE_RECORD; + if (ib_pkey_is_invalid(service_pkey)) { + /* if given an invalid service_pkey - don't turn the PKEY compmask on */ + user.comp_mask = IB_SR_COMPMASK_SID | + IB_SR_COMPMASK_SGID | + IB_SR_COMPMASK_SLEASE | + IB_SR_COMPMASK_SKEY | + IB_SR_COMPMASK_SNAME | + IB_SR_COMPMASK_SDATA8_0 | + IB_SR_COMPMASK_SDATA8_1 | + IB_SR_COMPMASK_SDATA16_0 | + IB_SR_COMPMASK_SDATA16_1 | + IB_SR_COMPMASK_SDATA32_0 | + IB_SR_COMPMASK_SDATA32_1 | + IB_SR_COMPMASK_SDATA64_0 | IB_SR_COMPMASK_SDATA64_1; + } else { + user.comp_mask = IB_SR_COMPMASK_SID | + IB_SR_COMPMASK_SGID | + IB_SR_COMPMASK_SPKEY | + IB_SR_COMPMASK_SLEASE | + IB_SR_COMPMASK_SKEY | + IB_SR_COMPMASK_SNAME | + IB_SR_COMPMASK_SDATA8_0 | + IB_SR_COMPMASK_SDATA8_1 | + IB_SR_COMPMASK_SDATA16_0 | + IB_SR_COMPMASK_SDATA16_1 | + IB_SR_COMPMASK_SDATA32_0 | + IB_SR_COMPMASK_SDATA32_1 | + IB_SR_COMPMASK_SDATA64_0 | IB_SR_COMPMASK_SDATA64_1; + } + user.attr_offset = ib_get_attr_offset(sizeof(ib_service_record_t)); + user.p_attr = &svc_rec; + + /* Dump to Service Data b4 send */ + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Dumping service data b4 send\n"); + osm_dump_service_record(&p_osmt->log, &svc_rec, OSM_LOG_VERBOSE); + + status = osmv_query_sa(p_osmt->h_bind, &req); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A05: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + goto Exit; + } + + status = context.result.status; + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A06: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + + if (status == IB_REMOTE_ERROR) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "Remote error = %s\n", + ib_get_mad_status_str(osm_madw_get_mad_ptr + (context.result. + p_result_madw))); + } + goto Exit; + } + + /* Check data on context to see if match */ + p_rec = osmv_get_query_svc_rec(context.result.p_result_madw, 0); + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "Comparing service data...\n"); + if (memcmp(service_data8, p_rec->service_data8, 16 * sizeof(uint8_t)) != + 0 + || memcmp(service_data16, p_rec->service_data16, + 8 * sizeof(uint16_t)) != 0 + || memcmp(service_data32, p_rec->service_data32, + 4 * sizeof(uint32_t)) != 0 + || memcmp(service_data64, p_rec->service_data64, + 2 * sizeof(uint64_t)) != 0) { + status = IB_REMOTE_ERROR; + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "Data mismatch in service_data8\n"); + goto Exit; + } + +Exit: + if (context.result.p_result_madw != NULL) { + osm_mad_pool_put(&p_osmt->mad_pool, + context.result.p_result_madw); + context.result.p_result_madw = NULL; + } + + OSM_LOG_EXIT(&p_osmt->log); + return status; +} + +ib_api_status_t +osmt_get_service_by_id_and_name(IN osmtest_t * const p_osmt, + IN uint32_t rec_num, + IN ib_net64_t sid, + IN char *sr_name, + OUT ib_service_record_t * p_out_rec) +{ + + ib_api_status_t status = IB_SUCCESS; + osmtest_req_context_t context; + osmv_query_req_t req; + ib_service_record_t svc_rec, *p_rec; + uint32_t num_recs = 0; + osmv_user_query_t user; + + OSM_LOG_ENTER(&p_osmt->log); + + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Getting service record: id: 0x%016" PRIx64 + " and name: %s\n", cl_ntoh64(sid), sr_name); + + /* + * Do a blocking query for this record in the subnet. + * The result is returned in the result field of the caller's + * context structure. + * + * The query structures are locals. + */ + memset(&req, 0, sizeof(req)); + memset(&context, 0, sizeof(context)); + + context.p_osmt = p_osmt; + + /* prepare the data used for this query */ + req.query_type = OSMV_QUERY_USER_DEFINED; + req.timeout_ms = p_osmt->opt.transaction_timeout; + req.retry_cnt = p_osmt->opt.retry_count; + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = &context; + req.pfn_query_cb = osmtest_query_res_cb; + req.sm_key = 0; + + memset(&svc_rec, 0, sizeof(svc_rec)); + memset(&user, 0, sizeof(user)); + /* set the new service record fields */ + memset(svc_rec.service_name, 0, sizeof(svc_rec.service_name)); + memcpy(svc_rec.service_name, sr_name, + (strlen(sr_name) + 1) * sizeof(char)); + svc_rec.service_id = sid; + req.p_query_input = &user; + + user.method = IB_MAD_METHOD_GET; + user.attr_id = IB_MAD_ATTR_SERVICE_RECORD; + user.comp_mask = IB_SR_COMPMASK_SID | IB_SR_COMPMASK_SNAME; + user.attr_offset = ib_get_attr_offset(sizeof(ib_service_record_t)); + user.p_attr = &svc_rec; + + status = osmv_query_sa(p_osmt->h_bind, &req); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A07: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + goto Exit; + } + + status = context.result.status; + num_recs = context.result.result_cnt; + + if (status != IB_SUCCESS) { + char mad_stat_err[256]; + + /* If the failure is due to IB_SA_MAD_STATUS_NO_RECORDS and rec_num is 0, + then this is fine */ + if (status == IB_REMOTE_ERROR) + strcpy(mad_stat_err, + ib_get_mad_status_str(osm_madw_get_mad_ptr + (context.result. + p_result_madw))); + else + strcpy(mad_stat_err, ib_get_err_str(status)); + if (status == IB_REMOTE_ERROR && + !strcmp(mad_stat_err, "IB_SA_MAD_STATUS_NO_RECORDS") && + rec_num == 0) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "IS EXPECTED ERROR ^^^^\n"); + status = IB_SUCCESS; + } else { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A08: " + "Query failed: %s (%s)\n", + ib_get_err_str(status), mad_stat_err); + goto Exit; + } + } + + if (rec_num && num_recs != rec_num) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "Unmatched number of records: expected: %d, received: %d\n", + rec_num, num_recs); + status = IB_REMOTE_ERROR; + goto Exit; + } + + p_rec = osmv_get_query_svc_rec(context.result.p_result_madw, 0); + *p_out_rec = *p_rec; + + if (num_recs) { + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Found service record: name: %s id: 0x%016" PRIx64 "\n", + p_rec->service_name, cl_ntoh64(p_rec->service_id)); + + osm_dump_service_record(&p_osmt->log, p_rec, OSM_LOG_DEBUG); + } + +Exit: + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Expected and found %d records\n", rec_num); + + if (context.result.p_result_madw != NULL) { + osm_mad_pool_put(&p_osmt->mad_pool, + context.result.p_result_madw); + context.result.p_result_madw = NULL; + } + + OSM_LOG_EXIT(&p_osmt->log); + return status; +} + +ib_api_status_t +osmt_get_service_by_id(IN osmtest_t * const p_osmt, + IN uint32_t rec_num, + IN ib_net64_t sid, OUT ib_service_record_t * p_out_rec) +{ + + ib_api_status_t status = IB_SUCCESS; + osmtest_req_context_t context; + osmv_query_req_t req; + ib_service_record_t svc_rec, *p_rec; + uint32_t num_recs = 0; + osmv_user_query_t user; + + OSM_LOG_ENTER(&p_osmt->log); + + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Getting service record: id: 0x%016" PRIx64 "\n", + cl_ntoh64(sid)); + + /* + * Do a blocking query for this record in the subnet. + * The result is returned in the result field of the caller's + * context structure. + * + * The query structures are locals. + */ + memset(&req, 0, sizeof(req)); + memset(&context, 0, sizeof(context)); + + context.p_osmt = p_osmt; + + /* prepare the data used for this query */ + req.query_type = OSMV_QUERY_USER_DEFINED; + req.timeout_ms = p_osmt->opt.transaction_timeout; + req.retry_cnt = p_osmt->opt.retry_count; + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = &context; + req.pfn_query_cb = osmtest_query_res_cb; + req.sm_key = 0; + + memset(&svc_rec, 0, sizeof(svc_rec)); + memset(&user, 0, sizeof(user)); + /* set the new service record fields */ + svc_rec.service_id = sid; + req.p_query_input = &user; + + user.method = IB_MAD_METHOD_GET; + user.attr_id = IB_MAD_ATTR_SERVICE_RECORD; + user.comp_mask = IB_SR_COMPMASK_SID; + user.attr_offset = ib_get_attr_offset(sizeof(ib_service_record_t)); + user.p_attr = &svc_rec; + + status = osmv_query_sa(p_osmt->h_bind, &req); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A09: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + goto Exit; + } + + status = context.result.status; + num_recs = context.result.result_cnt; + + if (status != IB_SUCCESS) { + char mad_stat_err[256]; + + /* If the failure is due to IB_SA_MAD_STATUS_NO_RECORDS and rec_num is 0, + then this is fine */ + if (status == IB_REMOTE_ERROR) + strcpy(mad_stat_err, + ib_get_mad_status_str(osm_madw_get_mad_ptr + (context.result. + p_result_madw))); + else + strcpy(mad_stat_err, ib_get_err_str(status)); + + if (status == IB_REMOTE_ERROR && + !strcmp(mad_stat_err, "IB_SA_MAD_STATUS_NO_RECORDS") && + rec_num == 0) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "IS EXPECTED ERROR ^^^^\n"); + status = IB_SUCCESS; + } else { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A0A: " + "Query failed: %s (%s)\n", + ib_get_err_str(status), mad_stat_err); + goto Exit; + } + } + + if (rec_num && num_recs != rec_num) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A0B: " + "Unmatched number of records: expected: %d received: %d\n", + rec_num, num_recs); + status = IB_REMOTE_ERROR; + goto Exit; + } + + p_rec = osmv_get_query_svc_rec(context.result.p_result_madw, 0); + *p_out_rec = *p_rec; + + if (num_recs) { + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Found service record: name: %s id: 0x%016" PRIx64 "\n", + p_rec->service_name, cl_ntoh64(p_rec->service_id)); + + osm_dump_service_record(&p_osmt->log, p_rec, OSM_LOG_DEBUG); + } + +Exit: + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Expected and found %d records\n", rec_num); + + if (context.result.p_result_madw != NULL) { + osm_mad_pool_put(&p_osmt->mad_pool, + context.result.p_result_madw); + context.result.p_result_madw = NULL; + } + + OSM_LOG_EXIT(&p_osmt->log); + return status; +} + +ib_api_status_t +osmt_get_service_by_name_and_key(IN osmtest_t * const p_osmt, + IN char *sr_name, + IN uint32_t rec_num, + IN uint8_t * skey, + OUT ib_service_record_t * p_out_rec) +{ + + ib_api_status_t status = IB_SUCCESS; + osmtest_req_context_t context; + osmv_query_req_t req; + ib_service_record_t svc_rec, *p_rec; + uint32_t num_recs = 0, i; + osmv_user_query_t user; + + OSM_LOG_ENTER(&p_osmt->log); + + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Getting service record: name: %s and key: " + "0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", + sr_name, skey[0], skey[1], skey[2], skey[3], skey[4], skey[5], + skey[6], skey[7], skey[8], skey[9], skey[10], skey[11], + skey[12], skey[13], skey[14], skey[15]); + + /* + * Do a blocking query for this record in the subnet. + * The result is returned in the result field of the caller's + * context structure. + * + * The query structures are locals. + */ + memset(&req, 0, sizeof(req)); + memset(&context, 0, sizeof(context)); + + context.p_osmt = p_osmt; + + /* prepare the data used for this query */ + req.query_type = OSMV_QUERY_USER_DEFINED; + req.timeout_ms = p_osmt->opt.transaction_timeout; + req.retry_cnt = p_osmt->opt.retry_count; + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = &context; + req.pfn_query_cb = osmtest_query_res_cb; + req.sm_key = 0; + + memset(&svc_rec, 0, sizeof(svc_rec)); + memset(&user, 0, sizeof(user)); + /* set the new service record fields */ + memset(svc_rec.service_name, 0, sizeof(svc_rec.service_name)); + memcpy(svc_rec.service_name, sr_name, + (strlen(sr_name) + 1) * sizeof(char)); + for (i = 0; i <= 15; i++) + svc_rec.service_key[i] = skey[i]; + + req.p_query_input = &user; + + user.method = IB_MAD_METHOD_GET; + user.attr_id = IB_MAD_ATTR_SERVICE_RECORD; + user.comp_mask = IB_SR_COMPMASK_SNAME | IB_SR_COMPMASK_SKEY; + user.attr_offset = ib_get_attr_offset(sizeof(ib_service_record_t)); + user.p_attr = &svc_rec; + status = osmv_query_sa(p_osmt->h_bind, &req); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A0C: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + goto Exit; + } + + status = context.result.status; + num_recs = context.result.result_cnt; + + if (status != IB_SUCCESS) { + char mad_stat_err[256]; + + /* If the failure is due to IB_SA_MAD_STATUS_NO_RECORDS and rec_num is 0, + then this is fine */ + if (status == IB_REMOTE_ERROR) + strcpy(mad_stat_err, + ib_get_mad_status_str(osm_madw_get_mad_ptr + (context.result. + p_result_madw))); + else + strcpy(mad_stat_err, ib_get_err_str(status)); + + if (status == IB_REMOTE_ERROR && + !strcmp(mad_stat_err, "IB_SA_MAD_STATUS_NO_RECORDS") && + rec_num == 0) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "IS EXPECTED ERROR ^^^^\n"); + status = IB_SUCCESS; + } else { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A0D: " + "Query failed:%s (%s)\n", + ib_get_err_str(status), mad_stat_err); + goto Exit; + } + } + + if (rec_num && num_recs != rec_num) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "Unmatched number of records: expected: %d, received: %d\n", + rec_num, num_recs); + status = IB_REMOTE_ERROR; + goto Exit; + } + + p_rec = osmv_get_query_svc_rec(context.result.p_result_madw, 0); + *p_out_rec = *p_rec; + + if (num_recs) { + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Found service record: name: %s id: 0x%016" PRIx64 "\n", + sr_name, cl_ntoh64(p_rec->service_id)); + + osm_dump_service_record(&p_osmt->log, p_rec, OSM_LOG_DEBUG); + } + +Exit: + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Expected and found %d records\n", rec_num); + + if (context.result.p_result_madw != NULL) { + osm_mad_pool_put(&p_osmt->mad_pool, + context.result.p_result_madw); + context.result.p_result_madw = NULL; + } + + OSM_LOG_EXIT(&p_osmt->log); + return status; +} + +ib_api_status_t +osmt_get_service_by_name(IN osmtest_t * const p_osmt, + IN char *sr_name, + IN uint32_t rec_num, + OUT ib_service_record_t * p_out_rec) +{ + + ib_api_status_t status = IB_SUCCESS; + osmtest_req_context_t context; + osmv_query_req_t req; + ib_service_record_t *p_rec; + ib_svc_name_t service_name; + uint32_t num_recs = 0; + + OSM_LOG_ENTER(&p_osmt->log); + + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Getting service record: name: %s\n", sr_name); + + /* + * Do a blocking query for this record in the subnet. + * The result is returned in the result field of the caller's + * context structure. + * + * The query structures are locals. + */ + memset(&req, 0, sizeof(req)); + memset(&context, 0, sizeof(context)); + + context.p_osmt = p_osmt; + + /* prepare the data used for this query */ + req.query_type = OSMV_QUERY_SVC_REC_BY_NAME; + req.timeout_ms = p_osmt->opt.transaction_timeout; + req.retry_cnt = p_osmt->opt.retry_count; + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = &context; + req.pfn_query_cb = osmtest_query_res_cb; + req.sm_key = 0; + + memset(service_name, 0, sizeof(service_name)); + memcpy(service_name, sr_name, (strlen(sr_name) + 1) * sizeof(char)); + req.p_query_input = service_name; + + status = osmv_query_sa(p_osmt->h_bind, &req); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A0E: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + goto Exit; + } + + status = context.result.status; + num_recs = context.result.result_cnt; + + if (status != IB_SUCCESS) { + char mad_stat_err[256]; + + /* If the failure is due to IB_SA_MAD_STATUS_NO_RECORDS and rec_num is 0, + then this is fine */ + if (status == IB_REMOTE_ERROR) + strcpy(mad_stat_err, + ib_get_mad_status_str(osm_madw_get_mad_ptr + (context.result. + p_result_madw))); + else + strcpy(mad_stat_err, ib_get_err_str(status)); + + if (status == IB_REMOTE_ERROR && + !strcmp(mad_stat_err, "IB_SA_MAD_STATUS_NO_RECORDS") && + rec_num == 0) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "IS EXPECTED ERROR ^^^^\n"); + status = IB_SUCCESS; + } else { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A0F: " + "Query failed: %s (%s)\n", + ib_get_err_str(status), mad_stat_err); + goto Exit; + } + } + + if (rec_num && num_recs != rec_num) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A10: " + "Unmatched number of records: expected: %d, received: %d\n", + rec_num, num_recs); + status = IB_REMOTE_ERROR; + goto Exit; + } + + p_rec = osmv_get_query_svc_rec(context.result.p_result_madw, 0); + *p_out_rec = *p_rec; + + if (num_recs) { + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Found service record: name: %s id: 0x%016" PRIx64 "\n", + sr_name, cl_ntoh64(p_rec->service_id)); + + osm_dump_service_record(&p_osmt->log, p_rec, OSM_LOG_DEBUG); + } + +Exit: + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Expected and found %d records\n", rec_num); + + if (context.result.p_result_madw != NULL) { + osm_mad_pool_put(&p_osmt->mad_pool, + context.result.p_result_madw); + context.result.p_result_madw = NULL; + } + + OSM_LOG_EXIT(&p_osmt->log); + return status; +} + +#ifdef VENDOR_RMPP_SUPPORT +ib_api_status_t +osmt_get_all_services_and_check_names(IN osmtest_t * const p_osmt, + IN ib_svc_name_t * + const p_valid_service_names_arr, + IN uint8_t num_of_valid_names, + OUT uint32_t * num_services) +{ + ib_api_status_t status = IB_SUCCESS; + osmtest_req_context_t context; + osmv_query_req_t req; + ib_service_record_t *p_rec; + uint32_t num_recs = 0, i, j; + uint8_t *p_checked_names; + + OSM_LOG_ENTER(&p_osmt->log); + + /* Prepare tracker for the checked names */ + p_checked_names = + (uint8_t *) malloc(sizeof(uint8_t) * num_of_valid_names); + for (j = 0; j < num_of_valid_names; j++) { + p_checked_names[j] = 0; + } + + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "Getting all service records\n"); + + /* + * Do a blocking query for this record in the subnet. + * The result is returned in the result field of the caller's + * context structure. + * + * The query structures are locals. + */ + memset(&req, 0, sizeof(req)); + memset(&context, 0, sizeof(context)); + + context.p_osmt = p_osmt; + + req.query_type = OSMV_QUERY_ALL_SVC_RECS; + req.timeout_ms = p_osmt->opt.transaction_timeout; + req.retry_cnt = p_osmt->opt.retry_count; + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = &context; + req.pfn_query_cb = osmtest_query_res_cb; + req.sm_key = 0; + + status = osmv_query_sa(p_osmt->h_bind, &req); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A12: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + goto Exit; + } + + status = context.result.status; + + if (status != IB_SUCCESS) { + if (status != IB_INVALID_PARAMETER) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A13: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + } + if (status == IB_REMOTE_ERROR) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "Remote error = %s\n", + ib_get_mad_status_str(osm_madw_get_mad_ptr + (context.result. + p_result_madw))); + } + goto Exit; + } + + num_recs = context.result.result_cnt; + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Received %u records\n", num_recs); + + for (i = 0; i < num_recs; i++) { + p_rec = osmv_get_query_svc_rec(context.result.p_result_madw, i); + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Found service record: name: %s id: 0x%016" PRIx64 "\n", + p_rec->service_name, cl_ntoh64(p_rec->service_id)); + osm_dump_service_record(&p_osmt->log, p_rec, OSM_LOG_VERBOSE); + for (j = 0; j < num_of_valid_names; j++) { + /* If the service names exist in the record, mark it as checked (1) */ + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "-I- Comparing source name : >%s<, with record name : >%s<, idx : %d\n", + p_valid_service_names_arr[j], + p_rec->service_name, p_checked_names[j]); + if (strcmp + ((char *)p_valid_service_names_arr[j], + (char *)p_rec->service_name) == 0) { + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "-I- The service %s is valid\n", + p_valid_service_names_arr[j]); + p_checked_names[j] = 1; + break; + } + } + } + /* Check that all service names have been identified */ + for (j = 0; j < num_of_valid_names; j++) + if (p_checked_names[j] == 0) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A14: " + "Missing valid service: name: %s\n", + p_valid_service_names_arr[j]); + status = IB_ERROR; + goto Exit; + } + *num_services = num_recs; + +Exit: + if (context.result.p_result_madw != NULL) { + osm_mad_pool_put(&p_osmt->mad_pool, + context.result.p_result_madw); + context.result.p_result_madw = NULL; + } + + OSM_LOG_EXIT(&p_osmt->log); + return status; +} +#endif + +ib_api_status_t +osmt_delete_service_by_name(IN osmtest_t * const p_osmt, + IN uint8_t IsServiceExist, + IN char *sr_name, IN uint32_t rec_num) +{ + osmv_query_req_t req; + osmv_user_query_t user; + osmtest_req_context_t context; + ib_service_record_t svc_rec; + ib_api_status_t status; + + OSM_LOG_ENTER(&p_osmt->log); + + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Trying to Delete service name: %s\n", sr_name); + + memset(&svc_rec, 0, sizeof(svc_rec)); + + status = osmt_get_service_by_name(p_osmt, sr_name, rec_num, &svc_rec); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A15: " + "Failed to get service: name: %s\n", sr_name); + goto ExitNoDel; + } + + memset(&req, 0, sizeof(req)); + memset(&context, 0, sizeof(context)); + memset(&user, 0, sizeof(user)); + + /* set the new service record fields */ + memset(svc_rec.service_name, 0, sizeof(svc_rec.service_name)); + memcpy(svc_rec.service_name, sr_name, + (strlen(sr_name) + 1) * sizeof(char)); + + /* prepare the data used for this query */ + context.p_osmt = p_osmt; + req.timeout_ms = p_osmt->opt.transaction_timeout; + req.query_context = &context; + req.query_type = OSMV_QUERY_USER_DEFINED; /* basically a don't care here */ + req.pfn_query_cb = osmtest_query_res_cb; + req.p_query_input = &user; + req.flags = OSM_SA_FLAGS_SYNC; + req.sm_key = 0; + + user.method = IB_MAD_METHOD_DELETE; + user.attr_id = IB_MAD_ATTR_SERVICE_RECORD; + user.comp_mask = IB_SR_COMPMASK_SNAME; + user.attr_offset = ib_get_attr_offset(sizeof(ib_service_record_t)); + user.p_attr = &svc_rec; + + status = osmv_query_sa(p_osmt->h_bind, &req); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A16: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + goto Exit; + } + + status = context.result.status; + if (IsServiceExist) { + /* If IsServiceExist = 1 then we should succeed here */ + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A17: " + "ib_query failed (%s)\n", + ib_get_err_str(status)); + + if (status == IB_REMOTE_ERROR) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "ERR 4A18: Remote error = %s\n", + ib_get_mad_status_str + (osm_madw_get_mad_ptr + (context.result.p_result_madw))); + } + } + } else { + /* If IsServiceExist = 0 then we should fail here */ + if (status == IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A19: " + "Succeeded to delete service: %s which " + "shouldn't exist", sr_name); + status = IB_ERROR; + } else { + /* The deletion should have failed, since the service_name + shouldn't exist. */ + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "IS EXPECTED ERROR ^^^^\n"); + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Failed to delete service_name: %s\n", sr_name); + status = IB_SUCCESS; + } + } + +Exit: + if (context.result.p_result_madw != NULL) { + osm_mad_pool_put(&p_osmt->mad_pool, + context.result.p_result_madw); + context.result.p_result_madw = NULL; + } + +ExitNoDel: + OSM_LOG_EXIT(&p_osmt->log); + return status; +} + +/* + * Run a complete service records flow: + * - register a service + * - register a service (with a lease period) + * - get a service by name + * - get all services / must be 2 + * - delete a service + * - get all services / must be 1 + * - wait for the lease to expire + * - get all services / must be 0 + * - get / set service by data + */ +ib_api_status_t osmt_run_service_records_flow(IN osmtest_t * const p_osmt) +{ + ib_service_record_t srv_rec; + ib_api_status_t status; + uint8_t instance, i; + uint8_t service_data8[16], service_key[16]; + ib_net16_t service_data16[8]; + ib_net32_t service_data32[4]; + ib_net64_t service_data64[2]; + uint64_t pid = getpid(); + uint64_t id[7]; + /* We use up to seven service names - we use the extra for bad flow */ + ib_svc_name_t service_name[7]; +#ifdef VENDOR_RMPP_SUPPORT + /* This array contain only the valid names after registering vs SM */ + ib_svc_name_t service_valid_names[3]; + uint32_t num_recs = 0; +#endif + + OSM_LOG_ENTER(&p_osmt->log); + + /* Init Service names */ + for (i = 0; i < 7; i++) { +#ifdef __WIN__ + uint64_t rand_val = rand() - (uint64_t) i; +#else + uint64_t rand_val = random() - (uint64_t) i; +#endif + id[i] = abs((int)(pid - rand_val)); + /* Just to be unique any place on any host */ + sprintf((char *)(service_name[i]), + "osmt.srvc.%" PRIu64 ".%" PRIu64, rand_val, pid); + /*printf("-I- Service Name is : %s, ID is : 0x%" PRIx64 "\n",service_name[i],id[i]); */ + } + + status = osmt_register_service(p_osmt, cl_ntoh64(id[0]), /* IN ib_net64_t service_id, */ + IB_DEFAULT_PKEY, /* IN ib_net16_t service_pkey, */ + 0xFFFFFFFF, /* IN ib_net32_t service_lease, */ + 11, /* IN uint8_t service_key_lsb, */ + (char *)service_name[0] /* IN char *service_name */ + ); + if (status != IB_SUCCESS) { + goto Exit; + } + + status = osmt_register_service(p_osmt, cl_ntoh64(id[1]), /* IN ib_net64_t service_id, */ + IB_DEFAULT_PKEY, /* IN ib_net16_t service_pkey, */ + cl_hton32(0x00000004), /* IN ib_net32_t service_lease, */ + 11, /* IN uint8_t service_key_lsb, */ + (char *)service_name[1] /* IN char *service_name */ + ); + if (status != IB_SUCCESS) { + goto Exit; + } + + status = osmt_register_service(p_osmt, cl_ntoh64(id[2]), /* IN ib_net64_t service_id, */ + 0, /* IN ib_net16_t service_pkey, */ + 0xFFFFFFFF, /* IN ib_net32_t service_lease, */ + 11, /* Remove Service Record IN uint8_t service_key_lsb, */ + (char *)service_name[2] /* IN char *service_name */ + ); + + if (status != IB_SUCCESS) { + goto Exit; + } + + /* Generate 2 instances of service record with consecutive data */ + for (instance = 0; instance < 2; instance++) { + /* First, clear all arrays */ + memset(service_data8, 0, 16 * sizeof(uint8_t)); + memset(service_data16, 0, 8 * sizeof(uint16_t)); + memset(service_data32, 0, 4 * sizeof(uint32_t)); + memset(service_data64, 0, 2 * sizeof(uint64_t)); + service_data8[instance] = instance + 1; + service_data16[instance] = cl_hton16(instance + 2); + service_data32[instance] = cl_hton32(instance + 3); + service_data64[instance] = cl_hton64(instance + 4); + status = osmt_register_service_with_data(p_osmt, cl_ntoh64(id[3]), /* IN ib_net64_t service_id, */ + IB_DEFAULT_PKEY, /* IN ib_net16_t service_pkey, */ + cl_ntoh32(10), /* IN ib_net32_t service_lease, */ + 12, /* IN uint8_t service_key_lsb, */ + service_data8, service_data16, service_data32, service_data64, /* service data structures */ + (char *)service_name[3] /* IN char *service_name */ + ); + + if (status != IB_SUCCESS) { + goto Exit; + } + + } + + /* Trying to create service with zero key */ + memset(service_key, 0, 16 * sizeof(uint8_t)); + status = osmt_register_service_with_full_key(p_osmt, cl_ntoh64(id[5]), /* IN ib_net64_t service_id, */ + 0, /* IN ib_net16_t service_pkey, */ + 0xFFFFFFFF, /* IN ib_net32_t service_lease, */ + service_key, /* full service_key, */ + (char *)service_name[5] /* IN char *service_name */ + ); + + if (status != IB_SUCCESS) { + goto Exit; + } + + /* Now update it with Unique key and different service name */ + for (i = 0; i <= 15; i++) { + service_key[i] = i + 1; + } + status = osmt_register_service_with_full_key(p_osmt, cl_ntoh64(id[5]), /* IN ib_net64_t service_id, */ + 0, /* IN ib_net16_t service_pkey, */ + 0xFFFFFFFF, /* IN ib_net32_t service_lease, */ + service_key, /* full service_key, */ + (char *)service_name[6] /* IN char *service_name */ + ); + if (status != IB_SUCCESS) { + goto Exit; + } + + /* Let OpenSM handle it */ + usleep(100); + + /* Make sure service_name[0] exists */ + status = osmt_get_service_by_name(p_osmt, + (char *)service_name[0], 1, &srv_rec); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A1A: " + "Fail to find service: name: %s\n", + (char *)service_name[0]); + status = IB_ERROR; + goto Exit; + } + + /* Make sure service_name[1] exists */ + status = osmt_get_service_by_name(p_osmt, + (char *)service_name[1], 1, &srv_rec); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A1B: " + "Fail to find service: name: %s\n", + (char *)service_name[1]); + status = IB_ERROR; + goto Exit; + } + + /* Make sure service_name[2] exists */ + status = osmt_get_service_by_name(p_osmt, + (char *)service_name[2], 1, &srv_rec); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A1C: " + "Fail to find service: name: %s\n", + (char *)service_name[2]); + status = IB_ERROR; + goto Exit; + } + + /* Make sure service_name[3] exists. */ + /* After 10 seconds the service should not exist: service_lease = 10 */ + status = osmt_get_service_by_name(p_osmt, + (char *)service_name[3], 1, &srv_rec); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A1D: " + "Fail to find service: name: %s\n", + (char *)service_name[3]); + status = IB_ERROR; + goto Exit; + } + + sleep(10); + + status = osmt_get_service_by_name(p_osmt, + (char *)service_name[3], 0, &srv_rec); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A1E: " + "Found service: name: %s that should have been " + "deleted due to service lease expiring\n", + (char *)service_name[3]); + status = IB_ERROR; + goto Exit; + } + + /* Check that for service: id[5] only one record exists */ + status = osmt_get_service_by_id(p_osmt, 1, cl_ntoh64(id[5]), &srv_rec); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A1F: " + "Found number of records != 1 for " + "service: id: 0x%016" PRIx64 "\n", id[5]); + status = IB_ERROR; + goto Exit; + } + + /* Bad Flow of Get with invalid Service ID: id[6] */ + status = osmt_get_service_by_id(p_osmt, 0, cl_ntoh64(id[6]), &srv_rec); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A20: " + "Found service: id: 0x%016" PRIx64 " " + "that is invalid\n", id[6]); + status = IB_ERROR; + goto Exit; + } + + /* Check by both id and service name: id[0], service_name[0] */ + status = osmt_get_service_by_id_and_name(p_osmt, 1, cl_ntoh64(id[0]), + (char *)service_name[0], + &srv_rec); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A21: " + "Fail to find service: id: 0x%016" PRIx64 " " + "name: %s\n", id[0], (char *)service_name[0]); + status = IB_ERROR; + goto Exit; + } + + /* Check by both id and service name: id[5], service_name[6] */ + status = osmt_get_service_by_id_and_name(p_osmt, 1, cl_ntoh64(id[5]), + (char *)service_name[6], + &srv_rec); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A22: " + "Fail to find service: id: 0x%016" PRIx64 " " + "name: %s\n", id[5], (char *)service_name[6]); + status = IB_ERROR; + goto Exit; + } + + /* Bad Flow of Get with invalid name(service_name[3]) and valid ID(id[0]) */ + status = osmt_get_service_by_id_and_name(p_osmt, 0, cl_ntoh64(id[0]), + (char *)service_name[3], + &srv_rec); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A23: " + "Found service: id: 0x%016" PRIx64 + "name: %s which is an invalid service\n", + id[0], (char *)service_name[3]); + status = IB_ERROR; + goto Exit; + } + + /* Bad Flow of Get with unmatched name(service_name[5]) and id(id[3]) (both valid) */ + status = osmt_get_service_by_id_and_name(p_osmt, 0, cl_ntoh64(id[3]), + (char *)service_name[5], + &srv_rec); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A24: " + "Found service: id: 0x%016" PRIx64 + "name: %s which is an invalid service\n", + id[3], (char *)service_name[5]); + status = IB_ERROR; + goto Exit; + } + + /* Bad Flow of Get with service name that doesn't exist (service_name[4]) */ + status = osmt_get_service_by_name(p_osmt, + (char *)service_name[4], 0, &srv_rec); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A25: " + "Found service: name: %s that shouldn't exist\n", + (char *)service_name[4]); + status = IB_ERROR; + goto Exit; + } + + /* Bad Flow : Check that getting service_name[5] brings no records since another service + has been updated with the same ID (service_name[6] */ + status = osmt_get_service_by_name(p_osmt, + (char *)service_name[5], 0, &srv_rec); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A26: " + "Found service: name: %s which is an " + "invalid service\n", (char *)service_name[5]); + status = IB_ERROR; + goto Exit; + } + + /* Check that getting service_name[6] by name ONLY is valid, + since we do not support key&name association, also trusted queries */ + status = osmt_get_service_by_name(p_osmt, + (char *)service_name[6], 1, &srv_rec); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A27: " + "Fail to find service: name: %s\n", + (char *)service_name[6]); + status = IB_ERROR; + goto Exit; + } + + /* Test Service Key */ + memset(service_key, 0, 16 * sizeof(uint8_t)); + + /* Check for service_name[5] with service_key=0 - the service shouldn't + exist with this name. */ + status = osmt_get_service_by_name_and_key(p_osmt, + (char *)service_name[5], + 0, service_key, &srv_rec); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A28: " + "Found service: name: %s key:0 which is an " + "invalid service (wrong name)\n", + (char *)service_name[5]); + status = IB_ERROR; + goto Exit; + } + + /* Check for service_name[6] with service_key=0 - the service should + exist with different key. */ + status = osmt_get_service_by_name_and_key(p_osmt, + (char *)service_name[6], + 0, service_key, &srv_rec); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A29: " + "Found service: name: %s key: 0 which is an " + "invalid service (wrong service_key)\n", + (char *)service_name[6]); + status = IB_ERROR; + goto Exit; + } + + /* check for service_name[6] with the correct service_key */ + for (i = 0; i <= 15; i++) + service_key[i] = i + 1; + status = osmt_get_service_by_name_and_key(p_osmt, + (char *)service_name[6], + 1, service_key, &srv_rec); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A2A: " + "Fail to find service: name: %s with " + "correct service key\n", (char *)service_name[6]); + status = IB_ERROR; + goto Exit; + } +#ifdef VENDOR_RMPP_SUPPORT + /* These ar the only service_names which are valid */ + memcpy(&service_valid_names[0], &service_name[0], sizeof(uint8_t) * 64); + memcpy(&service_valid_names[1], &service_name[2], sizeof(uint8_t) * 64); + memcpy(&service_valid_names[2], &service_name[6], sizeof(uint8_t) * 64); + + status = + osmt_get_all_services_and_check_names(p_osmt, service_valid_names, + 3, &num_recs); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A2B: " + "Fail to find all services that should exist\n"); + status = IB_ERROR; + goto Exit; + } +#endif + + /* Delete service_name[0] */ + status = osmt_delete_service_by_name(p_osmt, 1, + (char *)service_name[0], 1); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A2C: " + "Fail to delete service: name: %s\n", + (char *)service_name[0]); + status = IB_ERROR; + goto Exit; + } + + /* Make sure deletion of service_name[0] succeeded */ + status = osmt_get_service_by_name(p_osmt, + (char *)service_name[0], 0, &srv_rec); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A2D: " + "Found service: name: %s that was deleted\n", + (char *)service_name[0]); + status = IB_ERROR; + goto Exit; + } + + /* Make sure service_name[1] doesn't exist (expired service lease) */ + status = osmt_get_service_by_name(p_osmt, + (char *)service_name[1], 0, &srv_rec); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A2E: " + "Found service: name: %s that should have expired\n", + (char *)service_name[1]); + status = IB_ERROR; + goto Exit; + } + + /* Make sure service_name[2] exists */ + status = osmt_get_service_by_name(p_osmt, + (char *)service_name[2], 1, &srv_rec); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A2F: " + "Fail to find service: name: %s\n", + (char *)service_name[2]); + status = IB_ERROR; + goto Exit; + } + + /* Bad Flow - try to delete non-existent service_name[5] */ + status = osmt_delete_service_by_name(p_osmt, 0, + (char *)service_name[5], 0); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A30: " + "Succeed to delete non-existent service: name: %s\n", + (char *)service_name[5]); + status = IB_ERROR; + goto Exit; + } + + /* Delete service_name[2] */ + status = osmt_delete_service_by_name(p_osmt, 1, + (char *)service_name[2], 1); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A31: " + "Fail to delete service: name: %s\n", + (char *)service_name[2]); + status = IB_ERROR; + goto Exit; + } + + /* Delete service_name[6] */ + status = osmt_delete_service_by_name(p_osmt, 1, + (char *)service_name[6], 1); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A32: " + "Failed to delete service name: %s\n", + (char *)service_name[6]); + goto Exit; + } + +Exit: + OSM_LOG_EXIT(&p_osmt->log); + return status; +} diff --git a/branches/WOF2-3/ulp/opensm/user/osmtest/osmt_slvl_vl_arb.c b/branches/WOF2-3/ulp/opensm/user/osmtest/osmt_slvl_vl_arb.c new file mode 100644 index 00000000..e82e7d8d --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/osmtest/osmt_slvl_vl_arb.c @@ -0,0 +1,526 @@ +/* + * Copyright (c) 2006-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of SLtoVL and VL Arbitration testing flow.. + * Top level is osmt_run_slvl_and_vlarb_records_flow: + * osmt_query_all_ports_vl_arb + * osmt_query_all_ports_slvl_map + * + */ + +#ifndef __WIN__ +#include +#endif +#include +#include +#include +#include +#include "osmtest.h" + +static ib_api_status_t +osmtest_write_vl_arb_table(IN osmtest_t * const p_osmt, + IN FILE * fh, + IN const ib_vl_arb_table_record_t * const p_rec) +{ + int result, i; + cl_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER(&p_osmt->log); + + result = fprintf(fh, + "VL_ARBITRATION_TABLE\n" + "lid 0x%X\n" + "port_num 0x%X\n" + "block 0x%X\n", + cl_ntoh16(p_rec->lid), + p_rec->port_num, p_rec->block_num); + + fprintf(fh, " "); + for (i = 0; i < 32; i++) + fprintf(fh, "| %-2u ", i); + fprintf(fh, "|\nVL: "); + + for (i = 0; i < 32; i++) + fprintf(fh, "|0x%02X", p_rec->vl_arb_tbl.vl_entry[i].vl); + fprintf(fh, "|\nWEIGHT:"); + + for (i = 0; i < 32; i++) + fprintf(fh, "|0x%02X", p_rec->vl_arb_tbl.vl_entry[i].weight); + fprintf(fh, "|\nEND\n\n"); + + /* Exit: */ + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + * GET A SINGLE PORT INFO BY NODE LID AND PORT NUMBER + **********************************************************************/ +ib_api_status_t +osmt_query_vl_arb(IN osmtest_t * const p_osmt, + IN ib_net16_t const lid, + IN uint8_t const port_num, + IN uint8_t const block_num, IN FILE * fh) +{ + osmtest_req_context_t context; + ib_api_status_t status = IB_SUCCESS; + osmv_user_query_t user; + osmv_query_req_t req; + ib_vl_arb_table_record_t record, *p_rec; + + OSM_LOG_ENTER(&p_osmt->log); + + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "Getting VL_Arbitration Table for port with LID 0x%X Num:0x%X\n", + cl_ntoh16(lid), port_num); + + /* + * Do a blocking query for this record in the subnet. + * The result is returned in the result field of the caller's + * context structure. + * + * The query structures are locals. + */ + memset(&req, 0, sizeof(req)); + memset(&user, 0, sizeof(user)); + memset(&context, 0, sizeof(context)); + + context.p_osmt = p_osmt; + + record.lid = lid; + record.port_num = port_num; + record.block_num = block_num; + user.p_attr = &record; + + req.query_type = OSMV_QUERY_VLARB_BY_LID_PORT_BLOCK; + req.timeout_ms = p_osmt->opt.transaction_timeout; + req.retry_cnt = p_osmt->opt.retry_count; + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = &context; + req.pfn_query_cb = osmtest_query_res_cb; + req.p_query_input = &user; + req.sm_key = 0; + + status = osmv_query_sa(p_osmt->h_bind, &req); + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0405: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + goto Exit; + } + + status = context.result.status; + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0466: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + + if (status == IB_REMOTE_ERROR) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "Remote error = %s\n", + ib_get_mad_status_str(osm_madw_get_mad_ptr + (context.result. + p_result_madw))); + } + goto Exit; + } + + /* ok it worked */ + p_rec = osmv_get_query_result(context.result.p_result_madw, 0); + if (fh) { + osmtest_write_vl_arb_table(p_osmt, fh, p_rec); + } + +Exit: + /* + * Return the IB query MAD to the pool as necessary. + */ + if (context.result.p_result_madw != NULL) { + osm_mad_pool_put(&p_osmt->mad_pool, + context.result.p_result_madw); + context.result.p_result_madw = NULL; + } + + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +static ib_api_status_t +osmt_query_all_ports_vl_arb(IN osmtest_t * const p_osmt, IN FILE * fh) +{ + cl_status_t status = CL_SUCCESS; + cl_qmap_t *p_tbl; + port_t *p_src_port; + uint8_t block, anyErr = 0; + + OSM_LOG_ENTER(&p_osmt->log); + + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Obtaining ALL Ports VL Arbitration Tables\n"); + + /* + * Go over all ports that exist in the subnet + * get the relevant VLarbs + */ + + p_tbl = &p_osmt->exp_subn.port_key_tbl; + + p_src_port = (port_t *) cl_qmap_head(p_tbl); + + while (p_src_port != (port_t *) cl_qmap_end(p_tbl)) { + + /* HACK we use capability_mask to know diff a CA port from switch port */ + if (p_src_port->rec.port_info.capability_mask) { + /* this is an hca port */ + for (block = 1; block <= 4; block++) { + /* NOTE to comply we must set port number to 0 and the SA should figure it out */ + /* since it is a CA port */ + status = + osmt_query_vl_arb(p_osmt, + p_src_port->rec.lid, 0, + block, fh); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "ERR 0467: " + "Failed to get Lid:0x%X Port:0x%X (%s)\n", + cl_ntoh16(p_src_port->rec.lid), + 0, ib_get_err_str(status)); + anyErr = 1; + } + } + } else { + /* this is a switch port */ + for (block = 1; block <= 4; block++) { + status = + osmt_query_vl_arb(p_osmt, + p_src_port->rec.lid, + p_src_port->rec.port_num, + block, fh); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "ERR 0468: " + "Failed to get Lid:0x%X Port:0x%X (%s)\n", + cl_ntoh16(p_src_port->rec.lid), + p_src_port->rec.port_num, + ib_get_err_str(status)); + anyErr = 1; + } + } + } + + p_src_port = (port_t *) cl_qmap_next(&p_src_port->map_item); + } + + OSM_LOG_EXIT(&p_osmt->log); + if (anyErr) { + status = IB_ERROR; + } + return (status); +} + +/******************************************************************************* + SLtoVL +*******************************************************************************/ +static ib_api_status_t +osmtest_write_slvl_map_table(IN osmtest_t * const p_osmt, + IN FILE * fh, + IN const ib_slvl_table_record_t * const p_rec) +{ + int result, i; + cl_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER(&p_osmt->log); + + result = fprintf(fh, + "SLtoVL_MAP_TABLE\n" + "lid 0x%X\n" + "in_port_num 0x%X\n" + "out_port_num 0x%X\n", + cl_ntoh16(p_rec->lid), + p_rec->in_port_num, p_rec->out_port_num); + + fprintf(fh, "SL:"); + for (i = 0; i < 16; i++) + fprintf(fh, "| %-2u ", i); + fprintf(fh, "|\nVL:"); + + for (i = 0; i < 16; i++) + fprintf(fh, "| 0x%01X ", + ib_slvl_table_get(&p_rec->slvl_tbl, (uint8_t) i)); + fprintf(fh, "|\nEND\n\n"); + + /* Exit: */ + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + * GET A SINGLE PORT INFO BY NODE LID AND PORT NUMBER + **********************************************************************/ +ib_api_status_t +osmt_query_slvl_map(IN osmtest_t * const p_osmt, + IN ib_net16_t const lid, + IN uint8_t const out_port_num, + IN uint8_t const in_port_num, IN FILE * fh) +{ + osmtest_req_context_t context; + ib_api_status_t status = IB_SUCCESS; + osmv_user_query_t user; + osmv_query_req_t req; + ib_slvl_table_record_t record, *p_rec; + + OSM_LOG_ENTER(&p_osmt->log); + + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "Getting SLtoVL Map Table for out-port with LID 0x%X Num:0x%X from In-Port:0x%X\n", + cl_ntoh16(lid), out_port_num, in_port_num); + + /* + * Do a blocking query for this record in the subnet. + * The result is returned in the result field of the caller's + * context structure. + * + * The query structures are locals. + */ + memset(&req, 0, sizeof(req)); + memset(&user, 0, sizeof(user)); + memset(&context, 0, sizeof(context)); + + context.p_osmt = p_osmt; + + record.lid = lid; + record.in_port_num = in_port_num; + record.out_port_num = out_port_num; + user.p_attr = &record; + + req.query_type = OSMV_QUERY_SLVL_BY_LID_AND_PORTS; + req.timeout_ms = p_osmt->opt.transaction_timeout; + req.retry_cnt = p_osmt->opt.retry_count; + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = &context; + req.pfn_query_cb = osmtest_query_res_cb; + req.p_query_input = &user; + req.sm_key = 0; + + status = osmv_query_sa(p_osmt->h_bind, &req); + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0469: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + goto Exit; + } + + status = context.result.status; + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0470: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + + if (status == IB_REMOTE_ERROR) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "Remote error = %s\n", + ib_get_mad_status_str(osm_madw_get_mad_ptr + (context.result. + p_result_madw))); + } + goto Exit; + } + + /* ok it worked */ + p_rec = osmv_get_query_result(context.result.p_result_madw, 0); + if (fh) { + osmtest_write_slvl_map_table(p_osmt, fh, p_rec); + } + +Exit: + /* + * Return the IB query MAD to the pool as necessary. + */ + if (context.result.p_result_madw != NULL) { + osm_mad_pool_put(&p_osmt->mad_pool, + context.result.p_result_madw); + context.result.p_result_madw = NULL; + } + + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +static ib_api_status_t +osmt_query_all_ports_slvl_map(IN osmtest_t * const p_osmt, IN FILE * fh) +{ + cl_status_t status = CL_SUCCESS; + cl_qmap_t *p_tbl; + port_t *p_src_port; + uint8_t in_port, anyErr = 0, num_ports; + node_t *p_node; + const cl_qmap_t *p_node_tbl; + + OSM_LOG_ENTER(&p_osmt->log); + + /* + * Go over all ports that exist in the subnet + * get the relevant SLtoVLs + */ + + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Obtaining ALL Ports (to other ports) SLtoVL Maps\n"); + + p_tbl = &p_osmt->exp_subn.port_key_tbl; + p_node_tbl = &p_osmt->exp_subn.node_lid_tbl; + + p_src_port = (port_t *) cl_qmap_head(p_tbl); + + while (p_src_port != (port_t *) cl_qmap_end(p_tbl)) { + + /* HACK we use capability_mask to know diff a CA port from switch port */ + if (p_src_port->rec.port_info.capability_mask) { + /* this is an hca port */ + /* NOTE to comply we must set port number to 0 and the SA should figure it out */ + /* since it is a CA port */ + status = + osmt_query_slvl_map(p_osmt, p_src_port->rec.lid, 0, + 0, fh); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0471: " + "Failed to get Lid:0x%X In-Port:0x%X Out-Port:0x%X(%s)\n", + cl_ntoh16(p_src_port->rec.lid), 0, 0, + ib_get_err_str(status)); + anyErr = 1; + } + } else { + /* this is a switch port */ + /* get the node */ + p_node = + (node_t *) cl_qmap_get(p_node_tbl, + p_src_port->rec.lid); + if (p_node == (node_t *) cl_qmap_end(p_node_tbl)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0472: " + "Failed to get Node by Lid:0x%X\n", + p_src_port->rec.lid); + goto Exit; + } + + num_ports = p_node->rec.node_info.num_ports; + + for (in_port = 1; in_port <= num_ports; in_port++) { + status = + osmt_query_slvl_map(p_osmt, + p_src_port->rec.lid, + p_src_port->rec. + port_num, in_port, fh); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "ERR 0473: " + "Failed to get Lid:0x%X In-Port:0x%X Out-Port:0x%X (%s)\n", + cl_ntoh16(p_src_port->rec.lid), + p_src_port->rec.port_num, + in_port, + ib_get_err_str(status)); + anyErr = 1; + } + } + } + + p_src_port = (port_t *) cl_qmap_next(&p_src_port->map_item); + } + +Exit: + OSM_LOG_EXIT(&p_osmt->log); + if (anyErr) { + status = IB_ERROR; + } + return (status); +} + +/* + * Run a vl arbitration queries and sl2vl maps queries flow: + * Good flow: + * - for each physical port on the network - obtain the VL Arb + * - for each CA physical port obtain its SLtoVL Map + * - for each SW physical port (out) obtain the SLtoVL Map to each other port + * BAD flow: + * - Try get with multiple results + * - Try gettable + * - Try providing non existing port + */ +ib_api_status_t +osmt_run_slvl_and_vlarb_records_flow(IN osmtest_t * const p_osmt) +{ + ib_api_status_t status; + FILE *fh; + ib_net16_t test_lid; + uint8_t lmc; + + OSM_LOG_ENTER(&p_osmt->log); + + fh = fopen("qos.txt", "w"); + + /* go over all ports in the subnet */ + status = osmt_query_all_ports_vl_arb(p_osmt, fh); + if (status != IB_SUCCESS) { + goto Exit; + } + + status = osmt_query_all_ports_slvl_map(p_osmt, fh); + if (status != IB_SUCCESS) { + goto Exit; + } + + /* If LMC > 0, test non base LID SA QoS Record requests */ + status = + osmtest_get_local_port_lmc(p_osmt, p_osmt->local_port.lid, &lmc); + if (status != IB_SUCCESS) + goto Exit; + + if (lmc != 0) { + test_lid = cl_ntoh16(p_osmt->local_port.lid + 1); + + status = osmt_query_vl_arb(p_osmt, test_lid, 0, 1, NULL); + if (status != IB_SUCCESS) + goto Exit; + + status = osmt_query_slvl_map(p_osmt, test_lid, 0, 0, NULL); + if (status != IB_SUCCESS) + goto Exit; + } + +Exit: + fclose(fh); + OSM_LOG_EXIT(&p_osmt->log); + return status; +} diff --git a/branches/WOF2-3/ulp/opensm/user/osmtest/osmtest.c b/branches/WOF2-3/ulp/opensm/user/osmtest/osmtest.c new file mode 100644 index 00000000..20564688 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/osmtest/osmtest.c @@ -0,0 +1,7410 @@ +/* + * Copyright (c) 2006-2009 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2007 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Copyright (c) 2009 HNR Consulting. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* 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. + * + */ + +#include +#include +#include +#include +#include +#include "osmtest.h" + +#define POOL_MIN_ITEMS 64 +#define MAX_LOCAL_IBPORTS 64 + +typedef struct _osmtest_sm_info_rec { + ib_net64_t sm_guid; + ib_net16_t lid; + uint8_t priority; + uint8_t sm_state; +} osmtest_sm_info_rec_t; + +typedef struct _osmtest_inform_info { + boolean_t subscribe; + ib_net32_t qpn; + ib_net16_t trap; +} osmtest_inform_info_t; + +typedef struct _osmtest_inform_info_rec { + ib_gid_t subscriber_gid; + ib_net16_t subscriber_enum; +} osmtest_inform_info_rec_t; + +typedef enum _osmtest_token_val { + OSMTEST_TOKEN_COMMENT = 0, + OSMTEST_TOKEN_END, + OSMTEST_TOKEN_DEFINE_NODE, + OSMTEST_TOKEN_DEFINE_PORT, + OSMTEST_TOKEN_DEFINE_PATH, + OSMTEST_TOKEN_DEFINE_LINK, + OSMTEST_TOKEN_LID, + OSMTEST_TOKEN_BASE_VERSION, + OSMTEST_TOKEN_CLASS_VERSION, + OSMTEST_TOKEN_NODE_TYPE, + OSMTEST_TOKEN_NUM_PORTS, + OSMTEST_TOKEN_SYS_GUID, + OSMTEST_TOKEN_NODE_GUID, + OSMTEST_TOKEN_PORT_GUID, + OSMTEST_TOKEN_PARTITION_CAP, + OSMTEST_TOKEN_DEVICE_ID, + OSMTEST_TOKEN_REVISION, + OSMTEST_TOKEN_PORT_NUM, + OSMTEST_TOKEN_VENDOR_ID, + OSMTEST_TOKEN_DGID, + OSMTEST_TOKEN_SGID, + OSMTEST_TOKEN_DLID, + OSMTEST_TOKEN_SLID, + OSMTEST_TOKEN_HOP_FLOW_RAW, + OSMTEST_TOKEN_TCLASS, + OSMTEST_TOKEN_NUM_PATH, + OSMTEST_TOKEN_PKEY, + OSMTEST_TOKEN_SL, + OSMTEST_TOKEN_RATE, + OSMTEST_TOKEN_PKT_LIFE, + OSMTEST_TOKEN_PREFERENCE, + OSMTEST_TOKEN_MKEY, + OSMTEST_TOKEN_SUBN_PREF, + OSMTEST_TOKEN_BASE_LID, + OSMTEST_TOKEN_SM_BASE_LID, + OSMTEST_TOKEN_CAP_MASK, + OSMTEST_TOKEN_DIAG_CODE, + OSMTEST_TOKEN_MKEY_LEASE_PER, + OSMTEST_TOKEN_LOC_PORT_NUM, + OSMTEST_TOKEN_LINK_WID_EN, + OSMTEST_TOKEN_LINK_WID_SUP, + OSMTEST_TOKEN_LINK_WID_ACT, + OSMTEST_TOKEN_LINK_SPEED_SUP, + OSMTEST_TOKEN_PORT_STATE, + OSMTEST_TOKEN_STATE_INFO2, + OSMTEST_TOKEN_MKEY_PROT_BITS, + OSMTEST_TOKEN_LMC, + OSMTEST_TOKEN_LINK_SPEED, + OSMTEST_TOKEN_MTU_SMSL, + OSMTEST_TOKEN_VL_CAP, + OSMTEST_TOKEN_VL_HIGH_LIMIT, + OSMTEST_TOKEN_VL_ARB_HIGH_CAP, + OSMTEST_TOKEN_VL_ARB_LOW_CAP, + OSMTEST_TOKEN_MTU_CAP, + OSMTEST_TOKEN_VL_STALL_LIFE, + OSMTEST_TOKEN_VL_ENFORCE, + OSMTEST_TOKEN_MKEY_VIOL, + OSMTEST_TOKEN_PKEY_VIOL, + OSMTEST_TOKEN_QKEY_VIOL, + OSMTEST_TOKEN_GUID_CAP, + OSMTEST_TOKEN_SUBN_TIMEOUT, + OSMTEST_TOKEN_RESP_TIME_VAL, + OSMTEST_TOKEN_ERR_THRESHOLD, + OSMTEST_TOKEN_MTU, + OSMTEST_TOKEN_FROMLID, + OSMTEST_TOKEN_FROMPORTNUM, + OSMTEST_TOKEN_TOPORTNUM, + OSMTEST_TOKEN_TOLID, + OSMTEST_TOKEN_UNKNOWN +} osmtest_token_val_t; + +typedef struct _osmtest_token { + osmtest_token_val_t val; + size_t str_size; + const char *str; +} osmtest_token_t; + +const osmtest_token_t token_array[] = { + {OSMTEST_TOKEN_COMMENT, 1, "#"}, + {OSMTEST_TOKEN_END, 3, "END"}, + {OSMTEST_TOKEN_DEFINE_NODE, 11, "DEFINE_NODE"}, + {OSMTEST_TOKEN_DEFINE_PORT, 11, "DEFINE_PORT"}, + {OSMTEST_TOKEN_DEFINE_PATH, 11, "DEFINE_PATH"}, + {OSMTEST_TOKEN_DEFINE_LINK, 11, "DEFINE_LINK"}, + {OSMTEST_TOKEN_LID, 3, "LID"}, + {OSMTEST_TOKEN_BASE_VERSION, 12, "BASE_VERSION"}, + {OSMTEST_TOKEN_CLASS_VERSION, 13, "CLASS_VERSION"}, + {OSMTEST_TOKEN_NODE_TYPE, 9, "NODE_TYPE"}, + {OSMTEST_TOKEN_NUM_PORTS, 9, "NUM_PORTS"}, + {OSMTEST_TOKEN_SYS_GUID, 8, "SYS_GUID"}, + {OSMTEST_TOKEN_NODE_GUID, 9, "NODE_GUID"}, + {OSMTEST_TOKEN_PORT_GUID, 9, "PORT_GUID"}, + {OSMTEST_TOKEN_PARTITION_CAP, 13, "PARTITION_CAP"}, + {OSMTEST_TOKEN_DEVICE_ID, 9, "DEVICE_ID"}, + {OSMTEST_TOKEN_REVISION, 8, "REVISION"}, + {OSMTEST_TOKEN_PORT_NUM, 8, "PORT_NUM"}, + {OSMTEST_TOKEN_VENDOR_ID, 9, "VENDOR_ID"}, + {OSMTEST_TOKEN_DGID, 4, "DGID"}, + {OSMTEST_TOKEN_SGID, 4, "SGID"}, + {OSMTEST_TOKEN_DLID, 4, "DLID"}, + {OSMTEST_TOKEN_SLID, 4, "SLID"}, + {OSMTEST_TOKEN_HOP_FLOW_RAW, 12, "HOP_FLOW_RAW"}, + {OSMTEST_TOKEN_TCLASS, 6, "TCLASS"}, + {OSMTEST_TOKEN_NUM_PATH, 8, "NUM_PATH"}, + {OSMTEST_TOKEN_PKEY, 4, "PKEY"}, + {OSMTEST_TOKEN_SL, 2, "SL"}, + {OSMTEST_TOKEN_RATE, 4, "RATE"}, + {OSMTEST_TOKEN_PKT_LIFE, 8, "PKT_LIFE"}, + {OSMTEST_TOKEN_PREFERENCE, 10, "PREFERENCE"}, + {OSMTEST_TOKEN_MKEY, 4, "M_KEY"}, + {OSMTEST_TOKEN_SUBN_PREF, 13, "SUBNET_PREFIX"}, + {OSMTEST_TOKEN_BASE_LID, 8, "BASE_LID"}, + {OSMTEST_TOKEN_SM_BASE_LID, 18, "MASTER_SM_BASE_LID"}, + {OSMTEST_TOKEN_CAP_MASK, 15, "CAPABILITY_MASK"}, + {OSMTEST_TOKEN_DIAG_CODE, 9, "DIAG_CODE"}, + {OSMTEST_TOKEN_MKEY_LEASE_PER, 18, "m_key_lease_period"}, + {OSMTEST_TOKEN_LOC_PORT_NUM, 14, "local_port_num"}, + {OSMTEST_TOKEN_LINK_WID_EN, 18, "link_width_enabled"}, + {OSMTEST_TOKEN_LINK_WID_SUP, 20, "link_width_supported"}, + {OSMTEST_TOKEN_LINK_WID_ACT, 17, "link_width_active"}, + {OSMTEST_TOKEN_LINK_SPEED_SUP, 20, "link_speed_supported"}, + {OSMTEST_TOKEN_PORT_STATE, 10, "port_state"}, + {OSMTEST_TOKEN_STATE_INFO2, 10, "state_info2"}, + {OSMTEST_TOKEN_MKEY_PROT_BITS, 3, "mpb"}, + {OSMTEST_TOKEN_LMC, 3, "lmc"}, + {OSMTEST_TOKEN_LINK_SPEED, 10, "link_speed"}, + {OSMTEST_TOKEN_MTU_SMSL, 8, "mtu_smsl"}, + {OSMTEST_TOKEN_VL_CAP, 6, "vl_cap"}, + {OSMTEST_TOKEN_VL_HIGH_LIMIT, 13, "vl_high_limit"}, + {OSMTEST_TOKEN_VL_ARB_HIGH_CAP, 15, "vl_arb_high_cap"}, + {OSMTEST_TOKEN_VL_ARB_LOW_CAP, 14, "vl_arb_low_cap"}, + {OSMTEST_TOKEN_MTU_CAP, 7, "mtu_cap"}, + {OSMTEST_TOKEN_VL_STALL_LIFE, 13, "vl_stall_life"}, + {OSMTEST_TOKEN_VL_ENFORCE, 10, "vl_enforce"}, + {OSMTEST_TOKEN_MKEY_VIOL, 16, "m_key_violations"}, + {OSMTEST_TOKEN_PKEY_VIOL, 16, "p_key_violations"}, + {OSMTEST_TOKEN_QKEY_VIOL, 16, "q_key_violations"}, + {OSMTEST_TOKEN_GUID_CAP, 8, "guid_cap"}, + {OSMTEST_TOKEN_SUBN_TIMEOUT, 14, "subnet_timeout"}, + {OSMTEST_TOKEN_RESP_TIME_VAL, 15, "resp_time_value"}, + {OSMTEST_TOKEN_ERR_THRESHOLD, 15, "error_threshold"}, + {OSMTEST_TOKEN_MTU, 3, "MTU"}, /* must be after the other mtu... tokens. */ + {OSMTEST_TOKEN_FROMLID, 8, "from_lid"}, + {OSMTEST_TOKEN_FROMPORTNUM, 13, "from_port_num"}, + {OSMTEST_TOKEN_TOPORTNUM, 11, "to_port_num"}, + {OSMTEST_TOKEN_TOLID, 6, "to_lid"}, + {OSMTEST_TOKEN_UNKNOWN, 0, ""} /* must be last entry */ +}; + +#define IB_MAD_STATUS_CLASS_MASK (CL_HTON16(0xFF00)) + +static const char ib_mad_status_str_busy[] = "IB_MAD_STATUS_BUSY"; +static const char ib_mad_status_str_redirect[] = "IB_MAD_STATUS_REDIRECT"; +static const char ib_mad_status_str_unsup_class_ver[] = + "IB_MAD_STATUS_UNSUP_CLASS_VER"; +static const char ib_mad_status_str_unsup_method[] = + "IB_MAD_STATUS_UNSUP_METHOD"; +static const char ib_mad_status_str_unsup_method_attr[] = + "IB_MAD_STATUS_UNSUP_METHOD_ATTR"; +static const char ib_mad_status_str_invalid_field[] = + "IB_MAD_STATUS_INVALID_FIELD"; +static const char ib_mad_status_str_no_resources[] = + "IB_SA_MAD_STATUS_NO_RESOURCES"; +static const char ib_mad_status_str_req_invalid[] = + "IB_SA_MAD_STATUS_REQ_INVALID"; +static const char ib_mad_status_str_no_records[] = + "IB_SA_MAD_STATUS_NO_RECORDS"; +static const char ib_mad_status_str_too_many_records[] = + "IB_SA_MAD_STATUS_TOO_MANY_RECORDS"; +static const char ib_mad_status_str_invalid_gid[] = + "IB_SA_MAD_STATUS_INVALID_GID"; +static const char ib_mad_status_str_insuf_comps[] = + "IB_SA_MAD_STATUS_INSUF_COMPS"; +static const char generic_or_str[] = " | "; + +const char *ib_get_mad_status_str(IN const ib_mad_t * const p_mad) +{ + static char line[512]; + uint32_t offset = 0; + ib_net16_t status; + boolean_t first = TRUE; + + line[offset] = '\0'; + + status = (ib_net16_t) (p_mad->status & IB_SMP_STATUS_MASK); + + if (status == 0) { + strcat(&line[offset], "IB_SUCCESS"); + return (line); + } + + if (status & IB_MAD_STATUS_BUSY) { + strcat(&line[offset], ib_mad_status_str_busy); + offset += sizeof(ib_mad_status_str_busy); + } + if (status & IB_MAD_STATUS_REDIRECT) { + if (!first) { + strcat(&line[offset], generic_or_str); + offset += sizeof(generic_or_str) - 1; + } + first = FALSE; + strcat(&line[offset], ib_mad_status_str_redirect); + offset += sizeof(ib_mad_status_str_redirect) - 1; + } + if ((status & IB_MAD_STATUS_INVALID_FIELD) == + IB_MAD_STATUS_UNSUP_CLASS_VER) { + if (!first) { + strcat(&line[offset], generic_or_str); + offset += sizeof(generic_or_str) - 1; + } + first = FALSE; + strcat(&line[offset], ib_mad_status_str_unsup_class_ver); + offset += sizeof(ib_mad_status_str_unsup_class_ver) - 1; + } + if ((status & IB_MAD_STATUS_INVALID_FIELD) == + IB_MAD_STATUS_UNSUP_METHOD) { + if (!first) { + strcat(&line[offset], generic_or_str); + offset += sizeof(generic_or_str) - 1; + } + first = FALSE; + strcat(&line[offset], ib_mad_status_str_unsup_method); + offset += sizeof(ib_mad_status_str_unsup_method) - 1; + } + if ((status & IB_MAD_STATUS_INVALID_FIELD) == + IB_MAD_STATUS_UNSUP_METHOD_ATTR) { + if (!first) { + strcat(&line[offset], generic_or_str); + offset += sizeof(generic_or_str) - 1; + } + first = FALSE; + strcat(&line[offset], ib_mad_status_str_unsup_method_attr); + offset += sizeof(ib_mad_status_str_unsup_method_attr) - 1; + } + if ((status & IB_MAD_STATUS_INVALID_FIELD) == + IB_MAD_STATUS_INVALID_FIELD) { + if (!first) { + strcat(&line[offset], generic_or_str); + offset += sizeof(generic_or_str) - 1; + } + first = FALSE; + strcat(&line[offset], ib_mad_status_str_invalid_field); + offset += sizeof(ib_mad_status_str_invalid_field) - 1; + } + if ((status & IB_MAD_STATUS_CLASS_MASK) == + IB_SA_MAD_STATUS_NO_RESOURCES) { + if (!first) { + strcat(&line[offset], generic_or_str); + offset += sizeof(generic_or_str) - 1; + } + first = FALSE; + strcat(&line[offset], ib_mad_status_str_no_resources); + offset += sizeof(ib_mad_status_str_no_resources) - 1; + } + if ((status & IB_MAD_STATUS_CLASS_MASK) == IB_SA_MAD_STATUS_REQ_INVALID) { + if (!first) { + strcat(&line[offset], generic_or_str); + offset += sizeof(generic_or_str) - 1; + } + first = FALSE; + strcat(&line[offset], ib_mad_status_str_req_invalid); + offset += sizeof(ib_mad_status_str_req_invalid) - 1; + } + if ((status & IB_MAD_STATUS_CLASS_MASK) == IB_SA_MAD_STATUS_NO_RECORDS) { + if (!first) { + strcat(&line[offset], generic_or_str); + offset += sizeof(generic_or_str) - 1; + } + first = FALSE; + strcat(&line[offset], ib_mad_status_str_no_records); + offset += sizeof(ib_mad_status_str_no_records) - 1; + } + if ((status & IB_MAD_STATUS_CLASS_MASK) == + IB_SA_MAD_STATUS_TOO_MANY_RECORDS) { + if (!first) { + strcat(&line[offset], generic_or_str); + offset += sizeof(generic_or_str) - 1; + } + first = FALSE; + strcat(&line[offset], ib_mad_status_str_too_many_records); + offset += sizeof(ib_mad_status_str_too_many_records) - 1; + } + if ((status & IB_MAD_STATUS_CLASS_MASK) == IB_SA_MAD_STATUS_INVALID_GID) { + if (!first) { + strcat(&line[offset], generic_or_str); + offset += sizeof(generic_or_str) - 1; + } + first = FALSE; + strcat(&line[offset], ib_mad_status_str_invalid_gid); + offset += sizeof(ib_mad_status_str_invalid_gid) - 1; + } + if ((status & IB_MAD_STATUS_CLASS_MASK) == IB_SA_MAD_STATUS_INSUF_COMPS) { + if (!first) { + strcat(&line[offset], generic_or_str); + offset += sizeof(generic_or_str) - 1; + } + first = FALSE; + strcat(&line[offset], ib_mad_status_str_insuf_comps); + offset += sizeof(ib_mad_status_str_insuf_comps) - 1; + } + + return (line); +} + +void subnet_construct(IN subnet_t * const p_subn) +{ + cl_qmap_init(&p_subn->link_tbl); + cl_qmap_init(&p_subn->node_lid_tbl); + cl_qmap_init(&p_subn->node_guid_tbl); + cl_qmap_init(&p_subn->mgrp_mlid_tbl); + + /* NO WAY TO HAVE UNIQUE PORT BY LID OR GUID */ + /* cl_qmap_init( &p_subn->port_lid_tbl ); */ + /* cl_qmap_init( &p_subn->port_guid_tbl ); */ + + /* port key is a lid and num pair */ + cl_qmap_init(&p_subn->port_key_tbl); + cl_qmap_init(&p_subn->path_tbl); +} + +cl_status_t subnet_init(IN subnet_t * const p_subn) +{ + cl_status_t status = IB_SUCCESS; + + subnet_construct(p_subn); + + return (status); +} + +void osmtest_construct(IN osmtest_t * const p_osmt) +{ + memset(p_osmt, 0, sizeof(*p_osmt)); + osm_log_construct(&p_osmt->log); + subnet_construct(&p_osmt->exp_subn); +} + +void osmtest_destroy(IN osmtest_t * const p_osmt) +{ + cl_map_item_t *p_item, *p_next_item; + + /* Currently there is a problem with IBAL exit flow - memory overrun, + so bypass vendor deletion - it will be cleaned by the Windows OS */ +#ifndef __WIN__ + if (p_osmt->p_vendor) + osm_vendor_delete(&p_osmt->p_vendor); +#endif + + cl_qpool_destroy(&p_osmt->port_pool); + cl_qpool_destroy(&p_osmt->node_pool); + + /* destroy the qmap tables */ + p_next_item = cl_qmap_head(&p_osmt->exp_subn.link_tbl); + while (p_next_item != cl_qmap_end(&p_osmt->exp_subn.link_tbl)) { + p_item = p_next_item; + p_next_item = cl_qmap_next(p_item); + free(p_item); + } + p_next_item = cl_qmap_head(&p_osmt->exp_subn.mgrp_mlid_tbl); + while (p_next_item != cl_qmap_end(&p_osmt->exp_subn.mgrp_mlid_tbl)) { + p_item = p_next_item; + p_next_item = cl_qmap_next(p_item); + free(p_item); + } + p_next_item = cl_qmap_head(&p_osmt->exp_subn.node_guid_tbl); + while (p_next_item != cl_qmap_end(&p_osmt->exp_subn.node_guid_tbl)) { + p_item = p_next_item; + p_next_item = cl_qmap_next(p_item); + free(p_item); + } + + p_next_item = cl_qmap_head(&p_osmt->exp_subn.node_lid_tbl); + while (p_next_item != cl_qmap_end(&p_osmt->exp_subn.node_lid_tbl)) { + p_item = p_next_item; + p_next_item = cl_qmap_next(p_item); + free(p_item); + } + + p_next_item = cl_qmap_head(&p_osmt->exp_subn.path_tbl); + while (p_next_item != cl_qmap_end(&p_osmt->exp_subn.path_tbl)) { + p_item = p_next_item; + p_next_item = cl_qmap_next(p_item); + free(p_item); + } + p_next_item = cl_qmap_head(&p_osmt->exp_subn.port_key_tbl); + while (p_next_item != cl_qmap_end(&p_osmt->exp_subn.port_key_tbl)) { + p_item = p_next_item; + p_next_item = cl_qmap_next(p_item); + free(p_item); + } + + osm_log_destroy(&p_osmt->log); +} + +ib_api_status_t +osmtest_init(IN osmtest_t * const p_osmt, + IN const osmtest_opt_t * const p_opt, + IN const osm_log_level_t log_flags) +{ + ib_api_status_t status; + + /* Can't use log macros here, since we're initializing the log. */ + osmtest_construct(p_osmt); + + status = osm_log_init_v2(&p_osmt->log, p_opt->force_log_flush, + 0x0001, p_opt->log_file, 0, TRUE); + if (status != IB_SUCCESS) + return (status); + + /* but we do not want any extra stuff here */ + osm_log_set_level(&p_osmt->log, log_flags); + + OSM_LOG(&p_osmt->log, OSM_LOG_FUNCS, "[\n"); + + p_osmt->opt = *p_opt; + + status = cl_qpool_init(&p_osmt->node_pool, POOL_MIN_ITEMS, 0, + POOL_MIN_ITEMS, sizeof(node_t), NULL, NULL, + NULL); + CL_ASSERT(status == CL_SUCCESS); + + status = cl_qpool_init(&p_osmt->port_pool, POOL_MIN_ITEMS, 0, + POOL_MIN_ITEMS, sizeof(port_t), NULL, NULL, + NULL); + CL_ASSERT(status == CL_SUCCESS); + + p_osmt->p_vendor = osm_vendor_new(&p_osmt->log, + p_opt->transaction_timeout); + + if (p_osmt->p_vendor == NULL) { + status = IB_INSUFFICIENT_RESOURCES; + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0001: " + "Unable to allocate vendor object"); + status = IB_ERROR; + goto Exit; + } + + osm_mad_pool_construct(&p_osmt->mad_pool); + status = osm_mad_pool_init(&p_osmt->mad_pool); + if (status != IB_SUCCESS) + goto Exit; + +Exit: + OSM_LOG(&p_osmt->log, OSM_LOG_FUNCS, "]\n"); + return (status); +} + +void osmtest_query_res_cb(IN osmv_query_res_t * p_rec) +{ + osmtest_req_context_t *const p_ctxt = + (osmtest_req_context_t *) p_rec->query_context; + osmtest_t *const p_osmt = p_ctxt->p_osmt; + + OSM_LOG_ENTER(&p_osmt->log); + + p_ctxt->result = *p_rec; + + if (p_rec->status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0003: " + "Error on query (%s)\n", ib_get_err_str(p_rec->status)); + } + + OSM_LOG_EXIT(&p_osmt->log); +} + +ib_api_status_t +osmtest_get_all_recs(IN osmtest_t * const p_osmt, + IN ib_net16_t const attr_id, + IN size_t const attr_size, + IN OUT osmtest_req_context_t * const p_context) +{ + ib_api_status_t status = IB_SUCCESS; + osmv_user_query_t user; + osmv_query_req_t req; + + OSM_LOG_ENTER(&p_osmt->log); + + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, "Getting all %s records\n", + ib_get_sa_attr_str(attr_id)); + + /* + * Do a blocking query for all records in the subnet. + * The result is returned in the result field of the caller's + * context structure. + * + * The query structures are locals. + */ + memset(&req, 0, sizeof(req)); + memset(&user, 0, sizeof(user)); + + p_context->p_osmt = p_osmt; + user.attr_id = attr_id; + user.attr_offset = ib_get_attr_offset((uint16_t) attr_size); + + 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 = ib_get_attr_offset((uint16_t) sizeof(record)); + 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 = ib_get_attr_offset((uint16_t) sizeof(record)); + 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 = ib_get_attr_offset((uint16_t) sizeof(record)); + 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 %u 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 (by lid pair) 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))); + } + } + +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 %u 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 %u 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 %u 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 /* !VENDOR_RMPP_SUPPORT */ +/* + * 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); +} + +ib_api_status_t +osmtest_stress_path_recs_by_lid(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; + cl_status_t status; + ib_net16_t dlid, slid; + int num_recs, i; + + OSM_LOG_ENTER(&p_osmt->log); + + memset(&context, 0, sizeof(context)); + + slid = cl_ntoh16(p_osmt->local_port.lid); +#ifdef OSM_VENDOR_INTF_AL + dlid = p_osmt->local_port.sm_lid; // already in correct byte-order +#else + dlid = cl_ntoh16(p_osmt->local_port.sm_lid); +#endif + + /* + * Do a blocking query for the PathRecord. + */ + status = osmtest_get_path_rec_by_lid_pair(p_osmt, slid, dlid, &context); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 000A: " + "osmtest_get_path_rec_by_lid_pair 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, 0); + 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); +} + +static ib_api_status_t osmtest_stress_get_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; + 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_GET_PR) && (num_timeouts < 100)) { + delta_recs = 0; + delta_queries = 0; + + status = osmtest_stress_path_recs_by_lid(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 + " path_rec queries 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 + " path_rec queries 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 %u 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 %u 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 %u 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 = ib_get_attr_offset((uint16_t) sizeof(record)); + 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 = ib_get_attr_offset((uint16_t) sizeof(record)); + 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 = ib_get_attr_offset((uint16_t) sizeof(record)); + 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 = ib_get_attr_offset((uint16_t) sizeof(record)); + 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 = ib_get_attr_offset((uint16_t) sizeof(record)); + 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 = ib_get_attr_offset((uint16_t) sizeof(record)); + 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 = ib_get_attr_offset((uint16_t) sizeof(record)); + 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 = ib_get_attr_offset((uint16_t) sizeof(record)); + 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 = ib_get_attr_offset((uint16_t) sizeof(record)); + /* 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 %u\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 = ib_get_attr_offset((uint16_t) sizeof(record)); + 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, "%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); + + /* + * 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 (strncasecmp(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, choice = 0; + + OSM_LOG_ENTER(&p_osmt->log); + + /* + * User needs prompting for the local port GUID with which + * to bind. + */ + + while (1) { + 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); + fflush(stdout); + if (scanf("%u", &choice) <= 0) { + char junk[256]; + if (scanf("%s", junk) <= 0) + printf("\nError: Cannot scan!\n"); + } else if (choice && choice <= num_ports) + break; + printf("\nError: Lame choice!\n"); + } + 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 = MAX_LOCAL_IBPORTS; + ib_port_attr_t attr_array[MAX_LOCAL_IBPORTS] = { {0} }; + + 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; + case 4: /* SA Get PR to SA LID */ + status = osmtest_stress_get_pr(p_osmt); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "ERR 014B: " + "SA Get PR 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/branches/WOF2-3/ulp/opensm/user/osmtest/osmtest.rc b/branches/WOF2-3/ulp/opensm/user/osmtest/osmtest.rc new file mode 100644 index 00000000..77ccc239 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/osmtest/osmtest.rc @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN +#ifdef _DEBUG_ +#define VER_FILEDESCRIPTION_STR "OpenSM Test Application 3.3.6 (Debug)" +#define VER_INTERNALNAME_STR "osmtest.exe" +#define VER_ORIGINALFILENAME_STR "osmtest.exe" +#else +#define VER_FILEDESCRIPTION_STR "OpenSM Test Application 3.3.6" +#define VER_INTERNALNAME_STR "osmtest.exe" +#define VER_ORIGINALFILENAME_STR "osmtest.exe" +#endif +#include diff --git a/branches/WOF2-3/ulp/opensm/user/osmtest/vendor-ibal.inc b/branches/WOF2-3/ulp/opensm/user/osmtest/vendor-ibal.inc new file mode 100644 index 00000000..303cdd49 --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/osmtest/vendor-ibal.inc @@ -0,0 +1,2 @@ + +!INCLUDE ..\opensm\vendor-ibal.inc diff --git a/branches/WOF2-3/ulp/opensm/user/osmtest/vendor-umad.inc b/branches/WOF2-3/ulp/opensm/user/osmtest/vendor-umad.inc new file mode 100644 index 00000000..d106d80f --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/osmtest/vendor-umad.inc @@ -0,0 +1,2 @@ + +!INCLUDE ..\opensm\vendor-umad.inc diff --git a/branches/WOF2-3/ulp/opensm/user/scripts/osm-regress.bat b/branches/WOF2-3/ulp/opensm/user/scripts/osm-regress.bat new file mode 100644 index 00000000..9229f91e --- /dev/null +++ b/branches/WOF2-3/ulp/opensm/user/scripts/osm-regress.bat @@ -0,0 +1,45 @@ +@echo off +setlocal + +rem requires cmd.exe /E /V, make it so... JLP +set F=on +set F=off +if "!F!" == "off" goto OK + +%comspec% /E:on /V:on /C %0 %1 %2 +exit /B %ERRORLEVEL% + +:OK + +if "%1" == "" ( +:usage + echo usage: osm-regress results-filename {exit-on-error} + exit /B 1 +) +if exist "%1" del /Q "%1" + +rem if not exist "osmtest.dat" ( +rem echo missing inventory file .\osmtest.dat ? +rem exit /B 1 +rem ) + +rem set T=..\..\..\bin\user\objchk_wlh_amd64\amd64\osmtest.exe +set T=osmtest.exe + +rem Event forwarding test 'e' is not yet implemented [3.3.5] + +set TESTS="c" "v" "m -M1" "m -M2" "m -M3" "m -M4" "f -s1" "f -s2" "f -s3" "f -s4" "s" "a" +rem set TESTS="c" "v" "a" "f -s1" "f -s2" "f -s3" "f -s4" "s" + +for %%t in ( %TESTS% ) DO ( + echo TEST: osmtest -f %%~t + echo TEST: osmtest -f %%~t >> %1 + %T% -f %%~t >> %1 + if !ERRORLEVEL! NEQ 0 ( + echo Error !ERRORLEVEL! reported in osmtest -f %%~t ? + if Not "%2" == "" exit /B 1 + ) + echo. >> %1 + echo PASS. +) +endlocal diff --git a/branches/WOF2-3/ulp/qlgcvnic/dirs b/branches/WOF2-3/ulp/qlgcvnic/dirs new file mode 100644 index 00000000..ed41dcf4 --- /dev/null +++ b/branches/WOF2-3/ulp/qlgcvnic/dirs @@ -0,0 +1,2 @@ +DIRS=\ + kernel diff --git a/branches/WOF2-3/ulp/qlgcvnic/kernel/SOURCES b/branches/WOF2-3/ulp/qlgcvnic/kernel/SOURCES new file mode 100644 index 00000000..0f0ed04b --- /dev/null +++ b/branches/WOF2-3/ulp/qlgcvnic/kernel/SOURCES @@ -0,0 +1,90 @@ +######################################################################## +# +# Copyright(c) Infinicon Systems All rights reserved. +# +######################################################################## + + +# The TARGETNAME. This is name of the item being built (without the +# extension. +TARGETNAME=qlgcvnic + +######################################################################## +# The path where all binaries are built. +# +TARGETPATH=..\..\..\bin\kernel\obj$(BUILD_ALT_DIR) + +######################################################################## +# WDK build only: transform .inx --> .inf adding date & version stamp. +# See '.\makefile.inc'. netvnic.inf file created in $(INF_TARGET) +# +!if $(_NT_TOOLS_VERSION) != 0x700 +INF_NAME=netvnic +INF_TARGET=..\..\..\bin\kernel\$(O)\$(INF_NAME).inf +NTTARGETFILES=$(INF_TARGET) +!endif + +######################################################################## +# The type of item that is being built. This is manditory. +# Value Meaning +# DYNLINK - A DLL. +# DRIVER - A kernel device driver. +# EXPORT_DRIVER - A kernel device driver with exports. +# PROGRAM - A windows executable. +# PROGLIB - A windows library. +# MINPORT - A miniport driver. +# GDI_DRIVER - A video driver. +# LIBRARY - A library +TARGETTYPE=MINIPORT + +######################################################################## +# The type of driver being built. This affects the include paths. +# Comment out for non-WDM drivers. +#DRIVERTYPE=WDM + +# +######################################################################## +# All the source files in this project. +# +SOURCES= inic.rc \ + vnic_driver.c \ + vnic_adapter.c \ + vnic_ib.c \ + vnic_control.c \ + vnic_data.c \ + vnic_netpath.c \ + vnic_viport.c \ + + + + +INCLUDES=..;..\..\..\inc;..\..\..\inc\kernel; + +C_DEFINES=$(C_DEFINES) -DNDIS_MINIPORT_DRIVER -DNDIS_WDM=1 \ + -DDEPRECATE_DDK_FUNCTIONS -DNDIS51_MINIPORT -DBINARY_COMPATIBLE=0 -DLBFO_ENABLED=1 + +#!if $(FREEBUILD) +# Free build will printout error messages +#C_DEFINES=$(C_DEFINES) -DFREE_BUILD_DBG=1 +#!endif + +TARGETLIBS= \ + $(DDK_LIB_PATH)\ntoskrnl.lib \ + $(DDK_LIB_PATH)\hal.lib \ + $(DDK_LIB_PATH)\ndis.lib \ + $(TARGETPATH)\*\complib.lib + +#!if !defined(DDK_TARGET_OS) || "$(DDK_TARGET_OS)"=="Win2K" +# +# The driver is built in the Win2K build environment +# - use the library version of safe strings +# +#TARGETLIBS= $(TARGETLIBS) $(DDK_LIB_PATH)\ntstrsafe.lib +#!endif + +######################################################################## +# Set the warning levels to maximum. +MSC_WARNING_LEVEL= /W4 +# + + diff --git a/branches/WOF2-3/ulp/qlgcvnic/kernel/inic.rc b/branches/WOF2-3/ulp/qlgcvnic/kernel/inic.rc new file mode 100644 index 00000000..84699441 --- /dev/null +++ b/branches/WOF2-3/ulp/qlgcvnic/kernel/inic.rc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_DRV_NETWORK + +#ifdef _DEBUG_ +#define VER_FILEDESCRIPTION_STR "QLogic VNIC NDIS Miniport (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "QLogic VNIC NDIS Miniport" +#endif + +#define VER_INTERNALNAME_STR "qlgcvnic.sys" +#define VER_ORIGINALFILENAME_STR "qlgcvnic.sys" + +#include diff --git a/branches/WOF2-3/ulp/qlgcvnic/kernel/makefile b/branches/WOF2-3/ulp/qlgcvnic/kernel/makefile new file mode 100644 index 00000000..128ed372 --- /dev/null +++ b/branches/WOF2-3/ulp/qlgcvnic/kernel/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the Windows NT DDK +# + +!INCLUDE ..\..\..\inc\openib.def diff --git a/branches/WOF2-3/ulp/qlgcvnic/kernel/makefile.inc b/branches/WOF2-3/ulp/qlgcvnic/kernel/makefile.inc new file mode 100644 index 00000000..4f29f500 --- /dev/null +++ b/branches/WOF2-3/ulp/qlgcvnic/kernel/makefile.inc @@ -0,0 +1,17 @@ + +# Transform .inx file to .inf file adding date + major,min & svn.version stamp +# Output .inf file is copied to the $(INF_TARGET) folder (commonly where .sys file resides). + +_LNG=$(LANGUAGE) + +!IF !DEFINED(_INX) +_INX=. +!ENDIF + +STAMP=stampinf -a $(_BUILDARCH) + +!INCLUDE mod_ver.def + +$(INF_TARGET) : $(_INX)\$(INF_NAME).inx + copy $(_INX)\$(@B).inx $@ + $(STAMP) -f $@ -d * -v $(IB_MAJORVERSION).$(IB_MINORVERSION).$(IB_BUILDVERSION).$(OPENIB_REV) diff --git a/branches/WOF2-3/ulp/qlgcvnic/kernel/netvnic.cdf b/branches/WOF2-3/ulp/qlgcvnic/kernel/netvnic.cdf new file mode 100644 index 00000000..7f1a2767 --- /dev/null +++ b/branches/WOF2-3/ulp/qlgcvnic/kernel/netvnic.cdf @@ -0,0 +1,8 @@ +[CatalogHeader] +Name=netvnic.cat +PublicVersion=0x0000001 +EncodingType=0x00010001 +CATATTR1=0x10010001:OSAttr:2:6.0 +[CatalogFiles] +netvnic.inf=netvnic.inf +qlgcvnic.sys=qlgcvnic.sys diff --git a/branches/WOF2-3/ulp/qlgcvnic/kernel/netvnic.inx b/branches/WOF2-3/ulp/qlgcvnic/kernel/netvnic.inx new file mode 100644 index 00000000..c20210ac --- /dev/null +++ b/branches/WOF2-3/ulp/qlgcvnic/kernel/netvnic.inx @@ -0,0 +1,198 @@ +; QLogic Corporation Ethernet over Infiniband NIC. +; Copyright (c) QLogic Corporation all Rights Reserved. + +[Version] +Signature="$Windows NT$" +Class=Net +ClassGUID={4d36e972-e325-11ce-bfc1-08002be10318} +Provider=%Inf_Provider% +DriverVer=01/21/2008,1.0.0000.927 +CatalogFile=netvnic.cat + +[ControlFlags] +ExcludeFromSelect = IBA\V00066aP00000030 + +; ================= Device Install section ===================== + +[DestinationDirs] +DefaultDestDir=12 + +[SourceDisksNames.x86] +1=%DiskId%,,,"" + +[SourceDisksNames.amd64] +1=%DiskId%,,,"" + +[SourceDisksNames.ia64] +1=%DiskId%,,,"" + +[SourceDisksFiles] +qlgcvnic.sys=1 + +[Manufacturer] +%Inf_Provider% = vnic.DeviceSection,ntx86,ntamd64,ntia64 + +[vnic.DeviceSection] +; empty since we don't support W9x/Me + +[vnic.DeviceSection.ntx86] +%vnic.DeviceDesc% = VNIC.DDInstall,IBA\qlgcvnic + +[vnic.DeviceSection.ntamd64] +%vnic.DeviceDesc% = VNIC.DDInstall,IBA\qlgcvnic + +[vnic.DeviceSection.ntia64] +%vnic.DeviceDesc% = VNIC.DDInstall,IBA\qlgcvnic + +[vnic.DDInstall.ntx86] +Characteristics = %CHARACTERISTICS% +AddReg = vnic.AddReg +CopyFiles = vnic.CopyFiles + +[vnic.DDInstall.ntamd64] +Characteristics = %CHARACTERISTICS% +AddReg = vnic.AddReg +CopyFiles = vnic.CopyFiles + +[vnic.DDInstall.ntia64] +Characteristics = %CHARACTERISTICS% +AddReg = vnic.AddReg +CopyFiles = vnic.CopyFiles + +[vnic.DDInstall.ntx86.Services] +AddService = qlgcvnic,%SPSVCINST_ASSOCSERVICE%,vnic.ServiceInstall,vnic.EventLogInstall + +[vnic.DDInstall.ntamd64.Services] +AddService = qlgcvnic,%SPSVCINST_ASSOCSERVICE%,vnic.ServiceInstall,vnic.EventLogInstall + +[vnic.DDInstall.ntia64.Services] +AddService = qlgcvnic,%SPSVCINST_ASSOCSERVICE%,vnic.ServiceInstall,vnic.EventLogInstall + +[vnic.CopyFiles] +qlgcvnic.sys,,,2 + +[vnic.AddReg] +HKR, Ndi, Service, 0, "qlgcvnic" +HKR, Ndi\Interfaces, UpperRange, 0, "ndis5" +HKR, Ndi\Interfaces, LowerRange, 0, "ethernet" + +HKR, Ndi\params\VlanId, ParamDesc, 0, "802.1q VlanId" +HKR, Ndi\params\VlanId, Type, 0, "dword" +HKR, Ndi\params\VlanId, Optional, 0, "1" +HKR, Ndi\params\VlanId, Default, 0, "1" +HKR, Ndi\params\VlanId, Min, 0, "1" +HKR, Ndi\params\VlanId, Max, 0, "4094" +HKR, Ndi\params\VlanId, Step, 0, "1" +HKR, Ndi\params\VlanId, Base, 0, "10" + +HKR, Ndi\params\UserPriority, ParamDesc, 0, "802.1p Priority" +HKR, Ndi\params\UserPriority, Type, 0, "dword" +HKR, Ndi\Params\UserPriority, Optional, 0, "1" +HKR, Ndi\params\UserPriority, Default, 0, "0" +HKR, Ndi\params\UserPriority, Min, 0, "0" +HKR, Ndi\params\UserPriority, Max, 0, "7" +HKR, Ndi\params\UserPriority, Step, 0, "1" + +HKR, Ndi\Params\PayloadMtu, ParamDesc, 0, "Payload Mtu size" +HKR, Ndi\Params\PayloadMtu, Type, 0, "dword" +HKR, Ndi\Params\PayloadMtu, Default, 0, "1500" +HKR, Ndi\Params\PayloadMtu, Min, 0, "1500" +HKR, Ndi\Params\PayloadMtu, Max, 0, "9500" +HKR, Ndi\Params\PayloadMtu, Step, 0, "100" +HKR, Ndi\Params\PayloadMtu, Base, 0, "10" + +HKR, Ndi\Params\UseTxCsum, ParamDesc, 0, "Send Chksum Offload" +HKR, Ndi\Params\UseTxCsum, Type, 0, "enum" +HKR, Ndi\Params\UseTxCsum, Default, 0, "1" +HKR, Ndi\Params\UseTxCsum, Optional, 0, "0" +HKR, Ndi\Params\UseTxCsum\enum, "0", 0, "Disabled" +HKR, Ndi\Params\UseTxCsum\enum, "1", 0, "Enabled" + +HKR, Ndi\Params\UseRxCsum,ParamDesc, 0, "Recv Chksum Offload" +HKR, Ndi\Params\UseRxCsum,Type, 0, "enum" +HKR, Ndi\Params\UseRxCsum,Default, 0, "1" +HKR, Ndi\Params\UseRxCsum,Optional, 0, "0" +HKR, Ndi\Params\UseRxCsum\enum, "0", 0, "Disabled" +HKR, Ndi\Params\UseRxCsum\enum, "1", 0, "Enabled" + +HKR, Ndi\Params\SecondaryPath, ParamDesc, 0, "Secondary path" +HKR, Ndi\Params\SecondaryPath, Type, 0, "enum" +HKR, Ndi\Params\SecondaryPath, Default, 0, "0" +HKR, Ndi\Params\SecondaryPath, Optional, 0, "0" +HKR, Ndi\Params\SecondaryPath\enum, "0", 0, "Disabled" +HKR, Ndi\Params\SecondaryPath\enum, "1", 0, "Enabled" + +HKR, Ndi\Params\Heartbeat, ParamDesc, 0, "Heartbeat interval (ms)" +HKR, Ndi\Params\Heartbeat, Type, 0, "dword" +HKR, Ndi\Params\Heartbeat, Default, 0, "2000" +HKR, Ndi\Params\Heartbeat, Min, 0, "0" +HKR, Ndi\Params\Heartbeat, Max, 0, "10000" +HKR, Ndi\Params\Heartbeat, Step, 0, "1000" +HKR, Ndi\Params\Heartbeat, Base, 0, "10" + +HKR, Ndi\Params\BundleId, ParamDesc, 0, "LBFO Bundle Id" +HKR, Ndi\Params\BundleId, Type, 0, "enum" +HKR, Ndi\Params\BundleId, Default, 0, "1" +HKR, Ndi\Params\BundleId, Optional, 0, "1" +HKR, Ndi\Params\BundleId\enum, "1", 0, "Bundle 1" +HKR, Ndi\Params\BundleId\enum, "2", 0, "Bundle 2" +HKR, Ndi\Params\BundleId\enum, "3", 0, "Bundle 3" +HKR, Ndi\Params\BundleId\enum, "4", 0, "Bundle 4" +; +; +; ============= Service Install section ============== +; + +[vnic.ServiceInstall] +DisplayName = %vnic.ServiceDesc% +ServiceType = %SERVICE_KERNEL_DRIVER% +StartType = %SERVICE_DEMAND_START% +ErrorControl = %SERVICE_ERROR_NORMAL% +ServiceBinary = %12%\qlgcvnic.sys +LoadOrderGroup = NDIS +AddReg = vnic.ParamsReg + +[vnic.ParamsReg] + +HKR,"Parameters","DebugFlags",%REG_DWORD%,0x00000003 + +HKR,"Parameters","MinHostPoolSz",%REG_DWORD%,256 +HKR, "Parameters","HostRecvPoolEntries",%REG_DWORD%,512 +HKR, "Parameters","MinEiocPoolSz",%REG_DWORD%,256 +HKR, "Parameters","MaxEiocPoolSz",%REG_DWORD%,512 +HKR, "Parameters","MinHostKickTimeout",%REG_DWORD%,50 +HKR, "Parameters","MaxHostKickTimeout",%REG_DWORD%,100 +HKR, "Parameters","MinHostKickEntries",%REG_DWORD%,1 +HKR, "Parameters","MaxHostKickEntries",%REG_DWORD%,64 +HKR, "Parameters","MinHostKickBytes",%REG_DWORD%,0 +HKR, "Parameters","MaxHostKickBytes",%REG_DWORD%,5000 +HKR, "Parameters","MinHostUpdateSz",%REG_DWORD%,8 +HKR, "Parameters","MaxHostUpdateSz",%REG_DWORD%,32 +HKR, "Parameters","MinEiocUpdateSz",%REG_DWORD%,8 +HKR, "Parameters","MaxEiocUpdateSz",%REG_DWORD%,32 +HKR, "Parameters","HeartbeatTimeout",%REG_DWORD%,40000 + +[vnic.EventLogInstall] +AddReg = vnic.EventLogAddReg + +[vnic.EventLogAddReg] +HKR,,EventMessageFile,%REG_EXPAND_SZ%,"%%SystemRoot%%\System32\netevent.dll" +HKR,,TypesSupported,%REG_DWORD%,7 + +[Strings] +NetClassGuid="{4d36e972-e325-11ce-bfc1-08002be10318}" +Inf_Provider="QLogic Corporation" +vnic.DeviceDesc="Ethernet over InfiniBand Virtual NIC" +vnic.ServiceDesc="Virtual NIC" +DiskId="QLogic Ethernet over InfiniBand Disk" +InternalBus=0 +PNPBus=15 +SPSVCINST_NULL=0x0 +SPSVCINST_ASSOCSERVICE=0x00000002 +SERVICE_KERNEL_DRIVER=1 +SERVICE_DEMAND_START=3 +SERVICE_ERROR_NORMAL=1 +REG_DWORD=0x00010001 +REG_DWORD_NO_CLOBBER=0x00010003 +REG_EXPAND_SZ=0x00020000 +CHARACTERISTICS=0x81; NCF_VIRTUAL | NCF_HAS_UI diff --git a/branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_adapter.c b/branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_adapter.c new file mode 100644 index 00000000..dfec0429 --- /dev/null +++ b/branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_adapter.c @@ -0,0 +1,1845 @@ +/* + * Copyright (c) 2007 QLogic Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include +#include +#include +#include "vnic_adapter.h" + +//#include "vnic_driver.h" + +extern struct _vnic_globals g_vnic; + +NDIS_STATUS +vnic_get_adapter_params( + IN NDIS_HANDLE h_handle, + OUT vnic_params_t* const p_params ); + +static +NDIS_STATUS +_adapter_set_sg_size( + IN NDIS_HANDLE h_handle, + IN ULONG mtu_size ); + +NDIS_STATUS +vnic_get_adapter_interface( + IN NDIS_HANDLE h_handle, + IN vnic_adapter_t *p_adapter); + +static +vnic_path_record_t* +__path_record_add( + IN vnic_adapter_t* const p_adapter, + IN ib_path_rec_t* const p_path_rec ); + +static +vnic_path_record_t* +__path_record_remove( + IN vnic_adapter_t* const p_adapter, + IN ib_path_rec_t* const p_path_rec ); + +static BOOLEAN +__path_records_match( + IN ib_path_rec_t* const p_path1, + IN ib_path_rec_t* const p_path2 ); + +static +vnic_path_record_t * +__path_record_find( + IN vnic_adapter_t* const p_adapter, + IN ib_path_rec_t* const p_path_rec ); + +static +vnic_path_record_t* +__path_record_get( + IN vnic_adapter_t* const p_adapter ); + +static void +__path_records_cleanup( + IN vnic_adapter_t *p_adapter ); + +static ib_api_status_t +_adapter_open_ca( + IN vnic_adapter_t* const p_adapter ); + + +static ib_api_status_t +_adapter_close_ca( + IN vnic_adapter_t* const p_adapter ); + +static +ib_api_status_t +_adapter_netpath_update( + IN vnic_adapter_t* const p_adapter, + IN viport_t* const p_viport, + IN vnic_path_record_t* p_path ); + +static +ib_api_status_t +adapter_netpath_update_and_connect( + IN vnic_adapter_t* const p_adapter, + IN vnic_path_record_t *p_path ); + +static inline uint8_t +_get_ioc_num_from_iocguid( + IN ib_net64_t *p_iocguid ); + +static BOOLEAN +__sid_valid( + IN vnic_adapter_t *p_adapter, + IN ib_net64_t sid ); + +static void +__adapter_cleanup( + IN vnic_adapter_t *p_adapter ); + +#if ( LBFO_ENABLED ) + +static NDIS_STATUS +__adapter_set_failover_primary( + IN vnic_adapter_t* const p_adapter, + IN BOOLEAN promote_secondary ); + +static NDIS_STATUS +__adapter_set_failover_secondary( + IN vnic_adapter_t* const p_adapter, + IN NDIS_HANDLE primary_handle ); + +static void +__adapter_add_to_failover_list( + IN vnic_adapter_t* const p_adapter, + IN lbfo_state_t failover_state ); +static void +__adapter_remove_from_failover_list( + IN vnic_adapter_t* const p_adapter ); + +static +vnic_adapter_t* +__adapter_find_on_failover_list( + IN int list_flag, + IN uint32_t bundle_id ); + +#endif // LBFO_ENABLED + + +uint32_t _get_instance(ioc_ifc_data_t *ifc_data) +{ + cl_qlist_t *qlist; + cl_list_item_t *item; + vnic_adapter_t *p_adapter; + uint32_t instance = 1; + + qlist = &g_vnic.adapter_list; + + if (cl_qlist_count(qlist)) { + + item = cl_qlist_head(qlist); + + while(item != cl_qlist_end(qlist)) { + p_adapter = PARENT_STRUCT(item, vnic_adapter_t, list_adapter); + if (p_adapter->ifc_data.guid == ifc_data->guid) { + instance += 2; // Right now we are considering one interface will consume two instance IDs + } + item = cl_qlist_next(item); + } + + } + + return instance; + +} + +ib_api_status_t +vnic_create_adapter( + IN NDIS_HANDLE h_handle, + IN NDIS_HANDLE wrapper_config_context, + OUT vnic_adapter_t** const pp_adapter) +{ + NDIS_STATUS status; + ib_api_status_t ib_status; + vnic_adapter_t *p_adapter; + + VNIC_ENTER( VNIC_DBG_ADAPTER ); + + status = NdisAllocateMemoryWithTag( &p_adapter, sizeof(vnic_adapter_t), 'pada'); + + if ( status != NDIS_STATUS_SUCCESS ) + { + VNIC_TRACE_EXIT(VNIC_DBG_ERROR,("Failed to allocate adapter\n")); + return IB_INSUFFICIENT_MEMORY; + } + + NdisZeroMemory( p_adapter, sizeof(vnic_adapter_t) ); + + NdisAllocateSpinLock( &p_adapter->lock ); + NdisAllocateSpinLock( &p_adapter->path_records_lock ); + NdisAllocateSpinLock( &p_adapter->pending_list_lock ); + NdisAllocateSpinLock( &p_adapter->cancel_list_lock ); + + InitializeListHead( &p_adapter->send_pending_list ); + InitializeListHead( &p_adapter->cancel_send_list ); + + cl_qlist_init( &p_adapter->path_records_list ); + + status = + vnic_get_adapter_params( wrapper_config_context, &p_adapter->params ); + + if ( status != NDIS_STATUS_SUCCESS ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + (" vnic_get_adapter_params failed with status %d\n", status)); + NdisFreeMemory( p_adapter, sizeof(vnic_adapter_t), 0 ); + return IB_INVALID_PARAMETER; + } + + status = vnic_get_adapter_interface( h_handle, p_adapter ); + if ( status != NDIS_STATUS_SUCCESS ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + ("failed status %x\n", status ) ); + NdisFreeMemory( p_adapter, sizeof(vnic_adapter_t), 0 ); + return IB_INVALID_PARAMETER; + } + + /*Open AL */ + ib_status = p_adapter->ifc.open_al( &p_adapter->h_al ); + if ( ib_status != IB_SUCCESS ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + ("ib_open_al returned %s\n", + p_adapter->ifc.get_err_str( ib_status )) ); + NdisFreeMemory( p_adapter, sizeof(vnic_adapter_t), 0 ); + return ib_status; + } + + /* we will use these indexes later as an viport instance ID for connect request + * since target requires unique instance per connection per IOC. + */ + p_adapter->primaryPath.instance = _get_instance(&p_adapter->ifc_data); + p_adapter->secondaryPath.instance = (p_adapter->primaryPath.instance) + 1; + /* set adapter level params here */ + p_adapter->vlan_info = p_adapter->params.VlanInfo; + +#if ( LBFO_ENABLED ) + + p_adapter->failover.bundle_id = p_adapter->params.bundle_id; + p_adapter->failover.fo_state = _ADAPTER_NOT_BUNDLED; + +#endif + + p_adapter->h_handle = h_handle; + *pp_adapter = p_adapter; + + // Insert in global list of adapters + cl_qlist_insert_tail (&g_vnic.adapter_list, &p_adapter->list_adapter); + VNIC_EXIT( VNIC_DBG_ADAPTER ); + return IB_SUCCESS; +} + + +void +vnic_destroy_adapter( + IN vnic_adapter_t *p_adapter) +{ + ib_api_status_t ib_status = IB_SUCCESS; + ib_pnp_handle_t h_pnp; + ib_al_handle_t h_al; + + VNIC_ENTER( VNIC_DBG_ADAPTER ); + + ASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL ); + + if( ( h_pnp = InterlockedExchangePointer( (void *)&p_adapter->h_pnp, NULL ) ) != NULL ) + { + ib_status = + p_adapter->ifc.dereg_pnp( h_pnp, NULL ); + } + + /* should not receive new path notifications anymore, safe to cleanup */ + + if( InterlockedCompareExchange( (volatile LONG *)&p_adapter->state, + INIC_DEREGISTERING, INIC_REGISTERED ) == INIC_REGISTERED ) + { + __adapter_cleanup( p_adapter ); + } + + _adapter_close_ca( p_adapter ); + +#if ( LBFO_ENABLED ) + + __adapter_remove_from_failover_list( p_adapter ); + +#endif + + InterlockedExchange( (volatile LONG *)&p_adapter->state, INIC_UNINITIALIZED ); + if( ( h_al = InterlockedExchangePointer( (void *)&p_adapter->h_al, NULL ) ) != NULL ) + { + ib_status = p_adapter->ifc.close_al( h_al ); + ASSERT( ib_status == IB_SUCCESS ); + } + + cl_qlist_remove_item(&g_vnic.adapter_list, &p_adapter->list_adapter); + NdisFreeSpinLock( &p_adapter->lock ); + NdisFreeSpinLock( &p_adapter->path_records_lock ); + NdisFreeMemory( p_adapter, sizeof(vnic_adapter_t), 0 ); + p_adapter = NULL; + + VNIC_EXIT( VNIC_DBG_ADAPTER ); +} + +static ib_api_status_t +_adapter_open_ca( + IN vnic_adapter_t* const p_adapter ) +{ + ib_api_status_t ib_status = IB_SUCCESS; + ib_al_ifc_t *p_ifc = &p_adapter->ifc; + uint32_t attr_size; + ib_ca_attr_t *p_ca_attrs; + uint32_t num; + uint64_t start_addr = 0; + + if( p_adapter->h_ca ) + return ib_status; + + ib_status = p_ifc->open_ca( p_adapter->h_al, + p_adapter->ifc_data.ca_guid, + NULL, //ib_asyncEvent, + p_adapter, + &p_adapter->h_ca ); + + if ( ib_status != IB_SUCCESS ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + ("Failed to open hca\n") ); + return IB_INSUFFICIENT_RESOURCES; + } + + ib_status = p_ifc->query_ca( p_adapter->h_ca, NULL , &attr_size ); + if( ib_status != IB_INSUFFICIENT_MEMORY ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + ("ib_query_ca failed status %s\n", + p_ifc->get_err_str( ib_status )) ); + + ib_status = IB_INSUFFICIENT_RESOURCES; + goto ca_failure; + } + + ASSERT( attr_size ); + + p_ca_attrs = cl_zalloc( attr_size ); + if ( p_ca_attrs == NULL ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + ("Allocate %d bytes failed for Channel adapter\n", attr_size )); + + ib_status = IB_INSUFFICIENT_MEMORY; + goto ca_failure; + } + + ib_status = p_ifc->query_ca( p_adapter->h_ca, p_ca_attrs , &attr_size ); + if ( ib_status != IB_SUCCESS ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + ("CA attributes query failed\n") ); + cl_free ( p_ca_attrs ); + goto ca_failure; + } + + p_adapter->ca.numPorts = p_ca_attrs->num_ports; + if( p_adapter->ca.numPorts > VNIC_CA_MAX_PORTS ) + p_adapter->ca.numPorts = VNIC_CA_MAX_PORTS; + + for( num = 0; num < p_adapter->ca.numPorts; num++ ) + p_adapter->ca.portGuids[num] = p_ca_attrs->p_port_attr[num].port_guid; + + p_adapter->ca.caGuid = p_adapter->ifc_data.ca_guid; + + cl_free ( p_ca_attrs ); + + ib_status = p_adapter->ifc.alloc_pd( p_adapter->h_ca, + IB_PDT_NORMAL, p_adapter, &p_adapter->ca.hPd ); + if ( ib_status != IB_SUCCESS ) + { + VNIC_TRACE_EXIT ( VNIC_DBG_ERROR, + ("Alloc PD failed status %s(%d)\n", + p_adapter->ifc.get_err_str(ib_status), ib_status )); + goto ca_failure; + } + + if ( ( ib_status = ibregion_physInit( p_adapter, + &p_adapter->ca.region, + p_adapter->ca.hPd, + &start_addr, + MAX_PHYS_MEMORY ) ) != IB_SUCCESS ) + { + VNIC_TRACE_EXIT ( VNIC_DBG_ERROR, + ("phys region init failed status %s(%d)\n", + p_adapter->ifc.get_err_str(ib_status), ib_status )); + p_adapter->ifc.dealloc_pd( p_adapter->ca.hPd, NULL ); + goto ca_failure; + } + + return ib_status; + +ca_failure: + if( p_adapter->h_ca ) + p_ifc->close_ca( p_adapter->h_ca, NULL ); + + return ib_status; +} + +static BOOLEAN +_adapter_params_sanity_check(vnic_params_t *p_params) +{ + DEFAULT_PARAM( p_params->MaxAddressEntries, MAX_ADDRESS_ENTRIES ); + DEFAULT_PARAM( p_params->MinAddressEntries, MIN_ADDRESS_ENTRIES ); + + DEFAULT_PARAM( p_params->ViportStatsInterval, VIPORT_STATS_INTERVAL ); + DEFAULT_PARAM( p_params->ViportHbInterval, VIPORT_HEARTBEAT_INTERVAL ); + DEFAULT_PARAM( p_params->ViportHbTimeout, VIPORT_HEARTBEAT_TIMEOUT ); + + DEFAULT_PARAM( p_params->ControlRspTimeout, CONTROL_RSP_TIMEOUT ); + DEFAULT_PARAM( p_params->ControlReqRetryCount, CONTROL_REQ_RETRY_COUNT ); + + DEFAULT_PARAM( p_params->RetryCount, RETRY_COUNT ); + DEFAULT_PARAM( p_params->MinRnrTimer, MIN_RNR_TIMER ); + + DEFAULT_PARAM( p_params->MaxViportsPerNetpath, MAX_VIPORTS_PER_NETPATH ); + DEFAULT_PARAM( p_params->DefaultViportsPerNetpath, DEFAULT_VIPORTS_PER_NETPATH ); + + DEFAULT_PARAM( p_params->DefaultPkey, DEFAULT_PKEY ); + DEFAULT_PARAM( p_params->NotifyBundleSz, NOTIFY_BUNDLE_SZ ); + DEFAULT_PARAM( p_params->DefaultNoPathTimeout, DEFAULT_NO_PATH_TIMEOUT ); + DEFAULT_PARAM( p_params->DefaultPrimaryConnectTimeout, DEFAULT_PRI_CON_TIMEOUT ); + DEFAULT_PARAM( p_params->DefaultPrimaryReconnectTimeout, DEFAULT_PRI_RECON_TIMEOUT ); + DEFAULT_PARAM( p_params->DefaultPrimarySwitchTimeout, DEFAULT_PRI_SWITCH_TIMEOUT ); + DEFAULT_PARAM( p_params->DefaultPreferPrimary, DEFAULT_PREFER_PRIMARY ); + + U32_RANGE( p_params->MaxAddressEntries ); + U32_RANGE( p_params->MinAddressEntries ); + RANGE_CHECK( p_params->MinMtu, MIN_MTU, MAX_MTU ); + RANGE_CHECK( p_params->MaxMtu, MIN_MTU, MAX_MTU ); + U32_RANGE( p_params->HostRecvPoolEntries ); + U32_RANGE( p_params->MinHostPoolSz ); + U32_RANGE( p_params->MinEiocPoolSz ); + U32_RANGE( p_params->MaxEiocPoolSz ); + U32_ZERO_RANGE( p_params->MinHostKickTimeout ); + U32_ZERO_RANGE( p_params->MaxHostKickTimeout ); + U32_ZERO_RANGE( p_params->MinHostKickEntries ); + U32_ZERO_RANGE( p_params->MaxHostKickEntries ); + U32_ZERO_RANGE( p_params->MinHostKickBytes ); + U32_ZERO_RANGE( p_params->MaxHostKickBytes ); + U32_RANGE( p_params->MinHostUpdateSz ); + U32_RANGE( p_params->MaxHostUpdateSz ); + U32_RANGE( p_params->MinEiocUpdateSz ); + U32_RANGE( p_params->MaxEiocUpdateSz ); + U8_RANGE( p_params->NotifyBundleSz ); + U32_ZERO_RANGE( p_params->ViportStatsInterval ); + U32_ZERO_RANGE( p_params->ViportHbInterval ); + U32_ZERO_RANGE( p_params->ViportHbTimeout ); + U32_RANGE( p_params->ControlRspTimeout ); + U8_RANGE( p_params->ControlReqRetryCount ); + ZERO_RANGE_CHECK( p_params->RetryCount, 0, 7 ); + ZERO_RANGE_CHECK( p_params->MinRnrTimer, 0, 31 ); + U32_RANGE( p_params->DefaultViportsPerNetpath ); + U8_RANGE( p_params->MaxViportsPerNetpath ); + U16_ZERO_RANGE( p_params->DefaultPkey ); + U32_RANGE( p_params->DefaultNoPathTimeout ); + U32_RANGE( p_params->DefaultPrimaryConnectTimeout ); + U32_RANGE( p_params->DefaultPrimaryReconnectTimeout ); + U32_RANGE( p_params->DefaultPrimarySwitchTimeout ); + BOOLEAN_RANGE( p_params->DefaultPreferPrimary ); + BOOLEAN_RANGE( p_params->UseRxCsum ); + BOOLEAN_RANGE( p_params->UseTxCsum ); + + LESS_THAN_OR_EQUAL( p_params->MinAddressEntries, p_params->MaxAddressEntries ); + LESS_THAN_OR_EQUAL( p_params->MinMtu, p_params->MaxMtu ); + LESS_THAN_OR_EQUAL( p_params->MinHostPoolSz, p_params->HostRecvPoolEntries ); + POWER_OF_2( p_params->HostRecvPoolEntries ); + POWER_OF_2( p_params->MinHostPoolSz ); + POWER_OF_2( p_params->NotifyBundleSz ); + LESS_THAN( p_params->NotifyBundleSz, p_params->MinEiocPoolSz ); + LESS_THAN_OR_EQUAL( p_params->MinEiocPoolSz, p_params->MaxEiocPoolSz ); + POWER_OF_2( p_params->MinEiocPoolSz ); + POWER_OF_2( p_params->MaxEiocPoolSz ); + LESS_THAN_OR_EQUAL( p_params->MinHostKickTimeout, p_params->MaxHostKickTimeout ); + LESS_THAN_OR_EQUAL( p_params->MinHostKickEntries, p_params->MaxHostKickEntries ); + LESS_THAN_OR_EQUAL( p_params->MinHostKickBytes, p_params->MaxHostKickBytes ); + LESS_THAN_OR_EQUAL( p_params->MinHostUpdateSz, p_params->MaxHostUpdateSz ); + POWER_OF_2( p_params->MinHostUpdateSz ); + POWER_OF_2( p_params->MaxHostUpdateSz ); + LESS_THAN( p_params->MinHostUpdateSz, p_params->MinHostPoolSz ); + LESS_THAN( p_params->MaxHostUpdateSz, p_params->HostRecvPoolEntries ); + LESS_THAN_OR_EQUAL( p_params->MinEiocUpdateSz, p_params->MaxEiocUpdateSz ); + POWER_OF_2( p_params->MinEiocUpdateSz ); + POWER_OF_2( p_params->MaxEiocUpdateSz ); + LESS_THAN( p_params->MinEiocUpdateSz, p_params->MinEiocPoolSz ); + LESS_THAN( p_params->MaxEiocUpdateSz, p_params->MaxEiocPoolSz ); + LESS_THAN_OR_EQUAL( p_params->DefaultViportsPerNetpath, p_params->MaxViportsPerNetpath ); + + return TRUE; + +} +NDIS_STATUS +vnic_get_adapter_params( + IN NDIS_HANDLE wrapper_config_context, + OUT vnic_params_t* const p_params ) +{ + NDIS_STATUS status; + NDIS_HANDLE h_config; + NDIS_CONFIGURATION_PARAMETER *p_reg_prm; + NDIS_STRING keyword; + + VNIC_ENTER( VNIC_DBG_ADAPTER ); + + CL_ASSERT(p_params ); + + /* prepare params for default initialization */ + cl_memset( p_params, 0xff, sizeof (vnic_params_t) ); + + NdisOpenConfiguration( &status, &h_config, wrapper_config_context ); + if( status != NDIS_STATUS_SUCCESS ) + { + VNIC_TRACE_EXIT( VNIC_DBG_ERROR, + ("NdisOpenConfiguration returned 0x%.8x\n", status) ); + return status; + } + + status = NDIS_STATUS_FAILURE; + p_reg_prm = NULL; + + RtlInitUnicodeString( &keyword, L"PayloadMtu" ); + NdisReadConfiguration( + &status, &p_reg_prm, h_config, &keyword, NdisParameterInteger ); + + p_params->MinMtu = ( status != NDIS_STATUS_SUCCESS ) ? MIN_MTU: + p_reg_prm->ParameterData.IntegerData; + p_params->MaxMtu = MAX_MTU; + + RtlInitUnicodeString( &keyword, L"UseRxCsum" ); + NdisReadConfiguration( + &status, &p_reg_prm, h_config, &keyword, NdisParameterInteger ); + + p_params->UseRxCsum = ( status != NDIS_STATUS_SUCCESS ) ? + TRUE : ( p_reg_prm->ParameterData.IntegerData )? TRUE : FALSE; + + RtlInitUnicodeString( &keyword, L"UseTxCsum" ); + NdisReadConfiguration( + &status, &p_reg_prm, h_config, &keyword, NdisParameterInteger ); + + /* turn it on by default, if not present */ + p_params->UseTxCsum = ( status != NDIS_STATUS_SUCCESS ) ? + TRUE : ( p_reg_prm->ParameterData.IntegerData )? TRUE : FALSE; + + /* handle VLAN + Priority paramters */ + RtlInitUnicodeString( &keyword, L"VlanId" ); + NdisReadConfiguration( + &status, &p_reg_prm, h_config, &keyword, NdisParameterInteger ); + + if( status == NDIS_STATUS_SUCCESS ) + { + p_params->VlanInfo = + ( p_reg_prm->ParameterData.IntegerData & 0x00000fff ); + + RtlInitUnicodeString( &keyword, L"UserPriority" ); + NdisReadConfiguration( + &status, &p_reg_prm, h_config, &keyword, NdisParameterInteger ); + + p_params->VlanInfo |= ( status != NDIS_STATUS_SUCCESS ) ? 0 : + ( ( p_reg_prm->ParameterData.IntegerData & 0x00000007 ) << 13 ); + } + else + { + p_params->VlanInfo = 0; + } + + RtlInitUnicodeString( &keyword, L"SecondaryPath" ); + NdisReadConfiguration( + &status, &p_reg_prm, h_config, &keyword, NdisParameterInteger ); + + /* disable, if not set. Save extra viport slot */ + p_params->SecondaryPath = ( status != NDIS_STATUS_SUCCESS ) ? + FALSE : ( p_reg_prm->ParameterData.IntegerData )? TRUE : FALSE; + + RtlInitUnicodeString( &keyword, L"Heartbeat" ); + NdisReadConfiguration( + &status, &p_reg_prm, h_config, &keyword, NdisParameterInteger ); + + p_params->ViportHbInterval = ( status != NDIS_STATUS_SUCCESS ) ? + VIPORT_HEARTBEAT_INTERVAL : p_reg_prm->ParameterData.IntegerData; + +#if ( LBFO_ENABLED ) + /* read Failover group Name/Number */ + + RtlInitUnicodeString( &keyword, L"BundleId" ); + NdisReadConfiguration( + &status, &p_reg_prm, h_config, &keyword, NdisParameterInteger ); + + p_params->bundle_id = ( status != NDIS_STATUS_SUCCESS ) ? 0 : + p_reg_prm->ParameterData.IntegerData; +#endif // LBFO_ENABLED + + NdisCloseConfiguration( h_config ); + + /* initialize the rest of adapter parameters with driver's global set */ + if( g_vnic.p_params != NULL ) + { + /* get global parameters from service entry */ + p_params->MinHostPoolSz = g_vnic.p_params[INDEX_MIN_HOST_POOL_SZ].value; + p_params->HostRecvPoolEntries = g_vnic.p_params[INDEX_HOST_RECV_POOL_ENTRIES].value; + + p_params->MinEiocPoolSz = g_vnic.p_params[INDEX_MIN_EIOC_POOL_SZ].value; + p_params->MaxEiocPoolSz = g_vnic.p_params[INDEX_MAX_EIOC_POOL_SZ].value; + + p_params->MinHostKickTimeout = g_vnic.p_params[INDEX_MIN_HOST_KICK_TIMEOUT].value; + p_params->MaxHostKickTimeout = g_vnic.p_params[INDEX_MAX_HOST_KICK_TIMEOUT].value; + + p_params->MinHostKickEntries = g_vnic.p_params[INDEX_MIN_HOST_KICK_ENTRIES].value; + p_params->MaxHostKickEntries = g_vnic.p_params[INDEX_MAX_HOST_KICK_ENTRIES].value; + + p_params->MinHostKickBytes = g_vnic.p_params[INDEX_MIN_HOST_KICK_BYTES].value; + p_params->MaxHostKickBytes = g_vnic.p_params[INDEX_MAX_HOST_KICK_BYTES].value; + + p_params->MinHostUpdateSz = g_vnic.p_params[INDEX_MIN_HOST_UPDATE_SZ].value; + p_params->MaxHostUpdateSz = g_vnic.p_params[INDEX_MAX_HOST_UPDATE_SZ].value; + + p_params->MinEiocUpdateSz = g_vnic.p_params[INDEX_MIN_EIOC_UPDATE_SZ].value; + p_params->MaxEiocUpdateSz = g_vnic.p_params[INDEX_MAX_EIOC_UPDATE_SZ].value; + + p_params->ViportHbTimeout = g_vnic.p_params[INDEX_HEARTBEAT_TIMEOUT].value; + } + else + { + /* set default constants */ + p_params->MinHostPoolSz = MIN_HOST_POOL_SZ; + p_params->HostRecvPoolEntries = HOST_RECV_POOL_ENTRIES; + p_params->MinEiocPoolSz = MIN_EIOC_POOL_SZ; + p_params->MaxEiocPoolSz = MAX_EIOC_POOL_SZ; + p_params->MinHostKickTimeout = MIN_HOST_KICK_TIMEOUT; + p_params->MaxHostKickTimeout = MAX_HOST_KICK_TIMEOUT; + p_params->MinHostKickEntries = MIN_HOST_KICK_ENTRIES; + p_params->MaxHostKickEntries = MAX_HOST_KICK_ENTRIES; + p_params->MinHostKickBytes = MIN_HOST_KICK_BYTES; + p_params->MaxHostKickBytes = MAX_HOST_KICK_BYTES; + p_params->MinHostUpdateSz = MIN_HOST_UPDATE_SZ; + p_params->MaxHostUpdateSz = MAX_HOST_UPDATE_SZ; + p_params->MinEiocUpdateSz = MIN_EIOC_UPDATE_SZ; + p_params->MaxEiocUpdateSz = MAX_EIOC_UPDATE_SZ; + } + + status = ( _adapter_params_sanity_check(p_params)? + NDIS_STATUS_SUCCESS: NDIS_STATUS_FAILURE ); + + VNIC_EXIT( VNIC_DBG_ADAPTER ); + return status; +} + +ib_api_status_t +adapter_viport_allocate( + IN vnic_adapter_t* const p_adapter, + IN OUT viport_t** const pp_viport ) +{ + viport_t *p_viport; + NDIS_STATUS status; + + VNIC_ENTER( VNIC_DBG_ADAPTER ); + + NdisAcquireSpinLock( &p_adapter->lock ); + + status = NdisAllocateMemoryWithTag( &p_viport, sizeof(viport_t), 'trop' ); + if( status != NDIS_STATUS_SUCCESS ) + { + NdisReleaseSpinLock( &p_adapter->lock ); + VNIC_TRACE_EXIT(VNIC_DBG_ERROR, + ( "Failed allocating Viport structure\n" )); + return IB_ERROR; + } + + NdisZeroMemory( p_viport, sizeof(viport_t) ); + NdisAllocateSpinLock( &p_viport->lock ); + InitializeListHead( &p_viport->listPtrs ); + cl_event_init( &p_viport->sync_event, FALSE ); + + p_viport->p_adapter = p_adapter; + viport_config_defaults ( p_viport ); + + control_construct( &p_viport->control, p_viport ); + data_construct( &p_viport->data, p_viport ); + + p_viport->ioc_num = _get_ioc_num_from_iocguid( &p_adapter->ifc_data.guid ); + if( !p_adapter->ioc_num ) + { + p_adapter->ioc_num = p_viport->ioc_num; + } + + CL_ASSERT( p_adapter->ioc_num == p_viport->ioc_num ); + + *pp_viport = p_viport; + + NdisReleaseSpinLock( &p_adapter->lock ); + + VNIC_EXIT( VNIC_DBG_ADAPTER ); + return IB_SUCCESS; +} + + +static void +_adapter_netpath_free( + IN vnic_adapter_t* const p_adapter, + IN Netpath_t* p_netpath ) +{ + + UNREFERENCED_PARAMETER( p_adapter ); + + if( netpath_is_valid( p_netpath ) ) + { + VNIC_TRACE( VNIC_DBG_INFO, + ("IOC[%d] instance %d Free Path\n", + p_adapter->ioc_num, p_netpath->instance )); + + netpath_free( p_netpath ); + netpath_init( p_netpath, NULL ); + } +} + +NDIS_STATUS +adapter_set_mcast( + IN vnic_adapter_t* const p_adapter, + IN mac_addr_t* const p_mac_array, + IN const uint8_t mc_count ) +{ + NDIS_STATUS status; + int i; + VNIC_ENTER( VNIC_DBG_MCAST ); + + if( !netpath_is_valid( p_adapter->p_currentPath ) ) + return NDIS_STATUS_NOT_ACCEPTED; + + VNIC_TRACE( VNIC_DBG_MCAST, + ("IOC[%d] MCAST COUNT to set = %d\n", + p_adapter->ioc_num, mc_count)); + + /* Copy the MC address list into the adapter. */ + if( mc_count ) + { + RtlCopyMemory( + p_adapter->mcast_array, p_mac_array, mc_count * MAC_ADDR_LEN ); + for( i = 0; i < mc_count; i++ ) + VNIC_TRACE( VNIC_DBG_MCAST, + ("[%d] %02x:%02x:%02x:%02x:%02x:%02x\n", i, + p_mac_array->addr[0], p_mac_array->addr[1], p_mac_array->addr[2], + p_mac_array->addr[3], p_mac_array->addr[4], p_mac_array->addr[5] )); + } + p_adapter->mc_count = mc_count; + + p_adapter->pending_set = TRUE; + status = netpath_setMulticast( p_adapter->p_currentPath ); + if( status != NDIS_STATUS_PENDING ) + { + p_adapter->pending_set = FALSE; + } + + VNIC_EXIT( VNIC_DBG_MCAST ); + return status; +} + + +static BOOLEAN +__path_records_match( + IN ib_path_rec_t* const p_path1, + IN ib_path_rec_t* const p_path2 ) +{ + if( p_path1->dgid.unicast.prefix != p_path2->dgid.unicast.prefix ) + return FALSE; + if( p_path1->dgid.unicast.interface_id != p_path2->dgid.unicast.interface_id ) + return FALSE; + if( p_path1->dlid != p_path2->dlid ) + return FALSE; + + if( p_path1->sgid.unicast.prefix != p_path2->sgid.unicast.prefix ) + return FALSE; + if( p_path1->sgid.unicast.interface_id != p_path2->sgid.unicast.interface_id ) + return FALSE; + if( p_path1->slid != p_path2->slid ) + return FALSE; + + if( p_path1->pkey != p_path2->pkey ) + return FALSE; + if( p_path1->rate != p_path2->rate ) + return FALSE; + if( ib_path_rec_sl(p_path1) != ib_path_rec_sl(p_path2) ) + return FALSE; + if( p_path1->tclass != p_path2->tclass ) + return FALSE; + + return TRUE; +} + +static BOOLEAN +__sid_valid( + IN vnic_adapter_t *p_adapter, + IN ib_net64_t sid ) +{ + vnic_sid_t svc_id; + svc_id.as_uint64 = sid; + if( ( svc_id.s.base_id & 0x10 ) != 0x10 ) + return FALSE; + if( svc_id.s.oui[0] != 0x00 && + svc_id.s.oui[1] != 0x06 && + svc_id.s.oui[2] != 0x6a ) + return FALSE; + if ( svc_id.s.type != CONTROL_SID && + svc_id.s.type != DATA_SID ) + return FALSE; + if ( svc_id.s.ioc_num != _get_ioc_num_from_iocguid( &p_adapter->ifc_data.guid ) ) + return FALSE; + return TRUE; +} +static inline uint8_t +_get_ioc_num_from_iocguid( + IN ib_net64_t *p_iocguid ) +{ + return ( (vnic_ioc_guid_t *)p_iocguid)->s.ioc_num; +} + +static +vnic_path_record_t* +__path_record_add( + IN vnic_adapter_t* const p_adapter, + IN ib_path_rec_t* const p_path_rec ) +{ + + vnic_path_record_t *p_path; + + p_path = __path_record_find( p_adapter, p_path_rec ); + + if( !p_path ) + { + p_path = cl_zalloc( sizeof( vnic_path_record_t ) ); + if( !p_path ) + return NULL; + + NdisAcquireSpinLock( &p_adapter->path_records_lock ); + + p_path->path_rec = *p_path_rec; + cl_qlist_insert_tail( &p_adapter->path_records_list, &p_path->list_entry ); + + NdisReleaseSpinLock( &p_adapter->path_records_lock ); + + VNIC_TRACE( VNIC_DBG_PNP, + ("New path Added to the list[ list size %d]\n", + cl_qlist_count(&p_adapter->path_records_list) )); + + return p_path; + } + VNIC_TRACE( VNIC_DBG_PNP, + ( "Path to add is already on the List\n" ) ); + + return NULL; +} + +static +vnic_path_record_t* +__path_record_get( + IN vnic_adapter_t* const p_adapter ) +{ + cl_list_item_t *p_item; + + p_item = cl_qlist_head( &p_adapter->path_records_list ); + + if( p_item != cl_qlist_end( &p_adapter->path_records_list ) ) + { + return ( vnic_path_record_t *)p_item; + } + return NULL; +} + +static +vnic_path_record_t* +__path_record_remove( + IN vnic_adapter_t* const p_adapter, + IN ib_path_rec_t* const p_path_rec ) +{ + + vnic_path_record_t *p_path; + + + p_path = __path_record_find( p_adapter, p_path_rec ); + + if ( p_path ) + { + NdisAcquireSpinLock( &p_adapter->path_records_lock ); + + cl_qlist_remove_item( &p_adapter->path_records_list, &p_path->list_entry ); + + NdisReleaseSpinLock( &p_adapter->path_records_lock ); + } + + return p_path; +} + +static +vnic_path_record_t * +__path_record_find( + IN vnic_adapter_t* const p_adapter, + IN ib_path_rec_t* const p_path_rec ) +{ + cl_list_item_t *p_item; + vnic_path_record_t *p_path = NULL; + + NdisAcquireSpinLock( &p_adapter->path_records_lock ); + + if( !cl_qlist_count( &p_adapter->path_records_list ) ) + { + NdisReleaseSpinLock( &p_adapter->path_records_lock ); + return NULL; + } + + p_item = cl_qlist_head( &p_adapter->path_records_list ); + + while( p_item != cl_qlist_end( &p_adapter->path_records_list ) ) + { + p_path = ( vnic_path_record_t *)p_item; + + if ( __path_records_match( &p_path->path_rec, p_path_rec ) ) + { + break; + } + + p_item = cl_qlist_next( p_item ); + } + + NdisReleaseSpinLock( &p_adapter->path_records_lock ); + + if( p_item == cl_qlist_end( &p_adapter->path_records_list ) ) + { + p_path = NULL; + } + return p_path; +} + +void +__pending_queue_cleanup( + IN vnic_adapter_t *p_adapter ) +{ + LIST_ENTRY *p_list_item; + NDIS_PACKET *p_packet; + + VNIC_ENTER( VNIC_DBG_ADAPTER ); + + /* clear pending queue if any */ + + while( ( p_list_item = NdisInterlockedRemoveHeadList( + &p_adapter->send_pending_list, + &p_adapter->pending_list_lock )) != NULL ) + { + p_packet = VNIC_PACKET_FROM_LIST_ITEM( p_list_item ); + if ( p_packet ) + { + NDIS_SET_PACKET_STATUS( p_packet, NDIS_STATUS_FAILURE ); + NdisMSendComplete( p_adapter->h_handle, p_packet, NDIS_STATUS_FAILURE ); + } + } + + VNIC_EXIT( VNIC_DBG_ADAPTER ); +} + +static void +__path_records_cleanup( + vnic_adapter_t *p_adapter ) +{ + + vnic_path_record_t *p_path; + cl_list_item_t *p_item; + + p_item = cl_qlist_remove_head( &p_adapter->path_records_list ); + + while( p_item != cl_qlist_end( &p_adapter->path_records_list ) ) + { + p_path = (vnic_path_record_t *)p_item; + + cl_free( p_path ); + + p_item = cl_qlist_remove_head( &p_adapter->path_records_list ); + } + + return; +} + +ib_api_status_t +__vnic_pnp_cb( + IN ib_pnp_rec_t *p_pnp_rec ) +{ + ib_api_status_t ib_status = IB_SUCCESS; + ib_pnp_ioc_rec_t *p_ioc_rec; + ib_pnp_ioc_path_rec_t *p_ioc_path; + vnic_path_record_t *p_path_record; + Netpath_t* p_netpath = NULL; + +#if ( LBFO_ENABLED ) + vnic_adapter_t *p_primary_adapter; +#endif + + vnic_adapter_t * p_adapter = (vnic_adapter_t *)p_pnp_rec->pnp_context; + + VNIC_ENTER( VNIC_DBG_PNP ); + + CL_ASSERT( p_adapter ); + + switch( p_pnp_rec->pnp_event ) + { + case IB_PNP_IOC_ADD: + p_ioc_rec = (ib_pnp_ioc_rec_t*)p_pnp_rec; + + if( p_adapter->ifc_data.ca_guid != p_ioc_rec->ca_guid ) + { + ib_status = IB_INVALID_GUID; + break; + } + if( p_adapter->ifc_data.guid != p_ioc_rec->info.profile.ioc_guid ) + { + ib_status = IB_INVALID_GUID; + break; + } + InterlockedExchange( (volatile LONG*)&p_adapter->pnp_state, IB_PNP_IOC_ADD ); + + VNIC_TRACE( VNIC_DBG_PNP, ("IB_PNP_IOC_ADD for %s.\n", + p_ioc_rec->info.profile.id_string) ); + + /* get ioc profile data */ + NdisAcquireSpinLock( &p_adapter->lock ); + + if( !__sid_valid( p_adapter, p_ioc_rec->svc_entry_array[0].id ) ) + { + NdisReleaseSpinLock( &p_adapter->lock ); + + VNIC_TRACE_EXIT( VNIC_DBG_ERROR, + ("Invalid Service ID %#I64x\n",p_ioc_rec->svc_entry_array[0].id ) ); + + ib_status = IB_INVALID_GUID; // should it be set INVALID_SERVICE_TYPE ? + break; + } + + p_adapter->ioc_info = p_ioc_rec->info; + CL_ASSERT(p_adapter->ioc_info.profile.num_svc_entries == 2 ); + + p_adapter->svc_entries[0] = p_ioc_rec->svc_entry_array[0]; + p_adapter->svc_entries[1] = p_ioc_rec->svc_entry_array[1]; + p_adapter->ioc_num = _get_ioc_num_from_iocguid( &p_adapter->ifc_data.guid ); + + VNIC_TRACE( VNIC_DBG_PNP, + ("Found %d Service Entries.\n", p_adapter->ioc_info.profile.num_svc_entries)); + + NdisReleaseSpinLock( &p_adapter->lock ); + + break; + + case IB_PNP_IOC_REMOVE: + CL_ASSERT( p_pnp_rec->guid == p_adapter->ifc_data.guid ); + + p_ioc_rec = (ib_pnp_ioc_rec_t*)p_pnp_rec; + + if( InterlockedExchange( (volatile LONG*)&p_adapter->pnp_state, IB_PNP_IOC_REMOVE ) == IB_PNP_IOC_ADD ) + { + VNIC_TRACE( VNIC_DBG_INIT, ("IB_PNP_IOC_REMOVE for %s.\n", + p_adapter->ioc_info.profile.id_string) ); + + if( netpath_is_valid( p_adapter->p_currentPath ) ) + { + netpath_stopXmit( p_adapter->p_currentPath ); + InterlockedExchange( &p_adapter->p_currentPath->carrier, (LONG)FALSE ); + netpath_linkDown( p_adapter->p_currentPath ); + __pending_queue_cleanup( p_adapter ); + } + } + break; + + case IB_PNP_IOC_PATH_ADD: + /* path for our IOC ? */ + if ( p_pnp_rec->guid != p_adapter->ifc_data.guid ) + { + VNIC_TRACE( VNIC_DBG_PNP, + ("Getting path for wrong IOC\n") ); + ib_status = IB_INVALID_GUID; + break; + } + p_ioc_path = (ib_pnp_ioc_path_rec_t*)p_pnp_rec; + + p_path_record = __path_record_add( p_adapter, &p_ioc_path->path ); + if ( p_path_record == NULL ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + ("Failed to add path record\n") ); + break; + } + + if( p_adapter->state == INIC_REGISTERED ) + { + if( p_adapter->num_paths > 0 ) + { + if( p_adapter->params.SecondaryPath != TRUE ) + { + VNIC_TRACE ( VNIC_DBG_WARN, + ("Allowed one path at a time\n") ); + break; + } + } + + if( p_adapter->num_paths > 1 ) + { + VNIC_TRACE ( VNIC_DBG_WARN, + ("Max Paths[%d] Connected already\n", p_adapter->num_paths) ); + break; + } + } + + ib_status = adapter_netpath_update_and_connect( + p_adapter, p_path_record ); + if( ib_status != IB_SUCCESS ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + ("IOC[%d] adapter_netpath_update_and_connect return %s\n", + p_adapter->ioc_num, + p_adapter->ifc.get_err_str( ib_status )) ); + break; + } + + InterlockedCompareExchange( (volatile LONG *)&p_adapter->state, + INIC_REGISTERED, INIC_UNINITIALIZED ); +#if ( LBFO_ENABLED ) + + if( p_adapter->failover.fo_state == _ADAPTER_NOT_BUNDLED ) + { + /* we don't look for zero id, since it meant to be primary by default */ + if( p_adapter->failover.bundle_id != 0 && + ( p_primary_adapter = __adapter_find_on_failover_list( _ADAPTER_PRIMARY, + p_adapter->failover.bundle_id ) ) != NULL ) + { + /* found matching primary */ + __adapter_set_failover_secondary( + p_adapter, p_primary_adapter->h_handle ); + } + else + { + /* bundle_id '0' , all go to primary */ + __adapter_set_failover_primary( p_adapter, FALSE ); + } + } + +#endif // LBFO_ENABLED + + break; + + case IB_PNP_IOC_PATH_REMOVE: + p_ioc_path = (ib_pnp_ioc_path_rec_t*)p_pnp_rec; + + VNIC_TRACE( VNIC_DBG_PNP, + ("IB_PNP_IOC_PATH_REMOVE (slid:%d dlid:%d) for %s.\n", + ntoh16( p_ioc_path->path.slid ), + ntoh16( p_ioc_path->path.dlid ), + p_adapter->ioc_info.profile.id_string)); + + p_path_record = __path_record_remove( p_adapter, &p_ioc_path->path ); + + if ( p_path_record != NULL ) + { + int fail_over = 0; + + if( p_adapter->p_currentPath->p_path_rec != &p_path_record->path_rec ) + { + VNIC_TRACE( VNIC_DBG_INFO, + ("IOC[%d] Standby Path lost\n", p_adapter->ioc_num )); + + if( p_adapter->p_currentPath != &p_adapter->primaryPath ) + { + _adapter_netpath_free( p_adapter, &p_adapter->primaryPath ); + } + else + { + _adapter_netpath_free( p_adapter, &p_adapter->secondaryPath ); + } + + cl_free( p_path_record ); + break; + } + + VNIC_TRACE( VNIC_DBG_ERROR, + ("IOC[%d]Current Path lost\n", p_adapter->ioc_num )); + + p_netpath = p_adapter->p_currentPath; + netpath_stopXmit( p_netpath ); + viport_timerStop( p_netpath->pViport ); + + if( !p_adapter->params.SecondaryPath ) + { + vnic_path_record_t* p_record; + + netpath_linkDown( p_netpath ); + _adapter_netpath_free(p_adapter, p_netpath ); + + p_record = __path_record_get( p_adapter ); + if( p_record ) + { + ib_status = adapter_netpath_update_and_connect( p_adapter, p_record ); + } + + cl_free( p_path_record ); + break; + } + + if( p_netpath == &p_adapter->primaryPath ) + { + if( netpath_is_connected( &p_adapter->secondaryPath ) ) + { + netpath_stopXmit( &p_adapter->secondaryPath ); + p_adapter->p_currentPath = &p_adapter->secondaryPath; + fail_over = 1; + VNIC_TRACE( VNIC_DBG_ERROR, + ("IOC[%d]Switch to Secondary Path\n", p_adapter->ioc_num )); + } + } + else + { + if( netpath_is_connected( &p_adapter->primaryPath ) ) + { + netpath_stopXmit( &p_adapter->primaryPath ); + p_adapter->p_currentPath = &p_adapter->primaryPath; + fail_over = 1; + VNIC_TRACE( VNIC_DBG_ERROR, + ("IOC[%d]Switch to Primary Path\n", p_adapter->ioc_num )); + } + } + if( fail_over ) + { + viport_setLink( p_adapter->p_currentPath->pViport, + INIC_FLAG_ENABLE_NIC| INIC_FLAG_SET_MTU, + (uint16_t)p_adapter->params.MinMtu, FALSE ); + } + + _adapter_netpath_free(p_adapter, p_netpath ); + cl_free( p_path_record ); + } + + break; + + default: + VNIC_TRACE( VNIC_DBG_PNP, + (" Received unhandled PnP event %#x\n", p_pnp_rec->pnp_event ) ); + break; + } + + VNIC_EXIT( VNIC_DBG_PNP ); + return ib_status; +} + +NDIS_STATUS +vnic_get_adapter_interface( + IN NDIS_HANDLE h_handle, + IN vnic_adapter_t *p_adapter) +{ + NTSTATUS status; + ib_al_ifc_data_t data; + IO_STACK_LOCATION io_stack; + + VNIC_ENTER( VNIC_DBG_ADAPTER ); + + NdisMGetDeviceProperty( h_handle, &p_adapter->p_pdo, NULL, NULL, NULL, NULL ); + + data.size = sizeof(ioc_ifc_data_t); + data.type = &GUID_IOC_INTERFACE_DATA; + data.version = IOC_INTERFACE_DATA_VERSION; + data.p_data = &p_adapter->ifc_data; + + io_stack.MinorFunction = IRP_MN_QUERY_INTERFACE; + io_stack.Parameters.QueryInterface.Version = AL_INTERFACE_VERSION; + io_stack.Parameters.QueryInterface.Size = sizeof(ib_al_ifc_t); + io_stack.Parameters.QueryInterface.Interface = (INTERFACE*)&p_adapter->ifc; + io_stack.Parameters.QueryInterface.InterfaceSpecificData = &data; + io_stack.Parameters.QueryInterface.InterfaceType = &GUID_IB_AL_INTERFACE; + + status = cl_fwd_query_ifc( p_adapter->p_pdo, &io_stack ); + + if( !NT_SUCCESS( status ) ) + { + VNIC_TRACE_EXIT( VNIC_DBG_ERROR, + ("Query interface for VNIC interface returned %08x.\n", status) ); + return status; + } + /* + * Dereference the interface now so that the bus driver doesn't fail a + * query remove IRP. We will always get unloaded before the bus driver + * since we're a child device. + */ + p_adapter->ifc.wdm.InterfaceDereference( + p_adapter->ifc.wdm.Context ); + + VNIC_EXIT( VNIC_DBG_ADAPTER ); + + return NDIS_STATUS_SUCCESS; +} + + +static void +__adapter_cleanup( + IN vnic_adapter_t *p_adapter ) +{ + __pending_queue_cleanup( p_adapter ); + + __path_records_cleanup( p_adapter ); + + _adapter_netpath_free( p_adapter, &p_adapter->primaryPath ); + _adapter_netpath_free( p_adapter, &p_adapter->secondaryPath ); + + VNIC_EXIT( VNIC_DBG_ADAPTER ); +} + +void +__vnic_pnp_dereg_cb( + IN void* context ) +{ + vnic_adapter_t* p_adapter; + ib_api_status_t ib_status; + ib_pnp_req_t pnp_req; + + NDIS_STATUS ndis_status = NDIS_STATUS_SUCCESS; + + VNIC_ENTER( VNIC_DBG_INIT ); + + p_adapter = (vnic_adapter_t*)context; + + CL_ASSERT( !p_adapter->h_pnp ); + + /* Destroy port instances if still exist. */ + __adapter_cleanup( p_adapter ); + + if( p_adapter->pnp_state != IB_PNP_IOC_REMOVE ) + { + p_adapter->pnp_state = IB_PNP_IOC_ADD; + /* Register for IOC events */ + pnp_req.pfn_pnp_cb = __vnic_pnp_cb; + pnp_req.pnp_class = IB_PNP_IOC | IB_PNP_FLAG_REG_SYNC; + pnp_req.pnp_context = (const void *)p_adapter; + + ib_status = p_adapter->ifc.reg_pnp( p_adapter->h_al, &pnp_req, &p_adapter->h_pnp ); + if( ib_status != IB_SUCCESS ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + ("pnp_reg returned %s\n", + p_adapter->ifc.get_err_str( ib_status )) ); + ndis_status = NDIS_STATUS_HARD_ERRORS; + } + } + else + { + ndis_status = NDIS_STATUS_HARD_ERRORS; + } + + if( p_adapter->reset ) + { + p_adapter->reset = FALSE; + NdisMResetComplete( + p_adapter->h_handle, ndis_status, TRUE ); + } + + VNIC_EXIT( VNIC_DBG_INIT ); +} + + +ib_api_status_t +adapter_reset( + IN vnic_adapter_t* const p_adapter ) +{ + + ib_api_status_t status; + ib_pnp_handle_t h_pnp; + + VNIC_ENTER( VNIC_DBG_INIT ); + + if( p_adapter->reset ) + return IB_INVALID_STATE; + + p_adapter->reset = TRUE; + p_adapter->hung = 0; + +#if ( LBFO_ENABLED ) + __adapter_remove_from_failover_list( p_adapter ); + +#endif // LBFO_ENABLED + + if( p_adapter->h_pnp ) + { + h_pnp = p_adapter->h_pnp; + p_adapter->h_pnp = NULL; + status = p_adapter->ifc.dereg_pnp( h_pnp, __vnic_pnp_dereg_cb ); + if( status == IB_SUCCESS ) + status = IB_NOT_DONE; + } + else + { + status = IB_NOT_FOUND; + } + + VNIC_EXIT( VNIC_DBG_INIT ); + return status; +} + +static +NDIS_STATUS +_adapter_set_sg_size( + IN NDIS_HANDLE h_handle, + IN ULONG mtu_size ) +{ + NDIS_STATUS status; + ULONG buf_size; + + VNIC_ENTER( VNIC_DBG_INIT ); + + buf_size = mtu_size + ETH_VLAN_HLEN; + + status = NdisMInitializeScatterGatherDma( h_handle, TRUE, buf_size ); + + if ( status != NDIS_STATUS_SUCCESS ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + ("Init ScatterGatherDma failed status %#x\n", status ) ); + } + + VNIC_EXIT( VNIC_DBG_INIT ); + return status; +} + +static ib_api_status_t +_adapter_close_ca( + IN vnic_adapter_t* const p_adapter ) +{ + ib_api_status_t ib_status = IB_SUCCESS; + ib_ca_handle_t h_ca; + + VNIC_ENTER( VNIC_DBG_INIT ); + + if( !p_adapter ) + return ib_status; + + VNIC_TRACE(VNIC_DBG_INIT, + ("IOC[%d] Close CA\n", p_adapter->ioc_num )); + + if( p_adapter->ca.region.h_mr ) + { + ib_status = p_adapter->ifc.dereg_mr( p_adapter->ca.region.h_mr ); + if( ib_status != IB_SUCCESS ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + ("Failed to dereg MR\n")); + } + p_adapter->ca.region.h_mr = NULL; + } + + if( p_adapter->ca.hPd ) + { + ib_status = p_adapter->ifc.dealloc_pd( p_adapter->ca.hPd, NULL ); + if( ib_status != IB_SUCCESS ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + ("Failed to dealloc PD\n")); + } + p_adapter->ca.hPd = NULL; + } + + if( ( h_ca = InterlockedExchangePointer( (void *)&p_adapter->h_ca, NULL ) ) != NULL ) + { + + ib_status = p_adapter->ifc.close_ca( h_ca, NULL ); + if( ib_status != IB_SUCCESS ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + ("Failed to close CA\n")); + } + } + + VNIC_EXIT( VNIC_DBG_INIT ); + return ib_status; +} + +static +ib_api_status_t +_adapter_netpath_update( + IN vnic_adapter_t* const p_adapter, + IN viport_t* const p_viport, + IN vnic_path_record_t* p_path ) +{ + + Netpath_t *p_netpath_init; + + VNIC_ENTER( VNIC_DBG_PNP ); + + NdisAcquireSpinLock( &p_adapter->lock ); + /* set primary first */ + if( !netpath_is_valid( p_adapter->p_currentPath ) ) + { + p_netpath_init = &p_adapter->primaryPath; + p_adapter->p_currentPath = p_netpath_init; + } + + else + { + if( p_adapter->p_currentPath != &p_adapter->primaryPath ) + { + p_netpath_init = &p_adapter->primaryPath; + } + else + { + p_netpath_init = &p_adapter->secondaryPath; + } + } + + /* shouldn't really happened ?? */ + if( netpath_is_connected( p_netpath_init ) ) + { + VNIC_TRACE( VNIC_DBG_WARN, + ("No available Netpath found for update\n")); + + NdisReleaseSpinLock( &p_adapter->lock ); + return IB_NO_MATCH; + } + + p_netpath_init->p_path_rec = &p_path->path_rec; + + /* netpath initialization */ + + p_netpath_init->p_adapter = p_adapter; + p_netpath_init->pViport = p_viport; + p_netpath_init->carrier = FALSE; + + /* viport initialization */ + p_viport->p_netpath = p_netpath_init; + + p_viport->portGuid = p_netpath_init->p_path_rec->sgid.unicast.interface_id; + p_viport->port_config.dataConfig.ibConfig.pathInfo = *p_netpath_init->p_path_rec; + p_viport->port_config.controlConfig.ibConfig.pathInfo = *p_netpath_init->p_path_rec; + + /* set our instance id per IOC */ + p_viport->port_config.controlConfig.ibConfig.connData.inicInstance = (uint8_t)p_netpath_init->instance; + p_viport->port_config.dataConfig.ibConfig.connData.inicInstance = (uint8_t)p_netpath_init->instance; + /* save for later use */ + p_viport->port_config.controlConfig.inicInstance = (uint8_t)p_netpath_init->instance; + + p_viport->iocGuid = p_adapter->ioc_info.profile.ioc_guid; + p_viport->port_config.controlConfig.ibConfig.sid = p_adapter->svc_entries[0].id; + p_viport->port_config.dataConfig.ibConfig.sid = p_adapter->svc_entries[1].id; + + VNIC_TRACE( VNIC_DBG_INFO, + ("IOC[%d] instance %d [%s] is using SLID=%d DLID=%d Target:%s\n", + p_viport->ioc_num, + p_netpath_init->instance, + netpath_to_string( p_netpath_init ), + cl_ntoh16( p_path->path_rec.slid ), + cl_ntoh16( p_path->path_rec.dlid), + p_adapter->ioc_info.profile.id_string) ); + + NdisReleaseSpinLock( &p_adapter->lock ); + + VNIC_EXIT( VNIC_DBG_PNP ); + return IB_SUCCESS; +} + +static +ib_api_status_t +adapter_netpath_update_and_connect( + IN vnic_adapter_t* const p_adapter, + IN vnic_path_record_t* p_path ) +{ + ib_api_status_t ib_status; + viport_t* p_viport; + + ib_status = adapter_viport_allocate( p_adapter, &p_viport ); + if( ib_status != IB_SUCCESS ) + { + VNIC_TRACE ( VNIC_DBG_ERROR, + ("IOC[%] Viport allocate Failed status %s\n", + p_adapter->ioc_num, p_adapter->ifc.get_err_str( ib_status )) ); + goto err; + } + + ib_status = _adapter_open_ca( p_adapter ); + if( ib_status != IB_SUCCESS ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + ("IOC[%d]Open CA failed %s\n", p_adapter->ioc_num, + p_adapter->ifc.get_err_str( ib_status )) ); + goto err; + } + + ib_status = _adapter_netpath_update( p_adapter, p_viport, p_path ); + if( ib_status != IB_SUCCESS ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + ("IOC[%d]Update New Path failed %s\n", p_adapter->ioc_num, + p_adapter->ifc.get_err_str( ib_status )) ); + goto err; + } + + ib_status = viport_control_connect( p_viport ); + if( ib_status != IB_SUCCESS ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + ("IOC[%d]Control QP connect return %s\n", p_adapter->ioc_num, + p_adapter->ifc.get_err_str( ib_status )) ); + goto err; + } + + /* should call this only once */ + if( p_adapter->state == INIC_UNINITIALIZED ) + { + if( _adapter_set_sg_size( p_adapter->h_handle, + p_adapter->params.MinMtu ) != NDIS_STATUS_SUCCESS ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + ("IOC[%d]ScatterGather Init using MTU size %d failed\n", p_adapter->ioc_num, + p_adapter->params.MinMtu ) ); + goto err; + } + } + + ib_status = viport_data_connect( p_viport ); + if( ib_status != IB_SUCCESS ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + ("IOC[%d]Data QP connect return %s\n", p_adapter->ioc_num, + p_adapter->ifc.get_err_str( ib_status )) ); + goto err; + } + + VNIC_TRACE( VNIC_DBG_INFO, + ("IOC[%d] instance %d %s is CONNECTED\n", + p_viport->ioc_num, + p_viport->p_netpath->instance, + netpath_to_string( p_viport->p_netpath ) )); + + if( p_viport->state == VIPORT_CONNECTED ) + { + p_adapter->num_paths++; + } + + if( p_adapter->num_paths > 1 && + p_viport->p_netpath != p_adapter->p_currentPath ) + { + if ( !netpath_setUnicast( p_viport->p_netpath, + p_adapter->p_currentPath->pViport->hwMacAddress ) ) + { + ib_status = IB_ERROR; + goto err; + } + } + + return ib_status; + +err: + VNIC_TRACE( VNIC_DBG_ERROR, + ("IOC[%d] allocate return %#x (%s)\n", p_adapter->ioc_num, + ib_status, p_adapter->ifc.get_err_str( ib_status )) ); + + if( p_viport != NULL && + p_viport->p_netpath != NULL ) + { + netpath_free( p_viport->p_netpath ); + } + return ib_status; +} + +#if ( LBFO_ENABLED ) + +static void +__adapter_add_to_failover_list( + IN vnic_adapter_t* const p_adapter, + IN lbfo_state_t state ) +{ + + CL_ASSERT( p_adapter ); + CL_ASSERT( state == _ADAPTER_PRIMARY || state == _ADAPTER_SECONDARY ); + + p_adapter->failover.fo_state = state; + + if( state == _ADAPTER_PRIMARY ) + { + p_adapter->failover.primary_handle = p_adapter; + cl_qlist_insert_tail( &g_vnic.primary_list, &p_adapter->list_item ); + } + else + { + cl_qlist_insert_tail( &g_vnic.secondary_list, &p_adapter->list_item ); + } +} + +static void +__adapter_remove_from_failover_list( + IN vnic_adapter_t* const p_adapter ) +{ + lbfo_state_t lbfo_state; + vnic_adapter_t *p_adapter_to_promote; + uint32_t bundle_id; + + CL_ASSERT( p_adapter ); + + lbfo_state = p_adapter->failover.fo_state; + p_adapter->failover.fo_state = _ADAPTER_NOT_BUNDLED; + bundle_id = p_adapter->failover.bundle_id; + + if( lbfo_state == _ADAPTER_PRIMARY ) + { + cl_qlist_remove_item( &g_vnic.primary_list, &p_adapter->list_item ); + + /* search for secondary adapter with same id && (id != 0 ) */ + if( bundle_id != 0 ) + { + p_adapter_to_promote = + __adapter_find_on_failover_list( _ADAPTER_SECONDARY, bundle_id ); + + if( p_adapter_to_promote && + p_adapter_to_promote->pnp_state != IB_PNP_IOC_REMOVE && + p_adapter_to_promote->state == INIC_REGISTERED && + p_adapter_to_promote->reset == FALSE ) + { + /* a small recursion */ + __adapter_set_failover_primary( p_adapter_to_promote, TRUE ); + } + } + } + else if( lbfo_state == _ADAPTER_SECONDARY ) + { + cl_qlist_remove_item( &g_vnic.secondary_list, &p_adapter->list_item ); + VNIC_TRACE( VNIC_DBG_INFO, + ("IOC[%d] LBFO bundle %d Secondary Adapter Removed\n", + p_adapter->ioc_num, p_adapter->failover.bundle_id )); + } + else if( lbfo_state == _ADAPTER_NOT_BUNDLED ) + { + VNIC_TRACE( VNIC_DBG_INFO, + ("IOC[%d] Adapter not bundled\n", p_adapter->ioc_num )); + } + + return; +} + + +static vnic_adapter_t* +__adapter_find_on_failover_list( + IN lbfo_state_t list_flag, + IN uint32_t bundle_id ) +{ + vnic_adapter_t *p_adapter = NULL; + cl_list_item_t *p_item; + cl_qlist_t *p_qlist = ( list_flag == _ADAPTER_PRIMARY ) ? + &g_vnic.primary_list : &g_vnic.secondary_list; + + p_item = cl_qlist_head( p_qlist ); + + while( p_item != cl_qlist_end( p_qlist ) ) + { + p_adapter = PARENT_STRUCT( p_item, vnic_adapter_t, list_item ); + + if( p_adapter && + p_adapter->failover.bundle_id == bundle_id ) + { + return p_adapter; + } + + p_item = cl_qlist_next( p_item ); + } + return NULL; +} + +static NDIS_STATUS +__adapter_set_failover_primary( + IN vnic_adapter_t* const p_adapter, + IN BOOLEAN promote_secondary ) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + + CL_ASSERT( p_adapter ); + + if( promote_secondary ) + { + if( p_adapter->failover.fo_state != _ADAPTER_SECONDARY ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + ("LBFO Can't promote NON_SECONDARY\n")); + return NDIS_STATUS_NOT_ACCEPTED; + } + __adapter_remove_from_failover_list( p_adapter ); + status = NdisMPromoteMiniport( p_adapter->h_handle ); + } + + if( status == NDIS_STATUS_SUCCESS ) + { + p_adapter->failover.p_adapter = p_adapter; + p_adapter->failover.fo_state = _ADAPTER_PRIMARY; + p_adapter->failover.primary_handle = p_adapter->h_handle; + __adapter_add_to_failover_list( p_adapter, _ADAPTER_PRIMARY ); + + VNIC_TRACE( VNIC_DBG_INFO, + ("IOC[%d] Set LBFO bundle %d Primary Adapter\n", + p_adapter->ioc_num, p_adapter->failover.bundle_id )); + } + else + VNIC_TRACE( VNIC_DBG_ERROR, + ("LBFO Set to Primary Failed\n")); + + return status; +} + +static NDIS_STATUS +__adapter_set_failover_secondary( + IN vnic_adapter_t* const p_adapter, + IN NDIS_HANDLE primary_handle ) +{ + NDIS_STATUS status; + + CL_ASSERT( p_adapter ); + + status = NdisMSetMiniportSecondary( p_adapter->h_handle, primary_handle ); + + if ( status == NDIS_STATUS_SUCCESS ) + { + p_adapter->failover.fo_state = _ADAPTER_SECONDARY; + p_adapter->failover.primary_handle = primary_handle; + __adapter_add_to_failover_list( p_adapter, _ADAPTER_SECONDARY ); + + VNIC_TRACE( VNIC_DBG_INFO, + ("IOC[%d] Set LBFO bundle %d Secondary Adapter\n", + p_adapter->ioc_num, p_adapter->failover.bundle_id )); + } + + return status; +} + +#endif //LBFO_ENABLED diff --git a/branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_adapter.h b/branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_adapter.h new file mode 100644 index 00000000..cbed2237 --- /dev/null +++ b/branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_adapter.h @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2007 QLogic Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#if !defined _VNIC_ADAPTER_H_ +#define _VNIC_ADAPTER_H_ + +#include +#include +#include +#include +#include "vnic_ib.h" +#include "vnic_controlpkt.h" +#include "vnic_config.h" +#include "vnic_control.h" +#include "vnic_data.h" +#include "vnic_viport.h" +#include + +typedef struct _pending_oid +{ + NDIS_OID oid; + PVOID p_buf; + ULONG buf_len; + PULONG p_bytes_used; + PULONG p_bytes_needed; + +} pending_oid_t; + +typedef struct _ipv4_address_item +{ + union _net_address_item_address + { + ULONG as_ulong; + UCHAR as_bytes[4]; + } address; + +} ipv4_address_item_t; + +typedef struct _lbfo_failover { + struct _vnic_adapter *p_adapter; + NDIS_HANDLE primary_handle; + uint32_t bundle_id; + lbfo_state_t fo_state; +} lbfo_failover_t; + +typedef struct _vnic_params { + uint32_t MaxAddressEntries; + uint32_t MinAddressEntries; + uint32_t MinMtu; + uint32_t MaxMtu; + uint32_t HostRecvPoolEntries; + uint32_t MinHostPoolSz; + uint32_t MinEiocPoolSz; + uint32_t MaxEiocPoolSz; + uint32_t MinHostKickTimeout; + uint32_t MaxHostKickTimeout; + uint32_t MinHostKickEntries; + uint32_t MaxHostKickEntries; + uint32_t MinHostKickBytes; + uint32_t MaxHostKickBytes; + uint32_t MinHostUpdateSz; + uint32_t MaxHostUpdateSz; + uint32_t MinEiocUpdateSz; + uint32_t MaxEiocUpdateSz; + uint32_t NotifyBundleSz; + uint32_t ViportStatsInterval; + uint32_t ViportHbInterval; + uint32_t ViportHbTimeout; + uint32_t ControlRspTimeout; + uint32_t ControlReqRetryCount; + uint32_t RetryCount; + uint32_t MinRnrTimer; + uint32_t MaxViportsPerNetpath; + uint32_t DefaultViportsPerNetpath; + uint32_t DefaultPkey; + uint32_t DefaultNoPathTimeout; + uint32_t DefaultPrimaryConnectTimeout; + uint32_t DefaultPrimaryReconnectTimeout; + uint32_t DefaultPrimarySwitchTimeout; + uint32_t DefaultPreferPrimary; + uint32_t UseRxCsum; + uint32_t UseTxCsum; + uint32_t VlanInfo; + uint32_t SecondaryPath; + uint32_t bundle_id; + mac_addr_t conf_mac; +} vnic_params_t; + + +typedef struct _vnic_adapter { + cl_list_item_t list_item; + NDIS_HANDLE h_handle; + DEVICE_OBJECT *p_pdo; + NDIS_SPIN_LOCK lock; + ib_al_ifc_t ifc; + ioc_ifc_data_t ifc_data; + ib_ioc_info_t ioc_info; + LIST_ENTRY send_pending_list; + LIST_ENTRY cancel_send_list; + NDIS_SPIN_LOCK pending_list_lock; + NDIS_SPIN_LOCK cancel_list_lock; + NDIS_SPIN_LOCK path_records_lock; + cl_qlist_t path_records_list; + ib_al_handle_t h_al; + ib_ca_handle_t h_ca; + ib_pnp_handle_t h_pnp; + ib_pnp_event_t pnp_state; + IbCa_t ca; + InicState_t state; + struct Netpath primaryPath; + struct Netpath secondaryPath; + struct Netpath *p_currentPath; + vnic_params_t params; + uint32_t num_paths; + int macSet; + int mc_count; + mac_addr_t mcast_array[MAX_MCAST]; + LONG xmitStarted; + LONG carrier; + uint32_t ioc_num; + uint32_t link_speed; + uint32_t packet_filter; + uint32_t vlan_info; + uint32_t hung; + BOOLEAN reset; + BOOLEAN pending_set; + BOOLEAN pending_query; + pending_oid_t query_oid; + pending_oid_t set_oid; + ib_svc_entry_t svc_entries[2]; + +#if ( LBFO_ENABLED ) + lbfo_failover_t failover; +#endif +#ifdef VNIC_STATISTIC + struct { + uint64_t startTime; + uint64_t connTime; + uint64_t disconnRef; /* Intermediate time */ + uint64_t disconnTime; + uint32_t disconnNum; + uint64_t xmitTime; + uint32_t xmitNum; + uint32_t xmitFail; + uint64_t recvTime; + uint32_t recvNum; + uint64_t xmitRef; /* Intermediate time */ + uint64_t xmitOffTime; + uint32_t xmitOffNum; + uint64_t carrierRef; /* Intermediate time */ + uint64_t carrierOffTime; + uint32_t carrierOffNum; + } statistics; +#endif /* VNIC_STATISTIC */ + cl_list_item_t list_adapter; +} vnic_adapter_t; + +ib_api_status_t +vnic_create_adapter( + IN NDIS_HANDLE h_handle, + IN NDIS_HANDLE wrapper_config_context, + OUT vnic_adapter_t** const pp_adapter); + +void +vnic_destroy_adapter( + IN vnic_adapter_t* p_adapter); + +ib_api_status_t +vnic_construct_adapter( + IN vnic_adapter_t *p_adapter); + +NDIS_STATUS +adapter_set_mcast( + IN vnic_adapter_t* const p_adapter, + IN mac_addr_t* const p_mac_array, + IN const uint8_t mc_count ); + +ib_api_status_t +adapter_viport_allocate( + IN vnic_adapter_t* const p_adapter, + IN OUT viport_t** const pp_viport ); + +void +vnic_resume_set_oids( + IN vnic_adapter_t* const p_adapter ); + +void +vnic_resume_oids( + IN vnic_adapter_t* const p_adapter ); + +ib_api_status_t +__vnic_pnp_cb( + IN ib_pnp_rec_t *p_pnp_rec ); + +ib_api_status_t +ibregion_physInit( + IN struct _vnic_adapter* p_adapter, + OUT IbRegion_t *pRegion, + IN ib_pd_handle_t hPd, + IN uint64_t *p_vaddr, + IN uint64_t len ); + +void +__vnic_pnp_dereg_cb( + IN void* context ); + +ib_api_status_t +adapter_reset( + IN vnic_adapter_t* const p_adapter ); +void +__pending_queue_cleanup( + IN vnic_adapter_t *p_adapter ); + +#endif /* !defined _VNIC_ADAPTER_H_ */ diff --git a/branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_config.h b/branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_config.h new file mode 100644 index 00000000..7d49064c --- /dev/null +++ b/branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_config.h @@ -0,0 +1,302 @@ +/* + * Copyright (c) 2007 QLogic Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ +#ifndef _VNIC_CONFIG_H_ +#define _VNIC_CONFIG_H_ + +#include "vnic_util.h" +/* These are hard, compile time limits. + * Lower runtime overrides may be in effect + */ +#define INIC_CLASS_SUBCLASS 0x2000066A +#define INIC_PROTOCOL 0 +#define INIC_PROT_VERSION 1 + +#define INIC_MAJORVERSION 1 +#define INIC_MINORVERSION 1 + +#define LIMIT_OUTSTANDING_SENDS 0 + +#define MAX_ADDRESS_ENTRIES 64 /* max entries to negotiate with remote */ +#define MIN_ADDRESS_ENTRIES 16 /* min entries remote can return to us that we agree with */ +#define MAX_ADDR_ARRAY 32 /* address array we can handle. for now */ +#define MIN_MTU 1500 /* Minimum Negotiated payload size */ +#define MAX_MTU 9500 /* max Jumbo frame payload size */ +#define ETH_VLAN_HLEN 18 /* ethernet header with VLAN tag */ + +#define HOST_RECV_POOL_ENTRIES 512 /* TBD: Abritrary */ +#define MIN_HOST_POOL_SZ 256 /* TBD: Abritrary */ +#define MIN_EIOC_POOL_SZ 256 /* TBD: Abritrary */ +#define MAX_EIOC_POOL_SZ 512 /* TBD: Abritrary */ + +#define MIN_HOST_KICK_TIMEOUT 100 /* TBD: Arbitrary */ +#define MAX_HOST_KICK_TIMEOUT 200 /* In uSec */ + +#define MIN_HOST_KICK_ENTRIES 1 /* TBD: Arbitrary */ +#define MAX_HOST_KICK_ENTRIES 128 /* TBD: Arbitrary */ + +#define MIN_HOST_KICK_BYTES 0 +#define MAX_HOST_KICK_BYTES 5000 + +#define MIN_HOST_UPDATE_SZ 8 /* TBD: Arbitrary */ +#define MAX_HOST_UPDATE_SZ 32 /* TBD: Arbitrary */ +#define MIN_EIOC_UPDATE_SZ 8 /* TBD: Arbitrary */ +#define MAX_EIOC_UPDATE_SZ 32 /* TBD: Arbitrary */ + +#define NOTIFY_BUNDLE_SZ 32 + +#define MAX_PARAM_VALUE 0x40000000 + +#define DEFAULT_VIPORTS_PER_NETPATH 1 +#define MAX_VIPORTS_PER_NETPATH 1 + +#define INIC_USE_RX_CSUM TRUE +#define INIC_USE_TX_CSUM TRUE +#define DEFAULT_NO_PATH_TIMEOUT 10000 /* TBD: Arbitrary */ +#define DEFAULT_PRI_CON_TIMEOUT 10000 /* TBD: Arbitrary */ +#define DEFAULT_PRI_RECON_TIMEOUT 10000 /* TBD: Arbitrary */ +#define DEFAULT_PRI_SWITCH_TIMEOUT 10000 /* TBD: Arbitrary */ +#define DEFAULT_PREFER_PRIMARY TRUE + +/* timeouts: !! all data defined in milliseconds, + some later will be converted to microseconds */ +#define VIPORT_STATS_INTERVAL 5000 /* 5 sec */ +#define VIPORT_HEARTBEAT_INTERVAL 2000 /* 2 seconds */ +#define VIPORT_HEARTBEAT_TIMEOUT 60000 /* 60 sec */ +#define CONTROL_RSP_TIMEOUT 2000 /* 2 sec */ + +#define _100NS_IN_1MS (10000) +inline uint64_t +get_time_stamp_ms( void ) +{ + return( (KeQueryInterruptTime() / _100NS_IN_1MS ) ); +} + +/* InfiniBand Connection Parameters */ +#define CONTROL_REQ_RETRY_COUNT 4 +#define RETRY_COUNT 3 +#define MIN_RNR_TIMER 22 /* 20 ms */ +#define DEFAULT_PKEY 0 /* Pkey table index */ + +/* phys memory size to register with HCA*/ +#define MEM_REG_SIZE 0xFFFFFFFFFFFFFFFF + +/* link speed in 100 bits/sec units */ +#define LINK_SPEED_1MBIT_x100BPS 10000 +#define LINK_SPEED_1GBIT_x100BPS 10000000 +#define LINK_SPEED_10GBIT_x100BPS 100000000 + /* if VEx does not report it's link speed, so set it 1Gb/s so far */ +#define DEFAULT_LINK_SPEED_x100BPS LINK_SPEED_1GBIT_x100BPS + +#define DEFAULT_PARAM(x,y) if(x == MAXU32) { \ + x = y; } +#define POWER_OF_2(x) if (!IsPowerOf2(x)) { \ + VNIC_TRACE( VNIC_DBG_WARN, (" %s (%d) must be a power of 2\n",#x,x) ); \ + x = SetMinPowerOf2(x); \ + } +#define LESS_THAN(lo, hi) if (lo >= hi) { \ + VNIC_TRACE( VNIC_DBG_ERROR, (" %s (%d) must be less than %s (%d)\n",#lo,lo,#hi,hi) ); \ + lo = hi >> 1; \ + } +#define LESS_THAN_OR_EQUAL(lo, hi) if (lo > hi) { \ + VNIC_TRACE( VNIC_DBG_WARN, (" %s (%d) cannot be greater than %s (%d)\n",#lo,lo,#hi,hi) ); \ + lo = hi; \ + } +#define RANGE_CHECK(x, min, max) if ((x < min) || (x > max)) { \ + VNIC_TRACE( VNIC_DBG_WARN, (" %s (%d) must be between %d and %d\n",#x,x,min,max) ); \ + if (x < min) \ + x = min; \ + else \ + x = max; \ + } +#define ZERO_RANGE_CHECK(x, min, max) if (x > max) { \ + VNIC_TRACE( VNIC_DBG_WARN, (" %s (%d) must be between %d and %d\n",#x,x,min,max) ); \ + x = max; \ + } + +#define BOOLEAN_RANGE(x) ZERO_RANGE_CHECK(x, 0, 1) +#define U32_ZERO_RANGE(x) ZERO_RANGE_CHECK(x, 0, 0x7FFFFFFF) +#define U32_RANGE(x) RANGE_CHECK(x, 1, 0x7FFFFFFF) +#define U16_ZERO_RANGE(x) ZERO_RANGE_CHECK(x, 0, 0xFFFF) +#define U16_RANGE(x) RANGE_CHECK(x, 1, 0xFFFF) +#define U8_ZERO_RANGE(x) ZERO_RANGE_CHECK(x, 0, 0xFF) +#define U8_RANGE(x) RANGE_CHECK(x, 1, 0xFF) + +enum { + INDEX_RESERVED, + INDEX_MIN_HOST_POOL_SZ, + INDEX_HOST_RECV_POOL_ENTRIES, + INDEX_MIN_EIOC_POOL_SZ, + INDEX_MAX_EIOC_POOL_SZ, + INDEX_MIN_HOST_KICK_TIMEOUT, + INDEX_MAX_HOST_KICK_TIMEOUT, + INDEX_MIN_HOST_KICK_ENTRIES, + INDEX_MAX_HOST_KICK_ENTRIES, + INDEX_MIN_HOST_KICK_BYTES, + INDEX_MAX_HOST_KICK_BYTES, + INDEX_MIN_HOST_UPDATE_SZ, + INDEX_MAX_HOST_UPDATE_SZ, + INDEX_MIN_EIOC_UPDATE_SZ, + INDEX_MAX_EIOC_UPDATE_SZ, + INDEX_HEARTBEAT_TIMEOUT, + INDEX_LAST // keep it the last entry +}; + +typedef struct _g_registry_params { + PWSTR name; + uint32_t value; +}g_registry_params_t; + +#define ENTRY_INIT_VALUE MAXULONG +#define VNIC_REGISTRY_TBL_SIZE INDEX_LAST + +typedef struct { + uint64_t ioc_guid; + uint64_t portGuid; + uint64_t port; + uint64_t hca; + uint64_t instance; + char ioc_string[65]; + char ioc_guid_set; + char ioc_string_set; +} PathParam_t; + +typedef struct _vnic_globals { + NDIS_HANDLE ndis_handle; // ndis wrapper handle + NDIS_SPIN_LOCK lock; +#if ( LBFO_ENABLED ) + cl_qlist_t primary_list; + cl_qlist_t secondary_list; +#endif + uint32_t shutdown; + uint8_t host_name[IB_NODE_DESCRIPTION_SIZE]; + g_registry_params_t *p_params; + cl_qlist_t adapter_list; +} vnic_globals_t; + +typedef struct IbConfig { + ib_path_rec_t pathInfo; + uint64_t sid; + Inic_ConnectionData_t connData; + uint32_t retryCount; + uint32_t rnrRetryCount; + uint8_t minRnrTimer; + uint32_t numSends; + uint32_t numRecvs; + uint32_t recvScatter; /* 1 */ + uint32_t sendGather; /* 1 or 2 */ + uint32_t overrides; +} IbConfig_t; + +typedef struct ControlConfig { + IbConfig_t ibConfig; + uint32_t numRecvs; + uint8_t inicInstance; + uint16_t maxAddressEntries; + uint16_t minAddressEntries; + uint32_t rspTimeout; + uint8_t reqRetryCount; + uint32_t overrides; +} ControlConfig_t; + +typedef struct DataConfig { + IbConfig_t ibConfig; + uint64_t pathId; + uint32_t numRecvs; + uint32_t hostRecvPoolEntries; + Inic_RecvPoolConfig_t hostMin; + Inic_RecvPoolConfig_t hostMax; + Inic_RecvPoolConfig_t eiocMin; + Inic_RecvPoolConfig_t eiocMax; + uint32_t notifyBundle; + uint32_t overrides; +} DataConfig_t; + +typedef struct ViportConfig { + struct _viport *pViport; + ControlConfig_t controlConfig; + DataConfig_t dataConfig; + uint32_t hca; + uint32_t port; + uint32_t statsInterval; + uint32_t hbInterval; /* heartbeat interval */ + uint32_t hbTimeout; /* heartbeat timeout */ + uint64_t portGuid; + uint64_t guid; + size_t instance; + char ioc_string[65]; + +#define HB_INTERVAL_OVERRIDE 0x1 +#define GUID_OVERRIDE 0x2 +#define STRING_OVERRIDE 0x4 +#define HCA_OVERRIDE 0x8 +#define PORT_OVERRIDE 0x10 +#define PORTGUID_OVERRIDE 0x20 + uint32_t overrides; +} ViportConfig_t; + +/* + * primaryConnectTimeout - If the secondary connects first, how long do we + * give the primary? + * primaryReconnectTimeout - Same as above, but used when recovering when + * both paths fail + * primarySwitchTimeout - How long do we wait before switching to the + * primary when it comes back? + */ +#define IFNAMSIZ 65 +typedef struct InicConfig { + //struct Inic *pInic; + char name[IFNAMSIZ]; + uint32_t noPathTimeout; + uint32_t primaryConnectTimeout; + uint32_t primaryReconnectTimeout; + uint32_t primarySwitchTimeout; + int preferPrimary; + BOOLEAN useRxCsum; + BOOLEAN useTxCsum; +#define USE_RX_CSUM_OVERRIDE 0x1 +#define USE_TX_CSUM_OVERRIDE 0x2 + uint32_t overrides; +} InicConfig_t; + +typedef enum { + INIC_UNINITIALIZED, + INIC_DEREGISTERING, + INIC_REGISTERED, +} InicState_t; + +typedef enum { + _ADAPTER_NOT_BUNDLED = 0, + _ADAPTER_PRIMARY, + _ADAPTER_SECONDARY +} lbfo_state_t; + +#endif /* _VNIC_CONFIG_H_ */ + diff --git a/branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_control.c b/branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_control.c new file mode 100644 index 00000000..5d7bce80 --- /dev/null +++ b/branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_control.c @@ -0,0 +1,2091 @@ +/* + * Copyright (c) 2007 QLogic Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include "vnic_adapter.h" + +static void +control_recv( Control_t *pControl, RecvIo_t *pRecvIo ); + +static void +control_recvComplete( + IN Io_t *pIo ); + +static ib_api_status_t +control_send( Control_t *pControl ); + +static void +control_sendComplete( Io_t *pIo ); +static void +control_timeout( void * context ); + +static void +control_timer( Control_t *pControl, int timeout ); + +static void +control_timerStop( Control_t *pControl ); + +static void +control_initHdr( Control_t *pControl, uint8_t cmd ); + +static RecvIo_t * +control_getRsp( Control_t *pControl ); + +static void +copyRecvPoolConfig( Inic_RecvPoolConfig_t *pSrc, + Inic_RecvPoolConfig_t *pDst ); + +static BOOLEAN +checkRecvPoolConfigValue( + IN void *pSrc, + IN void *pDst, + IN void *pMax, + IN void *pMin, + IN char *name ); + +static BOOLEAN checkRecvPoolConfig( + Inic_RecvPoolConfig_t *pSrc, + Inic_RecvPoolConfig_t *pDst, + Inic_RecvPoolConfig_t *pMax, + Inic_RecvPoolConfig_t *pMin); + +static void +__control_logControlPacket( + Inic_ControlPacket_t *pPkt ); + +void +control_construct( + IN Control_t *pControl, + IN viport_t *pViport ) +{ + VNIC_ENTER( VNIC_DBG_CTRL ); + + cl_memclr(pControl, sizeof(Control_t)); + + pControl->p_viport = pViport; + + pControl->reqOutstanding = FALSE; + pControl->seqNum = 0; + + pControl->pResponse = NULL; + pControl->pInfo = NULL; + + pControl->p_viport->addrs_query_done = TRUE; + + InitializeListHead(&pControl->failureList); + KeInitializeSpinLock(&pControl->ioLock); + + cl_timer_construct( &pControl->timer ); + + ibqp_construct( &pControl->qp, pViport ); + + VNIC_EXIT( VNIC_DBG_CTRL ); +} + + +ib_api_status_t +control_init( + IN Control_t *pControl, + IN viport_t *pViport, + IN ControlConfig_t *pConfig, + IN uint64_t guid ) +{ + ib_api_status_t ib_status; + ib_pd_handle_t hPd; + Inic_ControlPacket_t *pkt; + Io_t *pIo; + int sz; + unsigned int i; + + VNIC_ENTER( VNIC_DBG_CTRL ); + + pControl->p_conf = pConfig; + + hPd = pViport->p_adapter->ca.hPd; + + cl_timer_init( &pControl->timer, control_timeout, pControl ); + + ib_status = ibqp_init( + &pControl->qp, guid, &pConfig->ibConfig ); + if( ib_status != IB_SUCCESS ) + { + VNIC_TRACE_EXIT( VNIC_DBG_ERROR, ("ibqp_init returned %s\n", + pViport->p_adapter->ifc.get_err_str( ib_status )) ); + goto failure; + } + + sz = (sizeof(RecvIo_t) * pConfig->numRecvs ) + + (sizeof(Inic_ControlPacket_t) * (pConfig->numRecvs + 1)); + + pControl->pLocalStorage = cl_zalloc( sz ); + + if ( pControl->pLocalStorage == NULL ) + { + VNIC_TRACE_EXIT( VNIC_DBG_ERROR, + ("Failed allocating space for local storage\n" )); + + ibqp_cleanup(&pControl->qp); + ib_status = IB_INSUFFICIENT_MEMORY; + goto failure; + } + + pControl->pRecvIos = (RecvIo_t *)pControl->pLocalStorage; + + pkt = (Inic_ControlPacket_t *)(pControl->pLocalStorage + + sizeof(SendIo_t) * pConfig->numRecvs); + + sz = sizeof(Inic_ControlPacket_t) * (pConfig->numRecvs + 1); + + ib_status = ibregion_init( pViport, &pControl->region, hPd, + pkt, sz, IB_AC_LOCAL_WRITE ); + if ( ib_status != IB_SUCCESS ) + { + /* NOTE: I'm allowing recvs into the send buffer as well + * as the receive buffers. I'm doing this to combine them + * into a single region, and conserve a region. + */ + VNIC_TRACE_EXIT( VNIC_DBG_ERROR , + (" Failed setting up control space region\n" )); + + ibqp_cleanup( &pControl->qp ); + cl_free( pControl->pLocalStorage ); + pControl->pLocalStorage = NULL; + goto failure; + } + pIo = &pControl->sendIo.io; + pIo->pViport = pViport; + pIo->pRoutine = control_sendComplete; + + pIo->wrq.p_next = NULL; + pIo->wrq.wr_type = WR_SEND; + pIo->wrq.send_opt = IB_SEND_OPT_SIGNALED; + pIo->wrq.wr_id = (ULONG_PTR)pIo; + pIo->wrq.num_ds = 1; + pIo->wrq.ds_array = &pControl->sendIo.dsList; + pIo->wrq.ds_array[0].length = sizeof(Inic_ControlPacket_t); + pIo->wrq.ds_array[0].lkey = pControl->region.lkey; + pIo->wrq.ds_array[0].vaddr = (ULONG_PTR)pkt++; + + for (i = 0; i < pConfig->numRecvs; i++ ) + { + pIo = &pControl->pRecvIos[i].io; + pIo->pViport = pViport; + pIo->pRoutine = control_recvComplete; + + pIo->r_wrq.wr_id = (ULONG_PTR)pIo; + pIo->r_wrq.p_next = NULL; + pIo->r_wrq.num_ds = 1; + pIo->r_wrq.ds_array = &pControl->pRecvIos[i].dsList; + pIo->r_wrq.ds_array[0].length = sizeof(Inic_ControlPacket_t); + pIo->r_wrq.ds_array[0].vaddr = (ULONG_PTR)pkt++; + pIo->r_wrq.ds_array[0].lkey = pControl->region.lkey; + + if ( ibqp_postRecv( &pControl->qp, pIo ) != IB_SUCCESS ) + { + control_cleanup( pControl ); + ib_status = IB_ERROR; + break; + } + } + +failure: + VNIC_EXIT( VNIC_DBG_CTRL ); + return ib_status; +} + + +void +control_cleanup( + IN Control_t *pControl ) +{ + VNIC_ENTER( VNIC_DBG_CTRL ); + + control_timerStop( pControl ); + ibqp_detach( &pControl->qp ); + ibregion_cleanup( pControl->p_viport, &pControl->region ); + + if ( pControl->pLocalStorage ) + { + cl_free( pControl->pLocalStorage ); + pControl->pLocalStorage = NULL; + } + + cl_timer_destroy( &pControl->timer ); + + VNIC_EXIT( VNIC_DBG_CTRL ); + return; +} + +void +control_processAsync( + IN Control_t *pControl ) +{ + RecvIo_t *pRecvIo; + Inic_ControlPacket_t *pPkt; + LIST_ENTRY *p_list_entry; + + VNIC_ENTER( VNIC_DBG_CTRL ); + + pRecvIo = InterlockedExchangePointer( &pControl->pInfo, NULL ); + + if ( pRecvIo != NULL ) + { + VNIC_TRACE( VNIC_DBG_CTRL, + ("IOC %d: processing info packet\n", + pControl->p_viport->ioc_num ) ); + + pPkt = control_packet( pRecvIo ); + + if ( pPkt->hdr.pktCmd == CMD_REPORT_STATUS ) + { + switch( ntoh32(pPkt->cmd.reportStatus.statusNumber) ) + { + case INIC_STATUS_LINK_UP: + VNIC_TRACE( VNIC_DBG_CTRL, + ("IOC %d: STATUS LINK UP\n", pControl->p_viport->ioc_num ) ); + /* renew link speed info since it can change */ + pControl->p_viport->p_adapter->link_speed = + ntoh32( pPkt->cmd.reportStatus.statusInfo ); + viport_linkUp( pControl->p_viport ); + break; + + case INIC_STATUS_LINK_DOWN: + VNIC_TRACE( VNIC_DBG_CTRL, + ("IOC %d: STATUS LINK DOWN\n", pControl->p_viport->ioc_num ) ); + + viport_linkDown( pControl->p_viport ); + break; + case INIC_STATUS_EIOC_ERROR: + case INIC_STATUS_EIOC_SHUTDOWN: + viport_failure( pControl->p_viport ); + VNIC_TRACE( VNIC_DBG_ERROR, + ("IOC %d: STATUS EIOC ERROR\n", + pControl->p_viport->ioc_num ) ); + break; + default: + VNIC_TRACE( VNIC_DBG_CTRL | VNIC_DBG_ERROR, + ("IOC %d: Asynchronous status %#x received\n", + pControl->p_viport->ioc_num, + ntoh32(pPkt->cmd.reportStatus.statusNumber)) ); + __control_logControlPacket( pPkt ); + break; + } + } + + if ( pPkt->hdr.pktCmd != CMD_REPORT_STATUS || + pPkt->cmd.reportStatus.isFatal ) + { + viport_failure( pControl->p_viport ); + } + + control_recv( pControl, pRecvIo ); + } + + while ( !IsListEmpty( &pControl->failureList ) ) + { + + VNIC_TRACE( VNIC_DBG_CTRL, + ("IOC %d: processing error packet\n", + pControl->p_viport->ioc_num ) ); + + p_list_entry = ExInterlockedRemoveHeadList( &pControl->failureList, &pControl->ioLock ); + pRecvIo = (RecvIo_t *)p_list_entry; + pPkt = control_packet( pRecvIo ); + + VNIC_TRACE( VNIC_DBG_CTRL, + ("IOC %d: Asynchronous error received from EIOC\n", + pControl->p_viport->ioc_num ) ); + + __control_logControlPacket( pPkt ); + + if ( ( pPkt->hdr.pktType != TYPE_ERR ) || + ( pPkt->hdr.pktCmd != CMD_REPORT_STATUS ) || + ( pPkt->cmd.reportStatus.isFatal ) ) + { + viport_failure( pControl->p_viport ); + break; + } + + control_recv( pControl, pRecvIo ); + } + + VNIC_EXIT( VNIC_DBG_CTRL ); +} + + +ib_api_status_t +control_initInicReq( + IN Control_t *pControl ) +{ + ControlConfig_t *p_conf = pControl->p_conf; + Inic_ControlPacket_t *pPkt; + Inic_CmdInitInicReq_t *pInitInicReq; + ib_api_status_t ib_status; + + VNIC_ENTER( VNIC_DBG_CTRL ); + + if( pControl->p_viport->errored ) + { + return IB_ERROR; + } + control_initHdr( pControl, CMD_INIT_INIC ); + + pPkt = control_packet( &pControl->sendIo ); + pInitInicReq = &pPkt->cmd.initInicReq; + pInitInicReq->inicMajorVersion = hton16( INIC_MAJORVERSION ); + pInitInicReq->inicMinorVersion = hton16( INIC_MINORVERSION ); + pInitInicReq->inicInstance = p_conf->inicInstance; + pInitInicReq->numDataPaths = 1; + pInitInicReq->numAddressEntries = hton16( p_conf->maxAddressEntries ); + + ib_status = control_send( pControl ); + VNIC_EXIT( VNIC_DBG_CTRL ); + return ib_status; +} + + +BOOLEAN +control_initInicRsp( + IN Control_t *pControl, + IN uint32_t *pFeatures, + IN uint8_t *pMacAddress, + IN uint16_t *pNumAddrs, + IN uint16_t *pVlan ) +{ + RecvIo_t *pRecvIo; + ControlConfig_t *p_conf = pControl->p_conf; + Inic_ControlPacket_t *pPkt; + Inic_CmdInitInicRsp_t *pInitInicRsp; + uint8_t numDataPaths, + numLanSwitches; + + VNIC_ENTER( VNIC_DBG_CTRL ); + + pRecvIo = control_getRsp( pControl ); + if (!pRecvIo) + return FALSE; + + pPkt = control_packet( pRecvIo ); + + if ( pPkt->hdr.pktCmd != CMD_INIT_INIC ) + { + + VNIC_TRACE( VNIC_DBG_CTRL | VNIC_DBG_ERROR, + ("IOC %d: Sent control request:\n", + pControl->p_viport->ioc_num ) ); + + __control_logControlPacket( control_lastReq( pControl ) ); + + VNIC_TRACE_EXIT( VNIC_DBG_CTRL | VNIC_DBG_ERROR, + ("IOC %d: Received control response:\n", + pControl->p_viport->ioc_num ) ); + + __control_logControlPacket( pPkt ); + goto failure; + } +#ifdef _DEBUG_ + VNIC_TRACE( VNIC_DBG_CTRL_PKT, + ("IOC %d: instance %d Sent initINIC request:\n", + pControl->p_viport->ioc_num, + pControl->p_viport->p_netpath->instance ) ); + __control_logControlPacket( control_lastReq( pControl ) ); + + VNIC_TRACE(VNIC_DBG_CTRL_PKT, + ("IOC %d: instance %d Received initInic response:\n", + pControl->p_viport->ioc_num, + pControl->p_viport->p_netpath->instance ) ); + __control_logControlPacket( pPkt ); +#endif + + pInitInicRsp = &pPkt->cmd.initInicRsp; + pControl->majVer = ntoh16( pInitInicRsp->inicMajorVersion ); + pControl->minVer = ntoh16( pInitInicRsp->inicMinorVersion ); + numDataPaths = pInitInicRsp->numDataPaths; + numLanSwitches = pInitInicRsp->numLanSwitches; + *pFeatures = ntoh32( pInitInicRsp->featuresSupported ); + *pNumAddrs = ntoh16( pInitInicRsp->numAddressEntries ); + + if ( ( pControl->majVer > INIC_MAJORVERSION ) || + (( pControl->majVer == INIC_MAJORVERSION ) && + ( pControl->minVer > INIC_MINORVERSION )) ) + { + VNIC_TRACE_EXIT( VNIC_DBG_CTRL | VNIC_DBG_ERROR, + ("IOC %d: Unsupported version\n", + pControl->p_viport->ioc_num ) ); + goto failure; + } + + if ( numDataPaths != 1 ) + { + VNIC_TRACE_EXIT( VNIC_DBG_CTRL | VNIC_DBG_ERROR, + ("IOC %d: EIOC returned too many datapaths\n", + pControl->p_viport->ioc_num ) ); + goto failure; + } + + if ( *pNumAddrs > p_conf->maxAddressEntries ) + { + VNIC_TRACE_EXIT( VNIC_DBG_CTRL | VNIC_DBG_ERROR, + ("IOC %d: EIOC returned more Address entries than requested\n", + pControl->p_viport->ioc_num) ); + goto failure; + } + if ( *pNumAddrs < p_conf->minAddressEntries ) + { + VNIC_TRACE_EXIT( VNIC_DBG_CTRL | VNIC_DBG_ERROR, + ("IOC %d: Not enough address entries\n", + pControl->p_viport->ioc_num ) ); + goto failure; + } + if ( numLanSwitches < 1 ) + { + VNIC_TRACE_EXIT( VNIC_DBG_CTRL | VNIC_DBG_ERROR, + ("IOC %d: EIOC returned no lan switches\n", + pControl->p_viport->ioc_num ) ); + goto failure; + } + if ( numLanSwitches > 1 ) + { + VNIC_TRACE_EXIT( VNIC_DBG_CTRL | VNIC_DBG_ERROR, + ("IOC %d: EIOC returned multiple lan switches\n", + pControl->p_viport->ioc_num ) ); + goto failure; + } + + pControl->lanSwitch.lanSwitchNum = + pInitInicRsp->lanSwitch[0].lanSwitchNum ; + pControl->lanSwitch.numEnetPorts = + pInitInicRsp->lanSwitch[0].numEnetPorts ; + pControl->lanSwitch.defaultVlan = + ntoh16( pInitInicRsp->lanSwitch[0].defaultVlan ); + *pVlan = pControl->lanSwitch.defaultVlan; + cl_memcpy( pControl->lanSwitch.hwMacAddress, + pInitInicRsp->lanSwitch[0].hwMacAddress, MAC_ADDR_LEN ); + cl_memcpy( pMacAddress, + pInitInicRsp->lanSwitch[0].hwMacAddress, MAC_ADDR_LEN); + + control_recv( pControl, pRecvIo ); + + VNIC_EXIT( VNIC_DBG_CTRL ); + return TRUE; +failure: + viport_failure( pControl->p_viport ); + return FALSE; +} + + +ib_api_status_t +control_configDataPathReq( + IN Control_t *pControl, + IN uint64_t pathId, + IN Inic_RecvPoolConfig_t *pHost, + IN Inic_RecvPoolConfig_t *pEioc ) +{ + Inic_ControlPacket_t *pPkt; + Inic_CmdConfigDataPath_t *pConfigDataPath; + ib_api_status_t ib_status; + + VNIC_ENTER( VNIC_DBG_CTRL ); + + if( pControl->p_viport->errored ) + { + return IB_ERROR; + } + control_initHdr( pControl, CMD_CONFIG_DATA_PATH ); + + pPkt = control_packet( &pControl->sendIo ); + pConfigDataPath = &pPkt->cmd.configDataPathReq; + NdisZeroMemory( pConfigDataPath, sizeof( Inic_CmdConfigDataPath_t ) ); + pConfigDataPath->dataPath = 0; + pConfigDataPath->pathIdentifier = pathId; + copyRecvPoolConfig( pHost, &pConfigDataPath->hostRecvPoolConfig ); + copyRecvPoolConfig( pEioc, &pConfigDataPath->eiocRecvPoolConfig ); + + ib_status = control_send( pControl ); + VNIC_EXIT( VNIC_DBG_CTRL ); + return ib_status; +} + + +BOOLEAN +control_configDataPathRsp( + IN Control_t *pControl, + IN Inic_RecvPoolConfig_t *pHost, + IN Inic_RecvPoolConfig_t *pEioc, + IN Inic_RecvPoolConfig_t *pMaxHost, + IN Inic_RecvPoolConfig_t *pMaxEioc, + IN Inic_RecvPoolConfig_t *pMinHost, + IN Inic_RecvPoolConfig_t *pMinEioc ) +{ + RecvIo_t *pRecvIo; + Inic_ControlPacket_t *pPkt; + Inic_CmdConfigDataPath_t *pConfigDataPath; + + VNIC_ENTER( VNIC_DBG_CTRL ); + + pRecvIo = control_getRsp( pControl ); + if ( !pRecvIo ) + return FALSE; + + pPkt = control_packet( pRecvIo ); + + if ( pPkt->hdr.pktCmd != CMD_CONFIG_DATA_PATH ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + ("IOC %d: Sent control request:\n", + pControl->p_viport->ioc_num ) ); + + __control_logControlPacket( control_lastReq( pControl ) ); + + VNIC_TRACE( VNIC_DBG_ERROR, + ("IOC %d: Received control response:\n", + pControl->p_viport->ioc_num ) ); + + __control_logControlPacket( pPkt ); + goto failure; + } +#ifdef _DEBUG_ + VNIC_TRACE( VNIC_DBG_CTRL_PKT, + ("IOC %d: instance %d Sent configDATAPATH request:\n", + pControl->p_viport->ioc_num, + pControl->p_viport->p_netpath->instance ) ); + __control_logControlPacket( control_lastReq( pControl ) ); + + VNIC_TRACE(VNIC_DBG_CTRL_PKT, + ("IOC %d: instance %d Received configDATAPATH response:\n", + pControl->p_viport->ioc_num, + pControl->p_viport->p_netpath->instance ) ); + __control_logControlPacket( pPkt ); +#endif + pConfigDataPath = &pPkt->cmd.configDataPathRsp; + + if ( pConfigDataPath->dataPath != 0 ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + ("IOC %d: Received CMD_CONFIG_DATA_PATH response for wrong data path: %u\n", + pControl->p_viport->ioc_num , pConfigDataPath->dataPath) ); + goto failure; + } + + if ( !checkRecvPoolConfig(&pConfigDataPath->hostRecvPoolConfig, + pHost, pMaxHost, pMinHost ) + || !checkRecvPoolConfig(&pConfigDataPath->eiocRecvPoolConfig, + pEioc, pMaxEioc, pMinEioc)) + { + goto failure; + } + + control_recv( pControl, pRecvIo ); + + VNIC_EXIT( VNIC_DBG_CTRL ); + return TRUE; +failure: + viport_failure( pControl->p_viport ); + VNIC_EXIT( VNIC_DBG_CTRL ); + return FALSE; +} + + +ib_api_status_t +control_exchangePoolsReq( + IN Control_t *pControl, + IN uint64_t addr, + IN uint32_t rkey ) +{ + Inic_CmdExchangePools_t *pExchangePools; + Inic_ControlPacket_t *pPkt; + ib_api_status_t ib_status; + + VNIC_ENTER( VNIC_DBG_CTRL ); + + if( pControl->p_viport->errored ) + { + return IB_ERROR; + } + control_initHdr(pControl, CMD_EXCHANGE_POOLS ); + + pPkt = control_packet( &pControl->sendIo ); + pExchangePools = &pPkt->cmd.exchangePoolsReq; + NdisZeroMemory( pExchangePools, sizeof( Inic_CmdExchangePools_t ) ); + pExchangePools->dataPath = 0; + pExchangePools->poolRKey = rkey; + pExchangePools->poolAddr = hton64( addr ); + + ib_status = control_send( pControl ); + VNIC_EXIT( VNIC_DBG_CTRL ); + return ib_status; +} + + +BOOLEAN +control_exchangePoolsRsp( + IN Control_t *pControl, + IN OUT uint64_t *pAddr, + IN OUT uint32_t *pRkey ) +{ + RecvIo_t *pRecvIo; + Inic_ControlPacket_t *pPkt; + Inic_CmdExchangePools_t *pExchangePools; + + VNIC_ENTER( VNIC_DBG_CTRL ); + + pRecvIo = control_getRsp( pControl ); + if ( !pRecvIo ) + return FALSE; + + pPkt = control_packet( pRecvIo ); + + if ( pPkt->hdr.pktCmd != CMD_EXCHANGE_POOLS ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + ("IOC %d: Sent control request:\n", + pControl->p_viport->ioc_num ) ); + + __control_logControlPacket( control_lastReq(pControl ) ); + + VNIC_TRACE( VNIC_DBG_ERROR, + ("IOC %d: Received control response:\n", + pControl->p_viport->ioc_num ) ); + + __control_logControlPacket( pPkt ); + goto failure; + } + +#ifdef _DEBUG_ + VNIC_TRACE( VNIC_DBG_CTRL_PKT, + ("IOC %d: instance %d Sent exchangePOOLS request:\n", + pControl->p_viport->ioc_num, + pControl->p_viport->p_netpath->instance ) ); + __control_logControlPacket( control_lastReq( pControl ) ); + + VNIC_TRACE(VNIC_DBG_CTRL_PKT, + ("IOC %d: instance %d Received exchangePOOLS response:\n", + pControl->p_viport->ioc_num, + pControl->p_viport->p_netpath->instance ) ); + __control_logControlPacket( pPkt ); +#endif + pExchangePools = &pPkt->cmd.exchangePoolsRsp; + *pRkey = pExchangePools->poolRKey; + *pAddr = ntoh64( pExchangePools->poolAddr ); + + if ( hton32( pExchangePools->dataPath ) != 0 ) + { + VNIC_TRACE_EXIT( VNIC_DBG_ERROR, + ("IOC %d: Received CMD_EXCHANGE_POOLS response for wrong data path: %u\n", + pControl->p_viport->ioc_num , pExchangePools->dataPath ) ); + goto failure; + } + + control_recv( pControl, pRecvIo ); + + VNIC_EXIT( VNIC_DBG_CTRL ); + return TRUE; + +failure: + viport_failure( pControl->p_viport ); + return FALSE; +} + + +ib_api_status_t +control_configLinkReq( + IN Control_t *pControl, + IN uint8_t flags, + IN uint16_t mtu ) +{ + Inic_CmdConfigLink_t *pConfigLinkReq; + Inic_ControlPacket_t *pPkt; + ib_api_status_t ib_status; + + VNIC_ENTER( VNIC_DBG_CTRL ); + + if( pControl->p_viport->errored ) + { + return IB_ERROR; + } + control_initHdr( pControl, CMD_CONFIG_LINK ); + + pPkt = control_packet( &pControl->sendIo ); + pConfigLinkReq = &pPkt->cmd.configLinkReq; + NdisZeroMemory( pConfigLinkReq, sizeof( Inic_CmdConfigLink_t ) ); + pConfigLinkReq->lanSwitchNum = pControl->lanSwitch.lanSwitchNum; + + if ( flags & INIC_FLAG_ENABLE_NIC ) + { + pConfigLinkReq->cmdFlags |= INIC_FLAG_ENABLE_NIC; + } + else + { + pConfigLinkReq->cmdFlags |= INIC_FLAG_DISABLE_NIC; + } + + if (flags & INIC_FLAG_ENABLE_MCAST_ALL ) + { + pConfigLinkReq->cmdFlags |= INIC_FLAG_ENABLE_MCAST_ALL; + } + else + { + pConfigLinkReq->cmdFlags |= INIC_FLAG_DISABLE_MCAST_ALL; + } + if (flags & INIC_FLAG_ENABLE_PROMISC ) + { + pConfigLinkReq->cmdFlags |= INIC_FLAG_ENABLE_PROMISC; + /* The EIOU doesn't really do PROMISC mode. + * If PROMISC is set, it only receives unicast packets + * I also have to set MCAST_ALL if I want real + * PROMISC mode. + */ + pConfigLinkReq->cmdFlags &= ~INIC_FLAG_DISABLE_MCAST_ALL; + pConfigLinkReq->cmdFlags |= INIC_FLAG_ENABLE_MCAST_ALL; + } + else + { + pConfigLinkReq->cmdFlags |= INIC_FLAG_DISABLE_PROMISC; + } + + if( flags & INIC_FLAG_SET_MTU ) + { + pConfigLinkReq->cmdFlags |= INIC_FLAG_SET_MTU; + pConfigLinkReq->mtuSize = hton16( mtu ); + } + + ib_status = control_send( pControl ); + VNIC_EXIT( VNIC_DBG_CTRL ); + return ib_status; +} + + +BOOLEAN +control_configLinkRsp( + IN Control_t *pControl, + IN OUT uint8_t *pFlags, + IN OUT uint16_t *pMtu ) +{ + RecvIo_t *pRecvIo; + Inic_ControlPacket_t *pPkt; + Inic_CmdConfigLink_t *pConfigLinkRsp; + + VNIC_ENTER( VNIC_DBG_CTRL ); + + pRecvIo = control_getRsp( pControl ); + if ( !pRecvIo ) + return FALSE; + + pPkt = control_packet( pRecvIo ); + if ( pPkt->hdr.pktCmd != CMD_CONFIG_LINK ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + ("IOC %d: Sent control request:\n", + pControl->p_viport->ioc_num ) ); + + __control_logControlPacket( control_lastReq( pControl ) ); + + VNIC_TRACE( VNIC_DBG_ERROR, + ("IOC %d: Received control response:\n", + pControl->p_viport->ioc_num ) ); + + __control_logControlPacket( pPkt ); + goto failure; + } +#ifdef _DEBUG_ + VNIC_TRACE( VNIC_DBG_CTRL_PKT, + ("IOC %d: instance %d Sent configLINK request:\n", + pControl->p_viport->ioc_num, + pControl->p_viport->p_netpath->instance ) ); + __control_logControlPacket( control_lastReq( pControl ) ); + + VNIC_TRACE(VNIC_DBG_CTRL_PKT, + ("IOC %d: instance %d Received configLINK response:\n", + pControl->p_viport->ioc_num, + pControl->p_viport->p_netpath->instance ) ); + __control_logControlPacket( pPkt ); +#endif + pConfigLinkRsp = &pPkt->cmd.configLinkRsp; + + *pFlags = pConfigLinkRsp->cmdFlags; + *pMtu = ntoh16( pConfigLinkRsp->mtuSize ); + + control_recv( pControl, pRecvIo ); + + VNIC_EXIT( VNIC_DBG_CTRL ); + return TRUE; + +failure: + viport_failure( pControl->p_viport ); + VNIC_EXIT( VNIC_DBG_CTRL ); + return FALSE; +} + +/* control_configAddrsReq: + * Return values: + * -1: failure + * 0: incomplete (successful operation, but more address + * table entries to be updated) + * 1: complete + */ +ib_api_status_t +control_configAddrsReq( + IN Control_t *pControl, + IN Inic_AddressOp_t *pAddrs, + IN uint16_t num, + OUT int32_t *pAddrQueryDone ) +{ + Inic_CmdConfigAddresses_t *pConfigAddrsReq; + Inic_ControlPacket_t *pPkt; + uint16_t i; + uint8_t j; + ib_api_status_t ib_status; + + VNIC_ENTER( VNIC_DBG_CTRL ); + + if( pControl->p_viport->errored ) + { + return IB_ERROR; + } + control_initHdr( pControl, CMD_CONFIG_ADDRESSES ); + + pPkt = control_packet( &pControl->sendIo ); + pConfigAddrsReq = &pPkt->cmd.configAddressesReq; + NdisZeroMemory( pConfigAddrsReq, sizeof( Inic_CmdConfigAddresses_t ) ); + pConfigAddrsReq->lanSwitchNum = pControl->lanSwitch.lanSwitchNum; + + for ( i=0, j = 0; ( i < num ) && ( j < 16 ); i++ ) + { + if ( !pAddrs[i].operation ) + continue; + + pConfigAddrsReq->listAddressOps[j].index = hton16(i); + pConfigAddrsReq->listAddressOps[j].operation = INIC_OP_SET_ENTRY; + pConfigAddrsReq->listAddressOps[j].valid = pAddrs[i].valid; + + cl_memcpy( pConfigAddrsReq->listAddressOps[j].address, + pAddrs[i].address, MAC_ADDR_LEN ); + pConfigAddrsReq->listAddressOps[j].vlan = hton16( pAddrs[i].vlan ); + pAddrs[i].operation = 0; + j++; + } + pConfigAddrsReq->numAddressOps = j; + + for ( ; i < num; i++ ) + { + if ( pAddrs[i].operation ) + break; + } + *pAddrQueryDone = (i == num); + + ib_status = control_send( pControl ); + VNIC_EXIT( VNIC_DBG_CTRL ); + return ib_status; +} + + +BOOLEAN +control_configAddrsRsp( + IN Control_t *pControl ) +{ + RecvIo_t *pRecvIo; + Inic_ControlPacket_t *pPkt; + Inic_CmdConfigAddresses_t *pConfigAddrsRsp; + + VNIC_ENTER( VNIC_DBG_CTRL ); + + pRecvIo = control_getRsp( pControl ); + if ( !pRecvIo ) + return FALSE; + + pPkt = control_packet( pRecvIo ); + if ( pPkt->hdr.pktCmd != CMD_CONFIG_ADDRESSES ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + ("IOC %d: Sent control request:\n", + pControl->p_viport->ioc_num ) ); + + __control_logControlPacket( control_lastReq( pControl ) ); + + VNIC_TRACE_EXIT(VNIC_DBG_ERROR, + ("IOC %d: Received control response:\n", + pControl->p_viport->ioc_num ) ); + + __control_logControlPacket( pPkt ); + + goto failure; + } + +#ifdef _DEBUG_ + VNIC_TRACE( VNIC_DBG_CTRL_PKT, + ("IOC %d: instance %d Sent configADDRS request:\n", + pControl->p_viport->ioc_num, + pControl->p_viport->p_netpath->instance ) ); + __control_logControlPacket( control_lastReq( pControl ) ); + + VNIC_TRACE(VNIC_DBG_CTRL_PKT, + ("IOC %d: instance %d Received configADDRS response:\n", + pControl->p_viport->ioc_num, + pControl->p_viport->p_netpath->instance ) ); + __control_logControlPacket( pPkt ); +#endif + + pConfigAddrsRsp = &pPkt->cmd.configAddressesRsp; + + control_recv( pControl, pRecvIo ); + VNIC_EXIT( VNIC_DBG_CTRL ); + return TRUE; + +failure: + viport_failure( pControl->p_viport ); + return FALSE; +} + + +ib_api_status_t +control_reportStatisticsReq( + IN Control_t *pControl ) +{ + Inic_ControlPacket_t *pPkt; + Inic_CmdReportStatisticsReq_t *pReportStatisticsReq; + ib_api_status_t ib_status; + + VNIC_ENTER( VNIC_DBG_CTRL ); + + control_initHdr( pControl, CMD_REPORT_STATISTICS ); + + pPkt = control_packet( &pControl->sendIo ); + pReportStatisticsReq = &pPkt->cmd.reportStatisticsReq; + pReportStatisticsReq->lanSwitchNum = pControl->lanSwitch.lanSwitchNum; + + ib_status = control_send( pControl ); + VNIC_EXIT( VNIC_DBG_CTRL ); + return ib_status; +} + + +BOOLEAN +control_reportStatisticsRsp( + IN Control_t *pControl, + IN Inic_CmdReportStatisticsRsp_t *pStats ) +{ + RecvIo_t *pRecvIo; + Inic_ControlPacket_t *pPkt; + Inic_CmdReportStatisticsRsp_t *pRepStatRsp; + + VNIC_ENTER( VNIC_DBG_CTRL ); + + pRecvIo = control_getRsp( pControl ); + if (!pRecvIo) + return FALSE; + + pPkt = control_packet( pRecvIo ); + if ( pPkt->hdr.pktCmd != CMD_REPORT_STATISTICS ) + { + VNIC_TRACE(VNIC_DBG_ERROR, + ("IOC %d: Sent control request:\n", + pControl->p_viport->ioc_num ) ); + + __control_logControlPacket( control_lastReq( pControl ) ); + + VNIC_TRACE_EXIT(VNIC_DBG_ERROR, + ("IOC %d: Received control response:\n", + pControl->p_viport->ioc_num ) ); + + __control_logControlPacket( pPkt ); + + goto failure; + } + + pRepStatRsp = &pPkt->cmd.reportStatisticsRsp; + pStats->ifInBroadcastPkts = ntoh64(pRepStatRsp->ifInBroadcastPkts); + pStats->ifInMulticastPkts = ntoh64(pRepStatRsp->ifInMulticastPkts); + pStats->ifInOctets = ntoh64(pRepStatRsp->ifInOctets); + pStats->ifInUcastPkts = ntoh64(pRepStatRsp->ifInUcastPkts); + pStats->ifInNUcastPkts = ntoh64(pRepStatRsp->ifInNUcastPkts); + pStats->ifInUnderrun = ntoh64(pRepStatRsp->ifInUnderrun); + pStats->ifInErrors = ntoh64(pRepStatRsp->ifInErrors); + pStats->ifOutErrors = ntoh64(pRepStatRsp->ifOutErrors); + pStats->ifOutOctets = ntoh64(pRepStatRsp->ifOutOctets); + pStats->ifOutUcastPkts = ntoh64(pRepStatRsp->ifOutUcastPkts); + pStats->ifOutMulticastPkts = ntoh64(pRepStatRsp->ifOutMulticastPkts); + pStats->ifOutBroadcastPkts = ntoh64(pRepStatRsp->ifOutBroadcastPkts); + pStats->ifOutNUcastPkts = ntoh64(pRepStatRsp->ifOutNUcastPkts); + pStats->ifOutOk = ntoh64(pRepStatRsp->ifOutOk); + pStats->ifInOk = ntoh64(pRepStatRsp->ifInOk); + pStats->ifOutUcastBytes = ntoh64(pRepStatRsp->ifOutUcastBytes); + pStats->ifOutMulticastBytes = ntoh64(pRepStatRsp->ifOutMulticastBytes); + pStats->ifOutBroadcastBytes = ntoh64(pRepStatRsp->ifOutBroadcastBytes); + pStats->ifInUcastBytes = ntoh64(pRepStatRsp->ifInUcastBytes); + pStats->ifInMulticastBytes = ntoh64(pRepStatRsp->ifInMulticastBytes); + pStats->ifInBroadcastBytes = ntoh64(pRepStatRsp->ifInBroadcastBytes); + pStats->ethernetStatus = ntoh64(pRepStatRsp->ethernetStatus); + + control_recv(pControl, pRecvIo); + + VNIC_EXIT( VNIC_DBG_CTRL ); + return TRUE; +failure: + viport_failure( pControl->p_viport ); + return FALSE; +} + + +ib_api_status_t +control_resetReq( + IN Control_t *pControl ) +{ + ib_api_status_t ib_status; + + VNIC_ENTER( VNIC_DBG_CTRL ); + + control_initHdr( pControl, CMD_RESET ); + ib_status = control_send( pControl ); + + VNIC_EXIT( VNIC_DBG_CTRL ); + return ib_status; +} + +BOOLEAN +control_resetRsp( + IN Control_t *pControl ) +{ + RecvIo_t *pRecvIo; + Inic_ControlPacket_t *pPkt; + + VNIC_ENTER( VNIC_DBG_CTRL ); + + pRecvIo = control_getRsp( pControl ); + if ( !pRecvIo ) return FALSE; + + pPkt = control_packet( pRecvIo ); + + if ( pPkt->hdr.pktCmd != CMD_RESET ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + ("IOC %d: Sent control request:\n", + pControl->p_viport->ioc_num ) ); + + __control_logControlPacket( control_lastReq( pControl ) ); + + VNIC_TRACE( VNIC_DBG_ERROR, + ("IOC %d: Received control response:\n", + pControl->p_viport->ioc_num ) ); + + __control_logControlPacket( pPkt ); + + goto failure; + } + + control_recv( pControl, pRecvIo ); + VNIC_EXIT( VNIC_DBG_CTRL ); + return TRUE; +failure: + viport_failure( pControl->p_viport ); + VNIC_EXIT( VNIC_DBG_CTRL ); + return FALSE; +} + + +ib_api_status_t +control_heartbeatReq( + IN Control_t *pControl, + IN uint32_t hbInterval ) +{ + Inic_ControlPacket_t *pPkt; + Inic_CmdHeartbeat_t *pHeartbeatReq; + ib_api_status_t ib_status; + + VNIC_ENTER( VNIC_DBG_CTRL ); + if( pControl->p_viport->errored ) + { + return IB_ERROR; + } + control_initHdr(pControl, CMD_HEARTBEAT); + + pPkt = control_packet(&pControl->sendIo); + pHeartbeatReq = &pPkt->cmd.heartbeatReq; + + /* pass timeout for the target in microseconds */ + pHeartbeatReq->hbInterval = hton32( hbInterval*1000 ); + + ib_status = control_send( pControl ); + VNIC_EXIT( VNIC_DBG_CTRL ); + return ib_status; +} + +BOOLEAN +control_heartbeatRsp( + IN Control_t *pControl ) +{ + RecvIo_t *pRecvIo; + Inic_ControlPacket_t *pPkt; + Inic_CmdHeartbeat_t *pHeartbeatRsp; + + VNIC_ENTER( VNIC_DBG_CTRL ); + + pRecvIo = control_getRsp( pControl ); + + if (!pRecvIo) + return FALSE; + + pPkt = control_packet(pRecvIo); + + if ( pPkt->hdr.pktCmd != CMD_HEARTBEAT ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + ("IOC %d: Sent control request:\n", + pControl->p_viport->ioc_num ) ); + + __control_logControlPacket( control_lastReq(pControl) ); + + VNIC_TRACE( VNIC_DBG_ERROR, + ("IOC %d: Received control response:\n", + pControl->p_viport->ioc_num ) ); + + __control_logControlPacket( pPkt ); + goto failure; + } + + pHeartbeatRsp = &pPkt->cmd.heartbeatRsp; + + control_recv( pControl, pRecvIo ); + VNIC_EXIT ( VNIC_DBG_CTRL ); + return TRUE; + +failure: + viport_failure( pControl->p_viport ); + VNIC_EXIT ( VNIC_DBG_CTRL ); + return FALSE; +} + +static void +control_recv( + IN Control_t *pControl, + IN RecvIo_t *pRecvIo ) +{ + VNIC_ENTER( VNIC_DBG_CTRL ); + + if ( ibqp_postRecv( &pControl->qp, &pRecvIo->io ) != IB_SUCCESS ) + viport_failure( pControl->p_viport ); + + VNIC_EXIT ( VNIC_DBG_CTRL ); +} + + +static void +control_recvComplete( + IN Io_t *pIo ) +{ + RecvIo_t *pRecvIo = (RecvIo_t *)pIo; + RecvIo_t *pLastRecvIo; + BOOLEAN status = FALSE; + Control_t *pControl = &pIo->pViport->control; + viport_t *p_viport = pIo->pViport; + Inic_ControlPacket_t *pPkt = control_packet(pRecvIo); + Inic_ControlHeader_t *pCHdr = &pPkt->hdr; + + if( p_viport->errored ) + { + return; + } + switch ( pCHdr->pktType ) + { + case TYPE_INFO: + pLastRecvIo = InterlockedExchangePointer( &pControl->pInfo, pRecvIo ); + + control_processAsync( pControl ); + + if ( pLastRecvIo ) + { + control_recv( pControl, pLastRecvIo ); + } + return; + + case TYPE_RSP: + break; + + default: + //TODO: Should we ever reach this? Who processes the list entries? + ASSERT( pCHdr->pktType == TYPE_INFO || pCHdr->pktType == TYPE_RSP ); + ExInterlockedInsertTailList( &pRecvIo->io.listPtrs, + &pControl->failureList, + &pControl->ioLock ); + return; + } + + if( !InterlockedExchange( (volatile LONG*)&pControl->rspExpected, FALSE ) ) + { + VNIC_TRACE_EXIT( VNIC_DBG_ERROR, + ("UNEXPECTED RSP Packet CMD: %d\n", pCHdr->pktCmd ) ); + return; + } + + InterlockedExchangePointer( &pControl->pResponse, pRecvIo ); + + switch ( pCHdr->pktCmd ) + { + case CMD_INIT_INIC: + status = control_initInicRsp( pControl, + &p_viport->featuresSupported, + p_viport->hwMacAddress, + &p_viport->numMacAddresses, + &p_viport->defaultVlan ); + if( status ) + { + InterlockedExchange( + (volatile LONG*)&p_viport->linkState, + (LONG)LINK_INITINICRSP ); + } + InterlockedOr( &p_viport->updates, SYNC_QUERY ); + break; + + case CMD_CONFIG_DATA_PATH: + status = control_configDataPathRsp( pControl, + data_hostPool( &p_viport->data ), + data_eiocPool( &p_viport->data ), + data_hostPoolMax( &p_viport->data ), + data_eiocPoolMax( &p_viport->data ), + data_hostPoolMin( &p_viport->data ), + data_eiocPoolMin( &p_viport->data )); + if( status ) + { + InterlockedExchange( + (volatile LONG*)&p_viport->linkState, + (LONG)LINK_CONFIGDATAPATHRSP ); + } + InterlockedOr( &p_viport->updates, SYNC_QUERY ); + break; + + case CMD_EXCHANGE_POOLS: + status = control_exchangePoolsRsp( &p_viport->control, + data_remotePoolAddr( &p_viport->data ), + data_remotePoolRkey( &p_viport->data ) ); + if( status ) + { + InterlockedExchange( + (volatile LONG*)&p_viport->linkState, + (LONG)LINK_XCHGPOOLRSP ); + } + InterlockedOr( &p_viport->updates, SYNC_QUERY ); + break; + + /* process other responses */ + case CMD_CONFIG_LINK: + status = control_configLinkRsp( &p_viport->control, + &p_viport->flags, + &p_viport->mtu ); + if( status ) + { + InterlockedExchange( + (volatile LONG*)&p_viport->linkState, + (LONG)LINK_CONFIGLINKRSP ); + + if( p_viport->flags & INIC_FLAG_ENABLE_NIC ) + { + /* don't indicate media state yet if in sync query */ + if( ( InterlockedExchange( &p_viport->p_netpath->carrier, TRUE ) == FALSE ) && + !( p_viport->updates & SYNC_QUERY ) ) + { + viport_restartXmit( p_viport ); + //viport_linkUp( p_viport ); + } + } + else if( p_viport->flags & INIC_FLAG_DISABLE_NIC ) + { + if( InterlockedExchange( &p_viport->p_netpath->carrier, FALSE ) == TRUE ) + { + viport_stopXmit( p_viport ); + viport_linkDown( p_viport ); + } + } + InterlockedAnd( &p_viport->updates, ~NEED_LINK_CONFIG ); + } + break; + + case CMD_HEARTBEAT: + status = control_heartbeatRsp( pControl ); + if( status && + !p_viport->errored && + !p_viport->disconnect ) + { + InterlockedExchange( + (volatile LONG*)&p_viport->link_hb_state, + (LONG)LINK_HEARTBEATRSP ); + } + // Don't signal any waiting thread or start processing other updates. + return; + + case CMD_CONFIG_ADDRESSES: + status = control_configAddrsRsp( pControl ); + if( status == TRUE ) + { // need more entries to send? + if( p_viport->addrs_query_done == 0 ) + { + if( !p_viport->errored ) + { + if( control_configAddrsReq( pControl, + p_viport->macAddresses, + p_viport->numMacAddresses, + &p_viport->addrs_query_done ) != IB_SUCCESS ) + { + viport_failure( p_viport ); + } + } + // Don't signal any waiting thread or start processing other updates. + return; + } + + InterlockedAnd( &p_viport->updates, ~NEED_ADDRESS_CONFIG ); + InterlockedExchange( (volatile LONG*)&p_viport->linkState, + (LONG)LINK_CONFIGADDRSRSP ); + } + break; + + case CMD_REPORT_STATISTICS: + status = control_reportStatisticsRsp( pControl, &p_viport->stats ); + if ( status ) + { + if( p_viport->stats.ethernetStatus > 0 && + !p_viport->errored ) + { + viport_linkUp( p_viport ); + } + else + { + viport_linkDown( p_viport ); + } + } + InterlockedAnd( &p_viport->updates, ~NEED_STATS ); + break; + + case CMD_RESET: + status = control_resetRsp( pControl ); + if( status ) + { + status = FALSE; + InterlockedExchange( + (volatile LONG*)&p_viport->linkState, + (LONG)LINK_RESETRSP ); + } + break; + + default: + break; + } + + if( _viport_process_query( p_viport, FALSE ) != NDIS_STATUS_PENDING ) + { + /* Complete any pending set OID. */ + vnic_resume_set_oids( p_viport->p_adapter ); + } + + if( InterlockedAnd( &p_viport->updates, ~SYNC_QUERY ) & SYNC_QUERY ) + cl_event_signal( &p_viport->sync_event ); +} + + +static ib_api_status_t +control_send( + IN Control_t *pControl ) +{ + Inic_ControlPacket_t *pPkt = control_packet(&pControl->sendIo); + + VNIC_ENTER ( VNIC_DBG_CTRL ); + + if ( InterlockedCompareExchange( (volatile LONG*)&pControl->reqOutstanding, + TRUE, FALSE ) == TRUE ) + { + /* IF WE HIT THIS WE ARE HOSED!!! + * by the time we detect this error, the send buffer has been + * overwritten, and if we retry we will send garbage data. + */ + VNIC_TRACE_EXIT( VNIC_DBG_ERROR, + ("IB Send never completed\n" ) ); + goto failure; + } + +#ifdef _DEBUG_ + //__control_logControlPacket( pPkt ); +#endif + InterlockedExchange( (volatile LONG*)&pControl->rspExpected, + (LONG)pPkt->hdr.pktCmd ); + + control_timer( pControl, pControl->p_conf->rspTimeout ); + +#ifdef VNIC_STATISTIC + pControl->statistics.requestTime = cl_get_time_stamp(); +#endif /* VNIC_STATISTIC */ + + if( ( ibqp_postSend( &pControl->qp, &pControl->sendIo.io )) != IB_SUCCESS ) + { + InterlockedExchange((volatile LONG*)&pControl->reqOutstanding, FALSE ); + + VNIC_TRACE( VNIC_DBG_ERROR, + ("IOC %d: Failed to post send\n", pControl->p_viport->ioc_num ) ); + goto failure; + } + + VNIC_EXIT( VNIC_DBG_CTRL ); + return IB_SUCCESS; + +failure: + pControl->p_viport->p_adapter->hung++; + viport_failure( pControl->p_viport ); + VNIC_EXIT( VNIC_DBG_CTRL ); + return IB_ERROR; +} + + +static void +control_sendComplete( + IN Io_t *pIo ) +{ + Control_t *pControl = &pIo->pViport->control; + + VNIC_ENTER( VNIC_DBG_CTRL ); + + InterlockedExchange((volatile LONG*)&pControl->reqOutstanding, FALSE ); + + VNIC_EXIT( VNIC_DBG_CTRL ); + return; +} + +static void +control_timeout( + IN void *p_context ) +{ + Control_t *pControl; + + VNIC_ENTER( VNIC_DBG_CTRL ); + + pControl = (Control_t *)p_context; + + InterlockedExchange( (LONG *)&pControl->timerstate, (LONG)TIMER_EXPIRED ); + + InterlockedExchange( (volatile LONG*)&pControl->rspExpected, FALSE ); + + VNIC_EXIT( VNIC_DBG_CTRL ); + return; +} + +static void +control_timer( + IN Control_t *pControl, + IN int timeout ) +{ + VNIC_ENTER( VNIC_DBG_CTRL ); + + InterlockedExchange( (LONG *)&pControl->timerstate, (LONG)TIMER_ACTIVE ); + + cl_timer_start(&pControl->timer, timeout); + + VNIC_EXIT( VNIC_DBG_CTRL ); + return; +} + +static void +control_timerStop( + IN Control_t *pControl ) +{ + VNIC_ENTER( VNIC_DBG_CTRL ); + + + if ( ( InterlockedExchange( (LONG *)&pControl->timerstate, + (LONG)TIMER_IDLE )) == TIMER_ACTIVE ) + { + cl_timer_stop( &pControl->timer ); + } + + VNIC_EXIT( VNIC_DBG_CTRL ); + return; +} + +static void +control_initHdr( + IN Control_t * pControl, + IN uint8_t cmd ) +{ + ControlConfig_t *p_conf; + Inic_ControlPacket_t *pPkt; + Inic_ControlHeader_t *pHdr; + + VNIC_ENTER( VNIC_DBG_CTRL ); + + p_conf = pControl->p_conf; + + pPkt = control_packet( &pControl->sendIo ); + pHdr = &pPkt->hdr; + + pHdr->pktType = TYPE_REQ; + pHdr->pktCmd = cmd; + pHdr->pktSeqNum = ++pControl->seqNum; + pControl->reqRetryCounter = 0; + pHdr->pktRetryCount = 0; + + VNIC_EXIT( VNIC_DBG_CTRL ); +} + +static RecvIo_t* +control_getRsp( + IN Control_t *pControl ) +{ + RecvIo_t *pRecvIo; + + VNIC_ENTER ( VNIC_DBG_CTRL ); + + pRecvIo = InterlockedExchangePointer( &pControl->pResponse, NULL ); + + if ( pRecvIo != NULL ) + { + control_timerStop(pControl); + return pRecvIo; + } + + if ( ( pControl->timerstate = + InterlockedCompareExchange( (LONG *)&pControl->timerstate, + (LONG)TIMER_IDLE, (LONG)TIMER_EXPIRED )) == TIMER_EXPIRED ) + { + Inic_ControlPacket_t *pPkt = control_packet( &pControl->sendIo ); + Inic_ControlHeader_t *pHdr = &pPkt->hdr; + + VNIC_TRACE( VNIC_DBG_ERROR, + ("IOC %d: No response received from EIOC\n", + pControl->p_viport->ioc_num ) ); +#ifdef VNIC_STATISTIC + pControl->statistics.timeoutNum++; +#endif /* VNIC_STATISTIC */ + + pControl->reqRetryCounter++; + + if ( pControl->reqRetryCounter >= pControl->p_conf->reqRetryCount ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + ("IOC %d: Control packet retry exceeded\n", + pControl->p_viport->ioc_num ) ); + } + else + { + pHdr->pktRetryCount = pControl->reqRetryCounter; + control_send( pControl ); + } + } + return NULL; +} + +static void +copyRecvPoolConfig( + IN Inic_RecvPoolConfig_t *pSrc, + IN OUT Inic_RecvPoolConfig_t *pDst ) +{ + + pDst->sizeRecvPoolEntry = hton32(pSrc->sizeRecvPoolEntry); + pDst->numRecvPoolEntries = hton32(pSrc->numRecvPoolEntries); + pDst->timeoutBeforeKick = hton32(pSrc->timeoutBeforeKick); + pDst->numRecvPoolEntriesBeforeKick = hton32(pSrc->numRecvPoolEntriesBeforeKick); + pDst->numRecvPoolBytesBeforeKick = hton32(pSrc->numRecvPoolBytesBeforeKick); + pDst->freeRecvPoolEntriesPerUpdate = hton32(pSrc->freeRecvPoolEntriesPerUpdate); + return; +} + +static BOOLEAN +checkRecvPoolConfigValue( + IN void *pSrc, + IN void *pDst, + IN void *pMax, + IN void *pMin, + IN char *name ) +{ + uint32_t value; + uint32_t *p_src = (uint32_t *)pSrc; + uint32_t *p_dst = (uint32_t *)pDst; + uint32_t *p_min = (uint32_t *)pMin; + uint32_t *p_max = (uint32_t *)pMax; + + UNREFERENCED_PARAMETER( name ); + + value = ntoh32( *p_src ); + + if (value > *p_max ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + ("Value %s too large\n", name) ); + return FALSE; + } + else if (value < *p_min ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + ("Value %s too small\n", name) ); + return FALSE; + } + + *p_dst = value; + return TRUE; +} + +static BOOLEAN +checkRecvPoolConfig( + IN Inic_RecvPoolConfig_t *pSrc, + IN Inic_RecvPoolConfig_t *pDst, + IN Inic_RecvPoolConfig_t *pMax, + IN Inic_RecvPoolConfig_t *pMin ) +{ + if (!checkRecvPoolConfigValue(&pSrc->sizeRecvPoolEntry, &pDst->sizeRecvPoolEntry, + &pMax->sizeRecvPoolEntry, &pMin->sizeRecvPoolEntry, "sizeRecvPoolEntry") + || !checkRecvPoolConfigValue(&pSrc->numRecvPoolEntries, &pDst->numRecvPoolEntries, + &pMax->numRecvPoolEntries, &pMin->numRecvPoolEntries, "numRecvPoolEntries") + || !checkRecvPoolConfigValue(&pSrc->timeoutBeforeKick, &pDst->timeoutBeforeKick, + &pMax->timeoutBeforeKick, &pMin->timeoutBeforeKick, "timeoutBeforeKick") + || !checkRecvPoolConfigValue(&pSrc->numRecvPoolEntriesBeforeKick, + &pDst->numRecvPoolEntriesBeforeKick, &pMax->numRecvPoolEntriesBeforeKick, + &pMin->numRecvPoolEntriesBeforeKick, "numRecvPoolEntriesBeforeKick") + || !checkRecvPoolConfigValue(&pSrc->numRecvPoolBytesBeforeKick, + &pDst->numRecvPoolBytesBeforeKick, &pMax->numRecvPoolBytesBeforeKick, + &pMin->numRecvPoolBytesBeforeKick, "numRecvPoolBytesBeforeKick") + || !checkRecvPoolConfigValue(&pSrc->freeRecvPoolEntriesPerUpdate, + &pDst->freeRecvPoolEntriesPerUpdate, &pMax->freeRecvPoolEntriesPerUpdate, + &pMin->freeRecvPoolEntriesPerUpdate, "freeRecvPoolEntriesPerUpdate")) + return FALSE; + + if ( !IsPowerOf2( pDst->numRecvPoolEntries ) ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + ("numRecvPoolEntries (%d) must be power of 2\n", + pDst->numRecvPoolEntries) ); + return FALSE; + } + if ( !IsPowerOf2( pDst->freeRecvPoolEntriesPerUpdate ) ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + ("freeRecvPoolEntriesPerUpdate (%d) must be power of 2\n", + pDst->freeRecvPoolEntriesPerUpdate) ); + return FALSE; + } + if ( pDst->freeRecvPoolEntriesPerUpdate >= pDst->numRecvPoolEntries ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + ("freeRecvPoolEntriesPerUpdate (%d) must be less than numRecvPoolEntries (%d)\n", + pDst->freeRecvPoolEntriesPerUpdate, pDst->numRecvPoolEntries) ); + return FALSE; + } + if ( pDst->numRecvPoolEntriesBeforeKick >= pDst->numRecvPoolEntries ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + ("numRecvPoolEntriesBeforeKick (%d) must be less than numRecvPoolEntries (%d)\n", + pDst->numRecvPoolEntriesBeforeKick, pDst->numRecvPoolEntries) ); + return FALSE; + } + + return TRUE; +} + +static void +__control_logControlPacket( + IN Inic_ControlPacket_t *pPkt ) +{ + char *type; + int i; + + switch( pPkt->hdr.pktType ) + { + case TYPE_INFO: + type = "TYPE_INFO"; + break; + case TYPE_REQ: + type = "TYPE_REQ"; + break; + case TYPE_RSP: + type = "TYPE_RSP"; + break; + case TYPE_ERR: + type = "TYPE_ERR"; + break; + default: + type = "UNKNOWN"; + } + switch( pPkt->hdr.pktCmd ) + { + case CMD_INIT_INIC: + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + ("ControlPacket: pktType = %s, pktCmd = CMD_INIT_INIC\n", type ) ); + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" pktSeqNum = %u, pktRetryCount = %u\n", + pPkt->hdr.pktSeqNum, + pPkt->hdr.pktRetryCount) ); + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" inicMajorVersion = %u, inicMinorVersion = %u\n", + ntoh16(pPkt->cmd.initInicReq.inicMajorVersion), + ntoh16(pPkt->cmd.initInicReq.inicMinorVersion)) ); + if (pPkt->hdr.pktType == TYPE_REQ) + { + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" inicInstance = %u, numDataPaths = %u\n", + pPkt->cmd.initInicReq.inicInstance, + pPkt->cmd.initInicReq.numDataPaths) ); + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" numAddressEntries = %u\n", + ntoh16(pPkt->cmd.initInicReq.numAddressEntries)) ); + } + else + { + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" numLanSwitches = %u, numDataPaths = %u\n", + pPkt->cmd.initInicRsp.numLanSwitches, + pPkt->cmd.initInicRsp.numDataPaths) ); + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" numAddressEntries = %u, featuresSupported = %08x\n", + ntoh16(pPkt->cmd.initInicRsp.numAddressEntries), + ntoh32(pPkt->cmd.initInicRsp.featuresSupported)) ); + if (pPkt->cmd.initInicRsp.numLanSwitches != 0) + { + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + ("lanSwitch[0] lanSwitchNum = %u, numEnetPorts = %08x\n", + pPkt->cmd.initInicRsp.lanSwitch[0].lanSwitchNum, + pPkt->cmd.initInicRsp.lanSwitch[0].numEnetPorts) ); + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" defaultVlan = %u, hwMacAddress = %02x:%02x:%02x:%02x:%02x:%02x\n", + ntoh16(pPkt->cmd.initInicRsp.lanSwitch[0].defaultVlan), + pPkt->cmd.initInicRsp.lanSwitch[0].hwMacAddress[0], + pPkt->cmd.initInicRsp.lanSwitch[0].hwMacAddress[1], + pPkt->cmd.initInicRsp.lanSwitch[0].hwMacAddress[2], + pPkt->cmd.initInicRsp.lanSwitch[0].hwMacAddress[3], + pPkt->cmd.initInicRsp.lanSwitch[0].hwMacAddress[4], + pPkt->cmd.initInicRsp.lanSwitch[0].hwMacAddress[5]) ); + } + } + break; + case CMD_CONFIG_DATA_PATH: + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + ( "ControlPacket: pktType = %s, pktCmd = CMD_CONFIG_DATA_PATH\n", type) ); + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" pktSeqNum = %u, pktRetryCount = %u\n", + pPkt->hdr.pktSeqNum, + pPkt->hdr.pktRetryCount) ); + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" pathIdentifier = %"PRIx64", dataPath = %u\n", + pPkt->cmd.configDataPathReq.pathIdentifier, + pPkt->cmd.configDataPathReq.dataPath) ); + + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + ("Host Config sizeRecvPoolEntry = %u, numRecvPoolEntries = %u\n", + ntoh32(pPkt->cmd.configDataPathReq.hostRecvPoolConfig.sizeRecvPoolEntry), + ntoh32(pPkt->cmd.configDataPathReq.hostRecvPoolConfig.numRecvPoolEntries)) ); + + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" timeoutBeforeKick = %u, numRecvPoolEntriesBeforeKick = %u\n", + ntoh32(pPkt->cmd.configDataPathReq.hostRecvPoolConfig.timeoutBeforeKick), + ntoh32(pPkt->cmd.configDataPathReq.hostRecvPoolConfig.numRecvPoolEntriesBeforeKick)) ); + + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" numRecvPoolBytesBeforeKick = %u, freeRecvPoolEntriesPerUpdate = %u\n", + ntoh32(pPkt->cmd.configDataPathReq.hostRecvPoolConfig.numRecvPoolBytesBeforeKick), + ntoh32(pPkt->cmd.configDataPathReq.hostRecvPoolConfig.freeRecvPoolEntriesPerUpdate)) ); + + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + ("Eioc Config sizeRecvPoolEntry = %u, numRecvPoolEntries = %u\n", + ntoh32(pPkt->cmd.configDataPathReq.eiocRecvPoolConfig.sizeRecvPoolEntry), + ntoh32(pPkt->cmd.configDataPathReq.eiocRecvPoolConfig.numRecvPoolEntries)) ); + + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" timeoutBeforeKick = %u, numRecvPoolEntriesBeforeKick = %u\n", + ntoh32(pPkt->cmd.configDataPathReq.eiocRecvPoolConfig.timeoutBeforeKick), + ntoh32(pPkt->cmd.configDataPathReq.eiocRecvPoolConfig.numRecvPoolEntriesBeforeKick)) ); + + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" numRecvPoolBytesBeforeKick = %u, freeRecvPoolEntriesPerUpdate = %u\n", + ntoh32(pPkt->cmd.configDataPathReq.eiocRecvPoolConfig.numRecvPoolBytesBeforeKick), + ntoh32(pPkt->cmd.configDataPathReq.eiocRecvPoolConfig.freeRecvPoolEntriesPerUpdate)) ); + break; + case CMD_EXCHANGE_POOLS: + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + ("ControlPacket: pktType = %s, pktCmd = CMD_EXCHANGE_POOLS\n", type ) ); + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" pktSeqNum = %u, pktRetryCount = %u\n", + pPkt->hdr.pktSeqNum, + pPkt->hdr.pktRetryCount) ); + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" datapath = %u\n", + pPkt->cmd.exchangePoolsReq.dataPath) ); + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" poolRKey = %08x poolAddr = %"PRIx64"\n", + ntoh32(pPkt->cmd.exchangePoolsReq.poolRKey), + ntoh64(pPkt->cmd.exchangePoolsReq.poolAddr)) ); + break; + case CMD_CONFIG_ADDRESSES: + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + ( "ControlPacket: pktType = %s, pktCmd = CMD_CONFIG_ADDRESSES\n", type ) ); + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" pktSeqNum = %u, pktRetryCount = %u\n", + pPkt->hdr.pktSeqNum, + pPkt->hdr.pktRetryCount) ); + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" numAddressOps = %x, lanSwitchNum = %d\n", + pPkt->cmd.configAddressesReq.numAddressOps, + pPkt->cmd.configAddressesReq.lanSwitchNum) ); + for (i = 0; ( i < pPkt->cmd.configAddressesReq.numAddressOps) && (i < 16); i++) + { + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" listAddressOps[%u].index = %u\n", + i, ntoh16(pPkt->cmd.configAddressesReq.listAddressOps[i].index)) ); + + switch(pPkt->cmd.configAddressesReq.listAddressOps[i].operation) + { + case INIC_OP_GET_ENTRY: + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" listAddressOps[%u].operation = INIC_OP_GET_ENTRY\n", i) ); + break; + case INIC_OP_SET_ENTRY: + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" listAddressOps[%u].operation = INIC_OP_SET_ENTRY\n", i) ); + break; + default: + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" listAddressOps[%u].operation = UNKNOWN(%d)\n", + i, pPkt->cmd.configAddressesReq.listAddressOps[i].operation) ); + break; + } + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" listAddressOps[%u].valid = %u\n", + i, pPkt->cmd.configAddressesReq.listAddressOps[i].valid) ); + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" listAddressOps[%u].address = %02x:%02x:%02x:%02x:%02x:%02x\n", i, + pPkt->cmd.configAddressesReq.listAddressOps[i].address[0], + pPkt->cmd.configAddressesReq.listAddressOps[i].address[1], + pPkt->cmd.configAddressesReq.listAddressOps[i].address[2], + pPkt->cmd.configAddressesReq.listAddressOps[i].address[3], + pPkt->cmd.configAddressesReq.listAddressOps[i].address[4], + pPkt->cmd.configAddressesReq.listAddressOps[i].address[5]) ); + + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" listAddressOps[%u].vlan = %u\n", + i, ntoh16(pPkt->cmd.configAddressesReq.listAddressOps[i].vlan)) ); + } + break; + case CMD_CONFIG_LINK: + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + ("ControlPacket: pktType = %s, pktCmd = CMD_CONFIG_LINK\n", type) ); + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" pktSeqNum = %u, pktRetryCount = %u\n", + pPkt->hdr.pktSeqNum, + pPkt->hdr.pktRetryCount) ); + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" cmdFlags = %x\n", + pPkt->cmd.configLinkReq.cmdFlags) ); + + if ( pPkt->cmd.configLinkReq.cmdFlags & INIC_FLAG_ENABLE_NIC ) + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" INIC_FLAG_ENABLE_NIC\n") ); + + if ( pPkt->cmd.configLinkReq.cmdFlags & INIC_FLAG_DISABLE_NIC ) + + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" INIC_FLAG_DISABLE_NIC\n") ); + + if ( pPkt->cmd.configLinkReq.cmdFlags & INIC_FLAG_ENABLE_MCAST_ALL ) + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" INIC_FLAG_ENABLE_MCAST_ALL\n") ); + + if ( pPkt->cmd.configLinkReq.cmdFlags & INIC_FLAG_DISABLE_MCAST_ALL ) + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" INIC_FLAG_DISABLE_MCAST_ALL\n") ); + + if ( pPkt->cmd.configLinkReq.cmdFlags & INIC_FLAG_ENABLE_PROMISC ) + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" INIC_FLAG_ENABLE_PROMISC\n") ); + + if ( pPkt->cmd.configLinkReq.cmdFlags & INIC_FLAG_DISABLE_PROMISC ) + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" INIC_FLAG_DISABLE_PROMISC\n") ); + if ( pPkt->cmd.configLinkReq.cmdFlags & INIC_FLAG_SET_MTU ) + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" INIC_FLAG_SET_MTU\n") ); + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" lanSwitchNum = %x, mtuSize = %d\n", + pPkt->cmd.configLinkReq.lanSwitchNum, + ntoh16(pPkt->cmd.configLinkReq.mtuSize)) ); + if ( pPkt->hdr.pktType == TYPE_RSP ) + { + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" defaultVlan = %u, hwMacAddress = %02x:%02x:%02x:%02x:%02x:%02x\n", + ntoh16(pPkt->cmd.configLinkReq.defaultVlan), + pPkt->cmd.configLinkReq.hwMacAddress[0], + pPkt->cmd.configLinkReq.hwMacAddress[1], + pPkt->cmd.configLinkReq.hwMacAddress[2], + pPkt->cmd.configLinkReq.hwMacAddress[3], + pPkt->cmd.configLinkReq.hwMacAddress[4], + pPkt->cmd.configLinkReq.hwMacAddress[5]) ); + } + break; + case CMD_REPORT_STATISTICS: + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + ("ControlPacket: pktType = %s, pktCmd = CMD_REPORT_STATISTICS\n", type ) ); + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" pktSeqNum = %u, pktRetryCount = %u\n", + pPkt->hdr.pktSeqNum, + pPkt->hdr.pktRetryCount) ); + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" lanSwitchNum = %u\n", + pPkt->cmd.reportStatisticsReq.lanSwitchNum) ); + + if (pPkt->hdr.pktType == TYPE_REQ) + break; + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" ifInBroadcastPkts = %"PRIu64, + ntoh64(pPkt->cmd.reportStatisticsRsp.ifInBroadcastPkts)) ); + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" ifInMulticastPkts = %"PRIu64"\n", + ntoh64(pPkt->cmd.reportStatisticsRsp.ifInMulticastPkts)) ); + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" ifInOctets = %"PRIu64, + ntoh64(pPkt->cmd.reportStatisticsRsp.ifInOctets)) ); + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" ifInUcastPkts = %"PRIu64"\n", + ntoh64(pPkt->cmd.reportStatisticsRsp.ifInUcastPkts)) ); + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" ifInNUcastPkts = %"PRIu64, + ntoh64(pPkt->cmd.reportStatisticsRsp.ifInNUcastPkts)) ); + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" ifInUnderrun = %"PRIu64"\n", + ntoh64(pPkt->cmd.reportStatisticsRsp.ifInUnderrun)) ); + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" ifInErrors = %"PRIu64, + ntoh64(pPkt->cmd.reportStatisticsRsp.ifInErrors)) ); + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" ifOutErrors = %"PRIu64"\n", + ntoh64(pPkt->cmd.reportStatisticsRsp.ifOutErrors)) ); + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" ifOutOctets = %"PRIu64, + ntoh64(pPkt->cmd.reportStatisticsRsp.ifOutOctets)) ); + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" ifOutUcastPkts = %"PRIu64"\n", + ntoh64(pPkt->cmd.reportStatisticsRsp.ifOutUcastPkts)) ); + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" ifOutMulticastPkts = %"PRIu64, + ntoh64(pPkt->cmd.reportStatisticsRsp.ifOutMulticastPkts)) ); + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" ifOutBroadcastPkts = %"PRIu64"\n", + ntoh64(pPkt->cmd.reportStatisticsRsp.ifOutBroadcastPkts)) ); + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" ifOutNUcastPkts = %"PRIu64, + ntoh64(pPkt->cmd.reportStatisticsRsp.ifOutNUcastPkts)) ); + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" ifOutOk = %"PRIu64"\n", + ntoh64(pPkt->cmd.reportStatisticsRsp.ifOutOk)) ); + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" ifInOk = %"PRIu64, + ntoh64(pPkt->cmd.reportStatisticsRsp.ifInOk)) ); + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" ifOutUcastBytes = %"PRIu64"\n", + ntoh64(pPkt->cmd.reportStatisticsRsp.ifOutUcastBytes)) ); + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" ifOutMulticastBytes = %"PRIu64, + ntoh64(pPkt->cmd.reportStatisticsRsp.ifOutMulticastBytes)) ); + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" ifOutBroadcastBytes = %"PRIu64"\n", + ntoh64(pPkt->cmd.reportStatisticsRsp.ifOutBroadcastBytes)) ); + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" ifInUcastBytes = %"PRIu64, + ntoh64(pPkt->cmd.reportStatisticsRsp.ifInUcastBytes)) ); + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" ifInMulticastBytes = %"PRIu64"\n", + ntoh64(pPkt->cmd.reportStatisticsRsp.ifInMulticastBytes)) ); + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" ifInBroadcastBytes = %"PRIu64, + ntoh64(pPkt->cmd.reportStatisticsRsp.ifInBroadcastBytes)) ); + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" ethernetStatus = %"PRIu64"\n", + ntoh64(pPkt->cmd.reportStatisticsRsp.ethernetStatus)) ); + break; + case CMD_CLEAR_STATISTICS: + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + ("ControlPacket: pktType = %s, pktCmd = CMD_CLEAR_STATISTICS\n", type ) ); + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" pktSeqNum = %u, pktRetryCount = %u\n", + pPkt->hdr.pktSeqNum, + pPkt->hdr.pktRetryCount) ); + break; + case CMD_REPORT_STATUS: + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + ("ControlPacket: pktType = %s, pktCmd = CMD_REPORT_STATUS\n", + type) ); + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" pktSeqNum = %u, pktRetryCount = %u\n", + pPkt->hdr.pktSeqNum, + pPkt->hdr.pktRetryCount) ); + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" lanSwitchNum = %u, isFatal = %u\n", + pPkt->cmd.reportStatus.lanSwitchNum, + pPkt->cmd.reportStatus.isFatal) ); + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" statusNumber = %u, statusInfo = %u\n", + ntoh32(pPkt->cmd.reportStatus.statusNumber), + ntoh32(pPkt->cmd.reportStatus.statusInfo)) ); + pPkt->cmd.reportStatus.fileName[31] = '\0'; + pPkt->cmd.reportStatus.routine[31] = '\0'; + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" filename = %s, routine = %s\n", + pPkt->cmd.reportStatus.fileName, + pPkt->cmd.reportStatus.routine) ); + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" lineNum = %u, errorParameter = %u\n", + ntoh32(pPkt->cmd.reportStatus.lineNum), + ntoh32(pPkt->cmd.reportStatus.errorParameter)) ); + pPkt->cmd.reportStatus.descText[127] = '\0'; + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" descText = %s\n", + pPkt->cmd.reportStatus.descText) ); + break; + case CMD_RESET: + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + ("ControlPacket: pktType = %s, pktCmd = CMD_RESET\n", type ) ); + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" pktSeqNum = %u, pktRetryCount = %u\n", + pPkt->hdr.pktSeqNum, + pPkt->hdr.pktRetryCount) ); + break; + case CMD_HEARTBEAT: + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + ("ControlPacket: pktType = %s, pktCmd = CMD_HEARTBEAT\n", type ) ); + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" pktSeqNum = %u, pktRetryCount = %u\n", + pPkt->hdr.pktSeqNum, + pPkt->hdr.pktRetryCount) ); + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" hbInterval = %d\n", + ntoh32(pPkt->cmd.heartbeatReq.hbInterval)) ); + break; + default: + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + ("ControlPacket: pktType = %s, pktCmd = UNKNOWN (%u)\n", + type,pPkt->hdr.pktCmd) ); + VNIC_PRINT( VNIC_DBG_CTRL_PKT, + (" pktSeqNum = %u, pktRetryCount = %u\n", + pPkt->hdr.pktSeqNum, + pPkt->hdr.pktRetryCount) ); + break; + } + return; +} diff --git a/branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_control.h b/branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_control.h new file mode 100644 index 00000000..b18372bf --- /dev/null +++ b/branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_control.h @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2007 QLogic Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#ifndef _VNIC_CONTROL_H_ +#define _VNIC_CONTROL_H_ + +#include "vnic_controlpkt.h" +#include "vnic_util.h" + +typedef enum { + TIMER_IDLE, + TIMER_ACTIVE, + TIMER_EXPIRED +}timerstate_t; + +typedef struct Control { + struct _viport *p_viport; + struct ControlConfig *p_conf; + IbRegion_t region; + IbQp_t qp; + uint8_t *pLocalStorage; + uint16_t majVer; + uint16_t minVer; + Inic_LanSwitchAttributes_t lanSwitch; + SendIo_t sendIo; + RecvIo_t *pRecvIos; + + timerstate_t timerstate; + cl_timer_t timer; + uint8_t reqRetryCounter; + uint8_t seqNum; + uint32_t reqOutstanding; + uint32_t rspExpected; + RecvIo_t *pResponse; + RecvIo_t *pInfo; + LIST_ENTRY failureList; + KSPIN_LOCK ioLock; + +#ifdef VNIC_STATISTIC + struct { + uint64_t requestTime; /* Intermediate value */ + uint64_t responseTime; + uint32_t responseNum; + uint64_t responseMax; + uint64_t responseMin; + uint32_t timeoutNum; + } statistics; +#endif /* VNIC_STATISTIC */ +} Control_t; + +void +control_construct( + IN Control_t *pControl, + IN struct _viport *pViport ); + +ib_api_status_t control_init(Control_t *pControl, struct _viport *pViport, + struct ControlConfig *p_conf, uint64_t guid); +void control_cleanup(Control_t *pControl); +void control_processAsync(Control_t *pControl); +ib_api_status_t control_initInicReq(Control_t *pControl); +BOOLEAN control_initInicRsp(Control_t *pControl, uint32_t *pFeatures, + uint8_t *pMacAddress, uint16_t *pNumAddrs, uint16_t *pVlan); +ib_api_status_t control_configDataPathReq(Control_t *pControl, uint64_t pathId, + struct Inic_RecvPoolConfig *pHost, + struct Inic_RecvPoolConfig *pEioc); +BOOLEAN control_configDataPathRsp(Control_t *pControl, + struct Inic_RecvPoolConfig *pHost, + struct Inic_RecvPoolConfig *pEioc, + struct Inic_RecvPoolConfig *pMaxHost, + struct Inic_RecvPoolConfig *pMaxEioc, + struct Inic_RecvPoolConfig *pMinHost, + struct Inic_RecvPoolConfig *pMinEioc); +ib_api_status_t control_exchangePoolsReq(Control_t *pControl, uint64_t addr, uint32_t rkey); +BOOLEAN control_exchangePoolsRsp(Control_t *pControl, uint64_t *pAddr, + uint32_t *pRkey); +ib_api_status_t control_configLinkReq(Control_t *pControl, uint8_t flags, uint16_t mtu); +BOOLEAN control_configLinkRsp(Control_t *pControl, uint8_t *pFlags, uint16_t *pMtu); +ib_api_status_t control_configAddrsReq(Control_t *pControl, Inic_AddressOp_t *pAddrs, + uint16_t num, int32_t *pAddrQueryDone); +BOOLEAN control_configAddrsRsp(Control_t *pControl); +ib_api_status_t control_reportStatisticsReq(Control_t *pControl); +BOOLEAN control_reportStatisticsRsp(Control_t *pControl, + struct Inic_CmdReportStatisticsRsp *pStats); +ib_api_status_t control_resetReq( Control_t *pControl ); +BOOLEAN control_resetRsp(Control_t *pControl); +ib_api_status_t control_heartbeatReq(Control_t *pControl, uint32_t hbInterval); +BOOLEAN control_heartbeatRsp(Control_t *pControl); + +#define control_packet(pIo) (Inic_ControlPacket_t *)(LONG_PTR)((pIo)->dsList.vaddr ) +#define control_lastReq(pControl) control_packet(&(pControl)->sendIo) +#define control_features(pControl) (pControl)->featuresSupported +#define control_getMacAddress(pControl,addr) \ + memcpy(addr,(pControl)->lanSwitch.hwMacAddress,MAC_ADDR_LEN) + +#endif /* _VNIC_CONTROL_H_ */ diff --git a/branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_controlpkt.h b/branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_controlpkt.h new file mode 100644 index 00000000..12427267 --- /dev/null +++ b/branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_controlpkt.h @@ -0,0 +1,287 @@ +/* + * Copyright (c) 2007 QLogic Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#ifndef _VNIC_CONTROLPKT_H_ +#define _VNIC_CONTROLPKT_H_ + +#include +#define MAX_HOST_NAME_SIZE 64 + +typedef struct Inic_ConnectionData { + uint64_t pathId; + uint8_t inicInstance; + uint8_t pathNum; + uint8_t nodename[MAX_HOST_NAME_SIZE+1]; + uint8_t reserved; + uint32_t featuresSupported; +} Inic_ConnectionData_t; + +typedef struct Inic_ControlHeader { + uint8_t pktType; + uint8_t pktCmd; + uint8_t pktSeqNum; + uint8_t pktRetryCount; + uint32_t reserved; /* for 64-bit alignmnet */ +} Inic_ControlHeader_t; + +/* ptkType values */ +#define TYPE_INFO 0 +#define TYPE_REQ 1 +#define TYPE_RSP 2 +#define TYPE_ERR 3 + +/* ptkCmd values */ +#define CMD_INIT_INIC 1 +#define CMD_CONFIG_DATA_PATH 2 +#define CMD_EXCHANGE_POOLS 3 +#define CMD_CONFIG_ADDRESSES 4 +#define CMD_CONFIG_LINK 5 +#define CMD_REPORT_STATISTICS 6 +#define CMD_CLEAR_STATISTICS 7 +#define CMD_REPORT_STATUS 8 +#define CMD_RESET 9 +#define CMD_HEARTBEAT 10 + +#define MAC_ADDR_LEN HW_ADDR_LEN + +/* pktCmd CMD_INIT_INIC, pktType TYPE_REQ data format */ +typedef struct Inic_CmdInitInicReq { + uint16_t inicMajorVersion; + uint16_t inicMinorVersion; + uint8_t inicInstance; + uint8_t numDataPaths; + uint16_t numAddressEntries; +} Inic_CmdInitInicReq_t; + +/* pktCmd CMD_INIT_INIC, pktType TYPE_RSP subdata format */ +typedef struct Inic_LanSwitchAttributes { + uint8_t lanSwitchNum; + uint8_t numEnetPorts; + uint16_t defaultVlan; + uint8_t hwMacAddress[MAC_ADDR_LEN]; +} Inic_LanSwitchAttributes_t; + +/* pktCmd CMD_INIT_INIC, pktType TYPE_RSP data format */ +typedef struct Inic_CmdInitInicRsp { + uint16_t inicMajorVersion; + uint16_t inicMinorVersion; + uint8_t numLanSwitches; + uint8_t numDataPaths; + uint16_t numAddressEntries; + uint32_t featuresSupported; + Inic_LanSwitchAttributes_t lanSwitch[1]; +} Inic_CmdInitInicRsp_t; + +/* featuresSupported values */ +#define INIC_FEAT_IPV4_HEADERS 0x00000001 +#define INIC_FEAT_IPV6_HEADERS 0x00000002 +#define INIC_FEAT_IPV4_CSUM_RX 0x00000004 +#define INIC_FEAT_IPV4_CSUM_TX 0x00000008 +#define INIC_FEAT_TCP_CSUM_RX 0x00000010 +#define INIC_FEAT_TCP_CSUM_TX 0x00000020 +#define INIC_FEAT_UDP_CSUM_RX 0x00000040 +#define INIC_FEAT_UDP_CSUM_TX 0x00000080 +#define INIC_FEAT_TCP_SEGMENT 0x00000100 +#define INIC_FEAT_IPV4_IPSEC_OFFLOAD 0x00000200 +#define INIC_FEAT_IPV6_IPSEC_OFFLOAD 0x00000400 +#define INIC_FEAT_FCS_PROPAGATE 0x00000800 +#define INIC_FEAT_PF_KICK 0x00001000 +#define INIC_FEAT_PF_FORCE_ROUTE 0x00002000 +#define INIC_FEAT_CHASH_OFFLOAD 0x00004000 +#define INIC_FEAT_RDMA_IMMED 0x00008000 +#define INIC_FEAT_IGNORE_VLAN 0x00010000 +#define INIC_FEAT_INBOUND_IB_MC 0x00200000 + +/* pktCmd CMD_CONFIG_DATA_PATH subdata format */ +typedef struct Inic_RecvPoolConfig { + uint32_t sizeRecvPoolEntry; + uint32_t numRecvPoolEntries; + uint32_t timeoutBeforeKick; + uint32_t numRecvPoolEntriesBeforeKick; + uint32_t numRecvPoolBytesBeforeKick; + uint32_t freeRecvPoolEntriesPerUpdate; +} Inic_RecvPoolConfig_t; + +/* pktCmd CMD_CONFIG_DATA_PATH data format */ +typedef struct Inic_CmdConfigDataPath { + uint64_t pathIdentifier; + uint8_t dataPath; + uint8_t reserved[3]; + Inic_RecvPoolConfig_t hostRecvPoolConfig; + Inic_RecvPoolConfig_t eiocRecvPoolConfig; +} Inic_CmdConfigDataPath_t; + +/* pktCmd CMD_EXCHANGE_POOLS data format */ +typedef struct Inic_CmdExchangePools { + uint8_t dataPath; + uint8_t reserved[3]; + uint32_t poolRKey; + uint64_t poolAddr; +} Inic_CmdExchangePools_t; + +/* pktCmd CMD_CONFIG_ADDRESSES subdata format */ +typedef struct Inic_AddressOp { + uint16_t index; + uint8_t operation; + uint8_t valid; + uint8_t address[6]; + uint16_t vlan; +} Inic_AddressOp_t; + +/* operation values */ +#define INIC_OP_SET_ENTRY 0x01 +#define INIC_OP_GET_ENTRY 0x02 + +/* pktCmd CMD_CONFIG_ADDRESSES data format */ +typedef struct Inic_CmdConfigAddresses { + uint8_t numAddressOps; + uint8_t lanSwitchNum; + Inic_AddressOp_t listAddressOps[1]; +} Inic_CmdConfigAddresses_t; + +/* CMD_CONFIG_LINK data format */ +typedef struct Inic_CmdConfigLink { + uint8_t cmdFlags; + uint8_t lanSwitchNum; + uint16_t mtuSize; + uint16_t defaultVlan; + uint8_t hwMacAddress[6]; +} Inic_CmdConfigLink_t; + +/* cmdFlags values */ +#define INIC_FLAG_ENABLE_NIC 0x01 +#define INIC_FLAG_DISABLE_NIC 0x02 +#define INIC_FLAG_ENABLE_MCAST_ALL 0x04 +#define INIC_FLAG_DISABLE_MCAST_ALL 0x08 +#define INIC_FLAG_ENABLE_PROMISC 0x10 +#define INIC_FLAG_DISABLE_PROMISC 0x20 +#define INIC_FLAG_SET_MTU 0x40 + +/* pktCmd CMD_REPORT_STATISTICS, pktType TYPE_REQ data format */ +typedef struct Inic_CmdReportStatisticsReq { + uint8_t lanSwitchNum; +} Inic_CmdReportStatisticsReq_t; + +/* pktCmd CMD_REPORT_STATISTICS, pktType TYPE_RSP data format */ +typedef struct Inic_CmdReportStatisticsRsp { + uint8_t lanSwitchNum; + uint8_t reserved[7]; /* for 64-bit alignment */ + uint64_t ifInBroadcastPkts; + uint64_t ifInMulticastPkts; + uint64_t ifInOctets; + uint64_t ifInUcastPkts; + uint64_t ifInNUcastPkts; /* ifInBroadcastPkts + ifInMulticastPkts */ + uint64_t ifInUnderrun; /* (OID_GEN_RCV_NO_BUFFER) */ + uint64_t ifInErrors; /* (OID_GEN_RCV_ERROR) */ + uint64_t ifOutErrors; /* (OID_GEN_XMIT_ERROR) */ + uint64_t ifOutOctets; + uint64_t ifOutUcastPkts; + uint64_t ifOutMulticastPkts; + uint64_t ifOutBroadcastPkts; + uint64_t ifOutNUcastPkts; /* ifOutBroadcastPkts + ifOutMulticastPkts */ + uint64_t ifOutOk; /* ifOutNUcastPkts + ifOutUcastPkts (OID_GEN_XMIT_OK)*/ + uint64_t ifInOk; /* ifInNUcastPkts + ifInUcastPkts (OID_GEN_RCV_OK) */ + uint64_t ifOutUcastBytes; /* (OID_GEN_DIRECTED_BYTES_XMT) */ + uint64_t ifOutMulticastBytes; /* (OID_GEN_MULTICAST_BYTES_XMT) */ + uint64_t ifOutBroadcastBytes; /* (OID_GEN_BROADCAST_BYTES_XMT) */ + uint64_t ifInUcastBytes; /* (OID_GEN_DIRECTED_BYTES_RCV) */ + uint64_t ifInMulticastBytes; /* (OID_GEN_MULTICAST_BYTES_RCV) */ + uint64_t ifInBroadcastBytes; /* (OID_GEN_BROADCAST_BYTES_RCV) */ + uint64_t ethernetStatus; /* OID_GEN_MEDIA_CONNECT_STATUS) */ +} Inic_CmdReportStatisticsRsp_t; + +/* pktCmd CMD_CLEAR_STATISTICS data format */ +typedef struct Inic_CmdClearStatistics { + uint8_t lanSwitchNum; +} Inic_CmdClearStatistics_t; + +/* pktCmd CMD_REPORT_STATUS data format */ +typedef struct Inic_CmdReportStatus { + uint8_t lanSwitchNum; + uint8_t isFatal; + uint8_t reserved[2]; /* for 32-bit alignment */ + uint32_t statusNumber; + uint32_t statusInfo; + uint8_t fileName[32]; + uint8_t routine[32]; + uint32_t lineNum; + uint32_t errorParameter; + uint8_t descText[128]; +} Inic_CmdReportStatus_t; + +/* pktCmd CMD_HEARTBEAT data format */ +typedef struct Inic_CmdHeartbeat { + uint32_t hbInterval; +} Inic_CmdHeartbeat_t; + +#define INIC_STATUS_LINK_UP 1 +#define INIC_STATUS_LINK_DOWN 2 +#define INIC_STATUS_ENET_AGGREGATION_CHANGE 3 +#define INIC_STATUS_EIOC_SHUTDOWN 4 +#define INIC_STATUS_CONTROL_ERROR 5 +#define INIC_STATUS_EIOC_ERROR 6 + +#define INIC_MAX_CONTROLPKTSZ 256 +#define INIC_MAX_CONTROLDATASZ \ + (INIC_MAX_CONTROLPKTSZ - sizeof(Inic_ControlHeader_t)) + +typedef struct Inic_ControlPacket { + Inic_ControlHeader_t hdr; + union { + Inic_CmdInitInicReq_t initInicReq; + Inic_CmdInitInicRsp_t initInicRsp; + Inic_CmdConfigDataPath_t configDataPathReq; + Inic_CmdConfigDataPath_t configDataPathRsp; + Inic_CmdExchangePools_t exchangePoolsReq; + Inic_CmdExchangePools_t exchangePoolsRsp; + Inic_CmdConfigAddresses_t configAddressesReq; + Inic_CmdConfigAddresses_t configAddressesRsp; + Inic_CmdConfigLink_t configLinkReq; + Inic_CmdConfigLink_t configLinkRsp; + Inic_CmdReportStatisticsReq_t reportStatisticsReq; + Inic_CmdReportStatisticsRsp_t reportStatisticsRsp; + Inic_CmdClearStatistics_t clearStatisticsReq; + Inic_CmdClearStatistics_t clearStatisticsRsp; + Inic_CmdReportStatus_t reportStatus; + Inic_CmdHeartbeat_t heartbeatReq; + Inic_CmdHeartbeat_t heartbeatRsp; + char cmdData[INIC_MAX_CONTROLDATASZ]; + } cmd; +} Inic_ControlPacket_t; +/* +typedef struct _mac_addr +{ + uint8_t addr[MAC_ADDR_LEN]; +} PACK_SUFFIX mac_addr_t; +*/ +#include + +#endif /* _VNIC_CONTROLPKT_H_ */ diff --git a/branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_data.c b/branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_data.c new file mode 100644 index 00000000..09f1ca55 --- /dev/null +++ b/branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_data.c @@ -0,0 +1,1459 @@ +/* + * Copyright (c) 2007 QLogic Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ +#include +#include "vnic_driver.h" + +static void data_postRecvs(Data_t *pData); +static void _data_receivedKick(Io_t *pIo); +static void _data_xmitComplete(Io_t *pIo); +static void data_sendKickMessage(Data_t *pData); +static void _data_kickTimeoutHandler( void *context ); +static BOOLEAN data_allocXmitBuffer(Data_t *pData, + BufferPoolEntry_t **ppBpe, RdmaIo_t **ppRdmaIo, BOOLEAN *pLast); +static void data_checkXmitBuffers(Data_t *pData); + +static +ib_api_status_t +data_rdmaPacket( + Data_t *pData, + BufferPoolEntry_t *pBpe, + RdmaIo_t *pRdmaIo ); +static +BOOLEAN +_data_recv_to_ndis_pkt( + Data_t *pData, + RdmaDest_t *pRdmaDest ); + +static void +_data_allocBuffers( + Data_t *pData, + BOOLEAN initialAllocation ); + +static void +_data_addFreeBuffer( + Data_t *pData, + int index, + RdmaDest_t *pRdmaDest ); + +static uint32_t +_data_incomingRecv( + Data_t *pData ); + +static void +_data_sendFreeRecvBuffers( + Data_t *pData ); + +static uint8_t +_tx_chksum_flags( + IN NDIS_PACKET* const p_packet ); + +static void +_data_return_recv( + IN NDIS_PACKET *p_packet ); + +static void +_data_kickTimer_start( + IN Data_t *pData, + IN uint32_t microseconds ); + +static void +_data_kickTimer_stop( + IN Data_t *pData ); + +#define INBOUND_COPY + +#ifdef VNIC_STATISTIC +int64_t recvRef; +#endif /* VNIC_STATISTIC */ + +void +data_construct( + IN Data_t *pData, + IN viport_t *pViport ) +{ + VNIC_ENTER( VNIC_DBG_DATA ); + + RtlZeroMemory( pData, sizeof(*pData) ); + + pData->p_viport = pViport; + pData->p_phy_region = &pViport->p_adapter->ca.region; + InitializeListHead( &pData->recvIos ); + KeInitializeSpinLock( &pData->recvListLock ); + NdisAllocateSpinLock( &pData->recvIosLock ); + NdisAllocateSpinLock( &pData->xmitBufLock ); + cl_timer_construct( &pData->kickTimer ); + + ibqp_construct( &pData->qp, pViport ); + + VNIC_EXIT( VNIC_DBG_DATA ); +} + + +ib_api_status_t +data_init( + IN Data_t *pData, + IN DataConfig_t *p_conf, + IN uint64_t guid ) +{ + ib_api_status_t ib_status; + + VNIC_ENTER( VNIC_DBG_DATA ); + + ASSERT( pData->p_viport != NULL ); + pData->p_conf = p_conf; + + cl_timer_init( &pData->kickTimer, _data_kickTimeoutHandler, pData ); + + ib_status = ibqp_init(&pData->qp, guid, &p_conf->ibConfig ); + if( ib_status != IB_SUCCESS ) + VNIC_TRACE( VNIC_DBG_ERROR, ("data ibqp_init failed\n") ); + + VNIC_EXIT( VNIC_DBG_DATA ); + return ib_status; +} + + +ib_api_status_t +data_connect( + IN Data_t *pData ) +{ + NDIS_STATUS status; + ib_api_status_t ib_status; + XmitPool_t *pXmitPool = &pData->xmitPool; + RecvPool_t *pRecvPool = &pData->recvPool; + RecvIo_t *pRecvIo; + SendIo_t *pSendIo; + RdmaIo_t *pRdmaIo; + RdmaDest_t *pRdmaDest; + uint8_t *pRegionData; + int sz, regionSz; + unsigned int i, j; + + VNIC_ENTER( VNIC_DBG_DATA ); + + pRecvPool->poolSz = pData->p_conf->hostRecvPoolEntries; + pRecvPool->eiocPoolSz = pData->hostPoolParms.numRecvPoolEntries; + + if ( pRecvPool->poolSz > pRecvPool->eiocPoolSz ) + { + pRecvPool->poolSz = pData->hostPoolParms.numRecvPoolEntries; + } + pRecvPool->szFreeBundle = + pData->hostPoolParms.freeRecvPoolEntriesPerUpdate; + pRecvPool->numFreeBufs = 0; + pRecvPool->numPostedBufs = 0; + pRecvPool->nextFullBuf = 0; + pRecvPool->nextFreeBuf = 0; + pRecvPool->kickOnFree = FALSE; + pRecvPool->bufferSz = pData->hostPoolParms.sizeRecvPoolEntry; + + pXmitPool->bufferSz = pData->eiocPoolParms.sizeRecvPoolEntry; + pXmitPool->poolSz = pData->eiocPoolParms.numRecvPoolEntries; + pXmitPool->notifyCount = 0; + pXmitPool->notifyBundle = pData->p_conf->notifyBundle; + pXmitPool->nextXmitPool = 0; + +#if LIMIT_OUTSTANDING_SENDS + pXmitPool->numXmitBufs = pXmitPool->notifyBundle * 2; +#else /* !LIMIT_OUTSTANDING_SENDS */ + pXmitPool->numXmitBufs = pXmitPool->poolSz; +#endif /* LIMIT_OUTSTANDING_SENDS */ + + pXmitPool->nextXmitBuf = 0; + pXmitPool->lastCompBuf = pXmitPool->numXmitBufs - 1; + pXmitPool->kickCount = 0; + pXmitPool->kickByteCount = 0; + pXmitPool->sendKicks = + (BOOLEAN)(( pData->eiocPoolParms.numRecvPoolEntriesBeforeKick != 0 ) + || ( pData->eiocPoolParms.numRecvPoolBytesBeforeKick != 0 )); + pXmitPool->kickBundle = + pData->eiocPoolParms.numRecvPoolEntriesBeforeKick; + pXmitPool->kickByteBundle = + pData->eiocPoolParms.numRecvPoolBytesBeforeKick; + pXmitPool->needBuffers = TRUE; + + sz = sizeof(RdmaDest_t) * pRecvPool->poolSz; + sz += sizeof(RecvIo_t) * pData->p_conf->numRecvs; + sz += sizeof(RdmaIo_t) * pXmitPool->numXmitBufs; + + regionSz = 4 * pData->p_conf->numRecvs; + regionSz += sizeof(BufferPoolEntry_t) * pRecvPool->eiocPoolSz; + regionSz += sizeof(BufferPoolEntry_t) * pXmitPool->poolSz; + sz += regionSz; + + status = NdisAllocateMemoryWithTag( &pData->pLocalStorage, + (UINT)sz, + 'grtS' ); + if ( status != NDIS_STATUS_SUCCESS ) + { + VNIC_TRACE_EXIT( VNIC_DBG_ERROR, + ("Failed allocating %d bytes local storage\n", sz ) ); + ib_status = IB_INSUFFICIENT_MEMORY; + goto err1; + } + + NdisZeroMemory( pData->pLocalStorage, sz ); + pData->localStorageSz = sz; + + pRecvPool->pRecvBufs = (RdmaDest_t *)pData->pLocalStorage; + sz = sizeof(RdmaDest_t) * pRecvPool->poolSz; + pRecvIo = (RecvIo_t *)(pData->pLocalStorage + sz); + sz += sizeof(RecvIo_t) * pData->p_conf->numRecvs; + + pXmitPool->pXmitBufs = (RdmaIo_t *)(pData->pLocalStorage + sz); + sz += sizeof(RdmaIo_t) * pXmitPool->numXmitBufs; + + pRegionData = pData->pLocalStorage + sz; + sz += 4 * pData->p_conf->numRecvs; + + pRecvPool->bufPool = (BufferPoolEntry_t *)(pData->pLocalStorage + sz); + sz += sizeof(BufferPoolEntry_t) * pRecvPool->eiocPoolSz; + pXmitPool->bufPool = (BufferPoolEntry_t *)(pData->pLocalStorage + sz); + + ib_status = ibregion_init( pData->p_viport, &pData->region, + pData->p_viport->p_adapter->ca.hPd, pRegionData, regionSz, + ( IB_AC_LOCAL_WRITE | IB_AC_RDMA_WRITE ) ); + if( ib_status != IB_SUCCESS ) + { + VNIC_TRACE_EXIT( VNIC_DBG_ERROR, ("ib_region_init failed\n") ); + goto err2; + } + + pRdmaIo = &pData->freeBufsIo; + pRdmaIo->io.pViport = pData->p_viport; + pRdmaIo->io.pRoutine = NULL; + pRdmaIo->io.wrq.p_next = NULL; + pRdmaIo->io.wrq.wr_type = WR_RDMA_WRITE; + pRdmaIo->io.wrq.wr_id = (ULONG_PTR)pRdmaIo; + pRdmaIo->io.wrq.num_ds = 1; + pRdmaIo->io.wrq.ds_array = pRdmaIo->dsList; + pRdmaIo->dsList[0].lkey = pData->region.lkey; + pRdmaIo->io.wrq.send_opt = IB_SEND_OPT_SIGNALED; + + pSendIo = &pData->kickIo; + pSendIo->io.pViport = pData->p_viport; + pSendIo->io.pRoutine = NULL; + pSendIo->io.wrq.p_next = NULL; + pSendIo->io.wrq.wr_type = WR_SEND; + pSendIo->io.wrq.wr_id = (ULONG_PTR)pSendIo; + pSendIo->io.wrq.num_ds = 1; + pSendIo->io.wrq.ds_array = &pSendIo->dsList; + + pSendIo->io.wrq.send_opt = IB_SEND_OPT_SIGNALED; + + pSendIo->dsList.length = 0; + pSendIo->dsList.vaddr = (ULONG_PTR)pRegionData; + pSendIo->dsList.lkey = pData->region.lkey; + + for ( i = 0; i < pData->p_conf->numRecvs; i++ ) + { + pRecvIo[i].io.pViport = pData->p_viport; + pRecvIo[i].io.pRoutine = _data_receivedKick; + pRecvIo[i].io.r_wrq.wr_id = (ULONG_PTR)&pRecvIo[i].io; + pRecvIo[i].io.r_wrq.p_next = NULL; + pRecvIo[i].io.r_wrq.num_ds = 1; + pRecvIo[i].io.r_wrq.ds_array = &pRecvIo[i].dsList; + pRecvIo[i].dsList.length = 4; + pRecvIo[i].dsList.vaddr = (ULONG_PTR)pRegionData; + pRecvIo[i].dsList.lkey = pData->region.lkey; + + InitializeListHead( &pRecvIo[i].io.listPtrs ); + ExInterlockedInsertTailList( &pData->recvIos, &pRecvIo[i].io.listPtrs, &pData->recvListLock ); + /* Do not need to move pointer since the receive info + * is not read. Note, we could reduce the amount + * of memory allocated and the size of the region. + * pRegionData += 4; + * */ + } + + sz = pRecvPool->poolSz * pRecvPool->bufferSz; + status = NdisAllocateMemoryWithTag(&pData->p_recv_bufs, + sz, 'fubr'); + if( status != NDIS_STATUS_SUCCESS ) + { + VNIC_TRACE_EXIT( VNIC_DBG_ERROR, + ("Allocate recv buffers failed\n")); + ib_status = IB_INSUFFICIENT_MEMORY; + goto err3; + } + NdisZeroMemory( pData->p_recv_bufs, sz ); + + pData->recv_bufs_sz = sz; + + ib_status = ibregion_init( pData->p_viport, &pData->rbuf_region, + pData->p_viport->p_adapter->ca.hPd, pData->p_recv_bufs, sz, + (IB_AC_LOCAL_WRITE | IB_AC_RDMA_WRITE) ); + if( ib_status != IB_SUCCESS ) + { + goto err4; + } + + NdisAllocatePacketPool( &status, + &pData->h_recv_pkt_pool, + pRecvPool->poolSz, + PROTOCOL_RESERVED_SIZE_IN_PACKET ); + + if( status != NDIS_STATUS_SUCCESS ) + { + VNIC_TRACE_EXIT( VNIC_DBG_ERROR, + ("Allocate packet pool failed status %#x\n", status )); + ib_status = IB_INSUFFICIENT_MEMORY; + goto err5; + } + + NdisAllocateBufferPool( + &status, &pData->h_recv_buf_pool, pRecvPool->poolSz ); + + if( status != NDIS_STATUS_SUCCESS ) + { + VNIC_TRACE_EXIT( VNIC_DBG_ERROR, + ("Allocate packet pool failed status %#x\n", status )); + ib_status = IB_INSUFFICIENT_MEMORY; + goto err6; + } + pData->recvPool.recv_pkt_array = + cl_zalloc( sizeof(NDIS_PACKET*)* pRecvPool->poolSz ); + if( !pData->recvPool.recv_pkt_array ) + { + VNIC_TRACE_EXIT( VNIC_DBG_ERROR, + ("Allocate packet array failed\n" ) ); + ib_status = IB_INSUFFICIENT_MEMORY; + goto err7; + } + + InitializeListHead( &pRecvPool->availRecvBufs ); + + for ( i = 0; i < pRecvPool->poolSz; i++ ) + { + pRdmaDest = &pRecvPool->pRecvBufs[i]; + pRdmaDest->p_viport = pData->p_viport; + pRdmaDest->data = pData->p_recv_bufs + (i * pRecvPool->bufferSz ); + pRdmaDest->region = pData->rbuf_region; + InsertTailList( &pRecvPool->availRecvBufs, &pRdmaDest->listPtrs ); + } + + for ( i = 0; i < pXmitPool->numXmitBufs; i++ ) + { + pRdmaIo = &pXmitPool->pXmitBufs[i]; + pRdmaIo->index = (uint16_t)i; + pRdmaIo->io.pViport = pData->p_viport; + pRdmaIo->io.pRoutine = _data_xmitComplete; + pRdmaIo->io.wrq.p_next = NULL; + pRdmaIo->io.wrq.wr_type = WR_RDMA_WRITE; + pRdmaIo->io.wrq.wr_id = (ULONG_PTR)pRdmaIo; + pRdmaIo->io.wrq.num_ds = MAX_NUM_SGE; // will set actual number when transmit + pRdmaIo->io.wrq.ds_array = pRdmaIo->dsList; + pRdmaIo->p_trailer = (ViportTrailer_t *)&pRdmaIo->data[0]; + for( j = 0; j < MAX_NUM_SGE; j++ ) + { + pRdmaIo->dsList[j].lkey = pData->p_phy_region->lkey; + } + } + + pXmitPool->rdmaRKey = pData->region.rkey; + pXmitPool->rdmaAddr = (ULONG_PTR)pXmitPool->bufPool; + + data_postRecvs( pData ); + + ib_status = ibqp_connect( &pData->qp ); + if( ib_status != IB_SUCCESS ) + { + VNIC_TRACE( VNIC_DBG_ERROR, ("ibqp_connect returned %s\n", + pData->p_viport->p_adapter->ifc.get_err_str( ib_status )) ); +err7: + NdisFreeBufferPool( pData->h_recv_buf_pool ); + pData->h_recv_buf_pool = NULL; +err6: + NdisFreePacketPool( pData->h_recv_pkt_pool ); + pData->h_recv_pkt_pool = NULL; +err5: + ibregion_cleanup( pData->p_viport, &pData->rbuf_region ); +err4: + NdisFreeMemory( pData->p_recv_bufs, pData->recv_bufs_sz, 0 ); + pData->p_recv_bufs = NULL; +err3: + ibregion_cleanup(pData->p_viport, &pData->region ); +err2: + NdisFreeMemory( pData->pLocalStorage, pData->localStorageSz, 0 ); + pData->pLocalStorage = NULL; +err1: + pRecvPool->poolSz = 0; + } + + VNIC_EXIT( VNIC_DBG_DATA ); + return ib_status; +} + + +ib_api_status_t +data_connected( + IN Data_t *pData ) +{ + VNIC_ENTER( VNIC_DBG_DATA ); + + pData->freeBufsIo.io.wrq.remote_ops.rkey = + pData->recvPool.eiocRdmaRkey; + + _data_allocBuffers(pData, TRUE); + _data_sendFreeRecvBuffers(pData); + + if( pData->p_viport->errored ) + { + return IB_ERROR; + } + + pData->connected = TRUE; + + VNIC_EXIT( VNIC_DBG_DATA ); + return IB_SUCCESS; +} + +void +data_disconnect( + IN Data_t *pData ) +{ + RecvPool_t *pRecvPool = &pData->recvPool; + viport_t *p_viport = pData->p_viport; + NDIS_PACKET *p_packet; + NDIS_BUFFER *p_buf; + unsigned int i; + + VNIC_ENTER( VNIC_DBG_DATA ); + + _data_kickTimer_stop ( pData ); + + pData->connected = FALSE; + + ibqp_detach( &pData->qp ); + + ibregion_cleanup( p_viport, &pData->rbuf_region ); + ibregion_cleanup( p_viport, &pData->region ); + + for ( i = 0; i < pRecvPool->poolSz; i++ ) + { + p_packet = pRecvPool->pRecvBufs[i].p_packet; + if ( p_packet != NULL ) + { + pRecvPool->pRecvBufs[i].p_packet = NULL; + NdisUnchainBufferAtFront( p_packet, &p_buf ); + if( p_buf ) + { + /* Return the NDIS packet and NDIS buffer to their pools. */ + NdisFreeBuffer( p_buf ); + } + NdisFreePacket( p_packet ); + } + } + + VNIC_EXIT( VNIC_DBG_DATA ); + return; +} + +BOOLEAN +data_xmitPacket( + IN Data_t *pData, + IN NDIS_PACKET* const p_packet ) +{ + XmitPool_t *p_xmitPool; + RdmaIo_t *pRdmaIo; + BufferPoolEntry_t *pBpe; + BOOLEAN last; + uint8_t *p_buf; + uint32_t buf_len; + uint32_t pkt_size; + NDIS_BUFFER *p_buf_desc; + eth_hdr_t* p_eth_hdr; + int pad; + SCATTER_GATHER_LIST *p_sgl; + uint32_t i; + PHYSICAL_ADDRESS phy_addr; + NDIS_PACKET_8021Q_INFO vlanInfo; + net16_t pri_vlan = 0; + + VNIC_ENTER( VNIC_DBG_DATA ); + + p_sgl = NDIS_PER_PACKET_INFO_FROM_PACKET( p_packet, + ScatterGatherListPacketInfo ); + if ( p_sgl == NULL ) + { + return FALSE; + } + + NdisGetFirstBufferFromPacketSafe( p_packet, + &p_buf_desc, + &p_buf, + &buf_len, + &pkt_size, + NormalPagePriority ); + + if( pkt_size > pData->xmitPool.bufferSz ) + { + VNIC_TRACE_EXIT( VNIC_DBG_ERROR, + ("Outbound packet too large, size = %d\n", pkt_size ) ); + return FALSE; + } + + if ( p_sgl->NumberOfElements > (ULONG)MAX_NUM_SGE - 1 ) + { + VNIC_TRACE( VNIC_DBG_DATA, + (" Xmit packet exceeded SGE limit - %d\n", + p_sgl->NumberOfElements ) ); + return FALSE; + } + + vlanInfo.Value = NDIS_PER_PACKET_INFO_FROM_PACKET( p_packet, Ieee8021QInfo ); + p_eth_hdr = (eth_hdr_t *)p_buf; + + if( vlanInfo.Value ) /* there is VLAN_ID specified the packet */ + { + if( vlanInfo.TagHeader.VlanId != 0 ) + { + /* packet vlanId does not match */ + if( pData->p_viport->p_adapter->vlan_info && + ( pData->p_viport->p_adapter->vlan_info & 0x00000fff ) != vlanInfo.TagHeader.VlanId ) + { + return FALSE; + } + pri_vlan = (uint16_t)vlanInfo.TagHeader.VlanId; + pri_vlan |= (uint16_t)( vlanInfo.TagHeader.UserPriority << 13 ); + } + else if( pData->p_viport->p_adapter->vlan_info ) + { + pri_vlan = (uint16_t)( pData->p_viport->p_adapter->vlan_info ); + } + } + else /* no VLAN_ID info in a packet */ + { + if( pData->p_viport->p_adapter->vlan_info ) + { + pri_vlan = (uint16_t)( pData->p_viport->p_adapter->vlan_info ); + } + } + + if( !data_allocXmitBuffer( pData, &pBpe, &pRdmaIo, &last ) ) + { + return FALSE; + } + + pRdmaIo->p_packet = p_packet; + pRdmaIo->packet_sz = pkt_size; + + pRdmaIo->len = (uint32_t)ROUNDUPP2( + max(MIN_PACKET_LEN, pRdmaIo->packet_sz), VIPORT_TRAILER_ALIGNMENT ); + pad = pRdmaIo->len - pRdmaIo->packet_sz; + + pRdmaIo->p_trailer = (ViportTrailer_t *)&pRdmaIo->data[pad]; + + cl_memclr( pRdmaIo->data, pad + sizeof( ViportTrailer_t ) ); + cl_memcpy( pRdmaIo->p_trailer->destMacAddr, p_eth_hdr->dst.addr, MAC_ADDR_LEN ); + + pRdmaIo->p_trailer->dataLength = + cl_hton16( (uint16_t)max( MIN_PACKET_LEN, pRdmaIo->packet_sz ) ); + + if( pri_vlan ) + { + /* if tagged frame */ + if( *(uint16_t *)(p_buf + 12 ) == ETH_PROT_VLAN_TAG ) + { + /* strip vlan tag from header */ + RtlMoveMemory( p_buf + 4, p_buf, 12 ); + /* adjust data length */ + pRdmaIo->p_trailer->dataLength = + cl_hton16( (uint16_t)max( MIN_PACKET_LEN, pRdmaIo->packet_sz ) - 4 ); + } + pRdmaIo->p_trailer->vLan = cl_hton16( pri_vlan ); + pRdmaIo->p_trailer->pktFlags |= PF_VLAN_INSERT; + } + + for( i=0; i < p_sgl->NumberOfElements; i++ ) + { + pRdmaIo->dsList[i].vaddr = p_sgl->Elements[i].Address.QuadPart; + pRdmaIo->dsList[i].length = p_sgl->Elements[i].Length; + } + if( viport_canTxCsum( pData->p_viport ) && + pData->p_viport->p_adapter->params.UseTxCsum ) + { + pRdmaIo->p_trailer->txChksumFlags = _tx_chksum_flags( p_packet ); + } + else + { + pRdmaIo->p_trailer->txChksumFlags = 0; + } + pRdmaIo->p_trailer->connectionHashAndValid = CHV_VALID; + + if( last || pData->xmitPool.needBuffers ) + pRdmaIo->p_trailer->pktFlags |= PF_KICK; + + /* fill last data segment with trailer and pad */ + phy_addr = MmGetPhysicalAddress( pRdmaIo->data ); + + pRdmaIo->dsList[p_sgl->NumberOfElements].vaddr = phy_addr.QuadPart; + pRdmaIo->dsList[p_sgl->NumberOfElements].length = pRdmaIo->len - + pRdmaIo->packet_sz + + sizeof( ViportTrailer_t ); + + pRdmaIo->io.wrq.num_ds =p_sgl->NumberOfElements + 1; + + if( data_rdmaPacket( pData, pBpe, pRdmaIo ) != IB_SUCCESS ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + ("RDMA WRITE Failed\n")); + return FALSE; + } + p_xmitPool = &pData->xmitPool; + if( p_xmitPool->sendKicks ) + { + /* EIOC needs kicks to inform it of sent packets */ + + p_xmitPool->kickCount++; + p_xmitPool->kickByteCount += pRdmaIo->packet_sz; + if( ( p_xmitPool->kickCount >= p_xmitPool->kickBundle ) + || ( p_xmitPool->kickByteCount >= p_xmitPool->kickByteBundle ) ) + { + data_sendKickMessage( pData ); + } + else if( p_xmitPool->kickCount == 1 ) + { + _data_kickTimer_start( pData, pData->eiocPoolParms.timeoutBeforeKick ); + } + } + return TRUE; +} + +static uint8_t +_tx_chksum_flags( + IN NDIS_PACKET* const p_packet ) + +{ + NDIS_TCP_IP_CHECKSUM_PACKET_INFO *p_packet_info; + ULONG packet_info; + uint8_t txChksumFlags = 0; + + if( NDIS_PROTOCOL_ID_TCP_IP == NDIS_GET_PACKET_PROTOCOL_TYPE(p_packet) ) + { + packet_info = PtrToUlong( NDIS_PER_PACKET_INFO_FROM_PACKET( p_packet, TcpIpChecksumPacketInfo)); + p_packet_info = ( NDIS_TCP_IP_CHECKSUM_PACKET_INFO *)&packet_info; + + if( p_packet_info ) + { + if( p_packet_info->Transmit.NdisPacketChecksumV4 ) + { + txChksumFlags = TX_CHKSUM_FLAGS_CHECKSUM_V4 + | ( p_packet_info->Transmit.NdisPacketIpChecksum ? TX_CHKSUM_FLAGS_IP_CHECKSUM: 0 ) + | ( p_packet_info->Transmit.NdisPacketTcpChecksum ? TX_CHKSUM_FLAGS_TCP_CHECKSUM: 0 ) + | ( p_packet_info->Transmit.NdisPacketUdpChecksum ? TX_CHKSUM_FLAGS_UDP_CHECKSUM: 0 ); + } + else if( p_packet_info->Transmit.NdisPacketChecksumV6 ) + { + txChksumFlags = TX_CHKSUM_FLAGS_CHECKSUM_V6 + | ( p_packet_info->Transmit.NdisPacketIpChecksum ? TX_CHKSUM_FLAGS_IP_CHECKSUM: 0 ) + | ( p_packet_info->Transmit.NdisPacketTcpChecksum ? TX_CHKSUM_FLAGS_TCP_CHECKSUM: 0 ) + | ( p_packet_info->Transmit.NdisPacketUdpChecksum ? TX_CHKSUM_FLAGS_UDP_CHECKSUM: 0 ); + } + } + } + + VNIC_TRACE( VNIC_DBG_DATA , + ("txChksumFlags = %#x: V4 %c, V6 %c, IP %c, TCP %c, UDP %c\n", + txChksumFlags, + ((txChksumFlags & TX_CHKSUM_FLAGS_CHECKSUM_V4 )? '+': '-'), + ((txChksumFlags & TX_CHKSUM_FLAGS_CHECKSUM_V6 )? '+': '-'), + ((txChksumFlags & TX_CHKSUM_FLAGS_IP_CHECKSUM )? '+': '-'), + ((txChksumFlags & TX_CHKSUM_FLAGS_TCP_CHECKSUM )? '+': '-'), + ((txChksumFlags & TX_CHKSUM_FLAGS_UDP_CHECKSUM )? '+': '-') )); + + return txChksumFlags; +} + +static void +data_postRecvs( + IN Data_t *pData ) +{ + RecvIo_t *pRecvIo; + LIST_ENTRY *p_list_entry; + ib_api_status_t ib_status; + + VNIC_ENTER ( VNIC_DBG_DATA ); + + if( pData->p_viport->errored ) + return; + + while( ( p_list_entry = ExInterlockedRemoveHeadList( &pData->recvIos, &pData->recvListLock ) ) != NULL ) + { + pRecvIo = (RecvIo_t *)p_list_entry; + + ib_status = ibqp_postRecv( &pData->qp, &pRecvIo->io ); + if( ib_status != IB_SUCCESS ) + { + VNIC_TRACE_EXIT( VNIC_DBG_ERROR, ("ibqp_postRecv returned %s\n", + pData->p_viport->p_adapter->ifc.get_err_str( ib_status )) ); + viport_failure( pData->p_viport ); + return; + } + } + + VNIC_EXIT( VNIC_DBG_DATA ); + return; +} + +static void +_data_receivedKick( + IN Io_t *pIo ) +{ + + uint32_t num_pkts = 0; + + VNIC_ENTER( VNIC_DBG_DATA ); + + NdisAcquireSpinLock( &pIo->pViport->data.recvIosLock ); + +#ifdef VNIC_STATISTIC + recvRef = cl_get_tick_count(); +#endif /* VNIC_STATISTIC */ + + ExInterlockedInsertTailList( &pIo->pViport->data.recvIos, + &pIo->listPtrs, + &pIo->pViport->data.recvListLock ); + + data_postRecvs( &pIo->pViport->data ); + +#ifdef VNIC_STATISTIC + pIo->pViport->data.statistics.kickRecvs++; +#endif /* VNIC_STATISTIC */ + + data_checkXmitBuffers( &pIo->pViport->data ); + + num_pkts = _data_incomingRecv( &pIo->pViport->data ); + + NdisReleaseSpinLock(&pIo->pViport->data.recvIosLock ); + + if( num_pkts ) + { + viport_recvPacket( pIo->pViport, + pIo->pViport->data.recvPool.recv_pkt_array, + num_pkts ); + + pIo->pViport->stats.ifInOk += num_pkts; + } + + VNIC_EXIT( VNIC_DBG_DATA ); + return; +} + +static void +_data_xmitComplete( + IN Io_t *pIo ) +{ + + Data_t *pData; + XmitPool_t *p_xmitPool; + NDIS_PACKET *p_packet; + NDIS_STATUS ndis_status; + uint32_t io_index; + + VNIC_ENTER( VNIC_DBG_DATA ); + + NdisAcquireSpinLock( &pIo->pViport->data.xmitBufLock ); + + io_index = ((RdmaIo_t *)pIo)->index; + pData = &pIo->pViport->data; + p_xmitPool = &pData->xmitPool; + + while ( p_xmitPool->lastCompBuf != io_index ) + { + INC(p_xmitPool->lastCompBuf, 1, p_xmitPool->numXmitBufs); + + p_packet = p_xmitPool->pXmitBufs[p_xmitPool->lastCompBuf].p_packet; + + p_xmitPool->pXmitBufs[p_xmitPool->lastCompBuf].p_packet = NULL; + + if( p_packet != NULL ) + { + if( pIo->wc_status != IB_WCS_SUCCESS ) + { + ndis_status = NDIS_STATUS_FAILURE; + pIo->pViport->stats.ifOutErrors++; + pIo->wc_status = IB_WCS_SUCCESS; + } + else + { + ndis_status = NDIS_STATUS_SUCCESS; + pIo->pViport->stats.ifOutOk++; + } + NDIS_SET_PACKET_STATUS( p_packet, ndis_status ); + NdisMSendComplete( pIo->pViport->p_adapter->h_handle, + p_packet, ndis_status ); + } + } + NdisReleaseSpinLock( &pData->xmitBufLock ); + + if( !pData->p_viport->errored ) + { + data_checkXmitBuffers( pData ); + } + VNIC_EXIT( VNIC_DBG_DATA ); + return; +} + +static void +data_sendKickMessage( + IN Data_t *pData ) +{ + XmitPool_t *pPool = &pData->xmitPool; + + VNIC_ENTER( VNIC_DBG_DATA ); + + /* stop timer for BundleTimeout */ + _data_kickTimer_stop( pData ); + + pPool->kickCount = 0; + pPool->kickByteCount = 0; + + /* TBD: Keep track of when kick is outstanding, and + * don't reuse until complete + */ + if ( ibqp_postSend( &pData->qp, &pData->kickIo.io ) != IB_SUCCESS ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + ("Unable to send kick to EIOC\n") ); + viport_failure( pData->p_viport ); + } + + VNIC_EXIT( VNIC_DBG_DATA ); +} + +static void +_data_kickTimeoutHandler( void * context ) +{ + Data_t* pData = (Data_t *)context; + + VNIC_ENTER( VNIC_DBG_DATA ); + + InterlockedExchange( &pData->kickTimerOn, FALSE ); + data_sendKickMessage( pData ); + + VNIC_EXIT( VNIC_DBG_DATA ); + + return; +} + +static BOOLEAN +data_allocXmitBuffer( + IN Data_t *pData, + OUT BufferPoolEntry_t **ppBpe, + OUT RdmaIo_t **ppRdmaIo, + OUT BOOLEAN *pLast ) +{ + XmitPool_t *p_xmitPool; + + VNIC_ENTER( VNIC_DBG_DATA ); + + NdisAcquireSpinLock( &pData->xmitBufLock ); + + p_xmitPool = &pData->xmitPool; + *pLast = FALSE; + *ppRdmaIo = &p_xmitPool->pXmitBufs[p_xmitPool->nextXmitBuf]; + *ppBpe = &p_xmitPool->bufPool[p_xmitPool->nextXmitPool]; + + if ( (*ppBpe)->valid && p_xmitPool->nextXmitBuf != p_xmitPool->lastCompBuf ) + { + INC(p_xmitPool->nextXmitBuf, 1, p_xmitPool->numXmitBufs); + INC(p_xmitPool->nextXmitPool, 1, p_xmitPool->poolSz); + + if ( !p_xmitPool->bufPool[p_xmitPool->nextXmitPool].valid ) + { + VNIC_TRACE( VNIC_DBG_DATA, + ("Just used the last EIOU receive buffer\n") ); + + *pLast = TRUE; + p_xmitPool->needBuffers = TRUE; + viport_stopXmit( pData->p_viport ); +#ifdef VNIC_STATISTIC + pData->statistics.kickReqs++; +#endif /* VNIC_STATISTIC */ + } + else if ( p_xmitPool->nextXmitBuf == p_xmitPool->lastCompBuf ) + { + VNIC_TRACE( VNIC_DBG_DATA, + ("Just used our last xmit buffer\n") ); + + p_xmitPool->needBuffers = TRUE; + viport_stopXmit( pData->p_viport ); + } + + (*ppBpe)->valid = 0; + + NdisReleaseSpinLock( &pData->xmitBufLock ); + return TRUE; + } + else + { +#ifdef VNIC_STATISTIC + pData->statistics.noXmitBufs++; +#endif /* VNIC_STATISTIC */ + + VNIC_TRACE( VNIC_DBG_ERROR, + ("Out of xmit buffers\n") ); + + p_xmitPool->needBuffers = TRUE; + viport_stopXmit( pData->p_viport ); + + NdisReleaseSpinLock( &pData->xmitBufLock ); + return FALSE; + } +} + +static void +data_checkXmitBuffers( + IN Data_t *pData ) +{ + VNIC_ENTER( VNIC_DBG_DATA ); + + NdisAcquireSpinLock( &pData->xmitBufLock ); + + if ( pData->xmitPool.needBuffers + && pData->xmitPool.bufPool[pData->xmitPool.nextXmitPool].valid + && pData->xmitPool.nextXmitBuf != pData->xmitPool.lastCompBuf ) + { + pData->xmitPool.needBuffers = FALSE; + viport_restartXmit( pData->p_viport ); + + VNIC_TRACE( VNIC_DBG_DATA, + ("There are free xmit buffers\n") ); + } + + NdisReleaseSpinLock( &pData->xmitBufLock ); + + VNIC_EXIT( VNIC_DBG_DATA ); + return; +} + +static +ib_api_status_t +data_rdmaPacket( + IN Data_t *pData, + IN BufferPoolEntry_t *pBpe, + IN RdmaIo_t *pRdmaIo ) +{ + ib_send_wr_t *pWrq; + uint64_t remote_addr; + + VNIC_ENTER( VNIC_DBG_DATA ); + + pWrq = &pRdmaIo->io.wrq; + + remote_addr = ntoh64( pBpe->remoteAddr ); + remote_addr += pData->xmitPool.bufferSz; + remote_addr -= ( pRdmaIo->len + sizeof(ViportTrailer_t) ); + + pWrq->remote_ops.vaddr = remote_addr; + pWrq->remote_ops.rkey = pBpe->rKey; + + pData->xmitPool.notifyCount++; + + if( pData->xmitPool.notifyCount >= pData->xmitPool.notifyBundle ) + { + pData->xmitPool.notifyCount = 0; + pWrq->send_opt = IB_SEND_OPT_SIGNALED; + } + else + { + pWrq->send_opt &= ~IB_SEND_OPT_SIGNALED; + } + pWrq->send_opt = IB_SEND_OPT_SIGNALED; + + if( pData->p_viport->featuresSupported & INIC_FEAT_RDMA_IMMED ) + { + pWrq->send_opt |= IB_SEND_OPT_IMMEDIATE; + pWrq->immediate_data = 0; + } + + if( ibqp_postSend( &pData->qp, &pRdmaIo->io ) != IB_SUCCESS ) + { + VNIC_TRACE(VNIC_DBG_ERROR, + ("Failed sending data to EIOC\n") ); + return IB_ERROR; + } +#ifdef VNIC_STATISTIC + pData->statistics.xmitNum++; +#endif /* VNIC_STATISTIC */ + + VNIC_EXIT( VNIC_DBG_DATA ); + return IB_SUCCESS; +} + +static BOOLEAN +_data_recv_to_ndis_pkt( + IN Data_t *pData, + IN RdmaDest_t *pRdmaDest ) +{ + struct ViportTrailer *pTrailer; + NDIS_PACKET *p_packet; + NDIS_STATUS ndis_status; + int start; + unsigned int len; + NDIS_TCP_IP_CHECKSUM_PACKET_INFO packet_info; + NDIS_PACKET_8021Q_INFO vlan_info; + uint16_t vlanId; + uint8_t rxChksumFlags; + + VNIC_ENTER( VNIC_DBG_DATA ); + + pTrailer = pRdmaDest->pTrailer; + p_packet = pRdmaDest->p_packet; + + start = (int)data_offset(pData, pTrailer); + len = data_len(pData, pTrailer); + + NdisAllocateBuffer( &ndis_status, + &pRdmaDest->p_buf, + pData->h_recv_buf_pool, + pRdmaDest->data + start, + len ); + + if ( ndis_status != NDIS_STATUS_SUCCESS ) + { + VNIC_TRACE_EXIT( VNIC_DBG_ERROR, + ( "NdisAllocateBuffer failed %#x\n", ndis_status ) ); + return FALSE; + } + + NdisChainBufferAtFront( p_packet, pRdmaDest->p_buf ); + pRdmaDest->buf_sz = len; + + if ( pTrailer->pktFlags & PF_VLAN_INSERT && + !( pData->p_viport->featuresSupported & INIC_FEAT_IGNORE_VLAN ) ) + { + /* handle VLAN tag insertion */ + vlan_info.Value = NDIS_PER_PACKET_INFO_FROM_PACKET( p_packet, Ieee8021QInfo ); + vlanId = cl_ntoh16( pTrailer->vLan ); + + if( !( vlanId & 0xfff ) || + ( ( (vlanId & 0xfff ) != 0 ) && + (vlanId & 0xfff ) == ((uint16_t)pData->p_viport->p_adapter->vlan_info & 0xfff ) )) + { + if( pTrailer->pktFlags & PF_PVID_OVERRIDDEN ) + { + vlan_info.TagHeader.VlanId = 0; + } + else + { + vlan_info.TagHeader.VlanId = vlanId & 0xfff; + } + vlan_info.TagHeader.UserPriority = vlanId & 0xe000; + vlan_info.TagHeader.CanonicalFormatId = 0; + vlan_info.TagHeader.Reserved = 0; + NDIS_PER_PACKET_INFO_FROM_PACKET( p_packet, Ieee8021QInfo ) = vlan_info.Value; + } + } + + if( viport_canRxCsum( pData->p_viport ) && + pData->p_viport->p_adapter->params.UseRxCsum ) + { + rxChksumFlags = pTrailer->rxChksumFlags; + + VNIC_TRACE( VNIC_DBG_DATA, + ("rxChksumFlags = %#x, LOOP = %c, IP = %c, TCP = %c, UDP = %c\n", + rxChksumFlags, + (rxChksumFlags & RX_CHKSUM_FLAGS_LOOPBACK)? 'Y': 'N', + (rxChksumFlags & RX_CHKSUM_FLAGS_IP_CHECKSUM_SUCCEEDED)? 'Y': + (rxChksumFlags & RX_CHKSUM_FLAGS_IP_CHECKSUM_FAILED)? 'N': '-', + (rxChksumFlags & RX_CHKSUM_FLAGS_TCP_CHECKSUM_SUCCEEDED)? 'Y': + (rxChksumFlags & RX_CHKSUM_FLAGS_TCP_CHECKSUM_FAILED)? 'N': '-', + (rxChksumFlags & RX_CHKSUM_FLAGS_UDP_CHECKSUM_SUCCEEDED)? 'Y': + (rxChksumFlags & RX_CHKSUM_FLAGS_UDP_CHECKSUM_FAILED)? 'N': '-') ); + + packet_info.Value = 0; + + if( rxChksumFlags & RX_CHKSUM_FLAGS_IP_CHECKSUM_SUCCEEDED ) + packet_info.Receive.NdisPacketIpChecksumSucceeded = TRUE; + else if( rxChksumFlags & RX_CHKSUM_FLAGS_IP_CHECKSUM_FAILED ) + packet_info.Receive.NdisPacketIpChecksumFailed = TRUE; + + if( rxChksumFlags & RX_CHKSUM_FLAGS_TCP_CHECKSUM_SUCCEEDED ) + packet_info.Receive.NdisPacketTcpChecksumSucceeded = TRUE; + else if( rxChksumFlags & RX_CHKSUM_FLAGS_TCP_CHECKSUM_FAILED ) + packet_info.Receive.NdisPacketTcpChecksumFailed = TRUE; + + if( rxChksumFlags & RX_CHKSUM_FLAGS_TCP_CHECKSUM_SUCCEEDED ) + packet_info.Receive.NdisPacketUdpChecksumSucceeded = TRUE; + else if( rxChksumFlags & RX_CHKSUM_FLAGS_TCP_CHECKSUM_FAILED ) + packet_info.Receive.NdisPacketUdpChecksumFailed = TRUE; + + NDIS_PER_PACKET_INFO_FROM_PACKET( p_packet, TcpIpChecksumPacketInfo )= + (void *)(uintn_t)packet_info.Value; + } + + NDIS_SET_PACKET_STATUS( p_packet, NDIS_STATUS_SUCCESS ); + NDIS_SET_PACKET_HEADER_SIZE( p_packet, sizeof(eth_hdr_t) ); + VNIC_RECV_FROM_PACKET( p_packet ) = pRdmaDest; + + VNIC_EXIT( VNIC_DBG_DATA ); + return TRUE; +} + +/* NOTE: This routine is not reentrant */ +static void +_data_allocBuffers( + IN Data_t *pData, + IN BOOLEAN initialAllocation ) +{ + NDIS_STATUS ndis_status; + RecvPool_t *p_recvPool = &pData->recvPool; + RdmaDest_t *pRdmaDest; + LIST_ENTRY *p_list_entry; + int index; + + VNIC_ENTER( VNIC_DBG_DATA ); + + index = ADD(p_recvPool->nextFreeBuf, p_recvPool->numFreeBufs, p_recvPool->eiocPoolSz); + + while ( !IsListEmpty( &p_recvPool->availRecvBufs ) ) + { + p_list_entry = RemoveHeadList( &p_recvPool->availRecvBufs ); + pRdmaDest = (RdmaDest_t*)p_list_entry; + + if( initialAllocation ) + { + pRdmaDest->buf_sz = p_recvPool->bufferSz; + pRdmaDest->pTrailer = + (struct ViportTrailer*)(pRdmaDest->data + pRdmaDest->buf_sz + - sizeof(struct ViportTrailer)); + pRdmaDest->pTrailer->connectionHashAndValid = 0; + + NdisAllocatePacket( &ndis_status, + &pRdmaDest->p_packet, + pData->h_recv_pkt_pool ); + + if ( ndis_status != NDIS_STATUS_SUCCESS ) + { + VNIC_TRACE_EXIT( VNIC_DBG_ERROR, + ( "NdisAllocatePacket failed %#x\n", ndis_status ) ); + return; + } + } + + _data_addFreeBuffer( pData, index, pRdmaDest ); + index = NEXT(index,p_recvPool->eiocPoolSz); + } + + VNIC_EXIT( VNIC_DBG_DATA ); + return; +} + +static void +_data_addFreeBuffer( + IN Data_t *pData, + IN int index, + IN RdmaDest_t *pRdmaDest ) +{ + RecvPool_t *p_recvPool = &pData->recvPool; + BufferPoolEntry_t *pBpe; + + pRdmaDest->pTrailer->connectionHashAndValid = 0; + pBpe = &p_recvPool->bufPool[index]; + + pBpe->rKey = pRdmaDest->region.rkey; + pBpe->remoteAddr = hton64( (ULONG_PTR)pRdmaDest->data ); + pBpe->valid = (uint32_t)(pRdmaDest - &p_recvPool->pRecvBufs[0]) + 1; + ++p_recvPool->numFreeBufs; + + return; +} + +static uint32_t +_data_incomingRecv( + IN Data_t *pData ) +{ + RecvPool_t *p_recvPool = &pData->recvPool; + RdmaDest_t *pRdmaDest; + ViportTrailer_t *pTrailer; + BufferPoolEntry_t *pBpe; + uint32_t idx = 0; + BOOLEAN status = FALSE; + + VNIC_ENTER( VNIC_DBG_DATA ); + + while( !status ) + { + if ( p_recvPool->nextFullBuf == p_recvPool->nextFreeBuf ) + return idx; + + pBpe = &p_recvPool->bufPool[p_recvPool->nextFullBuf]; + + CL_ASSERT(pBpe->valid != 0 ); + + pRdmaDest = &p_recvPool->pRecvBufs[pBpe->valid - 1]; + pTrailer = pRdmaDest->pTrailer; + + if ( ( pTrailer != NULL ) && + ( pTrailer->connectionHashAndValid & CHV_VALID ) ) + { + /* received a packet */ + if ( pTrailer->pktFlags & PF_KICK ) + { + p_recvPool->kickOnFree = TRUE; + } + /* we do not want to indicate packet if filter is not set */ + if( pData->p_viport->p_adapter->xmitStarted && + pData->p_viport->p_adapter->packet_filter && + p_recvPool->numPostedBufs > 0 ) + { + if ( _data_recv_to_ndis_pkt( pData, pRdmaDest ) ) + { + p_recvPool->recv_pkt_array[idx++] = pRdmaDest->p_packet; + } + } + else + { /* put back to free buffers pool */ + InsertTailList( &p_recvPool->availRecvBufs, + &pRdmaDest->listPtrs ); + } + pBpe->valid = 0; + INC( p_recvPool->nextFullBuf, 1, p_recvPool->eiocPoolSz ); + p_recvPool->numPostedBufs--; +#ifdef VNIC_STATISTIC + pData->statistics.recvNum++; +#endif /* VNIC_STATISTIC */ + } + else + break; + } + return idx; +} + + +void +vnic_return_packet( + IN NDIS_HANDLE adapter_context, + IN NDIS_PACKET * const p_packet ) +{ + + RdmaDest_t *p_rdma_dest; + viport_t *p_viport; + + VNIC_ENTER( VNIC_DBG_DATA ); + + UNREFERENCED_PARAMETER( adapter_context ); + + p_rdma_dest = VNIC_RECV_FROM_PACKET( p_packet ); + p_viport = p_rdma_dest->p_viport; + + ASSERT( p_rdma_dest->p_packet == p_packet ); + + NdisAcquireSpinLock( &p_viport->data.recvIosLock ); + + _data_return_recv( p_packet ); + + NdisReinitializePacket( p_packet ); + + InsertTailList( &p_viport->data.recvPool.availRecvBufs, + &p_rdma_dest->listPtrs ); + _data_allocBuffers( &p_viport->data, FALSE ); + _data_sendFreeRecvBuffers( &p_viport->data ); + + NdisReleaseSpinLock(&p_viport->data.recvIosLock ); + + VNIC_EXIT( VNIC_DBG_DATA ); +} +static void +_data_return_recv( + IN NDIS_PACKET *p_packet ) +{ + NDIS_BUFFER *p_buf; + PNDIS_PACKET_OOB_DATA p_oob_data; + + /* Unchain the NDIS buffer. */ + NdisUnchainBufferAtFront( p_packet, &p_buf ); + if( p_buf ) + { + /* Return the NDIS packet and NDIS buffer to their pools. */ + NdisFreeBuffer( p_buf ); + } + /* take care of OOB_DATA block since NdisReinitializePacket doesn't */ + p_oob_data = NDIS_OOB_DATA_FROM_PACKET( p_packet ); + NdisZeroMemory( p_oob_data, sizeof( NDIS_PACKET_OOB_DATA )); +} + +static void +_data_sendFreeRecvBuffers( + IN Data_t *pData ) +{ + RecvPool_t *p_recvPool = &pData->recvPool; + ib_send_wr_t *pWrq = &pData->freeBufsIo.io.wrq; + BOOLEAN bufsSent = FALSE; + uint64_t rdmaAddr; + uint32_t offset; + uint32_t sz; + unsigned int numToSend, + nextIncrement; + + VNIC_ENTER( VNIC_DBG_DATA ); + + for ( numToSend = p_recvPool->szFreeBundle; + numToSend <= p_recvPool->numFreeBufs; + numToSend += p_recvPool->szFreeBundle ) + { + + /* Handle multiple bundles as one when possible. */ + nextIncrement = numToSend + p_recvPool->szFreeBundle; + if (( nextIncrement <= p_recvPool->numFreeBufs ) + && ( p_recvPool->nextFreeBuf + nextIncrement <= p_recvPool->eiocPoolSz ) ) + { + continue; + } + + offset = p_recvPool->nextFreeBuf * sizeof(BufferPoolEntry_t); + sz = numToSend * sizeof(BufferPoolEntry_t); + rdmaAddr = p_recvPool->eiocRdmaAddr + offset; + + pWrq->ds_array->length = sz; + pWrq->ds_array->vaddr = (ULONG_PTR)((uint8_t *)p_recvPool->bufPool + offset); + pWrq->remote_ops.vaddr = rdmaAddr; + + if ( ibqp_postSend( &pData->qp, &pData->freeBufsIo.io ) != IB_SUCCESS ) + { + VNIC_TRACE(VNIC_DBG_ERROR, + ("Unable to rdma free buffers to EIOC\n") ); + + viport_failure( pData->p_viport ); + break; + } + + INC( p_recvPool->nextFreeBuf, numToSend, p_recvPool->eiocPoolSz ); + p_recvPool->numFreeBufs -= numToSend; + p_recvPool->numPostedBufs += numToSend; + bufsSent = TRUE; + } + + if( bufsSent ) + { + if( p_recvPool->kickOnFree ) + { + data_sendKickMessage( pData ); + } + } + if( p_recvPool->numPostedBufs == 0 ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + ("IOC %d: Unable to allocate receive buffers NumFreeBufs: %d nextFreeBuf: %d nextFullBuf %d eiocPoolSz: %d\n", + pData->p_viport->ioc_num, p_recvPool->numFreeBufs, + p_recvPool->nextFreeBuf, p_recvPool->nextFullBuf, + p_recvPool->eiocPoolSz ) ); + + //viport_failure( pData->p_viport ); + } + VNIC_EXIT( VNIC_DBG_DATA ); +} + + +void +data_cleanup( + IN Data_t *pData ) +{ + VNIC_ENTER( VNIC_DBG_DATA ); + + VNIC_TRACE(VNIC_DBG_DATA, + ("IOC[%d]data cleanup\n", pData->p_viport->ioc_num )); + + if( pData->p_recv_bufs ) + { + NdisFreeMemory( pData->p_recv_bufs, pData->recv_bufs_sz, 0 ); + pData->p_recv_bufs = NULL; + } + + if( pData->recvPool.recv_pkt_array ) + { + cl_free( pData->recvPool.recv_pkt_array ); + pData->recvPool.recv_pkt_array = NULL; + pData->recvPool.poolSz = 0; + } + + if ( pData->pLocalStorage ) + { + NdisFreeMemory( pData->pLocalStorage, pData->localStorageSz, 0 ); + pData->pLocalStorage = NULL; + } + + if( pData->h_recv_buf_pool ) + { + NdisFreeBufferPool( pData->h_recv_buf_pool ); + pData->h_recv_buf_pool = NULL; + } + + if ( pData->h_recv_pkt_pool ) + { + if( NdisPacketPoolUsage(pData->h_recv_pkt_pool) != 0) + { + VNIC_TRACE( VNIC_DBG_WARN, + ("Recv packet pool is not empty!!!\n") ); + } + NdisFreePacketPool( pData->h_recv_pkt_pool ); + pData->h_recv_pkt_pool = NULL; + } + // clear Qp struct for reuse + cl_memclr( &pData->qp, sizeof( IbQp_t) ); + + cl_timer_destroy( &pData->kickTimer ); + + VNIC_EXIT( VNIC_DBG_DATA ); +} + + +static void +_data_kickTimer_start( + IN Data_t *pData, + IN uint32_t microseconds ) +{ + VNIC_ENTER( VNIC_DBG_DATA ); + + InterlockedExchange( (LONG *)&pData->kickTimerOn, TRUE ); + + usec_timer_start(&pData->kickTimer, microseconds ); + + VNIC_EXIT( VNIC_DBG_DATA ); + return; +} + +static void +_data_kickTimer_stop( + IN Data_t *pData ) +{ + VNIC_ENTER( VNIC_DBG_DATA ); + + if( InterlockedExchange( &pData->kickTimerOn, FALSE ) == TRUE ) + { + cl_timer_stop( &pData->kickTimer ); + } + + VNIC_EXIT( VNIC_DBG_DATA ); +} diff --git a/branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_data.h b/branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_data.h new file mode 100644 index 00000000..14bc0c1b --- /dev/null +++ b/branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_data.h @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2007 QLogic Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#ifndef _VNIC_DATA_H_ +#define _VNIC_DATA_H_ + +#include "vnic_trailer.h" + +typedef struct RdmaDest { + LIST_ENTRY listPtrs; + IbRegion_t region; + struct _viport *p_viport; + NDIS_PACKET *p_packet; + NDIS_BUFFER *p_buf; + uint32_t buf_sz; + uint8_t *data; + struct ViportTrailer *pTrailer; +} RdmaDest_t; + +typedef struct BufferPoolEntry { + uint64_t remoteAddr; + net32_t rKey; + uint32_t valid; +} BufferPoolEntry_t; + +typedef struct RecvPool { + uint32_t bufferSz; + uint32_t poolSz; + uint32_t eiocPoolSz; + uint32_t eiocRdmaRkey; + uint64_t eiocRdmaAddr; + uint32_t nextFullBuf; + uint32_t nextFreeBuf; + uint32_t numFreeBufs; + uint32_t numPostedBufs; + uint32_t szFreeBundle; + BOOLEAN kickOnFree; + BufferPoolEntry_t *bufPool; + RdmaDest_t *pRecvBufs; + LIST_ENTRY availRecvBufs; + NDIS_PACKET **recv_pkt_array; +} RecvPool_t; + +typedef struct XmitPool { + uint32_t bufferSz; + uint32_t poolSz; + uint32_t notifyCount; + uint32_t notifyBundle; + uint32_t nextXmitBuf; + uint32_t lastCompBuf; + uint32_t numXmitBufs; + uint32_t nextXmitPool; + uint32_t kickCount; + uint32_t kickByteCount; + uint32_t kickBundle; + uint32_t kickByteBundle; + BOOLEAN needBuffers; + BOOLEAN sendKicks; + uint32_t rdmaRKey; + uint64_t rdmaAddr; + BufferPoolEntry_t *bufPool; + RdmaIo_t *pXmitBufs; +} XmitPool_t; + +typedef struct Data { + struct _viport *p_viport; + DataConfig_t *p_conf; + IbRegion_t *p_phy_region; + IbRegion_t region; + IbRegion_t rbuf_region; + IbQp_t qp; + uint8_t *pLocalStorage; + uint32_t localStorageSz; + uint8_t *p_recv_bufs; + uint32_t recv_bufs_sz; + Inic_RecvPoolConfig_t hostPoolParms; + Inic_RecvPoolConfig_t eiocPoolParms; + RecvPool_t recvPool; + XmitPool_t xmitPool; + RdmaIo_t freeBufsIo; + SendIo_t kickIo; + LIST_ENTRY recvIos; + KSPIN_LOCK recvListLock; + NDIS_SPIN_LOCK recvIosLock; + NDIS_SPIN_LOCK xmitBufLock; + volatile LONG kickTimerOn; + BOOLEAN connected; + cl_timer_t kickTimer; + NDIS_HANDLE h_recv_pkt_pool; + NDIS_HANDLE h_recv_buf_pool; +#ifdef VNIC_STATISTIC + struct { + uint32_t xmitNum; + uint32_t recvNum; + uint32_t freeBufSends; + uint32_t freeBufNum; + uint32_t freeBufMin; + uint32_t kickRecvs; + uint32_t kickReqs; + uint32_t noXmitBufs; + uint64_t noXmitBufTime; + } statistics; +#endif /* VNIC_STATISTIC */ +} Data_t; + +void +vnic_return_packet( + IN NDIS_HANDLE adapter_context, + IN NDIS_PACKET* const p_packet ); + +void +data_construct( + IN Data_t *pData, + IN struct _viport *pViport ); + +ib_api_status_t +data_init( + Data_t *pData, + DataConfig_t *p_conf, + uint64_t guid ); + +ib_api_status_t +data_connect( + Data_t *pData ); + +ib_api_status_t +data_connected( + Data_t *pData ); + +void +data_disconnect( + Data_t *pData ); + +BOOLEAN +data_xmitPacket( + Data_t *pData, + NDIS_PACKET* const p_pkt ); + +void +data_cleanup( + Data_t *pData ); + +#define data_pathId(pData) (pData)->p_conf->pathId +#define data_eiocPool(pData) &(pData)->eiocPoolParms +#define data_hostPool(pData) &(pData)->hostPoolParms +#define data_eiocPoolMin(pData) &(pData)->p_conf->eiocMin +#define data_hostPoolMin(pData) &(pData)->p_conf->hostMin +#define data_eiocPoolMax(pData) &(pData)->p_conf->eiocMax +#define data_hostPoolMax(pData) &(pData)->p_conf->hostMax +#define data_localPoolAddr(pData) (pData)->xmitPool.rdmaAddr +#define data_localPoolRkey(pData) (pData)->xmitPool.rdmaRKey +#define data_remotePoolAddr(pData) &(pData)->recvPool.eiocRdmaAddr +#define data_remotePoolRkey(pData) &(pData)->recvPool.eiocRdmaRkey +#define data_maxMtu(pData) MAX_PAYLOAD(min((pData)->recvPool.bufferSz, (pData)->xmitPool.bufferSz)) - ETH_VLAN_HLEN +#define data_len(pData, pTrailer) ntoh16(pTrailer->dataLength) +#define data_offset(pData, pTrailer) \ + pData->recvPool.bufferSz - sizeof(struct ViportTrailer) \ + - (uint32_t)ROUNDUPP2(data_len(pData, pTrailer), VIPORT_TRAILER_ALIGNMENT) \ + + pTrailer->dataAlignmentOffset + + +/* The following macros manipulate ring buffer indexes. + * The ring buffer size must be a power of 2. + */ +#define ADD(index, increment, size) (((index) + (increment))&((size) - 1)) +#define NEXT(index, size) ADD(index, 1, size) +#define INC(index, increment, size) (index) = ADD(index, increment, size) + +#define VNIC_RECV_FROM_PACKET( P ) \ + (((RdmaDest_t **)P->MiniportReservedEx)[1]) + +#define VNIC_LIST_ITEM_FROM_PACKET( P ) \ + ((LIST_ENTRY *)P->MiniportReservedEx) + +#define VNIC_PACKET_FROM_LIST_ITEM( I ) \ + (PARENT_STRUCT( I, NDIS_PACKET, MiniportReservedEx )) + +#endif /* _VNIC_DATA_H_ */ diff --git a/branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_debug.h b/branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_debug.h new file mode 100644 index 00000000..a5df64f3 --- /dev/null +++ b/branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_debug.h @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2007 QLogic Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#ifndef _VNIC_DEBUG_H_ +#define _VNIC_DEBUG_H_ + + +#include + +/* + * Debug macros + */ +extern uint32_t g_vnic_dbg_lvl; + + +#define VNIC_DBG_INIT ( ( VNIC_DBG_INFO ) | 0x00000001 ) +#define VNIC_DBG_PNP ( ( VNIC_DBG_INFO ) | 0x00000002 ) +#define VNIC_DBG_SEND ( ( VNIC_DBG_INFO ) | 0x00000004 ) +#define VNIC_DBG_RECV ( ( VNIC_DBG_INFO ) | 0x00000008 ) +#define VNIC_DBG_STATUS ( ( VNIC_DBG_INFO ) | 0x00000010 ) +#define VNIC_DBG_IB ( ( VNIC_DBG_INFO ) | 0x00000020 ) +#define VNIC_DBG_BUF ( ( VNIC_DBG_INFO ) | 0x00000040 ) +#define VNIC_DBG_MCAST ( ( VNIC_DBG_INFO ) | 0x00000080 ) +#define VNIC_DBG_ALLOC ( ( VNIC_DBG_INFO ) | 0x00000100 ) +#define VNIC_DBG_OID ( ( VNIC_DBG_INFO ) | 0x00000200 ) +#define VNIC_DBG_DATA ( ( VNIC_DBG_INFO ) | 0x00000400 ) +#define VNIC_DBG_CTRL ( ( VNIC_DBG_INFO ) | 0x00000800 ) +#define VNIC_DBG_CTRL_PKT ( ( VNIC_DBG_INFO ) | 0x00001000 ) +#define VNIC_DBG_CONF ( ( VNIC_DBG_INFO ) | 0x00002000 ) +#define VNIC_DBG_VIPORT ( ( VNIC_DBG_INFO ) | 0x00004000 ) +#define VNIC_DBG_ADAPTER ( ( VNIC_DBG_INFO ) | 0x00008000 ) +#define VNIC_DBG_NETPATH ( ( VNIC_DBG_INFO ) | 0x00010000 ) + +#define VNIC_DBG_FUNC (0x10000000) /* For function entry/exit */ +#define VNIC_DBG_INFO (0x20000000) /* For verbose information */ +#define VNIC_DBG_WARN (0x40000000) /* For warnings. */ +#define VNIC_DBG_ERROR CL_DBG_ERROR +#define VNIC_DBG_ALL CL_DBG_ALL + +#define VNIC_DEBUG_FLAGS ( VNIC_DBG_ERROR | VNIC_DBG_WARN | VNIC_DBG_INFO ) +/* Enter and exit macros automatically add VNIC_DBG_FUNC bit */ +#define VNIC_ENTER( lvl ) \ + CL_ENTER( (lvl | VNIC_DBG_FUNC), g_vnic_dbg_lvl ) + +#define VNIC_EXIT( lvl ) \ + CL_EXIT( (lvl | VNIC_DBG_FUNC), g_vnic_dbg_lvl ) + +#if defined FREE_BUILD_DBG +#define VNIC_TRACE( lvl, msg ) \ + { \ + switch( (lvl) & VNIC_DBG_ERROR ) \ + { \ + case VNIC_DBG_ERROR: \ + cl_msg_out msg; \ + default: \ + CL_TRACE( (lvl), g_vnic_dbg_lvl, msg ); \ + } \ + } + +#define VNIC_TRACE_EXIT( lvl, msg ) \ + { \ + switch( (lvl) & VNIC_DBG_ERROR ) \ + { \ + case VNIC_DBG_ERROR: \ + cl_msg_out msg; \ + default: \ + CL_TRACE_EXIT( (lvl), g_vnic_dbg_lvl, msg ); \ + } \ + } + +#else // ! FREE_BUILD_DBG + +#define VNIC_TRACE( lvl, msg ) \ + CL_TRACE( (lvl), g_vnic_dbg_lvl, msg ) + +#define VNIC_TRACE_EXIT( lvl, msg ) \ + CL_TRACE_EXIT( (lvl), g_vnic_dbg_lvl, msg ) + +#endif // FREE_BUILD_DBG + +#define VNIC_PRINT( lvl, msg ) \ + CL_PRINT ( (lvl), g_vnic_dbg_lvl, msg ) + +#define VNIC_TRACE_BYTES( lvl, ptr, len ) \ + { \ + size_t _loop_; \ + for (_loop_ = 0; _loop_ < (len); ++_loop_) \ + { \ + CL_PRINT( (lvl), g_vnic_dbg_lvl, ("0x%.2X ", ((uint8_t*)(ptr))[_loop_])); \ + if ((_loop_ + 1)% 16 == 0) \ + { \ + CL_PRINT( (lvl), g_vnic_dbg_lvl, ("\n") ); \ + } \ + else if ((_loop_ % 4 + 1) == 0) \ + { \ + CL_PRINT( (lvl), g_vnic_dbg_lvl, (" ") ); \ + } \ + } \ + CL_PRINT( (lvl), g_vnic_dbg_lvl, ("\n") ); \ + } + + +#endif /* _VNIC_DEBUG_H_ */ diff --git a/branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_driver.c b/branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_driver.c new file mode 100644 index 00000000..08947e9b --- /dev/null +++ b/branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_driver.c @@ -0,0 +1,2152 @@ +/* + * Copyright (c) 2007 QLogic Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + +#include +#include "vnic_driver.h" + + +vnic_globals_t g_vnic; + +g_registry_params_t reg_array[VNIC_REGISTRY_TBL_SIZE] = { + {L"", 0}, + {L"MinHostPoolSz", ENTRY_INIT_VALUE}, + {L"HostRecvPoolEntries", ENTRY_INIT_VALUE}, + {L"MinEiocPoolSz", ENTRY_INIT_VALUE}, + {L"MaxEiocPoolSz", ENTRY_INIT_VALUE}, + {L"MinHostKickTimeout", ENTRY_INIT_VALUE}, + {L"MaxHostKickTimeout", ENTRY_INIT_VALUE}, + {L"MinHostKickEntries", ENTRY_INIT_VALUE}, + {L"MaxHostKickEntries", ENTRY_INIT_VALUE}, + {L"MinHostKickBytes", ENTRY_INIT_VALUE}, + {L"MaxHostKickBytes", ENTRY_INIT_VALUE}, + {L"MinHostUpdateSz", ENTRY_INIT_VALUE}, + {L"MaxHostUpdateSz", ENTRY_INIT_VALUE}, + {L"MinEiocUpdateSz", ENTRY_INIT_VALUE}, + {L"MaxEiocUpdateSz", ENTRY_INIT_VALUE}, + {L"HeartbeatTimeout", ENTRY_INIT_VALUE}, +}; + +#define DEFAULT_HOST_NAME "VNIC Host" + +uint32_t g_vnic_dbg_lvl = VNIC_DEBUG_FLAGS; + +static void +_vnic_complete_query( + IN vnic_adapter_t* const p_adapter, + IN pending_oid_t* const p_oid_info, + IN const NDIS_STATUS status, + IN const void* const p_buf, + IN const ULONG buf_len ); + +static NDIS_STATUS +__vnic_get_tcp_task_offload( + IN vnic_adapter_t* p_adapter, + IN pending_oid_t* const p_oid_info ); + +static NDIS_STATUS +__vnic_set_tcp_task_offload( + IN vnic_adapter_t* p_adapter, + IN void* const p_info_buf, + IN ULONG* const p_info_len ); + +static NDIS_STATUS +_vnic_process_packet_filter( + IN vnic_adapter_t* const p_adapter, + IN ULONG pkt_filter ); + +static void +__vnic_read_machine_name( void ); + +static NTSTATUS +__vnic_read_service_registry( + IN UNICODE_STRING* const p_registry_path ); + +static NDIS_STATUS +__vnic_set_machine_name( + IN VOID *p_uni_array, + IN USHORT buf_size ); + +/* +p_drv_obj + Pointer to Driver Object for this device driver +p_registry_path + Pointer to unicode string containing path to this driver's registry area +return + STATUS_SUCCESS, NDIS_STATUS_BAD_CHARACTERISTICS, NDIS_STATUS_BAD_VERSION, + NDIS_STATUS_RESOURCES, or NDIS_STATUS_FAILURE +IRQL = PASSIVE_LEVEL +*/ +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT p_drv_obj, + IN PUNICODE_STRING p_registry_path ) +{ + NDIS_STATUS status; + NDIS_MINIPORT_CHARACTERISTICS characteristics; + + VNIC_ENTER( VNIC_DBG_INIT ); + +#ifdef _DEBUG_ + PAGED_CODE(); +#endif +/* + status = CL_INIT; + + if( !NT_SUCCESS( status ) ) + { + VNIC_TRACE_EXIT( VNIC_DBG_ERROR, + ("cl_init failed.\n") ); + return status; + } +*/ + status = NDIS_STATUS_SUCCESS; + + g_vnic.ndis_handle = NULL; + g_vnic.shutdown = 0; + g_vnic.p_params = NULL; + + NdisMInitializeWrapper( &g_vnic.ndis_handle, p_drv_obj, p_registry_path, NULL ); + + if ( g_vnic.ndis_handle == NULL ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + ("NdisMInitializeWrapper failed\n")); + CL_DEINIT; + return NDIS_STATUS_FAILURE; + } + + cl_memclr( &characteristics, sizeof(characteristics) ); + + characteristics.MajorNdisVersion = MAJOR_NDIS_VERSION; + characteristics.MinorNdisVersion = MINOR_NDIS_VERSION; + characteristics.CheckForHangHandler = vnic_check_for_hang; + characteristics.HaltHandler = vnic_halt; + characteristics.InitializeHandler = vnic_initialize; + characteristics.QueryInformationHandler = vnic_oid_query_info; + characteristics.ResetHandler = vnic_reset; + characteristics.SetInformationHandler = vnic_oid_set_info; + characteristics.ReturnPacketHandler = vnic_return_packet; + characteristics.SendPacketsHandler = vnic_send_packets; + +#ifdef NDIS51_MINIPORT + characteristics.CancelSendPacketsHandler = vnic_cancel_xmit; + characteristics.PnPEventNotifyHandler = vnic_pnp_notify; + characteristics.AdapterShutdownHandler = vnic_shutdown; +#endif + + status = NdisMRegisterMiniport( + g_vnic.ndis_handle, &characteristics, sizeof(characteristics) ); + + if( status != NDIS_STATUS_SUCCESS ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + ("NdisMRegisterMiniport failed with status of %d\n", status) ); + NdisTerminateWrapper( g_vnic.ndis_handle, NULL ); + CL_DEINIT; + } + else + { + NdisMRegisterUnloadHandler( g_vnic.ndis_handle, vnic_unload ); + + __vnic_read_machine_name(); + __vnic_read_service_registry( p_registry_path ); + +#if ( LBFO_ENABLED ) + cl_qlist_init( &g_vnic.primary_list ); + cl_qlist_init( &g_vnic.secondary_list ); +#endif + cl_qlist_init( &g_vnic.adapter_list); + } + + VNIC_EXIT( VNIC_DBG_INIT ); + return status; +} + + +VOID +vnic_unload( + IN PDRIVER_OBJECT p_drv_obj ) +{ + VNIC_ENTER( VNIC_DBG_INIT ); + + UNREFERENCED_PARAMETER( p_drv_obj ); + + VNIC_TRACE_EXIT( VNIC_DBG_INFO, + (" Driver Unloaded....\n")); + //CL_DEINIT; +} + + +//! Initialization function called for each IOC discovered +/* The MiniportInitialize function is a required function that sets up a +NIC (or virtual NIC) for network I/O operations, claims all hardware +resources necessary to the NIC in the registry, and allocates resources +the driver needs to carry out network I/O operations. +IRQL = PASSIVE_LEVEL + +@param p_open_status Pointer to a status field set if this function returns NDIS_STATUS_OPEN_ERROR +@param p_selected_medium_index Pointer to unsigned integer noting index into medium_array for this NIC +@param medium_array Array of mediums for this NIC +@param medium_array_size Number of elements in medium_array +@param h_handle Handle assigned by NDIS for this NIC +@param wrapper_config_context Handle used for Ndis initialization functions +@return NDIS_STATUS_SUCCESS, NDIS_STATUS_UNSUPPORTED_MEDIA, NDIS_STATUS_RESOURCES, +NDIS_STATUS_NOT_SUPPORTED +*/ +NDIS_STATUS +vnic_initialize( + OUT PNDIS_STATUS p_open_status, + OUT PUINT p_selected_medium_index, + IN PNDIS_MEDIUM medium_array, + IN UINT medium_array_size, + IN NDIS_HANDLE h_handle, + IN NDIS_HANDLE wrapper_config_context ) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + ib_api_status_t ib_status; + ib_pnp_req_t pnp_req; + UINT medium_index; + vnic_adapter_t *p_adapter; + + VNIC_ENTER( VNIC_DBG_INIT ); + +#ifdef _DEBUG_ + PAGED_CODE(); +#endif + + UNUSED_PARAM( p_open_status ); + + /* Search for our medium */ + for( medium_index = 0; medium_index < medium_array_size; ++medium_index ) + { + /* Check to see if we found our medium */ + if( medium_array[medium_index] == NdisMedium802_3 ) + break; + } + + if( medium_index == medium_array_size ) /* Never found it */ + { + VNIC_TRACE_EXIT( VNIC_DBG_ERROR, ("No supported media.\n") ); + return NDIS_STATUS_UNSUPPORTED_MEDIA; + } + + *p_selected_medium_index = medium_index; + + /* Create the adapter */ + ib_status = vnic_create_adapter( h_handle, wrapper_config_context, &p_adapter ); + if( ib_status != IB_SUCCESS ) + { + VNIC_TRACE_EXIT( VNIC_DBG_ERROR, + ("returned status %x\n", ib_status ) ); + return NDIS_STATUS_FAILURE; + } + + /* set NDIS features we support */ + NdisMSetAttributesEx( h_handle, + (NDIS_HANDLE)p_adapter, + 0, /*check for hung timeout, 2 sec */ + NDIS_ATTRIBUTE_BUS_MASTER | + NDIS_ATTRIBUTE_DESERIALIZE | + NDIS_ATTRIBUTE_SURPRISE_REMOVE_OK | + NDIS_ATTRIBUTE_USES_SAFE_BUFFER_APIS, + NdisInterfacePNPBus ); + + /* Register for IOC events */ + pnp_req.pfn_pnp_cb = __vnic_pnp_cb; + pnp_req.pnp_class = IB_PNP_IOC | IB_PNP_FLAG_REG_SYNC; + pnp_req.pnp_context = (const void *)p_adapter; + + ib_status = p_adapter->ifc.reg_pnp( p_adapter->h_al, &pnp_req, &p_adapter->h_pnp ); + + if( ib_status != IB_SUCCESS ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + ("ib_reg_pnp returned %s\n", p_adapter->ifc.get_err_str( ib_status )) ); + NdisWriteErrorLogEntry( h_handle, + NDIS_ERROR_CODE_OUT_OF_RESOURCES, 0); + status = NDIS_STATUS_FAILURE; + } + else if( p_adapter->state != INIC_REGISTERED ) + { + status = NDIS_STATUS_OPEN_FAILED; + *p_open_status = NDIS_STATUS_DEVICE_FAILED; + + VNIC_TRACE( VNIC_DBG_ERROR, + ("IOC[%d] ADAPTER Initialization Failed\n", p_adapter->ioc_num ) ); + NdisWriteErrorLogEntry( h_handle, + NDIS_ERROR_CODE_HARDWARE_FAILURE, 1, p_adapter->ioc_num ); + } + + if( status != NDIS_STATUS_SUCCESS ) + { + vnic_destroy_adapter( p_adapter ); + } + + VNIC_EXIT( VNIC_DBG_INIT ); + return status; + +} + + +//! Deallocates resources when the NIC is removed and halts the NIC.. +/* IRQL = DISPATCH_LEVEL + +@param adapter_context The adapter context allocated at start +*/ +void +vnic_halt( + IN NDIS_HANDLE adapter_context ) +{ + VNIC_ENTER( VNIC_DBG_INIT ); + CL_ASSERT( adapter_context ); + + vnic_destroy_adapter( (vnic_adapter_t*)adapter_context ); + + VNIC_EXIT( VNIC_DBG_INIT ); +} + + +//! Reports the state of the NIC, or monitors the responsiveness of an underlying device driver. +/* IRQL = DISPATCH_LEVEL + +@param adapter_context The adapter context allocated at start +@return TRUE if the driver determines that its NIC is not operating +*/ + +BOOLEAN +vnic_check_for_hang( + IN NDIS_HANDLE adapter_context ) +{ + vnic_adapter_t *p_adapter; + + CL_ASSERT( adapter_context ); + p_adapter = (vnic_adapter_t*)adapter_context; + + /* current path is Ok */ + if( netpath_is_connected( p_adapter->p_currentPath ) ) + { + return FALSE; + } + + if( p_adapter->hung != 0 && + p_adapter->hung >= p_adapter->num_paths ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + ("IOC[%d] Adapter Hung: %d NumPath: %d\n", + p_adapter->ioc_num, p_adapter->hung, p_adapter->num_paths ) ); + return TRUE; + } + + return FALSE; +} + + +//! Returns information about the capabilities and status of the driver and/or its NIC. +/* IRQL = DISPATCH_LEVEL + +@param adapter_context The adapter context allocated at start +@param oid Object ID representing the query operation to be carried out +@param info_buf Buffer containing any input for this query and location for output +@param info_buf_len Number of bytes available in info_buf +@param p_bytes_written Pointer to number of bytes written into info_buf +@param p_bytes_needed Pointer to number of bytes needed to satisfy this oid +@return NDIS_STATUS_SUCCESS, NDIS_STATUS_PENDING, NDIS_STATUS_INVALID_OID, +NDIS_STATUS_INVALID_LENGTH, NDIS_STATUS_NOT_ACCEPTED, NDIS_STATUS_NOT_SUPPORTED, +NDIS_STATUS_RESOURCES +*/ +NDIS_STATUS +vnic_oid_query_info( + IN NDIS_HANDLE adapter_context, + IN NDIS_OID oid, + IN PVOID info_buf, + IN ULONG info_buf_len, + OUT PULONG p_bytes_written, + OUT PULONG p_bytes_needed ) +{ + vnic_adapter_t *p_adapter; + Netpath_t *p_netpath; + + NDIS_STATUS status; + USHORT version; + uint32_t info32 = 0; + uint64_t info64 = 0; + PVOID src_buf; + ULONG buf_len; + pending_oid_t oid_info; + + VNIC_ENTER( VNIC_DBG_OID ); + + oid_info.oid = oid; + oid_info.p_buf = info_buf; + oid_info.buf_len = info_buf_len; + oid_info.p_bytes_used = p_bytes_written; + oid_info.p_bytes_needed = p_bytes_needed; + + CL_ASSERT( adapter_context ); + p_adapter = (vnic_adapter_t *)adapter_context; + + CL_ASSERT( p_bytes_written ); + CL_ASSERT( p_bytes_needed ); + + status = NDIS_STATUS_SUCCESS; + src_buf = &info32; + buf_len = sizeof(info32); + + if( g_vnic.shutdown != 0 ) + { + *p_bytes_written = 0; + return NDIS_STATUS_NOT_ACCEPTED; + } + + p_netpath = p_adapter->p_currentPath; + if( !p_netpath || !p_netpath->carrier ) + { + status = NDIS_STATUS_NOT_ACCEPTED; + goto complete; + } + + switch( oid ) + { + /* Required General */ + case OID_GEN_SUPPORTED_LIST: + VNIC_TRACE( VNIC_DBG_OID, + ("received query for OID_GEN_SUPPORTED_LIST\n") ); + src_buf = (PVOID)SUPPORTED_OIDS; + buf_len = sizeof(SUPPORTED_OIDS); + break; + + case OID_GEN_HARDWARE_STATUS: + VNIC_TRACE( VNIC_DBG_OID, + ("received query for OID_GEN_HARDWARE_STATUS\n") ); + + if( p_netpath->carrier ) + { + VNIC_TRACE( VNIC_DBG_OID, + ("returning NdisHardwareStatusReady\n") ); + info32 = NdisHardwareStatusReady; + } + else + { + VNIC_TRACE( VNIC_DBG_OID, + ("returning NdisHardwareStatusInitializing\n") ); + info32 = NdisHardwareStatusNotReady; + } + break; + + case OID_GEN_MEDIA_SUPPORTED: + case OID_GEN_MEDIA_IN_USE: + VNIC_TRACE( VNIC_DBG_OID, + ("received query for OID_GEN_MEDIA_SUPPORTED " + "or OID_GEN_MEDIA_IN_USE\n") ); + info32 = NdisMedium802_3; + break; + + case OID_GEN_MAXIMUM_TOTAL_SIZE: /* frame size inlcuding header */ + info32 = sizeof( eth_hdr_t ); + case OID_GEN_MAXIMUM_FRAME_SIZE: /* wihout header */ + VNIC_TRACE( VNIC_DBG_OID, + ("received query for OID_GEN_MAXIMUM_FRAME_SIZE\n") ); + if( !p_netpath->carrier ) + { + info32 += MIN_MTU; + } + else + { + info32 += p_adapter->p_currentPath->pViport->mtu; + } + break; + + case OID_GEN_LINK_SPEED: + VNIC_TRACE( VNIC_DBG_OID, + ("received query for OID_GEN_LINK_SPEED\n") ); + + if( p_netpath->carrier ) + { + /* if we get link speed value - it is in Mbps units - have to convert to 100bps*/ + info32 = ( p_adapter->link_speed )? + ( p_adapter->link_speed * LINK_SPEED_1MBIT_x100BPS ): + DEFAULT_LINK_SPEED_x100BPS; + } + else + { + status = NDIS_STATUS_NOT_ACCEPTED; + } + break; + + case OID_GEN_TRANSMIT_BUFFER_SPACE: + VNIC_TRACE( VNIC_DBG_OID, + ("received query for OID_GEN_TRANSMIT_BUFFER_SPACE\n") ); + if ( !p_netpath->carrier ) + { + status= NDIS_STATUS_NOT_ACCEPTED; + } + else + { + info32 = p_netpath->pViport->data.xmitPool.bufferSz * + p_netpath->pViport->data.xmitPool.poolSz; + } + break; + + case OID_GEN_RECEIVE_BUFFER_SPACE: + VNIC_TRACE( VNIC_DBG_OID, + ("received query for OID_GEN_RECEIVE_BUFFER_SPACE " + "or OID_GEN_RECEIVE_BUFFER_SPACE\n") ); + if ( !p_netpath->carrier ) + { + status = NDIS_STATUS_NOT_ACCEPTED; + } + else + { + info32 = p_netpath->pViport->data.recvPool.bufferSz * + p_netpath->pViport->data.recvPool.poolSz; + } + break; + case OID_GEN_MAXIMUM_LOOKAHEAD: + case OID_GEN_CURRENT_LOOKAHEAD: + case OID_GEN_TRANSMIT_BLOCK_SIZE: + case OID_GEN_RECEIVE_BLOCK_SIZE: + VNIC_TRACE( VNIC_DBG_OID, + ("received query for OID_GEN_MAXIMUM_LOOKAHEAD " + "or OID_GEN_CURRENT_LOOKAHEAD or " + "OID_GEN_TRANSMIT_BLOCK_SIZE or " + "OID_GEN_RECEIVE_BLOCK_SIZE\n") ); + if( !p_netpath->carrier ) + { + info32 = MIN_MTU; + } + else + { + info32 = p_adapter->p_currentPath->pViport->mtu; + } + /*TODO: add VLAN tag size if support requested */ + info32 += sizeof(eth_hdr_t); + break; + + case OID_GEN_VENDOR_ID: + VNIC_TRACE( VNIC_DBG_OID, + ("received query for OID_GEN_VENDOR_ID\n") ); + + src_buf = (void*)VENDOR_ID; + buf_len = sizeof(VENDOR_ID); + break; + + case OID_GEN_VENDOR_DESCRIPTION: + VNIC_TRACE( VNIC_DBG_OID, + ("received query for OID_GEN_VENDOR_DESCRIPTION\n") ); + src_buf = VENDOR_DESCRIPTION; + buf_len = sizeof(VENDOR_DESCRIPTION); + break; + + case OID_GEN_VENDOR_DRIVER_VERSION: + VNIC_TRACE( VNIC_DBG_OID, + (" received query for OID_GEN_VENDOR_DRIVER_VERSION\n" ) ); + src_buf = &version; + buf_len = sizeof(version); + //TODO: Figure out what the right version is. + version = INIC_MAJORVERSION << 8 | INIC_MINORVERSION; + break; + + case OID_GEN_PHYSICAL_MEDIUM: + VNIC_TRACE( VNIC_DBG_OID, + (" received query for OID_GEN_PHYSICAL_MEDIUM\n" ) ); + info32 = NdisPhysicalMediumUnspecified; + break; + + case OID_GEN_CURRENT_PACKET_FILTER: + VNIC_TRACE( VNIC_DBG_OID, + (" received query for OID_GEN_CURRENT_PACKET_FILTER\n" ) ); + info32 = p_adapter->packet_filter; + break; + + case OID_GEN_DRIVER_VERSION: + VNIC_TRACE( VNIC_DBG_OID, + (" received query for OID_GEN_DRIVER_VERSION\n" ) ); + src_buf = &version; + buf_len = sizeof(version); + version = MAJOR_NDIS_VERSION << 8 | MINOR_NDIS_VERSION; + break; + + case OID_GEN_MAC_OPTIONS: + VNIC_TRACE( VNIC_DBG_OID, + (" received query for OID_GEN_MAC_OPTIONS\n" ) ); + info32 = NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA | + NDIS_MAC_OPTION_TRANSFERS_NOT_PEND | + NDIS_MAC_OPTION_NO_LOOPBACK | + NDIS_MAC_OPTION_FULL_DUPLEX | + NDIS_MAC_OPTION_8021P_PRIORITY | + NDIS_MAC_OPTION_8021Q_VLAN; + + break; + + case OID_GEN_MEDIA_CONNECT_STATUS: + VNIC_TRACE( VNIC_DBG_OID, + (" received query for OID_GEN_MEDIA_CONNECT_STATUS\n" ) ); + + info32 = ( p_adapter->carrier )? + NdisMediaStateConnected : + NdisMediaStateDisconnected; + break; + + case OID_GEN_MAXIMUM_SEND_PACKETS: + VNIC_TRACE( VNIC_DBG_OID, + (" received query for OID_GEN_MAXIMUM_SEND_PACKETS\n" ) ); + info32 = MAXLONG; // NDIS ignored it anyway + break; + + /* Required General Statistics */ + case OID_GEN_XMIT_OK: + VNIC_TRACE( VNIC_DBG_OID, + (" received query for OID_GEN_XMIT_OK\n" ) ); + if ( !p_netpath->carrier ) + { + info32 = 0; + } + else + { + info64 = p_netpath->pViport->stats.ifOutOk; + src_buf = &info64; + buf_len = sizeof(info64); + } + break; + + case OID_GEN_RCV_OK: + VNIC_TRACE( VNIC_DBG_OID, + (" received query for OID_GEN_RCV_OK\n" ) ); + if ( !p_netpath->carrier) + { + info32 = 0; + break; + } + if ( info_buf_len == sizeof(info32) ) + { + info32 = (uint32_t)p_netpath->pViport->stats.ifInOk; + } + else + { + info64 = p_netpath->pViport->stats.ifInOk; + src_buf = &info64; + buf_len = sizeof(info64); + } + break; + + case OID_GEN_XMIT_ERROR: + VNIC_TRACE( VNIC_DBG_OID, + (" received query for OID_GEN_XMIT_ERROR\n" ) ); + if ( !p_netpath->carrier ) + { + info32 = 0; + } + else + { + info64 = p_netpath->pViport->stats.ifOutErrors; + src_buf = &info64; + buf_len = sizeof(info64); + } + break; + + case OID_GEN_RCV_ERROR: + VNIC_TRACE( VNIC_DBG_OID, + (" received query for OID_GEN_RCV_ERROR\n" ) ); + if ( !p_netpath->carrier ) + { + info32 = 0; + } + else + { + info64 = p_netpath->pViport->stats.ifInErrors; + src_buf = &info64; + buf_len = sizeof(info64); + } + break; + + case OID_GEN_RCV_NO_BUFFER: + VNIC_TRACE( VNIC_DBG_OID, + (" received query for OID_GEN_RCV_NO_BUFFER\n" ) ); + info32 = 0; + break; + + case OID_GEN_DIRECTED_BYTES_XMIT: + VNIC_TRACE( VNIC_DBG_OID, + (" received query for OID_GEN_DIRECTED_BYTES_XMIT\n" ) ); + if ( !p_netpath->carrier ) + { + info32 = 0; + } + else + { + info64 = p_netpath->pViport->stats.ifOutUcastBytes; + src_buf = &info64; + buf_len = sizeof(info64); + } + break; + + case OID_GEN_DIRECTED_FRAMES_XMIT: + VNIC_TRACE( VNIC_DBG_OID, + (" received query for OID_GEN_DIRECTED_FRAMES_XMIT\n" ) ); + if ( !p_netpath->carrier ) + { + info32 = 0; + } + else + { + info64 = p_netpath->pViport->stats.ifOutNUcastPkts; + src_buf = &info64; + buf_len = sizeof(info64); + } + break; + + case OID_GEN_MULTICAST_BYTES_XMIT: + VNIC_TRACE( VNIC_DBG_OID, + (" received query for OID_GEN_MULTICAST_BYTES_XMIT\n" ) ); + if ( !p_netpath->carrier ) + { + info32 = 0; + } + else + { + info64 = p_netpath->pViport->stats.ifOutMulticastBytes; + src_buf = &info64; + buf_len = sizeof(info64); + } + break; + + case OID_GEN_MULTICAST_FRAMES_XMIT: + VNIC_TRACE( VNIC_DBG_OID, + (" received query for OID_GEN_MULTICAST_FRAMES_XMIT\n" ) ); + if ( !p_netpath->carrier ) + { + info32 = 0; + } + else + { + info64 = p_netpath->pViport->stats.ifOutMulticastPkts; + src_buf = &info64; + buf_len = sizeof(info64); + } + break; + + case OID_GEN_BROADCAST_BYTES_XMIT: + VNIC_TRACE( VNIC_DBG_OID, + (" received query for OID_GEN_BROADCAST_BYTES_XMIT\n" ) ); + if ( !p_netpath->carrier ) + { + info32 = 0; + } + else + { + info64 = p_netpath->pViport->stats.ifOutBroadcastBytes; + src_buf = &info64; + buf_len = sizeof(info64); + } + break; + + case OID_GEN_BROADCAST_FRAMES_XMIT: + VNIC_TRACE( VNIC_DBG_OID, + (" received query for OID_GEN_BROADCAST_FRAMES_XMIT\n" ) ); + if ( !p_netpath->carrier ) + { + info32 = 0; + } + else + { + info64 = p_netpath->pViport->stats.ifOutBroadcastPkts; + src_buf = &info64; + buf_len = sizeof(info64); + } + break; + case OID_GEN_DIRECTED_BYTES_RCV: + VNIC_TRACE( VNIC_DBG_OID, + (" received query for OID_GEN_DIRECTED_BYTES_RCV\n" ) ); + if ( !p_netpath->carrier ) + { + info32 = 0; + } + else + { + info64 = p_netpath->pViport->stats.ifInUcastBytes; + src_buf = &info64; + buf_len = sizeof(info64); + } + break; + + case OID_GEN_DIRECTED_FRAMES_RCV: + VNIC_TRACE( VNIC_DBG_OID, + (" received query for OID_GEN_DIRECTED_FRAMES_RCV\n" ) ); + if ( !p_netpath->carrier ) + { + info32 = 0; + } + else + { + info64 = p_netpath->pViport->stats.ifInNUcastPkts; + src_buf = &info64; + buf_len = sizeof(info64); + } + break; + + case OID_GEN_MULTICAST_BYTES_RCV: + VNIC_TRACE( VNIC_DBG_OID, + (" received query for OID_GEN_MULTICAST_BYTES_RCV\n" ) ); + if ( !p_netpath->carrier ) + { + info32 = 0; + } + else + { + info64 = p_netpath->pViport->stats.ifInMulticastBytes; + src_buf = &info64; + buf_len = sizeof(info64); + } + break; + + case OID_GEN_MULTICAST_FRAMES_RCV: + VNIC_TRACE( VNIC_DBG_OID, + (" received query for OID_GEN_MULTICAST_FRAMES_RCV\n" ) ); + if ( !p_netpath->carrier ) + { + info32 = 0; + } + else + { + info64 = p_netpath->pViport->stats.ifInMulticastPkts; + src_buf = &info64; + buf_len = sizeof(info64); + } + break; + + case OID_GEN_BROADCAST_BYTES_RCV: + VNIC_TRACE( VNIC_DBG_OID, + (" received query for OID_GEN_BROADCAST_BYTES_RCV\n" ) ); + if ( !p_netpath->carrier ) + { + info32 = 0; + } + else + { + info64 = p_netpath->pViport->stats.ifInBroadcastBytes; + src_buf = &info64; + buf_len = sizeof(info64); + } + break; + + case OID_GEN_BROADCAST_FRAMES_RCV: + VNIC_TRACE( VNIC_DBG_OID, + (" received query for OID_GEN_BROADCAST_FRAMES_RCV\n" ) ); + if ( !p_netpath->carrier ) + { + info32 = 0; + } + else + { + info64 = p_netpath->pViport->stats.ifInBroadcastPkts; + src_buf = &info64; + buf_len = sizeof(info64); + } + break; + + /* Required Ethernet operational characteristics */ + case OID_802_3_PERMANENT_ADDRESS: + case OID_802_3_CURRENT_ADDRESS: +#if defined( _DEBUG_ ) + if( oid == OID_802_3_PERMANENT_ADDRESS ) + { + VNIC_TRACE( VNIC_DBG_OID, + (" received query for OID_802_3_PERMANENT_ADDRESS\n" ) ); + } + else + { + VNIC_TRACE( VNIC_DBG_OID, + (" received query for OID_802_3_CURRENT_ADDRESS\n" ) ); + } +#endif /* defined( _DEBUG_ )*/ + if( !p_netpath->pViport || + p_netpath->pViport->errored || + p_netpath->pViport->disconnect ) + { + status = NDIS_STATUS_NOT_ACCEPTED; + break; + } + if ( !p_adapter->macSet ) + { + p_adapter->pending_query = TRUE; + p_adapter->query_oid = oid_info; + + VNIC_TRACE( VNIC_DBG_OID, + ("returning NDIS_STATUS_PENDING\n") ); + status = NDIS_STATUS_PENDING; + } + else + { + src_buf = &p_netpath->pViport->hwMacAddress; + buf_len = HW_ADDR_LEN; + } + break; + + case OID_802_3_MULTICAST_LIST: + VNIC_TRACE( VNIC_DBG_OID, + (" received query for OID_802_3_MULTICAST_LIST\n" ) ); + + if( !p_netpath->carrier || + !(p_netpath->pViport->flags & INIC_FLAG_ENABLE_NIC) ) + { +/* p_adapter->pending_query = TRUE; + p_adapter->query_oid = oid_info; + + VNIC_TRACE( VNIC_DBG_OID, + ("returning NDIS_STATUS_PENDING\n") ); + status = NDIS_STATUS_PENDING; +*/ + status = NDIS_STATUS_NOT_ACCEPTED; + break; + } + if( p_adapter->mc_count > 0 ) + { + buf_len = p_adapter->mc_count * sizeof( mac_addr_t ); + src_buf = &p_adapter->mcast_array; + } + else + { + info32 = 0; + } + break; + + case OID_802_3_MAXIMUM_LIST_SIZE: + VNIC_TRACE( VNIC_DBG_OID, + (" received query for OID_802_3_MAXIMUM_LIST_SIZE\n" ) ); + if ( !p_adapter->macSet ) + { + info32 = MAX_MCAST; + } + else + { + info32 = p_netpath->pViport->numMacAddresses - MCAST_ADDR_START; + } + break; + case OID_802_3_MAC_OPTIONS: + VNIC_TRACE( VNIC_DBG_OID, + (" received query for OID_802_3_MAC_OPTIONS\n" ) ); + info32 = 0; + break; + + /* Required Ethernet stats */ + case OID_802_3_RCV_ERROR_ALIGNMENT: + case OID_802_3_XMIT_ONE_COLLISION: + case OID_802_3_XMIT_MORE_COLLISIONS: + VNIC_TRACE( VNIC_DBG_OID, + (" received query for OID_802_3_RCV_ERROR_ALIGNMENT or " + "OID_802_3_XMIT_ONE_COLLISION or " + "OID_802_3_XMIT_MORE_COLLISIONS\n" ) ); + info32 = 0; + break; + + case OID_TCP_TASK_OFFLOAD: + VNIC_TRACE( VNIC_DBG_OID, + (" received query for OID_TCP_TASK_OFFLOAD\n" ) ); + + src_buf = NULL; + status = __vnic_get_tcp_task_offload( p_adapter, &oid_info ); + break; + + case OID_GEN_VLAN_ID: + /* return current vlan info */ + info32 =( p_adapter->vlan_info & 0x00000fff ); + break; + /* Optional General */ + case OID_GEN_SUPPORTED_GUIDS: + /* Optional General Stats */ + case OID_GEN_RCV_CRC_ERROR: + case OID_GEN_TRANSMIT_QUEUE_LENGTH: + + /* Optional Ethernet Stats */ + case OID_802_3_XMIT_DEFERRED: + case OID_802_3_XMIT_MAX_COLLISIONS: + case OID_802_3_RCV_OVERRUN: + case OID_802_3_XMIT_UNDERRUN: + case OID_802_3_XMIT_HEARTBEAT_FAILURE: + case OID_802_3_XMIT_TIMES_CRS_LOST: + case OID_802_3_XMIT_LATE_COLLISIONS: + case OID_PNP_CAPABILITIES: + status = NDIS_STATUS_NOT_SUPPORTED; + VNIC_TRACE( VNIC_DBG_OID, + (" received an unsupported oid of 0x%.8X!\n" , oid) ); + break; + + case OID_GEN_PROTOCOL_OPTIONS: + case OID_GEN_TRANSPORT_HEADER_OFFSET: +#ifdef NDIS51_MINIPORT + case OID_GEN_MACHINE_NAME: + case OID_GEN_RNDIS_CONFIG_PARAMETER: +#endif + default: + status = NDIS_STATUS_INVALID_OID; + VNIC_TRACE( VNIC_DBG_OID, + (" received an invalid oid of 0x%.8X!\n" , oid) ); + break; + } + + /* + * Complete the request as if it was handled asynchronously to maximize + * code reuse for when we really handle the requests asynchronously. + * Note that this requires the QueryInformation entry point to always + * return NDIS_STATUS_PENDING + */ +complete: + if( status != NDIS_STATUS_PENDING ) + { + _vnic_complete_query( + p_adapter, &oid_info, status, src_buf, buf_len ); + } + + VNIC_EXIT( VNIC_DBG_OID ); + return NDIS_STATUS_PENDING; +} + + +static void +_vnic_complete_query( + IN vnic_adapter_t* const p_adapter, + IN pending_oid_t* const p_oid_info, + IN const NDIS_STATUS status, + IN const void* const p_buf, + IN const ULONG buf_len ) +{ + NDIS_STATUS oid_status = status; + + VNIC_ENTER( VNIC_DBG_OID ); + + CL_ASSERT( status != NDIS_STATUS_PENDING ); + + if( status == NDIS_STATUS_SUCCESS ) + { + if( p_oid_info->buf_len < buf_len ) + { + VNIC_TRACE( VNIC_DBG_OID, + ("Insufficient buffer space. " + "Returning NDIS_STATUS_INVALID_LENGTH.\n") ); + oid_status = NDIS_STATUS_INVALID_LENGTH; + *p_oid_info->p_bytes_needed = buf_len; + *p_oid_info->p_bytes_used = 0; + } + else if( p_oid_info->p_buf ) + { + /* Only copy if we have a distinct source buffer. */ + if( p_buf ) + { + NdisMoveMemory( p_oid_info->p_buf, p_buf, buf_len ); + *p_oid_info->p_bytes_used = buf_len; + } + } + else + { + VNIC_TRACE( VNIC_DBG_OID, + ("Returning NDIS_NOT_ACCEPTED") ); + oid_status = NDIS_STATUS_NOT_ACCEPTED; + } + } + else + { + *p_oid_info->p_bytes_used = 0; + } + + p_adapter->pending_query = FALSE; + + NdisMQueryInformationComplete( p_adapter->h_handle, oid_status ); + + VNIC_EXIT( VNIC_DBG_OID ); +} + + +static NDIS_STATUS +__vnic_get_tcp_task_offload( + IN vnic_adapter_t* p_adapter, + IN pending_oid_t* const p_oid_info ) +{ + NDIS_TASK_OFFLOAD_HEADER *p_offload_hdr; + NDIS_TASK_OFFLOAD *p_offload_task; + NDIS_TASK_TCP_IP_CHECKSUM *p_offload_chksum; + + ULONG buf_len; + uint32_t enabled_TxCsum; + uint32_t enabled_RxCsum; + + buf_len = sizeof(NDIS_TASK_OFFLOAD_HEADER) + + sizeof(NDIS_TASK_OFFLOAD) + + sizeof(NDIS_TASK_TCP_IP_CHECKSUM) - 1; + + *(p_oid_info->p_bytes_needed) = buf_len; + + if( p_oid_info->buf_len < buf_len ) + return NDIS_STATUS_INVALID_LENGTH; + + p_offload_hdr = (NDIS_TASK_OFFLOAD_HEADER*)p_oid_info->p_buf; + if( p_offload_hdr->Version != NDIS_TASK_OFFLOAD_VERSION ) + return NDIS_STATUS_INVALID_DATA; + + if( p_offload_hdr->EncapsulationFormat.Encapsulation != + IEEE_802_3_Encapsulation ) + { + return NDIS_STATUS_INVALID_DATA; + } + /* too early, we didn't get response on CMD_INIT_INIC yet */ + if( !netpath_is_connected( p_adapter->p_currentPath ) ) + { + return NDIS_STATUS_NOT_ACCEPTED; + } + enabled_RxCsum = + (uint32_t)( p_adapter->params.UseRxCsum && + netpath_canRxCsum( p_adapter->p_currentPath ) ); + + enabled_TxCsum = + (uint32_t)( p_adapter->params.UseTxCsum && + netpath_canTxCsum( p_adapter->p_currentPath ) ); + + p_offload_hdr->OffsetFirstTask = sizeof(NDIS_TASK_OFFLOAD_HEADER); + p_offload_task = (NDIS_TASK_OFFLOAD*)(p_offload_hdr + 1); + p_offload_task->Version = NDIS_TASK_OFFLOAD_VERSION; + p_offload_task->Size = sizeof(NDIS_TASK_OFFLOAD); + p_offload_task->Task = TcpIpChecksumNdisTask; + p_offload_task->OffsetNextTask = 0; + p_offload_task->TaskBufferLength = sizeof(NDIS_TASK_TCP_IP_CHECKSUM); + p_offload_chksum = + (NDIS_TASK_TCP_IP_CHECKSUM*)p_offload_task->TaskBuffer; + + p_offload_chksum->V4Transmit.IpOptionsSupported = enabled_TxCsum; + p_offload_chksum->V4Transmit.TcpOptionsSupported = enabled_TxCsum; + p_offload_chksum->V4Transmit.TcpChecksum = enabled_TxCsum; + p_offload_chksum->V4Transmit.UdpChecksum = enabled_TxCsum; + p_offload_chksum->V4Transmit.IpChecksum = enabled_TxCsum; + + p_offload_chksum->V4Receive.IpOptionsSupported = enabled_RxCsum; + p_offload_chksum->V4Receive.TcpOptionsSupported = enabled_RxCsum; + p_offload_chksum->V4Receive.TcpChecksum = enabled_RxCsum; + p_offload_chksum->V4Receive.UdpChecksum = enabled_RxCsum; + p_offload_chksum->V4Receive.IpChecksum = enabled_RxCsum; + + p_offload_chksum->V6Transmit.IpOptionsSupported = enabled_TxCsum; + p_offload_chksum->V6Transmit.TcpOptionsSupported = enabled_TxCsum; + p_offload_chksum->V6Transmit.TcpChecksum = enabled_TxCsum; + p_offload_chksum->V6Transmit.UdpChecksum = enabled_TxCsum; + + p_offload_chksum->V6Receive.IpOptionsSupported = enabled_RxCsum; + p_offload_chksum->V6Receive.TcpOptionsSupported = enabled_RxCsum; + p_offload_chksum->V6Receive.TcpChecksum = enabled_RxCsum; + p_offload_chksum->V6Receive.UdpChecksum = enabled_RxCsum; + + *(p_oid_info->p_bytes_used) = buf_len; + + return NDIS_STATUS_SUCCESS; +} + +static NDIS_STATUS +__vnic_set_tcp_task_offload( + IN vnic_adapter_t* p_adapter, + IN void* const p_info_buf, + IN ULONG* const p_info_len ) +{ + NDIS_TASK_OFFLOAD_HEADER *p_offload_hdr; + NDIS_TASK_OFFLOAD *p_offload_task; + NDIS_TASK_TCP_IP_CHECKSUM *p_offload_chksum; + + ULONG enabled_TxCsum; + ULONG enabled_RxCsum; + + VNIC_ENTER( VNIC_DBG_OID ); + + if( !netpath_is_connected( p_adapter->p_currentPath ) ) + { + return NDIS_STATUS_NOT_ACCEPTED; + } + + p_offload_hdr = (NDIS_TASK_OFFLOAD_HEADER*)p_info_buf; + + if( *p_info_len < sizeof(NDIS_TASK_OFFLOAD_HEADER) ) + return NDIS_STATUS_INVALID_LENGTH; + + if( p_offload_hdr->Version != NDIS_TASK_OFFLOAD_VERSION ) + return NDIS_STATUS_INVALID_DATA; + + if( p_offload_hdr->Size != sizeof(NDIS_TASK_OFFLOAD_HEADER) ) + return NDIS_STATUS_INVALID_LENGTH; + + if( !p_offload_hdr->OffsetFirstTask ) + return NDIS_STATUS_SUCCESS; + + if( p_offload_hdr->EncapsulationFormat.Encapsulation != + IEEE_802_3_Encapsulation ) + { + return NDIS_STATUS_INVALID_DATA; + } + + p_offload_task = (NDIS_TASK_OFFLOAD*) + (((UCHAR*)p_offload_hdr) + p_offload_hdr->OffsetFirstTask); + + if( *p_info_len < sizeof(NDIS_TASK_OFFLOAD_HEADER) + + offsetof( NDIS_TASK_OFFLOAD, TaskBuffer ) + + sizeof(NDIS_TASK_TCP_IP_CHECKSUM) ) + { + return NDIS_STATUS_INVALID_LENGTH; + } + + if( p_offload_task->Version != NDIS_TASK_OFFLOAD_VERSION ) + return NDIS_STATUS_INVALID_DATA; + p_offload_chksum = + (NDIS_TASK_TCP_IP_CHECKSUM*)p_offload_task->TaskBuffer; + + enabled_TxCsum = + ( p_adapter->params.UseTxCsum && + netpath_canTxCsum( p_adapter->p_currentPath ) ); + enabled_RxCsum = + ( p_adapter->params.UseRxCsum && + netpath_canRxCsum( p_adapter->p_currentPath ) ); + + if( !enabled_TxCsum && + (p_offload_chksum->V4Transmit.IpOptionsSupported || + p_offload_chksum->V4Transmit.TcpOptionsSupported || + p_offload_chksum->V4Transmit.TcpChecksum || + p_offload_chksum->V4Transmit.UdpChecksum || + p_offload_chksum->V4Transmit.IpChecksum || + p_offload_chksum->V6Transmit.IpOptionsSupported || + p_offload_chksum->V6Transmit.TcpOptionsSupported || + p_offload_chksum->V6Transmit.TcpChecksum || + p_offload_chksum->V6Transmit.UdpChecksum ) ) + { + return NDIS_STATUS_NOT_SUPPORTED; + } + + if( !enabled_RxCsum && + (p_offload_chksum->V4Receive.IpOptionsSupported || + p_offload_chksum->V4Receive.TcpOptionsSupported || + p_offload_chksum->V4Receive.TcpChecksum || + p_offload_chksum->V4Receive.UdpChecksum || + p_offload_chksum->V4Receive.IpChecksum || + p_offload_chksum->V6Receive.IpOptionsSupported || + p_offload_chksum->V6Receive.TcpOptionsSupported || + p_offload_chksum->V6Receive.TcpChecksum || + p_offload_chksum->V6Receive.UdpChecksum ) ) + { + return NDIS_STATUS_NOT_SUPPORTED; + } + + VNIC_EXIT( VNIC_DBG_OID ); + + return NDIS_STATUS_SUCCESS; +} + + +//! Issues a hardware reset to the NIC and/or resets the driver's software state. +/* Tear down the connection and start over again. This is only called when there is a problem. +For example, if a send, query info, or set info had a time out. MiniportCheckForHang will +be called first. +IRQL = DISPATCH_LEVEL + +@param p_addr_resetPointer to BOOLLEAN that is set to TRUE if the NDIS +library should call MiniportSetInformation to restore addressing information to the current values. +@param adapter_context The adapter context allocated at start +@return NDIS_STATUS_SUCCESS, NDIS_STATUS_PENDING, NDIS_STATUS_NOT_RESETTABLE, +NDIS_STATUS_RESET_IN_PROGRESS, NDIS_STATUS_SOFT_ERRORS, NDIS_STATUS_HARD_ERRORS +*/ +NDIS_STATUS +vnic_reset( + OUT PBOOLEAN p_addr_reset, + IN NDIS_HANDLE adapter_context) +{ + vnic_adapter_t* p_adapter; + ib_api_status_t status; + + VNIC_ENTER( VNIC_DBG_INIT ); + + CL_ASSERT( p_addr_reset ); + CL_ASSERT( adapter_context ); + + p_adapter = (vnic_adapter_t*)adapter_context; + + status = adapter_reset( p_adapter ); + VNIC_EXIT( VNIC_DBG_INIT ); + switch( status ) + { + case IB_SUCCESS: + *p_addr_reset = TRUE; + return NDIS_STATUS_SUCCESS; + + case IB_NOT_DONE: + return NDIS_STATUS_PENDING; + + case IB_INVALID_STATE: + return NDIS_STATUS_RESET_IN_PROGRESS; + + default: + return NDIS_STATUS_HARD_ERRORS; + } +} + +//! Request changes in the state information that the miniport driver maintains +/* For example, this is used to set multicast addresses and the packet filter. +IRQL = DISPATCH_LEVEL + +@param adapter_context The adapter context allocated at start +@param oid Object ID representing the set operation to be carried out +@param info_buf Buffer containing input for this set and location for any output +@param info_buf_len Number of bytes available in info_buf +@param p_bytes_read Pointer to number of bytes read from info_buf +@param p_bytes_needed Pointer to number of bytes needed to satisfy this oid +@return NDIS_STATUS_SUCCESS, NDIS_STATUS_PENDING, NDIS_STATUS_INVALID_OID, +NDIS_STATUS_INVALID_LENGTH, NDIS_STATUS_INVALID_DATA, NDIS_STATUS_NOT_ACCEPTED, +NDIS_STATUS_NOT_SUPPORTED, NDIS_STATUS_RESOURCES +*/ +NDIS_STATUS +vnic_oid_set_info( + IN NDIS_HANDLE adapter_context, + IN NDIS_OID oid, + IN PVOID info_buf, + IN ULONG info_buf_len, + OUT PULONG p_bytes_read, + OUT PULONG p_bytes_needed ) +{ + vnic_adapter_t* p_adapter; + Netpath_t* p_netpath; + NDIS_STATUS status; + ULONG buf_len; + pending_oid_t oid_info; + + VNIC_ENTER( VNIC_DBG_OID ); + + CL_ASSERT( adapter_context ); + CL_ASSERT( p_bytes_read ); + CL_ASSERT( p_bytes_needed ); + + p_adapter = (vnic_adapter_t*)adapter_context; + CL_ASSERT( !p_adapter->pending_set ); + + p_netpath = p_adapter->p_currentPath; + /* do not set anything until IB path initialized and NIC is enabled */ + if( !netpath_is_valid( p_netpath ) || !p_netpath->carrier ) + { + *p_bytes_read = 0; + return NDIS_STATUS_NOT_ACCEPTED; + } + + status = NDIS_STATUS_SUCCESS; + *p_bytes_needed = 0; + buf_len = sizeof(ULONG); + + oid_info.oid = oid; + oid_info.p_buf = info_buf; + oid_info.buf_len = info_buf_len; + oid_info.p_bytes_used = p_bytes_read; + oid_info.p_bytes_needed = p_bytes_needed; + + switch( oid ) + { + /* Required General */ + case OID_GEN_CURRENT_PACKET_FILTER: + VNIC_TRACE( VNIC_DBG_OID, + (" IOC %d received set for OID_GEN_CURRENT_PACKET_FILTER, %#x\n", + p_netpath->pViport->ioc_num, *(uint32_t*)info_buf ) ); + + if( info_buf_len < sizeof( p_adapter->packet_filter ) ) + { + status = NDIS_STATUS_INVALID_LENGTH; + } + else if( !info_buf ) + { + status = NDIS_STATUS_INVALID_DATA; + } + else + { + p_adapter->set_oid = oid_info; + status = _vnic_process_packet_filter( p_adapter, *((ULONG*)info_buf) ); + } + break; + + case OID_GEN_CURRENT_LOOKAHEAD: + VNIC_TRACE( VNIC_DBG_OID, + (" received set for OID_GEN_CURRENT_LOOKAHEAD\n" )); + if( info_buf_len < buf_len ) + status = NDIS_STATUS_INVALID_LENGTH; + break; + + case OID_GEN_PROTOCOL_OPTIONS: + VNIC_TRACE( VNIC_DBG_OID, + (" received set for OID_GEN_PROTOCOL_OPTIONS\n" )); + if( info_buf_len < buf_len ) + status = NDIS_STATUS_INVALID_LENGTH; + break; + +#ifdef NDIS51_MINIPORT + case OID_GEN_MACHINE_NAME: + VNIC_TRACE( VNIC_DBG_OID, + (" received set for OID_GEN_MACHINE_NAME\n" ) ); + if( info_buf_len < buf_len ) + status = NDIS_STATUS_INVALID_LENGTH; + // else + // status = __vnic_set_machine_name( info_buf, + // (USHORT)info_buf_len ); + break; +#endif + + /* Required Ethernet operational characteristics */ + case OID_802_3_MULTICAST_LIST: + if( !p_adapter->p_currentPath->carrier ) + { + status = NDIS_STATUS_NOT_ACCEPTED; + break; + } + VNIC_TRACE( VNIC_DBG_OID, + (" IOC %d received set for OID_802_3_MULTICAST_LIST\n", + p_adapter->p_currentPath->pViport->ioc_num ) ); + if( info_buf_len > MAX_MCAST * sizeof(mac_addr_t) ) + { + VNIC_TRACE( VNIC_DBG_OID, + (" OID_802_3_MULTICAST_LIST - Multicast list full.\n" ) ); + status = NDIS_STATUS_MULTICAST_FULL; + *p_bytes_needed = MAX_MCAST * sizeof(mac_addr_t); + } + else if( info_buf_len % sizeof(mac_addr_t) ) + { + VNIC_TRACE( VNIC_DBG_OID, + (" OID_802_3_MULTICAST_LIST - Invalid input buffer length.\n" ) ); + status = NDIS_STATUS_INVALID_DATA; + } + else if( info_buf == NULL && info_buf_len != 0 ) + { + VNIC_TRACE( VNIC_DBG_OID, + (" OID_802_3_MULTICAST_LIST - Invalid input buffer.\n" ) ); + status = NDIS_STATUS_INVALID_DATA; + } + else + { + p_adapter->set_oid = oid_info; + status = adapter_set_mcast( p_adapter, (mac_addr_t*)info_buf, + (uint8_t)(info_buf_len / sizeof(mac_addr_t)) ); + } + break; + + case OID_TCP_TASK_OFFLOAD: + VNIC_TRACE( VNIC_DBG_OID, + (" received set for OID_TCP_TASK_OFFLOAD\n" ) ); + buf_len = info_buf_len; + status = __vnic_set_tcp_task_offload( p_adapter, info_buf, &buf_len ); + break; + + /* Optional General */ + case OID_GEN_TRANSPORT_HEADER_OFFSET: + VNIC_TRACE( VNIC_DBG_OID, + ("Set for OID_GEN_TRANSPORT_HEADER_OFFSET\n") ); + break; + case OID_GEN_VLAN_ID: + if( info_buf_len != 4 ) + { + status = NDIS_STATUS_INVALID_LENGTH; + break; + } + if( *(( uint32_t *)info_buf) < 4095 ) + { + p_adapter->vlan_info = *((uint32_t*)info_buf ); + } + else + { + status = NDIS_STATUS_INVALID_DATA; + } + break; + + case OID_GEN_SUPPORTED_LIST: + case OID_GEN_HARDWARE_STATUS: + case OID_GEN_MEDIA_SUPPORTED: + case OID_GEN_MEDIA_IN_USE: + case OID_GEN_MAXIMUM_FRAME_SIZE: + case OID_GEN_LINK_SPEED: + case OID_GEN_TRANSMIT_BUFFER_SPACE: + case OID_GEN_RECEIVE_BUFFER_SPACE: + case OID_GEN_MAXIMUM_LOOKAHEAD: + case OID_GEN_TRANSMIT_BLOCK_SIZE: + case OID_GEN_RECEIVE_BLOCK_SIZE: + case OID_GEN_MAXIMUM_TOTAL_SIZE: + case OID_GEN_VENDOR_ID: + case OID_GEN_VENDOR_DESCRIPTION: + case OID_GEN_VENDOR_DRIVER_VERSION: + case OID_GEN_DRIVER_VERSION: + case OID_GEN_MAC_OPTIONS: + case OID_GEN_MEDIA_CONNECT_STATUS: + case OID_GEN_MAXIMUM_SEND_PACKETS: + case OID_GEN_SUPPORTED_GUIDS: + case OID_GEN_PHYSICAL_MEDIUM: + default: + status = NDIS_STATUS_INVALID_OID; + VNIC_TRACE( VNIC_DBG_OID, + (" received an invalid oid of 0x%.8X!\n" , oid)); + break; + } + + if( status == NDIS_STATUS_SUCCESS ) + { + *p_bytes_read = buf_len; + } + else + { + if( status == NDIS_STATUS_INVALID_LENGTH ) + { + if ( !*p_bytes_needed ) + { + *p_bytes_needed = buf_len; + } + } + + *p_bytes_read = 0; + } + + VNIC_EXIT( VNIC_DBG_OID ); + return status; +} + + +//! Transfers some number of packets, specified as an array of packet pointers, over the network. +/* For a deserialized driver, these packets are completed asynchronously +using NdisMSendComplete. +IRQL <= DISPATCH_LEVEL + +@param adapter_context Pointer to vnic_adapter_t structure with per NIC state +@param packet_array Array of packets to send +@param numPackets Number of packets in the array +*/ +void +vnic_send_packets( + IN NDIS_HANDLE adapter_context, + IN PPNDIS_PACKET packet_array, + IN UINT num_packets ) +{ + vnic_adapter_t* const p_adapter =(vnic_adapter_t* const )adapter_context; + UINT packet_num; + + VNIC_ENTER( VNIC_DBG_SEND ); + + CL_ASSERT( adapter_context ); + + for( packet_num = 0; packet_num < num_packets; ++packet_num ) + { + netpath_xmitPacket( p_adapter->p_currentPath, + packet_array[packet_num] ); + } + VNIC_EXIT( VNIC_DBG_SEND ); +} + +void vnic_cancel_xmit( + IN NDIS_HANDLE adapter_context, + IN PVOID cancel_id ) +{ + vnic_adapter_t* const p_adapter =(vnic_adapter_t* const )adapter_context; + + if( p_adapter && + p_adapter->p_currentPath ) + { + netpath_cancel_xmit( p_adapter->p_currentPath, cancel_id ); + } +} + +void +vnic_pnp_notify( + IN NDIS_HANDLE adapter_context, + IN NDIS_DEVICE_PNP_EVENT pnp_event, + IN PVOID info_buf, + IN ULONG info_buf_len ) +{ + vnic_adapter_t *p_adapter; + + VNIC_ENTER( VNIC_DBG_PNP ); + + UNUSED_PARAM( info_buf ); + UNUSED_PARAM( info_buf_len ); + + p_adapter = (vnic_adapter_t*)adapter_context; + + CL_ASSERT( p_adapter ); + + VNIC_TRACE( VNIC_DBG_PNP, ("Event %d for IOC[%d] in state %#x\n", + pnp_event, p_adapter->ioc_num, p_adapter->pnp_state ) ); + + switch ( pnp_event ) + { + case NdisDevicePnPEventPowerProfileChanged: + break; + case NdisDevicePnPEventQueryRemoved: + case NdisDevicePnPEventRemoved: + case NdisDevicePnPEventSurpriseRemoved: + case NdisDevicePnPEventQueryStopped: + case NdisDevicePnPEventStopped: + case NdisDevicePnPEventMaximum: + + if( InterlockedExchange( (volatile LONG*)&p_adapter->pnp_state, IB_PNP_IOC_REMOVE ) == IB_PNP_IOC_ADD ) + { + if( netpath_is_valid( p_adapter->p_currentPath ) ) + { + netpath_stopXmit( p_adapter->p_currentPath ); + InterlockedExchange( &p_adapter->p_currentPath->carrier, (LONG)FALSE ); + netpath_linkDown( p_adapter->p_currentPath ); + __pending_queue_cleanup( p_adapter ); + } + } + vnic_resume_oids( p_adapter ); + break; + } + + VNIC_EXIT( VNIC_DBG_PNP ); +} + + +void +vnic_shutdown( + IN PVOID adapter_context ) +{ + vnic_adapter_t *p_adapter; + Netpath_t *p_netpath; + + VNIC_ENTER( VNIC_DBG_INIT ); + p_adapter = (vnic_adapter_t *)adapter_context; + + if( p_adapter ) + { + g_vnic.shutdown = p_adapter->ioc_num; + VNIC_TRACE( VNIC_DBG_INIT, + ("IOC[%d] going to Shutdown\n", p_adapter->ioc_num )); + p_netpath = p_adapter->p_currentPath; + + if( p_netpath && p_netpath->pViport ) + { + netpath_stopXmit( p_netpath ); + InterlockedExchange( &p_netpath->carrier, (LONG)FALSE ); + netpath_linkDown( p_netpath ); + } + + vnic_destroy_adapter( p_adapter ); + } + + VNIC_EXIT( VNIC_DBG_INIT ); +} + + +void +vnic_resume_set_oids( + IN vnic_adapter_t* const p_adapter ) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + BOOLEAN pending_set; + pending_oid_t set_oid = {0}; + + Netpath_t* p_netpath; + VNIC_ENTER( VNIC_DBG_OID ); + + if( !p_adapter->pending_set ) + { + VNIC_EXIT( VNIC_DBG_OID ); + return; + } + NdisAcquireSpinLock( &p_adapter->lock ); + p_netpath = p_adapter->p_currentPath; + VNIC_TRACE( VNIC_DBG_OID, + ("IOC[%d]Resume Set OID %#x\n", + p_adapter->ioc_num, p_adapter->set_oid.oid )); + /* + * Set the status depending on our state. Fail OID requests that + * are pending while we reset the adapter. + */ + if( p_adapter->pnp_state != IB_PNP_IOC_REMOVE && + netpath_is_connected( p_netpath ) ) + { + status = NDIS_STATUS_SUCCESS; + } + else + { + status = NDIS_STATUS_NOT_ACCEPTED; + if( p_adapter->pending_set ) + { + VNIC_TRACE( VNIC_DBG_PNP, + ("IOC[%d]Pending set OID %#x while removing \n", + p_adapter->ioc_num, p_adapter->set_oid.oid )); + } + } + + pending_set = p_adapter->pending_set; + if( pending_set ) + { + set_oid = p_adapter->set_oid; + p_adapter->pending_set = FALSE; + } + NdisReleaseSpinLock( &p_adapter->lock ); + + ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL ); + + if( pending_set && status == NDIS_STATUS_SUCCESS ) + { + switch( set_oid.oid ) + { + case OID_GEN_CURRENT_PACKET_FILTER: + VNIC_TRACE( VNIC_DBG_OID, + (" IOC %d resume PACKET_FILTER set \n", + p_netpath->pViport->ioc_num ) ); + /* Validation already performed in the SetInformation path. */ + p_adapter->packet_filter = *(PULONG)set_oid.p_buf; + break; + + case OID_GEN_MACHINE_NAME: + status = __vnic_set_machine_name ( p_adapter->set_oid.p_buf, (USHORT)p_adapter->set_oid.buf_len ); + break; + + case OID_802_3_MULTICAST_LIST: + VNIC_TRACE( VNIC_DBG_OID, + (" IOC %d resume MULTICAST_LIST\n", + p_netpath->pViport->ioc_num ) ); + break; + + default: + CL_ASSERT( set_oid.oid && 0 ); + break; + } + } + + if( !netpath_is_connected( p_netpath ) ) + { + NdisMSetInformationComplete( p_adapter->h_handle, + NDIS_STATUS_NOT_ACCEPTED ); + } + else + NdisMSetInformationComplete( p_adapter->h_handle, status ); + + VNIC_EXIT( VNIC_DBG_OID ); +} + + +void +vnic_resume_oids( + IN vnic_adapter_t* const p_adapter ) +{ + ULONG info; + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + BOOLEAN pending_query; + pending_oid_t query_oid = {0}; + KIRQL irql; + + Netpath_t* p_netpath = p_adapter->p_currentPath; + + uint8_t mac[HW_ADDR_LEN]; + + VNIC_ENTER( VNIC_DBG_OID ); + + NdisAcquireSpinLock( &p_adapter->lock ); + /* + * Set the status depending on our state. Fail OID requests that + * are pending while we reset the adapter. + */ + if( !netpath_is_connected( p_netpath ) ) + { + status = NDIS_STATUS_NOT_ACCEPTED; + } + + switch( p_adapter->pnp_state ) + { + case IB_PNP_IOC_ADD: + break; + + case IB_PNP_IOC_REMOVE: + default: + status = NDIS_STATUS_NOT_ACCEPTED; + break; + } + + pending_query = p_adapter->pending_query; + + if( pending_query ) + { + query_oid = p_adapter->query_oid; + p_adapter->pending_query = FALSE; + } + NdisReleaseSpinLock( &p_adapter->lock ); + + KeRaiseIrql( DISPATCH_LEVEL, &irql ); + + /* + * If we had a pending OID request for OID_GEN_LINK_SPEED, + * complete it now. Note that we hold the object lock since + * NdisMQueryInformationComplete is called at DISPATCH_LEVEL. + */ + if( pending_query ) + { + switch( query_oid.oid ) + { + case OID_802_3_CURRENT_ADDRESS: + case OID_802_3_PERMANENT_ADDRESS: + if ( status == NDIS_STATUS_SUCCESS ) + { + cl_memcpy( mac, p_netpath->pViport->hwMacAddress, HW_ADDR_LEN ); + } + _vnic_complete_query( p_adapter, + &query_oid, + status, + mac, + HW_ADDR_LEN ); + break; + case OID_GEN_LINK_SPEED: + info = DEFAULT_LINK_SPEED_x100BPS; + _vnic_complete_query( p_adapter, + &query_oid, + status, + &info, + sizeof( info ) ); + break; + + case OID_GEN_MEDIA_CONNECT_STATUS: + info = ( p_adapter->carrier )? NdisMediaStateConnected : + NdisMediaStateDisconnected; + _vnic_complete_query( p_adapter, + &query_oid, + status, + &info, + sizeof( info ) ); + break; + case OID_802_3_MULTICAST_LIST: + _vnic_complete_query( p_adapter, + &query_oid, + status, + p_netpath->p_adapter->mcast_array, + p_adapter->mc_count * sizeof( mac_addr_t ) ); + break; + case OID_GEN_TRANSMIT_BUFFER_SPACE: + if( status == NDIS_STATUS_SUCCESS ) + { + info = p_netpath->pViport->data.xmitPool.bufferSz * + p_netpath->pViport->data.xmitPool.numXmitBufs; + } + else + { + info = 0; + } + _vnic_complete_query( p_adapter, + &query_oid, + status, + &info, + sizeof( info ) ); + break; + case OID_GEN_RECEIVE_BUFFER_SPACE: + if( status == NDIS_STATUS_SUCCESS ) + { + info = p_netpath->pViport->data.recvPool.bufferSz * + p_netpath->pViport->data.recvPool.poolSz; + } + else + { + info = 0; + } + _vnic_complete_query( p_adapter, + &query_oid, + status, + &info, + sizeof( info ) ); + break; + default: + CL_ASSERT( query_oid.oid == OID_GEN_LINK_SPEED || + query_oid.oid == OID_GEN_MEDIA_CONNECT_STATUS || + query_oid.oid == OID_802_3_MULTICAST_LIST || + query_oid.oid == OID_802_3_CURRENT_ADDRESS || + query_oid.oid == OID_802_3_PERMANENT_ADDRESS || + query_oid.oid == OID_GEN_RECEIVE_BUFFER_SPACE || + query_oid.oid == OID_GEN_TRANSMIT_BUFFER_SPACE ); + break; + } + } + + vnic_resume_set_oids( p_adapter ); + + KeLowerIrql( irql ); + + VNIC_EXIT( VNIC_DBG_OID ); +} + +static NDIS_STATUS +__vnic_set_machine_name( + IN VOID *p_uni_array, + IN USHORT buf_size ) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + uint8_t *p_src_buf = (uint8_t *)p_uni_array; + uint32_t i; + + VNIC_ENTER( VNIC_DBG_OID ); + + if( buf_size > 0 ) + { + cl_memclr(g_vnic.host_name, sizeof( g_vnic.host_name ) ); + for( i = 0; i < min( ( buf_size > 1 ), sizeof( g_vnic.host_name ) ); i++ ) + { + g_vnic.host_name[i] = *(p_src_buf + i*2); + } + } + + return status; +} + +static void +__vnic_read_machine_name( void ) +{ + /* this code is borrowed from the bus_driver */ + + NTSTATUS nt_status; + /* Remember the terminating entry in the table below. */ + RTL_QUERY_REGISTRY_TABLE table[2]; + UNICODE_STRING hostNamePath; + UNICODE_STRING hostNameW; + ANSI_STRING hostName; + + VNIC_ENTER( VNIC_DBG_INIT ); + + /* Get the host name. */ + RtlInitUnicodeString( &hostNamePath, L"ComputerName\\ComputerName" ); + RtlInitUnicodeString( &hostNameW, NULL ); + + /* + * Clear the table. This clears all the query callback pointers, + * and sets up the terminating table entry. + */ + cl_memclr( table, sizeof(table) ); + + /* Setup the table entries. */ + table[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED; + table[0].Name = L"ComputerName"; + table[0].EntryContext = &hostNameW; + table[0].DefaultType = REG_SZ; + table[0].DefaultData = &hostNameW; + table[0].DefaultLength = 0; + + /* Have at it! */ + nt_status = RtlQueryRegistryValues( RTL_REGISTRY_CONTROL, + hostNamePath.Buffer, table, NULL, NULL ); + if( NT_SUCCESS( nt_status ) ) + { + /* Convert the UNICODE host name to UTF-8 (ASCII). */ + hostName.Length = 0; + hostName.MaximumLength = sizeof(g_vnic.host_name) - 1; + hostName.Buffer = (PCHAR)g_vnic.host_name; + nt_status = RtlUnicodeStringToAnsiString( &hostName, &hostNameW, FALSE ); + RtlFreeUnicodeString( &hostNameW ); + } + else + { + VNIC_TRACE(VNIC_DBG_ERROR , ("Failed to get host name from registry\n") ); + /* Use the default name... */ + cl_memcpy( g_vnic.host_name, + DEFAULT_HOST_NAME, + min (sizeof( g_vnic.host_name), sizeof(DEFAULT_HOST_NAME) ) ); + } + + VNIC_EXIT( VNIC_DBG_INIT ); +} + +/* function: usec_timer_start + uses cl_timer* functionality (init/destroy/stop/start ) + except it takes expiration time parameter in microseconds. +*/ +cl_status_t +usec_timer_start( + IN cl_timer_t* const p_timer, + IN const uint32_t time_usec ) +{ + LARGE_INTEGER due_time; + + CL_ASSERT( p_timer ); + CL_ASSERT( p_timer->pfn_callback ); + CL_ASSERT( KeGetCurrentIrql() <= DISPATCH_LEVEL ); + + /* Due time is in 100 ns increments. Negative for relative time. */ + due_time.QuadPart = -(int64_t)(((uint64_t)time_usec) * 10); + + /* Store the timeout time in the timer object. in microseconds */ + p_timer->timeout_time = cl_get_time_stamp() + (((uint64_t)time_usec)); + + KeSetTimer( &p_timer->timer, due_time, &p_timer->dpc ); + return( CL_SUCCESS ); +} + + +static NDIS_STATUS +_vnic_process_packet_filter( + IN vnic_adapter_t* const p_adapter, + IN ULONG pkt_filter ) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + viport_t *p_viport; + ULONG need_updates = 0; + + VNIC_ENTER(VNIC_DBG_FUNC ); + + ASSERT( p_adapter ); + + p_viport = p_adapter->p_currentPath->pViport; + + ASSERT( p_viport ); + ASSERT( !( p_viport->updates & SYNC_QUERY ) ); + + if( ( InterlockedExchange( + (volatile LONG*)&p_adapter->packet_filter, pkt_filter )) == (LONG)pkt_filter ) + { + InterlockedExchange( &p_viport->updates, 0 ); + return status; + } + + ASSERT( (p_viport->updates & ~MCAST_OVERFLOW) == 0 ); + + if( pkt_filter ) + { + if( !( p_viport->flags & INIC_FLAG_ENABLE_NIC ) ) + { + p_viport->newFlags &= ~INIC_FLAG_DISABLE_NIC; + p_viport->newFlags |= INIC_FLAG_ENABLE_NIC | INIC_FLAG_SET_MTU; + p_viport->newMtu = (uint16_t)p_adapter->params.MinMtu; + InterlockedOr( (volatile LONG*)&need_updates, NEED_LINK_CONFIG ); + } + + if( pkt_filter & NDIS_PACKET_TYPE_ALL_MULTICAST ) + { + if( !( p_viport->flags & INIC_FLAG_ENABLE_MCAST_ALL ) ) + { + p_viport->newFlags &= ~INIC_FLAG_DISABLE_MCAST_ALL; + p_viport->newFlags |= INIC_FLAG_ENABLE_MCAST_ALL; + InterlockedOr( (volatile LONG*)&need_updates, + NEED_LINK_CONFIG | MCAST_OVERFLOW ); + } + } + else + { + if( p_viport->flags & NDIS_PACKET_TYPE_ALL_MULTICAST ) + { + p_viport->newFlags &= ~INIC_FLAG_ENABLE_MCAST_ALL; + p_viport->newFlags |= INIC_FLAG_DISABLE_MCAST_ALL; + InterlockedOr( (volatile LONG*)&need_updates, NEED_LINK_CONFIG ); + } + } + + if ( pkt_filter & NDIS_PACKET_TYPE_PROMISCUOUS ) + { + if( !( p_viport->flags & INIC_FLAG_ENABLE_PROMISC ) ) + { + p_viport->newFlags &= ~INIC_FLAG_DISABLE_PROMISC; + p_viport->newFlags |= INIC_FLAG_ENABLE_PROMISC; + InterlockedOr( (volatile LONG*)&need_updates, NEED_LINK_CONFIG ); + } + } + else + { + if( p_viport->flags & INIC_FLAG_ENABLE_PROMISC ) + { + p_viport->newFlags &= ~INIC_FLAG_ENABLE_PROMISC; + p_viport->newFlags |= INIC_FLAG_DISABLE_PROMISC; + InterlockedOr( (volatile LONG*)&need_updates, NEED_LINK_CONFIG ); + } + } + } + + /* ENABLE NIC, BROADCAST and MULTICAST flags set on start */ + if( need_updates ) + { + p_adapter->pending_set = TRUE; + InterlockedOr( &p_viport->updates, need_updates ); + + status = _viport_process_query( p_viport, FALSE ); + VNIC_TRACE( VNIC_DBG_OID, + ("LINK CONFIG status %x\n", status )); + if( status != NDIS_STATUS_PENDING ) + { + p_adapter->pending_set = FALSE; + } + } + + VNIC_EXIT( VNIC_DBG_FUNC ); + return status; +} + +static NTSTATUS +__vnic_read_service_registry( + IN UNICODE_STRING* const p_registry_path ) +{ + NTSTATUS status; + RTL_QUERY_REGISTRY_TABLE table[VNIC_REGISTRY_TBL_SIZE + 1]; + UNICODE_STRING param_path; + ULONG _reg_dbg_lvl = 0; + int i; + + RtlInitUnicodeString( ¶m_path, NULL ); + param_path.MaximumLength = + p_registry_path->Length + sizeof(L"\\Parameters"); + + param_path.Buffer = cl_zalloc( param_path.MaximumLength ); + if( !param_path.Buffer ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + ("Failed to allocate parameters path buffer.\n") ); + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlAppendUnicodeStringToString( ¶m_path, p_registry_path ); + RtlAppendUnicodeToString( ¶m_path, L"\\Parameters" ); + + cl_memclr( table, sizeof(table) ); + + /* init debug flags entry */ + table[0].Flags = RTL_QUERY_REGISTRY_DIRECT; + table[0].Name = L"DebugFlags"; + table[0].EntryContext = &_reg_dbg_lvl; + table[0].DefaultType = REG_DWORD; + table[0].DefaultData = &_reg_dbg_lvl; + table[0].DefaultLength = sizeof(ULONG); + + /* Setup the rest of table entries. */ + for ( i = 1; i < VNIC_REGISTRY_TBL_SIZE; i++ ) + { + table[i].Flags = RTL_QUERY_REGISTRY_DIRECT; + table[i].Name = reg_array[i].name; + table[i].EntryContext = ®_array[i].value; + table[i].DefaultType = REG_DWORD; + table[i].DefaultData = ®_array[i].value; + table[i].DefaultLength = sizeof(ULONG); + } + + status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE, + param_path.Buffer, table, NULL, NULL ); + + if( status == STATUS_SUCCESS ) + { + g_vnic_dbg_lvl |= _reg_dbg_lvl; + VNIC_TRACE(VNIC_DBG_INFO, ("DebugFlags Set %#x\n",g_vnic_dbg_lvl )); + g_vnic.p_params = reg_array; + } + + cl_free( param_path.Buffer ); + + return status; +} diff --git a/branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_driver.h b/branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_driver.h new file mode 100644 index 00000000..fe1ab950 --- /dev/null +++ b/branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_driver.h @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2007 QLogic Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#ifndef _VNIC_DRIVER_H_ +#define _VNIC_DRIVER_H_ + +#include "vnic_adapter.h" +#include "vnic_debug.h" + + +#if defined(NDIS50_MINIPORT) +#define MAJOR_NDIS_VERSION 5 +#define MINOR_NDIS_VERSION 0 +#elif defined (NDIS51_MINIPORT) +#define MAJOR_NDIS_VERSION 5 +#define MINOR_NDIS_VERSION 1 +#else +#error NDIS Version not defined, try defining NDIS50_MINIPORT or NDIS51_MINIPORT +#endif + +#include + +static const NDIS_OID SUPPORTED_OIDS[] = +{ + OID_GEN_SUPPORTED_LIST, + OID_GEN_HARDWARE_STATUS, + OID_GEN_MEDIA_SUPPORTED, + OID_GEN_MEDIA_IN_USE, + OID_GEN_MAXIMUM_LOOKAHEAD, + OID_GEN_MAXIMUM_FRAME_SIZE, + OID_GEN_LINK_SPEED, + OID_GEN_TRANSMIT_BUFFER_SPACE, + OID_GEN_RECEIVE_BUFFER_SPACE, + OID_GEN_TRANSMIT_BLOCK_SIZE, + OID_GEN_RECEIVE_BLOCK_SIZE, + OID_GEN_VENDOR_ID, + OID_GEN_VENDOR_DESCRIPTION, + OID_GEN_CURRENT_PACKET_FILTER, + OID_GEN_CURRENT_LOOKAHEAD, + OID_GEN_DRIVER_VERSION, + OID_GEN_MAXIMUM_TOTAL_SIZE, + OID_GEN_PROTOCOL_OPTIONS, // ? + OID_GEN_MAC_OPTIONS, + OID_GEN_MEDIA_CONNECT_STATUS, + OID_GEN_MAXIMUM_SEND_PACKETS, + OID_GEN_VENDOR_DRIVER_VERSION, + OID_GEN_PHYSICAL_MEDIUM, + OID_GEN_XMIT_OK, + OID_GEN_RCV_OK, + OID_GEN_XMIT_ERROR, + OID_GEN_RCV_ERROR, + OID_GEN_RCV_NO_BUFFER, + OID_GEN_DIRECTED_BYTES_XMIT, + OID_GEN_DIRECTED_FRAMES_XMIT, + OID_GEN_MULTICAST_BYTES_XMIT, + OID_GEN_MULTICAST_FRAMES_XMIT, + OID_GEN_BROADCAST_BYTES_XMIT, + OID_GEN_BROADCAST_FRAMES_XMIT, + OID_GEN_DIRECTED_BYTES_RCV, + OID_GEN_DIRECTED_FRAMES_RCV, + OID_GEN_MULTICAST_BYTES_RCV, + OID_GEN_MULTICAST_FRAMES_RCV, + OID_GEN_BROADCAST_BYTES_RCV, + OID_GEN_BROADCAST_FRAMES_RCV, + OID_GEN_VLAN_ID, + OID_802_3_PERMANENT_ADDRESS, + OID_802_3_CURRENT_ADDRESS, + OID_802_3_MULTICAST_LIST, + OID_802_3_MAXIMUM_LIST_SIZE, + OID_802_3_MAC_OPTIONS, + OID_802_3_RCV_ERROR_ALIGNMENT, + OID_802_3_XMIT_ONE_COLLISION, + OID_802_3_XMIT_MORE_COLLISIONS, + OID_TCP_TASK_OFFLOAD +}; + +static const unsigned char VENDOR_ID[] = {0x00, 0x06, 0x6A, 0x00}; +#define VENDOR_DESCRIPTION "Virtual Ethernet over InfiniBand" +#define DEFAULT_VNIC_NAME "VNIC" + +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT p_drv_obj, + IN PUNICODE_STRING p_reg_path ); + +VOID +vnic_unload( + IN PDRIVER_OBJECT p_drv_obj ); + +NDIS_STATUS +vnic_initialize( + OUT PNDIS_STATUS p_open_err_status, + OUT PUINT p_selected_medium_index, + IN PNDIS_MEDIUM medium_array, + IN UINT medium_array_size, + IN NDIS_HANDLE h_handle, + IN NDIS_HANDLE wrapper_configuration_context ); + +BOOLEAN +vnic_check_for_hang( + IN NDIS_HANDLE adapter_context ); + +void +vnic_halt( + IN NDIS_HANDLE adapter_context ); + +NDIS_STATUS +vnic_oid_query_info( + IN NDIS_HANDLE adapter_context, + IN NDIS_OID oid, + IN PVOID info_buf, + IN ULONG info_buf_len, + OUT PULONG p_bytes_written, + OUT PULONG p_bytes_needed ); + +NDIS_STATUS +vnic_reset( + OUT PBOOLEAN p_addressing_reset, + IN NDIS_HANDLE adapter_context ); + +NDIS_STATUS +vnic_oid_set_info( + IN NDIS_HANDLE adapter_context, + IN NDIS_OID oid, + IN PVOID info_buf, + IN ULONG info_buf_length, + OUT PULONG p_bytes_read, + OUT PULONG p_bytes_needed ); + +void +vnic_send_packets( + IN NDIS_HANDLE adapter_context, + IN PPNDIS_PACKET packet_array, + IN UINT num_packets ); + +void +vnic_cancel_xmit( + IN NDIS_HANDLE adapter_context, + IN PVOID cancel_id ); +void +vnic_pnp_notify( + IN NDIS_HANDLE adapter_context, + IN NDIS_DEVICE_PNP_EVENT pnp_event, + IN PVOID info_buf, + IN ULONG info_buf_len ); + +void +vnic_shutdown( + IN PVOID adapter_context ); + +NDIS_STATUS +vnic_get_agapter_interface( + IN NDIS_HANDLE h_handle, + IN vnic_adapter_t *p_adapter); + + +/* same as cl_timer_start() except it takes timeout param in usec */ +/* need to run kicktimer */ +cl_status_t +usec_timer_start( + IN cl_timer_t* const p_timer, + IN const uint32_t time_usec ); + +#endif /* _VNIC_DRIVER_H_ */ diff --git a/branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_ib.c b/branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_ib.c new file mode 100644 index 00000000..b902e784 --- /dev/null +++ b/branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_ib.c @@ -0,0 +1,921 @@ +/* + * Copyright (c) 2007 QLogic Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ +#include "vnic_adapter.h" +#include "vnic_util.h" + +#ifndef max_t +#define max_t(type,x,y) \ + ({ type __x = (x); type __y = (y); __x > __y ? __x: __y; }) +#endif + + +static int inicIbInited = 0; + +extern struct _vnic_globals g_vnic; + +void +ib_asyncEvent( + ib_async_event_rec_t *pEventRecord ); + +static void +_ib_qpCompletion( + IN IbQp_t *pQp); +static void +_ibqp_connect_cb( + IN ib_cm_rep_rec_t *p_cm_rep ); + +static void +_ibqp_detach_cb( + IN ib_cm_drep_rec_t *p_drep_rec ); + +static void +_ibqp_dreq_cb( + IN ib_cm_dreq_rec_t *p_dreq_rec ); + +static void +_ibqp_mra_cb( + IN ib_cm_mra_rec_t *p_mra_rec ); + +static void +_ibqp_rej_cb( + IN ib_cm_rej_rec_t *p_rej_rec ); +static +void ib_workCompletion( + IN ib_cq_handle_t h_cq, + IN void *cqContext ); + + +uint8_t +ibca_findPortNum( + struct _viport *p_viport, + uint64_t guid ) +{ + uint8_t port; + + for (port = 0; port < p_viport->p_adapter->ca.numPorts; port++ ) + { + if (p_viport->p_adapter->ca.portGuids[port] == guid ) + { + return port+1; + } + } + return 0; +} + +ib_api_status_t +ibregion_physInit( + IN struct _vnic_adapter* p_adapter, + IN IbRegion_t *pRegion, + IN ib_pd_handle_t hPd, + IN uint64_t *p_vaddr, + IN uint64_t len ) +{ + ib_phys_create_t phys_mem; + ib_phys_range_t phys_range; + ib_api_status_t ib_status = IB_SUCCESS; + uint64_t vaddr = 0; + VNIC_ENTER ( VNIC_DBG_IB ); + + UNUSED_PARAM( p_vaddr ); + + phys_range.base_addr = *(p_vaddr); + phys_range.size = len; + phys_mem.access_ctrl = ( IB_AC_LOCAL_WRITE | IB_AC_RDMA_WRITE ); + phys_mem.buf_offset = 0; + phys_mem.hca_page_size = PAGE_SIZE; + phys_mem.length = len; + phys_mem.num_ranges = 1; + phys_mem.range_array = &phys_range; + + ib_status = p_adapter->ifc.reg_phys( hPd, + &phys_mem, + &vaddr, + &pRegion->lkey, + &pRegion->rkey, + &pRegion->h_mr ); + + if ( ib_status != IB_SUCCESS ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + ("ib_reg_phys failed status %s(%d)\n", + p_adapter->ifc.get_err_str(ib_status), ib_status ) ); + pRegion->h_mr = NULL; + } + else + { + pRegion->virtAddress = vaddr; + pRegion->len = len; + } + + VNIC_EXIT( VNIC_DBG_IB ); + return ib_status; +} + +ib_api_status_t +ibregion_init ( + IN viport_t *p_viport, + IN OUT IbRegion_t *pRegion, + IN ib_pd_handle_t hPd, + IN void* vaddr, + IN uint64_t len, + IN ib_access_t access_ctrl ) +{ + ib_api_status_t ib_status; + ib_mr_create_t create_mem; + + VNIC_ENTER ( VNIC_DBG_IB ); + + create_mem.length = len; + create_mem.vaddr = vaddr; + create_mem.access_ctrl = access_ctrl; + + ib_status = p_viport->p_adapter->ifc.reg_mem( hPd, + &create_mem, + &pRegion->lkey, + &pRegion->rkey, + &pRegion->h_mr ); + if ( ib_status != IB_SUCCESS ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + ("ib_reg_mem failed status %s(%d)\n", + p_viport->p_adapter->ifc.get_err_str( ib_status ), ib_status )); + pRegion->h_mr = NULL; + } + else + { + pRegion->len = len; + pRegion->virtAddress = (ULONG_PTR)vaddr; + } + VNIC_EXIT ( VNIC_DBG_IB ); + return ib_status; +} + +void +ibregion_cleanup( + IN viport_t *p_viport, + IN IbRegion_t *pRegion ) +{ + ib_api_status_t ib_status; + + VNIC_ENTER( VNIC_DBG_IB ); + + if( pRegion->h_mr != NULL ) + { + ib_status = p_viport->p_adapter->ifc.dereg_mr( pRegion->h_mr ); + if ( ib_status != IB_SUCCESS ) + { + VNIC_TRACE_EXIT( VNIC_DBG_ERROR, + ("Dereg MR failed status (%d)\n", ib_status )); + } + pRegion->h_mr = NULL; + } + + VNIC_EXIT( VNIC_DBG_IB ); +} + + +void +ibqp_construct( + IN OUT IbQp_t *pQp, + IN viport_t *pViport ) +{ + VNIC_ENTER ( VNIC_DBG_IB ); + + ASSERT( pQp->qpState == IB_UNINITTED ); + + pQp->qp = NULL; + pQp->cq = NULL; + pQp->pViport = pViport; + pQp->pCa = &pViport->p_adapter->ca; + + NdisAllocateSpinLock( &pQp->qpLock ); + + InitializeListHead( &pQp->listPtrs); +} + + +ib_api_status_t +ibqp_init( + IN OUT IbQp_t *pQp, + IN uint64_t guid, + IN IbConfig_t *p_conf ) +{ + ib_qp_create_t attribCreate; + ib_qp_mod_t attribMod; + ib_qp_attr_t qpAttribs; + + ib_cq_create_t cq_create; + ib_cq_handle_t h_cq; + + ib_api_status_t ib_status = IB_SUCCESS; + + VNIC_ENTER ( VNIC_DBG_IB ); + + if (pQp->qpState != IB_UNINITTED && pQp->qpState != IB_DETACHED ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + ("ibqp_init: out of state (%d)\n", pQp->qpState) ); + return IB_ERROR; + } + + InterlockedExchange( &pQp->qpState, IB_UNINITTED ); + + pQp->p_conf = p_conf; + + cq_create.size = p_conf->numSends + p_conf->numRecvs; + cq_create.pfn_comp_cb = ib_workCompletion; + cq_create.h_wait_obj = NULL; + + ib_status = pQp->pViport->p_adapter->ifc.create_cq( + pQp->pViport->p_adapter->h_ca, &cq_create, pQp, ib_asyncEvent, &h_cq ); + + if( ib_status != IB_SUCCESS ) + { + VNIC_TRACE_EXIT( VNIC_DBG_ERROR, + ("Failed allocating completion queue\n") ); + goto err1; + } + + pQp->cq = h_cq; + + cl_memclr( &attribCreate, sizeof(attribCreate) ); + + attribCreate.qp_type = IB_QPT_RELIABLE_CONN; + attribCreate.sq_depth = p_conf->numSends; + attribCreate.rq_depth = p_conf->numRecvs; + attribCreate.sq_sge = p_conf->sendGather; + attribCreate.rq_sge = p_conf->recvScatter; + attribCreate.h_sq_cq = pQp->cq; + attribCreate.h_rq_cq = pQp->cq; + attribCreate.sq_signaled = FALSE; + + ib_status = pQp->pViport->p_adapter->ifc.create_qp( + pQp->pViport->p_adapter->ca.hPd, + &attribCreate, + pQp, + ib_asyncEvent, + &pQp->qp ); + if( ib_status != IB_SUCCESS ) + { + VNIC_TRACE_EXIT( VNIC_DBG_IB, ("Create QP failed %s\n", + pQp->pViport->p_adapter->ifc.get_err_str( ib_status )) ); + goto err2; + } + ib_status = pQp->pViport->p_adapter->ifc.query_qp(pQp->qp, &qpAttribs); + if( ib_status != IB_SUCCESS ) + { + VNIC_TRACE( VNIC_DBG_ERROR, ("Query QP failed %s\n", + pQp->pViport->p_adapter->ifc.get_err_str( ib_status )) ); + goto err3; + } + pQp->qpNumber = qpAttribs.num; + pQp->portGuid = guid; + cl_memclr( &attribMod, sizeof(attribMod) ); + + attribMod.req_state = IB_QPS_INIT; + attribMod.state.init.primary_port = ibca_findPortNum( pQp->pViport, guid ); + attribMod.state.init.pkey_index = 0; + attribMod.state.init.access_ctrl = IB_AC_LOCAL_WRITE; + attribMod.state.init.access_ctrl |= (p_conf->sendGather > 1) ? IB_AC_RDMA_WRITE : 0; + + ib_status = pQp->pViport->p_adapter->ifc.modify_qp( pQp->qp, &attribMod ); + if( ib_status != IB_SUCCESS ) + { + VNIC_TRACE_EXIT( VNIC_DBG_IB, ("Init QP failed %s\n", + pQp->pViport->p_adapter->ifc.get_err_str( ib_status )) ); + +err3: + pQp->pViport->p_adapter->ifc.destroy_qp( pQp->qp, NULL ); +err2: + pQp->pViport->p_adapter->ifc.destroy_cq( pQp->cq, NULL ); + } + else + { + InterlockedExchange( &pQp->qpState, IB_INITTED ); + } + +err1: + VNIC_EXIT ( VNIC_DBG_IB ); + return ib_status; +} + + +ib_api_status_t +ibqp_connect( + IN IbQp_t *pQp) +{ + IbCa_t *pCa; + viport_t *p_viport; + IbConfig_t *p_conf; + ib_api_status_t ib_status = IB_SUCCESS; + ib_cm_req_t conn_req; + + VNIC_ENTER( VNIC_DBG_IB ); + + if ( pQp->qpState != IB_INITTED ) + { + VNIC_TRACE_EXIT( VNIC_DBG_IB, + ("ibqp_connect: out of state (%d)\n",pQp->qpState) ); + return IB_INVALID_STATE; + } + + p_viport = pQp->pViport; + pCa = pQp->pCa; + p_conf = pQp->p_conf; + +#ifdef VNIC_STATISTIC + pQp->statistics.connectionTime = cl_get_time_stamp(); +#endif + + cl_memclr( &conn_req, sizeof(conn_req)); + + conn_req.h_al = p_viport->p_adapter->h_al; + conn_req.qp_type = IB_QPT_RELIABLE_CONN; + conn_req.h_qp = pQp->qp; + conn_req.p_req_pdata = (uint8_t*)&pQp->p_conf->connData; + conn_req.req_length = sizeof( Inic_ConnectionData_t ); + conn_req.svc_id = pQp->p_conf->sid; + conn_req.pkey = pQp->p_conf->pathInfo.pkey; + + conn_req.p_primary_path = &pQp->p_conf->pathInfo; + + conn_req.retry_cnt = (uint8_t)pQp->p_conf->retryCount; + conn_req.rnr_nak_timeout = pQp->p_conf->minRnrTimer; + conn_req.rnr_retry_cnt = (uint8_t)pQp->p_conf->rnrRetryCount; + conn_req.max_cm_retries = 5; + conn_req.remote_resp_timeout = ib_path_rec_pkt_life( &pQp->p_conf->pathInfo ) + 1; + conn_req.local_resp_timeout = ib_path_rec_pkt_life( &pQp->p_conf->pathInfo ) + 1; + + conn_req.compare_length = 0; + conn_req.resp_res = 0; + + conn_req.flow_ctrl = TRUE; + + conn_req.pfn_cm_req_cb = NULL; + conn_req.pfn_cm_rep_cb = _ibqp_connect_cb; + conn_req.pfn_cm_mra_cb = _ibqp_mra_cb; + conn_req.pfn_cm_rej_cb = _ibqp_rej_cb; + + InterlockedExchange( &pQp->qpState, IB_ATTACHING ); + + ib_status = p_viport->p_adapter->ifc.cm_req ( &conn_req ); + if ( ib_status != IB_SUCCESS && ib_status != IB_PENDING ) + { + VNIC_TRACE_EXIT( VNIC_DBG_ERROR, + ("Connect request return status %s\n", + p_viport->p_adapter->ifc.get_err_str( ib_status )) ); + InterlockedExchange( &pQp->qpState, IB_DETACHED ); + return ib_status; + } + + if( cl_event_wait_on( + &p_viport->sync_event, EVENT_NO_TIMEOUT, FALSE ) != CL_SUCCESS ) + { + VNIC_TRACE_EXIT( VNIC_DBG_ERROR, ("conn event timeout!\n") ); + return IB_TIMEOUT; + } + + if( pQp->qpState != IB_ATTACHED ) + { + VNIC_TRACE( VNIC_DBG_ERROR, ("QP connect failed\n") ); + ib_status = IB_ERROR; + } + + VNIC_EXIT( VNIC_DBG_IB ); + return ib_status; +} + + +static void +_ibqp_detach_cb( + IN ib_cm_drep_rec_t *p_drep_rec ) +{ + IbQp_t *pQp = (IbQp_t *)p_drep_rec->qp_context; + VNIC_ENTER( VNIC_DBG_IB ); + CL_ASSERT( p_drep_rec ); + + InterlockedExchange( &pQp->qpState, IB_DETACHED ); + viport_failure( pQp->pViport ); + + VNIC_EXIT( VNIC_DBG_IB ); +} + +static void +_ibqp_rej_cb( + IN ib_cm_rej_rec_t *p_rej_rec ) +{ + IbQp_t *pQp = (IbQp_t *)p_rej_rec->qp_context; + CL_ASSERT(p_rej_rec ); + + InterlockedExchange( &pQp->qpState, IB_DETACHED ); + switch ( p_rej_rec->rej_status ) + { + case IB_REJ_USER_DEFINED: + + VNIC_TRACE ( VNIC_DBG_IB | VNIC_DBG_ERROR, + ("Conn req user reject status %d\nARI: %s\n", + cl_ntoh16( p_rej_rec->rej_status ), + p_rej_rec->p_ari )); + break; + default: + VNIC_TRACE( VNIC_DBG_IB | VNIC_DBG_ERROR, + ("Conn req reject status %d\n", + cl_ntoh16( p_rej_rec->rej_status )) ); + } + + pQp->pViport->p_adapter->hung++; + cl_event_signal( &pQp->pViport->sync_event ); +} + +static void +_ibqp_mra_cb( + IN ib_cm_mra_rec_t *p_mra_rec ) +{ + VNIC_ENTER( VNIC_DBG_IB ); + CL_ASSERT( p_mra_rec ); + UNREFERENCED_PARAMETER( p_mra_rec ); + VNIC_EXIT( VNIC_DBG_IB ); +} + +static void +_ibqp_dreq_cb( + IN ib_cm_dreq_rec_t *p_dreq_rec ) +{ + ib_api_status_t ib_status = IB_SUCCESS; + ib_cm_drep_t cm_drep; + IbQp_t *pQp = (IbQp_t *)p_dreq_rec->qp_context; + + VNIC_ENTER( VNIC_DBG_IB ); + CL_ASSERT( p_dreq_rec ); + + cm_drep.drep_length = 0; + cm_drep.p_drep_pdata = NULL; + + ib_status = pQp->pViport->p_adapter->ifc.cm_drep( + p_dreq_rec->h_cm_dreq, &cm_drep ); + if ( ib_status != IB_SUCCESS ) + { + VNIC_TRACE_EXIT( VNIC_DBG_ERROR, + ("dreq_cb failed status %s(%d)\n", + pQp->pViport->p_adapter->ifc.get_err_str( ib_status ), ib_status)); + return; + } + + InterlockedExchange (&pQp->qpState, IB_DETACHED ); + pQp->pViport->p_adapter->hung++; + viport_failure( pQp->pViport ); + + VNIC_EXIT( VNIC_DBG_IB ); +} + +void +ibqp_detach( + IN IbQp_t *pQp ) +{ + ib_cm_dreq_t cm_dreq; + ib_api_status_t ib_status = IB_SUCCESS; + + VNIC_ENTER( VNIC_DBG_IB ); + + if( InterlockedCompareExchange( &pQp->qpState, + IB_DETACHING, IB_ATTACHED ) == IB_ATTACHED ) + { + NdisAcquireSpinLock( &pQp->qpLock ); + + cm_dreq.h_qp = pQp->qp; + cm_dreq.qp_type = IB_QPT_RELIABLE_CONN; + cm_dreq.p_dreq_pdata = NULL; + cm_dreq.dreq_length = 0; + cm_dreq.pfn_cm_drep_cb = _ibqp_detach_cb; + ib_status = pQp->pViport->p_adapter->ifc.cm_dreq( &cm_dreq ); + if ( ib_status != IB_SUCCESS ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + (" cm_dreq failed status %s\n", + pQp->pViport->p_adapter->ifc.get_err_str( ib_status ))); + } + + NdisReleaseSpinLock( &pQp->qpLock ); + + ib_status = pQp->pViport->p_adapter->ifc.destroy_qp( pQp->qp, NULL ); + if ( ib_status != IB_SUCCESS ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + (" QP destroy failed status %s\n", + pQp->pViport->p_adapter->ifc.get_err_str( ib_status ))); + } + } + + VNIC_EXIT( VNIC_DBG_IB ); + return; +} + +void +ibqp_cleanup( + IN IbQp_t *pQp ) +{ + ib_api_status_t ib_status = IB_SUCCESS; + LONG qp_state; + + VNIC_ENTER( VNIC_DBG_IB ); + + qp_state = InterlockedExchange( &pQp->qpState, IB_UNINITTED ); + if ( qp_state != IB_UNINITTED && + qp_state != IB_DETACHED && + qp_state != IB_DETACHING ) + { + ib_status = pQp->pViport->p_adapter->ifc.destroy_qp( pQp->qp, NULL ); + if ( ib_status != IB_SUCCESS ) + { + VNIC_TRACE_EXIT( VNIC_DBG_ERROR, + ("destroy_qp failed status %s\n", + pQp->pViport->p_adapter->ifc.get_err_str( ib_status )) ); + } + } + + VNIC_EXIT( VNIC_DBG_IB ); + return; +} + +ib_api_status_t ibqp_postSend(IbQp_t *pQp, Io_t *pIo) +{ + ib_api_status_t ib_status; + +#ifdef VNIC_STATISTIC + int64_t postTime; +#endif /* VNIC_STATISTIC */ + + VNIC_ENTER( VNIC_DBG_IB ); + + NdisAcquireSpinLock( &pQp->qpLock ); + + if( pQp->qpState != IB_ATTACHED ) + { + ib_status = IB_INVALID_STATE; + goto failure; + } + +#ifdef VNIC_STATISTIC + pIo->time = postTime = cl_get_time_stamp(); +#endif /* VNIC_STATISTIC */ + if (pIo->wrq.wr_type == WR_RDMA_WRITE ) + pIo->type = RDMA; + else + pIo->type = SEND; + + ib_status = + pQp->pViport->p_adapter->ifc.post_send( pQp->qp, &pIo->wrq, NULL ); + +#ifdef VNIC_STATISTIC + postTime = cl_get_time_stamp() - postTime; +#endif /* VNIC_STATISTIC */ + + if( ib_status != IB_SUCCESS ) + { + VNIC_TRACE( VNIC_DBG_ERROR, ("ib_post_send returned %s\n", + pQp->pViport->p_adapter->ifc.get_err_str( ib_status )) ); + } + else + { +#ifdef VNIC_STATISTIC + if (pIo->wrq.wr_type == WR_RDMA_WRITE) + { + pQp->statistics.rdmaPostTime += postTime; + pQp->statistics.rdmaPostIos++; + } + else + { + pQp->statistics.sendPostTime += postTime; + pQp->statistics.sendPostIos++; + } +#endif /* VNIC_STATISTIC */ + } + +failure: + NdisReleaseSpinLock( &pQp->qpLock ); + VNIC_EXIT( VNIC_DBG_IB ); + return ib_status; +} + + +ib_api_status_t +ibqp_postRecv(IbQp_t *pQp, Io_t *pIo) +{ + ib_api_status_t ib_status = IB_SUCCESS; +#ifdef VNIC_STATISTIC + int64_t postTime; +#endif /* VNIC_STATISTIC */ + + NdisAcquireSpinLock( &pQp->qpLock ); + /* can post recvieves before connecting queue pair */ + if( pQp->qpState != IB_INITTED && pQp->qpState != IB_ATTACHED ) + { + NdisReleaseSpinLock( &pQp->qpLock ); + return IB_INVALID_STATE; + } + pIo->type = RECV; + +#ifdef VNIC_STATISTIC + postTime = cl_get_time_stamp(); + if (pIo->time != 0) + { + pQp->statistics.recvCompTime += postTime - pIo->time; + pQp->statistics.recvCompIos++; + } +#endif /* VNIC_STATISTIC */ + + ib_status = + pQp->pViport->p_adapter->ifc.post_recv(pQp->qp, &pIo->r_wrq, NULL ); + +#ifdef VNIC_STATISTIC + postTime = (cl_get_time_stamp()) - postTime; +#endif /* VNIC_STATISTIC */ + + if( ib_status != IB_SUCCESS ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + ("Post Recv failed status %s(%d)\n", + pQp->pViport->p_adapter->ifc.get_err_str(ib_status), ib_status )); + + NdisReleaseSpinLock( &pQp->qpLock ); + return ib_status; + } + else + { +#ifdef VNIC_STATISTIC + pQp->statistics.recvPostTime += postTime; + pQp->statistics.recvPostIos++; +#endif /* VNIC_STATISTIC */ + } + + NdisReleaseSpinLock( &pQp->qpLock ); + return ib_status; +} + + +static void +_ibqp_connect_cb( + IN ib_cm_rep_rec_t *p_cm_rep ) +{ + IbQp_t *pQp; + ib_api_status_t ib_status = IB_SUCCESS; + + union + { + ib_cm_rtu_t cm_rtu; + ib_cm_mra_t cm_mra; + ib_cm_rej_t cm_rej; + } u_reply; + + viport_t *p_viport; + + VNIC_ENTER( VNIC_DBG_IB ); + + pQp = (IbQp_t *)p_cm_rep->qp_context; + p_viport = pQp->pViport; + + ASSERT( pQp->qpState == IB_ATTACHING ); + + ib_status = p_viport->p_adapter->ifc.rearm_cq( pQp->cq, FALSE ); + if ( ib_status != IB_SUCCESS ) + { + VNIC_TRACE_EXIT( VNIC_DBG_ERROR, + ("Rearm CQ failed %s\n", + p_viport->p_adapter->ifc.get_err_str( ib_status )) ); + + cl_memclr( &u_reply.cm_rej, sizeof( u_reply.cm_rej ) ); + u_reply.cm_rej.rej_status = IB_REJ_INSUF_RESOURCES; + + p_viport->p_adapter->ifc.cm_rej( p_cm_rep->h_cm_rep, &u_reply.cm_rej ); + goto err; + } + + cl_memclr( &u_reply.cm_rtu, sizeof( u_reply.cm_rtu ) ); + u_reply.cm_rtu.access_ctrl = IB_AC_LOCAL_WRITE; + + if( pQp->p_conf->sendGather > 1 ) + u_reply.cm_rtu.access_ctrl |= ( IB_AC_RDMA_WRITE ); + + u_reply.cm_rtu.pfn_cm_dreq_cb = _ibqp_dreq_cb; + + ib_status = p_viport->p_adapter->ifc.cm_rtu ( p_cm_rep->h_cm_rep, &u_reply.cm_rtu ); + if ( ib_status != IB_SUCCESS ) + { + VNIC_TRACE_EXIT( VNIC_DBG_ERROR, + ("Send RTU failed: status %#x\n", ib_status ) ); +err: + InterlockedExchange( &pQp->qpState, IB_DETACHED ); + pQp->pViport->p_adapter->hung++; + } + else + { + InterlockedExchange ( &pQp->qpState, IB_ATTACHED ); + } + + cl_event_signal( &p_viport->sync_event ); + VNIC_EXIT( VNIC_DBG_IB ); +} + + +#define WC_LIST_SIZE_TO_POLL 32 +static void +_ib_qpCompletion( + IN IbQp_t *pQp ) +{ + Io_t *pIo; + ib_wc_t wc[WC_LIST_SIZE_TO_POLL]; + ib_wc_t *p_free_wc; + ib_wc_t *p_done_wc; + ib_api_status_t ib_status = IB_SUCCESS; + int i; + +#ifdef VNIC_STATISTIC + int64_t compTime; +#endif /* VNIC_STATISTIC */ + + VNIC_ENTER ( VNIC_DBG_IB ); + + if ( pQp->qpState != IB_ATTACHING && pQp->qpState != IB_ATTACHED ) + return; + +#ifdef VNIC_STATISTIC + compTime = cl_get_time_stamp(); + pQp->statistics.numCallbacks++; +#endif /* VNIC_STATISTIC */ + + for( i = 0; i < (WC_LIST_SIZE_TO_POLL - 1); i++ ) + { + wc[i].p_next = &wc[i + 1]; + } + wc[(WC_LIST_SIZE_TO_POLL - 1)].p_next = NULL; + + p_free_wc = wc; + p_done_wc = NULL; + + ib_status = pQp->pViport->p_adapter->ifc.poll_cq( pQp->cq, &p_free_wc, &p_done_wc ); + + if ( ib_status != IB_SUCCESS && ib_status != IB_NOT_FOUND ) + { + VNIC_TRACE ( VNIC_DBG_ERROR, + ("ib_poll_cq failed status %d(%s)\n", ib_status, + pQp->pViport->p_adapter->ifc.get_err_str( ib_status )) ); + return; + } + + while ( p_done_wc ) + { + pIo = (Io_t *)(uintn_t)p_done_wc->wr_id; + + /* keep completion status for proper ndis packet return status */ + pIo->wc_status = p_done_wc->status; + + if( p_done_wc->status != IB_WCS_SUCCESS ) + { + VNIC_TRACE( VNIC_DBG_IB, + ("Failed Completion: WcType = %d, Status = %d, Length = %d\n", + p_done_wc->wc_type, + p_done_wc->status, + ( p_done_wc->wc_type == IB_WC_RECV )? p_done_wc->length : 0 ) ); + + if( pIo && pIo->type == RDMA ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + ("Failed RDMA Op, WC type = %d, WC status = %d IO type %d\n", + p_done_wc->wc_type, p_done_wc->status, pIo->type )); + + /* we must complete send packets */ + (*pIo->pRoutine)( pIo ); + } + } + else if(pIo) + { + if( pIo->pRoutine ) + { + (*pIo->pRoutine)( pIo ); + } + } + + p_done_wc = p_done_wc->p_next; + } + + ib_status = pQp->pViport->p_adapter->ifc.rearm_cq( pQp->cq, FALSE ); + + if ( ib_status != IB_SUCCESS ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + ("Rearm CQ failed status %d(%s)\n", ib_status, + pQp->pViport->p_adapter->ifc.get_err_str( ib_status )) ); + viport_failure( pQp->pViport ); + } + return; +} + + +static +void ib_workCompletion( + IN ib_cq_handle_t h_cq, + IN void *cqContext ) +{ + IbQp_t *pQp; + + VNIC_ENTER ( VNIC_DBG_IB ); + UNREFERENCED_PARAMETER( h_cq ); + pQp = (IbQp_t *)cqContext; + _ib_qpCompletion(pQp); + + VNIC_EXIT ( VNIC_DBG_IB ); + return; +} + +void +ib_asyncEvent( + IN ib_async_event_rec_t *pEventRecord ) +{ + vnic_adapter_t *p_adapter; + viport_t *p_viport; + + VNIC_ENTER ( VNIC_DBG_IB ); + + if ( pEventRecord ) + { + + switch ( pEventRecord->code ) + { + case IB_AE_PORT_DOWN: + p_adapter = (vnic_adapter_t *)pEventRecord->context; + + if( p_adapter && + p_adapter->p_currentPath->pViport && + !p_adapter->p_currentPath->pViport->errored ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + ("Async Event Port Down for CA GUID: %#016I64x\n", + p_adapter->ifc_data.ca_guid ) ); + } + break; + + case IB_AE_CQ_ERROR: + case IB_AE_RQ_ERROR: + case IB_AE_SQ_ERROR: + case IB_AE_QP_FATAL: + case IB_AE_WQ_REQ_ERROR: + case IB_AE_WQ_ACCESS_ERROR: + + p_viport = ((IbQp_t *)pEventRecord->context)->pViport; + + if( p_viport && !p_viport->errored ) + { + viport_failure( p_viport ); + + VNIC_TRACE( VNIC_DBG_ERROR, + ("Async Event %#x for port GUID: %#016I64x\n", + pEventRecord->code, + p_viport->portGuid ) ); + } + break; + + default: + VNIC_TRACE( VNIC_DBG_IB, + ("Async Event %d\n", pEventRecord->code )); + break; + } + } + + VNIC_EXIT ( VNIC_DBG_IB ); +} + + + + + + + diff --git a/branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_ib.h b/branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_ib.h new file mode 100644 index 00000000..b230c3ba --- /dev/null +++ b/branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_ib.h @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2007 QLogic Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ +#ifndef _VNIC_IB_H_ +#define _VNIC_IB_H_ + + +#include +#include +#include "vnic_trailer.h" +struct Io; + +typedef void (CompRoutine_t)(struct Io *pIo); + +#define MAX_HCAS 4 +#define MAX_NUM_SGE 8 + +#define MAX_PHYS_MEMORY 0xFFFFFFFFFFFFFFFF +#define CONTROL_SID 0 +#define DATA_SID 1 + +#include +typedef union _vnic_sid { + uint64_t as_uint64; + struct { + uint8_t base_id; /* base id for vnic is 0x10 */ + uint8_t oui[3]; /* OUI */ + uint16_t reserved; /* should be zero */ + uint8_t type; /* control or data */ + uint8_t ioc_num; /* ioc number */ + }s; +} vnic_sid_t; + +typedef union _vnic_ioc_guid { + uint64_t as_uint64; + struct { + uint8_t oui[3]; + uint8_t ioc_num; + uint32_t counter; /* SST device type: 8 bits, counter:24 bits */ + }s; +} vnic_ioc_guid_t; +#include + +typedef enum { + IB_UNINITTED = 0, + IB_INITTED, + IB_ATTACHING, + IB_ATTACHED, + IB_DETACHING, + IB_DETACHED, + IB_DISCONNECTED +} IbState_t; +#pragma warning ( disable : 4324 ) +typedef struct _vnic_path_record { + cl_list_item_t list_entry; + ib_path_rec_t path_rec; +} vnic_path_record_t; +#pragma warning( default : 4324 ) + +typedef struct IbQp { + LIST_ENTRY listPtrs; + struct _viport *pViport; + struct IbConfig *p_conf; + NDIS_SPIN_LOCK qpLock; + volatile LONG qpState; + uint32_t qpNumber; + struct IbCa *pCa; + uint64_t portGuid; + ib_qp_handle_t qp; + ib_cq_handle_t cq; +#ifdef VNIC_STATISTIC + struct { + int64_t connectionTime; + int64_t rdmaPostTime; + uint32_t rdmaPostIos; + int64_t rdmaCompTime; + uint32_t rdmaCompIos; + int64_t sendPostTime; + uint32_t sendPostIos; + int64_t sendCompTime; + uint32_t sendCompIos; + int64_t recvPostTime; + uint32_t recvPostIos; + int64_t recvCompTime; + uint32_t recvCompIos; + uint32_t numIos; + uint32_t numCallbacks; + uint32_t maxIos; + } statistics; +#endif /* VNIC_STATISTIC */ +} IbQp_t; + +typedef struct IbRegion { + uint64_t virtAddress; + net64_t len; + ib_mr_handle_t h_mr; + net32_t lkey; + net32_t rkey; +} IbRegion_t; + + +#define VNIC_CA_MAX_PORTS 2 +typedef struct IbCa { + cl_list_item_t list_entry; + net64_t caGuid; + ib_pd_handle_t hPd; + IbRegion_t region; + uint32_t numPorts; + uint64_t portGuids[VNIC_CA_MAX_PORTS]; +} IbCa_t; + +typedef enum _OpType { + RECV, + RDMA, + SEND +} OpType_t; + +typedef struct Io { + LIST_ENTRY listPtrs; + struct _viport *pViport; + CompRoutine_t *pRoutine; + ib_send_wr_t wrq; + ib_recv_wr_t r_wrq; + ib_wc_status_t wc_status; +#ifdef VNIC_STATISTIC + int64_t time; +#endif /* VNIC_STATISTIC */ + OpType_t type; +} Io_t; + +typedef struct RdmaIo { + Io_t io; + ib_local_ds_t dsList[MAX_NUM_SGE]; + uint16_t index; + uint32_t len; + NDIS_PACKET *p_packet; + NDIS_BUFFER *p_buf; + ULONG packet_sz; + struct ViportTrailer *p_trailer; + uint8_t data[2* VIPORT_TRAILER_ALIGNMENT]; +} RdmaIo_t; + +typedef struct SendIo { + Io_t io; + ib_local_ds_t dsList; +} SendIo_t; + +typedef struct RecvIo { + Io_t io; + ib_local_ds_t dsList; +} RecvIo_t; + +void +ibqp_construct( + IN OUT IbQp_t *pQp, + IN struct _viport *pViport ); + +ib_api_status_t +ibqp_init( + IN IbQp_t *pQp, + IN uint64_t guid, + IN OUT struct IbConfig *p_conf); + +ib_api_status_t +ibqp_connect( + IN IbQp_t *pQp); + +void +ibqp_detach( + IN IbQp_t *pQp); + +void +ibqp_cleanup( + IN IbQp_t *pQp); + +ib_api_status_t +ibqp_postSend( + IN IbQp_t *pQp, + IN Io_t *pIo); + +ib_api_status_t +ibqp_postRecv( + IN IbQp_t *pQp, + IN Io_t *pIo); +uint8_t +ibca_findPortNum( + IN struct _viport *p_viport, + IN uint64_t guid ); + +ib_api_status_t +ibregion_init( + IN struct _viport *p_viport, + OUT IbRegion_t *pRegion, + IN ib_pd_handle_t hPd, + IN void* vaddr, + IN uint64_t len, + IN ib_access_t access_ctrl ); + +void +ibregion_cleanup( + IN struct _viport *p_viport, + IN IbRegion_t *pRegion ); + +void +ib_asyncEvent( + IN ib_async_event_rec_t *pEventRecord ); + +#define ibpd_fromCa(pCa) (&(pCa)->pd) + + +#endif /* _VNIC_IB_H_ */ diff --git a/branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_netpath.c b/branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_netpath.c new file mode 100644 index 00000000..98ddb374 --- /dev/null +++ b/branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_netpath.c @@ -0,0 +1,345 @@ +/* + * Copyright (c) 2007 QLogic Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ +#include "vnic_adapter.h" + +extern vnic_globals_t g_vnic; + + +void +netpath_init( + IN Netpath_t *pNetpath, + IN vnic_adapter_t *p_adapter ) +{ + VNIC_ENTER( VNIC_DBG_FUNC ); + + pNetpath->p_adapter = p_adapter; + pNetpath->carrier = 0; + pNetpath->pViport = NULL; + pNetpath->p_path_rec = NULL; + pNetpath->timerState = NETPATH_TS_IDLE; + + VNIC_EXIT( VNIC_DBG_FUNC ); + return; +} + +BOOLEAN +netpath_addPath ( + Netpath_t *pNetpath, + viport_t *pViport ) +{ + + if( pNetpath->pViport ) + { + return FALSE; + } + else + { + pNetpath->pViport = pViport; + viport_setParent( pViport, pNetpath ); + return TRUE; + } +} + +BOOLEAN +netpath_setUnicast( + IN Netpath_t* p_netpath, + IN uint8_t* p_address ) +{ + if( p_netpath->pViport ) + { + return( viport_setUnicast( p_netpath->pViport, p_address ) ); + } + return FALSE; +} + +NDIS_STATUS +netpath_setMulticast( + IN Netpath_t* p_netpath ) +{ + if( netpath_is_connected( p_netpath ) ) + { + return viport_setMulticast( p_netpath->pViport ); + } + return NDIS_STATUS_NOT_ACCEPTED; +} + +BOOLEAN +netpath_removePath( + IN Netpath_t *p_netpath, + IN viport_t *p_viport ) + +{ + if( p_netpath->pViport != p_viport ) + { + return FALSE; + } + else + { + viport_timerStop( p_netpath->pViport ); + viport_unsetParent( p_netpath->pViport ); + viport_cleanup( p_viport ); + } + + return TRUE; +} + +void +netpath_free( + IN Netpath_t *pNetpath ) +{ + if( netpath_is_valid( pNetpath ) ) + { + netpath_removePath( pNetpath, pNetpath->pViport ); + } + return; +} + +BOOLEAN +netpath_is_valid( + IN Netpath_t* const p_netpath ) +{ + if( p_netpath == NULL ) + return FALSE; + + if( p_netpath->pViport == NULL ) + return FALSE; + + return TRUE; +} + +BOOLEAN +netpath_is_connected( + IN Netpath_t* const p_netpath ) +{ + if( !netpath_is_valid( p_netpath ) ) + return FALSE; + + if( p_netpath->pViport->errored ) + return FALSE; + + if( p_netpath->p_path_rec == NULL ) + return FALSE; + + if( p_netpath->pViport->state != VIPORT_CONNECTED ) + return FALSE; + + + return TRUE; +} + +BOOLEAN +netpath_is_primary( + IN Netpath_t* const p_netpath ) +{ + return (BOOLEAN)( p_netpath->instance == NETPATH_PRIMARY ); +} +BOOLEAN +netpath_linkUp( + IN Netpath_t* p_netpath ) +{ + if( p_netpath != p_netpath->p_adapter->p_currentPath ) + return FALSE; + + if( p_netpath->carrier == TRUE && + InterlockedExchange( &p_netpath->p_adapter->carrier, TRUE ) == FALSE ) + { + NdisMIndicateStatus( p_netpath->p_adapter->h_handle, + NDIS_STATUS_MEDIA_CONNECT, NULL, 0 ); + NdisMIndicateStatusComplete( p_netpath->p_adapter->h_handle ); + VNIC_TRACE( VNIC_DBG_INIT, + ("IOC[%d] %s Link UP\n", + p_netpath->p_adapter->ioc_num, + netpath_to_string( p_netpath ) ) ); + } + return TRUE; +} + +BOOLEAN +netpath_linkDown( + IN Netpath_t* p_netpath ) +{ + if( p_netpath != p_netpath->p_adapter->p_currentPath ) + return FALSE; + + if ( InterlockedExchange( &p_netpath->p_adapter->carrier, FALSE ) == TRUE ) + { + NdisMIndicateStatus( p_netpath->p_adapter->h_handle, + NDIS_STATUS_MEDIA_DISCONNECT, NULL, 0 ); + NdisMIndicateStatusComplete( p_netpath->p_adapter->h_handle ); + VNIC_TRACE( VNIC_DBG_INIT, + ("IOC[%d] %s Link DOWN\n", + p_netpath->p_adapter->ioc_num, + netpath_to_string( p_netpath ) ) ); + } + + return TRUE; +} + +int netpath_maxMtu(Netpath_t *pNetpath) +{ + int ret = MAX_PARAM_VALUE; + + if (pNetpath->pViport) { + ret = viport_maxMtu(pNetpath->pViport); + } + return ret; +} + +BOOLEAN +netpath_xmitPacket( + IN Netpath_t *pNetpath, + IN NDIS_PACKET * const p_packet ) +{ + + if ( pNetpath->pViport && + pNetpath->p_adapter->xmitStarted ) + { + return ( viport_xmitPacket(pNetpath->pViport, p_packet ) ); + } + else + { + NdisInterlockedInsertTailList( + &pNetpath->p_adapter->send_pending_list, + VNIC_LIST_ITEM_FROM_PACKET( p_packet ), + &pNetpath->p_adapter->pending_list_lock ); + return TRUE; + } +} + +void +netpath_cancel_xmit( + IN Netpath_t *p_netpath, + IN PVOID cancel_id ) +{ + if( p_netpath->pViport ) + { + viport_cancel_xmit( p_netpath->pViport, cancel_id ); + } +} + +void +netpath_stopXmit( + IN Netpath_t *pNetpath ) + +{ + + VNIC_ENTER( VNIC_DBG_NETPATH ); + + if( pNetpath == pNetpath->p_adapter->p_currentPath ) + { + InterlockedCompareExchange( &pNetpath->p_adapter->xmitStarted, 0, 1 ); + } +#ifdef INIC_STATISTICS + if ( pNetpath->p_adapter->statistics.xmitRef == 0) + { + pNetpath->p_adapter->statistics.xmitRef = get_time_stamp_ms(); + } +#endif /* INIC_STATISTICS */ + return; +} + +void netpath_restartXmit( + IN Netpath_t *pNetpath ) +{ + VNIC_ENTER( VNIC_DBG_NETPATH ); + + if( ( netpath_is_connected( pNetpath ) ) && + pNetpath == pNetpath->p_adapter->p_currentPath ) + { + InterlockedCompareExchange( &pNetpath->p_adapter->xmitStarted, 1, 0 ); + VNIC_TRACE( VNIC_DBG_NETPATH, + ("IOC[%d] instance %d Restart TRANSMIT\n", + pNetpath->pViport->ioc_num, + pNetpath->instance )); + + } +#ifdef INIC_STATISTICS + if (pNetpath->p_adapter->statistics.xmitRef != 0) + { + pNetpath->p_adapter->statistics.xmitOffTime += + get_time_stamp_ms() - pNetpath->p_adapter->statistics.xmitRef; + pNetpath->p_adapter->statistics.xmitOffNum++; + pNetpath->p_adapter->statistics.xmitRef = 0; + } +#endif /* INIC_STATISTICS */ + return; +} + +// Viport on input calls this +void netpath_recvPacket( + IN Netpath_t *pNetpath, + IN NDIS_PACKET** pp_packet_array, + IN uint32_t num_packets ) +{ + +#ifdef INIC_STATISTICS + extern uin64_t recvRef; +#endif /* INIC_STATISTICS */ + + VNIC_ENTER( VNIC_DBG_NETPATH ); + +#ifdef INIC_STATISTICS + pNetpath->p_adapter->statistics.recvTime += cl_get_tick_count() - recvRef; + pNetpath->p_adapter->statistics.recvNum++; +#endif /* INIC_STATISTICS */ + + NdisMIndicateReceivePacket( pNetpath->p_adapter->h_handle, + pp_packet_array, + num_packets ); + return; +} + +void netpath_tx_timeout( + IN Netpath_t *pNetpath ) +{ + if ( pNetpath->pViport ) + { + viport_failure( pNetpath->pViport ); + } +} + +const char * +netpath_to_string( + IN Netpath_t *p_netpath ) +{ + if ( !netpath_is_valid( p_netpath ) ) + { + return "NULL"; + } + else if ( p_netpath == p_netpath->p_adapter->p_currentPath ) + { + return "CURRENT"; + } + else + { + return "STANDBY"; + } +} diff --git a/branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_trailer.h b/branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_trailer.h new file mode 100644 index 00000000..c047a9b6 --- /dev/null +++ b/branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_trailer.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2007 QLogic Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#ifndef _VNIC_TRAILER_H_ +#define _VNIC_TRAILER_H_ + +/* pktFlags values */ +#define PF_CHASH_VALID 0x01 +#define PF_IPSEC_VALID 0x02 +#define PF_TCP_SEGMENT 0x04 +#define PF_KICK 0x08 +#define PF_VLAN_INSERT 0x10 +#define PF_PVID_OVERRIDDEN 0x20 +#define PF_FCS_INCLUDED 0x40 +#define PF_FORCE_ROUTE 0x80 + +/* txChksumFlags values */ +#define TX_CHKSUM_FLAGS_CHECKSUM_V4 0x01 +#define TX_CHKSUM_FLAGS_CHECKSUM_V6 0x02 +#define TX_CHKSUM_FLAGS_TCP_CHECKSUM 0x04 +#define TX_CHKSUM_FLAGS_UDP_CHECKSUM 0x08 +#define TX_CHKSUM_FLAGS_IP_CHECKSUM 0x10 + +/* rxChksumFlags values */ +#define RX_CHKSUM_FLAGS_TCP_CHECKSUM_FAILED 0x01 +#define RX_CHKSUM_FLAGS_UDP_CHECKSUM_FAILED 0x02 +#define RX_CHKSUM_FLAGS_IP_CHECKSUM_FAILED 0x04 +#define RX_CHKSUM_FLAGS_TCP_CHECKSUM_SUCCEEDED 0x08 +#define RX_CHKSUM_FLAGS_UDP_CHECKSUM_SUCCEEDED 0x10 +#define RX_CHKSUM_FLAGS_IP_CHECKSUM_SUCCEEDED 0x20 +#define RX_CHKSUM_FLAGS_LOOPBACK 0x40 +#define RX_CHKSUM_FLAGS_RESERVED 0x80 + +/* connectionHashAndValid values */ +#define CHV_VALID 0x80 +#define CHV_HASH_MASH 0x7f + +/* round down value to align, align must be a power of 2 */ +#ifndef ROUNDDOWNP2 +#define ROUNDDOWNP2(val, align) \ + (((ULONG)(val)) & (~((ULONG)(align)-1))) +#endif + +/* round up value to align, align must be a power of 2 */ +#ifndef ROUNDUPP2 +#define ROUNDUPP2(val, align) \ + (((ULONG)(val) + (ULONG)(align) - 1) & (~((ULONG)(align)-1))) +#endif + +#define VIPORT_TRAILER_ALIGNMENT 32 +#define BUFFER_SIZE(len) (sizeof(ViportTrailer_t) + ROUNDUPP2((len), VIPORT_TRAILER_ALIGNMENT)) +#define MAX_PAYLOAD(len) ROUNDDOWNP2((len) - sizeof(ViportTrailer_t), VIPORT_TRAILER_ALIGNMENT) +#define MIN_PACKET_LEN 64 +#include + +typedef struct ViportTrailer { + int8_t dataAlignmentOffset; + uint8_t rndisHeaderLength; /* reserved for use by Edp */ + uint16_t dataLength; + uint8_t pktFlags; + + uint8_t txChksumFlags; + + uint8_t rxChksumFlags; + + uint8_t ipSecFlags; + uint32_t tcpSeqNo; + uint32_t ipSecOffloadHandle; + uint32_t ipSecNextOffloadHandle; + uint8_t destMacAddr[6]; + uint16_t vLan; + uint16_t timeStamp; + uint8_t origin; + uint8_t connectionHashAndValid; +} ViportTrailer_t; + +#include + +#endif /* _VNIC_TRAILER_H_ */ diff --git a/branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_util.h b/branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_util.h new file mode 100644 index 00000000..4704404a --- /dev/null +++ b/branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_util.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2007 QLogic Corporation. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#ifndef _VNIC_UTIL_H_ +#define _VNIC_UTIL_H_ + +#include "vnic_debug.h" + +#define MAXU32 MAXULONG +#define MAXU64 ((uint64_t)(~0)) + +#ifndef min +#define min(a,b) ((a)<(b)?(a):(b)) +#endif + +#define hton16(x) _byteswap_ushort(x) +#define hton32(x) _byteswap_ulong(x) +#define hton64(x) _byteswap_uint64(x) + +#define ntoh16(x) hton16(x) +#define ntoh32(x) hton32(x) +#define ntoh64(x) hton64(x) + +#define IsPowerOf2(value) (((value) & (value - 1)) == 0) +/* round down to closest power of 2 value */ + +#define SetMinPowerOf2(_val) ((_val) & ( 1 << RtlFindMostSignificantBit( (uint64_t)(_val) ))) + + +#endif /* _VNIC_UTIL_H_ */ + diff --git a/branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_viport.c b/branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_viport.c new file mode 100644 index 00000000..fe3adac2 --- /dev/null +++ b/branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_viport.c @@ -0,0 +1,1232 @@ +/* + * Copyright (c) 2007 QLogic Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include "iba/ib_al.h" +#include "vnic_util.h" +#include "vnic_driver.h" +#include "vnic_viport.h" +#include "vnic_control.h" +#include "vnic_data.h" +#include "vnic_config.h" +#include "vnic_controlpkt.h" + +extern vnic_globals_t g_vnic; + +static void +viport_timeout( + void *context ); + +static ib_api_status_t +viport_initMacAddresses( + viport_t *p_viport ); + +BOOLEAN +viport_config_defaults( + IN viport_t *p_viport ) +{ + + vnic_adapter_t *p_adapter = p_viport->p_adapter; + ViportConfig_t *pConfig = &p_viport->port_config; + ControlConfig_t *pControlConfig = &p_viport->port_config.controlConfig; + DataConfig_t *pDataConfig = &p_viport->port_config.dataConfig; + + VNIC_ENTER( VNIC_DBG_VIPORT ); + + p_viport->state = VIPORT_DISCONNECTED; + p_viport->linkState = LINK_RETRYWAIT; + p_viport->newMtu = 1500; + p_viport->newFlags = 0; + p_viport->hb_send_pending = FALSE; + + cl_timer_init( &p_viport->timer, viport_timeout, p_viport ); + + pConfig->statsInterval = p_adapter->params.ViportStatsInterval; + pConfig->hbInterval = p_adapter->params.ViportHbInterval; + pConfig->hbTimeout = p_adapter->params.ViportHbTimeout; + + cl_memcpy ( pConfig->ioc_string, + p_adapter->ioc_info.profile.id_string, + min( sizeof( p_adapter->ioc_info.profile.id_string ), + sizeof( pConfig->ioc_string )) ); + + pControlConfig->ibConfig.sid = 0; /* will set it later, from svc entries */ + pControlConfig->ibConfig.connData.pathId = 0; + pControlConfig->ibConfig.connData.inicInstance = 0; // assign instance id in update_path + pControlConfig->ibConfig.connData.pathNum = 0; + + pControlConfig->ibConfig.retryCount = p_adapter->params.RetryCount; + pControlConfig->ibConfig.rnrRetryCount = p_adapter->params.RetryCount; + pControlConfig->ibConfig.minRnrTimer = (uint8_t)p_adapter->params.MinRnrTimer; + pControlConfig->ibConfig.numRecvs = 5; /* Not configurable */ + pControlConfig->ibConfig.numSends = 1; /* Not configurable */ + pControlConfig->ibConfig.recvScatter = 1; /* Not configurable */ + pControlConfig->ibConfig.sendGather = 1; /* Not configurable */ + + /* indicate new features support capabilities */ + pControlConfig->ibConfig.connData.featuresSupported = + hton32((uint32_t)(INIC_FEAT_IGNORE_VLAN | INIC_FEAT_RDMA_IMMED )); + + cl_memcpy ( pControlConfig->ibConfig.connData.nodename, + g_vnic.host_name, + min( sizeof( g_vnic.host_name ), + sizeof( pControlConfig->ibConfig.connData.nodename )) ); + + pControlConfig->numRecvs = pControlConfig->ibConfig.numRecvs; + + pControlConfig->inicInstance = pControlConfig->ibConfig.connData.inicInstance; + pControlConfig->maxAddressEntries = (uint16_t)p_adapter->params.MaxAddressEntries; + pControlConfig->minAddressEntries = (uint16_t)p_adapter->params.MinAddressEntries; + pControlConfig->reqRetryCount = (uint8_t)p_adapter->params.ControlReqRetryCount; + pControlConfig->rspTimeout = p_adapter->params.ControlRspTimeout; + + pDataConfig->ibConfig.sid = 0; /* will set it later, from svc entries */ + pDataConfig->ibConfig.connData.pathId = get_time_stamp_ms(); + pDataConfig->ibConfig.connData.inicInstance = pControlConfig->inicInstance; + pDataConfig->ibConfig.connData.pathNum = 0; + + pDataConfig->ibConfig.retryCount = p_adapter->params.RetryCount; + pDataConfig->ibConfig.rnrRetryCount = p_adapter->params.RetryCount; + pDataConfig->ibConfig.minRnrTimer = (uint8_t)p_adapter->params.MinRnrTimer; + + /* + * NOTE: The numRecvs size assumes that the EIOC could + * RDMA enough packets to fill all of the host recv + * pool entries, plus send a kick message after each + * packet, plus RDMA new buffers for the size of + * the EIOC recv buffer pool, plus send kick messages + * after each MinHostUpdateSz of new buffers all + * before the Host can even pull off the first completed + * receive off the completion queue, and repost the + * receive. NOT LIKELY! + */ + pDataConfig->ibConfig.numRecvs = p_adapter->params.HostRecvPoolEntries + + ( p_adapter->params.MaxEiocPoolSz / p_adapter->params.MinHostUpdateSz ); + +#if LIMIT_OUTSTANDING_SENDS + + pDataConfig->ibConfig.numSends = (2 * p_adapter->params.NotifyBundleSz ) + + ( p_adapter->params.HostRecvPoolEntries / p_adapter->params.MinEiocUpdateSz ) + 1; + +#else /* !defined(LIMIT_OUTSTANDING_SENDS) */ + /* + * NOTE: The numSends size assumes that the HOST could + * post RDMA sends for every single buffer in the EIOCs + * receive pool, and allocate a full complement of + * receive buffers on the host, and RDMA free buffers + * every MinEiocUpdateSz entries all before the HCA + * can complete a single RDMA transfer. VERY UNLIKELY, + * BUT NOT COMPLETELY IMPOSSIBLE IF THERE IS AN IB + * PROBLEM! + */ + pDataConfig->ibConfig.numSends = p_adapter->params.MaxEiocPoolSz + + ( p_adapter->params.HostRecvPoolEntries / p_adapter->params.MinEiocUpdateSz ) + 1; + +#endif /* !defined(LIMIT_OUTSTANDING_SENDS) */ + + pDataConfig->ibConfig.recvScatter = 1; /* Not configurable */ + pDataConfig->ibConfig.sendGather = MAX_NUM_SGE; /* Not configurable */ + + pDataConfig->numRecvs = pDataConfig->ibConfig.numRecvs; + pDataConfig->pathId = pDataConfig->ibConfig.connData.pathId; + + pDataConfig->hostMin.sizeRecvPoolEntry = + (uint32_t)BUFFER_SIZE(ETH_VLAN_HLEN + p_adapter->params.MinMtu); + pDataConfig->hostMax.sizeRecvPoolEntry = + (uint32_t)BUFFER_SIZE(ETH_VLAN_HLEN + p_adapter->params.MaxMtu); + pDataConfig->eiocMin.sizeRecvPoolEntry = + (uint32_t)BUFFER_SIZE(ETH_VLAN_HLEN + p_adapter->params.MinMtu); + pDataConfig->eiocMax.sizeRecvPoolEntry = MAX_PARAM_VALUE; + + pDataConfig->hostRecvPoolEntries = p_adapter->params.HostRecvPoolEntries; + pDataConfig->notifyBundle = p_adapter->params.NotifyBundleSz; + + pDataConfig->hostMin.numRecvPoolEntries = p_adapter->params.MinHostPoolSz; + pDataConfig->hostMax.numRecvPoolEntries = MAX_PARAM_VALUE; + pDataConfig->eiocMin.numRecvPoolEntries = p_adapter->params.MinEiocPoolSz; + pDataConfig->eiocMax.numRecvPoolEntries = p_adapter->params.MaxEiocPoolSz; + + pDataConfig->hostMin.timeoutBeforeKick = p_adapter->params.MinHostKickTimeout; + pDataConfig->hostMax.timeoutBeforeKick = p_adapter->params.MaxHostKickTimeout; + pDataConfig->eiocMin.timeoutBeforeKick = 0; + pDataConfig->eiocMax.timeoutBeforeKick = MAX_PARAM_VALUE; + + pDataConfig->hostMin.numRecvPoolEntriesBeforeKick = p_adapter->params.MinHostKickEntries; + pDataConfig->hostMax.numRecvPoolEntriesBeforeKick = p_adapter->params.MaxHostKickEntries; + pDataConfig->eiocMin.numRecvPoolEntriesBeforeKick = 0; + pDataConfig->eiocMax.numRecvPoolEntriesBeforeKick = MAX_PARAM_VALUE; + + pDataConfig->hostMin.numRecvPoolBytesBeforeKick = p_adapter->params.MinHostKickBytes; + pDataConfig->hostMax.numRecvPoolBytesBeforeKick = p_adapter->params.MaxHostKickBytes; + pDataConfig->eiocMin.numRecvPoolBytesBeforeKick = 0; + pDataConfig->eiocMax.numRecvPoolBytesBeforeKick = MAX_PARAM_VALUE; + + pDataConfig->hostMin.freeRecvPoolEntriesPerUpdate = p_adapter->params.MinHostUpdateSz; + pDataConfig->hostMax.freeRecvPoolEntriesPerUpdate = p_adapter->params.MaxHostUpdateSz; + pDataConfig->eiocMin.freeRecvPoolEntriesPerUpdate = p_adapter->params.MinEiocUpdateSz; + pDataConfig->eiocMax.freeRecvPoolEntriesPerUpdate = p_adapter->params.MaxEiocUpdateSz; + + VNIC_EXIT( VNIC_DBG_VIPORT ); + return TRUE; +} + +static BOOLEAN config_isValid(ViportConfig_t *pConfig) +{ + UNREFERENCED_PARAMETER( pConfig ); + return TRUE; +} + + +void +viport_cleanup( + viport_t *p_viport ) +{ + VNIC_ENTER( VNIC_DBG_VIPORT ); + + if( p_viport ) + { + if( InterlockedExchange( (volatile LONG *)&p_viport->disconnect, TRUE ) ) + { + return; + } + + VNIC_TRACE(VNIC_DBG_VIPORT, + ("IOC[%d]viport cleanup\n", p_viport->ioc_num )); + + data_disconnect( &p_viport->data ); + + control_cleanup( &p_viport->control ); + + data_cleanup( &p_viport->data ); + + if( p_viport->macAddresses != NULL ) + { + NdisFreeMemory( p_viport->macAddresses, + p_viport->numMacAddresses * sizeof(Inic_AddressOp_t), 0 ); + } + + cl_timer_destroy( &p_viport->timer ); + + NdisFreeMemory( p_viport, sizeof(viport_t), 0 ); + p_viport = NULL; + } + + VNIC_EXIT( VNIC_DBG_VIPORT ); + return; +} + +BOOLEAN +viport_setParent( + IN viport_t *p_viport, + IN Netpath_t *pNetpath ) +{ + VNIC_ENTER( VNIC_DBG_VIPORT ); + + + if(p_viport->p_netpath != NULL) + { + return FALSE; + } + + p_viport->p_netpath = pNetpath; + + VNIC_EXIT( VNIC_DBG_VIPORT ); + return TRUE; +} + +BOOLEAN +viport_unsetParent( + IN viport_t *p_viport ) +{ + if( !p_viport || + !p_viport->p_netpath ) + { + return FALSE; + } + InterlockedExchange( &p_viport->p_netpath->carrier, FALSE ); + p_viport->p_netpath->pViport = NULL; + p_viport->p_netpath = NULL; + + if( p_viport->state == VIPORT_CONNECTED ) + { + p_viport->p_adapter->num_paths--; + } + return TRUE; +} + + +NDIS_STATUS +viport_setLink( + IN viport_t *p_viport, + IN uint8_t flags, + IN uint16_t mtu , + IN BOOLEAN sync ) +{ + + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + + VNIC_ENTER( VNIC_DBG_VIPORT ); + + if( mtu > data_maxMtu(&p_viport->data) ) + { + viport_failure(p_viport); + VNIC_TRACE_EXIT( VNIC_DBG_ERROR, + ("IOC[%d] Configuration error. Mtu of %d unsupported\n", p_viport->ioc_num, mtu ) ); + return NDIS_STATUS_FAILURE; + } + + NdisAcquireSpinLock( &p_viport->lock ); + + if( ( (p_viport->newFlags & flags ) != flags ) || + ( p_viport->newMtu != mtu ) ) + { + p_viport->newFlags = flags; + p_viport->newMtu = mtu; + InterlockedOr( &p_viport->updates, NEED_LINK_CONFIG ); + + NdisReleaseSpinLock( &p_viport->lock ); + + status = _viport_process_query( p_viport, sync ); + } + else + NdisReleaseSpinLock( &p_viport->lock ); + + VNIC_EXIT( VNIC_DBG_VIPORT ); + return status; +} + +BOOLEAN +viport_setUnicast( + IN viport_t* const p_viport, + IN uint8_t *p_address ) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + + VNIC_ENTER( VNIC_DBG_VIPORT ); + + if( !p_viport ) + return FALSE; + + NdisAcquireSpinLock( &p_viport->lock ); + + if( p_viport->macAddresses == NULL ) + { + NdisReleaseSpinLock( &p_viport->lock ); + return FALSE; + } + + if( cl_memcmp(p_viport->macAddresses[UNICAST_ADDR].address, + p_address, MAC_ADDR_LEN ) ) + { + + cl_memcpy( p_viport->macAddresses[UNICAST_ADDR].address, + p_address, MAC_ADDR_LEN ); + + VNIC_TRACE( VNIC_DBG_VIPORT, + ("Change Viport MAC From : %02x %02x %02x %02x %02x %02x -> to : %02x %02x %02x %02x %02x %02x\n", + p_viport->hwMacAddress[0], p_viport->hwMacAddress[1], p_viport->hwMacAddress[2], + p_viport->hwMacAddress[3], p_viport->hwMacAddress[4], p_viport->hwMacAddress[5], + p_viport->macAddresses[UNICAST_ADDR].address[0], p_viport->macAddresses[UNICAST_ADDR].address[1], + p_viport->macAddresses[UNICAST_ADDR].address[2], p_viport->macAddresses[UNICAST_ADDR].address[3], + p_viport->macAddresses[UNICAST_ADDR].address[4], p_viport->macAddresses[UNICAST_ADDR].address[5] + ) ); + + NdisMoveMemory( p_viport->hwMacAddress, + p_viport->macAddresses[UNICAST_ADDR].address, MAC_ADDR_LEN ); + + p_viport->macAddresses[UNICAST_ADDR].operation = INIC_OP_SET_ENTRY; + + InterlockedOr( &p_viport->updates, NEED_ADDRESS_CONFIG ); + + NdisReleaseSpinLock( &p_viport->lock ); + + status = _viport_process_query( p_viport, FALSE ); + if( status != NDIS_STATUS_SUCCESS && + status != NDIS_STATUS_PENDING ) + { + VNIC_TRACE_EXIT( VNIC_DBG_ERROR, ("Viport MAC set failed\n") ); + return FALSE; + } + } + + NdisReleaseSpinLock( &p_viport->lock ); + + VNIC_EXIT( VNIC_DBG_VIPORT ); + return TRUE; +} + + +/* Returns flags for state machine operations. */ +NDIS_STATUS +viport_setMulticast( + IN viport_t* const p_viport ) +{ + vnic_adapter_t *p_adapter = p_viport->p_adapter; + uint32_t updates = 0; + int i; + NDIS_STATUS status; + + VNIC_ENTER( VNIC_DBG_VIPORT ); + + NdisAcquireSpinLock( &p_viport->lock ); + + if( p_viport->macAddresses == NULL ) + { + NdisReleaseSpinLock( &p_viport->lock ); + return NDIS_STATUS_NOT_ACCEPTED; + } + + ASSERT( (p_viport->updates & ~MCAST_OVERFLOW) == 0 ); + + if( p_adapter->mc_count == 0 ) + { + /* invalidate all entries for the remote */ + for (i = MCAST_ADDR_START; + i < min( MAX_ADDR_ARRAY, p_viport->numMacAddresses ); i++ ) + { + p_viport->macAddresses[i].valid = 0; + p_viport->macAddresses[i].operation = INIC_OP_SET_ENTRY; + } + /* do we have to report to remote ? */ + p_viport->updates = 0; + NdisReleaseSpinLock( &p_viport->lock ); + return NDIS_STATUS_SUCCESS; + } + + if( p_adapter->mc_count > p_viport->numMacAddresses - MCAST_ADDR_START ) + { + updates |= NEED_LINK_CONFIG | MCAST_OVERFLOW; + } + else + { + if( InterlockedAnd( + &p_viport->updates, ~MCAST_OVERFLOW ) & MCAST_OVERFLOW ) + { + updates |= NEED_LINK_CONFIG; + } + /* Brute force algorithm */ + for (i = MCAST_ADDR_START; + i < min( MAX_ADDR_ARRAY, p_adapter->mc_count + MCAST_ADDR_START ); + i++ ) + { + if( p_viport->macAddresses[i].valid && + NdisEqualMemory( p_viport->macAddresses[i].address, + p_adapter->mcast_array[i - MCAST_ADDR_START].addr, + MAC_ADDR_LEN ) ) + { + continue; + } + + NdisMoveMemory( &p_viport->macAddresses[i].address, + p_adapter->mcast_array[i - MCAST_ADDR_START].addr, + MAC_ADDR_LEN ); + + p_viport->macAddresses[i].valid = 1; + p_viport->macAddresses[i].operation = INIC_OP_SET_ENTRY; + + updates |= NEED_ADDRESS_CONFIG; + } + for (; i < min( MAX_ADDR_ARRAY, p_viport->numMacAddresses ); i++ ) + { + if( !p_viport->macAddresses[i].valid ) + continue; + + updates |= NEED_ADDRESS_CONFIG; + + p_viport->macAddresses[i].valid = 0; + p_viport->macAddresses[i].operation = INIC_OP_SET_ENTRY; + } + } + + /* + * Now that the mac array is setup, we can set the update bits + * to send the request. + */ + InterlockedOr( &p_viport->updates, updates ); + NdisReleaseSpinLock( &p_viport->lock ); + + status = _viport_process_query( p_viport, FALSE ); + + VNIC_EXIT( VNIC_DBG_VIPORT ); + return status; +} + +NDIS_STATUS +viport_getStats( + IN viport_t *p_viport ) +{ + uint64_t stats_update_ms; + NDIS_STATUS status = STATUS_SUCCESS; + + VNIC_ENTER( VNIC_DBG_VIPORT ); + + stats_update_ms = get_time_stamp_ms(); + + if( stats_update_ms > p_viport->lastStatsTime + p_viport->port_config.statsInterval ) + { + p_viport->lastStatsTime = (uint32_t)stats_update_ms; + + InterlockedOr( &p_viport->updates, NEED_STATS ); + + status = _viport_process_query( p_viport, FALSE ); + if ( status != NDIS_STATUS_SUCCESS ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + ("Query NEED_STATS Failed\n") ); + } + } + + VNIC_EXIT( VNIC_DBG_VIPORT ); + return status; +} + + +BOOLEAN +viport_xmitPacket( + IN viport_t* const p_viport, + IN NDIS_PACKET* const p_packet ) +{ + BOOLEAN status; + LIST_ENTRY *p_list_item; + NDIS_PACKET *p_pending_packet; + vnic_adapter_t* p_adapter; + + VNIC_ENTER( VNIC_DBG_VIPORT ); + + NdisAcquireSpinLock( &p_viport->lock ); + + p_adapter = p_viport->p_netpath->p_adapter; + + while( ( p_list_item = NdisInterlockedRemoveHeadList( + &p_adapter->send_pending_list, + &p_adapter->pending_list_lock ) ) != NULL ) + { + p_pending_packet = VNIC_PACKET_FROM_LIST_ITEM( p_list_item ); + + status = data_xmitPacket( &p_viport->data, p_pending_packet ); + if( !status ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + ("IOC[%d] Xmit Pending Packet failed\n", p_viport->ioc_num )); + + /* put it back on pending list - will complete it on cleanup */ + NdisInterlockedInsertHeadList( + &p_adapter->send_pending_list, + VNIC_LIST_ITEM_FROM_PACKET( p_pending_packet ), + &p_adapter->pending_list_lock ); + /*do not try to send packet, just exit */ + goto err; + } + } + + /* send a packet */ + status = data_xmitPacket( &p_viport->data, p_packet ); + if( status ) + { + NdisReleaseSpinLock( &p_viport->lock ); + + VNIC_EXIT( VNIC_DBG_VIPORT ); + return status; + } + +err: + NdisInterlockedInsertTailList( + &p_adapter->send_pending_list, + VNIC_LIST_ITEM_FROM_PACKET( p_packet ), + &p_adapter->pending_list_lock ); + + viport_stopXmit( p_viport ); + + NdisReleaseSpinLock( &p_viport->lock ); + + VNIC_EXIT( VNIC_DBG_VIPORT ); + return status; +} + +void +viport_cancel_xmit( + viport_t *p_viport, + PVOID cancel_id ) +{ + NDIS_PACKET *p_packet; + LIST_ENTRY *p_list_item; + LIST_ENTRY *p_list; + PVOID _id; + vnic_adapter_t* p_adapter; + + NdisAcquireSpinLock( &p_viport->lock ); + + p_adapter = p_viport->p_netpath->p_adapter; + p_list = &p_adapter->send_pending_list; + + while( !IsListEmpty( &p_adapter->send_pending_list ) ) + { + p_list_item = p_list->Flink; + + if ( p_list_item->Flink == &p_adapter->send_pending_list ) + break; + + p_packet = VNIC_PACKET_FROM_LIST_ITEM( p_list_item ); + + _id = NdisGetPacketCancelId( p_packet ); + + if( _id == cancel_id ) + { + NdisInterlockedRemoveHeadList( p_list, &p_adapter->pending_list_lock ); + NdisInterlockedInsertTailList( &p_adapter->cancel_send_list, p_list_item, + &p_adapter->cancel_list_lock ); + p_list_item = p_list->Flink; + } + else + { + p_list = p_list_item; + } + } + + while( !IsListEmpty( &p_adapter->cancel_send_list ) ) + { + p_list_item = NdisInterlockedRemoveHeadList( &p_adapter->cancel_send_list, + &p_adapter->cancel_list_lock ); + + p_packet = VNIC_PACKET_FROM_LIST_ITEM( p_list_item ); + + if( p_packet ) + { + NDIS_SET_PACKET_STATUS( p_packet, NDIS_STATUS_REQUEST_ABORTED ); + NdisMSendComplete( p_adapter->h_handle, p_packet, NDIS_STATUS_REQUEST_ABORTED ); + } + } + + NdisReleaseSpinLock( &p_viport->lock ); +} + +void +viport_linkUp(viport_t *p_viport) +{ + VNIC_ENTER( VNIC_DBG_VIPORT ); + + netpath_linkUp( p_viport->p_netpath ); + + VNIC_EXIT( VNIC_DBG_VIPORT ); + return; +} + +void +viport_linkDown(viport_t *p_viport) +{ + VNIC_ENTER( VNIC_DBG_VIPORT ); + + netpath_linkDown( p_viport->p_netpath ); + + VNIC_EXIT( VNIC_DBG_VIPORT ); + return; +} + +void +viport_stopXmit(viport_t *p_viport) +{ + VNIC_ENTER( VNIC_DBG_VIPORT ); + netpath_stopXmit( p_viport->p_netpath ); + VNIC_EXIT( VNIC_DBG_VIPORT ); + return; +} + +void +viport_restartXmit(viport_t *p_viport) +{ + VNIC_ENTER( VNIC_DBG_VIPORT ); + netpath_restartXmit( p_viport->p_netpath ); + VNIC_EXIT( VNIC_DBG_VIPORT ); + return; +} + +void +viport_recvPacket( + IN viport_t *p_viport, + IN NDIS_PACKET **pp_pkt_arr, + IN uint32_t num_packets ) +{ + VNIC_ENTER( VNIC_DBG_VIPORT ); + netpath_recvPacket(p_viport->p_netpath, pp_pkt_arr, num_packets ); + VNIC_EXIT( VNIC_DBG_VIPORT ); + return; +} + + +void +viport_failure( + IN viport_t *p_viport ) +{ + VNIC_ENTER( VNIC_DBG_VIPORT ); + + if( !p_viport || !p_viport->p_netpath ) + return; + + InterlockedExchange( &p_viport->p_netpath->carrier, FALSE ); + + if( InterlockedExchange( (volatile LONG*)&p_viport->errored, TRUE ) == FALSE ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + ("IOC[%d] %s instance %d FAILED\n", + p_viport->ioc_num, + netpath_to_string( p_viport->p_netpath ), + p_viport->p_netpath->instance )); + viport_stopXmit( p_viport ); + viport_linkDown( p_viport ); + } + + VNIC_EXIT( VNIC_DBG_VIPORT ); +} + + +void +viport_timeout( + IN void *context ) +{ + viport_t *p_viport = (viport_t *)context; + CL_ASSERT( p_viport ); + + if( InterlockedExchange( &p_viport->timerActive, FALSE ) == TRUE ) + { + // did we send a query and got response ? + if( p_viport->link_hb_state != LINK_HEARTBEATRSP && + !p_viport->hb_send_pending ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + ("IOC[%d] instance %d HEARTBEAT TIMEOUT\n", + p_viport->ioc_num, + p_viport->p_netpath->instance )); + viport_failure( p_viport ); + return; + } + /* send heartbeat message again */ + else if( !p_viport->errored && + p_viport->state == VIPORT_CONNECTED ) + { + viport_timer( p_viport, p_viport->port_config.hbInterval ); + } + } +} + + +void +viport_timer( + IN viport_t *p_viport, + IN int timeout ) +{ + ib_api_status_t ib_status; + + VNIC_ENTER( VNIC_DBG_VIPORT ); + + if( !p_viport->errored ) + { + p_viport->link_hb_state = LINK_HEARTBEATREQ; + InterlockedExchange( &p_viport->timerActive, TRUE ); + + /* we can send now */ + if( !p_viport->control.reqOutstanding ) + { + p_viport->hb_send_pending = FALSE; + cl_timer_start( &p_viport->timer, (uint32_t)timeout ); + + ib_status = control_heartbeatReq( &p_viport->control, + p_viport->port_config.hbTimeout ); + + if( ib_status != IB_SUCCESS ) + { + viport_timerStop( p_viport ); + VNIC_TRACE( VNIC_DBG_ERROR, + ("IOC[%d] instance %d HEARTBEAT send failed\n", + p_viport->ioc_num, + p_viport->p_netpath->instance )); + viport_failure( p_viport ); + return; + } + } + /* schedule send on next timeout */ + else + { + p_viport->hb_send_pending = TRUE; + cl_timer_start(&p_viport->timer, (uint32_t)timeout ); + } + } + + VNIC_EXIT( VNIC_DBG_VIPORT ); +} + + +void +viport_timerStop( + IN viport_t *p_viport ) +{ + VNIC_ENTER( VNIC_DBG_VIPORT ); + + if( p_viport ) + { + if( InterlockedExchange( &p_viport->timerActive, FALSE ) == TRUE ) + { + cl_timer_stop( &p_viport->timer ); + } + } + + VNIC_EXIT( VNIC_DBG_VIPORT ); + return; +} + +static ib_api_status_t +viport_initMacAddresses( + IN viport_t *p_viport ) +{ + int i, size; + NDIS_STATUS status; + VNIC_ENTER( VNIC_DBG_VIPORT ); + + size = p_viport->numMacAddresses * sizeof(Inic_AddressOp_t); + status = NdisAllocateMemoryWithTag( &p_viport->macAddresses, size , 'acam' ); + + if ( status != NDIS_STATUS_SUCCESS ) + { + VNIC_TRACE_EXIT( VNIC_DBG_ERROR, + ("Failed allocating MAC address table size %d\n", size) ); + return IB_INSUFFICIENT_MEMORY; + } + + NdisZeroMemory( p_viport->macAddresses, size ); + + NdisAcquireSpinLock( &p_viport->lock ); + for( i = 0; i < p_viport->numMacAddresses; i++ ) + { + p_viport->macAddresses[i].index = (uint16_t)i; + p_viport->macAddresses[i].vlan = p_viport->defaultVlan; + } + + NdisFillMemory( p_viport->macAddresses[BROADCAST_ADDR].address, + MAC_ADDR_LEN, 0xFF ); + p_viport->macAddresses[BROADCAST_ADDR].valid = TRUE; + + NdisMoveMemory( p_viport->macAddresses[UNICAST_ADDR].address, + p_viport->hwMacAddress, MAC_ADDR_LEN ); + + p_viport->macAddresses[UNICAST_ADDR].valid = TRUE; + + if( !p_viport->p_adapter->macSet ) + { + p_viport->p_adapter->macSet = TRUE; + } + + NdisReleaseSpinLock( &p_viport->lock ); + + VNIC_EXIT( VNIC_DBG_VIPORT ); + return IB_SUCCESS; +} + + +ib_api_status_t +viport_control_connect( + IN viport_t* const p_viport ) +{ + ib_api_status_t ib_status; + cl_status_t cl_status; + + VNIC_ENTER( VNIC_DBG_INIT ); + + ib_status = control_init( &p_viport->control, p_viport, + &p_viport->port_config.controlConfig, p_viport->portGuid ); + if( ib_status != IB_SUCCESS ) + { + VNIC_EXIT( VNIC_DBG_VIPORT ); + return ib_status; + } + + ib_status = ibqp_connect( &p_viport->control.qp ); + if( ib_status != IB_SUCCESS ) + { + VNIC_TRACE_EXIT( VNIC_DBG_ERROR, + ("control QP connect failed\n")); + control_cleanup( &p_viport->control ); + return ib_status; + } + + InterlockedExchange( (volatile LONG*)&p_viport->linkState, + (LONG)LINK_INITINICREQ ); + + ib_status = control_initInicReq( &p_viport->control ); + if( ib_status != IB_SUCCESS ) + { + VNIC_TRACE_EXIT( VNIC_DBG_ERROR, + ("CMD_INIT_INIC REQ failed\n") ); + + control_cleanup( &p_viport->control ); + return ib_status; + } + cl_status = cl_event_wait_on( &p_viport->sync_event, + (p_viport->control.p_conf->rspTimeout << 11), FALSE ); + + if( p_viport->linkState != LINK_INITINICRSP ) + { + VNIC_TRACE_EXIT( VNIC_DBG_ERROR, + ("CMD_INIT_INIC RSP failed: return linkstate: %d, cl_status: %d\n", + p_viport->linkState, cl_status )); + + ib_status = IB_INSUFFICIENT_RESOURCES; + control_cleanup( &p_viport->control ); + return ib_status; + } + + vnic_resume_oids( p_viport->p_adapter ); + + ib_status = viport_initMacAddresses( p_viport ); + if( ib_status != IB_SUCCESS ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + ("Init MAC Addresses failed\n")); + control_cleanup( &p_viport->control ); + } + + VNIC_EXIT( VNIC_DBG_INIT ); + return ib_status; +} + +ib_api_status_t +viport_data_connect( + IN viport_t* const p_viport ) +{ + NDIS_STATUS status; + ib_api_status_t ib_status; + + VNIC_ENTER( VNIC_DBG_INIT ); + + ib_status = data_init( &p_viport->data, + &p_viport->port_config.dataConfig, + p_viport->portGuid ); + if( ib_status != IB_SUCCESS ) + { + VNIC_TRACE( VNIC_DBG_ERROR, ("Data init returned %s\n", + p_viport->p_adapter->ifc.get_err_str( ib_status )) ); + return ib_status; + } + InterlockedExchange( (volatile LONG*)&p_viport->linkState, + (LONG)LINK_CONFIGDATAPATHREQ ); + + ib_status = control_configDataPathReq( &p_viport->control, + data_pathId(&p_viport->data ), data_hostPoolMax( &p_viport->data ), + data_eiocPoolMax( &p_viport->data ) ); + if( ib_status != IB_SUCCESS ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + ("command CONFIGDATAPATH REQ failed\n")); + return ib_status; + } + cl_event_wait_on( &p_viport->sync_event, + (p_viport->control.p_conf->rspTimeout << 11), TRUE ); + + if( p_viport->linkState != LINK_CONFIGDATAPATHRSP ) + { + VNIC_TRACE( VNIC_DBG_ERROR, + ("failed to get CONFIGDATAPATH RSP\n")); + return IB_INSUFFICIENT_RESOURCES; + } + + ib_status = data_connect( &p_viport->data ); + if( ib_status != IB_SUCCESS ) + { + VNIC_EXIT( VNIC_DBG_INIT ); + return ib_status; + } + cl_event_wait_on( &p_viport->sync_event, + (p_viport->control.p_conf->rspTimeout << 11), TRUE ); + if( p_viport->data.qp.qpState != IB_ATTACHED ) + { + VNIC_EXIT( VNIC_DBG_INIT ); + return IB_ERROR; + } + InterlockedExchange( (volatile LONG*)&p_viport->linkState, + (LONG)LINK_XCHGPOOLREQ ); + ib_status = control_exchangePoolsReq( &p_viport->control, + data_localPoolAddr(&p_viport->data), + data_localPoolRkey(&p_viport->data) ); + if( ib_status != IB_SUCCESS ) + { + VNIC_TRACE_EXIT( VNIC_DBG_ERROR, + ("command XCHGPOOL REQ failed\n")); + return ib_status; + } + cl_event_wait_on( &p_viport->sync_event, + (p_viport->control.p_conf->rspTimeout << 11), TRUE ); + + if( p_viport->linkState != LINK_XCHGPOOLRSP ) + { + VNIC_TRACE_EXIT( VNIC_DBG_ERROR, + ("failed to get LINK_XCHGPOOL RSP\n")); + return IB_ERROR; + } + + InterlockedExchange( (volatile LONG*)&p_viport->linkState, + (LONG)LINK_INITIALIZED ); + + p_viport->state = VIPORT_CONNECTED; + + ib_status = data_connected( &p_viport->data ); + if( ib_status != IB_SUCCESS ) + { + VNIC_TRACE_EXIT( VNIC_DBG_ERROR, + ("Alloc/Send Recv Buffers failed\n")); + return ib_status; + } + + p_viport->flags = 0; + + if( p_viport->p_netpath == p_viport->p_adapter->p_currentPath ) + { + status = viport_setLink( p_viport, + INIC_FLAG_ENABLE_NIC| INIC_FLAG_SET_MTU, + (uint16_t)p_viport->p_adapter->params.MinMtu, TRUE ); + if( status != NDIS_STATUS_SUCCESS ) + { + VNIC_TRACE_EXIT( VNIC_DBG_ERROR, + ("failed to set Link flags\n")); + return IB_ERROR; + } + + /* start periodic heartbeat timer for active path */ + if( p_viport->port_config.hbInterval ) + { + viport_timer( p_viport, p_viport->port_config.hbInterval ); + } + } + VNIC_EXIT( VNIC_DBG_INIT ); + return IB_SUCCESS; +} + + +NDIS_STATUS +_viport_process_query( + IN viport_t* const p_viport, + IN BOOLEAN sync ) +{ + NDIS_STATUS status; + ib_api_status_t ib_status; + LinkState_t expected_state = 0; + + VNIC_ENTER( VNIC_DBG_VIPORT ); + + if( p_viport->errored || + p_viport->p_adapter->pnp_state == IB_PNP_IOC_REMOVE ) + { + VNIC_TRACE( VNIC_DBG_WARN, + ("IOC[%d] updates = %#x packet_filter = %#x, query: %#x(%d) set: %#x(%d)\n", + p_viport->ioc_num, + p_viport->updates, + p_viport->p_adapter->packet_filter, + p_viport->p_adapter->query_oid.oid, + p_viport->p_adapter->pending_query, + p_viport->p_adapter->set_oid.oid, + p_viport->p_adapter->pending_set )); + + VNIC_TRACE_EXIT( VNIC_DBG_WARN, ("IOC[%d] in REMOVE or invalid state.\n", + p_viport->ioc_num )); + + return NDIS_STATUS_NOT_ACCEPTED; + } + + // Check for updates. Note that unless sync is set to TRUE, this + // is the only way for this function to return success. + if( !InterlockedCompareExchange( &p_viport->updates, 0, 0 ) ) + { + /* now can restart heartbeats */ + if( !p_viport->timerActive && + p_viport->port_config.hbInterval ) + { + viport_timer( p_viport, p_viport->port_config.hbInterval ); + } + return NDIS_STATUS_SUCCESS; + } + + else + { + /* stop heartbeat timer to serve another query */ + viport_timerStop( p_viport ); + } + + if( sync ) + { + status = NDIS_STATUS_SUCCESS; + InterlockedOr( &p_viport->updates, SYNC_QUERY ); + } + else + { + status = NDIS_STATUS_PENDING; + } + + // Handle update bits one at a time. + if( p_viport->updates & NEED_ADDRESS_CONFIG ) + { + VNIC_TRACE( VNIC_DBG_CONF,("QUERY NEED_ADDRESS_CONFIG\n")); + + NdisAcquireSpinLock(&p_viport->lock ); + + p_viport->linkState = LINK_CONFIGADDRSREQ; + ib_status = control_configAddrsReq( + &p_viport->control, p_viport->macAddresses, + p_viport->numMacAddresses, &p_viport->addrs_query_done ); + + NdisReleaseSpinLock( &p_viport->lock ); + + if ( ib_status != IB_SUCCESS ) + { + InterlockedAnd( &p_viport->updates, ~NEED_ADDRESS_CONFIG ); + VNIC_EXIT( VNIC_DBG_VIPORT ); + return NDIS_STATUS_FAILURE; + } + expected_state = LINK_CONFIGADDRSRSP; + } + else if( p_viport->updates & NEED_LINK_CONFIG ) + { + VNIC_TRACE( VNIC_DBG_CONF, + ("QUERY NEED_LINK_CONFIG\n")); + + NdisAcquireSpinLock(&p_viport->lock ); + + p_viport->linkState = LINK_CONFIGLINKREQ; + + if( (InterlockedAnd( + &p_viport->updates, ~MCAST_OVERFLOW ) & MCAST_OVERFLOW ) ) + { + p_viport->newFlags |= INIC_FLAG_ENABLE_MCAST_ALL; + } + else + { + p_viport->newFlags &= ~INIC_FLAG_ENABLE_MCAST_ALL; + } + + if ( p_viport->mtu != p_viport->newMtu ) + { + p_viport->newFlags |= INIC_FLAG_SET_MTU; + p_viport->mtu = p_viport->newMtu; + } + if( ( p_viport->newFlags & INIC_FLAG_ENABLE_NIC ) && + ( p_viport->p_netpath != p_viport->p_adapter->p_currentPath ) ) + { + ASSERT(0); + } + + ib_status = control_configLinkReq( &p_viport->control, + p_viport->newFlags, p_viport->newMtu ); + + p_viport->newFlags &= ~INIC_FLAG_SET_MTU; + + NdisReleaseSpinLock( &p_viport->lock ); + + if( ib_status != IB_SUCCESS ) + { + InterlockedAnd( &p_viport->updates, ~NEED_LINK_CONFIG ); + VNIC_EXIT( VNIC_DBG_VIPORT ); + return NDIS_STATUS_FAILURE; + } + expected_state = LINK_CONFIGLINKRSP; + } + else if( p_viport->updates & NEED_STATS ) + { + // TODO: + VNIC_TRACE( VNIC_DBG_CONF, + ("QUERY NEED_STATS\n")); + + NdisAcquireSpinLock( &p_viport->lock ); + + p_viport->linkState = LINK_REPORTSTATREQ; + + ib_status = control_reportStatisticsReq( &p_viport->control ); + + NdisReleaseSpinLock( &p_viport->lock ); + + if( ib_status != IB_SUCCESS ) + { + InterlockedAnd( &p_viport->updates, ~NEED_STATS ); + VNIC_EXIT( VNIC_DBG_VIPORT ); + return NDIS_STATUS_FAILURE; + } + expected_state = LINK_REPORTSTATRSP; + } + + if( sync ) + { + cl_event_wait_on( &p_viport->sync_event, EVENT_NO_TIMEOUT, TRUE ); + + if( p_viport->linkState != expected_state ) + { + status = NDIS_STATUS_FAILURE; + VNIC_TRACE( VNIC_DBG_ERROR, + ("Link state error: expected %d but got %d\n", + expected_state, p_viport->linkState)); + } + } + VNIC_EXIT( VNIC_DBG_VIPORT ); + return status; +} + +BOOLEAN +viport_canTxCsum( + IN viport_t* p_viport ) +{ + if( !p_viport ) + return FALSE; + + return( BOOLEAN )( ( p_viport->featuresSupported & + ( INIC_FEAT_IPV4_HEADERS | + INIC_FEAT_IPV6_HEADERS | + INIC_FEAT_IPV4_CSUM_TX | + INIC_FEAT_TCP_CSUM_TX | + INIC_FEAT_UDP_CSUM_TX ) ) == + ( INIC_FEAT_IPV4_HEADERS | + INIC_FEAT_IPV6_HEADERS | + INIC_FEAT_IPV4_CSUM_TX | + INIC_FEAT_TCP_CSUM_TX | + INIC_FEAT_UDP_CSUM_TX ) ); +} + +BOOLEAN +viport_canRxCsum( + IN viport_t* p_viport ) +{ + if( !p_viport ) + return FALSE; + + return( BOOLEAN )( ( p_viport->featuresSupported & + ( INIC_FEAT_IPV4_HEADERS | + INIC_FEAT_IPV6_HEADERS | + INIC_FEAT_IPV4_CSUM_RX | + INIC_FEAT_TCP_CSUM_RX | + INIC_FEAT_UDP_CSUM_RX ) ) == + ( INIC_FEAT_IPV4_HEADERS | + INIC_FEAT_IPV6_HEADERS | + INIC_FEAT_IPV4_CSUM_RX | + INIC_FEAT_TCP_CSUM_RX | + INIC_FEAT_UDP_CSUM_RX ) ); +} diff --git a/branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_viport.h b/branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_viport.h new file mode 100644 index 00000000..b881e69f --- /dev/null +++ b/branches/WOF2-3/ulp/qlgcvnic/kernel/vnic_viport.h @@ -0,0 +1,396 @@ +/* + * Copyright (c) 2007 QLogic Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ +#ifndef _VNIC_VIPORT_H_ +#define _VNIC_VIPORT_H_ + +typedef struct _mc_list { + uint8_t mc_addr[MAC_ADDR_LEN]; +} mc_list_t; + +typedef enum { + VIPORT_DISCONNECTED, + VIPORT_CONNECTED +} viport_state_t; + +typedef enum { + LINK_UNINITIALIZED, + LINK_INITIALIZE, + LINK_INITIALIZECONTROL, + LINK_INITIALIZEDATA, + LINK_CONTROLCONNECT, + LINK_CONTROLCONNECTWAIT, + LINK_INITINICREQ, + LINK_INITINICRSP, + LINK_BEGINDATAPATH, + LINK_CONFIGDATAPATHREQ, + LINK_CONFIGDATAPATHRSP, + LINK_DATACONNECT, + LINK_DATACONNECTWAIT, + LINK_XCHGPOOLREQ, + LINK_XCHGPOOLRSP, + LINK_INITIALIZED, + LINK_IDLE, + LINK_IDLING, + LINK_CONFIGLINKREQ, + LINK_CONFIGLINKRSP, + LINK_CONFIGADDRSREQ, + LINK_CONFIGADDRSRSP, + LINK_REPORTSTATREQ, + LINK_REPORTSTATRSP, + LINK_HEARTBEATREQ, + LINK_HEARTBEATRSP, + LINK_RESET, + LINK_RESETRSP, + LINK_RESETCONTROL, + LINK_RESETCONTROLRSP, + LINK_DATADISCONNECT, + LINK_CONTROLDISCONNECT, + LINK_CLEANUPDATA, + LINK_CLEANUPCONTROL, + LINK_DISCONNECTED, + LINK_RETRYWAIT +} LinkState_t; + +/* index entries */ +#define BROADCAST_ADDR 0 +#define UNICAST_ADDR 1 +#define MCAST_ADDR_START 2 +#define MAX_MCAST (MAX_ADDR_ARRAY - MCAST_ADDR_START) + +#define currentMacAddress macAddresses[UNICAST_ADDR].address + +#define NEED_STATS 0x00000001 +#define NEED_ADDRESS_CONFIG 0x00000002 +#define NEED_LINK_CONFIG 0x00000004 +#define MCAST_OVERFLOW 0x00000008 +#define SYNC_QUERY 0x80000000 + +typedef enum { + NETPATH_TS_IDLE, + NETPATH_TS_ACTIVE, + NETPATH_TS_EXPIRED +} netpathTS_t; + + +typedef struct { + LIST_ENTRY listPtrs; + struct _vnic_adapter *p_adapter; + uint8_t event_num; +} InicNPEvent_t; + +typedef enum { + NETPATH_PRIMARY = 1, + NETPATH_SECONDARY = 2 +} netpath_instance_t; + + +typedef struct Netpath { + volatile LONG carrier; + struct _vnic_adapter *p_adapter; + struct _viport *pViport; + ib_path_rec_t *p_path_rec; + uint64_t connectTime; + netpathTS_t timerState; + netpath_instance_t instance; +} Netpath_t; + +typedef enum { + WAIT, + DELAY, + NOW +} conn_wait_state_t; + +typedef struct _viport { + LIST_ENTRY listPtrs; + NDIS_SPIN_LOCK lock; + cl_obj_t obj; + struct _vnic_adapter *p_adapter; + struct Netpath *p_netpath; + struct ViportConfig port_config; + struct Control control; + struct Data data; + uint64_t iocGuid; + uint64_t portGuid; + uint32_t ioc_num; + // connected/disconnected state of control and data QPs. + viport_state_t state; + + // Control Path cmd state Query/Rsp + LinkState_t linkState; + LinkState_t link_hb_state; + Inic_CmdReportStatisticsRsp_t stats; + uint64_t lastStatsTime; + uint32_t featuresSupported; + uint8_t hwMacAddress[MAC_ADDR_LEN]; + uint16_t defaultVlan; + uint16_t numMacAddresses; + Inic_AddressOp_t *macAddresses; + int32_t addrs_query_done; + + // Indicates actions (to the VEx) that need to be taken. + volatile LONG updates; + + uint8_t flags; + uint8_t newFlags; + uint16_t mtu; + uint16_t newMtu; + uint32_t errored; + uint32_t disconnect; + volatile LONG timerActive; + cl_timer_t timer; + cl_event_t sync_event; + BOOLEAN hb_send_pending; +} viport_t; + + +BOOLEAN +viport_xmitPacket( + IN viport_t* const p_viport, + IN NDIS_PACKET* const p_pkt ); + +BOOLEAN +viport_config_defaults( + IN viport_t *p_viport ); + +uint32_t +viport_get_adapter_name( + IN viport_t *p_viport ); + +void +viport_cleanup( + IN viport_t *p_viport ); + +BOOLEAN +viport_setParent( + IN viport_t *pViport, + IN struct Netpath *pNetpath); + +NDIS_STATUS +viport_setLink( + IN viport_t *pViport, + IN uint8_t flags, + IN uint16_t mtu, + IN BOOLEAN sync ); + +NDIS_STATUS +viport_getStats( + IN viport_t *pViport ); + +void +viport_timer( + IN viport_t *p_viport, + IN int timeout ); + +void +viport_timerStop( + IN viport_t *p_viport ); + +void +viport_linkUp( + IN viport_t *pViport); + +void +viport_linkDown( + IN viport_t *pViport); + +void +viport_stopXmit( + IN viport_t *pViport); + +void +viport_restartXmit( + IN viport_t *pViport); + +void +viport_recvPacket( + IN viport_t *pViport, + IN NDIS_PACKET **p_pkt, + IN uint32_t num_pkts ); + +void +viport_failure( + IN viport_t *pViport); + +BOOLEAN +viport_setUnicast( + IN viport_t* const pViport, + IN uint8_t * pAddress); + +NDIS_STATUS +viport_setMulticast( + IN viport_t* const pViport ); + +void +netpath_init( + IN struct Netpath *pNetpath, + IN struct _vnic_adapter *p_adapter ); + +BOOLEAN +netpath_addPath( + IN struct Netpath *pNetpath, + IN viport_t *pViport); + +BOOLEAN +viport_unsetParent( + IN viport_t *pViport ); + +ib_api_status_t +viport_control_connect( + IN viport_t* const p_viport ); + +ib_api_status_t +viport_data_connect( + IN viport_t* const p_viport ); + +NDIS_STATUS +_viport_process_query( + IN viport_t* const p_viport, + IN BOOLEAN sync ); + +void +viport_cancel_xmit( + IN viport_t *p_viport, + IN void *p_cancel_id ); + +BOOLEAN +netpath_removePath( + IN struct Netpath *pNetpath, + IN viport_t *p_viport ); + +void +netpath_free( + IN struct Netpath *pNetpath ); + +BOOLEAN +netpath_getStats( + IN struct Netpath *pNetpath ); + +NDIS_STATUS +netpath_setMulticast( + IN struct Netpath *pNetpath ); + +int +netpath_maxMtu( + IN struct Netpath *pNetpath); + +BOOLEAN +netpath_linkDown( + IN Netpath_t* p_netpath ); + + +BOOLEAN +netpath_linkUp( + IN Netpath_t* p_netpath ); + +BOOLEAN +netpath_is_valid( + IN Netpath_t* const p_netpath ); + +BOOLEAN +netpath_is_connected( + IN Netpath_t* const p_netpath ); + +BOOLEAN +netpath_is_primary( + IN Netpath_t* const p_netpath ); + +BOOLEAN +netpath_xmitPacket( + IN struct Netpath* pNetpath, + IN NDIS_PACKET* const p_pkt ); + +void +netpath_cancel_xmit( + IN struct Netpath* p_netpath, + IN PVOID cancel_id ); + +void +netpath_recvPacket( + IN struct Netpath* pNetpath, + IN NDIS_PACKET** pp_pkt, + IN uint32_t num_packets); + +void +netpath_stopXmit( + IN struct Netpath *pNetpath ); + +void +netpath_restartXmit( + IN struct Netpath *pNetpath ); + +void +netpath_kick( + IN struct Netpath *pNetpath); + +void +netpath_timer( + IN struct Netpath *pNetpath, + IN int timeout); + +void +netpath_tx_timeout( + IN struct Netpath *pNetpath); + +const char* +netpath_to_string( + IN struct Netpath *pNetpath ); + +BOOLEAN +netpath_setUnicast( + IN Netpath_t* p_netpath, + IN uint8_t* p_address ); + +BOOLEAN +viport_canTxCsum( + IN viport_t* p_viport ); + +BOOLEAN +viport_canRxCsum( + IN viport_t* p_viport ); + +#define viport_portGuid(pViport) ((pViport)->portGuid) +#define viport_maxMtu(pViport) data_maxMtu(&(pViport)->data) + +#define viport_getHwAddr(pViport,pAddress) \ + cl_memcpy(pAddress, (pViport)->hwMacAddress, MAC_ADDR_LEN) + +#define viport_features(pViport) ( (pViport)->featuresSupported ) + +#define netpath_getHwAddr(pNetpath, pAddress) \ + viport_getHwAddr((pNetpath)->pViport, pAddress) + +#define netpath_canTxCsum(pNetpath) \ + viport_canTxCsum( (pNetpath)->pViport ) + +#define netpath_canRxCsum(pNetpath) \ + viport_canRxCsum( (pNetpath)->pViport ) + +#endif /* _VNIC_VIPORT_H_ */ diff --git a/branches/WOF2-3/ulp/srp/dirs b/branches/WOF2-3/ulp/srp/dirs new file mode 100644 index 00000000..ed41dcf4 --- /dev/null +++ b/branches/WOF2-3/ulp/srp/dirs @@ -0,0 +1,2 @@ +DIRS=\ + kernel diff --git a/branches/WOF2-3/ulp/srp/kernel/SOURCES b/branches/WOF2-3/ulp/srp/kernel/SOURCES new file mode 100644 index 00000000..237c439a --- /dev/null +++ b/branches/WOF2-3/ulp/srp/kernel/SOURCES @@ -0,0 +1,64 @@ +TARGETNAME=ibsrp +TARGETPATH=..\..\..\bin\kernel\obj$(BUILD_ALT_DIR) +TARGETTYPE=MINIPORT + +!if $(_NT_TOOLS_VERSION) != 0x700 +# WDK build only - transform .inx --> .inf adding date & version stamp. +# see .\makefile.inc +INF_NAME=ib_srp +INF_TARGET=..\..\..\bin\kernel\$(O)\$(INF_NAME).inf +NTTARGETFILES=$(INF_TARGET) +!endif + +!if $(FREEBUILD) +ENABLE_EVENT_TRACING=1 +!else +#ENABLE_EVENT_TRACING=1 +!endif + + +SOURCES= ibsrp.rc \ + srp_connection.c \ + srp_data_path.c \ + srp_descriptors.c \ + srp_driver.c \ + srp_event.c \ + srp_hba.c \ + srp_hca.c \ + srp_session.c + +INCLUDES=..\..\..\inc;..\..\..\inc\kernel; + +!if defined(DDK_TARGET_OS) && "$(DDK_TARGET_OS)"=="WinXP" +# storport.h in WinXP DDK already have "..._ALIASES" definition +C_DEFINES=$(C_DEFINES) -DDEPRECATE_DDK_FUNCTIONS -DWinXP -DNEED_CL_OBJ +!else +C_DEFINES=$(C_DEFINES) -DDEPRECATE_DDK_FUNCTIONS -DSTOR_USE_SCSI_ALIASES \ + -DNEED_CL_OBJ +!endif + +TARGETLIBS= \ + $(TARGETPATH)\*\complib.lib \ + $(DDK_LIB_PATH)\scsiwmi.lib \ + $(DDK_LIB_PATH)\ntoskrnl.lib \ + $(DDK_LIB_PATH)\hal.lib + +#!if !defined(DDK_TARGET_OS) || "$(DDK_TARGET_OS)"=="Win2K" +# Win2k doesn't support StorPort. +#TARGETLIBS= $(TARGETLIBS) $(DDK_LIB_PATH)\scsiport.lib +#!else +TARGETLIBS= $(TARGETLIBS) $(DDK_LIB_PATH)\storport.lib +#!endif + +!IFDEF ENABLE_EVENT_TRACING + +C_DEFINES = $(C_DEFINES) -DEVENT_TRACING + +RUN_WPP = $(SOURCES) -km -ext: .c .h .C .H \ + -scan:srp_debug.h \ + -func:SRP_PRINT(LEVEL,FLAGS,(MSG,...)) \ + -func:SRP_PRINT_EXIT(LEVEL,FLAGS,(MSG,...)) + +!ENDIF + +MSC_WARNING_LEVEL= /W4 diff --git a/branches/WOF2-3/ulp/srp/kernel/ib_srp.cdf b/branches/WOF2-3/ulp/srp/kernel/ib_srp.cdf new file mode 100644 index 00000000..59269844 --- /dev/null +++ b/branches/WOF2-3/ulp/srp/kernel/ib_srp.cdf @@ -0,0 +1,10 @@ +[CatalogHeader] +Name=ibsrp.cat +PublicVersion=0x0000001 +EncodingType=0x00010001 +CATATTR1=0x10010001:OSAttr:2:6.0 +[CatalogFiles] +ib_srp.inf=ib_srp.inf +ibsrp.sys=ibsrp.sys + + diff --git a/branches/WOF2-3/ulp/srp/kernel/ib_srp.inx b/branches/WOF2-3/ulp/srp/kernel/ib_srp.inx new file mode 100644 index 00000000..5b57db83 --- /dev/null +++ b/branches/WOF2-3/ulp/srp/kernel/ib_srp.inx @@ -0,0 +1,136 @@ +; OpenIB InfiniBand SRP Miniport. +; Copyright 2005 SilverStorm Technologies all Rights Reserved. + +[Version] +Signature="$Windows NT$" +Class=SCSIAdapter +ClassGUID={4D36E97B-E325-11CE-BFC1-08002BE10318} +Provider=%OPENIB% +DriverVer=06/13/2008,1.0.0000.1207 +CatalogFile=ibsrp.cat + + +; ================= Device Install section ===================== + +[DestinationDirs] +DefaultDestDir=12 + +[SourceDisksNames.x86] +1=%DiskId%,,,"" + +[SourceDisksNames.amd64] +1=%DiskId%,,,"" + +[SourceDisksNames.ia64] +1=%DiskId%,,,"" + +[SourceDisksFiles] +ibsrp.sys=1 + +[Manufacturer] +%OPENIB% = SRP.DeviceSection,ntx86...0x1,ntx86,ntamd64,ntia64 +%SST% = VFx.DeviceSection,ntx86...0x1,ntx86,ntamd64,ntia64 + +[SRP.DeviceSection] +; empty since we don't support W9x/Me + +[SRP.DeviceSection.ntx86...0x1] +; empty since we don't yet support XP. + +[SRP.DeviceSection.ntx86] +%SRP.DeviceDesc% = SRP.DDInstall,IBA\C0100c609ep0108r0001, \ + IBA\Cff00c609ep0108r0001, \ + IBA\C0100c609ep0108, \ + IBA\Cff00c609ep0108 + +[SRP.DeviceSection.ntamd64] +%SRP.DeviceDesc% = SRP.DDInstall,IBA\C0100c609ep0108r0001, \ + IBA\Cff00c609ep0108r0001, \ + IBA\C0100c609ep0108, \ + IBA\Cff00c609ep0108 + +[SRP.DeviceSection.ntia64] +%SRP.DeviceDesc% = SRP.DDInstall,IBA\C0100c609ep0108r0001, \ + IBA\Cff00c609ep0108r0001, \ + IBA\C0100c609ep0108, \ + IBA\Cff00c609ep0108 + +[VFx.DeviceSection] +; empty since we don't support W9x/Me + +[VFx.DeviceSection.ntx86...0x1] +; empty since we don't yet support XP. + +[VFx.DeviceSection.ntx86] +%VFx.DeviceDesc% = SRP.DDInstall,IBA\V00066aP00000038S00066as00000038v0001, \ + IBA\V00066aP00000038S00066as00000038, \ + IBA\V00066aP00000038v0001, \ + IBA\V00066aP00000038 + +[VFx.DeviceSection.ntamd64] +%VFx.DeviceDesc% = SRP.DDInstall,IBA\V00066aP00000038S00066as00000038v0001, \ + IBA\V00066aP00000038S00066as00000038, \ + IBA\V00066aP00000038v0001, \ + IBA\V00066aP00000038 + +[VFx.DeviceSection.ntia64] +%VFx.DeviceDesc% = SRP.DDInstall,IBA\V00066aP00000038S00066as00000038v0001, \ + IBA\V00066aP00000038S00066as00000038, \ + IBA\V00066aP00000038v0001, \ + IBA\V00066aP00000038 + +[SRP.DDInstall.nt] +CopyFiles = SRP.CopyFiles + +[SRP.DDInstall.nt.Services] +AddService = ibsrp,%SPSVCINST_ASSOCSERVICE%,SRP.ServiceInstall,SRP.EventLogInstall + +[SRP.CopyFiles] +ibsrp.sys + +; +; ============= Service Install section ============== +; + +[SRP.ServiceInstall] +DisplayName = %SRP.ServiceDesc% +ServiceType = %SERVICE_KERNEL_DRIVER% +StartType = %SERVICE_DEMAND_START% +ErrorControl = %SERVICE_ERROR_NORMAL% +ServiceBinary = %12%\ibsrp.sys +LoadOrderGroup = SCSI Miniport +AddReg = SRP.ParamsReg + +[SRP.ParamsReg] +HKR,"Parameters\PnpInterface",%InternalBus%,%REG_DWORD%,1 +HKR,"Parameters\PnpInterface",%PNPBus%,%REG_DWORD%,1 +HKR,"Parameters","DebugLevel",%REG_DWORD%,2 +HKR,"Parameters","DebugFlags",%REG_DWORD%,0x00ffffff +HKR,"Parameters","ModeFlags",%REG_DWORD%,0 + +; +; == The NT EventLog entries are the same for all SCSI miniports. == +; +[SRP.EventLogInstall] +AddReg = SRP.EventLogAddReg + +[SRP.EventLogAddReg] +HKR,,EventMessageFile,0x00020000,"%%SystemRoot%%\System32\IoLogMsg.dll" +HKR,,TypesSupported,0x00010001,7 + +[Strings] +OPENIB = "OpenIB Alliance" +SST = "SilverStorm Technologies" +SRP.DeviceDesc = "InfiniBand SRP Miniport" +VFx.DeviceDesc = "SilverStorm VFx I/O Controller" +SRP.ServiceDesc = "OpenIB InfiniBand SRP Miniport" +DiskId = "OpenIB InfiniBand SRP installation disk" +InternalBus = 0 +PNPBus = 15 +SPSVCINST_NULL = 0x0 +SPSVCINST_ASSOCSERVICE = 0x00000002 +SERVICE_KERNEL_DRIVER = 1 +SERVICE_DEMAND_START = 3 +SERVICE_ERROR_NORMAL = 1 +REG_DWORD = 0x00010001 +REG_DWORD_NO_CLOBBER = 0x00010003 diff --git a/branches/WOF2-3/ulp/srp/kernel/ibsrp.rc b/branches/WOF2-3/ulp/srp/kernel/ibsrp.rc new file mode 100644 index 00000000..5de864e8 --- /dev/null +++ b/branches/WOF2-3/ulp/srp/kernel/ibsrp.rc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef _DEBUG_ +#define VER_FILEDESCRIPTION_STR "InfiniBand SRP Miniport (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "InfiniBand SRP Miniport" +#endif + +#define VER_INTERNALNAME_STR "ibsrp.sys" +#define VER_ORIGINALFILENAME_STR "ibsrp.sys" + +#include diff --git a/branches/WOF2-3/ulp/srp/kernel/makefile b/branches/WOF2-3/ulp/srp/kernel/makefile new file mode 100644 index 00000000..bffacaa7 --- /dev/null +++ b/branches/WOF2-3/ulp/srp/kernel/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# + +!INCLUDE ..\..\..\inc\openib.def diff --git a/branches/WOF2-3/ulp/srp/kernel/makefile.inc b/branches/WOF2-3/ulp/srp/kernel/makefile.inc new file mode 100644 index 00000000..4f29f500 --- /dev/null +++ b/branches/WOF2-3/ulp/srp/kernel/makefile.inc @@ -0,0 +1,17 @@ + +# Transform .inx file to .inf file adding date + major,min & svn.version stamp +# Output .inf file is copied to the $(INF_TARGET) folder (commonly where .sys file resides). + +_LNG=$(LANGUAGE) + +!IF !DEFINED(_INX) +_INX=. +!ENDIF + +STAMP=stampinf -a $(_BUILDARCH) + +!INCLUDE mod_ver.def + +$(INF_TARGET) : $(_INX)\$(INF_NAME).inx + copy $(_INX)\$(@B).inx $@ + $(STAMP) -f $@ -d * -v $(IB_MAJORVERSION).$(IB_MINORVERSION).$(IB_BUILDVERSION).$(OPENIB_REV) diff --git a/branches/WOF2-3/ulp/srp/kernel/srp.h b/branches/WOF2-3/ulp/srp/kernel/srp.h new file mode 100644 index 00000000..626af3ec --- /dev/null +++ b/branches/WOF2-3/ulp/srp/kernel/srp.h @@ -0,0 +1,370 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#ifndef _SRP_H_INCLUDED_ +#define _SRP_H_INCLUDED_ + +#include +#include +#include + +/* + SRP Service Definitions + */ +#define SRP_IO_CLASS CL_HTON16(0x0100) /* T10 changed */ +#define SRP_IO_CLASS_R10 CL_HTON16(0xff00) /* FF + high 8 bits of NCITS OUI */ +#define SRP_IO_SUBCLASS CL_HTON16(0x609e) /* Low 16 bits of NCITS OUI */ +#define SRP_PROTOCOL 0x0108 /* T10 administered identifier */ +#define SRP_PROTOCOL_VER 0x0001 /* Approved standard version */ +#define SRP_SERVICE_NAME_PREFIX "SRP.T10:" +#define SRP_EXTENSION_ID_LENGTH 16 /* Service name extension ID length */ + +#define SRP_MIN_IU_SIZE 64 +#define SRP_MAX_SG_IN_INDIRECT_DATA_BUFFER 257 /* it was 16 */ +#define SRP_MAX_IU_SIZE (SRP_MIN_IU_SIZE + 20 + 16*SRP_MAX_SG_IN_INDIRECT_DATA_BUFFER) + +#define SRP_MIN_INI_TO_TGT_IU 64 // Minimum initiator message size +#define SRP_MIN_TGT_TO_INI_IU 56 // Minimum target message size +#define SRP_MIN_TGT_TO_INI_DMA 512 // At least one sector! + +/* Requests sent from SRP initiator ports to SRP target ports */ +#define SRP_LOGIN_REQ 0x00 +#define SRP_TSK_MGMT 0x01 +#define SRP_CMD 0x02 +#define SRP_I_LOGOUT 0x03 + +/* Responses sent from SRP target ports to SRP initiator ports */ +#define SRP_LOGIN_RSP 0xC0 +#define SRP_RSP 0xC1 +#define SRP_LOGIN_REJ 0xC2 + +/* Requests sent from SRP target ports to SRP initiator ports */ +#define SRP_T_LOGOUT 0x80 +#define SRP_CRED_REQ 0x81 +#define SRP_AER_REQ 0x82 + +/* Responses sent from SRP initiator ports to SRP target ports */ +#define SRP_CRED_RSP 0x41 +#define SRP_AER_RSP 0x42 + +typedef struct _srp_information_unit +{ + uint8_t type; + uint8_t reserved[7]; + uint64_t tag; +} PACK_SUFFIX srp_information_unit_t; + +/* Mask values applied to bit fields for access */ +#define DATA_BUFFER_DESCRIPTOR_FORMAT_MASK 0x06 +#define MULTI_CHANNEL_ACTION_MASK 0x03 +#define MULTI_CHANNEL_RESULT_MASK 0x03 + +/* Allowable values for the Data Buffer Descriptor Formats */ +typedef enum data_buffer_descriptor_format_enum +{ + DBDF_NO_DATA_BUFFER_DESCRIPTOR_PRESENT = 0x00, + DBDF_DIRECT_DATA_BUFFER_DESCRIPTOR = 0x01, + DBDF_INDIRECT_DATA_BUFFER_DESCRIPTORS = 0x02 +} DATA_BUFFER_DESCRIPTOR_FORMAT; + +/* Requested Supportted Data Buffer Format flag values */ +#define DIRECT_DATA_BUFFER_DESCRIPTOR_REQUESTED 0x02 +#define INDIRECT_DATA_BUFFER_DESCRIPTOR_REQUESTED 0x04 + +typedef struct _srp_req_sup_db_fmt +{ + uint8_t reserved; + uint8_t flags; /* IDBD/DDBD */ +} PACK_SUFFIX srp_req_sup_db_fmt_t; + +/* + * The SRP spec r10 defines the port identifiers as + * GUID:ExtensionID, while the SRP 2.0 spec defines them + * as ExtensionID:GUID. Lucky for us the IO_CLASS in the + * IOC profile changed from 0xFF to 0x100. + */ +typedef struct _srp_ib_port_id +{ + net64_t field1; + net64_t field2; + +} PACK_SUFFIX srp_ib_port_id_t; + +/* Allowable values for the MultiChannel Action field */ +typedef enum multi_channel_action_enum +{ + MCA_TERMINATE_EXISTING = 0x00, + MCA_INDEPENDENT_OPERATION = 0x01 +} MULTI_CHANNEL_ACTION; + +typedef struct _srp_login_req +{ + uint8_t type; + uint8_t reserved1[7]; + uint64_t tag; + uint32_t req_max_init_to_targ_iu; + uint8_t reserved2[4]; + srp_req_sup_db_fmt_t req_buffer_fmts; + uint8_t flags; /* MULTI-CHANNEL ACTION */ + uint8_t reserved3; + uint8_t reserved4[4]; + srp_ib_port_id_t initiator_port_id; + srp_ib_port_id_t target_port_id; +} PACK_SUFFIX srp_login_req_t; + +/* Allowable values for the MultiChannel Result field */ +typedef enum multi_channel_result_enum +{ + MCR_NO_EXISTING_TERMINATED = 0x00, + MCR_EXISTING_TERMINATED = 0x01, + MCR_EXISTING_CONTINUED = 0x02 +} MULTI_CHANNEL_RESULT; + +typedef struct _srp_login_rsp +{ + uint8_t type; + uint8_t reserved1[3]; + int32_t request_limit_delta; + uint64_t tag; + uint32_t max_init_to_targ_iu; + uint32_t max_targ_to_init_iu; + srp_req_sup_db_fmt_t sup_buffer_fmts; + uint8_t flags; /* MULTI-CHANNEL RESULT */ + uint8_t reserved2; + uint8_t reserved3[24]; +} PACK_SUFFIX srp_login_rsp_t; + +/* Allowable values for SRP LOGIN REJ Reason Codes */ +typedef enum login_reject_code_enum +{ + LIREJ_UNABLE_TO_ESTABLISH_RDMA_CHANNEL = 0x00010000, + LIREJ_INSUFFICIENT_RDMA_CHANNEL_RESOURCES = 0x00010001, + LIREJ_INIT_TO_TARG_IU_LENGTH_TOO_LARGE = 0x00010002, + LIREJ_UNABLE_TO_ASSOCIATE_RDMA_CHANNEL_WITH_I_T_NEXUS = 0x00010003, + LIREJ_UNSUPPORTED_DATA_BUFFER_DESCRIPTOR_FORMAT = 0x00010004, + LIREJ_NO_TARGET_SUPPORT_FOR_MULTIPLE_RDMA_CHANNELS_PER_I_T_NEXUS = 0x00010005 +} LOGIN_REJECT_CODE; + +typedef struct _srp_login_rej +{ + uint8_t type; + uint8_t reserved1[3]; + uint32_t reason; + uint64_t tag; + uint8_t reserved2[8]; + srp_req_sup_db_fmt_t sup_buffer_fmts; + uint8_t reserved3[6]; +} PACK_SUFFIX srp_login_rej_t; + +typedef struct _srp_i_logout +{ + uint8_t type; + uint8_t reserved[7]; + uint64_t tag; +} PACK_SUFFIX srp_i_logout_t; + +/* Srp Target Logout Reason Codes */ +typedef enum target_logout_reason_code_enum +{ + TLO_NO_REASON = 0x0000, + TLO_INACTIVE_RDMA_CHANNEL = 0x0001, + TLO_INVALID_IU_TYPE_RECEIVED_BY_TARGET = 0x0002, + TLO_RESPONSE_WITH_NO_OUTSTANDING_TARGET_PORT_REQUEST = 0x0003, + TLO_DISCONNECT_DUE_TO_MULTI_CHANNEL_ACTION_ON_NEW_LOGIN = 0x0004, + TLO_UNSUPPORTED_FORMAT_FOR_DATA_OUT_BUFFER_DESCRIPTOR = 0x0006, + TLO_UNSUPPORTED_FORMAT_FOR_DATA_IN_BUFFER_DESCRIPTOR = 0x0007, + TLO_INVALID_COUNT_VALUE_IN_DATA_OUT_BUFFER_DESCRIPTOR_COUNT = 0x0008, + TLO_INVALID_COUNT_VALUE_IN_DATA_IN_BUFFER_DESCRIPTOR_COUNT = 0x0009 +} TARGET_LOGOUT_REASON_CODE; + +typedef struct _srp_t_logout +{ + uint8_t type; + uint8_t reserved[3]; + uint32_t reason; + uint64_t m_tag; +} PACK_SUFFIX srp_t_logout_t; + +/* Srp Task Management Flags */ +#define TMF_ABORT_TASK 0x01 +#define TMF_ABORT_TASK_SET 0x02 +#define TMF_CLEAR_TASK_SET 0x04 +#define TMF_LOGICAL_UNIT_RESET 0x08 +#define TMF_RESTRICTED 0x20 +#define TMF_CLEAR_ACA 0x40 + +typedef struct _srp_tsk_mgmt +{ + uint8_t type; + uint8_t reserved1[7]; + uint64_t tag; + uint8_t reserved2[4]; + uint64_t logical_unit_number; + uint8_t reserved3; + uint8_t reserved4; + uint8_t task_management_flags; + uint8_t reserved5; + uint64_t managed_task_tag; + uint8_t reserved6[8]; +} PACK_SUFFIX srp_tsk_mgmt_t; + +/* Srp TASK ATTRIBUTE VALUES */ +typedef enum task_attribute_value_enum +{ + TAV_SIMPLE_TASK = 0x00, + TAV_HEAD_OF_QUEUE_TASK = 0x01, + TAV_ORDERED = 0x02, + TAV_AUTOMATIC_CONTINGENT_ALLIANCE_TASK = 0x04 +} TASK_ATTRIBUTE_VALUE; + +typedef struct _srp_memory_descriptor +{ + uint64_t virtual_address; + uint32_t memory_handle; + uint32_t data_length; +} PACK_SUFFIX srp_memory_descriptor_t; + +typedef struct _srp_memory_table_descriptor +{ + srp_memory_descriptor_t descriptor; + uint32_t total_length; +} PACK_SUFFIX srp_memory_table_descriptor_t; + +typedef struct _srp_cmd +{ + uint8_t type; + uint8_t reserved1[4]; + uint8_t data_out_in_buffer_desc_fmt; + uint8_t data_out_buffer_desc_count; + uint8_t data_in_buffer_desc_count; + uint64_t tag; + uint8_t reserved2[4]; + uint64_t logical_unit_number; + uint8_t reserved3; + uint8_t flags1; /* TASK ATTRIBUTE */ + uint8_t reserved4; + uint8_t flags2; /* ADDITIONAL CDB LENGTH in 4 byte words */ + uint8_t cdb[16]; + uint8_t additional_cdb[1]; /* place holder, may not be present */ + /* srp_memory_descriptor_t data_out_buffer_desc[] */ + /* srp_memory_descriptor_t data_in_buffer_desc[] */ +} PACK_SUFFIX srp_cmd_t; + +/* Srp Response Code values */ +typedef enum response_code_value_enum +{ + RC_NO_FAILURE_OR_TSK_MGMT_FUNC_COMPLETE = 0x00, + RC_REQUEST_FIELDS_INVALID = 0x02, + RC_TSK_MGMT_FUNCTION_NOT_SUPPORTED = 0x04, + RC_TSK_MGMT_FUNCTION_FAILED = 0x05 +} RESPONSE_CODE_VALUE; + +typedef struct _srp_response_data +{ + uint8_t reserved[3]; + uint8_t response_code; +} PACK_SUFFIX srp_response_data_t; + +typedef struct _srp_rsp +{ + uint8_t type; + uint8_t reserved1[3]; + int32_t request_limit_delta; + uint64_t tag; + uint8_t reserved2[2]; + uint8_t flags; /* DIUNDER DIOVER DOUNDER DOOVER SNSVALID RSPVALID */ + uint8_t status; + uint32_t data_out_residual_count; + uint32_t data_in_residual_count; + uint32_t sense_data_list_length; + uint32_t response_data_list_length; + srp_response_data_t response_data[1]; /* place holder. may not be present */ + /* uint8_t sense_data[] */ +} PACK_SUFFIX srp_rsp_t; + +typedef struct _srp_cred_req +{ + uint8_t type; + uint8_t reserved[3]; + int32_t request_limit_delta; + uint64_t tag; +} PACK_SUFFIX srp_cred_req_t; + +typedef struct _srp_cred_rsp +{ + uint8_t type; + uint8_t reserved[7]; + uint64_t tag; +} PACK_SUFFIX srp_cred_rsp_t; + +typedef struct _srp_aer_req +{ + uint8_t type; + uint8_t reserved1[3]; + int32_t request_limit_delta; + uint64_t tag; + uint8_t reserved2[4]; + uint64_t logical_unit_number; + uint32_t sense_data_list_length; + uint8_t reserved3[4]; + uint8_t sense_data[1]; /* actually a place holder may not be present */ +} PACK_SUFFIX srp_aer_req_t; + +typedef struct _srp_aer_rsp +{ + uint8_t type; + uint8_t reserved[7]; + uint64_t tag; +} PACK_SUFFIX srp_aer_rsp_t; + +typedef union _srp_iu_buffer +{ + uint64_t alignment_dummy; + uint8_t iu_buffer[SRP_MAX_IU_SIZE]; + srp_information_unit_t information_unit; + srp_login_req_t login_request; + srp_login_rsp_t login_response; + srp_login_rej_t login_reject; + srp_i_logout_t initiator_logout; + srp_t_logout_t target_logout; + srp_tsk_mgmt_t task_management; + srp_cmd_t command; + srp_rsp_t response; + srp_cred_req_t credit_request; + srp_cred_rsp_t credit_response; + srp_aer_req_t async_event_request; + srp_aer_rsp_t async_event_response; +} PACK_SUFFIX srp_iu_buffer_t; + +#include + +#endif /* SRP_H_INCLUDED */ diff --git a/branches/WOF2-3/ulp/srp/kernel/srp_aer_req.h b/branches/WOF2-3/ulp/srp/kernel/srp_aer_req.h new file mode 100644 index 00000000..540c41ce --- /dev/null +++ b/branches/WOF2-3/ulp/srp/kernel/srp_aer_req.h @@ -0,0 +1,295 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#ifndef SRP_AER_REQ_H_INCLUDED +#define SRP_AER_REQ_H_INCLUDED + +#include "srp.h" +#include "srp_iu_buffer.h" +#include "srp_Information_unit.h" + +/* set_srp_async_event_request_tag */ +/*! +Sets the tag field of a AsyncEvent request information unit + +@param p_information_unit - pointer to the IU structure +@param iu_tag - tag value of IU + +@return - none +*/ +static inline +void +set_srp_async_event_request_tag( + IN OUT srp_aer_req_t *p_information_unit, + IN uint64_t iu_tag ) +{ + set_srp_information_unit_tag( ( srp_information_unit_t* ) p_information_unit, iu_tag ); +} + +/* init_srp_async_event_request */ +/*! +Initializes the AsyncEvent request IU to zeroes +and sets the IU type to Srp AsyncEvent request +and sets the tag to the value supplied + +@param p_information_unit - pointer to the IU structure +@param iu_tag - tag value to be used for the req/rsp pair + +@return - none +*/ +static inline +void +init_srp_async_event_request( + IN OUT srp_aer_req_t *p_information_unit, + IN uint64_t iu_tag ) +{ + init_srp_iu_buffer( ( srp_iu_buffer_t* ) p_information_unit, SRP_AER_REQ ) ; + set_srp_async_event_request_tag( p_information_unit, iu_tag ); +} + +/* set_srp_async_event_request_request_limit_delta */ +/*! +Sets the request limit delta for the AsyncEvent request + +@param p_information_unit - pointer to the IU structure +@param request_limit_delta - flow control request limit delta + +@return - none +*/ +static inline +void +set_srp_async_event_request_request_limit_delta( + IN OUT srp_aer_req_t *p_information_unit, + IN int32_t request_limit_delta ) +{ + p_information_unit->request_limit_delta = request_limit_delta; +} + +/* set_srp_async_event_request_logical_unit_number */ +/*! +Sets the logical unit number for the AsyncEvent request + +@param p_information_unit - pointer to the IU structure +@param logical_unit_number - logical unit number for request + +@return - none +*/ +static inline +void +set_srp_async_event_request_logical_unit_number( + IN OUT srp_aer_req_t *p_information_unit, + IN uint64_t logical_unit_number ) +{ + p_information_unit->logical_unit_number = logical_unit_number; +} + +/* set_srp_async_event_request_sense_data_list_length */ +/*! +Sets the sense data list length for the AsyncEvent request + +@param p_information_unit - pointer to the IU structure +@param sense_data_list_length - length of sense data + +@return - none +*/ +static inline +void +set_srp_async_event_request_sense_data_list_length( + IN OUT srp_aer_req_t *p_information_unit, + IN uint32_t sense_data_list_length ) +{ + p_information_unit->sense_data_list_length = sense_data_list_length; +} + +/* setup_srp_async_event_request */ +/*! +Initializes and sets the Srp AsyncEvent request IU to the values supplied + +@param p_information_unit - pointer to the IU structure +@param iu_tag - tag value to be used for the req/rsp pair +@param request_limit_delta - flow control request limit delta +@param logical_unit_number - logical unit number for request +@param sense_data_list_length - length of sense data + +@return - pointer to the sense data area +*/ +static inline +uint8_t* +setup_srp_async_event_request( + IN OUT srp_aer_req_t *p_information_unit, + IN uint64_t iu_tag, + IN int32_t request_limit_delta, + IN uint64_t logical_unit_number, + IN uint32_t sense_data_list_length ) +{ + init_srp_async_event_request( p_information_unit, iu_tag ); + set_srp_async_event_request_request_limit_delta( p_information_unit, request_limit_delta ); + set_srp_async_event_request_logical_unit_number( p_information_unit, logical_unit_number ); + set_srp_async_event_request_sense_data_list_length( p_information_unit, sense_data_list_length ); + return( p_information_unit->sense_data ); +} + +/* get_srp_async_event_request_tag */ +/*! +Returns the value of the tag field of a AsyncEvent request + +@param p_information_unit - pointer to the IU structure + +@return - tag value +*/ +static inline +uint64_t +get_srp_async_event_request_tag( + IN srp_aer_req_t *p_information_unit ) +{ + return( get_srp_information_unit_tag( ( srp_information_unit_t* ) p_information_unit ) ); +} + +/* get_srp_async_event_request_request_limit_delta */ +/*! +Returns the value of the request limit delta field of a AsyncEvent request + +@param p_information_unit - pointer to the IU structure + +@return - request limit delta value +*/ +static inline +int32_t +get_srp_async_event_request_request_limit_delta( + IN srp_aer_req_t *p_information_unit ) +{ + return( p_information_unit->request_limit_delta ); +} + +/* get_srp_async_event_request_logical_unit_number */ +/*! +Returns the value of the logical unit number field of a AsyncEvent request + +@param p_information_unit - pointer to the IU structure + +@return - logical unit number value +*/ +static inline +uint64_t +get_srp_async_event_request_logical_unit_number( + IN srp_aer_req_t *p_information_unit ) +{ + return( p_information_unit->logical_unit_number ); +} + +/* get_srp_async_event_request_sense_data_list_length */ +/*! +Returns the value of the sense data list length field of a AsyncEvent request + +@param p_information_unit - pointer to the IU structure + +@return - sense data list length value +*/ +static inline +uint32_t +get_srp_async_event_request_sense_data_list_length( + IN srp_aer_req_t *p_information_unit ) +{ + return( p_information_unit->sense_data_list_length ); +} + +/* get_srp_async_event_request_sense_data */ +/*! +Returns a pointer to the sense data field of a AsyncEvent request + +@param p_information_unit - pointer to the IU structure + +@return - pointer to the sense data +*/ +static inline +uint8_t* +get_srp_async_event_request_sense_data( + IN srp_aer_req_t *p_information_unit ) +{ + return( p_information_unit->sense_data ); +} + +/* get_srp_async_event_request_length */ +/*! +Returns the size in bytes of the Srp AsyncEvent request IU + +@param p_information_unit - pointer to the IU structure + +@return - tag value +*/ +static inline +uint32_t +get_srp_async_event_request_length( + IN srp_aer_req_t *p_information_unit ) +{ + /* do not include sense data field in the sizeof the IU. add it's length to the structure size */ + return( ( sizeof( *p_information_unit ) - sizeof( p_information_unit->sense_data ) ) + p_information_unit->sense_data_list_length ); +} + +/* set_srp_async_event_request_from_host_to_network */ +/*! +Swaps the IU fields from Host to Network ordering + +@param p_information_unit - pointer to the IU structure + +@return - none +*/ + +static inline +void +set_srp_async_event_request_from_host_to_network( + IN OUT srp_aer_req_t *p_information_unit ) +{ + set_srp_information_unit_from_host_to_network( ( srp_information_unit_t* ) p_information_unit ); + p_information_unit->request_limit_delta = cl_hton32( p_information_unit->request_limit_delta ); + p_information_unit->logical_unit_number = cl_hton64( p_information_unit->logical_unit_number ); + p_information_unit->sense_data_list_length = cl_hton32( p_information_unit->sense_data_list_length ); +} + +/* set_srp_async_event_request_from_network_to_host */ +/*! +Swaps the IU fields from Network to Host ordering + +@param p_information_unit - pointer to the IU structure + +@return - none +*/ + +static inline +void +set_srp_async_event_request_from_network_to_host( + IN OUT srp_aer_req_t *p_information_unit ) +{ + set_srp_async_event_request_from_host_to_network ( p_information_unit ); +} + +#endif /* SRP_AER_REQ_H_INCLUDED */ diff --git a/branches/WOF2-3/ulp/srp/kernel/srp_aer_rsp.h b/branches/WOF2-3/ulp/srp/kernel/srp_aer_rsp.h new file mode 100644 index 00000000..78d9deeb --- /dev/null +++ b/branches/WOF2-3/ulp/srp/kernel/srp_aer_rsp.h @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#ifndef SRP_AER_RSP_H_INCLUDED +#define SRP_AER_RSP_H_INCLUDED + +#include "srp.h" +#include "srp_iu_buffer.h" +#include "srp_Information_unit.h" + +/* set_srp_async_event_response_tag */ +/*! +Sets the tag field of a Async Event response information unit + +@param p_information_unit - pointer to the IU structure +@param iu_tag - tag value of IU + +@return - none +*/ +static inline +void +set_srp_async_event_response_tag( + IN OUT srp_aer_rsp_t *p_information_unit, + IN uint64_t iu_tag ) +{ + set_srp_information_unit_tag( ( srp_information_unit_t* ) p_information_unit, iu_tag ); +} + +/* init_srp_async_event_response */ +/*! +Initializes the Async Event response IU to zeroes +and sets the IU type to Srp Async Event Response +and sets the tag to the value supplied + +@param p_information_unit - pointer to the IU structure +@param iu_tag - tag value to be used for the req/rsp pair + +@return - none +*/ +static inline +void +init_srp_async_event_response( + IN OUT srp_aer_rsp_t *p_information_unit, + IN uint64_t iu_tag ) +{ + init_srp_iu_buffer( ( srp_iu_buffer_t* ) p_information_unit, SRP_AER_RSP ) ; + set_srp_async_event_response_tag( p_information_unit, iu_tag ); +} + +/* setup_srp_async_event_response */ +/*! +Initializes and sets the Srp Async Event Response IU to the values supplied + +@param p_information_unit - pointer to the IU structure +@param iu_tag - tag value to be used for the req/rsp pair + +@return - none +*/ +static inline +void +setup_srp_async_event_response( + IN OUT srp_aer_rsp_t *p_information_unit, + IN uint64_t iu_tag ) +{ + init_srp_async_event_response( p_information_unit, iu_tag ); +} + +/* get_srp_async_event_response_tag */ +/*! +Returns the value of the tag field of a Async Event response + +@param p_information_unit - pointer to the IU structure + +@return - tag value +*/ +static inline +uint64_t +get_srp_async_event_response_tag( + IN srp_aer_rsp_t *p_information_unit ) +{ + return( get_srp_information_unit_tag( ( srp_information_unit_t* ) p_information_unit ) ); +} + +/* get_srp_async_event_response_length */ +/*! +Returns the size in bytes of the Srp AsyncEvent Response IU + +@param p_information_unit - pointer to the IU structure + +@return - tag value +*/ +static inline +uint32_t +get_srp_async_event_response_length( + IN srp_aer_rsp_t *p_information_unit ) +{ + return( sizeof( *p_information_unit ) ); +} + +/* set_srp_async_event_response_from_host_to_network */ +/*! +Swaps the IU fields from Host to Network ordering + +@param p_information_unit - pointer to the IU structure + +@return - none +*/ + +static inline +void +set_srp_async_event_response_from_host_to_network( + IN OUT srp_aer_rsp_t *p_information_unit ) +{ + set_srp_information_unit_from_host_to_network( ( srp_information_unit_t* ) p_information_unit ); +} + +/* set_srp_async_event_response_from_network_to_host */ +/*! +Swaps the IU fields from Network to Host ordering + +@param p_information_unit - pointer to the IU structure + +@return - none +*/ + +static inline +void +set_srp_async_event_response_from_network_to_host( + IN OUT srp_aer_rsp_t *p_information_unit ) +{ + set_srp_async_event_response_from_host_to_network ( p_information_unit ); +} + +#endif /* SRP_AER_RSP_H_INCLUDED */ diff --git a/branches/WOF2-3/ulp/srp/kernel/srp_cmd.h b/branches/WOF2-3/ulp/srp/kernel/srp_cmd.h new file mode 100644 index 00000000..3c1e76e3 --- /dev/null +++ b/branches/WOF2-3/ulp/srp/kernel/srp_cmd.h @@ -0,0 +1,648 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#ifndef SRP_CMD_H_INCLUDED +#define SRP_CMD_H_INCLUDED + +#include "srp.h" +#include "srp_iu_buffer.h" +#include "srp_information_unit.h" + +/* set_srp_command_tag */ +/*! +Sets the tag field of a command information unit + +@param p_information_unit - pointer to the IU structure +@param iu_tag - tag value of IU + +@return - none +*/ +static inline +void +set_srp_command_tag( + IN OUT srp_cmd_t *p_information_unit, + IN uint64_t iu_tag ) +{ + set_srp_information_unit_tag( ( srp_information_unit_t* ) p_information_unit, iu_tag ); +} + +/* init_srp_command */ +/*! +Initializes the command IU to zeroes +and sets the IU type to command +and sets the tag to the value supplied + +@param p_information_unit - pointer to the IU structure +@param iu_tag - tag value to be used for the req/rsp pair + +@return - none +*/ +static inline +void +init_srp_command( + IN OUT srp_cmd_t *p_information_unit, + IN uint64_t iu_tag ) +{ + init_srp_iu_buffer( ( srp_iu_buffer_t* ) p_information_unit, SRP_CMD ) ; + set_srp_command_tag( p_information_unit, iu_tag ); +} + +/* set_srp_command_data_out_buffer_desc_fmt */ +/*! +sets the data out buffer descriptor format value + +@param p_information_unit - pointer to the IU structure +@param data_out_buffer_desc_fmt - buffer descriptor format value + +@return - none +*/ +static inline +void +set_srp_command_data_out_buffer_desc_fmt( + IN OUT srp_cmd_t *p_information_unit, + IN DATA_BUFFER_DESCRIPTOR_FORMAT data_out_buffer_desc_fmt ) +{ + p_information_unit->data_out_in_buffer_desc_fmt = + ( p_information_unit->data_out_in_buffer_desc_fmt & 0x0F ) | ( (uint8_t)data_out_buffer_desc_fmt << 4 ); +} + +/* set_srp_command_data_in_buffer_desc_fmt */ +/*! +sets the data in buffer descriptor format value + +@param p_information_unit - pointer to the IU structure +@param data_in_buffer_desc_fmt - buffer descriptor format value + +@return - none +*/ +static inline +void +set_srp_command_data_in_buffer_desc_fmt( + IN OUT srp_cmd_t *p_information_unit, + IN DATA_BUFFER_DESCRIPTOR_FORMAT data_in_buffer_desc_fmt ) +{ + p_information_unit->data_out_in_buffer_desc_fmt = ( p_information_unit->data_out_in_buffer_desc_fmt & 0xF0 ) | (uint8_t)data_in_buffer_desc_fmt; +} + +/* set_srp_command_data_out_buffer_desc_count */ +/*! +sets the data out buffer descriptor count value + +@param p_information_unit - pointer to the IU structure +@param data_out_buffer_desc_count - buffer descriptor count value + +@return - none +*/ +static inline +void +set_srp_command_data_out_buffer_desc_count( + IN OUT srp_cmd_t *p_information_unit, + IN uint8_t data_out_buffer_desc_count ) +{ + p_information_unit->data_out_buffer_desc_count = data_out_buffer_desc_count; +} + +/* set_srp_command_data_in_buffer_desc_count */ +/*! +sets the data in buffer descriptor count value + +@param p_information_unit - pointer to the IU structure +@param data_in_buffer_desc_count - buffer descriptor count value + +@return - none +*/ +static inline +void +set_srp_command_data_in_buffer_desc_count( + IN OUT srp_cmd_t *p_information_unit, + IN uint8_t data_in_buffer_desc_count ) +{ + p_information_unit->data_in_buffer_desc_count = data_in_buffer_desc_count; +} + +/* set_srp_command_logical_unit_number */ +/*! +Sets the logical unit number for the command IU + +@param p_information_unit - pointer to the IU structure +@param logical_unit_number - logical unit number for request + +@return - none +*/ +static inline +void +set_srp_command_logical_unit_number( + IN OUT srp_cmd_t *p_information_unit, + IN uint64_t logical_unit_number ) +{ + p_information_unit->logical_unit_number = logical_unit_number; +} + +/* set_srp_command_task_attribute */ +/*! +Sets the task attribute for the command IU + +@param p_information_unit - pointer to the IU structure +@param task_attribute - task attribute for the request + +@return - none +*/ +static inline +void +set_srp_command_task_attribute( + IN OUT srp_cmd_t *p_information_unit, + IN TASK_ATTRIBUTE_VALUE task_attribute ) +{ + p_information_unit->flags1 = ( p_information_unit->flags1 & 0xF8 ) | ( (uint8_t)task_attribute ); +} + +/* set_srp_command_additional_cdb_length */ +/*! +Sets the additional CDB length for the command IU + +@param p_information_unit - pointer to the IU structure +@param additional_cdb_length - additional CDB length for the request + +@return - none +*/ +static inline +void +set_srp_command_additional_cdb_length( + IN OUT srp_cmd_t *p_information_unit, + IN uint8_t additional_cdb_length ) +{ + p_information_unit->flags2 = ( p_information_unit->flags2 & 0x03 ) | ( additional_cdb_length << 2 ); +} + +/* setup_srp_command */ +/*! +Initializes and sets the Srp command IU to the values supplied + +@param p_information_unit - pointer to the IU structure +@param iu_tag - tag value to be used for the req/rsp pair +@param data_out_buffer_desc_fmt - buffer descriptor format value +@param data_in_buffer_desc_fmt - buffer descriptor format value +@param data_out_buffer_desc_count - buffer descriptor count value +@param data_in_buffer_desc_count - buffer descriptor count value +@param logical_unit_number - logical unit number for request +@param task_attribute - task attribute for the request +@param additional_cdb_length - additional CDB length for the request + +@return - pointer to the CDB +*/ +static inline +uint8_t* +setup_srp_command( + IN OUT srp_cmd_t *p_information_unit, + IN uint64_t iu_tag, + IN DATA_BUFFER_DESCRIPTOR_FORMAT data_out_buffer_desc_fmt, + IN DATA_BUFFER_DESCRIPTOR_FORMAT data_in_buffer_desc_fmt, + IN uint8_t data_out_buffer_desc_count, + IN uint8_t data_in_buffer_desc_count, + IN uint64_t logical_unit_number, + IN TASK_ATTRIBUTE_VALUE task_attribute, + IN uint8_t additional_cdb_length ) +{ + init_srp_command( p_information_unit, iu_tag ); + set_srp_command_data_out_buffer_desc_fmt( p_information_unit, data_out_buffer_desc_fmt ); + set_srp_command_data_in_buffer_desc_fmt( p_information_unit, data_in_buffer_desc_fmt ); + set_srp_command_data_out_buffer_desc_count( p_information_unit, data_out_buffer_desc_count ); + set_srp_command_data_in_buffer_desc_count( p_information_unit, data_in_buffer_desc_count ); + set_srp_command_logical_unit_number( p_information_unit, logical_unit_number ); + set_srp_command_task_attribute( p_information_unit, task_attribute ); + set_srp_command_additional_cdb_length( p_information_unit, additional_cdb_length ); + return( p_information_unit->cdb ); +} + +/* get_srp_command_tag */ +/*! +Returns the value of the tag field of a AsyncEvent request + +@param p_information_unit - pointer to the IU structure + +@return - tag value +*/ +static inline +uint64_t +get_srp_command_tag( + IN srp_cmd_t *p_information_unit ) +{ + return( get_srp_information_unit_tag( ( srp_information_unit_t* ) p_information_unit ) ); +} + +/* get_srp_command_data_out_buffer_desc_fmt */ +/*! +Returns the value of the data out buffer descriptor format field of a command + +@param p_information_unit - pointer to the IU structure + +@return - data out buffer descriptor format value +*/ +static inline +DATA_BUFFER_DESCRIPTOR_FORMAT +get_srp_command_data_out_buffer_desc_fmt( + IN srp_cmd_t *p_information_unit ) +{ + return( ( DATA_BUFFER_DESCRIPTOR_FORMAT ) ( p_information_unit->data_out_in_buffer_desc_fmt >> 4 ) ); +} + +/* get_srp_command_data_in_buffer_desc_fmt */ +/*! +Returns the value of the data in buffer descriptor format field of a command + +@param p_information_unit - pointer to the IU structure + +@return - data in buffer descriptor format value +*/ +static inline +DATA_BUFFER_DESCRIPTOR_FORMAT +get_srp_command_data_in_buffer_desc_fmt( + IN srp_cmd_t *p_information_unit ) +{ + return( ( DATA_BUFFER_DESCRIPTOR_FORMAT ) ( p_information_unit->data_out_in_buffer_desc_fmt & 0x0F ) ); +} + +/* get_srp_command_data_out_buffer_desc_count */ +/*! +Returns the value of the data out buffer descriptor count field of a command + +@param p_information_unit - pointer to the IU structure + +@return - data out buffer descriptor count value +*/ +static inline +uint8_t +get_srp_command_data_out_buffer_desc_count( + IN srp_cmd_t *p_information_unit ) +{ + return( p_information_unit->data_out_buffer_desc_count ); +} + +/* get_srp_command_data_in_buffer_desc_count */ +/*! +Returns the value of the data in buffer descriptor count field of a command + +@param p_information_unit - pointer to the IU structure + +@return - data in buffer descriptor count value +*/ +static inline +uint8_t +get_srp_command_data_in_buffer_desc_count( + IN srp_cmd_t *p_information_unit ) +{ + return( p_information_unit->data_in_buffer_desc_count ); +} + +/* get_srp_command_logical_unit_number */ +/*! +Returns the value of the logical unit number field of a command IU + +@param p_information_unit - pointer to the IU structure + +@return - logical unit number value +*/ +static inline +uint64_t +get_srp_command_logical_unit_number( + IN srp_cmd_t *p_information_unit ) +{ + return( p_information_unit->logical_unit_number ); +} + +/* get_srp_command_task_attribute */ +/*! +Returns the value of the task attribute field of a command + +@param p_information_unit - pointer to the IU structure + +@return - task attribute value +*/ +static inline +TASK_ATTRIBUTE_VALUE +get_srp_command_task_attribute( + IN srp_cmd_t *p_information_unit ) +{ + return( ( TASK_ATTRIBUTE_VALUE ) ( p_information_unit->flags1 & 0x07 ) ); +} + +/* get_srp_command_additional_cdb_length */ +/*! +Returns the value of the additional CDB length field of a command + +@param p_information_unit - pointer to the IU structure + +@return - additional CDB length value +*/ +static inline +uint8_t +get_srp_command_additional_cdb_length( + IN srp_cmd_t *p_information_unit ) +{ + return( ( uint8_t ) ( p_information_unit->flags2 & 0xFC ) >> 2 ); +} + +/* get_srp_command_cdb */ +/*! +Returns a pointer to the CDB field of a command + +@param p_information_unit - pointer to the IU structure + +@return - pointer to the CDB +*/ +static inline +uint8_t* +get_srp_command_cdb( + IN srp_cmd_t *p_information_unit ) +{ + return( p_information_unit->cdb ); +} + +/* get_srp_command_additional_cdb */ +/*! +Returns a pointer to the additional CDB field of a command + +@param p_information_unit - pointer to the IU structure + +@return - pointer to the additional CDB +*/ +static inline +uint8_t* +get_srp_command_additional_cdb( + IN srp_cmd_t *p_information_unit ) +{ + if( get_srp_command_additional_cdb_length( p_information_unit ) == 0 ) + { + return( NULL ); + } + + return( p_information_unit->additional_cdb ); +} + +/* get_srp_command_data_out_buffer_desc */ +/*! +Returns a pointer to the data out buffer desc field of a command + +WARNING!!!! Set the additional CDB length before this call so the + offset can be correctly calculated + +@param p_information_unit - pointer to the IU structure + +@return - pointer to data out buffer desc +*/ +static inline +srp_memory_descriptor_t* +get_srp_command_data_out_buffer_desc( + IN srp_cmd_t *p_information_unit ) +{ + if( get_srp_command_data_out_buffer_desc_fmt( p_information_unit ) == DBDF_NO_DATA_BUFFER_DESCRIPTOR_PRESENT ) + { + return( NULL ); + } + + return( ( srp_memory_descriptor_t* ) ( p_information_unit->additional_cdb + ( get_srp_command_additional_cdb_length( p_information_unit ) * 4 ) ) ); +} + +/* get_srp_command_data_in_buffer_desc */ +/*! +Returns a pointer to the data in buffer desc field of a command + +WARNING!!!! Set the additional CDB length and data out buffer descriptor count + before this call so the offset can be correctly calculated + +@param p_information_unit - pointer to the IU structure + +@return - pointer to data in buffer desc +*/ +static inline +srp_memory_descriptor_t* +get_srp_command_data_in_buffer_desc( + IN srp_cmd_t *p_information_unit ) +{ + if( get_srp_command_data_in_buffer_desc_fmt( p_information_unit ) == DBDF_NO_DATA_BUFFER_DESCRIPTOR_PRESENT ) + { + return( NULL ); + } + + return( ( srp_memory_descriptor_t* ) ( p_information_unit->additional_cdb + + ( get_srp_command_additional_cdb_length( p_information_unit ) * 4 ) + + ( get_srp_command_data_out_buffer_desc_count( p_information_unit ) * sizeof( srp_memory_descriptor_t ) ) ) ); +} + +/* get_srp_command_buffer_desc */ +/*! +Returns a pointer to the start of the data buffer descs of a command + +WARNING!!!! Set the additional CDB length before this call so the + offset can be correctly calculated + +@param p_information_unit - pointer to the IU structure + +@return - pointer to start of data buffer descs block +*/ +static inline +srp_memory_descriptor_t* +get_srp_command_buffer_desc( + IN srp_cmd_t *p_information_unit ) +{ + return( ( srp_memory_descriptor_t* ) ( p_information_unit->additional_cdb + ( get_srp_command_additional_cdb_length( p_information_unit ) * 4 ) ) ); +} + + +/* get_srp_command_Length */ +/*! +Returns the size in bytes of the Srp command IU + +@param p_information_unit - pointer to the IU structure + +@return - used length of command IU buffer +*/ +static inline +uint32_t +get_srp_command_length( + IN srp_cmd_t *p_information_unit ) +{ + int buffer_desc_count; + uint32_t srp_cmd_length = ( sizeof( *p_information_unit ) - sizeof( p_information_unit->additional_cdb ) ) + + ( get_srp_command_additional_cdb_length( p_information_unit ) * 4 ); + + switch ( get_srp_command_data_out_buffer_desc_fmt ( p_information_unit )) + { + case DBDF_DIRECT_DATA_BUFFER_DESCRIPTOR: + buffer_desc_count = get_srp_command_data_out_buffer_desc_count( p_information_unit ); + srp_cmd_length += ( buffer_desc_count == 0)? sizeof(srp_memory_descriptor_t): + ( buffer_desc_count * sizeof(srp_memory_descriptor_t )); + break; + case DBDF_INDIRECT_DATA_BUFFER_DESCRIPTORS: + buffer_desc_count = get_srp_command_data_out_buffer_desc_count( p_information_unit ); + srp_cmd_length += sizeof(srp_memory_table_descriptor_t) + ( buffer_desc_count * sizeof(srp_memory_descriptor_t)); + break; + default: + break; + } + + switch ( get_srp_command_data_in_buffer_desc_fmt ( p_information_unit )) + { + case DBDF_DIRECT_DATA_BUFFER_DESCRIPTOR: + buffer_desc_count = get_srp_command_data_in_buffer_desc_count( p_information_unit ); + srp_cmd_length += ( buffer_desc_count == 0)? sizeof(srp_memory_descriptor_t): + ( buffer_desc_count * sizeof(srp_memory_descriptor_t )); + break; + case DBDF_INDIRECT_DATA_BUFFER_DESCRIPTORS: + buffer_desc_count = get_srp_command_data_in_buffer_desc_count( p_information_unit ); + srp_cmd_length += sizeof(srp_memory_table_descriptor_t) + ( buffer_desc_count * sizeof(srp_memory_descriptor_t)); + break; + default: + break; + } + return ( srp_cmd_length ); +} + +/* set_srp_command_from_host_to_network */ +/*! +Swaps the IU fields from Host to Network ordering + +@param p_information_unit - pointer to the IU structure + +@return - none +*/ + +static inline +void +set_srp_command_from_host_to_network( + IN OUT srp_cmd_t *p_information_unit ) +{ + srp_memory_descriptor_t *p_memory_descriptor; + srp_memory_table_descriptor_t *p_table_descriptor; + int buffer_desc_count; + int i; + + set_srp_information_unit_from_host_to_network( ( srp_information_unit_t* ) p_information_unit ); + p_information_unit->logical_unit_number = cl_hton64( p_information_unit->logical_unit_number ); + + p_memory_descriptor = get_srp_command_buffer_desc( p_information_unit ); + + switch (get_srp_command_data_out_buffer_desc_fmt(p_information_unit) ) + { + case DBDF_DIRECT_DATA_BUFFER_DESCRIPTOR: + buffer_desc_count = get_srp_command_data_out_buffer_desc_count( p_information_unit ); + if ( p_memory_descriptor != NULL ) + { + for ( i=0; i < buffer_desc_count; i++) + { + p_memory_descriptor->virtual_address = cl_hton64( p_memory_descriptor->virtual_address ); + p_memory_descriptor->data_length = cl_hton32 ( p_memory_descriptor->data_length ); + p_memory_descriptor++; + } + } + break; + case DBDF_INDIRECT_DATA_BUFFER_DESCRIPTORS: + buffer_desc_count = get_srp_command_data_out_buffer_desc_count( p_information_unit ); + if ( p_memory_descriptor != NULL ) + { + p_table_descriptor = ( srp_memory_table_descriptor_t *)p_memory_descriptor; + p_memory_descriptor = ( srp_memory_descriptor_t *)( p_table_descriptor + 1); + + p_table_descriptor->descriptor.virtual_address = cl_hton64( p_table_descriptor->descriptor.virtual_address ); + p_table_descriptor->descriptor.data_length = cl_hton32( p_table_descriptor->descriptor.data_length ); + p_table_descriptor->total_length = cl_hton32( p_table_descriptor->total_length ); + + for ( i=0; i < buffer_desc_count; i++) + { + p_memory_descriptor->virtual_address = cl_hton64( p_memory_descriptor->virtual_address ); + p_memory_descriptor->data_length = cl_hton32( p_memory_descriptor->data_length ); + p_memory_descriptor++; + } + } + break; + case DBDF_NO_DATA_BUFFER_DESCRIPTOR_PRESENT: + default: + break; + } + + switch (get_srp_command_data_in_buffer_desc_fmt(p_information_unit) ) + { + case DBDF_DIRECT_DATA_BUFFER_DESCRIPTOR: + buffer_desc_count = get_srp_command_data_in_buffer_desc_count( p_information_unit ); + if ( p_memory_descriptor != NULL ) + { + for ( i=0; i < buffer_desc_count; i++) + { + p_memory_descriptor->virtual_address = cl_hton64( p_memory_descriptor->virtual_address ); + p_memory_descriptor->data_length = cl_hton32 ( p_memory_descriptor->data_length ); + p_memory_descriptor++; + } + } + break; + case DBDF_INDIRECT_DATA_BUFFER_DESCRIPTORS: + buffer_desc_count = get_srp_command_data_in_buffer_desc_count( p_information_unit ); + if ( p_memory_descriptor != NULL ) + { + p_table_descriptor = ( srp_memory_table_descriptor_t *)p_memory_descriptor; + p_memory_descriptor = ( srp_memory_descriptor_t *)( p_table_descriptor + 1); + + p_table_descriptor->descriptor.virtual_address = cl_hton64( p_table_descriptor->descriptor.virtual_address ); + p_table_descriptor->descriptor.data_length = cl_hton32( p_table_descriptor->descriptor.data_length ); + p_table_descriptor->total_length = cl_hton32( p_table_descriptor->total_length ); + + for ( i=0; i < buffer_desc_count; i++) + { + p_memory_descriptor->virtual_address = cl_hton64( p_memory_descriptor->virtual_address ); + p_memory_descriptor->data_length = cl_hton32( p_memory_descriptor->data_length ); + p_memory_descriptor++; + } + } + break; + case DBDF_NO_DATA_BUFFER_DESCRIPTOR_PRESENT: + default: + break; + } +} + +/* set_srp_command_from_network_to_host */ +/*! +Swaps the IU fields from Network to Host ordering + +@param p_information_unit - pointer to the IU structure + +@return - none +*/ + +static inline +void +set_srp_command_from_network_to_host( + IN OUT srp_cmd_t *p_information_unit ) +{ + set_srp_command_from_host_to_network ( p_information_unit ); +} + +#endif /* SRP_CMD_H_INCLUDED */ diff --git a/branches/WOF2-3/ulp/srp/kernel/srp_connection.c b/branches/WOF2-3/ulp/srp/kernel/srp_connection.c new file mode 100644 index 00000000..5b7780ff --- /dev/null +++ b/branches/WOF2-3/ulp/srp/kernel/srp_connection.c @@ -0,0 +1,874 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corp. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include "srp_data_path.h" +#include "srp_debug.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "srp_connection.tmh" +#endif +#include "srp_event.h" +#include "srp_hca.h" +#include "srp_session.h" + +#include "srp.h" +#include "srp_login_req.h" +#include "srp_login_rsp.h" +#include "srp_login_rej.h" + +#include "srp_connection.h" + +#include + +#if DBG + +extern void* gp_session[SRP_MAX_SERVICE_ENTRIES]; + +#endif + +/* __srp_create_cqs */ +/*! +Creates the send/recv completion queues to be used by this connection + +@param p_srp_connection - pointer to the connection structure +@param p_hca - pointer to the hca structure used by the connection +@param p_session - context passed to callback functions + +@return - result of cq creation +*/ +static +ib_api_status_t +__srp_create_cqs( + IN OUT srp_connection_t *p_srp_connection, + IN srp_hca_t *p_hca, + IN p_srp_session_t p_session ) +{ + ib_api_status_t status; + ib_cq_create_t cq_create; + ib_al_ifc_t *p_ifc; + + SRP_ENTER( SRP_DBG_PNP ); + + p_ifc = &p_hca->p_hba->ifc; + + // Create Send CQ + cq_create.size = SRP_DEFAULT_SEND_Q_DEPTH; + cq_create.pfn_comp_cb = srp_send_completion_cb; + cq_create.h_wait_obj = NULL; + + status = p_ifc->create_cq( p_hca->h_ca, + &cq_create, + p_session, + srp_async_event_handler_cb, + &p_srp_connection->h_send_cq ); + if( status != IB_SUCCESS ) + { + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("Cannot Create Send Completion Queue. Status = %d\n", status) ); + goto exit; + } + + // Create Receive CQ + cq_create.size = SRP_DEFAULT_RECV_Q_DEPTH; + cq_create.pfn_comp_cb = srp_recv_completion_cb; + cq_create.h_wait_obj = NULL; + + status = p_ifc->create_cq( p_hca->h_ca, + &cq_create, + p_session, + srp_async_event_handler_cb, + &p_srp_connection->h_recv_cq ); + if( status != IB_SUCCESS ) + { + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("Cannot Create Receive Completion Queue. Status = %d\n", status) ); + } + +exit: + SRP_EXIT( SRP_DBG_PNP ); + + return ( status ); +} + +/* __srp_create_qp */ +/*! +Creates the queue pair to be used by this connection + +@param p_srp_connection - pointer to the connection structure +@param p_hca - pointer to the hca structure used by the connection +@param p_session - context passed to callback functions + +@return - result of qp creation +*/ +static +ib_api_status_t +__srp_create_qp( + IN OUT srp_connection_t *p_srp_connection, + IN srp_hca_t *p_hca, + IN p_srp_session_t p_session ) +{ + ib_api_status_t status; + ib_qp_create_t qp_create; + ib_al_ifc_t *p_ifc; + + SRP_ENTER( SRP_DBG_PNP ); + + p_ifc = &p_hca->p_hba->ifc; + + // Create QP + cl_memclr( &qp_create, sizeof(qp_create) ); + qp_create.qp_type = IB_QPT_RELIABLE_CONN; + qp_create.sq_depth = SRP_DEFAULT_SEND_Q_DEPTH; + qp_create.rq_depth = SRP_DEFAULT_RECV_Q_DEPTH; + qp_create.sq_sge = 1; + qp_create.rq_sge = 1; + qp_create.h_sq_cq = p_srp_connection->h_send_cq; + qp_create.h_rq_cq = p_srp_connection->h_recv_cq; + qp_create.sq_signaled = FALSE;//TRUE; + + status = p_ifc->create_qp( p_hca->h_pd, + &qp_create, + p_session, + srp_async_event_handler_cb, + &p_srp_connection->h_qp ); + if ( status != IB_SUCCESS ) + { + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("Cannot Create Queue Pair. Status = %d\n", status) ); + } + + SRP_EXIT( SRP_DBG_PNP ); + + return ( status ); +} + +static +cl_status_t +__srp_create_wc_free_list( + IN OUT srp_connection_t *p_connection, + IN uint32_t completion_count ) +{ + cl_status_t status = CL_SUCCESS; + ib_wc_t *p_wc; + uint32_t i; + + SRP_ENTER( SRP_DBG_PNP ); + + p_connection->p_wc_array = cl_zalloc( sizeof( ib_wc_t ) * completion_count ); + if ( p_connection->p_wc_array == NULL ) + { + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("Failed to allocate %d work completions.\n", completion_count) ); + status = CL_INSUFFICIENT_MEMORY; + goto exit; + } + + p_wc = p_connection->p_wc_array; + + for ( i = 1; i < completion_count; i++, p_wc++ ) + { + p_wc->p_next = (p_wc + 1); + } + + p_connection->p_wc_free_list = p_connection->p_wc_array; + +exit: + SRP_EXIT( SRP_DBG_PNP ); + + return ( status ); +} + + +/* __srp_cm_request_cb */ +/*! +Callback for a connect request - not used by SRP - We initiate connections + +@param p_cm_request - pointer to the connect request structure + +@return - none +*/ +static +void +__srp_cm_request_cb( + IN ib_cm_req_rec_t *p_cm_request) +{ + SRP_ENTER( SRP_DBG_PNP ); + + UNUSED_PARAM ( p_cm_request ); + + SRP_EXIT( SRP_DBG_PNP ); +} + +/* __srp_cm_apr_cb */ +/*! +Callback for alternate path response - not used by SRP + +@param p_cm_apr_rec - pointer to the alternate path response structure + +@return - none +*/ +static +void +__srp_cm_apr_cb( + IN ib_cm_apr_rec_t *p_cm_apr_rec ) +{ + SRP_ENTER( SRP_DBG_PNP ); + + UNUSED_PARAM( p_cm_apr_rec ); + + SRP_EXIT( SRP_DBG_PNP ); +} + +/* __srp_cm_mra_cb */ +/*! +Callback for message received acknowledgement - ignored by SRP - wait for connect reply + +@param p_cm_mra_rec - pointer to the message received acknowledgement structure + +@return - none +*/ +static +void +__srp_cm_mra_cb( + IN ib_cm_mra_rec_t *p_cm_mra_rec) +{ + SRP_ENTER( SRP_DBG_PNP ); + + UNUSED_PARAM ( p_cm_mra_rec ); + + SRP_EXIT( SRP_DBG_PNP ); +} + +/* __srp_cm_dreq_cb */ +/*! +Callback for disconnect request from the target +Initiates the disconnect for the session + +TODO: + +@param p_cm_dreq_rec - pointer to the disconnect request structure + +@return - none +*/ +static +void +__srp_cm_dreq_cb( + IN ib_cm_dreq_rec_t *p_cm_dreq_rec ) +{ + srp_session_t *p_srp_session = (srp_session_t*)p_cm_dreq_rec->qp_context; + srp_hba_t *p_hba = p_srp_session->p_hba; + + SRP_ENTER( SRP_DBG_PNP ); + + cl_obj_lock( &p_srp_session->obj ); + + if (p_srp_session->connection.state == SRP_CONNECTED) + { + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_PNP, + ("**** SRP_CONNECTED => SRP_CONNECT_FAILURE. \n") ); + p_srp_session->connection.state = SRP_CONNECT_FAILURE; + cl_obj_unlock( &p_srp_session->obj ); + } + else // since the connection is no longer there, just exit + { + cl_obj_unlock( &p_srp_session->obj ); + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_PNP, + ("**** NOT SRP_CONNECTED *****. connection state = %d\n", p_srp_session->connection.state) ); + SRP_EXIT( SRP_DBG_PNP ); + return; + } + + SRP_PRINT( TRACE_LEVEL_WARNING, SRP_DBG_PNP, + ("Target has issued a disconnect request for Session %d ref_cnt = %d.\n", + p_srp_session->target_id, + p_srp_session->obj.ref_cnt) ); + + if( !p_hba->adapter_stopped ) + { + srp_session_failed( p_srp_session ); + } + + SRP_EXIT( SRP_DBG_PNP ); +} + +/* __srp_cm_reply_cb */ +/*! +Callback for connect reply from the target +The target has accepted our connect/login request + +@param p_cm_reply - pointer to the connect reply structure + +@return - none +*/ +static +void +__srp_cm_reply_cb( + IN ib_cm_rep_rec_t *p_cm_reply) +{ + srp_session_t *p_srp_session = (srp_session_t*)p_cm_reply->qp_context; + srp_connection_t *p_connection; + srp_login_rsp_t *p_srp_login_rsp = (srp_login_rsp_t*)p_cm_reply->p_rep_pdata; + ib_api_status_t status; + union + { + ib_cm_mra_t cm_mra; + ib_cm_rtu_t cm_rtu; + ib_cm_rej_t cm_rej; + + } u; + cl_status_t cl_status; + ib_al_ifc_t *p_ifc; + + SRP_ENTER( SRP_DBG_PNP ); + + p_ifc = &p_srp_session->p_hba->ifc; + p_connection = &p_srp_session->connection; + + set_srp_login_response_from_network_to_host( p_srp_login_rsp ); + p_connection->descriptor_format = get_srp_login_response_supported_data_buffer_formats( p_srp_login_rsp ); + + p_connection->request_limit = + MIN( get_srp_login_response_request_limit_delta( p_srp_login_rsp ), SRP_DEFAULT_RECV_Q_DEPTH ); + + if( ib_ioc_profile_get_vend_id( &p_srp_session->p_hba->ioc_info.profile) == 0x00066a && + cl_ntoh32( p_srp_session->p_hba->ioc_info.profile.subsys_id ) == 0x38 ) + { + /* workaround for FVIC */ + p_connection->request_limit /= 2; + } + + p_connection->max_limit = p_connection->request_limit; + p_connection->request_threashold = 2; +#if DBG + p_srp_session->x_req_limit = p_connection->request_limit; +#endif + + p_connection->send_queue_depth = p_connection->request_limit; + p_connection->recv_queue_depth = p_connection->request_limit; + p_connection->init_to_targ_iu_sz = get_srp_login_response_max_init_to_targ_iu( p_srp_login_rsp ); + p_connection->targ_to_init_iu_sz = get_srp_login_response_max_targ_to_init_iu( p_srp_login_rsp ); + + p_connection->signaled_send_completion_count = 32; + + if (( p_connection->descriptor_format & DBDF_INDIRECT_DATA_BUFFER_DESCRIPTORS ) == DBDF_INDIRECT_DATA_BUFFER_DESCRIPTORS ) + { + p_connection->max_scatter_gather_entries = + ( MIN( SRP_MAX_IU_SIZE, p_connection->init_to_targ_iu_sz ) - offsetof( srp_cmd_t, additional_cdb )- sizeof(srp_memory_table_descriptor_t)) / sizeof( srp_memory_descriptor_t ); + } + else if (( p_connection->descriptor_format & DBDF_DIRECT_DATA_BUFFER_DESCRIPTOR ) == DBDF_DIRECT_DATA_BUFFER_DESCRIPTOR ) + { + p_connection->max_scatter_gather_entries = + ((p_connection->init_to_targ_iu_sz - offsetof( srp_cmd_t, additional_cdb )) / sizeof( srp_memory_descriptor_t )) ? 1 : 0; + } + else /* not reported any descriptor format */ + { + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_DEBUG, + ("Target does not support valid descriptor formats\n") ); + goto rej; + } + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_DEBUG, + ("Request Limit = %d, SendQ Depth = %d, RecvQDepth = %d, " + "ItoT size = %d, TtoI size = %d, Max S/G = %d\n", + p_connection->request_limit, + p_connection->send_queue_depth, + p_connection->recv_queue_depth, + p_connection->init_to_targ_iu_sz, + p_connection->targ_to_init_iu_sz, + p_connection->max_scatter_gather_entries) ); + + /* will be used in srp_find_adapter to calculate NumberOfPhysicalBreaks */ + p_srp_session->p_hba->max_sg = p_connection->max_scatter_gather_entries; + + u.cm_mra.svc_timeout = 0x08; + u.cm_mra.p_mra_pdata = NULL; + u.cm_mra.mra_length = 0; + + status = p_ifc->cm_mra( p_cm_reply->h_cm_rep, &u.cm_mra ); + if ( status != IB_SUCCESS ) + { + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("Cannot Send MRA. Status = %d\n", status) ); + goto rej; + } + + status = p_ifc->modify_cq( p_connection->h_send_cq, &p_connection->send_queue_depth ); + if ( status != IB_SUCCESS ) + { + SRP_PRINT( TRACE_LEVEL_WARNING, SRP_DBG_PNP, + ("Cannot Modify Send Completion Queue Depth. Status = %d\n", status) ); + } + + status = p_ifc->modify_cq( p_connection->h_recv_cq, &p_connection->recv_queue_depth ); + if ( status != IB_SUCCESS ) + { + SRP_PRINT( TRACE_LEVEL_WARNING, SRP_DBG_PNP, + ("Cannot Modify Recv Completion Queue Depth. Status = %d\n", status) ); + } + + cl_status = __srp_create_wc_free_list( p_connection, (p_connection->request_limit * 2) );/* Send/Recv */ + if ( cl_status != CL_SUCCESS ) + { + goto rej; + } + + status = srp_init_descriptors( &p_srp_session->descriptors, + p_connection->request_limit, + p_connection->targ_to_init_iu_sz, + &p_srp_session->p_hba->ifc, + p_srp_session->hca.h_pd, + p_connection->h_qp, + p_srp_session->hca.lkey ); + if ( status != IB_SUCCESS ) + { + goto err_init_desc; + } + + u.cm_rtu.access_ctrl = IB_AC_LOCAL_WRITE | IB_AC_RDMA_READ | IB_AC_RDMA_WRITE; + + /* Have to set to 0 to indicate not to modify because Tavor doesn't support this */ + u.cm_rtu.sq_depth = 0 /*p_connection->request_limit*/; + u.cm_rtu.rq_depth = 0 /*p_connection->request_limit*/; + + u.cm_rtu.p_rtu_pdata = NULL; + u.cm_rtu.rtu_length = 0; + u.cm_rtu.pfn_cm_apr_cb = __srp_cm_apr_cb; + u.cm_rtu.pfn_cm_dreq_cb = __srp_cm_dreq_cb; + + status = p_ifc->cm_rtu( p_cm_reply->h_cm_rep, &u.cm_rtu ); + if ( status != IB_SUCCESS ) + { + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("Cannot Send RTU. Status = %d\n", status) ); + goto err_send_rtu; + } + + p_connection->state = SRP_CONNECTED; + + status = p_ifc->rearm_cq( p_connection->h_send_cq, FALSE ); + if ( status != IB_SUCCESS) + { + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("ib_rearm_cq() for send cq failed!, status 0x%x", status) ); + + // TODO: Kill session and inform port driver link down storportnotification + goto err_send_rtu; + } + + status = p_ifc->rearm_cq( p_connection->h_recv_cq, FALSE ); + if ( status != IB_SUCCESS) + { + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("ib_rearm_cq() for recv failed!, status 0x%x", status) ); + + // TODO: Kill session and inform port driver link down storportnotification + goto err_send_rtu; + } + goto exit; + +err_send_rtu: + // the rest will be cleaned up in srp_session_login + +err_init_desc: + cl_free( p_connection->p_wc_array ); + p_connection->p_wc_array = NULL; + p_connection->p_wc_free_list = NULL; + +rej: + p_connection->state = SRP_CONNECT_FAILURE; + cl_memclr( &u.cm_rej, sizeof(u.cm_rej) ); + u.cm_rej.rej_status = IB_REJ_INSUF_RESOURCES; + p_ifc->cm_rej( p_cm_reply->h_cm_rep, &u.cm_rej ); + +exit: + cl_status = cl_event_signal( &p_connection->conn_req_event ); + + SRP_EXIT( SRP_DBG_PNP ); +} + + +/* __srp_cm_rej_cb */ +/*! +Callback for connect reject from the target +The target has rejected our connect/login request + +@param p_cm_reject - pointer to the connect reject structure + +@return - none +*/ +static +void +__srp_cm_rej_cb( + IN ib_cm_rej_rec_t *p_cm_reject) +{ + srp_session_t *p_srp_session = (srp_session_t*)p_cm_reject->qp_context; + srp_connection_t *p_connection; + srp_login_rej_t *p_srp_login_rej = (srp_login_rej_t*)p_cm_reject->p_rej_pdata; + cl_status_t cl_status; + + SRP_ENTER( SRP_DBG_PNP ); + + p_connection = &p_srp_session->connection; + + if( p_srp_login_rej ) + { + set_srp_login_reject_from_network_to_host( p_srp_login_rej ); // <-- Is this coming back NULL? + p_connection->reject_reason = get_srp_login_reject_reason( p_srp_login_rej ); + + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("Login Rejected. IBT Code = 0x%x, SRP Code = 0x%x\n", + p_cm_reject->rej_status, p_connection->reject_reason ) ); + switch( p_connection->reject_reason ) + { + case LIREJ_INIT_TO_TARG_IU_LENGTH_TOO_LARGE: + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("REQUESTED IU_SIZE %d\n", + p_connection->req_max_iu_msg_size )); + break; + case LIREJ_UNSUPPORTED_DATA_BUFFER_DESCRIPTOR_FORMAT: + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("REQUESTED DESC FORMAT: %#x, SUPPORTED FORMAT %#x\n", + p_connection->descriptor_format, + get_srp_login_reject_supported_data_buffer_formats(p_srp_login_rej) )); + __srp_issue_session_login( p_connection, (srp_hca_t *)&p_srp_session->hca, p_connection->ioc_max_send_msg_depth ); + return; + default: + break; + } + } + else + { + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("Login Rejected. IBT Code = 0x%x\n", + p_cm_reject->rej_status) ); +} + p_connection->state = SRP_CONNECT_FAILURE; + + cl_status = cl_event_signal( &p_connection->conn_req_event ); + + SRP_EXIT( SRP_DBG_PNP ); +} + +/* __srp_issue_session_login */ +/*! +Initializes and issues a login/cm connect request to the target + +@param p_connection - pointer to the connection structure +@param p_hca - pointer to the hca structure used by this connection +@param send_msg_depth - initial request limit delta value + +@return - result of login/cm connect request operations +*/ +#pragma warning( disable : 4748) +#pragma optimize( "", off ) +static +ib_api_status_t +__srp_issue_session_login( + IN OUT srp_connection_t *p_connection, + IN srp_hca_t *p_hca, + IN uint8_t send_msg_depth ) +{ + ib_api_status_t status; + ib_cm_req_t cm_req; + srp_login_req_t login_req; + + SRP_ENTER( SRP_DBG_PNP ); + + cl_memclr( &cm_req, sizeof(ib_cm_req_t) ); + + cm_req.svc_id = p_connection->service_id; + + cm_req.flags = 0; // event used instead of IB_FLAGS_SYNC + cm_req.max_cm_retries = 8; + cm_req.p_primary_path = p_connection->p_path_rec; + + /*already tried to login before and failed ? */ + if ( !p_connection->reject_reason ) + { + p_connection->descriptor_format = DBDF_DIRECT_DATA_BUFFER_DESCRIPTOR | DBDF_INDIRECT_DATA_BUFFER_DESCRIPTORS; + } + else if ( p_connection->reject_reason == LIREJ_UNSUPPORTED_DATA_BUFFER_DESCRIPTOR_FORMAT ) + { + p_connection->descriptor_format = DBDF_DIRECT_DATA_BUFFER_DESCRIPTOR; + } + else + { + p_connection->state = SRP_CONNECT_FAILURE; + status = IB_ERROR; + goto exit; + } + p_connection->req_max_iu_msg_size = ( p_connection->ioc_max_send_msg_size >= SRP_MAX_IU_SIZE ) ? SRP_MAX_IU_SIZE: p_connection->ioc_max_send_msg_size; + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_ERROR, + ( "(init_to_targ_iu_sz requested) req_max_iu_msg_size %d, (from profile) ioc_max_send_msg_size %d\n", + p_connection->req_max_iu_msg_size, p_connection->ioc_max_send_msg_size )); + /* + Build SRP Login request + */ + setup_srp_login_request( &login_req, + 0, /* tag */ + p_connection->req_max_iu_msg_size, + p_connection->descriptor_format, + MCA_TERMINATE_EXISTING, + &p_connection->init_port_id, + &p_connection->targ_port_id ); + set_srp_login_request_from_host_to_network(&login_req); + + cm_req.p_req_pdata = (const uint8_t *)&login_req; + cm_req.req_length = (uint8_t)get_srp_login_request_length( &login_req ); + + cm_req.qp_type = IB_QPT_RELIABLE_CONN; + cm_req.h_qp = p_connection->h_qp; + + /* The maximum number of outstanding RDMA read/atomic operations. */ + status = srp_get_responder_resources( p_hca, &cm_req.resp_res ); + if ( status != IB_SUCCESS ) + { + goto exit; + } + + cm_req.init_depth = send_msg_depth; + + cm_req.remote_resp_timeout = ib_path_rec_pkt_life( p_connection->p_path_rec ) + 1; + cm_req.flow_ctrl = FALSE; + cm_req.local_resp_timeout = ib_path_rec_pkt_life( p_connection->p_path_rec ) + 1; + cm_req.retry_cnt = 1; + cm_req.rnr_nak_timeout = 0; /* 655.36 ms */ + cm_req.rnr_retry_cnt = 6; + + cm_req.pfn_cm_rep_cb = __srp_cm_reply_cb; + cm_req.pfn_cm_req_cb = NULL; /* Set only for P2P */ + cm_req.pfn_cm_mra_cb = __srp_cm_mra_cb; + cm_req.pfn_cm_rej_cb = __srp_cm_rej_cb; + + cm_req.pkey = p_connection->p_path_rec->pkey; + + status = p_hca->p_hba->ifc.cm_req( &cm_req ); + if ( status == IB_SUCCESS ) + { + p_connection->state = SRP_CONNECT_REQUESTED; + } + else + { + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("Cannot Send Connect Request. Status = %d\n", status) ); + p_connection->state = SRP_CONNECT_FAILURE; + } + +exit: + SRP_EXIT( SRP_DBG_PNP ); + + return ( status ); +} +#pragma optimize( "", on ) +#pragma warning( default : 4748) + +/* srp_init_connection */ +/*! +Initializes a connection structure + +@param p_connection - pointer to the connection structure +@param p_profile - Pointer to IOC profile. +@param ca_guid - Local CA GUID to use in as initiator GUID. +@param ext_id - Initiator and target extension ID. +@param p_path_rec - pointer to the path to the target +@param service_id - service id to which we want to connect + +@return - always success (for now) +*/ +ib_api_status_t +srp_init_connection( + IN OUT srp_connection_t *p_connection, + IN ib_ioc_profile_t* const p_profile, + IN net64_t ca_guid, + IN net64_t ext_id, + IN ib_path_rec_t *p_path_rec, + IN ib_net64_t service_id ) +{ + SRP_ENTER( SRP_DBG_PNP ); + + cl_memclr( p_connection, sizeof(*p_connection) );\ + + p_connection->initialized = TRUE; + + p_connection->state = SRP_NOT_CONNECTED; + + p_connection->p_path_rec = p_path_rec; + switch( p_profile->io_class ) + { + case SRP_IO_CLASS_R10: + p_connection->init_port_id.field1 = ca_guid; + p_connection->init_port_id.field2 = ext_id; + p_connection->targ_port_id.field1 = p_profile->ioc_guid; + p_connection->targ_port_id.field2 = ext_id; + break; + + case SRP_IO_CLASS: + p_connection->init_port_id.field1 = ext_id; + p_connection->init_port_id.field2 = ca_guid; + p_connection->targ_port_id.field1 = ext_id; + p_connection->targ_port_id.field2 = p_profile->ioc_guid; + break; + + default: + return IB_INVALID_PARAMETER; + } + p_connection->service_id = service_id; + p_connection->send_queue_depth = SRP_DEFAULT_SEND_Q_DEPTH; + p_connection->recv_queue_depth = SRP_DEFAULT_RECV_Q_DEPTH; + + SRP_EXIT( SRP_DBG_PNP ); + + return ( IB_SUCCESS ); +} + +/* srp_connect */ +/*! +Orchestrates the processing required to connect to a target device + +@param p_connection - pointer to the connection structure +@param p_hca - pointer to the hca structure used by this connection +@param send_msg_depth - initial request limit delta value +@param p_session - context passed to callback functions + +@return - result of connect operations +*/ +ib_api_status_t +srp_connect( + IN OUT srp_connection_t *p_connection, + IN srp_hca_t *p_hca, + IN uint8_t send_msg_depth, + IN p_srp_session_t p_session ) +{ + ib_api_status_t status; + cl_status_t cl_status; + + SRP_ENTER( SRP_DBG_PNP ); + + p_connection->ioc_max_send_msg_size = + cl_ntoh32 (p_session->p_hba->ioc_info.profile.send_msg_size); + p_connection->ioc_max_send_msg_depth = send_msg_depth; + p_connection->reject_reason = 0; + + status = __srp_create_cqs( p_connection, p_hca, p_session ); + if ( status != IB_SUCCESS ) + { + goto exit; + } + + status = __srp_create_qp( p_connection, p_hca, p_session ); + if ( status != IB_SUCCESS ) + { + goto exit; + } + + cl_status = cl_event_init( &p_connection->conn_req_event, TRUE ); + if ( cl_status != CL_SUCCESS ) + { + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("Cannot Initialize Connect Request Event. Status = %d\n", cl_status) ); + status = cl_status; + goto exit; + } + + status = __srp_issue_session_login( p_connection, p_hca, send_msg_depth ); + if ( status != IB_SUCCESS ) + { + cl_event_destroy( &p_connection->conn_req_event ); + goto exit; + } + + cl_status = cl_event_wait_on( &p_connection->conn_req_event, EVENT_NO_TIMEOUT, FALSE ); + if ( cl_status != CL_SUCCESS ) + { + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("Wait On Connect Request Event Failed. Status = %d\n", cl_status) ); + status = cl_status; + cl_event_destroy( &p_connection->conn_req_event ); + goto exit; + } + + cl_event_destroy( &p_connection->conn_req_event ); + + if ( p_connection->state != SRP_CONNECTED ) + { + status = IB_ERROR; + goto exit; + } + + cl_thread_init( &p_session->recovery_thread, + (cl_pfn_thread_callback_t)srp_session_recovery_thread, + (void *)p_session, "srp_thread" ); +#if DBG + gp_session[p_session->target_id] = p_session; +#endif + +exit: + SRP_EXIT( SRP_DBG_PNP ); + + return ( status ); +} + +/* srp_free_connection */ +/*! +Frees connection resources + +@param p_connection - pointer to the connection structure + +@return - none +*/ +void +srp_free_connection( + IN srp_connection_t *p_srp_connection ) +{ + SRP_ENTER( SRP_DBG_PNP ); + + if ( p_srp_connection->initialized == TRUE ) + { + if ( p_srp_connection->p_wc_array != NULL ) + { + cl_free( p_srp_connection->p_wc_array ); + } + + cl_event_destroy( &p_srp_connection->conn_req_event ); + + cl_memclr( p_srp_connection, sizeof( *p_srp_connection ) ); + } + + SRP_EXIT( SRP_DBG_PNP ); +} + + + + + diff --git a/branches/WOF2-3/ulp/srp/kernel/srp_connection.h b/branches/WOF2-3/ulp/srp/kernel/srp_connection.h new file mode 100644 index 00000000..982a7b81 --- /dev/null +++ b/branches/WOF2-3/ulp/srp/kernel/srp_connection.h @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#ifndef _SRP_CONNECTION_H_ +#define _SRP_CONNECTION_H_ + + +#include +#include +#include + +#include "srp.h" +#include "srp_connection.h" +#include "srp_hca.h" + +/* Default Max Inflight IO Depth Commands */ +#define SRP_DEFAULT_SEND_Q_DEPTH 1000 +/* Default Max Inflight IO Depth Responses */ +#define SRP_DEFAULT_RECV_Q_DEPTH 1000 + +typedef enum +{ + SRP_NOT_CONNECTED, + SRP_CONNECT_REQUESTED, + SRP_CONNECTED, + SRP_CONNECT_FAILURE, + SRP_CONNECTION_CLOSING, + SRP_TARGET_DISCONNECTING +} srp_connection_state_t; + +typedef struct _srp_session *p_srp_session_t; + +/* Connection information. */ +typedef struct _srp_connection +{ + BOOLEAN initialized; + + srp_connection_state_t state; + + ib_cq_handle_t h_send_cq; + ib_cq_handle_t h_recv_cq; + ib_qp_handle_t h_qp; + + ib_path_rec_t *p_path_rec; + srp_ib_port_id_t init_port_id; + srp_ib_port_id_t targ_port_id; + ib_net64_t service_id; + + uint32_t send_queue_depth; + uint32_t recv_queue_depth; + + atomic32_t tag; + atomic32_t request_limit; + atomic32_t max_limit; + int32_t request_threashold; + uint32_t init_to_targ_iu_sz; + uint32_t targ_to_init_iu_sz; + + ib_wc_t *p_wc_array; + ib_wc_t *p_wc_free_list; + + uint32_t signaled_send_completion_count; + uint32_t max_scatter_gather_entries; + uint32_t ioc_max_send_msg_size; + uint32_t req_max_iu_msg_size; + cl_event_t conn_req_event; + DATA_BUFFER_DESCRIPTOR_FORMAT descriptor_format; + LOGIN_REJECT_CODE reject_reason; + uint8_t ioc_max_send_msg_depth; +} srp_connection_t; + +ib_api_status_t +srp_init_connection( + IN OUT srp_connection_t *p_connection, + IN ib_ioc_profile_t* const p_profile, + IN net64_t ca_guid, + IN net64_t ext_id, + IN ib_path_rec_t *p_path_rec, + IN ib_net64_t service_id ); + +ib_api_status_t +srp_connect( + IN OUT srp_connection_t *p_connection, + IN srp_hca_t *p_hca, + IN uint8_t send_msg_depth, + IN p_srp_session_t p_session ); + +void +srp_free_connection( + IN srp_connection_t *p_srp_connection ); +static +ib_api_status_t +__srp_issue_session_login( + IN OUT srp_connection_t *p_connection, + IN srp_hca_t *p_hca, + IN uint8_t send_msg_depth ); + +#endif /* _SRP_CONNECTION_H_ */ diff --git a/branches/WOF2-3/ulp/srp/kernel/srp_cred_req.h b/branches/WOF2-3/ulp/srp/kernel/srp_cred_req.h new file mode 100644 index 00000000..6f47638a --- /dev/null +++ b/branches/WOF2-3/ulp/srp/kernel/srp_cred_req.h @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#ifndef SRP_CRED_REQ_H_INCLUDED +#define SRP_CRED_REQ_H_INCLUDED + +#include "srp.h" +#include "srp_iu_buffer.h" +#include "srp_information_unit.h" + +/* set_srp_credit_request_tag */ +/*! +Sets the tag field of a credit request information unit + +@param p_information_unit - pointer to the IU structure +@param iu_tag - tag value of IU + +@return - none +*/ +static inline +void +set_srp_credit_request_tag( + IN OUT srp_cred_req_t *p_information_unit, + IN uint64_t iu_tag ) +{ + set_srp_information_unit_tag( ( srp_information_unit_t* ) p_information_unit, iu_tag ); +} + +/* init_srp_credit_request */ +/*! +Initializes the credit request IU to zeroes +and sets the IU type to Srp credit request +and sets the tag to the value supplied + +@param p_information_unit - pointer to the IU structure +@param iu_tag - tag value to be used for the req/rsp pair + +@return - none +*/ +static inline +void +init_srp_credit_request( + IN OUT srp_cred_req_t *p_information_unit, + IN uint64_t iu_tag ) +{ + init_srp_iu_buffer( ( srp_iu_buffer_t* ) p_information_unit, SRP_CRED_REQ ) ; + set_srp_credit_request_tag( p_information_unit, iu_tag ); +} + +/* set_srp_credit_request_request_limit_delta */ +/*! +Sets the request limit delta for the credit request + +@param p_information_unit - pointer to the IU structure +@param request_limit_delta - flow control request limit delta + +@return - none +*/ +static inline +void +set_srp_credit_request_request_limit_delta( + IN OUT srp_cred_req_t *p_information_unit, + IN int32_t request_limit_delta ) +{ + p_information_unit->request_limit_delta = request_limit_delta; +} + +/* setup_srp_credit_request */ +/*! +Initializes and sets the Srp credit request IU to the values supplied + +@param p_information_unit - pointer to the IU structure +@param iu_tag - tag value to be used for the req/rsp pair +@param request_limit_delta - flow control request limit delta + +@return - none +*/ +static inline +void +setup_srp_credit_request( + IN OUT srp_cred_req_t *p_information_unit, + IN uint64_t iu_tag, + IN int32_t request_limit_delta ) +{ + init_srp_credit_request( p_information_unit, iu_tag ); + set_srp_credit_request_request_limit_delta( p_information_unit, request_limit_delta ); +} + +/* get_srp_credit_request_tag */ +/*! +Returns the value of the tag field of a credit request + +@param p_information_unit - pointer to the IU structure + +@return - tag value +*/ +static inline +uint64_t +get_srp_credit_request_tag( + IN srp_cred_req_t *p_information_unit ) +{ + return( get_srp_information_unit_tag( ( srp_information_unit_t* ) p_information_unit ) ); +} + +/* get_srp_credit_request_request_limit_delta */ +/*! +Returns the value of the request limit delta field of a credit request + +@param p_information_unit - pointer to the IU structure + +@return - request limit delta value +*/ +static inline +int32_t +get_srp_credit_request_request_limit_delta( + IN srp_cred_req_t *p_information_unit ) +{ + return( p_information_unit->request_limit_delta ); +} + +/* get_srp_credit_request_length */ +/*! +Returns the size in bytes of the Srp credit request IU + +@param p_information_unit - pointer to the IU structure + +@return - tag value +*/ +static inline +uint32_t +get_srp_credit_request_length( + IN srp_cred_req_t *p_information_unit ) +{ + return( sizeof( *p_information_unit ) ); +} + +/* set_srp_credit_request_from_host_to_network */ +/*! +Swaps the IU fields from Host to Network ordering + +@param p_information_unit - pointer to the IU structure + +@return - none +*/ + +static inline +void +set_srp_credit_request_from_host_to_network( + IN OUT srp_cred_req_t *p_information_unit ) +{ + set_srp_information_unit_from_host_to_network( ( srp_information_unit_t* ) p_information_unit ); + p_information_unit->request_limit_delta = cl_hton32( p_information_unit->request_limit_delta ); +} + +/* set_srp_credit_request_from_network_to_host */ +/*! +Swaps the IU fields from Network to Host ordering + +@param p_information_unit - pointer to the IU structure + +@return - none +*/ + +static inline +void +set_srp_credit_request_from_network_to_host( + IN OUT srp_cred_req_t *p_information_unit ) +{ + set_srp_credit_request_from_host_to_network ( p_information_unit ); +} + +#endif /* SRP_CRED_REQ_H_INCLUDED */ diff --git a/branches/WOF2-3/ulp/srp/kernel/srp_cred_rsp.h b/branches/WOF2-3/ulp/srp/kernel/srp_cred_rsp.h new file mode 100644 index 00000000..70b3ca9f --- /dev/null +++ b/branches/WOF2-3/ulp/srp/kernel/srp_cred_rsp.h @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#ifndef SRP_CRED_RSP_H_INCLUDED +#define SRP_CRED_RSP_H_INCLUDED + +#include "srp.h" +#include "srp_iu_buffer.h" +#include "srp_information_unit.h" + +/* set_srp_credit_response_tag */ +/*! +Sets the tag field of a credit response information unit + +@param p_information_unit - pointer to the IU structure +@param iu_tag - tag value of IU + +@return - none +*/ +static inline +void +set_srp_credit_response_tag( + IN OUT srp_cred_rsp_t *p_information_unit, + IN uint64_t iu_tag ) +{ + set_srp_information_unit_tag( ( srp_information_unit_t* ) p_information_unit, iu_tag ); +} + +/* init_srp_credit_response */ +/*! +Initializes the credit response IU to zeroes +and sets the IU type to Srp credit Response +and sets the tag to the value supplied + +@param p_information_unit - pointer to the IU structure +@param iu_tag - tag value to be used for the req/rsp pair + +@return - none +*/ +static inline +void +init_srp_credit_response( + IN OUT srp_cred_rsp_t *p_information_unit, + IN uint64_t iu_tag ) +{ + init_srp_iu_buffer( ( srp_iu_buffer_t* ) p_information_unit, SRP_CRED_RSP ) ; + set_srp_credit_response_tag( p_information_unit, iu_tag ); +} + +/* setup_srp_credit_response */ +/*! +Initializes and sets the Srp Credit Response IU to the values supplied + +@param p_information_unit - pointer to the IU structure +@param iu_tag - tag value to be used for the req/rsp pair + +@return - none +*/ +static inline +void +setup_srp_credit_response( + IN OUT srp_cred_rsp_t *p_information_unit, + IN uint64_t iu_tag ) +{ + init_srp_credit_response( p_information_unit, iu_tag ); +} + +/* get_srp_credit_response_tag */ +/*! +Returns the value of the tag field of a credit response + +@param p_information_unit - pointer to the IU structure + +@return - tag value +*/ +static inline +uint64_t +get_srp_credit_response_tag( + IN srp_cred_rsp_t *p_information_unit ) +{ + return( get_srp_information_unit_tag( ( srp_information_unit_t* ) p_information_unit ) ); +} + +/* get_srp_credit_response_length */ +/*! +Returns the size in bytes of the Srp Credit Response IU + +@param p_information_unit - pointer to the IU structure + +@return - tag value +*/ +static inline +uint32_t +get_srp_credit_response_length( + IN srp_cred_rsp_t *p_information_unit ) +{ + return( sizeof( *p_information_unit ) ); +} + +/* set_srp_credit_response_from_host_to_network */ +/*! +Swaps the IU fields from Host to Network ordering + +@param p_information_unit - pointer to the IU structure + +@return - none +*/ + +static inline +void +set_srp_credit_response_from_host_to_network( + IN OUT srp_cred_rsp_t *p_information_unit ) +{ + set_srp_information_unit_from_host_to_network( ( srp_information_unit_t* ) p_information_unit ); +} + +/* set_srp_credit_response_from_network_to_host */ +/*! +Swaps the IU fields from Network to Host ordering + +@param p_information_unit - pointer to the IU structure + +@return - none +*/ + +static inline +void +set_srp_credit_response_from_network_to_host( + IN OUT srp_cred_rsp_t *p_information_unit ) +{ + set_srp_credit_response_from_host_to_network ( p_information_unit ); +} + +#endif /* SRP_CRED_RSP_H_INCLUDED */ diff --git a/branches/WOF2-3/ulp/srp/kernel/srp_data.h b/branches/WOF2-3/ulp/srp/kernel/srp_data.h new file mode 100644 index 00000000..87c5d1bc --- /dev/null +++ b/branches/WOF2-3/ulp/srp/kernel/srp_data.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + +#ifndef _SRP_DATA_H_ +#define _SRP_DATA_H_ + + +//#define SRP_SCSI_MINIPORT + + +#include +#pragma warning( push, 3 ) +//#if WINVER == 0x500 || defined( SRP_SCSI_MINIPORT ) +//#include +//#include +//#else /* WINVER == 0x500 */ + +// WinXP typo workaround +#if defined (WinXP) +#define RaidPortReady StorPortReady +#endif + +#include +//#endif /* WINVER == 0x500 */ +#pragma warning( pop ) + +#define SRP_OBJ_TYPE_DRV 0x10000000 +#define SRP_OBJ_TYPE_HBA 0x10000001 +#define SRP_OBJ_TYPE_SESSION 0x10000002 + + +/* Device extension */ +typedef struct _srp_ext +{ + struct _srp_hba *p_hba; + +} srp_ext_t; +/* +* NOTES +* The device extension only contains a pointer to our dynamically +* allocated HBA structure. This is done since we don't have control +* over the destruction of the device extension, but we need to be able to +* control the creation and destruction of the HBA object. We hook the driver +* unload routine so that we can clean up any remaining objects. +*********/ + +extern BOOLEAN g_srp_system_shutdown; + + +#endif /* _SRP_DATA_H_ */ diff --git a/branches/WOF2-3/ulp/srp/kernel/srp_data_path.c b/branches/WOF2-3/ulp/srp/kernel/srp_data_path.c new file mode 100644 index 00000000..f879d7f2 --- /dev/null +++ b/branches/WOF2-3/ulp/srp/kernel/srp_data_path.c @@ -0,0 +1,1627 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corp. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include +#include + +#include "srp_cmd.h" +#include "srp_data_path.h" +#include "srp_debug.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "srp_data_path.tmh" +#endif +#include "srp_descriptors.h" +#include "srp_rsp.h" +#include "srp_session.h" +#include "srp_tsk_mgmt.h" + +//#include "srp_aer_req.h" +//#include "srp_aer_rsp.h" + +//#include "srp_cred_req.h" +//#include "srp_cred_rsp.h" + +//#include "srp_i_logout.h" +//#include "srp_t_logout.h" + +// Final address is of the form 0b00ttttttllllllll +#define BUILD_SCSI_ADDRESS(lun) ((uint64_t)lun << 48) + +#define SRP_REQUEST_LIMIT_THRESHOLD 2 + +static ib_api_status_t +__srp_map_fmr( + IN PVOID p_dev_ext, + IN PSTOR_SCATTER_GATHER_LIST p_scatter_gather_list, + IN srp_send_descriptor_t *p_send_descriptor, + IN OUT srp_memory_descriptor_t *p_memory_descriptor) +{ + srp_hba_t *p_hba = ((srp_ext_t *)p_dev_ext)->p_hba; + PSTOR_SCATTER_GATHER_ELEMENT p_sg_element; + uint32_t total_len = 0; + uint32_t i,j,list_len = 0; + uint64_t *p_addr_list; + uint64_t vaddr=0; + ib_api_status_t status; + srp_hca_t hca; + uint64_t fmr_page_mask; + net32_t lkey; + net32_t rkey; + srp_session_t *p_srp_session; + mlnx_fmr_pool_el_t p_fmr_el; + + SRP_ENTER( SRP_DBG_DATA ); + + if (g_srp_mode_flags & SRP_MODE_NO_FMR_POOL) + return IB_UNSUPPORTED; + + p_srp_session = p_hba->session_list[p_send_descriptor->p_srb->TargetId]; + if ( p_srp_session == NULL ) + return IB_INVALID_STATE; + + hca = p_srp_session->hca; + fmr_page_mask = ~(hca.fmr_page_size-1); + + for ( i = 0, p_sg_element = p_scatter_gather_list->List; + i < p_scatter_gather_list->NumberOfElements; + i++, p_sg_element++ ) + { + uint32_t dma_len = p_sg_element->Length; + + if (p_sg_element->PhysicalAddress.QuadPart & ~fmr_page_mask) { + if (i > 0) + { // buffer start not from the beginning of the page is allowed only for the first SG element + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("Unaligned address at the begin of the list\n") ); + return IB_INVALID_PARAMETER; + } + } + + if ((p_sg_element->PhysicalAddress.QuadPart + dma_len) & ~fmr_page_mask) { + if (i < (uint32_t)p_scatter_gather_list->NumberOfElements -1) + { // buffer end not on the beginning of the page is allowed only for the last SG element + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("Unaligned address at the end of the list\n") ); + return IB_INVALID_PARAMETER; + } + } + + total_len += p_sg_element->Length; + list_len += (p_sg_element->Length + (hca.fmr_page_size-1)) >> hca.fmr_page_shift; + } + + + p_addr_list = cl_zalloc(sizeof(uint64_t)*list_len); + if(!p_addr_list) + { + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR,("Failed to allocate page list\n")); + return IB_INSUFFICIENT_MEMORY; + } + + list_len = 0; + for ( i = 0, p_sg_element = p_scatter_gather_list->List; + i < p_scatter_gather_list->NumberOfElements; + i++, p_sg_element++ ) + { + uint32_t dma_len = p_sg_element->Length; + for( j = 0; j < dma_len; j+=PAGE_SIZE) + { + p_addr_list[list_len++] = (p_sg_element->PhysicalAddress.QuadPart & fmr_page_mask) + j; + } + } + + p_send_descriptor->p_fmr_el = NULL; + status = p_hba->ifc.map_phys_mlnx_fmr_pool + (hca.h_fmr_pool, p_addr_list, list_len, &vaddr, &lkey, &rkey, &p_fmr_el ); + + cl_free( p_addr_list ); + + if(status != IB_SUCCESS) + { + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR,("Failed to map fmr\n")); + return status; + } + + p_send_descriptor->p_fmr_el = p_fmr_el; + p_sg_element = p_scatter_gather_list->List; + + p_memory_descriptor->virtual_address = cl_hton64( p_sg_element->PhysicalAddress.QuadPart & ~fmr_page_mask); + p_memory_descriptor->memory_handle = rkey; + p_memory_descriptor->data_length = cl_hton32( total_len); + +#if DBG + /* statistics */ + p_srp_session->x_pkt_fmr++; +#endif + + SRP_EXIT( SRP_DBG_DATA ); + return IB_SUCCESS; +} + + + +static inline +void +__srp_dump_srb_info(srp_send_descriptor_t* p_send_descriptor) +{ + + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_DATA, + ("Srb Address = %p\n", + p_send_descriptor->p_srb) ); + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_DATA, + ("Srb DataBuffer Address = %p\n", + p_send_descriptor->p_srb->DataBuffer) ); + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_DATA, + ("Srb DataTransferLength = %d\n", + p_send_descriptor->p_srb->DataTransferLength) ); + + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_DATA, + ("Returning SrbStatus %s(0x%x) for " + "Function = %s(0x%x), Path = 0x%x, Target = 0x%x, " + "Lun = 0x%x, tag 0x%I64xn", + g_srb_status_name[p_send_descriptor->p_srb->SrbStatus], + p_send_descriptor->p_srb->SrbStatus, + g_srb_function_name[p_send_descriptor->p_srb->Function], + p_send_descriptor->p_srb->Function, + p_send_descriptor->p_srb->PathId, + p_send_descriptor->p_srb->TargetId, + p_send_descriptor->p_srb->Lun, + get_srp_command_tag( (srp_cmd_t *)p_send_descriptor->data_segment )) ); +} + + +static inline +void +__srp_process_session_send_completions( + IN srp_session_t *p_srp_session ) +{ + ib_api_status_t status; + ib_wc_t *p_wc_done_list = NULL; + ib_wc_t *p_wc; + BOOLEAN to_recover = FALSE; + + SRP_ENTER( SRP_DBG_DATA ); + + cl_obj_lock( &p_srp_session->obj ); + + if ( p_srp_session->connection.state != SRP_CONNECTED ) + { + cl_obj_unlock( &p_srp_session->obj ); + SRP_EXIT( SRP_DBG_DATA ); + return; + } + + status = p_srp_session->p_hba->ifc.poll_cq( + p_srp_session->connection.h_send_cq, + &p_srp_session->connection.p_wc_free_list, + &p_wc_done_list ); + if ( status != IB_SUCCESS ) + { + SRP_PRINT_EXIT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("ib_poll_cq() failed!, status 0x%x\n", status) ); + + p_srp_session->connection.state = SRP_CONNECT_FAILURE; + cl_obj_unlock( &p_srp_session->obj ); + return; + } + + cl_obj_ref( &p_srp_session->obj ); + cl_obj_unlock( &p_srp_session->obj ); + + while ( (p_wc = p_wc_done_list) != NULL ) + { + srp_send_descriptor_t *p_send_descriptor; + + p_send_descriptor = (srp_send_descriptor_t *)((uintn_t)p_wc->wr_id); + + /* Remove head from list */ + p_wc_done_list = p_wc->p_next; + p_wc->p_next = NULL; + + switch ( p_wc->status) + { + case IB_WCS_SUCCESS: + break; + case IB_WCS_WR_FLUSHED_ERR: + if( !to_recover ) + to_recover = TRUE; + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_DATA, + ("Send Completion Status %s Vendore Status = 0x%x, \n", + p_srp_session->p_hba->ifc.get_wc_status_str( p_wc->status ), + (int)p_wc->vendor_specific)); + + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_DATA, + ("Send Completion Received for Function = %s(0x%x), " + "Path = 0x%x, Target = 0x%x, Lun = 0x%x, tag 0x%I64xn", + g_srb_function_name[p_send_descriptor->p_srb->Function], + p_send_descriptor->p_srb->Function, + p_send_descriptor->p_srb->PathId, + p_send_descriptor->p_srb->TargetId, + p_send_descriptor->p_srb->Lun, + get_srp_command_tag( (srp_cmd_t *)p_send_descriptor->data_segment )) ); + break; + default: + to_recover = TRUE; + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("Send Completion Status %s Vendore Status = 0x%x, \n", + p_srp_session->p_hba->ifc.get_wc_status_str( p_wc->status ), + (int)p_wc->vendor_specific)); + + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("Send Completion Received for Function = %s(0x%x), " + "Path = 0x%x, Target = 0x%x, Lun = 0x%x, tag 0x%I64xn", + g_srb_function_name[p_send_descriptor->p_srb->Function], + p_send_descriptor->p_srb->Function, + p_send_descriptor->p_srb->PathId, + p_send_descriptor->p_srb->TargetId, + p_send_descriptor->p_srb->Lun, + get_srp_command_tag( (srp_cmd_t *)p_send_descriptor->data_segment )) ); + break; + } + + /* Put onto head of free list */ + cl_obj_lock( &p_srp_session->obj ); + p_wc->p_next = p_srp_session->connection.p_wc_free_list; + p_srp_session->connection.p_wc_free_list = p_wc; + cl_obj_unlock( &p_srp_session->obj ); + + /* Get next completion */ + p_wc = p_wc_done_list; + } + + if( !to_recover ) + { + /* Re-arm the CQ for more completions */ + status = p_srp_session->p_hba->ifc.rearm_cq( + p_srp_session->connection.h_send_cq, FALSE ); + if ( status != IB_SUCCESS) + { + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("ib_rearm_cq() failed!, status 0x%x\n", status) ); + p_srp_session->connection.state = SRP_CONNECT_FAILURE; + to_recover = TRUE; + } + } + if( to_recover == TRUE ) + { + p_srp_session->connection.state = SRP_CONNECT_FAILURE; + } + + cl_obj_deref( &p_srp_session->obj ); + + SRP_EXIT( SRP_DBG_DATA ); +} + +/* srp_send_completion_cb */ +/*! +Set Timer to Process Send Completions - Usually bad if we get here + +@param p_context - context pointer to the owning session + +@return - none +*/ +void +srp_send_completion_cb( + IN const ib_cq_handle_t h_cq, + IN void *p_context ) +{ + srp_session_t *p_srp_session = (srp_session_t *)p_context; + + SRP_ENTER( SRP_DBG_DATA ); + + UNUSED_PARAM( h_cq ); + + __srp_process_session_send_completions( p_srp_session ); + + if( p_srp_session->connection.state == SRP_CONNECT_FAILURE ) + { + if( !p_srp_session->p_hba->adapter_stopped ) + { + srp_session_failed( p_srp_session ); + } + } + + SRP_EXIT( SRP_DBG_DATA ); +} + + +static inline ib_api_status_t +__srp_clean_send_descriptor( + IN srp_send_descriptor_t *p_send_descriptor, + IN srp_session_t *p_srp_session ) +{ + ib_api_status_t status = IB_SUCCESS; + + if(p_srp_session && p_send_descriptor && p_send_descriptor->p_fmr_el) + { + status = p_srp_session->p_hba->ifc.unmap_mlnx_fmr_pool(p_send_descriptor->p_fmr_el); + p_send_descriptor->p_fmr_el = NULL; + } + return status; +} + +ib_api_status_t +__srp_post_io_request( + IN PVOID p_dev_ext, + IN OUT PSCSI_REQUEST_BLOCK p_srb, + srp_session_t *p_srp_session ) +{ + ib_api_status_t status; + srp_send_descriptor_t *p_send_descriptor = (srp_send_descriptor_t *)p_srb->SrbExtension; + + SRP_ENTER( SRP_DBG_DATA ); + + status = srp_post_send_descriptor( &p_srp_session->descriptors, + p_send_descriptor, + p_srp_session ); + + if ( status == IB_SUCCESS ) + { + cl_atomic_dec( &p_srp_session->connection.request_limit ); +#if DBG + { /* statistics */ + uint32_t size = (uint32_t)cl_qlist_count(&p_srp_session->descriptors.sent_descriptors); + p_srp_session->x_sent_num++; + p_srp_session->x_sent_total += size; + if ( p_srp_session->x_sent_max < size ) + p_srp_session->x_sent_max = size; + } +#endif + goto exit; + } + else + { + p_srb->SrbStatus = SRB_STATUS_NO_HBA; + + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("Returning SrbStatus %s(0x%x) for Function = %s(0x%x), Path = 0x%x, " + "Target = 0x%x, Lun = 0x%x, tag 0x%I64x\n", + g_srb_status_name[p_srb->SrbStatus], + p_srb->SrbStatus, + g_srb_function_name[p_srb->Function], + p_srb->Function, + p_srb->PathId, + p_srb->TargetId, + p_srb->Lun, + get_srp_command_tag( (srp_cmd_t *)p_send_descriptor->data_segment )) ); + + status = __srp_clean_send_descriptor( p_send_descriptor, p_srp_session ); + if ( status != IB_SUCCESS ) + { + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("Failed to unmap FMR Status = %d.\n", status) ); + // TODO: Kill session and inform port driver link down storportnotification + } + + StorPortNotification( RequestComplete, p_dev_ext, p_srb ); + } + +exit: + SRP_EXIT( SRP_DBG_DATA ); + return status; +} + +static +ib_api_status_t +__srp_repost_io_request( + IN srp_session_t *p_srp_session ) +{ + srp_hba_t *p_hba; + srp_send_descriptor_t *p_send_descriptor = NULL; + srp_descriptors_t *p_descriptors = &p_srp_session->descriptors; + ib_api_status_t ib_status = IB_SUCCESS; + + SRP_ENTER( SRP_DBG_DATA ); + + if ( !cl_qlist_count(&p_descriptors->pending_descriptors) || + (p_srp_session->connection.request_limit <= p_srp_session->connection.request_threashold) ) + goto exit; + +#if DBG + { /* statistics */ + uint32_t size = (uint32_t)cl_qlist_count(&p_descriptors->pending_descriptors); + p_srp_session->x_pend_num++; + p_srp_session->x_pend_total += size; + if ( p_srp_session->x_pend_max < size ) + p_srp_session->x_pend_max = size; + } +#endif + + /* in case when the follows loop will release the last pending request for sending it, + there will be race between it and StorPort, that can call srp_post_io_request + just at that moment. In the "worst" case it will cause changing order between 2 posting. + The flag 'repost_is_on' is intended for preventing ths case */ + cl_atomic_inc( &p_srp_session->repost_is_on ); + + while (p_srp_session->connection.request_limit > p_srp_session->connection.request_threashold) + { + cl_list_item_t *p_list_item; + + /* extract a pending descriptor, if any */ + cl_spinlock_acquire ( &p_descriptors->pending_list_lock ); + p_list_item = cl_qlist_remove_head( &p_descriptors->pending_descriptors ); + if ( p_list_item == cl_qlist_end( &p_descriptors->pending_descriptors ) ) + { + cl_spinlock_release ( &p_descriptors->pending_list_lock ); + break; + } + cl_spinlock_release ( &p_descriptors->pending_list_lock ); + + /* post the request */ + p_hba = p_srp_session->p_hba; + p_send_descriptor = PARENT_STRUCT(p_list_item, srp_send_descriptor_t,list_item); + ib_status = __srp_post_io_request( p_hba->p_ext, p_send_descriptor->p_srb, p_srp_session ); + } + + cl_atomic_dec( &p_srp_session->repost_is_on ); + +exit: + SRP_EXIT( SRP_DBG_DATA ); + return ib_status; +} + +static inline void +__srp_fix_request_limit( + IN srp_session_t *p_srp_session, + IN srp_rsp_t *p_srp_rsp ) +{ + int32_t rld = get_srp_response_request_limit_delta( p_srp_rsp ); + cl_atomic_add( &p_srp_session->connection.request_limit, rld ); +#if DBG + /* statistics */ + p_srp_session->x_rld_num++; + p_srp_session->x_rld_total += rld; + if ( p_srp_session->x_rld_max < rld ) + p_srp_session->x_rld_max = rld; + if ( p_srp_session->x_rld_min > rld ) + p_srp_session->x_rld_min = rld; +#endif +} + +static inline +ib_api_status_t +__srp_process_recv_completion( + IN srp_recv_descriptor_t *p_recv_descriptor, + IN srp_session_t *p_srp_session ) +{ + ib_api_status_t status = IB_SUCCESS; + srp_rsp_t *p_srp_rsp; + uint8_t response_status; + srp_send_descriptor_t *p_send_descriptor; + uint64_t response_tag; + BOOLEAN session_recover = FALSE; + + SRP_ENTER( SRP_DBG_DATA ); + + p_srp_rsp = (srp_rsp_t *)p_recv_descriptor->p_data_segment; + + set_srp_response_from_network_to_host( p_srp_rsp ); + + response_status = get_srp_response_status( p_srp_rsp ); + response_tag = get_srp_response_tag( (srp_rsp_t *)p_recv_descriptor->p_data_segment ); + + p_send_descriptor = srp_find_matching_send_descriptor( + &p_srp_session->descriptors, response_tag ); + if ( p_send_descriptor == NULL ) + { + /* Repost the recv descriptor */ + status = p_srp_session->p_hba->ifc.post_recv( + p_srp_session->connection.h_qp, &p_recv_descriptor->wr, NULL ); + if ( status != IB_SUCCESS ) + { + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("Failed to post send descriptor. Status = %d.\n", status) ); + } + else + { + __srp_fix_request_limit( p_srp_session, p_srp_rsp ); + } + SRP_PRINT( TRACE_LEVEL_WARNING, SRP_DBG_DATA, + ("Matching Send Descriptor not Found: tag %#I64x\n", response_tag ) ); + + if( status == IB_SUCCESS && + !cl_qlist_count( &p_srp_session->descriptors.sent_descriptors ) ) + { + /* Seem all commands from sent queue were aborted by timeout already */ + /* most likely Target get stuck. schedule session recovery */ + status = IB_ERROR; + } + return ( status ); + } + + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_DATA, + ("Recv Completion Received for Function = %s(0x%x), " + "Path = 0x%x, Target = 0x%x, Lun = 0x%x, tag 0x%I64x\n", + g_srb_function_name[p_send_descriptor->p_srb->Function], + p_send_descriptor->p_srb->Function, + p_send_descriptor->p_srb->PathId, + p_send_descriptor->p_srb->TargetId, + p_send_descriptor->p_srb->Lun, + get_srp_command_tag( (srp_cmd_t *)p_send_descriptor->data_segment )) ); + + switch ( get_srp_iu_buffer_type( (srp_iu_buffer_t *)p_send_descriptor->data_segment ) ) + { + case SRP_TSK_MGMT: + { + srp_tsk_mgmt_t *p_srp_tsk_mgmt = (srp_tsk_mgmt_t *)p_send_descriptor->data_segment; + + set_srp_tsk_mgmt_from_network_to_host( p_srp_tsk_mgmt ); + + if(response_status == SCSISTAT_GOOD) + { + p_send_descriptor->p_srb->SrbStatus = SRB_STATUS_SUCCESS; + } + else + { + p_send_descriptor->p_srb->SrbStatus = SRB_STATUS_ABORT_FAILED; + SRP_PRINT( TRACE_LEVEL_WARNING, SRP_DBG_DATA, + ("Scsi Error %s (%#x) Received for Function = %s(0x%x), " + "Path = 0x%x, Target = 0x%x, Lun = 0x%x, tag 0x%I64x\n", + g_srb_scsi_status_name[response_status], + response_status, + g_srb_function_name[p_send_descriptor->p_srb->Function], + p_send_descriptor->p_srb->Function, + p_send_descriptor->p_srb->PathId, + p_send_descriptor->p_srb->TargetId, + p_send_descriptor->p_srb->Lun, + get_srp_command_tag( (srp_cmd_t *)p_send_descriptor->data_segment )) ); + } + + if ( get_srp_tsk_mgmt_task_management_flags( p_srp_tsk_mgmt ) == TMF_ABORT_TASK ) + { + /* Repost the recv descriptor */ + status = p_srp_session->p_hba->ifc.post_recv( + p_srp_session->connection.h_qp, &p_recv_descriptor->wr, NULL ); + if ( status != IB_SUCCESS ) + { + session_recover = TRUE; + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("Failed to post recv descriptor. Status = %d.\n", status) ); + } + + } + + break; + } + + case SRP_CMD: + p_send_descriptor->p_srb->ScsiStatus = response_status; + if(response_status == SCSISTAT_GOOD) + { + p_send_descriptor->p_srb->SrbStatus = SRB_STATUS_SUCCESS; + } + else + { + p_send_descriptor->p_srb->SrbStatus = SRB_STATUS_ABORT_FAILED; + SRP_PRINT( TRACE_LEVEL_WARNING, SRP_DBG_DATA, + ("Scsi Error %s (%#x) Received for Function = %s(0x%x), " + "Path = 0x%x, Target = 0x%x, Lun = 0x%x, tag 0x%I64x\n", + g_srb_scsi_status_name[response_status], + response_status, + g_srb_function_name[p_send_descriptor->p_srb->Function], + p_send_descriptor->p_srb->Function, + p_send_descriptor->p_srb->PathId, + p_send_descriptor->p_srb->TargetId, + p_send_descriptor->p_srb->Lun, + get_srp_command_tag( (srp_cmd_t *)p_send_descriptor->data_segment )) ); + } + + if ( get_srp_response_flags( p_srp_rsp ) != 0 ) + { + uint32_t resid; + + if ( (response_status != SCSISTAT_CHECK_CONDITION) && get_srp_response_di_under( p_srp_rsp ) ) + { + resid = get_srp_response_data_in_residual_count( p_srp_rsp ); + + SRP_PRINT( TRACE_LEVEL_WARNING, SRP_DBG_DATA, + ("DI Underflow in response: expected %d got %d.\n", + p_send_descriptor->p_srb->DataTransferLength, + p_send_descriptor->p_srb->DataTransferLength - resid) ); + + p_send_descriptor->p_srb->DataTransferLength -= resid; + + if ( p_send_descriptor->p_srb->SrbStatus == SRB_STATUS_SUCCESS ) + { + p_send_descriptor->p_srb->SrbStatus = SRB_STATUS_DATA_OVERRUN; /* Also for underrun see DDK */ + } + } + + if ( (response_status != SCSISTAT_CHECK_CONDITION) && get_srp_response_do_under( p_srp_rsp ) ) + { + resid = get_srp_response_data_out_residual_count( p_srp_rsp ); + + SRP_PRINT( TRACE_LEVEL_WARNING, SRP_DBG_DATA, + ("DI Underflow in response: expected %d got %d.\n", + p_send_descriptor->p_srb->DataTransferLength, + p_send_descriptor->p_srb->DataTransferLength - resid) ); + + p_send_descriptor->p_srb->DataTransferLength -= resid; + + if ( p_send_descriptor->p_srb->SrbStatus == SRB_STATUS_SUCCESS ) + { + p_send_descriptor->p_srb->SrbStatus = SRB_STATUS_DATA_OVERRUN; /* Also for underrun see DDK */ + } + } + + if ( get_srp_response_sns_valid( p_srp_rsp ) ) + { + uint8_t *p_sense_data = get_srp_response_sense_data( p_srp_rsp ); + + /* Copy only as much of the sense data as we can hold. */ + cl_memcpy( p_send_descriptor->p_srb->SenseInfoBuffer, + p_sense_data, + MIN( get_srp_response_sense_data_list_length( p_srp_rsp ), + p_send_descriptor->p_srb->SenseInfoBufferLength ) ); + SRP_PRINT( TRACE_LEVEL_WARNING, SRP_DBG_DATA, + ("Sense Data SENSE_KEY 0x%02x ADDITIONAL_SENSE_CODE" + "0x%02x ADDITIONAL_SENSE_QUALIFIER 0x%02x.\n", + p_sense_data[2],p_sense_data[12],p_sense_data[13]) ); + + if ( ((p_sense_data[2]&0xf) == 0x0b /*ABORTED_COMMAND*/) && + (p_sense_data[12] == 0x08) && + (p_sense_data[13] == 0x00) ) + + { + /* probably a problem with the Vfx FC san like wire pull*/ + /* initiate session recovery */ + session_recover = TRUE; + if( p_srp_session->p_hba->session_paused[p_srp_session->target_id] == FALSE ) + { + p_srp_session->p_hba->session_paused[p_srp_session->target_id] = TRUE; + SRP_PRINT( TRACE_LEVEL_WARNING, SRP_DBG_DATA, + ("Sense Data indicates FC link connectivity has been lost.\n") ); + StorPortDeviceBusy( p_srp_session->p_hba->p_ext, + SP_UNTAGGED, + p_srp_session->target_id, + SP_UNTAGGED, + (ULONG)-1 ); + } + } + } + + if ( get_srp_response_di_over( p_srp_rsp ) || get_srp_response_do_over( p_srp_rsp ) ) + { + SRP_PRINT( TRACE_LEVEL_WARNING, SRP_DBG_DATA, + ("Overflow error in response.\n") ); + if ( p_send_descriptor->p_srb->SrbStatus == SRB_STATUS_SUCCESS ) + { + p_send_descriptor->p_srb->SrbStatus = SRB_STATUS_DATA_OVERRUN; + } + } + } + + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_DATA, + ("DataBuffer = 0x%I64x.\n", MmGetPhysicalAddress( + p_send_descriptor->p_srb->DataBuffer ).QuadPart) ); + + /* Repost the recv descriptor */ + status = p_srp_session->p_hba->ifc.post_recv( + p_srp_session->connection.h_qp, &p_recv_descriptor->wr, NULL ); + if ( status != IB_SUCCESS ) + { + session_recover = TRUE; + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("Failed to post recv descriptor. Status = %d.\n", status) ); + } + + break; + + case SRP_LOGIN_REQ: + case SRP_I_LOGOUT: + case SRP_CRED_RSP: + case SRP_AER_RSP: + default: + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("Illegal SRP IU CMD/RSP %#x received\n", + get_srp_iu_buffer_type( (srp_iu_buffer_t *)p_send_descriptor->data_segment ) ) ); + session_recover = TRUE; + break; + } + + status = __srp_clean_send_descriptor( p_send_descriptor, p_srp_session ); + if ( status != IB_SUCCESS ) + { + session_recover = TRUE; + } + + if( session_recover == TRUE ) + { + status = IB_ERROR; + } + else + { + __srp_fix_request_limit( p_srp_session, p_srp_rsp ); + status = __srp_repost_io_request( p_srp_session ); + } + + __srp_dump_srb_info( p_send_descriptor); + + StorPortNotification( RequestComplete, p_srp_session->p_hba->p_ext, p_send_descriptor->p_srb ); + + SRP_EXIT( SRP_DBG_DATA ); + + return ( status ); +} + +static inline +void +__srp_process_session_recv_completions( + IN srp_session_t *p_srp_session ) +{ + ib_api_status_t status; + ib_wc_t *p_wc_done_list; + ib_wc_t *p_wc; + + SRP_ENTER( SRP_DBG_DATA ); + + cl_obj_lock( &p_srp_session->obj ); + + if ( p_srp_session->connection.state != SRP_CONNECTED ) + { + cl_obj_unlock( &p_srp_session->obj ); + SRP_EXIT( SRP_DBG_DATA ); + return; + } + + status = p_srp_session->p_hba->ifc.poll_cq( + p_srp_session->connection.h_recv_cq, + &p_srp_session->connection.p_wc_free_list, + &p_wc_done_list ); + if ( status != IB_SUCCESS ) + { + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("ib_poll_cq() failed!, status 0x%x\n", status) ); + + p_srp_session->connection.state = SRP_CONNECT_FAILURE; + + SRP_EXIT( SRP_DBG_DATA ); + cl_obj_unlock( &p_srp_session->obj ); + return; + } + + cl_obj_ref( &p_srp_session->obj ); + cl_obj_unlock( &p_srp_session->obj ); + + while ( (p_wc = p_wc_done_list) != NULL ) + { + srp_recv_descriptor_t *p_recv_descriptor; + + /* Remove head from list */ + p_wc_done_list = p_wc->p_next; + p_wc->p_next = NULL; + + p_recv_descriptor = (srp_recv_descriptor_t *)((uintn_t)p_wc->wr_id); + + if ( p_wc->status == IB_WCS_SUCCESS ) + { + status = __srp_process_recv_completion( p_recv_descriptor, p_srp_session ); + if ( status != IB_SUCCESS ) + { + p_srp_session->connection.state = SRP_CONNECT_FAILURE; + cl_obj_deref( &p_srp_session->obj ); + return; + } + } + else + { + if( p_wc->status != IB_WCS_WR_FLUSHED_ERR ) + { + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("Recv Completion with Error Status %s (vendore specific %#x)\n", + p_srp_session->p_hba->ifc.get_wc_status_str( p_wc->status ), + (int)p_wc->vendor_specific) ); + } + else + { + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_DATA, + ("Recv Completion Flushed in Error Status: %s\n", + p_srp_session->p_hba->ifc.get_wc_status_str( p_wc->status ))); + + } + + p_srp_session->connection.state = SRP_CONNECT_FAILURE; + cl_obj_deref( &p_srp_session->obj ); + return; + } + + /* Put onto head of free list */ + cl_obj_lock( &p_srp_session->obj ); + p_wc->p_next = p_srp_session->connection.p_wc_free_list; + p_srp_session->connection.p_wc_free_list = p_wc; + cl_obj_unlock( &p_srp_session->obj ); + + /* Get next completion */ + p_wc = p_wc_done_list; + } + + /* Re-arm the CQ for more completions */ + status = p_srp_session->p_hba->ifc.rearm_cq( + p_srp_session->connection.h_recv_cq, FALSE ); + if ( status != IB_SUCCESS) + { + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("ib_rearm_cq() failed!, status 0x%x\n", status) ); + p_srp_session->connection.state = SRP_CONNECT_FAILURE; + + cl_obj_deref( &p_srp_session->obj ); + return; + } + + cl_obj_deref( &p_srp_session->obj ); + + SRP_EXIT( SRP_DBG_DATA ); +} + +/* srp_recv_completion_cb */ +/*! +Set Timer to Process Receive Completions - Responses to our requests + +@param p_context - context pointer to the owning session + +@return - none +*/ +void +srp_recv_completion_cb( + IN const ib_cq_handle_t h_cq, + IN void *p_context ) +{ + srp_session_t *p_srp_session = (srp_session_t *)p_context; + + SRP_ENTER( SRP_DBG_DATA ); + + UNUSED_PARAM( h_cq ); + + __srp_process_session_recv_completions( p_srp_session ); + if( p_srp_session->connection.state == SRP_CONNECT_FAILURE ) + { + srp_session_failed( p_srp_session ); + } + SRP_EXIT( SRP_DBG_DATA ); +} + +/* __srp_build_cmd */ +/*! +Build the SRP Cmd to be sent to the VFx target + +@param p_dev_ext - our context pointer +@param p_srb - scsi request to send to target + +@return - none +*/ +static inline +BOOLEAN +__srp_build_cmd( + IN PVOID p_dev_ext, + IN OUT PSCSI_REQUEST_BLOCK p_srb, + IN srp_conn_info_t *p_srp_conn_info ) +{ + srp_send_descriptor_t *p_send_descriptor = (srp_send_descriptor_t *)p_srb->SrbExtension; + srp_cmd_t *p_srp_cmd = (srp_cmd_t *)p_send_descriptor->data_segment; + UCHAR *p_cdb; + PSTOR_SCATTER_GATHER_LIST p_scatter_gather_list = NULL; + uint8_t scatter_gather_count = 0; + srp_memory_descriptor_t *p_memory_descriptor = NULL; + srp_memory_table_descriptor_t *p_table_descriptor = NULL; + uint32_t i; + ULONG scsi_direction = p_srb->SrbFlags & ( SRB_FLAGS_DATA_IN | SRB_FLAGS_DATA_OUT ); + DATA_BUFFER_DESCRIPTOR_FORMAT format = p_srp_conn_info->descriptor_format & DBDF_INDIRECT_DATA_BUFFER_DESCRIPTORS; + ULONG length; +#if DBG + srp_hba_t *p_hba = ((srp_ext_t *)p_dev_ext)->p_hba; + srp_session_t *p_srp_session; +#endif + + SRP_ENTER( SRP_DBG_DATA ); + +#if DBG + /* statistics */ + p_srp_session = p_hba->session_list[p_send_descriptor->p_srb->TargetId]; + p_srp_session->x_pkt_built++; +#endif + + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_DATA, + ("Sending I/O to Path = 0x%x, Target = 0x%x, Lun = 0x%x\n", + p_srb->PathId, + p_srb->TargetId, + p_srb->Lun) ); + + setup_srp_command( p_srp_cmd, + p_send_descriptor->tag, + DBDF_NO_DATA_BUFFER_DESCRIPTOR_PRESENT, + DBDF_NO_DATA_BUFFER_DESCRIPTOR_PRESENT, + 0, + 0, + BUILD_SCSI_ADDRESS( p_srb->Lun ), + TAV_SIMPLE_TASK, + 0 ); + + p_cdb = get_srp_command_cdb( p_srp_cmd ); + cl_memcpy( p_cdb, p_srb->Cdb, p_srb->CdbLength ); + + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_DATA, + ("CDB Length = %d.\n", p_srb->CdbLength) ); +#if DBG + { + char* cmd; + cmd = cl_zalloc(p_srb->CdbLength +1); + if(cmd) + { + for ( i = 0; i < p_srb->CdbLength; i++ ) + { + cmd[i] = p_srb->Cdb[i]; + } + cmd[i] = '\0'; + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_DATA, ("CDB = 0x%s\n",cmd) ); + + cl_free(cmd); + } + + } +#endif + + if ( !format ) + { + format = DBDF_DIRECT_DATA_BUFFER_DESCRIPTOR; + } + + if ( scsi_direction ) + { + p_scatter_gather_list = StorPortGetScatterGatherList( p_dev_ext, p_srb ); + CL_ASSERT( p_scatter_gather_list != NULL ); + scatter_gather_count = (uint8_t)p_scatter_gather_list->NumberOfElements; + } + + /* Cap the length of the inline descriptors to the maximum IU size. */ + if( p_srp_conn_info->max_scatter_gather_entries < scatter_gather_count ) + { + scatter_gather_count = + (uint8_t)p_srp_conn_info->max_scatter_gather_entries; + } + + if ( scsi_direction == SRB_FLAGS_DATA_IN ) + { + set_srp_command_data_in_buffer_desc_fmt( p_srp_cmd, format ); + set_srp_command_data_in_buffer_desc_count( p_srp_cmd, scatter_gather_count ); + p_memory_descriptor = get_srp_command_data_in_buffer_desc( p_srp_cmd ); + } + + else if ( scsi_direction == SRB_FLAGS_DATA_OUT ) + { + set_srp_command_data_out_buffer_desc_fmt( p_srp_cmd, format ); + set_srp_command_data_out_buffer_desc_count( p_srp_cmd, scatter_gather_count ); + p_memory_descriptor = get_srp_command_data_out_buffer_desc( p_srp_cmd ); + } + +#if DBG + { /* print max SG list, gotten from the StorPort */ + static ULONG s_sg_max = 0; + if ( p_scatter_gather_list && s_sg_max < p_scatter_gather_list->NumberOfElements ) + { + uint32_t total = 0; + PSTOR_SCATTER_GATHER_ELEMENT p_sg_el; + for ( i = 0, p_sg_el = p_scatter_gather_list->List; + i < scatter_gather_count; i++, p_sg_el++ ) + { + total += p_sg_el->Length; + } + s_sg_max = p_scatter_gather_list->NumberOfElements; + SRP_PRINT( TRACE_LEVEL_WARNING, SRP_DBG_DATA, + ( "StorPort sg_cnt %d, total %#x, max sg_cnt %d, direction %s\n", + s_sg_max, total, p_srp_conn_info->max_scatter_gather_entries, + ( scsi_direction == SRB_FLAGS_DATA_IN ) ? "IN" : "OUT" )); + } + } +#endif + + if ( p_memory_descriptor != NULL ) + { + PSTOR_SCATTER_GATHER_ELEMENT p_sg_element; + uint32_t totalLength; + uint64_t buf_addr; + if ( format == DBDF_INDIRECT_DATA_BUFFER_DESCRIPTORS ) + { + p_table_descriptor = (srp_memory_table_descriptor_t *)p_memory_descriptor; + p_memory_descriptor = ( srp_memory_descriptor_t *)(p_table_descriptor + 1 ); + + buf_addr = (StorPortGetPhysicalAddress( p_dev_ext,p_srb, p_memory_descriptor, &length)).QuadPart; + + /* we don't swap rkey - it is already in network order*/ + p_table_descriptor->descriptor.virtual_address = cl_hton64( buf_addr ); + p_table_descriptor->descriptor.memory_handle = p_srp_conn_info->rkey; + + if((p_scatter_gather_list->NumberOfElements > 1) && !__srp_map_fmr(p_dev_ext,p_scatter_gather_list,p_send_descriptor,p_memory_descriptor)) + { + /* Set the discriptor list len */ + p_table_descriptor->descriptor.data_length = + cl_hton32( sizeof(srp_memory_descriptor_t) *1); + p_table_descriptor->total_length = p_memory_descriptor->data_length; + if ( scsi_direction == SRB_FLAGS_DATA_IN ) + set_srp_command_data_in_buffer_desc_count( p_srp_cmd, 1 ); + else if ( scsi_direction == SRB_FLAGS_DATA_OUT ) + set_srp_command_data_out_buffer_desc_count( p_srp_cmd, 1 ); + + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_DATA, + ("virtual_address[%d] = 0x%I64x.\n", + 0, cl_ntoh64(p_memory_descriptor->virtual_address) ) ); + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_DATA, + ("memory_handle[%d] = 0x%x.\n", + 0, cl_ntoh32( p_memory_descriptor->memory_handle) ) ); + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_DATA, + ("data_length[%d] = %d.\n", + 0, cl_ntoh32( p_memory_descriptor->data_length) ) ); + } + else + { + CL_ASSERT( scatter_gather_count == + p_scatter_gather_list->NumberOfElements ); + + /* Set the descriptor list len */ + p_table_descriptor->descriptor.data_length = + cl_hton32( sizeof(srp_memory_descriptor_t) * + p_scatter_gather_list->NumberOfElements ); + + for ( i = 0, totalLength = 0, p_sg_element = p_scatter_gather_list->List; + i < scatter_gather_count; + i++, p_memory_descriptor++, p_sg_element++ ) + { + buf_addr = p_srp_conn_info->vaddr + p_sg_element->PhysicalAddress.QuadPart; + + p_memory_descriptor->virtual_address = cl_hton64( buf_addr ); + p_memory_descriptor->memory_handle = p_srp_conn_info->rkey; + p_memory_descriptor->data_length = cl_hton32( p_sg_element->Length ); + totalLength += p_sg_element->Length; + + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_DATA, + ("virtual_address[%d] = 0x%I64x.\n", + i, cl_ntoh64(p_memory_descriptor->virtual_address) ) ); + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_DATA, + ("memory_handle[%d] = 0x%x.\n", + i, cl_ntoh32( p_memory_descriptor->memory_handle) ) ); + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_DATA, + ("data_length[%d] = %d.\n", + i, cl_ntoh32( p_memory_descriptor->data_length) ) ); + } + p_table_descriptor->total_length = cl_hton32( totalLength ); + } + } + else if ( format == DBDF_DIRECT_DATA_BUFFER_DESCRIPTOR ) + { + CL_ASSERT( scatter_gather_count == + p_scatter_gather_list->NumberOfElements ); + if((p_scatter_gather_list->NumberOfElements > 1) && !__srp_map_fmr(p_dev_ext,p_scatter_gather_list,p_send_descriptor,p_memory_descriptor)) + { + if ( scsi_direction == SRB_FLAGS_DATA_IN ) + set_srp_command_data_in_buffer_desc_count( p_srp_cmd, 1 ); + else if ( scsi_direction == SRB_FLAGS_DATA_OUT ) + set_srp_command_data_out_buffer_desc_count( p_srp_cmd, 1 ); + } + else + { + for ( i = 0, p_sg_element = p_scatter_gather_list->List; + i < scatter_gather_count; i++, p_memory_descriptor++, p_sg_element++ ) + { + buf_addr = p_srp_conn_info->vaddr + p_sg_element->PhysicalAddress.QuadPart; + p_memory_descriptor->virtual_address = cl_hton64( buf_addr ); + p_memory_descriptor->memory_handle = p_srp_conn_info->rkey; + p_memory_descriptor->data_length = cl_hton32( p_sg_element->Length ); + + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_DATA, + ("virtual_address[%d] = 0x%I64x.\n", + i, cl_ntoh64(p_memory_descriptor->virtual_address) ) ); + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_DATA, + ("memory_handle[%d] = 0x%x.\n", + i, cl_ntoh32( p_memory_descriptor->memory_handle) ) ); + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_DATA, + ("data_length[%d] = %d.\n", + i, cl_ntoh32( p_memory_descriptor->data_length) ) ); + } + } + } + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_DATA, + ("scatter/gather count = %d.\n", scatter_gather_count)); + } + + p_srp_cmd->logical_unit_number = cl_hton64( p_srp_cmd->logical_unit_number ); + + //set_srp_command_from_host_to_network( p_srp_cmd ); + + SRP_EXIT( SRP_DBG_DATA ); + return TRUE; +} + +/* srp_format_io_request */ +/*! +Format the SRP Cmd for the VFx target + +@param p_dev_ext - our context pointer +@param p_srb - scsi request to send to target + +@return - TRUE for success, FALSE for failure +*/ +BOOLEAN +srp_format_io_request( + IN PVOID p_dev_ext, + IN OUT PSCSI_REQUEST_BLOCK p_srb ) +{ + srp_hba_t *p_hba = ((srp_ext_t *)p_dev_ext)->p_hba; + BOOLEAN result = TRUE; + srp_session_t *p_srp_session; + + SRP_ENTER( SRP_DBG_DATA ); + + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_DATA, + ("Device Extension Address = %p\n", p_dev_ext) ); + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_DATA, + ("Srb Address = %p\n", p_srb) ); + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_DATA, + ("Srb DataBuffer Address = %p\n", p_srb->DataBuffer) ); + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_DATA, + ("Srb DataTransferLength = %d\n", p_srb->DataTransferLength) ); + + cl_obj_lock( &p_hba->obj ); + + p_srp_session = p_hba->session_list[p_srb->TargetId]; + + if ( p_srp_session != NULL && + p_srp_session->connection.state == SRP_CONNECTED && + !p_hba->session_paused[p_srb->TargetId] ) + { + srp_conn_info_t srp_conn_info; + + cl_obj_ref( &p_srp_session->obj ); + cl_obj_unlock( &p_hba->obj ); + + srp_conn_info.vaddr = p_srp_session->hca.vaddr; + srp_conn_info.lkey = p_srp_session->hca.lkey; + srp_conn_info.rkey = p_srp_session->hca.rkey; + srp_conn_info.descriptor_format = p_srp_session->connection.descriptor_format; + srp_conn_info.init_to_targ_iu_sz = p_srp_session->connection.init_to_targ_iu_sz; + srp_conn_info.max_scatter_gather_entries = p_srp_session->connection.max_scatter_gather_entries; + srp_conn_info.tag = cl_atomic_inc( &p_srp_session->connection.tag ); + srp_conn_info.signal_send_completion = + ((srp_conn_info.tag % p_srp_session->connection.signaled_send_completion_count) == 0) ? TRUE : FALSE; + + cl_obj_deref( &p_srp_session->obj ); + + srp_build_send_descriptor( p_dev_ext, p_srb, &srp_conn_info ); + + result = __srp_build_cmd( p_dev_ext, p_srb, &srp_conn_info ); + + if( result != TRUE ) + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("BUILD command %#x failed = %#x tag %#I64x\n", + p_srb->Cdb[0], p_srb->SrbStatus, srp_conn_info.tag ) ); + } + else + { + // Handle the error case here + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("Cannot Find Session For Target ID = %d\n", p_srb->TargetId) ); + + p_srb->SrbStatus = SRB_STATUS_INVALID_TARGET_ID; + cl_obj_unlock( &p_hba->obj ); + result = FALSE; + } + + SRP_EXIT( SRP_DBG_DATA ); + return ( result ); +} + +void +srp_post_io_request( + IN PVOID p_dev_ext, + IN OUT PSCSI_REQUEST_BLOCK p_srb ) +{ + ib_api_status_t status = IB_SUCCESS; + srp_hba_t *p_hba = ((srp_ext_t *)p_dev_ext)->p_hba; + srp_send_descriptor_t *p_send_descriptor = (srp_send_descriptor_t *)p_srb->SrbExtension; + srp_session_t *p_srp_session; + srp_descriptors_t *p_descriptors; + + SRP_ENTER( SRP_DBG_DATA ); + + cl_obj_lock( &p_hba->obj ); + + p_srp_session = p_hba->session_list[p_srb->TargetId]; + + if( p_hba->session_paused[p_srb->TargetId] == TRUE ) + { + cl_obj_unlock( &p_hba->obj ); + p_srb->SrbStatus = SRB_STATUS_BUSY; + goto err; + } + + if ( p_srp_session != NULL && + p_srp_session->connection.state == SRP_CONNECTED ) + { + cl_obj_ref( &p_srp_session->obj ); + cl_obj_unlock( &p_hba->obj ); + + p_descriptors = &p_srp_session->descriptors; + + cl_spinlock_acquire ( &p_descriptors->pending_list_lock ); + if ( (p_srp_session->connection.request_limit <= p_srp_session->connection.request_threashold) || + !cl_is_qlist_empty( &p_descriptors->pending_descriptors ) || + p_srp_session->repost_is_on ) + { + int32_t num_pending_desc = (int32_t)cl_qlist_count( &p_descriptors->pending_descriptors ); + cl_spinlock_release ( &p_descriptors->pending_list_lock ); + srp_add_pending_descriptor( p_descriptors, p_send_descriptor ); + + /* don't allow pending queue grow indefinitely */ + if( num_pending_desc >= p_srp_session->connection.max_limit ) + { + StorPortDeviceBusy( p_dev_ext, + p_srb->PathId, + p_srb->TargetId, + p_srb->Lun, + 1 ); + } + + cl_obj_deref( &p_srp_session->obj ); + goto exit; + } + cl_spinlock_release ( &p_descriptors->pending_list_lock ); + + status = __srp_post_io_request( p_dev_ext, p_srb, p_srp_session ); + cl_obj_deref( &p_srp_session->obj ); + goto exit; + } + else + { + cl_obj_unlock( &p_hba->obj ); + p_srb->SrbStatus = SRB_STATUS_NO_HBA; + goto err; + } + +err: + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("Returning SrbStatus %s(0x%x) for Function = %s(0x%x), Path = 0x%x, " + "Target = 0x%x, Lun = 0x%x, tag 0x%I64x\n", + g_srb_status_name[p_srb->SrbStatus], + p_srb->SrbStatus, + g_srb_function_name[p_srb->Function], + p_srb->Function, + p_srb->PathId, + p_srb->TargetId, + p_srb->Lun, + get_srp_command_tag( (srp_cmd_t *)p_send_descriptor->data_segment )) ); + + status = __srp_clean_send_descriptor( p_send_descriptor, p_srp_session ); + if ( status != IB_SUCCESS ) + { + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("Failed to unmap FMR Status = %d.\n", status) ); + // TODO: Kill session and inform port driver link down storportnotification + } + + StorPortNotification( RequestComplete, p_dev_ext, p_srb ); + +exit: + if( status != IB_SUCCESS ) + { + p_srp_session->connection.state = SRP_CONNECT_FAILURE; + srp_session_failed( p_srp_session ); + } + SRP_EXIT( SRP_DBG_DATA ); +} + +void +srp_abort_command( + IN PVOID p_dev_ext, + IN OUT PSCSI_REQUEST_BLOCK p_srb ) +{ + srp_hba_t *p_hba = ((srp_ext_t *)p_dev_ext)->p_hba; + srp_session_t *p_srp_session; + uint64_t iu_tag; + srp_send_descriptor_t *p_srb_send_descriptor; + srp_send_descriptor_t *p_send_descriptor; + srp_conn_info_t srp_conn_info; + srp_tsk_mgmt_t *p_srp_tsk_mgmt; + + SRP_ENTER( SRP_DBG_DATA ); + + cl_obj_lock( &p_hba->obj ); + + p_srp_session = p_hba->session_list[p_srb->TargetId]; + if ( p_srp_session == NULL ) + { + /* If the session is NULL there is no connection and cannot be aborted */ + p_srb->SrbStatus = SRB_STATUS_ABORT_FAILED; + goto exit; + } + + p_srb_send_descriptor = (srp_send_descriptor_t *)p_srb->NextSrb->SrbExtension; + + iu_tag = get_srp_information_unit_tag( (srp_information_unit_t *)p_srb_send_descriptor->data_segment ); + + p_send_descriptor = srp_find_matching_pending_descriptor(&p_srp_session->descriptors, iu_tag ); + + /*complete pending locally as failed */ + if( p_send_descriptor != NULL ) + { + p_srb->SrbStatus = SRB_STATUS_ABORT_FAILED; + p_srb->ScsiStatus = SCSISTAT_COMMAND_TERMINATED; + + __srp_clean_send_descriptor( p_send_descriptor, p_srp_session ); + goto exit; + } + + p_send_descriptor = srp_find_matching_send_descriptor( &p_srp_session->descriptors, iu_tag ); + if ( p_send_descriptor == NULL ) + { + /* Cannot find the command so it must have been completed */ + p_srb->SrbStatus = SRB_STATUS_ABORT_FAILED; + goto exit; + } + + CL_ASSERT( p_srb_send_descriptor == p_send_descriptor ); + + if( __srp_clean_send_descriptor( p_send_descriptor, p_srp_session ) != IB_SUCCESS ) + { + p_srb->SrbStatus = SRB_STATUS_ABORT_FAILED; + goto exit; + } + + p_srb->NextSrb->SrbStatus = SRB_STATUS_ABORTED; + + /* create and send abort request to the VFx */ + + srp_conn_info.vaddr = p_srp_session->hca.vaddr; + srp_conn_info.lkey = p_srp_session->hca.lkey; + srp_conn_info.rkey = p_srp_session->hca.rkey; + + srp_conn_info.init_to_targ_iu_sz = p_srp_session->connection.init_to_targ_iu_sz; + srp_conn_info.max_scatter_gather_entries = p_srp_session->connection.max_scatter_gather_entries; + srp_conn_info.tag = cl_atomic_inc( &p_srp_session->connection.tag ); + srp_conn_info.signal_send_completion = + ((srp_conn_info.tag % p_srp_session->connection.signaled_send_completion_count) == 0) ? TRUE : FALSE; + + srp_build_send_descriptor( p_dev_ext, p_srb, &srp_conn_info ); + + p_srp_tsk_mgmt = (srp_tsk_mgmt_t *)p_send_descriptor->data_segment; + + setup_srp_tsk_mgmt( p_srp_tsk_mgmt, + p_send_descriptor->tag, + BUILD_SCSI_ADDRESS( p_srb->Lun ), + TMF_ABORT_TASK, + iu_tag ); + + set_srp_tsk_mgmt_from_host_to_network( p_srp_tsk_mgmt ); + + srp_post_io_request( p_dev_ext, p_srb ); + +exit: + cl_obj_unlock( &p_hba->obj ); + if ( p_srb->SrbStatus == SRB_STATUS_ABORT_FAILED ) + { + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_DATA, + ("Returning SrbStatus %s(0x%x) for Function = %s(0x%x), " + "Path = 0x%x, Target = 0x%x, Lun = 0x%x\n", + g_srb_status_name[p_srb->SrbStatus], + p_srb->SrbStatus, + g_srb_function_name[p_srb->Function], + p_srb->Function, + p_srb->PathId, + p_srb->TargetId, + p_srb->Lun) ); + StorPortNotification( RequestComplete, p_dev_ext, p_srb ); + } + + SRP_EXIT( SRP_DBG_DATA ); +} + +void +srp_lun_reset( + IN PVOID p_dev_ext, + IN OUT PSCSI_REQUEST_BLOCK p_srb ) +{ + + ib_api_status_t status = IB_SUCCESS; + srp_hba_t *p_hba = ((srp_ext_t *)p_dev_ext)->p_hba; + srp_session_t *p_srp_session; + + SRP_ENTER( SRP_DBG_DATA ); + + cl_obj_lock( &p_hba->obj ); + + p_srp_session = p_hba->session_list[p_srb->TargetId]; + if ( p_srp_session != NULL ) + { + srp_send_descriptor_t *p_send_descriptor; + UCHAR path_id = p_srb->PathId; + UCHAR target_id = p_srb->TargetId; + UCHAR lun = p_srb->Lun; + + StorPortPauseDevice( p_dev_ext, p_srb->PathId, p_srb->TargetId, p_srb->Lun, 10 ); + + /* release this device' descriptors from the pending_list */ + while ( (p_send_descriptor = srp_remove_lun_head_pending_descriptor( &p_srp_session->descriptors, p_srb->Lun )) != NULL ) + { + status = __srp_clean_send_descriptor( p_send_descriptor, p_srp_session ); + if ( status != IB_SUCCESS ) + { + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("Failed to unmap FMR Status = %d.\n", status) ); + // TODO: Kill session and inform port driver link down storportnotification + } + + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_DATA, + ("Returning SrbStatus %s(0x%x) for Function = %s(0x%x), " + "Path = 0x%x, Target = 0x%x, Lun = 0x%x, tag 0x%I64xn", + g_srb_status_name[SRB_STATUS_BUS_RESET], + SRB_STATUS_BUS_RESET, + g_srb_function_name[p_send_descriptor->p_srb->Function], + p_send_descriptor->p_srb->Function, + p_send_descriptor->p_srb->PathId, + p_send_descriptor->p_srb->TargetId, + p_send_descriptor->p_srb->Lun, + get_srp_command_tag( (srp_cmd_t *)p_send_descriptor->data_segment )) ); + } + + /* release this device' descriptors from the sent_list */ + while ( (p_send_descriptor = srp_remove_lun_head_send_descriptor( &p_srp_session->descriptors, p_srb->Lun )) != NULL ) + { + status = __srp_clean_send_descriptor( p_send_descriptor, p_srp_session ); + if ( status != IB_SUCCESS ) + { + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("Failed to unmap FMR Status = %d.\n", status) ); + // TODO: Kill session and inform port driver link down storportnotification + } + + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_DATA, + ("Returning SrbStatus %s(0x%x) for Function = %s(0x%x), " + "Path = 0x%x, Target = 0x%x, Lun = 0x%x, tag 0x%I64xn", + g_srb_status_name[SRB_STATUS_BUS_RESET], + SRB_STATUS_BUS_RESET, + g_srb_function_name[p_send_descriptor->p_srb->Function], + p_send_descriptor->p_srb->Function, + p_send_descriptor->p_srb->PathId, + p_send_descriptor->p_srb->TargetId, + p_send_descriptor->p_srb->Lun, + get_srp_command_tag( (srp_cmd_t *)p_send_descriptor->data_segment )) ); + } + + + p_srb->SrbStatus = SRB_STATUS_SUCCESS; + + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_DATA, + ("Returning SrbStatus %s(0x%x) for Function = %s(0x%x), " + "Path = 0x%x, Target = 0x%x, Lun = 0x%x\n", + g_srb_status_name[p_srb->SrbStatus], + p_srb->SrbStatus, + g_srb_function_name[p_srb->Function], + p_srb->Function, + p_srb->PathId, + p_srb->TargetId, + p_srb->Lun) ); + + StorPortNotification( RequestComplete, p_dev_ext, p_srb ); + + StorPortCompleteRequest( p_dev_ext, path_id, target_id, lun, SRB_STATUS_BUS_RESET ); + + StorPortResumeDevice( p_dev_ext, path_id, target_id, lun ); + } + else + { + // Handle the error case here + p_srb->SrbStatus = SRB_STATUS_INVALID_TARGET_ID; + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_DATA, + ("Returning SrbStatus %s(0x%x) for Function = %s(0x%x), " + "Path = 0x%x, Target = 0x%x, Lun = 0x%x\n", + g_srb_status_name[p_srb->SrbStatus], + p_srb->SrbStatus, + g_srb_function_name[p_srb->Function], + p_srb->Function, + p_srb->PathId, + p_srb->TargetId, + p_srb->Lun) ); + + StorPortNotification( RequestComplete, p_dev_ext, p_srb ); + } + + cl_obj_unlock( &p_hba->obj ); + + SRP_EXIT( SRP_DBG_DATA ); +} + +#if DBG + +/* statistics */ + +void +srp_x_clean( + IN void *p_session ) +{ + srp_session_t *p_srp_session = p_session; + + if (p_srp_session == NULL || + p_srp_session->connection.state != SRP_CONNECTED ) + return; + + p_srp_session->x_pkt_fmr = 0; + p_srp_session->x_pkt_built = 0; + p_srp_session->x_rld_total = 0; + p_srp_session->x_rld_num = 0; + p_srp_session->x_rld_max = 0; + p_srp_session->x_rld_min = p_srp_session->x_req_limit; + p_srp_session->x_pend_total = 0; + p_srp_session->x_pend_num = 0; + p_srp_session->x_pend_max = 0; + p_srp_session->x_sent_total = 0; + p_srp_session->x_sent_num = 0; + p_srp_session->x_sent_max = 0; +} + +void +srp_x_print( + IN void *p_session ) +{ + srp_session_t *p_srp_session = p_session; + + if (p_srp_session == NULL || + p_srp_session->connection.state != SRP_CONNECTED ) + return; + + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_DATA, + ("req_limit %d, pkt_built %d, pkt_fmr'ed %d\n", + p_srp_session->x_req_limit, + p_srp_session->x_pkt_built, + p_srp_session->x_pkt_fmr )); + + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_DATA, + ("request_limit_delta: max %d, min %d, average %d, num %d\n", + p_srp_session->x_rld_max, p_srp_session->x_rld_min, + (p_srp_session->x_rld_num) ? p_srp_session->x_rld_total / p_srp_session->x_rld_num : 0, + p_srp_session->x_rld_num )); + + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_DATA, + ("pendinq_desc: max %d, average %d, num %d\n", + p_srp_session->x_pend_max, + (p_srp_session->x_pend_num) ? p_srp_session->x_pend_total / p_srp_session->x_pend_num : 0, + p_srp_session->x_pend_num )); + + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_DATA, + ("sent_desc: max %d, average %d, num %d\n", + p_srp_session->x_sent_max, + (p_srp_session->x_sent_num) ? p_srp_session->x_sent_total / p_srp_session->x_sent_num : 0, + p_srp_session->x_sent_num )); + +} + +#endif diff --git a/branches/WOF2-3/ulp/srp/kernel/srp_data_path.h b/branches/WOF2-3/ulp/srp/kernel/srp_data_path.h new file mode 100644 index 00000000..63db7be2 --- /dev/null +++ b/branches/WOF2-3/ulp/srp/kernel/srp_data_path.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corp. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + +#ifndef _SRP_DATA_PATH_H_ +#define _SRP_DATA_PATH_H_ + + +#include +#include +#include "srp.h" +#include "srp_data.h" + +typedef struct _srp_conn_info +{ + uint64_t vaddr; + net32_t lkey; + net32_t rkey; + uint32_t init_to_targ_iu_sz; + uint64_t tag; + uint32_t max_scatter_gather_entries; + BOOLEAN signal_send_completion; + DATA_BUFFER_DESCRIPTOR_FORMAT descriptor_format; +} srp_conn_info_t; + +void +srp_send_completion_cb( + IN const ib_cq_handle_t h_cq, + IN void *p_context ); + +void +srp_recv_completion_cb( + IN const ib_cq_handle_t h_cq, + IN void *p_context ); + +BOOLEAN +srp_format_io_request( + IN PVOID p_dev_ext, + IN OUT PSCSI_REQUEST_BLOCK p_srb ); + +void +srp_post_io_request( + IN PVOID p_dev_ext, + IN OUT PSCSI_REQUEST_BLOCK p_srb ); + +void +srp_abort_command( + IN PVOID p_dev_ext, + IN OUT PSCSI_REQUEST_BLOCK p_srb ); + +void +srp_lun_reset( + IN PVOID p_dev_ext, + IN OUT PSCSI_REQUEST_BLOCK p_srb ); + +#endif /* _SRP_DATA_PATH_H_ */ diff --git a/branches/WOF2-3/ulp/srp/kernel/srp_debug.h b/branches/WOF2-3/ulp/srp/kernel/srp_debug.h new file mode 100644 index 00000000..9a5ff7a1 --- /dev/null +++ b/branches/WOF2-3/ulp/srp/kernel/srp_debug.h @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + +#ifndef _SRP_DEBUG_H_ +#define _SRP_DEBUG_H_ + + +#include + + +extern uint32_t g_srp_dbg_level; +extern uint32_t g_srp_dbg_flags; +extern uint32_t g_srp_mode_flags; + +// mode flags +#define SRP_MODE_NO_FMR_POOL (1 << 0) /* don't use FMR_POOL - for tuning purposes */ +#define SRP_MODE_SG_UNLIMITED (1 << 1) /* don't obey the limitation, stated in DDK, not to enlarge StorPort max SG */ + +#if defined(EVENT_TRACING) +// +// Software Tracing Definitions +// + + +#define WPP_CONTROL_GUIDS \ + WPP_DEFINE_CONTROL_GUID(SRPCtlGuid,(5AF07B3C,D119,4233,9C81,C07EF481CBE6), \ + WPP_DEFINE_BIT( SRP_DBG_ERROR) \ + WPP_DEFINE_BIT( SRP_DBG_PNP) \ + WPP_DEFINE_BIT( SRP_DBG_DATA) \ + WPP_DEFINE_BIT( SRP_DBG_SESSION) \ + WPP_DEFINE_BIT( SRP_DBG_DEBUG)) + + + +#define WPP_LEVEL_FLAGS_ENABLED(lvl, flags) (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= lvl) +#define WPP_LEVEL_FLAGS_LOGGER(lvl,flags) WPP_LEVEL_LOGGER(flags) +#define WPP_FLAG_ENABLED(flags)(WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= TRACE_LEVEL_VERBOSE) +#define WPP_FLAG_LOGGER(flags) WPP_LEVEL_LOGGER(flags) + + +// begin_wpp config +// SRP_ENTER(FLAG); +// SRP_EXIT(FLAG); +// USEPREFIX(SRP_PRINT, "%!STDPREFIX! [SRP] :%!FUNC!() :"); +// USEPREFIX(SRP_PRINT_EXIT, "%!STDPREFIX! [SRP] :%!FUNC!() :"); +// USESUFFIX(SRP_ENTER, " [SRP] :%!FUNC!():["); +// USESUFFIX(SRP_EXIT, " [SRP] :%!FUNC!():]"); +// end_wpp + + +#else + + +#include + +/* + * Debug macros + */ + + +#define SRP_DBG_ERR (1 << 0) +#define SRP_DBG_PNP (1 << 1) +#define SRP_DBG_DATA (1 << 2) +#define SRP_DBG_SESSION (1 << 3) +#define SRP_DBG_DEBUG (1 << 4) + +#define SRP_DBG_ERROR (CL_DBG_ERROR | SRP_DBG_ERR) +#define SRP_DBG_ALL CL_DBG_ALL + +#if DBG + +// assignment of _level_ is need to to overcome warning C4127 +#define SRP_PRINT(_level_,_flag_,_msg_) \ + { \ + if( g_srp_dbg_level >= (_level_) ) \ + CL_TRACE( _flag_, g_srp_dbg_flags, _msg_ ); \ + } + +#define SRP_PRINT_EXIT(_level_,_flag_,_msg_) \ + { \ + if( g_srp_dbg_level >= (_level_) ) \ + CL_TRACE( _flag_, g_srp_dbg_flags, _msg_ );\ + SRP_EXIT(_flag_);\ + } + +#define SRP_ENTER(_flag_) \ + { \ + if( g_srp_dbg_level >= TRACE_LEVEL_VERBOSE ) \ + CL_ENTER( _flag_, g_srp_dbg_flags ); \ + } + +#define SRP_EXIT(_flag_)\ + { \ + if( g_srp_dbg_level >= TRACE_LEVEL_VERBOSE ) \ + CL_EXIT( _flag_, g_srp_dbg_flags ); \ + } + + +#else + +#define SRP_PRINT(lvl, flags, msg) + +#define SRP_PRINT_EXIT(_level_,_flag_,_msg_) + +#define SRP_ENTER(_flag_) + +#define SRP_EXIT(_flag_) + + +#endif + + +#endif //EVENT_TRACING + +extern char g_srb_function_name[][32]; +extern char g_srb_status_name[][32]; +extern char g_srb_scsi_status_name[][32]; + +#endif /* _SRP_DEBUG_H_ */ diff --git a/branches/WOF2-3/ulp/srp/kernel/srp_descriptors.c b/branches/WOF2-3/ulp/srp/kernel/srp_descriptors.c new file mode 100644 index 00000000..bf07ec79 --- /dev/null +++ b/branches/WOF2-3/ulp/srp/kernel/srp_descriptors.c @@ -0,0 +1,687 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corp. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include "srp_connection.h" +#include "srp_cmd.h" +#include "srp_data_path.h" +#include "srp_descriptors.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "srp_descriptors.tmh" +#endif +#include "srp_rsp.h" +#include "srp_session.h" +#include "srp_tsk_mgmt.h" + +/* __srp_create_recv_descriptors */ +/*! +Creates the receive descriptors and posts them to the receive queue + +@param p_descriptors - pointer to the work requests structure +@param h_pd - protection domain used for registration of memory +@param h_qp - queue pair used to post work requests +@param lkey - lkey for all physical memory + +@return - result of operations +*/ +static ib_api_status_t +__srp_create_recv_descriptors( + IN OUT srp_descriptors_t *p_descriptors, + IN ib_al_ifc_t* const p_ifc, + IN ib_pd_handle_t h_pd, + IN ib_qp_handle_t h_qp, + IN net32_t lkey) +{ + ib_api_status_t status = IB_SUCCESS; + srp_recv_descriptor_t *p_descriptor; + uint8_t *p_data_segment; + uint32_t i; + + SRP_ENTER( SRP_DBG_PNP ); + UNUSED_PARAM( h_pd ); + /* Create the array of recv descriptors */ + p_descriptors->p_recv_descriptors_array = + (srp_recv_descriptor_t *)cl_zalloc( p_descriptors->recv_descriptor_count * sizeof(srp_recv_descriptor_t) ); + if ( p_descriptors->p_recv_descriptors_array == NULL ) + { + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("Failed to allocate %d recv descriptors.\n", p_descriptors->recv_descriptor_count) ); + status = IB_INSUFFICIENT_MEMORY; + goto exit; + } + + /* Create the array of recv data segments */ + p_descriptors->p_recv_data_segments_array = + cl_zalloc( p_descriptors->recv_descriptor_count * p_descriptors->recv_data_segment_size ); + if ( p_descriptors->p_recv_data_segments_array == NULL ) + { + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("Failed to allocate %d recv data segments of %d length.\n", + p_descriptors->recv_descriptor_count, + p_descriptors->recv_data_segment_size) ); + + cl_free( p_descriptors->p_recv_descriptors_array ); + p_descriptors->p_recv_descriptors_array = NULL; + status = IB_INSUFFICIENT_MEMORY; + goto exit; + } + + /* Initialize them and post to receive queue */ + p_descriptor = p_descriptors->p_recv_descriptors_array; + p_data_segment = p_descriptors->p_recv_data_segments_array; + + for ( i = 0; i < p_descriptors->recv_descriptor_count; i++ ) + { + p_descriptor->wr.p_next = NULL; + p_descriptor->wr.wr_id = (ULONG_PTR)p_descriptor; + p_descriptor->wr.num_ds = 1; + p_descriptor->wr.ds_array = p_descriptor->ds; + + p_descriptor->ds[0].vaddr = cl_get_physaddr(p_data_segment); + p_descriptor->ds[0].length = p_descriptors->recv_data_segment_size; + p_descriptor->ds[0].lkey = lkey; + + p_descriptors->p_recv_descriptors_array[i].p_data_segment = p_data_segment; + + status = p_ifc->post_recv( h_qp, &p_descriptor->wr, NULL ); + if ( status != IB_SUCCESS ) + { + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("Failed to post recv descriptor. Status = %d.\n", status) ); + goto exit; + } + + p_descriptor++; + p_data_segment += p_descriptors->recv_data_segment_size; + } + +exit: + SRP_EXIT( SRP_DBG_PNP ); + + return ( status ); +} + +/* srp_init_descriptors */ +/*! +Orchestrates creation of receive descriptor buffers and sent list + +@param p_descriptors - pointer to the descriptors structure +@param recv descriptor_count - number of receive descriptors to create +@param recv data_segment_size - size of each receive descriptor's data area +@param h_pd - protection domain used for registration of memory +@param h_qp - queue pair used to post work requests +@param lkey - lkey for all physical memory + +@return - result of operations +*/ +ib_api_status_t +srp_init_descriptors( + IN OUT srp_descriptors_t *p_descriptors, + IN uint32_t recv_descriptor_count, + IN uint32_t recv_data_segment_size, + IN ib_al_ifc_t* const p_ifc, + IN ib_pd_handle_t h_pd, + IN ib_qp_handle_t h_qp, + IN net32_t lkey) +{ + ib_api_status_t status; + + SRP_ENTER( SRP_DBG_PNP ); + + CL_ASSERT( p_descriptors != NULL ); + + cl_memclr( p_descriptors, sizeof(*p_descriptors) ); + + cl_spinlock_init ( &p_descriptors->sent_list_lock ); + cl_spinlock_init ( &p_descriptors->pending_list_lock ); + cl_qlist_init( &p_descriptors->sent_descriptors ); + cl_qlist_init( &p_descriptors->pending_descriptors ); + + p_descriptors->initialized = TRUE; + + p_descriptors->recv_descriptor_count = recv_descriptor_count; + p_descriptors->recv_data_segment_size = recv_data_segment_size; + + status = __srp_create_recv_descriptors( p_descriptors, p_ifc, h_pd, h_qp, lkey ); + if ( status != IB_SUCCESS ) + { + srp_destroy_descriptors( p_descriptors ); + } + + SRP_EXIT( SRP_DBG_PNP ); + + return ( status ); +} + +/* srp_destroy_descriptors */ +/*! +Destroys the receive work request buffers + +@param p_descriptors - pointer to the descriptors structure + +@return - result of operations +*/ +ib_api_status_t +srp_destroy_descriptors( + IN OUT srp_descriptors_t *p_descriptors ) +{ + SRP_ENTER( SRP_DBG_PNP ); + + if ( p_descriptors->initialized == TRUE ) + { + cl_spinlock_destroy ( &p_descriptors->sent_list_lock ); + cl_spinlock_destroy ( &p_descriptors->pending_list_lock ); + + if ( p_descriptors->p_recv_data_segments_array != NULL ) + { + cl_free( p_descriptors->p_recv_data_segments_array ); + } + + if ( p_descriptors->p_recv_descriptors_array != NULL ) + { + cl_free( p_descriptors->p_recv_descriptors_array ); + } + + cl_memclr( p_descriptors, sizeof( *p_descriptors ) ); + } + + SRP_EXIT( SRP_DBG_PNP ); + + return IB_SUCCESS; +} + +/* __srp_add_descriptor */ +/*! +Puts descriptor at tail of the list + +@param p_descriptors - pointer to the descriptors structure +@param p_descriptor - pointer to the descriptor to add +@param descriptors_list - pointer to the list + +@return - none +*/ +inline +void +__srp_add_descriptor( + IN srp_send_descriptor_t *p_descriptor, + IN cl_qlist_t *descriptors_list, + IN cl_spinlock_t *p_lock) +{ + SRP_ENTER( SRP_DBG_DATA ); + + cl_spinlock_acquire ( p_lock ); + + cl_qlist_insert_tail( descriptors_list, &p_descriptor->list_item ); + CL_ASSERT( descriptors_list == p_descriptor->list_item.p_list ); + + cl_spinlock_release ( p_lock ); + + SRP_EXIT( SRP_DBG_DATA ); +} + +/* srp_add_send_descriptor */ +/*! +Puts send descriptor at tail of the sent list + +@param p_descriptors - pointer to the descriptors structure +@param p_descriptor - pointer to the descriptor to add + +@return - none +*/ +inline +void +srp_add_send_descriptor( + IN srp_descriptors_t *p_descriptors, + IN srp_send_descriptor_t *p_descriptor ) +{ + SRP_ENTER( SRP_DBG_DATA ); + __srp_add_descriptor( p_descriptor, + &p_descriptors->sent_descriptors, &p_descriptors->sent_list_lock ); + SRP_EXIT( SRP_DBG_DATA ); +} + +/* srp_add_pending_descriptor */ +/*! +Puts pending send descriptor at tail of the pending list + +@param p_descriptors - pointer to the descriptors structure +@param p_descriptor - pointer to the descriptor to add + +@return - none +*/ +void +srp_add_pending_descriptor( + IN srp_descriptors_t *p_descriptors, + IN srp_send_descriptor_t *p_descriptor ) +{ + SRP_ENTER( SRP_DBG_DATA ); + __srp_add_descriptor( p_descriptor, + &p_descriptors->pending_descriptors, &p_descriptors->pending_list_lock ); + SRP_EXIT( SRP_DBG_DATA ); +} + +/* __srp_remove_send_descriptor */ +/*! +Removes send descriptor from the sent list + +@param p_descriptors - pointer to the descriptors structure +@param p_descriptor - pointer to the descriptor to add +@param descriptors_list - pointer to the list + +@return - none +*/ +inline +void +__srp_remove_send_descriptor( + IN srp_send_descriptor_t *p_descriptor, + IN cl_qlist_t *descriptors_list, + IN cl_spinlock_t *p_lock) +{ + SRP_ENTER( SRP_DBG_DATA ); + + cl_spinlock_acquire ( p_lock ); + + CL_ASSERT( descriptors_list == p_descriptor->list_item.p_list ); + cl_qlist_remove_item( descriptors_list, &p_descriptor->list_item ); + + cl_spinlock_release ( p_lock ); + + SRP_EXIT( SRP_DBG_DATA ); +} + + +/* srp_remove_send_descriptor */ +/*! +Removes send descriptor from the sent list + +@param p_descriptors - pointer to the descriptors structure +@param p_descriptor - pointer to the descriptor to add + +@return - none +*/ +inline +void +srp_remove_send_descriptor( + IN srp_descriptors_t *p_descriptors, + IN srp_send_descriptor_t *p_descriptor ) +{ + SRP_ENTER( SRP_DBG_DATA ); + __srp_remove_send_descriptor( p_descriptor, + &p_descriptors->sent_descriptors, &p_descriptors->sent_list_lock ); + SRP_EXIT( SRP_DBG_DATA ); +} + +/* srp_remove_pending_descriptor */ +/*! +Removes pending send descriptor from the sent list + +@param p_descriptors - pointer to the descriptors structure +@param p_descriptor - pointer to the descriptor to add + +@return - none +*/ +inline +void +srp_remove_pending_descriptor( + IN srp_descriptors_t *p_descriptors, + IN srp_send_descriptor_t *p_descriptor ) +{ + SRP_ENTER( SRP_DBG_DATA ); + __srp_remove_send_descriptor( p_descriptor, + &p_descriptors->pending_descriptors, &p_descriptors->pending_list_lock ); + SRP_EXIT( SRP_DBG_DATA ); +} + +/* __srp_remove_lun_head_send_descriptor */ +/*! +Removes and returns the send descriptor from the head of the a list for the lun specified + +@param p_descriptors - pointer to the descriptors structure +@param lun - lun for which to remove head send descriptor +@param descriptors_list - pointer to the list + +@return - srp_send_descriptor at head of sent list or NULL if empty +*/ +srp_send_descriptor_t* +__srp_remove_lun_head_send_descriptor( + IN UCHAR lun, + IN cl_qlist_t *descriptors_list, + IN cl_spinlock_t *p_lock) +{ + srp_send_descriptor_t *p_descriptor; + + SRP_ENTER( SRP_DBG_DATA ); + + cl_spinlock_acquire ( p_lock ); + + p_descriptor = (srp_send_descriptor_t *)cl_qlist_head( descriptors_list ); + CL_ASSERT( descriptors_list == p_descriptor->list_item.p_list ); + + while ( p_descriptor != (srp_send_descriptor_t *)cl_qlist_end( descriptors_list ) ) + { + if ( p_descriptor->p_srb->Lun == lun ) + { + CL_ASSERT( descriptors_list == p_descriptor->list_item.p_list ); + cl_qlist_remove_item( descriptors_list, &p_descriptor->list_item ); + break; + } + + p_descriptor = (srp_send_descriptor_t *)cl_qlist_next( &p_descriptor->list_item ); + CL_ASSERT( descriptors_list == p_descriptor->list_item.p_list ); + } + + if ( p_descriptor == (srp_send_descriptor_t *)cl_qlist_end( descriptors_list ) ) + { + p_descriptor = NULL; + } + + cl_spinlock_release ( p_lock ); + + SRP_EXIT( SRP_DBG_DATA ); + + return ( p_descriptor ); +} + + +/* srp_remove_lun_head_send_descriptor */ +/*! +Removes and returns the send descriptor from the head of the sent list for the lun specified + +@param p_descriptors - pointer to the descriptors structure +@param lun - lun for which to remove head send descriptor + +@return - srp_send_descriptor at head of sent list or NULL if empty +*/ +srp_send_descriptor_t* +srp_remove_lun_head_send_descriptor( + IN srp_descriptors_t *p_descriptors, + IN UCHAR lun ) +{ + srp_send_descriptor_t *p_descriptor; + + SRP_ENTER( SRP_DBG_DATA ); + p_descriptor = __srp_remove_lun_head_send_descriptor( + lun, &p_descriptors->sent_descriptors, &p_descriptors->sent_list_lock ); + SRP_EXIT( SRP_DBG_DATA ); + + return ( p_descriptor ); +} + +/* srp_remove_lun_head_pending_descriptor */ +/*! +Removes and returns the send descriptor from the head of the sent list for the lun specified + +@param p_descriptors - pointer to the descriptors structure +@param lun - lun for which to remove head send descriptor + +@return - srp_send_descriptor at head of sent list or NULL if empty +*/ +srp_send_descriptor_t* +srp_remove_lun_head_pending_descriptor( + IN srp_descriptors_t *p_descriptors, + IN UCHAR lun ) +{ + srp_send_descriptor_t *p_descriptor; + + SRP_ENTER( SRP_DBG_DATA ); + p_descriptor = __srp_remove_lun_head_send_descriptor( + lun, &p_descriptors->pending_descriptors, &p_descriptors->pending_list_lock ); + SRP_EXIT( SRP_DBG_DATA ); + + return ( p_descriptor ); +} + +/* srp_post_send_descriptor */ +/*! +Posts send descriptor across the connection specified and +if successful add it to the sent descriptors list + +@param p_descriptors - pointer to the descriptors structure +@param p_descriptor - pointer to the descriptor to send +@param p_session - pointer to the session used to send + +@return - result of post operation, or IB_ERROR if not connected +*/ +ib_api_status_t +srp_post_send_descriptor( + IN srp_descriptors_t *p_descriptors, + IN srp_send_descriptor_t *p_descriptor, + IN srp_session_t *p_session ) +{ + ib_api_status_t status = IB_ERROR; + srp_connection_t *p_connection; + ib_al_ifc_t *p_ifc; + + SRP_ENTER( SRP_DBG_DATA ); + + p_connection = &p_session->connection; + p_ifc = &p_session->hca.p_hba->ifc; + + if ( p_connection->state == SRP_CONNECTED ) + { + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_DATA, + ("wr_id = 0x%I64x.\n", p_descriptor->wr.wr_id) ); + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_DATA, + ("wr_type = 0x%x.\n", p_descriptor->wr.wr_type) ); + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_DATA, + ("send_opt = 0x%x.\n", p_descriptor->wr.send_opt) ); + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_DATA, + ("num_ds = 0x%x.\n", p_descriptor->wr.num_ds) ); + + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_DATA, + ("Posting I/O for Function = %s(0x%x), Path = 0x%x, " + "Target = 0x%x, Lun = 0x%x, tag 0x%I64x\n", + g_srb_function_name[p_descriptor->p_srb->Function], + p_descriptor->p_srb->Function, + p_descriptor->p_srb->PathId, + p_descriptor->p_srb->TargetId, + p_descriptor->p_srb->Lun, + get_srp_command_tag( (srp_cmd_t *)p_descriptor->data_segment )) ); + + if ( get_srp_iu_buffer_type( (srp_iu_buffer_t *)p_descriptor->data_segment ) == SRP_CMD ) + { + p_descriptor->ds[0].length = get_srp_command_length( (srp_cmd_t *)p_descriptor->data_segment ); + } + else /* task type */ + { + p_descriptor->ds[0].length = get_srp_tsk_mgmt_length( (srp_tsk_mgmt_t *)p_descriptor->data_segment ); + } + + ASSERT( p_descriptor->ds[0].length <= p_connection->init_to_targ_iu_sz ); + + srp_add_send_descriptor( p_descriptors, p_descriptor ); + + status = p_ifc->post_send( + p_connection->h_qp, &p_descriptor->wr, NULL ); + if ( status != IB_SUCCESS ) + { + /* Remove From Sent List */ + srp_remove_send_descriptor( p_descriptors, p_descriptor ); + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("Failed to post send descriptor. " + "ib_post_send status = 0x%x tag = 0x%I64x\n", + status, + get_srp_command_tag( (srp_cmd_t *)p_descriptor->data_segment )) ); + } + } + else + { + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("Attempting to post to an unconnected session.\n") ); + } + + SRP_EXIT( SRP_DBG_DATA ); + + return ( status ); +} + +static srp_send_descriptor_t* +__srp_find_matching_send_descriptor( + IN cl_qlist_t *p_descriptors_list, + IN uint64_t tag ) +{ + srp_send_descriptor_t *p_send_descriptor; + + SRP_ENTER( SRP_DBG_DATA ); + /* assumed list lock is taken outside */ + p_send_descriptor = (srp_send_descriptor_t *)cl_qlist_head( p_descriptors_list ); + CL_ASSERT( p_descriptors_list == p_send_descriptor->list_item.p_list ); + + while ( p_send_descriptor != (srp_send_descriptor_t *)cl_qlist_end( p_descriptors_list ) ) + { + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_DATA, ("cmd tag = 0x%I64x.\n", + get_srp_command_tag( (srp_cmd_t *)p_send_descriptor->data_segment )) ); + + if ( get_srp_command_tag( (srp_cmd_t *)p_send_descriptor->data_segment ) == tag ) + { + CL_ASSERT( p_descriptors_list == p_send_descriptor->list_item.p_list ); + cl_qlist_remove_item( p_descriptors_list, &p_send_descriptor->list_item ); + goto exit; + } + + p_send_descriptor = (srp_send_descriptor_t *)cl_qlist_next( &p_send_descriptor->list_item ); + } + + /* This is not an error. The request may have been aborted */ + p_send_descriptor = NULL; + +exit: + SRP_EXIT( SRP_DBG_DATA ); + + return ( p_send_descriptor ); +} + +/* srp_find_matching_send_descriptor */ +/*! +Given a received response find the matching send descriptor +which originated the request to the VFx and remove it from +the sent descriptor list + +@param p_descriptors - pointer to the descriptors structure +@param tag - tag of descriptor to find + +@return - pointer to send descriptor or NULL if not found +*/ +srp_send_descriptor_t* +srp_find_matching_send_descriptor( + IN srp_descriptors_t *p_descriptors, + IN uint64_t tag ) +{ + srp_send_descriptor_t *p_send_descriptor; + + SRP_ENTER( SRP_DBG_DATA ); + + cl_spinlock_acquire( &p_descriptors->sent_list_lock ); + + p_send_descriptor = __srp_find_matching_send_descriptor( &p_descriptors->sent_descriptors, tag ); + + cl_spinlock_release( &p_descriptors->sent_list_lock ); + + SRP_EXIT( SRP_DBG_DATA ); + + return ( p_send_descriptor ); +} + +srp_send_descriptor_t* +srp_find_matching_pending_descriptor( + IN srp_descriptors_t *p_descriptors, + IN uint64_t tag ) +{ + srp_send_descriptor_t *p_send_descriptor; + + SRP_ENTER( SRP_DBG_DATA ); + + cl_spinlock_acquire( &p_descriptors->pending_list_lock ); + + p_send_descriptor = __srp_find_matching_send_descriptor( &p_descriptors->pending_descriptors, tag ); + + cl_spinlock_release( &p_descriptors->pending_list_lock ); + + SRP_EXIT( SRP_DBG_DATA ); + + return ( p_send_descriptor ); +} + +/* srp_build_send_descriptor */ +/*! +Initializes a send descriptor's fields + +@param p_dev_ext - our context pointer +@param p_srb - scsi request to send to target +@param p_srp_conn_info - information about our connection to the VFx + +@return - none +*/ +void +srp_build_send_descriptor( + IN PVOID p_dev_ext, + IN OUT PSCSI_REQUEST_BLOCK p_srb, + IN p_srp_conn_info_t p_srp_conn_info ) +{ + srp_send_descriptor_t *p_send_descriptor = (srp_send_descriptor_t *)p_srb->SrbExtension; + STOR_PHYSICAL_ADDRESS physical_address; + ULONG length; + + SRP_ENTER( SRP_DBG_DATA ); + + cl_memclr( p_send_descriptor, (sizeof ( srp_send_descriptor_t ) - SRP_MAX_IU_SIZE) ); + + physical_address = StorPortGetPhysicalAddress( p_dev_ext, p_srb, p_send_descriptor->data_segment, &length ); + + p_send_descriptor->wr.wr_id = (uint64_t)((uintn_t)p_send_descriptor); + p_send_descriptor->wr.wr_type = WR_SEND; + p_send_descriptor->wr.send_opt = (p_srp_conn_info->signal_send_completion == TRUE) ? IB_SEND_OPT_SIGNALED : 0; + p_send_descriptor->wr.num_ds = 1; + p_send_descriptor->wr.ds_array = p_send_descriptor->ds; + p_send_descriptor->tag = p_srp_conn_info->tag; + p_send_descriptor->p_srb = p_srb; + p_send_descriptor->ds[0].vaddr = p_srp_conn_info->vaddr + physical_address.QuadPart; + p_send_descriptor->ds[0].length = p_srp_conn_info->init_to_targ_iu_sz; + p_send_descriptor->ds[0].lkey = p_srp_conn_info->lkey; + p_send_descriptor->p_fmr_el = NULL; + + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_DATA, + ("hca vaddr = 0x%I64x.\n", p_srp_conn_info->vaddr)); + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_DATA, + ("physical_address = 0x%I64x.\n", physical_address.QuadPart)); + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_DATA, + ("IU vaddr = 0x%I64x.\n", p_send_descriptor->ds[0].vaddr)); + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_DATA, + ("length = %d.\n", p_send_descriptor->ds[0].length)); + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_DATA, + ("lkey = 0x%x.\n", p_send_descriptor->ds[0].lkey)); + + SRP_EXIT( SRP_DBG_DATA ); +} diff --git a/branches/WOF2-3/ulp/srp/kernel/srp_descriptors.h b/branches/WOF2-3/ulp/srp/kernel/srp_descriptors.h new file mode 100644 index 00000000..00cbe1a6 --- /dev/null +++ b/branches/WOF2-3/ulp/srp/kernel/srp_descriptors.h @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corp. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#ifndef SRP_DESCRIPTORS_H_INCLUDED +#define SRP_DESCRIPTORS_H_INCLUDED + + +#include +#include +#include + +#include "srp_connection.h" +#include "srp_data.h" +#include "srp_debug.h" + +/* + * Number of data segments. + */ +#define SRP_NUM_SGE 1 + +typedef struct _srp_session *p_srp_session_t; +typedef struct _srp_conn_info *p_srp_conn_info_t; + +/* SRP SCSI request block extension. */ +typedef struct _srp_send_descriptor +{ + /* Leave this as first member variable */ + cl_list_item_t list_item; + ib_send_wr_t wr; + uint64_t tag; + SCSI_REQUEST_BLOCK *p_srb; + mlnx_fmr_pool_el_t p_fmr_el; + ib_local_ds_t ds[SRP_NUM_SGE]; + /* must be the last*/ + uint8_t data_segment[SRP_MAX_IU_SIZE]; +}srp_send_descriptor_t; + +typedef struct _srp_recv_descriptor +{ + ib_recv_wr_t wr; + ib_local_ds_t ds[SRP_NUM_SGE]; + uint8_t *p_data_segment; +}srp_recv_descriptor_t; + +typedef struct _srp_descriptors +{ + BOOLEAN initialized; + + cl_spinlock_t sent_list_lock; + cl_qlist_t sent_descriptors; + cl_spinlock_t pending_list_lock; + cl_qlist_t pending_descriptors; + + uint32_t recv_descriptor_count; + srp_recv_descriptor_t *p_recv_descriptors_array; + + uint32_t recv_data_segment_size; + void *p_recv_data_segments_array; + + +} srp_descriptors_t; + +ib_api_status_t +srp_init_descriptors( + IN OUT srp_descriptors_t *p_descriptors, + IN uint32_t recv_descriptor_count, + IN uint32_t recv_data_segment_size, + IN ib_al_ifc_t* const p_ifc, + IN ib_pd_handle_t h_pd, + IN ib_qp_handle_t h_qp, + IN net32_t lkey); + +ib_api_status_t +srp_destroy_descriptors( + IN OUT srp_descriptors_t *p_descriptors ); + +srp_send_descriptor_t* +srp_remove_lun_head_send_descriptor( + IN srp_descriptors_t *p_descriptors, + IN UCHAR lun ); + +srp_send_descriptor_t* +srp_remove_lun_head_pending_descriptor( + IN srp_descriptors_t *p_descriptors, + IN UCHAR lun ); + +void +srp_add_pending_descriptor( + IN srp_descriptors_t *p_descriptors, + IN srp_send_descriptor_t *p_descriptor ); + +ib_api_status_t +srp_post_send_descriptor( + IN srp_descriptors_t *p_descriptors, + IN srp_send_descriptor_t *p_descriptor, + IN struct _srp_session *p_session ); + +srp_send_descriptor_t* +srp_find_matching_send_descriptor( + IN srp_descriptors_t *p_descriptors, + IN uint64_t tag ) ; + +srp_send_descriptor_t* +srp_find_matching_pending_descriptor( + IN srp_descriptors_t *p_descriptors, + IN uint64_t tag ) ; + +void +srp_build_send_descriptor( + IN PVOID p_dev_ext, + IN OUT PSCSI_REQUEST_BLOCK p_srb, + IN p_srp_conn_info_t p_srp_conn_info ); + +#endif /* SRP_DESCRIPTORS_H_INCLUDED */ diff --git a/branches/WOF2-3/ulp/srp/kernel/srp_driver.c b/branches/WOF2-3/ulp/srp/kernel/srp_driver.c new file mode 100644 index 00000000..14f5167e --- /dev/null +++ b/branches/WOF2-3/ulp/srp/kernel/srp_driver.c @@ -0,0 +1,941 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include "srp_data.h" +#include "srp_data_path.h" +#include "srp_debug.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "srp_driver.tmh" +#endif +#include "srp_descriptors.h" +#include "srp_hba.h" +#include "srp_session.h" + +#include +#include +#include + + +#define SCSI_MAXIMUM_TRANSFER_SIZE (1024 * 1024) + +BOOLEAN g_srp_system_shutdown = FALSE; + + +uint32_t g_srp_dbg_level = TRACE_LEVEL_ERROR; +uint32_t g_srp_dbg_flags = 0x0000ffff; +uint32_t g_srp_mode_flags = 0; + +char g_srb_function_name[][32] = +{ + "EXECUTE_SCSI", // 0x00 + "CLAIM_DEVICE", // 0x01 + "IO_CONTROL", // 0x02 + "RECEIVE_EVENT", // 0x03 + "RELEASE_QUEUE", // 0x04 + "ATTACH_DEVICE", // 0x05 + "RELEASE_DEVICE", // 0x06 + "SHUTDOWN", // 0x07 + "FLUSH", // 0x08 + "", // 0x09 + "", // 0x0A + "", // 0x0B + "", // 0x0C + "", // 0x0D + "", // 0x0E + "", // 0x0F + "ABORT_COMMAND", // 0x10 + "RELEASE_RECOVERY", // 0x11 + "RESET_BUS", // 0x12 + "RESET_DEVICE", // 0x13 + "TERMINATE_IO", // 0x14 + "FLUSH_QUEUE", // 0x15 + "REMOVE_DEVICE", // 0x16 + "WMI", // 0x17 + "LOCK_QUEUE", // 0x18 + "UNLOCK_QUEUE", // 0x19 + "", // 0x1A + "", // 0x1B + "", // 0x1C + "", // 0x1D + "", // 0x1E + "", // 0x1F + "RESET_LOGICAL_UNIT", // 0x20 + "SET_LINK_TIMEOUT", // 0x21 + "LINK_TIMEOUT_OCCURRED", // 0x22 + "LINK_TIMEOUT_COMPLETE" // 0x23 +}; + +char g_srb_status_name[][32] = +{ + "PENDING", // 0x00 + "SUCCESS", // 0x01 + "ABORTED", // 0x02 + "ABORT_FAILED", // 0x03 + "ERROR", // 0x04 + "BUSY", // 0x05 + "INVALID_REQUEST", // 0x06 + "INVALID_PATH_ID", // 0x07 + "NO_DEVICE", // 0x08 + "TIMEOUT", // 0x09 + "SELECTION_TIMEOUT", // 0x0A + "COMMAND_TIMEOUT", // 0x0B + "", // 0x0C + "MESSAGE_REJECTED", // 0x0D + "BUS_RESET", // 0x0E + "PARITY_ERROR", // 0x0F + "REQUEST_SENSE_FAILED", // 0x10 + "NO_HBA", // 0x11 + "DATA_OVERRUN", // 0x12 + "UNEXPECTED_BUS_FREE", // 0x13 + "PHASE_SEQUENCE_FAILURE", // 0x14 + "BAD_SRB_BLOCK_LENGTH", // 0x15 + "REQUEST_FLUSHED", // 0x16 + "", // 0x17 + "", // 0x18 + "", // 0x19 + "", // 0x1A + "", // 0x1B + "", // 0x1C + "", // 0x1D + "", // 0x1E + "", // 0x1F + "INVALID_LUN", // 0x20 + "INVALID_TARGET_ID", // 0x21 + "BAD_FUNCTION", // 0x22 + "ERROR_RECOVERY", // 0x23 + "NOT_POWERED", // 0x24 + "LINK_DOWN" // 0x25 +}; + +char g_srb_scsi_status_name[][32] = +{ + "SCSISTAT_GOOD", //0x00 + "", //0x01 + " SCSISTAT_CHECK_CONDITION", //0x02 + "", //0x03 + " SCSISTAT_CONDITION_MET", //0x04 + "", //0x05 + "", //0x06 + "", //0x07 + " SCSISTAT_BUSY", //0x08 + "", //0x09 + "", //0x0A + "", //0x0B + "", //0x0C + "", //0x0D + "", //0x0E + "", //0x0F + " SCSISTAT_INTERMEDIATE", //0x10 + "", //0x11 + "", //0x12 + "", //0x13 + " SCSISTAT_INTERMEDIATE_COND_MET", //0x14 + "", //0x15 + "", //0x16 + "", //0x17 + " SCSISTAT_RESERVATION_CONFLICT", //0x18 + "", //0x19 + "", // 0x1A + "", // 0x1B + "", // 0x1C + "", // 0x1D + "", // 0x1E + "", // 0x1F + "", //0x20 + "", //0x21 + " SCSISTAT_COMMAND_TERMINATED", //0x22 + "", //0x23 + "", //0x24 + "", //0x25 + "", //0x26 + "", //0x27 + " SCSISTAT_QUEUE_FULL", //0x28 +}; + +DRIVER_OBJECT *gp_drv_obj; +cl_obj_t g_drv_obj; + +/* Mutex protecting the next lower device object pointer. */ +KMUTEX g_srp_pnp_mutex; + +PDRIVER_DISPATCH gpfn_pnp; +PDRIVER_ADD_DEVICE gpfn_add_device; +PDRIVER_UNLOAD gpfn_unload; + + +static NTSTATUS +__read_registry( + IN UNICODE_STRING* const p_Param_Path ); + +NTSTATUS +srp_add_device( + IN DRIVER_OBJECT *p_drv_obj, + IN DEVICE_OBJECT *p_pdo ); + +NTSTATUS +srp_dispatch_pnp( + IN DEVICE_OBJECT *p_dev_obj, + IN IRP *p_irp ); + +BOOLEAN +srp_init( + IN PVOID p_dev_ext ); + +BOOLEAN +srp_start_io( + IN PVOID p_dev_ext, + IN PSCSI_REQUEST_BLOCK p_srb ); + +BOOLEAN +srp_isr( + IN PVOID p_dev_ext ); + +ULONG +srp_find_adapter( + IN PVOID p_dev_ext, + IN PVOID resv1, + IN PVOID resv2, + IN PCHAR arg_str, + IN OUT PPORT_CONFIGURATION_INFORMATION p_config, + OUT PBOOLEAN resv3 ); + +BOOLEAN +srp_reset( + IN PVOID p_dev_ext, + IN ULONG path_id ); + +SCSI_ADAPTER_CONTROL_STATUS +srp_adapter_ctrl( + IN PVOID p_dev_ext, + IN SCSI_ADAPTER_CONTROL_TYPE ctrl_type, + IN PVOID params ); + +BOOLEAN +srp_build_io( + IN PVOID p_dev_ext, + IN PSCSI_REQUEST_BLOCK p_srb ); + +static void +srp_unload( + IN DRIVER_OBJECT *p_drv_obj ); + +static void +__srp_free( + IN cl_obj_t *p_obj ); + +#if DBG + +void +srp_x_print( + IN void *p_session ); + +void +srp_x_clean( + IN void *p_session ); + +void* gp_session[SRP_MAX_SERVICE_ENTRIES]; + +#endif + + +static NTSTATUS +__read_registry( + IN UNICODE_STRING* const p_registry_path ) +{ + NTSTATUS status; + /* Remember the terminating entry in the table below. */ + RTL_QUERY_REGISTRY_TABLE table[4]; + UNICODE_STRING param_path; + + SRP_ENTER( SRP_DBG_PNP ); + + RtlInitUnicodeString( ¶m_path, NULL ); + param_path.MaximumLength = p_registry_path->Length + + sizeof(L"\\Parameters"); + param_path.Buffer = cl_zalloc( param_path.MaximumLength ); + if( !param_path.Buffer ) + { + SRP_PRINT_EXIT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("Failed to allocate parameters path buffer.\n") ); + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlAppendUnicodeStringToString( ¶m_path, p_registry_path ); + RtlAppendUnicodeToString( ¶m_path, L"\\Parameters" ); + + /* + * Clear the table. This clears all the query callback pointers, + * and sets up the terminating table entry. + */ + cl_memclr( table, sizeof(table) ); + + /* Setup the table entries. */ + table[0].Flags = RTL_QUERY_REGISTRY_DIRECT; + table[0].Name = L"DebugLevel"; + table[0].EntryContext = &g_srp_dbg_level; + table[0].DefaultType = REG_DWORD; + table[0].DefaultData = &g_srp_dbg_level; + table[0].DefaultLength = sizeof(ULONG); + + table[1].Flags = RTL_QUERY_REGISTRY_DIRECT; + table[1].Name = L"DebugFlags"; + table[1].EntryContext = &g_srp_dbg_flags; + table[1].DefaultType = REG_DWORD; + table[1].DefaultData = &g_srp_dbg_flags; + table[1].DefaultLength = sizeof(ULONG); + + table[2].Flags = RTL_QUERY_REGISTRY_DIRECT; + table[2].Name = L"ModeFlags"; + table[2].EntryContext = &g_srp_mode_flags; + table[2].DefaultType = REG_DWORD; + table[2].DefaultData = &g_srp_mode_flags; + table[2].DefaultLength = sizeof(ULONG); + + + /* Have at it! */ + status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE, + param_path.Buffer, table, NULL, NULL ); + +#ifndef EVENT_TRACING + if( g_srp_dbg_flags & SRP_DBG_ERR ) + g_srp_dbg_flags |= CL_DBG_ERROR; +#endif + + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_PNP, + ("debug level %d debug flags 0x%.8x\n", + g_srp_dbg_level, + g_srp_dbg_flags) ); + + cl_free( param_path.Buffer ); + SRP_EXIT( SRP_DBG_PNP ); + return status; +} + + +ULONG +DriverEntry( + IN DRIVER_OBJECT *p_drv_obj, + IN UNICODE_STRING *p_registry_path ) +{ + ULONG status; + HW_INITIALIZATION_DATA hw_data; + cl_status_t cl_status; + + SRP_ENTER( SRP_DBG_PNP ); + +#if defined(EVENT_TRACING) + WPP_INIT_TRACING( p_drv_obj, p_registry_path ); +#endif + + status = CL_INIT; + if( !NT_SUCCESS(status) ) + { + SRP_PRINT_EXIT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("cl_init returned %08X.\n", status) ); + return status; + } + + gp_drv_obj = p_drv_obj; + + /* Get the registry values. */ + status = __read_registry( p_registry_path ); + if( !NT_SUCCESS(status) ) + { + CL_DEINIT; + SRP_PRINT_EXIT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("__read_registry returned %08x.\n", status) ); + return status; + } + + cl_obj_construct( &g_drv_obj, SRP_OBJ_TYPE_DRV ); + + KeInitializeMutex( &g_srp_pnp_mutex, 0 ); + + cl_memclr( &hw_data, sizeof(HW_INITIALIZATION_DATA) ); + + hw_data.HwInitializationDataSize = sizeof(HW_INITIALIZATION_DATA); + + hw_data.AdapterInterfaceType = Internal; + + /* Miniport driver routines */ + hw_data.HwInitialize = srp_init; + hw_data.HwStartIo = srp_start_io; +// hw_data.HwInterrupt = srp_isr; + hw_data.HwInterrupt = NULL; + hw_data.HwFindAdapter = srp_find_adapter; + hw_data.HwResetBus = srp_reset; + hw_data.HwAdapterControl = srp_adapter_ctrl; + hw_data.HwBuildIo = srp_build_io; + hw_data.HwDmaStarted = NULL; + hw_data.HwAdapterState = NULL; + + /* Extension sizes. */ + hw_data.DeviceExtensionSize = sizeof(srp_ext_t); + /* TODO: Do we need per-LU data? */ + hw_data.SpecificLuExtensionSize = 0; + hw_data.SrbExtensionSize = sizeof(srp_send_descriptor_t); + + /* Driver parameters. */ + hw_data.NumberOfAccessRanges = 1; + /* TODO: Can this be STOR_MAP_NO_BUFFERS? */ + hw_data.MapBuffers = STOR_MAP_NON_READ_WRITE_BUFFERS; + + hw_data.NeedPhysicalAddresses = TRUE; + hw_data.TaggedQueuing = TRUE; + hw_data.AutoRequestSense = TRUE; + hw_data.MultipleRequestPerLu = TRUE; + + cl_status = + cl_obj_init( &g_drv_obj, CL_DESTROY_SYNC, NULL, NULL, __srp_free ); + if( cl_status == CL_SUCCESS ) + { + // Invoke the port initialization function. + status = StorPortInitialize(p_drv_obj, p_registry_path, &hw_data, NULL); + if( NT_SUCCESS( status ) ) + { + /* + * Overwrite the PnP entrypoint, but save the original + * so we can call it. + */ + gpfn_pnp = p_drv_obj->MajorFunction[IRP_MJ_PNP]; + p_drv_obj->MajorFunction[IRP_MJ_PNP] = srp_dispatch_pnp; + gpfn_add_device = p_drv_obj->DriverExtension->AddDevice; + p_drv_obj->DriverExtension->AddDevice = srp_add_device; + gpfn_unload = p_drv_obj->DriverUnload; + p_drv_obj->DriverUnload = srp_unload; + } + else + { + CL_DEINIT; + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("StorPortInitialize returned 0x%x.\n", status) ); + } + } + else + { + CL_DEINIT; + status = (ULONG)STATUS_INSUFFICIENT_RESOURCES; + } + + SRP_PRINT_EXIT( TRACE_LEVEL_INFORMATION, SRP_DBG_PNP, + ("DriverEntry returning status of 0x%x.\n", status) ); + return status; +} + +static void +srp_unload( + IN DRIVER_OBJECT *p_drv_obj ) +{ + SRP_ENTER( SRP_DBG_PNP ); +#if defined(EVENT_TRACING) + WPP_CLEANUP( p_drv_obj ); +#endif + + /* Kill all SRP objects. */ + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_DEBUG, + ("Destroying all SRP objects.\n") ); + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_DEBUG, + ("Driver Object ref_cnt = %d\n", g_drv_obj.ref_cnt) ); + cl_obj_destroy( &g_drv_obj ); + + CL_DEINIT; + + /* Invoke the port driver's unload routine. */ + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_DEBUG, + ("Invoking the port driver's unload routine.\n") ); + gpfn_unload( p_drv_obj ); + + SRP_EXIT( SRP_DBG_PNP ); +} + + +static void +__srp_free( + IN cl_obj_t *p_obj ) +{ +// CL_ASSERT( p_obj == &g_drv_obj ); + UNUSED_PARAM ( p_obj ); + cl_obj_deinit( &g_drv_obj ); +} + + +NTSTATUS +srp_add_device( + IN DRIVER_OBJECT *p_drv_obj, + IN DEVICE_OBJECT *p_pdo ) +{ + NTSTATUS status; + + SRP_ENTER( SRP_DBG_PNP ); + + status = gpfn_add_device( p_drv_obj, p_pdo ); + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_PNP, + ("srp_add_device status = 0x%x.\n", status) ); + + SRP_EXIT( SRP_DBG_PNP ); + return status; +} + + +NTSTATUS +srp_dispatch_pnp( + IN DEVICE_OBJECT *p_dev_obj, + IN IRP *p_irp ) +{ + NTSTATUS status; + IO_STACK_LOCATION *p_stack; + UCHAR minor; + SRP_ENTER( SRP_DBG_PNP ); + + p_stack = IoGetCurrentIrpStackLocation( p_irp ); + minor = p_stack->MinorFunction; + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_PNP, + ("Minor PNP Function = %d.\n", minor) ); + + if( minor == IRP_MN_START_DEVICE ) + { + NTSTATUS wait_status; + + wait_status = KeWaitForMutexObject( + &g_srp_pnp_mutex, Executive, KernelMode, FALSE, NULL ); + + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_PNP, + ("KeWaitForMutexObject status = 0x%x.\n", wait_status) ); + gp_self_do = p_dev_obj; + } + status = gpfn_pnp( p_dev_obj, p_irp ); + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_PNP, + ("gpfn_pnp status = 0x%x.\n", status) ); + + if( minor == IRP_MN_START_DEVICE ) + { + LONG release_status; + gp_self_do = NULL; + release_status = KeReleaseMutex( &g_srp_pnp_mutex, FALSE ); + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_PNP, + ("KeReleaseMutex status = %d.\n", release_status) ); + } + + #if DBG_STATISTICS + /* statistics */ + + /* this function is called sometimes in the begging of the test with + IRP_MN_QUERY_DEVICE_RELATIONS (7) request. Use this fact to print the statistics */ + { + /* sometimes it's called once in 50msec, so we'll print once in 20 times */ + static int interval = 40; /* 2 sec */ + static int cnt = 0; + static int i; + if (++cnt >= interval) + { + cnt = 0; + if(i > 3 ) i = 0; + srp_x_print( gp_session[i] ); + srp_x_clean( gp_session[i] ); + i++; + } + } + + #endif + + SRP_EXIT( SRP_DBG_PNP ); + return status; +} + + +ULONG +srp_find_adapter( + IN PVOID p_dev_ext, + IN PVOID resv1, + IN PVOID resv2, + IN PCHAR arg_str, + IN OUT PPORT_CONFIGURATION_INFORMATION p_config, + OUT PBOOLEAN resv3 ) +{ + srp_ext_t *p_ext; + ib_api_status_t ib_status; + + SRP_ENTER( SRP_DBG_PNP ); + + UNUSED_PARAM( resv1 ); + UNUSED_PARAM( resv2 ); + UNUSED_PARAM( resv3 ); + UNUSED_PARAM( arg_str ); + UNUSED_PARAM( p_config ); + + if( KeGetCurrentIrql() >= DISPATCH_LEVEL ) + { + SRP_PRINT_EXIT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("Improper IRQL!\n") ); + return SP_RETURN_ERROR; + } + + p_ext = (srp_ext_t*)p_dev_ext; + + ib_status = srp_hba_create( &g_drv_obj, p_ext ); + if( ib_status != IB_SUCCESS ) + { + SRP_PRINT_EXIT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("srp_hba_create returned %d\n", ib_status) ); + return SP_RETURN_ERROR; + } + + p_config->SrbExtensionSize = MAX( p_ext->p_hba->max_srb_ext_sz, sizeof( srp_send_descriptor_t )); + //CL_ASSERT( p_config->SrbExtensionSize >= sizeof( srp_send_descriptor_t ) ); + + p_config->MaximumTransferLength = SCSI_MAXIMUM_TRANSFER_SIZE; + p_config->AlignmentMask = 0; /* byte alignment */ + p_config->NumberOfBuses = 1; + p_config->ScatterGather = TRUE; + p_config->Master = TRUE; // The HBA is a "bus" master. +// p_config->CachesData = TRUE; // Assume the HBA does cache data. + p_config->CachesData = FALSE; // Assume the HBA does not cache data. + p_config->MaximumNumberOfTargets = p_ext->p_hba->ioc_info.profile.num_svc_entries; + p_config->MaximumNumberOfLogicalUnits = SCSI_MAXIMUM_LUNS_PER_TARGET; + p_config->MultipleRequestPerLu = TRUE; + p_config->SynchronizationModel = StorSynchronizeFullDuplex; + p_config->MapBuffers = STOR_MAP_NON_READ_WRITE_BUFFERS; + p_config->ResetTargetSupported = FALSE; + +// p_config->InitiatorBusId[0] = 127; +// p_config->DeviceExtensionSize = sizeof( srp_ext_t ); + + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_DEBUG, + ("NumberOfPhysicalBreaks passed in = %d.\n", p_config->NumberOfPhysicalBreaks) ); + + if ( p_config->NumberOfPhysicalBreaks == SP_UNINITIALIZED_VALUE ) + { + p_config->NumberOfPhysicalBreaks = p_ext->p_hba->max_sg - 1; + } + else + { + if (g_srp_mode_flags & SRP_MODE_SG_UNLIMITED) + // It is prohibited by DDK, but seems like work + p_config->NumberOfPhysicalBreaks = p_ext->p_hba->max_sg - 1; + else + p_config->NumberOfPhysicalBreaks = MIN( p_ext->p_hba->max_sg - 1, p_config->NumberOfPhysicalBreaks ); + } + + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_DEBUG, + ( "max_sg %d, New NumberOfPhysicalBreaks %d\n", + p_ext->p_hba->max_sg, p_config->NumberOfPhysicalBreaks)); + + SRP_EXIT( SRP_DBG_PNP ); + return SP_RETURN_FOUND; +} + +BOOLEAN +srp_init( + IN PVOID p_dev_ext ) +{ + SRP_ENTER( SRP_DBG_PNP ); + + UNUSED_PARAM( p_dev_ext ); + + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_PNP, + ("called at IRQL %d\n", KeGetCurrentIrql()) ); + + SRP_EXIT( SRP_DBG_PNP ); + return TRUE; +} + +BOOLEAN +srp_start_io( + IN PVOID p_dev_ext, + IN PSCSI_REQUEST_BLOCK p_srb ) +{ + SRP_ENTER( SRP_DBG_DATA ); + + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_DATA, + ("Starting I/O for Function = %s(0x%x), Path = 0x%x, " + "Target = 0x%x, Lun = 0x%x\n", + g_srb_function_name[p_srb->Function], + p_srb->Function, + p_srb->PathId, + p_srb->TargetId, + p_srb->Lun) ); + + CL_ASSERT( p_srb->SrbExtension != NULL ); + + // Check the operation here + switch ( p_srb->Function ) + { + case SRB_FUNCTION_EXECUTE_SCSI: + srp_post_io_request( p_dev_ext, p_srb ); + break; + + case SRB_FUNCTION_ABORT_COMMAND: + srp_abort_command( p_dev_ext, p_srb ); + break; +#if !defined(WinXP) + case SRB_FUNCTION_RESET_LOGICAL_UNIT: +#endif + case SRB_FUNCTION_RESET_DEVICE: + srp_lun_reset( p_dev_ext, p_srb ); + break; + + case SRB_FUNCTION_SHUTDOWN: /* Only receive this if CachesData is TRUE in PORT_CONFIGURATION_INFORMATION */ + { + srp_hba_t *p_hba = ((srp_ext_t *)p_dev_ext)->p_hba; + srp_session_t *p_srp_session = p_hba->session_list[p_srb->TargetId]; + + g_srp_system_shutdown = TRUE; + + if ( (p_srb->Lun == 0) && (p_srp_session != NULL) ) + { + p_srp_session->p_shutdown_srb = p_srb; + + if( !p_hba->adapter_stopped ) + { + p_hba->adapter_stopped = TRUE; + srp_disconnect_sessions( p_hba ); + } + } + else + { + p_srb->SrbStatus = SRB_STATUS_SUCCESS; + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_DATA, + ("Returning SrbStatus %s(0x%x) for " + "Function = %s(0x%x), Path = 0x%x, " + "Target = 0x%x, Lun = 0x%x\n", + g_srb_status_name[p_srb->SrbStatus], + p_srb->SrbStatus, + g_srb_function_name[p_srb->Function], + p_srb->Function, + p_srb->PathId, + p_srb->TargetId, + p_srb->Lun) ); + StorPortNotification( RequestComplete, p_dev_ext, p_srb ); + } + break; + } + + case SRB_FUNCTION_FLUSH: /* Only receive this if CachesData is TRUE in PORT_CONFIGURATION_INFORMATION */ + p_srb->SrbStatus = SRB_STATUS_SUCCESS; + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_DATA, + ("Returning SrbStatus %s(0x%x) for " + "Function = %s(0x%x), Path = 0x%x, " + "Target = 0x%x, Lun = 0x%x\n", + g_srb_status_name[p_srb->SrbStatus], + p_srb->SrbStatus, + g_srb_function_name[p_srb->Function], + p_srb->Function, + p_srb->PathId, + p_srb->TargetId, + p_srb->Lun) ); + StorPortNotification( RequestComplete, p_dev_ext, p_srb ); + break; + + case SRB_FUNCTION_IO_CONTROL: /***** May Need To Support *****/ + + case SRB_FUNCTION_RESET_BUS: + case SRB_FUNCTION_TERMINATE_IO: + case SRB_FUNCTION_RELEASE_RECOVERY: + case SRB_FUNCTION_RECEIVE_EVENT: + case SRB_FUNCTION_LOCK_QUEUE: + case SRB_FUNCTION_UNLOCK_QUEUE: + case SRB_FUNCTION_CLAIM_DEVICE: + case SRB_FUNCTION_RELEASE_QUEUE: + case SRB_FUNCTION_ATTACH_DEVICE: + case SRB_FUNCTION_RELEASE_DEVICE: + case SRB_FUNCTION_FLUSH_QUEUE: + case SRB_FUNCTION_REMOVE_DEVICE: + case SRB_FUNCTION_WMI: +#if !defined(WinXP) + case SRB_FUNCTION_SET_LINK_TIMEOUT: + case SRB_FUNCTION_LINK_TIMEOUT_OCCURRED: + case SRB_FUNCTION_LINK_TIMEOUT_COMPLETE: +#endif + default: + p_srb->SrbStatus = SRB_STATUS_INVALID_REQUEST; + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_DATA, + ("Returning SrbStatus %s(0x%x) for " + "Function = %s(0x%x), Path = 0x%x, " + "Target = 0x%x, Lun = 0x%x\n", + g_srb_status_name[p_srb->SrbStatus], + p_srb->SrbStatus, + g_srb_function_name[p_srb->Function], + p_srb->Function, + p_srb->PathId, + p_srb->TargetId, + p_srb->Lun) ); + StorPortNotification( RequestComplete, p_dev_ext, p_srb ); + + } + + SRP_EXIT( SRP_DBG_DATA ); + + return ( TRUE ); +} + +BOOLEAN +srp_isr( + IN PVOID p_dev_ext ) +{ + SRP_ENTER( SRP_DBG_PNP ); + + UNUSED_PARAM( p_dev_ext ); + + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_PNP, + ("called at IRQL %d\n", KeGetCurrentIrql()) ); + + SRP_EXIT( SRP_DBG_PNP ); + return TRUE; +} + +BOOLEAN +srp_reset( + IN PVOID p_dev_ext, + IN ULONG path_id ) +{ + SRP_ENTER( SRP_DBG_PNP ); + + UNUSED_PARAM( p_dev_ext ); + + StorPortCompleteRequest( p_dev_ext, (UCHAR)path_id, SP_UNTAGGED, SP_UNTAGGED, SRB_STATUS_NO_HBA ); + + SRP_EXIT( SRP_DBG_PNP ); + return FALSE; +} + +SCSI_ADAPTER_CONTROL_STATUS +srp_adapter_ctrl( + IN PVOID p_dev_ext, + IN SCSI_ADAPTER_CONTROL_TYPE ctrl_type, + IN PVOID params ) +{ + srp_ext_t *p_ext; + SCSI_SUPPORTED_CONTROL_TYPE_LIST *p_ctrl_list; + + SRP_ENTER( SRP_DBG_PNP ); + + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_PNP, + ("called at IRQL %d\n", KeGetCurrentIrql()) ); + + p_ext = (srp_ext_t*)p_dev_ext; + + switch( ctrl_type ) + { + case ScsiQuerySupportedControlTypes: + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_DEBUG, + ("ScsiQuerySupportedControlTypes\n") ); + p_ctrl_list = (SCSI_SUPPORTED_CONTROL_TYPE_LIST*)params; + p_ctrl_list->SupportedTypeList[ScsiQuerySupportedControlTypes] = TRUE; + p_ctrl_list->SupportedTypeList[ScsiStopAdapter] = TRUE; + p_ctrl_list->SupportedTypeList[ScsiRestartAdapter] = FALSE; + p_ctrl_list->SupportedTypeList[ScsiSetBootConfig] = FALSE; + p_ctrl_list->SupportedTypeList[ScsiSetRunningConfig] = FALSE; + break; + + case ScsiStopAdapter: + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_DEBUG, + ("ScsiStopAdapter\n") ); + if( p_ext->p_hba ) + { + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_DEBUG, + ("HBA Object ref_cnt = %d\n", p_ext->p_hba->obj.ref_cnt) ); + if( !p_ext->p_hba->adapter_stopped ) + p_ext->p_hba->adapter_stopped = TRUE; + srp_disconnect_sessions( p_ext->p_hba ); + cl_obj_destroy( &p_ext->p_hba->obj ); + p_ext->p_hba = NULL; + } + break; + + case ScsiRestartAdapter: + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_DEBUG, + ("ScsiRestartAdapter\n") ); + break; + + case ScsiSetBootConfig: + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_DEBUG, + ("ScsiSetBootConfig\n") ); + break; + + case ScsiSetRunningConfig: + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_DEBUG, + ("ScsiSetRunningConfig\n") ); + break; + } + + SRP_EXIT( SRP_DBG_PNP ); + return ScsiAdapterControlSuccess; +} + +BOOLEAN +srp_build_io( + IN PVOID p_dev_ext, + IN PSCSI_REQUEST_BLOCK p_srb ) +{ + SRP_ENTER( SRP_DBG_DATA ); + + if ( p_srb->Function == SRB_FUNCTION_EXECUTE_SCSI ) + { + + CL_ASSERT( p_srb->SrbExtension != NULL ); + + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_DATA, + ("Building I/O for Function = %s(0x%x), " + "Path = 0x%x, Target = 0x%x, Lun = 0x%x\n", + g_srb_function_name[p_srb->Function], + p_srb->Function, + p_srb->PathId, + p_srb->TargetId, + p_srb->Lun) ); + + if ( srp_format_io_request( p_dev_ext, p_srb ) == FALSE ) + { + SRP_PRINT_EXIT( TRACE_LEVEL_ERROR, SRP_DBG_DATA, + ("Returning SrbStatus %s(0x%x) for " + "Function = %s(0x%x), Path = 0x%x, " + "Target = 0x%x, Lun = 0x%x\n", + g_srb_status_name[p_srb->SrbStatus], + p_srb->SrbStatus, + g_srb_function_name[p_srb->Function], + p_srb->Function, + p_srb->PathId, + p_srb->TargetId, + p_srb->Lun) ); + + StorPortNotification( RequestComplete, p_dev_ext, p_srb ); + + return ( FALSE ); + } + } + + SRP_EXIT( SRP_DBG_DATA ); + + return ( TRUE ); +} diff --git a/branches/WOF2-3/ulp/srp/kernel/srp_event.c b/branches/WOF2-3/ulp/srp/kernel/srp_event.c new file mode 100644 index 00000000..be1c2ad6 --- /dev/null +++ b/branches/WOF2-3/ulp/srp/kernel/srp_event.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corp. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include "srp_debug.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "srp_event.tmh" +#endif +#include "srp_event.h" +#include "srp_session.h" + +/* srp_async_event_handler_cb */ +/*! +Handles asynchronous events from ib + +@param p_event_rec - pointer to the async event + +@return - none +*/ +void +srp_async_event_handler_cb( + IN ib_async_event_rec_t *p_event_rec ) +{ + srp_session_t *p_srp_session = (srp_session_t *)p_event_rec->context; + + SRP_ENTER( SRP_DBG_PNP ); + + switch ( p_event_rec->code ) + { + case IB_AE_PORT_ACTIVE: + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_DEBUG, + ("Async Event IB_AE_PORT_ACTIVE (%d) received for %s.\n", + p_event_rec->code, + p_srp_session->p_hba->ioc_info.profile.id_string) ); + break; + + case IB_AE_PORT_DOWN: + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_DEBUG, + ("Async Event IB_AE_PORT_DOWN (%d) received for %s.\n", + p_event_rec->code, + p_srp_session->p_hba->ioc_info.profile.id_string) ); + break; + + default: + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_DEBUG, + ("Async Event %d received.\n", p_event_rec->code) ); + break; + } + + SRP_EXIT( SRP_DBG_PNP ); +} diff --git a/branches/WOF2-3/ulp/srp/kernel/srp_event.h b/branches/WOF2-3/ulp/srp/kernel/srp_event.h new file mode 100644 index 00000000..2aad4eaf --- /dev/null +++ b/branches/WOF2-3/ulp/srp/kernel/srp_event.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#ifndef _SRP_EVENT_H_ +#define _SRP_EVENT_H_ + +#include + +void +srp_async_event_handler_cb( + IN ib_async_event_rec_t *p_event_rec ); + +#endif /* _SRP_EVENT_H_ */ diff --git a/branches/WOF2-3/ulp/srp/kernel/srp_hba.c b/branches/WOF2-3/ulp/srp/kernel/srp_hba.c new file mode 100644 index 00000000..7bfcdd4c --- /dev/null +++ b/branches/WOF2-3/ulp/srp/kernel/srp_hba.c @@ -0,0 +1,1032 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corp. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + + +#include "srp_hba.h" +#include "srp_data.h" +#include "srp_data_path.h" +#include "srp_debug.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "srp_hba.tmh" +#endif +#include "srp_session.h" + +#include +#include +#include +#include + + +static void +__srp_destroying_hba( + IN cl_obj_t *p_obj ); + +static void +__srp_cleanup_hba( + IN cl_obj_t *p_obj ); + +static void +__srp_free_hba( + IN cl_obj_t *p_obj ); + +static ib_api_status_t +__srp_pnp_cb( + IN ib_pnp_rec_t *p_pnp_rec ); + +void +__srp_dump_ioc_info( const ib_ioc_info_t *p_ioc_info ) +{ + UNUSED_PARAM( p_ioc_info ); + + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_PNP, + ("Dumping IOC Info\n") ); + + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_PNP, + ("\tchassis_guid\t= 0x%I64x\n", + cl_ntoh64( p_ioc_info->chassis_guid )) ); + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_PNP, + ("\tchassis_slot\t= %d\n", + p_ioc_info->chassis_slot) ); + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_PNP, + ("\tiou_guid\t= 0x%I64x\n", + cl_ntoh64( p_ioc_info->iou_guid )) ); + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_PNP, + ("\tiou_slot\t= %d\n", + p_ioc_info->iou_slot) ); + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_PNP, ("\n") ); + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_PNP, + ("Dumping IOC Info Profile\n") ); + + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_PNP, + ("\tioc_guid\t= 0x%I64x\n", + cl_ntoh64( p_ioc_info->profile.ioc_guid )) ); + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_PNP, + ("\tvend_id\t= 0x%x\n", + cl_ntoh32( p_ioc_info->profile.vend_id )) ); + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_PNP, + ("\tdev_id\t= 0x%x\n", + cl_ntoh32( p_ioc_info->profile.dev_id )) ); + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_PNP, + ("\tdev_ver\t= 0x%x\n", + cl_ntoh16( p_ioc_info->profile.dev_ver )) ); + + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_PNP, + ("\tsubsys_vend_id\t= 0x%x\n", + cl_ntoh32( p_ioc_info->profile.subsys_vend_id )) ); + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_PNP, + ("\tsubsys_id\t= 0x%x\n", + cl_ntoh32( p_ioc_info->profile.subsys_id )) ); + + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_PNP, + ("\tio_class\t= 0x%x\n", + cl_ntoh16( p_ioc_info->profile.io_class )) ); + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_PNP, + ("\tio_subclass\t= 0x%x\n", + cl_ntoh16( p_ioc_info->profile.io_subclass )) ); + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_PNP, + ("\tprotocol\t= 0x%x\n", + cl_ntoh16( p_ioc_info->profile.protocol )) ); + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_PNP, + ("\tprotocol_ver\t= 0x%x\n", + cl_ntoh16( p_ioc_info->profile.protocol_ver )) ); + + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_PNP, + ("\tsend_msg_depth\t= %d\n", + cl_ntoh16( p_ioc_info->profile.send_msg_depth )) ); + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_PNP, + ("\trdma_read_depth\t= %d\n", + p_ioc_info->profile.rdma_read_depth) ); + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_PNP, + ("\tsend_msg_size\t= %d\n", + cl_ntoh32( p_ioc_info->profile.send_msg_size )) ); + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_PNP, + ("\trdma_size\t = %d\n", + cl_ntoh32( p_ioc_info->profile.rdma_size )) ); + + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_PNP, + ("\tctrl_ops_cap\t= 0x%X\n", + p_ioc_info->profile.ctrl_ops_cap) ); + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_PNP, + ("\tnum_svc_entries\t= 0x%X\n", + p_ioc_info->profile.num_svc_entries) ); + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_PNP, + ("\tid_string\t= %s\n", + p_ioc_info->profile.id_string) ); +} + + +static boolean_t +__get_ioc_ifc( + IN srp_hba_t* const p_hba ) +{ + NTSTATUS status; + ib_al_ifc_data_t data; + IO_STACK_LOCATION io_stack; + + SRP_ENTER( SRP_DBG_PNP ); + + /* Query for our interface. */ + data.size = sizeof(ioc_ifc_data_t); + data.version = IOC_INTERFACE_DATA_VERSION; + data.type = &GUID_IOC_INTERFACE_DATA; + data.p_data = &p_hba->info; + + io_stack.MinorFunction = IRP_MN_QUERY_INTERFACE; + io_stack.Parameters.QueryInterface.Version = AL_INTERFACE_VERSION; + io_stack.Parameters.QueryInterface.Size = sizeof(ib_al_ifc_t); + io_stack.Parameters.QueryInterface.Interface = (INTERFACE*)&p_hba->ifc; + io_stack.Parameters.QueryInterface.InterfaceSpecificData = &data; + io_stack.Parameters.QueryInterface.InterfaceType = &GUID_IB_AL_INTERFACE; + + status = cl_fwd_query_ifc( gp_self_do, &io_stack ); + if( !NT_SUCCESS( status ) ) + { + SRP_PRINT_EXIT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("Query interface for IOU parameters returned %08x.\n", status) ); + return FALSE; + } + else + { + /* + * Dereference the interface now so that the bus driver doesn't fail a + * query remove IRP. We will always get unloaded before the bus driver + * since we're a child device. + */ + p_hba->ifc.wdm.InterfaceDereference( p_hba->ifc.wdm.Context ); + SRP_EXIT( SRP_DBG_PNP ); + return TRUE; + } +} + + +ib_api_status_t +srp_hba_create( + IN cl_obj_t* const p_drv_obj, + OUT srp_ext_t* const p_ext ) +{ + srp_hba_t *p_hba; + cl_status_t cl_status; + ib_api_status_t ib_status; + ib_pnp_req_t pnp_req; + uint32_t i; + + SRP_ENTER( SRP_DBG_PNP ); + + p_hba = (srp_hba_t*)cl_zalloc( sizeof(srp_hba_t) ); + if( !p_hba ) + { + SRP_PRINT_EXIT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("Failed to allocate srp_hba_t structure.\n") ); + return IB_INSUFFICIENT_MEMORY; + } + + cl_qlist_init( &p_hba->path_record_list ); + cl_spinlock_init( &p_hba->path_record_list_lock ); + + /* Store instance parameters. */ + p_hba->p_ext = p_ext; + p_hba->max_sg = 0xFFFFFFFF; + p_hba->max_srb_ext_sz = 0xFFFFFFFF; + + if( !__get_ioc_ifc( p_hba ) ) + { + SRP_PRINT_EXIT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("__get_ioc_ifc failed.\n") ); + return IB_ERROR; + } + + for ( i = 0; i < SRP_MAX_SERVICE_ENTRIES; i++ ) + { + p_hba->session_list[i] = NULL; + } + + cl_obj_construct( &p_hba->obj, SRP_OBJ_TYPE_HBA ); + cl_status = cl_obj_init( &p_hba->obj, CL_DESTROY_ASYNC, + __srp_destroying_hba, __srp_cleanup_hba, __srp_free_hba ); + if( cl_status != CL_SUCCESS ) + { + SRP_PRINT_EXIT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("cl_obj_init returned %#x\n", cl_status) ); + return IB_ERROR; + } + + ib_status = p_hba->ifc.open_al( &p_hba->h_al ); + if( ib_status != IB_SUCCESS ) + { + SRP_PRINT_EXIT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("ib_open_al returned %s\n", p_hba->ifc.get_err_str( ib_status )) ); + goto err; + } + + /* Register for IOC events */ + pnp_req.pfn_pnp_cb = __srp_pnp_cb; + pnp_req.pnp_class = IB_PNP_IOC | IB_PNP_FLAG_REG_SYNC; + pnp_req.pnp_context = p_hba; + /* Reference the HBA object before registering for PnP notifications. */ + cl_obj_ref( &p_hba->obj ); + + cl_obj_insert_rel( &p_hba->rel, p_drv_obj, &p_hba->obj ); + + ib_status = p_hba->ifc.reg_pnp( p_hba->h_al, &pnp_req, &p_hba->h_pnp ); + if( ib_status != IB_SUCCESS ) + { + SRP_PRINT_EXIT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("ib_reg_pnp returned %s\n", p_hba->ifc.get_err_str( ib_status )) ); + goto err; + } + ib_status = IB_ERROR; + for ( i = 0; i < p_hba->ioc_info.profile.num_svc_entries; i++ ) + { + if ( p_hba->session_list[i] != NULL ) + ib_status = IB_SUCCESS; + } + + if( ib_status != IB_SUCCESS ) + { + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("Session Connection Failure.\n") ); + +err: + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_DEBUG, + ("HBA Object ref_cnt = %d\n", p_hba->obj.ref_cnt) ); + cl_obj_destroy( &p_hba->obj ); + + return ib_status; + } + + /* + * Add the HBA to the driver object's child list. This will cause + * everything to clean up properly in case we miss an unload notification. + */ + p_ext->p_hba = p_hba; + + SRP_EXIT( SRP_DBG_PNP ); + return ib_status; +} + + +static void +__srp_destroying_hba( + IN cl_obj_t *p_obj ) +{ + srp_hba_t *p_hba; + + SRP_ENTER( SRP_DBG_PNP ); + + p_hba = PARENT_STRUCT( p_obj, srp_hba_t, obj ); + + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_DEBUG, + ("Before dereg pnp HBA Object ref_cnt = %d\n", p_hba->obj.ref_cnt) ); + + if( p_hba->h_pnp ) + { + p_hba->ifc.dereg_pnp( p_hba->h_pnp, cl_obj_deref ); + } + + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_DEBUG, + ("After dereg pnp HBA Object ref_cnt = %d\n", p_hba->obj.ref_cnt) ); + + SRP_EXIT( SRP_DBG_PNP ); +} + +static void +__srp_remove_path_records( + IN srp_hba_t *p_hba ) +{ + srp_path_record_t *p_srp_path_record; + + SRP_ENTER( SRP_DBG_PNP ); + + cl_spinlock_acquire( &p_hba->path_record_list_lock ); + p_srp_path_record = (srp_path_record_t *)cl_qlist_remove_head( &p_hba->path_record_list ); + + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_DEBUG, + ("Removing any remaining path records.\n") ); + + while ( p_srp_path_record != (srp_path_record_t *)cl_qlist_end( &p_hba->path_record_list ) ) + { + cl_free( p_srp_path_record ); + p_srp_path_record = (srp_path_record_t *)cl_qlist_remove_head( &p_hba->path_record_list ); + } + + cl_spinlock_release( &p_hba->path_record_list_lock ); + + SRP_EXIT( SRP_DBG_PNP ); +} + +static void +__srp_cleanup_hba( + IN cl_obj_t *p_obj ) +{ + srp_hba_t *p_hba; + + SRP_ENTER( SRP_DBG_PNP ); + + p_hba = PARENT_STRUCT( p_obj, srp_hba_t, obj ); + + if( p_hba->h_al ) + p_hba->ifc.close_al( p_hba->h_al ); + + __srp_remove_path_records( p_hba ); + + cl_spinlock_destroy( &p_hba->path_record_list_lock ); + + if ( p_hba->p_svc_entries ) + cl_free( p_hba->p_svc_entries ); + + SRP_EXIT( SRP_DBG_PNP ); +} + + +static void +__srp_free_hba( + IN cl_obj_t *p_obj ) +{ + srp_hba_t *p_hba; + + SRP_ENTER( SRP_DBG_PNP ); + + p_hba = PARENT_STRUCT( p_obj, srp_hba_t, obj ); + + cl_obj_deinit( p_obj ); + cl_free( p_hba ); + + SRP_EXIT( SRP_DBG_PNP ); +} + +static BOOLEAN +__srp_validate_ioc( + IN ib_pnp_ioc_rec_t *p_ioc_rec ) +{ + SRP_ENTER( SRP_DBG_PNP ); + + // Is this really an SRP device? + if ( ( p_ioc_rec->info.profile.io_class != SRP_IO_CLASS && + p_ioc_rec->info.profile.io_class != SRP_IO_CLASS_R10 ) || + p_ioc_rec->info.profile.io_subclass != SRP_IO_SUBCLASS ) + { + SRP_PRINT_EXIT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("Not an SRP CLASS(0x%x)/SUBCLASS(0x%x).\n", + cl_ntoh16( p_ioc_rec->info.profile.io_class ), + cl_ntoh16( p_ioc_rec->info.profile.io_subclass )) ); + return FALSE; + } + + // Does it have the required features? + if ( cl_ntoh16( p_ioc_rec->info.profile.protocol ) != SRP_PROTOCOL || + cl_ntoh16( p_ioc_rec->info.profile.protocol_ver ) != SRP_PROTOCOL_VER || + !(p_ioc_rec->info.profile.ctrl_ops_cap & CTRL_OPS_CAP_ST) || + !(p_ioc_rec->info.profile.ctrl_ops_cap & CTRL_OPS_CAP_SF) || + !(p_ioc_rec->info.profile.ctrl_ops_cap & CTRL_OPS_CAP_RF) || + !(p_ioc_rec->info.profile.ctrl_ops_cap & CTRL_OPS_CAP_WF) ) + { + SRP_PRINT_EXIT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("Not an SRP PROTOCOL/PROTOCOL_VER.\n") ); + return FALSE; + } + + // Can it handle our IO requirements? + if ( cl_ntoh32( p_ioc_rec->info.profile.send_msg_size ) < SRP_MIN_TGT_TO_INI_IU || + cl_ntoh16( p_ioc_rec->info.profile.send_msg_depth ) == 0 || + cl_ntoh32( p_ioc_rec->info.profile.rdma_size ) < SRP_MIN_TGT_TO_INI_DMA ) + { + SRP_PRINT_EXIT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("Device Not Capable.\n") ); + return FALSE; + } + + SRP_EXIT( SRP_DBG_PNP ); + + return TRUE; +} + +static BOOLEAN +__srp_path_rec_equal( + IN const ib_path_rec_t *p_path_rec_1, + IN const ib_path_rec_t *p_path_rec_2, + IN BOOLEAN check_num_path, + IN BOOLEAN check_preference ) +{ + SRP_ENTER( SRP_DBG_PNP ); + + if ( p_path_rec_1->dgid.unicast.prefix != p_path_rec_2->dgid.unicast.prefix ) + return ( FALSE ); + + if ( p_path_rec_1->dgid.unicast.interface_id != p_path_rec_2->dgid.unicast.interface_id ) + return ( FALSE ); + + if ( p_path_rec_1->sgid.unicast.prefix != p_path_rec_2->sgid.unicast.prefix ) + return ( FALSE ); + + if ( p_path_rec_1->sgid.unicast.interface_id != p_path_rec_2->sgid.unicast.interface_id ) + return ( FALSE ); + + if ( p_path_rec_1->dlid != p_path_rec_2->dlid ) + return ( FALSE ); + + if ( p_path_rec_1->slid != p_path_rec_2->slid ) + return ( FALSE ); + + if ( p_path_rec_1->hop_flow_raw != p_path_rec_2->hop_flow_raw ) + { + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_DEBUG, + ("hop_flow_raw.val does not match.\n") ); + return ( FALSE ); + } + + if ( p_path_rec_1->tclass != p_path_rec_2->tclass ) + { + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_DEBUG, + ("tclass does not match.\n") ); + return ( FALSE ); + } + + if ( p_path_rec_1->num_path != p_path_rec_2->num_path ) + { + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_DEBUG, + ("num_path does not match.\n") ); + if ( check_num_path == TRUE ) + { + return ( FALSE ); + } + } + + if ( p_path_rec_1->pkey != p_path_rec_2->pkey ) + { + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_DEBUG, + ("pkey does not match.\n") ); + return ( FALSE ); + } + + if ( ib_path_rec_sl(p_path_rec_1) != ib_path_rec_sl(p_path_rec_2) ) + { + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_DEBUG, + ("sl does not match.\n") ); + return ( FALSE ); + } + + if ( p_path_rec_1->mtu != p_path_rec_2->mtu ) + { + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_DEBUG, + ("mtu does not match.\n") ); + return ( FALSE ); + } + + if ( p_path_rec_1->rate != p_path_rec_2->rate ) + { + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_DEBUG, + ("rate does not match.\n") ); + return ( FALSE ); + } + + if ( p_path_rec_1->pkt_life != p_path_rec_2->pkt_life ) + { + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_DEBUG, + ("pkt_life does not match.\n") ); + return ( FALSE ); + } + + if ( p_path_rec_1->preference != p_path_rec_2->preference ) + { + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_DEBUG, + ("preference does not match.\n") ); + if ( check_preference == TRUE ) + { + return ( FALSE ); + } + } + +#if defined( _DEBUG_ ) + + if ( cl_memcmp( p_path_rec_1, p_path_rec_2, sizeof( ib_path_rec_t ) ) != 0 ) + { + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_DEBUG, + ("p_path_rec_1 does not match p_path_rec_2.\n") ); + } + else + { + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_DEBUG, + ("p_path_rec_1 matches p_path_rec_2.\n") ); + } + +#endif + + SRP_EXIT( SRP_DBG_PNP ); + + return ( TRUE ); +} + +static +srp_path_record_t* +__srp_find_path( + IN srp_hba_t *p_hba, + IN const ib_path_rec_t *p_path_rec, + IN BOOLEAN check_num_path, + IN BOOLEAN check_preference ) +{ + srp_path_record_t *p_srp_path_record; + + SRP_ENTER( SRP_DBG_PNP ); + + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_PNP, + ("Finding path record (slid:0x%x dlid:0x%x) for %s.\n", + cl_ntoh16(p_path_rec->slid), + cl_ntoh16(p_path_rec->dlid), + p_hba->ioc_info.profile.id_string) ); + + cl_spinlock_acquire( &p_hba->path_record_list_lock ); + + p_srp_path_record = (srp_path_record_t *)cl_qlist_head( &p_hba->path_record_list ); + + while ( p_srp_path_record != (srp_path_record_t *)cl_qlist_end( &p_hba->path_record_list ) ) + { + if ( __srp_path_rec_equal( (const ib_path_rec_t *)&p_srp_path_record->path_rec, + p_path_rec, + check_num_path, + check_preference ) == TRUE ) + { + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_PNP, + ("Found path record (slid:0x%x dlid:0x%x) for %s.\n", + cl_ntoh16(p_path_rec->slid), + cl_ntoh16(p_path_rec->dlid), + p_hba->ioc_info.profile.id_string) ); + break; + } + + p_srp_path_record = (srp_path_record_t *)cl_qlist_next( &p_srp_path_record->list_item ); + } + + if ( p_srp_path_record == (srp_path_record_t *)cl_qlist_end( &p_hba->path_record_list ) ) + { + p_srp_path_record = NULL; + } + + cl_spinlock_release( &p_hba->path_record_list_lock ); + + SRP_EXIT( SRP_DBG_PNP ); + + return p_srp_path_record; +} + +static +srp_path_record_t* +__srp_remove_path( + IN srp_hba_t *p_hba, + IN const ib_path_rec_t *p_path_rec ) +{ + srp_path_record_t *p_srp_path_record; + + SRP_ENTER( SRP_DBG_PNP ); + + p_srp_path_record = __srp_find_path( p_hba, p_path_rec, TRUE, TRUE ); + if ( p_srp_path_record != NULL ) + { + cl_spinlock_acquire( &p_hba->path_record_list_lock ); + + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_PNP, + ("Removing path record (slid:0x%x dlid:0x%x) for %s.\n", + cl_ntoh16(p_path_rec->slid), + cl_ntoh16(p_path_rec->dlid), + p_hba->ioc_info.profile.id_string) ); + + cl_qlist_remove_item( &p_hba->path_record_list, &p_srp_path_record->list_item ); + + cl_spinlock_release( &p_hba->path_record_list_lock ); + } + + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_PNP, + ("Current Path count for %s = %d \n", + p_hba->ioc_info.profile.id_string, + (int)cl_qlist_count( &p_hba->path_record_list )) ); + + SRP_EXIT( SRP_DBG_PNP ); + + return p_srp_path_record; +} + +static +srp_path_record_t* +__srp_add_path( + IN srp_hba_t *p_hba, + IN const ib_path_rec_t *p_path_rec ) +{ + srp_path_record_t *p_srp_path_record; + + SRP_ENTER( SRP_DBG_PNP ); + + p_srp_path_record = __srp_find_path( p_hba, p_path_rec, FALSE, FALSE ); + if ( p_srp_path_record != NULL ) + { + cl_spinlock_acquire( &p_hba->path_record_list_lock ); + p_srp_path_record->path_rec = *p_path_rec; + cl_spinlock_release( &p_hba->path_record_list_lock ); + + SRP_PRINT( TRACE_LEVEL_WARNING, SRP_DBG_PNP, + ("Discarding/Updating duplicate path record (slid:0x%x dlid:0x%x) for %s.\n", + cl_ntoh16(p_path_rec->slid), + cl_ntoh16(p_path_rec->dlid), + p_hba->ioc_info.profile.id_string) ); + + goto exit; + } + + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_PNP, + ("Adding path record (slid:0x%x dlid:0x%x) for %s.\n", + cl_ntoh16(p_path_rec->slid), + cl_ntoh16(p_path_rec->dlid), + p_hba->ioc_info.profile.id_string) ); + + + p_srp_path_record = cl_zalloc( sizeof( srp_path_record_t ) ); + if ( p_srp_path_record == NULL ) + { + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("Insufficient Memory.\n") ); + } + else + { + p_srp_path_record->path_rec = *p_path_rec; + + cl_spinlock_acquire( &p_hba->path_record_list_lock ); + cl_qlist_insert_tail( &p_hba->path_record_list, &p_srp_path_record->list_item ); + cl_spinlock_release( &p_hba->path_record_list_lock ); + } + + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_PNP, + ("Current Path count for %s = %d \n", + p_hba->ioc_info.profile.id_string, + (int)cl_qlist_count( &p_hba->path_record_list )) ); + +exit: + SRP_EXIT( SRP_DBG_PNP ); + + return p_srp_path_record; +} + +static ib_api_status_t +__srp_connect_sessions( + IN OUT srp_hba_t *p_hba ) +{ + uint32_t i; + srp_session_t *p_session; + ib_api_status_t status = IB_ERROR; + BOOLEAN any_ioc_connected = FALSE; + + SRP_ENTER( SRP_DBG_PNP ); + + /* Create the session(s). */ + for ( i = 0; i < p_hba->ioc_info.profile.num_svc_entries; i++ ) + { + int retry_count = 0; + + do{ + retry_count++; + + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_PNP, + ("Creating New Session For Service Entry Index %d.\n", i )); + + p_session = srp_new_session( + p_hba, + &p_hba->p_svc_entries[i], + &p_hba->p_srp_path_record->path_rec, + &status ); + if( p_session == NULL ) + { + status = IB_INSUFFICIENT_MEMORY; + break; + } + + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_PNP, + ("New Session For Service Entry Index %d Created.\n", i )); + + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_PNP, + ("Attempting to connect %s. Svc Idx %d; Connection Attempt Count = %d.\n", + p_hba->ioc_info.profile.id_string, i, + retry_count) ); + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_PNP, + ("Logging Into Session.\n")); + status = srp_session_login( p_session ); + if ( status == IB_SUCCESS ) + { + any_ioc_connected = TRUE; + + srp_session_adjust_params( p_session ); + + cl_obj_lock( &p_hba->obj ); + p_session->target_id = (UCHAR)i; + p_hba->session_list[i] = p_session; + cl_obj_unlock( &p_hba->obj ); + + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_PNP, + ("Session Login Issued Successfully.\n")); + } + else + { + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_PNP, + ("Session Login for Service Idx %d Failure Status = %d.\n", i, status)); + cl_obj_destroy( &p_session->obj ); + } + + } while ( (status != IB_SUCCESS) && (retry_count < 3) ); + + } + + if ( any_ioc_connected == TRUE ) + { + status = IB_SUCCESS; + for( i = 0; i < p_hba->ioc_info.profile.num_svc_entries; i++ ) + { + p_session = p_hba->session_list[i]; + + if( p_session != NULL && + p_session->connection.state == SRP_CONNECTED && + p_hba->session_paused[i] == TRUE ) + { + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_PNP, + ("Resuming Adapter Session %d for %s.\n", i, + p_hba->ioc_info.profile.id_string) ); + + p_hba->session_paused[i] = FALSE; + StorPortDeviceReady( p_hba->p_ext, SP_UNTAGGED, (UCHAR)i, SP_UNTAGGED ); + } + } + } + + SRP_EXIT( SRP_DBG_PNP ); + + return status; +} + +void +srp_disconnect_sessions( + IN srp_hba_t *p_hba ) +{ + uint32_t i; + srp_session_t *p_session; + + SRP_ENTER( SRP_DBG_PNP ); + + cl_obj_lock( &p_hba->obj ); + + for ( i = 0; i < p_hba->ioc_info.profile.num_svc_entries; i++ ) + { + if ( p_hba->session_list[i] != NULL ) + { + p_session = p_hba->session_list[i]; + p_hba->session_list[i] = NULL; + p_session->connection.state = SRP_CONNECT_FAILURE; + srp_session_failed( p_session ); + } + } + + cl_obj_unlock( &p_hba->obj ); + + SRP_EXIT( SRP_DBG_PNP ); +} + +static ib_api_status_t +__srp_connect_path( + IN srp_hba_t *p_hba ) +{ + ib_api_status_t status = IB_ERROR; + srp_path_record_t *p_srp_path_record; + + SRP_ENTER( SRP_DBG_PNP ); + + while ( g_srp_system_shutdown == FALSE ) + { + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_PNP, + ("Searching for path to %s.\n", + p_hba->ioc_info.profile.id_string) ); + + cl_spinlock_acquire( &p_hba->path_record_list_lock ); + p_srp_path_record = (srp_path_record_t *)cl_qlist_head( &p_hba->path_record_list ); + cl_spinlock_release( &p_hba->path_record_list_lock ); + if ( p_srp_path_record == (srp_path_record_t *)cl_qlist_end( &p_hba->path_record_list ) ) + { + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_PNP, + ("No paths to %s found.\n", + p_hba->ioc_info.profile.id_string) ); + break; + } + + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_PNP, + ("Connecting path to %s.\n", + p_hba->ioc_info.profile.id_string) ); + + p_hba->p_srp_path_record = p_srp_path_record; + status = __srp_connect_sessions( p_hba ); + if ( status == IB_SUCCESS ) + { + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_PNP, + ("Path to %s has connected.\n", + p_hba->ioc_info.profile.id_string) ); + break; + } + + p_hba->p_srp_path_record = NULL; + cl_spinlock_acquire( &p_hba->path_record_list_lock ); + cl_qlist_remove_item( &p_hba->path_record_list, &p_srp_path_record->list_item ); + cl_spinlock_release( &p_hba->path_record_list_lock ); + cl_free( p_srp_path_record ); + } + + SRP_EXIT( SRP_DBG_PNP ); + + return status; +} + +static ib_api_status_t +__srp_pnp_cb( + IN ib_pnp_rec_t *p_pnp_rec ) +{ + ib_api_status_t status = IB_SUCCESS; + ib_pnp_ioc_rec_t *p_ioc_rec; + ib_pnp_ioc_path_rec_t *p_ioc_path; + srp_hba_t *p_hba; + srp_path_record_t *p_srp_path_record; + + SRP_ENTER( SRP_DBG_PNP ); + + p_hba = (srp_hba_t*)p_pnp_rec->pnp_context; + p_ioc_rec = (ib_pnp_ioc_rec_t*)p_pnp_rec; + p_ioc_path = (ib_pnp_ioc_path_rec_t*)p_pnp_rec; + + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_PNP, + ("p_pnp_rec->pnp_event = 0x%x (%s)\n", + p_pnp_rec->pnp_event, ib_get_pnp_event_str( p_pnp_rec->pnp_event )) ); + + + switch( p_pnp_rec->pnp_event ) + { + case IB_PNP_IOC_ADD: + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_PNP, + ("IB_PNP_IOC_ADD for %s.\n", + p_ioc_rec->info.profile.id_string) ); + + __srp_dump_ioc_info( &p_ioc_rec->info ); + + /* + * Trap our CA GUID so we filter path notifications + * for our bound CA only. + */ + if( p_ioc_rec->ca_guid != p_hba->info.ca_guid ) + { + SRP_PRINT_EXIT( TRACE_LEVEL_WARNING, SRP_DBG_PNP, + ("Ignoring CA GUID.\n") ); + status = IB_INVALID_GUID; + break; + } + + /* Trap our IOC GUID so we can get path notification events. */ + if( p_ioc_rec->info.profile.ioc_guid != p_hba->info.guid ) + { + SRP_PRINT_EXIT( TRACE_LEVEL_WARNING, SRP_DBG_PNP, + ("Ignoring GUID.\n") ); + status = IB_INVALID_GUID; + break; + } + + if ( __srp_validate_ioc( p_ioc_rec ) == FALSE ) + { + status = IB_INVALID_GUID; + break; + } + + p_hba->ioc_info = p_ioc_rec->info; + p_hba->p_svc_entries = cl_zalloc( sizeof(ib_svc_entry_t) * p_hba->ioc_info.profile.num_svc_entries ); + if ( p_hba->p_svc_entries == NULL ) + { + SRP_PRINT_EXIT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("Insufficient Memory.\n") ); + status = IB_INSUFFICIENT_MEMORY; + break; + } + + cl_memcpy ( p_hba->p_svc_entries, + p_ioc_rec->svc_entry_array, + sizeof(ib_svc_entry_t) * p_hba->ioc_info.profile.num_svc_entries); + + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_PNP, + ("Found %d Service Entries.\n", + p_hba->ioc_info.profile.num_svc_entries)); + break; + + case IB_PNP_IOC_REMOVE: + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_PNP, + ("IB_PNP_IOC_REMOVE for %s.\n", + p_hba->ioc_info.profile.id_string) ); + + CL_ASSERT( p_pnp_rec->guid == p_hba->info.guid ); + + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_PNP, + ("Hey!!! Our IOC went away.\n") ); + + if( !p_hba->adapter_stopped ) + p_hba->adapter_stopped = TRUE; + + srp_disconnect_sessions( p_hba ); + __srp_remove_path_records( p_hba ); + + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_PNP, + ("IB_PNP_IOC_REMOVE HBA Object ref_cnt = %d\n", p_hba->obj.ref_cnt ) ); + + break; + + case IB_PNP_IOC_PATH_ADD: + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_PNP, + ("IB_PNP_IOC_PATH_ADD (slid:0x%x dlid:0x%x) for %s.\n", + cl_ntoh16(p_ioc_path->path.slid), + cl_ntoh16(p_ioc_path->path.dlid), + p_hba->ioc_info.profile.id_string)); + + p_srp_path_record = __srp_add_path( p_hba, &p_ioc_path->path ); + if ( p_srp_path_record == NULL ) + { + status = IB_INSUFFICIENT_MEMORY; + break; + } + + if ( p_hba->p_srp_path_record == NULL ) + { + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_PNP, + ("Connecting new path to %s.\n", + p_hba->ioc_info.profile.id_string) ); + status = __srp_connect_path( p_hba ); + } + + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_PNP, + (" IOC_PATH ADD HBA Object ref_cnt = %d\n", p_hba->obj.ref_cnt ) ); + break; + + case IB_PNP_IOC_PATH_REMOVE: + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_PNP, + ("IB_PNP_IOC_PATH_REMOVE (slid:%x dlid:%x) for %s.\n", + cl_ntoh16(p_ioc_path->path.slid), + cl_ntoh16(p_ioc_path->path.dlid), + p_hba->ioc_info.profile.id_string)); + + p_srp_path_record = __srp_remove_path( p_hba, &p_ioc_path->path ); + if ( p_srp_path_record != NULL ) + { + if ( p_srp_path_record == p_hba->p_srp_path_record ) + { + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_PNP, + ("Current path to %s has been lost.\n", + p_hba->ioc_info.profile.id_string) ); + + if ( g_srp_system_shutdown == FALSE ) + { + srp_disconnect_sessions( p_hba ); + } + } + + cl_free( p_srp_path_record ); + } + break; + + default: + CL_ASSERT( p_pnp_rec->pnp_event == IB_PNP_IOC_ADD || + p_pnp_rec->pnp_event == IB_PNP_IOC_REMOVE || + p_pnp_rec->pnp_event == IB_PNP_IOC_PATH_ADD || + p_pnp_rec->pnp_event == IB_PNP_IOC_PATH_REMOVE ); + break; + } + + SRP_EXIT( SRP_DBG_PNP ); + return status; +} diff --git a/branches/WOF2-3/ulp/srp/kernel/srp_hba.h b/branches/WOF2-3/ulp/srp/kernel/srp_hba.h new file mode 100644 index 00000000..86d3238b --- /dev/null +++ b/branches/WOF2-3/ulp/srp/kernel/srp_hba.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + +#ifndef _SRP_HBA_H_ +#define _SRP_HBA_H_ + +#include +#include +#include +#include + +#define SRP_MAX_SERVICE_ENTRIES 255 + +typedef struct _srp_session *p_srp_session_t; + + +#pragma warning(disable:4324) +typedef struct _srp_path_record +{ + cl_list_item_t list_item; + ib_path_rec_t path_rec; + +} srp_path_record_t; +#pragma warning(default:4324) + + +typedef struct _srp_hba +{ + cl_obj_t obj; + cl_obj_rel_t rel; + + /* The extension is needed for StorPort calls. */ + struct _srp_ext *p_ext; + + ib_al_handle_t h_al; + ib_pnp_handle_t h_pnp; + + ib_al_ifc_t ifc; + ioc_ifc_data_t info; + + ib_ioc_info_t ioc_info; + ib_svc_entry_t *p_svc_entries; + + srp_path_record_t *p_srp_path_record; + cl_qlist_t path_record_list; + cl_spinlock_t path_record_list_lock; + BOOLEAN adapter_stopped; + + uint32_t max_sg; + uint32_t max_srb_ext_sz; + /* List of sessions indexed by target id */ + p_srp_session_t session_list[SRP_MAX_SERVICE_ENTRIES]; + BOOLEAN session_paused[SRP_MAX_SERVICE_ENTRIES]; +} srp_hba_t; + + +/* Pointer to the PDO for an instance being initialized. */ +DEVICE_OBJECT *gp_self_do; + + +ib_api_status_t +srp_hba_create( + IN cl_obj_t* const p_drv_obj, + OUT struct _srp_ext* const p_ext ); + +void +srp_disconnect_sessions( + IN srp_hba_t *p_hba ); + +#endif /* _SRP_HBA_H_ */ diff --git a/branches/WOF2-3/ulp/srp/kernel/srp_hca.c b/branches/WOF2-3/ulp/srp/kernel/srp_hca.c new file mode 100644 index 00000000..14f0cf5d --- /dev/null +++ b/branches/WOF2-3/ulp/srp/kernel/srp_hca.c @@ -0,0 +1,263 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include "srp_debug.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "srp_hca.tmh" +#endif +#include "srp_event.h" +#include "srp_hca.h" +#include "srp_session.h" + +/* Amount of physical memory to register. */ +#define MEM_REG_SIZE 0xFFFFFFFFFFFFFFFF + + +/* srp_open_ca */ +/*! +Open the channel adapter associated with the SRP initiator +Allocates a protection domain and +Registers all of physical memory + +@param p_hca - pointer to the hca structure +@param p_context - context pointer passed back to callback functions + +@return - result of operation +*/ +ib_api_status_t +srp_open_ca( + IN OUT srp_hca_t *p_hca, + IN void *p_context ) +{ + ib_api_status_t status; + ib_phys_create_t phys_create; + ib_phys_range_t phys_range; + mlnx_fmr_pool_create_t fmr_pool_create; + + SRP_ENTER( SRP_DBG_PNP ); + + status = p_hca->p_hba->ifc.open_ca( p_hca->p_hba->h_al, + p_hca->p_hba->info.ca_guid, srp_async_event_handler_cb, + p_context, &p_hca->h_ca ); + if ( status != IB_SUCCESS ) + { + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("Failed to open Channel Adapter. Status = %d\n", status) ); + goto exit; + } + + status = p_hca->p_hba->ifc.alloc_pd( p_hca->h_ca, + IB_PDT_NORMAL, + p_context, + &p_hca->h_pd ); + if ( status != IB_SUCCESS ) + { + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("Failed to create Protection Domain. Status = %d\n", status) ); + goto exit; + } + + /* Register all of physical memory */ + phys_create.length = MEM_REG_SIZE; + phys_create.num_ranges = 1; + phys_create.range_array = &phys_range; + phys_create.buf_offset = 0; + phys_create.hca_page_size = PAGE_SIZE; + phys_create.access_ctrl = IB_AC_LOCAL_WRITE | IB_AC_RDMA_READ | IB_AC_RDMA_WRITE | IB_AC_MW_BIND; + + phys_range.base_addr = 0; + phys_range.size = MEM_REG_SIZE; + + p_hca->vaddr = 0; + + + status = p_hca->p_hba->ifc.reg_phys( p_hca->h_pd, + &phys_create, + &p_hca->vaddr, + &p_hca->lkey, + &p_hca->rkey, + &p_hca->h_mr ); + + if( status != IB_SUCCESS ) + { + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("Physical Memory Registration Failure. Status = %d\n", status) ); + goto exit; + } + + if ( g_srp_mode_flags & SRP_MODE_NO_FMR_POOL ) + { + SRP_EXIT( SRP_DBG_PNP ); + return IB_SUCCESS; + } + + fmr_pool_create.max_pages_per_fmr = SRP_MAX_SG_IN_INDIRECT_DATA_BUFFER; + fmr_pool_create.page_size = 12; + fmr_pool_create.access_ctrl = IB_AC_LOCAL_WRITE | IB_AC_RDMA_READ | IB_AC_RDMA_WRITE; + fmr_pool_create.pool_size = 100; + fmr_pool_create.dirty_watermark = 2; + fmr_pool_create.flush_function = NULL; + fmr_pool_create.flush_arg = NULL; + fmr_pool_create.cache = TRUE; + + status = p_hca->p_hba->ifc.create_mlnx_fmr_pool(p_hca->h_pd, &fmr_pool_create, &p_hca->h_fmr_pool); + + if( status != IB_SUCCESS ) + { + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("FMR pool creation Failure. Status = %d\n", status) ); + goto exit; + } + + p_hca->fmr_page_size = 1<< fmr_pool_create.page_size; + p_hca->fmr_page_shift = (uint32_t)fmr_pool_create.page_size; + + SRP_EXIT( SRP_DBG_PNP ); + return IB_SUCCESS; +exit: + srp_close_ca( p_hca ); + + SRP_EXIT( SRP_DBG_PNP ); + return ( status ); +} + +/* srp_close_ca */ +/*! +Closes the channel adapter + +@param p_hca - pointer to the hca structure + +@return - none +*/ +void +srp_close_ca( + IN OUT srp_hca_t *p_hca ) +{ + SRP_ENTER( SRP_DBG_PNP ); + + if( p_hca->h_ca ) + { + p_hca->p_hba->ifc.close_ca( p_hca->h_ca, ib_sync_destroy ); + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_DEBUG, + ("Closed Channel Adapter.\n") ); + } + + cl_memclr( p_hca, sizeof( *p_hca ) ); + + SRP_EXIT( SRP_DBG_PNP ); +} + +/* srp_get_responder_resources */ +/*! +Queries the channel adapter for the number of +outstanding atomic/rdma operations it supports + +@param p_hca - pointer to the hca structure +@param p_responder_resources - value to hold responder resource count + +@return - result of operation +*/ +ib_api_status_t +srp_get_responder_resources( + IN srp_hca_t *p_hca, + OUT uint8_t *p_responder_resources ) +{ + ib_api_status_t status; + ib_ca_attr_t *p_ca_attr = NULL; + uint32_t ca_attr_size = 0; + + SRP_ENTER( SRP_DBG_PNP ); + + status = p_hca->p_hba->ifc.query_ca( p_hca->h_ca, NULL, &ca_attr_size ); + if ( status != IB_INSUFFICIENT_MEMORY ) + { + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("Cannot Query Channel Adapter. Status = %d\n", status) ); + goto exit; + } + + p_ca_attr = cl_zalloc( ca_attr_size ); + if ( p_ca_attr == NULL ) + { + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("Memory Allocation Error: Cannot Create CA Attributes.\n") ); + goto exit; + } + + status = p_hca->p_hba->ifc.query_ca( p_hca->h_ca, p_ca_attr, &ca_attr_size ); + if ( status != IB_SUCCESS ) + { + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("Cannot Query Channel Adapter. Status = %d\n", status) ); + } + else + { + *p_responder_resources = p_ca_attr->max_qp_resp_res; + } + + cl_free ( p_ca_attr ); + +exit: + SRP_EXIT( SRP_DBG_PNP ); + + return ( status ); +} + +/* srp_init_hca */ +/*! +Initializes hca resources + +@param p_hca - pointer to the hca structure + +@return - result of initialization +*/ +ib_api_status_t +srp_init_hca( + IN OUT srp_hca_t *p_hca, + IN srp_hba_t *p_hba ) +{ + SRP_ENTER( SRP_DBG_PNP ); + + cl_memclr( p_hca, sizeof( *p_hca ) ); + + p_hca->p_hba = p_hba; + + SRP_EXIT( SRP_DBG_PNP ); + + return ( IB_SUCCESS ); +} + + + diff --git a/branches/WOF2-3/ulp/srp/kernel/srp_hca.h b/branches/WOF2-3/ulp/srp/kernel/srp_hca.h new file mode 100644 index 00000000..897a3e9d --- /dev/null +++ b/branches/WOF2-3/ulp/srp/kernel/srp_hca.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + +#ifndef _SRP_HCA_H_ +#define _SRP_HCA_H_ + + +#include +#include "srp_hba.h" + +typedef struct _srp_hca +{ + srp_hba_t *p_hba; + + ib_ca_handle_t h_ca; + ib_pd_handle_t h_pd; + ib_mr_handle_t h_mr; + mlnx_fmr_pool_handle_t h_fmr_pool; + uint32_t fmr_page_size; + uint32_t fmr_page_shift; + uint64_t vaddr; + net32_t lkey; + net32_t rkey; + +} srp_hca_t; + +ib_api_status_t +srp_open_ca( + IN OUT srp_hca_t *p_hca, + IN void *p_context ); + +void +srp_close_ca( + IN OUT srp_hca_t *p_hca ); + +ib_api_status_t +srp_get_responder_resources( + IN srp_hca_t *p_hca, + OUT uint8_t *p_responder_resources ); + +ib_api_status_t +srp_init_hca( + IN OUT srp_hca_t *p_hca, + IN srp_hba_t *p_hba ); + +#endif /* _SRP_HCA_H_ */ diff --git a/branches/WOF2-3/ulp/srp/kernel/srp_i_logout.h b/branches/WOF2-3/ulp/srp/kernel/srp_i_logout.h new file mode 100644 index 00000000..55c0188c --- /dev/null +++ b/branches/WOF2-3/ulp/srp/kernel/srp_i_logout.h @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#ifndef SRP_I_LOGOUT_H_INCLUDED +#define SRP_I_LOGOUT_H_INCLUDED + +#include "srp.h" +#include "srp_iu_buffer.h" +#include "srp_information_unit.h" + +/* set_srp_i_logout_tag */ +/*! +Sets the tag field of an initiator logout information unit + +@param p_information_unit - pointer to the IU structure +@param iu_tag - tag value of IU + +@return - none +*/ +static inline +void +set_srp_i_logout_tag( + IN OUT srp_i_logout_t *p_information_unit, + IN uint64_t iu_tag ) +{ + set_srp_information_unit_tag( ( srp_information_unit_t* ) p_information_unit, iu_tag ); +} + +/* init_srp_i_logout */ +/*! +Initializes the initiator logout IU to zeroes +and sets the IU type to Srp Initiator Logout +and sets the tag to the value supplied + +@param p_information_unit - pointer to the IU structure +@param iu_tag - tag value to be used for the req/rsp pair + +@return - none +*/ +static inline +void +init_srp_i_logout( + IN OUT srp_i_logout_t *p_information_unit, + IN uint64_t iu_tag ) +{ + init_srp_iu_buffer( ( srp_iu_buffer_t* ) p_information_unit, SRP_I_LOGOUT ) ; + set_srp_i_logout_tag( p_information_unit, iu_tag ); +} + +/* setup_srp_i_logout */ +/*! +Initializes and sets the Srp Initiator Logout IU to the values supplied + +@param p_information_unit - pointer to the IU structure +@param iu_tag - tag value to be used for the req/rsp pair + +@return - none +*/ +static inline +void +setup_srp_i_logout( + IN OUT srp_i_logout_t *p_information_unit, + IN uint64_t iu_tag ) +{ + init_srp_i_logout( p_information_unit, iu_tag ); +} + +/* get_srp_i_logout_tag */ +/*! +Returns the value of the tag field of an initiator logout + +@param p_information_unit - pointer to the IU structure + +@return - tag value +*/ +static inline +uint64_t +get_srp_i_logout_tag( + IN srp_i_logout_t *p_information_unit ) +{ + return( get_srp_information_unit_tag( ( srp_information_unit_t* ) p_information_unit ) ); +} + +/* get_srp_i_logout_length */ +/*! +Returns the size in bytes of the Srp Initiator Logout IU + +@param p_information_unit - pointer to the IU structure + +@return - tag value +*/ +static inline +uint32_t +get_srp_i_logout_length( + IN srp_i_logout_t *p_information_unit ) +{ + return( sizeof( *p_information_unit ) ); +} + +/* set_srp_i_logout_from_host_to_network */ +/*! +Swaps the IU fields from Host to Network ordering + +@param p_information_unit - pointer to the IU structure + +@return - none +*/ + +static inline +void +set_srp_i_logout_from_host_to_network( + IN OUT srp_i_logout_t *p_information_unit ) +{ + set_srp_information_unit_from_host_to_network( ( srp_information_unit_t* ) p_information_unit ); +} + +/* set_srp_i_logout_from_network_to_host */ +/*! +Swaps the IU fields from Network to Host ordering + +@param p_information_unit - pointer to the IU structure + +@return - none +*/ + +static inline +void +set_srp_i_logout_from_network_to_host( + IN OUT srp_i_logout_t *p_information_unit ) +{ + set_srp_i_logout_from_host_to_network ( p_information_unit ); +} + +#endif /* SRP_I_LOGOUT_H_INCLUDED */ diff --git a/branches/WOF2-3/ulp/srp/kernel/srp_information_unit.h b/branches/WOF2-3/ulp/srp/kernel/srp_information_unit.h new file mode 100644 index 00000000..6a6e5d67 --- /dev/null +++ b/branches/WOF2-3/ulp/srp/kernel/srp_information_unit.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#ifndef SRP_INFORMATION_UNIT_H_INCLUDED +#define SRP_INFORMATION_UNIT_H_INCLUDED + +#include "srp_iu_buffer.h" +#include + +/* set_srp_information_unit_tag */ +/*! +Set the Information Unit tag for the Srp buffer + +@param p_information_unit - pointer to the IU structure +@param iuTag - IU tag value +*/ +static inline +void +set_srp_information_unit_tag( + IN OUT srp_information_unit_t *p_information_unit, + uint64_t iu_tag ) +{ + p_information_unit->tag = iu_tag; +} + +/* get_srp_information_unit_tag */ +/*! +Returns the Information Unit tag for the Srp buffer + +@param p_information_unit - pointer to the IU structure + +@return - IU tag field value +*/ +static inline +uint64_t +get_srp_information_unit_tag( + IN srp_information_unit_t *p_information_unit ) +{ + return( p_information_unit->tag ); +} + +/* set_srp_information_unit_from_host_to_network */ +/*! +Swaps the tag field bytes from Host to Network ordering + +@param p_information_unit - pointer to the IU structure + +@return - NONE +*/ + +static inline +void +set_srp_information_unit_from_host_to_network( + IN OUT srp_information_unit_t *p_information_unit ) +{ + UNUSED_PARAM( p_information_unit ); +// p_information_unit->tag = cl_hton64( p_information_unit->tag ); +} + +/* set_srp_information_unit_from_network_to_host */ +/*! +Swaps the tag field bytes from Network To Host ordering + +@param p_information_unit - pointer to the IU structure + +@return - NONE +*/ + +static inline +void +set_srp_information_unit_from_network_to_host( + IN OUT srp_information_unit_t *p_information_unit ) +{ + set_srp_information_unit_from_host_to_network ( p_information_unit ); +} + +#endif /* SRP_INFORMATION_UNIT_H_INCLUDED */ diff --git a/branches/WOF2-3/ulp/srp/kernel/srp_iu_buffer.h b/branches/WOF2-3/ulp/srp/kernel/srp_iu_buffer.h new file mode 100644 index 00000000..5939e4b7 --- /dev/null +++ b/branches/WOF2-3/ulp/srp/kernel/srp_iu_buffer.h @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#ifndef SRP_IU_BUFFER_H_INCLUDED +#define SRP_IU_BUFFER_H_INCLUDED + +#include "srp.h" + +/* set_srp_iu_buffer_type */ +/*! +Set the Information Unit type for the Srp IU buffer + +@param p_buffer - pointer to the IU buffer +@param iu_type - IU structure type +*/ +static inline +void +set_srp_iu_buffer_type( + IN OUT srp_iu_buffer_t *p_buffer, + IN uint8_t iu_type ) +{ + p_buffer->information_unit.type = iu_type; +} + +/* init_srp_iu_buffer */ +/*! +Initialize the Srp IU buffer to 0 and set it's type + +@param p_buffer - pointer to the IU buffer +@param iu_type - IU structure type +*/ +static inline +void +init_srp_iu_buffer( + IN OUT srp_iu_buffer_t *p_buffer, + IN uint8_t iu_type ) +{ + size_t iu_size = 0; + + switch( iu_type ) + { + case SRP_RSP: + /* don't dirty the second cache line */ + iu_size = offsetof( srp_rsp_t, data_out_residual_count ); + break; + + case SRP_LOGIN_REQ: + iu_size = sizeof( srp_login_req_t ); + break; + + case SRP_TSK_MGMT: + iu_size = sizeof( srp_tsk_mgmt_t ); + break; + + case SRP_CMD: + iu_size = sizeof( srp_cmd_t ); + break; + + case SRP_I_LOGOUT: + iu_size = sizeof( srp_i_logout_t ); + break; + + case SRP_LOGIN_RSP: + iu_size = sizeof( srp_login_rsp_t ); + break; + + case SRP_LOGIN_REJ: + iu_size = sizeof( srp_login_rej_t ); + break; + + case SRP_T_LOGOUT: + iu_size = sizeof( srp_t_logout_t ); + break; + + case SRP_CRED_REQ: + iu_size = sizeof( srp_cred_req_t ); + break; + + case SRP_AER_REQ: + iu_size = sizeof( srp_aer_req_t ); + break; + + case SRP_CRED_RSP: + iu_size = sizeof( srp_cred_rsp_t ); + break; + + case SRP_AER_RSP: + iu_size = sizeof( srp_aer_rsp_t ); + break; + } + + memset( p_buffer, 0, iu_size ); + + set_srp_iu_buffer_type( p_buffer, iu_type ); +} + +/* get_srp_iu_buffer_type */ +/*! +Returns the Information Unit type for the Srp buffer + +@param p_buffer - pointer to the IU structure + +@return - IU type value +*/ +static inline +uint8_t +get_srp_iu_buffer_type( + IN srp_iu_buffer_t *p_buffer ) +{ + return( p_buffer->information_unit.type ); +} + +#endif /* SRP_IU_BUFFER_H_INCLUDED */ diff --git a/branches/WOF2-3/ulp/srp/kernel/srp_login_rej.h b/branches/WOF2-3/ulp/srp/kernel/srp_login_rej.h new file mode 100644 index 00000000..99b66653 --- /dev/null +++ b/branches/WOF2-3/ulp/srp/kernel/srp_login_rej.h @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#ifndef SRP_LOGIN_REJ_H_INCLUDED +#define SRP_LOGIN_REJ_H_INCLUDED + +#include "srp.h" +#include "srp_iu_buffer.h" +#include "srp_Information_unit.h" + +/* set_srp_login_reject_tag */ +/*! +Sets the tag field of a login reject information unit + +@param p_information_unit - pointer to the IU structure +@param iu_tag - tag value of IU + +@return - none +*/ +static inline +void +set_srp_login_reject_tag( + IN OUT srp_login_rej_t *p_information_unit, + IN uint64_t iu_tag ) +{ + set_srp_information_unit_tag( ( srp_information_unit_t* ) p_information_unit, iu_tag ); +} + +/* init_srp_login_reject */ +/*! +Initializes the login reject IU to zeroes +and sets the IU type to Srp Login Reject +and sets the tag to the value supplied + +@param p_information_unit - pointer to the IU structure +@param iu_tag - tag value to be used for the req/rsp pair + +@return - none +*/ +static inline +void +init_srp_login_reject( + IN OUT srp_login_rej_t *p_information_unit, + IN uint64_t iu_tag ) +{ + init_srp_iu_buffer( ( srp_iu_buffer_t* ) p_information_unit, SRP_LOGIN_REJ ) ; + set_srp_login_reject_tag( p_information_unit, iu_tag ) ; +} + +/* set_srp_login_reject_reason */ +/*! +Sets the reason for the rejection + +@param p_information_unit - pointer to the IU structure +@param reason - rejection reason code + +@return - none +*/ +static inline +void +set_srp_login_reject_reason( + IN OUT srp_login_rej_t *p_information_unit, + IN LOGIN_REJECT_CODE reason ) +{ + p_information_unit->reason = reason; +} + +/* set_srp_login_reject_supported_data_buffer_formats */ +/*! +Sets the flags indicating the type of data buffer descriptors +which are supported by the target on this channel + +@param p_information_unit - pointer to the IU structure +@param data_buffer_descriptor_formats - usage indicator values + +@return - none +*/ +static inline +void +set_srp_login_reject_supported_data_buffer_formats( + IN OUT srp_login_rej_t *p_information_unit, + IN DATA_BUFFER_DESCRIPTOR_FORMAT data_buffer_descriptor_formats ) +{ + p_information_unit->sup_buffer_fmts.flags = 0; + + if ( data_buffer_descriptor_formats & DBDF_DIRECT_DATA_BUFFER_DESCRIPTOR ) + { + p_information_unit->sup_buffer_fmts.flags |= DIRECT_DATA_BUFFER_DESCRIPTOR_REQUESTED; + } + + if ( data_buffer_descriptor_formats & DBDF_INDIRECT_DATA_BUFFER_DESCRIPTORS ) + { + p_information_unit->sup_buffer_fmts.flags |= INDIRECT_DATA_BUFFER_DESCRIPTOR_REQUESTED; + } +} + +/* setup_srp_login_reject */ +/*! +Initializes and sets the Srp Login Reject IU to the values supplied + +@param p_information_unit - pointer to the IU structure +@param iu_tag - tag value to be used for the req/rsp pair +@param reason - reason code for login rejection +@param data_buffer_descriptor_formats - usage indicator values + +@return - none +*/ +static inline +void +setup_srp_login_reject( + IN OUT srp_login_rej_t *p_information_unit, + IN uint64_t iu_tag, + IN LOGIN_REJECT_CODE reason, + IN DATA_BUFFER_DESCRIPTOR_FORMAT data_buffer_descriptor_formats ) +{ + init_srp_login_reject( p_information_unit, iu_tag ); + set_srp_login_reject_reason( p_information_unit, reason ); + set_srp_login_reject_supported_data_buffer_formats( p_information_unit, data_buffer_descriptor_formats ); +} + +/* get_srp_login_reject_tag */ +/*! +Returns the value of the tag field of a login reject + +@param p_information_unit - pointer to the IU structure + +@return - tag value +*/ +static inline +uint64_t +get_srp_login_reject_tag( + IN srp_login_rej_t *p_information_unit ) +{ + return( get_srp_information_unit_tag( ( srp_information_unit_t* ) p_information_unit ) ); +} + +/* get_srp_login_reject_reason */ +/*! +Returns the value of the reason code field of a login reject + +@param p_information_unit - pointer to the IU structure + +@return - reason code value +*/ +static inline +LOGIN_REJECT_CODE +get_srp_login_reject_reason( + IN srp_login_rej_t *p_information_unit ) +{ + return( ( LOGIN_REJECT_CODE ) p_information_unit->reason ); +} + +/* get_srp_login_reject_supported_data_buffer_formats */ +/*! +Returns the supported data buffer formats that can be used on the channel + +@param p_information_unit - pointer to the IU structure + +@return - supported data buffer formats settings +*/ +static inline +DATA_BUFFER_DESCRIPTOR_FORMAT +get_srp_login_reject_supported_data_buffer_formats( + IN srp_login_rej_t *p_information_unit ) +{ + switch ( p_information_unit->sup_buffer_fmts.flags & DATA_BUFFER_DESCRIPTOR_FORMAT_MASK ) + { + case DIRECT_DATA_BUFFER_DESCRIPTOR_REQUESTED: + return( DBDF_DIRECT_DATA_BUFFER_DESCRIPTOR ); + + case INDIRECT_DATA_BUFFER_DESCRIPTOR_REQUESTED: + return( DBDF_INDIRECT_DATA_BUFFER_DESCRIPTORS ); + + case DIRECT_DATA_BUFFER_DESCRIPTOR_REQUESTED | INDIRECT_DATA_BUFFER_DESCRIPTOR_REQUESTED: + return( ( DATA_BUFFER_DESCRIPTOR_FORMAT ) ( DBDF_DIRECT_DATA_BUFFER_DESCRIPTOR | DBDF_INDIRECT_DATA_BUFFER_DESCRIPTORS ) ); + + default: + return( DBDF_NO_DATA_BUFFER_DESCRIPTOR_PRESENT ); + } +} + +/* get_srp_login_reject_length */ +/*! +Returns the size in bytes of the Srp Login Reject IU + +@param p_information_unit - pointer to the IU structure + +@return - tag value +*/ +static inline +uint32_t +get_srp_login_reject_length( + IN srp_login_rej_t *p_information_unit ) +{ + return( sizeof( *p_information_unit ) ); +} + +/* set_srp_login_reject_from_host_to_network */ +/*! +Swaps the IU fields from Host to Network ordering + +@param p_information_unit - pointer to the IU structure + +@return - none +*/ + +static inline +void +set_srp_login_reject_from_host_to_network( + IN OUT srp_login_rej_t *p_information_unit ) +{ + set_srp_information_unit_from_host_to_network( ( srp_information_unit_t* ) p_information_unit ); + p_information_unit->reason = cl_hton32( p_information_unit->reason ); +} + +/* set_srp_login_reject_from_network_to_host */ +/*! +Swaps the IU fields from Network to Host ordering + +@param p_information_unit - pointer to the IU structure + +@return - none +*/ + +static inline +void +set_srp_login_reject_from_network_to_host( + IN OUT srp_login_rej_t *p_information_unit ) +{ + set_srp_login_reject_from_host_to_network ( p_information_unit ); +} + +#endif /* SRP_LOGIN_REJ_H_INCLUDED */ diff --git a/branches/WOF2-3/ulp/srp/kernel/srp_login_req.h b/branches/WOF2-3/ulp/srp/kernel/srp_login_req.h new file mode 100644 index 00000000..24487ba9 --- /dev/null +++ b/branches/WOF2-3/ulp/srp/kernel/srp_login_req.h @@ -0,0 +1,364 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#ifndef SRP_LOGIN_REQ_H_INCLUDED +#define SRP_LOGIN_REQ_H_INCLUDED + +#include "srp.h" +#include "srp_iu_buffer.h" +#include "srp_information_unit.h" +#include + +/* set_srp_login_request_tag */ +/*! +Sets the tag field of the login request IU to the supplied value + +@param p_information_unit - pointer to the IU structure +@param iu_tag - tag value to be used for the req/rsp pair + +@return - none +*/ +static inline +void +set_srp_login_request_tag( + IN OUT srp_login_req_t *p_information_unit, + IN uint64_t iu_tag ) +{ + set_srp_information_unit_tag( ( srp_information_unit_t* ) p_information_unit, iu_tag ); +} + +/* init_srp_login_request */ +/*! +Initializes the login request IU to zeroes +and sets the IU type to Srp Login Request +and set the tag to the value supplied + +@param p_information_unit - pointer to the IU structure +@param iu_tag - tag value to be used for the req/rsp pair + +@return - none +*/ +static inline +void +init_srp_login_request( + IN OUT srp_login_req_t *p_information_unit, + IN uint64_t iu_tag ) +{ + init_srp_iu_buffer( ( srp_iu_buffer_t* ) p_information_unit, SRP_LOGIN_REQ ) ; + set_srp_login_request_tag( p_information_unit, iu_tag ); +} + +/* set_srp_login_request_req_max_init_to_targ_iu */ +/*! +Sets the maximum sized IU to be sent on this channel from initiator to target + +@param p_information_unit - pointer to the IU structure +@param req_max_init_to_targ_iu - max initiator to target IU size (64 or greater) + +@return - none +*/ +static inline +void +set_srp_login_request_req_max_init_to_targ_iu( + IN OUT srp_login_req_t *p_information_unit, + IN uint32_t req_max_init_to_targ_iu ) +{ + p_information_unit->req_max_init_to_targ_iu = req_max_init_to_targ_iu; +} + +/* set_srp_login_request_required_data_buffer_formats */ +/*! +Sets the flags indicating whether or not the initiator will use +target support of direct/indirect data buffer descriptors on this channel + +@param p_information_unit - pointer to the IU structure +@param data_buffer_descriptor_formats - usage indicator values + +@return - none +*/ +static inline +void +set_srp_login_request_required_data_buffer_formats( + IN OUT srp_login_req_t *p_information_unit, + IN DATA_BUFFER_DESCRIPTOR_FORMAT data_buffer_descriptor_formats ) +{ + p_information_unit->req_buffer_fmts.flags = 0; + + if ( data_buffer_descriptor_formats & DBDF_DIRECT_DATA_BUFFER_DESCRIPTOR ) + { + p_information_unit->req_buffer_fmts.flags |= DIRECT_DATA_BUFFER_DESCRIPTOR_REQUESTED; + } + + if ( data_buffer_descriptor_formats & DBDF_INDIRECT_DATA_BUFFER_DESCRIPTORS ) + { + p_information_unit->req_buffer_fmts.flags |= INDIRECT_DATA_BUFFER_DESCRIPTOR_REQUESTED; + } +} + +/* set_srp_login_request_multi_channel_action */ +/*! +Sets the value indicating how existing RDMA channels associated with the +same I_T nexus specified by the Initiator Port Identifier and Target Port +Identifier fields are to be treated. They can either be terminated or allowed +to continue processing. + +@param p_information_unit - pointer to the IU structure +@param multi_channel_action - value indicating action to be applied to + existing RDMA channels + +@return - none +*/ +static inline +void +set_srp_login_request_multi_channel_action( + IN OUT srp_login_req_t *p_information_unit, + IN MULTI_CHANNEL_ACTION multi_channel_action ) +{ + p_information_unit->flags |= multi_channel_action; +} + +/* setSrpLoginRequestITNexus */ +/*! +Sets the I_T nexus value + +@param p_information_unit - pointer to the IU structure +@param p_initiator_port_id - initiator's port id value +@param p_target_port_id - target's port id value + +@return - none +*/ +static inline +void +set_srp_login_request_it_nexus( + IN OUT srp_login_req_t *p_information_unit, + IN srp_ib_port_id_t *p_initiator_port_id, + IN srp_ib_port_id_t *p_target_port_id ) +{ + RtlCopyMemory( &p_information_unit->initiator_port_id, + p_initiator_port_id, sizeof(srp_ib_port_id_t) ); + RtlCopyMemory( &p_information_unit->target_port_id, + p_target_port_id, sizeof(srp_ib_port_id_t) ); +} + +/* setup_srp_login_request */ +/*! +Initializes and sets the Srp Login Request IU to the values supplied + +@param p_information_unit - pointer to the IU structure +@param iu_tag - tag value to be used for the req/rsp pair +@param req_max_init_to_targ_iu - max initiator to target IU size (64 or greater) +@param data_buffer_descriptor_formats - usage indicator values +@param multi_channel_action - value indicating action to be applied to existing RDMA channels +@param p_initiator_port_id - initiator's port id value (for I_T nexus) +@param p_target_port_id - target's port id value (for I_T nexus) + +@return - none +*/ +static inline +void +setup_srp_login_request( + IN OUT srp_login_req_t *p_information_unit, + IN uint64_t iu_tag, + IN uint32_t req_max_init_to_targ_iu, + IN DATA_BUFFER_DESCRIPTOR_FORMAT data_buffer_descriptor_formats, + IN MULTI_CHANNEL_ACTION multi_channel_action, + IN srp_ib_port_id_t *p_initiator_port_id, + IN srp_ib_port_id_t *p_target_port_id ) +{ + init_srp_login_request( p_information_unit, iu_tag ); + set_srp_login_request_req_max_init_to_targ_iu( p_information_unit, req_max_init_to_targ_iu ); + set_srp_login_request_required_data_buffer_formats( p_information_unit, data_buffer_descriptor_formats ); + set_srp_login_request_multi_channel_action( p_information_unit, multi_channel_action ); + set_srp_login_request_it_nexus( p_information_unit, p_initiator_port_id, p_target_port_id ); +} + +/* get_srp_login_request_tag */ +/*! +Returns the value of the tag field of a login request + +@param p_information_unit - pointer to the IU structure + +@return - tag value +*/ +static inline +uint64_t +get_srp_login_request_tag( + IN srp_login_req_t *p_information_unit ) +{ + return( get_srp_information_unit_tag( ( srp_information_unit_t* ) p_information_unit ) ); +} + +/* get_srp_login_request_req_max_init_to_targ_iu */ +/*! +Returns the requested max initiator to target information unit size + +@param p_information_unit - pointer to the IU structure + +@return - requested max initiator to target information unit size value +*/ +static inline +uint32_t +get_srp_login_request_req_max_init_to_targ_iu( + IN srp_login_req_t *p_information_unit ) +{ + return( p_information_unit->req_max_init_to_targ_iu ); +} + +/* get_srp_login_request_required_data_buffer_formats */ +/*! +Returns the required data buffer formats to be used on the channel + +@param p_information_unit - pointer to the IU structure + +@return - required data buffer formats settings +*/ +static inline +DATA_BUFFER_DESCRIPTOR_FORMAT +get_srp_login_request_required_data_buffer_formats( + IN srp_login_req_t *p_information_unit ) +{ + switch ( p_information_unit->req_buffer_fmts.flags & DATA_BUFFER_DESCRIPTOR_FORMAT_MASK ) + { + case DIRECT_DATA_BUFFER_DESCRIPTOR_REQUESTED: + return( DBDF_DIRECT_DATA_BUFFER_DESCRIPTOR ); + + case INDIRECT_DATA_BUFFER_DESCRIPTOR_REQUESTED: + return( DBDF_INDIRECT_DATA_BUFFER_DESCRIPTORS ); + + case DIRECT_DATA_BUFFER_DESCRIPTOR_REQUESTED | INDIRECT_DATA_BUFFER_DESCRIPTOR_REQUESTED: + return( ( DATA_BUFFER_DESCRIPTOR_FORMAT ) ( DBDF_DIRECT_DATA_BUFFER_DESCRIPTOR | DBDF_INDIRECT_DATA_BUFFER_DESCRIPTORS ) ); + + default: + return( DBDF_NO_DATA_BUFFER_DESCRIPTOR_PRESENT ); + } +} + +/* get_srp_login_request_multi_channel_action */ +/*! +Returns the multi channel action setting + +@param p_information_unit - pointer to the IU structure + +@return - multi channel action setting +*/ +static inline +MULTI_CHANNEL_ACTION +get_srp_login_request_multi_channel_action( + IN srp_login_req_t *p_information_unit ) +{ + return( ( MULTI_CHANNEL_ACTION ) ( p_information_unit->flags & MULTI_CHANNEL_ACTION_MASK ) ); +} + +/* get_srp_login_request_initiator_port_id */ +/*! +Returns the initiator port identifier + +@param p_information_unit - pointer to the IU structure + +@return - pointer to initiator port id value +*/ +static inline +srp_ib_port_id_t* +get_srp_login_request_initiator_port_id( + IN srp_login_req_t *p_information_unit ) +{ + return( &p_information_unit->initiator_port_id ); +} + +/* get_srp_login_request_target_port_id */ +/*! +Returns the target port identifier + +@param p_information_unit - pointer to the IU structure + +@return - pointer to target port id value +*/ +static inline +srp_ib_port_id_t* +get_srp_login_request_target_port_id( + IN srp_login_req_t *p_information_unit ) +{ + return( &p_information_unit->target_port_id ); +} + +/* get_srp_login_request_length */ +/*! +Returns the size in bytes of the Srp Login Request IU + +@param p_information_unit - pointer to the IU structure + +@return - tag value +*/ +static inline +uint32_t +get_srp_login_request_length( + IN srp_login_req_t *p_information_unit ) +{ + return( sizeof( *p_information_unit ) ); +} + +/* set_srp_login_request_from_host_to_network */ +/*! +Swaps the IU fields from Host to Network ordering + +@param p_information_unit - pointer to the IU structure + +@return - none +*/ + +static inline +void +set_srp_login_request_from_host_to_network( + IN OUT srp_login_req_t *p_information_unit ) +{ + set_srp_information_unit_from_host_to_network( ( srp_information_unit_t* ) p_information_unit ); + p_information_unit->req_max_init_to_targ_iu = cl_hton32( p_information_unit->req_max_init_to_targ_iu ); +} + +/* set_srp_login_request_from_network_to_host */ +/*! +Swaps the IU fields from Network to Host ordering + +@param p_information_unit - pointer to the IU structure + +@return - none +*/ + +static inline +void +set_srp_login_request_from_network_to_host( + IN OUT srp_login_req_t *p_information_unit ) +{ + set_srp_login_request_from_host_to_network ( p_information_unit ); +} + +#endif /* SRP_LOGIN_REQ_H_INCLUDED */ diff --git a/branches/WOF2-3/ulp/srp/kernel/srp_login_rsp.h b/branches/WOF2-3/ulp/srp/kernel/srp_login_rsp.h new file mode 100644 index 00000000..38561c14 --- /dev/null +++ b/branches/WOF2-3/ulp/srp/kernel/srp_login_rsp.h @@ -0,0 +1,382 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#ifndef SRP_LOGIN_RSP_H_INCLUDED +#define SRP_LOGIN_RSP_H_INCLUDED + +#include "srp.h" +#include "srp_iu_buffer.h" +#include "srp_information_unit.h" + +#include + +/* set_srp_login_response_tag */ +/*! +Sets the tag field of a login response information unit + +@param p_information_unit - pointer to the IU structure +@param iu_tag - tag value of IU + +@return - none +*/ +static inline +void +set_srp_login_response_tag( + IN OUT srp_login_rsp_t *p_information_unit, + IN uint64_t iu_tag ) +{ + set_srp_information_unit_tag( ( srp_information_unit_t* ) p_information_unit, iu_tag ); +} + +/* init_srp_login_response */ +/*! +Initializes the login response IU to zeroes +and sets the IU type to Srp Login Response +and sets the tag to the value supplied + +@param p_information_unit - pointer to the IU structure +@param iu_tag - tag value to be used for the req/rsp pair + +@return - none +*/ +static inline +void +init_srp_login_response( + IN OUT srp_login_rsp_t *p_information_unit, + IN uint64_t iu_tag ) +{ + init_srp_iu_buffer( ( srp_iu_buffer_t* ) p_information_unit, SRP_LOGIN_RSP ) ; + set_srp_login_response_tag( p_information_unit, iu_tag ); +} + +/* set_srp_login_response_request_limit_delta */ +/*! +Sets the request limit delta value for flow control + +@param p_information_unit - pointer to the IU structure +@param request_limit_delta - flow control request limit delta value + +@return - none +*/ +static inline +void +set_srp_login_response_request_limit_delta( + IN OUT srp_login_rsp_t *p_information_unit, + IN int32_t request_limit_delta + ) +{ + p_information_unit->request_limit_delta = request_limit_delta; +} + +/* set_srp_login_response_max_init_to_targ_iu */ +/*! +Sets the maximum sized IU to be sent on this channel from initiator to target + +@param p_information_unit - pointer to the IU structure +@param max_init_to_targ_iu - max initiator to target IU size (64 or greater) + +@return - none +*/ +static inline +void +set_srp_login_response_max_init_to_targ_iu( + IN OUT srp_login_rsp_t *p_information_unit, + IN uint32_t max_init_to_targ_iu ) +{ + p_information_unit->max_init_to_targ_iu = max_init_to_targ_iu; +} + +/* set_srp_login_response_max_targ_to_init_iu */ +/*! +Sets the maximum sized IU to be sent on this channel from target to initiator + +@param p_information_unit - pointer to the IU structure +@param max_targ_to_init_iu - max initiator to target IU size (64 or greater) + +@return - none +*/ +static inline +void +set_srp_login_response_max_targ_to_init_iu( + IN OUT srp_login_rsp_t *p_information_unit, + IN uint32_t max_targ_to_init_iu ) +{ + p_information_unit->max_targ_to_init_iu = max_targ_to_init_iu; +} + +/* set_srp_login_response_supported_data_buffer_formats */ +/*! +Sets the flags indicating whether or not the target can and will use +direct/indirect data buffer descriptors on this channel + +@param p_information_unit - pointer to the IU structure +@param dataBufferDescriptorFormats - usage indicator values + +@return - none +*/ +static inline +void +set_srp_login_response_supported_data_buffer_formats( + IN OUT srp_login_rsp_t *p_information_unit, + IN DATA_BUFFER_DESCRIPTOR_FORMAT data_buffer_descriptor_formats ) +{ + p_information_unit->sup_buffer_fmts.flags = 0; + + if ( data_buffer_descriptor_formats & DBDF_DIRECT_DATA_BUFFER_DESCRIPTOR ) + { + p_information_unit->sup_buffer_fmts.flags |= DIRECT_DATA_BUFFER_DESCRIPTOR_REQUESTED; + } + + if ( data_buffer_descriptor_formats & DBDF_INDIRECT_DATA_BUFFER_DESCRIPTORS ) + { + p_information_unit->sup_buffer_fmts.flags |= INDIRECT_DATA_BUFFER_DESCRIPTOR_REQUESTED; + } +} + +/* set_srp_login_response_multi_channel_result */ +/*! +Sets the value indicating how existing RDMA channels associated with the +same I_T nexus specified by the Initiator Port Identifier and Target Port +Identifier fields were treated. They can either be terminated or allowed +to continue processing. + +@param p_information_unit - pointer to the IU structure +@param multi_channel_result - value indicating action applied to + existing RDMA channels + +@return - none +*/ +static inline +void +set_srp_login_response_multi_channel_result( + IN OUT srp_login_rsp_t *p_information_unit, + IN MULTI_CHANNEL_RESULT multi_channel_result ) +{ + p_information_unit->flags |= multi_channel_result; +} + +/* setup_srp_login_response */ +/*! +Initializes and sets the Srp Login Response IU to the values supplied + +@param p_information_unit - pointer to the IU structure +@param iu_tag - tag value to be used for the req/rsp pair +@param request_limit_delta - flow control request limit delta value +@param max_init_to_targ_iu - max initiator to target IU size (64 or greater) +@param max_targ_to_init_iu - max target to initiator IU size (64 or greater) +@param dataBufferDescriptorFormats - usage indicator values +@param multi_channel_result - value indicating action applied to existing RDMA channels + +@return - none +*/ +static inline +void +setup_srp_login_response( + IN OUT srp_login_rsp_t *p_information_unit, + IN uint64_t iu_tag, + IN int32_t request_limit_delta, + IN uint32_t max_init_to_targ_iu, + IN uint32_t max_targ_to_init_iu, + IN DATA_BUFFER_DESCRIPTOR_FORMAT data_buffer_descriptor_formats, + IN MULTI_CHANNEL_RESULT multi_channel_result ) +{ + init_srp_login_response( p_information_unit, iu_tag ); + set_srp_login_response_request_limit_delta( p_information_unit, request_limit_delta ); + set_srp_login_response_max_init_to_targ_iu( p_information_unit, max_init_to_targ_iu ); + set_srp_login_response_max_targ_to_init_iu( p_information_unit, max_targ_to_init_iu ); + set_srp_login_response_supported_data_buffer_formats( p_information_unit, data_buffer_descriptor_formats ); + set_srp_login_response_multi_channel_result( p_information_unit, multi_channel_result ); +} + +/* get_srp_login_response_tag */ +/*! +Returns the value of the tag field of a login response + +@param p_information_unit - pointer to the IU structure + +@return - tag value +*/ +static inline +uint64_t +get_srp_login_response_tag( + IN srp_login_rsp_t *p_information_unit ) +{ + return( get_srp_information_unit_tag( ( srp_information_unit_t* ) p_information_unit ) ); +} + +/* get_srp_login_response_request_limit_delta */ +/*! +Returns the value of the request limit delta field of a login response + +@param p_information_unit - pointer to the IU structure + +@return - request limit delta value +*/ +static inline +int32_t +get_srp_login_response_request_limit_delta( + IN srp_login_rsp_t *p_information_unit ) +{ + return( p_information_unit->request_limit_delta ); +} + +/* get_srp_login_response_max_init_to_targ_iu */ +/*! +Returns the value of the max initiator to target IU size value + +@param p_information_unit - pointer to the IU structure + +@return - max initiator to target IU value +*/ +static inline +uint32_t +get_srp_login_response_max_init_to_targ_iu( + IN srp_login_rsp_t *p_information_unit ) +{ + return( p_information_unit->max_init_to_targ_iu ); +} + +/* get_srp_login_response_max_targ_to_init_iu */ +/*! +Returns the value of the max target to initiator IU size value + +@param p_information_unit - pointer to the IU structure + +@return - max target to initiator IU value +*/ +static inline +uint32_t +get_srp_login_response_max_targ_to_init_iu( + IN srp_login_rsp_t *p_information_unit ) +{ + return( p_information_unit->max_targ_to_init_iu ); +} + +/* get_srp_login_response_supported_data_buffer_formats */ +/*! +Returns the supported data buffer formats to be used on the channel + +@param p_information_unit - pointer to the IU structure + +@return - supported data buffer formats settings +*/ +static inline +DATA_BUFFER_DESCRIPTOR_FORMAT +get_srp_login_response_supported_data_buffer_formats( + IN srp_login_rsp_t *p_information_unit ) +{ + switch ( p_information_unit->sup_buffer_fmts.flags & DATA_BUFFER_DESCRIPTOR_FORMAT_MASK ) + { + case DIRECT_DATA_BUFFER_DESCRIPTOR_REQUESTED: + return( DBDF_DIRECT_DATA_BUFFER_DESCRIPTOR ); + + case INDIRECT_DATA_BUFFER_DESCRIPTOR_REQUESTED: + return( DBDF_INDIRECT_DATA_BUFFER_DESCRIPTORS ); + + case DIRECT_DATA_BUFFER_DESCRIPTOR_REQUESTED | INDIRECT_DATA_BUFFER_DESCRIPTOR_REQUESTED: + return( ( DATA_BUFFER_DESCRIPTOR_FORMAT ) ( DBDF_DIRECT_DATA_BUFFER_DESCRIPTOR | DBDF_INDIRECT_DATA_BUFFER_DESCRIPTORS ) ); + + default: + return( DBDF_NO_DATA_BUFFER_DESCRIPTOR_PRESENT ); + } +} + +/* get_srp_login_response_multi_channel_result */ +/*! +Returns the multi channel result setting + +@param p_information_unit - pointer to the IU structure + +@return - multi channel result setting +*/ +static inline +MULTI_CHANNEL_RESULT +get_srp_login_response_multi_channel_result( + IN srp_login_rsp_t *p_information_unit ) +{ + return( ( MULTI_CHANNEL_RESULT ) ( p_information_unit->flags & MULTI_CHANNEL_RESULT_MASK ) ); +} + +/* get_srp_login_response_length */ +/*! +Returns the size in bytes of the Srp Login Response IU + +@param p_information_unit - pointer to the IU structure + +@return - tag value +*/ +static inline +uint32_t +get_srp_login_response_length( + IN srp_login_rsp_t *p_information_unit ) +{ + return( sizeof( *p_information_unit ) ); +} + +/* set_srp_login_response_from_host_to_network */ +/*! +Swaps the IU fields from Host to Network ordering + +@param p_information_unit - pointer to the IU structure + +@return - none +*/ + +static inline +void +set_srp_login_response_from_host_to_network( + IN OUT srp_login_rsp_t *p_information_unit ) +{ + set_srp_information_unit_from_host_to_network( ( srp_information_unit_t* ) p_information_unit ); + p_information_unit->request_limit_delta = cl_hton32( p_information_unit->request_limit_delta ); + p_information_unit->max_init_to_targ_iu = cl_hton32( p_information_unit->max_init_to_targ_iu ); + p_information_unit->max_targ_to_init_iu = cl_hton32( p_information_unit->max_targ_to_init_iu ); +} + +/* setSrpLoginResponseFromNetworkToHost */ +/*! +Swaps the IU fields from Network to Host ordering + +@param p_information_unit - pointer to the IU structure + +@return - none +*/ + +static inline +void +set_srp_login_response_from_network_to_host( + IN OUT srp_login_rsp_t *p_information_unit ) +{ + set_srp_login_response_from_host_to_network ( p_information_unit ); +} + +#endif /* SRP_LOGIN_RSP_H_INCLUDED */ diff --git a/branches/WOF2-3/ulp/srp/kernel/srp_rsp.h b/branches/WOF2-3/ulp/srp/kernel/srp_rsp.h new file mode 100644 index 00000000..5e3e526b --- /dev/null +++ b/branches/WOF2-3/ulp/srp/kernel/srp_rsp.h @@ -0,0 +1,726 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#ifndef SRP_RSP_H_INCLUDED +#define SRP_RSP_H_INCLUDED + +#include "srp.h" +#include "srp_iu_buffer.h" +#include "srp_information_unit.h" + +/* set_srp_response_tag */ +/*! +Sets the tag field of a Response information unit + +@param p_information_unit - pointer to the IU structure +@param iu_tag - tag value of IU + +@return - none +*/ +static inline +void +set_srp_response_tag( + IN OUT srp_rsp_t *p_information_unit, + IN uint64_t iu_tag ) +{ + set_srp_information_unit_tag( ( srp_information_unit_t* ) p_information_unit, iu_tag ); +} + +/* init_srp_response */ +/*! +Initializes the Response IU to zeroes +and sets the IU type to Response +and sets the tag to the value supplied + +@param p_information_unit - pointer to the IU structure +@param iu_tag - tag value to be used for the req/rsp pair + +@return - none +*/ +static inline +void +init_srp_response( + IN OUT srp_rsp_t *p_information_unit, + IN uint64_t iu_tag ) +{ + init_srp_iu_buffer( ( srp_iu_buffer_t* ) p_information_unit, SRP_RSP ) ; + set_srp_response_tag( p_information_unit, iu_tag ); +} + +/* set_srp_response_request_limit_delta */ +/*! +sets the request limit delta value + +@param p_information_unit - pointer to the IU structure +@param request_limit_delta - buffer descriptor format value + +@return - none +*/ +static inline +void +set_srp_response_request_limit_delta( + IN OUT srp_rsp_t *p_information_unit, + IN int32_t request_limit_delta ) +{ + p_information_unit->request_limit_delta = request_limit_delta; +} + +/* set_srp_response_flags */ +/*! +sets the flags field + +@param p_information_unit - pointer to the IU structure +@param flags - flags di_under di_over do_under do_over sns_valid RSPVALID + +@return - none +*/ +static inline +void +set_srp_response_flags( + IN OUT srp_rsp_t *p_information_unit, + IN uint8_t flags ) +{ + p_information_unit->flags = flags & 0x3F; +} + +/* set_srp_response_di_under */ +/*! +sets the DIUNDER flag + +@param p_information_unit - pointer to the IU structure +@param di_under - DIUNDER flag + +this is a boolean flag and therefore any non-zero value is true +while zero is of course then false + +@return - none +*/ +static inline +void +set_srp_response_di_under( + IN OUT srp_rsp_t *p_information_unit, + IN uint8_t di_under ) +{ + p_information_unit->flags = ( p_information_unit->flags & 0xDF ) | ( di_under == 0 ? 0 : 0x20 ); +} + +/* set_srp_response_di_over */ +/*! +sets the DIOVER flag + +@param p_information_unit - pointer to the IU structure +@param di_over - DIOVER flag + +this is a boolean flag and therefore any non-zero value is true +while zero is of course then false + +@return - none +*/ +static inline +void +set_srp_response_di_over( + IN OUT srp_rsp_t *p_information_unit, + IN uint8_t di_over ) +{ + p_information_unit->flags = ( p_information_unit->flags & 0xEF ) | ( di_over == 0 ? 0 : 0x10 ); +} + +/* set_srp_response_do_under */ +/*! +sets the DOUNDER flag + +@param p_information_unit - pointer to the IU structure +@param do_under - DOUNDER flag + +this is a boolean flag and therefore any non-zero value is true +while zero is of course then false + +@return - none +*/ +static inline +void +set_srp_response_do_under( + IN OUT srp_rsp_t *p_information_unit, + IN uint8_t do_under ) +{ + p_information_unit->flags = ( p_information_unit->flags & 0xF7 ) | ( do_under == 0 ? 0 : 0x08 ); +} + +/* set_srp_response_do_over */ +/*! +sets the DOOVER flag + +@param p_information_unit - pointer to the IU structure +@param do_over - DOOVER flag + +this is a boolean flag and therefore any non-zero value is true +while zero is of course then false + +@return - none +*/ +static inline +void +set_srp_response_do_over( + IN OUT srp_rsp_t *p_information_unit, + IN uint8_t do_over ) +{ + p_information_unit->flags = ( p_information_unit->flags & 0xFB ) | ( do_over == 0 ? 0 : 0x04 ); +} + +/* set_srp_response_sns_valid */ +/*! +sets the SNSVALID flag + +@param p_information_unit - pointer to the IU structure +@param sns_valid - SNSVALID flag + +this is a boolean flag and therefore any non-zero value is true +while zero is of course then false + +@return - none +*/ +static inline +void +set_srp_response_sns_valid( + IN OUT srp_rsp_t *p_information_unit, + IN uint8_t sns_valid ) +{ + p_information_unit->flags = ( p_information_unit->flags & 0xFD ) | ( sns_valid == 0 ? 0 : 0x02 ); +} + +/* set_srp_response_rsp_valid */ +/*! +sets the RSPVALID flag + +@param p_information_unit - pointer to the IU structure +@param rsp_valid - RSPVALID flag + +this is a boolean flag and therefore any non-zero value is true +while zero is of course then false + +@return - none +*/ +static inline +void +set_srp_response_rsp_valid( + IN OUT srp_rsp_t *p_information_unit, + IN uint8_t rsp_valid ) +{ + p_information_unit->flags = ( p_information_unit->flags & 0xFE ) | ( rsp_valid == 0 ? 0 : 0x01 ); +} + +/* set_srp_response_status */ +/*! +sets the Status value + +@param p_information_unit - pointer to the IU structure +@param status - Status value + +@return - none +*/ +static inline +void +set_srp_response_status( + IN OUT srp_rsp_t *p_information_unit, + IN uint8_t status ) +{ + p_information_unit->status = status; +} + +/* set_srp_response_data_out_residual_count */ +/*! +Sets the data out residual count for the Response IU + +@param p_information_unit - pointer to the IU structure +@param data_out_residual_count - data out residual count for the request + +@return - none +*/ +static inline +void +set_srp_response_data_out_residual_count( + IN OUT srp_rsp_t *p_information_unit, + IN uint32_t data_out_residual_count ) +{ + p_information_unit->data_out_residual_count = data_out_residual_count; +} + +/* set_srp_response_data_in_residual_count */ +/*! +Sets the data in residual count for the Response IU + +@param p_information_unit - pointer to the IU structure +@param data_in_residual_count - data out residual count for the request + +@return - none +*/ +static inline +void +set_srp_response_data_in_residual_count( + IN OUT srp_rsp_t *p_information_unit, + IN uint32_t data_in_residual_count ) +{ + p_information_unit->data_in_residual_count = data_in_residual_count; +} + +/* set_srp_response_sense_data_list_length */ +/*! +Sets the sense data list length for the Response IU + +@param p_information_unit - pointer to the IU structure +@param sense_data_list_length - sense data list length for the request + +@return - none +*/ +static inline +void +set_srp_response_sense_data_list_length( + IN OUT srp_rsp_t *p_information_unit, + IN uint32_t sense_data_list_length ) +{ + p_information_unit->sense_data_list_length = sense_data_list_length; +} + +/* set_srp_response_response_data_list_length */ +/*! +Sets the response data list length for the Response IU + +@param p_information_unit - pointer to the IU structure +@param response_data_list_length - response data list length for the request + +@return - none +*/ +static inline +void +set_srp_response_response_data_list_length( + IN OUT srp_rsp_t *p_information_unit, + IN uint32_t response_data_list_length ) +{ + p_information_unit->response_data_list_length = response_data_list_length; +} + +/* setup_srp_response */ +/*! +Initializes and sets the Srp Response IU to the values supplied + +@param p_information_unit - pointer to the IU structure +@param iu_tag - tag value to be used for the req/rsp pair +@param request_limit_delta - buffer descriptor format value +@param di_under - DIUNDER flag +@param di_over - DIOVER flag +@param do_under - DOUNDER flag +@param do_over - DOOVER flag +@param sns_valid - SNSVALID flag +@param rsp_valid - RSPVALID flag +@param status - Status value +@param data_out_residual_count - data out residual count for the request +@param data_in_residual_count - data out residual count for the request +@param sense_data_list_length - sense data list length for the request +@param response_data_list_length - response data list length for the request + +@return - none +*/ +static inline +void +setup_srp_response( + IN OUT srp_rsp_t *p_information_unit, + IN uint64_t iu_tag, + IN int32_t request_limit_delta, + IN uint8_t di_under, + IN uint8_t di_over, + IN uint8_t do_under, + IN uint8_t do_over, + IN uint8_t sns_valid, + IN uint8_t rsp_valid, + IN uint8_t status, + IN uint32_t data_out_residual_count, + IN uint32_t data_in_residual_count, + IN uint32_t sense_data_list_length, + IN uint32_t response_data_list_length ) +{ + init_srp_response( p_information_unit, iu_tag ); + set_srp_response_request_limit_delta( p_information_unit, request_limit_delta ); + set_srp_response_di_under( p_information_unit, di_under ); + set_srp_response_di_over( p_information_unit, di_over ); + set_srp_response_do_under( p_information_unit, do_under ); + set_srp_response_do_over( p_information_unit, do_over ); + set_srp_response_sns_valid( p_information_unit, sns_valid ); + set_srp_response_rsp_valid( p_information_unit, rsp_valid ); + set_srp_response_status( p_information_unit, status ); + set_srp_response_data_out_residual_count( p_information_unit, data_out_residual_count ); + set_srp_response_data_in_residual_count( p_information_unit, data_in_residual_count ); + set_srp_response_sense_data_list_length( p_information_unit, sense_data_list_length ); + set_srp_response_response_data_list_length( p_information_unit, response_data_list_length ); +} + +/* get_srp_response_tag */ +/*! +Returns the value of the tag field of a response IU + +@param p_information_unit - pointer to the IU structure + +@return - tag value +*/ +static inline +uint64_t +get_srp_response_tag( + IN srp_rsp_t *p_information_unit ) +{ + return( get_srp_information_unit_tag( ( srp_information_unit_t* ) p_information_unit ) ); +} + +/* get_srp_response_request_limit_delta */ +/*! +Returns the value of the request limit delta field of a Response IU + +@param p_information_unit - pointer to the IU structure + +@return - request limit delta value +*/ +static inline +int32_t +get_srp_response_request_limit_delta( + IN srp_rsp_t *p_information_unit ) +{ + return( p_information_unit->request_limit_delta ); +} + +/* get_srp_response_flags */ +/*! +Returns flags field of a Response IU + +@param p_information_unit - pointer to the IU structure + +@return - value of the flags field +*/ +static inline +uint8_t +get_srp_response_flags( + IN srp_rsp_t *p_information_unit ) +{ + return( p_information_unit->flags ); +} + +/* get_srp_response_di_under */ +/*! +Returns the DIUNDER flag setting of a Response IU + +@param p_information_unit - pointer to the IU structure + +@return - set/clear setting + one indicates set while zero indicates not set +*/ +static inline +uint8_t +get_srp_response_di_under( + IN srp_rsp_t *p_information_unit ) +{ + return( ( p_information_unit->flags & 0x20 ) != 0 ? 1 : 0 ); +} + +/* get_srp_response_di_over */ +/*! +Returns the DIOVER flag setting of a Response IU + +@param p_information_unit - pointer to the IU structure + +@return - set/clear setting + one indicates set while zero indicates not set +*/ +static inline +uint8_t +get_srp_response_di_over( + IN srp_rsp_t *p_information_unit ) +{ + return( ( p_information_unit->flags & 0x10 ) != 0 ? 1 : 0 ); +} + +/* get_srp_response_do_under */ +/*! +Returns the DOUNDER flag setting of a Response IU + +@param p_information_unit - pointer to the IU structure + +@return - set/clear setting + one indicates set while zero indicates not set +*/ +static inline +uint8_t +get_srp_response_do_under( + IN srp_rsp_t *p_information_unit ) +{ + return( ( p_information_unit->flags & 0x08 ) != 0 ? 1 : 0 ); +} + +/* get_srp_response_do_over */ +/*! +Returns the DOOVER flag setting of a Response IU + +@param p_information_unit - pointer to the IU structure + +@return - set/clear setting + one indicates set while zero indicates not set +*/ +static inline +uint8_t +get_srp_response_do_over( + IN srp_rsp_t *p_information_unit ) +{ + return( ( p_information_unit->flags & 0x04 ) != 0 ? 1 : 0 ); +} + +/* get_srp_response_sns_valid */ +/*! +Returns the SNSVALID flag setting of a Response IU + +@param p_information_unit - pointer to the IU structure + +@return - set/clear setting + one indicates set while zero indicates not set +*/ +static inline +uint8_t +get_srp_response_sns_valid( + IN srp_rsp_t *p_information_unit ) +{ + return( ( p_information_unit->flags & 0x02 ) != 0 ? 1 : 0 ); +} + +/* get_srp_response_rsp_valid */ +/*! +Returns the RSPVALID flag setting of a Response IU + +@param p_information_unit - pointer to the IU structure + +@return - set/clear setting + one indicates set while zero indicates not set +*/ +static inline +uint8_t +get_srp_response_rsp_valid( + IN srp_rsp_t *p_information_unit ) +{ + return( ( p_information_unit->flags & 0x01 ) != 0 ? 1 : 0 ); +} + +/* get_srp_response_status */ +/*! +Returns the Status field setting of a Response IU + +@param p_information_unit - pointer to the IU structure + +@return - Status value setting +*/ +static inline +uint8_t +get_srp_response_status( + IN srp_rsp_t *p_information_unit ) +{ + return( p_information_unit->status ); +} + +/* get_srp_response_data_out_residual_count */ +/*! +Returns the data out residual count field setting of a Response IU + +@param p_information_unit - pointer to the IU structure + +@return - data out residual count value setting +*/ +static inline +uint32_t +get_srp_response_data_out_residual_count( + IN srp_rsp_t *p_information_unit ) +{ + return( p_information_unit->data_out_residual_count ); +} + +/* get_srp_response_data_in_residual_count */ +/*! +Returns the data in residual count field setting of a Response IU + +@param p_information_unit - pointer to the IU structure + +@return - data in residual count value setting +*/ +static inline +uint32_t +get_srp_response_data_in_residual_count( + IN srp_rsp_t *p_information_unit ) +{ + return( p_information_unit->data_in_residual_count ); +} + +/* get_srp_response_sense_data_list_length */ +/*! +Returns the sense data list length field setting of a Response IU + +@param p_information_unit - pointer to the IU structure + +@return - sense data list length value setting +*/ +static inline +uint32_t +get_srp_response_sense_data_list_length( + IN srp_rsp_t *p_information_unit ) +{ + return( p_information_unit->sense_data_list_length ); +} + +/* get_srp_response_response_data_list_length */ +/*! +Returns the response data list length field setting of a Response IU + +@param p_information_unit - pointer to the IU structure + +@return - response data list length value setting +*/ +static inline +uint32_t +get_srp_response_response_data_list_length( + IN srp_rsp_t *p_information_unit ) +{ + return( p_information_unit->response_data_list_length ); +} + +/* get_srp_response_response_data */ +/*! +Returns a pointer to the response data field of a Response + +@param p_information_unit - pointer to the IU structure + +@return - pointer to the response data +*/ +static inline +srp_response_data_t* +get_srp_response_response_data( + IN srp_rsp_t *p_information_unit ) +{ + if ( get_srp_response_rsp_valid( p_information_unit ) ) + return( p_information_unit->response_data ); + + return( NULL ); +} + +/* get_srp_response_sense_data */ +/*! +Returns a pointer to the sense data field of a Response + +WARNING!!!! Set the response data list length before this call so the + offset can be correctly calculated + +@param p_information_unit - pointer to the IU structure + +@return - pointer to sense data +*/ +static inline +uint8_t* +get_srp_response_sense_data( + IN srp_rsp_t *p_information_unit ) +{ + if ( get_srp_response_sns_valid( p_information_unit ) ) + { + if ( get_srp_response_response_data( p_information_unit ) != NULL ) + { + return( ( ( uint8_t* ) p_information_unit->response_data ) + get_srp_response_response_data_list_length( p_information_unit ) ); + } + else + { + return( ( uint8_t* ) p_information_unit->response_data ); + } + } + + return( NULL ); +} + +/* get_srp_response_length */ +/*! +Returns the size in bytes of the Srp Response IU + +@param p_information_unit - pointer to the IU structure + +@return - used length of Response IU buffer +*/ +static inline +uint32_t +get_srp_response_length( + IN srp_rsp_t *p_information_unit ) +{ + /* do not include response data field in the sizeof the IU. add it's length and sense data list length to the structure size */ + return( ( sizeof( *p_information_unit ) - sizeof( p_information_unit->response_data ) ) + + ( get_srp_response_rsp_valid( p_information_unit ) ? get_srp_response_response_data_list_length( p_information_unit ) : 0 ) + + ( get_srp_response_sns_valid( p_information_unit ) ? get_srp_response_sense_data_list_length( p_information_unit ) : 0 ) ); +} + +/* set_srp_response_from_host_to_network */ +/*! +Swaps the IU fields from Host to Network ordering + +@param p_information_unit - pointer to the IU structure + +@return - none +*/ + +static inline +void +set_srp_response_from_host_to_network( + IN OUT srp_rsp_t *p_information_unit ) +{ + set_srp_information_unit_from_host_to_network( ( srp_information_unit_t* ) p_information_unit ); + p_information_unit->request_limit_delta = cl_hton32( p_information_unit->request_limit_delta ); + if ( get_srp_response_flags( p_information_unit ) != 0 ) + { + p_information_unit->data_out_residual_count = cl_hton32( p_information_unit->data_out_residual_count ); + p_information_unit->data_in_residual_count = cl_hton32( p_information_unit->data_in_residual_count ); + p_information_unit->sense_data_list_length = cl_hton32( p_information_unit->sense_data_list_length ); + p_information_unit->response_data_list_length = cl_hton32( p_information_unit->response_data_list_length ); + } +} + +/* set_srp_response_from_network_to_host */ +/*! +Swaps the IU fields from Network to Host ordering + +@param p_information_unit - pointer to the IU structure + +@return - none +*/ + +static inline +void +set_srp_response_from_network_to_host( + IN OUT srp_rsp_t *p_information_unit ) +{ + set_srp_response_from_host_to_network ( p_information_unit ); +} + +#endif /* SRP_RSP_H_INCLUDED */ diff --git a/branches/WOF2-3/ulp/srp/kernel/srp_session.c b/branches/WOF2-3/ulp/srp/kernel/srp_session.c new file mode 100644 index 00000000..c9dfdd20 --- /dev/null +++ b/branches/WOF2-3/ulp/srp/kernel/srp_session.c @@ -0,0 +1,597 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include "srp_debug.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "srp_session.tmh" +#endif +#include "srp_session.h" +#include + +/* __srp_destroying_session */ +/*! +Called when session has been marked for destruction + +@param p_obj - pointer to a session object + +@return - none +*/ +static void +__srp_destroying_session( + IN cl_obj_t *p_obj ) +{ + srp_session_t *p_srp_session; + + SRP_ENTER( SRP_DBG_SESSION ); + + p_srp_session = PARENT_STRUCT( p_obj, srp_session_t, obj ); + + cl_obj_lock( &p_srp_session->obj ); + if( p_srp_session->connection.state != SRP_CONNECT_FAILURE ) + { + cl_obj_unlock( &p_srp_session->obj ); + return; + } + + p_srp_session->connection.state = SRP_CONNECTION_CLOSING; + cl_obj_unlock( &p_srp_session->obj ); + + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_DEBUG, + ("Session Object ref_cnt = %d\n", p_srp_session->obj.ref_cnt) ); + + SRP_EXIT( SRP_DBG_SESSION ); +} + + +/* __srp_cleanup_session */ +/*! +Called when session is being destroyed +in order to perform resource deallocation + +@param p_obj - pointer to a session object + +@return - none +*/ +void +__srp_cleanup_session( + IN cl_obj_t *p_obj ) +{ + srp_session_t *p_srp_session; + + SRP_ENTER( SRP_DBG_SESSION ); + + p_srp_session = PARENT_STRUCT( p_obj, srp_session_t, obj ); + + srp_close_ca( &p_srp_session->hca ); + + if ( p_srp_session->p_shutdown_srb != NULL ) + { + p_srp_session->p_shutdown_srb->SrbStatus = SRB_STATUS_SUCCESS; + SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_DEBUG, + ("Returning SrbStatus %s(0x%x) for Function = %s(0x%x), " + "Path = 0x%x, Target = 0x%x, Lun = 0x%x\n", + g_srb_status_name[p_srp_session->p_shutdown_srb->SrbStatus], + p_srp_session->p_shutdown_srb->SrbStatus, + g_srb_function_name[p_srp_session->p_shutdown_srb->Function], + p_srp_session->p_shutdown_srb->Function, + p_srp_session->p_shutdown_srb->PathId, + p_srp_session->p_shutdown_srb->TargetId, + p_srp_session->p_shutdown_srb->Lun) ); + StorPortNotification( RequestComplete, p_srp_session->p_hba->p_ext, + p_srp_session->p_shutdown_srb ); + } + + srp_free_connection( &p_srp_session->connection ); + srp_destroy_descriptors( &p_srp_session->descriptors ); + + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_DEBUG, + ("Session Object ref_cnt = %d\n", p_srp_session->obj.ref_cnt) ); + + SRP_EXIT( SRP_DBG_SESSION ); +} + +/* __srp_free_session */ +/*! +Called when session has been destroyed +and is ready for deallocation + +@param p_obj - pointer to a session object + +@return - none +*/ +static void +__srp_free_session( + IN cl_obj_t *p_obj ) +{ + srp_session_t *p_srp_session; + + SRP_ENTER( SRP_DBG_SESSION ); + + p_srp_session = PARENT_STRUCT( p_obj, srp_session_t, obj ); + + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_DEBUG, + ("Before DeInit Session Object ref_cnt = %d\n", + p_srp_session->obj.ref_cnt) ); + + cl_obj_deinit( p_obj ); + + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_DEBUG, + ("After DeInit Session Object ref_cnt = %d\n", + p_srp_session->obj.ref_cnt) ); + + cl_free( p_srp_session ); + + SRP_EXIT( SRP_DBG_SESSION ); +} + +/* __srp_validate_service_entry */ +/*! +Validates the format of the Service Name and +Converts and returns the id extension encoded +within the service name string + +@param p_svc_entry - pointer to the service entry +@param p_target_id_extension - pointer value to hold the returned id extension + +@return - result of operation +*/ +static ib_api_status_t +__srp_validate_service_entry( + IN ib_svc_entry_t *p_svc_entry, + OUT uint64_t *p_target_id_extension ) +{ + ib_api_status_t status = IB_SUCCESS; + char target_id_extension[SRP_EXTENSION_ID_LENGTH + 1]; + size_t target_id_extension_size; + uint64_t multiplier = 1; + ULONG id_extension; + + SRP_ENTER( SRP_DBG_SESSION ); + + if ( cl_memcmp( p_svc_entry->name, SRP_SERVICE_NAME_PREFIX, strlen(SRP_SERVICE_NAME_PREFIX)) != 0 ) + { + SRP_PRINT_EXIT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("Service Name Not Properly Formatted.\n") ); + status = IB_INVALID_SERVICE_TYPE; + goto exit; + } + + *p_target_id_extension = 0; + + cl_memclr( target_id_extension, sizeof(target_id_extension) ); + cl_memcpy( target_id_extension, &p_svc_entry->name[strlen(SRP_SERVICE_NAME_PREFIX)], 16 ); + + target_id_extension_size = strlen( target_id_extension ); + + while ( target_id_extension_size != 0 ) + { + char current_digit[2] = {'\0', '\0'}; + NTSTATUS ntstatus; + + target_id_extension_size--; + + current_digit[0] = target_id_extension[target_id_extension_size]; + + ntstatus = RtlCharToInteger( current_digit, 16, &id_extension ); + if ( ntstatus != STATUS_SUCCESS ) + { + SRP_PRINT_EXIT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("Target Id Extension INVALID.\n") ); + status = IB_INVALID_PARAMETER; + break; + } + + (*p_target_id_extension) += ( id_extension * multiplier ); + + multiplier <<= 4; + } + + /* Swap to network order now. */ + *p_target_id_extension = cl_hton64( *p_target_id_extension ); + +exit: + SRP_EXIT( SRP_DBG_SESSION ); + + return ( status ); +} + +/* srp_new_session */ +/*! +Allocates and initializes a session structure and it's sub-structures + +@param p_hba - pointer to the hba associated with the new session +@param ioc_guid - pointer to the target's ioc guid +@param p_svc_entry - pointer to the service entry +@param p_path_rec - pointer to path record to use. + +@param p_status - pointer to the reason code + +@return - Pointer to new session or NULL if failure. See p_status for reason code. +*/ +srp_session_t* +srp_new_session( + IN srp_hba_t *p_hba, + IN ib_svc_entry_t *p_svc_entry, + IN ib_path_rec_t *p_path_rec, + OUT ib_api_status_t *p_status ) +{ + uint64_t target_id_extension; + srp_session_t *p_srp_session = NULL; + cl_status_t cl_status; + + SRP_ENTER( SRP_DBG_SESSION ); + + *p_status = __srp_validate_service_entry( p_svc_entry, &target_id_extension ); + if ( *p_status != IB_SUCCESS ) + { + goto exit; + } + + if( p_path_rec == NULL ) + { + goto exit; + } + + p_srp_session = (srp_session_t*)cl_zalloc( sizeof(srp_session_t) ); + if ( p_srp_session == NULL ) + { + SRP_PRINT_EXIT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("Failed to allocate srp_session_t structure.\n") ); + *p_status = IB_INSUFFICIENT_MEMORY; + goto exit; + } + + p_srp_session->p_hba = p_hba; + + *p_status = srp_init_connection( &p_srp_session->connection, + &p_hba->ioc_info.profile, + p_hba->info.ca_guid, + target_id_extension, + p_path_rec, + p_svc_entry->id ); + if ( *p_status != IB_SUCCESS ) + { + cl_free( p_srp_session ); + p_srp_session = NULL; + goto exit; + } + + cl_obj_construct( &p_srp_session->obj, SRP_OBJ_TYPE_SESSION ); + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_DEBUG, + ("After Construct Session Object ref_cnt = %d\n", + p_srp_session->obj.ref_cnt) ); + cl_status = cl_obj_init( &p_srp_session->obj, + CL_DESTROY_ASYNC, + __srp_destroying_session, + __srp_cleanup_session, + __srp_free_session ); + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_DEBUG, + ("After Init Session Object ref_cnt = %d\n", + p_srp_session->obj.ref_cnt) ); + if( cl_status != CL_SUCCESS ) + { + SRP_PRINT_EXIT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR, + ("cl_obj_init returned %#x\n", cl_status) ); + + cl_free( p_srp_session ); + p_srp_session = NULL; + *p_status = IB_ERROR; + goto exit; + } + + cl_obj_insert_rel( &p_srp_session->rel, + &p_srp_session->p_hba->obj, + &p_srp_session->obj ); + + SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_DEBUG, + ("After Insert Rel Session Object ref_cnt = %d\n", + p_srp_session->obj.ref_cnt) ); +exit: + SRP_EXIT( SRP_DBG_SESSION ); + + return ( p_srp_session ); +} + +/* srp_new_session */ +/*! +Orchestrates the connection process for a session to a target + +@param p_srp_session - pointer to the session to connect to the target + +@return - result of operation +*/ +ib_api_status_t +srp_session_login( + IN srp_session_t *p_srp_session ) +{ + ib_api_status_t status; + + SRP_ENTER( SRP_DBG_SESSION ); + + status = srp_init_hca( &p_srp_session->hca, p_srp_session->p_hba ); + if ( status != IB_SUCCESS ) + { + goto exit; + } + + status = srp_open_ca( &p_srp_session->hca, p_srp_session ); + if ( status != IB_SUCCESS ) + goto exit; + + status = srp_connect( &p_srp_session->connection, + &p_srp_session->hca, + (uint8_t)p_srp_session->p_hba->ioc_info.profile.send_msg_depth, + p_srp_session ); + +exit: + SRP_EXIT( SRP_DBG_SESSION ); + return ( status ); +} + +void +srp_session_failed( +IN srp_session_t* p_srp_session ) +{ + + SRP_ENTER( SRP_DBG_SESSION ); + + if( !p_srp_session ) + return; + + cl_obj_lock( &p_srp_session->obj ); + + if( p_srp_session->obj.state != CL_INITIALIZED ) + { + cl_obj_unlock( &p_srp_session->obj ); + return; + } + + if( p_srp_session->connection.state != SRP_CONNECT_FAILURE ) + { + cl_obj_unlock( &p_srp_session->obj ); + return; + } + p_srp_session->connection.state = SRP_CONNECTION_CLOSING; + + cl_obj_unlock( &p_srp_session->obj ); + + SRP_PRINT( TRACE_LEVEL_WARNING, SRP_DBG_DATA, + ("Session Idx %d failed\n", p_srp_session->target_id ) ); + + cl_event_signal( &p_srp_session->offload_event ); +} + +ib_api_status_t +srp_session_connect( + IN srp_hba_t *p_hba, + IN OUT p_srp_session_t *pp_srp_session, + IN UCHAR svc_idx ) +{ + ib_api_status_t ib_status; + srp_path_record_t *p_srp_path_rec; + srp_session_t *p_session; + uint64_t target_id_extension; + + SRP_ENTER( SRP_DBG_SESSION ); + + if( *pp_srp_session != NULL ) + { + return IB_ERROR; + } + + cl_spinlock_acquire( &p_hba->path_record_list_lock ); + if( !cl_qlist_count( &p_hba->path_record_list ) ) + { + cl_spinlock_release( &p_hba->path_record_list_lock ); + return IB_NOT_FOUND; + } + + p_srp_path_rec = (srp_path_record_t *)cl_qlist_head( &p_hba->path_record_list ); + + cl_spinlock_release( &p_hba->path_record_list_lock ); + + if( p_srp_path_rec == (srp_path_record_t *)cl_qlist_end( &p_hba->path_record_list ) ) + { + return IB_NOT_FOUND; + } + + ib_status = __srp_validate_service_entry( &p_hba->p_svc_entries[svc_idx], &target_id_extension ); + if( ib_status != IB_SUCCESS ) + { + SRP_PRINT( TRACE_LEVEL_WARNING, SRP_DBG_SESSION, + ("Failed validate service entry status %x\n", ib_status )); + return ib_status; + } + + p_session = srp_new_session( p_hba, + &p_hba->p_svc_entries[svc_idx], + &p_srp_path_rec->path_rec, + &ib_status ); + + if( ib_status != IB_SUCCESS || p_session == NULL ) + { + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_SESSION, + ("Failed create Session for SVC idx %d status %x\n", svc_idx, ib_status )); + + *pp_srp_session = NULL; + + return ib_status; + } + + ib_status = srp_session_login( p_session ); + if( ib_status != IB_SUCCESS ) + { + SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_SESSION, + ("Failed Session Login status %x\n", ib_status )); + + *pp_srp_session = NULL; + + cl_obj_destroy( &p_session->obj ); + + return ib_status; + } + srp_session_adjust_params( p_session ); + + cl_obj_lock( &p_hba->obj ); + + p_session->target_id = svc_idx; + + *pp_srp_session = p_session; + + cl_obj_unlock( &p_hba->obj ); + + + SRP_EXIT( SRP_DBG_SESSION ); + return ib_status; +} + +void +srp_session_adjust_params( + IN srp_session_t *p_session ) +{ + + if ( ( p_session->p_hba->max_sg > p_session->connection.max_scatter_gather_entries ) + && !( p_session->connection.descriptor_format & DBDF_INDIRECT_DATA_BUFFER_DESCRIPTORS) ) + { + p_session->p_hba->max_sg = p_session->connection.max_scatter_gather_entries; + } + + if ( p_session->p_hba->max_srb_ext_sz > p_session->connection.init_to_targ_iu_sz ) + { + p_session->p_hba->max_srb_ext_sz = + sizeof( srp_send_descriptor_t ) - + SRP_MAX_IU_SIZE + + p_session->connection.init_to_targ_iu_sz; + } +} + +static void +__srp_session_recovery( +IN srp_session_t* p_failed_session , +IN BOOLEAN reconnect_request ) +{ + ib_api_status_t ib_status; + srp_hba_t* p_hba; + srp_session_t* p_new; + srp_session_t* p_old; + UCHAR target_id; + int retry_count; + + SRP_ENTER( SRP_DBG_SESSION ); + + if( !p_failed_session ) + return; + if ( ( p_hba = p_failed_session->p_hba ) == NULL ) + return; + + p_old = p_failed_session; + target_id = p_old->target_id; + p_hba->session_list[target_id] = NULL; + + if( !reconnect_request ) + { + /* we're done here */ + SRP_PRINT( TRACE_LEVEL_WARNING, SRP_DBG_DATA, + ("Session Id: %d won't recover\n", p_old->target_id ) ); + cl_obj_destroy( &p_old->obj ); + return; + } + + if( !p_hba->session_paused[target_id] ) + { + p_hba->session_paused[target_id] = TRUE; + + StorPortDeviceBusy( p_hba->p_ext, + SP_UNTAGGED, + target_id, + SP_UNTAGGED, + (ULONG)-1 ); + } + + SRP_PRINT( TRACE_LEVEL_WARNING, SRP_DBG_DATA, + ("Pausing Adapter Session %d\n", target_id ) ); + + cl_obj_destroy( &p_old->obj ); + + for( retry_count=0; retry_count < 3 ; retry_count++ ) + { + ib_status = srp_session_connect( p_hba, &p_new, target_id ); + + if( ib_status != IB_SUCCESS ) + { + SRP_PRINT( TRACE_LEVEL_WARNING, SRP_DBG_DATA, + ("Failed session idx %d connect\n", target_id ) ); + + continue; + } + + p_hba->session_list[target_id] = p_new; + + SRP_PRINT( TRACE_LEVEL_WARNING, SRP_DBG_DATA, + ("Session idx %d connected. Resuming\n", target_id ) ); + + StorPortDeviceReady( p_hba->p_ext, + SP_UNTAGGED, + target_id, + SP_UNTAGGED ); + + p_hba->session_paused[target_id] = FALSE; + + return; + } + + /* what do we do now ? */ + SRP_PRINT( TRACE_LEVEL_WARNING, SRP_DBG_DATA, + ("Session idx %d recovery failed\n", target_id) ); + + return; +} + +void +srp_session_recovery_thread( + IN void* const context ) +{ + srp_session_t* p_session = (srp_session_t *)context; + cl_status_t status; + + if( p_session == NULL ) + return; + + cl_event_init( &p_session->offload_event, FALSE); + + status = cl_event_wait_on( &p_session->offload_event, EVENT_NO_TIMEOUT, FALSE ); + + __srp_session_recovery( p_session, !p_session->p_hba->adapter_stopped ); +} diff --git a/branches/WOF2-3/ulp/srp/kernel/srp_session.h b/branches/WOF2-3/ulp/srp/kernel/srp_session.h new file mode 100644 index 00000000..a0ee0365 --- /dev/null +++ b/branches/WOF2-3/ulp/srp/kernel/srp_session.h @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + + +#ifndef _SRP_SESSION_H_ +#define _SRP_SESSION_H_ + + +#include +#include +#include + +#include "srp_hba.h" +#include "srp_hca.h" +#include "srp_connection.h" +#include "srp_descriptors.h" + +/* Session information. */ +typedef struct _srp_session +{ + cl_obj_t obj; + cl_obj_rel_t rel; + + srp_hba_t *p_hba; + atomic32_t repost_is_on; + srp_hca_t hca; + srp_connection_t connection; + srp_descriptors_t descriptors; + + SCSI_REQUEST_BLOCK *p_shutdown_srb; + + /* keep session level SCSI address */ + UCHAR target_id; + cl_event_t offload_event; + cl_thread_t recovery_thread; + +#if DBG + /* statistics */ + + /* packets, built */ + uint64_t x_pkt_fmr; /* number of packets, mapped by fmr_pool */ + uint64_t x_pkt_built; /* number of packets, built */ + + /* request_limit_delta */ + int64_t x_rld_total; /* sum of req_limit_delta values */ + int32_t x_rld_num; /* number of req_limit_delta values */ + int32_t x_rld_max; /* max req_limit_delta value */ + int32_t x_rld_min; /* min req_limit_delta value */ + int32_t x_rld_zeroes; /* number of zeroes */ + + int32_t x_rld_zeroes_cur; /* number of zeroes */ + int32_t x_rld_zeroes_cur_min; /* number of zeroes */ + int32_t x_rld_busy_success; + int32_t x_rld_busy_fail; + + /* pending queue */ + uint64_t x_pend_total; /* sum of pending_descriptors queue sizes */ + uint32_t x_pend_num; /* number of pending_descriptors queue sizes */ + uint32_t x_pend_max; /* max pending_descriptors queue size */ + + /* pending queue */ + uint64_t x_sent_total; /* sum of sent_descriptors queue sizes */ + uint32_t x_sent_num; /* number of sent_descriptors queue sizes */ + uint32_t x_sent_max; /* max sent_descriptors queue size */ + + uint32_t x_req_limit; /* max number in-flight packets */ +#endif +} srp_session_t; + +srp_session_t* +srp_new_session( + IN srp_hba_t *p_hba, + IN ib_svc_entry_t *p_svc_entry, + IN ib_path_rec_t *p_path_rec, + OUT ib_api_status_t *p_status ); + +ib_api_status_t +srp_session_login( + IN srp_session_t *p_srp_session ); + +void +__srp_cleanup_session( + IN cl_obj_t *p_obj ); + +ib_api_status_t +srp_session_connect( + IN srp_hba_t *p_hba, + IN OUT p_srp_session_t *pp_srp_session, + IN UCHAR svc_idx ); + +void +srp_session_adjust_params( + IN srp_session_t *p_session ); + +void +srp_session_failed( +IN srp_session_t* p_srp_session ); + +void +srp_session_recovery_thread( +IN void* const context ); + +#endif /* _SRP_SESSION_H_ */ diff --git a/branches/WOF2-3/ulp/srp/kernel/srp_t_logout.h b/branches/WOF2-3/ulp/srp/kernel/srp_t_logout.h new file mode 100644 index 00000000..e284fbea --- /dev/null +++ b/branches/WOF2-3/ulp/srp/kernel/srp_t_logout.h @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#ifndef SRP_T_LOGOUT_H_INCLUDED +#define SRP_T_LOGOUT_H_INCLUDED + +#include "srp.h" +#include "srp_iu_buffer.h" +#include "srp_information_unit.h" + +/* set_srp_t_logout_tag */ +/*! +Sets the tag field of a target logout information unit + +@param p_information_unit - pointer to the IU structure +@param iu_tag - tag value of IU + +@return - none +*/ +static inline +void +set_srp_t_logout_tag( + IN OUT srp_t_logout_t *p_information_unit, + IN uint64_t iu_tag ) +{ + set_srp_information_unit_tag( ( srp_information_unit_t* ) p_information_unit, iu_tag ); +} + +/* init_srp_t_logout */ +/*! +Initializes the target logout IU to zeroes +and sets the IU type to Srp Target Logout +and sets the tag to the value supplied + +@param p_information_unit - pointer to the IU structure +@param iu_tag - tag value to be used for the req/rsp pair + +@return - none +*/ +static inline +void +init_srp_t_logout( + IN OUT srp_t_logout_t *p_information_unit, + IN uint64_t iu_tag ) +{ + init_srp_iu_buffer( ( srp_iu_buffer_t* ) p_information_unit, SRP_T_LOGOUT ) ; + set_srp_t_logout_tag( p_information_unit, iu_tag ); +} + +/* set_srp_t_logout_reason */ +/*! +Sets the reason for the target logout + +@param p_information_unit - pointer to the IU structure +@param reason - target logout reason code + +@return - none +*/ +static inline +void +set_srp_t_logout_reason( + IN OUT srp_t_logout_t *p_information_unit, + IN TARGET_LOGOUT_REASON_CODE reason ) +{ + p_information_unit->reason = reason; +} + +/* setup_srp_t_logout */ +/*! +Initializes and sets the Srp Target Logout IU to the values supplied + +@param p_information_unit - pointer to the IU structure +@param iu_tag - tag value to be used for the req/rsp pair + +@return - none +*/ +static inline +void +setup_srp_t_logout( + IN OUT srp_t_logout_t *p_information_unit, + IN uint64_t iu_tag, + IN TARGET_LOGOUT_REASON_CODE reason ) +{ + init_srp_t_logout( p_information_unit, iu_tag ); + set_srp_t_logout_reason( p_information_unit, reason ); +} + +/* get_srp_t_logout_tag */ +/*! +Returns the value of the tag field of a target logout + +@param p_information_unit - pointer to the IU structure + +@return - tag value +*/ +static inline +uint64_t +get_srp_t_logout_tag( + IN srp_t_logout_t *p_information_unit ) +{ + return( get_srp_information_unit_tag( ( srp_information_unit_t* ) p_information_unit ) ); +} + +/* get_srp_t_logout_reason */ +/*! +Returns the value of the reason code field of a target logout + +@param p_information_unit - pointer to the IU structure + +@return - reason code value +*/ +static inline +TARGET_LOGOUT_REASON_CODE +get_srp_t_logout_reason( + IN srp_t_logout_t *p_information_unit ) +{ + return( ( TARGET_LOGOUT_REASON_CODE ) p_information_unit->reason); +} + +/* get_srp_t_logout_length */ +/*! +Returns the size in bytes of the Srp Target Logout IU + +@param p_information_unit - pointer to the IU structure + +@return - tag value +*/ +static inline +uint32_t +get_srp_t_logout_length( + IN srp_t_logout_t *p_information_unit ) +{ + return( sizeof( *p_information_unit ) ); +} + +/* set_srp_t_logout_from_host_to_network */ +/*! +Swaps the IU fields from Host to Network ordering + +@param p_information_unit - pointer to the IU structure + +@return - none +*/ + +static inline +void +set_srp_t_logout_from_host_to_network( + IN OUT srp_t_logout_t *p_information_unit ) +{ + set_srp_information_unit_from_host_to_network( ( srp_information_unit_t* ) p_information_unit ); + p_information_unit->reason = cl_hton32( p_information_unit->reason ); +} + +/* set_srp_t_logout_from_network_to_host */ +/*! +Swaps the IU fields from Network to Host ordering + +@param p_information_unit - pointer to the IU structure + +@return - none +*/ + +static inline +void +set_srp_t_logout_from_network_to_host( + IN OUT srp_t_logout_t *p_information_unit ) +{ + set_srp_t_logout_from_host_to_network ( p_information_unit ); +} + +#endif /* SRP_T_LOGOUT_H_INCLUDED */ diff --git a/branches/WOF2-3/ulp/srp/kernel/srp_tsk_mgmt.h b/branches/WOF2-3/ulp/srp/kernel/srp_tsk_mgmt.h new file mode 100644 index 00000000..3eacd1c8 --- /dev/null +++ b/branches/WOF2-3/ulp/srp/kernel/srp_tsk_mgmt.h @@ -0,0 +1,276 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#ifndef SRP_TSK_MGMT_H_INCLUDED +#define SRP_TSK_MGMT_H_INCLUDED + +#include "srp.h" +#include "srp_iu_buffer.h" +#include "srp_information_unit.h" + +/* set_srp_tsk_mgmt_tag */ +/*! +Sets the tag field of a task management information unit + +@param p_information_unit - pointer to the IU structure +@param iu_tag - tag value of IU + +@return - none +*/ +static inline +void +set_srp_tsk_mgmt_tag( + IN OUT srp_tsk_mgmt_t *p_information_unit, + IN uint64_t iu_tag ) +{ + set_srp_information_unit_tag( ( srp_information_unit_t* ) p_information_unit, iu_tag ); +} + +/* init_srp_tsk_mgmt */ +/*! +Initializes the task management IU to zeroes +and sets the IU type to Srp Target Logout +and sets the tag to the value supplied + +@param p_information_unit - pointer to the IU structure +@param iu_tag - tag value to be used for the req/rsp pair + +@return - none +*/ +static inline +void +init_srp_tsk_mgmt( + IN OUT srp_tsk_mgmt_t *p_information_unit, + IN uint64_t iu_tag ) +{ + init_srp_iu_buffer( ( srp_iu_buffer_t* ) p_information_unit, SRP_TSK_MGMT ) ; + set_srp_tsk_mgmt_tag( p_information_unit, iu_tag ); +} + +/* set_srp_tsk_mgmt_logical_unit_number */ +/*! +Sets the logical unit number for the task management request IU + +@param p_information_unit - pointer to the IU structure +@param logical_unit_number - logical unit number + +@return - none +*/ +static inline +void +set_srp_tsk_mgmt_logical_unit_number( + IN OUT srp_tsk_mgmt_t *p_information_unit, + IN uint64_t logical_unit_number ) +{ + p_information_unit->logical_unit_number = logical_unit_number; +} + +/* set_srp_tsk_mgmt_task_management_flags */ +/*! +Sets the task management flags for a task management IU + +@param p_information_unit - pointer to the IU structure +@param task_management_flags - logical unit number + +@return - none +*/ +static inline +void +set_srp_tsk_mgmt_task_management_flags( + IN OUT srp_tsk_mgmt_t *p_information_unit, + IN uint8_t task_management_flags ) +{ + p_information_unit->task_management_flags = task_management_flags; +} + +/* set_srp_tsk_mgmt_managed_task_tag */ +/*! +Sets the task management flags for a task management IU + +@param p_information_unit - pointer to the IU structure +@param managed_task_tag - id of task to be managed + +@return - none +*/ +static inline +void +set_srp_tsk_mgmt_managed_task_tag( + IN OUT srp_tsk_mgmt_t *p_information_unit, + IN uint64_t managed_task_tag ) +{ + p_information_unit->managed_task_tag = managed_task_tag; +} + +/* setup_srp_tsk_mgmt */ +/*! +Initializes and sets the Srp Task Management IU to the values supplied + +@param p_information_unit - pointer to the IU structure +@param iu_tag - tag value to be used for the req/rsp pair +@param logical_unit_number - logical unit number +@param task_management_flags - logical unit number +@param managed_task_tag - id of task to be managed + +@return - none +*/ +static inline +void +setup_srp_tsk_mgmt( + IN OUT srp_tsk_mgmt_t *p_information_unit, + IN uint64_t iu_tag, + IN uint64_t logical_unit_number, + IN uint8_t task_management_flags, + IN uint64_t managed_task_tag ) +{ + init_srp_tsk_mgmt( p_information_unit, iu_tag ); + set_srp_tsk_mgmt_logical_unit_number( p_information_unit, logical_unit_number ); + set_srp_tsk_mgmt_task_management_flags( p_information_unit, task_management_flags ); + set_srp_tsk_mgmt_managed_task_tag( p_information_unit, managed_task_tag ); +} + +/* get_srp_tsk_mgmt_tag */ +/*! +Returns the value of the tag field of a task management iu + +@param p_information_unit - pointer to the IU structure + +@return - tag value +*/ +static inline +uint64_t +get_srp_tsk_mgmt_tag( + IN srp_tsk_mgmt_t *p_information_unit ) +{ + return( get_srp_information_unit_tag( ( srp_information_unit_t* ) p_information_unit ) ); +} + +/* get_srp_tsk_mgmt_logical_unit_number */ +/*! +Returns the value of the logical unit number field of a task management iu + +@param p_information_unit - pointer to the IU structure + +@return - logical unit number +*/ +static inline +uint64_t +get_srp_tsk_mgmt_logical_unit_number( + IN srp_tsk_mgmt_t *p_information_unit ) +{ + return( p_information_unit->logical_unit_number ); +} + +/* get_srp_tsk_mgmt_task_management_flags */ +/*! +Returns the value of the task management flags field of a task management iu + +@param p_information_unit - pointer to the IU structure + +@return - task management flags +*/ +static inline +uint8_t +get_srp_tsk_mgmt_task_management_flags( + IN srp_tsk_mgmt_t *p_information_unit ) +{ + return( p_information_unit->task_management_flags ); +} + +/* get_srp_tsk_mgmt_managed_task_tag */ +/*! +Returns the value of the managed task tag field of a task management iu + +@param p_information_unit - pointer to the IU structure + +@return - managed task tag +*/ +static inline +uint64_t +get_srp_tsk_mgmt_managed_task_tag( + IN srp_tsk_mgmt_t *p_information_unit ) +{ + return( p_information_unit->managed_task_tag ); +} + +/* get_srp_tsk_mgmt_length */ +/*! +Returns the size in bytes of the Srp Task Management IU + +@param p_information_unit - pointer to the IU structure + +@return - tag value +*/ +static inline +uint32_t +get_srp_tsk_mgmt_length( + IN srp_tsk_mgmt_t *p_information_unit ) +{ + return( sizeof( *p_information_unit ) ); +} + +/* set_srp_tsk_mgmt_from_host_to_network */ +/*! +Swaps the IU fields from Host to Network ordering + +@param p_information_unit - pointer to the IU structure + +@return - none +*/ + +static inline +void +set_srp_tsk_mgmt_from_host_to_network( + IN OUT srp_tsk_mgmt_t *p_information_unit ) +{ + set_srp_information_unit_from_host_to_network( ( srp_information_unit_t* ) p_information_unit ); + p_information_unit->logical_unit_number = cl_hton64( p_information_unit->logical_unit_number ); + p_information_unit->managed_task_tag = cl_hton64( p_information_unit->managed_task_tag ); +} + +/* set_srp_tsk_mgmt_from_network_to_host */ +/*! +Swaps the IU fields from Network To Host ordering + +@param p_information_unit - pointer to the IU structure + +@return - none +*/ + +static inline +void +set_srp_tsk_mgmt_from_network_to_host( + IN OUT srp_tsk_mgmt_t *p_information_unit ) +{ + set_srp_tsk_mgmt_from_host_to_network ( p_information_unit ); +} + +#endif /* SRP_TSK_MGMT_H_INCLUDED */ diff --git a/branches/WOF2-3/ulp/wsd/dirs b/branches/WOF2-3/ulp/wsd/dirs new file mode 100644 index 00000000..389156fd --- /dev/null +++ b/branches/WOF2-3/ulp/wsd/dirs @@ -0,0 +1,2 @@ +DIRS=\ + user diff --git a/branches/WOF2-3/ulp/wsd/user/README b/branches/WOF2-3/ulp/wsd/user/README new file mode 100644 index 00000000..dd75d261 --- /dev/null +++ b/branches/WOF2-3/ulp/wsd/user/README @@ -0,0 +1,38 @@ +TODO +==== + +- use pd_handle or pd, but be consistent. + +- try to inline FindSocketContext and more. + +- use more than one wqc with ib_poll_cq. + +- I think WSPRecv can be called before the connection is +established. Therefore the check of the state of the socket is +incorrect. + +- protect the socket state transition. Use a function to check for +valid transitions? + +- finish to fillup ibsp_pnp.c to manage dynamic IP addresses. + +- ib_cm_rep can be sent synchronously. Should solve the accept dilema. + +- some error paths are leaking ressources, esp IBSPAccept + +- socket_info_list is not protected + +- it might be possible to not get a completion event when the event bit is not set -> optimization. Disable sollicitation bit in that case. + +- duplicating listen socket is not implemented. Is that possible? Will the switch do it? + +- replace listen.mutex by mutex? + +- maybe create a pool of created qps to speedup connections? Or keep existing QPs in a pool after the are moved to RESET. + +- is it a good idea to hold socket_info->mutex while calling CM? + +- do something about socket_info->port->hca + + + diff --git a/branches/WOF2-3/ulp/wsd/user/SOURCES b/branches/WOF2-3/ulp/wsd/user/SOURCES new file mode 100644 index 00000000..8672f54c --- /dev/null +++ b/branches/WOF2-3/ulp/wsd/user/SOURCES @@ -0,0 +1,63 @@ +TARGETNAME=ibwsd +TARGETPATH=..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE=DYNLINK +DLLENTRY=DllMain +DLLDEF=ibspdll.def +USE_NTDLL=1 + +!if $(FREEBUILD) +ENABLE_EVENT_TRACING=1 +!endif + + +SOURCES=\ + ibspdll.rc \ + extensions.c \ + ib_cm.c \ + ibsp_iblow.c \ + ibsp_ip.c \ + ibsp_mem.c \ + ibsp_pnp.c \ + ibspdebug.c \ + ibspdll.c \ + misc.c \ + sockinfo.c \ + ibsp_duplicate.c \ + ibsp_perfmon.c + +INCLUDES=..\..\..\inc;..\..\..\inc\user;$(DDK_INC_PATH); + +USER_C_FLAGS=$(USER_C_FLAGS) -DCL_NO_TRACK_MEM -DPERFMON_ENABLED -DWPP_OLDCC + + +TARGETLIBS=\ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\Advapi32.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ + $(SDK_LIB_PATH)\iphlpapi.lib \ + $(SDK_LIB_PATH)\rpcrt4.lib \ + $(SDK_LIB_PATH)\LoadPerf.lib \ + $(TARGETPATH)\*\ibat.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\complib.lib \ + $(TARGETPATH)\*\ibal.lib +!else + $(TARGETPATH)\*\complibd.lib \ + $(TARGETPATH)\*\ibald.lib +!endif + +!IFDEF ENABLE_EVENT_TRACING + +C_DEFINES = $(C_DEFINES) -DEVENT_TRACING + +RUN_WPP= $(SOURCES) -ext: .c .h -dll \ + -scan:ibspdebug.h\ + -func:IBSP_PRINT(LEVEL,FLAGS,(MSG,...)) \ + -func:IBSP_PRINT_EXIT(LEVEL,FLAGS,(MSG,...)) \ + -func:IBSP_ERROR{LEVEL=TRACE_LEVEL_ERROR,FLAGS=IBSP_DBG_ERROR}((MSG,...)) \ + -func:IBSP_ERROR_EXIT{LEVEL=TRACE_LEVEL_ERROR,FLAGS=IBSP_DBG_ERROR}((MSG,...)) + +!ENDIF + + +MSC_WARNING_LEVEL= /W4 diff --git a/branches/WOF2-3/ulp/wsd/user/extensions.c b/branches/WOF2-3/ulp/wsd/user/extensions.c new file mode 100644 index 00000000..cebf3bc6 --- /dev/null +++ b/branches/WOF2-3/ulp/wsd/user/extensions.c @@ -0,0 +1,651 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2006 Mellanox Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include "ibspdebug.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "extensions.tmh" +#endif + +#include "ibspdll.h" + + +/* Function: IBSPRegisterMemory + * Description: + * Registers buffer memory + */ +HANDLE WSPAPI +IBSPRegisterMemory( + IN SOCKET s, + IN PVOID lpBuffer, + IN DWORD dwBufferLength, + IN DWORD dwFlags, + OUT LPINT lpErrno ) +{ + struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s; + ib_access_t access_ctrl; + struct memory_node *node; + + IBSP_ENTER( IBSP_DBG_MEM ); + + fzprint(("%s():%d:0x%x:0x%x: socket=0x%p \n", __FUNCTION__, + __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s)); + + if( lpBuffer == NULL ) + { + IBSP_ERROR_EXIT( ( "invalid buffer %p\n", lpBuffer ) ); + *lpErrno = WSAEFAULT; + return NULL; + } + + if( dwBufferLength > socket_info->socket_options.max_msg_size ) + { + IBSP_ERROR_EXIT( ( "invalid buffer length %d\n", dwBufferLength ) ); + *lpErrno = WSAEFAULT; + return NULL; + } + + switch( dwFlags ) + { + case MEM_READ: + access_ctrl = 0; + break; + + case MEM_WRITE: + access_ctrl = IB_AC_LOCAL_WRITE; + break; + + case MEM_READWRITE: + access_ctrl = IB_AC_LOCAL_WRITE; + break; + + default: + IBSP_ERROR_EXIT( ("invalid flags %x\n", dwFlags) ); + *lpErrno = WSAEINVAL; + return NULL; + } + + node = ibsp_reg_mem( socket_info, socket_info->hca_pd, + lpBuffer, dwBufferLength, access_ctrl, lpErrno ); + + fzprint(("%s():%d:0x%x:0x%x: registering MEM from %p to %p, len %d, handle %p\n", + __FUNCTION__, __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), + lpBuffer, (unsigned char *)lpBuffer + dwBufferLength, dwBufferLength, node)); + + + if( node == NULL ) + { + IBSP_ERROR( ("ibsp_reg_mem failed (pd=%p)\n", socket_info->hca_pd) ); + *lpErrno = WSAENOBUFS; + } + else + { + IBSP_PRINT(TRACE_LEVEL_INFORMATION, + IBSP_DBG_MEM, ("returning node %p\n", node) ); + *lpErrno = 0; + } + + IBSP_EXIT( IBSP_DBG_MEM ); + + return (HANDLE) node; +} + +/* Function: IBSPDeregisterMemory + * Description: + * This is our provider's DeregisterMemory function. + */ +int WSPAPI +IBSPDeregisterMemory( + IN SOCKET s, + IN HANDLE handle, + OUT LPINT lpErrno ) +{ + struct memory_node *node = handle; + struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s; + int ret; + + IBSP_ENTER( IBSP_DBG_MEM ); + + fzprint(("%s():%d:0x%x:0x%x: handle=0x%p socket=0x%p \n", __FUNCTION__, + __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), handle, s)); + + if( s == INVALID_SOCKET ) + { + IBSP_ERROR_EXIT( ("invalid socket handle %Ix\n", s) ); + *lpErrno = WSAENOTSOCK; + return SOCKET_ERROR; + } + + ret = ibsp_dereg_mem( socket_info, node, lpErrno ); + + fzprint(("%s():%d:0x%x:0x%x: unregistering MEM %p, mr_num=%d, ret=%d\n", + __FUNCTION__, + __LINE__, GetCurrentProcessId(), + GetCurrentThreadId(), node, g_ibsp.mr_num, ret)); + + IBSP_EXIT( IBSP_DBG_MEM ); + return ret; +} + +/* Function: IBSPRegisterRdmaMemory + * Description: + * This is our provider's RegisterRdmaMemory function. +*/ +int WSPAPI +IBSPRegisterRdmaMemory( + IN SOCKET s, + IN PVOID lpBuffer, + IN DWORD dwBufferLength, + IN DWORD dwFlags, + OUT LPVOID lpRdmaBufferDescriptor, + IN OUT LPDWORD lpdwDescriptorLength, + OUT LPINT lpErrno ) +{ + struct memory_node *node2; + struct rdma_memory_desc *desc; + struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s; + ib_access_t access_ctrl; + struct ibsp_hca *hca; + + IBSP_ENTER( IBSP_DBG_MEM ); + + fzprint(("%s():%d:0x%x:0x%x: socket=0x%p \n", __FUNCTION__, + __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s)); + + if( *lpdwDescriptorLength < sizeof(struct rdma_memory_desc) ) + { + /* This is the probe from the switch to learn the length of the descriptor. */ + IBSP_ERROR_EXIT( ("invalid descriptor length %d (usually not an error)\n", + *lpdwDescriptorLength) ); + *lpdwDescriptorLength = sizeof(struct rdma_memory_desc); + *lpErrno = WSAEFAULT; + return SOCKET_ERROR; + } + + if( lpBuffer == NULL ) + { + IBSP_ERROR_EXIT( ("invalid buffer %p\n", lpBuffer) ); + *lpErrno = WSAEFAULT; + return SOCKET_ERROR; + } + + if( dwBufferLength > socket_info->socket_options.max_msg_size ) + { + IBSP_ERROR_EXIT( ("invalid buffer length %d\n", dwBufferLength) ); + *lpErrno = WSAEFAULT; + return SOCKET_ERROR; + } + + switch( dwFlags ) + { + case MEM_READ: + access_ctrl = IB_AC_RDMA_READ; + break; + + case MEM_WRITE: + access_ctrl = IB_AC_LOCAL_WRITE | IB_AC_RDMA_WRITE; + break; + + case MEM_READWRITE: + access_ctrl = IB_AC_LOCAL_WRITE | IB_AC_RDMA_READ | IB_AC_RDMA_WRITE; + break; + + default: + IBSP_ERROR_EXIT( ("invalid flags %x\n", dwFlags) ); + *lpErrno = WSAEINVAL; + return SOCKET_ERROR; + } + + hca = socket_info->port->hca; + + /** TODO: Fix locking so we dont' dereference node outside of mutex. */ + node2 = ibsp_reg_mem( socket_info, hca->pd, + lpBuffer, dwBufferLength, access_ctrl, lpErrno ); + + if( !node2 ) + { + IBSP_ERROR_EXIT( ("ibsp_reg_mem failed %d\n", *lpErrno) ); + *lpErrno = WSAENOBUFS; + return SOCKET_ERROR; + } + + desc = lpRdmaBufferDescriptor; + + desc->iova = (uint64_t) (uintptr_t) lpBuffer; + desc->lkey = node2->p_reg1->lkey; + desc->rkey = node2->p_reg1->rkey; + desc->node1 = node2; + + *lpErrno = 0; + + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_MEM, + ("Socket %Ix registered RDMA MEM at %p, len %d, for access %d, " + "returning handle %p, rkey %08x\n", + s, lpBuffer, dwBufferLength, dwFlags, node2, desc->rkey)); + + + IBSP_EXIT( IBSP_DBG_MEM ); + + return 0; +} + +/* Function: IBSPDeregisterRdmaMemory + * Description: + * This is our provider's DeregisterRdmaMemory function. + */ +int WSPAPI +IBSPDeregisterRdmaMemory( + IN SOCKET s, + IN LPVOID lpRdmaBufferDescriptor, + IN DWORD dwDescriptorLength, + OUT LPINT lpErrno ) +{ + struct rdma_memory_desc *desc; + struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s; + int ret; + + IBSP_ENTER( IBSP_DBG_MEM ); + + fzprint(("%s():%d:0x%x:0x%x: socket=0x%p \n", __FUNCTION__, + __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s)); + + if( s == INVALID_SOCKET ) + { + /* Seen in real life with overlap/client test. + * The switch closes a socket then calls this. Why? */ + IBSP_ERROR_EXIT( ("invalid socket handle %Ix\n", s) ); + *lpErrno = WSAENOTSOCK; + return SOCKET_ERROR; + } + + CL_ASSERT( lpRdmaBufferDescriptor ); + + if( dwDescriptorLength < sizeof(struct rdma_memory_desc) ) + { + IBSP_ERROR_EXIT( ("invalid descriptor length %d)\n", dwDescriptorLength) ); + *lpErrno = WSAEINVAL; + return SOCKET_ERROR; + } + + desc = lpRdmaBufferDescriptor; + + ret = ibsp_dereg_mem( socket_info, desc->node1, lpErrno ); + + fzprint(("%s():%d:0x%x:0x%x: Unregistering RDMA MEM %p\n", + __FUNCTION__, __LINE__, GetCurrentProcessId(), + GetCurrentThreadId(), desc->node)); + + IBSP_EXIT( IBSP_DBG_MEM ); + return ret; +} + + +/* + * Do a RDMA read or write operation since the code for both is very close. + */ +static int +do_rdma_op( + IN SOCKET s, + IN LPWSABUFEX lpBuffers, + IN DWORD dwBufferCount, + IN LPVOID lpTargetBufferDescriptor, + IN DWORD dwTargetDescriptorLength, + IN DWORD dwTargetBufferOffset, + IN LPWSAOVERLAPPED lpOverlapped, + IN ib_wr_type_t wr_type, + OUT LPINT lpErrno ) +{ + struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s; + ib_api_status_t status; + struct rdma_memory_desc *desc; /* remote descriptor */ + struct _wr *wr; + ib_send_wr_t send_wr; + ib_local_ds_t local_ds[QP_ATTRIB_SQ_SGE]; + DWORD ds_idx; + + IBSP_ENTER( IBSP_DBG_IO ); + + CL_ASSERT( wr_type == WR_RDMA_WRITE || wr_type == WR_RDMA_READ ); + + cl_spinlock_acquire( &socket_info->mutex1 ); + switch( socket_info->socket_state ) + { + case IBSP_CONNECTED: + case IBSP_DISCONNECTED: + break; + + default: + cl_spinlock_release( &socket_info->mutex1 ); + IBSP_ERROR_EXIT( ("Socket is not in connected socket_state state=%s\n", + IBSP_SOCKET_STATE_STR( socket_info->socket_state )) ); + *lpErrno = WSAENOTCONN; + return SOCKET_ERROR; + } + cl_spinlock_release( &socket_info->mutex1 ); + + if( socket_info->qp_error ) + { + IBSP_ERROR_EXIT( ("QP is in error state %d\n", socket_info->qp_error) ); + *lpErrno = socket_info->qp_error; + return SOCKET_ERROR; + } + + /* This function only works for that case. */ + if( dwBufferCount > QP_ATTRIB_SQ_SGE ) + { + CL_ASSERT( dwBufferCount <= QP_ATTRIB_SQ_SGE ); + /* TODO - support splitting large requests into multiple RDMA operations. */ + IBSP_ERROR_EXIT( + ("dwBufferCount is greater than %d\n", QP_ATTRIB_SQ_SGE) ); + *lpErrno = WSAEINVAL; + return SOCKET_ERROR; + } + + if( dwTargetDescriptorLength != sizeof(struct rdma_memory_desc) ) + { + IBSP_ERROR_EXIT( ( + "invalid descriptor length %d)\n", dwTargetDescriptorLength) ); + *lpErrno = WSAEINVAL; + return SOCKET_ERROR; + } + + desc = lpTargetBufferDescriptor; + + /* The send lock is only used to serialize posting. */ + cl_spinlock_acquire( &socket_info->send_lock ); + if( socket_info->send_cnt == QP_ATTRIB_SQ_DEPTH ) + { + /* TODO: queue requests. */ + cl_spinlock_release( &socket_info->send_lock ); + IBSP_ERROR_EXIT( ("not enough wr on the free list\n") ); + *lpErrno = WSAENETDOWN; + return SOCKET_ERROR; + } + + wr = &socket_info->send_wr[socket_info->send_idx]; + + wr->lpOverlapped = lpOverlapped; + wr->socket_info = socket_info; + + /* Format the send work request and post. */ + send_wr.p_next = NULL; + send_wr.wr_id = (ULONG_PTR)wr; + send_wr.wr_type = wr_type; + send_wr.send_opt = 0; + send_wr.num_ds = dwBufferCount; + send_wr.ds_array = local_ds; + + send_wr.remote_ops.vaddr = desc->iova + dwTargetBufferOffset; + send_wr.remote_ops.rkey = desc->rkey; + + lpOverlapped->InternalHigh = 0; + for( ds_idx = 0; ds_idx < dwBufferCount; ds_idx++ ) + { + local_ds[ds_idx].vaddr = (ULONG_PTR)lpBuffers[ds_idx].buf; + local_ds[ds_idx].length = lpBuffers[ds_idx].len; + local_ds[ds_idx].lkey = + ((struct memory_node*)lpBuffers[ds_idx].handle)->p_reg1->lkey; + + lpOverlapped->InternalHigh += lpBuffers[ds_idx].len; + } + + if( wr_type == WR_RDMA_READ ) + { + /* + * Next send must be fenced since it could indicate that this + * RDMA READ is complete. + */ + socket_info->send_opt = IB_SEND_OPT_FENCE; + } + else if( lpOverlapped->InternalHigh <= socket_info->max_inline ) + { + send_wr.send_opt |= IB_SEND_OPT_INLINE; + } + + /* + * We must set this now, because the operation could complete + * before ib_post_send returns. + */ + lpOverlapped->Internal = WSS_OPERATION_IN_PROGRESS; + + cl_atomic_inc( &socket_info->send_cnt ); + +#ifdef _DEBUG_ + if( lpOverlapped->hEvent == 0 ) + { + cl_atomic_inc( &g_ibsp.overlap_h0_count ); + } + else + { + cl_atomic_inc( &g_ibsp.overlap_h1_count ); + cl_atomic_inc( &g_ibsp.overlap_h1_comp_count ); + } + + fzprint(("%s():%d:0x%x:0x%x: ov=0x%p h0_cnt=%d h1_cnt=%d\n", + __FUNCTION__, __LINE__, GetCurrentProcessId(), + GetCurrentThreadId(), lpOverlapped, + g_ibsp.overlap_h0_count, g_ibsp.overlap_h1_count)); + +#endif + + status = ib_post_send( socket_info->qp, &send_wr, NULL ); + + if( status == IB_SUCCESS ) + { + /* Update the index and wrap as needed */ +#if QP_ATTRIB_SQ_DEPTH == 256 || QP_ATTRIB_SQ_DEPTH == 128 || \ + QP_ATTRIB_SQ_DEPTH == 64 || QP_ATTRIB_SQ_DEPTH == 32 || \ + QP_ATTRIB_SQ_DEPTH == 16 || QP_ATTRIB_SQ_DEPTH == 8 + socket_info->send_idx++; + socket_info->send_idx &= (QP_ATTRIB_SQ_DEPTH - 1); +#else + if( ++socket_info->send_idx == QP_ATTRIB_SQ_DEPTH ) + socket_info->send_idx = 0; +#endif + + *lpErrno = WSA_IO_PENDING; + + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_IO, + ("Posted RDMA: socket=%Ix, ov=%p, type=%d, local=%p, len=%d, " + "dest=%016I64x, rkey=%08x\n", + s, lpOverlapped, wr_type, lpBuffers[0].buf, lpBuffers[0].len, + send_wr.remote_ops.vaddr, send_wr.remote_ops.rkey) ); + + fzprint(("posted RDMA %p, len=%d, op=%d, mr handle=%p\n", + lpOverlapped, lpBuffers[0].len, wr_type, node)); + } + else + { + IBSP_ERROR( ("ib_post_send returned %s\n", ib_get_err_str( status )) ); + +#ifdef _DEBUG_ + + if( lpOverlapped->hEvent == 0 ) + { + cl_atomic_dec( &g_ibsp.overlap_h0_count ); + } + else + { + cl_atomic_dec( &g_ibsp.overlap_h1_count ); + cl_atomic_dec( &g_ibsp.overlap_h1_comp_count ); + } + + memset( wr, 0x44, sizeof(struct _wr) ); +#endif + cl_atomic_dec( &socket_info->send_cnt ); + + *lpErrno = ibal_to_wsa_error( status ); + } + + cl_spinlock_release( &socket_info->send_lock ); + + /* We never complete the operation here. */ + IBSP_EXIT( IBSP_DBG_IO ); + return SOCKET_ERROR; +} + + +/* Function: IBSPRdmaWrite + Description: + This is our provider's RdmaWrite function. When an app calls WSAIoctl + to request the function pointer to RdmaWrite, we return pointer to this + function and this function is called by application directly using the function pointer. +*/ +int WSPAPI +IBSPRdmaWrite( + IN SOCKET s, + IN LPWSABUFEX lpBuffers, + IN DWORD dwBufferCount, + IN LPVOID lpTargetBufferDescriptor, + IN DWORD dwTargetDescriptorLength, + IN DWORD dwTargetBufferOffset, + OUT LPDWORD lpdwNumberOfBytesWritten, + IN DWORD dwFlags, + IN LPWSAOVERLAPPED lpOverlapped, + IN LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine, + IN LPWSATHREADID lpThreadId, + OUT LPINT lpErrno ) +{ + int ret; + + IBSP_ENTER( IBSP_DBG_IO ); + + UNUSED_PARAM( lpThreadId ); + UNUSED_PARAM( lpCompletionRoutine ); + UNUSED_PARAM( lpdwNumberOfBytesWritten ); + + if( s == INVALID_SOCKET ) + { + IBSP_ERROR_EXIT( ("invalid socket handle %Ix\n", s) ); + *lpErrno = WSAENOTSOCK; + return SOCKET_ERROR; + } + + fzprint(("%s():%d:0x%x:0x%x: socket=0x%p overlapped=0x%p\n", __FUNCTION__, + __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s, lpOverlapped)); + + /* Store the flags for reporting back in IBSPGetOverlappedResult */ + lpOverlapped->Offset = dwFlags; + + ret = do_rdma_op( s, lpBuffers, dwBufferCount, lpTargetBufferDescriptor, + dwTargetDescriptorLength, dwTargetBufferOffset, + lpOverlapped, WR_RDMA_WRITE, lpErrno ); + + IBSP_EXIT( IBSP_DBG_IO ); + + return ret; +} + + +/* Function: IBSPRdmaRead + Description: + This is our provider's RdmaRead function. When an app calls WSAIoctl + to request the function pointer to RdmaRead, we return pointer to this + function and this function is called by application directly using the function pointer. +*/ +int WSPAPI +IBSPRdmaRead( + IN SOCKET s, + IN LPWSABUFEX lpBuffers, + IN DWORD dwBufferCount, + IN LPVOID lpTargetBufferDescriptor, + IN DWORD dwTargetDescriptorLength, + IN DWORD dwTargetBufferOffset, + OUT LPDWORD lpdwNumberOfBytesRead, + IN DWORD dwFlags, + IN LPWSAOVERLAPPED lpOverlapped, + IN LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine, + IN LPWSATHREADID lpThreadId, + OUT LPINT lpErrno ) +{ + int ret; + + IBSP_ENTER( IBSP_DBG_IO ); + + UNUSED_PARAM( lpThreadId ); + UNUSED_PARAM( lpCompletionRoutine ); + UNUSED_PARAM( lpdwNumberOfBytesRead ); + + fzprint(("%s():%d:0x%x:0x%x: socket=0x%p overlapped=0x%p \n", __FUNCTION__, + __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s, lpOverlapped)); + + /* Store the flags for reporting back in IBSPGetOverlappedResult */ + lpOverlapped->Offset = dwFlags; + + ret = do_rdma_op( s, lpBuffers, dwBufferCount, lpTargetBufferDescriptor, + dwTargetDescriptorLength, dwTargetBufferOffset, + lpOverlapped, WR_RDMA_READ, lpErrno ); + + IBSP_EXIT( IBSP_DBG_IO ); + + return ret; +} + + +/* Function: IBSPMemoryRegistrationCacheCallback + * Description: + * This is our provider's MemoryRegistrationCacheCallback + * function. When an app calls WSAIoctl to request the function + * pointer to MemoryRegistrationCacheCallback, we return pointer to + * this function and this function is called by application directly + * using the function pointer. + */ +int WSPAPI +IBSPMemoryRegistrationCacheCallback( + IN LPVOID lpvAddress, + IN SIZE_T Size, + OUT LPINT lpErrno ) +{ + cl_list_item_t *p_item; + + IBSP_ENTER( IBSP_DBG_MEM ); + + UNUSED_PARAM( lpErrno ); + + cl_spinlock_acquire( &g_ibsp.hca_mutex ); + for( p_item = cl_qlist_head( &g_ibsp.hca_list ); + p_item != cl_qlist_end( &g_ibsp.hca_list ); + p_item = cl_qlist_next( p_item ) ) + { + ibsp_hca_flush_mr_cache( + PARENT_STRUCT( p_item, struct ibsp_hca, item ), lpvAddress, Size ); + } + cl_spinlock_release( &g_ibsp.hca_mutex ); + + IBSP_EXIT( IBSP_DBG_MEM ); + return 0; +} diff --git a/branches/WOF2-3/ulp/wsd/user/ib_cm.c b/branches/WOF2-3/ulp/wsd/user/ib_cm.c new file mode 100644 index 00000000..7965c244 --- /dev/null +++ b/branches/WOF2-3/ulp/wsd/user/ib_cm.c @@ -0,0 +1,991 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2006 Mellanox Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ +#include "ibspdebug.h" +#if defined(EVENT_TRACING) +#include "ib_cm.tmh" +#endif + +#include "ibspdll.h" + +static void AL_API cm_req_callback(IN ib_cm_req_rec_t * p_cm_req_rec); +static void AL_API cm_rep_callback(IN ib_cm_rep_rec_t * p_cm_rep_rec); +static void AL_API cm_rtu_callback(IN ib_cm_rtu_rec_t * p_cm_rtu_rec); +static void AL_API cm_rej_callback(IN ib_cm_rej_rec_t * p_cm_rej_rec); +static void AL_API cm_mra_callback(IN ib_cm_mra_rec_t * p_cm_mra_rec); +static void AL_API cm_dreq_callback(IN ib_cm_dreq_rec_t * p_cm_dreq_rec); +void AL_API cm_apr_callback(IN ib_cm_apr_rec_t * p_cm_apr_rec); + + +/* Computes a service ID for a port. */ +static inline ib_net64_t +get_service_id_for_port( + ib_net16_t ip_port) +{ + return BASE_LISTEN_ID | ip_port; +} + + +/* Signals a select event to the switch. */ +void +ibsp_post_select_event( + struct ibsp_socket_info *socket_info, + int event, + int error ) +{ + HANDLE h_event; + + IBSP_ENTER( IBSP_DBG_NEV ); + + CL_ASSERT( socket_info ); + CL_ASSERT( event ); + + switch( event ) + { + case FD_CONNECT: + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_NEV, + ("socket %p FD_CONNECT\n", socket_info) ); + socket_info->errno_connect = error; + break; + + case FD_ACCEPT: + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_NEV, + ("socket %p FD_ACCEPT\n", socket_info) ); + break; + + default: + CL_ASSERT( 0 ); + break; + } + + _InterlockedOr( &socket_info->network_events, event ); + + h_event = InterlockedCompareExchangePointer( + &socket_info->event_select, NULL, NULL ); + /* Check for event notification request and signal as needed. */ + if( (socket_info->event_mask & event) && h_event ) + { + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_NEV, + ("Signaling eventHandle %p at time %I64d.\n", + h_event, cl_get_time_stamp() ) ); + SetEvent( h_event ); + } + + IBSP_EXIT( IBSP_DBG_NEV ); +} + + +/* + * A user-specified callback that is invoked after receiving a connection + * request message (REQ). + */ +static void AL_API +cm_req_callback( + IN ib_cm_req_rec_t *p_cm_req_rec ) +{ + struct ibsp_socket_info *socket_info = + (struct ibsp_socket_info *)p_cm_req_rec->context; + struct listen_incoming *incoming; + + IBSP_ENTER( IBSP_DBG_CM ); + + CL_ASSERT( socket_info ); + CL_ASSERT( p_cm_req_rec->p_req_pdata ); + + cl_spinlock_acquire( &socket_info->mutex1 ); + + switch( socket_info->socket_state ) + { + case IBSP_LISTEN: + if( cl_qlist_count( &socket_info->listen.list ) >= + socket_info->listen.backlog ) + { + /* Already too many connection requests are queued */ + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_CM, + ("already too many incoming connections, rejecting\n") ); + ib_reject( p_cm_req_rec->h_cm_req, IB_REJ_USER_DEFINED ); + break; + } + + incoming = HeapAlloc( g_ibsp.heap, 0, sizeof(struct listen_incoming) ); + if( !incoming ) + { + /* Low on memory. */ + IBSP_ERROR( ("HeapAlloc failed, rejecting\n") ); + ib_reject( p_cm_req_rec->h_cm_req, IB_REJ_INSUF_RESOURCES ); + IBSP_EXIT( IBSP_DBG_CM ); + return; + } + + incoming->cm_req_received = *p_cm_req_rec; + cl_memcpy( &incoming->params, p_cm_req_rec->p_req_pdata, + sizeof(struct cm_req_params) ); + incoming->cm_req_received.p_req_pdata = (const uint8_t*)&incoming->params; + + /* Add to the waiting list */ + cl_qlist_insert_tail( &socket_info->listen.list, &incoming->item ); + + ibsp_post_select_event( socket_info, FD_ACCEPT, 0 ); + break; + + case IBSP_DUPLICATING_REMOTE: + { + int ret; + + /* Non-blocking cancel since we're in CM callback context */ + ib_cm_cancel( socket_info->listen.handle, NULL ); + socket_info->listen.handle = NULL; + cl_spinlock_release( &socket_info->mutex1 ); + + wait_cq_drain( socket_info ); + + cl_spinlock_acquire( &socket_info->mutex1 ); + ret = ib_accept( socket_info, p_cm_req_rec ); + if( ret ) + { + cl_spinlock_release( &socket_info->mutex1 ); + IBSP_ERROR( ( + "ib_accept for duplicate socket returned %d, rejecting\n", + ret) ); + /* Call ib_destroy_socket for above ib_create_socket() call */ + ib_destroy_socket( socket_info ); + ib_reject( p_cm_req_rec->h_cm_req, IB_REJ_USER_DEFINED ); + ibsp_dup_overlap_abort( socket_info ); + IBSP_EXIT( IBSP_DBG_CM ); + return; + } + } + break; + + default: + IBSP_ERROR( ("socket is not listening anymore\n") ); + /* We're closing down - let some other listen match. */ + ib_reject( p_cm_req_rec->h_cm_req, IB_REJ_INVALID_SID ); + break; + } + + cl_spinlock_release( &socket_info->mutex1 ); + + IBSP_EXIT( IBSP_DBG_CM ); +} + + +/* + * A user-specified callback that is invoked after receiving a connection + * request reply message (REP). + */ +static void AL_API +cm_rep_callback( + IN ib_cm_rep_rec_t *p_cm_rep_rec ) +{ + struct ibsp_socket_info *socket_info = + (struct ibsp_socket_info *)p_cm_rep_rec->qp_context; + ib_cm_rtu_t cm_rtu; + ib_api_status_t status; + + IBSP_ENTER( IBSP_DBG_CM ); + + memset( &cm_rtu, 0, sizeof(cm_rtu) ); + + cm_rtu.access_ctrl = IB_AC_RDMA_READ | IB_AC_RDMA_WRITE | IB_AC_LOCAL_WRITE; +#if 0 + // Bug in TAVOR + cm_rtu.sq_depth = QP_ATTRIB_SQ_DEPTH; + cm_rtu.rq_depth = QP_ATTRIB_RQ_DEPTH; +#endif + cm_rtu.pfn_cm_apr_cb = cm_apr_callback; + cm_rtu.pfn_cm_dreq_cb = cm_dreq_callback; + + cl_spinlock_acquire( &socket_info->mutex1 ); + + switch( socket_info->socket_state ) + { + case IBSP_CONNECT: + status = ib_cm_rtu( p_cm_rep_rec->h_cm_rep, &cm_rtu ); + if( status != IB_SUCCESS ) + { + /* Note: a REJ has been automatically sent. */ + IBSP_ERROR( ("ib_cm_rtu returned %s\n", ib_get_err_str( status )) ); + IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_BIND ); + + /* We changed the state - remove from connection map. */ + ibsp_conn_remove( socket_info ); + + ibsp_post_select_event( socket_info, FD_CONNECT, WSAETIMEDOUT ); + } + else + { + IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_CONNECTED ); + ibsp_post_select_event( socket_info, FD_CONNECT, 0 ); + } + break; + + case IBSP_DUPLICATING_NEW: + status = ib_cm_rtu( p_cm_rep_rec->h_cm_rep, &cm_rtu ); + if( status != IB_SUCCESS ) + { + IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_BIND ); + + /* We changed the state - remove from connection map. */ + ibsp_conn_remove( socket_info ); + + /* Note: a REJ has been automatically sent. */ + IBSP_ERROR( ("ib_cm_rtu returned %s\n", ib_get_err_str( status )) ); + } + else + { + IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_CONNECTED ); + } + SetEvent( socket_info->h_event ); + break; + + default: + /* The socket might be closing */ + IBSP_ERROR( ("socket %p not in connecting state (%s)\n", + socket_info, IBSP_SOCKET_STATE_STR( socket_info->socket_state )) ); + + ib_reject( p_cm_rep_rec->h_cm_rep, IB_REJ_USER_DEFINED ); + } + + cl_spinlock_release( &socket_info->mutex1 ); + + IBSP_EXIT( IBSP_DBG_CM ); +} + + +/* + * A user-specified callback that is invoked after receiving a connection + * ready to use message (RTU). + */ +static void AL_API +cm_rtu_callback( + IN ib_cm_rtu_rec_t *p_cm_rtu_rec ) +{ + struct ibsp_socket_info *socket_info = + (struct ibsp_socket_info *)p_cm_rtu_rec->qp_context; + + IBSP_ENTER( IBSP_DBG_CM ); + + cl_spinlock_acquire( &socket_info->mutex1 ); + + if( socket_info->socket_state == IBSP_DUPLICATING_REMOTE ) + { + struct _recv_wr *wr; + ib_api_status_t status; + uint8_t idx; + + /* Repost all the WR to the new QP */ + cl_spinlock_acquire( &socket_info->recv_lock ); + + while( socket_info->dup_cnt ) + { + if( (socket_info->recv_cnt + socket_info->dup_cnt) > + QP_ATTRIB_RQ_DEPTH ) + { + CL_ASSERT( (socket_info->recv_cnt + socket_info->dup_cnt) <= + QP_ATTRIB_RQ_DEPTH ); + /* TODO: Flag the socket as having failed. */ + break; + } + + + /* Figure out the starting index in the duplicate array. */ + idx = socket_info->dup_idx - (uint8_t)socket_info->dup_cnt; + if( idx >= QP_ATTRIB_RQ_DEPTH ) + { + /* The duplicates wrap over the end of the array. */ + idx += QP_ATTRIB_RQ_DEPTH; + } + + /* + * Copy the duplicate work request from the duplicate array + * to the receive array. + */ + socket_info->recv_wr[socket_info->recv_idx] = + socket_info->dup_wr[idx]; + + wr = &socket_info->recv_wr[socket_info->recv_idx]; + + /* Update the work request ID. */ + wr->recv.wr_id = (ULONG_PTR)wr; + + /* + * Increment the count before posting so it doesn't go + * negative in the completion path. + */ + cl_atomic_inc( &socket_info->recv_cnt ); + + status = ib_post_recv( socket_info->qp, &wr->recv, NULL ); + + if( status == IB_SUCCESS ) + { + /* Update the index and wrap as needed */ +#if QP_ATTRIB_RQ_DEPTH == 256 || QP_ATTRIB_RQ_DEPTH == 128 || \ + QP_ATTRIB_RQ_DEPTH == 64 || QP_ATTRIB_RQ_DEPTH == 32 || \ + QP_ATTRIB_RQ_DEPTH == 16 || QP_ATTRIB_RQ_DEPTH == 8 + socket_info->recv_idx++; + socket_info->recv_idx &= (QP_ATTRIB_RQ_DEPTH - 1); +#else + if( ++socket_info->recv_idx == QP_ATTRIB_RQ_DEPTH ) + socket_info->recv_idx = 0; +#endif + + cl_atomic_dec( &socket_info->dup_cnt ); + } + else + { + IBSP_ERROR( ( + "ib_post_recv returned %s for reposted buffer\n", + ib_get_err_str( status )) ); + + cl_atomic_dec( &socket_info->recv_cnt ); + CL_ASSERT( status == IB_SUCCESS ); + /* TODO: Flag the socket as having failed. */ + break; + } + } + + cl_spinlock_release( &socket_info->recv_lock ); + + socket_info->qp_error = 0; + IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_CONNECTED ); + } + else if( socket_info->socket_state != IBSP_CONNECTED ) + { + /* The Socket might be closing */ + IBSP_ERROR( ("Got RTU while in socket_state %s - ignoring\n", + IBSP_SOCKET_STATE_STR( socket_info->socket_state )) ); + } + + cl_spinlock_release( &socket_info->mutex1 ); + + IBSP_EXIT( IBSP_DBG_CM ); +} + + +/* Force the QP to error state to flush posted work requests. */ +static inline void +__flush_qp( + IN struct ibsp_socket_info *p_socket ) +{ + ib_qp_mod_t qp_mod; + ib_api_status_t status; + + memset( &qp_mod, 0, sizeof(qp_mod) ); + qp_mod.req_state = IB_QPS_ERROR; + status = ib_modify_qp( p_socket->qp, &qp_mod ); + if( status != IB_SUCCESS ) + { + IBSP_ERROR( ("ib_modify_qp returned %s\n", ib_get_err_str( status )) ); + p_socket->send_cnt = 0; + p_socket->recv_cnt = 0; + } +} + + +/* + * A user-specified callback that is invoked after receiving a connection + * rejection message (REJ). + */ +static void AL_API +cm_rej_callback( + IN ib_cm_rej_rec_t *p_cm_rej_rec ) +{ + struct ibsp_socket_info *socket_info = + (struct ibsp_socket_info *)p_cm_rej_rec->qp_context; + + IBSP_ENTER( IBSP_DBG_CM ); + + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_CM, ("socket %p connect reject, reason=%d\n", + socket_info, cl_ntoh16(p_cm_rej_rec->rej_status)) ); + + cl_spinlock_acquire( &socket_info->mutex1 ); + + switch( socket_info->socket_state ) + { + case IBSP_CONNECT: + /* Remove from connection map. */ + ibsp_conn_remove( socket_info ); + + IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_BIND ); + if( p_cm_rej_rec->rej_status == IB_REJ_TIMEOUT ) + ibsp_post_select_event( socket_info, FD_CONNECT, WSAETIMEDOUT ); + else + ibsp_post_select_event( socket_info, FD_CONNECT, WSAECONNREFUSED ); + break; + + case IBSP_CONNECTED: + /* + * DISCONNECTED is a terminal state. We'll remove the connection + * when the socket gets destroyed. + */ + IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_DISCONNECTED ); + + socket_info->qp_error = WSAECONNABORTED; + + __flush_qp( socket_info ); + break; + + case IBSP_DUPLICATING_NEW: + /* Leave in that state. IBSPSocket will eventually return + * an error becaus the socket is not connected. */ + ibsp_conn_remove( socket_info ); + SetEvent( socket_info->h_event ); + break; + + default: + IBSP_ERROR( ("socket %p got an REJ reason %d in state %s\n", + socket_info, cl_ntoh16( p_cm_rej_rec->rej_status ), + IBSP_SOCKET_STATE_STR(socket_info->socket_state)) ); + break; + } + + cl_spinlock_release( &socket_info->mutex1 ); + + IBSP_EXIT( IBSP_DBG_CM ); +} + + +/* + * A user-specified callback that is invoked after receiving a message + * received acknowledgement. + */ +static void AL_API +cm_mra_callback( + IN ib_cm_mra_rec_t *p_cm_mra_rec ) +{ + /* TODO */ + IBSP_ENTER( IBSP_DBG_CM ); + + UNUSED_PARAM( p_cm_mra_rec ); + + IBSP_EXIT( IBSP_DBG_CM ); +} + + +/* + * A user-specified callback that is invoked after receiving a disconnect + * request message (DREQ). + */ +static void AL_API +cm_dreq_callback( + IN ib_cm_dreq_rec_t *p_cm_dreq_rec ) +{ + ib_api_status_t status; + ib_cm_drep_t cm_drep; + struct disconnect_reason *reason; + struct ibsp_socket_info *socket_info = + (struct ibsp_socket_info *)p_cm_dreq_rec->qp_context; + + IBSP_ENTER( IBSP_DBG_CM ); + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_CM, + ("socket=%p state=%s\n", + socket_info, IBSP_SOCKET_STATE_STR( socket_info->socket_state )) ); + + reason = (struct disconnect_reason *)p_cm_dreq_rec->p_dreq_pdata; + + cl_spinlock_acquire( &socket_info->mutex1 ); + + if( socket_info->socket_state == IBSP_CONNECTED ) + { + switch( reason->type ) + { + case DISC_DUPLICATING: + { + int ret; + + IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_DUPLICATING_REMOTE ); + socket_info->qp_error = -1; + socket_info->duplicate.identifier = reason->duplicating.identifier; + socket_info->duplicate.dwProcessId = reason->duplicating.dwProcessId; + + /* Now, setup our listening callback. */ + socket_info->listen.listen_req_param.dwProcessId = + reason->duplicating.dwProcessId; + socket_info->listen.listen_req_param.identifier = + reason->duplicating.identifier; + + ret = ib_listen( socket_info ); + if( !ret ) + { + /* We changed the state - remove from connection map. */ + ibsp_conn_remove( socket_info ); + break; + } + + IBSP_ERROR_EXIT( ("ib_listen failed with %d\n", ret) ); + /* Fall through. */ + } + default: + /* Right now, treat anything as a normal disconnect. */ + IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_DISCONNECTED ); + /* + * DISCONNECTED is a terminal state. We'll remove the connection + * when the socket gets destroyed. + */ + socket_info->qp_error = WSAECONNRESET; + } + + memset( &cm_drep, 0, sizeof(cm_drep) ); + + status = ib_cm_drep( p_cm_dreq_rec->h_cm_dreq, &cm_drep ); + if( status != IB_SUCCESS ) + IBSP_ERROR( ("ib_cm_drep returned %s\n", ib_get_err_str( status )) ); + } + cl_spinlock_release( &socket_info->mutex1 ); + + IBSP_EXIT( IBSP_DBG_CM ); +} + + +/* + * A user-specified callback that is invoked after receiving a disconnect + * reply message. + */ +static void AL_API +cm_drep_callback( + IN ib_cm_drep_rec_t *p_cm_drep_rec ) +{ + IBSP_ENTER( IBSP_DBG_CM ); + UNUSED_PARAM( p_cm_drep_rec ); + IBSP_EXIT( IBSP_DBG_CM ); +} + + +/* + * A user-specified callback that is invoked after receiving a load + * alternate path response message. + */ +void AL_API +cm_apr_callback( + IN ib_cm_apr_rec_t *p_cm_apr_rec ) +{ + struct ibsp_socket_info *socket_info = + (struct ibsp_socket_info *)p_cm_apr_rec->qp_context; + + IBSP_ENTER( IBSP_DBG_CM ); + + IBSP_PRINT_EXIT(TRACE_LEVEL_INFORMATION, IBSP_DBG_APM, ("cm_apr_callback called p_cm_apr_rec->cm_status = %d\n", p_cm_apr_rec->cm_status) ); + + cl_spinlock_acquire( &g_ibsp.socket_info_mutex ); + CL_ASSERT(socket_info->apm_state == APM_LAP_SENT); + + if ((p_cm_apr_rec->cm_status == IB_SUCCESS) && + (p_cm_apr_rec->apr_status == IB_SUCCESS)){ + socket_info->apm_state = APM_ARMED; + socket_info->SuccesfulMigrations++; + } else { + socket_info->apm_state = APM_MIGRATED; + } + cl_spinlock_release( &g_ibsp.socket_info_mutex ); + + + + + IBSP_EXIT( IBSP_DBG_CM ); +} + + +/* + * A user-specified callback that is invoked after receiving a load + * alternate path message. + * + * SYNOPSIS + */ +static void AL_API +cm_lap_callback( + IN ib_cm_lap_rec_t *p_cm_lap_rec ) +{ + ib_cm_apr_t cm_apr; + struct ibsp_socket_info *socket_info = + (struct ibsp_socket_info *)p_cm_lap_rec->qp_context; + + ib_api_status_t status; + + IBSP_ENTER( IBSP_DBG_CM ); + + IBSP_PRINT_EXIT(TRACE_LEVEL_INFORMATION, IBSP_DBG_APM, ("called \n") ); + + + cl_memclr(&cm_apr, sizeof(cm_apr)); + cm_apr.qp_type = IB_QPT_RELIABLE_CONN; + cm_apr.h_qp = socket_info->qp; + + + status = ib_cm_apr(p_cm_lap_rec->h_cm_lap, &cm_apr); + if( status != IB_SUCCESS ) { + // Actually not much that we can do at this stage. + // The other side will get timeout and retry + CL_ASSERT(FALSE); + IBSP_ERROR( ("ib_cm_apr returned %s\n", ib_get_err_str( status )) ); + } + + + IBSP_EXIT( IBSP_DBG_CM ); +} + + +/* Listen for an incoming connection. */ +int +ib_listen( + IN struct ibsp_socket_info *socket_info ) +{ + ib_cm_listen_t param; + ib_api_status_t status; + + IBSP_ENTER( IBSP_DBG_CM ); + + memset( ¶m, 0, sizeof(param) ); + + param.svc_id = get_service_id_for_port( socket_info->local_addr.sin_port ); + if( socket_info->port ) + { + /* The socket is bound to an IP address */ + param.ca_guid = socket_info->port->hca->guid; + param.port_guid = socket_info->port->guid; + } + else + { + /* The socket is bound to INADDR_ANY */ + param.ca_guid = IB_ALL_CAS; + param.port_guid = IB_ALL_PORTS; + } + param.lid = IB_ALL_LIDS; + + param.p_compare_buffer = (uint8_t *) & socket_info->listen.listen_req_param; + param.compare_length = sizeof(struct listen_req_param); + param.compare_offset = offsetof(struct cm_req_params, listen_req_param); + + fzprint(("%s():%d:0x%x:0x%x: socket=0x%p params: %x %x\n", __FUNCTION__, + __LINE__, GetCurrentProcessId(), + GetCurrentThreadId(), socket_info, + socket_info->listen.listen_req_param.dwProcessId, + socket_info->listen.listen_req_param.identifier)); + + param.pfn_cm_req_cb = cm_req_callback; + + param.qp_type = IB_QPT_RELIABLE_CONN; + + status = ib_cm_listen( g_ibsp.al_handle, ¶m, socket_info, /* context */ + &socket_info->listen.handle ); + + if( status != IB_SUCCESS ) + { + IBSP_ERROR_EXIT( ("ib_cm_listen failed (0x%d)\n", status) ); + return ibal_to_wsa_error( status ); + } + + STAT_INC( listen_num ); + + IBSP_PRINT_EXIT(TRACE_LEVEL_INFORMATION, IBSP_DBG_CM, + ("started listening for port %d\n", + CL_HTON16( socket_info->local_addr.sin_port )) ); + + return 0; +} + + +/* Reject all the queued incoming connection requests. */ +void +ib_listen_backlog( + IN struct ibsp_socket_info *socket_info, + IN int backlog ) +{ + cl_list_item_t *item; + struct listen_incoming *incoming; + + socket_info->listen.backlog = backlog; + + while( + cl_qlist_count( &socket_info->listen.list ) > (uint32_t)backlog ) + { + item = cl_qlist_remove_tail( &socket_info->listen.list ); + + incoming = PARENT_STRUCT(item, struct listen_incoming, item); + + ib_reject( incoming->cm_req_received.h_cm_req, IB_REJ_USER_DEFINED ); + + HeapFree( g_ibsp.heap, 0, incoming ); + } +} + + +/* Stop listening on the socket. */ +void +ib_listen_cancel( + IN struct ibsp_socket_info *socket_info ) +{ + ib_api_status_t status; + + IBSP_ENTER( IBSP_DBG_CM ); + + status = ib_cm_cancel( socket_info->listen.handle, ib_sync_destroy ); + if( status ) + { + IBSP_ERROR( ( + "ib_cm_cancel returned %s\n", ib_get_err_str( status )) ); + } + else + { + STAT_DEC( listen_num ); + } + + /* We can empty the queue now. Since we are closing, + * no new entry will be added. */ + cl_spinlock_acquire( &socket_info->mutex1 ); + ib_listen_backlog( socket_info, 0 ); + cl_spinlock_release( &socket_info->mutex1 ); + + socket_info->listen.handle = NULL; + + IBSP_EXIT( IBSP_DBG_CM ); +} + + +int +ib_connect( + IN struct ibsp_socket_info *socket_info, + IN ib_path_rec_t *path_rec, + IN ib_path_rec_t *alt_path_rec ) + +{ + ib_cm_req_t cm_req; + ib_api_status_t status; + struct cm_req_params params; + + IBSP_ENTER( IBSP_DBG_CM ); + + fzprint(("%s():%d:0x%x:0x%x: socket=0x%p \n", __FUNCTION__, + __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), socket_info)); + + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_CM, ("From:\n") ); + DebugPrintSockAddr( IBSP_DBG_CM, &socket_info->local_addr ); + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_CM, ("To:\n") ); + DebugPrintSockAddr( IBSP_DBG_CM, &socket_info->peer_addr ); + + /* Insert into the connection map. */ + if( !ibsp_conn_insert( socket_info ) ) + { + IBSP_EXIT( IBSP_DBG_CM ); + return WSAEADDRINUSE; + } + + memset( &cm_req, 0, sizeof(cm_req) ); + + cm_req.svc_id = get_service_id_for_port( socket_info->peer_addr.sin_port ); + cm_req.max_cm_retries = g_max_cm_retries; + cm_req.p_primary_path = path_rec; + cm_req.p_alt_path = alt_path_rec; + cm_req.pfn_cm_rep_cb = cm_rep_callback; + + cm_req.p_req_pdata = (uint8_t *) & params; + params.source = socket_info->local_addr; + params.dest = socket_info->peer_addr; + params.listen_req_param.dwProcessId = socket_info->duplicate.dwProcessId; + params.listen_req_param.identifier = socket_info->duplicate.identifier; + + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_CM, + ("ib_connect listen params: %x \n", params.listen_req_param.dwProcessId + /*params.listen_req_param.identifier*/)); + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_CM, + ("connecting to port %d, SID=%016I64x\n", socket_info->peer_addr.sin_port, + cm_req.svc_id) ); + + cm_req.req_length = sizeof(struct cm_req_params); + + cm_req.qp_type = IB_QPT_RELIABLE_CONN; + cm_req.h_qp = socket_info->qp; + cm_req.resp_res = QP_ATTRIB_RESPONDER_RESOURCES; + cm_req.init_depth = QP_ATTRIB_INITIATOR_DEPTH; + + cm_req.remote_resp_timeout = + ib_path_rec_pkt_life( path_rec ) + CM_REMOTE_TIMEOUT; + if( cm_req.remote_resp_timeout > 0x1F ) + cm_req.remote_resp_timeout = 0x1F; + else if( cm_req.remote_resp_timeout < CM_MIN_REMOTE_TIMEOUT ) + cm_req.remote_resp_timeout = CM_MIN_REMOTE_TIMEOUT; + + cm_req.flow_ctrl = TRUE; /* HCAs must support end-to-end flow control. */ + + cm_req.local_resp_timeout = + ib_path_rec_pkt_life( path_rec ) + CM_LOCAL_TIMEOUT; + if( cm_req.local_resp_timeout > 0x1F ) + cm_req.local_resp_timeout = 0x1F; + else if( cm_req.local_resp_timeout < CM_MIN_LOCAL_TIMEOUT ) + cm_req.local_resp_timeout = CM_MIN_LOCAL_TIMEOUT; + + cm_req.rnr_nak_timeout = QP_ATTRIB_RNR_NAK_TIMEOUT; + cm_req.rnr_retry_cnt = QP_ATTRIB_RNR_RETRY; + cm_req.retry_cnt = g_qp_retries; + cm_req.pfn_cm_mra_cb = cm_mra_callback; + cm_req.pfn_cm_rej_cb = cm_rej_callback; + + status = ib_cm_req( &cm_req ); + if( status != IB_SUCCESS ) + { + /* Remove from connection map. */ + ibsp_conn_remove( socket_info ); + + IBSP_ERROR_EXIT( ("ib_cm_req failed (0x%d)\n", status) ); + return WSAEHOSTUNREACH; + } + + IBSP_EXIT( IBSP_DBG_CM ); + /* Operation is pending */ + return WSAEWOULDBLOCK; +} + + +void +ib_reject( + IN const ib_cm_handle_t h_cm, + IN const ib_rej_status_t rej_status ) +{ + ib_cm_rej_t cm_rej; + ib_api_status_t status; + + IBSP_ENTER( IBSP_DBG_CM ); + + memset( &cm_rej, 0, sizeof(cm_rej) ); + cm_rej.rej_status = rej_status; + + status = ib_cm_rej( h_cm, &cm_rej ); + if( status != IB_SUCCESS ) + IBSP_ERROR( ("ib_cm_rej returned %s\n", ib_get_err_str( status )) ); + + IBSP_EXIT( IBSP_DBG_CM ); +} + + +int +ib_accept( + IN struct ibsp_socket_info *socket_info, + IN ib_cm_req_rec_t *cm_req_received ) +{ + ib_cm_rep_t cm_rep; + ib_api_status_t status; + + IBSP_ENTER( IBSP_DBG_CM ); + + /* Insert into the connection map. */ + if( !ibsp_conn_insert( socket_info ) ) + { + IBSP_EXIT( IBSP_DBG_CM ); + return WSAEADDRINUSE; + } + + memset( &cm_rep, 0, sizeof(cm_rep) ); + + cm_rep.qp_type = IB_QPT_RELIABLE_CONN; + cm_rep.h_qp = socket_info->qp; + cm_rep.access_ctrl = IB_AC_RDMA_READ | IB_AC_RDMA_WRITE | IB_AC_LOCAL_WRITE; +#if 0 + // Bug in TAVOR + cm_rep.sq_depth = QP_ATTRIB_SQ_DEPTH; + cm_rep.rq_depth = QP_ATTRIB_RQ_DEPTH; +#endif + cm_rep.init_depth = QP_ATTRIB_INITIATOR_DEPTH; + cm_rep.target_ack_delay = 10; + cm_rep.failover_accepted = g_use_APM ? IB_FAILOVER_ACCEPT_SUCCESS : IB_FAILOVER_ACCEPT_UNSUPPORTED; + cm_rep.flow_ctrl = cm_req_received->flow_ctrl; + cm_rep.rnr_nak_timeout = QP_ATTRIB_RNR_NAK_TIMEOUT; + cm_rep.rnr_retry_cnt = cm_req_received->rnr_retry_cnt; + cm_rep.pfn_cm_mra_cb = cm_mra_callback; + cm_rep.pfn_cm_rej_cb = cm_rej_callback; + cm_rep.pfn_cm_rtu_cb = cm_rtu_callback; + cm_rep.pfn_cm_lap_cb = cm_lap_callback; + cm_rep.pfn_cm_dreq_cb = cm_dreq_callback; + + fzprint(("%s():%d:0x%x:0x%x: flow_ctrl=%d rnr_retry_cnt=%d\n", __FUNCTION__, + __LINE__, GetCurrentProcessId(), + GetCurrentThreadId(), cm_rep.flow_ctrl, cm_rep.rnr_retry_cnt)); + + status = ib_cm_rep( cm_req_received->h_cm_req, &cm_rep ); + if( status != IB_SUCCESS ) + { + /* Remove from connection map. */ + ibsp_conn_remove( socket_info ); + + IBSP_ERROR_EXIT( ("ib_cm_rep failed (0x%s) at time %I64d\n", + ib_get_err_str( status ), cl_get_time_stamp()) ); + return WSAEACCES; + } + + IBSP_EXIT( IBSP_DBG_CM ); + return 0; +} + + +void +ib_disconnect( + IN struct ibsp_socket_info *socket_info, + IN struct disconnect_reason *reason ) +{ + ib_api_status_t status; + ib_cm_dreq_t cm_dreq; + + IBSP_ENTER( IBSP_DBG_CM ); + + memset( &cm_dreq, 0, sizeof(cm_dreq) ); + + cm_dreq.qp_type = IB_QPT_RELIABLE_CONN; + cm_dreq.h_qp = socket_info->qp; + cm_dreq.pfn_cm_drep_cb = cm_drep_callback; + + cm_dreq.p_dreq_pdata = (uint8_t *) reason; + cm_dreq.dreq_length = sizeof(struct disconnect_reason); + + status = ib_cm_dreq( &cm_dreq ); + + /* + * If both sides initiate disconnection, we might get + * an invalid state or handle here. + */ + if( status != IB_SUCCESS && status != IB_INVALID_STATE && + status != IB_INVALID_HANDLE ) + { + IBSP_ERROR( ("ib_cm_dreq returned %s\n", ib_get_err_str( status )) ); + } + + /* + * Note that we don't care about getting the DREP - we move the QP to the + * error state now and flush all posted work requests. If the + * disconnection was graceful, we'll only have the pre-posted receives to + * flush. If the disconnection is ungraceful, we don't care if we + * interrupt transfers. + */ + + /* Move the QP to error to flush any work requests. */ + __flush_qp( socket_info ); + + IBSP_EXIT( IBSP_DBG_CM ); +} diff --git a/branches/WOF2-3/ulp/wsd/user/ibsp_duplicate.c b/branches/WOF2-3/ulp/wsd/user/ibsp_duplicate.c new file mode 100644 index 00000000..0a5d35a9 --- /dev/null +++ b/branches/WOF2-3/ulp/wsd/user/ibsp_duplicate.c @@ -0,0 +1,343 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2006 Mellanox Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include "ibspdebug.h" +#if defined(EVENT_TRACING) + +#include "ibsp_duplicate.tmh" +#endif + +#include "ibspdll.h" +#include "rpc.h" + + +/* +http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/using_shared_memory_in_a_dynamic_link_library.asp +*/ + + +static void +create_name( + OUT char *fname, + IN const DWORD dwProcessId, + IN const GUID *p_guid ) +{ + sprintf( fname, "Global\\%s-WSD-%08lx-" + "%08lx-%04hx-%04hx-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x", + VER_PROVIDER, dwProcessId, p_guid->Data1, p_guid->Data2, p_guid->Data3, + (int)p_guid->Data4[0], (int)p_guid->Data4[1], + (int)p_guid->Data4[2], (int)p_guid->Data4[3], + (int)p_guid->Data4[4], (int)p_guid->Data4[5], + (int)p_guid->Data4[6], (int)p_guid->Data4[7] ); +} + + +/* Create a duplicated socket. param is given by the other process through the + * lpProtocolInfo->dwProviderReserved field. + * This function is called by the next-controlling process. */ +int +setup_duplicate_socket( + IN struct ibsp_socket_info *socket_info, + IN HANDLE h_dup_info ) +{ + int ret, err; + struct ibsp_duplicate_info *dup_info; + ib_net64_t dest_port_guid; + ib_path_rec_t path_rec; + ib_path_rec_t alt_path_rec, *palt_path_rec = NULL; + + IBSP_ENTER( IBSP_DBG_DUP ); + + CL_ASSERT( socket_info->socket_state == IBSP_CREATE ); + + /* Get a pointer to the file-mapped shared memory. */ + dup_info = MapViewOfFile( h_dup_info, FILE_MAP_READ, 0, 0, 0 ); + if( dup_info == NULL ) + { + IBSP_ERROR( ("MapViewOfFile failed with %d\n", GetLastError()) ); + ret = WSAENETDOWN; + goto err1; + } + + socket_info->peer_addr = dup_info->peer_addr; + socket_info->local_addr = dup_info->local_addr; + socket_info->socket_options = dup_info->socket_options; + socket_info->duplicate.dwProcessId = dup_info->dwProcessId; + socket_info->duplicate.identifier = dup_info->identifier; + + socket_info->port = get_port_from_ip_address( dup_info->local_addr.sin_addr ); + if( socket_info->port == NULL ) + { + IBSP_ERROR( ("incoming destination IP address not local (%s)\n", + inet_ntoa( dup_info->local_addr.sin_addr )) ); + ret = WSAENETDOWN; + goto err1; + } + + /* Get the GUID for the remote IP address. */ + ret = query_guid_address( + (struct sockaddr*)&socket_info->local_addr, + (struct sockaddr*)&socket_info->peer_addr, + &dest_port_guid ); + if( ret ) + { + IBSP_ERROR( ("query_guid_address failed for IP %08x\n", + socket_info->peer_addr.sin_addr.s_addr) ); + ret = WSAENETDOWN; + goto err1; + } + + /* Get the path record */ + ret = query_pr( socket_info->port->guid, dest_port_guid, socket_info->port->hca->dev_id, &path_rec ); + if( ret ) + { + IBSP_ERROR( ("query_pr failed for IP %08x\n", + socket_info->peer_addr.sin_addr.s_addr) ); + ret = WSAENETDOWN; + goto err1; + } + /* Get the alternate path record */ + if (g_use_APM) + { + ret = query_pr(GetOtherPortGuid(socket_info->port->guid), GetOtherPortGuid(dest_port_guid), socket_info->port->hca->dev_id, &alt_path_rec ); + if( ret ) + { + // We can ignore a failure here, since APM is not a MUST + IBSP_ERROR( ("QPR for alternate path failed (error ignored)\n") ); + } + else + { + palt_path_rec = &alt_path_rec; + } + } + + + IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_DUPLICATING_NEW ); + socket_info->h_event = CreateEvent( NULL, FALSE, FALSE, NULL ); + if( !socket_info->h_event ) + { + IBSP_ERROR( ("CreateEvent failed (%d)\n", GetLastError()) ); + goto err1; + } + + ret = ib_create_socket( socket_info ); + if( ret ) + { + IBSP_ERROR( ("ib_create socket failed with %d\n", ret) ); + goto err1; + } + + /* Connects the QP. */ + ret = ib_connect( socket_info, &path_rec, palt_path_rec ); + if( ret != WSAEWOULDBLOCK ) + { + IBSP_ERROR( ("ib_connect failed (%d)\n", ret) ); + goto err2; + } + + if( WaitForSingleObject( socket_info->h_event, INFINITE ) != WAIT_OBJECT_0 ) + IBSP_ERROR( ("WaitForSingleObject failed\n") ); + + cl_spinlock_acquire( &socket_info->mutex1 ); + if( socket_info->socket_state != IBSP_CONNECTED ) + { + cl_spinlock_release( &socket_info->mutex1 ); + IBSP_ERROR( ("Failed to connect\n") ); + ret = WSAENETDOWN; +err2: + g_ibsp.up_call_table.lpWPUCloseSocketHandle( + socket_info->switch_socket, &err ); + socket_info->switch_socket = INVALID_SOCKET; + STAT_DEC( wpusocket_num ); + + ib_destroy_socket( socket_info ); + } + else + { + ret = 0; + cl_spinlock_release( &socket_info->mutex1 ); + } + +err1: + if( socket_info->h_event ) + { + CloseHandle( socket_info->h_event ); + socket_info->h_event = NULL; + } + + CloseHandle( h_dup_info ); + + IBSP_EXIT( IBSP_DBG_DUP ); + return ret; +} + + +/* Function: IBSPDuplicateSocket + + Description: + This function provides a WSAPROTOCOL_INFOW structure which can be passed + to another process to open a handle to the same socket. First we need + to translate the user socket into the provider socket and call the underlying + WSPDuplicateSocket. Note that the lpProtocolInfo structure passed into us + is an out parameter only! +*/ +int WSPAPI +IBSPDuplicateSocket( + SOCKET s, + DWORD dwProcessId, + LPWSAPROTOCOL_INFOW lpProtocolInfo, + LPINT lpErrno ) +{ + struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s; + struct ibsp_duplicate_info *dup_info = NULL; + char fname[100]; + GUID guid; + HANDLE h_dup_info, h_target_process, h_target_dup_info; + struct disconnect_reason reason; + + IBSP_ENTER( IBSP_DBG_DUP ); + + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_DUP, + ("Duplicating socket=0x%p to dwProcessId=0x%x \n", + socket_info, dwProcessId) ); + + cl_spinlock_acquire( &socket_info->mutex1 ); + if( socket_info->socket_state != IBSP_CONNECTED ) + { + cl_spinlock_release( &socket_info->mutex1 ); + IBSP_PRINT_EXIT(TRACE_LEVEL_INFORMATION, IBSP_DBG_DUP, + ("Socket state not IBSP_CONNECTED, state=%s.\n", + IBSP_SOCKET_STATE_STR( socket_info->socket_state )) ); + *lpErrno = WSAENOTCONN; + return SOCKET_ERROR; + } + + /* Create a GUID to use as unique identifier for this duplication. */ + UuidCreate( &guid ); + create_name( fname, dwProcessId, &guid ); + + h_dup_info = CreateFileMapping( INVALID_HANDLE_VALUE, NULL, + PAGE_READWRITE, 0, sizeof(struct ibsp_duplicate_info), fname ); + if( !h_dup_info ) + { + cl_spinlock_release( &socket_info->mutex1 ); + IBSP_ERROR_EXIT( ("CreateFileMapping for %s failed with %d\n", + fname, GetLastError()) ); + *lpErrno = WSAENETDOWN; + return SOCKET_ERROR; + } + + /* Get a pointer to the file-mapped shared memory. */ + dup_info = MapViewOfFile( h_dup_info, FILE_MAP_WRITE, 0, 0, 0 ); + if( !dup_info ) + { + cl_spinlock_release( &socket_info->mutex1 ); + IBSP_ERROR_EXIT( ("MapViewOfFile failed with %d\n", GetLastError()) ); + CloseHandle( h_dup_info ); + *lpErrno = WSAENETDOWN; + return SOCKET_ERROR; + } + + /* + * Store addressing information so that the duplicating + * process can reconnect. + */ + dup_info->identifier = guid; + dup_info->socket_options = socket_info->socket_options; + dup_info->peer_addr = socket_info->peer_addr; + dup_info->local_addr = socket_info->local_addr; + dup_info->dwProcessId = dwProcessId; + + /* Release the reference on the underlying file */ + UnmapViewOfFile( dup_info ); + + /* Open the target process. */ + h_target_process = OpenProcess( PROCESS_DUP_HANDLE, FALSE, dwProcessId ); + if( !h_target_process ) + { + cl_spinlock_release( &socket_info->mutex1 ); + IBSP_ERROR_EXIT( ("OpenProcess failed with %d\n", GetLastError()) ); + CloseHandle( h_dup_info ); + *lpErrno = WSAENETDOWN; + return SOCKET_ERROR; + } + + if( !DuplicateHandle( GetCurrentProcess(), h_dup_info, + h_target_process, &h_target_dup_info, 0, TRUE, + DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS ) ) + { + cl_spinlock_release( &socket_info->mutex1 ); + IBSP_ERROR_EXIT( ("DuplicateHandle failed with %d\n", GetLastError()) ); + CloseHandle( h_target_process ); + *lpErrno = WSAENETDOWN; + return SOCKET_ERROR; + } + + CloseHandle( h_target_process ); +#if defined(_WIN64) + CL_ASSERT( !((ULONG_PTR)h_target_dup_info >> 32) ); +#endif + lpProtocolInfo->dwProviderReserved = (DWORD)(ULONG_PTR)h_target_dup_info; + + socket_info->duplicate.identifier = guid; + + IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_DUPLICATING_OLD ); + + memset( &reason, 0, sizeof(reason) ); + reason.type = DISC_DUPLICATING; + reason.duplicating.identifier = guid; + reason.duplicating.dwProcessId = dwProcessId; + + /* + * Flush all the receive buffers. There should be no + * send/rdma buffers left. + */ + ib_disconnect( socket_info, &reason ); + + /* We changed the state - remove from connection map. */ + ibsp_conn_remove( socket_info ); + + cl_spinlock_release( &socket_info->mutex1 ); + + wait_cq_drain( socket_info ); + + cl_spinlock_acquire( &socket_info->mutex1 ); + ib_destroy_socket( socket_info ); + cl_spinlock_release( &socket_info->mutex1 ); + + /* And that's it */ + IBSP_EXIT( IBSP_DBG_DUP ); + *lpErrno = 0; + return 0; +} diff --git a/branches/WOF2-3/ulp/wsd/user/ibsp_iblow.c b/branches/WOF2-3/ulp/wsd/user/ibsp_iblow.c new file mode 100644 index 00000000..dc2f4535 --- /dev/null +++ b/branches/WOF2-3/ulp/wsd/user/ibsp_iblow.c @@ -0,0 +1,1328 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2006 Mellanox Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ +#include "ibspdebug.h" + +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "ibsp_iblow.tmh" +#endif +#include +#include "ibspdll.h" + +#ifdef PERFMON_ENABLED +#include "ibsp_perfmon.h" +#endif + + +typedef struct _io_comp_info +{ + struct ibsp_socket_info *p_socket; + LPWSAOVERLAPPED p_ov; + +} io_comp_info_t; + + +/* Work queue entry completion routine. */ +static void +complete_wq( + IN const ib_wc_t *wc, + OUT io_comp_info_t *p_io_info ) +{ + struct _wr *wr = NULL; + struct _recv_wr *p_recv_wr = NULL; + LPWSAOVERLAPPED lpOverlapped = NULL; + struct ibsp_socket_info *socket_info = NULL; + + IBSP_ENTER( IBSP_DBG_IO ); + + wr = (struct _wr *)(ULONG_PTR)wc->wr_id; + p_recv_wr = (struct _recv_wr *)(ULONG_PTR)wc->wr_id; + + CL_ASSERT( wr ); + + socket_info = wr->socket_info; + p_io_info->p_socket = socket_info; + + lpOverlapped = wr->lpOverlapped; + + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_IO, + ("socket %p, ov %p, work completion status=%s, wc_type=%s\n", + socket_info, lpOverlapped, ib_get_wc_status_str( wc->status ), + ib_get_wc_type_str( wc->wc_type )) ); + + /* Set the windows error code. It's not easy to find an easy + * correspondence between the IBAL error codes and windows error + * codes; but it probably does not matter, as long as it returns an + * error. */ + switch( wc->status ) + { + case IB_WCS_SUCCESS: + /* + * Set the length of the operation. Under Infiniband, the work + * completion length is only valid for a receive + * operation. Fortunately we had already set the length during the + * send operation. + * + * lpWPUCompleteOverlappedRequest is supposed to store the length + * into InternalHigh, however it will not be called if the low + * order bit of lpOverlapped->hEvent is set. So we do it and hope + * for the best. + * + * NOTE: Without a valid length, the switch doesn't seem to call + * GetOverlappedResult() even if we call lpWPUCompleteOverlappedRequest() + */ + switch ( wc->wc_type ) + { + case IB_WC_RECV: + CL_ASSERT(wc->length != 0); + lpOverlapped->InternalHigh = wc->length; +#ifdef IBSP_LOGGING + cl_spinlock_acquire( &socket_info->recv_lock ); + DataLogger_WriteData(&socket_info->RecvDataLogger, + p_recv_wr->idx, (void *)p_recv_wr->ds_array[0].vaddr, + wc->length); + cl_spinlock_release( &socket_info->recv_lock ); +#endif +#ifdef PERFMON_ENABLED + InterlockedIncrement64( &g_pm_stat.pdata[COMP_RECV] ); + InterlockedExchangeAdd64( &g_pm_stat.pdata[BYTES_RECV], + lpOverlapped->InternalHigh ); +#endif +#ifdef _DEBUG_ + cl_atomic_inc(&g_ibsp.total_recv_compleated); +#endif + break; + + case IB_WC_RDMA_READ: + CL_ASSERT(wc->length != 0); + lpOverlapped->InternalHigh = wc->length; +#ifdef PERFMON_ENABLED + InterlockedIncrement64( &g_pm_stat.pdata[COMP_RECV] ); + InterlockedExchangeAdd64( &g_pm_stat.pdata[BYTES_READ], + lpOverlapped->InternalHigh ); +#endif /* PERFMON_ENABLED */ + break; + +#ifdef PERFMON_ENABLED + case IB_WC_SEND: + InterlockedIncrement64( &g_pm_stat.pdata[COMP_SEND] ); + InterlockedExchangeAdd64( &g_pm_stat.pdata[BYTES_SEND], + lpOverlapped->InternalHigh ); + break; + + case IB_WC_RDMA_WRITE: + InterlockedIncrement64( &g_pm_stat.pdata[COMP_SEND] ); + InterlockedExchangeAdd64( &g_pm_stat.pdata[BYTES_WRITE], + lpOverlapped->InternalHigh ); +#endif /* PERFMON_ENABLED */ + default: + break; + } + + + lpOverlapped->OffsetHigh = 0; + break; + + case IB_WCS_WR_FLUSHED_ERR: + cl_spinlock_acquire( &socket_info->mutex1 ); + + if( socket_info->socket_state == IBSP_DUPLICATING_REMOTE && + wc->wc_type == IB_WC_RECV ) + { + /* + * Take the wr off the wr_list, and place onto the + * dup_wr_list. We will post them later on the new QP. + */ + cl_spinlock_acquire( &socket_info->recv_lock ); + + /* Copy to the duplicate WR array. */ + socket_info->dup_wr[socket_info->dup_idx] = *p_recv_wr; + +#if QP_ATTRIB_RQ_DEPTH == 256 || QP_ATTRIB_RQ_DEPTH == 128 || \ + QP_ATTRIB_RQ_DEPTH == 64 || QP_ATTRIB_RQ_DEPTH == 32 || \ + QP_ATTRIB_RQ_DEPTH == 16 || QP_ATTRIB_RQ_DEPTH == 8 + socket_info->dup_idx++; + socket_info->dup_idx &= (QP_ATTRIB_RQ_DEPTH - 1); +#else + if( ++socket_info->dup_idx == QP_ATTRIB_RQ_DEPTH ) + socket_info->dup_idx = 0; +#endif + + cl_atomic_inc( &socket_info->dup_cnt ); + /* ib_cq_comp will decrement the receive count. */ + cl_atomic_dec( &socket_info->recv_cnt ); + + cl_spinlock_release( &socket_info->recv_lock ); + + cl_spinlock_release( &socket_info->mutex1 ); + p_io_info->p_ov = NULL; + IBSP_EXIT( IBSP_DBG_IO ); + return; + } + + /* Check for flushing the receive buffers on purpose. */ + if( socket_info->socket_state == IBSP_DUPLICATING_OLD ) + wr->lpOverlapped->OffsetHigh = 0; + else + wr->lpOverlapped->OffsetHigh = WSA_OPERATION_ABORTED; + + cl_spinlock_release( &socket_info->mutex1 ); + + /* Override the length, as per the WSD specs. */ + wr->lpOverlapped->InternalHigh = 0; + break; + + case IB_WCS_LOCAL_LEN_ERR: + case IB_WCS_LOCAL_OP_ERR: + case IB_WCS_LOCAL_PROTECTION_ERR: + case IB_WCS_MEM_WINDOW_BIND_ERR: + case IB_WCS_REM_ACCESS_ERR: + case IB_WCS_REM_OP_ERR: + case IB_WCS_RNR_RETRY_ERR: + case IB_WCS_TIMEOUT_RETRY_ERR: + case IB_WCS_REM_INVALID_REQ_ERR: + default: + { + char comp_name[MAX_COMPUTERNAME_LENGTH + 1] = {0}; + DWORD len = sizeof(comp_name); + GetComputerName( comp_name, &len ); + IBSP_ERROR( ("%s (%s:%d to ", + comp_name, inet_ntoa( socket_info->local_addr.sin_addr ), + socket_info->local_addr.sin_port) ); + IBSP_ERROR( ("%s:%d) %s error: %s (vendor specific %I64x)\n", + inet_ntoa( socket_info->peer_addr.sin_addr ), + socket_info->peer_addr.sin_port, + ib_get_wc_type_str( wc->wc_type ), + ib_get_wc_status_str( wc->status ), + wc->vendor_specific) ); + lpOverlapped->OffsetHigh = WSAECONNABORTED; + wr->lpOverlapped->InternalHigh = 0; + socket_info->qp_error = WSAECONNABORTED; + break; + } + } + +#ifdef PERFMON_ENABLED + InterlockedIncrement64( &g_pm_stat.pdata[COMP_TOTAL] ); +#endif + +#ifdef _DEBUG_ + if( wc->wc_type == IB_WC_RECV ) + { + // This code requires the recv count to be decremented here, but it needs + // to be decremented after any callbacks are invoked so socket destruction + // gets delayed until all callbacks have been invoked. + //{ + // uint8_t idx; + + // cl_spinlock_acquire( &socket_info->recv_lock ); + // idx = socket_info->recv_idx - (uint8_t)socket_info->recv_cnt; + // if( idx >= QP_ATTRIB_RQ_DEPTH ) + // idx += QP_ATTRIB_RQ_DEPTH; + + // CL_ASSERT( wc->wr_id == (ULONG_PTR)&socket_info->recv_wr[idx] ); + // cl_atomic_dec( &socket_info->recv_cnt ); + // cl_spinlock_release( &socket_info->recv_lock ); + //} + + if( wc->status == IB_SUCCESS && p_recv_wr->ds_array[0].length >= 40 ) + { + debug_dump_buffer( IBSP_DBG_WQ, "RECV", + (void *)(ULONG_PTR)p_recv_wr->ds_array[0].vaddr, 40 ); + } + + cl_atomic_dec( &g_ibsp.recv_count ); + cl_atomic_inc( &socket_info->recv_comp ); + + memset( p_recv_wr, 0x33, sizeof(struct _recv_wr) ); + } + else + { + // This code requires the send count to be decremented here, but it needs + // to be decremented after any callbacks are invoked so socket destruction + // gets delayed until all callbacks have been invoked. + //{ + // uint8_t idx; + + // cl_spinlock_acquire( &socket_info->send_lock ); + // idx = socket_info->send_idx - (uint8_t)socket_info->send_cnt; + // if( idx >= QP_ATTRIB_SQ_DEPTH ) + // idx += QP_ATTRIB_SQ_DEPTH; + // CL_ASSERT( wc->wr_id == (ULONG_PTR)&socket_info->send_wr[idx] ); + // cl_atomic_dec( &socket_info->send_cnt ); + // cl_spinlock_release( &socket_info->send_lock ); + //} + + if( wc->wc_type == IB_WC_SEND ) + { + cl_atomic_dec( &g_ibsp.send_count ); + cl_atomic_inc( &socket_info->send_comp ); + + fzprint(("%s():%d:0x%x:0x%x: send_count=%d\n", + __FUNCTION__, + __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), g_ibsp.send_count)); + } + + memset( wr, 0x33, sizeof(struct _wr) ); + } +#endif + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_IO, + ("overlapped=%p, InternalHigh=%Id, hEvent=%p\n", + lpOverlapped, lpOverlapped->InternalHigh, + lpOverlapped->hEvent) ); + + + + /* Don't notify the switch for that completion only if: + * - the switch don't want a notification + * - the wq completed with success + * - the socket is still connected + */ + if( ((uintptr_t) lpOverlapped->hEvent) & 0x00000001 ) + { + /* Indicate this operation is complete. The switch will poll + * with calls to WSPGetOverlappedResult(). */ + +#ifdef _DEBUG_ + cl_atomic_dec( &g_ibsp.overlap_h1_comp_count ); + + fzprint(("%s():%d:0x%x:0x%x: ov=0x%p h0=%d h1=%d h1_c=%d send=%d recv=%d\n", + __FUNCTION__, __LINE__, GetCurrentProcessId(), + GetCurrentThreadId(), lpOverlapped, + g_ibsp.overlap_h0_count, g_ibsp.overlap_h1_count, + g_ibsp.overlap_h1_comp_count, g_ibsp.send_count, g_ibsp.recv_count)); +#endif + + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_IO, + ("Not calling lpWPUCompleteOverlappedRequest: " + "socket=%p, ov=%p OffsetHigh=%d, InternalHigh=%Id hEvent=%p\n", + socket_info, lpOverlapped, lpOverlapped->OffsetHigh, + lpOverlapped->InternalHigh, lpOverlapped->hEvent) ); + + lpOverlapped->Internal = 0; + p_io_info->p_ov = NULL; + } + else + { +#ifdef _DEBUG_ + cl_atomic_dec( &g_ibsp.overlap_h0_count ); + + fzprint(("%s():%d:0x%x:0x%x: ov=0x%p h0=%d h1=%d h1_c=%d send=%d recv=%d\n", + __FUNCTION__, __LINE__, GetCurrentProcessId(), + GetCurrentThreadId(), lpOverlapped, + g_ibsp.overlap_h0_count, g_ibsp.overlap_h1_count, + g_ibsp.overlap_h1_comp_count, g_ibsp.send_count, g_ibsp.recv_count)); +#endif + + p_io_info->p_ov = lpOverlapped; + cl_atomic_inc( &socket_info->ref_cnt1 ); + } + + if( wc->wc_type == IB_WC_RECV ) + { + cl_atomic_dec( &socket_info->recv_cnt ); + } + else + { + cl_atomic_dec( &socket_info->send_cnt ); + } + + IBSP_EXIT( IBSP_DBG_IO ); +} + + +/* CQ completion handler. */ +int +ib_cq_comp( + void *cq_context ) +{ + struct cq_thread_info *cq_tinfo = cq_context; + ib_api_status_t status; + ib_wc_t wclist[WC_LIST_SIZE]; + ib_wc_t *free_wclist; + ib_wc_t *done_wclist; + io_comp_info_t info[WC_LIST_SIZE]; + int cb_idx; + int i; + int n_comp = 0; +#ifdef _DEBUG_ + int comp_count; +#endif + + IBSP_ENTER( IBSP_DBG_WQ ); + + CL_ASSERT( WC_LIST_SIZE >= 1 ); + + do + { + /* Try to retrieve up to WC_LIST_SIZE completions at a time. */ + for( i = 0; i < (WC_LIST_SIZE - 1); i++ ) + { + wclist[i].p_next = &wclist[i + 1]; + } + wclist[(WC_LIST_SIZE - 1)].p_next = NULL; + + free_wclist = &wclist[0]; + done_wclist = NULL; + + cl_spinlock_acquire(&cq_tinfo->cq_spinlock); + + status = ib_poll_cq( cq_tinfo->cq, &free_wclist, &done_wclist ); + + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_WQ, + ("poll CQ got status %d, free=%p, done=%p\n", + status, free_wclist, done_wclist) ); + + switch( status ) + { + case IB_NOT_FOUND: + case IB_SUCCESS: + break; + + case IB_INVALID_CQ_HANDLE: + /* This happens when the switch closes the socket while the + * execution thread was calling lpWPUCompleteOverlappedRequest. */ + IBSP_ERROR( ( + "ib_poll_cq returned IB_INVLALID_CQ_HANDLE\n") ); + cl_spinlock_release(&cq_tinfo->cq_spinlock); + goto done; + + default: + IBSP_ERROR( ( + "ib_poll_cq failed returned %s\n", ib_get_err_str( status )) ); + break; + } + +#ifdef _DEBUG_ + comp_count = 0; +#endif + + /* We have some completions. */ + cb_idx = 0; + while( done_wclist ) + { +#ifdef _DEBUG_ + comp_count++; +#endif + complete_wq( done_wclist, &info[cb_idx++] ); + + done_wclist = done_wclist->p_next; + } + cl_spinlock_release(&cq_tinfo->cq_spinlock); + + for( i = 0; i < cb_idx; i++ ) + { + int error; + int ret; + + if( info[i].p_ov ) + { + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_IO, + ("Calling lpWPUCompleteOverlappedRequest: " + "socket=%p, ov=%p OffsetHigh=%d " + "InternalHigh=%Id hEvent=%p\n", + info[i].p_socket, info[i].p_ov, info[i].p_ov->OffsetHigh, + info[i].p_ov->InternalHigh, info[i].p_ov->hEvent) ); + + ret = g_ibsp.up_call_table.lpWPUCompleteOverlappedRequest( + info[i].p_socket->switch_socket, info[i].p_ov, + info[i].p_ov->OffsetHigh, + (DWORD)info[i].p_ov->InternalHigh, &error ); + if( ret != 0 ) + { + IBSP_ERROR( ("WPUCompleteOverlappedRequest for ov=%p " + "returned %d err %d\n", info[i].p_ov, ret, error) ); + } + deref_socket_info( info[i].p_socket ); + } + } + + n_comp += i; + +#ifdef _DEBUG_ + if( comp_count > g_ibsp.max_comp_count ) + { + g_ibsp.max_comp_count = comp_count; + } +#endif + } while( !free_wclist ); + +done: + +#ifdef _DEBUG_ + fzprint(("%s():%d:0x%x:0x%x: overlap_h0_count=%d overlap_h1_count=%d\n", + __FUNCTION__, + __LINE__, GetCurrentProcessId(), + GetCurrentThreadId(), g_ibsp.overlap_h0_count, g_ibsp.overlap_h1_count)); +#endif + + IBSP_EXIT( IBSP_DBG_WQ ); + return n_comp; +} + + +/* IB completion thread */ +static DWORD WINAPI +ib_cq_thread( + LPVOID lpParameter ) +{ + struct cq_thread_info *cq_tinfo = (struct cq_thread_info *)lpParameter; + cl_status_t cl_status; + ib_api_status_t status; + int i; + DWORD_PTR old_afinity; + + IBSP_ENTER( IBSP_DBG_HW ); + + fzprint(("%s():%d:0x%x:0x%x: cq_tinfo=0x%p\n", __FUNCTION__, + __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), cq_tinfo)); + + old_afinity = SetThreadAffinityMask (GetCurrentThread (),g_dwPollThreadAffinityMask); + if (old_afinity == 0) { + IBSP_ERROR(("SetThreadAffinityMask failed\n")); + } else { + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_DLL,("SetThreadAffinityMask succeeded\n")); + } + + + do + { + cl_status = cl_waitobj_wait_on( cq_tinfo->cq_waitobj, EVENT_NO_TIMEOUT, TRUE ); + if( cl_status != CL_SUCCESS ) + { + IBSP_ERROR( ( + "cl_waitobj_wait_on() (%d)\n", cl_status) ); + } + + /* + * TODO: By rearranging thread creation and cq creation, this check + * may be eliminated. + */ + if( cq_tinfo->cq != NULL ) + { + fzprint(("%s():%d:0x%x:0x%x: Calling ib_cq_comp().\n", __FUNCTION__, + __LINE__, GetCurrentProcessId(), GetCurrentThreadId())); + +#ifdef PERFMON_ENABLED + InterlockedIncrement64( &g_pm_stat.pdata[INTR_TOTAL] ); +#endif + i = g_max_poll; + do + { + if( ib_cq_comp( cq_tinfo ) ) + i = g_max_poll; + + } while( i-- ); + + fzprint(("%s():%d:0x%x:0x%x: Done calling ib_cq_comp().\n", __FUNCTION__, + __LINE__, GetCurrentProcessId(), GetCurrentThreadId())); + + status = ib_rearm_cq( cq_tinfo->cq, FALSE ); + if( status != IB_SUCCESS ) + { + IBSP_ERROR( ( + "ib_rearm_cq returned %s)\n", ib_get_err_str( status )) ); + } + } + + } while( !cq_tinfo->ib_cq_thread_exit_wanted ); + + cl_status = cl_waitobj_destroy( cq_tinfo->cq_waitobj ); + if( cl_status != CL_SUCCESS ) + { + IBSP_ERROR( ( + "cl_waitobj_destroy() returned %s\n", CL_STATUS_MSG(cl_status)) ); + } + HeapFree( g_ibsp.heap, 0, cq_tinfo ); + + /* No special exit code, even on errors. */ + IBSP_EXIT( IBSP_DBG_HW ); + ExitThread( 0 ); +} + + +/* Called with the HCA's CQ lock held. */ +static struct cq_thread_info * +ib_alloc_cq_tinfo( + struct ibsp_hca *hca ) +{ + struct cq_thread_info *cq_tinfo = NULL; + ib_cq_create_t cq_create; + ib_api_status_t status; + cl_status_t cl_status; + + IBSP_ENTER( IBSP_DBG_HW ); + + cq_tinfo = HeapAlloc( + g_ibsp.heap, HEAP_ZERO_MEMORY, sizeof(struct cq_thread_info) ); + + if( !cq_tinfo ) + { + IBSP_ERROR_EXIT( ("HeapAlloc() Failed.\n") ); + return NULL; + } + + cl_status = cl_waitobj_create( FALSE, &cq_tinfo->cq_waitobj ); + if( cl_status != CL_SUCCESS ) + { + cq_tinfo->cq_waitobj = NULL; + ib_destroy_cq_tinfo( cq_tinfo ); + IBSP_ERROR_EXIT( ( + "cl_waitobj_create() returned %s\n", CL_STATUS_MSG(cl_status)) ); + return NULL; + } + + cq_tinfo->hca = hca; + cq_tinfo->ib_cq_thread_exit_wanted = FALSE; + + cq_tinfo->ib_cq_thread = CreateThread( NULL, 0, ib_cq_thread, cq_tinfo, 0, + (LPDWORD)&cq_tinfo->ib_cq_thread_id ); + + if( cq_tinfo->ib_cq_thread == NULL ) + { + ib_destroy_cq_tinfo( cq_tinfo ); + IBSP_ERROR_EXIT( ("CreateThread failed (%d)", GetLastError()) ); + return NULL; + } + + STAT_INC( thread_num ); + + /* Completion queue */ + cq_create.size = IB_INIT_CQ_SIZE; + + cq_create.pfn_comp_cb = NULL; + cq_create.h_wait_obj = cq_tinfo->cq_waitobj; + + status = ib_create_cq( hca->hca_handle, &cq_create, cq_tinfo, + NULL, &cq_tinfo->cq ); + if( status ) + { + ib_destroy_cq_tinfo( cq_tinfo ); + IBSP_ERROR_EXIT( ( + "ib_create_cq returned %s\n", ib_get_err_str( status )) ); + return NULL; + } + + STAT_INC( cq_num ); + + status = ib_rearm_cq( cq_tinfo->cq, FALSE ); + if( status ) + { + ib_destroy_cq_tinfo( cq_tinfo ); + IBSP_ERROR_EXIT( ( + "ib_rearm_cq returned %s\n", ib_get_err_str( status )) ); + return NULL; + } + + cq_tinfo->cqe_size = cq_create.size; + + if( hca->cq_tinfo ) + { + __cl_primitive_insert( + &hca->cq_tinfo->list_item, &cq_tinfo->list_item ); + } + else + { + /* Setup the list entry to point to itself. */ + cq_tinfo->list_item.p_next = &cq_tinfo->list_item; + cq_tinfo->list_item.p_prev = &cq_tinfo->list_item; + } + + /* We will be assigned to a QP - set the QP count. */ + cq_tinfo->qp_count = 1; + + /* Upon allocation, the new CQ becomes the primary. */ + hca->cq_tinfo = cq_tinfo; + + cl_spinlock_init(&cq_tinfo->cq_spinlock); + + IBSP_EXIT( IBSP_DBG_HW ); + return (cq_tinfo); +} + + +void +ib_destroy_cq_tinfo( + struct cq_thread_info *cq_tinfo ) +{ + ib_wc_t wclist; + ib_wc_t *free_wclist; + ib_wc_t *done_wclist; + ib_api_status_t status; + HANDLE h_cq_thread; + DWORD cq_thread_id; + + IBSP_ENTER( IBSP_DBG_HW ); + + CL_ASSERT( cq_tinfo ); + CL_ASSERT( cq_tinfo->qp_count == 0 ); + + cl_spinlock_destroy(&cq_tinfo->cq_spinlock); + + if( cq_tinfo->cq ) + { + wclist.p_next = NULL; + free_wclist = &wclist; + + while( ib_poll_cq( + cq_tinfo->cq, &free_wclist, &done_wclist ) == IB_SUCCESS ) + { + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_WQ, + ("free=%p, done=%p\n", free_wclist, done_wclist) ); + } + + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_WQ, ("ib_destroy_cq() start..\n") ); + + /* + * Called from cleanup thread, okay to block. + */ + status = ib_destroy_cq( cq_tinfo->cq, ib_sync_destroy ); + if( status ) + { + IBSP_ERROR( ( + "ib_destroy_cq returned %s\n", ib_get_err_str( status )) ); + } + else + { + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_WQ, ("ib_destroy_cq() finished.\n") ); + + cq_tinfo->cq = NULL; + + STAT_DEC( cq_num ); + } + } + + if( cq_tinfo->ib_cq_thread ) + { + /* ib_cq_thread() will release the cq_tinfo before exit. Don't + reference cq_tinfo after signaling */ + h_cq_thread = cq_tinfo->ib_cq_thread; + cq_tinfo->ib_cq_thread = NULL; + cq_thread_id = cq_tinfo->ib_cq_thread_id; + + cq_tinfo->ib_cq_thread_exit_wanted = TRUE; + cl_waitobj_signal( cq_tinfo->cq_waitobj ); + + /* Wait for ib_cq_thread to die, if we are not running on it */ + if( GetCurrentThreadId() != cq_thread_id ) + { + fzprint(("%s():%d:0x%x:0x%x: Waiting for ib_cq_thread=0x%x to die\n", + __FUNCTION__, __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), + cq_thread_id )); + if( WaitForSingleObject( h_cq_thread, INFINITE ) != WAIT_OBJECT_0 ) + { + IBSP_ERROR( ("WaitForSingleObject failed\n") ); + } + else + { + STAT_DEC( thread_num ); + } + } + else + { + fzprint(("%s():%d:0x%x:0x%x: Currently on ib_cq_thread.\n", __FUNCTION__, + __LINE__, GetCurrentProcessId(), GetCurrentThreadId())); + STAT_DEC( thread_num ); + } + CloseHandle( h_cq_thread ); + } + else + { + /* There was no thread created, destroy cq_waitobj and + free memory */ + if( cq_tinfo->cq_waitobj ) + { + cl_waitobj_destroy( cq_tinfo->cq_waitobj ); + cq_tinfo->cq_waitobj = NULL; + } + HeapFree( g_ibsp.heap, 0, cq_tinfo ); + } + + IBSP_EXIT( IBSP_DBG_HW ); +} + + +static struct cq_thread_info * +ib_acquire_cq_tinfo( + struct ibsp_hca *hca ) +{ + struct cq_thread_info *cq_tinfo = NULL, *cq_end; + uint32_t cqe_size; + ib_api_status_t status; + + IBSP_ENTER( IBSP_DBG_HW ); + + cl_spinlock_acquire( &hca->cq_lock ); + + if( !hca->cq_tinfo ) + { + cq_tinfo = ib_alloc_cq_tinfo( hca ); + if( !cq_tinfo ) + IBSP_ERROR( ("ib_alloc_cq_tinfo() failed\n") ); + cl_spinlock_release( &hca->cq_lock ); + IBSP_EXIT( IBSP_DBG_HW ); + return cq_tinfo; + } + + cq_tinfo = hca->cq_tinfo; + cq_end = cq_tinfo; + cqe_size = (cq_tinfo->qp_count + 1) * IB_CQ_SIZE; + + do + { + if( cq_tinfo->cqe_size >= cqe_size ) + { + cq_tinfo->qp_count++; + cl_spinlock_release( &hca->cq_lock ); + IBSP_EXIT( IBSP_DBG_HW ); + return (cq_tinfo); + } + + status = ib_modify_cq( cq_tinfo->cq, &cqe_size ); + switch( status ) + { + case IB_SUCCESS: + cq_tinfo->cqe_size = cqe_size; + cq_tinfo->qp_count++; + break; + + default: + IBSP_ERROR_EXIT( ( + "ib_modify_cq() returned %s\n", ib_get_err_str(status)) ); + case IB_INVALID_CQ_SIZE: + case IB_UNSUPPORTED: + cq_tinfo = PARENT_STRUCT( + cl_qlist_next( &cq_tinfo->list_item ), struct cq_thread_info, + list_item ); + cqe_size = (cq_tinfo->qp_count + 1) * IB_CQ_SIZE; + } + + } while( cq_tinfo != cq_end ); + + if( cq_tinfo == cq_end ) + cq_tinfo = ib_alloc_cq_tinfo( hca ); + + cl_spinlock_release( &hca->cq_lock ); + IBSP_EXIT( IBSP_DBG_HW ); + return (cq_tinfo); +} + +void +ib_release_cq_tinfo( + struct cq_thread_info *cq_tinfo ) +{ + IBSP_ENTER( IBSP_DBG_HW ); + + CL_ASSERT( cq_tinfo ); + CL_ASSERT( cq_tinfo->hca ); + + cl_spinlock_acquire( &cq_tinfo->hca->cq_lock ); + /* If this CQ now has fewer QPs than the primary, make it the primary. */ + if( --cq_tinfo->qp_count < cq_tinfo->hca->cq_tinfo->qp_count ) + cq_tinfo->hca->cq_tinfo = cq_tinfo; + cl_spinlock_release( &cq_tinfo->hca->cq_lock ); + + IBSP_EXIT( IBSP_DBG_HW ); +} + + +/* Release IB ressources. */ +void +ib_release(void) +{ + cl_fmap_item_t *p_item; + + IBSP_ENTER( IBSP_DBG_HW ); + + if( g_ibsp.al_handle ) + { + cl_list_item_t *item; + ib_api_status_t status; + + unregister_pnp(); + + while( (item = cl_qlist_head( &g_ibsp.hca_list )) != cl_qlist_end( &g_ibsp.hca_list ) ) + { + struct ibsp_hca *hca = PARENT_STRUCT(item, struct ibsp_hca, item); + + pnp_ca_remove( hca ); + } + + fzprint(("%s():%d:0x%x:0x%x: Calling ib_close_al...\n", __FUNCTION__, + __LINE__, GetCurrentProcessId(), GetCurrentThreadId())); + + status = ib_close_al( g_ibsp.al_handle ); + + fzprint(("%s():%d:0x%x:0x%x: Done calling ib_close_al, status=%d.\n", + __FUNCTION__, __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), + status)); + if( status != IB_SUCCESS ) + { + IBSP_ERROR( ( + "ib_close_al returned %s\n", ib_get_err_str( status )) ); + } + else + { + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_HW, ("ib_close_al success\n") ); + STAT_DEC( al_num ); + } + g_ibsp.al_handle = NULL; + } + + for( p_item = cl_fmap_head( &g_ibsp.ip_map ); + p_item != cl_fmap_end( &g_ibsp.ip_map ); + p_item = cl_fmap_head( &g_ibsp.ip_map ) ) + { + cl_fmap_remove_item( &g_ibsp.ip_map, p_item ); + + HeapFree( g_ibsp.heap, 0, + PARENT_STRUCT(p_item, struct ibsp_ip_addr, item) ); + } + + IBSP_EXIT( IBSP_DBG_HW ); +} + + +/* Initialize IB ressources. */ +int +ibsp_initialize(void) +{ + ib_api_status_t status; + int ret; + + IBSP_ENTER( IBSP_DBG_HW ); + + CL_ASSERT( g_ibsp.al_handle == NULL ); + CL_ASSERT( cl_qlist_count( &g_ibsp.hca_list ) == 0 ); + + /* Open the IB library */ + status = ib_open_al( &g_ibsp.al_handle ); + + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_HW, ("open is %d %p\n", status, g_ibsp.al_handle) ); + + if( status != IB_SUCCESS ) + { + IBSP_ERROR( ("ib_open_al failed (%d)\n", status) ); + ret = WSAEPROVIDERFAILEDINIT; + goto done; + } + + STAT_INC( al_num ); + + /* Register for PNP events */ + status = register_pnp(); + if( status ) + { + IBSP_ERROR( ("register_pnp failed (%d)\n", status) ); + ret = WSAEPROVIDERFAILEDINIT; + goto done; + } + + STAT_INC( thread_num ); + + ret = 0; +done: + if( ret ) + { + /* Free up resources. */ + ib_release(); + } + + IBSP_EXIT( IBSP_DBG_HW ); + + return ret; +} + + +/* Destroys the infiniband ressources of a socket. */ +void +ib_destroy_socket( + IN OUT struct ibsp_socket_info *socket_info ) +{ + ib_api_status_t status; + + IBSP_ENTER( IBSP_DBG_EP ); + + if( socket_info->qp ) + { + + + ib_qp_mod_t qp_mod; + + cl_atomic_inc( &socket_info->ref_cnt1 ); + + cl_memclr( &qp_mod, sizeof(ib_qp_mod_t) ); + qp_mod.req_state = IB_QPS_ERROR; + status = ib_modify_qp(socket_info->qp, &qp_mod); + if( status != IB_SUCCESS ) + { + IBSP_ERROR( ("ib_modify_qp returned %s\n", + ib_get_err_str( status )) ); + deref_socket_info( socket_info ); + } + + + /* Wait for all work requests to get flushed. */ + while( socket_info->send_cnt || socket_info->send_cnt ) + cl_thread_suspend( 0 ); + + status = ib_destroy_qp( socket_info->qp, deref_socket_info ); + if( status != IB_SUCCESS ) + { + IBSP_ERROR( ("ib_destroy_qp returned %s\n", + ib_get_err_str( status )) ); + deref_socket_info( socket_info ); + } + + ib_release_cq_tinfo( socket_info->cq_tinfo ); + + socket_info->qp = NULL; + } + + IBSP_EXIT( IBSP_DBG_EP ); +} + + +/* + * Creates the necessary IB ressources for a socket + */ +int +ib_create_socket( + IN OUT struct ibsp_socket_info *socket_info) +{ + ib_qp_create_t qp_create; + ib_api_status_t status; + ib_qp_attr_t qp_attr; + + IBSP_ENTER( IBSP_DBG_EP ); + + CL_ASSERT( socket_info != NULL ); + CL_ASSERT( socket_info->port != NULL ); + CL_ASSERT( socket_info->qp == NULL ); + + socket_info->hca_pd = socket_info->port->hca->pd; + + /* Get the completion queue and thread info for this socket */ + socket_info->cq_tinfo = ib_acquire_cq_tinfo( socket_info->port->hca ); + if( !socket_info->cq_tinfo ) + { + IBSP_ERROR_EXIT( ("ib_acquire_cq_tinfo failed\n") ); + return WSAENOBUFS; + } + + /* Queue pair */ + cl_memclr(&qp_create, sizeof(ib_qp_create_t)); + qp_create.qp_type = IB_QPT_RELIABLE_CONN; + qp_create.sq_depth = QP_ATTRIB_SQ_DEPTH; + qp_create.rq_depth = QP_ATTRIB_RQ_DEPTH; + qp_create.sq_sge = QP_ATTRIB_SQ_SGE; + qp_create.rq_sge = 1; + qp_create.h_rq_cq = socket_info->cq_tinfo->cq; + qp_create.h_sq_cq = socket_info->cq_tinfo->cq; + qp_create.sq_signaled = TRUE; + + status = ib_create_qp( socket_info->hca_pd, &qp_create, socket_info, /* context */ + qp_event_handler, /* async handler */ + &socket_info->qp ); + if( status ) + { + ib_release_cq_tinfo( socket_info->cq_tinfo ); + IBSP_ERROR_EXIT( ( + "ib_create_qp returned %s\n", ib_get_err_str( status )) ); + return WSAENOBUFS; + } + + status = ib_query_qp( socket_info->qp, &qp_attr ); + if( status == IB_SUCCESS ) + { + socket_info->max_inline = min( g_max_inline, qp_attr.sq_max_inline ); + } + else + { + IBSP_ERROR( ("ib_query_qp returned %s\n", ib_get_err_str( status )) ); + socket_info->max_inline = 0; + } + + STAT_INC( qp_num ); + + IBSP_EXIT( IBSP_DBG_EP ); + return 0; +} + + +void +wait_cq_drain( + IN OUT struct ibsp_socket_info *socket_info ) +{ + IBSP_ENTER( IBSP_DBG_EP ); + + if( socket_info->cq_tinfo == NULL ) + { + IBSP_EXIT( IBSP_DBG_EP ); + return; + } + + /* Wait for the QP to be drained. */ + while( socket_info->send_cnt || socket_info->recv_cnt ) + { + fzprint(("%s():%d:0x%x:0x%x: socket=0x%p wr_list_count=%d qp state=%d\n", + __FUNCTION__, __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), + socket_info, cl_qlist_count(&socket_info->wr_list))); + + Sleep(100); + } + + IBSP_EXIT( IBSP_DBG_EP ); +} + + +void +ibsp_dup_overlap_abort( + IN OUT struct ibsp_socket_info *socket_info ) +{ + LPWSAOVERLAPPED lpOverlapped = NULL; + int error; + int ret; + uint8_t idx; + + IBSP_ENTER( IBSP_DBG_EP ); + CL_ASSERT( !socket_info->send_cnt && !socket_info->recv_cnt ); + + /* Browse the list of all posted overlapped structures + * to mark them as aborted. */ + idx = socket_info->dup_idx - (uint8_t)socket_info->dup_cnt; + if( idx >= QP_ATTRIB_RQ_DEPTH ) + idx += QP_ATTRIB_RQ_DEPTH; + + while( socket_info->dup_cnt ) + { + lpOverlapped = socket_info->dup_wr[idx].wr.lpOverlapped; + + fzprint(("%s():%d:0x%x:0x%x: socket=0x%p wr=0x%p overlapped=0x%p Internal=%d InternalHigh=%d hEvent=%d\n", + __FUNCTION__, __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), socket_info, &socket_info->dup_wr[idx], lpOverlapped, lpOverlapped->Internal, lpOverlapped->InternalHigh, lpOverlapped->hEvent)); + + lpOverlapped->OffsetHigh = WSAECONNABORTED; + lpOverlapped->InternalHigh = 0; + + if( ((uintptr_t) lpOverlapped->hEvent) & 0x00000001 ) + { + /* Indicate this operation is complete. The switch will poll + * with calls to WSPGetOverlappedResult(). */ +#ifdef _DEBUG_ + cl_atomic_dec(&g_ibsp.overlap_h1_comp_count); + + fzprint(("%s():%d:0x%x:0x%x: ov=0x%p h0=%d h1=%d h1_c=%d send=%d recv=%d\n", + __FUNCTION__, __LINE__, GetCurrentProcessId(), + GetCurrentThreadId(), lpOverlapped, + g_ibsp.overlap_h0_count, g_ibsp.overlap_h1_count, + g_ibsp.overlap_h1_comp_count, g_ibsp.send_count, g_ibsp.recv_count)); +#endif + + IBSP_PRINT(TRACE_LEVEL_INFORMATION,IBSP_DBG_WQ, + ("set internal overlapped=0x%p Internal=%Id OffsetHigh=%d\n", + lpOverlapped, lpOverlapped->Internal, + lpOverlapped->OffsetHigh)); + + lpOverlapped->Internal = 0; + } + else + { +#ifdef _DEBUG_ + cl_atomic_dec(&g_ibsp.overlap_h0_count); + + + fzprint(("%s():%d:0x%x:0x%x: ov=0x%p h0=%d h1=%d h1_c=%d send=%d recv=%d\n", + __FUNCTION__, __LINE__, GetCurrentProcessId(), + GetCurrentThreadId(), lpOverlapped, + g_ibsp.overlap_h0_count, g_ibsp.overlap_h1_count, + g_ibsp.overlap_h1_comp_count, g_ibsp.send_count, g_ibsp.recv_count)); +#endif + IBSP_PRINT(TRACE_LEVEL_INFORMATION,IBSP_DBG_WQ, + (" calls lpWPUCompleteOverlappedRequest, overlapped=0x%p OffsetHigh=%d " + "InternalHigh=%Id hEvent=%p\n", + lpOverlapped, lpOverlapped->OffsetHigh, + lpOverlapped->InternalHigh, lpOverlapped->hEvent)); + + ret = g_ibsp.up_call_table.lpWPUCompleteOverlappedRequest + (socket_info->switch_socket, + lpOverlapped, + lpOverlapped->OffsetHigh, (DWORD) lpOverlapped->InternalHigh, &error); + + if( ret != 0 ) + { + IBSP_ERROR( ("lpWPUCompleteOverlappedRequest failed with %d/%d\n", ret, error) ); + } + } + cl_atomic_dec( &socket_info->dup_cnt ); + } + + IBSP_EXIT( IBSP_DBG_EP ); +} + + +/* Closes a connection and release its ressources. */ +void +shutdown_and_destroy_socket_info( + IN OUT struct ibsp_socket_info *socket_info ) +{ + enum ibsp_socket_state old_state; + + IBSP_ENTER( IBSP_DBG_EP ); + + cl_spinlock_acquire( &socket_info->mutex1 ); + old_state = socket_info->socket_state; + IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_CLOSED ); + cl_spinlock_release( &socket_info->mutex1 ); + + if( socket_info->listen.handle ) + { + /* Stop listening and reject queued connections. */ + ib_listen_cancel( socket_info ); + } + + cl_spinlock_acquire( &g_ibsp.socket_info_mutex ); + cl_qlist_remove_item( &g_ibsp.socket_info_list, &socket_info->item ); + + switch( old_state ) + { + case IBSP_CREATE: + case IBSP_LISTEN: + /* Nothing to do. */ + break; + + case IBSP_CONNECTED: + { + struct disconnect_reason reason; + + memset( &reason, 0, sizeof(reason) ); + reason.type = DISC_SHUTDOWN; + ib_disconnect( socket_info, &reason ); + } + /* Fall through. */ + + case IBSP_CONNECT: + case IBSP_DISCONNECTED: + /* We changed the state - remove from connection map. */ + CL_ASSERT( socket_info->conn_item.p_map ); + cl_rbmap_remove_item( &g_ibsp.conn_map, &socket_info->conn_item ); + break; + } + cl_spinlock_release( &g_ibsp.socket_info_mutex ); + + /* Flush all completions. */ + if( socket_info->dup_cnt ) + ibsp_dup_overlap_abort( socket_info ); + + while( socket_info->send_cnt || socket_info->recv_cnt ) + ib_cq_comp( socket_info->cq_tinfo ); + + ibsp_dereg_socket( socket_info ); + + ib_destroy_socket( socket_info ); + +#ifdef IBSP_LOGGING + DataLogger_Shutdown(&socket_info->SendDataLogger); + DataLogger_Shutdown(&socket_info->RecvDataLogger); +#endif + + /* Release the initial reference and clean up. */ + deref_socket_info( socket_info ); + + IBSP_EXIT( IBSP_DBG_EP ); +} + + +boolean_t +ibsp_conn_insert( + IN struct ibsp_socket_info *s ) +{ + struct ibsp_socket_info *p_sock; + cl_rbmap_item_t *p_item, *p_insert_at; + boolean_t left = TRUE; + + cl_spinlock_acquire( &g_ibsp.socket_info_mutex ); + p_item = cl_rbmap_root( &g_ibsp.conn_map ); + p_insert_at = p_item; + + CL_ASSERT( !s->conn_item.p_map ); + while( p_item != cl_rbmap_end( &g_ibsp.conn_map ) ) + { + p_insert_at = p_item; + p_sock = PARENT_STRUCT( p_item, struct ibsp_socket_info, conn_item ); + if( p_sock->local_addr.sin_family < s->local_addr.sin_family ) + p_item = cl_rbmap_left( p_item ), left = TRUE; + else if( p_sock->local_addr.sin_family > s->local_addr.sin_family ) + p_item = cl_rbmap_right( p_item ), left = FALSE; + else if( p_sock->local_addr.sin_addr.S_un.S_addr < s->local_addr.sin_addr.S_un.S_addr ) + p_item = cl_rbmap_left( p_item ), left = TRUE; + else if( p_sock->local_addr.sin_addr.S_un.S_addr > s->local_addr.sin_addr.S_un.S_addr ) + p_item = cl_rbmap_right( p_item ), left = FALSE; + else if( p_sock->local_addr.sin_port < s->local_addr.sin_port ) + p_item = cl_rbmap_left( p_item ), left = TRUE; + else if( p_sock->local_addr.sin_port > s->local_addr.sin_port ) + p_item = cl_rbmap_right( p_item ), left = FALSE; + else if( p_sock->peer_addr.sin_family < s->peer_addr.sin_family ) + p_item = cl_rbmap_left( p_item ), left = TRUE; + else if( p_sock->peer_addr.sin_family > s->peer_addr.sin_family ) + p_item = cl_rbmap_right( p_item ), left = FALSE; + else if( p_sock->peer_addr.sin_addr.S_un.S_addr < s->peer_addr.sin_addr.S_un.S_addr ) + p_item = cl_rbmap_left( p_item ), left = TRUE; + else if( p_sock->peer_addr.sin_addr.S_un.S_addr > s->peer_addr.sin_addr.S_un.S_addr ) + p_item = cl_rbmap_right( p_item ), left = FALSE; + else if( p_sock->peer_addr.sin_port < s->peer_addr.sin_port ) + p_item = cl_rbmap_left( p_item ), left = TRUE; + else if( p_sock->peer_addr.sin_port > s->peer_addr.sin_port ) + p_item = cl_rbmap_right( p_item ), left = FALSE; + else + goto done; + } + + cl_rbmap_insert( &g_ibsp.conn_map, p_insert_at, &s->conn_item, left ); + +done: + cl_spinlock_release( &g_ibsp.socket_info_mutex ); + return p_item == cl_rbmap_end( &g_ibsp.conn_map ); +} + + +void +ibsp_conn_remove( + IN struct ibsp_socket_info *s ) +{ + cl_spinlock_acquire( &g_ibsp.socket_info_mutex ); + CL_ASSERT( s->conn_item.p_map ); + cl_rbmap_remove_item( &g_ibsp.conn_map, &s->conn_item ); + cl_spinlock_release( &g_ibsp.socket_info_mutex ); +} diff --git a/branches/WOF2-3/ulp/wsd/user/ibsp_ip.c b/branches/WOF2-3/ulp/wsd/user/ibsp_ip.c new file mode 100644 index 00000000..b0124bb4 --- /dev/null +++ b/branches/WOF2-3/ulp/wsd/user/ibsp_ip.c @@ -0,0 +1,556 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2006 Mellanox Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +/* Builds and returns the list of IP addresses available from all + * adapters. */ + +#include "ibspdebug.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "ibsp_ip.tmh" +#endif + +#include "ibspdll.h" +#include "iba/ibat.h" + +/*--------------------------------------------------------------------------*/ + +/* + * Query an IP address from a GUID + */ + +struct ip_query_context +{ + cl_fmap_t *p_ip_map; + struct ibsp_port *p_port; +}; + + +int CL_API +ip_cmp( + IN const void* const p_key1, + IN const void* const p_key2 ) +{ + struct ibsp_ip_addr *p_ip1, *p_ip2; + + p_ip1 = (struct ibsp_ip_addr*)p_key1; + p_ip2 = (struct ibsp_ip_addr*)p_key2; + + if( p_ip1->ip_addr.S_un.S_addr < p_ip2->ip_addr.S_un.S_addr ) + return -1; + else if( p_ip1->ip_addr.S_un.S_addr > p_ip2->ip_addr.S_un.S_addr ) + return 1; + + /* IP addresses match. See if we need a port match too. */ + if( !p_ip1->p_port || !p_ip2->p_port ) + return 0; + + /* We need a port match too. */ + return cl_memcmp( + &p_ip1->p_port->guid, &p_ip2->p_port->guid, sizeof(net64_t) ); +} + + +/* Synchronously query the SA for an IP address. */ +int +query_ip_address( + IN struct ibsp_port *p_port, + IN OUT cl_fmap_t *p_ip_map ) +{ + IOCTL_IBAT_IP_ADDRESSES_IN in; + IOCTL_IBAT_IP_ADDRESSES_OUT *p_out; + DWORD size; + LONG i; + cl_fmap_item_t *p_item; + + IBSP_ENTER( IBSP_DBG_HW ); + + /* The list must be initialized and empty */ + CL_ASSERT( !cl_fmap_count( p_ip_map ) ); + in.Version = IBAT_IOCTL_VERSION; + in.PortGuid = p_port->guid; + + cl_spinlock_acquire( &g_ibsp.ip_mutex ); + if( g_ibsp.h_ibat_dev == INVALID_HANDLE_VALUE ) + { + g_ibsp.h_ibat_dev = CreateFileW( IBAT_WIN32_NAME, + MAXIMUM_ALLOWED, 0, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); + } + cl_spinlock_release( &g_ibsp.ip_mutex ); + + size = sizeof(IOCTL_IBAT_IP_ADDRESSES_OUT); + + do + { + p_out = HeapAlloc( g_ibsp.heap, 0, size ); + + if( !p_out ) + { + IBSP_ERROR_EXIT( ("Failed to allocate output buffer.\n") ); + return -1; + } + + if( !DeviceIoControl( g_ibsp.h_ibat_dev, IOCTL_IBAT_IP_ADDRESSES, + &in, sizeof(in), p_out, size, &size, NULL ) ) + { + HeapFree( g_ibsp.heap, 0, p_out ); + IBSP_ERROR_EXIT( ( + "IOCTL_IBAT_IP_ADDRESSES for port %I64x failed (%x).\n", + p_port->guid, GetLastError()) ); + return -1; + } + + if( p_out->Size > size ) + { + size = p_out->Size; + HeapFree( g_ibsp.heap, 0, p_out ); + p_out = NULL; + } + + } while( !p_out ); + + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_HW, ("Port %I64x has %d IP addresses.\n", + p_port->guid, p_out->AddressCount) ); + + for( i = 0; i < p_out->AddressCount; i++ ) + { + struct ibsp_ip_addr *ip_addr; + + ip_addr = HeapAlloc( + g_ibsp.heap, 0, sizeof(struct ibsp_ip_addr) ); + if( !ip_addr ) + { + IBSP_ERROR_EXIT( ("no memory\n") ); + break; + } + /* Copy the IP address being ia64 friendly */ + memcpy( (void*)&ip_addr->ip_addr.S_un.S_addr, + (void*)&p_out->Address[i].Address[ATS_IPV4_OFFSET], + sizeof(ib_net32_t) ); + + ip_addr->p_port = p_port; + + p_item = cl_fmap_insert( p_ip_map, ip_addr, &ip_addr->item ); + if( p_item != &ip_addr->item ) + { + /* Duplicate! Should never happen. */ + IBSP_ERROR( ( + "Got duplicate addr %s\n", inet_ntoa( ip_addr->ip_addr )) ); + HeapFree( g_ibsp.heap, 0, ip_addr ); + continue; + } + + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_HW, + ("Got addr %s\n", inet_ntoa( ip_addr->ip_addr )) ); + } + + HeapFree( g_ibsp.heap, 0, p_out ); + + IBSP_EXIT( IBSP_DBG_HW ); + return 0; +} + + +/* Query a port for it list of supported IP addresses, and update the port and global lists. + * The port mutex must be taken. */ +static int +update_ip_addresses( + struct ibsp_port *port ) +{ + cl_fmap_t new_ip, old_ip, dup_ip; + cl_fmap_item_t *p_item; + int ret; + + cl_fmap_init( &new_ip, ip_cmp ); + cl_fmap_init( &old_ip, ip_cmp ); + cl_fmap_init( &dup_ip, ip_cmp ); + + /* Get the list of new addresses */ + ret = query_ip_address( port, &dup_ip ); + if( ret ) + { + IBSP_ERROR_EXIT( ( + "query_ip_address failed (%d)\n", ret) ); + return 1; + } + + cl_spinlock_acquire( &g_ibsp.ip_mutex ); + + /* Insert the new list of IP into the global list of IP addresses. */ + cl_fmap_delta( &g_ibsp.ip_map, &dup_ip, &new_ip, &old_ip ); + cl_fmap_merge( &g_ibsp.ip_map, &new_ip ); + CL_ASSERT( !cl_fmap_count( &new_ip ) ); + + /* + * Note that the map delta operation will have moved all IP addresses + * for other ports into the old list. Move them back. + */ + for( p_item = cl_fmap_head( &old_ip ); + p_item != cl_fmap_end( &old_ip ); + p_item = cl_fmap_head( &old_ip ) ) + { + struct ibsp_ip_addr *p_ip = + PARENT_STRUCT( p_item, struct ibsp_ip_addr, item ); + + cl_fmap_remove_item( &old_ip, p_item ); + + if( p_ip->p_port != port ) + { + p_item = cl_fmap_insert( &g_ibsp.ip_map, p_ip, &p_ip->item ); + CL_ASSERT( p_item == &p_ip->item ); + } + else + { + HeapFree( g_ibsp.heap, 0, p_ip ); + } + } + + cl_spinlock_release( &g_ibsp.ip_mutex ); + + /* Now clean up duplicates entries. */ + for( p_item = cl_fmap_head( &dup_ip ); + p_item != cl_fmap_end( &dup_ip ); + p_item = cl_fmap_head( &dup_ip ) ) + { + struct ibsp_ip_addr *p_ip = + PARENT_STRUCT( p_item, struct ibsp_ip_addr, item ); + + cl_fmap_remove_item( &dup_ip, p_item ); + + HeapFree( g_ibsp.heap, 0, p_ip ); + } + + return 0; +} + +/*--------------------------------------------------------------------------*/ + + +/* Synchronously query the SA for a GUID. Return 0 on success. */ +int +query_guid_address( + IN const struct sockaddr *p_src_addr, + IN const struct sockaddr *p_dest_addr, + OUT ib_net64_t *port_guid ) +{ + ib_path_rec_t path; + HRESULT hr; + + IBSP_ENTER( IBSP_DBG_HW ); + hr = IbatResolvePath(p_src_addr, p_dest_addr, (IBAT_PATH_BLOB*)&path, + INFINITE); + + if( hr == S_OK ) + { + *port_guid = path.dgid.unicast.interface_id; + } + else + { + IBSP_ERROR( ("IBAT::Resolve for IP %08x\n", + ((struct sockaddr_in*)p_dest_addr)->sin_addr.s_addr) ); + } + return hr; +} + +/*--------------------------------------------------------------------------*/ + +/* + * Get a path record from a GUID + */ +struct query_pr_context +{ + ib_api_status_t status; + ib_path_rec_t *path_rec; +}; + + +static void AL_API +query_pr_callback( + ib_query_rec_t *p_query_rec ) +{ + struct query_pr_context *query_context = + (struct query_pr_context *)p_query_rec->query_context; + ib_api_status_t status; + + IBSP_ENTER( IBSP_DBG_HW ); + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_HW, ("status is %d\n", p_query_rec->status) ); + + if( p_query_rec->status == IB_SUCCESS && p_query_rec->result_cnt ) + { + ib_path_rec_t *path_rec; + + query_context->status = IB_SUCCESS; + + path_rec = ib_get_query_path_rec( p_query_rec->p_result_mad, 0 ); + + CL_ASSERT( path_rec ); + + /* Copy the path record */ + *query_context->path_rec = *path_rec; + } + else + { + query_context->status = IB_ERROR; + } + + if( p_query_rec->p_result_mad ) + status = ib_put_mad( p_query_rec->p_result_mad ); + + IBSP_EXIT( IBSP_DBG_HW ); +} + + +/* Synchronously query the SA for a GUID. Return 0 on success. */ +int +query_pr( + IN ib_net64_t guid, + IN ib_net64_t dest_port_guid, + IN uint16_t dev_id, + OUT ib_path_rec_t *path_rec ) +{ + ib_gid_pair_t user_query; + struct query_pr_context query_context; + ib_query_handle_t query_handle; + ib_query_req_t query_req; + ib_api_status_t status; + uint8_t pkt_life; + + IBSP_ENTER( IBSP_DBG_HW ); + + query_req.query_type = IB_QUERY_PATH_REC_BY_GIDS; + query_req.p_query_input = &user_query; + query_req.port_guid = guid; + query_req.timeout_ms = g_sa_timeout; + query_req.retry_cnt = g_sa_retries; + query_req.flags = IB_FLAGS_SYNC; + query_req.query_context = &query_context; + query_req.pfn_query_cb = query_pr_callback; + + ib_gid_set_default( &user_query.src_gid, guid ); + ib_gid_set_default( &user_query.dest_gid, dest_port_guid ); + + query_context.path_rec = path_rec; + + fzprint(("%s():%d:0x%x:0x%x: Calling ib_query()..\n", __FUNCTION__, + __LINE__, GetCurrentProcessId(), GetCurrentThreadId())); + + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_HW, + ("Query for path from %I64x to %I64x\n", + guid , dest_port_guid) ); + + status = ib_query( g_ibsp.al_handle, &query_req, &query_handle ); + + if( status != IB_SUCCESS ) + { + IBSP_ERROR( ("ib_query failed (%d)\n", status) ); + goto error; + } + + fzprint(("%s():%d:0x%x:0x%x: Done calling ib_query()..\n", __FUNCTION__, + __LINE__, GetCurrentProcessId(), GetCurrentThreadId())); + + if( query_context.status != IB_SUCCESS ) + { + IBSP_ERROR( ("query failed (%d)\n", query_context.status) ); + goto error; + } + + if( (dev_id == 0x5A44) && + (ib_path_rec_mtu( path_rec ) > IB_MTU_LEN_1024) ) + { + /* Local endpoint is Tavor - cap MTU to 1K for extra bandwidth. */ + path_rec->mtu &= IB_PATH_REC_SELECTOR_MASK; + path_rec->mtu |= IB_MTU_LEN_1024; + } + + pkt_life = ib_path_rec_pkt_life( path_rec ) + g_pkt_life_modifier; + if( pkt_life > 0x1F ) + pkt_life = 0x1F; + + path_rec->pkt_life &= IB_PATH_REC_SELECTOR_MASK; + path_rec->pkt_life |= pkt_life; + + IBSP_EXIT( IBSP_DBG_HW ); + return 0; + +error: + IBSP_ERROR_EXIT( ("query_pr failed\n") ); + return 1; +} + +/*--------------------------------------------------------------------------*/ + +/* Builds the list of all IP addresses supported. */ +int +build_ip_list( + IN OUT LPSOCKET_ADDRESS_LIST ip_list, + IN OUT LPDWORD ip_list_size, + OUT LPINT lpErrno ) +{ + size_t size_req; + size_t num_ip; + cl_list_item_t *p_hca_item, *p_port_item; + cl_fmap_item_t *p_item; + struct ibsp_hca *p_hca; + struct ibsp_port *p_port; + struct sockaddr_in *addr; + int i; + + IBSP_ENTER( IBSP_DBG_HW ); + + cl_spinlock_acquire( &g_ibsp.hca_mutex ); + for( p_hca_item = cl_qlist_head( &g_ibsp.hca_list ); + p_hca_item != cl_qlist_end( &g_ibsp.hca_list ); + p_hca_item = cl_qlist_next( p_hca_item ) ) + { + p_hca = PARENT_STRUCT( p_hca_item, struct ibsp_hca, item ); + + cl_spinlock_acquire( &p_hca->port_lock ); + for( p_port_item = cl_qlist_head( &p_hca->port_list ); + p_port_item != cl_qlist_end( &p_hca->port_list ); + p_port_item = cl_qlist_next( p_port_item ) ) + { + p_port = PARENT_STRUCT( p_port_item, struct ibsp_port, item ); + update_ip_addresses( p_port ); + } + cl_spinlock_release( &p_hca->port_lock ); + } + cl_spinlock_release( &g_ibsp.hca_mutex ); + + cl_spinlock_acquire( &g_ibsp.ip_mutex ); + + num_ip = cl_fmap_count( &g_ibsp.ip_map ); + + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_HW, (" num ip = %Id\n", num_ip) ); + + /* Note: the required size computed is a few bytes larger than necessary, + * but that keeps the code clean. */ + size_req = sizeof(SOCKET_ADDRESS_LIST); + + switch( num_ip ) + { + case 0: + cl_spinlock_acquire( &g_ibsp.ip_mutex ); + if( g_ibsp.h_ibat_dev != INVALID_HANDLE_VALUE ) + { + CloseHandle( g_ibsp.h_ibat_dev ); + g_ibsp.h_ibat_dev = INVALID_HANDLE_VALUE; + } + cl_spinlock_release( &g_ibsp.ip_mutex ); + break; + + default: + size_req += + (num_ip - 1) * (sizeof(SOCKET_ADDRESS) + sizeof(SOCKADDR)); + /* Fall through. */ + + case 1: + /* Add the space for the first address. */ + size_req += sizeof(SOCKADDR); + break; + } + + if( size_req > *ip_list_size ) + { + cl_spinlock_release( &g_ibsp.ip_mutex ); + *ip_list_size = (DWORD) size_req; + *lpErrno = WSAEFAULT; + IBSP_ERROR_EXIT( ( + "returning default, size %Id (usually not an error)\n", size_req) ); + return SOCKET_ERROR; + } + + memset( ip_list, 0, *ip_list_size ); + + /* We store the array of addresses after the last address pointer. */ + addr = (struct sockaddr_in *)(&(ip_list->Address[num_ip])); + *ip_list_size = (DWORD) size_req; + + ip_list->iAddressCount = (INT) num_ip; + + for( i = 0, p_item = cl_fmap_head( &g_ibsp.ip_map ); + p_item != cl_fmap_end( &g_ibsp.ip_map ); + i++, p_item = cl_fmap_next( p_item ) ) + { + struct ibsp_ip_addr *ip_addr = + PARENT_STRUCT(p_item, struct ibsp_ip_addr, item); + + ip_list->Address[i].iSockaddrLength = sizeof(struct sockaddr_in); + ip_list->Address[i].lpSockaddr = (LPSOCKADDR) addr; + + addr->sin_family = AF_INET; + addr->sin_port = 0; + addr->sin_addr = ip_addr->ip_addr; + + addr++; + } + + cl_spinlock_release( &g_ibsp.ip_mutex ); + + IBSP_EXIT( IBSP_DBG_HW ); + + lpErrno = 0; + return 0; +} + + +/* Find a port associated with an IP address. */ +struct ibsp_port * +get_port_from_ip_address( + IN const struct in_addr sin_addr ) +{ + cl_fmap_item_t *p_item; + struct ibsp_ip_addr ip; + struct ibsp_port *p_port = NULL; + + IBSP_ENTER( IBSP_DBG_HW ); + + ip.ip_addr = sin_addr; + ip.p_port = NULL; + + cl_spinlock_acquire( &g_ibsp.ip_mutex ); + + p_item = cl_fmap_get( &g_ibsp.ip_map, &ip ); + if( p_item != cl_fmap_end( &g_ibsp.ip_map ) ) + p_port = PARENT_STRUCT(p_item, struct ibsp_ip_addr, item)->p_port; + else + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_HW, ("not found\n") ); + + cl_spinlock_release( &g_ibsp.ip_mutex ); + + IBSP_EXIT( IBSP_DBG_HW ); + return p_port; +} diff --git a/branches/WOF2-3/ulp/wsd/user/ibsp_mem.c b/branches/WOF2-3/ulp/wsd/user/ibsp_mem.c new file mode 100644 index 00000000..70710441 --- /dev/null +++ b/branches/WOF2-3/ulp/wsd/user/ibsp_mem.c @@ -0,0 +1,400 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2006 Mellanox Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +/* Registers a memory region */ +#include "ibspdebug.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "ibsp_mem.tmh" +#endif + +#include "ibspdll.h" + + +__forceinline boolean_t +__check_mr( + IN struct memory_reg *p_reg, + IN ib_access_t acl_mask, + IN void *start, + IN size_t len ) +{ + return( (p_reg->type.access_ctrl & acl_mask) == acl_mask && + start >= p_reg->type.vaddr && + ((ULONG_PTR)start) + len <= + ((ULONG_PTR)p_reg->type.vaddr) + p_reg->type.length ); +} + + +/* Find the first registered mr that matches the given region. + * mem_list is either socket_info->buf_mem_list or socket_info->rdma_mem_list. + */ +struct memory_node * +lookup_partial_mr( + IN struct ibsp_socket_info *s, + IN ib_access_t acl_mask, + IN void *start, + IN size_t len ) +{ + struct memory_node *p_node; + cl_list_item_t *p_item; + + IBSP_ENTER( IBSP_DBG_MEM ); + + cl_spinlock_acquire( &s->port->hca->rdma_mem_list.mutex ); + + for( p_item = cl_qlist_head( &s->mr_list ); + p_item != cl_qlist_end( &s->mr_list ); + p_item = cl_qlist_next( p_item ) ) + { + p_node = PARENT_STRUCT( p_item, struct memory_node, socket_item ); + if(p_node->p_reg1 && + __check_mr( p_node->p_reg1, acl_mask, start, len ) ) + { + cl_spinlock_release( &s->port->hca->rdma_mem_list.mutex ); + IBSP_EXIT( IBSP_DBG_MEM ); + return p_node; + } + } + + cl_spinlock_release( &s->port->hca->rdma_mem_list.mutex ); + + IBSP_PRINT_EXIT(TRACE_LEVEL_INFORMATION, IBSP_DBG_MEM, ("mr not found\n") ); + return NULL; +} + + +/* Registers a memory region. The memory region might be cached. + * mem_list is either socket_info->buf_mem_list or hca->rdma_mem_list. + */ +struct memory_node * +ibsp_reg_mem( + IN struct ibsp_socket_info *s, + IN ib_pd_handle_t pd, + IN void *start, + IN size_t len, + IN ib_access_t access_ctrl, + OUT LPINT lpErrno ) +{ + struct memory_node *p_node; + struct memory_reg *p_reg; + cl_list_item_t *p_item; + ib_api_status_t status; + + IBSP_ENTER( IBSP_DBG_MEM ); + + CL_ASSERT( start != NULL ); + CL_ASSERT( len != 0 ); + CL_ASSERT( (access_ctrl & ~(IB_AC_RDMA_READ | IB_AC_RDMA_WRITE | IB_AC_LOCAL_WRITE)) == + 0 ); + + /* Optimistically allocate a tracking structure. */ + p_node = HeapAlloc( g_ibsp.heap, 0, sizeof(struct memory_node) ); + if( !p_node ) + { + IBSP_ERROR_EXIT( ("AllocateOverlappedBuf:HeapAlloc() failed: %d\n", + GetLastError()) ); + *lpErrno = WSAENOBUFS; + return NULL; + } + + /* First, try to find a suitable MR */ + cl_spinlock_acquire( &s->port->hca->rdma_mem_list.mutex ); + + /* Find the first registered mr that matches the given region. */ + for( p_item = cl_qlist_head( &s->port->hca->rdma_mem_list.list ); + p_item != cl_qlist_end( &s->port->hca->rdma_mem_list.list ); + p_item = cl_qlist_next( p_item ) ) + { + p_reg = PARENT_STRUCT(p_item, struct memory_reg, item); + + if( __check_mr( p_reg, access_ctrl, start, len ) ) + { + p_node->p_reg1 = p_reg; + p_node->s = s; + cl_qlist_insert_tail( &p_reg->node_list, &p_node->mr_item ); + cl_qlist_insert_head( + &s->mr_list, &p_node->socket_item ); + cl_spinlock_release( &s->port->hca->rdma_mem_list.mutex ); + IBSP_EXIT( IBSP_DBG_MEM ); + return p_node; + } + } + + /* No corresponding MR has been found. Create a new one. */ + p_reg = HeapAlloc( g_ibsp.heap, 0, sizeof(struct memory_reg) ); + + if( !p_reg ) + { + IBSP_ERROR_EXIT( ("AllocateOverlappedBuf:HeapAlloc() failed: %d\n", + GetLastError()) ); + cl_spinlock_release( &s->port->hca->rdma_mem_list.mutex ); + HeapFree( g_ibsp.heap, 0, p_node ); + *lpErrno = WSAENOBUFS; + return NULL; + } + + /* The node is not initialized yet. All the parameters given are + * supposed to be valid so we don't check them. */ + cl_qlist_init( &p_reg->node_list ); + p_reg->type.vaddr = start; + p_reg->type.length = len; + p_reg->type.access_ctrl = access_ctrl; + + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_MEM, ("pinning memory node %p\n", p_node) ); + status = ib_reg_mem( + pd, &p_reg->type, &p_reg->lkey, &p_reg->rkey, &p_reg->mr_handle ); + + if( status ) + { + cl_spinlock_release( &s->port->hca->rdma_mem_list.mutex ); + HeapFree( g_ibsp.heap, 0, p_reg ); + HeapFree( g_ibsp.heap, 0, p_node ); + + IBSP_ERROR_EXIT( ("ib_reg_mem returned %s\n", ib_get_err_str(status)) ); + + *lpErrno = WSAEFAULT; + return NULL; + } + + STAT_INC( mr_num ); + + p_node->p_reg1 = p_reg; + p_node->s = s; + + /* Link to the list of nodes. */ + cl_qlist_insert_head( &s->port->hca->rdma_mem_list.list, &p_reg->item ); + cl_qlist_insert_head( &s->mr_list, &p_node->socket_item ); + cl_qlist_insert_tail( &p_reg->node_list, &p_node->mr_item ); + cl_spinlock_release( &s->port->hca->rdma_mem_list.mutex ); + + IBSP_EXIT( IBSP_DBG_MEM ); + + *lpErrno = 0; + return p_node; +} + + +static inline int __ibsp_dereg_mem_mr( + IN struct memory_node *node ) +{ + IBSP_ENTER( IBSP_DBG_MEM ); + + // Underlying registration could be freed before the node. + if( node->p_reg1 ) + cl_qlist_remove_item( &node->p_reg1->node_list, &node->mr_item ); + + cl_qlist_remove_item( &node->s->mr_list, &node->socket_item ); + + + memset(node,0x45,sizeof node); + HeapFree( g_ibsp.heap, 0, node ); + + IBSP_EXIT( IBSP_DBG_MEM ); + return 0; +} + + +/* Deregisters a memory region */ +int +ibsp_dereg_mem( + IN struct ibsp_socket_info *s, + IN struct memory_node *node, + OUT LPINT lpErrno ) +{ + IBSP_ENTER( IBSP_DBG_MEM ); + + cl_spinlock_acquire( &s->port->hca->rdma_mem_list.mutex ); + *lpErrno = __ibsp_dereg_mem_mr( node ); + cl_spinlock_release( &s->port->hca->rdma_mem_list.mutex ); + + IBSP_EXIT( IBSP_DBG_MEM ); + return (*lpErrno? SOCKET_ERROR : 0); +} + + +/* + * Deregister the remaining memory regions on an HCA. This function should + * only be called before destroying the PD. In normal case, the list should + * be empty because the switch should have done it. + */ +void +ibsp_dereg_hca( + IN struct mr_list *mem_list ) +{ + cl_list_item_t *item; + cl_list_item_t *item1; + + IBSP_ENTER( IBSP_DBG_MEM ); + + cl_spinlock_acquire( &mem_list->mutex ); + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_MEM, + ("%Id registrations.\n", cl_qlist_count( &mem_list->list )) ); + + for( item = cl_qlist_remove_head( &mem_list->list ); + item != cl_qlist_end( &mem_list->list ); + item = cl_qlist_remove_head( &mem_list->list ) ) + { + struct memory_reg *p_reg = PARENT_STRUCT(item, struct memory_reg, item); + ib_api_status_t status; + + /* + * Clear the pointer from the node to this registration. No need + * to remove from the list as we're about to free the registration. + */ + for( item1 = cl_qlist_head( &p_reg->node_list ); + item1 != cl_qlist_end( &p_reg->node_list ); + item1 = cl_qlist_next( item1 ) ) + { + struct memory_node *p_node = + PARENT_STRUCT( item1, struct memory_node, mr_item ); + p_node->p_reg1 = NULL; + } + + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_MEM, ("unpinning ,memory reg %p\n", p_reg) ); + status = ib_dereg_mr( p_reg->mr_handle ); + if( status ) + { + IBSP_ERROR( ( + "ib_dereg_mem returned %s\n", ib_get_err_str( status )) ); + } + else + { + STAT_DEC( mr_num ); + } + + HeapFree( g_ibsp.heap, 0, p_reg ); + } + + cl_spinlock_release( &mem_list->mutex ); + + IBSP_EXIT( IBSP_DBG_MEM ); +} + + +/* Deregister the remaining memory regions. This function should only + * be called when destroying the socket. In normal case, the list should + * be empty because the switch should have done it. */ +void +ibsp_dereg_socket( + IN struct ibsp_socket_info *s ) +{ + IBSP_ENTER( IBSP_DBG_MEM ); + + if( !s->port ) + { + CL_ASSERT( !cl_qlist_count( &s->mr_list ) ); + IBSP_EXIT( IBSP_DBG_MEM ); + return; + } + + cl_spinlock_acquire( &s->port->hca->rdma_mem_list.mutex ); + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_MEM, + ("%Id registrations.\n", cl_qlist_count( &s->mr_list )) ); + + while( cl_qlist_count( &s->mr_list ) ) + { + __ibsp_dereg_mem_mr( PARENT_STRUCT( cl_qlist_head( &s->mr_list ), + struct memory_node, socket_item) ); + } + + cl_spinlock_release( &s->port->hca->rdma_mem_list.mutex ); + + IBSP_EXIT( IBSP_DBG_MEM ); +} + + +/* + * Loop through all the memory registrations on an HCA and release + * all that fall within the specified range. + */ +void +ibsp_hca_flush_mr_cache( + IN struct ibsp_hca *p_hca, + IN LPVOID lpvAddress, + IN SIZE_T Size ) +{ + struct memory_reg *p_reg; + cl_list_item_t *p_item; + cl_list_item_t *p_item1; + ib_api_status_t status; + + IBSP_ENTER( IBSP_DBG_MEM ); + + cl_spinlock_acquire( &p_hca->rdma_mem_list.mutex ); + p_item = cl_qlist_head( &p_hca->rdma_mem_list.list ); + while( p_item != cl_qlist_end( &p_hca->rdma_mem_list.list ) ) + { + p_reg = PARENT_STRUCT( p_item, struct memory_reg, item ); + + /* Move to the next item now so we can remove the current. */ + p_item = cl_qlist_next( p_item ); + + if( lpvAddress > p_reg->type.vaddr || + ((ULONG_PTR)lpvAddress) + Size < + ((ULONG_PTR)p_reg->type.vaddr) + p_reg->type.length ) + { + continue; + } + + /* + * Clear the pointer from all sockets' nodes to this registration. + * No need to remove from the list as we're about to free the + * registration. + */ + for( p_item1 = cl_qlist_head( &p_reg->node_list ); + p_item1 != cl_qlist_end( &p_reg->node_list ); + p_item1 = cl_qlist_next( p_item1 ) ) + { + struct memory_node *p_node = + PARENT_STRUCT( p_item1, struct memory_node, mr_item ); + + p_node->p_reg1 = NULL; + } + + cl_qlist_remove_item( &p_hca->rdma_mem_list.list, &p_reg->item ); + + status = ib_dereg_mr( p_reg->mr_handle ); + if( status != IB_SUCCESS ) + { + IBSP_ERROR( ( + "ib_dereg_mr returned %s\n", ib_get_err_str(status)) ); + } + + HeapFree( g_ibsp.heap, 0, p_reg ); + } + cl_spinlock_release( &p_hca->rdma_mem_list.mutex ); + + IBSP_EXIT( IBSP_DBG_MEM ); +} diff --git a/branches/WOF2-3/ulp/wsd/user/ibsp_mem.h b/branches/WOF2-3/ulp/wsd/user/ibsp_mem.h new file mode 100644 index 00000000..39861287 --- /dev/null +++ b/branches/WOF2-3/ulp/wsd/user/ibsp_mem.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ diff --git a/branches/WOF2-3/ulp/wsd/user/ibsp_perfmon.c b/branches/WOF2-3/ulp/wsd/user/ibsp_perfmon.c new file mode 100644 index 00000000..e4d947a7 --- /dev/null +++ b/branches/WOF2-3/ulp/wsd/user/ibsp_perfmon.c @@ -0,0 +1,562 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2006 Mellanox Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include "ibspdebug.h" +#if defined(EVENT_TRACING) +#include "ibsp_perfmon.tmh" +#endif + +#include +#include "ibspdll.h" +#include "ibsp_perfmon.h" + + +struct _ibsp_pm_definition g_ibsp_pm_def; /* IB WSD performance object */ + +struct _pm_stat g_pm_stat; + +void +IBSPPmInit( void ) +{ + HANDLE h_mapping; + BOOL just_created; + SECURITY_ATTRIBUTES sec_attr; + + IBSP_ENTER( IBSP_DBG_PERFMON ); + + g_pm_stat.idx = INVALID_IDX; + g_pm_stat.p_shmem = NULL; + + sec_attr.nLength = sizeof(SECURITY_ATTRIBUTES); + sec_attr.bInheritHandle = FALSE; + + if( !ConvertStringSecurityDescriptorToSecurityDescriptor( + IBSP_PM_SEC_STRING, SDDL_REVISION_1, + &(sec_attr.lpSecurityDescriptor), NULL ) ) + { + IBSP_ERROR( ("SecurityDescriptor error %d\n", GetLastError()) ); + return; + } + + h_mapping = CreateFileMapping( + INVALID_HANDLE_VALUE, // use paging file + &sec_attr, // security attributes + PAGE_READWRITE, // read/write access + 0, // size: high 32-bits + sizeof(pm_shmem_t), // size: low 32-bits + IBSP_PM_MAPPED_OBJ_NAME ); + + just_created = (GetLastError() != ERROR_ALREADY_EXISTS); + + LocalFree( sec_attr.lpSecurityDescriptor ); + + if( h_mapping == NULL ) + { + IBSP_ERROR_EXIT( ("CreateFileMapping error %d\n", GetLastError()) ); + return; + } + + /* Get a pointer to the shared memory. */ + g_pm_stat.p_shmem = MapViewOfFile( + h_mapping, // object handle + FILE_MAP_ALL_ACCESS, + 0, // high offset: map from + 0, // low offset: beginning + 0); // num bytes to map + + /* Now that we have the view mapped, we don't need the mapping handle. */ + g_pm_stat.h_mapping = h_mapping; + + if( g_pm_stat.p_shmem == NULL ) + { + IBSP_ERROR( ("MapViewOfFile returned %d\n", GetLastError()) ); + return; + } + + if( just_created ) + { + /* + * Reserve instance 0 for fallback counters + * Apps that can't get a dedicated slot will share this one. + */ + wcscpy( g_pm_stat.p_shmem->obj[0].app_name, + IBSP_PM_TOTAL_COUNTER_NAME ); + g_pm_stat.p_shmem->obj[0].taken = 1; + } + + IBSP_EXIT( IBSP_DBG_PERFMON ); +} + + +/* + * We always get a slot - either an individual one, or fall back on the + * common one. + */ +void +IBSPPmGetSlot( void ) +{ + WCHAR mod_path[MAX_PATH]; + WCHAR* buf; + int idx; + size_t name_len; + WCHAR id_str[12]; + mem_obj_t *p_slot; + pm_shmem_t* p_mem = g_pm_stat.p_shmem; + + IBSP_ENTER( IBSP_DBG_PERFMON ); + + if( g_pm_stat.p_shmem == NULL ) + { + g_pm_stat.pdata = g_pm_stat.fall_back_data; + return; + } + + GetModuleFileNameW( NULL, mod_path, MAX_PATH ); + + buf = wcsrchr( mod_path, L'\\' ); + if( !buf ) + buf = mod_path; + else + buf++; + + /* The max length is 11, one for the ':', and 10 for the process ID. */ + id_str[0] = ':'; + _ultow( GetCurrentProcessId(), &id_str[1], 10 ); + + /* Cap the length of the application. */ + name_len = min( wcslen( buf ), + IBSP_PM_APP_NAME_SIZE - 1 - wcslen( id_str ) ); + + /* instance 0 is taken for "Total" counters, so don't try it */ + for( idx = 1; idx < IBSP_PM_NUM_INSTANCES; idx++) + { + /* Compare with 0, exchange with 1 */ + if( InterlockedCompareExchange( + &g_pm_stat.p_shmem->obj[idx].taken, 1, 0 ) ) + { + continue; + } + + p_slot = &g_pm_stat.p_shmem->obj[idx]; + + /* Copy the app name. */ + CopyMemory( p_slot->app_name, buf, name_len * sizeof(WCHAR) ); + CopyMemory( &p_slot->app_name[name_len], id_str, + (wcslen( id_str ) + 1) * sizeof(WCHAR) ); + + g_pm_stat.idx = idx; + g_pm_stat.pdata = g_pm_stat.p_shmem->obj[idx].data; + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_PERFMON, + ("%S got slot %d\n", p_slot->app_name, idx) ); + break; + } + + if( idx == IBSP_PM_NUM_INSTANCES ) + { + /* + * Assign "Total" slot for this process to avoid loosing precious + * statistic. Keep saved idx INVALID so data won't be flushed during + * process closeout. + */ + g_pm_stat.pdata = p_mem->obj[0].data; + } + + IBSP_EXIT( IBSP_DBG_PERFMON ); +} + + +void +IBSPPmReleaseSlot( void ) +{ + mem_obj_t *p_slot; + int idx; + + /* perfmon never get registered itself in shared mem buffer */ + if ( g_pm_stat.idx == INVALID_IDX ) + return; + + if( g_pm_stat.p_shmem == NULL ) + return; + + p_slot = &g_pm_stat.p_shmem->obj[g_pm_stat.idx]; + + /* Add all the data to the "Total" bin (0) */ + for( idx = 0; idx < IBSP_PM_NUM_COUNTERS; idx++ ) + { + InterlockedExchangeAdd64( &g_pm_stat.p_shmem->obj[0].data[idx], + InterlockedExchange64( &g_pm_stat.pdata[idx], 0 ) ); + } + ZeroMemory( p_slot->app_name, sizeof(p_slot->app_name) ); + InterlockedExchange( &p_slot->taken, 0 ); + + g_pm_stat.idx = INVALID_IDX; + + IBSP_EXIT( IBSP_DBG_PERFMON ); +} + + +static BOOL +__PmIsQuerySupported( + IN WCHAR* p_query_str ) +{ + if( p_query_str == NULL ) + return TRUE; + + if( *p_query_str == 0 ) + return TRUE; + + if( wcsstr( p_query_str, L"Global" ) != NULL ) + return TRUE; + + if( wcsstr( p_query_str, L"Foreign" ) != NULL ) + return FALSE; + + if( wcsstr( p_query_str, L"Costly" ) != NULL ) + return FALSE; + + else + return TRUE; +} + + +/* + * http://msdn.microsoft.com/library/en-us/perfctrs/perf/openperformancedata.asp + */ +DWORD APIENTRY +IBSPPmOpen( + IN LPWSTR lpDeviceNames ) +{ + DWORD status = ERROR_SUCCESS; + HKEY pm_hkey = NULL; + DWORD data_size; + DWORD data_type; + DWORD first_counter = 0; + DWORD first_help = 0; + int num = 0; + int num_offset; + + IBSP_ENTER( IBSP_DBG_PERFMON ); + + UNUSED_PARAM(lpDeviceNames); + + if( g_pm_stat.threads++ ) + { + IBSP_EXIT( IBSP_DBG_PERFMON ); + return ERROR_SUCCESS; + } + + /* open Registry and query for the first and last keys */ + status = RegOpenKeyEx( HKEY_LOCAL_MACHINE, + IBSP_PM_REGISTRY_PATH IBSP_PM_SUBKEY_PERF, + 0L, KEY_READ, &pm_hkey); + + if( status != ERROR_SUCCESS ) + { + g_pm_stat.threads--; + IBSP_ERROR_EXIT( ("RegOpenKeyEx for perf information returned %d.\n", status) ); + return status; + } + + data_size = sizeof(DWORD); + status = RegQueryValueEx( pm_hkey, "First Counter", 0L, + &data_type, (LPBYTE)&first_counter, &data_size ); + + if( status != ERROR_SUCCESS ) + { + RegCloseKey(pm_hkey); + g_pm_stat.threads--; + IBSP_ERROR_EXIT( ("RegQueryValueEx for \"First Counter\" returned %d.\n", status) ); + return status; + } + + data_size = sizeof(DWORD); + status = RegQueryValueEx( pm_hkey, "First Help", 0L, + &data_type, (LPBYTE)&first_help, &data_size ); + + RegCloseKey( pm_hkey ); + + if( status != ERROR_SUCCESS ) + { + g_pm_stat.threads--; + IBSP_ERROR_EXIT( ("RegQueryValueEx for \"First Help\" returned %d.\n", status) ); + return status; + } + + /* perf_obj */ + g_ibsp_pm_def.perf_obj.ObjectNameTitleIndex = IBSP_PM_OBJ + first_counter; + g_ibsp_pm_def.perf_obj.ObjectHelpTitleIndex = IBSP_PM_OBJ + first_help; + g_ibsp_pm_def.perf_obj.TotalByteLength = + sizeof(ibsp_pm_definition_t) + sizeof(ibsp_pm_counters_t); + g_ibsp_pm_def.perf_obj.DefinitionLength = sizeof(ibsp_pm_definition_t); + g_ibsp_pm_def.perf_obj.HeaderLength = sizeof(PERF_OBJECT_TYPE); + + g_ibsp_pm_def.perf_obj.ObjectNameTitle = 0; + g_ibsp_pm_def.perf_obj.ObjectHelpTitle = 0; + + g_ibsp_pm_def.perf_obj.DetailLevel = PERF_DETAIL_NOVICE; + g_ibsp_pm_def.perf_obj.NumCounters = IBSP_PM_NUM_COUNTERS; + g_ibsp_pm_def.perf_obj.DefaultCounter = 0; + g_ibsp_pm_def.perf_obj.NumInstances = 0; + g_ibsp_pm_def.perf_obj.CodePage = 0; + + QueryPerformanceFrequency( &g_ibsp_pm_def.perf_obj.PerfFreq ); + + /* initialize all counter definitions */ + num_offset = IBSP_PM_OBJ + 2; + for ( num = 0; num < IBSP_PM_NUM_COUNTERS ; num++, num_offset += 2) + { + g_ibsp_pm_def.counter[num].CounterNameTitleIndex = num_offset + first_counter; + g_ibsp_pm_def.counter[num].CounterHelpTitleIndex = num_offset + first_help; + g_ibsp_pm_def.counter[num].ByteLength = sizeof(PERF_COUNTER_DEFINITION); + g_ibsp_pm_def.counter[num].CounterNameTitle = 0; + g_ibsp_pm_def.counter[num].CounterHelpTitle = 0; + g_ibsp_pm_def.counter[num].DefaultScale = 0; + g_ibsp_pm_def.counter[num].DetailLevel = PERF_DETAIL_NOVICE; + g_ibsp_pm_def.counter[num].CounterType = PERF_COUNTER_BULK_COUNT; + /* All counters should be kept to 64-bits for consistency and simplicity. */ + g_ibsp_pm_def.counter[num].CounterSize = sizeof(LONG64); + g_ibsp_pm_def.counter[num].CounterOffset = + (DWORD)offsetof( ibsp_pm_counters_t, data[num] ); + } + + g_pm_stat.h_evlog = RegisterEventSource( NULL, IBSP_PM_SUBKEY_NAME ); + if( !g_pm_stat.h_evlog ) + { + g_pm_stat.threads--; + status = GetLastError(); + IBSP_ERROR_EXIT( ("RegisterEventSource failed with %d\n", status) ); + return status; + } + + IBSP_EXIT( IBSP_DBG_PERFMON ); + return ERROR_SUCCESS; +} + + +/* + * http://msdn.microsoft.com/library/en-us/perfctrs/perf/closeperformancedata.asp + */ +DWORD APIENTRY +IBSPPmClose( void ) +{ + BOOL status; + + IBSP_ENTER( IBSP_DBG_PERFMON ); + + if( --g_pm_stat.threads ) + { + IBSP_EXIT( IBSP_DBG_PERFMON ); + return ERROR_SUCCESS; + } + + IBSPPmReleaseSlot(); + + /* avoid double closing */ + if( g_pm_stat.p_shmem != NULL ) + { + status = UnmapViewOfFile( g_pm_stat.p_shmem ); + g_pm_stat.p_shmem = NULL; + } + + if( g_pm_stat.h_evlog != NULL ) + { + DeregisterEventSource( g_pm_stat.h_evlog ); + g_pm_stat.h_evlog = NULL; + } + + IBSP_EXIT( IBSP_DBG_PERFMON ); + return ERROR_SUCCESS; +} + + + +/* + * http://msdn.microsoft.com/library/en-us/perfctrs/perf/collectperformancedata.asp + */ +DWORD WINAPI +IBSPPmCollectData( + IN LPWSTR lpValueName, + IN OUT LPVOID* lppData, + IN OUT LPDWORD lpcbTotalBytes, + IN OUT LPDWORD lpNumObjectTypes ) +{ + int32_t sh_num; + int32_t num_instances, max_instances; + uint32_t use_bytes; + ibsp_pm_definition_t *p_obj_def; + ibsp_pm_counters_t *p_count_def; + PERF_INSTANCE_DEFINITION *p_inst_def; + pm_shmem_t *p_mem; + LONG64 total_data[IBSP_PM_NUM_COUNTERS]; + + IBSP_ENTER( IBSP_DBG_PERFMON ); + + p_mem = (pm_shmem_t *)g_pm_stat.p_shmem; + + if( p_mem == NULL ) + { + IBSP_ERROR( ("No shared memory object\n") ); + goto done; + } + + if( !__PmIsQuerySupported(lpValueName ) ) + { + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_PERFMON, ("Unsupported query\n") ); + goto done; + } + + if( !g_pm_stat.threads ) + { + IBSP_ERROR( ("Initialization was not completed\n") ); +done: + *lpcbTotalBytes = 0; + *lpNumObjectTypes = 0; + + IBSP_EXIT( IBSP_DBG_PERFMON ); + return ERROR_SUCCESS; + } + + ZeroMemory( &total_data, sizeof(total_data) ); + num_instances = 0; + /* sum total counters that were not filled in completion routine */ + for( sh_num = 0; sh_num < IBSP_PM_NUM_INSTANCES; sh_num++ ) + { + if( !InterlockedCompareExchange( &p_mem->obj[sh_num].taken, 1, 1 ) ) + continue; + + total_data[BYTES_SEND] += p_mem->obj[sh_num].data[BYTES_SEND]; + total_data[BYTES_RECV] += p_mem->obj[sh_num].data[BYTES_RECV]; + total_data[BYTES_WRITE] += p_mem->obj[sh_num].data[BYTES_WRITE]; + total_data[BYTES_READ] += p_mem->obj[sh_num].data[BYTES_READ]; + /* Update total for current slot. */ + p_mem->obj[sh_num].data[BYTES_TOTAL] = + p_mem->obj[sh_num].data[BYTES_SEND] + + p_mem->obj[sh_num].data[BYTES_RECV] + + p_mem->obj[sh_num].data[BYTES_WRITE] + + p_mem->obj[sh_num].data[BYTES_READ]; + total_data[BYTES_TOTAL] += p_mem->obj[sh_num].data[BYTES_TOTAL]; + total_data[COMP_SEND] += p_mem->obj[sh_num].data[COMP_SEND]; + total_data[COMP_RECV] += p_mem->obj[sh_num].data[COMP_RECV]; + total_data[COMP_TOTAL] += p_mem->obj[sh_num].data[COMP_TOTAL]; + total_data[INTR_TOTAL] += p_mem->obj[sh_num].data[INTR_TOTAL]; + + num_instances++; + } + + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_PERFMON, ("%d instances.\n", num_instances) ); + + /* calc buffer size required for data return */ + use_bytes = sizeof(ibsp_pm_definition_t) + \ + (sizeof(PERF_INSTANCE_DEFINITION) + \ + sizeof(ibsp_pm_counters_t) + \ + (sizeof(WCHAR) * IBSP_PM_APP_NAME_SIZE)) * num_instances; + + if( *lpcbTotalBytes < use_bytes ) + { + *lpcbTotalBytes = 0; + *lpNumObjectTypes = 0; + return ERROR_MORE_DATA; + } + + p_obj_def = (ibsp_pm_definition_t*)*lppData; + use_bytes = sizeof(ibsp_pm_definition_t); + + /* Copy counter definition */ + CopyMemory( p_obj_def, &g_ibsp_pm_def, sizeof(ibsp_pm_definition_t) ); + + p_obj_def->perf_obj.NumInstances = num_instances; + QueryPerformanceCounter( &p_obj_def->perf_obj.PerfTime ); + + max_instances = num_instances; + + /* Assign pointers for the first instance */ + p_inst_def = (PERF_INSTANCE_DEFINITION*)(p_obj_def + 1); + + for( sh_num = 0; sh_num < IBSP_PM_NUM_INSTANCES; sh_num++ ) + { + if( !InterlockedCompareExchange( &p_mem->obj[sh_num].taken, 1, 1 ) ) + continue; + + /* Make sure we don't overrun the buffer! */ + if( max_instances-- == 0 ) + break; + + p_inst_def->ByteLength = sizeof(PERF_INSTANCE_DEFINITION) + + (sizeof(WCHAR) * IBSP_PM_APP_NAME_SIZE); + p_inst_def->ParentObjectTitleIndex = 0; + p_inst_def->ParentObjectInstance = 0; + p_inst_def->UniqueID = -1; /* using module names */ + p_inst_def->NameOffset = sizeof(PERF_INSTANCE_DEFINITION); + + /* Length in bytes of Unicode name string, including terminating NULL */ + p_inst_def->NameLength = + (DWORD)wcslen( p_mem->obj[sh_num].app_name ) + 1; + p_inst_def->NameLength *= sizeof(WCHAR); + + CopyMemory( (WCHAR*)(p_inst_def + 1), + p_mem->obj[sh_num].app_name, p_inst_def->NameLength ); + + use_bytes += p_inst_def->ByteLength; + + /* advance to counter definition */ + p_count_def = (ibsp_pm_counters_t*) + (((BYTE*)p_inst_def) + p_inst_def->ByteLength); + + p_count_def->pm_block.ByteLength = sizeof(ibsp_pm_counters_t); + use_bytes += sizeof(ibsp_pm_counters_t); + + /* Here we report actual counter values. */ + if( sh_num == 0 ) + { + CopyMemory( p_count_def->data, total_data, sizeof(total_data) ); + } + else + { + CopyMemory( p_count_def->data, p_mem->obj[sh_num].data, + sizeof(p_mem->obj[sh_num].data) ); + } + + /* Advance pointers for the next instance definition */ + p_inst_def = (PERF_INSTANCE_DEFINITION*)(p_count_def + 1); + } + + p_obj_def->perf_obj.TotalByteLength = (DWORD)use_bytes; + + *lppData = ((BYTE*)*lppData) + use_bytes; + *lpNumObjectTypes = 1; + *lpcbTotalBytes = (DWORD)use_bytes; + + IBSP_EXIT( IBSP_DBG_PERFMON ); + return ERROR_SUCCESS; +} diff --git a/branches/WOF2-3/ulp/wsd/user/ibsp_perfmon.h b/branches/WOF2-3/ulp/wsd/user/ibsp_perfmon.h new file mode 100644 index 00000000..1d94cb78 --- /dev/null +++ b/branches/WOF2-3/ulp/wsd/user/ibsp_perfmon.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#ifndef _IBSP_PERFMON_H_ +#define _IBSP_PERFMON_H_ + + +#include +#include +#include "wsd/ibsp_regpath.h" + + +/* invalid instance index value to initialize */ +#define INVALID_IDX 0xffffffff + +#define IBSP_PM_SEC_STRING \ + TEXT("D:(A;CIOI;GAFA;;;WD)") /* SDDL_EVERYONE */ + +#define IBSP_PM_NUM_OBJECT_TYPES 1 +#define IBSP_PM_NUM_INSTANCES 100 /* how many processes we can handle */ + +#define IBSP_PM_APP_NAME_SIZE 24 /* Must be multiple of 8 */ +#define IBSP_PM_TOTAL_COUNTER_NAME L"_Total" +#define IBSP_PM_MAPPED_OBJ_NAME TEXT("Global\\ibwsd_perfmon_data") + + +/* Structures used to report counter information to perfmon. */ +typedef struct _ibsp_pm_definition +{ + PERF_OBJECT_TYPE perf_obj; + PERF_COUNTER_DEFINITION counter[IBSP_PM_NUM_COUNTERS]; + +} ibsp_pm_definition_t; + +typedef struct _ibsp_pm_counters +{ + PERF_COUNTER_BLOCK pm_block; + LONG64 data[IBSP_PM_NUM_COUNTERS]; + +} ibsp_pm_counters_t; + + +/* Structures used to manage counters internally */ +typedef struct _mem_obj +{ + volatile LONG taken; + WCHAR app_name[IBSP_PM_APP_NAME_SIZE]; + LONG64 data[IBSP_PM_NUM_COUNTERS]; + +} mem_obj_t; + +typedef struct _pm_shmem +{ + mem_obj_t obj[IBSP_PM_NUM_INSTANCES]; + +} pm_shmem_t; + + +/* global data for every process linked to this DLL */ +struct _pm_stat +{ + struct _pm_shmem* p_shmem; /* base pointer to shared memory for this process */ + volatile LONG64* pdata; /* pointer to data collected */ + HANDLE h_mapping; + HANDLE h_evlog; /* event log handle */ + DWORD threads; /* number of threads open */ + DWORD idx; /* slot index assigned for this process */ + LONG64 fall_back_data[IBSP_PM_NUM_COUNTERS]; + +}; + +extern struct _pm_stat g_pm_stat; + + +void +IBSPPmInit( void ); + +DWORD APIENTRY +IBSPPmClose( void ); + +void +IBSPPmGetSlot( void ); + +void +IBSPPmReleaseSlot( void ); + +#endif /* _IBSP_PERFMON_H_ */ diff --git a/branches/WOF2-3/ulp/wsd/user/ibsp_pnp.c b/branches/WOF2-3/ulp/wsd/user/ibsp_pnp.c new file mode 100644 index 00000000..efd1ef90 --- /dev/null +++ b/branches/WOF2-3/ulp/wsd/user/ibsp_pnp.c @@ -0,0 +1,443 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2006 Mellanox Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +/* TODO: right now, hotplug is not supported. */ + +#include "ibspdebug.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "ibsp_pnp.tmh" +#endif + +#include "ibspdll.h" + + +static void pnp_port_remove( + IN struct ibsp_port* const port ); + + +/* Find a HCA in the list based on its GUID */ +static struct ibsp_hca * +lookup_hca( + ib_net64_t ca_guid ) +{ + cl_list_item_t *item; + + cl_spinlock_acquire( &g_ibsp.hca_mutex ); + + for( item = cl_qlist_head( &g_ibsp.hca_list ); + item != cl_qlist_end( &g_ibsp.hca_list ); + item = cl_qlist_next( item ) ) + { + struct ibsp_hca *hca = PARENT_STRUCT(item, struct ibsp_hca, item); + if( hca->guid == ca_guid ) + { + /* Found */ + cl_spinlock_release( &g_ibsp.hca_mutex ); + return hca; + } + } + + cl_spinlock_release( &g_ibsp.hca_mutex ); + + return NULL; +} + + +/* Add a new adapter */ +ib_api_status_t +pnp_ca_add( + IN ib_pnp_ca_rec_t* const p_ca_rec ) +{ + struct ibsp_hca *hca; + ib_api_status_t status; + + IBSP_ENTER( IBSP_DBG_HW ); + + hca = HeapAlloc( g_ibsp.heap, HEAP_ZERO_MEMORY, sizeof(struct ibsp_hca) ); + if( hca == NULL ) + { + IBSP_ERROR( ("can't get enough memory (%d)\n", sizeof(struct ibsp_hca)) ); + status = IB_INSUFFICIENT_MEMORY; + goto pnp_ca_add_err1; + } + + hca->guid = p_ca_rec->p_ca_attr->ca_guid; + hca->dev_id = p_ca_rec->p_ca_attr->dev_id; + cl_qlist_init( &hca->port_list ); + cl_spinlock_init( &hca->port_lock ); + cl_qlist_init( &hca->rdma_mem_list.list ); + cl_spinlock_init( &hca->rdma_mem_list.mutex ); + cl_spinlock_init( &hca->cq_lock ); + + /* HCA handle */ + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_HW, + ("handle is %p %016I64x\n", g_ibsp.al_handle, hca->guid) ); + status = + ib_open_ca( g_ibsp.al_handle, hca->guid, NULL, hca, &hca->hca_handle ); + + if( status != IB_SUCCESS ) + { + IBSP_ERROR( ("ib_open_ca failed (%d)\n", status) ); + goto pnp_ca_add_err2; + } + + STAT_INC( ca_num ); + + /* Protection domain for the HCA */ + status = ib_alloc_pd( hca->hca_handle, IB_PDT_NORMAL, hca, &hca->pd ); + if( status == IB_SUCCESS ) + { + STAT_INC( pd_num ); + + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_EP, ("allocated PD %p for HCA\n", hca->pd) ); + + /* Success */ + cl_spinlock_acquire( &g_ibsp.hca_mutex ); + cl_qlist_insert_tail( &g_ibsp.hca_list, &hca->item ); + cl_spinlock_release( &g_ibsp.hca_mutex ); + + p_ca_rec->pnp_rec.context = hca; + } + else + { + IBSP_ERROR( ("ib_alloc_pd failed (%d)\n", status) ); + if( ib_close_ca( hca->hca_handle, NULL ) == IB_SUCCESS ) + STAT_DEC( ca_num ); + +pnp_ca_add_err2: + HeapFree( g_ibsp.heap, 0, hca ); + + } +pnp_ca_add_err1: + + IBSP_EXIT( IBSP_DBG_HW ); + return status; +} + + +/* Remove an adapter and its ports. */ +void +pnp_ca_remove( + struct ibsp_hca *hca ) +{ + ib_api_status_t status; + cl_list_item_t *p_item; + struct cq_thread_info *p_cq_tinfo; + + IBSP_ENTER( IBSP_DBG_HW ); + + /* + * Remove all the ports + */ + cl_spinlock_acquire( &hca->port_lock ); + while( cl_qlist_count( &hca->port_list ) ) + { + p_item = cl_qlist_remove_head( &hca->port_list ); + + HeapFree( g_ibsp.heap, 0, + PARENT_STRUCT(p_item, struct ibsp_port, item) ); + } + cl_spinlock_release( &hca->port_lock ); + + cl_spinlock_acquire( &hca->cq_lock ); + while( hca->cq_tinfo ) + { + p_cq_tinfo = hca->cq_tinfo; + + hca->cq_tinfo = PARENT_STRUCT( + cl_qlist_next( &hca->cq_tinfo->list_item ), + struct cq_thread_info, list_item ); + + __cl_primitive_remove( &p_cq_tinfo->list_item ); + + if( hca->cq_tinfo == p_cq_tinfo ) + break; + + cl_spinlock_release( &hca->cq_lock ); + ib_destroy_cq_tinfo( p_cq_tinfo ); + cl_spinlock_acquire( &hca->cq_lock ); + } + cl_spinlock_release( &hca->cq_lock ); + + if( hca->pd ) + { + ibsp_dereg_hca( &hca->rdma_mem_list ); + + /* + * No need to wait for PD destruction - CA destruction will block + * until all child resources are released. + */ + status = ib_dealloc_pd( hca->pd, NULL ); + if( status ) + { + IBSP_ERROR( ("ib_dealloc_pd failed (%d)\n", status) ); + } + else + { + STAT_DEC( pd_num ); + } + hca->pd = NULL; + } + + if( hca->hca_handle ) + { + status = ib_close_ca( hca->hca_handle, ib_sync_destroy ); + if( status != IB_SUCCESS ) + IBSP_ERROR( ("ib_close_ca failed (%d)\n", status) ); + + hca->hca_handle = NULL; + } + + /* Remove the HCA from the HCA list and free it. */ + cl_spinlock_acquire( &g_ibsp.hca_mutex ); + cl_qlist_remove_item( &g_ibsp.hca_list, &hca->item ); + cl_spinlock_release( &g_ibsp.hca_mutex ); + + cl_spinlock_destroy( &hca->port_lock ); + cl_spinlock_destroy( &hca->rdma_mem_list.mutex ); + + cl_spinlock_destroy( &hca->cq_lock ); + + HeapFree( g_ibsp.heap, 0, hca ); + + IBSP_EXIT( IBSP_DBG_HW ); +} + + +/* Add a new port to an adapter */ +static ib_api_status_t +pnp_port_add( + IN OUT ib_pnp_port_rec_t* const p_port_rec ) +{ + struct ibsp_hca *hca; + struct ibsp_port *port; + + IBSP_ENTER( IBSP_DBG_HW ); + + hca = lookup_hca( p_port_rec->p_ca_attr->ca_guid ); + if( !hca ) + { + IBSP_ERROR( ("Failed to lookup HCA (%016I64x) for new port (%016I64x)\n", + p_port_rec->p_ca_attr->ca_guid, p_port_rec->p_port_attr->port_guid) ); + IBSP_EXIT( IBSP_DBG_HW ); + return IB_INVALID_GUID; + } + + port = HeapAlloc( g_ibsp.heap, HEAP_ZERO_MEMORY, sizeof(struct ibsp_port) ); + if( port == NULL ) + { + IBSP_ERROR( ("HeapAlloc failed (%d)\n", sizeof(struct ibsp_port)) ); + IBSP_EXIT( IBSP_DBG_HW ); + return IB_INSUFFICIENT_MEMORY; + } + + port->guid = p_port_rec->p_port_attr->port_guid; + port->port_num = p_port_rec->p_port_attr->port_num; + port->hca = hca; + + cl_spinlock_acquire( &hca->port_lock ); + cl_qlist_insert_tail( &hca->port_list, &port->item ); + cl_spinlock_release( &hca->port_lock ); + p_port_rec->pnp_rec.context = port; + + IBSP_EXIT( IBSP_DBG_HW ); + return IB_SUCCESS; +} + + +/* Remove a port. The IP addresses should have already been removed. */ +static void +pnp_port_remove( + IN struct ibsp_port* const port ) +{ + IBSP_ENTER( IBSP_DBG_HW ); + + if( !port ) + goto done; + + CL_ASSERT( port->hca ); + + /* Remove the port from the HCA list */ + cl_spinlock_acquire( &port->hca->port_lock ); + cl_qlist_remove_item( &port->hca->port_list, &port->item ); + cl_spinlock_release( &port->hca->port_lock ); + + HeapFree( g_ibsp.heap, 0, port ); + +done: + IBSP_EXIT( IBSP_DBG_HW ); +} + + +static ib_api_status_t AL_API +pnp_callback( + IN ib_pnp_rec_t *pnp_rec ) +{ + ib_api_status_t status = IB_SUCCESS; + ib_pnp_port_rec_t* p_port_rec = (ib_pnp_port_rec_t*)pnp_rec; + + IBSP_ENTER( IBSP_DBG_HW ); + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_HW, ("event is %x\n", pnp_rec->pnp_event) ); + + switch( pnp_rec->pnp_event ) + { + /* CA events */ + case IB_PNP_CA_ADD: + status = pnp_ca_add( (ib_pnp_ca_rec_t*)pnp_rec ); + break; + + case IB_PNP_CA_REMOVE: + pnp_ca_remove( (struct ibsp_hca*)pnp_rec->context ); + break; + + /* Port events */ + case IB_PNP_PORT_ADD: + status = pnp_port_add( p_port_rec ); + break; + + case IB_PNP_PORT_INIT: + case IB_PNP_PORT_ARMED: + case IB_PNP_PORT_ACTIVE: + case IB_PNP_PORT_DOWN: + /* Nothing to do. */ + break; + + case IB_PNP_PORT_REMOVE: + pnp_port_remove( (struct ibsp_port*)pnp_rec->context ); + break; + + case IB_PNP_PKEY_CHANGE: + case IB_PNP_SM_CHANGE: + case IB_PNP_GID_CHANGE: + case IB_PNP_LID_CHANGE: + case IB_PNP_SUBNET_TIMEOUT_CHANGE: + IBSP_ERROR( ("pnp_callback: unsupported event %x\n", pnp_rec->pnp_event) ); + break; + + /* Discovery complete event */ + case IB_PNP_REG_COMPLETE: + break; + + default: + IBSP_ERROR( ("pnp_callback: unsupported event %x\n", pnp_rec->pnp_event) ); + break; + } + + IBSP_EXIT( IBSP_DBG_HW ); + + return status; +} + + + + +/* Registers for PNP events and starts the hardware discovery */ +ib_api_status_t +register_pnp(void) +{ + ib_api_status_t status; + ib_pnp_req_t pnp_req; + + IBSP_ENTER( IBSP_DBG_HW ); + + pnp_req.pnp_class = IB_PNP_CA; + pnp_req.pnp_context = NULL; + pnp_req.pfn_pnp_cb = pnp_callback; + status = ib_reg_pnp( g_ibsp.al_handle, &pnp_req, &g_ibsp.pnp_handle_port ); + if( status != IB_SUCCESS ) + { + IBSP_ERROR( ("register_pnp: ib_reg_pnp for PORT failed (%d)\n", status) ); + goto done; + } + + pnp_req.pnp_class = IB_PNP_PORT | IB_PNP_FLAG_REG_SYNC; + pnp_req.pnp_context = NULL; + pnp_req.pfn_pnp_cb = pnp_callback; + status = ib_reg_pnp( g_ibsp.al_handle, &pnp_req, &g_ibsp.pnp_handle_port ); + if( status != IB_SUCCESS ) + { + IBSP_ERROR( ("register_pnp: ib_reg_pnp for PORT failed (%d)\n", status) ); + goto done; + } + + STAT_INC( pnp_num ); + +done: + if( status != IB_SUCCESS ) + { + unregister_pnp(); + } + + IBSP_EXIT( IBSP_DBG_HW ); + + return status; +} + + +/* Unregisters the PNP events */ +void +unregister_pnp(void) +{ + ib_api_status_t status; + + IBSP_ENTER( IBSP_DBG_HW ); + + if( g_ibsp.pnp_handle_port ) + { + status = ib_dereg_pnp( g_ibsp.pnp_handle_port, ib_sync_destroy ); + if( status != IB_SUCCESS ) + { + IBSP_ERROR( ("unregister_pnp: ib_dereg_pnp for PORT failed (%d)\n", + status) ); + } + + g_ibsp.pnp_handle_port = NULL; + } + + if( g_ibsp.pnp_handle_ca ) + { + status = ib_dereg_pnp( g_ibsp.pnp_handle_ca, ib_sync_destroy ); + if( status != IB_SUCCESS ) + { + IBSP_ERROR( ("unregister_pnp: ib_dereg_pnp for PORT failed (%d)\n", + status) ); + } + + g_ibsp.pnp_handle_ca = NULL; + } + + IBSP_EXIT( IBSP_DBG_HW ); +} diff --git a/branches/WOF2-3/ulp/wsd/user/ibspdebug.c b/branches/WOF2-3/ulp/wsd/user/ibspdebug.c new file mode 100644 index 00000000..c67a84d3 --- /dev/null +++ b/branches/WOF2-3/ulp/wsd/user/ibspdebug.c @@ -0,0 +1,291 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2006 Mellanox Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include "ibspdll.h" + +#ifdef _DEBUG_ + + +void +DebugPrintIBSPIoctlParams( + uint32_t flags, + DWORD dwIoControlCode, + LPVOID lpvInBuffer, + DWORD cbInBuffer, + LPVOID lpvOutBuffer, + DWORD cbOutBuffer, + LPWSAOVERLAPPED lpOverlapped, + LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine, + LPWSATHREADID lpThreadId ) +{ + UNUSED_PARAM( lpThreadId ); + + IBSP_PRINT( TRACE_LEVEL_INFORMATION, flags,("\tdwIoControlCode :") ); + switch( dwIoControlCode ) + { + case SIO_GET_QOS: + IBSP_PRINT( TRACE_LEVEL_INFORMATION, flags,("SIO_GET_QOS\n") ); + break; + case SIO_GET_GROUP_QOS: + IBSP_PRINT( TRACE_LEVEL_INFORMATION, flags,("SIO_GET_GROUP_QOS\n") ); + break; + case SIO_SET_QOS: + IBSP_PRINT( TRACE_LEVEL_INFORMATION, flags,("SIO_SET_QOS\n") ); + break; + case SIO_SET_GROUP_QOS: + IBSP_PRINT( TRACE_LEVEL_INFORMATION, flags,("SIO_SET_GROUP_QOS\n") ); + break; + case SIO_ADDRESS_LIST_QUERY: + IBSP_PRINT( TRACE_LEVEL_INFORMATION, flags,("SIO_ADDRESS_LIST_QUERY\n") ); + break; + default: + IBSP_PRINT( TRACE_LEVEL_INFORMATION, flags,("UNKNOWN control code 0x%x)\n", dwIoControlCode) ); + break; + } + + if( lpvInBuffer == NULL ) + { + IBSP_PRINT( TRACE_LEVEL_INFORMATION, flags,("\tInput Buffer pointer is NULL\n") ); + } + else + { + IBSP_PRINT( TRACE_LEVEL_INFORMATION, flags,("\tInput buffer len (%d)\n", cbInBuffer) ); + } + if( lpvOutBuffer == NULL ) + { + IBSP_PRINT( TRACE_LEVEL_INFORMATION, flags,("\tOutput Buffer pointer is NULL\n") ); + } + else + { + IBSP_PRINT( TRACE_LEVEL_INFORMATION, flags,("\tOutput buffer len (%d)\n", cbOutBuffer) ); + } + IBSP_PRINT( TRACE_LEVEL_INFORMATION, flags, + ("\tOverlapped IO is (%s)\n", ( lpOverlapped == NULL) ? "FALSE" : "TRUE") ); + IBSP_PRINT( TRACE_LEVEL_INFORMATION, flags, + ("\tCompletion Routine is %s\n", + ( lpCompletionRoutine == NULL) ? "NULL" : "non NULL") ); +} + + +void +DebugPrintSockAddr( + uint32_t flags, + struct sockaddr_in *pSockAddr ) +{ + + IBSP_PRINT( TRACE_LEVEL_INFORMATION, flags,("\tAddressFamily (0x%x)\n", pSockAddr->sin_family) ); + IBSP_PRINT( TRACE_LEVEL_INFORMATION, flags,("\tPortNumber (0x%x)\n", pSockAddr->sin_port) ); + IBSP_PRINT( TRACE_LEVEL_INFORMATION, flags,("\tIPAddress (%s)\n", inet_ntoa(pSockAddr->sin_addr )) ); +} + + +void +debug_dump_buffer( + uint32_t flags, + const char *name, + void *buf, + size_t len ) +{ + unsigned char *p = buf; + size_t i; + char str[100]; + char *s; + + s = str; + *s = 0; + + IBSP_PRINT( TRACE_LEVEL_VERBOSE, flags,("HEX for %s:\n", name) ); + + for( i = 0; i < len; i++ ) + { + s += sprintf( s, "%02x ", p[i] ); + if( i % 16 == 15 ) + { + IBSP_PRINT( TRACE_LEVEL_VERBOSE, flags, ("HEX:%s: %s\n", name, str) ); + s = str; + *s = 0; + } + } + IBSP_PRINT( TRACE_LEVEL_VERBOSE, flags, ("HEX:%s: %s\n", name, str) ); +} + + +void +debug_dump_overlapped( + uint32_t flags, + const char *name, + LPWSAOVERLAPPED lpOverlapped ) +{ + IBSP_PRINT( TRACE_LEVEL_INFORMATION, flags, ("dumping OVERLAPPED %s:\n", name) ); + IBSP_PRINT( TRACE_LEVEL_INFORMATION, flags, (" lpOverlapped = %p\n", lpOverlapped) ); + IBSP_PRINT( TRACE_LEVEL_INFORMATION, flags, (" Internal = %x\n", lpOverlapped->Internal) ); + IBSP_PRINT( TRACE_LEVEL_INFORMATION, flags, (" InternalHigh = %d\n", lpOverlapped->InternalHigh) ); + IBSP_PRINT( TRACE_LEVEL_INFORMATION, flags, (" Offset = %d\n", lpOverlapped->Offset) ); + IBSP_PRINT( TRACE_LEVEL_INFORMATION, flags, (" OffsetHigh = %d %\n", lpOverlapped->OffsetHigh) ); + IBSP_PRINT( TRACE_LEVEL_INFORMATION, flags, (" hEvent = %x\n", (uintptr_t) lpOverlapped->hEvent) ); +} + +#endif /* _DEBUG_ */ + + +#ifdef IBSP_LOGGING + +VOID DataLogger_Init( + DataLogger *pLogger, + char *prefix, + struct sockaddr_in *addr1, + struct sockaddr_in *addr2 ) +{ + HANDLE hFile; + HANDLE hMapFile; + + char Name[100]; + DWORD DataSize = 20 * 1024 * 1024; + + sprintf(Name,"c:\\%s_%d.%d.%d.%d_%d_%d.%d.%d.%d_%d", + prefix, + addr1->sin_addr.S_un.S_un_b.s_b1, + addr1->sin_addr.S_un.S_un_b.s_b2, + addr1->sin_addr.S_un.S_un_b.s_b3, + addr1->sin_addr.S_un.S_un_b.s_b4, + CL_NTOH16(addr1->sin_port), + addr2->sin_addr.S_un.S_un_b.s_b1, + addr2->sin_addr.S_un.S_un_b.s_b2, + addr2->sin_addr.S_un.S_un_b.s_b3, + addr2->sin_addr.S_un.S_un_b.s_b4, + CL_NTOH16(addr2->sin_port) + ); + + pLogger->NextPrint = NULL; + pLogger->BufferStart = NULL; + pLogger->ShutdownClosed = FALSE; + pLogger->ToatalPrinted = 0; + pLogger->TotalSize = DataSize; + + hFile = CreateFile( Name, GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, + FILE_ATTRIBUTE_NORMAL, NULL ); + + if (hFile == INVALID_HANDLE_VALUE) + { + IBSP_ERROR( ("CreateFile failed with error %d\n", GetLastError()) ); + return; + } + + hMapFile = CreateFileMapping(hFile, // current file handle + NULL, // default security + PAGE_READWRITE, // read/write permission + 0, // max. object size + DataSize, // size of hFile + NULL); // name of mapping object + + CloseHandle( hFile ); + + if (hMapFile == NULL) + { + IBSP_ERROR( ("Could not create file mapping object.\n") ); + return; + } + + pLogger->BufferStart = MapViewOfFile(hMapFile, // handle to mapping object + FILE_MAP_ALL_ACCESS, // read/write permission + 0, // max. object size + 0, // size of hFile + 0); // map entire file + + CloseHandle( hMapFile ); + + if( pLogger->BufferStart == NULL ) + { + IBSP_ERROR( ("Could not MapViewOfFile.\n") ); + return; + } + + pLogger->NextPrint = pLogger->BufferStart; + cl_memclr(pLogger->NextPrint, DataSize); +} + + +VOID DataLogger_WriteData( + DataLogger *pLogger, + long Idx, + char *Data, + DWORD Len ) +{ + char MessageHeader[16]; + CL_ASSERT(Len < 64000); + CL_ASSERT(pLogger->ShutdownClosed == FALSE); + CL_ASSERT(Len < pLogger->TotalSize / 3); + + if( !pLogger->BufferStart ) + return; + + cl_memset( MessageHeader, 0xff, sizeof(MessageHeader) ); + cl_memcpy( MessageHeader+4, &Idx, sizeof(Idx) ); + cl_memcpy( MessageHeader+8, &Len, sizeof(Len) ); + + pLogger->ToatalPrinted += Len; + + if( pLogger->NextPrint + Len + (2 * sizeof (MessageHeader)) > + pLogger->BufferStart + pLogger->TotalSize ) + { + /* We will now zero the remaing of the buffer, and restart */ + cl_memclr( pLogger->NextPrint, + pLogger->TotalSize - (pLogger->NextPrint - pLogger->BufferStart) ); + pLogger->NextPrint = pLogger->BufferStart; + } + + /* Just simple copy */ + cl_memcpy( pLogger->NextPrint, MessageHeader, sizeof(MessageHeader) ); + pLogger->NextPrint += sizeof(MessageHeader); + + cl_memcpy( pLogger->NextPrint, Data, Len ); + pLogger->NextPrint += Len; + + /* + * Add the end marker but don't update NextPrint so the next message + * overwrites the previous message's end marker. + */ + cl_memset( pLogger->NextPrint, 0xff, sizeof(MessageHeader) ); +} + + +VOID DataLogger_Shutdown( + DataLogger *pLogger ) +{ + if( !pLogger->BufferStart ) + return; + + UnmapViewOfFile( pLogger->BufferStart ); +} + +#endif /* IBSP_LOGGING */ diff --git a/branches/WOF2-3/ulp/wsd/user/ibspdebug.h b/branches/WOF2-3/ulp/wsd/user/ibspdebug.h new file mode 100644 index 00000000..b250c93c --- /dev/null +++ b/branches/WOF2-3/ulp/wsd/user/ibspdebug.h @@ -0,0 +1,268 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2006 Mellanox Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#ifndef _IBSP_DEBUG_H_ +#define _IBSP_DEBUG_H_ + + +#include "ibspdll.h" +#include +#include + +#ifndef __MODULE__ +#define __MODULE__ "[IBSP]" +#endif + + + + +extern uint32_t g_ibsp_dbg_level; +extern uint32_t g_ibsp_dbg_flags; + +#if defined(EVENT_TRACING) +// +// Software Tracing Definitions +// + + +#define WPP_CONTROL_GUIDS \ + WPP_DEFINE_CONTROL_GUID(IBSPCtlGuid,(156A98A5,8FDC,4d00,A673,0638123DF336), \ + WPP_DEFINE_BIT( IBSP_DBG_ERROR) \ + WPP_DEFINE_BIT( IBSP_DBG_DLL) \ + WPP_DEFINE_BIT( IBSP_DBG_SI) \ + WPP_DEFINE_BIT( IBSP_DBG_INIT) \ + WPP_DEFINE_BIT( IBSP_DBG_WQ) \ + WPP_DEFINE_BIT( IBSP_DBG_EP) \ + WPP_DEFINE_BIT( IBSP_DBG_MEM) \ + WPP_DEFINE_BIT( IBSP_DBG_CM) \ + WPP_DEFINE_BIT( IBSP_DBG_CONN) \ + WPP_DEFINE_BIT( IBSP_DBG_OPT) \ + WPP_DEFINE_BIT( IBSP_DBG_NEV) \ + WPP_DEFINE_BIT( IBSP_DBG_HW) \ + WPP_DEFINE_BIT( IBSP_DBG_IO) \ + WPP_DEFINE_BIT( IBSP_DBG_DUP) \ + WPP_DEFINE_BIT( IBSP_DBG_PERFMON) \ + WPP_DEFINE_BIT( IBSP_DBG_APM)) + + +#define WPP_LEVEL_FLAGS_ENABLED(lvl, flags) (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= lvl) +#define WPP_LEVEL_FLAGS_LOGGER(lvl,flags) WPP_LEVEL_LOGGER(flags) +#define WPP_FLAG_ENABLED(flags)(WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= TRACE_LEVEL_VERBOSE) +#define WPP_FLAG_LOGGER(flags) WPP_LEVEL_LOGGER(flags) + + +// begin_wpp config +// IBSP_ENTER( FLAG ); +// IBSP_EXIT( FLAG ); +// USEPREFIX(IBSP_PRINT, "%!STDPREFIX! %!FUNC!() :"); +// USEPREFIX(IBSP_PRINT_EXIT, "%!STDPREFIX! %!FUNC!() :"); +// USEPREFIX(IBSP_ERROR, "%!STDPREFIX! %!FUNC!() :ERR***"); +// USEPREFIX(IBSP_ERROR_EXIT, "%!STDPREFIX! %!FUNC!() :ERR***"); +// USESUFFIX(IBSP_ENTER, " %!FUNC!():["); +// USESUFFIX(IBSP_EXIT, " %!FUNC!():]"); +// end_wpp + + + +#define STAT_INC(name) +#define STAT_DEC(name) +#define BREAKPOINT(x) +#define DebugPrintIBSPIoctlParams(a,b,c,d,e,f,g,h,i) +#define DebugPrintSockAddr(a,b) +#define fzprint(a) +#define STATS(expr) + +#else + +#include +#include + +/* + * Debug macros + */ + + + +#define IBSP_DBG_ERR 0x00000001 /* error */ +#define IBSP_DBG_DLL 0x00000002 /* DLL */ +#define IBSP_DBG_SI 0x00000004 /* socket info */ +#define IBSP_DBG_INIT 0x00000008 /* initialization code */ +#define IBSP_DBG_WQ 0x00000010 /* WQ related functions */ +#define IBSP_DBG_EP 0x00000020 /* Enpoints related functions */ +#define IBSP_DBG_MEM 0x00000040 /* memory registration */ +#define IBSP_DBG_CM 0x00000080 /* CM */ +#define IBSP_DBG_CONN 0x00000100 /* connections */ +#define IBSP_DBG_OPT 0x00000200 /* socket options */ +#define IBSP_DBG_NEV 0x00000400 /* network events */ +#define IBSP_DBG_HW 0x00000800 /* Hardware */ +#define IBSP_DBG_IO 0x00001000 /* Overlapped I/O request */ +#define IBSP_DBG_DUP 0x00002000 /* Socket Duplication */ +#define IBSP_DBG_PERFMON 0x00004000 /* Performance Monitoring */ +#define IBSP_DBG_APM 0x00008000 /* APM handeling */ + +#define IBSP_DBG_ERROR (CL_DBG_ERROR | IBSP_DBG_ERR) + + + +#if DBG + +// assignment of _level_ is need to to overcome warning C4127 +#define IBSP_PRINT( _level_,_flag_,_msg_) \ + { \ + if( g_ibsp_dbg_level >= (_level_) ) \ + CL_TRACE( _flag_, g_ibsp_dbg_flags, _msg_ ); \ + } + + +#define IBSP_PRINT_EXIT( _level_,_flag_,_msg_) \ + { \ + if( g_ibsp_dbg_level >= (_level_) ) \ + CL_TRACE( _flag_, g_ibsp_dbg_flags, _msg_ );\ + IBSP_EXIT( _flag_ );\ + } + +#define IBSP_ENTER( _flag_) \ + { \ + if( g_ibsp_dbg_level >= TRACE_LEVEL_VERBOSE ) \ + CL_ENTER( _flag_, g_ibsp_dbg_flags ); \ + } + +#define IBSP_EXIT( _flag_)\ + { \ + if( g_ibsp_dbg_level >= TRACE_LEVEL_VERBOSE ) \ + CL_EXIT( _flag_, g_ibsp_dbg_flags ); \ + } + + +//#define fzprint(a) CL_PRINT(IBSP_DBG_USER, IBSP_DBG_USER, a) +#define fzprint(a) + +//#define BREAKPOINT(x) if( gCurrentDebugLevel & x ) { DebugBreak(); } +void +DebugPrintIBSPIoctlParams( + uint32_t flags, + DWORD dwIoControlCode, + LPVOID lpvInBuffer, + DWORD cbInBuffer, + LPVOID lpvOutBuffer, + DWORD cbOutBuffer, + LPWSAOVERLAPPED lpOverlapped, + LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine, + LPWSATHREADID lpThreadId ); + + +void +DebugPrintSockAddr( + uint32_t flags, + struct sockaddr_in *sockaddr ); + +void +debug_dump_buffer( + uint32_t flags, + const char *name, + void *buf, + size_t len ); + +void +debug_dump_overlapped( + uint32_t flags, + const char *name, + LPWSAOVERLAPPED lpOverlapped ); + +/* Activate memory tracking debugging */ +#define HeapAlloc(a,b,c) cl_zalloc(c) +#define HeapFree(a,b,c) (cl_free(c), TRUE) +#define HeapCreate(a,b,c) ((HANDLE)(-1)) +#define HeapDestroy(a) + +#define STAT_INC(name) cl_atomic_inc( &g_ibsp.name ) +#define STAT_DEC(name) cl_atomic_dec( &g_ibsp.name ) + +#else + + +#define IBSP_PRINT( _level_,_flag_,_msg_) +#define IBSP_PRINT_EXIT( _level_,_flag_,_msg_) +#define IBSP_ENTER( _flag_) +#define IBSP_EXIT( _flag_) +#define fzprint(a) +#endif /* DBG */ + + +#define IBSP_ERROR( _msg_) \ + IBSP_PRINT( TRACE_LEVEL_ERROR, IBSP_DBG_ERROR, _msg_) + +#define IBSP_ERROR_EXIT( _msg_) \ + IBSP_PRINT_EXIT( TRACE_LEVEL_ERROR, IBSP_DBG_ERROR, _msg_) + + +#endif /* EVENT_TRACING */ + +/* + * To enable logging of all Send/Receive data for each socket + * uncomment the following line. + */ +//#define IBSP_LOGGING + +#ifdef IBSP_LOGGING + +typedef struct _DataLogger +{ + char *BufferStart; + size_t TotalSize; + char *NextPrint; + size_t ToatalPrinted; + BOOL ShutdownClosed; + HANDLE hMapFile; + +} DataLogger; + + +VOID DataLogger_Init( + DataLogger *pLoger, + char *prefix, + struct sockaddr_in *addr1, + struct sockaddr_in *addr2 ); + + +VOID DataLogger_WriteData( + DataLogger *pLoger, + long Idx, + char *Data, + DWORD Len ); + +VOID DataLogger_Shutdown( + DataLogger *pLoger ); + +#endif /* IBSP_LOGGING */ + +#endif /* _IBSP_DEBUG_H_ */ diff --git a/branches/WOF2-3/ulp/wsd/user/ibspdefines.h b/branches/WOF2-3/ulp/wsd/user/ibspdefines.h new file mode 100644 index 00000000..3af02c3e --- /dev/null +++ b/branches/WOF2-3/ulp/wsd/user/ibspdefines.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +/* Message sizes. */ +/* TODO: these sizes are arbitrary */ +#define IB_MAX_MSG_SIZE 0xFFFFFFFF //(32*1024*1024) +#define IB_MAX_RDMA_SIZE 0xFFFFFFFF //(16*1024*1024) +#define IB_RDMA_THRESHOLD_SIZE (4*1024) +/* TODO: Change back */ +//#define IB_RDMA_THRESHOLD_SIZE (16*1024) + +/* Number of work completion to poll at a time */ +#define WC_LIST_SIZE 8 + +/* QP creation parameters */ +#define QP_ATTRIB_RESPONDER_RESOURCES 4 +#define QP_ATTRIB_INITIATOR_DEPTH 4 +#define QP_ATTRIB_RETRY_COUNT 6 +#define QP_ATTRIB_RNR_RETRY 7 +#define QP_ATTRIB_RNR_NAK_TIMEOUT 8 /* 16 ms */ + +#define QP_ATTRIB_SQ_DEPTH 16 + +/* + * Only the RDMA calls can have more than one SGE - the send and receive always + * have just one. For send and receives, the switch always uses its internal + * buffers. For RDMAs the switch will issue requests with at most 4 SGEs. + * We support twice that for good measure. + */ +#define QP_ATTRIB_SQ_SGE 8 + +/* Our indexes are single-byte, so make sure we don't screw up. */ +C_ASSERT( QP_ATTRIB_SQ_DEPTH <= 256 ); + +/* + * TODO: During testing, the switch has been observed to post + * 12 receive buffers. It would be nice to know what the max is. + */ +#define QP_ATTRIB_RQ_DEPTH 16 +#define QP_ATTRIB_RQ_SGE 1 + +/* Our indexes are single-byte, so make sure we don't screw up. */ +C_ASSERT( QP_ATTRIB_RQ_DEPTH <= 256 ); + +/* Number of entries in a CQ */ +/* + * TODO: Workaround until MTHCA driver supports resize CQ, pre-allocate + * for 100 QPs per CQ. + */ +#define IB_CQ_SIZE (QP_ATTRIB_SQ_DEPTH + QP_ATTRIB_RQ_DEPTH) +#define IB_INIT_CQ_SIZE (IB_CQ_SIZE * 500) + +/* CM timeouts */ +#define CM_MIN_LOCAL_TIMEOUT (18) +#define CM_LOCAL_TIMEOUT (1) +#define CM_MIN_REMOTE_TIMEOUT (18) +#define CM_REMOTE_TIMEOUT (2) +#define CM_RETRIES 4 + +/* Base service ID for listen */ +#define BASE_LISTEN_ID (CL_CONST64(0xb6e36efb8eda0000)) diff --git a/branches/WOF2-3/ulp/wsd/user/ibspdll.c b/branches/WOF2-3/ulp/wsd/user/ibspdll.c new file mode 100644 index 00000000..ba69201f --- /dev/null +++ b/branches/WOF2-3/ulp/wsd/user/ibspdll.c @@ -0,0 +1,2594 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2006 Mellanox Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include "ibspdebug.h" +#if defined(EVENT_TRACING) +#include "ibspdll.tmh" +#endif + + +#include +#include +#include "ibspdll.h" + +#ifdef PERFMON_ENABLED +#include "ibsp_perfmon.h" +#endif /* PERFMON_ENABLED */ + +/* Globals */ +struct ibspdll_globals g_ibsp; + +/* Defines */ +static const WCHAR *Description = L"Winsock Service Provider for Infiniband Transport"; + +/* Unique provider GUID generated with "uuidgen -s". Same as in installsp.c. */ +static const GUID provider_guid = { + /* c943654d-2c84-4db7-af3e-fdf1c5322458 */ + 0xc943654d, 0x2c84, 0x4db7, + {0xaf, 0x3e, 0xfd, 0xf1, 0xc5, 0x32, 0x24, 0x58} +}; + +static DWORD no_read = 0; +uint32_t g_max_inline = 0xFFFFFFFF; +uint32_t g_max_poll = 500; +uint32_t g_sa_timeout = 500; +uint32_t g_sa_retries = 4; +int g_connect_err = WSAEADDRNOTAVAIL; +uint8_t g_max_cm_retries = CM_RETRIES; +int8_t g_pkt_life_modifier = 0; +uint8_t g_qp_retries = QP_ATTRIB_RETRY_COUNT; +uint8_t g_use_APM = 0; +DWORD_PTR g_dwPollThreadAffinityMask = 0; + +uint32_t g_ibsp_dbg_level = TRACE_LEVEL_ERROR; +uint32_t g_ibsp_dbg_flags = 0x1; + +BOOL InitApmLib(); +VOID ShutDownApmLib(); + +/* + * Function: DllMain + * + * Description: + * Provides initialization when the ibspdll DLL is loaded. + */ +#pragma auto_inline( off ) +static BOOL +_DllMain( + IN HINSTANCE hinstDll, + IN DWORD dwReason, + IN LPVOID lpvReserved ) +{ + TCHAR env_var[16]; + DWORD i; + + IBSP_ENTER( IBSP_DBG_DLL ); + + UNUSED_PARAM( hinstDll ); + UNUSED_PARAM( lpvReserved ); + + fzprint(("%s():%d:0x%x:0x%x: hinstDll=%d dwReason=%d lpvReserved=0x%p\n", + __FUNCTION__, + __LINE__, GetCurrentProcessId(), + GetCurrentThreadId(), hinstDll, dwReason, lpvReserved)); + +//#ifdef _DEBUG_ +#if 0 + { + char buf[64]; + if( GetEnvironmentVariable( "IBSPLOAD", buf, sizeof(buf) ) == 0 ) + { + IBSP_ERROR_EXIT( ("IBSPLOAD not defined:\n") ); + + return FALSE; + } + } +#endif + + switch( dwReason ) + { + case DLL_PROCESS_ATTACH: + + +#if defined(EVENT_TRACING) +#if DBG + WPP_INIT_TRACING(L"ibspdll.dll"); +#else + WPP_INIT_TRACING(L"ibspdll.dll"); +#endif +#endif + + + + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_DLL, ("DllMain: DLL_PROCESS_ATTACH\n") ); + + +#if !defined(EVENT_TRACING) +#if DBG + + i = GetEnvironmentVariable( "IBWSD_DBG_LEVEL", env_var, sizeof(env_var) ); + if( i && i <= 16 ) + { + g_ibsp_dbg_level = _tcstoul( env_var, NULL, 16 ); + } + + i = GetEnvironmentVariable( "IBWSD_DBG_FLAGS", env_var, sizeof(env_var) ); + if( i && i <= 16 ) + { + g_ibsp_dbg_flags = _tcstoul( env_var, NULL, 16 ); + } + + if( g_ibsp_dbg_flags & IBSP_DBG_ERR ) + g_ibsp_dbg_flags |= CL_DBG_ERROR; + + IBSP_PRINT(TRACE_LEVEL_INFORMATION ,IBSP_DBG_DLL , + ("Given IBAL_UAL_DBG debug level:%d debug flags 0x%x\n", + g_ibsp_dbg_level ,g_ibsp_dbg_flags) ); + +#endif +#endif + + + /* See if the user wants to disable RDMA reads. */ + no_read = GetEnvironmentVariable( "IBWSD_NO_READ", NULL, 0 ); + + i = GetEnvironmentVariable( "IBWSD_INLINE", env_var, sizeof(env_var) ); + if( i && i <= 16 ) + g_max_inline = _tcstoul( env_var, NULL, 10 ); + + i = GetEnvironmentVariable( "IBWSD_POLL", env_var, sizeof(env_var) ); + if( i && i <= 16 ) + g_max_poll = _tcstoul( env_var, NULL, 10 ); + + i = GetEnvironmentVariable( "IBWSD_POLL_THREAD_AFFINITY_MASK", env_var, sizeof(env_var) ); + if( i && i <= 16 ) + g_dwPollThreadAffinityMask = _tcstoul( env_var, NULL, 10 ); + else + { + DWORD_PTR xx; + BOOL ret = GetProcessAffinityMask(GetCurrentProcess(), &g_dwPollThreadAffinityMask, &xx); + CL_ASSERT(ret != 0); + if (ret == 0) { + IBSP_ERROR( ("GetProcessAffinityMask Failed (not a fatal error)\n") ); + } + ret = ret; + } + + i = GetEnvironmentVariable( "IBWSD_SA_RETRY", env_var, sizeof(env_var) ); + if( i && i <= 16 ) + g_sa_retries = _tcstoul( env_var, NULL, 10 ); + + i = GetEnvironmentVariable( "IBWSD_SA_TIMEOUT", env_var, sizeof(env_var) ); + if( i && i <= 16 ) + g_sa_timeout = _tcstoul( env_var, NULL, 10 ); + + i = GetEnvironmentVariable( "IBWSD_NO_IPOIB", env_var, sizeof(env_var) ); + if( i ) + g_connect_err = WSAEHOSTUNREACH; + + i = GetEnvironmentVariable( "IBWSD_CM_RETRY", env_var, sizeof(env_var) ); + if( i && i <= 16 ) + { + g_max_cm_retries = (uint8_t)_tcstoul( env_var, NULL, 0 ); + if( g_max_cm_retries < 4 ) + g_max_cm_retries = 4; + else if( g_max_cm_retries > 0xF ) + g_max_cm_retries = 0xFF; + } + + i = GetEnvironmentVariable( "IBWSD_PKT_LIFE", env_var, sizeof(env_var) ); + if( i && i <= 16 ) + { + g_pkt_life_modifier = (int8_t)_tcstoul( env_var, NULL, 0 ); + if( g_pkt_life_modifier > 0x1F ) + g_pkt_life_modifier = 0x1F; + } + + i = GetEnvironmentVariable( "IBWSD_QP_RETRY", env_var, sizeof(env_var) ); + if( i && i <= 16 ) + { + g_qp_retries = (uint8_t)_tcstoul( env_var, NULL, 0 ); + if( g_qp_retries > 7 ) + g_qp_retries = 7; + } + + i = GetEnvironmentVariable( "IBWSD_USE_APM", env_var, sizeof(env_var) ); + if( i && i <= 16 ) + { + g_use_APM = (uint8_t)_tcstoul( env_var, NULL, 0 ); + } + + if( init_globals() ) + return FALSE; + + if (g_use_APM) + { + InitApmLib(); + // We continue weather it succeeded or not + } +#ifdef PERFMON_ENABLED + IBSPPmInit(); +#endif + break; + + case DLL_THREAD_ATTACH: + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_DLL, ("DllMain: DLL_THREAD_ATTACH\n") ); + break; + + case DLL_THREAD_DETACH: + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_DLL, ("DllMain: DLL_THREAD_DETACH\n") ); + break; + + case DLL_PROCESS_DETACH: + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_DLL, ("DllMain: DLL_PROCESS_DETACH\n") ); + +#ifdef _DEBUG_ + { + cl_list_item_t *socket_item = NULL; + + cl_spinlock_acquire( &g_ibsp.socket_info_mutex ); + + for( socket_item = cl_qlist_head( &g_ibsp.socket_info_list ); + socket_item != cl_qlist_end( &g_ibsp.socket_info_list ); + socket_item = cl_qlist_next( socket_item ) ) + { + struct ibsp_socket_info *socket_info = NULL; + socket_info = PARENT_STRUCT(socket_item, struct ibsp_socket_info, item); + +#ifdef IBSP_LOGGING + DataLogger_Shutdown(&socket_info->SendDataLogger); + DataLogger_Shutdown(&socket_info->RecvDataLogger); +#endif + } + + cl_spinlock_release( &g_ibsp.socket_info_mutex ); + + IBSP_ERROR( ("Statistics:\n") ); + IBSP_ERROR( ( + " overlap_h0_count = %d\n", g_ibsp.overlap_h0_count) ); + IBSP_ERROR( ( + " max_comp_count = %d\n", g_ibsp.max_comp_count) ); + IBSP_ERROR( ( + " overlap_h1_count = %d\n", g_ibsp.overlap_h1_count) ); + + IBSP_ERROR( (" send_count = %d\n", g_ibsp.send_count) ); + + IBSP_ERROR( (" total_send_count = %d\n", g_ibsp.total_send_count) ); + + IBSP_ERROR( (" total_recv_count = %d\n", g_ibsp.total_recv_count) ); + + IBSP_ERROR( (" total_recv_compleated = %d\n", g_ibsp.total_recv_compleated) ); + + IBSP_ERROR( ( + " number of QPs left = %d\n", g_ibsp.qp_num) ); + IBSP_ERROR( ( + " number of CQs left = %d\n", g_ibsp.cq_num) ); + IBSP_ERROR( ( + " number of PDs left = %d\n", g_ibsp.pd_num) ); + IBSP_ERROR( ( + " number of ALs left = %d\n", g_ibsp.al_num) ); + IBSP_ERROR( ( + " number of MRs left = %d\n", g_ibsp.mr_num) ); + IBSP_ERROR( ( + " number of listens left = %d\n", g_ibsp.listen_num) ); + IBSP_ERROR( ( + " number of PNPs left = %d\n", g_ibsp.pnp_num) ); + IBSP_ERROR( ( + " number of threads left = %d\n", g_ibsp.thread_num) ); + IBSP_ERROR( ( + " number of WPU sockets left = %d\n", g_ibsp.wpusocket_num) ); + + IBSP_ERROR( ( + " CloseSocket_count = %d\n", g_ibsp.CloseSocket_count) ); + + } +#endif + release_globals(); +#ifdef PERFMON_ENABLED + IBSPPmClose(); +#endif + + +#if defined(EVENT_TRACING) + WPP_CLEANUP(); +#endif + break; + } + + IBSP_EXIT( IBSP_DBG_DLL ); + + return TRUE; +} +#pragma auto_inline( off ) + + +extern BOOL APIENTRY +_DllMainCRTStartupForGS( + IN HINSTANCE h_module, + IN DWORD ul_reason_for_call, + IN LPVOID lp_reserved ); + + +BOOL APIENTRY +DllMain( + IN HINSTANCE h_module, + IN DWORD ul_reason_for_call, + IN LPVOID lp_reserved ) +{ + switch( ul_reason_for_call ) + { + case DLL_PROCESS_ATTACH: + if( !_DllMainCRTStartupForGS( + h_module, ul_reason_for_call, lp_reserved ) ) + { + return FALSE; + } + + return _DllMain( h_module, ul_reason_for_call, lp_reserved ); + + case DLL_PROCESS_DETACH: + _DllMain( h_module, ul_reason_for_call, lp_reserved ); + + return _DllMainCRTStartupForGS( + h_module, ul_reason_for_call, lp_reserved ); + } + return TRUE; +} + + +static SOCKET +accept_socket( + IN struct ibsp_socket_info *p_socket, + IN struct listen_incoming *p_incoming, + IN struct ibsp_port *p_port, + OUT LPINT lpErrno ) +{ + struct ibsp_socket_info *new_socket_info; + int ret; + + IBSP_ENTER( IBSP_DBG_CONN ); + + /* Create a new socket here */ + new_socket_info = create_socket_info( lpErrno ); + if( !new_socket_info ) + { + ib_reject( + p_incoming->cm_req_received.h_cm_req, IB_REJ_INSUF_RESOURCES ); + + IBSP_ERROR_EXIT( ("create_socket_info failed (%d)\n", *lpErrno) ); + return INVALID_SOCKET; + } + + /* Time to allocate our IB QP */ + new_socket_info->port = p_port; + *lpErrno = ib_create_socket( new_socket_info ); + if( *lpErrno ) + { + deref_socket_info( new_socket_info ); + + ib_reject( + p_incoming->cm_req_received.h_cm_req, IB_REJ_INSUF_QP ); + + IBSP_ERROR_EXIT( ("ib_create_socket failed (%d)\n", *lpErrno) ); + return INVALID_SOCKET; + } + + /* Store the IP address and port number in the socket context */ + new_socket_info->local_addr = p_incoming->params.dest; + + /* Copy the socket context info from parent socket context */ + new_socket_info->socket_options = p_socket->socket_options; + + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_CONN, + ("The socket address of connecting entity is\n") ); + DebugPrintSockAddr( IBSP_DBG_CONN, &p_incoming->params.source ); + + new_socket_info->peer_addr = p_incoming->params.source; + +#ifdef IBSP_LOGGING + DataLogger_Init( &new_socket_info->SendDataLogger, "Send", + &new_socket_info->peer_addr, &new_socket_info->local_addr ); + DataLogger_Init( &new_socket_info->RecvDataLogger, "Recv", + &new_socket_info->local_addr, &new_socket_info->peer_addr ); +#endif + + cl_spinlock_acquire( &new_socket_info->mutex1 ); + /* Update the state of the socket context */ + IBSP_CHANGE_SOCKET_STATE( new_socket_info, IBSP_CONNECTED ); + + *lpErrno = ib_accept( new_socket_info, &p_incoming->cm_req_received ); + if( *lpErrno ) + { + IBSP_CHANGE_SOCKET_STATE( new_socket_info, IBSP_CREATE ); + cl_spinlock_release( &new_socket_info->mutex1 ); + + if( *lpErrno == WSAEADDRINUSE ) + { + /* Be nice and reject that connection. */ + ib_reject( p_incoming->cm_req_received.h_cm_req, IB_REJ_INSUF_QP ); + } + + g_ibsp.up_call_table.lpWPUCloseSocketHandle( + new_socket_info->switch_socket, &ret ); + new_socket_info->switch_socket = INVALID_SOCKET; + STAT_DEC( wpusocket_num ); + + ib_destroy_socket( new_socket_info ); + deref_socket_info( new_socket_info ); + return INVALID_SOCKET; + } + + cl_spinlock_acquire( &g_ibsp.socket_info_mutex ); + cl_qlist_insert_tail( + &g_ibsp.socket_info_list, &new_socket_info->item ); + cl_spinlock_release( &g_ibsp.socket_info_mutex ); + + cl_spinlock_release( &new_socket_info->mutex1 ); + + IBSP_PRINT_EXIT(TRACE_LEVEL_INFORMATION, IBSP_DBG_CONN, + ("returns new socket (0x%p)\n", new_socket_info) ); + return (SOCKET)new_socket_info; +} + + +/* Function: IBSPAccept + * + * Description: + * Handle the WSAAccept function. The only special consideration here + * is the conditional accept callback. You can choose to intercept + * this by substituting your own callback (you'll need to keep track + * of the user supplied callback so you can trigger that once your + * substituted function is triggered). + */ +static SOCKET WSPAPI +IBSPAccept( + IN SOCKET s, + OUT struct sockaddr FAR *addr, + IN OUT LPINT addrlen, + IN LPCONDITIONPROC lpfnCondition, + IN DWORD_PTR dwCallbackData, + OUT LPINT lpErrno ) +{ + struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s; + WSABUF caller_id; + WSABUF callee_id; + struct listen_incoming *incoming; + struct ibsp_port *port; + ib_cm_mra_t mra; + + IBSP_ENTER( IBSP_DBG_CONN ); + + fzprint(("%s():%d:0x%x:0x%x: socket=0x%p \n", __FUNCTION__, + __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s)); + + CL_ASSERT( lpfnCondition ); + + if( *addrlen < sizeof(struct sockaddr_in) ) + { + IBSP_ERROR_EXIT( ("invalid addrlen (%d, %d)\n", + *addrlen, sizeof(struct sockaddr_in)) ); + *lpErrno = WSAEFAULT; + return INVALID_SOCKET; + } + + /* Check if there is any pending connection for this socket. If + * there is one, create a socket, and then query the switch about + * the pending connection */ + + cl_spinlock_acquire( &socket_info->mutex1 ); + + /* Verify the state of the socket */ + if( socket_info->socket_state != IBSP_LISTEN ) + { + cl_spinlock_release( &socket_info->mutex1 ); + IBSP_ERROR_EXIT( ("Socket is not in right socket_state (%s)\n", + IBSP_SOCKET_STATE_STR( socket_info->socket_state )) ); + *lpErrno = WSAEINVAL; + return INVALID_SOCKET; + } + + if( cl_qlist_count( &socket_info->listen.list ) == 0 ) + { + cl_spinlock_release( &socket_info->mutex1 ); + + IBSP_ERROR_EXIT( ("No pending connection found for this socket\n") ); + *lpErrno = WSAEWOULDBLOCK; + return INVALID_SOCKET; + } + + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_CONN, + ("IBSPAccept: Found pending connection on this socket\n") ); + + incoming = PARENT_STRUCT(cl_qlist_remove_head( &socket_info->listen.list ), + struct listen_incoming, item); + + /* Signal the event again if there are more connection requests. */ + if( cl_qlist_count( &socket_info->listen.list ) ) + ibsp_post_select_event( socket_info, FD_ACCEPT, 0 ); + cl_spinlock_release( &socket_info->mutex1 ); + + port = socket_info->port; + + /* Find the destination IP address */ + if( !port ) + { + /* The socket was bound to INADDR_ANY. We must find the correct port + * for the new socket. */ + port = get_port_from_ip_address( incoming->params.dest.sin_addr ); + if( !port ) + { + IBSP_ERROR( ("incoming destination IP address not local (%s)\n", + inet_ntoa( incoming->params.dest.sin_addr )) ); + goto reject; + } + } + + /* Cross-check with the path info to make sure we are conectiong correctly */ + if( port->guid != ib_gid_get_guid( &incoming->cm_req_received.primary_path.sgid ) ) + { + IBSP_ERROR( ( + "GUIDs of port for destination IP address and primary path do not match (%016I64x, %016I64x)\n", + port->guid, + ib_gid_get_guid( &incoming->cm_req_received.primary_path.sgid )) ); + +reject: + ib_reject( incoming->cm_req_received.h_cm_req, IB_REJ_INSUF_QP ); + + HeapFree( g_ibsp.heap, 0, incoming ); + IBSP_ERROR_EXIT( ("bad incoming parameter\n") ); + *lpErrno = WSAECONNREFUSED; + return INVALID_SOCKET; + } + + /* + * Check against the conditional routine if socket can be created + * or not + */ + + /* Set the caller and callee data buffer */ + caller_id.buf = (char *)&incoming->params.source; + caller_id.len = sizeof(incoming->params.source); + + callee_id.buf = (char *)&incoming->params.dest; + callee_id.len = sizeof(incoming->params.dest); + + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_CONN, + ("Got incoming conn from %s/%d-%d to %s/%d-%d\n", + inet_ntoa( incoming->params.source.sin_addr ), + cl_ntoh16( incoming->params.source.sin_port ), + incoming->params.source.sin_family, + inet_ntoa( incoming->params.dest.sin_addr ), + cl_ntoh16( incoming->params.dest.sin_port ), + incoming->params.dest.sin_family) ); + + /* Call the conditional function */ + switch( lpfnCondition( &caller_id, NULL, NULL, NULL, + &callee_id, NULL, NULL, dwCallbackData ) ) + { + default: + /* Should never happen */ + IBSP_ERROR( ("Conditional routine returned undocumented code\n") ); + /* Fall through. */ + + case CF_REJECT: + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_CONN, + ("Conditional routine returned CF_REJECT\n") ); + + ib_reject( incoming->cm_req_received.h_cm_req, IB_REJ_USER_DEFINED ); + + HeapFree( g_ibsp.heap, 0, incoming ); + *lpErrno = WSAECONNREFUSED; + IBSP_EXIT( IBSP_DBG_CONN ); + return INVALID_SOCKET; + + case CF_DEFER: + /* Send MRA */ + mra.mra_length = 0; + mra.p_mra_pdata = NULL; + mra.svc_timeout = 0x15; + ib_cm_mra( incoming->cm_req_received.h_cm_req, &mra ); + + /* Put the item back at the head of the list. */ + cl_spinlock_acquire( &socket_info->mutex1 ); + cl_qlist_insert_head( &socket_info->listen.list, &incoming->item ); + cl_spinlock_release( &socket_info->mutex1 ); + + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_CONN, + ("Conditional routine returned CF_DEFER\n") ); + + *lpErrno = WSATRY_AGAIN; + IBSP_EXIT( IBSP_DBG_CONN ); + return INVALID_SOCKET; + + case CF_ACCEPT: + break; + } + + s = accept_socket( socket_info, incoming, port, lpErrno ); + if( s != INVALID_SOCKET ) + { + /* Store the client socket address information */ + memcpy( addr, &incoming->params.source, sizeof(struct sockaddr_in) ); + *addrlen = sizeof(struct sockaddr_in); + } + + HeapFree( g_ibsp.heap, 0, incoming ); + + IBSP_EXIT( IBSP_DBG_CONN ); + return s; +} + + +/* Function: IBSPBind + * + * Description: + * Bind the socket to a local address. + * +*/ +static int WSPAPI +IBSPBind( + IN SOCKET s, + IN const struct sockaddr FAR *name, + IN int namelen, + OUT LPINT lpErrno ) +{ + struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s; + struct sockaddr_in *addr = (struct sockaddr_in *)name; + struct ibsp_port *port; + int ret; + + IBSP_ENTER( IBSP_DBG_CONN ); + + fzprint(("%s():%d:0x%x:0x%x: socket=0x%p \n", __FUNCTION__, + __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s)); + + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_CONN, ("Address to bind to:\n") ); + DebugPrintSockAddr( IBSP_DBG_CONN, addr ); + + fzprint(("binding to IP %s\n", inet_ntoa( addr->sin_addr ))); + + /* Sanity checks */ + if( namelen != sizeof(struct sockaddr_in) ) + { + IBSP_ERROR( ("invalid namelen (%d instead of %d)\n", + namelen, sizeof(struct sockaddr_in)) ); + *lpErrno = WSAEFAULT; + goto error; + } + + if( addr->sin_family != AF_INET ) + { + IBSP_ERROR( ("bad family for socket\n") ); + *lpErrno = WSAEFAULT; + goto error; + } + + /* Check if the ip address is assigned to one of our IBoIB HCA. */ + if( addr->sin_addr.S_un.S_addr != INADDR_ANY ) + { + port = get_port_from_ip_address( addr->sin_addr ); + if( port == NULL ) + { + IBSP_ERROR( ( + "This IP address does not belong to that host (%08x)\n", + addr->sin_addr.S_un.S_addr) ); + *lpErrno = WSAEADDRNOTAVAIL; + goto error; + } + } + else + { + port = NULL; + } + + /* We are going to take this mutex for some time, + * but at this stage, it shouldn't impact anything. */ + cl_spinlock_acquire( &socket_info->mutex1 ); + + /* Verify the state of the socket */ + if( socket_info->socket_state != IBSP_CREATE ) + { + cl_spinlock_release( &socket_info->mutex1 ); + IBSP_ERROR( ( + "Invalid socket state (%s)\n", + IBSP_SOCKET_STATE_STR( socket_info->socket_state )) ); + *lpErrno = WSAEINVAL; + goto error; + } + + if( addr->sin_addr.S_un.S_addr != INADDR_ANY ) + { + /* Time to allocate our IB QP */ + socket_info->port = port; + ret = ib_create_socket( socket_info ); + if( ret ) + { + socket_info->port = NULL; + cl_spinlock_release( &socket_info->mutex1 ); + IBSP_ERROR( ("ib_create socket failed with %d\n", ret) ); + *lpErrno = WSAENOBUFS; + goto error; + } + } + + /* Success */ + socket_info->local_addr = *addr; + + IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_BIND ); + + cl_spinlock_release( &socket_info->mutex1 ); + + IBSP_EXIT( IBSP_DBG_CONN ); + return 0; + +error: + CL_ASSERT( *lpErrno != 0 ); + IBSP_PRINT_EXIT(TRACE_LEVEL_INFORMATION, IBSP_DBG_CONN, ("failed with error %d\n", *lpErrno) ); + return SOCKET_ERROR; +} + + +/* Function: IBSPCloseSocket + * + * Description: + * Close the socket handle of the app socket as well as the provider socket. + * However, if there are outstanding async IO requests on the app socket + * we only close the provider socket. Only when all the IO requests complete + * (with error) will we then close the app socket. + */ +static int WSPAPI +IBSPCloseSocket( + SOCKET s, + LPINT lpErrno ) +{ + struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s; + + IBSP_ENTER( IBSP_DBG_CONN ); + + fzprint(("%s():%d:0x%x:0x%x: socket=0x%p \n", __FUNCTION__, + __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s)); + + if( s == INVALID_SOCKET ) + { + IBSP_ERROR_EXIT( ("invalid socket handle %Ix\n", s) ); + *lpErrno = WSAENOTSOCK; + return SOCKET_ERROR; + } +#ifdef _DEBUG_ + cl_atomic_inc( &g_ibsp.CloseSocket_count ); +#endif + + shutdown_and_destroy_socket_info( socket_info ); + + IBSP_EXIT( IBSP_DBG_CONN ); + + *lpErrno = 0; + return 0; +} + + +/* Function: IBSPConnect + * + * Description: + * Performs a connect call. The only thing we need to do is translate + * the socket handle. + */ +static int WSPAPI +IBSPConnect( + SOCKET s, + const struct sockaddr FAR *name, + int namelen, + LPWSABUF lpCallerData, + LPWSABUF lpCalleeData, + LPQOS lpSQOS, + LPQOS lpGQOS, + LPINT lpErrno ) +{ + struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s; + struct sockaddr_in *addr = (struct sockaddr_in *)name; + int ret; + ib_net64_t dest_port_guid; + ib_path_rec_t path_rec; + ib_path_rec_t alt_path_rec, *palt_path_rec = NULL; + + + IBSP_ENTER( IBSP_DBG_CONN ); + + UNUSED_PARAM( lpCalleeData ); + UNUSED_PARAM( lpSQOS ); + UNUSED_PARAM( lpGQOS ); + + fzprint(("%s():%d:0x%x:0x%x: socket=0x%p state=%s\n", __FUNCTION__, + __LINE__, GetCurrentProcessId(), + GetCurrentThreadId(), s, IBSP_SOCKET_STATE_STR( socket_info->socket_state ))); + + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_CONN, + ("lpCallerData=%p, lpCalleeData=%p\n", lpCallerData, lpCalleeData) ); + + + socket_info->active_side = TRUE; + /* Sanity checks */ + if( lpCallerData ) + { + /* We don't support that. The current switch does not use it. */ + IBSP_ERROR_EXIT( ("lpCallerData.len=%d\n", lpCallerData->len) ); + *lpErrno = WSAEINVAL; + return SOCKET_ERROR; + } + + if( namelen < sizeof(struct sockaddr_in) ) + { + IBSP_ERROR_EXIT( ( + "invalid remote address (%d)\n", socket_info->socket_state) ); + *lpErrno = WSAEFAULT; + return SOCKET_ERROR; + } + + /* Check if the name (actually address) of peer entity is correct */ + if( addr->sin_family != AF_INET || + addr->sin_port == 0 || addr->sin_addr.s_addr == INADDR_ANY ) + { + IBSP_ERROR_EXIT( ("peer entity address is invalid (%d, %d, %x)\n", + addr->sin_family, addr->sin_port, addr->sin_addr.s_addr) ); + *lpErrno = WSAEADDRNOTAVAIL; + return SOCKET_ERROR; + } + + if( socket_info->local_addr.sin_addr.S_un.S_addr == addr->sin_addr.S_un.S_addr ) + { + /* Loopback - let the regular stack take care of that. */ + IBSP_PRINT_EXIT(TRACE_LEVEL_INFORMATION, IBSP_DBG_CONN, ("Loopback!\n") ); + *lpErrno = WSAEADDRNOTAVAIL; + return SOCKET_ERROR; + } + + /* Get the GUID for that IP address. */ + ret = query_guid_address( + (struct sockaddr*)&socket_info->local_addr, name, &dest_port_guid ); + if( ret ) + { + IBSP_ERROR_EXIT( ("query_guid_address failed for IP %08x\n", + addr->sin_addr.s_addr) ); + *lpErrno = g_connect_err; + return SOCKET_ERROR; + } + socket_info->dest_port_guid = dest_port_guid; + + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_CONN, ("got GUID %I64x for IP %s\n", + CL_NTOH64( dest_port_guid ), inet_ntoa( addr->sin_addr )) ); + + if( dest_port_guid == socket_info->port->guid ) + { + IBSP_PRINT_EXIT(TRACE_LEVEL_INFORMATION, IBSP_DBG_CONN, ("Loopback!\n") ); + *lpErrno = WSAEADDRNOTAVAIL; + return SOCKET_ERROR; + } + + /* Get the path record */ + ret = query_pr( socket_info->port->guid, dest_port_guid,socket_info->port->hca->dev_id, &path_rec ); + if( ret ) + { + IBSP_ERROR_EXIT( ( + "query_pr failed for IP %08x\n", addr->sin_addr.s_addr) ); + *lpErrno = g_connect_err; + return SOCKET_ERROR; + } + /* Get the alternate path record */ + if (g_use_APM) + { + ret = query_pr(GetOtherPortGuid(socket_info->port->guid), GetOtherPortGuid(dest_port_guid), socket_info->port->hca->dev_id, &alt_path_rec ); + if( ret ) + { + // We can ignore a failure here, since APM is not a MUST + IBSP_ERROR( ("QPR for alternate path failed (error ignored)\n") ); + } + else + { + palt_path_rec = &alt_path_rec; + } + } + + + cl_spinlock_acquire( &socket_info->mutex1 ); + + /* Verify the state of the socket */ + switch( socket_info->socket_state ) + { + case IBSP_BIND: + /* Good. That's the only valid state we want. */ + break; + + case IBSP_CONNECTED: + IBSP_ERROR( ("Socket is already connected\n") ); + *lpErrno = WSAEISCONN; + goto done; + + case IBSP_LISTEN: + IBSP_ERROR( ("Socket is a listening socket\n") ); + *lpErrno = WSAEINVAL; + goto done; + + default: + IBSP_ERROR( ("Socket is not in the bound state (%s)\n", + IBSP_SOCKET_STATE_STR( socket_info->socket_state )) ); + *lpErrno = WSAEINVAL; + goto done; + } + + /* Store the peer entity's address in socket context */ + socket_info->peer_addr = *addr; + +#ifdef IBSP_LOGGING + DataLogger_Init( &socket_info->SendDataLogger, "Send", + &socket_info->peer_addr, &socket_info->local_addr ); + DataLogger_Init( &socket_info->RecvDataLogger, "Recv", + &socket_info->local_addr, &socket_info->peer_addr ); +#endif + + /* Update the socket state */ + IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_CONNECT ); + + /* Connect */ + *lpErrno = ib_connect( socket_info, &path_rec, palt_path_rec ); + if( *lpErrno != WSAEWOULDBLOCK ) + { + /* We must be sure none destroyed our socket */ + IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_BIND ); + memset( &socket_info->peer_addr, 0, sizeof(struct sockaddr_in) ); + + IBSP_ERROR( ("ib_connect failed (%d)\n", *lpErrno) ); + } + +done: + cl_spinlock_release( &socket_info->mutex1 ); + IBSP_EXIT( IBSP_DBG_CONN ); + return SOCKET_ERROR; +} + + +/* Function: IBSPEnumNetworkEvents + * + * Description: + * Enumerate the network events for a socket. We only need to + * translate the socket handle. +*/ +static int WSPAPI +IBSPEnumNetworkEvents( + SOCKET s, + WSAEVENT hEventObject, + LPWSANETWORKEVENTS lpNetworkEvents, + LPINT lpErrno ) +{ + struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s; + + IBSP_ENTER( IBSP_DBG_NEV ); + + if( hEventObject != NULL ) + { + ResetEvent( hEventObject ); + } + + lpNetworkEvents->lNetworkEvents = + InterlockedExchange( &socket_info->network_events, 0 ); + + if( lpNetworkEvents->lNetworkEvents & FD_ACCEPT ) + { + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_NEV, + ("socket %p notify FD_ACCEPT at time %I64d\n", + socket_info, cl_get_time_stamp()) ); + lpNetworkEvents->iErrorCode[FD_ACCEPT_BIT] = 0; + } + + if( lpNetworkEvents->lNetworkEvents & FD_CONNECT ) + { + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_NEV, + ("socket %p notify FD_CONNECT %d at time %I64d\n", + socket_info, socket_info->errno_connect, cl_get_time_stamp()) ); + lpNetworkEvents->iErrorCode[FD_CONNECT_BIT] = socket_info->errno_connect; + } + + *lpErrno = 0; + IBSP_EXIT( IBSP_DBG_NEV ); + return 0; +} + + +/* Function: IBSPEventSelect + * + * Description: + * Register the specified events on the socket with the given event handle. + * All we need to do is translate the socket handle. + */ +static int WSPAPI +IBSPEventSelect( + SOCKET s, + WSAEVENT hEventObject, + long lNetworkEvents, + LPINT lpErrno ) +{ + struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s; + long events; + + IBSP_ENTER( IBSP_DBG_NEV ); + + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_NEV, + ("Socket %Ix requesting notifiction of %d on event %p.\n", + s, lNetworkEvents, hEventObject)); + + if( (lNetworkEvents & ~(FD_ACCEPT | FD_CONNECT)) != 0 ) + { + IBSP_PRINT_EXIT(TRACE_LEVEL_INFORMATION,IBSP_DBG_NEV, + ("Unknown lNetworkEvents flag given (%x)\n", lNetworkEvents) ); + *lpErrno = WSAEINVAL; + return SOCKET_ERROR; + } + + CL_ASSERT( lpErrno ); + + socket_info->event_mask = lNetworkEvents; + InterlockedExchangePointer( &socket_info->event_select, hEventObject ); + + events = InterlockedCompareExchange( &socket_info->network_events, 0, 0 ); + /* Check for existing events and signal as appropriate. */ + if( (socket_info->event_mask & events) && hEventObject ) + { + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_NEV, + ("Signaling eventHandle %p .\n", socket_info->event_select) ); + SetEvent( hEventObject ); + } + + IBSP_EXIT( IBSP_DBG_NEV ); + return 0; +} + + +/* Function: IBSPGetOverlappedResult + * + * Description: + * This function reports whether the specified overlapped call has + * completed. If it has, return the requested information. If not, + * and fWait is true, wait until completion. Otherwise return an + * error immediately. + */ +static BOOL WSPAPI +IBSPGetOverlappedResult( + IN SOCKET s, + IN LPWSAOVERLAPPED lpOverlapped, + OUT LPDWORD lpcbTransfer, + IN BOOL fWait, + OUT LPDWORD lpdwFlags, + OUT LPINT lpErrno ) +{ + struct ibsp_socket_info *p_socket_info; + BOOL rc; + + IBSP_ENTER( IBSP_DBG_IO ); + + fzprint(("%s():%d:0x%x:0x%x: socket=0x%p overlapped=0x%p Internal=%d InternalHigh=%d OffsetHigh=%d hEvent=%d\n", __FUNCTION__, __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s, lpOverlapped, lpOverlapped->Internal, lpOverlapped->InternalHigh, lpOverlapped->OffsetHigh, lpOverlapped->hEvent)); + + CL_ASSERT( fWait == FALSE ); + if( fWait == TRUE ) + { + IBSP_ERROR_EXIT( ("fWait not supported\n") ); + *lpErrno = WSAENETDOWN; + return FALSE; + } + + if( s == INVALID_SOCKET ) + { + /* Seen in real life with overlap/client test. + * The switch closes a socket then calls this. Why? */ + IBSP_ERROR_EXIT( ("invalid socket handle %Ix\n", s) ); + *lpErrno = WSAENOTSOCK; + return SOCKET_ERROR; + } + + if( lpOverlapped->Internal == WSS_OPERATION_IN_PROGRESS ) + { + p_socket_info = (struct ibsp_socket_info*)s; + /* Poll just in case it's done. */ + ib_cq_comp( p_socket_info->cq_tinfo ); + } + + if( lpOverlapped->Internal != WSS_OPERATION_IN_PROGRESS ) + { + /* Operation has completed, perhaps with error */ + *lpdwFlags = lpOverlapped->Offset; + *lpErrno = lpOverlapped->OffsetHigh; + +#ifdef _DEBUG_ + if( ((uintptr_t) lpOverlapped->hEvent) & 0x00000001 ) + { + cl_atomic_dec( &g_ibsp.overlap_h1_count ); + + fzprint(("%s():%d:0x%x:0x%x: ov=0x%p h0=%d h1=%d h1_c=%d send=%d recv=%d\n", + __FUNCTION__, __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), + lpOverlapped, g_ibsp.overlap_h0_count, g_ibsp.overlap_h1_count, + g_ibsp.overlap_h1_comp_count, g_ibsp.send_count, g_ibsp.recv_count)); + } + + fzprint(("%s():%d:0x%x:0x%x: socket=0x%p completed overlap=0x%x overlap_h0_count=%d overlap_h1_count=%d\n", __FUNCTION__, __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s, lpOverlapped, g_ibsp.overlap_h0_count, g_ibsp.overlap_h1_count)); +#endif + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_IO, + ("socket=%p completed ov=%p\n", (void*)s, lpOverlapped)); + } + else + { + /* Operation is still in progress */ + *lpErrno = WSA_IO_INCOMPLETE; + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_IO, + ("socket=%p ov=%p hEvent=%p, operation in progress\n", + (void*)s, lpOverlapped, lpOverlapped->hEvent)); + } + + *lpcbTransfer = (DWORD)lpOverlapped->InternalHigh; + + if( *lpErrno == 0 ) + rc = TRUE; + else + rc = FALSE; + + fzprint(("%s():%d:0x%x:0x%x: socket=0x%p overlapped=0x%p lpErrno=%d rc=%d\n", + __FUNCTION__, __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s, + lpOverlapped, *lpErrno, rc)); + + if (rc == TRUE) CL_ASSERT(*lpcbTransfer > 0); + + IBSP_EXIT( IBSP_DBG_IO ); + return rc; +} + + +/* Function: IBSPGetSockOpt + * + * Description: + * Get the specified socket option. All we need to do is translate the + * socket handle. + */ +static int WSPAPI +IBSPGetSockOpt( + SOCKET s, + int level, + int optname, + char FAR *optval, + LPINT optlen, + LPINT lpErrno ) +{ + struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s; + + IBSP_ENTER( IBSP_DBG_OPT ); + + fzprint(("%s():%d:0x%x:0x%x: socket=0x%p\n", __FUNCTION__, + __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s)); + + if( level != SOL_SOCKET ) + { + IBSP_ERROR_EXIT( ("invalid level %d", level) ); + *lpErrno = WSAENOPROTOOPT; + return SOCKET_ERROR; + } + + if( optval == NULL || optlen == NULL ) + { + IBSP_ERROR_EXIT( ("invalid optval=%p or optlen=%p", optval, optlen) ); + *lpErrno = WSAEFAULT; + return SOCKET_ERROR; + } + + switch( optname ) + { + case SO_DEBUG: + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_OPT, ("Option name SO_DEBUG\n") ); + if( *optlen < sizeof(BOOL) ) + { + IBSP_ERROR_EXIT( ("option len is invalid (0x%x)\n", *optlen) ); + *optlen = sizeof(BOOL); + *lpErrno = WSAEFAULT; + return SOCKET_ERROR; + } + + memcpy( optval, &socket_info->socket_options.debug, sizeof(BOOL) ); + *optlen = sizeof(BOOL); + break; + + case SO_GROUP_ID: + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_OPT, ("Option name SO_GROUP_ID\n") ); + if( *optlen < sizeof(GROUP) ) + { + IBSP_ERROR_EXIT( ("option len is invalid (0x%x)\n", *optlen) ); + *optlen = sizeof(GROUP); + *lpErrno = WSAEFAULT; + return SOCKET_ERROR; + } + + memcpy( optval, &socket_info->socket_options.group_id, sizeof(GROUP) ); + *optlen = sizeof(GROUP); + break; + + case SO_GROUP_PRIORITY: + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_OPT, ("Option name SO_GROUP_PRIORITY\n") ); + + if( *optlen < sizeof(int) ) + { + IBSP_ERROR_EXIT( ("option len is invalid (0x%x)\n", *optlen) ); + *optlen = sizeof(int); + *lpErrno = WSAEFAULT; + return SOCKET_ERROR; + } + + memcpy( optval, &socket_info->socket_options.group_priority, sizeof(int) ); + *optlen = sizeof(int); + break; + + case SO_MAX_MSG_SIZE: + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_OPT, ("Option name SO_MAX_MSG_SIZE\n") ); + + if( *optlen < sizeof(unsigned int) ) + { + IBSP_ERROR_EXIT( ("option len is invalid (0x%x)\n", *optlen) ); + *optlen = sizeof(unsigned int); + *lpErrno = WSAEFAULT; + return SOCKET_ERROR; + } + + memcpy( optval, &socket_info->socket_options.max_msg_size, sizeof(unsigned int) ); + *optlen = sizeof(unsigned int); + break; + + case SO_MAX_RDMA_SIZE: + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_OPT, ("Option name SO_MAX_RDMA_SIZE\n") ); + + if( *optlen < sizeof(unsigned int) ) + { + IBSP_ERROR_EXIT( ("option len is invalid (0x%x)\n", *optlen) ); + *optlen = sizeof(unsigned int); + *lpErrno = WSAEFAULT; + return SOCKET_ERROR; + } + + memcpy( optval, &socket_info->socket_options.max_rdma_size, sizeof(unsigned int) ); + *optlen = sizeof(unsigned int); + break; + + case SO_RDMA_THRESHOLD_SIZE: + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_OPT, ("Option name SO_RDMA_THRESHOLD_SIZE\n") ); + + if( *optlen < sizeof(unsigned int) ) + { + IBSP_ERROR_EXIT( ("option len is invalid (0x%x)\n", *optlen) ); + *optlen = sizeof(unsigned int); + *lpErrno = WSAEFAULT; + return SOCKET_ERROR; + } + + memcpy( optval, &socket_info->socket_options.rdma_threshold_size, + sizeof(unsigned int) ); + *optlen = sizeof(unsigned int); + break; + + default: + *lpErrno = WSAENOPROTOOPT; + + IBSP_ERROR_EXIT( ("unknown option 0x%x\n", optname) ); + + return SOCKET_ERROR; + break; + } + + IBSP_EXIT( IBSP_DBG_OPT ); + return 0; +} + + +/* Function: IBSPGetQOSByName + * + * Description: + * Get a QOS template by name. All we need to do is translate the socket + * handle. + */ +static BOOL WSPAPI +IBSPGetQOSByName( + SOCKET s, + LPWSABUF lpQOSName, + LPQOS lpQOS, + LPINT lpErrno ) +{ + IBSP_ENTER( IBSP_DBG_OPT ); + + UNUSED_PARAM( s ); + UNUSED_PARAM( lpQOSName ); + UNUSED_PARAM( lpQOS ); + + fzprint(("%s():%d:0x%x:0x%x: socket=0x%p\n", __FUNCTION__, + __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s)); + + *lpErrno = WSAEOPNOTSUPP; + + IBSP_ERROR_EXIT( ("not supported\n") ); + + return FALSE; +} + + +/* Function: IBSPIoctl + * + * Description: + * Invoke an ioctl. In most cases, we just need to translate the socket + * handle. However, if the dwIoControlCode is SIO_GET_EXTENSION_FUNCTION_POINTER, + * we'll need to intercept this and return our own function pointers. + */ +static int WSPAPI +IBSPIoctl( + IN SOCKET s, + IN DWORD dwIoControlCode, + IN LPVOID lpvInBuffer, + IN DWORD cbInBuffer, + OUT LPVOID lpvOutBuffer, + IN DWORD cbOutBuffer, + OUT LPDWORD lpcbBytesReturned, + IN LPWSAOVERLAPPED lpOverlapped, + IN LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine, + IN LPWSATHREADID lpThreadId, + OUT LPINT lpErrno ) +{ + struct ibsp_socket_info *socket_info; + GUID SANRegisterMemory = WSAID_REGISTERMEMORY; + GUID SANDeregisterMemory = WSAID_DEREGISTERMEMORY; + GUID SANRegisterRDMAMemory = WSAID_REGISTERRDMAMEMORY; + GUID SANDeregisterRDMAMemory = WSAID_DEREGISTERRDMAMEMORY; + GUID SANRDMAWrite = WSAID_RDMAWRITE; + GUID SANRDMARead = WSAID_RDMAREAD; + GUID SANMemoryRegistrationCacheCallback = WSAID_MEMORYREGISTRATIONCACHECALLBACK; + + IBSP_ENTER( IBSP_DBG_OPT ); + + UNUSED_PARAM( cbInBuffer ); + UNUSED_PARAM( lpOverlapped ); + UNUSED_PARAM( lpCompletionRoutine ); + UNUSED_PARAM( lpThreadId ); + + if( dwIoControlCode == SIO_GET_EXTENSION_FUNCTION_POINTER ) + { + /* This a special case. The socket handle passed is not valid. */ + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_OPT, ("Get extension function pointer\n") ); + + if( memcmp( lpvInBuffer, &SANRegisterMemory, sizeof(GUID) ) == 0 ) + { + /* Return a pointer to our intermediate extension function */ + *((LPFN_WSPREGISTERMEMORY *) lpvOutBuffer) = IBSPRegisterMemory; + } + else if( memcmp( lpvInBuffer, &SANDeregisterMemory, sizeof(GUID) ) == 0 ) + { + /* Return a pointer to our intermediate extension function */ + *((LPFN_WSPDEREGISTERMEMORY *) lpvOutBuffer) = IBSPDeregisterMemory; + } + else if( memcmp( lpvInBuffer, &SANRegisterRDMAMemory, sizeof(GUID) ) == 0 ) + { + /* Return a pointer to our intermediate extension function */ + *((LPFN_WSPREGISTERRDMAMEMORY *) lpvOutBuffer) = IBSPRegisterRdmaMemory; + } + else if( memcmp( lpvInBuffer, &SANDeregisterRDMAMemory, sizeof(GUID) ) == 0 ) + { + /* Return a pointer to our intermediate extension function */ + *((LPFN_WSPDEREGISTERRDMAMEMORY *) lpvOutBuffer) = IBSPDeregisterRdmaMemory; + } + else if( memcmp( lpvInBuffer, &SANRDMAWrite, sizeof(GUID) ) == 0 ) + { + /* Return a pointer to our intermediate extension function */ + *((LPFN_WSPRDMAWRITE *) lpvOutBuffer ) = IBSPRdmaWrite; + } + else if( memcmp( lpvInBuffer, &SANRDMARead, sizeof(GUID) ) == 0 ) + { + if( no_read ) + { + IBSP_PRINT(TRACE_LEVEL_WARNING, IBSP_DBG_OPT, + ("RDMA_READ disabled.\n") ); + *lpErrno = WSAEOPNOTSUPP; + return SOCKET_ERROR; + } + else + { + /* Return a pointer to our intermediate extension function */ + *((LPFN_WSPRDMAREAD *) lpvOutBuffer ) = IBSPRdmaRead; + } + } + else if( memcmp( lpvInBuffer, &SANMemoryRegistrationCacheCallback, + sizeof(GUID) ) == 0 ) + { + /* Return a pointer to our intermediate extension function */ + *((LPFN_WSPMEMORYREGISTRATIONCACHECALLBACK *) lpvOutBuffer ) = + IBSPMemoryRegistrationCacheCallback; + } + else + { + IBSP_ERROR_EXIT( ("invalid extension GUID\n") ); + *lpErrno = WSAEINVAL; + return SOCKET_ERROR; + } + IBSP_EXIT( IBSP_DBG_OPT ); + return 0; + } + + socket_info = (struct ibsp_socket_info *)s; + + /* Verify the state of the socket */ + /* Not sure which state socket should be in to receive this call */ + DebugPrintIBSPIoctlParams( IBSP_DBG_OPT, + dwIoControlCode, + lpvInBuffer, + cbInBuffer, + lpvOutBuffer, + cbOutBuffer, lpOverlapped, lpCompletionRoutine, lpThreadId ); + + switch( dwIoControlCode ) + { + case SIO_GET_QOS: + case SIO_GET_GROUP_QOS: + case SIO_SET_QOS: + case SIO_SET_GROUP_QOS: + /* We don't support that. dwServiceFlags1 in installSP + * wasn't set. */ + IBSP_ERROR_EXIT( ("unsupported dwIoControlCode %d\n", dwIoControlCode) ); + *lpErrno = WSAENOPROTOOPT; + return SOCKET_ERROR; + break; + + case SIO_ADDRESS_LIST_QUERY: + { + int ret; + + *lpcbBytesReturned = cbOutBuffer; + ret = build_ip_list( (LPSOCKET_ADDRESS_LIST)lpvOutBuffer, + lpcbBytesReturned, lpErrno ); + + IBSP_EXIT( IBSP_DBG_OPT ); + return ret; + } + break; + + default: + IBSP_ERROR_EXIT( ("invalid dwIoControlCode %d\n", dwIoControlCode) ); + + *lpErrno = WSAENOPROTOOPT; + return SOCKET_ERROR; + break; + } + + /* unreachable */ +} + + +/* Function: IBSPListen + * + * Description: + * This function establishes a socket to listen for incoming connections. It sets + * the backlog value on a listening socket. + */ +static int WSPAPI +IBSPListen( + SOCKET s, + int backlog, + LPINT lpErrno ) +{ + struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s; + int ret; + + IBSP_ENTER( IBSP_DBG_CONN ); + + fzprint(("%s():%d:0x%x:0x%x: socket=0x%p\n", __FUNCTION__, + __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s)); + + cl_spinlock_acquire( &socket_info->mutex1 ); + + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_CONN, ("socket_state is %s\n", + IBSP_SOCKET_STATE_STR( socket_info->socket_state )) ); + + /* Verify the state of the socket */ + switch( socket_info->socket_state ) + { + case IBSP_BIND: + + /* Store the backlog value in the context */ + socket_info->listen.backlog = backlog; + IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_LISTEN ); + + socket_info->listen.listen_req_param.dwProcessId = 0; + cl_memclr( &socket_info->listen.listen_req_param.identifier, + sizeof(socket_info->listen.listen_req_param.identifier) ); + + ret = ib_listen( socket_info ); + if( ret ) + { + IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_BIND ); + IBSP_ERROR_EXIT( ("ib_listen failed with %d\n", ret) ); + } + break; + + case IBSP_LISTEN: + /* Change the backlog */ + ib_listen_backlog( socket_info, backlog ); + ret = 0; + break; + + default: + IBSP_ERROR( ("Invalid socket_state (%s)\n", + IBSP_SOCKET_STATE_STR( socket_info->socket_state )) ); + ret = WSAEINVAL; + break; + } + + cl_spinlock_release( &socket_info->mutex1 ); + + *lpErrno = ret; + + IBSP_EXIT( IBSP_DBG_CONN ); + if( ret ) + return SOCKET_ERROR; + else + return 0; +} + + +/* Function: IBSPRecv + * + * Description: + * This function receives data on a given socket and also allows for asynchronous + * (overlapped) operation. First translate the socket handle to the lower provider + * handle and then make the receive call. If called with overlap, post the operation + * to our IOCP or completion routine. +*/ +static int WSPAPI +IBSPRecv( + SOCKET s, + LPWSABUF lpBuffers, + DWORD dwBufferCount, + LPDWORD lpNumberOfBytesRecvd, + LPDWORD lpFlags, + LPWSAOVERLAPPED lpOverlapped, + LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine, + LPWSATHREADID lpThreadId, + LPINT lpErrno ) +{ + struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s; + ib_api_status_t status; + struct memory_node *node; + struct _recv_wr *wr; + DWORD ds_idx; + + IBSP_ENTER( IBSP_DBG_IO ); + + UNUSED_PARAM( lpNumberOfBytesRecvd ); + UNUSED_PARAM( lpCompletionRoutine ); + UNUSED_PARAM( lpThreadId ); + + fzprint(("%s():%d:0x%x:0x%x: socket=0x%p\n", __FUNCTION__, + __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s)); + + CL_ASSERT( lpCompletionRoutine == NULL ); + CL_ASSERT( lpOverlapped != NULL ); + + if( s == INVALID_SOCKET ) + { + /* Seen in real life with overlap/client test. + * The switch closes a socket then calls this. Why? */ + IBSP_PRINT_EXIT(TRACE_LEVEL_WARNING, IBSP_DBG_IO, + ("invalid socket handle %Ix\n", s) ); + *lpErrno = WSAENOTSOCK; + return SOCKET_ERROR; + } + + cl_spinlock_acquire( &socket_info->mutex1 ); + switch( socket_info->socket_state ) + { + case IBSP_CONNECTED: + case IBSP_DISCONNECTED: + break; + + default: + cl_spinlock_release( &socket_info->mutex1 ); + IBSP_ERROR_EXIT( ("Socket is not in connected socket_state state=%s\n", + IBSP_SOCKET_STATE_STR( socket_info->socket_state )) ); + *lpErrno = WSAENOTCONN; + return SOCKET_ERROR; + } + cl_spinlock_release( &socket_info->mutex1 ); + + if( socket_info->qp_error != 0 ) + { + IBSP_ERROR_EXIT( ("QP is in error state %d\n", socket_info->qp_error) ); + *lpErrno = socket_info->qp_error; + return SOCKET_ERROR; + } + + /* This function only works for that case. Right now the switch is + * only using that. */ + if( dwBufferCount > QP_ATTRIB_RQ_SGE ) + { + CL_ASSERT( dwBufferCount <= QP_ATTRIB_RQ_SGE ); + IBSP_ERROR_EXIT( ("dwBufferCount is greater than %d\n", + QP_ATTRIB_RQ_SGE) ); + *lpErrno = WSAEINVAL; + return SOCKET_ERROR; + } + + cl_spinlock_acquire( &socket_info->recv_lock ); + if( socket_info->recv_cnt == QP_ATTRIB_RQ_DEPTH ) + { + /* This should never happen */ + cl_spinlock_release( &socket_info->recv_lock ); + IBSP_ERROR_EXIT( ("not enough wr on the free list\n") ); + *lpErrno = WSAENETDOWN; + return SOCKET_ERROR; + } + + wr = &socket_info->recv_wr[socket_info->recv_idx]; + + wr->wr.lpOverlapped = lpOverlapped; + wr->wr.socket_info = socket_info; + + /* Looks good. Post the receive buffer. */ + wr->recv.p_next = NULL; + wr->recv.wr_id = (ULONG_PTR)wr; + wr->recv.num_ds = dwBufferCount; + wr->recv.ds_array = wr->ds_array; + + for( ds_idx = 0; ds_idx < dwBufferCount; ds_idx++ ) + { + /* Get the memory region node */ + node = lookup_partial_mr( socket_info, IB_AC_LOCAL_WRITE, + lpBuffers[ds_idx].buf, lpBuffers[ds_idx].len ); + if( !node ) + { + cl_spinlock_release( &socket_info->recv_lock ); + /* + * No mr fits. This should never happen. This error is not + * official, but seems to be the closest. + */ + IBSP_ERROR_EXIT( ("no MR found\n") ); + *lpErrno = WSAEFAULT; + return SOCKET_ERROR; + } + + wr->ds_array[ds_idx].vaddr = + (ULONG_PTR)lpBuffers[ds_idx].buf; + wr->ds_array[ds_idx].length = lpBuffers[ds_idx].len; + wr->ds_array[ds_idx].lkey = node->p_reg1->lkey; + } + + /* + * We must set this now, because the operation could complete + * before ib_post_Recv returns. + */ + lpOverlapped->Internal = WSS_OPERATION_IN_PROGRESS; + + /* Store the flags for reporting back in IBSPGetOverlappedResult */ + lpOverlapped->Offset = *lpFlags; + + cl_atomic_inc( &socket_info->recv_cnt ); + +#ifdef _DEBUG_ + if( lpOverlapped->hEvent == 0 ) + { + cl_atomic_inc( &g_ibsp.overlap_h0_count ); + } + else + { + cl_atomic_inc( &g_ibsp.overlap_h1_count ); + cl_atomic_inc( &g_ibsp.overlap_h1_comp_count ); + } + + cl_atomic_inc( &g_ibsp.recv_count ); + cl_atomic_inc( &g_ibsp.total_recv_count ); + + fzprint(("%s():%d:0x%x:0x%x: ov=0x%p h0=%d h1=%d h1_c=%d send=%d recv=%d\n", + __FUNCTION__, __LINE__, GetCurrentProcessId(), + GetCurrentThreadId(), lpOverlapped, + g_ibsp.overlap_h0_count, g_ibsp.overlap_h1_count, + g_ibsp.overlap_h1_comp_count, g_ibsp.send_count, g_ibsp.recv_count)); +#endif + +#ifdef IBSP_LOGGING + wr->idx = socket_info->recv_log_idx++; +#endif + + fzprint(("%s():%d:0x%x:0x%x: posting RECV socket=0x%p overlap=%p wr=0x%p\n", + __FUNCTION__, __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s, + lpOverlapped, wr)); + + status = ib_post_recv( socket_info->qp, &wr->recv, NULL ); + + if( status == IB_SUCCESS ) + { + /* Update the index and wrap as needed */ +#if QP_ATTRIB_RQ_DEPTH == 256 || QP_ATTRIB_RQ_DEPTH == 128 || \ + QP_ATTRIB_RQ_DEPTH == 64 || QP_ATTRIB_RQ_DEPTH == 32 || \ + QP_ATTRIB_RQ_DEPTH == 16 || QP_ATTRIB_RQ_DEPTH == 8 + socket_info->recv_idx++; + socket_info->recv_idx &= (QP_ATTRIB_RQ_DEPTH - 1); +#else + if( ++socket_info->recv_idx == QP_ATTRIB_RQ_DEPTH ) + socket_info->recv_idx = 0; +#endif + + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_IO, + ("Posted RECV: socket=%p, ov=%p, addr=%p, len=%d\n", + (void*)s, lpOverlapped, lpBuffers[0].buf, lpBuffers[0].len)); + + *lpErrno = WSA_IO_PENDING; + } + else + { + IBSP_ERROR( ("ib_post_recv returned %s\n", ib_get_err_str( status )) ); +#ifdef _DEBUG_ + if( lpOverlapped->hEvent == 0 ) + { + cl_atomic_dec( &g_ibsp.overlap_h0_count ); + } + else + { + cl_atomic_dec( &g_ibsp.overlap_h1_count ); + cl_atomic_dec( &g_ibsp.overlap_h1_comp_count ); + } + + cl_atomic_dec( &g_ibsp.recv_count ); + + memset( wr, 0x33, sizeof(struct _recv_wr) ); +#endif + + cl_atomic_dec( &socket_info->recv_cnt ); + *lpErrno = ibal_to_wsa_error( status ); + } + + cl_spinlock_release( &socket_info->recv_lock ); + + /* We never complete the operation here. */ + IBSP_EXIT( IBSP_DBG_IO ); + return SOCKET_ERROR; +} + + +void print_cur_apm_state(ib_qp_handle_t h_qp) +{ + ib_qp_attr_t qp_attr; + char *apm_states[] = { "IB_APM_MIGRATED", "IB_APM_REARM", "IB_APM_ARMED" }; + + if (!ib_query_qp(h_qp, &qp_attr)) { + IBSP_ERROR(("Querying QP returned that APM FSM is %s (%d)\n", + (qp_attr.apm_state<1 || qp_attr.apm_state>3) ? "UNKNOWN" : + apm_states[qp_attr.apm_state-1], qp_attr.apm_state)); + } + Sleep(10); +} + +/* Function: IBSPSend + * + * Description: + * This function sends data on a given socket and also allows for asynchronous + * (overlapped) operation. First translate the socket handle to the lower provider + * handle and then make the send call. +*/ +static int WSPAPI +IBSPSend( + IN SOCKET s, + IN LPWSABUF lpBuffers, + IN DWORD dwBufferCount, + OUT LPDWORD lpNumberOfBytesSent, + IN DWORD dwFlags, + IN LPWSAOVERLAPPED lpOverlapped, + IN LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine, + IN LPWSATHREADID lpThreadId, + OUT LPINT lpErrno ) +{ + struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s; + ib_api_status_t status; + struct memory_node *node; + struct _wr *wr; + ib_send_wr_t send_wr; + ib_local_ds_t local_ds[QP_ATTRIB_SQ_SGE]; + DWORD ds_idx; + + IBSP_ENTER( IBSP_DBG_IO ); + + UNUSED_PARAM( lpNumberOfBytesSent ); + UNUSED_PARAM( lpCompletionRoutine ); + UNUSED_PARAM( lpThreadId ); + + fzprint(("%s():%d:0x%x:0x%x: socket=0x%p overlap=%p\n", __FUNCTION__, + __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s, lpOverlapped)); + + if( s == INVALID_SOCKET ) + { + IBSP_ERROR_EXIT( ("invalid socket handle %Ix\n", s) ); + *lpErrno = WSAENOTSOCK; + return SOCKET_ERROR; + } + + CL_ASSERT( lpCompletionRoutine == NULL ); + CL_ASSERT( lpOverlapped != NULL ); + + cl_spinlock_acquire( &socket_info->mutex1 ); + switch( socket_info->socket_state ) + { + case IBSP_CONNECTED: + case IBSP_DISCONNECTED: + break; + + default: + cl_spinlock_release( &socket_info->mutex1 ); + IBSP_ERROR_EXIT( ("Socket is not in connected socket_state state=%s\n", + IBSP_SOCKET_STATE_STR( socket_info->socket_state )) ); + *lpErrno = WSAENOTCONN; + return SOCKET_ERROR; + } + cl_spinlock_release( &socket_info->mutex1 ); + + if( socket_info->qp_error ) + { + IBSP_ERROR_EXIT( ("QP is in error state %d\n", socket_info->qp_error) ); + *lpErrno = socket_info->qp_error; + return SOCKET_ERROR; + } + + /* This function only works for that case. */ + if( dwBufferCount > QP_ATTRIB_SQ_SGE ) + { + CL_ASSERT( dwBufferCount <= QP_ATTRIB_SQ_SGE ); + IBSP_ERROR_EXIT( ("dwBufferCount is greater than %d\n", QP_ATTRIB_SQ_SGE) ); + *lpErrno = WSAEINVAL; + return SOCKET_ERROR; + } + + /* The send lock is only used to serialize posting. */ + cl_spinlock_acquire( &socket_info->send_lock ); + if( socket_info->send_cnt == QP_ATTRIB_SQ_DEPTH ) + { + /* This should never happen */ + cl_spinlock_release( &socket_info->send_lock ); + IBSP_ERROR_EXIT( ("not enough wr on the free list\n") ); + *lpErrno = WSAENETDOWN; + return SOCKET_ERROR; + } + + wr = &socket_info->send_wr[socket_info->send_idx]; + + wr->lpOverlapped = lpOverlapped; + wr->socket_info = socket_info; + + /* Looks good. Post the send buffer. */ + send_wr.p_next = NULL; + send_wr.wr_id = (uint64_t) (uintptr_t) wr; + send_wr.wr_type = WR_SEND; + send_wr.send_opt = socket_info->send_opt; + socket_info->send_opt = 0; + + send_wr.num_ds = dwBufferCount; + send_wr.ds_array = local_ds; + + lpOverlapped->InternalHigh = 0; + for( ds_idx = 0; ds_idx < dwBufferCount; ds_idx++ ) + { + local_ds[ds_idx].vaddr = (ULONG_PTR)lpBuffers[ds_idx].buf; + local_ds[ds_idx].length = lpBuffers[ds_idx].len; + + lpOverlapped->InternalHigh += lpBuffers[ds_idx].len; + } + + if( lpOverlapped->InternalHigh <= socket_info->max_inline ) + { + send_wr.send_opt |= IB_SEND_OPT_INLINE; + } + else + { + for( ds_idx = 0; ds_idx < dwBufferCount; ds_idx++ ) + { + /* Get the memory region node */ + node = lookup_partial_mr( socket_info, 0, /* READ */ + lpBuffers[ds_idx].buf, lpBuffers[ds_idx].len ); + if( !node ) + { + cl_spinlock_release( &socket_info->send_lock ); + /* + * No mr fits. This error is not official, but seems to be the + * closest. + */ + IBSP_ERROR_EXIT( ("mr lookup failed\n") ); + *lpErrno = WSAEFAULT; + return SOCKET_ERROR; + } + + local_ds[ds_idx].lkey = node->p_reg1->lkey; + } + } + + /* + * We must set this now, because the operation could complete + * before ib_post_send returns. + */ + lpOverlapped->Internal = WSS_OPERATION_IN_PROGRESS; + + /* Store the flags for reporting back in IBSPGetOverlappedResult */ + lpOverlapped->Offset = dwFlags; + + cl_atomic_inc( &socket_info->send_cnt ); + +#ifdef _DEBUG_ + if( lpOverlapped->hEvent == 0) + { + cl_atomic_inc( &g_ibsp.overlap_h0_count ); + } + else + { + cl_atomic_inc( &g_ibsp.overlap_h1_count ); + cl_atomic_inc( &g_ibsp.overlap_h1_comp_count ); + } + + cl_atomic_inc( &g_ibsp.send_count ); + cl_atomic_inc( &g_ibsp.total_send_count ); + + fzprint(("%s():%d:0x%x:0x%x: ov=0x%p h0=%d h1=%d h1_c=%d send=%d recv=%d\n", + __FUNCTION__, __LINE__, GetCurrentProcessId(), + GetCurrentThreadId(), lpOverlapped, + g_ibsp.overlap_h0_count, g_ibsp.overlap_h1_count, + g_ibsp.overlap_h1_comp_count, g_ibsp.send_count, g_ibsp.recv_count)); + + +#endif + + + fzprint(("%s():%d:0x%x:0x%x: posting SEND %p, mr handle=%p, addr=%p, len=%d\n", + __FUNCTION__, + __LINE__, GetCurrentProcessId(), + GetCurrentThreadId(), + lpOverlapped, node, lpBuffers[0].buf, lpBuffers[0].len)); + +#ifdef _DEBUG_ + if( lpBuffers[0].len >= 40 ) + { + debug_dump_buffer( IBSP_DBG_WQ , "SEND", + lpBuffers[0].buf, 40 ); + } +#endif + +#ifdef IBSP_LOGGING + { + DWORD i; + + for( i=0; i < dwBufferCount; i++ ) + { + DataLogger_WriteData( &socket_info->SendDataLogger, + socket_info->send_log_idx++, lpBuffers[i].buf, + lpBuffers[i].len); + } + } +#endif + + status = ib_post_send( socket_info->qp, &send_wr, NULL ); + + if( status == IB_SUCCESS ) + { + /* Update the index and wrap as needed */ +#if QP_ATTRIB_SQ_DEPTH == 256 || QP_ATTRIB_SQ_DEPTH == 128 || \ + QP_ATTRIB_SQ_DEPTH == 64 || QP_ATTRIB_SQ_DEPTH == 32 || \ + QP_ATTRIB_SQ_DEPTH == 16 || QP_ATTRIB_SQ_DEPTH == 8 + socket_info->send_idx++; + socket_info->send_idx &= (QP_ATTRIB_SQ_DEPTH - 1); +#else + if( ++socket_info->send_idx == QP_ATTRIB_SQ_DEPTH ) + socket_info->send_idx = 0; +#endif + + + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_IO, + ("Posted SEND: socket=%p, ov=%p, addr=%p, len=%d\n", + (void*)s, lpOverlapped, lpBuffers[0].buf, lpBuffers[0].len)); + + *lpErrno = WSA_IO_PENDING; + } + else + { + IBSP_ERROR( ("ib_post_send returned %s\n", ib_get_err_str( status )) ); + +#ifdef _DEBUG_ + if( lpOverlapped->hEvent == 0 ) + { + cl_atomic_dec( &g_ibsp.overlap_h0_count ); + } + else + { + cl_atomic_dec( &g_ibsp.overlap_h1_count ); + cl_atomic_dec( &g_ibsp.overlap_h1_comp_count ); + } + cl_atomic_dec( &g_ibsp.send_count ); + + memset( wr, 0x37, sizeof(struct _wr) ); +#endif + cl_atomic_dec( &socket_info->send_cnt ); + + *lpErrno = ibal_to_wsa_error( status ); + } + cl_spinlock_release( &socket_info->send_lock ); + + /* We never complete the operation here. */ + IBSP_EXIT( IBSP_DBG_IO ); + return SOCKET_ERROR; +} + + +/* Function: IBSPSetSockOpt + * + * Description: + * Set a socket option. For most all options we just have to translate the + * socket option and call the lower provider. The only special case is for + * SO_UPDATE_ACCEPT_CONTEXT in which case a socket handle is passed as the + * argument which we need to translate before calling the lower provider. + */ +static int WSPAPI +IBSPSetSockOpt( + SOCKET s, + int level, + int optname, + const char FAR *optval, + int optlen, + LPINT lpErrno ) +{ + struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s; + + IBSP_ENTER( IBSP_DBG_OPT ); + + fzprint(("%s():%d:0x%x:0x%x: socket=0x%p\n", __FUNCTION__, + __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s)); + + if( level != SOL_SOCKET ) + { + IBSP_ERROR_EXIT( ("invalid level %d", level) ); + *lpErrno = WSAENOPROTOOPT; + return SOCKET_ERROR; + } + + if( optval == NULL ) + { + IBSP_ERROR_EXIT( ("invalid optval=%p", optval) ); + *lpErrno = WSAEFAULT; + return SOCKET_ERROR; + } + + switch( optname ) + { + case SO_DEBUG: + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_OPT, ("Option name SO_DEBUG\n") ); + if( optlen != sizeof(BOOL) ) + { + IBSP_ERROR_EXIT( ("option len is invalid (0x%x)\n", optlen) ); + *lpErrno = WSAEFAULT; + return SOCKET_ERROR; + } + memcpy( &socket_info->socket_options.debug, optval, sizeof(BOOL) ); + break; + + case SO_GROUP_PRIORITY: + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_OPT, ("Option name SO_GROUP_PRIORITY\n") ); + if( optlen != sizeof(int) ) + { + IBSP_ERROR_EXIT( ("option len is invalid (0x%x)\n", optlen) ); + *lpErrno = WSAEFAULT; + return SOCKET_ERROR; + } + memcpy( &socket_info->socket_options.group_priority, optval, sizeof(int) ); + break; + + default: + IBSP_ERROR_EXIT( ("invalid option %x\n", optname) ); + *lpErrno = WSAENOPROTOOPT; + return SOCKET_ERROR; + break; + } + + IBSP_EXIT( IBSP_DBG_OPT ); + + return 0; +} + + +/* Function: IBSPSocket + * + * Description: + * This function creates a socket. There are two sockets created. The first + * socket is created by calling the lower providers WSPSocket. This is the + * handle that we use internally within our LSP. We then create a second + * socket with WPUCreateSocketHandle which will be returned to the calling + * application. We will also create a socket context structure which will + * maintain information on each socket. This context is associated with the + * socket handle passed to the application. +*/ +static SOCKET WSPAPI +IBSPSocket( + int af, + int type, + int protocol, + LPWSAPROTOCOL_INFOW lpProtocolInfo, + GROUP g, + DWORD dwFlags, + LPINT lpErrno ) +{ + struct ibsp_socket_info *socket_info = NULL; + + IBSP_ENTER( IBSP_DBG_SI ); + + UNUSED_PARAM( g ); + + if( af != AF_INET ) + { + IBSP_ERROR_EXIT( ("bad family %d instead of %d\n", af, AF_INET) ); + *lpErrno = WSAEAFNOSUPPORT; + return INVALID_SOCKET; + } + + if( type != SOCK_STREAM ) + { + IBSP_ERROR_EXIT( ("bad type %d instead of %d\n", type, SOCK_STREAM) ); + *lpErrno = WSAEPROTOTYPE; + return INVALID_SOCKET; + } + + if( protocol != IPPROTO_TCP ) + { + IBSP_ERROR_EXIT( ("bad protocol %d instead of %d\n", protocol, IPPROTO_TCP) ); + *lpErrno = WSAEPROTONOSUPPORT; + return INVALID_SOCKET; + } + + if( (dwFlags != WSA_FLAG_OVERLAPPED) ) + { + IBSP_ERROR_EXIT( ("dwFlags is not WSA_FLAG_OVERLAPPED (%x)\n", dwFlags) ); + *lpErrno = WSAEINVAL; + return INVALID_SOCKET; + } + + socket_info = create_socket_info( lpErrno ); + if( socket_info == NULL ) + { + IBSP_ERROR_EXIT( ("create_socket_info return NULL\n") ); + return INVALID_SOCKET; + } + + if( lpProtocolInfo->dwProviderReserved != 0 ) + { + /* This is a duplicate socket. */ + *lpErrno = setup_duplicate_socket( socket_info, + (HANDLE)(ULONG_PTR)lpProtocolInfo->dwProviderReserved ); + if( *lpErrno ) + { + deref_socket_info( socket_info ); + IBSP_ERROR( ("setup_duplicate_socket failed with %d\n", *lpErrno) ); + return INVALID_SOCKET; + } + } + else + { + socket_info->socket_state = IBSP_CREATE; + + /* Set the (non-zero) default socket options for that socket */ + socket_info->socket_options.max_msg_size = IB_MAX_MSG_SIZE; + socket_info->socket_options.max_rdma_size = IB_MAX_RDMA_SIZE; + socket_info->socket_options.rdma_threshold_size = IB_RDMA_THRESHOLD_SIZE; + } + + cl_spinlock_acquire( &g_ibsp.socket_info_mutex ); + cl_qlist_insert_tail( &g_ibsp.socket_info_list, &socket_info->item ); + cl_spinlock_release( &g_ibsp.socket_info_mutex ); + + *lpErrno = 0; + + fzprint(("%s():%d:0x%x:0x%x: socket=0x%p\n", __FUNCTION__, + __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), socket_info)); + + IBSP_PRINT_EXIT(TRACE_LEVEL_INFORMATION, IBSP_DBG_SI, + ("returning socket handle %p\n", socket_info) ); + + return (SOCKET) socket_info; +} + + +/* Function: IBSPCleanup + * + * Description: + * Decrement the entry count. If equal to zero then we can prepare to have us + * unloaded. Close any outstanding sockets and free up allocated memory. + */ +static int WSPAPI +IBSPCleanup( + LPINT lpErrno ) +{ + int ret = 0; + + IBSP_ENTER( IBSP_DBG_INIT ); + + cl_spinlock_acquire( &g_ibsp.mutex ); + + if( !g_ibsp.entry_count ) + { + cl_spinlock_release( &g_ibsp.mutex ); + + *lpErrno = WSANOTINITIALISED; + + IBSP_ERROR_EXIT( ("returning WSAENOTINITIALISED\n") ); + + return SOCKET_ERROR; + } + + /* Decrement the entry count */ + g_ibsp.entry_count--; + + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_INIT, ("WSPCleanup: %d\n", g_ibsp.entry_count) ); + + if( g_ibsp.entry_count == 0 ) + { + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_INIT, ("entry_count is 0 => cleaning up\n") ); + ShutDownApmLib(); + ib_release(); + +#ifdef PERFMON_ENABLED + IBSPPmReleaseSlot(); +#endif + } + + cl_spinlock_release( &g_ibsp.mutex ); + + IBSP_EXIT( IBSP_DBG_INIT ); + + return ret; +} + + +/* + * Function: WSPStartupEx + * + * Description: + * This function intializes the service provider. We maintain a ref count to keep track + * of how many times this function has been called. + */ +int WSPAPI +WSPStartupEx( + WORD wVersion, + LPWSPDATA lpWSPData, + LPWSAPROTOCOL_INFOW lpProtocolInfo, + LPWSPUPCALLTABLEEX UpCallTable, + LPWSPPROC_TABLE lpProcTable ) +{ + static WSPPROC_TABLE gProcTable; + static WSPDATA gWSPData; + + IBSP_ENTER( IBSP_DBG_INIT ); + + /* Make sure that the version requested is >= 2.2. The low byte is the + major version and the high byte is the minor version. */ + if( (LOBYTE(wVersion) < 2) || ((LOBYTE(wVersion) == 2) && (HIBYTE(wVersion) < 2)) ) + { + IBSP_ERROR_EXIT( ("Invalid winsock version requested %x\n", wVersion) ); + + return WSAVERNOTSUPPORTED; + } + + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_INIT, ("entry_count=%d)\n", g_ibsp.entry_count) ); + + cl_spinlock_acquire( &g_ibsp.mutex ); + + if( g_ibsp.entry_count == 0 ) + { + int ret; + + /* Save the global WSPData */ + gWSPData.wVersion = MAKEWORD(2, 2); + gWSPData.wHighVersion = MAKEWORD(2, 2); + wcscpy( gWSPData.szDescription, Description ); + + /* provide Service provider's entry points in proc table */ + memset( &gProcTable, 0, sizeof(gProcTable) ); + gProcTable.lpWSPAccept = IBSPAccept; + gProcTable.lpWSPBind = IBSPBind; + gProcTable.lpWSPCleanup = IBSPCleanup; + gProcTable.lpWSPCloseSocket = IBSPCloseSocket; + gProcTable.lpWSPConnect = IBSPConnect; + gProcTable.lpWSPDuplicateSocket = IBSPDuplicateSocket; + gProcTable.lpWSPEnumNetworkEvents = IBSPEnumNetworkEvents; + gProcTable.lpWSPEventSelect = IBSPEventSelect; + gProcTable.lpWSPGetOverlappedResult = IBSPGetOverlappedResult; + gProcTable.lpWSPGetSockOpt = IBSPGetSockOpt; + gProcTable.lpWSPGetQOSByName = IBSPGetQOSByName; + gProcTable.lpWSPIoctl = IBSPIoctl; + gProcTable.lpWSPListen = IBSPListen; + gProcTable.lpWSPRecv = IBSPRecv; + gProcTable.lpWSPSend = IBSPSend; + gProcTable.lpWSPSetSockOpt = IBSPSetSockOpt; + gProcTable.lpWSPSocket = IBSPSocket; + + /* Since we only support 2.2, set both wVersion and wHighVersion to 2.2. */ + lpWSPData->wVersion = MAKEWORD(2, 2); + lpWSPData->wHighVersion = MAKEWORD(2, 2); + wcscpy( lpWSPData->szDescription, Description ); + +#ifdef LATER + /* TODO: remove? */ + cl_qlist_init( &g_ibsp.cq_thread_info_list ); + cl_spinlock_init( &g_ibsp.cq_thread_info_mutex ); +#endif + + g_ibsp.protocol_info = *lpProtocolInfo; + + /* Initialize Infiniband */ + ret = ibsp_initialize(); + if( ret ) + { + IBSP_ERROR_EXIT( ("ibsp_initialize failed (%d)\n", ret) ); + return ret; + } + } + g_ibsp.entry_count++; + + cl_spinlock_release( &g_ibsp.mutex ); + + /* Set the return parameters */ + *lpWSPData = gWSPData; + *lpProcTable = gProcTable; + + /* store the upcall function table */ + g_ibsp.up_call_table = *UpCallTable; + + IBSP_EXIT( IBSP_DBG_INIT ); + +#ifdef PERFMON_ENABLED + /* Socket application register with perfmon */ + IBSPPmGetSlot(); +#endif /* PERFMON_ENABLED */ + + return 0; +} + + +// TRUE means that all is well with socket, no need to recall it +BOOL rearm_socket(struct ibsp_socket_info *socket_info) +{ + + + ib_path_rec_t path_rec; + ib_cm_lap_t cm_lap; + int ret; + ib_api_status_t status; + + ib_net64_t dest_port_guid; + ib_net64_t src_port_guid; + + CL_ASSERT(socket_info->active_side == TRUE); + // Try to send the LAP message: + + + if ((socket_info->SuccesfulMigrations & 1) == 0) + { + src_port_guid = socket_info->port->guid; + dest_port_guid = socket_info->dest_port_guid; + } + else + { + src_port_guid = GetOtherPortGuid(socket_info->port->guid); + dest_port_guid = GetOtherPortGuid(socket_info->dest_port_guid); + } + /* Get the path record */ + ret = query_pr( src_port_guid, dest_port_guid, socket_info->port->hca->dev_id, &path_rec ); + if(ret != IB_SUCCESS) + { + IBSP_ERROR( ("query_pr for apm failed\n") ); + return FALSE; + } + + cl_memclr(&cm_lap, sizeof(cm_lap)); + cm_lap.qp_type = IB_QPT_RELIABLE_CONN; + cm_lap.h_qp = socket_info->qp; + cm_lap.remote_resp_timeout = ib_path_rec_pkt_life( &path_rec ) + CM_REMOTE_TIMEOUT; + cm_lap.p_alt_path = &path_rec; + cm_lap.pfn_cm_apr_cb = cm_apr_callback; + status = ib_cm_lap(&cm_lap); + if( status != IB_SUCCESS ) + { + /* Note: a REJ has been automatically sent. */ + IBSP_ERROR( ("ib_cm_lap returned %s\n", ib_get_err_str( status )) ); + return FALSE; + } + else + { + IBSP_PRINT_EXIT(TRACE_LEVEL_INFORMATION, IBSP_DBG_APM, ("ib_cm_lap returned succesfuly\n") ); + socket_info->apm_state = APM_LAP_SENT; + } + + + // Actually we always return false, since we need to make sure that the lap + // was realy successfull. + return FALSE; +} + + + +VOID APMCallback(struct ibsp_socket_info *apm_socket_info) +{ + cl_list_item_t *socket_item = NULL; + BOOL found = FALSE; + + if (g_ibsp.apm_data.hEvent== 0) { + // This means that we have failed to start our timer, not much + // that we can do. + return; + } + + + // Find our socket and mark it as needs to load a new path. + // Avoid race by searching in the list + // BUGBUG: Need to have a better solution than this + cl_spinlock_acquire( &g_ibsp.socket_info_mutex ); + for( socket_item = cl_qlist_head( &g_ibsp.socket_info_list ); + socket_item != cl_qlist_end( &g_ibsp.socket_info_list ); + socket_item = cl_qlist_next( socket_item ) ) + { + struct ibsp_socket_info *socket_info = NULL; + socket_info = PARENT_STRUCT(socket_item, struct ibsp_socket_info, item); + if (apm_socket_info == socket_info) { + if (apm_socket_info->active_side) { + CL_ASSERT(apm_socket_info->apm_state == APM_ARMED); + apm_socket_info->apm_state = APM_MIGRATED ; + } + found = TRUE; + break; + } + } + CL_ASSERT(found == TRUE); // The case that we are not found is very rare + // and is probably a bug + + SetEvent(g_ibsp.apm_data.hEvent); + + cl_spinlock_release( &g_ibsp.socket_info_mutex ); + +} + +DWORD WINAPI ApmThreadProc( + LPVOID lpParameter +) +{ + DWORD dwTimeOut = INFINITE; + DWORD ret; + cl_list_item_t *socket_item = NULL; + + UNREFERENCED_PARAMETER(lpParameter); + + for(;;) { + BOOL AllSocketsDone = TRUE; + ret = WaitForSingleObject(g_ibsp.apm_data.hEvent, dwTimeOut); + if (g_ibsp.apm_data.ThreadExit) { + return 0; + } + cl_spinlock_acquire( &g_ibsp.socket_info_mutex ); + for( socket_item = cl_qlist_head( &g_ibsp.socket_info_list ); + socket_item != cl_qlist_end( &g_ibsp.socket_info_list ); + socket_item = cl_qlist_next( socket_item ) ) + { + struct ibsp_socket_info *socket_info = NULL; + socket_info = PARENT_STRUCT(socket_item, struct ibsp_socket_info, item); + if(socket_info->apm_state == APM_MIGRATED) + { + AllSocketsDone &= rearm_socket(socket_info); + } else if(socket_info->apm_state == APM_LAP_SENT) { + AllSocketsDone = FALSE; + } + } + if (AllSocketsDone) + { + dwTimeOut = INFINITE; + } + else + { + dwTimeOut = 2000; + } + + cl_spinlock_release( &g_ibsp.socket_info_mutex ); + + + } +} + + +void qp_event_handler(ib_async_event_rec_t *p_event) +{ + + if (p_event->code == IB_AE_QP_APM) + { + struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)p_event->context; + IBSP_PRINT_EXIT(TRACE_LEVEL_INFORMATION, IBSP_DBG_APM,("Received an APM event\n")); + APMCallback(socket_info); + } +} + + + +BOOL InitApmLib() +{ + IBSP_PRINT_EXIT(TRACE_LEVEL_INFORMATION, IBSP_DBG_APM,("called\n")); + + g_ibsp.apm_data.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + if (g_ibsp.apm_data.hEvent == NULL) { + IBSP_ERROR_EXIT( ("CreateEvent failed with error %d\n", GetLastError())); + return FALSE; + } + + g_ibsp.apm_data.hThread = CreateThread( + NULL, // Default security attributes + 0, + ApmThreadProc, + NULL, + 0, + NULL + ); + if (g_ibsp.apm_data.hThread == NULL) { + IBSP_ERROR_EXIT( ("CreateThread failed with error %d\n", GetLastError())); + CloseHandle(g_ibsp.apm_data.hEvent); + g_ibsp.apm_data.hEvent = NULL; + return FALSE; + } + + + return TRUE; + + + +} + + +VOID ShutDownApmLib() +{ + DWORD dwRet; + + if (g_ibsp.apm_data.hEvent== 0) { + // This means that we have failed to start our timer, not much + // that we can do. + return; + } + + g_ibsp.apm_data.ThreadExit = TRUE; + SetEvent(g_ibsp.apm_data.hEvent); + + dwRet = WaitForSingleObject(g_ibsp.apm_data.hThread, INFINITE); + CL_ASSERT(dwRet == WAIT_OBJECT_0); + + dwRet = CloseHandle(g_ibsp.apm_data.hThread); + CL_ASSERT(dwRet != 0); + + dwRet = CloseHandle(g_ibsp.apm_data.hEvent); + CL_ASSERT(dwRet != 0); +} + diff --git a/branches/WOF2-3/ulp/wsd/user/ibspdll.def b/branches/WOF2-3/ulp/wsd/user/ibspdll.def new file mode 100644 index 00000000..8932928b --- /dev/null +++ b/branches/WOF2-3/ulp/wsd/user/ibspdll.def @@ -0,0 +1,6 @@ +LIBRARY ibwsd +EXPORTS +WSPStartupEx +IBSPPmOpen +IBSPPmCollectData +IBSPPmClose diff --git a/branches/WOF2-3/ulp/wsd/user/ibspdll.h b/branches/WOF2-3/ulp/wsd/user/ibspdll.h new file mode 100644 index 00000000..ce3a0afd --- /dev/null +++ b/branches/WOF2-3/ulp/wsd/user/ibspdll.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#ifndef IBSPDLL_H +#define IBSPDLL_H + + +#ifdef __GNUC__ +#include +#endif + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "ibspdefines.h" +#include "ibspdebug.h" +#include "ibspstruct.h" +#include "ibspproto.h" +#include "ibsp_mem.h" + +/*--------------------------------------------------------------------------*/ + +extern struct ibspdll_globals g_ibsp; + +extern uint32_t g_max_inline; +extern uint32_t g_max_poll; +extern uint32_t g_sa_timeout; +extern uint32_t g_sa_retries; +extern DWORD_PTR g_dwPollThreadAffinityMask; + +/* Allow users to control SA timeouts behavior - fall back on IPoIB or fail. */ +extern int g_connect_err; +extern uint8_t g_max_cm_retries; +extern int8_t g_pkt_life_modifier; +extern uint8_t g_qp_retries; +extern uint8_t g_use_APM; + + +#endif /* IBSPDLL_H */ diff --git a/branches/WOF2-3/ulp/wsd/user/ibspdll.rc b/branches/WOF2-3/ulp/wsd/user/ibspdll.rc new file mode 100644 index 00000000..3cbc9d8e --- /dev/null +++ b/branches/WOF2-3/ulp/wsd/user/ibspdll.rc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + + +#include + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef _DEBUG_ +#define VER_FILEDESCRIPTION_STR "Winsock Direct for InfiniBand (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "Winsock Direct for InfiniBand" +#endif + +#define VER_INTERNALNAME_STR "ibwsd.dll" +#define VER_ORIGINALFILENAME_STR "ibwsd.dll" + +#include diff --git a/branches/WOF2-3/ulp/wsd/user/ibspproto.h b/branches/WOF2-3/ulp/wsd/user/ibspproto.h new file mode 100644 index 00000000..8e1c80e8 --- /dev/null +++ b/branches/WOF2-3/ulp/wsd/user/ibspproto.h @@ -0,0 +1,311 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +/* protos from socketinfo.c */ +struct ibsp_socket_info * +create_socket_info( + OUT LPINT lpErrno ); + +void AL_API +deref_socket_info( + IN struct ibsp_socket_info *p_socket ); + +/* protos from extension.c */ +HANDLE WSPAPI +IBSPRegisterMemory( + IN SOCKET s, + IN PVOID lpBuffer, + IN DWORD dwBufferLength, + IN DWORD dwFlags, + OUT LPINT lpErrno ); + +int WSPAPI +IBSPDeregisterMemory( + IN SOCKET s, + IN HANDLE handle, + OUT LPINT lpErrno ); + +int WSPAPI +IBSPRegisterRdmaMemory( + IN SOCKET s, + IN PVOID lpBuffer, + IN DWORD dwBufferLength, + IN DWORD dwFlags, + OUT LPVOID lpRdmaBufferDescriptor, + IN OUT LPDWORD lpdwDescriptorLength, + OUT LPINT lpErrno ); + +int WSPAPI +IBSPDeregisterRdmaMemory( + IN SOCKET s, + IN LPVOID lpRdmaBufferDescriptor, + IN DWORD dwDescriptorLength, + OUT LPINT lpErrno ); + +int WSPAPI +IBSPRdmaWrite( + IN SOCKET s, + IN LPWSABUFEX lpBuffers, + IN DWORD dwBufferCount, + IN LPVOID lpTargetBufferDescriptor, + IN DWORD dwTargetDescriptorLength, + IN DWORD dwTargetBufferOffset, + OUT LPDWORD lpdwNumberOfBytesWritten, + IN DWORD dwFlags, + IN LPWSAOVERLAPPED lpOverlapped, + IN LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine, + IN LPWSATHREADID lpThreadId, + OUT LPINT lpErrno ); + +int WSPAPI +IBSPRdmaRead( + IN SOCKET s, + IN LPWSABUFEX lpBuffers, + IN DWORD dwBufferCount, + IN LPVOID lpTargetBufferDescriptor, + IN DWORD dwTargetDescriptorLength, + IN DWORD dwTargetBufferOffset, + OUT LPDWORD lpdwNumberOfBytesRead, + IN DWORD dwFlags, + IN LPWSAOVERLAPPED lpOverlapped, + IN LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine, + IN LPWSATHREADID lpThreadId, + OUT LPINT lpErrno ); + +int WSPAPI +IBSPMemoryRegistrationCacheCallback( + IN LPVOID lpvAddress, + IN SIZE_T Size, + OUT LPINT lpErrno ); + +/* Protos from ibsp_iblow.c */ +extern void +ib_release( void ); + +extern int +ibsp_initialize( void ); + +void +ib_release_cq_tinfo( + struct cq_thread_info *cq_tinfo ); + +void +ib_destroy_cq_tinfo( + struct cq_thread_info *cq_tinfo ); + +int +ib_create_socket( + IN OUT struct ibsp_socket_info *socket_info ); + +void +ib_destroy_socket( + IN OUT struct ibsp_socket_info *socket_info ); + +void +shutdown_and_destroy_socket_info( + IN OUT struct ibsp_socket_info *socket_info ); + +int +ib_cq_comp( + void *cq_context ); + +void +wait_cq_drain( + IN OUT struct ibsp_socket_info *socket_info ); + +void +ibsp_dup_overlap_abort( + IN OUT struct ibsp_socket_info *socket_info ); + +/* Protos from misc.c */ +extern int +ibal_to_wsa_error( + IN const ib_api_status_t status ); + +/* Protos from ibsp_ip.c */ +int CL_API +ip_cmp( + IN const void* const p_key1, + IN const void* const p_key2 ); + +int +query_guid_address( + IN const struct sockaddr *p_src_addr, + IN const struct sockaddr *p_dest_addr, + OUT ib_net64_t *port_guid ); + +int +query_pr( + IN ib_net64_t guid, + IN ib_net64_t dest_port_guid, + IN uint16_t dev_id, + OUT ib_path_rec_t *path_rec ); + +int +build_ip_list( + IN OUT LPSOCKET_ADDRESS_LIST ip_list, + IN OUT LPDWORD ip_list_size, + OUT LPINT lpErrno ); + +struct ibsp_port* +get_port_from_ip_address( + IN const struct in_addr sin_addr ); + +/* Protos from ibsp_cm.c */ +extern int +ib_listen( + IN struct ibsp_socket_info *socket_info ); + +void +ib_listen_cancel( + IN struct ibsp_socket_info *socket_info ); + +void +ib_reject( + IN const ib_cm_handle_t h_cm, + IN const ib_rej_status_t rej_status ); + +int +ib_accept( + IN struct ibsp_socket_info *socket_info, + IN ib_cm_req_rec_t *cm_req_received ); + +int +ib_connect( + IN struct ibsp_socket_info *socket_info, + IN ib_path_rec_t *path_rec, + IN ib_path_rec_t *alt_path_rec ); + +void +ib_disconnect( + IN struct ibsp_socket_info *socket_info, + IN struct disconnect_reason *reason ); + +void +ib_listen_backlog( + IN struct ibsp_socket_info *socket_info, + IN int backlog ); + +/* ibsp_pnp.h */ +ib_api_status_t +register_pnp( void ); + +void +unregister_pnp( void ); + +void +pnp_ca_remove( + struct ibsp_hca *hca); + +/* ibsp_duplicate.c */ +int +setup_duplicate_socket( + IN struct ibsp_socket_info *socket_info, + IN HANDLE h_dup_info ); + +int WSPAPI +IBSPDuplicateSocket( + SOCKET s, + DWORD dwProcessId, + LPWSAPROTOCOL_INFOW lpProtocolInfo, + LPINT lpErrno ); + +/* ibsp_mem.c */ + + +struct memory_node * +lookup_partial_mr( + IN struct ibsp_socket_info *s, + IN ib_access_t acl_mask, + IN void *start, + IN size_t len ); + +struct memory_node * +ibsp_reg_mem( + IN struct ibsp_socket_info *s, + IN ib_pd_handle_t pd, + IN void *start, + IN size_t len, + IN ib_access_t access_ctrl, + OUT LPINT lpErrno ); + +int +ibsp_dereg_mem( + IN struct ibsp_socket_info *s, + IN struct memory_node *node, + OUT LPINT lpErrno ); + +void +ibsp_dereg_hca( + IN struct mr_list *mem_list ); + +void +ibsp_dereg_socket( + IN struct ibsp_socket_info *s ); + +void +ibsp_hca_flush_mr_cache( + IN struct ibsp_hca *p_hca, + IN LPVOID lpvAddress, + IN SIZE_T Size ); + +int +ibsp_conn_insert( + IN struct ibsp_socket_info *socket_info ); + +void +ibsp_conn_remove( + IN struct ibsp_socket_info *socket_info ); + +void +ibsp_post_select_event( + struct ibsp_socket_info *socket_info, + int event, + int error ); + +/* ibspdll.c */ +extern int +init_globals( void ); + +extern void +release_globals( void ); + +inline ib_net64_t GetOtherPortGuid(ib_net64_t DestPortGuid) +{ + return DestPortGuid ^ 0x300000000000000; + +} +void AL_API cm_apr_callback( + IN ib_cm_apr_rec_t *p_cm_apr_rec ); + + +void qp_event_handler(ib_async_event_rec_t *p_event); diff --git a/branches/WOF2-3/ulp/wsd/user/ibspstruct.h b/branches/WOF2-3/ulp/wsd/user/ibspstruct.h new file mode 100644 index 00000000..d019b1e5 --- /dev/null +++ b/branches/WOF2-3/ulp/wsd/user/ibspstruct.h @@ -0,0 +1,491 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include +#include +#include +#include +#include + + + +enum ibsp_socket_state +{ + IBSP_CREATE = 0, + IBSP_BIND, + IBSP_CONNECT, + IBSP_LISTEN, + IBSP_CONNECTED, + IBSP_DUPLICATING_OLD, /* duplicating socket on the original controlling process */ + IBSP_DUPLICATING_NEW, /* duplicating socket on the new controlling process */ + IBSP_DUPLICATING_REMOTE, /* duplicating socket on the remote side */ + IBSP_DISCONNECTED, + IBSP_CLOSED, + IBSP_NUM_STATES +}; + +extern char *ibsp_socket_state_str[IBSP_NUM_STATES]; + +#define IBSP_SOCKET_STATE_STR(state) \ + (state < IBSP_NUM_STATES)?ibsp_socket_state_str[state]:"INVALID" + +/* Socket Options structure */ +struct ibsp_socket_options +{ + BOOL debug; /* SO_DEBUG */ + GROUP group_id; /* SO_GROUP_ID */ + int group_priority; /* SO_GROUP_PRIORITY */ + unsigned int max_msg_size; /* SO_MAX_MSG_SIZE */ + int max_rdma_size; /* SO_MAX_RDMA_SIZE */ + int rdma_threshold_size; /* SO_RDMA_THRESHOLD_SIZE */ +}; + +/* Used to discriminate between various listen on the same ports. + * We need this for socket duplication. + * { 0, 0 } is a standard connection request. */ +struct listen_req_param +{ + DWORD dwProcessId; + GUID identifier; +}; + +/* Parameters given to establish a connection */ +struct cm_req_params +{ + struct listen_req_param listen_req_param; + struct sockaddr_in dest; + struct sockaddr_in source; /* Source of connect() */ +}; + +/* Listen structure. + * Used to remember an incoming connection. */ +struct listen_incoming +{ + cl_list_item_t item; + + ib_cm_req_rec_t cm_req_received; + struct cm_req_params params; +}; + + +/* Keeps track of the posted WR */ +struct _wr +{ + LPWSAOVERLAPPED lpOverlapped; + struct ibsp_socket_info *socket_info; +}; + + +/* Keeps track of the posted WR */ +struct _recv_wr +{ + struct _wr wr; + ib_recv_wr_t recv; + ib_local_ds_t ds_array[QP_ATTRIB_RQ_SGE]; +#ifdef IBSP_LOGGING + LONG idx; +#endif +}; + + +/* Keeps track of the registered MRs */ +struct mr_list +{ + cl_qlist_t list; /* Regions registered through IBSPRegisterMemory */ + cl_spinlock_t mutex; /* Protects the list */ +}; + +/* Information necessary to duplicate sockets */ +struct ibsp_duplicate_info +{ + GUID identifier; + struct ibsp_socket_options socket_options; + struct sockaddr_in local_addr; + struct sockaddr_in peer_addr; + DWORD dwProcessId; +}; + +/* Give the reason for disconnections */ +struct disconnect_reason +{ + enum + { + DISC_INVALID, + DISC_SHUTDOWN, /* normal shutdown */ + DISC_DUPLICATING /* socket duplication */ + } type; + + struct _disconnect_reason_dup + { + GUID identifier; + DWORD dwProcessId; + + } duplicating; +}; + + +/* Internal node describing a registered region. */ +struct memory_reg +{ + cl_list_item_t item; + /* + * List count serves as reference count. The memory registration + * can be released when the list is empty. + */ + cl_qlist_t node_list; + +#ifdef _DEBUG_ +#define MR_NODE_MAGIC 0x7fba43ce + int magic; +#endif + + /* Characteristics of that region. */ + ib_mr_create_t type; + + /* Memory registration parameters, returned by ib_reg_mem. */ + uint32_t lkey; + uint32_t rkey; + ib_mr_handle_t mr_handle; +}; + + +struct memory_node +{ + /* List item to track within a socket structure. */ + cl_list_item_t socket_item; + struct ibsp_socket_info *s; + /* List item to track within the registration structure. */ + cl_list_item_t mr_item; + struct memory_reg *p_reg1; +}; + + + +/* Descriptor given back to WSPRegisterRdmaMemory */ +struct rdma_memory_desc +{ + uint64_t iova; + uint32_t lkey; + uint32_t rkey; + struct memory_node *node1; /* valid only on registering node */ +}; + +struct cq_thread_info +{ + cl_list_item_t list_item; + + cl_waitobj_handle_t cq_waitobj; + ib_cq_handle_t cq; + + /* Number of qp's using this cq */ + atomic32_t qp_count; + + /* Current cqe size */ + uint32_t cqe_size; + + HANDLE ib_cq_thread; + DWORD ib_cq_thread_id; + BOOL ib_cq_thread_exit_wanted; + cl_spinlock_t cq_spinlock; + + struct ibsp_hca *hca; /* HCA to which this cq belongs. */ +}; + + +enum APM_STATE { + APM_ARMED, + APM_MIGRATED, + APM_LAP_SENT + +}; + + +/* Structure representing the context information stored for each + * socket created */ +struct ibsp_socket_info +{ + cl_list_item_t item; /* Link to next SOCKET_INFO in the global list */ + cl_rbmap_item_t conn_item; + cl_spinlock_t mutex1; /* protect this structure */ + + /* Switch socket handle created by WPUCreateSocketHandle. */ + SOCKET switch_socket; + + /* IP address and port this socket is bound to. Set by WSPBind */ + struct sockaddr_in local_addr; + + /* Remote address of peer entity after connect/accept is complete */ + struct sockaddr_in peer_addr; + + /* Back pointer to the port to which this socket is + * bound. It is NULL until the socket is bound, except if the listen + * binds to INADDR_ANY. */ + struct ibsp_port *port; + + enum ibsp_socket_state socket_state; /* represents current socket state */ + + struct + { + /* Listening socket */ + unsigned int backlog; /* Maximum number of pending connections */ + cl_qlist_t list; /* list of pending connections */ + ib_listen_handle_t handle; + struct listen_req_param listen_req_param; + } listen; + + /* Event for blocking accept, and connect */ + HANDLE h_event; + + /* Variables associated with IBSPSelectEvent */ + WSAEVENT event_select; /* Handle to Event Object */ + long event_mask; /* Events we care about */ + long network_events; /* Events that happenned */ + int errno_connect; /* errno code (if any) returned by connect */ + + struct ibsp_socket_options socket_options; /* Socket Options */ + + /* Infiniband ressources */ + ib_pd_handle_t hca_pd; /* Copy of the HCA PD, for faster access. */ + + /* Pointer to completion queue and thread assigned to this socket */ + struct cq_thread_info *cq_tinfo; + + ib_qp_handle_t qp; + uint32_t max_inline; + + /* State on the QP. This is only valid when the socket state is IBSP_CONNECTED. + * 0 : good + * <0 : an error occurred, contains a windoes error *ie WSAExxxx + * -1 : disconected, for duplication process. + */ + int qp_error; + + /* Send request processing. */ + cl_spinlock_t send_lock; + ib_send_opt_t send_opt; + struct _wr send_wr[QP_ATTRIB_SQ_DEPTH]; + uint8_t send_idx; + atomic32_t send_cnt; /* Used to limit access to send_wr array. */ + + /* Receive request processing. */ + cl_spinlock_t recv_lock; + struct _recv_wr recv_wr[QP_ATTRIB_RQ_DEPTH]; + uint8_t recv_idx; + atomic32_t recv_cnt; /* Used to limit access to recv_wr array. */ + + /* + * Used to stall destruction of switch socket until all completion + * upcalls have unwound. + */ + atomic32_t ref_cnt1; + +#ifdef _DEBUG_ + atomic32_t send_comp; + atomic32_t recv_comp; +#endif + + struct _recv_wr dup_wr[QP_ATTRIB_RQ_DEPTH]; + uint8_t dup_idx; + atomic32_t dup_cnt; + + /* + * The switch will register local and RDMA memory for use in RDMA + * transfers. All RDMA registrations are cached in the HCA structure, + * and have memory_node structures referencing them stored here in the + * socket structures. + */ + cl_qlist_t mr_list; + + /* Stuff for socket duplication */ + struct + { + GUID identifier; /* Unique identifier */ + DWORD dwProcessId; + } duplicate; + BOOL active_side; // Tell if we have started this call + enum APM_STATE apm_state; + UINT SuccesfulMigrations; + ib_net64_t dest_port_guid; + +#ifdef IBSP_LOGGING + DataLogger SendDataLogger; + DataLogger RecvDataLogger; + long recv_log_idx; + long send_log_idx; +#endif +}; + + +inline void +ibsp_css( + char *calling_func, + int line, + struct ibsp_socket_info *s, + enum ibsp_socket_state new_state ) +{ + enum ibsp_socket_state old_state; + + UNUSED_PARAM( calling_func ); + UNUSED_PARAM( line ); + + old_state = s->socket_state; + + if( old_state == new_state ) + { + /* Nothing to change */ + return; + } + + /* IBSP_CLOSED is a dead end state */ + if( old_state == IBSP_CLOSED ) + { + return; + } + + + s->socket_state = new_state; +} + +#define IBSP_CHANGE_SOCKET_STATE(socket_info, new_state) \ + ibsp_css(__FUNCTION__, __LINE__, socket_info, new_state) + + +/*--------------------------------------------------------------------------*/ + +/* Describes an IP address */ +struct ibsp_ip_addr +{ + cl_fmap_item_t item; /* next IP for that port */ + + struct ibsp_port *p_port; /* port that owns this IP address */ + struct in_addr ip_addr; /* IPv4 address */ +}; + +/* describes a port */ +struct ibsp_port +{ + cl_list_item_t item; + + struct ibsp_hca *hca; /* HCA to which this port belong. */ + + ib_net64_t guid; + uint8_t port_num; +}; + +/* Describes a hca */ +struct ibsp_hca +{ + cl_list_item_t item; + + ib_net64_t guid; + uint16_t dev_id; /* Device ID to selectively cap MTU to 1K for Tavor. */ + ib_ca_handle_t hca_handle; + + ib_pd_handle_t pd; + + /* Memory management */ + struct mr_list rdma_mem_list; /* Regions registered through IBSPRegisterRdmaMemory */ + + cl_spinlock_t port_lock; + cl_qlist_t port_list; + + /* + * The CQ list is a circular list without an end. The pointer here + * points to the entry that should be used for the next allocation. + */ + cl_spinlock_t cq_lock; + struct cq_thread_info *cq_tinfo; +}; + +struct apm_data_t +{ + HANDLE hThread; + HANDLE hEvent; + BOOL ThreadExit; +}; + +/* There is only one instance of that structure. */ +struct ibspdll_globals +{ + /* Special values. Keep first and in this order. These are not reset + * between WSAStartupEx and WSACleanup calls. */ + cl_spinlock_t mutex; + UINT entry_count; + + /* Provider */ + WSPUPCALLTABLEEX up_call_table; /* MUST keep afetr entry_count */ + HANDLE heap; + cl_qlist_t socket_info_list; /* List of all the created sockets */ + cl_rbmap_t conn_map; /* rb tree of all connections to ensure unique 4-tuple */ + cl_spinlock_t socket_info_mutex; + + WSAPROTOCOL_INFOW protocol_info; + + /* Infiniband */ + ib_al_handle_t al_handle; + ib_pnp_handle_t pnp_handle_ca; + ib_pnp_handle_t pnp_handle_port; + + cl_qlist_t hca_list; + cl_spinlock_t hca_mutex; + + HANDLE h_ibat_dev; + cl_fmap_t ip_map; /* list of all IP addresses supported by all the ports. */ + cl_spinlock_t ip_mutex; + + struct apm_data_t apm_data; + +#ifdef _DEBUG_ + /* Statistics */ + atomic32_t qp_num; + atomic32_t cq_num; + atomic32_t pd_num; + atomic32_t al_num; + atomic32_t mr_num; + atomic32_t ca_num; + atomic32_t listen_num; + atomic32_t pnp_num; + atomic32_t thread_num; + atomic32_t wpusocket_num; + + atomic32_t overlap_h0_count; + atomic32_t overlap_h1_comp_count; + atomic32_t overlap_h1_count; + atomic32_t max_comp_count; + atomic32_t send_count; + atomic32_t recv_count; + atomic32_t total_send_count; + atomic32_t total_recv_count; + atomic32_t total_recv_compleated; + atomic32_t CloseSocket_count; +#endif +}; diff --git a/branches/WOF2-3/ulp/wsd/user/makefile b/branches/WOF2-3/ulp/wsd/user/makefile new file mode 100644 index 00000000..a28a5610 --- /dev/null +++ b/branches/WOF2-3/ulp/wsd/user/makefile @@ -0,0 +1,8 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the OpenIB Windows project. +# +MINIMUM_NT_TARGET_VERSION=0x502 + +!INCLUDE ..\..\..\inc\openib.def diff --git a/branches/WOF2-3/ulp/wsd/user/misc.c b/branches/WOF2-3/ulp/wsd/user/misc.c new file mode 100644 index 00000000..5d81bb52 --- /dev/null +++ b/branches/WOF2-3/ulp/wsd/user/misc.c @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2006 Mellanox Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include "ibspdebug.h" +#if defined(EVENT_TRACING) +#ifdef offsetof +#undef offsetof +#endif +#include "misc.tmh" +#endif + +#include "ibspdll.h" + +char *ibsp_socket_state_str[IBSP_NUM_STATES] = { + "IBSP_CREATE", + "IBSP_BIND", + "IBSP_CONNECT", + "IBSP_LISTEN", + "IBSP_CONNECTED", + "IBSP_DUPLICATING_OLD", + "IBSP_DUPLICATING_NEW", + "IBSP_DUPLICATING_REMOTE", + "IBSP_DISCONNECTED", + "IBSP_CLOSED" +}; + +/* Convert an IBAL error to a Winsock error. */ +int +ibal_to_wsa_error( + const ib_api_status_t status ) +{ + switch( status ) + { + case IB_SUCCESS: + return 0; + + case IB_INVALID_QP_HANDLE: + return WSAENOTCONN; + + case IB_INVALID_PARAMETER: + return WSAEINVAL; + + case IB_INSUFFICIENT_RESOURCES: + return WSAENOBUFS; + + case IB_INVALID_WR_TYPE: + return WSAEINVAL; + + case IB_INVALID_QP_STATE: + return WSAENOTCONN; + + default: + return WSAEINVAL; + } +} + + +/* Initialize the global structure. Only the mutex and entry_count fields + * have been initialized so far. */ +int +init_globals( void ) +{ + /* Set everything to 0 */ + memset( &g_ibsp, 0, sizeof(g_ibsp) ); + + /* Create our private heap */ + g_ibsp.heap = HeapCreate( 0, 128000, 0 ); + if( g_ibsp.heap == NULL) + { + IBSP_ERROR_EXIT( ("HeapCreate() failed: %d\n", GetLastError()) ); + return 1; + } + + /* Initialize our various lock and lists */ + cl_spinlock_init( &g_ibsp.mutex ); + + cl_qlist_init( &g_ibsp.hca_list ); + cl_spinlock_init( &g_ibsp.hca_mutex ); + + g_ibsp.h_ibat_dev = INVALID_HANDLE_VALUE; + cl_fmap_init( &g_ibsp.ip_map, ip_cmp ); + cl_spinlock_init( &g_ibsp.ip_mutex ); + + cl_qlist_init( &g_ibsp.socket_info_list ); + cl_rbmap_init( &g_ibsp.conn_map ); + cl_spinlock_init( &g_ibsp.socket_info_mutex ); + + return 0; +} + + +/* Free ressources allocated in our global structure. */ +void +release_globals( void ) +{ + HeapDestroy( g_ibsp.heap ); + + if( g_ibsp.h_ibat_dev != INVALID_HANDLE_VALUE ) + CloseHandle( g_ibsp.h_ibat_dev ); + + cl_spinlock_destroy( &g_ibsp.socket_info_mutex ); + cl_spinlock_destroy( &g_ibsp.hca_mutex ); + cl_spinlock_destroy( &g_ibsp.ip_mutex ); + cl_spinlock_destroy( &g_ibsp.mutex ); +} diff --git a/branches/WOF2-3/ulp/wsd/user/sockinfo.c b/branches/WOF2-3/ulp/wsd/user/sockinfo.c new file mode 100644 index 00000000..1f5247d2 --- /dev/null +++ b/branches/WOF2-3/ulp/wsd/user/sockinfo.c @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2005 SilverStorm Technologies. All rights reserved. + * Copyright (c) 2006 Mellanox Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include "ibspdebug.h" +#if defined(EVENT_TRACING) +#include "sockinfo.tmh" +#endif + +#include "ibspdll.h" + + +static void +free_socket_info( + IN struct ibsp_socket_info *socket_info ); + +/* + * Function: create_socket_info + * + * Description: + * Allocates a new socket info context structure and initializes some fields. +*/ +struct ibsp_socket_info * +create_socket_info( + OUT LPINT lpErrno ) +{ + struct ibsp_socket_info *socket_info; + + IBSP_ENTER( IBSP_DBG_SI ); + + socket_info = HeapAlloc( g_ibsp.heap, + HEAP_ZERO_MEMORY, sizeof(struct ibsp_socket_info) ); + if( socket_info == NULL ) + { + IBSP_PRINT_EXIT(TRACE_LEVEL_INFORMATION, IBSP_DBG_SI, + ("HeapAlloc() failed: %d\n", GetLastError()) ); + *lpErrno = WSAENOBUFS; + return NULL; + } + + cl_spinlock_construct( &socket_info->mutex1 ); + cl_spinlock_construct( &socket_info->send_lock ); + cl_spinlock_construct( &socket_info->recv_lock ); + cl_qlist_init( &socket_info->mr_list ); + cl_qlist_init( &socket_info->listen.list ); + + if( cl_spinlock_init( &socket_info->mutex1 ) != CL_SUCCESS ) + goto err; + + if( cl_spinlock_init( &socket_info->send_lock ) != CL_SUCCESS ) + goto err; + + if( cl_spinlock_init( &socket_info->recv_lock ) != CL_SUCCESS ) + goto err; + +#ifdef _DEBUG_ + memset( socket_info->send_wr, 0x38, sizeof(socket_info->send_wr) ); + memset( socket_info->recv_wr, 0x38, sizeof(socket_info->recv_wr) ); + memset( socket_info->dup_wr, 0x38, sizeof(socket_info->dup_wr) ); +#endif + + socket_info->switch_socket = + g_ibsp.up_call_table.lpWPUCreateSocketHandle( + 0, (DWORD_PTR)socket_info, lpErrno ); + + if( socket_info->switch_socket == INVALID_SOCKET ) + { + IBSP_ERROR( ("WPUCreateSocketHandle() failed: %d", *lpErrno) ); +err: + free_socket_info( socket_info ); + IBSP_EXIT( IBSP_DBG_SI ); + return NULL; + } + + STAT_INC( wpusocket_num ); + + /* + * Preset to 1, IBSPCloseSocket will decrement it, and switch socket + * will be freed once it goes to zero. + */ + socket_info->ref_cnt1 = 1; + + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_SI, ("socket_info (%p), switch socket (%p)\n", + socket_info, (void*)socket_info->switch_socket) ); + + IBSP_EXIT( IBSP_DBG_SI ); + return socket_info; +} + + +static void +free_socket_info( + IN struct ibsp_socket_info *p_socket ) +{ + int ret, error; + + if( p_socket->switch_socket != INVALID_SOCKET ) + { + /* ref_cnt hit zero - destroy the switch socket. */ + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_SI, + ("socket=0x%p calling lpWPUCloseSocketHandle=0x%p\n", + p_socket, (void*)p_socket->switch_socket) ); + + ret = g_ibsp.up_call_table.lpWPUCloseSocketHandle( + p_socket->switch_socket, &error ); + if( ret == SOCKET_ERROR ) + { + IBSP_ERROR( ("WPUCloseSocketHandle failed: %d\n", error) ); + } + else + { + STAT_DEC( wpusocket_num ); + } + p_socket->switch_socket = INVALID_SOCKET; + } + + CL_ASSERT( !p_socket->qp ); + CL_ASSERT( !p_socket->conn_item.p_map ); + CL_ASSERT(!p_socket->send_cnt && !p_socket->recv_cnt); + cl_spinlock_destroy( &p_socket->mutex1 ); + + cl_spinlock_destroy( &p_socket->send_lock ); + cl_spinlock_destroy( &p_socket->recv_lock ); + + HeapFree( g_ibsp.heap, 0, p_socket ); +} + + +/* + * Function: deref_sock_info + * + * Description: + * This routine decrements a socket context's reference count, and if + * it reaches zero, frees the socket context structure. + */ +void AL_API +deref_socket_info( + IN struct ibsp_socket_info *p_socket ) +{ + IBSP_ENTER( IBSP_DBG_SI ); + + if( !cl_atomic_dec( &p_socket->ref_cnt1 ) ) + { + free_socket_info( p_socket ); + IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_SI, ("Freed socket_info (%p)\n", p_socket) ); + } + IBSP_EXIT( IBSP_DBG_SI ); +} -- 2.46.0

+  +